Merge from Chromium at DEPS revision 232015

This commit was generated by merge_to_master.py.

Change-Id: If86767ad396b9e2e1a4c1e9df1427daea29703ef
diff --git a/.DEPS.git b/.DEPS.git
index 923b88b..7314c05 100644
--- a/.DEPS.git
+++ b/.DEPS.git
@@ -1,7 +1,7 @@
 # DO NOT EDIT EXCEPT FOR LOCAL TESTING.
 # THIS IS A GENERATED FILE.
 # ALL MANUAL CHANGES WILL BE OVERWRITTEN.
-# SEE http://code.google.com/p/chromium/wiki/UsingNewGit
+# SEE http://code.google.com/p/chromium/wiki/UsingGit
 # FOR HOW TO ROLL DEPS
 vars = {
     'ffmpeg_hash':
@@ -11,7 +11,7 @@
     'git_url':
          'https://chromium.googlesource.com',
     'webkit_rev':
-         '@b4efce582acf5214852ec038b05b29db47d99cd2'
+         '@5a1ecad97e33924a192c887f8f1190aeffbcdfb0'
 }
 
 deps = {
@@ -26,9 +26,9 @@
     'src/chrome/test/data/perf/third_party/octane':
         Var('git_url') + '/external/octane-benchmark.git@9ac27bfd9e0bc73663db0c0551440215d8b20d09',
     'src/media/cdm/ppapi/api':
-        Var('git_url') + '/chromium/cdm.git@e13eb2f380636922a8bb13ea35189d169a6caa03',
+        Var('git_url') + '/chromium/cdm.git@38f9d195181e1e2e2d52c0b2b50b70bed00058af',
     'src/native_client':
-        Var('git_url') + '/native_client/src/native_client.git@90ec6579b95cb52cc1f0eba817541a0d97db8687',
+        Var('git_url') + '/native_client/src/native_client.git@8004836801c44ce1ed4d51dffdd3f0ce583db80a',
     'src/sdch/open-vcdiff':
         Var('git_url') + '/external/open-vcdiff.git@438f2a5be6d809bc21611a94cd37bfc8c28ceb33',
     'src/testing/gmock':
@@ -38,7 +38,7 @@
     'src/third_party/WebKit':
         Var('webkit_url') + Var('webkit_rev'),
     'src/third_party/angle_dx11':
-        Var('git_url') + '/external/angle.git@b992a7d282a996d15da3e194695ddebff50fd956',
+        Var('git_url') + '/external/angle.git@0f0edf94bfe1fc28979b0d12747a900164bb966a',
     'src/third_party/bidichecker':
         Var('git_url') + '/external/bidichecker/lib.git@97f2aa645b74c28c57eca56992235c79850fa9e0',
     'src/third_party/cacheinvalidation/src':
@@ -80,7 +80,7 @@
     'src/third_party/libyuv':
         Var('git_url') + '/external/libyuv.git@d36d2606fc7c9d719190676740b4d7b0cc53942f',
     'src/third_party/mesa/src':
-        Var('git_url') + '/chromium/deps/mesa.git@2a3406721cd61852bebd502c7a907cf07b7be731',
+        Var('git_url') + '/chromium/deps/mesa.git@e740c825b11773ebe636675977e5f79de253c745',
     'src/third_party/openmax_dl':
         Var('git_url') + '/external/webrtc/deps/third_party/openmax.git@6b2bf4b577035e2be7e5b096a7148171e5ffadd2',
     'src/third_party/opus/src':
@@ -98,11 +98,11 @@
     'src/third_party/sfntly/cpp/src':
         Var('git_url') + '/external/sfntly/cpp/src.git@8f090032dd4f8f8908f338cc73bb840b788377f2',
     'src/third_party/skia/gyp':
-        Var('git_url') + '/external/skia/gyp.git@46cb86854172e27c7e6ce4d2867eb3afc5c63be4',
+        Var('git_url') + '/external/skia/gyp.git@6e406ee3881de46938405d7e4171cdd4d8f91307',
     'src/third_party/skia/include':
-        Var('git_url') + '/external/skia/include.git@8a9d0c109f36a045baaa598fd4c63790b602794a',
+        Var('git_url') + '/external/skia/include.git@92bf21623a4fd8d829c2bc5a3e174f8727f35387',
     'src/third_party/skia/src':
-        Var('git_url') + '/external/skia/src.git@962b78ab5ec04ec6176b2171200b5183e94de448',
+        Var('git_url') + '/external/skia/src.git@31ec9b62eabed18b73f29c336272aaaef3eb3af6',
     'src/third_party/smhasher/src':
         Var('git_url') + '/external/smhasher.git@6f63a4882e6b2cf87e8eec1a3ef8644e0d963283',
     'src/third_party/snappy/src':
@@ -110,7 +110,7 @@
     'src/third_party/speex':
         Var('git_url') + '/chromium/deps/speex.git@f448dfcceac99e0a771feaeedf447523b3fd26e1',
     'src/third_party/swig/Lib':
-        Var('git_url') + '/chromium/deps/swig/Lib.git@549f0b084ad9c40ef42d111303d831eb8d91252e',
+        Var('git_url') + '/chromium/deps/swig/Lib.git@f2a695d52e61e6a8d967731434f165ed400f0d69',
     'src/third_party/trace-viewer':
         Var('git_url') + '/external/trace-viewer.git@4f179283ae6325f9bc2899ca8bcfbfeccc211614',
     'src/third_party/usrsctp/usrsctplib':
@@ -118,7 +118,7 @@
     'src/third_party/webdriver/pylib':
         Var('git_url') + '/external/selenium/py.git@8212c8017c92a1ba740caf01c1acefb3674a6a44',
     'src/third_party/webgl_conformance':
-        Var('git_url') + '/chromium/deps/webgl/sdk/tests.git@d05d6b35275d1e52db05cd64b39897e4e5c123b6',
+        Var('git_url') + '/chromium/deps/webgl/sdk/tests.git@effa22ac00aa8fd88b55fc49a846d5dd39168173',
     'src/third_party/webpagereplay':
         Var('git_url') + '/external/web-page-replay.git@b4773b3704bce171f67f25bccdae6125296fea6e',
     'src/third_party/webrtc':
@@ -126,17 +126,17 @@
     'src/third_party/yasm/source/patched-yasm':
         Var('git_url') + '/chromium/deps/yasm/patched-yasm.git@c960eb11ccda80b10ed50be39df4f0663b371d1d',
     'src/tools/deps2git':
-        Var('git_url') + '/chromium/tools/deps2git.git@92b6fca498aa9d9cca70e80b25a4c41313a537f0',
+        Var('git_url') + '/chromium/tools/deps2git.git@89559a9d3ade3e71993db9cc5959fcc58ed14b9e',
     'src/tools/grit':
         Var('git_url') + '/external/grit-i18n.git@11e589a0b4a958ad1b5411692ee576cbee9f6ca5',
     'src/tools/gyp':
-        Var('git_url') + '/external/gyp.git@0635a6e266eb4cdd01e942331997f76b3737be79',
+        Var('git_url') + '/external/gyp.git@072660db6ec1fafc1e0997439b5015913f0b9aa5',
     'src/tools/page_cycler/acid3':
         Var('git_url') + '/chromium/deps/acid3.git@6be0a66a1ebd7ebc5abc1b2f405a945f6d871521',
     'src/tools/swarm_client':
-        Var('git_url') + '/chromium/tools/swarm_client.git@f24e5c3a284b836668b956cbbe7d92c62c90f303',
+        Var('git_url') + '/chromium/tools/swarm_client.git@141ef86f4abf255e578320bfe6e42006c251bc39',
     'src/v8':
-        Var('git_url') + '/external/v8.git@71f9fca5cfb606009211e0631f33b76cc2ddce3c',
+        Var('git_url') + '/external/v8.git@4000f228dd279f96628ed845f1e81d01ba7e14d8',
 }
 
 deps_os = {
@@ -167,7 +167,7 @@
         'src/third_party/lss':
             Var('git_url') + '/external/linux-syscall-support/lss.git@e6c7682c40c27527894fbb8bcba38f77edbbb6b7',
         'src/third_party/openssl':
-            Var('git_url') + '/chromium/deps/openssl.git@8f54aac19a36d72ea630c813cae51c81a3cc0d78',
+            Var('git_url') + '/chromium/deps/openssl.git@fc8760c61cfe4155d0636a956ed70726c4d19dd2',
     },
     'ios':
     {
@@ -276,13 +276,13 @@
     'unix':
     {
         'src/chrome/tools/test/reference_build/chrome_linux':
-            Var('git_url') + '/chromium/reference_builds/chrome_linux.git@d2c2fe41693de657ef707f59d6f43aa64dca71a2',
+            Var('git_url') + '/chromium/reference_builds/chrome_linux.git@5bcc748379d5c5b734d41f8fc834d38f562e210b',
         'src/third_party/chromite':
             Var('git_url') + '/chromiumos/chromite.git@cbdd21c5ea76aa93ba4619a6d253697765f4de1f',
         'src/third_party/cros_dbus_cplusplus/source':
             Var('git_url') + '/chromiumos/third_party/dbus-cplusplus.git@5e8f6d9db5c2abfb91d91f751184f25bb5cd0900',
         'src/third_party/cros_system_api':
-            Var('git_url') + '/chromiumos/platform/system_api.git@0be3036f55a52d274d547d6be0d0b8ab201d7d24',
+            Var('git_url') + '/chromiumos/platform/system_api.git@99bce39f55240926a75454bb70998ab9f5ce9f13',
         'src/third_party/freetype2/src':
             Var('git_url') + '/chromium/src/third_party/freetype2.git@d699c2994ecc178c4ed05ac2086061b2034c2178',
         'src/third_party/gold':
@@ -294,7 +294,7 @@
         'src/third_party/mtpd/source':
             Var('git_url') + '/chromiumos/platform/mtpd.git@5be739c938a0a229ba9479b00b180e1f9c843e81',
         'src/third_party/openssl':
-            Var('git_url') + '/chromium/deps/openssl.git@8f54aac19a36d72ea630c813cae51c81a3cc0d78',
+            Var('git_url') + '/chromium/deps/openssl.git@fc8760c61cfe4155d0636a956ed70726c4d19dd2',
         'src/third_party/pyelftools':
             Var('git_url') + '/chromiumos/third_party/pyelftools.git@bdc1d380acd88d4bfaf47265008091483b0d614e',
         'src/third_party/swig/linux':
@@ -313,7 +313,7 @@
         'src/third_party/bison':
             Var('git_url') + '/chromium/deps/bison.git@083c9a45e4affdd5464ee2b224c2df649c6e26c3',
         'src/third_party/cygwin':
-            Var('git_url') + '/chromium/deps/cygwin.git@b0a440065673ae5a93e51b6a1e4765b71aaad59d',
+            Var('git_url') + '/chromium/deps/cygwin.git@c89e446b273697fadf3a10ff1007a97c0b7de6df',
         'src/third_party/gnu_binutils':
             Var('git_url') + '/native_client/deps/third_party/gnu_binutils.git@f4003433b61b25666565690caf3d7a7a1a4ec436',
         'src/third_party/gperf':
@@ -479,6 +479,36 @@
     {
     'action':
          [
+    'download_from_google_storage',
+    '--platform=win32',
+    '--directory',
+    '--bucket',
+    'chromium-gn',
+    'src/tools/gn/bin/win'
+],
+    'pattern':
+         '\\.sha1$',
+    'name':
+         'gn_win'
+},
+    {
+    'action':
+         [
+    'download_from_google_storage',
+    '--platform="linux*"',
+    '--directory',
+    '--bucket',
+    'chromium-gn',
+    'src/tools/gn/bin/linux'
+],
+    'pattern':
+         '\\.sha1$',
+    'name':
+         'gn_linux'
+},
+    {
+    'action':
+         [
     'python',
     'src/build/gyp_chromium'
 ],
diff --git a/.gitignore b/.gitignore
index 45c2cbf..767bdf5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -305,6 +305,9 @@
 /third_party/yasm/yasm.xml
 /tools/deps2git/
 /tools/distcc
+/tools/gn/bin/linux
+/tools/gn/bin/mac
+/tools/gn/bin/win
 /tools/grit
 /tools/gyp
 /tools/histograms
diff --git a/AUTHORS b/AUTHORS
index 9b4a420..98591fb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -229,6 +229,7 @@
 Ravi Phaneendra Kasibhatla <ravi.kasibhatla@motorola.com>
 Rene Bolldorf <rb@radix.io>
 Rijubrata Bhaumik <rijubrata.bhaumik@intel.com>
+Rob Buis <rob.buis@samsung.com>
 Robert Bear Travis <bear.travis@gmail.com>
 Robert Bear Travis <betravis@adobe.com>
 Robert Goldberg <goldberg@adobe.com>
@@ -248,6 +249,7 @@
 Sanne Wouda <sanne.wouda@gmail.com>
 Sathish Kuppuswamy <sathish.kuppuswamy@intel.com>
 Satoshi Matsuzaki <satoshi.matsuzaki@gmail.com>
+Scott Blomquist <sblom@microsoft.com>
 Sean Bryant <sean@cyberwang.net>
 Seo Sanghyeon <sanxiyn@gmail.com>
 Seokju Kwon <seokju.kwon@gmail.com>
diff --git a/DEPS b/DEPS
index ce679d4..784be97 100644
--- a/DEPS
+++ b/DEPS
@@ -1,3 +1,14 @@
+# This file is automatically processed to create .DEPS.git which is the file
+# that gclient uses under git.
+#
+# See http://code.google.com/p/chromium/wiki/UsingGit
+#
+# To test manually, run:
+#   python tools/deps2git/deps2git.py -o .DEPS.git
+#   gclient runhooks
+# DO NOT CHECK IN CHANGES TO .DEPS.git. It will be automatically updated by
+# a bot when you modify this one.
+#
 # When adding a new dependency, please update the top-level .gitignore file
 # to list the dependency's destination directory.
 
@@ -8,15 +19,15 @@
   "sourceforge_url": "http://svn.code.sf.net/p/%(repo)s/code",
   "webkit_trunk": "http://src.chromium.org/blink/trunk",
   "nacl_trunk": "http://src.chromium.org/native_client/trunk",
-  "webkit_revision": "160175",
+  "webkit_revision": "160934",
   "chromium_git": "https://chromium.googlesource.com",
   "chromiumos_git": "https://chromium.googlesource.com/chromiumos",
   "skia_git": "https://skia.googlesource.com",
-  "swig_revision": "69281",
-  "nacl_revision": "12284",
+  "swig_revision": "230490",
+  "nacl_revision": "12321",
   # After changing nacl_revision, run 'glient sync' and check native_client/DEPS
   # to update other nacl_*_revision's.
-  "nacl_tools_revision": "12279",  # native_client/DEPS: tools_rev
+  "nacl_tools_revision": "12289",  # native_client/DEPS: tools_rev
   "gtm_revision": "616",
 
   "libphonenumber_revision": "621",
@@ -30,12 +41,12 @@
 
   "sfntly_revision": "228",
   "lighttpd_revision": "33737",
-  "skia_revision": "11899",
-  "skia_hash": "56c55885882870aff9fd5e5a7c085c6f7a920942",
+  "skia_revision": "12012",
+  "skia_hash": "e8166a5e9e9656909029d14d284c15c47acb653f",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
-  "v8_revision": "17310",
+  "v8_revision": "17429",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
@@ -45,11 +56,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarm_client
   # and whatever else without interference from each other.
-  "swarm_revision": "228254",
+  "swarm_revision": "230741",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openssl
   # and whatever else without interference from each other.
-  "openssl_revision": "207965",
+  "openssl_revision": "231572",
 }
 
 deps = {
@@ -67,7 +78,7 @@
 
   "src/third_party/angle_dx11":
     Var("chromium_git") +
-    "/external/angle.git@b992a7d282a996d15da3e194695ddebff50fd956",
+    "/external/angle.git@0f0edf94bfe1fc28979b0d12747a900164bb966a",
 
   "src/third_party/trace-viewer":
     (Var("googlecode_url") % "trace-viewer") + "/trunk@1040",
@@ -104,7 +115,7 @@
     (Var("googlecode_url") % "grit-i18n") + "/trunk@136",
 
   "src/tools/gyp":
-    (Var("googlecode_url") % "gyp") + "/trunk@1765",
+    (Var("googlecode_url") % "gyp") + "/trunk@1773",
 
   "src/tools/swarm_client":
     "/trunk/tools/swarm_client@" + Var("swarm_revision"),
@@ -151,7 +162,7 @@
     (Var("googlecode_url") % "bidichecker") + "/trunk/lib@4",
 
   "src/third_party/webgl_conformance":
-    "/trunk/deps/third_party/webgl/sdk/tests@229432",
+    "/trunk/deps/third_party/webgl/sdk/tests@230853",
 
   "src/third_party/swig/Lib":
     "/trunk/deps/third_party/swig/Lib@" + Var("swig_revision"),
@@ -229,7 +240,7 @@
          Var("libphonenumber_revision"),
 
   "src/tools/deps2git":
-    "/trunk/tools/deps2git@214390",
+    "/trunk/tools/deps2git@230538",
 
   "src/third_party/webpagereplay":
     (Var("googlecode_url") % "web-page-replay") + "/trunk@522",
@@ -241,10 +252,10 @@
     "/trunk/deps/third_party/opus@185324",
 
   "src/media/cdm/ppapi/api":
-    "/trunk/deps/cdm@229868",
+    "/trunk/deps/cdm@230180",
 
   "src/third_party/mesa/src":
-    "/trunk/deps/third_party/mesa@210110",
+    "/trunk/deps/third_party/mesa@229994",
 
   "src/third_party/cld_2/src":
     (Var("googlecode_url") % "cld2") + "/trunk@84",
@@ -257,7 +268,7 @@
       "/trunk/deps/reference_builds/chrome_win@221746",
 
     "src/third_party/cygwin":
-      "/trunk/deps/third_party/cygwin@229213",
+      "/trunk/deps/third_party/cygwin@231940",
 
     "src/third_party/python_26":
       "/trunk/tools/third_party/python_26@89111",
@@ -394,7 +405,7 @@
   "unix": {
     # Linux, really.
     "src/chrome/tools/test/reference_build/chrome_linux":
-      "/trunk/deps/reference_builds/chrome_linux@221746",
+      "/trunk/deps/reference_builds/chrome_linux@230875",
 
     "src/third_party/xdg-utils":
       "/trunk/deps/third_party/xdg-utils@203785",
@@ -428,7 +439,7 @@
     # For Linux and Chromium OS.
     "src/third_party/cros_system_api":
       Var("chromiumos_git") + "/platform/system_api.git" +
-      "@0be3036f55a52d274d547d6be0d0b8ab201d7d24",
+      "@99bce39f55240926a75454bb70998ab9f5ce9f13",
 
     # Note that this is different from Android's freetype repo.
     "src/third_party/freetype2/src":
@@ -606,6 +617,27 @@
                "-s", "src/third_party/WebKit",
                "-o", "src/build/util/LASTCHANGE.blink"],
   },
+  # Pull GN binaries. This needs to be before running GYP below.
+  {
+    "name": "gn_win",
+    "pattern": "\\.sha1$",
+    "action": [ "download_from_google_storage",
+                "--platform=win32",
+                "--directory",
+                "--bucket", "chromium-gn",
+                "src/tools/gn/bin/win",
+    ],
+  },
+  {
+    "name": "gn_linux",
+    "pattern": "\\.sha1$",
+    "action": [ "download_from_google_storage",
+                "--platform=\"linux*\"",
+                "--directory",
+                "--bucket", "chromium-gn",
+                "src/tools/gn/bin/linux",
+    ],
+  },
   {
     # A change to a .gyp, .gypi, or to GYP itself should run the generator.
     "name": "gyp",
diff --git a/GypAndroid.darwin-arm.mk b/GypAndroid.darwin-arm.mk
index 9b2ae57..0e7dbce 100644
--- a/GypAndroid.darwin-arm.mk
+++ b/GypAndroid.darwin-arm.mk
@@ -119,7 +119,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.darwin-arm.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.darwin-arm.mk
@@ -212,7 +211,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.darwin-arm.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.darwin-arm.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/ui.target.darwin-arm.mk
diff --git a/GypAndroid.darwin-mips.mk b/GypAndroid.darwin-mips.mk
index b1b26b2..85ebb0b 100644
--- a/GypAndroid.darwin-mips.mk
+++ b/GypAndroid.darwin-mips.mk
@@ -115,7 +115,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.darwin-mips.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.darwin-mips.mk
@@ -208,7 +207,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.darwin-mips.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.darwin-mips.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/ui.target.darwin-mips.mk
diff --git a/GypAndroid.darwin-x86.mk b/GypAndroid.darwin-x86.mk
index ad259ad..2748e22 100644
--- a/GypAndroid.darwin-x86.mk
+++ b/GypAndroid.darwin-x86.mk
@@ -123,7 +123,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.darwin-x86.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.darwin-x86.mk
@@ -226,7 +225,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.darwin-x86.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.darwin-x86.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/ui.target.darwin-x86.mk
diff --git a/GypAndroid.linux-arm.mk b/GypAndroid.linux-arm.mk
index ef552ec..3ad6c56 100644
--- a/GypAndroid.linux-arm.mk
+++ b/GypAndroid.linux-arm.mk
@@ -119,7 +119,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.linux-arm.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.linux-arm.mk
@@ -212,7 +211,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.linux-arm.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.linux-arm.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/ui.target.linux-arm.mk
diff --git a/GypAndroid.linux-mips.mk b/GypAndroid.linux-mips.mk
index cf08110..c94b9a7 100644
--- a/GypAndroid.linux-mips.mk
+++ b/GypAndroid.linux-mips.mk
@@ -115,7 +115,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.linux-mips.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.linux-mips.mk
@@ -208,7 +207,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.linux-mips.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.linux-mips.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/ui.target.linux-mips.mk
diff --git a/GypAndroid.linux-x86.mk b/GypAndroid.linux-x86.mk
index 42f23f8..ea7f6ba 100644
--- a/GypAndroid.linux-x86.mk
+++ b/GypAndroid.linux-x86.mk
@@ -123,7 +123,6 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_dom.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_html.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform.target.linux-x86.mk
-include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_platform_geometry.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_prerequisites.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_remaining.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/core/webcore_rendering.target.linux-x86.mk
@@ -226,7 +225,7 @@
 include $(LOCAL_PATH)/ui/gl/surface_jni_headers.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/keycode_converter.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/native_theme/native_theme.target.linux-x86.mk
-include $(LOCAL_PATH)/ui/shell_dialogs.target.linux-x86.mk
+include $(LOCAL_PATH)/ui/shell_dialogs/shell_dialogs.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/snapshot/snapshot.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/surface/surface.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/ui.target.linux-x86.mk
diff --git a/WATCHLISTS b/WATCHLISTS
index 0ee960f..4f13358 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -268,9 +268,6 @@
     'ftp': {
       'filepath': 'ftp',
     },
-    'fullscreen_controller': {
-      'filepath': 'fullscreen_controller',
-    },
     'geolocation': {
       'filepath': 'chrome/browser/geolocation/|'\
                   'content/browser/geolocation|'\
@@ -411,6 +408,8 @@
     },
     'ozone': {
       'filepath': 'ui/base/ozone/|'\
+        'ui/events/ozone/|'\
+        'ui/gfx/ozone/|'\
         'ui/gl/gl_.*egl.*|'\
         'ui/gl/gl_.*ozone.*'
     },
@@ -713,7 +712,6 @@
     'filebrowse': ['rginda+watch@chromium.org'],
     'filesapp': ['mtomasz+watch@chromium.org'],
     'ftp': ['phajdan.jr@chromium.org'],
-    'fullscreen_controller': ['scheib+watch@chromium.org'],
     'geolocation': ['mvanouwerkerk@chromium.org'],
     'gfx_geometry': ['cc-bugs@chromium.org'],
     'gfx_image': ['rsesek+watch@chromium.org'],
@@ -728,7 +726,7 @@
                 'melevin+watch@chromium.org', 'dougw+watch@chromium.org',
                 'kmadhusu+watch@chromium.org', 'dhollowa+watch@chromium.org',
                 'jfweitz+watch@chromium.org', 'skanuj+watch@chromium.org',
-                'donnd+watch@chromium.org', 'mad+watch@chromium.org'],
+                'donnd+watch@chromium.org'],
     'ipc': ['jam@chromium.org', 'darin-cc@chromium.org'],
     'linux_fonts': ['derat+watch@chromium.org'],
     'linux_sandboxing': ['agl@chromium.org', 'jln+watch@chromium.org'],
@@ -742,6 +740,7 @@
                 'isherman@chromium.org',
                 'asvitkine+watch@chromium.org'],
     'mojo': ['aa@chromium.org',
+             'abarth@chromium.org',
              'ben+mojo@chromium.org',
              'darin@chromium.org',
              'viettrungluu+watch@chromium.org'],
@@ -756,7 +755,8 @@
             'pedrosimonetti+watch@chromium.org'],
     'omnibox': ['suzhe@chromium.org'],
     'options': ['dbeam+watch-options@chromium.org'],
-    'ozone': ['rjkroege@chromium.org', 'kalyan.kondapally@intel.com'],
+    'ozone': ['kalyan.kondapally@intel.com', 'ozone-reviews@chromium.org',
+              'rjkroege@chromium.org'],
     'panels': ['dimich@chromium.org', 'jennb@chromium.org',
                'dcheng@chromium.org', 'jianli@chromium.org'],
     'pepper_api': ['piman+watch@chromium.org',
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 824e610..23f63f0 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -5,8 +5,12 @@
   'variables': {
     'chromium_code': 1,
   },
-  'includes': [
-    'android_webview_tests.gypi',
+  'conditions': [
+    ['android_webview_build==0', {
+      'includes': [
+        'android_webview_tests.gypi',
+      ],
+    }],
   ],
   'targets': [
     {
@@ -17,6 +21,11 @@
         'android_webview_common',
       ],
       'conditions': [
+        # Avoid clashes between the versions of this library built with
+        # android_webview_build==1 by using a different name prefix.
+        [ 'android_webview_build==0', {
+          'product_prefix': 'libstandalone',
+        }],
         # The general approach is to allow the executable target to choose
         # the allocator, but as in the WebView case we are building a library
         # only, put the dependency on the allocator here
@@ -88,11 +97,11 @@
         '../components/components.gyp:visitedlink_renderer',
         '../components/components.gyp:web_contents_delegate_android',
         '../content/content.gyp:content_app_both',
-        '../skia/skia.gyp:skia',
         '../gpu/gpu.gyp:command_buffer_service',
         '../gpu/gpu.gyp:gles2_implementation',
+        '../skia/skia.gyp:skia',
         '../ui/gl/gl.gyp:gl',
-        '../ui/ui.gyp:shell_dialogs',
+        '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
         '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
         'android_webview_pak',
       ],
diff --git a/android_webview/android_webview_common.target.darwin-arm.mk b/android_webview/android_webview_common.target.darwin-arm.mk
index fc53ec4..3831659 100644
--- a/android_webview/android_webview_common.target.darwin-arm.mk
+++ b/android_webview/android_webview_common.target.darwin-arm.mk
@@ -108,13 +108,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_common.target.darwin-mips.mk b/android_webview/android_webview_common.target.darwin-mips.mk
index 0d522de..913d731 100644
--- a/android_webview/android_webview_common.target.darwin-mips.mk
+++ b/android_webview/android_webview_common.target.darwin-mips.mk
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_common.target.darwin-x86.mk b/android_webview/android_webview_common.target.darwin-x86.mk
index a45e9a9..16bd5d8 100644
--- a/android_webview/android_webview_common.target.darwin-x86.mk
+++ b/android_webview/android_webview_common.target.darwin-x86.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -221,13 +221,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_common.target.linux-arm.mk b/android_webview/android_webview_common.target.linux-arm.mk
index fc53ec4..3831659 100644
--- a/android_webview/android_webview_common.target.linux-arm.mk
+++ b/android_webview/android_webview_common.target.linux-arm.mk
@@ -108,13 +108,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_common.target.linux-mips.mk b/android_webview/android_webview_common.target.linux-mips.mk
index 0d522de..913d731 100644
--- a/android_webview/android_webview_common.target.linux-mips.mk
+++ b/android_webview/android_webview_common.target.linux-mips.mk
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_common.target.linux-x86.mk b/android_webview/android_webview_common.target.linux-x86.mk
index a45e9a9..16bd5d8 100644
--- a/android_webview/android_webview_common.target.linux-x86.mk
+++ b/android_webview/android_webview_common.target.linux-x86.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -221,13 +221,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi
index e416559..ffbd8e5 100644
--- a/android_webview/android_webview_tests.gypi
+++ b/android_webview/android_webview_tests.gypi
@@ -14,7 +14,7 @@
       'variables': {
         'apk_name': 'AndroidWebView',
         'java_in_dir': 'test/shell',
-        'native_lib_target': 'libwebviewchromium',
+        'native_lib_target': 'libstandalonelibwebviewchromium',
         'resource_dir': 'test/shell/res',
         'additional_input_paths': [
           '<(PRODUCT_DIR)/android_webview_apk/assets/webviewchromium.pak',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 7adc6dd..ca3a5b8 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -247,12 +247,20 @@
 void AwBrowserContext::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   // TODO(toyoshim): Android is not supported yet.
   callback.Run(false);
 }
 
+void AwBrowserContext::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+}
+
 net::URLRequestContextGetter*
 AwBrowserContext::GetMediaRequestContextForRenderProcess(
     int renderer_child_id) {
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index c7c3ea9..d77393c 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -90,8 +90,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+        int render_process_id,
+        int render_view_id,
+        int bridge_id,
+        const GURL& requesting_frame) OVERRIDE;
   virtual content::ResourceContext* GetResourceContext() OVERRIDE;
   virtual content::DownloadManagerDelegate*
       GetDownloadManagerDelegate() OVERRIDE;
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 97bdf1f..05658c1 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -24,6 +24,7 @@
 #include "content/public/common/url_constants.h"
 #include "grit/ui_resources.h"
 #include "net/android/network_library.h"
+#include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_info.h"
 #include "ui/base/l10n/l10n_util_android.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -265,6 +266,18 @@
     *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
 }
 
+void AwContentBrowserClient::SelectClientCertificate(
+      int render_process_id,
+      int render_view_id,
+      const net::HttpNetworkSession* network_session,
+      net::SSLCertRequestInfo* cert_request_info,
+      const base::Callback<void(net::X509Certificate*)>& callback) {
+  LOG(INFO) << "Client certificate request from "
+        << cert_request_info->host_and_port
+        << " rejected. (Client certificates not supported in WebView)";
+  callback.Run(NULL);
+}
+
 WebKit::WebNotificationPresenter::Permission
     AwContentBrowserClient::CheckDesktopNotificationPermission(
         const GURL& source_url,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index afa29cb..f0309c9 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -103,6 +103,12 @@
       bool strict_enforcement,
       const base::Callback<void(bool)>& callback,
       content::CertificateRequestResultType* result) OVERRIDE;
+  virtual void SelectClientCertificate(
+      int render_process_id,
+      int render_view_id,
+      const net::HttpNetworkSession* network_session,
+      net::SSLCertRequestInfo* cert_request_info,
+      const base::Callback<void(net::X509Certificate*)>& callback) OVERRIDE;
   virtual WebKit::WebNotificationPresenter::Permission
       CheckDesktopNotificationPermission(
           const GURL& source_url,
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 642d943..0b5312a 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -290,6 +290,19 @@
   return true;
 }
 
+bool AwResourceDispatcherHostDelegate::AcceptSSLClientCertificateRequest(
+    net::URLRequest* request,
+    net::SSLCertRequestInfo* cert_info) {
+  // WebView does not support client certificate selection, however it does
+  // send a no-certificate response to the server to allow it decide how to
+  // proceed. The base class returns false here, which causes the entire
+  // resource request to be abort. We don't want that, so we must return true
+  // here (and subsequently complete the request in
+  // AwContentBrowserClient::SelectClientCertificate) to get the intended
+  // behavior.
+  return true;
+}
+
 content::ResourceDispatcherHostLoginDelegate*
     AwResourceDispatcherHostDelegate::CreateLoginDelegate(
         net::AuthChallengeInfo* auth_info,
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index 570f22f..b5009e0 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -48,6 +48,10 @@
       ScopedVector<content::ResourceThrottle>* throttles) OVERRIDE;
   virtual bool AcceptAuthRequest(net::URLRequest* request,
                                  net::AuthChallengeInfo* auth_info) OVERRIDE;
+  virtual bool AcceptSSLClientCertificateRequest(
+      net::URLRequest* request,
+      net::SSLCertRequestInfo* cert_info) OVERRIDE;
+
   virtual content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
       net::URLRequest* request) OVERRIDE;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 5e1ab63..7032b72 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -19,7 +19,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Message;
-import android.os.Process;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -103,13 +102,6 @@
      * dispatching of view methods through the containing view.
      */
     public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate {
-        /**
-         * @see View#onScrollChanged(int, int, int, int)
-         *
-         * TODO(mkosiba): WebViewClassic calls this, AwContents doesn't. Check if there
-         * are any cases we're missing, if not - remove.
-         */
-        void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
 
         /**
          * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean);
@@ -367,6 +359,12 @@
             if (mNativeAwContents == 0) return;
             nativeSetFixedLayoutSize(mNativeAwContents, widthDip, heightDip);
         }
+
+        @Override
+        public boolean isLayoutParamsHeightWrapContent() {
+            return mContainerView.getLayoutParams() != null &&
+                mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
+        }
     }
 
     //--------------------------------------------------------------------------------------------
@@ -516,11 +514,20 @@
             InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
             boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer,
             boolean supportsLegacyQuirks) {
+        this(browserContext, containerView, internalAccessAdapter, contentsClient,
+                layoutSizer, new AwSettings(containerView.getContext(),
+                        isAccessFromFileURLsGrantedByDefault, supportsLegacyQuirks));
+    }
+
+    public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
+            InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
+            AwLayoutSizer layoutSizer, AwSettings settings) {
         mBrowserContext = browserContext;
         mContainerView = containerView;
         mInternalAccessAdapter = internalAccessAdapter;
         mContentsClient = contentsClient;
         mLayoutSizer = layoutSizer;
+        mSettings = settings;
         mDIPScale = DeviceDisplayInfo.create(mContainerView.getContext()).getDIPScale();
         mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
         mLayoutSizer.setDIPScale(mDIPScale);
@@ -530,10 +537,6 @@
         mIoThreadClient = new IoThreadClientImpl();
         mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
 
-        boolean hasInternetPermission = mContainerView.getContext().checkPermission(
-                    android.Manifest.permission.INTERNET,
-                    Process.myPid(),
-                    Process.myUid()) == PackageManager.PERMISSION_GRANTED;
         AwSettings.ZoomSupportChangeListener zoomListener =
                 new AwSettings.ZoomSupportChangeListener() {
                     @Override
@@ -543,11 +546,11 @@
                     }
 
                 };
-        mSettings = new AwSettings(mContainerView.getContext(), hasInternetPermission, zoomListener,
-                isAccessFromFileURLsGrantedByDefault, mDIPScale, supportsLegacyQuirks);
+        mSettings.setZoomListener(zoomListener);
         mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
         mSettings.setDefaultVideoPosterURL(
                 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
+        mSettings.setDIPScale(mDIPScale);
         mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate(),
                 new OverScroller(mContainerView.getContext()));
 
@@ -555,7 +558,7 @@
         setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
         mContainerView.addOnLayoutChangeListener(new AwLayoutChangeListener());
 
-        setNewAwContents(nativeInit(browserContext));
+        setNewAwContents(nativeInit(mBrowserContext));
 
         onVisibilityChanged(mContainerView, mContainerView.getVisibility());
         onWindowVisibilityChanged(mContainerView.getWindowVisibility());
@@ -1223,10 +1226,27 @@
         return mContentViewCore.onKeyUp(keyCode, event);
     }
 
+    private boolean isDpadEvent(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_DPAD_CENTER:
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                case KeyEvent.KEYCODE_DPAD_UP:
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent)
      */
     public boolean dispatchKeyEvent(KeyEvent event) {
+        if (isDpadEvent(event)) {
+            mSettings.setSpatialNavigationEnabled(true);
+        }
         return mContentViewCore.dispatchKeyEvent(event);
     }
 
@@ -1485,6 +1505,10 @@
     public boolean onTouchEvent(MotionEvent event) {
         if (mNativeAwContents == 0) return false;
 
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mSettings.setSpatialNavigationEnabled(false);
+        }
+
         mScrollOffsetManager.setProcessingTouchEvent(true);
         boolean rv = mContentViewCore.onTouchEvent(event);
         mScrollOffsetManager.setProcessingTouchEvent(false);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
index 1f7bb24..41989dd 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
@@ -43,8 +43,7 @@
 public abstract class AwContentsClient {
 
     private static final String TAG = "AwContentsClient";
-    private final AwContentsClientCallbackHelper mCallbackHelper =
-        new AwContentsClientCallbackHelper(this);
+    private final AwContentsClientCallbackHelper mCallbackHelper;
 
     private AwWebContentsObserver mWebContentsObserver;
 
@@ -56,6 +55,15 @@
 
     private static final int INVALID_COLOR = 0;
 
+    public AwContentsClient() {
+        this(Looper.myLooper());
+    }
+
+    // Alllow injection of the callback thread, for testing.
+    public AwContentsClient(Looper looper) {
+        mCallbackHelper = new AwContentsClientCallbackHelper(looper, this);
+    }
+
     class AwWebContentsObserver extends WebContentsObserverAndroid {
         public AwWebContentsObserver(ContentViewCore contentViewCore) {
             super(contentViewCore);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
index 8b9fcb6..12f28ae 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
@@ -86,7 +86,13 @@
 
     private final AwContentsClient mContentsClient;
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+    private final Handler mHandler;
+
+    private class MyHandler extends Handler {
+        private MyHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
@@ -142,7 +148,8 @@
         }
     };
 
-    public AwContentsClientCallbackHelper(AwContentsClient contentsClient) {
+    public AwContentsClientCallbackHelper(Looper looper, AwContentsClient contentsClient) {
+        mHandler = new MyHandler(looper);
         mContentsClient = contentsClient;
     }
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
index c3a9ec9..3b996a0 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
@@ -58,6 +58,7 @@
         void requestLayout();
         void setMeasuredDimension(int measuredWidth, int measuredHeight);
         void setFixedLayoutSize(int widthDip, int heightDip);
+        boolean isLayoutParamsHeightWrapContent();
     }
 
     /**
@@ -225,14 +226,34 @@
     // call from onSizeChanged, since onSizeChanged won't fire if the view's physical size doesn't
     // change.
     private void updateFixedLayoutSize(int w, int h, float pageScaleFactor) {
-        // If the WebView's measuredDimension depends on the size of its contents (which is the
-        // case if any of the measurement modes are AT_MOST or UNSPECIFIED) the viewport size
-        // cannot be directly calculated from the size as that can result in the layout being
-        // unstable or unpredictable.
-        // If both the width and height are fixed (specified by the parent) then content size
+        boolean wrapContentForHeight = mDelegate.isLayoutParamsHeightWrapContent();
+        // If the WebView's size in the Android view system depends on the size of its contents then
+        // the viewport size cannot be directly calculated from the WebView's physical size as that
+        // can result in the layout being unstable (for example loading the following contents
+        //   <div style="height:150%">a</a>
+        // would cause the WebView to indefinitely attempt to increase its height by 50%).
+        // If both the width and height are fixed (specified by the parent View) then content size
         // changes will not cause subsequent layout passes and so we don't need to do anything
         // special.
-        if ((mWidthMeasurementIsFixed && mHeightMeasurementIsFixed) || pageScaleFactor == 0) {
+        // We assume the width is 'fixed' if the parent View specified an EXACT or an AT_MOST
+        // measureSpec for the width (in which case the AT_MOST upper bound is the width).
+        // That means that the WebView will ignore LayoutParams.width set to WRAP_CONTENT and will
+        // instead try to take up as much width as possible. This is necessary because it's not
+        // practical to do web layout without a set width.
+        // For height the behavior is different because for a given width it is possible to
+        // calculate the minimum height required to display all of the content. As such the WebView
+        // can size itself vertically to match the content height. Because certain container views
+        // (LinearLayout with a WRAP_CONTENT height, for example) can result in onMeasure calls with
+        // both EXACTLY and AT_MOST height measureSpecs it is not possible to infer the sizing
+        // policy for the whole subtree based on the parameters passed to the onMeasure call.
+        // For that reason the LayoutParams.height property of the WebView is used. This behaves
+        // more predictably and means that toggling the fixedLayoutSize mode (which can have
+        // significant impact on how the web contents is laid out) is a direct consequence of the
+        // developer's choice. The downside is that it could result in the Android layout being
+        // unstable if a parent of the WebView has a wrap_content height while the WebView itself
+        // has height set to match_parent. Unfortunately addressing this edge case is costly so it
+        // will have to stay as is (this is compatible with Classic behavior).
+        if ((mWidthMeasurementIsFixed && !wrapContentForHeight) || pageScaleFactor == 0) {
             setFixedLayoutSize(0, 0);
             return;
         }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index deee0a5..46fa65d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -4,10 +4,11 @@
 
 package org.chromium.android_webview;
 
+import android.content.pm.PackageManager;
 import android.content.Context;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.provider.Settings;
 import android.webkit.WebSettings.PluginState;
 import android.webkit.WebSettings;
@@ -44,8 +45,9 @@
 
     // Values passed in on construction.
     private final boolean mHasInternetPermission;
-    private final ZoomSupportChangeListener mZoomChangeListener;
-    private final double mDIPScale;
+
+    private ZoomSupportChangeListener mZoomChangeListener;
+    private double mDIPScale = 1.0;
 
     // Lock to protect all settings.
     private final Object mAwSettingsLock = new Object();
@@ -81,6 +83,7 @@
     private boolean mMediaPlaybackRequiresUserGesture = true;
     private String mDefaultVideoPosterURL;
     private float mInitialPageScalePercent = 0;
+    private boolean mSpatialNavigationEnabled;  // Default depends on device features.
 
     private final boolean mSupportLegacyQuirks;
 
@@ -129,7 +132,11 @@
         private Handler mHandler;
 
         EventHandler() {
-            mHandler = new Handler(Looper.getMainLooper()) {
+        }
+
+        void bindUiThread() {
+            if (mHandler != null) return;
+            mHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
                     @Override
                     public void handleMessage(Message msg) {
                         switch (msg.what) {
@@ -145,10 +152,23 @@
                 };
         }
 
+        void maybeRunOnUiThreadBlocking(Runnable r) {
+            if (mHandler != null) {
+                ThreadUtils.runOnUiThreadBlocking(r);
+            }
+        }
+
+        void maybePostOnUiThread(Runnable r) {
+            if (mHandler != null) {
+                mHandler.post(r);
+            }
+        }
+
         private void updateWebkitPreferencesLocked() {
             assert Thread.holdsLock(mAwSettingsLock);
             if (mNativeAwSettings == 0) return;
-            if (Looper.myLooper() == mHandler.getLooper()) {
+            if (mHandler == null) return;
+            if (ThreadUtils.runningOnUiThread()) {
                 updateWebkitPreferencesOnUiThreadLocked();
             } else {
                 // We're being called on a background thread, so post a message.
@@ -172,26 +192,27 @@
         public void onGestureZoomSupportChanged(boolean supportsGestureZoom);
     }
 
-    public AwSettings(Context context, boolean hasInternetPermission,
-            ZoomSupportChangeListener zoomChangeListener,
+    public AwSettings(Context context,
             boolean isAccessFromFileURLsGrantedByDefault,
-            double dipScale,
             boolean supportsLegacyQuirks) {
-        ThreadUtils.assertOnUiThread();
+       boolean hasInternetPermission = context.checkPermission(
+                    android.Manifest.permission.INTERNET,
+                    Process.myPid(),
+                    Process.myUid()) == PackageManager.PERMISSION_GRANTED;
         synchronized (mAwSettingsLock) {
             mHasInternetPermission = hasInternetPermission;
-            mZoomChangeListener = zoomChangeListener;
-            mDIPScale = dipScale;
-            mEventHandler = new EventHandler();
             mBlockNetworkLoads = !hasInternetPermission;
-
+            mEventHandler = new EventHandler();
             if (isAccessFromFileURLsGrantedByDefault) {
                 mAllowUniversalAccessFromFileURLs = true;
                 mAllowFileAccessFromFileURLs = true;
             }
 
             mUserAgent = LazyDefaultUserAgent.sInstance;
-            onGestureZoomSupportChanged(supportsGestureZoomLocked());
+
+            // Best-guess a sensible initial value based on the features supported on the device.
+            mSpatialNavigationEnabled = !context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_TOUCHSCREEN);
 
             // Respect the system setting for password echoing.
             mPasswordEchoEnabled = Settings.System.getInt(context.getContentResolver(),
@@ -213,15 +234,31 @@
         return mDIPScale;
     }
 
-    public void setWebContents(int nativeWebContents) {
+    void setDIPScale(double dipScale) {
+        synchronized (mAwSettingsLock) {
+            mDIPScale = dipScale;
+            // TODO(joth): This should also be synced over to native side, but right now
+            // the setDIPScale call is always followed by a setWebContents() which covers this.
+        }
+    }
+
+    void setZoomListener(ZoomSupportChangeListener zoomChangeListener) {
+        synchronized (mAwSettingsLock) {
+            mZoomChangeListener = zoomChangeListener;
+        }
+    }
+
+    void setWebContents(int nativeWebContents) {
         synchronized (mAwSettingsLock) {
             if (mNativeAwSettings != 0) {
                 nativeDestroy(mNativeAwSettings);
                 assert mNativeAwSettings == 0;  // nativeAwSettingsGone should have been called.
             }
             if (nativeWebContents != 0) {
+                mEventHandler.bindUiThread();
                 mNativeAwSettings = nativeInit(nativeWebContents);
                 nativeUpdateEverythingLocked(mNativeAwSettings);
+                onGestureZoomSupportChanged(supportsGestureZoomLocked());
             }
         }
     }
@@ -324,7 +361,7 @@
         synchronized (mAwSettingsLock) {
             if (mInitialPageScalePercent != scaleInPercent) {
                 mInitialPageScalePercent = scaleInPercent;
-                ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
                     @Override
                     public void run() {
                         if (mNativeAwSettings != 0) {
@@ -341,6 +378,20 @@
         return mInitialPageScalePercent;
     }
 
+    void setSpatialNavigationEnabled(boolean enable) {
+        synchronized (mAwSettingsLock) {
+            if (mSpatialNavigationEnabled != enable) {
+                mSpatialNavigationEnabled = enable;
+                mEventHandler.updateWebkitPreferencesLocked();
+            }
+        }
+    }
+
+    @CalledByNative
+    private boolean getSpatialNavigationLocked() {
+        return mSpatialNavigationEnabled;
+    }
+
     /**
      * See {@link android.webkit.WebSettings#setNeedInitialFocus}.
      */
@@ -377,7 +428,7 @@
         synchronized (mAwSettingsLock) {
             if (mAutoCompleteEnabled != enable) {
                 mAutoCompleteEnabled = enable;
-                ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
                     @Override
                     public void run() {
                         if (mNativeAwSettings != 0) {
@@ -423,7 +474,7 @@
                 mUserAgent = ua;
             }
             if (!oldUserAgent.equals(mUserAgent)) {
-                ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
                     @Override
                     public void run() {
                         if (mNativeAwSettings != 0) {
@@ -457,7 +508,7 @@
             if (mLoadWithOverviewMode != overview) {
                 mLoadWithOverviewMode = overview;
                 mEventHandler.updateWebkitPreferencesLocked();
-                ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
                     @Override
                     public void run() {
                         if (mNativeAwSettings != 0) {
@@ -1067,7 +1118,7 @@
     }
 
     @CalledByNative
-    private boolean getPasswordEchoEnabled() {
+    private boolean getPasswordEchoEnabledLocked() {
         return mPasswordEchoEnabled;
     }
 
@@ -1254,10 +1305,14 @@
 
     private void onGestureZoomSupportChanged(final boolean supportsGestureZoom) {
         // Always post asynchronously here, to avoid doubling back onto the caller.
-        ThreadUtils.postOnUiThread(new Runnable() {
+        mEventHandler.maybePostOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mZoomChangeListener.onGestureZoomSupportChanged(supportsGestureZoom);
+                synchronized (mAwSettingsLock) {
+                    if (mZoomChangeListener != null) {
+                        mZoomChangeListener.onGestureZoomSupportChanged(supportsGestureZoom);
+                    }
+                }
             }
         });
     }
@@ -1357,6 +1412,7 @@
 
     private void updateWebkitPreferencesOnUiThreadLocked() {
         if (mNativeAwSettings != 0) {
+            assert mEventHandler.mHandler != null;
             ThreadUtils.assertOnUiThread();
             nativeUpdateWebkitPreferencesLocked(mNativeAwSettings);
         }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
index 15ed6f7..b122a29 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -6,7 +6,6 @@
 
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -14,6 +13,7 @@
 import android.webkit.ConsoleMessage;
 import android.webkit.ValueCallback;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.content.browser.ContentViewCore;
 
 /**
@@ -131,7 +131,7 @@
 
         // TODO(sgurun) Remember the URL to cancel the reload behavior
         // if it is different than the most recent NavigationController entry.
-        final Handler handler = new Handler(Looper.getMainLooper()) {
+        final Handler handler = new Handler(ThreadUtils.getUiThreadLooper()) {
             @Override
             public void handleMessage(Message msg) {
                 switch(msg.what) {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
index 5d8b56b..357e922 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
@@ -20,6 +20,7 @@
         public int measuredHeight;
         public int fixedLayoutWidth;
         public int fixedLayoutHeight;
+        public boolean heightWrapContent;
 
         @Override
         public void requestLayout() {
@@ -38,6 +39,11 @@
             fixedLayoutWidth = widthDip;
             fixedLayoutHeight = heightDip;
         }
+
+        @Override
+        public boolean isLayoutParamsHeightWrapContent() {
+            return heightWrapContent;
+        }
     }
 
     private static final int FIRST_CONTENT_WIDTH = 101;
@@ -382,7 +388,7 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
-    public void testViewportWithWrapContentMeasureSpec() {
+    public void testViewportWithUnspecifiedMeasureSpec() {
         AwLayoutSizer layoutSizer = new AwLayoutSizer();
         LayoutSizerDelegate delegate = new LayoutSizerDelegate();
         layoutSizer.setDelegate(delegate);
@@ -391,7 +397,6 @@
         final int pageScale = 2;
         final int dipAndPageScale = (int) (dipScale * pageScale);
 
-
         int contentWidth = 800;
         int contentHeight = 400;
         int atMostWidth = contentWidth * dipAndPageScale;
@@ -431,6 +436,41 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    public void testViewportWithAtMostMeasureSpec() {
+        AwLayoutSizer layoutSizer = new AwLayoutSizer();
+        LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+        delegate.heightWrapContent = true;
+        layoutSizer.setDelegate(delegate);
+
+        final float dipScale = 1.5f;
+        final int pageScale = 2;
+        final int dipAndPageScale = (int) (dipScale * pageScale);
+
+        int contentWidth = 800;
+        int contentHeight = 400;
+        int contentWidthPix = contentWidth * dipAndPageScale;
+        int contentHeightPix = contentHeight * dipAndPageScale;
+
+        layoutSizer.setDIPScale(dipScale);
+        layoutSizer.onContentSizeChanged(contentWidth, contentHeight);
+        layoutSizer.onPageScaleChanged(pageScale);
+        layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(contentWidthPix, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(contentHeightPix * 2, MeasureSpec.AT_MOST));
+
+        assertTrue(delegate.setMeasuredDimensionCalled);
+        int measuredWidth = delegate.measuredWidth & View.MEASURED_SIZE_MASK;
+        int measuredHeight = delegate.measuredHeight & View.MEASURED_SIZE_MASK;
+
+        int sizeWidth = measuredWidth;
+        int sizeHeight = measuredHeight;
+        layoutSizer.onSizeChanged(sizeWidth, sizeHeight, 0, 0);
+
+        assertEquals(contentWidth, delegate.fixedLayoutWidth);
+        assertEquals(AwLayoutSizer.FIXED_LAYOUT_HEIGHT, delegate.fixedLayoutHeight);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
     public void testFixedLayoutViewportGoesBackToZeroWithWrapContentMeasureSpec() {
         AwLayoutSizer layoutSizer = new AwLayoutSizer();
         LayoutSizerDelegate delegate = new LayoutSizerDelegate();
@@ -465,6 +505,7 @@
     public void testFixedLayoutSizeUpdatedOnPageScaleChangeItNoLayoutRequest() {
         AwLayoutSizer layoutSizer = new AwLayoutSizer();
         LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+        delegate.heightWrapContent = true;
         layoutSizer.setDelegate(delegate);
         layoutSizer.setDIPScale(DIP_SCALE);
 
@@ -514,4 +555,24 @@
 
         assertEquals(fixedLayoutWidth * 2, delegate.fixedLayoutWidth);
     }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testFixedLayoutSizeDoesNotDependOnMeasureSpec() {
+        AwLayoutSizer layoutSizer = new AwLayoutSizer();
+        LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+        delegate.heightWrapContent = false;
+        layoutSizer.setDelegate(delegate);
+        layoutSizer.setDIPScale(DIP_SCALE);
+
+        layoutSizer.onContentSizeChanged(TOO_LARGE_CONTENT_SIZE, TOO_LARGE_CONTENT_SIZE);
+        layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
+        layoutSizer.onMeasure(
+                MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST),
+                MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST));
+        layoutSizer.onSizeChanged(AT_MOST_MEASURE_SIZE, AT_MOST_MEASURE_SIZE, 0, 0);
+
+        assertEquals(0, delegate.fixedLayoutWidth);
+        assertEquals(0, delegate.fixedLayoutHeight);
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
index 2018de0..cc72322 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -370,4 +370,28 @@
             }
         });
     }
+
+    /**
+     * Returns whether a user can zoom the page in.
+     */
+    protected boolean canZoomInOnUiThread(final AwContents awContents) throws Throwable {
+        return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return awContents.canZoomIn();
+            }
+        });
+    }
+
+    /**
+     * Returns whether a user can zoom the page out.
+     */
+    protected boolean canZoomOutOnUiThread(final AwContents awContents) throws Throwable {
+        return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return awContents.canZoomOut();
+            }
+        });
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwViewportTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwViewportTest.java
index efe253a..5fcf02b 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwViewportTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwViewportTest.java
@@ -162,4 +162,61 @@
                 "matchMedia(\"screen and (device-height:" + (int)screenHeight + "px)\").matches");
         assertEquals("true", deviceHeightEqualsScreenHeight);
     }
+
+    @MediumTest
+    @Feature({"AndroidWebView"})
+    public void testMetaMergeContentQuirk() throws Throwable {
+        final TestAwContentsClient contentClient = new TestAwContentsClient();
+        final AwTestContainerView testContainerView =
+                createAwTestContainerViewOnMainSync(contentClient);
+        final AwContents awContents = testContainerView.getAwContents();
+        AwSettings settings = getAwSettingsOnUiThread(awContents);
+        CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
+
+        final int pageWidth = 3000;
+        final float pageScale = 1.0f;
+        final String page = String.format("<html><head>" +
+                "<meta name='viewport' content='width=%d' />" +
+                "<meta name='viewport' content='initial-scale=%.1f' />" +
+                "<meta name='viewport' content='user-scalable=0' />" +
+                "</head><body onload='document.title=document.body.clientWidth'></body></html>",
+                pageWidth, pageScale);
+
+        settings.setJavaScriptEnabled(true);
+        settings.setUseWideViewPort(true);
+        settings.setBuiltInZoomControls(true);
+        settings.setSupportZoom(true);
+
+        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
+        int width = Integer.parseInt(getTitleOnUiThread(awContents));
+        assertEquals(pageWidth, width);
+        assertEquals(pageScale, getScaleOnUiThread(awContents));
+        assertEquals(false, canZoomInOnUiThread(awContents));
+        assertEquals(false, canZoomOutOnUiThread(awContents));
+    }
+
+    @MediumTest
+    @Feature({"AndroidWebView"})
+    public void testMetaMergeContentQuirkOverrides() throws Throwable {
+        final TestAwContentsClient contentClient = new TestAwContentsClient();
+        final AwTestContainerView testContainerView =
+                createAwTestContainerViewOnMainSync(contentClient);
+        final AwContents awContents = testContainerView.getAwContents();
+        AwSettings settings = getAwSettingsOnUiThread(awContents);
+        CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
+
+        final int pageWidth = 3000;
+        final String page = String.format("<html><head>" +
+                "<meta name='viewport' content='width=device-width' />" +
+                "<meta name='viewport' content='width=%d' />" +
+                "</head><body onload='document.title=document.body.clientWidth'></body></html>",
+                pageWidth);
+
+        settings.setJavaScriptEnabled(true);
+        settings.setUseWideViewPort(true);
+
+        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
+        int width = Integer.parseInt(getTitleOnUiThread(awContents));
+        assertEquals(pageWidth, width);
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
index a0b3913..8e55c8a 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
@@ -73,24 +73,6 @@
         });
     }
 
-    private boolean canZoomInOnUiThread() throws Throwable {
-        return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return mAwContents.canZoomIn();
-            }
-        });
-    }
-
-    private boolean canZoomOutOnUiThread() throws Throwable {
-        return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return mAwContents.canZoomOut();
-            }
-        });
-    }
-
     private View getZoomControlsOnUiThread() throws Throwable {
         return runTestOnUiThreadAndGetResult(new Callable<View>() {
             @Override
@@ -155,7 +137,8 @@
                 @Override
                 public boolean isSatisfied() {
                     try {
-                        return !canZoomInOnUiThread() && !canZoomOutOnUiThread();
+                        return !canZoomInOnUiThread(mAwContents) &&
+                                !canZoomOutOnUiThread(mAwContents);
                     } catch (Throwable t) {
                         t.printStackTrace();
                         fail("Failed to query canZoomIn/Out: " + t.toString());
@@ -171,18 +154,18 @@
                 getZoomableHtml(), "text/html", false);
         mContentsClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
         getAwSettingsOnUiThread(mAwContents).setSupportZoom(supportZoom);
-        assertTrue("Should be able to zoom in", canZoomInOnUiThread());
-        assertFalse("Should not be able to zoom out", canZoomOutOnUiThread());
+        assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
+        assertFalse("Should not be able to zoom out", canZoomOutOnUiThread(mAwContents));
 
-        while (canZoomInOnUiThread()) {
+        while (canZoomInOnUiThread(mAwContents)) {
             assertTrue(zoomInOnUiThreadAndWait());
         }
-        assertTrue("Should be able to zoom out", canZoomOutOnUiThread());
+        assertTrue("Should be able to zoom out", canZoomOutOnUiThread(mAwContents));
 
-        while (canZoomOutOnUiThread()) {
+        while (canZoomOutOnUiThread(mAwContents)) {
             assertTrue(zoomOutOnUiThreadAndWait());
         }
-        assertTrue("Should be able to zoom in", canZoomInOnUiThread());
+        assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
     }
 
     /*
@@ -238,7 +221,7 @@
                 getZoomableHtml(), "text/html", false);
         mContentsClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
         // It must be possible to zoom in (or zoom out) for zoom controls to be shown
-        assertTrue("Should be able to zoom in", canZoomInOnUiThread());
+        assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
 
         assertTrue(webSettings.supportZoom());
         webSettings.setBuiltInZoomControls(true);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index cd85ef5..6292201 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -12,6 +12,7 @@
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
+import org.chromium.base.ThreadUtils;
 
 class TestAwContentsClient extends NullContentsClient {
     private String mUpdatedTitle;
@@ -24,6 +25,7 @@
     private final PictureListenerHelper mPictureListenerHelper;
 
     public TestAwContentsClient() {
+        super(ThreadUtils.getUiThreadLooper());
         mOnPageStartedHelper = new OnPageStartedHelper();
         mOnPageFinishedHelper = new OnPageFinishedHelper();
         mOnReceivedErrorHelper = new OnReceivedErrorHelper();
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java
index 9442b50..f2f8315 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java
@@ -6,6 +6,7 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 
 /**
@@ -26,12 +27,16 @@
         assertEquals(4, findAllAsyncOnUiThread("chuck"));
     }
 
+    /*
     @SmallTest
     @Feature({"AndroidWebView", "FindInPage"})
+    crbug.com/311495
+    */
+    @DisabledTest
     public void testFindAllDoubleNext() throws Throwable {
         assertEquals(4, findAllAsyncOnUiThread("wood"));
         assertEquals(4, findAllAsyncOnUiThread("wood"));
-        assertEquals(2, findNextOnUiThread(true));
+        assertEquals(1, findNextOnUiThread(true));
     }
 
     @SmallTest
@@ -107,13 +112,17 @@
         clearMatchesOnUiThread();
     }
 
+    /*
     @SmallTest
     @Feature({"AndroidWebView", "FindInPage"})
+    crbug.com/311495
+    */
+    @DisabledTest
     public void testClearFindNext() throws Throwable {
         assertEquals(4, findAllAsyncOnUiThread("wood"));
         clearMatchesOnUiThread();
         assertEquals(4, findAllAsyncOnUiThread("wood"));
-        assertEquals(2, findNextOnUiThread(true));
+        assertEquals(1, findNextOnUiThread(true));
     }
 
     @SmallTest
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 02f030f..5b79eb6 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -72,9 +72,6 @@
   // File system API not supported (requires some new API; internal bug 6930981)
   cl->AppendSwitch(switches::kDisableFileSystem);
 
-  // Enable D-PAD navigation for application compatibility.
-  cl->AppendSwitch(switches::kEnableSpatialNavigation);
-
   // Disable compositor touch hit testing for now to mitigate risk of bugs.
   cl->AppendSwitch(cc::switches::kDisableCompositorTouchHitTesting);
 
diff --git a/android_webview/libwebviewchromium.target.darwin-arm.mk b/android_webview/libwebviewchromium.target.darwin-arm.mk
index 6f44b2c..1a986c2 100644
--- a/android_webview/libwebviewchromium.target.darwin-arm.mk
+++ b/android_webview/libwebviewchromium.target.darwin-arm.mk
@@ -56,7 +56,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -146,7 +146,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -279,13 +278,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -363,13 +362,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -491,7 +490,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -544,7 +543,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/libwebviewchromium.target.darwin-mips.mk b/android_webview/libwebviewchromium.target.darwin-mips.mk
index d8cbc32..ca8593c 100644
--- a/android_webview/libwebviewchromium.target.darwin-mips.mk
+++ b/android_webview/libwebviewchromium.target.darwin-mips.mk
@@ -55,7 +55,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -145,7 +145,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -274,13 +273,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -357,13 +356,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -480,7 +479,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -532,7 +531,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/libwebviewchromium.target.darwin-x86.mk b/android_webview/libwebviewchromium.target.darwin-x86.mk
index f600c6c..90cacda 100644
--- a/android_webview/libwebviewchromium.target.darwin-x86.mk
+++ b/android_webview/libwebviewchromium.target.darwin-x86.mk
@@ -56,7 +56,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -151,7 +151,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -285,13 +284,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -372,13 +371,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -495,7 +494,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -552,7 +551,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-arm.mk b/android_webview/libwebviewchromium.target.linux-arm.mk
index 6f44b2c..1a986c2 100644
--- a/android_webview/libwebviewchromium.target.linux-arm.mk
+++ b/android_webview/libwebviewchromium.target.linux-arm.mk
@@ -56,7 +56,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -146,7 +146,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -279,13 +278,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -363,13 +362,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -491,7 +490,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -544,7 +543,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-mips.mk b/android_webview/libwebviewchromium.target.linux-mips.mk
index d8cbc32..ca8593c 100644
--- a/android_webview/libwebviewchromium.target.linux-mips.mk
+++ b/android_webview/libwebviewchromium.target.linux-mips.mk
@@ -55,7 +55,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -145,7 +145,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -274,13 +273,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -357,13 +356,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -480,7 +479,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -532,7 +531,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-x86.mk b/android_webview/libwebviewchromium.target.linux-x86.mk
index f600c6c..90cacda 100644
--- a/android_webview/libwebviewchromium.target.linux-x86.mk
+++ b/android_webview/libwebviewchromium.target.linux-x86.mk
@@ -56,7 +56,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_libpng_libpng_gyp)/third_party_libpng_libpng_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_libjpeg_libjpeg_gyp)/libjpeg.stamp \
 	$(call intermediates-dir-for,GYP,ui_gfx_gfx_jni_headers_gyp)/gfx_jni_headers.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_gyp)/ui_shell_dialogs_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_shell_dialogs_shell_dialogs_gyp)/ui_shell_dialogs_shell_dialogs_gyp.a \
 	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_events_events_gyp)/ui_events_events_gyp.a \
@@ -151,7 +151,6 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_html_gyp)/third_party_WebKit_Source_core_webcore_html_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_gyp)/third_party_WebKit_Source_core_webcore_platform_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_harfbuzz_ng_harfbuzz_ng_gyp)/third_party_harfbuzz_ng_harfbuzz_ng_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_platform_geometry_gyp)/third_party_WebKit_Source_core_webcore_platform_geometry_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_remaining_gyp)/third_party_WebKit_Source_core_webcore_remaining_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_rendering_gyp)/third_party_WebKit_Source_core_webcore_rendering_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_WebKit_Source_core_webcore_svg_gyp)/third_party_WebKit_Source_core_webcore_svg_gyp.a \
@@ -285,13 +284,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -372,13 +371,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -495,7 +494,7 @@
 	skia_skia_chrome_opts_gyp \
 	ui_gfx_gfx_gyp \
 	third_party_libpng_libpng_gyp \
-	ui_shell_dialogs_gyp \
+	ui_shell_dialogs_shell_dialogs_gyp \
 	ui_ui_gyp \
 	ui_events_events_gyp \
 	webkit_common_user_agent_user_agent_gyp \
@@ -552,7 +551,6 @@
 	third_party_WebKit_Source_core_webcore_html_gyp \
 	third_party_WebKit_Source_core_webcore_platform_gyp \
 	third_party_harfbuzz_ng_harfbuzz_ng_gyp \
-	third_party_WebKit_Source_core_webcore_platform_geometry_gyp \
 	third_party_WebKit_Source_core_webcore_remaining_gyp \
 	third_party_WebKit_Source_core_webcore_rendering_gyp \
 	third_party_WebKit_Source_core_webcore_svg_gyp \
diff --git a/android_webview/native/android_jar_jni_headers.target.darwin-arm.mk b/android_webview/native/android_jar_jni_headers.target.darwin-arm.mk
index 1fb2a7b..2268dd0 100644
--- a/android_webview/native/android_jar_jni_headers.target.darwin-arm.mk
+++ b/android_webview/native/android_jar_jni_headers.target.darwin-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_jar_jni_headers.target.darwin-mips.mk b/android_webview/native/android_jar_jni_headers.target.darwin-mips.mk
index cfd4a2b..d153681 100644
--- a/android_webview/native/android_jar_jni_headers.target.darwin-mips.mk
+++ b/android_webview/native/android_jar_jni_headers.target.darwin-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_jar_jni_headers.target.darwin-x86.mk b/android_webview/native/android_jar_jni_headers.target.darwin-x86.mk
index 3669d52..49e8c0a 100644
--- a/android_webview/native/android_jar_jni_headers.target.darwin-x86.mk
+++ b/android_webview/native/android_jar_jni_headers.target.darwin-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_jar_jni_headers.target.linux-arm.mk b/android_webview/native/android_jar_jni_headers.target.linux-arm.mk
index 1fb2a7b..2268dd0 100644
--- a/android_webview/native/android_jar_jni_headers.target.linux-arm.mk
+++ b/android_webview/native/android_jar_jni_headers.target.linux-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_jar_jni_headers.target.linux-mips.mk b/android_webview/native/android_jar_jni_headers.target.linux-mips.mk
index cfd4a2b..d153681 100644
--- a/android_webview/native/android_jar_jni_headers.target.linux-mips.mk
+++ b/android_webview/native/android_jar_jni_headers.target.linux-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_jar_jni_headers.target.linux-x86.mk b/android_webview/native/android_jar_jni_headers.target.linux-x86.mk
index 3669d52..49e8c0a 100644
--- a/android_webview/native/android_jar_jni_headers.target.linux-x86.mk
+++ b/android_webview/native/android_jar_jni_headers.target.linux-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.darwin-arm.mk b/android_webview/native/android_webview_native_jni.target.darwin-arm.mk
index 07a3ee3..75d2c51 100644
--- a/android_webview/native/android_webview_native_jni.target.darwin-arm.mk
+++ b/android_webview/native/android_webview_native_jni.target.darwin-arm.mk
@@ -261,13 +261,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -339,13 +339,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.darwin-mips.mk b/android_webview/native/android_webview_native_jni.target.darwin-mips.mk
index 76885e9..834d66b 100644
--- a/android_webview/native/android_webview_native_jni.target.darwin-mips.mk
+++ b/android_webview/native/android_webview_native_jni.target.darwin-mips.mk
@@ -260,13 +260,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -337,13 +337,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.darwin-x86.mk b/android_webview/native/android_webview_native_jni.target.darwin-x86.mk
index 0ebd333..9d6901b 100644
--- a/android_webview/native/android_webview_native_jni.target.darwin-x86.mk
+++ b/android_webview/native/android_webview_native_jni.target.darwin-x86.mk
@@ -263,13 +263,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -344,13 +344,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.linux-arm.mk b/android_webview/native/android_webview_native_jni.target.linux-arm.mk
index 07a3ee3..75d2c51 100644
--- a/android_webview/native/android_webview_native_jni.target.linux-arm.mk
+++ b/android_webview/native/android_webview_native_jni.target.linux-arm.mk
@@ -261,13 +261,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -339,13 +339,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.linux-mips.mk b/android_webview/native/android_webview_native_jni.target.linux-mips.mk
index 76885e9..834d66b 100644
--- a/android_webview/native/android_webview_native_jni.target.linux-mips.mk
+++ b/android_webview/native/android_webview_native_jni.target.linux-mips.mk
@@ -260,13 +260,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -337,13 +337,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/android_webview_native_jni.target.linux-x86.mk b/android_webview/native/android_webview_native_jni.target.linux-x86.mk
index 0ebd333..9d6901b 100644
--- a/android_webview/native/android_webview_native_jni.target.linux-x86.mk
+++ b/android_webview/native/android_webview_native_jni.target.linux-x86.mk
@@ -263,13 +263,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -344,13 +344,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/aw_autofill_manager_delegate.cc b/android_webview/native/aw_autofill_manager_delegate.cc
index d0ccf15..2ca6b1b 100644
--- a/android_webview/native/aw_autofill_manager_delegate.cc
+++ b/android_webview/native/aw_autofill_manager_delegate.cc
@@ -135,7 +135,9 @@
 void AwAutofillManagerDelegate::UpdateAutofillPopupDataListValues(
     const std::vector<base::string16>& values,
     const std::vector<base::string16>& labels) {
-  NOTIMPLEMENTED();
+  // Leaving as an empty method since updating autofill popup window
+  // dynamically does not seem to be a useful feature for android webview.
+  // See crrev.com/18102002 if need to implement.
 }
 
 void AwAutofillManagerDelegate::HideAutofillPopup() {
diff --git a/android_webview/native/aw_dev_tools_server.cc b/android_webview/native/aw_dev_tools_server.cc
index 9903378..285608f 100644
--- a/android_webview/native/aw_dev_tools_server.cc
+++ b/android_webview/native/aw_dev_tools_server.cc
@@ -17,7 +17,6 @@
 #include "content/public/browser/devtools_target.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/AwDevToolsServer_jni.h"
-#include "net/base/escape.h"
 #include "net/socket/unix_domain_socket_posix.h"
 #include "webkit/common/user_agent/user_agent_util.h"
 
@@ -71,7 +70,7 @@
       DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost());
   id_ = agent_host_->GetId();
   description_ = GetViewDescription(web_contents);
-  title_ = UTF16ToUTF8(net::EscapeForHTML(web_contents->GetTitle()));
+  title_ = UTF16ToUTF8(web_contents->GetTitle());
   url_ = web_contents->GetURL();
   last_activity_time_ = web_contents->GetLastSelectedTime();
 }
@@ -98,7 +97,8 @@
     return "";
   }
 
-  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget() OVERRIDE {
+  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
+      const GURL&) OVERRIDE {
     return scoped_ptr<content::DevToolsTarget>();
   }
 
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index ac4459a..d46394b 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -300,12 +300,15 @@
   web_prefs->support_deprecated_target_density_dpi = support_quirks;
   web_prefs->use_legacy_background_size_shorthand_behavior = support_quirks;
   web_prefs->viewport_meta_layout_size_quirk = support_quirks;
+  web_prefs->viewport_meta_merge_content_quirk = support_quirks;
   web_prefs->viewport_meta_zero_values_quirk = support_quirks;
   web_prefs->ignore_main_frame_overflow_hidden_quirk = support_quirks;
   web_prefs->report_screen_size_in_physical_pixels_quirk = support_quirks;
 
   web_prefs->password_echo_enabled =
-      Java_AwSettings_getPasswordEchoEnabled(env, obj);
+      Java_AwSettings_getPasswordEchoEnabledLocked(env, obj);
+  web_prefs->spatial_navigation_enabled =
+      Java_AwSettings_getSpatialNavigationLocked(env, obj);
 }
 
 static jint Init(JNIEnv* env,
diff --git a/android_webview/native/webview_native.target.darwin-arm.mk b/android_webview/native/webview_native.target.darwin-arm.mk
index 9dde02a..097c9c2 100644
--- a/android_webview/native/webview_native.target.darwin-arm.mk
+++ b/android_webview/native/webview_native.target.darwin-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -199,13 +199,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/webview_native.target.darwin-mips.mk b/android_webview/native/webview_native.target.darwin-mips.mk
index 06fe37e..658f30c 100644
--- a/android_webview/native/webview_native.target.darwin-mips.mk
+++ b/android_webview/native/webview_native.target.darwin-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -197,13 +197,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/webview_native.target.darwin-x86.mk b/android_webview/native/webview_native.target.darwin-x86.mk
index 6bd96df..2f5dab8 100644
--- a/android_webview/native/webview_native.target.darwin-x86.mk
+++ b/android_webview/native/webview_native.target.darwin-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -203,13 +203,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/webview_native.target.linux-arm.mk b/android_webview/native/webview_native.target.linux-arm.mk
index 9dde02a..097c9c2 100644
--- a/android_webview/native/webview_native.target.linux-arm.mk
+++ b/android_webview/native/webview_native.target.linux-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -199,13 +199,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/webview_native.target.linux-mips.mk b/android_webview/native/webview_native.target.linux-mips.mk
index 06fe37e..658f30c 100644
--- a/android_webview/native/webview_native.target.linux-mips.mk
+++ b/android_webview/native/webview_native.target.linux-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -197,13 +197,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/native/webview_native.target.linux-x86.mk b/android_webview/native/webview_native.target.linux-x86.mk
index 6bd96df..2f5dab8 100644
--- a/android_webview/native/webview_native.target.linux-x86.mk
+++ b/android_webview/native/webview_native.target.linux-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -203,13 +203,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc
index 5d2f57c..5a110d7 100644
--- a/android_webview/renderer/aw_render_view_ext.cc
+++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -341,7 +341,6 @@
 void AwRenderViewExt::OnSetFixedLayoutSize(const gfx::Size& size) {
   if (!render_view() || !render_view()->GetWebView())
     return;
-  DCHECK(render_view()->GetWebView()->isFixedLayoutModeEnabled());
   render_view()->GetWebView()->setFixedLayoutSize(size);
 }
 
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
index 7e03d4f..ba3b2b9 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
@@ -23,23 +23,11 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        // TODO(joth): When SW-renderer is available, we'll want to enable this on a per-test
-        // basis.
-        boolean hardwareAccelerated = true;
-        Log.i("AwTestRunnerActivity", "Is " + (hardwareAccelerated ? "" : "NOT ")
-                + "hardware accelerated");
-
-        if (hardwareAccelerated) {
-            getWindow().setFlags(
-                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-        }
-
         mLinearLayout = new LinearLayout(this);
         mLinearLayout.setOrientation(LinearLayout.VERTICAL);
         mLinearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
-        mLinearLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                LayoutParams.WRAP_CONTENT));
+        mLinearLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
 
         setContentView(mLinearLayout);
     }
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java b/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java
index 0264089..3abc1dd 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java
@@ -7,6 +7,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Picture;
 import android.net.http.SslError;
+import android.os.Looper;
 import android.os.Message;
 import android.view.KeyEvent;
 import android.view.View;
@@ -20,12 +21,21 @@
 import org.chromium.android_webview.InterceptedRequestData;
 import org.chromium.android_webview.JsPromptResultReceiver;
 import org.chromium.android_webview.JsResultReceiver;
+import org.chromium.base.ThreadUtils;
 
 /**
  * As a convience for tests that only care about specefic callbacks, this class provides
  * empty implementations of all abstract methods.
  */
 public class NullContentsClient extends AwContentsClient {
+    public NullContentsClient() {
+        this(ThreadUtils.getUiThreadLooper());
+    }
+
+    public NullContentsClient(Looper looper) {
+        super(looper);  // "...beams are gonna blind me".
+    }
+
     @Override
     public boolean shouldOverrideUrlLoading(String url) {
         return false;
diff --git a/android_webview/tools/third_party_files_whitelist.txt b/android_webview/tools/third_party_files_whitelist.txt
index b6f00e9..2f37e3c 100644
--- a/android_webview/tools/third_party_files_whitelist.txt
+++ b/android_webview/tools/third_party_files_whitelist.txt
@@ -35,17 +35,17 @@
 # Credits notice for ChromeOS.
 chrome/browser/resources/chromeos/about_os_credits.html
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/action_choice_scripts.js
+chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_scripts.js
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
+chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/main_scripts.js
+chrome/browser/resources/file_manager/foreground/js/main_scripts.js
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
+chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/media/video_player_scripts.js
+chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js
 # String 'copyright' used in code.
-chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
+chrome/browser/resources/file_manager/foreground/js/photo/photo_import_scripts.js
 # String 'copyright' used in code.
 chrome/common/importer/firefox_importer_utils.cc
 # Copyright Netscape Communications Corporation; MPL, GPL v2 or LGPL v2
diff --git a/apps/DEPS b/apps/DEPS
index b7cf3e1..1563676 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -41,13 +41,11 @@
   "+chrome/browser/extensions/extension_system.h",
   "+chrome/browser/extensions/extension_system_factory.h",
   "+chrome/browser/extensions/extension_web_contents_observer.h",
-  "+chrome/browser/extensions/lazy_background_task_queue.h",
   "+chrome/browser/extensions/suggest_permission_util.h",
   "+chrome/browser/extensions/unpacked_installer.h",
   "+chrome/common/extensions/api/app_runtime.h",
   "+chrome/common/extensions/api/app_window.h",
   "+chrome/common/extensions/extension.h",
-  "+chrome/common/extensions/extension_constants.h",
   "+chrome/common/extensions/extension_messages.h",
   "+chrome/common/extensions/extension_set.h",
   "+chrome/common/extensions/manifest_handlers/icons_handler.h",
diff --git a/apps/OWNERS b/apps/OWNERS
index 22c418a..9c3a6df 100644
--- a/apps/OWNERS
+++ b/apps/OWNERS
@@ -1,8 +1,10 @@
 # Apps team members
 asargent@chromium.org
 benwells@chromium.org
+kalman@chromium.org
 koz@chromium.org
 mek@chromium.org
 miket@chromium.org
 scheib@chromium.org
 tapted@chromium.org
+yoz@chromium.org
diff --git a/apps/app_keep_alive_service.cc b/apps/app_keep_alive_service.cc
new file mode 100644
index 0000000..825e0bb
--- /dev/null
+++ b/apps/app_keep_alive_service.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 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 "apps/app_keep_alive_service.h"
+
+#include "apps/app_lifetime_monitor.h"
+#include "apps/app_lifetime_monitor_factory.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace apps {
+
+AppKeepAliveService::AppKeepAliveService(content::BrowserContext* context)
+    : context_(context) {
+  AppLifetimeMonitor* app_lifetime_monitor =
+      AppLifetimeMonitorFactory::GetForProfile(static_cast<Profile*>(context));
+  app_lifetime_monitor->AddObserver(this);
+}
+
+AppKeepAliveService::~AppKeepAliveService() {}
+
+void AppKeepAliveService::Shutdown() {
+  AppLifetimeMonitor* app_lifetime_monitor =
+      AppLifetimeMonitorFactory::GetForProfile(static_cast<Profile*>(context_));
+  app_lifetime_monitor->RemoveObserver(this);
+  OnChromeTerminating();
+}
+
+void AppKeepAliveService::OnAppStart(Profile* profile,
+                                     const std::string& app_id) {
+  if (profile != context_)
+    return;
+
+  if (running_apps_.insert(app_id).second)
+    chrome::StartKeepAlive();
+}
+
+void AppKeepAliveService::OnAppStop(Profile* profile,
+                                    const std::string& app_id) {
+  if (profile != context_)
+    return;
+
+  if (running_apps_.erase(app_id))
+    chrome::EndKeepAlive();
+}
+
+void AppKeepAliveService::OnAppActivated(Profile* profile,
+                                         const std::string& app_id) {}
+
+void AppKeepAliveService::OnAppDeactivated(Profile* profile,
+                                           const std::string& app_id) {}
+
+void AppKeepAliveService::OnChromeTerminating() {
+  size_t keep_alives = running_apps_.size();
+  running_apps_.clear();
+
+  // In some tests, the message loop isn't running during shutdown and ending
+  // the last keep alive in that case CHECKs.
+  if (!base::MessageLoop::current() ||
+      base::MessageLoop::current()->is_running()) {
+    while (keep_alives--)
+      chrome::EndKeepAlive();
+  }
+}
+
+}  // namespace apps
diff --git a/apps/app_keep_alive_service.h b/apps/app_keep_alive_service.h
new file mode 100644
index 0000000..563a953
--- /dev/null
+++ b/apps/app_keep_alive_service.h
@@ -0,0 +1,38 @@
+// Copyright 2013 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 APPS_APP_KEEP_ALIVE_SERVICE_H_
+#define APPS_APP_KEEP_ALIVE_SERVICE_H_
+
+#include "apps/app_lifetime_monitor.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+
+namespace apps {
+
+class AppKeepAliveService : public BrowserContextKeyedService,
+                            public AppLifetimeMonitor::Observer {
+ public:
+  AppKeepAliveService(content::BrowserContext* context);
+  virtual ~AppKeepAliveService();
+  virtual void Shutdown() OVERRIDE;
+
+  // AppLifetimeMonitor::Observer:
+  virtual void OnAppStart(Profile* profile, const std::string& app_id) OVERRIDE;
+  virtual void OnAppStop(Profile* profile, const std::string& app_id) OVERRIDE;
+  virtual void OnAppActivated(Profile* profile,
+                              const std::string& app_id) OVERRIDE;
+  virtual void OnAppDeactivated(Profile* profile,
+                                const std::string& app_id) OVERRIDE;
+  virtual void OnChromeTerminating() OVERRIDE;
+
+ private:
+  content::BrowserContext* context_;
+  std::set<std::string> running_apps_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppKeepAliveService);
+};
+
+}  // namespace apps
+
+#endif  // APPS_APP_KEEP_ALIVE_SERVICE_H_
diff --git a/apps/app_keep_alive_service_factory.cc b/apps/app_keep_alive_service_factory.cc
new file mode 100644
index 0000000..dc9e725
--- /dev/null
+++ b/apps/app_keep_alive_service_factory.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 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 "apps/app_keep_alive_service_factory.h"
+
+#include "apps/app_keep_alive_service.h"
+#include "apps/app_lifetime_monitor_factory.h"
+#include "apps/shell_window_registry.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+namespace apps {
+
+// static
+AppKeepAliveServiceFactory* AppKeepAliveServiceFactory::GetInstance() {
+  return Singleton<AppKeepAliveServiceFactory>::get();
+}
+
+AppKeepAliveServiceFactory::AppKeepAliveServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "AppKeepAliveService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(AppLifetimeMonitorFactory::GetInstance());
+}
+
+AppKeepAliveServiceFactory::~AppKeepAliveServiceFactory() {}
+
+BrowserContextKeyedService* AppKeepAliveServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new AppKeepAliveService(context);
+}
+
+bool AppKeepAliveServiceFactory::ServiceIsCreatedWithBrowserContext() const {
+  return true;
+}
+
+content::BrowserContext* AppKeepAliveServiceFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+bool AppKeepAliveServiceFactory::ServiceIsNULLWhileTesting() const {
+  return true;
+}
+
+}  // namespace apps
diff --git a/apps/app_keep_alive_service_factory.h b/apps/app_keep_alive_service_factory.h
new file mode 100644
index 0000000..32575d9
--- /dev/null
+++ b/apps/app_keep_alive_service_factory.h
@@ -0,0 +1,36 @@
+// Copyright 2013 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 APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
+#define APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+namespace apps {
+
+class AppKeepAliveService;
+
+class AppKeepAliveServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static AppKeepAliveServiceFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<AppKeepAliveServiceFactory>;
+
+  AppKeepAliveServiceFactory();
+  virtual ~AppKeepAliveServiceFactory();
+
+  // BrowserContextKeyedServiceFactory:
+  virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const OVERRIDE;
+  virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
+  virtual content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const OVERRIDE;
+  virtual bool ServiceIsNULLWhileTesting() const OVERRIDE;
+};
+
+}  // namespace apps
+
+#endif  // APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
diff --git a/apps/app_keep_alive_service_unittest.cc b/apps/app_keep_alive_service_unittest.cc
new file mode 100644
index 0000000..3478162
--- /dev/null
+++ b/apps/app_keep_alive_service_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2013 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 "apps/app_keep_alive_service.h"
+#include "apps/app_keep_alive_service_factory.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if !defined(OS_ANDROID)
+
+class AppKeepAliveServiceUnitTest : public testing::Test {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    testing::Test::SetUp();
+    service_.reset(new apps::AppKeepAliveService(&profile_));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    while (chrome::WillKeepAlive())
+      chrome::EndKeepAlive();
+    testing::Test::TearDown();
+  }
+
+  TestingProfile profile_;
+  scoped_ptr<apps::AppKeepAliveService> service_;
+};
+
+TEST_F(AppKeepAliveServiceUnitTest, Basic) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that apps running in different profiles are ignored.
+TEST_F(AppKeepAliveServiceUnitTest, DifferentProfile) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(NULL, "foo");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(NULL, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that OnAppStop without a prior corresponding OnAppStart is ignored.
+TEST_F(AppKeepAliveServiceUnitTest, StopAppBeforeOpening) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that OnAppStart for an app that has already started is ignored.
+TEST_F(AppKeepAliveServiceUnitTest, StartMoreThanOnce) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+TEST_F(AppKeepAliveServiceUnitTest, MultipleApps) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "bar");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "bar");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that all keep alives are ended when OnChromeTerminating is called.
+TEST_F(AppKeepAliveServiceUnitTest, ChromeTerminateWithAppsStarted) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "bar");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnChromeTerminating();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStop(&profile_, "foo");
+  service_->OnAppStop(&profile_, "bar");
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that all keep alives are ended when Shutdown is called.
+TEST_F(AppKeepAliveServiceUnitTest, ProfileShutdownWithAppsStarted) {
+  ASSERT_FALSE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "foo");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->OnAppStart(&profile_, "bar");
+  EXPECT_TRUE(chrome::WillKeepAlive());
+  service_->Shutdown();
+  EXPECT_FALSE(chrome::WillKeepAlive());
+}
+#endif
diff --git a/apps/app_load_service.cc b/apps/app_load_service.cc
index a0a6a66..c4e24c3 100644
--- a/apps/app_load_service.cc
+++ b/apps/app_load_service.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -26,7 +25,8 @@
 namespace apps {
 
 AppLoadService::PostReloadAction::PostReloadAction()
-    : command_line(CommandLine::NO_PROGRAM) {
+    : action_type(LAUNCH),
+      command_line(CommandLine::NO_PROGRAM) {
 }
 
 AppLoadService::AppLoadService(Profile* profile)
@@ -131,7 +131,7 @@
 
 bool AppLoadService::WasUnloadedForReload(
     const extensions::UnloadedExtensionInfo& unload_info) {
-  if (unload_info.reason == extension_misc::UNLOAD_REASON_DISABLE) {
+  if (unload_info.reason == extensions::UnloadedExtensionInfo::REASON_DISABLE) {
     ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
      return (prefs->GetDisableReasons(unload_info.extension->id()) &
         Extension::DISABLE_RELOAD) != 0;
diff --git a/apps/app_shim/DEPS b/apps/app_shim/DEPS
index fc7d0e0..8d51bf5 100644
--- a/apps/app_shim/DEPS
+++ b/apps/app_shim/DEPS
@@ -1,15 +1,16 @@
 include_rules = [
   # TODO(benwells): move this whole folder out of apps and review these.
   # See http://crbug.com/266705.
-  "+chrome/browser/apps/app_launcher_util.h",
   "+chrome/browser/browser_process.h",
   "+chrome/browser/ui/app_list/app_list_service.h",
+  "+chrome/browser/ui/app_list/app_list_util.h",
   "+chrome/browser/ui/extensions/application_launch.h",
   "+chrome/browser/ui/web_applications/web_app_ui.h",
   "+chrome/browser/ui/webui/ntp/core_app_launcher_handler.h",
   "+chrome/browser/web_applications/web_app_mac.h",
   "+chrome/common/chrome_constants.h",
   "+chrome/common/chrome_paths.h",
+  "+chrome/common/extensions/extension_constants.h",
   "+chrome/common/mac/app_mode_common.h",
   "+grit/generated_resources.h",
 ]
diff --git a/apps/app_shim/app_shim_handler_mac.cc b/apps/app_shim/app_shim_handler_mac.cc
index 6593155..f50acdb 100644
--- a/apps/app_shim/app_shim_handler_mac.cc
+++ b/apps/app_shim/app_shim_handler_mac.cc
@@ -25,8 +25,10 @@
 void TerminateIfNoShellWindows() {
   bool shell_windows_left =
       apps::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(0);
-  if (!shell_windows_left && !AppListService::Get()->IsAppListVisible())
+  if (!shell_windows_left && !AppListService::Get(
+          chrome::HOST_DESKTOP_TYPE_NATIVE)->IsAppListVisible()) {
     chrome::AttemptExit();
+  }
 }
 
 class AppShimHandlerRegistry : public content::NotificationObserver {
diff --git a/apps/app_shim/app_shim_mac.cc b/apps/app_shim/app_shim_mac.cc
index e9eddd7..553f07c 100644
--- a/apps/app_shim/app_shim_mac.cc
+++ b/apps/app_shim/app_shim_mac.cc
@@ -5,7 +5,7 @@
 #include "apps/app_shim/app_shim_mac.h"
 
 #include "base/command_line.h"
-#include "chrome/browser/apps/app_launcher_util.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/common/chrome_switches.h"
 
 namespace apps {
diff --git a/apps/app_window_contents.cc b/apps/app_window_contents.cc
index 4f11a10..751ccc2 100644
--- a/apps/app_window_contents.cc
+++ b/apps/app_window_contents.cc
@@ -19,6 +19,12 @@
 
 namespace app_window = extensions::api::app_window;
 
+namespace {
+
+const int kUnboundedSize = apps::ShellWindow::SizeConstraints::kUnboundedSize;
+
+}
+
 namespace apps {
 
 AppWindowContents::AppWindowContents(ShellWindow* host)
@@ -94,6 +100,19 @@
   dictionary->SetBoolean("maximized", native_app_window->IsMaximized());
   dictionary->SetBoolean("alwaysOnTop", native_app_window->IsAlwaysOnTop());
 
+  const ShellWindow::SizeConstraints& size_constraints =
+      host_->size_constraints();
+  gfx::Size min_size = size_constraints.GetMinimumSize();
+  gfx::Size max_size = size_constraints.GetMaximumSize();
+  if (min_size.width() != kUnboundedSize)
+    dictionary->SetInteger("minWidth", min_size.width());
+  if (min_size.height() != kUnboundedSize)
+    dictionary->SetInteger("minHeight", min_size.height());
+  if (max_size.width() != kUnboundedSize)
+    dictionary->SetInteger("maxWidth", max_size.width());
+  if (max_size.height() != kUnboundedSize)
+    dictionary->SetInteger("maxHeight", max_size.height());
+
   content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
   rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(),
                                            host_->extension_id(),
diff --git a/apps/apps.gypi b/apps/apps.gypi
index e956c46..ea177bd 100644
--- a/apps/apps.gypi
+++ b/apps/apps.gypi
@@ -23,6 +23,10 @@
         '<(grit_out_dir)',
       ],
       'sources': [
+        'app_keep_alive_service.cc',
+        'app_keep_alive_service.h',
+        'app_keep_alive_service_factory.cc',
+        'app_keep_alive_service_factory.h',
         'app_lifetime_monitor.cc',
         'app_lifetime_monitor.h',
         'app_lifetime_monitor_factory.cc',
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 731ff88..8e9b151 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/app_runtime.h"
 #include "chrome/common/extensions/extension.h"
@@ -30,6 +29,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
 #include "url/gurl.h"
diff --git a/apps/saved_files_service.cc b/apps/saved_files_service.cc
index 20f81e8..b4dfab7 100644
--- a/apps/saved_files_service.cc
+++ b/apps/saved_files_service.cc
@@ -15,9 +15,9 @@
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permission_set.h"
 
 namespace apps {
 
diff --git a/apps/shell_window.cc b/apps/shell_window.cc
index 2b169d0..abed875 100644
--- a/apps/shell_window.cc
+++ b/apps/shell_window.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
@@ -33,9 +32,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/media_stream_request.h"
 #include "extensions/browser/view_type_utils.h"
-#include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/screen.h"
 
 #if !defined(OS_MACOSX)
@@ -319,22 +316,6 @@
   ShellWindowRegistry::Get(profile_)->ShellWindowActivated(this);
 }
 
-scoped_ptr<gfx::Image> ShellWindow::GetAppListIcon() {
-  // TODO(skuhne): We might want to use LoadImages in UpdateExtensionAppIcon
-  // instead to let the extension give us pre-defined icons in the launcher
-  // and the launcher list sizes. Since there is no mock yet, doing this now
-  // seems a bit premature and we scale for the time being.
-  if (app_icon_.IsEmpty())
-    return make_scoped_ptr(new gfx::Image());
-
-  SkBitmap bmp = skia::ImageOperations::Resize(
-        *app_icon_.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
-        extension_misc::EXTENSION_ICON_SMALLISH,
-        extension_misc::EXTENSION_ICON_SMALLISH);
-  return make_scoped_ptr(
-      new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)));
-}
-
 content::WebContents* ShellWindow::web_contents() const {
   return shell_window_contents_->GetWebContents();
 }
@@ -672,12 +653,10 @@
 
 ShellWindow::CreateParams ShellWindow::LoadDefaultsAndConstrain(
     CreateParams params) const {
-  gfx::Rect bounds = params.bounds;
-
-  if (bounds.width() == 0)
-    bounds.set_width(kDefaultWidth);
-  if (bounds.height() == 0)
-    bounds.set_height(kDefaultHeight);
+  if (params.bounds.width() == 0)
+    params.bounds.set_width(kDefaultWidth);
+  if (params.bounds.height() == 0)
+    params.bounds.set_height(kDefaultHeight);
 
   // If left and top are left undefined, the native shell window will center
   // the window on the main screen in a platform-defined manner.
@@ -701,13 +680,13 @@
                                       cached_screen_bounds,
                                       current_screen_bounds,
                                       params.minimum_size,
-                                      &bounds);
+                                      &params.bounds);
       params.state = cached_state;
     }
   }
 
   SizeConstraints size_constraints(params.minimum_size, params.maximum_size);
-  params.bounds.set_size(size_constraints.ClampSize(bounds.size()));
+  params.bounds.set_size(size_constraints.ClampSize(params.bounds.size()));
   params.minimum_size = size_constraints.GetMinimumSize();
   params.maximum_size = size_constraints.GetMaximumSize();
 
diff --git a/apps/shell_window.h b/apps/shell_window.h
index efc6915..103eb1b 100644
--- a/apps/shell_window.h
+++ b/apps/shell_window.h
@@ -245,10 +245,6 @@
   // Returns the bounds that should be reported to the renderer.
   gfx::Rect GetClientBounds() const;
 
-  // This will return a slightly smaller icon then the app_icon to be used in
-  // application lists.
-  scoped_ptr<gfx::Image> GetAppListIcon();
-
   // NativeAppWindows should call this to determine what the window's title
   // is on startup and from within UpdateWindowTitle().
   string16 GetTitle() const;
diff --git a/ash/accelerators/accelerator_commands.cc b/ash/accelerators/accelerator_commands.cc
index 1cb326d..003562e 100644
--- a/ash/accelerators/accelerator_commands.cc
+++ b/ash/accelerators/accelerator_commands.cc
@@ -23,10 +23,7 @@
     return true;
   }
   wm::WindowState* window_state = wm::GetWindowState(window);
-  // Disable the shortcut for minimizing full screen window due to
-  // crbug.com/131709, which is a crashing issue related to minimizing
-  // full screen pepper window.
-  if (window_state->IsFullscreen() || !window_state->CanMinimize())
+  if (!window_state->CanMinimize())
     return false;
   ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction(
       ash::UMA_MINIMIZE_PER_KEY);
@@ -40,10 +37,16 @@
     return;
   // Get out of fullscreen when in fullscreen mode.
   if (window_state->IsFullscreen())
-    Shell::GetInstance()->delegate()->ToggleFullscreen();
+    ToggleFullscreen();
   else
     window_state->ToggleMaximized();
 }
 
+void ToggleFullscreen() {
+  wm::WindowState* window_state = wm::GetActiveWindowState();
+  if (window_state)
+    window_state->ToggleFullscreen();
+}
+
 }  // namespace accelerators
 }  // namespace ash
diff --git a/ash/accelerators/accelerator_commands.h b/ash/accelerators/accelerator_commands.h
index 36006e7..df576ba 100644
--- a/ash/accelerators/accelerator_commands.h
+++ b/ash/accelerators/accelerator_commands.h
@@ -21,6 +21,10 @@
 // fullscreen mode.
 ASH_EXPORT void ToggleMaximized();
 
+// Toggles the fullscreen state. The behavior can be overridden
+// by WindowStateDelegate::ToggleFullscreen().
+ASH_EXPORT void ToggleFullscreen();
+
 }  // namespace accelerators
 }  // namespace ash
 
diff --git a/ash/accelerators/accelerator_commands_unittest.cc b/ash/accelerators/accelerator_commands_unittest.cc
index 2423bb5..c193b26 100644
--- a/ash/accelerators/accelerator_commands_unittest.cc
+++ b/ash/accelerators/accelerator_commands_unittest.cc
@@ -8,6 +8,12 @@
 #include "ash/wm/window_state.h"
 #include "ui/aura/window.h"
 
+// Note: The unit tests for |ToggleMaximized()| and
+// |ToggleFullscreen()| are in
+// chrome/browser/ui/ash/accelerator_commands_browsertests.cc.
+// because they depends on chrome implementation of
+// |ash::wm::WindowStateDelegate|.
+
 namespace ash {
 namespace accelerators {
 
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 4a73ee4..13fc182 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -25,6 +25,7 @@
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/magnifier/partial_magnification_controller.h"
 #include "ash/multi_profile_uma.h"
+#include "ash/new_window_delegate.h"
 #include "ash/root_window_controller.h"
 #include "ash/rotator/screen_rotation.h"
 #include "ash/screenshot_delegate.h"
@@ -134,8 +135,10 @@
 }
 
 bool HandleAccessibleFocusCycle(bool reverse) {
-  if (!Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled())
+  if (!Shell::GetInstance()->accessibility_delegate()->
+      IsSpokenFeedbackEnabled()) {
     return false;
+  }
   aura::Window* active_window = ash::wm::GetActiveWindow();
   if (!active_window)
     return false;
@@ -157,10 +160,11 @@
 }
 
 void HandleSilenceSpokenFeedback() {
-  if (!Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled())
+  AccessibilityDelegate* delegate =
+      Shell::GetInstance()->accessibility_delegate();
+  if (!delegate->IsSpokenFeedbackEnabled())
     return;
-
-  Shell::GetInstance()->delegate()->SilenceSpokenFeedback();
+  delegate->SilenceSpokenFeedback();
 }
 
 #if defined(OS_CHROMEOS)
@@ -170,17 +174,17 @@
 }
 
 bool HandleFileManager() {
-  Shell::GetInstance()->delegate()->OpenFileManager();
+  Shell::GetInstance()->new_window_delegate()->OpenFileManager();
   return true;
 }
 
 bool HandleCrosh() {
-  Shell::GetInstance()->delegate()->OpenCrosh();
+  Shell::GetInstance()->new_window_delegate()->OpenCrosh();
   return true;
 }
 
 bool HandleToggleSpokenFeedback() {
-  Shell::GetInstance()->delegate()->
+  Shell::GetInstance()->accessibility_delegate()->
       ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW);
   return true;
 }
@@ -280,7 +284,7 @@
 }
 
 bool HandleToggleRootWindowFullScreen() {
-  Shell::GetPrimaryRootWindow()->ToggleFullScreen();
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->ToggleFullScreen();
   return true;
 }
 
@@ -613,25 +617,27 @@
       return true;
 #endif
     case OPEN_FEEDBACK_PAGE:
-      ash::Shell::GetInstance()->delegate()->OpenFeedbackPage();
+      ash::Shell::GetInstance()->new_window_delegate()->OpenFeedbackPage();
       return true;
     case EXIT:
       // UMA metrics are recorded in the handler.
       exit_warning_handler_.HandleAccelerator();
       return true;
     case NEW_INCOGNITO_WINDOW:
-      Shell::GetInstance()->delegate()->NewWindow(true /* is_incognito */);
+      Shell::GetInstance()->new_window_delegate()->NewWindow(
+          true /* is_incognito */);
       return true;
     case NEW_TAB:
       if (key_code == ui::VKEY_T)
         shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEWTAB_T);
-      Shell::GetInstance()->delegate()->NewTab();
+      Shell::GetInstance()->new_window_delegate()->NewTab();
       return true;
     case NEW_WINDOW:
-      Shell::GetInstance()->delegate()->NewWindow(false /* is_incognito */);
+      Shell::GetInstance()->new_window_delegate()->NewWindow(
+          false /* is_incognito */);
       return true;
     case RESTORE_TAB:
-      Shell::GetInstance()->delegate()->RestoreTab();
+      Shell::GetInstance()->new_window_delegate()->RestoreTab();
       return true;
     case TAKE_SCREENSHOT:
       if (screenshot_delegate_.get() &&
@@ -662,7 +668,8 @@
       // consume the key since Search+Shift is one of the shortcuts the a11y
       // feature uses. crbug.com/132296
       DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code());
-      if (Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled())
+      if (Shell::GetInstance()->accessibility_delegate()->
+          IsSpokenFeedbackEnabled())
         return false;
       ash::Shell::GetInstance()->ToggleAppList(NULL);
       return true;
@@ -710,15 +717,21 @@
         return keyboard_brightness_control_delegate_->
             HandleKeyboardBrightnessUp(accelerator);
       break;
-    case VOLUME_MUTE:
-      return shell->system_tray_delegate()->GetVolumeControlDelegate()->
-          HandleVolumeMute(accelerator);
-    case VOLUME_DOWN:
-      return shell->system_tray_delegate()->GetVolumeControlDelegate()->
-          HandleVolumeDown(accelerator);
-    case VOLUME_UP:
-      return shell->system_tray_delegate()->GetVolumeControlDelegate()->
-          HandleVolumeUp(accelerator);
+    case VOLUME_MUTE: {
+      ash::VolumeControlDelegate* volume_delegate =
+          shell->system_tray_delegate()->GetVolumeControlDelegate();
+      return volume_delegate && volume_delegate->HandleVolumeMute(accelerator);
+    }
+    case VOLUME_DOWN: {
+      ash::VolumeControlDelegate* volume_delegate =
+          shell->system_tray_delegate()->GetVolumeControlDelegate();
+      return volume_delegate && volume_delegate->HandleVolumeDown(accelerator);
+    }
+    case VOLUME_UP: {
+      ash::VolumeControlDelegate* volume_delegate =
+          shell->system_tray_delegate()->GetVolumeControlDelegate();
+      return volume_delegate && volume_delegate->HandleVolumeUp(accelerator);
+    }
     case FOCUS_LAUNCHER:
       return shell->focus_cycler()->FocusWidget(
           Launcher::ForPrimaryDisplay()->shelf_widget());
@@ -727,7 +740,7 @@
     case FOCUS_PREVIOUS_PANE:
       return HandleRotatePaneFocus(Shell::BACKWARD);
     case SHOW_KEYBOARD_OVERLAY:
-      ash::Shell::GetInstance()->delegate()->ShowKeyboardOverlay();
+      ash::Shell::GetInstance()->new_window_delegate()->ShowKeyboardOverlay();
       return true;
     case SHOW_OAK:
       if (CommandLine::ForCurrentProcess()->HasSwitch(
@@ -759,7 +772,7 @@
       break;
     }
     case SHOW_TASK_MANAGER:
-      Shell::GetInstance()->delegate()->ShowTaskManager();
+      Shell::GetInstance()->new_window_delegate()->ShowTaskManager();
       return true;
     case NEXT_IME:
       // This check is necessary e.g. not to process the Shift+Alt+
@@ -842,7 +855,7 @@
         shell->delegate()->RecordUserMetricsAction(
             UMA_ACCEL_FULLSCREEN_F4);
       }
-      shell->delegate()->ToggleFullscreen();
+      accelerators::ToggleFullscreen();
       return true;
     }
     case TOGGLE_MAXIMIZED: {
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 47d82a3..575a5ec 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_table.h"
+#include "ash/accessibility_delegate.h"
 #include "ash/caps_lock_delegate.h"
 #include "ash/display/display_manager.h"
 #include "ash/ime_control_delegate.h"
@@ -602,21 +603,23 @@
   GetController()->Register(accelerator_a, &target);
 
   // The accelerator is processed only once.
+  aura::WindowEventDispatcher* dispatcher =
+      Shell::GetPrimaryRootWindow()->GetDispatcher();
 #if defined(OS_WIN)
   MSG msg1 = { NULL, WM_KEYDOWN, ui::VKEY_A, 0 };
   ui::TranslatedKeyEvent key_event1(msg1, false);
-  EXPECT_TRUE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event1));
+  EXPECT_TRUE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event1));
 
   MSG msg2 = { NULL, WM_CHAR, L'A', 0 };
   ui::TranslatedKeyEvent key_event2(msg2, true);
-  EXPECT_FALSE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event2));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event2));
 
   MSG msg3 = { NULL, WM_KEYUP, ui::VKEY_A, 0 };
   ui::TranslatedKeyEvent key_event3(msg3, false);
-  EXPECT_FALSE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event3));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event3));
 #elif defined(USE_X11)
   XEvent key_event;
   ui::InitXKeyEventForTesting(ui::ET_KEY_PRESSED,
@@ -624,20 +627,20 @@
                               0,
                               &key_event);
   ui::TranslatedKeyEvent key_event1(&key_event, false);
-  EXPECT_TRUE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event1));
+  EXPECT_TRUE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event1));
 
   ui::TranslatedKeyEvent key_event2(&key_event, true);
-  EXPECT_FALSE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event2));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event2));
 
   ui::InitXKeyEventForTesting(ui::ET_KEY_RELEASED,
                               ui::VKEY_A,
                               0,
                               &key_event);
   ui::TranslatedKeyEvent key_event3(&key_event, false);
-  EXPECT_FALSE(Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->
-      OnHostKeyEvent(&key_event3));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(
+      &key_event3));
 #endif
   EXPECT_EQ(1, target.accelerator_pressed_count());
 }
@@ -957,9 +960,8 @@
 }
 
 TEST_F(AcceleratorControllerTest, GlobalAcceleratorsToggleAppList) {
-  test::TestShellDelegate* delegate =
-      reinterpret_cast<test::TestShellDelegate*>(
-          ash::Shell::GetInstance()->delegate());
+  AccessibilityDelegate* delegate =
+          ash::Shell::GetInstance()->accessibility_delegate();
   EXPECT_FALSE(ash::Shell::GetInstance()->GetAppListTargetVisibility());
 
   // The press event should not open the AppList, the release should instead.
diff --git a/ash/accelerators/accelerator_dispatcher.cc b/ash/accelerators/accelerator_dispatcher.cc
index d023c6e..23bae22 100644
--- a/ash/accelerators/accelerator_dispatcher.cc
+++ b/ash/accelerators/accelerator_dispatcher.cc
@@ -40,6 +40,11 @@
 bool IsKeyEvent(const XEvent* xev) {
   return xev->type == KeyPress || xev->type == KeyRelease;
 }
+#elif defined(USE_OZONE)
+bool IsKeyEvent(const base::NativeEvent& native_event) {
+  const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
+  return event->IsKeyEvent();
+}
 #endif
 
 bool IsPossibleAcceleratorNotForMenu(const ui::KeyEvent& key_event) {
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index e770cc8..3efc0de 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -144,7 +144,11 @@
   // Window management shortcuts.
   { true, ui::VKEY_OEM_4, ui::EF_ALT_DOWN, WINDOW_SNAP_LEFT },
   { true, ui::VKEY_OEM_6, ui::EF_ALT_DOWN, WINDOW_SNAP_RIGHT },
-  { true, ui::VKEY_OEM_MINUS, ui::EF_ALT_DOWN, WINDOW_MINIMIZE },
+  // The same accelerator is defined in
+  // c/b/ui/views/accelerator_table.cc in order for the web page to
+  // intercept and process this shortcut. This accelerator is used if the
+  // focused window isn't browser window nor web content.
+  { true, ui::VKEY_M, ui::EF_CONTROL_DOWN, WINDOW_MINIMIZE },
   { true, ui::VKEY_OEM_PLUS, ui::EF_ALT_DOWN, TOGGLE_MAXIMIZED },
   { true, ui::VKEY_OEM_PLUS, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
     WINDOW_POSITION_CENTER },
diff --git a/ash/accelerators/exit_warning_handler.cc b/ash/accelerators/exit_warning_handler.cc
index 6ea635a..1f8b53e 100644
--- a/ash/accelerators/exit_warning_handler.cc
+++ b/ash/accelerators/exit_warning_handler.cc
@@ -11,7 +11,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "grit/ash_strings.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
 #include "ui/base/accessibility/accessible_view_state.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -165,7 +165,7 @@
 void ExitWarningHandler::Show() {
   if (widget_)
     return;
-  aura::RootWindow* root_window = Shell::GetTargetRootWindow();
+  aura::Window* root_window = Shell::GetTargetRootWindow();
   ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView;
   gfx::Size rs = root_window->bounds().size();
   gfx::Size ps = delegate->GetPreferredSize();
diff --git a/ash/accelerators/nested_dispatcher_controller_unittest.cc b/ash/accelerators/nested_dispatcher_controller_unittest.cc
index 955630c..232ae9c 100644
--- a/ash/accelerators/nested_dispatcher_controller_unittest.cc
+++ b/ash/accelerators/nested_dispatcher_controller_unittest.cc
@@ -88,16 +88,18 @@
                               ui::VKEY_A,
                               0,
                               &native_event);
-  ash::Shell::GetPrimaryRootWindow()->PostNativeEvent(&native_event);
+  aura::WindowEventDispatcher* dispatcher =
+      ash::Shell::GetPrimaryRootWindow()->GetDispatcher();
+  dispatcher->PostNativeEvent(&native_event);
   ui::InitXKeyEventForTesting(ui::ET_KEY_RELEASED,
                               ui::VKEY_A,
                               0,
                               &native_event);
-  ash::Shell::GetPrimaryRootWindow()->PostNativeEvent(&native_event);
+  dispatcher->PostNativeEvent(&native_event);
 #endif
 
   // Send noop event to signal dispatcher to exit.
-  ash::Shell::GetPrimaryRootWindow()->PostNativeEvent(ui::CreateNoopEvent());
+  dispatcher->PostNativeEvent(ui::CreateNoopEvent());
 }
 
 }  // namespace
@@ -111,7 +113,7 @@
 
   Shell::GetInstance()->session_state_delegate()->LockScreen();
   DispatchKeyReleaseA();
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
   aura::client::GetDispatcherClient(root_window)->RunWithDispatcher(
       &inner_dispatcher,
       associated_window.get(),
@@ -132,7 +134,7 @@
       mock_lock_container.get()));
 
   DispatchKeyReleaseA();
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
   aura::client::GetDispatcherClient(root_window)->RunWithDispatcher(
       &inner_dispatcher,
       associated_window.get(),
@@ -143,7 +145,7 @@
 // Test that the nested dispatcher handles accelerators.
 TEST_F(NestedDispatcherTest, AcceleratorsHandled) {
   MockDispatcher inner_dispatcher;
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
 
   ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE);
   accelerator.set_type(ui::ET_KEY_RELEASED);
diff --git a/ash/accessibility_delegate.h b/ash/accessibility_delegate.h
new file mode 100644
index 0000000..a77e840
--- /dev/null
+++ b/ash/accessibility_delegate.h
@@ -0,0 +1,78 @@
+// Copyright 2013 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 ASH_ACCESSIBILITY_DELEGATE_H_
+#define ASH_ACCESSIBILITY_DELEGATE_H_
+
+#include "ash/ash_export.h"
+#include "ash/magnifier/magnifier_constants.h"
+
+namespace ash {
+
+enum AccessibilityNotificationVisibility {
+  A11Y_NOTIFICATION_NONE,
+  A11Y_NOTIFICATION_SHOW,
+};
+
+// A deletate class to control accessibility features.
+class ASH_EXPORT AccessibilityDelegate {
+ public:
+  AccessibilityDelegate() {}
+  virtual ~AccessibilityDelegate() {}
+
+  // Invoked to toggle spoken feedback for accessibility
+  virtual void ToggleSpokenFeedback(
+      AccessibilityNotificationVisibility notify) = 0;
+
+  // Returns true if spoken feedback is enabled.
+  virtual bool IsSpokenFeedbackEnabled() const = 0;
+
+  // Invoked to toggle high contrast mode for accessibility.
+  virtual void ToggleHighContrast() = 0;
+
+  // Returns true if high contrast mode is enabled.
+  virtual bool IsHighContrastEnabled() const = 0;
+
+  // Invoked to enable the screen magnifier.
+  virtual void SetMagnifierEnabled(bool enabled) = 0;
+
+  // Invoked to change the type of the screen magnifier.
+  virtual void SetMagnifierType(MagnifierType type) = 0;
+
+  // Returns true if the screen magnifier is enabled or not.
+  virtual bool IsMagnifierEnabled() const = 0;
+
+  // Returns the current screen magnifier mode.
+  virtual MagnifierType GetMagnifierType() const = 0;
+
+  // Invoked to enable Large Cursor.
+  virtual void SetLargeCursorEnabled(bool enabled) = 0;
+
+  // Returns ture if Large Cursor is enabled or not.
+  virtual bool IsLargeCursorEnabled() const = 0;
+
+  // Invoked to enable autoclick.
+  virtual void SetAutoclickEnabled(bool enabled) = 0;
+
+  // Returns if autoclick is enabled or not.
+  virtual bool IsAutoclickEnabled() const = 0;
+
+  // Returns true if the user wants to show accesibility menu even when all the
+  // accessibility features are disabled.
+  virtual bool ShouldAlwaysShowAccessibilityMenu() const = 0;
+
+  // Cancel all current and queued speech immediately.
+  virtual void SilenceSpokenFeedback() const = 0;
+
+  // Saves the zoom scale of the full screen magnifier.
+  virtual void SaveScreenMagnifierScale(double scale) = 0;
+
+  // Gets a saved value of the zoom scale of full screen magnifier. If a value
+  // is not saved, return a negative value.
+  virtual double GetSavedScreenMagnifierScale() = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_ACCESSIBILITYDELEGATE_H_
diff --git a/ash/ash.gyp b/ash/ash.gyp
index df74c49..99e8489 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -67,6 +67,7 @@
         'accelerators/focus_manager_factory.h',
         'accelerators/nested_dispatcher_controller.cc',
         'accelerators/nested_dispatcher_controller.h',
+        'accessibility_delegate.h',
         'autoclick/autoclick_controller.cc',
         'autoclick/autoclick_controller.h',
         'ash_constants.cc',
@@ -80,6 +81,8 @@
         'caps_lock_delegate_stub.h',
         'debug.cc',
         'debug.h',
+        'default_accessibility_delegate.cc',
+        'default_accessibility_delegate.h',
         'default_user_wallpaper_delegate.cc',
         'default_user_wallpaper_delegate.h',
         'desktop_background/desktop_background_controller.cc',
@@ -124,6 +127,8 @@
         'display/screen_position_controller.h',
         'display/shared_display_edge_indicator.cc',
         'display/shared_display_edge_indicator.h',
+        'display/virtual_keyboard_window_controller.cc',
+        'display/virtual_keyboard_window_controller.h',
         'drag_drop/drag_drop_controller.cc',
         'drag_drop/drag_drop_controller.h',
         'drag_drop/drag_drop_tracker.cc',
@@ -157,11 +162,12 @@
         'launcher/launcher_delegate.h',
         'launcher/launcher_item_delegate_manager.cc',
         'launcher/launcher_item_delegate_manager.h',
-        'launcher/launcher_icon_observer.h',
         'launcher/launcher_item_delegate.h',
         'launcher/launcher_model.cc',
         'launcher/launcher_model.h',
         'launcher/launcher_model_observer.h',
+        'launcher/launcher_model_util.cc',
+        'launcher/launcher_model_util.h',
         'launcher/launcher_types.cc',
         'launcher/launcher_types.h',
         'magnifier/magnification_controller.cc',
@@ -205,6 +211,7 @@
         'shelf/shelf_alignment_menu.h',
         'shelf/shelf_bezel_event_filter.cc',
         'shelf/shelf_bezel_event_filter.h',
+        'shelf/shelf_icon_observer.h',
         'shelf/shelf_layout_manager.cc',
         'shelf/shelf_layout_manager.h',
         'shelf/shelf_layout_manager_observer.h',
@@ -213,8 +220,6 @@
         'shelf/shelf_tooltip_manager.cc',
         'shelf/shelf_tooltip_manager.h',
         'shelf/shelf_types.h',
-        'shelf/shelf_util.cc',
-        'shelf/shelf_util.h',
         'shelf/shelf_view.cc',
         'shelf/shelf_view.h',
         'shelf/shelf_widget.cc',
@@ -466,6 +471,8 @@
         'wm/overlay_event_filter.h',
         'wm/overview/scoped_transform_overview_window.cc',
         'wm/overview/scoped_transform_overview_window.h',
+        'wm/overview/scoped_window_copy.cc',
+        'wm/overview/scoped_window_copy.h',
         'wm/overview/window_overview.cc',
         'wm/overview/window_overview.h',
         'wm/overview/window_selector.cc',
@@ -533,6 +540,8 @@
         'wm/window_positioner.h',
         'wm/window_state.cc',
         'wm/window_state.h',
+        'wm/window_state_delegate.cc',
+        'wm/window_state_delegate.h',
         'wm/window_state_observer.h',
         'wm/window_properties.cc',
         'wm/window_properties.h',
@@ -614,6 +623,8 @@
         'ash_resources',
       ],
       'sources': [
+        'shell/toplevel_window.cc',
+        'shell/toplevel_window.h',
         'test/app_list_controller_test_api.cc',
         'test/app_list_controller_test_api.h',
         'test/ash_test_base.cc',
@@ -670,11 +681,6 @@
             'test/test_metro_viewer_process_host.cc',
             'test/test_metro_viewer_process_host.h',
           ],
-          'msvs_settings': {
-            'VCCLCompilerTool': {
-              'ForcedIncludeFiles': [ 'build/intsafe_workaround.h' ],
-            },
-          },
         }],
       ],
     },
@@ -702,7 +708,7 @@
         '../ui/message_center/message_center.gyp:message_center_test_support',
         '../ui/ui.gyp:ui',
         '../ui/ui.gyp:ui_resources',
-        '../ui/ui.gyp:ui_test_support',
+        '../ui/ui_unittests.gyp:ui_test_support',
         '../ui/views/views.gyp:views',
         '../ui/views/views.gyp:views_examples_with_content_lib',
         '../ui/views/views.gyp:views_test_support',
@@ -769,8 +775,6 @@
         'shell/panel_window.h',
         'shell/shell_delegate_impl.cc',
         'shell/shell_delegate_impl.h',
-        'shell/toplevel_window.cc',
-        'shell/toplevel_window.h',
         'shell/widgets.cc',
         'shell/window_type_launcher.cc',
         'shell/window_type_launcher.h',
@@ -782,6 +786,7 @@
         'shell_unittest.cc',
         'system/chromeos/managed/tray_locally_managed_user_unittest.cc',
         'system/chromeos/network/network_state_notifier_unittest.cc',
+        'system/chromeos/power/power_event_observer_unittest.cc',
         'system/chromeos/power/power_status_unittest.cc',
         'system/chromeos/power/tray_power_unittest.cc',
         'system/chromeos/screen_security/screen_tray_item_unittest.cc',
@@ -822,6 +827,7 @@
         'wm/window_cycle_controller_unittest.cc',
         'wm/window_manager_unittest.cc',
         'wm/window_modality_controller_unittest.cc',
+        'wm/window_positioner_unittest.cc',
         'wm/window_util_unittest.cc',
         'wm/workspace/magnetism_matcher_unittest.cc',
         'wm/workspace/multi_window_resize_controller_unittest.cc',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 75559f4..289c8b1 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -439,6 +439,9 @@
       <message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR" desc="The label used in the accessibility menu of the system tray to toggle on/off large mouse cursor feature.">
         Large mouse cursor
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK" desc="The label used in the accessibility menu of the system tray to toggle on/off automatic mouse clicks.">
+        Automatic clicks
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LEARN_MORE" desc="The label used in the accessibility menu of the system tray
      to open a webpage (article on help center) containing explanation about accessibility feature.">
         Learn more...
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index 394e5a6..934cbac 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -61,14 +61,7 @@
 const char kAshDisableDisplayChangeLimiter[] =
     "ash-disable-display-change-limiter";
 
-// Disable immersive fullscreen mode, regardless of default setting.
-const char kAshDisableImmersiveFullscreen[] =
-    "ash-disable-immersive-fullscreen";
-
 #if defined(OS_CHROMEOS)
-// Disable compositor based mirroring.
-const char kAshDisableSoftwareMirroring[] = "ash-disable-software-mirroring";
-
 // Disable the notification when a low-power USB charger is connected.
 const char kAshDisableUsbChargerNotification[] =
     "ash-disable-usb-charger-notification";
@@ -91,9 +84,6 @@
 const char kAshEnableAlternateFrameCaptionButtonStyle[] =
     "ash-enable-alternate-caption-button";
 
-// Enables settings ui to control the autoclick accessibility feature.
-const char kAshEnableAutoclick[] = "ash-enable-autoclick";
-
 // Always enable brightness control. Used by machines that don't report their
 // main monitor as internal.
 const char kAshEnableBrightnessControl[] = "ash-enable-brightness-control";
@@ -110,9 +100,6 @@
     "ash-enable-full-multi-profile-mode";
 #endif
 
-// Enable immersive fullscreen mode, regardless of default setting.
-const char kAshEnableImmersiveFullscreen[] = "ash-enable-immersive-fullscreen";
-
 #if defined(OS_LINUX)
 // Enable memory monitoring.
 const char kAshEnableMemoryMonitor[] = "ash-enable-memory-monitor";
@@ -151,15 +138,14 @@
 // "1024x768*2" sets the scale factor to 2 for a high DPI display.
 const char kAshHostWindowBounds[] = "ash-host-window-bounds";
 
-// Hides the small tab indicators at the top of the screen during immersive
-// fullscreen mode.
-const char kAshImmersiveHideTabIndicators[] =
-    "ash-immersive-hide-tab-indicators";
-
 // OEM-supplied wallpaper (as paths to trusted, non-user-writable JPEG files).
 const char kAshOemWallpaperLarge[] = "ash-oem-wallpaper-large";
 const char kAshOemWallpaperSmall[] = "ash-oem-wallpaper-small";
 
+// Specifies the delay in milliseconds before beginning overview mode after
+// getting an alt tab keypress.
+const char kAshOverviewDelayOnAltTab[] = "ash-overview-delay-on-alt-tab";
+
 // Specifies the layout mode and offsets for the secondary display for
 // testing. The format is "<t|r|b|l>,<offset>" where t=TOP, r=RIGHT,
 // b=BOTTOM and L=LEFT. For example, 'r,-100' means the secondary display
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 099b5b9..76f3976 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -32,23 +32,19 @@
 ASH_EXPORT extern const char kAshDisableAutoMaximizing[];
 ASH_EXPORT extern const char kAshDisableDisplayChangeLimiter[];
 ASH_EXPORT extern const char kAshDisableDragOffShelf[];
-ASH_EXPORT extern const char kAshDisableImmersiveFullscreen[];
 ASH_EXPORT extern const char kAshDisableOverviewMode[];
 ASH_EXPORT extern const char kAshDisableDragAndDropAppListToLauncher[];
 #if defined(OS_CHROMEOS)
-ASH_EXPORT extern const char kAshDisableSoftwareMirroring[];
 ASH_EXPORT extern const char kAshDisableUsbChargerNotification[];
 ASH_EXPORT extern const char kAshEnableAudioDeviceMenu[];
 #endif
 ASH_EXPORT extern const char kAshEnableAdvancedGestures[];
 ASH_EXPORT extern const char kAshEnableAlternateFrameCaptionButtonStyle[];
-ASH_EXPORT extern const char kAshEnableAutoclick[];
 ASH_EXPORT extern const char kAshEnableBrightnessControl[];
 ASH_EXPORT extern const char kAshEnableDockedWindows[];
 #if defined(OS_CHROMEOS)
 ASH_EXPORT extern const char kAshEnableFullMultiProfileMode[];
 #endif
-ASH_EXPORT extern const char kAshEnableImmersiveFullscreen[];
 #if defined(OS_LINUX)
 ASH_EXPORT extern const char kAshEnableMemoryMonitor[];
 #endif
@@ -61,9 +57,9 @@
 ASH_EXPORT extern const char kAshGuestWallpaperSmall[];
 ASH_EXPORT extern const char kAshHideNotificationsForFactory[];
 ASH_EXPORT extern const char kAshHostWindowBounds[];
-ASH_EXPORT extern const char kAshImmersiveHideTabIndicators[];
 ASH_EXPORT extern const char kAshOemWallpaperLarge[];
 ASH_EXPORT extern const char kAshOemWallpaperSmall[];
+ASH_EXPORT extern const char kAshOverviewDelayOnAltTab[];
 ASH_EXPORT extern const char kAshSecondaryDisplayLayout[];
 ASH_EXPORT extern const char kAshTouchHud[];
 ASH_EXPORT extern const char kAshUseAlternateShelfLayout[];
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc
index 848fea9..9b49ca2 100644
--- a/ash/autoclick/autoclick_controller.cc
+++ b/ash/autoclick/autoclick_controller.cc
@@ -13,9 +13,29 @@
 #include "ui/events/event_constants.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/point.h"
+#include "ui/gfx/vector2d.h"
 
 namespace ash {
 
+namespace {
+
+// The threshold of mouse movement measured in DIP that will
+// initiate a new autoclick.
+const int kMovementThreshold = 20;
+
+bool IsModifierKey(ui::KeyboardCode key_code) {
+  return key_code == ui::VKEY_SHIFT ||
+      key_code == ui::VKEY_LSHIFT ||
+      key_code == ui::VKEY_CONTROL ||
+      key_code == ui::VKEY_LCONTROL ||
+      key_code == ui::VKEY_RCONTROL ||
+      key_code == ui::VKEY_MENU ||
+      key_code == ui::VKEY_LMENU ||
+      key_code == ui::VKEY_RMENU;
+}
+
+}  // namespace
+
 // static.
 const int AutoclickController::kDefaultAutoclickDelayMs = 400;
 
@@ -36,6 +56,8 @@
   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
   virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
 
   void InitClickTimer();
 
@@ -45,6 +67,9 @@
   int delay_ms_;
   int mouse_event_flags_;
   scoped_ptr<base::Timer> autoclick_timer_;
+  // The position in screen coordinates used to determine
+  // the distance the mouse has moved.
+  gfx::Point anchor_location_;
 
   DISALLOW_COPY_AND_ASSIGN(AutoclickControllerImpl);
 };
@@ -53,7 +78,8 @@
 AutoclickControllerImpl::AutoclickControllerImpl()
     : enabled_(false),
       delay_ms_(kDefaultAutoclickDelayMs),
-      mouse_event_flags_(ui::EF_NONE) {
+      mouse_event_flags_(ui::EF_NONE),
+      anchor_location_(-kMovementThreshold, -kMovementThreshold) {
   InitClickTimer();
 }
 
@@ -98,7 +124,23 @@
 void AutoclickControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
   if (event->type() == ui::ET_MOUSE_MOVED) {
     mouse_event_flags_ = event->flags();
-    autoclick_timer_->Reset();
+
+    gfx::Point mouse_location = event->root_location();
+    ash::wm::ConvertPointToScreen(
+        wm::GetRootWindowAt(mouse_location),
+        &mouse_location);
+
+    // The distance between the mouse location and the anchor location
+    // must exceed a certain threshold to initiate a new autoclick countdown.
+    // This ensures that mouse jitter caused by poor motor control does not
+    // 1. initiate an unwanted autoclick from rest
+    // 2. prevent the autoclick from ever occuring when the mouse
+    //    arrives at the target.
+    gfx::Vector2d delta = mouse_location - anchor_location_;
+    if (delta.LengthSquared() >= kMovementThreshold * kMovementThreshold) {
+      anchor_location_ = event->root_location();
+      autoclick_timer_->Reset();
+    }
   } else if (event->type() == ui::ET_MOUSE_PRESSED) {
     autoclick_timer_->Stop();
   } else if (event->type() == ui::ET_MOUSEWHEEL &&
@@ -116,21 +158,35 @@
       ui::EF_EXTENDED;
   int new_modifiers = event->flags() & modifier_mask;
   mouse_event_flags_ = (mouse_event_flags_ & ~modifier_mask) | new_modifiers;
+
+  if (!IsModifierKey(event->key_code()))
+    autoclick_timer_->Stop();
 }
 
 void AutoclickControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
   autoclick_timer_->Stop();
 }
 
+void AutoclickControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
+  autoclick_timer_->Stop();
+}
+
+void AutoclickControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
+  autoclick_timer_->Stop();
+}
+
 void AutoclickControllerImpl::DoAutoclick() {
   gfx::Point screen_location =
       aura::Env::GetInstance()->last_mouse_location();
-  aura::RootWindow* root_window = wm::GetRootWindowAt(screen_location);
+  aura::Window* root_window = wm::GetRootWindowAt(screen_location);
   DCHECK(root_window) << "Root window not found while attempting autoclick.";
 
   gfx::Point click_location(screen_location);
+  anchor_location_ = click_location;
   wm::ConvertPointFromScreen(root_window, &click_location);
-  root_window->ConvertPointToHost(&click_location);
+
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  dispatcher->ConvertPointToHost(&click_location);
 
   ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED,
                              click_location,
@@ -141,8 +197,8 @@
                                click_location,
                                mouse_event_flags_ | ui::EF_LEFT_MOUSE_BUTTON);
 
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&press_event);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&release_event);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&press_event);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&release_event);
 }
 
 // static.
diff --git a/ash/autoclick/autoclick_unittest.cc b/ash/autoclick/autoclick_unittest.cc
index d756b58..f081c32 100644
--- a/ash/autoclick/autoclick_unittest.cc
+++ b/ash/autoclick/autoclick_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/autoclick/autoclick_controller.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/test/event_generator.h"
 #include "ui/aura/window.h"
 #include "ui/events/event.h"
@@ -17,6 +18,7 @@
 class MouseEventCapturer : public ui::EventHandler {
  public:
   MouseEventCapturer() { Reset(); }
+  virtual ~MouseEventCapturer() {}
 
   void Reset() {
     events_.clear();
@@ -66,7 +68,7 @@
     GetAutoclickController()->SetAutoclickDelay(0);
 
     // Move mouse to deterministic location at the start of each test.
-    GetEventGenerator().MoveMouseTo(10, 10);
+    GetEventGenerator().MoveMouseTo(100, 100);
   }
 
   virtual void TearDown() OVERRIDE {
@@ -117,7 +119,7 @@
   // We should not get any more clicks until we move the mouse.
   events = WaitForMouseEvents();
   EXPECT_EQ(0u, events.size());
-  GetEventGenerator().MoveMouseTo(0, 1);
+  GetEventGenerator().MoveMouseTo(30, 30);
   events = WaitForMouseEvents();
   EXPECT_EQ(2u, events.size());
   EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
@@ -130,22 +132,13 @@
   EXPECT_EQ(0u, events.size());
 }
 
-#if defined(OS_WIN)
-// On Windows, we are getting unexpected mouse drag events that
-// are breaking this test. See http://crbug.com/303830.
-#define MAYBE_MouseMovement \
-        DISABLED_MouseMovement
-#else
-#define MAYBE_MouseMovement \
-        MouseMovement
-#endif
-TEST_F(AutoclickTest, MAYBE_MouseMovement) {
+TEST_F(AutoclickTest, MouseMovement) {
   std::vector<ui::MouseEvent> events;
   GetAutoclickController()->SetEnabled(true);
 
-  gfx::Point p1(1, 1);
-  gfx::Point p2(2, 2);
-  gfx::Point p3(3, 3);
+  gfx::Point p1(0, 0);
+  gfx::Point p2(20, 20);
+  gfx::Point p3(40, 40);
 
   // Move mouse to p1.
   GetEventGenerator().MoveMouseTo(p1);
@@ -164,6 +157,24 @@
   EXPECT_EQ(p3.ToString(), events[1].root_location().ToString());
 }
 
+TEST_F(AutoclickTest, MovementThreshold) {
+  GetAutoclickController()->SetEnabled(true);
+  GetEventGenerator().MoveMouseTo(0, 0);
+  EXPECT_EQ(2u, WaitForMouseEvents().size());
+
+  // Small mouse movements should not trigger an autoclick.
+  GetEventGenerator().MoveMouseTo(1, 1);
+  EXPECT_EQ(0u, WaitForMouseEvents().size());
+  GetEventGenerator().MoveMouseTo(2, 2);
+  EXPECT_EQ(0u, WaitForMouseEvents().size());
+  GetEventGenerator().MoveMouseTo(0, 0);
+  EXPECT_EQ(0u, WaitForMouseEvents().size());
+
+  // A large mouse movement should trigger an autoclick.
+  GetEventGenerator().MoveMouseTo(100, 100);
+  EXPECT_EQ(2u, WaitForMouseEvents().size());
+}
+
 TEST_F(AutoclickTest, SingleKeyModifier) {
   GetAutoclickController()->SetEnabled(true);
   MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN);
@@ -204,15 +215,7 @@
   EXPECT_EQ(ui::EF_ALT_DOWN, events[0].flags() & ui::EF_ALT_DOWN);
 }
 
-#if defined(OS_WIN)
-// Multiple displays are not supported on Windows Ash. http://crbug.com/165962
-#define MAYBE_ExtendedDisplay \
-        DISABLED_ExtendedDisplay
-#else
-#define MAYBE_ExtendedDisplay \
-        ExtendedDisplay
-#endif
-TEST_F(AutoclickTest, MAYBE_ExtendedDisplay) {
+TEST_F(AutoclickTest, ExtendedDisplay) {
   UpdateDisplay("1280x1024,800x600");
   RunAllPendingInMessageLoop();
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
@@ -236,6 +239,51 @@
   EXPECT_EQ(2u, events.size());
   EXPECT_EQ(300, events[0].root_location().x());
   EXPECT_EQ(400, events[0].root_location().y());
+
+  // Test movement threshold between displays.
+}
+
+TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
+  GetAutoclickController()->SetEnabled(true);
+  std::vector<ui::MouseEvent> events;
+
+  // Pressing a normal key should cancel the autoclick.
+  GetEventGenerator().MoveMouseTo(200, 200);
+  GetEventGenerator().PressKey(ui::VKEY_K, ui::EF_NONE);
+  GetEventGenerator().ReleaseKey(ui::VKEY_K, ui::EF_NONE);
+  events = WaitForMouseEvents();
+  EXPECT_EQ(0u, events.size());
+
+  // Pressing a modifier key should NOT cancel the autoclick.
+  GetEventGenerator().MoveMouseTo(100, 100);
+  GetEventGenerator().PressKey(ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN);
+  GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT, ui::EF_NONE);
+  events = WaitForMouseEvents();
+  EXPECT_EQ(2u, events.size());
+
+  // Performing a gesture should cancel the autoclick.
+  GetEventGenerator().MoveMouseTo(200, 200);
+  GetEventGenerator().GestureTapDownAndUp(gfx::Point(100, 100));
+  events = WaitForMouseEvents();
+  EXPECT_EQ(0u, events.size());
+
+  // Test another gesture.
+  GetEventGenerator().MoveMouseTo(100, 100);
+  GetEventGenerator().GestureScrollSequence(
+      gfx::Point(100, 100),
+      gfx::Point(200, 200),
+      base::TimeDelta::FromMilliseconds(200),
+      3);
+  events = WaitForMouseEvents();
+  EXPECT_EQ(0u, events.size());
+
+  // Test scroll events.
+  GetEventGenerator().MoveMouseTo(200, 200);
+  GetEventGenerator().ScrollSequence(
+      gfx::Point(100, 100), base::TimeDelta::FromMilliseconds(200),
+      0, 100, 3, 2);
+  events = WaitForMouseEvents();
+  EXPECT_EQ(0u, events.size());
 }
 
 }  // namespace ash
diff --git a/ash/default_accessibility_delegate.cc b/ash/default_accessibility_delegate.cc
new file mode 100644
index 0000000..bfc6b50
--- /dev/null
+++ b/ash/default_accessibility_delegate.cc
@@ -0,0 +1,87 @@
+// Copyright 2013 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 "ash/default_accessibility_delegate.h"
+
+#include <limits>
+
+namespace ash {
+namespace internal {
+
+DefaultAccessibilityDelegate::DefaultAccessibilityDelegate()
+    : spoken_feedback_enabled_(false),
+      high_contrast_enabled_(false),
+      screen_magnifier_enabled_(false),
+      screen_magnifier_type_(kDefaultMagnifierType),
+      large_cursor_enabled_(false),
+      autoclick_enabled_(false) {
+}
+
+DefaultAccessibilityDelegate::~DefaultAccessibilityDelegate() {}
+
+bool DefaultAccessibilityDelegate::IsSpokenFeedbackEnabled() const {
+  return spoken_feedback_enabled_;
+}
+
+void DefaultAccessibilityDelegate::ToggleHighContrast() {
+  high_contrast_enabled_ = !high_contrast_enabled_;
+}
+
+bool DefaultAccessibilityDelegate::IsHighContrastEnabled() const {
+  return high_contrast_enabled_;
+}
+
+void DefaultAccessibilityDelegate::SetMagnifierEnabled(bool enabled) {
+  screen_magnifier_enabled_ = enabled;
+}
+
+void DefaultAccessibilityDelegate::SetMagnifierType(MagnifierType type) {
+  screen_magnifier_type_ = type;
+}
+
+bool DefaultAccessibilityDelegate::IsMagnifierEnabled() const {
+  return screen_magnifier_enabled_;
+}
+
+MagnifierType DefaultAccessibilityDelegate::GetMagnifierType() const {
+  return screen_magnifier_type_;
+}
+
+void DefaultAccessibilityDelegate::SetLargeCursorEnabled(bool enabled) {
+  large_cursor_enabled_ = enabled;
+}
+
+bool DefaultAccessibilityDelegate::IsLargeCursorEnabled() const {
+  return large_cursor_enabled_;
+}
+
+void DefaultAccessibilityDelegate::SetAutoclickEnabled(bool enabled) {
+  autoclick_enabled_ = enabled;
+}
+
+bool DefaultAccessibilityDelegate::IsAutoclickEnabled() const {
+  return autoclick_enabled_;
+}
+
+bool DefaultAccessibilityDelegate::ShouldAlwaysShowAccessibilityMenu() const {
+  return false;
+}
+
+void DefaultAccessibilityDelegate::SilenceSpokenFeedback() const {
+}
+
+void DefaultAccessibilityDelegate::ToggleSpokenFeedback(
+    AccessibilityNotificationVisibility notify) {
+  spoken_feedback_enabled_ = !spoken_feedback_enabled_;
+}
+
+void DefaultAccessibilityDelegate::SaveScreenMagnifierScale(double scale) {
+}
+
+double DefaultAccessibilityDelegate::GetSavedScreenMagnifierScale() {
+  return std::numeric_limits<double>::min();
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/default_accessibility_delegate.h b/ash/default_accessibility_delegate.h
new file mode 100644
index 0000000..58a48ab
--- /dev/null
+++ b/ash/default_accessibility_delegate.h
@@ -0,0 +1,53 @@
+// Copyright 2013 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 ASH_DEFAULT_ACCESSIBILITY_DELEGATE_H_
+#define ASH_DEFAULT_ACCESSIBILITY_DELEGATE_H_
+
+#include "ash/accessibility_delegate.h"
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace ash {
+namespace internal {
+
+class ASH_EXPORT DefaultAccessibilityDelegate : public AccessibilityDelegate {
+ public:
+  DefaultAccessibilityDelegate();
+  virtual ~DefaultAccessibilityDelegate();
+
+  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE;
+  virtual void ToggleHighContrast() OVERRIDE;
+  virtual bool IsHighContrastEnabled() const OVERRIDE;
+  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE;
+  virtual void SetMagnifierType(MagnifierType type) OVERRIDE;
+  virtual bool IsMagnifierEnabled() const OVERRIDE;
+  virtual MagnifierType GetMagnifierType() const OVERRIDE;
+  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE;
+  virtual bool IsLargeCursorEnabled() const OVERRIDE;
+  virtual void SetAutoclickEnabled(bool enabled) OVERRIDE;
+  virtual bool IsAutoclickEnabled() const OVERRIDE;
+  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE;
+  virtual void SilenceSpokenFeedback() const OVERRIDE;
+  virtual void ToggleSpokenFeedback(
+      AccessibilityNotificationVisibility notify) OVERRIDE;
+  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
+  virtual double GetSavedScreenMagnifierScale() OVERRIDE;
+
+ private:
+  bool spoken_feedback_enabled_;
+  bool high_contrast_enabled_;
+  bool screen_magnifier_enabled_;
+  MagnifierType screen_magnifier_type_;
+  bool large_cursor_enabled_;
+  bool autoclick_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityDelegate);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // DEFAULT_ACCESSIBILITY_DELEGATE_H_
diff --git a/ash/desktop_background/desktop_background_controller_unittest.cc b/ash/desktop_background/desktop_background_controller_unittest.cc
index 4d91949..6a7d19c 100644
--- a/ash/desktop_background/desktop_background_controller_unittest.cc
+++ b/ash/desktop_background/desktop_background_controller_unittest.cc
@@ -45,7 +45,7 @@
 
 // Returns number of child windows in a shell window container.
 int ChildCountForContainer(int container_id) {
-  RootWindow* root = ash::Shell::GetPrimaryRootWindow();
+  Window* root = ash::Shell::GetPrimaryRootWindow();
   Window* container = root->GetChildById(container_id);
   return static_cast<int>(container->children().size());
 }
diff --git a/ash/dip_unittest.cc b/ash/dip_unittest.cc
index 59020e8..a501ad2 100644
--- a/ash/dip_unittest.cc
+++ b/ash/dip_unittest.cc
@@ -35,7 +35,7 @@
 TEST_F(DIPTest, WorkArea) {
   UpdateDisplay("1000x900*1.0f");
 
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   const gfx::Display display =
       Shell::GetScreen()->GetDisplayNearestWindow(root);
 
@@ -74,7 +74,7 @@
       ash::switches::kAshDisableAlternateShelfLayout);
   UpdateDisplay("1000x900*1.0f");
 
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   const gfx::Display display =
       Shell::GetScreen()->GetDisplayNearestWindow(root);
 
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc
index 71bdfcd..0d67e45 100644
--- a/ash/display/display_change_observer_chromeos.cc
+++ b/ash/display/display_change_observer_chromeos.cc
@@ -197,6 +197,9 @@
     displays.back().SetBounds(display_bounds);
     displays.back().set_native(true);
     displays.back().set_resolutions(resolutions);
+    displays.back().set_touch_support(
+        output.touch_device_id == 0 ? gfx::Display::TOUCH_SUPPORT_UNAVAILABLE :
+                                      gfx::Display::TOUCH_SUPPORT_AVAILABLE);
   }
 
   // DisplayManager can be null during the boot.
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index 5714b93..8a0b6b9 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -13,6 +13,7 @@
 #include "ash/display/display_manager.h"
 #include "ash/display/mirror_window_controller.h"
 #include "ash/display/root_window_transformers.h"
+#include "ash/display/virtual_keyboard_window_controller.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/root_window_controller.h"
 #include "ash/root_window_settings.h"
@@ -144,7 +145,7 @@
 
   void Store(bool display_removed) {
     if (!activation_client_) {
-      aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+      aura::Window* root = Shell::GetPrimaryRootWindow();
       activation_client_ = aura::client::GetActivationClient(root);
       capture_client_ = aura::client::GetCaptureClient(root);
       focus_client_ = aura::client::GetFocusClient(root);
@@ -221,7 +222,9 @@
 DisplayController::DisplayController()
     : primary_root_window_for_replace_(NULL),
       focus_activation_store_(new internal::FocusActivationStore()),
-      mirror_window_controller_(new internal::MirrorWindowController) {
+      mirror_window_controller_(new internal::MirrorWindowController),
+      virtual_keyboard_window_controller_(
+          new internal::VirtualKeyboardWindowController) {
 #if defined(OS_CHROMEOS)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) &&
@@ -251,6 +254,7 @@
   Shell::GetInstance()->display_manager()->set_delegate(NULL);
 
   mirror_window_controller_.reset();
+  virtual_keyboard_window_controller_.reset();
 
   DCHECK(!primary_display_for_shutdown);
   primary_display_for_shutdown = new gfx::Display(
@@ -311,12 +315,12 @@
   observers_.RemoveObserver(observer);
 }
 
-aura::RootWindow* DisplayController::GetPrimaryRootWindow() {
+aura::Window* DisplayController::GetPrimaryRootWindow() {
   DCHECK(!root_windows_.empty());
   return root_windows_[primary_display_id];
 }
 
-aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) {
+aura::Window* DisplayController::GetRootWindowForDisplayId(int64 id) {
   return root_windows_[id];
 }
 
@@ -495,12 +499,12 @@
   int64 closest_distance_squared = -1;
   internal::DisplayManager* display_manager = GetDisplayManager();
 
-  aura::RootWindow* dst_root_window = NULL;
+  aura::Window* dst_root_window = NULL;
   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
     const gfx::Display& display = display_manager->GetDisplayAt(i);
     const internal::DisplayInfo display_info =
         display_manager->GetDisplayInfo(display.id());
-    aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
+    aura::Window* root_window = GetRootWindowForDisplayId(display.id());
     if (display_info.bounds_in_native().Contains(
             cursor_location_in_native_coords_for_restore_)) {
       dst_root_window = root_window;
@@ -517,24 +521,25 @@
     int64 distance_squared = (center - point_in_screen).LengthSquared();
     if (closest_distance_squared < 0 ||
         closest_distance_squared > distance_squared) {
-      aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
+      aura::Window* root_window = GetRootWindowForDisplayId(display.id());
       aura::client::ScreenPositionClient* client =
           aura::client::GetScreenPositionClient(root_window);
       client->ConvertPointFromScreen(root_window, &center);
-      root_window->ConvertPointToNativeScreen(&center);
+      root_window->GetDispatcher()->ConvertPointToNativeScreen(&center);
       dst_root_window = root_window;
       target_location_in_native = center;
       closest_distance_squared = distance_squared;
     }
   }
-  dst_root_window->ConvertPointFromNativeScreen(&target_location_in_native);
+  dst_root_window->GetDispatcher()->ConvertPointFromNativeScreen(
+      &target_location_in_native);
   dst_root_window->MoveCursorTo(target_location_in_native);
 }
 
 bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow(
     const aura::Window* window,
     const gfx::Insets& insets) {
-  const aura::RootWindow* root_window = window->GetRootWindow();
+  const aura::Window* root_window = window->GetRootWindow();
   int64 id = internal::GetRootWindowSettings(root_window)->display_id;
   // if id is |kInvaildDisplayID|, it's being deleted.
   DCHECK(id != gfx::Display::kInvalidDisplayID);
@@ -545,7 +550,7 @@
     const aura::Window* window) const {
   if (!window)
     return GetPrimaryDisplay();
-  const aura::RootWindow* root_window = window->GetRootWindow();
+  const aura::Window* root_window = window->GetRootWindow();
   if (!root_window)
     return GetPrimaryDisplay();
   int64 id = internal::GetRootWindowSettings(root_window)->display_id;
@@ -553,12 +558,10 @@
   DCHECK(id != gfx::Display::kInvalidDisplayID);
 
   internal::DisplayManager* display_manager = GetDisplayManager();
-  // RootWindow needs Display to determine its device scale factor.
-  // TODO(oshima): We don't need full display info for mirror
-  // window. Refactor so that RootWindow doesn't use it.
-  if (display_manager->mirrored_display().id() == id)
-    return display_manager->mirrored_display();
-
+  // RootWindow needs Display to determine its device scale factor
+  // for non desktop display.
+  if (display_manager->non_desktop_display().id() == id)
+    return display_manager->non_desktop_display();
   return display_manager->GetDisplayForId(id);
 }
 
@@ -675,13 +678,25 @@
   }
 }
 
-void DisplayController::CreateOrUpdateMirrorWindow(
+void DisplayController::CreateOrUpdateNonDesktopDisplay(
     const internal::DisplayInfo& info) {
-  mirror_window_controller_->UpdateWindow(info);
+  switch (GetDisplayManager()->second_display_mode()) {
+    case internal::DisplayManager::MIRRORING:
+      mirror_window_controller_->UpdateWindow(info);
+      virtual_keyboard_window_controller_->Close();
+      break;
+    case internal::DisplayManager::VIRTUAL_KEYBOARD:
+      mirror_window_controller_->Close();
+      virtual_keyboard_window_controller_->UpdateWindow(info);
+      break;
+    case internal::DisplayManager::EXTENDED:
+      NOTREACHED();
+  }
 }
 
-void DisplayController::CloseMirrorWindow() {
+void DisplayController::CloseNonDesktopDisplay() {
   mirror_window_controller_->Close();
+  virtual_keyboard_window_controller_->Close();
 }
 
 void DisplayController::PreDisplayConfigurationChange(bool display_removed) {
@@ -691,12 +706,12 @@
   gfx::Point point_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
   gfx::Display display =
       Shell::GetScreen()->GetDisplayNearestPoint(point_in_screen);
-  aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
+  aura::Window* root_window = GetRootWindowForDisplayId(display.id());
 
   aura::client::ScreenPositionClient* client =
       aura::client::GetScreenPositionClient(root_window);
   client->ConvertPointFromScreen(root_window, &point_in_screen);
-  root_window->ConvertPointToNativeScreen(&point_in_screen);
+  root_window->GetDispatcher()->ConvertPointToNativeScreen(&point_in_screen);
   cursor_location_in_native_coords_for_restore_ = point_in_screen;
 }
 
@@ -774,12 +789,13 @@
   // crbug.com/120229 - set the window title for the primary dislpay
   // to "aura_root_0" so gtalk can find the primary root window to broadcast.
   // TODO(jhorwich) Remove this once Chrome supports window-based broadcasting.
-  aura::RootWindow* primary = Shell::GetPrimaryRootWindow();
+  aura::Window* primary = Shell::GetPrimaryRootWindow();
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
   for (size_t i = 0; i < root_windows.size(); ++i) {
     std::string name =
         root_windows[i] == primary ? "aura_root_0" : "aura_root_x";
-    gfx::AcceleratedWidget xwindow = root_windows[i]->GetAcceleratedWidget();
+    gfx::AcceleratedWidget xwindow =
+        root_windows[i]->GetDispatcher()->GetAcceleratedWidget();
     XStoreName(gfx::GetXDisplay(), xwindow, name.c_str());
   }
 #endif
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index dbe5f50..ec84a58 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -42,6 +42,7 @@
 class FocusActivationStore;
 class MirrorWindowController;
 class RootWindowController;
+class VirtualKeyboardWindowController;
 }
 
 // DisplayController owns and maintains RootWindows for each attached
@@ -93,10 +94,10 @@
   void RemoveObserver(Observer* observer);
 
   // Returns the root window for primary display.
-  aura::RootWindow* GetPrimaryRootWindow();
+  aura::Window* GetPrimaryRootWindow();
 
   // Returns the root window for |display_id|.
-  aura::RootWindow* GetRootWindowForDisplayId(int64 id);
+  aura::Window* GetRootWindowForDisplayId(int64 id);
 
   // Toggle mirror mode.
   void ToggleMirrorMode();
@@ -158,9 +159,9 @@
   virtual void OnRootWindowHostResized(const aura::RootWindow* root) OVERRIDE;
 
   // aura::DisplayManager::Delegate overrides:
-  virtual void CreateOrUpdateMirrorWindow(
+  virtual void CreateOrUpdateNonDesktopDisplay(
       const internal::DisplayInfo& info) OVERRIDE;
-  virtual void CloseMirrorWindow() OVERRIDE;
+  virtual void CloseNonDesktopDisplay() OVERRIDE;
   virtual void PreDisplayConfigurationChange(bool dispay_removed) OVERRIDE;
   virtual void PostDisplayConfigurationChange() OVERRIDE;
 
@@ -209,8 +210,9 @@
 
   scoped_ptr<internal::FocusActivationStore> focus_activation_store_;
 
-
   scoped_ptr<internal::MirrorWindowController> mirror_window_controller_;
+  scoped_ptr<internal::VirtualKeyboardWindowController>
+      virtual_keyboard_window_controller_;
 
   // Stores the curent cursor location (in native coordinates) used to
   // restore the cursor location when display configuration
diff --git a/ash/display/display_controller_unittest.cc b/ash/display/display_controller_unittest.cc
index 3d4acf2..a422109 100644
--- a/ash/display/display_controller_unittest.cc
+++ b/ash/display/display_controller_unittest.cc
@@ -258,7 +258,7 @@
 
  private:
   gfx::Point mouse_location_;
-  aura::RootWindow* target_root_;
+  aura::Window* target_root_;
 
   float touch_radius_x_;
   float touch_radius_y_;
@@ -279,8 +279,8 @@
 }
 
 #if defined(USE_X11)
-void GetPrimaryAndSeconary(aura::RootWindow** primary,
-                           aura::RootWindow** secondary) {
+void GetPrimaryAndSeconary(aura::Window** primary,
+                           aura::Window** secondary) {
   *primary = Shell::GetPrimaryRootWindow();
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
   *secondary = root_windows[0] == *primary ? root_windows[1] : root_windows[0];
@@ -547,9 +547,9 @@
   display_manager->SetLayoutForCurrentDisplays(display_layout);
 
   EXPECT_NE(primary_display.id(), secondary_display.id());
-  aura::RootWindow* primary_root =
+  aura::Window* primary_root =
       display_controller->GetRootWindowForDisplayId(primary_display.id());
-  aura::RootWindow* secondary_root =
+  aura::Window* secondary_root =
       display_controller->GetRootWindowForDisplayId(secondary_display.id());
   EXPECT_NE(primary_root, secondary_root);
   aura::Window* launcher_window =
@@ -641,9 +641,9 @@
   display_manager->SetLayoutForCurrentDisplays(display_layout);
 
   EXPECT_NE(primary_display.id(), secondary_display.id());
-  aura::RootWindow* primary_root =
+  aura::Window* primary_root =
       display_controller->GetRootWindowForDisplayId(primary_display.id());
-  aura::RootWindow* secondary_root =
+  aura::Window* secondary_root =
       display_controller->GetRootWindowForDisplayId(secondary_display.id());
   EXPECT_NE(primary_root, secondary_root);
   aura::Window* launcher_window =
@@ -732,9 +732,9 @@
   display_manager->SetLayoutForCurrentDisplays(display_layout);
 
   EXPECT_NE(primary_display.id(), secondary_display.id());
-  aura::RootWindow* primary_root =
+  aura::Window* primary_root =
       display_controller->GetRootWindowForDisplayId(primary_display.id());
-  aura::RootWindow* secondary_root =
+  aura::Window* secondary_root =
       display_controller->GetRootWindowForDisplayId(secondary_display.id());
   aura::Window* launcher_window =
       Launcher::ForPrimaryDisplay()->shelf_widget()->GetNativeView();
@@ -850,20 +850,20 @@
   gfx::Display primary_display = Shell::GetScreen()->GetPrimaryDisplay();
   gfx::Display secondary_display = ScreenAsh::GetSecondaryDisplay();
 
-  aura::RootWindow* primary_root =
+  aura::Window* primary_root =
       display_controller->GetRootWindowForDisplayId(primary_display.id());
-  aura::RootWindow* secondary_root =
+  aura::Window* secondary_root =
       display_controller->GetRootWindowForDisplayId(secondary_display.id());
   EXPECT_NE(primary_root, secondary_root);
 
   test::CursorManagerTestApi test_api(Shell::GetInstance()->cursor_manager());
 
-  EXPECT_EQ(1.0f,
-            primary_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+  EXPECT_EQ(1.0f, primary_root->GetDispatcher()->AsRootWindowHostDelegate()->
+      GetDeviceScaleFactor());
   primary_root->MoveCursorTo(gfx::Point(50, 50));
   EXPECT_EQ(1.0f, test_api.GetDisplay().device_scale_factor());
-  EXPECT_EQ(2.0f,
-            secondary_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+  EXPECT_EQ(2.0f, secondary_root->GetDispatcher()->AsRootWindowHostDelegate()->
+      GetDeviceScaleFactor());
   secondary_root->MoveCursorTo(gfx::Point(50, 50));
   EXPECT_EQ(2.0f, test_api.GetDisplay().device_scale_factor());
 
@@ -872,13 +872,13 @@
 
   // Cursor's device scale factor should be updated accroding to the swap of
   // primary and secondary.
-  EXPECT_EQ(1.0f,
-            secondary_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+  EXPECT_EQ(1.0f, secondary_root->GetDispatcher()->AsRootWindowHostDelegate()->
+      GetDeviceScaleFactor());
   secondary_root->MoveCursorTo(gfx::Point(50, 50));
   EXPECT_EQ(1.0f, test_api.GetDisplay().device_scale_factor());
   primary_root->MoveCursorTo(gfx::Point(50, 50));
-  EXPECT_EQ(2.0f,
-            primary_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+  EXPECT_EQ(2.0f, primary_root->GetDispatcher()->AsRootWindowHostDelegate()->
+      GetDeviceScaleFactor());
   EXPECT_EQ(2.0f, test_api.GetDisplay().device_scale_factor());
 
   // Deleting 2nd display.
@@ -889,8 +889,8 @@
   EXPECT_EQ(1.0f, test_api.GetDisplay().device_scale_factor());
 
   primary_root->MoveCursorTo(gfx::Point(50, 50));
-  EXPECT_EQ(1.0f,
-            primary_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+  EXPECT_EQ(1.0f, primary_root->GetDispatcher()->AsRootWindowHostDelegate()->
+      GetDeviceScaleFactor());
   EXPECT_EQ(1.0f, test_api.GetDisplay().device_scale_factor());
 }
 
@@ -1145,25 +1145,27 @@
 
 #if defined(USE_X11)
 TEST_F(DisplayControllerTest, XWidowNameForRootWindow) {
-  EXPECT_EQ("aura_root_0", GetXWindowName(Shell::GetPrimaryRootWindow()));
+  EXPECT_EQ("aura_root_0", GetXWindowName(
+      Shell::GetPrimaryRootWindow()->GetDispatcher()));
 
   // Multiple display.
   UpdateDisplay("200x200,300x300");
-  aura::RootWindow* primary, *secondary;
+  aura::Window* primary, *secondary;
   GetPrimaryAndSeconary(&primary, &secondary);
-  EXPECT_EQ("aura_root_0", GetXWindowName(primary));
-  EXPECT_EQ("aura_root_x", GetXWindowName(secondary));
+  EXPECT_EQ("aura_root_0", GetXWindowName(primary->GetDispatcher()));
+  EXPECT_EQ("aura_root_x", GetXWindowName(secondary->GetDispatcher()));
 
   // Swap primary.
   primary = secondary = NULL;
   Shell::GetInstance()->display_controller()->SwapPrimaryDisplay();
   GetPrimaryAndSeconary(&primary, &secondary);
-  EXPECT_EQ("aura_root_0", GetXWindowName(primary));
-  EXPECT_EQ("aura_root_x", GetXWindowName(secondary));
+  EXPECT_EQ("aura_root_0", GetXWindowName(primary->GetDispatcher()));
+  EXPECT_EQ("aura_root_x", GetXWindowName(secondary->GetDispatcher()));
 
   // Switching back to single display.
   UpdateDisplay("300x400");
-  EXPECT_EQ("aura_root_0", GetXWindowName(Shell::GetPrimaryRootWindow()));
+  EXPECT_EQ("aura_root_0", GetXWindowName(
+      Shell::GetPrimaryRootWindow()->GetDispatcher()));
 }
 #endif
 
diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc
index fdaa80f..c09dfc3 100644
--- a/ash/display/display_info.cc
+++ b/ash/display/display_info.cc
@@ -137,6 +137,7 @@
     : id_(gfx::Display::kInvalidDisplayID),
       has_overscan_(false),
       rotation_(gfx::Display::ROTATE_0),
+      touch_support_(gfx::Display::TOUCH_SUPPORT_UNKNOWN),
       device_scale_factor_(1.0f),
       overscan_insets_in_dip_(0, 0, 0, 0),
       ui_scale_(1.0f),
@@ -150,6 +151,7 @@
       name_(name),
       has_overscan_(has_overscan),
       rotation_(gfx::Display::ROTATE_0),
+      touch_support_(gfx::Display::TOUCH_SUPPORT_UNKNOWN),
       device_scale_factor_(1.0f),
       overscan_insets_in_dip_(0, 0, 0, 0),
       ui_scale_(1.0f),
@@ -169,6 +171,7 @@
   size_in_pixel_ = native_info.size_in_pixel_;
   device_scale_factor_ = native_info.device_scale_factor_;
   resolutions_ = native_info.resolutions_;
+  touch_support_ = native_info.touch_support_;
 
   // Copy overscan_insets_in_dip_ if it's not empty. This is for test
   // cases which use "/o" annotation which sets the overscan inset
@@ -225,14 +228,17 @@
   int rotation_degree = static_cast<int>(rotation_) * 90;
   return base::StringPrintf(
       "DisplayInfo[%lld] native bounds=%s, size=%s, scale=%f, "
-      "overscan=%s, rotation=%d, ui-scale=%f",
+      "overscan=%s, rotation=%d, ui-scale=%f, touchscreen=%s",
       static_cast<long long int>(id_),
       bounds_in_native_.ToString().c_str(),
       size_in_pixel_.ToString().c_str(),
       device_scale_factor_,
       overscan_insets_in_dip_.ToString().c_str(),
       rotation_degree,
-      ui_scale_);
+      ui_scale_,
+      touch_support_ == gfx::Display::TOUCH_SUPPORT_AVAILABLE ? "yes" :
+      touch_support_ == gfx::Display::TOUCH_SUPPORT_UNAVAILABLE ? "no" :
+      "unknown");
 }
 
 std::string DisplayInfo::ToFullString() const {
diff --git a/ash/display/display_info.h b/ash/display/display_info.h
index e81ad17..958b6d4 100644
--- a/ash/display/display_info.h
+++ b/ash/display/display_info.h
@@ -89,6 +89,11 @@
   void set_rotation(gfx::Display::Rotation rotation) { rotation_ = rotation; }
   gfx::Display::Rotation rotation() const { return rotation_; }
 
+  void set_touch_support(gfx::Display::TouchSupport support) {
+    touch_support_ = support;
+  }
+  gfx::Display::TouchSupport touch_support() const { return touch_support_; }
+
   // Gets/Sets the device scale factor of the display.
   float device_scale_factor() const { return device_scale_factor_; }
   void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
@@ -150,6 +155,7 @@
   std::string name_;
   bool has_overscan_;
   gfx::Display::Rotation rotation_;
+  gfx::Display::TouchSupport touch_support_;
 
   // This specifies the device's pixel density. (For example, a
   // display whose DPI is higher than the threshold is considered to have
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index 9ffa6c8..7724c85 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -101,28 +101,28 @@
     gfx::Display::SetInternalDisplayId(id);
 }
 
-// Scoped objects used to either create or close the mirror window
+// Scoped objects used to either create or close the non desktop window
 // at specific timing.
-class MirrorWindowUpdater {
+class NonDesktopDisplayUpdater {
  public:
-  MirrorWindowUpdater(DisplayManager* manager,
-                      DisplayManager::Delegate* delegate)
+  NonDesktopDisplayUpdater(DisplayManager* manager,
+                           DisplayManager::Delegate* delegate)
       : manager_(manager),
         delegate_(delegate),
-        enabled_(manager_->software_mirroring_enabled() &&
-                 manager_->mirrored_display().is_valid()) {
+        enabled_(manager_->second_display_mode() != DisplayManager::EXTENDED &&
+                 manager_->non_desktop_display().is_valid()) {
   }
 
-  ~MirrorWindowUpdater() {
+  ~NonDesktopDisplayUpdater() {
     if (!delegate_)
       return;
 
     if (enabled_) {
       DisplayInfo display_info = manager_->GetDisplayInfo(
-          manager_->mirrored_display().id());
-      delegate_->CreateOrUpdateMirrorWindow(display_info);
+          manager_->non_desktop_display().id());
+      delegate_->CreateOrUpdateNonDesktopDisplay(display_info);
     } else {
-      delegate_->CloseMirrorWindow();
+      delegate_->CloseNonDesktopDisplay();
     }
   }
 
@@ -132,7 +132,7 @@
   DisplayManager* manager_;
   DisplayManager::Delegate* delegate_;
   bool enabled_;
-  DISALLOW_COPY_AND_ASSIGN(MirrorWindowUpdater);
+  DISALLOW_COPY_AND_ASSIGN(NonDesktopDisplayUpdater);
 };
 
 }  // namespace
@@ -147,7 +147,8 @@
       num_connected_displays_(0),
       force_bounds_changed_(false),
       change_display_upon_host_resize_(false),
-      software_mirroring_enabled_(false) {
+      second_display_mode_(EXTENDED),
+      mirrored_display_id_(gfx::Display::kInvalidDisplayID) {
 #if defined(OS_CHROMEOS)
   change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
 #endif
@@ -216,7 +217,7 @@
     MaybeInitInternalDisplay(info_list[0].id());
   if (info_list.size() > 1 &&
       command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
-    SetSoftwareMirroring(true);
+    SetSecondDisplayMode(MIRRORING);
   }
   OnNativeDisplaysChanged(info_list);
 }
@@ -268,8 +269,7 @@
 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
   if (IsMirrored()) {
     DCHECK_LE(2u, num_connected_displays());
-    int64 mirrored_id = mirrored_display().id();
-    return std::make_pair(displays_[0].id(), mirrored_id);
+    return std::make_pair(displays_[0].id(), mirrored_display_id_);
   } else {
     CHECK_GE(2u, displays_.size());
     int64 id_at_zero = displays_[0].id();
@@ -511,7 +511,8 @@
 
   bool internal_display_connected = false;
   num_connected_displays_ = updated_displays.size();
-  mirrored_display_ = gfx::Display();
+  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
+  non_desktop_display_ = gfx::Display();
   DisplayInfoList new_display_info_list;
   for (DisplayInfoList::const_iterator iter = updated_displays.begin();
        iter != updated_displays.end();
@@ -522,7 +523,7 @@
     gfx::Point origin = iter->bounds_in_native().origin();
     if (origins.find(origin) != origins.end()) {
       InsertAndUpdateDisplayInfo(*iter);
-      mirrored_display_ = CreateDisplayFromDisplayInfoById(iter->id());
+      mirrored_display_id_ = iter->id();
     } else {
       origins.insert(origin);
       new_display_info_list.push_back(*iter);
@@ -580,26 +581,37 @@
   // the root window so that it matches the external display's
   // resolution. This is necessary in order for scaling to work while
   // mirrored.
-  int64 mirrored_display_id = gfx::Display::kInvalidDisplayID;
-  if (software_mirroring_enabled_ && new_display_info_list.size() == 2) {
+  int64 non_desktop_display_id = gfx::Display::kInvalidDisplayID;
+
+  if (second_display_mode_ != EXTENDED && new_display_info_list.size() == 2) {
     bool zero_is_source =
         first_display_id_ == new_display_info_list[0].id() ||
         gfx::Display::InternalDisplayId() == new_display_info_list[0].id();
-    mirrored_display_id = new_display_info_list[zero_is_source ? 1 : 0].id();
+    if (second_display_mode_ == MIRRORING) {
+      mirrored_display_id_ = new_display_info_list[zero_is_source ? 1 : 0].id();
+      non_desktop_display_id = mirrored_display_id_;
+    } else {
+      // TODO(oshima|bshe): The virtual keyboard is currently assigned to
+      // the 1st display.
+      non_desktop_display_id =
+          new_display_info_list[zero_is_source ? 0 : 1].id();
+    }
   }
 
   while (curr_iter != displays_.end() ||
          new_info_iter != new_display_info_list.end()) {
     if (new_info_iter != new_display_info_list.end() &&
-        mirrored_display_id == new_info_iter->id()) {
+        non_desktop_display_id == new_info_iter->id()) {
       DisplayInfo info = *new_info_iter;
       info.SetOverscanInsets(gfx::Insets());
       InsertAndUpdateDisplayInfo(info);
-      mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id());
+      non_desktop_display_ =
+          CreateDisplayFromDisplayInfoById(non_desktop_display_id);
       ++new_info_iter;
-      // Remove existing external dispaly if it is going to be mirrored.
+      // Remove existing external dispaly if it is going to be used as
+      // non desktop.
       if (curr_iter != displays_.end() &&
-          curr_iter->id() == mirrored_display_id) {
+          curr_iter->id() == non_desktop_display_id) {
         removed_displays.push_back(*curr_iter);
         ++curr_iter;
       }
@@ -660,8 +672,8 @@
     }
   }
 
-  scoped_ptr<MirrorWindowUpdater> mirror_window_updater(
-      new MirrorWindowUpdater(this, delegate_));
+  scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater(
+      new NonDesktopDisplayUpdater(this, delegate_));
 
   // Do not update |displays_| if there's nothing to be updated. Without this,
   // it will not update the display layout, which causes the bug
@@ -698,18 +710,18 @@
     Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back());
     displays_.pop_back();
   }
-  // Close the mirror window here to avoid creating two compositor on
+  // Close the non desktop window here to avoid creating two compositor on
   // one display.
-  if (!mirror_window_updater->enabled())
-    mirror_window_updater.reset();
+  if (!non_desktop_display_updater->enabled())
+    non_desktop_display_updater.reset();
   for (std::vector<size_t>::iterator iter = added_display_indices.begin();
        iter != added_display_indices.end(); ++iter) {
     Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]);
   }
-  // Create the mirror window after all displays are added so that
+  // Create the non destkop window after all displays are added so that
   // it can mirror the display newly added. This can happen when switching
   // from dock mode to software mirror mode.
-  mirror_window_updater.reset();
+  non_desktop_display_updater.reset();
   for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
        iter != changed_display_indices.end(); ++iter) {
     Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
@@ -729,9 +741,8 @@
 }
 
 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
-  if (GetNumDisplays() == 1) {
+  if (GetNumDisplays() == 1)
     return displays_[0];
-  }
   DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
       GetCurrentDisplayIdPair());
   return GetDisplayForId(layout.primary_id);
@@ -742,7 +753,7 @@
 }
 
 bool DisplayManager::IsMirrored() const {
-  return mirrored_display_.id() != gfx::Display::kInvalidDisplayID;
+  return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
 }
 
 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
@@ -784,7 +795,8 @@
     return;
   }
 #endif
-  SetSoftwareMirroring(mirrored);
+  // This is fallback path to emulate mirroroing on desktop.
+  SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
   DisplayInfoList display_info_list;
   int count = 0;
   for (std::map<int64, DisplayInfo>::const_iterator iter =
@@ -815,7 +827,7 @@
             "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
   }
   num_connected_displays_ = new_display_info_list.size();
-  mirrored_display_ = gfx::Display();
+  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
   UpdateDisplays(new_display_info_list);
 }
 
@@ -833,9 +845,20 @@
   UpdateDisplays(new_display_info_list);
 }
 
+#if defined(OS_CHROMEOS)
 void DisplayManager::SetSoftwareMirroring(bool enabled) {
-  software_mirroring_enabled_ = enabled;
-  mirrored_display_ = gfx::Display();
+  // TODO(oshima|bshe): Support external display on the system
+  // that has virtual keyboard display.
+  if (second_display_mode_ == VIRTUAL_KEYBOARD)
+    return;
+  SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
+}
+#endif
+
+void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
+  second_display_mode_ = mode;
+  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
+  non_desktop_display_ = gfx::Display();
 }
 
 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
@@ -843,7 +866,7 @@
   if (change_display_upon_host_resize_) {
     display_info_[display_id].SetBounds(new_bounds);
     // Don't notify observers if the mirrored window has changed.
-    if (software_mirroring_enabled_ && mirrored_display_.id() == display_id)
+    if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
       return false;
     gfx::Display* display = FindDisplayForId(display_id);
     display->SetSize(display_info_[display_id].size_in_pixel());
@@ -854,7 +877,7 @@
 }
 
 void DisplayManager::CreateMirrorWindowIfAny() {
-  MirrorWindowUpdater updater(this, delegate_);
+  NonDesktopDisplayUpdater updater(this, delegate_);
 }
 
 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
@@ -869,8 +892,8 @@
 
 void DisplayManager::AddMirrorDisplayInfoIfAny(
     std::vector<DisplayInfo>* display_info_list) {
-  if (software_mirroring_enabled_ && mirrored_display_.is_valid())
-    display_info_list->push_back(GetDisplayInfo(mirrored_display_.id()));
+  if (software_mirroring_enabled() && IsMirrored())
+    display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
 }
 
 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
@@ -898,6 +921,7 @@
   new_display.SetScaleAndBounds(
       display_info.device_scale_factor(), gfx::Rect(bounds_in_native.size()));
   new_display.set_rotation(display_info.rotation());
+  new_display.set_touch_support(display_info.touch_support());
   return new_display;
 }
 
diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h
index 6b547eb..eaedfe8 100644
--- a/ash/display/display_manager.h
+++ b/ash/display/display_manager.h
@@ -51,18 +51,31 @@
    public:
     virtual ~Delegate() {}
 
-    // Create or updates the mirror window with |display_info|.
-    virtual void CreateOrUpdateMirrorWindow(
+    // Create or updates the non desktop window with |display_info|.
+    virtual void CreateOrUpdateNonDesktopDisplay(
         const DisplayInfo& display_info) = 0;
 
     // Closes the mirror window if exists.
-    virtual void CloseMirrorWindow() = 0;
+    virtual void CloseNonDesktopDisplay() = 0;
 
     // Called before and after the display configuration changes.
     virtual void PreDisplayConfigurationChange(bool display_removed) = 0;
     virtual void PostDisplayConfigurationChange() = 0;
   };
 
+  // How the second display will be used.
+  // 1) EXTENDED mode extends the desktop to the second dislpay.
+  // 2) MIRRORING mode copies the content of the primary display to
+  //    the 2nd display. (Software Mirroring).
+  // 3) In VIRTUAL_KEYBOARD mode, the 2nd display is used as a
+  //    dedicated display for virtual keyboard, and it is not
+  //    recognized as a part of desktop.
+  enum SecondDisplayMode {
+    EXTENDED,
+    MIRRORING,
+    VIRTUAL_KEYBOARD
+  };
+
   // Returns the list of possible UI scales for the display.
   static std::vector<float> GetScalesForDisplay(const DisplayInfo& info);
 
@@ -194,7 +207,12 @@
 
   // Returns the mirroring status.
   bool IsMirrored() const;
-  const gfx::Display& mirrored_display() const { return mirrored_display_; }
+  int64 mirrored_display_id() const { return mirrored_display_id_; }
+
+  // Returns the display object that is not a part of desktop.
+  const gfx::Display& non_desktop_display() const {
+    return non_desktop_display_;
+  }
 
   // Retuns the display info associated with |display_id|.
   const DisplayInfo& GetDisplayInfo(int64 display_id) const;
@@ -219,13 +237,17 @@
   // SoftwareMirroringController override:
 #if defined(OS_CHROMEOS)
   virtual void SetSoftwareMirroring(bool enabled) OVERRIDE;
-#else
-  void SetSoftwareMirroring(bool enabled);
 #endif
   bool software_mirroring_enabled() const {
-    return software_mirroring_enabled_;
+    return second_display_mode_ == MIRRORING;
   };
 
+  // Sets/gets second display mode.
+  void SetSecondDisplayMode(SecondDisplayMode mode);
+  SecondDisplayMode second_display_mode() const {
+    return second_display_mode_;
+  }
+
   // Update the bounds of the display given by |display_id|.
   bool UpdateDisplayBounds(int64 display_id,
                            const gfx::Rect& new_bounds);
@@ -286,8 +308,6 @@
 
   int64 first_display_id_;
 
-  gfx::Display mirrored_display_;
-
   // List of current active dispays.
   DisplayList displays_;
 
@@ -308,7 +328,9 @@
   // on device as well as during the unit tests.
   bool change_display_upon_host_resize_;
 
-  bool software_mirroring_enabled_;
+  SecondDisplayMode second_display_mode_;
+  int64 mirrored_display_id_;
+  gfx::Display non_desktop_display_;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayManager);
 };
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 7e8652e..2af8d06 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -96,10 +96,6 @@
     return GetDisplayInfo(display_manager()->GetDisplayForId(id));
   }
 
-  const gfx::Display GetMirroredDisplay() {
-    return Shell::GetInstance()->display_manager()->mirrored_display();
-  }
-
   // aura::DisplayObserver overrides:
   virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE {
     changed_.push_back(display);
@@ -386,13 +382,13 @@
     return;
 
   UpdateDisplay("1000x600");
-  EXPECT_EQ(1,
-            Shell::GetPrimaryRootWindow()->compositor()->device_scale_factor());
+  aura::WindowEventDispatcher* dispatcher =
+      Shell::GetPrimaryRootWindow()->GetDispatcher();
+  EXPECT_EQ(1, dispatcher->compositor()->device_scale_factor());
   EXPECT_EQ("1000x600",
             Shell::GetPrimaryRootWindow()->bounds().size().ToString());
   UpdateDisplay("1000x600*2");
-  EXPECT_EQ(2,
-            Shell::GetPrimaryRootWindow()->compositor()->device_scale_factor());
+  EXPECT_EQ(2, dispatcher->compositor()->device_scale_factor());
   EXPECT_EQ("500x300",
             Shell::GetPrimaryRootWindow()->bounds().size().ToString());
 }
@@ -429,7 +425,7 @@
   EXPECT_EQ(default_bounds,
             display_manager()->GetDisplayAt(0).bounds().ToString());
   EXPECT_EQ(1U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 
   if (!SupportsMultipleDisplays())
     return;
@@ -443,7 +439,7 @@
   EXPECT_EQ("1,1 100x100",
             GetDisplayInfoForId(external_id).bounds_in_native().ToString());
   EXPECT_EQ(1U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
   EXPECT_EQ(external_id, Shell::GetScreen()->GetPrimaryDisplay().id());
 
   EXPECT_EQ(internal_display_id, gfx::Display::InternalDisplayId());
@@ -462,7 +458,7 @@
   EXPECT_EQ("1,1 100x100",
             GetDisplayInfoForId(10).bounds_in_native().ToString());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
   EXPECT_EQ(ToDisplayName(internal_display_id),
             display_manager()->GetDisplayNameForId(internal_display_id));
 
@@ -475,7 +471,7 @@
   EXPECT_EQ("1,1 100x100",
             GetDisplayInfoForId(10).bounds_in_native().ToString());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
   EXPECT_EQ(ToDisplayName(internal_display_id),
             display_manager()->GetDisplayNameForId(internal_display_id));
 
@@ -486,21 +482,21 @@
   EXPECT_EQ("0,0 500x500",
             GetDisplayForId(internal_display_id).bounds().ToString());
   EXPECT_EQ(1U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 
   // External display was changed during suspend.
   display_info_list.push_back(external_display_info);
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 
   // suspend...
   display_info_list.clear();
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 
   // and resume with different external display.
   display_info_list.push_back(internal_display_info);
@@ -508,7 +504,7 @@
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
   EXPECT_FALSE(display_manager()->IsMirrored());
 
   // mirrored...
@@ -520,7 +516,7 @@
   EXPECT_EQ("0,0 500x500",
             GetDisplayForId(internal_display_id).bounds().ToString());
   EXPECT_EQ(2U, display_manager()->num_connected_displays());
-  EXPECT_EQ(11U, display_manager()->mirrored_display().id());
+  EXPECT_EQ(11U, display_manager()->mirrored_display_id());
   EXPECT_TRUE(display_manager()->IsMirrored());
 
   // Test display name.
@@ -554,7 +550,7 @@
   EXPECT_EQ("1,1 100x100",
             GetDisplayInfoForId(external_id).bounds_in_native().ToString());
   EXPECT_EQ(1U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 
   // Switched to another display
   display_info_list.clear();
@@ -565,7 +561,7 @@
       "0,0 500x500",
       GetDisplayInfoForId(internal_display_id).bounds_in_native().ToString());
   EXPECT_EQ(1U, display_manager()->num_connected_displays());
-  EXPECT_FALSE(display_manager()->mirrored_display().is_valid());
+  EXPECT_FALSE(display_manager()->IsMirrored());
 }
 
 #if defined(OS_WIN)
@@ -594,8 +590,8 @@
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
   EXPECT_EQ("1,1 100x100",
             GetDisplayInfoForId(10).bounds_in_native().ToString());
-  EXPECT_EQ("100x100",
-            ash::Shell::GetPrimaryRootWindow()->GetHostSize().ToString());
+  EXPECT_EQ("100x100", ash::Shell::GetPrimaryRootWindow()->GetDispatcher()->
+      GetHostSize().ToString());
 }
 
 #if defined(OS_WIN)
@@ -977,7 +973,7 @@
   Shell::GetScreen()->AddObserver(&display_observer);
 
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   display_manager->UpdateDisplays();
   EXPECT_TRUE(display_observer.changed_and_reset());
   EXPECT_EQ(1U, display_manager->GetNumDisplays());
@@ -1001,28 +997,23 @@
   UpdateDisplay("300x400@0.5,400x500");
   EXPECT_FALSE(display_observer.changed_and_reset());
   EXPECT_EQ("300x400", test_api.GetRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString());
 
   UpdateDisplay("310x410*2,400x500");
   EXPECT_FALSE(display_observer.changed_and_reset());
   EXPECT_EQ("310x410", test_api.GetRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString());
 
   UpdateDisplay("320x420/r,400x500");
   EXPECT_FALSE(display_observer.changed_and_reset());
   EXPECT_EQ("320x420", test_api.GetRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString());
 
   UpdateDisplay("330x440/r,400x500");
   EXPECT_FALSE(display_observer.changed_and_reset());
   EXPECT_EQ("330x440", test_api.GetRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString());
 
   // Overscan insets are ignored.
   UpdateDisplay("400x600/o,600x800/o");
   EXPECT_FALSE(display_observer.changed_and_reset());
   EXPECT_EQ("400x600", test_api.GetRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("600x800", GetMirroredDisplay().size().ToString());
 
   Shell::GetScreen()->RemoveObserver(&display_observer);
 }
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index acdfe4c..31cb7f4 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -187,9 +187,9 @@
     root_window_->AddChild(mirror_window);
     mirror_window->SetBounds(root_window_->bounds());
     mirror_window->Show();
-    reflector_ = ui::ContextFactory::GetInstance()->
-        CreateReflector(Shell::GetPrimaryRootWindow()->compositor(),
-                        mirror_window->layer());
+    reflector_ = ui::ContextFactory::GetInstance()->CreateReflector(
+        Shell::GetPrimaryRootWindow()->GetDispatcher()->compositor(),
+        mirror_window->layer());
 
     cursor_window_ = new aura::Window(cursor_window_delegate_.get());
     cursor_window_->SetTransparent(true);
@@ -204,7 +204,7 @@
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
   const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
       Shell::GetScreen()->GetPrimaryDisplay().id());
-  DCHECK(display_manager->mirrored_display().is_valid());
+  DCHECK(display_manager->IsMirrored());
   scoped_ptr<aura::RootWindowTransformer> transformer(
       internal::CreateRootWindowTransformerForMirroredDisplay(
           source_display_info,
@@ -218,7 +218,7 @@
   if (root_window_.get()) {
     DisplayManager* display_manager = Shell::GetInstance()->display_manager();
     const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
-        display_manager->mirrored_display().id());
+        display_manager->mirrored_display_id());
     UpdateWindow(mirror_display_info);
   }
 }
@@ -244,7 +244,7 @@
   if (cursor_window_) {
     // TODO(oshima): Rotate cursor image (including hotpoint).
     gfx::Point point = aura::Env::GetInstance()->last_mouse_location();
-    Shell::GetPrimaryRootWindow()->ConvertPointToHost(&point);
+    Shell::GetPrimaryRootWindow()->GetDispatcher()->ConvertPointToHost(&point);
     point.Offset(-hot_point_.x(), -hot_point_.y());
     gfx::Rect bounds = cursor_window_->bounds();
     bounds.set_origin(point);
@@ -329,10 +329,10 @@
 MirrorWindowController::CreateRootWindowTransformer() const {
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
   const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
-      display_manager->mirrored_display().id());
+      display_manager->mirrored_display_id());
   const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
       Shell::GetScreen()->GetPrimaryDisplay().id());
-  DCHECK(display_manager->mirrored_display().is_valid());
+  DCHECK(display_manager->IsMirrored());
   return scoped_ptr<aura::RootWindowTransformer>(
       internal::CreateRootWindowTransformerForMirroredDisplay(
           source_display_info,
diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc
index fd3cc81..dc10b57 100644
--- a/ash/display/mirror_window_controller_unittest.cc
+++ b/ash/display/mirror_window_controller_unittest.cc
@@ -73,9 +73,9 @@
   test_window_delegate.set_window_component(HTTOP);
 
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   UpdateDisplay("400x400,400x400");
-  aura::RootWindow* root = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
       &test_window_delegate,
       0,
@@ -130,9 +130,9 @@
   test_window_delegate.set_window_component(HTTOP);
 
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   UpdateDisplay("400x400,400x400");
-  aura::RootWindow* root = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
       &test_window_delegate,
       0,
@@ -194,12 +194,12 @@
 TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorLocations) {
   test::MirrorWindowTestApi test_api;
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
 
   // Test with device scale factor.
   UpdateDisplay("400x600*2,400x600");
 
-  aura::RootWindow* root = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
   aura::test::EventGenerator generator(root);
   generator.MoveMouseToInHost(10, 20);
 
@@ -246,7 +246,7 @@
       CreateDisplayInfo(external_id, gfx::Rect(1, 1, 100, 100));
   std::vector<DisplayInfo> display_info_list;
 
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
 
   // software mirroring.
   display_info_list.push_back(internal_display_info);
@@ -254,12 +254,12 @@
   display_manager->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(1U, display_manager->GetNumDisplays());
   EXPECT_TRUE(display_manager->IsMirrored());
-  EXPECT_EQ(external_id, display_manager->mirrored_display().id());
+  EXPECT_EQ(external_id, display_manager->mirrored_display_id());
 
   // dock mode.
   display_info_list.clear();
   display_info_list.push_back(external_display_info);
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   display_manager->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(1U, display_manager->GetNumDisplays());
   EXPECT_FALSE(display_manager->IsMirrored());
@@ -268,11 +268,11 @@
   display_info_list.clear();
   display_info_list.push_back(internal_display_info);
   display_info_list.push_back(external_display_info);
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   display_manager->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(1U, display_manager->GetNumDisplays());
   EXPECT_TRUE(display_manager->IsMirrored());
-  EXPECT_EQ(external_id, display_manager->mirrored_display().id());
+  EXPECT_EQ(external_id, display_manager->mirrored_display_id());
 }
 
 TEST_F(MirrorOnBootTest, MAYBE_MirrorOnBoot) {
diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc
index 3d97c27..ebac900 100644
--- a/ash/display/mouse_cursor_event_filter.cc
+++ b/ash/display/mouse_cursor_event_filter.cc
@@ -40,6 +40,7 @@
     : mouse_warp_mode_(WARP_ALWAYS),
       was_mouse_warped_(false),
       drag_source_root_(NULL),
+      scale_when_drag_started_(1.0f),
       shared_display_edge_indicator_(new SharedDisplayEdgeIndicator) {
 }
 
@@ -48,7 +49,7 @@
 }
 
 void MouseCursorEventFilter::ShowSharedEdgeIndicator(
-    const aura::RootWindow* from) {
+    const aura::Window* from) {
   HideSharedEdgeIndicator();
   if (Shell::GetScreen()->GetNumDisplays() <= 1 || from == NULL) {
     src_indicator_bounds_.SetRect(0, 0, 0, 0);
@@ -74,6 +75,13 @@
 }
 
 void MouseCursorEventFilter::OnMouseEvent(ui::MouseEvent* event) {
+  if (event->type() == ui::ET_MOUSE_PRESSED) {
+    aura::Window* target = static_cast<aura::Window*>(event->target());
+    scale_when_drag_started_ = ui::GetDeviceScaleFactor(target->layer());
+  } else if (event->type() == ui::ET_MOUSE_RELEASED) {
+    scale_when_drag_started_ = 1.0f;
+  }
+
   // Handle both MOVED and DRAGGED events here because when the mouse pointer
   // enters the other root window while dragging, the underlying window system
   // (at least X11) stops generating a ui::ET_MOUSE_MOVED event.
@@ -92,7 +100,7 @@
 }
 
 bool MouseCursorEventFilter::WarpMouseCursorIfNecessary(
-    aura::RootWindow* target_root,
+    aura::Window* target_root,
     const gfx::Point& point_in_screen) {
   if (Shell::GetScreen()->GetNumDisplays() <= 1 ||
       mouse_warp_mode_ == WARP_NONE)
@@ -108,48 +116,46 @@
     return false;
   }
 
-  const float scale_at_target = ui::GetDeviceScaleFactor(target_root->layer());
-
-  aura::RootWindow* root_at_point = wm::GetRootWindowAt(point_in_screen);
+  aura::Window* root_at_point = wm::GetRootWindowAt(point_in_screen);
   gfx::Point point_in_root = point_in_screen;
   wm::ConvertPointFromScreen(root_at_point, &point_in_root);
   gfx::Rect root_bounds = root_at_point->bounds();
   int offset_x = 0;
   int offset_y = 0;
 
-  const float scale_at_point = ui::GetDeviceScaleFactor(root_at_point->layer());
-  // If the window is dragged from 2x display to 1x display, the
-  // pointer location is rounded by the source scale factor (2x) so
-  // it will never reach the edge (which is odd). Shrink by scale
-  // factor instead.  Only integral scale factor is supported.
-  int shrink =
-      target_root != root_at_point && scale_at_target != scale_at_point ?
-      static_cast<int>(scale_at_target) : 1;
+  // If the window is dragged between 2x display and 1x display,
+  // staring from 2x display, pointer location is rounded by the
+  // source scale factor (2x) so it will never reach the edge (which
+  // is odd). Shrink by scale factor of the display where the dragging
+  // started instead.  Only integral scale factor is supported for now.
+  int shrink = scale_when_drag_started_;
   // Make the bounds inclusive to detect the edge.
   root_bounds.Inset(0, 0, shrink, shrink);
+  gfx::Rect src_indicator_bounds = src_indicator_bounds_;
+  src_indicator_bounds.Inset(-shrink, -shrink, -shrink, -shrink);
 
   if (point_in_root.x() <= root_bounds.x()) {
     // Use -2, not -1, to avoid infinite loop of pointer warp.
-    offset_x = -2 * scale_at_target;
+    offset_x = -2 * scale_when_drag_started_;
   } else if (point_in_root.x() >= root_bounds.right()) {
-    offset_x = 2 * scale_at_target;
+    offset_x = 2 * scale_when_drag_started_;
   } else if (point_in_root.y() <= root_bounds.y()) {
-    offset_y = -2 * scale_at_target;
+    offset_y = -2 * scale_when_drag_started_;
   } else if (point_in_root.y() >= root_bounds.bottom()) {
-    offset_y = 2 * scale_at_target;
+    offset_y = 2 * scale_when_drag_started_;
   } else {
     return false;
   }
 
   gfx::Point point_in_dst_screen(point_in_screen);
   point_in_dst_screen.Offset(offset_x, offset_y);
-  aura::RootWindow* dst_root = wm::GetRootWindowAt(point_in_dst_screen);
+  aura::Window* dst_root = wm::GetRootWindowAt(point_in_dst_screen);
 
   // Warp the mouse cursor only if the location is in the indicator bounds
   // or the mouse pointer is in the destination root.
   if (mouse_warp_mode_ == WARP_DRAG &&
       dst_root != drag_source_root_ &&
-      !src_indicator_bounds_.Contains(point_in_screen)) {
+      !src_indicator_bounds.Contains(point_in_screen)) {
     return false;
   }
 
diff --git a/ash/display/mouse_cursor_event_filter.h b/ash/display/mouse_cursor_event_filter.h
index 78f9074..b05456e 100644
--- a/ash/display/mouse_cursor_event_filter.h
+++ b/ash/display/mouse_cursor_event_filter.h
@@ -14,6 +14,7 @@
 
 namespace aura {
 class RootWindow;
+class Window;
 }
 
 namespace ash {
@@ -43,7 +44,7 @@
 
   // Shows/Hide the indicator for window dragging. The |from|
   // is the window where the dragging started.
-  void ShowSharedEdgeIndicator(const aura::RootWindow* from);
+  void ShowSharedEdgeIndicator(const aura::Window* from);
   void HideSharedEdgeIndicator();
 
   // Overridden from ui::EventHandler:
@@ -69,7 +70,7 @@
   // hits or exceeds the edge of the |target_root| and the mouse cursor
   // is considered to be in an alternate display. Returns true if
   // the cursor was moved.
-  bool WarpMouseCursorIfNecessary(aura::RootWindow* target_root,
+  bool WarpMouseCursorIfNecessary(aura::Window* target_root,
                                   const gfx::Point& point_in_screen);
 
   void UpdateHorizontalIndicatorWindowBounds();
@@ -87,7 +88,9 @@
   gfx::Rect dst_indicator_bounds_;
 
   // The root window in which the dragging started.
-  const aura::RootWindow* drag_source_root_;
+  const aura::Window* drag_source_root_;
+
+  float scale_when_drag_started_;
 
   // Shows the area where a window can be dragged in to/out from
   // another display.
diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc
index 949c7c0..d08095d 100644
--- a/ash/display/mouse_cursor_event_filter_unittest.cc
+++ b/ash/display/mouse_cursor_event_filter_unittest.cc
@@ -48,6 +48,26 @@
     return is_warped;
   }
 
+  bool WarpMouseCursorIfNecessaryWithDragRoot(
+      aura::RootWindow* drag_source_root,
+      aura::RootWindow* target_root,
+      gfx::Point point_in_screen) {
+    gfx::Point location = drag_source_root->bounds().CenterPoint();
+    ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, location,
+                           location, 0);
+    ui::Event::DispatcherApi(&pressed).set_target(drag_source_root);
+    event_filter()->OnMouseEvent(&pressed);
+    bool is_warped = event_filter()->WarpMouseCursorIfNecessary(
+        target_root, point_in_screen);
+    event_filter()->reset_was_mouse_warped_for_test();
+
+    ui::MouseEvent released(ui::ET_MOUSE_RELEASED, location,
+                           location, 0);
+    ui::Event::DispatcherApi(&released).set_target(drag_source_root);
+    event_filter()->OnMouseEvent(&released);
+    return is_warped;
+  }
+
  private:
   MouseCursorEventFilter* event_filter_;
 
@@ -144,20 +164,33 @@
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
   aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
 
-  // This emulates the dragging back to the 2nd display, which has
+  // This emulates the dragging to the 2nd display, which has
   // higher scale factor, by having 2nd display's root as target
   // but have the edge of 1st display.
-  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1],
-                                         gfx::Point(498, 123)));
+  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
+      root_windows[1], root_windows[1], gfx::Point(498, 123)));
   EXPECT_EQ("502,123",
             aura::Env::GetInstance()->last_mouse_location().ToString());
 
   // Touch the edge of 2nd display again and make sure it warps to
   // 1st dislay.
-  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1],
-                                         gfx::Point(500, 123)));
+  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
+      root_windows[1], root_windows[1], gfx::Point(500, 123)));
   EXPECT_EQ("496,123",
             aura::Env::GetInstance()->last_mouse_location().ToString());
+
+  // Draging back from 1x to 2x.
+  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
+      root_windows[1], root_windows[0], gfx::Point(500, 123)));
+  EXPECT_EQ("496,123",
+            aura::Env::GetInstance()->last_mouse_location().ToString());
+
+  UpdateDisplay("500x500*2,600x600");
+  // Draging back from 1x to 2x.
+  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
+      root_windows[0], root_windows[1], gfx::Point(250, 123)));
+  EXPECT_EQ("246,123",
+            aura::Env::GetInstance()->last_mouse_location().ToString());
 }
 
 TEST_F(MouseCursorEventFilterTest, DoNotWarpTwice) {
diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc
index efb11f3..0c81684 100644
--- a/ash/display/root_window_transformers.cc
+++ b/ash/display/root_window_transformers.cc
@@ -50,7 +50,7 @@
 // when the device scale factor is changed, instead of
 // precalculating the transform using fixed value.
 
-gfx::Transform CreateRotationTransform(aura::RootWindow* root_window,
+gfx::Transform CreateRotationTransform(aura::Window* root_window,
                                        const gfx::Display& display) {
   DisplayInfo info =
       Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
@@ -92,7 +92,7 @@
   return rotate;
 }
 
-gfx::Transform CreateMagnifierTransform(aura::RootWindow* root_window) {
+gfx::Transform CreateMagnifierTransform(aura::Window* root_window) {
   MagnificationController* magnifier =
       Shell::GetInstance()->magnification_controller();
   float magnifier_scale = 1.f;
@@ -123,7 +123,7 @@
   return transform;
 }
 
-gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window,
+gfx::Transform CreateOverscanAndUIScaleTransform(aura::Window* root_window,
                                                  const gfx::Display& display) {
   DisplayInfo info =
       Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
@@ -136,7 +136,7 @@
 // RootWindowTransformer for ash environment.
 class AshRootWindowTransformer : public aura::RootWindowTransformer {
  public:
-  AshRootWindowTransformer(aura::RootWindow* root,
+  AshRootWindowTransformer(aura::Window* root,
                            const gfx::Display& display)
       : root_window_(root) {
     root_window_bounds_transform_ =
@@ -185,7 +185,7 @@
  private:
   virtual ~AshRootWindowTransformer() {}
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
   gfx::Transform transform_;
 
   // The accurate representation of the inverse of the |transform_|.
@@ -277,7 +277,7 @@
 }  // namespace
 
 aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay(
-    aura::RootWindow* root,
+    aura::Window* root,
     const gfx::Display& display) {
   return new AshRootWindowTransformer(root, display);
 }
diff --git a/ash/display/root_window_transformers.h b/ash/display/root_window_transformers.h
index 8af9ee8..e1d4053 100644
--- a/ash/display/root_window_transformers.h
+++ b/ash/display/root_window_transformers.h
@@ -8,8 +8,8 @@
 #include "ash/ash_export.h"
 
 namespace aura {
-class RootWindow;
 class RootWindowTransformer;
+class Window;
 }
 
 namespace gfx {
@@ -22,7 +22,7 @@
 class DisplayInfo;
 
 ASH_EXPORT aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay(
-    aura::RootWindow* root,
+    aura::Window* root,
     const gfx::Display& display);
 
 // Creates a RootWindowTransformers for mirror root window.
diff --git a/ash/display/root_window_transformers_unittest.cc b/ash/display/root_window_transformers_unittest.cc
index 9cb362e..38e2cf3 100644
--- a/ash/display/root_window_transformers_unittest.cc
+++ b/ash/display/root_window_transformers_unittest.cc
@@ -96,7 +96,7 @@
 
  private:
   gfx::Point mouse_location_;
-  aura::RootWindow* target_root_;
+  aura::Window* target_root_;
 
   float touch_radius_x_;
   float touch_radius_y_;
@@ -396,7 +396,7 @@
     return;
   test::MirrorWindowTestApi test_api;
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
   UpdateDisplay("400x200,500x500");
   scoped_ptr<aura::RootWindowTransformer> transformer(
       test_api.CreateCurrentRootWindowTransformer());
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc
index b416d38..c8b8c1d 100644
--- a/ash/display/screen_position_controller.cc
+++ b/ash/display/screen_position_controller.cc
@@ -14,7 +14,6 @@
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/focus_client.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window_tracker.h"
 #include "ui/compositor/dip_util.h"
@@ -36,7 +35,7 @@
 // the child windows and transient children of the transient children.
 void MoveAllTransientChildrenToNewRoot(const gfx::Display& display,
                                        aura::Window* window) {
-  aura::RootWindow* dst_root = Shell::GetInstance()->display_controller()->
+  aura::Window* dst_root = Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display.id());
   aura::Window::Windows transient_children = window->transient_children();
   for (aura::Window::Windows::iterator iter = transient_children.begin();
@@ -67,7 +66,7 @@
 std::pair<aura::RootWindow*, gfx::Point> GetRootWindowRelativeToWindow(
     aura::Window* window,
     const gfx::Point& location) {
-  aura::RootWindow* root_window = window->GetRootWindow();
+  aura::Window* root_window = window->GetRootWindow();
   gfx::Point location_in_root(location);
   aura::Window::ConvertPointToTarget(window, root_window, &location_in_root);
 
@@ -90,7 +89,8 @@
     // extended root window's coordinates.
 
     gfx::Point location_in_native(location_in_root);
-    root_window->ConvertPointToNativeScreen(&location_in_native);
+    root_window->GetDispatcher()->ConvertPointToNativeScreen(
+        &location_in_native);
 
     Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
     for (size_t i = 0; i < root_windows.size(); ++i) {
@@ -100,7 +100,8 @@
       if (native_bounds.Contains(location_in_native)) {
         root_window = root_windows[i];
         location_in_root = location_in_native;
-        root_window->ConvertPointFromNativeScreen(&location_in_root);
+        root_window->GetDispatcher()->ConvertPointFromNativeScreen(
+            &location_in_root);
         break;
       }
     }
@@ -109,7 +110,7 @@
   // TODO(yusukes): Support non-X11 platforms if necessary.
 #endif
 
-  return std::make_pair(root_window, location_in_root);
+  return std::make_pair(root_window->GetDispatcher(), location_in_root);
 }
 
 }  // namespace
@@ -119,29 +120,30 @@
 void ScreenPositionController::ConvertPointToScreen(
     const aura::Window* window,
     gfx::Point* point) {
-  const aura::RootWindow* root = window->GetRootWindow();
+  const aura::Window* root = window->GetRootWindow();
   aura::Window::ConvertPointToTarget(window, root, point);
   const gfx::Point display_origin = Shell::GetScreen()->GetDisplayNearestWindow(
-      const_cast<aura::RootWindow*>(root)).bounds().origin();
+      const_cast<aura::Window*>(root)).bounds().origin();
   point->Offset(display_origin.x(), display_origin.y());
 }
 
 void ScreenPositionController::ConvertPointFromScreen(
     const aura::Window* window,
     gfx::Point* point) {
-  const aura::RootWindow* root = window->GetRootWindow();
+  const aura::Window* root = window->GetRootWindow();
   const gfx::Point display_origin = Shell::GetScreen()->GetDisplayNearestWindow(
-      const_cast<aura::RootWindow*>(root)).bounds().origin();
+      const_cast<aura::Window*>(root)).bounds().origin();
   point->Offset(-display_origin.x(), -display_origin.y());
   aura::Window::ConvertPointToTarget(root, window, point);
 }
 
 void ScreenPositionController::ConvertHostPointToScreen(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     gfx::Point* point) {
-  root_window->ConvertPointFromHost(point);
+  aura::Window* root = root_window->GetRootWindow();
+  root->GetDispatcher()->ConvertPointFromHost(point);
   std::pair<aura::RootWindow*, gfx::Point> pair =
-      GetRootWindowRelativeToWindow(root_window, *point);
+      GetRootWindowRelativeToWindow(root, *point);
   *point = pair.second;
   ConvertPointToScreen(pair.first, point);
 }
@@ -163,7 +165,7 @@
   //    outside of the display.
   if (!window->transient_parent() &&
       !ShouldStayInSameRootWindow(window)) {
-    aura::RootWindow* dst_root =
+    aura::Window* dst_root =
         Shell::GetInstance()->display_controller()->GetRootWindowForDisplayId(
             display.id());
     DCHECK(dst_root);
@@ -197,8 +199,9 @@
       // Restore focused/active window.
       if (tracker.Contains(focused)) {
         aura::client::GetFocusClient(window)->FocusWindow(focused);
+        // TODO(beng): replace with GetRootWindow().
         ash::Shell::GetInstance()->set_target_root_window(
-            focused->GetRootWindow());
+            focused->GetDispatcher());
       } else if (tracker.Contains(active)) {
         activation_client->ActivateWindow(active);
       }
diff --git a/ash/display/screen_position_controller.h b/ash/display/screen_position_controller.h
index 51bf501..ad692f9 100644
--- a/ash/display/screen_position_controller.h
+++ b/ash/display/screen_position_controller.h
@@ -21,7 +21,7 @@
                                     gfx::Point* point) OVERRIDE;
   virtual void ConvertPointFromScreen(const aura::Window* window,
                                       gfx::Point* point) OVERRIDE;
-  virtual void ConvertHostPointToScreen(aura::RootWindow* window,
+  virtual void ConvertHostPointToScreen(aura::Window* window,
                                         gfx::Point* point) OVERRIDE;
   virtual void SetBounds(aura::Window* window,
                          const gfx::Rect& bounds,
diff --git a/ash/display/screen_position_controller_unittest.cc b/ash/display/screen_position_controller_unittest.cc
index 680ee83..2cd6133 100644
--- a/ash/display/screen_position_controller_unittest.cc
+++ b/ash/display/screen_position_controller_unittest.cc
@@ -56,7 +56,7 @@
     window_.reset(new aura::Window(&window_delegate_));
     window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window_.get());
+    ParentWindowInPrimaryRootWindow(window_.get());
     window_->set_id(1);
   }
 
diff --git a/ash/display/virtual_keyboard_window_controller.cc b/ash/display/virtual_keyboard_window_controller.cc
new file mode 100644
index 0000000..111ce3a
--- /dev/null
+++ b/ash/display/virtual_keyboard_window_controller.cc
@@ -0,0 +1,71 @@
+// Copyright 2013 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 "ash/display/virtual_keyboard_window_controller.h"
+
+#include "ash/display/display_controller.h"
+#include "ash/display/display_info.h"
+#include "ash/display/display_manager.h"
+#include "ash/host/root_window_host_factory.h"
+#include "ash/root_window_controller.h"
+#include "ash/root_window_settings.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+
+namespace ash {
+namespace internal {
+
+VirtualKeyboardWindowController::VirtualKeyboardWindowController() {
+}
+
+VirtualKeyboardWindowController::~VirtualKeyboardWindowController() {
+  // Make sure the root window gets deleted before cursor_window_delegate.
+  Close();
+}
+
+void VirtualKeyboardWindowController::UpdateWindow(
+    const DisplayInfo& display_info) {
+  static int virtual_keyboard_root_window_count = 0;
+  if (!root_window_controller_.get()) {
+    const gfx::Rect& bounds_in_native = display_info.bounds_in_native();
+    aura::RootWindow::CreateParams params(bounds_in_native);
+    params.host = Shell::GetInstance()->root_window_host_factory()->
+        CreateRootWindowHost(bounds_in_native);
+    aura::RootWindow* root_window = new aura::RootWindow(params);
+
+    root_window->SetName(
+        base::StringPrintf("VirtualKeyboardRootWindow-%d",
+                           virtual_keyboard_root_window_count++));
+
+    // No need to remove RootWindowObserver because
+    // the DisplayController object outlives RootWindow objects.
+    root_window->AddRootWindowObserver(
+        Shell::GetInstance()->display_controller());
+    InitRootWindowSettings(root_window)->display_id = display_info.id();
+    root_window->Init();
+    RootWindowController::CreateForVirtualKeyboardDisplay(root_window);
+    root_window_controller_.reset(GetRootWindowController(root_window));
+    root_window_controller_->root_window()->ShowRootWindow();
+  } else {
+    aura::RootWindow* root_window = root_window_controller_->root_window();
+    GetRootWindowSettings(root_window)->display_id = display_info.id();
+    root_window->SetHostBounds(display_info.bounds_in_native());
+  }
+}
+
+void VirtualKeyboardWindowController::Close() {
+  if (root_window_controller_.get()) {
+    root_window_controller_->root_window()->RemoveRootWindowObserver(
+        Shell::GetInstance()->display_controller());
+    root_window_controller_->Shutdown();
+    root_window_controller_.reset();
+  }
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/display/virtual_keyboard_window_controller.h b/ash/display/virtual_keyboard_window_controller.h
new file mode 100644
index 0000000..def3c06
--- /dev/null
+++ b/ash/display/virtual_keyboard_window_controller.h
@@ -0,0 +1,41 @@
+// Copyright 2013 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 ASH_DISPLAY_VIRTUAL_KEYBOARD_WINDOW_CONTROLLER_H_
+#define ASH_DISPLAY_VIRTUAL_KEYBOARD_WINDOW_CONTROLLER_H_
+
+#include "ash/ash_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace ash {
+
+namespace internal {
+class DisplayInfo;
+class RootWindowController;
+
+// This class maintains the RootWindowController dedicated for
+// virtual keyboard.
+class ASH_EXPORT VirtualKeyboardWindowController {
+ public:
+  VirtualKeyboardWindowController();
+  virtual ~VirtualKeyboardWindowController();
+
+  // Updates the root window's bounds using |display_info|.
+  // Creates the new root window if one doesn't exist.
+  void UpdateWindow(const DisplayInfo& display_info);
+
+  // Close the mirror window.
+  void Close();
+
+ private:
+  scoped_ptr<RootWindowController> root_window_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardWindowController);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // ASH_DISPLAY_VIRTUAL_KEYBOARD_WINDOW_CONTROLLER_H_
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index d335465..07ab4f3 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -33,8 +33,6 @@
 namespace ash {
 namespace internal {
 
-using aura::RootWindow;
-
 namespace {
 // The duration of the drag cancel animation in millisecond.
 const int kCancelAnimationDuration = 250;
@@ -160,7 +158,7 @@
 
 int DragDropController::StartDragAndDrop(
     const ui::OSExchangeData& data,
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& root_location,
     int operation,
diff --git a/ash/drag_drop/drag_drop_controller.h b/ash/drag_drop/drag_drop_controller.h
index 6471db2..a9220db 100644
--- a/ash/drag_drop/drag_drop_controller.h
+++ b/ash/drag_drop/drag_drop_controller.h
@@ -16,11 +16,6 @@
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/rect.h"
 
-namespace aura {
-class RootWindow;
-class Window;
-}
-
 namespace gfx {
 class LinearAnimation;
 }
@@ -53,7 +48,7 @@
   // Overridden from aura::client::DragDropClient:
   virtual int StartDragAndDrop(
       const ui::OSExchangeData& data,
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       aura::Window* source_window,
       const gfx::Point& root_location,
       int operation,
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index 39f9974..fa4f2bc 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -163,7 +163,7 @@
 
   virtual int StartDragAndDrop(
       const ui::OSExchangeData& data,
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       aura::Window* source_window,
       const gfx::Point& location,
       int operation,
@@ -283,7 +283,8 @@
       ui::EventTimeForNow(),
       ui::GestureEventDetails(gesture_type, 0, 0),
       1);
-  Shell::GetPrimaryRootWindow()->DispatchGestureEvent(&gesture_event);
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->DispatchGestureEvent(
+      &gesture_event);
 }
 
 bool IsGestureEventType(ui::EventType type) {
@@ -762,8 +763,8 @@
     gfx::Point mouse_move_location = drag_view->bounds().CenterPoint();
     ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location,
                               mouse_move_location, 0);
-    Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->OnHostMouseEvent(
-        &mouse_move);
+    Shell::GetPrimaryRootWindow()->GetDispatcher()->AsRootWindowHostDelegate()->
+        OnHostMouseEvent(&mouse_move);
   }
 
   generator.ReleaseLeftButton();
diff --git a/ash/drag_drop/drag_drop_tracker.cc b/ash/drag_drop/drag_drop_tracker.cc
index 4fd1de8..03ecf79 100644
--- a/ash/drag_drop/drag_drop_tracker.cc
+++ b/ash/drag_drop/drag_drop_tracker.cc
@@ -7,7 +7,9 @@
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
 #include "ash/wm/coordinate_conversion.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
 #include "ui/events/event.h"
 #include "ui/gfx/screen.h"
 
@@ -17,12 +19,12 @@
 namespace {
 
 // Creates a window for capturing drag events.
-aura::Window* CreateCaptureWindow(aura::RootWindow* context_root,
+aura::Window* CreateCaptureWindow(aura::Window* context_root,
                                   aura::WindowDelegate* delegate) {
   aura::Window* window = new aura::Window(delegate);
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_NOT_DRAWN);
-  window->SetDefaultParentByRootWindow(context_root, gfx::Rect());
+  aura::client::ParentWindowWithContext(window, context_root, gfx::Rect());
   window->Show();
   DCHECK(window->bounds().size().IsEmpty());
   return window;
@@ -30,7 +32,7 @@
 
 }  // namespace
 
-DragDropTracker::DragDropTracker(aura::RootWindow* context_root,
+DragDropTracker::DragDropTracker(aura::Window* context_root,
                                  aura::WindowDelegate* delegate)
     : capture_window_(CreateCaptureWindow(context_root, delegate)) {
 }
@@ -48,7 +50,7 @@
   gfx::Point location_in_screen = event.location();
   wm::ConvertPointToScreen(capture_window_.get(),
                            &location_in_screen);
-  aura::RootWindow* root_window_at_point =
+  aura::Window* root_window_at_point =
       wm::GetRootWindowAt(location_in_screen);
   gfx::Point location_in_root = location_in_screen;
   wm::ConvertPointFromScreen(root_window_at_point, &location_in_root);
diff --git a/ash/drag_drop/drag_drop_tracker.h b/ash/drag_drop/drag_drop_tracker.h
index c20952c..b4dcf6e 100644
--- a/ash/drag_drop/drag_drop_tracker.h
+++ b/ash/drag_drop/drag_drop_tracker.h
@@ -11,7 +11,6 @@
 #include "ui/events/event.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 class WindowDelegate;
 }
@@ -26,7 +25,7 @@
 // is supported for now.
 class ASH_EXPORT DragDropTracker {
  public:
-  DragDropTracker(aura::RootWindow* context_root,
+  DragDropTracker(aura::Window* context_root,
                   aura::WindowDelegate* delegate);
   ~DragDropTracker();
 
diff --git a/ash/focus_cycler_unittest.cc b/ash/focus_cycler_unittest.cc
index aebede4..f7629dc 100644
--- a/ash/focus_cycler_unittest.cc
+++ b/ash/focus_cycler_unittest.cc
@@ -383,7 +383,7 @@
 
   // Pressing "Escape" while on the status area should
   // deactivate it, and activate the browser window.
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   aura::test::EventGenerator event_generator(root, root);
   event_generator.PressKey(ui::VKEY_ESCAPE, 0);
   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc
index 9637acb..e981709 100644
--- a/ash/launcher/launcher.cc
+++ b/ash/launcher/launcher.cc
@@ -121,11 +121,11 @@
     ActivateLauncherItem(item_index);
 }
 
-void Launcher::AddIconObserver(LauncherIconObserver* observer) {
+void Launcher::AddIconObserver(ShelfIconObserver* observer) {
   shelf_view_->AddIconObserver(observer);
 }
 
-void Launcher::RemoveIconObserver(LauncherIconObserver* observer) {
+void Launcher::RemoveIconObserver(ShelfIconObserver* observer) {
   shelf_view_->RemoveIconObserver(observer);
 }
 
diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h
index 693f137..5c663b4 100644
--- a/ash/launcher/launcher.h
+++ b/ash/launcher/launcher.h
@@ -41,9 +41,9 @@
 class LauncherTestAPI;
 }
 
-class LauncherIconObserver;
 class LauncherDelegate;
 class LauncherModel;
+class ShelfIconObserver;
 class ShelfWidget;
 
 class ASH_EXPORT Launcher {
@@ -82,8 +82,8 @@
   // Cycles the window focus linearly over the current launcher items.
   void CycleWindowLinear(CycleDirection direction);
 
-  void AddIconObserver(LauncherIconObserver* observer);
-  void RemoveIconObserver(LauncherIconObserver* observer);
+  void AddIconObserver(ShelfIconObserver* observer);
+  void RemoveIconObserver(ShelfIconObserver* observer);
 
   // Returns true if the Launcher is showing a context menu.
   bool IsShowingMenu() const;
diff --git a/ash/launcher/launcher_icon_observer.h b/ash/launcher/launcher_icon_observer.h
deleted file mode 100644
index d452934..0000000
--- a/ash/launcher/launcher_icon_observer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2012 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 ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_
-#define ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_
-
-#include "ash/ash_export.h"
-#include "base/basictypes.h"
-
-namespace ash {
-
-class ASH_EXPORT LauncherIconObserver {
- public:
-  // Invoked when any icon on launcher changes position.
-  virtual void OnLauncherIconPositionsChanged() = 0;
-
- protected:
-  virtual ~LauncherIconObserver() {}
-};
-
-}  // namespace ash
-
-#endif  // ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_
diff --git a/ash/launcher/launcher_item_delegate.h b/ash/launcher/launcher_item_delegate.h
index a72b6e6..dbc1e65 100644
--- a/ash/launcher/launcher_item_delegate.h
+++ b/ash/launcher/launcher_item_delegate.h
@@ -53,7 +53,7 @@
   // Returns the context menumodel for the specified item on
   // |root_window|.  Return NULL if there should be no context
   // menu. The caller takes ownership of the returned model.
-  virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root_window) = 0;
+  virtual ui::MenuModel* CreateContextMenu(aura::Window* root_window) = 0;
 
   // Returns the application menu model for the specified item. There are three
   // possible return values:
diff --git a/ash/launcher/launcher_model_util.cc b/ash/launcher/launcher_model_util.cc
new file mode 100644
index 0000000..b1d63a4
--- /dev/null
+++ b/ash/launcher/launcher_model_util.cc
@@ -0,0 +1,20 @@
+// Copyright 2013 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 "ash/launcher/launcher_model_util.h"
+
+#include "ash/launcher/launcher_model.h"
+
+namespace ash {
+
+int GetLauncherItemIndexForType(LauncherItemType type,
+                                const LauncherModel& launcher_model) {
+  for (size_t i = 0; i < launcher_model.items().size(); i++) {
+    if (launcher_model.items()[i].type == type)
+      return i;
+  }
+  return -1;
+}
+
+}  // namespace ash
diff --git a/ash/launcher/launcher_model_util.h b/ash/launcher/launcher_model_util.h
new file mode 100644
index 0000000..9cc9932
--- /dev/null
+++ b/ash/launcher/launcher_model_util.h
@@ -0,0 +1,25 @@
+// Copyright 2013 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 ASH_LAUNCHER_LAUNCHER_MODEL_UTIL_H_
+#define ASH_LAUNCHER_LAUNCHER_MODEL_UTIL_H_
+
+#include "ash/ash_export.h"
+#include "ash/launcher/launcher_types.h"
+
+namespace ash {
+
+class LauncherModel;
+
+// Return the index of the |type| from a given |launcher_model|.
+// Note:
+//  * If there are many items for |type| in the |launcher_model|, an index of
+//    first item will be returned.
+//  * If there is no item for |type|, -1 will be returned.
+ASH_EXPORT int GetLauncherItemIndexForType(LauncherItemType type,
+                                           const LauncherModel& launcher_model);
+
+}  // namespace ash
+
+#endif  // ASH_LAUNCHER_LAUNCHER_MODEL_UTIL_H_
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index c2e269d..0df6e12 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -4,9 +4,9 @@
 
 #include "ash/magnifier/magnification_controller.h"
 
+#include "ash/accessibility_delegate.h"
 #include "ash/display/root_window_transformers.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "base/synchronization/waitable_event.h"
 #include "ui/aura/client/cursor_client.h"
@@ -127,7 +127,7 @@
   //  - Unzoom the current root_window.
   //  - Zoom the given new root_window |new_root_window|.
   //  - Switch the target window from current window to |new_root_window|.
-  void SwitchTargetRootWindow(aura::RootWindow* new_root_window,
+  void SwitchTargetRootWindow(aura::Window* new_root_window,
                               bool redraw_original_root_window);
 
   // Returns if the magnification scale is 1.0 or not (larger then 1.0).
@@ -147,7 +147,7 @@
   virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
   // Target root window. This must not be NULL.
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   // True if the magnified window is currently animating a change. Otherwise,
   // false.
@@ -273,7 +273,7 @@
       Shell::GetScreen()->GetDisplayNearestWindow(root_window_);
   scoped_ptr<aura::RootWindowTransformer> transformer(
       internal::CreateRootWindowTransformerForDisplay(root_window_, display));
-  root_window_->SetRootWindowTransformer(transformer.Pass());
+  root_window_->GetDispatcher()->SetRootWindowTransformer(transformer.Pass());
 
   if (animate)
     is_on_animation_ = true;
@@ -380,7 +380,7 @@
     if (ret) {
       // If the magnified region is moved, hides the mouse cursor and moves it.
       if (x_diff != 0 || y_diff != 0)
-        MoveCursorTo(root_window_, mouse);
+        MoveCursorTo(root_window_->GetDispatcher(), mouse);
     }
   }
 }
@@ -437,7 +437,7 @@
     return;
 
   if (move_cursor_after_animation_) {
-    MoveCursorTo(root_window_, position_after_animation_);
+    MoveCursorTo(root_window_->GetDispatcher(), position_after_animation_);
     move_cursor_after_animation_ = false;
 
     aura::client::CursorClient* cursor_client =
@@ -456,7 +456,7 @@
     // destroyed before the root windows get destroyed.
     DCHECK(root_window);
 
-    aura::RootWindow* target_root_window = Shell::GetTargetRootWindow();
+    aura::Window* target_root_window = Shell::GetTargetRootWindow();
     CHECK(target_root_window);
 
     // The destroyed root window must not be target.
@@ -475,7 +475,7 @@
 }
 
 void MagnificationControllerImpl::SwitchTargetRootWindow(
-    aura::RootWindow* new_root_window,
+    aura::Window* new_root_window,
     bool redraw_original_root_window) {
   DCHECK(new_root_window);
 
@@ -503,7 +503,8 @@
     return;
 
   ValidateScale(&scale);
-  ash::Shell::GetInstance()->delegate()->SaveScreenMagnifierScale(scale);
+  ash::Shell::GetInstance()->accessibility_delegate()->
+      SaveScreenMagnifierScale(scale);
   RedrawKeepingMousePosition(scale, animate);
 }
 
@@ -543,7 +544,8 @@
 void MagnificationControllerImpl::SetEnabled(bool enabled) {
   if (enabled) {
     float scale =
-        ash::Shell::GetInstance()->delegate()->GetSavedScreenMagnifierScale();
+        ash::Shell::GetInstance()->accessibility_delegate()->
+        GetSavedScreenMagnifierScale();
     if (scale <= 0.0f)
       scale = kInitialMagnifiedScale;
     ValidateScale(&scale);
@@ -554,7 +556,8 @@
 
     is_enabled_ = enabled;
     RedrawKeepingMousePosition(scale, true);
-    ash::Shell::GetInstance()->delegate()->SaveScreenMagnifierScale(scale);
+    ash::Shell::GetInstance()->accessibility_delegate()->
+        SaveScreenMagnifierScale(scale);
   } else {
     // Do nothing, if already disabled.
     if (!is_enabled_)
@@ -574,7 +577,7 @@
 
 void MagnificationControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
-  aura::RootWindow* current_root = target->GetRootWindow();
+  aura::Window* current_root = target->GetRootWindow();
   gfx::Rect root_bounds = current_root->bounds();
 
   if (root_bounds.Contains(event->root_location())) {
@@ -612,7 +615,7 @@
 
 void MagnificationControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
-  aura::RootWindow* current_root = target->GetRootWindow();
+  aura::Window* current_root = target->GetRootWindow();
   if (current_root == root_window_) {
     gfx::Rect root_bounds = current_root->bounds();
     if (root_bounds.Contains(event->root_location()))
diff --git a/ash/magnifier/magnification_controller_unittest.cc b/ash/magnifier/magnification_controller_unittest.cc
index 63608fc..2f87ee1 100644
--- a/ash/magnifier/magnification_controller_unittest.cc
+++ b/ash/magnifier/magnification_controller_unittest.cc
@@ -32,7 +32,7 @@
     AshTestBase::SetUp();
     UpdateDisplay(base::StringPrintf("%dx%d", kRootWidth, kRootHeight));
 
-    aura::RootWindow* root = GetRootWindow();
+    aura::Window* root = GetRootWindow();
     gfx::Rect root_bounds(root->bounds());
 
 #if defined(OS_WIN)
@@ -48,13 +48,13 @@
   }
 
  protected:
-  aura::RootWindow* GetRootWindow() const {
+  aura::Window* GetRootWindow() const {
     return Shell::GetPrimaryRootWindow();
   }
 
   std::string GetHostMouseLocation() {
     gfx::Point point;
-    GetRootWindow()->QueryMouseLocationForTest(&point);
+    GetRootWindow()->GetDispatcher()->QueryMouseLocationForTest(&point);
     return point.ToString();
   }
 
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc
index d913856..3e762b7 100644
--- a/ash/magnifier/partial_magnification_controller.cc
+++ b/ash/magnifier/partial_magnification_controller.cc
@@ -79,7 +79,7 @@
 void PartialMagnificationController::OnMouseEvent(ui::MouseEvent* event) {
   if (IsPartialMagnified() && event->type() == ui::ET_MOUSE_MOVED) {
     aura::Window* target = static_cast<aura::Window*>(event->target());
-    aura::RootWindow* current_root = target->GetRootWindow();
+    aura::Window* current_root = target->GetRootWindow();
     // TODO(zork): Handle the case where the event is captured on a different
     // display, such as when a menu is opened.
     gfx::Rect root_bounds = current_root->bounds();
@@ -178,14 +178,14 @@
 void PartialMagnificationController::RemoveZoomWidgetObservers() {
   DCHECK(zoom_widget_);
   zoom_widget_->RemoveObserver(this);
-  aura::RootWindow* root_window =
+  aura::Window* root_window =
       zoom_widget_->GetNativeView()->GetRootWindow();
   DCHECK(root_window);
   root_window->RemoveObserver(this);
 }
 
 void PartialMagnificationController::SwitchTargetRootWindow(
-    aura::RootWindow* new_root_window) {
+    aura::Window* new_root_window) {
   if (zoom_widget_ &&
       new_root_window == zoom_widget_->GetNativeView()->GetRootWindow())
     return;
diff --git a/ash/magnifier/partial_magnification_controller.h b/ash/magnifier/partial_magnification_controller.h
index 54c15f3..01c3a2b 100644
--- a/ash/magnifier/partial_magnification_controller.h
+++ b/ash/magnifier/partial_magnification_controller.h
@@ -49,7 +49,7 @@
   //  - Remove the magnifier from the current root window.
   //  - Create a magnifier in the new root_window |new_root_window|.
   //  - Switch the target window from current window to |new_root_window|.
-  void SwitchTargetRootWindow(aura::RootWindow* new_root_window);
+  void SwitchTargetRootWindow(aura::Window* new_root_window);
 
   // Returns the root window that contains the mouse cursor.
   aura::RootWindow* GetCurrentRootWindow();
diff --git a/ash/new_window_delegate.h b/ash/new_window_delegate.h
new file mode 100644
index 0000000..b4a592b
--- /dev/null
+++ b/ash/new_window_delegate.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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 ASH_NEW_WINDOW_DELEGATE_H_
+#define ASH_NEW_WINDOW_DELEGATE_H_
+
+namespace ash {
+
+// A delegate class to create or open windows that are not a part of
+// ash.
+class NewWindowDelegate {
+ public:
+  NewWindowDelegate() {}
+  virtual ~NewWindowDelegate() {}
+
+  // Invoked when the user uses Ctrl+T to open a new tab.
+  virtual void NewTab() = 0;
+
+  // Invoked when the user uses Ctrl-N or Ctrl-Shift-N to open a new window.
+  virtual void NewWindow(bool incognito) = 0;
+
+  // Invoked when an accelerator is used to open the file manager.
+  virtual void OpenFileManager() = 0;
+
+  // Invoked when the user opens Crosh.
+  virtual void OpenCrosh() = 0;
+
+  // Invoked when the user uses Shift+Ctrl+T to restore the closed tab.
+  virtual void RestoreTab() = 0;
+
+  // Shows the keyboard shortcut overlay.
+  virtual void ShowKeyboardOverlay() = 0;
+
+  // Shows the task manager window.
+  virtual void ShowTaskManager() = 0;
+
+  // Opens the feedback page for "Report Issue".
+  virtual void OpenFeedbackPage() = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_NEW_WINDOW_DELEGATE_H_
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index fd4ca14..de1cd9b 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -90,8 +90,6 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER" file="cros/network/status_cellular_enabled_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_DISPLAY" file="cros/status/status_display_dark.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_DISPLAY_LIGHT" file="cros/status/status_display.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SCREEN_SHARE_DARK" file="cros/status/status_screen_share_dark.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SCREEN_SHARE_LIGHT" file="cros/status/status_screen_share_light.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_DRIVE" file="cros/status/status_drive.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_DRIVE_CANCEL" file="cros/status/status_drive_item_cancel.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_DRIVE_CANCEL_HOVER" file="cros/status/status_drive_item_cancel_hover.png" />
diff --git a/ash/resources/default_100_percent/cros/status/status_screen_share_dark.png b/ash/resources/default_100_percent/cros/status/status_screen_share_dark.png
deleted file mode 100644
index 173c45c..0000000
--- a/ash/resources/default_100_percent/cros/status/status_screen_share_dark.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_screen_share_light.png b/ash/resources/default_100_percent/cros/status/status_screen_share_light.png
deleted file mode 100644
index 0b767e1..0000000
--- a/ash/resources/default_100_percent/cros/status/status_screen_share_light.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_screen_share_dark.png b/ash/resources/default_200_percent/cros/status/status_screen_share_dark.png
deleted file mode 100644
index 392b99d..0000000
--- a/ash/resources/default_200_percent/cros/status/status_screen_share_dark.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_screen_share_light.png b/ash/resources/default_200_percent/cros/status/status_screen_share_light.png
deleted file mode 100644
index 4845e0a..0000000
--- a/ash/resources/default_200_percent/cros/status/status_screen_share_light.png
+++ /dev/null
Binary files differ
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 6964f14..22eeda4 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -110,7 +110,7 @@
 }
 
 // Reparents the appropriate set of windows from |src| to |dst|.
-void ReparentAllWindows(aura::RootWindow* src, aura::RootWindow* dst) {
+void ReparentAllWindows(aura::Window* src, aura::Window* dst) {
   // Set of windows to move.
   const int kContainerIdsToMove[] = {
     internal::kShellWindowId_DefaultContainer,
@@ -217,15 +217,22 @@
 namespace internal {
 
 void RootWindowController::CreateForPrimaryDisplay(
-    aura::RootWindow * root) {
+    aura::RootWindow* root) {
   RootWindowController* controller = new RootWindowController(root);
-  controller->Init(true /* primary */,
+  controller->Init(RootWindowController::PRIMARY,
                    Shell::GetInstance()->delegate()->IsFirstRunAfterBoot());
 }
 
 void RootWindowController::CreateForSecondaryDisplay(aura::RootWindow * root) {
   RootWindowController* controller = new RootWindowController(root);
-  controller->Init(false /* secondary */, false /* first run */);
+  controller->Init(RootWindowController::SECONDARY, false /* first run */);
+}
+
+void RootWindowController::CreateForVirtualKeyboardDisplay(
+    aura::RootWindow * root) {
+  RootWindowController* controller = new RootWindowController(root);
+  controller->Init(RootWindowController::VIRTUAL_KEYBOARD,
+                   false /* first run */);
 }
 
 // static
@@ -276,7 +283,7 @@
   // being removed triggers a relayout of the shelf it will try to build a
   // window list adding windows from the target root window's containers which
   // may have already gone away.
-  if (Shell::GetTargetRootWindow() == root_window_) {
+  if (Shell::GetTargetRootWindow() == root_window_.get()) {
     Shell::GetInstance()->set_target_root_window(
         Shell::GetPrimaryRootWindow() == root_window_.get() ?
         NULL : Shell::GetPrimaryRootWindow());
@@ -456,7 +463,7 @@
   shelf_.reset(NULL);
 }
 
-void RootWindowController::MoveWindowsTo(aura::RootWindow* dst) {
+void RootWindowController::MoveWindowsTo(aura::Window* dst) {
   // Forget the shelf early so that shelf don't update itself using wrong
   // display info.
   workspace_controller_->SetShelf(NULL);
@@ -565,15 +572,20 @@
   screen_dimmer_.reset(new ScreenDimmer(root_window));
 
   stacking_controller_.reset(new StackingController);
-  aura::client::SetStackingClient(root_window, stacking_controller_.get());
+  aura::client::SetWindowTreeClient(root_window, stacking_controller_.get());
   capture_client_.reset(new views::corewm::ScopedCaptureClient(root_window));
 }
 
-void RootWindowController::Init(bool is_primary, bool first_run_after_boot) {
+void RootWindowController::Init(RootWindowType root_window_type,
+                                bool first_run_after_boot) {
   Shell::GetInstance()->InitRootWindow(root_window_.get());
 
   root_window_->SetCursor(ui::kCursorPointer);
   CreateContainersInRootWindow(root_window_.get());
+
+  if (root_window_type == VIRTUAL_KEYBOARD)
+    return;
+
   CreateSystemBackground(first_run_after_boot);
 
   InitLayoutManagers();
@@ -587,7 +599,7 @@
   Shell* shell = Shell::GetInstance();
   shell->AddShellObserver(this);
 
-  if (is_primary) {
+  if (root_window_type == PRIMARY) {
     root_window_layout()->OnWindowResized();
     shell->InitKeyboard(this);
   } else {
@@ -596,9 +608,6 @@
         root_window_.get());
     shell->high_contrast_controller()->OnRootWindowAdded(root_window_.get());
     root_window_->ShowRootWindow();
-    // Activate new root for testing.
-    // TODO(oshima): remove this.
-    shell->set_target_root_window(root_window_.get());
 
     // Create a launcher if a user is already logged.
     if (shell->session_state_delegate()->NumberOfLoggedInUsers())
@@ -765,12 +774,6 @@
   views::corewm::SetChildWindowVisibilityChangesAnimated(docked_container);
   SetUsesScreenCoordinates(docked_container);
 
-  aura::Window* panel_container = CreateContainer(
-      kShellWindowId_PanelContainer,
-      "PanelContainer",
-      non_lock_screen_containers);
-  SetUsesScreenCoordinates(panel_container);
-
   aura::Window* shelf_container =
       CreateContainer(kShellWindowId_ShelfContainer,
                       "ShelfContainer",
@@ -778,6 +781,19 @@
   SetUsesScreenCoordinates(shelf_container);
   DescendantShouldStayInSameRootWindow(shelf_container);
 
+  aura::Window* panel_container = CreateContainer(
+      kShellWindowId_PanelContainer,
+      "PanelContainer",
+      non_lock_screen_containers);
+  SetUsesScreenCoordinates(panel_container);
+
+  aura::Window* shelf_bubble_container =
+      CreateContainer(kShellWindowId_ShelfBubbleContainer,
+                      "ShelfBubbleContainer",
+                      non_lock_screen_containers);
+  SetUsesScreenCoordinates(shelf_bubble_container);
+  DescendantShouldStayInSameRootWindow(shelf_bubble_container);
+
   aura::Window* app_list_container =
       CreateContainer(kShellWindowId_AppListContainer,
                       "AppListContainer",
@@ -799,6 +815,8 @@
       kShellWindowId_InputMethodContainer,
       "InputMethodContainer",
       non_lock_screen_containers);
+  views::corewm::SetChildWindowVisibilityChangesAnimated(
+      input_method_container);
   SetUsesScreenCoordinates(input_method_container);
 
   // TODO(beng): Figure out if we can make this use
@@ -887,7 +905,7 @@
 }
 
 RootWindowController* GetRootWindowController(
-    const aura::RootWindow* root_window) {
+    const aura::Window* root_window) {
   return root_window ? GetRootWindowSettings(root_window)->controller : NULL;
 }
 
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 4e6b8d1..fa8172f 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -84,6 +84,10 @@
   // Creates and Initialize the RootWindowController for secondary displays.
   static void CreateForSecondaryDisplay(aura::RootWindow* root_window);
 
+  // Creates and Initialize the RootWindowController for virtual
+  // keyboard displays.
+  static void CreateForVirtualKeyboardDisplay(aura::RootWindow* root_window);
+
   // Returns a RootWindowController that has a launcher for given
   // |window|. This returns the RootWindowController for the |window|'s
   // root window when multiple launcher mode is enabled, or the primary
@@ -202,7 +206,7 @@
   void CloseChildWindows();
 
   // Moves child windows to |dest|.
-  void MoveWindowsTo(aura::RootWindow* dest);
+  void MoveWindowsTo(aura::Window* dest);
 
   // Force the shelf to query for it's current visibility state.
   void UpdateShelfVisibility();
@@ -222,11 +226,16 @@
 
  private:
   explicit RootWindowController(aura::RootWindow* root_window);
+  enum RootWindowType {
+    PRIMARY,
+    SECONDARY,
+    VIRTUAL_KEYBOARD
+  };
 
   // Initializes the RootWindowController.  |is_primary| is true if
   // the controller is for primary display.  |first_run_after_boot| is
   // set to true only for primary root window after boot.
-  void Init(bool is_primary, bool first_run_after_boot);
+  void Init(RootWindowType root_window_type, bool first_run_after_boot);
 
   void InitLayoutManagers();
 
@@ -301,7 +310,7 @@
 
 // Gets the RootWindowController for |root_window|.
 ASH_EXPORT RootWindowController* GetRootWindowController(
-    const aura::RootWindow* root_window);
+    const aura::Window* root_window);
 
 }  // namespace internal
 }  // ash
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 70d9146..b8c480c 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/command_line.h"
 #include "ui/aura/client/focus_change_observer.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/event_generator.h"
@@ -573,8 +574,8 @@
   window1->set_owned_by_parent(false);
   observer1.SetWindow(window1);
   window1->Init(ui::LAYER_NOT_DRAWN);
-  window1->SetDefaultParentByRootWindow(
-      Shell::GetInstance()->GetPrimaryRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      window1, Shell::GetInstance()->GetPrimaryRootWindow(), gfx::Rect());
 
   DestroyedWindowObserver observer2;
   aura::Window* window2 = new aura::Window(NULL);
@@ -596,7 +597,7 @@
 
 // Make sure that an event handler exists for entire display area.
 TEST_F(NoSessionRootWindowControllerTest, Event) {
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   const gfx::Size size = root->bounds().size();
   aura::Window* event_target = root->GetEventHandlerForPoint(gfx::Point(0, 0));
   EXPECT_TRUE(event_target);
@@ -620,6 +621,8 @@
     CommandLine::ForCurrentProcess()->AppendSwitch(
         keyboard::switches::kEnableVirtualKeyboard);
     test::AshTestBase::SetUp();
+    Shell::GetPrimaryRootWindowController()->ActivateKeyboard(
+        Shell::GetInstance()->keyboard_controller());
   }
 
  private:
@@ -636,8 +639,8 @@
   UpdateDisplay("500x500,500x500");
 
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
-  aura::RootWindow* primary_root_window = Shell::GetPrimaryRootWindow();
-  aura::RootWindow* secondary_root_window =
+  aura::Window* primary_root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* secondary_root_window =
       root_windows[0] == primary_root_window ?
           root_windows[1] : root_windows[0];
 
@@ -653,7 +656,7 @@
 // events at blocked user session.
 TEST_F(VirtualKeyboardRootWindowControllerTest,
        ClickVirtualKeyboardInBlockedWindow) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   aura::Window* keyboard_container = Shell::GetContainer(root_window,
       internal::kShellWindowId_VirtualKeyboardContainer);
   ASSERT_TRUE(keyboard_container);
@@ -686,7 +689,7 @@
 // GetWindowContainer().
 TEST_F(VirtualKeyboardRootWindowControllerTest,
        DeleteOldContainerOnVirtualKeyboardInit) {
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
   aura::Window* keyboard_container = Shell::GetContainer(root_window,
       internal::kShellWindowId_VirtualKeyboardContainer);
   ASSERT_TRUE(keyboard_container);
diff --git a/ash/root_window_settings.cc b/ash/root_window_settings.cc
index 06198ca..33880ed 100644
--- a/ash/root_window_settings.cc
+++ b/ash/root_window_settings.cc
@@ -22,17 +22,17 @@
       controller(NULL) {
 }
 
-RootWindowSettings* InitRootWindowSettings(aura::RootWindow* root) {
+RootWindowSettings* InitRootWindowSettings(aura::Window* root) {
   RootWindowSettings* settings = new RootWindowSettings();
   root->SetProperty(kRootWindowSettingsKey, settings);
   return settings;
 }
 
-RootWindowSettings* GetRootWindowSettings(aura::RootWindow* root) {
+RootWindowSettings* GetRootWindowSettings(aura::Window* root) {
   return root->GetProperty(kRootWindowSettingsKey);
 }
 
-const RootWindowSettings* GetRootWindowSettings(const aura::RootWindow* root) {
+const RootWindowSettings* GetRootWindowSettings(const aura::Window* root) {
   return root->GetProperty(kRootWindowSettingsKey);
 }
 
diff --git a/ash/root_window_settings.h b/ash/root_window_settings.h
index 784cce6..e49b0f2 100644
--- a/ash/root_window_settings.h
+++ b/ash/root_window_settings.h
@@ -9,7 +9,7 @@
 #include "base/basictypes.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 }
 
 namespace ash {
@@ -37,14 +37,14 @@
 
 // Initializes and returns RootWindowSettings for |root|.
 // It is owned by the |root|.
-RootWindowSettings* InitRootWindowSettings(aura::RootWindow* root);
+RootWindowSettings* InitRootWindowSettings(aura::Window* root);
 
 // Returns the RootWindowSettings for |root|.
-ASH_EXPORT RootWindowSettings* GetRootWindowSettings(aura::RootWindow* root);
+ASH_EXPORT RootWindowSettings* GetRootWindowSettings(aura::Window* root);
 
 // const version of GetRootWindowSettings.
 ASH_EXPORT const RootWindowSettings*
-GetRootWindowSettings(const aura::RootWindow* root);
+GetRootWindowSettings(const aura::Window* root);
 
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/scoped_target_root_window.cc b/ash/scoped_target_root_window.cc
index b488a6f..c34f4c3 100644
--- a/ash/scoped_target_root_window.cc
+++ b/ash/scoped_target_root_window.cc
@@ -9,7 +9,7 @@
 namespace internal {
 
 ScopedTargetRootWindow::ScopedTargetRootWindow(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   Shell::GetInstance()->scoped_target_root_window_ = root_window;
 }
 
diff --git a/ash/scoped_target_root_window.h b/ash/scoped_target_root_window.h
index ab695be..0e7a8b1 100644
--- a/ash/scoped_target_root_window.h
+++ b/ash/scoped_target_root_window.h
@@ -7,7 +7,7 @@
 #include "base/basictypes.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 }
 
 namespace ash {
@@ -20,7 +20,7 @@
 // a new window using launcher's icon.
 class ScopedTargetRootWindow {
  public:
-  explicit ScopedTargetRootWindow(aura::RootWindow* root_window);
+  explicit ScopedTargetRootWindow(aura::Window* root_window);
   ~ScopedTargetRootWindow();
 
  private:
diff --git a/ash/screensaver/screensaver_view.cc b/ash/screensaver/screensaver_view.cc
index 6c2c1e0..b16d812 100644
--- a/ash/screensaver/screensaver_view.cc
+++ b/ash/screensaver/screensaver_view.cc
@@ -143,7 +143,7 @@
 }
 
 void ScreensaverView::ShowWindow() {
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
   gfx::Rect screen_rect =
       Shell::GetScreen()->GetDisplayNearestWindow(root_window).bounds();
 
diff --git a/ash/session_state_delegate.h b/ash/session_state_delegate.h
index 7fac828..47570ff 100644
--- a/ash/session_state_delegate.h
+++ b/ash/session_state_delegate.h
@@ -109,7 +109,7 @@
   // is therefore shown on the desktop of every user.
   virtual bool TransferWindowToDesktopOfUser(
       aura::Window* window,
-      ash::MultiProfileIndex index) const = 0;
+      ash::MultiProfileIndex index) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/session_state_delegate_stub.cc b/ash/session_state_delegate_stub.cc
index 91602b3..6daa593 100644
--- a/ash/session_state_delegate_stub.cc
+++ b/ash/session_state_delegate_stub.cc
@@ -95,7 +95,7 @@
 
 bool SessionStateDelegateStub::TransferWindowToDesktopOfUser(
     aura::Window* window,
-    ash::MultiProfileIndex index) const {
+    ash::MultiProfileIndex index) {
   return false;
 }
 
diff --git a/ash/session_state_delegate_stub.h b/ash/session_state_delegate_stub.h
index 894759d..6fe1eb9 100644
--- a/ash/session_state_delegate_stub.h
+++ b/ash/session_state_delegate_stub.h
@@ -45,7 +45,7 @@
       ash::SessionStateObserver* observer) OVERRIDE;
   virtual bool TransferWindowToDesktopOfUser(
       aura::Window* window,
-      ash::MultiProfileIndex index) const OVERRIDE;
+      ash::MultiProfileIndex index) OVERRIDE;
 
  private:
   bool screen_locked_;
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index 231f68d..f032d69 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -36,7 +36,7 @@
 }
 
 ui::MenuModel* AppListShelfItemDelegate::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   return NULL;
 }
 
diff --git a/ash/shelf/app_list_shelf_item_delegate.h b/ash/shelf/app_list_shelf_item_delegate.h
index 2827599..6a14f14 100644
--- a/ash/shelf/app_list_shelf_item_delegate.h
+++ b/ash/shelf/app_list_shelf_item_delegate.h
@@ -23,7 +23,7 @@
   virtual void ItemSelected(const ui::Event& event) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual LauncherMenuModel* CreateApplicationMenu(int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
   virtual bool ShouldShowTooltip() OVERRIDE;
diff --git a/ash/shelf/overflow_bubble.cc b/ash/shelf/overflow_bubble.cc
index 554e89f..0b62f46 100644
--- a/ash/shelf/overflow_bubble.cc
+++ b/ash/shelf/overflow_bubble.cc
@@ -12,6 +12,7 @@
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
+#include "ash/shell_window_ids.h"
 #include "ash/system/tray/system_tray.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/root_window.h"
@@ -120,6 +121,9 @@
   shelf_view_ = shelf_view;
   AddChildView(shelf_view_);
 
+  set_parent_window(Shell::GetContainer(
+        anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
+        internal::kShellWindowId_ShelfBubbleContainer));
   views::BubbleDelegateView::CreateBubble(this);
 }
 
diff --git a/ash/shelf/shelf_alignment_menu.cc b/ash/shelf/shelf_alignment_menu.cc
index d0d381f..722b053 100644
--- a/ash/shelf/shelf_alignment_menu.cc
+++ b/ash/shelf/shelf_alignment_menu.cc
@@ -8,12 +8,12 @@
 #include "ash/shelf/shelf_types.h"
 #include "ash/shell.h"
 #include "grit/ash_strings.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
-ShelfAlignmentMenu::ShelfAlignmentMenu(aura::RootWindow* root)
+ShelfAlignmentMenu::ShelfAlignmentMenu(aura::Window* root)
     : ui::SimpleMenuModel(NULL),
       root_window_(root) {
   DCHECK(root_window_);
diff --git a/ash/shelf/shelf_alignment_menu.h b/ash/shelf/shelf_alignment_menu.h
index 288de9a..e7acce2 100644
--- a/ash/shelf/shelf_alignment_menu.h
+++ b/ash/shelf/shelf_alignment_menu.h
@@ -19,7 +19,7 @@
 class ASH_EXPORT ShelfAlignmentMenu : public ui::SimpleMenuModel,
                                       public ui::SimpleMenuModel::Delegate {
  public:
-  explicit ShelfAlignmentMenu(aura::RootWindow* root);
+  explicit ShelfAlignmentMenu(aura::Window* root);
   virtual ~ShelfAlignmentMenu();
 
   // ui::SimpleMenuModel::Delegate overrides:
@@ -38,7 +38,7 @@
     MENU_ALIGN_BOTTOM,
   };
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(ShelfAlignmentMenu);
 };
diff --git a/ash/shelf/shelf_icon_observer.h b/ash/shelf/shelf_icon_observer.h
new file mode 100644
index 0000000..8132a89
--- /dev/null
+++ b/ash/shelf/shelf_icon_observer.h
@@ -0,0 +1,23 @@
+// Copyright 2013 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 ASH_SHELF_SHELF_ICON_OBSERVER_H_
+#define ASH_SHELF_SHELF_ICON_OBSERVER_H_
+
+#include "ash/ash_export.h"
+
+namespace ash {
+
+class ASH_EXPORT ShelfIconObserver {
+ public:
+  // Invoked when any icon on shelf changes position.
+  virtual void OnShelfIconPositionsChanged() = 0;
+
+ protected:
+  virtual ~ShelfIconObserver() {}
+};
+
+}  // namespace ash
+
+#endif  // ASH_SHELF_SHELF_ICON_OBSERVER_H_
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index e270547..566db94 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -26,7 +26,6 @@
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_animations.h"
-#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace_controller.h"
@@ -321,10 +320,12 @@
     WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
     switch (window_state) {
       case WORKSPACE_WINDOW_STATE_FULL_SCREEN:
-        if (FullscreenWithMinimalChrome()) {
-          SetState(SHELF_AUTO_HIDE);
-        } else {
+        if (FullscreenWithHiddenShelf()) {
           SetState(SHELF_HIDDEN);
+        } else {
+          // The shelf is sometimes not hidden when in immersive fullscreen.
+          // Force the shelf to be auto hidden in this case.
+          SetState(SHELF_AUTO_HIDE);
         }
         break;
       case WORKSPACE_WINDOW_STATE_MAXIMIZED:
@@ -469,10 +470,10 @@
       gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
       SHELF_AUTO_HIDE_BEHAVIOR_NEVER : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
 
-  // In fullscreen with minimal chrome, the auto hide behavior affects neither
-  // the visibility state nor the auto hide state. Set |gesture_drag_status_|
-  // to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto hide state to
-  // |gesture_drag_auto_hide_state_|.
+  // When in fullscreen and the shelf is forced to be auto hidden, the auto hide
+  // behavior affects neither the visibility state nor the auto hide state. Set
+  // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto
+  // hide state to |gesture_drag_auto_hide_state_|.
   gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
   if (auto_hide_behavior_ != new_auto_hide_behavior)
     SetAutoHideBehavior(new_auto_hide_behavior);
@@ -537,16 +538,14 @@
          GetAlignment() == SHELF_ALIGNMENT_TOP;
 }
 
-bool ShelfLayoutManager::FullscreenWithMinimalChrome() const {
+bool ShelfLayoutManager::FullscreenWithHiddenShelf() const {
   RootWindowController* controller = GetRootWindowController(root_window_);
   if (!controller)
     return false;
   const aura::Window* window = controller->GetTopmostFullscreenWindow();
   if (!window)
     return false;
-  if (!window->GetProperty(kFullscreenUsesMinimalChromeKey))
-    return false;
-  return true;
+  return wm::GetWindowState(window)->hide_shelf_when_fullscreen();
 }
 
 // static
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index d8b6e8f..13f90b6 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -212,9 +212,9 @@
   // Is the shelf's alignment horizontal?
   bool IsHorizontalAlignment() const;
 
-  // Tests if the browser is currently in fullscreen mode with minimal
-  // Chrome. When minimal Chrome is present the shelf should be displayed.
-  bool FullscreenWithMinimalChrome() const;
+  // Returns true if there is a fullscreen window and the shelf needs to be
+  // hidden for the topmost fullscreen window.
+  bool FullscreenWithHiddenShelf() const;
 
   // Returns a ShelfLayoutManager on the display which has a launcher for
   // given |window|. See RootWindowController::ForLauncher for more info.
@@ -342,7 +342,7 @@
   // The RootWindow is cached so that we don't invoke Shell::GetInstance() from
   // our destructor. We avoid that as at the time we're deleted Shell is being
   // deleted too.
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling
   // UpdateBoundsAndOpacity() again from SetChildBounds().
diff --git a/ash/shelf/shelf_layout_manager_observer.h b/ash/shelf/shelf_layout_manager_observer.h
index 328e209..6209980 100644
--- a/ash/shelf/shelf_layout_manager_observer.h
+++ b/ash/shelf/shelf_layout_manager_observer.h
@@ -9,7 +9,7 @@
 #include "ash/shelf/shelf_types.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 }
 
 namespace ash {
@@ -28,7 +28,7 @@
   virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) {}
 
   // Called when the auto hide behavior is changed.
-  virtual void OnAutoHideBehaviorChanged(aura::RootWindow* root_window,
+  virtual void OnAutoHideBehaviorChanged(aura::Window* root_window,
                                          ShelfAutoHideBehavior new_behavior) {}
 };
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 93dfc57..4ee9e00 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -23,7 +23,7 @@
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/launcher_test_api.h"
-#include "ash/wm/window_properties.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
@@ -347,7 +347,7 @@
     window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window->Init(ui::LAYER_TEXTURED);
-    SetDefaultParentByPrimaryRootWindow(window);
+    ParentWindowInPrimaryRootWindow(window);
     return window;
   }
 
@@ -579,9 +579,10 @@
   EXPECT_EQ(shelf_hidden.ToString(),
             GetShelfWidget()->GetWindowBoundsInScreen().ToString());
 
-  // Enter into fullscreen with minimal chrome (immersive fullscreen).
+  // Put |widget| into fullscreen. Set the shelf to be auto hidden when |widget|
+  // is fullscreen. (eg browser immersive fullscreen).
   widget->SetFullscreen(true);
-  window->SetProperty(ash::internal::kFullscreenUsesMinimalChromeKey, true);
+  wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(false);
   shelf->UpdateVisibilityState();
 
   gfx::Rect bounds_fullscreen = window->bounds();
@@ -613,9 +614,9 @@
             GetShelfWidget()->GetWindowBoundsInScreen().ToString());
   EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString());
 
-  // Put the window into fullscreen without any chrome at all (eg tab
-  // fullscreen).
-  window->SetProperty(ash::internal::kFullscreenUsesMinimalChromeKey, false);
+  // Set the shelf to be hidden when |widget| is fullscreen. (eg tab fullscreen
+  // with or without immersive browser fullscreen).
+  wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(true);
   shelf->UpdateVisibilityState();
   EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
   EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
@@ -797,7 +798,7 @@
 
 // Various assertions around auto-hide.
 TEST_F(ShelfLayoutManagerTest, MAYBE_AutoHide) {
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   aura::test::EventGenerator generator(root, root);
   generator.MoveMouseTo(0, 0);
 
@@ -974,7 +975,7 @@
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
 
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   // LayoutShelf() forces the animation to completion, at which point the
   // launcher should go off the screen.
   shelf->LayoutShelf();
diff --git a/ash/shelf/shelf_tooltip_manager.cc b/ash/shelf/shelf_tooltip_manager.cc
index bdf3306..10ea4a6 100644
--- a/ash/shelf/shelf_tooltip_manager.cc
+++ b/ash/shelf/shelf_tooltip_manager.cc
@@ -96,7 +96,7 @@
   SetLayoutManager(new views::FillLayout());
   // The anchor may not have the widget in tests.
   if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) {
-    aura::RootWindow* root_window =
+    aura::Window* root_window =
         anchor->GetWidget()->GetNativeView()->GetRootWindow();
     set_parent_window(ash::Shell::GetInstance()->GetContainer(
         root_window, ash::internal::kShellWindowId_SettingBubbleContainer));
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc
index 6f2f0fa..d4b9c07 100644
--- a/ash/shelf/shelf_tooltip_manager_unittest.cc
+++ b/ash/shelf/shelf_tooltip_manager_unittest.cc
@@ -180,7 +180,7 @@
   ShowImmediately();
   ASSERT_TRUE(TooltipIsVisible());
 
-  aura::RootWindow* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
   ui::EventHandler* event_handler = GetEventHandler();
 
   // Should not hide for key events.
@@ -222,7 +222,7 @@
   ShowImmediately();
   ASSERT_TRUE(TooltipIsVisible());
 
-  aura::RootWindow* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
   ui::EventHandler* event_handler = GetEventHandler();
 
   gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds();
@@ -251,7 +251,7 @@
   ShowImmediately();
   ASSERT_TRUE(TooltipIsVisible());
 
-  aura::RootWindow* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
   ui::EventHandler* event_handler = GetEventHandler();
 
   gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds();
diff --git a/ash/shelf/shelf_util.cc b/ash/shelf/shelf_util.cc
deleted file mode 100644
index 07dfbbe..0000000
--- a/ash/shelf/shelf_util.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 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 "ash/shelf/shelf_util.h"
-
-#include "ash/launcher/launcher_model.h"
-#include "ash/launcher/launcher_types.h"
-
-namespace ash {
-
-int GetBrowserItemIndex(const LauncherModel& launcher_model) {
-  for (size_t i = 0; i < launcher_model.items().size(); i++) {
-    if (launcher_model.items()[i].type == ash::TYPE_BROWSER_SHORTCUT)
-      return i;
-  }
-  return -1;
-}
-
-}  // namespace ash
diff --git a/ash/shelf/shelf_util.h b/ash/shelf/shelf_util.h
deleted file mode 100644
index daf6c0f..0000000
--- a/ash/shelf/shelf_util.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2013 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 ASH_SHELF_SHELF_UTIL_H_
-#define ASH_SHELF_SHELF_UTIL_H_
-
-#include "ash/ash_export.h"
-
-namespace ash {
-
-class LauncherModel;
-
-// Return the index of the browser item from a given |launcher_model|.
-ASH_EXPORT int GetBrowserItemIndex(const LauncherModel& launcher_model);
-
-}  // namespace ash
-
-#endif  // ASH_SHELF_SHELF_UTIL_H_
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 25053e3..5b2a345 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -11,7 +11,6 @@
 #include "ash/drag_drop/drag_image_view.h"
 #include "ash/launcher/launcher_button.h"
 #include "ash/launcher/launcher_delegate.h"
-#include "ash/launcher/launcher_icon_observer.h"
 #include "ash/launcher/launcher_item_delegate.h"
 #include "ash/launcher/launcher_item_delegate_manager.h"
 #include "ash/launcher/launcher_model.h"
@@ -21,6 +20,7 @@
 #include "ash/shelf/app_list_button.h"
 #include "ash/shelf/overflow_bubble.h"
 #include "ash/shelf/overflow_button.h"
+#include "ash/shelf/shelf_icon_observer.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_tooltip_manager.h"
 #include "ash/shelf/shelf_widget.h"
@@ -139,7 +139,6 @@
   DISALLOW_COPY_AND_ASSIGN(LauncherMenuModelAdapter);
 };
 
-
 LauncherMenuModelAdapter::LauncherMenuModelAdapter(
     ash::LauncherMenuModel* menu_model)
     : MenuModelAdapter(menu_model),
@@ -254,21 +253,6 @@
   DISALLOW_COPY_AND_ASSIGN(LauncherButtonFocusBorder);
 };
 
-// AnimationDelegate that deletes a view when done. This is used when a launcher
-// item is removed, which triggers a remove animation. When the animation is
-// done we delete the view.
-class DeleteViewAnimationDelegate
-    : public views::BoundsAnimator::OwnedAnimationDelegate {
- public:
-  explicit DeleteViewAnimationDelegate(views::View* view) : view_(view) {}
-  virtual ~DeleteViewAnimationDelegate() {}
-
- private:
-  scoped_ptr<views::View> view_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeleteViewAnimationDelegate);
-};
-
 // AnimationDelegate used when inserting a new item. This steadily increases the
 // opacity of the layer as the animation progress.
 class FadeInAnimationDelegate
@@ -327,7 +311,7 @@
 gfx::Point GetPositionInScreen(const gfx::Point& root_location,
                                views::View* view) {
   gfx::Point root_location_in_screen = root_location;
-  aura::RootWindow* root_window =
+  aura::Window* root_window =
       view->GetWidget()->GetNativeWindow()->GetRootWindow();
   aura::client::GetScreenPositionClient(root_window->GetRootWindow())->
         ConvertPointToScreen(root_window, &root_location_in_screen);
@@ -415,7 +399,8 @@
       drag_and_drop_launcher_id_(0),
       dragged_off_shelf_(false),
       snap_back_from_rip_off_view_(NULL),
-      item_manager_(Shell::GetInstance()->launcher_item_delegate_manager()) {
+      item_manager_(Shell::GetInstance()->launcher_item_delegate_manager()),
+      layout_manager_(shelf_layout_manager) {
   DCHECK(model_);
   bounds_animator_.reset(new views::BoundsAnimator(this));
   bounds_animator_->AddObserver(this);
@@ -461,14 +446,13 @@
     // TODO: remove when AppIcon is a Launcher Button.
     if (TYPE_APP_LIST == model_->items()[i].type &&
         !ash::switches::UseAlternateShelfLayout()) {
-      ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
       static_cast<AppListButton*>(view_model_->view_at(i))->SetImageAlignment(
-          shelf->SelectValueForShelfAlignment(
+          layout_manager_->SelectValueForShelfAlignment(
               views::ImageButton::ALIGN_CENTER,
               views::ImageButton::ALIGN_LEFT,
               views::ImageButton::ALIGN_RIGHT,
               views::ImageButton::ALIGN_CENTER),
-          shelf->SelectValueForShelfAlignment(
+          layout_manager_->SelectValueForShelfAlignment(
               views::ImageButton::ALIGN_TOP,
               views::ImageButton::ALIGN_MIDDLE,
               views::ImageButton::ALIGN_MIDDLE,
@@ -517,19 +501,21 @@
 
   gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()),
                               midpoint.y());
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
   int target_index = current_index;
   while (target_index > first_panel_index &&
-         shelf->PrimaryAxisValue(view_model_->ideal_bounds(target_index).x(),
-                                 view_model_->ideal_bounds(target_index).y()) >
-         shelf->PrimaryAxisValue(midpoint_in_view.x(), midpoint_in_view.y())) {
+         layout_manager_->PrimaryAxisValue(
+             view_model_->ideal_bounds(target_index).x(),
+             view_model_->ideal_bounds(target_index).y()) >
+         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
+                                           midpoint_in_view.y())) {
     --target_index;
   }
   while (target_index < view_model_->view_size() - 1 &&
-         shelf->PrimaryAxisValue(
+         layout_manager_->PrimaryAxisValue(
              view_model_->ideal_bounds(target_index).right(),
              view_model_->ideal_bounds(target_index).bottom()) <
-         shelf->PrimaryAxisValue(midpoint_in_view.x(), midpoint_in_view.y())) {
+         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
+                                           midpoint_in_view.y())) {
     ++target_index;
   }
   if (current_index != target_index)
@@ -697,21 +683,19 @@
 }
 
 void ShelfView::LayoutToIdealBounds() {
+  if (bounds_animator_->IsAnimating()) {
+    AnimateToIdealBounds();
+    return;
+  }
+
   IdealBounds ideal_bounds;
   CalculateIdealBounds(&ideal_bounds);
-
-  if (bounds_animator_->IsAnimating())
-    AnimateToIdealBounds();
-  else
-    views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
-
+  views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
   overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds);
 }
 
 void ShelfView::CalculateIdealBounds(IdealBounds* bounds) {
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-
-  int available_size = shelf->PrimaryAxisValue(width(), height());
+  int available_size = layout_manager_->PrimaryAxisValue(width(), height());
   DCHECK(model_->item_count() == view_model_->view_size());
   if (!available_size)
     return;
@@ -722,17 +706,17 @@
   // Initial x,y values account both leading_inset in primary
   // coordinate and secondary coordinate based on the dynamic edge of the
   // launcher (eg top edge on bottom-aligned launcher).
-  int inset = ash::switches::UseAlternateShelfLayout() ? 0 : leading_inset();
-  int x = shelf->SelectValueForShelfAlignment(inset, 0, 0, inset);
-  int y = shelf->SelectValueForShelfAlignment(0, inset, inset, 0);
+  int inset = ash::switches::UseAlternateShelfLayout() ? 0 : leading_inset_;
+  int x = layout_manager_->SelectValueForShelfAlignment(inset, 0, 0, inset);
+  int y = layout_manager_->SelectValueForShelfAlignment(0, inset, inset, 0);
 
   int button_size = ash::switches::UseAlternateShelfLayout() ?
       kButtonSize : kLauncherPreferredSize;
   int button_spacing = ash::switches::UseAlternateShelfLayout() ?
       kAlternateButtonSpacing : kButtonSpacing;
 
-  int w = shelf->PrimaryAxisValue(button_size, width());
-  int h = shelf->PrimaryAxisValue(height(), button_size);
+  int w = layout_manager_->PrimaryAxisValue(button_size, width());
+  int h = layout_manager_->PrimaryAxisValue(height(), button_size);
   for (int i = 0; i < view_model_->view_size(); ++i) {
     if (i < first_visible_index_) {
       view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
@@ -741,12 +725,14 @@
 
     view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
     if (i != last_button_index) {
-      x = shelf->PrimaryAxisValue(x + w + button_spacing, x);
-      y = shelf->PrimaryAxisValue(y, y + h + button_spacing);
+      x = layout_manager_->PrimaryAxisValue(x + w + button_spacing, x);
+      y = layout_manager_->PrimaryAxisValue(y, y + h + button_spacing);
     }
   }
 
   if (is_overflow_mode()) {
+    // The overflow button is not shown in overflow mode.
+    overflow_button_->SetVisible(false);
     DCHECK_LT(last_visible_index_, view_model_->view_size());
     for (int i = 0; i < view_model_->view_size(); ++i) {
       bool visible = i >= first_visible_index_ &&
@@ -763,26 +749,26 @@
   if (!ash::switches::UseAlternateShelfLayout()) {
     if (view_model_->view_size() > 0) {
       view_model_->set_ideal_bounds(0, gfx::Rect(gfx::Size(
-          shelf->PrimaryAxisValue(inset + w, w),
-          shelf->PrimaryAxisValue(h, inset + h))));
+          layout_manager_->PrimaryAxisValue(inset + w, w),
+          layout_manager_->PrimaryAxisValue(h, inset + h))));
     }
   }
 
   // Right aligned icons.
   int end_position = available_size - button_spacing;
-  x = shelf->PrimaryAxisValue(end_position, 0);
-  y = shelf->PrimaryAxisValue(0, end_position);
+  x = layout_manager_->PrimaryAxisValue(end_position, 0);
+  y = layout_manager_->PrimaryAxisValue(0, end_position);
   for (int i = view_model_->view_size() - 1;
        i >= first_panel_index; --i) {
-    x = shelf->PrimaryAxisValue(x - w - button_spacing, x);
-    y = shelf->PrimaryAxisValue(y, y - h - button_spacing);
+    x = layout_manager_->PrimaryAxisValue(x - w - button_spacing, x);
+    y = layout_manager_->PrimaryAxisValue(y, y - h - button_spacing);
     view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
-    end_position = shelf->PrimaryAxisValue(x, y);
+    end_position = layout_manager_->PrimaryAxisValue(x, y);
   }
 
   // Icons on the left / top are guaranteed up to kLeftIconProportion of
   // the available space.
-  int last_icon_position = shelf->PrimaryAxisValue(
+  int last_icon_position = layout_manager_->PrimaryAxisValue(
       view_model_->ideal_bounds(last_button_index).right(),
       view_model_->ideal_bounds(last_button_index).bottom())
       + button_size + inset;
@@ -794,9 +780,9 @@
   else
     end_position = std::max(end_position, reserved_icon_space);
 
-  bounds->overflow_bounds.set_size(gfx::Size(
-      shelf->PrimaryAxisValue(w, width()),
-      shelf->PrimaryAxisValue(height(), h)));
+  bounds->overflow_bounds.set_size(
+      gfx::Size(layout_manager_->PrimaryAxisValue(w, width()),
+                layout_manager_->PrimaryAxisValue(height(), h)));
 
   if (ash::switches::UseAlternateShelfLayout()) {
     last_visible_index_ = DetermineLastVisibleIndex(
@@ -833,17 +819,17 @@
   if (show_overflow) {
     DCHECK_NE(0, view_model_->view_size());
     if (last_visible_index_ == -1) {
-      x = shelf->SelectValueForShelfAlignment(inset, 0, 0, inset);
-      y = shelf->SelectValueForShelfAlignment(0, inset, inset, 0);
+      x = layout_manager_->SelectValueForShelfAlignment(inset, 0, 0, inset);
+      y = layout_manager_->SelectValueForShelfAlignment(0, inset, inset, 0);
     } else if (last_visible_index_ == last_button_index
         && !ash::switches::UseAlternateShelfLayout()) {
       x = view_model_->ideal_bounds(last_visible_index_).x();
       y = view_model_->ideal_bounds(last_visible_index_).y();
     } else {
-      x = shelf->PrimaryAxisValue(
+      x = layout_manager_->PrimaryAxisValue(
           view_model_->ideal_bounds(last_visible_index_).right(),
           view_model_->ideal_bounds(last_visible_index_).x());
-      y = shelf->PrimaryAxisValue(
+      y = layout_manager_->PrimaryAxisValue(
           view_model_->ideal_bounds(last_visible_index_).y(),
           view_model_->ideal_bounds(last_visible_index_).bottom());
     }
@@ -851,14 +837,21 @@
     for (int i = first_panel_index; i <= last_hidden_index_; ++i)
       view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
 
+    // Add more space between last visible item and overflow button.
+    // Without this, two buttons look too close compared with other items.
+    if (ash::switches::UseAlternateShelfLayout()) {
+      x = layout_manager_->PrimaryAxisValue(x + button_spacing, x);
+      y = layout_manager_->PrimaryAxisValue(y, y + button_spacing);
+    }
+
     bounds->overflow_bounds.set_x(x);
     bounds->overflow_bounds.set_y(y);
     if (!ash::switches::UseAlternateShelfLayout()) {
       // Position app list after overflow button.
       gfx::Rect app_list_bounds = view_model_->ideal_bounds(last_button_index);
 
-      x = shelf->PrimaryAxisValue(x + w + button_spacing, x);
-      y = shelf->PrimaryAxisValue(y, y + h + button_spacing);
+      x = layout_manager_->PrimaryAxisValue(x + w + button_spacing, x);
+      y = layout_manager_->PrimaryAxisValue(y, y + h + button_spacing);
       app_list_bounds.set_x(x);
       app_list_bounds.set_y(y);
       view_model_->set_ideal_bounds(last_button_index, app_list_bounds);
@@ -872,11 +865,9 @@
 }
 
 int ShelfView::DetermineLastVisibleIndex(int max_value) const {
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-
   int index = model_->FirstPanelIndex() - 1;
   while (index >= 0 &&
-         shelf->PrimaryAxisValue(
+         layout_manager_->PrimaryAxisValue(
              view_model_->ideal_bounds(index).right(),
              view_model_->ideal_bounds(index).bottom()) > max_value) {
     index--;
@@ -885,11 +876,9 @@
 }
 
 int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const {
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-
   int index = model_->FirstPanelIndex();
   while (index < view_model_->view_size() &&
-         shelf->PrimaryAxisValue(
+         layout_manager_->PrimaryAxisValue(
              view_model_->ideal_bounds(index).right(),
              view_model_->ideal_bounds(index).bottom()) < min_value) {
     ++index;
@@ -897,11 +886,11 @@
   return index;
 }
 
-void ShelfView::AddIconObserver(LauncherIconObserver* observer) {
+void ShelfView::AddIconObserver(ShelfIconObserver* observer) {
   observers_.AddObserver(observer);
 }
 
-void ShelfView::RemoveIconObserver(LauncherIconObserver* observer) {
+void ShelfView::RemoveIconObserver(ShelfIconObserver* observer) {
   observers_.RemoveObserver(observer);
 }
 
@@ -929,8 +918,8 @@
     case TYPE_WINDOWED_APP:
     case TYPE_PLATFORM_APP:
     case TYPE_APP_PANEL: {
-      LauncherButton* button = LauncherButton::Create(
-          this, this, tooltip_->shelf_layout_manager());
+      LauncherButton* button =
+          LauncherButton::Create(this, this, layout_manager_);
       button->SetImage(item.image);
       ReflectItemStatus(item, button);
       view = button;
@@ -939,19 +928,19 @@
 
     case TYPE_APP_LIST: {
       if (ash::switches::UseAlternateShelfLayout()) {
-        view = new AlternateAppListButton(this, this,
-            tooltip_->shelf_layout_manager()->shelf_widget());
+        view = new AlternateAppListButton(this,
+                                          this,
+                                          layout_manager_->shelf_widget());
       } else {
         // TODO(dave): turn this into a LauncherButton too.
         AppListButton* button = new AppListButton(this, this);
-        ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
         button->SetImageAlignment(
-            shelf->SelectValueForShelfAlignment(
+            layout_manager_->SelectValueForShelfAlignment(
                 views::ImageButton::ALIGN_CENTER,
                 views::ImageButton::ALIGN_LEFT,
                 views::ImageButton::ALIGN_RIGHT,
                 views::ImageButton::ALIGN_CENTER),
-            shelf->SelectValueForShelfAlignment(
+            layout_manager_->SelectValueForShelfAlignment(
                 views::ImageButton::ALIGN_TOP,
                 views::ImageButton::ALIGN_MIDDLE,
                 views::ImageButton::ALIGN_MIDDLE,
@@ -1041,8 +1030,7 @@
       last_drag_index > last_visible_index_)
     last_drag_index = last_visible_index_;
   int x = 0, y = 0;
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-  if (shelf->IsHorizontalAlignment()) {
+  if (layout_manager_->IsHorizontalAlignment()) {
     x = std::max(view_model_->ideal_bounds(indices.first).x(),
                      drag_point.x() - drag_offset_);
     x = std::min(view_model_->ideal_bounds(last_drag_index).right() -
@@ -1065,7 +1053,7 @@
   int target_index =
       views::ViewModelUtils::DetermineMoveIndex(
           *view_model_, drag_view_,
-          shelf->IsHorizontalAlignment() ?
+          layout_manager_->IsHorizontalAlignment() ?
               views::ViewModelUtils::HORIZONTAL :
               views::ViewModelUtils::VERTICAL,
           x, y);
@@ -1116,9 +1104,11 @@
     drag_view_->layer()->SetOpacity(0.0f);
     dragged_off_shelf_ = true;
     if (RemovableByRipOff(current_index) == REMOVABLE) {
-      // Move the item to the end of the launcher and hide it.
+      // Move the item to the front of the first panel item and hide it.
+      // LauncherItemMoved() callback will handle the |view_model_| update and
+      // call AnimateToIdealBounds().
       model_->Move(current_index, model_->FirstPanelIndex() - 1);
-      AnimateToIdealBounds();
+      StartFadeInLastVisibleItem();
       // Make the item partially disappear to show that it will get removed if
       // dropped.
       drag_image_->SetOpacity(0.5f);
@@ -1246,7 +1236,7 @@
     overflow_bubble_.reset(new OverflowBubble());
 
   ShelfView* overflow_view =
-      new ShelfView(model_, delegate_, tooltip_->shelf_layout_manager());
+      new ShelfView(model_, delegate_, layout_manager_);
   overflow_view->Init();
   overflow_view->set_owner_overflow_bubble(overflow_bubble_.get());
   overflow_view->OnShelfAlignmentChanged();
@@ -1261,15 +1251,13 @@
   if (ash::switches::UseAlternateShelfLayout())
     return;
 
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-
   // Creates an empty border for first launcher button to make included leading
   // inset act as the button's padding. This is only needed on button creation
   // and when shelf alignment changes.
   if (view_model_->view_size() > 0) {
     view_model_->view_at(0)->set_border(views::Border::CreateEmptyBorder(
-        shelf->PrimaryAxisValue(0, leading_inset()),
-        shelf->PrimaryAxisValue(leading_inset(), 0),
+        layout_manager_->PrimaryAxisValue(0, leading_inset_),
+        layout_manager_->PrimaryAxisValue(leading_inset_, 0),
         0,
         0));
   }
@@ -1277,7 +1265,10 @@
 
 void ShelfView::OnFadeOutAnimationEnded() {
   AnimateToIdealBounds();
+  StartFadeInLastVisibleItem();
+}
 
+void ShelfView::StartFadeInLastVisibleItem() {
   // If overflow button is visible and there is a valid new last item, fading
   // the new last item in after sliding animation is finished.
   if (overflow_button_->visible() && last_visible_index_ >= 0) {
@@ -1357,8 +1348,7 @@
   IdealBounds ideal_bounds;
   CalculateIdealBounds(&ideal_bounds);
 
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-  const int preferred_size = shelf->GetPreferredShelfSize();
+  const int preferred_size = layout_manager_->GetPreferredShelfSize();
 
   const int app_list_index = view_model_->view_size() - 1;
   const int last_button_index = is_overflow_mode() ?
@@ -1368,19 +1358,19 @@
           view_model_->view_at(last_button_index)->bounds() :
           gfx::Rect(gfx::Size(preferred_size, preferred_size));
 
-  if (shelf->IsHorizontalAlignment()) {
-    return gfx::Size(last_button_bounds.right() + leading_inset(),
+  if (layout_manager_->IsHorizontalAlignment()) {
+    return gfx::Size(last_button_bounds.right() + leading_inset_,
                      preferred_size);
   }
 
   return gfx::Size(preferred_size,
-                   last_button_bounds.bottom() + leading_inset());
+                   last_button_bounds.bottom() + leading_inset_);
 }
 
 void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
   LayoutToIdealBounds();
-  FOR_EACH_OBSERVER(LauncherIconObserver, observers_,
-                    OnLauncherIconPositionsChanged());
+  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
+                    OnShelfIconPositionsChanged());
 
   if (IsShowingOverflowBubble())
     overflow_bubble_->Hide();
@@ -1551,19 +1541,16 @@
   if (view_model_->view_size() <= 1 || !item_delegate->IsDraggable())
     return;  // View is being deleted or not draggable, ignore request.
 
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
-
   drag_view_ = view;
-  drag_offset_ = shelf->PrimaryAxisValue(event.x(), event.y());
+  drag_offset_ = layout_manager_->PrimaryAxisValue(event.x(), event.y());
 }
 
 void ShelfView::PointerDraggedOnButton(views::View* view,
                                        Pointer pointer,
                                        const ui::LocatedEvent& event) {
-  ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager();
   if (!dragging() && drag_view_ &&
-      shelf->PrimaryAxisValue(abs(event.x() - drag_offset_),
-                              abs(event.y() - drag_offset_)) >=
+      layout_manager_->PrimaryAxisValue(abs(event.x() - drag_offset_),
+                                        abs(event.y() - drag_offset_)) >=
       kMinimumDragDistance) {
     PrepareForDrag(pointer, event);
   }
@@ -1831,8 +1818,8 @@
 }
 
 void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) {
-  FOR_EACH_OBSERVER(LauncherIconObserver, observers_,
-                    OnLauncherIconPositionsChanged());
+  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
+                    OnShelfIconPositionsChanged());
   PreferredSizeChanged();
 }
 
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 0953dd3..58e5fde 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -34,9 +34,9 @@
 
 class LauncherDelegate;
 struct LauncherItem;
-class LauncherIconObserver;
 class LauncherItemDelegateManager;
 class LauncherModel;
+class ShelfIconObserver;
 
 namespace internal {
 
@@ -63,6 +63,8 @@
 
   ShelfTooltipManager* tooltip_manager() { return tooltip_.get(); }
 
+  ShelfLayoutManager* shelf_layout_manager() { return layout_manager_; }
+
   LauncherModel* model() { return model_; }
 
   void Init();
@@ -77,8 +79,8 @@
   // Repositions the icon for the specified item by the midpoint of the window.
   void UpdatePanelIconPosition(LauncherID id, const gfx::Point& midpoint);
 
-  void AddIconObserver(LauncherIconObserver* observer);
-  void RemoveIconObserver(LauncherIconObserver* observer);
+  void AddIconObserver(ShelfIconObserver* observer);
+  void RemoveIconObserver(ShelfIconObserver* observer);
 
   // Returns true if we're showing a menu.
   bool IsShowingMenu() const;
@@ -100,9 +102,6 @@
   // of the buttons area.
   bool ShouldHideTooltip(const gfx::Point& cursor_location);
 
-  int leading_inset() const { return leading_inset_; }
-  void set_leading_inset(int leading_inset) { leading_inset_ = leading_inset; }
-
   // Returns rectangle bounding all visible launcher items. Used screen
   // coordinate system.
   gfx::Rect GetVisibleItemsBoundsInScreen();
@@ -145,7 +144,7 @@
 
   enum RemovableState {
     REMOVABLE,     // Item can be removed when dragged away.
-    DRAGGABLE,     // Item can be removed, but will snap always back to origin.
+    DRAGGABLE,     // Item can be dragged, but will snap always back to origin.
     NOT_REMOVABLE, // Item is fixed and can never be removed.
   };
 
@@ -223,6 +222,9 @@
   // Invoked after the fading out animation for item deletion is ended.
   void OnFadeOutAnimationEnded();
 
+  // Fade in last visible item.
+  void StartFadeInLastVisibleItem();
+
   // Updates the visible range of overflow items in |overflow_view|.
   void UpdateOverflowRange(ShelfView* overflow_view);
 
@@ -319,7 +321,7 @@
 
   // Index of first visible launcher item. When it it greater than 0,
   // ShelfView is hosted in an overflow bubble. In this mode, it does not
-  // show browser, app list and overflow button.
+  // show app list, panel, and overflow button.
   int first_visible_index_;
 
   // Last index of a launcher button that is visible
@@ -357,7 +359,7 @@
 
   scoped_ptr<views::MenuRunner> launcher_menu_runner_;
 
-  ObserverList<LauncherIconObserver> observers_;
+  ObserverList<ShelfIconObserver> observers_;
 
   // Amount content is inset on the left edge (or top edge for vertical
   // alignment).
@@ -412,6 +414,9 @@
   // Holds LauncherItemDelegateManager.
   LauncherItemDelegateManager* item_manager_;
 
+  // Holds ShelfLayoutManager.
+  ShelfLayoutManager* layout_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(ShelfView);
 };
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 1e1765b..4fb440d 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -10,11 +10,11 @@
 #include "ash/ash_switches.h"
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_button.h"
-#include "ash/launcher/launcher_icon_observer.h"
 #include "ash/launcher/launcher_item_delegate_manager.h"
 #include "ash/launcher/launcher_model.h"
 #include "ash/launcher/launcher_types.h"
 #include "ash/root_window_controller.h"
+#include "ash/shelf/shelf_icon_observer.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_tooltip_manager.h"
 #include "ash/shelf/shelf_widget.h"
@@ -47,24 +47,24 @@
 namespace test {
 
 ////////////////////////////////////////////////////////////////////////////////
-// LauncherIconObserver tests.
+// ShelfIconObserver tests.
 
-class TestLauncherIconObserver : public LauncherIconObserver {
+class TestShelfIconObserver : public ShelfIconObserver {
  public:
-  explicit TestLauncherIconObserver(Launcher* launcher)
+  explicit TestShelfIconObserver(Launcher* launcher)
       : launcher_(launcher),
         change_notified_(false) {
     if (launcher_)
       launcher_->AddIconObserver(this);
   }
 
-  virtual ~TestLauncherIconObserver() {
+  virtual ~TestShelfIconObserver() {
     if (launcher_)
       launcher_->RemoveIconObserver(this);
   }
 
-  // LauncherIconObserver implementation.
-  virtual void OnLauncherIconPositionsChanged() OVERRIDE {
+  // ShelfIconObserver implementation.
+  virtual void OnShelfIconPositionsChanged() OVERRIDE {
     change_notified_ = true;
   }
 
@@ -75,7 +75,7 @@
   Launcher* launcher_;
   bool change_notified_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestLauncherIconObserver);
+  DISALLOW_COPY_AND_ASSIGN(TestShelfIconObserver);
 };
 
 class ShelfViewIconObserverTest : public ash::test::AshTestBase {
@@ -86,7 +86,7 @@
   virtual void SetUp() OVERRIDE {
     AshTestBase::SetUp();
     Launcher* launcher = Launcher::ForPrimaryDisplay();
-    observer_.reset(new TestLauncherIconObserver(launcher));
+    observer_.reset(new TestShelfIconObserver(launcher));
 
     shelf_view_test_.reset(new ShelfViewTestAPI(
         LauncherTestAPI(launcher).shelf_view()));
@@ -98,7 +98,7 @@
     AshTestBase::TearDown();
   }
 
-  TestLauncherIconObserver* observer() { return observer_.get(); }
+  TestShelfIconObserver* observer() { return observer_.get(); }
 
   ShelfViewTestAPI* shelf_view_test() {
     return shelf_view_test_.get();
@@ -109,7 +109,7 @@
   }
 
  private:
-  scoped_ptr<TestLauncherIconObserver> observer_;
+  scoped_ptr<TestShelfIconObserver> observer_;
   scoped_ptr<ShelfViewTestAPI> shelf_view_test_;
 
   DISALLOW_COPY_AND_ASSIGN(ShelfViewIconObserverTest);
@@ -151,7 +151,7 @@
 // launcher on external display as well as one on primary.
 TEST_F(ShelfViewIconObserverTest, MAYBE_AddRemoveWithMultipleDisplays) {
   UpdateDisplay("400x400,400x400");
-  TestLauncherIconObserver second_observer(LauncherForSecondaryDisplay());
+  TestShelfIconObserver second_observer(LauncherForSecondaryDisplay());
 
   ash::test::TestLauncherDelegate* launcher_delegate =
       ash::test::TestLauncherDelegate::instance();
@@ -1062,13 +1062,13 @@
 
 // Confirm that launcher item bounds are correctly updated on shelf changes.
 TEST_F(ShelfViewTest, LauncherItemBoundsCheck) {
-  internal::ShelfLayoutManager* shelf_layout_manager =
-      Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
   VerifyLauncherItemBoundsAreValid();
-  shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
+      SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   test_api_->RunMessageLoopUntilAnimationsDone();
   VerifyLauncherItemBoundsAreValid();
-  shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
+  shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
+      SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
   test_api_->RunMessageLoopUntilAnimationsDone();
   VerifyLauncherItemBoundsAreValid();
 }
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc
index 6004a6c..010db18 100644
--- a/ash/shelf/shelf_widget_unittest.cc
+++ b/ash/shelf/shelf_widget_unittest.cc
@@ -54,7 +54,7 @@
   EXPECT_FALSE(shelf_widget->CanActivate());
 }
 
-void TestLauncherAlignment(aura::RootWindow* root,
+void TestLauncherAlignment(aura::Window* root,
                            ShelfAlignment alignment,
                            const std::string& expected) {
   Shell::GetInstance()->SetShelfAlignment(alignment, root);
diff --git a/ash/shell.cc b/ash/shell.cc
index 6e25c52..e97959e 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -33,14 +33,15 @@
 #include "ash/launcher/launcher_item_delegate.h"
 #include "ash/launcher/launcher_item_delegate_manager.h"
 #include "ash/launcher/launcher_model.h"
+#include "ash/launcher/launcher_model_util.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/magnifier/partial_magnification_controller.h"
+#include "ash/new_window_delegate.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_ash.h"
 #include "ash/session_state_delegate.h"
 #include "ash/shelf/app_list_shelf_item_delegate.h"
 #include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_util.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell_delegate.h"
 #include "ash/shell_factory.h"
@@ -95,6 +96,7 @@
 #include "ui/gfx/size.h"
 #include "ui/keyboard/keyboard.h"
 #include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_switches.h"
 #include "ui/keyboard/keyboard_util.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/corewm/compound_event_filter.h"
@@ -201,12 +203,12 @@
 }
 
 // static
-aura::RootWindow* Shell::GetPrimaryRootWindow() {
+aura::Window* Shell::GetPrimaryRootWindow() {
   return GetInstance()->display_controller()->GetPrimaryRootWindow();
 }
 
 // static
-aura::RootWindow* Shell::GetTargetRootWindow() {
+aura::Window* Shell::GetTargetRootWindow() {
   Shell* shell = GetInstance();
   if (shell->scoped_target_root_window_)
     return shell->scoped_target_root_window_;
@@ -225,13 +227,13 @@
 }
 
 // static
-aura::Window* Shell::GetContainer(aura::RootWindow* root_window,
+aura::Window* Shell::GetContainer(aura::Window* root_window,
                                   int container_id) {
   return root_window->GetChildById(container_id);
 }
 
 // static
-const aura::Window* Shell::GetContainer(const aura::RootWindow* root_window,
+const aura::Window* Shell::GetContainer(const aura::Window* root_window,
                                         int container_id) {
   return root_window->GetChildById(container_id);
 }
@@ -239,7 +241,7 @@
 // static
 std::vector<aura::Window*> Shell::GetContainersFromAllRootWindows(
     int container_id,
-    aura::RootWindow* priority_root) {
+    aura::Window* priority_root) {
   std::vector<aura::Window*> containers;
   RootWindowList root_windows = GetAllRootWindows();
   for (RootWindowList::const_iterator it = root_windows.begin();
@@ -264,7 +266,7 @@
   if (session_state_delegate_->IsScreenLocked())
     return;
 
-  aura::RootWindow* root =
+  aura::Window* root =
       wm::GetRootWindowMatching(gfx::Rect(location_in_screen, gfx::Size()));
   internal::GetRootWindowController(root)->
       ShowContextMenu(location_in_screen, source_type);
@@ -337,6 +339,8 @@
     // TODO(bshe): Primary root window controller may not be the controller to
     // attach virtual keyboard. See http://crbug.com/303429
     InitKeyboard(GetPrimaryRootWindowController());
+    GetPrimaryRootWindowController()->ActivateKeyboard(
+        keyboard_controller_.get());
   }
   FOR_EACH_OBSERVER(ShellObserver, observers_, OnLoginStateChanged(status));
 }
@@ -399,19 +403,19 @@
 }
 
 void Shell::SetShelfAutoHideBehavior(ShelfAutoHideBehavior behavior,
-                                     aura::RootWindow* root_window) {
+                                     aura::Window* root_window) {
   ash::internal::ShelfLayoutManager::ForLauncher(root_window)->
       SetAutoHideBehavior(behavior);
 }
 
 ShelfAutoHideBehavior Shell::GetShelfAutoHideBehavior(
-    aura::RootWindow* root_window) const {
+    aura::Window* root_window) const {
   return ash::internal::ShelfLayoutManager::ForLauncher(root_window)->
       auto_hide_behavior();
 }
 
 void Shell::SetShelfAlignment(ShelfAlignment alignment,
-                              aura::RootWindow* root_window) {
+                              aura::Window* root_window) {
   if (ash::internal::ShelfLayoutManager::ForLauncher(root_window)->
       SetAlignment(alignment)) {
     FOR_EACH_OBSERVER(
@@ -419,7 +423,7 @@
   }
 }
 
-ShelfAlignment Shell::GetShelfAlignment(aura::RootWindow* root_window) {
+ShelfAlignment Shell::GetShelfAlignment(aura::Window* root_window) {
   return internal::GetRootWindowController(root_window)->
       GetShelfLayoutManager()->GetAlignment();
 }
@@ -432,7 +436,7 @@
 }
 
 void Shell::NotifyFullscreenStateChange(bool is_fullscreen,
-                                        aura::RootWindow* root_window) {
+                                        aura::Window* root_window) {
   FOR_EACH_OBSERVER(ShellObserver, observers_, OnFullscreenStateChanged(
       is_fullscreen, root_window));
 }
@@ -491,16 +495,12 @@
     scoped_ptr<LauncherItemDelegate> controller(
         new internal::AppListShelfItemDelegate);
 
-    ash::LauncherID app_list_id = 0;
-    // TODO(simon.hong81): Make function for this in shelf_util.h
     // Finding the launcher model's location of the app list and setting its
     // LauncherItemDelegate.
-    for (size_t i = 0; i < launcher_model_->items().size(); ++i) {
-      if (launcher_model_->items()[i].type == ash::TYPE_APP_LIST) {
-        app_list_id = launcher_model_->items()[i].id;
-        break;
-      }
-    }
+    int app_list_index =
+        ash::GetLauncherItemIndexForType(ash::TYPE_APP_LIST, *launcher_model_);
+    DCHECK_GE(app_list_index, 0);
+    ash::LauncherID app_list_id = launcher_model_->items()[app_list_index].id;
     DCHECK(app_list_id);
     launcher_item_delegate_manager_->SetLauncherItemDelegate(
         app_list_id,
@@ -664,6 +664,7 @@
   screen_position_controller_.reset();
 
   keyboard_controller_.reset();
+  accessibility_delegate_.reset();
 
 #if defined(OS_CHROMEOS) && defined(USE_X11)
    if (display_change_observer_)
@@ -695,6 +696,10 @@
   output_configurator_animation_.reset(
       new internal::OutputConfiguratorAnimation());
   output_configurator_->AddObserver(output_configurator_animation_.get());
+  if (command_line->HasSwitch(keyboard::switches::kKeyboardUsabilityTest)) {
+    display_manager_->SetSecondDisplayMode(
+        internal::DisplayManager::VIRTUAL_KEYBOARD);
+  }
   if (base::SysInfo::IsRunningOnChromeOS()) {
     display_change_observer_.reset(new internal::DisplayChangeObserver);
     // Register |display_change_observer_| first so that the rest of
@@ -703,8 +708,7 @@
     display_error_observer_.reset(new internal::DisplayErrorObserver());
     output_configurator_->AddObserver(display_error_observer_.get());
     output_configurator_->set_state_controller(display_change_observer_.get());
-    if (!command_line->HasSwitch(ash::switches::kAshDisableSoftwareMirroring))
-      output_configurator_->set_mirroring_controller(display_manager_.get());
+    output_configurator_->set_mirroring_controller(display_manager_.get());
     output_configurator_->Start(
         delegate_->IsFirstRunAfterBoot() ? kChromeOsBootColor : 0);
     display_initialized = true;
@@ -745,7 +749,7 @@
 
   display_controller_->Start();
   display_controller_->InitPrimaryDisplay();
-  aura::RootWindow* root_window = display_controller_->GetPrimaryRootWindow();
+  aura::Window* root_window = display_controller_->GetPrimaryRootWindow();
   target_root_window_ = root_window;
 
   resolution_notification_controller_.reset(
@@ -770,7 +774,7 @@
   AddShellObserver(overlay_filter_.get());
 
   input_method_filter_.reset(new views::corewm::InputMethodEventFilter(
-                                 root_window->GetAcceleratedWidget()));
+      root_window->GetDispatcher()->GetAcceleratedWidget()));
   AddPreTargetHandler(input_method_filter_.get());
 
   accelerator_filter_.reset(new internal::AcceleratorFilter);
@@ -835,6 +839,8 @@
   caps_lock_delegate_.reset(delegate_->CreateCapsLockDelegate());
 
   session_state_delegate_.reset(delegate_->CreateSessionStateDelegate());
+  accessibility_delegate_.reset(delegate_->CreateAccessibilityDelegate());
+  new_window_delegate_.reset(delegate_->CreateNewWindowDelegate());
 
   if (!command_line->HasSwitch(views::corewm::switches::kNoDropShadows)) {
     resize_shadow_controller_.reset(new internal::ResizeShadowController());
@@ -858,7 +864,8 @@
   // TODO(oshima): Initialize all RootWindowControllers once, and
   // initialize controller/delegates above when initializing the
   // primary root window controller.
-  internal::RootWindowController::CreateForPrimaryDisplay(root_window);
+  internal::RootWindowController::CreateForPrimaryDisplay(
+      root_window->GetDispatcher());
 
   display_controller_->InitSecondaryDisplays();
 
@@ -892,13 +899,16 @@
       new internal::VideoActivityNotifier(video_detector_.get()));
 #endif
 
+  weak_display_manager_factory_.reset(
+      new base::WeakPtrFactory<internal::DisplayManager>(
+          display_manager_.get()));
   // The compositor thread and main message loop have to be running in
   // order to create mirror window. Run it after the main message loop
   // is started.
   base::MessageLoopForUI::current()->PostTask(
       FROM_HERE,
       base::Bind(&internal::DisplayManager::CreateMirrorWindowIfAny,
-                 base::Unretained(display_manager_.get())));
+                 weak_display_manager_factory_->GetWeakPtr()));
 }
 
 void Shell::InitKeyboard(internal::RootWindowController* root) {
@@ -914,7 +924,6 @@
         delegate_->CreateKeyboardControllerProxy();
     keyboard_controller_.reset(
         new keyboard::KeyboardController(proxy));
-    root->ActivateKeyboard(keyboard_controller_.get());
   }
 }
 
diff --git a/ash/shell.h b/ash/shell.h
index af884f4..62379ac 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -16,6 +16,7 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "ui/aura/client/activation_change_observer.h"
 #include "ui/base/ui_base_types.h"
@@ -76,6 +77,7 @@
 namespace ash {
 
 class AcceleratorController;
+class AccessibilityDelegate;
 class AshNativeCursorManager;
 class AutoclickController;
 class CapsLockDelegate;
@@ -88,14 +90,15 @@
 class LauncherItemDelegate;
 class LauncherItemDelegateManager;
 class LauncherModel;
+class LockStateController;
 class MagnificationController;
 class MruWindowTracker;
 class NestedDispatcherController;
+class NewWindowDelegate;
 class PartialMagnificationController;
 class PowerButtonController;
 class RootWindowHostFactory;
 class ScreenAsh;
-class LockStateController;
 class SessionStateDelegate;
 class ShellDelegate;
 class ShellObserver;
@@ -189,16 +192,16 @@
   // TODO(oshima): move this to |RootWindowController|
   static RootWindowControllerList GetAllRootWindowControllers();
 
-  // Returns the primary RootWindow. The primary RootWindow is the one
-  // that has a launcher.
-  static aura::RootWindow* GetPrimaryRootWindow();
+  // Returns the primary root Window. The primary root Window is the one that
+  // has a launcher.
+  static aura::Window* GetPrimaryRootWindow();
 
-  // Returns a RootWindow when used as a target when creating a new window.
+  // Returns a root Window when used as a target when creating a new window.
   // The root window of the active window is used in most cases, but can
   // be overridden by using ScopedTargetRootWindow().
-  // If you want to get a RootWindow of the active window, just use
+  // If you want to get the root Window of the active window, just use
   // |wm::GetActiveWindow()->GetRootWindow()|.
-  static aura::RootWindow* GetTargetRootWindow();
+  static aura::Window* GetTargetRootWindow();
 
   // Returns the global Screen object that's always active in ash.
   static gfx::Screen* GetScreen();
@@ -206,9 +209,9 @@
   // Returns all root windows.
   static RootWindowList GetAllRootWindows();
 
-  static aura::Window* GetContainer(aura::RootWindow* root_window,
+  static aura::Window* GetContainer(aura::Window* root_window,
                                     int container_id);
-  static const aura::Window* GetContainer(const aura::RootWindow* root_window,
+  static const aura::Window* GetContainer(const aura::Window* root_window,
                                           int container_id);
 
   // Returns the list of containers that match |container_id| in
@@ -216,9 +219,9 @@
   // in the |priority_root| will be inserted at the top of the list.
   static std::vector<aura::Window*> GetContainersFromAllRootWindows(
       int container_id,
-      aura::RootWindow* priority_root);
+      aura::Window* priority_root);
 
-  void set_target_root_window(aura::RootWindow* target_root_window) {
+  void set_target_root_window(aura::Window* target_root_window) {
     target_root_window_ = target_root_window;
   }
 
@@ -366,6 +369,14 @@
     return session_state_delegate_.get();
   }
 
+  AccessibilityDelegate* accessibility_delegate() {
+    return accessibility_delegate_.get();
+  }
+
+  NewWindowDelegate* new_window_delegate() {
+    return new_window_delegate_.get();
+  }
+
   HighContrastController* high_contrast_controller() {
     return high_contrast_controller_.get();
   }
@@ -400,14 +411,14 @@
 
   // Sets/gets the shelf auto-hide behavior on |root_window|.
   void SetShelfAutoHideBehavior(ShelfAutoHideBehavior behavior,
-                                aura::RootWindow* root_window);
+                                aura::Window* root_window);
   ShelfAutoHideBehavior GetShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const;
+      aura::Window* root_window) const;
 
   // Sets/gets shelf's alignment on |root_window|.
   void SetShelfAlignment(ShelfAlignment alignment,
-                         aura::RootWindow* root_window);
-  ShelfAlignment GetShelfAlignment(aura::RootWindow* root_window);
+                         aura::Window* root_window);
+  ShelfAlignment GetShelfAlignment(aura::Window* root_window);
 
   // Dims or undims the screen.
   void SetDimming(bool should_dim);
@@ -415,7 +426,7 @@
   // Notifies |observers_| when entering or exiting fullscreen mode in
   // |root_window|.
   void NotifyFullscreenStateChange(bool is_fullscreen,
-                                   aura::RootWindow* root_window);
+                                   aura::Window* root_window);
 
   // Creates a modal background (a partially-opaque fullscreen window)
   // on all displays for |window|.
@@ -556,8 +567,8 @@
   // created on |scoped_target_root_window_| , unless NULL in
   // which case they are created on |target_root_window_|.
   // |target_root_window_| never becomes NULL during the session.
-  aura::RootWindow* target_root_window_;
-  aura::RootWindow* scoped_target_root_window_;
+  aura::Window* target_root_window_;
+  aura::Window* scoped_target_root_window_;
 
   // The CompoundEventFilter owned by aura::Env object.
   scoped_ptr<views::corewm::CompoundEventFilter> env_filter_;
@@ -573,6 +584,8 @@
   scoped_ptr<UserWallpaperDelegate> user_wallpaper_delegate_;
   scoped_ptr<CapsLockDelegate> caps_lock_delegate_;
   scoped_ptr<SessionStateDelegate> session_state_delegate_;
+  scoped_ptr<AccessibilityDelegate> accessibility_delegate_;
+  scoped_ptr<NewWindowDelegate> new_window_delegate_;
   scoped_ptr<LauncherDelegate> launcher_delegate_;
   scoped_ptr<LauncherItemDelegateManager> launcher_item_delegate_manager_;
 
@@ -633,6 +646,8 @@
   scoped_ptr<views::corewm::InputMethodEventFilter> input_method_filter_;
 
   scoped_ptr<internal::DisplayManager> display_manager_;
+  scoped_ptr<base::WeakPtrFactory<internal::DisplayManager> >
+      weak_display_manager_factory_;
 
   scoped_ptr<internal::LocaleNotificationController>
       locale_notification_controller_;
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 7448de4..fe62d21 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/app_list/app_list_item_list.h"
 #include "ui/app_list/app_list_item_model.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_view_delegate.h"
@@ -195,14 +196,14 @@
   ExampleAppListViewDelegate() : model_(NULL) {}
 
  private:
-  void PopulateApps(app_list::AppListModel::Apps* apps) {
+  void PopulateApps(app_list::AppListItemList* item_list) {
     for (int i = 0;
          i < static_cast<int>(WindowTypeLauncherItem::LAST_TYPE);
          ++i) {
       WindowTypeLauncherItem::Type type =
           static_cast<WindowTypeLauncherItem::Type>(i);
       std::string id = base::StringPrintf("%d", i);
-      apps->Add(new WindowTypeLauncherItem(id, type));
+      item_list->AddItem(new WindowTypeLauncherItem(id, type));
     }
   }
 
@@ -233,7 +234,7 @@
 
   virtual void InitModel(app_list::AppListModel* model) OVERRIDE {
     model_ = model;
-    PopulateApps(model_->apps());
+    PopulateApps(model_->item_list());
     DecorateSearchBox(model_->search_box());
   }
 
diff --git a/ash/shell/content_client/shell_browser_main_parts.cc b/ash/shell/content_client/shell_browser_main_parts.cc
index 46575ae..71e6ca4 100644
--- a/ash/shell/content_client/shell_browser_main_parts.cc
+++ b/ash/shell/content_client/shell_browser_main_parts.cc
@@ -21,7 +21,6 @@
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_net_log.h"
 #include "net/base/net_module.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
@@ -135,7 +134,7 @@
   Shell::GetInstance()->desktop_background_controller()->SetDefaultWallpaper(
       false /* is_guest */);
 
-  ash::Shell::GetPrimaryRootWindow()->ShowRootWindow();
+  ash::Shell::GetPrimaryRootWindow()->GetDispatcher()->ShowRootWindow();
 }
 
 void ShellBrowserMainParts::PostMainMessageLoopRun() {
diff --git a/ash/shell/context_menu.cc b/ash/shell/context_menu.cc
index e1a62d1..19ad408 100644
--- a/ash/shell/context_menu.cc
+++ b/ash/shell/context_menu.cc
@@ -14,7 +14,7 @@
 namespace ash {
 namespace shell {
 
-ContextMenu::ContextMenu(aura::RootWindow* root)
+ContextMenu::ContextMenu(aura::Window* root)
     : ui::SimpleMenuModel(NULL),
       root_window_(root),
       alignment_menu_(root) {
diff --git a/ash/shell/context_menu.h b/ash/shell/context_menu.h
index a07310e..32421ca 100644
--- a/ash/shell/context_menu.h
+++ b/ash/shell/context_menu.h
@@ -21,7 +21,7 @@
 class ContextMenu : public ui::SimpleMenuModel,
                     public ui::SimpleMenuModel::Delegate {
  public:
-  explicit ContextMenu(aura::RootWindow* root);
+  explicit ContextMenu(aura::Window* root);
   virtual ~ContextMenu();
 
   // ui::SimpleMenuModel::Delegate overrides:
@@ -38,7 +38,7 @@
     MENU_ALIGNMENT_MENU,
   };
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   ShelfAlignmentMenu alignment_menu_;
 
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 6d65f8b..e1ca903 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -4,12 +4,13 @@
 
 #include "ash/shell/shell_delegate_impl.h"
 
-#include <limits>
-
+#include "ash/accessibility_delegate.h"
 #include "ash/caps_lock_delegate_stub.h"
+#include "ash/default_accessibility_delegate.h"
 #include "ash/default_user_wallpaper_delegate.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/keyboard_controller_proxy_stub.h"
+#include "ash/new_window_delegate.h"
 #include "ash/session_state_delegate.h"
 #include "ash/session_state_delegate_stub.h"
 #include "ash/shell/context_menu.h"
@@ -25,15 +26,36 @@
 
 namespace ash {
 namespace shell {
+namespace {
+
+class NewWindowDelegateImpl : public NewWindowDelegate {
+ public:
+  NewWindowDelegateImpl() {}
+  virtual ~NewWindowDelegateImpl() {}
+
+  virtual void NewTab() OVERRIDE {}
+  virtual void NewWindow(bool incognito) OVERRIDE {
+    ash::shell::ToplevelWindow::CreateParams create_params;
+    create_params.can_resize = true;
+    create_params.can_maximize = true;
+    ash::shell::ToplevelWindow::CreateToplevelWindow(create_params);
+  }
+  virtual void OpenFileManager() OVERRIDE {}
+  virtual void OpenCrosh() OVERRIDE {}
+  virtual void RestoreTab() OVERRIDE {}
+  virtual void ShowKeyboardOverlay() OVERRIDE {}
+  virtual void ShowTaskManager() OVERRIDE {}
+  virtual void OpenFeedbackPage() OVERRIDE {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NewWindowDelegateImpl);
+};
+
+}  // namespace
 
 ShellDelegateImpl::ShellDelegateImpl()
     : watcher_(NULL),
-      launcher_delegate_(NULL),
-      spoken_feedback_enabled_(false),
-      high_contrast_enabled_(false),
-      screen_magnifier_enabled_(false),
-      screen_magnifier_type_(kDefaultMagnifierType),
-      large_cursor_enabled_(false) {
+      launcher_delegate_(NULL) {
 }
 
 ShellDelegateImpl::~ShellDelegateImpl() {
@@ -67,95 +89,15 @@
   base::MessageLoopForUI::current()->Quit();
 }
 
-void ShellDelegateImpl::NewTab() {
-}
-
-void ShellDelegateImpl::NewWindow(bool incognito) {
-  ash::shell::ToplevelWindow::CreateParams create_params;
-  create_params.can_resize = true;
-  create_params.can_maximize = true;
-  ash::shell::ToplevelWindow::CreateToplevelWindow(create_params);
-}
-
-void ShellDelegateImpl::ToggleFullscreen() {
-  // TODO(oshima): Remove this when crbug.com/309837 is implemented.
-  wm::WindowState* window_state = wm::GetActiveWindowState();
-  if (window_state)
-    window_state->ToggleMaximized();
-}
-
-void ShellDelegateImpl::OpenFileManager() {
-}
-
-void ShellDelegateImpl::OpenCrosh() {
-}
-
-void ShellDelegateImpl::RestoreTab() {
-}
-
-void ShellDelegateImpl::ShowKeyboardOverlay() {
-}
-
 keyboard::KeyboardControllerProxy*
     ShellDelegateImpl::CreateKeyboardControllerProxy() {
   return new KeyboardControllerProxyStub();
 }
 
-void ShellDelegateImpl::ShowTaskManager() {
-}
-
 content::BrowserContext* ShellDelegateImpl::GetCurrentBrowserContext() {
   return Shell::GetInstance()->browser_context();
 }
 
-void ShellDelegateImpl::ToggleSpokenFeedback(
-    AccessibilityNotificationVisibility notify) {
-  spoken_feedback_enabled_ = !spoken_feedback_enabled_;
-}
-
-bool ShellDelegateImpl::IsSpokenFeedbackEnabled() const {
-  return spoken_feedback_enabled_;
-}
-
-void ShellDelegateImpl::ToggleHighContrast() {
-  high_contrast_enabled_ = !high_contrast_enabled_;
-}
-
-bool ShellDelegateImpl::IsHighContrastEnabled() const {
-  return high_contrast_enabled_;
-}
-
-void ShellDelegateImpl::SetMagnifierEnabled(bool enabled) {
-  screen_magnifier_enabled_ = enabled;
-}
-
-void ShellDelegateImpl::SetMagnifierType(MagnifierType type) {
-  screen_magnifier_type_ = type;
-}
-
-bool ShellDelegateImpl::IsMagnifierEnabled() const {
-  return screen_magnifier_enabled_;
-}
-
-MagnifierType ShellDelegateImpl::GetMagnifierType() const {
-  return screen_magnifier_type_;
-}
-
-void ShellDelegateImpl::SetLargeCursorEnabled(bool enabled) {
-  large_cursor_enabled_ = enabled;
-}
-
-bool ShellDelegateImpl::IsLargeCursorEnabled() const {
-  return large_cursor_enabled_;
-}
-
-bool ShellDelegateImpl::ShouldAlwaysShowAccessibilityMenu() const {
-  return false;
-}
-
-void ShellDelegateImpl::SilenceSpokenFeedback() const {
-}
-
 app_list::AppListViewDelegate* ShellDelegateImpl::CreateAppListViewDelegate() {
   return ash::shell::CreateAppListViewDelegate();
 }
@@ -182,11 +124,16 @@
   return new SessionStateDelegateStub;
 }
 
-aura::client::UserActionClient* ShellDelegateImpl::CreateUserActionClient() {
-  return NULL;
+ash::AccessibilityDelegate* ShellDelegateImpl::CreateAccessibilityDelegate() {
+  return new internal::DefaultAccessibilityDelegate;
 }
 
-void ShellDelegateImpl::OpenFeedbackPage() {
+ash::NewWindowDelegate* ShellDelegateImpl::CreateNewWindowDelegate() {
+  return new NewWindowDelegateImpl;
+}
+
+aura::client::UserActionClient* ShellDelegateImpl::CreateUserActionClient() {
+  return NULL;
 }
 
 void ShellDelegateImpl::RecordUserMetricsAction(UserMetricsAction action) {
@@ -201,14 +148,7 @@
 void ShellDelegateImpl::HandleMediaPrevTrack() {
 }
 
-void ShellDelegateImpl::SaveScreenMagnifierScale(double scale) {
-}
-
-double ShellDelegateImpl::GetSavedScreenMagnifierScale() {
-  return std::numeric_limits<double>::min();
-}
-
-ui::MenuModel* ShellDelegateImpl::CreateContextMenu(aura::RootWindow* root) {
+ui::MenuModel* ShellDelegateImpl::CreateContextMenu(aura::Window* root) {
   return new ContextMenu(root);
 }
 
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 4d4abe9..647331e 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -33,30 +33,9 @@
   virtual void PreInit() OVERRIDE;
   virtual void Shutdown() OVERRIDE;
   virtual void Exit() OVERRIDE;
-  virtual void NewTab() OVERRIDE;
-  virtual void NewWindow(bool incognito) OVERRIDE;
-  virtual void ToggleFullscreen() OVERRIDE;
-  virtual void OpenFileManager() OVERRIDE;
-  virtual void OpenCrosh() OVERRIDE;
-  virtual void RestoreTab() OVERRIDE;
-  virtual void ShowKeyboardOverlay() OVERRIDE;
   virtual keyboard::KeyboardControllerProxy*
       CreateKeyboardControllerProxy() OVERRIDE;
-  virtual void ShowTaskManager() OVERRIDE;
   virtual content::BrowserContext* GetCurrentBrowserContext() OVERRIDE;
-  virtual void ToggleSpokenFeedback(
-      AccessibilityNotificationVisibility notify) OVERRIDE;
-  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE;
-  virtual void ToggleHighContrast() OVERRIDE;
-  virtual bool IsHighContrastEnabled() const OVERRIDE;
-  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE;
-  virtual void SetMagnifierType(MagnifierType type) OVERRIDE;
-  virtual bool IsMagnifierEnabled() const OVERRIDE;
-  virtual MagnifierType GetMagnifierType() const OVERRIDE;
-  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE;
-  virtual bool IsLargeCursorEnabled() const OVERRIDE;
-  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE;
-  virtual void SilenceSpokenFeedback() const OVERRIDE;
   virtual app_list::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
   virtual ash::LauncherDelegate* CreateLauncherDelegate(
       ash::LauncherModel* model) OVERRIDE;
@@ -64,16 +43,15 @@
   virtual ash::UserWallpaperDelegate* CreateUserWallpaperDelegate() OVERRIDE;
   virtual ash::CapsLockDelegate* CreateCapsLockDelegate() OVERRIDE;
   virtual ash::SessionStateDelegate* CreateSessionStateDelegate() OVERRIDE;
+  virtual ash::AccessibilityDelegate* CreateAccessibilityDelegate() OVERRIDE;
+  virtual ash::NewWindowDelegate* CreateNewWindowDelegate() OVERRIDE;
   virtual aura::client::UserActionClient* CreateUserActionClient() OVERRIDE;
-  virtual void OpenFeedbackPage() OVERRIDE;
   virtual void RecordUserMetricsAction(UserMetricsAction action) OVERRIDE;
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
-  virtual double GetSavedScreenMagnifierScale() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual RootWindowHostFactory* CreateRootWindowHostFactory() OVERRIDE;
   virtual base::string16 GetProductName() const OVERRIDE;
 
@@ -83,12 +61,6 @@
 
   LauncherDelegateImpl* launcher_delegate_;
 
-  bool spoken_feedback_enabled_;
-  bool high_contrast_enabled_;
-  bool screen_magnifier_enabled_;
-  MagnifierType screen_magnifier_type_;
-  bool large_cursor_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(ShellDelegateImpl);
 };
 
diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc
index fbea77e..b12a37c 100644
--- a/ash/shell/toplevel_window.cc
+++ b/ash/shell/toplevel_window.cc
@@ -36,13 +36,21 @@
 }
 
 // static
-void ToplevelWindow::CreateToplevelWindow(const CreateParams& params) {
+views::Widget* ToplevelWindow::CreateToplevelWindow(
+    const CreateParams& params) {
   views::Widget* widget = views::Widget::CreateWindowWithContext(
       new ToplevelWindow(params), Shell::GetPrimaryRootWindow());
   widget->GetNativeView()->SetName("Examples:ToplevelWindow");
   wm::WindowState* window_state = wm::GetWindowState(widget->GetNativeView());
   window_state->set_window_position_managed(true);
   widget->Show();
+  return widget;
+}
+
+// static
+void ToplevelWindow::ClearSavedStateForTest() {
+  delete saved_state;
+  saved_state = NULL;
 }
 
 ToplevelWindow::ToplevelWindow(const CreateParams& params) : params_(params) {
diff --git a/ash/shell/toplevel_window.h b/ash/shell/toplevel_window.h
index 77b29aa..71bbfa2 100644
--- a/ash/shell/toplevel_window.h
+++ b/ash/shell/toplevel_window.h
@@ -18,7 +18,12 @@
     bool can_resize;
     bool can_maximize;
   };
-  static void CreateToplevelWindow(const CreateParams& params);
+  static views::Widget* CreateToplevelWindow(
+      const CreateParams& params);
+
+  // Clears saved show state and bounds used to position
+  // a new window.
+  static void ClearSavedStateForTest();
 
  private:
   explicit ToplevelWindow(const CreateParams& params);
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc
index 7c72e27..302a523 100644
--- a/ash/shell/window_watcher.cc
+++ b/ash/shell/window_watcher.cc
@@ -36,7 +36,7 @@
     window->RemoveObserver(watcher_);
   }
 
-  void RootWindowAdded(aura::RootWindow* root) {
+  void RootWindowAdded(aura::Window* root) {
     aura::Window* panel_container = ash::Shell::GetContainer(
         root,
         internal::kShellWindowId_PanelContainer);
@@ -150,7 +150,7 @@
 }
 
 void WindowWatcher::OnDisplayAdded(const gfx::Display& new_display) {
-  aura::RootWindow* root = Shell::GetInstance()->display_controller()->
+  aura::Window* root = Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(new_display.id());
   workspace_window_watcher_->RootWindowAdded(root);
 }
diff --git a/ash/shell/window_watcher_launcher_item_delegate.cc b/ash/shell/window_watcher_launcher_item_delegate.cc
index 553b9fc..e755a6e 100644
--- a/ash/shell/window_watcher_launcher_item_delegate.cc
+++ b/ash/shell/window_watcher_launcher_item_delegate.cc
@@ -36,7 +36,7 @@
 }
 
 ui::MenuModel* WindowWatcherLauncherItemDelegate::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   return NULL;
 }
 
diff --git a/ash/shell/window_watcher_launcher_item_delegate.h b/ash/shell/window_watcher_launcher_item_delegate.h
index e7d0b22..53014b6 100644
--- a/ash/shell/window_watcher_launcher_item_delegate.h
+++ b/ash/shell/window_watcher_launcher_item_delegate.h
@@ -25,7 +25,7 @@
   virtual void ItemSelected(const ui::Event& event) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
diff --git a/ash/shell/window_watcher_unittest.cc b/ash/shell/window_watcher_unittest.cc
index 71a2f87..4d470ae 100644
--- a/ash/shell/window_watcher_unittest.cc
+++ b/ash/shell/window_watcher_unittest.cc
@@ -24,7 +24,7 @@
 
   shell::ShellDelegateImpl* delegate = new ash::shell::ShellDelegateImpl;
   Shell::CreateInstance(delegate);
-  Shell::GetPrimaryRootWindow()->ShowRootWindow();
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->ShowRootWindow();
   Shell::GetInstance()->CreateLauncher();
   Shell::GetInstance()->UpdateAfterLoginStatusChange(
       user::LOGGED_IN_USER);
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 02fea7f..1023689 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "ash/ash_export.h"
-#include "ash/magnifier/magnifier_constants.h"
 #include "ash/shell.h"
 #include "base/callback.h"
 #include "base/strings/string16.h"
@@ -43,7 +42,9 @@
 class LauncherDelegate;
 class LauncherModel;
 struct LauncherItem;
+class NewWindowDelegate;
 class RootWindowHostFactory;
+class AccessibilityDelegate;
 class SessionStateDelegate;
 class SystemTrayDelegate;
 class UserWallpaperDelegate;
@@ -101,11 +102,6 @@
   UMA_WINDOW_SELECTION,
 };
 
-enum AccessibilityNotificationVisibility {
-  A11Y_NOTIFICATION_NONE,
-  A11Y_NOTIFICATION_SHOW,
-};
-
 // Delegate of the Shell.
 class ASH_EXPORT ShellDelegate {
  public:
@@ -133,75 +129,13 @@
   // Invoked when the user uses Ctrl-Shift-Q to close chrome.
   virtual void Exit() = 0;
 
-  // Invoked when the user uses Ctrl+T to open a new tab.
-  virtual void NewTab() = 0;
-
-  // Invoked when the user uses Ctrl-N or Ctrl-Shift-N to open a new window.
-  virtual void NewWindow(bool incognito) = 0;
-
-  // Invoked when the user uses Shift+F4 to toggle the window fullscreen state.
-  virtual void ToggleFullscreen() = 0;
-
-  // Invoked when an accelerator is used to open the file manager.
-  virtual void OpenFileManager() = 0;
-
-  // Invoked when the user opens Crosh.
-  virtual void OpenCrosh() = 0;
-
-  // Invoked when the user uses Shift+Ctrl+T to restore the closed tab.
-  virtual void RestoreTab() = 0;
-
-  // Shows the keyboard shortcut overlay.
-  virtual void ShowKeyboardOverlay() = 0;
-
   // Create a shell-specific keyboard::KeyboardControllerProxy
   virtual keyboard::KeyboardControllerProxy*
       CreateKeyboardControllerProxy() = 0;
 
-  // Shows the task manager window.
-  virtual void ShowTaskManager() = 0;
-
   // Get the current browser context. This will get us the current profile.
   virtual content::BrowserContext* GetCurrentBrowserContext() = 0;
 
-  // Invoked to toggle spoken feedback for accessibility
-  virtual void ToggleSpokenFeedback(
-      AccessibilityNotificationVisibility notify) = 0;
-
-  // Returns true if spoken feedback is enabled.
-  virtual bool IsSpokenFeedbackEnabled() const = 0;
-
-  // Invoked to toggle high contrast for accessibility.
-  virtual void ToggleHighContrast() = 0;
-
-  // Returns true if high contrast mode is enabled.
-  virtual bool IsHighContrastEnabled() const = 0;
-
-  // Invoked to enable the screen magnifier.
-  virtual void SetMagnifierEnabled(bool enabled) = 0;
-
-  // Invoked to change the type of the screen magnifier.
-  virtual void SetMagnifierType(MagnifierType type) = 0;
-
-  // Returns if the screen magnifier is enabled or not.
-  virtual bool IsMagnifierEnabled() const = 0;
-
-  // Returns the current screen magnifier mode.
-  virtual MagnifierType GetMagnifierType() const = 0;
-
-  // Invoked to enable Large Cursor.
-  virtual void SetLargeCursorEnabled(bool enabled) = 0;
-
-  // Returns if Large Cursor is enabled or not.
-  virtual bool IsLargeCursorEnabled() const = 0;
-
-  // Returns true if the user want to show accesibility menu even when all the
-  // accessibility features are disabled.
-  virtual bool ShouldAlwaysShowAccessibilityMenu() const = 0;
-
-  // Cancel all current and queued speech immediately.
-  virtual void SilenceSpokenFeedback() const = 0;
-
   // Invoked to create an AppListViewDelegate. Shell takes the ownership of
   // the created delegate.
   virtual app_list::AppListViewDelegate* CreateAppListViewDelegate() = 0;
@@ -223,12 +157,15 @@
   // Creates a session state delegate. Shell takes ownership of the delegate.
   virtual SessionStateDelegate* CreateSessionStateDelegate() = 0;
 
+  // Creates a accessibility delegate. Shell takes ownership of the delegate.
+  virtual AccessibilityDelegate* CreateAccessibilityDelegate() = 0;
+
+  // Creates an application delegate. Shell takes ownership of the delegate.
+  virtual NewWindowDelegate* CreateNewWindowDelegate() = 0;
+
   // Creates a user action client. Shell takes ownership of the object.
   virtual aura::client::UserActionClient* CreateUserActionClient() = 0;
 
-  // Opens the feedback page for "Report Issue".
-  virtual void OpenFeedbackPage() = 0;
-
   // Records that the user performed an action.
   virtual void RecordUserMetricsAction(UserMetricsAction action) = 0;
 
@@ -241,15 +178,8 @@
   // Handles the Previous Track Media shortcut key.
   virtual void HandleMediaPrevTrack() = 0;
 
-  // Saves the zoom scale of the full screen magnifier.
-  virtual void SaveScreenMagnifierScale(double scale) = 0;
-
-  // Gets a saved value of the zoom scale of full screen magnifier. If a value
-  // is not saved, return a negative value.
-  virtual double GetSavedScreenMagnifierScale() = 0;
-
   // Creates a menu model of the context for the |root_window|.
-  virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root_window) = 0;
+  virtual ui::MenuModel* CreateContextMenu(aura::Window* root_window) = 0;
 
   // Creates a root window host factory. Shell takes ownership of the returned
   // value.
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index b09229b..9d1db02 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -9,7 +9,7 @@
 #include "ash/system/user/login_status.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 }
 
 namespace ash {
@@ -30,14 +30,14 @@
   virtual void OnLockStateChanged(bool locked) {}
 
   // Invoked when the shelf alignment in |root_window| is changed.
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) {}
+  virtual void OnShelfAlignmentChanged(aura::Window* root_window) {}
 
   // Invoked when the projection touch HUD is toggled.
   virtual void OnTouchHudProjectionToggled(bool enabled) {}
 
   // Invoked when entering or exiting fullscreen mode in |root_window|.
   virtual void OnFullscreenStateChanged(bool is_fullscreen,
-                                        aura::RootWindow* root_window) {}
+                                        aura::Window* root_window) {}
 
  protected:
   virtual ~ShellObserver() {}
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index 79c64f9..309ebae 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -54,7 +54,7 @@
 
 // Expect ALL the containers!
 void ExpectAllContainers() {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   EXPECT_TRUE(Shell::GetContainer(
       root_window, internal::kShellWindowId_DesktopBackgroundContainer));
   EXPECT_TRUE(Shell::GetContainer(
@@ -397,8 +397,9 @@
   EXPECT_TRUE(launcher_widget->IsVisible());
   // Launcher is at bottom-left of screen.
   EXPECT_EQ(0, launcher_widget->GetWindowBoundsInScreen().x());
-  EXPECT_EQ(Shell::GetPrimaryRootWindow()->GetHostSize().height(),
-            launcher_widget->GetWindowBoundsInScreen().bottom());
+  EXPECT_EQ(
+      Shell::GetPrimaryRootWindow()->GetDispatcher()->GetHostSize().height(),
+      launcher_widget->GetWindowBoundsInScreen().bottom());
   // We have a desktop background but not a bare layer.
   // TODO (antrim): enable once we find out why it fails component build.
   //  internal::DesktopBackgroundWidgetController* background =
@@ -477,12 +478,12 @@
   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window.get());
+  ParentWindowInPrimaryRootWindow(window.get());
   window->Show();
   wm::ActivateWindow(window.get());
 
   Shell* shell = Shell::GetInstance();
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
                                   root_window);
   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
diff --git a/ash/shell_window_ids.h b/ash/shell_window_ids.h
index 1c1c396..ab5fd23 100644
--- a/ash/shell_window_ids.h
+++ b/ash/shell_window_ids.h
@@ -50,54 +50,57 @@
 // The container for windows docked to either side of the desktop.
 const int kShellWindowId_DockedContainer = 8;
 
-// The container for panel windows.
-const int kShellWindowId_PanelContainer = 9;
-
 // The container for the shelf.
-const int kShellWindowId_ShelfContainer = 10;
+const int kShellWindowId_ShelfContainer = 9;
+
+// The container for bubbles which float over the shelf.
+const int kShellWindowId_ShelfBubbleContainer = 10;
+
+// The container for panel windows.
+const int kShellWindowId_PanelContainer = 11;
 
 // The container for the app list.
-const int kShellWindowId_AppListContainer = 11;
+const int kShellWindowId_AppListContainer = 12;
 
 // The container for user-specific modal windows.
-const int kShellWindowId_SystemModalContainer = 12;
+const int kShellWindowId_SystemModalContainer = 13;
 
 // The container for input method components such like candidate windows.  They
 // are almost panels but have no activations/focus, and they should appear over
 // the AppList and SystemModal dialogs.
-const int kShellWindowId_InputMethodContainer = 13;
+const int kShellWindowId_InputMethodContainer = 14;
 
 // The container for the lock screen background.
-const int kShellWindowId_LockScreenBackgroundContainer = 14;
+const int kShellWindowId_LockScreenBackgroundContainer = 15;
 
 // The container for the lock screen.
-const int kShellWindowId_LockScreenContainer = 15;
+const int kShellWindowId_LockScreenContainer = 16;
 
 // The container for the lock screen modal windows.
-const int kShellWindowId_LockSystemModalContainer = 16;
+const int kShellWindowId_LockSystemModalContainer = 17;
 
 // The container for the status area.
-const int kShellWindowId_StatusContainer = 17;
+const int kShellWindowId_StatusContainer = 18;
 
 // The container for menus.
-const int kShellWindowId_MenuContainer = 18;
+const int kShellWindowId_MenuContainer = 19;
 
 // The container for drag/drop images and tooltips.
-const int kShellWindowId_DragImageAndTooltipContainer = 19;
+const int kShellWindowId_DragImageAndTooltipContainer = 20;
 
 // The container for bubbles briefly overlaid onscreen to show settings changes
 // (volume, brightness, etc.).
-const int kShellWindowId_SettingBubbleContainer = 20;
+const int kShellWindowId_SettingBubbleContainer = 21;
 
 // The container for special components overlaid onscreen, such as the
 // region selector for partial screenshots.
-const int kShellWindowId_OverlayContainer = 21;
+const int kShellWindowId_OverlayContainer = 22;
 
 // ID of the window created by PhantomWindowController or DragWindowController.
-const int kShellWindowId_PhantomWindow = 22;
+const int kShellWindowId_PhantomWindow = 23;
 
 // The topmost container, used for power off animation.
-const int kShellWindowId_PowerButtonAnimationContainer = 23;
+const int kShellWindowId_PowerButtonAnimationContainer = 24;
 
 }  // namespace internal
 
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index 5b0c52e..37912dd 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -98,7 +98,7 @@
 <translation id="3963445509666917109">স্পিকার (অভ্যন্তরীণ)</translation>
 <translation id="2825619548187458965">শেল্ফ</translation>
 <translation id="2614835198358683673">চালু থাকার সময় আপনার Chromebook চার্জ নাও হতে পারে৷ এটির নিজস্ব চার্জার ব্যবহার করার কথা বিবেচনা করুন৷</translation>
-<translation id="1895658205118569222">শাটডাউন</translation>
+<translation id="1895658205118569222">বন্ধ করুন</translation>
 <translation id="4430019312045809116">ভলিউম</translation>
 <translation id="8681498213689260554">আপডেট করার জন্য আবার শুরু করুন এবং পাওয়ারওয়াশ করুন</translation>
 <translation id="4442424173763614572">DNS খোঁজ ব্যর্থ হয়েছে</translation>
diff --git a/ash/strings/ash_strings_ru.xtb b/ash/strings/ash_strings_ru.xtb
index 7f6da93..e4e5b24 100644
--- a/ash/strings/ash_strings_ru.xtb
+++ b/ash/strings/ash_strings_ru.xtb
@@ -120,7 +120,7 @@
 <translation id="2372145515558759244">Синхронизация приложений…</translation>
 <translation id="7256405249507348194">Неопознанная ошибка: <ph name="DESC"/></translation>
 <translation id="7925247922861151263">Сбой при проверке AAA</translation>
-<translation id="8456362689280298700"><ph name="HOUR"/>:<ph name="MINUTE"/> до заполнения</translation>
+<translation id="8456362689280298700">до полной зарядки: <ph name="HOUR"/>:<ph name="MINUTE"/></translation>
 <translation id="5787281376604286451">Голосовое сопровождение включено. Чтобы отключить его, нажмите Ctrl + Alt + Z.</translation>
 <translation id="4479639480957787382">Ethernet</translation>
 <translation id="6312403991423642364">Неизвестная ошибка сети</translation>
diff --git a/ash/system/chromeos/enterprise/tray_enterprise.cc b/ash/system/chromeos/enterprise/tray_enterprise.cc
index 05ff799..8fca1c6 100644
--- a/ash/system/chromeos/enterprise/tray_enterprise.cc
+++ b/ash/system/chromeos/enterprise/tray_enterprise.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/chromeos/enterprise/tray_enterprise.h"
 
+#include "ash/shell.h"
 #include "ash/system/chromeos/label_tray_view.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/user/login_status.h"
@@ -57,4 +58,3 @@
 
 } // namespace internal
 } // namespace ash
-
diff --git a/ash/system/chromeos/managed/tray_locally_managed_user.cc b/ash/system/chromeos/managed/tray_locally_managed_user.cc
index 0f0ab4c..9a8fd48 100644
--- a/ash/system/chromeos/managed/tray_locally_managed_user.cc
+++ b/ash/system/chromeos/managed/tray_locally_managed_user.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/chromeos/managed/tray_locally_managed_user.h"
 
+#include "ash/shell.h"
 #include "ash/system/chromeos/label_tray_view.h"
 #include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray_notifier.h"
diff --git a/ash/system/chromeos/power/power_event_observer.cc b/ash/system/chromeos/power/power_event_observer.cc
index 2dc4a84..c99ae50 100644
--- a/ash/system/chromeos/power/power_event_observer.cc
+++ b/ash/system/chromeos/power/power_event_observer.cc
@@ -16,7 +16,8 @@
 namespace ash {
 namespace internal {
 
-PowerEventObserver::PowerEventObserver() {
+PowerEventObserver::PowerEventObserver()
+    : screen_locked_(false) {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
       AddObserver(this);
   chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
diff --git a/ash/system/chromeos/power/power_event_observer.h b/ash/system/chromeos/power/power_event_observer.h
index aeb89b9..b35cb1b 100644
--- a/ash/system/chromeos/power/power_event_observer.h
+++ b/ash/system/chromeos/power/power_event_observer.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_CHROMEOS_POWER_POWER_EVENT_OBSERVER_H_
 #define ASH_SYSTEM_CHROMEOS_POWER_POWER_EVENT_OBSERVER_H_
 
+#include "ash/ash_export.h"
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -15,8 +16,9 @@
 namespace internal {
 
 // A class that observes power-management-related events.
-class PowerEventObserver : public chromeos::PowerManagerClient::Observer,
-                           public chromeos::SessionManagerClient::Observer {
+class ASH_EXPORT PowerEventObserver
+    : public chromeos::PowerManagerClient::Observer,
+      public chromeos::SessionManagerClient::Observer {
  public:
   // This class registers/unregisters itself as an observer in ctor/dtor.
   PowerEventObserver();
diff --git a/ash/system/chromeos/power/power_event_observer_unittest.cc b/ash/system/chromeos/power/power_event_observer_unittest.cc
new file mode 100644
index 0000000..a2282c3
--- /dev/null
+++ b/ash/system/chromeos/power/power_event_observer_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2013 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 "ash/system/chromeos/power/power_event_observer.h"
+
+#include "ash/test/ash_test_base.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/power_manager_client.h"
+
+namespace ash {
+namespace internal {
+
+class PowerEventObserverTest : public test::AshTestBase {
+ public:
+  PowerEventObserverTest() {}
+  virtual ~PowerEventObserverTest() {}
+
+  // test::AshTestBase::SetUp() overrides:
+  virtual void SetUp() OVERRIDE {
+    test::AshTestBase::SetUp();
+    observer_.reset(new PowerEventObserver());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    observer_.reset();
+    test::AshTestBase::TearDown();
+  }
+
+ protected:
+  scoped_ptr<PowerEventObserver> observer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PowerEventObserverTest);
+};
+
+TEST_F(PowerEventObserverTest, LockBeforeSuspend) {
+  chromeos::PowerManagerClient* client =
+      chromeos::DBusThreadManager::Get()->GetPowerManagerClient();
+  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+
+  // Check that the observer requests a suspend-readiness callback when it hears
+  // that the system is about to suspend.
+  SetCanLockScreen(true);
+  SetShouldLockScreenBeforeSuspending(true);
+  observer_->SuspendImminent();
+  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+
+  // It should run the callback when it hears that the screen is locked.
+  observer_->ScreenIsLocked();
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+
+  // If the system is already locked, no callback should be requested.
+  observer_->SystemResumed(base::TimeDelta());
+  observer_->ScreenIsUnlocked();
+  observer_->ScreenIsLocked();
+  observer_->SuspendImminent();
+  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+
+  // It also shouldn't request a callback if it isn't instructed to lock the
+  // screen.
+  observer_->SystemResumed(base::TimeDelta());
+  SetShouldLockScreenBeforeSuspending(false);
+  observer_->SuspendImminent();
+  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/system/chromeos/power/power_status.cc b/ash/system/chromeos/power/power_status.cc
index 0283a0c..6b05401 100644
--- a/ash/system/chromeos/power/power_status.cc
+++ b/ash/system/chromeos/power/power_status.cc
@@ -112,7 +112,9 @@
   DCHECK(hours);
   DCHECK(minutes);
   *hours = time.InHours();
-  *minutes = (time - base::TimeDelta::FromHours(*hours)).InMinutes();
+  const double seconds =
+      (time - base::TimeDelta::FromHours(*hours)).InSecondsF();
+  *minutes = static_cast<int>(seconds / 60.0 + 0.5);
 }
 
 void PowerStatus::AddObserver(Observer* observer) {
diff --git a/ash/system/chromeos/power/power_status.h b/ash/system/chromeos/power/power_status.h
index a5cf3ae..3ac2de9 100644
--- a/ash/system/chromeos/power/power_status.h
+++ b/ash/system/chromeos/power/power_status.h
@@ -62,6 +62,9 @@
   static bool ShouldDisplayBatteryTime(const base::TimeDelta& time);
 
   // Copies the hour and minute components of |time| to |hours| and |minutes|.
+  // The minute component is rounded rather than truncated: a |time| value
+  // corresponding to 92 seconds will produce a |minutes| value of 2, for
+  // example.
   static void SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time,
                                            int* hours,
                                            int* minutes);
diff --git a/ash/system/chromeos/power/power_status_unittest.cc b/ash/system/chromeos/power/power_status_unittest.cc
index baf4997..ba9d2c1 100644
--- a/ash/system/chromeos/power/power_status_unittest.cc
+++ b/ash/system/chromeos/power/power_status_unittest.cc
@@ -129,6 +129,17 @@
       base::TimeDelta::FromSeconds(7 * 3600 + 23 * 60), &hours, &minutes);
   EXPECT_EQ(7, hours);
   EXPECT_EQ(23, minutes);
+
+  // Check that minutes are rounded.
+  PowerStatus::SplitTimeIntoHoursAndMinutes(
+      base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 30), &hours, &minutes);
+  EXPECT_EQ(2, hours);
+  EXPECT_EQ(4, minutes);
+
+  PowerStatus::SplitTimeIntoHoursAndMinutes(
+      base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 29), &hours, &minutes);
+  EXPECT_EQ(2, hours);
+  EXPECT_EQ(3, minutes);
 }
 
 }  // namespace internal
diff --git a/ash/system/chromeos/power/power_status_view.cc b/ash/system/chromeos/power/power_status_view.cc
index 9cb2072..f0fe4b1 100644
--- a/ash/system/chromeos/power/power_status_view.cc
+++ b/ash/system/chromeos/power/power_status_view.cc
@@ -186,9 +186,8 @@
               base::IntToString16(min)));
     } else {
       // This is a low battery warning prompting the user in minutes.
-      min = hour * 60 + min;
       time_label_->SetText(ui::TimeFormat::TimeRemaining(
-          base::TimeDelta::FromMinutes(min)));
+          base::TimeDelta::FromMinutes(hour * 60 + min)));
     }
   } else {
     time_label_->SetText(base::string16());
diff --git a/ash/system/chromeos/power/tray_power.cc b/ash/system/chromeos/power/tray_power.cc
index 75ac669..a0d7e5d 100644
--- a/ash/system/chromeos/power/tray_power.cc
+++ b/ash/system/chromeos/power/tray_power.cc
@@ -34,19 +34,6 @@
 
 namespace ash {
 namespace internal {
-
-namespace {
-// Notification times.
-const int kCriticalSeconds = 5 * 60;
-const int kLowPowerSeconds = 15 * 60;
-const int kNoWarningSeconds = 30 * 60;
-// Notification in battery percentage.
-const double kCriticalPercentage = 5.0;
-const double kLowPowerPercentage = 10.0;
-const double kNoWarningPercentage = 15.0;
-
-}  // namespace
-
 namespace tray {
 
 // This view is used only for the tray.
@@ -108,6 +95,13 @@
 
 using tray::PowerNotificationView;
 
+const int TrayPower::kCriticalMinutes = 5;
+const int TrayPower::kLowPowerMinutes = 15;
+const int TrayPower::kNoWarningMinutes = 30;
+const int TrayPower::kCriticalPercentage = 5;
+const int TrayPower::kLowPowerPercentage = 10;
+const int TrayPower::kNoWarningPercentage = 15;
+
 TrayPower::TrayPower(SystemTray* system_tray, MessageCenter* message_center)
     : SystemTrayItem(system_tray),
       message_center_(message_center),
@@ -235,27 +229,29 @@
 }
 
 bool TrayPower::UpdateNotificationStateForRemainingTime() {
-  const int remaining_seconds =
-      PowerStatus::Get()->GetBatteryTimeToEmpty().InSeconds();
+  // The notification includes a rounded minutes value, so round the estimate
+  // received from the power manager to match.
+  const int remaining_minutes = static_cast<int>(
+      PowerStatus::Get()->GetBatteryTimeToEmpty().InSecondsF() / 60.0 + 0.5);
 
-  if (remaining_seconds >= kNoWarningSeconds) {
+  if (remaining_minutes >= kNoWarningMinutes) {
     notification_state_ = NOTIFICATION_NONE;
     return false;
   }
 
   switch (notification_state_) {
     case NOTIFICATION_NONE:
-      if (remaining_seconds <= kCriticalSeconds) {
+      if (remaining_minutes <= kCriticalMinutes) {
         notification_state_ = NOTIFICATION_CRITICAL;
         return true;
       }
-      if (remaining_seconds <= kLowPowerSeconds) {
+      if (remaining_minutes <= kLowPowerMinutes) {
         notification_state_ = NOTIFICATION_LOW_POWER;
         return true;
       }
       return false;
     case NOTIFICATION_LOW_POWER:
-      if (remaining_seconds <= kCriticalSeconds) {
+      if (remaining_minutes <= kCriticalMinutes) {
         notification_state_ = NOTIFICATION_CRITICAL;
         return true;
       }
@@ -268,9 +264,12 @@
 }
 
 bool TrayPower::UpdateNotificationStateForRemainingPercentage() {
-  const double remaining_percentage = PowerStatus::Get()->GetBatteryPercent();
+  // The notification includes a rounded percentage, so round the value received
+  // from the power manager to match.
+  const int remaining_percentage =
+      PowerStatus::Get()->GetRoundedBatteryPercent();
 
-  if (remaining_percentage > kNoWarningPercentage) {
+  if (remaining_percentage >= kNoWarningPercentage) {
     notification_state_ = NOTIFICATION_NONE;
     return false;
   }
diff --git a/ash/system/chromeos/power/tray_power.h b/ash/system/chromeos/power/tray_power.h
index 2a66cd5..9fb65b7 100644
--- a/ash/system/chromeos/power/tray_power.h
+++ b/ash/system/chromeos/power/tray_power.h
@@ -41,6 +41,16 @@
     NOTIFICATION_CRITICAL,
   };
 
+  // Time-based notification thresholds when on battery power.
+  static const int kCriticalMinutes;
+  static const int kLowPowerMinutes;
+  static const int kNoWarningMinutes;
+
+  // Percentage-based notification thresholds when using a low-power charger.
+  static const int kCriticalPercentage;
+  static const int kLowPowerPercentage;
+  static const int kNoWarningPercentage;
+
   TrayPower(SystemTray* system_tray,
             message_center::MessageCenter* message_center);
   virtual ~TrayPower();
diff --git a/ash/system/chromeos/power/tray_power_unittest.cc b/ash/system/chromeos/power/tray_power_unittest.cc
index 82bac27..069ece0 100644
--- a/ash/system/chromeos/power/tray_power_unittest.cc
+++ b/ash/system/chromeos/power/tray_power_unittest.cc
@@ -161,12 +161,63 @@
   EXPECT_FALSE(UpdateNotificationState(charging));
   EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
 
-  // Critical low battery notification.
+  // When the rounded minutes-to-empty are above the threshold, no notification
+  // should be shown.
+  PowerSupplyProperties low = DefaultPowerSupplyProperties();
+  low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 30);
+  EXPECT_FALSE(UpdateNotificationState(low));
+  EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
+
+  // When the rounded value matches the threshold, the notification should
+  // appear.
+  low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 29);
+  EXPECT_TRUE(UpdateNotificationState(low));
+  EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
+
+  // It should persist at lower values.
+  low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 - 20);
+  EXPECT_FALSE(UpdateNotificationState(low));
+  EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
+
+  // The critical low battery notification should be shown when the rounded
+  // value is at the lower threshold.
   PowerSupplyProperties critical = DefaultPowerSupplyProperties();
-  critical.set_battery_time_to_empty_sec(60);
-  critical.set_battery_percent(2.0);
+  critical.set_battery_time_to_empty_sec(TrayPower::kCriticalMinutes * 60 + 29);
   EXPECT_TRUE(UpdateNotificationState(critical));
   EXPECT_EQ(TrayPower::NOTIFICATION_CRITICAL, notification_state());
+
+  // The notification should be dismissed when the no-warning threshold is
+  // reached.
+  PowerSupplyProperties safe = DefaultPowerSupplyProperties();
+  safe.set_battery_time_to_empty_sec(TrayPower::kNoWarningMinutes * 60 - 29);
+  EXPECT_FALSE(UpdateNotificationState(safe));
+  EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
+
+  // Test that rounded percentages are used when a USB charger is connected.
+  PowerSupplyProperties low_usb = DefaultPowerSupplyProperties();
+  low_usb.set_external_power(
+      power_manager::PowerSupplyProperties_ExternalPower_USB);
+  low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.5);
+  EXPECT_FALSE(UpdateNotificationState(low_usb));
+  EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
+
+  low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.49);
+  EXPECT_TRUE(UpdateNotificationState(low_usb));
+  EXPECT_EQ(TrayPower::NOTIFICATION_LOW_POWER, notification_state());
+
+  PowerSupplyProperties critical_usb = DefaultPowerSupplyProperties();
+  critical_usb.set_external_power(
+      power_manager::PowerSupplyProperties_ExternalPower_USB);
+  critical_usb.set_battery_percent(TrayPower::kCriticalPercentage + 0.2);
+  EXPECT_TRUE(UpdateNotificationState(critical_usb));
+  EXPECT_EQ(TrayPower::NOTIFICATION_CRITICAL, notification_state());
+
+  PowerSupplyProperties safe_usb = DefaultPowerSupplyProperties();
+  safe_usb.set_external_power(
+      power_manager::PowerSupplyProperties_ExternalPower_USB);
+  safe_usb.set_battery_percent(TrayPower::kNoWarningPercentage - 0.1);
+  EXPECT_FALSE(UpdateNotificationState(safe_usb));
+  EXPECT_EQ(TrayPower::NOTIFICATION_NONE, notification_state());
 }
 
 }  // namespace internal
diff --git a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
index 80f54b4..928dad7 100644
--- a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
+++ b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/chromeos/screen_security/screen_tray_item.h"
 
+#include "ash/shell.h"
 #include "ash/system/chromeos/screen_security/screen_capture_tray_item.h"
 #include "ash/system/chromeos/screen_security/screen_share_tray_item.h"
 #include "ash/system/tray/tray_item_view.h"
diff --git a/ash/system/chromeos/system_clock_observer.cc b/ash/system/chromeos/system_clock_observer.cc
index 9142dd9..c5ab20c 100644
--- a/ash/system/chromeos/system_clock_observer.cc
+++ b/ash/system/chromeos/system_clock_observer.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/chromeos/system_clock_observer.h"
 
+#include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 
diff --git a/ash/system/chromeos/tray_display.cc b/ash/system/chromeos/tray_display.cc
index 9e1cdc9..fcee915 100644
--- a/ash/system/chromeos/tray_display.cc
+++ b/ash/system/chromeos/tray_display.cc
@@ -46,10 +46,13 @@
   DisplayManager* display_manager = GetDisplayManager();
 
   const gfx::Display* display = &display_manager->GetDisplayForId(display_id);
-  if (display_manager->IsMirrored() &&
-      display_manager->mirrored_display().id() == display_id) {
-    display = &display_manager->mirrored_display();
-  }
+
+  // We don't show display size for mirrored display. Fallback
+  // to empty string if this happens on release build.
+  bool mirrored_display = display_manager->mirrored_display_id() == display_id;
+  DCHECK(!mirrored_display);
+  if (mirrored_display)
+    return base::string16();
 
   DCHECK(display->is_valid());
   return UTF8ToUTF16(display->size().ToString());
@@ -60,6 +63,8 @@
 base::string16 GetDisplayInfoLine(int64 display_id) {
   const DisplayInfo& display_info =
       GetDisplayManager()->GetDisplayInfo(display_id);
+  if (GetDisplayManager()->mirrored_display_id() == display_id)
+    return GetDisplayName(display_id);
 
   base::string16 size_text = GetDisplaySize(display_id);
   base::string16 display_data;
@@ -102,18 +107,18 @@
 }
 
 // Returns the name of the currently connected external display.
+// This should not be used when the external display is used for
+// mirroring.
 base::string16 GetExternalDisplayName() {
   DisplayManager* display_manager = GetDisplayManager();
-  int64 external_id = display_manager->mirrored_display().id();
+  DCHECK(!display_manager->IsMirrored());
 
-  if (external_id == gfx::Display::kInvalidDisplayID) {
-    int64 internal_display_id = gfx::Display::InternalDisplayId();
-    for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
-      int64 id = display_manager->GetDisplayAt(i).id();
-      if (id != internal_display_id) {
-        external_id = id;
-        break;
-      }
+  int64 external_id = gfx::Display::kInvalidDisplayID;
+  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
+    int64 id = display_manager->GetDisplayAt(i).id();
+    if (id != gfx::Display::InternalDisplayId()) {
+      external_id = id;
+      break;
     }
   }
 
@@ -156,7 +161,8 @@
   if (display_manager->IsMirrored()) {
     if (GetDisplayManager()->HasInternalDisplay()) {
       return l10n_util::GetStringFUTF16(
-          IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetExternalDisplayName());
+          IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING,
+          GetDisplayName(display_manager->mirrored_display_id()));
     }
     return l10n_util::GetStringUTF16(
         IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL);
diff --git a/ash/system/chromeos/tray_display_unittest.cc b/ash/system/chromeos/tray_display_unittest.cc
index 9cb9fee..8884da8 100644
--- a/ash/system/chromeos/tray_display_unittest.cc
+++ b/ash/system/chromeos/tray_display_unittest.cc
@@ -31,9 +31,13 @@
                               const std::string& data2) {
   std::vector<base::string16> lines;
   lines.push_back(headline);
-  lines.push_back(l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
-      name1, UTF8ToUTF16(data1)));
+  if (data1.empty()) {
+    lines.push_back(name1);
+  } else {
+    lines.push_back(l10n_util::GetStringFUTF16(
+        IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
+        name1, UTF8ToUTF16(data1)));
+  }
   if (!name2.empty()) {
     lines.push_back(l10n_util::GetStringFUTF16(
         IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
@@ -63,7 +67,7 @@
 base::string16 GetMirroredDisplayName() {
   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
   return UTF8ToUTF16(display_manager->GetDisplayNameForId(
-      display_manager->mirrored_display().id()));
+      display_manager->mirrored_display_id()));
 }
 
 class TrayDisplayTest : public ash::test::AshTestBase {
@@ -300,13 +304,10 @@
   // Mirroring
   display_manager->SetSoftwareMirroring(true);
   UpdateDisplay("400x400,200x200@1.5");
-  base::string16 mirror_name = l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
-      GetMirroredDisplayName(), UTF8ToUTF16("300x300"));
   tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
   EXPECT_TRUE(IsDisplayVisibleInTray());
   expected = l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, mirror_name);
+      IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName());
   EXPECT_EQ(expected, GetTrayDisplayText());
   EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"),
             GetTrayDisplayTooltipText());
diff --git a/ash/system/chromeos/tray_tracing.cc b/ash/system/chromeos/tray_tracing.cc
index 764e943..eddeac7 100644
--- a/ash/system/chromeos/tray_tracing.cc
+++ b/ash/system/chromeos/tray_tracing.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/chromeos/tray_tracing.h"
 
+#include "ash/shell.h"
 #include "ash/system/tray/actionable_view.h"
 #include "ash/system/tray/fixed_sized_image_view.h"
 #include "ash/system/tray/system_tray.h"
@@ -24,17 +25,16 @@
 
 namespace tray {
 
-class DefaultTracingView : public ash::internal::ActionableView {
+class DefaultTracingView : public internal::ActionableView {
  public:
   DefaultTracingView() {
     SetLayoutManager(new views::BoxLayout(
         views::BoxLayout::kHorizontal,
-        ash::kTrayPopupPaddingHorizontal, 0,
-        ash::kTrayPopupPaddingBetweenItems));
+        kTrayPopupPaddingHorizontal, 0,
+        kTrayPopupPaddingBetweenItems));
 
     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-    image_ =
-        new ash::internal::FixedSizedImageView(0, ash::kTrayPopupItemHeight);
+    image_ = new internal::FixedSizedImageView(0, kTrayPopupItemHeight);
     image_->SetImage(
         bundle.GetImageNamed(IDR_AURA_UBER_TRAY_TRACING).ToImageSkia());
     AddChildView(image_);
@@ -51,7 +51,7 @@
  private:
   // Overridden from ActionableView.
   virtual bool PerformAction(const ui::Event& event) OVERRIDE {
-    ash::Shell::GetInstance()->system_tray_delegate()->ShowChromeSlow();
+    Shell::GetInstance()->system_tray_delegate()->ShowChromeSlow();
     return true;
   }
 
diff --git a/ash/system/date/tray_date.cc b/ash/system/date/tray_date.cc
index 466cf50..4b1552e 100644
--- a/ash/system/date/tray_date.cc
+++ b/ash/system/date/tray_date.cc
@@ -111,6 +111,10 @@
 
   virtual ~DateDefaultView() {}
 
+  views::View* GetHelpButtonView() const {
+    return help_;
+  }
+
  private:
   // Overridden from views::ButtonListener.
   virtual void ButtonPressed(views::Button* sender,
@@ -146,7 +150,8 @@
 
 TrayDate::TrayDate(SystemTray* system_tray)
     : SystemTrayItem(system_tray),
-      time_tray_(NULL) {
+      time_tray_(NULL),
+      default_view_(NULL) {
 #if defined(OS_CHROMEOS)
   system_clock_observer_.reset(new SystemClockObserver());
 #endif
@@ -157,6 +162,12 @@
   Shell::GetInstance()->system_tray_notifier()->RemoveClockObserver(this);
 }
 
+views::View* TrayDate::GetHelpButtonView() const {
+  if (!default_view_)
+    return NULL;
+  return static_cast<DateDefaultView*>(default_view_)->GetHelpButtonView();
+}
+
 views::View* TrayDate::CreateTrayView(user::LoginStatus status) {
   CHECK(time_tray_ == NULL);
   ClockLayout clock_layout =
@@ -170,7 +181,8 @@
 }
 
 views::View* TrayDate::CreateDefaultView(user::LoginStatus status) {
-  return new DateDefaultView(status);
+  default_view_ = new DateDefaultView(status);
+  return default_view_;
 }
 
 views::View* TrayDate::CreateDetailedView(user::LoginStatus status) {
@@ -182,6 +194,7 @@
 }
 
 void TrayDate::DestroyDefaultView() {
+  default_view_ = NULL;
 }
 
 void TrayDate::DestroyDetailedView() {
diff --git a/ash/system/date/tray_date.h b/ash/system/date/tray_date.h
index ddda3d3..c009f60 100644
--- a/ash/system/date/tray_date.h
+++ b/ash/system/date/tray_date.h
@@ -34,6 +34,9 @@
   explicit TrayDate(SystemTray* system_tray);
   virtual ~TrayDate();
 
+  // Returns view for help button if it is exists. Returns NULL otherwise.
+  views::View* GetHelpButtonView() const;
+
  private:
   // Overridden from SystemTrayItem.
   virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
@@ -54,6 +57,7 @@
   void SetupLabelForTimeTray(views::Label* label);
 
   tray::TimeView* time_tray_;
+  views::View* default_view_;
 
 #if defined(OS_CHROMEOS)
   scoped_ptr<SystemClockObserver> system_clock_observer_;
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 266f58e..8020b4f 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -8,6 +8,7 @@
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/shell/panel_window.h"
+#include "ash/shell_delegate.h"
 #include "ash/shell_window_ids.h"
 #include "ash/system/bluetooth/tray_bluetooth.h"
 #include "ash/system/date/tray_date.h"
@@ -77,13 +78,15 @@
  public:
   // Takes ownership of |bubble|.
   explicit SystemBubbleWrapper(internal::SystemTrayBubble* bubble)
-      : bubble_(bubble) {
+      : bubble_(bubble),
+        is_persistent_(false) {
   }
 
   // Initializes the bubble view and creates |bubble_wrapper_|.
   void InitView(TrayBackgroundView* tray,
                 views::View* anchor,
-                TrayBubbleView::InitParams* init_params) {
+                TrayBubbleView::InitParams* init_params,
+                bool is_persistent) {
     DCHECK(anchor);
     user::LoginStatus login_status =
         Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
@@ -95,6 +98,7 @@
       bubble_->bubble_view()->SetArrowPaintType(
           views::BubbleBorder::PAINT_NONE);
     }
+    is_persistent_ = is_persistent;
   }
 
   // Convenience accessors:
@@ -103,10 +107,12 @@
     return bubble_->bubble_type();
   }
   TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
+  bool is_persistent() const { return is_persistent_; }
 
  private:
   scoped_ptr<internal::SystemTrayBubble> bubble_;
   scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
+  bool is_persistent_;
 
   DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
 };
@@ -123,7 +129,8 @@
       default_bubble_height_(0),
       hide_notifications_(false),
       full_system_tray_menu_(false),
-      tray_accessibility_(NULL) {
+      tray_accessibility_(NULL),
+      tray_date_(NULL) {
   SetContentsBackground();
 }
 
@@ -162,6 +169,7 @@
 #endif
 
   tray_accessibility_ = new internal::TrayAccessibility(this);
+  tray_date_ = new internal::TrayDate(this);
 
 #if defined(OS_CHROMEOS)
   AddTrayItem(new internal::TrayEnterprise(this));
@@ -184,10 +192,11 @@
   AddTrayItem(new internal::TrayCapsLock(this));
   AddTrayItem(new internal::TraySettings(this));
   AddTrayItem(new internal::TrayUpdate(this));
-  AddTrayItem(new internal::TrayDate(this));
+  AddTrayItem(tray_date_);
 #elif defined(OS_WIN)
   AddTrayItem(tray_accessibility_);
-  AddTrayItem(new internal::TrayDate(this));
+  AddTrayItem(new internal::TrayUpdate(this));
+  AddTrayItem(tray_date_);
 #elif defined(OS_LINUX)
   AddTrayItem(new internal::TrayIME(this));
   AddTrayItem(tray_accessibility_);
@@ -195,7 +204,7 @@
   AddTrayItem(new internal::TrayDrive(this));
   AddTrayItem(new internal::TrayCapsLock(this));
   AddTrayItem(new internal::TrayUpdate(this));
-  AddTrayItem(new internal::TrayDate(this));
+  AddTrayItem(tray_date_);
 #endif
 
 #if defined(OS_LINUX)
@@ -235,8 +244,17 @@
 }
 
 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
-  ShowDefaultViewWithOffset(creation_type,
-                            TrayBubbleView::InitParams::kArrowDefaultOffset);
+  ShowDefaultViewWithOffset(
+      creation_type,
+      TrayBubbleView::InitParams::kArrowDefaultOffset,
+      false);
+}
+
+void SystemTray::ShowPersistentDefaultView() {
+  ShowDefaultViewWithOffset(
+      BUBBLE_CREATE_NEW,
+      TrayBubbleView::InitParams::kArrowDefaultOffset,
+      true);
 }
 
 void SystemTray::ShowDetailedView(SystemTrayItem* item,
@@ -245,7 +263,7 @@
                                   BubbleCreationType creation_type) {
   std::vector<SystemTrayItem*> items;
   items.push_back(item);
-  ShowItems(items, true, activate, creation_type, GetTrayXOffset(item));
+  ShowItems(items, true, activate, creation_type, GetTrayXOffset(item), false);
   if (system_bubble_)
     system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
 }
@@ -353,6 +371,10 @@
   return true;
 }
 
+views::View* SystemTray::GetHelpButtonView() const {
+  return tray_date_->GetHelpButtonView();
+}
+
 bool SystemTray::CloseNotificationBubbleForTest() const {
   if (!notification_bubble_)
     return false;
@@ -404,15 +426,17 @@
 }
 
 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type,
-                                           int arrow_offset) {
-  ShowItems(items_.get(), false, true, creation_type, arrow_offset);
+                                           int arrow_offset,
+                                           bool persistent) {
+  ShowItems(items_.get(), false, true, creation_type, arrow_offset, persistent);
 }
 
 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
                            bool detailed,
                            bool can_activate,
                            BubbleCreationType creation_type,
-                           int arrow_offset) {
+                           int arrow_offset,
+                           bool persistent) {
   // No system tray bubbles in kiosk mode.
   if (Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus() ==
       ash::user::LOGGED_IN_KIOSK_APP) {
@@ -456,6 +480,8 @@
       init_params.arrow_color = kHeaderBackgroundColor;
     }
     init_params.arrow_offset = arrow_offset;
+    if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)
+      init_params.close_on_deactivate = !persistent;
     // For Volume and Brightness we don't want to show an arrow when
     // they are shown in a bubble by themselves.
     init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL;
@@ -463,7 +489,7 @@
       init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT;
     SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
     system_bubble_.reset(new internal::SystemBubbleWrapper(bubble));
-    system_bubble_->InitView(this, tray_container(), &init_params);
+    system_bubble_->InitView(this, tray_container(), &init_params, persistent);
   }
   // Save height of default view for creating detailed views directly.
   if (!detailed)
@@ -521,7 +547,7 @@
   init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
   notification_bubble_.reset(
       new internal::SystemBubbleWrapper(notification_bubble));
-  notification_bubble_->InitView(this, anchor, &init_params);
+  notification_bubble_->InitView(this, anchor, &init_params, false);
 
   if (notification_bubble->bubble_view()->child_count() == 0) {
     // It is possible that none of the items generated actual notifications.
@@ -603,7 +629,7 @@
 }
 
 bool SystemTray::ClickedOutsideBubble() {
-  if (!system_bubble_)
+  if (!system_bubble_ || system_bubble_->is_persistent())
     return false;
   HideBubbleWithView(system_bubble_->bubble_view());
   return true;
@@ -647,6 +673,11 @@
   return it == tray_item_map_.end() ? NULL : it->second;
 }
 
+void SystemTray::AddTrayUserItemForTest(internal::TrayUser* tray_user) {
+  AddTrayItem(tray_user);
+  user_items_.push_back(tray_user);
+}
+
 bool SystemTray::PerformAction(const ui::Event& event) {
   // If we're already showing the default view, hide it; otherwise, show it
   // (and hide any popup that's currently shown).
@@ -664,7 +695,7 @@
         arrow_offset = point.x();
       }
     }
-    ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset);
+    ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset, false);
   }
   return true;
 }
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index 93ce180..7b1681d 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -27,6 +27,7 @@
 namespace internal {
 class SystemBubbleWrapper;
 class TrayAccessibility;
+class TrayDate;
 class TrayUser;
 }
 
@@ -61,6 +62,9 @@
   // Shows the default view of all items.
   void ShowDefaultView(BubbleCreationType creation_type);
 
+  // Shows default view that ingnores outside clicks and activation loss.
+  void ShowPersistentDefaultView();
+
   // Shows details of a particular item. If |close_delay_in_seconds| is
   // non-zero, then the view is automatically closed after the specified time.
   void ShowDetailedView(SystemTrayItem* item,
@@ -115,6 +119,10 @@
   // Closes system bubble and returns true if it did exist.
   bool CloseSystemBubble() const;
 
+  // Returns view for help button if default view is shown. Returns NULL
+  // otherwise.
+  views::View* GetHelpButtonView() const;
+
   // Accessors for testing.
 
   // Returns true if the bubble exists.
@@ -146,6 +154,10 @@
   // Get the tray item view (or NULL) for a given |tray_item| in a unit test.
   views::View* GetTrayItemViewForTest(SystemTrayItem* tray_item);
 
+  // Add a tray user item for testing purposes. Note: The passed |tray_user|
+  // will be owned by the SystemTray after the call.
+  void AddTrayUserItemForTest(internal::TrayUser* tray_user);
+
  private:
   // Creates the default set of items for the sytem tray.
   void CreateItems(SystemTrayDelegate* delegate);
@@ -162,7 +174,8 @@
 
   // Shows the default view and its arrow position is shifted by |x_offset|.
   void ShowDefaultViewWithOffset(BubbleCreationType creation_type,
-                                 int x_offset);
+                                 int x_offset,
+                                 bool persistent);
 
   // Constructs or re-constructs |system_bubble_| and populates it with |items|.
   // Specify |change_tray_status| to true if want to change the tray background
@@ -171,7 +184,8 @@
                  bool details,
                  bool activate,
                  BubbleCreationType creation_type,
-                 int x_offset);
+                 int x_offset,
+                 bool persistent);
 
   // Constructs or re-constructs |notification_bubble_| and populates it with
   // |notification_items_|, or destroys it if there are no notification items.
@@ -223,6 +237,7 @@
   bool full_system_tray_menu_;
 
   internal::TrayAccessibility* tray_accessibility_;  // not owned
+  internal::TrayDate* tray_date_;
 
   DISALLOW_COPY_AND_ASSIGN(SystemTray);
 };
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc
index 8b1d06c..779975a 100644
--- a/ash/system/tray/system_tray_unittest.cc
+++ b/ash/system/tray/system_tray_unittest.cc
@@ -13,7 +13,11 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/window_util.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/view.h"
@@ -372,5 +376,46 @@
   EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
 }
 
+TEST_F(SystemTrayTest, PersistentBubble) {
+  SystemTray* tray = GetSystemTray();
+  ASSERT_TRUE(tray->GetWidget());
+
+  TestItem* test_item = new TestItem;
+  tray->AddTrayItem(test_item);
+
+  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
+
+  // Tests for usual default view.
+  // Activating window.
+  tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  ASSERT_TRUE(tray->HasSystemBubble());
+  wm::ActivateWindow(window.get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_FALSE(tray->HasSystemBubble());
+
+  tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  ASSERT_TRUE(tray->HasSystemBubble());
+  {
+    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
+                                         gfx::Point(5, 5));
+    generator.ClickLeftButton();
+    ASSERT_FALSE(tray->HasSystemBubble());
+  }
+
+  // Same tests for persistent default view.
+  tray->ShowPersistentDefaultView();
+  ASSERT_TRUE(tray->HasSystemBubble());
+  wm::ActivateWindow(window.get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(tray->HasSystemBubble());
+
+  {
+    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
+                                         gfx::Point(5, 5));
+    generator.ClickLeftButton();
+    ASSERT_TRUE(tray->HasSystemBubble());
+  }
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index b106122..f357706 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -573,7 +573,7 @@
 
   // TODO(jennyz): May need to add left/right alignment in the following code.
   if (rect.IsEmpty()) {
-    aura::RootWindow* target_root = anchor_widget ?
+    aura::Window* target_root = anchor_widget ?
         anchor_widget->GetNativeView()->GetRootWindow() :
         Shell::GetPrimaryRootWindow();
     rect = target_root->bounds();
@@ -622,7 +622,7 @@
   if (switches::UseAlternateShelfLayout())
     return;
 
-  aura::RootWindow* root_window =
+  aura::Window* root_window =
       bubble_view->GetWidget()->GetNativeView()->GetRootWindow();
   ash::internal::ShelfLayoutManager* shelf =
       ShelfLayoutManager::ForLauncher(root_window);
diff --git a/ash/system/tray/tray_bubble_wrapper.cc b/ash/system/tray/tray_bubble_wrapper.cc
index c5738e5..2bcb07b 100644
--- a/ash/system/tray/tray_bubble_wrapper.cc
+++ b/ash/system/tray/tray_bubble_wrapper.cc
@@ -8,6 +8,7 @@
 #include "ash/system/tray/tray_event_filter.h"
 #include "ash/wm/window_properties.h"
 #include "ui/aura/client/capture_client.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/views/bubble/tray_bubble_view.h"
 #include "ui/views/widget/widget.h"
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc
index a5ea3a2..676c8b6 100644
--- a/ash/system/tray/tray_event_filter.cc
+++ b/ash/system/tray/tray_event_filter.cc
@@ -75,7 +75,7 @@
 
     gfx::Rect bounds = bubble_widget->GetWindowBoundsInScreen();
     bounds.Inset(wrapper->bubble_view()->GetBorderInsets());
-    aura::RootWindow* root = bubble_widget->GetNativeView()->GetRootWindow();
+    aura::Window* root = bubble_widget->GetNativeView()->GetRootWindow();
     aura::client::ScreenPositionClient* screen_position_client =
         aura::client::GetScreenPositionClient(root);
     gfx::Point screen_point(event->root_location());
diff --git a/ash/system/tray_accessibility.cc b/ash/system/tray_accessibility.cc
index 6297d5c..63fd215 100644
--- a/ash/system/tray_accessibility.cc
+++ b/ash/system/tray_accessibility.cc
@@ -4,8 +4,8 @@
 
 #include "ash/system/tray_accessibility.h"
 
+#include "ash/accessibility_delegate.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
@@ -36,19 +36,23 @@
   A11Y_HIGH_CONTRAST    = 1 << 1,
   A11Y_SCREEN_MAGNIFIER = 1 << 2,
   A11Y_LARGE_CURSOR     = 1 << 3,
+  A11Y_AUTOCLICK        = 1 << 4,
 };
 
 uint32 GetAccessibilityState() {
-  ShellDelegate* shell_delegate = Shell::GetInstance()->delegate();
+  AccessibilityDelegate* delegate =
+      Shell::GetInstance()->accessibility_delegate();
   uint32 state = A11Y_NONE;
-  if (shell_delegate->IsSpokenFeedbackEnabled())
+  if (delegate->IsSpokenFeedbackEnabled())
     state |= A11Y_SPOKEN_FEEDBACK;
-  if (shell_delegate->IsHighContrastEnabled())
+  if (delegate->IsHighContrastEnabled())
     state |= A11Y_HIGH_CONTRAST;
-  if (shell_delegate->IsMagnifierEnabled())
+  if (delegate->IsMagnifierEnabled())
     state |= A11Y_SCREEN_MAGNIFIER;
-  if (shell_delegate->IsLargeCursorEnabled())
+  if (delegate->IsLargeCursorEnabled())
     state |= A11Y_LARGE_CURSOR;
+  if (delegate->IsAutoclickEnabled())
+    state |= A11Y_AUTOCLICK;
   return state;
 }
 
@@ -112,10 +116,12 @@
         large_cursor_view_(NULL),
         help_view_(NULL),
         settings_view_(NULL),
+        autoclick_view_(NULL),
         spoken_feedback_enabled_(false),
         high_contrast_enabled_(false),
         screen_magnifier_enabled_(false),
         large_cursor_enabled_(false),
+        autoclick_enabled_(false),
         login_(login) {
 
   Reset();
@@ -131,8 +137,9 @@
   CreateScrollableList();
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
 
-  ShellDelegate* shell_delegate = Shell::GetInstance()->delegate();
-  spoken_feedback_enabled_ = shell_delegate->IsSpokenFeedbackEnabled();
+  AccessibilityDelegate* delegate =
+      Shell::GetInstance()->accessibility_delegate();
+  spoken_feedback_enabled_ = delegate->IsSpokenFeedbackEnabled();
   spoken_feedback_view_ = AddScrollListItem(
       bundle.GetLocalizedString(
           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK),
@@ -141,7 +148,7 @@
 
   // Large Cursor item is shown only in Login screen.
   if (login_ == user::LOGGED_IN_NONE) {
-    large_cursor_enabled_ = shell_delegate->IsLargeCursorEnabled();
+    large_cursor_enabled_ = delegate->IsLargeCursorEnabled();
     large_cursor_view_ = AddScrollListItem(
         bundle.GetLocalizedString(
             IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR),
@@ -149,18 +156,28 @@
         large_cursor_enabled_);
   }
 
-  high_contrast_enabled_ = shell_delegate->IsHighContrastEnabled();
+  high_contrast_enabled_ = delegate->IsHighContrastEnabled();
   high_contrast_view_ = AddScrollListItem(
       bundle.GetLocalizedString(
           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE),
       high_contrast_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
       high_contrast_enabled_);
-  screen_magnifier_enabled_ = shell_delegate->IsMagnifierEnabled();
+  screen_magnifier_enabled_ = delegate->IsMagnifierEnabled();
   screen_magnifier_view_ = AddScrollListItem(
       bundle.GetLocalizedString(
           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER),
       screen_magnifier_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
       screen_magnifier_enabled_);
+
+  // Don't show autoclick option at login screen.
+  if (login_ != user::LOGGED_IN_NONE) {
+    autoclick_enabled_ = delegate->IsAutoclickEnabled();
+    autoclick_view_ = AddScrollListItem(
+        bundle.GetLocalizedString(
+            IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK),
+        autoclick_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
+        autoclick_enabled_);
+  }
 }
 
 void AccessibilityDetailedView::AppendHelpEntries() {
@@ -209,18 +226,20 @@
 }
 
 void AccessibilityDetailedView::OnViewClicked(views::View* sender) {
-  ShellDelegate* shell_delegate = Shell::GetInstance()->delegate();
+  AccessibilityDelegate* delegate =
+      Shell::GetInstance()->accessibility_delegate();
   if (sender == footer()->content()) {
     owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
   } else if (sender == spoken_feedback_view_) {
-    shell_delegate->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_NONE);
+    delegate->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_NONE);
   } else if (sender == high_contrast_view_) {
-    shell_delegate->ToggleHighContrast();
+    delegate->ToggleHighContrast();
   } else if (sender == screen_magnifier_view_) {
-    shell_delegate->SetMagnifierEnabled(!shell_delegate->IsMagnifierEnabled());
+    delegate->SetMagnifierEnabled(!delegate->IsMagnifierEnabled());
   } else if (large_cursor_view_ && sender == large_cursor_view_) {
-    shell_delegate->
-        SetLargeCursorEnabled(!shell_delegate->IsLargeCursorEnabled());
+    delegate->SetLargeCursorEnabled(!delegate->IsLargeCursorEnabled());
+  } else if (autoclick_view_ && sender == autoclick_view_) {
+    delegate->SetAutoclickEnabled(!delegate->IsAutoclickEnabled());
   }
 }
 
@@ -283,7 +302,8 @@
   // - "Enable accessibility menu" on chrome://settings is checked;
   // - or any of accessibility features is enabled
   // Otherwise, not shows it.
-  ShellDelegate* delegate = Shell::GetInstance()->delegate();
+  AccessibilityDelegate* delegate =
+      Shell::GetInstance()->accessibility_delegate();
   if (login_ != user::LOGGED_IN_NONE &&
       !delegate->ShouldAlwaysShowAccessibilityMenu() &&
       // On login screen, keeps the initial visivility of the menu.
@@ -334,7 +354,7 @@
   SetTrayIconVisible(GetInitialVisibility());
 
   uint32 accessibility_state = GetAccessibilityState();
-  if ((notify == ash::A11Y_NOTIFICATION_SHOW)&&
+  if ((notify == ash::A11Y_NOTIFICATION_SHOW) &&
       !(previous_accessibility_state_ & A11Y_SPOKEN_FEEDBACK) &&
       (accessibility_state & A11Y_SPOKEN_FEEDBACK)) {
     // Shows popup if |notify| is true and the spoken feedback is being enabled.
diff --git a/ash/system/tray_accessibility.h b/ash/system/tray_accessibility.h
index 0171378..a3f53cb 100644
--- a/ash/system/tray_accessibility.h
+++ b/ash/system/tray_accessibility.h
@@ -5,7 +5,7 @@
 #ifndef ASH_SYSTEM_TRAY_ACCESSIBILITY_H_
 #define ASH_SYSTEM_TRAY_ACCESSIBILITY_H_
 
-#include "ash/shell_delegate.h"
+#include "ash/accessibility_delegate.h"
 #include "ash/shell_observer.h"
 #include "ash/system/tray/tray_details_view.h"
 #include "ash/system/tray/tray_image_item.h"
@@ -76,11 +76,13 @@
   views::View* large_cursor_view_;;
   views::View* help_view_;
   views::View* settings_view_;
+  views::View* autoclick_view_;
 
   bool spoken_feedback_enabled_;
   bool high_contrast_enabled_;
   bool screen_magnifier_enabled_;
   bool large_cursor_enabled_;
+  bool autoclick_enabled_;
   user::LoginStatus login_;
 
   friend class chromeos::TrayAccessibilityTest;
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index ba62612..65ac529 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -118,6 +118,11 @@
 
 // Switch to a user with the given |user_index|.
 void SwitchUser(ash::MultiProfileIndex user_index) {
+  // Do not switch users when the log screen is presented.
+  if (ash::Shell::GetInstance()->session_state_delegate()->
+          IsUserSessionBlocked())
+    return;
+
   DCHECK(user_index > 0);
   ash::SessionStateDelegate* delegate =
       ash::Shell::GetInstance()->session_state_delegate();
@@ -1033,7 +1038,10 @@
 }
 
 bool UserView::SupportsMultiProfile() {
-  return Shell::GetInstance()->delegate()->IsMultiProfilesEnabled();
+  // We do not want to see any multi profile additions to a user view when the
+  // log in screen is shown.
+  return Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
+      !Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked();
 }
 
 AddUserView::AddUserView(UserCard* owner, views::ButtonListener* listener)
@@ -1148,7 +1156,7 @@
 }
 
 bool TrayUser::TransferWindowToUser(aura::Window* window) {
-  const SessionStateDelegate* session_state_delegate =
+  SessionStateDelegate* session_state_delegate =
       ash::Shell::GetInstance()->session_state_delegate();
   return session_state_delegate->TransferWindowToDesktopOfUser(window,
                                                                GetTrayIndex());
@@ -1177,11 +1185,15 @@
 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
   if (status == user::LOGGED_IN_NONE)
     return NULL;
+  const SessionStateDelegate* session_state_delegate =
+      Shell::GetInstance()->session_state_delegate();
+
+  // If the screen is locked show only the currently active user.
+  if (multiprofile_index_ && session_state_delegate->IsUserSessionBlocked())
+    return NULL;
 
   CHECK(user_ == NULL);
 
-  const SessionStateDelegate* session_state_delegate =
-      Shell::GetInstance()->session_state_delegate();
   int logged_in_users = session_state_delegate->NumberOfLoggedInUsers();
 
   // If there are multiple users logged in, the users will be separated from the
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index 70e2b5b..53a381b 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -83,7 +83,7 @@
 
   // Starts observing |shelf| and shell and sends the change to |collection|.
   void StartObserving(message_center::MessagePopupCollection* collection,
-                      aura::RootWindow* root_window);
+                      aura::Window* root_window);
 
   // Stops the observing session.
   void StopObserving();
@@ -99,7 +99,7 @@
   void UpdateShelf();
 
   message_center::MessagePopupCollection* collection_;
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
   ShelfLayoutManager* shelf_;
   int system_tray_height_;
 
@@ -139,7 +139,7 @@
 
 void WorkAreaObserver::StartObserving(
     message_center::MessagePopupCollection* collection,
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   DCHECK(collection);
   collection_ = collection;
   root_window_ = root_window;
@@ -349,7 +349,7 @@
       break;
     }
     case SHELF_ALIGNMENT_TOP: {
-      aura::RootWindow* root = status_area_window->GetRootWindow();
+      aura::Window* root = status_area_window->GetRootWindow();
       max_height =
           root->bounds().height() - status_area_window->bounds().height();
       break;
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index d763a56..5ae2e49 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -16,7 +16,7 @@
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_system_tray_delegate.h"
-#include "ash/wm/window_properties.h"
+#include "ash/wm/window_state.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/aura/client/aura_constants.h"
@@ -286,12 +286,12 @@
   internal::DisplayManager* display_manager =
       Shell::GetInstance()->display_manager();
 
-  display_manager->SetSoftwareMirroring(true);
+  display_manager->SetSecondDisplayMode(internal::DisplayManager::MIRRORING);
   UpdateDisplay("400x400,200x200");
   EXPECT_TRUE(GetTray()->IsPopupVisible());
   EXPECT_FALSE(GetSecondaryTray());
 
-  display_manager->SetSoftwareMirroring(false);
+  display_manager->SetSecondDisplayMode(internal::DisplayManager::EXTENDED);
   UpdateDisplay("400x400,200x200");
   EXPECT_TRUE(GetTray()->IsPopupVisible());
   secondary_tray = GetSecondaryTray();
@@ -429,8 +429,10 @@
   gfx::Rect work_area_auto_hidden = GetPopupWorkArea();
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
 
-  // Make the window to use immersive mode.
-  window->SetProperty(internal::kFullscreenUsesMinimalChromeKey, true);
+  // Put |window| into fullscreen without forcing the shelf to hide. Currently,
+  // this is used by immersive fullscreen and forces the shelf to be auto
+  // hidden.
+  wm::GetWindowState(window.get())->set_hide_shelf_when_fullscreen(false);
   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
   RunAllPendingInMessageLoop();
 
diff --git a/ash/test/app_list_controller_test_api.cc b/ash/test/app_list_controller_test_api.cc
index df21070..7e2ac2d 100644
--- a/ash/test/app_list_controller_test_api.cc
+++ b/ash/test/app_list_controller_test_api.cc
@@ -6,6 +6,11 @@
 
 #include "ash/test/shell_test_api.h"
 #include "ash/wm/app_list_controller.h"
+#include "ui/app_list/views/app_list_main_view.h"
+#include "ui/app_list/views/app_list_view.h"
+#include "ui/app_list/views/apps_container_view.h"
+#include "ui/app_list/views/apps_grid_view.h"
+#include "ui/app_list/views/contents_view.h"
 
 namespace ash {
 namespace test {
@@ -13,6 +18,11 @@
 AppListControllerTestApi::AppListControllerTestApi(Shell* shell)
     : app_list_controller_(ShellTestApi(shell).app_list_controller()) {}
 
+app_list::AppsGridView* AppListControllerTestApi::GetRootGridView() {
+  return view()->app_list_main_view()->contents_view()->
+      apps_container_view()->apps_grid_view();
+}
+
 app_list::AppListView* AppListControllerTestApi::view() {
   return app_list_controller_->view_;
 }
diff --git a/ash/test/app_list_controller_test_api.h b/ash/test/app_list_controller_test_api.h
index 3534ffb..4064a77 100644
--- a/ash/test/app_list_controller_test_api.h
+++ b/ash/test/app_list_controller_test_api.h
@@ -9,6 +9,7 @@
 
 namespace app_list {
 class AppListView;
+class AppsGridView;
 }
 
 namespace ash {
@@ -24,6 +25,9 @@
  public:
   explicit AppListControllerTestApi(Shell* shell);
 
+  // Gets the root level apps grid view.
+  app_list::AppsGridView* GetRootGridView();
+
   app_list::AppListView* view();
 
  private:
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index dcbc747..0da80aa 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -11,6 +11,7 @@
 #include "ash/display/display_controller.h"
 #include "ash/screen_ash.h"
 #include "ash/shell.h"
+#include "ash/shell/toplevel_window.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/test_session_state_delegate.h"
@@ -20,6 +21,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/event_generator.h"
 #include "ui/aura/test/test_window_delegate.h"
@@ -59,7 +61,7 @@
     gfx::Screen* screen = Shell::GetScreen();
     gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen);
     return Shell::GetInstance()->display_controller()->
-        GetRootWindowForDisplayId(display.id());
+        GetRootWindowForDisplayId(display.id())->GetDispatcher();
   }
 
   virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
@@ -100,6 +102,11 @@
 
 void AshTestBase::SetUp() {
   setup_called_ = true;
+
+  // Clears the saved state so that test doesn't use on the wrong
+  // default state.
+  shell::ToplevelWindow::ClearSavedStateForTest();
+
   // TODO(jamescook): Can we do this without changing command line?
   // Use the origin (1,1) so that it doesn't over
   // lap with the native mouse cursor.
@@ -114,7 +121,7 @@
   ash_test_helper_->SetUp(start_session_);
 
   Shell::GetPrimaryRootWindow()->Show();
-  Shell::GetPrimaryRootWindow()->ShowRootWindow();
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->ShowRootWindow();
   // Move the mouse cursor to far away so that native events doesn't
   // interfere test expectations.
   Shell::GetPrimaryRootWindow()->MoveCursorTo(gfx::Point(-1000, -1000));
@@ -206,7 +213,7 @@
   display_manager_test_api.UpdateDisplay(display_specs);
 }
 
-aura::RootWindow* AshTestBase::CurrentContext() {
+aura::Window* AshTestBase::CurrentContext() {
   return ash_test_helper_->CurrentContext();
 }
 
@@ -249,24 +256,24 @@
   window->Show();
 
   if (bounds.IsEmpty()) {
-    SetDefaultParentByPrimaryRootWindow(window);
+    ParentWindowInPrimaryRootWindow(window);
   } else {
     gfx::Display display =
         Shell::GetScreen()->GetDisplayMatching(bounds);
-    aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()->
+    aura::Window* root = ash::Shell::GetInstance()->display_controller()->
         GetRootWindowForDisplayId(display.id());
     gfx::Point origin = bounds.origin();
     wm::ConvertPointFromScreen(root, &origin);
     window->SetBounds(gfx::Rect(origin, bounds.size()));
-    window->SetDefaultParentByRootWindow(root, bounds);
+    aura::client::ParentWindowWithContext(window, root, bounds);
   }
   window->SetProperty(aura::client::kCanMaximizeKey, true);
   return window;
 }
 
-void AshTestBase::SetDefaultParentByPrimaryRootWindow(aura::Window* window) {
-  window->SetDefaultParentByRootWindow(
-      Shell::GetPrimaryRootWindow(), gfx::Rect());
+void AshTestBase::ParentWindowInPrimaryRootWindow(aura::Window* window) {
+  aura::client::ParentWindowWithContext(
+      window, Shell::GetPrimaryRootWindow(), gfx::Rect());
 }
 
 void AshTestBase::RunAllPendingInMessageLoop() {
@@ -292,6 +299,11 @@
       SetCanLockScreen(can_lock_screen);
 }
 
+void AshTestBase::SetShouldLockScreenBeforeSuspending(bool should_lock) {
+  ash_test_helper_->test_shell_delegate()->test_session_state_delegate()->
+      SetShouldLockScreenBeforeSuspending(should_lock);
+}
+
 void AshTestBase::SetUserAddingScreenRunning(bool user_adding_screen_running) {
   ash_test_helper_->test_shell_delegate()->test_session_state_delegate()->
       SetUserAddingScreenRunning(user_adding_screen_running);
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index 281073e..7b5bb44 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -64,10 +64,10 @@
   // See ash::test::DisplayManagerTestApi::UpdateDisplay for more details.
   void UpdateDisplay(const std::string& display_specs);
 
-  // Returns a RootWindow. Usually this is the active RootWindow, but that
+  // Returns a root Window. Usually this is the active root Window, but that
   // method can return NULL sometimes, and in those cases, we fall back on the
-  // primary RootWindow.
-  aura::RootWindow* CurrentContext();
+  // primary root Window.
+  aura::Window* CurrentContext();
 
   // Versions of the functions in aura::test:: that go through our shell
   // StackingController instead of taking a parent.
@@ -87,7 +87,7 @@
       const gfx::Rect& bounds);
 
   // Attach |window| to the current shell's root window.
-  void SetDefaultParentByPrimaryRootWindow(aura::Window* window);
+  void ParentWindowInPrimaryRootWindow(aura::Window* window);
 
   // Returns the EventGenerator that uses screen coordinates and works
   // across multiple displays. It createse a new generator if it
@@ -122,6 +122,7 @@
   void SetSessionStarted(bool session_started);
   void SetUserLoggedIn(bool user_logged_in);
   void SetCanLockScreen(bool can_lock_screen);
+  void SetShouldLockScreenBeforeSuspending(bool should_lock);
   void SetUserAddingScreenRunning(bool user_adding_screen_running);
 
   // Methods to emulate blocking and unblocking user session with given
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 49bb4d1..4b84a2e 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -19,6 +19,7 @@
 #include "ui/aura/test/env_test_helper.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/corewm/capture_controller.h"
 
@@ -54,6 +55,9 @@
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
   ui::InitializeInputMethodForTesting();
 
+  bool allow_test_contexts = true;
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
+
   // Creates Shell and hook with Desktop.
   test_shell_delegate_ = new TestShellDelegate;
 
@@ -111,6 +115,7 @@
 #endif
 
   aura::Env::DeleteInstance();
+  ui::TerminateContextFactoryForTests();
 
   // Need to reset the initial login status.
   TestSystemTrayDelegate::SetInitialLoginStatus(user::LOGGED_IN_USER);
@@ -128,8 +133,8 @@
   run_loop.RunUntilIdle();
 }
 
-aura::RootWindow* AshTestHelper::CurrentContext() {
-  aura::RootWindow* root_window = Shell::GetTargetRootWindow();
+aura::Window* AshTestHelper::CurrentContext() {
+  aura::Window* root_window = Shell::GetTargetRootWindow();
   if (!root_window)
     root_window = Shell::GetPrimaryRootWindow();
   DCHECK(root_window);
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 030f7f8..9e78fea 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 }  // namespace aura
 
 namespace base {
@@ -41,10 +41,10 @@
   // Destroys the ash::Shell and performs associated cleanup.
   void TearDown();
 
-  // Returns a RootWindow. Usually this is the active RootWindow, but that
+  // Returns a root Window. Usually this is the active root Window, but that
   // method can return NULL sometimes, and in those cases, we fall back on the
-  // primary RootWindow.
-  aura::RootWindow* CurrentContext();
+  // primary root Window.
+  aura::Window* CurrentContext();
 
   void RunAllPendingInMessageLoop();
 
diff --git a/ash/test/test_launcher_delegate.cc b/ash/test/test_launcher_delegate.cc
index 98f1db0..1867980 100644
--- a/ash/test/test_launcher_delegate.cc
+++ b/ash/test/test_launcher_delegate.cc
@@ -6,7 +6,6 @@
 
 #include "ash/launcher/launcher_item_delegate_manager.h"
 #include "ash/launcher/launcher_model.h"
-#include "ash/shelf/shelf_util.h"
 #include "ash/shell.h"
 #include "ash/test/test_launcher_item_delegate.h"
 #include "base/strings/string_util.h"
diff --git a/ash/test/test_launcher_item_delegate.cc b/ash/test/test_launcher_item_delegate.cc
index 9cb56bb..7ac8b72 100644
--- a/ash/test/test_launcher_item_delegate.cc
+++ b/ash/test/test_launcher_item_delegate.cc
@@ -31,7 +31,7 @@
 }
 
 ui::MenuModel* TestLauncherItemDelegate::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   return NULL;
 }
 
diff --git a/ash/test/test_launcher_item_delegate.h b/ash/test/test_launcher_item_delegate.h
index 138a772..fd4c394 100644
--- a/ash/test/test_launcher_item_delegate.h
+++ b/ash/test/test_launcher_item_delegate.h
@@ -26,7 +26,7 @@
   virtual void ItemSelected(const ui::Event& event) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
diff --git a/ash/test/test_session_state_delegate.cc b/ash/test/test_session_state_delegate.cc
index e18f7d1..8032f4f 100644
--- a/ash/test/test_session_state_delegate.cc
+++ b/ash/test/test_session_state_delegate.cc
@@ -31,9 +31,11 @@
     : has_active_user_(false),
       active_user_session_started_(false),
       can_lock_screen_(true),
+      should_lock_screen_before_suspending_(false),
       screen_locked_(false),
       user_adding_screen_running_(false),
-      logged_in_users_(1) {
+      logged_in_users_(1),
+      num_transfer_to_desktop_of_user_calls_(0) {
 }
 
 TestSessionStateDelegate::~TestSessionStateDelegate() {
@@ -61,7 +63,7 @@
 }
 
 bool TestSessionStateDelegate::ShouldLockScreenBeforeSuspending() const {
-  return false;
+  return should_lock_screen_before_suspending_;
 }
 
 void TestSessionStateDelegate::LockScreen() {
@@ -101,6 +103,11 @@
   can_lock_screen_ = can_lock_screen;
 }
 
+void TestSessionStateDelegate::SetShouldLockScreenBeforeSuspending(
+    bool should_lock) {
+  should_lock_screen_before_suspending_ = should_lock;
+}
+
 void TestSessionStateDelegate::SetUserAddingScreenRunning(
     bool user_adding_screen_running) {
   user_adding_screen_running_ = user_adding_screen_running;
@@ -154,7 +161,8 @@
 
 bool TestSessionStateDelegate::TransferWindowToDesktopOfUser(
     aura::Window* window,
-    ash::MultiProfileIndex index) const {
+    ash::MultiProfileIndex index) {
+  num_transfer_to_desktop_of_user_calls_++;
   return false;
 }
 
diff --git a/ash/test/test_session_state_delegate.h b/ash/test/test_session_state_delegate.h
index 105c0b1..fcd375d 100644
--- a/ash/test/test_session_state_delegate.h
+++ b/ash/test/test_session_state_delegate.h
@@ -48,7 +48,7 @@
       ash::SessionStateObserver* observer) OVERRIDE;
   virtual bool TransferWindowToDesktopOfUser(
       aura::Window* window,
-      ash::MultiProfileIndex index) const OVERRIDE;
+      ash::MultiProfileIndex index) OVERRIDE;
 
   // TODO(oshima): Use state machine instead of using boolean variables.
 
@@ -69,10 +69,18 @@
   // is an active user.
   void SetCanLockScreen(bool can_lock_screen);
 
+  // Updates |should_lock_screen_before_suspending_|.
+  void SetShouldLockScreenBeforeSuspending(bool should_lock);
+
   // Updates the internal state that indicates whether user adding screen is
   // running now.
   void SetUserAddingScreenRunning(bool user_adding_screen_running);
 
+  // Returns the number of calls to TransferWindowToDesktopOfUser.
+  int num_transfer_to_desktop_of_user_calls() {
+    return num_transfer_to_desktop_of_user_calls_;
+  }
+
  private:
   // Whether a session is in progress and there is an active user.
   bool has_active_user_;
@@ -86,6 +94,9 @@
   // when this is |true| and there is an active user.
   bool can_lock_screen_;
 
+  // Return value for ShouldLockScreenBeforeSuspending().
+  bool should_lock_screen_before_suspending_;
+
   // Whether the screen is currently locked.
   bool screen_locked_;
 
@@ -101,6 +112,9 @@
   // A test user image.
   gfx::ImageSkia null_image_;
 
+  // The number of calls which happened to TransferWindowToDesktopOfUser.
+  int num_transfer_to_desktop_of_user_calls_;
+
   DISALLOW_COPY_AND_ASSIGN(TestSessionStateDelegate);
 };
 
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index 8dfff8e..a882f87 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -7,8 +7,10 @@
 #include <limits>
 
 #include "ash/caps_lock_delegate_stub.h"
+#include "ash/default_accessibility_delegate.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/keyboard_controller_proxy_stub.h"
+#include "ash/new_window_delegate.h"
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
@@ -21,18 +23,26 @@
 #include "base/logging.h"
 #include "content/public/test/test_browser_context.h"
 #include "ui/aura/window.h"
-#include "ui/compositor/compositor.h"
 
 namespace ash {
 namespace test {
+namespace {
+
+class NewWindowDelegateImpl : public NewWindowDelegate {
+  virtual void NewTab() OVERRIDE {}
+  virtual void NewWindow(bool incognito) OVERRIDE {}
+  virtual void OpenFileManager() OVERRIDE {}
+  virtual void OpenCrosh() OVERRIDE {}
+  virtual void RestoreTab() OVERRIDE {}
+  virtual void ShowKeyboardOverlay() OVERRIDE {}
+  virtual void ShowTaskManager() OVERRIDE {}
+  virtual void OpenFeedbackPage() OVERRIDE {}
+};
+
+}  // namespace
 
 TestShellDelegate::TestShellDelegate()
-    : spoken_feedback_enabled_(false),
-      high_contrast_enabled_(false),
-      screen_magnifier_enabled_(false),
-      screen_magnifier_type_(kDefaultMagnifierType),
-      large_cursor_enabled_(false),
-      num_exit_requests_(0),
+    : num_exit_requests_(0),
       multi_profiles_enabled_(false),
       test_session_state_delegate_(NULL) {
 }
@@ -62,88 +72,16 @@
   num_exit_requests_++;
 }
 
-void TestShellDelegate::NewTab() {
-}
-
-void TestShellDelegate::NewWindow(bool incognito) {
-}
-
-void TestShellDelegate::ToggleFullscreen() {
-}
-
-void TestShellDelegate::OpenFileManager() {
-}
-
-void TestShellDelegate::OpenCrosh() {
-}
-
-void TestShellDelegate::RestoreTab() {
-}
-
-void TestShellDelegate::ShowKeyboardOverlay() {
-}
-
 keyboard::KeyboardControllerProxy*
     TestShellDelegate::CreateKeyboardControllerProxy() {
   return new KeyboardControllerProxyStub();
 }
 
-void TestShellDelegate::ShowTaskManager() {
-}
-
 content::BrowserContext* TestShellDelegate::GetCurrentBrowserContext() {
   current_browser_context_.reset(new content::TestBrowserContext());
   return current_browser_context_.get();
 }
 
-void TestShellDelegate::ToggleSpokenFeedback(
-    AccessibilityNotificationVisibility notify) {
-  spoken_feedback_enabled_ = !spoken_feedback_enabled_;
-}
-
-bool TestShellDelegate::IsSpokenFeedbackEnabled() const {
-  return spoken_feedback_enabled_;
-}
-
-void TestShellDelegate::ToggleHighContrast() {
-  high_contrast_enabled_ = !high_contrast_enabled_;
-}
-
-bool TestShellDelegate::IsHighContrastEnabled() const {
-  return high_contrast_enabled_;
-}
-
-void TestShellDelegate::SetMagnifierEnabled(bool enabled) {
-  screen_magnifier_enabled_ = enabled;
-}
-
-void TestShellDelegate::SetMagnifierType(MagnifierType type) {
-  screen_magnifier_type_ = type;
-}
-
-bool TestShellDelegate::IsMagnifierEnabled() const {
-  return screen_magnifier_enabled_;
-}
-
-MagnifierType TestShellDelegate::GetMagnifierType() const {
-  return screen_magnifier_type_;
-}
-
-void TestShellDelegate::SetLargeCursorEnabled(bool enabled) {
-  large_cursor_enabled_ = enabled;
-}
-
-bool TestShellDelegate::IsLargeCursorEnabled() const {
-  return large_cursor_enabled_;
-}
-
-bool TestShellDelegate::ShouldAlwaysShowAccessibilityMenu() const {
-  return false;
-}
-
-void TestShellDelegate::SilenceSpokenFeedback() const {
-}
-
 app_list::AppListViewDelegate* TestShellDelegate::CreateAppListViewDelegate() {
   return NULL;
 }
@@ -171,11 +109,16 @@
   return test_session_state_delegate_;
 }
 
-aura::client::UserActionClient* TestShellDelegate::CreateUserActionClient() {
-  return NULL;
+AccessibilityDelegate* TestShellDelegate::CreateAccessibilityDelegate() {
+  return new internal::DefaultAccessibilityDelegate();
 }
 
-void TestShellDelegate::OpenFeedbackPage() {
+NewWindowDelegate* TestShellDelegate::CreateNewWindowDelegate() {
+  return new NewWindowDelegateImpl;
+}
+
+aura::client::UserActionClient* TestShellDelegate::CreateUserActionClient() {
+  return NULL;
 }
 
 void TestShellDelegate::RecordUserMetricsAction(UserMetricsAction action) {
@@ -190,22 +133,11 @@
 void TestShellDelegate::HandleMediaPrevTrack() {
 }
 
-void TestShellDelegate::SaveScreenMagnifierScale(double scale) {
-}
-
-ui::MenuModel* TestShellDelegate::CreateContextMenu(aura::RootWindow* root) {
+ui::MenuModel* TestShellDelegate::CreateContextMenu(aura::Window* root) {
   return NULL;
 }
 
-double TestShellDelegate::GetSavedScreenMagnifierScale() {
-  return std::numeric_limits<double>::min();
-}
-
 RootWindowHostFactory* TestShellDelegate::CreateRootWindowHostFactory() {
-  // The ContextFactory must exist before any Compositors are created.
-  bool allow_test_contexts = true;
-  ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
-
   return RootWindowHostFactory::Create();
 }
 
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h
index c4c8332..47c268d 100644
--- a/ash/test/test_shell_delegate.h
+++ b/ash/test/test_shell_delegate.h
@@ -36,30 +36,9 @@
   virtual void PreInit() OVERRIDE;
   virtual void Shutdown() OVERRIDE;
   virtual void Exit() OVERRIDE;
-  virtual void NewTab() OVERRIDE;
-  virtual void NewWindow(bool incognito) OVERRIDE;
-  virtual void ToggleFullscreen() OVERRIDE;
-  virtual void OpenFileManager() OVERRIDE;
-  virtual void OpenCrosh() OVERRIDE;
-  virtual void RestoreTab() OVERRIDE;
-  virtual void ShowKeyboardOverlay() OVERRIDE;
   virtual keyboard::KeyboardControllerProxy*
       CreateKeyboardControllerProxy() OVERRIDE;
-  virtual void ShowTaskManager() OVERRIDE;
   virtual content::BrowserContext* GetCurrentBrowserContext() OVERRIDE;
-  virtual void ToggleSpokenFeedback(
-      AccessibilityNotificationVisibility notify) OVERRIDE;
-  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE;
-  virtual void ToggleHighContrast() OVERRIDE;
-  virtual bool IsHighContrastEnabled() const OVERRIDE;
-  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE;
-  virtual void SetMagnifierType(MagnifierType type) OVERRIDE;
-  virtual bool IsMagnifierEnabled() const OVERRIDE;
-  virtual MagnifierType GetMagnifierType() const OVERRIDE;
-  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE;
-  virtual bool IsLargeCursorEnabled() const OVERRIDE;
-  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE;
-  virtual void SilenceSpokenFeedback() const OVERRIDE;
   virtual app_list::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
   virtual LauncherDelegate* CreateLauncherDelegate(
       ash::LauncherModel* model) OVERRIDE;
@@ -67,15 +46,14 @@
   virtual UserWallpaperDelegate* CreateUserWallpaperDelegate() OVERRIDE;
   virtual CapsLockDelegate* CreateCapsLockDelegate() OVERRIDE;
   virtual SessionStateDelegate* CreateSessionStateDelegate() OVERRIDE;
+  virtual AccessibilityDelegate* CreateAccessibilityDelegate() OVERRIDE;
+  virtual NewWindowDelegate* CreateNewWindowDelegate() OVERRIDE;
   virtual aura::client::UserActionClient* CreateUserActionClient() OVERRIDE;
-  virtual void OpenFeedbackPage() OVERRIDE;
   virtual void RecordUserMetricsAction(UserMetricsAction action) OVERRIDE;
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
-  virtual double GetSavedScreenMagnifierScale() OVERRIDE;
-  virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root) OVERRIDE;
+  virtual ui::MenuModel* CreateContextMenu(aura::Window* root) OVERRIDE;
   virtual RootWindowHostFactory* CreateRootWindowHostFactory() OVERRIDE;
   virtual base::string16 GetProductName() const OVERRIDE;
 
@@ -84,11 +62,6 @@
   TestSessionStateDelegate* test_session_state_delegate();
 
  private:
-  bool spoken_feedback_enabled_;
-  bool high_contrast_enabled_;
-  bool screen_magnifier_enabled_;
-  MagnifierType screen_magnifier_type_;
-  bool large_cursor_enabled_;
   int num_exit_requests_;
   bool multi_profiles_enabled_;
 
diff --git a/ash/test/ui_controls_factory_ash.cc b/ash/test/ui_controls_factory_ash.cc
index 458a4cb..b8393e5 100644
--- a/ash/test/ui_controls_factory_ash.cc
+++ b/ash/test/ui_controls_factory_ash.cc
@@ -30,11 +30,12 @@
 // Returns the UIControls object for RootWindow.
 // kUIControlsKey is owned property and UIControls object
 // will be deleted when the root window is deleted.
-UIControlsAura* GetUIControlsForRootWindow(aura::RootWindow* root_window) {
+UIControlsAura* GetUIControlsForRootWindow(aura::Window* root_window) {
   UIControlsAura* native_ui_control =
       root_window->GetProperty(kUIControlsKey);
   if (!native_ui_control) {
-    native_ui_control = aura::test::CreateUIControlsAura(root_window);
+    native_ui_control =
+        aura::test::CreateUIControlsAura(root_window->GetDispatcher());
     // Pass the ownership to the |root_window|.
     root_window->SetProperty(kUIControlsKey, native_ui_control);
   }
@@ -47,7 +48,7 @@
 // the |point_in_screen|.
 UIControlsAura* GetUIControlsAt(gfx::Point* point_in_screen) {
   // TODO(mazda): Support the case passive grab is taken.
-  aura::RootWindow* root = ash::wm::GetRootWindowAt(*point_in_screen);
+  aura::Window* root = ash::wm::GetRootWindowAt(*point_in_screen);
 
   aura::client::ScreenPositionClient* screen_position_client =
       aura::client::GetScreenPositionClient(root);
@@ -85,7 +86,7 @@
       bool alt,
       bool command,
       const base::Closure& closure) OVERRIDE {
-    aura::RootWindow* root =
+    aura::Window* root =
         window ? window->GetRootWindow() : ash::Shell::GetTargetRootWindow();
     UIControlsAura* ui_controls = GetUIControlsForRootWindow(root);
     return ui_controls && ui_controls->SendKeyPressNotifyWhenDone(
diff --git a/ash/touch/touch_hud_projection.cc b/ash/touch/touch_hud_projection.cc
index b7e75e0..173cbd0 100644
--- a/ash/touch/touch_hud_projection.cc
+++ b/ash/touch/touch_hud_projection.cc
@@ -118,7 +118,10 @@
 
   // Overridden from views::WidgetObserver.
   virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE {
-    fadeout_->Stop();
+    if (fadeout_)
+      fadeout_->Stop();
+    else
+      Remove();
   }
 
   const gfx::Point circle_center_;
diff --git a/ash/touch/touch_hud_projection.h b/ash/touch/touch_hud_projection.h
index 29fddc3..197482d 100644
--- a/ash/touch/touch_hud_projection.h
+++ b/ash/touch/touch_hud_projection.h
@@ -24,6 +24,8 @@
   virtual void Clear() OVERRIDE;
 
  private:
+  friend class TouchHudProjectionTest;
+
   virtual ~TouchHudProjection();
 
   // Overriden from TouchObserverHUD.
diff --git a/ash/touch/touch_observer_hud.h b/ash/touch/touch_observer_hud.h
index b94cc17..1a903e0 100644
--- a/ash/touch/touch_observer_hud.h
+++ b/ash/touch/touch_observer_hud.h
@@ -77,10 +77,10 @@
   virtual void OnDisplayConfigurationChanged() OVERRIDE;
 
  private:
-  friend class TouchHudTest;
+  friend class TouchHudTestBase;
 
   const int64 display_id_;
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   views::Widget* widget_;
 
diff --git a/ash/touch/touch_observer_hud_unittest.cc b/ash/touch/touch_observer_hud_unittest.cc
index df992ba..90328a8 100644
--- a/ash/touch/touch_observer_hud_unittest.cc
+++ b/ash/touch/touch_observer_hud_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
 #include "ash/touch/touch_hud_debug.h"
+#include "ash/touch/touch_hud_projection.h"
 #include "base/command_line.h"
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
@@ -20,18 +21,12 @@
 namespace ash {
 namespace internal {
 
-class TouchHudTest : public test::AshTestBase {
+class TouchHudTestBase : public test::AshTestBase {
  public:
-  TouchHudTest() {}
-  virtual ~TouchHudTest() {}
+  TouchHudTestBase() {}
+  virtual ~TouchHudTestBase() {}
 
   virtual void SetUp() OVERRIDE {
-    // Add ash-touch-hud flag to enable touch HUD. This flag should be set
-    // before Ash environment is set up, i.e., before
-    // test::AshTestBase::SetUp().
-    CommandLine::ForCurrentProcess()->AppendSwitch(
-        ash::switches::kAshTouchHud);
-
     test::AshTestBase::SetUp();
 
     // Initialize display infos. They should be initialized after Ash
@@ -131,29 +126,7 @@
     return external_display_id_;
   }
 
-  void CheckInternalDisplay() {
-    EXPECT_NE(static_cast<internal::TouchObserverHUD*>(NULL),
-              GetInternalTouchHud());
-    EXPECT_EQ(internal_display_id(), GetInternalTouchHud()->display_id_);
-    EXPECT_EQ(GetInternalRootWindow(), GetInternalTouchHud()->root_window_);
-    EXPECT_EQ(GetInternalRootWindow(),
-              GetInternalTouchHud()->widget_->GetNativeView()->GetRootWindow());
-    EXPECT_EQ(GetInternalDisplay().size(),
-              GetInternalTouchHud()->widget_->GetWindowBoundsInScreen().size());
-  }
-
-  void CheckExternalDisplay() {
-    EXPECT_NE(static_cast<internal::TouchObserverHUD*>(NULL),
-              GetExternalTouchHud());
-    EXPECT_EQ(external_display_id(), GetExternalTouchHud()->display_id_);
-    EXPECT_EQ(GetExternalRootWindow(), GetExternalTouchHud()->root_window_);
-    EXPECT_EQ(GetExternalRootWindow(),
-              GetExternalTouchHud()->widget_->GetNativeView()->GetRootWindow());
-    EXPECT_EQ(GetExternalDisplay().size(),
-              GetExternalTouchHud()->widget_->GetWindowBoundsInScreen().size());
-  }
-
- private:
+ protected:
   DisplayManager* GetDisplayManager() {
     return Shell::GetInstance()->display_manager();
   }
@@ -170,68 +143,60 @@
     return GetDisplayManager()->GetDisplayForId(external_display_id_);
   }
 
-  aura::RootWindow* GetInternalRootWindow() {
+  aura::Window* GetInternalRootWindow() {
     return GetDisplayController()->GetRootWindowForDisplayId(
         internal_display_id_);
   }
 
-  aura::RootWindow* GetExternalRootWindow() {
+  aura::Window* GetExternalRootWindow() {
     return GetDisplayController()->GetRootWindowForDisplayId(
         external_display_id_);
   }
 
-  aura::RootWindow* GetPrimaryRootWindow() {
+  aura::Window* GetPrimaryRootWindow() {
     const gfx::Display& display = GetPrimaryDisplay();
     return GetDisplayController()->GetRootWindowForDisplayId(display.id());
   }
 
-  aura::RootWindow* GetSecondaryRootWindow() {
+  aura::Window* GetSecondaryRootWindow() {
     const gfx::Display& display = GetSecondaryDisplay();
     return GetDisplayController()->GetRootWindowForDisplayId(display.id());
   }
 
   internal::RootWindowController* GetInternalRootController() {
-    aura::RootWindow* root = GetInternalRootWindow();
+    aura::Window* root = GetInternalRootWindow();
     return GetRootWindowController(root);
   }
 
   internal::RootWindowController* GetExternalRootController() {
-    aura::RootWindow* root = GetExternalRootWindow();
+    aura::Window* root = GetExternalRootWindow();
     return GetRootWindowController(root);
   }
 
   internal::RootWindowController* GetPrimaryRootController() {
-    aura::RootWindow* root = GetPrimaryRootWindow();
+    aura::Window* root = GetPrimaryRootWindow();
     return GetRootWindowController(root);
   }
 
   internal::RootWindowController* GetSecondaryRootController() {
-    aura::RootWindow* root = GetSecondaryRootWindow();
+    aura::Window* root = GetSecondaryRootWindow();
     return GetRootWindowController(root);
   }
 
-  internal::TouchObserverHUD* GetInternalTouchHud() {
-    return GetInternalRootController()->touch_hud_debug();
-  }
-
-  internal::TouchObserverHUD* GetExternalTouchHud() {
-    return GetExternalRootController()->touch_hud_debug();
-  }
-
-  internal::TouchObserverHUD* GetPrimaryTouchHud() {
-    return GetPrimaryRootController()->touch_hud_debug();
-  }
-
-  internal::TouchObserverHUD* GetSecondaryTouchHud() {
-    return GetSecondaryRootController()->touch_hud_debug();
-  }
-
   DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) {
     DisplayInfo info(id, base::StringPrintf("x-%" PRId64, id), false);
     info.SetBounds(bounds);
     return info;
   }
 
+  aura::Window* GetRootWindowForTouchHud(internal::TouchObserverHUD* hud) {
+    return hud->root_window_;
+  }
+
+  views::Widget* GetWidgetForTouchHud(internal::TouchObserverHUD* hud) {
+    return hud->widget_;
+  }
+
   int64 internal_display_id_;
   int64 external_display_id_;
   int64 mirrored_display_id_;
@@ -241,11 +206,120 @@
 
   std::vector<DisplayInfo> display_info_list_;
 
-  DISALLOW_COPY_AND_ASSIGN(TouchHudTest);
+  DISALLOW_COPY_AND_ASSIGN(TouchHudTestBase);
 };
 
-// Checks if touch HUDs are correctly initialized for displays.
-TEST_F(TouchHudTest, Basic) {
+class TouchHudDebugTest : public TouchHudTestBase {
+ public:
+  TouchHudDebugTest() {}
+  virtual ~TouchHudDebugTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    // Add ash-touch-hud flag to enable debug touch HUD. This flag should be set
+    // before Ash environment is set up, i.e., before TouchHudTestBase::SetUp().
+    CommandLine::ForCurrentProcess()->AppendSwitch(
+        ash::switches::kAshTouchHud);
+
+    TouchHudTestBase::SetUp();
+  }
+
+  void CheckInternalDisplay() {
+    EXPECT_NE(static_cast<internal::TouchObserverHUD*>(NULL),
+              GetInternalTouchHudDebug());
+    EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id());
+    EXPECT_EQ(GetInternalRootWindow(),
+              GetRootWindowForTouchHud(GetInternalTouchHudDebug()));
+    EXPECT_EQ(GetInternalRootWindow(),
+              GetWidgetForTouchHud(GetInternalTouchHudDebug())->
+                  GetNativeView()->GetRootWindow());
+    EXPECT_EQ(GetInternalDisplay().size(),
+              GetWidgetForTouchHud(GetInternalTouchHudDebug())->
+                  GetWindowBoundsInScreen().size());
+  }
+
+  void CheckExternalDisplay() {
+    EXPECT_NE(static_cast<internal::TouchHudDebug*>(NULL),
+              GetExternalTouchHudDebug());
+    EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id());
+    EXPECT_EQ(GetExternalRootWindow(),
+              GetRootWindowForTouchHud(GetExternalTouchHudDebug()));
+    EXPECT_EQ(GetExternalRootWindow(),
+              GetWidgetForTouchHud(GetExternalTouchHudDebug())->
+                  GetNativeView()->GetRootWindow());
+    EXPECT_EQ(GetExternalDisplay().size(),
+              GetWidgetForTouchHud(GetExternalTouchHudDebug())->
+                  GetWindowBoundsInScreen().size());
+  }
+
+ private:
+  internal::TouchHudDebug* GetInternalTouchHudDebug() {
+    return GetInternalRootController()->touch_hud_debug();
+  }
+
+  internal::TouchHudDebug* GetExternalTouchHudDebug() {
+    return GetExternalRootController()->touch_hud_debug();
+  }
+
+  internal::TouchHudDebug* GetPrimaryTouchHudDebug() {
+    return GetPrimaryRootController()->touch_hud_debug();
+  }
+
+  internal::TouchHudDebug* GetSecondaryTouchHudDebug() {
+    return GetSecondaryRootController()->touch_hud_debug();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest);
+};
+
+class TouchHudProjectionTest : public TouchHudTestBase {
+ public:
+  TouchHudProjectionTest() {}
+  virtual ~TouchHudProjectionTest() {}
+
+  void EnableTouchHudProjection() {
+    Shell::GetInstance()->SetTouchHudProjectionEnabled(true);
+  }
+
+  void DisableTouchHudProjection() {
+    Shell::GetInstance()->SetTouchHudProjectionEnabled(false);
+  }
+
+  internal::TouchHudProjection* GetInternalTouchHudProjection() {
+    return GetInternalRootController()->touch_hud_projection();
+  }
+
+  int GetInternalTouchPointsCount() {
+    return GetInternalTouchHudProjection()->points_.size();
+  }
+
+  void SendTouchEventToInternalHud(ui::EventType type,
+                                   const gfx::Point& location,
+                                   int touch_id) {
+    ui::TouchEvent event(type, location, touch_id, event_time);
+    GetInternalTouchHudProjection()->OnTouchEvent(&event);
+
+    // Advance time for next event.
+    event_time += base::TimeDelta::FromMilliseconds(100);
+  }
+
+ private:
+  base::TimeDelta event_time;
+
+  DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest);
+};
+
+// Checks if debug touch HUD is correctly initialized for a single display.
+TEST_F(TouchHudDebugTest, SingleDisplay) {
+  // Setup a single display setting.
+  SetupSingleDisplay();
+
+  // Check if touch HUD is set correctly and associated with appropriate
+  // display.
+  CheckInternalDisplay();
+}
+
+// Checks if debug touch HUDs are correctly initialized for two displays.
+TEST_F(TouchHudDebugTest, DualDisplays) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -258,8 +332,9 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when primary display is changed.
-TEST_F(TouchHudTest, SwapPrimaryDisplay) {
+// Checks if debug touch HUDs are correctly handled when primary display is
+// changed.
+TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -285,8 +360,8 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when displays are mirrored.
-TEST_F(TouchHudTest, MirrorDisplays) {
+// Checks if debug touch HUDs are correctly handled when displays are mirrored.
+TEST_F(TouchHudDebugTest, MirrorDisplays) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -310,9 +385,9 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when displays are mirrored after
-// setting the external display as the primary one.
-TEST_F(TouchHudTest, SwapPrimaryThenMirrorDisplays) {
+// Checks if debug touch HUDs are correctly handled when displays are mirrored
+// after setting the external display as the primary one.
+TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -340,9 +415,9 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when the external display, which
-// is the secondary one, is removed.
-TEST_F(TouchHudTest, RemoveSecondaryDisplay) {
+// Checks if debug touch HUDs are correctly handled when the external display,
+// which is the secondary one, is removed.
+TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -366,9 +441,9 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when the external display, which
-// is set as the primary display, is removed.
-TEST_F(TouchHudTest, RemovePrimaryDisplay) {
+// Checks if debug touch HUDs are correctly handled when the external display,
+// which is set as the primary display, is removed.
+TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -396,8 +471,9 @@
   CheckExternalDisplay();
 }
 
-// Checks if touch HUDs are correctly handled when all displays are removed.
-TEST_F(TouchHudTest, Headless) {
+// Checks if debug touch HUDs are correctly handled when all displays are
+// removed.
+TEST_F(TouchHudDebugTest, Headless) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -415,5 +491,107 @@
   CheckInternalDisplay();
 }
 
+// Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
+// and touch-released events.
+TEST_F(TouchHudProjectionTest, TouchMoveRelease) {
+  SetupSingleDisplay();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+
+  EnableTouchHudProjection();
+  EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL),
+            GetInternalTouchHudProjection());
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  // Disabling projection touch HUD shoud remove it without crashing.
+  DisableTouchHudProjection();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+}
+
+// Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
+// and touch-cancelled events.
+TEST_F(TouchHudProjectionTest, TouchMoveCancel) {
+  SetupSingleDisplay();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+
+  EnableTouchHudProjection();
+  EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL),
+            GetInternalTouchHudProjection());
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  // Disabling projection touch HUD shoud remove it without crashing.
+  DisableTouchHudProjection();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+}
+
+// Checks projection touch HUD with two simultaneous touches.
+TEST_F(TouchHudProjectionTest, DoubleTouch) {
+  SetupSingleDisplay();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+
+  EnableTouchHudProjection();
+  EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL),
+            GetInternalTouchHudProjection());
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2);
+  EXPECT_EQ(2, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(2, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2);
+  EXPECT_EQ(2, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2);
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  // Disabling projection touch HUD shoud remove it without crashing.
+  DisableTouchHudProjection();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+}
+
+// Checks if turning off touch HUD projection while touching the screen is
+// handled correctly.
+TEST_F(TouchHudProjectionTest, DisableWhileTouching) {
+  SetupSingleDisplay();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+
+  EnableTouchHudProjection();
+  EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL),
+            GetInternalTouchHudProjection());
+  EXPECT_EQ(0, GetInternalTouchPointsCount());
+
+  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
+  EXPECT_EQ(1, GetInternalTouchPointsCount());
+
+  // Disabling projection touch HUD shoud remove it without crashing.
+  DisableTouchHudProjection();
+  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
+}
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/wm/app_list_controller.cc b/ash/wm/app_list_controller.cc
index a6549c2..df3f724 100644
--- a/ash/wm/app_list_controller.cc
+++ b/ash/wm/app_list_controller.cc
@@ -163,7 +163,7 @@
     // will be released with AppListView on close.
     app_list::AppListView* view = new app_list::AppListView(
         Shell::GetInstance()->delegate()->CreateAppListViewDelegate());
-    aura::RootWindow* root_window = window->GetRootWindow();
+    aura::Window* root_window = window->GetRootWindow();
     aura::Window* container = GetRootWindowController(root_window)->
         GetContainer(kShellWindowId_AppListContainer);
     if (ash::switches::UseAlternateShelfLayout()) {
@@ -369,15 +369,15 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // AppListController, ShellObserver implementation:
-void AppListController::OnShelfAlignmentChanged(aura::RootWindow* root_window) {
+void AppListController::OnShelfAlignmentChanged(aura::Window* root_window) {
   if (view_)
     view_->SetBubbleArrow(GetBubbleArrow(view_->GetWidget()->GetNativeView()));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// AppListController, LauncherIconObserver implementation:
+// AppListController, ShelfIconObserver implementation:
 
-void AppListController::OnLauncherIconPositionsChanged() {
+void AppListController::OnShelfIconPositionsChanged() {
   UpdateBounds();
 }
 
diff --git a/ash/wm/app_list_controller.h b/ash/wm/app_list_controller.h
index f47c7a4..2e41758 100644
--- a/ash/wm/app_list_controller.h
+++ b/ash/wm/app_list_controller.h
@@ -5,7 +5,7 @@
 #ifndef ASH_WM_APP_LIST_CONTROLLER_H_
 #define ASH_WM_APP_LIST_CONTROLLER_H_
 
-#include "ash/launcher/launcher_icon_observer.h"
+#include "ash/shelf/shelf_icon_observer.h"
 #include "ash/shell_observer.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -45,7 +45,7 @@
                           public ui::ImplicitAnimationObserver,
                           public views::WidgetObserver,
                           public ShellObserver,
-                          public LauncherIconObserver,
+                          public ShelfIconObserver,
                           public app_list::PaginationModelObserver {
  public:
   AppListController();
@@ -111,10 +111,10 @@
   virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE;
 
   // ShellObserver overrides:
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
+  virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE;
 
-  // LauncherIconObserver overrides:
-  virtual void OnLauncherIconPositionsChanged() OVERRIDE;
+  // ShelfIconObserver overrides:
+  virtual void OnShelfIconPositionsChanged() OVERRIDE;
 
   // app_list::PaginationModelObserver overrides:
   virtual void TotalPagesChanged() OVERRIDE;
diff --git a/ash/wm/ash_focus_rules.cc b/ash/wm/ash_focus_rules.cc
index e6688d7..02b2d02 100644
--- a/ash/wm/ash_focus_rules.cc
+++ b/ash/wm/ash_focus_rules.cc
@@ -105,7 +105,7 @@
   int starting_container_index = 0;
   // If the container of the window losing focus is in the list, start from that
   // container.
-  aura::RootWindow* root = ignore->GetRootWindow();
+  aura::Window* root = ignore->GetRootWindow();
   if (!root)
     root = Shell::GetTargetRootWindow();
   int container_count = static_cast<int>(arraysize(kWindowContainerIds));
@@ -137,7 +137,7 @@
     int index,
     aura::Window* ignore) const {
   aura::Window* window = NULL;
-  aura::RootWindow* root = ignore ? ignore->GetRootWindow() : NULL;
+  aura::Window* root = ignore ? ignore->GetRootWindow() : NULL;
   aura::Window::Windows containers = Shell::GetContainersFromAllRootWindows(
       kWindowContainerIds[index], root);
   for (aura::Window::Windows::const_iterator iter = containers.begin();
diff --git a/ash/wm/ash_native_cursor_manager_unittest.cc b/ash/wm/ash_native_cursor_manager_unittest.cc
index 113e624..76da49d 100644
--- a/ash/wm/ash_native_cursor_manager_unittest.cc
+++ b/ash/wm/ash_native_cursor_manager_unittest.cc
@@ -173,7 +173,7 @@
 }
 
 TEST_F(AshNativeCursorManagerTest, DisabledQueryMouseLocation) {
-  aura::RootWindow* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
 #if defined(OS_WIN)
   if (base::win::GetVersion() < base::win::VERSION_WIN8)
     return;
@@ -193,11 +193,12 @@
   Sleep(100);
   RunAllPendingInMessageLoop();
 #endif
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
   gfx::Point mouse_location;
-  EXPECT_TRUE(root_window->QueryMouseLocationForTest(&mouse_location));
+  EXPECT_TRUE(dispatcher->QueryMouseLocationForTest(&mouse_location));
   EXPECT_EQ("10,10", mouse_location.ToString());
   Shell::GetInstance()->cursor_manager()->DisableMouseEvents();
-  EXPECT_FALSE(root_window->QueryMouseLocationForTest(&mouse_location));
+  EXPECT_FALSE(dispatcher->QueryMouseLocationForTest(&mouse_location));
   EXPECT_EQ("0,0", mouse_location.ToString());
 }
 
diff --git a/ash/wm/base_layout_manager.cc b/ash/wm/base_layout_manager.cc
index 90c0d97..65fb820 100644
--- a/ash/wm/base_layout_manager.cc
+++ b/ash/wm/base_layout_manager.cc
@@ -15,7 +15,6 @@
 #include "ash/wm/workspace/workspace_window_resizer.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/layer.h"
@@ -29,7 +28,7 @@
 /////////////////////////////////////////////////////////////////////////////
 // BaseLayoutManager, public:
 
-BaseLayoutManager::BaseLayoutManager(aura::RootWindow* root_window)
+BaseLayoutManager::BaseLayoutManager(aura::Window* root_window)
     : root_window_(root_window) {
   Shell::GetInstance()->activation_client()->AddObserver(this);
   Shell::GetInstance()->AddShellObserver(this);
diff --git a/ash/wm/base_layout_manager.h b/ash/wm/base_layout_manager.h
index 7a94bf3..6f74e4c 100644
--- a/ash/wm/base_layout_manager.h
+++ b/ash/wm/base_layout_manager.h
@@ -19,7 +19,6 @@
 #include "ui/events/event_handler.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -44,7 +43,7 @@
  public:
   typedef std::set<aura::Window*> WindowSet;
 
-  explicit BaseLayoutManager(aura::RootWindow* root_window);
+  explicit BaseLayoutManager(aura::Window* root_window);
   virtual ~BaseLayoutManager();
 
   const WindowSet& windows() const { return windows_; }
@@ -109,7 +108,7 @@
       wm::WindowState* window_state,
       AdjustWindowReason reason);
 
-  aura::RootWindow* root_window() { return root_window_; }
+  aura::Window* root_window() { return root_window_; }
 
  private:
   // Update window bounds based on a change in show state.
@@ -118,7 +117,7 @@
   // Set of windows we're listening to.
   WindowSet windows_;
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(BaseLayoutManager);
 };
diff --git a/ash/wm/caption_buttons/frame_maximize_button_unittest.cc b/ash/wm/caption_buttons/frame_maximize_button_unittest.cc
index 2eaa333..c2ea2e8 100644
--- a/ash/wm/caption_buttons/frame_maximize_button_unittest.cc
+++ b/ash/wm/caption_buttons/frame_maximize_button_unittest.cc
@@ -535,7 +535,7 @@
 
 TEST_F(FrameMaximizeButtonTest, MaximizeTap) {
   aura::Window* window = widget()->GetNativeWindow();
-  aura::RootWindow* root_window = window->GetRootWindow();
+  aura::Window* root_window = window->GetRootWindow();
   ash::FrameMaximizeButton* maximize_button =
       FrameMaximizeButtonTest::maximize_button();
   gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
@@ -544,12 +544,13 @@
       ui::GestureConfiguration::default_radius();
   ui::GestureConfiguration::set_default_radius(0);
 
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
   const int kTouchId = 2;
   ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
                        button_pos,
                        kTouchId,
                        ui::EventTimeForNow());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
 
   button_pos.Offset(9, 8);
   ui::TouchEvent release(
@@ -557,7 +558,7 @@
       button_pos,
       kTouchId,
       press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
 
   ui::GestureConfiguration::set_default_radius(touch_default_radius);
 }
diff --git a/ash/wm/coordinate_conversion.cc b/ash/wm/coordinate_conversion.cc
index 467a1fc..448bd0f 100644
--- a/ash/wm/coordinate_conversion.cc
+++ b/ash/wm/coordinate_conversion.cc
@@ -7,7 +7,6 @@
 #include "ash/display/display_controller.h"
 #include "ash/shell.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/point.h"
 #include "ui/gfx/rect.h"
@@ -16,7 +15,7 @@
 namespace ash {
 namespace wm {
 
-aura::RootWindow* GetRootWindowAt(const gfx::Point& point) {
+aura::Window* GetRootWindowAt(const gfx::Point& point) {
   const gfx::Display& display =
       Shell::GetScreen()->GetDisplayNearestPoint(point);
   DCHECK(display.is_valid());
@@ -26,7 +25,7 @@
       GetRootWindowForDisplayId(display.id());
 }
 
-aura::RootWindow* GetRootWindowMatching(const gfx::Rect& rect) {
+aura::Window* GetRootWindowMatching(const gfx::Rect& rect) {
   const gfx::Display& display = Shell::GetScreen()->GetDisplayMatching(rect);
   return Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display.id());
diff --git a/ash/wm/coordinate_conversion.h b/ash/wm/coordinate_conversion.h
index b1ee83c..f5c1af8 100644
--- a/ash/wm/coordinate_conversion.h
+++ b/ash/wm/coordinate_conversion.h
@@ -8,7 +8,6 @@
 #include "ash/ash_export.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }  // namespace gfx
 
@@ -23,11 +22,11 @@
 // Returns the RootWindow at |point| in the virtual screen coordinates.
 // Returns NULL if the root window does not exist at the given
 // point.
-ASH_EXPORT aura::RootWindow* GetRootWindowAt(const gfx::Point& point);
+ASH_EXPORT aura::Window* GetRootWindowAt(const gfx::Point& point);
 
 // Returns the RootWindow that shares the most area with |rect| in
 // the virtual scren coordinates.
-ASH_EXPORT aura::RootWindow* GetRootWindowMatching(const gfx::Rect& rect);
+ASH_EXPORT aura::Window* GetRootWindowMatching(const gfx::Rect& rect);
 
 // Converts the |point| from a given |window|'s coordinates into the screen
 // coordinates.
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index e30a94b..19f92f1 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -23,6 +23,7 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
@@ -104,23 +105,14 @@
 }
 
 void UndockWindow(aura::Window* window) {
-  aura::Window* focused =
-      aura::client::GetFocusClient(window)->GetFocusedWindow();
-  bool had_focus = window == focused || window->Contains(focused);
-  window->Hide();
-  window->layer()->GetAnimator()->StopAnimating();
   gfx::Rect previous_bounds = window->bounds();
   aura::Window* previous_parent = window->parent();
-  window->SetDefaultParentByRootWindow(window->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(window, window, gfx::Rect());
   if (window->parent() != previous_parent)
     wm::ReparentTransientChildrenOfChild(window->parent(), window);
-  // Animate maximize animation from previous window bounds.
-  if (wm::GetWindowState(window)->IsMaximized())
-    window->layer()->SetBounds(previous_bounds);
-  window->Show();
-  // Restore focus if the window had it before.
-  if (had_focus && !wm::GetWindowState(window)->IsFullscreen())
-    focused->Focus();
+  // Start maximize or fullscreen (affecting packaged apps) animation from
+  // previous window bounds.
+  window->layer()->SetBounds(previous_bounds);
 }
 
 // Returns width that is as close as possible to |target_width| while being
@@ -479,6 +471,7 @@
   child->RemoveObserver(this);
   wm::GetWindowState(child)->RemoveObserver(this);
   Relayout();
+  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
 }
 
 void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
@@ -509,7 +502,7 @@
 }
 
 void DockedWindowLayoutManager::OnFullscreenStateChanged(
-    bool is_fullscreen, aura::RootWindow* root_window) {
+    bool is_fullscreen, aura::Window* root_window) {
   if (dock_container_->GetRootWindow() != root_window)
     return;
   // Entering fullscreen mode (including immersive) hides docked windows.
@@ -541,7 +534,7 @@
 }
 
 void DockedWindowLayoutManager::OnShelfAlignmentChanged(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   if (dock_container_->GetRootWindow() != root_window)
     return;
 
@@ -584,7 +577,7 @@
     // Reparenting changes the source bounds for the animation if a window is
     // visible so hide it here and show later when it is already in the desktop.
     UndockWindow(window);
-  } else {
+  } else if (old_type == wm::SHOW_TYPE_MINIMIZED) {
     RestoreDockedWindow(window_state);
   }
 }
diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h
index 29979d7..f380f77 100644
--- a/ash/wm/dock/docked_window_layout_manager.h
+++ b/ash/wm/dock/docked_window_layout_manager.h
@@ -143,8 +143,8 @@
   // ash::ShellObserver:
   virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE;
   virtual void OnFullscreenStateChanged(bool is_fullscreen,
-                                        aura::RootWindow* root_window) OVERRIDE;
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
+                                        aura::Window* root_window) OVERRIDE;
+  virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE;
 
   // wm::WindowStateObserver:
   virtual void OnWindowShowTypeChanged(wm::WindowState* window_state,
diff --git a/ash/wm/dock/docked_window_resizer.cc b/ash/wm/dock/docked_window_resizer.cc
index 218391a..28d0438 100644
--- a/ash/wm/dock/docked_window_resizer.cc
+++ b/ash/wm/dock/docked_window_resizer.cc
@@ -22,6 +22,7 @@
 #include "base/command_line.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
@@ -41,7 +42,7 @@
   gfx::Display display = ScreenAsh::FindDisplayContainingPoint(point);
   if (!display.is_valid())
     return NULL;
-  aura::RootWindow* root = Shell::GetInstance()->display_controller()->
+  aura::Window* root = Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display.id());
   aura::Window* dock_container = Shell::GetContainer(
       root, kShellWindowId_DockedContainer);
@@ -270,7 +271,7 @@
       wm::ReparentChildWithTransientChildren(dock_container, window);
     } else if (window->parent()->id() == kShellWindowId_DockedContainer) {
       // Reparent the window back to workspace.
-      // We need to be careful to give SetDefaultParentByRootWindow location in
+      // We need to be careful to give ParentWindowWithContext a location in
       // the right root window (matching the logic in DragWindowResizer) based
       // on which root window a mouse pointer is in. We want to undock into the
       // right screen near the edge of a multiscreen setup (based on where the
@@ -278,8 +279,7 @@
       gfx::Rect near_last_location(last_location_, gfx::Size());
       // Reparenting will cause Relayout and possible dock shrinking.
       aura::Window* previous_parent = window->parent();
-      window->SetDefaultParentByRootWindow(window->GetRootWindow(),
-                                           near_last_location);
+      aura::client::ParentWindowWithContext(window, window, near_last_location);
       if (window->parent() != previous_parent)
         wm::ReparentTransientChildrenOfChild(window->parent(), window);
     }
diff --git a/ash/wm/drag_window_controller.cc b/ash/wm/drag_window_controller.cc
index 01ae80f..937af3b 100644
--- a/ash/wm/drag_window_controller.cc
+++ b/ash/wm/drag_window_controller.cc
@@ -7,6 +7,7 @@
 #include "ash/shell_window_ids.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
diff --git a/ash/wm/drag_window_resizer.cc b/ash/wm/drag_window_resizer.cc
index 92b8755..5713cf8 100644
--- a/ash/wm/drag_window_resizer.cc
+++ b/ash/wm/drag_window_resizer.cc
@@ -12,6 +12,7 @@
 #include "ash/system/user/tray_user.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "ash/wm/drag_window_controller.h"
+#include "ash/wm/window_state.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
@@ -30,6 +31,9 @@
 // The maximum opacity of the drag phantom window.
 const float kMaxOpacity = 0.8f;
 
+// The opacity of the window when dragging it over a user item in the tray.
+const float kOpacityWhenDraggedOverUserIcon = 0.4f;
+
 // Returns true if Ash has more than one root window.
 bool HasSecondaryRootWindow() {
   return Shell::GetAllRootWindows().size() > 1;
@@ -37,7 +41,7 @@
 
 // When there are two root windows, returns one of the root windows which is not
 // |root_window|. Returns NULL if only one root window exists.
-aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) {
+aura::RootWindow* GetAnotherRootWindow(aura::Window* root_window) {
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
   if (root_windows.size() < 2)
     return NULL;
@@ -53,6 +57,8 @@
 DragWindowResizer* DragWindowResizer::instance_ = NULL;
 
 DragWindowResizer::~DragWindowResizer() {
+  if (GetTarget())
+    wm::GetWindowState(GetTarget())->set_window_resizer_(NULL);
   Shell* shell = Shell::GetInstance();
   shell->mouse_cursor_filter()->set_mouse_warp_mode(
       MouseCursorEventFilter::WARP_ALWAYS);
@@ -77,11 +83,12 @@
   base::WeakPtr<DragWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr());
 
   // If we are on top of a window to desktop transfer button, we move the window
-  // temporarily back to where it was initially (showing that we do something).
-  gfx::Point filtered_location = GetTrayUserItemAtPoint(location) ?
-      details_.initial_location_in_parent : location;
+  // temporarily back to where it was initially and make it semi-transparent.
+  GetTarget()->layer()->SetOpacity(
+      GetTrayUserItemAtPoint(location) ? kOpacityWhenDraggedOverUserIcon :
+                                         details_.initial_opacity);
 
-  next_window_resizer_->Drag(filtered_location, event_flags);
+  next_window_resizer_->Drag(location, event_flags);
 
   if (!resizer)
     return;
@@ -168,7 +175,7 @@
     return;
 
   // It's available. Show a phantom window on the display if needed.
-  aura::RootWindow* another_root =
+  aura::Window* another_root =
       GetAnotherRootWindow(GetTarget()->GetRootWindow());
   const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen());
   const gfx::Rect bounds_in_screen =
@@ -257,6 +264,7 @@
   // it's thing and return the transparency to its original value.
   int old_opacity = GetTarget()->layer()->opacity();
   GetTarget()->layer()->SetOpacity(0);
+  GetTarget()->SetBounds(details_.initial_bounds_in_parent);
   if (!tray_user->TransferWindowToUser(details_.window)) {
     GetTarget()->layer()->SetOpacity(old_opacity);
     return false;
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index a17f9b5..844cbaa 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -23,6 +23,13 @@
 #include "ui/gfx/screen.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(OS_CHROMEOS)
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/user/tray_user.h"
+#include "ash/test/test_session_state_delegate.h"
+#include "ash/test/test_shell_delegate.h"
+#endif
+
 namespace ash {
 namespace internal {
 namespace {
@@ -40,7 +47,7 @@
     AshTestBase::SetUp();
     UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
 
-    aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+    aura::Window* root = Shell::GetPrimaryRootWindow();
     gfx::Rect root_bounds(root->bounds());
     EXPECT_EQ(kRootHeight, root_bounds.height());
     EXPECT_EQ(800, root_bounds.width());
@@ -48,14 +55,14 @@
     window_.reset(new aura::Window(&delegate_));
     window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window_.get());
+    ParentWindowInPrimaryRootWindow(window_.get());
     window_->set_id(1);
 
     always_on_top_window_.reset(new aura::Window(&delegate2_));
     always_on_top_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     always_on_top_window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
     always_on_top_window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(always_on_top_window_.get());
+    ParentWindowInPrimaryRootWindow(always_on_top_window_.get());
     always_on_top_window_->set_id(2);
 
     system_modal_window_.reset(new aura::Window(&delegate3_));
@@ -63,26 +70,26 @@
     system_modal_window_->SetProperty(aura::client::kModalKey,
                                       ui::MODAL_TYPE_SYSTEM);
     system_modal_window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(system_modal_window_.get());
+    ParentWindowInPrimaryRootWindow(system_modal_window_.get());
     system_modal_window_->set_id(3);
 
     transient_child_ = new aura::Window(&delegate4_);
     transient_child_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     transient_child_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(transient_child_);
+    ParentWindowInPrimaryRootWindow(transient_child_);
     transient_child_->set_id(4);
 
     transient_parent_.reset(new aura::Window(&delegate5_));
     transient_parent_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     transient_parent_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(transient_parent_.get());
+    ParentWindowInPrimaryRootWindow(transient_parent_.get());
     transient_parent_->AddTransientChild(transient_child_);
     transient_parent_->set_id(5);
 
     panel_window_.reset(new aura::Window(&delegate6_));
     panel_window_->SetType(aura::client::WINDOW_TYPE_PANEL);
     panel_window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(panel_window_.get());
+    ParentWindowInPrimaryRootWindow(panel_window_.get());
   }
 
   virtual void TearDown() OVERRIDE {
@@ -227,7 +234,7 @@
   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window.get());
+  ParentWindowInPrimaryRootWindow(window.get());
   window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
                             Shell::GetScreen()->GetPrimaryDisplay());
   window->Show();
@@ -566,5 +573,92 @@
   }
 }
 
+#if defined(OS_CHROMEOS)
+// Checks that moving a window to another desktop will properly set and reset
+// the transparency.
+TEST_F(DragWindowResizerTest, DragToOtherDesktopOpacity) {
+  // Set up a few things we need for multi profile.
+  ash::test::TestSessionStateDelegate* session_delegate =
+      static_cast<ash::test::TestSessionStateDelegate*>(
+          ash::Shell::GetInstance()->session_state_delegate());
+  session_delegate->set_logged_in_users(2);
+  ash::test::TestShellDelegate* shell_delegate =
+      static_cast<ash::test::TestShellDelegate*>(
+          ash::Shell::GetInstance()->delegate());
+  shell_delegate->set_multi_profiles_enabled(true);
+
+  // Create one other user where we can drag our stuff onto.
+  SystemTray* tray = Shell::GetPrimaryRootWindowController()->GetSystemTray();
+  TrayUser* tray_user = new TrayUser(tray, 1);
+  tray->AddTrayUserItemForTest(tray_user);
+
+  // Move the view somewhere where we can hit it.
+  views::View* view = tray->GetTrayItemViewForTest(tray_user);
+  view->SetBounds(80, 0, 20, 20);
+  gfx::Point center = view->GetBoundsInScreen().CenterPoint();
+
+  gfx::Rect initial_bounds = gfx::Rect(0, 0, 50, 60);
+  // Drag the window over the icon and let it drop. Test that the window's
+  // layer gets transparent and reverts back.
+  {
+    aura::Window* window = window_.get();
+    window->SetBoundsInScreen(initial_bounds,
+                              Shell::GetScreen()->GetPrimaryDisplay());
+    // Grab (0, 0) of the window.
+    scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
+        window, gfx::Point(), HTCAPTION));
+    ASSERT_TRUE(resizer.get());
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    resizer->Drag(center, 0);
+    EXPECT_NE(1.0, window->layer()->opacity());
+    EXPECT_EQ(0, session_delegate->num_transfer_to_desktop_of_user_calls());
+    resizer->CompleteDrag(0);
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    EXPECT_EQ(1, session_delegate->num_transfer_to_desktop_of_user_calls());
+    EXPECT_EQ(initial_bounds.ToString(), window->bounds().ToString());
+  }
+
+  // Drag the window over the icon and cancel the operation. Test that the
+  // window's layer gets transparent and reverts back.
+  {
+    aura::Window* window = window_.get();
+    window->SetBoundsInScreen(initial_bounds,
+                              Shell::GetScreen()->GetPrimaryDisplay());
+    // Grab (0, 0) of the window.
+    scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
+        window, gfx::Point(), HTCAPTION));
+    ASSERT_TRUE(resizer.get());
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    resizer->Drag(center, 0);
+    EXPECT_NE(1.0, window->layer()->opacity());
+    resizer->RevertDrag();
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    EXPECT_EQ(1, session_delegate->num_transfer_to_desktop_of_user_calls());
+    EXPECT_EQ(initial_bounds.ToString(), window->bounds().ToString());
+  }
+
+  // Drag the window over the icon and somewhere else and see that it properly
+  // reverts its transparency.
+  {
+    aura::Window* window = window_.get();
+    window->SetBoundsInScreen(initial_bounds,
+                              Shell::GetScreen()->GetPrimaryDisplay());
+    // Grab (0, 0) of the window.
+    scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
+        window, gfx::Point(), HTCAPTION));
+    ASSERT_TRUE(resizer.get());
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    resizer->Drag(center, 0);
+    EXPECT_NE(1.0, window->layer()->opacity());
+    resizer->Drag(gfx::Point(), 0);
+    EXPECT_EQ(1.0, window->layer()->opacity());
+    resizer->CompleteDrag(0);
+    EXPECT_EQ(1, session_delegate->num_transfer_to_desktop_of_user_calls());
+    EXPECT_NE(initial_bounds.ToString(), window->bounds().ToString());
+  }
+}
+#endif
+
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/wm/event_client_impl.cc b/ash/wm/event_client_impl.cc
index 03d4dea..fbf5f86 100644
--- a/ash/wm/event_client_impl.cc
+++ b/ash/wm/event_client_impl.cc
@@ -21,7 +21,7 @@
 
 bool EventClientImpl::CanProcessEventsWithinSubtree(
     const aura::Window* window) const {
-  const aura::RootWindow* root_window = window ? window->GetRootWindow() : NULL;
+  const aura::Window* root_window = window ? window->GetRootWindow() : NULL;
   if (!root_window ||
       !Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked()) {
     return true;
diff --git a/ash/wm/event_client_impl.h b/ash/wm/event_client_impl.h
index 897e881..b38228b 100644
--- a/ash/wm/event_client_impl.h
+++ b/ash/wm/event_client_impl.h
@@ -6,12 +6,10 @@
 #define ASH_WM_EVENT_CLIENT_IMPL_H_
 
 #include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
 #include "ui/aura/client/event_client.h"
 
-namespace aura {
-class RootWindow;
-}
-
 namespace ash {
 namespace internal {
 
diff --git a/ash/wm/gestures/long_press_affordance_handler.cc b/ash/wm/gestures/long_press_affordance_handler.cc
index aae7e1a..8faa78f 100644
--- a/ash/wm/gestures/long_press_affordance_handler.cc
+++ b/ash/wm/gestures/long_press_affordance_handler.cc
@@ -59,7 +59,7 @@
 const SkColor kAffordanceArcColor = SkColorSetARGB(80, 0, 0, 0);
 const int kAffordanceFrameRateHz = 60;
 
-views::Widget* CreateAffordanceWidget(aura::RootWindow* root_window) {
+views::Widget* CreateAffordanceWidget(aura::Window* root_window) {
   views::Widget* widget = new views::Widget;
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
@@ -140,7 +140,7 @@
     : public views::View {
  public:
   LongPressAffordanceView(const gfx::Point& event_location,
-                          aura::RootWindow* root_window)
+                          aura::Window* root_window)
       : views::View(),
         widget_(CreateAffordanceWidget(root_window)),
         current_angle_(kAffordanceAngleStartValue),
@@ -272,6 +272,7 @@
           event->root_location(), tap_down_location_))
         StopAnimation();
       break;
+    case ui::ET_GESTURE_SHOW_PRESS:
     case ui::ET_TOUCH_CANCELLED:
     case ui::ET_GESTURE_END:
       // We will stop the animation on TOUCH_RELEASED.
@@ -291,7 +292,7 @@
 // LongPressAffordanceHandler, private
 
 void LongPressAffordanceHandler::StartAnimation() {
-  aura::RootWindow* root_window = NULL;
+  aura::Window* root_window = NULL;
   switch (current_animation_type_) {
     case GROW_ANIMATION:
       root_window = Shell::GetInstance()->display_controller()->
diff --git a/ash/wm/gestures/shelf_gesture_handler.cc b/ash/wm/gestures/shelf_gesture_handler.cc
index 463c282..9dcd3f2 100644
--- a/ash/wm/gestures/shelf_gesture_handler.cc
+++ b/ash/wm/gestures/shelf_gesture_handler.cc
@@ -12,7 +12,7 @@
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/wm/gestures/tray_gesture_handler.h"
-#include "ash/wm/window_properties.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
@@ -43,11 +43,11 @@
 
   ShelfLayoutManager* shelf = controller->GetShelfLayoutManager();
 
-  // The gesture are disabled for fullscreen windows that are not in immersive
-  // mode.
   const aura::Window* fullscreen = controller->GetTopmostFullscreenWindow();
-  if (fullscreen && !shelf->FullscreenWithMinimalChrome())
+  if (fullscreen &&
+      ash::wm::GetWindowState(fullscreen)->hide_shelf_when_fullscreen()) {
     return false;
+  }
 
   if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) {
     drag_in_progress_ = true;
diff --git a/ash/wm/gestures/two_finger_drag_handler.cc b/ash/wm/gestures/two_finger_drag_handler.cc
index f4d2e68..5cf98a6 100644
--- a/ash/wm/gestures/two_finger_drag_handler.cc
+++ b/ash/wm/gestures/two_finger_drag_handler.cc
@@ -74,7 +74,8 @@
 namespace internal {
 
 TwoFingerDragHandler::TwoFingerDragHandler()
-    : first_finger_hittest_(HTNOWHERE) {
+    : first_finger_hittest_(HTNOWHERE),
+      in_gesture_drag_(false) {
 }
 
 TwoFingerDragHandler::~TwoFingerDragHandler() {
@@ -96,11 +97,14 @@
 
   if (event.type() == ui::ET_GESTURE_BEGIN &&
       event.details().touch_points() == 2) {
-    if (!window_resizer_.get() && window_state->IsNormalShowState() &&
+    if (!in_gesture_drag_ && window_state->IsNormalShowState() &&
       target->type() == aura::client::WINDOW_TYPE_NORMAL) {
       if (WindowComponentsAllowMoving(first_finger_hittest_,
           target->delegate()->GetNonClientComponent(event.location()))) {
+        in_gesture_drag_ = true;
         target->AddObserver(this);
+        // Only create a new WindowResizer if one doesn't already exist
+        // for the target window.
         window_resizer_ = CreateWindowResizer(
             target,
             event.details().bounding_box().CenterPoint(),
@@ -113,20 +117,28 @@
     return false;
   }
 
-  if (!window_resizer_) {
+  if (!in_gesture_drag_) {
     // Consume all two-finger gestures on a normal window.
     return event.details().touch_points() == 2 &&
            target->type() == aura::client::WINDOW_TYPE_NORMAL &&
            window_state->IsNormalShowState();
   }
+  // Since |in_gesture_drag_| is true a resizer was either created above or
+  // it was created elsewhere and can be found in |window_state|.
+  WindowResizer* any_window_resizer = window_resizer_ ?
+      window_resizer_.get() : window_state->window_resizer();
+  DCHECK(any_window_resizer);
 
-  if (target != window_resizer_->GetTarget())
+  if (target != any_window_resizer->GetTarget())
     return false;
 
   switch (event.type()) {
     case ui::ET_GESTURE_BEGIN:
-      if (event.details().touch_points() > 2)
-        Reset();
+      if (event.details().touch_points() > 2) {
+        if (window_resizer_)
+          window_resizer_->CompleteDrag(event.flags());
+        Reset(target);
+      }
       return false;
 
     case ui::ET_GESTURE_SCROLL_BEGIN:
@@ -136,8 +148,10 @@
 
     case ui::ET_GESTURE_MULTIFINGER_SWIPE: {
       // For a swipe, the window either maximizes, minimizes, or snaps. In this
-      // case, cancel the drag, and do the appropriate action.
-      Reset();
+      // case, complete the drag, and do the appropriate action.
+      if (window_resizer_)
+        window_resizer_->CompleteDrag(event.flags());
+      Reset(target);
       if (event.details().swipe_up()) {
         if (window_state->CanMaximize())
           window_state->Maximize();
@@ -157,19 +171,21 @@
 
     case ui::ET_GESTURE_PINCH_UPDATE:
     case ui::ET_GESTURE_SCROLL_UPDATE:
-      window_resizer_->Drag(event.details().bounding_box().CenterPoint(),
-                            event.flags());
+      any_window_resizer->Drag(event.details().bounding_box().CenterPoint(),
+                               event.flags());
       return true;
 
     case ui::ET_GESTURE_PINCH_END:
-      window_resizer_->CompleteDrag(event.flags());
-      Reset();
+      if (window_resizer_)
+        window_resizer_->CompleteDrag(event.flags());
+      Reset(target);
       return true;
 
     case ui::ET_GESTURE_END:
       if (event.details().touch_points() == 2) {
-        window_resizer_->RevertDrag();
-        Reset();
+        if (window_resizer_)
+          window_resizer_->RevertDrag();
+        Reset(target);
         return true;
       }
       break;
@@ -181,18 +197,19 @@
   return false;
 }
 
-void TwoFingerDragHandler::Reset() {
-  window_resizer_->GetTarget()->RemoveObserver(this);
+void TwoFingerDragHandler::Reset(aura::Window* window) {
+  window->RemoveObserver(this);
   window_resizer_.reset();
+  in_gesture_drag_ = false;
 }
 
 void TwoFingerDragHandler::OnWindowVisibilityChanged(aura::Window* window,
                                                      bool visible) {
-  Reset();
+  Reset(window);
 }
 
 void TwoFingerDragHandler::OnWindowDestroying(aura::Window* window) {
-  Reset();
+  Reset(window);
 }
 
 }  // namespace internal
diff --git a/ash/wm/gestures/two_finger_drag_handler.h b/ash/wm/gestures/two_finger_drag_handler.h
index 06cb86d..11b7f51 100644
--- a/ash/wm/gestures/two_finger_drag_handler.h
+++ b/ash/wm/gestures/two_finger_drag_handler.h
@@ -35,7 +35,7 @@
   bool ProcessGestureEvent(aura::Window* target, const ui::GestureEvent& event);
 
  private:
-  void Reset();
+  void Reset(aura::Window* window);
 
   // Overridden from aura::WindowObserver.
   virtual void OnWindowVisibilityChanged(aura::Window* window,
@@ -44,6 +44,9 @@
 
   int first_finger_hittest_;
 
+  // Set to true while a drag initiated with two-finger gesture is in progress.
+  bool in_gesture_drag_;
+
   scoped_ptr<WindowResizer> window_resizer_;
 
   DISALLOW_COPY_AND_ASSIGN(TwoFingerDragHandler);
diff --git a/ash/wm/header_painter.cc b/ash/wm/header_painter.cc
index 99f8515..3f8f2fe 100644
--- a/ash/wm/header_painter.cc
+++ b/ash/wm/header_painter.cc
@@ -22,7 +22,6 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/layout.h"
@@ -172,7 +171,7 @@
 
 // Returns a list of windows in |root_window|| that potentially could have
 // a transparent solo-window header.
-std::vector<Window*> GetWindowsForSoloHeaderUpdate(RootWindow* root_window) {
+std::vector<Window*> GetWindowsForSoloHeaderUpdate(Window* root_window) {
   std::vector<Window*> windows;
   // Avoid memory allocations for typical window counts.
   windows.reserve(16);
@@ -274,7 +273,7 @@
 }
 
 // static
-void HeaderPainter::UpdateSoloWindowHeader(RootWindow* root_window) {
+void HeaderPainter::UpdateSoloWindowHeader(Window* root_window) {
   // Use a separate function here so callers outside of HeaderPainter don't need
   // to know about "ignorable_window".
   UpdateSoloWindowInRoot(root_window, NULL /* ignorable_window */);
@@ -690,15 +689,15 @@
   // Don't use transparent headers for panels, pop-ups, etc.
   if (!IsSoloWindowHeaderCandidate(window_))
     return false;
-  aura::RootWindow* root = window_->GetRootWindow();
+  aura::Window* root = window_->GetRootWindow();
   // Don't recompute every time, as it would require many window property
   // lookups.
   return internal::GetRootWindowSettings(root)->solo_window_header;
 }
 
 // static
-bool HeaderPainter::UseSoloWindowHeaderInRoot(RootWindow* root_window,
-                                             Window* ignore_window) {
+bool HeaderPainter::UseSoloWindowHeaderInRoot(Window* root_window,
+                                              Window* ignore_window) {
   int visible_window_count = 0;
   std::vector<Window*> windows = GetWindowsForSoloHeaderUpdate(root_window);
   for (std::vector<Window*>::const_iterator it = windows.begin();
@@ -722,8 +721,8 @@
 }
 
 // static
-void HeaderPainter::UpdateSoloWindowInRoot(RootWindow* root,
-                                          Window* ignore_window) {
+void HeaderPainter::UpdateSoloWindowInRoot(Window* root,
+                                           Window* ignore_window) {
 #if defined(OS_WIN)
   // Non-Ash Windows doesn't do solo-window counting for transparency effects,
   // as the desktop background and window frames are managed by the OS.
diff --git a/ash/wm/header_painter.h b/ash/wm/header_painter.h
index 0d6c3d8..bdc5dbf 100644
--- a/ash/wm/header_painter.h
+++ b/ash/wm/header_painter.h
@@ -16,7 +16,6 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 namespace gfx {
@@ -69,7 +68,7 @@
 
   // Updates the solo-window transparent header appearance for all windows
   // using frame painters in |root_window|.
-  static void UpdateSoloWindowHeader(aura::RootWindow* root_window);
+  static void UpdateSoloWindowHeader(aura::Window* root_window);
 
   // Returns the bounds of the client view for a window with |header_height|
   // and |window_bounds|. The return value and |window_bounds| are in the
@@ -198,7 +197,7 @@
   // Returns true if |root_window| has exactly one visible, normal-type window.
   // It ignores |ignore_window| while calculating the number of windows.
   // Pass NULL for |ignore_window| to consider all windows.
-  static bool UseSoloWindowHeaderInRoot(aura::RootWindow* root_window,
+  static bool UseSoloWindowHeaderInRoot(aura::Window* root_window,
                                         aura::Window* ignore_window);
 
   // Updates the solo-window transparent header appearance for all windows in
@@ -206,7 +205,7 @@
   // counting visible windows. This is useful for updates when a window is about
   // to be closed or is moving to another root. If the solo window status
   // changes it schedules paints as necessary.
-  static void UpdateSoloWindowInRoot(aura::RootWindow* root_window,
+  static void UpdateSoloWindowInRoot(aura::Window* root_window,
                                      aura::Window* ignore_window);
 
   // Schedules a paint for the header. Used when transitioning from no header to
diff --git a/ash/wm/header_painter_unittest.cc b/ash/wm/header_painter_unittest.cc
index 4691911..55f0ff7 100644
--- a/ash/wm/header_painter_unittest.cc
+++ b/ash/wm/header_painter_unittest.cc
@@ -17,6 +17,7 @@
 #include "grit/ash_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/hit_test.h"
@@ -207,7 +208,7 @@
 TEST_F(HeaderPainterTest, CreateAndDeleteSingleWindow) {
   // Ensure that creating/deleting a window works well and doesn't cause
   // crashes.  See crbug.com/155634
-  aura::RootWindow* root = Shell::GetTargetRootWindow();
+  aura::Window* root = Shell::GetTargetRootWindow();
 
   scoped_ptr<Widget> widget(CreateTestWidget());
   scoped_ptr<HeaderPainter> painter(CreateTestPainter(widget.get()));
@@ -395,8 +396,8 @@
   scoped_ptr<aura::Window> window(new aura::Window(NULL));
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_NOT_DRAWN);
-  window->SetDefaultParentByRootWindow(
-      widget->GetNativeWindow()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(window.get(), widget->GetNativeWindow(),
+                                        gfx::Rect());
   window->Show();
 
   // Despite two windows, the first window should still be considered "solo"
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 6117224..11b840b 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -27,7 +27,7 @@
 namespace {
 
 aura::Window* GetBackground() {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   return Shell::GetContainer(root_window,
       internal::kShellWindowId_DesktopBackgroundContainer);
 }
@@ -156,11 +156,12 @@
       shutdown_after_lock_(false),
       animating_lock_(false),
       can_cancel_lock_animation_(false) {
-  Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this);
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->AddRootWindowObserver(this);
 }
 
 LockStateController::~LockStateController() {
-  Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this);
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->RemoveRootWindowObserver(
+      this);
 }
 
 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc
index 001a5f7..425f439 100644
--- a/ash/wm/lock_state_controller_unittest.cc
+++ b/ash/wm/lock_state_controller_unittest.cc
@@ -46,7 +46,7 @@
 }
 
 aura::Window* GetContainer(int container ) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   return Shell::GetContainer(root_window, container);
 }
 
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 8ff631b..5974aad 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -23,9 +23,9 @@
 
 // Adds the windows that can be cycled through for the specified window id to
 // |windows|.
-void AddTrackedWindows(aura::RootWindow* root,
-                     int container_id,
-                     MruWindowTracker::WindowList* windows) {
+void AddTrackedWindows(aura::Window* root,
+                       int container_id,
+                       MruWindowTracker::WindowList* windows) {
   aura::Window* container = Shell::GetContainer(root, container_id);
   const MruWindowTracker::WindowList& children(container->children());
   windows->insert(windows->end(), children.begin(), children.end());
@@ -59,7 +59,7 @@
   MruWindowTracker::WindowList windows;
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
 
-  aura::RootWindow* active_root = Shell::GetTargetRootWindow();
+  aura::Window* active_root = Shell::GetTargetRootWindow();
   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
        iter != root_windows.end(); ++iter) {
     if (*iter == active_root)
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index d51a56e..dc82e6e 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -6,135 +6,19 @@
 
 #include "ash/screen_ash.h"
 #include "ash/shell.h"
+#include "ash/wm/overview/scoped_window_copy.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
-#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/interpolated_transform.h"
-#include "ui/gfx/transform_util.h"
-#include "ui/views/corewm/shadow_types.h"
 #include "ui/views/corewm/window_animations.h"
-#include "ui/views/corewm/window_util.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
 
 namespace {
 
-// Creates a copy of |window| with |recreated_layer| in the |target_root|.
-views::Widget* CreateCopyOfWindow(aura::RootWindow* target_root,
-                                  aura::Window* src_window,
-                                  ui::Layer* recreated_layer) {
-  // Save and remove the transform from the layer to later reapply to both the
-  // source and newly created copy window.
-  gfx::Transform transform = recreated_layer->transform();
-  recreated_layer->SetTransform(gfx::Transform());
-
-  src_window->SetTransform(transform);
-  views::Widget* widget = new views::Widget;
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params.parent = src_window->parent();
-  params.can_activate = false;
-  params.keep_on_top = true;
-  widget->set_focus_on_creation(false);
-  widget->Init(params);
-  widget->SetVisibilityChangedAnimationsEnabled(false);
-  std::string name = src_window->name() + " (Copy)";
-  widget->GetNativeWindow()->SetName(name);
-  views::corewm::SetShadowType(widget->GetNativeWindow(),
-                               views::corewm::SHADOW_TYPE_RECTANGULAR);
-
-  // Set the bounds in the target root window.
-  gfx::Display target_display =
-      Shell::GetScreen()->GetDisplayNearestWindow(target_root);
-  aura::client::ScreenPositionClient* screen_position_client =
-      aura::client::GetScreenPositionClient(src_window->GetRootWindow());
-  if (screen_position_client && target_display.is_valid()) {
-    screen_position_client->SetBounds(widget->GetNativeWindow(),
-        src_window->GetBoundsInScreen(), target_display);
-  } else {
-    widget->SetBounds(src_window->GetBoundsInScreen());
-  }
-  widget->StackAbove(src_window);
-
-  // Move the |recreated_layer| to the newly created window.
-  recreated_layer->set_delegate(src_window->layer()->delegate());
-  gfx::Rect layer_bounds = recreated_layer->bounds();
-  layer_bounds.set_origin(gfx::Point(0, 0));
-  recreated_layer->SetBounds(layer_bounds);
-  recreated_layer->SetVisible(false);
-  recreated_layer->parent()->Remove(recreated_layer);
-
-  aura::Window* window = widget->GetNativeWindow();
-  recreated_layer->SetVisible(true);
-  window->layer()->Add(recreated_layer);
-  window->layer()->StackAtTop(recreated_layer);
-  window->layer()->SetOpacity(1);
-  window->SetTransform(transform);
-  window->Show();
-  return widget;
-}
-
-// An observer which closes the widget and deletes the layer after an
-// animation finishes.
-class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver {
- public:
-  CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer);
-
-  // ui::LayerAnimationObserver:
-  virtual void OnLayerAnimationEnded(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-  virtual void OnLayerAnimationAborted(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-  virtual void OnLayerAnimationScheduled(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-
- private:
-  virtual ~CleanupWidgetAfterAnimationObserver();
-
-  views::Widget* widget_;
-  ui::Layer* layer_;
-
-  DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver);
-};
-
-CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver(
-        views::Widget* widget,
-        ui::Layer* layer)
-    : widget_(widget),
-      layer_(layer) {
-  widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this);
-}
-
-void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded(
-    ui::LayerAnimationSequence* sequence) {
-  delete this;
-}
-
-void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted(
-    ui::LayerAnimationSequence* sequence) {
-  delete this;
-}
-
-void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled(
-    ui::LayerAnimationSequence* sequence) {
-}
-
-CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {
-  widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this);
-  widget_->Close();
-  widget_ = NULL;
-  if (layer_) {
-    views::corewm::DeepDeleteLayers(layer_);
-    layer_ = NULL;
-  }
-}
-
 // The animation settings used for window selector animations.
 class WindowSelectorAnimationSettings
     : public ui::ScopedLayerAnimationSettings {
@@ -203,8 +87,6 @@
 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
         aura::Window* window)
     : window_(window),
-      window_copy_(NULL),
-      layer_(NULL),
       minimized_(window->GetProperty(aura::client::kShowStateKey) ==
                  ui::SHOW_STATE_MINIMIZED),
       ignored_by_shelf_(ash::wm::GetWindowState(window)->ignored_by_shelf()),
@@ -216,15 +98,7 @@
   if (window_) {
     WindowSelectorAnimationSettings animation_settings(window_);
     gfx::Transform transform;
-    // If the initial window wasn't destroyed and we have copied the window
-    // layer, the copy needs to be animated out.
-    // CleanupWidgetAfterAnimationObserver will destroy the widget and
-    // layer after the animation is complete.
-    if (window_copy_)
-      new CleanupWidgetAfterAnimationObserver(window_copy_, layer_);
     SetTransformOnWindowAndTransientChildren(original_transform_, true);
-    window_copy_ = NULL;
-    layer_ = NULL;
     if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) !=
         ui::SHOW_STATE_MINIMIZED) {
       // Setting opacity 0 and visible false ensures that the property change
@@ -239,20 +113,15 @@
                            ui::SHOW_STATE_MINIMIZED);
     }
     ash::wm::GetWindowState(window_)->set_ignored_by_shelf(ignored_by_shelf_);
-  } else if (window_copy_) {
-    // If this class still owns a copy of the window, clean up the copy. This
-    // will be the case if the window was destroyed.
-    window_copy_->Close();
-    if (layer_)
-      views::corewm::DeepDeleteLayers(layer_);
-    window_copy_ = NULL;
-    layer_ = NULL;
   }
 }
 
 bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const {
-  if (window_copy_ && window_copy_->GetNativeWindow()->Contains(target))
-    return true;
+  for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
+      window_copies_.begin(); iter != window_copies_.end(); ++iter) {
+    if ((*iter)->GetWindow()->Contains(target))
+      return true;
+  }
   aura::Window* window = window_;
   while (window) {
     if (window->Contains(target))
@@ -289,55 +158,78 @@
   window_ = NULL;
 }
 
-gfx::Transform ScopedTransformOverviewWindow::
-    GetTransformForRectPreservingAspectRatio(const gfx::Rect& rect,
-                                             const gfx::Rect& bounds) {
+gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
+    const gfx::Rect& rect,
+    const gfx::Rect& bounds) {
   DCHECK(!rect.IsEmpty());
   DCHECK(!bounds.IsEmpty());
   float scale = std::min(1.0f,
       std::min(static_cast<float>(bounds.width()) / rect.width(),
                static_cast<float>(bounds.height()) / rect.height()));
+  return gfx::Rect(bounds.x() + 0.5 * (bounds.width() - scale * rect.width()),
+                   bounds.y() + 0.5 * (bounds.height() - scale * rect.height()),
+                   rect.width() * scale,
+                   rect.height() * scale);
+}
+
+gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect(
+    const gfx::Rect& src_rect,
+    const gfx::Rect& dst_rect) {
+  DCHECK(!src_rect.IsEmpty());
+  DCHECK(!dst_rect.IsEmpty());
   gfx::Transform transform;
-  gfx::Vector2d offset(
-      0.5 * (bounds.width() - scale * rect.width()),
-      0.5 * (bounds.height() - scale * rect.height()));
-  transform.Translate(bounds.x() - rect.x() + offset.x(),
-                      bounds.y() - rect.y() + offset.y());
-  transform.Scale(scale, scale);
+  transform.Translate(dst_rect.x() - src_rect.x(),
+                      dst_rect.y() - src_rect.y());
+  transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(),
+                  static_cast<float>(dst_rect.height()) / src_rect.height());
   return transform;
 }
 
 void ScopedTransformOverviewWindow::SetTransform(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     const gfx::Transform& transform,
     bool animate) {
   DCHECK(overview_started_);
 
-  // If the window bounds have changed and a copy of the window is being
-  // shown on another display, forcibly recreate the copy.
-  if (window_copy_ && window_copy_->GetNativeWindow()->GetBoundsInScreen() !=
-      window_->GetBoundsInScreen()) {
-    DCHECK_NE(window_->GetRootWindow(), root_window);
-    // TODO(flackr): If only the position changed and not the size, update the
-    // existing window_copy_'s position and continue to use it.
-    window_copy_->Close();
-    if (layer_)
-      views::corewm::DeepDeleteLayers(layer_);
-    window_copy_ = NULL;
-    layer_ = NULL;
-  }
-
-  if (root_window != window_->GetRootWindow() && !window_copy_) {
-    DCHECK(!layer_);
-    // TODO(flackr): Create copies of the transient children and transient
-    // parent windows as well. Currently they will only be visible on the
-    // window's initial display.
-    layer_ = views::corewm::RecreateWindowLayers(window_, true);
-    window_copy_ = CreateCopyOfWindow(root_window, window_, layer_);
+  if (root_window != window_->GetRootWindow()) {
+    if (!window_copies_.empty()) {
+      bool bounds_or_hierarchy_changed = false;
+      aura::Window* window = window_;
+      for (ScopedVector<ScopedWindowCopy>::reverse_iterator iter =
+               window_copies_.rbegin();
+           !bounds_or_hierarchy_changed && iter != window_copies_.rend();
+           ++iter, window = GetModalTransientParent(window)) {
+        if (!window) {
+          bounds_or_hierarchy_changed = true;
+        } else if ((*iter)->GetWindow()->GetBoundsInScreen() !=
+                window->GetBoundsInScreen()) {
+          bounds_or_hierarchy_changed = true;
+        }
+      }
+      // Clearing the window copies array will force it to be recreated.
+      // TODO(flackr): If only the position changed and not the size,
+      // update the existing window copy's position and continue to use it.
+      if (bounds_or_hierarchy_changed)
+        window_copies_.clear();
+    }
+    if (window_copies_.empty()) {
+      // TODO(flackr): Create copies of the transient children windows as well.
+      // Currently they will only be visible on the window's initial display.
+      CopyWindowAndTransientParents(root_window, window_);
+    }
   }
   SetTransformOnWindowAndTransientChildren(transform, animate);
 }
 
+void ScopedTransformOverviewWindow::CopyWindowAndTransientParents(
+    aura::Window* target_root,
+    aura::Window* window) {
+  aura::Window* modal_parent = GetModalTransientParent(window);
+  if (modal_parent)
+    CopyWindowAndTransientParents(target_root, modal_parent);
+  window_copies_.push_back(new ScopedWindowCopy(target_root, window));
+}
+
 void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
     const gfx::Transform& transform,
     bool animate) {
@@ -345,11 +237,13 @@
   aura::Window* window = window_;
   while (window->transient_parent())
     window = window->transient_parent();
-  if (window_copy_) {
+  for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
+      window_copies_.begin(); iter != window_copies_.end(); ++iter) {
     SetTransformOnWindow(
-        window_copy_->GetNativeWindow(),
+        (*iter)->GetWindow(),
         TranslateTransformOrigin(ScreenAsh::ConvertRectToScreen(
-            window_->parent(), window_->GetTargetBounds()).origin() - origin,
+            (*iter)->GetWindow()->parent(),
+            (*iter)->GetWindow()->GetTargetBounds()).origin() - origin,
             transform),
         animate);
   }
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h
index af656c1..2bc1b0f 100644
--- a/ash/wm/overview/scoped_transform_overview_window.h
+++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -6,11 +6,11 @@
 #define ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_
 
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/transform.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -24,6 +24,8 @@
 
 namespace ash {
 
+class ScopedWindowCopy;
+
 // Manages a window in the overview mode. This class allows transforming the
 // window with a helper to determine the best fit in certain bounds and
 // copies the window if being moved to another display. The window's state is
@@ -33,12 +35,16 @@
   // The duration of transitions used for window transforms.
   static const int kTransitionMilliseconds;
 
-  // Returns the transform necessary to fit |rect| into |bounds| preserving
-  // aspect ratio and centering.
-  static gfx::Transform GetTransformForRectPreservingAspectRatio(
+  // Returns |rect| having been shrunk to fit within |bounds| (preserving the
+  // aspect ratio).
+  static gfx::Rect ShrinkRectToFitPreservingAspectRatio(
       const gfx::Rect& rect,
       const gfx::Rect& bounds);
 
+  // Returns the transform turning |src_rect| into |dst_rect|.
+  static gfx::Transform GetTransformForRect(const gfx::Rect& src_rect,
+                                            const gfx::Rect& dst_rect);
+
   explicit ScopedTransformOverviewWindow(aura::Window* window);
   virtual ~ScopedTransformOverviewWindow();
 
@@ -67,13 +73,18 @@
   // Sets |transform| on the window and a copy of the window if the target
   // |root_window| is not the window's root window. If |animate| the transform
   // is animated in, otherwise it is immediately applied.
-  void SetTransform(aura::RootWindow* root_window,
+  void SetTransform(aura::Window* root_window,
                     const gfx::Transform& transform,
                     bool animate);
 
   aura::Window* window() const { return window_; }
 
  private:
+  // Creates copies of |window| and all of its modal transient parents on the
+  // root window |target_root|.
+  void CopyWindowAndTransientParents(aura::Window* target_root,
+                                     aura::Window* window);
+
   // Applies the |transform| to the overview window and all of its transient
   // children using animations. If |animate| the transform is animated in,
   // otherwise it is applied immediately.
@@ -83,11 +94,8 @@
   // A weak pointer to the real window in the overview.
   aura::Window* window_;
 
-  // A copy of the window used to transition the window to another root.
-  views::Widget* window_copy_;
-
-  // A weak pointer to a deep copy of the window's layers.
-  ui::Layer* layer_;
+  // Copies of the window and transient parents for a different root window.
+  ScopedVector<ScopedWindowCopy> window_copies_;
 
   // If true, the window was minimized and should be restored if the window
   // was not selected.
diff --git a/ash/wm/overview/scoped_window_copy.cc b/ash/wm/overview/scoped_window_copy.cc
new file mode 100644
index 0000000..660b284
--- /dev/null
+++ b/ash/wm/overview/scoped_window_copy.cc
@@ -0,0 +1,178 @@
+// Copyright 2013 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 "ash/wm/overview/scoped_window_copy.h"
+
+#include "ash/screen_ash.h"
+#include "ash/shell.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/gfx/display.h"
+#include "ui/views/corewm/shadow_types.h"
+#include "ui/views/corewm/window_util.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+// Creates a copy of |window| with |recreated_layer| in the |target_root|.
+views::Widget* CreateCopyOfWindow(aura::Window* target_root,
+                                  aura::Window* src_window,
+                                  ui::Layer* recreated_layer) {
+  // Save and remove the transform from the layer to later reapply to both the
+  // source and newly created copy window.
+  gfx::Transform transform = recreated_layer->transform();
+  recreated_layer->SetTransform(gfx::Transform());
+
+  src_window->SetTransform(transform);
+  views::Widget* widget = new views::Widget;
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+  params.parent = src_window->parent();
+  params.can_activate = false;
+  params.keep_on_top = true;
+  widget->set_focus_on_creation(false);
+  widget->Init(params);
+  widget->SetVisibilityChangedAnimationsEnabled(false);
+  std::string name = src_window->name() + " (Copy)";
+  widget->GetNativeWindow()->SetName(name);
+  views::corewm::SetShadowType(widget->GetNativeWindow(),
+                               views::corewm::SHADOW_TYPE_RECTANGULAR);
+
+  // Set the bounds in the target root window.
+  gfx::Display target_display =
+      Shell::GetScreen()->GetDisplayNearestWindow(target_root);
+  aura::client::ScreenPositionClient* screen_position_client =
+      aura::client::GetScreenPositionClient(src_window->GetRootWindow());
+  if (screen_position_client && target_display.is_valid()) {
+    screen_position_client->SetBounds(widget->GetNativeWindow(),
+        src_window->GetBoundsInScreen(), target_display);
+  } else {
+    widget->SetBounds(src_window->GetBoundsInScreen());
+  }
+  widget->StackAbove(src_window);
+
+  // Move the |recreated_layer| to the newly created window.
+  recreated_layer->set_delegate(src_window->layer()->delegate());
+  gfx::Rect layer_bounds = recreated_layer->bounds();
+  layer_bounds.set_origin(gfx::Point(0, 0));
+  recreated_layer->SetBounds(layer_bounds);
+  recreated_layer->SetVisible(false);
+  recreated_layer->parent()->Remove(recreated_layer);
+
+  aura::Window* window = widget->GetNativeWindow();
+  recreated_layer->SetVisible(true);
+  window->layer()->Add(recreated_layer);
+  window->layer()->StackAtTop(recreated_layer);
+  window->layer()->SetOpacity(1);
+  window->SetTransform(transform);
+  window->Show();
+  return widget;
+}
+
+}  // namespace
+
+// An observer which closes the widget and deletes the layer after an
+// animation finishes.
+class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver {
+ public:
+  CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer);
+
+  // Takes ownership of the widget. At this point the class will delete itself
+  // and clean up the layer when there are no pending animations.
+  void TakeOwnershipOfWidget();
+
+  // ui::LayerAnimationObserver:
+  virtual void OnLayerAnimationEnded(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+  virtual void OnLayerAnimationAborted(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+  virtual void OnLayerAnimationScheduled(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+
+ private:
+  virtual ~CleanupWidgetAfterAnimationObserver();
+
+  // If the necessary conditions have been satisfied to destruct this
+  // class, deletes itself and cleans up the widget and layer.
+  void MaybeDestruct();
+
+  views::Widget* widget_;
+  ui::Layer* layer_;
+  bool owns_widget_;
+  int pending_animations_;
+
+  DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver);
+};
+
+CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver(
+        views::Widget* widget,
+        ui::Layer* layer)
+    : widget_(widget),
+      layer_(layer),
+      owns_widget_(false),
+      pending_animations_(0) {
+  widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this);
+}
+
+void CleanupWidgetAfterAnimationObserver::TakeOwnershipOfWidget() {
+  owns_widget_ = true;
+  MaybeDestruct();
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded(
+    ui::LayerAnimationSequence* sequence) {
+  pending_animations_--;
+  MaybeDestruct();
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted(
+    ui::LayerAnimationSequence* sequence) {
+  pending_animations_--;
+  MaybeDestruct();
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled(
+    ui::LayerAnimationSequence* sequence) {
+  pending_animations_++;
+}
+
+CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {
+  widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this);
+  widget_->Close();
+  widget_ = NULL;
+  if (layer_) {
+    views::corewm::DeepDeleteLayers(layer_);
+    layer_ = NULL;
+  }
+}
+
+void CleanupWidgetAfterAnimationObserver::MaybeDestruct() {
+  if (pending_animations_ || !owns_widget_)
+    return;
+  delete this;
+}
+
+ScopedWindowCopy::ScopedWindowCopy(aura::Window* target_root,
+                                   aura::Window* src_window) {
+  layer_ = views::corewm::RecreateWindowLayers(src_window, true);
+  widget_ = CreateCopyOfWindow(target_root, src_window, layer_);
+  cleanup_observer_ = new CleanupWidgetAfterAnimationObserver(widget_, layer_);
+}
+
+ScopedWindowCopy::~ScopedWindowCopy() {
+  // The cleanup observer will delete itself and the window when any pending
+  // animations have completed.
+  cleanup_observer_->TakeOwnershipOfWidget();
+}
+
+aura::Window* ScopedWindowCopy::GetWindow() {
+  return widget_->GetNativeWindow();
+}
+
+}  // namespace ash
diff --git a/ash/wm/overview/scoped_window_copy.h b/ash/wm/overview/scoped_window_copy.h
new file mode 100644
index 0000000..d5da445
--- /dev/null
+++ b/ash/wm/overview/scoped_window_copy.h
@@ -0,0 +1,54 @@
+// Copyright 2013 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 ASH_WM_OVERVIEW_SCOPED_WINDOW_COPY_H_
+#define ASH_WM_OVERVIEW_SCOPED_WINDOW_COPY_H_
+
+#include "base/basictypes.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace ui {
+class Layer;
+}
+
+namespace views {
+class Widget;
+}
+
+namespace ash {
+
+class CleanupWidgetAfterAnimationObserver;
+
+// ScopedWindowCopy copies a window and will clean up the copied layers after
+// the class goes out of scope and the last animation has finished.
+class ScopedWindowCopy {
+ public:
+  ScopedWindowCopy(aura::Window* target_root, aura::Window* src_window);
+  ~ScopedWindowCopy();
+
+  aura::Window* GetWindow();
+
+ private:
+  // A weak pointer to a copy of the source window owned by cleanup_observer_.
+  views::Widget* widget_;
+
+  // A weak pointer to the deep copy of the source window's layers owned by
+  // cleanup_observer_.
+  ui::Layer* layer_;
+
+  // A weak pointer to an animation observer which owns itself. When the
+  // ScopedWindowCopy is destroyed The animation observer will clean up the
+  // widget, layer and itself once any pending animations have completed.
+  CleanupWidgetAfterAnimationObserver* cleanup_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedWindowCopy);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERVIEW_SCOPED_WINDOW_COPY_H_
diff --git a/ash/wm/overview/window_overview.cc b/ash/wm/overview/window_overview.cc
index 03d973c..649f3d4 100644
--- a/ash/wm/overview/window_overview.cc
+++ b/ash/wm/overview/window_overview.cc
@@ -27,13 +27,30 @@
 
 namespace {
 
+// Conceptually the window overview is a table or grid of cells having this
+// fixed aspect ratio. The number of columns is determined by maximizing the
+// area of them based on the number of windows.
 const float kCardAspectRatio = 4.0f / 3.0f;
+
+// In the conceptual overview table, the window margin is the space reserved
+// around the window within the cell. This margin does not overlap so the
+// closest distance between adjacent windows will be twice this amount.
 const int kWindowMargin = 30;
+
+// The minimum number of cards along the major axis (i.e. horizontally on a
+// landscape orientation).
 const int kMinCardsMajor = 3;
+
+// The duration of transition animations on the overview selector.
 const int kOverviewSelectorTransitionMilliseconds = 100;
+
+// The color and opacity of the overview selector.
 const SkColor kWindowOverviewSelectionColor = SK_ColorBLACK;
 const float kWindowOverviewSelectionOpacity = 0.5f;
-const int kWindowOverviewSelectionPadding = 15;
+
+// The padding or amount of the window selector widget visible around the edges
+// of the currently selected window.
+const int kWindowOverviewSelectionPadding = 25;
 
 // A comparator for locating a given target window.
 struct WindowSelectorItemComparator
@@ -100,7 +117,7 @@
 
 WindowOverview::WindowOverview(WindowSelector* window_selector,
                                WindowSelectorItemList* windows,
-                               aura::RootWindow* single_root_window)
+                               aura::Window* single_root_window)
     : window_selector_(window_selector),
       windows_(windows),
       selection_index_(0),
@@ -117,6 +134,7 @@
       windows_->front()->GetRootWindow());
   if (cursor_client_) {
     cursor_client_->SetCursor(ui::kCursorPointer);
+    cursor_client_->ShowCursor();
     // TODO(flackr): Only prevent cursor changes for windows in the overview.
     // This will be easier to do without exposing the overview mode code if the
     // cursor changes are moved to ToplevelWindowEventHandler::HandleMouseMoved
@@ -167,8 +185,8 @@
         change -= windows;
     }
     if (selection_index_ < windows_->size() &&
-        (*windows_)[selection_index_]->bounds().y() !=
-            (*windows_)[index]->bounds().y() &&
+        (*windows_)[selection_index_]->target_bounds().y() !=
+            (*windows_)[index]->target_bounds().y() &&
         abs(change) == 1) {
       // The selection has changed forward or backwards by one with a change
       // in the height of the target. In this case create a new selection widget
@@ -177,7 +195,7 @@
           selection_widget_->GetNativeWindow())->GetDisplayMatching(
               target_bounds);
       gfx::Vector2d fade_out_direction(
-          change * ((*windows_)[selection_index_]->bounds().width() +
+          change * ((*windows_)[selection_index_]->target_bounds().width() +
                     2 * kWindowMargin), 0);
       aura::Window* old_selection = selection_widget_->GetNativeWindow();
 
@@ -221,7 +239,7 @@
   PositionWindows();
 }
 
-void WindowOverview::MoveToSingleRootWindow(aura::RootWindow* root_window) {
+void WindowOverview::MoveToSingleRootWindow(aura::Window* root_window) {
   single_root_window_ = root_window;
   PositionWindows();
 }
@@ -263,7 +281,7 @@
   // the window, perhaps a transparent window in front of the target window
   // or using EventClientImpl::CanProcessEventsWithinSubtree and then a tap
   // gesture could be used to activate the window.
-  event->StopPropagation();
+  event->SetHandled();
   window_selector_->SelectWindow(target);
 }
 
@@ -330,7 +348,7 @@
   }
 }
 
-void WindowOverview::PositionWindowsFromRoot(aura::RootWindow* root_window) {
+void WindowOverview::PositionWindowsFromRoot(aura::Window* root_window) {
   std::vector<WindowSelectorItem*> windows;
   for (WindowSelectorItemList::iterator iter = windows_->begin();
        iter != windows_->end(); ++iter) {
@@ -341,7 +359,7 @@
 }
 
 void WindowOverview::PositionWindowsOnRoot(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     const std::vector<WindowSelectorItem*>& windows) {
   if (windows.empty())
     return;
diff --git a/ash/wm/overview/window_overview.h b/ash/wm/overview/window_overview.h
index fed1bc9..3f21dac 100644
--- a/ash/wm/overview/window_overview.h
+++ b/ash/wm/overview/window_overview.h
@@ -14,14 +14,10 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
-
 class Window;
-class RootWindow;
-
 namespace client {
 class CursorClient;
 }
-
 }  // namespace aura
 
 namespace ui {
@@ -50,7 +46,7 @@
   // given root window.
   WindowOverview(WindowSelector* window_selector,
                  WindowSelectorItemList* windows,
-                 aura::RootWindow* single_root_window);
+                 aura::Window* single_root_window);
   virtual ~WindowOverview();
 
   // Sets the selected window to be the window in position |index|.
@@ -60,7 +56,7 @@
   void OnWindowsChanged();
 
   // Moves the overview to only |root_window|.
-  void MoveToSingleRootWindow(aura::RootWindow* root_window);
+  void MoveToSingleRootWindow(aura::Window* root_window);
 
   // ui::EventHandler:
   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
@@ -82,9 +78,9 @@
   // Position all of the windows based on the current selection mode.
   void PositionWindows();
   // Position all of the windows from |root_window| on |root_window|.
-  void PositionWindowsFromRoot(aura::RootWindow* root_window);
+  void PositionWindowsFromRoot(aura::Window* root_window);
   // Position all of the |windows| to fit on the |root_window|.
-  void PositionWindowsOnRoot(aura::RootWindow* root_window,
+  void PositionWindowsOnRoot(aura::Window* root_window,
                              const std::vector<WindowSelectorItem*>& windows);
 
   // Creates the selection widget.
@@ -111,7 +107,7 @@
   // If NULL, each root window displays an overview of the windows in that
   // display. Otherwise, all windows are in a single overview on
   // |single_root_window_|.
-  aura::RootWindow* single_root_window_;
+  aura::Window* single_root_window_;
 
   // The time when overview was started.
   base::Time overview_start_time_;
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index a5973ca..16345f6 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "ash/ash_switches.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
@@ -15,12 +16,15 @@
 #include "ash/wm/overview/window_selector_window.h"
 #include "ash/wm/window_state.h"
 #include "base/auto_reset.h"
+#include "base/command_line.h"
 #include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/timer/timer.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
 #include "ui/events/event.h"
 #include "ui/events/event_handler.h"
 
@@ -28,7 +32,34 @@
 
 namespace {
 
-const int kOverviewDelayOnCycleMilliseconds = 500;
+// The time from when the user pressed alt+tab while still holding alt before
+// overview is engaged.
+const int kOverviewDelayOnCycleMilliseconds = 100;
+
+// If the delay before overview is less than or equal to this threshold the
+// initial monitor is used for multi-display overview, otherwise the monitor
+// of the currently selected window is used.
+const int kOverviewDelayInitialMonitorThreshold = 100;
+
+// The maximum amount of time allowed for the delay before overview on cycling.
+// If the specified time exceeds this the timer will not be started.
+const int kMaxOverviewDelayOnCycleMilliseconds = 10000;
+
+int GetOverviewDelayOnCycleMilliseconds() {
+  static int value = -1;
+  if (value == -1) {
+    value = kOverviewDelayOnCycleMilliseconds;
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshOverviewDelayOnAltTab)) {
+      if (!base::StringToInt(CommandLine::ForCurrentProcess()->
+            GetSwitchValueASCII(switches::kAshOverviewDelayOnAltTab), &value)) {
+        LOG(ERROR) << "Expected int value for "
+                   << switches::kAshOverviewDelayOnAltTab;
+      }
+    }
+  }
+  return value;
+}
 
 // A comparator for locating a given target window.
 struct WindowSelectorItemComparator
@@ -47,7 +78,7 @@
 // A comparator for locating a selector item for a given root.
 struct WindowSelectorItemForRoot
     : public std::unary_function<WindowSelectorItem*, bool> {
-  explicit WindowSelectorItemForRoot(const aura::RootWindow* root)
+  explicit WindowSelectorItemForRoot(const aura::Window* root)
       : root_window(root) {
   }
 
@@ -55,7 +86,7 @@
     return item->GetRootWindow() == root_window;
   }
 
-  const aura::RootWindow* root_window;
+  const aura::Window* root_window;
 };
 
 // Filter to watch for the termination of a keyboard gesture to cycle through
@@ -105,14 +136,114 @@
   }
 }
 
+// Returns the window immediately below |window| in the current container.
+aura::Window* GetWindowBelow(aura::Window* window) {
+  aura::Window* parent = window->parent();
+  if (!parent)
+    return NULL;
+  aura::Window* below = NULL;
+  for (aura::Window::Windows::const_iterator iter = parent->children().begin();
+       iter != parent->children().end(); ++iter) {
+    if (*iter == window)
+      return below;
+    below = *iter;
+  }
+  NOTREACHED();
+  return NULL;
+}
+
 }  // namespace
 
+// This class restores and moves a window to the front of the stacking order for
+// the duration of the class's scope.
+class ScopedShowWindow : public aura::WindowObserver {
+ public:
+  ScopedShowWindow();
+  virtual ~ScopedShowWindow();
+
+  // Show |window| at the top of the stacking order.
+  void Show(aura::Window* window);
+
+  // Cancel restoring the window on going out of scope.
+  void CancelRestore();
+
+  aura::Window* window() { return window_; }
+
+  // aura::WindowObserver:
+  virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
+
+ private:
+  // The window being shown.
+  aura::Window* window_;
+
+  // The window immediately below where window_ belongs.
+  aura::Window* stack_window_above_;
+
+  // If true, minimize window_ on going out of scope.
+  bool minimized_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow);
+};
+
+ScopedShowWindow::ScopedShowWindow()
+    : window_(NULL),
+      stack_window_above_(NULL),
+      minimized_(false) {
+}
+
+void ScopedShowWindow::Show(aura::Window* window) {
+  DCHECK(!window_);
+  window_ = window;
+  stack_window_above_ = GetWindowBelow(window);
+  minimized_ = wm::GetWindowState(window)->IsMinimized();
+  window_->Show();
+  window_->SetTransform(gfx::Transform());
+  window_->parent()->AddObserver(this);
+  window_->parent()->StackChildAtTop(window_);
+}
+
+ScopedShowWindow::~ScopedShowWindow() {
+  if (window_) {
+    window_->parent()->RemoveObserver(this);
+
+    // Restore window's stacking position.
+    if (stack_window_above_)
+      window_->parent()->StackChildAbove(window_, stack_window_above_);
+    else
+      window_->parent()->StackChildAtBottom(window_);
+
+    // Restore minimized state.
+    if (minimized_)
+      wm::GetWindowState(window_)->Minimize();
+  }
+}
+
+void ScopedShowWindow::CancelRestore() {
+  if (!window_)
+    return;
+  window_->parent()->RemoveObserver(this);
+  window_ = stack_window_above_ = NULL;
+}
+
+void ScopedShowWindow::OnWillRemoveWindow(aura::Window* window) {
+  if (window == window_) {
+    CancelRestore();
+  } else if (window == stack_window_above_) {
+    // If the window this window was above is removed, use the next window down
+    // as the restore marker.
+    stack_window_above_ = GetWindowBelow(stack_window_above_);
+  }
+}
+
 WindowSelector::WindowSelector(const WindowList& windows,
                                WindowSelector::Mode mode,
                                WindowSelectorDelegate* delegate)
     : mode_(mode),
+      timer_enabled_(GetOverviewDelayOnCycleMilliseconds() <
+                         kMaxOverviewDelayOnCycleMilliseconds),
       start_overview_timer_(FROM_HERE,
-          base::TimeDelta::FromMilliseconds(kOverviewDelayOnCycleMilliseconds),
+          base::TimeDelta::FromMilliseconds(
+              GetOverviewDelayOnCycleMilliseconds()),
           this, &WindowSelector::StartOverview),
       delegate_(delegate),
       selected_window_(0),
@@ -161,7 +292,8 @@
 
   if (mode == WindowSelector::CYCLE) {
     event_handler_.reset(new WindowSelectorEventFilter(this));
-    start_overview_timer_.Reset();
+    if (timer_enabled_)
+      start_overview_timer_.Reset();
   } else {
     StartOverview();
   }
@@ -206,12 +338,11 @@
   if (window_overview_) {
     window_overview_->SetSelection(selected_window_);
   } else {
-    aura::Window* current_window =
-        windows_[selected_window_]->SelectionWindow();
-    current_window->Show();
-    current_window->SetTransform(gfx::Transform());
-    current_window->parent()->StackChildAtTop(current_window);
+    showing_window_.reset(new ScopedShowWindow);
+    showing_window_->Show(windows_[selected_window_]->SelectionWindow());
     start_overview_timer_.Reset();
+    if (timer_enabled_)
+      start_overview_timer_.Reset();
   }
 }
 
@@ -221,6 +352,8 @@
 }
 
 void WindowSelector::SelectWindow(aura::Window* window) {
+  if (showing_window_ && showing_window_->window() == window)
+    showing_window_->CancelRestore();
   ScopedVector<WindowSelectorItem>::iterator iter =
       std::find_if(windows_.begin(), windows_.end(),
                    WindowSelectorItemComparator(window));
@@ -327,8 +460,14 @@
 
 void WindowSelector::StartOverview() {
   DCHECK(!window_overview_);
-  window_overview_.reset(new WindowOverview(this, &windows_,
-      mode_ == CYCLE ? windows_[selected_window_]->GetRootWindow() : NULL));
+  aura::Window* overview_root = NULL;
+  if (mode_ == CYCLE) {
+    overview_root = GetOverviewDelayOnCycleMilliseconds() <=
+                        kOverviewDelayInitialMonitorThreshold ?
+                    Shell::GetTargetRootWindow() :
+                    windows_[selected_window_]->GetRootWindow();
+  }
+  window_overview_.reset(new WindowOverview(this, &windows_, overview_root));
   if (mode_ == CYCLE)
     window_overview_->SetSelection(selected_window_);
   UpdateShelfVisibility();
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index b962ff3..4fc29d1 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -30,6 +30,7 @@
 class WindowSelectorTest;
 }
 
+class ScopedShowWindow;
 class WindowOverview;
 class WindowSelectorDelegate;
 class WindowSelectorItem;
@@ -112,6 +113,11 @@
   // cycling.
   scoped_ptr<ui::EventHandler> event_handler_;
 
+  // The currently selected window being shown (temporarily brought to the front
+  // of the stacking order and made visible).
+  scoped_ptr<ScopedShowWindow> showing_window_;
+
+  bool timer_enabled_;
   base::DelayTimer<WindowSelector> start_overview_timer_;
   scoped_ptr<WindowOverview> window_overview_;
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 284ec55..a2c25b6 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -16,22 +16,22 @@
 WindowSelectorItem::~WindowSelectorItem() {
 }
 
-void WindowSelectorItem::SetBounds(aura::RootWindow* root_window,
+void WindowSelectorItem::SetBounds(aura::Window* root_window,
                                    const gfx::Rect& target_bounds) {
   if (in_bounds_update_)
     return;
   base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
   root_window_ = root_window;
-  bounds_ = target_bounds;
+  target_bounds_ = target_bounds;
   SetItemBounds(root_window, target_bounds, true);
 }
 
 void WindowSelectorItem::RecomputeWindowTransforms() {
-  if (in_bounds_update_ || bounds_.IsEmpty())
+  if (in_bounds_update_ || target_bounds_.IsEmpty())
     return;
   DCHECK(root_window_);
   base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
-  SetItemBounds(root_window_, bounds_, false);
+  SetItemBounds(root_window_, target_bounds_, false);
 }
 
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 0c4132a..4b0ef01 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -9,7 +9,6 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -24,7 +23,7 @@
   virtual ~WindowSelectorItem();
 
   // Returns the root window on which this item is shown.
-  virtual aura::RootWindow* GetRootWindow() = 0;
+  virtual aura::Window* GetRootWindow() = 0;
 
   // Returns the targeted window given the event |target| window.
   // Returns NULL if no Window in this item was selected.
@@ -51,28 +50,35 @@
 
   // Sets the bounds of this window selector item to |target_bounds| in the
   // |root_window| root window.
-  void SetBounds(aura::RootWindow* root_window,
+  void SetBounds(aura::Window* root_window,
                  const gfx::Rect& target_bounds);
 
   // Recomputes the positions for the windows in this selection item. This is
   // dispatched when the bounds of a window change.
   void RecomputeWindowTransforms();
 
-  // Returns the current bounds of this selector item.
   const gfx::Rect& bounds() { return bounds_; }
+  const gfx::Rect& target_bounds() { return target_bounds_; }
 
  protected:
   // Sets the bounds of this selector item to |target_bounds| in |root_window|.
   // If |animate| the windows are animated from their current location.
-  virtual void SetItemBounds(aura::RootWindow* root_window,
+  virtual void SetItemBounds(aura::Window* root_window,
                              const gfx::Rect& target_bounds,
                              bool animate) = 0;
 
+  // Sets the bounds used by the selector item's windows.
+  void set_bounds(const gfx::Rect& bounds) { bounds_ = bounds; }
+
  private:
   // The root window this item is being displayed on.
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
-  // The bounds this item is fit to.
+  // The target bounds this selector item is fit within.
+  gfx::Rect target_bounds_;
+
+  // The actual bounds of the window(s) for this item. The aspect ratio of
+  // window(s) are maintained so they may not fill the target_bounds_.
   gfx::Rect bounds_;
 
   // True if running SetItemBounds. This prevents recursive calls resulting from
diff --git a/ash/wm/overview/window_selector_panels.cc b/ash/wm/overview/window_selector_panels.cc
index 52642bf..70f9028 100644
--- a/ash/wm/overview/window_selector_panels.cc
+++ b/ash/wm/overview/window_selector_panels.cc
@@ -97,7 +97,7 @@
   transform_windows_.push_back(new ScopedTransformPanelWindow(window));
 }
 
-aura::RootWindow* WindowSelectorPanels::GetRootWindow() {
+aura::Window* WindowSelectorPanels::GetRootWindow() {
   return transform_windows_.front()->window()->GetRootWindow();
 }
 
@@ -146,7 +146,7 @@
   }
 }
 
-void WindowSelectorPanels::SetItemBounds(aura::RootWindow* root_window,
+void WindowSelectorPanels::SetItemBounds(aura::Window* root_window,
                                          const gfx::Rect& target_bounds,
                                          bool animate) {
   gfx::Rect bounding_rect;
@@ -154,9 +154,11 @@
        iter != transform_windows_.end(); ++iter) {
     bounding_rect.Union((*iter)->GetBoundsInScreen());
   }
+  set_bounds(ScopedTransformOverviewWindow::
+      ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds));
   gfx::Transform bounding_transform =
-      ScopedTransformOverviewWindow::GetTransformForRectPreservingAspectRatio(
-          bounding_rect, target_bounds);
+      ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect,
+                                                         bounds());
   for (WindowList::iterator iter = transform_windows_.begin();
        iter != transform_windows_.end(); ++iter) {
     gfx::Transform transform;
diff --git a/ash/wm/overview/window_selector_panels.h b/ash/wm/overview/window_selector_panels.h
index 785c6dc..bcc9137 100644
--- a/ash/wm/overview/window_selector_panels.h
+++ b/ash/wm/overview/window_selector_panels.h
@@ -10,11 +10,6 @@
 #include "base/memory/scoped_vector.h"
 #include "ui/gfx/rect.h"
 
-namespace aura {
-class RootWindow;
-class Window;
-}
-
 namespace ash {
 
 class ScopedTransformOverviewWindow;
@@ -32,14 +27,14 @@
   void AddWindow(aura::Window* window);
 
   // WindowSelectorItem:
-  virtual aura::RootWindow* GetRootWindow() OVERRIDE;
+  virtual aura::Window* GetRootWindow() OVERRIDE;
   virtual aura::Window* TargetedWindow(const aura::Window* target) OVERRIDE;
   virtual void RestoreWindowOnExit(aura::Window* window) OVERRIDE;
   virtual aura::Window* SelectionWindow() OVERRIDE;
   virtual void RemoveWindow(const aura::Window* window) OVERRIDE;
   virtual bool empty() const OVERRIDE;
   virtual void PrepareForOverview() OVERRIDE;
-  virtual void SetItemBounds(aura::RootWindow* root_window,
+  virtual void SetItemBounds(aura::Window* root_window,
                              const gfx::Rect& target_bounds,
                              bool animate) OVERRIDE;
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index a2bd8ea..ba17961 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -47,6 +47,55 @@
   }
 };
 
+bool IsWindowAbove(aura::Window* w1, aura::Window* w2) {
+  aura::Window* parent = w1->parent();
+  DCHECK_EQ(parent, w2->parent());
+  for (aura::Window::Windows::const_iterator iter = parent->children().begin();
+       iter != parent->children().end(); ++iter) {
+    if (*iter == w1)
+      return false;
+    if (*iter == w2)
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+aura::Window* GetWindowByName(aura::Window* container,
+                              const std::string& name) {
+  aura::Window* window = NULL;
+  for (aura::Window::Windows::const_iterator iter =
+       container->children().begin(); iter != container->children().end();
+       ++iter) {
+    if ((*iter)->name() == name) {
+      // The name should be unique.
+      DCHECK(!window);
+      window = *iter;
+    }
+  }
+  return window;
+}
+
+// Returns the copy of |window| created for overview. It is found using the
+// window name which should be the same as the source window's name with a
+// special suffix, and in the same container as the source window.
+aura::Window* GetCopyWindow(aura::Window* window) {
+  aura::Window* copy_window = NULL;
+  std::string copy_name = window->name() + " (Copy)";
+  std::vector<aura::Window*> containers(
+      Shell::GetContainersFromAllRootWindows(window->parent()->id(), NULL));
+  for (std::vector<aura::Window*>::iterator iter = containers.begin();
+       iter != containers.end(); ++iter) {
+    aura::Window* found = GetWindowByName(*iter, copy_name);
+    if (found) {
+      // There should only be one copy window.
+      DCHECK(!copy_window);
+      copy_window = found;
+    }
+  }
+  return copy_window;
+}
+
 }  // namespace
 
 class WindowSelectorTest : public test::AshTestBase {
@@ -170,7 +219,7 @@
 // Tests entering overview mode with two windows and selecting one.
 TEST_F(WindowSelectorTest, Basic) {
   gfx::Rect bounds(0, 0, 400, 400);
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   scoped_ptr<aura::Window> window1(CreateWindow(bounds));
   scoped_ptr<aura::Window> window2(CreateWindow(bounds));
   scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
@@ -181,6 +230,8 @@
   EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
   EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
   EXPECT_EQ(window2.get(), GetFocusedWindow());
+  // Hide the cursor before entering overview to test that it will be shown.
+  aura::client::GetCursorClient(root_window)->HideCursor();
 
   // In overview mode the windows should no longer overlap and focus should
   // be removed from the window.
@@ -192,9 +243,11 @@
   // item.
   EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
 
-  // The cursor should be locked as a pointer
-  EXPECT_EQ(ui::kCursorPointer, root_window->last_cursor().native_type());
-  EXPECT_TRUE(GetCursorClient(root_window)->IsCursorLocked());
+  // The cursor should be visible and locked as a pointer
+  EXPECT_EQ(ui::kCursorPointer,
+            root_window->GetDispatcher()->last_cursor().native_type());
+  EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
+  EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorVisible());
 
   // Clicking window 1 should activate it.
   ClickWindow(window1.get());
@@ -203,7 +256,7 @@
   EXPECT_EQ(window1.get(), GetFocusedWindow());
 
   // Cursor should have been unlocked.
-  EXPECT_FALSE(GetCursorClient(root_window)->IsCursorLocked());
+  EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
 }
 
 // Tests that the shelf dimming state is removed while in overview and restored
@@ -309,6 +362,59 @@
   EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
 }
 
+// Tests that cycling through windows preserves the window stacking order.
+TEST_F(WindowSelectorTest, CyclePreservesStackingOrder) {
+  gfx::Rect bounds(0, 0, 400, 400);
+  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
+  wm::ActivateWindow(window3.get());
+  wm::ActivateWindow(window2.get());
+  wm::ActivateWindow(window1.get());
+  // Window order from top to bottom is 1, 2, 3.
+  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
+  EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
+
+  // On window 2.
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_TRUE(IsWindowAbove(window2.get(), window1.get()));
+  EXPECT_TRUE(IsWindowAbove(window1.get(), window3.get()));
+
+  // On window 3.
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_TRUE(IsWindowAbove(window3.get(), window1.get()));
+  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
+
+  // Back on window 1.
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
+  EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
+  StopCycling();
+}
+
+// Tests that cycling through windows shows and minimizes windows as they
+// are passed.
+TEST_F(WindowSelectorTest, CyclePreservesMinimization) {
+  gfx::Rect bounds(0, 0, 400, 400);
+  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+  wm::ActivateWindow(window2.get());
+  wm::GetWindowState(window2.get())->Minimize();
+  wm::ActivateWindow(window1.get());
+  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
+
+  // On window 2.
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_FALSE(wm::IsWindowMinimized(window2.get()));
+
+  // Back on window 1.
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
+
+  StopCycling();
+  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
+}
+
 // Tests beginning cycling while in overview mode.
 TEST_F(WindowSelectorTest, OverviewTransitionToCycle) {
   gfx::Rect bounds(0, 0, 400, 400);
@@ -641,8 +747,8 @@
 }
 
 // Verifies that the single display overview used during alt tab cycling uses
-// the display of the currently selected window.
-TEST_F(WindowSelectorTest, CycleOverviewUsesCurrentDisplay) {
+// the display of the initial window by default.
+TEST_F(WindowSelectorTest, CycleOverviewUsesInitialDisplay) {
   if (!SupportsMultipleDisplays())
     return;
 
@@ -660,10 +766,79 @@
   Cycle(WindowSelector::FORWARD);
   FireOverviewStartTimer();
 
-  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
       ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
-  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
       ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
+  StopCycling();
+}
+
+// Verifies that the windows being shown on another display are copied.
+TEST_F(WindowSelectorTest, CycleMultipleDisplaysCopiesWindows) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("400x400,400x400");
+  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+
+  gfx::Rect root1_rect(0, 0, 100, 100);
+  gfx::Rect root2_rect(450, 0, 100, 100);
+  scoped_ptr<aura::Window> unmoved1(CreateWindow(root2_rect));
+  scoped_ptr<aura::Window> unmoved2(CreateWindow(root2_rect));
+  scoped_ptr<aura::Window> moved1_trans_parent(CreateWindow(root1_rect));
+  scoped_ptr<aura::Window> moved1(CreateWindow(root1_rect));
+  unmoved1->SetName("unmoved1");
+  unmoved2->SetName("unmoved2");
+  moved1->SetName("moved1");
+  moved1->SetProperty(aura::client::kModalKey,
+                      ui::MODAL_TYPE_WINDOW);
+  moved1_trans_parent->AddTransientChild(moved1.get());
+  moved1_trans_parent->SetName("moved1_trans_parent");
+
+  EXPECT_EQ(root_windows[0], moved1->GetRootWindow());
+  EXPECT_EQ(root_windows[0], moved1_trans_parent->GetRootWindow());
+  EXPECT_EQ(root_windows[1], unmoved1->GetRootWindow());
+  EXPECT_EQ(root_windows[1], unmoved2->GetRootWindow());
+  wm::ActivateWindow(unmoved2.get());
+  wm::ActivateWindow(unmoved1.get());
+
+  Cycle(WindowSelector::FORWARD);
+  FireOverviewStartTimer();
+
+  // All windows are moved to second root window.
+  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+      ToEnclosingRect(GetTransformedTargetBounds(unmoved1.get()))));
+  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+      ToEnclosingRect(GetTransformedTargetBounds(unmoved2.get()))));
+  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+      ToEnclosingRect(GetTransformedTargetBounds(moved1.get()))));
+  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
+      ToEnclosingRect(GetTransformedTargetBounds(moved1_trans_parent.get()))));
+
+  // unmoved1 and unmoved2 were already on the correct display and should not
+  // have been copied.
+  EXPECT_TRUE(!GetCopyWindow(unmoved1.get()));
+  EXPECT_TRUE(!GetCopyWindow(unmoved2.get()));
+
+  // moved1 and its transient parent moved1_trans_parent should have also been
+  // copied for displaying on root_windows[1].
+  aura::Window* copy1 = GetCopyWindow(moved1.get());
+  aura::Window* copy1_trans_parent = GetCopyWindow(moved1_trans_parent.get());
+  ASSERT_FALSE(!copy1);
+  ASSERT_FALSE(!copy1_trans_parent);
+
+  // Verify that the bounds and transform of the copy match the original window
+  // but that it is on the other root window.
+  EXPECT_EQ(root_windows[1], copy1->GetRootWindow());
+  EXPECT_EQ(moved1->GetBoundsInScreen(), copy1->GetBoundsInScreen());
+  EXPECT_EQ(moved1->layer()->GetTargetTransform(),
+            copy1->layer()->GetTargetTransform());
+  StopCycling();
+
+  // After cycling the copy windows should have been destroyed.
+  RunAllPendingInMessageLoop();
+  EXPECT_TRUE(!GetCopyWindow(moved1.get()));
+  EXPECT_TRUE(!GetCopyWindow(moved1_trans_parent.get()));
 }
 
 // Tests that beginning to cycle from overview mode moves windows to the
@@ -706,10 +881,13 @@
 
   scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
   scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
+  scoped_ptr<aura::Window> window3(CreateWindow(gfx::Rect(450, 0, 100, 100)));
   EXPECT_EQ(root_windows[0], window1->GetRootWindow());
   EXPECT_EQ(root_windows[1], window2->GetRootWindow());
-  wm::ActivateWindow(window2.get());
+  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
   wm::ActivateWindow(window1.get());
+  wm::ActivateWindow(window2.get());
+  wm::ActivateWindow(window3.get());
 
   Cycle(WindowSelector::FORWARD);
   FireOverviewStartTimer();
diff --git a/ash/wm/overview/window_selector_window.cc b/ash/wm/overview/window_selector_window.cc
index d257d29..7c3e36c 100644
--- a/ash/wm/overview/window_selector_window.cc
+++ b/ash/wm/overview/window_selector_window.cc
@@ -15,7 +15,7 @@
 WindowSelectorWindow::~WindowSelectorWindow() {
 }
 
-aura::RootWindow* WindowSelectorWindow::GetRootWindow() {
+aura::Window* WindowSelectorWindow::GetRootWindow() {
   return transform_window_.window()->GetRootWindow();
 }
 
@@ -46,13 +46,14 @@
   transform_window_.PrepareForOverview();
 }
 
-void WindowSelectorWindow::SetItemBounds(aura::RootWindow* root_window,
+void WindowSelectorWindow::SetItemBounds(aura::Window* root_window,
                                          const gfx::Rect& target_bounds,
                                          bool animate) {
-  gfx::Rect bounding_rect = transform_window_.window()->GetBoundsInScreen();
+  gfx::Rect src_rect = transform_window_.GetBoundsInScreen();
+  set_bounds(ScopedTransformOverviewWindow::
+      ShrinkRectToFitPreservingAspectRatio(src_rect, target_bounds));
   transform_window_.SetTransform(root_window,
-      ScopedTransformOverviewWindow::GetTransformForRectPreservingAspectRatio(
-          transform_window_.GetBoundsInScreen(), target_bounds),
+      ScopedTransformOverviewWindow::GetTransformForRect(src_rect, bounds()),
       animate);
 }
 
diff --git a/ash/wm/overview/window_selector_window.h b/ash/wm/overview/window_selector_window.h
index ef912eb..fb49a58 100644
--- a/ash/wm/overview/window_selector_window.h
+++ b/ash/wm/overview/window_selector_window.h
@@ -11,7 +11,6 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -25,14 +24,14 @@
   virtual ~WindowSelectorWindow();
 
   // WindowSelectorItem:
-  virtual aura::RootWindow* GetRootWindow() OVERRIDE;
+  virtual aura::Window* GetRootWindow() OVERRIDE;
   virtual aura::Window* TargetedWindow(const aura::Window* target) OVERRIDE;
   virtual void RestoreWindowOnExit(aura::Window* window) OVERRIDE;
   virtual aura::Window* SelectionWindow() OVERRIDE;
   virtual void RemoveWindow(const aura::Window* window) OVERRIDE;
   virtual bool empty() const OVERRIDE;
   virtual void PrepareForOverview() OVERRIDE;
-  virtual void SetItemBounds(aura::RootWindow* root_window,
+  virtual void SetItemBounds(aura::Window* root_window,
                              const gfx::Rect& target_bounds,
                              bool animate) OVERRIDE;
 
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc
index 0a6bce5..bafe29f 100644
--- a/ash/wm/panels/panel_frame_view.cc
+++ b/ash/wm/panels/panel_frame_view.cc
@@ -80,6 +80,10 @@
   header_painter_->set_header_height(NonClientTopBorderHeight());
 }
 
+void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) {
+  // Nothing.
+}
+
 void PanelFrameView::ResetWindowControls() {
   NOTIMPLEMENTED();
 }
@@ -99,10 +103,6 @@
   header_painter_->SchedulePaintForTitle(title_font_);
 }
 
-void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) {
-  // Nothing.
-}
-
 int PanelFrameView::NonClientHitTest(const gfx::Point& point) {
   if (!header_painter_)
     return HTNOWHERE;
diff --git a/ash/wm/panels/panel_layout_manager.cc b/ash/wm/panels/panel_layout_manager.cc
index c646679..4d0f0d5 100644
--- a/ash/wm/panels/panel_layout_manager.cc
+++ b/ash/wm/panels/panel_layout_manager.cc
@@ -25,6 +25,7 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
@@ -352,9 +353,8 @@
     // back to appropriate container and ignore it.
     // TODO(varkha): Updating bounds during a drag can cause problems and a more
     // general solution is needed. See http://crbug.com/251813 .
-    child->SetDefaultParentByRootWindow(
-        child->GetRootWindow(),
-        child->GetRootWindow()->GetBoundsInScreen());
+    aura::client::ParentWindowWithContext(
+        child, child, child->GetRootWindow()->GetBoundsInScreen());
     wm::ReparentTransientChildrenOfChild(child->parent(), child);
     DCHECK(child->parent()->id() != kShellWindowId_PanelContainer);
     return;
@@ -438,9 +438,9 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// PanelLayoutManager, ash::LauncherIconObserver implementation:
+// PanelLayoutManager, ShelfIconObserver implementation:
 
-void PanelLayoutManager::OnLauncherIconPositionsChanged() {
+void PanelLayoutManager::OnShelfIconPositionsChanged() {
   // TODO: As this is called for every animation step now. Relayout needs to be
   // updated to use current icon position instead of use the ideal bounds so
   // that the panels slide with their icons instead of jumping.
@@ -450,8 +450,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager, ash::ShellObserver implementation:
 
-void PanelLayoutManager::OnShelfAlignmentChanged(
-    aura::RootWindow* root_window) {
+void PanelLayoutManager::OnShelfAlignmentChanged(aura::Window* root_window) {
   if (panel_container_->GetRootWindow() == root_window)
     Relayout();
 }
diff --git a/ash/wm/panels/panel_layout_manager.h b/ash/wm/panels/panel_layout_manager.h
index 27ec0cd..7ffe81a 100644
--- a/ash/wm/panels/panel_layout_manager.h
+++ b/ash/wm/panels/panel_layout_manager.h
@@ -9,7 +9,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/display/display_controller.h"
-#include "ash/launcher/launcher_icon_observer.h"
+#include "ash/shelf/shelf_icon_observer.h"
 #include "ash/shelf/shelf_layout_manager_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/window_state_observer.h"
@@ -53,8 +53,8 @@
 
 class ASH_EXPORT PanelLayoutManager
     : public aura::LayoutManager,
-      public ash::LauncherIconObserver,
-      public ash::ShellObserver,
+      public ShelfIconObserver,
+      public ShellObserver,
       public aura::WindowObserver,
       public aura::client::ActivationChangeObserver,
       public keyboard::KeyboardControllerObserver,
@@ -89,11 +89,11 @@
   virtual void SetChildBounds(aura::Window* child,
                               const gfx::Rect& requested_bounds) OVERRIDE;
 
-  // Overridden from ash::LauncherIconObserver
-  virtual void OnLauncherIconPositionsChanged() OVERRIDE;
+  // Overridden from ShelfIconObserver
+  virtual void OnShelfIconPositionsChanged() OVERRIDE;
 
-  // Overridden from ash::ShellObserver
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
+  // Overridden from ShellObserver
+  virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE;
 
   // Overridden from ash::wm::WindowStateObserver
   virtual void OnWindowShowTypeChanged(wm::WindowState* window_state,
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index 7c61f73..e387138 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -236,12 +236,12 @@
     test_api.RunMessageLoopUntilAnimationsDone();
   }
 
-  void SetAlignment(aura::RootWindow* root_window, ShelfAlignment alignment) {
+  void SetAlignment(aura::Window* root_window, ShelfAlignment alignment) {
     ash::Shell* shell = ash::Shell::GetInstance();
     shell->SetShelfAlignment(alignment, root_window);
   }
 
-  ShelfAlignment GetAlignment(aura::RootWindow* root_window) {
+  ShelfAlignment GetAlignment(aura::Window* root_window) {
     ash::Shell* shell = ash::Shell::GetInstance();
     return shell->GetShelfAlignment(root_window);
   }
diff --git a/ash/wm/panels/panel_window_resizer.cc b/ash/wm/panels/panel_window_resizer.cc
index 03a69f0..d8b4b26 100644
--- a/ash/wm/panels/panel_window_resizer.cc
+++ b/ash/wm/panels/panel_window_resizer.cc
@@ -17,6 +17,7 @@
 #include "ash/wm/window_util.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
@@ -76,7 +77,7 @@
     // complete it would begin positioning the panel.
     if (GetTarget()->parent() != panel_container_)
       GetPanelLayoutManager(panel_container_)->FinishDragging();
-    aura::RootWindow* dst_root = Shell::GetInstance()->display_controller()->
+    aura::Window* dst_root = Shell::GetInstance()->display_controller()->
         GetRootWindowForDisplayId(dst_display.id());
     panel_container_ = Shell::GetContainer(
         dst_root, internal::kShellWindowId_PanelContainer);
@@ -195,10 +196,11 @@
     wm::GetWindowState(GetTarget())->set_panel_attached(true);
     // We use root window coordinates to ensure that during the drag the panel
     // is reparented to a container in the root window that has that window.
-    GetTarget()->SetDefaultParentByRootWindow(
-        GetTarget()->GetRootWindow(),
-        GetTarget()->GetRootWindow()->GetBoundsInScreen());
-    wm::ReparentTransientChildrenOfChild(GetTarget()->parent(), GetTarget());
+    aura::Window* target = GetTarget();
+    aura::Window* target_root = target->GetRootWindow();
+    aura::client::ParentWindowWithContext(
+        target, target_root, target_root->GetBoundsInScreen());
+    wm::ReparentTransientChildrenOfChild(target->parent(), target);
   }
 }
 
@@ -209,10 +211,11 @@
     wm::GetWindowState(GetTarget())->set_panel_attached(should_attach_);
     // We use last known location to ensure that after the drag the panel
     // is reparented to a container in the root window that has that location.
-    GetTarget()->SetDefaultParentByRootWindow(
-        GetTarget()->GetRootWindow(),
-        gfx::Rect(last_location_, gfx::Size()));
-    wm::ReparentTransientChildrenOfChild(GetTarget()->parent(), GetTarget());
+    aura::Window* target = GetTarget();
+    aura::Window* target_root = target->GetRootWindow();
+    aura::client::ParentWindowWithContext(
+        target, target_root, gfx::Rect(last_location_, gfx::Size()));
+    wm::ReparentTransientChildrenOfChild(target->parent(), GetTarget());
   }
 
   // If we started the drag in one root window and moved into another root
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index 8cdec83..e5c4157 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -102,7 +102,7 @@
   void DetachReattachTest(aura::Window* window, int dx, int dy) {
     wm::WindowState* window_state = wm::GetWindowState(window);
     EXPECT_TRUE(window_state->panel_attached());
-    aura::RootWindow* root_window = window->GetRootWindow();
+    aura::Window* root_window = window->GetRootWindow();
     EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
     DragStart(window);
     gfx::Rect initial_bounds = window->GetBoundsInScreen();
diff --git a/ash/wm/partial_screenshot_view.cc b/ash/wm/partial_screenshot_view.cc
index e3f5528..66a4259 100644
--- a/ash/wm/partial_screenshot_view.cc
+++ b/ash/wm/partial_screenshot_view.cc
@@ -163,7 +163,7 @@
 
   is_dragging_ = false;
   if (screenshot_delegate_) {
-    aura::RootWindow *root_window =
+    aura::Window*root_window =
         GetWidget()->GetNativeWindow()->GetRootWindow();
     screenshot_delegate_->HandleTakePartialScreenshot(
         root_window,
diff --git a/ash/wm/screen_dimmer_unittest.cc b/ash/wm/screen_dimmer_unittest.cc
index 5b74e0f..a87c71b 100644
--- a/ash/wm/screen_dimmer_unittest.cc
+++ b/ash/wm/screen_dimmer_unittest.cc
@@ -71,7 +71,7 @@
   // When we resize the root window, the dimming layer should be resized to
   // match.
   gfx::Size kNewSize(400, 300);
-  Shell::GetPrimaryRootWindow()->SetHostSize(kNewSize);
+  Shell::GetPrimaryRootWindow()->GetDispatcher()->SetHostSize(kNewSize);
   EXPECT_EQ(kNewSize.ToString(), dimming_layer->bounds().size().ToString());
 }
 
diff --git a/ash/wm/session_state_animator.cc b/ash/wm/session_state_animator.cc
index 81e3fcc..38091bf 100644
--- a/ash/wm/session_state_animator.cc
+++ b/ash/wm/session_state_animator.cc
@@ -403,7 +403,7 @@
 
 bool SessionStateAnimator::TestApi::RootWindowIsAnimated(AnimationType type)
     const {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   ui::Layer* layer = root_window->layer();
   return IsLayerAnimated(layer, type);
 }
@@ -455,7 +455,7 @@
 // Fills |containers| with the containers described by |container_mask|.
 void SessionStateAnimator::GetContainers(int container_mask,
                                          aura::Window::Windows* containers) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   containers->clear();
 
   if (container_mask & DESKTOP_BACKGROUND) {
@@ -542,7 +542,7 @@
 
 void SessionStateAnimator::StartGlobalAnimation(AnimationType type,
                                                 AnimationSpeed speed) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   RunAnimationForWindow(root_window, type, speed, NULL);
 }
 
diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc
index 0d23d69..bd4a654 100644
--- a/ash/wm/stacking_controller.cc
+++ b/ash/wm/stacking_controller.cc
@@ -23,13 +23,13 @@
 // coordinates is enabled and the bounds is specified, the root window
 // that matches the window's bound will be used. Otherwise, it'll
 // return the active root window.
-aura::RootWindow* FindContainerRoot(const gfx::Rect& bounds) {
+aura::Window* FindContainerRoot(const gfx::Rect& bounds) {
   if (bounds.x() == 0 && bounds.y() == 0 && bounds.IsEmpty())
     return Shell::GetTargetRootWindow();
   return wm::GetRootWindowMatching(bounds);
 }
 
-aura::Window* GetContainerById(aura::RootWindow* root, int id) {
+aura::Window* GetContainerById(aura::Window* root, int id) {
   return Shell::GetContainer(root, id);
 }
 
@@ -50,7 +50,7 @@
 }
 
 internal::AlwaysOnTopController*
-GetAlwaysOnTopController(aura::RootWindow* root_window) {
+GetAlwaysOnTopController(aura::Window* root_window) {
   return internal::GetRootWindowController(root_window)->
       always_on_top_controller();
 }
@@ -67,12 +67,12 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// StackingController, aura::StackingClient implementation:
+// StackingController, aura::client::WindowTreeClient implementation:
 
 aura::Window* StackingController::GetDefaultParent(aura::Window* context,
                                                    aura::Window* window,
                                                    const gfx::Rect& bounds) {
-  aura::RootWindow* target_root = NULL;
+  aura::Window* target_root = NULL;
   if (window->transient_parent()) {
     // Transient window should use the same root as its transient parent.
     target_root = window->transient_parent()->GetRootWindow();
@@ -115,7 +115,7 @@
 // StackingController, private:
 
 aura::Window* StackingController::GetSystemModalContainer(
-    aura::RootWindow* root,
+    aura::Window* root,
     aura::Window* window) const {
   DCHECK(IsSystemModal(window));
 
diff --git a/ash/wm/stacking_controller.h b/ash/wm/stacking_controller.h
index 07003cb..bbe715e 100644
--- a/ash/wm/stacking_controller.h
+++ b/ash/wm/stacking_controller.h
@@ -9,24 +9,19 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/stacking_client.h"
-
-namespace aura{
-class RootWindow;
-}
+#include "ui/aura/client/window_tree_client.h"
 
 namespace ash {
-
 namespace internal {
 class AlwaysOnTopController;
 }
 
-class ASH_EXPORT StackingController : public aura::client::StackingClient {
+class ASH_EXPORT StackingController : public aura::client::WindowTreeClient {
  public:
   StackingController();
   virtual ~StackingController();
 
-  // Overridden from aura::client::StackingClient:
+  // Overridden from aura::client::WindowTreeClient:
   virtual aura::Window* GetDefaultParent(aura::Window* context,
                                          aura::Window* window,
                                          const gfx::Rect& bounds) OVERRIDE;
@@ -37,7 +32,7 @@
   // normal modal container.
   // Otherwise those that originate from LockScreen container and above are
   // placed in the screen lock modal container.
-  aura::Window* GetSystemModalContainer(aura::RootWindow* root,
+  aura::Window* GetSystemModalContainer(aura::Window* root,
                                         aura::Window* window) const;
 
   DISALLOW_COPY_AND_ASSIGN(StackingController);
diff --git a/ash/wm/stacking_controller_unittest.cc b/ash/wm/stacking_controller_unittest.cc
index b7b1f1b..e0ccaa1 100644
--- a/ash/wm/stacking_controller_unittest.cc
+++ b/ash/wm/stacking_controller_unittest.cc
@@ -50,7 +50,7 @@
   scoped_ptr<Window> w1(CreateTestWindow());
   w2->AddTransientChild(w1.get());
   w1->SetBounds(gfx::Rect(10, 11, 250, 251));
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   w1->Show();
   wm::ActivateWindow(w1.get());
 
diff --git a/ash/wm/sticky_keys.cc b/ash/wm/sticky_keys.cc
index 74a8699..dd2f389 100644
--- a/ash/wm/sticky_keys.cc
+++ b/ash/wm/sticky_keys.cc
@@ -4,8 +4,10 @@
 
 #include "ash/wm/sticky_keys.h"
 
+#if defined(USE_X11)
 #include <X11/Xlib.h>
 #undef RootWindow
+#endif
 
 #include "base/basictypes.h"
 #include "base/debug/stack_trace.h"
@@ -40,7 +42,7 @@
 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event,
                                                      aura::Window* target) {
   DCHECK(target);
-  target->GetRootWindow()->AsRootWindowHostDelegate()->OnHostKeyEvent(event);
+  target->GetDispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(event);
 }
 
 }  // namespace
@@ -75,6 +77,7 @@
     : modifier_flag_(target_modifier_flag),
       current_state_(DISABLED),
       keyevent_from_myself_(false),
+      preparing_to_enable_(false),
       delegate_(delegate) {
 }
 
@@ -133,11 +136,19 @@
 bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
   switch (TranslateKeyEvent(event)) {
     case TARGET_MODIFIER_UP:
-      current_state_ = ENABLED;
-      modifier_up_event_.reset(event->Copy());
-      return true;
+      if (preparing_to_enable_) {
+        preparing_to_enable_ = false;
+        current_state_ = ENABLED;
+        modifier_up_event_.reset(event->Copy());
+        return true;
+      }
+      return false;
     case TARGET_MODIFIER_DOWN:
+      preparing_to_enable_ = true;
+      return false;
     case NORMAL_KEY_DOWN:
+      preparing_to_enable_ = false;
+      return false;
     case NORMAL_KEY_UP:
     case OTHER_MODIFIER_DOWN:
     case OTHER_MODIFIER_UP:
@@ -199,6 +210,7 @@
 }
 
 void StickyKeysHandler::AppendModifier(ui::KeyEvent* event) {
+#if defined(USE_X11)
   XEvent* xev = event->native_event();
   XKeyEvent* xkey = &(xev->xkey);
   switch (modifier_flag_) {
@@ -214,6 +226,9 @@
     default:
       NOTREACHED();
   }
+#elif defined(USE_OZONE)
+  NOTIMPLEMENTED() << "Modifier key is not handled";
+#endif
   event->set_flags(event->flags() | modifier_flag_);
   event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
                                                    event->flags()));
diff --git a/ash/wm/sticky_keys.h b/ash/wm/sticky_keys.h
index 7a75a43..40e8a80 100644
--- a/ash/wm/sticky_keys.h
+++ b/ash/wm/sticky_keys.h
@@ -167,6 +167,12 @@
   // True if the received key event is sent by StickyKeyHandler.
   bool keyevent_from_myself_;
 
+  // True if we received the TARGET_MODIFIER_DOWN event while in the DISABLED
+  // state but before we receive the TARGET_MODIFIER_UP event. Normal
+  // shortcuts (eg. ctrl + t) during this time will prevent a transition to
+  // the ENABLED state.
+  bool preparing_to_enable_;
+
   // The modifier up key event to be sent on non modifier key on ENABLED state.
   scoped_ptr<ui::KeyEvent> modifier_up_event_;
 
diff --git a/ash/wm/sticky_keys_unittest.cc b/ash/wm/sticky_keys_unittest.cc
index d9e952f..1d77eef 100644
--- a/ash/wm/sticky_keys_unittest.cc
+++ b/ash/wm/sticky_keys_unittest.cc
@@ -241,4 +241,28 @@
   EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
 }
 
+TEST_F(StickyKeysTest, NormalShortcutTest) {
+  // Sticky keys should not be enabled if we perform a normal shortcut.
+  scoped_ptr<ui::KeyEvent> ev;
+  MockStickyKeysHandlerDelegate* mock_delegate =
+      new MockStickyKeysHandlerDelegate();
+  StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+
+  EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
+
+  // Perform ctrl+n shortcut.
+  ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
+  sticky_key.HandleKeyEvent(ev.get());
+  ev.reset(GenerateKey(true, ui::VKEY_N));
+  sticky_key.HandleKeyEvent(ev.get());
+  ev.reset(GenerateKey(false, ui::VKEY_N));
+  sticky_key.HandleKeyEvent(ev.get());
+  EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
+
+  // Sticky keys should not be enabled afterwards.
+  ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
+  sticky_key.HandleKeyEvent(ev.get());
+  EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
+}
+
 }  // namespace ash
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc
index 65e3151..d4edc82 100644
--- a/ash/wm/system_gesture_event_filter_unittest.cc
+++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -171,9 +171,11 @@
 
 } // namespace
 
-class SystemGestureEventFilterTest : public AshTestBase {
+class SystemGestureEventFilterTest
+    : public AshTestBase,
+      public testing::WithParamInterface<bool> {
  public:
-  SystemGestureEventFilterTest() : AshTestBase() {}
+  SystemGestureEventFilterTest() : AshTestBase(), docked_enabled_(GetParam()) {}
   virtual ~SystemGestureEventFilterTest() {}
 
   internal::LongPressAffordanceHandler* GetLongPressAffordance() {
@@ -200,6 +202,10 @@
   virtual void SetUp() OVERRIDE {
     CommandLine::ForCurrentProcess()->AppendSwitch(
         ash::switches::kAshEnableAdvancedGestures);
+    if (docked_enabled_) {
+      CommandLine::ForCurrentProcess()->AppendSwitch(
+          ash::switches::kAshEnableDockedWindows);
+    }
     test::AshTestBase::SetUp();
     // Enable brightness key.
     test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
@@ -207,6 +213,9 @@
   }
 
  private:
+  // true if docked windows are enabled with a flag.
+  bool docked_enabled_;
+
   DISALLOW_COPY_AND_ASSIGN(SystemGestureEventFilterTest);
 };
 
@@ -234,7 +243,8 @@
                         gfx::Point(-10, ypos + ypos_half),
                         touch_id,
                         ui::EventTimeForNow());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+  root_window->GetDispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
+      &press1);
 
   // There is a noise filter which will require several calls before it
   // allows the touch event through.
@@ -275,8 +285,8 @@
   EXPECT_EQ(expected_value, delegate->handle_percent());
 }
 
-TEST_F(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+TEST_P(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   aura::test::TestWindowDelegate delegate;
   scoped_ptr<aura::Window> window0(
@@ -300,7 +310,8 @@
                        gfx::Point(10, 10),
                        kTouchId,
                        ui::EventTimeForNow());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+  root_window->GetDispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
+      &press);
   EXPECT_TRUE(window1->HasCapture());
 
   base::OneShotTimer<internal::LongPressAffordanceHandler>* timer =
@@ -334,8 +345,8 @@
   EXPECT_EQ(NULL, GetLongPressAffordanceView());
 }
 
-TEST_F(SystemGestureEventFilterTest, MultiFingerSwipeGestures) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+TEST_P(SystemGestureEventFilterTest, MultiFingerSwipeGestures) {
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
       new ResizableWidgetDelegate, root_window, gfx::Rect(0, 0, 600, 600));
   toplevel->Show();
@@ -392,9 +403,9 @@
   EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
 }
 
-TEST_F(SystemGestureEventFilterTest, TwoFingerDrag) {
+TEST_P(SystemGestureEventFilterTest, TwoFingerDrag) {
   gfx::Rect bounds(0, 0, 600, 600);
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
       new ResizableWidgetDelegate, root_window, bounds);
   toplevel->Show();
@@ -450,8 +461,8 @@
   EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
 }
 
-TEST_F(SystemGestureEventFilterTest, TwoFingerDragTwoWindows) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+TEST_P(SystemGestureEventFilterTest, TwoFingerDragTwoWindows) {
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   ui::GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels(0);
   views::Widget* first = views::Widget::CreateWindowWithContextAndBounds(
       new ResizableWidgetDelegate, root_window, gfx::Rect(0, 0, 50, 100));
@@ -474,8 +485,9 @@
   };
 
   aura::test::EventGenerator generator(root_window);
+  // Do not drag too fast to avoid fling.
   generator.GestureMultiFingerScroll(kTouchPoints, points,
-      15, kSteps, 0, 150);
+      50, kSteps, 0, 150);
 
   EXPECT_NE(first_bounds.ToString(),
             first->GetWindowBoundsInScreen().ToString());
@@ -483,9 +495,9 @@
             second->GetWindowBoundsInScreen().ToString());
 }
 
-TEST_F(SystemGestureEventFilterTest, WindowsWithMaxSizeDontSnap) {
+TEST_P(SystemGestureEventFilterTest, WindowsWithMaxSizeDontSnap) {
   gfx::Rect bounds(150, 150, 100, 100);
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
       new MaxSizeWidgetDelegate, root_window, bounds);
   toplevel->Show();
@@ -542,9 +554,9 @@
       toplevel->GetWindowBoundsInScreen().ToString());
 }
 
-TEST_F(SystemGestureEventFilterTest, TwoFingerDragEdge) {
+TEST_P(SystemGestureEventFilterTest, TwoFingerDragEdge) {
   gfx::Rect bounds(0, 0, 100, 100);
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
       new ResizableWidgetDelegate, root_window, bounds);
   toplevel->Show();
@@ -569,5 +581,82 @@
             toplevel->GetNativeWindow()->bounds().ToString());
 }
 
+TEST_P(SystemGestureEventFilterTest, TwoFingerDragDelayed) {
+  gfx::Rect bounds(0, 0, 100, 100);
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
+  views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
+      new ResizableWidgetDelegate, root_window, bounds);
+  toplevel->Show();
+
+  const int kSteps = 15;
+  const int kTouchPoints = 2;
+  gfx::Point points[kTouchPoints] = {
+    gfx::Point(30, 20),  // Caption
+    gfx::Point(34, 20),  // Caption
+  };
+  int delays[kTouchPoints] = {0, 120};
+
+  EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
+        GetNonClientComponent(points[0]));
+  EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
+        GetNonClientComponent(points[1]));
+
+  aura::test::EventGenerator generator(root_window,
+                                       toplevel->GetNativeWindow());
+
+  bounds = toplevel->GetNativeWindow()->bounds();
+  // Swipe right and down starting with one finger.
+  // Add another finger after 120ms and continue dragging.
+  // The window should move and the drag should be determined by the center
+  // point between the fingers.
+  generator.GestureMultiFingerScrollWithDelays(
+      kTouchPoints, points, delays, 15, kSteps, 150, 150);
+  bounds += gfx::Vector2d(150 + (points[1].x() - points[0].x()) / 2, 150);
+  EXPECT_EQ(bounds.ToString(),
+            toplevel->GetNativeWindow()->bounds().ToString());
+}
+
+TEST_P(SystemGestureEventFilterTest, ThreeFingerGestureStopsDrag) {
+  gfx::Rect bounds(0, 0, 100, 100);
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
+  views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
+      new ResizableWidgetDelegate, root_window, bounds);
+  toplevel->Show();
+
+  const int kSteps = 10;
+  const int kTouchPoints = 3;
+  gfx::Point points[kTouchPoints] = {
+    gfx::Point(30, 20),  // Caption
+    gfx::Point(34, 20),  // Caption
+    gfx::Point(38, 20),  // Caption
+  };
+  int delays[kTouchPoints] = {0, 0, 120};
+
+  EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
+        GetNonClientComponent(points[0]));
+  EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
+        GetNonClientComponent(points[1]));
+
+  aura::test::EventGenerator generator(root_window,
+                                       toplevel->GetNativeWindow());
+
+  bounds = toplevel->GetNativeWindow()->bounds();
+  // Swipe right and down starting with two fingers.
+  // Add third finger after 120ms and continue dragging.
+  // The window should start moving but stop when the 3rd finger touches down.
+  const int kEventSeparation = 15;
+  generator.GestureMultiFingerScrollWithDelays(
+      kTouchPoints, points, delays, kEventSeparation, kSteps, 150, 150);
+  int expected_drag = 150 / kSteps * 120 / kEventSeparation;
+  bounds += gfx::Vector2d(expected_drag, expected_drag);
+  EXPECT_EQ(bounds.ToString(),
+            toplevel->GetNativeWindow()->bounds().ToString());
+}
+
+// Tests run twice - with docked windows disabled or enabled.
+INSTANTIATE_TEST_CASE_P(DockedWindowsDisabledOrEnabled,
+                        SystemGestureEventFilterTest,
+                        testing::Bool());
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc
index 0a11329..551382b 100644
--- a/ash/wm/system_modal_container_layout_manager_unittest.cc
+++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -90,7 +90,7 @@
                                          mouse_presses_(0) {}
   virtual ~EventTestWindow() {}
 
-  aura::Window* OpenTestWindowWithContext(aura::RootWindow* context) {
+  aura::Window* OpenTestWindowWithContext(aura::Window* context) {
     views::Widget* widget =
         views::Widget::CreateWindowWithContext(this, context);
     widget->Show();
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index f6d5902..ef8051d 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -335,7 +335,7 @@
   DCHECK(!in_move_loop_);  // Can only handle one nested loop at a time.
   in_move_loop_ = true;
   move_cancelled_ = false;
-  aura::RootWindow* root_window = source->GetRootWindow();
+  aura::Window* root_window = source->GetRootWindow();
   DCHECK(root_window);
   gfx::Point drag_location;
   if (move_source == aura::client::WINDOW_MOVE_SOURCE_TOUCH &&
@@ -345,7 +345,7 @@
         GetLastTouchPointForTarget(source, &drag_location);
     DCHECK(has_point);
   } else {
-    drag_location = root_window->GetLastMouseLocationInRoot();
+    drag_location = root_window->GetDispatcher()->GetLastMouseLocationInRoot();
     aura::Window::ConvertPointToTarget(
         root_window, source->parent(), &drag_location);
   }
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index ef1f1e5..7bb9d27 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -18,6 +18,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/test/test_windows.h"
 #include "ui/aura/window.h"
 #include "ui/gfx/rect.h"
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index 2968f73..6f24d6d 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -143,7 +143,7 @@
   Shell::GetInstance()->RemovePreTargetHandler(
       shell_test.input_method_event_filter());
 
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   root_window->SetBounds(gfx::Rect(0, 0, 510, 510));
 
   // Supplied ids are negative so as not to collide with shell ids.
@@ -183,21 +183,23 @@
       aura::client::GetFocusClient(w121.get());
   EXPECT_EQ(w121.get(), focus_client->GetFocusedWindow());
 
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+
   // The key press should be sent to the focused sub-window.
   ui::KeyEvent keyev(ui::ET_KEY_PRESSED, ui::VKEY_E, 0, false);
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev);
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev);
   EXPECT_EQ(ui::VKEY_E, w121delegate->last_key_code());
 
   // Touch on a sub-window (w122) to focus it.
   gfx::Point click_point = w122->bounds().CenterPoint();
   aura::Window::ConvertPointToTarget(w122->parent(), root_window, &click_point);
   ui::TouchEvent touchev(ui::ET_TOUCH_PRESSED, click_point, 0, getTime());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev);
   focus_client = aura::client::GetFocusClient(w122.get());
   EXPECT_EQ(w122.get(), focus_client->GetFocusedWindow());
 
   // The key press should be sent to the focused sub-window.
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev);
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev);
   EXPECT_EQ(ui::VKEY_E, w122delegate->last_key_code());
 
   // Hiding the focused window will set the focus to its parent if
@@ -234,7 +236,7 @@
   EXPECT_EQ(aura::client::GetFocusClient(w12.get()),
             aura::client::GetFocusClient(w123.get()));
   EXPECT_EQ(NULL, aura::client::GetFocusClient(w12.get())->GetFocusedWindow());
-  EXPECT_FALSE(root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev));
 
   // Set the focus back to w123
   aura::client::SetActivationDelegate(w1.get(), NULL);
@@ -248,12 +250,12 @@
   // parent window is not focusable.
   w12->RemoveChild(w123.get());
   EXPECT_EQ(NULL, aura::client::GetFocusClient(w123.get()));
-  EXPECT_FALSE(root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev));
+  EXPECT_FALSE(dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&keyev));
 }
 
 // Various assertion testing for activating windows.
 TEST_F(WindowManagerTest, ActivateOnMouse) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   test::TestActivationDelegate d1;
   aura::test::TestWindowDelegate wd;
@@ -408,7 +410,7 @@
 
 // Essentially the same as ActivateOnMouse, but for touch events.
 TEST_F(WindowManagerTest, ActivateOnTouch) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   test::TestActivationDelegate d1;
   aura::test::TestWindowDelegate wd;
@@ -438,7 +440,9 @@
   gfx::Point press_point = w2->bounds().CenterPoint();
   aura::Window::ConvertPointToTarget(w2->parent(), root_window, &press_point);
   ui::TouchEvent touchev1(ui::ET_TOUCH_PRESSED, press_point, 0, getTime());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev1);
+
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev1);
 
   // Window2 should have become active.
   EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
@@ -455,7 +459,7 @@
   aura::Window::ConvertPointToTarget(w1->parent(), root_window, &press_point);
   d1.set_activate(false);
   ui::TouchEvent touchev2(ui::ET_TOUCH_PRESSED, press_point, 1, getTime());
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev2);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev2);
 
   // Window2 should still be active and focused.
   EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
@@ -479,7 +483,7 @@
 }
 
 TEST_F(WindowManagerTest, MouseEventCursors) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   // Create a window.
   const int kWindowLeft = 123;
@@ -497,76 +501,78 @@
   gfx::Point point2(kWindowLeft + 1, kWindowTop + 1);
   aura::Window::ConvertPointToTarget(window->parent(), root_window, &point2);
 
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+
   // Cursor starts as a pointer (set during Shell::Init()).
-  EXPECT_EQ(ui::kCursorPointer, root_window->last_cursor().native_type());
+  EXPECT_EQ(ui::kCursorPointer, dispatcher->last_cursor().native_type());
 
   {
     // Resize edges and corners show proper cursors.
     window_delegate.set_hittest_code(HTBOTTOM);
     ui::MouseEvent move1(ui::ET_MOUSE_MOVED, point1, point1, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
-    EXPECT_EQ(ui::kCursorSouthResize, root_window->last_cursor().native_type());
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
+    EXPECT_EQ(ui::kCursorSouthResize, dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTBOTTOMLEFT);
     ui::MouseEvent move2(ui::ET_MOUSE_MOVED, point2, point2, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
     EXPECT_EQ(ui::kCursorSouthWestResize,
-              root_window->last_cursor().native_type());
+              dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTBOTTOMRIGHT);
     ui::MouseEvent move1(ui::ET_MOUSE_MOVED, point1, point1, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
     EXPECT_EQ(ui::kCursorSouthEastResize,
-              root_window->last_cursor().native_type());
+              dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTLEFT);
     ui::MouseEvent move2(ui::ET_MOUSE_MOVED, point2, point2, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
-    EXPECT_EQ(ui::kCursorWestResize, root_window->last_cursor().native_type());
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
+    EXPECT_EQ(ui::kCursorWestResize, dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTRIGHT);
     ui::MouseEvent move1(ui::ET_MOUSE_MOVED, point1, point1, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
-    EXPECT_EQ(ui::kCursorEastResize, root_window->last_cursor().native_type());
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
+    EXPECT_EQ(ui::kCursorEastResize, dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTTOP);
     ui::MouseEvent move2(ui::ET_MOUSE_MOVED, point2, point2, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
-    EXPECT_EQ(ui::kCursorNorthResize, root_window->last_cursor().native_type());
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
+    EXPECT_EQ(ui::kCursorNorthResize, dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTTOPLEFT);
     ui::MouseEvent move1(ui::ET_MOUSE_MOVED, point1, point1, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
     EXPECT_EQ(ui::kCursorNorthWestResize,
-              root_window->last_cursor().native_type());
+              dispatcher->last_cursor().native_type());
   }
 
   {
     window_delegate.set_hittest_code(HTTOPRIGHT);
     ui::MouseEvent move2(ui::ET_MOUSE_MOVED, point2, point2, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move2);
     EXPECT_EQ(ui::kCursorNorthEastResize,
-              root_window->last_cursor().native_type());
+              dispatcher->last_cursor().native_type());
   }
 
   {
     // Client area uses null cursor.
     window_delegate.set_hittest_code(HTCLIENT);
     ui::MouseEvent move1(ui::ET_MOUSE_MOVED, point1, point1, 0x0);
-    root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
-    EXPECT_EQ(ui::kCursorNull, root_window->last_cursor().native_type());
+    dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&move1);
+    EXPECT_EQ(ui::kCursorNull, dispatcher->last_cursor().native_type());
   }
 }
 
@@ -576,7 +582,7 @@
 #define MAYBE_TransformActivate TransformActivate
 #endif
 TEST_F(WindowManagerTest, MAYBE_TransformActivate) {
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   gfx::Size size = root_window->bounds().size();
   EXPECT_EQ(gfx::Rect(size).ToString(),
             Shell::GetScreen()->GetDisplayNearestPoint(
@@ -601,13 +607,14 @@
                           miss_point,
                           miss_point,
                           ui::EF_LEFT_MOUSE_BUTTON);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseev1);
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseev1);
   EXPECT_EQ(NULL, aura::client::GetFocusClient(w1.get())->GetFocusedWindow());
   ui::MouseEvent mouseup(ui::ET_MOUSE_RELEASED,
                          miss_point,
                          miss_point,
                          ui::EF_LEFT_MOUSE_BUTTON);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseup);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseup);
 
   gfx::Point hit_point(5, 15);
   transform.TransformPoint(&hit_point);
@@ -615,7 +622,7 @@
                           hit_point,
                           hit_point,
                           ui::EF_LEFT_MOUSE_BUTTON);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseev2);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseev2);
   EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
   EXPECT_EQ(w1.get(),
             aura::client::GetFocusClient(w1.get())->GetFocusedWindow());
@@ -628,7 +635,7 @@
   Shell::GetInstance()->RemovePreTargetHandler(
       shell_test.input_method_event_filter());
 
-  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   // Creates a window and make it active
   scoped_ptr<aura::Window> w1(CreateTestWindowInShell(
@@ -647,10 +654,11 @@
 
   // Dispatches mouse and keyboard events.
   ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
   ui::MouseEvent mouse_pressed(
       ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0), 0x0);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_pressed);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_pressed);
 
   // Both filters should get the events.
   EXPECT_EQ(1, f1->num_key_events());
@@ -666,10 +674,10 @@
   f1->set_mouse_event_handling_result(ui::ER_CONSUMED);
 
   // Dispatches events.
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
   ui::MouseEvent mouse_released(
       ui::ET_MOUSE_RELEASED, gfx::Point(0, 0), gfx::Point(0, 0), 0x0);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_released);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_released);
 
   // f1 should still get the events but f2 no longer gets them.
   EXPECT_EQ(1, f1->num_key_events());
@@ -684,8 +692,8 @@
   env_filter->RemoveHandler(f1.get());
 
   // Dispatches events.
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
-  root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_pressed);
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&key_event);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_pressed);
 
   // f1 should get no events since it's out and f2 should get them.
   EXPECT_EQ(0, f1->num_key_events());
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index 6f93fdc..58f4fb9 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -46,8 +46,14 @@
 // through an automatic "intelligent" window management option.
 const int kWindowAutoMoveDurationMS = 125;
 
+// If set to true all window repositioning actions will be ignored. Set through
+// WindowPositioner::SetIgnoreActivations().
+static bool disable_auto_positioning = false;
+
 // Check if any management should be performed (with a given |window|).
 bool UseAutoWindowManager(const aura::Window* window) {
+  if (disable_auto_positioning)
+    return false;
   const wm::WindowState* window_state = wm::GetWindowState(window);
   return window_state->tracked_by_workspace() &&
       window_state->window_position_managed();
@@ -57,6 +63,8 @@
 // not minimized/maximized/the user has changed it's size by hand already.
 // It furthermore checks for the WindowIsManaged status.
 bool WindowPositionCanBeManaged(const aura::Window* window) {
+  if (disable_auto_positioning)
+    return false;
   const wm::WindowState* window_state = wm::GetWindowState(window);
   return window_state->window_position_managed() &&
       !window_state->IsMinimized() &&
@@ -138,7 +146,7 @@
 }
 
 // Get the first open (non minimized) window which is on the screen defined.
-aura::Window* GetReferenceWindow(const aura::RootWindow* root_window,
+aura::Window* GetReferenceWindow(const aura::Window* root_window,
                                  const aura::Window* exclude,
                                  bool *single_window) {
   if (single_window)
@@ -212,27 +220,25 @@
     ui::WindowShowState* show_state_out) {
 
   // Always open new window in the target display.
-  aura::RootWindow* target = Shell::GetTargetRootWindow();
+  aura::Window* target = Shell::GetTargetRootWindow();
 
   aura::Window* top_window = GetReferenceWindow(target, NULL, NULL);
   // Our window should not have any impact if we are already on top.
   if (top_window == new_window)
     top_window = NULL;
 
-  // If there is no valid other window we take the coordinates as is.
+  // If there is no valid other window we take and adjust the passed coordinates
+  // and show state.
   if (!top_window) {
     gfx::Rect work_area = screen->GetDisplayNearestWindow(target).work_area();
 
-    if (is_saved_bounds) {
-      // Restore to saved state - if there is one.
-      bounds_in_out->AdjustToFit(work_area);
+    bounds_in_out->AdjustToFit(work_area);
+    // Use adjusted saved bounds, if there is one.
+    if (is_saved_bounds)
       return;
-    }
-
     // When using "small screens" we want to always open in full screen mode.
     if (show_state_in == ui::SHOW_STATE_DEFAULT &&
-        work_area.width() <=
-        WindowPositioner::GetForceMaximizedWidthLimit() &&
+        work_area.width() <= GetForceMaximizedWidthLimit() &&
         (!new_window || !wm::GetWindowState(new_window)->IsFullscreen())) {
       *show_state_out = ui::SHOW_STATE_MAXIMIZED;
     }
@@ -267,6 +273,13 @@
 }
 
 // static
+bool WindowPositioner::DisableAutoPositioning(bool ignore) {
+  bool old_state = disable_auto_positioning;
+  disable_auto_positioning = ignore;
+  return old_state;
+}
+
+// static
 void WindowPositioner::RearrangeVisibleWindowOnShow(
     aura::Window* added_window) {
   wm::WindowState* added_window_state = wm::GetWindowState(added_window);
diff --git a/ash/wm/window_positioner.h b/ash/wm/window_positioner.h
index eb6ef61..45ad779 100644
--- a/ash/wm/window_positioner.h
+++ b/ash/wm/window_positioner.h
@@ -66,6 +66,10 @@
   static void RearrangeVisibleWindowOnHideOrRemove(
       const aura::Window* removed_window);
 
+  // Turn the automatic positioning logic temporarily off. Returns the previous
+  // state.
+  static bool DisableAutoPositioning(bool ignore);
+
   // Check if after insertion or showing of the given |added_window|
   // an automated desktop location management can be performed and
   // rearrange accordingly.
diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc
new file mode 100644
index 0000000..497e014
--- /dev/null
+++ b/ash/wm/window_positioner_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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 "ash/wm/window_positioner.h"
+
+#include "ash/shell.h"
+#include "ash/shell/toplevel_window.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/window_state.h"
+#include "ui/aura/root_window.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+typedef test::AshTestBase WindowPositionerTest;
+
+TEST_F(WindowPositionerTest, OpenMaximizedWindowOnSecondDisplay) {
+  if (!SupportsMultipleDisplays())
+    return;
+  UpdateDisplay("400x400,500x500");
+  Shell::GetInstance()->set_target_root_window(
+      Shell::GetAllRootWindows()[1]);
+  shell::ToplevelWindow::CreateParams params;
+  params.can_resize = true;
+  params.can_maximize = true;
+  views::Widget* widget =
+      shell::ToplevelWindow::CreateToplevelWindow(params);
+  EXPECT_EQ("400,0 500x453", widget->GetWindowBoundsInScreen().ToString());
+}
+
+TEST_F(WindowPositionerTest, OpenDefaultWindowOnSecondDisplay) {
+  if (!SupportsMultipleDisplays())
+    return;
+  UpdateDisplay("400x400,1400x900");
+  aura::Window* second_root_window = Shell::GetAllRootWindows()[1];
+  Shell::GetInstance()->set_target_root_window(
+      second_root_window);
+  shell::ToplevelWindow::CreateParams params;
+  params.can_resize = true;
+  params.can_maximize = true;
+  views::Widget* widget =
+      shell::ToplevelWindow::CreateToplevelWindow(params);
+  gfx::Rect bounds = widget->GetWindowBoundsInScreen();
+  // The window should be in the 2nd display with the default size.
+  EXPECT_EQ("300x300", bounds.size().ToString());
+  EXPECT_TRUE(Shell::GetScreen()->GetDisplayNearestWindow(
+      second_root_window).bounds().Contains(bounds));
+}
+
+}  // namespace
diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc
index 4df599a..ced25b2 100644
--- a/ash/wm/window_properties.cc
+++ b/ash/wm/window_properties.cc
@@ -11,8 +11,6 @@
 
 namespace ash {
 namespace internal {
-DEFINE_WINDOW_PROPERTY_KEY(bool, kAnimateToFullscreenKey, true);
-DEFINE_WINDOW_PROPERTY_KEY(bool, kFullscreenUsesMinimalChromeKey, false);
 DEFINE_WINDOW_PROPERTY_KEY(bool, kStayInSameRootWindowKey, false);
 DEFINE_WINDOW_PROPERTY_KEY(bool, kUsesScreenCoordinatesKey, false);
 DEFINE_OWNED_WINDOW_PROPERTY_KEY(wm::WindowState,
diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h
index 1bf28ff..74ae495 100644
--- a/ash/wm/window_properties.h
+++ b/ash/wm/window_properties.h
@@ -25,16 +25,6 @@
 
 // Alphabetical sort.
 
-//  A property key to suppress the cross-fade animation for the transition to
-// the fullscreen state.
-extern const aura::WindowProperty<bool>* const kAnimateToFullscreenKey;
-
-// A property key to indicate whether there is any chrome at all that cannot be
-// hidden when the window is fullscreen. This is unrelated to whether the full
-// chrome can be revealed by hovering the mouse at the top of the screen.
-ASH_EXPORT extern const aura::WindowProperty<bool>* const
-    kFullscreenUsesMinimalChromeKey;
-
 // If this is set to true, the window stays in the same root window
 // even if the bounds outside of its root window is set.
 // This is exported as it's used in the tests.
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 2afba08..b3448e9 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -8,6 +8,7 @@
 #include "ash/screen_ash.h"
 #include "ash/shell_window_ids.h"
 #include "ash/wm/window_properties.h"
+#include "ash/wm/window_state_delegate.h"
 #include "ash/wm/window_state_observer.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_types.h"
@@ -36,7 +37,10 @@
       ignored_by_shelf_(false),
       can_consume_system_keys_(false),
       top_row_keys_are_function_keys_(false),
+      window_resizer_(NULL),
       always_restores_to_restore_bounds_(false),
+      hide_shelf_when_fullscreen_(true),
+      animate_to_fullscreen_(true),
       window_show_type_(ToWindowShowType(GetShowState())) {
   window_->AddObserver(this);
 }
@@ -44,6 +48,11 @@
 WindowState::~WindowState() {
 }
 
+void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) {
+  DCHECK(!delegate_.get());
+  delegate_ = delegate.Pass();
+}
+
 ui::WindowShowState WindowState::GetShowState() const {
   return window_->GetProperty(aura::client::kShowStateKey);
 }
@@ -73,6 +82,11 @@
   return IsActiveWindow(window_);
 }
 
+bool WindowState::IsDocked() const {
+  return window_->parent() &&
+      window_->parent()->id() == internal::kShellWindowId_DockedContainer;
+}
+
 bool WindowState::CanMaximize() const {
   return window_->GetProperty(aura::client::kCanMaximizeKey);
 }
@@ -154,6 +168,22 @@
     Maximize();
 }
 
+void WindowState::ToggleFullscreen() {
+  // Window which cannot be maximized should not be fullscreened.
+  // It can, however, be restored if it was fullscreened.
+  bool is_fullscreen = IsFullscreen();
+  if (!is_fullscreen && !CanMaximize())
+    return;
+  if (delegate_ && delegate_->ToggleFullscreen(this))
+    return;
+  if (is_fullscreen) {
+    Restore();
+  } else {
+    window_->SetProperty(aura::client::kShowStateKey,
+                         ui::SHOW_STATE_FULLSCREEN);
+  }
+}
+
 void WindowState::SetBoundsInScreen(
     const gfx::Rect& bounds_in_screen) {
   gfx::Rect bounds_in_parent =
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 8c68e24..320977e 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -22,7 +22,10 @@
 }
 
 namespace ash {
+class WindowResizer;
+
 namespace wm {
+class WindowStateDelegate;
 class WindowStateObserver;
 
 // WindowState manages and defines ash specific window state and
@@ -46,6 +49,8 @@
   aura::Window* window() { return window_; }
   const aura::Window* window() const { return window_; }
 
+  void SetDelegate(scoped_ptr<WindowStateDelegate> delegate);
+
   // Returns the window's current show state.
   ui::WindowShowState GetShowState() const;
 
@@ -63,6 +68,7 @@
   // SHOW_STATE_DEFAULT.
   bool IsNormalShowState() const;
   bool IsActive() const;
+  bool IsDocked() const;
 
   // Checks if the window can change its state accordingly.
   bool CanMaximize() const;
@@ -81,6 +87,7 @@
   void Deactivate();
   void Restore();
   void ToggleMaximized();
+  void ToggleFullscreen();
   void SnapLeft(const gfx::Rect& bounds);
   void SnapRight(const gfx::Rect& bounds);
 
@@ -122,6 +129,25 @@
     always_restores_to_restore_bounds_ = value;
   }
 
+  // Gets/sets whether the shelf should be hidden when this window is
+  // fullscreen.
+  bool hide_shelf_when_fullscreen() const {
+    return hide_shelf_when_fullscreen_;
+  }
+
+  void set_hide_shelf_when_fullscreen(bool value) {
+    hide_shelf_when_fullscreen_ = value;
+  }
+
+  // Sets/gets the flag to suppress the cross-fade animation for
+  // the transition to the fullscreen state.
+  bool animate_to_fullscreen() const {
+    return animate_to_fullscreen_;
+  }
+  void set_animate_to_fullscreen(bool value) {
+    animate_to_fullscreen_ = value;
+  }
+
   // Gets/Sets the bounds of the window before it was moved by the auto window
   // management. As long as it was not auto-managed, it will return NULL.
   const gfx::Rect* pre_auto_manage_window_bounds() const {
@@ -195,6 +221,19 @@
     top_row_keys_are_function_keys_ = value;
   }
 
+  // Returns or sets a pointer to WindowResizer when resizing is active.
+  // The pointer to a WindowResizer that is returned is set when a resizer gets
+  // created and cleared when it gets destroyed. WindowState does not own the
+  // |window_resizer_| instance and the resizer's lifetime is controlled
+  // externally. It can be used to avoid creating multiple instances of a
+  // WindowResizer for the same window.
+  WindowResizer* window_resizer() const {
+    return window_resizer_;
+  }
+  void set_window_resizer_(WindowResizer* window_resizer) {
+    window_resizer_ = window_resizer;
+  }
+
   // aura::WindowObserver overrides:
   virtual void OnWindowPropertyChanged(aura::Window* window,
                                        const void* key,
@@ -208,6 +247,7 @@
 
   // The owner of this window settings.
   aura::Window* window_;
+  scoped_ptr<WindowStateDelegate> delegate_;
 
   bool tracked_by_workspace_;
   bool window_position_managed_;
@@ -217,8 +257,11 @@
   bool ignored_by_shelf_;
   bool can_consume_system_keys_;
   bool top_row_keys_are_function_keys_;
+  WindowResizer* window_resizer_;
 
   bool always_restores_to_restore_bounds_;
+  bool hide_shelf_when_fullscreen_;
+  bool animate_to_fullscreen_;
 
   // A property to remember the window position which was set before the
   // auto window position manager changed the window bounds, so that it can get
diff --git a/ash/wm/window_state_delegate.cc b/ash/wm/window_state_delegate.cc
new file mode 100644
index 0000000..0004073
--- /dev/null
+++ b/ash/wm/window_state_delegate.cc
@@ -0,0 +1,21 @@
+// Copyright 2013 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 "ash/wm/window_state_delegate.h"
+
+namespace ash {
+namespace wm {
+
+WindowStateDelegate::WindowStateDelegate() {
+}
+
+WindowStateDelegate::~WindowStateDelegate() {
+}
+
+bool WindowStateDelegate::ToggleFullscreen(WindowState* window_state) {
+  return false;
+}
+
+}  // namespace wm
+}  // namespace ash
diff --git a/ash/wm/window_state_delegate.h b/ash/wm/window_state_delegate.h
new file mode 100644
index 0000000..7b9a8ba
--- /dev/null
+++ b/ash/wm/window_state_delegate.h
@@ -0,0 +1,32 @@
+// Copyright 2013 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 ASH_WM_WINDOW_STATE_DELEGATE_H_
+#define ASH_WM_WINDOW_STATE_DELEGATE_H_
+
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+
+namespace ash {
+namespace wm {
+class WindowState;
+
+class ASH_EXPORT WindowStateDelegate {
+ public:
+  WindowStateDelegate();
+  virtual ~WindowStateDelegate();
+
+  // Invoked when the user uses Shift+F4/F4 to toggle the window
+  // fullscreen state.  The caller (ash::wm::WindowState) falls backs
+  // to the default implementation if this returns false.
+  virtual bool ToggleFullscreen(WindowState* window_state);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WindowStateDelegate);
+};
+
+}  // namespace wm
+}  // namespace ash
+
+#endif  // ASH_WM_WINDOW_STATE_DELEGATE_H_
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 66a6243..46a776a 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -62,10 +62,6 @@
   window->SetBoundsInScreen(center, display);
 }
 
-void SetAnimateToFullscreen(aura::Window* window, bool animate) {
-  window->SetProperty(ash::internal::kAnimateToFullscreenKey, animate);
-}
-
 void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& visible_area,
                                                  gfx::Rect* bounds) {
   AdjustBoundsToEnsureWindowVisibility(
@@ -100,7 +96,7 @@
   views::View* target = static_cast<views::View*>(event.target());
   if (!target)
     return false;
-  aura::RootWindow* target_root =
+  aura::Window* target_root =
       target->GetWidget()->GetNativeView()->GetRootWindow();
   if (!target_root || target_root == window->GetRootWindow())
     return false;
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index fd71a0b..fb12959 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -47,9 +47,6 @@
 // Moves the window to the center of the display.
 ASH_EXPORT void CenterWindow(aura::Window* window);
 
-// Change the availability of animation to the fullscreen of the |window|.
-ASH_EXPORT void SetAnimateToFullscreen(aura::Window* window, bool animate);
-
 // Move the given bounds inside the given |visible_area| in parent coordinates,
 // including a safety margin given by |kMinimumOnScreenArea|.
 // This also ensures that the top of the bounds is visible.
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index 9a3d43c..a4756aa 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -42,7 +42,7 @@
     aura::Window* window = new aura::Window(delegate);
     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window->Init(ui::LAYER_TEXTURED);
-    SetDefaultParentByPrimaryRootWindow(window);
+    ParentWindowInPrimaryRootWindow(window);
     window->SetBounds(bounds);
     window->Show();
     return window;
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index cd2865e..0eb934d 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -104,7 +104,7 @@
   if (bounds_in_screen == bounds_in_screen_)
     return;
   bounds_in_screen_ = bounds_in_screen;
-  aura::RootWindow* target_root = wm::GetRootWindowMatching(bounds_in_screen);
+  aura::Window* target_root = wm::GetRootWindowMatching(bounds_in_screen);
   // Show the phantom at the current bounds of the window. We'll animate to the
   // target bounds. If phantom exists, update the start bounds.
   if (!phantom_widget_)
@@ -122,7 +122,7 @@
   // Create a secondary widget in a second screen if start_bounds_ lie at least
   // partially in that other screen. This allows animations to start or restart
   // in one root window and progress into another root.
-  aura::RootWindow* start_root = wm::GetRootWindowMatching(start_bounds_);
+  aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_);
   if (start_root == target_root) {
     Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
     for (size_t i = 0; i < root_windows.size(); ++i) {
@@ -172,7 +172,7 @@
 }
 
 views::Widget* PhantomWindowController::CreatePhantomWidget(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     const gfx::Rect& bounds_in_screen) {
   views::Widget* phantom_widget = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
diff --git a/ash/wm/workspace/phantom_window_controller.h b/ash/wm/workspace/phantom_window_controller.h
index 4a92792..77d4a28 100644
--- a/ash/wm/workspace/phantom_window_controller.h
+++ b/ash/wm/workspace/phantom_window_controller.h
@@ -13,7 +13,6 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -65,7 +64,7 @@
 
   // Creates, shows and returns a phantom widget at |bounds|
   // with kShellWindowId_ShelfContainer in |root_window| as a parent.
-  views::Widget* CreatePhantomWidget(aura::RootWindow* root_window,
+  views::Widget* CreatePhantomWidget(aura::Window* root_window,
                                      const gfx::Rect& bounds_in_screen);
 
   // Window the phantom is placed beneath.
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc
index 843d136..d0dcdb6 100644
--- a/ash/wm/workspace/workspace_event_handler_unittest.cc
+++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -37,7 +37,7 @@
     aura::Window* window = new aura::Window(delegate);
     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window->Init(ui::LAYER_TEXTURED);
-    SetDefaultParentByPrimaryRootWindow(window);
+    ParentWindowInPrimaryRootWindow(window);
     window->SetBounds(bounds);
     window->Show();
     return window;
@@ -256,7 +256,7 @@
 
   wm::WindowState* window_state = wm::GetWindowState(window.get());
   EXPECT_FALSE(window_state->IsMaximized());
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   aura::test::EventGenerator generator(root, window.get());
   generator.DoubleClickLeftButton();
   EXPECT_NE("1,2 30x40", window->bounds().ToString());
@@ -272,11 +272,12 @@
   ui::MouseEvent press(ui::ET_MOUSE_PRESSED, generator.current_location(),
                        generator.current_location(),
                        ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK);
-  root->AsRootWindowHostDelegate()->OnHostMouseEvent(&press);
+  aura::WindowEventDispatcher* dispatcher = root->GetDispatcher();
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&press);
   ui::MouseEvent release(ui::ET_MOUSE_RELEASED, generator.current_location(),
                          generator.current_location(),
                          ui::EF_IS_DOUBLE_CLICK);
-  root->AsRootWindowHostDelegate()->OnHostMouseEvent(&release);
+  dispatcher->AsRootWindowHostDelegate()->OnHostMouseEvent(&release);
 
   EXPECT_FALSE(window_state->IsMaximized());
   EXPECT_EQ("1,2 30x40", window->bounds().ToString());
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index cbc886b..513ea19 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -55,7 +55,7 @@
         Shell::GetInstance()->display_controller();
     const gfx::Display& display =
         display_controller->GetDisplayMatching(restore_bounds);
-    aura::RootWindow* new_root =
+    aura::Window* new_root =
         display_controller->GetRootWindowForDisplayId(display.id());
     if (new_root != window_state->window()->GetRootWindow()) {
       aura::Window* new_container =
@@ -186,6 +186,14 @@
     restore = window_state->GetRestoreBoundsInScreen();
     window_state->SaveCurrentBoundsForRestore();
   }
+  // Notify observers that fullscreen state may be changing.
+  if (old_state != new_state &&
+      (new_state == ui::SHOW_STATE_FULLSCREEN ||
+       old_state == ui::SHOW_STATE_FULLSCREEN)) {
+    ash::Shell::GetInstance()->NotifyFullscreenStateChange(
+        new_state == ui::SHOW_STATE_FULLSCREEN,
+        window_state->window()->GetRootWindow());
+  }
 
   UpdateBoundsFromShowState(window_state, old_state);
   ShowStateChanged(window_state, old_state);
@@ -341,7 +349,7 @@
       MoveToDisplayForRestore(window_state);
       gfx::Rect new_bounds = ScreenAsh::GetDisplayBoundsInParent(
           window->parent()->parent());
-      if (window->GetProperty(kAnimateToFullscreenKey) &&
+      if (window_state->animate_to_fullscreen() &&
           last_show_state != ui::SHOW_STATE_MINIMIZED) {
         CrossFadeToBounds(window, new_bounds);
       } else {
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 6194f1c..f735e0c 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -287,7 +287,7 @@
   // NOTE: for this test to exercise the failure the observer needs to be added
   // before the parent set. This mimics what BrowserFrameAsh does.
   window->AddObserver(&window_observer);
-  SetDefaultParentByPrimaryRootWindow(window.get());
+  ParentWindowInPrimaryRootWindow(window.get());
   window->Show();
 
   wm::WindowState* window_state = wm::GetWindowState(window.get());
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 7c9394b..731fcb3 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -47,9 +47,12 @@
     aura::client::WindowMoveSource source) {
   DCHECK(window);
   wm::WindowState* window_state = wm::GetWindowState(window);
-  // No need to return a resizer when the window cannot get resized.
-  if (!window_state->CanResize() && window_component != HTCAPTION)
+  // No need to return a resizer when the window cannot get resized or when a
+  // resizer already exists for this window.
+  if ((!window_state->CanResize() && window_component != HTCAPTION) ||
+      window_state->window_resizer()) {
     return scoped_ptr<WindowResizer>();
+  }
 
   // TODO(varkha): The chaining of window resizers causes some of the logic
   // to be repeated and the logic flow difficult to control. With some windows
@@ -102,6 +105,7 @@
     window_resizer = internal::DockedWindowResizer::Create(
         window_resizer, window, point_in_parent, window_component, source);
   }
+  window_state->set_window_resizer_(window_resizer);
   return make_scoped_ptr<WindowResizer>(window_resizer);
 }
 
@@ -390,7 +394,7 @@
   gfx::Point location_in_screen = location_in_parent;
   wm::ConvertPointToScreen(window()->parent(), &location_in_screen);
 
-  aura::RootWindow* root = NULL;
+  aura::Window* root = NULL;
   gfx::Display display =
       ScreenAsh::FindDisplayContainingPoint(location_in_screen);
   // Track the last screen that the pointer was on to keep the snap phantom
@@ -822,25 +826,26 @@
   const int right_edge = work_area.right();
   const int top_edge = work_area.y();
   const int bottom_edge = work_area.bottom();
+  bool updated = false;
   if (ShouldStickToEdge(bounds->x() - left_edge, sticky_size)) {
     bounds->set_x(left_edge);
-    return true;
+    updated = true;
   } else if (ShouldStickToEdge(right_edge - bounds->right(), sticky_size)) {
     bounds->set_x(right_edge - bounds->width());
-    return true;
+    updated = true;
   }
   if (ShouldStickToEdge(bounds->y() - top_edge, sticky_size)) {
     bounds->set_y(top_edge);
-    return true;
+    updated = true;
   } else if (ShouldStickToEdge(bottom_edge - bounds->bottom(), sticky_size) &&
              bounds->height() < (bottom_edge - top_edge)) {
     // Only snap to the bottom if the window is smaller than the work area.
     // Doing otherwise can lead to window snapping in weird ways as it bounces
     // between snapping to top then bottom.
     bounds->set_y(bottom_edge - bounds->height());
-    return true;
+    updated = true;
   }
-  return false;
+  return updated;
 }
 
 void WorkspaceWindowResizer::StickToWorkAreaOnResize(
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index 9d6969b..1e75349 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -107,7 +107,7 @@
     AshTestBase::SetUp();
     UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
 
-    aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+    aura::Window* root = Shell::GetPrimaryRootWindow();
     gfx::Rect root_bounds(root->bounds());
 #if defined(OS_WIN)
     // RootWindow and Display can't resize on Windows Ash.
@@ -119,25 +119,25 @@
     window_.reset(new aura::Window(&delegate_));
     window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window_.get());
+    ParentWindowInPrimaryRootWindow(window_.get());
     window_->set_id(1);
 
     window2_.reset(new aura::Window(&delegate2_));
     window2_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window2_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window2_.get());
+    ParentWindowInPrimaryRootWindow(window2_.get());
     window2_->set_id(2);
 
     window3_.reset(new aura::Window(&delegate3_));
     window3_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window3_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window3_.get());
+    ParentWindowInPrimaryRootWindow(window3_.get());
     window3_->set_id(3);
 
     window4_.reset(new aura::Window(&delegate4_));
     window4_->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window4_->Init(ui::LAYER_NOT_DRAWN);
-    SetDefaultParentByPrimaryRootWindow(window4_.get());
+    ParentWindowInPrimaryRootWindow(window4_.get());
     window4_->set_id(4);
   }
 
@@ -462,7 +462,7 @@
 // windows.
 TEST_F(WorkspaceWindowResizerTest, MAYBE_AttachedResize_BOTTOM_3) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   window_->SetBounds(gfx::Rect( 300, 100, 300, 200));
@@ -946,6 +946,22 @@
   EXPECT_EQ("96,20 320x160", window_->bounds().ToString());
   resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 7), 0);
   EXPECT_EQ("96,0 320x160", window_->bounds().ToString());
+
+  // And bottom/left should snap too.
+  resizer->Drag(
+      CalculateDragPoint(*resizer, 7 - 96, 600 - 160 - 112 - 3 - 7), 0);
+  EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
+  resizer->Drag(
+      CalculateDragPoint(*resizer, -15 - 96, 600 - 160 - 112 - 3 + 15), 0);
+  EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
+  // should move past snap points.
+  resizer->Drag(
+      CalculateDragPoint(*resizer, -32 - 96, 600 - 160 - 112 - 2 + 32), 0);
+  EXPECT_EQ("-32,470 320x160", window_->bounds().ToString());
+  resizer->Drag(
+      CalculateDragPoint(*resizer, -33 - 96, 600 - 160 - 112 - 2 + 33), 0);
+  EXPECT_EQ("-33,471 320x160", window_->bounds().ToString());
+
   // No need to test dragging < 0 as we force that to 0.
 }
 
@@ -1478,7 +1494,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, DontRewardRightmostWindowForOverflows) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Four 100x100 windows flush against eachother, starting at 100,100.
@@ -1509,7 +1525,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, DontExceedMaxWidth) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Four 100x100 windows flush against eachother, starting at 100,100.
@@ -1538,7 +1554,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, DontExceedMaxHeight) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Four 100x100 windows flush against eachother, starting at 100,100.
@@ -1574,7 +1590,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, MAYBE_DontExceedMinHeight) {
   UpdateDisplay("600x500");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Four 100x100 windows flush against eachother, starting at 100,100.
@@ -1603,7 +1619,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, DontExpandRightmostPastMaxWidth) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Three 100x100 windows flush against eachother, starting at 100,100.
@@ -1629,7 +1645,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, MoveAttachedWhenGrownToMaxSize) {
   UpdateDisplay("600x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Three 100x100 windows flush against eachother, starting at 100,100.
@@ -1663,7 +1679,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, MAYBE_MainWindowHonoursMaxWidth) {
   UpdateDisplay("400x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Three 100x100 windows flush against eachother, starting at 100,100.
@@ -1690,7 +1706,7 @@
 
 TEST_F(WorkspaceWindowResizerTest, MainWindowHonoursMinWidth) {
   UpdateDisplay("400x800");
-  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  aura::Window* root = Shell::GetPrimaryRootWindow();
   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
 
   // Three 100x100 windows flush against eachother, starting at 100,100.
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index ecb8248..14ecd84 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -95,7 +95,7 @@
     window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     window->Init(ui::LAYER_TEXTURED);
-    SetDefaultParentByPrimaryRootWindow(window);
+    ParentWindowInPrimaryRootWindow(window);
     return window;
   }
 
@@ -241,7 +241,7 @@
 TEST_F(WorkspaceControllerTest, SnapToGrid) {
   scoped_ptr<Window> w1(CreateTestWindowUnparented());
   w1->SetBounds(gfx::Rect(1, 6, 25, 30));
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   // We are not aligning this anymore this way. When the window gets shown
   // the window is expected to be handled differently, but this cannot be
   // tested with this test. So the result of this test should be that the
@@ -661,7 +661,7 @@
   // window active.
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
 
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   delegate.set_window(w1.get());
   w1->Show();
 }
@@ -679,7 +679,7 @@
   scoped_ptr<Window> w1(CreateTestWindowUnparented());
   Shell::GetInstance()->GetPrimaryRootWindow()->AddTransientChild(w1.get());
   w1->SetBounds(gfx::Rect(10, 11, 250, 251));
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   w1->Show();
   wm::ActivateWindow(w1.get());
 
@@ -703,7 +703,7 @@
   scoped_ptr<Window> w2(CreateTestWindowUnparented());
   w2->SetBounds(gfx::Rect(1, 6, 25, 30));
   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
-  SetDefaultParentByPrimaryRootWindow(w2.get());
+  ParentWindowInPrimaryRootWindow(w2.get());
   w2->Show();
   wm::GetWindowState(w2.get())->SetTrackedByWorkspace(false);
   wm::ActivateWindow(w2.get());
@@ -1163,7 +1163,7 @@
           gfx::Rect(5, 6, 7, 8),
           NULL));
   browser->SetName("browser");
-  SetDefaultParentByPrimaryRootWindow(browser.get());
+  ParentWindowInPrimaryRootWindow(browser.get());
   browser->Show();
   wm::ActivateWindow(browser.get());
 
@@ -1179,7 +1179,7 @@
           gfx::Rect(5, 6, 7, 8),
           NULL);
   browser->AddTransientChild(status_bubble);
-  SetDefaultParentByPrimaryRootWindow(status_bubble);
+  ParentWindowInPrimaryRootWindow(status_bubble);
   status_bubble->SetName("status_bubble");
 
   scoped_ptr<Window> app(
@@ -1189,7 +1189,7 @@
           gfx::Rect(5, 6, 7, 8),
           NULL));
   app->SetName("app");
-  SetDefaultParentByPrimaryRootWindow(app.get());
+  ParentWindowInPrimaryRootWindow(app.get());
 
   aura::Window* parent = browser->parent();
 
@@ -1282,7 +1282,7 @@
                                                aura::client::WINDOW_TYPE_NORMAL,
                                                gfx::Rect(5, 6, 7, 8),
                                                NULL));
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
   w1->Show();
   wm::ActivateWindow(w1.get());
@@ -1331,7 +1331,7 @@
                                                aura::client::WINDOW_TYPE_NORMAL,
                                                gfx::Rect(5, 6, 7, 8),
                                                NULL));
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindowInPrimaryRootWindow(w1.get());
   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
   w1->Show();
   wm::ActivateWindow(w1.get());
@@ -1373,7 +1373,7 @@
   scoped_ptr<Window> modal_window(CreateTestWindowUnparented());
   modal_window->SetBounds(gfx::Rect(10, 11, 21, 22));
   modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
-  SetDefaultParentByPrimaryRootWindow(modal_window.get());
+  ParentWindowInPrimaryRootWindow(modal_window.get());
   modal_window->Show();
   wm::ActivateWindow(modal_window.get());
 
diff --git a/base/allocator/allocator_extension_thunks.target.darwin-arm.mk b/base/allocator/allocator_extension_thunks.target.darwin-arm.mk
index ef1aacc..dcc7ab0 100644
--- a/base/allocator/allocator_extension_thunks.target.darwin-arm.mk
+++ b/base/allocator/allocator_extension_thunks.target.darwin-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/allocator_extension_thunks.target.darwin-mips.mk b/base/allocator/allocator_extension_thunks.target.darwin-mips.mk
index e182074..f524890 100644
--- a/base/allocator/allocator_extension_thunks.target.darwin-mips.mk
+++ b/base/allocator/allocator_extension_thunks.target.darwin-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/allocator_extension_thunks.target.darwin-x86.mk b/base/allocator/allocator_extension_thunks.target.darwin-x86.mk
index 003ac40..ca27e20 100644
--- a/base/allocator/allocator_extension_thunks.target.darwin-x86.mk
+++ b/base/allocator/allocator_extension_thunks.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/allocator_extension_thunks.target.linux-arm.mk b/base/allocator/allocator_extension_thunks.target.linux-arm.mk
index ef1aacc..dcc7ab0 100644
--- a/base/allocator/allocator_extension_thunks.target.linux-arm.mk
+++ b/base/allocator/allocator_extension_thunks.target.linux-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/allocator_extension_thunks.target.linux-mips.mk b/base/allocator/allocator_extension_thunks.target.linux-mips.mk
index e182074..f524890 100644
--- a/base/allocator/allocator_extension_thunks.target.linux-mips.mk
+++ b/base/allocator/allocator_extension_thunks.target.linux-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/allocator_extension_thunks.target.linux-x86.mk b/base/allocator/allocator_extension_thunks.target.linux-x86.mk
index 003ac40..ca27e20 100644
--- a/base/allocator/allocator_extension_thunks.target.linux-x86.mk
+++ b/base/allocator/allocator_extension_thunks.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/allocator/win_allocator.cc b/base/allocator/win_allocator.cc
index 899b867..ee451f5 100644
--- a/base/allocator/win_allocator.cc
+++ b/base/allocator/win_allocator.cc
@@ -56,7 +56,12 @@
   DCHECK_LT(size, allocation_size);
   DCHECK_LT(alignment, allocation_size);
 
+  // Since we're directly calling the allocator function, before OOM handling,
+  // we need to NULL check to ensure the allocation succeeded.
   void* ptr = win_heap_malloc(allocation_size);
+  if (!ptr)
+    return ptr;
+
   char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*);
   aligned_ptr +=
       alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1);
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index a880ede..af50de6 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -17,6 +17,42 @@
  */
 public class ThreadUtils {
 
+    private static final Object sLock = new Object();
+
+    private static boolean sWillOverride = false;
+
+    private static Handler sUiThreadHandler = null;
+
+    public static void setWillOverrideUiThread() {
+        synchronized (sLock) {
+            sWillOverride = true;
+        }
+    }
+
+    public static void setUiThread(Looper looper) {
+        synchronized (sLock) {
+            if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
+                throw new RuntimeException("UI thread looper is already set to " +
+                        sUiThreadHandler.getLooper() + " (Main thread looper is " +
+                        Looper.getMainLooper() + "), cannot set to new looper " + looper);
+            } else {
+                sUiThreadHandler = new Handler(looper);
+            }
+        }
+    }
+
+    private static Handler getUiThreadHandler() {
+        synchronized (sLock) {
+            if (sUiThreadHandler == null) {
+                if (sWillOverride) {
+                    throw new RuntimeException("Did not yet override the UI thread");
+                }
+                sUiThreadHandler = new Handler(Looper.getMainLooper());
+            }
+            return sUiThreadHandler;
+        }
+    }
+
     /**
      * Run the supplied Runnable on the main thread. The method will block until the Runnable
      * completes.
@@ -107,7 +143,7 @@
         if (runningOnUiThread()) {
             r.run();
         } else {
-            LazyHolder.sUiThreadHandler.post(r);
+            getUiThreadHandler().post(r);
         }
     }
 
@@ -119,7 +155,7 @@
      * @return The queried task (to aid inline construction)
      */
     public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
-        LazyHolder.sUiThreadHandler.post(task);
+        getUiThreadHandler().post(task);
         return task;
     }
 
@@ -130,7 +166,7 @@
      * @param task The Runnable to run
      */
     public static void postOnUiThread(Runnable r) {
-        LazyHolder.sUiThreadHandler.post(r);
+        getUiThreadHandler().post(r);
     }
 
     /**
@@ -141,7 +177,7 @@
      * @param delayMillis The delay in milliseconds until the Runnable will be run
      */
     public static void postOnUiThreadDelayed(Runnable r, long delayMillis) {
-        LazyHolder.sUiThreadHandler.postDelayed(r, delayMillis);
+        getUiThreadHandler().postDelayed(r, delayMillis);
     }
 
     /**
@@ -155,7 +191,11 @@
      * @return true iff the current thread is the main (UI) thread.
      */
     public static boolean runningOnUiThread() {
-      return Looper.getMainLooper() == Looper.myLooper();
+        return getUiThreadHandler().getLooper() == Looper.myLooper();
+    }
+
+    public static Looper getUiThreadLooper() {
+        return getUiThreadHandler().getLooper();
     }
 
     /**
@@ -165,8 +205,4 @@
     public static void setThreadPriorityAudio(int tid) {
       Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
     }
-
-    private static class LazyHolder {
-        private static Handler sUiThreadHandler = new Handler(Looper.getMainLooper());
-    }
 }
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index d2a7d06..782e76a 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -76,6 +76,7 @@
     self.name = kwargs['name']
     self.params = kwargs['params']
     self.method_id_var_name = kwargs.get('method_id_var_name', None)
+    self.signature = kwargs.get('signature')
     self.is_constructor = kwargs.get('is_constructor', False)
     self.env_call = GetEnvCall(self.is_constructor, self.static,
                                self.return_type)
@@ -141,6 +142,11 @@
                                      inner]
 
   @staticmethod
+  def ParseJavaPSignature(signature_line):
+    prefix = 'Signature: '
+    return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):]
+
+  @staticmethod
   def JavaToJni(param):
     """Converts a java param into a JNI signature type."""
     pod_param_map = {
@@ -466,7 +472,7 @@
     re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
                            '\((?P<params>.*?)\)')
     self.called_by_natives = []
-    for content in contents[2:]:
+    for lineno, content in enumerate(contents[2:], 2):
       match = re.match(re_method, content)
       if not match:
         continue
@@ -477,11 +483,12 @@
           java_class_name='',
           return_type=match.group('return_type').replace('.', '/'),
           name=match.group('name'),
-          params=JniParams.Parse(match.group('params').replace('.', '/')))]
-    re_constructor = re.compile('.*? public ' +
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
+    re_constructor = re.compile('(.*?)public ' +
                                 self.fully_qualified_class.replace('/', '.') +
                                 '\((?P<params>.*?)\)')
-    for content in contents[2:]:
+    for lineno, content in enumerate(contents[2:], 2):
       match = re.match(re_constructor, content)
       if not match:
         continue
@@ -493,6 +500,7 @@
           return_type=self.fully_qualified_class,
           name='Constructor',
           params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
           is_constructor=True)]
     self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
     self.inl_header_file_generator = InlHeaderFileGenerator(
@@ -505,7 +513,7 @@
   @staticmethod
   def CreateFromClass(class_file, options):
     class_name = os.path.splitext(os.path.basename(class_file))[0]
-    p = subprocess.Popen(args=['javap', class_name],
+    p = subprocess.Popen(args=['javap', '-s', class_name],
                          cwd=os.path.dirname(class_file),
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
@@ -931,14 +939,18 @@
     if called_by_native.is_constructor:
       jni_name = '<init>'
       jni_return_type = 'void'
+    if called_by_native.signature:
+      signature = called_by_native.signature
+    else:
+      signature = JniParams.Signature(called_by_native.params,
+                                      jni_return_type,
+                                      True)
     values = {
         'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
         'JNI_NAME': jni_name,
         'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
         'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
-        'JNI_SIGNATURE': JniParams.Signature(called_by_native.params,
-                                             jni_return_type,
-                                             True)
+        'JNI_SIGNATURE': signature,
     }
     return template.substitute(values)
 
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index eaa3f73..bf78d9c 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -1583,6 +1583,7 @@
 public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E>
       implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
     public void dummy();
+  Signature: ()V
 }
 """
     jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
@@ -1632,10 +1633,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_HashSet_clazz,
       "dummy",
-
-"("
-")"
-"V",
+"()V",
       &g_HashSet_dummy);
 
   env->CallVoidMethod(obj,
@@ -1658,20 +1656,55 @@
 """
     self.assertTextEquals(golden_content, jni_from_javap.GetContent())
 
+  def testSnippnetJavap6_7(self):
+    content_javap6 = """
+public class java.util.HashSet {
+public boolean add(java.lang.Object);
+ Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap7 = """
+public class java.util.HashSet {
+public boolean add(E);
+  Signature: (Ljava/lang/Object;)Z
+}
+"""
+    jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'),
+                                                 TestOptions())
+    jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'),
+                                                 TestOptions())
+    self.assertTrue(jni_from_javap6.GetContent())
+    self.assertTrue(jni_from_javap7.GetContent())
+    # Ensure the javap7 is correctly parsed and uses the Signature field rather
+    # than the "E" parameter.
+    self.assertTextEquals(jni_from_javap6.GetContent(),
+                          jni_from_javap7.GetContent())
+
   def testFromJavaP(self):
     contents = """
-public abstract class java.io.InputStream extends java.lang.Object
-      implements java.io.Closeable{
-    public java.io.InputStream();
-    public int available()       throws java.io.IOException;
-    public void close()       throws java.io.IOException;
-    public void mark(int);
-    public boolean markSupported();
-    public abstract int read()       throws java.io.IOException;
-    public int read(byte[])       throws java.io.IOException;
-    public int read(byte[], int, int)       throws java.io.IOException;
-    public synchronized void reset()       throws java.io.IOException;
-    public long skip(long)       throws java.io.IOException;
+public abstract class java.io.InputStream extends
+  java.lang.Object implements java.io.Closeable{
+public java.io.InputStream();
+  Signature: ()V
+public int available()   throws java.io.IOException;
+  Signature: ()I
+public void close()   throws java.io.IOException;
+  Signature: ()V
+public void mark(int);
+  Signature: (I)V
+public boolean markSupported();
+  Signature: ()Z
+public abstract int read()   throws java.io.IOException;
+  Signature: ()I
+public int read(byte[])   throws java.io.IOException;
+  Signature: ([B)I
+public int read(byte[], int, int)   throws java.io.IOException;
+  Signature: ([BII)I
+public synchronized void reset()   throws java.io.IOException;
+  Signature: ()V
+public long skip(long)   throws java.io.IOException;
+  Signature: (J)J
 }
 """
     jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
@@ -1721,10 +1754,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "available",
-
-"("
-")"
-"I",
+"()I",
       &g_InputStream_available);
 
   jint ret =
@@ -1745,10 +1775,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "close",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_close);
 
   env->CallVoidMethod(obj,
@@ -1768,11 +1795,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "mark",
-
-"("
-"I"
-")"
-"V",
+"(I)V",
       &g_InputStream_mark);
 
   env->CallVoidMethod(obj,
@@ -1792,10 +1815,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "markSupported",
-
-"("
-")"
-"Z",
+"()Z",
       &g_InputStream_markSupported);
 
   jboolean ret =
@@ -1816,10 +1836,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-")"
-"I",
+"()I",
       &g_InputStream_readI);
 
   jint ret =
@@ -1840,11 +1857,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-"[B"
-")"
-"I",
+"([B)I",
       &g_InputStream_readI_AB);
 
   jint ret =
@@ -1870,13 +1883,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-"[B"
-"I"
-"I"
-")"
-"I",
+"([BII)I",
       &g_InputStream_readI_AB_I_I);
 
   jint ret =
@@ -1897,10 +1904,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "reset",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_reset);
 
   env->CallVoidMethod(obj,
@@ -1920,11 +1924,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "skip",
-
-"("
-"J"
-")"
-"J",
+"(J)J",
       &g_InputStream_skip);
 
   jlong ret =
@@ -1945,10 +1945,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "<init>",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_Constructor);
 
   jobject ret =
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc
index 42a2db1..2a7db19 100644
--- a/base/android/sys_utils.cc
+++ b/base/android/sys_utils.cc
@@ -4,6 +4,7 @@
 
 #include "base/android/sys_utils.h"
 
+#include "base/android/build_info.h"
 #include "base/sys_info.h"
 #include "jni/SysUtils_jni.h"
 
@@ -16,6 +17,9 @@
 const int64 kLowEndMemoryThreshold =
     1024 * 1024 * ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
 
+// Only support low end device changes on builds greater than JB MR2.
+const int kLowEndSdkIntThreshold = 18;
+
 // Defined and called by JNI
 static jboolean IsLowEndDevice(JNIEnv* env, jclass clazz) {
   return base::android::SysUtils::IsLowEndDevice();
@@ -29,7 +33,8 @@
 }
 
 bool SysUtils::IsLowEndDevice() {
-  return SysInfo::AmountOfPhysicalMemory() <= kLowEndMemoryThreshold;
+  return SysInfo::AmountOfPhysicalMemory() <= kLowEndMemoryThreshold &&
+      BuildInfo::GetInstance()->sdk_int() > kLowEndSdkIntThreshold;
 }
 
 SysUtils::SysUtils() { }
diff --git a/base/base.gyp b/base/base.gyp
index fb37803..6ff64e3 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -392,6 +392,8 @@
         'prefs/pref_value_map.h',
         'prefs/pref_value_store.cc',
         'prefs/pref_value_store.h',
+        'prefs/scoped_user_pref_update.cc',
+        'prefs/scoped_user_pref_update.h',
         'prefs/value_map_pref_store.cc',
         'prefs/value_map_pref_store.h',
       ],
@@ -530,6 +532,7 @@
         'md5_unittest.cc',
         'memory/aligned_memory_unittest.cc',
         'memory/discardable_memory_unittest.cc',
+        'memory/discardable_memory_provider_unittest.cc',
         'memory/linked_ptr_unittest.cc',
         'memory/ref_counted_memory_unittest.cc',
         'memory/ref_counted_unittest.cc',
@@ -551,6 +554,7 @@
         'metrics/bucket_ranges_unittest.cc',
         'metrics/field_trial_unittest.cc',
         'metrics/histogram_base_unittest.cc',
+        'metrics/histogram_delta_serialization_unittest.cc',
         'metrics/histogram_unittest.cc',
         'metrics/sparse_histogram_unittest.cc',
         'metrics/stats_table_unittest.cc',
@@ -573,6 +577,7 @@
         'prefs/pref_service_unittest.cc',
         'prefs/pref_value_map_unittest.cc',
         'prefs/pref_value_store_unittest.cc',
+        'prefs/scoped_user_pref_update_unittest.cc',
         'process/memory_unittest.cc',
         'process/memory_unittest_mac.h',
         'process/memory_unittest_mac.mm',
@@ -829,6 +834,11 @@
             'third_party/nspr/nspr.gyp:nspr',
           ],
         }],
+        ['<(native_discardable_memory)==1', {
+          'sources!': [
+            'memory/discardable_memory_provider_unittest.cc',
+          ],
+        }],
       ],  # conditions
       'target_conditions': [
         ['OS == "ios" and _toolset != "host"', {
diff --git a/base/base.gypi b/base/base.gypi
index 73e6ccc..eeda3e1 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -283,10 +283,12 @@
           'mac/sdk_forward_declarations.h',
           'memory/aligned_memory.cc',
           'memory/aligned_memory.h',
-          'memory/discardable_memory.cc',
           'memory/discardable_memory.h',
           'memory/discardable_memory_android.cc',
+          'memory/discardable_memory_emulated.cc',
           'memory/discardable_memory_mac.cc',
+          'memory/discardable_memory_provider.cc',
+          'memory/discardable_memory_provider.h',
           'memory/linked_ptr.h',
           'memory/manual_constructor.h',
           'memory/memory_pressure_listener.cc',
@@ -339,6 +341,8 @@
           'metrics/histogram.h',
           'metrics/histogram_base.cc',
           'metrics/histogram_base.h',
+          'metrics/histogram_delta_serialization.cc',
+          'metrics/histogram_delta_serialization.h',
           'metrics/histogram_flattener.h',
           'metrics/histogram_samples.cc',
           'metrics/histogram_samples.h',
@@ -845,6 +849,14 @@
               'sources/': [ ['exclude', '^win/'] ],
             },
           ],
+          ['<(native_discardable_memory)==1', {
+              'sources!': [
+                'memory/discardable_memory_emulated.cc',
+                'memory/discardable_memory_provider.cc',
+                'memory/discardable_memory_provider.h',
+              ],
+            },
+          ],
           ['OS != "android" or >(nacl_untrusted_build)==1', {
               'sources/': [ ['exclude', '^android/'] ],
             },
diff --git a/base/base.target.darwin-arm.mk b/base/base.target.darwin-arm.mk
index 556dc1c..fa73476 100644
--- a/base/base.target.darwin-arm.mk
+++ b/base/base.target.darwin-arm.mk
@@ -113,7 +113,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -133,6 +132,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -275,13 +275,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -358,13 +358,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base.target.darwin-mips.mk b/base/base.target.darwin-mips.mk
index 1465e99..20f8b85 100644
--- a/base/base.target.darwin-mips.mk
+++ b/base/base.target.darwin-mips.mk
@@ -113,7 +113,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -133,6 +132,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -274,13 +274,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -356,13 +356,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base.target.darwin-x86.mk b/base/base.target.darwin-x86.mk
index eb687d3..0c0efa8 100644
--- a/base/base.target.darwin-x86.mk
+++ b/base/base.target.darwin-x86.mk
@@ -114,7 +114,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -134,6 +133,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -278,13 +278,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -364,13 +364,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base.target.linux-arm.mk b/base/base.target.linux-arm.mk
index 556dc1c..fa73476 100644
--- a/base/base.target.linux-arm.mk
+++ b/base/base.target.linux-arm.mk
@@ -113,7 +113,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -133,6 +132,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -275,13 +275,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -358,13 +358,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base.target.linux-mips.mk b/base/base.target.linux-mips.mk
index 1465e99..20f8b85 100644
--- a/base/base.target.linux-mips.mk
+++ b/base/base.target.linux-mips.mk
@@ -113,7 +113,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -133,6 +132,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -274,13 +274,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -356,13 +356,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base.target.linux-x86.mk b/base/base.target.linux-x86.mk
index eb687d3..0c0efa8 100644
--- a/base/base.target.linux-x86.mk
+++ b/base/base.target.linux-x86.mk
@@ -114,7 +114,6 @@
 	base/location.cc \
 	base/logging.cc \
 	base/memory/aligned_memory.cc \
-	base/memory/discardable_memory.cc \
 	base/memory/discardable_memory_android.cc \
 	base/memory/memory_pressure_listener.cc \
 	base/memory/ref_counted.cc \
@@ -134,6 +133,7 @@
 	base/metrics/bucket_ranges.cc \
 	base/metrics/histogram.cc \
 	base/metrics/histogram_base.cc \
+	base/metrics/histogram_delta_serialization.cc \
 	base/metrics/histogram_samples.cc \
 	base/metrics/histogram_snapshot_manager.cc \
 	base/metrics/sparse_histogram.cc \
@@ -278,13 +278,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -364,13 +364,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.darwin-arm.mk b/base/base_i18n.target.darwin-arm.mk
index 56b9894..7d69354 100644
--- a/base/base_i18n.target.darwin-arm.mk
+++ b/base/base_i18n.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.darwin-mips.mk b/base/base_i18n.target.darwin-mips.mk
index d995a27..e6ee08d 100644
--- a/base/base_i18n.target.darwin-mips.mk
+++ b/base/base_i18n.target.darwin-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.darwin-x86.mk b/base/base_i18n.target.darwin-x86.mk
index 1af4568..a934aa4 100644
--- a/base/base_i18n.target.darwin-x86.mk
+++ b/base/base_i18n.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.linux-arm.mk b/base/base_i18n.target.linux-arm.mk
index 56b9894..7d69354 100644
--- a/base/base_i18n.target.linux-arm.mk
+++ b/base/base_i18n.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.linux-mips.mk b/base/base_i18n.target.linux-mips.mk
index d995a27..e6ee08d 100644
--- a/base/base_i18n.target.linux-mips.mk
+++ b/base/base_i18n.target.linux-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_i18n.target.linux-x86.mk b/base/base_i18n.target.linux-x86.mk
index 1af4568..a934aa4 100644
--- a/base/base_i18n.target.linux-x86.mk
+++ b/base/base_i18n.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.darwin-arm.mk b/base/base_java_activity_state.target.darwin-arm.mk
index aae8c41..f3f91ff 100644
--- a/base/base_java_activity_state.target.darwin-arm.mk
+++ b/base/base_java_activity_state.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.darwin-mips.mk b/base/base_java_activity_state.target.darwin-mips.mk
index 2e64efe..bd08338 100644
--- a/base/base_java_activity_state.target.darwin-mips.mk
+++ b/base/base_java_activity_state.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.darwin-x86.mk b/base/base_java_activity_state.target.darwin-x86.mk
index e12ccc6..30c24d0 100644
--- a/base/base_java_activity_state.target.darwin-x86.mk
+++ b/base/base_java_activity_state.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.linux-arm.mk b/base/base_java_activity_state.target.linux-arm.mk
index aae8c41..f3f91ff 100644
--- a/base/base_java_activity_state.target.linux-arm.mk
+++ b/base/base_java_activity_state.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.linux-mips.mk b/base/base_java_activity_state.target.linux-mips.mk
index 2e64efe..bd08338 100644
--- a/base/base_java_activity_state.target.linux-mips.mk
+++ b/base/base_java_activity_state.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_activity_state.target.linux-x86.mk b/base/base_java_activity_state.target.linux-x86.mk
index e12ccc6..30c24d0 100644
--- a/base/base_java_activity_state.target.linux-x86.mk
+++ b/base/base_java_activity_state.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.darwin-arm.mk b/base/base_java_memory_pressure_level_list.target.darwin-arm.mk
index a8a2353..ef18ef2 100644
--- a/base/base_java_memory_pressure_level_list.target.darwin-arm.mk
+++ b/base/base_java_memory_pressure_level_list.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.darwin-mips.mk b/base/base_java_memory_pressure_level_list.target.darwin-mips.mk
index 2af2bf4..50d3806 100644
--- a/base/base_java_memory_pressure_level_list.target.darwin-mips.mk
+++ b/base/base_java_memory_pressure_level_list.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.darwin-x86.mk b/base/base_java_memory_pressure_level_list.target.darwin-x86.mk
index 9495741..83f99dd 100644
--- a/base/base_java_memory_pressure_level_list.target.darwin-x86.mk
+++ b/base/base_java_memory_pressure_level_list.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.linux-arm.mk b/base/base_java_memory_pressure_level_list.target.linux-arm.mk
index a8a2353..ef18ef2 100644
--- a/base/base_java_memory_pressure_level_list.target.linux-arm.mk
+++ b/base/base_java_memory_pressure_level_list.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.linux-mips.mk b/base/base_java_memory_pressure_level_list.target.linux-mips.mk
index 2af2bf4..50d3806 100644
--- a/base/base_java_memory_pressure_level_list.target.linux-mips.mk
+++ b/base/base_java_memory_pressure_level_list.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_java_memory_pressure_level_list.target.linux-x86.mk b/base/base_java_memory_pressure_level_list.target.linux-x86.mk
index 9495741..83f99dd 100644
--- a/base/base_java_memory_pressure_level_list.target.linux-x86.mk
+++ b/base/base_java_memory_pressure_level_list.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.darwin-arm.mk b/base/base_jni_headers.target.darwin-arm.mk
index 8b28992..6883c0c 100644
--- a/base/base_jni_headers.target.darwin-arm.mk
+++ b/base/base_jni_headers.target.darwin-arm.mk
@@ -212,13 +212,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -290,13 +290,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.darwin-mips.mk b/base/base_jni_headers.target.darwin-mips.mk
index c6b110f..4e59e61 100644
--- a/base/base_jni_headers.target.darwin-mips.mk
+++ b/base/base_jni_headers.target.darwin-mips.mk
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -288,13 +288,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.darwin-x86.mk b/base/base_jni_headers.target.darwin-x86.mk
index 4bc9f74..b02c8ba 100644
--- a/base/base_jni_headers.target.darwin-x86.mk
+++ b/base/base_jni_headers.target.darwin-x86.mk
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -295,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.linux-arm.mk b/base/base_jni_headers.target.linux-arm.mk
index 8b28992..6883c0c 100644
--- a/base/base_jni_headers.target.linux-arm.mk
+++ b/base/base_jni_headers.target.linux-arm.mk
@@ -212,13 +212,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -290,13 +290,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.linux-mips.mk b/base/base_jni_headers.target.linux-mips.mk
index c6b110f..4e59e61 100644
--- a/base/base_jni_headers.target.linux-mips.mk
+++ b/base/base_jni_headers.target.linux-mips.mk
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -288,13 +288,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_jni_headers.target.linux-x86.mk b/base/base_jni_headers.target.linux-x86.mk
index 4bc9f74..b02c8ba 100644
--- a/base/base_jni_headers.target.linux-x86.mk
+++ b/base/base_jni_headers.target.linux-x86.mk
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -295,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.darwin-arm.mk b/base/base_prefs.target.darwin-arm.mk
index 07e47ca..f6b776b 100644
--- a/base/base_prefs.target.darwin-arm.mk
+++ b/base/base_prefs.target.darwin-arm.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -76,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.darwin-mips.mk b/base/base_prefs.target.darwin-mips.mk
index 725ba1e..a23eebb 100644
--- a/base/base_prefs.target.darwin-mips.mk
+++ b/base/base_prefs.target.darwin-mips.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -75,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.darwin-x86.mk b/base/base_prefs.target.darwin-x86.mk
index e5f5da9..c7ce440 100644
--- a/base/base_prefs.target.darwin-x86.mk
+++ b/base/base_prefs.target.darwin-x86.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -78,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.linux-arm.mk b/base/base_prefs.target.linux-arm.mk
index 07e47ca..f6b776b 100644
--- a/base/base_prefs.target.linux-arm.mk
+++ b/base/base_prefs.target.linux-arm.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -76,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.linux-mips.mk b/base/base_prefs.target.linux-mips.mk
index 725ba1e..a23eebb 100644
--- a/base/base_prefs.target.linux-mips.mk
+++ b/base/base_prefs.target.linux-mips.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -75,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_prefs.target.linux-x86.mk b/base/base_prefs.target.linux-x86.mk
index e5f5da9..c7ce440 100644
--- a/base/base_prefs.target.linux-x86.mk
+++ b/base/base_prefs.target.linux-x86.mk
@@ -36,6 +36,7 @@
 	base/prefs/pref_store.cc \
 	base/prefs/pref_value_map.cc \
 	base/prefs/pref_value_store.cc \
+	base/prefs/scoped_user_pref_update.cc \
 	base/prefs/value_map_pref_store.cc
 
 
@@ -78,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.darwin-arm.mk b/base/base_static.target.darwin-arm.mk
index cc15f67..ad43fb7 100644
--- a/base/base_static.target.darwin-arm.mk
+++ b/base/base_static.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.darwin-mips.mk b/base/base_static.target.darwin-mips.mk
index fc2d0e5..6d43e81 100644
--- a/base/base_static.target.darwin-mips.mk
+++ b/base/base_static.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.darwin-x86.mk b/base/base_static.target.darwin-x86.mk
index b7f12d8..16ecda0 100644
--- a/base/base_static.target.darwin-x86.mk
+++ b/base/base_static.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.linux-arm.mk b/base/base_static.target.linux-arm.mk
index cc15f67..ad43fb7 100644
--- a/base/base_static.target.linux-arm.mk
+++ b/base/base_static.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.linux-mips.mk b/base/base_static.target.linux-mips.mk
index fc2d0e5..6d43e81 100644
--- a/base/base_static.target.linux-mips.mk
+++ b/base/base_static.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_static.target.linux-x86.mk b/base/base_static.target.linux-x86.mk
index b7f12d8..16ecda0 100644
--- a/base/base_static.target.linux-x86.mk
+++ b/base/base_static.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/base_switches.cc b/base/base_switches.cc
index bdd7b62..d6b7d02 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -15,6 +15,11 @@
 // Disables the crash reporting.
 const char kDisableBreakpad[]               = "disable-breakpad";
 
+// Indicates that crash reporting should be enabled. On platforms where helper
+// processes cannot access to files needed to make this decision, this flag is
+// generated internally.
+const char kEnableCrashReporter[]           = "enable-crash-reporter";
+
 // Enable DCHECKs in release mode.
 const char kEnableDCHECK[]                  = "enable-dcheck";
 
@@ -49,12 +54,4 @@
 // Sends a pretty-printed version of tracing info to the console.
 const char kTraceToConsole[]                = "trace-to-console";
 
-#if defined(OS_POSIX)
-// A flag, generated internally for renderer and other helper process command
-// lines on Linux and Mac. It tells the helper process to enable crash dumping
-// and reporting, because helpers cannot access the files needed to make this
-// decision.
-const char kEnableCrashReporter[]           = "enable-crash-reporter";
-#endif
-
 }  // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
index 7686e76..1d8a8a8 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -13,6 +13,7 @@
 
 extern const char kDebugOnStart[];
 extern const char kDisableBreakpad[];
+extern const char kEnableCrashReporter[];
 extern const char kEnableDCHECK[];
 extern const char kFullMemoryCrashReport[];
 extern const char kNoErrorDialogs[];
@@ -22,10 +23,6 @@
 extern const char kWaitForDebugger[];
 extern const char kTraceToConsole[];
 
-#if defined(OS_POSIX)
-extern const char kEnableCrashReporter[];
-#endif
-
 }  // namespace switches
 
 #endif  // BASE_BASE_SWITCHES_H_
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index 0b140dd..dd9e6b8 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -16,8 +16,8 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
         'isolate_dependency_tracked': [
           '../testing/xvfb.py',
@@ -40,8 +40,8 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
       },
     }],
diff --git a/base/containers/mru_cache.h b/base/containers/mru_cache.h
index e59e909..15ea2fc 100644
--- a/base/containers/mru_cache.h
+++ b/base/containers/mru_cache.h
@@ -123,8 +123,6 @@
 
   // Retrieves the payload associated with a given key and returns it via
   // result without affecting the ordering (unlike Get).
-  //
-  // TODO(brettw) We may want a const version of this function in the future.
   iterator Peek(const KeyType& key) {
     typename KeyIndex::const_iterator index_iter = index_.find(key);
     if (index_iter == index_.end())
@@ -132,6 +130,13 @@
     return index_iter->second;
   }
 
+  const_iterator Peek(const KeyType& key) const {
+    typename KeyIndex::const_iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    return index_iter->second;
+  }
+
   // Erases the item referenced by the given iterator. An iterator to the item
   // following it will be returned. The iterator must be valid.
   iterator Erase(iterator pos) {
diff --git a/base/cpu.cc b/base/cpu.cc
index 1761529..78064e2 100644
--- a/base/cpu.cc
+++ b/base/cpu.cc
@@ -145,6 +145,13 @@
     __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
     has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
   }
+#elif defined(ARCH_CPU_ARM_FAMILY)
+  // TODO(piman): Expand this. ARM has a CPUID register, but it's not available
+  // in user mode. /proc/cpuinfo has some information, but it's non standard,
+  // platform-specific, and not accessible from the sandbox.
+  // For some purposes, this first approximation is enough.
+  // crbug.com/313454
+  cpu_brand_.assign("ARM");
 #endif
 }
 
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index 066c592..cab4c48 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -195,9 +195,18 @@
 // +-------+-----------------+-----------------+
 //
 // Thus we do the following:
-// Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT.
+// Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
+//        SIGABRT
 // Mac: Always send SIGTRAP.
 
+#if defined(ARCH_CPU_ARM_FAMILY)
+#define DEBUG_BREAK_ASM() asm("bkpt 0")
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+#define DEBUG_BREAK_ASM() asm("break 2")
+#elif defined(ARCH_CPU_X86_FAMILY)
+#define DEBUG_BREAK_ASM() asm("int3")
+#endif
+
 #if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
 #define DEBUG_BREAK() abort()
 #elif defined(OS_NACL)
@@ -205,7 +214,7 @@
 // should ask for advice from some NaCl experts about the optimum thing here.
 // http://code.google.com/p/nativeclient/issues/detail?id=645
 #define DEBUG_BREAK() abort()
-#elif defined(OS_ANDROID)
+#elif !defined(OS_MACOSX)
 // Though Android has a "helpful" process called debuggerd to catch native
 // signals on the general assumption that they are fatal errors. If no debugger
 // is attached, we call abort since Breakpad needs SIGABRT to create a dump.
@@ -214,13 +223,17 @@
 // difficulty continuing in a debugger once we stop from SIG triggered by native
 // code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
 // "int3" to setup breakpiont and raise SIGTRAP.
+//
+// On other POSIX architectures, except Mac OS X, we use the same logic to
+// ensure that breakpad creates a dump on crashes while it is still possible to
+// use a debugger.
 namespace {
 void DebugBreak() {
   if (!BeingDebugged()) {
     abort();
   } else {
-#if defined(ARCH_CPU_X86_FAMILY)
-    asm("int3");
+#if defined(DEBUG_BREAK_ASM)
+    DEBUG_BREAK_ASM();
 #else
     volatile int go = 0;
     while (!go) {
@@ -231,13 +244,10 @@
 }
 }  // namespace
 #define DEBUG_BREAK() DebugBreak()
-#elif defined(ARCH_CPU_ARM_FAMILY)
-// ARM && !ANDROID
-#define DEBUG_BREAK() asm("bkpt 0")
-#elif defined(ARCH_CPU_MIPS_FAMILY)
-#define DEBUG_BREAK() asm("break 2")
+#elif defined(DEBUG_BREAK_ASM)
+#define DEBUG_BREAK() DEBUG_BREAK_ASM()
 #else
-#define DEBUG_BREAK() asm("int3")
+#error "Don't know how to debug break on this architecture/OS"
 #endif
 
 void BreakDebugger() {
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index 9bf9149..1cd43a3 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -520,12 +520,18 @@
 //   all match. |id| must either be a pointer or an integer value up to 64 bits.
 //   If it's a pointer, the bits will be xored with a hash of the process ID so
 //   that the same pointer on two different processes will not collide.
+//
 // An asynchronous operation can consist of multiple phases. The first phase is
 // defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
-// ASYNC_STEP macros. When the operation completes, call ASYNC_END.
-// An ASYNC trace typically occur on a single thread (if not, they will only be
+// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
+// annotate the block following the call. The ASYNC_STEP_PAST macro will
+// annotate the block prior to the call. Note that any particular event must use
+// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
+// operation completes, call ASYNC_END.
+//
+// An ASYNC trace typically occurs on a single thread (if not, they will only be
 // drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
-// operation must use the same |name| and |id|. Each event can have its own
+// operation must use the same |name| and |id|. Each step can have its own
 // args.
 #define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
@@ -553,27 +559,34 @@
         category_group, name, id, TRACE_EVENT_FLAG_COPY, \
         arg1_name, arg1_val, arg2_name, arg2_val)
 
-// Records a single ASYNC_STEP event for |step| immediately. If the category
-// is not enabled, then this does nothing. The |name| and |id| must match the
-// ASYNC_BEGIN event above. The |step| param identifies this step within the
-// async event. This should be called at the beginning of the next phase of an
-// asynchronous operation.
-#define TRACE_EVENT_ASYNC_STEP0(category_group, name, id, step) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_PAST events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
-#define TRACE_EVENT_ASYNC_STEP1(category_group, name, id, step, \
-                                      arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
         arg1_name, arg1_val)
 
-#define TRACE_EVENT_COPY_ASYNC_STEP0(category_group, name, id, step) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
-#define TRACE_EVENT_COPY_ASYNC_STEP1(category_group, name, id, step, \
-        arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
+// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_INTO events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
         arg1_name, arg1_val)
 
 // Records a single ASYNC_END event for "name" immediately. If the category
@@ -924,7 +937,8 @@
 #define TRACE_EVENT_PHASE_COMPLETE ('X')
 #define TRACE_EVENT_PHASE_INSTANT  ('i')
 #define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
-#define TRACE_EVENT_PHASE_ASYNC_STEP  ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO  ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST  ('p')
 #define TRACE_EVENT_PHASE_ASYNC_END   ('F')
 #define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
 #define TRACE_EVENT_PHASE_FLOW_STEP  ('t')
diff --git a/base/debug/trace_event_android.cc b/base/debug/trace_event_android.cc
index 8bea609..567c48e 100644
--- a/base/debug/trace_event_android.cc
+++ b/base/debug/trace_event_android.cc
@@ -10,6 +10,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
 
 namespace {
 
@@ -57,6 +58,20 @@
   write(g_atrace_fd, out.c_str(), out.size());
 }
 
+void NoOpOutputCallback(base::WaitableEvent* complete_event,
+                        const scoped_refptr<base::RefCountedString>&,
+                        bool has_more_events) {
+  if (!has_more_events)
+    complete_event->Signal();
+}
+
+void EndChromeTracing(base::debug::TraceLog* trace_log,
+                      base::WaitableEvent* complete_event) {
+  trace_log->SetDisabled();
+  // Delete the buffered trace events as they have been sent to atrace.
+  trace_log->Flush(base::Bind(&NoOpOutputCallback, complete_event));
+}
+
 }  // namespace
 
 namespace base {
@@ -91,9 +106,16 @@
 
   close(g_atrace_fd);
   g_atrace_fd = -1;
-  SetDisabled();
-  // Delete the buffered trace events as they have been sent to atrace.
-  Flush(OutputCallback());
+
+  // TraceLog::Flush() requires the current thread to have a message loop, but
+  // this thread called from Java may not have one, so flush in another thread.
+  Thread end_chrome_tracing_thread("end_chrome_tracing");
+  WaitableEvent complete_event(false, false);
+  end_chrome_tracing_thread.Start();
+  end_chrome_tracing_thread.message_loop()->PostTask(
+      FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
+                            Unretained(&complete_event)));
+  complete_event.Wait();
 }
 
 void TraceEvent::SendToATrace() {
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index 651ee56..f76d9de 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -63,8 +63,10 @@
 const size_t kTraceEventBatchChunks = 1000 / kTraceBufferChunkSize;
 // Can store results for 30 seconds with 1 ms sampling interval.
 const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
+// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
+const size_t kEchoToConsoleTraceEventBufferChunks = 256;
 
-const int kThreadFlushTimeoutMs = 1000;
+const int kThreadFlushTimeoutMs = 3000;
 
 #define MAX_CATEGORY_GROUPS 100
 
@@ -106,42 +108,6 @@
       TimeTicks::ThreadNow() : TimeTicks();
 }
 
-class TraceBufferDiscardsEvents : public TraceBuffer {
- public:
-  TraceBufferDiscardsEvents() {}
-
-  virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) OVERRIDE {
-    return scoped_ptr<TraceBufferChunk>();
-  }
-  virtual void ReturnChunk(size_t index,
-                           scoped_ptr<TraceBufferChunk>) OVERRIDE {
-    NOTREACHED();
-  }
-
-  virtual bool IsFull() const OVERRIDE { return false; }
-  virtual size_t Size() const OVERRIDE { return 0; }
-
-  // As this buffer is never full, we can return any positive number.
-  virtual size_t Capacity() const OVERRIDE { return 1; }
-
-  virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) OVERRIDE {
-    return NULL;
-  }
-
-  virtual const TraceBufferChunk* NextChunk() OVERRIDE {
-    NOTREACHED();
-    return NULL;
-  }
-
-  virtual scoped_ptr<TraceBuffer> CloneForIteration() const OVERRIDE {
-    NOTIMPLEMENTED();
-    return scoped_ptr<TraceBuffer>();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TraceBufferDiscardsEvents);
-};
-
 class TraceBufferRingBuffer : public TraceBuffer {
  public:
   TraceBufferRingBuffer(size_t max_chunks)
@@ -242,15 +208,35 @@
   }
 
  private:
-  class ClonedTraceBuffer : public TraceBufferDiscardsEvents {
+  class ClonedTraceBuffer : public TraceBuffer {
    public:
     ClonedTraceBuffer() : current_iteration_index_(0) {}
 
+    // The only implemented method.
     virtual const TraceBufferChunk* NextChunk() OVERRIDE {
       return current_iteration_index_ < chunks_.size() ?
           chunks_[current_iteration_index_++] : NULL;
     }
 
+    virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) OVERRIDE {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBufferChunk>();
+    }
+    virtual void ReturnChunk(size_t index,
+                             scoped_ptr<TraceBufferChunk>) OVERRIDE {
+      NOTIMPLEMENTED();
+    }
+    virtual bool IsFull() const OVERRIDE { return false; }
+    virtual size_t Size() const OVERRIDE { return 0; }
+    virtual size_t Capacity() const OVERRIDE { return 0; }
+    virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) OVERRIDE {
+      return NULL;
+    }
+    virtual scoped_ptr<TraceBuffer> CloneForIteration() const OVERRIDE {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBuffer>();
+    }
+
     size_t current_iteration_index_;
     ScopedVector<TraceBufferChunk> chunks_;
   };
@@ -432,12 +418,31 @@
     }
   }
 
+  void EnsureReleased() {
+    if (locked_) {
+      lock_.Release();
+      locked_ = false;
+    }
+  }
+
  private:
   Lock& lock_;
   bool locked_;
   DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
 };
 
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32 chunk_seq, size_t chunk_index, size_t event_index,
+                TraceEventHandle* handle) {
+  DCHECK(chunk_seq);
+  DCHECK(chunk_index < (1u << 16));
+  DCHECK(event_index < (1u << 16));
+  handle->chunk_seq = chunk_seq;
+  handle->chunk_index = static_cast<uint16>(chunk_index);
+  handle->event_index = static_cast<uint16>(event_index);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 // TraceEvent
@@ -966,10 +971,6 @@
 
   void FlushWhileLocked();
 
-  void CheckGeneration() const {
-    DCHECK(trace_log_->CheckGeneration(generation_));
-  }
-
   void CheckThisIsCurrentBuffer() const {
     DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
   }
@@ -1004,9 +1005,6 @@
   CheckThisIsCurrentBuffer();
   MessageLoop::current()->RemoveDestructionObserver(this);
 
-  if (!trace_log_->CheckGeneration(generation_))
-    return;
-
   // Zero event_count_ happens in either of the following cases:
   // - no event generated for the thread;
   // - the thread has no message loop;
@@ -1049,7 +1047,8 @@
   size_t event_index;
   TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
   if (trace_event && handle)
-    *handle = TraceEventHandle(chunk_->seq(), chunk_index_, event_index);
+    MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
+
   return trace_event;
 }
 
@@ -1060,7 +1059,6 @@
   if (!g_category_group_enabled[g_category_trace_event_overhead])
     return;
 
-  CheckGeneration();
   CheckThisIsCurrentBuffer();
 
   event_count_++;
@@ -1087,9 +1085,16 @@
 }
 
 void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
+  if (!chunk_)
+    return;
+
   trace_log_->lock_.AssertAcquired();
-  DCHECK(chunk_);
-  trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
+  if (trace_log_->CheckGeneration(generation_)) {
+    // Return the chunk to the buffer only if the generation matches,
+    trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
+  }
+  // Otherwise this method may be called from the destructor, or TraceLog will
+  // find the generation mismatch and delete this buffer soon.
 }
 
 TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log)
@@ -1459,7 +1464,7 @@
   else if (options & MONITOR_SAMPLING)
     return new TraceBufferRingBuffer(kMonitorTraceEventBufferChunks);
   else if (options & ECHO_TO_CONSOLE)
-    return new TraceBufferDiscardsEvents();
+    return new TraceBufferRingBuffer(kEchoToConsoleTraceEventBufferChunks);
   return new TraceBufferVector();
 }
 
@@ -1484,8 +1489,8 @@
   size_t event_index;
   TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
   if (trace_event && handle) {
-    *handle = TraceEventHandle(thread_shared_chunk_->seq(),
-                               thread_shared_chunk_index_, event_index);
+    MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
+               event_index, handle);
   }
   return trace_event;
 }
@@ -1628,12 +1633,10 @@
   // This will flush the thread local buffer.
   delete thread_local_event_buffer_.Get();
 
-  {
-    AutoLock lock(lock_);
-    if (!CheckGeneration(generation) || !flush_message_loop_proxy_ ||
-        thread_message_loops_.size())
-      return;
-  }
+  AutoLock lock(lock_);
+  if (!CheckGeneration(generation) || !flush_message_loop_proxy_ ||
+      thread_message_loops_.size())
+    return;
 
   flush_message_loop_proxy_->PostTask(
       FROM_HERE,
@@ -1716,7 +1719,7 @@
     const unsigned long long* arg_values,
     const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
     unsigned char flags) {
-  TraceEventHandle handle;
+  TraceEventHandle handle = { 0, 0, 0 };
   if (!*category_group_enabled)
     return handle;
 
@@ -1749,6 +1752,7 @@
     }
   }
 
+  OptionalAutoLock lock(lock_);
   // Check and update the current thread name only if the event is for the
   // current thread to avoid locks in most cases.
   if (thread_id == static_cast<int>(PlatformThread::CurrentId())) {
@@ -1762,7 +1766,7 @@
         new_name && *new_name) {
       g_current_thread_name.Get().Set(new_name);
 
-      AutoLock lock(lock_);
+      lock.EnsureAcquired();
       hash_map<int, std::string>::iterator existing_name =
           thread_names_.find(thread_id);
       if (existing_name == thread_names_.end()) {
@@ -1784,10 +1788,10 @@
     }
   }
 
+  TraceEvent* trace_event = NULL;
   if (!subtle::NoBarrier_Load(&buffer_is_full_)) {
-    TraceEvent* trace_event;
-    OptionalAutoLock lock(lock_);
     if (thread_local_event_buffer) {
+      lock.EnsureReleased();
       trace_event = thread_local_event_buffer->AddTraceEvent(&notifier,
                                                              &handle);
     } else {
@@ -1804,25 +1808,33 @@
 #if defined(OS_ANDROID)
       trace_event->SendToATrace();
 #endif
-
-      if (trace_options() & ECHO_TO_CONSOLE) {
-        lock.EnsureAcquired();
-        OutputEventToConsoleWhileLocked(trace_event);
-      }
     }
   }
 
+  if (trace_options() & ECHO_TO_CONSOLE) {
+    lock.EnsureAcquired();
+    OutputEventToConsoleWhileLocked(
+        phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+        timestamp, trace_event);
+  }
+
   if (reinterpret_cast<const unsigned char*>(subtle::NoBarrier_Load(
       &watch_category_)) == category_group_enabled) {
-    AutoLock lock(lock_);
+    lock.EnsureAcquired();
     if (watch_event_name_ == name)
       notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
   }
 
+  lock.EnsureReleased();
   EventCallback event_callback = reinterpret_cast<EventCallback>(
       subtle::NoBarrier_Load(&event_callback_));
   if (event_callback) {
-    event_callback(phase, category_group_enabled, name, id,
+    // TODO(wangxianzhu): Should send TRACE_EVENT_PHASE_COMPLETE directly to
+    // clients if it is beneficial and feasible.
+    event_callback(now,
+                   phase == TRACE_EVENT_PHASE_COMPLETE ?
+                       TRACE_EVENT_PHASE_BEGIN : phase,
+                   category_group_enabled, name, id,
                    num_args, arg_names, arg_types, arg_values,
                    flags);
   }
@@ -1835,19 +1847,21 @@
   return handle;
 }
 
-void TraceLog::OutputEventToConsoleWhileLocked(TraceEvent* trace_event) {
+// May be called when a COMPELETE event ends and the unfinished event has been
+// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
+void TraceLog::OutputEventToConsoleWhileLocked(unsigned char phase,
+                                               const TimeTicks& timestamp,
+                                               TraceEvent* trace_event) {
+  // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
+  // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
+  DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
   lock_.AssertAcquired();
 
   TimeDelta duration;
-  unsigned char phase = trace_event->phase();
-  int thread_id = trace_event->thread_id();
+  int thread_id = trace_event ?
+      trace_event->thread_id() : PlatformThread::CurrentId();
   if (phase == TRACE_EVENT_PHASE_END) {
-    duration = trace_event->timestamp() -
-        thread_event_start_times_[thread_id].top();
-    thread_event_start_times_[thread_id].pop();
-  } else if (phase == TRACE_EVENT_PHASE_COMPLETE &&
-             trace_event->duration().ToInternalValue() != -1) {
-    duration = trace_event->duration();
+    duration = timestamp - thread_event_start_times_[thread_id].top();
     thread_event_start_times_[thread_id].pop();
   }
 
@@ -1868,14 +1882,15 @@
   for (size_t i = 0; i < depth; ++i)
     log << "| ";
 
-  trace_event->AppendPrettyPrinted(&log);
+  if (trace_event)
+    trace_event->AppendPrettyPrinted(&log);
   if (phase == TRACE_EVENT_PHASE_END)
     log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
 
   LOG(ERROR) << log.str() << "\x1b[0;m";
 
-  if (phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_COMPLETE)
-    thread_event_start_times_[thread_id].push(trace_event->timestamp());
+  if (phase == TRACE_EVENT_PHASE_BEGIN)
+    thread_event_start_times_[thread_id].push(timestamp);
 }
 
 void TraceLog::AddTraceEventEtw(char phase,
@@ -1905,20 +1920,37 @@
   OptionalAutoLock lock(lock_);
 
   TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
-  if (!trace_event) {
-    // The event has been recycled.
-    return;
-  }
-
-  trace_event->UpdateDuration();
-
+  if (trace_event) {
+    DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
+    trace_event->UpdateDuration();
 #if defined(OS_ANDROID)
-  trace_event->SendToATrace();
+    trace_event->SendToATrace();
 #endif
+  }
 
   if (trace_options() & ECHO_TO_CONSOLE) {
     lock.EnsureAcquired();
-    OutputEventToConsoleWhileLocked(trace_event);
+    OutputEventToConsoleWhileLocked(TRACE_EVENT_PHASE_END,
+                                    TimeTicks::NowFromSystemTraceTime(),
+                                    trace_event);
+  }
+
+  EventCallback event_callback = reinterpret_cast<EventCallback>(
+      subtle::NoBarrier_Load(&event_callback_));
+  if (event_callback && trace_event) {
+    // The copy is needed when trace_event is from the main buffer in which case
+    // the lock has been locked.
+    TraceEvent event_copy;
+    event_copy.CopyFrom(*trace_event);
+    lock.EnsureReleased();
+    DCHECK(event_copy.duration().InMicroseconds() >= 0);
+    // TODO(wangxianzhu): Should send TRACE_EVENT_PHASE_COMPLETE directly to
+    // clients if it is beneficial and feasible.
+    event_callback(event_copy.timestamp() + event_copy.duration(),
+                   TRACE_EVENT_PHASE_END,
+                   event_copy.category_group_enabled(),
+                   event_copy.name(), event_copy.id(),
+                   0, NULL, NULL, NULL, event_copy.flags());
   }
 }
 
@@ -2011,6 +2043,9 @@
 
 TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
                                                OptionalAutoLock* lock) {
+  if (!handle.chunk_seq)
+    return NULL;
+
   if (thread_local_event_buffer_.Get()) {
     TraceEvent* trace_event =
         thread_local_event_buffer_.Get()->GetEventByHandle(handle);
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 1d30153..6af2877 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -80,25 +80,6 @@
 };
 
 struct TraceEventHandle {
-  TraceEventHandle()
-      : chunk_seq(0),
-        chunk_index(0),
-        event_index(0) {
-  }
-
-  TraceEventHandle(uint32 a_chunk_seq,
-                   size_t a_chunk_index,
-                   size_t a_event_index)
-      : chunk_seq(a_chunk_seq),
-        chunk_index(static_cast<uint16>(a_chunk_index)),
-        event_index(static_cast<uint16>(a_event_index)) {
-    DCHECK(chunk_seq);
-    DCHECK(a_chunk_index < (1u << 16));
-    DCHECK(a_event_index < (1u << 16));
-  }
-
-  bool IsNull() const { return chunk_seq == 0; }
-
   uint32 chunk_seq;
   uint16 chunk_index;
   uint16 event_index;
@@ -163,6 +144,8 @@
   char phase() const { return phase_; }
   int thread_id() const { return thread_id_; }
   TimeDelta duration() const { return duration_; }
+  unsigned long long id() const { return id_; }
+  unsigned char flags() const { return flags_; }
 
   // Exposed for unittesting:
 
@@ -471,7 +454,12 @@
   // WARNING: It is possible for the previously set callback to be called
   // after a call to SetEventCallback() that replaces or clears the callback.
   // This callback may be invoked on any thread.
-  typedef void (*EventCallback)(char phase,
+  // TODO(wangxianzhu): For now for TRACE_EVENT_PHASE_COMPLETE events, the
+  // client will still receive pairs of TRACE_EVENT_PHASE_BEGIN and
+  // TRACE_EVENT_PHASE_END events. Should send TRACE_EVENT_PHASE_COMPLETE
+  // directly to clients if it is beneficial and feasible.
+  typedef void (*EventCallback)(TimeTicks timestamp,
+                                char phase,
                                 const unsigned char* category_group_enabled,
                                 const char* name,
                                 unsigned long long id,
@@ -649,7 +637,9 @@
   TraceBuffer* trace_buffer() const { return logged_events_.get(); }
   TraceBuffer* CreateTraceBuffer();
 
-  void OutputEventToConsoleWhileLocked(TraceEvent* trace_event);
+  void OutputEventToConsoleWhileLocked(unsigned char phase,
+                                       const TimeTicks& timestamp,
+                                       TraceEvent* trace_event);
 
   TraceEvent* AddEventToThreadSharedChunkWhileLocked(
       NotificationHelper* notifier, TraceEventHandle* handle);
diff --git a/base/debug/trace_event_memory.cc b/base/debug/trace_event_memory.cc
index 1be1b09..4b2b050 100644
--- a/base/debug/trace_event_memory.cc
+++ b/base/debug/trace_event_memory.cc
@@ -246,11 +246,8 @@
 // static
 bool ScopedTraceMemory::enabled_ = false;
 
-ScopedTraceMemory::ScopedTraceMemory(const char* category, const char* name) {
-  // Not enabled indicates that the trace system isn't running, so don't
-  // record anything.
-  if (!enabled_)
-    return;
+void ScopedTraceMemory::Initialize(const char* category, const char* name) {
+  DCHECK(enabled_);
   // Get our thread's copy of the stack.
   TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
   const size_t index = trace_memory_stack->scope_depth;
@@ -264,11 +261,8 @@
   trace_memory_stack->scope_depth++;
 }
 
-ScopedTraceMemory::~ScopedTraceMemory() {
-  // Not enabled indicates that the trace system isn't running, so don't
-  // record anything.
-  if (!enabled_)
-    return;
+void ScopedTraceMemory::Destroy() {
+  DCHECK(enabled_);
   // Get our thread's copy of the stack.
   TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
   // The tracing system can be turned on with ScopedTraceMemory objects
diff --git a/base/debug/trace_event_memory.h b/base/debug/trace_event_memory.h
index 5427154..df2e663 100644
--- a/base/debug/trace_event_memory.h
+++ b/base/debug/trace_event_memory.h
@@ -94,8 +94,16 @@
 
   // Memory for |category| and |name| must be static, for example, literal
   // strings in a TRACE_EVENT macro.
-  ScopedTraceMemory(const char* category, const char* name);
-  ~ScopedTraceMemory();
+  ScopedTraceMemory(const char* category, const char* name) {
+    if (!enabled_)
+      return;
+    Initialize(category, name);
+  }
+  ~ScopedTraceMemory() {
+    if (!enabled_)
+      return;
+    Destroy();
+  }
 
   // Enables the storing of trace names on a per-thread stack.
   static void set_enabled(bool enabled) { enabled_ = enabled; }
@@ -107,6 +115,9 @@
   static ScopeData GetScopeDataForTest(int stack_index);
 
  private:
+  void Initialize(const char* category, const char* name);
+  void Destroy();
+
   static bool enabled_;
   DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
 };
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 28f706d..a6a86c7 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -90,6 +90,19 @@
     flush_complete_event.Wait();
   }
 
+  // Used when testing thread-local buffers which requires the thread initiating
+  // flush to have a message loop.
+  void EndTraceAndFlushInThreadWithMessageLoop() {
+    WaitableEvent flush_complete_event(false, false);
+    Thread flush_thread("flush");
+    flush_thread.Start();
+    flush_thread.message_loop()->PostTask(FROM_HERE,
+      base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+                 base::Unretained(this),
+                 &flush_complete_event));
+    flush_complete_event.Wait();
+  }
+
   void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
     while (TraceLog::GetInstance()->IsEnabled())
       TraceLog::GetInstance()->SetDisabled();
@@ -387,10 +400,10 @@
                              "name1", "value1",
                              "name2", "value2");
 
-    TRACE_EVENT_ASYNC_STEP0("all", "TRACE_EVENT_ASYNC_STEP0 call",
-                                  5, "step1");
-    TRACE_EVENT_ASYNC_STEP1("all", "TRACE_EVENT_ASYNC_STEP1 call",
-                                  5, "step2", "name1", "value1");
+    TRACE_EVENT_ASYNC_STEP_INTO0("all", "TRACE_EVENT_ASYNC_STEP_INTO0 call",
+                                 kAsyncId, "step_begin1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("all", "TRACE_EVENT_ASYNC_STEP_INTO1 call",
+                                 kAsyncId, "step_begin2", "name1", "value1");
 
     TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId);
     TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId,
@@ -425,6 +438,11 @@
     TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
         "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
         kAsyncId2, kThreadId, 34567);
+    TRACE_EVENT_ASYNC_STEP_PAST0("all", "TRACE_EVENT_ASYNC_STEP_PAST0 call",
+                                 kAsyncId2, "step_end1");
+    TRACE_EVENT_ASYNC_STEP_PAST1("all", "TRACE_EVENT_ASYNC_STEP_PAST1 call",
+                                 kAsyncId2, "step_end2", "name1", "value1");
+
     TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all",
         "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call",
         kAsyncId2, kThreadId, 45678);
@@ -544,14 +562,14 @@
   EXPECT_SUB_FIND_("name2");
   EXPECT_SUB_FIND_("value2");
 
-  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP0 call");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO0 call");
   EXPECT_SUB_FIND_("id");
   EXPECT_SUB_FIND_(kAsyncIdStr);
-  EXPECT_SUB_FIND_("step1");
-  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP1 call");
+  EXPECT_SUB_FIND_("step_begin1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO1 call");
   EXPECT_SUB_FIND_("id");
   EXPECT_SUB_FIND_(kAsyncIdStr);
-  EXPECT_SUB_FIND_("step2");
+  EXPECT_SUB_FIND_("step_begin2");
   EXPECT_SUB_FIND_("name1");
   EXPECT_SUB_FIND_("value1");
 
@@ -696,6 +714,19 @@
     EXPECT_EQ(kAsyncId2Str, id);
   }
 
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST0 call");
+  {
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end1");
+    EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST1 call");
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end2");
+    EXPECT_SUB_FIND_("name1");
+    EXPECT_SUB_FIND_("value1");
+  }
+
   EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call");
   {
     int val;
@@ -1209,10 +1240,11 @@
 
   unsigned long long id = 0xfeedbeeffeedbeefull;
   TRACE_EVENT_ASYNC_BEGIN0( "cat", "name1", id);
-  TRACE_EVENT_ASYNC_STEP0( "cat", "name1", id, "step1");
+  TRACE_EVENT_ASYNC_STEP_INTO0( "cat", "name1", id, "step1");
   TRACE_EVENT_ASYNC_END0("cat", "name1", id);
   TRACE_EVENT_BEGIN0( "cat", "name2");
   TRACE_EVENT_ASYNC_BEGIN0( "cat", "name3", 0);
+  TRACE_EVENT_ASYNC_STEP_PAST0( "cat", "name3", 0, "step2");
 
   EndTraceAndFlush();
 
@@ -1227,6 +1259,7 @@
   EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str()));
   EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str()));
   EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0"));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name3", "p", "id", "0x0"));
 
   // BEGIN events should not have id
   EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0"));
@@ -1380,14 +1413,7 @@
     delete task_complete_events[i];
   }
 
-  WaitableEvent flush_complete_event(false, false);
-  Thread flush_thread("flush");
-  flush_thread.Start();
-  flush_thread.message_loop()->PostTask(FROM_HERE,
-    base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
-               base::Unretained(this),
-               &flush_complete_event));
-  flush_complete_event.Wait();
+  EndTraceAndFlushInThreadWithMessageLoop();
   ValidateInstantEventPresentOnEveryThread(trace_parsed_,
                                            num_threads, num_events);
 
@@ -1969,9 +1995,12 @@
 
  protected:
   std::vector<std::string> collected_events_;
+  std::vector<unsigned char> collected_event_phases_;
+  std::vector<TimeTicks> collected_events_timestamps_;
 
   static TraceEventCallbackTest* s_instance;
-  static void Callback(char phase,
+  static void Callback(TimeTicks timestamp,
+                       char phase,
                        const unsigned char* category_enabled,
                        const char* name,
                        unsigned long long id,
@@ -1981,6 +2010,8 @@
                        const unsigned long long arg_values[],
                        unsigned char flags) {
     s_instance->collected_events_.push_back(name);
+    s_instance->collected_event_phases_.push_back(phase);
+    s_instance->collected_events_timestamps_.push_back(timestamp);
   }
 };
 
@@ -1994,12 +2025,28 @@
   TraceLog::GetInstance()->SetEventCallback(Callback);
   TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
+  {
+    TRACE_EVENT0("all", "duration");
+    TRACE_EVENT_INSTANT0("all", "event3", TRACE_EVENT_SCOPE_GLOBAL);
+  }
   TraceLog::GetInstance()->SetEventCallback(NULL);
   TRACE_EVENT_INSTANT0("all", "after callback removed",
                        TRACE_EVENT_SCOPE_GLOBAL);
-  ASSERT_EQ(2u, collected_events_.size());
+  ASSERT_EQ(5u, collected_events_.size());
   EXPECT_EQ("event1", collected_events_[0]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_event_phases_[0]);
   EXPECT_EQ("event2", collected_events_[1]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_event_phases_[1]);
+  EXPECT_EQ("duration", collected_events_[2]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_BEGIN, collected_event_phases_[2]);
+  EXPECT_EQ("event3", collected_events_[3]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_event_phases_[3]);
+  EXPECT_EQ("duration", collected_events_[4]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_END, collected_event_phases_[4]);
+  for (size_t i = 1; i < collected_events_timestamps_.size(); i++) {
+    EXPECT_LE(collected_events_timestamps_[i - 1],
+              collected_events_timestamps_[i]);
+  }
 }
 
 TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
@@ -2290,5 +2337,89 @@
   thread.Stop();
 }
 
+TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.message_loop()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.message_loop()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+
+  // The thread will timeout in this flush.
+  EndTraceAndFlushInThreadWithMessageLoop();
+  Clear();
+
+  // Let the thread's message loop continue to spin.
+  task_stop_event.Signal();
+
+  // The following sequence ensures that the FlushCurrentThread task has been
+  // executed in the thread before continuing.
+  task_start_event.Reset();
+  task_stop_event.Reset();
+  thread.message_loop()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+  task_stop_event.Signal();
+  Clear();
+
+  // TraceLog should discover the generation mismatch and recover the thread
+  // local buffer for the thread without any error.
+  BeginTrace();
+  thread.message_loop()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+  EndTraceAndFlushInThreadWithMessageLoop();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+std::string* g_log_buffer = NULL;
+bool MockLogMessageHandler(int, const char*, int, size_t,
+                           const std::string& str) {
+  if (!g_log_buffer)
+    g_log_buffer = new std::string();
+  g_log_buffer->append(str);
+  return false;
+}
+
+TEST_F(TraceEventTestFixture, EchoToConsole) {
+  logging::LogMessageHandlerFunction old_log_message_handler =
+      logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(MockLogMessageHandler);
+
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::ECHO_TO_CONSOLE);
+  TRACE_EVENT_BEGIN0("a", "begin_end");
+  {
+    TRACE_EVENT0("b", "duration");
+    TRACE_EVENT0("b1", "duration1");
+  }
+  TRACE_EVENT_INSTANT0("c", "instant", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_END0("a", "begin_end");
+
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| instant[c]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a] ("));
+
+  EndTraceAndFlush();
+  delete g_log_buffer;
+  logging::SetLogMessageHandler(old_log_message_handler);
+  g_log_buffer = NULL;
+}
+
 }  // namespace debug
 }  // namespace base
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
index ce9bd1f..38bb833 100644
--- a/base/files/file_enumerator.h
+++ b/base/files/file_enumerator.h
@@ -53,6 +53,9 @@
     Time GetLastModifiedTime() const;
 
 #if defined(OS_WIN)
+    // Note that the cAlternateFileName (used to hold the "short" 8.3 name)
+    // of the WIN32_FIND_DATA will be empty. Since we don't use short file
+    // names, we tell Windows to omit it which speeds up the query slightly.
     const WIN32_FIND_DATA& find_data() const { return find_data_; }
 #elif defined(OS_POSIX)
     const struct stat& stat() const { return stat_; }
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index e47f542..6da1667 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
 
 namespace base {
 
@@ -99,7 +100,18 @@
       else
         src = src.Append(pattern_);
 
-      find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
+      if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+        // Use a "large fetch" on newer Windows which should speed up large
+        // enumerations (we seldom abort in the middle).
+        find_handle_ = FindFirstFileEx(src.value().c_str(),
+                                       FindExInfoBasic,  // Omit short name.
+                                       &find_data_,
+                                       FindExSearchNameMatch,
+                                       NULL,
+                                       FIND_FIRST_EX_LARGE_FETCH);
+      } else {
+        find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
+      }
       has_find_data_ = true;
     } else {
       // Search for the next file/directory.
diff --git a/base/mac/authorization_util.h b/base/mac/authorization_util.h
index b34348d..4629039 100644
--- a/base/mac/authorization_util.h
+++ b/base/mac/authorization_util.h
@@ -33,11 +33,20 @@
 namespace base {
 namespace mac {
 
-// Obtains an AuthorizationRef that can be used to run commands as root.  If
-// necessary, prompts the user for authentication.  If the user is prompted,
+// Obtains an AuthorizationRef for the rights indicated by |rights|.  If
+// necessary, prompts the user for authentication. If the user is prompted,
 // |prompt| will be used as the prompt string and an icon appropriate for the
-// application will be displayed in a prompt dialog.  Note that the system
-// appends its own text to the prompt string.  Returns NULL on failure.
+// application will be displayed in a prompt dialog. Note that the system
+// appends its own text to the prompt string. |extraFlags| will be ORed
+// together with the default flags. Returns NULL on failure.
+BASE_EXPORT
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags);
+
+// Obtains an AuthorizationRef (using |GetAuthorizationRightsWithPrompt|) that
+// can be used to run commands as root.
 BASE_EXPORT
 AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
 
diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm
index c292589..6cb8de3 100644
--- a/base/mac/authorization_util.mm
+++ b/base/mac/authorization_util.mm
@@ -22,7 +22,10 @@
 namespace base {
 namespace mac {
 
-AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags) {
   // Create an empty AuthorizationRef.
   ScopedAuthorizationRef authorization;
   OSStatus status = AuthorizationCreate(NULL,
@@ -34,12 +37,11 @@
     return NULL;
   }
 
-  // Specify the "system.privilege.admin" right, which allows
-  // AuthorizationExecuteWithPrivileges to run commands as root.
-  AuthorizationItem right_items[] = {
-    {kAuthorizationRightExecute, 0, NULL, 0}
-  };
-  AuthorizationRights rights = {arraysize(right_items), right_items};
+  AuthorizationFlags flags = kAuthorizationFlagDefaults |
+                             kAuthorizationFlagInteractionAllowed |
+                             kAuthorizationFlagExtendRights |
+                             kAuthorizationFlagPreAuthorize |
+                             extraFlags;
 
   // product_logo_32.png is used instead of app.icns because Authorization
   // Services can't deal with .icns files.
@@ -63,16 +65,12 @@
   AuthorizationEnvironment environment = {arraysize(environment_items),
                                           environment_items};
 
-  AuthorizationFlags flags = kAuthorizationFlagDefaults |
-                             kAuthorizationFlagInteractionAllowed |
-                             kAuthorizationFlagExtendRights |
-                             kAuthorizationFlagPreAuthorize;
-
   status = AuthorizationCopyRights(authorization,
-                                   &rights,
+                                   rights,
                                    &environment,
                                    flags,
                                    NULL);
+
   if (status != errAuthorizationSuccess) {
     if (status != errAuthorizationCanceled) {
       OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights";
@@ -83,6 +81,17 @@
   return authorization.release();
 }
 
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+  // Specify the "system.privilege.admin" right, which allows
+  // AuthorizationExecuteWithPrivileges to run commands as root.
+  AuthorizationItem right_items[] = {
+    {kAuthorizationRightExecute, 0, NULL, 0}
+  };
+  AuthorizationRights rights = {arraysize(right_items), right_items};
+
+  return GetAuthorizationRightsWithPrompt(&rights, prompt, 0);
+}
+
 OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
                                         const char* tool_path,
                                         AuthorizationFlags options,
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
index 447f7bf..46ea3c3 100644
--- a/base/mac/foundation_util.h
+++ b/base/mac/foundation_util.h
@@ -16,10 +16,14 @@
 
 #if defined(__OBJC__)
 #import <Foundation/Foundation.h>
+@class NSFont;
+@class UIFont;
 #else  // __OBJC__
 #include <CoreFoundation/CoreFoundation.h>
 class NSBundle;
+class NSFont;
 class NSString;
+class UIFont;
 #endif  // __OBJC__
 
 #if defined(OS_IOS)
@@ -225,6 +229,12 @@
 CF_TO_NS_MUTABLE_CAST_DECL(String);
 CF_TO_NS_CAST_DECL(CFURL, NSURL);
 
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DECL(CTFont, UIFont);
+#else
+CF_TO_NS_CAST_DECL(CTFont, NSFont);
+#endif
+
 #undef CF_TO_NS_CAST_DECL
 #undef CF_TO_NS_MUTABLE_CAST_DECL
 #undef OBJC_CPP_CLASS_DECL
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index 1897b6f..4e9b224 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -17,45 +17,33 @@
 extern "C" {
 CFTypeID SecACLGetTypeID();
 CFTypeID SecTrustedApplicationGetTypeID();
+Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj);
 }  // extern "C"
 #endif
 
 namespace base {
 namespace mac {
 
-static bool g_override_am_i_bundled = false;
-static bool g_override_am_i_bundled_value = false;
+namespace {
 
-// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
-static bool UncachedAmIBundled() {
+bool g_override_am_i_bundled = false;
+bool g_override_am_i_bundled_value = false;
+
+bool UncachedAmIBundled() {
 #if defined(OS_IOS)
-  // All apps are bundled on iOS
+  // All apps are bundled on iOS.
   return true;
 #else
   if (g_override_am_i_bundled)
     return g_override_am_i_bundled_value;
 
-  ProcessSerialNumber psn = {0, kCurrentProcess};
-
-  FSRef fsref;
-  OSStatus pbErr;
-  if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) {
-    OSSTATUS_DLOG(ERROR, pbErr) << "GetProcessBundleLocation failed";
-    return false;
-  }
-
-  FSCatalogInfo info;
-  OSErr fsErr;
-  if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
-                                NULL, NULL, NULL)) != noErr) {
-    OSSTATUS_DLOG(ERROR, fsErr) << "FSGetCatalogInfo failed";
-    return false;
-  }
-
-  return info.nodeFlags & kFSNodeIsDirectoryMask;
+  // Yes, this is cheap.
+  return [[base::mac::OuterBundle() bundlePath] hasSuffix:@".app"];
 #endif
 }
 
+}  // namespace
+
 bool AmIBundled() {
   // If the return value is not cached, this function will return different
   // values depending on when it's called. This confuses some client code, see
@@ -303,6 +291,31 @@
 CF_TO_NS_MUTABLE_CAST_DEFN(String);
 CF_TO_NS_CAST_DEFN(CFURL, NSURL);
 
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DEFN(CTFont, UIFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+NSFont* CFToNSCast(CTFontRef cf_val) {
+  NSFont* ns_val =
+      const_cast<NSFont*>(reinterpret_cast<const NSFont*>(cf_val));
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         (_CFIsObjC(CTFontGetTypeID(), cf_val) &&
+          [ns_val isKindOfClass:NSClassFromString(@"NSFont")]));
+  return ns_val;
+}
+
+CTFontRef NSToCFCast(NSFont* ns_val) {
+  CTFontRef cf_val = reinterpret_cast<CTFontRef>(ns_val);
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         [ns_val isKindOfClass:NSClassFromString(@"NSFont")]);
+  return cf_val;
+}
+#endif
+
 #undef CF_TO_NS_CAST_DEFN
 #undef CF_TO_NS_MUTABLE_CAST_DEFN
 
@@ -340,9 +353,41 @@
 
 CF_CAST_DEFN(CGColor);
 
-CF_CAST_DEFN(CTFont);
 CF_CAST_DEFN(CTRun);
 
+#if defined(OS_IOS)
+CF_CAST_DEFN(CTFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+template<> CTFontRef
+CFCast<CTFontRef>(const CFTypeRef& cf_val) {
+  if (cf_val == NULL) {
+    return NULL;
+  }
+  if (CFGetTypeID(cf_val) == CTFontGetTypeID()) {
+    return (CTFontRef)(cf_val);
+  }
+
+  if (!_CFIsObjC(CTFontGetTypeID(), cf_val))
+    return NULL;
+
+  id<NSObject> ns_val = reinterpret_cast<id>(const_cast<void*>(cf_val));
+  if ([ns_val isKindOfClass:NSClassFromString(@"NSFont")]) {
+    return (CTFontRef)(cf_val);
+  }
+  return NULL;
+}
+
+template<> CTFontRef
+CFCastStrict<CTFontRef>(const CFTypeRef& cf_val) {
+  CTFontRef rv = CFCast<CTFontRef>(cf_val);
+  DCHECK(cf_val == NULL || rv);
+  return rv;
+}
+#endif
+
 #if !defined(OS_IOS)
 CF_CAST_DEFN(SecACL);
 CF_CAST_DEFN(SecTrustedApplication);
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index 5f82f43..e827f37 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -92,16 +92,6 @@
 // Excludes the file given by |file_path| from being backed up by Time Machine.
 BASE_EXPORT bool SetFileBackupExclusion(const FilePath& file_path);
 
-// Sets the process name as displayed in Activity Monitor to process_name.
-BASE_EXPORT void SetProcessName(CFStringRef process_name);
-
-// Converts a NSImage to a CGImageRef.  Normally, the system frameworks can do
-// this fine, especially on 10.6.  On 10.5, however, CGImage cannot handle
-// converting a PDF-backed NSImage into a CGImageRef.  This function will
-// rasterize the PDF into a bitmap CGImage.  The caller is responsible for
-// releasing the return value.
-BASE_EXPORT CGImageRef CopyNSImageToCGImage(NSImage* image);
-
 // Checks if the current application is set as a Login Item, so it will launch
 // on Login. If a non-NULL pointer to is_hidden is passed, the Login Item also
 // is queried for the 'hide on launch' flag.
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index bb35c2b..c256599 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -298,129 +298,6 @@
   return os_err == noErr;
 }
 
-void SetProcessName(CFStringRef process_name) {
-  if (!process_name || CFStringGetLength(process_name) == 0) {
-    NOTREACHED() << "SetProcessName given bad name.";
-    return;
-  }
-
-  if (![NSThread isMainThread]) {
-    NOTREACHED() << "Should only set process name from main thread.";
-    return;
-  }
-
-  // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
-  // plugin host, and could break at any time (although realistically it's only
-  // likely to break in a new major release).
-  // When 10.7 is available, check that this still works, and update this
-  // comment for 10.8.
-
-  // Private CFType used in these LaunchServices calls.
-  typedef CFTypeRef PrivateLSASN;
-  typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
-  typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
-                                                          CFStringRef,
-                                                          CFStringRef,
-                                                          CFDictionaryRef*);
-
-  static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
-      NULL;
-  static LSSetApplicationInformationItemType
-      ls_set_application_information_item_func = NULL;
-  static CFStringRef ls_display_name_key = NULL;
-
-  static bool did_symbol_lookup = false;
-  if (!did_symbol_lookup) {
-    did_symbol_lookup = true;
-    CFBundleRef launch_services_bundle =
-        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
-    if (!launch_services_bundle) {
-      DLOG(ERROR) << "Failed to look up LaunchServices bundle";
-      return;
-    }
-
-    ls_get_current_application_asn_func =
-        reinterpret_cast<LSGetCurrentApplicationASNType>(
-            CFBundleGetFunctionPointerForName(
-                launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
-    if (!ls_get_current_application_asn_func)
-      DLOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";
-
-    ls_set_application_information_item_func =
-        reinterpret_cast<LSSetApplicationInformationItemType>(
-            CFBundleGetFunctionPointerForName(
-                launch_services_bundle,
-                CFSTR("_LSSetApplicationInformationItem")));
-    if (!ls_set_application_information_item_func)
-      DLOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
-
-    CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
-        CFBundleGetDataPointerForName(launch_services_bundle,
-                                      CFSTR("_kLSDisplayNameKey")));
-    ls_display_name_key = key_pointer ? *key_pointer : NULL;
-    if (!ls_display_name_key)
-      DLOG(ERROR) << "Could not find _kLSDisplayNameKey";
-
-    // Internally, this call relies on the Mach ports that are started up by the
-    // Carbon Process Manager.  In debug builds this usually happens due to how
-    // the logging layers are started up; but in release, it isn't started in as
-    // much of a defined order.  So if the symbols had to be loaded, go ahead
-    // and force a call to make sure the manager has been initialized and hence
-    // the ports are opened.
-    ProcessSerialNumber psn;
-    GetCurrentProcess(&psn);
-  }
-  if (!ls_get_current_application_asn_func ||
-      !ls_set_application_information_item_func ||
-      !ls_display_name_key) {
-    return;
-  }
-
-  PrivateLSASN asn = ls_get_current_application_asn_func();
-  // Constant used by WebKit; what exactly it means is unknown.
-  const int magic_session_constant = -2;
-  OSErr err =
-      ls_set_application_information_item_func(magic_session_constant, asn,
-                                               ls_display_name_key,
-                                               process_name,
-                                               NULL /* optional out param */);
-  OSSTATUS_DLOG_IF(ERROR, err != noErr, err)
-      << "Call to set process name failed";
-}
-
-// Converts a NSImage to a CGImageRef.  Normally, the system frameworks can do
-// this fine, especially on 10.6.  On 10.5, however, CGImage cannot handle
-// converting a PDF-backed NSImage into a CGImageRef.  This function will
-// rasterize the PDF into a bitmap CGImage.  The caller is responsible for
-// releasing the return value.
-CGImageRef CopyNSImageToCGImage(NSImage* image) {
-  // This is based loosely on http://www.cocoadev.com/index.pl?CGImageRef .
-  NSSize size = [image size];
-  ScopedCFTypeRef<CGContextRef> context(
-      CGBitmapContextCreate(NULL,  // Allow CG to allocate memory.
-                            size.width,
-                            size.height,
-                            8,  // bitsPerComponent
-                            0,  // bytesPerRow - CG will calculate by default.
-                            [[NSColorSpace genericRGBColorSpace] CGColorSpace],
-                            kCGBitmapByteOrder32Host |
-                                kCGImageAlphaPremultipliedFirst));
-  if (!context.get())
-    return NULL;
-
-  [NSGraphicsContext saveGraphicsState];
-  [NSGraphicsContext setCurrentContext:
-      [NSGraphicsContext graphicsContextWithGraphicsPort:context.get()
-                                                 flipped:NO]];
-  [image drawInRect:NSMakeRect(0,0, size.width, size.height)
-           fromRect:NSZeroRect
-          operation:NSCompositeCopy
-           fraction:1.0];
-  [NSGraphicsContext restoreGraphicsState];
-
-  return CGBitmapContextCreateImage(context);
-}
-
 bool CheckLoginItemStatus(bool* is_hidden) {
   ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
   if (!item.get())
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index 0688b5a..15ceca3 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -124,20 +124,6 @@
   EXPECT_FALSE(excluded_by_path);
 }
 
-TEST_F(MacUtilTest, CopyNSImageToCGImage) {
-  base::scoped_nsobject<NSImage> nsImage(
-      [[NSImage alloc] initWithSize:NSMakeSize(20, 20)]);
-  [nsImage lockFocus];
-  [[NSColor redColor] set];
-  NSRect rect = NSZeroRect;
-  rect.size = [nsImage size];
-  NSRectFill(rect);
-  [nsImage unlockFocus];
-
-  ScopedCFTypeRef<CGImageRef> cgImage(CopyNSImageToCGImage(nsImage.get()));
-  EXPECT_TRUE(cgImage.get());
-}
-
 TEST_F(MacUtilTest, NSObjectRetainRelease) {
   base::scoped_nsobject<NSArray> array(
       [[NSArray alloc] initWithObjects:@"foo", nil]);
diff --git a/base/memory/discardable_memory.cc b/base/memory/discardable_memory.cc
deleted file mode 100644
index 5dcfc1c..0000000
--- a/base/memory/discardable_memory.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2013 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/memory/discardable_memory.h"
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-
-namespace base {
-
-// Stub implementations for platforms that don't support discardable memory.
-
-#if !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
-// static
-bool DiscardableMemory::Supported() {
-  return false;
-}
-
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
-    size_t size) {
-  return scoped_ptr<DiscardableMemory>();
-}
-
-// static
-bool DiscardableMemory::PurgeForTestingSupported() {
-  return false;
-}
-
-// static
-void DiscardableMemory::PurgeForTesting() {
-  NOTIMPLEMENTED();
-}
-
-#endif  // OS_*
-
-}  // namespace base
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
index c6a8d82..d8fd4f6 100644
--- a/base/memory/discardable_memory.h
+++ b/base/memory/discardable_memory.h
@@ -38,6 +38,9 @@
 //   - Because of memory alignment, the amount of memory allocated can be
 //     larger than the requested memory size. It is not very efficient for
 //     small allocations.
+//   - A discardable memory instance is not thread safe. It is the
+//     responsibility of users of discardable memory to ensure there are no
+//     races.
 //
 // References:
 //   - Linux: http://lwn.net/Articles/452035/
@@ -48,8 +51,9 @@
  public:
   virtual ~DiscardableMemory() {}
 
-  // Returns whether the system supports discardable memory.
-  static bool Supported();
+  // Check whether the system supports discardable memory natively. Returns
+  // false if the support is emulated.
+  static bool SupportedNatively();
 
   static scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size);
 
diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc
index b88a136..3850439 100644
--- a/base/memory/discardable_memory_android.cc
+++ b/base/memory/discardable_memory_android.cc
@@ -135,7 +135,7 @@
 }  // namespace
 
 // static
-bool DiscardableMemory::Supported() {
+bool DiscardableMemory::SupportedNatively() {
   return true;
 }
 
diff --git a/base/memory/discardable_memory_emulated.cc b/base/memory/discardable_memory_emulated.cc
new file mode 100644
index 0000000..2462462
--- /dev/null
+++ b/base/memory/discardable_memory_emulated.cc
@@ -0,0 +1,85 @@
+// Copyright 2013 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/memory/discardable_memory.h"
+
+#include "base/memory/discardable_memory_provider.h"
+
+using base::internal::DiscardableMemoryProvider;
+
+namespace base {
+namespace {
+
+class DiscardableMemoryEmulated : public DiscardableMemory {
+ public:
+  explicit DiscardableMemoryEmulated(size_t size) : is_locked_(false) {
+    DiscardableMemoryProvider::GetInstance()->Register(this, size);
+  }
+
+  virtual ~DiscardableMemoryEmulated() {
+    if (is_locked_)
+      Unlock();
+    DiscardableMemoryProvider::GetInstance()->Unregister(this);
+  }
+
+  // DiscardableMemory:
+  virtual LockDiscardableMemoryStatus Lock() OVERRIDE {
+    DCHECK(!is_locked_);
+
+    bool purged = false;
+    memory_ = DiscardableMemoryProvider::GetInstance()->Acquire(this, &purged);
+    if (!memory_)
+      return DISCARDABLE_MEMORY_FAILED;
+
+    is_locked_ = true;
+    return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS;
+  }
+
+  virtual void Unlock() OVERRIDE {
+    DCHECK(is_locked_);
+    DiscardableMemoryProvider::GetInstance()->Release(this, memory_.Pass());
+    is_locked_ = false;
+  }
+
+  virtual void* Memory() const OVERRIDE {
+    DCHECK(memory_);
+    return memory_.get();
+  }
+
+ private:
+  scoped_ptr<uint8, FreeDeleter> memory_;
+  bool is_locked_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryEmulated);
+};
+
+}  // namespace
+
+// static
+bool DiscardableMemory::SupportedNatively() {
+  return false;
+}
+
+// static
+scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
+    size_t size) {
+  scoped_ptr<DiscardableMemory> memory(new DiscardableMemoryEmulated(size));
+  if (!memory)
+    return scoped_ptr<DiscardableMemory>();
+  if (memory->Lock() != DISCARDABLE_MEMORY_PURGED)
+    return scoped_ptr<DiscardableMemory>();
+  return memory.Pass();
+}
+
+// static
+bool DiscardableMemory::PurgeForTestingSupported() {
+  return true;
+}
+
+// static
+void DiscardableMemory::PurgeForTesting() {
+  DiscardableMemoryProvider::GetInstance()->PurgeAll();
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory_mac.cc b/base/memory/discardable_memory_mac.cc
index a7f47bb..aa68235 100644
--- a/base/memory/discardable_memory_mac.cc
+++ b/base/memory/discardable_memory_mac.cc
@@ -75,7 +75,7 @@
 }  // namespace
 
 // static
-bool DiscardableMemory::Supported() {
+bool DiscardableMemory::SupportedNatively() {
   return true;
 }
 
diff --git a/base/memory/discardable_memory_provider.cc b/base/memory/discardable_memory_provider.cc
new file mode 100644
index 0000000..a0ba0ad
--- /dev/null
+++ b/base/memory/discardable_memory_provider.cc
@@ -0,0 +1,240 @@
+// Copyright 2013 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/memory/discardable_memory_provider.h"
+
+#include "base/bind.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/mru_cache.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/memory/discardable_memory.h"
+#include "base/synchronization/lock.h"
+#include "base/sys_info.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+static base::LazyInstance<DiscardableMemoryProvider>::Leaky g_provider =
+    LAZY_INSTANCE_INITIALIZER;
+
+// If this is given a valid value via SetInstanceForTest, this pointer will be
+// returned by GetInstance rather than |g_provider|.
+static DiscardableMemoryProvider* g_provider_for_test = NULL;
+
+// This is admittedly pretty magical. It's approximately enough memory for two
+// 2560x1600 images.
+static const size_t kDefaultDiscardableMemoryLimit = 32 * 1024 * 1024;
+static const size_t kDefaultBytesToReclaimUnderModeratePressure =
+    kDefaultDiscardableMemoryLimit / 2;
+
+}  // namespace
+
+DiscardableMemoryProvider::DiscardableMemoryProvider()
+    : allocations_(AllocationMap::NO_AUTO_EVICT),
+      bytes_allocated_(0),
+      discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
+      bytes_to_reclaim_under_moderate_pressure_(
+          kDefaultBytesToReclaimUnderModeratePressure),
+      memory_pressure_listener_(
+          base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure)) {
+}
+
+DiscardableMemoryProvider::~DiscardableMemoryProvider() {
+  DCHECK(allocations_.empty());
+  DCHECK_EQ(0u, bytes_allocated_);
+}
+
+// static
+DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() {
+  if (g_provider_for_test)
+    return g_provider_for_test;
+  return g_provider.Pointer();
+}
+
+// static
+void DiscardableMemoryProvider::SetInstanceForTest(
+    DiscardableMemoryProvider* provider) {
+  g_provider_for_test = provider;
+}
+
+// static
+void DiscardableMemoryProvider::NotifyMemoryPressure(
+    MemoryPressureListener::MemoryPressureLevel pressure_level) {
+  switch (pressure_level) {
+    case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
+      DiscardableMemoryProvider::GetInstance()->Purge();
+      return;
+    case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
+      DiscardableMemoryProvider::GetInstance()->PurgeAll();
+      return;
+  }
+
+  NOTREACHED();
+}
+
+void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) {
+  AutoLock lock(lock_);
+  discardable_memory_limit_ = bytes;
+  EnforcePolicyWithLockAcquired();
+}
+
+void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure(
+    size_t bytes) {
+  AutoLock lock(lock_);
+  bytes_to_reclaim_under_moderate_pressure_ = bytes;
+  EnforcePolicyWithLockAcquired();
+}
+
+void DiscardableMemoryProvider::Register(
+    const DiscardableMemory* discardable, size_t bytes) {
+  AutoLock lock(lock_);
+  DCHECK(allocations_.Peek(discardable) == allocations_.end());
+  allocations_.Put(discardable, Allocation(bytes));
+}
+
+void DiscardableMemoryProvider::Unregister(
+    const DiscardableMemory* discardable) {
+  AutoLock lock(lock_);
+  AllocationMap::iterator it = allocations_.Peek(discardable);
+  if (it == allocations_.end())
+    return;
+
+  if (it->second.memory) {
+    size_t bytes = it->second.bytes;
+    DCHECK_LE(bytes, bytes_allocated_);
+    bytes_allocated_ -= bytes;
+    free(it->second.memory);
+  }
+  allocations_.Erase(it);
+}
+
+scoped_ptr<uint8, FreeDeleter> DiscardableMemoryProvider::Acquire(
+    const DiscardableMemory* discardable,
+    bool* purged) {
+  AutoLock lock(lock_);
+  // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
+  // cache.
+  AllocationMap::iterator it = allocations_.Get(discardable);
+  CHECK(it != allocations_.end());
+
+  if (it->second.memory) {
+    scoped_ptr<uint8, FreeDeleter> memory(it->second.memory);
+    it->second.memory = NULL;
+    *purged = false;
+    return memory.Pass();
+  }
+
+  size_t bytes = it->second.bytes;
+  if (!bytes)
+    return scoped_ptr<uint8, FreeDeleter>();
+
+  if (discardable_memory_limit_) {
+    size_t limit = 0;
+    if (bytes < discardable_memory_limit_)
+      limit = discardable_memory_limit_ - bytes;
+
+    PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
+  }
+
+  bytes_allocated_ += bytes;
+  *purged = true;
+  return scoped_ptr<uint8, FreeDeleter>(static_cast<uint8*>(malloc(bytes)));
+}
+
+void DiscardableMemoryProvider::Release(
+    const DiscardableMemory* discardable,
+    scoped_ptr<uint8, FreeDeleter> memory) {
+  AutoLock lock(lock_);
+  // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
+  // cache.
+  AllocationMap::iterator it = allocations_.Get(discardable);
+  CHECK(it != allocations_.end());
+
+  DCHECK(!it->second.memory);
+  it->second.memory = memory.release();
+
+  EnforcePolicyWithLockAcquired();
+}
+
+void DiscardableMemoryProvider::PurgeAll() {
+  AutoLock lock(lock_);
+  PurgeLRUWithLockAcquiredUntilUsageIsWithin(0);
+}
+
+bool DiscardableMemoryProvider::IsRegisteredForTest(
+    const DiscardableMemory* discardable) const {
+  AutoLock lock(lock_);
+  AllocationMap::const_iterator it = allocations_.Peek(discardable);
+  return it != allocations_.end();
+}
+
+bool DiscardableMemoryProvider::CanBePurgedForTest(
+    const DiscardableMemory* discardable) const {
+  AutoLock lock(lock_);
+  AllocationMap::const_iterator it = allocations_.Peek(discardable);
+  return it != allocations_.end() && it->second.memory;
+}
+
+size_t DiscardableMemoryProvider::GetBytesAllocatedForTest() const {
+  AutoLock lock(lock_);
+  return bytes_allocated_;
+}
+
+void DiscardableMemoryProvider::Purge() {
+  AutoLock lock(lock_);
+
+  if (bytes_to_reclaim_under_moderate_pressure_ == 0)
+    return;
+
+  size_t limit = 0;
+  if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
+    limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
+
+  PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
+}
+
+void DiscardableMemoryProvider::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
+    size_t limit) {
+  TRACE_EVENT1(
+      "base",
+      "DiscardableMemoryProvider::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
+      "limit", limit);
+
+  lock_.AssertAcquired();
+
+  for (AllocationMap::reverse_iterator it = allocations_.rbegin();
+       it != allocations_.rend();
+       ++it) {
+    if (bytes_allocated_ <= limit)
+      break;
+    if (!it->second.memory)
+      continue;
+
+    size_t bytes = it->second.bytes;
+    DCHECK_LE(bytes, bytes_allocated_);
+    bytes_allocated_ -= bytes;
+    free(it->second.memory);
+    it->second.memory = NULL;
+  }
+}
+
+void DiscardableMemoryProvider::EnforcePolicyWithLockAcquired() {
+  lock_.AssertAcquired();
+
+  bool exceeded_bound = bytes_allocated_ > discardable_memory_limit_;
+  if (!exceeded_bound || !bytes_to_reclaim_under_moderate_pressure_)
+    return;
+
+  size_t limit = 0;
+  if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
+    limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
+
+  PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/memory/discardable_memory_provider.h b/base/memory/discardable_memory_provider.h
new file mode 100644
index 0000000..005cc1d
--- /dev/null
+++ b/base/memory/discardable_memory_provider.h
@@ -0,0 +1,151 @@
+// Copyright 2013 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 BASE_MEMORY_DISCARDABLE_MEMORY_PROVIDER_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_PROVIDER_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/mru_cache.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+class DiscardableMemory;
+}  // namespace base
+
+#if defined(COMPILER_GCC)
+namespace BASE_HASH_NAMESPACE {
+template <>
+struct hash<const base::DiscardableMemory*> {
+  size_t operator()(const base::DiscardableMemory* ptr) const {
+    return hash<size_t>()(reinterpret_cast<size_t>(ptr));
+  }
+};
+}  // namespace BASE_HASH_NAMESPACE
+#endif  // COMPILER
+
+namespace base {
+namespace internal {
+
+// The DiscardableMemoryProvider manages a collection of emulated
+// DiscardableMemory instances. It is used on platforms that do not support
+// discardable memory natively. It keeps track of all DiscardableMemory
+// instances (in case they need to be purged), and the total amount of
+// allocated memory (in case this forces a purge).
+//
+// When notified of memory pressure, the provider either purges the LRU
+// memory -- if the pressure is moderate -- or all discardable memory
+// if the pressure is critical.
+//
+// NB - this class is an implementation detail. It has been exposed for testing
+// purposes. You should not need to use this class directly.
+class BASE_EXPORT_PRIVATE DiscardableMemoryProvider {
+ public:
+  DiscardableMemoryProvider();
+  ~DiscardableMemoryProvider();
+
+  static DiscardableMemoryProvider* GetInstance();
+
+  // Sets the instance of DiscardableMemoryProvider to be returned by
+  // GetInstance. This should only be used by tests and must be called
+  // prior to GetInstance(). The ownership of the given provider is
+  // retained by the caller.
+  static void SetInstanceForTest(DiscardableMemoryProvider* provider);
+
+  // The maximum number of bytes of discardable memory that may be allocated
+  // before we assume moderate memory pressure. If this amount is zero, it is
+  // interpreted as having no limit at all.
+  void SetDiscardableMemoryLimit(size_t bytes);
+
+  // Sets the amount of memory to reclaim when we're under moderate pressure.
+  void SetBytesToReclaimUnderModeratePressure(size_t bytes);
+
+  // Adds the given discardable memory to the provider's collection.
+  void Register(const DiscardableMemory* discardable, size_t bytes);
+
+  // Removes the given discardable memory from the provider's collection.
+  void Unregister(const DiscardableMemory* discardable);
+
+  // Returns NULL if an error occurred. Otherwise, returns the backing buffer
+  // and sets |purged| to indicate whether or not the backing buffer has been
+  // purged since last use.
+  scoped_ptr<uint8, FreeDeleter> Acquire(
+      const DiscardableMemory* discardable, bool* purged);
+
+  // Release a previously acquired backing buffer. This gives the buffer back
+  // to the provider where it can be purged if necessary.
+  void Release(const DiscardableMemory* discardable,
+               scoped_ptr<uint8, FreeDeleter> memory);
+
+  // Purges all discardable memory.
+  void PurgeAll();
+
+  // Returns true if discardable memory has been added to the provider's
+  // collection. This should only be used by tests.
+  bool IsRegisteredForTest(const DiscardableMemory* discardable) const;
+
+  // Returns true if discardable memory can be purged. This should only
+  // be used by tests.
+  bool CanBePurgedForTest(const DiscardableMemory* discardable) const;
+
+  // Returns total amount of allocated discardable memory. This should only
+  // be used by tests.
+  size_t GetBytesAllocatedForTest() const;
+
+ private:
+  struct Allocation {
+   explicit Allocation(size_t bytes)
+       : bytes(bytes),
+         memory(NULL) {
+   }
+
+    size_t bytes;
+    uint8* memory;
+  };
+  typedef HashingMRUCache<const DiscardableMemory*, Allocation> AllocationMap;
+
+  // This can be called as a hint that the system is under memory pressure.
+  static void NotifyMemoryPressure(
+      MemoryPressureListener::MemoryPressureLevel pressure_level);
+
+  // Purges least recently used memory based on the value of
+  // |bytes_to_reclaim_under_moderate_pressure_|.
+  void Purge();
+
+  // Purges least recently used memory until usage is less or equal to |limit|.
+  // Caller must acquire |lock_| prior to calling this function.
+  void PurgeLRUWithLockAcquiredUntilUsageIsWithin(size_t limit);
+
+  // Ensures that we don't allocate beyond our memory limit.
+  // Caller must acquire |lock_| prior to calling this function.
+  void EnforcePolicyWithLockAcquired();
+
+  // Needs to be held when accessing members.
+  mutable Lock lock_;
+
+  // A MRU cache of all allocated bits of discardable memory. Used for purging.
+  AllocationMap allocations_;
+
+  // The total amount of allocated discardable memory.
+  size_t bytes_allocated_;
+
+  // The maximum number of bytes of discardable memory that may be allocated
+  // before we assume moderate memory pressure.
+  size_t discardable_memory_limit_;
+
+  // Under moderate memory pressure, we will purge this amount of memory.
+  size_t bytes_to_reclaim_under_moderate_pressure_;
+
+  // Allows us to be respond when the system reports that it is under memory
+  // pressure.
+  MemoryPressureListener memory_pressure_listener_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryProvider);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_MEMORY_PROVIDER_H_
diff --git a/base/memory/discardable_memory_provider_unittest.cc b/base/memory/discardable_memory_provider_unittest.cc
new file mode 100644
index 0000000..8c1aee8
--- /dev/null
+++ b/base/memory/discardable_memory_provider_unittest.cc
@@ -0,0 +1,347 @@
+// Copyright 2013 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/memory/discardable_memory_provider.h"
+
+#include "base/bind.h"
+#include "base/memory/discardable_memory.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::internal::DiscardableMemoryProvider;
+
+namespace base {
+
+class DiscardableMemoryProviderTestBase {
+ public:
+  DiscardableMemoryProviderTestBase()
+      : message_loop_(MessageLoop::TYPE_IO),
+        provider_(new DiscardableMemoryProvider) {
+    // We set a provider here for two reasons:
+    //   1. It ensures that one test cannot affect the next, and
+    //   2. Since the provider listens for pressure notifications on the thread
+    //      it was created on, if we create it on the test thread, we can run
+    //      the test thread's message loop until idle when we want to process
+    //      one of these notifications.
+    DiscardableMemoryProvider::SetInstanceForTest(provider_.get());
+  }
+
+  virtual ~DiscardableMemoryProviderTestBase() {
+    DiscardableMemoryProvider::SetInstanceForTest(NULL);
+  }
+
+ protected:
+  bool IsRegistered(const DiscardableMemory* discardable) {
+    return DiscardableMemoryProvider::GetInstance()->IsRegisteredForTest(
+        discardable);
+  }
+
+  bool CanBePurged(const DiscardableMemory* discardable) {
+    return DiscardableMemoryProvider::GetInstance()->CanBePurgedForTest(
+        discardable);
+  }
+
+  size_t BytesAllocated() const {
+    return DiscardableMemoryProvider::GetInstance()->
+        GetBytesAllocatedForTest();
+  }
+
+  void* Memory(const DiscardableMemory* discardable) const {
+    return discardable->Memory();
+  }
+
+  void SetDiscardableMemoryLimit(size_t bytes) {
+    DiscardableMemoryProvider::GetInstance()->
+        SetDiscardableMemoryLimit(bytes);
+  }
+
+  void SetBytesToReclaimUnderModeratePressure(size_t bytes) {
+    DiscardableMemoryProvider::GetInstance()->
+        SetBytesToReclaimUnderModeratePressure(bytes);
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<DiscardableMemoryProvider> provider_;
+};
+
+class DiscardableMemoryProviderTest
+    : public DiscardableMemoryProviderTestBase,
+      public testing::Test {
+ public:
+  DiscardableMemoryProviderTest() {}
+};
+
+TEST_F(DiscardableMemoryProviderTest, CreateLockedMemory) {
+  size_t size = 1024;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_TRUE(IsRegistered(discardable.get()));
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+  EXPECT_EQ(1024u, BytesAllocated());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+}
+
+TEST_F(DiscardableMemoryProviderTest, CreateLockedMemoryZeroSize) {
+  size_t size = 0;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_FALSE(discardable);
+  EXPECT_FALSE(IsRegistered(discardable.get()));
+  EXPECT_EQ(0u, BytesAllocated());
+}
+
+TEST_F(DiscardableMemoryProviderTest, LockAfterUnlock) {
+  size_t size = 1024;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_TRUE(IsRegistered(discardable.get()));
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+  EXPECT_EQ(1024u, BytesAllocated());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+
+  // Now unlock so we can lock later.
+  discardable->Unlock();
+  EXPECT_TRUE(CanBePurged(discardable.get()));
+
+  EXPECT_EQ(DISCARDABLE_MEMORY_SUCCESS, discardable->Lock());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+}
+
+TEST_F(DiscardableMemoryProviderTest, LockAfterPurge) {
+  size_t size = 1024;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_TRUE(IsRegistered(discardable.get()));
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+  EXPECT_EQ(1024u, BytesAllocated());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+
+  // Now unlock so we can lock later.
+  discardable->Unlock();
+  EXPECT_TRUE(CanBePurged(discardable.get()));
+
+  // Force the system to purge.
+  MemoryPressureListener::NotifyMemoryPressure(
+      MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
+
+  // Required because ObserverListThreadSafe notifies via PostTask.
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(DISCARDABLE_MEMORY_PURGED, discardable->Lock());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+}
+
+TEST_F(DiscardableMemoryProviderTest, LockAfterPurgeAndCannotReallocate) {
+  size_t size = 1024;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_TRUE(IsRegistered(discardable.get()));
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+  EXPECT_EQ(1024u, BytesAllocated());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+
+  // Now unlock so we can lock later.
+  discardable->Unlock();
+  EXPECT_TRUE(CanBePurged(discardable.get()));
+
+  // Set max allowed allocation to 1 byte. This will make cause the memory
+  // to be purged.
+  SetDiscardableMemoryLimit(1);
+
+  EXPECT_EQ(DISCARDABLE_MEMORY_PURGED, discardable->Lock());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+}
+
+class PermutationTestData {
+ public:
+  PermutationTestData(unsigned d0, unsigned d1, unsigned d2) {
+    ordering_[0] = d0;
+    ordering_[1] = d1;
+    ordering_[2] = d2;
+  }
+
+  const unsigned* ordering() const { return ordering_; }
+
+ private:
+  unsigned ordering_[3];
+};
+
+class DiscardableMemoryProviderPermutationTest
+    : public DiscardableMemoryProviderTestBase,
+      public testing::TestWithParam<PermutationTestData> {
+ public:
+  DiscardableMemoryProviderPermutationTest() {}
+
+ protected:
+  // Use discardable memory in order specified by ordering parameter.
+  void CreateAndUseDiscardableMemory() {
+    for (int i = 0; i < 3; ++i) {
+      discardables_[i] = DiscardableMemory::CreateLockedMemory(1024);
+      EXPECT_TRUE(discardables_[i]);
+      EXPECT_NE(static_cast<void*>(NULL), Memory(discardables_[i].get()));
+      discardables_[i]->Unlock();
+    }
+    for (int i = 0; i < 3; ++i) {
+      int index = GetParam().ordering()[i];
+      EXPECT_NE(DISCARDABLE_MEMORY_FAILED, discardables_[index]->Lock());
+      // Leave i == 0 locked.
+      if (i > 0)
+        discardables_[index]->Unlock();
+    }
+  }
+
+  DiscardableMemory* discardable(unsigned position) {
+    return discardables_[GetParam().ordering()[position]].get();
+  }
+
+ private:
+  scoped_ptr<DiscardableMemory> discardables_[3];
+};
+
+// Verify that memory was discarded in the correct order after applying
+// memory pressure.
+TEST_P(DiscardableMemoryProviderPermutationTest, LRUDiscardedModeratePressure) {
+  CreateAndUseDiscardableMemory();
+
+  SetBytesToReclaimUnderModeratePressure(1024);
+  MemoryPressureListener::NotifyMemoryPressure(
+      MemoryPressureListener::MEMORY_PRESSURE_MODERATE);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_NE(DISCARDABLE_MEMORY_FAILED, discardable(2)->Lock());
+  EXPECT_NE(DISCARDABLE_MEMORY_SUCCESS, discardable(1)->Lock());
+  // 0 should still be locked.
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(0)));
+}
+
+// Verify that memory was discarded in the correct order after changing
+// memory limit.
+TEST_P(DiscardableMemoryProviderPermutationTest, LRUDiscardedExceedLimit) {
+  CreateAndUseDiscardableMemory();
+
+  SetBytesToReclaimUnderModeratePressure(1024);
+  SetDiscardableMemoryLimit(2048);
+
+  EXPECT_NE(DISCARDABLE_MEMORY_FAILED, discardable(2)->Lock());
+  EXPECT_NE(DISCARDABLE_MEMORY_SUCCESS, discardable(1)->Lock());
+  // 0 should still be locked.
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(0)));
+}
+
+TEST_P(DiscardableMemoryProviderPermutationTest,
+       CriticalPressureFreesAllUnlocked) {
+  CreateAndUseDiscardableMemory();
+
+  MemoryPressureListener::NotifyMemoryPressure(
+      MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
+  RunLoop().RunUntilIdle();
+
+  for (int i = 0; i < 3; ++i) {
+    if (i == 0)
+      EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(i)));
+    else
+      EXPECT_EQ(DISCARDABLE_MEMORY_PURGED, discardable(i)->Lock());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(DiscardableMemoryProviderPermutationTests,
+                        DiscardableMemoryProviderPermutationTest,
+                        ::testing::Values(PermutationTestData(0, 1, 2),
+                                          PermutationTestData(0, 2, 1),
+                                          PermutationTestData(1, 0, 2),
+                                          PermutationTestData(1, 2, 0),
+                                          PermutationTestData(2, 0, 1),
+                                          PermutationTestData(2, 1, 0)));
+
+TEST_F(DiscardableMemoryProviderTest, NormalDestruction) {
+  {
+    size_t size = 1024;
+    const scoped_ptr<DiscardableMemory> discardable(
+        DiscardableMemory::CreateLockedMemory(size));
+    EXPECT_TRUE(IsRegistered(discardable.get()));
+    EXPECT_EQ(1024u, BytesAllocated());
+  }
+  EXPECT_EQ(0u, BytesAllocated());
+}
+
+TEST_F(DiscardableMemoryProviderTest, DestructionWhileLocked) {
+  {
+    size_t size = 1024;
+    const scoped_ptr<DiscardableMemory> discardable(
+        DiscardableMemory::CreateLockedMemory(size));
+    EXPECT_TRUE(IsRegistered(discardable.get()));
+    EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+    EXPECT_EQ(1024u, BytesAllocated());
+    EXPECT_FALSE(CanBePurged(discardable.get()));
+  }
+  // Should have ignored the "locked" status and freed the discardable memory.
+  EXPECT_EQ(0u, BytesAllocated());
+}
+
+#if !defined(NDEBUG) && !defined(OS_ANDROID)
+// Death tests are not supported with Android APKs.
+TEST_F(DiscardableMemoryProviderTest, UnlockedMemoryAccessCrashesInDebugMode) {
+  size_t size = 1024;
+  const scoped_ptr<DiscardableMemory> discardable(
+      DiscardableMemory::CreateLockedMemory(size));
+  EXPECT_TRUE(IsRegistered(discardable.get()));
+  EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+  EXPECT_EQ(1024u, BytesAllocated());
+  EXPECT_FALSE(CanBePurged(discardable.get()));
+  discardable->Unlock();
+  EXPECT_TRUE(CanBePurged(discardable.get()));
+  // We *must* die if we are asked to vend a pointer to unlocked memory.
+  EXPECT_DEATH(discardable->Memory(), ".*Check failed.*");
+}
+#endif
+
+class ThreadedDiscardableMemoryProviderTest
+    : public DiscardableMemoryProviderTest {
+ public:
+  ThreadedDiscardableMemoryProviderTest()
+      : memory_usage_thread_("memory_usage_thread"),
+        thread_sync_(true, false) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    memory_usage_thread_.Start();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    memory_usage_thread_.Stop();
+  }
+
+  void UseMemoryHelper() {
+    size_t size = 1024;
+    const scoped_ptr<DiscardableMemory> discardable(
+        DiscardableMemory::CreateLockedMemory(size));
+    EXPECT_TRUE(IsRegistered(discardable.get()));
+    EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get()));
+    discardable->Unlock();
+  }
+
+  void SignalHelper() {
+    thread_sync_.Signal();
+  }
+
+  Thread memory_usage_thread_;
+  WaitableEvent thread_sync_;
+};
+
+TEST_F(ThreadedDiscardableMemoryProviderTest, UseMemoryOnThread) {
+  memory_usage_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      Bind(&ThreadedDiscardableMemoryProviderTest::UseMemoryHelper,
+           Unretained(this)));
+  memory_usage_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      Bind(&ThreadedDiscardableMemoryProviderTest::SignalHelper,
+           Unretained(this)));
+  thread_sync_.Wait();
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory_unittest.cc b/base/memory/discardable_memory_unittest.cc
index 2c5b40c..eb730f1 100644
--- a/base/memory/discardable_memory_unittest.cc
+++ b/base/memory/discardable_memory_unittest.cc
@@ -7,13 +7,22 @@
 
 namespace base {
 
-#if defined(OS_ANDROID) || defined(OS_MACOSX)
 const size_t kSize = 1024;
 
+TEST(DiscardableMemoryTest, SupportedNatively) {
+#if defined(DISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY)
+  ASSERT_TRUE(DiscardableMemory::SupportedNatively());
+#else
+  // If we ever have a platform that decides at runtime if it can support
+  // discardable memory natively, then we'll have to add a 'never supported
+  // natively' define for this case. At present, if it's not always supported
+  // natively, it's never supported.
+  ASSERT_FALSE(DiscardableMemory::SupportedNatively());
+#endif
+}
+
 // Test Lock() and Unlock() functionalities.
 TEST(DiscardableMemoryTest, LockAndUnLock) {
-  ASSERT_TRUE(DiscardableMemory::Supported());
-
   const scoped_ptr<DiscardableMemory> memory(
       DiscardableMemory::CreateLockedMemory(kSize));
   ASSERT_TRUE(memory);
@@ -32,17 +41,14 @@
 
 // Test delete a discardable memory while it is locked.
 TEST(DiscardableMemoryTest, DeleteWhileLocked) {
-  ASSERT_TRUE(DiscardableMemory::Supported());
-
   const scoped_ptr<DiscardableMemory> memory(
       DiscardableMemory::CreateLockedMemory(kSize));
   ASSERT_TRUE(memory);
 }
 
-#if defined(OS_MACOSX)
+#if !defined(OS_ANDROID)
 // Test forced purging.
 TEST(DiscardableMemoryTest, Purge) {
-  ASSERT_TRUE(DiscardableMemory::Supported());
   ASSERT_TRUE(DiscardableMemory::PurgeForTestingSupported());
 
   const scoped_ptr<DiscardableMemory> memory(
@@ -53,7 +59,7 @@
   DiscardableMemory::PurgeForTesting();
   EXPECT_EQ(DISCARDABLE_MEMORY_PURGED, memory->Lock());
 }
-#endif  // OS_MACOSX
+#endif  // !OS_ANDROID
 
 #if !defined(NDEBUG) && !defined(OS_ANDROID)
 // Death tests are not supported with Android APKs.
@@ -62,10 +68,9 @@
       DiscardableMemory::CreateLockedMemory(kSize));
   ASSERT_TRUE(memory);
   memory->Unlock();
-  ASSERT_DEATH({ *static_cast<int*>(memory->Memory()) = 0xdeadbeef; }, ".*");
+  ASSERT_DEATH_IF_SUPPORTED(
+      { *static_cast<int*>(memory->Memory()) = 0xdeadbeef; }, ".*");
 }
 #endif
 
-#endif  // OS_*
-
 }
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index 42e0b04..d27ebc1 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -60,8 +60,8 @@
       lock_(NULL) {
   ::DuplicateHandle(process, handle,
                     GetCurrentProcess(), &mapped_file_,
-                    STANDARD_RIGHTS_REQUIRED |
-                    (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS),
+                    read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                        FILE_MAP_WRITE,
                     FALSE, 0);
 }
 
@@ -147,8 +147,8 @@
   name_ = ASCIIToWide(name);
   read_only_ = read_only;
   mapped_file_ = OpenFileMapping(
-      read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false,
-      name_.empty() ? NULL : name_.c_str());
+      read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
+      false, name_.empty() ? NULL : name_.c_str());
   if (mapped_file_ != NULL) {
     // Note: size_ is not set in this case.
     return true;
@@ -164,7 +164,8 @@
     return false;
 
   memory_ = MapViewOfFile(mapped_file_,
-                          read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+                          read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                              FILE_MAP_WRITE,
                           static_cast<uint64>(offset) >> 32,
                           static_cast<DWORD>(offset),
                           bytes);
@@ -190,7 +191,7 @@
                                         SharedMemoryHandle *new_handle,
                                         bool close_self) {
   *new_handle = 0;
-  DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
+  DWORD access = FILE_MAP_READ;
   DWORD options = 0;
   HANDLE mapped_file = mapped_file_;
   HANDLE result;
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index d500a29..b99f314 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -72,25 +72,6 @@
 //------------------------------------------------------------------------------
 // FieldTrial methods and members.
 
-FieldTrial::FieldTrial(const std::string& trial_name,
-                       const Probability total_probability,
-                       const std::string& default_group_name,
-                       double entropy_value)
-    : trial_name_(trial_name),
-      divisor_(total_probability),
-      default_group_name_(default_group_name),
-      random_(GetGroupBoundaryValue(total_probability, entropy_value)),
-      accumulated_group_probability_(0),
-      next_group_number_(kDefaultGroupNumber + 1),
-      group_(kNotFinalized),
-      enable_field_trial_(true),
-      forced_(false),
-      group_reported_(false) {
-  DCHECK_GT(total_probability, 0);
-  DCHECK(!trial_name_.empty());
-  DCHECK(!default_group_name_.empty());
-}
-
 FieldTrial::EntropyProvider::~EntropyProvider() {
 }
 
@@ -146,7 +127,8 @@
 
 int FieldTrial::group() {
   FinalizeGroupChoice();
-  FieldTrialList::NotifyFieldTrialGroupSelection(this);
+  if (trial_registered_)
+    FieldTrialList::NotifyFieldTrialGroupSelection(this);
   return group_;
 }
 
@@ -157,12 +139,6 @@
   return group_name_;
 }
 
-// static
-void FieldTrial::EnableBenchmarking() {
-  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
-  enable_benchmarking_ = true;
-}
-
 void FieldTrial::SetForced() {
   // We might have been forced before (e.g., by CreateFieldTrial) and it's
   // first come first served, e.g., command line switch has precedence.
@@ -174,8 +150,50 @@
   forced_ = true;
 }
 
+// static
+void FieldTrial::EnableBenchmarking() {
+  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
+  enable_benchmarking_ = true;
+}
+
+// static
+FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
+    const std::string& trial_name,
+    Probability total_probability,
+    const std::string& default_group_name,
+    double entropy_value) {
+  return new FieldTrial(trial_name, total_probability, default_group_name,
+                        entropy_value);
+}
+
+FieldTrial::FieldTrial(const std::string& trial_name,
+                       const Probability total_probability,
+                       const std::string& default_group_name,
+                       double entropy_value)
+    : trial_name_(trial_name),
+      divisor_(total_probability),
+      default_group_name_(default_group_name),
+      random_(GetGroupBoundaryValue(total_probability, entropy_value)),
+      accumulated_group_probability_(0),
+      next_group_number_(kDefaultGroupNumber + 1),
+      group_(kNotFinalized),
+      enable_field_trial_(true),
+      forced_(false),
+      group_reported_(false),
+      trial_registered_(false) {
+  DCHECK_GT(total_probability, 0);
+  DCHECK(!trial_name_.empty());
+  DCHECK(!default_group_name_.empty());
+}
+
 FieldTrial::~FieldTrial() {}
 
+void FieldTrial::SetTrialRegistered() {
+  DCHECK_EQ(kNotFinalized, group_);
+  DCHECK(!trial_registered_);
+  trial_registered_ = true;
+}
+
 void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
   group_ = number;
   if (group_name.empty())
@@ -434,9 +452,9 @@
   }
   const int kTotalProbability = 100;
   field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
+  FieldTrialList::Register(field_trial);
   // Force the trial, which will also finalize the group choice.
   field_trial->SetForced();
-  FieldTrialList::Register(field_trial);
   return field_trial;
 }
 
@@ -510,6 +528,7 @@
   AutoLock auto_lock(global_->lock_);
   DCHECK(!global_->PreLockedFind(trial->trial_name()));
   trial->AddRef();
+  trial->SetTrialRegistered();
   global_->registered_[trial->trial_name()] = trial;
 }
 
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 2928935..70ce2f9 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -140,9 +140,6 @@
   // is used as the group name. This causes a winner to be chosen if none was.
   const std::string& group_name();
 
-  // Enable benchmarking sets field trials to a common setting.
-  static void EnableBenchmarking();
-
   // Set the field trial as forced, meaning that it was setup earlier than
   // the hard coded registration of the field trial to override it.
   // This allows the code that was hard coded to register the field trial to
@@ -153,6 +150,25 @@
   // be done from the UI thread.
   void SetForced();
 
+  // Enable benchmarking sets field trials to a common setting.
+  static void EnableBenchmarking();
+
+  // Creates a FieldTrial object with the specified parameters, to be used for
+  // simulation of group assignment without actually affecting global field
+  // trial state in the running process. Group assignment will be done based on
+  // |entropy_value|, which must have a range of [0, 1).
+  //
+  // Note: Using this function will not register the field trial globally in the
+  // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
+  //
+  // The ownership of the returned FieldTrial is transfered to the caller which
+  // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
+  static FieldTrial* CreateSimulatedFieldTrial(
+      const std::string& trial_name,
+      Probability total_probability,
+      const std::string& default_group_name,
+      double entropy_value);
+
  private:
   // Allow tests to access our innards for testing purposes.
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
@@ -184,7 +200,7 @@
 
   // Creates a field trial with the specified parameters. Group assignment will
   // be done based on |entropy_value|, which must have a range of [0, 1).
-  FieldTrial(const std::string& name,
+  FieldTrial(const std::string& trial_name,
              Probability total_probability,
              const std::string& default_group_name,
              double entropy_value);
@@ -193,6 +209,10 @@
   // Return the default group name of the FieldTrial.
   std::string default_group_name() const { return default_group_name_; }
 
+  // Marks this trial as having been registered with the FieldTrialList. Must be
+  // called no more than once and before any |group()| calls have occurred.
+  void SetTrialRegistered();
+
   // Sets the chosen group name and number.
   void SetGroupChoice(const std::string& group_name, int number);
 
@@ -230,6 +250,7 @@
   // Sum of the probabilities of all appended groups.
   Probability accumulated_group_probability_;
 
+  // The number that will be returned by the next AppendGroup() call.
   int next_group_number_;
 
   // The pseudo-randomly assigned group number.
@@ -251,6 +272,10 @@
   // Specifies whether the group choice has been reported to observers.
   bool group_reported_;
 
+  // Whether this trial is registered with the global FieldTrialList and thus
+  // should notify it when its group is queried.
+  bool trial_registered_;
+
   // When benchmarking is enabled, field trials all revert to the 'default'
   // group.
   static bool enable_benchmarking_;
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 10d3c3f..a77633e 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -877,4 +877,47 @@
   EXPECT_EQ("2", trial->group_name());
 }
 
+TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
+  const char kTrialName[] = "CreateSimulatedFieldTrial";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Different cases to test, e.g. default vs. non default group being chosen.
+  struct {
+    double entropy_value;
+    const char* expected_group;
+  } test_cases[] = {
+    { 0.4, "A" },
+    { 0.85, "B" },
+    { 0.95, kDefaultGroupName },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+    TestFieldTrialObserver observer;
+    scoped_refptr<FieldTrial> trial(
+       FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                             test_cases[i].entropy_value));
+    trial->AppendGroup("A", 80);
+    trial->AppendGroup("B", 10);
+    EXPECT_EQ(test_cases[i].expected_group, trial->group_name());
+
+    // Field trial shouldn't have been registered with the list.
+    EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
+    EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
+
+    // Observer shouldn't have been notified.
+    RunLoop().RunUntilIdle();
+    EXPECT_TRUE(observer.trial_name().empty());
+
+    // The trial shouldn't be in the active set of trials.
+    FieldTrial::ActiveGroups active_groups;
+    FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+    EXPECT_TRUE(active_groups.empty());
+
+    // The trial shouldn't be listed in the |StatesToString()| result.
+    std::string states;
+    FieldTrialList::StatesToString(&states);
+    EXPECT_TRUE(states.empty());
+  }
+}
+
 }  // namespace base
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index 5b46d29..5c6e2d2 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -58,20 +58,6 @@
   }
 }
 
-void DeserializeHistogramAndAddSamples(PickleIterator* iter) {
-  HistogramBase* histogram = DeserializeHistogramInfo(iter);
-  if (!histogram)
-    return;
-
-  if (histogram->flags() & base::HistogramBase::kIPCSerializationSourceFlag) {
-    DVLOG(1) << "Single process mode, histogram observed and not copied: "
-             << histogram->histogram_name();
-    return;
-  }
-  histogram->AddSamplesFromPickle(iter);
-}
-
-
 const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
 
 HistogramBase::HistogramBase(const std::string& name)
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index 4663647..4248bd8 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -6,6 +6,7 @@
 #define BASE_METRICS_HISTOGRAM_BASE_H_
 
 #include <string>
+#include <vector>
 
 #include "base/atomicops.h"
 #include "base/base_export.h"
@@ -43,10 +44,6 @@
 BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
     PickleIterator* iter);
 
-// Create or find existing histogram and add the samples from pickle.
-// Silently returns when seeing any data problem in the pickle.
-BASE_EXPORT void DeserializeHistogramAndAddSamples(PickleIterator* iter);
-
 ////////////////////////////////////////////////////////////////////////////////
 
 class BASE_EXPORT HistogramBase {
diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc
index 0e19d56..4a2963a 100644
--- a/base/metrics/histogram_base_unittest.cc
+++ b/base/metrics/histogram_base_unittest.cc
@@ -61,40 +61,6 @@
   EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags());
 }
 
-TEST_F(HistogramBaseTest, DeserializeHistogramAndAddSamples) {
-  HistogramBase* histogram = Histogram::FactoryGet(
-      "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag);
-  histogram->Add(1);
-  histogram->Add(10);
-  histogram->Add(100);
-  histogram->Add(1000);
-
-  Pickle pickle;
-  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
-  histogram->SnapshotSamples()->Serialize(&pickle);
-
-  PickleIterator iter(pickle);
-  DeserializeHistogramAndAddSamples(&iter);
-
-  // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
-  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
-  EXPECT_EQ(1, snapshot->GetCount(1));
-  EXPECT_EQ(1, snapshot->GetCount(10));
-  EXPECT_EQ(1, snapshot->GetCount(100));
-  EXPECT_EQ(1, snapshot->GetCount(1000));
-
-  // Clear kIPCSerializationSourceFlag to emulate multi-process usage.
-  histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag);
-  PickleIterator iter2(pickle);
-  DeserializeHistogramAndAddSamples(&iter2);
-
-  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
-  EXPECT_EQ(2, snapshot2->GetCount(1));
-  EXPECT_EQ(2, snapshot2->GetCount(10));
-  EXPECT_EQ(2, snapshot2->GetCount(100));
-  EXPECT_EQ(2, snapshot2->GetCount(1000));
-}
-
 TEST_F(HistogramBaseTest, DeserializeLinearHistogram) {
   HistogramBase* histogram = LinearHistogram::FactoryGet(
       "TestHistogram", 1, 1000, 10,
diff --git a/base/metrics/histogram_delta_serialization.cc b/base/metrics/histogram_delta_serialization.cc
new file mode 100644
index 0000000..924916d
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 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/metrics/histogram_delta_serialization.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/pickle.h"
+#include "base/safe_numerics.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+// Create or find existing histogram and add the samples from pickle.
+// Silently returns when seeing any data problem in the pickle.
+void DeserializeHistogramAndAddSamples(PickleIterator* iter) {
+  HistogramBase* histogram = DeserializeHistogramInfo(iter);
+  if (!histogram)
+    return;
+
+  if (histogram->flags() & HistogramBase::kIPCSerializationSourceFlag) {
+    DVLOG(1) << "Single process mode, histogram observed and not copied: "
+             << histogram->histogram_name();
+    return;
+  }
+  histogram->AddSamplesFromPickle(iter);
+}
+
+}  // namespace
+
+HistogramDeltaSerialization::HistogramDeltaSerialization(
+    const std::string& caller_name)
+    : histogram_snapshot_manager_(this),
+      serialized_deltas_(NULL) {
+  inconsistencies_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name, 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistencies_unique_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name + "Unique", 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistent_snapshot_histogram_ =
+      Histogram::FactoryGet(
+          "Histogram.InconsistentSnapshot" + caller_name, 1, 1000000, 50,
+          HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+HistogramDeltaSerialization::~HistogramDeltaSerialization() {
+}
+
+void HistogramDeltaSerialization::PrepareAndSerializeDeltas(
+    std::vector<std::string>* serialized_deltas) {
+  serialized_deltas_ = serialized_deltas;
+  // Note: Before serializing, we set the kIPCSerializationSourceFlag for all
+  // the histograms, so that the receiving process can distinguish them from the
+  // local histograms.
+  histogram_snapshot_manager_.PrepareDeltas(
+      Histogram::kIPCSerializationSourceFlag, false);
+  serialized_deltas_ = NULL;
+}
+
+// static
+void HistogramDeltaSerialization::DeserializeAndAddSamples(
+    const std::vector<std::string>& serialized_deltas) {
+  for (std::vector<std::string>::const_iterator it = serialized_deltas.begin();
+       it != serialized_deltas.end(); ++it) {
+    Pickle pickle(it->data(), checked_numeric_cast<int>(it->size()));
+    PickleIterator iter(pickle);
+    DeserializeHistogramAndAddSamples(&iter);
+  }
+}
+
+void HistogramDeltaSerialization::RecordDelta(
+    const HistogramBase& histogram,
+    const HistogramSamples& snapshot) {
+  DCHECK_NE(0, snapshot.TotalCount());
+
+  Pickle pickle;
+  histogram.SerializeInfo(&pickle);
+  snapshot.Serialize(&pickle);
+  serialized_deltas_->push_back(
+      std::string(static_cast<const char*>(pickle.data()), pickle.size()));
+}
+
+void HistogramDeltaSerialization::InconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::UniqueInconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_unique_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
+    int amount) {
+  inconsistent_snapshot_histogram_->Add(std::abs(amount));
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_delta_serialization.h b/base/metrics/histogram_delta_serialization.h
new file mode 100644
index 0000000..ccadb12
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.h
@@ -0,0 +1,65 @@
+// Copyright 2013 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 BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+#define BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+
+namespace base {
+
+class HistogramBase;
+
+// Serializes and restores histograms deltas.
+class BASE_EXPORT HistogramDeltaSerialization : public HistogramFlattener {
+ public:
+  // |caller_name| is string used in histograms for counting inconsistencies.
+  explicit HistogramDeltaSerialization(const std::string& caller_name);
+  virtual ~HistogramDeltaSerialization();
+
+  // Computes deltas in histogram bucket counts relative to the previous call to
+  // this method. Stores the deltas in serialized form into |serialized_deltas|.
+  // If |serialized_deltas| is NULL, no data is serialized, though the next call
+  // will compute the deltas relative to this one.
+  void PrepareAndSerializeDeltas(std::vector<std::string>* serialized_deltas);
+
+  // Deserialize deltas and add samples to corresponding histograms, creating
+  // them if necessary. Silently ignores errors in |serialized_deltas|.
+  static void DeserializeAndAddSamples(
+      const std::vector<std::string>& serialized_deltas);
+
+ private:
+  // HistogramFlattener implementation.
+  virtual void RecordDelta(const HistogramBase& histogram,
+                           const HistogramSamples& snapshot) OVERRIDE;
+  virtual void InconsistencyDetected(
+      HistogramBase::Inconsistency problem) OVERRIDE;
+  virtual void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) OVERRIDE;
+  virtual void InconsistencyDetectedInLoggedCount(int amount) OVERRIDE;
+
+  // Calculates deltas in histogram counters.
+  HistogramSnapshotManager histogram_snapshot_manager_;
+
+  // Output buffer for serialized deltas.
+  std::vector<std::string>* serialized_deltas_;
+
+  // Histograms to count inconsistencies in snapshots.
+  HistogramBase* inconsistencies_histogram_;
+  HistogramBase* inconsistencies_unique_histogram_;
+  HistogramBase* inconsistent_snapshot_histogram_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramDeltaSerialization);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
diff --git a/base/metrics/histogram_delta_serialization_unittest.cc b/base/metrics/histogram_delta_serialization_unittest.cc
new file mode 100644
index 0000000..b53520c
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 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/metrics/histogram_delta_serialization.h"
+
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(HistogramDeltaSerializationTest, DeserializeHistogramAndAddSamples) {
+  StatisticsRecorder statistic_recorder;
+  HistogramDeltaSerialization serializer("HistogramDeltaSerializationTest");
+  std::vector<std::string> deltas;
+  // Nothing was changed yet.
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_TRUE(deltas.empty());
+
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag);
+  histogram->Add(1);
+  histogram->Add(10);
+  histogram->Add(100);
+  histogram->Add(1000);
+
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_FALSE(deltas.empty());
+
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot->GetCount(1));
+  EXPECT_EQ(1, snapshot->GetCount(10));
+  EXPECT_EQ(1, snapshot->GetCount(100));
+  EXPECT_EQ(1, snapshot->GetCount(1000));
+
+  // Clear kIPCSerializationSourceFlag to emulate multi-process usage.
+  histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag);
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(2, snapshot2->GetCount(1));
+  EXPECT_EQ(2, snapshot2->GetCount(10));
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(2, snapshot2->GetCount(1000));
+}
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 9a55225..0fdfb76 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -85,6 +85,8 @@
   friend class HistogramTest;
   friend class SparseHistogramTest;
   friend class StatisticsRecorderTest;
+  FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
+                           DeserializeHistogramAndAddSamples);
 
   // The constructor just initializes static members. Usually client code should
   // use Initialize to do this. But in test code, you can friend this class and
diff --git a/base/pickle.cc b/base/pickle.cc
index af3191b..c88503c 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -153,8 +153,8 @@
 Pickle::Pickle()
     : header_(NULL),
       header_size_(sizeof(Header)),
-      capacity_(0),
-      variable_buffer_offset_(0) {
+      capacity_after_header_(0),
+      write_offset_(0) {
   Resize(kPayloadUnit);
   header_->payload_size = 0;
 }
@@ -162,23 +162,23 @@
 Pickle::Pickle(int header_size)
     : header_(NULL),
       header_size_(AlignInt(header_size, sizeof(uint32))),
-      capacity_(0),
-      variable_buffer_offset_(0) {
+      capacity_after_header_(0),
+      write_offset_(0) {
   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
   DCHECK_LE(header_size, kPayloadUnit);
   Resize(kPayloadUnit);
   header_->payload_size = 0;
 }
 
-Pickle::Pickle(const char* data, int data_len)
+Pickle::Pickle(const char* data, size_t data_len)
     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
       header_size_(0),
-      capacity_(kCapacityReadOnly),
-      variable_buffer_offset_(0) {
-  if (data_len >= static_cast<int>(sizeof(Header)))
+      capacity_after_header_(kCapacityReadOnly),
+      write_offset_(0) {
+  if (data_len >= sizeof(Header))
     header_size_ = data_len - header_->payload_size;
 
-  if (header_size_ > static_cast<unsigned int>(data_len))
+  if (header_size_ > data_len)
     header_size_ = 0;
 
   if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
@@ -192,16 +192,15 @@
 Pickle::Pickle(const Pickle& other)
     : header_(NULL),
       header_size_(other.header_size_),
-      capacity_(0),
-      variable_buffer_offset_(other.variable_buffer_offset_) {
+      capacity_after_header_(0),
+      write_offset_(other.write_offset_) {
   size_t payload_size = header_size_ + other.header_->payload_size;
-  bool resized = Resize(payload_size);
-  CHECK(resized);  // Realloc failed.
+  Resize(payload_size);
   memcpy(header_, other.header_, payload_size);
 }
 
 Pickle::~Pickle() {
-  if (capacity_ != kCapacityReadOnly)
+  if (capacity_after_header_ != kCapacityReadOnly)
     free(header_);
 }
 
@@ -210,20 +209,19 @@
     NOTREACHED();
     return *this;
   }
-  if (capacity_ == kCapacityReadOnly) {
+  if (capacity_after_header_ == kCapacityReadOnly) {
     header_ = NULL;
-    capacity_ = 0;
+    capacity_after_header_ = 0;
   }
   if (header_size_ != other.header_size_) {
     free(header_);
     header_ = NULL;
     header_size_ = other.header_size_;
   }
-  bool resized = Resize(other.header_size_ + other.header_->payload_size);
-  CHECK(resized);  // Realloc failed.
+  Resize(other.header_->payload_size);
   memcpy(header_, other.header_,
          other.header_size_ + other.header_->payload_size);
-  variable_buffer_offset_ = other.variable_buffer_offset_;
+  write_offset_ = other.write_offset_;
   return *this;
 }
 
@@ -254,91 +252,31 @@
   return length >= 0 && WriteInt(length) && WriteBytes(data, length);
 }
 
-bool Pickle::WriteBytes(const void* data, int data_len) {
-  DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly";
-
-  char* dest = BeginWrite(data_len);
-  if (!dest)
-    return false;
-
-  memcpy(dest, data, data_len);
-
-  EndWrite(dest, data_len);
+bool Pickle::WriteBytes(const void* data, int length) {
+  WriteBytesCommon(data, length);
   return true;
 }
 
-char* Pickle::BeginWriteData(int length) {
-  DCHECK_EQ(variable_buffer_offset_, 0U) <<
-    "There can only be one variable buffer in a Pickle";
-
-  if (length < 0 || !WriteInt(length))
-    return NULL;
-
-  char *data_ptr = BeginWrite(length);
-  if (!data_ptr)
-    return NULL;
-
-  variable_buffer_offset_ =
-      data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
-
-  // EndWrite doesn't necessarily have to be called after the write operation,
-  // so we call it here to pad out what the caller will eventually write.
-  EndWrite(data_ptr, length);
-  return data_ptr;
-}
-
-void Pickle::TrimWriteData(int new_length) {
-  DCHECK_NE(variable_buffer_offset_, 0U);
-
-  // Fetch the the variable buffer size
-  int* cur_length = reinterpret_cast<int*>(
-      reinterpret_cast<char*>(header_) + variable_buffer_offset_);
-
-  if (new_length < 0 || new_length > *cur_length) {
-    NOTREACHED() << "Invalid length in TrimWriteData.";
-    return;
-  }
-
-  // Update the payload size and variable buffer size
-  header_->payload_size -= (*cur_length - new_length);
-  *cur_length = new_length;
-}
-
-char* Pickle::BeginWrite(size_t length) {
-  // write at a uint32-aligned offset from the beginning of the header
-  size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
-
-  size_t new_size = offset + length;
-  size_t needed_size = header_size_ + new_size;
-  if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
-    return NULL;
-
+void Pickle::Reserve(size_t length) {
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
 #ifdef ARCH_CPU_64_BITS
-  DCHECK_LE(length, kuint32max);
+  DCHECK_LE(data_len, kuint32max);
 #endif
-
-  header_->payload_size = static_cast<uint32>(new_size);
-  return mutable_payload() + offset;
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_)
+    Resize(capacity_after_header_ * 2 + new_size);
 }
 
-void Pickle::EndWrite(char* dest, int length) {
-  // Zero-pad to keep tools like valgrind from complaining about uninitialized
-  // memory.
-  if (length % sizeof(uint32))
-    memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
-}
-
-bool Pickle::Resize(size_t new_capacity) {
+void Pickle::Resize(size_t new_capacity) {
   new_capacity = AlignInt(new_capacity, kPayloadUnit);
 
-  CHECK_NE(capacity_, kCapacityReadOnly);
-  void* p = realloc(header_, new_capacity);
-  if (!p)
-    return false;
-
+  CHECK_NE(capacity_after_header_, kCapacityReadOnly);
+  void* p = realloc(header_, header_size_ + new_capacity);
+  CHECK(p);
   header_ = reinterpret_cast<Header*>(p);
-  capacity_ = new_capacity;
-  return true;
+  capacity_after_header_ = new_capacity;
 }
 
 // static
@@ -359,3 +297,32 @@
 
   return (payload_end > end) ? NULL : payload_end;
 }
+
+template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
+  WriteBytesCommon(data, length);
+}
+
+template void Pickle::WriteBytesStatic<2>(const void* data);
+template void Pickle::WriteBytesStatic<4>(const void* data);
+template void Pickle::WriteBytesStatic<8>(const void* data);
+
+inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+  DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+      << "oops: pickle is readonly";
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, kuint32max);
+#endif
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_) {
+    Resize(std::max(capacity_after_header_ * 2, new_size));
+  }
+
+  char* write = mutable_payload() + write_offset_;
+  memcpy(write, data, length);
+  memset(write + length, 0, data_len - length);
+  header_->payload_size = static_cast<uint32>(write_offset_ + length);
+  write_offset_ = new_size;
+}
diff --git a/base/pickle.h b/base/pickle.h
index cb9bab9..952ef0d 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -114,7 +114,7 @@
   // instead the data is merely referenced by this Pickle.  Only const methods
   // should be used on the Pickle when initialized this way.  The header
   // padding size is deduced from the data length.
-  Pickle(const char* data, int data_len);
+  Pickle(const char* data, size_t data_len);
 
   // Initializes a Pickle as a deep copy of another Pickle.
   Pickle(const Pickle& other);
@@ -216,7 +216,7 @@
     return WriteInt(value ? 1 : 0);
   }
   bool WriteInt(int value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   // WARNING: DO NOT USE THIS METHOD IF PICKLES ARE PERSISTED IN ANY WAY.
   // It will write whatever a "long" is on this architecture. On 32-bit
@@ -224,22 +224,22 @@
   // pickles are still around after upgrading to 64-bit, or if they are copied
   // between dissimilar systems, YOUR PICKLES WILL HAVE GONE BAD.
   bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteUInt16(uint16 value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteUInt32(uint32 value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteInt64(int64 value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteUInt64(uint64 value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteFloat(float value) {
-    return WriteBytes(&value, sizeof(value));
+    return WritePOD(value);
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
@@ -247,31 +247,15 @@
   // "Data" is a blob with a length. When you read it out you will be given the
   // length. See also WriteBytes.
   bool WriteData(const char* data, int length);
-  // "Bytes" is a blob with no length. The caller must specify the lenght both
+  // "Bytes" is a blob with no length. The caller must specify the length both
   // when reading and writing. It is normally used to serialize PoD types of a
   // known size. See also WriteData.
-  bool WriteBytes(const void* data, int data_len);
+  bool WriteBytes(const void* data, int length);
 
-  // Same as WriteData, but allows the caller to write directly into the
-  // Pickle. This saves a copy in cases where the data is not already
-  // available in a buffer. The caller should take care to not write more
-  // than the length it declares it will. Use ReadData to get the data.
-  // Returns NULL on failure.
-  //
-  // The returned pointer will only be valid until the next write operation
-  // on this Pickle.
-  char* BeginWriteData(int length);
-
-  // For Pickles which contain variable length buffers (e.g. those created
-  // with BeginWriteData), the Pickle can
-  // be 'trimmed' if the amount of data required is less than originally
-  // requested.  For example, you may have created a buffer with 10K of data,
-  // but decided to only fill 10 bytes of that data.  Use this function
-  // to trim the buffer so that we don't send 9990 bytes of unused data.
-  // You cannot increase the size of the variable buffer; only shrink it.
-  // This function assumes that the length of the variable buffer has
-  // not been changed.
-  void TrimWriteData(int length);
+  // Reserves space for upcoming writes when multiple writes will be made and
+  // their sizes are computed in advance. It can be significantly faster to call
+  // Reserve() before calling WriteFoo() multiple times.
+  void Reserve(size_t additional_capacity);
 
   // Payload follows after allocation of Header (header size is customizable).
   struct Header {
@@ -311,26 +295,13 @@
     return reinterpret_cast<char*>(header_) + header_size_;
   }
 
-  size_t capacity() const {
-    return capacity_;
+  size_t capacity_after_header() const {
+    return capacity_after_header_;
   }
 
-  // Resizes the buffer for use when writing the specified amount of data. The
-  // location that the data should be written at is returned, or NULL if there
-  // was an error. Call EndWrite with the returned offset and the given length
-  // to pad out for the next write.
-  char* BeginWrite(size_t length);
-
-  // Completes the write operation by padding the data with NULL bytes until it
-  // is padded. Should be paired with BeginWrite, but it does not necessarily
-  // have to be called after the data is written.
-  void EndWrite(char* dest, int length);
-
-  // Resize the capacity, note that the input value should include the size of
-  // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
-  // A realloc() failure will cause a Resize failure... and caller should check
-  // the return result for true (i.e., successful resizing).
-  bool Resize(size_t new_capacity);
+  // Resize the capacity, note that the input value should not include the size
+  // of the header.
+  void Resize(size_t new_capacity);
 
   // Aligns 'i' by rounding it up to the next multiple of 'alignment'
   static size_t AlignInt(size_t i, int alignment) {
@@ -351,9 +322,22 @@
 
   Header* header_;
   size_t header_size_;  // Supports extra data between header and payload.
-  // Allocation size of payload (or -1 if allocation is const).
-  size_t capacity_;
-  size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
+  // Allocation size of payload (or -1 if allocation is const). Note: this
+  // doesn't count the header.
+  size_t capacity_after_header_;
+  // The offset at which we will write the next field. Note: this doesn't count
+  // the header.
+  size_t write_offset_;
+
+  // Just like WriteBytes, but with a compile-time size, for performance.
+  template<size_t length> void WriteBytesStatic(const void* data);
+
+  // Writes a POD by copying its bytes.
+  template <typename T> bool WritePOD(const T& data) {
+    WriteBytesStatic<sizeof(data)>(&data);
+    return true;
+  }
+  inline void WriteBytesCommon(const void* data, size_t length);
 
   FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
   FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index cc384c7..9dd0091 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -58,10 +58,6 @@
   EXPECT_EQ(testdatalen, outdatalen);
   EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
 
-  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
-  EXPECT_EQ(testdatalen, outdatalen);
-  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
-
   // reads past the end should fail
   EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
 }
@@ -79,14 +75,6 @@
   EXPECT_TRUE(pickle.WriteUInt16(testuint16));
   EXPECT_TRUE(pickle.WriteFloat(testfloat));
   EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
-
-  // Over allocate BeginWriteData so we can test TrimWriteData.
-  char* dest = pickle.BeginWriteData(testdatalen + 100);
-  EXPECT_TRUE(dest);
-  memcpy(dest, testdata, testdatalen);
-
-  pickle.TrimWriteData(testdatalen);
-
   VerifyResult(pickle);
 
   // test copy constructor
@@ -229,19 +217,19 @@
   size_t cur_payload = payload_size_after_header;
 
   // note: we assume 'unit' is a power of 2
-  EXPECT_EQ(unit, pickle.capacity());
+  EXPECT_EQ(unit, pickle.capacity_after_header());
   EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
 
   // fill out a full page (noting data header)
   pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
   cur_payload += unit;
-  EXPECT_EQ(unit * 2, pickle.capacity());
+  EXPECT_EQ(unit * 2, pickle.capacity_after_header());
   EXPECT_EQ(cur_payload, pickle.payload_size());
 
   // one more byte should double the capacity
   pickle.WriteData(data_ptr, 1);
   cur_payload += 5;
-  EXPECT_EQ(unit * 4, pickle.capacity());
+  EXPECT_EQ(unit * 4, pickle.capacity_after_header());
   EXPECT_EQ(cur_payload, pickle.payload_size());
 }
 
diff --git a/base/platform_file.h b/base/platform_file.h
index 6a0e161..62b5c35 100644
--- a/base/platform_file.h
+++ b/base/platform_file.h
@@ -122,7 +122,7 @@
 #if defined(OS_WIN)
 typedef HANDLE PlatformFile;
 const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
-PlatformFileError LastErrorToPlatformFileError(DWORD saved_errno);
+BASE_EXPORT PlatformFileError LastErrorToPlatformFileError(DWORD last_error);
 #elif defined(OS_POSIX)
 typedef int PlatformFile;
 const PlatformFile kInvalidPlatformFileValue = -1;
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc
new file mode 100644
index 0000000..c86b163
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.cc
@@ -0,0 +1,36 @@
+// Copyright 2013 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/prefs/scoped_user_pref_update.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_service.h"
+
+namespace subtle {
+
+ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
+                                                   const char* path)
+    : service_(service),
+      path_(path),
+      value_(NULL) {}
+
+ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
+  Notify();
+}
+
+Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
+  if (!value_)
+    value_ = service_->GetMutableUserPref(path_.c_str(), type);
+  return value_;
+}
+
+void ScopedUserPrefUpdateBase::Notify() {
+  if (value_) {
+    service_->ReportUserPrefChanged(path_);
+    value_ = NULL;
+  }
+}
+
+}  // namespace subtle
diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h
new file mode 100644
index 0000000..82d6739
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.h
@@ -0,0 +1,108 @@
+// Copyright 2013 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.
+//
+// A helper class that assists preferences in firing notifications when lists
+// or dictionaries are changed.
+
+#ifndef BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+#define BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_service.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace subtle {
+
+// Base class for ScopedUserPrefUpdateTemplate that contains the parts
+// that do not depend on ScopedUserPrefUpdateTemplate's template parameter.
+//
+// We need this base class mostly for making it a friend of PrefService
+// and getting access to PrefService::GetMutableUserPref and
+// PrefService::ReportUserPrefChanged.
+class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
+ protected:
+  ScopedUserPrefUpdateBase(PrefService* service, const char* path);
+
+  // Calls Notify().
+  ~ScopedUserPrefUpdateBase();
+
+  // Sets |value_| to |service_|->GetMutableUserPref and returns it.
+  base::Value* GetValueOfType(base::Value::Type type);
+
+ private:
+  // If |value_| is not null, triggers a notification of PrefObservers and
+  // resets |value_|.
+  void Notify();
+
+  // Weak pointer.
+  PrefService* service_;
+  // Path of the preference being updated.
+  std::string path_;
+  // Cache of value from user pref store (set between Get() and Notify() calls).
+  base::Value* value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase);
+};
+
+}  // namespace subtle
+
+// Class to support modifications to DictionaryValues and ListValues while
+// guaranteeing that PrefObservers are notified of changed values.
+//
+// This class may only be used on the UI thread as it requires access to the
+// PrefService.
+template <typename T, base::Value::Type type_enum_value>
+class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
+ public:
+  ScopedUserPrefUpdate(PrefService* service, const char* path)
+      : ScopedUserPrefUpdateBase(service, path) {}
+
+  // Triggers an update notification if Get() was called.
+  virtual ~ScopedUserPrefUpdate() {}
+
+  // Returns a mutable |T| instance that
+  // - is already in the user pref store, or
+  // - is (silently) created and written to the user pref store if none existed
+  //   before.
+  //
+  // Calling Get() implies that an update notification is necessary at
+  // destruction time.
+  //
+  // The ownership of the return value remains with the user pref store.
+  // Virtual so it can be overriden in subclasses that transform the value
+  // before returning it (for example to return a subelement of a dictionary).
+  virtual T* Get() {
+    return static_cast<T*>(GetValueOfType(type_enum_value));
+  }
+
+  T& operator*() {
+    return *Get();
+  }
+
+  T* operator->() {
+    return Get();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
+};
+
+typedef ScopedUserPrefUpdate<base::DictionaryValue,
+                             base::Value::TYPE_DICTIONARY>
+    DictionaryPrefUpdate;
+typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
+    ListPrefUpdate;
+
+#endif  // BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/base/prefs/scoped_user_pref_update_unittest.cc b/base/prefs/scoped_user_pref_update_unittest.cc
new file mode 100644
index 0000000..505526c
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2013 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/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+class ScopedUserPrefUpdateTest : public testing::Test {
+ public:
+  ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
+  virtual ~ScopedUserPrefUpdateTest() {}
+
+ protected:
+  virtual void SetUp() {
+    prefs_.registry()->RegisterDictionaryPref(kPref);
+    registrar_.Init(&prefs_);
+    registrar_.Add(kPref, observer_.GetCallback());
+  }
+
+  static const char kPref[];
+  static const char kKey[];
+  static const char kValue[];
+
+  TestingPrefServiceSimple prefs_;
+  MockPrefChangeCallback observer_;
+  PrefChangeRegistrar registrar_;
+};
+
+const char ScopedUserPrefUpdateTest::kPref[] = "name";
+const char ScopedUserPrefUpdateTest::kKey[] = "key";
+const char ScopedUserPrefUpdateTest::kValue[] = "value";
+
+TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
+  // Dictionary that will be expected to be set at the end.
+  DictionaryValue expected_dictionary;
+  expected_dictionary.SetString(kKey, kValue);
+
+  {
+    EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+    DictionaryPrefUpdate update(&prefs_, kPref);
+    DictionaryValue* value = update.Get();
+    ASSERT_TRUE(value);
+    value->SetString(kKey, kValue);
+
+    // The dictionary was created for us but the creation should have happened
+    // silently without notifications.
+    Mock::VerifyAndClearExpectations(&observer_);
+
+    // Modifications happen online and are instantly visible, though.
+    const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+    ASSERT_TRUE(current_value);
+    EXPECT_TRUE(expected_dictionary.Equals(current_value));
+
+    // Now we are leaving the scope of the update so we should be notified.
+    observer_.Expect(kPref, &expected_dictionary);
+  }
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+  ASSERT_TRUE(current_value);
+  EXPECT_TRUE(expected_dictionary.Equals(current_value));
+}
+
+TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
+  const DictionaryValue* old_value = prefs_.GetDictionary(kPref);
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  {
+    DictionaryPrefUpdate update(&prefs_, kPref);
+  }
+  const DictionaryValue* new_value = prefs_.GetDictionary(kPref);
+  EXPECT_EQ(old_value, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
index 127fb46..83289b8 100644
--- a/base/process/process_metrics.cc
+++ b/base/process/process_metrics.cc
@@ -42,4 +42,12 @@
   return res.PassAs<Value>();
 }
 
+double ProcessMetrics::GetPlatformIndependentCPUUsage() {
+#if defined(OS_WIN)
+  return GetCPUUsage() * processor_count_;
+#else
+  return GetCPUUsage();
+#endif
+}
+
 }  // namespace base
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index f6b225f..81fd445 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -160,14 +160,19 @@
   // load and fragmentation.
   bool CalculateFreeMemory(FreeMBytes* free) const;
 
-  // Returns the CPU usage in percent since the last time this method was
-  // called. The first time this method is called it returns 0 and will return
-  // the actual CPU info on subsequent calls.
-  // On Windows, the CPU usage value is for all CPUs. So if you have 2 CPUs and
-  // your process is using all the cycles of 1 CPU and not the other CPU, this
-  // method returns 50.
+  // Returns the CPU usage in percent since the last time this method or
+  // GetPlatformIndependentCPUUsage() was called. The first time this method
+  // is called it returns 0 and will return the actual CPU info on subsequent
+  // calls. On Windows, the CPU usage value is for all CPUs. So if you have
+  // 2 CPUs and your process is using all the cycles of 1 CPU and not the other
+  // CPU, this method returns 50.
   double GetCPUUsage();
 
+  // Same as GetCPUUsage(), but will return consistent values on all platforms
+  // (cancelling the Windows exception mentioned above) by returning a value in
+  // the range of 0 to (100 * numCPUCores) everywhere.
+  double GetPlatformIndependentCPUUsage();
+
   // Retrieves accounting information for all I/O operations performed by the
   // process.
   // If IO information is retrieved successfully, the function returns true
diff --git a/base/security_unittest.cc b/base/security_unittest.cc
index 8f59219..1c24fad 100644
--- a/base/security_unittest.cc
+++ b/base/security_unittest.cc
@@ -147,10 +147,10 @@
 
 // The tests bellow check for overflows in new[] and calloc().
 
-#if defined(OS_IOS) || defined(OS_WIN)
-  #define DISABLE_ON_IOS_AND_WIN(function) DISABLED_##function
+#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER)
+  #define DISABLE_ON_IOS_AND_WIN_AND_TSAN(function) DISABLED_##function
 #else
-  #define DISABLE_ON_IOS_AND_WIN(function) function
+  #define DISABLE_ON_IOS_AND_WIN_AND_TSAN(function) function
 #endif
 
 // There are platforms where these tests are known to fail. We would like to
@@ -174,7 +174,7 @@
 // Test array[TooBig][X] and array[X][TooBig] allocations for int overflows.
 // IOS doesn't honor nothrow, so disable the test there.
 // Crashes on Windows Dbg builds, disable there as well.
-TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN(NewOverflow)) {
+TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN_AND_TSAN(NewOverflow)) {
   const size_t kArraySize = 4096;
   // We want something "dynamic" here, so that the compiler doesn't
   // immediately reject crazy arrays.
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
index b9412d9..e3e71be 100644
--- a/base/strings/string_number_conversions.cc
+++ b/base/strings/string_number_conversions.cc
@@ -301,6 +301,11 @@
 };
 
 template<typename ITERATOR>
+class BaseHexIteratorRangeToUIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
+};
+
+template<typename ITERATOR>
 class BaseHexIteratorRangeToInt64Traits
     : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
 };
@@ -313,6 +318,9 @@
 typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
     HexIteratorRangeToIntTraits;
 
+typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToUIntTraits;
+
 typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
     HexIteratorRangeToInt64Traits;
 
@@ -499,6 +507,11 @@
     input.begin(), input.end(), output);
 }
 
+bool HexStringToUInt(const StringPiece& input, uint32* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
 bool HexStringToInt64(const StringPiece& input, int64* output) {
   return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
     input.begin(), input.end(), output);
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
index b199bb5..6f5df4a 100644
--- a/base/strings/string_number_conversions.h
+++ b/base/strings/string_number_conversions.h
@@ -101,6 +101,12 @@
 
 // Best effort conversion, see StringToInt above for restrictions.
 // Will only successful parse hex values that will fit into |output|, i.e.
+// 0x00000000 < |input| < 0xFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
 // -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
 BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
 
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
index b861964..b6e5f96 100644
--- a/base/strings/string_number_conversions_unittest.cc
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -458,6 +458,66 @@
   EXPECT_EQ(0xc0ffee, output);
 }
 
+TEST(StringNumberConversionsTest, HexStringToUInt) {
+  static const struct {
+    std::string input;
+    uint32 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 0x42, true},
+    {"-42", 0, false},
+    {"+42", 0x42, true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", 0, false},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 0x42, true},
+    {"-0x42", 0, false},
+    {"+0x42", 0x42, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", 0, false},
+    {"0xffffffff", kuint32max, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000000", 0, false},
+    {"0x8000000000000000", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000001", 0, false},
+    {"0xFFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"FFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"0x0000000000000000", 0, true},
+    {"0000000000000000", 0, true},
+    {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
+    {"0x0f", 0x0f, true},
+    {"0f", 0x0f, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    uint32 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\09";
+  std::string input_string(input, arraysize(input) - 1);
+  uint32 output;
+  EXPECT_FALSE(HexStringToUInt(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
 TEST(StringNumberConversionsTest, HexStringToInt64) {
   static const struct {
     std::string input;
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc
index ebe4c9a..f6d17e7 100644
--- a/base/sync_socket_nacl.cc
+++ b/base/sync_socket_nacl.cc
@@ -64,11 +64,11 @@
 }
 
 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
-  return Send(buffer, length);
+  return SyncSocket::Send(buffer, length);
 }
 
 bool CancelableSyncSocket::Shutdown() {
-  return Close();
+  return SyncSocket::Close();
 }
 
 // static
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java b/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java
deleted file mode 100644
index 1c82e20..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2013 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.base.test.util;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for specifying that the test should only be run on phones.
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface PhoneOnly {
-
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
new file mode 100644
index 0000000..bf7c741
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation for listing restrictions for a test method. For example, if a test method is only
+ * applicable on a phone with small memory:
+ *     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_SMALL_MEMORY})
+ * Test classes are free to define restrictions and enforce them using reflection at runtime.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Restriction {
+    /** Specifies the test is only valid on phone form factors. */
+    public static final String RESTRICTION_TYPE_PHONE = "Phone";
+
+    /** Specifies the test is only valid on tablet form factors. */
+    public static final String RESTRICTION_TYPE_TABLET = "Tablet";
+
+    /** Specifies the test is only valid on devices with a small amount of memory. */
+    public static final String RESTRICTION_TYPE_SMALL_MEMORY = "Small_Memory";
+
+    /**
+     * @return A list of restrictions.
+     */
+    public String[] value();
+}
\ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java b/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java
deleted file mode 100644
index 36cdf81..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2013 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.base.test.util;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for specifying that the test should only be run on tablets.
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface TabletOnly {
-
-}
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
index 7fddc85..bcba363 100644
--- a/base/test/gtest_xml_util.cc
+++ b/base/test/gtest_xml_util.cc
@@ -139,10 +139,14 @@
           // This is our custom extension that helps recognize which test was
           // running when the test binary crashed.
           TestResult result;
-          if (!xml_reader.NodeAttribute("classname", &result.test_case_name))
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
             return false;
-          if (!xml_reader.NodeAttribute("name", &result.test_name))
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
             return false;
+          result.full_name = test_case_name + "." + test_name;
 
           result.elapsed_time = TimeDelta();
 
@@ -161,10 +165,14 @@
             break;
 
           TestResult result;
-          if (!xml_reader.NodeAttribute("classname", &result.test_case_name))
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
             return false;
-          if (!xml_reader.NodeAttribute("name", &result.test_name))
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
             return false;
+          result.full_name = test_case_name + "." + test_name;
 
           std::string test_time_str;
           if (!xml_reader.NodeAttribute("time", &test_time_str))
@@ -176,8 +184,7 @@
           result.status = TestResult::TEST_SUCCESS;
 
           if (!results->empty() &&
-              results->at(results->size() - 1).GetFullName() ==
-                  result.GetFullName() &&
+              results->at(results->size() - 1).full_name == result.full_name &&
               results->at(results->size() - 1).status ==
                   TestResult::TEST_CRASH) {
             // Erase the fail-safe "crashed" result - now we know the test did
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 21952a7..1b2e79a 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -210,9 +210,14 @@
       test_started_count_(0),
       test_finished_count_(0),
       test_success_count_(0),
+      retry_count_(0),
+      retry_limit_(3),  // TODO(phajdan.jr): Make a flag control this.
       run_result_(true) {
 }
 
+TestLauncher::~TestLauncher() {
+}
+
 bool TestLauncher::Run(int argc, char** argv) {
   if (!Init())
     return false;
@@ -261,6 +266,126 @@
   return run_result_;
 }
 
+void TestLauncher::OnTestFinished(const TestResult& result) {
+  ++test_finished_count_;
+
+  bool print_snippet = false;
+  std::string print_test_stdio("auto");
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherPrintTestStdio)) {
+    print_test_stdio = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTestLauncherPrintTestStdio);
+  }
+  if (print_test_stdio == "auto") {
+    print_snippet = (result.status != TestResult::TEST_SUCCESS);
+  } else if (print_test_stdio == "always") {
+    print_snippet = true;
+  } else if (print_test_stdio == "never") {
+    print_snippet = false;
+  } else {
+    LOG(WARNING) << "Invalid value of " << switches::kTestLauncherPrintTestStdio
+                 << ": " << print_test_stdio;
+  }
+  if (print_snippet) {
+    fprintf(stdout, "%s", result.output_snippet.c_str());
+    fflush(stdout);
+  }
+
+  if (result.status == TestResult::TEST_SUCCESS) {
+    ++test_success_count_;
+  } else {
+    tests_to_retry_.insert(result.full_name);
+  }
+
+  results_tracker_.AddTestResult(result);
+
+  // TODO(phajdan.jr): Align counter (padding).
+  std::string status_line(
+      StringPrintf("[%" PRIuS "/%" PRIuS "] %s ",
+                   test_finished_count_,
+                   test_started_count_,
+                   result.full_name.c_str()));
+  if (result.completed()) {
+    status_line.append(StringPrintf("(%" PRId64 " ms)",
+                                    result.elapsed_time.InMilliseconds()));
+  } else if (result.status == TestResult::TEST_TIMEOUT) {
+    status_line.append("(TIMED OUT)");
+  } else if (result.status == TestResult::TEST_CRASH) {
+    status_line.append("(CRASHED)");
+  } else if (result.status == TestResult::TEST_SKIPPED) {
+    status_line.append("(SKIPPED)");
+  } else if (result.status == TestResult::TEST_UNKNOWN) {
+    status_line.append("(UNKNOWN)");
+  } else {
+    // Fail very loudly so it's not ignored.
+    CHECK(false) << "Unhandled test result status: " << result.status;
+  }
+  fprintf(stdout, "%s\n", status_line.c_str());
+  fflush(stdout);
+
+  if (test_finished_count_ == test_started_count_) {
+    if (!tests_to_retry_.empty() && retry_count_ < retry_limit_) {
+      retry_count_++;
+
+      std::vector<std::string> test_names(tests_to_retry_.begin(),
+                                          tests_to_retry_.end());
+
+      tests_to_retry_.clear();
+
+      size_t retry_started_count =
+          launcher_delegate_->RetryTests(this, test_names);
+      if (retry_started_count == 0) {
+        // Signal failure, but continue to run all requested test iterations.
+        // With the summary of all iterations at the end this is a good default.
+        run_result_ = false;
+
+        // The current iteration is done.
+        fprintf(stdout, "%" PRIuS " test%s run\n",
+                test_finished_count_,
+                test_finished_count_ > 1 ? "s" : "");
+        fflush(stdout);
+
+        results_tracker_.PrintSummaryOfCurrentIteration();
+
+        // Kick off the next iteration.
+        MessageLoop::current()->PostTask(
+            FROM_HERE,
+            Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+      } else {
+        fprintf(stdout, "Retrying %" PRIuS " test%s (retry #%" PRIuS ")\n",
+                retry_started_count,
+                retry_started_count > 1 ? "s" : "",
+                retry_count_);
+        fflush(stdout);
+
+        test_started_count_ += retry_started_count;
+      }
+    } else {
+      // The current iteration is done.
+      fprintf(stdout, "%" PRIuS " test%s run\n",
+              test_finished_count_,
+              test_finished_count_ > 1 ? "s" : "");
+      fflush(stdout);
+
+      results_tracker_.PrintSummaryOfCurrentIteration();
+
+      // When we retry tests, success is determined by having nothing more
+      // to retry (everything eventually passed), as opposed to having
+      // no failures at all.
+      if (!tests_to_retry_.empty()) {
+        // Signal failure, but continue to run all requested test iterations.
+        // With the summary of all iterations at the end this is a good default.
+        run_result_ = false;
+      }
+
+      // Kick off the next iteration.
+      MessageLoop::current()->PostTask(
+          FROM_HERE,
+          Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+    }
+  }
+}
+
 bool TestLauncher::Init() {
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
 
@@ -318,6 +443,8 @@
 
   int num_runnable_tests = 0;
 
+  std::vector<std::string> test_names;
+
   for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
     const testing::TestCase* test_case = unit_test->GetTestCase(i);
     for (int j = 0; j < test_case->total_test_count(); ++j) {
@@ -349,27 +476,21 @@
       if (num_runnable_tests++ % total_shards_ != shard_index_)
         continue;
 
-      test_started_count_++;
-      MessageLoop::current()->PostTask(
-          FROM_HERE,
-          Bind(&TestLauncherDelegate::RunTest,
-               Unretained(launcher_delegate_),
-               test_case,
-               test_info,
-               Bind(&TestLauncher::OnTestFinished,
-                    Unretained(this))));
+      test_names.push_back(test_name);
     }
   }
 
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&TestLauncherDelegate::RunRemainingTests,
-           Unretained(launcher_delegate_)));
+  test_started_count_ = launcher_delegate_->RunTests(this, test_names);
 
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      Bind(&TestLauncher::OnAllTestsStarted,
-           Unretained(this)));
+  if (test_started_count_ == 0) {
+    fprintf(stdout, "0 tests run\n");
+    fflush(stdout);
+
+    // No tests have actually been started, so kick off the next iteration.
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+  }
 }
 
 void TestLauncher::RunTestIteration() {
@@ -384,6 +505,8 @@
   test_started_count_ = 0;
   test_finished_count_ = 0;
   test_success_count_ = 0;
+  retry_count_ = 0;
+  tests_to_retry_.clear();
   results_tracker_.OnTestIterationStarting();
   launcher_delegate_->OnTestIterationStarting();
 
@@ -392,88 +515,21 @@
 }
 
 void TestLauncher::OnAllTestsStarted() {
-  if (test_started_count_ == 0) {
-    fprintf(stdout, "0 tests run\n");
-    fflush(stdout);
-
-    // No tests have actually been started, so kick off the next iteration.
-    MessageLoop::current()->PostTask(
-        FROM_HERE,
-        Bind(&TestLauncher::RunTestIteration, Unretained(this)));
-  }
-}
-
-void TestLauncher::OnTestFinished(const TestResult& result) {
-  ++test_finished_count_;
-
-  if (result.status == TestResult::TEST_SUCCESS) {
-    ++test_success_count_;
-  } else {
-    fprintf(stdout, "%s", result.output_snippet.c_str());
-    fflush(stdout);
-  }
-
-  results_tracker_.AddTestResult(result);
-
-  // TODO(phajdan.jr): Align counter (padding).
-  std::string status_line(
-      StringPrintf("[%" PRIuS "/%" PRIuS "] %s ",
-                   test_finished_count_,
-                   test_started_count_,
-                   result.GetFullName().c_str()));
-  if (result.completed()) {
-    status_line.append(StringPrintf("(%" PRId64 " ms)",
-                                    result.elapsed_time.InMilliseconds()));
-  } else if (result.status == TestResult::TEST_TIMEOUT) {
-    status_line.append("(TIMED OUT)");
-  } else if (result.status == TestResult::TEST_CRASH) {
-    status_line.append("(CRASHED)");
-  } else if (result.status == TestResult::TEST_SKIPPED) {
-    status_line.append("(SKIPPED)");
-  } else if (result.status == TestResult::TEST_UNKNOWN) {
-    status_line.append("(UNKNOWN)");
-  } else {
-    // Fail very loudly so it's not ignored.
-    CHECK(false) << "Unhandled test result status: " << result.status;
-  }
-  fprintf(stdout, "%s\n", status_line.c_str());
-  fflush(stdout);
-
-  if (test_finished_count_ == test_started_count_) {
-    // The current iteration is done.
-    fprintf(stdout, "%" PRIuS " test%s run\n",
-            test_finished_count_,
-            test_finished_count_ > 1 ? "s" : "");
-    fflush(stdout);
-
-    results_tracker_.PrintSummaryOfCurrentIteration();
-
-    if (test_success_count_ != test_finished_count_) {
-      // Signal failure, but continue to run all requested test iterations.
-      // With the summary of all iterations at the end this is a good default.
-      run_result_ = false;
-    }
-
-    // Kick off the next iteration.
-    MessageLoop::current()->PostTask(
-        FROM_HERE,
-        Bind(&TestLauncher::RunTestIteration, Unretained(this)));
-  }
 }
 
 std::string GetTestOutputSnippet(const TestResult& result,
                                  const std::string& full_output) {
   size_t run_pos = full_output.find(std::string("[ RUN      ] ") +
-                                    result.GetFullName());
+                                    result.full_name);
   if (run_pos == std::string::npos)
     return std::string();
 
   size_t end_pos = full_output.find(std::string("[  FAILED  ] ") +
-                                    result.GetFullName(),
+                                    result.full_name,
                                     run_pos);
   if (end_pos == std::string::npos) {
     end_pos = full_output.find(std::string("[       OK ] ") +
-                               result.GetFullName(),
+                               result.full_name,
                                run_pos);
   }
   if (end_pos != std::string::npos) {
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
index 36b6ca7..eee9851 100644
--- a/base/test/launcher/test_launcher.h
+++ b/base/test/launcher/test_launcher.h
@@ -5,6 +5,7 @@
 #ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
 #define BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
 
+#include <set>
 #include <string>
 
 #include "base/basictypes.h"
@@ -24,6 +25,7 @@
 namespace base {
 
 struct LaunchOptions;
+class TestLauncher;
 
 // Constants for GTest command-line flags.
 extern const char kGTestFilterFlag[];
@@ -55,18 +57,21 @@
   virtual bool ShouldRunTest(const testing::TestCase* test_case,
                              const testing::TestInfo* test_info) = 0;
 
-  // Called to make the delegate run specified test. After the delegate
-  // finishes running the test (can do so asynchronously and out-of-order)
-  // it must call |callback| regardless of test success.
-  typedef base::Callback<void(const TestResult& result)> TestResultCallback;
-  virtual void RunTest(const testing::TestCase* test_case,
-                       const testing::TestInfo* test_info,
-                       const TestResultCallback& callback) = 0;
+  // Called to make the delegate run the specified tests. The delegate must
+  // return the number of actual tests it's going to run (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every run test,
+  // regardless of its success.
+  virtual size_t RunTests(TestLauncher* test_launcher,
+                          const std::vector<std::string>& test_names) = 0;
 
-  // If the delegate is running tests asynchronously, it must finish
-  // running all pending tests and call their callbacks before returning
-  // from this method.
-  virtual void RunRemainingTests() = 0;
+  // Called to make the delegate retry the specified tests. The delegate must
+  // return the number of actual tests it's going to retry (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every retried test,
+  // regardless of its success.
+  virtual size_t RetryTests(TestLauncher* test_launcher,
+                            const std::vector<std::string>& test_names) = 0;
 
  protected:
   virtual ~TestLauncherDelegate();
@@ -76,10 +81,14 @@
 class TestLauncher {
  public:
   explicit TestLauncher(TestLauncherDelegate* launcher_delegate);
+  ~TestLauncher();
 
   // Runs the launcher. Must be called at most once.
   bool Run(int argc, char** argv) WARN_UNUSED_RESULT;
 
+  // Called when a test has finished running.
+  void OnTestFinished(const TestResult& result);
+
  private:
   bool Init() WARN_UNUSED_RESULT;
 
@@ -90,8 +99,6 @@
 
   void OnAllTestsStarted();
 
-  void OnTestFinished(const TestResult& result);
-
   TestLauncherDelegate* launcher_delegate_;
 
   // Support for outer sharding, just like gtest does.
@@ -113,6 +120,15 @@
   // Number of tests successfully finished in this iteration.
   size_t test_success_count_;
 
+  // Number of retries in this iteration.
+  size_t retry_count_;
+
+  // Maximum number of retries per iteration.
+  size_t retry_limit_;
+
+  // Tests to retry in this iteration.
+  std::set<std::string> tests_to_retry_;
+
   // Result to be returned from Run.
   bool run_result_;
 
diff --git a/base/test/launcher/test_result.cc b/base/test/launcher/test_result.cc
index 706b51e..39b641e 100644
--- a/base/test/launcher/test_result.cc
+++ b/base/test/launcher/test_result.cc
@@ -35,4 +35,16 @@
   return std::string();
 }
 
+std::string TestResult::GetTestName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(dot_pos + 1);
+}
+
+std::string TestResult::GetTestCaseName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(0, dot_pos);
+}
+
 }  // namespace base
diff --git a/base/test/launcher/test_result.h b/base/test/launcher/test_result.h
index 17f0643..cbae3d2 100644
--- a/base/test/launcher/test_result.h
+++ b/base/test/launcher/test_result.h
@@ -25,11 +25,15 @@
   TestResult();
   ~TestResult();
 
-  std::string GetFullName() const { return test_case_name + "." + test_name; }
-
   // Returns the test status as string (e.g. for display).
   std::string StatusAsString() const;
 
+  // Returns the test name (e.g. "B" for "A.B").
+  std::string GetTestName() const;
+
+  // Returns the test case name (e.g. "A" for "A.B").
+  std::string GetTestCaseName() const;
+
   // Returns true if the test has completed (i.e. the test binary exited
   // normally, possibly with an exit code indicating failure, but didn't crash
   // or time out in the middle of the test).
@@ -37,11 +41,8 @@
     return status == TEST_SUCCESS || status == TEST_FAILURE;
   }
 
-  // Name of the test case (before the dot, e.g. "A" for test "A.B").
-  std::string test_case_name;
-
-  // Name of the test (after the dot, e.g. "B" for test "A.B").
-  std::string test_name;
+  // Full name of the test (e.g. "A.B").
+  std::string full_name;
 
   Status status;
 
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index fcb6db1..895f88b 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -58,10 +58,22 @@
   fprintf(out_, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
   fprintf(out_, "<testsuites name=\"AllTests\" tests=\"\" failures=\"\""
           " disabled=\"\" errors=\"\" time=\"\">\n");
+
+  // Maps test case names to test results.
+  typedef std::map<std::string, std::vector<TestResult> > TestCaseMap;
+  TestCaseMap test_case_map;
+
   for (PerIterationData::ResultsMap::iterator i =
            per_iteration_data_[iteration_].results.begin();
        i != per_iteration_data_[iteration_].results.end();
        ++i) {
+    // Use the last test result as the final one.
+    TestResult result = i->second.test_results.back();
+    test_case_map[result.GetTestCaseName()].push_back(result);
+  }
+  for (TestCaseMap::iterator i = test_case_map.begin();
+       i != test_case_map.end();
+       ++i) {
     fprintf(out_, "  <testsuite name=\"%s\" tests=\"%" PRIuS "\" failures=\"\""
             " disabled=\"\" errors=\"\" time=\"\">\n",
             i->first.c_str(), i->second.size());
@@ -69,9 +81,9 @@
       const TestResult& result = i->second[j];
       fprintf(out_, "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
               " classname=\"%s\">\n",
-              result.test_name.c_str(),
+              result.GetTestName().c_str(),
               result.elapsed_time.InSecondsF(),
-              result.test_case_name.c_str());
+              result.GetTestCaseName().c_str());
       if (result.status != TestResult::TEST_SUCCESS)
         fprintf(out_, "      <failure message=\"\" type=\"\"></failure>\n");
       fprintf(out_, "    </testcase>\n");
@@ -144,52 +156,72 @@
 void TestResultsTracker::AddTestResult(const TestResult& result) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  per_iteration_data_[iteration_].results[result.test_case_name].push_back(
-      result);
-  per_iteration_data_[iteration_].tests_by_status[result.status].push_back(
-      result.GetFullName());
+  per_iteration_data_[iteration_].results[
+      result.full_name].test_results.push_back(result);
 }
 
 void TestResultsTracker::PrintSummaryOfCurrentIteration() const {
-  PrintTestsByStatus(TestResult::TEST_FAILURE, "failed");
-  PrintTestsByStatus(TestResult::TEST_TIMEOUT, "timed out");
-  PrintTestsByStatus(TestResult::TEST_CRASH, "crashed");
-  PrintTestsByStatus(TestResult::TEST_SKIPPED, "skipped");
-  PrintTestsByStatus(TestResult::TEST_UNKNOWN, "had unknown result");
+  std::map<TestResult::Status, std::set<std::string> > tests_by_status;
+
+  for (PerIterationData::ResultsMap::const_iterator j =
+           per_iteration_data_[iteration_].results.begin();
+       j != per_iteration_data_[iteration_].results.end();
+       ++j) {
+    // Use the last test result as the final one.
+    TestResult result = j->second.test_results.back();
+    tests_by_status[result.status].insert(result.full_name);
+  }
+
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
+             "failed");
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
+             "timed out");
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
+             "crashed");
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
+             "skipped");
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
+             "had unknown result");
 }
 
 void TestResultsTracker::PrintSummaryOfAllIterations() const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  std::map<TestResult::Status, std::set<std::string> > all_tests_by_status;
+  std::map<TestResult::Status, std::set<std::string> > tests_by_status;
 
   for (int i = 0; i <= iteration_; i++) {
-    for (PerIterationData::StatusMap::const_iterator j =
-             per_iteration_data_[i].tests_by_status.begin();
-         j != per_iteration_data_[i].tests_by_status.end();
+    for (PerIterationData::ResultsMap::const_iterator j =
+             per_iteration_data_[i].results.begin();
+         j != per_iteration_data_[i].results.end();
          ++j) {
-      for (size_t k = 0; k < j->second.size(); k++)
-        all_tests_by_status[j->first].insert(j->second[k]);
+      // Use the last test result as the final one.
+      TestResult result = j->second.test_results.back();
+      tests_by_status[result.status].insert(result.full_name);
     }
   }
 
   fprintf(stdout, "Summary of all itest iterations:\n");
   fflush(stdout);
 
-  PrintTests(all_tests_by_status[TestResult::TEST_FAILURE].begin(),
-             all_tests_by_status[TestResult::TEST_FAILURE].end(),
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
              "failed");
-  PrintTests(all_tests_by_status[TestResult::TEST_TIMEOUT].begin(),
-             all_tests_by_status[TestResult::TEST_TIMEOUT].end(),
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
              "timed out");
-  PrintTests(all_tests_by_status[TestResult::TEST_CRASH].begin(),
-             all_tests_by_status[TestResult::TEST_CRASH].end(),
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
              "crashed");
-  PrintTests(all_tests_by_status[TestResult::TEST_SKIPPED].begin(),
-             all_tests_by_status[TestResult::TEST_SKIPPED].end(),
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
              "skipped");
-  PrintTests(all_tests_by_status[TestResult::TEST_UNKNOWN].begin(),
-             all_tests_by_status[TestResult::TEST_UNKNOWN].end(),
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
              "had unknown result");
 
   fprintf(stdout, "End of the summary.\n");
@@ -203,20 +235,22 @@
   summary_root->Set("per_iteration_data", per_iteration_data);
 
   for (int i = 0; i <= iteration_; i++) {
-    ListValue* current_iteration_data = new ListValue;
+    DictionaryValue* current_iteration_data = new DictionaryValue;
     per_iteration_data->Append(current_iteration_data);
 
     for (PerIterationData::ResultsMap::const_iterator j =
              per_iteration_data_[i].results.begin();
          j != per_iteration_data_[i].results.end();
          ++j) {
-      for (size_t k = 0; k < j->second.size(); k++) {
-        const TestResult& test_result = j->second[k];
+      ListValue* test_results = new ListValue;
+      current_iteration_data->SetWithoutPathExpansion(j->first, test_results);
+
+      for (size_t k = 0; k < j->second.test_results.size(); k++) {
+        const TestResult& test_result = j->second.test_results[k];
 
         DictionaryValue* test_result_value = new DictionaryValue;
-        current_iteration_data->Append(test_result_value);
+        test_results->Append(test_result_value);
 
-        test_result_value->SetString("full_name", test_result.GetFullName());
         test_result_value->SetString("status", test_result.StatusAsString());
         test_result_value->SetInteger(
             "elapsed_time_ms", test_result.elapsed_time.InMilliseconds());
@@ -230,22 +264,16 @@
   return serializer.Serialize(*summary_root);
 }
 
+TestResultsTracker::AggregateTestResult::AggregateTestResult() {
+}
+
+TestResultsTracker::AggregateTestResult::~AggregateTestResult() {
+}
+
 TestResultsTracker::PerIterationData::PerIterationData() {
 }
 
 TestResultsTracker::PerIterationData::~PerIterationData() {
 }
 
-void TestResultsTracker::PrintTestsByStatus(
-    TestResult::Status status,
-    const std::string& description) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  PerIterationData::StatusMap::const_iterator i(
-      per_iteration_data_[iteration_].tests_by_status.find(status));
-  if (i == per_iteration_data_[iteration_].tests_by_status.end())
-    return;
-  PrintTests(i->second.begin(), i->second.end(), description);
-}
-
 }  // namespace base
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
index d33c480..5743507 100644
--- a/base/test/launcher/test_results_tracker.h
+++ b/base/test/launcher/test_results_tracker.h
@@ -54,23 +54,22 @@
   bool SaveSummaryAsJSON(const FilePath& path) const WARN_UNUSED_RESULT;
 
  private:
+  struct AggregateTestResult {
+    AggregateTestResult();
+    ~AggregateTestResult();
+
+    std::vector<TestResult> test_results;
+  };
+
   struct PerIterationData {
     PerIterationData();
     ~PerIterationData();
 
-    // Test results grouped by test case name.
-    typedef std::map<std::string, std::vector<TestResult> > ResultsMap;
+    // Aggregate test results grouped by full test name.
+    typedef std::map<std::string, AggregateTestResult> ResultsMap;
     ResultsMap results;
-
-    // List of full names of failed tests.
-    typedef std::map<TestResult::Status, std::vector<std::string> > StatusMap;
-    StatusMap tests_by_status;
   };
 
-  // Prints a list of tests that finished with |status|.
-  void PrintTestsByStatus(TestResult::Status status,
-                          const std::string& description) const;
-
   ThreadChecker thread_checker_;
 
   // Store test results for each iteration.
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 151dc09..63c64c9 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -89,14 +89,10 @@
   }
 
  private:
-  struct TestLaunchInfo {
-    std::string GetFullName() const {
-      return test_case_name + "." + test_name;
-    }
-
-    std::string test_case_name;
-    std::string test_name;
-    TestResultCallback callback;
+  struct GTestCallbackState {
+    TestLauncher* test_launcher;
+    std::vector<std::string> test_names;
+    FilePath output_file;
   };
 
   virtual void OnTestIterationStarting() OVERRIDE {
@@ -119,28 +115,46 @@
     return true;
   }
 
-  virtual void RunTest(const testing::TestCase* test_case,
-                       const testing::TestInfo* test_info,
-                       const TestResultCallback& callback) OVERRIDE {
+  virtual size_t RunTests(TestLauncher* test_launcher,
+                          const std::vector<std::string>& test_names) OVERRIDE {
     DCHECK(thread_checker_.CalledOnValidThread());
 
-    TestLaunchInfo launch_info;
-    launch_info.test_case_name = test_case->name();
-    launch_info.test_name = test_info->name();
-    launch_info.callback = callback;
-    tests_.push_back(launch_info);
+    std::vector<std::string> batch;
+    for (size_t i = 0; i < test_names.size(); i++) {
+      batch.push_back(test_names[i]);
 
-    // Run tests in batches no larger than the limit.
-    if (tests_.size() >= batch_limit_)
-      RunRemainingTests();
+      if (batch.size() >= batch_limit_) {
+        RunBatch(test_launcher, batch);
+        batch.clear();
+      }
+    }
+
+    RunBatch(test_launcher, batch);
+
+    return test_names.size();
   }
 
-  virtual void RunRemainingTests() OVERRIDE {
-    DCHECK(thread_checker_.CalledOnValidThread());
+  virtual size_t RetryTests(
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) OVERRIDE {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&UnitTestLauncherDelegate::RunSerially,
+             Unretained(this),
+             test_launcher,
+             test_names));
+    return test_names.size();
+  }
 
-    if (tests_.empty())
+  void RunSerially(TestLauncher* test_launcher,
+                   const std::vector<std::string>& test_names) {
+    if (test_names.empty())
       return;
 
+    std::vector<std::string> new_test_names(test_names);
+    std::string test_name(new_test_names.back());
+    new_test_names.pop_back();
+
     // Create a dedicated temporary directory to store the xml result data
     // per run to ensure clean state and make it possible to launch multiple
     // processes in parallel.
@@ -149,9 +163,40 @@
                                             &output_file));
     output_file = output_file.AppendASCII("test_results.xml");
 
-    std::vector<std::string> test_names;
-    for (size_t i = 0; i < tests_.size(); i++)
-      test_names.push_back(tests_[i].GetFullName());
+    std::vector<std::string> current_test_names;
+    current_test_names.push_back(test_name);
+    CommandLine cmd_line(
+        GetCommandLineForChildGTestProcess(current_test_names, output_file));
+
+    GTestCallbackState callback_state;
+    callback_state.test_launcher = test_launcher;
+    callback_state.test_names = current_test_names;
+    callback_state.output_file = output_file;
+
+    parallel_launcher_.LaunchChildGTestProcess(
+        cmd_line,
+        std::string(),
+        TestTimeouts::test_launcher_timeout(),
+        Bind(&UnitTestLauncherDelegate::SerialGTestCallback,
+             Unretained(this),
+             callback_state,
+             new_test_names));
+  }
+
+  void RunBatch(TestLauncher* test_launcher,
+                const std::vector<std::string>& test_names) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    if (test_names.empty())
+      return;
+
+    // Create a dedicated temporary directory to store the xml result data
+    // per run to ensure clean state and make it possible to launch multiple
+    // processes in parallel.
+    base::FilePath output_file;
+    CHECK(file_util::CreateNewTempDirectory(FilePath::StringType(),
+                                            &output_file));
+    output_file = output_file.AppendASCII("test_results.xml");
 
     CommandLine cmd_line(
         GetCommandLineForChildGTestProcess(test_names, output_file));
@@ -165,51 +210,93 @@
     base::TimeDelta timeout =
         test_names.size() * TestTimeouts::test_launcher_timeout();
 
+    GTestCallbackState callback_state;
+    callback_state.test_launcher = test_launcher;
+    callback_state.test_names = test_names;
+    callback_state.output_file = output_file;
+
     parallel_launcher_.LaunchChildGTestProcess(
         cmd_line,
         std::string(),
         timeout,
         Bind(&UnitTestLauncherDelegate::GTestCallback,
-             base::Unretained(this),
-             tests_,
-             output_file));
-    tests_.clear();
+             Unretained(this),
+             callback_state));
   }
 
-  void GTestCallback(const std::vector<TestLaunchInfo>& tests,
-                     const FilePath& output_file,
+  void GTestCallback(const GTestCallbackState& callback_state,
                      int exit_code,
                      const TimeDelta& elapsed_time,
                      bool was_timeout,
                      const std::string& output) {
     DCHECK(thread_checker_.CalledOnValidThread());
-    std::vector<TestLaunchInfo> tests_to_relaunch_after_interruption;
+    std::vector<std::string> tests_to_relaunch_after_interruption;
     bool called_any_callbacks =
-        ProcessTestResults(tests,
-                           output_file,
+        ProcessTestResults(callback_state.test_launcher,
+                           callback_state.test_names,
+                           callback_state.output_file,
                            output,
                            exit_code,
                            was_timeout,
                            &tests_to_relaunch_after_interruption);
 
-    for (size_t i = 0; i < tests_to_relaunch_after_interruption.size(); i++)
-      tests_.push_back(tests_to_relaunch_after_interruption[i]);
-    RunRemainingTests();
+    RunBatch(callback_state.test_launcher,
+             tests_to_relaunch_after_interruption);
 
     if (called_any_callbacks)
       parallel_launcher_.ResetOutputWatchdog();
 
     // The temporary file's directory is also temporary.
-    DeleteFile(output_file.DirName(), true);
+    DeleteFile(callback_state.output_file.DirName(), true);
+  }
+
+  void SerialGTestCallback(const GTestCallbackState& callback_state,
+                           const std::vector<std::string>& test_names,
+                           int exit_code,
+                           const TimeDelta& elapsed_time,
+                           bool was_timeout,
+                           const std::string& output) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    std::vector<std::string> tests_to_relaunch_after_interruption;
+    bool called_any_callbacks =
+        ProcessTestResults(callback_state.test_launcher,
+                           callback_state.test_names,
+                           callback_state.output_file,
+                           output,
+                           exit_code,
+                           was_timeout,
+                           &tests_to_relaunch_after_interruption);
+
+    // There is only one test, there cannot be other tests to relaunch
+    // due to a crash.
+    DCHECK(tests_to_relaunch_after_interruption.empty());
+
+    if (called_any_callbacks) {
+      parallel_launcher_.ResetOutputWatchdog();
+    } else {
+      // There is only one test, we should have called back with its result.
+      NOTREACHED();
+    }
+
+    // The temporary file's directory is also temporary.
+    DeleteFile(callback_state.output_file.DirName(), true);
+
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&UnitTestLauncherDelegate::RunSerially,
+             Unretained(this),
+             callback_state.test_launcher,
+             test_names));
   }
 
   static bool ProcessTestResults(
-      const std::vector<TestLaunchInfo>& tests,
+      TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names,
       const base::FilePath& output_file,
       const std::string& output,
       int exit_code,
       bool was_timeout,
-      std::vector<TestLaunchInfo>* tests_to_relaunch_after_interruption) {
+      std::vector<std::string>* tests_to_relaunch_after_interruption) {
     std::vector<TestResult> test_results;
     bool crashed = false;
     bool have_test_results =
@@ -222,13 +309,13 @@
       // the results we got from XML file and tests we intended to run.
       std::map<std::string, TestResult> results_map;
       for (size_t i = 0; i < test_results.size(); i++)
-        results_map[test_results[i].GetFullName()] = test_results[i];
+        results_map[test_results[i].full_name] = test_results[i];
 
       bool had_interrupted_test = false;
 
-      for (size_t i = 0; i < tests.size(); i++) {
-        if (ContainsKey(results_map, tests[i].GetFullName())) {
-          TestResult test_result = results_map[tests[i].GetFullName()];
+      for (size_t i = 0; i < test_names.size(); i++) {
+        if (ContainsKey(results_map, test_names[i])) {
+          TestResult test_result = results_map[test_names[i]];
           if (test_result.status == TestResult::TEST_CRASH) {
             had_interrupted_test = true;
 
@@ -252,21 +339,20 @@
           }
           test_result.output_snippet =
               GetTestOutputSnippet(test_result, output);
-          tests[i].callback.Run(test_result);
+          test_launcher->OnTestFinished(test_result);
           called_any_callback = true;
         } else if (had_interrupted_test) {
-          tests_to_relaunch_after_interruption->push_back(tests[i]);
+          tests_to_relaunch_after_interruption->push_back(test_names[i]);
         } else {
           // TODO(phajdan.jr): Explicitly pass the info that the test didn't
           // run for a mysterious reason.
-          LOG(ERROR) << "no test result for " << tests[i].GetFullName();
+          LOG(ERROR) << "no test result for " << test_names[i];
           TestResult test_result;
-          test_result.test_case_name = tests[i].test_case_name;
-          test_result.test_name = tests[i].test_name;
+          test_result.full_name = test_names[i];
           test_result.status = TestResult::TEST_UNKNOWN;
           test_result.output_snippet =
               GetTestOutputSnippet(test_result, output);
-          tests[i].callback.Run(test_result);
+          test_launcher->OnTestFinished(test_result);
           called_any_callback = true;
         }
       }
@@ -289,12 +375,11 @@
       // to all tests.
       // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
       // individually.
-      for (size_t i = 0; i < tests.size(); i++) {
+      for (size_t i = 0; i < test_names.size(); i++) {
         TestResult test_result;
-        test_result.test_case_name = tests[i].test_case_name;
-        test_result.test_name = tests[i].test_name;
+        test_result.full_name = test_names[i];
         test_result.status = TestResult::TEST_UNKNOWN;
-        tests[i].callback.Run(test_result);
+        test_launcher->OnTestFinished(test_result);
         called_any_callback = true;
       }
     }
@@ -308,8 +393,6 @@
 
   // Maximum number of tests to run in a single batch.
   size_t batch_limit_;
-
-  std::vector<TestLaunchInfo> tests_;
 };
 
 bool GetSwitchValueAsInt(const std::string& switch_name, int* result) {
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
index b02e9f4..18b4881 100644
--- a/base/test/test_switches.cc
+++ b/base/test/test_switches.cc
@@ -21,6 +21,11 @@
 const char switches::kTestLauncherSummaryOutput[] =
     "test-launcher-summary-output";
 
+// Flag controlling when test stdio is displayed as part of the launcher's
+// standard output.
+const char switches::kTestLauncherPrintTestStdio[] =
+    "test-launcher-print-test-stdio";
+
 // Time (in milliseconds) that the tests should wait before timing out.
 const char switches::kTestLauncherTimeout[] = "test-launcher-timeout";
 // TODO(phajdan.jr): Clean up the switch names.
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
index 15c7f9f..330b925 100644
--- a/base/test/test_switches.h
+++ b/base/test/test_switches.h
@@ -14,6 +14,7 @@
 extern const char kTestLauncherJobs[];
 extern const char kTestLauncherOutput[];
 extern const char kTestLauncherSummaryOutput[];
+extern const char kTestLauncherPrintTestStdio[];
 extern const char kTestLauncherTimeout[];
 extern const char kTestTinyTimeout[];
 extern const char kUiTestActionTimeout[];
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
index 467c0fe..70bed30 100644
--- a/base/test/test_timeouts.cc
+++ b/base/test/test_timeouts.cc
@@ -68,7 +68,7 @@
 #endif  // NDEBUG
 int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;
 
-int TestTimeouts::test_launcher_timeout_ms_ = 45000;
+int TestTimeouts::test_launcher_timeout_ms_ = 70000;
 
 // static
 void TestTimeouts::Initialize() {
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index 719560a..4f8225f 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -48,7 +48,8 @@
   bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
   bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
   bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
-                     phase == TRACE_EVENT_PHASE_ASYNC_STEP ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
                      phase == TRACE_EVENT_PHASE_ASYNC_END);
 
   if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
@@ -717,9 +718,11 @@
 
   Query begin(
       Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
-      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP));
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
   Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
-            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP));
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
   Query match(Query::EventName() == Query::OtherName() &&
               Query::EventCategory() == Query::OtherCategory() &&
               Query::EventId() == Query::OtherId());
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
index 5d66261..760def2 100644
--- a/base/test/trace_event_analyzer_unittest.cc
+++ b/base/test/trace_event_analyzer_unittest.cc
@@ -562,17 +562,17 @@
 
   BeginTracing();
   {
-    TRACE_EVENT_ASYNC_STEP0("c", "n", 0xA, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s1");
     TRACE_EVENT_ASYNC_END0("c", "n", 0xA);
     TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xB);
     TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xC);
-    TRACE_EVENT_ASYNC_STEP0("c", "n", 0xB, "s1");
-    TRACE_EVENT_ASYNC_STEP0("c", "n", 0xC, "s1");
-    TRACE_EVENT_ASYNC_STEP1("c", "n", 0xC, "s2", "a", 1);
+    TRACE_EVENT_ASYNC_STEP_PAST0("c", "n", 0xB, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xC, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("c", "n", 0xC, "s2", "a", 1);
     TRACE_EVENT_ASYNC_END0("c", "n", 0xB);
     TRACE_EVENT_ASYNC_END0("c", "n", 0xC);
     TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xA);
-    TRACE_EVENT_ASYNC_STEP0("c", "n", 0xA, "s2");
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s2");
   }
   EndTracing();
 
@@ -586,15 +586,15 @@
   ASSERT_EQ(3u, found.size());
 
   EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
-  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, found[0]->other_event->phase);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, found[0]->other_event->phase);
   EXPECT_TRUE(found[0]->other_event->other_event);
   EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
             found[0]->other_event->other_event->phase);
 
   EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
-  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, found[1]->other_event->phase);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[1]->other_event->phase);
   EXPECT_TRUE(found[1]->other_event->other_event);
-  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP,
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
             found[1]->other_event->other_event->phase);
   double arg_actual = 0;
   EXPECT_TRUE(found[1]->other_event->other_event->GetArgAsNumber(
@@ -605,7 +605,7 @@
             found[1]->other_event->other_event->other_event->phase);
 
   EXPECT_STRCASEEQ("0xa", found[2]->id.c_str());
-  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, found[2]->other_event->phase);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[2]->other_event->phase);
 }
 
 // Test that the TraceAnalyzer custom associations work.
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-arm.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-arm.mk
index 283b288..a639f1a 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-arm.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-mips.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-mips.mk
index fb92a68..d916607 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-mips.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-x86.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-x86.mk
index 380e083..ff991f6 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-x86.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-arm.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-arm.mk
index 283b288..a639f1a 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-arm.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-mips.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-mips.mk
index fb92a68..d916607 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-mips.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-x86.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-x86.mk
index 380e083..ff991f6 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-x86.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 813af31..cc64c65 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -328,7 +328,7 @@
 
 typedef HWND (*MetroRootWindow) ();
 
-// As for this writing, GetMonitorInfo function seem to return wrong values
+// As of this writing, GetMonitorInfo function seem to return wrong values
 // for rcWork.left and rcWork.top in case of split screen situation inside
 // metro mode. In order to get required values we query for core window screen
 // coordinates.
@@ -341,6 +341,11 @@
     static MetroRootWindow root_window = NULL;
     if (!root_window) {
       HMODULE metro = base::win::GetMetroModule();
+      // There are apparently instances when current process is inside metro
+      // environment but metro driver dll is not loaded.
+      if (!metro) {
+        return ret;
+      }
       root_window = reinterpret_cast<MetroRootWindow>(
           ::GetProcAddress(metro, "GetRootWindow"));
     }
diff --git a/build/all.gyp b/build/all.gyp
index 7e8fa4d..43ac284 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -13,6 +13,7 @@
         '../base/base.gyp:*',
         '../chrome/chrome.gyp:*',
         '../content/content.gyp:*',
+        '../content/content_shell_and_tests.gyp:*',
         '../crypto/crypto.gyp:*',
         '../net/net.gyp:*',
         '../sdch/sdch.gyp:*',
@@ -33,6 +34,7 @@
           'dependencies': [
             '../cc/cc_tests.gyp:*',
             '../components/components.gyp:*',
+            '../components/components_tests.gyp:*',
             '../device/bluetooth/bluetooth.gyp:*',
             '../device/device_tests.gyp:*',
             '../device/usb/usb.gyp:*',
@@ -220,7 +222,7 @@
         '../crypto/crypto.gyp:crypto_unittests',
         '../net/net.gyp:net_unittests',
         '../sql/sql.gyp:sql_unittests',
-        '../ui/ui.gyp:ui_unittests',
+        '../ui/ui_unittests.gyp:ui_unittests',
         '../url/url.gyp:url_unittests',
       ],
       'conditions': [
@@ -236,7 +238,7 @@
             '../chrome/chrome.gyp:interactive_ui_tests',
             '../chrome/chrome.gyp:sync_integration_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_shell',
             '../content/content_shell_and_tests.gyp:content_unittests',
@@ -427,6 +429,16 @@
                 '../chrome/chrome.gyp:linux_symbols'
               ],
             }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
           ],
         }, # target_name: chromium_gpu_builder
         {
@@ -454,6 +466,16 @@
                 '../chrome/chrome.gyp:linux_symbols'
               ],
             }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
           ],
         }, # target_name: chromium_gpu_debug_builder
         {
@@ -586,7 +608,7 @@
             '../chrome/chrome.gyp:sync_integration_tests',
             '../chrome/chrome.gyp:unit_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../device/device_tests.gyp:device_unittests',
@@ -604,7 +626,7 @@
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
             '../url/url.gyp:url_unittests',
             '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests',
           ],
@@ -620,7 +642,7 @@
             '../chrome/chrome.gyp:sync_integration_tests',
             '../chrome/chrome.gyp:unit_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../device/device_tests.gyp:device_unittests',
@@ -637,7 +659,7 @@
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
             '../url/url.gyp:url_unittests',
             '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests',
           ],
@@ -675,7 +697,7 @@
             '../base/base.gyp:base_unittests',
             '../chrome/chrome.gyp:unit_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../crypto/crypto.gyp:crypto_unittests',
             '../device/device_tests.gyp:device_unittests',
@@ -690,7 +712,7 @@
             '../sync/sync.gyp:sync_unit_tests',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
             '../url/url.gyp:url_unittests',
           ],
         },
@@ -715,7 +737,7 @@
             '../chrome/chrome.gyp:sync_integration_tests',
             '../chrome/chrome.gyp:unit_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             # mini_installer_tests depends on mini_installer. This should be
@@ -737,7 +759,7 @@
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
             '../ui/views/views.gyp:views_unittests',
             '../url/url.gyp:url_unittests',
             '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests',
@@ -784,7 +806,7 @@
           'dependencies': [
             '../base/base.gyp:base_unittests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../crypto/crypto.gyp:crypto_unittests',
             '../ipc/ipc.gyp:ipc_tests',
@@ -807,7 +829,7 @@
             '../chrome/chrome.gyp:unit_tests',
             '../chrome/chrome.gyp:browser_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../crypto/crypto.gyp:crypto_unittests',
             '../device/device_tests.gyp:device_unittests',
@@ -892,7 +914,7 @@
             '../chrome/chrome.gyp:chrome',
             '../chrome/chrome.gyp:interactive_ui_tests',
             '../chrome/chrome.gyp:unit_tests',
-            '../components/components.gyp:components_unittests',
+            '../components/components_tests.gyp:components_unittests',
             '../content/content_shell_and_tests.gyp:content_browsertests',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../device/device_tests.gyp:device_unittests',
@@ -902,7 +924,7 @@
             '../ui/aura/aura.gyp:*',
             '../ui/compositor/compositor.gyp:*',
             '../ui/message_center/message_center.gyp:*',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
             '../ui/snapshot/snapshot.gyp:snapshot_unittests',
             '../ui/views/views.gyp:views',
             '../ui/views/views.gyp:views_examples_with_content_exe',
diff --git a/build/all_android.gyp b/build/all_android.gyp
index 708646c..d855750 100644
--- a/build/all_android.gyp
+++ b/build/all_android.gyp
@@ -18,6 +18,7 @@
       'type': 'none',
       'dependencies': [
         '../content/content_shell_and_tests.gyp:content_shell_apk',
+        '../mojo/mojo.gyp:mojo_shell_apk',
         '<@(android_app_targets)',
         'android_builder_tests',
         '../android_webview/android_webview.gyp:android_webview_apk',
@@ -63,7 +64,7 @@
         '../cc/cc_tests.gyp:cc_perftests_apk',
         '../cc/cc_tests.gyp:cc_unittests',
         '../chrome/chrome.gyp:unit_tests',
-        '../components/components.gyp:components_unittests',
+        '../components/components_tests.gyp:components_unittests',
         '../content/content_shell_and_tests.gyp:content_browsertests',
         '../content/content_shell_and_tests.gyp:content_gl_tests',
         '../content/content_shell_and_tests.gyp:content_shell_test_apk',
@@ -80,7 +81,7 @@
         '../tools/android/android_tools.gyp:android_tools',
         '../tools/android/android_tools.gyp:memconsumer',
         '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test',
-        '../ui/ui.gyp:ui_unittests',
+        '../ui/ui_unittests.gyp:ui_unittests',
         # Required by ui_unittests.
         # TODO(wangxianzhu): It'd better let ui_unittests depend on it, but
         # this would cause circular gyp dependency which needs refactoring the
@@ -95,7 +96,7 @@
             '../base/base.gyp:base_unittests_apk',
             '../cc/cc_tests.gyp:cc_unittests_apk',
             '../chrome/chrome.gyp:unit_tests_apk',
-            '../components/components.gyp:components_unittests_apk',
+            '../components/components_tests.gyp:components_unittests_apk',
             '../content/content_shell_and_tests.gyp:content_browsertests_apk',
             '../content/content_shell_and_tests.gyp:content_gl_tests_apk',
             '../content/content_shell_and_tests.gyp:content_unittests_apk',
@@ -108,7 +109,7 @@
             '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk',
             '../sql/sql.gyp:sql_unittests_apk',
             '../sync/sync.gyp:sync_unit_tests_apk',
-            '../ui/ui.gyp:ui_unittests_apk',
+            '../ui/ui_unittests.gyp:ui_unittests_apk',
             '../android_webview/android_webview.gyp:android_webview_test_apk',
             '../chrome/chrome.gyp:chromium_testshell_test_apk',
             '../chrome/chrome.gyp:chromium_testshell_uiautomator_tests',
diff --git a/build/android/adb_gdb_mojo_shell b/build/android/adb_gdb_mojo_shell
new file mode 100755
index 0000000..ba91149
--- /dev/null
+++ b/build/android/adb_gdb_mojo_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2013 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.
+#
+# Attach to or start a ContentShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.MojoShellActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=MojoShell \
+    --package-name=org.chromium.mojo_shell_apk \
+    "$@"
diff --git a/build/android/adb_profile_chrome.py b/build/android/adb_profile_chrome.py
index ead6741..bb3e9d0 100755
--- a/build/android/adb_profile_chrome.py
+++ b/build/android/adb_profile_chrome.py
@@ -4,6 +4,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import base64
 import gzip
 import logging
 import optparse
@@ -13,6 +14,7 @@
 import sys
 import threading
 import time
+import webbrowser
 import zipfile
 import zlib
 
@@ -22,6 +24,43 @@
 from pylib import pexpect
 
 
+_TRACE_VIEWER_TEMPLATE = """<!DOCTYPE html>
+<html>
+  <head>
+    <title>%(title)s</title>
+    <style>
+      %(timeline_css)s
+    </style>
+    <style>
+      .view {
+        overflow: hidden;
+        position: absolute;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+      }
+    </style>
+    <script>
+      %(timeline_js)s
+    </script>
+    <script>
+      document.addEventListener('DOMContentLoaded', function() {
+        var trace_data = window.atob('%(trace_data_base64)s');
+        var m = new tracing.TraceModel(trace_data);
+        var timelineViewEl = document.querySelector('.view');
+        ui.decorate(timelineViewEl, tracing.TimelineView);
+        timelineViewEl.model = m;
+        timelineViewEl.tabIndex = 1;
+        timelineViewEl.timeline.focusElement = timelineViewEl;
+      });
+    </script>
+  </head>
+  <body>
+    <div class="view"></view>
+  </body>
+</html>"""
+
 _DEFAULT_CHROME_CATEGORIES = '_DEFAULT_CHROME_CATEGORIES'
 
 
@@ -29,6 +68,32 @@
  return time.strftime('%Y-%m-%d-%H%M%S', time.localtime())
 
 
+def _PackageTraceAsHtml(trace_file_name, html_file_name):
+  trace_viewer_root = os.path.join(constants.DIR_SOURCE_ROOT,
+                                   'third_party', 'trace-viewer')
+  build_dir = os.path.join(trace_viewer_root, 'build')
+  src_dir = os.path.join(trace_viewer_root, 'src')
+  if not build_dir in sys.path:
+    sys.path.append(build_dir)
+  generate = __import__('generate', {}, {})
+  parse_deps = __import__('parse_deps', {}, {})
+
+  basename = os.path.splitext(trace_file_name)[0]
+  load_sequence = parse_deps.calc_load_sequence(
+      ['tracing/standalone_timeline_view.js'], [src_dir])
+
+  with open(trace_file_name) as trace_file:
+    trace_data = base64.b64encode(trace_file.read())
+    with open(html_file_name, 'w') as html_file:
+      html = _TRACE_VIEWER_TEMPLATE % {
+        'title': os.path.basename(os.path.splitext(trace_file_name)[0]),
+        'timeline_js': generate.generate_js(load_sequence),
+        'timeline_css': generate.generate_css(load_sequence),
+        'trace_data_base64': trace_data
+      }
+      html_file.write(html)
+
+
 class ChromeTracingController(object):
   def __init__(self, adb, package_info, categories, ring_buffer):
     self._adb = adb
@@ -208,7 +273,7 @@
     controller.StopTracing()
 
 
-def _PullTraces(controllers, output, compress):
+def _PullTraces(controllers, output, compress, write_html):
   _PrintMessage('Downloading...', eol='')
   trace_files = []
   for controller in controllers:
@@ -226,11 +291,18 @@
   else:
     result = trace_files[0]
 
+  if write_html:
+    result, trace_file = os.path.splitext(result)[0] + '.html', result
+    _PackageTraceAsHtml(trace_file, result)
+    if trace_file != result:
+      os.unlink(trace_file)
+
   _PrintMessage('done')
   _PrintMessage('Trace written to %s' % os.path.abspath(result))
+  return result
 
 
-def _CaptureAndPullTrace(controllers, interval, output, compress):
+def _CaptureAndPullTrace(controllers, interval, output, compress, write_html):
   trace_type = ' + '.join(map(str, controllers))
   try:
     _StartTracing(controllers, interval)
@@ -248,7 +320,7 @@
   if interval:
     _PrintMessage('done')
 
-  _PullTraces(controllers, output, compress)
+  return _PullTraces(controllers, output, compress, write_html)
 
 
 def _ComputeChromeCategories(options):
@@ -311,7 +383,14 @@
                         'GPU data.', action='store_true')
   parser.add_option_group(categories)
 
-  parser.add_option('-o', '--output', help='Save profile output to file.')
+  output_options = optparse.OptionGroup(parser, 'Output options')
+  output_options.add_option('-o', '--output', help='Save trace output to file.')
+  output_options.add_option('--html', help='Package trace into a standalone '
+                            'html file.', action='store_true')
+  output_options.add_option('--view', help='Open resulting trace file in a '
+                            'browser.', action='store_true')
+  parser.add_option_group(output_options)
+
   browsers = sorted(_GetSupportedBrowsers().keys())
   parser.add_option('-b', '--browser', help='Select among installed browsers. '
                     'One of ' + ', '.join(browsers) + ', "stable" is used by '
@@ -358,10 +437,13 @@
     _PrintMessage('No trace categories enabled.')
     return 1
 
-  _CaptureAndPullTrace(controllers,
-                       options.time if not options.continuous else 0,
-                       options.output,
-                       options.compress)
+  result = _CaptureAndPullTrace(controllers,
+                                options.time if not options.continuous else 0,
+                                options.output,
+                                options.compress,
+                                options.html)
+  if options.view:
+    webbrowser.open(result)
 
 
 if __name__ == '__main__':
diff --git a/build/android/adb_run_mojo_shell b/build/android/adb_run_mojo_shell
new file mode 100755
index 0000000..d47270e
--- /dev/null
+++ b/build/android/adb_run_mojo_shell
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# Copyright 2013 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.
+
+if [ $# -gt 0 ] ; then
+   INTENT_ARGS="-d \"$1\""  # e.g. a URL
+fi
+
+adb shell am start \
+  -a android.intent.action.VIEW \
+  -n org.chromium.mojo_shell_apk/.MojoShellActivity \
+  $INTENT_ARGS
diff --git a/build/android/ant/apk-codegen.xml b/build/android/ant/apk-codegen.xml
index 37abb07..f9b7171 100644
--- a/build/android/ant/apk-codegen.xml
+++ b/build/android/ant/apk-codegen.xml
@@ -43,7 +43,7 @@
     list the res folders in project.library.res.folder.path and the
     corresponding java packages in project.library.packages, which must be
     semicolon-delimited while ADDITIONAL_RES_PACKAGES is space-delimited, hence
-    the javascript task.
+    the replacestring filterchain task.
   -->
   <path id="project.library.res.folder.path">
     <filelist files="${ADDITIONAL_RES_DIRS}"/>
@@ -51,10 +51,15 @@
   <path id="project.library.bin.r.file.path">
     <filelist files="${ADDITIONAL_R_TEXT_FILES}"/>
   </path>
-  <script language="javascript">
-    var before = project.getProperty("ADDITIONAL_RES_PACKAGES");
-    project.setProperty("project.library.packages", before.replaceAll(" ", ";"));
-  </script>
+
+  <loadresource property="project.library.packages">
+    <propertyresource name="ADDITIONAL_RES_PACKAGES"/>
+    <filterchain>
+      <replacestring from=" " to=";"/>
+    </filterchain>
+  </loadresource>
+  <!-- Set to empty if not set by the loadresource above -->
+  <property name="project.library.packages" value=""/>
 
   <path id="project.library.manifest.file.path">
     <filelist files="${LIBRARY_MANIFEST_PATHS}"/>
diff --git a/build/android/ant/apk-compile.xml b/build/android/ant/apk-compile.xml
index 4f3d664..69dc6a8 100644
--- a/build/android/ant/apk-compile.xml
+++ b/build/android/ant/apk-compile.xml
@@ -122,9 +122,28 @@
         <!-- get the project manifest package -->
         <xpath input="${out.manifest.abs.file}"
                 expression="/manifest/@package" output="project.app.package" />
-        <property name="create.test.jar.file"
-          location="${CREATE_TEST_JAR_PATH}" />
-        <script language="javascript" src="${create.test.jar.file}"/>
+        <loadresource property="project.app.packagepath">
+          <propertyresource name="project.app.package"/>
+          <filterchain>
+            <replacestring from="." to="/"/>
+          </filterchain>
+        </loadresource>
+        <property name="create.test.jar.exclusions"
+                  value="${project.app.packagepath}/R.class ${project.app.packagepath}/R$*.class ${project.app.packagepath}/Manifest.class ${project.app.packagepath}/Manifest$*.class ${project.app.packagepath}/BuildConfig.class"/>
+        <jar destfile="${TEST_JAR_PATH}"
+             excludes="${create.test.jar.exclusions}"
+             duplicate="preserve"
+             >
+          <restrict>
+            <name name="**/*.class"/>
+            <archives>
+              <zips>
+                <path refid="javac.custom.classpath"/>
+              </zips>
+            </archives>
+          </restrict>
+          <fileset dir="${out.dir}/classes"/>
+        </jar>
       </then>
     </if>
 
diff --git a/build/android/ant/apk-obfuscate.xml b/build/android/ant/apk-obfuscate.xml
index b15ce73..4e737da 100644
--- a/build/android/ant/apk-obfuscate.xml
+++ b/build/android/ant/apk-obfuscate.xml
@@ -69,9 +69,27 @@
         <!-- get the project manifest package -->
         <xpath input="${out.manifest.abs.file}"
                 expression="/manifest/@package" output="project.app.package" />
-        <property name="create.test.jar.file"
-          location="${CREATE_TEST_JAR_PATH}" />
-        <script language="javascript" src="${create.test.jar.file}"/>
+        <loadresource property="project.app.packagepath">
+          <propertyresource name="project.app.package"/>
+          <filterchain>
+            <replacestring from="." to="/"/>
+          </filterchain>
+        </loadresource>
+        <property name="create.test.jar.exclusions" value="${project.app.packagepath}/R.class ${project.app.packagepath}/R$*.class ${project.app.packagepath}/Manifest.class ${project.app.packagepath}/Manifest$*.class ${project.app.packagepath}/BuildConfig.class"/>
+        <jar destfile="${TEST_JAR_PATH}"
+             excludes="${create.test.jar.exclusions}"
+             duplicate="preserve"
+             >
+          <restrict>
+            <name name="**/*.class"/>
+            <archives>
+              <zips>
+                <path refid="javac.custom.classpath"/>
+              </zips>
+            </archives>
+          </restrict>
+          <fileset dir="${out.dir}/classes"/>
+        </jar>
       </then>
     </if>
     <if>
diff --git a/build/android/ant/apk-package-resources.xml b/build/android/ant/apk-package-resources.xml
index 3bfd3c9..b716c16 100644
--- a/build/android/ant/apk-package-resources.xml
+++ b/build/android/ant/apk-package-resources.xml
@@ -71,7 +71,7 @@
       list the res folders in project.library.res.folder.path and the
       corresponding java packages in project.library.packages, which must be
       semicolon-delimited while ADDITIONAL_RES_PACKAGES is space-delimited, hence
-      the javascript task.
+      the replacestring filterchain task.
   -->
   <path id="project.library.res.folder.path">
     <filelist files="${ADDITIONAL_RES_DIRS}"/>
@@ -79,10 +79,15 @@
   <path id="project.library.bin.r.file.path">
     <filelist files="${ADDITIONAL_R_TEXT_FILES}"/>
   </path>
-  <script language="javascript">
-    var before = project.getProperty("ADDITIONAL_RES_PACKAGES");
-    project.setProperty("project.library.packages", before.replaceAll(" ", ";"));
-  </script>
+
+  <loadresource property="project.library.packages">
+    <propertyresource name="ADDITIONAL_RES_PACKAGES"/>
+    <filterchain>
+      <replacestring from=" " to=";"/>
+    </filterchain>
+  </loadresource>
+  <!-- Set to empty if not set by the loadresource above -->
+  <property name="project.library.packages" value=""/>
 
   <property name="build.packaging.nocrunch" value="true" />
 
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index e279b50..a021bfc 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -8,10 +8,13 @@
 import logging
 import optparse
 import os
+import psutil
+import re
+import signal
 import smtplib
 import subprocess
 import sys
-import re
+import time
 import urllib
 
 import bb_annotations
@@ -109,6 +112,26 @@
   return device_type, device_build, battery_level, full_report, errors, True
 
 
+def GetLastDevices(out_dir):
+  """Returns a list of devices that have been seen on the bot.
+
+  Args:
+    options: out_dir parameter of options argument is used as the base
+             directory to load and update the cache file.
+
+  Returns: List of device serial numbers that were on the bot.
+  """
+  devices_path = os.path.join(out_dir, '.last_devices')
+  devices = []
+  try:
+    with open(devices_path) as f:
+      devices = f.read().splitlines()
+  except IOError:
+    # Ignore error, file might not exist
+    pass
+  return devices
+
+
 def CheckForMissingDevices(options, adb_online_devs):
   """Uses file of previous online devices to detect broken phones.
 
@@ -125,17 +148,6 @@
 
   out_dir = os.path.abspath(options.out_dir)
 
-  def ReadDeviceList(file_name):
-    devices_path = os.path.join(out_dir, file_name)
-    devices = []
-    try:
-      with open(devices_path) as f:
-        devices = f.read().splitlines()
-    except IOError:
-      # Ignore error, file might not exist
-      pass
-    return devices
-
   def WriteDeviceList(file_name, device_list):
     path = os.path.join(out_dir, file_name)
     if not os.path.exists(out_dir):
@@ -145,7 +157,7 @@
       f.write('\n'.join(set(device_list)))
 
   last_devices_path = os.path.join(out_dir, '.last_devices')
-  last_devices = ReadDeviceList('.last_devices')
+  last_devices = GetLastDevices(out_dir)
   missing_devs = list(set(last_devices) - set(adb_online_devs))
 
   all_known_devices = list(set(adb_online_devs) | set(last_devices))
@@ -241,6 +253,24 @@
   return 0
 
 
+def KillAllAdb():
+  def GetAllAdb():
+    for p in psutil.process_iter():
+      if 'adb' in p.name or 'adb' in ' '.join(p.cmdline):
+        yield p
+
+  for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
+    for p in GetAllAdb():
+      try:
+        print 'kill %d %d (%s [%s])' % (sig, p.pid, p.name,
+            ' '.join(p.cmdline))
+        p.send_signal(sig)
+      except psutil.error.NoSuchProcess:
+        pass
+  for p in GetAllAdb():
+    print 'Unable to kill %d (%s [%s])' % (p.pid, p.name, ' '.join(p.cmdline))
+
+
 def main():
   parser = optparse.OptionParser()
   parser.add_option('', '--out-dir',
@@ -257,9 +287,20 @@
     parser.error('Unknown options %s' % args)
 
   if options.restart_usb:
-    rc = RestartUsb()
-    if rc:
-      return 1
+    expected_devices = GetLastDevices(os.path.abspath(options.out_dir))
+    devices = android_commands.GetAttachedDevices()
+    # Only restart usb if devices are missing
+    if set(expected_devices) != set(devices):
+      KillAllAdb()
+      if RestartUsb():
+        return 1
+      retries = 5
+      while retries:
+        time.sleep(1)
+        devices = android_commands.GetAttachedDevices()
+        if set(expected_devices) == set(devices):
+          break
+        retries -= 1
 
   devices = android_commands.GetAttachedDevices()
   # TODO(navabi): Test to make sure this fails and then fix call
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index f80a2a4..9738361 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -24,6 +24,7 @@
 from pylib.gtest import gtest_config
 
 CHROME_SRC_DIR = bb_utils.CHROME_SRC
+DIR_BUILD_ROOT = os.path.dirname(CHROME_SRC_DIR)
 CHROME_OUT_DIR = bb_utils.CHROME_OUT_DIR
 sys.path.append(os.path.join(
     CHROME_SRC_DIR, 'third_party', 'android_testrunner'))
@@ -48,6 +49,10 @@
     'annotation', 'exclude_annotation', 'extra_flags'])
 
 
+def SrcPath(*path):
+  return os.path.join(CHROME_SRC_DIR, *path)
+
+
 def I(name, apk, apk_package, test_apk, test_data, host_driven_root=None,
       annotation=None, exclude_annotation=None, extra_flags=None):
   return I_TEST(name, apk, apk_package, test_apk, test_data, host_driven_root,
@@ -221,7 +226,7 @@
 def RunWebkitLint(target):
   """Lint WebKit's TestExpectation files."""
   bb_annotations.PrintNamedStep('webkit_lint')
-  RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py',
+  RunCmd([SrcPath('webkit/tools/layout_tests/run_webkit_tests.py'),
           '--lint-test-files',
           '--chromium',
           '--target', target])
@@ -261,8 +266,8 @@
     cmd_args.extend(
         ['--additional-expectations=%s' % os.path.join(CHROME_SRC_DIR, *f)])
 
-  exit_code = RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py'] +
-                     cmd_args)
+  exit_code = RunCmd([SrcPath('webkit/tools/layout_tests/run_webkit_tests.py')]
+                     + cmd_args)
   if exit_code == 255: # test_run_results.UNEXPECTED_ERROR_EXIT_STATUS
     bb_annotations.PrintMsg('?? (crashed or hung)')
   elif exit_code == 254: # test_run_results.NO_DEVICES_EXIT_STATUS
@@ -310,7 +315,8 @@
             '--build-dir', CHROME_OUT_DIR,
             '--build-number', build_number,
             '--builder-name', builder_name,
-            '--gs-bucket', gs_bucket])
+            '--gs-bucket', gs_bucket],
+            cwd=DIR_BUILD_ROOT)
 
 
 def _ParseLayoutTestResults(results):
@@ -322,13 +328,19 @@
   passes = {}
   for (test, result) in tests.iteritems():
     if result.get('is_unexpected'):
-      actual_result = result['actual']
-      if ' PASS' in actual_result:
-        flakes[test] = actual_result
-      elif actual_result == 'PASS':
+      actual_results = result['actual'].split()
+      expected_results = result['expected'].split()
+      if len(actual_results) > 1:
+        # We report the first failure type back, even if the second
+        # was more severe.
+        if actual_results[1] in expected_results:
+          flakes[test] = actual_results[0]
+        else:
+          failures[test] = actual_results[0]
+      elif actual_results[0] == 'PASS':
         passes[test] = result
       else:
-        failures[test] = actual_result
+        failures[test] = actual_results[0]
 
   return (passes, failures, flakes)
 
@@ -436,13 +448,9 @@
 def RunGPUTests(options):
   InstallApk(options, INSTRUMENTATION_TESTS['ContentShell'], False)
 
-  # Pixel tests require that the browser implements GrabWindowSnapshot and
-  # GrabViewSnapshot, which android-content-shell currently does not.
-  # (crbug.com/285932)
-
-  # bb_annotations.PrintNamedStep('gpu_tests')
-  # RunCmd(['content/test/gpu/run_gpu_test',
-  #         '--browser=android-content-shell', 'pixel'])
+  bb_annotations.PrintNamedStep('gpu_tests')
+  RunCmd(['content/test/gpu/run_gpu_test',
+          '--browser=android-content-shell', 'pixel'])
 
   bb_annotations.PrintNamedStep('webgl_conformance_tests')
   RunCmd(['content/test/gpu/run_gpu_test',
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh
index 51f225a..dda9eaf 100755
--- a/build/android/envsetup.sh
+++ b/build/android/envsetup.sh
@@ -9,13 +9,12 @@
 # ANDROID_SDK_BUILD=1 will then be defined and used in the rest of the setup to
 # specifiy build type.
 
-# TODO(ilevy): Figure out the right check here. This breaks the webkit build as
-# is since it's sourced from another script:
-# http://build.webkit.org/builders/Chromium%20Android%20Release/builds/34681
-#if [ "$_" == "$0" ]; then
-#  echo "ERROR: envsetup must be sourced."
-#  exit 1
-#fi
+# Make sure we're being sourced (possibly by another script). Check for bash
+# since zsh sets $0 when sourcing.
+if [[ -n "$BASH_VERSION" && "${BASH_SOURCE:-$0}" == "$0" ]]; then
+  echo "ERROR: envsetup must be sourced."
+  exit 1
+fi
 
 # Source functions script.  The file is in the same directory as this script.
 SCRIPT_DIR="$(dirname "${BASH_SOURCE:-$0}")"
@@ -109,26 +108,6 @@
   webview_build_init
 fi
 
-java -version 2>&1 | grep -qs "Java HotSpot"
-if [ $? -ne 0 ]; then
-  echo "Please check and make sure you are using the Oracle Java SDK, and it"
-  echo "appears before other Java SDKs in your path."
-  echo "Refer to the \"Install prerequisites\" section here:"
-  echo "https://code.google.com/p/chromium/wiki/AndroidBuildInstructions"
-  return 1
-fi
-
-if [[ -n "$JAVA_HOME" && -x "$JAVA_HOME/bin/java" ]]; then
-  "$JAVA_HOME/bin/java" -version 2>&1 | grep -qs "Java HotSpot"
-  if [ $? -ne 0 ]; then
-    echo "If JAVA_HOME is defined then it must refer to the install location"
-    echo "of the Oracle Java SDK."
-    echo "Refer to the \"Install prerequisites\" section here:"
-    echo "https://code.google.com/p/chromium/wiki/AndroidBuildInstructions"
-    return 1
-  fi
-fi
-
 # Workaround for valgrind build
 if [[ -n "$CHROME_ANDROID_VALGRIND_BUILD" ]]; then
 # arm_thumb=0 is a workaround for https://bugs.kde.org/show_bug.cgi?id=270709
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
index 1650398..1741619 100644
--- a/build/android/pylib/android_commands.py
+++ b/build/android/pylib/android_commands.py
@@ -891,7 +891,6 @@
     changed_files = self.GetFilesChanged(host_path, device_path)
     logging.info('Found %d files that need to be pushed to %s',
         len(changed_files), device_path)
-    logging.info([os.path.relpath(f[0], host_path) for f in changed_files])
     if not changed_files:
       return
 
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
index bf1fcf0..535711b 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -7,7 +7,6 @@
 MediaSourceTest.*
 WebGLConformanceTest.*
 MessagePortTest.Tests
-*EncryptedMediaTest.*
 CrossPlatformAccessibilityBrowserTest.*
 DatabaseTest.*
 ResourceDispatcherHostBrowserTest.SyncXMLHttpRequest_DuringUnload
@@ -83,6 +82,10 @@
 # http://crbug.com/175683
 WebrtcBrowserTest.CallWithDataAndLaterAddMedia
 
+# http://crbug.com/311348
+WebrtcBrowserTest.CallWithSctpDataOnly
+WebrtcBrowserTest.CallWithSctpDataAndMedia
+
 # http://crbug.com/224134
 RenderWidgetHostBrowserTest.GetSnapshotFromRendererTest
 
@@ -106,3 +109,9 @@
 
 # http://crbug.com/256238
 SignalTest.*
+
+# http://crbug.com/311344
+BrowserGpuChannelHostFactoryTest.AlreadyEstablished
+BrowserGpuChannelHostFactoryTest.Basic
+BrowserGpuChannelHostFactoryTest.CrashAndRecover
+BrowserGpuChannelHostFactoryTest.EstablishAndTerminate
diff --git a/build/android/pylib/gtest/filter/media_unittests_disabled b/build/android/pylib/gtest/filter/media_unittests_disabled
index 2690683..ed3b9aa 100644
--- a/build/android/pylib/gtest/filter/media_unittests_disabled
+++ b/build/android/pylib/gtest/filter/media_unittests_disabled
@@ -6,6 +6,3 @@
 
 # http://crbug.com/138833
 AesDecryptorTest.*
-
-# crbug.com/138930
-SkCanvasVideoRendererTest.*
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
index c6fc730..4508d7c 100644
--- a/build/android/pylib/gtest/setup.py
+++ b/build/android/pylib/gtest/setup.py
@@ -61,7 +61,7 @@
 }
 
 # Append the WebRTC tests with the full path from Chromium's src/ root.
-for test,isolate_path in _WEBRTC_ISOLATE_FILE_PATHS.items():
+for test, isolate_path in _WEBRTC_ISOLATE_FILE_PATHS.items():
   _ISOLATE_FILE_PATHS[test] = 'third_party/webrtc/%s' % isolate_path
 
 # Used for filtering large data deps at a finer grain than what's allowed in
@@ -211,9 +211,9 @@
       return runner_factory(device, 0).GetAllTests()
     except (android_commands.errors.WaitForResponseTimedOutError,
             android_commands.errors.DeviceUnresponsiveError), e:
-      logging.warning('Failed obtaining tests from %s with exception: %s',
+      logging.warning('Failed obtaining test list from %s with exception: %s',
                       device, e)
-  raise Exception('No device available to get the list of tests.')
+  raise Exception('Failed to obtain test list from devices.')
 
 
 def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False):
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 7312c36..c47bf66 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -11,6 +11,7 @@
 from pylib import pexpect
 from pylib.base import base_test_result
 from pylib.base import base_test_runner
+from pylib.perf import perf_control
 
 
 def _TestSuiteRequiresMockTestServer(suite_name):
@@ -21,6 +22,9 @@
   return (suite_name in
           tests_require_net_test_server)
 
+def _TestSuiteRequiresHighPerfMode(suite_name):
+  """Returns True if the test suite requires high performance mode."""
+  return 'perftests' in suite_name
 
 class TestRunner(base_test_runner.BaseTestRunner):
   def __init__(self, test_options, device, test_package):
@@ -48,6 +52,7 @@
       timeout = timeout * 2
 
     self._timeout = timeout * self.tool.GetTimeoutScale()
+    self._perf_controller = perf_control.PerfControl(self.adb)
 
   #override
   def InstallTestPackage(self):
@@ -182,11 +187,15 @@
     super(TestRunner, self).SetUp()
     if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
       self.LaunchChromeTestServerSpawner()
+    if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
+      self._perf_controller.SetHighPerfMode()
     self.tool.SetupEnvironment()
 
   #override
   def TearDown(self):
     """Cleans up the test enviroment for the test suite."""
+    if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
+      self._perf_controller.RestoreOriginalPerfMode()
     self.test_package.ClearApplicationState(self.adb)
     self.tool.CleanUpEnvironment()
     super(TestRunner, self).TearDown()
diff --git a/build/android/pylib/utils/findbugs.py b/build/android/pylib/utils/findbugs.py
index 487e559..8dde7f6 100644
--- a/build/android/pylib/utils/findbugs.py
+++ b/build/android/pylib/utils/findbugs.py
@@ -122,7 +122,7 @@
     cmd = '%s -exclude %s ' % (cmd, os.path.abspath(exclude))
 
   if findbug_args:
-    cmd = '%s %s ' % (cmd, fingbug_args)
+    cmd = '%s %s ' % (cmd, findbug_args)
 
 
   chrome_classes = _GetChromeClasses(release_version)
diff --git a/build/common.gypi b/build/common.gypi
index 4a1c3d8..869696b 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -225,7 +225,6 @@
       # Python version.
       'python_ver%': '2.6',
 
-
       # Set NEON compilation flags.
       'arm_neon%': 1,
 
@@ -558,6 +557,11 @@
           'proprietary_codecs%': 0,
         }],
 
+        ['OS=="mac"', {
+          'native_discardable_memory%': 1,
+          'native_memory_pressure_signals%': 1,
+        }],
+
         # Enable autofill dialog for Android, Mac and Views-enabled platforms.
         ['toolkit_views==1 or (OS=="android" and android_webview_build==0) or OS=="mac"', {
           'enable_autofill_dialog%': 1
@@ -675,7 +679,6 @@
           'sysroot%': '<!(cd <(DEPTH) && pwd -P)/arm-sysroot',
         }], # OS=="linux" and target_arch=="arm" and chromeos==0
 
-
         ['OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0', {
           'conditions': [
             ['target_arch=="x64"', {
@@ -1740,8 +1743,8 @@
         'release_valgrind_build': 1,
       }],
 
-      # Enable RLZ on Win, Mac and ChromeOS.
-      ['branding=="Chrome" and (OS=="win" or OS=="mac" or chromeos==1)', {
+      # Enable RLZ on Win, Mac, iOS and ChromeOS.
+      ['branding=="Chrome" and (OS=="win" or OS=="mac" or OS=="ios" or chromeos==1)', {
         'enable_rlz%': 1,
       }],
 
@@ -1771,6 +1774,7 @@
             'arm_fpu%': 'vfpv3-d16',
           }],
         ],
+        # Change the default to hard once the armhf transition is complete.
         'arm_float_abi%': 'softfp',
         'arm_thumb%': 1,
       }],
@@ -1783,6 +1787,11 @@
         'arm_float_abi%': '',
         'arm_thumb%': 0,
       }],
+
+      # Enable brlapi by default for chromeos.
+      [ 'chromeos==1', {
+        'use_brlapi%': 1,
+      }],
     ],
 
 
@@ -2053,6 +2062,12 @@
       ['enable_hidpi==1', {
         'defines': ['ENABLE_HIDPI=1'],
       }],
+      ['native_discardable_memory==1', {
+        'defines': ['DISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY'],
+      }],
+      ['native_memory_pressure_signals==1', {
+        'defines': ['SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE'],
+      }],
       ['fastbuild!=0', {
         'xcode_settings': {
           'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
@@ -3463,12 +3478,6 @@
               '-B<(PRODUCT_DIR)/../../third_party/gold',
             ],
           }],
-          ['native_discardable_memory', {
-            'defines': ['DISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY'],
-          }],
-          ['native_memory_pressure_signals', {
-            'defines': ['SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE'],
-          }],
         ],
       },
     }],
@@ -4195,12 +4204,10 @@
             'xcode_settings': {
               'SDKROOT': 'macosx<(mac_sdk)',  # -isysroot
               'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)',
+              'ARCHS': [
+                'x86_64'
+              ],
             },
-            'conditions': [
-              ['"<(GENERATOR)"!="xcode"', {
-                'xcode_settings': { 'ARCHS': [ 'x86_64' ] },
-              }],
-            ],
           }],
           ['_toolset=="target"', {
             'xcode_settings': {
@@ -4209,13 +4216,6 @@
               # instead set it here for target only.
               'IPHONEOS_DEPLOYMENT_TARGET': '<(ios_deployment_target)',
             },
-            'conditions': [
-              ['target_arch=="armv7" and "<(GENERATOR)"!="xcode"', {
-                'xcode_settings': { 'ARCHS': [ 'armv7' ]},
-              }, {
-                'xcode_settings': { 'ARCHS': [ 'i386' ] },
-              }],
-            ],
           }],
           ['_type=="executable"', {
             'configurations': {
@@ -4232,77 +4232,17 @@
                 },
               },
             },
-            'conditions': [
-              ['"<(GENERATOR)"=="xcode"', {
-                'xcode_settings': {
-                  # TODO(justincohen): ninja builds don't support signing yet.
-                  'conditions': [
-                    ['chromium_ios_signing', {
-                      # iOS SDK wants everything for device signed.
-                      'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
-                    }, {
-                      'CODE_SIGNING_REQUIRED': 'NO',
-                      'CODE_SIGN_IDENTITY[sdk=iphoneos*]': '',
-                    }],
-                  ],
-                },
-              }],
-              ['"<(GENERATOR)"=="xcode" and clang!=1', {
-                'xcode_settings': {
-                  # It is necessary to link with the -fobjc-arc flag to use
-                  # subscripting on iOS < 6.
-                  'OTHER_LDFLAGS': [
-                    '-fobjc-arc',
-                  ],
-                },
-              }],
-              ['clang==1', {
-                'target_conditions': [
-                  ['_toolset=="target"', {
-                    'variables': {
-                      'developer_dir': '<!(xcode-select -print-path)',
-                      'arc_toolchain_path': '<(developer_dir)/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc',
-                    },
-                    # It is necessary to force load libarclite from Xcode for
-                    # third_party/llvm-build because libarclite_* is only
-                    # distributed by Xcode.
-                    'conditions': [
-                      ['"<(GENERATOR)"=="ninja" and target_arch=="armv7"', {
-                        'xcode_settings': {
-                          'OTHER_LDFLAGS': [
-                            '-force_load',
-                            '<(arc_toolchain_path)/libarclite_iphoneos.a',
-                          ],
-                        },
-                      }],
-                      ['"<(GENERATOR)"=="ninja" and target_arch!="armv7"', {
-                        'xcode_settings': {
-                          'OTHER_LDFLAGS': [
-                            '-force_load',
-                            '<(arc_toolchain_path)/libarclite_iphonesimulator.a',
-                          ],
-                        },
-                      }],
-                      # Xcode sets target_arch at compile-time.
-                      ['"<(GENERATOR)"=="xcode"', {
-                        'xcode_settings': {
-                          'OTHER_LDFLAGS[arch=armv7]': [
-                            '$(inherited)',
-                            '-force_load',
-                            '<(arc_toolchain_path)/libarclite_iphoneos.a',
-                          ],
-                          'OTHER_LDFLAGS[arch=i386]': [
-                            '$(inherited)',
-                            '-force_load',
-                            '<(arc_toolchain_path)/libarclite_iphonesimulator.a',
-                          ],
-                        },
-                      }],
-                    ],
-                  }],
-                ],
-              }],
-            ],
+            'xcode_settings': {
+              'conditions': [
+                ['chromium_ios_signing', {
+                  # iOS SDK wants everything for device signed.
+                  'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+                }, {
+                  'CODE_SIGNING_REQUIRED': 'NO',
+                  'CODE_SIGN_IDENTITY[sdk=iphoneos*]': '',
+                }],
+              ],
+            },
           }],
         ],  # target_conditions
       },  # target_defaults
@@ -4429,6 +4369,20 @@
               '<(windows_driver_kit_path)/inc/mfc42',
             ],
           }],
+          # Workaround for intsafe in 2010 Express + WDK. ATL code uses
+          # intsafe.h and both intsafe.h and stdint.h define INT8_MIN et al.
+          # We can't use this workaround in third_party code because it has
+          # various levels of intolerance for including stdint.h.
+          ['msvs_express and chromium_code', {
+            'msvs_system_include_dirs': [
+              '<(DEPTH)/build',
+            ],
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'ForcedIncludeFiles': [ 'intsafe_workaround.h', ],
+              },
+            },
+          }],
         ],
         'msvs_system_include_dirs': [
           '<(windows_sdk_path)/Include/shared',
@@ -4644,35 +4598,6 @@
       ],
     }],
   ],
-  'configurations': {
-    # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT!
-    # This block adds *project-wide* configuration settings to each project
-    # file.  It's almost always wrong to put things here.  Specify your
-    # custom |configurations| in target_defaults to add them to targets instead.
-    'conditions': [
-      ['OS=="ios"', {
-        'Debug': {
-          'xcode_settings': {
-            # Enable 'Build Active Architecture Only' for Debug. This
-            # avoids a project-level warning in Xcode.
-            # Note that this configuration uses the default VALID_ARCHS value
-            # because if there is a device connected Xcode sets the active arch
-            # to the arch of the device. In cases where the device's arch is not
-            # in VALID_ARCHS (e.g. iPhone5 is armv7s) Xcode complains because it
-            # can't determine what arch to compile for.
-            'ONLY_ACTIVE_ARCH': 'YES',
-          },
-        },
-        'Release': {
-          'xcode_settings': {
-            # Override VALID_ARCHS and omit armv7s. Otherwise Xcode compiles for
-            # both armv7 and armv7s, doubling the binary size.
-            'VALID_ARCHS': 'armv7 i386',
-          },
-        },
-      }],
-    ],
-  },
   'xcode_settings': {
     # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT!
     # This block adds *project-wide* configuration settings to each project
@@ -4698,7 +4623,7 @@
           ['ios_sdk_path==""', {
             'conditions': [
               # TODO(justincohen): Ninja only supports simulator for now.
-              ['"<(GENERATOR)"=="xcode" or ("<(GENERATOR)"=="ninja" and target_arch=="armv7")', {
+              ['"<(GENERATOR)"=="xcode"', {
                 'SDKROOT': 'iphoneos<(ios_sdk)',  # -isysroot
               }, {
                 'SDKROOT': 'iphonesimulator<(ios_sdk)',  # -isysroot
@@ -4712,6 +4637,7 @@
       ['OS=="ios"', {
         # Target both iPhone and iPad.
         'TARGETED_DEVICE_FAMILY': '1,2',
+        'VALID_ARCHS': 'armv7 i386',
       }],
       ['target_arch=="x64"', {
         'ARCHS': [
diff --git a/build/filename_rules.gypi b/build/filename_rules.gypi
index 7f7a1e6..bcfaf4f 100644
--- a/build/filename_rules.gypi
+++ b/build/filename_rules.gypi
@@ -92,6 +92,9 @@
     ['<(use_aura)==0 or OS!="win" or >(nacl_untrusted_build)==1', {
       'sources/': [ ['exclude', '_aurawin\\.(h|cc)$'] ]
     }],
+    ['<(use_aura)==0 or OS!="linux" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_auralinux\\.(h|cc)$'] ]
+    }],
     ['<(use_ash)==0 or >(nacl_untrusted_build)==1', {
       'sources/': [ ['exclude', '_ash(_browsertest|_unittest)?\\.(h|cc)$'],
                     ['exclude', '(^|/)ash/'],
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 67e60cd..b165f70 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -138,11 +138,15 @@
     args.append('--no-circular-check')
 
   # Default to ninja on linux, but only if no generator has explicitly been set.
+  # Also default to ninja on mac, but only when not building chrome/ios.
   # . -f / --format has precedence over the env var, no need to check for it
   # . set the env var only if it hasn't been set yet
   # . chromium.gyp_env has been applied to os.environ at this point already
   if sys.platform.startswith('linux') and not os.environ.get('GYP_GENERATORS'):
     os.environ['GYP_GENERATORS'] = 'ninja'
+  elif sys.platform == 'darwin' and not os.environ.get('GYP_GENERATORS') and \
+      not 'OS=ios' in os.environ.get('GYP_DEFINES', []):
+    os.environ['GYP_GENERATORS'] = 'ninja'
 
   # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
   # to enfore syntax checking.
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index cda72a6..6f8b3ff 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -17,6 +17,10 @@
   echo "--[no-]chromeos-fonts: enable or disable installation of Chrome OS"\
        "fonts"
   echo "--no-prompt: silently select standard options/defaults"
+  echo "--quick-check: quickly try to determine if dependencies are installed"
+  echo "               (this avoids interactive prompts and sudo commands,"
+  echo "               so might not be 100% accurate)"
+  echo "--unsupported: attempt installation even on unsupported systems"
   echo "Script will prompt interactively if options not given."
   exit 1
 }
@@ -41,6 +45,7 @@
   --no-prompt)              do_default=1
                             do_quietly="-qq --assume-yes"
     ;;
+  --quick-check)            do_quick_check=1;;
   --unsupported)            do_unsupported=1;;
   *) usage;;
   esac
@@ -55,7 +60,7 @@
 # they're doing.
 gcel_issue="^GCEL"
 
-if [ 0 -eq "${do_unsupported-0}" ] ; then
+if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
   if ! egrep -q "($ubuntu_issue|$gcel_issue)" /etc/issue; then
     echo "ERROR: Only Ubuntu 12.04 (precise) through 13.04 (raring) are"\
         "currently supported" >&2
@@ -68,28 +73,28 @@
   fi
 fi
 
-if [ "x$(id -u)" != x0 ]; then
+if [ "x$(id -u)" != x0 ] && [ 0 -eq "${do_quick_check-0}" ]; then
   echo "Running as non-root user."
   echo "You might have to enter your password one or more times for 'sudo'."
   echo
 fi
 
 # Packages needed for chromeos only
-chromeos_dev_list="libbluetooth-dev libbrlapi-dev"
+chromeos_dev_list="libbluetooth-dev"
 
 # Packages need for development
 dev_list="apache2.2-bin bison curl elfutils fakeroot flex g++ gperf
-          language-pack-fr libapache2-mod-php5 libasound2-dev libbrlapi-dev
-          libbz2-dev libcairo2-dev libcups2-dev libcurl4-gnutls-dev libelf-dev
-          libgconf2-dev libgl1-mesa-dev libglib2.0-dev libglu1-mesa-dev
-          libgnome-keyring-dev libgtk2.0-dev libkrb5-dev libnspr4-dev
-          libnss3-dev libpam0g-dev libpci-dev libpulse-dev libsctp-dev
-          libspeechd-dev libsqlite3-dev libssl-dev libudev-dev libwww-perl
-          libxslt1-dev libxss-dev libxt-dev libxtst-dev mesa-common-dev
-          openbox patch perl php5-cgi pkg-config python python-cherrypy3
-          python-dev python-psutil rpm ruby subversion ttf-dejavu-core
-          ttf-indic-fonts ttf-kochi-gothic ttf-kochi-mincho ttf-thai-tlwg
-          wdiff git-core libdrm-dev
+          language-pack-fr libapache2-mod-php5 libasound2-dev
+          libbrlapi-dev libbz2-dev libcairo2-dev libcap-dev libcups2-dev
+          libcurl4-gnutls-dev libelf-dev libgconf2-dev libgl1-mesa-dev
+          libglib2.0-dev libglu1-mesa-dev libgnome-keyring-dev libgtk2.0-dev
+          libkrb5-dev libnspr4-dev libnss3-dev libpam0g-dev libpci-dev
+          libpulse-dev libsctp-dev libspeechd-dev libsqlite3-dev libssl-dev
+          libudev-dev libwww-perl libxslt1-dev libxss-dev libxt-dev libxtst-dev
+          mesa-common-dev openbox patch perl php5-cgi pkg-config python
+          python-cherrypy3 python-dev python-psutil rpm ruby subversion
+          ttf-dejavu-core ttf-indic-fonts ttf-kochi-gothic ttf-kochi-mincho
+          ttf-thai-tlwg wdiff git-core libdrm-dev
           $chromeos_dev_list"
 
 # 64-bit systems need a minimum set of 32-bit compat packages for the pre-built
@@ -100,10 +105,10 @@
 fi
 
 # Run-time libraries required by chromeos only
-chromeos_lib_list="libpulse0 libbz2-1.0 libcurl4-gnutls-dev"
+chromeos_lib_list="libpulse0 libbz2-1.0"
 
 # Full list of required run-time libraries
-lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcups2 libexpat1
+lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcap2 libcups2 libexpat1
           libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0
           libgtk2.0-0 libpam0g libpango1.0-0 libpci3 libpcre3 libpixman-1-0
           libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6
@@ -119,14 +124,24 @@
           libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
           libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
 
-# arm cross toolchain packages needed to build chrome on arm
-arm_list="libc6-armel-cross libc6-dev-armel-cross libgcc1-armel-cross
-          libgomp1-armel-cross linux-libc-dev-armel-cross
-          libgcc1-dbg-armel-cross libgomp1-dbg-armel-cross
-          binutils-arm-linux-gnueabi cpp-arm-linux-gnueabi
-          gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
-          libmudflap0-dbg-armel-cross"
+# arm cross toolchain packages needed to build chrome on armhf
+arm_list="libc6-armhf-cross libc6-dev-armhf-cross libgcc1-armhf-cross
+          libgomp1-armhf-cross linux-libc-dev-armhf-cross
+          libgcc1-dbg-armhf-cross libgomp1-dbg-armhf-cross
+          binutils-arm-linux-gnueabihf cpp-arm-linux-gnueabihf
+          gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
+          libmudflap0-dbg-armhf-cross"
 
+# Old armel cross toolchain packages
+armel_list="libc6-armel-cross libc6-dev-armel-cross libgcc1-armel-cross
+            libgomp1-armel-cross linux-libc-dev-armel-cross
+            libgcc1-dbg-armel-cross libgomp1-dbg-armel-cross
+            binutils-arm-linux-gnueabi cpp-arm-linux-gnueabi
+            gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
+            libmudflap0-dbg-armel-cross"
+
+# TODO(sbc): remove armel once the armhf transition is complete
+arm_list="$arm_list $armel_list"
 
 # Some package names have changed over time
 if package_exists ttf-mscorefonts-installer; then
@@ -203,7 +218,7 @@
   done
 }
 
-if test "$do_inst_syms" = ""
+if test "$do_inst_syms" = "" && test 0 -eq ${do_quick_check-0}
 then
   echo "This script installs all tools and libraries needed to build Chromium."
   echo ""
@@ -216,9 +231,9 @@
   fi
 fi
 if test "$do_inst_syms" = "1"; then
-  echo "Installing debugging symbols."
+  echo "Including debugging symbols."
 else
-  echo "Skipping installation of debugging symbols."
+  echo "Skipping debugging symbols."
   dbg_list=
 fi
 
@@ -229,19 +244,59 @@
   arm_list="$arm_list g++-multilib"
 fi
 
-if test "$do_inst_arm" = "1"; then
+if test "$do_inst_arm" = "1" ; then
   . /etc/lsb-release
-  if test "$DISTRIB_CODENAME" != "precise"; then
+  if ! [ "${DISTRIB_CODENAME}" = "precise" -o \
+      1 -eq "${do_unsupported-0}" ]; then
     echo "ERROR: Installing the ARM cross toolchain is only available on" \
          "Ubuntu precise." >&2
     exit 1
   fi
-  echo "Installing ARM cross toolchain."
+  echo "Including ARM cross toolchain."
 else
-  echo "Skipping installation of ARM cross toolchain."
+  echo "Skipping ARM cross toolchain."
   arm_list=
 fi
 
+packages="$(echo "${dev_list} ${lib_list} ${dbg_list} ${arm_list}" | \
+  tr " " "\n" | sort -u | tr "\n" " ")"
+
+if [ 1 -eq "${do_quick_check-0}" ] ; then
+  failed_check="$(dpkg-query -W -f '${PackageSpec}:${Status}\n' \
+    ${packages} 2>&1 | grep -v "ok installed" || :)"
+  if [ -n "${failed_check}" ]; then
+    echo
+    nomatch="$(echo "${failed_check}" | \
+      sed -e "s/^No packages found matching \(.*\).$/\1/;t;d")"
+    missing="$(echo "${failed_check}" | \
+      sed -e "/^No packages found matching/d;s/^\(.*\):.*$/\1/")"
+    if [ "$nomatch" ]; then
+      # Distinguish between packages that actually aren't available to the
+      # system (i.e. not in any repo) and packages that just aren't known to
+      # dpkg (i.e. managed by apt).
+      unknown=""
+      for p in ${nomatch}; do
+        if apt-cache show ${p} > /dev/null 2>&1; then
+          missing="${p}\n${missing}"
+        else
+          unknown="${p}\n${unknown}"
+        fi
+      done
+      if [ -n "${unknown}" ]; then
+        echo "WARNING: The following packages are unknown to your system"
+        echo "(maybe missing a repo or need to 'sudo apt-get update'):"
+        echo -e "${unknown}" | sed -e "s/^/  /"
+      fi
+    fi
+    if [ -n "${missing}" ]; then
+      echo "WARNING: The following packages are not installed:"
+      echo -e "${missing}" | sed -e "s/^/  /"
+    fi
+    exit 1
+  fi
+  exit 0
+fi
+
 sudo apt-get update
 
 # We initially run "apt-get" with the --reinstall option and parse its output.
@@ -249,7 +304,6 @@
 # without accidentally promoting any packages from "auto" to "manual".
 # We then re-run "apt-get" with just the list of missing packages.
 echo "Finding missing packages..."
-packages="${dev_list} ${lib_list} ${dbg_list} ${arm_list}"
 # Intentionally leaving $packages unquoted so it's more readable.
 echo "Packages required: " $packages
 echo
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index de54c76..afc2bab 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -122,6 +122,7 @@
         'native_lib_target%': '',
         'use_content_linker%': 0,
         'enable_content_linker_tests%': 0,
+        'is_test_apk%': 0,
       },
       'conditions': [
         ['gyp_managed_install == 1 and native_lib_target != ""', {
@@ -134,12 +135,17 @@
         }, {
           'apk_package_native_libs_dir': '<(intermediate_dir)/libs',
         }],
+        ['is_test_apk == 0 and emma_coverage != 0', {
+          'emma_instrument': 1,
+        },{
+          'emma_instrument': 0,
+        }],
       ],
     },
     'native_lib_target%': '',
     'use_content_linker%': 0,
     'enable_content_linker_tests%': 0,
-    'emma_instrument': '<(emma_coverage)',
+    'emma_instrument': '<(emma_instrument)',
     'apk_package_native_libs_dir': '<(apk_package_native_libs_dir)',
     'unsigned_standalone_apk_path': '<(unsigned_standalone_apk_path)',
     'extra_native_libs': [],
diff --git a/build/json_schema_bundle_compile.gypi b/build/json_schema_bundle_compile.gypi
index b6107cf..3f6021a 100644
--- a/build/json_schema_bundle_compile.gypi
+++ b/build/json_schema_bundle_compile.gypi
@@ -43,6 +43,7 @@
         '--namespace=<(root_namespace)',
         '--generator=cpp-bundle',
         '<@(schema_files)',
+        '<@(non_compiled_schema_files)',
       ],
       'message': 'Generating C++ API bundle code',
       'process_outputs_as_sources': 1,
diff --git a/build/landmine_utils.py b/build/landmine_utils.py
index 021fc9b..4b8b257 100644
--- a/build/landmine_utils.py
+++ b/build/landmine_utils.py
@@ -109,6 +109,6 @@
     elif IsLinux():
       return 'ninja'
     elif IsMac():
-      return 'xcode'
+      return 'ninja'
     else:
       assert False, 'Don\'t know what builder we\'re using!'
diff --git a/build/linux/install-arm-sysroot.py b/build/linux/install-arm-sysroot.py
index d1be1fd..5ba4411 100755
--- a/build/linux/install-arm-sysroot.py
+++ b/build/linux/install-arm-sysroot.py
@@ -22,7 +22,7 @@
 - ./tools/trusted_cross_toolchains/trusted-toolchain-creator.armel.precise.sh \
     BuildJail $SRC/out/arm-sysroot.tar.gz
 - gsutil cp -a public-read $SRC/out/arm-sysroot.tar.gz \
-    nativeclient-archive2/toolchain/$NACL_REV/naclsdk_linux_arm-trusted.tgz
+    nativeclient-archive2/toolchain/$NACL_REV/sysroot-arm-trusted.tgz
 """
 
 import os
@@ -34,9 +34,13 @@
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 URL_PREFIX = 'https://commondatastorage.googleapis.com'
 URL_PATH = 'nativeclient-archive2/toolchain'
-REVISION = 12203
-TARBALL = 'naclsdk_linux_arm-trusted.tgz'
+REVISION = 12292
+TARBALL = 'sysroot-arm-trusted.tgz'
 
+# TODO(sbc): remove armel support once the transision to armhf
+# is complete.
+REVISION_ARMEL = 12203
+TARBALL_ARMEL = 'naclsdk_linux_arm-trusted.tgz'
 
 def main(args):
   if '--linux-only' in args:
@@ -51,7 +55,10 @@
 
   src_root = os.path.dirname(os.path.dirname(SCRIPT_DIR))
   sysroot = os.path.join(src_root, 'arm-sysroot')
-  url = "%s/%s/%s/%s" % (URL_PREFIX, URL_PATH, REVISION, TARBALL)
+  if '-gnueabihf-' in os.environ.get('CC', ''):
+    url = "%s/%s/%s/%s" % (URL_PREFIX, URL_PATH, REVISION, TARBALL)
+  else:
+    url = "%s/%s/%s/%s" % (URL_PREFIX, URL_PATH, REVISION_ARMEL, TARBALL_ARMEL)
 
   stamp = os.path.join(sysroot, ".stamp")
   if os.path.exists(stamp):
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index d311728..68e1c0a 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -34,6 +34,27 @@
       # added back to Chrome OS. Don't try to use GTK on Chrome OS.
       'targets': [
         {
+          'target_name': 'gdk',
+          'type': 'none',
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags gdk-2.0)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gdk-2.0)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gdk-2.0)',
+                ],
+              },
+            }],
+          ],
+        },
+        {
           'target_name': 'gtk',
           'type': 'none',
           'toolsets': ['host', 'target'],
@@ -95,93 +116,59 @@
             }],
           ],
         },
-        {
-          'target_name': 'gdk',
-          'type': 'none',
-          'conditions': [
-            ['_toolset=="target"', {
-              'direct_dependent_settings': {
-                'cflags': [
-                  '<!@(<(pkg-config) --cflags gdk-2.0)',
-                ],
-              },
-              'link_settings': {
-                'ldflags': [
-                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gdk-2.0)',
-                ],
-                'libraries': [
-                  '<!@(<(pkg-config) --libs-only-l gdk-2.0)',
-                ],
-              },
-            }],
-          ],
-        },
       ],  # targets
     }],
   ],  # conditions
   'targets': [
     {
-      'target_name': 'ssl',
+      'target_name': 'dbus',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(<(pkg-config) --cflags dbus-1)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(<(pkg-config) --libs-only-L --libs-only-other dbus-1)',
+        ],
+        'libraries': [
+          '<!@(<(pkg-config) --libs-only-l dbus-1)',
+        ],
+      },
+    },
+    {
+      'target_name': 'dridrm',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(<(pkg-config) --cflags libdrm)',
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          '<!@(<(pkg-config) --libs-only-l libdrm)',
+        ],
+      },
+    },
+    {
+      'target_name': 'fontconfig',
       'type': 'none',
       'conditions': [
         ['_toolset=="target"', {
-          'conditions': [
-            ['use_openssl==1', {
-              'dependencies': [
-                '../../third_party/openssl/openssl.gyp:openssl',
-              ],
-            }],
-            ['use_openssl==0 and use_system_ssl==0', {
-              'dependencies': [
-                '../../net/third_party/nss/ssl.gyp:libssl',
-              ],
-              'direct_dependent_settings': {
-                'include_dirs+': [
-                  # We need for our local copies of the libssl3 headers to come
-                  # before other includes, as we are shadowing system headers.
-                  '<(DEPTH)/net/third_party/nss/ssl',
-                ],
-                'cflags': [
-                  '<!@(<(pkg-config) --cflags nss)',
-                ],
-              },
-              'link_settings': {
-                'ldflags': [
-                  '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
-                ],
-                'libraries': [
-                  '<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
-                ],
-              },
-            }],
-            ['use_openssl==0 and use_system_ssl==1', {
-              'direct_dependent_settings': {
-                'cflags': [
-                  '<!@(<(pkg-config) --cflags nss)',
-                ],
-                'defines': [
-                  'USE_SYSTEM_SSL',
-                ],
-              },
-              'link_settings': {
-                'ldflags': [
-                  '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
-                ],
-                'libraries': [
-                  '<!@(<(pkg-config) --libs-only-l nss)',
-                ],
-              },
-            }],
-            ['use_openssl==0 and clang==1', {
-              'direct_dependent_settings': {
-                'cflags': [
-                  # There is a broken header guard in /usr/include/nss/secmod.h:
-                  # https://bugzilla.mozilla.org/show_bug.cgi?id=884072
-                  '-Wno-header-guard',
-                ],
-              },
-            }],
-          ]
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags fontconfig)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other fontconfig)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l fontconfig)',
+            ],
+          },
         }],
       ],
     },
@@ -207,27 +194,6 @@
       ],
     },
     {
-      'target_name': 'fontconfig',
-      'type': 'none',
-      'conditions': [
-        ['_toolset=="target"', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags fontconfig)',
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(<(pkg-config) --libs-only-L --libs-only-other fontconfig)',
-            ],
-            'libraries': [
-              '<!@(<(pkg-config) --libs-only-l fontconfig)',
-            ],
-          },
-        }],
-      ],
-    },
-    {
       'target_name': 'gconf',
       'type': 'none',
       'conditions': [
@@ -327,6 +293,217 @@
       ],
     },
     {
+      'target_name': 'glib',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'glib_packages': 'glib-2.0 gmodule-2.0 gobject-2.0 gthread-2.0',
+      },
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags <(glib_packages))',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other <(glib_packages))',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l <(glib_packages))',
+            ],
+          },
+        }, {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(pkg-config --cflags <(glib_packages))',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(pkg-config --libs-only-L --libs-only-other <(glib_packages))',
+            ],
+            'libraries': [
+              '<!@(pkg-config --libs-only-l <(glib_packages))',
+            ],
+          },
+        }],
+        ['use_x11==1', {
+          'link_settings': {
+            'libraries': [ '-lXtst' ]
+          }
+        }],
+      ],
+    },
+    {
+      'target_name': 'gnome_keyring',
+      'type': 'none',
+      'conditions': [
+        ['use_gnome_keyring==1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
+            ],
+            'defines': [
+              'USE_GNOME_KEYRING',
+            ],
+            'conditions': [
+              ['linux_link_gnome_keyring==0', {
+                'defines': ['DLOPEN_GNOME_KEYRING'],
+              }],
+            ],
+          },
+          'conditions': [
+            ['linux_link_gnome_keyring!=0', {
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
+                ],
+              },
+            }, {
+              'conditions': [
+                ['OS=="linux"', {
+                 'link_settings': {
+                   'libraries': [
+                     '-ldl',
+                   ],
+                 },
+                }],
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      # The unit tests use a few convenience functions from the GNOME
+      # Keyring library directly. We ignore linux_link_gnome_keyring and
+      # link directly in this version of the target to allow this.
+      # *** Do not use this target in the main binary! ***
+      'target_name': 'gnome_keyring_direct',
+      'type': 'none',
+      'conditions': [
+        ['use_gnome_keyring==1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
+            ],
+            'defines': [
+              'USE_GNOME_KEYRING',
+            ],
+            'conditions': [
+              ['linux_link_gnome_keyring==0', {
+                'defines': ['DLOPEN_GNOME_KEYRING'],
+              }],
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'libbrlapi',
+      'type': 'static_library',
+      'dependencies': [
+        '../../base/base.gyp:base',
+      ],
+      'all_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+        'defines': [
+          'USE_BRLAPI',
+        ],
+        'conditions': [
+          ['linux_link_libbrlapi==1', {
+            'link_settings': {
+              'libraries': [
+                '-lbrlapi',
+              ],
+            }
+          }],
+        ],
+      },
+      'hard_dependency': 1,
+      'actions': [
+        {
+          'variables': {
+            'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libbrlapi.h',
+            'output_cc': '<(INTERMEDIATE_DIR)/libbrlapi_loader.cc',
+            'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+          },
+          'action_name': 'generate_brlapi_loader',
+          'inputs': [
+            '<(generator)',
+          ],
+          'outputs': [
+            '<(output_h)',
+            '<(output_cc)',
+          ],
+          'action': ['python',
+                     '<(generator)',
+                     '--name', 'LibBrlapiLoader',
+                     '--output-h', '<(output_h)',
+                     '--output-cc', '<(output_cc)',
+                     '--header', '<brlapi.h>',
+                     '--link-directly=<(linux_link_libbrlapi)',
+                     'brlapi_getHandleSize',
+                     'brlapi_error_location',
+                     'brlapi_expandKeyCode',
+                     'brlapi_strerror',
+                     'brlapi__acceptKeys',
+                     'brlapi__openConnection',
+                     'brlapi__closeConnection',
+                     'brlapi__getDisplaySize',
+                     'brlapi__enterTtyModeWithPath',
+                     'brlapi__leaveTtyMode',
+                     'brlapi__writeDots',
+                     'brlapi__readKey',
+          ],
+          'message': 'Generating libbrlapi library loader.',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'libcap',
+      'type': 'none',
+      'link_settings': {
+        'libraries': [
+          '-lcap',
+        ],
+      },
+    },
+    {
+      'target_name': 'libgcrypt',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target" and use_cups==1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(libgcrypt-config --cflags)',
+            ],
+          },
+          'link_settings': {
+            'libraries': [
+              '<!@(libgcrypt-config --libs)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
       'target_name': 'libpci',
       'type': 'static_library',
       'cflags': [
@@ -391,6 +568,15 @@
       ],
     },
     {
+      'target_name': 'libresolv',
+      'type': 'none',
+      'link_settings': {
+        'libraries': [
+          '-lresolv',
+        ],
+      },
+    },
+    {
       'target_name': 'libspeechd',
       'type': 'static_library',
       'direct_dependent_settings': {
@@ -470,67 +656,126 @@
       ],
     },
     {
-      'target_name': 'libbrlapi',
-      'type': 'static_library',
-      'dependencies': [
-        '../../base/base.gyp:base',
-      ],
-      'all_dependent_settings': {
-        'include_dirs': [
-          '<(SHARED_INTERMEDIATE_DIR)',
-        ],
-        'defines': [
-          'USE_BRLAPI',
-        ],
-        'conditions': [
-          ['linux_link_libbrlapi==1', {
-            'link_settings': {
-              'libraries': [
-                '-lbrlapi',
-              ],
-            }
-          }],
-        ],
-      },
-      'hard_dependency': 1,
-      'actions': [
-        {
-          'variables': {
-            'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libbrlapi.h',
-            'output_cc': '<(INTERMEDIATE_DIR)/libbrlapi_loader.cc',
-            'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+      'target_name': 'pangocairo',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags pangocairo pangoft2)',
+            ],
           },
-          'action_name': 'generate_brlapi_loader',
-          'inputs': [
-            '<(generator)',
-          ],
-          'outputs': [
-            '<(output_h)',
-            '<(output_cc)',
-          ],
-          'action': ['python',
-                     '<(generator)',
-                     '--name', 'LibBrlapiLoader',
-                     '--output-h', '<(output_h)',
-                     '--output-cc', '<(output_cc)',
-                     '--header', '<brlapi.h>',
-                     '--link-directly=<(linux_link_libbrlapi)',
-                     'brlapi_getHandleSize',
-                     'brlapi_error_location',
-                     'brlapi_expandKeyCode',
-                     'brlapi_strerror',
-                     'brlapi__acceptKeys',
-                     'brlapi__openConnection',
-                     'brlapi__closeConnection',
-                     'brlapi__getDisplaySize',
-                     'brlapi__enterTtyModeWithPath',
-                     'brlapi__leaveTtyMode',
-                     'brlapi__writeDots',
-                     'brlapi__readKey',
-          ],
-          'message': 'Generating libbrlapi library loader.',
-          'process_outputs_as_sources': 1,
-        },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other pangocairo pangoft2)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l pangocairo pangoft2)',
+            ],
+          },
+        }, {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(pkg-config --cflags pangocairo pangoft2)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(pkg-config --libs-only-L --libs-only-other pangocairo pangoft2)',
+            ],
+            'libraries': [
+              '<!@(pkg-config --libs-only-l pangocairo pangoft2)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'ssl',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'conditions': [
+            ['use_openssl==1', {
+              'dependencies': [
+                '../../third_party/openssl/openssl.gyp:openssl',
+              ],
+            }],
+            ['use_openssl==0 and use_system_ssl==0', {
+              'dependencies': [
+                '../../net/third_party/nss/ssl.gyp:libssl',
+              ],
+              'direct_dependent_settings': {
+                'include_dirs+': [
+                  # We need for our local copies of the libssl3 headers to come
+                  # before other includes, as we are shadowing system headers.
+                  '<(DEPTH)/net/third_party/nss/ssl',
+                ],
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags nss)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
+                ],
+              },
+            }],
+            ['use_openssl==0 and use_system_ssl==1', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags nss)',
+                ],
+                'defines': [
+                  'USE_SYSTEM_SSL',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l nss)',
+                ],
+              },
+            }],
+            ['use_openssl==0 and clang==1', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  # There is a broken header guard in /usr/include/nss/secmod.h:
+                  # https://bugzilla.mozilla.org/show_bug.cgi?id=884072
+                  '-Wno-header-guard',
+                ],
+              },
+            }],
+          ]
+        }],
+      ],
+    },
+    {
+      'target_name': 'udev',
+      'type': 'none',
+      'conditions': [
+        # libudev is not available on *BSD
+        ['_toolset=="target" and os_bsd!=1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libudev)'
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libudev)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libudev)',
+            ],
+          },
+        }],
       ],
     },
     {
@@ -647,241 +892,5 @@
         }],
       ],
     },
-    {
-      'target_name': 'libgcrypt',
-      'type': 'none',
-      'conditions': [
-        ['_toolset=="target" and use_cups==1', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(libgcrypt-config --cflags)',
-            ],
-          },
-          'link_settings': {
-            'libraries': [
-              '<!@(libgcrypt-config --libs)',
-            ],
-          },
-        }],
-      ],
-    },
-    {
-      'target_name': 'gnome_keyring',
-      'type': 'none',
-      'conditions': [
-        ['use_gnome_keyring==1', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
-            ],
-            'defines': [
-              'USE_GNOME_KEYRING',
-            ],
-            'conditions': [
-              ['linux_link_gnome_keyring==0', {
-                'defines': ['DLOPEN_GNOME_KEYRING'],
-              }],
-            ],
-          },
-          'conditions': [
-            ['linux_link_gnome_keyring!=0', {
-              'link_settings': {
-                'ldflags': [
-                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
-                ],
-                'libraries': [
-                  '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
-                ],
-              },
-            }, {
-              'conditions': [
-                ['OS=="linux"', {
-                 'link_settings': {
-                   'libraries': [
-                     '-ldl',
-                   ],
-                 },
-                }],
-              ],
-            }],
-          ],
-        }],
-      ],
-    },
-    {
-      # The unit tests use a few convenience functions from the GNOME
-      # Keyring library directly. We ignore linux_link_gnome_keyring and
-      # link directly in this version of the target to allow this.
-      # *** Do not use this target in the main binary! ***
-      'target_name': 'gnome_keyring_direct',
-      'type': 'none',
-      'conditions': [
-        ['use_gnome_keyring==1', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
-            ],
-            'defines': [
-              'USE_GNOME_KEYRING',
-            ],
-            'conditions': [
-              ['linux_link_gnome_keyring==0', {
-                'defines': ['DLOPEN_GNOME_KEYRING'],
-              }],
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
-            ],
-            'libraries': [
-              '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
-            ],
-          },
-        }],
-      ],
-    },
-    {
-      'target_name': 'dbus',
-      'type': 'none',
-      'direct_dependent_settings': {
-        'cflags': [
-          '<!@(<(pkg-config) --cflags dbus-1)',
-        ],
-      },
-      'link_settings': {
-        'ldflags': [
-          '<!@(<(pkg-config) --libs-only-L --libs-only-other dbus-1)',
-        ],
-        'libraries': [
-          '<!@(<(pkg-config) --libs-only-l dbus-1)',
-        ],
-      },
-    },
-    {
-      'target_name': 'glib',
-      'type': 'none',
-      'toolsets': ['host', 'target'],
-      'variables': {
-        'glib_packages': 'glib-2.0 gmodule-2.0 gobject-2.0 gthread-2.0',
-      },
-      'conditions': [
-        ['_toolset=="target"', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags <(glib_packages))',
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(<(pkg-config) --libs-only-L --libs-only-other <(glib_packages))',
-            ],
-            'libraries': [
-              '<!@(<(pkg-config) --libs-only-l <(glib_packages))',
-            ],
-          },
-        }, {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(pkg-config --cflags <(glib_packages))',
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(pkg-config --libs-only-L --libs-only-other <(glib_packages))',
-            ],
-            'libraries': [
-              '<!@(pkg-config --libs-only-l <(glib_packages))',
-            ],
-          },
-        }],
-        ['use_x11==1', {
-          'link_settings': {
-            'libraries': [ '-lXtst' ]
-          }
-        }],
-      ],
-    },
-    {
-      'target_name': 'pangocairo',
-      'type': 'none',
-      'toolsets': ['host', 'target'],
-      'conditions': [
-        ['_toolset=="target"', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags pangocairo pangoft2)',
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(<(pkg-config) --libs-only-L --libs-only-other pangocairo pangoft2)',
-            ],
-            'libraries': [
-              '<!@(<(pkg-config) --libs-only-l pangocairo pangoft2)',
-            ],
-          },
-        }, {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(pkg-config --cflags pangocairo pangoft2)',
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(pkg-config --libs-only-L --libs-only-other pangocairo pangoft2)',
-            ],
-            'libraries': [
-              '<!@(pkg-config --libs-only-l pangocairo pangoft2)',
-            ],
-          },
-        }],
-      ],
-    },
-    {
-      'target_name': 'libresolv',
-      'type': 'none',
-      'link_settings': {
-        'libraries': [
-          '-lresolv',
-        ],
-      },
-    },
-    {
-      'target_name': 'udev',
-      'type': 'none',
-      'conditions': [
-        # libudev is not available on *BSD
-        ['_toolset=="target" and os_bsd!=1', {
-          'direct_dependent_settings': {
-            'cflags': [
-              '<!@(<(pkg-config) --cflags libudev)'
-            ],
-          },
-          'link_settings': {
-            'ldflags': [
-              '<!@(<(pkg-config) --libs-only-L --libs-only-other libudev)',
-            ],
-            'libraries': [
-              '<!@(<(pkg-config) --libs-only-l libudev)',
-            ],
-          },
-        }],
-      ],
-    },
-    {
-      'target_name': 'dridrm',
-      'type': 'none',
-      'direct_dependent_settings': {
-        'cflags': [
-          '<!@(<(pkg-config) --cflags libdrm)',
-        ],
-      },
-      'link_settings': {
-        'libraries': [
-          '<!@(<(pkg-config) --libs-only-l libdrm)',
-        ],
-      },
-    },
   ],
 }
diff --git a/build/sanitize-mac-build-log.sed b/build/sanitize-mac-build-log.sed
old mode 100755
new mode 100644
index 3312eac..b4111c7
--- a/build/sanitize-mac-build-log.sed
+++ b/build/sanitize-mac-build-log.sed
@@ -1,5 +1,3 @@
-#!/bin/echo Use sanitize-mac-build-log.sh or sed -f
-
 # Copyright (c) 2012 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.
@@ -17,8 +15,8 @@
 # Xcode prints a short "compiling foobar.o" line followed by the lengthy
 # full command line.  These deletions drop the command line.
 \|^    /Developer/usr/bin/|d
-\|^    /Developer/Library/PrivateFrameworks/DevToolsCore.framework/|d
-\|^    /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/|d
+\|^    /Developer/Library/PrivateFrameworks/DevToolsCore\.framework/|d
+\|^    /Developer/Library/Xcode/Plug-ins/CoreBuildTasks\.xcplugin/|d
 
 # Drop any goma command lines as well.
 \|^    .*/gomacc |d
@@ -28,8 +26,8 @@
 \|^    /Users/[^/]*/bin/|d
 
 # There's already a nice note for bindings, don't need the command line.
-\|^python scripts/rule_binding.py|d
+\|^python scripts/rule_binding\.py|d
 
 # Shorten the "compiling foobar.o" line.
-s|^Distributed-CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2|    CC \1|
-s|^CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2|    CC \1|
+s|^Distributed-CompileC (.*) normal i386 c\+\+ com\.apple\.compilers\.gcc\.4_2|    CC \1|
+s|^CompileC (.*) normal i386 c\+\+ com\.apple\.compilers\.gcc\.4_2|    CC \1|
diff --git a/build/sanitize-mac-build-log.sh b/build/sanitize-mac-build-log.sh
index dc743fa..df5a7af 100755
--- a/build/sanitize-mac-build-log.sh
+++ b/build/sanitize-mac-build-log.sh
@@ -2,5 +2,4 @@
 # Copyright (c) 2010 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.
-sed -f `dirname "${0}"`/`basename "${0}" sh`sed
-
+sed -r -f `dirname "${0}"`/`basename "${0}" sh`sed
diff --git a/build/sanitize-win-build-log.sed b/build/sanitize-win-build-log.sed
old mode 100755
new mode 100644
index ce51654..4691b76
--- a/build/sanitize-win-build-log.sed
+++ b/build/sanitize-win-build-log.sed
@@ -1,5 +1,3 @@
-#!/bin/echo Use sanitize-win-build-log.sh or sed -f
-
 # Copyright (c) 2012 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.
@@ -11,8 +9,8 @@
 /The operation completed successfully\./d
 
 # Drop parallelization indicators on lines.
-s/^[0-9]\+>//
+s/^[0-9]+>//
 
 # Shorten bindings generation lines
-s/^.*"\(perl\|[^"]\+perl\.exe\)".*deprecated_generate_bindings\.pl".*\("[^"]\+\.idl"\).*$/  deprecated_generate_bindings \2/
-s/^.*"python".*idl_compiler\.py".*\("[^"]\+\.idl"\).*$/  idl_compiler \1/
+s/^.*"(perl|[^"]+perl\.exe)".*deprecated_generate_bindings\.pl".*("[^"]+\.idl").*$/  deprecated_generate_bindings \2/
+s/^.*"python".*idl_compiler\.py".*("[^"]+\.idl").*$/  idl_compiler \1/
diff --git a/build/sanitize-win-build-log.sh b/build/sanitize-win-build-log.sh
index dc743fa..df5a7af 100755
--- a/build/sanitize-win-build-log.sh
+++ b/build/sanitize-win-build-log.sh
@@ -2,5 +2,4 @@
 # Copyright (c) 2010 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.
-sed -f `dirname "${0}"`/`basename "${0}" sh`sed
-
+sed -r -f `dirname "${0}"`/`basename "${0}" sh`sed
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index e74f78a..5481d49 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=230120
+LASTCHANGE=232015
diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink
index 9f16e01..bd0fa8b 100644
--- a/build/util/LASTCHANGE.blink
+++ b/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=160175
+LASTCHANGE=160934
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 6a50cd2..dbe07f1 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -6,7 +6,7 @@
 This file is used for making non-code changes to trigger buildbot cycles. Make
 any modification below this line.
 
-======================================================================
+=====================================================================
 
 Let's make a story. Add one sentence for every commit:
 
diff --git a/cc/DEPS b/cc/DEPS
index 165444f..4e1cc74 100644
--- a/cc/DEPS
+++ b/cc/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+gpu/GLES2",
   "+gpu/command_buffer/client/context_support.h",
+  "+gpu/command_buffer/common/gpu_memory_allocation.h",
   "+gpu/command_buffer/common/mailbox.h",
   "+media",
   "+skia/ext",
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 9e84e3f..76358f3 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -196,4 +196,8 @@
 def GetPreferredTrySlaves(project, change):
   return [
     'linux_layout_rel',
+    'win_gpu',
+    'linux_gpu',
+    'mac_gpu',
+    'mac_gpu_retina',
     ]
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index 6b45917..6b5966b 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -33,7 +33,8 @@
 static const char* const s_targetPropertyNames[] = {
   "Transform",
   "Opacity",
-  "Filter"
+  "Filter",
+  "BackgroundColor"
 };
 
 COMPILE_ASSERT(static_cast<int>(cc::Animation::TargetPropertyEnumSize) ==
diff --git a/cc/animation/animation.h b/cc/animation/animation.h
index 9946298..f640318 100644
--- a/cc/animation/animation.h
+++ b/cc/animation/animation.h
@@ -47,6 +47,7 @@
     Transform = 0,
     Opacity,
     Filter,
+    BackgroundColor,
     // This sentinel must be last.
     TargetPropertyEnumSize
   };
diff --git a/cc/animation/animation_curve.cc b/cc/animation/animation_curve.cc
index cf04da7..65c21db 100644
--- a/cc/animation/animation_curve.cc
+++ b/cc/animation/animation_curve.cc
@@ -8,6 +8,13 @@
 
 namespace cc {
 
+const ColorAnimationCurve* AnimationCurve::ToColorAnimationCurve() const {
+  DCHECK(Type() == AnimationCurve::Color);
+  return static_cast<const ColorAnimationCurve*>(this);
+}
+
+AnimationCurve::CurveType ColorAnimationCurve::Type() const { return Color; }
+
 const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const {
   DCHECK(Type() == AnimationCurve::Float);
   return static_cast<const FloatAnimationCurve*>(this);
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index f4cdb10..f84bb1a 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -16,6 +16,7 @@
 
 namespace cc {
 
+class ColorAnimationCurve;
 class FilterAnimationCurve;
 class FloatAnimationCurve;
 class TransformAnimationCurve;
@@ -24,7 +25,7 @@
 // An animation curve is a function that returns a value given a time.
 class CC_EXPORT AnimationCurve {
  public:
-  enum CurveType { Float, Transform, Filter };
+  enum CurveType { Color, Float, Transform, Filter };
 
   virtual ~AnimationCurve() {}
 
@@ -32,11 +33,22 @@
   virtual CurveType Type() const = 0;
   virtual scoped_ptr<AnimationCurve> Clone() const = 0;
 
+  const ColorAnimationCurve* ToColorAnimationCurve() const;
   const FloatAnimationCurve* ToFloatAnimationCurve() const;
   const TransformAnimationCurve* ToTransformAnimationCurve() const;
   const FilterAnimationCurve* ToFilterAnimationCurve() const;
 };
 
+class CC_EXPORT ColorAnimationCurve : public AnimationCurve {
+ public:
+  virtual ~ColorAnimationCurve() {}
+
+  virtual SkColor GetValue(double t) const = 0;
+
+  // Partial Animation implementation.
+  virtual CurveType Type() const OVERRIDE;
+};
+
 class CC_EXPORT FloatAnimationCurve : public AnimationCurve {
  public:
   virtual ~FloatAnimationCurve() {}
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index 14dfd9c..d855dec 100644
--- a/cc/animation/keyframed_animation_curve.cc
+++ b/cc/animation/keyframed_animation_curve.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/animation/keyframed_animation_curve.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/box_f.h"
 
 namespace cc {
@@ -26,6 +27,17 @@
   keyframes.push_back(keyframe.Pass());
 }
 
+template <class Keyframes>
+float GetProgress(double t, size_t i, const Keyframes& keyframes) {
+  float progress =
+      static_cast<float>((t - keyframes[i]->Time()) /
+                         (keyframes[i + 1]->Time() - keyframes[i]->Time()));
+
+  if (keyframes[i]->timing_function())
+    progress = keyframes[i]->timing_function()->GetValue(progress);
+  return progress;
+}
+
 scoped_ptr<TimingFunction> CloneTimingFunction(
     const TimingFunction* timing_function) {
   DCHECK(timing_function);
@@ -46,6 +58,31 @@
   return time_;
 }
 
+scoped_ptr<ColorKeyframe> ColorKeyframe::Create(
+    double time,
+    SkColor value,
+    scoped_ptr<TimingFunction> timing_function) {
+  return make_scoped_ptr(
+      new ColorKeyframe(time, value, timing_function.Pass()));
+}
+
+ColorKeyframe::ColorKeyframe(double time,
+                             SkColor value,
+                             scoped_ptr<TimingFunction> timing_function)
+    : Keyframe(time, timing_function.Pass()),
+      value_(value) {}
+
+ColorKeyframe::~ColorKeyframe() {}
+
+SkColor ColorKeyframe::Value() const { return value_; }
+
+scoped_ptr<ColorKeyframe> ColorKeyframe::Clone() const {
+  scoped_ptr<TimingFunction> func;
+  if (timing_function())
+    func = CloneTimingFunction(timing_function());
+  return ColorKeyframe::Create(Time(), Value(), func.Pass());
+}
+
 scoped_ptr<FloatKeyframe> FloatKeyframe::Create(
     double time,
     float value,
@@ -127,6 +164,53 @@
   return FilterKeyframe::Create(Time(), Value(), func.Pass());
 }
 
+scoped_ptr<KeyframedColorAnimationCurve> KeyframedColorAnimationCurve::
+    Create() {
+  return make_scoped_ptr(new KeyframedColorAnimationCurve);
+}
+
+KeyframedColorAnimationCurve::KeyframedColorAnimationCurve() {}
+
+KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() {}
+
+void KeyframedColorAnimationCurve::AddKeyframe(
+    scoped_ptr<ColorKeyframe> keyframe) {
+  InsertKeyframe(keyframe.Pass(), keyframes_);
+}
+
+double KeyframedColorAnimationCurve::Duration() const {
+  return keyframes_.back()->Time() - keyframes_.front()->Time();
+}
+
+scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
+  scoped_ptr<KeyframedColorAnimationCurve> to_return(
+      KeyframedColorAnimationCurve::Create());
+  for (size_t i = 0; i < keyframes_.size(); ++i)
+    to_return->AddKeyframe(keyframes_[i]->Clone());
+  return to_return.PassAs<AnimationCurve>();
+}
+
+SkColor KeyframedColorAnimationCurve::GetValue(double t) const {
+  if (t <= keyframes_.front()->Time())
+    return keyframes_.front()->Value();
+
+  if (t >= keyframes_.back()->Time())
+    return keyframes_.back()->Value();
+
+  size_t i = 0;
+  for (; i < keyframes_.size() - 1; ++i) {
+    if (t < keyframes_[i + 1]->Time())
+      break;
+  }
+
+  float progress = GetProgress(t, i, keyframes_);
+
+  return gfx::Tween::ColorValueBetween(
+      progress, keyframes_[i]->Value(), keyframes_[i + 1]->Value());
+}
+
+// KeyframedFloatAnimationCurve
+
 scoped_ptr<KeyframedFloatAnimationCurve> KeyframedFloatAnimationCurve::
     Create() {
   return make_scoped_ptr(new KeyframedFloatAnimationCurve);
@@ -166,12 +250,7 @@
       break;
   }
 
-  float progress =
-      static_cast<float>((t - keyframes_[i]->Time()) /
-                         (keyframes_[i+1]->Time() - keyframes_[i]->Time()));
-
-  if (keyframes_[i]->timing_function())
-    progress = keyframes_[i]->timing_function()->GetValue(progress);
+  float progress = GetProgress(t, i, keyframes_);
 
   return keyframes_[i]->Value() +
       (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress;
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index 5892dc7..4b5ac3b 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -31,6 +31,26 @@
   DISALLOW_COPY_AND_ASSIGN(Keyframe);
 };
 
+class CC_EXPORT ColorKeyframe : public Keyframe {
+ public:
+  static scoped_ptr<ColorKeyframe> Create(
+      double time,
+      SkColor value,
+      scoped_ptr<TimingFunction> timing_function);
+  virtual ~ColorKeyframe();
+
+  SkColor Value() const;
+
+  scoped_ptr<ColorKeyframe> Clone() const;
+
+ private:
+  ColorKeyframe(double time,
+                SkColor value,
+                scoped_ptr<TimingFunction> timing_function);
+
+  SkColor value_;
+};
+
 class CC_EXPORT FloatKeyframe : public Keyframe {
  public:
   static scoped_ptr<FloatKeyframe> Create(
@@ -93,6 +113,32 @@
   FilterOperations value_;
 };
 
+class CC_EXPORT KeyframedColorAnimationCurve : public ColorAnimationCurve {
+ public:
+  // It is required that the keyframes be sorted by time.
+  static scoped_ptr<KeyframedColorAnimationCurve> Create();
+
+  virtual ~KeyframedColorAnimationCurve();
+
+  void AddKeyframe(scoped_ptr<ColorKeyframe> keyframe);
+
+  // AnimationCurve implementation
+  virtual double Duration() const OVERRIDE;
+  virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE;
+
+  // BackgrounColorAnimationCurve implementation
+  virtual SkColor GetValue(double t) const OVERRIDE;
+
+ private:
+  KeyframedColorAnimationCurve();
+
+  // Always sorted in order of increasing time. No two keyframes have the
+  // same time.
+  ScopedPtrVector<ColorKeyframe> keyframes_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyframedColorAnimationCurve);
+};
+
 class CC_EXPORT KeyframedFloatAnimationCurve : public FloatAnimationCurve {
  public:
   // It is required that the keyframes be sorted by time.
diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc
index 7eb3b1c..63e9866 100644
--- a/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/cc/animation/keyframed_animation_curve_unittest.cc
@@ -7,7 +7,9 @@
 #include "cc/animation/transform_operations.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/box_f.h"
+#include "ui/gfx/test/color_util.h"
 
 namespace cc {
 namespace {
@@ -22,6 +24,98 @@
   EXPECT_FLOAT_EQ(brightness, filter.at(0).amount());
 }
 
+// Tests that a color animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) {
+  SkColor color = SkColorSetARGB(255, 255, 255, 255);
+  scoped_ptr<KeyframedColorAnimationCurve> curve(
+      KeyframedColorAnimationCurve::Create());
+  curve->AddKeyframe(
+      ColorKeyframe::Create(0.0, color, scoped_ptr<TimingFunction>()));
+
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(-1.f));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.f));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.5f));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(1.f));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(2.f));
+}
+
+// Tests that a color animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) {
+  SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
+  SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
+  SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
+  scoped_ptr<KeyframedColorAnimationCurve> curve(
+      KeyframedColorAnimationCurve::Create());
+  curve->AddKeyframe(
+      ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));
+
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
+  EXPECT_SKCOLOR_EQ(color_midpoint, curve->GetValue(0.5f));
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
+}
+
+// Tests that a color animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) {
+  SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
+  SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
+  SkColor color_c = SkColorSetARGB(255, 0, 0, 255);
+  SkColor color_midpoint1 =
+      gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
+  SkColor color_midpoint2 =
+      gfx::Tween::ColorValueBetween(0.5, color_b, color_c);
+  scoped_ptr<KeyframedColorAnimationCurve> curve(
+      KeyframedColorAnimationCurve::Create());
+  curve->AddKeyframe(
+      ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(2.0, color_c, scoped_ptr<TimingFunction>()));
+
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
+  EXPECT_SKCOLOR_EQ(color_midpoint1, curve->GetValue(0.5f));
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
+  EXPECT_SKCOLOR_EQ(color_midpoint2, curve->GetValue(1.5f));
+  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(2.f));
+  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(3.f));
+}
+
+// Tests that a colro animation with multiple keys at a given time works sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) {
+  SkColor color_a = SkColorSetARGB(255, 64, 0, 0);
+  SkColor color_b = SkColorSetARGB(255, 192, 0, 0);
+
+  scoped_ptr<KeyframedColorAnimationCurve> curve(
+      KeyframedColorAnimationCurve::Create());
+  curve->AddKeyframe(
+      ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(1.0, color_a, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(2.0, color_b, scoped_ptr<TimingFunction>()));
+
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
+  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.5f));
+
+  SkColor value = curve->GetValue(1.0f);
+  EXPECT_EQ(255u, SkColorGetA(value));
+  int red_value = SkColorGetR(value);
+  EXPECT_LE(64, red_value);
+  EXPECT_GE(192, red_value);
+
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.5f));
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
+  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(3.f));
+}
+
 // Tests that a float animation with one keyframe works as expected.
 TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index 995a393..f720229 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -92,7 +92,7 @@
   UpdateActivation(NormalActivation);
 }
 
-// According to render layer backing, these are for testing only.
+// For testing only.
 void LayerAnimationController::SuspendAnimations(double monotonic_time) {
   for (size_t i = 0; i < active_animations_.size(); ++i) {
     if (!active_animations_[i]->is_finished())
@@ -100,15 +100,6 @@
   }
 }
 
-// Looking at GraphicsLayerCA, this appears to be the analog to
-// SuspendAnimations, which is for testing.
-void LayerAnimationController::ResumeAnimations(double monotonic_time) {
-  for (size_t i = 0; i < active_animations_.size(); ++i) {
-    if (active_animations_[i]->run_state() == Animation::Paused)
-      active_animations_[i]->SetRunState(Animation::Running, monotonic_time);
-  }
-}
-
 // Ensures that the list of active animations on the main thread and the impl
 // thread are kept in sync.
 void LayerAnimationController::PushAnimationUpdatesTo(
@@ -196,6 +187,8 @@
         break;
       }
 
+      case Animation::BackgroundColor: { break; }
+
       case Animation::TargetPropertyEnumSize:
         NOTREACHED();
     }
@@ -719,6 +712,11 @@
           break;
         }
 
+        case Animation::BackgroundColor: {
+          // Not yet implemented.
+          break;
+        }
+
         // Do nothing for sentinel value.
         case Animation::TargetPropertyEnumSize:
           NOTREACHED();
diff --git a/cc/animation/layer_animation_controller.h b/cc/animation/layer_animation_controller.h
index e397794..4861e25 100644
--- a/cc/animation/layer_animation_controller.h
+++ b/cc/animation/layer_animation_controller.h
@@ -45,7 +45,6 @@
   virtual void RemoveAnimation(int animation_id,
                                Animation::TargetProperty target_property);
   virtual void SuspendAnimations(double monotonic_time);
-  virtual void ResumeAnimations(double monotonic_time);
 
   // Ensures that the list of active animations on the main thread and the impl
   // thread are kept in sync. This function does not take ownership of the impl
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 0a88bfd..32252f1 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -138,18 +138,6 @@
   EXPECT_EQ(Animation::Paused,
             controller_impl->GetAnimation(group_id,
                                           Animation::Opacity)->run_state());
-
-  // Resume the main-thread animation.
-  controller->ResumeAnimations(2.0);
-  EXPECT_EQ(Animation::Running,
-            controller->GetAnimation(group_id,
-                                     Animation::Opacity)->run_state());
-
-  // The pause run state change should make it to the impl thread controller.
-  controller->PushAnimationUpdatesTo(controller_impl.get());
-  EXPECT_EQ(Animation::Running,
-            controller_impl->GetAnimation(group_id,
-                                          Animation::Opacity)->run_state());
 }
 
 TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
diff --git a/cc/animation/scrollbar_animation_controller_thinning.cc b/cc/animation/scrollbar_animation_controller_thinning.cc
index ce196fb..3de7598 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning.cc
@@ -10,14 +10,22 @@
 #include "cc/layers/layer_impl.h"
 #include "cc/layers/scrollbar_layer_impl_base.h"
 
+namespace {
+const float kIdleThicknessScale = 0.4f;
+const float kIdleOpacity = 0.7f;
+const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
+const int kDefaultAnimationDelay = 500;
+const int kDefaultAnimationDuration = 300;
+}
+
 namespace cc {
 
 scoped_ptr<ScrollbarAnimationControllerThinning>
 ScrollbarAnimationControllerThinning::Create(LayerImpl* scroll_layer) {
   return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
       scroll_layer,
-      base::TimeDelta::FromMilliseconds(500),
-      base::TimeDelta::FromMilliseconds(300)));
+      base::TimeDelta::FromMilliseconds(kDefaultAnimationDelay),
+      base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)));
 }
 
 scoped_ptr<ScrollbarAnimationControllerThinning>
@@ -33,11 +41,17 @@
     base::TimeDelta animation_duration)
     : ScrollbarAnimationController(),
       scroll_layer_(scroll_layer),
-      scroll_gesture_in_progress_(false),
       mouse_is_over_scrollbar_(false),
+      mouse_is_near_scrollbar_(false),
+      thickness_change_(NONE),
+      opacity_change_(NONE),
+      should_delay_animation_(false),
       animation_delay_(animation_delay),
       animation_duration_(animation_duration),
-      mouse_move_distance_to_trigger_animation_(100.f) {}
+      mouse_move_distance_to_trigger_animation_(
+          kDefaultMouseMoveDistanceToTriggerAnimation) {
+  ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
+}
 
 ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
 }
@@ -48,92 +62,120 @@
 
 base::TimeDelta ScrollbarAnimationControllerThinning::DelayBeforeStart(
     base::TimeTicks now) const {
+  if (!should_delay_animation_)
+    return base::TimeDelta();
   if (now > last_awaken_time_ + animation_delay_)
     return base::TimeDelta();
   return animation_delay_ - (now - last_awaken_time_);
 }
 
 bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) {
-  if (mouse_is_over_scrollbar_) {
-    ApplyOpacityAndThumbThicknessScale(1, 1);
-    return false;
-  }
   float progress = AnimationProgressAtTime(now);
   float opacity = OpacityAtAnimationProgress(progress);
   float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
       progress);
   ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
-  if (progress == 1.f)
+  if (progress == 1.f) {
+    opacity_change_ = NONE;
+    thickness_change_ = NONE;
     last_awaken_time_ = base::TimeTicks();
+  }
   return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta();
 }
 
 void ScrollbarAnimationControllerThinning::DidScrollGestureBegin() {
-  ApplyOpacityAndThumbThicknessScale(1, 1);
-  last_awaken_time_ = base::TimeTicks();
-  scroll_gesture_in_progress_ = true;
 }
 
 void ScrollbarAnimationControllerThinning::DidScrollGestureEnd(
     base::TimeTicks now) {
-  last_awaken_time_ = now;
-  scroll_gesture_in_progress_ = false;
 }
 
 void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar(
     base::TimeTicks now) {
   mouse_is_over_scrollbar_ = false;
-  DidScrollUpdate(now);
+  mouse_is_near_scrollbar_ = false;
+  last_awaken_time_ = now;
+  should_delay_animation_ = false;
+  opacity_change_ = DECREASE;
+  thickness_change_ = DECREASE;
 }
 
 bool ScrollbarAnimationControllerThinning::DidScrollUpdate(
     base::TimeTicks now) {
-  ApplyOpacityAndThumbThicknessScale(1, 1);
+  ApplyOpacityAndThumbThicknessScale(
+    1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
 
   last_awaken_time_ = now;
+  should_delay_animation_ = true;
+  if (!mouse_is_over_scrollbar_)
+    opacity_change_ = DECREASE;
   return true;
 }
 
 bool ScrollbarAnimationControllerThinning::DidMouseMoveNear(
     base::TimeTicks now, float distance) {
-  if (distance == 0.0) {
-    mouse_is_over_scrollbar_ = true;
+  bool mouse_is_over_scrollbar = distance == 0.0;
+  bool mouse_is_near_scrollbar =
+      distance < mouse_move_distance_to_trigger_animation_;
+
+  if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
+      mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
     return false;
+
+  if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) {
+    mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
+    opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE;
   }
 
-  if (distance < mouse_move_distance_to_trigger_animation_)
-    return DidScrollUpdate(now);
+  if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) {
+    mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
+    thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
+  }
 
-  return false;
+  last_awaken_time_ = now;
+  should_delay_animation_ = false;
+  return true;
 }
 
 float ScrollbarAnimationControllerThinning::AnimationProgressAtTime(
     base::TimeTicks now) {
-  if (scroll_gesture_in_progress_)
-    return 0;
-
   if (last_awaken_time_.is_null())
     return 1;
 
   base::TimeDelta delta = now - last_awaken_time_;
-  float progress = (delta - animation_delay_).InSecondsF() /
-      animation_duration_.InSecondsF();
+  if (should_delay_animation_)
+    delta -= animation_delay_;
+  float progress = delta.InSecondsF() / animation_duration_.InSecondsF();
   return std::max(std::min(progress, 1.f), 0.f);
 }
 
 float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
     float progress) {
-  const float kIdleOpacity = 0.7f;
-
-  return ((1.f - kIdleOpacity) * (1.f - progress)) + kIdleOpacity;
+  if (opacity_change_ == NONE)
+    return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity;
+  float factor = opacity_change_ == INCREASE ? progress : (1.f - progress);
+  float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity;
+  return ret;
 }
 
 float
 ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress(
     float progress) {
-  const float kIdleThicknessScale = 0.4f;
+  if (thickness_change_ == NONE)
+    return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
+  float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
+  return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale;
+}
 
-  return ((1.f - kIdleThicknessScale) * (1.f - progress)) + kIdleThicknessScale;
+float ScrollbarAnimationControllerThinning::AdjustScale(
+    float new_value,
+    float current_value,
+    AnimationChange animation_change) {
+  if (animation_change == INCREASE && current_value > new_value)
+    return current_value;
+  if (animation_change == DECREASE && current_value < new_value)
+    return current_value;
+  return new_value;
 }
 
 void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
@@ -141,16 +183,25 @@
   ScrollbarLayerImplBase* horizontal_scrollbar =
       scroll_layer_->horizontal_scrollbar_layer();
   if (horizontal_scrollbar) {
-    horizontal_scrollbar->SetOpacity(opacity);
-    horizontal_scrollbar->set_thumb_thickness_scale_factor(
-        thumb_thickness_scale);
+    horizontal_scrollbar->SetOpacity(
+        AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_));
+    horizontal_scrollbar->SetThumbThicknessScaleFactor(
+        AdjustScale(
+          thumb_thickness_scale,
+          horizontal_scrollbar->thumb_thickness_scale_factor(),
+          thickness_change_));
   }
 
   ScrollbarLayerImplBase* vertical_scrollbar =
       scroll_layer_->vertical_scrollbar_layer();
   if (vertical_scrollbar) {
-    vertical_scrollbar->SetOpacity(opacity);
-    vertical_scrollbar->set_thumb_thickness_scale_factor(thumb_thickness_scale);
+    vertical_scrollbar->SetOpacity(
+        AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_));
+    vertical_scrollbar->SetThumbThicknessScaleFactor(
+        AdjustScale(
+          thumb_thickness_scale,
+          vertical_scrollbar->thumb_thickness_scale_factor(),
+          thickness_change_));
   }
 }
 
diff --git a/cc/animation/scrollbar_animation_controller_thinning.h b/cc/animation/scrollbar_animation_controller_thinning.h
index 8038745..07b4515 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.h
+++ b/cc/animation/scrollbar_animation_controller_thinning.h
@@ -29,6 +29,8 @@
   void set_mouse_move_distance_for_test(float distance) {
     mouse_move_distance_to_trigger_animation_ = distance;
   }
+  bool mouse_is_over_scrollbar() const { return mouse_is_over_scrollbar_; }
+  bool mouse_is_near_scrollbar() const { return mouse_is_near_scrollbar_; }
 
   // ScrollbarAnimationController overrides.
   virtual bool IsAnimating() const OVERRIDE;
@@ -47,22 +49,40 @@
                                        base::TimeDelta animation_duration);
 
  private:
+  // Describes whether the current animation should INCREASE (darken / thicken)
+  // a bar or DECREASE it (lighten / thin).
+  enum AnimationChange {
+    NONE,
+    INCREASE,
+    DECREASE
+  };
   // Returns how far through the animation we are as a progress value from
   // 0 to 1.
   float AnimationProgressAtTime(base::TimeTicks now);
   float OpacityAtAnimationProgress(float progress);
   float ThumbThicknessScaleAtAnimationProgress(float progress);
+  float AdjustScale(float new_value,
+                    float current_value,
+                    AnimationChange animation_change);
   void ApplyOpacityAndThumbThicknessScale(float opacity,
                                           float thumb_thickness_scale);
 
   LayerImpl* scroll_layer_;
 
   base::TimeTicks last_awaken_time_;
-  bool scroll_gesture_in_progress_;
   bool mouse_is_over_scrollbar_;
-
+  bool mouse_is_near_scrollbar_;
+  // Are we narrowing or thickening the bars.
+  AnimationChange thickness_change_;
+  // Are we darkening or lightening the bars.
+  AnimationChange opacity_change_;
+  // Should the animation be delayed or start immediately.
+  bool should_delay_animation_;
+  // If |should_delay_animation_| is true, delay the animation by this amount.
   base::TimeDelta animation_delay_;
+  // The time for the animation to run.
   base::TimeDelta animation_duration_;
+  // How close should the mouse be to the scrollbar before we thicken it.
   float mouse_move_distance_to_trigger_animation_;
 
   DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerThinning);
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index 7bb5076..c915632 100644
--- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -43,175 +43,200 @@
   scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
 };
 
+// Check initialization of scrollbar.
 TEST_F(ScrollbarAnimationControllerThinningTest, Idle) {
   scrollbar_controller_->Animate(base::TimeTicks());
   EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
-TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByScrollGesture) {
-  base::TimeTicks time;
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->DidScrollGestureBegin();
-  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(100);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-  scrollbar_controller_->DidScrollGestureEnd(time);
-
-  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
-  EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-
-  scrollbar_controller_->DidScrollGestureBegin();
-  scrollbar_controller_->DidScrollGestureEnd(time);
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
-}
-
+// Scroll content. Confirm the scrollbar gets dark and then becomes light
+// after stopping.
 TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
   EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
   EXPECT_TRUE(scrollbar_controller_->IsAnimating());
   EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
-  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  // Scrollbar doesn't change size if triggered by scroll.
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Subsequent scroll restarts animation.
   EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
+  EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
 }
 
-TEST_F(ScrollbarAnimationControllerThinningTest, MouseOverAndOut) {
+// Initiate a scroll when the pointer is already near the scrollbar. It should
+// remain thick.
+TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidMouseMoveNear(time, 1);
+  time += base::TimeDelta::FromSeconds(3);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
   EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
   EXPECT_TRUE(scrollbar_controller_->IsAnimating());
   EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
-  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+  // Scrollbar should still be thick.
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(4);
+  time += base::TimeDelta::FromSeconds(5);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+// Move the pointer near the scrollbar. Confirm it gets thick and narrow when
+// moved away.
+TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(time, 1);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Should animate to thickened but not darken.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // Subsequent moves should not change anything.
+  scrollbar_controller_->DidMouseMoveNear(time, 1);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // Now move away from bar.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(time, 26);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Animate to narrow.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+}
+
+// Move the pointer over the scrollbar. Make sure it gets thick and dark
+// and that it gets thin and light when moved away.
+TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(time, 0);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Should animate to thickened and darkened.
+  time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
 
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // Subsequent moves should not change anything.
   scrollbar_controller_->DidMouseMoveNear(time, 0);
-  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // Now move away from bar.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(time, 26);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(4);
+  // Animate to narrow.
+  time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  scrollbar_controller_->DidMouseMoveOffScrollbar(time);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(4);
+  time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -220,6 +245,87 @@
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
   EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+}
+
+// First move the pointer near the scrollbar, then over it, then back near
+// then far away. Confirm that first the bar gets thick, then dark, then light,
+// then narrow.
+TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(time, 1);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Should animate to thickened but not darken.
+  time += base::TimeDelta::FromSeconds(3);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // Now move over.
+  scrollbar_controller_->DidMouseMoveNear(time, 0);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+  EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+
+  // Should animate to darkened.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+
+  // This is tricky. The DidMouseMoveOffScrollbar() is sent before the
+  // subsequent DidMouseMoveNear(), if the mouse moves in that direction.
+  // This results in the thumb thinning. We want to make sure that when the
+  // thumb starts expanding it doesn't first narrow to the idle thinness.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveOffScrollbar(time);
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  scrollbar_controller_->DidMouseMoveNear(time, 1);
+  // A new animation is kicked off.
+  EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  // We will initiate the narrowing again, but it won't get decremented until
+  // the new animation catches up to it.
+  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
+  // Now the thickness should be increasing, but it shouldn't happen until the
+  // animation catches up.
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
+  // The thickness now gets big again.
+  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
+  // The thickness now gets big again.
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
 }  // namespace
diff --git a/cc/animation/transform_operation.cc b/cc/animation/transform_operation.cc
index 5ede71b..889f7bd 100644
--- a/cc/animation/transform_operation.cc
+++ b/cc/animation/transform_operation.cc
@@ -163,11 +163,19 @@
     SkMScalar from_perspective_depth =
         IsOperationIdentity(from) ? std::numeric_limits<SkMScalar>::max()
                                   : from->perspective_depth;
-    SkMScalar to_perspective_depth = IsOperationIdentity(to)
-                                         ? std::numeric_limits<SkMScalar>::max()
-                                         : to->perspective_depth;
-    result->ApplyPerspectiveDepth(BlendSkMScalars(
-        from_perspective_depth, to_perspective_depth, progress));
+    SkMScalar to_perspective_depth =
+        IsOperationIdentity(to) ? std::numeric_limits<SkMScalar>::max()
+                                : to->perspective_depth;
+    if (from_perspective_depth == 0.f || to_perspective_depth == 0.f)
+      return false;
+
+    SkMScalar blended_perspective_depth = BlendSkMScalars(
+        1.f / from_perspective_depth, 1.f / to_perspective_depth, progress);
+
+    if (blended_perspective_depth == 0.f)
+      return false;
+
+    result->ApplyPerspectiveDepth(1.f / blended_perspective_depth);
     break;
   }
   case TransformOperation::TransformOperationMatrix: {
diff --git a/cc/animation/transform_operations_unittest.cc b/cc/animation/transform_operations_unittest.cc
index 6bc9e03..49b208e 100644
--- a/cc/animation/transform_operations_unittest.cc
+++ b/cc/animation/transform_operations_unittest.cc
@@ -570,8 +570,7 @@
     SkMScalar progress = 0.5f;
 
     gfx::Transform expected;
-    expected.ApplyPerspectiveDepth(500 +
-                                   0.5 * std::numeric_limits<SkMScalar>::max());
+    expected.ApplyPerspectiveDepth(2000);
 
     EXPECT_TRANSFORMATION_MATRIX_EQ(
         expected, operations.Blend(*identity_operations[i], progress));
@@ -662,8 +661,7 @@
     SkMScalar progress = 0.5f;
 
     gfx::Transform expected;
-    expected.ApplyPerspectiveDepth(500 +
-                                   0.5 * std::numeric_limits<SkMScalar>::max());
+    expected.ApplyPerspectiveDepth(2000);
 
     EXPECT_TRANSFORMATION_MATRIX_EQ(
         expected, identity_operations[i]->Blend(operations, progress));
@@ -678,13 +676,13 @@
   operations2.AppendPerspective(500);
 
   gfx::Transform expected;
-  expected.ApplyPerspectiveDepth(250);
+  expected.ApplyPerspectiveDepth(400);
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       expected, operations1.Blend(operations2, -0.5));
 
   expected.MakeIdentity();
-  expected.ApplyPerspectiveDepth(1250);
+  expected.ApplyPerspectiveDepth(2000);
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       expected, operations1.Blend(operations2, 1.5));
@@ -1072,6 +1070,33 @@
   }
 }
 
+TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) {
+    TransformOperations from_operations;
+    from_operations.AppendPerspective(200);
+
+    TransformOperations to_operations;
+    to_operations.AppendPerspective(1000);
+
+    gfx::Transform from_transform;
+    from_transform.ApplyPerspectiveDepth(200);
+
+    gfx::Transform to_transform;
+    to_transform.ApplyPerspectiveDepth(1000);
+
+    static const int steps = 20;
+    for (int i = 0; i < steps; ++i) {
+      double progress = static_cast<double>(i) / (steps - 1);
+
+      gfx::Transform blended_matrix = to_transform;
+      EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
+
+      gfx::Transform blended_transform =
+          to_operations.Blend(from_operations, progress);
+
+      EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform);
+    }
+}
+
 TEST(TransformOperationTest, BlendedBoundsForSequence) {
   TransformOperations operations_from;
   operations_from.AppendTranslate(2.0, 4.0, -1.0);
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index eeb1523..76b2bb9 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -466,6 +466,13 @@
 }
 
 static inline float ScaleOnAxis(double a, double b, double c) {
+  if (!b && !c)
+    return a;
+  if (!a && !c)
+    return b;
+  if (!a && !b)
+    return c;
+
   // Do the sqrt as a double to not lose precision.
   return static_cast<float>(std::sqrt(a * a + b * b + c * c));
 }
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index 5dbb296..be4a2c5 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -141,6 +141,9 @@
 // Prevents the layer tree unit tests from timing out.
 const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
 
+// Makes pixel tests write their output instead of read it.
+const char kCCRebaselinePixeltests[] = "cc-rebaseline-pixeltests";
+
 // Disable textures using RGBA_4444 layout.
 const char kDisable4444Textures[] = "disable-4444-textures";
 
@@ -162,7 +165,8 @@
 #endif
 }
 
-bool IsImplSidePaintingEnabled() {
+namespace {
+bool CheckImplSidePaintingStatus() {
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
 
   if (command_line.HasSwitch(cc::switches::kDisableImplSidePainting))
@@ -176,6 +180,12 @@
   return false;
 #endif
 }
+}  // namespace
+
+bool IsImplSidePaintingEnabled() {
+  static bool enabled = CheckImplSidePaintingStatus();
+  return enabled;
+}
 
 bool IsMapImageEnabled() {
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
diff --git a/cc/base/switches.h b/cc/base/switches.h
index ed6555a..e92eb2e 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -69,6 +69,7 @@
 
 // Unit test related.
 CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
+CC_EXPORT extern const char kCCRebaselinePixeltests[];
 
 CC_EXPORT bool IsLCDTextEnabled();
 CC_EXPORT bool IsImplSidePaintingEnabled();
diff --git a/cc/cc.gyp b/cc/cc.gyp
index df268ee..deb2fbd 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -360,6 +360,9 @@
         'resources/scoped_resource.h',
         'resources/scoped_ui_resource.cc',
         'resources/scoped_ui_resource.h',
+        'resources/shared_bitmap.cc',
+        'resources/shared_bitmap.h',
+        'resources/shared_bitmap_manager.h',
         'resources/single_release_callback.cc',
         'resources/single_release_callback.h',
         'resources/skpicture_content_layer_updater.cc',
diff --git a/cc/cc.target.darwin-arm.mk b/cc/cc.target.darwin-arm.mk
index 9c23ae0..570ebfd 100644
--- a/cc/cc.target.darwin-arm.mk
+++ b/cc/cc.target.darwin-arm.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -253,13 +254,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -363,13 +364,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc.target.darwin-mips.mk b/cc/cc.target.darwin-mips.mk
index 20fcbe3..c0d84f7 100644
--- a/cc/cc.target.darwin-mips.mk
+++ b/cc/cc.target.darwin-mips.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -252,13 +253,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -361,13 +362,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc.target.darwin-x86.mk b/cc/cc.target.darwin-x86.mk
index d358842..585967d 100644
--- a/cc/cc.target.darwin-x86.mk
+++ b/cc/cc.target.darwin-x86.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -255,13 +256,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -368,13 +369,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc.target.linux-arm.mk b/cc/cc.target.linux-arm.mk
index 9c23ae0..570ebfd 100644
--- a/cc/cc.target.linux-arm.mk
+++ b/cc/cc.target.linux-arm.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -253,13 +254,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -363,13 +364,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc.target.linux-mips.mk b/cc/cc.target.linux-mips.mk
index 20fcbe3..c0d84f7 100644
--- a/cc/cc.target.linux-mips.mk
+++ b/cc/cc.target.linux-mips.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -252,13 +253,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -361,13 +362,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc.target.linux-x86.mk b/cc/cc.target.linux-x86.mk
index d358842..585967d 100644
--- a/cc/cc.target.linux-x86.mk
+++ b/cc/cc.target.linux-x86.mk
@@ -180,6 +180,7 @@
 	cc/resources/resource_update_queue.cc \
 	cc/resources/scoped_resource.cc \
 	cc/resources/scoped_ui_resource.cc \
+	cc/resources/shared_bitmap.cc \
 	cc/resources/single_release_callback.cc \
 	cc/resources/skpicture_content_layer_updater.cc \
 	cc/resources/texture_mailbox.cc \
@@ -255,13 +256,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -368,13 +369,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index d48a4ae..49e82fc 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -24,6 +24,7 @@
       'layers/content_layer_unittest.cc',
       'layers/contents_scaling_layer_unittest.cc',
       'layers/delegated_frame_provider_unittest.cc',
+      'layers/delegated_frame_resource_collection_unittest.cc',
       'layers/delegated_renderer_layer_impl_unittest.cc',
       'layers/heads_up_display_unittest.cc',
       'layers/heads_up_display_layer_impl_unittest.cc',
@@ -35,6 +36,7 @@
       'layers/nine_patch_layer_unittest.cc',
       'layers/picture_image_layer_impl_unittest.cc',
       'layers/picture_layer_impl_unittest.cc',
+      'layers/picture_layer_unittest.cc',
       'layers/render_surface_unittest.cc',
       'layers/scrollbar_layer_unittest.cc',
       'layers/solid_color_layer_impl_unittest.cc',
@@ -76,6 +78,7 @@
       'scheduler/scheduler_unittest.cc',
       'scheduler/texture_uploader_unittest.cc',
       'test/fake_web_graphics_context_3d_unittest.cc',
+      'test/layer_tree_json_parser_unittest.cc',
       'trees/damage_tracker_unittest.cc',
       'trees/layer_sorter_unittest.cc',
       'trees/layer_tree_host_common_unittest.cc',
@@ -259,7 +262,8 @@
         'resources/worker_pool_perftest.cc',
         'test/cc_test_suite.cc',
         'test/lap_timer.cc',
-        'test/run_all_unittests.cc',
+        'test/run_all_perftests.cc',
+        'trees/layer_tree_host_common_perftest.cc',
         'trees/layer_tree_host_perftest.cc',
       ],
       'include_dirs': [
@@ -324,6 +328,7 @@
       'dependencies': [
         '../skia/skia.gyp:skia',
         '../ui/gfx/gfx.gyp:gfx',
+        '../ui/ui_unittests.gyp:ui_test_support',
       ],
     },
   ],
diff --git a/cc/debug/fake_web_graphics_context_3d.cc b/cc/debug/fake_web_graphics_context_3d.cc
index 25157bf..eab653b 100644
--- a/cc/debug/fake_web_graphics_context_3d.cc
+++ b/cc/debug/fake_web_graphics_context_3d.cc
@@ -9,6 +9,7 @@
 
 using WebKit::WGC3Dboolean;
 using WebKit::WGC3Denum;
+using WebKit::WGC3Dsizei;
 using WebKit::WebGLId;
 using WebKit::WebGraphicsContext3D;
 
@@ -234,48 +235,84 @@
   return false;
 }
 
-WebGLId FakeWebGraphicsContext3D::createBuffer() {
-  return 1;
+void FakeWebGraphicsContext3D::genBuffers(WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = 1;
 }
 
-void FakeWebGraphicsContext3D::deleteBuffer(WebKit::WebGLId id) {
+void FakeWebGraphicsContext3D::genFramebuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = 1;
+}
+
+void FakeWebGraphicsContext3D::genRenderbuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = 1;
+}
+
+void FakeWebGraphicsContext3D::genTextures(WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = 1;
+}
+
+void FakeWebGraphicsContext3D::deleteBuffers(WGC3Dsizei count, WebGLId* ids) {
+}
+
+void FakeWebGraphicsContext3D::deleteFramebuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+}
+
+void FakeWebGraphicsContext3D::deleteRenderbuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+}
+
+void FakeWebGraphicsContext3D::deleteTextures(WGC3Dsizei count, WebGLId* ids) {
+}
+
+WebGLId FakeWebGraphicsContext3D::createBuffer() {
+  return 1;
 }
 
 WebGLId FakeWebGraphicsContext3D::createFramebuffer() {
   return 1;
 }
 
-void FakeWebGraphicsContext3D::deleteFramebuffer(WebKit::WebGLId id) {
-}
-
-WebGLId FakeWebGraphicsContext3D::createProgram() {
-  return 1;
-}
-
-void FakeWebGraphicsContext3D::deleteProgram(WebKit::WebGLId id) {
-}
-
 WebGLId FakeWebGraphicsContext3D::createRenderbuffer() {
   return 1;
 }
 
-void FakeWebGraphicsContext3D::deleteRenderbuffer(WebKit::WebGLId id) {
-}
-
-WebGLId FakeWebGraphicsContext3D::createShader(WGC3Denum) {
-  return 1;
-}
-
-void FakeWebGraphicsContext3D::deleteShader(WebKit::WebGLId id) {
-}
-
 WebGLId FakeWebGraphicsContext3D::createTexture() {
   return 1;
 }
 
+void FakeWebGraphicsContext3D::deleteBuffer(WebKit::WebGLId id) {
+}
+
+void FakeWebGraphicsContext3D::deleteFramebuffer(WebKit::WebGLId id) {
+}
+
+void FakeWebGraphicsContext3D::deleteRenderbuffer(WebKit::WebGLId id) {
+}
+
 void FakeWebGraphicsContext3D::deleteTexture(WebGLId texture_id) {
 }
 
+WebGLId FakeWebGraphicsContext3D::createProgram() {
+  return 1;
+}
+
+WebGLId FakeWebGraphicsContext3D::createShader(WGC3Denum) {
+  return 1;
+}
+
+void FakeWebGraphicsContext3D::deleteProgram(WebKit::WebGLId id) {
+}
+
+void FakeWebGraphicsContext3D::deleteShader(WebKit::WebGLId id) {
+}
+
 void FakeWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) {
 }
 
diff --git a/cc/debug/fake_web_graphics_context_3d.h b/cc/debug/fake_web_graphics_context_3d.h
index 1bd3647..f923f71 100644
--- a/cc/debug/fake_web_graphics_context_3d.h
+++ b/cc/debug/fake_web_graphics_context_3d.h
@@ -530,19 +530,33 @@
       WebKit::WGC3Dsizei width,
       WebKit::WGC3Dsizei height) {}
 
+  virtual void genBuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genFramebuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genRenderbuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genTextures(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+
+  virtual void deleteBuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteFramebuffers(
+      WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteRenderbuffers(
+      WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteTextures(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+
   virtual WebKit::WebGLId createBuffer();
   virtual WebKit::WebGLId createFramebuffer();
-  virtual WebKit::WebGLId createProgram();
   virtual WebKit::WebGLId createRenderbuffer();
-  virtual WebKit::WebGLId createShader(WebKit::WGC3Denum);
   virtual WebKit::WebGLId createTexture();
 
   virtual void deleteBuffer(WebKit::WebGLId id);
   virtual void deleteFramebuffer(WebKit::WebGLId id);
-  virtual void deleteProgram(WebKit::WebGLId id);
   virtual void deleteRenderbuffer(WebKit::WebGLId id);
+  virtual void deleteTexture(WebKit::WebGLId id);
+
+  virtual WebKit::WebGLId createProgram();
+  virtual WebKit::WebGLId createShader(WebKit::WGC3Denum);
+
+  virtual void deleteProgram(WebKit::WebGLId id);
   virtual void deleteShader(WebKit::WebGLId id);
-  virtual void deleteTexture(WebKit::WebGLId texture_id);
 
   virtual void texStorage2DEXT(
       WebKit::WGC3Denum target,
diff --git a/cc/debug/test_context_support.cc b/cc/debug/test_context_support.cc
index edbbd72..e5a0b93 100644
--- a/cc/debug/test_context_support.cc
+++ b/cc/debug/test_context_support.cc
@@ -21,6 +21,10 @@
   sync_point_callbacks_.push_back(callback);
 }
 
+void TestContextSupport::SendManagedMemoryStats(
+    const gpu::ManagedMemoryStats& stats) {
+}
+
 void TestContextSupport::CallAllSyncPointCallbacks() {
   for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) {
     base::MessageLoop::current()->PostTask(
diff --git a/cc/debug/test_context_support.h b/cc/debug/test_context_support.h
index 4c092e9..067bcaf 100644
--- a/cc/debug/test_context_support.h
+++ b/cc/debug/test_context_support.h
@@ -21,6 +21,8 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
+  virtual void SendManagedMemoryStats(const gpu::ManagedMemoryStats& stats)
+    OVERRIDE;
 
   void CallAllSyncPointCallbacks();
 
diff --git a/cc/debug/test_web_graphics_context_3d.cc b/cc/debug/test_web_graphics_context_3d.cc
index 22f7602..4135ba0 100644
--- a/cc/debug/test_web_graphics_context_3d.cc
+++ b/cc/debug/test_web_graphics_context_3d.cc
@@ -188,68 +188,123 @@
   return false;
 }
 
-WebGLId TestWebGraphicsContext3D::createBuffer() {
-  return NextBufferId();
+void TestWebGraphicsContext3D::genBuffers(WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = NextBufferId();
 }
 
-void TestWebGraphicsContext3D::deleteBuffer(WebGLId id) {
+void TestWebGraphicsContext3D::genFramebuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = kFramebufferId | context_id_ << 16;
+}
+
+void TestWebGraphicsContext3D::genRenderbuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    ids[i] = kRenderbufferId | context_id_ << 16;
+}
+
+void TestWebGraphicsContext3D::genTextures(WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i) {
+    ids[i] = NextTextureId();
+    DCHECK_NE(ids[i], kExternalTextureId);
+  }
   base::AutoLock lock(namespace_->lock);
-  unsigned context_id = id >> 17;
-  unsigned buffer_id = id & 0x1ffff;
-  DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id);
-  DCHECK_EQ(context_id, context_id_);
+  for (int i = 0; i < count; ++i)
+    namespace_->textures.Append(ids[i], new TestTexture());
+}
+
+void TestWebGraphicsContext3D::deleteBuffers(WGC3Dsizei count, WebGLId* ids) {
+  base::AutoLock lock(namespace_->lock);
+  for (int i = 0; i < count; ++i) {
+    unsigned context_id = ids[i] >> 17;
+    unsigned buffer_id = ids[i] & 0x1ffff;
+    DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id);
+    DCHECK_EQ(context_id, context_id_);
+  }
+}
+
+void TestWebGraphicsContext3D::deleteFramebuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    DCHECK_EQ(kFramebufferId | context_id_ << 16, ids[i]);
+}
+
+void TestWebGraphicsContext3D::deleteRenderbuffers(
+    WGC3Dsizei count, WebGLId* ids) {
+  for (int i = 0; i < count; ++i)
+    DCHECK_EQ(kRenderbufferId | context_id_ << 16, ids[i]);
+}
+
+void TestWebGraphicsContext3D::deleteTextures(WGC3Dsizei count, WebGLId* ids) {
+  base::AutoLock lock(namespace_->lock);
+  for (int i = 0; i < count; ++i) {
+    namespace_->textures.Remove(ids[i]);
+    texture_targets_.UnbindTexture(ids[i]);
+  }
+}
+
+WebGLId TestWebGraphicsContext3D::createBuffer() {
+  WebGLId id;
+  genBuffers(1, &id);
+  return id;
 }
 
 WebGLId TestWebGraphicsContext3D::createFramebuffer() {
-  return kFramebufferId | context_id_ << 16;
+  WebGLId id;
+  genFramebuffers(1, &id);
+  return id;
+}
+
+WebGLId TestWebGraphicsContext3D::createRenderbuffer() {
+  WebGLId id;
+  genRenderbuffers(1, &id);
+  return id;
+}
+
+WebGLId TestWebGraphicsContext3D::createTexture() {
+  WebGLId id;
+  genTextures(1, &id);
+  return id;
+}
+
+void TestWebGraphicsContext3D::deleteBuffer(WebGLId id) {
+  deleteBuffers(1, &id);
 }
 
 void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id) {
-  DCHECK_EQ(kFramebufferId | context_id_ << 16, id);
+  deleteFramebuffers(1, &id);
+}
+
+void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id) {
+  deleteRenderbuffers(1, &id);
+}
+
+void TestWebGraphicsContext3D::deleteTexture(WebGLId id) {
+  deleteTextures(1, &id);
 }
 
 WebGLId TestWebGraphicsContext3D::createProgram() {
   return kProgramId | context_id_ << 16;
 }
 
-void TestWebGraphicsContext3D::deleteProgram(WebGLId id) {
-  DCHECK_EQ(kProgramId | context_id_ << 16, id);
-}
-
-WebGLId TestWebGraphicsContext3D::createRenderbuffer() {
-  return kRenderbufferId | context_id_ << 16;
-}
-
-void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id) {
-  DCHECK_EQ(kRenderbufferId | context_id_ << 16, id);
-}
-
 WebGLId TestWebGraphicsContext3D::createShader(WGC3Denum) {
   return kShaderId | context_id_ << 16;
 }
 
-void TestWebGraphicsContext3D::deleteShader(WebGLId id) {
-  DCHECK_EQ(kShaderId | context_id_ << 16, id);
-}
-
-WebGLId TestWebGraphicsContext3D::createTexture() {
-  WebGLId texture_id = NextTextureId();
-  DCHECK_NE(texture_id, kExternalTextureId);
-  base::AutoLock lock(namespace_->lock);
-  namespace_->textures.Append(texture_id, new TestTexture());
-  return texture_id;
-}
-
 WebGLId TestWebGraphicsContext3D::createExternalTexture() {
   base::AutoLock lock(namespace_->lock);
   namespace_->textures.Append(kExternalTextureId, new TestTexture());
   return kExternalTextureId;
 }
 
-void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id) {
-  base::AutoLock lock(namespace_->lock);
-  namespace_->textures.Remove(texture_id);
-  texture_targets_.UnbindTexture(texture_id);
+void TestWebGraphicsContext3D::deleteProgram(WebGLId id) {
+  DCHECK_EQ(kProgramId | context_id_ << 16, id);
+}
+
+void TestWebGraphicsContext3D::deleteShader(WebGLId id) {
+  DCHECK_EQ(kShaderId | context_id_ << 16, id);
 }
 
 void TestWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) {
@@ -370,18 +425,6 @@
   shared_contexts_.clear();
 }
 
-void TestWebGraphicsContext3D::signalSyncPoint(
-    unsigned sync_point,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
-void TestWebGraphicsContext3D::signalQuery(
-    WebKit::WebGLId query,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
 void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
     WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback) {
   if (test_capabilities_.swapbuffers_complete_callback)
diff --git a/cc/debug/test_web_graphics_context_3d.h b/cc/debug/test_web_graphics_context_3d.h
index 574a6bd..48ee70f 100644
--- a/cc/debug/test_web_graphics_context_3d.h
+++ b/cc/debug/test_web_graphics_context_3d.h
@@ -70,20 +70,34 @@
 
   virtual void useProgram(WebKit::WebGLId program);
 
+  virtual void genBuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genFramebuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genRenderbuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void genTextures(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+
+  virtual void deleteBuffers(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteFramebuffers(
+      WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteRenderbuffers(
+      WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+  virtual void deleteTextures(WebKit::WGC3Dsizei count, WebKit::WebGLId* ids);
+
   virtual WebKit::WebGLId createBuffer();
   virtual WebKit::WebGLId createFramebuffer();
-  virtual WebKit::WebGLId createProgram();
   virtual WebKit::WebGLId createRenderbuffer();
-  virtual WebKit::WebGLId createShader(WebKit::WGC3Denum);
   virtual WebKit::WebGLId createTexture();
-  virtual WebKit::WebGLId createExternalTexture();
 
   virtual void deleteBuffer(WebKit::WebGLId id);
   virtual void deleteFramebuffer(WebKit::WebGLId id);
-  virtual void deleteProgram(WebKit::WebGLId id);
   virtual void deleteRenderbuffer(WebKit::WebGLId id);
+  virtual void deleteTexture(WebKit::WebGLId id);
+
+  virtual WebKit::WebGLId createProgram();
+  virtual WebKit::WebGLId createShader(WebKit::WGC3Denum);
+  virtual WebKit::WebGLId createExternalTexture();
+
+  virtual void deleteProgram(WebKit::WebGLId id);
   virtual void deleteShader(WebKit::WebGLId id);
-  virtual void deleteTexture(WebKit::WebGLId texture_id);
 
   virtual void endQueryEXT(WebKit::WGC3Denum target);
   virtual void getQueryObjectuivEXT(
@@ -107,11 +121,6 @@
   virtual void loseContextCHROMIUM(WebKit::WGC3Denum current,
                                    WebKit::WGC3Denum other);
 
-  virtual void signalSyncPoint(unsigned sync_point,
-                               WebGraphicsSyncPointCallback* callback);
-  virtual void signalQuery(WebKit::WebGLId query,
-                           WebGraphicsSyncPointCallback* callback);
-
   virtual void setSwapBuffersCompleteCallbackCHROMIUM(
       WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback);
 
@@ -194,6 +203,9 @@
   void set_have_discard_framebuffer(bool have) {
     test_capabilities_.discard_framebuffer = have;
   }
+  void set_support_compressed_texture_etc1(bool support) {
+    test_capabilities_.texture_format_etc1 = support;
+  }
 
   // When this context is lost, all contexts in its share group are also lost.
   void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) {
@@ -290,7 +302,6 @@
   int times_map_buffer_chromium_succeeds_;
   WebGraphicsContextLostCallback* context_lost_callback_;
   WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* swap_buffers_callback_;
-  std::vector<WebGraphicsSyncPointCallback*> sync_point_callbacks_;
   base::hash_set<WebKit::WebGLId> used_textures_;
   std::vector<WebKit::WebGraphicsContext3D*> shared_contexts_;
   int max_texture_size_;
diff --git a/cc/input/top_controls_manager.cc b/cc/input/top_controls_manager.cc
index 925830c..871d9e6 100644
--- a/cc/input/top_controls_manager.cc
+++ b/cc/input/top_controls_manager.cc
@@ -7,11 +7,12 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/time/time.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/timing_function.h"
 #include "cc/input/top_controls_manager_client.h"
+#include "cc/output/begin_frame_args.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/transform.h"
 #include "ui/gfx/vector2d_f.h"
 
@@ -48,7 +49,8 @@
       top_controls_show_height_(
           top_controls_height * top_controls_hide_threshold),
       top_controls_hide_height_(
-          top_controls_height * (1.f - top_controls_show_threshold)) {
+          top_controls_height * (1.f - top_controls_show_threshold)),
+      pinch_gesture_active_(false) {
   CHECK(client_);
 }
 
@@ -89,6 +91,7 @@
 }
 
 void TopControlsManager::ScrollBegin() {
+  DCHECK(!pinch_gesture_active_);
   ResetAnimations();
   current_scroll_delta_ = 0.f;
   controls_scroll_begin_offset_ = controls_top_offset_;
@@ -96,6 +99,9 @@
 
 gfx::Vector2dF TopControlsManager::ScrollBy(
     const gfx::Vector2dF pending_delta) {
+  if (pinch_gesture_active_)
+    return pending_delta;
+
   if (permitted_state_ == SHOWN && pending_delta.y() > 0)
     return pending_delta;
   else if (permitted_state_ == HIDDEN && pending_delta.y() < 0)
@@ -120,9 +126,24 @@
 }
 
 void TopControlsManager::ScrollEnd() {
+  DCHECK(!pinch_gesture_active_);
   StartAnimationIfNecessary();
 }
 
+void TopControlsManager::PinchBegin() {
+  DCHECK(!pinch_gesture_active_);
+  pinch_gesture_active_ = true;
+  StartAnimationIfNecessary();
+}
+
+void TopControlsManager::PinchEnd() {
+  DCHECK(pinch_gesture_active_);
+  // Pinch{Begin,End} will always occur within the scope of Scroll{Begin,End},
+  // so return to a state expected by the remaining scroll sequence.
+  pinch_gesture_active_ = false;
+  ScrollBegin();
+}
+
 void TopControlsManager::SetControlsTopOffset(float controls_top_offset) {
   controls_top_offset = std::max(controls_top_offset, -top_controls_height_);
   controls_top_offset = std::min(controls_top_offset, 0.f);
@@ -174,7 +195,7 @@
 
   top_controls_animation_ = KeyframedFloatAnimationCurve::Create();
   double start_time =
-      (base::TimeTicks::Now() - base::TimeTicks()).InMillisecondsF();
+      (gfx::FrameTime::Now() - base::TimeTicks()).InMillisecondsF();
   top_controls_animation_->AddKeyframe(
       FloatKeyframe::Create(start_time, controls_top_offset_,
                             scoped_ptr<TimingFunction>()));
diff --git a/cc/input/top_controls_manager.h b/cc/input/top_controls_manager.h
index 9bc3040..246efba 100644
--- a/cc/input/top_controls_manager.h
+++ b/cc/input/top_controls_manager.h
@@ -56,6 +56,11 @@
   gfx::Vector2dF ScrollBy(const gfx::Vector2dF pending_delta);
   void ScrollEnd();
 
+  // The caller should ensure that |Pinch{Begin,End}| are called within
+  // the scope of |Scroll{Begin,End}|.
+  void PinchBegin();
+  void PinchEnd();
+
   gfx::Vector2dF Animate(base::TimeTicks monotonic_time);
 
  protected:
@@ -91,6 +96,8 @@
   // the user stops the scroll.
   float top_controls_hide_height_;
 
+  bool pinch_gesture_active_;
+
   DISALLOW_COPY_AND_ASSIGN(TopControlsManager);
 };
 
diff --git a/cc/input/top_controls_manager_unittest.cc b/cc/input/top_controls_manager_unittest.cc
index da7475f..74687ad 100644
--- a/cc/input/top_controls_manager_unittest.cc
+++ b/cc/input/top_controls_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/vector2d_f.h"
 
 namespace cc {
@@ -131,7 +132,7 @@
 
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -161,7 +162,7 @@
 
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -187,7 +188,7 @@
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -213,7 +214,7 @@
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -243,7 +244,7 @@
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -273,7 +274,7 @@
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
-  base::TimeTicks time = base::TimeTicks::Now();
+  base::TimeTicks time = gfx::FrameTime::Now();
   float previous_offset = manager->controls_top_offset();
   while (manager->animation()) {
     time = base::TimeDelta::FromMicroseconds(100) + time;
@@ -286,5 +287,88 @@
   EXPECT_EQ(100.f, manager->content_top_offset());
 }
 
+TEST(TopControlsManagerTest, PinchIgnoresScroll) {
+  MockTopControlsManagerClient client(0.5f, 0.5f);
+  TopControlsManager* manager = client.manager();
+
+  // Hide the controls.
+  manager->ScrollBegin();
+  EXPECT_EQ(0.f, manager->controls_top_offset());
+
+  manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
+  EXPECT_EQ(-100.f, manager->controls_top_offset());
+
+  manager->PinchBegin();
+  EXPECT_EQ(-100.f, manager->controls_top_offset());
+
+  // Scrolls are ignored during pinch.
+  manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
+  EXPECT_EQ(-100.f, manager->controls_top_offset());
+  manager->PinchEnd();
+  EXPECT_EQ(-100.f, manager->controls_top_offset());
+
+  // Scrolls should no long be ignored.
+  manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
+  EXPECT_EQ(-85.f, manager->controls_top_offset());
+  EXPECT_EQ(15.f, manager->content_top_offset());
+  manager->ScrollEnd();
+
+  EXPECT_TRUE(manager->animation());
+}
+
+TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) {
+  MockTopControlsManagerClient client(0.5f, 0.5f);
+  TopControlsManager* manager = client.manager();
+
+  manager->ScrollBegin();
+  manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
+  EXPECT_EQ(-100.f, manager->controls_top_offset());
+
+  manager->PinchBegin();
+  EXPECT_FALSE(manager->animation());
+
+  manager->PinchEnd();
+  EXPECT_FALSE(manager->animation());
+
+  manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
+  EXPECT_EQ(-85.f, manager->controls_top_offset());
+  EXPECT_EQ(15.f, manager->content_top_offset());
+
+  manager->PinchBegin();
+  EXPECT_TRUE(manager->animation());
+
+  base::TimeTicks time = base::TimeTicks::Now();
+  float previous_offset = manager->controls_top_offset();
+  while (manager->animation()) {
+    time = base::TimeDelta::FromMicroseconds(100) + time;
+    manager->Animate(time);
+    EXPECT_LT(manager->controls_top_offset(), previous_offset);
+    previous_offset = manager->controls_top_offset();
+  }
+  EXPECT_FALSE(manager->animation());
+
+  manager->PinchEnd();
+  EXPECT_FALSE(manager->animation());
+
+  manager->ScrollBy(gfx::Vector2dF(0.f, -55.f));
+  EXPECT_EQ(-45.f, manager->controls_top_offset());
+  EXPECT_EQ(55.f, manager->content_top_offset());
+  EXPECT_FALSE(manager->animation());
+
+  manager->ScrollEnd();
+  EXPECT_TRUE(manager->animation());
+
+  time = base::TimeTicks::Now();
+  previous_offset = manager->controls_top_offset();
+  while (manager->animation()) {
+    time = base::TimeDelta::FromMicroseconds(100) + time;
+    manager->Animate(time);
+    EXPECT_GT(manager->controls_top_offset(), previous_offset);
+    previous_offset = manager->controls_top_offset();
+  }
+  EXPECT_FALSE(manager->animation());
+  EXPECT_EQ(0.f, manager->controls_top_offset());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/layers/delegated_frame_resource_collection.cc b/cc/layers/delegated_frame_resource_collection.cc
index cd2633d..5ca4eda 100644
--- a/cc/layers/delegated_frame_resource_collection.cc
+++ b/cc/layers/delegated_frame_resource_collection.cc
@@ -12,7 +12,8 @@
 DelegatedFrameResourceCollection::DelegatedFrameResourceCollection()
     : client_(NULL),
       main_thread_runner_(BlockingTaskRunner::current()),
-      lost_all_resources_(false) {
+      lost_all_resources_(false),
+      weak_ptr_factory_(this) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 }
 
@@ -112,21 +113,21 @@
     resource_id_ref_count_map_[resources[i].id].refs_to_wait_for++;
 }
 
-ReturnCallback
-DelegatedFrameResourceCollection::GetReturnResourcesCallbackForImplThread() {
-  return base::Bind(
-      &DelegatedFrameResourceCollection::UnrefResourcesOnImplThread,
-      this,
-      main_thread_runner_);
-}
-
-void DelegatedFrameResourceCollection::UnrefResourcesOnImplThread(
+static void UnrefResourcesOnImplThread(
+    base::WeakPtr<DelegatedFrameResourceCollection> self,
     scoped_refptr<BlockingTaskRunner> main_thread_runner,
     const ReturnedResourceArray& returned) {
   main_thread_runner->PostTask(
       FROM_HERE,
       base::Bind(
-          &DelegatedFrameResourceCollection::UnrefResources, this, returned));
+          &DelegatedFrameResourceCollection::UnrefResources, self, returned));
+}
+
+ReturnCallback
+DelegatedFrameResourceCollection::GetReturnResourcesCallbackForImplThread() {
+  return base::Bind(&UnrefResourcesOnImplThread,
+                    weak_ptr_factory_.GetWeakPtr(),
+                    main_thread_runner_);
 }
 
 }  // namespace cc
diff --git a/cc/layers/delegated_frame_resource_collection.h b/cc/layers/delegated_frame_resource_collection.h
index 68ee11a..9a5d336 100644
--- a/cc/layers/delegated_frame_resource_collection.h
+++ b/cc/layers/delegated_frame_resource_collection.h
@@ -7,6 +7,7 @@
 
 #include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/return_callback.h"
@@ -46,10 +47,6 @@
   friend class base::RefCounted<DelegatedFrameResourceCollection>;
   ~DelegatedFrameResourceCollection();
 
-  void UnrefResourcesOnImplThread(
-      scoped_refptr<BlockingTaskRunner> main_thread_runner,
-      const ReturnedResourceArray& returned);
-
   DelegatedFrameResourceCollectionClient* client_;
   scoped_refptr<BlockingTaskRunner> main_thread_runner_;
 
@@ -64,6 +61,7 @@
   ResourceIdRefCountMap resource_id_ref_count_map_;
 
   base::ThreadChecker main_thread_checker_;
+  base::WeakPtrFactory<DelegatedFrameResourceCollection> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DelegatedFrameResourceCollection);
 };
diff --git a/cc/layers/delegated_frame_resource_collection_unittest.cc b/cc/layers/delegated_frame_resource_collection_unittest.cc
new file mode 100644
index 0000000..ace3def
--- /dev/null
+++ b/cc/layers/delegated_frame_resource_collection_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2013 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/bind.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "cc/layers/delegated_frame_resource_collection.h"
+#include "cc/resources/returned_resource.h"
+#include "cc/resources/transferable_resource.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class DelegatedFrameResourceCollectionTest
+    : public testing::Test,
+      public DelegatedFrameResourceCollectionClient {
+ protected:
+  DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
+
+  virtual void SetUp() OVERRIDE { CreateResourceCollection(); }
+
+  virtual void TearDown() OVERRIDE { DestroyResourceCollection(); }
+
+  void CreateResourceCollection() {
+    DCHECK(!resource_collection_);
+    resource_collection_ = new DelegatedFrameResourceCollection;
+    resource_collection_->SetClient(this);
+  }
+
+  void DestroyResourceCollection() {
+    if (resource_collection_) {
+      resource_collection_->SetClient(NULL);
+      resource_collection_ = NULL;
+    }
+  }
+
+  TransferableResourceArray CreateResourceArray() {
+    TransferableResourceArray resources;
+    TransferableResource resource;
+    resource.id = 444;
+    resources.push_back(resource);
+    return resources;
+  }
+
+  virtual void UnusedResourcesAreAvailable() OVERRIDE {
+    resources_available_ = true;
+    resource_collection_->TakeUnusedResourcesForChildCompositor(
+        &returned_resources_);
+    if (!resources_available_closure_.is_null())
+      resources_available_closure_.Run();
+  }
+
+  bool ReturnAndResetResourcesAvailable() {
+    bool r = resources_available_;
+    resources_available_ = false;
+    return r;
+  }
+
+  scoped_refptr<DelegatedFrameResourceCollection> resource_collection_;
+  bool resources_available_;
+  ReturnedResourceArray returned_resources_;
+  base::Closure resources_available_closure_;
+};
+
+// This checks that taking the return callback doesn't take extra refcounts,
+// since it's sent to other threads.
+TEST_F(DelegatedFrameResourceCollectionTest, NoRef) {
+  // Start with one ref.
+  EXPECT_TRUE(resource_collection_->HasOneRef());
+
+  ReturnCallback return_callback =
+      resource_collection_->GetReturnResourcesCallbackForImplThread();
+
+  // Callback shouldn't take a ref since it's sent to other threads.
+  EXPECT_TRUE(resource_collection_->HasOneRef());
+}
+
+void ReturnResourcesOnThread(ReturnCallback callback,
+                             const ReturnedResourceArray& resources,
+                             base::WaitableEvent* event) {
+  callback.Run(resources);
+  event->Wait();
+}
+
+// Tests that the ReturnCallback can run safely on threads even after the
+// last references to the collection were dropped.
+// Flaky: crbug.com/313441
+TEST_F(DelegatedFrameResourceCollectionTest, DISABLED_Thread) {
+  base::Thread thread("test thread");
+  thread.Start();
+
+  TransferableResourceArray resources = CreateResourceArray();
+  resource_collection_->ReceivedResources(resources);
+  resource_collection_->RefResources(resources);
+
+  ReturnedResourceArray returned_resources;
+  TransferableResource::ReturnResources(resources, &returned_resources);
+
+  base::WaitableEvent event(false, false);
+
+  {
+    base::RunLoop run_loop;
+    resources_available_closure_ = run_loop.QuitClosure();
+
+    thread.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &ReturnResourcesOnThread,
+            resource_collection_->GetReturnResourcesCallbackForImplThread(),
+            returned_resources,
+            &event));
+
+    run_loop.Run();
+  }
+  EXPECT_TRUE(ReturnAndResetResourcesAvailable());
+  EXPECT_EQ(1u, returned_resources_.size());
+  EXPECT_EQ(444u, returned_resources_[0].id);
+  EXPECT_EQ(1, returned_resources_[0].count);
+  returned_resources_.clear();
+
+  // The event prevents the return resources callback from being deleted.
+  // Destroy the last reference from this thread to the collection before
+  // signaling the event, to ensure any reference taken by the callback, if any,
+  // would be the last one.
+  DestroyResourceCollection();
+  event.Signal();
+
+  CreateResourceCollection();
+  resource_collection_->ReceivedResources(resources);
+  resource_collection_->RefResources(resources);
+
+  // Destroy the collection before we have a chance to run the return callback.
+  ReturnCallback return_callback =
+      resource_collection_->GetReturnResourcesCallbackForImplThread();
+  resource_collection_->LoseAllResources();
+  DestroyResourceCollection();
+
+  EXPECT_TRUE(ReturnAndResetResourcesAvailable());
+  EXPECT_EQ(1u, returned_resources_.size());
+  EXPECT_EQ(444u, returned_resources_[0].id);
+  EXPECT_EQ(1, returned_resources_[0].count);
+  EXPECT_TRUE(returned_resources_[0].lost);
+  returned_resources_.clear();
+
+  thread.message_loop()->PostTask(FROM_HERE,
+                                  base::Bind(&ReturnResourcesOnThread,
+                                             return_callback,
+                                             returned_resources,
+                                             &event));
+  event.Signal();
+
+  thread.Stop();
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc
index 35bd0b7..25a27af 100644
--- a/cc/layers/delegated_renderer_layer_impl.cc
+++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -237,6 +237,13 @@
     RenderPassSink* render_pass_sink) {
   DCHECK(HasContributingDelegatedRenderPasses());
 
+  const RenderPass* root_delegated_render_pass =
+      render_passes_in_draw_order_.back();
+  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
+  gfx::Transform delegated_frame_to_root_transform =
+      screen_space_transform() *
+      DelegatedFrameToLayerSpaceTransform(frame_size);
+
   for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
     RenderPass::Id output_render_pass_id(-1, -1);
     bool present =
@@ -248,8 +255,11 @@
                     << render_passes_in_draw_order_[i]->id.index;
     DCHECK_GT(output_render_pass_id.index, 0);
 
-    render_pass_sink->AppendRenderPass(
-        render_passes_in_draw_order_[i]->Copy(output_render_pass_id));
+    scoped_ptr<RenderPass> copy_pass =
+        render_passes_in_draw_order_[i]->Copy(output_render_pass_id);
+    copy_pass->transform_to_root_target.ConcatTransform(
+        delegated_frame_to_root_transform);
+    render_pass_sink->AppendRenderPass(copy_pass.Pass());
   }
 }
 
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 58fa366..05e8513 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -25,6 +25,7 @@
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -88,24 +89,21 @@
     delegated_renderer_layer->SetTransform(transform);
 
     ScopedPtrVector<RenderPass> delegated_render_passes;
-    TestRenderPass* pass1 = AddRenderPass(
-        &delegated_render_passes,
-        RenderPass::Id(9, 6),
-        gfx::Rect(6, 6, 6, 6),
-        gfx::Transform());
+    TestRenderPass* pass1 = AddRenderPass(&delegated_render_passes,
+                                          RenderPass::Id(9, 6),
+                                          gfx::Rect(6, 6, 6, 6),
+                                          gfx::Transform(1, 0, 0, 1, 5, 6));
     AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u);
-    TestRenderPass* pass2 = AddRenderPass(
-        &delegated_render_passes,
-        RenderPass::Id(9, 7),
-        gfx::Rect(7, 7, 7, 7),
-        gfx::Transform());
+    TestRenderPass* pass2 = AddRenderPass(&delegated_render_passes,
+                                          RenderPass::Id(9, 7),
+                                          gfx::Rect(7, 7, 7, 7),
+                                          gfx::Transform(1, 0, 0, 1, 7, 8));
     AddQuad(pass2, gfx::Rect(0, 0, 7, 7), 22u);
     AddRenderPassQuad(pass2, pass1);
-    TestRenderPass* pass3 = AddRenderPass(
-        &delegated_render_passes,
-        RenderPass::Id(9, 8),
-        gfx::Rect(0, 0, 8, 8),
-        gfx::Transform());
+    TestRenderPass* pass3 = AddRenderPass(&delegated_render_passes,
+                                          RenderPass::Id(9, 8),
+                                          gfx::Rect(0, 0, 8, 8),
+                                          gfx::Transform(1, 0, 0, 1, 9, 10));
     AddRenderPassQuad(pass3, pass2);
     delegated_renderer_layer->SetFrameDataForRenderPasses(
         &delegated_render_passes);
@@ -165,7 +163,7 @@
   EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
             frame.render_passes[2]->output_rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -201,7 +199,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(),
             frame.render_passes[1]->quad_list[0]->rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -228,7 +226,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 15, 15).ToString(),
             frame.render_passes[3]->quad_list[1]->rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -262,6 +260,42 @@
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       gfx::Transform(), frame.render_passes[1]->quad_list[0]->quadTransform());
 
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+  host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) {
+  LayerTreeHostImpl::FrameData frame;
+  EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+
+  // The delegated layer has a surface between it and the root.
+  EXPECT_TRUE(delegated_renderer_layer_->render_target()->parent());
+
+  // Each non-DelegatedRendererLayer added one RenderPass. The
+  // DelegatedRendererLayer added two contributing passes.
+  ASSERT_EQ(5u, frame.render_passes.size());
+
+  // The DelegatedRendererLayer is at position 9,9 compared to the root, so all
+  // render pass' transforms to the root should be shifted by this amount.
+  // The DelegatedRendererLayer has a size of 10x10, but the root delegated
+  // RenderPass has a size of 8x8, so any render passes should be scaled by
+  // 10/8.
+  gfx::Transform transform;
+  transform.Translate(9.0, 9.0);
+  transform.Scale(10.0 / 8.0, 10.0 / 8.0);
+
+  // The first contributing surface has a translation of 5, 6.
+  gfx::Transform five_six(1, 0, 0, 1, 5, 6);
+
+  // The second contributing surface has a translation of 7, 8.
+  gfx::Transform seven_eight(1, 0, 0, 1, 7, 8);
+
+  EXPECT_TRANSFORMATION_MATRIX_EQ(
+      transform * five_six, frame.render_passes[1]->transform_to_root_target);
+  EXPECT_TRANSFORMATION_MATRIX_EQ(
+      transform * seven_eight,
+      frame.render_passes[2]->transform_to_root_target);
+
   host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
@@ -274,7 +308,7 @@
   // has no need to be a RenderSurface for the quads it carries.
   EXPECT_FALSE(delegated_renderer_layer_->render_surface());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -289,7 +323,7 @@
   // render surface.
   EXPECT_TRUE(delegated_renderer_layer_->render_surface());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -307,7 +341,7 @@
   // render surface.
   EXPECT_TRUE(delegated_renderer_layer_->render_surface());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -354,7 +388,7 @@
   EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
             frame.render_passes[2]->output_rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -391,7 +425,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(),
             frame.render_passes[1]->quad_list[0]->rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -416,7 +450,7 @@
   EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
             frame.render_passes[3]->quad_list[0]->rect.ToString());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -448,7 +482,7 @@
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       gfx::Transform(), frame.render_passes[1]->quad_list[0]->quadTransform());
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -682,7 +716,7 @@
       expected,
       contrib_delegated_shared_quad_state->content_to_target_transform);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -745,7 +779,7 @@
       expected,
       contrib_delegated_shared_quad_state->content_to_target_transform);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -801,7 +835,7 @@
       expected,
       contrib_delegated_shared_quad_state->content_to_target_transform);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -856,7 +890,7 @@
       expected,
       contrib_delegated_shared_quad_state->content_to_target_transform);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1032,7 +1066,7 @@
   // Quads are clipped to the delegated renderer layer.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1061,7 +1095,7 @@
   // Quads came with a clip rect.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1091,7 +1125,7 @@
   // Quads are clipped to the delegated renderer layer.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1120,7 +1154,7 @@
   // Quads came with a clip rect.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1149,7 +1183,7 @@
   // clip rect is ignored, and they are not set as clipped.
   EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1179,7 +1213,7 @@
   // Quads came with a clip rect.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1208,7 +1242,7 @@
   // clip rect is ignored, and they are not set as clipped.
   EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1239,7 +1273,7 @@
   // Quads came with a clip rect.
   EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1292,7 +1326,7 @@
   EXPECT_EQ(DrawQuad::SOLID_COLOR,
             frame.render_passes[0]->quad_list[0]->material);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 80fad6a..b10112a 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -619,7 +619,7 @@
 
 void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) {
   DCHECK(IsPropertyChangeAllowed());
-  // This function only gets called during a begin frame, so there
+  // This function only gets called during a BeginMainFrame, so there
   // is no need to call SetNeedsUpdate here.
   DCHECK(layer_tree_host_ && layer_tree_host_->CommitRequested());
   if (scroll_offset_ == scroll_offset)
@@ -881,8 +881,8 @@
   }
 
   // Adjust the scroll delta to be just the scrolls that have happened since
-  // the begin frame was sent.  This happens for impl-side painting
-  // in LayerImpl::ApplyScrollDeltasSinceBeginFrame in a separate tree walk.
+  // the BeginMainFrame was sent.  This happens for impl-side painting
+  // in LayerImpl::ApplyScrollDeltasSinceBeginMainFrame in a separate tree walk.
   if (layer->layer_tree_impl()->settings().impl_side_painting) {
     layer->SetScrollOffset(scroll_offset_);
   } else {
@@ -1028,11 +1028,6 @@
   SetNeedsCommit();
 }
 
-void Layer::ResumeAnimations(double monotonic_time) {
-  layer_animation_controller_->ResumeAnimations(monotonic_time);
-  SetNeedsCommit();
-}
-
 void Layer::SetLayerAnimationControllerForTest(
     scoped_refptr<LayerAnimationController> controller) {
   layer_animation_controller_->RemoveValueObserver(this);
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 1328b07..274e82f 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -376,7 +376,6 @@
   void RemoveAnimation(int animation_id);
 
   void SuspendAnimations(double monotonic_time);
-  void ResumeAnimations(double monotonic_time);
 
   bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) {
     return layer_animation_controller_->AnimatedBoundsForBox(box, bounds);
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 14f3e2a..894daf1 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -385,7 +385,7 @@
   sent_scroll_delta_ = gfx::Vector2d();
 }
 
-void LayerImpl::ApplyScrollDeltasSinceBeginFrame() {
+void LayerImpl::ApplyScrollDeltasSinceBeginMainFrame() {
   // Only the pending tree can have missing scrolls.
   DCHECK(layer_tree_impl()->IsPendingTree());
   if (!scrollable())
@@ -614,6 +614,13 @@
   if (scrollable_)
     result->SetBoolean("Scrollable", scrollable_);
 
+  if (have_wheel_event_handlers_)
+    result->SetBoolean("WheelHandler", have_wheel_event_handlers_);
+  if (!touch_event_handler_region_.IsEmpty()) {
+    scoped_ptr<base::Value> region = touch_event_handler_region_.AsValue();
+    result->Set("TouchRegion", region.release());
+  }
+
   list = new base::ListValue;
   for (size_t i = 0; i < children_.size(); ++i)
     list->Append(children_[i]->LayerTreeAsJson());
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 4bd91da..9d3951b 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -382,7 +382,7 @@
   }
 
   void ApplySentScrollDeltasFromAbortedCommit();
-  void ApplyScrollDeltasSinceBeginFrame();
+  void ApplyScrollDeltasSinceBeginMainFrame();
 
   void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
     should_scroll_on_main_thread_ = should_scroll_on_main_thread;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 3a7a1c1..c66eb85 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -39,7 +39,7 @@
 class MockLayerTreeHost : public LayerTreeHost {
  public:
   explicit MockLayerTreeHost(LayerTreeHostClient* client)
-      : LayerTreeHost(client, LayerTreeSettings()) {
+      : LayerTreeHost(client, NULL, LayerTreeSettings()) {
     Initialize(NULL);
   }
 
@@ -803,11 +803,12 @@
       : client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
   scoped_ptr<LayerTreeHost> Create() {
-    return LayerTreeHost::Create(&client_, LayerTreeSettings(), NULL).Pass();
+    return LayerTreeHost::Create(&client_, NULL, LayerTreeSettings(), NULL)
+        .Pass();
   }
 
   scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
-    return LayerTreeHost::Create(&client_, settings, NULL).Pass();
+    return LayerTreeHost::Create(&client_, NULL, settings, NULL).Pass();
   }
 
  private:
diff --git a/cc/layers/nine_patch_layer_unittest.cc b/cc/layers/nine_patch_layer_unittest.cc
index f616560..7213a51 100644
--- a/cc/layers/nine_patch_layer_unittest.cc
+++ b/cc/layers/nine_patch_layer_unittest.cc
@@ -32,7 +32,7 @@
 class MockLayerTreeHost : public LayerTreeHost {
  public:
   explicit MockLayerTreeHost(LayerTreeHostClient* client)
-      : LayerTreeHost(client, LayerTreeSettings()) {
+      : LayerTreeHost(client, NULL, LayerTreeSettings()) {
     Initialize(NULL);
   }
 };
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index ef17a09..bc311a3 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -20,7 +20,8 @@
   : client_(client),
     pile_(make_scoped_refptr(new PicturePile())),
     instrumentation_object_tracker_(id()),
-    is_mask_(false) {
+    is_mask_(false),
+    update_source_frame_number_(-1) {
 }
 
 PictureLayer::~PictureLayer() {
@@ -38,6 +39,18 @@
   Layer::PushPropertiesTo(base_layer);
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
 
+  if (layer_impl->bounds().IsEmpty()) {
+    // Update may not get called for an empty layer, so resize here instead.
+    // Using layer_impl because either bounds() or paint_properties().bounds
+    // may disagree and either one could have been pushed to layer_impl.
+    pile_->Resize(gfx::Size());
+    pile_->UpdateRecordedRegion();
+  } else if (update_source_frame_number_ ==
+             layer_tree_host()->source_frame_number()) {
+    // If update called, then pile size must match bounds pushed to impl layer.
+    DCHECK_EQ(layer_impl->bounds().ToString(), pile_->size().ToString());
+  }
+
   layer_impl->SetIsMask(is_mask_);
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
@@ -78,6 +91,7 @@
                "source_frame_number",
                layer_tree_host()->source_frame_number());
 
+  update_source_frame_number_ = layer_tree_host()->source_frame_number();
   bool updated = Layer::Update(queue, occlusion);
 
   pile_->Resize(paint_properties().bounds);
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index f67ca91..e1e4a9c 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -56,6 +56,8 @@
   Region pile_invalidation_;
   bool is_mask_;
 
+  int update_source_frame_number_;
+
   DISALLOW_COPY_AND_ASSIGN(PictureLayer);
 };
 
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 36b2ba9..d2ef7d0 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -553,6 +553,7 @@
 
   if (!DrawsContent()) {
     ResetRasterScale();
+    tilings_->RemoveAllTilings();
     return;
   }
 
@@ -611,7 +612,8 @@
   // get updated prior to drawing or activation.  If this tree does not
   // need update draw properties, then its transforms are up to date and
   // we can create tiles for this tiling immediately.
-  if (!layer_tree_impl()->needs_update_draw_properties())
+  if (!layer_tree_impl()->needs_update_draw_properties() &&
+      should_update_tile_priorities_)
     UpdateTilePriorities();
 }
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index f9dfb99..7493e38 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -1106,6 +1106,41 @@
   EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
 }
 
+TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+  host_impl_.active_tree()->UpdateDrawProperties();
+  EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+
+  // Contrived unit test of a real crash. A layer is transparent during a
+  // context loss, and later becomes opaque, causing active layer SyncTiling to
+  // be called.
+  const float tile_scale = 2.f;
+  active_layer_->DidLoseOutputSurface();
+  EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(tile_scale));
+  pending_layer_->AddTiling(2.f);
+  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(tile_scale));
+}
+
+TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
+  // Set up layers with tilings.
+  SetupDefaultTrees(gfx::Size(10, 10));
+  SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, false);
+  pending_layer_->PushPropertiesTo(active_layer_);
+  EXPECT_TRUE(pending_layer_->DrawsContent());
+  EXPECT_TRUE(pending_layer_->CanHaveTilings());
+  EXPECT_GE(pending_layer_->num_tilings(), 0u);
+  EXPECT_GE(active_layer_->num_tilings(), 0u);
+
+  // Set content to false, which should make CanHaveTilings return false.
+  pending_layer_->SetDrawsContent(false);
+  EXPECT_FALSE(pending_layer_->DrawsContent());
+  EXPECT_FALSE(pending_layer_->CanHaveTilings());
+
+  // No tilings should be pushed to active layer.
+  pending_layer_->PushPropertiesTo(active_layer_);
+  EXPECT_EQ(0u, active_layer_->num_tilings());
+}
+
 class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
  public:
   DeferredInitPictureLayerImplTest()
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
new file mode 100644
index 0000000..c3dd244
--- /dev/null
+++ b/cc/layers/picture_layer_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2013 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 "cc/layers/picture_layer.h"
+
+#include "cc/layers/content_layer_client.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/resource_update_queue.h"
+#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_proxy.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/trees/occlusion_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class MockContentLayerClient : public ContentLayerClient {
+ public:
+  virtual void PaintContents(SkCanvas* canvas,
+                             gfx::Rect clip,
+                             gfx::RectF* opaque) OVERRIDE {}
+  virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+};
+
+TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
+  MockContentLayerClient client;
+  scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+  layer->SetBounds(gfx::Size(10, 10));
+
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  host->SetRootLayer(layer);
+  layer->SetIsDrawable(true);
+  layer->SavePaintProperties();
+
+  OcclusionTracker occlusion(gfx::Rect(0, 0, 1000, 1000), false);
+  scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue);
+  layer->Update(queue.get(), &occlusion);
+
+  layer->SetBounds(gfx::Size(0, 0));
+  layer->SavePaintProperties();
+  // Intentionally skipping Update since it would normally be skipped on
+  // a layer with empty bounds.
+
+  FakeProxy proxy;
+#ifndef NDEBUG
+  proxy.SetCurrentThreadIsImplThread(true);
+#endif
+  {
+    FakeLayerTreeHostImpl host_impl(ImplSidePaintingSettings(), &proxy);
+    host_impl.CreatePendingTree();
+    scoped_ptr<FakePictureLayerImpl> layer_impl =
+        FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
+
+    layer->PushPropertiesTo(layer_impl.get());
+    EXPECT_FALSE(layer_impl->CanHaveTilings());
+    EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
+    EXPECT_TRUE(layer_impl->pile()->size() == gfx::Size(0, 0));
+    EXPECT_TRUE(layer_impl->pile()->recorded_region().IsEmpty());
+  }
+#ifndef NDEBUG
+  proxy.SetCurrentThreadIsImplThread(false);
+#endif
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc
index c1e7126..362465b 100644
--- a/cc/layers/scrollbar_layer_impl_base.cc
+++ b/cc/layers/scrollbar_layer_impl_base.cc
@@ -72,6 +72,13 @@
   NoteLayerPropertyChanged();
 }
 
+void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) {
+  if (thumb_thickness_scale_factor_ == factor)
+    return;
+  thumb_thickness_scale_factor_ = factor;
+  NoteLayerPropertyChanged();
+}
+
 gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
   // Thumb extent is the length of the thumb in the scrolling direction, thumb
   // thickness is in the perpendicular direction. Here's an example of a
diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h
index 55ade6a..360ef97 100644
--- a/cc/layers/scrollbar_layer_impl_base.h
+++ b/cc/layers/scrollbar_layer_impl_base.h
@@ -44,9 +44,7 @@
   float thumb_thickness_scale_factor() {
     return thumb_thickness_scale_factor_;
   }
-  void set_thumb_thickness_scale_factor(float thumb_thickness_scale_factor) {
-    thumb_thickness_scale_factor_ = thumb_thickness_scale_factor;
-  }
+  void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor);
 
  protected:
   ScrollbarLayerImplBase(LayerTreeImpl* tree_impl,
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 250d610..0423cdc 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -514,7 +514,7 @@
  public:
   MockLayerTreeHost(LayerTreeHostClient* client,
                     const LayerTreeSettings& settings)
-      : LayerTreeHost(client, settings),
+      : LayerTreeHost(client, NULL, settings),
         next_id_(1),
         total_ui_resource_created_(0),
         total_ui_resource_deleted_(0) {
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc
index 18410fb..45a456e 100644
--- a/cc/layers/texture_layer.cc
+++ b/cc/layers/texture_layer.cc
@@ -132,9 +132,10 @@
   SetNextCommitWaitsForActivation();
 }
 
-void TextureLayer::SetTextureMailbox(
+void TextureLayer::SetTextureMailboxInternal(
     const TextureMailbox& mailbox,
-    scoped_ptr<SingleReleaseCallback> release_callback) {
+    scoped_ptr<SingleReleaseCallback> release_callback,
+    bool requires_commit) {
   DCHECK(uses_mailbox_);
   DCHECK(!mailbox.IsValid() || !holder_ref_ ||
          !mailbox.Equals(holder_ref_->holder()->mailbox()));
@@ -146,12 +147,26 @@
   else
     holder_ref_.reset();
   needs_set_mailbox_ = true;
-  SetNeedsCommit();
+  // If we are within a commit, no need to do it again immediately after.
+  if (requires_commit)
+    SetNeedsCommit();
+  else
+    SetNeedsPushProperties();
+
   // The active frame needs to be replaced and the mailbox returned before the
   // commit is called complete.
   SetNextCommitWaitsForActivation();
 }
 
+void TextureLayer::SetTextureMailbox(
+    const TextureMailbox& mailbox,
+    scoped_ptr<SingleReleaseCallback> release_callback) {
+  SetTextureMailboxInternal(
+      mailbox,
+      release_callback.Pass(),
+      true /* requires_commit */);
+}
+
 void TextureLayer::WillModifyTexture() {
   if (layer_tree_host() && (DrawsContent() || content_committed_)) {
     layer_tree_host()->AcquireLayerTextures();
@@ -209,7 +224,11 @@
               &mailbox,
               &release_callback,
               layer_tree_host()->UsingSharedMemoryResources())) {
-        SetTextureMailbox(mailbox, release_callback.Pass());
+        // Already within a commit, no need to do another one immediately.
+        SetTextureMailboxInternal(
+            mailbox,
+            release_callback.Pass(),
+            false /* requires_commit */);
         updated = true;
       }
     } else {
diff --git a/cc/layers/texture_layer.h b/cc/layers/texture_layer.h
index b0edb22..0a7fd4e 100644
--- a/cc/layers/texture_layer.h
+++ b/cc/layers/texture_layer.h
@@ -148,6 +148,11 @@
   virtual ~TextureLayer();
 
  private:
+  void SetTextureMailboxInternal(
+      const TextureMailbox& mailbox,
+      scoped_ptr<SingleReleaseCallback> release_callback,
+      bool requires_commit);
+
   TextureLayerClient* client_;
   bool uses_mailbox_;
 
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index bdb1358..63cf132 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -44,7 +44,7 @@
 class MockLayerTreeHost : public LayerTreeHost {
  public:
   explicit MockLayerTreeHost(LayerTreeHostClient* client)
-      : LayerTreeHost(client, LayerTreeSettings()) {
+      : LayerTreeHost(client, NULL, LayerTreeSettings()) {
     Initialize(NULL);
   }
 
@@ -1695,6 +1695,109 @@
 // delegating renderer.
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest);
 
+// Checks that TextureLayer::Update does not cause an extra commit when setting
+// the texture mailbox.
+class TextureLayerNoExtraCommitForMailboxTest
+    : public LayerTreeTest,
+      public TextureLayerClient {
+ public:
+  TextureLayerNoExtraCommitForMailboxTest()
+      : prepare_mailbox_count_(0) {}
+
+  // TextureLayerClient implementation.
+  virtual unsigned PrepareTexture() OVERRIDE {
+    NOTREACHED();
+    return 0;
+  }
+
+  // TextureLayerClient implementation.
+  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+    NOTREACHED();
+    return NULL;
+  }
+
+  virtual bool PrepareTextureMailbox(
+      cc::TextureMailbox* mailbox,
+      scoped_ptr<SingleReleaseCallback>* release_callback,
+      bool use_shared_memory) OVERRIDE {
+    prepare_mailbox_count_++;
+    // Alternate between two mailboxes to ensure that the TextureLayer updates
+    // and commits.
+    if (prepare_mailbox_count_ % 2 == 0)
+      *mailbox = MakeMailbox('1');
+    else
+      *mailbox = MakeMailbox('2');
+
+    // Non-zero mailboxes need a callback.
+    *release_callback = SingleReleaseCallback::Create(
+        base::Bind(&TextureLayerNoExtraCommitForMailboxTest::MailboxReleased,
+                   base::Unretained(this)));
+    // If the test fails, this would cause an infinite number of commits.
+    return true;
+  }
+
+  TextureMailbox MakeMailbox(char name) {
+    return TextureMailbox(std::string(64, name));
+  }
+
+  void MailboxReleased(unsigned sync_point, bool lost_resource) {
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(10, 10));
+    root->SetAnchorPoint(gfx::PointF());
+    root->SetIsDrawable(true);
+
+    solid_layer_ = SolidColorLayer::Create();
+    solid_layer_->SetBounds(gfx::Size(10, 10));
+    solid_layer_->SetIsDrawable(true);
+    solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+    root->AddChild(solid_layer_);
+
+    parent_layer_ = Layer::Create();
+    parent_layer_->SetBounds(gfx::Size(10, 10));
+    parent_layer_->SetIsDrawable(true);
+    root->AddChild(parent_layer_);
+
+    texture_layer_ = TextureLayer::CreateForMailbox(this);
+    texture_layer_->SetBounds(gfx::Size(10, 10));
+    texture_layer_->SetAnchorPoint(gfx::PointF());
+    texture_layer_->SetIsDrawable(true);
+    parent_layer_->AddChild(texture_layer_);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    PostSetNeedsCommitToMainThread();
+  }
+
+
+  virtual void DidCommit() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  scoped_refptr<SolidColorLayer> solid_layer_;
+  scoped_refptr<Layer> parent_layer_;
+  scoped_refptr<TextureLayer> texture_layer_;
+
+  int prepare_mailbox_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoExtraCommitForMailboxTest);
+
 // Checks that changing a mailbox in the client for a TextureLayer that's
 // invisible correctly works and uses the new mailbox as soon as the layer
 // becomes visible (and returns the old one).
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 47d694b..9bdb907 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -60,6 +60,7 @@
   virtual void SetUp() {
     impl_thread_.Start();
     layer_tree_host_ = LayerTreeHost::Create(&fake_layer_tree_host_client_,
+                                             NULL,
                                              settings_,
                                              impl_thread_.message_loop_proxy());
     proxy_ = layer_tree_host_->proxy();
@@ -73,7 +74,7 @@
     DebugScopedSetImplThreadAndMainThreadBlocked
         impl_thread_and_main_thread_blocked(proxy_);
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
     host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(proxy_));
   }
 
diff --git a/cc/layers/ui_resource_layer_impl.cc b/cc/layers/ui_resource_layer_impl.cc
index 23e33f9..2c9a286 100644
--- a/cc/layers/ui_resource_layer_impl.cc
+++ b/cc/layers/ui_resource_layer_impl.cc
@@ -113,8 +113,9 @@
 
   gfx::Rect quad_rect(bounds());
 
-  // TODO(clholgat): Properly calculate opacity: crbug.com/300027
-  gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
+  bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) ||
+                contents_opaque();
+  gfx::Rect opaque_rect(opaque ? quad_rect : gfx::Rect());
   scoped_ptr<TextureDrawQuad> quad;
 
   quad = TextureDrawQuad::Create();
diff --git a/cc/layers/ui_resource_layer_impl_unittest.cc b/cc/layers/ui_resource_layer_impl_unittest.cc
index 383b8a3..35ff05b 100644
--- a/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -23,6 +23,7 @@
     FakeUIResourceLayerTreeHostImpl* host_impl,
     gfx::Size bitmap_size,
     gfx::Size layer_size,
+    bool opaque,
     UIResourceId uid) {
   gfx::Rect visible_content_rect(layer_size);
   scoped_ptr<UIResourceLayerImpl> layer =
@@ -38,6 +39,7 @@
       SkBitmap::kARGB_8888_Config, bitmap_size.width(), bitmap_size.height());
   skbitmap.allocPixels();
   skbitmap.setImmutable();
+  skbitmap.setIsOpaque(opaque);
   UIResourceBitmap bitmap(skbitmap);
 
   host_impl->CreateUIResource(uid, bitmap);
@@ -64,10 +66,12 @@
   gfx::Size bitmap_size(100, 100);
   gfx::Size layer_size(100, 100);;
   size_t expected_quad_size = 1;
+  bool opaque = true;
   UIResourceId uid = 1;
   scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer(&host_impl,
                                                                   bitmap_size,
                                                                   layer_size,
+                                                                  opaque,
                                                                   uid);
   QuadSizeTest(layer.Pass(), expected_quad_size);
 
@@ -77,6 +81,7 @@
   layer = GenerateUIResourceLayer(&host_impl,
                                   bitmap_size,
                                   layer_size,
+                                  opaque,
                                   uid);
   QuadSizeTest(layer.Pass(), expected_quad_size);
 }
@@ -94,26 +99,48 @@
   EXPECT_EQ(expected_opaque_bounds, opaque_rect);
 }
 
-TEST(UIResourceLayerImplTest, VerifyOpaqueBounds) {
+TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
   FakeImplProxy proxy;
   FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
 
   gfx::Size bitmap_size(100, 100);
   gfx::Size layer_size(100, 100);;
+  bool opaque = false;
   UIResourceId uid = 1;
   scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer(&host_impl,
                                                                   bitmap_size,
                                                                   layer_size,
+                                                                  opaque,
                                                                   uid);
+  gfx::Rect expected_opaque_bounds;
+  OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds);
+
+  opaque = true;
+  layer = GenerateUIResourceLayer(&host_impl,
+                                  bitmap_size,
+                                  layer_size,
+                                  opaque,
+                                  uid);
+  expected_opaque_bounds = gfx::Rect(layer->bounds());
+  OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds);
+}
+
+TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
+  FakeImplProxy proxy;
+  FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
+
+  gfx::Size bitmap_size(100, 100);
+  gfx::Size layer_size(100, 100);
+  bool skbitmap_opaque = false;
+  UIResourceId uid = 1;
+  scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer(
+      &host_impl, bitmap_size, layer_size, skbitmap_opaque, uid);
   layer->SetContentsOpaque(false);
   gfx::Rect expected_opaque_bounds;
   OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds);
 
-  layer = GenerateUIResourceLayer(&host_impl,
-                                  bitmap_size,
-                                  layer_size,
-                                  uid);
-
+  layer = GenerateUIResourceLayer(
+      &host_impl, bitmap_size, layer_size, skbitmap_opaque, uid);
   layer->SetContentsOpaque(true);
   expected_opaque_bounds = gfx::Rect(layer->bounds());
   OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds);
diff --git a/cc/layers/ui_resource_layer_unittest.cc b/cc/layers/ui_resource_layer_unittest.cc
index 1720b81..a2c75c1 100644
--- a/cc/layers/ui_resource_layer_unittest.cc
+++ b/cc/layers/ui_resource_layer_unittest.cc
@@ -32,7 +32,7 @@
 class MockLayerTreeHost : public LayerTreeHost {
  public:
   explicit MockLayerTreeHost(LayerTreeHostClient* client)
-      : LayerTreeHost(client, LayerTreeSettings()) {
+      : LayerTreeHost(client, NULL, LayerTreeSettings()) {
     Initialize(NULL);
   }
 };
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc
index d7da76c..92901af 100644
--- a/cc/output/begin_frame_args.cc
+++ b/cc/output/begin_frame_args.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/output/begin_frame_args.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 
@@ -29,20 +30,20 @@
 BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor() {
   // For WebView/SynchronousCompositor, we always want to draw immediately,
   // so we set the deadline to 0 and guess that the interval is 16 milliseconds.
-  return BeginFrameArgs(base::TimeTicks::Now(),
+  return BeginFrameArgs(gfx::FrameTime::Now(),
                         base::TimeTicks(),
                         DefaultInterval());
 }
 
 BeginFrameArgs BeginFrameArgs::CreateForTesting() {
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   return BeginFrameArgs(now,
                         now + (DefaultInterval() / 2),
                         DefaultInterval());
 }
 
 BeginFrameArgs BeginFrameArgs::CreateExpiredForTesting() {
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   return BeginFrameArgs(now,
                         now - DefaultInterval(),
                         DefaultInterval());
diff --git a/cc/output/context_provider.cc b/cc/output/context_provider.cc
index 7f46f7c..a823fa2 100644
--- a/cc/output/context_provider.cc
+++ b/cc/output/context_provider.cc
@@ -21,6 +21,7 @@
       shallow_flush(false),
       swapbuffers_complete_callback(false),
       texture_format_bgra8888(false),
+      texture_format_etc1(false),
       texture_rectangle(false),
       texture_storage(false),
       texture_usage(false),
diff --git a/cc/output/context_provider.h b/cc/output/context_provider.h
index 01ba0d8..6db326d 100644
--- a/cc/output/context_provider.h
+++ b/cc/output/context_provider.h
@@ -41,6 +41,7 @@
     bool shallow_flush;
     bool swapbuffers_complete_callback;
     bool texture_format_bgra8888;
+    bool texture_format_etc1;
     bool texture_rectangle;
     bool texture_storage;
     bool texture_usage;
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc
index 772a16a..678d21a 100644
--- a/cc/output/delegating_renderer.cc
+++ b/cc/output/delegating_renderer.cc
@@ -22,6 +22,8 @@
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
 #include "cc/resources/resource_provider.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 
@@ -60,7 +62,8 @@
   capabilities_.using_offscreen_context3d = false;
 
   if (!output_surface_->context_provider()) {
-    // TODO(danakj): Make software compositing work.
+    capabilities_.using_shared_memory_resources = true;
+    capabilities_.using_map_image = settings_->use_map_image;
     return true;
   }
 
@@ -180,12 +183,13 @@
     NOTIMPLEMENTED();
     return;
   }
-  WebKit::WebGraphicsManagedMemoryStats stats;
-  stats.bytesVisible = bytes_visible;
-  stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
-  stats.bytesAllocated = bytes_allocated;
-  stats.backbufferRequested = false;
-  context_provider->Context3d()->sendManagedMemoryStatsCHROMIUM(&stats);
+  gpu::ManagedMemoryStats stats;
+  stats.bytes_required = bytes_visible;
+  stats.bytes_nice_to_have = bytes_visible_and_nearby;
+  stats.bytes_allocated = bytes_allocated;
+  stats.backbuffer_requested = false;
+
+  context_provider->ContextSupport()->SendManagedMemoryStats(stats);
 }
 
 void DelegatingRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) {
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index c02200d..24c3fc2 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -148,10 +148,11 @@
   if (!resource_provider_)
     return;
 
-  base::hash_map<RenderPass::Id, const RenderPass*> render_passes_in_frame;
+  base::hash_map<RenderPass::Id, gfx::Size> render_passes_in_frame;
   for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i)
-    render_passes_in_frame.insert(std::pair<RenderPass::Id, const RenderPass*>(
-        render_passes_in_draw_order[i]->id, render_passes_in_draw_order[i]));
+    render_passes_in_frame.insert(std::pair<RenderPass::Id, gfx::Size>(
+        render_passes_in_draw_order[i]->id,
+        RenderPassTextureSize(render_passes_in_draw_order[i])));
 
   std::vector<RenderPass::Id> passes_to_delete;
   base::ScopedPtrHashMap<RenderPass::Id, ScopedResource>::const_iterator
@@ -159,24 +160,20 @@
   for (pass_iter = render_pass_textures_.begin();
        pass_iter != render_pass_textures_.end();
        ++pass_iter) {
-    base::hash_map<RenderPass::Id, const RenderPass*>::const_iterator it =
+    base::hash_map<RenderPass::Id, gfx::Size>::const_iterator it =
         render_passes_in_frame.find(pass_iter->first);
     if (it == render_passes_in_frame.end()) {
       passes_to_delete.push_back(pass_iter->first);
       continue;
     }
 
-    const RenderPass* render_pass_in_frame = it->second;
-    gfx::Size required_size = RenderPassTextureSize(render_pass_in_frame);
-    ResourceFormat required_format =
-        RenderPassTextureFormat(render_pass_in_frame);
+    gfx::Size required_size = it->second;
     ScopedResource* texture = pass_iter->second;
     DCHECK(texture);
 
     bool size_appropriate = texture->size().width() >= required_size.width() &&
                             texture->size().height() >= required_size.height();
-    if (texture->id() &&
-        (!size_appropriate || texture->format() != required_format))
+    if (texture->id() && !size_appropriate)
       texture->Free();
   }
 
@@ -410,9 +407,8 @@
   size.Enlarge(enlarge_pass_texture_amount_.x(),
                enlarge_pass_texture_amount_.y());
   if (!texture->id() &&
-      !texture->Allocate(size,
-                         ResourceProvider::TextureUsageFramebuffer,
-                         RenderPassTextureFormat(render_pass)))
+      !texture->Allocate(
+           size, ResourceProvider::TextureUsageFramebuffer, RGBA_8888))
     return false;
 
   return BindFramebufferToTexture(frame, texture, render_pass->output_rect);
@@ -429,10 +425,4 @@
   return render_pass->output_rect.size();
 }
 
-// static
-ResourceFormat DirectRenderer::RenderPassTextureFormat(
-    const RenderPass* render_pass) {
-  return RGBA_8888;
-}
-
 }  // namespace cc
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index f55cc59..6be6707 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -86,7 +86,6 @@
                                      gfx::RectF draw_space_rect);
 
   static gfx::Size RenderPassTextureSize(const RenderPass* render_pass);
-  static ResourceFormat RenderPassTextureFormat(const RenderPass* render_pass);
 
   void DrawRenderPass(DrawingFrame* frame,
                       const RenderPass* render_pass,
diff --git a/cc/output/filter_operation.cc b/cc/output/filter_operation.cc
index 672dba7..50f111f 100644
--- a/cc/output/filter_operation.cc
+++ b/cc/output/filter_operation.cc
@@ -8,6 +8,7 @@
 #include "cc/base/math_util.h"
 #include "cc/output/filter_operation.h"
 #include "third_party/skia/include/core/SkMath.h"
+#include "ui/gfx/animation/tween.h"
 
 namespace cc {
 
@@ -97,52 +98,6 @@
 FilterOperation::~FilterOperation() {
 }
 
-// TODO(ajuma): Define a version of gfx::Tween::ValueBetween for floats, and use
-// that instead.
-static float BlendFloats(float from, float to, double progress) {
-  return from * (1.0 - progress) + to * progress;
-}
-
-static int BlendInts(int from, int to, double progress) {
-  return static_cast<int>(
-      MathUtil::Round(from * (1.0 - progress) + to * progress));
-}
-
-static uint8_t  BlendColorComponents(uint8_t from,
-                                     uint8_t to,
-                                     uint8_t from_alpha,
-                                     uint8_t to_alpha,
-                                     uint8_t blended_alpha,
-                                     double progress) {
-  // Since progress can be outside [0, 1], blending can produce a value outside
-  // [0, 255].
-  int blended_premultiplied = BlendInts(SkMulDiv255Round(from, from_alpha),
-                                        SkMulDiv255Round(to, to_alpha),
-                                        progress);
-  int blended = static_cast<int>(
-      MathUtil::Round(blended_premultiplied * 255.f / blended_alpha));
-  return static_cast<uint8_t>(MathUtil::ClampToRange(blended, 0, 255));
-}
-
-static SkColor BlendSkColors(SkColor from, SkColor to, double progress) {
-  int from_a = SkColorGetA(from);
-  int to_a = SkColorGetA(to);
-  int blended_a = BlendInts(from_a, to_a, progress);
-  if (blended_a <= 0)
-    return SkColorSetARGB(0, 0, 0, 0);
-  blended_a = std::min(blended_a, 255);
-
-  // TODO(ajuma): Use SkFourByteInterp once http://crbug.com/260369 is fixed.
-  uint8_t blended_r = BlendColorComponents(
-      SkColorGetR(from), SkColorGetR(to), from_a, to_a, blended_a, progress);
-  uint8_t blended_g = BlendColorComponents(
-      SkColorGetG(from), SkColorGetG(to), from_a, to_a, blended_a, progress);
-  uint8_t blended_b = BlendColorComponents(
-      SkColorGetB(from), SkColorGetB(to), from_a, to_a, blended_a, progress);
-
-  return SkColorSetARGB(blended_a, blended_r, blended_g, blended_b);
-}
-
 static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
   switch (type) {
     case FilterOperation::GRAYSCALE:
@@ -239,21 +194,25 @@
   }
 
   blended_filter.set_amount(ClampAmountForFilterType(
-      BlendFloats(from_op.amount(), to_op.amount(), progress), to_op.type()));
+      gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()),
+      to_op.type()));
 
   if (to_op.type() == FilterOperation::DROP_SHADOW) {
-    gfx::Point blended_offset(BlendInts(from_op.drop_shadow_offset().x(),
-                                        to_op.drop_shadow_offset().x(),
-                                        progress),
-                              BlendInts(from_op.drop_shadow_offset().y(),
-                                        to_op.drop_shadow_offset().y(),
-                                        progress));
+    gfx::Point blended_offset(
+        gfx::Tween::LinearIntValueBetween(progress,
+                                          from_op.drop_shadow_offset().x(),
+                                          to_op.drop_shadow_offset().x()),
+        gfx::Tween::LinearIntValueBetween(progress,
+                                          from_op.drop_shadow_offset().y(),
+                                          to_op.drop_shadow_offset().y()));
     blended_filter.set_drop_shadow_offset(blended_offset);
-    blended_filter.set_drop_shadow_color(BlendSkColors(
-        from_op.drop_shadow_color(), to_op.drop_shadow_color(), progress));
+    blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween(
+        progress, from_op.drop_shadow_color(), to_op.drop_shadow_color()));
   } else if (to_op.type() == FilterOperation::ZOOM) {
-    blended_filter.set_zoom_inset(std::max(
-        BlendInts(from_op.zoom_inset(), to_op.zoom_inset(), progress), 0));
+    blended_filter.set_zoom_inset(
+        std::max(gfx::Tween::LinearIntValueBetween(
+                     from_op.zoom_inset(), to_op.zoom_inset(), progress),
+                 0));
   }
 
   return blended_filter;
diff --git a/cc/output/filter_operations_unittest.cc b/cc/output/filter_operations_unittest.cc
index e975ed5..7f439b9 100644
--- a/cc/output/filter_operations_unittest.cc
+++ b/cc/output/filter_operations_unittest.cc
@@ -412,6 +412,11 @@
       gfx::Point(-2, -4), 0.f, SkColorSetARGB(0, 0, 0, 0));
   EXPECT_EQ(expected, blended);
 
+  blended = FilterOperation::Blend(&from, &to, 0.25);
+  expected = FilterOperation::CreateDropShadowFilter(
+      gfx::Point(1, 1), 3.f, SkColorSetARGB(24, 32, 64, 128));
+  EXPECT_EQ(expected, blended);
+
   blended = FilterOperation::Blend(&from, &to, 0.75);
   expected = FilterOperation::CreateDropShadowFilter(
       gfx::Point(2, 4), 5.f, SkColorSetARGB(42, 30, 61, 121));
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 6e8bd75..35f8684 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -38,6 +38,7 @@
 #include "cc/trees/single_thread_proxy.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
@@ -278,12 +279,12 @@
 void GLRenderer::SendManagedMemoryStats(size_t bytes_visible,
                                         size_t bytes_visible_and_nearby,
                                         size_t bytes_allocated) {
-  WebKit::WebGraphicsManagedMemoryStats stats;
-  stats.bytesVisible = bytes_visible;
-  stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
-  stats.bytesAllocated = bytes_allocated;
-  stats.backbufferRequested = !is_backbuffer_discarded_;
-  context_->sendManagedMemoryStatsCHROMIUM(&stats);
+  gpu::ManagedMemoryStats stats;
+  stats.bytes_required = bytes_visible;
+  stats.bytes_nice_to_have = bytes_visible_and_nearby;
+  stats.bytes_allocated = bytes_allocated;
+  stats.backbuffer_requested = !is_backbuffer_discarded_;
+  context_support_->SendManagedMemoryStats(stats);
 }
 
 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 7f60c2d..8b71ca4 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -221,7 +221,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false).Pass();
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false).Pass();
     renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_,
                                                    &settings_,
                                                    output_surface_.get(),
@@ -312,8 +312,8 @@
             new ShaderCreatorMockGraphicsContext())).Pass();
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
-    resource_provider_ = ResourceProvider::Create(
-        output_surface_.get(), 0, false).Pass();
+    resource_provider_ =
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false).Pass();
     renderer_.reset(new FakeRendererGL(&renderer_client_,
                                        &settings_,
                                        output_surface_.get(),
@@ -634,7 +634,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -679,7 +679,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -714,7 +714,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -752,7 +752,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -784,7 +784,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -860,7 +860,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -920,7 +920,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -1007,7 +1007,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   settings.should_clear_root_render_pass = false;
@@ -1095,7 +1095,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -1181,7 +1181,7 @@
   output_surface->set_fixed_size(gfx::Size(100, 100));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   settings.partial_swap_enabled = true;
@@ -1360,7 +1360,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   LayerTreeSettings settings;
   FakeRendererClient renderer_client;
@@ -1714,7 +1714,7 @@
     CHECK(output_surface_.BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(&output_surface_, 0, false).Pass();
+        ResourceProvider::Create(&output_surface_, NULL, 0, false).Pass();
 
     renderer_.reset(new FakeRendererGL(
         this, &settings_, &output_surface_, resource_provider_.get()));
diff --git a/cc/output/managed_memory_policy.cc b/cc/output/managed_memory_policy.cc
index 7e83766..ade2a27 100644
--- a/cc/output/managed_memory_policy.cc
+++ b/cc/output/managed_memory_policy.cc
@@ -11,18 +11,29 @@
 
 const size_t ManagedMemoryPolicy::kDefaultNumResourcesLimit = 10 * 1000 * 1000;
 
+using gpu::MemoryAllocation;
+
 ManagedMemoryPolicy::ManagedMemoryPolicy(size_t bytes_limit_when_visible)
     : bytes_limit_when_visible(bytes_limit_when_visible),
-      priority_cutoff_when_visible(CUTOFF_ALLOW_EVERYTHING),
+      priority_cutoff_when_visible(MemoryAllocation::CUTOFF_ALLOW_EVERYTHING),
       bytes_limit_when_not_visible(0),
-      priority_cutoff_when_not_visible(CUTOFF_ALLOW_NOTHING),
+      priority_cutoff_when_not_visible(MemoryAllocation::CUTOFF_ALLOW_NOTHING),
+      num_resources_limit(kDefaultNumResourcesLimit) {}
+
+ManagedMemoryPolicy::ManagedMemoryPolicy(
+    const gpu::MemoryAllocation& allocation)
+    : bytes_limit_when_visible(allocation.bytes_limit_when_visible),
+      priority_cutoff_when_visible(allocation.priority_cutoff_when_visible),
+      bytes_limit_when_not_visible(allocation.bytes_limit_when_not_visible),
+      priority_cutoff_when_not_visible(
+          allocation.priority_cutoff_when_not_visible),
       num_resources_limit(kDefaultNumResourcesLimit) {}
 
 ManagedMemoryPolicy::ManagedMemoryPolicy(
     size_t bytes_limit_when_visible,
-    PriorityCutoff priority_cutoff_when_visible,
+    MemoryAllocation::PriorityCutoff priority_cutoff_when_visible,
     size_t bytes_limit_when_not_visible,
-    PriorityCutoff priority_cutoff_when_not_visible,
+    MemoryAllocation::PriorityCutoff priority_cutoff_when_not_visible,
     size_t num_resources_limit)
     : bytes_limit_when_visible(bytes_limit_when_visible),
       priority_cutoff_when_visible(priority_cutoff_when_visible),
@@ -44,15 +55,16 @@
 }
 
 // static
-int ManagedMemoryPolicy::PriorityCutoffToValue(PriorityCutoff priority_cutoff) {
+int ManagedMemoryPolicy::PriorityCutoffToValue(
+    MemoryAllocation::PriorityCutoff priority_cutoff) {
   switch (priority_cutoff) {
-    case CUTOFF_ALLOW_NOTHING:
+    case MemoryAllocation::CUTOFF_ALLOW_NOTHING:
       return PriorityCalculator::AllowNothingCutoff();
-    case CUTOFF_ALLOW_REQUIRED_ONLY:
+    case MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY:
       return PriorityCalculator::AllowVisibleOnlyCutoff();
-    case CUTOFF_ALLOW_NICE_TO_HAVE:
+    case MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE:
       return PriorityCalculator::AllowVisibleAndNearbyCutoff();
-    case CUTOFF_ALLOW_EVERYTHING:
+    case MemoryAllocation::CUTOFF_ALLOW_EVERYTHING:
       return PriorityCalculator::AllowEverythingCutoff();
   }
   NOTREACHED();
@@ -62,15 +74,15 @@
 // static
 TileMemoryLimitPolicy
 ManagedMemoryPolicy::PriorityCutoffToTileMemoryLimitPolicy(
-    PriorityCutoff priority_cutoff) {
+    gpu::MemoryAllocation::PriorityCutoff priority_cutoff) {
   switch (priority_cutoff) {
-    case CUTOFF_ALLOW_NOTHING:
+    case MemoryAllocation::CUTOFF_ALLOW_NOTHING:
       return ALLOW_NOTHING;
-    case CUTOFF_ALLOW_REQUIRED_ONLY:
+    case MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY:
       return ALLOW_ABSOLUTE_MINIMUM;
-    case CUTOFF_ALLOW_NICE_TO_HAVE:
+    case MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE:
       return ALLOW_PREPAINT_ONLY;
-    case CUTOFF_ALLOW_EVERYTHING:
+    case MemoryAllocation::CUTOFF_ALLOW_EVERYTHING:
       return ALLOW_ANYTHING;
   }
   NOTREACHED();
diff --git a/cc/output/managed_memory_policy.h b/cc/output/managed_memory_policy.h
index 5a607a7..1a234f7 100644
--- a/cc/output/managed_memory_policy.h
+++ b/cc/output/managed_memory_policy.h
@@ -8,36 +8,35 @@
 #include "base/basictypes.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/tile_priority.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 
 namespace cc {
 
 struct CC_EXPORT ManagedMemoryPolicy {
-  enum PriorityCutoff {
-    CUTOFF_ALLOW_NOTHING,
-    CUTOFF_ALLOW_REQUIRED_ONLY,
-    CUTOFF_ALLOW_NICE_TO_HAVE,
-    CUTOFF_ALLOW_EVERYTHING,
-  };
   static const size_t kDefaultNumResourcesLimit;
 
   explicit ManagedMemoryPolicy(size_t bytes_limit_when_visible);
-  ManagedMemoryPolicy(size_t bytes_limit_when_visible,
-                      PriorityCutoff priority_cutoff_when_visible,
-                      size_t bytes_limit_when_not_visible,
-                      PriorityCutoff priority_cutoff_when_not_visible,
-                      size_t num_resources_limit);
+  explicit ManagedMemoryPolicy(
+      const gpu::MemoryAllocation& allocation);
+  ManagedMemoryPolicy(
+      size_t bytes_limit_when_visible,
+      gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_visible,
+      size_t bytes_limit_when_not_visible,
+      gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_not_visible,
+      size_t num_resources_limit);
   bool operator==(const ManagedMemoryPolicy&) const;
   bool operator!=(const ManagedMemoryPolicy&) const;
 
   size_t bytes_limit_when_visible;
-  PriorityCutoff priority_cutoff_when_visible;
+  gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_visible;
   size_t bytes_limit_when_not_visible;
-  PriorityCutoff priority_cutoff_when_not_visible;
+  gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_not_visible;
   size_t num_resources_limit;
 
-  static int PriorityCutoffToValue(PriorityCutoff priority_cutoff);
+  static int PriorityCutoffToValue(
+      gpu::MemoryAllocation::PriorityCutoff priority_cutoff);
   static TileMemoryLimitPolicy PriorityCutoffToTileMemoryLimitPolicy(
-      PriorityCutoff priority_cutoff);
+      gpu::MemoryAllocation::PriorityCutoff priority_cutoff);
 };
 
 }  // namespace cc
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc
index bcebeab..002a44a 100644
--- a/cc/output/output_surface.cc
+++ b/cc/output/output_surface.cc
@@ -25,6 +25,7 @@
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
 
@@ -48,10 +49,10 @@
       device_scale_factor_(-1),
       max_frames_pending_(0),
       pending_swap_buffers_(0),
-      needs_begin_frame_(false),
-      client_ready_for_begin_frame_(true),
+      needs_begin_impl_frame_(false),
+      client_ready_for_begin_impl_frame_(true),
       client_(NULL),
-      check_for_retroactive_begin_frame_pending_(false),
+      check_for_retroactive_begin_impl_frame_pending_(false),
       external_stencil_test_enabled_(false),
       weak_ptr_factory_(this),
       gpu_latency_history_(kGpuLatencyHistorySize) {}
@@ -64,10 +65,10 @@
       device_scale_factor_(-1),
       max_frames_pending_(0),
       pending_swap_buffers_(0),
-      needs_begin_frame_(false),
-      client_ready_for_begin_frame_(true),
+      needs_begin_impl_frame_(false),
+      client_ready_for_begin_impl_frame_(true),
       client_(NULL),
-      check_for_retroactive_begin_frame_pending_(false),
+      check_for_retroactive_begin_impl_frame_pending_(false),
       external_stencil_test_enabled_(false),
       weak_ptr_factory_(this),
       gpu_latency_history_(kGpuLatencyHistorySize) {}
@@ -82,22 +83,25 @@
       device_scale_factor_(-1),
       max_frames_pending_(0),
       pending_swap_buffers_(0),
-      needs_begin_frame_(false),
-      client_ready_for_begin_frame_(true),
+      needs_begin_impl_frame_(false),
+      client_ready_for_begin_impl_frame_(true),
       client_(NULL),
-      check_for_retroactive_begin_frame_pending_(false),
+      check_for_retroactive_begin_impl_frame_pending_(false),
       external_stencil_test_enabled_(false),
       weak_ptr_factory_(this),
       gpu_latency_history_(kGpuLatencyHistorySize) {}
 
-void OutputSurface::InitializeBeginFrameEmulation(
+void OutputSurface::InitializeBeginImplFrameEmulation(
     base::SingleThreadTaskRunner* task_runner,
     bool throttle_frame_production,
     base::TimeDelta interval) {
   if (throttle_frame_production) {
-    frame_rate_controller_.reset(
-        new FrameRateController(
-            DelayBasedTimeSource::Create(interval, task_runner)));
+    scoped_refptr<DelayBasedTimeSource> time_source;
+    if (gfx::FrameTime::TimestampsAreHighRes())
+      time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
+    else
+      time_source = DelayBasedTimeSource::Create(interval, task_runner);
+    frame_rate_controller_.reset(new FrameRateController(time_source));
   } else {
     frame_rate_controller_.reset(new FrameRateController(task_runner));
   }
@@ -133,9 +137,9 @@
                                             const BeginFrameArgs& args) {
   DCHECK(frame_rate_controller_);
   if (throttled)
-    skipped_begin_frame_args_ = args;
+    skipped_begin_impl_frame_args_ = args;
   else
-    BeginFrame(args);
+    BeginImplFrame(args);
 }
 
 // Forwarded to OutputSurfaceClient
@@ -144,62 +148,64 @@
   client_->SetNeedsRedrawRect(damage_rect);
 }
 
-void OutputSurface::SetNeedsBeginFrame(bool enable) {
-  TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable);
-  needs_begin_frame_ = enable;
-  client_ready_for_begin_frame_ = true;
+void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
+  TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
+  needs_begin_impl_frame_ = enable;
+  client_ready_for_begin_impl_frame_ = true;
   if (frame_rate_controller_) {
     BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
     if (skipped.IsValid())
-      skipped_begin_frame_args_ = skipped;
+      skipped_begin_impl_frame_args_ = skipped;
   }
-  if (needs_begin_frame_)
-    PostCheckForRetroactiveBeginFrame();
+  if (needs_begin_impl_frame_)
+    PostCheckForRetroactiveBeginImplFrame();
 }
 
-void OutputSurface::BeginFrame(const BeginFrameArgs& args) {
-  TRACE_EVENT2("cc", "OutputSurface::BeginFrame",
-               "client_ready_for_begin_frame_", client_ready_for_begin_frame_,
+void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
+  TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
+               "client_ready_for_begin_impl_frame_",
+               client_ready_for_begin_impl_frame_,
                "pending_swap_buffers_", pending_swap_buffers_);
-  if (!needs_begin_frame_ || !client_ready_for_begin_frame_ ||
+  if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
       (pending_swap_buffers_ >= max_frames_pending_ &&
        max_frames_pending_ > 0)) {
-    skipped_begin_frame_args_ = args;
+    skipped_begin_impl_frame_args_ = args;
   } else {
-    client_ready_for_begin_frame_ = false;
-    client_->BeginFrame(args);
-    // args might be an alias for skipped_begin_frame_args_.
-    // Do not reset it before calling BeginFrame!
-    skipped_begin_frame_args_ = BeginFrameArgs();
+    client_ready_for_begin_impl_frame_ = false;
+    client_->BeginImplFrame(args);
+    // args might be an alias for skipped_begin_impl_frame_args_.
+    // Do not reset it before calling BeginImplFrame!
+    skipped_begin_impl_frame_args_ = BeginFrameArgs();
   }
 }
 
-base::TimeTicks OutputSurface::RetroactiveBeginFrameDeadline() {
+base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
   // TODO(brianderson): Remove the alternative deadline once we have better
   // deadline estimations.
   base::TimeTicks alternative_deadline =
-      skipped_begin_frame_args_.frame_time +
+      skipped_begin_impl_frame_args_.frame_time +
       BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
-  return std::max(skipped_begin_frame_args_.deadline, alternative_deadline);
+  return std::max(skipped_begin_impl_frame_args_.deadline,
+                  alternative_deadline);
 }
 
-void OutputSurface::PostCheckForRetroactiveBeginFrame() {
-  if (!skipped_begin_frame_args_.IsValid() ||
-      check_for_retroactive_begin_frame_pending_)
+void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
+  if (!skipped_begin_impl_frame_args_.IsValid() ||
+      check_for_retroactive_begin_impl_frame_pending_)
     return;
 
   base::MessageLoop::current()->PostTask(
      FROM_HERE,
-     base::Bind(&OutputSurface::CheckForRetroactiveBeginFrame,
+     base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
                 weak_ptr_factory_.GetWeakPtr()));
-  check_for_retroactive_begin_frame_pending_ = true;
+  check_for_retroactive_begin_impl_frame_pending_ = true;
 }
 
-void OutputSurface::CheckForRetroactiveBeginFrame() {
-  TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame");
-  check_for_retroactive_begin_frame_pending_ = false;
-  if (base::TimeTicks::Now() < RetroactiveBeginFrameDeadline())
-    BeginFrame(skipped_begin_frame_args_);
+void OutputSurface::CheckForRetroactiveBeginImplFrame() {
+  TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
+  check_for_retroactive_begin_impl_frame_pending_ = false;
+  if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
+    BeginImplFrame(skipped_begin_impl_frame_args_);
 }
 
 void OutputSurface::DidSwapBuffers() {
@@ -208,7 +214,7 @@
                "pending_swap_buffers_", pending_swap_buffers_);
   if (frame_rate_controller_)
     frame_rate_controller_->DidSwapBuffers();
-  PostCheckForRetroactiveBeginFrame();
+  PostCheckForRetroactiveBeginImplFrame();
 }
 
 void OutputSurface::OnSwapBuffersComplete() {
@@ -218,7 +224,7 @@
   client_->OnSwapBuffersComplete();
   if (frame_rate_controller_)
     frame_rate_controller_->DidSwapBuffersComplete();
-  PostCheckForRetroactiveBeginFrame();
+  PostCheckForRetroactiveBeginImplFrame();
 }
 
 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
@@ -227,9 +233,9 @@
 
 void OutputSurface::DidLoseOutputSurface() {
   TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
-  client_ready_for_begin_frame_ = true;
+  client_ready_for_begin_impl_frame_ = true;
   pending_swap_buffers_ = 0;
-  skipped_begin_frame_args_ = BeginFrameArgs();
+  skipped_begin_impl_frame_args_ = BeginFrameArgs();
   if (frame_rate_controller_)
     frame_rate_controller_->SetActive(false);
   pending_gpu_latency_query_ids_.clear();
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 97e5744..2887e80 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -68,7 +68,7 @@
     int max_frames_pending;
     bool deferred_gl_initialization;
     bool draw_and_swap_full_viewport_every_frame;
-    // This doesn't handle the <webview> case, but once BeginFrame is
+    // This doesn't handle the <webview> case, but once BeginImplFrame is
     // supported natively, we shouldn't need adjust_deadline_for_parent.
     bool adjust_deadline_for_parent;
     // Whether this output surface renders to the default OpenGL zero
@@ -104,7 +104,7 @@
   // thread.
   virtual bool BindToClient(OutputSurfaceClient* client);
 
-  void InitializeBeginFrameEmulation(
+  void InitializeBeginImplFrameEmulation(
       base::SingleThreadTaskRunner* task_runner,
       bool throttle_frame_production,
       base::TimeDelta interval);
@@ -128,10 +128,10 @@
   // processing should be stopped, or lowered in priority.
   virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {}
 
-  // Requests a BeginFrame notification from the output surface. The
+  // Requests a BeginImplFrame notification from the output surface. The
   // notification will be delivered by calling
-  // OutputSurfaceClient::BeginFrame until the callback is disabled.
-  virtual void SetNeedsBeginFrame(bool enable);
+  // OutputSurfaceClient::BeginImplFrame until the callback is disabled.
+  virtual void SetNeedsBeginImplFrame(bool enable);
 
   bool HasClient() { return !!client_; }
 
@@ -160,7 +160,7 @@
   float device_scale_factor_;
 
   // The FrameRateController is deprecated.
-  // Platforms should move to native BeginFrames instead.
+  // Platforms should move to native BeginImplFrames instead.
   void OnVSyncParametersChanged(base::TimeTicks timebase,
                                 base::TimeDelta interval);
   virtual void FrameRateControllerTick(bool throttled,
@@ -168,17 +168,17 @@
   scoped_ptr<FrameRateController> frame_rate_controller_;
   int max_frames_pending_;
   int pending_swap_buffers_;
-  bool needs_begin_frame_;
-  bool client_ready_for_begin_frame_;
+  bool needs_begin_impl_frame_;
+  bool client_ready_for_begin_impl_frame_;
 
-  // This stores a BeginFrame that we couldn't process immediately, but might
-  // process retroactively in the near future.
-  BeginFrameArgs skipped_begin_frame_args_;
+  // This stores a BeginImplFrame that we couldn't process immediately,
+  // but might process retroactively in the near future.
+  BeginFrameArgs skipped_begin_impl_frame_args_;
 
   // Forwarded to OutputSurfaceClient but threaded through OutputSurface
   // first so OutputSurface has a chance to update the FrameRateController
   void SetNeedsRedrawRect(gfx::Rect damage_rect);
-  void BeginFrame(const BeginFrameArgs& args);
+  void BeginImplFrame(const BeginFrameArgs& args);
   void DidSwapBuffers();
   void OnSwapBuffersComplete();
   void ReclaimResources(const CompositorFrameAck* ack);
@@ -190,13 +190,12 @@
                                   bool valid_for_tile_management);
 
   // virtual for testing.
-  virtual base::TimeTicks RetroactiveBeginFrameDeadline();
-  virtual void PostCheckForRetroactiveBeginFrame();
-  void CheckForRetroactiveBeginFrame();
+  virtual base::TimeTicks RetroactiveBeginImplFrameDeadline();
+  virtual void PostCheckForRetroactiveBeginImplFrame();
+  void CheckForRetroactiveBeginImplFrame();
 
  private:
   OutputSurfaceClient* client_;
-  friend class OutputSurfaceCallbacks;
 
   void SetUpContext3d();
   void ResetContext3d();
@@ -204,9 +203,9 @@
                        bool discard_backbuffer_when_not_visible);
   void UpdateAndMeasureGpuLatency();
 
-  // check_for_retroactive_begin_frame_pending_ is used to avoid posting
-  // redundant checks for a retroactive BeginFrame.
-  bool check_for_retroactive_begin_frame_pending_;
+  // check_for_retroactive_begin_impl_frame_pending_ is used to avoid posting
+  // redundant checks for a retroactive BeginImplFrame.
+  bool check_for_retroactive_begin_impl_frame_pending_;
 
   bool external_stencil_test_enabled_;
 
diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h
index c0e2e45..192400c 100644
--- a/cc/output/output_surface_client.h
+++ b/cc/output/output_surface_client.h
@@ -31,7 +31,7 @@
       scoped_refptr<ContextProvider> offscreen_context_provider) = 0;
   virtual void ReleaseGL() = 0;
   virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) = 0;
-  virtual void BeginFrame(const BeginFrameArgs& args) = 0;
+  virtual void BeginImplFrame(const BeginFrameArgs& args) = 0;
   virtual void OnSwapBuffersComplete() = 0;
   virtual void ReclaimResources(const CompositorFrameAck* ack) = 0;
   virtual void DidLoseOutputSurface() = 0;
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index 91e7c39..1a1db29 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -15,6 +15,7 @@
 #include "cc/test/scheduler_test_common.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 namespace {
@@ -23,19 +24,19 @@
  public:
   explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
       : OutputSurface(context_provider),
-        retroactive_begin_frame_deadline_enabled_(false),
+        retroactive_begin_impl_frame_deadline_enabled_(false),
         override_retroactive_period_(false) {}
 
   explicit TestOutputSurface(
       scoped_ptr<cc::SoftwareOutputDevice> software_device)
       : OutputSurface(software_device.Pass()),
-        retroactive_begin_frame_deadline_enabled_(false),
+        retroactive_begin_impl_frame_deadline_enabled_(false),
         override_retroactive_period_(false) {}
 
   TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
                     scoped_ptr<cc::SoftwareOutputDevice> software_device)
       : OutputSurface(context_provider, software_device.Pass()),
-        retroactive_begin_frame_deadline_enabled_(false),
+        retroactive_begin_impl_frame_deadline_enabled_(false),
         override_retroactive_period_(false) {}
 
   bool InitializeNewContext3d(
@@ -51,8 +52,8 @@
     OnVSyncParametersChanged(timebase, interval);
   }
 
-  void BeginFrameForTesting() {
-    OutputSurface::BeginFrame(BeginFrameArgs::CreateExpiredForTesting());
+  void BeginImplFrameForTesting() {
+    OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting());
   }
 
   void DidSwapBuffersForTesting() {
@@ -67,33 +68,34 @@
     OnSwapBuffersComplete();
   }
 
-  void EnableRetroactiveBeginFrameDeadline(bool enable,
-                                           bool override_retroactive_period,
-                                           base::TimeDelta period_override) {
-    retroactive_begin_frame_deadline_enabled_ = enable;
+  void EnableRetroactiveBeginImplFrameDeadline(
+      bool enable,
+      bool override_retroactive_period,
+      base::TimeDelta period_override) {
+    retroactive_begin_impl_frame_deadline_enabled_ = enable;
     override_retroactive_period_ = override_retroactive_period;
     retroactive_period_override_ = period_override;
   }
 
  protected:
-  virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE {
+  virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE {
     // For testing purposes, we check immediately rather than posting a task.
-    CheckForRetroactiveBeginFrame();
+    CheckForRetroactiveBeginImplFrame();
   }
 
-  virtual base::TimeTicks RetroactiveBeginFrameDeadline() OVERRIDE {
-    if (retroactive_begin_frame_deadline_enabled_) {
+  virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE {
+    if (retroactive_begin_impl_frame_deadline_enabled_) {
       if (override_retroactive_period_) {
-        return skipped_begin_frame_args_.frame_time +
+        return skipped_begin_impl_frame_args_.frame_time +
                retroactive_period_override_;
       } else {
-        return OutputSurface::RetroactiveBeginFrameDeadline();
+        return OutputSurface::RetroactiveBeginImplFrameDeadline();
       }
     }
     return base::TimeTicks();
   }
 
-  bool retroactive_begin_frame_deadline_enabled_;
+  bool retroactive_begin_impl_frame_deadline_enabled_;
   bool override_retroactive_period_;
   base::TimeDelta retroactive_period_override_;
 };
@@ -218,7 +220,7 @@
   InitializeNewContextExpectFail();
 }
 
-TEST(OutputSurfaceTest, BeginFrameEmulation) {
+TEST(OutputSurfaceTest, BeginImplFrameEmulation) {
   TestOutputSurface output_surface(TestContextProvider::Create());
   EXPECT_FALSE(output_surface.HasClient());
 
@@ -227,84 +229,86 @@
   EXPECT_TRUE(output_surface.HasClient());
   EXPECT_FALSE(client.deferred_initialize_called());
 
-  // Initialize BeginFrame emulation
+  // Initialize BeginImplFrame emulation
   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
       new base::TestSimpleTaskRunner;
   bool throttle_frame_production = true;
   const base::TimeDelta display_refresh_interval =
       BeginFrameArgs::DefaultInterval();
 
-  output_surface.InitializeBeginFrameEmulation(
+  output_surface.InitializeBeginImplFrameEmulation(
       task_runner.get(),
       throttle_frame_production,
       display_refresh_interval);
 
   output_surface.SetMaxFramesPending(2);
-  output_surface.EnableRetroactiveBeginFrameDeadline(
+  output_surface.EnableRetroactiveBeginImplFrameDeadline(
       false, false, base::TimeDelta());
 
-  // We should start off with 0 BeginFrames
-  EXPECT_EQ(client.begin_frame_count(), 0);
+  // We should start off with 0 BeginImplFrames
+  EXPECT_EQ(client.begin_impl_frame_count(), 0);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
 
-  // We should not have a pending task until a BeginFrame has been requested.
+  // We should not have a pending task until a BeginImplFrame has been
+  // requested.
   EXPECT_FALSE(task_runner->HasPendingTask());
-  output_surface.SetNeedsBeginFrame(true);
+  output_surface.SetNeedsBeginImplFrame(true);
   EXPECT_TRUE(task_runner->HasPendingTask());
 
-  // BeginFrame should be called on the first tick.
+  // BeginImplFrame should be called on the first tick.
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
 
-  // BeginFrame should not be called when there is a pending BeginFrame.
+  // BeginImplFrame should not be called when there is a pending BeginImplFrame.
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
 
-  // SetNeedsBeginFrame should clear the pending BeginFrame after
+  // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after
   // a SwapBuffers.
   output_surface.DidSwapBuffersForTesting();
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
 
-  // BeginFrame should be throttled by pending swap buffers.
+  // BeginImplFrame should be throttled by pending swap buffers.
   output_surface.DidSwapBuffersForTesting();
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
 
-  // SwapAck should decrement pending swap buffers and unblock BeginFrame again.
+  // SwapAck should decrement pending swap buffers and unblock BeginImplFrame
+  // again.
   output_surface.OnSwapBuffersCompleteForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 3);
+  EXPECT_EQ(client.begin_impl_frame_count(), 3);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
 
-  // Calling SetNeedsBeginFrame again indicates a swap did not occur but
-  // the client still wants another BeginFrame.
-  output_surface.SetNeedsBeginFrame(true);
+  // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but
+  // the client still wants another BeginImplFrame.
+  output_surface.SetNeedsBeginImplFrame(true);
   task_runner->RunPendingTasks();
-  EXPECT_EQ(client.begin_frame_count(), 4);
+  EXPECT_EQ(client.begin_impl_frame_count(), 4);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
 
-  // Disabling SetNeedsBeginFrame should prevent further BeginFrames.
-  output_surface.SetNeedsBeginFrame(false);
+  // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames.
+  output_surface.SetNeedsBeginImplFrame(false);
   task_runner->RunPendingTasks();
   EXPECT_FALSE(task_runner->HasPendingTask());
-  EXPECT_EQ(client.begin_frame_count(), 4);
+  EXPECT_EQ(client.begin_impl_frame_count(), 4);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
 }
 
-TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginFrames) {
+TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) {
   TestOutputSurface output_surface(TestContextProvider::Create());
   EXPECT_FALSE(output_surface.HasClient());
 
@@ -314,47 +318,48 @@
   EXPECT_FALSE(client.deferred_initialize_called());
 
   output_surface.SetMaxFramesPending(2);
-  output_surface.EnableRetroactiveBeginFrameDeadline(
+  output_surface.EnableRetroactiveBeginImplFrameDeadline(
       true, false, base::TimeDelta());
 
-  // Optimistically injected BeginFrames should be throttled if
-  // SetNeedsBeginFrame is false...
-  output_surface.SetNeedsBeginFrame(false);
-  output_surface.BeginFrameForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 0);
-  // ...and retroactively triggered by a SetNeedsBeginFrame.
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  // Optimistically injected BeginImplFrames should be throttled if
+  // SetNeedsBeginImplFrame is false...
+  output_surface.SetNeedsBeginImplFrame(false);
+  output_surface.BeginImplFrameForTesting();
+  EXPECT_EQ(client.begin_impl_frame_count(), 0);
+  // ...and retroactively triggered by a SetNeedsBeginImplFrame.
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
 
-  // Optimistically injected BeginFrames should be throttled by pending
-  // BeginFrames...
-  output_surface.BeginFrameForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 1);
-  // ...and retroactively triggered by a SetNeedsBeginFrame.
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  // Optimistically injected BeginImplFrames should be throttled by pending
+  // BeginImplFrames...
+  output_surface.BeginImplFrameForTesting();
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
+  // ...and retroactively triggered by a SetNeedsBeginImplFrame.
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   // ...or retroactively triggered by a Swap.
-  output_surface.BeginFrameForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 2);
+  output_surface.BeginImplFrameForTesting();
+  EXPECT_EQ(client.begin_impl_frame_count(), 2);
   output_surface.DidSwapBuffersForTesting();
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 3);
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 3);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
 
-  // Optimistically injected BeginFrames should be by throttled by pending
+  // Optimistically injected BeginImplFrames should be by throttled by pending
   // swap buffers...
   output_surface.DidSwapBuffersForTesting();
-  output_surface.SetNeedsBeginFrame(true);
-  EXPECT_EQ(client.begin_frame_count(), 3);
+  output_surface.SetNeedsBeginImplFrame(true);
+  EXPECT_EQ(client.begin_impl_frame_count(), 3);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
-  output_surface.BeginFrameForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 3);
+  output_surface.BeginImplFrameForTesting();
+  EXPECT_EQ(client.begin_impl_frame_count(), 3);
   // ...and retroactively triggered by OnSwapBuffersComplete
   output_surface.OnSwapBuffersCompleteForTesting();
-  EXPECT_EQ(client.begin_frame_count(), 4);
+  EXPECT_EQ(client.begin_impl_frame_count(), 4);
 }
 
-TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) {
+TEST(OutputSurfaceTest,
+     RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) {
   scoped_refptr<TestContextProvider> context_provider =
       TestContextProvider::Create();
 
@@ -368,13 +373,13 @@
 
   base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10);
 
-  // Initialize BeginFrame emulation
+  // Initialize BeginImplFrame emulation
   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
       new base::TestSimpleTaskRunner;
   bool throttle_frame_production = true;
   const base::TimeDelta display_refresh_interval = big_interval;
 
-  output_surface.InitializeBeginFrameEmulation(
+  output_surface.InitializeBeginImplFrameEmulation(
       task_runner.get(),
       throttle_frame_production,
       display_refresh_interval);
@@ -382,31 +387,34 @@
   // We need to subtract an epsilon from Now() because some platforms have
   // a slow clock.
   output_surface.OnVSyncParametersChangedForTesting(
-      base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1), big_interval);
+      gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval);
 
   output_surface.SetMaxFramesPending(2);
-  output_surface.EnableRetroactiveBeginFrameDeadline(true, true, big_interval);
+  output_surface.EnableRetroactiveBeginImplFrameDeadline(
+      true, true, big_interval);
 
-  // We should start off with 0 BeginFrames
-  EXPECT_EQ(client.begin_frame_count(), 0);
+  // We should start off with 0 BeginImplFrames
+  EXPECT_EQ(client.begin_impl_frame_count(), 0);
   EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
 
-  // The first SetNeedsBeginFrame(true) should start a retroactive BeginFrame.
+  // The first SetNeedsBeginImplFrame(true) should start a retroactive
+  // BeginImplFrame.
   EXPECT_FALSE(task_runner->HasPendingTask());
-  output_surface.SetNeedsBeginFrame(true);
+  output_surface.SetNeedsBeginImplFrame(true);
   EXPECT_TRUE(task_runner->HasPendingTask());
   EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
 
-  output_surface.SetNeedsBeginFrame(false);
+  output_surface.SetNeedsBeginImplFrame(false);
   EXPECT_TRUE(task_runner->HasPendingTask());
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
 
-  // The second SetNeedBeginFrame(true) should not retroactively start a
-  // BeginFrame if the timestamp would be the same as the previous BeginFrame.
-  output_surface.SetNeedsBeginFrame(true);
+  // The second SetNeedBeginImplFrame(true) should not retroactively start a
+  // BeginImplFrame if the timestamp would be the same as the previous
+  // BeginImplFrame.
+  output_surface.SetNeedsBeginImplFrame(true);
   EXPECT_TRUE(task_runner->HasPendingTask());
-  EXPECT_EQ(client.begin_frame_count(), 1);
+  EXPECT_EQ(client.begin_impl_frame_count(), 1);
 }
 
 TEST(OutputSurfaceTest, MemoryAllocation) {
@@ -421,20 +429,20 @@
   ManagedMemoryPolicy policy(0);
   policy.bytes_limit_when_visible = 1234;
   policy.priority_cutoff_when_visible =
-      ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
+      gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
   policy.bytes_limit_when_not_visible = 4567;
   policy.priority_cutoff_when_not_visible =
-      ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
+      gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING;
 
   bool discard_backbuffer_when_not_visible = false;
 
   context_provider->SetMemoryAllocation(policy,
                                         discard_backbuffer_when_not_visible);
   EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
-  EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY,
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY,
             client.memory_policy().priority_cutoff_when_visible);
   EXPECT_EQ(4567u, client.memory_policy().bytes_limit_when_not_visible);
-  EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
             client.memory_policy().priority_cutoff_when_not_visible);
   EXPECT_FALSE(client.discard_backbuffer_when_not_visible());
 
@@ -444,14 +452,14 @@
   EXPECT_TRUE(client.discard_backbuffer_when_not_visible());
 
   policy.priority_cutoff_when_visible =
-      ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
+      gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
   policy.priority_cutoff_when_not_visible =
-      ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
+      gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
   context_provider->SetMemoryAllocation(policy,
                                         discard_backbuffer_when_not_visible);
-  EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
             client.memory_policy().priority_cutoff_when_visible);
-  EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
             client.memory_policy().priority_cutoff_when_not_visible);
 
   // 0 bytes limit should be ignored.
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index f88a9ee..450d1fe 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -34,7 +34,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
     renderer_ = SoftwareRenderer::Create(
         this, &settings_, output_surface_.get(), resource_provider());
   }
diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc
index e61a463..6d6c430 100644
--- a/cc/quads/render_pass.cc
+++ b/cc/quads/render_pass.cc
@@ -65,10 +65,11 @@
           source->shared_quad_state_list[i]->Copy());
     }
     for (size_t i = 0, sqs_i = 0; i < source->quad_list.size(); ++i) {
-      if (source->quad_list[i]->shared_quad_state !=
-          source->shared_quad_state_list[sqs_i])
+      while (source->quad_list[i]->shared_quad_state !=
+             source->shared_quad_state_list[sqs_i]) {
         ++sqs_i;
-      DCHECK(sqs_i < source->shared_quad_state_list.size());
+        DCHECK_LT(sqs_i, source->shared_quad_state_list.size());
+      }
       DCHECK(source->quad_list[i]->shared_quad_state ==
              source->shared_quad_state_list[sqs_i]);
 
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index 259ecad..394a3ec 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -33,6 +33,35 @@
   ScopedPtrVector<CopyOutputRequest> copy_callbacks;
 };
 
+static void CompareRenderPassLists(const RenderPassList& expected_list,
+                                   const RenderPassList& actual_list) {
+  EXPECT_EQ(expected_list.size(), actual_list.size());
+  for (size_t i = 0; i < actual_list.size(); ++i) {
+    RenderPass* expected = expected_list[i];
+    RenderPass* actual = actual_list[i];
+
+    EXPECT_EQ(expected->id, actual->id);
+    EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+    EXPECT_EQ(expected->transform_to_root_target,
+              actual->transform_to_root_target);
+    EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+    EXPECT_EQ(expected->has_transparent_background,
+              actual->has_transparent_background);
+
+    EXPECT_EQ(expected->shared_quad_state_list.size(),
+              actual->shared_quad_state_list.size());
+    EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size());
+
+    for (size_t i = 0; i < expected->quad_list.size(); ++i) {
+      EXPECT_EQ(expected->quad_list[i]->rect.ToString(),
+                actual->quad_list[i]->rect.ToString());
+      EXPECT_EQ(
+          expected->quad_list[i]->shared_quad_state->content_bounds.ToString(),
+          actual->quad_list[i]->shared_quad_state->content_bounds.ToString());
+    }
+  }
+}
+
 TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
   RenderPass::Id id(3, 2);
   gfx::Rect output_rect(45, 22, 120, 13);
@@ -177,30 +206,69 @@
   RenderPassList copy_list;
   RenderPass::CopyAll(pass_list, &copy_list);
 
-  EXPECT_EQ(pass_list.size(), copy_list.size());
-  for (size_t i = 0; i < copy_list.size(); ++i) {
-    RenderPass* pass = pass_list[i];
-    RenderPass* copy = copy_list[i];
+  CompareRenderPassLists(pass_list, copy_list);
+}
 
-    EXPECT_EQ(pass->id, copy->id);
-    EXPECT_RECT_EQ(pass->output_rect, copy->output_rect);
-    EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target);
-    EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect);
-    EXPECT_EQ(pass->has_transparent_background,
-              copy->has_transparent_background);
+TEST(RenderPassTest, CopyAllWithCulledQuads) {
+  RenderPassList pass_list;
 
-    EXPECT_EQ(pass->shared_quad_state_list.size(),
-              copy->shared_quad_state_list.size());
-    EXPECT_EQ(pass->quad_list.size(), copy->quad_list.size());
+  RenderPass::Id id(3, 2);
+  gfx::Rect output_rect(45, 22, 120, 13);
+  gfx::Transform transform_to_root =
+      gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0);
+  gfx::Rect damage_rect(56, 123, 19, 43);
+  bool has_transparent_background = true;
 
-    for (size_t i = 0; i < pass->quad_list.size(); ++i) {
-      EXPECT_EQ(pass->quad_list[i]->rect.ToString(),
-                copy->quad_list[i]->rect.ToString());
-      EXPECT_EQ(
-          pass->quad_list[i]->shared_quad_state->content_bounds.ToString(),
-          copy->quad_list[i]->shared_quad_state->content_bounds.ToString());
-    }
-  }
+  scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
+  pass->SetAll(id,
+               output_rect,
+               damage_rect,
+               transform_to_root,
+               has_transparent_background);
+
+  // A shared state with a quad.
+  scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create();
+  shared_state1->SetAll(
+      gfx::Transform(), gfx::Size(1, 1), gfx::Rect(), gfx::Rect(), false, 1);
+  pass->AppendSharedQuadState(shared_state1.Pass());
+
+  scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 =
+      CheckerboardDrawQuad::Create();
+  checkerboard_quad1->SetNew(
+      pass->shared_quad_state_list.back(), gfx::Rect(1, 1, 1, 1), SkColor());
+  pass->quad_list.push_back(checkerboard_quad1.PassAs<DrawQuad>());
+
+  // A shared state with no quads, they were culled.
+  scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create();
+  shared_state2->SetAll(
+      gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+  pass->AppendSharedQuadState(shared_state2.Pass());
+
+  // A second shared state with no quads.
+  scoped_ptr<SharedQuadState> shared_state3 = SharedQuadState::Create();
+  shared_state3->SetAll(
+      gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+  pass->AppendSharedQuadState(shared_state3.Pass());
+
+  // A last shared state with a quad again.
+  scoped_ptr<SharedQuadState> shared_state4 = SharedQuadState::Create();
+  shared_state4->SetAll(
+      gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+  pass->AppendSharedQuadState(shared_state4.Pass());
+
+  scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 =
+      CheckerboardDrawQuad::Create();
+  checkerboard_quad2->SetNew(
+      pass->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor());
+  pass->quad_list.push_back(checkerboard_quad2.PassAs<DrawQuad>());
+
+  pass_list.push_back(pass.PassAs<RenderPass>());
+
+  // Make a copy with CopyAll().
+  RenderPassList copy_list;
+  RenderPass::CopyAll(pass_list, &copy_list);
+
+  CompareRenderPassLists(pass_list, copy_list);
 }
 
 }  // namespace
diff --git a/cc/resources/bitmap_skpicture_content_layer_updater.cc b/cc/resources/bitmap_skpicture_content_layer_updater.cc
index 6b6cd9f..cc839a6 100644
--- a/cc/resources/bitmap_skpicture_content_layer_updater.cc
+++ b/cc/resources/bitmap_skpicture_content_layer_updater.cc
@@ -25,9 +25,9 @@
     gfx::Vector2d dest_offset,
     bool partial_update) {
   bitmap_.setConfig(
-      SkBitmap::kARGB_8888_Config, source_rect.width(), source_rect.height());
+      SkBitmap::kARGB_8888_Config, source_rect.width(), source_rect.height(), 0,
+      updater_->layer_is_opaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   bitmap_.allocPixels();
-  bitmap_.setIsOpaque(updater_->layer_is_opaque());
   SkBitmapDevice device(bitmap_);
   SkCanvas canvas(&device);
   updater_->PaintContentsRect(&canvas, source_rect);
diff --git a/cc/resources/image_raster_worker_pool.cc b/cc/resources/image_raster_worker_pool.cc
index 30add2a..e665837 100644
--- a/cc/resources/image_raster_worker_pool.cc
+++ b/cc/resources/image_raster_worker_pool.cc
@@ -149,7 +149,7 @@
   set_raster_required_for_activation_finished_task(
       new_raster_required_for_activation_finished_task);
 
-  TRACE_EVENT_ASYNC_STEP1(
+  TRACE_EVENT_ASYNC_STEP_INTO1(
       "cc", "ScheduledTasks", this, "rasterizing",
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
@@ -169,7 +169,7 @@
 void ImageRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() {
   DCHECK(raster_tasks_required_for_activation_pending_);
   raster_tasks_required_for_activation_pending_ = false;
-  TRACE_EVENT_ASYNC_STEP1(
+  TRACE_EVENT_ASYNC_STEP_INTO1(
       "cc", "ScheduledTasks", this, "rasterizing",
       "state", TracedValue::FromValue(StateAsValue().release()));
   client()->DidFinishRunningTasksRequiredForActivation();
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 8083050..7e278f8 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -86,7 +86,8 @@
 }
 
 Picture::Picture(gfx::Rect layer_rect)
-    : layer_rect_(layer_rect) {
+  : layer_rect_(layer_rect),
+    cell_size_(layer_rect.size()) {
   // Instead of recording a trace event for object creation here, we wait for
   // the picture to be recorded in Picture::Record.
 }
@@ -155,7 +156,8 @@
                  gfx::Rect opaque_rect) :
     layer_rect_(layer_rect),
     opaque_rect_(opaque_rect),
-    picture_(skia::AdoptRef(picture)) {
+    picture_(skia::AdoptRef(picture)),
+    cell_size_(layer_rect.size()) {
 }
 
 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
@@ -165,7 +167,8 @@
     layer_rect_(layer_rect),
     opaque_rect_(opaque_rect),
     picture_(picture),
-    pixel_refs_(pixel_refs) {
+    pixel_refs_(pixel_refs),
+    cell_size_(layer_rect.size()) {
 }
 
 Picture::~Picture() {
@@ -294,16 +297,21 @@
 int Picture::Raster(
     SkCanvas* canvas,
     SkDrawPictureCallback* callback,
-    gfx::Rect content_rect,
+    const Region& negated_content_region,
     float contents_scale) {
   TRACE_EVENT_BEGIN1(
-      "cc", "Picture::Raster",
-      "data", AsTraceableRasterData(content_rect, contents_scale));
+      "cc",
+      "Picture::Raster",
+      "data",
+      AsTraceableRasterData(contents_scale));
 
   DCHECK(picture_);
 
   canvas->save();
-  canvas->clipRect(gfx::RectToSkRect(content_rect));
+
+  for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
+    canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
+
   canvas->scale(contents_scale, contents_scale);
   canvas->translate(layer_rect_.x(), layer_rect_.y());
   picture_->draw(canvas, callback);
@@ -382,8 +390,9 @@
       current_index_(0) {
   gfx::Rect layer_rect = picture->layer_rect_;
   gfx::Size cell_size = picture->cell_size_;
+  DCHECK(!cell_size.IsEmpty());
 
-  // Early out if the query rect doesn't intersect this picture
+  // Early out if the query rect doesn't intersect this picture.
   if (!query_rect.Intersects(layer_rect)) {
     min_point_ = gfx::Point(0, 0);
     max_point_ = gfx::Point(0, 0);
@@ -460,14 +469,10 @@
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat>
-    Picture::AsTraceableRasterData(gfx::Rect rect, float scale) const {
+    Picture::AsTraceableRasterData(float scale) const {
   scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
   raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
   raster_data->SetDouble("scale", scale);
-  raster_data->SetDouble("rect_x", rect.x());
-  raster_data->SetDouble("rect_y", rect.y());
-  raster_data->SetDouble("rect_width", rect.width());
-  raster_data->SetDouble("rect_height", rect.height());
   return TracedValue::FromValue(raster_data.release());
 }
 
diff --git a/cc/resources/picture.h b/cc/resources/picture.h
index 8210e86..4eb238a 100644
--- a/cc/resources/picture.h
+++ b/cc/resources/picture.h
@@ -17,6 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
+#include "cc/base/region.h"
 #include "skia/ext/lazy_pixel_ref.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkPixelRef.h"
@@ -67,10 +68,11 @@
   // Has Record() been called yet?
   bool HasRecording() const { return picture_.get() != NULL; }
 
-  // Apply this contents scale and raster the content rect into the canvas.
+  // Apply this scale and raster the negated region into the canvas. See comment
+  // in PicturePileImpl::RasterCommon for explanation on negated content region.
   int Raster(SkCanvas* canvas,
              SkDrawPictureCallback* callback,
-             gfx::Rect content_rect,
+             const Region& negated_content_region,
              float contents_scale);
 
   // Draw the picture directly into the given canvas, without applying any
@@ -142,7 +144,7 @@
   gfx::Size cell_size_;
 
   scoped_refptr<base::debug::ConvertableToTraceFormat>
-    AsTraceableRasterData(gfx::Rect rect, float scale) const;
+    AsTraceableRasterData(float scale) const;
   scoped_refptr<base::debug::ConvertableToTraceFormat>
     AsTraceableRecordData() const;
 
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 655603d..7a9b8df 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -153,7 +153,12 @@
   RunInvalidateTest("50x50", full_region);
 }
 
+#if defined(OS_ANDROID)
+// TODO(vmpstr): Investigate why this is noisy (crbug.com/310220).
+TEST_F(PictureLayerTilingPerfTest, DISABLED_UpdateTilePriorities) {
+#else
 TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) {
+#endif  // defined(OS_ANDROID)
   gfx::Transform transform;
   RunUpdateTilePrioritiesStationaryTest("no_transform", transform);
   RunUpdateTilePrioritiesScrollingTest("no_transform", transform);
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index 231e378..c0d6f0d 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -66,7 +66,7 @@
     CHECK(output_surface->BindToClient(&output_surface_client));
 
     scoped_ptr<ResourceProvider> resource_provider =
-        ResourceProvider::Create(output_surface.get(), 0, false);
+        ResourceProvider::Create(output_surface.get(), NULL, 0, false);
 
     FakePictureLayerTilingClient client;
     client.SetTileSize(gfx::Size(256, 256));
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index d1cb0e1..9f485b8 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -13,12 +13,6 @@
 #include "cc/resources/picture_pile_impl.h"
 
 namespace {
-// Maximum number of pictures that can overlap before we collapse them into
-// a larger one.
-const size_t kMaxOverlapping = 2;
-// Maximum percentage area of the base picture another picture in the picture
-// list can be.  If higher, we destroy the list and recreate from scratch.
-const float kResetThreshold = 0.7f;
 // Layout pixel buffer around the visible layer rect to record.  Any base
 // picture that intersects the visible layer rect expanded by this distance
 // will be recorded.
@@ -49,138 +43,74 @@
       -kPixelDistanceToRecord,
       -kPixelDistanceToRecord,
       -kPixelDistanceToRecord);
-  bool modified_pile = false;
+
+  bool invalidated = false;
   for (Region::Iterator i(invalidation); i.has_rect(); i.next()) {
     gfx::Rect invalidation = i.rect();
     // Split this inflated invalidation across tile boundaries and apply it
     // to all tiles that it touches.
     for (TilingData::Iterator iter(&tiling_, invalidation);
          iter; ++iter) {
-      gfx::Rect tile =
-          tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y());
-      if (!tile.Intersects(interest_rect)) {
-        // This invalidation touches a tile outside the interest rect, so
-        // just remove the entire picture list.
-        picture_list_map_.erase(iter.index());
-        modified_pile = true;
-        continue;
-      }
+      const PictureMapKey& key = iter.index();
 
-      gfx::Rect tile_invalidation = gfx::IntersectRects(invalidation, tile);
-      if (tile_invalidation.IsEmpty())
+      PictureMap::iterator picture_it = picture_map_.find(key);
+      if (picture_it == picture_map_.end())
         continue;
-      PictureListMap::iterator find = picture_list_map_.find(iter.index());
-      if (find == picture_list_map_.end())
-        continue;
-      PictureList& pic_list = find->second;
-      // Leave empty pic_lists empty in case there are multiple invalidations.
-      if (!pic_list.empty()) {
-        // Inflate all recordings from invalidations with a margin so that when
-        // scaled down to at least min_contents_scale, any final pixel touched
-        // by an invalidation can be fully rasterized by this picture.
-        tile_invalidation.Inset(-buffer_pixels(), -buffer_pixels());
 
-        DCHECK_GE(tile_invalidation.width(), buffer_pixels() * 2 + 1);
-        DCHECK_GE(tile_invalidation.height(), buffer_pixels() * 2 + 1);
-
-        InvalidateRect(pic_list, tile_invalidation);
-        modified_pile = true;
-      }
+      invalidated = picture_it->second.Invalidate() || invalidated;
     }
   }
 
-  int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
-
-  // Walk through all pictures in the rect of interest and record.
-  for (TilingData::Iterator iter(&tiling_, interest_rect); iter; ++iter) {
-    // Create a picture in this list if it doesn't exist.
-    PictureList& pic_list = picture_list_map_[iter.index()];
-    if (pic_list.empty()) {
-      // Inflate the base picture with a margin, similar to invalidations, so
-      // that when scaled down to at least min_contents_scale, the enclosed
-      // rect still includes content all the way to the edge of the layer.
-      gfx::Rect tile = tiling_.TileBounds(iter.index_x(), iter.index_y());
-      tile.Inset(
-        -buffer_pixels(),
-        -buffer_pixels(),
-        -buffer_pixels(),
-        -buffer_pixels());
-      scoped_refptr<Picture> base_picture = Picture::Create(tile);
-      pic_list.push_back(base_picture);
+  gfx::Rect record_rect;
+  for (TilingData::Iterator it(&tiling_, interest_rect);
+       it; ++it) {
+    const PictureMapKey& key = it.index();
+    const PictureInfo& info = picture_map_[key];
+    if (!info.picture.get()) {
+      gfx::Rect tile = PaddedRect(key);
+      record_rect.Union(tile);
     }
+  }
 
-    for (PictureList::iterator pic = pic_list.begin();
-         pic != pic_list.end(); ++pic) {
-      if (!(*pic)->HasRecording()) {
-        modified_pile = true;
-        base::TimeDelta best_duration = base::TimeDelta::FromInternalValue(
-            std::numeric_limits<int64>::max());
-        for (int i = 0; i < repeat_count; i++) {
-          base::TimeTicks start_time = stats_instrumentation->StartRecording();
-          (*pic)->Record(painter, tile_grid_info_);
-          base::TimeDelta duration =
-              stats_instrumentation->EndRecording(start_time);
-          best_duration = std::min(duration, best_duration);
-        }
-        int recorded_pixel_count =
-            (*pic)->LayerRect().width() * (*pic)->LayerRect().height();
-        stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
-        (*pic)->GatherPixelRefs(tile_grid_info_);
-        (*pic)->CloneForDrawing(num_raster_threads_);
-      }
+  if (record_rect.IsEmpty()) {
+    if (invalidated)
+      UpdateRecordedRegion();
+    return invalidated;
+  }
+
+  int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
+  scoped_refptr<Picture> picture = Picture::Create(record_rect);
+
+  {
+    base::TimeDelta best_duration = base::TimeDelta::FromInternalValue(
+        std::numeric_limits<int64>::max());
+    for (int i = 0; i < repeat_count; i++) {
+      base::TimeTicks start_time = stats_instrumentation->StartRecording();
+      picture->Record(painter, tile_grid_info_);
+      base::TimeDelta duration =
+          stats_instrumentation->EndRecording(start_time);
+      best_duration = std::min(duration, best_duration);
+    }
+    int recorded_pixel_count =
+        picture->LayerRect().width() * picture->LayerRect().height();
+    stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
+    if (num_raster_threads_ > 1)
+      picture->GatherPixelRefs(tile_grid_info_);
+    picture->CloneForDrawing(num_raster_threads_);
+  }
+
+  for (TilingData::Iterator it(&tiling_, record_rect);
+       it; ++it) {
+    const PictureMapKey& key = it.index();
+    gfx::Rect tile = PaddedRect(key);
+    if (record_rect.Contains(tile)) {
+      PictureInfo& info = picture_map_[key];
+      info.picture = picture;
     }
   }
 
   UpdateRecordedRegion();
-
-  return modified_pile;
-}
-
-class FullyContainedPredicate {
- public:
-  explicit FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) {}
-  bool operator()(const scoped_refptr<Picture>& picture) {
-    return picture->LayerRect().IsEmpty() ||
-        layer_rect_.Contains(picture->LayerRect());
-  }
-  gfx::Rect layer_rect_;
-};
-
-void PicturePile::InvalidateRect(
-    PictureList& picture_list,
-    gfx::Rect invalidation) {
-  DCHECK(!picture_list.empty());
-  DCHECK(!invalidation.IsEmpty());
-
-  std::vector<PictureList::iterator> overlaps;
-  for (PictureList::iterator i = picture_list.begin();
-       i != picture_list.end(); ++i) {
-    if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording())
-      return;
-    if ((*i)->LayerRect().Intersects(invalidation) && i != picture_list.begin())
-      overlaps.push_back(i);
-  }
-
-  gfx::Rect picture_rect = invalidation;
-  if (overlaps.size() >= kMaxOverlapping) {
-    for (size_t j = 0; j < overlaps.size(); j++)
-      picture_rect.Union((*overlaps[j])->LayerRect());
-  }
-
-  Picture* base_picture = picture_list.front().get();
-  int max_pixels = kResetThreshold * base_picture->LayerRect().size().GetArea();
-  if (picture_rect.size().GetArea() > max_pixels) {
-    // This picture list will be entirely recreated, so clear it.
-    picture_list.clear();
-    return;
-  }
-
-  FullyContainedPredicate pred(picture_rect);
-  picture_list.erase(std::remove_if(picture_list.begin(),
-                                    picture_list.end(),
-                                    pred),
-                     picture_list.end());
-  picture_list.push_back(Picture::Create(picture_rect));
+  return true;
 }
 
 }  // namespace cc
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index 7830a9e..90fc015 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -46,12 +46,6 @@
  private:
   friend class PicturePileImpl;
 
-  // Add an invalidation to this picture list.  If the list needs to be
-  // entirely recreated, leave it empty.  Do not call this on an empty list.
-  void InvalidateRect(
-      PictureList& picture_list,
-      gfx::Rect invalidation);
-
   DISALLOW_COPY_AND_ASSIGN(PicturePile);
 };
 
diff --git a/cc/resources/picture_pile_base.cc b/cc/resources/picture_pile_base.cc
index 0352d30..8633a58 100644
--- a/cc/resources/picture_pile_base.cc
+++ b/cc/resources/picture_pile_base.cc
@@ -5,6 +5,7 @@
 #include "cc/resources/picture_pile_base.h"
 
 #include <algorithm>
+#include <set>
 #include <vector>
 
 #include "base/logging.h"
@@ -17,7 +18,7 @@
 namespace {
 // Dimensions of the tiles in this picture pile as well as the dimensions of
 // the base picture in each tile.
-const int kBasePictureSize = 3000;
+const int kBasePictureSize = 512;
 const int kTileGridBorderPixels = 1;
 }
 
@@ -37,7 +38,7 @@
 }
 
 PicturePileBase::PicturePileBase(const PicturePileBase* other)
-    : picture_list_map_(other->picture_list_map_),
+    : picture_map_(other->picture_map_),
       tiling_(other->tiling_),
       recorded_region_(other->recorded_region_),
       min_contents_scale_(other->min_contents_scale_),
@@ -62,16 +63,10 @@
           other->slow_down_raster_scale_factor_for_debug_),
       show_debug_picture_borders_(other->show_debug_picture_borders_),
       num_raster_threads_(other->num_raster_threads_) {
-  const PictureListMap& other_pic_list_map = other->picture_list_map_;
-  for (PictureListMap::const_iterator map_iter = other_pic_list_map.begin();
-       map_iter != other_pic_list_map.end(); ++map_iter) {
-    PictureList& pic_list = picture_list_map_[map_iter->first];
-    const PictureList& other_pic_list = map_iter->second;
-    for (PictureList::const_iterator pic_iter = other_pic_list.begin();
-         pic_iter != other_pic_list.end(); ++pic_iter) {
-      pic_list.push_back(
-          (*pic_iter)->GetCloneForDrawingOnThread(thread_index));
-    }
+  for (PictureMap::const_iterator it = other->picture_map_.begin();
+       it != other->picture_map_.end();
+       ++it) {
+    picture_map_[it->first] = it->second.CloneForThread(thread_index);
   }
 }
 
@@ -86,20 +81,22 @@
   tiling_.SetTotalSize(new_size);
 
   // Find all tiles that contain any pixels outside the new size.
-  std::vector<PictureListMapKey> to_erase;
+  std::vector<PictureMapKey> to_erase;
   int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
       std::min(old_size.width(), new_size.width()));
   int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
       std::min(old_size.height(), new_size.height()));
-  for (PictureListMap::iterator iter = picture_list_map_.begin();
-       iter != picture_list_map_.end(); ++iter) {
-    if (iter->first.first < min_toss_x && iter->first.second < min_toss_y)
+  for (PictureMap::const_iterator it = picture_map_.begin();
+       it != picture_map_.end();
+       ++it) {
+    const PictureMapKey& key = it->first;
+    if (key.first < min_toss_x && key.second < min_toss_y)
       continue;
-    to_erase.push_back(iter->first);
+    to_erase.push_back(key);
   }
 
   for (size_t i = 0; i < to_erase.size(); ++i)
-    picture_list_map_.erase(to_erase[i]);
+    picture_map_.erase(to_erase[i]);
 }
 
 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
@@ -147,25 +144,26 @@
 }
 
 void PicturePileBase::Clear() {
-  picture_list_map_.clear();
+  picture_map_.clear();
 }
 
 void PicturePileBase::UpdateRecordedRegion() {
   recorded_region_.Clear();
-  for (PictureListMap::iterator it = picture_list_map_.begin();
-       it != picture_list_map_.end(); ++it) {
-    const PictureListMapKey& key = it->first;
-    recorded_region_.Union(tile_bounds(key.first, key.second));
+  for (PictureMap::const_iterator it = picture_map_.begin();
+       it != picture_map_.end();
+       ++it) {
+    if (it->second.picture.get()) {
+      const PictureMapKey& key = it->first;
+      recorded_region_.Union(tile_bounds(key.first, key.second));
+    }
   }
 }
 
 bool PicturePileBase::HasRecordingAt(int x, int y) {
-  PictureListMap::iterator found =
-      picture_list_map_.find(PictureListMapKey(x, y));
-  if (found == picture_list_map_.end())
+  PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
+  if (found == picture_map_.end())
     return false;
-  DCHECK(!found->second.empty());
-  return true;
+  return !!found->second.picture.get();
 }
 
 bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) {
@@ -177,25 +175,49 @@
   return recorded_region_.Contains(layer_rect);
 }
 
+gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
+  gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
+  tile.Inset(
+      -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
+  return tile;
+}
+
 scoped_ptr<base::Value> PicturePileBase::AsValue() const {
   scoped_ptr<base::ListValue> pictures(new base::ListValue());
   gfx::Rect layer_rect(tiling_.total_size());
+  std::set<void*> appended_pictures;
   for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
        tile_iter; ++tile_iter) {
-    PictureListMap::const_iterator map_iter =
-        picture_list_map_.find(tile_iter.index());
-    if (map_iter == picture_list_map_.end())
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
       continue;
-    const PictureList& pic_list= map_iter->second;
-    if (pic_list.empty())
-      continue;
-    for (PictureList::const_reverse_iterator i = pic_list.rbegin();
-         i != pic_list.rend(); ++i) {
-      Picture* picture = (*i).get();
+
+    Picture* picture = map_iter->second.picture.get();
+    if (picture && (appended_pictures.count(picture) == 0)) {
+      appended_pictures.insert(picture);
       pictures->Append(TracedValue::CreateIDRef(picture).release());
     }
   }
   return pictures.PassAs<base::Value>();
 }
 
+PicturePileBase::PictureInfo::PictureInfo() {}
+
+PicturePileBase::PictureInfo::~PictureInfo() {}
+
+bool PicturePileBase::PictureInfo::Invalidate() {
+  if (!picture.get())
+    return false;
+  picture = NULL;
+  return true;
+}
+
+PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread(
+    int thread_index) const {
+  PictureInfo info = *this;
+  if (picture.get())
+    info.picture = picture->GetCloneForDrawingOnThread(thread_index);
+  return info;
+}
+
 }  // namespace cc
diff --git a/cc/resources/picture_pile_base.h b/cc/resources/picture_pile_base.h
index fdb593f..0fa63f4 100644
--- a/cc/resources/picture_pile_base.h
+++ b/cc/resources/picture_pile_base.h
@@ -47,19 +47,30 @@
   scoped_ptr<base::Value> AsValue() const;
 
  protected:
+  struct CC_EXPORT PictureInfo {
+    PictureInfo();
+    ~PictureInfo();
+
+    bool Invalidate();
+    PictureInfo CloneForThread(int thread_index) const;
+
+    scoped_refptr<Picture> picture;
+  };
+
+  typedef std::pair<int, int> PictureMapKey;
+  typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
+
   virtual ~PicturePileBase();
 
   int num_raster_threads() { return num_raster_threads_; }
   int buffer_pixels() const { return tiling_.border_texels(); }
   void Clear();
 
-  typedef std::pair<int, int> PictureListMapKey;
-  typedef std::list<scoped_refptr<Picture> > PictureList;
-  typedef base::hash_map<PictureListMapKey, PictureList> PictureListMap;
+  gfx::Rect PaddedRect(const PictureMapKey& key);
 
-  // A picture pile is a tiled set of picture lists.  The picture list map
-  // is a map of tile indices to picture lists.
-  PictureListMap picture_list_map_;
+  // A picture pile is a tiled set of pictures. The picture map is a map of tile
+  // indices to picture infos.
+  PictureMap picture_map_;
   TilingData tiling_;
   Region recorded_region_;
   float min_contents_scale_;
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 95b333c..3d0f5ec 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -142,6 +142,64 @@
                rendering_stats_instrumentation);
 }
 
+void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect,
+                                      gfx::Rect content_rect,
+                                      float contents_scale,
+                                      PictureRegionMap* results) {
+  DCHECK(results);
+  // Rasterize the collection of relevant picture piles.
+  gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
+      content_rect, 1.f / contents_scale);
+
+  // Coalesce rasters of the same picture into different rects:
+  //  - Compute the clip of each of the pile chunks,
+  //  - Subtract it from the canvas rect to get difference region
+  //  - Later, use the difference region to subtract each of the comprising
+  //    rects from the canvas.
+  // Note that in essence, we're trying to mimic clipRegion with intersect op
+  // that also respects the current canvas transform and clip. In order to use
+  // the canvas transform, we must stick to clipRect operations (clipRegion
+  // ignores the transform). Intersect then can be written as subtracting the
+  // negation of the region we're trying to intersect. Luckily, we know that all
+  // of the rects will have to fit into |content_rect|, so we can start with
+  // that and subtract chunk rects to get the region that we need to subtract
+  // from the canvas. Then, we can use clipRect with difference op to subtract
+  // each rect in the region.
+  for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
+       tile_iter; ++tile_iter) {
+    PictureMap::iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      continue;
+    PictureInfo& info = map_iter->second;
+    if (!info.picture.get())
+      continue;
+
+    // This is intentionally *enclosed* rect, so that the clip is aligned on
+    // integral post-scale content pixels and does not extend past the edges
+    // of the picture chunk's layer rect.  The min_contents_scale enforces that
+    // enough buffer pixels have been added such that the enclosed rect
+    // encompasses all invalidated pixels at any larger scale level.
+    gfx::Rect chunk_rect = PaddedRect(tile_iter.index());
+    gfx::Rect content_clip =
+        gfx::ScaleToEnclosedRect(chunk_rect, contents_scale);
+    DCHECK(!content_clip.IsEmpty()) << "Layer rect: "
+                                    << info.picture->LayerRect().ToString()
+                                    << "Contents scale: " << contents_scale;
+    content_clip.Intersect(canvas_rect);
+
+    PictureRegionMap::iterator it = results->find(info.picture.get());
+    if (it == results->end()) {
+      Region& region = (*results)[info.picture.get()];
+      region = content_rect;
+      region.Subtract(content_clip);
+      continue;
+    }
+
+    Region& region = it->second;
+    region.Subtract(content_clip);
+  }
+}
+
 void PicturePileImpl::RasterCommon(
     SkCanvas* canvas,
     SkDrawPictureCallback* callback,
@@ -151,111 +209,74 @@
   DCHECK(contents_scale >= min_contents_scale_);
 
   canvas->translate(-canvas_rect.x(), -canvas_rect.y());
-
   gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(),
                                                  contents_scale);
   gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size));
   gfx::Rect content_rect = total_content_rect;
   content_rect.Intersect(canvas_rect);
 
-  // Rasterize the collection of relevant picture piles.
-  gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
-      content_rect, 1.f / contents_scale);
-
   canvas->clipRect(gfx::RectToSkRect(content_rect),
                    SkRegion::kIntersect_Op);
-  Region unclipped(content_rect);
 
-  for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
-       tile_iter; ++tile_iter) {
-    PictureListMap::iterator map_iter =
-        picture_list_map_.find(tile_iter.index());
-    if (map_iter == picture_list_map_.end())
-      continue;
-    PictureList& pic_list= map_iter->second;
-    if (pic_list.empty())
-      continue;
+  PictureRegionMap picture_region_map;
+  CoalesceRasters(
+      canvas_rect, content_rect, contents_scale, &picture_region_map);
 
-    // Raster through the picture list top down, using clips to make sure that
-    // pictures on top are not overdrawn by pictures on the bottom.
-    for (PictureList::reverse_iterator i = pic_list.rbegin();
-         i != pic_list.rend(); ++i) {
-      // This is intentionally *enclosed* rect, so that the clip is aligned on
-      // integral post-scale content pixels and does not extend past the edges
-      // of the picture's layer rect.  The min_contents_scale enforces that
-      // enough buffer pixels have been added such that the enclosed rect
-      // encompasses all invalidated pixels at any larger scale level.
-      gfx::Rect content_clip = gfx::ScaleToEnclosedRect(
-          (*i)->LayerRect(), contents_scale);
+#ifndef NDEBUG
+  Region total_clip;
+#endif  // NDEBUG
 
-      DCHECK(!content_clip.IsEmpty()) <<
-          "Layer rect: " << (*i)->LayerRect().ToString() <<
-          "Contents scale: " << contents_scale;
+  // Iterate the coalesced map and use each picture's region
+  // to clip the canvas.
+  for (PictureRegionMap::iterator it = picture_region_map.begin();
+       it != picture_region_map.end();
+       ++it) {
+    Picture* picture = it->first;
+    Region negated_clip_region = it->second;
 
-      content_clip.Intersect(canvas_rect);
+#ifndef NDEBUG
+    Region positive_clip = content_rect;
+    positive_clip.Subtract(negated_clip_region);
+    total_clip.Union(positive_clip);
+#endif  // NDEBUG
 
-      if (!unclipped.Intersects(content_clip))
-        continue;
+    base::TimeDelta best_duration =
+        base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
+    int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
+    int rasterized_pixel_count = 0;
 
-      base::TimeDelta best_duration =
-          base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
-      int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
-      int rasterized_pixel_count = 0;
+    for (int j = 0; j < repeat_count; ++j) {
+      base::TimeTicks start_time;
+      if (rendering_stats_instrumentation)
+        start_time = rendering_stats_instrumentation->StartRecording();
 
-      for (int j = 0; j < repeat_count; ++j) {
-        base::TimeTicks start_time;
-        if (rendering_stats_instrumentation)
-          start_time = rendering_stats_instrumentation->StartRecording();
-        rasterized_pixel_count =
-            (*i)->Raster(canvas, callback, content_clip, contents_scale);
-        if (rendering_stats_instrumentation) {
-          base::TimeDelta duration =
-              rendering_stats_instrumentation->EndRecording(start_time);
-          best_duration = std::min(best_duration, duration);
-        }
-      }
+      rasterized_pixel_count = picture->Raster(
+          canvas, callback, negated_clip_region, contents_scale);
+
       if (rendering_stats_instrumentation) {
-        rendering_stats_instrumentation->AddRaster(best_duration,
-                                                   rasterized_pixel_count);
+        base::TimeDelta duration =
+            rendering_stats_instrumentation->EndRecording(start_time);
+        best_duration = std::min(best_duration, duration);
       }
+    }
 
-      if (show_debug_picture_borders_) {
-        gfx::Rect border = gfx::ScaleToEnclosedRect(
-             (*i)->LayerRect(), contents_scale);
-        border.Inset(0, 0, 1, 1);
-
-        SkPaint picture_border_paint;
-        picture_border_paint.setColor(DebugColors::PictureBorderColor());
-        canvas->drawLine(border.x(), border.y(), border.right(), border.y(),
-                         picture_border_paint);
-        canvas->drawLine(border.right(), border.y(), border.right(),
-                         border.bottom(), picture_border_paint);
-        canvas->drawLine(border.right(), border.bottom(), border.x(),
-                         border.bottom(), picture_border_paint);
-        canvas->drawLine(border.x(), border.bottom(), border.x(), border.y(),
-                         picture_border_paint);
-      }
-
-      // Don't allow pictures underneath to draw where this picture did.
-      canvas->clipRect(
-          gfx::RectToSkRect(content_clip),
-          SkRegion::kDifference_Op);
-      unclipped.Subtract(content_clip);
+    if (rendering_stats_instrumentation) {
+      rendering_stats_instrumentation->AddRaster(best_duration,
+                                                 rasterized_pixel_count);
     }
   }
 
 #ifndef NDEBUG
-  // Fill the remaining clip with debug color. This allows us to
+  // Fill the clip with debug color. This allows us to
   // distinguish between non painted areas and problems with missing
   // pictures.
   SkPaint paint;
+  for (Region::Iterator it(total_clip); it.has_rect(); it.next())
+    canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
   paint.setColor(DebugColors::MissingPictureFillColor());
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   canvas->drawPaint(paint);
 #endif  // NDEBUG
-
-  // We should always paint some part of |content_rect|.
-  DCHECK(!unclipped.Contains(content_rect));
 }
 
 skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() {
@@ -316,14 +337,12 @@
     : picture_pile_(picture_pile),
       layer_rect_(gfx::ScaleToEnclosingRect(
           content_rect, 1.f / contents_scale)),
-      tile_iterator_(&picture_pile_->tiling_, layer_rect_),
-      picture_list_(NULL) {
+      tile_iterator_(&picture_pile_->tiling_, layer_rect_) {
   // Early out if there isn't a single tile.
   if (!tile_iterator_)
     return;
 
-  if (AdvanceToTileWithPictures())
-    AdvanceToPictureWithPixelRefs();
+  AdvanceToTilePictureWithPixelRefs();
 }
 
 PicturePileImpl::PixelRefIterator::~PixelRefIterator() {
@@ -335,50 +354,39 @@
   if (pixel_ref_iterator_)
     return *this;
 
-  ++picture_list_iterator_;
-  AdvanceToPictureWithPixelRefs();
+  ++tile_iterator_;
+  AdvanceToTilePictureWithPixelRefs();
   return *this;
 }
 
-bool PicturePileImpl::PixelRefIterator::AdvanceToTileWithPictures() {
+void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
   for (; tile_iterator_; ++tile_iterator_) {
-    PictureListMap::const_iterator map_iterator =
-        picture_pile_->picture_list_map_.find(tile_iterator_.index());
-    if (map_iterator != picture_pile_->picture_list_map_.end()) {
-      picture_list_ = &map_iterator->second;
-      picture_list_iterator_ = picture_list_->begin();
-      return true;
-    }
+    PictureMap::const_iterator it =
+        picture_pile_->picture_map_.find(tile_iterator_.index());
+    if (it == picture_pile_->picture_map_.end())
+      continue;
+
+    const Picture* picture = it->second.picture.get();
+    if (!picture || (processed_pictures_.count(picture) != 0))
+      continue;
+
+    processed_pictures_.insert(picture);
+    pixel_ref_iterator_ = Picture::PixelRefIterator(layer_rect_, picture);
+    if (pixel_ref_iterator_)
+      break;
   }
-
-  return false;
-}
-
-void PicturePileImpl::PixelRefIterator::AdvanceToPictureWithPixelRefs() {
-  DCHECK(tile_iterator_);
-  do {
-    for (;
-         picture_list_iterator_ != picture_list_->end();
-         ++picture_list_iterator_) {
-      pixel_ref_iterator_ =
-          Picture::PixelRefIterator(layer_rect_, picture_list_iterator_->get());
-      if (pixel_ref_iterator_)
-        return;
-    }
-    ++tile_iterator_;
-  } while (AdvanceToTileWithPictures());
 }
 
 void PicturePileImpl::DidBeginTracing() {
   gfx::Rect layer_rect(tiling_.total_size());
-  for (PictureListMap::iterator pli = picture_list_map_.begin();
-       pli != picture_list_map_.end();
-       pli++) {
-    PictureList& picture_list = (*pli).second;
-    for (PictureList::iterator picture = picture_list.begin();
-         picture != picture_list.end();
-         picture++) {
-      (*picture)->EmitTraceSnapshot();
+  std::set<void*> processed_pictures;
+  for (PictureMap::iterator it = picture_map_.begin();
+       it != picture_map_.end();
+       ++it) {
+    Picture* picture = it->second.picture.get();
+    if (picture && (processed_pictures.count(picture) == 0)) {
+      picture->EmitTraceSnapshot();
+      processed_pictures.insert(picture);
     }
   }
 }
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index ed50bec..66b5f72 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -7,6 +7,7 @@
 
 #include <list>
 #include <map>
+#include <set>
 #include <vector>
 
 #include "base/time/time.h"
@@ -87,15 +88,13 @@
     operator bool() const { return pixel_ref_iterator_; }
 
    private:
-    bool AdvanceToTileWithPictures();
-    void AdvanceToPictureWithPixelRefs();
+    void AdvanceToTilePictureWithPixelRefs();
 
     const PicturePileImpl* picture_pile_;
     gfx::Rect layer_rect_;
     TilingData::Iterator tile_iterator_;
     Picture::PixelRefIterator pixel_ref_iterator_;
-    const PictureList* picture_list_;
-    PictureList::const_iterator picture_list_iterator_;
+    std::set<const void*> processed_pictures_;
   };
 
   void DidBeginTracing();
@@ -123,6 +122,13 @@
 
   PicturePileImpl(const PicturePileImpl* other, unsigned thread_index);
 
+ private:
+  typedef std::map<Picture*, Region> PictureRegionMap;
+  void CoalesceRasters(gfx::Rect canvas_rect,
+                       gfx::Rect content_rect,
+                       float contents_scale,
+                       PictureRegionMap* result);
+
   void RasterCommon(
       SkCanvas* canvas,
       SkDrawPictureCallback* callback,
diff --git a/cc/resources/picture_pile_impl_unittest.cc b/cc/resources/picture_pile_impl_unittest.cc
index a986c88..c68b185 100644
--- a/cc/resources/picture_pile_impl_unittest.cc
+++ b/cc/resources/picture_pile_impl_unittest.cc
@@ -635,85 +635,6 @@
   }
 }
 
-TEST(PicturePileImplTest, PixelRefIteratorMultiplePictures) {
-  gfx::Size tile_size(256, 256);
-  gfx::Size layer_bounds(256, 256);
-
-  SkTileGridPicture::TileGridInfo tile_grid_info;
-  tile_grid_info.fTileInterval = SkISize::Make(256, 256);
-  tile_grid_info.fMargin.setEmpty();
-  tile_grid_info.fOffset.setZero();
-
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
-  SkBitmap lazy_bitmap[2][2];
-  CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]);
-  CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][1]);
-  CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]);
-  SkBitmap non_lazy_bitmap;
-  CreateBitmap(gfx::Size(256, 256), "notlazy", &non_lazy_bitmap);
-
-  // Each bitmap goes into its own picture, the final layout
-  // has lazy pixel refs in the following regions:
-  // ||=======||
-  // ||x|   |x||
-  // ||--   --||
-  // ||     |x||
-  // ||=======||
-  pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 0));
-  pile->RerecordPile();
-
-  FakeContentLayerClient content_layer_clients[2][2];
-  scoped_refptr<Picture> pictures[2][2];
-  for (int y = 0; y < 2; ++y) {
-    for (int x = 0; x < 2; ++x) {
-      if (x == 0 && y == 1)
-        continue;
-      SkPaint paint;
-      content_layer_clients[y][x].add_draw_bitmap(
-          lazy_bitmap[y][x],
-          gfx::Point(x * 128 + 10, y * 128 + 10), paint);
-      pictures[y][x] = Picture::Create(
-          gfx::Rect(x * 128 + 10, y * 128 + 10, 64, 64));
-      pictures[y][x]->Record(
-          &content_layer_clients[y][x],
-          tile_grid_info);
-      pictures[y][x]->GatherPixelRefs(tile_grid_info);
-      pile->AddPictureToRecording(0, 0, pictures[y][x]);
-    }
-  }
-
-  // These should find only one pixel ref.
-  {
-    PicturePileImpl::PixelRefIterator iterator(
-        gfx::Rect(0, 0, 128, 128), 1.0, pile.get());
-    EXPECT_TRUE(iterator);
-    EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
-    EXPECT_FALSE(++iterator);
-  }
-  {
-    PicturePileImpl::PixelRefIterator iterator(
-        gfx::Rect(128, 0, 128, 128), 1.0, pile.get());
-    EXPECT_TRUE(iterator);
-    EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
-    EXPECT_FALSE(++iterator);
-  }
-  {
-    PicturePileImpl::PixelRefIterator iterator(
-        gfx::Rect(128, 128, 128, 128), 1.0, pile.get());
-    EXPECT_TRUE(iterator);
-    EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
-    EXPECT_FALSE(++iterator);
-  }
-  // This one should not find any refs
-  {
-    PicturePileImpl::PixelRefIterator iterator(
-        gfx::Rect(0, 128, 128, 128), 1.0, pile.get());
-    EXPECT_FALSE(iterator);
-  }
-}
-
 TEST(PicturePileImpl, RasterContentsOpaque) {
   gfx::Size tile_size(1000, 1000);
   gfx::Size layer_bounds(3, 5);
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 1eeb5ad..0c9b2e1 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -16,11 +16,11 @@
  public:
   using PicturePile::buffer_pixels;
 
-  PictureListMap& picture_list_map() { return picture_list_map_; }
+  PictureMap& picture_map() { return picture_map_; }
 
-  typedef PicturePile::PictureList PictureList;
-  typedef PicturePile::PictureListMapKey PictureListMapKey;
-  typedef PicturePile::PictureListMap PictureListMap;
+  typedef PicturePile::PictureInfo PictureInfo;
+  typedef PicturePile::PictureMapKey PictureMapKey;
+  typedef PicturePile::PictureMap PictureMap;
 
  protected:
     virtual ~TestPicturePile() {}
@@ -60,22 +60,17 @@
   EXPECT_EQ(1, pile->tiling().num_tiles_x());
   EXPECT_EQ(1, pile->tiling().num_tiles_y());
 
-  TestPicturePile::PictureList& picture_list =
-      pile->picture_list_map().find(
-          TestPicturePile::PictureListMapKey(0, 0))->second;
-  EXPECT_EQ(2u, picture_list.size());
-  for (TestPicturePile::PictureList::iterator it = picture_list.begin();
-       it != picture_list.end();
-       ++it) {
-    scoped_refptr<Picture> picture = *it;
-    gfx::Rect picture_rect =
-        gfx::ScaleToEnclosedRect(picture->LayerRect(), min_scale);
+  TestPicturePile::PictureInfo& picture_info =
+      pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+  // We should have a picture.
+  EXPECT_TRUE(!!picture_info.picture.get());
+  gfx::Rect picture_rect =
+      gfx::ScaleToEnclosedRect(picture_info.picture->LayerRect(), min_scale);
 
-    // The invalidation in each tile should have been made large enough
-    // that scaling it never makes a rect smaller than 1 px wide or tall.
-    EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " <<
-        picture_rect.ToString();
-  }
+  // The the picture should be large enough that scaling it never makes a rect
+  // smaller than 1 px wide or tall.
+  EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " <<
+      picture_rect.ToString();
 }
 
 TEST(PicturePileTest, LargeInvalidateInflated) {
@@ -112,24 +107,17 @@
   EXPECT_EQ(1, pile->tiling().num_tiles_x());
   EXPECT_EQ(1, pile->tiling().num_tiles_y());
 
-  TestPicturePile::PictureList& picture_list =
-      pile->picture_list_map().find(
-          TestPicturePile::PictureListMapKey(0, 0))->second;
-  EXPECT_EQ(2u, picture_list.size());
+  TestPicturePile::PictureInfo& picture_info =
+      pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+  EXPECT_TRUE(!!picture_info.picture.get());
 
   int expected_inflation = pile->buffer_pixels();
 
-  scoped_refptr<Picture> base_picture = *picture_list.begin();
+  scoped_refptr<Picture> base_picture = picture_info.picture;
   gfx::Rect base_picture_rect(layer_size);
   base_picture_rect.Inset(-expected_inflation, -expected_inflation);
   EXPECT_EQ(base_picture_rect.ToString(),
             base_picture->LayerRect().ToString());
-
-  scoped_refptr<Picture> picture = *(++picture_list.begin());
-  gfx::Rect picture_rect(invalidate_rect);
-  picture_rect.Inset(-expected_inflation, -expected_inflation);
-  EXPECT_EQ(picture_rect.ToString(),
-            picture->LayerRect().ToString());
 }
 
 TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) {
@@ -179,30 +167,13 @@
 
   for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) {
-      // (1, 0) and (1, 1) should be invalidated partially.
-      bool expect_invalidated = i == 1 && (j == 0 || j == 1);
+      TestPicturePile::PictureInfo& picture_info =
+          pile->picture_map().find(
+              TestPicturePile::PictureMapKey(i, j))->second;
 
-      TestPicturePile::PictureList& picture_list =
-          pile->picture_list_map().find(
-              TestPicturePile::PictureListMapKey(i, j))->second;
-      if (!expect_invalidated) {
-        EXPECT_EQ(1u, picture_list.size()) << "For i,j " << i << "," << j;
-        continue;
-      }
-
-      EXPECT_EQ(2u, picture_list.size()) << "For i,j " << i << "," << j;
-      for (TestPicturePile::PictureList::iterator it = picture_list.begin();
-           it != picture_list.end();
-           ++it) {
-        scoped_refptr<Picture> picture = *it;
-        gfx::Rect picture_rect =
-            gfx::ScaleToEnclosedRect(picture->LayerRect(), min_scale);
-
-        // The invalidation in each tile should have been made large enough
-        // that scaling it never makes a rect smaller than 1 px wide or tall.
-        EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " <<
-            picture_rect.ToString();
-      }
+      // TODO(vmpstr): Fix this to check invalidation frequency instead
+      // of the picture, since we always have one picture per tile.
+      EXPECT_TRUE(!!picture_info.picture.get());
     }
   }
 }
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.cc b/cc/resources/pixel_buffer_raster_worker_pool.cc
index a555e58..edd7d6c 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/cc/resources/pixel_buffer_raster_worker_pool.cc
@@ -212,7 +212,7 @@
   check_for_completed_raster_tasks_pending_ = false;
   ScheduleCheckForCompletedRasterTasks();
 
-  TRACE_EVENT_ASYNC_STEP1(
+  TRACE_EVENT_ASYNC_STEP_INTO1(
       "cc", "ScheduledTasks", this, StateName(),
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
@@ -397,7 +397,7 @@
   if (PendingRasterTaskCount())
     ScheduleMoreTasks();
 
-  TRACE_EVENT_ASYNC_STEP1(
+  TRACE_EVENT_ASYNC_STEP_INTO1(
       "cc", "ScheduledTasks", this, StateName(),
       "state", TracedValue::FromValue(StateAsValue().release()));
 
diff --git a/cc/resources/prioritized_resource.cc b/cc/resources/prioritized_resource.cc
index 313b275..8a7874d 100644
--- a/cc/resources/prioritized_resource.cc
+++ b/cc/resources/prioritized_resource.cc
@@ -124,6 +124,7 @@
       priority_at_last_priority_update_(PriorityCalculator::LowestPriority()),
       was_above_priority_cutoff_at_last_priority_update_(false),
       in_drawing_impl_tree_(false),
+      in_parent_compositor_(false),
 #ifdef NDEBUG
       resource_has_been_deleted_(false) {}
 #else
@@ -157,7 +158,7 @@
 bool PrioritizedResource::Backing::CanBeRecycled() const {
   DCHECK(!proxy() || proxy()->IsImplThread());
   return !was_above_priority_cutoff_at_last_priority_update_ &&
-         !in_drawing_impl_tree_;
+         !in_drawing_impl_tree_ && !in_parent_compositor_;
 }
 
 void PrioritizedResource::Backing::UpdatePriority() {
@@ -173,10 +174,12 @@
   }
 }
 
-void PrioritizedResource::Backing::UpdateInDrawingImplTree() {
+void PrioritizedResource::Backing::UpdateState(
+    ResourceProvider* resource_provider) {
   DCHECK(!proxy() ||
          (proxy()->IsImplThread() && proxy()->IsMainThreadBlocked()));
   in_drawing_impl_tree_ = !!owner();
+  in_parent_compositor_ = resource_provider->InUseByConsumer(id());
   if (!in_drawing_impl_tree_) {
     DCHECK_EQ(priority_at_last_priority_update_,
               PriorityCalculator::LowestPriority());
diff --git a/cc/resources/prioritized_resource.h b/cc/resources/prioritized_resource.h
index a3d5d89..bdd906d 100644
--- a/cc/resources/prioritized_resource.h
+++ b/cc/resources/prioritized_resource.h
@@ -111,7 +111,7 @@
             ResourceFormat format);
     ~Backing();
     void UpdatePriority();
-    void UpdateInDrawingImplTree();
+    void UpdateState(ResourceProvider* resource_provider);
 
     PrioritizedResource* owner() { return owner_; }
     bool CanBeRecycled() const;
@@ -122,6 +122,7 @@
       return was_above_priority_cutoff_at_last_priority_update_;
     }
     bool in_drawing_impl_tree() const { return in_drawing_impl_tree_; }
+    bool in_parent_compositor() const { return in_parent_compositor_; }
 
     void DeleteResource(ResourceProvider* resource_provider);
     bool ResourceHasBeenDeleted() const;
@@ -137,6 +138,8 @@
 
     // Set if this is currently-drawing impl tree.
     bool in_drawing_impl_tree_;
+    // Set if this is in the parent compositor.
+    bool in_parent_compositor_;
 
     bool resource_has_been_deleted_;
 
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc
index 4743b9a..ece04b1 100644
--- a/cc/resources/prioritized_resource_manager.cc
+++ b/cc/resources/prioritized_resource_manager.cc
@@ -160,7 +160,8 @@
       memory_visible_and_nearby_bytes_;
 }
 
-void PrioritizedResourceManager::UpdateBackingsInDrawingImplTree() {
+void PrioritizedResourceManager::UpdateBackingsState(
+    ResourceProvider* resource_provider) {
   TRACE_EVENT0("cc",
                "PrioritizedResourceManager::UpdateBackingsInDrawingImplTree");
   DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked());
@@ -169,7 +170,7 @@
   for (BackingList::iterator it = backings_.begin(); it != backings_.end();
        ++it) {
     PrioritizedResource::Backing* backing = (*it);
-    backing->UpdateInDrawingImplTree();
+    backing->UpdateState(resource_provider);
   }
   SortBackings();
   AssertInvariants();
@@ -320,8 +321,7 @@
        ++it) {
     if ((*it)->owner())
       break;
-    if (resource_provider->InUseByConsumer((*it)->id()) &&
-        !resource_provider->IsLost((*it)->id()))
+    if ((*it)->in_parent_compositor())
       continue;
     wasted_memory += (*it)->bytes();
   }
@@ -380,18 +380,6 @@
                                      resource_provider);
 }
 
-void PrioritizedResourceManager::ReduceWastedMemoryOnImplThread(
-    ResourceProvider* resource_provider) {
-  DCHECK(proxy_->IsImplThread());
-  DCHECK(resource_provider);
-  // If we are in the process of uploading a new frame then the backings at the
-  // very end of the list are not sorted by priority. Sort them before doing the
-  // eviction.
-  if (backings_tail_not_sorted_)
-    SortBackings();
-  ReduceWastedMemory(resource_provider);
-}
-
 void PrioritizedResourceManager::UnlinkAndClearEvictedBackings() {
   DCHECK(proxy_->IsMainThread());
   base::AutoLock scoped_lock(evicted_backings_lock_);
diff --git a/cc/resources/prioritized_resource_manager.h b/cc/resources/prioritized_resource_manager.h
index 07cc7cf..8a7c275 100644
--- a/cc/resources/prioritized_resource_manager.h
+++ b/cc/resources/prioritized_resource_manager.h
@@ -96,10 +96,6 @@
                                 int priority_cutoff,
                                 ResourceProvider* resource_provider);
 
-  // Delete contents textures' backing resources that can be recycled. This
-  // may be called on the impl thread while the main thread is running.
-  void ReduceWastedMemoryOnImplThread(ResourceProvider* resource_provider);
-
   // Returns true if there exist any textures that are linked to backings that
   // have had their resources evicted. Only when we commit a tree that has no
   // textures linked to evicted backings may we allow drawing. After an
@@ -129,7 +125,7 @@
   void PushTexturePrioritiesToBackings();
 
   // Mark all textures' backings as being in the drawing impl tree.
-  void UpdateBackingsInDrawingImplTree();
+  void UpdateBackingsState(ResourceProvider* resource_provider);
 
   const Proxy* ProxyForDebug() const;
 
@@ -159,6 +155,10 @@
     // Make textures that can be recycled appear first
     if (a->CanBeRecycled() != b->CanBeRecycled())
       return (a->CanBeRecycled() > b->CanBeRecycled());
+    // Put textures in the parent compositor last since they can't be
+    // freed when they are evicted anyhow.
+    if (a->in_parent_compositor() != b->in_parent_compositor())
+      return (a->in_parent_compositor() < b->in_parent_compositor());
     // Then sort by being above or below the priority cutoff.
     if (a->was_above_priority_cutoff_at_last_priority_update() !=
         b->was_above_priority_cutoff_at_last_priority_update())
diff --git a/cc/resources/prioritized_resource_unittest.cc b/cc/resources/prioritized_resource_unittest.cc
index fb71533..82178c2 100644
--- a/cc/resources/prioritized_resource_unittest.cc
+++ b/cc/resources/prioritized_resource_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "cc/resources/prioritized_resource.h"
 
+#include <vector>
+
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource.h"
 #include "cc/test/fake_output_surface.h"
@@ -24,7 +26,7 @@
     DebugScopedSetImplThread impl_thread(&proxy_);
     CHECK(output_surface_->BindToClient(&output_surface_client_));
     resource_provider_ =
-        cc::ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
   }
 
   virtual ~PrioritizedResourceTest() {
@@ -51,7 +53,7 @@
       texture->RequestLate();
     ResourceManagerAssertInvariants(texture->resource_manager());
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     bool success = texture->can_acquire_backing_texture();
     if (success)
       texture->AcquireBackingTexture(ResourceProvider());
@@ -67,7 +69,7 @@
   void ResourceManagerUpdateBackingsPriorities(
       PrioritizedResourceManager* resource_manager) {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->PushTexturePrioritiesToBackings();
   }
 
@@ -77,7 +79,7 @@
       PrioritizedResourceManager* resource_manager) {
 #ifndef NDEBUG
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->AssertInvariants();
 #endif
   }
@@ -91,12 +93,23 @@
     return resource_manager->evicted_backings_.size();
   }
 
+  std::vector<unsigned> BackingResources(
+      PrioritizedResourceManager* resource_manager) {
+    std::vector<unsigned> resources;
+    for (PrioritizedResourceManager::BackingList::iterator it =
+             resource_manager->backings_.begin();
+         it != resource_manager->backings_.end();
+         ++it)
+      resources.push_back((*it)->id());
+    return resources;
+  }
+
  protected:
   FakeProxy proxy_;
   const gfx::Size texture_size_;
   const ResourceFormat texture_format_;
   FakeOutputSurfaceClient output_surface_client_;
-  scoped_ptr<OutputSurface> output_surface_;
+  scoped_ptr<cc::OutputSurface> output_surface_;
   scoped_ptr<cc::ResourceProvider> resource_provider_;
 };
 
@@ -144,7 +157,7 @@
             resource_manager->MaxMemoryNeededBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -168,7 +181,7 @@
     ValidateTexture(textures[i].get(), false);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
 
@@ -183,7 +196,7 @@
     EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 5);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
 
@@ -200,7 +213,7 @@
     EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
 
@@ -211,7 +224,7 @@
             resource_manager->MaxMemoryNeededBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -249,7 +262,7 @@
   }
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
 
@@ -261,7 +274,8 @@
   PrioritizeTexturesAndBackings(resource_manager.get());
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->UpdateBackingsState(ResourceProvider());
     resource_manager->ReduceWastedMemory(ResourceProvider());
   }
   EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes());
@@ -273,13 +287,14 @@
   PrioritizeTexturesAndBackings(resource_manager.get());
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->UpdateBackingsState(ResourceProvider());
     resource_manager->ReduceWastedMemory(ResourceProvider());
   }
   EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -339,7 +354,8 @@
   PrioritizeTexturesAndBackings(resource_manager.get());
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->UpdateBackingsState(ResourceProvider());
     resource_manager->ReduceWastedMemory(ResourceProvider());
   }
   EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes());
@@ -351,13 +367,14 @@
   resource_provider_->ReceiveReturnsFromParent(returns);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->UpdateBackingsState(ResourceProvider());
     resource_manager->ReduceWastedMemory(ResourceProvider());
   }
   EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -384,7 +401,7 @@
     EXPECT_EQ(ValidateTexture(textures[i].get(), true), i < 6);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
   EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes());
@@ -398,17 +415,16 @@
     EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
   EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes());
 
   // Do a one-time eviction for one more texture based on priority cutoff
-  PrioritizedResourceManager::BackingList evicted_backings;
   resource_manager->UnlinkAndClearEvictedBackings();
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemoryOnImplThread(
         TexturesMemorySize(8), 104, ResourceProvider());
     EXPECT_EQ(0u, EvictedBackingCount(resource_manager.get()));
@@ -425,13 +441,149 @@
     EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ReduceMemory(ResourceProvider());
   }
   EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
+  resource_manager->ClearAllMemory(ResourceProvider());
+}
+
+TEST_F(PrioritizedResourceTest, NotEvictingTexturesInParent) {
+  const size_t kMaxTextures = 8;
+  scoped_ptr<PrioritizedResourceManager> resource_manager =
+      CreateManager(kMaxTextures);
+  scoped_ptr<PrioritizedResource> textures[kMaxTextures];
+  unsigned texture_resource_ids[kMaxTextures];
+
+  for (size_t i = 0; i < kMaxTextures; ++i) {
+    textures[i] =
+        resource_manager->CreateTexture(texture_size_, texture_format_);
+    textures[i]->set_request_priority(100 + i);
+  }
+
+  PrioritizeTexturesAndBackings(resource_manager.get());
+  for (size_t i = 0; i < kMaxTextures; ++i) {
+    EXPECT_TRUE(ValidateTexture(textures[i].get(), true));
+
+    {
+      DebugScopedSetImplThreadAndMainThreadBlocked
+          impl_thread_and_main_thread_blocked(&proxy_);
+      uint8_t image[4] = {0};
+      textures[i]->SetPixels(resource_provider_.get(),
+                             image,
+                             gfx::Rect(1, 1),
+                             gfx::Rect(1, 1),
+                             gfx::Vector2d());
+    }
+  }
+  {
+    DebugScopedSetImplThreadAndMainThreadBlocked
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->ReduceMemory(ResourceProvider());
+  }
+  EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes());
+
+  for (size_t i = 0; i < 8; ++i)
+    texture_resource_ids[i] = textures[i]->resource_id();
+
+  // Evict four textures. It will be the last four.
+  {
+    DebugScopedSetImplThreadAndMainThreadBlocked
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->ReduceMemoryOnImplThread(
+        TexturesMemorySize(4), 200, ResourceProvider());
+
+    EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get()));
+
+    // The last four backings are evicted.
+    std::vector<unsigned> remaining = BackingResources(resource_manager.get());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[0]) != remaining.end());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[1]) != remaining.end());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[2]) != remaining.end());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[3]) != remaining.end());
+  }
+  resource_manager->UnlinkAndClearEvictedBackings();
+  EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes());
+
+  // Re-allocate the the texture after the eviction.
+  PrioritizeTexturesAndBackings(resource_manager.get());
+  for (size_t i = 0; i < kMaxTextures; ++i) {
+    EXPECT_TRUE(ValidateTexture(textures[i].get(), true));
+
+    {
+      DebugScopedSetImplThreadAndMainThreadBlocked
+          impl_thread_and_main_thread_blocked(&proxy_);
+      uint8_t image[4] = {0};
+      textures[i]->SetPixels(resource_provider_.get(),
+                             image,
+                             gfx::Rect(1, 1),
+                             gfx::Rect(1, 1),
+                             gfx::Vector2d());
+    }
+  }
+  {
+    DebugScopedSetImplThreadAndMainThreadBlocked
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->ReduceMemory(ResourceProvider());
+  }
+  EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes());
+
+  // Send the last two of the textures to a parent compositor.
+  ResourceProvider::ResourceIdArray to_send;
+  TransferableResourceArray transferable;
+  for (size_t i = 6; i < 8; ++i)
+    to_send.push_back(textures[i]->resource_id());
+  resource_provider_->PrepareSendToParent(to_send, &transferable);
+
+  for (size_t i = 0; i < 8; ++i)
+    texture_resource_ids[i] = textures[i]->resource_id();
+
+  // Drop all the textures. Now we have backings that can be recycled.
+  for (size_t i = 0; i < 8; ++i)
+    textures[0].reset();
+  PrioritizeTexturesAndBackings(resource_manager.get());
+
+  // The next commit finishes.
+  {
+    DebugScopedSetImplThreadAndMainThreadBlocked
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->UpdateBackingsState(ResourceProvider());
+  }
+
+  // Evict four textures. It would be the last four again, except that 2 of them
+  // are sent to the parent, so they are evicted last.
+  {
+    DebugScopedSetImplThreadAndMainThreadBlocked
+        impl_thread_and_main_thread_blocked(&proxy_);
+    resource_manager->ReduceMemoryOnImplThread(
+        TexturesMemorySize(4), 200, ResourceProvider());
+
+    EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get()));
+    // The last 2 backings remain this time.
+    std::vector<unsigned> remaining = BackingResources(resource_manager.get());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[6]) != remaining.end());
+    EXPECT_TRUE(std::find(remaining.begin(),
+                          remaining.end(),
+                          texture_resource_ids[7]) != remaining.end());
+  }
+  resource_manager->UnlinkAndClearEvictedBackings();
+  EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes());
+
+  DebugScopedSetImplThreadAndMainThreadBlocked
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -494,7 +646,7 @@
   EXPECT_FALSE(textures[3]->have_backing_texture());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -539,7 +691,7 @@
             resource_manager->MemoryAboveCutoffBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -559,7 +711,7 @@
   EXPECT_TRUE(texture->have_backing_texture());
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->ClearAllMemory(ResourceProvider());
   }
   resource_manager.reset();
@@ -589,7 +741,7 @@
   texture->SetTextureManager(NULL);
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager_one->ClearAllMemory(ResourceProvider());
   }
   resource_manager_one.reset();
@@ -606,7 +758,7 @@
   EXPECT_TRUE(texture->have_backing_texture());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager_two->ClearAllMemory(ResourceProvider());
 }
 
@@ -663,7 +815,7 @@
             resource_manager->MaxMemoryNeededBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -711,7 +863,7 @@
             resource_manager->MaxMemoryNeededBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -763,7 +915,7 @@
             resource_manager->MemoryAboveCutoffBytes());
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -815,7 +967,7 @@
     EXPECT_FALSE(TextureBackingIsAbovePriorityCutoff(textures[i].get()));
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
@@ -841,7 +993,7 @@
 
   ResourceUpdateQueue queue;
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   for (size_t i = 0; i < kMaxTextures; ++i) {
     const ResourceUpdate upload = ResourceUpdate::Create(
         textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d());
@@ -934,7 +1086,7 @@
   // Push priorities to backings, and verify we see the new values.
   {
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(&proxy_);
+        impl_thread_and_main_thread_blocked(&proxy_);
     resource_manager->PushTexturePrioritiesToBackings();
     EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes());
     EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryVisibleBytes());
@@ -943,7 +1095,7 @@
   }
 
   DebugScopedSetImplThreadAndMainThreadBlocked
-  impl_thread_and_main_thread_blocked(&proxy_);
+      impl_thread_and_main_thread_blocked(&proxy_);
   resource_manager->ClearAllMemory(ResourceProvider());
 }
 
diff --git a/cc/resources/prioritized_tile_set_unittest.cc b/cc/resources/prioritized_tile_set_unittest.cc
index 37c9cc1..4bf27fb 100644
--- a/cc/resources/prioritized_tile_set_unittest.cc
+++ b/cc/resources/prioritized_tile_set_unittest.cc
@@ -57,9 +57,9 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false).Pass();
-    tile_manager_.reset(new FakeTileManager(&tile_manager_client_,
-                                            resource_provider_.get()));
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false).Pass();
+    tile_manager_.reset(
+        new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
     picture_pile_ = FakePicturePileImpl::CreatePile();
   }
 
diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc
index 43bc725..67c548f 100644
--- a/cc/resources/raster_worker_pool.cc
+++ b/cc/resources/raster_worker_pool.cc
@@ -140,6 +140,7 @@
         break;
       case LUMINANCE_8:
       case RGB_565:
+      case ETC1:
         NOTREACHED();
         break;
     }
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 61cb324..023be79 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -68,7 +68,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false).Pass();
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false).Pass();
   }
   virtual ~RasterWorkerPoolTest() {
     resource_provider_.reset();
diff --git a/cc/resources/resource.h b/cc/resources/resource.h
index 2650a0c..e9dd393 100644
--- a/cc/resources/resource.h
+++ b/cc/resources/resource.h
@@ -26,7 +26,8 @@
   size_t bytes() const;
 
   inline static size_t MemorySizeBytes(gfx::Size size, ResourceFormat format) {
-    return BytesPerPixel(format) * size.width() * size.height();
+    DCHECK_EQ(0u, (BitsPerPixel(format) * size.width() * size.height()) % 8);
+    return (BitsPerPixel(format) * size.width() * size.height()) / 8;
   }
 
  protected:
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc
index edd7b06..3561717 100644
--- a/cc/resources/resource_format.cc
+++ b/cc/resources/resource_format.cc
@@ -13,6 +13,7 @@
     case RGBA_8888:
     case BGRA_8888:
       return SkBitmap::kARGB_8888_Config;
+    case ETC1:
     case LUMINANCE_8:
     case RGB_565:
       NOTREACHED();
diff --git a/cc/resources/resource_format.h b/cc/resources/resource_format.h
index 47f9a50..5406139 100644
--- a/cc/resources/resource_format.h
+++ b/cc/resources/resource_format.h
@@ -17,7 +17,8 @@
   BGRA_8888,
   LUMINANCE_8,
   RGB_565,
-  RESOURCE_FORMAT_MAX = RGB_565,
+  ETC1,
+  RESOURCE_FORMAT_MAX = ETC1,
 };
 
 SkBitmap::Config SkBitmapConfig(ResourceFormat format);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index d76fc4b..874fe3f 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -8,6 +8,7 @@
 #include <limits>
 
 #include "base/containers/hash_tables.h"
+#include "base/debug/trace_event.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -15,6 +16,7 @@
 #include "cc/output/gl_renderer.h"  // For the GLC() macro.
 #include "cc/resources/platform_color.h"
 #include "cc/resources/returned_resource.h"
+#include "cc/resources/shared_bitmap_manager.h"
 #include "cc/resources/transferable_resource.h"
 #include "cc/scheduler/texture_uploader.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -45,6 +47,7 @@
     case RGBA_4444:
     case LUMINANCE_8:
     case RGB_565:
+    case ETC1:
       NOTREACHED();
       break;
   }
@@ -60,6 +63,7 @@
     case RGBA_4444:
     case LUMINANCE_8:
     case RGB_565:
+    case ETC1:
       return false;
   }
   return false;
@@ -118,7 +122,8 @@
       lost(false),
       hint(TextureUsageAny),
       type(static_cast<ResourceType>(0)),
-      format(RGBA_8888) {}
+      format(RGBA_8888),
+      shared_bitmap(NULL) {}
 
 ResourceProvider::Resource::~Resource() {}
 
@@ -159,11 +164,13 @@
       lost(false),
       hint(hint),
       type(GLTexture),
-      format(format) {
+      format(format),
+      shared_bitmap(NULL) {
   DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
 }
 
 ResourceProvider::Resource::Resource(uint8_t* pixels,
+                                     SharedBitmap* bitmap,
                                      gfx::Size size,
                                      GLenum filter,
                                      GLint wrap_mode)
@@ -196,7 +203,8 @@
       lost(false),
       hint(TextureUsageAny),
       type(Bitmap),
-      format(RGBA_8888) {
+      format(RGBA_8888),
+      shared_bitmap(bitmap) {
   DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
 }
 
@@ -206,10 +214,12 @@
 
 scoped_ptr<ResourceProvider> ResourceProvider::Create(
     OutputSurface* output_surface,
+    SharedBitmapManager* shared_bitmap_manager,
     int highp_threshold_min,
     bool use_rgba_4444_texture_format) {
   scoped_ptr<ResourceProvider> resource_provider(
       new ResourceProvider(output_surface,
+                           shared_bitmap_manager,
                            highp_threshold_min,
                            use_rgba_4444_texture_format));
 
@@ -311,10 +321,19 @@
 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  uint8_t* pixels = new uint8_t[4 * size.GetArea()];
+  scoped_ptr<SharedBitmap> bitmap;
+  if (shared_bitmap_manager_)
+    bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size);
+
+  uint8_t* pixels;
+  if (bitmap)
+    pixels = bitmap->pixels();
+  else
+    pixels = new uint8_t[4 * size.GetArea()];
 
   ResourceId id = next_id_++;
-  Resource resource(pixels, size, GL_LINEAR, GL_CLAMP_TO_EDGE);
+  Resource resource(
+      pixels, bitmap.release(), size, GL_LINEAR, GL_CLAMP_TO_EDGE);
   resource.allocated = true;
   resources_[id] = resource;
   return id;
@@ -375,8 +394,16 @@
     base::SharedMemory* shared_memory = mailbox.shared_memory();
     DCHECK(shared_memory->memory());
     uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
-    resource = Resource(
-        pixels, mailbox.shared_memory_size(), GL_LINEAR, GL_CLAMP_TO_EDGE);
+    scoped_ptr<SharedBitmap> shared_bitmap;
+    if (shared_bitmap_manager_) {
+      shared_bitmap =
+          shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory);
+    }
+    resource = Resource(pixels,
+                        shared_bitmap.release(),
+                        mailbox.shared_memory_size(),
+                        GL_LINEAR,
+                        GL_CLAMP_TO_EDGE);
   }
   resource.external = true;
   resource.allocated = true;
@@ -407,8 +434,9 @@
 
 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
                                               DeleteStyle style) {
+  TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
   Resource* resource = &it->second;
-  bool lost_resource = lost_output_surface_ || resource->lost;
+  bool lost_resource = resource->lost;
 
   DCHECK(resource->exported_count == 0 || style != Normal);
   if (style == ForShutdown && resource->exported_count > 0)
@@ -438,6 +466,7 @@
   if (resource->mailbox.IsValid() && resource->external) {
     unsigned sync_point = resource->mailbox.sync_point();
     if (resource->mailbox.IsTexture()) {
+      lost_resource |= lost_output_surface_;
       WebGraphicsContext3D* context3d = Context3d();
       DCHECK(context3d);
       if (resource->gl_id)
@@ -450,10 +479,16 @@
       if (resource->pixels && shared_memory) {
         DCHECK(shared_memory->memory() == resource->pixels);
         resource->pixels = NULL;
+        delete resource->shared_bitmap;
+        resource->shared_bitmap = NULL;
       }
     }
     resource->release_callback.Run(sync_point, lost_resource);
   }
+  if (resource->shared_bitmap) {
+    delete resource->shared_bitmap;
+    resource->pixels = NULL;
+  }
   if (resource->pixels)
     delete[] resource->pixels;
   if (resource->pixel_buffer)
@@ -754,9 +789,11 @@
 }
 
 ResourceProvider::ResourceProvider(OutputSurface* output_surface,
+                                   SharedBitmapManager* shared_bitmap_manager,
                                    int highp_threshold_min,
                                    bool use_rgba_4444_texture_format)
     : output_surface_(output_surface),
+      shared_bitmap_manager_(shared_bitmap_manager),
       lost_output_surface_(false),
       highp_threshold_min_(highp_threshold_min),
       next_id_(1),
@@ -803,6 +840,7 @@
   use_texture_storage_ext_ = caps.texture_storage;
   use_shallow_flush_ = caps.shallow_flush;
   use_texture_usage_hint_ = caps.texture_usage;
+  use_compressed_texture_etc1_ = caps.texture_format_etc1;
 
   texture_uploader_ =
       TextureUploader::Create(context3d, use_map_sub, use_shallow_flush_);
@@ -876,17 +914,15 @@
                                            TransferableResourceArray* list) {
   DCHECK(thread_checker_.CalledOnValidThread());
   WebGraphicsContext3D* context3d = Context3d();
-  if (!context3d || !context3d->makeContextCurrent()) {
-    // TODO(skaslev): Implement this path for software compositing.
-    return;
-  }
+  if (context3d)
+    context3d->makeContextCurrent();
   bool need_sync_point = false;
   for (ResourceIdArray::const_iterator it = resources.begin();
        it != resources.end();
        ++it) {
     TransferableResource resource;
     TransferResource(context3d, *it, &resource);
-    if (!resource.sync_point)
+    if (!resource.sync_point && !resource.is_software)
       need_sync_point = true;
     ++resources_.find(*it)->second.exported_count;
     list->push_back(resource);
@@ -906,10 +942,8 @@
     int child, const TransferableResourceArray& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
   WebGraphicsContext3D* context3d = Context3d();
-  if (!context3d || !context3d->makeContextCurrent()) {
-    // TODO(skaslev): Implement this path for software compositing.
-    return;
-  }
+  if (context3d)
+    context3d->makeContextCurrent();
   Child& child_info = children_.find(child)->second;
   for (TransferableResourceArray::const_iterator it = resources.begin();
        it != resources.end();
@@ -920,34 +954,58 @@
       resources_[resource_in_map_it->second].imported_count++;
       continue;
     }
-    unsigned texture_id;
-    // NOTE: If the parent is a browser and the child a renderer, the parent
-    // is not supposed to have its context wait, because that could induce
-    // deadlocks and/or security issues. The caller is responsible for
-    // waiting asynchronously, and resetting sync_point before calling this.
-    // However if the parent is a renderer (e.g. browser tag), it may be ok
-    // (and is simpler) to wait.
-    if (it->sync_point)
-      GLC(context3d, context3d->waitSyncPoint(it->sync_point));
-    GLC(context3d, texture_id = context3d->createTexture());
-    GLC(context3d, context3d->bindTexture(it->target, texture_id));
-    GLC(context3d,
-        context3d->consumeTextureCHROMIUM(it->target, it->mailbox.name));
+
+    scoped_ptr<SharedBitmap> bitmap;
+    uint8_t* pixels = NULL;
+    if (it->is_software) {
+      if (shared_bitmap_manager_)
+        bitmap = shared_bitmap_manager_->GetSharedBitmapFromId(it->size,
+                                                               it->mailbox);
+      if (bitmap)
+        pixels = bitmap->pixels();
+    }
+
+    if ((!it->is_software && !context3d) || (it->is_software && !pixels)) {
+      TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
+      ReturnedResourceArray to_return;
+      to_return.push_back(it->ToReturnedResource());
+      child_info.return_callback.Run(to_return);
+      continue;
+    }
+
     ResourceId local_id = next_id_++;
-    Resource resource(texture_id,
-                      it->size,
-                      it->target,
-                      it->filter,
-                      0,
-                      GL_CLAMP_TO_EDGE,
-                      TextureUsageAny,
-                      it->format);
-    resource.mailbox.SetName(it->mailbox);
+    Resource& resource = resources_[local_id];
+    if (it->is_software) {
+      resource = Resource(
+          pixels, bitmap.release(), it->size, GL_LINEAR, GL_CLAMP_TO_EDGE);
+    } else {
+      unsigned texture_id;
+      // NOTE: If the parent is a browser and the child a renderer, the parent
+      // is not supposed to have its context wait, because that could induce
+      // deadlocks and/or security issues. The caller is responsible for
+      // waiting asynchronously, and resetting sync_point before calling this.
+      // However if the parent is a renderer (e.g. browser tag), it may be ok
+      // (and is simpler) to wait.
+      if (it->sync_point)
+        GLC(context3d, context3d->waitSyncPoint(it->sync_point));
+      GLC(context3d, texture_id = context3d->createTexture());
+      GLC(context3d, context3d->bindTexture(it->target, texture_id));
+      GLC(context3d,
+          context3d->consumeTextureCHROMIUM(it->target, it->mailbox.name));
+      resource = Resource(texture_id,
+                          it->size,
+                          it->target,
+                          it->filter,
+                          0,
+                          GL_CLAMP_TO_EDGE,
+                          TextureUsageAny,
+                          it->format);
+      resource.mailbox.SetName(it->mailbox);
+    }
     resource.child_id = child;
     // Don't allocate a texture for a child.
     resource.allocated = true;
     resource.imported_count = 1;
-    resources_[local_id] = resource;
     child_info.parent_to_child_map[local_id] = it->id;
     child_info.child_to_parent_map[it->id] = local_id;
   }
@@ -997,10 +1055,8 @@
     const ReturnedResourceArray& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
   WebGraphicsContext3D* context3d = Context3d();
-  if (!context3d || !context3d->makeContextCurrent()) {
-    // TODO(skaslev): Implement this path for software compositing.
-    return;
-  }
+  if (context3d)
+    context3d->makeContextCurrent();
 
   int child_id = 0;
   Child* child_info = NULL;
@@ -1043,7 +1099,7 @@
     if (resource->gl_id) {
       if (returned.sync_point)
         GLC(context3d, context3d->waitSyncPoint(returned.sync_point));
-    } else {
+    } else if (!resource->shared_bitmap) {
       resource->mailbox =
           TextureMailbox(resource->mailbox.name(), returned.sync_point);
     }
@@ -1096,10 +1152,10 @@
   resource->filter = source->filter;
   resource->size = source->size;
 
-  // TODO(skaslev) Implement this path for shared memory resources.
-  DCHECK(!source->mailbox.IsSharedMemory());
-
-  if (!source->mailbox.IsTexture()) {
+  if (source->shared_bitmap) {
+    resource->mailbox = source->shared_bitmap->id();
+    resource->is_software = true;
+  } else if (!source->mailbox.IsValid()) {
     // This is a resource allocated by the compositor, we need to produce it.
     // Don't set a sync point, the caller will do it.
     DCHECK(source->gl_id);
@@ -1110,6 +1166,7 @@
                                         resource->mailbox.name));
     source->mailbox.SetName(resource->mailbox);
   } else {
+    DCHECK(source->mailbox.IsTexture());
     // This is either an external resource, or a compositor resource that we
     // already exported. Make sure to forward the sync point that we were given.
     resource->mailbox = source->mailbox.name();
@@ -1129,10 +1186,8 @@
     return;
 
   WebGraphicsContext3D* context3d = Context3d();
-  if (!context3d || !context3d->makeContextCurrent()) {
-    // TODO(skaslev): Implement this path for software compositing.
-    return;
-  }
+  if (context3d)
+    context3d->makeContextCurrent();
 
   ReturnedResourceArray to_return;
 
@@ -1152,7 +1207,8 @@
     ResourceId child_id = child_info->parent_to_child_map[local_id];
     DCHECK(child_info->child_to_parent_map.count(child_id));
 
-    bool is_lost = resource.lost || lost_output_surface_;
+    bool is_lost =
+        resource.lost || (!resource.shared_bitmap && lost_output_surface_);
     if (resource.exported_count > 0) {
       if (style != ForShutdown) {
         // Defer this until we receive the resource back from the parent.
@@ -1164,7 +1220,7 @@
       is_lost = true;
     }
 
-    if (resource.filter != resource.original_filter) {
+    if (context3d && resource.filter != resource.original_filter) {
       DCHECK(resource.target);
       DCHECK(resource.gl_id);
 
@@ -1182,7 +1238,7 @@
     ReturnedResource returned;
     returned.id = child_id;
     returned.sync_point = resource.mailbox.sync_point();
-    if (!returned.sync_point)
+    if (!returned.sync_point && !resource.shared_bitmap)
       need_sync_point = true;
     returned.count = resource.imported_count;
     returned.lost = is_lost;
@@ -1194,6 +1250,7 @@
     DeleteResourceInternal(it, style);
   }
   if (need_sync_point) {
+    DCHECK(context3d);
     unsigned int sync_point = context3d->insertSyncPoint();
     for (size_t i = 0; i < to_return.size(); ++i) {
       if (!to_return[i].sync_point)
@@ -1210,6 +1267,7 @@
   DCHECK(!resource->external);
   DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->image_id);
+  DCHECK_NE(ETC1, resource->format);
 
   if (resource->type == GLTexture) {
     WebGraphicsContext3D* context3d = Context3d();
@@ -1219,7 +1277,7 @@
     context3d->bindBuffer(
         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
         resource->gl_pixel_buffer_id);
-    unsigned bytes_per_pixel = BytesPerPixel(resource->format);
+    unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
     context3d->bufferData(
         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
         resource->size.height() * RoundUp(bytes_per_pixel
@@ -1542,15 +1600,19 @@
                                               size.width(),
                                               size.height()));
   } else {
-    GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D,
-                                         0,
-                                         GLInternalFormat(format),
-                                         size.width(),
-                                         size.height(),
-                                         0,
-                                         GLDataFormat(format),
-                                         GLDataType(format),
-                                         NULL));
+    // ETC1 does not support preallocation.
+    if (format != ETC1) {
+      GLC(context3d,
+          context3d->texImage2D(GL_TEXTURE_2D,
+                                0,
+                                GLInternalFormat(format),
+                                size.width(),
+                                size.height(),
+                                0,
+                                GLDataFormat(format),
+                                GLDataType(format),
+                                NULL));
+    }
   }
 }
 
@@ -1646,6 +1708,16 @@
   return stride;
 }
 
+base::SharedMemory* ResourceProvider::GetSharedMemory(ResourceId id) {
+  Resource* resource = GetResource(id);
+  DCHECK(!resource->external);
+  DCHECK_EQ(resource->exported_count, 0);
+
+  if (!resource->shared_bitmap)
+    return NULL;
+  return resource->shared_bitmap->memory();
+}
+
 GLint ResourceProvider::GetActiveTextureUnit(WebGraphicsContext3D* context) {
   GLint active_unit = 0;
   context->getIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index b8cb399..23f1414 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -39,6 +39,8 @@
 }
 
 namespace cc {
+class SharedBitmap;
+class SharedBitmapManager;
 class TextureUploader;
 
 // This class is not thread-safe and can only be called from the thread it was
@@ -59,9 +61,11 @@
     Bitmap,
   };
 
-  static scoped_ptr<ResourceProvider> Create(OutputSurface* output_surface,
-                                             int highp_threshold_min,
-                                             bool use_rgba_4444_texture_format);
+  static scoped_ptr<ResourceProvider> Create(
+      OutputSurface* output_surface,
+      SharedBitmapManager* shared_bitmap_manager,
+      int highp_threshold_min,
+      bool use_rgba_4444_texture_format);
   virtual ~ResourceProvider();
 
   void InitializeSoftware();
@@ -320,6 +324,8 @@
   // Returns the stride for the image.
   int GetImageStride(ResourceId id);
 
+  base::SharedMemory* GetSharedMemory(ResourceId id);
+
   // For tests only! This prevents detecting uninitialized reads.
   // Use SetPixels or LockForWrite to allocate implicitly.
   void AllocateForTesting(ResourceId id);
@@ -359,6 +365,7 @@
              TextureUsageHint hint,
              ResourceFormat format);
     Resource(uint8_t* pixels,
+             SharedBitmap* bitmap,
              gfx::Size size,
              GLenum filter,
              GLint wrap_mode);
@@ -398,6 +405,7 @@
     TextureUsageHint hint;
     ResourceType type;
     ResourceFormat format;
+    SharedBitmap* shared_bitmap;
   };
   typedef base::hash_map<ResourceId, Resource> ResourceMap;
 
@@ -422,6 +430,7 @@
   }
 
   ResourceProvider(OutputSurface* output_surface,
+                   SharedBitmapManager* shared_bitmap_manager,
                    int highp_threshold_min,
                    bool use_rgba_4444_texture_format);
 
@@ -461,6 +470,7 @@
   WebKit::WebGraphicsContext3D* Context3d() const;
 
   OutputSurface* output_surface_;
+  SharedBitmapManager* shared_bitmap_manager_;
   bool lost_output_surface_;
   int highp_threshold_min_;
   ResourceId next_id_;
@@ -472,6 +482,7 @@
   bool use_texture_storage_ext_;
   bool use_texture_usage_hint_;
   bool use_shallow_flush_;
+  bool use_compressed_texture_etc1_;
   scoped_ptr<TextureUploader> texture_uploader_;
   int max_texture_size_;
   ResourceFormat best_texture_format_;
@@ -487,16 +498,17 @@
 
 // TODO(epenner): Move these format conversions to resource_format.h
 // once that builds on mac (npapi.h currently #includes OpenGL.h).
-inline unsigned BytesPerPixel(ResourceFormat format) {
+inline unsigned BitsPerPixel(ResourceFormat format) {
   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
-  static const unsigned format_bytes_per_pixel[RESOURCE_FORMAT_MAX + 1] = {
-    4,  // RGBA_8888
-    2,  // RGBA_4444
-    4,  // BGRA_8888
-    1,  // LUMINANCE_8
-    2   // RGB_565
+  static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = {
+    32,  // RGBA_8888
+    16,  // RGBA_4444
+    32,  // BGRA_8888
+    8,   // LUMINANCE_8
+    16,  // RGB_565,
+    4    // ETC1
   };
-  return format_bytes_per_pixel[format];
+  return format_bits_per_pixel[format];
 }
 
 inline GLenum GLDataType(ResourceFormat format) {
@@ -506,7 +518,8 @@
     GL_UNSIGNED_SHORT_4_4_4_4,  // RGBA_4444
     GL_UNSIGNED_BYTE,           // BGRA_8888
     GL_UNSIGNED_BYTE,           // LUMINANCE_8
-    GL_UNSIGNED_SHORT_5_6_5     // RGB_565
+    GL_UNSIGNED_SHORT_5_6_5,    // RGB_565,
+    GL_UNSIGNED_BYTE            // ETC1
   };
   return format_gl_data_type[format];
 }
@@ -514,11 +527,12 @@
 inline GLenum GLDataFormat(ResourceFormat format) {
   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
   static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
-    GL_RGBA,       // RGBA_8888
-    GL_RGBA,       // RGBA_4444
-    GL_BGRA_EXT,   // BGRA_8888
-    GL_LUMINANCE,  // LUMINANCE_8
-    GL_RGB         // RGB_565
+    GL_RGBA,           // RGBA_8888
+    GL_RGBA,           // RGBA_4444
+    GL_BGRA_EXT,       // BGRA_8888
+    GL_LUMINANCE,      // LUMINANCE_8
+    GL_RGB,            // RGB_565
+    GL_ETC1_RGB8_OES   // ETC1
   };
   return format_gl_data_format[format];
 }
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 1e23183..a0b6523 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -15,6 +15,7 @@
 #include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/output_surface.h"
 #include "cc/resources/returned_resource.h"
+#include "cc/resources/shared_bitmap_manager.h"
 #include "cc/resources/single_release_callback.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
@@ -44,6 +45,41 @@
 
 static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
 
+static void SharedMemoryReleaseCallback(scoped_ptr<base::SharedMemory> memory,
+                                        unsigned sync_point,
+                                        bool lost_resource) {}
+
+static void ReleaseTextureMailbox(unsigned* release_sync_point,
+                                  bool* release_lost_resource,
+                                  unsigned sync_point,
+                                  bool lost_resource) {
+  *release_sync_point = sync_point;
+  *release_lost_resource = lost_resource;
+}
+
+static void ReleaseSharedMemoryCallback(
+    scoped_ptr<base::SharedMemory> shared_memory,
+    bool* release_called,
+    unsigned* release_sync_point,
+    bool* lost_resource_result,
+    unsigned sync_point,
+    bool lost_resource) {
+  *release_called = true;
+  *release_sync_point = sync_point;
+  *lost_resource_result = lost_resource;
+}
+
+static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
+    gfx::Size size,
+    uint32_t value) {
+  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
+  CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
+  uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
+  CHECK(pixels);
+  std::fill_n(pixels, size.GetArea(), value);
+  return shared_memory.Pass();
+}
+
 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
  public:
   MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture));
@@ -196,8 +232,11 @@
     CheckTextureIsBound(target);
     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
     ASSERT_FALSE(level);
-    ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
     ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+    {
+      base::AutoLock lock_for_texture_access(namespace_->lock);
+      ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
+    }
     ASSERT_TRUE(pixels);
     SetPixels(xoffset, yoffset, width, height, pixels);
   }
@@ -205,6 +244,7 @@
   virtual void texParameteri(WGC3Denum target, WGC3Denum param, WGC3Dint value)
       OVERRIDE {
     CheckTextureIsBound(target);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     scoped_refptr<TestTexture> texture = BoundTexture(target);
     if (param != GL_TEXTURE_MIN_FILTER)
       return;
@@ -224,6 +264,7 @@
     // haven't waited on that sync point.
     scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
     memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     pending->texture = BoundTexture(target);
     pending_produce_textures_.push_back(pending.Pass());
   }
@@ -231,14 +272,15 @@
   virtual void consumeTextureCHROMIUM(WGC3Denum target,
                                       const WGC3Dbyte* mailbox) OVERRIDE {
     CheckTextureIsBound(target);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     scoped_refptr<TestTexture> texture =
         shared_data_->ConsumeTexture(mailbox, last_waited_sync_point_);
-    base::AutoLock lock(namespace_->lock);
     namespace_->textures.Replace(BoundTextureId(target), texture);
   }
 
   void GetPixels(gfx::Size size, ResourceFormat format, uint8_t* pixels) {
     CheckTextureIsBound(GL_TEXTURE_2D);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
     ASSERT_EQ(texture->size, size);
     ASSERT_EQ(texture->format, format);
@@ -247,11 +289,13 @@
 
   WGC3Denum GetTextureFilter() {
     CheckTextureIsBound(GL_TEXTURE_2D);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     return BoundTexture(GL_TEXTURE_2D)->filter;
   }
 
   scoped_refptr<TestTexture> BoundTexture(WGC3Denum target) {
-    base::AutoLock lock(namespace_->lock);
+    // The caller is expected to lock the namespace for texture access.
+    namespace_->lock.AssertAcquired();
     return namespace_->textures.TextureForId(BoundTextureId(target));
   }
 
@@ -276,6 +320,7 @@
         texture_format = BGRA_8888;
         break;
     }
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format);
   }
 
@@ -285,6 +330,7 @@
                  int height,
                  const void* pixels) {
     CheckTextureIsBound(GL_TEXTURE_2D);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
     scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
     ASSERT_TRUE(texture->data.get());
     ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
@@ -313,6 +359,55 @@
   PendingProduceTextureList pending_produce_textures_;
 };
 
+void FreeSharedBitmap(SharedBitmap* shared_bitmap) {
+  delete shared_bitmap->memory();
+}
+
+void IgnoreSharedBitmap(SharedBitmap* shared_bitmap) {}
+
+class TestSharedBitmapManager : public SharedBitmapManager {
+ public:
+  TestSharedBitmapManager() : count_(0) {}
+  virtual ~TestSharedBitmapManager() {}
+
+  virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size size)
+      OVERRIDE {
+    scoped_ptr<base::SharedMemory> memory(new base::SharedMemory);
+    memory->CreateAndMapAnonymous(size.GetArea() * 4);
+    int8 name[64] = { 0 };
+    name[0] = count_++;
+    SharedBitmapId id;
+    id.SetName(name);
+    bitmap_map_[id] = memory.get();
+    return scoped_ptr<SharedBitmap>(
+        new SharedBitmap(memory.release(), id, base::Bind(&FreeSharedBitmap)));
+  }
+
+  virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
+      gfx::Size,
+      const SharedBitmapId& id) OVERRIDE {
+    if (bitmap_map_.find(id) == bitmap_map_.end())
+      return scoped_ptr<SharedBitmap>();
+    return scoped_ptr<SharedBitmap>(
+        new SharedBitmap(bitmap_map_[id], id, base::Bind(&IgnoreSharedBitmap)));
+  }
+
+  virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
+      base::SharedMemory* memory) OVERRIDE {
+    int8 name[64] = { 0 };
+    name[0] = count_++;
+    SharedBitmapId id;
+    id.SetName(name);
+    bitmap_map_[id] = memory;
+    return scoped_ptr<SharedBitmap>(
+        new SharedBitmap(memory, id, base::Bind(&IgnoreSharedBitmap)));
+  }
+
+ private:
+  int count_;
+  std::map<SharedBitmapId, base::SharedMemory*> bitmap_map_;
+};
+
 void GetResourcePixels(ResourceProvider* resource_provider,
                        ResourceProviderContext* context,
                        ResourceProvider::ResourceId id,
@@ -346,7 +441,8 @@
  public:
   ResourceProviderTest()
       : shared_data_(ContextSharedData::Create()),
-        context3d_(NULL) {
+        context3d_(NULL),
+        child_context_(NULL) {
     switch (GetParam()) {
       case ResourceProvider::GLTexture: {
         scoped_ptr<ResourceProviderContext> context3d(
@@ -358,19 +454,33 @@
                 context3d.PassAs<TestWebGraphicsContext3D>());
 
         output_surface_ = FakeOutputSurface::Create3d(context_provider);
+
+        scoped_ptr<ResourceProviderContext> child_context_owned =
+            ResourceProviderContext::Create(shared_data_.get());
+        child_context_ = child_context_owned.get();
+        child_output_surface_ = FakeOutputSurface::Create3d(
+            child_context_owned.PassAs<TestWebGraphicsContext3D>());
         break;
       }
       case ResourceProvider::Bitmap:
         output_surface_ = FakeOutputSurface::CreateSoftware(
             make_scoped_ptr(new SoftwareOutputDevice));
+        child_output_surface_ = FakeOutputSurface::CreateSoftware(
+            make_scoped_ptr(new SoftwareOutputDevice));
         break;
       case ResourceProvider::InvalidType:
         NOTREACHED();
         break;
     }
     CHECK(output_surface_->BindToClient(&output_surface_client_));
+    CHECK(child_output_surface_->BindToClient(&child_output_surface_client_));
+
+    shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+
     resource_provider_ = ResourceProvider::Create(
-        output_surface_.get(), 0, false);
+        output_surface_.get(), shared_bitmap_manager_.get(), 0, false);
+    child_resource_provider_ = ResourceProvider::Create(
+        child_output_surface_.get(), shared_bitmap_manager_.get(), 0, false);
   }
 
   static void CollectResources(ReturnedResourceArray* array,
@@ -391,12 +501,56 @@
 
   ResourceProviderContext* context() { return context3d_; }
 
+  ResourceProvider::ResourceId CreateChildMailbox(unsigned* release_sync_point,
+                                                  bool* lost_resource,
+                                                  bool* release_called,
+                                                  unsigned* sync_point) {
+    if (GetParam() == ResourceProvider::GLTexture) {
+      unsigned texture = child_context_->createTexture();
+      gpu::Mailbox gpu_mailbox;
+      child_context_->bindTexture(GL_TEXTURE_2D, texture);
+      child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
+      child_context_->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name);
+      *sync_point = child_context_->insertSyncPoint();
+      EXPECT_LT(0u, *sync_point);
+
+      scoped_ptr<base::SharedMemory> shared_memory;
+      scoped_ptr<SingleReleaseCallback> callback =
+          SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback,
+                                                   base::Passed(&shared_memory),
+                                                   release_called,
+                                                   release_sync_point,
+                                                   lost_resource));
+      return child_resource_provider_->CreateResourceFromTextureMailbox(
+          TextureMailbox(gpu_mailbox, *sync_point), callback.Pass());
+    } else {
+      gfx::Size size(64, 64);
+      scoped_ptr<base::SharedMemory> shared_memory(
+          CreateAndFillSharedMemory(size, 0));
+
+      base::SharedMemory* shared_memory_ptr = shared_memory.get();
+      scoped_ptr<SingleReleaseCallback> callback =
+          SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback,
+                                                   base::Passed(&shared_memory),
+                                                   release_called,
+                                                   release_sync_point,
+                                                   lost_resource));
+      return child_resource_provider_->CreateResourceFromTextureMailbox(
+          TextureMailbox(shared_memory_ptr, size), callback.Pass());
+    }
+  }
+
  protected:
   scoped_ptr<ContextSharedData> shared_data_;
   ResourceProviderContext* context3d_;
+  ResourceProviderContext* child_context_;
   FakeOutputSurfaceClient output_surface_client_;
+  FakeOutputSurfaceClient child_output_surface_client_;
   scoped_ptr<OutputSurface> output_surface_;
+  scoped_ptr<OutputSurface> child_output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
+  scoped_ptr<ResourceProvider> child_resource_provider_;
+  scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
 };
 
 void CheckCreateResource(ResourceProvider::ResourceType expected_default_type,
@@ -502,50 +656,35 @@
   resource_provider_->DeleteResource(id);
 }
 
-TEST_P(ResourceProviderTest, TransferResources) {
-  // Resource transfer is only supported with GL textures for now.
+TEST_P(ResourceProviderTest, TransferGLResources) {
   if (GetParam() != ResourceProvider::GLTexture)
     return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-  ResourceProviderContext* child_context = child_context_owned.get();
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(
-      FakeOutputSurface::Create3d(
-          child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
   size_t pixel_size = TextureSizeBytes(size, format);
   ASSERT_EQ(4U, pixel_size);
 
-  ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
+  ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data1[4] = { 1, 2, 3, 4 };
   gfx::Rect rect(size);
-  child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
 
-  ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource(
+  ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data2[4] = { 5, 5, 5, 5 };
-  child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
 
-  WebGLId external_texture_id = child_context->createExternalTexture();
-  child_context->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id);
+  WebGLId external_texture_id = child_context_->createExternalTexture();
+  child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id);
 
   gpu::Mailbox external_mailbox;
-  child_context->genMailboxCHROMIUM(external_mailbox.name);
-  child_context->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES,
-                                        external_mailbox.name);
-  const unsigned external_sync_point = child_context->insertSyncPoint();
+  child_context_->genMailboxCHROMIUM(external_mailbox.name);
+  child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES,
+                                         external_mailbox.name);
+  const unsigned external_sync_point = child_context_->insertSyncPoint();
   ResourceProvider::ResourceId id3 =
-      child_resource_provider->CreateResourceFromTextureMailbox(
+      child_resource_provider_->CreateResourceFromTextureMailbox(
           TextureMailbox(
               external_mailbox, GL_TEXTURE_EXTERNAL_OES, external_sync_point),
           SingleReleaseCallback::Create(base::Bind(&EmptyReleaseCallback)));
@@ -560,8 +699,8 @@
     resource_ids_to_transfer.push_back(id2);
     resource_ids_to_transfer.push_back(id3);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     ASSERT_EQ(3u, list.size());
     EXPECT_NE(0u, list[0].sync_point);
     EXPECT_NE(0u, list[1].sync_point);
@@ -569,9 +708,9 @@
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target);
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id3));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
     resource_provider_->ReceiveFromChild(child_id, list);
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_transfer);
@@ -605,17 +744,17 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(id1);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     EXPECT_EQ(1u, list.size());
     EXPECT_EQ(id1, list[0].id);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
     ReturnedResourceArray returned;
     TransferableResource::ReturnResources(list, &returned);
-    child_resource_provider->ReceiveReturnsFromParent(returned);
+    child_resource_provider_->ReceiveReturnsFromParent(returned);
     // id1 was exported twice, we returned it only once, it should still be
     // in-use.
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
   }
   {
     EXPECT_EQ(0u, returned_to_child.size());
@@ -632,25 +771,27 @@
     EXPECT_FALSE(returned_to_child[0].lost);
     EXPECT_FALSE(returned_to_child[1].lost);
     EXPECT_FALSE(returned_to_child[2].lost);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
     returned_to_child.clear();
   }
-  EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1));
-  EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2));
-  EXPECT_FALSE(child_resource_provider->InUseByConsumer(id3));
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
 
   {
-    ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id1);
+    ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
+                                            id1);
     ASSERT_NE(0U, lock.texture_id());
-    child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id());
-    child_context->GetPixels(size, format, result);
+    child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
+    child_context_->GetPixels(size, format, result);
     EXPECT_EQ(0, memcmp(data1, result, pixel_size));
   }
   {
-    ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id2);
+    ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
+                                            id2);
     ASSERT_NE(0U, lock.texture_id());
-    child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id());
-    child_context->GetPixels(size, format, result);
+    child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
+    child_context_->GetPixels(size, format, result);
     EXPECT_EQ(0, memcmp(data2, result, pixel_size));
   }
   {
@@ -660,8 +801,8 @@
     resource_ids_to_transfer.push_back(id2);
     resource_ids_to_transfer.push_back(id3);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     ASSERT_EQ(3u, list.size());
     EXPECT_EQ(id1, list[0].id);
     EXPECT_EQ(id2, list[1].id);
@@ -672,9 +813,9 @@
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target);
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id3));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
     resource_provider_->ReceiveFromChild(child_id, list);
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_transfer);
@@ -695,9 +836,234 @@
   EXPECT_FALSE(returned_to_child[2].lost);
 }
 
-TEST_P(ResourceProviderTest, DeleteExportedResources) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
+TEST_P(ResourceProviderTest, TransferSoftwareResources) {
+  if (GetParam() != ResourceProvider::Bitmap)
+    return;
+
+  gfx::Size size(1, 1);
+  ResourceFormat format = RGBA_8888;
+  size_t pixel_size = TextureSizeBytes(size, format);
+  ASSERT_EQ(4U, pixel_size);
+
+  ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+  uint8_t data1[4] = { 1, 2, 3, 4 };
+  gfx::Rect rect(size);
+  child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+
+  ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+  uint8_t data2[4] = { 5, 5, 5, 5 };
+  child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+
+  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
+  shared_memory->CreateAndMapAnonymous(1);
+  base::SharedMemory* shared_memory_ptr = shared_memory.get();
+  ResourceProvider::ResourceId id3 =
+      child_resource_provider_->CreateResourceFromTextureMailbox(
+          TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)),
+          SingleReleaseCallback::Create(base::Bind(
+              &SharedMemoryReleaseCallback, base::Passed(&shared_memory))));
+
+  ReturnedResourceArray returned_to_child;
+  int child_id =
+      resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+  {
+    // Transfer some resources to the parent.
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    resource_ids_to_transfer.push_back(id2);
+    resource_ids_to_transfer.push_back(id3);
+    TransferableResourceArray list;
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
+    ASSERT_EQ(3u, list.size());
+    EXPECT_EQ(0u, list[0].sync_point);
+    EXPECT_EQ(0u, list[1].sync_point);
+    EXPECT_EQ(0u, list[2].sync_point);
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+    resource_provider_->ReceiveFromChild(child_id, list);
+    resource_provider_->DeclareUsedResourcesFromChild(child_id,
+                                                      resource_ids_to_transfer);
+  }
+
+  EXPECT_EQ(3u, resource_provider_->num_resources());
+  ResourceProvider::ResourceIdMap resource_map =
+      resource_provider_->GetChildToParentMap(child_id);
+  ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
+  ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
+  ResourceProvider::ResourceId mapped_id3 = resource_map[id3];
+  EXPECT_NE(0u, mapped_id1);
+  EXPECT_NE(0u, mapped_id2);
+  EXPECT_NE(0u, mapped_id3);
+  EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
+  EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
+  EXPECT_FALSE(resource_provider_->InUseByConsumer(id3));
+
+  uint8_t result[4] = { 0 };
+  GetResourcePixels(
+      resource_provider_.get(), context(), mapped_id1, size, format, result);
+  EXPECT_EQ(0, memcmp(data1, result, pixel_size));
+
+  GetResourcePixels(
+      resource_provider_.get(), context(), mapped_id2, size, format, result);
+  EXPECT_EQ(0, memcmp(data2, result, pixel_size));
+
+  {
+    // Check that transfering again the same resource from the child to the
+    // parent works.
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    TransferableResourceArray list;
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
+    EXPECT_EQ(1u, list.size());
+    EXPECT_EQ(id1, list[0].id);
+    ReturnedResourceArray returned;
+    TransferableResource::ReturnResources(list, &returned);
+    child_resource_provider_->ReceiveReturnsFromParent(returned);
+    // id1 was exported twice, we returned it only once, it should still be
+    // in-use.
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+  }
+  {
+    EXPECT_EQ(0u, returned_to_child.size());
+
+    // Transfer resources back from the parent to the child. Set no resources as
+    // being in use.
+    ResourceProvider::ResourceIdArray no_resources;
+    resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
+
+    ASSERT_EQ(3u, returned_to_child.size());
+    EXPECT_EQ(0u, returned_to_child[0].sync_point);
+    EXPECT_EQ(0u, returned_to_child[1].sync_point);
+    EXPECT_EQ(0u, returned_to_child[2].sync_point);
+    EXPECT_EQ(id1, returned_to_child[0].id);
+    EXPECT_EQ(id2, returned_to_child[1].id);
+    EXPECT_EQ(id3, returned_to_child[2].id);
+    EXPECT_FALSE(returned_to_child[0].lost);
+    EXPECT_FALSE(returned_to_child[1].lost);
+    EXPECT_FALSE(returned_to_child[2].lost);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+    returned_to_child.clear();
+  }
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
+  EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
+
+  {
+    ResourceProvider::ScopedReadLockSoftware lock(
+        child_resource_provider_.get(), id1);
+    const SkBitmap* sk_bitmap = lock.sk_bitmap();
+    EXPECT_EQ(sk_bitmap->width(), size.width());
+    EXPECT_EQ(sk_bitmap->height(), size.height());
+    EXPECT_EQ(0, memcmp(data1, sk_bitmap->getPixels(), pixel_size));
+  }
+  {
+    ResourceProvider::ScopedReadLockSoftware lock(
+        child_resource_provider_.get(), id2);
+    const SkBitmap* sk_bitmap = lock.sk_bitmap();
+    EXPECT_EQ(sk_bitmap->width(), size.width());
+    EXPECT_EQ(sk_bitmap->height(), size.height());
+    EXPECT_EQ(0, memcmp(data2, sk_bitmap->getPixels(), pixel_size));
+  }
+  {
+    // Transfer resources to the parent again.
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    resource_ids_to_transfer.push_back(id2);
+    resource_ids_to_transfer.push_back(id3);
+    TransferableResourceArray list;
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
+    ASSERT_EQ(3u, list.size());
+    EXPECT_EQ(id1, list[0].id);
+    EXPECT_EQ(id2, list[1].id);
+    EXPECT_EQ(id3, list[2].id);
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+    resource_provider_->ReceiveFromChild(child_id, list);
+    resource_provider_->DeclareUsedResourcesFromChild(child_id,
+                                                      resource_ids_to_transfer);
+  }
+
+  EXPECT_EQ(0u, returned_to_child.size());
+
+  EXPECT_EQ(3u, resource_provider_->num_resources());
+  resource_provider_->DestroyChild(child_id);
+  EXPECT_EQ(0u, resource_provider_->num_resources());
+
+  ASSERT_EQ(3u, returned_to_child.size());
+  EXPECT_EQ(0u, returned_to_child[0].sync_point);
+  EXPECT_EQ(0u, returned_to_child[1].sync_point);
+  EXPECT_EQ(0u, returned_to_child[2].sync_point);
+  EXPECT_EQ(id1, returned_to_child[0].id);
+  EXPECT_EQ(id2, returned_to_child[1].id);
+  EXPECT_EQ(id3, returned_to_child[2].id);
+  EXPECT_FALSE(returned_to_child[0].lost);
+  EXPECT_FALSE(returned_to_child[1].lost);
+  EXPECT_FALSE(returned_to_child[2].lost);
+}
+
+TEST_P(ResourceProviderTest, TransferSoftwareToNonUber) {
+  // TODO(jbauman): Remove test when shared bitmap manager available
+  // everywhere.
+  if (GetParam() != ResourceProvider::Bitmap)
+    return;
+
+  scoped_ptr<FakeOutputSurface> parent_output_surface =
+      FakeOutputSurface::CreateSoftware(
+          make_scoped_ptr(new SoftwareOutputDevice));
+  FakeOutputSurfaceClient parent_output_surface_client;
+  CHECK(parent_output_surface->BindToClient(&parent_output_surface_client));
+
+  scoped_ptr<ResourceProvider> parent_resource_provider(
+      ResourceProvider::Create(parent_output_surface.get(), NULL, 0, false));
+
+  gfx::Size size(1, 1);
+  ResourceFormat format = RGBA_8888;
+  size_t pixel_size = TextureSizeBytes(size, format);
+  ASSERT_EQ(4U, pixel_size);
+
+  ResourceProvider::ResourceId id1 = resource_provider_->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+  uint8_t data1[4] = { 1, 2, 3, 4 };
+  gfx::Rect rect(size);
+  resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+
+  ReturnedResourceArray returned_to_child;
+  int child_id = parent_resource_provider->CreateChild(
+      GetReturnCallback(&returned_to_child));
+  {
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    TransferableResourceArray list;
+    resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
+    ASSERT_EQ(1u, list.size());
+    EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
+    parent_resource_provider->ReceiveFromChild(child_id, list);
+  }
+
+  EXPECT_EQ(0u, parent_resource_provider->num_resources());
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_EQ(returned_to_child[0].id, id1);
+  ResourceProvider::ResourceIdMap resource_map =
+      parent_resource_provider->GetChildToParentMap(child_id);
+  ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
+  EXPECT_EQ(0u, mapped_id1);
+
+  parent_resource_provider->DestroyChild(child_id);
+  EXPECT_EQ(0u, parent_resource_provider->num_resources());
+
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_FALSE(returned_to_child[0].lost);
+}
+
+TEST_P(ResourceProviderTest, TransferGLToSoftware) {
+  if (GetParam() != ResourceProvider::Bitmap)
     return;
 
   scoped_ptr<ResourceProviderContext> child_context_owned(
@@ -709,7 +1075,7 @@
   CHECK(child_output_surface->BindToClient(&child_output_surface_client));
 
   scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
+      ResourceProvider::Create(child_output_surface.get(), NULL, 0, false));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -718,14 +1084,103 @@
 
   ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
-  uint8_t data1[4] = {1, 2, 3, 4};
+  uint8_t data1[4] = { 1, 2, 3, 4 };
   gfx::Rect rect(size);
   child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
 
-  ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource(
+  ReturnedResourceArray returned_to_child;
+  int child_id =
+      resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+  {
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    TransferableResourceArray list;
+    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
+                                                 &list);
+    ASSERT_EQ(1u, list.size());
+    EXPECT_NE(0u, list[0].sync_point);
+    EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
+    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
+    resource_provider_->ReceiveFromChild(child_id, list);
+  }
+
+  EXPECT_EQ(0u, resource_provider_->num_resources());
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_EQ(returned_to_child[0].id, id1);
+  ResourceProvider::ResourceIdMap resource_map =
+      resource_provider_->GetChildToParentMap(child_id);
+  ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
+  EXPECT_EQ(0u, mapped_id1);
+
+  resource_provider_->DestroyChild(child_id);
+  EXPECT_EQ(0u, resource_provider_->num_resources());
+
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_FALSE(returned_to_child[0].lost);
+}
+
+TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
+  if (GetParam() != ResourceProvider::Bitmap)
+    return;
+
+  gfx::Size size(1, 1);
+  ResourceFormat format = RGBA_8888;
+  size_t pixel_size = TextureSizeBytes(size, format);
+  ASSERT_EQ(4U, pixel_size);
+
+  ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+  uint8_t data1[4] = { 1, 2, 3, 4 };
+  gfx::Rect rect(size);
+  child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+
+  ReturnedResourceArray returned_to_child;
+  int child_id =
+      resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+  {
+    ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+    resource_ids_to_transfer.push_back(id1);
+    TransferableResourceArray list;
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
+    ASSERT_EQ(1u, list.size());
+    // Make invalid.
+    list[0].mailbox.name[1] = 5;
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    resource_provider_->ReceiveFromChild(child_id, list);
+  }
+
+  EXPECT_EQ(0u, resource_provider_->num_resources());
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_EQ(returned_to_child[0].id, id1);
+  ResourceProvider::ResourceIdMap resource_map =
+      resource_provider_->GetChildToParentMap(child_id);
+  ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
+  EXPECT_EQ(0u, mapped_id1);
+
+  resource_provider_->DestroyChild(child_id);
+  EXPECT_EQ(0u, resource_provider_->num_resources());
+
+  ASSERT_EQ(1u, returned_to_child.size());
+  EXPECT_FALSE(returned_to_child[0].lost);
+}
+
+TEST_P(ResourceProviderTest, DeleteExportedResources) {
+  gfx::Size size(1, 1);
+  ResourceFormat format = RGBA_8888;
+  size_t pixel_size = TextureSizeBytes(size, format);
+  ASSERT_EQ(4U, pixel_size);
+
+  ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+  uint8_t data1[4] = { 1, 2, 3, 4 };
+  gfx::Rect rect(size);
+  child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+
+  ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data2[4] = {5, 5, 5, 5};
-  child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -736,13 +1191,15 @@
     resource_ids_to_transfer.push_back(id1);
     resource_ids_to_transfer.push_back(id2);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     ASSERT_EQ(2u, list.size());
-    EXPECT_NE(0u, list[0].sync_point);
-    EXPECT_NE(0u, list[1].sync_point);
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, list[0].sync_point);
+      EXPECT_NE(0u, list[1].sync_point);
+    }
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
     resource_provider_->ReceiveFromChild(child_id, list);
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_transfer);
@@ -767,8 +1224,10 @@
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     ASSERT_EQ(2u, list.size());
-    EXPECT_NE(0u, list[0].sync_point);
-    EXPECT_NE(0u, list[1].sync_point);
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, list[0].sync_point);
+      EXPECT_NE(0u, list[1].sync_point);
+    }
     EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
     EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
 
@@ -791,44 +1250,31 @@
 
     EXPECT_EQ(0u, resource_provider_->num_resources());
     ASSERT_EQ(2u, returned_to_child.size());
-    EXPECT_NE(0u, returned_to_child[0].sync_point);
-    EXPECT_NE(0u, returned_to_child[1].sync_point);
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, returned_to_child[0].sync_point);
+      EXPECT_NE(0u, returned_to_child[1].sync_point);
+    }
     EXPECT_FALSE(returned_to_child[0].lost);
     EXPECT_FALSE(returned_to_child[1].lost);
   }
 }
 
 TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
   size_t pixel_size = TextureSizeBytes(size, format);
   ASSERT_EQ(4U, pixel_size);
 
-  ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
+  ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data1[4] = {1, 2, 3, 4};
   gfx::Rect rect(size);
-  child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
 
-  ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource(
+  ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data2[4] = {5, 5, 5, 5};
-  child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -839,13 +1285,15 @@
     resource_ids_to_transfer.push_back(id1);
     resource_ids_to_transfer.push_back(id2);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     ASSERT_EQ(2u, list.size());
-    EXPECT_NE(0u, list[0].sync_point);
-    EXPECT_NE(0u, list[1].sync_point);
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, list[0].sync_point);
+      EXPECT_NE(0u, list[1].sync_point);
+    }
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
     resource_provider_->ReceiveFromChild(child_id, list);
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_transfer);
@@ -870,8 +1318,10 @@
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     ASSERT_EQ(2u, list.size());
-    EXPECT_NE(0u, list[0].sync_point);
-    EXPECT_NE(0u, list[1].sync_point);
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, list[0].sync_point);
+      EXPECT_NE(0u, list[1].sync_point);
+    }
     EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
     EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
 
@@ -889,8 +1339,10 @@
 
     EXPECT_EQ(0u, resource_provider_->num_resources());
     ASSERT_EQ(2u, returned_to_child.size());
-    EXPECT_NE(0u, returned_to_child[0].sync_point);
-    EXPECT_NE(0u, returned_to_child[1].sync_point);
+    if (GetParam() == ResourceProvider::GLTexture) {
+      EXPECT_NE(0u, returned_to_child[0].sync_point);
+      EXPECT_NE(0u, returned_to_child[1].sync_point);
+    }
     EXPECT_TRUE(returned_to_child[0].lost);
     EXPECT_TRUE(returned_to_child[1].lost);
     returned_to_child.clear();
@@ -909,32 +1361,16 @@
 }
 
 TEST_P(ResourceProviderTest, DeleteTransferredResources) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(
-      FakeOutputSurface::Create3d(
-          child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
   size_t pixel_size = TextureSizeBytes(size, format);
   ASSERT_EQ(4U, pixel_size);
 
-  ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
+  ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
   uint8_t data[4] = { 1, 2, 3, 4 };
   gfx::Rect rect(size);
-  child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
+  child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -944,19 +1380,20 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(id);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     ASSERT_EQ(1u, list.size());
-    EXPECT_NE(0u, list[0].sync_point);
-    EXPECT_TRUE(child_resource_provider->InUseByConsumer(id));
+    if (GetParam() == ResourceProvider::GLTexture)
+      EXPECT_NE(0u, list[0].sync_point);
+    EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
     resource_provider_->ReceiveFromChild(child_id, list);
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_transfer);
   }
 
   // Delete textures in the child, while they are transfered.
-  child_resource_provider->DeleteResource(id);
-  EXPECT_EQ(1u, child_resource_provider->num_resources());
+  child_resource_provider_->DeleteResource(id);
+  EXPECT_EQ(1u, child_resource_provider_->num_resources());
   {
     EXPECT_EQ(0u, returned_to_child.size());
 
@@ -966,10 +1403,11 @@
     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
 
     ASSERT_EQ(1u, returned_to_child.size());
-    EXPECT_NE(0u, returned_to_child[0].sync_point);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    if (GetParam() == ResourceProvider::GLTexture)
+      EXPECT_NE(0u, returned_to_child[0].sync_point);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
   }
-  EXPECT_EQ(0u, child_resource_provider->num_resources());
+  EXPECT_EQ(0u, child_resource_provider_->num_resources());
 }
 
 class ResourceProviderTestTextureFilters : public ResourceProviderTest {
@@ -985,7 +1423,7 @@
     CHECK(child_output_surface->BindToClient(&child_output_surface_client));
 
     scoped_ptr<ResourceProvider> child_resource_provider(
-        ResourceProvider::Create(child_output_surface.get(), 0, false));
+        ResourceProvider::Create(child_output_surface.get(), NULL, 0, false));
 
     scoped_ptr<TextureStateTrackingContext> parent_context_owned(
         new TextureStateTrackingContext);
@@ -997,7 +1435,7 @@
     CHECK(parent_output_surface->BindToClient(&parent_output_surface_client));
 
     scoped_ptr<ResourceProvider> parent_resource_provider(
-        ResourceProvider::Create(parent_output_surface.get(), 0, false));
+        ResourceProvider::Create(parent_output_surface.get(), NULL, 0, false));
 
     gfx::Size size(1, 1);
     ResourceFormat format = RGBA_8888;
@@ -1140,16 +1578,8 @@
   ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST);
 }
 
-void ReleaseTextureMailbox(unsigned* release_sync_point,
-                           bool* release_lost_resource,
-                           unsigned sync_point,
-                           bool lost_resource) {
-  *release_sync_point = sync_point;
-  *release_lost_resource = lost_resource;
-}
-
 TEST_P(ResourceProviderTest, TransferMailboxResources) {
-  // Resource transfer is only supported with GL textures for now.
+  // Other mailbox transfers tested elsewhere.
   if (GetParam() != ResourceProvider::GLTexture)
     return;
   unsigned texture = context()->createTexture();
@@ -1269,27 +1699,14 @@
 }
 
 TEST_P(ResourceProviderTest, LostResourceInParent) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
   ResourceProvider::ResourceId resource =
-      child_resource_provider->CreateResource(
+      child_resource_provider_->CreateResource(
           size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
-  child_resource_provider->AllocateForTesting(resource);
+  child_resource_provider_->AllocateForTesting(resource);
+  // Expect a GL resource to be lost.
+  bool should_lose_resource = GetParam() == ResourceProvider::GLTexture;
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -1299,8 +1716,8 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     EXPECT_EQ(1u, list.size());
 
     resource_provider_->ReceiveFromChild(child_id, list);
@@ -1319,42 +1736,28 @@
     ResourceProvider::ResourceIdArray no_resources;
     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
 
-    // Expect the resource to be lost.
+    // Expect a GL resource to be lost.
     ASSERT_EQ(1u, returned_to_child.size());
-    EXPECT_TRUE(returned_to_child[0].lost);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    EXPECT_EQ(should_lose_resource, returned_to_child[0].lost);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
     returned_to_child.clear();
   }
 
-  // The resource should be lost.
-  EXPECT_TRUE(child_resource_provider->IsLost(resource));
+  // A GL resource should be lost.
+  EXPECT_EQ(should_lose_resource, child_resource_provider_->IsLost(resource));
 
   // Lost resources stay in use in the parent forever.
-  EXPECT_TRUE(child_resource_provider->InUseByConsumer(resource));
+  EXPECT_EQ(should_lose_resource,
+            child_resource_provider_->InUseByConsumer(resource));
 }
 
 TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
   ResourceProvider::ResourceId resource =
-      child_resource_provider->CreateResource(
+      child_resource_provider_->CreateResource(
           size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
-  child_resource_provider->AllocateForTesting(resource);
+  child_resource_provider_->AllocateForTesting(resource);
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -1364,8 +1767,8 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     EXPECT_EQ(1u, list.size());
 
     resource_provider_->ReceiveFromChild(child_id, list);
@@ -1413,47 +1816,24 @@
     // Expect the resource to be lost.
     ASSERT_EQ(1u, returned_to_child.size());
     EXPECT_TRUE(returned_to_child[0].lost);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
     returned_to_child.clear();
   }
 
   // The resource should be lost.
-  EXPECT_TRUE(child_resource_provider->IsLost(resource));
+  EXPECT_TRUE(child_resource_provider_->IsLost(resource));
 
   // Lost resources stay in use in the parent forever.
-  EXPECT_TRUE(child_resource_provider->InUseByConsumer(resource));
+  EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource));
 }
 
 TEST_P(ResourceProviderTest, LostMailboxInParent) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-  ResourceProviderContext* child_context = child_context_owned.get();
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
-  unsigned texture = child_context->createTexture();
-  gpu::Mailbox gpu_mailbox;
-  child_context->bindTexture(GL_TEXTURE_2D, texture);
-  child_context->genMailboxCHROMIUM(gpu_mailbox.name);
-  child_context->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name);
-
   unsigned release_sync_point = 0;
   bool lost_resource = false;
-  ReleaseCallback callback =
-      base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
-  ResourceProvider::ResourceId resource =
-      child_resource_provider->CreateResourceFromTextureMailbox(
-          TextureMailbox(gpu_mailbox), SingleReleaseCallback::Create(callback));
+  bool release_called = false;
+  unsigned sync_point = 0;
+  ResourceProvider::ResourceId resource = CreateChildMailbox(
+      &release_sync_point, &lost_resource, &release_called, &sync_point);
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -1463,8 +1843,8 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     EXPECT_EQ(1u, list.size());
 
     resource_provider_->ReceiveFromChild(child_id, list);
@@ -1483,51 +1863,27 @@
     ResourceProvider::ResourceIdArray no_resources;
     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
 
-    // Expect the resource to be lost.
     ASSERT_EQ(1u, returned_to_child.size());
-    EXPECT_TRUE(returned_to_child[0].lost);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    // Losing an output surface only loses hardware resources.
+    EXPECT_EQ(returned_to_child[0].lost,
+              GetParam() == ResourceProvider::GLTexture);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
     returned_to_child.clear();
   }
 
-  // Delete the resource in the child. Expect the resource to be lost.
-  child_resource_provider->DeleteResource(resource);
-  EXPECT_TRUE(lost_resource);
-
-  child_context->waitSyncPoint(release_sync_point);
-  child_context->deleteTexture(texture);
+  // Delete the resource in the child. Expect the resource to be lost if it's
+  // a GL texture.
+  child_resource_provider_->DeleteResource(resource);
+  EXPECT_EQ(lost_resource, GetParam() == ResourceProvider::GLTexture);
 }
 
 TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
-  // Resource transfer is only supported with GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-
-  scoped_ptr<ResourceProviderContext> child_context_owned(
-      ResourceProviderContext::Create(shared_data_.get()));
-  ResourceProviderContext* child_context = child_context_owned.get();
-
-  FakeOutputSurfaceClient child_output_surface_client;
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      child_context_owned.PassAs<TestWebGraphicsContext3D>()));
-  CHECK(child_output_surface->BindToClient(&child_output_surface_client));
-
-  scoped_ptr<ResourceProvider> child_resource_provider(
-      ResourceProvider::Create(child_output_surface.get(), 0, false));
-
-  unsigned texture = child_context->createTexture();
-  gpu::Mailbox gpu_mailbox;
-  child_context->bindTexture(GL_TEXTURE_2D, texture);
-  child_context->genMailboxCHROMIUM(gpu_mailbox.name);
-  child_context->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name);
-
   unsigned release_sync_point = 0;
   bool lost_resource = false;
-  ReleaseCallback callback =
-      base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
-  ResourceProvider::ResourceId resource =
-      child_resource_provider->CreateResourceFromTextureMailbox(
-          TextureMailbox(gpu_mailbox), SingleReleaseCallback::Create(callback));
+  bool release_called = false;
+  unsigned sync_point = 0;
+  ResourceProvider::ResourceId resource = CreateChildMailbox(
+      &release_sync_point, &lost_resource, &release_called, &sync_point);
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -1537,8 +1893,8 @@
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
     TransferableResourceArray list;
-    child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
-                                                 &list);
+    child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                  &list);
     EXPECT_EQ(1u, list.size());
 
     resource_provider_->ReceiveFromChild(child_id, list);
@@ -1580,116 +1936,54 @@
     // Expect the resource to be lost.
     ASSERT_EQ(1u, returned_to_child.size());
     EXPECT_TRUE(returned_to_child[0].lost);
-    child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+    child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
     returned_to_child.clear();
   }
 
   // Delete the resource in the child. Expect the resource to be lost.
-  child_resource_provider->DeleteResource(resource);
+  child_resource_provider_->DeleteResource(resource);
   EXPECT_TRUE(lost_resource);
-
-  child_context->waitSyncPoint(release_sync_point);
-  child_context->deleteTexture(texture);
 }
 
 TEST_P(ResourceProviderTest, Shutdown) {
-  // TextureMailbox callbacks only exist for GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-  unsigned texture = context()->createTexture();
-  context()->bindTexture(GL_TEXTURE_2D, texture);
-  gpu::Mailbox mailbox;
-  context()->genMailboxCHROMIUM(mailbox.name);
-  context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
-  unsigned sync_point = context()->insertSyncPoint();
-
-  EXPECT_LT(0u, sync_point);
-
   unsigned release_sync_point = 0;
   bool lost_resource = false;
-  scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
-      base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource));
-  resource_provider_->CreateResourceFromTextureMailbox(
-      TextureMailbox(mailbox, sync_point),
-      callback.Pass());
+  bool release_called = false;
+  unsigned sync_point = 0;
+  CreateChildMailbox(
+      &release_sync_point, &lost_resource, &release_called, &sync_point);
 
   EXPECT_EQ(0u, release_sync_point);
   EXPECT_FALSE(lost_resource);
 
-  resource_provider_.reset();
+  child_resource_provider_.reset();
 
-  EXPECT_LE(sync_point, release_sync_point);
+  if (GetParam() == ResourceProvider::GLTexture) {
+    EXPECT_LE(sync_point, release_sync_point);
+  }
+  EXPECT_TRUE(release_called);
   EXPECT_FALSE(lost_resource);
 }
 
-static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
-    gfx::Size size, uint32_t value) {
-  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
-  CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
-  uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
-  CHECK(pixels);
-  std::fill_n(pixels, size.GetArea(), value);
-  return shared_memory.Pass();
-}
-
-static void ReleaseSharedMemoryCallback(
-    bool* release_called,
-    unsigned sync_point, bool lost_resource) {
-  *release_called = true;
-}
-
-TEST_P(ResourceProviderTest, ShutdownSharedMemory) {
-  if (GetParam() != ResourceProvider::Bitmap)
-    return;
-
-  gfx::Size size(64, 64);
-  scoped_ptr<base::SharedMemory> shared_memory(
-      CreateAndFillSharedMemory(size, 0));
-
-  bool release_called = false;
-  scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
-      base::Bind(ReleaseSharedMemoryCallback, &release_called));
-  resource_provider_->CreateResourceFromTextureMailbox(
-      TextureMailbox(shared_memory.get(), size),
-      callback.Pass());
-
-  resource_provider_.reset();
-
-  EXPECT_TRUE(release_called);
-}
-
 TEST_P(ResourceProviderTest, ShutdownWithExportedResource) {
-  // TextureMailbox callbacks only exist for GL textures for now.
-  if (GetParam() != ResourceProvider::GLTexture)
-    return;
-  unsigned texture = context()->createTexture();
-  context()->bindTexture(GL_TEXTURE_2D, texture);
-  gpu::Mailbox mailbox;
-  context()->genMailboxCHROMIUM(mailbox.name);
-  context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
-  unsigned sync_point = context()->insertSyncPoint();
-
-  EXPECT_LT(0u, sync_point);
-
   unsigned release_sync_point = 0;
   bool lost_resource = false;
-  scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
-      base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource));
-  ResourceProvider::ResourceId resource =
-      resource_provider_->CreateResourceFromTextureMailbox(
-          TextureMailbox(mailbox, sync_point),
-          callback.Pass());
+  bool release_called = false;
+  unsigned sync_point = 0;
+  ResourceProvider::ResourceId resource = CreateChildMailbox(
+      &release_sync_point, &lost_resource, &release_called, &sync_point);
 
   // Transfer the resource, so we can't release it properly on shutdown.
   ResourceProvider::ResourceIdArray resource_ids_to_transfer;
   resource_ids_to_transfer.push_back(resource);
   TransferableResourceArray list;
-  resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
+  child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                &list);
 
   EXPECT_EQ(0u, release_sync_point);
   EXPECT_FALSE(lost_resource);
 
-  resource_provider_.reset();
+  child_resource_provider_.reset();
 
   // Since the resource is in the parent, the child considers it lost.
   EXPECT_EQ(0u, release_sync_point);
@@ -1742,7 +2036,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -1823,7 +2117,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -1868,7 +2162,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -1921,7 +2215,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
       base::Bind(&EmptyReleaseCallback));
@@ -1956,7 +2250,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   unsigned texture_id = 1;
   unsigned sync_point = 30;
@@ -2020,7 +2314,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   unsigned texture_id = 1;
   unsigned sync_point = 30;
@@ -2114,6 +2408,15 @@
                     WGC3Denum format,
                     WGC3Denum type,
                     const void* pixels));
+  MOCK_METHOD8(compressedTexImage2D,
+               void(WGC3Denum target,
+                    WGC3Dint level,
+                    WGC3Denum internalformat,
+                    WGC3Dsizei width,
+                    WGC3Dsizei height,
+                    WGC3Dint border,
+                    WGC3Dsizei image_size,
+                    const void* data));
   MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum));
   MOCK_METHOD3(createImageCHROMIUM, WGC3Duint(WGC3Dsizei, WGC3Dsizei,
                                               WGC3Denum));
@@ -2140,7 +2443,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   gfx::Size size(2, 2);
   gfx::Vector2d offset(0, 0);
@@ -2216,7 +2519,7 @@
   int texture_id = 123;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -2253,7 +2556,7 @@
   const uint32_t kBadBeef = 0xbadbeef;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -2299,7 +2602,7 @@
   int texture_id = 123;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -2340,7 +2643,7 @@
   int texture_id = 123;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   EXPECT_CALL(*context, createTexture()).WillRepeatedly(Return(texture_id));
 
@@ -2378,7 +2681,7 @@
   const unsigned kImageId = 234u;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -2470,7 +2773,7 @@
   const uint32_t kBadBeef = 0xbadbeef;
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -2521,7 +2824,7 @@
           scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)));
   EXPECT_TRUE(output_surface->BindToClient(&client));
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
 
   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
 
@@ -2538,6 +2841,71 @@
                        output_surface.get());
 }
 
+TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
+  if (GetParam() != ResourceProvider::GLTexture)
+    return;
+
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new AllocationTrackingContext3D);
+  AllocationTrackingContext3D* context = context_owned.get();
+  context_owned->set_support_compressed_texture_etc1(true);
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
+  gfx::Size size(4, 4);
+  scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+      output_surface.get(), shared_bitmap_manager_.get(), 0, false));
+  int texture_id = 123;
+
+  ResourceProvider::ResourceId id = resource_provider->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1);
+  EXPECT_NE(0u, id);
+  EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
+  resource_provider->AllocateForTesting(id);
+
+  EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
+  resource_provider->DeleteResource(id);
+}
+
+TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
+  if (GetParam() != ResourceProvider::GLTexture)
+    return;
+
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new AllocationTrackingContext3D);
+  AllocationTrackingContext3D* context = context_owned.get();
+  context_owned->set_support_compressed_texture_etc1(true);
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
+  gfx::Size size(4, 4);
+  scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+      output_surface.get(), shared_bitmap_manager_.get(), 0, false));
+  int texture_id = 123;
+  uint8_t pixels[8];
+
+  ResourceProvider::ResourceId id = resource_provider->CreateResource(
+      size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1);
+  EXPECT_NE(0u, id);
+  EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
+  EXPECT_CALL(*context,
+              compressedTexImage2D(
+                  _, 0, _, size.width(), size.height(), _, _, _)).Times(1);
+  resource_provider->SetPixels(
+      id, pixels, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(0, 0));
+
+  EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
+  resource_provider->DeleteResource(id);
+}
+
 INSTANTIATE_TEST_CASE_P(
     ResourceProviderTests,
     ResourceProviderTest,
diff --git a/cc/resources/resource_update_controller.cc b/cc/resources/resource_update_controller.cc
index 3114d1e..59c536b 100644
--- a/cc/resources/resource_update_controller.cc
+++ b/cc/resources/resource_update_controller.cc
@@ -9,6 +9,7 @@
 #include "base/single_thread_task_runner.h"
 #include "cc/resources/prioritized_resource.h"
 #include "cc/resources/resource_provider.h"
+#include "ui/gfx/frame_time.h"
 
 namespace {
 
@@ -113,7 +114,7 @@
 }
 
 base::TimeTicks ResourceUpdateController::Now() const {
-  return base::TimeTicks::Now();
+  return gfx::FrameTime::Now();
 }
 
 base::TimeDelta ResourceUpdateController::UpdateMoreTexturesTime() const {
diff --git a/cc/resources/resource_update_controller_unittest.cc b/cc/resources/resource_update_controller_unittest.cc
index 498d682..9f43f80 100644
--- a/cc/resources/resource_update_controller_unittest.cc
+++ b/cc/resources/resource_update_controller_unittest.cc
@@ -137,7 +137,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
   }
 
   void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index 8b59995..dc0df8b 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -19,7 +19,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
   scoped_ptr<ScopedResource> texture =
       ScopedResource::create(resource_provider.get());
 
@@ -37,7 +37,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
   scoped_ptr<ScopedResource> texture =
       ScopedResource::create(resource_provider.get());
   texture->Allocate(gfx::Size(30, 30),
@@ -59,7 +59,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
   {
     scoped_ptr<ScopedResource> texture =
         ScopedResource::create(resource_provider.get());
@@ -93,7 +93,7 @@
   CHECK(output_surface->BindToClient(&output_surface_client));
 
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0, false));
+      ResourceProvider::Create(output_surface.get(), NULL, 0, false));
   {
     scoped_ptr<ScopedResource> texture =
         ScopedResource::create(resource_provider.get());
diff --git a/cc/resources/shared_bitmap.cc b/cc/resources/shared_bitmap.cc
new file mode 100644
index 0000000..3a6fc35
--- /dev/null
+++ b/cc/resources/shared_bitmap.cc
@@ -0,0 +1,17 @@
+// Copyright 2013 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 "cc/resources/shared_bitmap.h"
+
+namespace cc {
+
+SharedBitmap::SharedBitmap(
+    base::SharedMemory* memory,
+    const SharedBitmapId& id,
+    const base::Callback<void(SharedBitmap*)>& free_callback)
+    : memory_(memory), id_(id), free_callback_(free_callback) {}
+
+SharedBitmap::~SharedBitmap() { free_callback_.Run(this); }
+
+}  // namespace cc
diff --git a/cc/resources/shared_bitmap.h b/cc/resources/shared_bitmap.h
new file mode 100644
index 0000000..9575068
--- /dev/null
+++ b/cc/resources/shared_bitmap.h
@@ -0,0 +1,51 @@
+// Copyright 2013 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 CC_RESOURCES_SHARED_BITMAP_H_
+#define CC_RESOURCES_SHARED_BITMAP_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/shared_memory.h"
+#include "cc/base/cc_export.h"
+#include "gpu/command_buffer/common/mailbox.h"
+
+namespace base { class SharedMemory; }
+
+namespace cc {
+typedef gpu::Mailbox SharedBitmapId;
+
+class CC_EXPORT SharedBitmap {
+ public:
+  SharedBitmap(base::SharedMemory* memory,
+               const SharedBitmapId& id,
+               const base::Callback<void(SharedBitmap*)>& free_callback);
+
+  ~SharedBitmap();
+
+  bool operator<(const SharedBitmap& right) const {
+    if (memory_ < right.memory_)
+      return true;
+    if (memory_ > right.memory_)
+      return false;
+    return id_ < right.id_;
+  }
+
+  uint8* pixels() { return static_cast<uint8*>(memory_->memory()); }
+
+  base::SharedMemory* memory() { return memory_; }
+
+  SharedBitmapId id() { return id_; }
+
+ private:
+  base::SharedMemory* memory_;
+  SharedBitmapId id_;
+  base::Callback<void(SharedBitmap*)> free_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_SHARED_BITMAP_H_
diff --git a/cc/resources/shared_bitmap_manager.h b/cc/resources/shared_bitmap_manager.h
new file mode 100644
index 0000000..53dd156
--- /dev/null
+++ b/cc/resources/shared_bitmap_manager.h
@@ -0,0 +1,32 @@
+// Copyright 2013 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 CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
+#define CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/shared_bitmap.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+
+class CC_EXPORT SharedBitmapManager {
+ public:
+  SharedBitmapManager() {}
+
+  virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size) = 0;
+  virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
+      gfx::Size,
+      const SharedBitmapId&) = 0;
+  virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
+      base::SharedMemory*) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SharedBitmapManager);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index b2e536f..df69f70 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -471,13 +471,13 @@
 
   // Update internal state.
   if (state != global_state_) {
+    global_state_ = state;
     prioritized_tiles_dirty_ = true;
     resource_pool_->SetResourceUsageLimits(
         global_state_.memory_limit_in_bytes,
         global_state_.unused_memory_limit_in_bytes,
         global_state_.num_resources_limit);
   }
-  global_state_ = state;
 
   // We need to call CheckForCompletedTasks() once in-between each call
   // to ScheduleTasks() to prevent canceled tasks from being scheduled.
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7292f1d..f533e65 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -40,7 +40,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
     tile_manager_ = make_scoped_ptr(
         new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
     picture_pile_ = FakePicturePileImpl::CreatePile();
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 2f9db48..c5bc6da 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -26,7 +26,7 @@
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), 0, false);
+        ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
     tile_manager_ = make_scoped_ptr(
         new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
 
diff --git a/cc/resources/transferable_resource.cc b/cc/resources/transferable_resource.cc
index 88ad8fd..62f1bdb 100644
--- a/cc/resources/transferable_resource.cc
+++ b/cc/resources/transferable_resource.cc
@@ -9,7 +9,12 @@
 namespace cc {
 
 TransferableResource::TransferableResource()
-    : id(0), sync_point(0), format(RGBA_8888), target(0), filter(0) {}
+    : id(0),
+      sync_point(0),
+      format(RGBA_8888),
+      target(0),
+      filter(0),
+      is_software(false) {}
 
 TransferableResource::~TransferableResource() {
 }
diff --git a/cc/resources/transferable_resource.h b/cc/resources/transferable_resource.h
index cb650a7..5c93d1c 100644
--- a/cc/resources/transferable_resource.h
+++ b/cc/resources/transferable_resource.h
@@ -35,6 +35,7 @@
   uint32 filter;
   gfx::Size size;
   gpu::Mailbox mailbox;
+  bool is_software;
 };
 
 }  // namespace cc
diff --git a/cc/resources/ui_resource_bitmap.cc b/cc/resources/ui_resource_bitmap.cc
index 86acfa5..62a85fc 100644
--- a/cc/resources/ui_resource_bitmap.cc
+++ b/cc/resources/ui_resource_bitmap.cc
@@ -12,20 +12,21 @@
 
 void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref,
                               UIResourceFormat format,
-                              UIResourceWrapMode wrap_mode,
                               gfx::Size size) {
   DCHECK(size.width());
   DCHECK(size.height());
   DCHECK(pixel_ref);
   DCHECK(pixel_ref->isImmutable());
   format_ = format;
-  wrap_mode_ = wrap_mode;
   size_ = size;
   pixel_ref_ = pixel_ref;
+
+  // Default values for secondary parameters.
+  wrap_mode_ = CLAMP_TO_EDGE;
+  opaque_ = (format == ETC1);
 }
 
-UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap,
-                                   UIResourceWrapMode wrap_mode) {
+UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) {
   DCHECK_EQ(skbitmap.config(), SkBitmap::kARGB_8888_Config);
   DCHECK_EQ(skbitmap.width(), skbitmap.rowBytesAsPixels());
   DCHECK(skbitmap.isImmutable());
@@ -33,8 +34,15 @@
   skia::RefPtr<SkPixelRef> pixel_ref = skia::SharePtr(skbitmap.pixelRef());
   Create(pixel_ref,
          UIResourceBitmap::RGBA8,
-         wrap_mode,
          gfx::Size(skbitmap.width(), skbitmap.height()));
+
+  SetOpaque(skbitmap.isOpaque());
+}
+
+UIResourceBitmap::UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref,
+                                   UIResourceFormat format,
+                                   gfx::Size size) {
+  Create(pixel_ref, format, size);
 }
 
 UIResourceBitmap::~UIResourceBitmap() {}
diff --git a/cc/resources/ui_resource_bitmap.h b/cc/resources/ui_resource_bitmap.h
index 78cb465..d0f717a 100644
--- a/cc/resources/ui_resource_bitmap.h
+++ b/cc/resources/ui_resource_bitmap.h
@@ -24,7 +24,8 @@
 class CC_EXPORT UIResourceBitmap {
  public:
   enum UIResourceFormat {
-    RGBA8
+    RGBA8,
+    ETC1
   };
   enum UIResourceWrapMode {
     CLAMP_TO_EDGE,
@@ -34,12 +35,18 @@
   gfx::Size GetSize() const { return size_; }
   UIResourceFormat GetFormat() const { return format_; }
   UIResourceWrapMode GetWrapMode() const { return wrap_mode_; }
+  void SetWrapMode(UIResourceWrapMode wrap_mode) { wrap_mode_ = wrap_mode; }
+  bool GetOpaque() const { return opaque_; }
+  void SetOpaque(bool opaque) { opaque_ = opaque; }
 
   // The constructor for the UIResourceBitmap.  User must ensure that |skbitmap|
   // is immutable.  The SkBitmap format should be in 32-bit RGBA.  Wrap mode is
   // unnecessary for most UI resources and is defaulted to CLAMP_TO_EDGE.
-  UIResourceBitmap(const SkBitmap& skbitmap,
-                   UIResourceWrapMode wrap_mode = CLAMP_TO_EDGE);
+  explicit UIResourceBitmap(const SkBitmap& skbitmap);
+
+  UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref,
+                   UIResourceFormat format,
+                   gfx::Size size);
 
   ~UIResourceBitmap();
 
@@ -47,13 +54,13 @@
   friend class AutoLockUIResourceBitmap;
   void Create(const skia::RefPtr<SkPixelRef>& pixel_ref,
               UIResourceFormat format,
-              UIResourceWrapMode wrap_mode,
               gfx::Size size);
 
   skia::RefPtr<SkPixelRef> pixel_ref_;
   UIResourceFormat format_;
   UIResourceWrapMode wrap_mode_;
   gfx::Size size_;
+  bool opaque_;
 };
 
 class CC_EXPORT AutoLockUIResourceBitmap {
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 34c7ab6..b819b38 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -261,24 +261,30 @@
                              0xff);
     }
 
-    // In software mode, the resource provider won't be lost. Soon this callback
-    // will be called directly from the resource provider, same as 3d
-    // compositing mode, so this raw unretained resource_provider will always
-    // be valid when the callback is fired.
     RecycleResourceData recycle_data = {
       plane_resources[0].resource_id,
       plane_resources[0].resource_size,
       plane_resources[0].resource_format,
       gpu::Mailbox()
     };
+    base::SharedMemory* shared_memory =
+        resource_provider_->GetSharedMemory(plane_resources[0].resource_id);
+    if (shared_memory) {
+      external_resources.mailboxes.push_back(
+          TextureMailbox(shared_memory, plane_resources[0].resource_size));
+      external_resources.release_callbacks
+          .push_back(base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
+      external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
+    } else {
+      // TODO(jbauman): Remove this path once shared memory is available
+      // everywhere.
+      external_resources.software_resources
+          .push_back(plane_resources[0].resource_id);
+      external_resources.software_release_callback =
+          base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
+      external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
+    }
 
-    external_resources.software_resources.push_back(
-        plane_resources[0].resource_id);
-    external_resources.software_release_callback =
-        base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
-
-
-    external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
     return external_resources;
   }
 
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index c36689e..028e0a6 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -26,7 +26,7 @@
         FakeOutputSurface::Create3d(context3d.Pass());
     CHECK(output_surface3d_->BindToClient(&client_));
     resource_provider3d_ =
-        ResourceProvider::Create(output_surface3d_.get(), 0, false);
+        ResourceProvider::Create(output_surface3d_.get(), NULL, 0, false);
   }
 
   scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
diff --git a/cc/scheduler/delay_based_time_source.cc b/cc/scheduler/delay_based_time_source.cc
index d150c71..00515b7 100644
--- a/cc/scheduler/delay_based_time_source.cc
+++ b/cc/scheduler/delay_based_time_source.cc
@@ -33,6 +33,27 @@
 
 }  // namespace
 
+// The following methods correspond to the DelayBasedTimeSource that uses
+// the base::TimeTicks::HighResNow as the timebase.
+scoped_refptr<DelayBasedTimeSourceHighRes> DelayBasedTimeSourceHighRes::Create(
+    base::TimeDelta interval,
+    base::SingleThreadTaskRunner* task_runner) {
+  return make_scoped_refptr(
+      new DelayBasedTimeSourceHighRes(interval, task_runner));
+}
+
+DelayBasedTimeSourceHighRes::DelayBasedTimeSourceHighRes(
+    base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner)
+    : DelayBasedTimeSource(interval, task_runner) {}
+
+DelayBasedTimeSourceHighRes::~DelayBasedTimeSourceHighRes() {}
+
+base::TimeTicks DelayBasedTimeSourceHighRes::Now() const {
+  return base::TimeTicks::HighResNow();
+}
+
+// The following methods correspond to the DelayBasedTimeSource that uses
+// the base::TimeTicks::Now as the timebase.
 scoped_refptr<DelayBasedTimeSource> DelayBasedTimeSource::Create(
     base::TimeDelta interval,
     base::SingleThreadTaskRunner* task_runner) {
diff --git a/cc/scheduler/delay_based_time_source.h b/cc/scheduler/delay_based_time_source.h
index 55aac5a..ddb89da 100644
--- a/cc/scheduler/delay_based_time_source.h
+++ b/cc/scheduler/delay_based_time_source.h
@@ -15,7 +15,7 @@
 
 // This timer implements a time source that achieves the specified interval
 // in face of millisecond-precision delayed callbacks and random queueing
-// delays.
+// delays. DelayBasedTimeSource uses base::TimeTicks::Now as its timebase.
 class CC_EXPORT DelayBasedTimeSource : public TimeSource {
  public:
   static scoped_refptr<DelayBasedTimeSource> Create(
@@ -73,6 +73,23 @@
   DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
 };
 
+// DelayBasedTimeSource uses base::TimeTicks::HighResNow as its timebase.
+class DelayBasedTimeSourceHighRes : public DelayBasedTimeSource {
+ public:
+  static scoped_refptr<DelayBasedTimeSourceHighRes> Create(
+        base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner);
+
+  virtual base::TimeTicks Now() const OVERRIDE;
+
+ protected:
+  DelayBasedTimeSourceHighRes(base::TimeDelta interval,
+                              base::SingleThreadTaskRunner* task_runner);
+  virtual ~DelayBasedTimeSourceHighRes();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSourceHighRes);
+};
+
 }  // namespace cc
 
 #endif  // CC_SCHEDULER_DELAY_BASED_TIME_SOURCE_H_
diff --git a/cc/scheduler/frame_rate_controller.cc b/cc/scheduler/frame_rate_controller.cc
index 47c27ed..2729748 100644
--- a/cc/scheduler/frame_rate_controller.cc
+++ b/cc/scheduler/frame_rate_controller.cc
@@ -11,6 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "cc/scheduler/delay_based_time_source.h"
 #include "cc/scheduler/time_source.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 
@@ -165,7 +166,7 @@
   if (is_time_source_throttling_)
     return time_source_->LastTickTime();
 
-  return base::TimeTicks::Now();
+  return gfx::FrameTime::Now();
 }
 
 }  // namespace cc
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 382bd96..93b9131 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -9,6 +9,7 @@
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "cc/debug/traced_value.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 
@@ -78,6 +79,11 @@
   ProcessScheduledActions();
 }
 
+void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
+  state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
+  ProcessScheduledActions();
+}
+
 void Scheduler::SetMainThreadNeedsLayerTextures() {
   state_machine_.SetMainThreadNeedsLayerTextures();
   ProcessScheduledActions();
@@ -118,7 +124,7 @@
       last_begin_impl_frame_args_.interval <= base::TimeDelta())
     return base::TimeTicks();
 
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time,
                                       last_begin_impl_frame_args_.deadline);
   int64 intervals =
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 00b8377..1a284f1 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -86,6 +86,8 @@
 
   void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
 
+  void SetSmoothnessTakesPriority(bool smoothness_takes_priority);
+
   void FinishCommit();
   void BeginMainFrameAborted(bool did_handle);
 
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 6c1db6b..9b8032c 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -7,7 +7,7 @@
 namespace cc {
 
 SchedulerSettings::SchedulerSettings()
-    : deadline_scheduling_enabled(false),
+    : deadline_scheduling_enabled(true),
       impl_side_painting(false),
       timeout_and_draw_when_animation_checkerboards(true),
       maximum_number_of_failed_draws_before_draw_is_forced_(3),
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index c14186a..0fd0f57 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 
@@ -39,7 +40,8 @@
       pending_tree_is_ready_for_activation_(false),
       active_tree_needs_first_draw_(false),
       draw_if_possible_failed_(false),
-      did_create_and_initialize_first_output_surface_(false) {}
+      did_create_and_initialize_first_output_surface_(false),
+      smoothness_takes_priority_(false) {}
 
 const char* SchedulerStateMachine::OutputSurfaceStateToString(
     OutputSurfaceState state) {
@@ -192,7 +194,7 @@
   state->Set("major_state", major_state.release());
 
   scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue);
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   timestamps_state->SetDouble(
       "0_interval",
       last_begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
@@ -255,6 +257,8 @@
   minor_state->SetBoolean("draw_if_possible_failed", draw_if_possible_failed_);
   minor_state->SetBoolean("did_create_and_initialize_first_output_surface",
                           did_create_and_initialize_first_output_surface_);
+  minor_state->SetBoolean("smoothness_takes_priority",
+                          smoothness_takes_priority_);
   state->Set("minor_state", minor_state.release());
 
   return state.PassAs<base::Value>();
@@ -820,7 +824,7 @@
 // These are cases where we are very likely to draw soon, but might not
 // actually have a new frame to draw when we receive the next BeginImplFrame.
 // Proactively requesting the BeginImplFrame helps hide the round trip latency
-// of the SetNeedsBeginFrame request that has to go to the Browser.
+// of the SetNeedsBeginImplFrame request that has to go to the Browser.
 bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
   // The output surface is the provider of BeginImplFrames,
   // so we are not going to get them even if we ask for them.
@@ -847,9 +851,10 @@
     return true;
 
   // If we just swapped, it's likely that we are going to produce another
-  // frame soon. This helps avoid negative glitches in our SetNeedsBeginFrame
-  // requests, which may propagate to the BeginImplFrame provider and get
-  // sampled at an inopportune time, delaying the next BeginImplFrame.
+  // frame soon. This helps avoid negative glitches in our
+  // SetNeedsBeginImplFrame requests, which may propagate to the BeginImplFrame
+  // provider and get sampled at an inopportune time, delaying the next
+  // BeginImplFrame.
   if (last_frame_number_swap_performed_ == current_frame_number_)
     return true;
 
@@ -896,12 +901,19 @@
   if (active_tree_needs_first_draw_)
     return true;
 
+  if (!needs_redraw_)
+    return false;
+
   // This is used to prioritize impl-thread draws when the main thread isn't
   // producing anything, e.g., after an aborted commit. We also check that we
   // don't have a pending tree -- otherwise we should give it a chance to
   // activate.
   // TODO(skyostil): Revisit this when we have more accurate deadline estimates.
-  if (commit_state_ == COMMIT_STATE_IDLE && needs_redraw_ && !has_pending_tree_)
+  if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
+    return true;
+
+  // Prioritize impl-thread draws in smoothness mode.
+  if (smoothness_takes_priority_)
     return true;
 
   return false;
@@ -935,6 +947,11 @@
   swap_used_incomplete_tile_ = used_incomplete_tile;
 }
 
+void SchedulerStateMachine::SetSmoothnessTakesPriority(
+    bool smoothness_takes_priority) {
+  smoothness_takes_priority_ = smoothness_takes_priority;
+}
+
 void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
   draw_if_possible_failed_ = !success;
   if (draw_if_possible_failed_) {
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 01eeca6..9b6d4fb 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -171,6 +171,10 @@
   // with a low resolution or checkerboarded tile.
   void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
 
+  // Indicates whether to prioritize animation smoothness over new content
+  // activation.
+  void SetSmoothnessTakesPriority(bool smoothness_takes_priority);
+
   // Indicates whether ACTION_DRAW_AND_SWAP_IF_POSSIBLE drew to the screen.
   void DidDrawIfPossibleCompleted(bool success);
 
@@ -283,6 +287,7 @@
   bool active_tree_needs_first_draw_;
   bool draw_if_possible_failed_;
   bool did_create_and_initialize_first_output_surface_;
+  bool smoothness_takes_priority_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index e58015d..67925a0 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -1735,5 +1735,31 @@
   EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
 }
 
+TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyForSmoothness) {
+  SchedulerSettings settings;
+  settings.deadline_scheduling_enabled = true;
+  settings.impl_side_painting = true;
+  StateMachine state(settings);
+  state.SetCanStart();
+  state.UpdateState(state.NextAction());
+  state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+  state.SetVisible(true);
+  state.SetCanDraw(true);
+
+  // This test ensures that impl-draws are prioritized over main thread updates
+  // in prefer smoothness mode.
+  state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+  state.SetNeedsRedraw(true);
+  state.SetNeedsCommit();
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // The deadline is not triggered early until we enter prefer smoothness mode.
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+  state.SetSmoothnessTakesPriority(true);
+  EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/scheduler/texture_uploader.cc b/cc/scheduler/texture_uploader.cc
index cebc986..ba4e372 100644
--- a/cc/scheduler/texture_uploader.cc
+++ b/cc/scheduler/texture_uploader.cc
@@ -143,6 +143,13 @@
   if (is_full_upload)
     BeginQuery();
 
+  if (format == ETC1) {
+    // ETC1 does not support subimage uploads.
+    DCHECK(is_full_upload);
+    UploadWithTexImageETC1(image, size);
+    return;
+  }
+
   if (use_map_tex_sub_image_) {
     UploadWithMapTexSubImage(
         image, image_rect, source_rect, dest_offset, format);
@@ -190,7 +197,7 @@
   gfx::Vector2d offset(source_rect.origin() - image_rect.origin());
 
   const uint8* pixel_source;
-  unsigned bytes_per_pixel = BytesPerPixel(format);
+  unsigned bytes_per_pixel = BitsPerPixel(format) / 8;
   // Use 4-byte row alignment (OpenGL default) for upload performance.
   // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
   unsigned upload_image_stride =
@@ -239,11 +246,13 @@
   if (source_rect.IsEmpty())
     return;
   DCHECK(image);
+  // Compressed textures have no implementation of mapTexSubImage.
+  DCHECK_NE(ETC1, format);
 
   // Offset from image-rect to source-rect.
   gfx::Vector2d offset(source_rect.origin() - image_rect.origin());
 
-  unsigned bytes_per_pixel = BytesPerPixel(format);
+  unsigned bytes_per_pixel = BitsPerPixel(format) / 8;
   // Use 4-byte row alignment (OpenGL default) for upload performance.
   // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
   unsigned upload_image_stride =
@@ -285,6 +294,22 @@
   context_->unmapTexSubImage2DCHROMIUM(pixel_dest);
 }
 
+void TextureUploader::UploadWithTexImageETC1(const uint8* image,
+                                             gfx::Size size) {
+  TRACE_EVENT0("cc", "TextureUploader::UploadWithTexImageETC1");
+  DCHECK_EQ(0, size.width() % 4);
+  DCHECK_EQ(0, size.height() % 4);
+
+  context_->compressedTexImage2D(GL_TEXTURE_2D,
+                                 0,
+                                 GLInternalFormat(ETC1),
+                                 size.width(),
+                                 size.height(),
+                                 0,
+                                 Resource::MemorySizeBytes(size, ETC1),
+                                 image);
+}
+
 void TextureUploader::ProcessQueries() {
   while (!pending_queries_.empty()) {
     if (pending_queries_.front()->IsPending())
diff --git a/cc/scheduler/texture_uploader.h b/cc/scheduler/texture_uploader.h
index a131ba0..5b1b1d8 100644
--- a/cc/scheduler/texture_uploader.h
+++ b/cc/scheduler/texture_uploader.h
@@ -103,6 +103,7 @@
                                 gfx::Rect source_rect,
                                 gfx::Vector2d dest_offset,
                                 ResourceFormat format);
+  void UploadWithTexImageETC1(const uint8* image, gfx::Size size);
 
   WebKit::WebGraphicsContext3D* context_;
   ScopedPtrDeque<Query> pending_queries_;
diff --git a/cc/test/data/background_filter_blur_off_axis.png b/cc/test/data/background_filter_blur_off_axis.png
index 59488a6..b5777f4 100644
--- a/cc/test/data/background_filter_blur_off_axis.png
+++ b/cc/test/data/background_filter_blur_off_axis.png
Binary files differ
diff --git a/cc/test/data/touch_region_heavy.json b/cc/test/data/touch_region_heavy.json
new file mode 100644
index 0000000..26d618e
--- /dev/null
+++ b/cc/test/data/touch_region_heavy.json
@@ -0,0 +1,515 @@
+{
+   "Bounds": [ 0, 0 ],
+   "Children": [ {
+      "Bounds": [ 384, 640 ],
+      "Children": [ {
+         "Bounds": [ 384, 1681 ],
+         "Children": [ {
+            "Bounds": [ 384, 1681 ],
+            "Children": [ {
+               "Bounds": [ 384, 1681 ],
+               "Children": [ {
+                  "Bounds": [ 298, 114 ],
+                  "Children": [ {
+                     "Bounds": [ 12979, 130 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -10288.0, 118.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ -9999.0, -1.0 ],
+                     "TouchRegion": [ -9999, -1, 11499, 1, -9999, 0, 12979, 126, -9999, 126, 11499, 3 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 11.0, 119.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 11.0, 120.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 0.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 0.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 0.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 0.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 300, 114 ],
+                  "Children": [ {
+                     "Bounds": [ 300, 114 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 119.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 0.0, 0.0 ],
+                     "TouchRegion": [ 0, -1, 300, 115, 1, 114, 298, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 119.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 10.0, 120.0 ]
+               }, {
+                  "Bounds": [ 300, 114 ],
+                  "Children": [ {
+                     "Bounds": [ 18, 36 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 154.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 0.0, 35.0 ],
+                     "TouchRegion": [ -9999, -1, 10017, 36 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 119.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 10.0, 120.0 ]
+               }, {
+                  "Bounds": [ 300, 114 ],
+                  "Children": [ {
+                     "Bounds": [ 300, 36 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 154.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 0.0, 35.0 ],
+                     "TouchRegion": [ -9999, -1, 10017, 36 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, 119.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 10.0, 120.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 292.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 292.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 452.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 320 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 452.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 287.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 288.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 658.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 658.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 818.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 818.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 978.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 978.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 1138.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 1138.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 1298.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 800 ],
+                  "Children": [ {
+                     "Bounds": [ 152, 152 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 164.0, 1298.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 4.0, 5.0 ],
+                     "TouchRegion": [ -1, 0, 152, 117, -9895, 117, 10046, 5, -9994, 122, 10145, 24, -9895, 146, 10046, 1, -1, 147, 152, 5, 5, 152, 140, 1 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 653.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 654.0 ]
+               }, {
+                  "Bounds": [ 320, 1498 ],
+                  "Children": [ {
+                     "Bounds": [ 104, 37 ],
+                     "Children": [  ],
+                     "ContentsOpaque": false,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 5.0, 256.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 5.0, 147.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 109.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 110.0 ]
+               }, {
+                  "Bounds": [ 320, 1498 ],
+                  "Children": [ {
+                     "Bounds": [ 1, 13 ],
+                     "Children": [  ],
+                     "ContentsOpaque": true,
+                     "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 108.0, 266.0, 0.0, 1.0 ],
+                     "DrawsContent": true,
+                     "LayerType": "cc::TiledLayerImpl",
+                     "Opacity": 1.0,
+                     "Position": [ 108.0, 157.0 ]
+                  } ],
+                  "ContentsOpaque": false,
+                  "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 109.0, 0.0, 1.0 ],
+                  "DrawsContent": false,
+                  "LayerType": "cc::TiledLayerImpl",
+                  "Opacity": 1.0,
+                  "Position": [ 0.0, 110.0 ]
+               } ],
+               "ContentsOpaque": true,
+               "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+               "DrawsContent": true,
+               "LayerType": "cc::TiledLayerImpl",
+               "Opacity": 1.0,
+               "Position": [ 0.0, 0.0 ],
+               "TouchRegion": [ -9993, 0, 326, 50, 0, 0, 320, 50, -9993, 50, 326, 6, -9990, 56, 320, 3, -9990, 59, 320, 1, 8, 59, 44, 1, -9990, 60, 320, 32, 8, 60, 44, 32, 247, 60, 65, 32, -9990, 92, 320, 1, 8, 92, 44, 1, -9990, 93, 320, 27, -9990, 120, 320, 48, 10, 120, 300, 48, -9990, 168, 320, 42, -262, 168, 262, 42, 10, 168, 300, 42, -9990, 210, 320, 2, 10, 210, 300, 2, -9990, 212, 320, 22, -262, 212, 262, 22, 10, 212, 300, 22, -9990, 234, 320, 20, -262, 234, 262, 20, -9990, 254, 320, 2, -9990, 256, 320, 42, -262, 256, 262, 42, -9990, 298, 320, 2, -9990, 300, 320, 42, -262, 300, 262, 42, -9990, 342, 320, 180 ]
+            } ],
+            "ContentsOpaque": false,
+            "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+            "DrawsContent": false,
+            "LayerType": "cc::TiledLayerImpl",
+            "Opacity": 1.0,
+            "Position": [ 0.0, 0.0 ]
+         } ],
+         "ContentsOpaque": false,
+         "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+         "DrawsContent": false,
+         "LayerType": "cc::TiledLayerImpl",
+         "Opacity": 1.0,
+         "Position": [ 0.0, 0.0 ],
+         "Scrollable": true
+      } ],
+      "ContentsOpaque": false,
+      "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+      "DrawsContent": false,
+      "LayerType": "cc::TiledLayerImpl",
+      "Opacity": 1.0,
+      "Position": [ 0.0, 0.0 ]
+   }, {
+      "Bounds": [ 10, 640 ],
+      "Children": [ {
+         "Bounds": [ 10, 640 ],
+         "Children": [  ],
+         "ContentsOpaque": false,
+         "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 374.0, 0.0, 0.0, 1.0 ],
+         "DrawsContent": true,
+         "LayerType": "cc::PaintedScrollbarLayerImpl",
+         "Opacity": 1.0,
+         "Position": [ 0.0, 0.0 ]
+      } ],
+      "ContentsOpaque": false,
+      "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 374.0, 0.0, 0.0, 1.0 ],
+      "DrawsContent": false,
+      "LayerType": "cc::TiledLayerImpl",
+      "Opacity": 1.0,
+      "Position": [ 374.0, 0.0 ]
+   } ],
+   "ContentsOpaque": false,
+   "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+   "DrawsContent": false,
+   "LayerType": "cc::TiledLayerImpl",
+   "Opacity": 1.0,
+   "Position": [ 0.0, 0.0 ]
+}
+
diff --git a/cc/test/data/touch_region_light.json b/cc/test/data/touch_region_light.json
new file mode 100644
index 0000000..8b737b5
--- /dev/null
+++ b/cc/test/data/touch_region_light.json
@@ -0,0 +1,67 @@
+{
+   "Bounds": [ 0, 0 ],
+   "Children": [ {
+      "Bounds": [ 384, 640 ],
+      "Children": [ {
+         "Bounds": [ 384, 732 ],
+         "Children": [ {
+            "Bounds": [ 384, 732 ],
+            "Children": [ {
+               "Bounds": [ 384, 732 ],
+               "Children": [  ],
+               "ContentsOpaque": true,
+               "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+               "DrawsContent": true,
+               "LayerType": "cc::TiledLayerImpl",
+               "Opacity": 1.0,
+               "Position": [ 0.0, 0.0 ],
+               "TouchRegion": [ 0, 0, 384, 732 ]
+            } ],
+            "ContentsOpaque": false,
+            "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+            "DrawsContent": false,
+            "LayerType": "cc::TiledLayerImpl",
+            "Opacity": 1.0,
+            "Position": [ 0.0, 0.0 ]
+         } ],
+         "ContentsOpaque": false,
+         "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0, -1.0, 0.0, 1.0 ],
+         "DrawsContent": false,
+         "LayerType": "cc::TiledLayerImpl",
+         "Opacity": 1.0,
+         "Position": [ 0.0, 0.0 ],
+         "Scrollable": true
+      } ],
+      "ContentsOpaque": false,
+      "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+      "DrawsContent": false,
+      "LayerType": "cc::TiledLayerImpl",
+      "Opacity": 1.0,
+      "Position": [ 0.0, 0.0 ]
+   }, {
+      "Bounds": [ 10, 640 ],
+      "Children": [ {
+         "Bounds": [ 10, 640 ],
+         "Children": [  ],
+         "ContentsOpaque": false,
+         "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 374.0, 0.0, 0.0, 1.0 ],
+         "DrawsContent": true,
+         "LayerType": "cc::PaintedScrollbarLayerImpl",
+         "Opacity": 1.0,
+         "Position": [ 0.0, 0.0 ]
+      } ],
+      "ContentsOpaque": false,
+      "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 374.0, 0.0, 0.0, 1.0 ],
+      "DrawsContent": false,
+      "LayerType": "cc::TiledLayerImpl",
+      "Opacity": 1.0,
+      "Position": [ 374.0, 0.0 ]
+   } ],
+   "ContentsOpaque": false,
+   "DrawTransform": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+   "DrawsContent": false,
+   "LayerType": "cc::TiledLayerImpl",
+   "Opacity": 1.0,
+   "Position": [ 0.0, 0.0 ]
+}
+
diff --git a/cc/test/fake_layer_tree_host.h b/cc/test/fake_layer_tree_host.h
index 074355d..3acfdd2 100644
--- a/cc/test/fake_layer_tree_host.h
+++ b/cc/test/fake_layer_tree_host.h
@@ -46,7 +46,7 @@
  private:
   FakeLayerTreeHost(LayerTreeHostClient* client,
                     const LayerTreeSettings& settings)
-      : LayerTreeHost(client, settings),
+      : LayerTreeHost(client, NULL, settings),
         host_impl_(settings, &proxy_),
         needs_commit_(false) {}
 
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 0a8470a..a1e1708 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -24,8 +24,8 @@
   explicit FakeLayerTreeHostClient(RendererOptions options);
   virtual ~FakeLayerTreeHostClient();
 
-  virtual void WillBeginFrame() OVERRIDE {}
-  virtual void DidBeginFrame() OVERRIDE {}
+  virtual void WillBeginMainFrame() OVERRIDE {}
+  virtual void DidBeginMainFrame() OVERRIDE {}
   virtual void Animate(double frame_begin_time) OVERRIDE {}
   virtual void Layout() OVERRIDE {}
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index c1a7326..258617b 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -11,18 +11,19 @@
     : LayerTreeHostImpl(LayerTreeSettings(),
                         &client_,
                         proxy,
-                        &stats_instrumentation_) {
+                        &stats_instrumentation_,
+                        NULL) {
   // Explicitly clear all debug settings.
   SetDebugState(LayerTreeDebugState());
 }
 
-FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(
-    const LayerTreeSettings& settings,
-    Proxy* proxy)
+FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
+                                             Proxy* proxy)
     : LayerTreeHostImpl(settings,
                         &client_,
                         proxy,
-                        &stats_instrumentation_) {
+                        &stats_instrumentation_,
+                        NULL) {
   // Explicitly clear all debug settings.
   SetDebugState(LayerTreeDebugState());
 }
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index b0e3a15..708bbcf 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -15,7 +15,7 @@
   // LayerTreeHostImplClient implementation.
   virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {}
   virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
-  virtual void BeginFrameOnImplThread(const BeginFrameArgs& args)
+  virtual void BeginImplFrame(const BeginFrameArgs& args)
       OVERRIDE {}
   virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE {}
   virtual void NotifyReadyToActivate() OVERRIDE {}
@@ -30,7 +30,6 @@
   virtual bool ReduceContentsTextureMemoryOnImplThread(
       size_t limit_bytes,
       int priority_cutoff) OVERRIDE;
-  virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {}
   virtual void SendManagedMemoryStats() OVERRIDE {}
   virtual bool IsInsideDraw() OVERRIDE;
   virtual void RenewTreePriority() OVERRIDE {}
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index ae5bd22..a2d67f7 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -19,7 +19,7 @@
     : OutputSurface(context_provider),
       client_(NULL),
       num_sent_frames_(0),
-      needs_begin_frame_(false),
+      needs_begin_impl_frame_(false),
       forced_draw_to_software_device_(false),
       has_external_stencil_test_(false),
       fake_weak_ptr_factory_(this) {
@@ -84,22 +84,22 @@
   }
 }
 
-void FakeOutputSurface::SetNeedsBeginFrame(bool enable) {
-  needs_begin_frame_ = enable;
-  OutputSurface::SetNeedsBeginFrame(enable);
+void FakeOutputSurface::SetNeedsBeginImplFrame(bool enable) {
+  needs_begin_impl_frame_ = enable;
+  OutputSurface::SetNeedsBeginImplFrame(enable);
 
-  // If there is not BeginFrame emulation from the FrameRateController,
-  // then we just post a BeginFrame to emulate it as part of the test.
+  // If there is not BeginImplFrame emulation from the FrameRateController,
+  // then we just post a BeginImplFrame to emulate it as part of the test.
   if (enable && !frame_rate_controller_) {
     base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE, base::Bind(&FakeOutputSurface::OnBeginFrame,
+        FROM_HERE, base::Bind(&FakeOutputSurface::OnBeginImplFrame,
                               fake_weak_ptr_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(16));
   }
 }
 
-void FakeOutputSurface::OnBeginFrame() {
-  OutputSurface::BeginFrame(BeginFrameArgs::CreateForTesting());
+void FakeOutputSurface::OnBeginImplFrame() {
+  OutputSurface::BeginImplFrame(BeginFrameArgs::CreateForTesting());
 }
 
 
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index a93b4f3..0540f13 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -94,9 +94,9 @@
 
   virtual void SwapBuffers(CompositorFrame* frame) OVERRIDE;
 
-  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
-  bool needs_begin_frame() const {
-    return needs_begin_frame_;
+  virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE;
+  bool needs_begin_impl_frame() const {
+    return needs_begin_impl_frame_;
   }
 
   void set_forced_draw_to_software_device(bool forced) {
@@ -140,12 +140,12 @@
       scoped_ptr<SoftwareOutputDevice> software_device,
       bool delegated_rendering);
 
-  void OnBeginFrame();
+  void OnBeginImplFrame();
 
   OutputSurfaceClient* client_;
   CompositorFrame last_sent_frame_;
   size_t num_sent_frames_;
-  bool needs_begin_frame_;
+  bool needs_begin_impl_frame_;
   bool forced_draw_to_software_device_;
   bool has_external_stencil_test_;
   TransferableResourceArray resources_held_by_parent_;
diff --git a/cc/test/fake_output_surface_client.cc b/cc/test/fake_output_surface_client.cc
index 2ce6cf0..8417974 100644
--- a/cc/test/fake_output_surface_client.cc
+++ b/cc/test/fake_output_surface_client.cc
@@ -12,8 +12,8 @@
   return deferred_initialize_result_;
 }
 
-void FakeOutputSurfaceClient::BeginFrame(const BeginFrameArgs& args) {
-  begin_frame_count_++;
+void FakeOutputSurfaceClient::BeginImplFrame(const BeginFrameArgs& args) {
+  begin_impl_frame_count_++;
 }
 
 void FakeOutputSurfaceClient::DidLoseOutputSurface() {
diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h
index 08511ad..bf127d1 100644
--- a/cc/test/fake_output_surface_client.h
+++ b/cc/test/fake_output_surface_client.h
@@ -13,7 +13,7 @@
 class FakeOutputSurfaceClient : public OutputSurfaceClient {
  public:
   FakeOutputSurfaceClient()
-      : begin_frame_count_(0),
+      : begin_impl_frame_count_(0),
         deferred_initialize_result_(true),
         deferred_initialize_called_(false),
         did_lose_output_surface_called_(false),
@@ -24,7 +24,7 @@
       scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE;
   virtual void ReleaseGL() OVERRIDE {}
   virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {}
-  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
   virtual void OnSwapBuffersComplete() OVERRIDE {}
   virtual void ReclaimResources(const CompositorFrameAck* ack) OVERRIDE {}
   virtual void DidLoseOutputSurface() OVERRIDE;
@@ -37,8 +37,8 @@
   virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE;
   virtual void SetTreeActivationCallback(const base::Closure&) OVERRIDE {}
 
-  int begin_frame_count() {
-    return begin_frame_count_;
+  int begin_impl_frame_count() {
+    return begin_impl_frame_count_;
   }
 
   void set_deferred_initialize_result(bool result) {
@@ -60,7 +60,7 @@
   }
 
  private:
-  int begin_frame_count_;
+  int begin_impl_frame_count_;
   bool deferred_initialize_result_;
   bool deferred_initialize_called_;
   bool did_lose_output_surface_called_;
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 2eeaeef..759ceeb 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -47,6 +47,7 @@
 
   PictureLayerImpl* twin_layer() { return twin_layer_; }
   PictureLayerTilingSet* tilings() { return tilings_.get(); }
+  PicturePileImpl* pile() { return pile_.get(); }
   size_t append_quads_count() { return append_quads_count_; }
 
   const Region& invalidation() const { return invalidation_; }
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 03084ed..989c4f9 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -65,19 +65,12 @@
   scoped_refptr<Picture> picture(Picture::Create(bounds));
   picture->Record(&client_, tile_grid_info_);
   picture->GatherPixelRefs(tile_grid_info_);
-  picture_list_map_[std::pair<int, int>(x, y)].push_back(picture);
+  picture_map_[std::pair<int, int>(x, y)].picture = picture;
   EXPECT_TRUE(HasRecordingAt(x, y));
 
   UpdateRecordedRegion();
 }
 
-void FakePicturePileImpl::AddPictureToRecording(
-    int x,
-    int y,
-    scoped_refptr<Picture> picture) {
-  picture_list_map_[std::pair<int, int>(x, y)].push_back(picture);
-}
-
 void FakePicturePileImpl::RemoveRecordingAt(int x, int y) {
   EXPECT_GE(x, 0);
   EXPECT_GE(y, 0);
@@ -86,7 +79,7 @@
 
   if (!HasRecordingAt(x, y))
     return;
-  picture_list_map_.erase(std::pair<int, int>(x, y));
+  picture_map_.erase(std::pair<int, int>(x, y));
   EXPECT_FALSE(HasRecordingAt(x, y));
 
   UpdateRecordedRegion();
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index 770dffe..935e4a2 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -29,11 +29,6 @@
   void RemoveRecordingAt(int x, int y);
   void RerecordPile();
 
-  void AddPictureToRecording(
-      int x,
-      int y,
-      scoped_refptr<Picture> picture);
-
   void add_draw_rect(const gfx::RectF& rect) {
     client_.add_draw_rect(rect, default_paint_);
   }
diff --git a/cc/test/fake_proxy.cc b/cc/test/fake_proxy.cc
index 3fe12c8..90c5b1c 100644
--- a/cc/test/fake_proxy.cc
+++ b/cc/test/fake_proxy.cc
@@ -29,6 +29,8 @@
   return capabilities_;
 }
 
+bool FakeProxy::BeginMainFrameRequested() const { return false; }
+
 bool FakeProxy::CommitRequested() const { return false; }
 
 size_t FakeProxy::MaxPartialTextureUpdates() const {
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index 3127cb4..bcde11e 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -36,6 +36,7 @@
   virtual void NotifyInputThrottledUntilCommit() OVERRIDE {}
   virtual void SetDeferCommits(bool defer_commits) OVERRIDE {}
   virtual void MainThreadHasStoppedFlinging() OVERRIDE {}
+  virtual bool BeginMainFrameRequested() const OVERRIDE;
   virtual bool CommitRequested() const OVERRIDE;
   virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE {}
   virtual void Stop() OVERRIDE {}
diff --git a/cc/test/fake_ui_resource_layer_tree_host_impl.cc b/cc/test/fake_ui_resource_layer_tree_host_impl.cc
index ec087f2..c1d3e75 100644
--- a/cc/test/fake_ui_resource_layer_tree_host_impl.cc
+++ b/cc/test/fake_ui_resource_layer_tree_host_impl.cc
@@ -18,7 +18,12 @@
     const UIResourceBitmap& bitmap) {
   if (ResourceIdForUIResource(uid))
     DeleteUIResource(uid);
-  fake_ui_resource_map_[uid] = fake_next_resource_id_;
+
+  UIResourceData data;
+  data.resource_id = fake_next_resource_id_++;
+  data.size = bitmap.GetSize();
+  data.opaque = bitmap.GetOpaque();
+  fake_ui_resource_map_[uid] = data;
 }
 
 void FakeUIResourceLayerTreeHostImpl::DeleteUIResource(UIResourceId uid) {
@@ -32,8 +37,15 @@
         UIResourceId uid) const {
   UIResourceMap::const_iterator iter = fake_ui_resource_map_.find(uid);
   if (iter != fake_ui_resource_map_.end())
-    return iter->second;
+    return iter->second.resource_id;
   return 0;
 }
 
+bool FakeUIResourceLayerTreeHostImpl::IsUIResourceOpaque(UIResourceId uid)
+    const {
+  UIResourceMap::const_iterator iter = fake_ui_resource_map_.find(uid);
+  DCHECK(iter != fake_ui_resource_map_.end());
+  return iter->second.opaque;
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_ui_resource_layer_tree_host_impl.h b/cc/test/fake_ui_resource_layer_tree_host_impl.h
index eceece9..7e461df 100644
--- a/cc/test/fake_ui_resource_layer_tree_host_impl.h
+++ b/cc/test/fake_ui_resource_layer_tree_host_impl.h
@@ -23,9 +23,11 @@
   virtual ResourceProvider::ResourceId ResourceIdForUIResource(
       UIResourceId uid) const OVERRIDE;
 
+  virtual bool IsUIResourceOpaque(UIResourceId uid) const OVERRIDE;
+
  private:
   ResourceProvider::ResourceId fake_next_resource_id_;
-  typedef base::hash_map<UIResourceId, ResourceProvider::ResourceId>
+  typedef base::hash_map<UIResourceId, LayerTreeHostImpl::UIResourceData>
       UIResourceMap;
   UIResourceMap fake_ui_resource_map_;
 };
diff --git a/cc/test/layer_tree_json_parser.cc b/cc/test/layer_tree_json_parser.cc
index af24571..9a1b198 100644
--- a/cc/test/layer_tree_json_parser.cc
+++ b/cc/test/layer_tree_json_parser.cc
@@ -53,8 +53,8 @@
     ListValue* bounds;
     success &= dict->GetList("ImageBounds", &bounds);
     double image_width, image_height;
-    success &= bounds->GetDouble(0, &image_height);
-    success &= bounds->GetDouble(1, &image_width);
+    success &= bounds->GetDouble(0, &image_width);
+    success &= bounds->GetDouble(1, &image_height);
 
     success &= dict->GetList("Border", &list);
     int border_x, border_y, border_width, border_height;
@@ -81,7 +81,7 @@
 
     new_layer = nine_patch_layer;
   } else if (layer_type == "TextureLayer") {
-    new_layer = TextureLayer::Create(NULL);
+    new_layer = TextureLayer::CreateForMailbox(NULL);
   } else if (layer_type == "PictureLayer") {
     new_layer = PictureLayer::Create(content_client);
   } else {  // Type "Layer" or "unknown"
@@ -104,6 +104,24 @@
   if (dict->GetBoolean("Scrollable", &scrollable))
     new_layer->SetScrollable(scrollable);
 
+  bool wheel_handler;
+  if (dict->GetBoolean("WheelHandler", &wheel_handler))
+    new_layer->SetHaveWheelEventHandlers(wheel_handler);
+
+  if (dict->HasKey("TouchRegion")) {
+    success &= dict->GetList("TouchRegion", &list);
+    cc::Region touch_region;
+    for (size_t i = 0; i < list->GetSize(); ) {
+      int rect_x, rect_y, rect_width, rect_height;
+      success &= list->GetInteger(i++, &rect_x);
+      success &= list->GetInteger(i++, &rect_y);
+      success &= list->GetInteger(i++, &rect_width);
+      success &= list->GetInteger(i++, &rect_height);
+      touch_region.Union(gfx::Rect(rect_x, rect_y, rect_width, rect_height));
+    }
+    new_layer->SetTouchEventHandlerRegion(touch_region);
+  }
+
   success &= dict->GetList("DrawTransform", &list);
   double transform[16];
   for (int i = 0; i < 16; ++i)
diff --git a/cc/test/layer_tree_json_parser_unittest.cc b/cc/test/layer_tree_json_parser_unittest.cc
new file mode 100644
index 0000000..4261a71
--- /dev/null
+++ b/cc/test/layer_tree_json_parser_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright 2013 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 "cc/test/layer_tree_json_parser.h"
+
+#include "cc/layers/layer.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/geometry_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+namespace {
+
+bool LayerTreesMatch(LayerImpl* const layer_impl,
+                     Layer* const layer) {
+#define RETURN_IF_EXPECTATION_FAILS(exp) \
+  do { \
+    exp; \
+    if (testing::UnitTest::GetInstance()->current_test_info()-> \
+            result()->Failed()) \
+      return false; \
+  } while (0)
+
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->children().size(),
+                                        layer->children().size()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_SIZE_EQ(layer_impl->bounds(),
+                                             layer->bounds()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_POINT_EQ(layer_impl->position(),
+                                              layer->position()));
+  RETURN_IF_EXPECTATION_FAILS(
+      EXPECT_TRANSFORMATION_MATRIX_EQ(layer_impl->draw_transform(),
+                                      layer->draw_transform()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->contents_opaque(),
+                                        layer->contents_opaque()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->scrollable(),
+                                        layer->scrollable()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_FLOAT_EQ(layer_impl->opacity(),
+                                              layer->opacity()));
+  RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->have_wheel_event_handlers(),
+                                        layer->have_wheel_event_handlers()));
+  RETURN_IF_EXPECTATION_FAILS(
+      EXPECT_EQ(layer_impl->touch_event_handler_region(),
+                layer->touch_event_handler_region()));
+
+  for (size_t i = 0; i < layer_impl->children().size(); ++i) {
+    RETURN_IF_EXPECTATION_FAILS(
+        EXPECT_TRUE(LayerTreesMatch(layer_impl->children()[i],
+                                    layer->children()[i])));
+  }
+
+  return true;
+#undef RETURN_IF_EXPECTATION_FAILS
+}
+
+}  // namespace
+
+class LayerTreeJsonParserSanityCheck : public testing::Test {
+};
+
+TEST_F(LayerTreeJsonParserSanityCheck, Basic) {
+  FakeImplProxy proxy;
+  FakeLayerTreeHostImpl host_impl(&proxy);
+  LayerTreeImpl* tree = host_impl.active_tree();
+
+  scoped_ptr<LayerImpl> root_impl(LayerImpl::Create(tree, 1));
+  scoped_ptr<LayerImpl> parent(LayerImpl::Create(tree, 2));
+  scoped_ptr<LayerImpl> child(LayerImpl::Create(tree, 3));
+
+  root_impl->SetBounds(gfx::Size(100, 100));
+  parent->SetBounds(gfx::Size(50, 50));
+  child->SetBounds(gfx::Size(40, 40));
+
+  parent->SetPosition(gfx::Point(25, 25));
+
+  child->SetHaveWheelEventHandlers(true);
+
+  parent->AddChild(child.Pass());
+  root_impl->AddChild(parent.Pass());
+  tree->SetRootLayer(root_impl.Pass());
+
+  std::string json = host_impl.LayerTreeAsJson();
+  scoped_refptr<Layer> root = ParseTreeFromJson(json, NULL);
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(LayerTreesMatch(host_impl.RootLayer(), root.get()));
+}
+
+TEST_F(LayerTreeJsonParserSanityCheck, EventHandlerRegions) {
+  FakeImplProxy proxy;
+  FakeLayerTreeHostImpl host_impl(&proxy);
+  LayerTreeImpl* tree = host_impl.active_tree();
+
+  scoped_ptr<LayerImpl> root_impl(LayerImpl::Create(tree, 1));
+  scoped_ptr<LayerImpl> touch_layer(LayerImpl::Create(tree, 2));
+
+  root_impl->SetBounds(gfx::Size(100, 100));
+  touch_layer->SetBounds(gfx::Size(50, 50));
+
+  cc::Region touch_region;
+  touch_region.Union(gfx::Rect(10, 10, 20, 30));
+  touch_region.Union(gfx::Rect(40, 10, 20, 20));
+  touch_layer->SetTouchEventHandlerRegion(touch_region);
+
+  root_impl->AddChild(touch_layer.Pass());
+  tree->SetRootLayer(root_impl.Pass());
+
+  std::string json = host_impl.LayerTreeAsJson();
+  scoped_refptr<Layer> root = ParseTreeFromJson(json, NULL);
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(LayerTreesMatch(host_impl.RootLayer(), root.get()));
+}
+
+}  // namespace cc
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 70e6223..d0a5c59 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -4,7 +4,9 @@
 
 #include "cc/test/layer_tree_pixel_test.h"
 
+#include "base/command_line.h"
 #include "base/path_service.h"
+#include "cc/base/switches.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/texture_layer.h"
 #include "cc/output/copy_output_request.h"
@@ -96,8 +98,9 @@
   EXPECT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
   base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
 
-  // To rebaseline:
-  // EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
+  CommandLine* cmd = CommandLine::ForCurrentProcess();
+  if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
+    EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
 
   EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
                              ref_file_path,
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index da0ed55..9ca0bbd 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -23,6 +23,7 @@
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/size_conversions.h"
 
 namespace cc {
@@ -68,14 +69,15 @@
       : LayerTreeHostImpl(settings,
                           host_impl_client,
                           proxy,
-                          stats_instrumentation),
+                          stats_instrumentation,
+                          NULL),
         test_hooks_(test_hooks),
         block_notify_ready_to_activate_for_testing_(false),
         notify_ready_to_activate_was_blocked_(false) {}
 
-  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {
     test_hooks_->WillBeginImplFrameOnThread(this, args);
-    LayerTreeHostImpl::BeginFrame(args);
+    LayerTreeHostImpl::BeginImplFrame(args);
     test_hooks_->DidBeginImplFrameOnThread(this, args);
   }
 
@@ -233,7 +235,7 @@
   LayerTreeHostForTesting(TestHooks* test_hooks,
                           LayerTreeHostClient* client,
                           const LayerTreeSettings& settings)
-      : LayerTreeHost(client, settings),
+      : LayerTreeHost(client, NULL, settings),
         test_hooks_(test_hooks),
         test_started_(false) {}
 
@@ -250,9 +252,13 @@
   }
   virtual ~LayerTreeHostClientForTesting() {}
 
-  virtual void WillBeginFrame() OVERRIDE { test_hooks_->WillBeginFrame(); }
+  virtual void WillBeginMainFrame() OVERRIDE {
+    test_hooks_->WillBeginMainFrame();
+  }
 
-  virtual void DidBeginFrame() OVERRIDE { test_hooks_->DidBeginFrame(); }
+  virtual void DidBeginMainFrame() OVERRIDE {
+    test_hooks_->DidBeginMainFrame();
+  }
 
   virtual void Animate(double monotonic_time) OVERRIDE {
     test_hooks_->Animate(base::TimeTicks::FromInternalValue(
@@ -586,7 +592,7 @@
   }
 
   schedule_when_set_visible_true_ = false;
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   layer_tree_host_->Composite(now);
 }
 
@@ -602,7 +608,7 @@
 
   delegating_renderer_ = delegating_renderer;
 
-  // Spend less time waiting for BeginFrame because the output is
+  // Spend less time waiting for BeginImplFrame because the output is
   // mocked out.
   settings_.refresh_rate = 200.0;
   if (impl_side_painting) {
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 4fb5525..aa55837 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -57,8 +57,8 @@
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
                                    float scale) {}
   virtual void Animate(base::TimeTicks monotonic_time) {}
-  virtual void WillBeginFrame() {}
-  virtual void DidBeginFrame() {}
+  virtual void WillBeginMainFrame() {}
+  virtual void DidBeginMainFrame() {}
   virtual void Layout() {}
   virtual void DidInitializeOutputSurface(bool succeeded) {}
   virtual void DidFailToInitializeOutputSurface() {}
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 05688b1..12b729b 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -4,8 +4,10 @@
 
 #include "cc/test/pixel_test.h"
 
+#include "base/command_line.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "cc/base/switches.h"
 #include "cc/output/compositor_frame_metadata.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
@@ -49,7 +51,7 @@
   }
   virtual void ReleaseGL() OVERRIDE {}
   virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {}
-  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {}
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {}
   virtual void OnSwapBuffersComplete() OVERRIDE {}
   virtual void ReclaimResources(const CompositorFrameAck* ack) OVERRIDE {}
   virtual void DidLoseOutputSurface() OVERRIDE {}
@@ -147,8 +149,9 @@
   if (!result_bitmap_)
     return false;
 
-  // To rebaseline:
-  // return WritePNGFile(*result_bitmap_, test_data_dir.Append(ref_file), true);
+  CommandLine* cmd = CommandLine::ForCurrentProcess();
+  if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
+    return WritePNGFile(*result_bitmap_, test_data_dir.Append(ref_file), true);
 
   return MatchesPNGFile(*result_bitmap_,
                         test_data_dir.Append(ref_file),
@@ -165,7 +168,7 @@
   output_surface_->BindToClient(fake_client_.get());
 
   resource_provider_ =
-      ResourceProvider::Create(output_surface_.get(), 0, false);
+      ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
 
   texture_mailbox_deleter_ = make_scoped_ptr(new TextureMailboxDeleter);
 
@@ -208,12 +211,12 @@
   output_surface_.reset(new PixelTestOutputSurface(device.Pass()));
   output_surface_->BindToClient(fake_client_.get());
   resource_provider_ =
-      ResourceProvider::Create(output_surface_.get(), 0, false);
+      ResourceProvider::Create(output_surface_.get(), NULL, 0, false);
   renderer_ = SoftwareRenderer::Create(fake_client_.get(),
                                        &settings_,
                                        output_surface_.get(),
                                        resource_provider_.get())
-                  .PassAs<DirectRenderer>();
+      .PassAs<DirectRenderer>();
 }
 
 }  // namespace cc
diff --git a/cc/test/run_all_perftests.cc b/cc/test/run_all_perftests.cc
new file mode 100644
index 0000000..abe8549
--- /dev/null
+++ b/cc/test/run_all_perftests.cc
@@ -0,0 +1,16 @@
+// Copyright 2013 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 "cc/test/cc_test_suite.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleMock(&argc, argv);
+  cc::CCTestSuite test_suite(argc, argv);
+
+  // Always run the perf tests serially, to avoid distorting
+  // perf measurements with randomness resulting from running
+  // in parallel.
+  return test_suite.Run();
+}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 2d3c608..d93e3d5 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -95,10 +95,11 @@
 
 scoped_ptr<LayerTreeHost> LayerTreeHost::Create(
     LayerTreeHostClient* client,
+    SharedBitmapManager* manager,
     const LayerTreeSettings& settings,
     scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
-  scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(client,
-                                                              settings));
+  scoped_ptr<LayerTreeHost> layer_tree_host(
+      new LayerTreeHost(client, manager, settings));
   if (!layer_tree_host->Initialize(impl_task_runner))
     return scoped_ptr<LayerTreeHost>();
   return layer_tree_host.Pass();
@@ -107,6 +108,7 @@
 static int s_next_tree_id = 1;
 
 LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client,
+                             SharedBitmapManager* manager,
                              const LayerTreeSettings& settings)
     : next_ui_resource_id_(1),
       animating_(false),
@@ -134,7 +136,8 @@
       in_paint_layer_contents_(false),
       total_frames_used_for_lcd_text_metrics_(0),
       tree_id_(s_next_tree_id++),
-      next_commit_forces_redraw_(false) {
+      next_commit_forces_redraw_(false),
+      shared_bitmap_manager_(manager) {
   if (settings_.accelerated_animation_enabled)
     animation_registrar_ = AnimationRegistrar::Create();
   s_num_layer_tree_instances++;
@@ -258,8 +261,8 @@
   proxy_->AcquireLayerTextures();
 }
 
-void LayerTreeHost::DidBeginFrame() {
-  client_->DidBeginFrame();
+void LayerTreeHost::DidBeginMainFrame() {
+  client_->DidBeginMainFrame();
 }
 
 void LayerTreeHost::UpdateClientAnimations(base::TimeTicks frame_begin_time) {
@@ -310,7 +313,8 @@
     host_impl->set_max_memory_needed_bytes(
         contents_texture_manager_->MaxMemoryNeededBytes());
 
-    contents_texture_manager_->UpdateBackingsInDrawingImplTree();
+    contents_texture_manager_->UpdateBackingsState(
+        host_impl->resource_provider());
   }
 
   // In impl-side painting, synchronize to the pending tree so that it has
@@ -469,7 +473,9 @@
       LayerTreeHostImpl::Create(settings_,
                                 client,
                                 proxy_.get(),
-                                rendering_stats_instrumentation_.get());
+                                rendering_stats_instrumentation_.get(),
+                                shared_bitmap_manager_);
+  shared_bitmap_manager_ = NULL;
   if (settings_.calculate_top_controls_position &&
       host_impl->top_controls_manager()) {
     top_controls_manager_weak_ptr_ =
@@ -567,6 +573,11 @@
   return proxy_->CommitRequested();
 }
 
+bool LayerTreeHost::BeginMainFrameRequested() const {
+  return proxy_->BeginMainFrameRequested();
+}
+
+
 void LayerTreeHost::SetNextCommitWaitsForActivation() {
   proxy_->SetNextCommitWaitsForActivation();
 }
@@ -688,8 +699,9 @@
     bitmap_copy.setImmutable();
   }
 
-  overhang_ui_resource_ = ScopedUIResource::Create(
-      this, UIResourceBitmap(bitmap_copy, UIResourceBitmap::REPEAT));
+  UIResourceBitmap overhang_bitmap(bitmap_copy);
+  overhang_bitmap.SetWrapMode(UIResourceBitmap::REPEAT);
+  overhang_ui_resource_ = ScopedUIResource::Create(this, overhang_bitmap);
 }
 
 void LayerTreeHost::SetVisible(bool visible) {
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index fa025b6..c79f3e5 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -67,6 +67,7 @@
 class RenderingStatsInstrumentation;
 class ResourceProvider;
 class ResourceUpdateQueue;
+class SharedBitmapManager;
 class TopControlsManager;
 struct RenderingStats;
 struct ScrollAndScaleSet;
@@ -123,8 +124,10 @@
 
 class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
  public:
+  // The SharedBitmapManager will be used on the compositor thread.
   static scoped_ptr<LayerTreeHost> Create(
       LayerTreeHostClient* client,
+      SharedBitmapManager* manager,
       const LayerTreeSettings& settings,
       scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
   virtual ~LayerTreeHost();
@@ -140,8 +143,8 @@
   }
 
   // LayerTreeHost interface to Proxy.
-  void WillBeginFrame() { client_->WillBeginFrame(); }
-  void DidBeginFrame();
+  void WillBeginMainFrame() { client_->WillBeginMainFrame(); }
+  void DidBeginMainFrame();
   void UpdateClientAnimations(base::TimeTicks monotonic_frame_begin_time);
   void AnimateLayers(base::TimeTicks monotonic_frame_begin_time);
   void DidStopFlinging();
@@ -212,6 +215,7 @@
   void SetNeedsRedraw();
   void SetNeedsRedrawRect(gfx::Rect damage_rect);
   bool CommitRequested() const;
+  bool BeginMainFrameRequested() const;
 
   void SetNextCommitWaitsForActivation();
 
@@ -223,6 +227,7 @@
   void SetRootLayer(scoped_refptr<Layer> root_layer);
   Layer* root_layer() { return root_layer_.get(); }
   const Layer* root_layer() const { return root_layer_.get(); }
+  const Layer* page_scale_layer() const { return page_scale_layer_.get(); }
   void RegisterViewportLayers(
       scoped_refptr<Layer> page_scale_layer,
       scoped_refptr<Layer> inner_viewport_scroll_layer,
@@ -324,7 +329,9 @@
                               const MicroBenchmark::DoneCallback& callback);
 
  protected:
-  LayerTreeHost(LayerTreeHostClient* client, const LayerTreeSettings& settings);
+  LayerTreeHost(LayerTreeHostClient* client,
+                SharedBitmapManager* manager,
+                const LayerTreeSettings& settings);
   bool Initialize(scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
   bool InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
   void SetOutputSurfaceLostForTesting(bool is_lost) {
@@ -465,6 +472,8 @@
   scoped_refptr<Layer> inner_viewport_scroll_layer_;
   scoped_refptr<Layer> outer_viewport_scroll_layer_;
 
+  SharedBitmapManager* shared_bitmap_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHost);
 };
 
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 648ee85..bde12da 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -19,10 +19,10 @@
 
 class LayerTreeHostClient {
  public:
-  virtual void WillBeginFrame() = 0;
+  virtual void WillBeginMainFrame() = 0;
   // Marks finishing compositing-related tasks on the main thread. In threaded
   // mode, this corresponds to DidCommit().
-  virtual void DidBeginFrame() = 0;
+  virtual void DidBeginMainFrame() = 0;
   virtual void Animate(double frame_begin_time) = 0;
   virtual void Layout() = 0;
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 3ccedb1..4095900 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -135,8 +135,13 @@
 
   gfx::Vector2dF translation;
   for (const LayerType* target = descendant_target; target != ancestor_target;
-       target = NextTargetSurface(target))
-    translation += target->render_surface()->draw_transform().To2dTranslation();
+       target = NextTargetSurface(target)) {
+    const gfx::Transform& trans = target->render_surface()->draw_transform();
+    // Ensure that this translation is truly 2d.
+    DCHECK(trans.IsIdentityOrTranslation());
+    DCHECK_EQ(0.f, trans.matrix().get(2, 3));
+    translation += trans.To2dTranslation();
+  }
 
   return translation;
 }
@@ -743,7 +748,8 @@
 
 gfx::Transform ComputeScrollCompensationForThisLayer(
     LayerImpl* scrolling_layer,
-    const gfx::Transform& parent_matrix) {
+    const gfx::Transform& parent_matrix,
+    gfx::Vector2dF scroll_delta) {
   // For every layer that has non-zero scroll_delta, we have to compute a
   // transform that can undo the scroll_delta translation. In particular, we
   // want this matrix to premultiply a fixed-position layer's parent_matrix, so
@@ -765,7 +771,6 @@
   //
 
   gfx::Transform scroll_compensation_for_this_layer = parent_matrix;  // Step 3
-  gfx::Vector2dF scroll_delta = GetEffectiveScrollDelta(scrolling_layer);
   scroll_compensation_for_this_layer.Translate(
       scroll_delta.x(),
       scroll_delta.y());  // Step 2
@@ -783,7 +788,8 @@
 gfx::Transform ComputeScrollCompensationMatrixForChildren(
     Layer* current_layer,
     const gfx::Transform& current_parent_matrix,
-    const gfx::Transform& current_scroll_compensation) {
+    const gfx::Transform& current_scroll_compensation,
+    gfx::Vector2dF scroll_delta) {
   // The main thread (i.e. Layer) does not need to worry about scroll
   // compensation.  So we can just return an identity matrix here.
   return gfx::Transform();
@@ -792,7 +798,8 @@
 gfx::Transform ComputeScrollCompensationMatrixForChildren(
     LayerImpl* layer,
     const gfx::Transform& parent_matrix,
-    const gfx::Transform& current_scroll_compensation_matrix) {
+    const gfx::Transform& current_scroll_compensation_matrix,
+    gfx::Vector2dF scroll_delta) {
   // "Total scroll compensation" is the transform needed to cancel out all
   // scroll_delta translations that occurred since the nearest container layer,
   // even if there are render_surfaces in-between.
@@ -827,7 +834,6 @@
   // Avoid the overheads (including stack allocation and matrix
   // initialization/copy) if we know that the scroll compensation doesn't need
   // to be reset or adjusted.
-  gfx::Vector2dF scroll_delta = GetEffectiveScrollDelta(layer);
   if (!current_layer_resets_scroll_compensation_for_descendants &&
       scroll_delta.IsZero() && !layer->render_surface())
     return current_scroll_compensation_matrix;
@@ -846,7 +852,7 @@
   if (!scroll_delta.IsZero()) {
     gfx::Transform scroll_compensation_for_this_layer =
         ComputeScrollCompensationForThisLayer(
-            layer, parent_matrix);
+            layer, parent_matrix, scroll_delta);
     next_scroll_compensation_matrix.PreconcatTransform(
         scroll_compensation_for_this_layer);
   }
@@ -1093,7 +1099,7 @@
   int max_texture_size;
   float device_scale_factor;
   float page_scale_factor;
-  LayerType* page_scale_application_layer;
+  const LayerType* page_scale_application_layer;
   bool can_adjust_raster_scales;
   bool can_render_to_separate_surface;
 };
@@ -1490,12 +1496,19 @@
     combined_transform.Translate(position.x(), position.y());
   }
 
+  gfx::Vector2dF effective_scroll_delta = GetEffectiveScrollDelta(layer);
   if (!animating_transform_to_target && layer->scrollable() &&
       combined_transform.IsScaleOrTranslation()) {
     // Align the scrollable layer's position to screen space pixels to avoid
     // blurriness.  To avoid side-effects, do this only if the transform is
     // simple.
+    gfx::Vector2dF previous_translation = combined_transform.To2dTranslation();
     RoundTranslationComponents(&combined_transform);
+    gfx::Vector2dF current_translation = combined_transform.To2dTranslation();
+
+    // This rounding changes the scroll delta, and so must be included
+    // in the scroll compensation matrix.
+    effective_scroll_delta -= current_translation - previous_translation;
   }
 
   // Apply adjustment from position constraints.
@@ -1871,7 +1884,8 @@
         ComputeScrollCompensationMatrixForChildren(
             layer,
             data_from_ancestor.parent_matrix,
-            data_from_ancestor.scroll_compensation_matrix);
+            data_from_ancestor.scroll_compensation_matrix,
+            effective_scroll_delta);
     data_for_children.fixed_container =
         layer->IsContainerForFixedPositionLayers() ?
             layer : data_from_ancestor.fixed_container;
@@ -2344,34 +2358,21 @@
 LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
     gfx::PointF screen_space_point,
     const LayerImplList& render_surface_layer_list) {
-  LayerImpl* found_layer = NULL;
+  // First find out which layer was hit from the saved list of visible layers
+  // in the most recent frame.
+  LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
+      screen_space_point,
+      render_surface_layer_list);
 
-  typedef LayerIterator<LayerImpl,
-                        LayerImplList,
-                        RenderSurfaceImpl,
-                        LayerIteratorActions::FrontToBack> LayerIteratorType;
-  LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
-
-  for (LayerIteratorType
-           it = LayerIteratorType::Begin(&render_surface_layer_list);
-       it != end;
-       ++it) {
-    // We don't want to consider render_surfaces for hit testing.
-    if (!it.represents_itself())
-      continue;
-
-    LayerImpl* current_layer = (*it);
-
-    if (!LayerHasTouchEventHandlersAt(screen_space_point, current_layer))
-      continue;
-
-    found_layer = current_layer;
-    break;
+  // Walk up the hierarchy and look for a layer with a touch event handler
+  // region that the given point hits.
+  // This walk may not be necessary anymore: http://crbug.com/310817
+  for (; layer_impl; layer_impl = layer_impl->parent()) {
+    if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point,
+                                                          layer_impl))
+      break;
   }
-
-  // This can potentially return NULL, which means the screen_space_point did
-  // not successfully hit test any layers, not even the root layer.
-  return found_layer;
+  return layer_impl;
 }
 
 bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt(
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index adabd13..7272448 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -36,7 +36,7 @@
                         const gfx::Transform& device_transform,
                         float device_scale_factor,
                         float page_scale_factor,
-                        LayerType* page_scale_application_layer,
+                        const LayerType* page_scale_application_layer,
                         int max_texture_size,
                         bool can_use_lcd_text,
                         bool can_render_to_separate_surface,
@@ -59,7 +59,7 @@
     const gfx::Transform& device_transform;
     float device_scale_factor;
     float page_scale_factor;
-    LayerType* page_scale_application_layer;
+    const LayerType* page_scale_application_layer;
     int max_texture_size;
     bool can_use_lcd_text;
     bool can_render_to_separate_surface;
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
new file mode 100644
index 0000000..d940709
--- /dev/null
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -0,0 +1,204 @@
+// Copyright 2013 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 "cc/trees/layer_tree_host_common.h"
+
+#include <sstream>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "cc/layers/layer.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_layer_tree_host_client.h"
+#include "cc/test/lap_timer.h"
+#include "cc/test/layer_tree_json_parser.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/test/paths.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class LayerTreeHostCommonPerfTest : public LayerTreeTest {
+ public:
+  LayerTreeHostCommonPerfTest()
+      : timer_(kWarmupRuns,
+               base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+               kTimeCheckInterval) {}
+
+  void ReadTestFile(const std::string& name) {
+    base::FilePath test_data_dir;
+    ASSERT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
+    base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
+    ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    gfx::Size viewport = gfx::Size(720, 1038);
+    layer_tree_host()->SetViewportSize(viewport);
+    scoped_refptr<Layer> root =
+        ParseTreeFromJson(json_, &content_layer_client_);
+    ASSERT_TRUE(root.get());
+    layer_tree_host()->SetRootLayer(root);
+  }
+
+  void SetTestName(const std::string& name) { test_name_ = name; }
+
+  virtual void AfterTest() OVERRIDE {
+    CHECK(!test_name_.empty()) << "Must SetTestName() before TearDown().";
+    perf_test::PrintResult("calc_draw_props_count",
+                           "",
+                           test_name_,
+                           timer_.NumLaps(),
+                           "count",
+                           true);
+    perf_test::PrintResult("calc_draw_props_time",
+                           "",
+                           test_name_,
+                           1000 * timer_.MsPerLap(),
+                           "us",
+                           true);
+  }
+
+ protected:
+  FakeContentLayerClient content_layer_client_;
+  LapTimer timer_;
+  std::string test_name_;
+  std::string json_;
+};
+
+class CalcDrawPropsMainTest : public LayerTreeHostCommonPerfTest {
+ public:
+  void RunCalcDrawProps() {
+    RunTest(false, false, false);
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    timer_.Reset();
+
+    do {
+      bool can_render_to_separate_surface = true;
+      int max_texture_size = 8096;
+      RenderSurfaceLayerList update_list;
+      LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
+          layer_tree_host()->root_layer(),
+          layer_tree_host()->device_viewport_size(),
+          gfx::Transform(),
+          layer_tree_host()->device_scale_factor(),
+          layer_tree_host()->page_scale_factor(),
+          layer_tree_host()->page_scale_layer(),
+          max_texture_size,
+          layer_tree_host()->settings().can_use_lcd_text,
+          can_render_to_separate_surface,
+          layer_tree_host()
+              ->settings()
+              .layer_transforms_should_scale_layer_contents,
+          &update_list);
+      LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+      timer_.NextLap();
+    } while (!timer_.HasTimeLimitExpired());
+
+    EndTest();
+  }
+};
+
+class CalcDrawPropsImplTest : public LayerTreeHostCommonPerfTest {
+ public:
+  void RunCalcDrawProps() {
+    RunTestWithImplSidePainting();
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    timer_.Reset();
+    LayerTreeImpl* active_tree = host_impl->active_tree();
+
+    do {
+      bool can_render_to_separate_surface = true;
+      int max_texture_size = 8096;
+      LayerImplList update_list;
+      LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
+          active_tree->root_layer(),
+          active_tree->DrawViewportSize(),
+          host_impl->DrawTransform(),
+          active_tree->device_scale_factor(),
+          active_tree->total_page_scale_factor(),
+          active_tree->RootContainerLayer(),
+          max_texture_size,
+          host_impl->settings().can_use_lcd_text,
+          can_render_to_separate_surface,
+          host_impl->settings().layer_transforms_should_scale_layer_contents,
+          &update_list);
+      LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+      timer_.NextLap();
+    } while (!timer_.HasTimeLimitExpired());
+
+    EndTest();
+  }
+};
+
+TEST_F(CalcDrawPropsMainTest, TenTen) {
+  SetTestName("10_10");
+  ReadTestFile("10_10_layer_tree");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsMainTest, HeavyPage) {
+  SetTestName("heavy_page");
+  ReadTestFile("heavy_layer_tree");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsMainTest, TouchRegionLight) {
+  SetTestName("touch_region_light");
+  ReadTestFile("touch_region_light");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsMainTest, TouchRegionHeavy) {
+  SetTestName("touch_region_heavy");
+  ReadTestFile("touch_region_heavy");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsImplTest, TenTen) {
+  SetTestName("10_10");
+  ReadTestFile("10_10_layer_tree");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsImplTest, HeavyPage) {
+  SetTestName("heavy_page");
+  ReadTestFile("heavy_layer_tree");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsImplTest, TouchRegionLight) {
+  SetTestName("touch_region_light");
+  ReadTestFile("touch_region_light");
+  RunCalcDrawProps();
+}
+
+TEST_F(CalcDrawPropsImplTest, TouchRegionHeavy) {
+  SetTestName("touch_region_heavy");
+  ReadTestFile("touch_region_heavy");
+  RunCalcDrawProps();
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 700bca4..58d82ce 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -6025,6 +6025,90 @@
   EXPECT_EQ(456, result_layer->id());
 }
 
+TEST_F(LayerTreeHostCommonTest,
+       HitCheckingTouchHandlerOverlappingRegions) {
+  gfx::Transform identity_matrix;
+  gfx::PointF anchor;
+
+  FakeImplProxy proxy;
+  FakeLayerTreeHostImpl host_impl(&proxy);
+  scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+  SetLayerPropertiesForTesting(root.get(),
+                               identity_matrix,
+                               identity_matrix,
+                               anchor,
+                               gfx::PointF(),
+                               gfx::Size(100, 100),
+                               false);
+  {
+    scoped_ptr<LayerImpl> touch_layer =
+        LayerImpl::Create(host_impl.active_tree(), 123);
+    // this layer is positioned, and hit testing should correctly know where the
+    // layer is located.
+    gfx::PointF position;
+    gfx::Size bounds(50, 50);
+    SetLayerPropertiesForTesting(touch_layer.get(),
+                                 identity_matrix,
+                                 identity_matrix,
+                                 anchor,
+                                 position,
+                                 bounds,
+                                 false);
+    touch_layer->SetDrawsContent(true);
+    touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
+    root->AddChild(touch_layer.Pass());
+  }
+
+  {
+    scoped_ptr<LayerImpl> notouch_layer =
+        LayerImpl::Create(host_impl.active_tree(), 1234);
+    // this layer is positioned, and hit testing should correctly know where the
+    // layer is located.
+    gfx::PointF position(0, 25);
+    gfx::Size bounds(50, 50);
+    SetLayerPropertiesForTesting(notouch_layer.get(),
+                                 identity_matrix,
+                                 identity_matrix,
+                                 anchor,
+                                 position,
+                                 bounds,
+                                 false);
+    notouch_layer->SetDrawsContent(true);
+    root->AddChild(notouch_layer.Pass());
+  }
+
+  LayerImplList render_surface_layer_list;
+  LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+      root.get(), root->bounds(), &render_surface_layer_list);
+  inputs.can_adjust_raster_scales = true;
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+  // Sanity check the scenario we just created.
+  ASSERT_EQ(1u, render_surface_layer_list.size());
+  ASSERT_EQ(2u, root->render_surface()->layer_list().size());
+  ASSERT_EQ(123, root->render_surface()->layer_list().at(0)->id());
+  ASSERT_EQ(1234, root->render_surface()->layer_list().at(1)->id());
+
+  gfx::Point test_point(35, 35);
+  LayerImpl* result_layer =
+      LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
+          test_point, render_surface_layer_list);
+  EXPECT_FALSE(result_layer);
+
+  test_point = gfx::Point(35, 15);
+  result_layer =
+      LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
+          test_point, render_surface_layer_list);
+  ASSERT_TRUE(result_layer);
+  EXPECT_EQ(123, result_layer->id());
+
+  test_point = gfx::Point(35, 65);
+  result_layer =
+      LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
+          test_point, render_surface_layer_list);
+  EXPECT_FALSE(result_layer);
+}
+
 class NoScaleContentLayer : public ContentLayer {
  public:
   static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) {
@@ -9548,5 +9632,118 @@
   EXPECT_EQ(4, root->render_surface()->layer_list().at(3)->id());
 }
 
+TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
+  // This test verifies that a scrolling layer that gets snapped to
+  // integer coordinates doesn't move a fixed position child.
+  //
+  // + root
+  //   + container
+  //     + scroller
+  //       + fixed
+  //
+  FakeImplProxy proxy;
+  FakeLayerTreeHostImpl host_impl(&proxy);
+  host_impl.CreatePendingTree();
+  scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+  scoped_ptr<LayerImpl> container =
+      LayerImpl::Create(host_impl.active_tree(), 2);
+  LayerImpl* container_layer = container.get();
+  scoped_ptr<LayerImpl> scroller =
+      LayerImpl::Create(host_impl.active_tree(), 3);
+  LayerImpl* scroll_layer = scroller.get();
+  scoped_ptr<LayerImpl> fixed = LayerImpl::Create(host_impl.active_tree(), 4);
+  LayerImpl* fixed_layer = fixed.get();
+
+  container->SetIsContainerForFixedPositionLayers(true);
+
+  LayerPositionConstraint constraint;
+  constraint.set_is_fixed_position(true);
+  fixed->SetPositionConstraint(constraint);
+
+  scroller->SetScrollable(true);
+
+  gfx::Transform identity_transform;
+  gfx::Transform container_transform;
+  container_transform.Translate3d(10.0, 20.0, 0.0);
+  gfx::Vector2dF container_offset = container_transform.To2dTranslation();
+
+  SetLayerPropertiesForTesting(root.get(),
+                               identity_transform,
+                               identity_transform,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(50, 50),
+                               false);
+  SetLayerPropertiesForTesting(container.get(),
+                               container_transform,
+                               identity_transform,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(40, 40),
+                               false);
+  SetLayerPropertiesForTesting(scroller.get(),
+                               identity_transform,
+                               identity_transform,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(30, 30),
+                               false);
+  SetLayerPropertiesForTesting(fixed.get(),
+                               identity_transform,
+                               identity_transform,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(50, 50),
+                               false);
+
+  scroller->AddChild(fixed.Pass());
+  container->AddChild(scroller.Pass());
+  root->AddChild(container.Pass());
+
+  // Rounded to integers already.
+  {
+    gfx::Vector2dF scroll_delta(3.0, 5.0);
+    scroll_layer->SetScrollDelta(scroll_delta);
+
+    LayerImplList render_surface_layer_list;
+    LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+        root.get(), root->bounds(), &render_surface_layer_list);
+    LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+    EXPECT_TRANSFORMATION_MATRIX_EQ(
+        container_layer->draw_properties().screen_space_transform,
+        fixed_layer->draw_properties().screen_space_transform);
+    EXPECT_VECTOR_EQ(
+        fixed_layer->draw_properties().screen_space_transform.To2dTranslation(),
+        container_offset);
+    EXPECT_VECTOR_EQ(scroll_layer->draw_properties()
+                         .screen_space_transform.To2dTranslation(),
+                     container_offset - scroll_delta);
+  }
+
+  // Scroll delta requiring rounding.
+  {
+    gfx::Vector2dF scroll_delta(4.1f, 8.1f);
+    scroll_layer->SetScrollDelta(scroll_delta);
+
+    gfx::Vector2dF rounded_scroll_delta(4.f, 8.f);
+
+    LayerImplList render_surface_layer_list;
+    LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+        root.get(), root->bounds(), &render_surface_layer_list);
+    LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+    EXPECT_TRANSFORMATION_MATRIX_EQ(
+        container_layer->draw_properties().screen_space_transform,
+        fixed_layer->draw_properties().screen_space_transform);
+    EXPECT_VECTOR_EQ(
+        fixed_layer->draw_properties().screen_space_transform.To2dTranslation(),
+        container_offset);
+    EXPECT_VECTOR_EQ(scroll_layer->draw_properties()
+                         .screen_space_transform.To2dTranslation(),
+                     container_offset - rounded_scroll_delta);
+  }
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ebc1d83..7171580 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -56,6 +56,7 @@
 #include "cc/trees/quad_culler.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/gfx/vector2d_conversions.h"
 
@@ -180,19 +181,18 @@
     const LayerTreeSettings& settings,
     LayerTreeHostImplClient* client,
     Proxy* proxy,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation) {
-  return make_scoped_ptr(
-      new LayerTreeHostImpl(settings,
-                            client,
-                            proxy,
-                            rendering_stats_instrumentation));
+    RenderingStatsInstrumentation* rendering_stats_instrumentation,
+    SharedBitmapManager* manager) {
+  return make_scoped_ptr(new LayerTreeHostImpl(
+      settings, client, proxy, rendering_stats_instrumentation, manager));
 }
 
 LayerTreeHostImpl::LayerTreeHostImpl(
     const LayerTreeSettings& settings,
     LayerTreeHostImplClient* client,
     Proxy* proxy,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation)
+    RenderingStatsInstrumentation* rendering_stats_instrumentation,
+    SharedBitmapManager* manager)
     : client_(client),
       proxy_(proxy),
       input_handler_client_(NULL),
@@ -207,9 +207,9 @@
       visible_(true),
       cached_managed_memory_policy_(
           PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
-          ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+          gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
           0,
-          ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+          gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
           ManagedMemoryPolicy::kDefaultNumResourcesLimit),
       pinch_gesture_active_(false),
       pinch_gesture_end_should_clear_scrolling_layer_(false),
@@ -230,7 +230,8 @@
       external_stencil_test_enabled_(false),
       animation_registrar_(AnimationRegistrar::Create()),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
-      need_to_update_visible_tiles_before_draw_(false) {
+      need_to_update_visible_tiles_before_draw_(false),
+      shared_bitmap_manager_(manager) {
   DCHECK(proxy_->IsImplThread());
   DidVisibilityChange(this, visible_);
 
@@ -280,7 +281,7 @@
     // Impl-side painting needs an update immediately post-commit to have the
     // opportunity to create tilings.  Other paths can call UpdateDrawProperties
     // more lazily when needed prior to drawing.
-    pending_tree()->ApplyScrollDeltasSinceBeginFrame();
+    pending_tree()->ApplyScrollDeltasSinceBeginMainFrame();
     pending_tree_->set_needs_update_draw_properties();
     pending_tree_->UpdateDrawProperties();
     // Start working on newly created tiles immediately if needed.
@@ -436,21 +437,11 @@
   gfx::PointF device_viewport_point =
       gfx::ScalePoint(viewport_point, device_scale_factor_);
 
-  // First find out which layer was hit from the saved list of visible layers
-  // in the most recent frame.
-  LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
-      device_viewport_point,
-      active_tree_->RenderSurfaceLayerList());
-
-  // Walk up the hierarchy and look for a layer with a touch event handler
-  // region that the given point hits.
-  for (; layer_impl; layer_impl = layer_impl->parent()) {
-    if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(device_viewport_point,
-                                                          layer_impl))
-      return true;
-  }
-
-  return false;
+  LayerImpl* layer_impl =
+      LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
+          device_viewport_point,
+          active_tree_->RenderSurfaceLayerList());
+  return layer_impl != NULL;
 }
 
 void LayerTreeHostImpl::SetLatencyInfoForInputEvent(
@@ -513,7 +504,8 @@
   } else if (output_surface->context_provider()) {
     return DRAW_MODE_HARDWARE;
   } else {
-    DCHECK(output_surface->software_device());
+    DCHECK_EQ(!output_surface->software_device(),
+              output_surface->capabilities().delegated_rendering);
     return DRAW_MODE_SOFTWARE;
   }
 }
@@ -1207,8 +1199,8 @@
   client_->SetNeedsRedrawRectOnImplThread(damage_rect);
 }
 
-void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) {
-  client_->BeginFrameOnImplThread(args);
+void LayerTreeHostImpl::BeginImplFrame(const BeginFrameArgs& args) {
+  client_->BeginImplFrame(args);
 }
 
 void LayerTreeHostImpl::OnSwapBuffersComplete() {
@@ -1395,9 +1387,9 @@
   return true;
 }
 
-void LayerTreeHostImpl::SetNeedsBeginFrame(bool enable) {
+void LayerTreeHostImpl::SetNeedsBeginImplFrame(bool enable) {
   if (output_surface_)
-    output_surface_->SetNeedsBeginFrame(enable);
+    output_surface_->SetNeedsBeginImplFrame(enable);
 }
 
 gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const {
@@ -1479,9 +1471,7 @@
   else
     pending_tree_ = LayerTreeImpl::create(this);
   client_->OnCanDrawStateChanged(CanDraw());
-  TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree", pending_tree_.get());
-  TRACE_EVENT_ASYNC_STEP0("cc",
-                          "PendingTree", pending_tree_.get(), "waiting");
+  TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
 }
 
 void LayerTreeHostImpl::UpdateVisibleTiles() {
@@ -1492,7 +1482,7 @@
 
 void LayerTreeHostImpl::ActivatePendingTree() {
   CHECK(pending_tree_);
-  TRACE_EVENT_ASYNC_END0("cc", "PendingTree", pending_tree_.get());
+  TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get());
 
   need_to_update_visible_tiles_before_draw_ = true;
 
@@ -1524,10 +1514,6 @@
   active_tree_->SetRootLayerScrollOffsetDelegate(
       root_layer_scroll_offset_delegate_);
 
-  // Reduce wasted memory now that unlinked resources are guaranteed not
-  // to be used.
-  client_->ReduceWastedContentsTextureMemoryOnImplThread();
-
   client_->OnCanDrawStateChanged(CanDraw());
   client_->SetNeedsRedrawOnImplThread();
   client_->RenewTreePriority();
@@ -1575,9 +1561,9 @@
   ManagedMemoryPolicy actual = cached_managed_memory_policy_;
   if (debug_state_.rasterize_only_visible_content) {
     actual.priority_cutoff_when_not_visible =
-        ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
+        gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING;
     actual.priority_cutoff_when_visible =
-        ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
+        gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
   }
 
   if (zero_budget_) {
@@ -1682,10 +1668,11 @@
   if (!output_surface->BindToClient(this))
     return false;
 
-  scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
-      output_surface.get(),
-      settings_.highp_threshold_min,
-      settings_.use_rgba_4444_textures);
+  scoped_ptr<ResourceProvider> resource_provider =
+      ResourceProvider::Create(output_surface.get(),
+                               shared_bitmap_manager_,
+                               settings_.highp_threshold_min,
+                               settings_.use_rgba_4444_textures);
   if (!resource_provider)
     return false;
 
@@ -1705,14 +1692,14 @@
                             GetRendererCapabilities().using_map_image);
   }
 
-  // Setup BeginFrameEmulation if it's not supported natively
-  if (!settings_.begin_frame_scheduling_enabled) {
+  // Setup BeginImplFrameEmulation if it's not supported natively
+  if (!settings_.begin_impl_frame_scheduling_enabled) {
     const base::TimeDelta display_refresh_interval =
       base::TimeDelta::FromMicroseconds(
           base::Time::kMicrosecondsPerSecond /
           settings_.refresh_rate);
 
-    output_surface->InitializeBeginFrameEmulation(
+    output_surface->InitializeBeginImplFrameEmulation(
         proxy_->ImplThreadTaskRunner(),
         settings_.throttle_frame_production,
         display_refresh_interval);
@@ -2350,10 +2337,8 @@
 
   bool should_animate = animation_controller->DidMouseMoveNear(
       CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_);
-  if (should_animate) {
-    client_->SetNeedsRedrawOnImplThread();
+  if (should_animate)
     StartScrollbarAnimation();
-  }
 }
 
 bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl,
@@ -2363,8 +2348,11 @@
     layer_impl = active_tree_->LayerById(scroll_layer_id);
     if (layer_impl && layer_impl->scrollbar_animation_controller()) {
       scroll_layer_id_when_mouse_over_scrollbar_ = scroll_layer_id;
-      layer_impl->scrollbar_animation_controller()->DidMouseMoveNear(
-          CurrentPhysicalTimeTicks(), 0);
+      bool should_animate =
+          layer_impl->scrollbar_animation_controller()->DidMouseMoveNear(
+              CurrentPhysicalTimeTicks(), 0);
+      if (should_animate)
+        StartScrollbarAnimation();
     } else {
       scroll_layer_id_when_mouse_over_scrollbar_ = 0;
     }
@@ -2381,6 +2369,8 @@
   client_->RenewTreePriority();
   pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer();
   active_tree_->SetCurrentlyScrollingLayer(RootScrollLayer());
+  if (top_controls_manager_)
+    top_controls_manager_->PinchBegin();
 }
 
 void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
@@ -2418,6 +2408,8 @@
     pinch_gesture_end_should_clear_scrolling_layer_ = false;
     ClearCurrentlyScrollingLayer();
   }
+  if (top_controls_manager_)
+    top_controls_manager_->PinchEnd();
   client_->SetNeedsCommitOnImplThread();
 }
 
@@ -2691,7 +2683,7 @@
 }
 
 base::TimeTicks LayerTreeHostImpl::CurrentPhysicalTimeTicks() const {
-  return base::TimeTicks::Now();
+  return gfx::FrameTime::Now();
 }
 
 scoped_ptr<base::Value> LayerTreeHostImpl::AsValueWithFrame(
@@ -2760,6 +2752,7 @@
   UIResourceData data;
   data.resource_id = id;
   data.size = bitmap.GetSize();
+  data.opaque = bitmap.GetOpaque();
 
   ui_resource_map_[uid] = data;
 
@@ -2806,6 +2799,12 @@
   return 0;
 }
 
+bool LayerTreeHostImpl::IsUIResourceOpaque(UIResourceId uid) const {
+  UIResourceMap::const_iterator iter = ui_resource_map_.find(uid);
+  DCHECK(iter != ui_resource_map_.end());
+  return iter->second.opaque;
+}
+
 bool LayerTreeHostImpl::EvictedUIResourcesExist() const {
   return !evicted_ui_resources_.empty();
 }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 555cb24..dec0e6c 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -59,7 +59,7 @@
  public:
   virtual void DidLoseOutputSurfaceOnImplThread() = 0;
   virtual void OnSwapBuffersCompleteOnImplThread() = 0;
-  virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) = 0;
+  virtual void BeginImplFrame(const BeginFrameArgs& args) = 0;
   virtual void OnCanDrawStateChanged(bool can_draw) = 0;
   virtual void NotifyReadyToActivate() = 0;
   virtual void SetNeedsRedrawOnImplThread() = 0;
@@ -74,7 +74,6 @@
   virtual bool ReduceContentsTextureMemoryOnImplThread(
       size_t limit_bytes,
       int priority_cutoff) = 0;
-  virtual void ReduceWastedContentsTextureMemoryOnImplThread() = 0;
   virtual void SendManagedMemoryStats() = 0;
   virtual bool IsInsideDraw() = 0;
   virtual void RenewTreePriority() = 0;
@@ -99,7 +98,8 @@
       const LayerTreeSettings& settings,
       LayerTreeHostImplClient* client,
       Proxy* proxy,
-      RenderingStatsInstrumentation* rendering_stats_instrumentation);
+      RenderingStatsInstrumentation* rendering_stats_instrumentation,
+      SharedBitmapManager* manager);
   virtual ~LayerTreeHostImpl();
 
   // InputHandler implementation
@@ -220,7 +220,7 @@
       scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE;
   virtual void ReleaseGL() OVERRIDE;
   virtual void SetNeedsRedrawRect(gfx::Rect rect) OVERRIDE;
-  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
   virtual void SetExternalDrawConstraints(
       const gfx::Transform& transform,
       gfx::Rect viewport,
@@ -259,7 +259,7 @@
   const RendererCapabilities& GetRendererCapabilities() const;
 
   virtual bool SwapBuffers(const FrameData& frame);
-  void SetNeedsBeginFrame(bool enable);
+  void SetNeedsBeginImplFrame(bool enable);
   void DidModifyTilePriorities();
 
   void Readback(void* pixels, gfx::Rect rect_in_device_viewport);
@@ -401,9 +401,12 @@
   virtual ResourceProvider::ResourceId ResourceIdForUIResource(
       UIResourceId uid) const;
 
+  virtual bool IsUIResourceOpaque(UIResourceId uid) const;
+
   struct UIResourceData {
     ResourceProvider::ResourceId resource_id;
     gfx::Size size;
+    bool opaque;
   };
 
  protected:
@@ -411,7 +414,8 @@
       const LayerTreeSettings& settings,
       LayerTreeHostImplClient* client,
       Proxy* proxy,
-      RenderingStatsInstrumentation* rendering_stats_instrumentation);
+      RenderingStatsInstrumentation* rendering_stats_instrumentation,
+      SharedBitmapManager* manager);
 
   // Virtual for testing.
   virtual void AnimateLayers(base::TimeTicks monotonic_time,
@@ -620,6 +624,8 @@
   // Optional callback to notify of new tree activations.
   base::Closure tree_activation_callback_;
 
+  SharedBitmapManager* shared_bitmap_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
 };
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index f635025..18b273e 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -53,6 +53,7 @@
 #include "media/base/media.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/gfx/vector2d_conversions.h"
@@ -92,10 +93,8 @@
     settings.minimum_occlusion_tracking_size = gfx::Size();
     settings.impl_side_painting = true;
 
-    host_impl_ = LayerTreeHostImpl::Create(settings,
-                                           this,
-                                           &proxy_,
-                                           &stats_instrumentation_);
+    host_impl_ = LayerTreeHostImpl::Create(
+        settings, this, &proxy_, &stats_instrumentation_, NULL);
     host_impl_->InitializeRenderer(CreateOutputSurface());
     host_impl_->SetViewportSize(gfx::Size(10, 10));
   }
@@ -106,8 +105,7 @@
     did_lose_output_surface_ = true;
   }
   virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
-  virtual void BeginFrameOnImplThread(const BeginFrameArgs& args)
-      OVERRIDE {}
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {}
   virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE {
     on_can_draw_state_changed_called_ = true;
   }
@@ -139,7 +137,6 @@
     current_priority_cutoff_value_ = priority_cutoff;
     return reduce_memory_result_;
   }
-  virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {}
   virtual void SendManagedMemoryStats() OVERRIDE {}
   virtual bool IsInsideDraw() OVERRIDE { return false; }
   virtual void RenewTreePriority() OVERRIDE {}
@@ -157,10 +154,8 @@
     settings.minimum_occlusion_tracking_size = gfx::Size();
     settings.partial_swap_enabled = partial_swap;
 
-    host_impl_ = LayerTreeHostImpl::Create(settings,
-                                           this,
-                                           &proxy_,
-                                           &stats_instrumentation_);
+    host_impl_ = LayerTreeHostImpl::Create(
+        settings, this, &proxy_, &stats_instrumentation_, NULL);
 
     host_impl_->InitializeRenderer(output_surface.Pass());
     host_impl_->SetViewportSize(gfx::Size(10, 10));
@@ -272,7 +267,7 @@
   void DrawFrame() {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -391,7 +386,7 @@
   LayerTreeSettings settings;
   settings.impl_side_painting = true;
   host_impl_ = LayerTreeHostImpl::Create(
-      settings, this, &proxy_, &stats_instrumentation_);
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
 
   scoped_ptr<FakeOutputSurface> output_surface(
       FakeOutputSurface::CreateAlwaysDrawAndSwap3d());
@@ -494,10 +489,8 @@
 
 TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
   LayerTreeSettings settings;
-  host_impl_ = LayerTreeHostImpl::Create(settings,
-                                         this,
-                                         &proxy_,
-                                         &stats_instrumentation_);
+  host_impl_ = LayerTreeHostImpl::Create(
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
   scoped_ptr<TestWebGraphicsContext3D> context_owned =
       TestWebGraphicsContext3D::Create();
   context_owned->set_times_make_current_succeeds(0);
@@ -1152,8 +1145,8 @@
       : LayerTreeHostImpl(settings,
                           client,
                           proxy,
-                          rendering_stats_instrumentation) {}
-
+                          rendering_stats_instrumentation,
+                          NULL) {}
 
   virtual base::TimeTicks CurrentPhysicalTimeTicks() const OVERRIDE {
     return fake_current_physical_time_;
@@ -1214,7 +1207,7 @@
   host_impl_->active_tree()->DidBecomeActive();
   InitializeRendererAndDrawFrame();
 
-  base::TimeTicks fake_now = base::TimeTicks::Now();
+  base::TimeTicks fake_now = gfx::FrameTime::Now();
   host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now);
 
   // If no scroll happened recently, StartScrollbarAnimation should have no
@@ -1286,7 +1279,7 @@
   gfx::Size content_size(1000, 1000);
 
   host_impl_ = LayerTreeHostImpl::Create(
-      settings, this, &proxy_, &stats_instrumentation_);
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
   host_impl_->InitializeRenderer(CreateOutputSurface());
   host_impl_->SetDeviceScaleFactor(device_scale_factor);
   host_impl_->SetViewportSize(device_viewport_size);
@@ -1335,20 +1328,17 @@
   scrollbar_animation_controller->set_mouse_move_distance_for_test(100.f);
 
   host_impl_->MouseMoveAt(gfx::Point(1, 1));
-  EXPECT_FALSE(did_request_redraw_);
+  EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar());
 
-  did_request_redraw_ = false;
   host_impl_->MouseMoveAt(gfx::Point(200, 50));
-  EXPECT_TRUE(did_request_redraw_);
+  EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar());
 
-  did_request_redraw_ = false;
   host_impl_->MouseMoveAt(gfx::Point(184, 100));
-  EXPECT_FALSE(did_request_redraw_);
+  EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar());
 
   scrollbar_animation_controller->set_mouse_move_distance_for_test(102.f);
-  did_request_redraw_ = false;
   host_impl_->MouseMoveAt(gfx::Point(184, 100));
-  EXPECT_TRUE(did_request_redraw_);
+  EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar());
 
   did_request_redraw_ = false;
   EXPECT_EQ(0, host_impl_->scroll_layer_id_when_mouse_over_scrollbar());
@@ -1513,7 +1503,7 @@
   {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10)));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
 
     EXPECT_TRUE(layer->will_draw_called());
@@ -1528,7 +1518,7 @@
     layer->ClearDidDrawCheck();
 
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10)));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
 
     EXPECT_TRUE(layer->will_draw_called());
@@ -1560,7 +1550,7 @@
   EXPECT_FALSE(layer->did_draw_called());
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_FALSE(layer->will_draw_called());
@@ -1575,7 +1565,7 @@
   EXPECT_FALSE(layer->did_draw_called());
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_TRUE(layer->will_draw_called());
@@ -1614,7 +1604,7 @@
   EXPECT_FALSE(top_layer->did_draw_called());
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_FALSE(occluded_layer->will_draw_called());
@@ -1646,7 +1636,7 @@
 
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_TRUE(root->did_draw_called());
@@ -1719,7 +1709,7 @@
   LayerTreeHostImpl::FrameData frame;
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   // When a texture is missing and we're not animating, we draw as usual with
@@ -1737,7 +1727,7 @@
                                            host_impl_->resource_provider()));
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   // When a texture is missing and we're animating, we don't want to draw
@@ -1755,7 +1745,7 @@
                                            host_impl_->resource_provider()));
 
   EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   // When the layer skips draw and we're animating, we still draw the frame.
@@ -1772,7 +1762,7 @@
                                            host_impl_->resource_provider()));
 
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -1794,10 +1784,8 @@
   settings.calculate_top_controls_position = true;
   settings.top_controls_height = 50;
 
-  host_impl_ = LayerTreeHostImpl::Create(settings,
-                                         this,
-                                         &proxy_,
-                                         &stats_instrumentation_);
+  host_impl_ = LayerTreeHostImpl::Create(
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
   host_impl_->InitializeRenderer(CreateOutputSurface());
   host_impl_->SetViewportSize(gfx::Size(10, 10));
 
@@ -2068,7 +2056,7 @@
   // the page scale delta on the root layer is applied hierarchically.
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_EQ(1.f, root->draw_transform().matrix().getDouble(0, 0));
@@ -2759,7 +2747,7 @@
   LayerTreeSettings settings;
   settings.always_overscroll = true;
   host_impl_ = LayerTreeHostImpl::Create(
-      settings, this, &proxy_, &stats_instrumentation_);
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
 
   SetupScrollAndContentsLayers(gfx::Size(50, 50));
   host_impl_->SetViewportSize(gfx::Size(50, 50));
@@ -2903,7 +2891,7 @@
   layer1->SetExpectation(false, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -2912,7 +2900,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -2922,7 +2910,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -2932,7 +2920,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -2954,7 +2942,7 @@
   layer2->SetExpectation(false, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -2967,7 +2955,7 @@
   layer2->SetExpectation(false, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -2981,7 +2969,7 @@
   layer2->SetExpectation(false, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -2998,7 +2986,7 @@
   layer2->SetExpectation(false, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -3014,7 +3002,7 @@
   layer2->SetExpectation(true, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -3029,7 +3017,7 @@
   layer2->SetExpectation(true, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -3045,7 +3033,7 @@
   layer2->SetExpectation(false, false);
   layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   EXPECT_TRUE(layer2->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
@@ -3058,7 +3046,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -3070,7 +3058,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -3082,7 +3070,7 @@
   layer1->SetExpectation(true, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 
@@ -3095,7 +3083,7 @@
   layer1->SetExpectation(false, false);
   layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(layer1->quads_appended());
   host_impl_->DidDrawAllLayers(frame);
 }
@@ -3112,7 +3100,7 @@
     settings.minimum_occlusion_tracking_size = gfx::Size();
     settings.impl_side_painting = true;
     host_impl_ = LayerTreeHostImpl::Create(
-        settings, this, &proxy_, &stats_instrumentation_);
+        settings, this, &proxy_, &stats_instrumentation_, NULL);
 
     scoped_ptr<FakeOutputSurface> output_surface;
     if (always_draw)
@@ -3317,7 +3305,8 @@
   skbitmap.setImmutable();
 
   // Specify an overhang bitmap to use.
-  UIResourceBitmap ui_resource_bitmap(skbitmap, UIResourceBitmap::REPEAT);
+  UIResourceBitmap ui_resource_bitmap(skbitmap);
+  ui_resource_bitmap.SetWrapMode(UIResourceBitmap::REPEAT);
   UIResourceId ui_resource_id = 12345;
   host_impl_->CreateUIResource(ui_resource_id, ui_resource_bitmap);
   host_impl_->SetOverhangUIResource(ui_resource_id, gfx::Size(32, 32));
@@ -3453,7 +3442,7 @@
   host_impl_->SetViewportSize(gfx::Size(10, 10));
   host_impl_->SetDeviceScaleFactor(1.f);
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(reshape_tracker->reshape_called());
   EXPECT_EQ(reshape_tracker->last_reshape_width(), 10);
   EXPECT_EQ(reshape_tracker->last_reshape_height(), 10);
@@ -3463,7 +3452,7 @@
 
   host_impl_->SetViewportSize(gfx::Size(20, 30));
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(reshape_tracker->reshape_called());
   EXPECT_EQ(reshape_tracker->last_reshape_width(), 20);
   EXPECT_EQ(reshape_tracker->last_reshape_height(), 30);
@@ -3473,7 +3462,7 @@
 
   host_impl_->SetDeviceScaleFactor(2.f);
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   EXPECT_TRUE(reshape_tracker->reshape_called());
   EXPECT_EQ(reshape_tracker->last_reshape_width(), 20);
   EXPECT_EQ(reshape_tracker->last_reshape_height(), 30);
@@ -3532,10 +3521,8 @@
   LayerTreeSettings settings;
   settings.partial_swap_enabled = true;
   scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
-      LayerTreeHostImpl::Create(settings,
-                                this,
-                                &proxy_,
-                                &stats_instrumentation_);
+      LayerTreeHostImpl::Create(
+          settings, this, &proxy_, &stats_instrumentation_, NULL);
   layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
   layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
 
@@ -3559,7 +3546,7 @@
 
   // First frame, the entire screen should get swapped.
   EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
-  layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
+  layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
   layer_tree_host_impl->DidDrawAllLayers(frame);
   layer_tree_host_impl->SwapBuffers(frame);
   gfx::Rect actual_swap_rect = swap_tracker->update_rect();
@@ -3577,7 +3564,7 @@
   layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition(
       gfx::PointF());
   EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
-  layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
+  layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
   layer_tree_host_impl->SwapBuffers(frame);
   actual_swap_rect = swap_tracker->update_rect();
@@ -3597,7 +3584,7 @@
   layer_tree_host_impl->active_tree()->root_layer()->SetBackgroundColor(
       SK_ColorBLACK);
   EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
-  layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
+  layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
   layer_tree_host_impl->SwapBuffers(frame);
   actual_swap_rect = swap_tracker->update_rect();
@@ -3765,7 +3752,7 @@
   {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
   Mock::VerifyAndClearExpectations(&mock_context);
@@ -3778,7 +3765,7 @@
   {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
   Mock::VerifyAndClearExpectations(&mock_context);
@@ -3800,7 +3787,7 @@
   {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
   Mock::VerifyAndClearExpectations(&mock_context);
@@ -3815,7 +3802,7 @@
   {
     LayerTreeHostImpl::FrameData frame;
     EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
   Mock::VerifyAndClearExpectations(&mock_context);
@@ -3847,8 +3834,8 @@
 
   LayerTreeSettings settings;
   settings.partial_swap_enabled = partial_swap;
-  scoped_ptr<LayerTreeHostImpl> my_host_impl =
-      LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation);
+  scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create(
+      settings, client, proxy, stats_instrumentation, NULL);
   my_host_impl->InitializeRenderer(output_surface.Pass());
   my_host_impl->SetViewportSize(gfx::Size(100, 100));
 
@@ -3929,7 +3916,7 @@
     EXPECT_EQ(DrawQuad::RENDER_PASS,
               frame.render_passes[1]->quad_list[0]->material);
 
-    my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
+    my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
     my_host_impl->DidDrawAllLayers(frame);
   }
 }
@@ -3950,7 +3937,7 @@
     EXPECT_EQ(DrawQuad::RENDER_PASS,
               frame.render_passes[1]->quad_list[0]->material);
 
-    my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
+    my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
     my_host_impl->DidDrawAllLayers(frame);
   }
 }
@@ -4029,7 +4016,7 @@
 
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
   host_impl_->SwapBuffers(frame);
 
@@ -4072,7 +4059,7 @@
       .Times(1);
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
   Mock::VerifyAndClearExpectations(&mock_context);
 
@@ -4080,7 +4067,7 @@
   host_impl_->active_tree()->set_has_transparent_background(true);
   host_impl_->SetFullRootLayerDamage();
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
   Mock::VerifyAndClearExpectations(&mock_context);
 }
@@ -4167,7 +4154,7 @@
                      root_render_pass->quad_list[1]->visible_rect);
     }
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
     EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame));
   }
@@ -4228,10 +4215,8 @@
 TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
   LayerTreeSettings settings;
   settings.layer_transforms_should_scale_layer_contents = true;
-  host_impl_ = LayerTreeHostImpl::Create(settings,
-                                         this,
-                                         &proxy_,
-                                         &stats_instrumentation_);
+  host_impl_ = LayerTreeHostImpl::Create(
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
   host_impl_->InitializeRenderer(CreateOutputSurface());
   host_impl_->SetViewportSize(gfx::Size(10, 10));
 
@@ -4309,7 +4294,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4337,7 +4322,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4367,7 +4352,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 }
@@ -4430,7 +4415,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4457,7 +4442,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4487,7 +4472,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4512,7 +4497,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 }
@@ -4581,7 +4566,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4609,7 +4594,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4640,7 +4625,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4666,7 +4651,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 }
@@ -4757,7 +4742,7 @@
     EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 
@@ -4791,7 +4776,7 @@
     EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(),
               replica_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 }
@@ -4887,7 +4872,7 @@
                              1.f / 50.f).ToString(),
               render_pass_quad->mask_uv_rect.ToString());
 
-    host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
     host_impl_->DidDrawAllLayers(frame);
   }
 }
@@ -4960,7 +4945,7 @@
           quad->quadTransform(), quad, &device_layer_quad, edge);
   EXPECT_FALSE(antialiased);
 
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 }
 
@@ -5061,7 +5046,7 @@
 
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   EXPECT_EQ(1u, frame.will_draw_layers.size());
@@ -5219,10 +5204,8 @@
 // doesn't support memory management extensions.
 TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) {
   LayerTreeSettings settings;
-  host_impl_ = LayerTreeHostImpl::Create(settings,
-                                         this,
-                                         &proxy_,
-                                         &stats_instrumentation_);
+  host_impl_ = LayerTreeHostImpl::Create(
+      settings, this, &proxy_, &stats_instrumentation_, NULL);
 
   scoped_ptr<OutputSurface> output_surface(
       FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()));
@@ -5232,8 +5215,8 @@
 
 TEST_F(LayerTreeHostImplTest, MemoryPolicy) {
   ManagedMemoryPolicy policy1(
-      456, ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
-      123, ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE, 1000);
+      456, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
+      123, gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE, 1000);
   int visible_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue(
       policy1.priority_cutoff_when_visible);
   int not_visible_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue(
@@ -5331,12 +5314,10 @@
   scoped_refptr<TestContextProvider> context_provider =
       TestContextProvider::Create();
 
-  host_impl_ = LayerTreeHostImpl::Create(LayerTreeSettings(),
-                                         this,
-                                         &proxy_,
-                                         &stats_instrumentation_);
-  host_impl_->InitializeRenderer(
-      FakeOutputSurface::Create3d(context_provider).PassAs<OutputSurface>());
+  host_impl_ = LayerTreeHostImpl::Create(
+      LayerTreeSettings(), this, &proxy_, &stats_instrumentation_, NULL);
+  host_impl_->InitializeRenderer(FakeOutputSurface::Create3d(context_provider)
+                                     .PassAs<OutputSurface>());
   host_impl_->SetViewportSize(gfx::Size(10, 10));
 
   SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
@@ -5349,7 +5330,7 @@
 
   LayerTreeHostImpl::FrameData frame;
   EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
-  host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+  host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
   host_impl_->DidDrawAllLayers(frame);
 
   // The CopyOutputResult's callback has a ref on the ContextProvider and a
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc
index 1eebe41..79ee46b 100644
--- a/cc/trees/layer_tree_host_perftest.cc
+++ b/cc/trees/layer_tree_host_perftest.cc
@@ -44,6 +44,10 @@
     fake_content_layer_client_.set_paint_all_opaque(true);
   }
 
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->throttle_frame_production = false;
+  }
+
   virtual void BeginTest() OVERRIDE {
     BuildTree();
     PostSetNeedsCommitToMainThread();
diff --git a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
index a1990b0..c432a5e 100644
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -29,8 +29,8 @@
   virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     // Not enough memory available. Enforce on-demand rasterization.
     impl->SetMemoryPolicy(
-        ManagedMemoryPolicy(1, ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
-                            1, ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+        ManagedMemoryPolicy(1, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
+                            1, gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
                             1000));
     impl->SetDiscardBackBufferWhenNotVisible(true);
   }
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index c5127b1..950fd79 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -51,6 +51,7 @@
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/skia/include/core/SkPicture.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/point_conversions.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/gfx/vector2d_conversions.h"
@@ -730,6 +731,101 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNextCommitForcesRedraw);
 
+// Tests that if a layer is not drawn because of some reason in the parent then
+// its damage is preserved until the next time it is drawn.
+class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestUndrawnLayersDamageLater()
+      : root_layer_(ContentLayer::Create(&client_)) {
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    root_layer_->SetIsDrawable(true);
+    root_layer_->SetBounds(gfx::Size(50, 50));
+    layer_tree_host()->SetRootLayer(root_layer_);
+
+    // The initially transparent layer has a larger child layer, which is
+    // not initially drawn because of the this (parent) layer.
+    parent_layer_ = FakeContentLayer::Create(&client_);
+    parent_layer_->SetBounds(gfx::Size(15, 15));
+    parent_layer_->SetOpacity(0.0f);
+    root_layer_->AddChild(parent_layer_);
+
+    child_layer_ = FakeContentLayer::Create(&client_);
+    child_layer_->SetBounds(gfx::Size(25, 25));
+    parent_layer_->AddChild(child_layer_);
+
+    LayerTreeHostTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                     LayerTreeHostImpl::FrameData* frame_data,
+                                     bool result) OVERRIDE {
+    EXPECT_TRUE(result);
+
+    gfx::RectF root_damage_rect;
+    if (!frame_data->render_passes.empty())
+      root_damage_rect = frame_data->render_passes.back()->damage_rect;
+
+    // The first time, the whole view needs be drawn.
+    // Afterwards, just the opacity of surface_layer1 is changed a few times,
+    // and each damage should be the bounding box of it and its child. If this
+    // was working improperly, the damage might not include its childs bounding
+    // box.
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
+        break;
+      case 2:
+      case 3:
+      case 4:
+        EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
+        break;
+      default:
+        NOTREACHED();
+    }
+
+    return result;
+  }
+
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // Test not owning the surface.
+        parent_layer_->SetOpacity(1.0f);
+        break;
+      case 2:
+        parent_layer_->SetOpacity(0.0f);
+        break;
+      case 3:
+        // Test owning the surface.
+        parent_layer_->SetOpacity(0.5f);
+        parent_layer_->SetForceRenderSurface(true);
+        break;
+      case 4:
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  FakeContentLayerClient client_;
+  scoped_refptr<ContentLayer> root_layer_;
+  scoped_refptr<FakeContentLayer> parent_layer_;
+  scoped_refptr<FakeContentLayer> child_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
+
 // If the layerTreeHost says it can't draw, Then we should not try to draw.
 class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
  public:
@@ -1004,10 +1100,9 @@
       first_frame_time_ = impl->CurrentFrameTimeTicks();
       impl->SetNeedsRedraw();
 
-      // Since base::TimeTicks::Now() uses a low-resolution clock on
-      // Windows, we need to make sure that the clock has incremented past
-      // first_frame_time_.
-      while (first_frame_time_ == base::TimeTicks::Now()) {}
+      // Since we might use a low-resolution clock on Windows, we need to
+      // make sure that the clock has incremented past first_frame_time_.
+      while (first_frame_time_ == gfx::FrameTime::Now()) {}
 
       return;
     }
@@ -2204,7 +2299,7 @@
   LayerTreeHostWithProxy(FakeLayerTreeHostClient* client,
                          const LayerTreeSettings& settings,
                          scoped_ptr<FakeProxy> proxy)
-      : LayerTreeHost(client, settings) {
+      : LayerTreeHost(client, NULL, settings) {
     proxy->SetLayerTreeHost(this);
     EXPECT_TRUE(InitializeForTesting(proxy.PassAs<Proxy>()));
   }
@@ -2272,7 +2367,7 @@
   settings.max_partial_texture_updates = 4;
 
   scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, settings, NULL);
+      LayerTreeHost::Create(&client, NULL, settings, NULL);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
 }
@@ -2284,7 +2379,7 @@
   settings.max_partial_texture_updates = 4;
 
   scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, settings, NULL);
+      LayerTreeHost::Create(&client, NULL, settings, NULL);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
 }
@@ -2296,7 +2391,7 @@
   settings.max_partial_texture_updates = 4;
 
   scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, settings, NULL);
+      LayerTreeHost::Create(&client, NULL, settings, NULL);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
@@ -2309,7 +2404,7 @@
   settings.max_partial_texture_updates = 4;
 
   scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, settings, NULL);
+      LayerTreeHost::Create(&client, NULL, settings, NULL);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
@@ -2358,9 +2453,9 @@
         // Because a resource was evicted, a commit will be kicked off.
         host_impl->SetMemoryPolicy(
             ManagedMemoryPolicy(100 * 100 * 4 * 2,
-                                ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+                                gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
                                 100 * 100 * 4 * 1,
-                                ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+                                gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
                                 1000));
         host_impl->SetDiscardBackBufferWhenNotVisible(true);
         break;
@@ -2482,15 +2577,16 @@
 
 SINGLE_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
 
-// Verify that the BeginFrame notification is used to initiate rendering.
-class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
+// Verify that the BeginImplFrame notification is used to initiate rendering.
+class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest {
  public:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->begin_impl_frame_scheduling_enabled = true;
   }
 
   virtual void BeginTest() OVERRIDE {
-    // This will trigger a SetNeedsBeginFrame which will trigger a BeginFrame.
+    // This will trigger a SetNeedsBeginImplFrame which will trigger a
+    // BeginImplFrame.
     PostSetNeedsCommitToMainThread();
   }
 
@@ -2508,24 +2604,24 @@
   base::TimeTicks frame_time_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification);
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginImplFrameNotification);
 
-class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
+class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled
     : public LayerTreeHostTest {
  public:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->begin_impl_frame_scheduling_enabled = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
-    // The BeginFrame notification is turned off now but will get enabled
+    // The BeginImplFrame notification is turned off now but will get enabled
     // once we return. End test while it's enabled.
     ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest,
+        base::Bind(&LayerTreeHostTestBeginImplFrameNotification::EndTest,
                    base::Unretained(this)));
   }
 
@@ -2533,7 +2629,7 @@
 };
 
 MULTI_THREAD_TEST_F(
-    LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled);
+    LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled);
 
 class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
  protected:
@@ -2541,7 +2637,7 @@
       : commit_count_(0), commit_complete_count_(0) {}
 
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->begin_impl_frame_scheduling_enabled = true;
   }
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
@@ -4709,7 +4805,7 @@
 class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest {
  public:
   LayerTreeHostTestAbortEvictedTextures()
-      : num_will_begin_frames_(0), num_impl_commits_(0) {}
+      : num_will_begin_main_frames_(0), num_impl_commits_(0) {}
 
  protected:
   virtual void SetupTree() OVERRIDE {
@@ -4723,9 +4819,9 @@
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual void WillBeginFrame() OVERRIDE {
-    num_will_begin_frames_++;
-    switch (num_will_begin_frames_) {
+  virtual void WillBeginMainFrame() OVERRIDE {
+    num_will_begin_main_frames_++;
+    switch (num_will_begin_main_frames_) {
       case 2:
         // Send a redraw to the compositor thread.  This will (wrongly) be
         // ignored unless aborting resets the texture state.
@@ -4755,12 +4851,12 @@
 
   virtual void AfterTest() OVERRIDE {
     // Ensure that the commit was truly aborted.
-    EXPECT_EQ(2, num_will_begin_frames_);
+    EXPECT_EQ(2, num_will_begin_main_frames_);
     EXPECT_EQ(1, num_impl_commits_);
   }
 
  private:
-  int num_will_begin_frames_;
+  int num_will_begin_main_frames_;
   int num_impl_commits_;
 };
 
@@ -4881,9 +4977,9 @@
         // This will trigger a commit because the priority cutoff has changed.
         impl->SetMemoryPolicy(ManagedMemoryPolicy(
             16u*1024u*1024u,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
             0,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
             1000));
         break;
       case 2:
@@ -4891,9 +4987,9 @@
         // changed, and there is already enough memory for all allocations.
         impl->SetMemoryPolicy(ManagedMemoryPolicy(
             32u*1024u*1024u,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
             0,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
             1000));
         break;
       case 3:
@@ -5041,14 +5137,14 @@
                 second_context_provider_ :
                 first_context_provider_));
     output_surface->SetMemoryPolicyToSetAtBind(make_scoped_ptr(
-        new cc::ManagedMemoryPolicy(
+        new ManagedMemoryPolicy(
             second_context_provider_ ?
                 second_output_surface_memory_limit_ :
                 first_output_surface_memory_limit_,
-            cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
             0,
-            cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
-            cc::ManagedMemoryPolicy::kDefaultNumResourcesLimit)));
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
+            ManagedMemoryPolicy::kDefaultNumResourcesLimit)));
     return output_surface.PassAs<OutputSurface>();
   }
 
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 70e2a9e..90fc936 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -375,14 +375,17 @@
 
     // Verify that commits are actually alternating with empty / non-empty
     // trees.
-    switch (host_impl->active_tree()->source_frame_number()) {
+    int frame_number = host_impl->active_tree()->source_frame_number();
+    switch (frame_number) {
       case 0:
       case 2:
-        EXPECT_TRUE(host_impl->active_tree()->root_layer());
+        EXPECT_TRUE(host_impl->active_tree()->root_layer())
+            << "frame: " << frame_number;
         break;
       case 1:
       case 3:
-        EXPECT_FALSE(host_impl->active_tree()->root_layer());
+        EXPECT_FALSE(host_impl->active_tree()->root_layer())
+            << "frame: " << frame_number;
         break;
     }
 
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index e4a0ca7..03b8d7f 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -894,8 +894,9 @@
   RunTest(true, true, false);
 }
 
+// Flaky on all platforms, http://crbug.com/310979
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
+       DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
   lose_after_evict_ = true;
   RunTest(true, true, true);
 }
@@ -1089,7 +1090,7 @@
     child_output_surface_ = FakeOutputSurface::Create3d();
     child_output_surface_->BindToClient(&output_surface_client_);
     child_resource_provider_ =
-        ResourceProvider::Create(child_output_surface_.get(), 0, false);
+        ResourceProvider::Create(child_output_surface_.get(), NULL, 0, false);
   }
 
   static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
@@ -1402,13 +1403,16 @@
 
     times_output_surface_created_ = 0;
 
+    // Post the SetNeedsCommit before the readback to make sure it is run
+    // on the main thread before the readback's replacement commit when
+    // we have a threaded compositor.
+    PostSetNeedsCommitToMainThread();
+
     char pixels[4];
     bool result = layer_tree_host()->CompositeAndReadback(
         &pixels, gfx::Rect(1, 1));
     EXPECT_EQ(!delegating_renderer(), result);
     EXPECT_EQ(1, times_output_surface_created_);
-
-    PostSetNeedsCommitToMainThread();
   }
 
   virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
@@ -1781,6 +1785,7 @@
     settings.impl_side_painting = impl_side_painting;
     scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::Create(
         this,
+        NULL,
         settings,
         impl_thread ? impl_thread->message_loop_proxy() : NULL);
     EXPECT_FALSE(layer_tree_host);
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index 83831f6..402a56a 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -58,9 +58,9 @@
         // No evictions when we become not-visible.
         impl->SetMemoryPolicy(ManagedMemoryPolicy(
             1000 * 1000 * 1000,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
             1000 * 1000 * 1000,
-            ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
             ManagedMemoryPolicy::kDefaultNumResourcesLimit));
 
         PostSetVisibleToMainThread(false);
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index ab87be1..1142622 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -172,8 +172,8 @@
         impl_scroll_(-3, 2),
         second_main_scroll_(14, -3),
         impl_scale_(2.f),
-        num_will_begin_frames_(0),
-        num_did_begin_frames_(0),
+        num_will_begin_main_frames_(0),
+        num_did_begin_main_frames_(0),
         num_will_commits_(0),
         num_did_commits_(0),
         num_impl_commits_(0),
@@ -194,10 +194,10 @@
     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
   }
 
-  virtual void WillBeginFrame() OVERRIDE {
-    num_will_begin_frames_++;
+  virtual void WillBeginMainFrame() OVERRIDE {
+    num_will_begin_main_frames_++;
     Layer* root_scroll_layer = layer_tree_host()->root_layer()->children()[0];
-    switch (num_will_begin_frames_) {
+    switch (num_will_begin_main_frames_) {
       case 1:
         // This will not be aborted because of the initial prop changes.
         EXPECT_EQ(0, num_impl_scrolls_);
@@ -239,7 +239,7 @@
     }
   }
 
-  virtual void DidBeginFrame() OVERRIDE { num_did_begin_frames_++; }
+  virtual void DidBeginMainFrame() OVERRIDE { num_did_begin_main_frames_++; }
 
   virtual void WillCommit() OVERRIDE { num_will_commits_++; }
 
@@ -317,8 +317,8 @@
   virtual void AfterTest() OVERRIDE {
     EXPECT_EQ(3, num_impl_scrolls_);
     // Verify that the embedder sees aborted commits as real commits.
-    EXPECT_EQ(4, num_will_begin_frames_);
-    EXPECT_EQ(4, num_did_begin_frames_);
+    EXPECT_EQ(4, num_will_begin_main_frames_);
+    EXPECT_EQ(4, num_did_begin_main_frames_);
     EXPECT_EQ(4, num_will_commits_);
     EXPECT_EQ(4, num_did_commits_);
     // ...but the compositor thread only sees two real ones.
@@ -330,8 +330,8 @@
   gfx::Vector2d impl_scroll_;
   gfx::Vector2d second_main_scroll_;
   float impl_scale_;
-  int num_will_begin_frames_;
-  int num_did_begin_frames_;
+  int num_will_begin_main_frames_;
+  int num_did_begin_main_frames_;
   int num_will_commits_;
   int num_did_commits_;
   int num_impl_commits_;
@@ -1013,7 +1013,7 @@
 
   ASSERT_TRUE(impl_thread.message_loop_proxy().get());
   scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::Create(
-      &client, settings, impl_thread.message_loop_proxy());
+      &client, NULL, settings, impl_thread.message_loop_proxy());
 
   impl_thread.message_loop_proxy()
       ->PostTask(FROM_HERE,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 3e3d64c..4604043 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -271,17 +271,17 @@
       root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo));
 }
 
-static void ApplyScrollDeltasSinceBeginFrameTo(LayerImpl* layer) {
-  layer->ApplyScrollDeltasSinceBeginFrame();
+static void ApplyScrollDeltasSinceBeginMainFrameTo(LayerImpl* layer) {
+  layer->ApplyScrollDeltasSinceBeginMainFrame();
 }
 
-void LayerTreeImpl::ApplyScrollDeltasSinceBeginFrame() {
+void LayerTreeImpl::ApplyScrollDeltasSinceBeginMainFrame() {
   DCHECK(IsPendingTree());
   if (!root_layer())
     return;
 
   LayerTreeHostCommon::CallFunctionForSubtree(
-      root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginFrameTo));
+      root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginMainFrameTo));
 }
 
 void LayerTreeImpl::SetViewportLayersFromIds(
@@ -710,6 +710,10 @@
   return layer_tree_host_impl_->ResourceIdForUIResource(uid);
 }
 
+bool LayerTreeImpl::IsUIResourceOpaque(UIResourceId uid) const {
+  return layer_tree_host_impl_->IsUIResourceOpaque(uid);
+}
+
 void LayerTreeImpl::ProcessUIResourceRequestQueue() {
   while (ui_resource_request_queue_.size() > 0) {
     UIResourceRequest req = ui_resource_request_queue_.front();
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index faf360f..1b40b92 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -123,7 +123,7 @@
                                 int outer_viewport_scroll_layer_id);
   void ClearViewportLayers();
   void ApplySentScrollAndScaleDeltasFromAbortedCommit();
-  void ApplyScrollDeltasSinceBeginFrame();
+  void ApplyScrollDeltasSinceBeginMainFrame();
 
   SkColor background_color() const { return background_color_; }
   void set_background_color(SkColor color) { background_color_ = color; }
@@ -212,6 +212,8 @@
   ResourceProvider::ResourceId ResourceIdForUIResource(UIResourceId uid) const;
   void ProcessUIResourceRequestQueue();
 
+  bool IsUIResourceOpaque(UIResourceId uid) const;
+
   void AddLayerWithCopyOutputRequest(LayerImpl* layer);
   void RemoveLayerWithCopyOutputRequest(LayerImpl* layer);
   const std::vector<LayerImpl*> LayersWithCopyOutputRequest() const;
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index b7aafbb..eb0f2f3 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -16,8 +16,8 @@
     : impl_side_painting(false),
       allow_antialiasing(true),
       throttle_frame_production(true),
-      begin_frame_scheduling_enabled(false),
-      deadline_scheduling_enabled(false),
+      begin_impl_frame_scheduling_enabled(false),
+      deadline_scheduling_enabled(true),
       using_synchronous_renderer_compositor(false),
       per_tile_painting_enabled(false),
       partial_swap_enabled(false),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index ca063b8..fafeb4d 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -21,7 +21,7 @@
   bool impl_side_painting;
   bool allow_antialiasing;
   bool throttle_frame_production;
-  bool begin_frame_scheduling_enabled;
+  bool begin_impl_frame_scheduling_enabled;
   bool deadline_scheduling_enabled;
   bool using_synchronous_renderer_compositor;
   bool per_tile_painting_enabled;
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index 2bd9b55..8f98c27 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -272,12 +272,6 @@
   // to expand outside the clip.
   affected_area_in_target.Inset(
       -outset_left, -outset_top, -outset_right, -outset_bottom);
-
-  gfx::Rect FilterOutsetsInTarget(-outset_left,
-                                  -outset_top,
-                                  outset_left + outset_right,
-                                  outset_top + outset_bottom);
-
   Region affected_occlusion = IntersectRegions(*occlusion_from_inside_target,
                                                affected_area_in_target);
   Region::Iterator affected_occlusion_rects(affected_occlusion);
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 84844c8..69975a6 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -81,6 +81,7 @@
   virtual void MainThreadHasStoppedFlinging() = 0;
 
   virtual bool CommitRequested() const = 0;
+  virtual bool BeginMainFrameRequested() const = 0;
 
   // Must be called before using the proxy.
   virtual void Start(scoped_ptr<OutputSurface> first_output_surface) = 0;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 634c3bc..9de0fdd 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -15,6 +15,7 @@
 #include "cc/trees/blocking_task_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "ui/gfx/frame_time.h"
 
 namespace cc {
 
@@ -59,7 +60,7 @@
   gfx::Rect device_viewport_damage_rect = rect;
 
   LayerTreeHostImpl::FrameData frame;
-  if (!CommitAndComposite(base::TimeTicks::Now(),
+  if (!CommitAndComposite(gfx::FrameTime::Now(),
                           device_viewport_damage_rect,
                           true,  // for_readback
                           &frame))
@@ -254,6 +255,8 @@
 
 bool SingleThreadProxy::CommitRequested() const { return false; }
 
+bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
+
 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
   return std::numeric_limits<size_t>::max();
 }
@@ -329,11 +332,6 @@
       limit_bytes, priority_cutoff, layer_tree_host_impl_->resource_provider());
 }
 
-void SingleThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() {
-  // Impl-side painting only.
-  NOTREACHED();
-}
-
 void SingleThreadProxy::SendManagedMemoryStats() {
   DCHECK(Proxy::IsImplThread());
   if (!layer_tree_host_impl_)
@@ -455,7 +453,7 @@
                             device_viewport_damage_rect,
                             for_readback,
                             frame);
-  layer_tree_host_->DidBeginFrame();
+  layer_tree_host_->DidBeginMainFrame();
   return result;
 }
 
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 474fb1f..843be729 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -39,6 +39,7 @@
   virtual void NotifyInputThrottledUntilCommit() OVERRIDE {}
   virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
   virtual bool CommitRequested() const OVERRIDE;
+  virtual bool BeginMainFrameRequested() const OVERRIDE;
   virtual void MainThreadHasStoppedFlinging() OVERRIDE {}
   virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE;
   virtual void Stop() OVERRIDE;
@@ -51,7 +52,7 @@
   // LayerTreeHostImplClient implementation
   virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE;
   virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
-  virtual void BeginFrameOnImplThread(const BeginFrameArgs& args)
+  virtual void BeginImplFrame(const BeginFrameArgs& args)
       OVERRIDE {}
   virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE;
   virtual void NotifyReadyToActivate() OVERRIDE;
@@ -66,7 +67,6 @@
   virtual bool ReduceContentsTextureMemoryOnImplThread(
       size_t limit_bytes,
       int priority_cutoff) OVERRIDE;
-  virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE;
   virtual void SendManagedMemoryStats() OVERRIDE;
   virtual bool IsInsideDraw() OVERRIDE;
   virtual void RenewTreePriority() OVERRIDE {}
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index e57def2..4f2f488 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -22,6 +22,7 @@
 #include "cc/trees/blocking_task_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "ui/gfx/frame_time.h"
 
 // Measured in seconds.
 const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
@@ -72,7 +73,7 @@
       manage_tiles_pending_(false),
       commit_waits_for_activation_(false),
       inside_commit_(false),
-      begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL),
+      begin_main_frame_sent_completion_event_on_impl_thread_(NULL),
       readback_request_on_impl_thread_(NULL),
       commit_completion_event_on_impl_thread_(NULL),
       completion_event_for_commit_held_on_tree_activation_(NULL),
@@ -80,8 +81,8 @@
       next_frame_is_newly_committed_frame_on_impl_thread_(false),
       throttle_frame_production_(
           layer_tree_host->settings().throttle_frame_production),
-      begin_frame_scheduling_enabled_(
-          layer_tree_host->settings().begin_frame_scheduling_enabled),
+      begin_impl_frame_scheduling_enabled_(
+          layer_tree_host->settings().begin_impl_frame_scheduling_enabled),
       using_synchronous_renderer_compositor_(
           layer_tree_host->settings().using_synchronous_renderer_compositor),
       inside_draw_(false),
@@ -90,7 +91,7 @@
       input_throttled_until_commit_(false),
       renew_tree_priority_on_impl_thread_pending_(false),
       draw_duration_history_(kDurationHistorySize),
-      begin_frame_to_commit_duration_history_(kDurationHistorySize),
+      begin_main_frame_to_commit_duration_history_(kDurationHistorySize),
       commit_to_activate_duration_history_(kDurationHistorySize),
       weak_factory_on_impl_thread_(this),
       weak_factory_(this) {
@@ -126,22 +127,22 @@
   request.pixels = pixels;
   {
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
-    CompletionEvent begin_frame_sent_to_main_thread_completion;
+    CompletionEvent begin_main_frame_sent_completion;
     Proxy::ImplThreadTaskRunner()
         ->PostTask(FROM_HERE,
                    base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread,
                               impl_thread_weak_ptr_,
-                              &begin_frame_sent_to_main_thread_completion,
+                              &begin_main_frame_sent_completion,
                               &request));
-    begin_frame_sent_to_main_thread_completion.Wait();
+    begin_main_frame_sent_completion.Wait();
   }
 
   in_composite_and_readback_ = true;
   // This is the forced commit.
-  // Note: The Impl thread also queues a separate BeginFrameOnMainThread on the
+  // Note: The Impl thread also queues a separate BeginMainFrame on the
   // main thread, which will be called after this CompositeAndReadback
   // completes, to replace the forced commit.
-  BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>());
+  BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState>());
   in_composite_and_readback_ = false;
 
   // Composite and readback requires a second commit to undo any changes
@@ -153,15 +154,15 @@
 }
 
 void ThreadProxy::ForceCommitForReadbackOnImplThread(
-    CompletionEvent* begin_frame_sent_completion,
+    CompletionEvent* begin_main_frame_sent_completion,
     ReadbackRequest* request) {
   TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread");
   DCHECK(IsImplThread());
-  DCHECK(!begin_frame_sent_to_main_thread_completion_event_on_impl_thread_);
+  DCHECK(!begin_main_frame_sent_completion_event_on_impl_thread_);
   DCHECK(!readback_request_on_impl_thread_);
 
   if (!layer_tree_host_impl_) {
-    begin_frame_sent_completion->Signal();
+    begin_main_frame_sent_completion->Signal();
     request->success = false;
     request->completion.Signal();
     return;
@@ -171,12 +172,12 @@
 
   scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback();
   if (scheduler_on_impl_thread_->CommitPending()) {
-    begin_frame_sent_completion->Signal();
+    begin_main_frame_sent_completion->Signal();
     return;
   }
 
-  begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ =
-      begin_frame_sent_completion;
+  begin_main_frame_sent_completion_event_on_impl_thread_ =
+      begin_main_frame_sent_completion;
 }
 
 void ThreadProxy::FinishAllRendering() {
@@ -342,6 +343,11 @@
 
 void ThreadProxy::SetNeedsUpdateLayers() {
   DCHECK(IsMainThread());
+
+  if (commit_request_sent_to_impl_thread_)
+    return;
+  TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers");
+
   SendCommitRequestToImplThreadIfNeeded();
 }
 
@@ -387,13 +393,13 @@
   DCHECK(IsImplThread());
   TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginImplFrame",
                "enable", enable);
-  layer_tree_host_impl_->SetNeedsBeginFrame(enable);
+  layer_tree_host_impl_->SetNeedsBeginImplFrame(enable);
   UpdateBackgroundAnimateTicking();
 }
 
-void ThreadProxy::BeginFrameOnImplThread(const BeginFrameArgs& args) {
+void ThreadProxy::BeginImplFrame(const BeginFrameArgs& args) {
   DCHECK(IsImplThread());
-  TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnImplThread");
+  TRACE_EVENT0("cc", "ThreadProxy::BeginImplFrame");
 
   // Sample the frame time now. This time will be used for updating animations
   // when we draw.
@@ -460,16 +466,6 @@
   return true;
 }
 
-void ThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() {
-  DCHECK(IsImplThread());
-
-  if (!layer_tree_host_->contents_texture_manager())
-    return;
-
-  layer_tree_host_->contents_texture_manager()->ReduceWastedMemoryOnImplThread(
-      layer_tree_host_impl_->resource_provider());
-}
-
 void ThreadProxy::SendManagedMemoryStats() {
   DCHECK(IsImplThread());
   if (!layer_tree_host_impl_)
@@ -521,7 +517,7 @@
   if (!defer_commits_ && pending_deferred_commit_)
     Proxy::MainThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&ThreadProxy::BeginFrameOnMainThread,
+        base::Bind(&ThreadProxy::BeginMainFrame,
                    main_thread_weak_ptr_,
                    base::Passed(&pending_deferred_commit_)));
 }
@@ -531,6 +527,11 @@
   return commit_requested_;
 }
 
+bool ThreadProxy::BeginMainFrameRequested() const {
+  DCHECK(IsMainThread());
+  return commit_request_sent_to_impl_thread_;
+}
+
 void ThreadProxy::SetNeedsRedrawOnImplThread() {
   DCHECK(IsImplThread());
   TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread");
@@ -685,52 +686,52 @@
 
 void ThreadProxy::ScheduledActionSendBeginMainFrame() {
   TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginMainFrame");
-  scoped_ptr<BeginFrameAndCommitState> begin_frame_state(
-      new BeginFrameAndCommitState);
-  begin_frame_state->monotonic_frame_begin_time =
+  scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
+      new BeginMainFrameAndCommitState);
+  begin_main_frame_state->monotonic_frame_begin_time =
       layer_tree_host_impl_->CurrentPhysicalTimeTicks();
-  begin_frame_state->scroll_info =
+  begin_main_frame_state->scroll_info =
       layer_tree_host_impl_->ProcessScrollDeltas();
 
   if (!layer_tree_host_impl_->settings().impl_side_painting) {
     DCHECK_GT(layer_tree_host_impl_->memory_allocation_limit_bytes(), 0u);
   }
-  begin_frame_state->memory_allocation_limit_bytes =
+  begin_main_frame_state->memory_allocation_limit_bytes =
       layer_tree_host_impl_->memory_allocation_limit_bytes();
-  begin_frame_state->memory_allocation_priority_cutoff =
+  begin_main_frame_state->memory_allocation_priority_cutoff =
       layer_tree_host_impl_->memory_allocation_priority_cutoff();
-  begin_frame_state->evicted_ui_resources =
+  begin_main_frame_state->evicted_ui_resources =
       layer_tree_host_impl_->EvictedUIResourcesExist();
   Proxy::MainThreadTaskRunner()->PostTask(
       FROM_HERE,
-      base::Bind(&ThreadProxy::BeginFrameOnMainThread,
+      base::Bind(&ThreadProxy::BeginMainFrame,
                  main_thread_weak_ptr_,
-                 base::Passed(&begin_frame_state)));
+                 base::Passed(&begin_main_frame_state)));
 
-  if (begin_frame_sent_to_main_thread_completion_event_on_impl_thread_) {
-    begin_frame_sent_to_main_thread_completion_event_on_impl_thread_->Signal();
-    begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = NULL;
+  if (begin_main_frame_sent_completion_event_on_impl_thread_) {
+    begin_main_frame_sent_completion_event_on_impl_thread_->Signal();
+    begin_main_frame_sent_completion_event_on_impl_thread_ = NULL;
   }
-  begin_frame_sent_to_main_thread_time_ = base::TimeTicks::HighResNow();
+  begin_main_frame_sent_time_ = base::TimeTicks::HighResNow();
 }
 
-void ThreadProxy::BeginFrameOnMainThread(
-    scoped_ptr<BeginFrameAndCommitState> begin_frame_state) {
-  TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread");
+void ThreadProxy::BeginMainFrame(
+    scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
+  TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame");
   DCHECK(IsMainThread());
 
   if (!layer_tree_host_)
     return;
 
   if (defer_commits_) {
-    pending_deferred_commit_ = begin_frame_state.Pass();
+    pending_deferred_commit_ = begin_main_frame_state.Pass();
     layer_tree_host_->DidDeferCommit();
     TRACE_EVENT0("cc", "EarlyOut_DeferCommits");
     return;
   }
 
   // Do not notify the impl thread of commit requests that occur during
-  // the apply/animate/layout part of the BeginFrameAndCommit process since
+  // the apply/animate/layout part of the BeginMainFrameAndCommit process since
   // those commit requests will get painted immediately. Once we have done
   // the paint, commit_requested_ will be set to false to allow new commit
   // requests to be scheduled.
@@ -750,22 +751,22 @@
     bool did_handle = false;
     Proxy::ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread,
+        base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
                    impl_thread_weak_ptr_,
                    did_handle));
     return;
   }
 
-  if (begin_frame_state)
-    layer_tree_host_->ApplyScrollAndScale(*begin_frame_state->scroll_info);
+  if (begin_main_frame_state)
+    layer_tree_host_->ApplyScrollAndScale(*begin_main_frame_state->scroll_info);
 
-  layer_tree_host_->WillBeginFrame();
+  layer_tree_host_->WillBeginMainFrame();
 
-  if (begin_frame_state) {
+  if (begin_main_frame_state) {
     layer_tree_host_->UpdateClientAnimations(
-        begin_frame_state->monotonic_frame_begin_time);
+        begin_main_frame_state->monotonic_frame_begin_time);
     layer_tree_host_->AnimateLayers(
-        begin_frame_state->monotonic_frame_begin_time);
+        begin_main_frame_state->monotonic_frame_begin_time);
   }
 
   // Unlink any backings that the impl thread has evicted, so that we know to
@@ -774,18 +775,19 @@
     layer_tree_host_->contents_texture_manager()->
         UnlinkAndClearEvictedBackings();
 
-    if (begin_frame_state) {
+    if (begin_main_frame_state) {
       layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
-          begin_frame_state->memory_allocation_limit_bytes);
+          begin_main_frame_state->memory_allocation_limit_bytes);
       layer_tree_host_->contents_texture_manager()->SetExternalPriorityCutoff(
-          begin_frame_state->memory_allocation_priority_cutoff);
+          begin_main_frame_state->memory_allocation_priority_cutoff);
     }
   }
 
   // Recreate all UI resources if there were evicted UI resources when the impl
   // thread initiated the commit.
-  bool evicted_ui_resources =
-      begin_frame_state ? begin_frame_state->evicted_ui_resources : false;
+  bool evicted_ui_resources = begin_main_frame_state
+                                  ? begin_main_frame_state->evicted_ui_resources
+                                  : false;
   if (evicted_ui_resources)
       layer_tree_host_->RecreateUIResources();
 
@@ -818,7 +820,7 @@
     bool did_handle = true;
     Proxy::ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread,
+        base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
                    impl_thread_weak_ptr_,
                    did_handle));
 
@@ -826,7 +828,7 @@
     // detected to be a no-op.  From the perspective of an embedder, this commit
     // went through, and input should no longer be throttled, etc.
     layer_tree_host_->CommitComplete();
-    layer_tree_host_->DidBeginFrame();
+    layer_tree_host_->DidBeginMainFrame();
     return;
   }
 
@@ -854,7 +856,7 @@
   // point of view, but asynchronously performed on the impl thread,
   // coordinated by the Scheduler.
   {
-    TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread::commit");
+    TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit");
 
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
 
@@ -881,7 +883,7 @@
   }
 
   layer_tree_host_->CommitComplete();
-  layer_tree_host_->DidBeginFrame();
+  layer_tree_host_->DidBeginMainFrame();
 }
 
 void ThreadProxy::StartCommitOnImplThread(
@@ -933,8 +935,8 @@
       scheduler_on_impl_thread_->AnticipatedDrawTime());
 }
 
-void ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread(bool did_handle) {
-  TRACE_EVENT0("cc", "ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread");
+void ThreadProxy::BeginMainFrameAbortedOnImplThread(bool did_handle) {
+  TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread");
   DCHECK(IsImplThread());
   DCHECK(scheduler_on_impl_thread_);
   DCHECK(scheduler_on_impl_thread_->CommitPending());
@@ -992,8 +994,8 @@
   commit_waits_for_activation_ = false;
 
   commit_complete_time_ = base::TimeTicks::HighResNow();
-  begin_frame_to_commit_duration_history_.InsertSample(
-      commit_complete_time_ - begin_frame_sent_to_main_thread_time_);
+  begin_main_frame_to_commit_duration_history_.InsertSample(
+      commit_complete_time_ - begin_main_frame_sent_time_);
 
   // SetVisible kicks off the next scheduler action, so this must be last.
   scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
@@ -1243,7 +1245,7 @@
 }
 
 base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() {
-  return begin_frame_to_commit_duration_history_.Percentile(
+  return begin_main_frame_to_commit_duration_history_.Percentile(
       kCommitAndActivationDurationEstimationPercentile);
 }
 
@@ -1254,7 +1256,7 @@
 
 void ThreadProxy::PostBeginImplFrameDeadline(const base::Closure& closure,
                                              base::TimeTicks deadline) {
-  base::TimeDelta delta = deadline - base::TimeTicks::Now();
+  base::TimeDelta delta = deadline - gfx::FrameTime::Now();
   if (delta <= base::TimeDelta())
     delta = base::TimeDelta();
   Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta);
@@ -1398,7 +1400,7 @@
   layer_tree_host_->DeleteContentsTexturesOnImplThread(
       layer_tree_host_impl_->resource_provider());
   current_resource_update_controller_on_impl_thread_.reset();
-  layer_tree_host_impl_->SetNeedsBeginFrame(false);
+  layer_tree_host_impl_->SetNeedsBeginImplFrame(false);
   scheduler_on_impl_thread_.reset();
   layer_tree_host_impl_.reset();
   weak_factory_on_impl_thread_.InvalidateWeakPtrs();
@@ -1409,12 +1411,12 @@
   return ResourceUpdateController::MaxPartialTextureUpdates();
 }
 
-ThreadProxy::BeginFrameAndCommitState::BeginFrameAndCommitState()
+ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState()
     : memory_allocation_limit_bytes(0),
       memory_allocation_priority_cutoff(0),
       evicted_ui_resources(false) {}
 
-ThreadProxy::BeginFrameAndCommitState::~BeginFrameAndCommitState() {}
+ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {}
 
 scoped_ptr<base::Value> ThreadProxy::AsValue() const {
   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
@@ -1522,6 +1524,8 @@
     priority = NEW_CONTENT_TAKES_PRIORITY;
 
   layer_tree_host_impl_->SetTreePriority(priority);
+  scheduler_on_impl_thread_->SetSmoothnessTakesPriority(
+      priority == SMOOTHNESS_TAKES_PRIORITY);
 
   // Notify the the client of this compositor via the output surface.
   // TODO(epenner): Route this to compositor-thread instead of output-surface
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 6badb03..3a213b9 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -56,6 +56,7 @@
   virtual void NotifyInputThrottledUntilCommit() OVERRIDE;
   virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
   virtual bool CommitRequested() const OVERRIDE;
+  virtual bool BeginMainFrameRequested() const OVERRIDE;
   virtual void MainThreadHasStoppedFlinging() OVERRIDE;
   virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE;
   virtual void Stop() OVERRIDE;
@@ -69,7 +70,7 @@
   // LayerTreeHostImplClient implementation
   virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE;
   virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE;
-  virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) OVERRIDE;
+  virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
   virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE;
   virtual void NotifyReadyToActivate() OVERRIDE;
   virtual void SetNeedsRedrawOnImplThread() OVERRIDE;
@@ -83,7 +84,6 @@
   virtual bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
                                                        int priority_cutoff)
       OVERRIDE;
-  virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE;
   virtual void SendManagedMemoryStats() OVERRIDE;
   virtual bool IsInsideDraw() OVERRIDE;
   virtual void RenewTreePriority() OVERRIDE;
@@ -119,9 +119,9 @@
   ThreadProxy(LayerTreeHost* layer_tree_host,
               scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
 
-  struct BeginFrameAndCommitState {
-    BeginFrameAndCommitState();
-    ~BeginFrameAndCommitState();
+  struct BeginMainFrameAndCommitState {
+    BeginMainFrameAndCommitState();
+    ~BeginMainFrameAndCommitState();
 
     base::TimeTicks monotonic_frame_begin_time;
     scoped_ptr<ScrollAndScaleSet> scroll_info;
@@ -131,8 +131,8 @@
   };
 
   // Called on main thread.
-  void BeginFrameOnMainThread(
-      scoped_ptr<BeginFrameAndCommitState> begin_frame_state);
+  void BeginMainFrame(
+      scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
   void DidCommitAndDrawFrame();
   void DidCompleteSwapBuffers();
   void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue,
@@ -150,13 +150,13 @@
   struct SchedulerStateRequest;
 
   void ForceCommitForReadbackOnImplThread(
-      CompletionEvent* begin_frame_sent_completion,
+      CompletionEvent* begin_main_frame_sent_completion,
       ReadbackRequest* request);
   void StartCommitOnImplThread(
       CompletionEvent* completion,
       ResourceUpdateQueue* queue,
       scoped_refptr<cc::ContextProvider> offscreen_context_provider);
-  void BeginFrameAbortedByMainThreadOnImplThread(bool did_handle);
+  void BeginMainFrameAbortedOnImplThread(bool did_handle);
   void RequestReadbackOnImplThread(ReadbackRequest* request);
   void FinishAllRenderingOnImplThread(CompletionEvent* completion);
   void InitializeImplOnImplThread(CompletionEvent* completion);
@@ -198,9 +198,9 @@
   bool animate_requested_;
   // Set only when SetNeedsCommit is called.
   bool commit_requested_;
-  // Set by SetNeedsCommit and SetNeedsAnimate.
+  // Set by SetNeedsAnimate, SetNeedsUpdateLayers, and SetNeedsCommit.
   bool commit_request_sent_to_impl_thread_;
-  // Set by BeginFrameOnMainThread
+  // Set by BeginMainFrame
   bool created_offscreen_context_provider_;
   base::CancelableClosure output_surface_creation_callback_;
   LayerTreeHost* layer_tree_host_;
@@ -226,7 +226,7 @@
   // Set when the main thread is waiting on a
   // ScheduledActionSendBeginMainFrame to be issued.
   CompletionEvent*
-      begin_frame_sent_to_main_thread_completion_event_on_impl_thread_;
+      begin_main_frame_sent_completion_event_on_impl_thread_;
 
   // Set when the main thread is waiting on a readback.
   ReadbackRequest* readback_request_on_impl_thread_;
@@ -248,7 +248,7 @@
   bool next_frame_is_newly_committed_frame_on_impl_thread_;
 
   bool throttle_frame_production_;
-  bool begin_frame_scheduling_enabled_;
+  bool begin_impl_frame_scheduling_enabled_;
   bool using_synchronous_renderer_compositor_;
 
   bool inside_draw_;
@@ -257,19 +257,19 @@
 
   bool defer_commits_;
   bool input_throttled_until_commit_;
-  scoped_ptr<BeginFrameAndCommitState> pending_deferred_commit_;
+  scoped_ptr<BeginMainFrameAndCommitState> pending_deferred_commit_;
 
   base::TimeTicks smoothness_takes_priority_expiration_time_;
   bool renew_tree_priority_on_impl_thread_pending_;
 
   RollingTimeDeltaHistory draw_duration_history_;
-  RollingTimeDeltaHistory begin_frame_to_commit_duration_history_;
+  RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_;
   RollingTimeDeltaHistory commit_to_activate_duration_history_;
 
   // Used for computing samples added to
-  // begin_frame_to_commit_draw_duration_history_ and
+  // begin_main_frame_to_commit_duration_history_ and
   // activation_duration_history_.
-  base::TimeTicks begin_frame_sent_to_main_thread_time_;
+  base::TimeTicks begin_main_frame_sent_time_;
   base::TimeTicks commit_complete_time_;
 
   base::WeakPtr<ThreadProxy> main_thread_weak_ptr_;
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc
index 4e0c89f..3910bc0 100644
--- a/cc/trees/tree_synchronizer_unittest.cc
+++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -552,11 +552,8 @@
   FakeProxy proxy;
   DebugScopedSetImplThread impl(&proxy);
   FakeRenderingStatsInstrumentation stats_instrumentation;
-  scoped_ptr<LayerTreeHostImpl> host_impl =
-      LayerTreeHostImpl::Create(settings,
-                                NULL,
-                                &proxy,
-                                &stats_instrumentation);
+  scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
+      settings, NULL, &proxy, &stats_instrumentation, NULL);
 
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   host_->SetRootLayer(layer_tree_root);
@@ -587,11 +584,8 @@
   FakeProxy proxy;
   DebugScopedSetImplThread impl(&proxy);
   FakeRenderingStatsInstrumentation stats_instrumentation;
-  scoped_ptr<LayerTreeHostImpl> host_impl =
-      LayerTreeHostImpl::Create(settings,
-                                NULL,
-                                &proxy,
-                                &stats_instrumentation);
+  scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
+      settings, NULL, &proxy, &stats_instrumentation, NULL);
 
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> scroll_parent = Layer::Create();
@@ -665,11 +659,8 @@
   FakeProxy proxy;
   DebugScopedSetImplThread impl(&proxy);
   FakeRenderingStatsInstrumentation stats_instrumentation;
-  scoped_ptr<LayerTreeHostImpl> host_impl =
-      LayerTreeHostImpl::Create(settings,
-                                NULL,
-                                &proxy,
-                                &stats_instrumentation);
+  scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
+      settings, NULL, &proxy, &stats_instrumentation, NULL);
 
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> clip_parent = Layer::Create();
diff --git a/chrome/DEPS b/chrome/DEPS
index 252d584..8b0aa26 100644
--- a/chrome/DEPS
+++ b/chrome/DEPS
@@ -1,10 +1,7 @@
 include_rules = [
-  "+ash",
   "+base/prefs",
   "+crypto",
   "+gpu",
-  "+jni",
-  "+leveldb",
   "+net",
   "+printing",
   "+sql",
@@ -12,30 +9,17 @@
   "-v8",
   "+v8/include",
 
-  # chrome only needs switches from cc. All usage of the compositor is from
-  # content. Definitely don't include generic stuff from cc/base here, if this
-  # is needed these files need to move to base/
-  "+cc/base/switches.h",
-
   # Limit what we include from nacl.
   "-native_client",
-  "+native_client/src/trusted/service_runtime/osx",
-  "+native_client/src/trusted/service_runtime/win",
-  "+native_client/src/shared/imc",
 
   # The subdirectories in chrome/ will manually allow their own include
   # directories in chrome/ so we disallow all of them.
   "-chrome",
   "+chrome/common",
   "+chrome/test",
-  "+components/json_schema",
-  "+components/sessions",
   "+components/variations",
-  "+components/visitedlink/common",
   "+content/public/common",
   "+content/public/test",
-  "+content/test/gpu",
-  "+content/test/net",
 
   # Don't allow inclusion of these other libs we shouldn't be calling directly.
   "-webkit",
@@ -51,9 +35,7 @@
   "+third_party/hunspell",
   "+third_party/libxml",
   "+third_party/mozilla",     # Mozilla interface headers.
-  "+third_party/npapi",       # NPAPI interface headers.
   "+third_party/skia",
-  "+third_party/tcmalloc",
   "+third_party/zlib/google",
   "+third_party/GTM",         # Google Toolbox for Mac.
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 34bee34..5abafc9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=32
 MINOR=0
-BUILD=1679
+BUILD=1688
 PATCH=0
diff --git a/chrome/android/DEPS b/chrome/android/DEPS
new file mode 100644
index 0000000..c80012b
--- /dev/null
+++ b/chrome/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+jni",
+]
diff --git a/chrome/android/host_driven_tests/OWNERS b/chrome/android/host_driven_tests/OWNERS
new file mode 100644
index 0000000..cfc5e65
--- /dev/null
+++ b/chrome/android/host_driven_tests/OWNERS
@@ -0,0 +1,9 @@
+aruslan@chromium.org
+bulach@chromium.org
+dfalcantara@chromium.org
+dtrainor@chromium.org
+miguelg@chromium.org
+nyquist@chromium.org
+skyostil@chromium.org
+tedchoc@chromium.org
+yfriedman@chromium.org
diff --git a/chrome/android/host_driven_tests/SyncTest.py b/chrome/android/host_driven_tests/SyncTest.py
index 4d55f90..e264bbe 100755
--- a/chrome/android/host_driven_tests/SyncTest.py
+++ b/chrome/android/host_driven_tests/SyncTest.py
@@ -54,8 +54,10 @@
     java_tests = ['testAboutSyncPageDisplaysCurrentSyncStatus']
     return self._RunSyncTests(java_tests)
 
-  @tests_annotations.Feature(['Sync'])
-  @tests_annotations.EnormousTest
+  # Disabled for http://crbug.com/311091
+  # @tests_annotations.Feature(['Sync'])
+  # @tests_annotations.EnormousTest
+  @tests_annotations.DisabledTest
   def testDisableAndEnableSync(self):
     java_tests = ['testDisableAndEnableSync']
     return self._RunSyncTests(java_tests)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromiumApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromiumApplication.java
index 13d82fb..2cc9b86 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromiumApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromiumApplication.java
@@ -17,4 +17,10 @@
      */
     @CalledByNative
     protected abstract void openProtectedContentSettings();
+
+    @CalledByNative
+    protected abstract void showSyncSettings();
+
+    @CalledByNative
+    protected abstract void showTermsOfServiceDialog();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NativePage.java b/chrome/android/java/src/org/chromium/chrome/browser/NativePage.java
index d4d4790..c225da8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NativePage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NativePage.java
@@ -10,6 +10,10 @@
  * An interface for pages that will be shown in a tab using Android views instead of html.
  */
 public interface NativePage extends PageInfo {
+    /**
+     * @return The URL of the page.
+     */
+    String getUrl();
 
     /**
      * @return The hostname for this page, e.g. "newtab" or "bookmarks".
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/RecentlyClosedBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/RecentlyClosedBridge.java
new file mode 100644
index 0000000..2271d5e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/RecentlyClosedBridge.java
@@ -0,0 +1,122 @@
+// Copyright 2013 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 org.chromium.base.CalledByNative;
+import org.chromium.chrome.browser.profiles.Profile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class allows Java code to get and clear the list of recently closed tabs.
+ */
+public class RecentlyClosedBridge {
+    private int mNativeRecentlyClosedTabsBridge;
+
+    /**
+     * Callback interface for getting notified when the list of recently closed tabs is updated.
+     */
+    public interface RecentlyClosedCallback {
+        /**
+         * This method will be called every time the list of recently closed tabs is updated.
+         *
+         * It's a good place to call {@link RecentlyClosedBridge#getRecentlyClosedTabs()} to get the
+         * updated list of tabs.
+         */
+        @CalledByNative("RecentlyClosedCallback")
+        void onUpdated();
+    }
+
+    /**
+     * Represents a recently closed tab.
+     */
+    public static class RecentlyClosedTab {
+        public final int id;
+        public final String title;
+        public final String url;
+
+        private RecentlyClosedTab(int id, String title, String url) {
+            this.id = id;
+            this.title = title;
+            this.url = url;
+        }
+    }
+
+    @CalledByNative
+    private static void pushTab(
+            List<RecentlyClosedTab> tabs, int id, String title, String url) {
+        RecentlyClosedTab tab = new RecentlyClosedTab(id, title, url);
+        tabs.add(tab);
+    }
+
+    /**
+     * Initializes this class with the given profile.
+     * @param profile The Profile whose recently closed tabs will be queried.
+     */
+    public RecentlyClosedBridge(Profile profile) {
+        mNativeRecentlyClosedTabsBridge = nativeInit(profile);
+    }
+
+    @Override
+    protected void finalize() {
+        // Ensure that destroy() was called.
+        assert mNativeRecentlyClosedTabsBridge == 0;
+    }
+
+    /**
+     * Cleans up the C++ side of this class. This instance must not be used after calling destroy().
+     */
+    public void destroy() {
+        assert mNativeRecentlyClosedTabsBridge != 0;
+        nativeDestroy(mNativeRecentlyClosedTabsBridge);
+    }
+
+    /**
+     * Sets the callback to be called whenever the list of recently closed tabs changes.
+     * @param callback The RecentlyClosedCallback to be notified, or null.
+     */
+    public void setRecentlyClosedCallback(RecentlyClosedCallback callback) {
+        nativeSetRecentlyClosedCallback(mNativeRecentlyClosedTabsBridge, callback);
+    }
+
+    /**
+     * @return The list of recently closed tabs.
+     */
+    public List<RecentlyClosedTab> getRecentlyClosedTabs() {
+        List<RecentlyClosedTab> tabs = new ArrayList<RecentlyClosedTab>();
+        boolean received = nativeGetRecentlyClosedTabs(mNativeRecentlyClosedTabsBridge, tabs);
+        return received ? tabs : null;
+    }
+
+    /**
+     * Opens a recently closed tab in a new tab.
+     * Note: this will change to open in the current tab once http://crbug.com/257102 is fixed.
+     *
+     * @param tab The current TabBase.
+     * @param recentTab The RecentlyClosedTab to open.
+     * @return Whether the tab was successfully opened.
+     */
+    public boolean openRecentlyClosedTab(TabBase tab, RecentlyClosedTab recentTab) {
+        return nativeOpenRecentlyClosedTab(mNativeRecentlyClosedTabsBridge, tab, recentTab.id);
+    }
+
+    /**
+     * Clears all recently closed tabs.
+     */
+    public void clearRecentlyClosedTabs() {
+        nativeClearRecentlyClosedTabs(mNativeRecentlyClosedTabsBridge);
+    }
+
+    private native int nativeInit(Profile profile);
+    private native void nativeDestroy(int nativeRecentlyClosedTabsBridge);
+    private native void nativeSetRecentlyClosedCallback(
+            int nativeRecentlyClosedTabsBridge, RecentlyClosedCallback callback);
+    private native boolean nativeGetRecentlyClosedTabs(
+            int nativeRecentlyClosedTabsBridge, List<RecentlyClosedTab> tabs);
+    private native boolean nativeOpenRecentlyClosedTab(
+            int nativeRecentlyClosedTabsBridge, TabBase tab, int recentTabId);
+    private native void nativeClearRecentlyClosedTabs(int nativeRecentlyClosedTabsBridge);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java
new file mode 100644
index 0000000..31f2b55
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java
@@ -0,0 +1,76 @@
+// Copyright 2013 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 java.lang.Runnable;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import org.chromium.chrome.R;
+
+/**
+ * Form resubmission warning dialog. Presents the cancel/continue choice and fires one of two
+ * callbacks accordingly.
+ */
+class RepostFormWarningDialog extends DialogFragment {
+    // Warning dialog currently being shown, stored for testing.
+    private static Dialog sCurrentDialog;
+
+    private final Runnable mCancelCallback;
+    private final Runnable mContinueCallback;
+
+    public RepostFormWarningDialog(Runnable cancelCallback, Runnable continueCallback) {
+        mCancelCallback = cancelCallback;
+        mContinueCallback = continueCallback;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+                .setMessage(R.string.http_post_warning)
+                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        mCancelCallback.run();
+                    }
+                })
+                .setPositiveButton(R.string.http_post_warning_resend,
+                        new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        mContinueCallback.run();
+                    }
+                });
+
+        assert getCurrentDialog() == null;
+        Dialog dialog = builder.create();
+        setCurrentDialog(dialog);
+
+        return dialog;
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        super.onDismiss(dialog);
+        setCurrentDialog(null);
+    }
+
+    /**
+     * Sets the currently displayed dialog in sCurrentDialog. This is required by findbugs, which
+     * allows static fields only to be set from static methods.
+     */
+    private static void setCurrentDialog(Dialog dialog) {
+        sCurrentDialog = dialog;
+    }
+
+    /**
+     * @return dialog currently being displayed.
+     */
+    public static Dialog getCurrentDialog() {
+        return sCurrentDialog;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
index 4a61723..e1f56db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -38,15 +39,18 @@
 
     /**
      * Adds a shortcut for the current Tab.
+     * @param appContext The application context.
      * @param tab Tab to create a shortcut for.
      * @param userRequestedTitle Updated title for the shortcut.
      */
-    public static void addShortcut(TabBase tab, String userRequestedTitle) {
+    public static void addShortcut(Context appContext, TabBase tab, String userRequestedTitle) {
         if (TextUtils.isEmpty(sFullScreenAction)) {
             Log.e("ShortcutHelper", "ShortcutHelper is uninitialized.  Aborting.");
             return;
         }
-        nativeAddShortcut(tab.getNativePtr(), userRequestedTitle);
+        ActivityManager am = (ActivityManager) appContext.getSystemService(
+                Context.ACTIVITY_SERVICE);
+        nativeAddShortcut(tab.getNativePtr(), userRequestedTitle, am.getLauncherLargeIconSize());
     }
 
     /**
@@ -91,5 +95,6 @@
         context.startActivity(homeIntent);
     }
 
-    private static native void nativeAddShortcut(int tabAndroidPtr, String userRequestedTitle);
+    private static native void nativeAddShortcut(int tabAndroidPtr, String userRequestedTitle,
+            int launcherLargeIconSize);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
index 23f99a6..08c4221 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
@@ -5,12 +5,14 @@
 package org.chromium.chrome.browser;
 
 import android.app.Activity;
+import android.app.Dialog;
 import android.content.Context;
 import android.graphics.Color;
 import android.view.View;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.ObserverList;
+import org.chromium.chrome.browser.RepostFormWarningDialog;
 import org.chromium.chrome.browser.infobar.AutoLoginProcessor;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -109,6 +111,24 @@
         }
 
         @Override
+        public void showRepostFormWarningDialog(final ContentViewCore contentViewCore) {
+            RepostFormWarningDialog warningDialog = new RepostFormWarningDialog(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            contentViewCore.cancelPendingReload();
+                        }
+                    }, new Runnable() {
+                        @Override
+                        public void run() {
+                            contentViewCore.continuePendingReload();
+                        }
+                    });
+            Activity activity = (Activity)mContext;
+            warningDialog.show(activity.getFragmentManager(), null);
+        }
+
+        @Override
         public void toggleFullscreenModeForTab(boolean enableFullscreen) {
             for (TabObserver observer: mObservers) {
                 observer.onToggleFullscreenMode(TabBase.this, enableFullscreen);
@@ -544,7 +564,7 @@
      */
     @CalledByNative
     public String getUrl() {
-        return getPageInfo() != null ? getPageInfo().getUrl() : "";
+        return mContentView != null ? mContentView.getUrl() : "";
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
index f0f04ba..89d339a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
@@ -47,6 +47,12 @@
         mNativeFaviconHelper = nativeInit();
     }
 
+    @Override
+    protected void finalize() {
+        // Ensure that destroy() was called.
+        assert mNativeFaviconHelper == 0;
+    }
+
     /**
      * Clean up the C++ side of this class. After the call, this class instance shouldn't be used.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
index 674f5d8..aa7d47f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
@@ -9,6 +9,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.os.Build;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.AccelerateDecelerateInterpolator;
@@ -233,6 +234,13 @@
             public void onAnimationEnd(Animator animation) {
                 mTargetWrapperView.finishTransition();
                 mContainer.finishTransition();
+
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && mToShow != null &&
+                        (mAnimationType == ANIMATION_TYPE_SHOW ||
+                                mAnimationType == ANIMATION_TYPE_SWAP)) {
+                        mToShow.announceForAccessibility(
+                                mInfoBar.getMessageText(mContainer.getContext()));
+                }
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
index 600b867..2bb06c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
@@ -53,8 +53,9 @@
     private boolean mIsDismissed;
     private boolean mControlsEnabled;
 
-    // TODO(miguelg) make it private and enforce it in the Confirm and Translate
-    // infobars.
+    // This cannot be private until the swap in place infrastructure is
+    // improved since subclasses need to access a possibly replaced native
+    // pointer.
     protected int mNativeInfoBarPtr;
 
     // Used by tests to reference infobars.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
index dfb1d13..510172d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
@@ -49,7 +49,6 @@
     private TranslateSubPanel mSubPanel;
     private final boolean mShouldShowNeverBar;
     private final TranslateInfoBarDelegate mTranslateDelegate;
-    private final int mNativeInfoBarPtr;
 
     public TranslateInfoBar(int nativeInfoBarPtr, TranslateInfoBarDelegate delegate,
             int infoBarType, int sourceLanguageIndex, int targetLanguageIndex,
@@ -62,7 +61,6 @@
         mInfoBarType = infoBarType;
         mShouldShowNeverBar = shouldShowNeverBar;
         mOptionsPanelViewType = NO_PANEL;
-        mNativeInfoBarPtr = nativeInfoBarPtr;
         setNativeInfoBar(nativeInfoBarPtr);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
new file mode 100644
index 0000000..a6a56da
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
@@ -0,0 +1,134 @@
+// Copyright 2013 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.invalidation;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.content.Intent;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+import org.chromium.base.ActivityStatus;
+import org.chromium.base.CalledByNative;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.chromium.sync.notifier.InvalidationIntentProtocol;
+import org.chromium.sync.notifier.InvalidationPreferences;
+import org.chromium.sync.notifier.InvalidationService;
+import org.chromium.sync.notifier.SyncStatusHelper;
+
+import java.util.Set;
+
+/**
+ * Controller used to send start, stop, and registration-change commands to the invalidation
+ * client library used by Sync.
+ */
+public class InvalidationController implements ActivityStatus.StateListener {
+    private static final Object LOCK = new Object();
+
+    private static InvalidationController sInstance;
+
+    private final Context mContext;
+
+    /**
+     * Sets the types for which the client should register for notifications.
+     *
+     * @param account  Account of the user.
+     * @param allTypes If {@code true}, registers for all types, and {@code types} is ignored
+     * @param types    Set of types for which to register. Ignored if {@code allTypes == true}.
+     */
+    public void setRegisteredTypes(Account account, boolean allTypes, Set<ModelType> types) {
+        Intent registerIntent =
+                InvalidationIntentProtocol.createRegisterIntent(account, allTypes, types);
+        registerIntent.setClass(mContext, InvalidationService.class);
+        mContext.startService(registerIntent);
+    }
+
+    /**
+     * Reads all stored preferences and calls
+     * {@link #setRegisteredTypes(android.accounts.Account, boolean, java.util.Set)} with the stored
+     * values, refreshing the set of types with {@code types}. It can be used on startup of Chrome
+     * to ensure we always have a set of registrations consistent with the native code.
+     * @param types    Set of types for which to register.
+     */
+    public void refreshRegisteredTypes(Set<ModelType> types) {
+        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
+        Set<String> savedSyncedTypes = invalidationPreferences.getSavedSyncedTypes();
+        Account account = invalidationPreferences.getSavedSyncedAccount();
+        boolean allTypes = savedSyncedTypes != null &&
+                savedSyncedTypes.contains(ModelType.ALL_TYPES_TYPE);
+        setRegisteredTypes(account, allTypes, types);
+    }
+
+    /**
+     * Sets object ids for which the client should register for notification. This is intended for
+     * registering non-Sync types; Sync types are registered with {@code setRegisteredTypes}.
+     *
+     * @param objectSources The sources of the objects.
+     * @param objectNames   The names of the objects.
+     */
+    @CalledByNative
+    public void setRegisteredObjectIds(int[] objectSources, String[] objectNames) {
+        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
+        Account account = invalidationPreferences.getSavedSyncedAccount();
+        Intent registerIntent =
+                InvalidationIntentProtocol.createRegisterIntent(
+                        account, objectSources, objectNames);
+        registerIntent.setClass(mContext, InvalidationService.class);
+        mContext.startService(registerIntent);
+    }
+
+    /**
+     * Starts the invalidation client.
+     */
+    public void start() {
+        Intent intent = new Intent(mContext, InvalidationService.class);
+        mContext.startService(intent);
+    }
+
+    /**
+     * Stops the invalidation client.
+     */
+    public void stop() {
+        Intent intent = new Intent(mContext, InvalidationService.class);
+        intent.putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
+        mContext.startService(intent);
+    }
+
+    /**
+     * Returns the instance that will use {@code context} to issue intents.
+     *
+     * Calling this method will create the instance if it does not yet exist.
+     */
+    @CalledByNative
+    public static InvalidationController get(Context context) {
+        synchronized (LOCK) {
+            if (sInstance == null) {
+                sInstance = new InvalidationController(context);
+            }
+            return sInstance;
+        }
+    }
+
+    /**
+     * Creates an instance using {@code context} to send intents.
+     */
+    @VisibleForTesting
+    InvalidationController(Context context) {
+        mContext = Preconditions.checkNotNull(context.getApplicationContext());
+        ActivityStatus.registerStateListener(this);
+    }
+
+    @Override
+    public void onActivityStateChange(int newState) {
+        if (SyncStatusHelper.get(mContext).isSyncEnabled()) {
+            if (newState == ActivityStatus.PAUSED) {
+                stop();
+            } else if (newState == ActivityStatus.RESUMED) {
+                start();
+            }
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
index d378b5d..d01b171 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
@@ -98,13 +98,6 @@
     }
 
     /**
-     * Returns a configuration string for the data reduction proxy.
-     */
-    public String getDataReductionProxyAuth() {
-        return nativeGetDataReductionProxyAuth(mNativeDataReductionProxySettings);
-    }
-
-    /**
      * Sets the preference on whether to enable/disable the SPDY proxy. This will zero out the
      * data reduction statistics if this is the first time the SPDY proxy has been enabled.
      */
@@ -139,6 +132,30 @@
     }
 
     /**
+     * Returns true if the host and realm (as passed in to Tab.onReceivedHttpAuthRequest()) are such
+     * that a authentication token can be generated. The host must match one of the configured proxy
+     * hosts, and the realm must be prefixed with the authentication realm string used by the data
+     * reduction proxies.
+     * @param host The host requesting authentication.
+     * @param realm The authentication realm.
+     * @return True if host and realm can be authenticated.
+     */
+    public boolean isAcceptableAuthChallenge(String host, String realm) {
+        return nativeIsAcceptableAuthChallenge(mNativeDataReductionProxySettings, host, realm);
+    }
+
+    /**
+     * Returns an authentication token for the data reduction proxy. If the token cannot be
+     * generated, an empty string is returned.
+     * @param host The host requesting authentication.
+     * @param realm The authentication realm.
+     * @return The generated token.
+     */
+    public String getTokenForAuthChallenge(String host, String realm) {
+        return nativeGetTokenForAuthChallenge(mNativeDataReductionProxySettings, host, realm);
+    }
+
+    /**
      * Retrieves the history of daily totals of bytes that would have been
      * received if no data reducing mechanism had been applied.
      * @return The history of daily totals
@@ -183,8 +200,6 @@
             int nativeDataReductionProxySettingsAndroid);
     private native String nativeGetDataReductionProxyOrigin(
             int nativeDataReductionProxySettingsAndroid);
-    private native String nativeGetDataReductionProxyAuth(
-            int nativeDataReductionProxySettingsAndroid);
     private native boolean nativeIsDataReductionProxyEnabled(
             int nativeDataReductionProxySettingsAndroid);
     private native boolean nativeIsDataReductionProxyManaged(
@@ -195,6 +210,10 @@
             int nativeDataReductionProxySettingsAndroid);
     private native ContentLengths nativeGetContentLengths(
             int nativeDataReductionProxySettingsAndroid);
+    private native boolean nativeIsAcceptableAuthChallenge(
+            int nativeDataReductionProxySettingsAndroid, String host, String realm);
+    private native String nativeGetTokenForAuthChallenge(
+            int nativeDataReductionProxySettingsAndroid, String host, String realm);
     private native long[] nativeGetDailyOriginalContentLengths(
             int nativeDataReductionProxySettingsAndroid);
     private native long[] nativeGetDailyReceivedContentLengths(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
index 965f58d..1908333 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -15,11 +15,12 @@
 import android.util.Log;
 
 import org.chromium.base.CalledByNative;
+import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.invalidation.InvalidationController;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.R;
 import org.chromium.sync.internal_api.pub.base.ModelType;
-import org.chromium.sync.notifier.InvalidationController;
 import org.chromium.sync.notifier.SyncStatusHelper;
 import org.chromium.sync.signin.ChromeSigninController;
 
@@ -44,6 +45,15 @@
     private final Context mContext;
     private final int mNativeSigninManagerAndroid;
 
+    /** Tracks whether the First Run check has been completed.
+     *
+     * A new sign-in can not be started while this is pending, to prevent the
+     * pending check from eventually starting a 2nd sign-in.
+     */
+    private boolean mFirstRunCheckIsPending = true;
+    private ObserverList<SignInAllowedObserver> mSignInAllowedObservers =
+            new ObserverList<SignInAllowedObserver>();
+
     private Activity mSignInActivity;
     private Account mSignInAccount;
     private Observer mSignInObserver;
@@ -55,6 +65,16 @@
     private AlertDialog mPolicyConfirmationDialog;
 
     /**
+     * SignInAllowedObservers will be notified once signing-in becomes allowed or disallowed.
+     */
+    public static interface SignInAllowedObserver {
+        /**
+         * Invoked once all startup checks are done and signing-in becomes allowed, or disallowed.
+         */
+        public void onSignInAllowedChanged();
+    }
+
+    /**
      * The Observer of startSignIn() will be notified when sign-in completes.
      */
     public static interface Observer {
@@ -95,6 +115,47 @@
     }
 
     /**
+     * Notifies the SigninManager that the First Run check has completed.
+     *
+     * The user will be allowed to sign-in once this is signaled.
+     */
+    public void onFirstRunCheckDone() {
+        mFirstRunCheckIsPending = false;
+
+        if (isSignInAllowed()) {
+            notifySignInAllowedChanged();
+        }
+    }
+
+    /**
+     * Returns true if signin can be started now.
+     */
+    public boolean isSignInAllowed() {
+        return !mFirstRunCheckIsPending &&
+                mSignInAccount == null &&
+                ChromeSigninController.get(mContext).getSignedInUser() == null;
+    }
+
+    public void addSignInAllowedObserver(SignInAllowedObserver observer) {
+        mSignInAllowedObservers.addObserver(observer);
+    }
+
+    public void removeSignInAllowedObserver(SignInAllowedObserver observer) {
+        mSignInAllowedObservers.removeObserver(observer);
+    }
+
+    private void notifySignInAllowedChanged() {
+        new Handler().post(new Runnable() {
+            @Override
+            public void run() {
+                for (SignInAllowedObserver observer : mSignInAllowedObservers) {
+                    observer.onSignInAllowedChanged();
+                }
+            }
+        });
+    }
+
+    /**
      * Starts the sign-in flow, and executes the callback when ready to proceed.
      * <p/>
      * This method checks with the native side whether the account has management enabled, and may
@@ -111,11 +172,19 @@
         assert mSignInActivity == null;
         assert mSignInAccount == null;
         assert mSignInObserver == null;
+
+        if (mFirstRunCheckIsPending) {
+            Log.w(TAG, "Ignoring sign-in request until the First Run check completes.");
+            return;
+        }
+
         mSignInActivity = activity;
         mSignInAccount = account;
         mSignInObserver = observer;
         mPassive = passive;
 
+        notifySignInAllowedChanged();
+
         if (!nativeShouldLoadPolicyForUser(account.name)) {
             // Proceed with the sign-in flow without checking for policy if it can be determined
             // that this account can't have management enabled based on the username.
@@ -228,6 +297,7 @@
         mSignInActivity = null;
         mSignInAccount = null;
         mSignInObserver = null;
+        notifySignInAllowedChanged();
     }
 
     /**
@@ -275,6 +345,7 @@
         mSignInActivity = null;
         mSignInObserver = null;
         mSignInAccount = null;
+        notifySignInAllowedChanged();
     }
 
     private void wipeProfileData(Activity activity) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
index 774d02d..4ebfac9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
@@ -511,8 +511,6 @@
     private native void nativeDisableSync(int nativeProfileSyncServiceAndroid);
     private native void nativeSignInSync(int nativeProfileSyncServiceAndroid);
     private native void nativeSignOutSync(int nativeProfileSyncServiceAndroid);
-    private native void nativeTokenAvailable(
-            int nativeProfileSyncServiceAndroid, String username, String authToken);
     private native boolean nativeSetSyncSessionsId(int nativeProfileSyncServiceAndroid, String tag);
     private native String nativeQuerySyncStatusSummary(int nativeProfileSyncServiceAndroid);
     private native int nativeGetAuthError(int nativeProfileSyncServiceAndroid);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 5686e6a..0acfa71 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -118,7 +118,7 @@
       <message name="IDS_TRANSLATE_NEVER_TRANSLATE_SITE" desc="Text to display on the never translate site (like www.google.com) button. [CHAR-LIMIT=64]">
         Never translate this site
       </message>
-      <message name="IDS_TRANSLATE_NEVER_TRANSLATE_LANGUAGE" desc="Text to display on the never translate language button. [CHAR-LIMIT=64]">
+      <message name="IDS_TRANSLATE_NEVER_TRANSLATE_LANGUAGE" meaning="Android" desc="Text to display on the never translate language button. [CHAR-LIMIT=64]">
         Never translate <ph name="LANGUAGE">%1$s<ex>French</ex></ph>
       </message>
     </messages>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
index 0e45fee..dc5ffd6 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="am">
 <translation id="1491151370853475546">ይህን ገጽ ዳግም ይጫኑ</translation>
 <translation id="7658239707568436148">ሰርዝ</translation>
+<translation id="6458785801851713928">ማመሳሰል ለእርስዎ ጎራ አይገኝም።</translation>
 <translation id="2731700343119398978">እባክዎ ይጠብቁ...</translation>
+<translation id="3358663646935160692">ይህ መለያ የሚቀናበረው በ<ph name="DOMAIN_NAME"/> ነው።
+
+በሚቀናበር መለያ እየገቡ ነው፣ ይህም የChrome መገለጫዎ ቁጥጥር ለአስተዳዳሪው ይሰጠዋል። የእርስዎ Chrome ውሂብ እስከመጨረሻው ከዚህ መለያ ጋር የተሳሰረ ይሆናል። ከዚህ መለያ ማላቀቅ አካባቢያዊውን የChrome ውሂብ ይሰርዘዋል።</translation>
+<translation id="1623104350909869708">ይህ ገጽ ተጨማሪ መገናኛዎችን እንዳይፈጥር አግድ</translation>
+<translation id="3896036286668839683">የእውቅና ማረጋገጫ መመልከቻ</translation>
+<translation id="8583805026567836021">የመለያ ውሂብን በማጽዳት ላይ</translation>
+<translation id="4170011742729630528">አገልግሎቱ አይገኝም፤ ቆይተው እንደገና ይሞክሩ።</translation>
+<translation id="8627706565932943526">የማመሳሰል ስህተት</translation>
+<translation id="3136378934686431938">እባክዎ የመግቢያ ዝርዝሮችዎን ያዘምኑ።</translation>
+<translation id="4510973599275542560">ዳግም አትጫን</translation>
 <translation id="9154176715500758432">በዚሁ ገጽ ላይ ቆይ</translation>
+<translation id="7063006564040364415">ከማመሳሰያ አገልጋዩ ጋር መገናኘት አልተቻለም።</translation>
 <translation id="6512448926095770873">ይህን ገጽ ተወው</translation>
+<translation id="7947953824732555851">ተቀበል እና ግባ</translation>
 <translation id="6040143037577758943">ዝጋ</translation>
+<translation id="5032574515228824816">ጠይቅ</translation>
 <translation id="6965382102122355670">ይሁን</translation>
+<translation id="7495038789730067783">በመለያ መግባት ያረጋግጡ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
index 9416e6a..e394add 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
@@ -3,9 +3,22 @@
 <translationbundle lang="ar">
 <translation id="1491151370853475546">إعادة تحميل هذه الصفحة</translation>
 <translation id="7658239707568436148">إلغاء</translation>
+<translation id="6458785801851713928">المزامنة غير متاحة لنطاقك.</translation>
 <translation id="2731700343119398978">يرجى الانتظار...</translation>
+<translation id="3358663646935160692">‏تتم إدارة هذا الحساب من خلال <ph name="DOMAIN_NAME"/>. لقد سجلت دخولك باستخدام حساب مُدار تمنح المشرف عليه إمكانية التحكم في ملفك الشخصي على Chrome. ستظل بياناتك على Chrome مرتبطة دائمًا بهذا الحساب. ويؤدي إلغاء الربط بهذا الحساب إلى حذف بيانات Chrome المحلية.</translation>
+<translation id="1623104350909869708">منع هذه الصفحة من إنشاء مربعات حوار إضافية.</translation>
+<translation id="3896036286668839683">عارض الشهادات</translation>
+<translation id="8583805026567836021">محو بيانات الحساب</translation>
+<translation id="4170011742729630528">الخدمة غير متاحة، أعد المحاولة لاحقًا.</translation>
+<translation id="8627706565932943526">حدث خطأ أثناء المزامنة</translation>
+<translation id="3136378934686431938">الرجاء تحديث تفاصيل تسجيل الدخول.</translation>
+<translation id="4510973599275542560">عدم إعادة التحميل</translation>
 <translation id="9154176715500758432">البقاء في هذه الصفحة</translation>
+<translation id="7063006564040364415">تعذر الاتصال بخادم المزامنة.</translation>
 <translation id="6512448926095770873">مغادرة هذه الصفحة</translation>
+<translation id="7947953824732555851">قبول وتسجيل الدخول</translation>
 <translation id="6040143037577758943">إغلاق</translation>
+<translation id="5032574515228824816">مطالبة</translation>
 <translation id="6965382102122355670">موافق</translation>
+<translation id="7495038789730067783">تأكيد تسجيل الدخول</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
index 07c8e07..fc1daeb 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="bg">
 <translation id="1491151370853475546">Презареждане на тази страница</translation>
 <translation id="7658239707568436148">Отказ</translation>
+<translation id="6458785801851713928">Синхронизирането не е налице за домейна ви.</translation>
 <translation id="2731700343119398978">Моля, изчакайте...</translation>
+<translation id="3358663646935160692">Този профил се управлява от <ph name="DOMAIN_NAME"/>.
+
+Влизате с управляван профил и давате на администратора му контрол над потребителския си профил в Chrome. Данните ви в браузъра ще бъдат свързани за постоянно с този профил. Прекъсването на връзката с него ще изтрие локалната информация в Chrome.</translation>
+<translation id="1623104350909869708">Да не се създават допълнителни диалогови прозорци от тази страница</translation>
+<translation id="3896036286668839683">Визуализатор на сертификатите</translation>
+<translation id="8583805026567836021">Данните от профила се изчистват</translation>
+<translation id="4170011742729630528">Няма достъп до услугата. Опитайте отново по-късно.</translation>
+<translation id="8627706565932943526">Грешка при синхронизирането</translation>
+<translation id="3136378934686431938">Моля, актуализирайте данните си за вход.</translation>
+<translation id="4510973599275542560">Без презареждане</translation>
 <translation id="9154176715500758432">Нека остана на тази страница</translation>
+<translation id="7063006564040364415">Не можа да се установи връзка със синхронизиращия сървър.</translation>
 <translation id="6512448926095770873">Излизане от тази страница</translation>
+<translation id="7947953824732555851">Приемам и влизам</translation>
 <translation id="6040143037577758943">Затваряне</translation>
+<translation id="5032574515228824816">Подкана</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Потвърждаване на влизането в профила</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
index 41bb1c3..92cebbf 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="ca">
 <translation id="1491151370853475546">Torna a carregar aquesta pàgina</translation>
 <translation id="7658239707568436148">Cancel·la</translation>
+<translation id="6458785801851713928">La sincronització no està disponible per al vostre domini.</translation>
 <translation id="2731700343119398978">Espereu...</translation>
+<translation id="3358663646935160692"><ph name="DOMAIN_NAME"/> s'encarrega de gestionar aquest compte.
+
+Inicieu la sessió amb un compte gestionat, de manera que concediu al seu administrador el control sobre el vostre perfil de Chrome. Les vostres dades de Chrome estaran vinculades a aquest compte de manera permanent. Si desconnecteu aquest compte se suprimiran les dades de Chrome locals.</translation>
+<translation id="1623104350909869708">Impedeix que aquesta pàgina creï diàlegs addicionals.</translation>
+<translation id="3896036286668839683">Lector de certificats</translation>
+<translation id="8583805026567836021">S'estan esborrant les dades del compte</translation>
+<translation id="4170011742729630528">El servei no està disponible. Torneu-ho a provar més tard.</translation>
+<translation id="8627706565932943526">Error de sincronització</translation>
+<translation id="3136378934686431938">Actualitzeu les dades d'inici de sessió.</translation>
+<translation id="4510973599275542560">No tornis a carregar</translation>
 <translation id="9154176715500758432">Roman en aquesta pàgina</translation>
+<translation id="7063006564040364415">No s'ha pogut connectar amb el servidor de sincronització.</translation>
 <translation id="6512448926095770873">Abandona aquesta pàgina</translation>
+<translation id="7947953824732555851">Acc. i inicia sessió</translation>
 <translation id="6040143037577758943">Tanca</translation>
+<translation id="5032574515228824816">Sol·licitud</translation>
 <translation id="6965382102122355670">D'acord</translation>
+<translation id="7495038789730067783">Confirmació de l'inici de sessió</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
index ab3b88d..6acc383 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="cs">
 <translation id="1491151370853475546">Načíst tuto stránku znovu</translation>
 <translation id="7658239707568436148">Zrušit</translation>
+<translation id="6458785801851713928">Synchronizace není pro vaši doménu k dispozici.</translation>
 <translation id="2731700343119398978">Počkejte prosím...</translation>
+<translation id="3358663646935160692">Tento účet spravuje <ph name="DOMAIN_NAME"/>.
+
+Přihlašujete se pomocí spravovaného účtu a poskytujete jeho správci kontrolu nad vaším profilem Chrome. Údaje Chrome budou trvale přidruženy k tomuto účtu. Odpojením od tohoto účtu budou místní údaje Chrome trvale smazány.</translation>
+<translation id="1623104350909869708">Bránit této stránce ve vytváření dalších dialogových oken</translation>
+<translation id="3896036286668839683">Prohlížeč certifikátů</translation>
+<translation id="8583805026567836021">Mazání dat účtu</translation>
+<translation id="4170011742729630528">Služba není k dispozici, zkuste to později.</translation>
+<translation id="8627706565932943526">Chyba synchronizace</translation>
+<translation id="3136378934686431938">Aktualizujte prosím své přihlašovací údaje.</translation>
+<translation id="4510973599275542560">Nenačítat znovu</translation>
 <translation id="9154176715500758432">Zůstat na této stránce</translation>
+<translation id="7063006564040364415">K synchronizačnímu serveru se nelze připojit.</translation>
 <translation id="6512448926095770873">Opustit tuto stránku</translation>
+<translation id="7947953824732555851">Přijmout a přihlásit</translation>
 <translation id="6040143037577758943">Zavřít</translation>
+<translation id="5032574515228824816">Výzva</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Potvrdit přihlášení</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
index 27f5cba..2d72499 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="da">
 <translation id="1491151370853475546">Genindlæs denne side</translation>
 <translation id="7658239707568436148">Annuller</translation>
+<translation id="6458785801851713928">Synkronisering er ikke tilgængelig for dit domæne.</translation>
 <translation id="2731700343119398978">Vent et øjeblik...</translation>
+<translation id="3358663646935160692">Denne konto administreres af <ph name="DOMAIN_NAME"/>.
+
+Du logger ind med en administreret konto, og du giver administratoren kontrol over din Chrome-profil. Dine Chrome-data vil blive knyttet permanent til denne konto. Hvis du logger ud af denne konto, slettes de lokale Chrome-data.</translation>
+<translation id="1623104350909869708">Undgå, at denne side opretter yderligere dialogbokse</translation>
+<translation id="3896036286668839683">Certifikatvisning</translation>
+<translation id="8583805026567836021">Kontodataene ryddes</translation>
+<translation id="4170011742729630528">Tjenesten er ikke tilgængelig. Prøv igen senere.</translation>
+<translation id="8627706565932943526">Synkroniseringsfejl</translation>
+<translation id="3136378934686431938">Opdater dine loginoplysninger.</translation>
+<translation id="4510973599275542560">Genindlæs ikke siden</translation>
 <translation id="9154176715500758432">Bliv på denne side</translation>
+<translation id="7063006564040364415">Der kunne ikke oprettes forbindelse til synkroniseringsserveren.</translation>
 <translation id="6512448926095770873">Forlad denne side</translation>
+<translation id="7947953824732555851">Acceptér og log ind</translation>
 <translation id="6040143037577758943">Luk</translation>
+<translation id="5032574515228824816">Meddelelse</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Bekræft login</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
index 7dba50f..8834007 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="de">
 <translation id="1491151370853475546">Diese Seite aktualisieren</translation>
 <translation id="7658239707568436148">Abbrechen</translation>
+<translation id="6458785801851713928">Die Synchronisierung ist für Ihre Domain nicht verfügbar.</translation>
 <translation id="2731700343119398978">Bitte warten...</translation>
+<translation id="3358663646935160692">Dieses Konto wird von <ph name="DOMAIN_NAME"/> verwaltet.
+
+Sie melden sich gerade mit einem verwalteten Konto an und geben dem Administrator des Kontos Kontrolle über Ihr Chrome-Profil. Ihre Chrome-Daten werden dauerhaft mit diesem Konto verknüpft. Wenn Sie sich aus diesem Konto abmelden, werden alle lokalen Chrome-Daten gelöscht.</translation>
+<translation id="1623104350909869708">Keine weiteren Dialogfelder auf dieser Seite zulassen</translation>
+<translation id="3896036286668839683">Zertifikats-Viewer</translation>
+<translation id="8583805026567836021">Kontodaten werden gelöscht</translation>
+<translation id="4170011742729630528">Der Dienst ist momentan nicht verfügbar. Bitte versuchen Sie es später erneut.</translation>
+<translation id="8627706565932943526">Synchronisierungsfehler</translation>
+<translation id="3136378934686431938">Bitte aktualisieren Sie Ihre Anmeldeinformationen.</translation>
+<translation id="4510973599275542560">Nicht aktualisieren</translation>
 <translation id="9154176715500758432">Auf dieser Seite bleiben</translation>
+<translation id="7063006564040364415">Verbindung zum Synchronisierungsserver konnte nicht hergestellt werden.</translation>
 <translation id="6512448926095770873">Diese Seite verlassen</translation>
+<translation id="7947953824732555851">Annehmen und anmelden</translation>
 <translation id="6040143037577758943">Schließen</translation>
+<translation id="5032574515228824816">Eingabeaufforderung</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Anmeldung bestätigen</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
index 823659d..66b3b57 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="el">
 <translation id="1491151370853475546">Εκ νέου φόρτωση αυτής της σελίδας</translation>
 <translation id="7658239707568436148">Ακύρωση</translation>
+<translation id="6458785801851713928">Η υπηρεσία συγχρονισμού δεν είναι διαθέσιμη για τον τομέα σας.</translation>
 <translation id="2731700343119398978">Περιμένετε…</translation>
+<translation id="3358663646935160692">Αυτός ο λογαριασμός τελεί υπό διαχείριση του <ph name="DOMAIN_NAME"/>.
+ 
+Έχετε συνδεθεί με έναν διαχειριζόμενο λογαριασμό και παραχωρείτε τον έλεχγο διαχείρισής του μέσω του προφίλ σας Chrome. Τα δεδομένα σας Chrome θα συσχετιστούν μόνιμα με αυτόν το λογαριασμό. Η αποσύνδεση από αυτόν το λογαριασμό θα διαγράψει τα τοπικά δεδομένα Chrome.</translation>
+<translation id="1623104350909869708">Αποτροπή δημιουργίας πρόσθετων παραθύρων διαλόγου από αυτήν τη σελίδα</translation>
+<translation id="3896036286668839683">Πρόγραμμα προβ. πιστοποιητικού</translation>
+<translation id="8583805026567836021">Διαγραφή δεδομένων λογαριασμού</translation>
+<translation id="4170011742729630528">Η υπηρεσία δεν είναι διαθέσιμη. Δοκιμάστε ξανά αργότερα.</translation>
+<translation id="8627706565932943526">Σφάλμα συγχρονισμού</translation>
+<translation id="3136378934686431938">Ενημερώστε τις λεπτομέρειες της σύνδεσής σας.</translation>
+<translation id="4510973599275542560">Να μην γίνει επαναφ.</translation>
 <translation id="9154176715500758432">Παραμονή σε αυτή τη σελίδα</translation>
+<translation id="7063006564040364415">Δεν ήταν δυνατή η σύνδεση στον διακομιστή συγχρονισμού.</translation>
 <translation id="6512448926095770873">Έξοδος από αυτή τη σελίδα</translation>
+<translation id="7947953824732555851">Αποδοχή και σύνδεση</translation>
 <translation id="6040143037577758943">Κλείσιμο</translation>
+<translation id="5032574515228824816">Προτροπή</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Επιβεβαίωση σύνδεσης</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
index c8149d0..be8ad75 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="en-GB">
 <translation id="1491151370853475546">Reload this Page</translation>
 <translation id="7658239707568436148">Cancel</translation>
+<translation id="6458785801851713928">Sync is not available for your domain.</translation>
 <translation id="2731700343119398978">Please wait...</translation>
+<translation id="3358663646935160692">This account is managed by <ph name="DOMAIN_NAME"/>.
+
+You are signing in with a managed account and giving its administrator control over your Chrome profile. Your Chrome data will become permanently tied to this account. Disconnecting from this account will delete the local Chrome data.</translation>
+<translation id="1623104350909869708">Prevent this page from creating additional dialogues</translation>
+<translation id="3896036286668839683">Certificate Viewer</translation>
+<translation id="8583805026567836021">Clearing account data</translation>
+<translation id="4170011742729630528">The service is not available; try again later.</translation>
+<translation id="8627706565932943526">Sync error</translation>
+<translation id="3136378934686431938">Please update your sign in details.</translation>
+<translation id="4510973599275542560">Don't reload</translation>
 <translation id="9154176715500758432">Stay on this Page</translation>
+<translation id="7063006564040364415">Could not connect to the sync server.</translation>
 <translation id="6512448926095770873">Leave this Page</translation>
+<translation id="7947953824732555851">Accept and sign in</translation>
 <translation id="6040143037577758943">Close</translation>
+<translation id="5032574515228824816">Prompt</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Confirm sign in</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
index eaaa806..090b8b9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="es-419">
 <translation id="1491151370853475546">Volver a cargar esta página</translation>
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="6458785801851713928">Tu dominio no admite la sincronización.</translation>
 <translation id="2731700343119398978">Espera...</translation>
+<translation id="3358663646935160692">Esta cuenta está administrada por <ph name="DOMAIN_NAME"/>.
+
+Vas a acceder con una cuenta administrada, lo que significa que proporcionarás control sobre tu perfil de Chrome al administrador. Los datos de Chrome que tengas se vincularán de forma permanente a esta cuenta. Si la desconectas, se eliminarán los datos locales de Chrome.</translation>
+<translation id="1623104350909869708">Evitar que esta página cree cuadros de diálogo adicionales</translation>
+<translation id="3896036286668839683">Visualizador de certificados</translation>
+<translation id="8583805026567836021">Borrando datos de cuenta</translation>
+<translation id="4170011742729630528">El servicio no se encuentra disponible; vuelve a intentarlo más tarde.</translation>
+<translation id="8627706565932943526">Error al sincronizar</translation>
+<translation id="3136378934686431938">Actualiza tus detalles de acceso.</translation>
+<translation id="4510973599275542560">No volver a cargar</translation>
 <translation id="9154176715500758432">Permanecer en esta página</translation>
+<translation id="7063006564040364415">No se pudo establecer conexión con el servidor de sincronización.</translation>
 <translation id="6512448926095770873">Abandonar esta página</translation>
+<translation id="7947953824732555851">Aceptar y acceder</translation>
 <translation id="6040143037577758943">Cerrar</translation>
+<translation id="5032574515228824816">Solicitud</translation>
 <translation id="6965382102122355670">Aceptar</translation>
+<translation id="7495038789730067783">Confirmar acceso</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
index 796c24b..8c17fa9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="es">
 <translation id="1491151370853475546">Volver a cargar esta página</translation>
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="6458785801851713928">La función de sincronización no está disponible para tu dominio.</translation>
 <translation id="2731700343119398978">Espera...</translation>
+<translation id="3358663646935160692">Esta cuenta está administrada por <ph name="DOMAIN_NAME"/>.
+
+Vas a iniciar sesión con una cuenta administrada, lo que significa que proporcionarás a su administrador control sobre tu perfil de Google Chrome. Tus datos de Chrome se vincularán de forma permanente a esta cuenta. Si desconectas esta cuenta, se eliminarán los datos locales de Chrome.</translation>
+<translation id="1623104350909869708">Evitar que esta página cree cuadros de diálogo adicionales</translation>
+<translation id="3896036286668839683">Visor de certificados</translation>
+<translation id="8583805026567836021">Borrando datos de cuenta</translation>
+<translation id="4170011742729630528">El servicio no está disponible. Vuelve a intentarlo más tarde.</translation>
+<translation id="8627706565932943526">Error de sincronización</translation>
+<translation id="3136378934686431938">Actualiza tus datos de inicio de sesión.</translation>
+<translation id="4510973599275542560">No volver a cargar</translation>
 <translation id="9154176715500758432">Permanecer en esta página</translation>
+<translation id="7063006564040364415">No ha sido posible establecer conexión con el servidor de sincronización.</translation>
 <translation id="6512448926095770873">Abandonar esta página</translation>
+<translation id="7947953824732555851">Aceptar y acceder</translation>
 <translation id="6040143037577758943">Cerrar</translation>
+<translation id="5032574515228824816">Datos solicitados</translation>
 <translation id="6965382102122355670">Aceptar</translation>
+<translation id="7495038789730067783">Confirmar inicio de sesión</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
index 3e74d4c..0779987 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
@@ -3,9 +3,22 @@
 <translationbundle lang="fa">
 <translation id="1491151370853475546">بارگیری مجدد این صفحه</translation>
 <translation id="7658239707568436148">لغو</translation>
+<translation id="6458785801851713928">همگام‌سازی برای دامنه شما در دسترس نیست.</translation>
 <translation id="2731700343119398978">لطفاً صبر کنید...</translation>
+<translation id="3358663646935160692">‏این حساب توسط <ph name="DOMAIN_NAME"/> مدیریت می‌شود. شما با یک حساب مدیریت شده وارد سیستم شده‌اید و به سرپرست این حساب اجازه کنترل نمایه Chrome خود را می‌دهید. اطلاعات Chrome شما به صورت دائم با این حساب مرتبط می‌شود. با قطع ارتباط از این حساب، کلیه اطلاعات Chrome شما در دستگاه حذف می‌شود.</translation>
+<translation id="1623104350909869708">جلوگیری از ایجاد پنجره‌های اضافی توسط این صفحه</translation>
+<translation id="3896036286668839683">نمایشگر گواهی</translation>
+<translation id="8583805026567836021">پاکسازی اطلاعات حساب</translation>
+<translation id="4170011742729630528">این سرویس در دسترس نیست؛ بعداً دوباره امتحان کنید.</translation>
+<translation id="8627706565932943526">خطای همگام‌سازی</translation>
+<translation id="3136378934686431938">لطفاً جزئیات ورود به سیستمتان را به‌روز کنید.</translation>
+<translation id="4510973599275542560">تازه‌سازی نشود</translation>
 <translation id="9154176715500758432">ماندن در این صفحه</translation>
+<translation id="7063006564040364415">اتصال به سرور همگام‌سازی ممکن نیست.</translation>
 <translation id="6512448926095770873">ترک کردن این صفحه</translation>
+<translation id="7947953824732555851">پذیرش و ورود به سیستم</translation>
 <translation id="6040143037577758943">بستن</translation>
+<translation id="5032574515228824816">فرمان</translation>
 <translation id="6965382102122355670">تأیید</translation>
+<translation id="7495038789730067783">تأیید ورود به سیستم</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
index d563175..874b73f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="fi">
 <translation id="1491151370853475546">Päivitä tämä sivu</translation>
 <translation id="7658239707568436148">Peruuta</translation>
+<translation id="6458785801851713928">Synkronointi ei ole käytettävissä verkkotunnuksessasi.</translation>
 <translation id="2731700343119398978">Odota...</translation>
+<translation id="3358663646935160692">Tätä tiliä hallinnoi <ph name="DOMAIN_NAME"/>.
+
+Olet kirjautumassa hallinnoituun tiliin, jonka hallinnoijalla on oikeus muokata Chrome-profiiliasi. Chrome-tietosi yhdistetään tähän tiliin pysyvästi. Jos irrotat Chrome-tiedot tilistä, paikalliset Chrome-tiedot poistetaan.</translation>
+<translation id="1623104350909869708">Estä tätä sivua luomasta muita viestejä</translation>
+<translation id="3896036286668839683">Varmennetiedot</translation>
+<translation id="8583805026567836021">Poistetaan tilin tietoja</translation>
+<translation id="4170011742729630528">Palvelu ei ole käytettävissä. Yritä myöhemmin uudelleen.</translation>
+<translation id="8627706565932943526">Synkronointivirhe</translation>
+<translation id="3136378934686431938">Päivitä kirjautumistietosi.</translation>
+<translation id="4510973599275542560">Älä päivitä</translation>
 <translation id="9154176715500758432">Pysy tällä sivulla</translation>
+<translation id="7063006564040364415">Synkronointipalvelimeen ei saada yhteyttä.</translation>
 <translation id="6512448926095770873">Poistu tältä sivulta</translation>
+<translation id="7947953824732555851">Hyväksy ja kirjaudu sisään</translation>
 <translation id="6040143037577758943">Sulje</translation>
+<translation id="5032574515228824816">Kehote</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Vahvista kirjautuminen</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
index 8ea511e..1c00e76 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="fil">
 <translation id="1491151370853475546">I-reload ang Pahinang Ito</translation>
 <translation id="7658239707568436148">Kanselahin</translation>
+<translation id="6458785801851713928">Hindi available ang pag-sync para sa iyong domain.</translation>
 <translation id="2731700343119398978">Mangyaring maghintay...</translation>
+<translation id="3358663646935160692">Pinamamahalaan ang account na ito ng <ph name="DOMAIN_NAME"/>.
+
+Nagsa-sign in ka sa isang pinamamahalaang account at nagbibigay sa administrator nito ng kontrol sa iyong profile sa Chrome. Permanenteng mauugnay ang iyong data ng Chrome sa account na ito. Ang pagdiskonekta mula sa account na ito ay magtatanggal sa lokal na data ng Chrome.</translation>
+<translation id="1623104350909869708">Pigilan ang pahinang ito sa paggawa ng mga karagdagang dialog</translation>
+<translation id="3896036286668839683">Viewer ng Certificate</translation>
+<translation id="8583805026567836021">Kini-clear ang data ng account</translation>
+<translation id="4170011742729630528">Hindi available ang serbisyo; subukang muli sa ibang pagkakataon.</translation>
+<translation id="8627706565932943526">Error sa pag-sync</translation>
+<translation id="3136378934686431938">Paki-update ang iyong mga detalye sa pag-sign in.</translation>
+<translation id="4510973599275542560">Huwag i-reload</translation>
 <translation id="9154176715500758432">Manatili sa Pahinang ito</translation>
+<translation id="7063006564040364415">Hindi makakonekta sa server ng pag-sync.</translation>
 <translation id="6512448926095770873">Iwanan ang Pahinang ito</translation>
+<translation id="7947953824732555851">I-accept, mag-sign in</translation>
 <translation id="6040143037577758943">Isara</translation>
+<translation id="5032574515228824816">I-prompt</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Kumpirmahin ang pag-sign in</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
index 35bb684..aee0b5b 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="fr">
 <translation id="1491151370853475546">Actualiser cette page</translation>
 <translation id="7658239707568436148">Annuler</translation>
+<translation id="6458785801851713928">La synchronisation n'est pas disponible pour votre domaine.</translation>
 <translation id="2731700343119398978">Veuillez patienter…</translation>
+<translation id="3358663646935160692">Ce compte est géré par <ph name="DOMAIN_NAME"/>.
+
+Vous vous connectez avec un compte géré, et vous donnez à l'administrateur le contrôle de votre profil Google Chrome. Vos données Chrome vont être associées à ce compte de manière définitive. Si vous vous en déconnectez, les données Chrome locales sont supprimées.</translation>
+<translation id="1623104350909869708">Empêcher cette page de générer des boîtes de dialogue supplémentaires</translation>
+<translation id="3896036286668839683">Lecteur de certificats</translation>
+<translation id="8583805026567836021">Suppression des données du compte</translation>
+<translation id="4170011742729630528">Service indisponible. Veuillez réessayer plus tard.</translation>
+<translation id="8627706565932943526">Erreur de synchronisation.</translation>
+<translation id="3136378934686431938">Veuillez mettre à jour vos informations de connexion.</translation>
+<translation id="4510973599275542560">Ne pas actualiser</translation>
 <translation id="9154176715500758432">Rester sur cette page</translation>
+<translation id="7063006564040364415">Impossible de se connecter au serveur de synchronisation.</translation>
 <translation id="6512448926095770873">Quitter cette page</translation>
+<translation id="7947953824732555851">Accepter/Se connecter</translation>
 <translation id="6040143037577758943">Fermer</translation>
+<translation id="5032574515228824816">Invite</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Confirmer la connexion</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
index 356d15f..ce2c924 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="hi">
 <translation id="1491151370853475546">यह पृष्ठ पुन: लोड करें</translation>
 <translation id="7658239707568436148">रद्द करें</translation>
+<translation id="6458785801851713928">आपके डोमेन के लिए समन्‍वयन उपलब्‍ध नहीं है.</translation>
 <translation id="2731700343119398978">कृपया प्रतीक्षा करें...</translation>
+<translation id="3358663646935160692">यह खाता <ph name="DOMAIN_NAME"/> द्वारा प्रबंधित है.
+
+आप प्रबंधित खाते से प्रवेश कर रहे हैं और अपनी Chrome प्रोफ़ाइल को इसका व्यवस्थापक नियंत्रण दे रहे हैं. आपका Chrome डेटा इस खाते से स्थायी रूप से जुड़ जाएगा. इस खाते से डिस्कनेक्ट करने से स्थानीय Chrome डेटा हट जाएगा.</translation>
+<translation id="1623104350909869708">इस पृष्ठ को अतिरिक्त संवाद बनाने से रोकें</translation>
+<translation id="3896036286668839683">प्रमाणपत्र व्यूअर</translation>
+<translation id="8583805026567836021">खाते का डेटा साफ़ हो रहा है</translation>
+<translation id="4170011742729630528">सेवा उपलब्ध नहीं है; बाद में पुन: प्रयास करें.</translation>
+<translation id="8627706565932943526">समन्वयन त्रुटि</translation>
+<translation id="3136378934686431938">कृपया अपने प्रवेश विवरण अपडेट करें.</translation>
+<translation id="4510973599275542560">पुनः लोड न करें</translation>
 <translation id="9154176715500758432">इस पृष्ठ पर बनें रहें</translation>
+<translation id="7063006564040364415">समन्‍वयन सर्वर से कनेक्‍ट नहीं किया जा सका.</translation>
 <translation id="6512448926095770873">इस पृष्ठ से जाएं</translation>
+<translation id="7947953824732555851">स्वीकार करें और प्रवेश करें</translation>
 <translation id="6040143037577758943">बंद करें</translation>
+<translation id="5032574515228824816">शीघ्र</translation>
 <translation id="6965382102122355670">ठीक</translation>
+<translation id="7495038789730067783">प्रवेश की पुष्टि करें</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
index 3a092f7..08e05ea 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="hr">
 <translation id="1491151370853475546">Ponovo učitaj ovu stranicu</translation>
 <translation id="7658239707568436148">Odustani</translation>
+<translation id="6458785801851713928">Sinkronizacija nije dostupna za vašu domenu.</translation>
 <translation id="2731700343119398978">Pričekajte...</translation>
+<translation id="3358663646935160692">Ovim računom upravlja domena <ph name="DOMAIN_NAME"/>.
+
+Prijavljujete se svojim upravljanim računom i njenom administratoru dajete nadzor nad svojim Chrome profilom. Vaši podaci na Chromeu bit će trajno povezani s ovim računom. Prekidanje veze s ovim računom dovest će do brisanja lokalnih podataka na Chromeu.</translation>
+<translation id="1623104350909869708">Spriječi da ova stranica stvori dodatne dijaloške okvire</translation>
+<translation id="3896036286668839683">Preglednik certifikata</translation>
+<translation id="8583805026567836021">Brisanje podataka računa</translation>
+<translation id="4170011742729630528">Usluga nije dostupna, pokušajte ponovo kasnije.</translation>
+<translation id="8627706565932943526">Pogreška sinkronizacije</translation>
+<translation id="3136378934686431938">Ažurirajte pojedinosti prijave.</translation>
+<translation id="4510973599275542560">Ne učitavaj ponovo</translation>
 <translation id="9154176715500758432">Ostani na ovoj stranici</translation>
+<translation id="7063006564040364415">Nije uspjelo povezivanje s poslužiteljem za sinkronizaciju.</translation>
 <translation id="6512448926095770873">Zatvori ovu stranicu</translation>
+<translation id="7947953824732555851">Prihv. i prijavi se</translation>
 <translation id="6040143037577758943">Zatvori</translation>
+<translation id="5032574515228824816">Upit</translation>
 <translation id="6965382102122355670">U redu</translation>
+<translation id="7495038789730067783">Potvrda prijave</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
index e3a265d..1634611 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="hu">
 <translation id="1491151370853475546">Az oldal újratöltése</translation>
 <translation id="7658239707568436148">Mégse</translation>
+<translation id="6458785801851713928">A szinkronizálási szolgáltatás az Ön domainjén nem érhető el.</translation>
 <translation id="2731700343119398978">Kérjük, várjon...</translation>
+<translation id="3358663646935160692">Ennek a fióknak <ph name="DOMAIN_NAME"/> a kezelője.
+
+Ön jelenleg kezelt fiókkal jelentkezik be, és engedélyezi a rendszergazdának az Ön Chrome-profiljához való hozzáférést. Chrome-adatai ezután véglegesen ehhez a fiókhoz társulnak. A fiók leválasztásával törölheti a helyi Chrome-adatokat.</translation>
+<translation id="1623104350909869708">Akadályozza meg, hogy ez az oldal további párbeszédablakokat hozzon létre.</translation>
+<translation id="3896036286668839683">Tanúsítványmegtekintő</translation>
+<translation id="8583805026567836021">Fiókadatok törlése</translation>
+<translation id="4170011742729630528">A szolgáltatás nem érhető el, próbálja újra később.</translation>
+<translation id="8627706565932943526">Szinkronizálási hiba</translation>
+<translation id="3136378934686431938">Kérjük, frissítse bejelentkezési adatait.</translation>
+<translation id="4510973599275542560">Ne töltse újra</translation>
 <translation id="9154176715500758432">Maradok ezen az oldalon</translation>
+<translation id="7063006564040364415">Nem sikerült csatlakozni a szinkronizálószerverhez.</translation>
 <translation id="6512448926095770873">Az oldal elhagyása</translation>
+<translation id="7947953824732555851">Elfogadás és bejelentkezés</translation>
 <translation id="6040143037577758943">Bezárás</translation>
+<translation id="5032574515228824816">Parancssor</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Bejelentkezés megerősítése</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
index 2b541ef..8665757 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="id">
 <translation id="1491151370853475546">Muat Ulang Laman Ini</translation>
 <translation id="7658239707568436148">Batal</translation>
+<translation id="6458785801851713928">Sinkronisasi tidak tersedia untuk domain Anda.</translation>
 <translation id="2731700343119398978">Harap tunggu...</translation>
+<translation id="3358663646935160692">Akun ini dikelola oleh <ph name="DOMAIN_NAME"/>.
+
+Anda masuk dengan akun yang dikelola dan memberikan administratornya kontrol atas profil Chrome Anda. Data Chrome Anda akan terikat dengan akun ini secara permanen. Memutuskan tautan dengan akun ini akan menghapus data Chrome lokal.</translation>
+<translation id="1623104350909869708">Cegah dialog lain dari laman ini.</translation>
+<translation id="3896036286668839683">Penampil Sertifikat</translation>
+<translation id="8583805026567836021">Menghapus data akun</translation>
+<translation id="4170011742729630528">Layanan tidak tersedia; coba lagi nanti.</translation>
+<translation id="8627706565932943526">Kesalahan sinkronisasi</translation>
+<translation id="3136378934686431938">Perbarui detail proses masuk Anda.</translation>
+<translation id="4510973599275542560">Jangan muat ulang</translation>
 <translation id="9154176715500758432">Tetap di Laman ini</translation>
+<translation id="7063006564040364415">Tidak dapat menyambung ke server sinkronisasi.</translation>
 <translation id="6512448926095770873">Keluar dari Laman</translation>
+<translation id="7947953824732555851">Terima dan masuk</translation>
 <translation id="6040143037577758943">Tutup</translation>
+<translation id="5032574515228824816">Meminta</translation>
 <translation id="6965382102122355670">Oke</translation>
+<translation id="7495038789730067783">Konfirmasi info masuk</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
index 46b633b..dceb6cf 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="it">
 <translation id="1491151370853475546">Ricarica questa pagina</translation>
 <translation id="7658239707568436148">Annulla</translation>
+<translation id="6458785801851713928">Il servizio di sincronizzazione non è disponibile per il tuo dominio.</translation>
 <translation id="2731700343119398978">Attendi...</translation>
+<translation id="3358663646935160692">Questo account è gestito da <ph name="DOMAIN_NAME"/>.
+
+Stai per eseguire l'accesso con un account gestito e consentire al relativo amministratore di controllare il tuo profilo Chrome. I tuoi dati di Chrome verranno associati definitivamente a questo account. La disconnessione dall'account comporterà l'eliminazione dei dati di Chrome locali.</translation>
+<translation id="1623104350909869708">Impedisci la creazione di altre finestre di dialogo in questa pagina</translation>
+<translation id="3896036286668839683">Visualizzatore certificati</translation>
+<translation id="8583805026567836021">Cancellazione dati dell'account</translation>
+<translation id="4170011742729630528">Il servizio non è disponibile, riprova più tardi.</translation>
+<translation id="8627706565932943526">Errore di sincronizzazione</translation>
+<translation id="3136378934686431938">Aggiorna i dati di accesso.</translation>
+<translation id="4510973599275542560">Non ricaricare</translation>
 <translation id="9154176715500758432">Rimani su questa pagina</translation>
+<translation id="7063006564040364415">Impossibile collegarsi al server di sincronizzazione.</translation>
 <translation id="6512448926095770873">Esci dalla pagina</translation>
+<translation id="7947953824732555851">Accetta e accedi</translation>
 <translation id="6040143037577758943">Chiudi</translation>
+<translation id="5032574515228824816">Messaggio</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Conferma accesso</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
index 925adb4..1e22bb6 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="iw">
 <translation id="1491151370853475546">טען מחדש דף זה</translation>
 <translation id="7658239707568436148">ביטול</translation>
+<translation id="6458785801851713928">הסנכרון אינו זמין בדומיין שלך.</translation>
 <translation id="2731700343119398978">המתן בבקשה...</translation>
+<translation id="3358663646935160692">‏החשבון הזה מנוהל על ידי <ph name="DOMAIN_NAME"/>.
+
+אתה נכנס לחשבון מנוהל, ונותן למנהל המערכת שליטה על פרופיל Chrome שלך. נתוני Chrome שלך ייקשרו באופן קבוע לחשבון הזה. התנתקות מהחשבון הזה תמחק את נתוני Chrome המקומיים.</translation>
+<translation id="1623104350909869708">מנע מהדף זה ליצור תיבות דו-שיח נוספות</translation>
+<translation id="3896036286668839683">מציג האישורים</translation>
+<translation id="8583805026567836021">מנקה נתוני חשבון</translation>
+<translation id="4170011742729630528">השירות אינו זמין. נסה שוב מאוחר יותר.</translation>
+<translation id="8627706565932943526">שגיאת סנכרון</translation>
+<translation id="3136378934686431938">עדכן את פרטי הכניסה שלך.</translation>
+<translation id="4510973599275542560">אל תטען מחדש</translation>
 <translation id="9154176715500758432">הישאר בדף זה</translation>
+<translation id="7063006564040364415">לא ניתן היה להתחבר אל שרת הסנכרון.</translation>
 <translation id="6512448926095770873">צא מדף זה</translation>
+<translation id="7947953824732555851">קבל והיכנס</translation>
 <translation id="6040143037577758943">סגור</translation>
+<translation id="5032574515228824816">בקשה</translation>
 <translation id="6965382102122355670">אישור</translation>
+<translation id="7495038789730067783">אשר את הכניסה</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
index 5fc6b0c..50ec405 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="ja">
 <translation id="1491151370853475546">このページを再読み込み</translation>
 <translation id="7658239707568436148">キャンセル</translation>
+<translation id="6458785801851713928">お使いのドメインでは同期機能をご利用いただけません。</translation>
 <translation id="2731700343119398978">お待ちください...</translation>
+<translation id="3358663646935160692">このアカウントは <ph name="DOMAIN_NAME"/> によって管理されています。
+
+管理対象アカウントでログインし、アカウントの管理者に自分の Chrome プロフィールの管理を委ねようとしています。あなたの Chrome データはこのアカウントに永続的に関連付けられます。このアカウントを切り離すと、ローカルの Chrome データが削除されます。</translation>
+<translation id="1623104350909869708">このページで追加のダイアログが作成されないようにする</translation>
+<translation id="3896036286668839683">証明書ビューア</translation>
+<translation id="8583805026567836021">アカウント データをクリア中</translation>
+<translation id="4170011742729630528">このサービスはご利用になれません。しばらくしてからもう一度お試しください。</translation>
+<translation id="8627706565932943526">同期エラー</translation>
+<translation id="3136378934686431938">ログイン情報を更新してください。</translation>
+<translation id="4510973599275542560">再読み込みの中止</translation>
 <translation id="9154176715500758432">このページにとどまる</translation>
+<translation id="7063006564040364415">同期サーバーに接続できませんでした。</translation>
 <translation id="6512448926095770873">このページを離れる</translation>
+<translation id="7947953824732555851">同意してログイン</translation>
 <translation id="6040143037577758943">閉じる</translation>
+<translation id="5032574515228824816">メッセージ</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">ログインの確認</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
index f851f5d..4083f40 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="ko">
 <translation id="1491151370853475546">페이지 새로고침</translation>
 <translation id="7658239707568436148">취소</translation>
+<translation id="6458785801851713928">도메인에 대해 동기화를 사용할 수 없습니다.</translation>
 <translation id="2731700343119398978">잠시 기다려 주세요...</translation>
+<translation id="3358663646935160692"><ph name="DOMAIN_NAME"/>에서 관리하는 계정입니다.
+
+관리 계정으로 로그인하면 사용자의 Chrome 프로필에 대한 제어 권한이 관리자에게 부여됩니다. 사용자의 Chrome 데이터는 이 계정에 영구적으로 연결되며, 이 계정의 연결을 해제하면 로컬 Chrome 데이터가 삭제됩니다.</translation>
+<translation id="1623104350909869708">이 페이지가 추가적인 대화를 생성하지 않도록 차단</translation>
+<translation id="3896036286668839683">인증서 뷰어</translation>
+<translation id="8583805026567836021">계정 데이터 지우기</translation>
+<translation id="4170011742729630528">서비스를 사용할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
+<translation id="8627706565932943526">동기화 오류</translation>
+<translation id="3136378934686431938">로그인 세부정보를 업데이트하세요.</translation>
+<translation id="4510973599275542560">새로고침 안함</translation>
 <translation id="9154176715500758432">이 페이지에 머무르기</translation>
+<translation id="7063006564040364415">동기화 서버에 연결할 수 없습니다.</translation>
 <translation id="6512448926095770873">이 페이지 나오기</translation>
+<translation id="7947953824732555851">수락 및 로그인</translation>
 <translation id="6040143037577758943">닫기</translation>
+<translation id="5032574515228824816">프롬프트</translation>
 <translation id="6965382102122355670">확인</translation>
+<translation id="7495038789730067783">로그인 확인</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
index 30c909d..ca0441f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="lt">
 <translation id="1491151370853475546">Iš naujo įkelti šį puslapį</translation>
 <translation id="7658239707568436148">Atšaukti</translation>
+<translation id="6458785801851713928">Sinchronizavimo paslauga nepasiekiama jūsų domenui.</translation>
 <translation id="2731700343119398978">Palaukite...</translation>
+<translation id="3358663646935160692">Šią paskyrą valdo <ph name="DOMAIN_NAME"/>.
+
+Prisijungiate naudodami valdomą paskyrą ir leidžiate administratoriui valdyti jūsų „Chrome“ profilį. „Chrome“ duomenys bus visam laikui susieti su šia paskyra. Atsijungus nuo šios paskyros bus ištrinti vietiniai „Chrome“ duomenys.</translation>
+<translation id="1623104350909869708">Neleisti šiam puslapiui kurti papildomų dialogo langų</translation>
+<translation id="3896036286668839683">Sertifikato peržiūros priemonė</translation>
+<translation id="8583805026567836021">Valomi paskyros duomenys</translation>
+<translation id="4170011742729630528">Paslauga nepasiekiama; vėliau bandykite dar kartą.</translation>
+<translation id="8627706565932943526">Sinchronizavimo klaida</translation>
+<translation id="3136378934686431938">Atnaujinkite išsamią prisijungimo informaciją.</translation>
+<translation id="4510973599275542560">Neįkelti iš naujo</translation>
 <translation id="9154176715500758432">Likti šiame puslapyje</translation>
+<translation id="7063006564040364415">Nepavyko prisijungti prie sinchronizavimo serverio.</translation>
 <translation id="6512448926095770873">Išeiti iš šio puslapio</translation>
+<translation id="7947953824732555851">Sutikti ir prisij.</translation>
 <translation id="6040143037577758943">Uždaryti</translation>
+<translation id="5032574515228824816">Raginimas</translation>
 <translation id="6965382102122355670">Gerai</translation>
+<translation id="7495038789730067783">Patvirtinti prisijungimą</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
index 4d8b5f3..afceaa8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="lv">
 <translation id="1491151370853475546">Atkārtoti ielādēt šo lapu</translation>
 <translation id="7658239707568436148">Atcelt</translation>
+<translation id="6458785801851713928">Jūsu domēnam nav pieejama sinhronizācija.</translation>
 <translation id="2731700343119398978">Lūdzu, uzgaidiet...</translation>
+<translation id="3358663646935160692">Šis konts tiek pārvaldīts domēnā <ph name="DOMAIN_NAME"/>.
+
+Jūs pierakstāties, izmantojot pārvaldītu kontu, un ļaujat šī konta administratoram pārvaldīt jūsu Chrome profilu. Jūsu Chrome dati tiks neatgriezeniski saistīti ar šo kontu. Noņemot saiti no šī konta, tiks dzēsti lokālie Chrome dati.</translation>
+<translation id="1623104350909869708">Neļaut šai lapai veidot papildu dialoglodziņus</translation>
+<translation id="3896036286668839683">Sertifikāta skatītājs</translation>
+<translation id="8583805026567836021">Konta datu dzēšana</translation>
+<translation id="4170011742729630528">Pakalpojums nav pieejams. Vēlāk mēģiniet vēlreiz.</translation>
+<translation id="8627706565932943526">Sinhronizācijas kļūda.</translation>
+<translation id="3136378934686431938">Lūdzu, atjauniniet pierakstīšanās informāciju.</translation>
+<translation id="4510973599275542560">Neielādēt atkārtoti</translation>
 <translation id="9154176715500758432">Palikt šajā lapā</translation>
+<translation id="7063006564040364415">Nevarēja izveidot savienojumu ar sinhronizācijas serveri.</translation>
 <translation id="6512448926095770873">Pamest šo lapu</translation>
+<translation id="7947953824732555851">Pieņemt un pierakst.</translation>
 <translation id="6040143037577758943">Aizvērt</translation>
+<translation id="5032574515228824816">Uzvedne</translation>
 <translation id="6965382102122355670">Labi</translation>
+<translation id="7495038789730067783">Pierakstīšanās apstiprinājums</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
index e14f2c7..67a32f0 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="nl">
 <translation id="1491151370853475546">Deze pagina opnieuw laden</translation>
 <translation id="7658239707568436148">Annuleren</translation>
+<translation id="6458785801851713928">De synchronisatieservice is niet beschikbaar voor je domein.</translation>
 <translation id="2731700343119398978">Even geduld...</translation>
+<translation id="3358663646935160692">Dit account wordt beheerd door <ph name="DOMAIN_NAME"/>.
+
+Je logt in met een beheerd account en geeft de beheerder controle over je Chrome-profiel. Je Chrome-gegevens worden permanent gekoppeld aan dit account. Als je dit account loskoppelt, worden de lokale Chrome-gegevens verwijderd.</translation>
+<translation id="1623104350909869708">Voorkomen dat deze pagina extra dialoogvensters weergeeft</translation>
+<translation id="3896036286668839683">Certificaatweergave</translation>
+<translation id="8583805026567836021">Accountgegevens wissen</translation>
+<translation id="4170011742729630528">De service is niet beschikbaar. Probeer het later opnieuw.</translation>
+<translation id="8627706565932943526">Synchronisatiefout</translation>
+<translation id="3136378934686431938">Werk je inloggegevens bij.</translation>
+<translation id="4510973599275542560">Niet opnieuw laden</translation>
 <translation id="9154176715500758432">Op deze pagina blijven</translation>
+<translation id="7063006564040364415">Kan geen verbinding maken met synchronisatieserver.</translation>
 <translation id="6512448926095770873">Deze pagina verlaten</translation>
+<translation id="7947953824732555851">Accepteren en inloggen</translation>
 <translation id="6040143037577758943">Sluiten</translation>
+<translation id="5032574515228824816">Prompt</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Inloggen bevestigen</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
index 1c41b1c..2f6e783 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="no">
 <translation id="1491151370853475546">Last inn denne siden på nytt</translation>
 <translation id="7658239707568436148">Avbryt</translation>
+<translation id="6458785801851713928">Synkronisering er ikke tilgjengelig for domenet ditt.</translation>
 <translation id="2731700343119398978">Vent litt …</translation>
+<translation id="3358663646935160692">Denne kontoen administreres av <ph name="DOMAIN_NAME"/>.
+
+Du logger på med en administrert konto, og gir administratoren kontroll over Chrome-profilen din. Chrome-dataene dine blir permanent knyttet til denne kontoen. Hvis du kobler fra denne kontoen, slettes de lokale Chrome-dataene.</translation>
+<translation id="1623104350909869708">Hindre denne siden i å opprette flere dialogruter</translation>
+<translation id="3896036286668839683">Sertifikatfremviser</translation>
+<translation id="8583805026567836021">Fjerner kontodata …</translation>
+<translation id="4170011742729630528">Tjenesten er ikke tilgjengelig. Prøv på nytt senere.</translation>
+<translation id="8627706565932943526">Synkroniseringsfeil</translation>
+<translation id="3136378934686431938">Oppdater påloggingsinformasjonen din.</translation>
+<translation id="4510973599275542560">Ikke last inn på nytt</translation>
 <translation id="9154176715500758432">Bli værende på denne siden</translation>
+<translation id="7063006564040364415">Kunne ikke koble til synkroniseringstjeneren.</translation>
 <translation id="6512448926095770873">Forlat siden</translation>
+<translation id="7947953824732555851">Godta og logg på</translation>
 <translation id="6040143037577758943">Lukk</translation>
+<translation id="5032574515228824816">Ledetekst</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Bekreft pålogging</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
index 05e25bf..0342156 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="pl">
 <translation id="1491151370853475546">Załaduj tę stronę ponownie</translation>
 <translation id="7658239707568436148">Anuluj</translation>
+<translation id="6458785801851713928">Synchronizacja nie jest dostępna w Twojej domenie.</translation>
 <translation id="2731700343119398978">Czekaj...</translation>
+<translation id="3358663646935160692">Tym kontem zarządza <ph name="DOMAIN_NAME"/>.
+
+Logujesz się na zarządzane konto i dajesz jego administratorowi kontrolę nad swoim profilem Chrome. Twoje dane Chrome zostaną na stałe powiązane z tym kontem. Odłączenie od tego konta spowoduje usunięcie lokalnych danych Chrome.</translation>
+<translation id="1623104350909869708">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie</translation>
+<translation id="3896036286668839683">Przeglądarka certyfikatów</translation>
+<translation id="8583805026567836021">Usuwam dane konta</translation>
+<translation id="4170011742729630528">Usługa jest niedostępna. Spróbuj ponownie później.</translation>
+<translation id="8627706565932943526">Błąd synchronizacji</translation>
+<translation id="3136378934686431938">Zaktualizuj swoje dane logowania.</translation>
+<translation id="4510973599275542560">Nie ładuj ponownie</translation>
 <translation id="9154176715500758432">Pozostań na tej stronie</translation>
+<translation id="7063006564040364415">Nie udało się nawiązać połączenia z serwerem synchronizacji.</translation>
 <translation id="6512448926095770873">Opuść tę stronę</translation>
+<translation id="7947953824732555851">Zaakceptuj i zaloguj się</translation>
 <translation id="6040143037577758943">Zamknij</translation>
+<translation id="5032574515228824816">Monit</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Potwierdź, że chcesz się zalogować</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
index 41fb443..ceb3c60 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="pt-BR">
 <translation id="1491151370853475546">Atualizar esta página</translation>
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="6458785801851713928">A sincronização não está disponível para seu domínio.</translation>
 <translation id="2731700343119398978">Aguarde...</translation>
+<translation id="3358663646935160692">Esta conta é administrada por <ph name="DOMAIN_NAME"/>.
+
+Você está fazendo login com uma conta gerenciada e fornecendo ao administrador da conta o controle sobre seu perfil do Google Chrome. Seus dados do Chrome serão permanentemente vinculados a esta conta. Se você se desconectar desta conta, os dados locais do Chrome serão excluídos.</translation>
+<translation id="1623104350909869708">Impedir que esta página crie caixas de diálogo adicionais</translation>
+<translation id="3896036286668839683">Leitor de certificados</translation>
+<translation id="8583805026567836021">Limpando os dados da conta</translation>
+<translation id="4170011742729630528">O serviço não está disponível. Tente novamente mais tarde.</translation>
+<translation id="8627706565932943526">Erro de sincronização</translation>
+<translation id="3136378934686431938">Atualize seus detalhes de login.</translation>
+<translation id="4510973599275542560">Não atualizar</translation>
 <translation id="9154176715500758432">Permanecer nesta página</translation>
+<translation id="7063006564040364415">Não foi possível conectar ao servidor de sincronização.</translation>
 <translation id="6512448926095770873">Sair desta página</translation>
+<translation id="7947953824732555851">Aceitar/fazer login</translation>
 <translation id="6040143037577758943">Fechar</translation>
+<translation id="5032574515228824816">Prompt</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Confirmar login</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
index 9094496..ade3c06 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="pt-PT">
 <translation id="1491151370853475546">Atualizar esta Página</translation>
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="6458785801851713928">A sincronização não está disponível para o seu domínio.</translation>
 <translation id="2731700343119398978">Aguarde...</translation>
+<translation id="3358663646935160692">Esta conta é gerida por <ph name="DOMAIN_NAME"/>.
+
+Está a iniciar sessão com uma conta gerida e a atribuir ao respetivo administrador controlo sobre o seu perfil do Chrome. Os seus dados do Chrome ficarão associados permanentemente a esta conta. Desassociar esta conta irá eliminar os dados locais do Chrome.</translation>
+<translation id="1623104350909869708">Evitar que esta página crie caixas de diálogo adicionais</translation>
+<translation id="3896036286668839683">Visualizador de certificados</translation>
+<translation id="8583805026567836021">A limpar os dados da conta</translation>
+<translation id="4170011742729630528">O serviço não está disponível. Tente novamente mais tarde.</translation>
+<translation id="8627706565932943526">Erro de sincronização</translation>
+<translation id="3136378934686431938">Atualize os detalhes de início de sessão.</translation>
+<translation id="4510973599275542560">Não atualizar</translation>
 <translation id="9154176715500758432">Permanecer nesta página</translation>
+<translation id="7063006564040364415">Não foi possível estabelecer ligação ao servidor de sincronização.</translation>
 <translation id="6512448926095770873">Sair desta página</translation>
+<translation id="7947953824732555851">Aceitar e in. sessão</translation>
 <translation id="6040143037577758943">Fechar</translation>
+<translation id="5032574515228824816">Mensagem</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Confirmar início de sessão</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
index e3eb683..2e40a70 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="ro">
 <translation id="1491151370853475546">Reîncărcați această pagină</translation>
 <translation id="7658239707568436148">Anulaţi</translation>
+<translation id="6458785801851713928">Sincronizarea nu este disponibilă pentru domeniul dvs.</translation>
 <translation id="2731700343119398978">Așteptați...</translation>
+<translation id="3358663646935160692">Acest cont este gestionat de <ph name="DOMAIN_NAME"/>.
+
+Urmează să vă conectați cu un cont gestionat și să acordați administratorului control asupra profilului Chrome. Datele din Chrome vor fi asociate definitiv acestui cont. Dacă vă deconectați de la acest cont, datele locale Chrome se vor șterge.</translation>
+<translation id="1623104350909869708">Restricționați capacitatea acestei pagini de a crea casete de dialog suplimentare</translation>
+<translation id="3896036286668839683">Vizualizator de certificate</translation>
+<translation id="8583805026567836021">Se șterg datele contului</translation>
+<translation id="4170011742729630528">Serviciul nu este disponibil. Încercați din nou mai târziu.</translation>
+<translation id="8627706565932943526">Eroare de sincronizare</translation>
+<translation id="3136378934686431938">Actualizați detaliile de conectare.</translation>
+<translation id="4510973599275542560">Nu reîncărcați</translation>
 <translation id="9154176715500758432">Rămâneți pe această pagină</translation>
+<translation id="7063006564040364415">Nu s-a putut stabili conexiunea cu serverul de sincronizare.</translation>
 <translation id="6512448926095770873">Părăsiți această pagină</translation>
+<translation id="7947953824732555851">Accept și conectare</translation>
 <translation id="6040143037577758943">Închideți</translation>
+<translation id="5032574515228824816">Solicitare</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Confirmați conectarea</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
index 7a30afa..b98071f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="ru">
 <translation id="1491151370853475546">Обновить страницу</translation>
 <translation id="7658239707568436148">Отмена</translation>
+<translation id="6458785801851713928">В вашем домене синхронизация отключена</translation>
 <translation id="2731700343119398978">Подождите…</translation>
+<translation id="3358663646935160692">Этот аккаунт зарегистрирован в домене <ph name="DOMAIN_NAME"/>.
+
+Если вы войдете в аккаунт, администратор домена сможет управлять вашим профилем Chrome. Ваши данные будут связаны с этим аккаунтом. Если вы из него выйдете, все данные Chrome будут удалены с устройства.</translation>
+<translation id="1623104350909869708">Запретить создание дополнительных диалоговых окон на этой странице</translation>
+<translation id="3896036286668839683">Средство просмотра сертификатов</translation>
+<translation id="8583805026567836021">Удаление данных аккаунта</translation>
+<translation id="4170011742729630528">Сервис недоступен. Повторите попытку позже.</translation>
+<translation id="8627706565932943526">Ошибка синхронизации</translation>
+<translation id="3136378934686431938">Измените данные аккаунта</translation>
+<translation id="4510973599275542560">Отмена</translation>
 <translation id="9154176715500758432">Остаться на этой странице</translation>
+<translation id="7063006564040364415">Не удалось связаться с сервером синхронизации</translation>
 <translation id="6512448926095770873">Покинуть эту страницу</translation>
+<translation id="7947953824732555851">Принять и войти</translation>
 <translation id="6040143037577758943">Закрыть</translation>
+<translation id="5032574515228824816">Запрос</translation>
 <translation id="6965382102122355670">ОК</translation>
+<translation id="7495038789730067783">Подтвердите вход</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
index 9c8cbdb..c2805d5 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="sk">
 <translation id="1491151370853475546">Znova načítať stránku</translation>
 <translation id="7658239707568436148">Zrušiť</translation>
+<translation id="6458785801851713928">Synchronizácia nie je pre vašu doménu k dispozícii.</translation>
 <translation id="2731700343119398978">Počkajte...</translation>
+<translation id="3358663646935160692">Tento účet spravuje doména <ph name="DOMAIN_NAME"/>.
+
+Prihlasujete sa pomocou spravovaného účtu a jeho správcovi tak umožňujete úplnú kontrolu nad vaším profilom Chrome. Vaše údaje prehliadača Chrome sa natrvalo prepoja s týmto účtom. Po odpojení tohto účtu sa odstránia miestne údaje prehliadača Chrome.</translation>
+<translation id="1623104350909869708">Zakázať tejto stránke otvárať ďalšie dialógové okná</translation>
+<translation id="3896036286668839683">Zobrazovač certifikátov</translation>
+<translation id="8583805026567836021">Prebieha vymazávanie údajov účtu</translation>
+<translation id="4170011742729630528">Služba nie je k dispozícii. Skúste to znova neskôr.</translation>
+<translation id="8627706565932943526">Chyba synchronizácie</translation>
+<translation id="3136378934686431938">Aktualizujte svoje prihlasovacie údaje.</translation>
+<translation id="4510973599275542560">Nenačítať znova</translation>
 <translation id="9154176715500758432">Zostať na tejto stránke</translation>
+<translation id="7063006564040364415">Nepodarilo sa pripojiť k synchronizačnému serveru.</translation>
 <translation id="6512448926095770873">Odísť z tejto stránky</translation>
+<translation id="7947953824732555851">Prijať a prihl. sa</translation>
 <translation id="6040143037577758943">Zatvoriť</translation>
+<translation id="5032574515228824816">Výzva</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Potvrdenie prihlásenia</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
index 7fed002..360e472 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="sl">
 <translation id="1491151370853475546">Znova naloži stran</translation>
 <translation id="7658239707568436148">Prekliči</translation>
+<translation id="6458785801851713928">Sinhronizacija ni na voljo za vašo domeno.</translation>
 <translation id="2731700343119398978">Počakajte ...</translation>
+<translation id="3358663646935160692">Ta račun upravlja domena <ph name="DOMAIN_NAME"/>.
+
+Prijavljate se z upravljanim računom in s tem njegovemu skrbniku omogočate nadziranje vašega profila v Google Chromu. Vaši podatki v Google Chromu bodo trajno povezani s tem računom. Če prekinete povezavo s tem računom, se izbrišejo lokalni podatki v Google Chromu.</translation>
+<translation id="1623104350909869708">Tej strani prepreči, da bi ustvarila dodatna pogovorna okna</translation>
+<translation id="3896036286668839683">Pregledovalnik potrdil</translation>
+<translation id="8583805026567836021">Brisanje podatkov računa</translation>
+<translation id="4170011742729630528">Storitev ni na voljo; poskusite znova pozneje.</translation>
+<translation id="8627706565932943526">Napaka pri sinhronizaciji</translation>
+<translation id="3136378934686431938">Posodobite podrobnosti prijave.</translation>
+<translation id="4510973599275542560">Ne naloži znova</translation>
 <translation id="9154176715500758432">Ostani na tej strani</translation>
+<translation id="7063006564040364415">Povezave s strežnikom za sinhronizacijo ni bilo mogoče vzpostaviti.</translation>
 <translation id="6512448926095770873">Zapusti to stran</translation>
+<translation id="7947953824732555851">Sprejem in prijava</translation>
 <translation id="6040143037577758943">Zapri</translation>
+<translation id="5032574515228824816">Poziv</translation>
 <translation id="6965382102122355670">V redu</translation>
+<translation id="7495038789730067783">Potrditev prijave</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
index adbed2d..118e027 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="sr">
 <translation id="1491151370853475546">Поново учитај ову страницу</translation>
 <translation id="7658239707568436148">Откажи</translation>
+<translation id="6458785801851713928">Синхронизација није доступна за домен.</translation>
 <translation id="2731700343119398978">Сачекајте…</translation>
+<translation id="3358663646935160692">Овим налогом управља <ph name="DOMAIN_NAME"/>.
+
+Пријављујете се помоћу управљаног налога и дајете администратору контролу над Chrome профилом. Chrome подаци ће постати трајно повезани са овим налогом. Ако прекинете везу са овим налогом, избрисаћете локалне Chrome податке.</translation>
+<translation id="1623104350909869708">Спречи ову страницу да прави додатне дијалоге</translation>
+<translation id="3896036286668839683">Приказивач сертификата</translation>
+<translation id="8583805026567836021">Брисање података о налогу</translation>
+<translation id="4170011742729630528">Услуга није доступна. Покушајте поново касније.</translation>
+<translation id="8627706565932943526">Грешка при синхронизацији</translation>
+<translation id="3136378934686431938">Ажурирајте податке за пријављивање.</translation>
+<translation id="4510973599275542560">Не учитавај поново</translation>
 <translation id="9154176715500758432">Остани на овој страници</translation>
+<translation id="7063006564040364415">Није могуће повезивање са сервером за синхронизацију.</translation>
 <translation id="6512448926095770873">Напусти ову страницу</translation>
+<translation id="7947953824732555851">Прихвати и пријави ме</translation>
 <translation id="6040143037577758943">Затвори</translation>
+<translation id="5032574515228824816">Упит</translation>
 <translation id="6965382102122355670">Потврди</translation>
+<translation id="7495038789730067783">Потврдите пријављивање</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
index 566a9ee..3846c53 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="sv">
 <translation id="1491151370853475546">Hämta sidan igen</translation>
 <translation id="7658239707568436148">Avbryt</translation>
+<translation id="6458785801851713928">Synkronisering är inte tillgängligt för din domän.</translation>
 <translation id="2731700343119398978">Vänta ...</translation>
+<translation id="3358663646935160692">Kontot hanteras av <ph name="DOMAIN_NAME"/>.
+
+Du loggar in med ett hanterat konto, vilket innebär att administratören kontrollerar din Chrome-profil. Din Chrome-data kommer att knytas permanent till det här kontot. Om du kopplar ifrån det här kontot raderas din lokala Chrome-data.</translation>
+<translation id="1623104350909869708">Hindra sidan från att skapa fler dialogrutor</translation>
+<translation id="3896036286668839683">Certifikatvisare</translation>
+<translation id="8583805026567836021">Rensar kontouppgifter</translation>
+<translation id="4170011742729630528">Tjänsten är inte tillgänglig, försök igen senare.</translation>
+<translation id="8627706565932943526">Synkroniseringsfel</translation>
+<translation id="3136378934686431938">Uppdatera dina inloggningsuppgifter.</translation>
+<translation id="4510973599275542560">Hämta ej sidan igen</translation>
 <translation id="9154176715500758432">Stanna på den här sidan</translation>
+<translation id="7063006564040364415">Det gick inte att ansluta till synkroniseringsservern.</translation>
 <translation id="6512448926095770873">Lämna denna sida</translation>
+<translation id="7947953824732555851">Godkänn och logga in</translation>
 <translation id="6040143037577758943">Stäng</translation>
+<translation id="5032574515228824816">Fråga</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Bekräfta inloggning</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
index c58e746..b04e1f2 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="sw">
 <translation id="1491151370853475546">Pakia Ukurasa huu Upya</translation>
 <translation id="7658239707568436148">Ghairi</translation>
+<translation id="6458785801851713928">Huduma ya usawazishaji haipatikani kwa kikoa chako.</translation>
 <translation id="2731700343119398978">Tafadhali subiri...</translation>
+<translation id="3358663646935160692">Akaunti hii inasimamiwa na <ph name="DOMAIN_NAME"/>.
+
+Unaingia katika akaunti kwa kutumia akaunti inayosimamiwa na kumpa msimamizi wa akaunti udhibiti wa wasifu wako kwenye Chrome. Data yako ya Chrome itatumika kwenye akaunti hii kabisa. Kujiondoa kwenye akaunti hii kutafuta data yako ya Chrome iliyopo.</translation>
+<translation id="1623104350909869708">Zuia ukurasa huu usiunde vidadisi zaidi</translation>
+<translation id="3896036286668839683">Kitazama Cheti</translation>
+<translation id="8583805026567836021">Inafuta data ya akaunti</translation>
+<translation id="4170011742729630528">Huduma haipatikani; jaribu tena baadaye.</translation>
+<translation id="8627706565932943526">Hitilafu ya usawazishaji</translation>
+<translation id="3136378934686431938">Tafadhali sasisha maelezo yako ya kuingia katika akaunti.</translation>
+<translation id="4510973599275542560">Usipakie upya</translation>
 <translation id="9154176715500758432">Kaa kwenye Ukurasa huu</translation>
+<translation id="7063006564040364415">Haikuweza kuunganisha kwenye seva ya usawazishaji.</translation>
 <translation id="6512448926095770873">Ondoka kwenye ukurasa huu</translation>
+<translation id="7947953824732555851">Kubali na uingie katika akaunti</translation>
 <translation id="6040143037577758943">Funga</translation>
+<translation id="5032574515228824816">Uliza</translation>
 <translation id="6965382102122355670">Sawa</translation>
+<translation id="7495038789730067783">Thibitisha kuingia katika akaunti</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
index e127189..9e98acf 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="th">
 <translation id="1491151370853475546">โหลดหน้าเว็บนี้ซ้ำ</translation>
 <translation id="7658239707568436148">ยกเลิก</translation>
+<translation id="6458785801851713928">การซิงค์ไม่พร้อมใช้งานสำหรับโดเมนของคุณ</translation>
 <translation id="2731700343119398978">โปรดรอสักครู่...</translation>
+<translation id="3358663646935160692">ผู้จัดการบัญชีนี้คือ <ph name="DOMAIN_NAME"/>
+
+คุณกำลังลงชื่อเข้าใช้ด้วยบัญชีที่มีผู้อื่นเป็นผู้จัดการ และคุณอนุญาตให้ผู้ดูแลระบบควบคุมโปรไฟล์ Chrome ของคุณได้ ข้อมูล Chrome ของคุณจะเชื่อมโยงกับบัญชีนี้อย่างถาวร การยกเลิกการเชื่อมต่อกับบัญชีนี้จะเป็นการลบข้อมูล Chrome ในเครื่อง</translation>
+<translation id="1623104350909869708">ป้องกันหน้าเว็บนี้จากการสร้างการโต้ตอบเพิ่มเติม</translation>
+<translation id="3896036286668839683">เครื่องมือดูใบรับรอง</translation>
+<translation id="8583805026567836021">กำลังล้างข้อมูลบัญชี</translation>
+<translation id="4170011742729630528">บริการนี้ยังไม่สามารถใช้ได้ โปรดลองอีกครั้งในภายหลัง</translation>
+<translation id="8627706565932943526">ข้อผิดพลาดในการซิงค์</translation>
+<translation id="3136378934686431938">โปรดอัปเดตรายละเอียดการลงชื่อเข้าใช้ของคุณ</translation>
+<translation id="4510973599275542560">อย่าโหลดซ้ำ</translation>
 <translation id="9154176715500758432">อยู่ในหน้านี้</translation>
+<translation id="7063006564040364415">ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์การซิงค์</translation>
 <translation id="6512448926095770873">ออกจากหน้านี้</translation>
+<translation id="7947953824732555851">ยอมรับและลงชื่อเข้าใช้</translation>
 <translation id="6040143037577758943">ปิด</translation>
+<translation id="5032574515228824816">หน้าต่างแจ้งเตือน</translation>
 <translation id="6965382102122355670">ตกลง</translation>
+<translation id="7495038789730067783">ยืนยันการลงชื่อเข้าใช้</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
index 06601ab..e89625a 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="tr">
 <translation id="1491151370853475546">Bu Sayfayı Yeniden Yükle</translation>
 <translation id="7658239707568436148">İptal</translation>
+<translation id="6458785801851713928">Senkronizasyon özelliği alan adınızda kullanılamıyor.</translation>
 <translation id="2731700343119398978">Lütfen bekleyin...</translation>
+<translation id="3358663646935160692">Bu hesap <ph name="DOMAIN_NAME"/> tarafından yönetiliyor.
+
+Yönetilen bir hesapla oturum açıyor ve hesabın yöneticisine Chrome profilinizi denetleme olanağı veriyorsunuz. Chrome verileriniz bu hesaba kalıcı olarak bağlanır. Bu hesabın bağlantısı kesildiğinde yerel Chrome verileriniz silinir.</translation>
+<translation id="1623104350909869708">Bu sayfanın daha fazla iletişim kutusu oluşturmasını önle</translation>
+<translation id="3896036286668839683">Sertifika Görüntüleyici</translation>
+<translation id="8583805026567836021">Hesap verileri temizleniyor</translation>
+<translation id="4170011742729630528">Hizmet kullanılamıyor, daha sonra tekrar deneyin.</translation>
+<translation id="8627706565932943526">Senkronizasyon hatası</translation>
+<translation id="3136378934686431938">Lütfen oturum açma ayrıntılarınızı güncelleyin</translation>
+<translation id="4510973599275542560">Yeniden yükleme</translation>
 <translation id="9154176715500758432">Bu Sayfada Kal</translation>
+<translation id="7063006564040364415">Senkronizasyon sunucusuna bağlanılamadı.</translation>
 <translation id="6512448926095770873">Bu Sayfadan Ayrıl</translation>
+<translation id="7947953824732555851">Kabul et ve oturum aç</translation>
 <translation id="6040143037577758943">Kapat</translation>
+<translation id="5032574515228824816">İstem</translation>
 <translation id="6965382102122355670">Tamam</translation>
+<translation id="7495038789730067783">Oturum açmayı onaylayın</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
index df3dde8..83d68ba 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="uk">
 <translation id="1491151370853475546">Перезавантажити цю сторінку</translation>
 <translation id="7658239707568436148">Скасувати</translation>
+<translation id="6458785801851713928">Синхронізація не доступна для вашого домену.</translation>
 <translation id="2731700343119398978">Зачекайте...</translation>
+<translation id="3358663646935160692">Цим обліковим записом керує домен <ph name="DOMAIN_NAME"/>.
+
+Ви входите в керований обліковий запис і дозволяєте його адміністратору керувати вашим профілем Chrome. Ваші дані Chrome буде назавжди пов’язано з цим обліковим записом. Відключення від цього облікового запису видалить усі локальні дані Chrome.</translation>
+<translation id="1623104350909869708">Заборонити цій сторінці створювати додаткові діалогові вікна</translation>
+<translation id="3896036286668839683">Перегляд сертифікатів</translation>
+<translation id="8583805026567836021">Очищення даних облікового запису</translation>
+<translation id="4170011742729630528">Служба не доступна. Повторіть спробу пізніше.</translation>
+<translation id="8627706565932943526">Помилка синхронізації</translation>
+<translation id="3136378934686431938">Оновіть свої дані для входу.</translation>
+<translation id="4510973599275542560">Не оновлювати</translation>
 <translation id="9154176715500758432">Залишатися на цій сторінці</translation>
+<translation id="7063006564040364415">Не вдалося з’єднатись із сервером синхронізації.</translation>
 <translation id="6512448926095770873">Залишити цю сторінку</translation>
+<translation id="7947953824732555851">Прийняти й увійти</translation>
 <translation id="6040143037577758943">Закрити</translation>
+<translation id="5032574515228824816">Підказка</translation>
 <translation id="6965382102122355670">ОК</translation>
+<translation id="7495038789730067783">Підтвердити вхід</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
index 7d18964..fe71aa9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="vi">
 <translation id="1491151370853475546">Tải lại trang này</translation>
 <translation id="7658239707568436148">Hủy</translation>
+<translation id="6458785801851713928">Dịch vụ đồng bộ hóa không khả dụng cho miền của bạn.</translation>
 <translation id="2731700343119398978">Vui lòng chờ...</translation>
+<translation id="3358663646935160692">Tài khoản này được quản lý bởi <ph name="DOMAIN_NAME"/>.
+
+Bạn đang đăng nhập bằng tài khoản được quản lý và cung cấp cho quản trị viên quyền kiểm soát đối với tiểu sử trên Chrome của bạn. Dữ liệu Chrome của bạn sẽ vĩnh viễn gắn với tài khoản này. Ngắt kết nối khỏi tài khoản này sẽ xóa các dữ liệu Chrome cục bộ.</translation>
+<translation id="1623104350909869708">Ngăn trang này tạo hộp thoại bổ sung</translation>
+<translation id="3896036286668839683">Trình xem chứng chỉ</translation>
+<translation id="8583805026567836021">Xóa dữ liệu tài khoản</translation>
+<translation id="4170011742729630528">Dịch vụ không khả dụng; thử lại sau.</translation>
+<translation id="8627706565932943526">Lỗi đồng bộ hóa</translation>
+<translation id="3136378934686431938">Vui lòng cập nhật chi tiết đăng nhập của bạn.</translation>
+<translation id="4510973599275542560">Không tải lại</translation>
 <translation id="9154176715500758432">Ở lại Trang này</translation>
+<translation id="7063006564040364415">Không thể kết nối với máy chủ đồng bộ hóa.</translation>
 <translation id="6512448926095770873">Rời khỏi Trang này</translation>
+<translation id="7947953824732555851">Chấp nhận &amp; đăng nhập</translation>
 <translation id="6040143037577758943">Đóng</translation>
+<translation id="5032574515228824816">Lời nhắc</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="7495038789730067783">Xác nhận đăng nhập</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
index 6d9645a..1de6815 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="zh-CN">
 <translation id="1491151370853475546">重新加载此页</translation>
 <translation id="7658239707568436148">取消</translation>
+<translation id="6458785801851713928">您的网域不支持同步。</translation>
 <translation id="2731700343119398978">请稍候...</translation>
+<translation id="3358663646935160692">此帐户由 <ph name="DOMAIN_NAME"/> 管理。
+
+您目前登录的帐户是一个托管帐户,该帐户的管理员将能够控制您的 Chrome 个人资料。您的 Chrome 数据将永远与此帐户相关联。断开与此帐户的关联将删除本地 Chrome 数据。</translation>
+<translation id="1623104350909869708">阻止此页创建其他对话框</translation>
+<translation id="3896036286668839683">证书查看器</translation>
+<translation id="8583805026567836021">清除帐户数据</translation>
+<translation id="4170011742729630528">此服务目前无法使用,请稍后再试。</translation>
+<translation id="8627706565932943526">同步错误</translation>
+<translation id="3136378934686431938">请更新您的登录详情。</translation>
+<translation id="4510973599275542560">不重新加载</translation>
 <translation id="9154176715500758432">留在此页</translation>
+<translation id="7063006564040364415">无法连接到同步服务器。</translation>
 <translation id="6512448926095770873">离开此页</translation>
+<translation id="7947953824732555851">接受并登录</translation>
 <translation id="6040143037577758943">关闭</translation>
+<translation id="5032574515228824816">提示</translation>
 <translation id="6965382102122355670">确定</translation>
+<translation id="7495038789730067783">确认登录</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
index f4bc617..76166eb 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
@@ -3,9 +3,24 @@
 <translationbundle lang="zh-TW">
 <translation id="1491151370853475546">重新載入這個網頁</translation>
 <translation id="7658239707568436148">取消</translation>
+<translation id="6458785801851713928">您的網域無法進行同步處理</translation>
 <translation id="2731700343119398978">請稍候...</translation>
+<translation id="3358663646935160692">這個帳戶由 <ph name="DOMAIN_NAME"/> 負責管理。
+
+您即將登入受管理的帳戶,並且讓帳戶管理員控制您的 Chrome 設定檔。您的 Chrome 資料將與這個帳戶建立永久連結。如果與這個帳戶解除連結,本機 Chrome 資料將會遭到刪除。</translation>
+<translation id="1623104350909869708">防止這個網頁產生其他對話方塊</translation>
+<translation id="3896036286668839683">憑證檢視者</translation>
+<translation id="8583805026567836021">正在清除帳戶資料</translation>
+<translation id="4170011742729630528">服務無法使用,請稍後再試。</translation>
+<translation id="8627706565932943526">同步處理發生錯誤</translation>
+<translation id="3136378934686431938">請更新您的登入詳細資料。</translation>
+<translation id="4510973599275542560">不要重新載入</translation>
 <translation id="9154176715500758432">停留在此頁</translation>
+<translation id="7063006564040364415">無法連線至同步處理伺服器。</translation>
 <translation id="6512448926095770873">離開此頁</translation>
+<translation id="7947953824732555851">接受並登入</translation>
 <translation id="6040143037577758943">關閉</translation>
+<translation id="5032574515228824816">提示</translation>
 <translation id="6965382102122355670">確定</translation>
+<translation id="7495038789730067783">確認登入</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS
index 3ab779c..619b59b 100644
--- a/chrome/android/javatests/DEPS
+++ b/chrome/android/javatests/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+content/public/android/java",
+  "+sync/android/java/src/org/chromium/sync/internal_api/pub",
   "+sync/android/java/src/org/chromium/sync/notifier",
   "+sync/android/java/src/org/chromium/sync/signin",
   # We should only depend on the util package of something that lives in
diff --git a/chrome/android/javatests/OWNERS b/chrome/android/javatests/OWNERS
new file mode 100644
index 0000000..cfc5e65
--- /dev/null
+++ b/chrome/android/javatests/OWNERS
@@ -0,0 +1,9 @@
+aruslan@chromium.org
+bulach@chromium.org
+dfalcantara@chromium.org
+dtrainor@chromium.org
+miguelg@chromium.org
+nyquist@chromium.org
+skyostil@chromium.org
+tedchoc@chromium.org
+yfriedman@chromium.org
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
new file mode 100644
index 0000000..8ea3277
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
@@ -0,0 +1,144 @@
+// Copyright 2013 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.app.AlertDialog;
+import android.app.Dialog;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.test.util.EnormousTest;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.RepostFormWarningDialog;
+import org.chromium.chrome.test.util.TestHttpServerClient;
+import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
+import org.chromium.chrome.testshell.TabShellTabUtils;
+import org.chromium.chrome.testshell.TestShellTab;
+import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration tests verifying that form resubmission dialogs are correctly displayed and handled.
+ */
+public class RepostFormWarningTest extends ChromiumTestShellTestBase {
+    // Active tab.
+    private TestShellTab mTab;
+    // Callback helper that manages waiting for pageloads to finish.
+    private TestCallbackHelperContainer mCallbackHelper;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mTab = launchChromiumTestShellWithBlankPage().getActiveTab();
+        mCallbackHelper = TabShellTabUtils.getTestCallbackHelperContainer(mTab);
+
+        // Wait for the initial load of about://blank to finish.
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(0);
+    }
+
+    /** Verifies that the form resubmission warning is not displayed upon first POST navigation. */
+    @MediumTest
+    @Feature({"Navigation"})
+    public void testFormFirstNavigation() throws Throwable {
+        // Load the url posting data for the first time.
+        postNavigation();
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(1);
+        getInstrumentation().waitForIdleSync();
+
+        // Verify that the form resubmission warning was not shown.
+        assertNull("Form resubmission warning shown upon first load.",
+                RepostFormWarningDialog.getCurrentDialog());
+    }
+
+    /** Verifies that confirming the form reload performs the reload. */
+    @MediumTest
+    @Feature({"Navigation"})
+    public void testFormResubmissionContinue() throws Throwable {
+        // Load the url posting data for the first time.
+        postNavigation();
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(1);
+
+        // Trigger a reload and wait for the warning to be displayed.
+        reload();
+        getInstrumentation().waitForIdleSync();
+        AlertDialog dialog = (AlertDialog)RepostFormWarningDialog.getCurrentDialog();
+        assertNotNull("Form resubmission warning not shown upon reload.", dialog);
+
+        // Click "Continue" and verify that the page is reloaded.
+        clickButton(dialog, AlertDialog.BUTTON_POSITIVE);
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(2);
+
+        // Verify that the reference to the dialog in RepostFormWarningDialog was cleared.
+        assertNull("Form resubmission warning dialog was not dismissed correctly.",
+                RepostFormWarningDialog.getCurrentDialog());
+    }
+
+    /**
+     * Verifies that cancelling the form reload prevents it from happening. Currently the test waits
+     * after the "Cancel" button is clicked to verify that the load was not triggered, which blocks
+     * for CallbackHelper's default timeout upon each execution.
+     */
+    @EnormousTest
+    @Feature({"Navigation"})
+    public void testFormResubmissionCancel() throws Throwable {
+        // Load the url posting data for the first time.
+        postNavigation();
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(1);
+
+        // Trigger a reload and wait for the warning to be displayed.
+        reload();
+        getInstrumentation().waitForIdleSync();
+        AlertDialog dialog = (AlertDialog)RepostFormWarningDialog.getCurrentDialog();
+        assertNotNull("Form resubmission warning not shown upon reload.", dialog);
+
+        // Click "Cancel" and verify that the page is not reloaded.
+        clickButton(dialog, AlertDialog.BUTTON_NEGATIVE);
+        boolean timedOut = false;
+        try {
+            mCallbackHelper.getOnPageFinishedHelper().waitForCallback(2);
+        } catch (TimeoutException ex) {
+            timedOut = true;
+        }
+        assertTrue("Page was reloaded despite selecting Cancel.", timedOut);
+
+        // Verify that the reference to the dialog in RepostFormWarningDialog was cleared.
+        assertNull("Form resubmission warning dialog was not dismissed correctly.",
+                RepostFormWarningDialog.getCurrentDialog());
+    }
+
+    /** Performs a POST navigation in mTab. */
+    private void postNavigation() throws Throwable {
+        final String url = "chrome/test/data/empty.html";
+        final byte[] postData = new byte[] { 42 };
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTab.loadUrlWithSanitization(TestHttpServerClient.getUrl(url), postData);
+            }
+        });
+    }
+
+    /** Reloads mTab. */
+    private void reload() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTab.reload();
+            }
+        });
+    }
+
+    /** Clicks the given button in the given dialog. */
+    private void clickButton(final AlertDialog dialog, final int buttonId) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                dialog.getButton(buttonId).performClick();
+            }
+        });
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java
index ff418ef..772ef42 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java
@@ -162,7 +162,8 @@
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                ShortcutHelper.addShortcut(mActivity.getActiveTab(), title);
+                ShortcutHelper.addShortcut(mActivity.getApplicationContext(),
+                        mActivity.getActiveTab(), title);
             }
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
index 768de77..a0b3480 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
@@ -279,15 +279,14 @@
                 TEST_CC_CSC, "id", false, false, false);
     }
 
-// TODO(isherman): http://crbug.com/263705 autocomplete="cc-exp" type="month" doesn't work.
-//    @SmallTest
-//    @Feature({"autofill"})
-//    public void testRacTypeCCExp() throws InterruptedException, TimeoutException {
-//        verifyOneField(
-//                "<input id=\"id\" autocomplete=\"cc-exp\" type=\"month\" value=\"1111-11\">",
-//                "" + TEST_CC_EXP_YEAR + "-" + TEST_CC_EXP_MONTH,
-//                "id", false, false, false);
-//    }
+    @SmallTest
+    @Feature({"autofill"})
+    public void testRacTypeCCExp() throws InterruptedException, TimeoutException {
+        verifyOneField(
+                "<input id=\"id\" autocomplete=\"cc-exp\" type=\"month\" value=\"1111-11\">",
+                "" + TEST_CC_EXP_YEAR + "-" + TEST_CC_EXP_MONTH,
+                "id", false, false, false);
+    }
 
     @SmallTest
     @Feature({"autofill"})
@@ -494,10 +493,9 @@
         assertEquals("cc-csc did not match",
                 TEST_CC_CSC, DOMUtils.getNodeValue(view, viewClient, "id-cc-csc"));
 
-// TODO(isherman): http://crbug.com/263705 autocomplete="cc-exp" type="month" doesn't work.
-//        assertEquals("cc-exp did not match",
-//                "" + TEST_CC_EXP_YEAR + "-" + TEST_CC_EXP_MONTH,
-//                DOMUtils.getNodeValue(view, viewClient, "id-cc-exp"));
+        assertEquals("cc-exp did not match",
+                "" + TEST_CC_EXP_YEAR + "-" + TEST_CC_EXP_MONTH,
+                DOMUtils.getNodeValue(view, viewClient, "id-cc-exp"));
 
         assertEquals("cc-exp-month did not match",
                 "" + TEST_CC_EXP_MONTH,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index 1b12192..be000bc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -18,6 +18,7 @@
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.ui.autofill.AutofillPopup;
 
+import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.view.View;
@@ -69,8 +70,12 @@
         mHelper = new AutofillTestHelper();
     }
 
-    @MediumTest
-    @Feature({"autofill"})
+    /*
+     * @MediumTest
+     * @Feature({"autofill"})
+     * Bug 312896
+     */
+    @FlakyTest
     public void testClickAutofillPopupSuggestion()
             throws InterruptedException, ExecutionException, TimeoutException {
         // The TestInputMethodManagerWrapper intercepts showSoftInput so that a keyboard is never
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java
new file mode 100644
index 0000000..aada9f2
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationControllerTest.java
@@ -0,0 +1,353 @@
+// Copyright 2013 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.invalidation;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.ipc.invalidation.external.client.types.ObjectId;
+
+import org.chromium.base.ActivityStatus;
+import org.chromium.base.CollectionUtil;
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Feature;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.chromium.sync.notifier.InvalidationIntentProtocol;
+import org.chromium.sync.notifier.InvalidationPreferences;
+import org.chromium.sync.notifier.InvalidationService;
+import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.signin.AccountManagerHelper;
+import org.chromium.sync.signin.ChromeSigninController;
+import org.chromium.sync.test.util.MockSyncContentResolverDelegate;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests for the {@link InvalidationController}.
+ */
+public class InvalidationControllerTest extends InstrumentationTestCase {
+    private IntentSavingContext mContext;
+    private InvalidationController mController;
+
+    @Override
+    protected void setUp() throws Exception {
+        mContext = new IntentSavingContext(getInstrumentation().getTargetContext());
+        mController = InvalidationController.get(mContext);
+        // We don't want to use the system content resolver, so we override it.
+        MockSyncContentResolverDelegate delegate = new MockSyncContentResolverDelegate();
+        // Android master sync can safely always be on.
+        delegate.setMasterSyncAutomatically(true);
+        SyncStatusHelper.overrideSyncStatusHelperForTests(mContext, delegate);
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testStart() throws Exception {
+        mController.start();
+        assertEquals(1, mContext.getNumStartedIntents());
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertNull(intent.getExtras());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testStop() throws Exception {
+        mController.stop();
+        assertEquals(1, mContext.getNumStartedIntents());
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertEquals(1, intent.getExtras().size());
+        assertTrue(intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP));
+        assertTrue(intent.getBooleanExtra(InvalidationIntentProtocol.EXTRA_STOP, false));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testResumingMainActivity() throws Exception {
+        // Resuming main activity should trigger a start if sync is enabled.
+        setupSync(true);
+        mController.onActivityStateChange(ActivityStatus.RESUMED);
+        assertEquals(1, mContext.getNumStartedIntents());
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertNull(intent.getExtras());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testResumingMainActivityWithSyncDisabled() throws Exception {
+        // Resuming main activity should NOT trigger a start if sync is disabled.
+        setupSync(false);
+        mController.onActivityStateChange(ActivityStatus.RESUMED);
+        assertEquals(0, mContext.getNumStartedIntents());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testPausingMainActivity() throws Exception {
+        // Resuming main activity should trigger a stop if sync is enabled.
+        setupSync(true);
+        mController.onActivityStateChange(ActivityStatus.PAUSED);
+        assertEquals(1, mContext.getNumStartedIntents());
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertEquals(1, intent.getExtras().size());
+        assertTrue(intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP));
+        assertTrue(intent.getBooleanExtra(InvalidationIntentProtocol.EXTRA_STOP, false));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testPausingMainActivityWithSyncDisabled() throws Exception {
+        // Resuming main activity should NOT trigger a stop if sync is disabled.
+        setupSync(false);
+        mController.onActivityStateChange(ActivityStatus.PAUSED);
+        assertEquals(0, mContext.getNumStartedIntents());
+    }
+
+    private void setupSync(boolean syncEnabled) {
+        Account account = AccountManagerHelper.createAccountFromName("test@gmail.com");
+        ChromeSigninController chromeSigninController = ChromeSigninController.get(mContext);
+        chromeSigninController.setSignedInAccountName(account.name);
+        SyncStatusHelper syncStatusHelper = SyncStatusHelper.get(mContext);
+        if (syncEnabled) {
+            syncStatusHelper.enableAndroidSync(account);
+        } else {
+            syncStatusHelper.disableAndroidSync(account);
+        }
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testEnsureConstructorRegistersListener() throws Exception {
+        final AtomicBoolean listenerCallbackCalled = new AtomicBoolean();
+
+        // Create instance.
+        new InvalidationController(mContext) {
+            @Override
+            public void onActivityStateChange(int newState) {
+                listenerCallbackCalled.set(true);
+            }
+        };
+
+        // Ensure initial state is correct.
+        assertFalse(listenerCallbackCalled.get());
+
+        // Ensure we get a callback, which means we have registered for them.
+        ActivityStatus.onStateChangeForTesting(new Activity(), ActivityStatus.RESUMED);
+        assertTrue(listenerCallbackCalled.get());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testRegisterForSpecificTypes() {
+        InvalidationController controller = new InvalidationController(mContext);
+        Account account = new Account("test@example.com", "bogus");
+        controller.setRegisteredTypes(account, false,
+                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+        assertEquals(1, mContext.getNumStartedIntents());
+
+        // Validate destination.
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());
+
+        // Validate account.
+        Account intentAccount =
+                intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT);
+        assertEquals(account, intentAccount);
+
+        // Validate registered types.
+        Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.BOOKMARK.name(),
+                ModelType.SESSION.name());
+        Set<String> actualTypes = new HashSet<String>();
+        actualTypes.addAll(intent.getStringArrayListExtra(
+                                InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
+        assertEquals(expectedTypes, actualTypes);
+        assertNull(InvalidationIntentProtocol.getRegisteredObjectIds(intent));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testRegisterForAllTypes() {
+        Account account = new Account("test@example.com", "bogus");
+        mController.setRegisteredTypes(account, true,
+                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+        assertEquals(1, mContext.getNumStartedIntents());
+
+        // Validate destination.
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());
+
+        // Validate account.
+        Account intentAccount =
+                intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT);
+        assertEquals(account, intentAccount);
+
+        // Validate registered types.
+        Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE);
+        Set<String> actualTypes = new HashSet<String>();
+        actualTypes.addAll(intent.getStringArrayListExtra(
+                                InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
+        assertEquals(expectedTypes, actualTypes);
+        assertNull(InvalidationIntentProtocol.getRegisteredObjectIds(intent));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testRefreshShouldReadValuesFromDiskWithSpecificTypes() {
+        // Store some preferences for ModelTypes and account. We are using the helper class
+        // for this, so we don't have to deal with low-level details such as preference keys.
+        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
+        InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
+        Set<String> storedModelTypes = new HashSet<String>();
+        storedModelTypes.add(ModelType.BOOKMARK.name());
+        storedModelTypes.add(ModelType.TYPED_URL.name());
+        Set<ModelType> refreshedTypes = new HashSet<ModelType>();
+        refreshedTypes.add(ModelType.BOOKMARK);
+        refreshedTypes.add(ModelType.TYPED_URL);
+        invalidationPreferences.setSyncTypes(edit, storedModelTypes);
+        Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
+        invalidationPreferences.setAccount(edit, storedAccount);
+        invalidationPreferences.commit(edit);
+
+        // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
+        // we can inspect in the test.
+        final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
+        final AtomicBoolean resultAllTypes = new AtomicBoolean();
+        final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
+        InvalidationController controller = new InvalidationController(mContext) {
+            @Override
+            public void setRegisteredTypes(
+                    Account account, boolean allTypes, Set<ModelType> types) {
+                resultAccount.set(account);
+                resultAllTypes.set(allTypes);
+                resultTypes.set(types);
+            }
+        };
+
+        // Execute the test.
+        controller.refreshRegisteredTypes(refreshedTypes);
+
+        // Validate the values.
+        assertEquals(storedAccount, resultAccount.get());
+        assertEquals(false, resultAllTypes.get());
+        assertEquals(ModelType.syncTypesToModelTypes(storedModelTypes), resultTypes.get());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testRefreshShouldReadValuesFromDiskWithAllTypes() {
+        // Store preferences for the ModelType.ALL_TYPES_TYPE and account. We
+        // are using the helper class for this, so we don't have to deal with
+        // low-level details such as preference keys.
+        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
+        InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
+        List<String> storedModelTypes = new ArrayList<String>();
+        storedModelTypes.add(ModelType.ALL_TYPES_TYPE);
+        invalidationPreferences.setSyncTypes(edit, storedModelTypes);
+        Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
+        invalidationPreferences.setAccount(edit, storedAccount);
+        invalidationPreferences.commit(edit);
+
+        // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
+        // we can inspect in the test.
+        final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
+        final AtomicBoolean resultAllTypes = new AtomicBoolean();
+        final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
+        InvalidationController controller = new InvalidationController(mContext) {
+            @Override
+            public void setRegisteredTypes(
+                    Account account, boolean allTypes, Set<ModelType> types) {
+                resultAccount.set(account);
+                resultAllTypes.set(allTypes);
+                resultTypes.set(types);
+            }
+        };
+
+        // Execute the test.
+        controller.refreshRegisteredTypes(new HashSet<ModelType>());
+
+        // Validate the values.
+        assertEquals(storedAccount, resultAccount.get());
+        assertEquals(true, resultAllTypes.get());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSetRegisteredObjectIds() {
+        InvalidationController controller = new InvalidationController(mContext);
+        ObjectId bookmark = ModelType.BOOKMARK.toObjectId();
+        controller.setRegisteredObjectIds(new int[] {1, 2, bookmark.getSource()},
+                                          new String[] {"a", "b", new String(bookmark.getName())});
+        assertEquals(1, mContext.getNumStartedIntents());
+
+        // Validate destination.
+        Intent intent = mContext.getStartedIntent(0);
+        validateIntentComponent(intent);
+        assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());
+
+        // Validate registered object ids. The bookmark object should not be registered since it is
+        // a Sync type.
+        assertNull(intent.getStringArrayListExtra(
+                                InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
+        Set<ObjectId> objectIds = InvalidationIntentProtocol.getRegisteredObjectIds(intent);
+        assertEquals(2, objectIds.size());
+        assertTrue(objectIds.contains(ObjectId.newInstance(1, "a".getBytes())));
+        assertTrue(objectIds.contains(ObjectId.newInstance(2, "b".getBytes())));
+    }
+
+    /**
+     * Asserts that {@code intent} is destined for the correct component.
+     */
+    private static void validateIntentComponent(Intent intent) {
+        assertNotNull(intent.getComponent());
+        assertEquals(InvalidationService.class.getName(),
+                intent.getComponent().getClassName());
+    }
+
+    /**
+     * Mock context that saves all intents given to {@code startService}.
+     */
+    private static class IntentSavingContext extends AdvancedMockContext {
+        private final List<Intent> startedIntents = new ArrayList<Intent>();
+
+        IntentSavingContext(Context targetContext) {
+            super(targetContext);
+        }
+
+        @Override
+        public ComponentName startService(Intent intent) {
+            startedIntents.add(intent);
+            return new ComponentName(this, getClass());
+        }
+
+        int getNumStartedIntents() {
+            return startedIntents.size();
+        }
+
+        Intent getStartedIntent(int idx) {
+            return startedIntents.get(idx);
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return getBaseContext().getPackageManager();
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
index 0232409..e571421 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
@@ -4,9 +4,9 @@
 
 package org.chromium.chrome.browser.translate;
 
+import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.MediumTest;
 
-
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -41,9 +41,11 @@
 
     /**
      * Test the translate language panel.
+     * @MediumTest
+     * @Feature({"Browser", "Main"})
+     * http://crbug.com/311197
      */
-    @MediumTest
-    @Feature({"Browser", "Main"})
+    @FlakyTest
     public void testTranslateLanguagePanel() throws InterruptedException {
         List<InfoBar> infoBars = getActivity().getActiveTab().getInfoBarContainer().getInfoBars();
         loadUrlWithSanitization(TestHttpServerClient.getUrl(TRANSLATE_PAGE));
@@ -56,10 +58,12 @@
 
 
     /**
-     *  Test the "never translate" panel.
+     * Test the "never translate" panel.
+     * @MediumTest
+     * @Feature({"Browser", "Main"})
+     * http://crbug.com/311197
      */
-    @MediumTest
-    @Feature({"Browser", "Main"})
+    @FlakyTest
     public void testTranslateNeverPanel() throws InterruptedException {
         List<InfoBar> infoBars = getActivity().getActiveTab().getInfoBarContainer().getInfoBars();
         loadUrlWithSanitization(TestHttpServerClient.getUrl(TRANSLATE_PAGE));
diff --git a/chrome/android/testshell/chrome_data_reduction_proxy_testshell_android.cc b/chrome/android/testshell/chrome_data_reduction_proxy_testshell_android.cc
deleted file mode 100644
index 7df5082..0000000
--- a/chrome/android/testshell/chrome_data_reduction_proxy_testshell_android.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2013 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/app/android/chrome_data_reduction_proxy_android.h"
-#include "net/http/http_network_session.h"
-
-void ChromeDataReductionProxyAndroid::Init(net::HttpNetworkSession* session) {
-}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
index 678bcc2..61461da 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
@@ -6,6 +6,7 @@
 
 import android.content.Intent;
 
+import org.chromium.base.CalledByNative;
 import org.chromium.base.PathUtils;
 import org.chromium.chrome.browser.ChromiumApplication;
 import org.chromium.chrome.browser.UmaUtils;
@@ -70,4 +71,12 @@
     @Override
     protected void openProtectedContentSettings() {
     }
+
+    @Override
+    protected void showSyncSettings() {
+    }
+
+    @Override
+    protected void showTermsOfServiceDialog() {
+    }
 }
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellTab.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellTab.java
index 0152f75..d480ca4 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellTab.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellTab.java
@@ -66,8 +66,9 @@
     /**
      * Navigates this Tab's {@link ContentView} to a sanitized version of {@code url}.
      * @param url The potentially unsanitized URL to navigate to.
+     * @param postData Optional data to be sent via POST.
      */
-    public void loadUrlWithSanitization(String url) {
+    public void loadUrlWithSanitization(String url, byte[] postData) {
         if (url == null) return;
 
         // Sanitize the URL.
@@ -80,10 +81,22 @@
         if (TextUtils.equals(url, contentView.getUrl())) {
             contentView.reload();
         } else {
-            contentView.loadUrl(new LoadUrlParams(url));
+            if (postData == null) {
+                contentView.loadUrl(new LoadUrlParams(url));
+            } else {
+                contentView.loadUrl(LoadUrlParams.createLoadHttpPostParams(url, postData));
+            }
         }
     }
 
+    /**
+     * Navigates this Tab's {@link ContentView} to a sanitized version of {@code url}.
+     * @param url The potentially unsanitized URL to navigate to.
+     */
+    public void loadUrlWithSanitization(String url) {
+        loadUrlWithSanitization(url, null);
+    }
+
     @Override
     protected TabBaseChromeWebContentsDelegateAndroid createWebContentsDelegate() {
         return new TestShellTabBaseChromeWebContentsDelegateAndroid();
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SyncController.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SyncController.java
index eb719a1..ab2c5e1 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SyncController.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SyncController.java
@@ -12,10 +12,10 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
-import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator;
+import org.chromium.chrome.browser.invalidation.InvalidationController;
+import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.sync.notifier.InvalidationController;
 import org.chromium.sync.notifier.SyncStatusHelper;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
@@ -100,6 +100,7 @@
         // The SigninManager handles most of the sign-in flow, and doFinishSignIn handles the
         // Chromium testshell specific details.
         SigninManager signinManager = SigninManager.get(mContext);
+        signinManager.onFirstRunCheckDone();
         final boolean passive = false;
         signinManager.startSignIn(activity, account, passive, new SigninManager.Observer() {
             @Override
diff --git a/chrome/android/testshell/javatests/OWNERS b/chrome/android/testshell/javatests/OWNERS
new file mode 100644
index 0000000..cfc5e65
--- /dev/null
+++ b/chrome/android/testshell/javatests/OWNERS
@@ -0,0 +1,9 @@
+aruslan@chromium.org
+bulach@chromium.org
+dfalcantara@chromium.org
+dtrainor@chromium.org
+miguelg@chromium.org
+nyquist@chromium.org
+skyostil@chromium.org
+tedchoc@chromium.org
+yfriedman@chromium.org
diff --git a/chrome/android/testshell/testshell_tab.cc b/chrome/android/testshell/testshell_tab.cc
index aded2f7..b625479 100644
--- a/chrome/android/testshell/testshell_tab.cc
+++ b/chrome/android/testshell/testshell_tab.cc
@@ -62,14 +62,6 @@
   NOTIMPLEMENTED();
 }
 
-void TestShellTab::ShowSyncSettings() {
-  NOTIMPLEMENTED();
-}
-
-void TestShellTab::ShowTermsOfService() {
-  NOTIMPLEMENTED();
-}
-
 bool TestShellTab::ShouldWelcomePageLinkToTermsOfService() {
   NOTIMPLEMENTED();
   return false;
diff --git a/chrome/android/testshell/testshell_tab.h b/chrome/android/testshell/testshell_tab.h
index cd45fbd..3ffe25e 100644
--- a/chrome/android/testshell/testshell_tab.h
+++ b/chrome/android/testshell/testshell_tab.h
@@ -59,8 +59,6 @@
                                      int b_value) OVERRIDE;
   virtual void EditBookmark(int64 node_id, bool is_folder) OVERRIDE;
 
-  virtual void ShowSyncSettings() OVERRIDE;
-  virtual void ShowTermsOfService() OVERRIDE;
   virtual bool ShouldWelcomePageLinkToTermsOfService() OVERRIDE;
   virtual void OnNewTabPageReady() OVERRIDE;
 
diff --git a/chrome/android/uiautomator_tests/OWNERS b/chrome/android/uiautomator_tests/OWNERS
new file mode 100644
index 0000000..7c31091
--- /dev/null
+++ b/chrome/android/uiautomator_tests/OWNERS
@@ -0,0 +1,7 @@
+aruslan@chromium.org
+craigdh@chromium.org
+dtrainor@chromium.org
+frankf@chromium.org
+nyquist@chromium.org
+tedchoc@chromium.org
+
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index 57e43d9..4d39b78 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -16,6 +16,7 @@
   "+content/public/browser/browser_main_runner.h",
   "+content/public/browser/render_process_host.h",
   "+grit",  # For generated headers
+  "+native_client/src/trusted/service_runtime/osx",
   "+policy",  # For generated headers and source
   "+sandbox",
   "+tools/memory_watcher",
diff --git a/chrome/app/PRESUBMIT.py b/chrome/app/PRESUBMIT.py
new file mode 100644
index 0000000..3a0e26b
--- /dev/null
+++ b/chrome/app/PRESUBMIT.py
@@ -0,0 +1,47 @@
+# Copyright 2013 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.
+
+"""Presubmit script for changes affecting chrome/app/
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into gcl.
+"""
+
+import os
+
+def _CheckNoProductNameInGeneratedResources(input_api, output_api):
+  """Check that no PRODUCT_NAME placeholders are found in resources files.
+
+  These kinds of strings prevent proper localization in some languages. For
+  more information, see the following chromium-dev thread:
+  https://groups.google.com/a/chromium.org/forum/#!msg/chromium-dev/PBs5JfR0Aoc/NOcIHII9u14J
+  """
+
+  problems = []
+  filename_filter = lambda x: x.LocalPath().endswith('.grd')
+
+  for f, line_num, line in input_api.RightHandSideLines(filename_filter):
+    if 'PRODUCT_NAME' in line:
+      problems.append('%s:%d' % (f.LocalPath(), line_num))
+
+  if problems:
+    return [output_api.PresubmitPromptWarning(
+        "Don't use PRODUCT_NAME placeholders in string resources. Instead, add "
+        "separate strings to google_chrome_strings.grd and "
+        "chromium_strings.grd. See http://goo.gl/6614MQ for more information."
+        "Problems with this check? Contact dubroy@chromium.org.",
+        items=problems)]
+  return []
+
+def _CommonChecks(input_api, output_api):
+  """Checks common to both upload and commit."""
+  results = []
+  results.extend(_CheckNoProductNameInGeneratedResources(input_api, output_api))
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _CommonChecks(input_api, output_api)
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _CommonChecks(input_api, output_api)
diff --git a/chrome/app/android/chrome_data_reduction_proxy_android.cc b/chrome/app/android/chrome_data_reduction_proxy_android.cc
deleted file mode 100644
index 63e63d9..0000000
--- a/chrome/app/android/chrome_data_reduction_proxy_android.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2013 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/app/android/chrome_data_reduction_proxy_android.h"
-
-#include "net/http/http_network_session.h"
-
-ChromeDataReductionProxyAndroid::ChromeDataReductionProxyAndroid() {
-}
-
-ChromeDataReductionProxyAndroid::~ChromeDataReductionProxyAndroid() {
-}
diff --git a/chrome/app/android/chrome_data_reduction_proxy_android.h b/chrome/app/android/chrome_data_reduction_proxy_android.h
deleted file mode 100644
index 9b32dff..0000000
--- a/chrome/app/android/chrome_data_reduction_proxy_android.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 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_APP_ANDROID_CHROME_DATA_REDUCTION_PROXY_ANDROID_H_
-#define CHROME_APP_ANDROID_CHROME_DATA_REDUCTION_PROXY_ANDROID_H_
-
-#include "net/http/http_network_session.h"
-
-// Sets up state to interact with the data reduction proxy.
-class ChromeDataReductionProxyAndroid {
- public:
-  static void Init(net::HttpNetworkSession* session);
-
- protected:
-  ChromeDataReductionProxyAndroid();
-  virtual ~ChromeDataReductionProxyAndroid();
-
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeDataReductionProxyAndroid);
-};
-
-#endif  // CHROME_APP_ANDROID_CHROME_DATA_REDUCTION_PROXY_ANDROID_H_
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 79dac9c..a0930b3 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -87,6 +87,7 @@
 #define IDC_ADVANCED_PRINT              35007
 #define IDC_PRINT_TO_DESTINATION        35008
 #define IDC_BOOKMARK_PAGE_FROM_STAR     35009
+#define IDC_TRANSLATE_PAGE              35010
 
 // When adding a new encoding to this list, be sure to append it to the
 // EncodingMenuController::kValidEncodingIds array in
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index ae7cdaa..e7ec598 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -252,32 +252,6 @@
       process_type == switches::kUtilityProcess;
 }
 
-#if defined(OS_MACOSX)
-// Update the name shown in Activity Monitor so users are less likely to ask
-// why Chrome has so many processes.
-void SetMacProcessName(const CommandLine& command_line) {
-  std::string process_type =
-      command_line.GetSwitchValueASCII(switches::kProcessType);
-  // Don't worry about the browser process, its gets the stock name.
-  int name_id = 0;
-  if (command_line.HasSwitch(switches::kExtensionProcess)) {
-    name_id = IDS_WORKER_APP_NAME;
-  } else if (process_type == switches::kRendererProcess) {
-    name_id = IDS_RENDERER_APP_NAME;
-  } else if (process_type == switches::kPluginProcess ||
-             process_type == switches::kPpapiPluginProcess) {
-    name_id = IDS_PLUGIN_APP_NAME;
-  } else if (process_type == switches::kUtilityProcess) {
-    name_id = IDS_UTILITY_APP_NAME;
-  }
-  if (name_id) {
-    NSString* app_name = l10n_util::GetNSString(name_id);
-    base::mac::SetProcessName(base::mac::NSToCFCast(app_name));
-  }
-}
-
-#endif  // defined(OS_MACOSX)
-
 #if defined(OS_POSIX)
 // Check for --version and --product-version; return true if we encountered
 // one of these switches and should exit now.
@@ -721,12 +695,6 @@
     CHECK(!loaded_locale.empty()) << "Locale could not be found for " <<
         locale;
 
-#if defined(OS_MACOSX)
-    // Update the process name (need resources to get the strings, so
-    // only do this when ResourcesBundle has been initialized).
-    SetMacProcessName(command_line);
-#endif  // defined(OS_MACOSX)
-
 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
     if (process_type == switches::kUtilityProcess)
       chrome::ChromeContentUtilityClient::PreSandboxStartup();
@@ -780,7 +748,10 @@
       mac_relauncher::internal::RelauncherMain },
 #endif
 
-#if !defined(DISABLE_NACL) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
+    // This entry is not needed on Linux, where the NaCl loader
+    // process is launched via nacl_helper instead.
+#if !defined(DISABLE_NACL) && !defined(CHROME_MULTIPLE_DLL_BROWSER) && \
+    !defined(OS_LINUX)
     { switches::kNaClLoaderProcess,  NaClMain },
 #else
     { "<invalid>", NULL },  // To avoid constant array of size 0
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 5b5b839..45ce7f4 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -356,6 +356,9 @@
   <message name="IDS_APP_START_APP_WAIT_MESSAGE" desc="Message displayed while installing and/or launching web application in kiosk mode.">
     Initializing application...
   </message>
+  <message name="IDS_APP_START_WAIT_FOR_APP_WINDOW_MESSAGE" desc="Message displayed while waiting for the application to create its window in kiosk mode.">
+    Waiting for application window...
+  </message>
   <message name="IDS_APP_START_CONFIGURE_NETWORK" desc="Text displayed for configure network button while installing and/or launching web application in kiosk mode.">
     Configure network
   </message>
@@ -967,13 +970,13 @@
     Delay before click:
   </message>
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_EXTREMELY_SHORT" desc="Label for an extremely short autoclick delay option in the settings.">
-    extremely short 
+    extremely short
   </message>
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_VERY_SHORT" desc="Label for a very short autoclick delay option in the settings.">
-    very short 
+    very short
   </message>
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_SHORT" desc="Label for a short autoclick delay option in the settings.">
-    short 
+    short
   </message>
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_LONG" desc="Label for a long autoclick delay option in the settings.">
     long
@@ -2223,11 +2226,11 @@
   </message>
   <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT"
            desc="Explanatory message about how to switch input methods">
-    Press alt+shift to switch between input methods.
+    Press Alt+Shift to switch between input methods.
   </message>
   <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT"
            desc="Explanatory message about how to select the previous input method">
-    Press ctrl+space to select the previous input method.
+    Press Ctrl+Space to select the previous input method.
   </message>
   <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_IME"
            desc="Label for extension IMEs">
@@ -2369,6 +2372,14 @@
            desc="The dropdown list item for 'Customize modifier keys' overlay">
     Escape
   </message>
+  <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_SEND_FUNCTION_KEYS"
+           desc="The checkbox label for a setting to interpret the top-row keys as function keys instead.">
+    Treat top-row keys as function keys
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_SEND_FUNCTION_KEYS_DESCRIPTION"
+           desc="A label describing how to use the top-row keys' original actions when the treat-as-function-keys setting is enabled.">
+    Hold the Search key to switch the behavior of the top-row keys.
+  </message>
   <message name="IDS_OPTIONS_SETTINGS_CHANGE_LANGUAGE_AND_INPUT_SETTINGS"
            desc="The link to open 'Language and input settings' window.">
     Change language and input settings
@@ -3140,7 +3151,7 @@
     Mirror monitors
   </message>
   <message name="IDS_KEYBOARD_OVERLAY_NEW_INCOGNITO_WINDOW" desc="The text in the keyboard overlay to explain the shortcut.">
-    New Incognito window
+    New incognito window
   </message>
   <message name="IDS_KEYBOARD_OVERLAY_NEW_TAB" desc="The text in the keyboard overlay to explain the shortcut.">
     New tab
@@ -3166,6 +3177,9 @@
   <message name="IDS_KEYBOARD_OVERLAY_OPEN_FILE_MANAGER" desc="The text in the keyboard overlay to explain the shortcut (Open the file manager).">
     Open file manager
   </message>
+  <message name="IDS_KEYBOARD_OVERLAY_OPEN_GOOGLE_CLOUD_PRINT" desc="The text in the keyboard overlay to explain the shortcut (Opens the 'Google Cloud Print' dialog).">
+    Open Google Cloud Print
+  </message>
   <message name="IDS_KEYBOARD_OVERLAY_PAGE_DOWN" desc="The text in the keyboard overlay to explain the shortcut (Page down).">
     Page down
   </message>
@@ -3827,13 +3841,13 @@
 
   <!-- HDCP verification UI -->
   <message name="IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE" desc="The label to describe what the dialog wants to confirm.">
-    Google needs to uniquely identify your device to authorize the playback of HD content. <ph name="LEARN_MORE">$1<ex>Learn more</ex></ph>.
+    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires unique identification of your device, by Google, to play HD content. <ph name="LEARN_MORE">$2<ex>Learn more</ex></ph>.
   </message>
   <message name="IDS_PLATFORM_VERIFICATION_DIALOG_ALLOW" desc="The button label to allow access of HD playback.">
     Okay, got it
   </message>
   <message name="IDS_PLATFORM_VERIFICATION_DIALOG_DENY" desc="The button label to deny access of HD playback.">
-    No, disable HD
+    Disable HD on <ph name="DOMAIN">$1<ex>example.com</ex></ph>
   </message>
 
 </grit-part>
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index c4d51bb..37a6666 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -497,6 +497,11 @@
           Do you want Chromium to save your password for this site?
         </message>
       </if>
+      <if expr="is_macosx">
+        <message name="IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT" desc="Text for the dialog box that prompts the user for their OS account password before revealing plaintext passwords on the password page.">
+          Chromium is trying to show passwords.
+        </message>
+      </if>
       <message name="IDS_CANT_WRITE_USER_DIRECTORY_EXIT_BUTTON" desc="Text on button of dialog that closes Chrome if we can't create a directory for this user.">
         Exit Chromium
       </message>
@@ -656,13 +661,8 @@
       </message>
 
       <message name="IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS"
-               desc="Message shown on the download shelf when the download is known to change browser settings.">
-        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> may change your Chromium settings.
-      </message>
-
-      <message name="IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS"
-               desc="Message shown on the download shelf when the download is known to change search engine settings in the browser.">
-        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> may change how your searches work in Chromium.
+               desc="Message shown on the download shelf when the download is known to change settings in the browser in a malicious way.">
+        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> makes settings changes similar to some malware, so Chromium has blocked it.
       </message>
 
       <message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_URL"
@@ -848,23 +848,6 @@
         <message name="IDS_SHORT_HELPER_NAME" desc="The helper application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Helper, not Google Chrome Helper.">
           Chromium Helper
         </message>
-
-        <!-- TODO(mark): All helper tasks are currently handled by the helper process.  The following strings exist in support of possibly changing things so that there's a distinct .app bundle for each of the various tasks.  This ensures that if and when a split is made, translated names will be available.  If the helper process is not split into multiple .app bundles, these strings can be removed. -->
-        <message name="IDS_RENDERER_APP_NAME" desc="The renderer application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Renderer.">
-          Chromium Renderer
-        </message>
-        <message name="IDS_PLUGIN_APP_NAME" desc="The plug-in host application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Plug-In Host.">
-          Chromium Plug-In Host
-        </message>
-        <message name="IDS_SHORT_PLUGIN_APP_NAME" desc="The plug-in host application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Plug-In Host, not Google Chrome Plug-In Host.">
-          Chromium Plug-In Host
-        </message>
-        <message name="IDS_WORKER_APP_NAME" desc="The worker application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Worker.">
-          Chromium Worker
-        </message>
-        <message name="IDS_UTILITY_APP_NAME" desc="The utility application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Utility.">
-          Chromium Utility
-        </message>
       </if>
 
       <!-- One click sign in infobar -->
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index df07360..0b94992 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1200,7 +1200,7 @@
           Auto detect
         </message>
         <message name="IDC_VISIT_DESKTOP_OF_LRU_USER" desc="The text label of the menu item which allows the user to move a window from one users desktop to another.">
-          Teleport window to '<ph name="USER_NAME">$1<ex>User name</ex></ph>' 
+          Teleport window to '<ph name="USER_NAME">$1<ex>User name</ex></ph>'
         </message>
       </if>
       <message name="IDS_ACCNAME_ZOOM_PLUS2" desc="The accessible description of the Make Text Larger menu item in the merged menu">
@@ -1520,6 +1520,9 @@
       </if>
 
       <!-- Keywords -->
+      <message name="IDS_ANNOTATED_SUGGESTION" desc="A suggested search query in the omnibox dropdown, annotated to disambiguate it from other similar queries.">
+        <ph name="SUGGESTION">$1<ex>roosevelt</ex></ph> - <ph name="ANNOTATION">$2<ex>Franklin D. Roosevelt, 32nd U.S. President</ex></ph>
+      </message>
       <message name="IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR" desc="The separator between a result in the autocomplete popup and its description.">
         ''' - '''
       </message>
@@ -1848,10 +1851,12 @@
                desc="Prompt text for the confirmation dialog asking whether the user really meant to keep a dangerous download">
         This might hurt. Don't say we didn't warn you...
       </message>
-      <message name="IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD"
-               desc="Prompt text for the confirmation dialog asking whether the user really meant to keep a malicious download">
+      <message name="IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD"
+               desc="Lead prompt text for the confirmation dialog asking whether the user really meant to keep a malicious download">
         This file will harm your computer.
-
+      </message>
+      <message name="IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY"
+               desc="Body prompt text for the confirmation dialog asking whether the user really meant to keep a malicious download">
 Even if you have downloaded files from this website before, the website might have been hacked. Instead of recovering this file, you can retry the download later.
       </message>
       <message name="IDS_CONFIRM_DOWNLOAD_AGAIN"
@@ -3982,8 +3987,8 @@
       <message name="IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE" desc="Titlebar of the extension or app permissions review window">
         Current Permissions
       </message>
-      <message name="IDS_EXTENSION_FIRST_RUN_PROMPT_TITLE" desc="Titlebar of the extension or app permissions prompt window">
-        Confirm Permissions
+      <message name="IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE" desc="Titlebar of the app launch prompt window">
+        Confirm Launch App
       </message>
       <message name="IDS_EXTENSION_INSTALL_PROMPT_HEADING" desc="First bold line in the content area of the extension or app installation prompt. Asks the user if they want to install a particular extension or app.">
         Add "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
@@ -4009,8 +4014,8 @@
       <message name="IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING" desc="First bold line in the content area of the extension or app permissions prompt. Shows the user the permissions a particular extension or app has.">
         <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>
       </message>
-      <message name="IDS_EXTENSION_FIRST_RUN_PROMPT_HEADING" desc="First bold line in the content area of the extension or app permissions prompt. Asks the user if they want to accept permission for a particular app.">
-        Enable "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
+      <message name="IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING" desc="First bold line in the content area of the app launch prompt. Asks the user if they want to launch a particular app.">
+        Launch "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
       </message>
 
       <!-- Extension alerts. -->
@@ -4300,9 +4305,6 @@
       <message name="IDS_EXTENSION_PROMPT_WARNING_DOWNLOADS_OPEN" desc="Permission string for access to downloads.">
         Open downloaded files
       </message>
-      <message name="IDS_EXTENSION_PROMPT_WARNING_IDENTITY_EMAIL" desc="Permission string for access to profile email address.">
-        View email addresses signed in to your profile
-      </message>
       <message name="IDS_EXTENSION_PROMPT_WARNING_WALLPAPER" desc="Permission string for access to wallpaper.">
         Change your wallpaper
       </message>
@@ -4903,14 +4905,11 @@
       <message name="IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE" desc="The generic 'activate extension' text used as description for some commands.">
         Activate the extension
       </message>
-      <message name="IDS_EXTENSION_COMMANDS_GLOBAL" desc="The tooltip for commands that are global in nature.">
-        This keyboard shortcut is active at all times (not just when Chrome has focus). Click to change.
+      <message name="IDS_EXTENSION_COMMANDS_GLOBAL" desc="The text in the select box for commands that are global in nature (the shortcut works when Chrome does not have focus).">
+        Global
       </message>
-      <message name="IDS_EXTENSION_COMMANDS_NOT_GLOBAL" desc="The tooltip for commands that are not global in nature.">
-        This keyboard shortcut is only active when Chrome has focus. Click to change.
-      </message>
-      <message name="IDS_EXTENSION_COMMANDS_NOT_GLOBAL_PERMANENT" desc="The tooltip for commands that are not global in nature and never can be.">
-        This keyboard shortcut is only active when Chrome has focus.
+      <message name="IDS_EXTENSION_COMMANDS_NOT_GLOBAL" desc="The text in the select box for commands that are not global in nature (the shortcut works only when Chrome has focus).">
+        In Chrome
       </message>
 
       <message name="IDS_EXTENSION_PACK_DIALOG_TITLE" desc="Title of pack extension dialog">
@@ -4975,6 +4974,9 @@
       <message name="IDS_EXTENSION_PROMPT_INSTALL_BUTTON" desc="Text for the install button on the extension install prompt">
         Add
       </message>
+      <message name="IDS_EXTENSION_PROMPT_LAUNCH_BUTTON" desc="Text for the launch button on the extension install prompt">
+        Launch
+      </message>
       <message name="IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON" desc="Text for the uninstall button on the extension uninstall prompt">
         Remove
       </message>
@@ -4990,9 +4992,6 @@
       <message name="IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON" desc="Text for the Revoke File Access button on the extension permissions prompt">
         Revoke File Access
       </message>
-      <message name="IDS_EXTENSION_PROMPT_FIRST_RUN_ACCEPT_BUTTON" desc="Text for the allow button on the first run promopt to accept permissions and launch app">
-        Accept and open
-      </message>
       <message name="IDS_EXTENSION_WEB_STORE_TITLE" desc="Text for the Chrome Web Store">
         Chrome Web Store
       </message>
@@ -5637,6 +5636,12 @@
       <message name="IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_DESCRIPTION" desc="Description of the 'device discovery notifications' flag.">
         Device discovery notifications on local network.
       </message>
+      <message name="IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_NAME">
+        Enable Privet local printing
+      </message>
+      <message name="IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_DESCRIPTION">
+        Print to printers on the local network using the Privet protocol.
+      </message>
       <message name="IDS_FLAGS_TOUCH_OPTIMIZED_UI_NAME" desc="Title of the touch-optimized UI flag." >
         Touch Optimized UI
       </message>
@@ -5893,6 +5898,12 @@
       <message name="IDS_FLAGS_NTP_SUGGESTIONS_PAGE_DESCRIPTION" desc="Description of the 'Enable suggestions page' lab.">
         Add 'Suggestions' card to the new tab page, which suggests the pages to be opened.
       </message>
+      <message name="IDS_FLAGS_ENABLE_IME_MODE_INDICATOR" desc="Title for the flag to enable the new indicator for the active keyboard input mode.">
+        Enable the new indicator for the active keyboard input method
+      </message>
+      <message name="IDS_FLAGS_ENABLE_IME_MODE_INDICATOR_DESCRIPTION" desc="Description for the flag to enable the new indicator for the active keyboard input method.">
+        Shows the active input method near the caret when switching between keyboard input methods.
+      </message>
       <message name="IDS_FLAGS_ENABLE_INSTANT_EXTENDED_API" desc="Title for the flag to enable the Instant extended API.">
         Enable Instant Extended API
       </message>
@@ -6029,6 +6040,24 @@
       <message name="IDS_FLAGS_DISABLE_OVERVIEW_MODE_DESCRIPTION" desc="Description for the flag to disable window overview mode.">
         Disable overview mode, activated by pushing the switch window button.
       </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_NAME" desc="Title for the delay before engaging overview on alt+tab.">
+        Delay before engaging overview when cycling.
+      </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_DESCRIPTION" desc="Description for what the delay before engaging overview means.">
+        The time from the last alt+tab press before engaging overview mode when cycling through windows.
+      </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_INSTANT" desc="The choice to have overview engage immediately on alt+tab.">
+        Instant
+      </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_SHORT" desc="The choice to have overview engage almost immediately on alt+tab.">
+        Very short
+      </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_LONG" desc="The choice to have overview engage after a fairly long delay.">
+        Long
+      </message>
+      <message name="IDS_FLAGS_OVERVIEW_DELAY_NEVER" desc="The choice to have overview not engage on alt+tab.">
+        Never
+      </message>
       <message name="IDS_FLAGS_SCROLL_END_EFFECT_NAME" desc="Title for the flag for scroll end effect from vertical overscroll.">
         Scroll end effect
       </message>
@@ -6265,12 +6294,6 @@
         <message name="IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_DESCRIPTION" desc="Description for the flag to disable infobar popup for protected media identifier.">
           Disable infobar popup by default when accessing the protected media identifier.
         </message>
-        <message name="IDS_FLAGS_ENABLE_MEDIADRM_NAME" desc="Title for the flag to enable MediaDrm for encrypted content.">
-          Enable MediaDrm.
-        </message>
-        <message name="IDS_FLAGS_ENABLE_MEDIADRM_DESCRIPTION" desc="Description for the flag to enable MediaDrm for encrypted content.">
-          Enable MediaDrm by default for Encrypted Media Extensions.
-        </message>
         <message name="IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_NAME" desc="Title for the flag to enable non-conmpositing decoding in MediaDrm for encrypted content.">
           Enable non-compositing decoding.
         </message>
@@ -6327,12 +6350,6 @@
       <message name="IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_DESCRIPTION" desc="Description for the flag to disable drag and drop opertions from the app list menu to the launcher.">
         Disallow drag and drop from the app list menu to the shelf.
       </message>
-      <message name="IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_NAME" desc="Title for the flag for immersive fullscreen mode.">
-        Immersive fullscreen
-      </message>
-      <message name="IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_DESCRIPTION" desc="Description for the flag for immersive fullscreen mode.">
-        Enables "immersive fullscreen" where the tab strip at the top and the app shelf at the bottom are still accessible in fullscreen.
-      </message>
       <message name="IDS_FLAGS_ENABLE_MEMORY_MONITOR_NAME" desc="Title for the flag to enable advanced gestures.">
         Enable memory monitor
       </message>
@@ -6340,10 +6357,10 @@
         Enables visual memory monitor in status area.
       </message>
       <message name="IDS_FLAGS_ENABLE_FULL_MULTI_PROFILE_MODE" desc="Title for the full multi profile mode flag.">
-        Enable full multi profile mode
+        Enable side-by-side multi profile mode
       </message>
       <message name="IDS_FLAGS_ENABLE_FULL_MULTI_PROFILE_MODE_DESCRIPTION" desc="Title for the full multi profile mode flag.">
-        Enable full multi profile mode
+        Enable side-by-side multi profile mode in which all browser and app windows share the same workspace.
       </message>
       <message name="IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_NAME" desc="Title for a flag for audio switching.">
         Audio input/output menu
@@ -6454,12 +6471,6 @@
       <message name="IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION" desc="Description for the flag to force synchronous spellchecking.">
         Turn on autocorrection of text while typing. Synchronous spellchecking is not compatible with this feature.
       </message>
-      <message name="IDS_FLAGS_NO_DISCARD_TABS_NAME" desc="Name for the flag to disable the tab discarding feature.">
-        Don't discard tabs.
-      </message>
-      <message name="IDS_FLAGS_NO_DISCARD_TABS_DESCRIPTION" desc="Description for the flag to disable the tab discarding feature.">
-        Turns off tab discarding, a feature that discards infrequently used tabs under low memory conditions.
-      </message>
       <message name="IDS_FLAGS_DOCKED_WINDOWS_NAME" desc="Name for the flag to enable docked windows feature.">
         Enable docking of windows near screen edges.
       </message>
@@ -6545,12 +6556,6 @@
         <message name="IDS_FLAGS_ENABLE_STICKY_KEYS_DESCRIPTION" desc="Description for the flag to enable sticky keys.">
           StickyKeys allows the user to press and release a modifier key, such as Shift, Ctrl, or Alt, and have it remain active until any other key is pressed.
         </message>
-        <message name="IDS_FLAGS_ENABLE_AUTOCLICK_NAME" desc="Name for the flag to enable autoclick.">
-          Enable autoclick.
-        </message>
-        <message name="IDS_FLAGS_ENABLE_AUTOCLICK_DESCRIPTION" desc="Description for the flag to enable autoclick.">
-          Enables an accessibility setting which automatically triggers a click when the mouse pointer stops.
-        </message>
         <message name="IDS_FLAGS_ENABLE_SAML_SIGNIN_NAME" desc="Name for the flag to enable SAML signin support.">
           Enable SAML signin.
         </message>
@@ -6606,11 +6611,11 @@
       <message name="IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_DESCRIPTION" desc="Description of flag to enable or disable public suffix domain matching for autofill of passwords.">
         Enable or disable a feature which allows the user to select username/password combinations for domains that match the same public suffix registry domain.
       </message>
-      <message name="IDS_FLAGS_ENABLE_PEOPLE_SEARCH_NAME" desc="Name of the flag to enable people search.">
-        Enable people search.
+      <message name="IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME" desc="Name of the flag for the password manager reauthentication option.">
+        Password Manager Reauthentication
       </message>
-      <message name="IDS_FLAGS_ENABLE_PEOPLE_SEARCH_DESCRIPTION" desc="Description of flag to enable people search.">
-        Enable searching for people directly from the apps list search.
+      <message name="IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION" desc="Description of the flag for the password manager reauthentication option.">
+        Prompt the user for their OS password before revealing passwords on the passwords page.
       </message>
       <message name="IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_NAME" desc="Name for the flag to enable Performance Monitor.">
         Enable performance monitoring
@@ -6822,14 +6827,6 @@
       <message name="IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_DESCRIPTION" desc="Description for the flag to disable sync of user account image.">
         Disables sync of user account image between different ChromeOS devices.
       </message>
-      <if expr="is_android">
-        <message name="IDS_FLAGS_ENABLE_CAST_NAME" desc="Name of the flag to enable Chromecast support.">
-          Enable Chromecast support
-        </message>
-        <message name="IDS_FLAGS_ENABLE_CAST_DESCRIPTION" desc="Description for the flag to enable playing videos remotely on Chromecast.">
-          Enable playing videos remotely on Chromecast.
-        </message>
-      </if>
       <if expr="pp_ifdef('chromeos')">
         <message name="IDS_FLAGS_ENABLE_FIRST_RUN_UI_NAME" desc="Name of the flag to enable new first-run UI.">
           Enable new first-run UI.
@@ -6874,6 +6871,20 @@
       <message name="IDS_FLAGS_ENABLE_SERVICE_WORKER_DESCRIPTION" desc="Description for the flag to enable ServiceWorker.">
         ServiceWorker is a new kind of web worker that can intercept resource requests. See https://github.com/slightlyoff/ServiceWorker for more information.
       </message>
+      <if expr="is_android">
+        <message name="IDS_FLAGS_DISABLE_CLICK_DELAY_NAME" desc="Name of the flag to disable the click delay.">
+          Disable click delay.
+        </message>
+        <message name="IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION" desc="Description of the flag to disable the click delay.">
+          Always send click events immediate upon a tap, even when it's part of a double-tap gesture.  This speeds up navigation and other tap actions by 300ms on most pages, but means links and buttons must be avoided when double tapping to zoom.
+        </message>
+      </if>
+      <message name="IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME" desc="Name of the flag to enable the new Translate UX.">
+        Enable the new Translate UX.
+      </message>
+      <message name="IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION" desc="Description for the flag to enable the new Translate UX.">
+        Enable the new Translate bubble UX is offered instead of the infobar.
+      </message>
 
       <!-- Crashes -->
       <message name="IDS_CRASHES_TITLE" desc="Title for the chrome://crashes page.">
@@ -7431,6 +7442,9 @@
       <message name="IDS_TOOLTIP_MIC_SEARCH" desc="The tooltip for search-by-voice button">
         Search by voice
       </message>
+      <message name="IDS_TOOLTIP_TRANSLATE" desc="The tooltip for translate">
+        Translate this page
+      </message>
       <message name="IDS_TOOLTIP_ZOOM" desc="The tooltip for zoom icon">
         Zoom: <ph name="VALUE">$1<ex>100</ex></ph>%
       </message>
@@ -7784,9 +7798,10 @@
       </message>
       <message name="IDS_FEEDBACK_PRIVACY_NOTE" desc="Text for the privacy note included with Chrome OS">
         Your Chrome and operating system version will be submitted in addition
-        to any information you choose to include above. This feedback is used to
-        diagnose problems and help improve Chrome. Any personal information you
-        submit, whether explicitly or incidentally will be protected in
+        to any information you choose to include above. If you include your email
+        address, Google may contact you regarding your feedback report. This feedback
+        is used to diagnose problems and help improve Chrome. Any personal information
+        you submit, whether explicitly or incidentally will be protected in
         accordance with our privacy policies.<ph name="BEGIN_BOLD">&lt;strong&gt;
         </ph> By submitting this feedback, you agree that Google may use feedback
         that you provide to improve any Google product or service.
@@ -8589,7 +8604,7 @@
         Adding your printers to Google Cloud Print allows you to print from
         anywhere, to anywhere. Share your printers with whoever you choose and
         print to them from Chrome, your phone, tablet, PC, or any other
-        web-connected device. <ph name="START_LINK">$1</ph>Learn more<ph name="END_LINK">$2</ph>
+        web-connected device.
       </message>
       <message name="IDS_PRINT_PREVIEW_NO_DESTS_PROMO_ADD_PRINTER_BUTTON_LABEL" desc="Label of button to setup Google Cloud Print printers.">
         Add a printer
@@ -9622,6 +9637,14 @@
       <message name="IDS_FONT_LANGUAGE_SETTING_PLACEHOLDER" desc="Placeholder string for the Fonts and Encodings select menus">
         Loading...
       </message>
+      <message name="IDS_FONT_LANGUAGE_SETTING_ADVANCED_FONT_SETTINGS_INSTALL"
+               desc="Explanatory message about how to get the Advanced Font Settings extension">
+        <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>Advanced font settings<ph name="END_LINK">&lt;/a&gt;</ph> (requires extension)
+      </message>
+      <message name="IDS_FONT_LANGUAGE_SETTING_ADVANCED_FONT_SETTINGS_OPTIONS"
+               desc="Link to the Advanced Font Settings extension's options page">
+        Advanced font settings
+      </message>
 
       <!-- Language & spell-checker settings -->
       <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_DIALOG_TITLE">
@@ -9697,10 +9720,10 @@
       <message name="IDS_HTTP_POST_WARNING_TITLE" desc="Title for dialog that warns users about a navigation that results in a repost">
         Confirm Form Resubmission
       </message>
-      <message name="IDS_HTTP_POST_WARNING" desc="Re-navigation to page that leads to HTTP POST">
+      <message name="IDS_HTTP_POST_WARNING" desc="Re-navigation to page that leads to HTTP POST" formatter_data="android_java">
         The page that you're looking for used information that you entered. Returning to that page might cause any action you took to be repeated. Do you want to continue?
       </message>
-      <message name="IDS_HTTP_POST_WARNING_RESEND" desc="Resend button for post warning">
+      <message name="IDS_HTTP_POST_WARNING_RESEND" desc="Resend button for post warning" formatter_data="android_java">
         Continue
       </message>
 
@@ -10416,17 +10439,36 @@
       </message>
 
       <!-- Autofill dialog: legal documents -->
-      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_2" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_2" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept new legal documents (ex: Privacy Policy, Terms Of Service).">
         By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph> and <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Privacy Policy</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
       </message>
-      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_3" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
-        By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Virtual Card Notice</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Terms Of Use</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_3" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept new legal documents (ex: Privacy Policy, Terms Of Service).">
+        By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Privacy Policy</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
       </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_4" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept new legal documents (ex: Privacy Policy, Terms Of Service).">
+        By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Privacy Policy</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_5" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept new legal documents (ex: Privacy Policy, Terms Of Service).">
+        By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Further Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_5">$5<ex>Privacy Policy</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_6" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept new legal documents (ex: Privacy Policy, Terms Of Service).">
+        By clicking Continue you agree to the <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Further Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_5">$5<ex>Further Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_6">$6<ex>Privacy Policy</ex></ph>. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+
       <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_2" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
         The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph> and <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Privacy Policy</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
       </message>
       <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_3" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
-        The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Privacy Policy</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Terms Of Use</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+        The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms Of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Privacy Policy</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_4" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
+        The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms Of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms Of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Privacy Policy</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_5" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
+        The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms Of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms Of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Even More Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_5">$5<ex>Privacy Policy</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
+      </message>
+      <message name="IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_6" desc="Label at the bottom of the autofill dialog that is shown when a user needs to accept updated legal documents (ex: Privacy Policy, Terms Of Service).">
+        The <ph name="LEGAL_DOC_LINK_TEXT_1">$1<ex>Google Wallet Terms Of Service</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_2">$2<ex>Terms Of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_3">$3<ex>Further Terms Of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_4">$4<ex>Even More Terms of Use</ex></ph>, <ph name="LEGAL_DOC_LINK_TEXT_5">$5<ex>Yet More Terms of Use</ex></ph>, and <ph name="LEGAL_DOC_LINK_TEXT_6">$6<ex>Privacy Policy</ex></ph> have been updated. By clicking Continue you verify that you accept these changes. To protect you from fraud, information about your computer (including its location) will be shared with Google Wallet.
       </message>
 
       <!-- Autofill dialog: validation messages -->
@@ -10445,9 +10487,6 @@
       <message name="IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE" desc="Message displayed to user when credit card expiration date validation fails.">
         The card is expired. Please check the date or enter a new card.
       </message>
-      <message name="IDS_AUTOFILL_DIALOG_VALIDATION_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET" desc="Message displayed to user when user entered a credit card number that is not supported by Google Wallet.">
-        This type of card is not supported by Google Wallet. Please select a different card.
-      </message>
       <message name="IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_ZIP_CODE" desc="Message displayed to user when ZIP code (postal code) validation fails.">
         Invalid ZIP code. Please check and try again.
       </message>
@@ -11179,6 +11218,10 @@
                  desc="Text for the button that opens the app maximized. (In sentence case.)">
           Open maximized
         </message>
+        <message name="IDS_APP_CONTEXT_MENU_OPEN_TAB"
+                 desc="Text for the button that opens the app in a tab. (In sentence case.)">
+          Open in a tab
+        </message>
       </if>
 
       <if expr="pp_ifdef('use_titlecase')">
@@ -11222,6 +11265,10 @@
                  desc="Text for the button that opens the app maximized. (In title case.)">
           Open Maximized
         </message>
+        <message name="IDS_APP_CONTEXT_MENU_OPEN_TAB"
+                 desc="Text for the button that opens the app in a tab. (In title case.)">
+          Open in a Tab
+        </message>
       </if>
 
       <if expr="is_android">
@@ -13540,7 +13587,7 @@
         Nope
       </message>
       <message name="IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE" desc="Button label shown to never translate a specific language in the translate infobar">
-        Never translate <ph name="language">$1<ex>English</ex></ph>
+        Never translate <ph name="language">$1<ex>French</ex></ph>
       </message>
       <message name="IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE" desc="Button label shown to always translate a specific language in the translate infobar">
         Always translate <ph name="language">$1<ex>English</ex></ph>
@@ -13677,13 +13724,16 @@
         Upper right
       </message>
       <message name="IDS_NOTIFICATION_WELCOME_BODY" desc="Notification body for the Welcome Notification">
-        With Google Now, stay connected to what you need to know, across all devices.
+        Stay connected to what you need to know, across all devices.
+      </message>
+      <message name="IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE" desc="Learn more button text for the Welcome Notification">
+        Learn more
       </message>
       <message name="IDS_NOTIFICATION_WELCOME_DISPLAY_SOURCE" desc="Display source for the Welcome Notification">
         Notifications
       </message>
       <message name="IDS_NOTIFICATION_WELCOME_TITLE" desc="Notification title for the Welcome Notification">
-        Chrome notifications just got better!
+        Google Now on your desktop!
       </message>
       <if expr="is_macosx">
         <message name="IDS_MESSAGE_CENTER_FOOTER_WITH_PRODUCT_TITLE" desc="The label in the footer of the message center tray, with the product title.">
@@ -14416,12 +14466,16 @@
       <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_VALIDATION_FAILED" desc="Error message shown on the enrollment screen upon a failure to validate downloaded policy.">
         The policy downloaded from the server is invalid: <ph name="VALIDATION_ERROR">$1<ex>Invalid signature</ex></ph>.
       </message>
-      <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_ROBOT_AUTH_FETCH_FAILED" desc="Error message shown on the enrollment screen upon failure to fetch the OAuth2 authorization code for device-level API access.">
+      <message name="IDS_ENTERPRISE_ENROLLMENT_ROBOT_AUTH_FETCH_FAILED" desc="Error message shown on the enrollment screen upon failure to fetch the OAuth2 authorization code for device-level API access.">
         Oops!  The system failed to authorize API access for this device.
       </message>
-      <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_ROBOT_REFRESH_FETCH_FAILED" desc="Error message shown on the enrollment screen upon failure to fetch the OAuth2 refresh token for device-level API access.">
+      <message name="IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_FETCH_FAILED" desc="Error message shown on the enrollment screen upon failure to fetch the OAuth2 refresh token for device-level API access.">
         Oops!  The system failed to attain a long-term API access token for this device.
       </message>
+      <message name="IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_STORE_FAILED" desc="Error message shown on the enrollment screen upon failure to store the OAuth2 refresh token for device-level API access.">
+        Oops!  The system failed to store the long-term API access token for this device.
+      </message>
+
       <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_LOCK_ERROR" desc="Error message shown on the enrollment screen upon failure to lock the device mode.">
         Oops!  The system failed to establish the device installation-time attributes lock.
       </message>
@@ -14735,10 +14789,10 @@
       Oops! The new supervised user couldn't be created. Please make sure you're signed in properly and try again.
     </message>
     <message name="IDS_PROFILES_CREATE_MANAGED_SIGNED_IN_LABEL" desc="Label for the 'Supervised user' checkbox in the create-profile dialog when the current user is signed in. This will be followed by a 'Learn more' link.">
-      This is a supervised user managed by <ph name="CUSTODIAN_EMAIL">$1<ex>user@gmail.com</ex>.</ph>
+      This is a supervised user managed by <ph name="CUSTODIAN_EMAIL">$1<ex>user@gmail.com</ex></ph>.
     </message>
     <message name="IDS_PROFILES_CREATE_MANAGED_ACCOUNT_DETAILS_OUT_OF_DATE_LABEL" desc="Label for the 'Supervised user' checkbox in the create-profile dialog when the current user is signed in, but their login information is invalid. This will be followed by a 'Sign in again' link.">
-      This is a supervised user managed by <ph name="CUSTODIAN_EMAIL">$1<ex>user@gmail.com</ex>.</ph>
+      This is a supervised user managed by <ph name="CUSTODIAN_EMAIL">$1<ex>user@gmail.com</ex></ph>.
 Your account sign-in details are out of date.
     </message>
     <message name="IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN" desc="Warning message shown in the create-profile dialog when the custodian signed in recently, sync has not yet finished initializing, and so the creation process is likely to take extra time.">
@@ -14783,10 +14837,7 @@
 
 Creating a supervised user does not create a Google Account, and their settings and data will not follow them to other devices with Chrome Sync. Currently, a supervised user applies only to this installation of Chrome, on this device.
 
-After you create a new supervised user, you can manage their settings at any time, from any device, at www.chrome.com/manage.
-    </message>
-    <message name="IDS_NEW_MANAGED_USER_LEARN_EVEN_MORE_LABEL" desc="Label for the link within the 'Learn more' dialog for the supervised user feature, which links to a Help Center article giving even more information about the feature.">
-      Learn even more
+After you create a new supervised user, you can manage their settings at any time, from any device, at www.chrome.com/manage. <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chrome/?p=ui_supervised_users&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more about supervised users<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
     </message>
     <message name="IDS_NEW_MANAGED_USER_LEARN_MORE_DONE_BUTTON" desc="Text for the 'OK' button on the 'Learn more' dialog for the supervised user feature.">
       OK, got it!
@@ -15005,11 +15056,11 @@
     <message name="IDS_FLAGS_ENABLE_INLINE_SIGNIN_DESCRIPTION" desc="Description for the flag to enable inline signin flows">
       Enables inline sign flows, still using the existing gaia template.
     </message>
-    <message name="IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_NAME" desc="Title for the flag to enable the gaia profile information">
-      Enable GAIA profile name and icon
+    <message name="IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME" desc="Title for the flag to enable the google profile information">
+      Enable Google profile name and icon
     </message>
-    <message name="IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_DESCRIPTION" desc="Description for the flag to enable the gaia profile information">
-      Enables using GAIA information to populate the profile name and icon in the avatar menu.
+    <message name="IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION" desc="Description for the flag to enable the google profile information">
+      Enables using Google information to populate the profile name and icon in the avatar menu.
     </message>
     <message name="IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_NAME" desc="Name of about:flags option to turn on Google Now integration">
       Google Now
@@ -15031,6 +15082,13 @@
       Enable virtual keyboard support.
     </message>
 
+    <message name="IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME" desc="Name of about:flags option to turn on swipe selection for the virtual keyboard">
+      Swipe Selection
+    </message>
+    <message name="IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION" desc="Description of about:flags option to turn on swipe selection for the virtual keyboard">
+      Enable Swipe Selection support for the virtual keyboard. Unless the virtual keyboard is also enabled, this will do nothing.
+    </message>
+
     <!-- Simple Cache Backend experiment. -->
     <message name="IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME" desc="Name of about:flags option to turn on the Simple Cache Backend">
       Simple Cache for HTTP.
@@ -15172,6 +15230,9 @@
     <message name="IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED" desc="Label text to indicate a removable storage device is not attached.">
       not attached
     </message>
+    <message name="IDS_MEDIA_GALLERIES_DIALOG_DELETE" desc="Text label of the menu item which removes selected media gallery access for all apps.">
+      Permanently remove access for all apps
+    </message>
 
     <!-- App List. -->
     <message name="IDS_APP_LIST_CONTACT_CHAT_TOOLTIP" desc="Tooltip text for the 'chat' icon displayed next to a contact search result.">
@@ -15476,6 +15537,17 @@
       More Apps
     </message>
 
+    <!-- WebStore search results -->
+    <message name="IDS_WEBSTORE_RESULT_INSTALL" desc="Text of button on WebStore search result for installing an extension/app.">
+      Add
+    </message>
+    <message name="IDS_WEBSTORE_RESULT_LAUNCH" desc="Text of button on WebStore search result for launching an ephemeral app.">
+      Launch
+    </message>
+    <message name="IDS_WEBSTORE_RESULT_LAUNCH_APP_TOOLTIP" desc="Tooltip of button on WebStore search result for launching an ephemeral app.">
+      Launch app
+    </message>
+
     <!-- Synced Notification display strings -->
     <message name="IDS_FIRST_SYNCED_NOTIFICATION_SERVICE_NAME" desc="The name of the first service source for synced notifications.">
       Google+
@@ -15635,6 +15707,7 @@
     <message name="IDS_LOCAL_DISCOVERY_NOTIFICATIONS_DISABLE_BUTTON_LABEL" desc="Label for button disabling local device notifications">
       Don't show this again
     </message>
+
     <!-- People search strings -->
     <message name="IDS_PEOPLE_SEARCH_ACTION_EMAIL_TOOLTIP" desc="Tooltip text for sending an email to the person in the result">
       Email this person
@@ -15648,6 +15721,17 @@
     <message name="IDS_LOCAL_DISCOVERY_REGISTER_TIMEOUT_ON_PRINTER" desc="Label for when registration has timed out on the printer side">
       Printer registration has timed out. In order to register a printer, you must confirm registration on the printer.
     </message>
+
+    <!--Tab media indicator tooltip strings-->
+    <message name="IDS_TOOLTIP_TAB_MEDIA_STATE_RECORDING" desc="Extra tool tip text, when the tab is recording media.">
+      This tab is using your camera or microphone.
+    </message>
+    <message name="IDS_TOOLTIP_TAB_MEDIA_STATE_CAPTURING" desc="Extra tool tip text, when the tab content is being captured.">
+      This tab's content is being shared.
+    </message>
+    <message name="IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_PLAYING" desc="Extra tool tip text, when the tab is playing audio.">
+      This tab is playing audio.
+    </message>
   </messages>
 
   <structures fallback_to_english="true">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 138215f..d8eda0b 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -420,6 +420,11 @@
           Do you want Google Chrome to save your password for this site?
         </message>
       </if>
+      <if expr="is_macosx">
+        <message name="IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT" desc="Text for the dialog box that prompts the user for their OS account password before revealing plaintext passwords on the password page.">
+          Google Chrome is trying to show passwords.
+        </message>
+      </if>
       <message name="IDS_CANT_WRITE_USER_DIRECTORY_EXIT_BUTTON" desc="Text on button of dialog that closes Chrome if we can't create a directory for this user.">
         Exit Chrome
       </message>
@@ -580,13 +585,8 @@
       </message>
 
       <message name="IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS"
-               desc="Message shown on the download shelf when the download is known to change browser settings.">
-        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> may change your Chrome settings.
-      </message>
-
-      <message name="IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS"
-               desc="Message shown on the download shelf when the download is known to change search engine settings in the browser.">
-        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> may change how your searches work in Chrome.
+               desc="Message shown on the download shelf when the download is known to change settings in the browser.">
+        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> makes settings changes similar to some malware, so Chrome has blocked it.
       </message>
 
       <message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_URL"
@@ -772,23 +772,6 @@
         <message name="IDS_SHORT_HELPER_NAME" desc="The helper application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Helper, not Google Chrome Helper.">
           Chrome Helper
         </message>
-
-        <!-- TODO(mark): All helper tasks are currently handled by the helper process.  The following strings exist in support of possibly changing things so that there's a distinct .app bundle for each of the various tasks.  This ensures that if and when a split is made, translated names will be available.  If the helper process is not split into multiple .app bundles, these strings can be removed. -->
-        <message name="IDS_RENDERER_APP_NAME" desc="The renderer application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Renderer.">
-          Google Chrome Renderer
-        </message>
-        <message name="IDS_PLUGIN_APP_NAME" desc="The plug-in host application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Plug-In Host.">
-          Google Chrome Plug-In Host
-        </message>
-        <message name="IDS_SHORT_PLUGIN_APP_NAME" desc="The plug-in host application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Plug-In Host, not Google Chrome Plug-In Host.">
-          Chrome Plug-In Host
-        </message>
-        <message name="IDS_WORKER_APP_NAME" desc="The worker application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Worker.">
-          Google Chrome Worker
-        </message>
-        <message name="IDS_UTILITY_APP_NAME" desc="The utility application's name.  Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Utility.">
-          Google Chrome Utility
-        </message>
       </if>
 
       <!-- One click sign in infobar -->
diff --git a/chrome/app/policy/PRESUBMIT.py b/chrome/app/policy/PRESUBMIT.py
index a9e84b1..91f24c4 100644
--- a/chrome/app/policy/PRESUBMIT.py
+++ b/chrome/app/policy/PRESUBMIT.py
@@ -7,6 +7,23 @@
 
 import itertools
 import sys
+import xml.dom.minidom
+
+def _GetPolicyTemplates(template_path):
+  # Read list of policies in the template. eval() is used instead of a JSON
+  # parser because policy_templates.json is not quite JSON, and uses some
+  # python features such as #-comments and '''strings'''. policy_templates.json
+  # is actually maintained as a python dictionary.
+  with open(template_path) as f:
+    template_data = eval(f.read(), {})
+  policies = ( policy
+               for policy in template_data['policy_definitions']
+               if policy['type'] != 'group' )
+  groups = ( policy['policies']
+             for policy in template_data['policy_definitions']
+             if policy['type'] == 'group' )
+  subpolicies = ( policy for group in groups for policy in group )
+  return list(itertools.chain(policies, subpolicies))
 
 def _CheckPolicyTemplatesSyntax(input_api, output_api):
   filepath = input_api.os_path.join(input_api.PresubmitLocalPath(),
@@ -27,40 +44,18 @@
   return []
 
 
-def _CheckPolicyTestCases(input_api, output_api):
-  os_path = input_api.os_path
-  local_path = input_api.PresubmitLocalPath()
-  template_path = os_path.join(local_path, 'policy_templates.json')
-  affected_files = input_api.AffectedFiles()
-  if not any(f.AbsoluteLocalPath() == template_path for f in affected_files):
-    return []
-
-  # Read list of policies in the template. eval() is used instead of a JSON
-  # parser because policy_templates.json is not quite JSON, and uses some
-  # python features such as #-comments and '''strings'''. policy_templates.json
-  # is actually maintained as a python dictionary.
-  with open(template_path) as f:
-    template_data = eval(f.read(), {})
-  policies = ( policy['name']
-               for policy in template_data['policy_definitions']
-               if policy['type'] != 'group' )
-  groups = ( policy['policies']
-             for policy in template_data['policy_definitions']
-             if policy['type'] == 'group' )
-  subpolicies = ( policy['name'] for group in groups for policy in group )
-  template_policies = frozenset(itertools.chain(policies, subpolicies))
-
+def _CheckPolicyTestCases(input_api, output_api, policies):
   # Read list of policies in chrome/test/data/policy/policy_test_cases.json.
   root = input_api.change.RepositoryRoot()
-  policy_test_cases_file = os_path.join(
+  policy_test_cases_file = input_api.os_path.join(
       root, 'chrome', 'test', 'data', 'policy', 'policy_test_cases.json')
   test_names = input_api.json.load(open(policy_test_cases_file)).keys()
-  tested_policies = frozenset(
-      [name for name in test_names if name[:2] != '--'])
+  tested_policies = frozenset(name for name in test_names if name[:2] != '--')
+  policy_names = frozenset(policy['name'] for policy in policies)
 
   # Finally check if any policies are missing.
-  missing = template_policies - tested_policies
-  extra = tested_policies - template_policies
+  missing = policy_names - tested_policies
+  extra = tested_policies - policy_names
   error_missing = ('Policy \'%s\' was added to policy_templates.json but not '
                    'to src/chrome/test/data/policy/policy_test_cases.json. '
                    'Please update both files.')
@@ -75,10 +70,43 @@
   return results
 
 
+def _CheckPolicyHistograms(input_api, output_api, policies):
+  root = input_api.change.RepositoryRoot()
+  histograms = input_api.os_path.join(
+      root, 'tools', 'metrics', 'histograms', 'histograms.xml')
+  with open(histograms) as f:
+    tree = xml.dom.minidom.parseString(f.read())
+  enums = (tree.getElementsByTagName('histogram-configuration')[0]
+               .getElementsByTagName('enums')[0]
+               .getElementsByTagName('enum'))
+  policy_enum = [e for e in enums
+                 if e.getAttribute('name') == 'EnterprisePolicies'][0]
+  policy_ids = frozenset([int(e.getAttribute('value'))
+                          for e in policy_enum.getElementsByTagName('int')])
+
+  error_missing = ('Policy \'%s\' was added to policy_templates.json but not '
+                   'to src/tools/metrics/histograms/histograms.xml. '
+                   'Please update both files.')
+  results = []
+  for policy in policies:
+    if policy['id'] not in policy_ids:
+      results.append(output_api.PresubmitError(error_missing % policy['name']))
+  return results
+
+
 def _CommonChecks(input_api, output_api):
   results = []
   results.extend(_CheckPolicyTemplatesSyntax(input_api, output_api))
-  results.extend(_CheckPolicyTestCases(input_api, output_api))
+
+  os_path = input_api.os_path
+  local_path = input_api.PresubmitLocalPath()
+  template_path = os_path.join(local_path, 'policy_templates.json')
+  affected_files = input_api.AffectedFiles()
+  if any(f.AbsoluteLocalPath() == template_path for f in affected_files):
+    policies = _GetPolicyTemplates(template_path)
+    results.extend(_CheckPolicyTestCases(input_api, output_api, policies))
+    results.extend(_CheckPolicyHistograms(input_api, output_api, policies))
+
   return results
 
 
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 0579811..9973463 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -118,7 +118,7 @@
 #   persistent IDs for all fields (but not for groups!) are needed. These are
 #   specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
 #   because doing so would break the deployed wire format!
-#   For your editing convenience: highest ID currently used: 245
+#   For your editing convenience: highest ID currently used: 248
 #
 # Placeholders:
 #   The following placeholder strings are automatically substituted:
@@ -3374,6 +3374,44 @@
       If the policy is set to disabled or left not set signing in leads to regular profiles.'''
     },
     {
+      'name': 'AutoCleanUpStrategy',
+      'type': 'string-enum',
+      'schema': {
+        'type': 'string',
+        'enum': [
+          'remove-lru',
+        ],
+      },
+      'items': [
+        {
+          'name': 'RemoveLRU',
+          'value': 'remove-lru',
+          'caption': '''Least recently used users are removed until there is enough free space''',
+        },
+        {
+          'name': 'RemoveLRUIfDormant',
+          'value': 'remove-lru-if-dormant',
+          'caption': '''Least recently used users who have not logged in within last 3 months are removed until there is enough free space''',
+        },
+      ],
+      'supported_on': ['chrome_os:32-'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'example_value': 'remove-lru',
+      'id': 246,
+      'caption': '''Selects the strategy used to free up disk space during automatic clean-up''',
+      'desc': '''Controls the automatic clean-up behavior on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> devices. Automatic clean-up is triggered when the amount of free disk space reaches a critical level to recover some disk space.
+
+      If this policy is set to 'RemoveLRU', the automatic clean-up will keep removing users from the device in least-recently-logged-in order until there is enough free space.
+
+      If this policy is set to 'RemoveLRUIfDormant', the automatic clean-up will keep removing users who have not logged in for at least 3 months in least-recently-logged-in order until there is enough free space.
+
+      If this policy is not set, automatic clean-up uses the default built-in strategy. Currently, it is the 'RemoveLRUIfDormant' strategy.'''
+    },
+    {
       'name': 'ReportDeviceVersionInfo',
       'type': 'main',
       'schema': { 'type': 'boolean' },
@@ -3455,6 +3493,22 @@
       If the policy is not set, or set to false, the interface list will not be reported.''',
     },
     {
+      'name': 'ReportDeviceUsers',
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:32-'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+      },
+      'example_value': False,
+      'id': 248,
+      'caption': '''Report device users''',
+      'desc': '''Report list of device users that have recently logged in.
+
+      If the policy is not set, or set to false, the users will not be reported.''',
+    },
+    {
       'name': 'DeviceUserWhitelist',
       'type': 'list',
       'schema': {
@@ -4881,6 +4935,24 @@
 
           The scale factor must be 100% or more.''',
         },
+        {
+          'name': 'WaitForInitialUserActivity',
+          'type': 'main',
+          'schema': { 'type': 'boolean' },
+          'supported_on': ['chrome_os:32-'],
+          'features': {
+            'dynamic_refresh': True,
+            'per_profile': False,
+          },
+          'example_value': True,
+          'id': 247,
+          'caption': '''Specify whether power management delays and the session length limit should only start running after initial user activity in a session''',
+          'desc': '''Specifies whether power management delays and the session length limit should only start running after the first user activity has been observed in a session.
+
+          If this policy is set to True, power management delays and the session length limit do not start running until after the first user activity has been observed in a session.
+
+          If this policy is set to False or left unset, power management delays and the session length limit start running immediately on session start.''',
+        },
       ],
     },
     {
diff --git a/chrome/app/policy/policy_templates_ar.xtb b/chrome/app/policy/policy_templates_ar.xtb
index 6c91435..5abb46d 100644
--- a/chrome/app/policy/policy_templates_ar.xtb
+++ b/chrome/app/policy/policy_templates_ar.xtb
@@ -233,7 +233,7 @@
 <translation id="4668325077104657568">إعدادات الصور الافتراضية</translation>
 <translation id="4492287494009043413">تعطيل التقاط لقطات الشاشة</translation>
 <translation id="6368403635025849609">السماح بتشغيل جافا سكريبت في هذه المواقع</translation>
-<translation id="6074963268421707432">عدم السماح لأي موقع بعرض تنبيهات سطح المكتب</translation>
+<translation id="6074963268421707432">عدم السماح لأي موقع بعرض اشعارات سطح المكتب</translation>
 <translation id="8614804915612153606">تعطيل التحديث التلقائي</translation>
 <translation id="382476126209906314">‏تهيئة بادئة TalkGadget لعمليات استضافة الدخول عن بُعد</translation>
 <translation id="6561396069801924653">إظهار خيارات إمكانية الدخول في قائمة حاوية النظام</translation>
@@ -453,7 +453,7 @@
           إذا تم تعطيل هذا الإعداد أو لم يتم تعيينه، فإن عمليات الاستضافة يمكن مشاركتها باستخدام أي حساب.</translation>
 <translation id="6417861582779909667">‏للسماح لك بتعيين قائمة أنماط عناوين URL التي تحدد المواقع التي لا يُسمح لها بتعيين ملفات تعريف الارتباط. إذا تم ترك هذه السياسة بدون تعيين، فسيتم استخدام القيمة الافتراضية العامة لجميع المواقع إما من السياسة 'DefaultCookiesSetting' إذا تم تعيينها أو من التهيئة الشخصية للمستخدم.</translation>
 <translation id="5457296720557564923">السماح للصفحات بالدخول إلى إحصاءات استخدام ذاكرة جافا سكريبت. يجعل هذا الإعداد إحصاءات الذاكرة من لوحة الملفات الشخصية لأدوات مطوّري البرامج متاحة لصفحة الويب نفسها.</translation>
-<translation id="5776485039795852974">السؤال في كل مرة يريد فيها أحد المواقع عرض  تنبيهات سطح المكتب</translation>
+<translation id="5776485039795852974">السؤال في كل مرة يريد فيها أحد المواقع عرض  اشعارات سطح المكتب</translation>
 <translation id="5052081091120171147">تفرض هذه السياسة استيراد سجل التصفح من المتصفح الافتراضي الحالي إذا تم تمكينها. وفي حالة تمكينها، فإن هذه السياسة تؤثر أيضًا على مربع الحوار &quot;استيراد&quot;. وإذا تم تعطيلها، فلا يتم استيراد سجل التصفح. إذا لم يتم تعيينها، فقد يتم سؤال المستخدم بشأن الاستيراد أو إجراء الاستيراد تلقائيًا.</translation>
 <translation id="6786747875388722282">الإضافات</translation>
 <translation id="8947415621777543415">الإبلاغ عن موقع الجهاز</translation>
@@ -844,7 +844,7 @@
 <translation id="402759845255257575">عدم السماح لأي موقع بتشغيل جافا سكريبت</translation>
 <translation id="5457924070961220141">‏للسماح لك بتهيئة عارض HTML الافتراضي عندما يتم تثبيت <ph name="PRODUCT_FRAME_NAME"/>.
           الإعداد الافتراضي المستخدم عندما يتم ترك هذه السياسة بدون تعيينها هو السماح للمتصفح المضيف بالعرض، ولكن يمكنك اختياريًا تجاوز ذلك وعرض صفحات HTML افتراضيًا في <ph name="PRODUCT_FRAME_NAME"/>.</translation>
-<translation id="706669471845501145">السماح للمواقع بعرض تنبيهات سطح المكتب</translation>
+<translation id="706669471845501145">السماح للمواقع بعرض اشعارات سطح المكتب</translation>
 <translation id="7529144158022474049">تحديث عامل التشتيت تلقائيًا</translation>
 <translation id="2188979373208322108">لتمكين شريط الإشارات المرجعية في <ph name="PRODUCT_NAME"/>. إذا تم تمكين هذا الإعداد، فسيعرض <ph name="PRODUCT_NAME"/> شريط الإشارات المرجعية. إذا تم تعطيل هذا الإعداد، فلن يتمكن المستخدمون من رؤية شريط الإشارات المرجعية مطلقًا. إذا تم تمكين هذا الإعداد أو تعطيله، فلن يتمكن المستخدمون من تجاوزه في <ph name="PRODUCT_NAME"/>. إذا تم ترك هذا الإعداد بدون تعيين، يمكن أن يقرر المستخدم استخدام هذه الوظيفة أو عدم استخدامها.</translation>
 <translation id="5475361623548884387">تمكين الطباعة</translation>
@@ -887,7 +887,7 @@
 
       وإذا عطّلت هذا الإعداد، فلن يتحقق <ph name="PRODUCT_NAME"/> مطلقًا مما إذا كان هو المتصفح الافتراضي وسيتم تعطيل عناصر تحكم المستخدم في تعيين هذا الخيار.
 
-      وإذا لم يتم تعيين هذا الإعداد، فسيسمح <ph name="PRODUCT_NAME"/> للمستخدم بالتحكم في كونه المتصفح الافتراضي وفي عرض تنبيهات المستخدم عند عدم عرضها.</translation>
+      وإذا لم يتم تعيين هذا الإعداد، فسيسمح <ph name="PRODUCT_NAME"/> للمستخدم بالتحكم في كونه المتصفح الافتراضي وفي عرض اشعارات المستخدم عند عدم عرضها.</translation>
 <translation id="3504791027627803580">‏لتحديد عنوان URL لمحرك البحث المستخدم لتوفير إمكانية البحث عن الصور. سيتم إرسال طلبات البحث باستخدام طريقة GET. وعند تعيين سياسة DefaultSearchProviderImageURLPostParams فستستخدم طلبات البحث عن الصور طريقة المشاركة بدلاً من ذلك.
 
           تعد هذه السياسة سياسة اختيارية. وعند تعيينها، لن يتم استخدام أي بحث صور.
diff --git a/chrome/app/policy/policy_templates_bn.xtb b/chrome/app/policy/policy_templates_bn.xtb
index e91eb64..c56579c 100644
--- a/chrome/app/policy/policy_templates_bn.xtb
+++ b/chrome/app/policy/policy_templates_bn.xtb
@@ -1012,7 +1012,7 @@
 
           যদি আপনি এই নীতিটি সেট না করে ছেড়ে রাখেন তাহলে ইন্ট্রানেটে কোনো সার্ভার রয়েছে কিনা Chrome তা সনাক্ত করার চেষ্টা করবে এবং শুধুমাত্র তখনই এটি IWA অনুরোধগুলির উপর প্রতিক্রিয়া করবে৷ যদি একটি সার্ভার ইন্টারনেট হিসাবে সনাক্ত হয় তখন এর থেকে IWA অনুরোধগুলি Chrome এর দ্বারা উপেক্ষিত হবে৷</translation>
 <translation id="3653237928288822292">ডিফল্ট অনুসন্ধান সরবরাহকারী আইকন</translation>
-<translation id="2872961005593481000">শাট ডাউন</translation>
+<translation id="2872961005593481000">বন্ধ করুন</translation>
 <translation id="4445684791305970001">বিকাশকারী সরঞ্জাম ও JavaScript কনসোলকে অক্ষম করে৷ 
 
 আপনি এই সেটিং সক্ষম করলে, বিকাশকারী সরঞ্জামে অ্যাক্সেস করা যাবে না এবং ওয়েব-সাইট উপাদানে আর পরিদর্শন করা যাবে না৷ বিকাশকারী সরঞ্জাম বা JavaScript কনসোল খোলার জন্য যেকোন কীবোর্ড শর্টকাট ও যেকোন মেনু বা প্রসঙ্গ মেনু প্রবেশকার্য অক্ষম হবে৷
@@ -1092,7 +1092,7 @@
 <translation id="1859633270756049523">অধিবেশন সময় দ্বারা সীমাবদ্ধ করুন</translation>
 <translation id="7433714841194914373">ঝটপট সক্ষম করুন</translation>
 <translation id="4983201894483989687">চলমান পুরানো প্ল্যাগইনগুলিকে মঞ্জুর করুন</translation>
-<translation id="443665821428652897">ব্রাউজার শাটডাউনে ডেটা সাফ করুন (অসমর্থিত)</translation>
+<translation id="443665821428652897">ব্রাউজার বন্ধ করার ডেটা সাফ করুন (অসমর্থিত)</translation>
 <translation id="3823029528410252878"><ph name="PRODUCT_NAME"/>তে ব্রাউজারের ইতিহাস সংরক্ষণ অক্ষম করে এবং ব্যবহারকারীদের এই সেটিং পরিবর্তন করতে বাধা দেয়৷ যদি এই সেটিংটি সক্ষম থেকে থাকে তবে ব্রাউজিংয়ের ইতিহাস সংরক্ষিত হয় না৷ যদি এই সেটিংটি অক্ষম থাকে বা কনফিগার করা না থাকে তবে ব্রাউজিংয়ের ইতিহাস সংরক্ষিত হয়৷</translation>
 <translation id="2759224876420453487">একটি মাল্টিপ্রোফাইল সেশন ব্যবহারকারী আচরণ নিয়ন্ত্রণ করুন</translation>
 <translation id="3844092002200215574">ডিস্কে ক্যাশেযুক্ত ফাইলগুলিকে সংরক্ষণের জন্য <ph name="PRODUCT_NAME"/> যে ডিরেক্টরিকে ব্যবহার করবে সেটিকে কনফিগার করে৷
@@ -1287,7 +1287,7 @@
 
       লগ ইন স্ক্রীন দেখানোর সময় যখন কিছু সময়ের জন্য যখন কোনো ব্যবহারকারী কার্যকলাপ হয় না তখন <ph name="PRODUCT_OS_NAME"/> কেমন আচরণ করবে তা এই নীতিটি আপনাকে কনফিগার করতে দেয়৷ তাদের নিজস্ব শব্দ এবং মান ব্যাপ্তির জন্য, সংশ্লিষ্ট নীতিগুলি দেখুন যেগুলি একটি সেশনের মধ্যে শক্তি পরিচালনা নিয়ন্ত্রণ করে৷ এই নীতিগুলির একমাত্র বিচ্যুতিগুলি হল:
       * নিষ্ক্রিয় বা লিড বন্ধের উপর পদক্ষেপগুলি নিলে তা সেশন বন্ধ করবে না৷
-      * AC শক্তিতে চলার সময় নিষ্ক্রিয়তার জন্য নেওয়া ডিফল্ট পদক্ষেপ হল শাট ডাউন৷
+      * AC শক্তিতে চলার সময় নিষ্ক্রিয়তার জন্য নেওয়া ডিফল্ট পদক্ষেপ হল বন্ধ হওয়া৷
 
       নীতিটি একটি স্ট্রিং হিসেবে নির্দিষ্ট করা উচিত যা JSON ফর্ম্যাটে পৃথক সেটিংস প্রকাশ করে, নিম্নলিখিত স্কিমার সঙ্গে মানানসই করতে:
       {
diff --git a/chrome/app/policy/policy_templates_da.xtb b/chrome/app/policy/policy_templates_da.xtb
index 701c62d..f8ed873 100644
--- a/chrome/app/policy/policy_templates_da.xtb
+++ b/chrome/app/policy/policy_templates_da.xtb
@@ -70,11 +70,11 @@
 <translation id="3816312845600780067">Aktivér nødtastaturgenvej til automatisk login</translation>
 <translation id="3214164532079860003">Denne politik tvinger import af startsiden fra den aktuelle standardbrowser, hvis den er aktiveret. Hvis den er deaktiveret, importeres startsiden ikke. Hvis den ikke er angivet, kan brugeren blive spurgt, om den skal importeres, eller også sker det automatisk.</translation>
 <translation id="5330684698007383292">Tillad, at <ph name="PRODUCT_FRAME_NAME"/> håndterer følgende indholdstyper</translation>
-<translation id="6647965994887675196">Hvis dette er angivet som sandt, kan overvågede brugere oprettes og anvendes.
+<translation id="6647965994887675196">Hvis dette er angivet som sandt, kan administrerede brugere oprettes og anvendes.
 
-          Hvis dette er angivet som falsk eller ikke er konfigureret, vil oprettelse af overvågede brugere og login for sådanne brugere være deaktiveret. Alle eksisterende overvågede brugere vil blive skjult.
+          Hvis dette er angivet som falsk eller ikke er konfigureret, vil oprettelse af administrerede brugere og login for sådanne brugere være deaktiveret. Alle eksisterende administrerede brugere vil blive skjult.
 
-          BEMÆRK! Forbruger- og virksomhedsenheder opfører sig som standard forskelligt. På forbrugerenheder er overvågede brugere som standard aktiveret, men på virksomhedsenheder er de som standard deaktiveret.</translation>
+          BEMÆRK! Forbruger- og virksomhedsenheder opfører sig som standard forskelligt. På forbrugerenheder er administrerede brugere som standard aktiveret, men på virksomhedsenheder er de som standard deaktiveret.</translation>
 <translation id="69525503251220566">Parameter, der leverer funktion til billedsøgning i standardsøgemaskinen</translation>
 <translation id="5469825884154817306">Bloker billeder på disse websites</translation>
 <translation id="8412312801707973447">Om der udføres online kontrol af OCSP/CRL</translation>
@@ -768,7 +768,7 @@
 
           Hvis denne politik ikke indstilles, deaktiveres den store markør, men brugeren kan når som helst slå funktionen til.</translation>
 <translation id="2633084400146331575">Aktivér talefeedback</translation>
-<translation id="7712008868843631413">Aktivér overvågede brugere.</translation>
+<translation id="7712008868843631413">Aktivér administrerede brugere.</translation>
 <translation id="8731693562790917685">Indstillinger for indhold giver dig mulighed for at angive, hvordan en bestemt type indhold (for eksempel cookies, billeder eller JavaScript) skal behandles.</translation>
 <translation id="2411919772666155530">Bloker meddelelser på disse websites</translation>
 <translation id="6923366716660828830">Angiver navnet på standardsøgemaskinen. Hvis det ikke udfyldes eller angives, vil det værtsnavn, der er angivet af søgewebadressen, blive anvendt. Denne politik overvejes kun, hvis politikken &quot;DefaultSearchProviderEnabled&quot; er aktiveret.</translation>
@@ -1014,7 +1014,7 @@
 
           Hvis denne politik ikke indstilles, deaktiveres høj kontrast, når loginskærmen vises første gang. Brugerne kan når som helst aktivere eller deaktivere Høj kontrast, og dens status på loginskærmen fastholdes hos brugerne.</translation>
 <translation id="8580857153747395000">Vis en advarsel, når du er på websites uden for indholdspakkerne.</translation>
-<translation id="350796261613621561">Aktivér oprettelse af overvågede brugere.</translation>
+<translation id="350796261613621561">Aktivér oprettelse af administrerede brugere.</translation>
 <translation id="602728333950205286">Direkte webadresse til standardsøgemaskinen</translation>
 <translation id="3030000825273123558">Aktivér datarapportering</translation>
 <translation id="8465065632133292531">Parametre for direkte webadresse, som bruger POST</translation>
@@ -1045,9 +1045,9 @@
 <translation id="8864975621965365890">Undertrykker opfordringen til afvisning, som vises, når et website gengives af <ph name="PRODUCT_FRAME_NAME"/>.</translation>
 <translation id="3264793472749429012">Kodninger for standardsøgemaskinen</translation>
 <translation id="285480231336205327">Aktivér høj kontrast</translation>
-<translation id="5366977351895725771">Hvis dette er angivet som falsk, vil oprettelse af overvågede brugere være deaktiveret for denne bruger. Alle eksisterende overvågede brugere vil stadig være tilgængelige.
+<translation id="5366977351895725771">Hvis dette er angivet som falsk, vil oprettelse af administrerede brugere være deaktiveret for denne bruger. Alle eksisterende administrerede brugere vil stadig være tilgængelige.
 
-          Hvis dette er angivet som sandt eller ikke er konfigureret, kan overvågede brugere oprettes og administreres af denne bruger.</translation>
+          Hvis dette er angivet som sandt eller ikke er konfigureret, kan administrerede brugere oprettes og administreres af denne bruger.</translation>
 <translation id="8101760444435022591">Set i lyset af det faktum, at soft-fail online tilbagekaldelsesundersøgelser ikke har nogen effektive sikkerhedsfordele, deaktiveres de som standard i <ph name="PRODUCT_NAME"/> version 19 eller nyere. Hvis du indstiller denne politik til sand, gendannes den forrige adfærd, og der udføres online OCSP/CRL-undersøgelser. 
 
       Hvis politikken ikke angives eller indstilles til falsk, udfører Chrome ikke online tilbagekaldelsesundersøgelser i Chrome 19 eller nyere.</translation>
diff --git a/chrome/app/policy/policy_templates_ml.xtb b/chrome/app/policy/policy_templates_ml.xtb
index 601ed99..17d0b1e 100644
--- a/chrome/app/policy/policy_templates_ml.xtb
+++ b/chrome/app/policy/policy_templates_ml.xtb
@@ -328,7 +328,7 @@
 
       ഈ നയം സജ്ജമാക്കിയിട്ടില്ലെങ്കിൽ, കാലഹരണപ്പെടുന്നതിനുള്ള സമയം 0 മില്ലിസെക്കൻഡ് ആയിരിക്കും.
 
-      ഈ നയം മില്ലിസെക്കൻഡിലാണ് വ്യക്തമാക്കുന്നത്.</translation>
+      ഈ നയം മില്ലിസെക്കൻഡിലാണ് പറയുന്നത്.</translation>
 <translation id="7275334191706090484">നിയന്ത്രിത ബുക്ക്‌മാർക്കുകൾ</translation>
 <translation id="3570008976476035109">ഈ സൈറ്റുകളില്‍ പ്ലഗിനുകള്‍ തടയുക</translation>
 <translation id="8749370016497832113"><ph name="PRODUCT_NAME"/>-ലെ ബ്രൗസിംഗ് ചരിത്രവും ഡൗൺലോഡ് ചരിത്രവും ഇല്ലാതാക്കുന്നത് പ്രവർത്തനക്ഷമമാക്കുകയും ഈ ക്രമീകരണങ്ങൾ മാറ്റുന്നതിൽ നിന്ന് ഉപയോക്താക്കളെ തടയുകയും ചെയ്യുന്നു.
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index fee8c66..2470005 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">እረማ ሆሄ እና ሰዋስው አሳይ</translation>
 <translation id="7017587484910029005">ከታች በስዕሉ ላይ የሚያዩዋቸውን ቁምፊዎች ይተይቡ።</translation>
 <translation id="9013589315497579992">ጥሩ ያልሆነ SSL የተገልጋይ ማረጋገጫ ሰርቲፊኬት።</translation>
+<translation id="2085245445866855859">የ«kiosk_only» አንጸባራቂ አይነታ ያለው መተግበሪያ በChromeOS ኪዮስክ ሁነታ ላይ መጫን አለበት።</translation>
 <translation id="1467999917853307373"><ph name="URL"/> ውሂብ እስከ መጨረሻው በእርስዎ መሣሪያ ላይ ሊያከማች ይፈልጋል።</translation>
 <translation id="8524066305376229396">የቋሚነት ማከማቻ፦</translation>
 <translation id="7567293639574541773">አባል መ&amp;ርምር</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">የአገልጋይ እውቅና ማረጋገጫ ከሰረዙ የዚያ አገልጋይ መደበኛው የደህንነት ማረጋገጫዎችን ይመልሱና የሚሰራ የእውቅና ማረጋገጫ እንዲጠቀሙ ይፈልጉበታል።</translation>
 <translation id="9110235431257073974">የድር ማከማቻ እና Files.app ውህደትን ያንቁ።</translation>
+<translation id="6489433341782457580">ለገንቢዎች፦ ለrequestAutocomplete() Wallet ኤ ፒ አይ ጥሪዎች የማጠሪያ አገልግሎቱን ተጠቀሙ።</translation>
 <translation id="8186609076106987817">አገልጋዩ ፋይሉን ሊያገኝ አልቻለም።</translation>
 <translation id="2846816712032308263">ፈጣን የትር/መስኮት መዝጋትን አንቃ - የትሩን onunload js መቆጣጠሪያ ከGUI በተናጠል ያስኬዳል።</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">ክትትል የሚደረግበት ተጠቃሚ በመለያ ለመግባት ይህን የይለፍ ቃል መጠቀም ይኖርበታል፣ ስለዚህ የይለፍ ቃል በጥንቃቄ ይምረጡና ክትትል ከሚደረግበት ተጠቃሚ ጋር መነጋገርዎን ያስታውሱ።</translation>
 <translation id="5154917547274118687">ማህደረ ትውስታ</translation>
 <translation id="1493492096534259649">ይህ ቋንቋ ለፊደል ማረም መጠቀም አይቻልም</translation>
+<translation id="2103866351350079276">ቅጥያ የሌለው የMediaSource ነገር ያሰናክሉ። ይህ ነገር ጃቫስክሪፕት የሚዲያ ውሂብ በቀጥታ ለአንድ የቪዲዮ አባል እንዲልክ ያስችለዋል።</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> ፍለጋ</translation>
 <translation id="6460423884798879930">በመጀመሪያው የSYN ጥቅል ውስጥ ከዚህ ቀደም ለተገናኘ ደንበኛ ትርፍ የማረጋገጫ መረጃ የመላክ አማራጩን ያንቁ፣ ይህም የበለጠ ፈጣን የውሂብ መላክ መጀመር ያስችላል።</translation>
 <translation id="6563261555270336410">ስለ<ph name="ELEMENTS_HOST_NAME"/> ዝርዝሮች</translation>
@@ -1609,6 +1612,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">ቪትናምኛ</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> የተጠየቁ እርምጃዎችን የሚፈጽምበት የፍጥነት ልኬቶች</translation>
+<translation id="2048118585307365263">MediaDrmን ያንቁ።</translation>
 <translation id="4091434297613116013">የወረቀት ሉኮች</translation>
 <translation id="7475671414023905704">የNetscape የጠፋ የይለፍ ቃል URL</translation>
 <translation id="3335947283844343239">የተዘጋውን ትር ዳግም ክፈት</translation>
@@ -2765,7 +2769,7 @@
 <translation id="1653828314016431939">እሺ - አሁን ዳግም አስጀምር</translation>
 <translation id="7364796246159120393">ፋይል ምረጥ</translation>
 <translation id="6585283250473596934">ወደ ይፋዊ ክፍለ ጊዜ በመግባት ላይ።</translation>
-<translation id="7870278953869613713">ውይይት ይጀምሩ</translation>
+<translation id="7870278953869613713">Hangout ይጀምሩ</translation>
 <translation id="8915370057835397490">የጥቆማ አስተያየት በመጫን ላይ</translation>
 <translation id="1511623662787566703">እንደ <ph name="USER_EMAIL_ADDRESS"/> ሆነው ገብተዋል። ማመሳሰል በGoogle ዳሽቦርዱ በኩል እንዲቆም ተደርጓል።</translation>
 <translation id="4352333825734680558">ውይ! አዲሱ ክትትል የሚደረግበት ተጠቃሚ ለፈጠር አልቻለም። እባክዎ የአውታረ መረብዎን ግንኙነት ይፈትሹና ቆይተው እንደገና ይሞክሩ።</translation>
@@ -3883,6 +3887,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> ትልቅ ውሂብ በአካባቢያዊ ኮምፒውተርዎ ላይ እስከመጨረሻው ሊያከማች ይፈልጋል።</translation>
 <translation id="373572798843615002">1 ትር</translation>
 <translation id="4806065163318322702">የንግግር ግቤት ይቀያይሩ</translation>
+<translation id="6190185222845843088">የWallet ማጠሪያ አገልጋዮችን ይጠቀሙ</translation>
 <translation id="3177048931975664371">የይለፍ ቃልን ለመደበቅ ጠቅ ያድርጉ</translation>
 <translation id="5852137567692933493">ዳግም አስጀምር እና ፓወርዋሽ አድርግ</translation>
 <translation id="3092544800441494315">ይህን ቅጽበታዊ ገጽ እይታን ያካትቱ፦</translation>
@@ -4152,6 +4157,7 @@
 <translation id="1639239467298939599">በመጫን ላይ</translation>
 <translation id="5457599981699367932">እንደ እንግዳ ያስሱ</translation>
 <translation id="6850233365366645553">መሣሪያዎ በPowerwash ዳግም መጀመር ከመቻሉ በፊት እንደገና ማስጀመር ያስፈልጋል። Powerwash የእርስዎን <ph name="IDS_SHORT_PRODUCT_NAME"/> መሣሪያ ልክ እንደ አዲስ ዳግም ያስጀምረዋል።</translation>
+<translation id="4292622557427736684">MediaDrm በነባሪነት ለተመሰጠሩ የሚዲያ ቅጥያዎች ያንቁ።</translation>
 <translation id="1812514023095547458">ቀለም ይምረጡ</translation>
 <translation id="5089363139417863686">በፋይሎች መተግበሪያው ይመልከቱ</translation>
 <translation id="7047998246166230966">ጠቋሚ</translation>
@@ -4503,6 +4509,7 @@
 <translation id="1728442818359004787">ነባሪ መተግበሪያ ቀይር...</translation>
 <translation id="7540972813190816353">ዝማኔዎችን በመፈለግ ላይ ሳለ ስህተት ተከስቷል፦ <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">የማይደገፍ የብሉቱዝ መሣሪያ፦ «<ph name="DEVICE_NAME"/>»።</translation>
+<translation id="2990212470195050777">ቅጥያ የሌለው የሚዲያ ምንጭ ኤ ፒ አይ ያሰናክሉ።</translation>
 <translation id="2225024820658613551">መቀጠል የለብዎትም፣ &lt;strong&gt;በተለይ&lt;/strong&gt; ከዚህ በፊት ለዚህ ጣቢያ ማስጠንቀቂያ አይተው የማያውቁ ከሆኑ።</translation>
 <translation id="2049639323467105390">ይህ መሣሪያ በ<ph name="DOMAIN"/> ነው የሚቀናበረው።</translation>
 <translation id="1932098463447129402">በፊት ያልሆነ</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index 408ec6b..8174344 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">إظهار التدقيق الإملائي والتدقيق النحوي</translation>
 <translation id="7017587484910029005">اكتب الأحرف التي تراها في الصورة بالأسفل.</translation>
 <translation id="9013589315497579992">‏شهادة تالفة لمصادقة عميل SSL (طبقة المقابس الآمنة).</translation>
+<translation id="2085245445866855859">‏يجب أن يتم تثبيت التطبيق الذي يتضمن سمة البيان &quot;kiosk_only&quot; في وضع الكشك على نظام تشغيل Chrome.</translation>
 <translation id="1467999917853307373">يريد <ph name="URL"/> تخزين البيانات بشكل دائم على جهازك.</translation>
 <translation id="8524066305376229396">التخزين الثابت:</translation>
 <translation id="7567293639574541773">فح&amp;ص العنصر</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">فريتز</translation>
 <translation id="2231238007119540260">في حالة حذف شهادة الخادم، تتم استعادة العمليات المعتادة للتحقق من الأمان لذلك الخادم وسيتطلب الأمر استخدامه لشهادة صالحة.</translation>
 <translation id="9110235431257073974">‏تمكين دمج Webstore وتطبيق الملفات.</translation>
+<translation id="6489433341782457580">‏بالنسبة إلى مطوِّري البرامج: يمكن استخدام خدمة وضع الحماية مع مكالمات واجهة برمجة تطبيقات المحفظة لـ requestAutocomplete().</translation>
 <translation id="8186609076106987817">تعذر على الخادم العثور على الملف.</translation>
 <translation id="2846816712032308263">‏لتمكين الغلق السريع لعلامة التبويب/النافذة - لتشغيل معالج onunload js في علامة التبويب بشكل مستقل عن واجهة المستخدم الرسومية.</translation>
 <translation id="9134410174832249455">تعذر على <ph name="PRODUCT_NAME"/> تحميل صفحة الويب نظرًا لاستغراق <ph name="HOST_NAME"/> وقتًا أطول مما يجب للاستجابة. قد يكون موقع الويب معطلاً، أو ربما تواجهك مشكلات تتعلق باتصالك بالإنترنت.</translation>
@@ -354,6 +356,7 @@
 <translation id="8959810181433034287">سيحتاج المستخدم الذي يخضع للإشراف إلى استخدام كلمة المرور هذه لتسجيل الدخول، لذا يُرجى اختيار كلمة مرور آمنة ولا تنس طرح الأمر للنقاش مع المستخدم الخاضع للإشراف.</translation>
 <translation id="5154917547274118687">الذاكرة</translation>
 <translation id="1493492096534259649">لا يمكن استخدام هذه اللغة للتدقيق الإملائي</translation>
+<translation id="2103866351350079276">‏تعطيل عنصر MediaSource غير المسبوق ببادئة. ويتيح هذا العنصر لجافا سكريبت إرسال بيانات الوسائط إلى عنصر فيديو مباشرة.</translation>
 <translation id="6628463337424475685">بحث <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">‏يمكنك تمكين هذا الخيار لإرسال معلومات مصادقة إضافية في حزمة SYN الأولية لعميل متصل سابقًا، مما يتيح بدء أسرع لإرسال البيانات.</translation>
 <translation id="6563261555270336410">تفاصيل حول <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -657,7 +660,7 @@
 <translation id="6431347207794742960">سيعمل <ph name="PRODUCT_NAME"/> على إعداد التحديثات التلقائية لجميع مستخدمي هذا الكمبيوتر.</translation>
 <translation id="4973698491777102067">مسح العناصر التالية من:</translation>
 <translation id="9021662811137657072">تم اكتشاف فيروس</translation>
-<translation id="6074963268421707432">عدم السماح لأي موقع بعرض تنبيهات سطح المكتب</translation>
+<translation id="6074963268421707432">عدم السماح لأي موقع بعرض اشعارات سطح المكتب</translation>
 <translation id="3016857782996729000"><ph name="BEGIN_BOLD"/>لا تزل جهازك الآن.<ph name="END_BOLD"/>
        <ph name="LINE_BREAKS"/>
        قد تؤدي إزالة جهازك أثناء وجوده قيد الاستخدام إلى فقدان البيانات. الرجاء الانتظار حتى انتهاء العملية، ثم إخراج الجهاز باستخدام تطبيق الملفات.</translation>
@@ -677,7 +680,7 @@
 <translation id="6351933643423632811">‏تمكين إتاحة إشعارات مساعد Google الفوري.</translation>
 <translation id="4255096080864111471">حدد الحد الأقصى لعدد الأجزاء لمنطقة الاهتمامات.</translation>
 <translation id="5136529877787728692">F7</translation>
-<translation id="6974306300279582256">تمكين التنبيهات من <ph name="SITE"/></translation>
+<translation id="6974306300279582256">تمكين الاشعارات من <ph name="SITE"/></translation>
 <translation id="5233638681132016545">علامة تبويب جديدة</translation>
 <translation id="6567688344210276845">تعذر تحميل الرمز '<ph name="ICON"/>' لإجراء المتصفح.</translation>
 <translation id="5210365745912300556">إغلاق علامة التبويب</translation>
@@ -1062,7 +1065,7 @@
 <translation id="7441627299479586546">موضوع السياسة غير صحيح</translation>
 <translation id="5252456968953390977">تجوال</translation>
 <translation id="8744641000906923997">Romaji</translation>
-<translation id="348620396154188443">السماح لكل المواقع بعرض تنبيهات سطح المكتب</translation>
+<translation id="348620396154188443">السماح لكل المواقع بعرض اشعارات سطح المكتب</translation>
 <translation id="7375125077091615385">النوع:</translation>
 <translation id="8214489666383623925">فتح ملف...</translation>
 <translation id="4583537898417244378">ملف غير صالح أو تالف.</translation>
@@ -1573,7 +1576,7 @@
 <translation id="5745056705311424885">‏اكتشاف رقاقة ذاكرة USB</translation>
 <translation id="7651319298187296870">يلزم تسجيل الدخول لشهادة المستخدم.</translation>
 <translation id="626568068055008686">كلمة مرور غير صالحة أو ملف تالف.</translation>
-<translation id="5895875028328858187">عرض تنبيهات عندما تكون البيانات قليلة أو أوشكت صلاحيتها على الانتهاء</translation>
+<translation id="5895875028328858187">عرض اشعارات عندما تكون البيانات قليلة أو أوشكت صلاحيتها على الانتهاء</translation>
 <translation id="939598580284253335">إدخال عبارة المرور</translation>
 <translation id="8418240940464873056">وضع الحروف الصينية</translation>
 <translation id="6557224990928257403">‏(لإجراء تحديث تلقائي لهذه الصفحة، استخدم chrome://<ph name="PAGE_NAME"/>/&amp;lt;ثانية&amp;gt;)</translation>
@@ -1583,6 +1586,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">الفيتناميّة</translation>
 <translation id="6423064450797205562">المقاييس المتعلقة بسرعة أداء <ph name="SHORT_PRODUCT_NAME"/> للإجراءات المطلوبة</translation>
+<translation id="2048118585307365263">‏تمكين MediaDrm.</translation>
 <translation id="4091434297613116013">أوراق</translation>
 <translation id="7475671414023905704">‏عنوان URL لكلمة المرور المفقودة في Netscape</translation>
 <translation id="3335947283844343239">إعادة فتح علامة التبويب المغلقة</translation>
@@ -2426,7 +2430,7 @@
 <translation id="6432458268957186486">الطباعة باستخدام مربع الحوار <ph name="CLOUD_PRINT_NAME"/>...</translation>
 <translation id="2950186680359523359">أغلق الخادم الاتصال بدون إرسال أية بيانات.</translation>
 <translation id="4269099019648381197">لتمكين خيار طلب موقع الجهاز اللوحي في قائمة الإعدادات.</translation>
-<translation id="9142623379911037913">هل تريد السماح للموقع <ph name="SITE"/> بعرض تنبيهات سطح المكتب؟</translation>
+<translation id="9142623379911037913">هل تريد السماح للموقع <ph name="SITE"/> بعرض اشعارات سطح المكتب؟</translation>
 <translation id="6546686722964485737">‏الانضمام إلى شبكة WiMAX</translation>
 <translation id="266983583785200437">الأحداث المتعلقة بأعطال وإخفاقات <ph name="SHORT_PRODUCT_NAME"/></translation>
 <translation id="9118804773997839291">توجد أدناه قائمة بجميع العناصر غير الآمنة في الصفحة. انقر على الرابط التشخيصي لمزيد من المعلومات عن سلسلة عنصر معيِّن.</translation>
@@ -2965,7 +2969,7 @@
 <translation id="7208899522964477531">البحث  في الموقع <ph name="SITE_NAME"/> عن &quot;<ph name="SEARCH_TERMS"/>&quot;</translation>
 <translation id="4031910098617850788">F5</translation>
 <translation id="8960795431111723921">نحن نحقق في هذه المشكلة حاليًا.</translation>
-<translation id="2482878487686419369">التنبيهات</translation>
+<translation id="2482878487686419369">الاشعارات</translation>
 <translation id="7091371877941014288">هل ترغب في التمكّن من تشغيل تطبيقات الكشك على هذا الجهاز؟</translation>
 <translation id="3175100205257218635"><ph name="BEGIN_BOLD"/>أنت تستخدم تصفح الضيف<ph name="END_BOLD"/>. لن تظهر الصفحات التي تشاهدها في علامة التبويب هذه في سجل المتصفح أو في سجل البحث، كما أنها لن تترك أي آثار أخرى، مثل ملفات تعريف الارتباط، على الجهاز بعد الخروج. ولن يتم الاحتفاظ بالملفات التي تنزلها والإشارات المرجعية التي تنشئها.
           <ph name="LINE_BREAK"/>
@@ -3822,6 +3826,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> يريد تخزين بيانات ذات حجم كبير في جهاز الكمبيوتر المحلي بشكل دائم.</translation>
 <translation id="373572798843615002">علامة تبويب واحدة</translation>
 <translation id="4806065163318322702">تبديل إدخال الصوت</translation>
+<translation id="6190185222845843088">استخدام خوادم وضع الحماية في المحفظة</translation>
 <translation id="3177048931975664371">انقر لإخفاء كلمة المرور</translation>
 <translation id="5852137567692933493">‏إعادة التشغيل وإجراء Powerwash</translation>
 <translation id="3092544800441494315">تضمين لقطة الشاشة هذه:</translation>
@@ -4092,6 +4097,7 @@
 <translation id="1639239467298939599">جارٍ التحميل.</translation>
 <translation id="5457599981699367932">تصفَّح كزائر</translation>
 <translation id="6850233365366645553">‏يجب إعادة التشغيل قبل أن تتم إعادة تعيين الجهاز عبر Powerwash. إجراء Powerwash من شأنه أن يعيد تعيين جهاز <ph name="IDS_SHORT_PRODUCT_NAME"/> ليصبح كما لو كان جديدًا.</translation>
+<translation id="4292622557427736684">‏تمكين MediaDrm افتراضيًا مع إضافات الوسائط المشفرة.</translation>
 <translation id="1812514023095547458">تحديد اللون</translation>
 <translation id="5089363139417863686">عرض باستخدام تطبيق الملفات</translation>
 <translation id="7047998246166230966">المؤشر</translation>
@@ -4441,6 +4447,7 @@
 <translation id="1728442818359004787">تغيير التطبيق الافتراضي...</translation>
 <translation id="7540972813190816353">حدث خطأ أثناء التحقق من التحديثات: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">جهاز بلوتوث غير متوافق: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">‏تعطيل واجهة برمجة تطبيقات Media Source غير المسبوقة ببادئة.</translation>
 <translation id="2225024820658613551">‏يجب عدم المتابعة &lt;strong&gt;خاصةً&lt;/strong&gt; إذا لم يظهر هذا التحذير من قبل بشأن هذا الموقع.</translation>
 <translation id="2049639323467105390">تتم إدارة هذا الجهاز بواسطة <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">أول يوم لتفعيل الصلاحية</translation>
@@ -4449,7 +4456,7 @@
 <translation id="1332674359020733290">أدخل كلمة المرور هنا للتأكيد.</translation>
 <translation id="3819415294190923087">تحديد شبكة</translation>
 <translation id="7325437708553334317">إضافة التباين العالي</translation>
-<translation id="2192664328428693215">الرجوع إليّ عند محاولة موقع إظهار تنبيهات على سطح المكتب (مستحسن)</translation>
+<translation id="2192664328428693215">الرجوع إليّ عند محاولة موقع إظهار اشعارات على سطح المكتب (مستحسن)</translation>
 <translation id="6708242697268981054">المصدر:</translation>
 <translation id="1909880997794698664">هل تريد بالتأكيد تشغيل هذا الجهاز في وضع الكشك بشكل دائم؟</translation>
 <translation id="1986281090560408715">لتمكين شاشة علوية أعلى الجانب الأيمن من الشاشة تدرج معلومات حول نقاط الاتصال على الشاشة.</translation>
@@ -5061,7 +5068,7 @@
 <translation id="5765491088802881382">لا تتوفر أية شبكات</translation>
 <translation id="1971538228422220140">حذف ملفات تعريف الارتباط وبيانات الموقع والمكونات الإضافية الأخرى</translation>
 <translation id="6510391806634703461">مستخدم جديد</translation>
-<translation id="4469842253116033348">تعطيل التنبيهات من الموقع <ph name="SITE"/></translation>
+<translation id="4469842253116033348">تعطيل الاشعارات من الموقع <ph name="SITE"/></translation>
 <translation id="3709244229496787112">تم إيقاف تشغيل المتصفح قبل انتهاء التنزيل.</translation>
 <translation id="7999229196265990314">تم إنشاء الملفات التالية:
         
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index db0b0e7..19f2359 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Показване на проверката на правописа и граматиката</translation>
 <translation id="7017587484910029005">Въведете знаците, които виждате на изображението по-долу.</translation>
 <translation id="9013589315497579992">Невалиден сертификат за удостоверяване на SSL клиент.</translation>
+<translation id="2085245445866855859">Приложението, в чийто манифест е посочен атрибутът „kiosk-only“, трябва да се инсталира в павилионния режим на ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> иска да съхранява за постоянно данни на устройството ви.</translation>
 <translation id="8524066305376229396">Постоянно хранилище:</translation>
 <translation id="7567293639574541773">&amp;Проверка на елемента</translation>
@@ -183,6 +184,7 @@
 <translation id="4858913220355269194">Фриц</translation>
 <translation id="2231238007119540260">Ако изтриете сертификат на сървър, възстановявате обичайните проверки за сигурността за този сървър и изисквате да използва валиден сертификат.</translation>
 <translation id="9110235431257073974">Активиране на интегрирането на уеб магазина и приложението Файлове.</translation>
+<translation id="6489433341782457580">За програмисти: За requestAutocomplete() използвайте услугата за тестова среда за извиквания на приложния програмен интерфейс (API) на Wallet.</translation>
 <translation id="8186609076106987817">Сървърът не можа да намери файла.</translation>
 <translation id="2846816712032308263">Активира бързото затваряне на раздели/прозорци – изпълнява js манипулатора onunload на раздела отделно от графичния потребителски интерфейс.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> не можа да зареди уеб страницата, защото <ph name="HOST_NAME"/> не отговаря дълго време. Може да няма достъп да уебсайта или да имате проблеми с връзката си с интернет.</translation>
@@ -340,6 +342,7 @@
 <translation id="8959810181433034287">Контролираният потребител ще трябва да влиза с тази парола, затова я изберете надеждна и не забравяйте да я споделите с него.</translation>
 <translation id="5154917547274118687">Памет</translation>
 <translation id="1493492096534259649">Този език не може да се използва за проверка на правописа</translation>
+<translation id="2103866351350079276">Деактивирайте версията без префикс на обекта MediaSource. Той позволява на JavaScript да изпраща мултимедийни данни директно до видеоелемент.</translation>
 <translation id="6628463337424475685">Търсене с/ъс <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Активирайте опцията, с чиято помощ в първоначалния SYN пакет за клиентска програма, с която вече е установена връзка, се изпраща допълнителна информация за удостоверяване. Така изпращането на данни ще започва по-бързо.</translation>
 <translation id="6563261555270336410">Подробности относно <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1575,6 +1578,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Виетнамски</translation>
 <translation id="6423064450797205562">Показатели, свързани със скоростта, с която <ph name="SHORT_PRODUCT_NAME"/> изпълнява заявените действия</translation>
+<translation id="2048118585307365263">Активиране на MediaDrm.</translation>
 <translation id="4091434297613116013">листа</translation>
 <translation id="7475671414023905704">URL адрес за изгубена парола на Netscape</translation>
 <translation id="3335947283844343239">Повторно отваряне на затворения раздел</translation>
@@ -3802,6 +3806,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> иска да съхранява за постоянно голямо количество данни на локалния ви компютър.</translation>
 <translation id="373572798843615002">1 раздел</translation>
 <translation id="4806065163318322702">Превключване на говорните команди</translation>
+<translation id="6190185222845843088">Използване на тестовите сървъри на Wallet</translation>
 <translation id="3177048931975664371">Кликнете, за да скриете паролата</translation>
 <translation id="5852137567692933493">Рестартиране и извършване на Powerwash</translation>
 <translation id="3092544800441494315">Да се включи тази екранна снимка:</translation>
@@ -4068,6 +4073,7 @@
 <translation id="1639239467298939599">Зарежда се</translation>
 <translation id="5457599981699367932">Сърфиране като гост</translation>
 <translation id="6850233365366645553">Изисква се рестартиране, преди фабричните настройки на устройството ви с <ph name="IDS_SHORT_PRODUCT_NAME"/> да могат да се възстановят с Powerwash. При това то ще се върне към първоначалното си състояние.</translation>
+<translation id="4292622557427736684">Активирайте MediaDrm по подразбиране за разширенията за шифрована мултимедия.</translation>
 <translation id="1812514023095547458">Избор на цвят</translation>
 <translation id="5089363139417863686">Преглед с приложението Файлове</translation>
 <translation id="7047998246166230966">Курсор</translation>
@@ -4418,6 +4424,7 @@
 <translation id="1728442818359004787">Промяна на приложението по подразбиране...</translation>
 <translation id="7540972813190816353">При проверката за актуализации възникна грешка: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Неподдържано устройство с Bluetooth: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Деактивиране на версията без префикс на приложния програмен интерфейс (API) за медийни източници.</translation>
 <translation id="2225024820658613551">Не трябва да продължавате, &lt;strong&gt;особено&lt;/strong&gt; ако преди не сте виждали това предупреждение за този сайт.</translation>
 <translation id="2049639323467105390">Това устройство се управлява от <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Не преди</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 4ad9400..621010c 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">বানান এবং ব্যাকরণ দেখান</translation>
 <translation id="7017587484910029005">আপনি নীচের ছবিটিতে যে অক্ষরগুলি দেখছেন সেগুলি টাইপ করুন৷</translation>
 <translation id="9013589315497579992">খারাপ  SSL  ক্লায়েন্ট  প্রমাণীকরণ শংসাপত্র৷ </translation>
+<translation id="2085245445866855859">'Kiosk_only' ম্যানিফেস্ট অ্যাট্রিবিউটের সাথে অ্যাপ্লিকেশনকে অবশ্যই ChromeOS কিয়স্ক মোডে ইনস্টল করতে হবে৷</translation>
 <translation id="1467999917853307373"><ph name="URL"/> স্থায়ীভাবে আপনার ডিভাইসে ডেটা জমা করতে চায়৷</translation>
 <translation id="8524066305376229396">অনবরত সঞ্চয়স্থান:</translation>
 <translation id="7567293639574541773">সং&amp;বীক্ষণ উপাদান</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">ফ্রিটজ</translation>
 <translation id="2231238007119540260">যদি আপনি কোনও সার্ভার শংসাপত্র মুছে থাকেন তবে আপনি সেই সার্ভারের জন্য স্বাভাবিক সুরক্ষা যাচাইগুলি পুনরুদ্ধার করতে পারেন এবং এটির একটি বৈধ শংসাপত্র হিসাবে ব্যবহারের প্রয়োজন হতে পারে৷</translation>
 <translation id="9110235431257073974">Webstore এবং Files.app এর ইন্টিগ্রেশন সক্ষম করুন৷</translation>
+<translation id="6489433341782457580">বিকাশকারীদের জন্য: requestAutocomplete() এর Wallet API এর জন্য স্যান্ডবক্স পরিষেবাটি ব্যবহার করুন৷</translation>
 <translation id="8186609076106987817">সার্ভার ফাইলটি খুঁজে পায়নি৷</translation>
 <translation id="2846816712032308263">দ্রুত ট্যাব/উইন্ডো বন্ধ করা সক্ষম করে -  GUI এর ট্যাবের অনআনলোড js হ্যান্ডেলার স্বাধীনভাবে চালায়৷</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">সাইন ইন করতে তত্ত্বাবধান করা ব্যবহারকারীকে এই পাসওয়ার্ডটি ব্যবহার করতে হবে, তাই একটি নিরাপদ পাসওয়ার্ড নির্বাচন করুন এবং তত্ত্বাবধান করা ব্যবহারকারীকে এটি জানানোর কথা মনে রাখুন৷</translation>
 <translation id="5154917547274118687">স্মৃতি</translation>
 <translation id="1493492096534259649">এই ভাষাটি বানান পরীক্ষণের জন্য নাও ব্যবহৃত হতে পারে|</translation>
+<translation id="2103866351350079276">সমাধান না করা MediaSource অবজেক্ট অক্ষম করে৷ এই অবজেক্ট JavaScript কে কোনো ভিডিও উপাদানে সরাসরি মিডিয়া ডেটা প্রেরণ করতে অনুমতি দেয়৷</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> অনুসন্ধান</translation>
 <translation id="6460423884798879930">পূর্বে সংযুক্ত থাকা একটি ক্লায়েন্টের জন্য প্রারম্ভিক SYN প্যাকেটে অতিরিক্ত প্রমাণীকরণ তথ্য পাঠাতে বিকল্পটি সক্ষম করুন, মঞ্জুরিপ্রাপ্ত দ্রুততর ডেটা পাঠানো শুরু করা যাবে৷</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> সম্পর্কিত বিশদ বিবরণ</translation>
@@ -1597,6 +1600,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">ভিয়েতনামি</translation>
 <translation id="6423064450797205562">অনুরোধকৃত ক্রিয়াতে <ph name="SHORT_PRODUCT_NAME"/> যে গতিতে সম্পাদন করে তার সাথে সম্পর্কিত মেট্রিক্স</translation>
+<translation id="2048118585307365263">MediaDrm সক্ষম করুন৷</translation>
 <translation id="4091434297613116013">কাগজের তাল</translation>
 <translation id="7475671414023905704">Netscape পাসওয়ার্ড URL হারিয়েছে</translation>
 <translation id="3335947283844343239">বন্ধ হওয়া ট্যাব পুনরায় খুলুন</translation>
@@ -1989,7 +1993,7 @@
 <translation id="7238461040709361198">আপনি এই কম্পিউটারে শেষ বার সাইন ইন করার পরে আপনার Google অ্যাকাউন্টের পাসওয়ার্ড পরিবর্তিত হয়েছে৷</translation>
 <translation id="1956050014111002555">ফাইলটিতে একাধিক শংসাপত্র রয়েছে, এর মধ্যে কোনওটিই আমদানি করা হয়নি:</translation>
 <translation id="302620147503052030">প্রদর্শন  বোতাম</translation>
-<translation id="1895658205118569222">শাটডাউন</translation>
+<translation id="1895658205118569222">বন্ধ করুন</translation>
 <translation id="4432480718657344517">বাইট পঠন</translation>
 <translation id="8708000541097332489">প্রস্থানে সাফ করুন</translation>
 <translation id="6827236167376090743">পাশাপাশি এই ভিডিওটি দীর্ঘ সময় ধরে চলতে থাকবে৷</translation>
@@ -2733,7 +2737,7 @@
         গঠন হওয়া পৃষ্ঠার মত কিছু নির্দিষ্ট সংস্থানই কেবলমাত্র ক্যাশে থেকে
         নিরাপদভাবে লোড করা যাবে৷
         <ph name="LINE_BREAK"/>
-        ঠিকমত শাটডাউন না হওয়ার ফলে ক্যাশে দূষণের কারণেরও
+        ঠিকমত বন্ধ না হওয়ার ফলে ক্যাশে দূষণের কারণেরও
         এই ত্রুটি হতে পারে৷
         <ph name="LINE_BREAK"/>
         সমস্যাটি থেকে গেলে, ক্যাশে সাফ করার চেষ্টা করুন৷</translation>
@@ -2917,7 +2921,7 @@
 <translation id="7248671827512403053">অ্যাপ্লিকেশান</translation>
 <translation id="450070808725753129">নেটওয়ার্ক অ্যাক্সেস করতে এটি ইতিমধ্যেই মঞ্জুরিকৃত প্রোগ্রাম হিসাবে তালিকাতে
         আছে, তালিকাটি থেকে এটি সরানোর চেষ্টা করুন এবং পুনরায় যোগ করুন৷</translation>
-<translation id="5024161246034732431">শ্রেণীবদ্ধ ব্রাউজার শাটডাউন সক্ষম করুন</translation>
+<translation id="5024161246034732431">শ্রেণীবদ্ধ ব্রাউজার বন্ধ করতে সক্ষম করুন</translation>
 <translation id="16620462294541761">দুঃখিত, আপনার পাসওয়ার্ড যাচাই করা যায়নি৷ দয়া করে আবার চেষ্টা করুন৷</translation>
 <translation id="4968399700653439437">এই ডোমেনগুলিতে যেকোনো কম্পিউটারের সাথে ডেটা বিনিময় করুন: <ph name="DOMAINS"/></translation>
 <translation id="3058072209957292419">পরীক্ষামূলক স্থিত আইপি কনফিগারেশন</translation>
@@ -3030,8 +3034,8 @@
 <translation id="6739254200873843030">কার্ডের মেয়াদ শেষ হয়েছে৷ দয়া করে তারিখটি পরীক্ষা করুন এবং একটি নতুন কার্ড লিখুন৷</translation>
 <translation id="8793043992023823866">আমদানি হচ্ছে...</translation>
 <translation id="8106211421800660735">ক্রেডিট কার্ড নম্বর</translation>
-<translation id="8843709518995654957">এই ডিভাইসের জন্য <ph name="LINK_START"/>তত্ত্বাবধানে থাকা ব্যবহারকারী তৈরি করুন<ph name="LINK_END"/>৷</translation>
-<translation id="2872961005593481000">শাট ডাউন</translation>
+<translation id="8843709518995654957">এই ডিভাইসের জন্য একটি<ph name="LINK_START"/>তত্ত্বাবধানে থাকা ব্যবহারকারী তৈরি করুন<ph name="LINK_END"/>৷</translation>
+<translation id="2872961005593481000">বন্ধ করুন</translation>
 <translation id="8986267729801483565">ডাউনলোড অবস্থান:</translation>
 <translation id="7021076338299963900">রাস্তার ঠিকানা (ঐচ্ছিক)</translation>
 <translation id="2044540568167155862">Goats Teleported</translation>
@@ -3379,7 +3383,7 @@
 <translation id="4010065515774514159">ব্রাউজার ক্রিয়া</translation>
 <translation id="7295019613773647480">তত্ত্বাবধানে থাকা ব্যবহারকারীদের সক্ষম করুন</translation>
 <translation id="2893389635995517838">আপনার কম্পিউটার থেকে ফটো, সঙ্গীত ও অন্য মিডিয়াতে অ্যাক্সেস করুন</translation>
-<translation id="3529423920239848704"><ph name="SHORT_PRODUCT_NAME"/> সঠিকভাবে শাট ডাউন না হলে সংঘটন</translation>
+<translation id="3529423920239848704"><ph name="SHORT_PRODUCT_NAME"/> সঠিকভাবে বন্ধ না হলে তার সংঘটন</translation>
 <translation id="7022562585984256452">আপনার হোম পৃষ্ঠা সেট করা হয়েছে৷</translation>
 <translation id="267285457822962309">আপনার ডিভাইস এবং যন্ত্রপাতি বিশেষে সেটিংসমূহ পরিবর্তন করুন৷</translation>
 <translation id="1154228249304313899">এই পৃষ্ঠাটি খুলুন:</translation>
@@ -3853,6 +3857,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> স্থায়ীরূপে আপনার কম্পিউটারে অত্যধিক ডেটা জমা করতে চায়৷</translation>
 <translation id="373572798843615002">1 টি ট্যাব</translation>
 <translation id="4806065163318322702">কথন ইনপুট টগল করুন</translation>
+<translation id="6190185222845843088">Wallet স্যান্ডবক্স সার্ভারগুলি ব্যবহার করুন</translation>
 <translation id="3177048931975664371">পাসওয়ার্ড লুকাতে ক্লিক করুন</translation>
 <translation id="5852137567692933493">পুনরায় আরম্ভ করুন এবং পাওয়ারওয়াশ করুন</translation>
 <translation id="3092544800441494315">এই স্ক্রিনশটটি অন্তর্ভুক্ত করুন:</translation>
@@ -4110,7 +4115,7 @@
 <translation id="5981759340456370804">একরোখা প্রযুক্তিবিদের জন্য পরিসংখ্যান</translation>
 <translation id="7293654927214385623">প্রমাণীকৃত এনক্রিপটেড চ্যানেলের মাধ্যমে QUIC সক্ষম করে ( HTTPS লেনদেনগুলি প্রতিস্থাপন করতে পারে)৷ এই ফ্ল্যাগ ছাড়া, QUIC এ কেবল HTTP অনুরোধগুলি সমর্থিত৷ যদি QUIC প্রোটোকল সক্ষম থাকে তাহলেই এটি কার্যকর হয়৷</translation>
 <translation id="8160015581537295331">স্প্যানীয় কীবোর্ড</translation>
-<translation id="5770661467408662510">এই বিকল্পগুলি সক্ষম করলে শাটডাউন করার সময় ব্রাউজারের উইন্ডোগুলি বন্ধ করায় বিলম্ব করে, ততক্ষণ শাটডাউন বাতিলযোগ্য থাকে না৷</translation>
+<translation id="5770661467408662510">এই বিকল্পগুলি সক্ষম করলে বন্ধ করার সময় ব্রাউজারের উইন্ডোগুলি বন্ধ করায় বিলম্ব করে, ততক্ষণ বন্ধ করা বাতিলযোগ্য থাকে না৷</translation>
 <translation id="560412284261940334">পরিচালনা সমর্থিত নয়</translation>
 <translation id="6723661294526996303">বুকমার্কস এবং সেটিংস আমদানি করুন...</translation>
 <translation id="1782924894173027610">সিঙ্ক সার্ভার ব্যস্ত আছে, দয়া করে পরে আবার চেষ্টা করুন৷</translation>
@@ -4120,6 +4125,7 @@
 <translation id="1639239467298939599">লোড হচ্ছে</translation>
 <translation id="5457599981699367932">অতিথি হিসাবে ব্রাউজ করুন</translation>
 <translation id="6850233365366645553">আপনার ডিভাইসকে পাওয়ারওয়াশ দ্বারা পুনরায় সেট করতে এটিকে পুনরায় চালু করতে হবে৷ পাওয়ারওয়াশ আপনার <ph name="IDS_SHORT_PRODUCT_NAME"/> ডিভাইসকে একেবারে নতুনের মত পুনরায় সেট করে৷</translation>
+<translation id="4292622557427736684">এনক্রিপ্ট করা মিডিয়া এক্সটেনশানগুলি জন্য ডিফল্ট হিসাবে MediaDrm সক্ষম করুন৷</translation>
 <translation id="1812514023095547458">রঙ নির্বাচন করুন</translation>
 <translation id="5089363139417863686">ফাইলগুলির অ্যাপ্লিকেশানের মাধ্যমে দেখুন</translation>
 <translation id="7047998246166230966">পয়েন্টার</translation>
@@ -4468,6 +4474,7 @@
 <translation id="1728442818359004787">ডিফল্ট অ্যাপ্লিকেশান পরিবর্তন করুন...</translation>
 <translation id="7540972813190816353">আপডেট পরীক্ষা করার সময় একটি ত্রুটি হয়েছে: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">অসমর্থিত Bluetooth ডিভাইস: &quot;<ph name="DEVICE_NAME"/>&quot;৷</translation>
+<translation id="2990212470195050777">সমাধান না করা Media Source API অক্ষম করুন৷</translation>
 <translation id="2225024820658613551">আপনার এগিয়ে যাওয়া উচিত নয়, &lt;strong&gt;বিশেষ করে&lt;/strong&gt; আপনি যদি এই সাইটের জন্য আগে এই সতর্কবার্তা না দেখে থাকেন তাহলে৷</translation>
 <translation id="2049639323467105390">এই ডিভাইস <ph name="DOMAIN"/> দ্বারা পরিচালিত হয়৷</translation>
 <translation id="1932098463447129402">আগে কখনও নয়</translation>
@@ -5087,7 +5094,7 @@
 <translation id="1971538228422220140">কুকিজ এবং অন্যান্য সাইট এবং প্লাগ-ইন ডেটা মুছুন</translation>
 <translation id="6510391806634703461">নতুন ব্যবহারকারী</translation>
 <translation id="4469842253116033348"><ph name="SITE"/>-এর থেকে বিজ্ঞপ্তি অক্ষম করুন</translation>
-<translation id="3709244229496787112">ডাউনলোডটি সম্পূর্ণ হওয়ার আগে ব্রাউজারটি শাট ডাউন হয়েছিল৷</translation>
+<translation id="3709244229496787112">ডাউনলোডটি সম্পূর্ণ হওয়ার আগে ব্রাউজারটি বন্ধ হয়েছিল৷</translation>
 <translation id="7999229196265990314">নিম্নোক্ত ফাইলগুলি তৈরি হয়েছে:
 
 এক্সটেনশান: <ph name="EXTENSION_FILE"/>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 9d7a29e..5730a09 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Mostra l'ortografia i la gramàtica</translation>
 <translation id="7017587484910029005">Escriviu els caràcters que veieu a la imatge inferior.</translation>
 <translation id="9013589315497579992">Certificat d'autenticació de client SSL incorrecte.</translation>
+<translation id="2085245445866855859">L'aplicació amb l'atribut del fitxer de manifest &quot;kiosk_only&quot; s'ha d'instal·lar al mode quiosc de ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vol emmagatzemar dades al vostre dispositiu de manera permanent.</translation>
 <translation id="8524066305376229396">Emmagatzematge permanent:</translation>
 <translation id="7567293639574541773">I&amp;nspecciona l'element</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Pilota</translation>
 <translation id="2231238007119540260">Si suprimiu un certificat de servidor, restaurareu les comprovacions de seguretat normals per a aquell servidor i es necessitarà que utilitzi un certificat vàlid.</translation>
 <translation id="9110235431257073974">Activa la integració de WebStore i Files.app.</translation>
+<translation id="6489433341782457580">Per als desenvolupadors: utilitzeu el servei de la zona de proves per a les trucades a l'API de Wallet per a requestAutocomplete().</translation>
 <translation id="8186609076106987817">El servidor no ha pogut trobar el fitxer.</translation>
 <translation id="2846816712032308263">Activa el tancament ràpid de la pestanya/finestra; executa un gestor js de descàrrega de la pestanya independentment de la interfície gràfica d'usuari.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> no ha pogut carregar la pàgina web perquè <ph name="HOST_NAME"/> ha trigat massa a respondre. Pot ser que el lloc web estigui fora de servei o que tingueu problemes amb la connexió a Internet.</translation>
@@ -349,6 +351,7 @@
 <translation id="8959810181433034287">L'usuari supervisat haurà de fer servir aquesta contrasenya per iniciar la sessió, de manera que cal que escolliu una contrasenya segura i que us recordeu de proporcionar-la a l'usuari supervisat.</translation>
 <translation id="5154917547274118687">Memòria</translation>
 <translation id="1493492096534259649">Aquest idioma no es pot utilitzar per a la revisió de l'ortografia</translation>
+<translation id="2103866351350079276">Desactiva l'objecte MediaSource sense prefix. Aquest objecte permet que JavaScript enviï dades multimèdia directament a un element de vídeo.</translation>
 <translation id="6628463337424475685">Cerca de <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Activa l'opció per enviar informació d'autenticació addicional al paquet SYN inicial per a un client ja connectat, de manera que permet que s'iniciï l'enviament de dades més ràpidament.</translation>
 <translation id="6563261555270336410">Detalls sobre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1585,6 +1588,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Mètriques relacionades amb la velocitat amb què <ph name="SHORT_PRODUCT_NAME"/> realitza les accions requerides</translation>
+<translation id="2048118585307365263">Activa MediaDrm</translation>
 <translation id="4091434297613116013">fulls de paper</translation>
 <translation id="7475671414023905704">URL de contrasenya perduda de Netscape</translation>
 <translation id="3335947283844343239">Torna a obrir la pestanya tancada</translation>
@@ -3118,7 +3122,7 @@
 <translation id="5266113311903163739">Error d'importació de l'entitat emissora de certificats</translation>
 <translation id="4240511609794012987">Memòria compartida</translation>
 <translation id="4756388243121344051">&amp;Historial</translation>
-<translation id="5488640658880603382">Esteu segur que voleu suprimir &quot;<ph name="PROFILE_NAME"/>&quot; i totes les dades associades des d'aquest equip? Aquesta acció no es pot desfer.</translation>
+<translation id="5488640658880603382">Esteu segur que voleu suprimir &quot;<ph name="PROFILE_NAME"/>&quot; i totes les dades associades d'aquest ordinador? Aquesta acció no es pot desfer.</translation>
 <translation id="8044899503464538266">Lent</translation>
 <translation id="3789841737615482174">Instal·la</translation>
 <translation id="4320697033624943677">Afegeix usuaris</translation>
@@ -3239,7 +3243,7 @@
 <translation id="8813873272012220470">Activa una comprovació en processament de fons que us avisa si detecta incompatibilitats de programari (p. ex., mòduls de tercers que bloquegen el navegador).</translation>
 <translation id="3660234220361471169">No és de confiança</translation>
 <translation id="3504669335572969216">Aquest és un usuari supervisat gestionat per <ph name="CUSTODIAN_EMAIL"/>
-La vostra informació d'inici de sessió al compte ha caducat.</translation>
+La vostra informació d'inici de sessió al compte no està actualitzada.</translation>
 <translation id="2679385451463308372">Imprimeix amb el diàleg del sistema…</translation>
 <translation id="959890390740139744">Corregeix l'ortografia automàticament</translation>
 <translation id="2607991137469694339">Mètode d'introducció en tàmil (fonètic)</translation>
@@ -3831,6 +3835,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vol emmagatzemar de forma permanent una gran quantitat de dades a l'equip local.</translation>
 <translation id="373572798843615002">1 pestanya</translation>
 <translation id="4806065163318322702">Canvia a l'entrada de veu</translation>
+<translation id="6190185222845843088">Utilitza els servidors de la zona de proves de Wallet</translation>
 <translation id="3177048931975664371">Feu clic per amagar la contrasenya</translation>
 <translation id="5852137567692933493">Reinicia i utilitza Powerwash</translation>
 <translation id="3092544800441494315">Inclou aquesta captura de pantalla:</translation>
@@ -4098,6 +4103,7 @@
 <translation id="1639239467298939599">S'està carregant</translation>
 <translation id="5457599981699367932">Navega com a convidat</translation>
 <translation id="6850233365366645553">Per poder restablir el dispositiu amb Powerwash, abans cal reiniciar-lo. Una operació Powerwash restableix la configuració de fàbrica del dispositiu <ph name="IDS_SHORT_PRODUCT_NAME"/> i el deixa com si fos nou.</translation>
+<translation id="4292622557427736684">Activa MediaDrm de manera predeterminada per a les extensions de fitxers multimèdia encriptats.</translation>
 <translation id="1812514023095547458">Selecció de color</translation>
 <translation id="5089363139417863686">Visualitza amb l'aplicació Fitxers</translation>
 <translation id="7047998246166230966">Busca</translation>
@@ -4447,6 +4453,7 @@
 <translation id="1728442818359004787">Canvia l'aplicació predeterminada...</translation>
 <translation id="7540972813190816353">S'ha produït un error durant la cerca d'actualitzacions: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositiu Bluetooth no compatible: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Desactiva l'API font multimèdia sense prefix</translation>
 <translation id="2225024820658613551">No hauríeu de continuar, &lt;strong&gt;sobretot&lt;/strong&gt; si és la primera vegada que veieu aquesta advertència en aquest lloc.</translation>
 <translation id="2049639323467105390"><ph name="DOMAIN"/> gestiona aquest dispositiu.</translation>
 <translation id="1932098463447129402">No abans</translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index 2472719..c6eb1c9 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Zobrazit pravopis a gramatiku</translation>
 <translation id="7017587484910029005">Zadejte znaky, které vidíte na obrázku níže.</translation>
 <translation id="9013589315497579992">Špatný ověřovací certifikát klienta SSL</translation>
+<translation id="2085245445866855859">Aplikace s atributem manifestu kiosk_only je třeba nainstalovat v režimu veřejného terminálu systému Chrome OS.</translation>
 <translation id="1467999917853307373">Stránka <ph name="URL"/> chce trvale ukládat data v zařízení.</translation>
 <translation id="8524066305376229396">Trvalé úložiště:</translation>
 <translation id="7567293639574541773">Zkontrolovat &amp;prvek</translation>
@@ -183,6 +184,7 @@
 <translation id="4858913220355269194">Fotbal</translation>
 <translation id="2231238007119540260">Smažete-li certifikát serveru, bude server opět prověřován běžnými bezpečnostními kontrolami a bude od něj vyžadován platný certifikát.</translation>
 <translation id="9110235431257073974">Aktivovat integraci funkce Webstore s aplikací Soubory.</translation>
+<translation id="6489433341782457580">Pro vývojáře: Pro volání rozhraní Wallet API metody requestAutocomplete() používat službu sandbox.</translation>
 <translation id="8186609076106987817">Serveru se nepodařilo soubor najít.</translation>
 <translation id="2846816712032308263">Aktivuje rychlé zavírání karet nebo oken. Spouští obslužný nástroj rutiny OnUnload JavaScriptu nezávisle na grafickém uživatelském rozhraní.</translation>
 <translation id="9134410174832249455">Prohlížeči <ph name="PRODUCT_NAME"/> se nepodařilo načíst stránku, protože odezva serveru <ph name="HOST_NAME"/> byla příliš dlouhá. Webové stránky možná nejsou v provozu nebo máte potíže s připojením k internetu.</translation>
@@ -351,6 +353,7 @@
 <translation id="8959810181433034287">Dozorovaný uživatel se pomocí tohoto hesla bude přihlašovat. Vyberte proto bezpečné heslo a nezapomeňte je s daným uživatelem prodiskutovat.</translation>
 <translation id="5154917547274118687">Paměť</translation>
 <translation id="1493492096534259649">Tento jazyk nelze použít ke kontrole pravopisu</translation>
+<translation id="2103866351350079276">Deaktivovat objekt MediaSource bez předpony. Tento objekt umožňuje JavaScriptu odesílat data médií přímo do prvku videa.</translation>
 <translation id="6628463337424475685">Vyhledávání <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">U klienta, který již byl dříve připojen, bude aktivována možnost odeslání dodatečných ověřovacích údajů v počátečním paketu SYN, což zvyšuje rychlost zahájení odesílání dat.</translation>
 <translation id="6563261555270336410">Podrobnosti o webu <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1123,7 +1126,7 @@
 <translation id="7518003948725431193">Na webové adrese <ph name="URL"/> se nepodařilo nalézt žádnou webovou stránku.</translation>
 <translation id="7484645889979462775">Nikdy v případě těchto stránek</translation>
 <translation id="9086455579313502267">Nelze získat přístup k síti.</translation>
-<translation id="2772936498786524345">Ninja</translation>
+<translation id="2772936498786524345">Nindža</translation>
 <translation id="5595485650161345191">Upravit adresu</translation>
 <translation id="1849186935225320012">Tato stránka má úplnou kontrolu nad zařízeními MIDI.</translation>
 <translation id="7309416673261215716">Verze rozšíření</translation>
@@ -1372,7 +1375,6 @@
 <translation id="2660779039299703961">Událost</translation>
 <translation id="4249248555939881673">Čeká se na připojení k síti...</translation>
 <translation id="8651130890368571179">Dozorovaný uživatel si může prohlížet web podle vašich pokynů. Jakožto správce dozorovaného uživatele v Chromu můžete
-
  • povolit nebo zakázat konkrétní weby,
  • kontrolovat, které weby uživatel navštívil, a
  • spravovat další nastavení.
@@ -1573,6 +1575,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamština</translation>
 <translation id="6423064450797205562">Metriky související s rychlostí, kterou <ph name="SHORT_PRODUCT_NAME"/> provádí požadované akce</translation>
+<translation id="2048118585307365263">Aktivovat službu MediaDrm.</translation>
 <translation id="4091434297613116013">listy papíru</translation>
 <translation id="7475671414023905704">Adresa URL pro získání ztraceného hesla Netscape</translation>
 <translation id="3335947283844343239">Znovu otevřít zavřenou kartu</translation>
@@ -2855,7 +2858,7 @@
 <translation id="2912905526406334195">Stránka <ph name="HOST"/> chce použít váš mikrofon.</translation>
 <translation id="2805756323405976993">Aplikace</translation>
 <translation id="1608626060424371292">Odebrat tohoto uživatele</translation>
-<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> byl vytvořen jako dozorovaný uživatel.</translation>
+<translation id="3075239840551149663">Vytvořili jste dozorovaného uživatele <ph name="NEW_PROFILE_NAME"/>!</translation>
 <translation id="3651020361689274926">Požadovaný zdroj již neexistuje a není k dispozici ani adresa přesměrování. Tento stav je pravděpodobně trvalý.</translation>
 <translation id="7541236596838501870">Nahrané protokoly WebRTC (<ph name="WEBRTC_LOG_COUNT"/>)</translation>
 <translation id="6003284010415283671">Přidat aplikace</translation>
@@ -3831,6 +3834,7 @@
 <translation id="3672159315667503033">Stránka <ph name="URL"/> chce trvale ukládat data v místním počítači.</translation>
 <translation id="373572798843615002">1 karta</translation>
 <translation id="4806065163318322702">Přepnout hlasový vstup</translation>
+<translation id="6190185222845843088">Použít servery sandbox služby Peněženka</translation>
 <translation id="3177048931975664371">Kliknutím skryjete heslo</translation>
 <translation id="5852137567692933493">Restartovat a použít funkci Powerwash</translation>
 <translation id="3092544800441494315">Přiložit tento snímek obrazovky:</translation>
@@ -4098,6 +4102,7 @@
 <translation id="1639239467298939599">Načítání</translation>
 <translation id="5457599981699367932">Použít jako host</translation>
 <translation id="6850233365366645553">Před obnovením pomocí funkce Powerwash je nutné zařízení restartovat. Funkce Powerwash ve vašem zařízení <ph name="IDS_SHORT_PRODUCT_NAME"/> zcela obnoví počáteční nastavení.</translation>
+<translation id="4292622557427736684">Pro rozhraní Encrypted Media Extensions ve výchozím nastavení aktivovat službu MediaDrm.</translation>
 <translation id="1812514023095547458">Výběr barvy</translation>
 <translation id="5089363139417863686">Zobrazit pomocí aplikace Soubory</translation>
 <translation id="7047998246166230966">Kurzor</translation>
@@ -4447,6 +4452,7 @@
 <translation id="1728442818359004787">Změnit výchozí aplikaci...</translation>
 <translation id="7540972813190816353">Při kontrole aktualizací došlo k chybě: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nepodporované zařízení Bluetooth: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Deaktivovat rozhraní Media Source API bez předpony.</translation>
 <translation id="2225024820658613551">Neměli byste pokračovat, &lt;strong&gt;zvláště&lt;/strong&gt; pokud jste takové varování u těchto stránek dosud neviděli.</translation>
 <translation id="2049639323467105390">Zařízení je spravováno doménou <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Nikoli před</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index da127f7..41240c6 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -129,11 +129,12 @@
 <translation id="528468243742722775">End</translation>
 <translation id="1723824996674794290">&amp;Nyt vindue</translation>
 <translation id="1313405956111467313">Automatisk proxykonfiguration</translation>
-<translation id="3527276236624876118">En overvåget bruger ved navn <ph name="USER_DISPLAY_NAME"/> er blevet oprettet.</translation>
+<translation id="3527276236624876118">En administreret bruger ved navn <ph name="USER_DISPLAY_NAME"/> er blevet oprettet.</translation>
 <translation id="4367782753568896354">Vi kunne ikke installere:</translation>
 <translation id="1589055389569595240">Vis stavning og grammatik</translation>
 <translation id="7017587484910029005">Indtast de tegn, du kan se på billedet nedenfor.</translation>
 <translation id="9013589315497579992">Ugyldigt certifikat til SSL-klientgodkendelse.</translation>
+<translation id="2085245445866855859">Appen med manifestattributten &quot;kiosk_only&quot; skal installeres i ChromeOS-terminaltilstand.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vil gemme data permanent på din enhed.</translation>
 <translation id="8524066305376229396">Vedvarende lagring:</translation>
 <translation id="7567293639574541773">Vis detaljer om eleme&amp;ntet</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Laudrup</translation>
 <translation id="2231238007119540260">Hvis du sletter et servercertifikat, gendanner du den sædvanlige sikkerhedskontrol for den server og kræver, at den bruger et gyldigt certifikat.</translation>
 <translation id="9110235431257073974">Aktivér integrationen af Webshop i appen Filer.</translation>
+<translation id="6489433341782457580">For udviklere: Brug sandbox-tjenesten til Wallet API-kald for requestAutocomplete().</translation>
 <translation id="8186609076106987817">Serveren kunne ikke finde filen.</translation>
 <translation id="2846816712032308263">Aktiverer hurtig lukning af fane/vindue – kører en fanes onunload js handler uafhængigt af GUI'en.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> kunne ikke indlæse websiden, fordi <ph name="HOST_NAME"/> brugte for lang tid på at reagere. Websitet er muligvis nede, eller der kan være problemer med din internetforbindelse.</translation>
@@ -194,7 +196,7 @@
 <translation id="7624154074265342755">Trådløst netværk</translation>
 <translation id="2391762656119864333">Tilbagekald</translation>
 <translation id="3315158641124845231">Skjul <ph name="PRODUCT_NAME"/></translation>
-<translation id="7069168971636881066">Der skal være mindst én eksisterende konto på denne enhed, før der kan oprettes en overvåget bruger.</translation>
+<translation id="7069168971636881066">Der skal være mindst én eksisterende konto på denne enhed, før der kan oprettes en administreret bruger.</translation>
 <translation id="7809034755304591547"><ph name="EXTENSION_NAME"/> (udvidelses-id &quot;<ph name="EXTENSION_ID"/>&quot;) er blokeret af administratoren.</translation>
 <translation id="6373256700241079718">Netværk:</translation>
 <translation id="7766807826975222231">Få en rundvisning</translation>
@@ -223,7 +225,7 @@
 <translation id="645705751491738698">Fortsæt blokering af JavaScript</translation>
 <translation id="9177556055091995297">Administrer kreditkort</translation>
 <translation id="4780321648949301421">Gem side som...</translation>
-<translation id="8630903300770275248">Importér overvåget bruger</translation>
+<translation id="8630903300770275248">Importér administreret bruger</translation>
 <translation id="3866863539038222107">Inspicer</translation>
 <translation id="4552678318981539154">Køb mere lagerplads</translation>
 <translation id="2262243747453050782">HTTP-fejl</translation>
@@ -274,7 +276,7 @@
 <translation id="5748743223699164725">Aktivér eksperimentelle webplatformfunktioner, der er under udvikling.</translation>
 <translation id="8110513421455578152">Angiv standardhøjden for felter.</translation>
 <translation id="8848519885565996859">Brugerdefineret link til webadresse</translation>
-<translation id="7002454948392136538">Vælg administrator for den overvågede bruger</translation>
+<translation id="7002454948392136538">Vælg administrator for den administrerede bruger</translation>
 <translation id="4640525840053037973">Log ind med din Google-konto</translation>
 <translation id="5255315797444241226">Den angivne adgangssætning er forkert.</translation>
 <translation id="762917759028004464"><ph name="BROWSER_NAME"/> er i øjeblikket din standardbrowser.</translation>
@@ -349,9 +351,10 @@
 <translation id="6928441285542626375">Aktivér TCP Fast Open</translation>
 <translation id="7792388396321542707">Stop deling</translation>
 <translation id="5463275305984126951">Indeks over <ph name="LOCATION"/></translation>
-<translation id="8959810181433034287">Den overvågede bruger skal bruge denne adgangskode ved login, så vælg en sikker adgangskode, og husk at informere den overvågede bruger.</translation>
+<translation id="8959810181433034287">Den administrerede bruger skal bruge denne adgangskode ved login, så vælg en sikker adgangskode, og husk at informere den administrerede bruger.</translation>
 <translation id="5154917547274118687">Hukommelse</translation>
 <translation id="1493492096534259649">Dette sprog kan ikke bruges til stavekontrol</translation>
+<translation id="2103866351350079276">Deaktiver MediaSource-objektet uden præfiks. Dette gør det muligt for JavaScript at sende mediedata direkte til et videoelement.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Søg</translation>
 <translation id="6460423884798879930">Aktivér muligheden for at sende ekstra godkendelsesoplysninger i den oprindelige SYN-pakke for en tidligere tilsluttet klient, hvilket vil resultere i en hurtigere dataafsendelse.</translation>
 <translation id="6563261555270336410">Oplysninger om <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -361,7 +364,7 @@
 <translation id="6243774244933267674">Serveren er utilgængelig</translation>
 <translation id="2436707352762155834">Minimum</translation>
 <translation id="5556206011531515970">Klik på Næste for at vælge din standardbrowser.</translation>
-<translation id="8158300065514217730">Log ind for at importere overvågede brugere</translation>
+<translation id="8158300065514217730">Log ind for at importere administrerede brugere</translation>
 <translation id="2789486458103222910">OK</translation>
 <translation id="4792711294155034829">&amp;Rapporter et problem...</translation>
 <translation id="5819484510464120153">Opret &amp;programgenveje ...</translation>
@@ -723,7 +726,7 @@
 <translation id="6840184929775541289">Er ikke en certificeringsautoritet</translation>
 <translation id="6099520380851856040">Forekom <ph name="CRASH_TIME"/></translation>
 <translation id="144518587530125858">'<ph name="IMAGE_PATH"/>' for temaet kunne ikke indlæses.</translation>
-<translation id="8407525159012803013">Vis og administrer et ikon i systemindikatorområdet.</translation>
+<translation id="8407525159012803013">Se og administrer et ikon i systemindikatorområdet.</translation>
 <translation id="3984921062031549150">Renderer fryser</translation>
 <translation id="7925285046818567682">Venter på <ph name="HOST_NAME"/>...</translation>
 <translation id="1666717637711167064"><ph name="BEGIN_BOLD"/>Anbefaling: <ph name="END_BOLD"/>Sørg for, at du har valgt den rigtige gateway, og at den er konfigureret korrekt.</translation>
@@ -1146,7 +1149,7 @@
 <translation id="6840313690797192085">$1 PB</translation>
 <translation id="284232663722007589">Aktivér appen Udviklerværktøj til apps.</translation>
 <translation id="2374144379568843525">&amp;Skjul stavepanel</translation>
-<translation id="3313590242757056087">Du kan angive, hvilke websites den overvågede bruger skal kunne se, ved at konfigurere begrænsninger
+<translation id="3313590242757056087">Du kan angive, hvilke websites den administrerede bruger skal kunne se, ved at konfigurere begrænsninger
     og indstillinger på <ph name="MANAGEMENT_URL"/>.
     Hvis du ikke ændrer standardindstillingerne, kan <ph name="USER_DISPLAY_NAME"/>
     besøge alle websites på nettet.</translation>
@@ -1178,7 +1181,7 @@
 <translation id="2585300050980572691">Standardindstillinger for søgning</translation>
 <translation id="2617919205928008385">Der er ikke nok plads til rådighed.</translation>
 <translation id="1608306110678187802">Udsk&amp;riv ramme ...</translation>
-<translation id="3623574769078102674">Denne overvågede bruger administreres af <ph name="MANAGER_EMAIL"/>.</translation>
+<translation id="3623574769078102674">Denne administrerede bruger administreres af <ph name="MANAGER_EMAIL"/>.</translation>
 <translation id="3778152852029592020">Download blev annulleret.</translation>
 <translation id="7831368056091621108">for at få denne udvidelse, din historik og andre Chrome-indstillinger på alle dine enheder.</translation>
 <translation id="7427315641433634153">MSCHAP</translation>
@@ -1384,7 +1387,7 @@
 <translation id="1105608846356399385">Besøg website</translation>
 <translation id="7218608093942361839"><ph name="PRODUCT_NAME"/> <ph name="PRODUCT_VERSION"/> (Platform <ph name="PLATFORM_VERSION"/>)</translation>
 <translation id="1644184664548287040">Netværkskonfigurationen er ugyldig og kunne ikke importeres.</translation>
-<translation id="54870580363317966">Vælg en avatar for denne overvågede bruger.</translation>
+<translation id="54870580363317966">Vælg en avatar for denne administrerede bruger.</translation>
 <translation id="2776026170754897883">Deling af skrivebord – <ph name="APP_NAME"/></translation>
 <translation id="839736845446313156">Registrer</translation>
 <translation id="2660779039299703961">Hændelse</translation>
@@ -1395,9 +1398,9 @@
  • gennemse websites, som den administrerede bruger har besøgt, og
  • administrere andre indstillinger.
 
-Der oprettes ikke automatisk en Google-konto, når du opretter en administreret bruger, og indstillinger og data for denne person følger ikke automatisk med på andre enheder med Chrome-synkronisering. Den administrerede bruger gælder i øjeblikket kun for denne installation af Chrome på denne enhed
+Der oprettes ikke automatisk en Google-konto, når du opretter en administreret bruger, og indstillinger og data for denne person følger ikke automatisk med på andre enheder med Chrome-synkronisering. Den administrerede bruger gælder i øjeblikket kun for denne installation af Chrome på denne enhed.
       
-Når du har oprettet en ny administreret bruger, kan du administrere indstillingerne for brugeren når som helst og hvor som helst på www.chrome.com/manage.</translation>
+Når du har oprettet en ny administreret bruger, kan du altid administrere indstillingerne for brugeren på www.chrome.com/manage.</translation>
 <translation id="2409527877874991071">Angiv et nyt navn</translation>
 <translation id="4240069395079660403"><ph name="PRODUCT_NAME"/> kan ikke vises på dette sprog</translation>
 <translation id="747114903913869239">Fejl: Udvidelsen kunne ikke afkodes</translation>
@@ -1591,6 +1594,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamesisk</translation>
 <translation id="6423064450797205562">Målinger af den hastighed, hvormed <ph name="SHORT_PRODUCT_NAME"/> udfører de anmodede handlinger</translation>
+<translation id="2048118585307365263">Aktivér MediaDrm.</translation>
 <translation id="4091434297613116013">ark papir</translation>
 <translation id="7475671414023905704">Netscape-webadresse til mistet adgangskode</translation>
 <translation id="3335947283844343239">Åbn lukket fane igen</translation>
@@ -1628,7 +1632,7 @@
 <translation id="3029595853063638932">Genererer virtuelt kort til Google Wallet...</translation>
 <translation id="1354868058853714482">Adobe Reader er forældet og er muligvis ikke sikkert.</translation>
 <translation id="6146204502384987450">Indlæsningen blev udpakket...</translation>
-<translation id="3925083541997316308">Applikationer og udvidelser kan ikke ændres af overvågede brugere.</translation>
+<translation id="3925083541997316308">Applikationer og udvidelser kan ikke ændres af administrerede brugere.</translation>
 <translation id="2317808232945809">Kopieringen mislykkedes. Elementet findes: &quot;$1&quot;</translation>
 <translation id="8425755597197517046">Ind&amp;sæt og søg</translation>
 <translation id="6341850831632289108">Find din fysiske placering</translation>
@@ -1851,7 +1855,7 @@
 <translation id="4479812471636796472">Amerikansk (Dvorak) tastatur</translation>
 <translation id="8774379383902544371">Få adgang til USB-enheder</translation>
 <translation id="8673026256276578048">Søg på nettet ...</translation>
-<translation id="2969972665754920929">Applikationer og udvidelser må ikke ændres af overvågede brugere. Apps Developers Tools lukkes.</translation>
+<translation id="2969972665754920929">Applikationer og udvidelser må ikke ændres af administrerede brugere. Apps Developers Tools lukkes.</translation>
 <translation id="149347756975725155">Udvidelsesikonet '<ph name="ICON"/>' kunne ikke indlæses.</translation>
 <translation id="3011362742078013760">Åbn alle bogmærker i &amp;inkognitovindue</translation>
 <translation id="3009300415590184725">Er du sikker på, at du vil annullere konfigurationen af en mobildatatjeneste?</translation>
@@ -1886,7 +1890,7 @@
 <translation id="3058212636943679650">Hvis du skulle få brug for at genoprette din computers operativsystem, skal du bruge et SD-kort til genoprettelse eller en USB-nøgle.</translation>
 <translation id="7238196028794870999">Fortsæt tilladelse af ikke-sandboxede plugins</translation>
 <translation id="7252661675567922360">Indlæs ikke</translation>
-<translation id="1983959805486816857">Når du har oprettet en ny overvåget bruger, kan du når som helst administrere indstillingerne på en hvilken som helst enhed på <ph name="MANAGEMENT_URL"/>.</translation>
+<translation id="1983959805486816857">Når du har oprettet en ny administreret bruger, kan du når som helst administrere indstillingerne på en hvilken som helst enhed på <ph name="MANAGEMENT_URL"/>.</translation>
 <translation id="2815382244540487333">Følgende cookies blev blokeret:</translation>
 <translation id="8882395288517865445">Medtag adresser fra min Adressebog</translation>
 <translation id="4891950843328076106">Aktivér HTML Imports</translation>
@@ -2098,7 +2102,7 @@
 <translation id="4131410914670010031">Sort/hvid</translation>
 <translation id="3800503346337426623">Spring login over, og anvend som gæst</translation>
 <translation id="2615413226240911668">Denne side indeholder dog andre ressourcer, der ikke er sikre. Disse ressourcer kan ses af andre under transporten, og de kan her ændres af en ondsindet part, så sidens udseende og opførsel kan blive forvansket.</translation>
-<translation id="1416136326154112077">Indstillinger og browserhistorik for denne overvågede bruger kan muligvis stadig ses af administratoren for <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>.</translation>
+<translation id="1416136326154112077">Indstillinger og browserhistorik for denne administrerede bruger kan muligvis stadig ses af administratoren på <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>.</translation>
 <translation id="197288927597451399">Behold</translation>
 <translation id="5880867612172997051">Netværksadgangen er suspenderet</translation>
 <translation id="5495466433285976480">Dette vil fjerne alle lokale brugere, filer, data og andre indstillinger, når du genstarter næste gang. Alle brugere skal logge ind igen.</translation>
@@ -2234,7 +2238,7 @@
 <translation id="3898521660513055167">Status for token</translation>
 <translation id="1950295184970569138">* Google-profilfoto (indlæser)</translation>
 <translation id="8063491445163840780">Aktiver fane 4</translation>
-<translation id="7939997691108949385">Administratoren kan konfigurere begrænsninger og indstillinger for den overvågede bruger på <ph name="MANAGEMENT_URL"/>.</translation>
+<translation id="7939997691108949385">Administratoren kan konfigurere begrænsninger og indstillinger for den administrerede bruger på <ph name="MANAGEMENT_URL"/>.</translation>
 <translation id="2322193970951063277">Sidehoveder og -fødder</translation>
 <translation id="6436164536244065364">Vis i Webshop</translation>
 <translation id="9137013805542155359">Vis oprindelig</translation>
@@ -2471,7 +2475,7 @@
 <translation id="5094721898978802975">Kommuniker med indbyggede applikationer</translation>
 <translation id="1077946062898560804">Konfigurer automatiske opdateringer for alle brugere</translation>
 <translation id="3122496702278727796">Oprettelsen af datamappe mislykkedes</translation>
-<translation id="6690751852586194791">Vælg en overvåget bruger, der skal føjes til denne enhed.</translation>
+<translation id="6690751852586194791">Vælg en administreret bruger, der skal føjes til denne enhed.</translation>
 <translation id="6990081529015358884">Der er ikke mere plads</translation>
 <translation id="350945665292790777">Bruger GPU-accelereret sammensætning på alle sider, ikke kun dem, der omfatter GPU-accelererede lag.</translation>
 <translation id="5273628206174272911">Eksperimentel funktion, der muliggør vandret rulning i historikken.</translation>
@@ -2552,7 +2556,7 @@
 <translation id="8382913212082956454">Kopier &amp;e-mailadresse</translation>
 <translation id="7447930227192971403">Aktiver fane 3</translation>
 <translation id="3010559122411665027">Angiv posten &quot;<ph name="ENTRY_INDEX"/>&quot;: <ph name="ERROR"/></translation>
-<translation id="134260045699141506">Dette er en overvåget bruger, som vil blive administreret af dig.
+<translation id="134260045699141506">Dette er en administreret bruger, som vil blive administreret af dig.
 Du skal være logget ind, før du kan bruge denne funktion.</translation>
 <translation id="2903493209154104877">Adresser</translation>
 <translation id="3479552764303398839">Ikke nu</translation>
@@ -2734,7 +2738,7 @@
 <translation id="7870278953869613713">Start Hangout</translation>
 <translation id="8915370057835397490">Indlæser forslag</translation>
 <translation id="1511623662787566703">Logget ind som <ph name="USER_EMAIL_ADDRESS"/>. Synkronisering er blevet stoppet via Google Betjeningspanel.</translation>
-<translation id="4352333825734680558">Hov! Den nye overvågede bruger kunne ikke oprettes. Kontrollér din netværksforbindelse, og prøv igen senere.</translation>
+<translation id="4352333825734680558">Hov! Den nye administrerede bruger kunne ikke oprettes. Kontrollér din netværksforbindelse, og prøv igen senere.</translation>
 <translation id="8496133838154739422">(Opdaterer siden automatisk hvert <ph name="INTERVAL_SECONDS"/>. sekund).</translation>
 <translation id="174773101815569257">Muselås</translation>
 <translation id="2790759706655765283">Udgivers officielle webside</translation>
@@ -2857,7 +2861,7 @@
 <translation id="2912905526406334195"><ph name="HOST"/> ønsker at bruge din mikrofon.</translation>
 <translation id="2805756323405976993">Applikationer</translation>
 <translation id="1608626060424371292">Fjern denne bruger</translation>
-<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> er blevet oprettet som en overvåget bruger.</translation>
+<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> er blevet oprettet som en administreret bruger.</translation>
 <translation id="3651020361689274926">Den anmodede ressource findes ikke længere, og der findes ingen adresse til videresendelse. Dette forventes at være en varig tilstand.</translation>
 <translation id="7541236596838501870">Uploadede WebRTC-logfiler (<ph name="WEBRTC_LOG_COUNT"/>)</translation>
 <translation id="6003284010415283671">Tilføj apps</translation>
@@ -2870,13 +2874,13 @@
 <translation id="7525067979554623046">Opret</translation>
 <translation id="4853020600495124913">Åbn i &amp;nyt vindue</translation>
 <translation id="6847758263950452722">Gem side som MHTML</translation>
-<translation id="4217998989792742258">Dette er en overvåget bruger, der administreres af <ph name="CUSTODIAN_EMAIL"/></translation>
+<translation id="4217998989792742258">Dette er en administreret bruger, der administreres af <ph name="CUSTODIAN_EMAIL"/></translation>
 <translation id="4711094779914110278">Tyrkisk</translation>
 <translation id="5121130586824819730">Din harddisk er fuld. Gem til en anden placering, eller frigør mere plads på harddisken.</translation>
 <translation id="7643802497509977994">Skift tilbage til &quot;<ph name="FROM_LOCALE"/>&quot; (kræver, at du logger ud)</translation>
 <translation id="1875987452136482705">Denne valgmulighed deaktiverer understøttelse i WebRTC for afkodning af videostream via platformhardware.</translation>
-<translation id="6164005077879661055">Alle filer og lokale data, der er knyttet til den overvågede bruger, 
-slettes permanent, når den overvågede bruger fjernes. Besøgte websites og indstillinger for denne overvågede bruger er muligvis stadig synlige for administratoren på <ph name="MANAGEMENT_URL"/>.</translation>
+<translation id="6164005077879661055">Alle filer og lokale data, der er knyttet til den administrerede bruger, 
+slettes permanent, når den administrerede bruger fjernes. Besøgte websites og indstillinger for denne administrerede bruger er muligvis stadig synlige for administratoren på <ph name="MANAGEMENT_URL"/>.</translation>
 <translation id="1031460590482534116">Der opstod en fejl under forsøg på at gemme klientcertifikatet. Fejl <ph name="ERROR_NUMBER"/> (<ph name="ERROR_NAME"/>).</translation>
 <translation id="7296774163727375165">Vilkår for <ph name="DOMAIN"/></translation>
 <translation id="25597840138324075">Inkognitodownload er i gang</translation>
@@ -2937,7 +2941,7 @@
 <translation id="2319236583141234177">Kontrollér dine DNS-indstillinger.</translation>
 <translation id="114140604515785785">Udvidelsens rodmappe:</translation>
 <translation id="6664237456442406323">Din computer er desværre konfigureret med et hardware-id i forkert format. Dette forhindrer Chrome OS i at opdatere med de nyeste sikkerhedsrettelser, og din computer <ph name="BEGIN_BOLD"/>kan være sårbar over for ondartede angreb<ph name="END_BOLD"/>.</translation>
-<translation id="785160701896930981">En overvåget bruger ved navn <ph name="NEW_PROFILE_NAME"/> er blevet oprettet. Du kan angive, hvilke websites denne bruger skal kunne se, ved at konfigurere begrænsninger og indstillinger på <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Hvis du ikke ændrer standardindstillingerne, kan <ph name="NEW_PROFILE_NAME"/> gennemse alle websites på nettet.
+<translation id="785160701896930981">Der er nu oprettet en administreret bruger ved navn <ph name="NEW_PROFILE_NAME"/>. Du kan angive, hvilke websites denne bruger skal kunne se, ved at konfigurere begrænsninger og indstillinger på <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Hvis du ikke ændrer standardindstillingerne, kan <ph name="NEW_PROFILE_NAME"/> besøge alle websites på nettet.
 
 Tjek din e-mail på <ph name="ACCOUNT_EMAIL"/> for at se denne og flere vejledninger.</translation>
 <translation id="8493236660459102203">Mikrofon:</translation>
@@ -3010,7 +3014,7 @@
 <translation id="6739254200873843030">Kortet er udløbet. Kontrollér datoen, eller angiv et nyt kort.</translation>
 <translation id="8793043992023823866">Import...</translation>
 <translation id="8106211421800660735">Kreditkortnummer</translation>
-<translation id="8843709518995654957"><ph name="LINK_START"/>Opret en overvåget bruger<ph name="LINK_END"/> for denne enhed.</translation>
+<translation id="8843709518995654957"><ph name="LINK_START"/>Opret en administreret bruger<ph name="LINK_END"/> for denne enhed.</translation>
 <translation id="2872961005593481000">Luk</translation>
 <translation id="8986267729801483565">Download-placering:</translation>
 <translation id="7021076338299963900">Adresse (valgfri)</translation>
@@ -3068,7 +3072,7 @@
 <translation id="6116921718742659598">Rediger indstillingerne for sprog og indtastning</translation>
 <translation id="4365673000813822030">Ups, synkroniseringen fungerer ikke.</translation>
 <translation id="7026338066939101231">Reducer</translation>
-<translation id="5875858680971105888">Hov! Den overvågede bruger kunne ikke importeres. Kontrollér din netværksforbindelse, og prøv igen senere.</translation>
+<translation id="5875858680971105888">Hov! Den administrerede bruger kunne ikke importeres. Kontrollér din netværksforbindelse, og prøv igen senere.</translation>
 <translation id="5411472733320185105">Brug ikke proxyindstillingerne til disse værter eller domæner:</translation>
 <translation id="7358682983403815415">Åbne faner, bogmærker, historik m.m. er ved at blive synkroniseret med din Google-konto.</translation>
 <translation id="3685121001045880436">Der er muligvis sket en overbelastning af den server, som hoster websiden, eller der er opstået en fejl.
@@ -3085,7 +3089,7 @@
 <translation id="6691936601825168937">&amp;Frem</translation>
 <translation id="6566142449942033617">'<ph name="PLUGIN_PATH"/>' til plugin kunne ikke indlæses.</translation>
 <translation id="7299337219131431707">Aktivér gæstesession</translation>
-<translation id="2312980885338881851">Hov! Det ser ud til, at du ikke har nogen eksisterende overvågede bruger, der kan importeres. Opret en eller flere fra en anden enhed, så du kan importere dem her.</translation>
+<translation id="2312980885338881851">Hov! Det ser ud til, at du ikke har nogen eksisterende administrerede bruger, der kan importeres. Opret en eller flere fra en anden enhed, så du kan importere dem her.</translation>
 <translation id="6823506025919456619">Du skal logge ind på Chrome for at se dine enheder</translation>
 <translation id="7065534935986314333">Om systemet</translation>
 <translation id="4691088804026137116">Synkroniser ingenting</translation>
@@ -3145,7 +3149,7 @@
 <translation id="6615455863669487791">Vis mig</translation>
 <translation id="3543393733900874979">Opdateringen mislykkedes (fejl: <ph name="ERROR_NUMBER"/>)</translation>
 <translation id="1017280919048282932">&amp;Tilføj til ordbog</translation>
-<translation id="3534879087479077042">Hvad er en overvåget bruger?</translation>
+<translation id="3534879087479077042">Hvad er en administreret bruger?</translation>
 <translation id="7211828883345145708">Aktiverer yderligere tastaturgenveje, der er nyttige i forbindelse med fejlretning i Chromium.</translation>
 <translation id="8319414634934645341">Udvidet brug af nøgle</translation>
 <translation id="6056710589053485679">Almindelig genindlæsning</translation>
@@ -3355,14 +3359,14 @@
 <translation id="5832669303303483065">Tilføj ny adresse...</translation>
 <translation id="4516542078385226197">Du kan undgå denne fejl ved at logge ind på din Google-konto
     via loginskærmen. Du kan derefter logge ud af din Google-konto og
-    prøve at oprette en overvåget bruger igen.</translation>
+    prøve at oprette en administreret bruger igen.</translation>
 <translation id="3127919023693423797">Godkender...</translation>
 <translation id="3712624925041724820">Licenserne er opbrugt</translation>
 <translation id="4195643157523330669">Åbn i ny fane</translation>
 <translation id="8030169304546394654">Afbrudt</translation>
 <translation id="6672789615126913676">Forbrug og historik for denne bruger kan gennemgås af administratoren (<ph name="CUSTODIAN_EMAIL"/>) på chrome.com.</translation>
 <translation id="4010065515774514159">Browserhandling</translation>
-<translation id="7295019613773647480">Aktivér overvågede brugere</translation>
+<translation id="7295019613773647480">Aktivér administrerede brugere</translation>
 <translation id="2893389635995517838">Få adgang til billeder, musik og andre medier på din computer</translation>
 <translation id="3529423920239848704">Forekomster, hvor <ph name="SHORT_PRODUCT_NAME"/> ikke lukkede korrekt</translation>
 <translation id="7022562585984256452">Din startside er blevet konfigureret.</translation>
@@ -3585,7 +3589,7 @@
 <translation id="2750518858905599015"><ph name="SHORT_PRODUCT_NAME"/> er opdateret</translation>
 <translation id="7554791636758816595">Ny fane</translation>
 <translation id="3630337581925712713"><ph name="PERMISSION_TYPE_LABEL"/>:</translation>
-<translation id="2740393541869613458">gennemse de websites, som den overvågede bruger har besøgt, og</translation>
+<translation id="2740393541869613458">gennemse de websites, som den administrerede bruger har besøgt, og</translation>
 <translation id="1114091355035739006">Brug medianerne til at minimere outliereffekten i effektivitetsdata</translation>
 <translation id="3330616135759834145">Der er modtaget flere overskrifter med indholdsdisposition. Dette er ikke tilladt for at beskytte mod angreb med opdeling af HTTP-svar.</translation>
 <translation id="6032183131938659321">Timing</translation>
@@ -3608,7 +3612,7 @@
 <translation id="760537465793895946">Undersøg kendte konflikter med tredjepartsmoduler</translation>
 <translation id="1640180200866533862">Brugerpolitikker</translation>
 <translation id="7042418530779813870">Indsæt og søg</translation>
-<translation id="1794054777407898860">Denne bruger er overvåget.</translation>
+<translation id="1794054777407898860">Denne bruger er administreret.</translation>
 <translation id="9110447413660189038">&amp;Op</translation>
 <translation id="5026874946691314267">Vis ikke denne underretning igen</translation>
 <translation id="375403751935624634">Oversættelsen mislykkedes på grund af en serverfejl.</translation>
@@ -3835,6 +3839,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vil gemme store mængder data permanent på din lokale computer.</translation>
 <translation id="373572798843615002">1 fane</translation>
 <translation id="4806065163318322702">Slå taleinput til/fra</translation>
+<translation id="6190185222845843088">Brug Wallet-sandboxservere</translation>
 <translation id="3177048931975664371">Klik for at skjule adgangskode</translation>
 <translation id="5852137567692933493">Genstart og Powerwash</translation>
 <translation id="3092544800441494315">Medtag dette skærmbillede:</translation>
@@ -3960,7 +3965,7 @@
 <translation id="6681668084120808868">Tag billede</translation>
 <translation id="1368265273904755308">Rapportér problem</translation>
 <translation id="780301667611848630">Nej tak</translation>
-<translation id="8209677645716428427">En overvåget bruger kan søge på nettet med din hjælp. Som administrator for en overvåget bruger i Chrome kan du:</translation>
+<translation id="8209677645716428427">En administreret bruger kan søge på nettet med din hjælp. Som administrator for en administreret bruger i Chrome kan du:</translation>
 <translation id="2812989263793994277">Vis ikke billeder</translation>
 <translation id="722363467515709460">Aktivér skærmforstørrer</translation>
 <translation id="7190251665563814471">Tillad altid disse plugins på <ph name="HOST"/></translation>
@@ -4101,6 +4106,7 @@
 <translation id="1639239467298939599">Indlæser...</translation>
 <translation id="5457599981699367932">Gennemse som gæst</translation>
 <translation id="6850233365366645553">En genstart er nødvendig, før enheden kan nulstilles med Powerwash. En Powerwash nulstiller din <ph name="IDS_SHORT_PRODUCT_NAME"/>-enhed, så den bliver som ny.</translation>
+<translation id="4292622557427736684">Aktivér MediaDrm som standard for Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Vælg farve</translation>
 <translation id="5089363139417863686">Vis med appen Filer</translation>
 <translation id="7047998246166230966">Markør</translation>
@@ -4235,7 +4241,7 @@
 <translation id="943803541173786810">Aktivér synkronisering af favoritikon.</translation>
 <translation id="8735794438432839558">Du skal oprette forbindelse til internettet for at kunne logge ind på din Chromebook.</translation>
 <translation id="7939412583708276221">Behold alligevel</translation>
-<translation id="8140778357236808512">Importér en eksisterende overvåget bruger</translation>
+<translation id="8140778357236808512">Importér en eksisterende administreret bruger</translation>
 <translation id="6953992620120116713">HTTPS via eksperimentel QUIC-protokol.</translation>
 <translation id="8737260648576902897">Installer Adobe Reader</translation>
 <translation id="7876243839304621966">Fjern alt</translation>
@@ -4251,7 +4257,7 @@
 <translation id="1248269069727746712"><ph name="PRODUCT_NAME"/> anvender proxyindstillingerne fra din enheds system til at oprette forbindelse til netværket.</translation>
 <translation id="3467267818798281173">Bed Google om forslag</translation>
 <translation id="5155386449991325895">Deaktiver oversigtstilstand.</translation>
-<translation id="8982248110486356984">Skift brugere</translation>
+<translation id="8982248110486356984">Skift bruger</translation>
 <translation id="7649070708921625228">Hjælp</translation>
 <translation id="858637041960032120">Tilføj tlf.nr.
 </translation>
@@ -4450,6 +4456,7 @@
 <translation id="1728442818359004787">Skift standardapp...</translation>
 <translation id="7540972813190816353">Der opstod en fejl ved søgning efter opdateringer: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Ikke-understøttet Bluetooth-enhed: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Deaktiver Media Source API uden præfiks.</translation>
 <translation id="2225024820658613551">Du bør ikke fortsætte, &lt;strong&gt;især ikke&lt;/strong&gt; hvis du ikke tidligere har fået denne advarsel for dette website.</translation>
 <translation id="2049639323467105390">Denne enhed administreres af <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Ikke før</translation>
@@ -4659,7 +4666,7 @@
 <translation id="5170477580121653719">Ledig plads på Google Drev: <ph name="SPACE_AVAILABLE"/>.</translation>
 <translation id="4114470632216071239">Lås SIM-kort (kræv PIN-kode for at bruge mobildata)</translation>
 <translation id="6581162200855843583">Link til Google Drev</translation>
-<translation id="5783221160790377646">En overvåget bruger kunne ikke oprettes på grund af en fejl. Prøv igen senere.</translation>
+<translation id="5783221160790377646">En administreret bruger kunne ikke oprettes på grund af en fejl. Prøv igen senere.</translation>
 <translation id="340771324714262530">Stop spejling</translation>
 <translation id="3303260552072730022">En udvidelse har udløst fuld skærm.</translation>
 <translation id="1021323901059345250">Dine data kan være gået tabt eller være blevet beskadiget. Næste gang skal du klikke på ikonet Skub ud i appen Filer, før du fjerner din enhed.</translation>
@@ -4763,7 +4770,7 @@
 <translation id="1981905533439890161">Bekræft ny app</translation>
 <translation id="7717014941119698257">Downloader: <ph name="STATUS"/></translation>
 <translation id="2785530881066938471">Filen '<ph name="RELATIVE_PATH"/>' til indholdsscript kunne ikke indlæses. Det er ikke UTF-8-kodet.</translation>
-<translation id="8744525654891896746">Vælg en avatar for denne overvågede bruger</translation>
+<translation id="8744525654891896746">Vælg en avatar for denne administrerede bruger</translation>
 <translation id="3807747707162121253">&amp;Annuller</translation>
 <translation id="2740531572673183784">OK</translation>
 <translation id="202352106777823113">Overførslen tog for lang tid og blev stoppet af netværket.</translation>
@@ -5018,7 +5025,7 @@
 <translation id="5228076606934445476">Der er noget galt med enheden. Du skal genstarte enheden og prøve igen for at undgå denne fejl.</translation>
 <translation id="2273562597641264981">Operatør:</translation>
 <translation id="122082903575839559">Algoritme for certifikatsignatur</translation>
-<translation id="9013587737291179248">Hov! Den overvågede bruger kunne ikke importeres. Kontrollér, om der er ledig plads på din harddisk, og at du har de rette tilladelser, og prøv igen.</translation>
+<translation id="9013587737291179248">Hov! Den administrerede bruger kunne ikke importeres. Kontrollér, om der er ledig plads på din harddisk, og at du har de rette tilladelser, og prøv igen.</translation>
 <translation id="4462159676511157176">Tilpassede navneservere</translation>
 <translation id="4575703660920788003">Tryk på Shift+Alt for at skifte tastaturlayout</translation>
 <translation id="7240120331469437312">Alternativt navn på certifikatemne</translation>
@@ -5027,7 +5034,7 @@
 <translation id="8509646642152301857">Download af ordbog til stavekontrol mislykkedes.</translation>
 <translation id="1161575384898972166">Log ind på <ph name="TOKEN_NAME"/> for at eksportere klientcertifikatet.</translation>
 <translation id="1718559768876751602">Opret en Google-konto nu</translation>
-<translation id="2731710757838467317">Din overvågede bruger oprettes. Dette kan tage et øjeblik.</translation>
+<translation id="2731710757838467317">Din administrerede bruger oprettes. Dette kan tage et øjeblik.</translation>
 <translation id="1884319566525838835">Sandkassestatus</translation>
 <translation id="2770465223704140727">Fjern fra listen</translation>
 <translation id="8314013494437618358">Trådet sammensætning</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 112f60f..ab6eec8 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Rechtschreibung und Grammatik einblenden</translation>
 <translation id="7017587484910029005">Geben Sie die Zeichen aus dem angezeigten Bild ein.</translation>
 <translation id="9013589315497579992">Ungültiges Zertifikat für SSL-Clientauthentifizierung</translation>
+<translation id="2085245445866855859">App mit Manifest-Attribut &quot;kiosk_only&quot; muss im Chrome OS-Kioskmodus installiert werden.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> möchte Daten dauerhaft auf Ihrem Gerät speichern.</translation>
 <translation id="8524066305376229396">Permanentspeicher:</translation>
 <translation id="7567293639574541773">Element u&amp;ntersuchen</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fußball</translation>
 <translation id="2231238007119540260">Wenn Sie ein Serverzertifikat löschen, werden die üblichen Sicherheitsprüfungen für den jeweiligen Server wieder aktiviert und es muss ein gültiges Zertifikat verwendet werden.</translation>
 <translation id="9110235431257073974">Integration von WebStore und Files.app aktivieren</translation>
+<translation id="6489433341782457580">Für Entwickler: Verwenden Sie den Sandbox-Dienst für Wallet API-Aufrufe für requestAutocomplete().</translation>
 <translation id="8186609076106987817">Die Datei konnte nicht gefunden werden.</translation>
 <translation id="2846816712032308263">Aktiviert schnelles Schließen von Tabs und Fenstern – führt den onunload-JS-Handler eines Tabs unabhängig von der GUI aus</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> konnte die Webseite nicht laden, weil <ph name="HOST_NAME"/> zu lange zum Antworten benötigt. Möglicherweise ist die Website inaktiv oder es gibt Probleme mit Ihrer Internetverbindung.</translation>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">Der betreute Nutzer benötigt dieses Passwort für die Anmeldung. Achten Sie darauf, ein sicheres Passwort auszuwählen und es dem betreuten Nutzer mitzuteilen.</translation>
 <translation id="5154917547274118687">Speicher</translation>
 <translation id="1493492096534259649">Diese Sprache kann nicht für die Rechtschreibprüfung verwendet werden.</translation>
+<translation id="2103866351350079276">Das MediaSource-Objekt ohne Präfix wird deaktiviert. Über dieses Objekt kann JavaScript Mediendaten direkt an das Videoelement senden.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/>-Suche</translation>
 <translation id="6460423884798879930">Aktiviert die Option zum Senden zusätzlicher Authentifizierungsinformationen im ersten SYN-Paket für Clients, zu denen bereits eine Verbindung bestand. Dadurch beginnt das Senden der Daten schneller.</translation>
 <translation id="6563261555270336410">Details zu <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1580,6 +1583,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamesisch</translation>
 <translation id="6423064450797205562">Messwerte in Bezug auf die Geschwindigkeit, mit der <ph name="SHORT_PRODUCT_NAME"/> die geforderten Aktionen durchführt</translation>
+<translation id="2048118585307365263">MediaDrm aktivieren</translation>
 <translation id="4091434297613116013">Blatt Papier</translation>
 <translation id="7475671414023905704">Netscape-URL für vergessene Passwörter</translation>
 <translation id="3335947283844343239">Geschlossenen Tab wieder öffnen</translation>
@@ -3802,6 +3806,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> möchte umfangreiche Daten dauerhaft auf Ihrem lokalen Computer speichern.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">Spracheingabe starten/beenden</translation>
+<translation id="6190185222845843088">Wallet-Sandbox-Server verwenden</translation>
 <translation id="3177048931975664371">Hier klicken, um Passwort zu verbergen</translation>
 <translation id="5852137567692933493">Neu starten und Powerwash durchführen</translation>
 <translation id="3092544800441494315">Diesen Screenshot einfügen:</translation>
@@ -4068,6 +4073,7 @@
 <translation id="1639239467298939599">Wird geladen...</translation>
 <translation id="5457599981699367932">Als Gast nutzen</translation>
 <translation id="6850233365366645553">Ihr Gerät muss neu gestartet werden, damit es per Powerwash zurückgesetzt werden kann. Durch die Powerwash-Funktion wird der Werkszustand Ihres <ph name="IDS_SHORT_PRODUCT_NAME"/>-Geräts wieder hergestellt.</translation>
+<translation id="4292622557427736684">MediaDrm standardmäßig für verschlüsselte Medienerweiterungen aktivieren</translation>
 <translation id="1812514023095547458">Farbe auswählen</translation>
 <translation id="5089363139417863686">Mit der App &quot;Dateien&quot; ansehen</translation>
 <translation id="7047998246166230966">Mauszeiger</translation>
@@ -4418,6 +4424,7 @@
 <translation id="1728442818359004787">Standard-App ändern...</translation>
 <translation id="7540972813190816353">Fehler beim Suchen nach Updates: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nicht unterstütztes Bluetooth-Gerät: &quot;<ph name="DEVICE_NAME"/>&quot;</translation>
+<translation id="2990212470195050777">MediaSource API ohne Präfix deaktivieren</translation>
 <translation id="2225024820658613551">Fahren Sie nicht fort, &lt;strong&gt;insbesondere&lt;/strong&gt; wenn diese Warnung für diese Website vorher noch nie erschienen ist.</translation>
 <translation id="2049639323467105390">Dieses Gerät wird durch <ph name="DOMAIN"/> verwaltet.</translation>
 <translation id="1932098463447129402">Nicht vor</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb
index 78d0b99..6aefcb1 100644
--- a/chrome/app/resources/generated_resources_el.xtb
+++ b/chrome/app/resources/generated_resources_el.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Εμφάνιση Ορθογραφικού και Γραμματικού Ελέγχου</translation>
 <translation id="7017587484910029005">Πληκτρολογήστε τους χαρακτήρες που βλέπετε στην εικόνα παρακάτω.</translation>
 <translation id="9013589315497579992">Ακατάλληλο πιστοποιητικό ελέγχου ταυτότητας πελάτη SSL.</translation>
+<translation id="2085245445866855859">Θα πρέπει να εγκατασταθεί μια εφαρμογή με χαρακτηριστικό μανιφέστου &quot;kiosk_only&quot; στη λειτουργία kiosk του ChromeOS.</translation>
 <translation id="1467999917853307373">Ο ιστότοπος <ph name="URL"/> θέλει να αποθηκεύσει μόνιμα δεδομένα στη συσκευή σας.</translation>
 <translation id="8524066305376229396">Μόνιμος χώρος αποθήκευσης:</translation>
 <translation id="7567293639574541773">Επι&amp;θεώρηση στοιχείου</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Εάν διαγράψετε ένα πιστοποιητικό διακομιστή, θα επαναφέρετε τους συνήθεις ελέγχους ασφαλείας για αυτό το διακομιστή και θα απαιτείται η χρήση ενός έγκυρου πιστοποιητικού.</translation>
 <translation id="9110235431257073974">Ενεργοποίηση της ενοποίησης του Webstore και της εφαρμογής Αρχεία.</translation>
+<translation id="6489433341782457580">Για προγραμματιστές: χρησιμοποιήστε την υπηρεσία περιβάλλοντος δοκιμών για κλήσεις API Πορτοφολιού για την παράμετρο requestAutocomplete().</translation>
 <translation id="8186609076106987817">Δεν ήταν δυνατός ο εντοπισμός του αρχείου από τον διακομιστή.</translation>
 <translation id="2846816712032308263">Ενεργοποιεί το γρήγορο κλείσιμο καρτέλας/παραθύρου - εκτελεί το δείκτη χειρισμού onunload js μιας καρτέλας ανεξάρτητα από το GUI.</translation>
 <translation id="9134410174832249455">Το <ph name="PRODUCT_NAME"/> δεν μπόρεσε να φορτώσει την ιστοσελίδα επειδή ο ιστότοπος <ph name="HOST_NAME"/> άργησε πολύ να ανταποκριθεί.  Ο ιστότοπος ενδέχεται να βρίσκεται εκτός λειτουργίας ή να αντιμετωπίζετε προβλήματα με τη σύνδεσή σας στο Διαδίκτυο.</translation>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">Ο εποπτευόμενος χρήστης θα πρέπει να χρησιμοποιεί αυτόν τον κωδικό πρόσβασης για να συνδέεται, επομένως επιλέξτε έναν ασφαλή κωδικό πρόσβαση και φροντίστε να συζητήσετε τυχόν θέματα ασφαλείας με τον εποπτευόμενο χρήστη.</translation>
 <translation id="5154917547274118687">Μνήμη</translation>
 <translation id="1493492096534259649">Δεν είναι δυνατή η χρήση αυτής της γλώσσας για ορθογραφικό έλεγχο</translation>
+<translation id="2103866351350079276">Απενεργοποίηση αντικειμένου MediaSource χωρίς πρόθεμα. Αυτό το αντικείμενο επιτρέπει την εκτέλεση JavaScript για αποστολή δεδομένων μέσων απευθείας σε ένα στοιχείο βίντεο.</translation>
 <translation id="6628463337424475685">Αναζήτηση <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Ενεργοποιήστε την επιλογή για να αποστείλετε επιπλέον πληροφορίες ελέγχου ταυτότητας στο αρχικό πακέτο SYN για έναν πρώην συνδεδεμένο πελάτη, επιτρέποντας την ταχύτερη έναρξη αποστολής δεδομένων.</translation>
 <translation id="6563261555270336410">Λεπτομέρειες σχετικά με <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1593,6 +1596,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Βιετναμέζικα</translation>
 <translation id="6423064450797205562">Μετρήσεις που σχετίζονται με την ταχύτητα με την οποία το <ph name="SHORT_PRODUCT_NAME"/> εκτελεί τις απαιτούμενες ενέργειες</translation>
+<translation id="2048118585307365263">Ενεργοποίηση MediaDrm.</translation>
 <translation id="4091434297613116013">φύλλα χαρτιού</translation>
 <translation id="7475671414023905704">Διεύθυνση URL χαμένου κωδικού πρόσβασης Netscape</translation>
 <translation id="3335947283844343239">Εκ Νέου Άνοιγμα Κλεισμένης Καρτέλας</translation>
@@ -3851,6 +3855,7 @@
 <translation id="3672159315667503033">Ο ιστότοπος <ph name="URL"/> θέλει να αποθηκεύσει μόνιμα δεδομένα μεγάλου όγκου στον τοπικό υπολογιστή σας.</translation>
 <translation id="373572798843615002">1 Καρτέλα</translation>
 <translation id="4806065163318322702">Εναλλαγή εισαγωγής ομιλίας</translation>
+<translation id="6190185222845843088">Χρήση των διακομιστών περιβάλλοντος δοκιμών του Πορτοφολιού</translation>
 <translation id="3177048931975664371">Κάντε κλικ για να αποκρύψετε τον κωδικό πρόσβασης</translation>
 <translation id="5852137567692933493">Επανεκκίνηση και Powerwash</translation>
 <translation id="3092544800441494315">Συμπερίληψη αυτού του στιγμιότυπου οθόνης:</translation>
@@ -4120,6 +4125,7 @@
 <translation id="1639239467298939599">Γίνεται φόρτωση</translation>
 <translation id="5457599981699367932">Περιήγηση ως επισκέπτης</translation>
 <translation id="6850233365366645553">Απαιτείται επανεκκίνηση πριν από την επαναφορά της συσκευής σας με τη λειτουργία Powerwash. Η λειτουργία Powerwash επαναφέρει τη συσκευή σας <ph name="IDS_SHORT_PRODUCT_NAME"/> έτσι ώστε να μοιάζει με καινούρια.</translation>
+<translation id="4292622557427736684">Ενεργοποίηση MediaDrm από προεπιλογή για τις επεκτάσεις κρυπτογραφημένων μέσων.</translation>
 <translation id="1812514023095547458">Επιλογή χρώματος</translation>
 <translation id="5089363139417863686">Προβολή με την εφαρμογή &quot;Αρχεία&quot;</translation>
 <translation id="7047998246166230966">Δείκτης</translation>
@@ -4472,6 +4478,7 @@
 <translation id="1728442818359004787">Αλλαγή προεπιλεγμένης εφαρμογής…</translation>
 <translation id="7540972813190816353">Παρουσιάστηκε σφάλμα κατά τον έλεγχο για ενημερώσεις: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Μη υποστηριζόμενη συσκευή Bluetooth: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Απενεργοποίηση API πηγής μέσων χωρίς πρόθεμα.</translation>
 <translation id="2225024820658613551">Δεν πρέπει να προχωρήσετε, &lt;strong&gt;ιδιαίτερα&lt;/strong&gt; αν δεν έχει εμφανιστεί ποτέ πριν αυτή η προειδοποίηση για το συγκεκριμένο ιστότοπο.</translation>
 <translation id="2049639323467105390">Η διαχείριση της συσκευής γίνεται από τον τομέα <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Όχι πριν από</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index 2b6e2ff..34e0c24 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Show Spelling and Grammar</translation>
 <translation id="7017587484910029005">Type the characters that you see in the picture below.</translation>
 <translation id="9013589315497579992">Bad SSL client-authentication certificate.</translation>
+<translation id="2085245445866855859">App with 'kiosk_only' manifest attribute must be installed in ChromeOS kiosk mode.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> wants to permanently store data on your device.</translation>
 <translation id="8524066305376229396">Persistent Storage:</translation>
 <translation id="7567293639574541773">I&amp;nspect element</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Footy</translation>
 <translation id="2231238007119540260">If you delete a server certificate, you restore the usual security checks for that server and require that it uses a valid certificate.</translation>
 <translation id="9110235431257073974">Enable the integration of Webstore and Files.app.</translation>
+<translation id="6489433341782457580">For developers: use the sandbox service for Wallet API calls for requestAutocomplete().</translation>
 <translation id="8186609076106987817">The server could not find the file.</translation>
 <translation id="2846816712032308263">Enables fast tab/window closing - runs a tab's onunload js handler independently of the GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> could not load the web page because <ph name="HOST_NAME"/> took too long to respond. The website may be down or you may be experiencing issues with your Internet connection.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">The supervised user will need to use this password to sign in, so choose a safe password and remember to discuss it with the supervised user.</translation>
 <translation id="5154917547274118687">Memory</translation>
 <translation id="1493492096534259649">This language cannot be used for spell checking</translation>
+<translation id="2103866351350079276">Disable the unprefixed MediaSource object. This object allows JavaScript to send media data directly to a video element.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Search</translation>
 <translation id="6460423884798879930">Enable the option to send extra authentication information in the initial SYN packet for a previously connected client, allowing faster data send start.</translation>
 <translation id="6563261555270336410">Details about <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1600,6 +1603,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamese</translation>
 <translation id="6423064450797205562">Metrics relating to the speed with which <ph name="SHORT_PRODUCT_NAME"/> performs requested actions</translation>
+<translation id="2048118585307365263">Enable MediaDrm.</translation>
 <translation id="4091434297613116013">sheets of paper</translation>
 <translation id="7475671414023905704">Netscape Lost Password URL</translation>
 <translation id="3335947283844343239">Re-open Closed Tab</translation>
@@ -3848,6 +3852,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> wants to permanently store large data on your local computer.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">Toggle speech input</translation>
+<translation id="6190185222845843088">Use Wallet sandbox servers</translation>
 <translation id="3177048931975664371">Click to hide password</translation>
 <translation id="5852137567692933493">Restart and Powerwash</translation>
 <translation id="3092544800441494315">Include this screenshot:</translation>
@@ -4116,6 +4121,7 @@
 <translation id="1639239467298939599">Loading</translation>
 <translation id="5457599981699367932">Browse as Guest</translation>
 <translation id="6850233365366645553">A restart is required before your device can be reset with Powerwash. A Powerwash resets your <ph name="IDS_SHORT_PRODUCT_NAME"/> device to be just like new.</translation>
+<translation id="4292622557427736684">Enable MediaDrm by default for Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Select Colour</translation>
 <translation id="5089363139417863686">View with the Files app</translation>
 <translation id="7047998246166230966">Pointer</translation>
@@ -4465,6 +4471,7 @@
 <translation id="1728442818359004787">Change default app...</translation>
 <translation id="7540972813190816353">An error occurred while checking for updates: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Unsupported Bluetooth device: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Disable unprefixed Media Source API.</translation>
 <translation id="2225024820658613551">You should not proceed, &lt;strong&gt;especially&lt;/strong&gt; if you have never seen this warning before for this site.</translation>
 <translation id="2049639323467105390">This device is managed by <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Not Before</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 7519849..7996a70 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -131,6 +131,7 @@
 <translation id="1589055389569595240">Mostrar ortografía y gramática</translation>
 <translation id="7017587484910029005">Escribe los caracteres que ves en la imagen a continuación.</translation>
 <translation id="9013589315497579992">Certificado de autenticación de cliente SSL incorrecto</translation>
+<translation id="2085245445866855859">La aplicación con el atributo del manifiesto &quot;kiosk_only&quot; se debe instalar en el modo kiosco del Sistema operativo Chrome.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> quiere almacenar datos de forma permanente en el dispositivo.</translation>
 <translation id="8524066305376229396">Almacenamiento permanente:</translation>
 <translation id="7567293639574541773">I&amp;nspeccionar elemento</translation>
@@ -184,6 +185,7 @@
 <translation id="4858913220355269194">Balón</translation>
 <translation id="2231238007119540260">Al eliminar un certificado de servidor, restableces las verificaciones de seguridad normales para ese servidor, y solicitas que utilice un certificado válido.</translation>
 <translation id="9110235431257073974">Habilitar la integración de Chrome Web Store y la aplicación Archivos</translation>
+<translation id="6489433341782457580">Para programadores: utiliza el servicio de zona de pruebas para las solicitudes de requestAutocomplete() de la API de Wallet.</translation>
 <translation id="8186609076106987817">El servidor no pudo encontrar el archivo.</translation>
 <translation id="2846816712032308263">Permite cerrar rápidamente ventanas o pestañas, ya que ejecuta el controlador onunload de JavaScript de forma independiente de la interfaz gráfica de usuario.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> no ha podido cargar la página web porque <ph name="HOST_NAME"/> ha tardado demasiado en responder. Es posible que el sitio web no esté disponible o que se haya producido algún problema con tu conexión a Internet.</translation>
@@ -341,6 +343,7 @@
 <translation id="8959810181433034287">El usuario supervisado deberá utilizar esta contraseña para acceder, por lo que debes elegir una contraseña segura y comunicársela.</translation>
 <translation id="5154917547274118687">Memoria</translation>
 <translation id="1493492096534259649">No se puede usar este idioma para el corrector ortográfico</translation>
+<translation id="2103866351350079276">Inhabilita el objeto MediaSource sin prefijo. Este objeto permite que JavaScript envíe datos de medios directamente a un elemento de video.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Búsqueda</translation>
 <translation id="6460423884798879930">Habilita la opción de envío de información adicional de autenticación en el paquete SYN inicial de un cliente conectado anteriormente, lo que permite un inicio más rápido del envío de datos.</translation>
 <translation id="6563261555270336410">Información sobre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1577,6 +1580,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Estadísticas relacionadas con la velocidad a la que <ph name="SHORT_PRODUCT_NAME"/> realiza las acciones solicitadas</translation>
+<translation id="2048118585307365263">Habilitar MediaDrm</translation>
 <translation id="4091434297613116013">hojas de papel</translation>
 <translation id="7475671414023905704">URL de contraseña perdida de Netscape</translation>
 <translation id="3335947283844343239">Volver a abrir pestaña cerrada</translation>
@@ -3811,6 +3815,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> desea almacenar de forma permanente los datos de gran tamaño en tu computadora local.</translation>
 <translation id="373572798843615002">1 pestaña</translation>
 <translation id="4806065163318322702">Activar o desactivar la entrada de voz</translation>
+<translation id="6190185222845843088">Utilizar servidores de zona de pruebas de Wallet</translation>
 <translation id="3177048931975664371">Haz clic para ocultar la contraseña</translation>
 <translation id="5852137567692933493">Reiniciar y aplicar Powerwash</translation>
 <translation id="3092544800441494315">Incluir esta captura de pantalla:</translation>
@@ -4077,6 +4082,7 @@
 <translation id="1639239467298939599">Cargando</translation>
 <translation id="5457599981699367932">Navega como invitado</translation>
 <translation id="6850233365366645553">Debes reiniciar tu dispositivo para que pueda restablecerse con Powerwash. Un Powerwash restablece el dispositivo <ph name="IDS_SHORT_PRODUCT_NAME"/> para que quede como nuevo.</translation>
+<translation id="4292622557427736684">Habilita MediaDrm de forma predeterminada para extensiones de medios encriptados.</translation>
 <translation id="1812514023095547458">Seleccionar color</translation>
 <translation id="5089363139417863686">Ver con la aplicación de archivos</translation>
 <translation id="7047998246166230966">Puntero</translation>
@@ -4426,6 +4432,7 @@
 <translation id="1728442818359004787">Cambiar aplicación predeterminada...</translation>
 <translation id="7540972813190816353">Se produjo un error al buscar actualizaciones: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositivo Bluetooth no compatible: &quot;<ph name="DEVICE_NAME"/>&quot;</translation>
+<translation id="2990212470195050777">Inhabilitar la API de fuente de medios sin prefijo</translation>
 <translation id="2225024820658613551">No deberías continuar, &lt;strong&gt;sobre todo&lt;/strong&gt; si no has recibido nunca esta advertencia para este sitio.</translation>
 <translation id="2049639323467105390"><ph name="DOMAIN"/> administra esta cuenta.</translation>
 <translation id="1932098463447129402">No antes</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index 98d7437..08cf9fc 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Mostrar ortografía y gramática</translation>
 <translation id="7017587484910029005">Escribe los caracteres que veas en la imagen que aparece a continuación. </translation>
 <translation id="9013589315497579992">Certificado de autenticación de cliente SSL no válido</translation>
+<translation id="2085245445866855859">La aplicación con el atributo del archivo de manifiesto &quot;kiosk_only&quot; se debe instalar en el modo de kiosco de Chrome OS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> quiere almacenar datos de forma permanente en tu dispositivo.</translation>
 <translation id="8524066305376229396">Almacenamiento permanente:</translation>
 <translation id="7567293639574541773">I&amp;nspeccionar elemento</translation>
@@ -183,6 +184,7 @@
 <translation id="4858913220355269194">Balón</translation>
 <translation id="2231238007119540260">Si eliminas un certificado de servidor, restablecerás las comprobaciones de seguridad habituales de ese servidor y necesitarás que este utilice un certificado válido.</translation>
 <translation id="9110235431257073974">Habilitar la integración de Chrome Web Store en la aplicación Archivos.</translation>
+<translation id="6489433341782457580">Para desarrolladores: utiliza el servicio de zona de pruebas para las llamadas de la API de Wallet para requestAutocomplete().</translation>
 <translation id="8186609076106987817">El servidor no ha podido encontrar el archivo.</translation>
 <translation id="2846816712032308263">Permite cerrar rápidamente ventanas y pestañas, ya que ejecuta el controlador onunload de JavaScript de forma independiente a la interfaz gráfica de usuario.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -355,6 +357,7 @@
 <translation id="8959810181433034287">El usuario supervisado deberá utilizar esta contraseña para iniciar sesión, por lo que debes seleccionar una contraseña segura que deberás comunicar al usuario supervisado.</translation>
 <translation id="5154917547274118687">Memoria</translation>
 <translation id="1493492096534259649">Este idioma no se puede utilizar para el corrector ortográfico.</translation>
+<translation id="2103866351350079276">Inhabilita el objeto MediaSource sin prefijo. Este objeto permite que JavaScript envíe datos de medios directamente a un elemento de vídeo.</translation>
 <translation id="6628463337424475685">Búsqueda de <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Permite habilitar la opción de envío de información adicional de autenticación en el paquete SYN inicial de un cliente conectado previamente, lo que permite que el envío de datos se inicie más rápido.</translation>
 <translation id="6563261555270336410">Información sobre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1591,6 +1594,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Estadísticas relacionadas con la velocidad a la que <ph name="SHORT_PRODUCT_NAME"/> realiza las acciones solicitadas</translation>
+<translation id="2048118585307365263">Habilitar MediaDrm.</translation>
 <translation id="4091434297613116013">hojas de papel</translation>
 <translation id="7475671414023905704">URL de contraseñas perdidas de Netscape</translation>
 <translation id="3335947283844343239">Volver a abrir pestaña cerrada</translation>
@@ -3838,6 +3842,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> quiere almacenar datos de gran tamaño de forma permanente en tu ordenador local.</translation>
 <translation id="373572798843615002">Una pestaña</translation>
 <translation id="4806065163318322702">Activar o desactivar la entrada de voz</translation>
+<translation id="6190185222845843088">Utilizar servidores de zona de pruebas de Wallet</translation>
 <translation id="3177048931975664371">Haz clic aquí para ocultar la contraseña</translation>
 <translation id="5852137567692933493">Reiniciar y Powerwash</translation>
 <translation id="3092544800441494315">Incluir esta captura de pantalla:</translation>
@@ -4104,6 +4109,7 @@
 <translation id="1639239467298939599">Cargando</translation>
 <translation id="5457599981699367932">Navegar como invitado</translation>
 <translation id="6850233365366645553">Para que el dispositivo pueda restablecerse con el Powerwash, es necesario reiniciarlo. Un Powerwash restablece la configuración de fábrica del dispositivo <ph name="IDS_SHORT_PRODUCT_NAME"/> y lo deja como si fuera nuevo.</translation>
+<translation id="4292622557427736684">Habilita MediaDrm de forma predeterminada para extensiones de medios encriptados.</translation>
 <translation id="1812514023095547458">Seleccionar color</translation>
 <translation id="5089363139417863686">Ver con la aplicación de archivos</translation>
 <translation id="7047998246166230966">Puntero</translation>
@@ -4453,6 +4459,7 @@
 <translation id="1728442818359004787">Cambiar aplicación predeterminada...</translation>
 <translation id="7540972813190816353">Se ha producido un error al comprobar las actualizaciones: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositivo Bluetooth no compatible: <ph name="DEVICE_NAME"/></translation>
+<translation id="2990212470195050777">Inhabilita la API de fuente de medios sin prefijo.</translation>
 <translation id="2225024820658613551">No deberías continuar, &lt;strong&gt;sobre todo&lt;/strong&gt; si no has recibido nunca esta advertencia para este sitio.</translation>
 <translation id="2049639323467105390">Este dispositivo está gestionado por <ph name="DOMAIN"/></translation>
 <translation id="1932098463447129402">Posterior a</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb
index 4785379..648915d 100644
--- a/chrome/app/resources/generated_resources_et.xtb
+++ b/chrome/app/resources/generated_resources_et.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Näita õigekirja ja grammatikat</translation>
 <translation id="7017587484910029005">Sisestage allpool asuval pildil olevad tähemärgid.</translation>
 <translation id="9013589315497579992">Halb SSL-kliendi autentimise sertifikaat.</translation>
+<translation id="2085245445866855859">Rakendus manifesti atribuudiga „kiosk_only” tuleb installida ChromeOS-i kioskirežiimis.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> soovib andmed alaliselt teie seadmesse talletada.</translation>
 <translation id="8524066305376229396">Püsitalletusruum:</translation>
 <translation id="7567293639574541773">I&amp;nspekteeri elementi</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Serveri sertifikaadi kustutamisel taastate selle serveri tavapärased turvalisuse kontrollid ja selle taotlemine vajab kehtivat sertifikaati.</translation>
 <translation id="9110235431257073974">Veebipoe ja rakenduse Files.app. integratsiooni lubamine</translation>
+<translation id="6489433341782457580">Arendajatele: kasutage liivakasti teenust Walleti API toimingu requestAutocomplete() kutsete jaoks.</translation>
 <translation id="8186609076106987817">Server ei leidnud faili.</translation>
 <translation id="2846816712032308263">Lubab kiire vahelehe/akna sulgemise – käitab vahelehe töötlejat onunload js GUI-st sõltumatult.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> ei saanud veebilehte alla laadida, sest hostil <ph name="HOST_NAME"/> võttis vastamine liiga kaua aega. See veebisait võib olla maas või teil on probleeme Interneti-ühendusega.</translation>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">Valvatav kasutaja peab kasutama seda parooli sisselogimiseks, nii et valige turvaline parool ja rääkige sellest kindlasti ka valvatava kasutajaga.</translation>
 <translation id="5154917547274118687">Mälu</translation>
 <translation id="1493492096534259649">Selle keele õigekirja ei saa kontrollida</translation>
+<translation id="2103866351350079276">Keelab eesliiteta MediaSource'i objekti. See objekt lubab JavaScriptil saata meediaandmed otse videoelementi.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/>'i otsing</translation>
 <translation id="6460423884798879930">Andmete saatmise kiiremaks käivitamiseks tehke valik, mis lubab algses SYN-paketis saata autentimise lisateavet varem ühendatud kliendi jaoks.</translation>
 <translation id="6563261555270336410">Hosti <ph name="ELEMENTS_HOST_NAME"/> üksikasjad</translation>
@@ -1596,6 +1599,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">vietnami</translation>
 <translation id="6423064450797205562">Mõõdikud, mis on seotud kiirusega, millega rakendus <ph name="SHORT_PRODUCT_NAME"/> taotletud toiminguid teeb</translation>
+<translation id="2048118585307365263">MediaDrmi kasutamine.</translation>
 <translation id="4091434297613116013">paberilehed</translation>
 <translation id="7475671414023905704">Netscape'i kaotatud parooli URL</translation>
 <translation id="3335947283844343239">Ava uuesti suletud vaheleht</translation>
@@ -3843,6 +3847,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> tahab suured andmed alaliselt teie kohalikku arvutisse talletada.</translation>
 <translation id="373572798843615002">1 vahekaart</translation>
 <translation id="4806065163318322702">Kõnesisestus sisse/välja</translation>
+<translation id="6190185222845843088">Walleti liivakasti serverite kasutamine</translation>
 <translation id="3177048931975664371">Parooli peitmiseks klõpsake</translation>
 <translation id="5852137567692933493">Taaskäivita ja tee Powerwash</translation>
 <translation id="3092544800441494315">Lisa see ekraanipilt:</translation>
@@ -4111,6 +4116,7 @@
 <translation id="1639239467298939599">Laadimine</translation>
 <translation id="5457599981699367932">Sirvi külalisena</translation>
 <translation id="6850233365366645553">Enne seadme lähtestamist funktsiooniga Powerwash on vaja seade taaskäivitada. Pärast Powerwashiga lähtestamist on rakenduse <ph name="IDS_SHORT_PRODUCT_NAME"/> seade just nagu uus.</translation>
+<translation id="4292622557427736684">Lubab krüpteeritud meedialaienduste jaoks vaikimisi funktsiooni MediaDrm.</translation>
 <translation id="1812514023095547458">Värvi valimine</translation>
 <translation id="5089363139417863686">Kuva rakendusega Failid</translation>
 <translation id="7047998246166230966">Kursor</translation>
@@ -4461,6 +4467,7 @@
 <translation id="1728442818359004787">Muuda vaikerakendust ...</translation>
 <translation id="7540972813190816353">Värskenduste otsimisel ilmnes viga: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Toetamata Bluetooth-seade: „<ph name="DEVICE_NAME"/>”.</translation>
+<translation id="2990212470195050777">Eesliiteta meediaallika API keelamine.</translation>
 <translation id="2225024820658613551">Ärge jätkake, &lt;strong&gt;eriti&lt;/strong&gt; juhul, kui te ei ole sel saidil varem seda hoiatust näinud.</translation>
 <translation id="2049639323467105390">Seadet haldab <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Mitte enne</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb
index 7c13063..ee23aa1 100644
--- a/chrome/app/resources/generated_resources_fa.xtb
+++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">نمایش املا و گرامر</translation>
 <translation id="7017587484910029005">نویسه‌هایی را که در تصویر زیر می‌بینید تایپ کنید.</translation>
 <translation id="9013589315497579992">‏گواهی تأیید اعتبار سرویس گیرنده SSL نادرست است.</translation>
+<translation id="2085245445866855859">‏برنامه‌ای با ویژگی مانیفست «kiosk_only» باید در حالت کیوسک ChromeOS نصب شود.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> می‌خواهد داده‌ها را برای همیشه در دستگاه شما ذخیره کند.</translation>
 <translation id="8524066305376229396">محل ذخیره دائمی:</translation>
 <translation id="7567293639574541773">&amp;بازرسی عنصر</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">فوتبالی</translation>
 <translation id="2231238007119540260">در صورتی که یک مجوز سرور را حذف کنید، بررسی های امنیتی معمولی را برای آن سرور بازیابی می‌کنید و سرور ملزم به استفاده از یک مجوز معتبر می‌شود.</translation>
 <translation id="9110235431257073974">‏فعال کردن ادغام Webstore و Files.app.</translation>
+<translation id="6489433341782457580">‏برای برنامه‌نویسان: از سرویس جعبه ایمنی برای فراخوانی‌های Wallet API برای requestAutocomplete() استفاده کنید.</translation>
 <translation id="8186609076106987817">سرور نتوانست فایل را پیدا کند.</translation>
 <translation id="2846816712032308263">‏بستن سریع برگه/پنجره را فعال می‌کند - کنترل‌کننده onunload js برگه را مستقل از GUI اجرا می‌کند.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> نمی‌تواند صفحهٔ وب را بارگیری کند زیرا پاسخ <ph name="HOST_NAME"/> مدت زمان زیادی طول کشید. ممکن است وب سایت کار نکند، یا اتصال اینترنت شما مشکل داشته باشد.</translation>
@@ -346,6 +348,7 @@
 <translation id="8959810181433034287">کاربر نظارت‌شده برای ورود به سیستم باید از این گذرواژه استفاده کند. بنابراین گذرواژه‌ای ایمن انتخاب کرده، آن را با کاربر نظارت‌شده در میان بگذارید.</translation>
 <translation id="5154917547274118687">حافظه</translation>
 <translation id="1493492096534259649">امکان استفاده از این زبان برای بررسی املا وجود ندارد</translation>
+<translation id="2103866351350079276">‏شیء بدون پیشوند MediaSource را غیر فعال می‌کند. این شیء به جاوا اسکریپت امکان می‌دهد داده‌های رسانه‌ای را مستقیماً به یک عنصر ویدیویی ارسال کند.</translation>
 <translation id="6628463337424475685">جستجوی <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">‏قابلیت ارسال اطلاعات تأیید هویت اضافی در بسته اولیه SYN را برای سرویس‌گیرنده‌ای که قبلاً متصل شده است به کار می‌اندازد و باعث می‌شود ارسال داده سریع‌تر آغاز شود.</translation>
 <translation id="6563261555270336410">جزئيات مربوط به <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1580,6 +1583,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">ویتنامی</translation>
 <translation id="6423064450797205562">معیارهای اندازه‌گیری مربوط به سرعت انجام عملکردهای درخواستی توسط  <ph name="SHORT_PRODUCT_NAME"/></translation>
+<translation id="2048118585307365263">‏فعال کردن MediaDrm.</translation>
 <translation id="4091434297613116013">صفحات کاغذ</translation>
 <translation id="7475671414023905704">‏Netscape URL رمز ورود را گم کرده است</translation>
 <translation id="3335947283844343239">باز کردن مجدد برگه بسته شده</translation>
@@ -3825,6 +3829,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> می‌خواهد بطور دائم داده‌های بزرگ را در رایانه محلی شما ذخیره کند.</translation>
 <translation id="373572798843615002">1 برگه</translation>
 <translation id="4806065163318322702">تغییر حالت ورودی گفتار</translation>
+<translation id="6190185222845843088">‏استفاده از سرورهای جعبه ایمنی Wallet</translation>
 <translation id="3177048931975664371">برای پنهان کردن گذرواژه، کلیک کنید</translation>
 <translation id="5852137567692933493">‏راه‌اندازی مجدد و Powerwash</translation>
 <translation id="3092544800441494315">لحاظ کردن این عکس صفحهٔ نمایش:</translation>
@@ -4091,6 +4096,7 @@
 <translation id="1639239467298939599">بارگیری</translation>
 <translation id="5457599981699367932">مرور کردن به‌عنوان یک مهمان</translation>
 <translation id="6850233365366645553">‏‘پیش از آنکه دستگاه شما با Powerwash بازنشانی شود، یک راه‌اندازی مجدد مورد نیاز است. Powerwash دستگاه <ph name="IDS_SHORT_PRODUCT_NAME"/> شما را به گونه‌ای بازنشانی می‌کند که انگار یک دستگاه جدید است.</translation>
+<translation id="4292622557427736684">‏MediaDrm را به طور پیش‌فرض برای برنامه‌های افزودنی رسانه‌ای رمزگذاری شده فعال می‌کند.</translation>
 <translation id="1812514023095547458">انتخاب رنگ</translation>
 <translation id="5089363139417863686">مشاهده با برنامه «فایل‌ها»</translation>
 <translation id="7047998246166230966">اشاره‌گر</translation>
@@ -4441,6 +4447,7 @@
 <translation id="1728442818359004787">تغییر برنامه پیش‌فرض...</translation>
 <translation id="7540972813190816353">در هنگام بررسی برای وجود به‌روزرسانی خطایی رخ داد: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">دستگاه بلوتوث پشتیبانی نشده: «<ph name="DEVICE_NAME"/>».</translation>
+<translation id="2990212470195050777">‏غیرفعال کردن Media Source API بدون پیشوند.</translation>
 <translation id="2225024820658613551">‏نباید ادامه دهید، &lt;strong&gt;مخصوصاً&lt;/strong&gt; اگر قبلاً هیچوقت این هشدار را در مورد این سایت ندیده‌اید.</translation>
 <translation id="2049639323467105390">این دستگاه توسط <ph name="DOMAIN"/> مدیریت می‌شود.</translation>
 <translation id="1932098463447129402">نه قبل از</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb
index 405d443..cf74306 100644
--- a/chrome/app/resources/generated_resources_fi.xtb
+++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Näytä oikeinkirjoitus ja kielioppi</translation>
 <translation id="7017587484910029005">Kirjoita alla olevassa kuvassa näkyvät merkit.</translation>
 <translation id="9013589315497579992">Virheellinen SSL-asiakkaan todennusvarmenne.</translation>
+<translation id="2085245445866855859">Sovellukset, joilla on luetteloattribuutti kiosk_only, täytyy asentaa Chrome-käyttöjärjestelmän kioskitilassa.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> haluaa tallentaa tietoja pysyvästi laitteellesi.</translation>
 <translation id="8524066305376229396">Pysyvä tallennustila:</translation>
 <translation id="7567293639574541773">Tar&amp;kastele elementtiä</translation>
@@ -183,6 +184,7 @@
 <translation id="4858913220355269194">Litti</translation>
 <translation id="2231238007119540260">Jos poistat palvelimen varmenteen, palautat käyttöön palvelimen tavalliset turvatarkastukset ja edellytät siltä kelvollista varmennetta.</translation>
 <translation id="9110235431257073974">Salli Webstoren ja Files.appin integrointi.</translation>
+<translation id="6489433341782457580">Kehittäjille: käytä Wallet-sovellusliittymän requestAutocomplete()-kutsuissa hiekkalaatikkopalvelua.</translation>
 <translation id="8186609076106987817">Palvelin ei löydä tiedostoa.</translation>
 <translation id="2846816712032308263">Ottaa käyttöön välilehtien/ikkunoiden nopean sulkemisen. Suorittaa välilehden onunload js handler -tapahtuman graafisen käyttöliittymän ulkopuolella.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> ei voinut ladata verkkosivua, sillä <ph name="HOST_NAME"/> ei vastaa riittävän nopeasti. Sivusto voi olla pois käytöstä tai internetyhteydessäsi voi olla ongelmia.</translation>
@@ -340,6 +342,7 @@
 <translation id="8959810181433034287">Valvotun käyttäjän on käytettävä tätä salasanaa kirjautuakseen sisään, joten valitse turvallinen salasana ja muista keskustella siitä valvotun käyttäjän kanssa.</translation>
 <translation id="5154917547274118687">Muisti</translation>
 <translation id="1493492096534259649">Tällä kielellä ei voi käyttää oikeinkirjoituksen tarkistusta</translation>
+<translation id="2103866351350079276">Poista käytöstä etuliitteetön MediaSource-objekti. Tämä objekti antaa JavaScriptillle luvan lähettää mediatietoja suoraan videoelementtiin.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/>-haku</translation>
 <translation id="6460423884798879930">Kun tämä asetus on käytössä, edellisen asiakasyhteyden SYN-paketissa lähetetään lisätodennustietoja, mikä nopeuttaa tiedonlähetyksen aloitusta.</translation>
 <translation id="6563261555270336410">Tietoja sivustosta <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1574,6 +1577,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">vietnam</translation>
 <translation id="6423064450797205562">Tilastot, jotka liittyvät nopeuteen, jolla <ph name="SHORT_PRODUCT_NAME"/> suorittaa pyydetyt toiminnot</translation>
+<translation id="2048118585307365263">Ota MediaDrm käyttöön</translation>
 <translation id="4091434297613116013">paperiarkkia</translation>
 <translation id="7475671414023905704">Netscapen unohtunut salasana -URL</translation>
 <translation id="3335947283844343239">Avaa suljettu välilehti uudelleen</translation>
@@ -3803,6 +3807,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> haluaa tallentaa suuria tietomääriä pysyvästi paikalliselle tietokoneelle.</translation>
 <translation id="373572798843615002">1 välilehti</translation>
 <translation id="4806065163318322702">Puheen syöttö päälle/pois</translation>
+<translation id="6190185222845843088">Käytä Walletin hiekkalaatikkopalvelimia</translation>
 <translation id="3177048931975664371">Piilota salasana klikkaamalla</translation>
 <translation id="5852137567692933493">Käynnistä uudelleen ja suorita Powerwash</translation>
 <translation id="3092544800441494315">Liitä mukaan tämä kuvakaappaus:</translation>
@@ -4069,6 +4074,7 @@
 <translation id="1639239467298939599">Ladataan</translation>
 <translation id="5457599981699367932">Selaa vierailijana</translation>
 <translation id="6850233365366645553">Laite on käynnistettävä uudelleen ennen Powerwashin suorittamista. Powerwash palauttaa <ph name="IDS_SHORT_PRODUCT_NAME"/>-laitteesi uutta vastaavaan tilaan.</translation>
+<translation id="4292622557427736684">Ota MediaDrm käyttöön oletusarvona salatuille medialaajennuksille.</translation>
 <translation id="1812514023095547458">Valitse väri</translation>
 <translation id="5089363139417863686">Tarkastele Tiedostot-sovelluksessa</translation>
 <translation id="7047998246166230966">Osoitin</translation>
@@ -4418,6 +4424,7 @@
 <translation id="1728442818359004787">Vaihda oletussovellus…</translation>
 <translation id="7540972813190816353">Virhe tarkistettaessa päivityksiä: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Tukematon Bluetooth-laite: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Poista etuliitteetön medialähdesovellusliittymä käytöstä</translation>
 <translation id="2225024820658613551">Älä jatka, &lt;strong&gt;etenkään&lt;/strong&gt; jos et ole koskaan aiemmin nähnyt tätä varoitusta tässä sivustossa.</translation>
 <translation id="2049639323467105390">Tätä laitetta hallinnoi <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Ei aiemmin kuin</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index ca1a990..b5d44b7 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Show Spelling and Grammar</translation>
 <translation id="7017587484910029005">I-type ang mga character na iyong nakikita sa larawan sa ibaba.</translation>
 <translation id="9013589315497579992">Bad SSL client authentication certificate.</translation>
+<translation id="2085245445866855859">Naka-install dapat ang app na may katangian ng manifest na 'kiosk_only' sa ChromeOS kiosk mode.</translation>
 <translation id="1467999917853307373">Gusto ng <ph name="URL"/> na permanenteng mag-imbak ng data sa iyong device.</translation>
 <translation id="8524066305376229396">Matagalang storage:</translation>
 <translation id="7567293639574541773">S&amp;iyasatin ang elemento</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Azkals</translation>
 <translation id="2231238007119540260">Kung nagtanggal ka ng certificate ng server, ibinabalik mo ang mga karaniwang pagsusuri ng seguridad para sa server na iyon at kinakailangang gumagamit ito ng wastong certificate.</translation>
 <translation id="9110235431257073974">I-enable ang pagsasama ng Webstore at Files.app.</translation>
+<translation id="6489433341782457580">Para sa mga developer: gamitin ang serbisyo ng sandbox para sa mga tawag sa Wallet API para sa requestAutocomplete().</translation>
 <translation id="8186609076106987817">Hindi makita ng server ang file.</translation>
 <translation id="2846816712032308263">Ini-enable ang mabilis na pagsasara ng tab/window - pinapatakbo ang onunload js handler ng isang tab nang independiyente sa GUI.</translation>
 <translation id="9134410174832249455">Hindi ma-load ng <ph name="PRODUCT_NAME"/> ang webpage dahil masyadong matagal ang pagtugon ng <ph name="HOST_NAME"/>. Maaaring hindi gumagana ang website, o maaaring nakakaranas ka ng mga isyu sa iyong koneksyon sa Internet.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">Kakailanganin ng pinangangasiwaang user ang password na ito upang makapag-sign in, kaya pumili ng ligtas na password at tandaang italakay ito sa pinangangasiwaang user.</translation>
 <translation id="5154917547274118687">Memorya</translation>
 <translation id="1493492096534259649">Hindi magagamit ang wikang ito para sa spell checking</translation>
+<translation id="2103866351350079276">I-disable ang walang prefix na MediaSource object. Binibigyang-daan ng object na ito ang JavaScript na magpadala ng data ng media nang direkta sa isang elemento ng video.</translation>
 <translation id="6628463337424475685">Paghahanap ng <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">I-enable ang pagpipiliang ito upang magpadala ng karagdagang impormasyon sa pagpapatunay sa unang SYN packet para sa isang client na nakakonekta dati, na nagbibigay-daan sa mas mabilis na pagsisimula ng pagpapadala ng data.</translation>
 <translation id="6563261555270336410">Mga detalye tungkol sa <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1599,6 +1602,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamese</translation>
 <translation id="6423064450797205562">Mga sukatang may kaugnayan sa bilis ng paggawa ng <ph name="SHORT_PRODUCT_NAME"/> sa mga hiniling na pagkilos</translation>
+<translation id="2048118585307365263">I-enable ang MediaDrm.</translation>
 <translation id="4091434297613116013">mga sheet ng papel</translation>
 <translation id="7475671414023905704">URL ng Nawalang Password ng Netscape</translation>
 <translation id="3335947283844343239">Muling buksan ang Nakasarang Tab</translation>
@@ -3863,6 +3867,7 @@
 <translation id="3672159315667503033">Nais ng <ph name="URL"/> na permanenteng mag-imbak ng malaking data sa iyong lokal na computer.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">I-toggle ang input ng pananalita</translation>
+<translation id="6190185222845843088">Gumamit ng mga server ng sandbox ng Wallet</translation>
 <translation id="3177048931975664371">I-click upang itago ang password</translation>
 <translation id="5852137567692933493">I-restart at I-powerwash</translation>
 <translation id="3092544800441494315">Isama ang screenshot na ito</translation>
@@ -4132,6 +4137,7 @@
 <translation id="1639239467298939599">Naglo-load</translation>
 <translation id="5457599981699367932">Mag-browse bilang Bisita</translation>
 <translation id="6850233365366645553">Kinakailangan ang pag-restart bago ma-reset ang iyong device gamit ang Powerwash. Nire-reset ng Powerwash ang iyong <ph name="IDS_SHORT_PRODUCT_NAME"/> device upang maging parang bago.</translation>
+<translation id="4292622557427736684">I-enable ang MediaDrm bilang default para sa Mga Naka-encrypt na Extension ng Media.</translation>
 <translation id="1812514023095547458">Pumili ng Kulay</translation>
 <translation id="5089363139417863686">Tingnan gamit ang Files app</translation>
 <translation id="7047998246166230966">Pointer</translation>
@@ -4482,6 +4488,7 @@
 <translation id="1728442818359004787">Palitan ang default na app...</translation>
 <translation id="7540972813190816353">Naganap ang isang error habang nagsusuri ng mga update: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Hindi sinusuportahang Bluetooth device: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">I-disable ang walang prefix na Media Source API.</translation>
 <translation id="2225024820658613551">Hindi ka dapat magpatuloy, &lt;strong&gt;lalo na&lt;/strong&gt; kung hindi mo pa kailanman nakita ang babalang ito para sa site na ito.</translation>
 <translation id="2049639323467105390">Pinamamahalaan ng <ph name="DOMAIN"/> ang device na ito.</translation>
 <translation id="1932098463447129402">Hindi Bago</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index 4bf6a77..41c67a3 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Afficher l'orthographe et la grammaire</translation>
 <translation id="7017587484910029005">Saisissez les caractères visibles dans l'image ci-dessous.</translation>
 <translation id="9013589315497579992">Certificat d'authentification de client SSL incorrect</translation>
+<translation id="2085245445866855859">L'application dont le fichier manifeste comporte un attribut 'kiosk_only' doit être installée en mode Borne pour Chrome OS.</translation>
 <translation id="1467999917853307373">Une demande de stockage permanent de données sur votre appareil a été envoyée à partir de <ph name="URL"/>.</translation>
 <translation id="8524066305376229396">Stockage persistant :</translation>
 <translation id="7567293639574541773">I&amp;nspecter l'élément</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Foot</translation>
 <translation id="2231238007119540260">Lorsque vous supprimez un certificat de serveur, vous rétablissez les contrôles de sécurité habituels du serveur et un certificat valide lui est demandé.</translation>
 <translation id="9110235431257073974">Activer la fonctionnalité d'intégration de Chrome Web Store et Files.app</translation>
+<translation id="6489433341782457580">Pour les développeurs : utilisez le service de bac à sable pour les appels à l'API Wallet avec la méthode &quot;requestAutocomplete()&quot;.</translation>
 <translation id="8186609076106987817">Impossible de trouver le fichier sur le serveur.</translation>
 <translation id="2846816712032308263">Active la fermeture rapide des onglets et des fenêtres. Exécute le gestionnaire onUnload JS d'un onglet indépendamment de l'IUG.</translation>
 <translation id="9134410174832249455">Impossible de charger la page Web sur <ph name="PRODUCT_NAME"/>, car <ph name="HOST_NAME"/> n'a pas répondu à temps. Il est possible que le site soit bloqué ou que vous rencontriez des problèmes avec votre connexion Internet.</translation>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">L'utilisateur supervisé doit saisir ce mot de passe pour se connecter. Vous devez donc choisir un mot de passe sécurisé et le communiquer à l'utilisateur supervisé.</translation>
 <translation id="5154917547274118687">Mémoire</translation>
 <translation id="1493492096534259649">Impossible d'utiliser cette langue pour corriger l'orthographe.</translation>
+<translation id="2103866351350079276">Désactiver l'objet MediaSource sans préfixe. Cet objet permet d'envoyer directement des données multimédias à un élément vidéo via JavaScript.</translation>
 <translation id="6628463337424475685">Recherche <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Activez cette option pour envoyer des informations d'authentification supplémentaires dans le paquet SYN initial d'un client connecté précédemment. Cela vous garantit un démarrage plus rapide de l'envoi de données.</translation>
 <translation id="6563261555270336410">Détails sur <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1595,6 +1598,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamien</translation>
 <translation id="6423064450797205562">Statistiques relatives à la vitesse à laquelle <ph name="SHORT_PRODUCT_NAME"/> effectue les actions requises</translation>
+<translation id="2048118585307365263">Activer MediaDrm</translation>
 <translation id="4091434297613116013">feuilles de papier</translation>
 <translation id="7475671414023905704">URL de mot de passe perdu Netscape</translation>
 <translation id="3335947283844343239">Rouvrir l'onglet fermé</translation>
@@ -3864,6 +3868,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> veut stocker de façon permanente des données volumineuses sur votre ordinateur local.</translation>
 <translation id="373572798843615002">1 onglet</translation>
 <translation id="4806065163318322702">Démarrer/Arrêter la saisie vocale</translation>
+<translation id="6190185222845843088">Utiliser les serveurs de bac à sable Wallet</translation>
 <translation id="3177048931975664371">Cliquer pour masquer le mot de passe</translation>
 <translation id="5852137567692933493">Redémarrer et lancer Powerwash</translation>
 <translation id="3092544800441494315">Inclure cette capture d'écran :</translation>
@@ -4131,6 +4136,7 @@
 <translation id="1639239467298939599">Chargement en cours</translation>
 <translation id="5457599981699367932">Naviguer en tant qu'invité</translation>
 <translation id="6850233365366645553">Vous devez redémarrer votre appareil avant de pouvoir le réinitialiser via un Powerwash. Cette opération rétablira la configuration d'usine de votre appareil &quot;<ph name="IDS_SHORT_PRODUCT_NAME"/>&quot;.</translation>
+<translation id="4292622557427736684">Activer MediaDrm par défaut pour l'API Encrypted Media Extensions</translation>
 <translation id="1812514023095547458">Sélectionner une couleur</translation>
 <translation id="5089363139417863686">Afficher avec l'application Fichiers</translation>
 <translation id="7047998246166230966">Curseur</translation>
@@ -4480,6 +4486,7 @@
 <translation id="1728442818359004787">Changer d'application par défaut…</translation>
 <translation id="7540972813190816353">Une erreur s'est produite pendant la vérification des mises à jour : <ph name="ERROR"/>.</translation>
 <translation id="7664620655576155379">Appareil Bluetooth non compatible : &quot;<ph name="DEVICE_NAME"/>&quot;</translation>
+<translation id="2990212470195050777">Désactiver l'API Media Source sans préfixe</translation>
 <translation id="2225024820658613551">Ne poursuivez pas cette opération, &lt;strong&gt;notamment&lt;/strong&gt; si vous n'avez jamais vu cet avertissement concernant ce site auparavant.</translation>
 <translation id="2049639323467105390">Cet appareil est géré par <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Pas avant le</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 65937f5..822f4c6 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">જોડણી અને વ્યાકરણ બતાવો</translation>
 <translation id="7017587484910029005">નીચેના ચિત્રમાં તમે જોયેલા અક્ષરો લખો.</translation>
 <translation id="9013589315497579992">ખરાબ SSL ક્લાયંટ પ્રમાણીકરણ પ્રમાણપત્ર.</translation>
+<translation id="2085245445866855859">'Kiosk_only' મેનિફેસ્ટ લક્ષણ સાથેની એપ્લિકેશન ChromeOS કિઓસ્ક મોડમાં ઇન્સ્ટોલ કરેલી હોવી આવશ્યક છે.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> તમારા ઉપકરણ પર કાયમી ધોરણે ડેટા સ્ટોર કરવા માંગે છે.</translation>
 <translation id="8524066305376229396">સતત સ્ટોરેજ:</translation>
 <translation id="7567293639574541773">ઘટકની ત&amp;પાસ કરો</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">જો તમે કોઈ સર્વર પ્રમાણપત્રને કાઢી નાંખો છો, તો તમે તે સર્વર માટેની સામાન્ય સુરક્ષા તપાસોને પુનર્પ્રાપ્ત કરો છો અને આવશ્યક છે કે તે માન્ય પ્રામણપત્રનો ઉપયોગ કરે છે.</translation>
 <translation id="9110235431257073974">Webstore અને Files.app નું એકીકરણ સક્ષમ કરો.</translation>
+<translation id="6489433341782457580">વિકાસકર્તાઓ માટે: requestAutocomplete() માટે કૉલ કરતા Wallet API માટે સેન્ડબોક્સ સેવાનો ઉપયોગ કરો.</translation>
 <translation id="8186609076106987817">સર્વર ફાઇલને શોધી શક્યું નથી.</translation>
 <translation id="2846816712032308263">ઝડપી ટેબ/ વિંડો બંધ કરવું સક્ષમ કરે છે - GUI ના તે ટેબના onunload js હેન્ડલરને સ્વતંત્રરીતે શરૂ કરે છે.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">નિરીક્ષણ કરેલ વપરાશકર્તાને સાઇન ઇન કરવા માટે આ પાસવર્ડનો ઉપયોગ કરવાની જરૂર પડશે, જેથી સલામત પાસવર્ડ પસંદ કરો અને તેની નિરીક્ષણ કરેલ વપરાશકર્તા સાથે ચર્ચા કરવાનું યાદ રાખો.</translation>
 <translation id="5154917547274118687">મેમરી</translation>
 <translation id="1493492096534259649">આ ભાષાનો ઉપયોગ જોડણી પરીક્ષણ માટે કરી શકાતો નથી</translation>
+<translation id="2103866351350079276">પ્રીફિક્સ ન કરેલ MediaSource ઓબ્જેક્ટને અક્ષમ કરો. આ ઓબ્જેક્ટ JavaScript ને સીધા જ વિડિઓ ઘટક પર મીડિયા ડેટા મોકલવાની મંજૂરી આપે છે.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> શોધ</translation>
 <translation id="6460423884798879930">ઝડપી ડેટા મોકલો પ્રારંભ કરીને, પહેલાંથી કનેક્ટ થયેલા ક્લાયંટ માટે પ્રારંભિક SYN પૅકેટમાં વધારાની અધિકૃતતા માહિતી મોકલવાનો વિકલ્પ સક્ષમ કરો.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> વિશે વિગતો</translation>
@@ -832,7 +835,7 @@
 <translation id="7550830279652415241">bookmarks_<ph name="DATESTAMP"/>.html</translation>
 <translation id="3127360977178108225">અતિથિ સત્ર સમાપ્ત કરો</translation>
 <translation id="6327653052522436195">શહેર</translation>
-<translation id="164814987133974965">એક નિરીક્ષણ કરેલ વપરાશકર્તા તમારા માર્ગદર્શન હેઠળ વેબ એક્સ્પ્લોર કરી શકે છે. નિરીક્ષણ કરેલ વપરાશકર્તાના સંચાલક તરીકે, તમે 
+<translation id="164814987133974965">એક નિરીક્ષણ કરેલ વપરાશકર્તા તમારા માર્ગદર્શન હેઠળ વેબ પર અન્વેષણ કરી શકે છે. નિરીક્ષણ કરેલ વપરાશકર્તાના સંચાલક તરીકે, તમે 
     અમુક વેબસાઇટ્સને <ph name="BEGIN_BOLD"/>મંજુર અથવા પ્રતિબંધિત<ph name="END_BOLD"/> કરી શકો છો.
     નિરીક્ષણ કરેલ વપરાશકર્તાએ મુલાકાત લીધેલી વેબસાઇટ્સની <ph name="BEGIN_BOLD"/>સમીક્ષા<ph name="END_BOLD"/> કરી શકો છો, અને
     અન્ય સેટિંગ્સનું <ph name="BEGIN_BOLD"/>સંચાલન<ph name="END_BOLD"/> કરી શકો છો.</translation>
@@ -1473,7 +1476,7 @@
 
         જો આ ઉપકરણ તમારા સંગઠનનું ન હોય, અને તે તમારી વ્યક્તિગત ઉપકરણ હોય, તો તમે ઉપકરણની નોંધણીને રદ કરવા માટે હમણાં Ctrl+Alt+E દબાવી શકો છો અને સાઇન ઇન સ્ક્રીન પર પાછા ફરી શકો છો.</translation>
 <translation id="2655386581175833247">વપરાશકર્તા પ્રમાણપત્ર:</translation>
-<translation id="5039804452771397117">પરવાનગી આપો</translation>
+<translation id="5039804452771397117">મંજૂરી આપો</translation>
 <translation id="5435964418642993308">પાછળ જવા માટે એન્ટર અને ઇતિહાસ જોવા માટે સંદર્ભ મેનૂ કી દબાવો</translation>
 <translation id="6815206662964743929">વપરાશકર્તાને સ્વિચ કરો</translation>
 <translation id="81686154743329117">ઝેડઆરએમ</translation>
@@ -1604,6 +1607,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">વિયેતનામીસ</translation>
 <translation id="6423064450797205562">ઝડપથી સંબંધિત મેટ્રિક્સ કે જેની સાથે <ph name="SHORT_PRODUCT_NAME"/> વિનંતી કરેલ ક્રિયા કરે છે</translation>
+<translation id="2048118585307365263">MediaDrm સક્ષમ કરો.</translation>
 <translation id="4091434297613116013">કાગળનાં પત્રકો</translation>
 <translation id="7475671414023905704">નેટસ્કેપ ખોવાયેલો પાસવર્ડ URL</translation>
 <translation id="3335947283844343239">બંધ કરેલું ટૅબ ફરીથી ખોલો</translation>
@@ -3863,6 +3867,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> તમારા કમ્પ્યુટર પર કાયમી ધોરણે વિશાળ ડેટા સ્ટોર કરવા માંગે છે.</translation>
 <translation id="373572798843615002">1 ટૅબ</translation>
 <translation id="4806065163318322702">ભાષણ ઇનપુટ ટૉગલ કરો</translation>
+<translation id="6190185222845843088">Wallet સેન્ડબોક્સ સર્વર્સનો ઉપયોગ કરો</translation>
 <translation id="3177048931975664371">પાસવર્ડ છુપાવવા માટે ક્લિક કરો</translation>
 <translation id="5852137567692933493">પુનઃપ્રારંભ કરો અને પાવરવૉશ કરો</translation>
 <translation id="3092544800441494315">આ સ્ક્રીનશોટ શામેલ કરો:</translation>
@@ -4129,6 +4134,7 @@
 <translation id="1639239467298939599">લોડ કરી રહ્યું છે</translation>
 <translation id="5457599981699367932">અતિથિ તરીકે બ્રાઉઝ કરો</translation>
 <translation id="6850233365366645553">તમારા ઉપકરણને Powerwash સાથે સેટ કરવામાં આવે તે પહેલાં એક પુનઃપ્રારંભ આવશ્યક છે. Powerwash તમારા <ph name="IDS_SHORT_PRODUCT_NAME"/> ઉપકરણને નવાની જેમ જ ફરીથી સેટ કરે છે.</translation>
+<translation id="4292622557427736684">એન્ક્રિપ્ટ કરેલ મીડિયા એક્સ્ટેન્શન્સ માટે ડિફોલ્ટ તરીકે MediaDrm ને સક્ષમ કરો.</translation>
 <translation id="1812514023095547458">રંગ પસંદ કરો</translation>
 <translation id="5089363139417863686">ફાઇલો એપ્લિકેશન સાથે જુઓ</translation>
 <translation id="7047998246166230966">પોઇન્ટર</translation>
@@ -4477,6 +4483,7 @@
 <translation id="1728442818359004787">ડિફોલ્ટ એપ્લિકેશન બદલો...</translation>
 <translation id="7540972813190816353">અપડેટ્સ માટે તપાસ કરતી વખતે એક ભૂલ આવી: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">અસમર્થિત Bluetooth ઉપકરણ: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">પ્રીફિક્સ ન કરેલ મીડિયા સ્રોત API અક્ષમ કરો.</translation>
 <translation id="2225024820658613551">&lt;strong&gt;વિશેષ રૂપે&lt;/strong&gt;, જો તમે આ સાઇટ માટે પહેલાં આ ચેતવણીને ક્યારે પણ જોઈ નથી, તો તમારે આગળ વધવું જોઈએ નહીં.</translation>
 <translation id="2049639323467105390">આ ઉપકરણને <ph name="DOMAIN"/> દ્વારા મેનેજ કરવામાં આવેલું છે.</translation>
 <translation id="1932098463447129402">આની પહેલા નહીં</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index 4ef0d64..1d71dda 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -129,11 +129,12 @@
 <translation id="528468243742722775">समाप्त</translation>
 <translation id="1723824996674794290">&amp;नई विंडो</translation>
 <translation id="1313405956111467313">स्‍वचालित प्रॉक्सी कॉन्फ़िगरेशन</translation>
-<translation id="3527276236624876118">एक पर्यवेक्षित उपयोगकर्ता नाम <ph name="USER_DISPLAY_NAME"/> बना दिया गया है.</translation>
+<translation id="3527276236624876118"><ph name="USER_DISPLAY_NAME"/> नाम का एक पर्यवेक्षित उपयोगकर्ता बनाया गया है.</translation>
 <translation id="4367782753568896354">हम इन्‍हें इंस्‍टॉल करने में असमर्थ रहे:</translation>
 <translation id="1589055389569595240">वर्तनी और व्याकरण दिखाएं</translation>
 <translation id="7017587484910029005">नीचे चित्र में दिखाई देने वाले वर्ण लिखें.</translation>
 <translation id="9013589315497579992">ख़राब SSL क्लाइंट प्रमाणीकरण प्रमाणपत्र.</translation>
+<translation id="2085245445866855859">'kiosk_only' मेनिफ़ेस्ट विशेषता वाले ऐप्स ChromeOS कियोस्क मोड में ही इंस्टॉल किए जाने चाहिए.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> डेटा को स्‍थायी रूप से आपके उपकरण पर संगृहीत करना चाहता है..</translation>
 <translation id="8524066305376229396">स्थायी संग्रहण:</translation>
 <translation id="7567293639574541773">तत्व की &amp;जांच करें</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">फ्रिट्ज़</translation>
 <translation id="2231238007119540260">यदि आप किसी सर्वर प्रमाणपत्र को हटाते हैं, तो आप उस सर्वर के लिए सामान्‍य सुरक्षा जांच पुन: स्‍थापित करते हैं और इसके लिए किसी मान्य प्रमाणपत्र का उपयोग करने की आवश्यकता है.</translation>
 <translation id="9110235431257073974">वेबस्टोर और Files.app के एकीकरण को सक्षम करें.</translation>
+<translation id="6489433341782457580">डेवलपर के लिए: requestAutocomplete() के लिए Wallet API कॉल की सैंडबॉक्स सेवा उपयोग करें.</translation>
 <translation id="8186609076106987817">सर्वर को फ़ाइल नहीं मिल सकी.</translation>
 <translation id="2846816712032308263">टैब/विंडो को त्वरित रूप से बंद करना सक्षम बनाती है - किसी टैब के ऑनअनलोड js हैंडलर को GUI से स्वतंत्र रूप से चलाती है.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">पर्यवेक्षित उपयोगकर्ता को प्रवेश करने के लिए इस पासवर्ड की आवश्यकता होगी, इसलिए एक सुरक्षित पासवर्ड चुनें और पर्यवेक्षित उपयोगकर्ता के साथ उसकी चर्चा करना याद रखें.</translation>
 <translation id="5154917547274118687">स्मृति</translation>
 <translation id="1493492096534259649">वर्तनी जांच के लिए इस भाषा का उपयोग नहीं किया जा सकता है</translation>
+<translation id="2103866351350079276">उपसर्ग के रूप में उपयोग न किए गए MediaSource ऑब्जेक्ट को अक्षम करें. यह ऑब्जेक्ट JavaScript को मीडिया डेटा को सीधे किसी वीडियो तत्व पर भेजने देता है.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> खोज</translation>
 <translation id="6460423884798879930">पहले से कनेक्ट किसी क्लाइंट के लिए आरंभिक SYN पैकेट में अतिरिक्त प्रमाणीकरण जानकारी भेजने के लिए विकल्प सक्षम करें, ताकि तेज़ी से डेटा भेजा जाना प्रारंभ हो जाए.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> के बारे में विवरण</translation>
@@ -1597,6 +1600,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">वियतनामी</translation>
 <translation id="6423064450797205562">उस गति से संबंधित मीट्रिक जिनसे <ph name="SHORT_PRODUCT_NAME"/> अनुरोधित कार्यवाही निष्पादित करता है</translation>
+<translation id="2048118585307365263">MediaDrm सक्षम करें.</translation>
 <translation id="4091434297613116013">कागज़ की शीट</translation>
 <translation id="7475671414023905704">Netscape खोए पासवर्ड का URL</translation>
 <translation id="3335947283844343239">बंद किए गए टैब पुनः खोलें</translation>
@@ -2897,7 +2901,7 @@
 <translation id="2912905526406334195"><ph name="HOST"/> आपके माइक्रोफ़ोन का उपयोग करना चाहता है.</translation>
 <translation id="2805756323405976993">एप्स</translation>
 <translation id="1608626060424371292">इस उपयोगकर्ता को निकालें</translation>
-<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> को पर्यवेक्षित उपयोगकर्ता के रूप में बनाया गया है!</translation>
+<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> को पर्यवेक्षित उपयोगकर्ता बनाया गया है!</translation>
 <translation id="3651020361689274926">अनुरोधित संसाधन अब मौजूद नहीं है, और कोई अग्रेषण पता नहीं है.  इस स्‍थिति के स्‍थायी रहने की संभावना है.</translation>
 <translation id="7541236596838501870">अपलोड किए गए WebRTC लॉग ( <ph name="WEBRTC_LOG_COUNT"/> )</translation>
 <translation id="6003284010415283671">Apps जोड़ें</translation>
@@ -3877,6 +3881,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> आपके स्थानीय कंप्यूटर पर स्थायी रूप से बड़ी मात्रा में डेटा संग्रहीत करना चाहता है.</translation>
 <translation id="373572798843615002">1 टैब</translation>
 <translation id="4806065163318322702">वाक इनपुट टॉगल करें</translation>
+<translation id="6190185222845843088">वॉलेट सैंडबॉक्स सर्वर का उपयोग करें</translation>
 <translation id="3177048931975664371">पासवर्ड छुपाने के लिए क्लिक करें</translation>
 <translation id="5852137567692933493">पुनः प्रारंभ करें और पावरवॉश करें</translation>
 <translation id="3092544800441494315">इस स्‍क्रीनशॉट को शामिल करें:</translation>
@@ -4145,6 +4150,7 @@
 <translation id="1639239467298939599">लोड हो रहा है</translation>
 <translation id="5457599981699367932">अतिथि के रूप में ब्राउज़ करें</translation>
 <translation id="6850233365366645553">आपके उपकरण को Powerwash द्वारा रीसेट किया जा सके इससे पहले पुन: प्रारंभ किया जाना आवश्यक है. Powerwash आपके <ph name="IDS_SHORT_PRODUCT_NAME"/> उपकरण को बिल्कुल नए जैसा रीसेट कर देता है.</translation>
+<translation id="4292622557427736684">एन्क्रिप्ट किए गए मीडिया एक्सटेंशन के लिए MediaDrm सक्षम करें.</translation>
 <translation id="1812514023095547458">रंग को चुनें</translation>
 <translation id="5089363139417863686">फ़ाइलें एप्स के साथ देखें</translation>
 <translation id="7047998246166230966">सूचक</translation>
@@ -4496,6 +4502,7 @@
 <translation id="1728442818359004787">डिफ़ॉल्ट एप्स बदलें...</translation>
 <translation id="7540972813190816353">अपडेट की जांच करते समय कोई त्रुटि आई: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">असमर्थित Bluetooth उपकरण: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">उपसर्ग के रूप में उपयोग नहीं किया गया मीडिया स्रोत API अक्षम करें.</translation>
 <translation id="2225024820658613551">आपको आगे नहीं बढ़ना चाहिए, &lt;strong&gt;विशेष रूप से&lt;/strong&gt; तब यदि आपने पहले कभी इस साइट के लिए यह चेतावनी नहीं देखी हो.</translation>
 <translation id="2049639323467105390">यह उपकरण <ph name="DOMAIN"/> द्वारा प्रबंधित है.</translation>
 <translation id="1932098463447129402">पहले नहीं</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb
index bac608c..5fcc736 100644
--- a/chrome/app/resources/generated_resources_hr.xtb
+++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Prikaži pravopis i gramatiku</translation>
 <translation id="7017587484910029005">Upišite znakove koje vidite na slici u nastavku.</translation>
 <translation id="9013589315497579992">Loš certifikat SSL klijentske provjere autentičnosti.</translation>
+<translation id="2085245445866855859">Aplikaciju s atributom manifesta 'kiosk_only' potrebno je instalirati u načinu kioska ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> želi trajno pohraniti podatke na vaš uređaj.</translation>
 <translation id="8524066305376229396">Stalna pohrana:</translation>
 <translation id="7567293639574541773">P&amp;regledaj element</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Zvone</translation>
 <translation id="2231238007119540260">Ako izbrišete certifikat poslužitelja, vratit ćete uobičajene sigurnosne provjere za taj poslužitelj i tražiti da koristi važeće certifikate.</translation>
 <translation id="9110235431257073974">Omogućite integraciju Web-trgovine i aplikacije Datoteke.</translation>
+<translation id="6489433341782457580">Za razvojne programere: upotrijebite uslugu testnog okruženja za pozive API-ja Novčanik za requestAutocomplete().</translation>
 <translation id="8186609076106987817">Poslužitelj nije mogao pronaći datoteku.</translation>
 <translation id="2846816712032308263">Omogućuje brzo zatvaranje kartice/prozora – pokreće rukovatelja kartice &quot;OnUnload JS&quot; neovisno o grafičkom korisničkom sučelju.</translation>
 <translation id="9134410174832249455">Proizvod <ph name="PRODUCT_NAME"/> nije mogao učitati web-stranicu jer <ph name="HOST_NAME"/> nije na vrijeme odgovorio. Web-lokacija možda je neaktivna ili možda imate problema s internetskom vezom.</translation>
@@ -345,6 +347,7 @@
 <translation id="8959810181433034287">Nadzirani korisnik morat će upotrebljavati tu zaporku za prijavu te odaberite sigurnu zaporku i raspravite o njoj s nadziranim korisnikom.</translation>
 <translation id="5154917547274118687">Memorija</translation>
 <translation id="1493492096534259649">Taj se jezik ne može koristiti za provjeru pravopisa</translation>
+<translation id="2103866351350079276">Onemogući objekt MediaSource bez prefiksa. Taj objekt omogućuje JavaScriptu slanje medijskih podataka izravno na videoelement.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Pretraživanje</translation>
 <translation id="6460423884798879930">Omogućuje opciju slanja dodatnih podataka za autentifikaciju u početnom paketu SYN za prethodno povezani klijent dopuštajući brže pokretanje slanja podataka.</translation>
 <translation id="6563261555270336410">Pojedinosti o hostu <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1575,6 +1578,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">vijetnamski</translation>
 <translation id="6423064450797205562">Mjerenja u vezi s brzinom kojom proizvod <ph name="SHORT_PRODUCT_NAME"/> izvodi tražene radnje</translation>
+<translation id="2048118585307365263">Omogući MediaDrm.</translation>
 <translation id="4091434297613116013">listova papira</translation>
 <translation id="7475671414023905704">URL Netscape izgubljene zaporke</translation>
 <translation id="3335947283844343239">Ponovo otvori zatvorenu karticu</translation>
@@ -3809,6 +3813,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> želi trajno pohraniti veliku količinu podataka na vaše lokalno računalo.</translation>
 <translation id="373572798843615002">1 kartica</translation>
 <translation id="4806065163318322702">Uključi/isključi govorni unos</translation>
+<translation id="6190185222845843088">Upotrijebi poslužitelje testnog okruženja Novčanika</translation>
 <translation id="3177048931975664371">Kliknite za skrivanje zaporke</translation>
 <translation id="5852137567692933493">Pokreni ponovo i izvrši Powerwash</translation>
 <translation id="3092544800441494315">Uključi ovu snimku zaslona:</translation>
@@ -4075,6 +4080,7 @@
 <translation id="1639239467298939599">Učitavanje</translation>
 <translation id="5457599981699367932">Pregledavaj kao gost</translation>
 <translation id="6850233365366645553">Prvo morate ponovo pokrenuti uređaj da biste ga mogli poništiti funkcijom Powerwash. Powerwash vraća vaš <ph name="IDS_SHORT_PRODUCT_NAME"/> uređaj na zadano kako bi ponovo bio kao nov.</translation>
+<translation id="4292622557427736684">Omogući MediaDrm prema zadanim postavkama za proširenja kriptiranih medija.</translation>
 <translation id="1812514023095547458">Odabir boje</translation>
 <translation id="5089363139417863686">Prikaži aplikacijom Datoteke</translation>
 <translation id="7047998246166230966">Pokazivač</translation>
@@ -4425,6 +4431,7 @@
 <translation id="1728442818359004787">Promjena zadane aplikacije...</translation>
 <translation id="7540972813190816353">Došlo je do pogreške prilikom traženja ažuriranja: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nepodržani Bluetooth uređaj: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Onemogući API Media Source bez prefiksa.</translation>
 <translation id="2225024820658613551">Ne biste trebali nastaviti, &lt;strong&gt;posebno&lt;/strong&gt; ako nikad prije niste vidjeli takvo upozorenje za tu lokaciju.</translation>
 <translation id="2049639323467105390">Ovim uređajem upravlja <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Ne prije</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb
index 2276034..052902f 100644
--- a/chrome/app/resources/generated_resources_hu.xtb
+++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Helyesírás és nyelvhelyesség megjelenítése</translation>
 <translation id="7017587484910029005">Gépelje be az alábbi képen látható karaktereket.</translation>
 <translation id="9013589315497579992">Rossz SSL-ügyfélhitelesítési tanúsítvány.</translation>
+<translation id="2085245445866855859">A „kiosk_only” jegyzékattribútummal rendelkező alkalmazást kioszk módban kell telepíteni a ChromeOS rendszeren.</translation>
 <translation id="1467999917853307373">A(z) <ph name="URL"/> webhely állandó jelleggel adatokat akar tárolni az eszközén.</translation>
 <translation id="8524066305376229396">Állandó tárhely:</translation>
 <translation id="7567293639574541773">E&amp;lem megtekintése</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Foci</translation>
 <translation id="2231238007119540260">Ha töröl egy szervertanúsítványt, akkor annál a szervernél visszaállítja a hagyományos biztonsági ellenőrzéseket, és elvárja, hogy érvényes tanúsítványt használjon.</translation>
 <translation id="9110235431257073974">Az Internetes áruház és a Files.app integrálásának engedélyezése.</translation>
+<translation id="6489433341782457580">Fejlesztők figyelmébe: requestAutocomplete() esetében használja a Wallet API-hívásokhoz tartozó tesztkörnyezeti szolgáltatást.</translation>
 <translation id="8186609076106987817">A szerver nem találta a fájlt.</translation>
 <translation id="2846816712032308263">A lapok/ablakok gyors bezárásának engedélyezése – egy lap kiürítési js-kezelőjének futtatása a GUI-tól függetlenül.</translation>
 <translation id="9134410174832249455">A <ph name="PRODUCT_NAME"/> nem tudta betölteni a weblapot, mert a(z) <ph name="HOST_NAME"/> túl későn válaszolt. Lehet, hogy a webhely leállt, vagy lehet, hogy az internetkapcsolatával vannak problémák.</translation>
@@ -346,6 +348,7 @@
 <translation id="8959810181433034287">A felügyelt felhasználónak ezt a jelszót kell használnia majd a bejelentkezéshez, úgyhogy biztonságos jelszót válasszon, és ne feledje el megbeszélni vele.</translation>
 <translation id="5154917547274118687">Memória</translation>
 <translation id="1493492096534259649">Ezen a nyelven nem használhatja a helyesírás-ellenőrzőt</translation>
+<translation id="2103866351350079276">Az előtag nélküli MediaSource objektum letiltása. Az objektum lehetővé teszi, hogy a JavaScript közvetlenül küldjön médiaadatokat a videoelemeknek.</translation>
 <translation id="6628463337424475685">Keresés: <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Lehetővé teszi plusz hitelesítési információk küldését a kezdeti SYN csomagban korábban kapcsolódott ügyfelek esetén, amivel az adatküldés gyorsabb elindítása válik lehetővé.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> részletei</translation>
@@ -1578,6 +1581,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnami</translation>
 <translation id="6423064450797205562">Annak mérőszámai, hogy a(z) <ph name="SHORT_PRODUCT_NAME"/> milyen sebességgel végzi el a kért műveleteket</translation>
+<translation id="2048118585307365263">A MediaDrm engedélyezése.</translation>
 <translation id="4091434297613116013">papírlap</translation>
 <translation id="7475671414023905704">Netscape - elveszett jelszó URL</translation>
 <translation id="3335947283844343239">Bezárt lap megnyitása</translation>
@@ -3812,6 +3816,7 @@
 <translation id="3672159315667503033">A(z) <ph name="URL"/> webhely állandó, nagy méretű adatokat akar tárolni a helyi számítógépen.</translation>
 <translation id="373572798843615002">1 lap</translation>
 <translation id="4806065163318322702">Hangbevitel be-/kikapcsolása</translation>
+<translation id="6190185222845843088">Wallet tesztkörnyezeti szerverek használata</translation>
 <translation id="3177048931975664371">Kattintson ide a jelszó elrejtéséhez</translation>
 <translation id="5852137567692933493">Újraindítás és Powerwash</translation>
 <translation id="3092544800441494315">A következő képernyőkép mellékelése:</translation>
@@ -4078,6 +4083,7 @@
 <translation id="1639239467298939599">Betöltés</translation>
 <translation id="5457599981699367932">Böngészés vendégként</translation>
 <translation id="6850233365366645553">Újra kell indítania rendszerét, mielőtt a Powerwash segítségével visszaállíthatná azt. A Powerwash alaphelyzetbe állítja <ph name="IDS_SHORT_PRODUCT_NAME"/> eszközét, mintha csak új lenne.</translation>
+<translation id="4292622557427736684">A MediaDrm alapértelmezett engedélyezése a titkosított médiabővítményekhez (Encrypted Media Extension, EME).</translation>
 <translation id="1812514023095547458">Szín kiválasztása</translation>
 <translation id="5089363139417863686">Megtekintés a Fájlok alkalmazással</translation>
 <translation id="7047998246166230966">Mutató</translation>
@@ -4428,6 +4434,7 @@
 <translation id="1728442818359004787">Alapértelmezett alkalmazás módosítása...</translation>
 <translation id="7540972813190816353">Hiba történt a frissítések keresése közben: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nem támogatott Bluetooth-eszköz: „<ph name="DEVICE_NAME"/>”.</translation>
+<translation id="2990212470195050777">Az előtag nélküli Media Source API letiltása.</translation>
 <translation id="2225024820658613551">Javasoljuk, hogy ne menjen tovább, &lt;strong&gt;különösen&lt;/strong&gt; akkor, ha ezt a figyelmeztetést még nem látta ezen a webhelyen.</translation>
 <translation id="2049639323467105390">Ezt az eszközt a(z) <ph name="DOMAIN"/> domain kezeli.</translation>
 <translation id="1932098463447129402">Ez előtt nem:</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index a3e227c..3bba5c6 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Tampilkan Ejaan dan Grammar</translation>
 <translation id="7017587484910029005">Ketik karakter yang Anda lihat dalam gambar di bawah.</translation>
 <translation id="9013589315497579992">Sertifikat autentikasi klien SSL gagal.</translation>
+<translation id="2085245445866855859">Aplikasi dengan atribut manifes 'kiosk_only' harus dipasang dalam mode kios ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> ingin menyimpan data di perangkat Anda secara permanen.</translation>
 <translation id="8524066305376229396">Penyimpanan tetap:</translation>
 <translation id="7567293639574541773">Periksa eleme&amp;n</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Ronaldo</translation>
 <translation id="2231238007119540260">Jika Anda menghapus sertifikat server, Anda akan mengembalikan pemeriksaan keamanan yang biasa untuk server dan mengharuskannya menggunakan sertifikat yang valid.</translation>
 <translation id="9110235431257073974">Aktifkan integrasi aplikasi Toko Web dan File.</translation>
+<translation id="6489433341782457580">Untuk pengembang: gunakan layanan kotak pasir untuk panggilan API Wallet untuk requestAutocomplete().</translation>
 <translation id="8186609076106987817">Server tidak dapat menemukan file.</translation>
 <translation id="2846816712032308263">Mengaktifkan penutupan cepat tab/jendela - menjalankan penangan js saat pembongkaran di tab secara terpisah dari GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> tidak dapat memuat laman web karena <ph name="HOST_NAME"/> terlalu lama merespons. Situs web mungkin sedang tidak aktif atau sambungan internet Anda bermasalah.</translation>
@@ -346,6 +348,7 @@
 <translation id="8959810181433034287">Pengguna yang diawasi harus menggunakan sandi ini untuk masuk, jadi pilih sandi yang aman dan jangan lupa untuk membicarakannya dengan pengguna yang diawasi.</translation>
 <translation id="5154917547274118687">Memori</translation>
 <translation id="1493492096534259649">Bahasa ini tidak dapat digunakan untuk pemeriksaan ejaan</translation>
+<translation id="2103866351350079276">Menonaktifkan objek MediaSource tanpa awalan. Objek ini memungkinkan JavaScript mengirimkan data media langsung ke elemen video.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Penelusuran</translation>
 <translation id="6460423884798879930">Mengaktifkan opsi untuk mengirim informasi autentikasi ekstra pada paket SYN awal bagi klien yang sebelumnya telah tersambung, mengizinkan pemulaian pengiriman data dengan lebih cepat.</translation>
 <translation id="6563261555270336410">Detail mengenai <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1582,6 +1585,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnam</translation>
 <translation id="6423064450797205562">Metrik yang terkait dengan kecepatan saat <ph name="SHORT_PRODUCT_NAME"/> melakukan tindakan yang diminta</translation>
+<translation id="2048118585307365263">Aktifkan MediaDrm.</translation>
 <translation id="4091434297613116013">lembaran kertas</translation>
 <translation id="7475671414023905704">Netscape Lost Password URL</translation>
 <translation id="3335947283844343239">Buka Kembali Tab yang Tertutup</translation>
@@ -3821,6 +3825,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> ingin menyimpan data besar pada komputer lokal Anda secara permanen.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">Menghidupkan/mematikan masukan ucapan</translation>
+<translation id="6190185222845843088">Gunakan server kotak pasir Wallet</translation>
 <translation id="3177048931975664371">Klik untuk menyembunyikan sandi</translation>
 <translation id="5852137567692933493">Mulai Ulang dan Powerwash</translation>
 <translation id="3092544800441494315">Sertakan tangkapan layar ini:</translation>
@@ -4087,6 +4092,7 @@
 <translation id="1639239467298939599">Memuat</translation>
 <translation id="5457599981699367932">Jelajahi sebagai Tamu</translation>
 <translation id="6850233365366645553">Dibutuhkan memulai ulang sebelum perangkat Anda dapat disetel ulang dengan Powerwash. Powerwash menyetel ulang perangkat <ph name="IDS_SHORT_PRODUCT_NAME"/> Anda kembali seperti baru.</translation>
+<translation id="4292622557427736684">Mengaktifkan MediaDrm secara default untuk Ekstensi Media Terenkripsi.</translation>
 <translation id="1812514023095547458">Pilih Warna</translation>
 <translation id="5089363139417863686">Lihat dengan aplikasi File</translation>
 <translation id="7047998246166230966">Penunjuk</translation>
@@ -4132,7 +4138,7 @@
 <translation id="2202898655984161076">Ada masalah dengan pencantuman printer. Beberapa printer Anda mungkin tidak berhasil didaftarkan ke <ph name="CLOUD_PRINT_NAME"/>.</translation>
 <translation id="6154697846084421647">Saat ini telah masuk</translation>
 <translation id="8241707690549784388">Laman yang dicari menggunakan informasi yang Anda masukkan. Kembali ke laman tersebut dapat menyebabkan pengulangan tindakan apapun yang Anda lakukan. Apakah Anda ingin melanjutkan?</translation>
-<translation id="5359419173856026110">Menunjukkan rasio bingkai laman yang sebenarnya, dalam bingkai per detik, saat akselerasi perangkat keras diaktifkan.</translation>
+<translation id="5359419173856026110">Menunjukkan frekuensi gambar laman yang sebenarnya, dalam bingkai per detik, saat akselerasi perangkat keras diaktifkan.</translation>
 <translation id="4104163789986725820">E&amp;kspor...</translation>
 <translation id="380408572480438692">Mengaktifkan koleksi data kinerja akan membantu meningkatkan sistem sepanjang waktu. Tidak ada data yang terkirim hingga mengajukan laporan masukan (Alt-Shift-I) dan menyertakan data kinerja. Anda dapat kembali ke layar ini untuk menonaktifkan koleksi kapan saja.</translation>
 <translation id="2113479184312716848">Buka &amp;Berkas...</translation>
@@ -4436,6 +4442,7 @@
 <translation id="1728442818359004787">Ubah aplikasi default...</translation>
 <translation id="7540972813190816353">Terjadi kesalahan saat memeriksa untuk pembaruan: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Perangkat Bluetooth tidak didukung: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Menonaktifkan API Sumber Media tanpa awalan.</translation>
 <translation id="2225024820658613551">Anda tidak boleh melanjutkan, &lt;strong&gt;khususnya&lt;/strong&gt; jika peringatan ini belum pernah ditampilkan untuk situs ini.</translation>
 <translation id="2049639323467105390">Perangkat ini dikelola oleh <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Tidak Sebelum</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb
index 423a5de..4bc1436 100644
--- a/chrome/app/resources/generated_resources_it.xtb
+++ b/chrome/app/resources/generated_resources_it.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Mostra ortografia e grammatica</translation>
 <translation id="7017587484910029005">Digita i caratteri che vedi nella seguente immagine.</translation>
 <translation id="9013589315497579992">Certificato di autenticazione client SSL non corretto.</translation>
+<translation id="2085245445866855859">L'app con l'attributo del file manifest &quot;kiosk_only&quot; deve essere installata in modalità kiosk ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vuole memorizzare in modo permanente i dati sul tuo dispositivo.</translation>
 <translation id="8524066305376229396">Archiviazione persistente:</translation>
 <translation id="7567293639574541773">Ispeziona eleme&amp;nto</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Holly</translation>
 <translation id="2231238007119540260">Se elimini un certificato server, ripristini i normali controlli di protezione del server e richiedi l'utilizzo di un certificato valido per il server.</translation>
 <translation id="9110235431257073974">Attiva l'integrazione di Webstore e Files.app.</translation>
+<translation id="6489433341782457580">Per gli sviluppatori. Consente di utilizzare il servizio sandbox per le chiamate all'API di Wallet relative a requestAutocomplete().</translation>
 <translation id="8186609076106987817">Impossibile trovare il file sul server.</translation>
 <translation id="2846816712032308263">Consente la chiusura veloce di schede/finestre - viene eseguito il gestore onunload js di una scheda indipendentemente dalla GUI.</translation>
 <translation id="9134410174832249455">Impossibile caricare la pagina web su <ph name="PRODUCT_NAME"/> perché <ph name="HOST_NAME"/> ha impiegato troppo tempo per rispondere. Il sito web potrebbe non essere disponibile o potrebbero esserci problemi con la connessione Internet.</translation>
@@ -350,6 +352,7 @@
 <translation id="8959810181433034287">L'utente supervisionato dovrà utilizzare la password specificata per eseguire l'accesso, pertanto scegli una password sicura e ricordati di parlarne con l'utente supervisionato.</translation>
 <translation id="5154917547274118687">Memoria</translation>
 <translation id="1493492096534259649">Impossibile utilizzare questa lingua per il controllo ortografico</translation>
+<translation id="2103866351350079276">Consente di disattivare l'oggetto MediaSource senza prefisso, che consente a JavaScript di inviare i dati multimediali direttamente a un elemento video.</translation>
 <translation id="6628463337424475685">Ricerca <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Attiva l'opzione per inviare informazioni di autenticazione aggiuntive nel pacchetto SYN iniziale per un client precedentemente connesso, consentendo un avvio dell'invio dei dati più veloce.</translation>
 <translation id="6563261555270336410">Dettagli su <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1575,6 +1578,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Metriche relative alla velocità con cui <ph name="SHORT_PRODUCT_NAME"/> esegue le azioni richieste</translation>
+<translation id="2048118585307365263">Attiva MediaDrm.</translation>
 <translation id="4091434297613116013">fogli</translation>
 <translation id="7475671414023905704">URL password persa Netscape</translation>
 <translation id="3335947283844343239">Riapri scheda chiusa</translation>
@@ -2906,7 +2910,7 @@
 <translation id="8691686986795184760">(Attivato in base a norma aziendale)</translation>
 <translation id="878763818693997570">Il nome è troppo lungo</translation>
 <translation id="1976323404609382849">Sono stati bloccati cookie provenienti da più siti.</translation>
-<translation id="7913678092679498828">OK, ricevuto.</translation>
+<translation id="7913678092679498828">OK</translation>
 <translation id="3655670868607891010">Se questo problema si verifica spesso, prova questi <ph name="HELP_LINK"/>.</translation>
 <translation id="4504940961672722399">Utilizza questa estensione facendo clic su questa icona o premendo <ph name="EXTENSION_SHORTCUT"/>.</translation>
 <translation id="2523966157338854187">Apri una pagina specifica o un insieme di pagine.</translation>
@@ -3801,6 +3805,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vuole memorizzare in modo permanente grandi quantità di dati sul computer locale.</translation>
 <translation id="373572798843615002">1 scheda</translation>
 <translation id="4806065163318322702">Attiva/disattiva ingresso voce</translation>
+<translation id="6190185222845843088">Utilizza server sandbox di Wallet</translation>
 <translation id="3177048931975664371">Fai clic per nascondere la password</translation>
 <translation id="5852137567692933493">Riavvia ed esegui Powerwash</translation>
 <translation id="3092544800441494315">Includi questo screenshot:</translation>
@@ -4065,6 +4070,7 @@
 <translation id="1639239467298939599">Caricamento</translation>
 <translation id="5457599981699367932">Esplora come ospite</translation>
 <translation id="6850233365366645553">È necessario riavviare prima che il dispositivo possa essere ripristinato con un Powerwash. Un Powerwash ripristina il tuo dispositivo <ph name="IDS_SHORT_PRODUCT_NAME"/> facendolo tornare come nuovo.</translation>
+<translation id="4292622557427736684">Consente di attivare per impostazione predefinita MediaDrm per Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Seleziona colore</translation>
 <translation id="5089363139417863686">Visualizza con l'app File</translation>
 <translation id="7047998246166230966">Puntatore</translation>
@@ -4414,6 +4420,7 @@
 <translation id="1728442818359004787">Cambia applicazione predefinita...</translation>
 <translation id="7540972813190816353">Si è verificato un errore durante il controllo della disponibilità di aggiornamenti: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositivo Bluetooth non supportato: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Disattiva API Media Source senza prefisso.</translation>
 <translation id="2225024820658613551">Non procedere oltre, &lt;strong&gt;soprattutto&lt;/strong&gt; se questo avviso non è mai stato visualizzato per questo sito.</translation>
 <translation id="2049639323467105390">Questo dispositivo è gestito da <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Non prima</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index b873068..7bb89bc 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">הצג איות ודקדוק</translation>
 <translation id="7017587484910029005">הקלד למטה את התווים הבאים.</translation>
 <translation id="9013589315497579992">‏אישור אימות לקוח SSL פגום.</translation>
+<translation id="2085245445866855859">‏יש להתקין יישומים עם מאפיין המניפסט 'kiosk_only' רק במצב קיוסק של מערכת ההפעלה של Chrome.</translation>
 <translation id="1467999917853307373">אפליקציית האינטרנט <ph name="URL"/> מבקשת לאחסן נתונים במכשיר שלך באופן קבוע.</translation>
 <translation id="8524066305376229396">אחסון קבוע:</translation>
 <translation id="7567293639574541773">בדוק מרכיב</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">מסי</translation>
 <translation id="2231238007119540260">אם אתה מוחק אישור שרת, אתה משחזר את בדיקות האבטחה הרגילות לשרת זה ודורש שהוא ישתמש באישור חוקי.</translation>
 <translation id="9110235431257073974">אפשר שילוב של חנות האינטרנט עם היישום 'קבצים'.</translation>
+<translation id="6489433341782457580">‏למפתחים: השתמשו בשירות ארגז החול לקריאות ממשק ה-API של 'ארנק' עבור requestAutocomplete()‎.</translation>
 <translation id="8186609076106987817">השרת לא הצליח למצוא את הקובץ.</translation>
 <translation id="2846816712032308263">‏אפשרות לסגירה מהירה של כרטיסיות/חלונות -הפעלת המטפל onunload js של כרטיסייה בנפרד מממשק המשתמש הגרפי (GUI).</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> לא הצליח לטעון את דף האינטרנט משום שזמן התגובה של <ph name="HOST_NAME"/> היה ארוך מדי. ייתכן שהאתר מושבת או שיש בעיות עם החיבור לאינטרנט.</translation>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">המשתמש המבוקר יצטרך להשתמש בסיסמה זו כדי להיכנס, לכן בחר סיסמה בטוחה וזכור ליידע את המשתמש המבוקר.</translation>
 <translation id="5154917547274118687">זיכרון</translation>
 <translation id="1493492096534259649">לא ניתן להשתמש בשפה זו לבדיקת איות</translation>
+<translation id="2103866351350079276">‏השבת את אובייקט MediaSource המופיע ללא תחילית. האובייקט הזה מאפשר ל-JavaScript לשלוח נתוני מדיה ישירות לרכיב וידאו.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> חיפוש</translation>
 <translation id="6460423884798879930">‏הפעל את האפשרות לשלוח מידע נוסף לאימות במנת ה-SYN הראשונה עבור לקוח שכבר התחבר בעבר, כדי לאפשר התחלה של שליחת נתונים מהירה.</translation>
 <translation id="6563261555270336410">פרטים על <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1589,6 +1592,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> ‏[<ph name="ISSUED_TO"/>]‏</translation>
 <translation id="8899388739470541164">וייאטנאמית</translation>
 <translation id="6423064450797205562">מדדים המתייחסים למהירות שבה <ph name="SHORT_PRODUCT_NAME"/> מבצע פעולות מבוקשות</translation>
+<translation id="2048118585307365263">‏הפעל את MediaDrm.</translation>
 <translation id="4091434297613116013">גליונות נייר</translation>
 <translation id="7475671414023905704">‏כתובת אתר לסיסמה שאבדה של Netscape</translation>
 <translation id="3335947283844343239">פתח מחדש כרטיסייה שנסגרה</translation>
@@ -1619,7 +1623,7 @@
 <translation id="1397674396541164684">‏בטל הנפשות CSS מואצות</translation>
 <translation id="7124398136655728606">‏Esc מנקה את כל המאגר של טרום-עריכה</translation>
 <translation id="3344786168130157628">שם נקודת הגישה:</translation>
-<translation id="8293206222192510085">הוסף סימנייה</translation>
+<translation id="8293206222192510085">הוסף סימניה</translation>
 <translation id="2592884116796016067">‏חלק מדף זה (HTML WebWorker) קרס וייתכן שלא יפעל כראוי.</translation>
 <translation id="2529133382850673012">מקלדת אנגלית (ארה&quot;ב)</translation>
 <translation id="4411578466613447185">חותם קוד</translation>
@@ -3817,6 +3821,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> רוצה לאחסן נתונים גדולים במחשב המקומי שלך באופן קבוע.</translation>
 <translation id="373572798843615002">כרטיסייה 1</translation>
 <translation id="4806065163318322702">הפעל או השבת דיבור</translation>
+<translation id="6190185222845843088">‏השתמש בשרתי ארגז החול של ארנק Google</translation>
 <translation id="3177048931975664371">לחץ כדי להסתיר את הסיסמה</translation>
 <translation id="5852137567692933493">‏הפעל מחדש ובצע פעולת Powerwash</translation>
 <translation id="3092544800441494315">כלול צילום מסך זה:</translation>
@@ -4086,6 +4091,7 @@
 <translation id="1639239467298939599">טוען</translation>
 <translation id="5457599981699367932">גלוש כאורח</translation>
 <translation id="6850233365366645553">‏יש לבצע אתחול לפני שניתן יהיה לאפס את המכשיר באמצעות Powerwash‏. Powerash מאפס את מכשיר ה-<ph name="IDS_SHORT_PRODUCT_NAME"/> שלך כך שיהיה כמו חדש.</translation>
+<translation id="4292622557427736684">‏הפעל את MediaDrm כברירת מחדל עבור תוספי מדיה מוצפנים.</translation>
 <translation id="1812514023095547458">בחר צבע</translation>
 <translation id="5089363139417863686">הצג באמצעות יישום הקבצים</translation>
 <translation id="7047998246166230966">מצביע</translation>
@@ -4436,6 +4442,7 @@
 <translation id="1728442818359004787">שנה את יישום ברירת המחדל...</translation>
 <translation id="7540972813190816353">אירעה שגיאה בעת בדיקת עדכונים: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">‏מכשיר Bluetooth שאינו נתמך: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">‏השבת את ממשק ה-API של Media Source המופיע ללא תחילית.</translation>
 <translation id="2225024820658613551">‏מומלץ לא להמשיך, &lt;strong&gt;במיוחד&lt;/strong&gt; אם לא ראית בעבר את האזהרה הזו לגבי האתר.</translation>
 <translation id="2049639323467105390">מכשיר זה מנוהל על ידי <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">לא לפני</translation>
@@ -4690,7 +4697,7 @@
 <translation id="1732215134274276513">בטל הצמדה של כרטיסיות</translation>
 <translation id="4785040501822872973">מחשב זה יופעל מחדש בעוד <ph name="LOGOUT_TIME_LEFT"/> שניות.
 הקש על מקש כלשהו כדי להמשיך בסיור.</translation>
-<translation id="4084682180776658562">סימנייה</translation>
+<translation id="4084682180776658562">סימניה</translation>
 <translation id="8859057652521303089">בחר שפה:</translation>
 <translation id="5941864346249299673">מספר הבייטים שנקראו בכל הרשת</translation>
 <translation id="7243388728764696895">כרטיסייה חדשה - מכשירים אחרים</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 656a5dd..8cab0f6 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">スペルと文法を表示</translation>
 <translation id="7017587484910029005">下記の画像に表示されている文字を入力してください。</translation>
 <translation id="9013589315497579992">SSL クライアント認証証明書が不正です。</translation>
+<translation id="2085245445866855859">マニフェスト属性が kiosk_only のアプリをインストールするには ChromeOS でキオスク モードを有効にする必要があります。</translation>
 <translation id="1467999917853307373"><ph name="URL"/> がお使いの端末への永続的なデータ保存を必要としています。</translation>
 <translation id="8524066305376229396">永続的ストレージ:</translation>
 <translation id="7567293639574541773">要素を検証(&amp;N)</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">フリッツ</translation>
 <translation id="2231238007119540260">サーバー証明書を削除すると、そのサーバーの通常のセキュリティ チェックを復活させることになり、サーバーは正当な証明書を使用することが必要となります。</translation>
 <translation id="9110235431257073974">ウェブストアと Files.app の統合を有効にする。</translation>
+<translation id="6489433341782457580">デベロッパー向け: Wallet API で requestAutocomplete() を呼び出す場合はサンドボックス サービスをご利用ください。</translation>
 <translation id="8186609076106987817">お探しのファイルはサーバーにはありません。</translation>
 <translation id="2846816712032308263">タブ/ウィンドウを高速に閉じられるようにします(タブの onunload js ハンドラを GUI とは別に実行します)。</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/> からの応答が遅いため、<ph name="PRODUCT_NAME"/> ではウェブページの読み込みができませんでした。ウェブサイトがダウンしているか、インターネット接続に問題が発生している可能性があります。</translation>
@@ -351,6 +353,7 @@
 <translation id="8959810181433034287">監視対象ユーザーは、ログインするときにこのパスワードを使用する必要があります。そのため、安全なパスワードを選んでください。また、必ず監視対象ユーザー本人にも相談してください。</translation>
 <translation id="5154917547274118687">メモリ</translation>
 <translation id="1493492096534259649">この言語はスペルチェックに使用できません</translation>
+<translation id="2103866351350079276">プレフィックスなしの MediaSource オブジェクトを無効にします。このオブジェクトを有効にすると、JavaScript を使用してメディア データを video 要素に直接送信できます。</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> 検索</translation>
 <translation id="6460423884798879930">以前接続したクライアントの認証情報を最初の SYN パケットで送信し、データ送信が迅速に開始されるようにするには、このオプションを有効にします。</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> の詳細</translation>
@@ -1256,7 +1259,7 @@
 <translation id="14171126816530869"><ph name="LOCALITY"/> の <ph name="ORGANIZATION"/> の ID は、<ph name="ISSUER"/> によって確認済みです。</translation>
 <translation id="220858061631308971">「<ph name="DEVICE_NAME"/>」の PIN コードを入力してください:</translation>
 <translation id="6263082573641595914">Microsoft CA バージョン</translation>
-<translation id="953345106084818179">許可を要求</translation>
+<translation id="953345106084818179">許可をリクエスト</translation>
 <translation id="3105917916468784889">スクリーンショットを撮る</translation>
 <translation id="6000902307058248087">マイクへのアクセスをサイトが要求するたびに確認する(推奨)</translation>
 <translation id="1587275751631642843">JavaScript コンソール(&amp;J)</translation>
@@ -1588,6 +1591,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">ベトナム語</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> が要求された操作を実行する速度に関連する指標</translation>
+<translation id="2048118585307365263">MediaDrm を有効にする</translation>
 <translation id="4091434297613116013">用紙</translation>
 <translation id="7475671414023905704">Netscape パスワード紛失 URL</translation>
 <translation id="3335947283844343239">閉じたタブを開く</translation>
@@ -2832,7 +2836,7 @@
 <translation id="5618018737832496935">「adview」要素を有効にする</translation>
 <translation id="8190193592390505034"><ph name="PROVIDER_NAME"/> に接続中</translation>
 <translation id="2433452467737464329">ページを自動更新するには URL に次のようなクエリ パラメータを追加してください: chrome://network/?refresh=&lt;sec&gt;</translation>
-<translation id="8712637175834984815">了解</translation>
+<translation id="8712637175834984815">閉じる</translation>
 <translation id="6144890426075165477">現在、<ph name="PRODUCT_NAME"/> は既定のブラウザに設定されていません。</translation>
 <translation id="4068506536726151626">このページには、あなたの現在地を追跡している以下のサイトからの要素が含まれています。</translation>
 <translation id="4220128509585149162">クラッシュ</translation>
@@ -2883,7 +2887,7 @@
 <translation id="7525067979554623046">作成</translation>
 <translation id="4853020600495124913">新しいウィンドウで開く(&amp;N)</translation>
 <translation id="6847758263950452722">MHTML としてページを保存</translation>
-<translation id="4217998989792742258">これは <ph name="CUSTODIAN_EMAIL"/> によって管理されている監視対象ユーザーです</translation>
+<translation id="4217998989792742258"><ph name="CUSTODIAN_EMAIL"/> によって管理される監視対象ユーザー</translation>
 <translation id="4711094779914110278">トルコ語</translation>
 <translation id="5121130586824819730">ハード ディスクがいっぱいです。別の場所に保存するか、ハード ディスクの空き容量を増やしてください。</translation>
 <translation id="7643802497509977994">「<ph name="FROM_LOCALE"/>」に戻す(ログアウトが必要です)</translation>
@@ -3254,7 +3258,7 @@
 <translation id="8891727572606052622">プロキシ モードが無効です。</translation>
 <translation id="8813873272012220470">互換性のないソフトウェアが検出されたときに警告するためのバックグラウンド チェックを有効にします(たとえば、ブラウザのクラッシュの原因となるサードパーティ モジュールが検出されると警告します)。</translation>
 <translation id="3660234220361471169">信頼されていない</translation>
-<translation id="3504669335572969216"><ph name="CUSTODIAN_EMAIL"/> によって管理されている監視対象ユーザーです。
+<translation id="3504669335572969216"><ph name="CUSTODIAN_EMAIL"/> によって管理される監視対象ユーザー
 アカウントのログイン詳細が最新のものではありません。</translation>
 <translation id="2679385451463308372">システム ダイアログを使用して印刷...</translation>
 <translation id="959890390740139744">スペルミスの自動修正</translation>
@@ -3848,6 +3852,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> では、大容量のデータをローカル コンピュータに永続的に保存することを要求しています。</translation>
 <translation id="373572798843615002">タブ(1)</translation>
 <translation id="4806065163318322702">音声認識を切り替える</translation>
+<translation id="6190185222845843088">ウォレットのサンドボックス サーバーを使用する</translation>
 <translation id="3177048931975664371">クリックしてパスワードを隠す</translation>
 <translation id="5852137567692933493">再起動して Powerwash を実行する</translation>
 <translation id="3092544800441494315">このスクリーンショットを含める:</translation>
@@ -4115,6 +4120,7 @@
 <translation id="1639239467298939599">読み込み中</translation>
 <translation id="5457599981699367932">ゲストとしてブラウジング</translation>
 <translation id="6850233365366645553">Powerwash でデバイスをリセットするには、その前に再起動が必要です。Powerwash を実行すると、お使いの <ph name="IDS_SHORT_PRODUCT_NAME"/> デバイスは出荷時と同じ状態にリセットされます。</translation>
+<translation id="4292622557427736684">Encrypted Media Extensions に対して MediaDrm をデフォルトで有効にします。</translation>
 <translation id="1812514023095547458">色を選択</translation>
 <translation id="5089363139417863686">ファイル アプリで表示</translation>
 <translation id="7047998246166230966">ポインタ</translation>
@@ -4465,6 +4471,7 @@
 <translation id="1728442818359004787">デフォルトのアプリを変更...</translation>
 <translation id="7540972813190816353">更新の確認中にエラーが発生しました: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">サポートされていない Bluetooth デバイス: 「<ph name="DEVICE_NAME"/>」</translation>
+<translation id="2990212470195050777">プレフィックスなしの Media Source API を無効にする</translation>
 <translation id="2225024820658613551">先に進まないでください。このサイトについて今回初めてこの警告メッセージが表示された場合は&lt;strong&gt;特に&lt;/strong&gt;注意が必要です。</translation>
 <translation id="2049639323467105390">この端末は <ph name="DOMAIN"/> によって管理されています。</translation>
 <translation id="1932098463447129402">開始時刻</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index 9515de2..85bc99d 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -135,6 +135,7 @@
 <translation id="1589055389569595240">ಕಾಗುಣಿತ ಮತ್ತು ವ್ಯಾಕರಣ ತೋರಿಸು</translation>
 <translation id="7017587484910029005">ಕೆಳಗೆ ಕಾಣುವ ಚಿತ್ರದಲ್ಲಿನ ಅಕ್ಷರಗಳನ್ನು ಬೆರಳಚ್ಚಿಸಿ.</translation>
 <translation id="9013589315497579992">ಕೆಟ್ಟ SSL ಗ್ರಾಹಕ ಪ್ರಮಾಣೀಕರಣ ಪ್ರಮಾಣಪತ್ರ.</translation>
+<translation id="2085245445866855859">ChromeOS ಕಿಯೋಸ್ಕ್ ಮೋಡ್‌ನಲ್ಲಿ 'kiosk_only' ಮ್ಯಾನಿಫೆಸ್ಟ್‌ ಲಕ್ಷಣದ ಜೊತೆಗಿನ ಅಪ್ಲಿಕೇಶನ್‌ ಸ್ಥಾಪಿಸಿರಬೇಕು.</translation>
 <translation id="1467999917853307373">ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಡೇಟಾವನ್ನು ಶಾಶ್ವತವಾಗಿ ಸಂಗ್ರಹಿಸಲು <ph name="URL"/> ಬಯಸಿದೆ.</translation>
 <translation id="8524066305376229396">ಶಾಶ್ವತವಾಗಿರುವ ಸಂಗ್ರಹಣೆ:</translation>
 <translation id="7567293639574541773">ಅಂಶಗಳನ್ನು ಪರಿ&amp;ಶೀಲನೆ</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">ಫ್ರಿಟ್ಜ್</translation>
 <translation id="2231238007119540260">ನೀವು ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಅಳಿಸಿದರೆ, ನೀವು ಸಾಮಾನ್ಯ ಭದ್ರತೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಆ ಸರ್ವರ್‌ಗಾಗಿ ನೀವು ಮರುಸಂಗ್ರಹಿಸುತ್ತೀರಿ ಮತ್ತು ಅದು ಮಾನ್ಯ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಬಳಸುವುದು ಅಗತ್ಯವಾಗಿರುತ್ತದೆ.</translation>
 <translation id="9110235431257073974">ವೆಬ್‌ಸ್ಟೋರ್ ಮತ್ತು Files.app ನ ಸಮಗ್ರೀಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
+<translation id="6489433341782457580">ಡೆವಲಪರ್‌ಗಳಿಗೆ: requestAutocomplete() ಗಾಗಿ ವ್ಯಾಲೆಟ್ API ಕರೆಗಳಿಗೆ ಸ್ಯಾಂಡ್‌ಬಾಕ್ಸ್‌ ಸೇವೆ ಬಳಸಿ.</translation>
 <translation id="8186609076106987817">ಸರ್ವರ್‌ಗೆ ಫೈಲ್ ಅನ್ನು ಕಂಡುಹಿಡಿಯಲಾಗಲಿಲ್ಲ.</translation>
 <translation id="2846816712032308263">ವೇಗವಾದ ಟ್ಯಾಬ್/ವಿಂಡೋ ಮುಚ್ಚುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ - runs a tab's onunload js handler independently of the GUI.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">ಸೈನ್ ಇನ್ ಮಾಡಬೇಕಾದರೆ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡುವ ಬಳಕೆದಾರರು ಈ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಬಳಸಬೇಕಾದ ಅಗತ್ಯವಿದೆ, ಹಾಗಾಗಿ ಸುರಕ್ಷಿತ ಪಾಸ್‌ವರ್ಡ್ ಆರಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ಇದನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡುವ ಬಳಕೆದಾರರೊಂದಿಗೆ ಚರ್ಚಿಸಲು ಮರೆಯದಿರಿ.</translation>
 <translation id="5154917547274118687">ಸ್ಮರಣೆ</translation>
 <translation id="1493492096534259649">ಈ ಭಾಷೆಯನ್ನು ಕಾಗುಣಿತ ಪರಿಶೀಲನೆಗಾಗಿ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ</translation>
+<translation id="2103866351350079276">ಪೂರ್ವನಿಯೋಜಿತವಲ್ಲದ MediaSource ವಸ್ತುವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ. ಈ ವಸ್ತುವು ವೀಡಿಯೊ ಅಂಶವೊಂದಕ್ಕೆ ನೇರವಾಗಿ ಮಾಧ್ಯಮ ಡೇಟಾ ಕಳುಹಿಸಲು JavaScript ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> ಹುಡುಕಾಟ</translation>
 <translation id="6460423884798879930">ಈ ಹಿಂದೆ ಸಂಪರ್ಕಗೊಳಿಸಲಾದ ಕ್ಲೈಂಟ್‌ಗಾಗಿ ಇರುವ ಪ್ರಾರಂಭಿಕ SYN ಪ್ಯಾಕೆಟ್‌ನಲ್ಲಿರುವ ಹೆಚ್ಚುವರಿ ದೃಢೀಕರಣ ಮಾಹಿತಿಯನ್ನು ಕಳುಹಿಸಲು ಆಯ್ಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ, ಈ ಮೂಲಕ ವೇಗವಾದ ಡೇಟಾ ಕಳುಹಿಸುವಿಕೆ ಪ್ರಾರಂಭಿಸಲು ಅನುಮತಿಸುತ್ತದೆ.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> ಕುರಿತು ವಿವರಗಳು</translation>
@@ -832,9 +835,9 @@
 <translation id="7550830279652415241">bookmarks_<ph name="DATESTAMP"/>.html</translation>
 <translation id="3127360977178108225">ಅತಿಥಿ ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸು</translation>
 <translation id="6327653052522436195">ನಗರ</translation>
-<translation id="164814987133974965">ನಿಮ್ಮ ಮಾರ್ಗದರ್ಶನದೊಂದಿಗೆ ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರು ವೆಬ್‌ ಅನ್ನು ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಮಾಡಬಹುದು. ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರ ನಿರ್ವಾಹಕರಂತೆ ನೀವು
+<translation id="164814987133974965">ಮೇಲ್ವಿಚಾರಕ ಬಳಕೆದಾರರು ನಿಮ್ಮ ಮಾರ್ಗದರ್ಶನದೊಂದಿಗೆ ವೆಬ್‌ ಅನ್ನು ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಮಾಡಬಹುದು. ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರ ನಿರ್ವಾಹಕರಂತೆ ನೀವು
     ಕೆಲವು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು <ph name="BEGIN_BOLD"/>ಅನುಮತಿಸಬಹುದು ಅಥವಾ ನಿಷೇಧಿಸಬಹುದು<ph name="END_BOLD"/>,
-    ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ಭೇಟಿ ನೀಡಿದ ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು <ph name="BEGIN_BOLD"/>ವಿಮರ್ಶೆ<ph name="END_BOLD"/> ಮಾಡಬಹುದು, ಮತ್ತು
+    ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ಭೇಟಿ ನೀಡಿದ ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು <ph name="BEGIN_BOLD"/>ವಿಮರ್ಶೆ<ph name="END_BOLD"/> ಮಾಡಬಹುದು ಮತ್ತು
     ಇತರೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು <ph name="BEGIN_BOLD"/>ನಿರ್ವಹಿಸಬಹುದು<ph name="END_BOLD"/>.</translation>
 <translation id="6828153365543658583">ಕೆಳಗಿನ ಬಳಕೆದಾರರಿಗೆ ಸೈನ್-ಇನ್ ಮಾಡುವುದನ್ನು ನಿರ್ಬಂಧಿಸು:</translation>
 <translation id="8106045200081704138">ನನ್ನೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗಿದ್ದು</translation>
@@ -1402,11 +1405,11 @@
 <translation id="4249248555939881673">ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಕ್ಕಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="8651130890368571179">ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರು ನಿಮ್ಮ ಮಾರ್ಗದರ್ಶನದೊಂದಿಗೆ ವೆಬ್ ಅನ್ನು ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಮಾಡಬಹುದು. Chrome ನಲ್ಲಿನ ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರ ನಿರ್ವಾಹಕರಾಗಿ, ನೀವು
 
- • ನಿರ್ದಿಷ್ಟ ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಅನುಮತಿಸಬಹುದು ಅಥವಾ ನಿಷೇಧಿಸಬಹುದು,
+ • ನಿರ್ದಿಷ್ಟ ವೆಬ್‌ಸೈಟ್‌ಗಳಿಗೆ ಅನುಮತಿ ನೀಡಬಹುದು ಅಥವಾ ಅವುಗಳನ್ನು ನಿಷೇಧಿಸಬಹುದು,
  • ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ಭೇಟಿ ನೀಡಿದ ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಬಹುದು, ಮತ್ತು
  • ಇತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಬಹುದು.
 
-ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರನ್ನು ರಚಿಸುವುದರಿಂದ Google ಖಾತೆಯನ್ನು ರಚಿಸುವುದಿಲ್ಲ, ಮತ್ತು ಅದರ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಡೇಟಾ Chrome ಸಿಂಕ್‌ನೊಂದಿಗೆ ಇತರ ಸಾಧನಗಳಿಗೆ ಅದನ್ನು ಅನುಸರಿಸುವುದಿಲ್ಲ. ಪ್ರಸ್ತುತವಾಗಿ, ಈ ಸಾಧನದಲ್ಲಿ, Chrome ನ ಈ ಸ್ಥಾಪನೆಗೆ ಮಾತ್ರ ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ಅನ್ವಯವಾಗುತ್ತಾರೆ.
+ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಿದ ಕಾರಣಕ್ಕೆ Google ಖಾತೆಯನ್ನೂ ರಚಿಸಿದಂತಾಗುವುದಿಲ್ಲ. ಅದರ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಡೇಟಾ Chrome ಸಿಂಕ್‌ನೊಂದಿಗೆ ಇತರ ಸಾಧನಗಳಿಗೆ ಅದನ್ನು ಅನುಸರಿಸುವುದಿಲ್ಲ. ಸದ್ಯಕ್ಕೆ, ಈ ಸಾಧನದಲ್ಲಿ, Chrome ನ ಈ ಸ್ಥಾಪನೆಗೆ ಮಾತ್ರ ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ಅನ್ವಯವಾಗುತ್ತಾರೆ.
       
 ನೀವು ಹೊಸ ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಿದ ನಂತರ, ನೀವು www.chrome.com/manage ನಲ್ಲಿ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ, ಯಾವುದೇ ಸಾಧನದಿಂದ ಅವರ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಬಹುದು.</translation>
 <translation id="2409527877874991071">ಒಂದು ಹೊಸ ಹೆಸರನ್ನು ನಮೂದಿಸಿ</translation>
@@ -1598,6 +1601,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">ವಿಯೆಟ್ನಾಮೀಸ್</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> ನೊಂದಿಗಿನ ವೇಗಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಮೆಟ್ರಿಕ್‌ಗಳ ಕಾರ್ಯಾಚರಣೆಯ ವಿನಂತಿಯ ಕ್ರಿಯೆಗಳು</translation>
+<translation id="2048118585307365263">MediaDrm ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="4091434297613116013">ಕಾಗದದ ಹಾಳೆಗಳು</translation>
 <translation id="7475671414023905704">Netscape ಕಳೆದು ಹೋದ ಪಾಸ್‌ವರ್ಡ್ URL</translation>
 <translation id="3335947283844343239">ಮುಚ್ಚಿದ ಟ್ಯಾಬ್ ಮತ್ತೆತೆರೆಯಿರಿ</translation>
@@ -2850,7 +2854,7 @@
 <translation id="2912905526406334195">ನಿಮ್ಮ ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು <ph name="HOST"/> ಬಳಸಬೇಕೆಂದು ಬಯಸುತ್ತದೆ.</translation>
 <translation id="2805756323405976993">ಅಪ್ಲಿಕೇಶನ್‌ಗಳು</translation>
 <translation id="1608626060424371292">ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಿ</translation>
-<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> ಅನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರಂತೆ ರಚಿಸಲಾಗಿದೆ!</translation>
+<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> ಅವರನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರಾಗಿ ರಚಿಸಲಾಗಿದೆ!</translation>
 <translation id="3651020361689274926">ವಿನಂತಿಸಿದ ಸಂಪನ್ಮೂಲವು ಅಸ್ತಿತ್ವದಲ್ಲಿ ಇದ್ದಂತಿಲ್ಲ, ಹಾಗೂ ಯಾವ ಫಾರ್ವರ್ಡ್‌ ಮಾಡುವ ವಿಳಾಸವೂ ಇಲ್ಲ. ಇದು ಶಾಶ್ವತ ಸ್ಥಿತಿ ಎಂದು ಭಾವಿಸಲಡ್ಡಿಯಿಲ್ಲ. </translation>
 <translation id="7541236596838501870">ಅಪ್‌ಲೋಡ್‌ ಮಾಡಿರುವ WebRTC ಲಾಗ್‌ಗಳು (<ph name="WEBRTC_LOG_COUNT"/>)</translation>
 <translation id="6003284010415283671">ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸೇರಿಸಿ</translation>
@@ -3135,7 +3139,7 @@
 <translation id="6615455863669487791">ನನಗೆ ತೋರಿಸಿ</translation>
 <translation id="3543393733900874979">ನವೀಕರಣ ವಿಫಲವಾಗಿದೆ (ದೋಷ: <ph name="ERROR_NUMBER"/>)</translation>
 <translation id="1017280919048282932">ನಿಘಂಟಿಗೆ &amp;ಸೇರಿಸಿ</translation>
-<translation id="3534879087479077042">ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರ ಎಂದರೇನು?</translation>
+<translation id="3534879087479077042">ಮೇಲ್ವಿಚಾರಕ ಬಳಕೆದಾರ ಎಂದರೇನು?</translation>
 <translation id="7211828883345145708">ಡಿಬಗ್ ಮಾಡುತ್ತಿರುವ Chromium ಗಾಗಿ ಉಪಯುಕ್ತಕಾರಿ ಹೆಚ್ಚುವರಿ ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ.</translation>
 <translation id="8319414634934645341">ವಿಸ್ತರಿತ ಕೀಲಿ ಬಳಕೆ</translation>
 <translation id="6056710589053485679">ಸಾಮಾನ್ಯ ಮರುಲೋಡ್</translation>
@@ -3828,6 +3832,7 @@
 <translation id="3672159315667503033">ನಿಮ್ಮ ಸ್ಥಳೀಯ ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿ <ph name="URL"/> ಗೆ ಶಾಶ್ವತವಾಗಿ ಇನ್ನಷ್ಟು ಹೆಚ್ಚಿನ ಡೇಟಾವನ್ನು ಸಂಗ್ರಹಿಸವ ಇರಾದೆ ಇದೆ.</translation>
 <translation id="373572798843615002">1 ಟ್ಯಾಬ್</translation>
 <translation id="4806065163318322702">ಸ್ಪೀಚ್ ಇನ್‌ಪುಟ್ ಅನ್ನು ಟಾಗಲ್‌ ಮಾಡಿ</translation>
+<translation id="6190185222845843088">ವ್ಯಾಲೆಟ್‌ ಸ್ಯಾಂಡ್‌ಬಾಕ್ಸ್‌ ಸರ್ವರ್‌ಗಳನ್ನು ಬಳಸಿ</translation>
 <translation id="3177048931975664371">ಪಾಸ್‌ವರ್ಡ್ ಮರೆಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ</translation>
 <translation id="5852137567692933493">ಮರುಪ್ರಾರಂಭಿಸು ಮತ್ತು ಪವರ್‌ವಾಶ್ ಮಾಡು</translation>
 <translation id="3092544800441494315">ಈ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ಸೇರಿಸಿ:</translation>
@@ -3953,7 +3958,7 @@
 <translation id="6681668084120808868">ಫೋಟೋ ತೆಗೆಯಿರಿ</translation>
 <translation id="1368265273904755308">ಸಮಸ್ಯೆ ವರದಿ ಮಾಡಿ</translation>
 <translation id="780301667611848630">ಬೇಡ, ಧನ್ಯವಾದಗಳು</translation>
-<translation id="8209677645716428427">ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ನಿಮ್ಮ ಮಾರ್ಗದರ್ಶನದೊಂದಿಗೆ ವೆಬ್ ಅನ್ನು ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಮಾಡಬಹುದು. Chrome ನಲ್ಲಿ ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರ ನಿರ್ವಾಹಕರಾಗಿ, ನೀವು ಹೀಗೆ ಮಾಬಹುದು:</translation>
+<translation id="8209677645716428427">ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರು ನಿಮ್ಮ ಮಾರ್ಗದರ್ಶನದೊಂದಿಗೆ ವೆಬ್ ಅನ್ನು ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಮಾಡಬಹುದು. Chrome ನಲ್ಲಿ ಮೇಲ್ವಿಚಾರಣೆ ಬಳಕೆದಾರರ ನಿರ್ವಾಹಕರಾಗಿ, ನೀವು ಈ ಎಲ್ಲವನ್ನೂ ಮಾಡಬಹುದು:</translation>
 <translation id="2812989263793994277">ಯಾವುದೇ ಚಿತ್ರಗಳನ್ನು ತೋರಿಸದಿರಿ</translation>
 <translation id="722363467515709460">ಪರದೆ ವರ್ಧಕವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ</translation>
 <translation id="7190251665563814471"><ph name="HOST"/> ರಲ್ಲಿ ಪ್ಲಗ್-ಇನ್‌ಗಳನ್ನು ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ</translation>
@@ -4094,6 +4099,7 @@
 <translation id="1639239467298939599">ಲೋಡ್ ಆಗುತ್ತಿದೆ</translation>
 <translation id="5457599981699367932">ಅತಿಥಿಯಾಗಿ ಬ್ರೌಸ್ ಮಾಡಿ</translation>
 <translation id="6850233365366645553">Powerwash ನೊಂದಿಗೆ ನಿಮ್ಮ ಸಾಧನವು ಮರುಹೊಂದಿಸುವ ಮೊದಲು ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ. Powerwash ನಿಮ್ಮ <ph name="IDS_SHORT_PRODUCT_NAME"/> ಸಾಧನವನ್ನು ಹೊಸದರಂತೆ ಮರುಹೊಂದಿಸುತ್ತದೆ.</translation>
+<translation id="4292622557427736684">ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾದ ಮಾಧ್ಯಮ ವಿಸ್ತರಣೆಗಳಿಗಾಗಿ MediaDrm ಅನ್ನು ಡೀಫಾಲ್ಟ್‌ನಂತೆ ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="1812514023095547458">ಬಣ್ಣವನ್ನು ಆಯ್ಕೆಮಾಡಿ</translation>
 <translation id="5089363139417863686">ಫೈಲ್‌ಗಳ ಅಪ್ಲಿಕೇಶನ್‌ನೊಂದಿಗೆ ವೀಕ್ಷಿಸಿ</translation>
 <translation id="7047998246166230966">ಪಾಯಿಂಟರ್‌</translation>
@@ -4443,6 +4449,7 @@
 <translation id="1728442818359004787">ಡೀಫಾಲ್ಟ್ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಬದಲಾಯಿಸಿ...</translation>
 <translation id="7540972813190816353">ನವೀಕರಣಗಳಿಗಾಗಿ ಪರಿಶೀಲಿಸುತ್ತಿರುವಾಗ ದೋಷವೊಂದು ಸಂಭವಿಸಿದೆ: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">ಬೆಂಬಲಿಸದಿರುವ Bluetooth ಸಾಧನ: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">ಪೂರ್ವನಿಯೋಜಿತವಾಗಿರದ Media Source API ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="2225024820658613551">ಈ ಸೈಟ್‌ಗಾಗಿ ಈ ಎಚ್ಚರಿಕೆಯನ್ನು ನೀವು ನೋಡದೆ ಇದ್ದರೆ, &lt;strong&gt;ವಿಶೇಷವಾಗಿ&lt;/strong&gt; ನೀವು ಮುಂದುವರಿಯಬಾರದು.</translation>
 <translation id="2049639323467105390">ಈ ಸಾಧನವು <ph name="DOMAIN"/> ನಿಂದ ನಿರ್ವಹಿಸಲ್ಪಟ್ಟಿದೆ.</translation>
 <translation id="1932098463447129402">ಅದಕ್ಕಿಂತ ಮೊದಲಲ್ಲ</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index 3e74960..b8477a6 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">영문 철자 및 문법 보기</translation>
 <translation id="7017587484910029005">아래 그림에 표시된 문자를 입력하세요.</translation>
 <translation id="9013589315497579992">잘못된 SSL 클라이언트 인증서입니다.</translation>
+<translation id="2085245445866855859">'kiosk_only' 매니페스트 속성을 사용하는 앱은 Chrome OS 키오스크 모드에 설치되어야 합니다.</translation>
 <translation id="1467999917853307373"><ph name="URL"/>에서 내 기기에 데이터를 영구적으로 저장하려고 합니다.</translation>
 <translation id="8524066305376229396">영구 저장소:</translation>
 <translation id="7567293639574541773">요소 검사(&amp;N)</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">축구왕</translation>
 <translation id="2231238007119540260">서버 인증서를 삭제하려면 해당 서버에 대해 일반적인 보안 확인을 복원하고 유효한 인증서를 사용해야 합니다.</translation>
 <translation id="9110235431257073974">웹 스토어와 Files.app 통합 사용</translation>
+<translation id="6489433341782457580">개발자 전용: requestAutocomplete()에 대한 지갑 API 호출에 샌드박스 서비스를 사용합니다.</translation>
 <translation id="8186609076106987817">서버에서 파일을 찾을 수 없습니다.</translation>
 <translation id="2846816712032308263">빠른 탭/창 닫기 사용 - 탭의 onunload js 핸들러를 GUI와 별도로 실행합니다.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>이(가) 응답하는 데 시간이 너무 오래 걸려 <ph name="PRODUCT_NAME"/>을(를) 로드할 수 없습니다. 웹사이트가 다운되었거나 인터넷 연결에 문제가 발생했을 수 있습니다.</translation>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">관리 대상 사용자가 이 비밀번호를 사용하여 로그인해야 하므로 안전한 비밀번호를 선택하고 이에 대해 관리 대상 사용자와 상의해야 합니다.</translation>
 <translation id="5154917547274118687">메모리</translation>
 <translation id="1493492096534259649">맞춤법 검사를 사용할 수 없는 언어입니다.</translation>
+<translation id="2103866351350079276">접두어가 붙지 않은 미디어 소스 개체를 사용 중지합니다. 이 개체를 사용하면 자바스크립트가 미디어 데이터를 직접 동영상 요소에 보낼 수 있습니다.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> 검색</translation>
 <translation id="6460423884798879930">이전에 연결된 클라이언트가 초기 SYN 패킷에 추가 인증 정보를 전송할 수 있도록 옵션을 사용 설정하여 데이터에서 신속하게 '시작' 명령을 보낼 수 있도록 합니다.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> 관련 세부사항</translation>
@@ -1601,6 +1604,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/>[<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">베트남어</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/>이(가) 요청한 작업을 수행하는 속도 관련 통계</translation>
+<translation id="2048118585307365263">MediaDrm 사용 설정</translation>
 <translation id="4091434297613116013">장</translation>
 <translation id="7475671414023905704">Netscape Lost Password URL</translation>
 <translation id="3335947283844343239">닫은 탭 다시 열기</translation>
@@ -2960,7 +2964,7 @@
 <translation id="6664237456442406323">컴퓨터가 잘못된 형식의 하드웨어 ID로 구성되어 있습니다. 이렇게 하면 Chrome OS가 최신 보안 수정사항을 업데이트할 수 없으며 컴퓨터가<ph name="BEGIN_BOLD"/>악의적인 공격에 취약해 집니다<ph name="END_BOLD"/>.</translation>
 <translation id="785160701896930981"><ph name="NEW_PROFILE_NAME"/>(으)로 이름이 지정된 관리 대상 사용자가 생성되었습니다. 이 관리 대상 사용자가 볼 수 있는 웹사이트를 설정하려면 <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/> 페이지에서 제한사항 및 설정을 지정할 수 있습니다. 기본 설정을 변경하지 않는 경우 <ph name="NEW_PROFILE_NAME"/>에서 웹상의 모든 사이트를 탐색할 수 있습니다.
 
-이와 함께 자세한 안내를 보려면 <ph name="ACCOUNT_EMAIL"/>에서 이메일을 확인하세요.</translation>
+자세한 안내를 보려면 <ph name="ACCOUNT_EMAIL"/>에서 이메일을 확인하세요.</translation>
 <translation id="8493236660459102203">마이크:</translation>
 <translation id="4788968718241181184">베트남어 입력 방법(TCVN6064)</translation>
 <translation id="3254409185687681395">페이지 북마크</translation>
@@ -3857,6 +3861,7 @@
 <translation id="3672159315667503033"><ph name="URL"/>에서 로컬 컴퓨터에 대용량 데이터를 영구 저장하려고 합니다.</translation>
 <translation id="373572798843615002">탭 1개</translation>
 <translation id="4806065163318322702">음성 입력 전환</translation>
+<translation id="6190185222845843088">지갑 샌드박스 서버 사용</translation>
 <translation id="3177048931975664371">비밀번호를 숨기려면 클릭하세요.</translation>
 <translation id="5852137567692933493">다시 시작 및 Powerwash</translation>
 <translation id="3092544800441494315">다음 캡쳐화면 포함:</translation>
@@ -4125,6 +4130,7 @@
 <translation id="1639239467298939599">로드 중</translation>
 <translation id="5457599981699367932">손님으로 로그인</translation>
 <translation id="6850233365366645553">기기를 Powerwash로 재설정하기 전에 다시 시작해야 합니다. Powerwash로 <ph name="IDS_SHORT_PRODUCT_NAME"/> 기기를 재설정하면 새것처럼 초기화됩니다.</translation>
+<translation id="4292622557427736684">암호화된 미디어 확장 프로그램에 대해 기본적으로 MediaDrm을 사용하도록 설정합니다.</translation>
 <translation id="1812514023095547458">색상 선택</translation>
 <translation id="5089363139417863686">파일 앱으로 표시</translation>
 <translation id="7047998246166230966">포인터</translation>
@@ -4476,6 +4482,7 @@
 <translation id="1728442818359004787">기본 앱 변경</translation>
 <translation id="7540972813190816353">업데이트를 확인하는 동안 오류가 발생했습니다. <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">지원되지 않는 블루투스 기기(<ph name="DEVICE_NAME"/>)입니다.</translation>
+<translation id="2990212470195050777">접두어가 붙지 않은 미디어 소스 API 사용 중지</translation>
 <translation id="2225024820658613551">더 이상 진행하지 않는 것이 안전하며, &lt;strong&gt;특히&lt;/strong&gt; 해당 사이트에서 이 경고를 처음 보는 것이라면 더욱 주의해야 합니다.</translation>
 <translation id="2049639323467105390">기기는 <ph name="DOMAIN"/>에서 관리합니다.</translation>
 <translation id="1932098463447129402">시작:</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb
index 3c4abe1..2a2b429 100644
--- a/chrome/app/resources/generated_resources_lt.xtb
+++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Rodyti rašybos ir gramatikos tikrinimą</translation>
 <translation id="7017587484910029005">Įveskite simbolius, kuriuos matote toliau esančiame paveikslėlyje.</translation>
 <translation id="9013589315497579992">Blogas SSL kliento tapatybės nustatymo sertifikatas.</translation>
+<translation id="2085245445866855859">Programa su „kiosk_only“ deklaracijos atributu turi būti įdiegta „Chrome“ OS viešojo terminalo režimu.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> pageidaujama visą laiką saugoti duomenis jūsų įrenginyje.</translation>
 <translation id="8524066305376229396">Ilgalaikė atmintis:</translation>
 <translation id="7567293639574541773">P&amp;atikrinti elementą</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Šemberas</translation>
 <translation id="2231238007119540260">Jei ištrinsite serverio sertifikatą, atnaujinsite įprastas to serverio saugos patikras ir reikės naudoti galiojantį sertifikatą.</translation>
 <translation id="9110235431257073974">Įgalinti internetinės parduotuvės ir failų programos („Files.app“) integravimą.</translation>
+<translation id="6489433341782457580">Kūrėjams: naudokite „sandbox“ (smėlio dėžės) paslaugą Piniginės API „requestAutocomplete()“ iškvietoms.</translation>
 <translation id="8186609076106987817">Serveriui nepavyko rasti failo.</translation>
 <translation id="2846816712032308263">Įgalinamas greitas skirtuko lapo / lango uždarymas – paleidžiama skirtuko iškelties JS doroklė, neatsižvelgiant į VSS.</translation>
 <translation id="9134410174832249455">„<ph name="PRODUCT_NAME"/>“ nepavyko įkelti tinklalapio, nes <ph name="HOST_NAME"/> per ilgai neatsakė. Gali neveikti svetainė arba yra interneto ryšio problemų.</translation>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">Prižiūrimas naudotojas turės naudoti šį slaptažodį prisijungdamas, todėl pasirinkite saugų slaptažodį ir būtinai aptarkite jį su prižiūrimu naudotoju.</translation>
 <translation id="5154917547274118687">Atmintis</translation>
 <translation id="1493492096534259649">Šios kalbos negalima naudoti rašybai tikrinti</translation>
+<translation id="2103866351350079276">Išjunkite „MediaSource“ objektą be kodo. Taikant šį objektą leidžiama „JavaScript“ siųsti medijos duomenis tiesiogiai vaizdo įrašo elementui.</translation>
 <translation id="6628463337424475685">„<ph name="ENGINE"/>“ paieška</translation>
 <translation id="6460423884798879930">Įgalinkite parinktį siųsti papildomą autentifikavimo informaciją pradiniame anksčiau prijungto kliento programos SYN pakete, kad duomenys būtų pradedami siųsti greičiau.</translation>
 <translation id="6563261555270336410">Išsami informacija apie <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1600,6 +1603,7 @@
 <translation id="6736329909263487977">„<ph name="ISSUED_BY"/>“ [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">vietnamiečių</translation>
 <translation id="6423064450797205562">Metrika, susijusi su greičiu, kuriuo „<ph name="SHORT_PRODUCT_NAME"/>“ atlieka pageidaujamus veiksmus</translation>
+<translation id="2048118585307365263">Įgalinti „MediaDrm“.</translation>
 <translation id="4091434297613116013">popieriaus lapai</translation>
 <translation id="7475671414023905704">„Netscape“ prarasto slaptažodžio URL</translation>
 <translation id="3335947283844343239">Iš naujo atidarykite uždarytą skirtuką</translation>
@@ -3870,6 +3874,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> pageidaujama visam laikui išsaugoti daug duomenų jūsų vietiniame kompiuteryje.</translation>
 <translation id="373572798843615002">1 skirtukas</translation>
 <translation id="4806065163318322702">Perjungti kalbos įvestį</translation>
+<translation id="6190185222845843088">Piniginės „sandbox“ (smėlio dėžės) serverių naudojimas</translation>
 <translation id="3177048931975664371">Jei norite slėpti slaptažodį, spustelėkite.</translation>
 <translation id="5852137567692933493">Paleisti iš naujo ir naudoti „Powerwash“</translation>
 <translation id="3092544800441494315">Įtraukti šią ekrano kopiją:</translation>
@@ -4139,6 +4144,7 @@
 <translation id="1639239467298939599">Įkeliama</translation>
 <translation id="5457599981699367932">Naršyti kaip svečiui</translation>
 <translation id="6850233365366645553">Būtina paleisti iš naujo, kad įrenginį būtų galima nustatyti iš naujo naudojant „Powerwash“. „Powerwash“ iš naujo nustato „<ph name="IDS_SHORT_PRODUCT_NAME"/>“ įrenginį, kad jis būtų tarsi naujas.</translation>
+<translation id="4292622557427736684">Įgalinti šifruotų medijos plėtinių „MediaDrm“ pagal numatytuosius nustatymus.</translation>
 <translation id="1812514023095547458">Pasirinkti spalvą</translation>
 <translation id="5089363139417863686">Peržiūrėti naudojant Failų programą</translation>
 <translation id="7047998246166230966">Žymeklis</translation>
@@ -4488,6 +4494,7 @@
 <translation id="1728442818359004787">Keisti numatytąją programą...</translation>
 <translation id="7540972813190816353">Tikrinant, ar yra naujinių, įvyko klaida: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nepalaikomas „Bluetooth“ įrenginys: „<ph name="DEVICE_NAME"/>“.</translation>
+<translation id="2990212470195050777">Išjungti medijos šaltinio API be kodo.</translation>
 <translation id="2225024820658613551">Neturėtumėte toliau tęsti, &lt;strong&gt;ypač&lt;/strong&gt; jei anksčiau šioje svetainėje nesate matę tokio įspėjimo.</translation>
 <translation id="2049639323467105390">Įrenginys valdomas „<ph name="DOMAIN"/>“.</translation>
 <translation id="1932098463447129402">Nuo</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb
index 131d32d..3c8a557 100644
--- a/chrome/app/resources/generated_resources_lv.xtb
+++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Rādīt pareizrakstības un gramatikas ieteikumus</translation>
 <translation id="7017587484910029005">Ierakstiet rakstzīmes, kuras redzat attēlā tālāk.</translation>
 <translation id="9013589315497579992">Slikts SSL klienta autentifikācijas sertifikāts.</translation>
+<translation id="2085245445866855859">Lai instalētu lietotni ar manifesta atribūtu 'kiosk_only', ir jāizmanto ChromeOS kioska režīms.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vēlas pastāvīgi glabāt datus jūsu ierīcē.</translation>
 <translation id="8524066305376229396">Pastāvīga krātuve:</translation>
 <translation id="7567293639574541773">Pārbaudīt elementu</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Futbolbumba</translation>
 <translation id="2231238007119540260">Ja dzēsīsiet servera sertifikātu, jūs atjaunosiet šī servera parastās drošības pārbaudes un pieprasīsiet tam izmantot derīgu sertifikātu.</translation>
 <translation id="9110235431257073974">Iespējojiet interneta veikala un lietotnes Faili integrāciju.</translation>
+<translation id="6489433341782457580">Izstrādātājiem: Maka API pieprasījumu metodei requestAutocomplete() izmantojiet smilškastes pakalpojumu.</translation>
 <translation id="8186609076106987817">Serveris nevarēja atrast failu.</translation>
 <translation id="2846816712032308263">Iespējo ciļņu/logu ātru aizvēršanu — neatkarīgi no grafiskā lietotāja interfeisa tiek palaists cilnes apdarinātājs “onunload js”.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> nevarēja ielādēt tīmekļa lapu, jo <ph name="HOST_NAME"/> pārāk ilgi nereaģēja. Iespējams, vietne nedarbojas vai jums ir problēmas ar interneta savienojumu.</translation>
@@ -353,6 +355,7 @@
 <translation id="8959810181433034287">Uzraudzītajam lietotājam būs jāizmanto šī parole, lai pierakstītos, tāpēc izvēlieties drošu paroli un apspriediet to ar uzraudzīto lietotāju.</translation>
 <translation id="5154917547274118687">Atmiņa</translation>
 <translation id="1493492096534259649">Šo valodu nevar izmantot pareizrakstības pārbaudei</translation>
+<translation id="2103866351350079276">Atspējot šo MediaSource objektu, kas lietots bez prefiksa. Šis objekts ļauj valodā JavaScript sūtīt multivides datus tieši uz video elementu.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> meklēšana</translation>
 <translation id="6460423884798879930">Iespējo papildu autentifikācijas informācijas sūtīšanu sākotnējā SYN paketē iepriekš pievienotam klientam, tādējādi ļaujot sākt datu sūtīšanu ātrāk.</translation>
 <translation id="6563261555270336410">Detalizēta informācija par <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1593,6 +1596,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vjetnamiešu</translation>
 <translation id="6423064450797205562">Dati, kas saistīti ar ātrumu, kādā <ph name="SHORT_PRODUCT_NAME"/> veic pieprasītās darbības</translation>
+<translation id="2048118585307365263">Iespējot MediaDrm.</translation>
 <translation id="4091434297613116013">papīra lapas</translation>
 <translation id="7475671414023905704">Netscape pazaudētās paroles URL</translation>
 <translation id="3335947283844343239">Vēlreiz atvērt aizvērto cilni</translation>
@@ -3848,6 +3852,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vēlas pastāvīgi uzglabāt lielu datu apjomu jūsu lokālajā datorā.</translation>
 <translation id="373572798843615002">1 cilne</translation>
 <translation id="4806065163318322702">Pārslēgt runas ievadi</translation>
+<translation id="6190185222845843088">Izmantojiet Maka smilškastes serverus</translation>
 <translation id="3177048931975664371">Noklikšķiniet, lai slēptu paroli</translation>
 <translation id="5852137567692933493">Restartēt un aktivizēt funkciju Powerwash</translation>
 <translation id="3092544800441494315">Ietvert šo ekrānuzņēmumu:</translation>
@@ -4116,6 +4121,7 @@
 <translation id="1639239467298939599">Notiek ielāde</translation>
 <translation id="5457599981699367932">Pārlūkot kā viesim</translation>
 <translation id="6850233365366645553">Lai ierīces atiestatīšanai varētu izmantot funkciju Powerwash, ir jāveic restartēšana. Aktivizējot funkciju Powerwash, jūsu <ph name="IDS_SHORT_PRODUCT_NAME"/> ierīcē tiks atiestatīti sākotnējie iestatījumi.</translation>
+<translation id="4292622557427736684">Šifrētajiem multivides paplašinājumiem pēc noklusējuma iespējot MediaDrm.</translation>
 <translation id="1812514023095547458">Krāsas atlase</translation>
 <translation id="5089363139417863686">Skatīt, izmantojot lietotni Faili</translation>
 <translation id="7047998246166230966">Rādītājs</translation>
@@ -4466,6 +4472,7 @@
 <translation id="1728442818359004787">Mainīt noklusējuma lietotni...</translation>
 <translation id="7540972813190816353">Pārbaudot atjauninājumus, radās kļūda: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Neatbalstīta Bluetooth ierīce: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Atspējot tā multivides avota API bez prefiksa.</translation>
 <translation id="2225024820658613551">Jums nevajadzētu turpināt, &lt;strong&gt;īpaši&lt;/strong&gt;, ja jūs nekad neesat redzējis brīdinājumu šai vietnei.</translation>
 <translation id="2049639323467105390">Šo ierīci pārvalda vietne <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Nevis pirms</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index be4916f..686450e 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">സ്‌പെല്ലിംഗും വ്യാകരണവും കാണിക്കുക</translation>
 <translation id="7017587484910029005">നിങ്ങള്‍ ചുവടെയുള്ള ചിത്രത്തില്‍ കാണുന്ന പ്രതീകങ്ങള്‍ ടൈപ്പുചെയ്യുക.</translation>
 <translation id="9013589315497579992">SSL ക്ലയന്‍റ് പ്രാമാണീകരണ സര്‍‌ട്ടിഫിക്കറ്റ് മോശമാണ്.</translation>
+<translation id="2085245445866855859">'kiosk_only' മാനിഫെസ്റ്റ് ആട്രിബ്യൂട്ട് ഉള്ള അപ്ലിക്കേഷൻ ChromeOS കിയോസ്‌ക് മോഡിൽ ഇൻസ്റ്റാളുചെയ്യണം.</translation>
 <translation id="1467999917853307373"><ph name="URL"/>, നിങ്ങളുടെ ഉപകരണത്തിൽ ശാശ്വതമായി ഡാറ്റ സംഭരിക്കാന്‍ താൽപ്പര്യപ്പെടുന്നു.</translation>
 <translation id="8524066305376229396">നിരന്തരമായ സംഭരണം:</translation>
 <translation id="7567293639574541773">&amp;ഘടകം പരിശോധിക്കുക</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">ഫ്രിറ്റ്‌സ്</translation>
 <translation id="2231238007119540260">നിങ്ങള്‍ ഒ‍രു സെര്‍വര്‍ സാക്‌ഷ്യപത്രം ഇല്ലാതാക്കുന്നതിലൂടെ, നിങ്ങള്‍ ആ സെര്‍വറിനായുള്ള സാധാരണ സുരക്ഷ പുനഃസ്ഥാപിക്കുകയാണ്‌, ഒപ്പം അതൊരു സാധുവായ സാക്‍ഷ്യപത്രം ഉപയോഗിക്കേണ്ടതുമുണ്ട്.</translation>
 <translation id="9110235431257073974">വെബ്സ്റ്റോർ, Files.app എന്നിവയുടെ സംയോജനം പ്രവർത്തനക്ഷമമാക്കുക.</translation>
+<translation id="6489433341782457580">ഡവലപ്പർമാർക്കുള്ളത്: requestAutocomplete()-ന്റെ Wallet API കോളുകൾക്ക് സാൻഡ്‌ബോക്‌സ് സേവനം ഉപയോഗിക്കുക.</translation>
 <translation id="8186609076106987817">സെർവറിന് ഫയൽ കണ്ടെത്താൻ കഴിഞ്ഞില്ല.</translation>
 <translation id="2846816712032308263">വേഗത്തിലുള്ള ടാബ്/വിൻഡോ അടയ്‌ക്കൽ പ്രവർത്തനക്ഷമമാക്കുന്നു - ഒരു ടാബിന്റെ onunload js ഹാൻഡ്ലർ GUI അവലംബിക്കാതെ പ്രവർത്തിപ്പിക്കുന്നു.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>        എന്നത് പ്രതികരിക്കാന്‍ കൂടുതല്‍ സമയം എടുത്തതിനാല്‍        <ph name="PRODUCT_NAME"/>        എന്നതിന് വെബ്പേജ് ലോഡ് ചെയ്യാന്‍ സാധിക്കുന്നില്ല.  വെബ്പേജ് ഡൌണ്‍ ആയിരിക്കാം, അല്ലെങ്കില്‍        ഇന്‍റര്‍നെറ്റ് കണക്ഷനുമായി ബന്ധപ്പെട്ട് പ്രശ്നങ്ങള്‍ നിങ്ങള്‍ നേരിടുന്നുണ്ടാകാം.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">സൂപ്പർവൈസുചെയ്‌ത ഉപയോക്താവിന് സൈൻ ഇൻ ചെയ്യുന്നതിന് ഈ പാസ്‌വേഡ് ആവശ്യമായതിനാൽ, ഒരു സുരക്ഷിതമായ പാസ്‌വേഡ് തിരഞ്ഞെടുത്ത് അത് സൂപ്പർവൈസുചെയ്‌ത ഉപയോക്താവുമായി ചർച്ച ചെയ്യുന്ന കാര്യം ഓർമ്മിക്കുക.</translation>
 <translation id="5154917547274118687">മെമ്മറി</translation>
 <translation id="1493492096534259649">അക്ഷരപ്പിശക് പരിശോധനയ്ക്ക് ഈ ഭാഷ ഉപയോഗിക്കാന്‍ കഴിയില്ല</translation>
+<translation id="2103866351350079276">പ്രീഫിക്‌സ് ചെയ്യാത്ത MediaSource ഒബ്‌ജക്റ്റ് പ്രവർത്തനരഹിതമാക്കുക. ഈ ഒബ്‌ജക്റ്റ് ഒരു വീഡിയോ ഘടകത്തിലേക്ക് മീഡിയ ഡാറ്റ നേരിട്ട് അയയ്‌ക്കാൻ JavaScript-നെ അനുവദിക്കുന്നു.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> തിരയല്‍</translation>
 <translation id="6460423884798879930">മുമ്പ് കണക്റ്റുചെയ്‌ത ക്ലയന്റിനായുള്ള പ്രാരംഭ SYN പാക്കറ്റിലെ, വേഗമേറിയ ഡാറ്റ അയയ്‌ക്കൽ ആരംഭിക്കാൻ അനുവദിക്കുന്ന അധിക പ്രാമാണീകരണ വിവരങ്ങൾ അയയ്‌ക്കുന്നതിനുള്ള ഓപ്‌ഷൻ പ്രവർത്തനക്ഷമമാക്കുക.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> എന്നതിനെക്കുറിച്ചുള്ള വിശാദാംശങ്ങൾ</translation>
@@ -447,7 +450,7 @@
 <translation id="4372948949327679948">പ്രതീക്ഷിച്ച <ph name="VALUE_TYPE"/> മൂല്യം.</translation>
 <translation id="9123413579398459698">FTP പ്രോക്സി</translation>
 <translation id="1751752860232137596">പരീക്ഷണാത്മകവും ലളിതവുമായ സ്ക്രോളിംഗ് നടപ്പിലാക്കൽ പ്രാപ്തമാക്കുക.</translation>
-<translation id="8534801226027872331">ഈ സാഹചര്യത്തില്‍, നിങ്ങളുടെ ബ്രൌസറിനായി നല്‍കപ്പെട്ടിട്ടുള്ള സര്‍ട്ടിഫിക്കറ്റില്‍ പിശകുകളുണ്ടായിരിക്കും, അവ മനസിലാക്കാനും കഴിയില്ല. ഇത് ഒരു പക്ഷെ അര്‍ത്ഥമാക്കുന്നത് നമുക്ക് സര്‍ട്ടിഫിക്കറ്റിലെ തിരിച്ചറിയല്‍ വിവരങ്ങള്‍ മനസ്സിലാക്കാന്‍ കഴിഞ്ഞില്ല, അല്ലെങ്കില്‍ സര്‍ട്ടിഫിക്കറ്റിലെ മറ്റ് ചില വിവരങ്ങള്‍ കണക്ഷന്‍ സുരക്ഷിതമാക്കുന്നതിനായി ഉപയോഗിക്കുന്നു എന്നാണ്. നിങ്ങള്‍ മുന്നോട്ട് പോകരുത്.</translation>
+<translation id="8534801226027872331">ഈ സാഹചര്യത്തിൽ, നിങ്ങളുടെ ബ്രൌസറിനായി നല്‍കപ്പെട്ടിട്ടുള്ള സര്‍ട്ടിഫിക്കറ്റില്‍ പിശകുകളുണ്ടായിരിക്കും, അവ മനസിലാക്കാനും കഴിയില്ല. ഇത് ഒരു പക്ഷെ അര്‍ത്ഥമാക്കുന്നത് നമുക്ക് സര്‍ട്ടിഫിക്കറ്റിലെ തിരിച്ചറിയല്‍ വിവരങ്ങള്‍ മനസ്സിലാക്കാന്‍ കഴിഞ്ഞില്ല, അല്ലെങ്കില്‍ സര്‍ട്ടിഫിക്കറ്റിലെ മറ്റ് ചില വിവരങ്ങള്‍ കണക്ഷന്‍ സുരക്ഷിതമാക്കുന്നതിനായി ഉപയോഗിക്കുന്നു എന്നാണ്. നിങ്ങള്‍ മുന്നോട്ട് പോകരുത്.</translation>
 <translation id="3608527593787258723">ടാബ് 1 സജീവമാക്കുക</translation>
 <translation id="4130750466177569591">ഞാന്‍ അംഗീകരിക്കുന്നു</translation>
 <translation id="6993929801679678186">ഓട്ടോമാറ്റിക് ആയി പൂരിപ്പിച്ച പ്രവചനങ്ങൾ കാണുക</translation>
@@ -500,7 +503,7 @@
 <translation id="3878840326289104869">സൂപ്പർവൈസുചെയ്‌ത ഉപയോക്താവിനെ സൃഷ്‌ടിക്കുന്നു</translation>
 <translation id="406070391919917862">പശ്ചാത്തല അപ്ലിക്കേഷനുകള്‍</translation>
 <translation id="7000777920654628318">പ്രവർത്തനക്ഷമമാക്കുകയാണെങ്കിൽ, റാസ്‌റ്റർ ത്രെഡുകൾ GPU മെമ്മറിയിൽ നേരിട്ട് റൈറ്റുചെയ്യും.</translation>
-<translation id="8820817407110198400">ബുക്മാര്‍ക്കുകള്‍</translation>
+<translation id="8820817407110198400">ബുക്ക്‌മാർക്കുകൾ</translation>
 <translation id="2580170710466019930"><ph name="PRODUCT_NAME"/> ഏറ്റവും പുതിയ സിസ്റ്റം അപ്ഡേറ്റുകള്‍ ഇന്‍സ്റ്റാളുചെയ്യുന്ന സമയത്ത് ദയവായി കാത്തിരിക്കുക.</translation>
 <translation id="7428061718435085649">2 മത്തെയും 3 മത്തെയും കാന്‍ഡിഡേറ്റുകളെ തിരഞ്ഞെടുക്കുന്നത് ഇടതും വലതുമുള്ള Shift കീകള്‍ ഉപയോഗിക്കുക</translation>
 <translation id="1070066693520972135">WEP</translation>
@@ -1609,6 +1612,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">വിയറ്റ്നാമീസ്</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> നടപ്പിലാക്കിയ അഭ്യർത്ഥിത പ്രവർത്തനങ്ങളുടെ വേഗതയുമായി ബന്ധപ്പെട്ട മെട്രിക്കുകൾ</translation>
+<translation id="2048118585307365263">MediaDrm പ്രവർത്തനക്ഷമമാക്കുക.</translation>
 <translation id="4091434297613116013">പേപ്പര്‍ പാളികള്‍</translation>
 <translation id="7475671414023905704">നെറ്റ്‌സ്‌കേപ്പ് നഷ്‌ടമായ പാസ്‌വേഡ് URL</translation>
 <translation id="3335947283844343239">അടച്ച ടാബ് വീണ്ടും തുറക്കുക</translation>
@@ -3868,6 +3872,7 @@
 <translation id="3672159315667503033">നിങ്ങളുടെ പ്രാദേശിക കമ്പ്യൂട്ടറില്‍ <ph name="URL"/> എന്നത് സ്ഥിരമായി വലിയ ഡാറ്റ സംഭരിക്കാന്‍ ആഗ്രഹിക്കുന്നു.</translation>
 <translation id="373572798843615002">1 ടാബ്</translation>
 <translation id="4806065163318322702">സംഭാഷണ ഇൻപുട്ട് ടോഗിൾ ചെയ്യുക</translation>
+<translation id="6190185222845843088">Wallet സാൻഡ്‌ബോക്‌സ് സെർവറുകൾ ഉപയോഗിക്കുക</translation>
 <translation id="3177048931975664371">പാസ്‌വേഡ് മറയ്ക്കുന്നതിനായി ക്ലിക്ക് ചെയ്യുക</translation>
 <translation id="5852137567692933493">പുനരാരംഭിച്ച് പവർവാഷ് ചെയ്യുക</translation>
 <translation id="3092544800441494315">ഈ സ്ക്രീന്‍ഷോട്ട് ഉള്‍പ്പെടുത്തുക:</translation>
@@ -4137,6 +4142,7 @@
 <translation id="1639239467298939599">ലോഡുചെയ്യുന്നു</translation>
 <translation id="5457599981699367932">അതിഥിയായി ബ്രൌസുചെയ്യുക</translation>
 <translation id="6850233365366645553">നിങ്ങളുടെ ഉപകരണം പുതുക്കിയെടുത്ത് പുനഃസജ്ജമാക്കുന്നതിന് മുമ്പ് ഒരു പുനരാരംഭിക്കൽ ആവശ്യമാണ്. പുതുക്കിയെടുക്കൽ നിങ്ങളുടെ <ph name="IDS_SHORT_PRODUCT_NAME"/> ഉപകരണത്തെ പുതിയതുപോലെ പുനഃസജ്ജമാക്കുന്നു.</translation>
+<translation id="4292622557427736684">എൻക്രിപ്‌റ്റുചെയ്‌ത മീഡിയ വിപുലീകരണങ്ങൾക്കായി MediaDrm സ്ഥിരമായി പ്രവർത്തനക്ഷമമാക്കുക.</translation>
 <translation id="1812514023095547458">വർണ്ണം തിരഞ്ഞെടുക്കുക</translation>
 <translation id="5089363139417863686">ഫയലുകളുടെ അപ്ലിക്കേഷൻ ഉപയോഗിച്ച് കാണുക</translation>
 <translation id="7047998246166230966">പോയിന്റർ</translation>
@@ -4489,6 +4495,7 @@
 <translation id="1728442818359004787">സ്ഥിര അപ്ലിക്കേഷൻ മാറ്റുക...</translation>
 <translation id="7540972813190816353">അപ്‌ഡേറ്റുകൾക്കായി പരിശോധിക്കുമ്പോൾ ഒരു പിശക് സംഭവിച്ചു:  <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">പിന്തുണയ്‌ക്കാത്ത Bluetooth ഉപകരണം: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">പ്രീഫിക്‌സ് ചെയ്യാത്ത മീഡിയ ഉറവിട API പ്രവർത്തനരഹിതമാക്കുക.</translation>
 <translation id="2225024820658613551">നിങ്ങൾ തുടരരുത്, &lt;strong&gt;പ്രത്യേകിച്ച്&lt;/strong&gt; ഈ സൈറ്റിനായി ഈ മുന്നറിയിപ്പ് ഇതിനുമുമ്പ് നിങ്ങൾ കണ്ടിട്ടില്ലെങ്കിൽ.</translation>
 <translation id="2049639323467105390">ഈ ഉപകരണം നിയന്ത്രിക്കുന്നത് <ph name="DOMAIN"/> ആണ്.</translation>
 <translation id="1932098463447129402">മുമ്പല്ല</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index 09fb471..fc1e4b2 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">शुद्धलेखन आणि व्याकरण दर्शवा</translation>
 <translation id="7017587484910029005">आपल्याला खालील चित्रात दिसत असलेले वर्ण टाइप करा.</translation>
 <translation id="9013589315497579992">खराब SSL क्लायंट प्रमाणीकरण प्रमाणपत्र.</translation>
+<translation id="2085245445866855859">'kiosk_only' मॅनिफेस्ट विशेषता असलेला अ‍ॅप ChromeOS कियोस्क मोडमध्ये स्थापित करणे आवश्यक आहे.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> आपल्या डिव्हाइसवर डेटा कायमचा संचयित करू इच्छित आहे.</translation>
 <translation id="8524066305376229396">सातत्यपूर्ण संचयन:</translation>
 <translation id="7567293639574541773">घटक त&amp;पासा</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">फ्रिटझ</translation>
 <translation id="2231238007119540260">आपण एक सर्व्हर प्रमाणपत्र हटविल्यास, आपण त्या सर्व्हरसाठी नेहमीचे सुरक्षा चेक पुनर्संचयित करता आणि त्यास एक वैध प्रमाणपत्र वापरणे आवश्यक आहे.</translation>
 <translation id="9110235431257073974">वेबस्टोअर आणि Files.app चे संकलन सक्षम करा</translation>
+<translation id="6489433341782457580">विकासकांसाठी: requestAutocomplete() साठी Wallet API कॉलकरिता सॅन्डबॉक्स सेवा वापरा.</translation>
 <translation id="8186609076106987817">सर्व्हर फाइल शोधू शकले नाही.</translation>
 <translation id="2846816712032308263">जलद टॅब/विंडो बंद करणे सक्षम करते - GUI च्या  टॅब चे onunload js हँडलर वैयक्तिकरित्या चालविते.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -349,6 +351,7 @@
 <translation id="8959810181433034287">साइन इन करण्यासाठी पर्यवेक्षी वापरकर्त्यास हा संकेतशब्द वापरण्याची आवश्यकता असेल, म्हणून एक सुरक्षित संकेतशब्द निवडा आणि पर्यवेक्षी वापरकर्त्यासह त्याची चर्चा करण्याचे लक्षात ठेवा.</translation>
 <translation id="5154917547274118687">मेमरी</translation>
 <translation id="1493492096534259649">ही भाषा शब्दलेखन तपासण्यासाठी वापरली जाऊ शकत नाही</translation>
+<translation id="2103866351350079276">उपसर्ग नसलेले MediaSource ऑब्जेक्ट अक्षम करा. हे ऑब्जेक्ट थेट एका व्हिडिओ घटकावर माध्यम डेटा पाठविण्यास JavaScript ला अनुमती देते.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> शोध</translation>
 <translation id="6460423884798879930">जलद डेटा पाठवणे प्रारंभ करण्याची अनुमती देऊन, मागे कनेक्ट केलेल्या क्लायंटसाठी आरंभीच्या SYN पॅकेटमध्ये अतिरिक्त प्रमाणीकरण माहिती पाठविण्यासाठी पर्याय सक्षम करा.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> बद्दल तपशील</translation>
@@ -542,7 +545,7 @@
 <translation id="2587922270115112871">पर्यवेक्षी वापरकर्ता तयार करण्याने Google खाते तयार होत नाही आणि त्यांच्या सेटिंग्ज आणि डेटा
     Chrome Sync सह इतर डिव्हाइसवर त्यांचे अनुसरण करणार नाही. पर्यवेक्षी वापरकर्ता केवळ या डिव्हाइसवर लागू होतो.</translation>
 <translation id="4497097279402334319">नेटवर्कशी कनेक्ट करण्यात अयशस्वी.</translation>
-<translation id="7342729285348293164">आपली वैयक्तिकृत ब्राउझर वैशिष्‍ट्ये वेबवर जतन करण्‍यासाठी आणि त्यावर कोणत्याही <ph name="PRODUCT_NAME"/> संगणकावरुन प्रवेश करण्‍यासाठी आपल्या Google खात्यासह <ph name="PRODUCT_NAME"/> यामध्ये साइन इन करा. आपणास स्वयंचलितपणे आपल्या आवडीच्या Google सेवांमध्‍ये साइन इन करण्‍यात येईल.</translation>
+<translation id="7342729285348293164">आपली वैयक्तिकृत ब्राउझर वैशिष्‍ट्ये वेबवर जतन करण्‍यासाठी आणि त्यावर कोणत्याही <ph name="PRODUCT_NAME"/> संगणकावरुन प्रवेश करण्‍यासाठी आपल्या Google खात्यासह <ph name="PRODUCT_NAME"/> यामध्ये साइन इन करा. आपल्याला स्वयंचलितपणे आपल्या आवडीच्या Google सेवांमध्‍ये साइन इन केले जाईल.</translation>
 <translation id="2542049655219295786">Google सारणी</translation>
 <translation id="3899879303189199559">एक वर्षापेक्षा जास्त ऑफलाइन</translation>
 <translation id="5303618139271450299">हे वेबपृष्ठ आढळले नाही</translation>
@@ -621,7 +624,7 @@
 <translation id="4765210369020942754"><ph name="PRODUCT_NAME"/> वर प्रिंटर जोडा म्हणजे आपण कुठूनही मुद्रण करू शकता.</translation>
 <translation id="2038896902310685531">अरेरे, <ph name="WALLET_ERROR"/> Google Wallet शिवाय हा व्यवहार आपण पूर्ण करू शकता.</translation>
 <translation id="3925573269917483990">कॅमेराः</translation>
-<translation id="3170072451822350649">आपण साइन इन वगळू देखील शकता आणि <ph name="LINK_START"/>अतिथी म्हणून ब्राउझ करा<ph name="LINK_END"/>.</translation>
+<translation id="3170072451822350649">आपण साइन इन वगळुन <ph name="LINK_START"/>अतिथी म्हणून ब्राउझ<ph name="LINK_END"/> देखील करू शकता.</translation>
 <translation id="8390449457866780408">सर्व्हर अनुपलब्ध.</translation>
 <translation id="5098629044894065541">हिब्रू</translation>
 <translation id="5971820162272282813">कृपया नेटवर्कवर रीकनेक्ट करा.</translation>
@@ -1592,6 +1595,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">व्हिएतनामी</translation>
 <translation id="6423064450797205562">ज्यासह <ph name="SHORT_PRODUCT_NAME"/> विनंती केलेल्या क्रिया करते त्या गतीशी संबद्ध मेट्रिक्स</translation>
+<translation id="2048118585307365263">MediaDrm सक्षम करा.</translation>
 <translation id="4091434297613116013">कागदी पत्रके</translation>
 <translation id="7475671414023905704">Netscape संकेतशब्द URL गमावली</translation>
 <translation id="3335947283844343239">बंद केलेले टॅब पुन्हा उघडा</translation>
@@ -3853,6 +3857,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> आपल्या स्थानिक संगणकावर मोठ्या प्रमाणावर डेटा कायमचा संचयित करू इच्छित आहे.</translation>
 <translation id="373572798843615002">1 टॅब</translation>
 <translation id="4806065163318322702">भाषिक इनपुट टॉगल करा</translation>
+<translation id="6190185222845843088">Wallet सॅन्डबॉक्स सर्व्हर वापरा</translation>
 <translation id="3177048931975664371">संकेतशब्द लपविण्यासाठी क्लिक करा</translation>
 <translation id="5852137567692933493">रीस्टार्ट करा आणि पॉवरवॉश करा</translation>
 <translation id="3092544800441494315">हा स्क्रीनशॉट समाविष्ट करा:</translation>
@@ -4119,6 +4124,7 @@
 <translation id="1639239467298939599">लोड करीत आहे</translation>
 <translation id="5457599981699367932">अतिथी म्हणून ब्राउझ करा</translation>
 <translation id="6850233365366645553">Powerwash सह डिव्हाइस रीसेट केले जाण्यापूर्वी रीस्टार्ट करण्याची आवश्यकता आहे. Powerwash आपले <ph name="IDS_SHORT_PRODUCT_NAME"/> डिव्हाइस अगदी नव्यासारखे रीसेट करते.</translation>
+<translation id="4292622557427736684">कूटबद्ध माध्यम विस्तारांसाठी डीफॉल्टनुसार MediaDrm सक्षम करा.</translation>
 <translation id="1812514023095547458">रंग निवडा</translation>
 <translation id="5089363139417863686">फायली अ‍ॅपसह पहा</translation>
 <translation id="7047998246166230966">पॉइंटर</translation>
@@ -4468,6 +4474,7 @@
 <translation id="1728442818359004787">डीफॉल्ट अ‍ॅप बदला...</translation>
 <translation id="7540972813190816353">अद्यतने तपासताना एक त्रुटी आली: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">असमर्थित Bluetooth डिव्हाइस: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">उपसर्ग नसलेले माध्यम स्रोत API अक्षम करा.</translation>
 <translation id="2225024820658613551">&lt;strong&gt;विशेषत:&lt;/strong&gt;या साइटसाठी ही चेतावणी यापूर्वी कधीही पाहिली नसल्यास, आपण पुढे जाऊ नये.</translation>
 <translation id="2049639323467105390"><ph name="DOMAIN"/> याद्वारे हे डिव्हाइस व्यवस्‍थापित केले जाते.</translation>
 <translation id="1932098463447129402">पूर्वी नाही</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index 5267dce..f1a1937 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Tunjukkan Ejaan dan Tatabahasa</translation>
 <translation id="7017587484910029005">Taipkan aksara yang anda lihat dalam gambar di bawah.</translation>
 <translation id="9013589315497579992">Sijil pengesahan klien SSL tidak sah.</translation>
+<translation id="2085245445866855859">Apl dengan atribut manifes 'kiosk_only' mesti dipasang dalam mod kios ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> mahu menyimpan data pada peranti anda secara kekal.</translation>
 <translation id="8524066305376229396">Storan berterusan:</translation>
 <translation id="7567293639574541773">S&amp;emak unsur</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Jika anda memadamkan sijil pelayan, anda memulihkan pemeriksaan keselamatan biasa untuk pelayan tersebut dan memerlukannya untuk menggunakan sijil yang sah.</translation>
 <translation id="9110235431257073974">Dayakan persepaduan Kedai Web dan apl Fail.</translation>
+<translation id="6489433341782457580">Untuk pembangun: penggunaan perkhidmatan kotak pasir untuk API Wallet akan memerlukan requestAutocomplete().</translation>
 <translation id="8186609076106987817">Pelayan tidak dapat mencari fail.</translation>
 <translation id="2846816712032308263">Membolehkan penutupan pantas tab/tetingkap - menjalankan pengendali js onunload tab secara berasingan daripada GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> tidak dapat memuatkan halaman web kerana <ph name="HOST_NAME"/> mengambil masa terlalu lama untuk memberi respons. Tapak web mungkin tergendala atau anda mungkin mengalami isu dengan sambungan Internet anda.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">Pengguna yang diselia perlu menggunakan kata laluan ini untuk log masuk, jadi pilih kata laluan yang selamat dan jangan lupa untuk membincangkannya dengan pengguna yang diselia.</translation>
 <translation id="5154917547274118687">Memori</translation>
 <translation id="1493492096534259649">Bahasa ini tidak dapat digunakan untuk memeriksa ejaan</translation>
+<translation id="2103866351350079276">Lumpuhkan objek MediaSource tanpa awalan. Objek ini membenarkan JavaScript menghantar data media secara terus kepada unsur video.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Carian</translation>
 <translation id="6460423884798879930">Dayakan pilihan ini untuk menghantar maklumat pengesahan tambahan dalam paket SYN permulaan untuk pelanggan yang pernah disambungkan sebelum ini. Ini membolehkan penghantaran data dimulakan dengan lebih pantas.</translation>
 <translation id="6563261555270336410">Butiran mengenai <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1596,6 +1599,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Bahasa Vietnam</translation>
 <translation id="6423064450797205562">Metrik yang berkaitan dengan kelajuan yang <ph name="SHORT_PRODUCT_NAME"/> gunakan untuk melaksanakan tindakan yang diminta</translation>
+<translation id="2048118585307365263">Dayakan MediaDrm.</translation>
 <translation id="4091434297613116013">helai kertas</translation>
 <translation id="7475671414023905704">URL Kata Laluan Hilang Netscape</translation>
 <translation id="3335947283844343239">Buka Semula Tab Yang Ditutup</translation>
@@ -3878,6 +3882,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> mahu menyimpan data besar pada komputer setempat anda secara kekal.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">Togol input pertuturan</translation>
+<translation id="6190185222845843088">Gunakan pelayan kotak pasir Wallet</translation>
 <translation id="3177048931975664371">Klik untuk sembunyikan kata laluan</translation>
 <translation id="5852137567692933493">Mulakan Semula dan lakukan Powerwash</translation>
 <translation id="3092544800441494315">Termasuk tangkapan skrin ini:</translation>
@@ -4145,6 +4150,7 @@
 <translation id="1639239467298939599">Memuatkan</translation>
 <translation id="5457599981699367932">Semak Imbas sebagai Tetamu</translation>
 <translation id="6850233365366645553">Mula semula diperlukan sebelum peranti anda boleh ditetapkan semula dengan Powerwash. Powerwash menetapkan peranti <ph name="IDS_SHORT_PRODUCT_NAME"/> anda menjadi seperti baharu.</translation>
+<translation id="4292622557427736684">Dayakan MediaDrm secara lalai untuk Pelanjutan Media Disulitkan.</translation>
 <translation id="1812514023095547458">Pilih Warna</translation>
 <translation id="5089363139417863686">Lihat menggunakan apl Fail</translation>
 <translation id="7047998246166230966">Penunjuk</translation>
@@ -4495,6 +4501,7 @@
 <translation id="1728442818359004787">Tukar apl lalai...</translation>
 <translation id="7540972813190816353">Ralat berlaku semasa menyemak kemas kini: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Peranti Bluetooth tidak disokong: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Lumpuhkan API Sumber Media tanpa awalan.</translation>
 <translation id="2225024820658613551">Anda tidak harus meneruskan, &lt;strong&gt;terutamanya&lt;/ strong&gt; jika anda tidak pernah melihat amaran ini sebelum ini untuk tapak ini.</translation>
 <translation id="2049639323467105390">Peranti ini diuruskan oleh <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Bukan Sebelum</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index 3877b3a..601d9f2 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Toon spelling en grammatica</translation>
 <translation id="7017587484910029005">Typ de tekens die in de onderstaande afbeelding worden weergegeven.</translation>
 <translation id="9013589315497579992">Ongeldig SSL-certificaat voor clientverificatie.</translation>
+<translation id="2085245445866855859">Een app met het manifestkenmerk 'kiosk_only' moet worden geïnstalleerd in de Chrome OS-kioskmodus.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vraagt toestemming om gegevens permanent op je apparaat op te slaan.</translation>
 <translation id="8524066305376229396">Permanente opslag:</translation>
 <translation id="7567293639574541773">Eleme&amp;nt inspecteren</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Als je een servercertificaat verwijdert, herstel je de gebruikelijke beveiligingscontroles voor de server en verplicht je de server een geldig certificaat te gebruiken.</translation>
 <translation id="9110235431257073974">De integratie van Web Store en de Bestanden-app inschakelen.</translation>
+<translation id="6489433341782457580">Voor ontwikkelaars: gebruik de sandboxservice voor Wallet API-aanroepen voor requestAutocomplete().</translation>
 <translation id="8186609076106987817">De server kan het bestand niet vinden.</translation>
 <translation id="2846816712032308263">Snel sluiten van tabbladen/vensters inschakelen. Hiervoor wordt de onunload js handler van een tabblad onafhankelijk van de GUI uitgevoerd.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -361,6 +363,7 @@
 <translation id="8959810181433034287">De bewaakte gebruiker moet dit wachtwoord gebruiken om in te loggen, kies dus een veilig wachtwoord en geef dit door aan de bewaakte gebruiker.</translation>
 <translation id="5154917547274118687">Geheugen</translation>
 <translation id="1493492096534259649">Je kunt deze taal niet voor spellingcontrole gebruiken</translation>
+<translation id="2103866351350079276">Het MediaSource-object zonder voorvoegsels uitschakelen. Dit object staat JavaScript toe mediagegevens rechtstreeks naar een video-element te verzenden.</translation>
 <translation id="6628463337424475685">Zoeken via <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Hiermee schakel je de optie in om in het eerste SYN-pakket extra verificatiegegevens te verzenden voor een eerder verbonden client, waardoor het verzenden van gegevens sneller kan starten.</translation>
 <translation id="6563261555270336410">Details over <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1604,6 +1607,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamees</translation>
 <translation id="6423064450797205562">Statistieken met betrekking tot de snelheid waarmee <ph name="SHORT_PRODUCT_NAME"/> verzochte acties uitvoert</translation>
+<translation id="2048118585307365263">MediaDrm inschakelen.</translation>
 <translation id="4091434297613116013">vellen papier</translation>
 <translation id="7475671414023905704">URL van verloren Netscape-wachtwoord</translation>
 <translation id="3335947283844343239">Open gesloten tabblad opnieuw</translation>
@@ -3860,6 +3864,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vraagt toestemming om permanent veel gegevens op je lokale computer op te slaan.</translation>
 <translation id="373572798843615002">1 tabblad</translation>
 <translation id="4806065163318322702">Spraakinvoer in-/uitschakelen</translation>
+<translation id="6190185222845843088">Wallet-sandboxservers gebruiken</translation>
 <translation id="3177048931975664371">Klik om het wachtwoord te verbergen</translation>
 <translation id="5852137567692933493">Opnieuw opstarten en Powerwash uitvoeren</translation>
 <translation id="3092544800441494315">Dit screenshot opnemen:</translation>
@@ -4129,6 +4134,7 @@
 <translation id="1639239467298939599">Laden</translation>
 <translation id="5457599981699367932">Gebruiken als gast</translation>
 <translation id="6850233365366645553">Het apparaat moet opnieuw worden opgestart voordat het opnieuw kan worden ingesteld met de Powerwash-functie. Met de Powerwash-functie worden alle standaardinstellingen van je <ph name="IDS_SHORT_PRODUCT_NAME"/>-apparaat hersteld.</translation>
+<translation id="4292622557427736684">MediaDrm standaard inschakelen voor versleutelde media-extensies.</translation>
 <translation id="1812514023095547458">Kleur selecteren</translation>
 <translation id="5089363139417863686">Weergeven met de app Bestanden</translation>
 <translation id="7047998246166230966">Pijltje</translation>
@@ -4477,6 +4483,7 @@
 <translation id="1728442818359004787">Standaard-app wijzigen...</translation>
 <translation id="7540972813190816353">Er is een fout opgetreden bij het ​​controleren op updates: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Niet-ondersteund Bluetooth-apparaat: '<ph name="DEVICE_NAME"/>'.</translation>
+<translation id="2990212470195050777">Media Source API zonder voorvoegsels uitschakelen.</translation>
 <translation id="2225024820658613551">Je kunt beter niet verder gaan, &lt;strong&gt;vooral niet&lt;/strong&gt; als deze waarschuwing niet eerder is weergegeven voor deze website.</translation>
 <translation id="2049639323467105390">Dit apparaat wordt beheerd door <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Niet vóór</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb
index db39ab4..819e37f 100644
--- a/chrome/app/resources/generated_resources_no.xtb
+++ b/chrome/app/resources/generated_resources_no.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Vis stavekontroll og grammatikk</translation>
 <translation id="7017587484910029005">Skriv inn tegnene du ser i bildet nedenfor.</translation>
 <translation id="9013589315497579992">Ugyldig autentiseringssertifikat for SSL-klient.</translation>
+<translation id="2085245445866855859">App med «kiosk_only»-manifestattributt må være installert i kioskmodusen for ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> ønsker å lagre data på enheten din permanent.</translation>
 <translation id="8524066305376229396">Permanent lagring:</translation>
 <translation id="7567293639574541773">I&amp;nspiser element</translation>
@@ -181,6 +182,7 @@
 <translation id="4858913220355269194">Drible</translation>
 <translation id="2231238007119540260">Hvis du sletter et tjenersertifikat, gjenoppretter du de vanlige sikkerhetskontrollene for tjeneren og krever at den bruker et gyldig sertifikat.</translation>
 <translation id="9110235431257073974">Aktiver integrering av Nettbutikken og Files.app.</translation>
+<translation id="6489433341782457580">For utviklere: bruk prosessisolering for Wallet API-anrop for requestAutocomplete().</translation>
 <translation id="8186609076106987817">Tjeneren fant ikke filen.</translation>
 <translation id="2846816712032308263">Muliggjør rask lukking av faner og vinduer – kjøres på fanens onunload js-behandler, uavhengig av GUI,</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> kan ikke laste inn nettsiden fordi det tok <ph name="HOST_NAME"/> for lang tid å svare. Nettstedet kan være nede, eller det kan ha oppstått problemer med Internett-forbindelsen din.</translation>
@@ -321,7 +323,7 @@
 <translation id="2179052183774520942">Legg til søkemotor</translation>
 <translation id="4043223219875055035">Logg deg på med Google-kontoen din for å tillate apper å synkronisere innstillinger og tilby andre tilpassede tjenester.</translation>
 <translation id="5498951625591520696">Får ikke kontakt med tjeneren.</translation>
-<translation id="1621207256975573490">Lagre &amp;ramme som...</translation>
+<translation id="1621207256975573490">Lagre &amp;rammen som...</translation>
 <translation id="4681260323810445443">Du er ikke autorisert til å ha tilgang til nettsiden på <ph name="URL"/>. Det kan hende at du må logge deg på.</translation>
 <translation id="7207605296944356446">Mikrosekunder</translation>
 <translation id="6093888419484831006">Avbryter oppdatering …</translation>
@@ -349,6 +351,7 @@
 <translation id="8959810181433034287">Den overvåkede brukeren må bruke dette passordet til å logge seg på, så velg et sikkert passord, og husk å formidle det til den overvåkede brukeren.</translation>
 <translation id="5154917547274118687">Minne</translation>
 <translation id="1493492096534259649">Dette språket kan ikke brukes til stavekontroll</translation>
+<translation id="2103866351350079276">Deaktiver MediaSource-objektet uten prefiks. Dette objektet gjør det mulig for JavaScript å sende mediedata direkte til et videoelement.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Søk</translation>
 <translation id="6460423884798879930">Aktiver muligheten til å sende ekstra autentiseringsinformasjon med den første SYN-pakken for en klient som har vært tilkoblet tidligere. Dette gjør at datasending kan starte raskere.</translation>
 <translation id="6563261555270336410">Detaljer om <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -591,7 +594,7 @@
 <translation id="5640179856859982418">Sveitsisk tastatur</translation>
 <translation id="1662837784918284394">(ingen)</translation>
 <translation id="2573269395582837871">Velg bilde og navn</translation>
-<translation id="5910363049092958439">Lagre &amp;bilde som</translation>
+<translation id="5910363049092958439">Lagre &amp;bildet som</translation>
 <translation id="8793975580333839911">Kjør dette programtillegget</translation>
 <translation id="3645617779454068495">Ved å aktivere denne innstillingen gir du nettapper tillatelse til å bruke WebGL API-en.</translation>
 <translation id="1864146862702347178">Aktiver forslag ved rulling</translation>
@@ -986,7 +989,7 @@
 <translation id="3534176359640723312">Utvidelser som kommuniserer med denne siden:</translation>
 <translation id="7474889694310679759">Engelsk tastatur (Canada)</translation>
 <translation id="1817871734039893258">Microsoft-filgjenoppretting</translation>
-<translation id="2423578206845792524">Lagre &amp;bilde som...</translation>
+<translation id="2423578206845792524">Lagre &amp;bildet som...</translation>
 <translation id="6806236207372176468">Deaktiver støtte for videokoding for WebRTC-maskinvare.</translation>
 <translation id="7549584377607005141">Denne nettsiden krever data som du har skrevet inn tidligere for å vises korrekt. Du kan sende inn dataene på nytt, men hvis du gjør det, gjentas eventuelle handlinger denne siden utførte.</translation>
 <translation id="6954850746343724854">Aktiver Native Client for alle nettprogrammer, selv de som ikke ble installert fra Chrome Nettmarked.</translation>
@@ -1584,6 +1587,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamesisk</translation>
 <translation id="6423064450797205562">Beregninger knyttet til hvor raskt <ph name="SHORT_PRODUCT_NAME"/> utfører forespurte handlinger</translation>
+<translation id="2048118585307365263">Aktiver MediaDrm.</translation>
 <translation id="4091434297613116013">ark</translation>
 <translation id="7475671414023905704">Nettadresse for mistet passord – Netscape</translation>
 <translation id="3335947283844343239">Åpne lukkede faner igjen</translation>
@@ -3407,7 +3411,7 @@
 <translation id="4367133129601245178">K&amp;opier bildeadressen</translation>
 <translation id="6326175484149238433">Fjern fra Chrome</translation>
 <translation id="2554553592469060349">Den valgte filen er for stor (maksimal størrelse: 3 MB).</translation>
-<translation id="3494444535872870968">Lagre &amp;ramme som</translation>
+<translation id="3494444535872870968">Lagre &amp;rammen som</translation>
 <translation id="987264212798334818">Generelt</translation>
 <translation id="7496327459896094472">Berøringsoptimalisert grensesnitt</translation>
 <translation id="2356070529366658676">Spør</translation>
@@ -3836,6 +3840,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> ønsker permanent å lagre data lokalt på datamaskinen din.</translation>
 <translation id="373572798843615002">1 fane</translation>
 <translation id="4806065163318322702">Slå på taleinndata</translation>
+<translation id="6190185222845843088">Bruk prosessisoleringstjenere for Wallet</translation>
 <translation id="3177048931975664371">Klikk for å skjule passord</translation>
 <translation id="5852137567692933493">Omstart og Powerwash</translation>
 <translation id="3092544800441494315">Inkluder denne skjermdumpen:</translation>
@@ -4105,6 +4110,7 @@
 <translation id="1639239467298939599">Laster inn</translation>
 <translation id="5457599981699367932">Surf som gjest</translation>
 <translation id="6850233365366645553">Omstart er nødvendig før enheten din kan tilbakestilles med Powerwash. Powerwash tilbakestiller <ph name="IDS_SHORT_PRODUCT_NAME"/>-enheten så den blir akkurat som ny.</translation>
+<translation id="4292622557427736684">Aktiver MediaDrm som standard for krypterte medieutvidelser.</translation>
 <translation id="1812514023095547458">Velg farge</translation>
 <translation id="5089363139417863686">Se med filer-appen</translation>
 <translation id="7047998246166230966">Peker</translation>
@@ -4454,6 +4460,7 @@
 <translation id="1728442818359004787">Endre standardapp</translation>
 <translation id="7540972813190816353">Det oppsto en feil under søk etter oppdateringer: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Ustøttet Bluetooth-enhet: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Deaktiver mediekilde-API uten prefiks.</translation>
 <translation id="2225024820658613551">Du bør ikke fortsette, &lt;strong&gt;særlig&lt;/strong&gt; hvis du aldri har sett denne advarselen tidligere for dette nettstedet.</translation>
 <translation id="2049639323467105390">Denne enheten administreres av <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Ikke før</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index 1f08e72..cc0dbf3 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -136,6 +136,7 @@
 <translation id="1589055389569595240">Pokaż pisownię i gramatykę</translation>
 <translation id="7017587484910029005">Wpisz znaki widoczne na poniższym obrazie.</translation>
 <translation id="9013589315497579992">Błędny certyfikat uwierzytelniania klienta SSL.</translation>
+<translation id="2085245445866855859">Aplikacja z atrybutem „kiosk_only” w pliku manifestu musi być zainstalowana w trybie kiosku Chrome OS.</translation>
 <translation id="1467999917853307373">Witryna <ph name="URL"/> chce na stałe przechowywać dane na Twoim urządzeniu.</translation>
 <translation id="8524066305376229396">Stała przestrzeń dyskowa:</translation>
 <translation id="7567293639574541773">Z&amp;badaj element</translation>
@@ -189,6 +190,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Jeśli usuniesz certyfikat serwera, przywrócisz zwykłe sprawdzenia zabezpieczeń w odniesieniu do tego serwera z wymogiem używania przez niego ważnego certyfikatu.</translation>
 <translation id="9110235431257073974">Włącz integrację sklepu internetowego i aplikacji Pliki.</translation>
+<translation id="6489433341782457580">Programiści: w przypadku wywołań requestAutocomplete() interfejsu API Portfela należy używać usługi piaskownicy.</translation>
 <translation id="8186609076106987817">Serwer nie znalazł pliku.</translation>
 <translation id="2846816712032308263">Włącza szybkie zamykanie kart/okien – uruchamia moduł js zwolnienia karty niezależnie od GUI.</translation>
 <translation id="9134410174832249455">Przeglądarka <ph name="PRODUCT_NAME"/> nie może wczytać strony internetowej, ponieważ oczekiwanie na odpowiedź serwera <ph name="HOST_NAME"/> trwa zbyt długo. Witryna może być wyłączona lub mogły wystąpić problemy z połączeniem internetowym.</translation>
@@ -349,6 +351,7 @@
 <translation id="8959810181433034287">Użytkownik nadzorowany będzie musiał podawać to hasło podczas logowania się, więc utwórz takie, które będzie bezpieczne, i przekaż je temu użytkownikowi.</translation>
 <translation id="5154917547274118687">Pamięć</translation>
 <translation id="1493492096534259649">Nie można użyć tego języka do sprawdzania pisowni</translation>
+<translation id="2103866351350079276">Wyłącza obiekt MediaSource bez przedrostka. Pozwala on bezpośrednio przesyłać dane multimedialne z JavaScriptu do elementu wideo.</translation>
 <translation id="6628463337424475685">Wyszukiwarka <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Włącz tę opcję, by wysłać dodatkowe informacje uwierzytelniania we wstępnym pakiecie SYN dla uprzednio połączonego klienta, umożliwiając szybsze rozpoczęcie wysyłania danych.</translation>
 <translation id="6563261555270336410">Informacje o <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -384,7 +387,7 @@
 <translation id="4684748086689879921">Pomiń importowanie</translation>
 <translation id="6418443601594065950">Wyłącz wyskakujący pasek informacyjny dla chronionych nośników.</translation>
 <translation id="8191230140820435481">Zarządzać Twoimi aplikacjami, rozszerzeniami i motywami</translation>
-<translation id="8279107132611114222">Twoja prośba o dostęp to tej witryny została wysłana do: <ph name="NAME"/>.</translation>
+<translation id="8279107132611114222">Twoja prośba o dostęp to tej witryny została wysłana do: <ph name="NAME"/></translation>
 <translation id="8685753823371943147">Sprawdzanie dysku USB...</translation>
 <translation id="8034955203865359138">Brak wpisów historii.</translation>
 <translation id="9130015405878219958">Wprowadzono nieprawidłowy tryb.</translation>
@@ -541,7 +544,7 @@
 <translation id="1916935104118658523">Ukryj wtyczkę</translation>
 <translation id="1046059554679513793">Niestety, ta nazwa jest już używana.</translation>
 <translation id="2587922270115112871">Utworzenie użytkownika nadzorowanego nie powoduje utworzenia konta Google, a jego ustawienia
-    ani dane nie są przenoszone na inne urządzenia przez Synchronizację Chrome. Jego zasięg działania jest ograniczony tylko do tego urządzenia.</translation>
+    ani dane nie są przenoszone na inne urządzenia przez funkcje synchronizacji w Chrome. Jego zasięg działania jest ograniczony tylko do tego urządzenia.</translation>
 <translation id="4497097279402334319">Nie można nawiązać połączenia z siecią.</translation>
 <translation id="7342729285348293164">Zaloguj się do <ph name="PRODUCT_NAME"/> przy użyciu swojego konta Google, aby zapisać w sieci spersonalizowane funkcje przeglądarki i mieć do nich dostęp z przeglądarki <ph name="PRODUCT_NAME"/> na dowolnym komputerze. Będziesz też automatycznie logowany(a) do swoich ulubionych usług Google.</translation>
 <translation id="2542049655219295786">Tabela Google</translation>
@@ -819,8 +822,8 @@
 <translation id="7550830279652415241">bookmarks_<ph name="DATESTAMP"/>.html</translation>
 <translation id="3127360977178108225">Zakończ sesję gościa</translation>
 <translation id="6327653052522436195">Miasto</translation>
-<translation id="164814987133974965">Użytkownik nadzorowany może przeglądać internet z Twoją pomocą. Jako jego menedżer możesz:
-    <ph name="BEGIN_BOLD"/>zezwalać na dostęp do określonych witryn lub blokować go<ph name="END_BOLD"/>;
+<translation id="164814987133974965">Użytkownik nadzorowany może przeglądać internet zgodnie z Twoimi wytycznymi. Jako jego menedżer możesz:
+    <ph name="BEGIN_BOLD"/>zezwalać na dostęp do określonych witryn lub blokować go<ph name="END_BOLD"/>,
     <ph name="BEGIN_BOLD"/>sprawdzać<ph name="END_BOLD"/>, na jakie strony wszedł użytkownik nadzorowany, oraz
     <ph name="BEGIN_BOLD"/>zarządzać<ph name="END_BOLD"/> innymi ustawieniami.</translation>
 <translation id="6828153365543658583">Ogranicz logowanie do następujących użytkowników:</translation>
@@ -1145,7 +1148,7 @@
 <translation id="2374144379568843525">&amp;Ukryj panel pisowni</translation>
 <translation id="3313590242757056087">Aby określić, jakie strony będzie mógł przeglądać użytkownik nadzorowany,
     skonfiguruj ograniczenia i ustawienia na <ph name="MANAGEMENT_URL"/>.
-    Jeśli nie zmienisz ustawień domyślnych, <ph name="USER_DISPLAY_NAME"/>
+    Jeśli nie zmienisz ustawień domyślnych, użytkownik <ph name="USER_DISPLAY_NAME"/>
     będzie mieć dostęp do wszystkich stron w internecie.</translation>
 <translation id="2694026874607847549">Pliki cookie (1)</translation>
 <translation id="3909791450649380159">Wy&amp;tnij</translation>
@@ -1386,13 +1389,13 @@
 <translation id="839736845446313156">Zarejestruj</translation>
 <translation id="2660779039299703961">Wydarzenie</translation>
 <translation id="4249248555939881673">Czekam na połączenie z siecią...</translation>
-<translation id="8651130890368571179">Użytkownik nadzorowany może przeglądać internet z Twoją pomocą. Jako jego menedżer w Chrome możesz:
+<translation id="8651130890368571179">Użytkownik nadzorowany może przeglądać internet zgodnie z Twoimi wytycznymi. Jako jego menedżer w Chrome możesz:
 
- • zezwalać na dostęp do określonych witryn lub blokować go;
+ • zezwalać na dostęp do określonych witryn lub blokować go,
  • sprawdzać, na jakie strony wszedł użytkownik nadzorowany, oraz
  • zarządzać innymi ustawieniami.
 
-Utworzenie użytkownika nadzorowanego nie powoduje utworzenia konta Google, a jego ustawienia ani dane nie są przenoszone na inne urządzenia przez Synchronizację Chrome. Jego zasięg działania jest ograniczony tylko do tej instalacji Chrome na tym urządzeniu.
+Utworzenie użytkownika nadzorowanego nie powoduje utworzenia konta Google, a jego ustawienia ani dane nie są przenoszone na inne urządzenia przez funkcje synchronizacji w Chrome. Jego zasięg działania jest ograniczony tylko do tej instalacji Chrome na tym urządzeniu.
       
 Po utworzeniu nowego użytkownika nadzorowanego możesz w każdej chwili i z dowolnego urządzenia zarządzać jego ustawieniami na www.chrome.com/manage.</translation>
 <translation id="2409527877874991071">Wprowadź nową nazwę</translation>
@@ -1474,7 +1477,7 @@
 <translation id="3627671146180677314">Czas odnowienia certyfikatu firmy Netscape</translation>
 <translation id="6980956047710795611">Zapisz wszystkie dane systemu operacyjnego Chrome, używając nowego hasła (wymaga poprzedniego hasła).</translation>
 <translation id="8652487083013326477">opcja zakresu stron</translation>
-<translation id="5204967432542742771">Wprowadź hasło</translation>
+<translation id="5204967432542742771">Wpisz hasło</translation>
 <translation id="9025098623496448965">OK, wróć do ekranu logowania</translation>
 <translation id="589737135092634133">Sprawdź ustawienia serwera proxy lub skontaktuj się z administratorem sieci,
           by upewnić się, że serwer proxy działa. Jeśli uważasz, że
@@ -1576,7 +1579,7 @@
 <translation id="7651319298187296870">Wymagane jest zalogowanie, aby użyć certyfikatu użytkownika.</translation>
 <translation id="626568068055008686">Nieprawidłowe hasło lub uszkodzony plik.</translation>
 <translation id="5895875028328858187">Pokazuj powiadomienia, gdy abonament na dane jest na wyczerpaniu lub bliski wygaśnięcia</translation>
-<translation id="939598580284253335">Wprowadź hasło</translation>
+<translation id="939598580284253335">Wpisz hasło</translation>
 <translation id="8418240940464873056">Tryb Hanja</translation>
 <translation id="6557224990928257403">(Aby autoodświeżać tę stronę, wpisz chrome://<ph name="PAGE_NAME"/>/&amp;lt;sekundy&amp;gt;)</translation>
 <translation id="7917972308273378936">Klawiatura litewska</translation>
@@ -1585,6 +1588,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Wietnamski</translation>
 <translation id="6423064450797205562">Statystyki dotyczące szybkości, z jaką <ph name="SHORT_PRODUCT_NAME"/> wykonuje żądane działania</translation>
+<translation id="2048118585307365263">Włącz MediaDrm.</translation>
 <translation id="4091434297613116013">kartki</translation>
 <translation id="7475671414023905704">Adres URL utraconego hasła firmy Netscape</translation>
 <translation id="3335947283844343239">Otwórz ponownie zamkniętą kartę</translation>
@@ -1647,7 +1651,7 @@
 <translation id="1672536633972826703">Włącz zdarzenia kliknięć na obramowaniach.</translation>
 <translation id="4628757576491864469">Urządzenia</translation>
 <translation id="8461914792118322307">Serwer proxy</translation>
-<translation id="4707934200082538898">Dalsze instrukcje znajdziesz w e-mailu na koncie <ph name="BEGIN_BOLD"/><ph name="MANAGER_EMAIL"/><ph name="END_BOLD"/>.</translation>
+<translation id="4707934200082538898">Dalsze instrukcje znajdziesz w e-mailu przesłanym na adres <ph name="BEGIN_BOLD"/><ph name="MANAGER_EMAIL"/><ph name="END_BOLD"/>.</translation>
 <translation id="4089521618207933045">Ma menu podrzędne</translation>
 <translation id="3470442499439619530">Usuń tego użytkownika</translation>
 <translation id="1936157145127842922">Pokaż w folderze</translation>
@@ -2224,7 +2228,7 @@
 <translation id="3898521660513055167">Stan tokenu</translation>
 <translation id="1950295184970569138">* Zdjęcie z profilu Google (ładowanie)</translation>
 <translation id="8063491445163840780">Aktywuj kartę 4</translation>
-<translation id="7939997691108949385">Menedżer będzie mógł na stronie <ph name="MANAGEMENT_URL"/> konfigurować ograniczenia i ustawienia dla użytkownika nadzorowanego.</translation>
+<translation id="7939997691108949385">Menedżer będzie mógł konfigurować ograniczenia i ustawienia dla użytkownika nadzorowanego na stronie <ph name="MANAGEMENT_URL"/>.</translation>
 <translation id="2322193970951063277">Nagłówki i stopki</translation>
 <translation id="6436164536244065364">Zobacz w Chrome Web Store</translation>
 <translation id="9137013805542155359">Pokaż tekst oryginalny</translation>
@@ -2488,7 +2492,7 @@
 <translation id="4647090755847581616">&amp;Zamknij kartę</translation>
 <translation id="2649204054376361687"><ph name="CITY"/>, <ph name="COUNTRY"/></translation>
 <translation id="7886758531743562066">Witryna pod adresem <ph name="HOST_NAME"/> zawiera elementy pochodzące z witryn prawdopodobnie zawierających złośliwe oprogramowanie, które może zaszkodzić komputerowi lub w inny sposób działać bez zgody użytkownika. Samo odwiedzenie witryny zawierającej złośliwe oprogramowanie może spowodować zainfekowanie komputera.</translation>
-<translation id="4012185032967847512">Ups, wygląda na to, że jeśli chcesz wejść na tę stronę, musisz uzyskać pozwolenie od menedżera (<ph name="NAME"/>).</translation>
+<translation id="4012185032967847512">Wygląda na to, że jeśli chcesz wejść na tę stronę, musisz uzyskać pozwolenie od menedżera (<ph name="NAME"/>).</translation>
 <translation id="6593868448848741421">najlepsza</translation>
 <translation id="7126604456862387217">„&lt;b&gt;<ph name="SEARCH_STRING"/>&lt;/b&gt;” – &lt;em&gt;wyszukaj na Dysku&lt;/em&gt;</translation>
 <translation id="6181431612547969857">Pobieranie zostało zablokowane</translation>
@@ -2856,7 +2860,7 @@
 <translation id="2912905526406334195">Strona <ph name="HOST"/> chce użyć mikrofonu.</translation>
 <translation id="2805756323405976993">Aplikacje</translation>
 <translation id="1608626060424371292">Usuń tego użytkownika</translation>
-<translation id="3075239840551149663">Użytkownik nadzorowany <ph name="NEW_PROFILE_NAME"/> został utworzony.</translation>
+<translation id="3075239840551149663">Użytkownik nadzorowany o nazwie <ph name="NEW_PROFILE_NAME"/> został utworzony.</translation>
 <translation id="3651020361689274926">Żądany zasób już nie istnieje i nie jest dostępny adres przekazywania. Jest to prawdopodobnie sytuacja trwała.</translation>
 <translation id="7541236596838501870">Przesłane dzienniki WebRTC (<ph name="WEBRTC_LOG_COUNT"/>)</translation>
 <translation id="6003284010415283671">Dodaj aplikacje</translation>
@@ -2924,7 +2928,7 @@
 <translation id="8691686986795184760">(Włączona na podstawie zasad przedsiębiorstwa)</translation>
 <translation id="878763818693997570">Ta nazwa jest za długa</translation>
 <translation id="1976323404609382849">Pliki cookie z wielu witryn zostały zablokowane.</translation>
-<translation id="7913678092679498828">OK, rozumiem.</translation>
+<translation id="7913678092679498828">OK, rozumiem</translation>
 <translation id="3655670868607891010">Jeśli często widzisz ten komunikat, przeczytaj <ph name="HELP_LINK"/>.</translation>
 <translation id="4504940961672722399">Użyj tego rozszerzenia, klikając tę ikonę lub naciskając <ph name="EXTENSION_SHORTCUT"/>.</translation>
 <translation id="2523966157338854187">Otwórz konkretną stronę lub zestaw stron.</translation>
@@ -2935,9 +2939,9 @@
 <translation id="2319236583141234177">Sprawdź ustawienia DNS.</translation>
 <translation id="114140604515785785">Główny katalog rozszerzenia:</translation>
 <translation id="6664237456442406323">Twój komputer jest skonfigurowany przy użyciu błędnie sformatowanego identyfikatora sprzętu. Ta sytuacja uniemożliwia zaktualizowanie systemu operacyjnego Chrome za pomocą najnowszych poprawek zabezpieczeń, a komputer <ph name="BEGIN_BOLD"/>może być narażony na złośliwe ataki<ph name="END_BOLD"/>.</translation>
-<translation id="785160701896930981">Użytkownik nadzorowany o nazwie <ph name="NEW_PROFILE_NAME"/> został utworzony. Aby określić, jakie strony będzie on mógł przeglądać, skonfiguruj ograniczenia i ustawienia na <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Jeśli nie zmienisz ustawień domyślnych, <ph name="NEW_PROFILE_NAME"/> będzie mieć dostęp do wszystkich stron w internecie.
+<translation id="785160701896930981">Użytkownik nadzorowany o nazwie <ph name="NEW_PROFILE_NAME"/> został utworzony. Aby określić, jakie strony będzie on mógł przeglądać, skonfiguruj ograniczenia i ustawienia na <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Jeśli nie zmienisz ustawień domyślnych, użytkownik <ph name="NEW_PROFILE_NAME"/> będzie mieć dostęp do wszystkich stron w internecie.
 
-Te i dalsze instrukcje znajdziesz w e-mailu na koncie <ph name="ACCOUNT_EMAIL"/>.</translation>
+Dalsze instrukcje znajdziesz w e-mailu przesłanym na adres <ph name="ACCOUNT_EMAIL"/>.</translation>
 <translation id="8493236660459102203">Mikrofon:</translation>
 <translation id="4788968718241181184">wietnamski (TCVN6064)</translation>
 <translation id="3254409185687681395">Dodaj stronę do zakładek</translation>
@@ -3833,6 +3837,7 @@
 <translation id="3672159315667503033">Witryna <ph name="URL"/> chce na stałe przechowywać dużą ilość danych lokalnych na Twoim komputerze.</translation>
 <translation id="373572798843615002">1 karta</translation>
 <translation id="4806065163318322702">Przełącz wprowadzanie głosowe.</translation>
+<translation id="6190185222845843088">Użyj serwerów piaskownicy Portfela</translation>
 <translation id="3177048931975664371">Kliknij, aby ukryć hasło</translation>
 <translation id="5852137567692933493">Uruchom ponownie i użyj Powerwash</translation>
 <translation id="3092544800441494315">Dołącz następujący zrzut ekranu:</translation>
@@ -3958,7 +3963,7 @@
 <translation id="6681668084120808868">Zrób zdjęcie</translation>
 <translation id="1368265273904755308">Zgłoś problem</translation>
 <translation id="780301667611848630">Nie, dziękuję</translation>
-<translation id="8209677645716428427">Użytkownik nadzorowany może przeglądać internet z Twoją pomocą. Jako jego menedżer w Chrome możesz:</translation>
+<translation id="8209677645716428427">Użytkownik nadzorowany może przeglądać internet zgodnie z Twoimi wytycznymi. Jako jego menedżer w Chrome możesz:</translation>
 <translation id="2812989263793994277">Nie pokazuj żadnych grafik</translation>
 <translation id="722363467515709460">Włącz lupę</translation>
 <translation id="7190251665563814471">Zawsze zezwalaj na korzystanie z tych wtyczek w witrynie <ph name="HOST"/></translation>
@@ -4099,6 +4104,7 @@
 <translation id="1639239467298939599">Wczytywanie</translation>
 <translation id="5457599981699367932">Przeglądaj jako gość</translation>
 <translation id="6850233365366645553">Przed zresetowaniem urządzenia za pomocą funkcji Powerwash trzeba je ponownie uruchomić. Powerwash przywróci pierwotny stan urządzenia <ph name="IDS_SHORT_PRODUCT_NAME"/>.</translation>
+<translation id="4292622557427736684">Domyślnie włącza MediaDrm dla rozszerzeń zaszyfrowanych multimediów.</translation>
 <translation id="1812514023095547458">Wybierz kolor</translation>
 <translation id="5089363139417863686">Wyświetl w aplikacji Pliki</translation>
 <translation id="7047998246166230966">Wskaźnik</translation>
@@ -4449,6 +4455,7 @@
 <translation id="1728442818359004787">Zmień aplikację domyślną...</translation>
 <translation id="7540972813190816353">Podczas sprawdzania dostępności aktualizacji wystąpił błąd: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nieobsługiwane urządzenie Bluetooth: „<ph name="DEVICE_NAME"/>”.</translation>
+<translation id="2990212470195050777">Wyłącz interfejs API Media Source bez przedrostka.</translation>
 <translation id="2225024820658613551">Nie przechodź dalej – &lt;strong&gt;zwłaszcza&lt;/strong&gt; jeśli pierwszy raz widzisz to ostrzeżenie na tej stronie.</translation>
 <translation id="2049639323467105390">To urządzenie jest zarządzane przez: <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Nie wcześniej niż</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 31dab0a..cfed8c4 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Mostrar ortografia e gramática</translation>
 <translation id="7017587484910029005">Digite os caracteres que você vê na figura abaixo.</translation>
 <translation id="9013589315497579992">Certificado de autenticação de cliente SSL incorreto.</translation>
+<translation id="2085245445866855859">O aplicativo com o atributo de manifesto &quot;kiosk_only&quot; deve ser instalado no modo quiosque do Chrome OS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> deseja armazenar permanentemente os dados em seu dispositivo.</translation>
 <translation id="8524066305376229396">Armazenamento persistente:</translation>
 <translation id="7567293639574541773">I&amp;nspecionar elemento</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Pelé</translation>
 <translation id="2231238007119540260">Ao excluir um certificado do servidor, você restaura as verificações de segurança normais do servidor e solicita que ele utilize um certificado válido.</translation>
 <translation id="9110235431257073974">Ativar a integração da WebStore no aplicativo Arquivos.</translation>
+<translation id="6489433341782457580">Para desenvolvedores: use o serviço de sandbox para chamadas da API da Carteira virtual do Google para requestAutocomplete().</translation>
 <translation id="8186609076106987817">O servidor não encontrou o arquivo.</translation>
 <translation id="2846816712032308263">Ativa o fechamento rápido de guias/janelas – executa um gerenciador js de onunload da guia, independentemente da GUI.</translation>
 <translation id="9134410174832249455">O <ph name="PRODUCT_NAME"/> não pôde carregar a página porque <ph name="HOST_NAME"/> demorou muito para responder. O site está em manutenção ou sua conexão com a Internet não está funcionando.</translation>
@@ -346,6 +348,7 @@
 <translation id="8959810181433034287">O usuário supervisionado precisará usar esta senha para fazer login. Portanto, escolha uma senha segura e lembre-se de informá-la ao usuário supervisionado.</translation>
 <translation id="5154917547274118687">Memória</translation>
 <translation id="1493492096534259649">Este idioma não pode ser utilizado no corretor ortográfico</translation>
+<translation id="2103866351350079276">Desativar o objeto MediaSource sem prefixo. Este objeto permite que o JavaScript envie dados de mídia diretamente para um elemento de vídeo.</translation>
 <translation id="6628463337424475685">Pesquisa do <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Ativar a opção de enviar informações extras de autenticação no pacote SYN inicial para um cliente anteriormente conectado, permitindo mais rapidez no início do envio de dados.</translation>
 <translation id="6563261555270336410">Detalhes sobre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1577,6 +1580,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Métricas relacionadas à velocidade em que o <ph name="SHORT_PRODUCT_NAME"/> realiza as ações solicitadas</translation>
+<translation id="2048118585307365263">Ativar MediaDrm.</translation>
 <translation id="4091434297613116013">folhas de papel</translation>
 <translation id="7475671414023905704">URL da senha perdida do Netscape</translation>
 <translation id="3335947283844343239">Reabrir guia fechada</translation>
@@ -2919,7 +2923,7 @@
 <translation id="2319236583141234177">Verifique suas configurações de DNS.</translation>
 <translation id="114140604515785785">Diretório raiz da extensão:</translation>
 <translation id="6664237456442406323">Infelizmente, seu computador está configurado com um ID de hardware mal formado. Isso impede que o Chrome OS seja atualizado com as correções de segurança mais recentes e, por isso, seu computador <ph name="BEGIN_BOLD"/>pode ficar vulnerável a ataques maliciosos<ph name="END_BOLD"/>.</translation>
-<translation id="785160701896930981">Foi criado um usuário supervisionado chamado <ph name="NEW_PROFILE_NAME"/>. Para definir quais websites esse usuário pode visualizar, defina restrições e configurações acessando <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Se você não alterar as configurações padrão, <ph name="NEW_PROFILE_NAME"/> poderá navegar navegar por todos os sites da Web.
+<translation id="785160701896930981">Foi criado um usuário supervisionado chamado <ph name="NEW_PROFILE_NAME"/>. Para definir quais websites esse usuário pode visualizar, defina restrições e configurações acessando <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/>. Se você não alterar as configurações padrão, <ph name="NEW_PROFILE_NAME"/> poderá navegar por todos os sites da Web.
 
 Verifique seu e-mail em <ph name="ACCOUNT_EMAIL"/> para ver estas e outras instruções.</translation>
 <translation id="8493236660459102203">Microfone:</translation>
@@ -3817,6 +3821,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> quer armazenar permanentemente dados grandes no computador local.</translation>
 <translation id="373572798843615002">1 guia</translation>
 <translation id="4806065163318322702">Ativar entrada de fala</translation>
+<translation id="6190185222845843088">Usar servidores da sandbox da Carteira virtual do Google</translation>
 <translation id="3177048931975664371">Clique para ocultar senha</translation>
 <translation id="5852137567692933493">Reiniciar e executar PowerWash</translation>
 <translation id="3092544800441494315">Incluir esta captura de tela:</translation>
@@ -4083,6 +4088,7 @@
 <translation id="1639239467298939599">Carregando</translation>
 <translation id="5457599981699367932">Navegar como visitante</translation>
 <translation id="6850233365366645553">Para que seu dispositivo possa ser redefinido com o Powerwash, é necessário reiniciá-lo. O Powerwash redefine seu dispositivo <ph name="IDS_SHORT_PRODUCT_NAME"/> para as condições de novo.</translation>
+<translation id="4292622557427736684">Por padrão, ativar MediaDrm para Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Selecionar cor</translation>
 <translation id="5089363139417863686">Visualizar com o aplicativo Arquivos</translation>
 <translation id="7047998246166230966">Ponteiro</translation>
@@ -4432,6 +4438,7 @@
 <translation id="1728442818359004787">Alterar aplicativo padrão...</translation>
 <translation id="7540972813190816353">Ocorreu um erro durante a verificação de atualizações: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositivo Bluetooth não suportado: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Desativar API Media Source sem prefixo.</translation>
 <translation id="2225024820658613551">Você não deve continuar, &lt;strong&gt;principalmente&lt;/strong&gt; se nunca tiver visto este aviso antes neste site.</translation>
 <translation id="2049639323467105390">Este dispositivo é gerenciado por <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Não antes</translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb
index bdef0e1..f010b9a 100644
--- a/chrome/app/resources/generated_resources_pt-PT.xtb
+++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -132,6 +132,7 @@
 <translation id="1589055389569595240">Mostrar ortografia e gramática</translation>
 <translation id="7017587484910029005">Escreva os caracteres que vê na imagem abaixo.</translation>
 <translation id="9013589315497579992">Certificado de autenticação de cliente SSL incorrecto.</translation>
+<translation id="2085245445866855859">A aplicação com o atributo de manifesto &quot;kiosk_only&quot; tem de ser instalada no modo quiosque do SO Chrome.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> pretende armazenar definitivamente dados no seu dispositivo móvel.</translation>
 <translation id="8524066305376229396">Armazenamento persistente:</translation>
 <translation id="7567293639574541773">I&amp;nspeccionar elemento</translation>
@@ -185,6 +186,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Se eliminar um certificado de servidor, restaurará as verificações de segurança normais para esse servidor e será necessário que o servidor utilize um certificado válido.</translation>
 <translation id="9110235431257073974">Ative a integração da Web Store na aplicação Ficheiros.</translation>
+<translation id="6489433341782457580">Para programadores: utilize o serviço de isolamento de processos para chamadas da API do Google Wallet para requestAutocomplete().</translation>
 <translation id="8186609076106987817">O servidor não conseguiu encontrar o ficheiro.</translation>
 <translation id="2846816712032308263">Ativa o fecho rápido de separadores/janelas – executa um controlador onunload js de um separador independentemente da GUI.</translation>
 <translation id="9134410174832249455">O <ph name="PRODUCT_NAME"/> não conseguiu carregar a página Web porque <ph name="HOST_NAME"/> demorou demasiado a responder. O Web site pode não estar a funcionar ou poderá estar a ter problemas com a sua ligação à internet.</translation>
@@ -355,6 +357,7 @@
 <translation id="8959810181433034287">O utilizador supervisionado vai precisar de utilizar esta palavra-passe para iniciar sessão, logo, escolha uma palavra-passe segura e não se esqueça de a transmitir ao utilizador supervisionado.</translation>
 <translation id="5154917547274118687">Memória</translation>
 <translation id="1493492096534259649">Não é possível utilizar este idioma para a verificação ortográfica</translation>
+<translation id="2103866351350079276">Desativar o objeto MediaSource sem prefixo. Este objeto permite que o JavaScript envie dados multimédia diretamente para elementos de vídeo.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Pesquisar</translation>
 <translation id="6460423884798879930">Ativa a opção para enviar informações de autenticação adicionais no pacote SYN inicial para um cliente ligado anteriormente, permitindo que o envio de dados seja iniciado mais rapidamente.</translation>
 <translation id="6563261555270336410">Detalhes sobre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1590,6 +1593,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [ <ph name="ISSUED_TO"/> ]</translation>
 <translation id="8899388739470541164">Vietnamita</translation>
 <translation id="6423064450797205562">Métricas relacionadas com a velocidade com a qual o <ph name="SHORT_PRODUCT_NAME"/> realiza ações solicitadas</translation>
+<translation id="2048118585307365263">Ativar MediaDrm.</translation>
 <translation id="4091434297613116013">folhas de papel</translation>
 <translation id="7475671414023905704">URL de palavra-passe perdida Netscape</translation>
 <translation id="3335947283844343239">Reabrir separador fechado</translation>
@@ -3838,6 +3842,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> pretende armazenar permanentemente dados de grandes dimensões no seu computador local.</translation>
 <translation id="373572798843615002">1 Separador</translation>
 <translation id="4806065163318322702">Ativar/desativar entrada de voz</translation>
+<translation id="6190185222845843088">Utilizar servidores de isolamento de processos do Google Wallet</translation>
 <translation id="3177048931975664371">Clicar para ocultar a palavra-passe</translation>
 <translation id="5852137567692933493">Reiniciar e executar o Powerwash</translation>
 <translation id="3092544800441494315">Incluir esta captura de ecrã:</translation>
@@ -4104,6 +4109,7 @@
 <translation id="1639239467298939599">A carregar</translation>
 <translation id="5457599981699367932">Navegar como convidado</translation>
 <translation id="6850233365366645553">É necessário reiniciar antes de poder repor o seu dispositivo com a Powerwash. Uma Powerwash repõe o dispositivo <ph name="IDS_SHORT_PRODUCT_NAME"/> para funcionar como se fosse novo.</translation>
+<translation id="4292622557427736684">Ativar o MediaDrm por predefinição para Extensões multimédia encriptadas.</translation>
 <translation id="1812514023095547458">Selecionar a Cor</translation>
 <translation id="5089363139417863686">Ver com a aplicação Ficheiros</translation>
 <translation id="7047998246166230966">Ponteiro</translation>
@@ -4453,6 +4459,7 @@
 <translation id="1728442818359004787">Alterar a aplicação predefinida...</translation>
 <translation id="7540972813190816353">Ocorreu um erro durante a verificação de atualizações: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispositivo Bluetooth não suportado: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Desativar API de Fonte de multimédia sem prefixo.</translation>
 <translation id="2225024820658613551">Não deverá prosseguir, &lt;strong&gt;especialmente&lt;/strong&gt; se nunca tiver visto este aviso relativamente a esse site.</translation>
 <translation id="2049639323467105390">Este aparelho é gerido por <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Não anterior a</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index 0921841..e3d86a2 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Afișați verificarea ortografiei și a gramaticii</translation>
 <translation id="7017587484910029005">Introduceți caracterele din imaginea de mai jos.</translation>
 <translation id="9013589315497579992">Certificat de autentificare client SSL nevalid.</translation>
+<translation id="2085245445866855859">Aplicația cu atributul „kiosk_only” din manifest trebuie să fie instalată în modul chioșc pentru sistemul de operare Chrome.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> dorește să stocheze permanent date pe dispozitivul dvs.</translation>
 <translation id="8524066305376229396">Stocare persistentă:</translation>
 <translation id="7567293639574541773">I&amp;nspectați elementul</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Jucător</translation>
 <translation id="2231238007119540260">Dacă ștergeți un certificat de server, restabiliți verificările de securitate obișnuite pentru serverul respectiv și solicitați utilizarea unui certificat valid.</translation>
 <translation id="9110235431257073974">Activați integrarea Magazinului web și a aplicației Fișiere.</translation>
+<translation id="6489433341782457580">Pentru dezvoltatori: utilizați mediul de testare securizat pentru apelările rutinei requestAutocomplete() din API-ul Wallet.</translation>
 <translation id="8186609076106987817">Serverul nu a putut găsi fișierul.</translation>
 <translation id="2846816712032308263">Activează închiderea rapidă a filei/ferestrei – rulează un handler js onunload al filei independent de GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> nu a putut încărca pagina web, deoarece <ph name="HOST_NAME"/> a avut nevoie de prea mult timp pentru a răspunde. Este posibil ca site-ul să nu funcționeze sau să aveți probleme cu conexiunea la internet.</translation>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">Utilizatorul monitorizat va trebui să utilizeze această parolă pentru a se conecta. Prin urmare, alegeți o parolă sigură și nu uitați să discutați despre aceasta cu utilizatorul monitorizat.</translation>
 <translation id="5154917547274118687">Memorie</translation>
 <translation id="1493492096534259649">Această limbă nu poate fi utilizată pentru o verificare ortografică</translation>
+<translation id="2103866351350079276">Dezactivați obiectul fără prefix MediaSource. Acest obiect permite ca JavaScript să trimită date media direct către un element video.</translation>
 <translation id="6628463337424475685">Căutare <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Activați opțiunea pentru a trimite informații de autentificare suplimentare în pachetul SYN inițial pentru un client conectat anterior, ceea ce permite o pornire mai rapidă a trimiterii datelor.</translation>
 <translation id="6563261555270336410">Detalii despre <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1593,6 +1596,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnameză</translation>
 <translation id="6423064450797205562">Statistici legate de viteza cu care <ph name="SHORT_PRODUCT_NAME"/> efectuează acțiunile solicitate</translation>
+<translation id="2048118585307365263">Activați MediaDrm.</translation>
 <translation id="4091434297613116013">foi de hârtie</translation>
 <translation id="7475671414023905704">Adresă URL pentru parolă pierdută Netscape</translation>
 <translation id="3335947283844343239">Redeschideți fila închisă</translation>
@@ -3858,6 +3862,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vrea să stocheze în mod permanent un volum mare de date pe computerul dvs. local.</translation>
 <translation id="373572798843615002">O filă</translation>
 <translation id="4806065163318322702">Comutați introducerea prin vorbire</translation>
+<translation id="6190185222845843088">Utilizați serverele mediului de testare securizat Wallet</translation>
 <translation id="3177048931975664371">Faceți clic pentru a ascunde parola</translation>
 <translation id="5852137567692933493">Reporniți și efectuați Powerwash</translation>
 <translation id="3092544800441494315">Includeți această captură de ecran:</translation>
@@ -4125,6 +4130,7 @@
 <translation id="1639239467298939599">Se încarcă</translation>
 <translation id="5457599981699367932">Răsfoiți în calitate de invitat</translation>
 <translation id="6850233365366645553">Înainte ca dispozitivul să poată fi resetat utilizând Powerwash, este necesară repornirea acestuia. Utilizarea funcției Powerwash vă resetează dispozitivul <ph name="IDS_SHORT_PRODUCT_NAME"/> la setările din fabrică.</translation>
+<translation id="4292622557427736684">Activați MediaDrm în mod prestabilit pentru Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Selectați o culoare</translation>
 <translation id="5089363139417863686">Afișați utilizând aplicația Fișiere</translation>
 <translation id="7047998246166230966">Cursor</translation>
@@ -4474,6 +4480,7 @@
 <translation id="1728442818359004787">Schimbați aplicația prestabilită...</translation>
 <translation id="7540972813190816353">A avut loc o eroare la verificarea existenței unor actualizări: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Dispozitiv Bluetooth neacceptat: „<ph name="DEVICE_NAME"/>”.</translation>
+<translation id="2990212470195050777">Dezactivați API-ul Media Source fără prefix.</translation>
 <translation id="2225024820658613551">Vă recomandăm să nu continuați, &lt;strong&gt;mai ales&lt;/strong&gt; dacă nu ați mai văzut niciodată acest avertisment pentru acest site.</translation>
 <translation id="2049639323467105390">Acest dispozitiv este gestionat de <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Nu înainte de</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index c50764a..e1469f3 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Показать правописание и грамматику</translation>
 <translation id="7017587484910029005">Введите символы, которые показаны на картинке ниже.</translation>
 <translation id="9013589315497579992">Недопустимый сертификат SSL для аутентификации клиента.</translation>
+<translation id="2085245445866855859">Приложения, у которых в манифесте есть атрибут kiosk_only, можно устанавливать только в режиме информационного киоска.</translation>
 <translation id="1467999917853307373">От <ph name="URL"/> поступил запрос на постоянное хранение данных на вашем мобильном устройстве.</translation>
 <translation id="8524066305376229396">Папка для постоянного хранения:</translation>
 <translation id="7567293639574541773">П&amp;росмотр кода элемента</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Футбол</translation>
 <translation id="2231238007119540260">Если удалить сертификат сервера, восстановится обычная проверка безопасности сервера и будет необходимо использовать допустимый сертификат.</translation>
 <translation id="9110235431257073974">Включить интеграцию Интернет-магазина и приложения &quot;Файлы&quot;.</translation>
+<translation id="6489433341782457580">Разработчикам: для обращения к методу requestAutocomplete() API Кошелька используйте тестовую среду.</translation>
 <translation id="8186609076106987817">Этот файл отсутствует на сервере.</translation>
 <translation id="2846816712032308263">Быстрое  закрытие окон и вкладок – JS-обработчик &quot;onunload&quot; для вкладки выполняется независимо от интерфейса пользователя.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> не удалось загрузить веб-страницу из-за слишком долгого ожидания ответа от <ph name="HOST_NAME"/>. Сайт недоступен или отсутствует интернет-подключение.</translation>
@@ -345,6 +347,7 @@
 <translation id="8959810181433034287">Этот пароль будет использоваться контролируемым пользователем для входа. Выберите надежный пароль и сообщите его пользователю.</translation>
 <translation id="5154917547274118687">Память</translation>
 <translation id="1493492096534259649">Этот язык нельзя использовать для проверки правописания</translation>
+<translation id="2103866351350079276">Отключить объект MediaSource, в котором не используются префиксы. С помощью этого объекта JavaScript может отправлять медиаданные непосредственно в элемент &lt;video&gt;.</translation>
 <translation id="6628463337424475685">Поиск <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Обеспечивает отправку дополнительных данных аутентификации в исходном SYN-пакете подключенного клиента, благодаря чему ускоряется обмен данными.</translation>
 <translation id="6563261555270336410">Подробные сведения о ресурсе <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1582,6 +1585,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Вьетнамская</translation>
 <translation id="6423064450797205562">Показатели скорости выполнения требуемых действий в <ph name="SHORT_PRODUCT_NAME"/></translation>
+<translation id="2048118585307365263">Включить MediaDrm</translation>
 <translation id="4091434297613116013">лист. бумаги</translation>
 <translation id="7475671414023905704">URL потерянных паролей Netscape</translation>
 <translation id="3335947283844343239">Открыть закрытую вкладку</translation>
@@ -3811,6 +3815,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> запрашивает постоянное хранение данных на вашем компьютере.</translation>
 <translation id="373572798843615002">1 вкладка</translation>
 <translation id="4806065163318322702">Голосовой ввод</translation>
+<translation id="6190185222845843088">Использовать тестовую среду для Кошелька</translation>
 <translation id="3177048931975664371">Нажмите, чтобы скрыть пароль</translation>
 <translation id="5852137567692933493">Перезапуск и Powerwash</translation>
 <translation id="3092544800441494315">Включить этот снимок экрана:</translation>
@@ -4077,6 +4082,7 @@
 <translation id="1639239467298939599">Загрузка</translation>
 <translation id="5457599981699367932">Войти в гостевой режим</translation>
 <translation id="6850233365366645553">Перед запуском процесса Powerwash необходимо перезагрузить устройство. После его завершения на вашем устройстве <ph name="IDS_SHORT_PRODUCT_NAME"/> будут восстановлены заводские настройки.</translation>
+<translation id="4292622557427736684">Включить MediaDrm по умолчанию для зашифрованного контента</translation>
 <translation id="1812514023095547458">Выберите цвет</translation>
 <translation id="5089363139417863686">Просмотреть в приложении &quot;Файлы&quot;</translation>
 <translation id="7047998246166230966">Указатель</translation>
@@ -4426,6 +4432,7 @@
 <translation id="1728442818359004787">Изменить приложение по умолчанию...</translation>
 <translation id="7540972813190816353">При проверке обновлений произошла ошибка: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Устройство Bluetooth &quot;<ph name="DEVICE_NAME"/>&quot; не поддерживается.</translation>
+<translation id="2990212470195050777">Отключить API Media Source без префикса</translation>
 <translation id="2225024820658613551">Не стоит продолжать, &lt;strong&gt;особенно&lt;/strong&gt; если ранее вы не видели этого предупреждения для данного сайта.</translation>
 <translation id="2049639323467105390">Это устройство находится в домене <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Не ранее</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index 7f2d0b7..1e98a34 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Zobraziť pravopis a gramatiku</translation>
 <translation id="7017587484910029005">Zadajte znaky na obrázku nižšie.</translation>
 <translation id="9013589315497579992">Chybný certifikát SSL overenia klienta.</translation>
+<translation id="2085245445866855859">Aplikácie s atribútom manifestu „kiosk_only“ musia byť nainštalované v režime verejného terminálu OS Chrome.</translation>
 <translation id="1467999917853307373">Stránky <ph name="URL"/> chcú natrvalo ukladať údaje do vášho zariadenia.</translation>
 <translation id="8524066305376229396">Trvalý ukladací priestor:</translation>
 <translation id="7567293639574541773">&amp;Preskúmať prvok</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Ak odstránite certifikát servera, obnovíte zvyčajné bezpečnostné kontroly servera a server bude musieť používať platný certifikát.</translation>
 <translation id="9110235431257073974">Povoliť integráciu Internetového obchodu a aplikácie Files.app.</translation>
+<translation id="6489433341782457580">Pre vývojárov: pre volania rozhrania API služby Peňaženka „requestAutocomplete()“ používajte službu v karanténe.</translation>
 <translation id="8186609076106987817">Server nemohol nájsť súbor.</translation>
 <translation id="2846816712032308263">Povoliť rýchle zatváranie kariet alebo okien – táto možnosť spustí ovládač karty onunload v jazyku JavaScript nezávisle od hlavného používateľského rozhrania.</translation>
 <translation id="9134410174832249455">Nástroj <ph name="PRODUCT_NAME"/> nemohol načítať webovú stránku, pretože stránkam <ph name="HOST_NAME"/> trvala odpoveď príliš dlho. Webové stránky možno nie sú v prevádzke alebo máte problémy s internetovým pripojením.</translation>
@@ -356,6 +358,7 @@
 <translation id="8959810181433034287">Kontrolovaný používateľ bude toto heslo potrebovať na prihlásenie, preto vyberte bezpečné heslo a nezabudnite ho prekonzultovať s kontrolovaným používateľom.</translation>
 <translation id="5154917547274118687">Pamäť</translation>
 <translation id="1493492096534259649">Tento jazyk nie je možné použiť na kontrolu pravopisu</translation>
+<translation id="2103866351350079276">Zakáže objekt MediaSource bez predpony. Tento objekt umožňuje kódu JavaScript odosielať údaje médií priamo do prvku videa.</translation>
 <translation id="6628463337424475685">Vyhľadávanie <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Povolí možnosť odosielania dodatočných overovacích informácií v počiatočnom balíku SYN predošlého pripojeného klienta a umožní tak rýchlejší štart odosielania údajov.</translation>
 <translation id="6563261555270336410">Podrobnosti o lokalite <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1594,6 +1597,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [ <ph name="ISSUED_TO"/> ]</translation>
 <translation id="8899388739470541164">Vietnamské</translation>
 <translation id="6423064450797205562">Metriky súvisiace s rýchlosťou, s akou prehliadač <ph name="SHORT_PRODUCT_NAME"/> vykonáva požadované akcie</translation>
+<translation id="2048118585307365263">Povoliť ochranu MediaDrm.</translation>
 <translation id="4091434297613116013">listy papiera</translation>
 <translation id="7475671414023905704">Netscape – adresa URL pre zabudnuté heslo</translation>
 <translation id="3335947283844343239">Znova otvoriť zatvorenú kartu</translation>
@@ -2878,7 +2882,7 @@
 <translation id="7525067979554623046">Vytvoriť</translation>
 <translation id="4853020600495124913">Otvoriť v &amp;novom okne</translation>
 <translation id="6847758263950452722">Uložiť stránku vo formáte MHTML</translation>
-<translation id="4217998989792742258">Toto je kontrolovaný používateľ, ktorého spravuje správca <ph name="CUSTODIAN_EMAIL"/></translation>
+<translation id="4217998989792742258">Toto je kontrolovaný používateľ, ktorého bude spravovať <ph name="CUSTODIAN_EMAIL"/></translation>
 <translation id="4711094779914110278">Turecké</translation>
 <translation id="5121130586824819730">Pevný disk je plný. Uložte inde alebo uvoľnite viac miesta na pevnom disku. </translation>
 <translation id="7643802497509977994">Zmeniť späť na miestne nastavenie <ph name="FROM_LOCALE"/> (vyžaduje sa odhlásenie)</translation>
@@ -2946,7 +2950,7 @@
 <translation id="6664237456442406323">Váš počítač je žiaľ nakonfigurovaný pomocou poškodeného ID hardvéru. Systému Chrome OS to zabraňuje získať aktualizácie s najnovšími opravami zabezpečenia a váš počítač <ph name="BEGIN_BOLD"/>môže byť zraniteľný voči škodlivým útokom<ph name="END_BOLD"/>.</translation>
 <translation id="785160701896930981">Vytvoril sa kontrolovaný používateľ s názvom <ph name="NEW_PROFILE_NAME"/>. Ak chcete nastaviť, ktoré webové stránky môže kontrolovaný používateľ zobraziť, môžete prejsť na adresu <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/> a nakonfigurovať obmedzenia a nastavenia. Ak predvolené nastavenia nezmeníte, bude môcť používateľ <ph name="NEW_PROFILE_NAME"/> prehliadať všetky stránky na webe.
 
-Ak chcete získať príslušné pokyny a ďalšie informácie, skontrolujte svoje e-maily na adrese <ph name="ACCOUNT_EMAIL"/>.</translation>
+Tieto a ďalšie inštrukcie nájdete v e-maile, ktorý bol poslaný na adresu <ph name="ACCOUNT_EMAIL"/>.</translation>
 <translation id="8493236660459102203">Mikrofón:</translation>
 <translation id="4788968718241181184">Vietnamská metóda vstupu (TCVN6064)</translation>
 <translation id="3254409185687681395">Vytvoriť záložku pre túto stránku</translation>
@@ -3844,6 +3848,7 @@
 <translation id="3672159315667503033">Stránky <ph name="URL"/> chcú natrvalo ukladať údaje vo vašom počítači.</translation>
 <translation id="373572798843615002">1 karta</translation>
 <translation id="4806065163318322702">Prepnúť hlasový vstup</translation>
+<translation id="6190185222845843088">Použiť servery karantény služby Peňaženka</translation>
 <translation id="3177048931975664371">Kliknutím skryjete heslo</translation>
 <translation id="5852137567692933493">Reštartovať a použiť funkciu Powerwash</translation>
 <translation id="3092544800441494315">Zahrnúť túto snímku obrazovky:</translation>
@@ -4112,6 +4117,7 @@
 <translation id="1639239467298939599">Prebieha načítavanie</translation>
 <translation id="5457599981699367932">Prehliadať ako hosť</translation>
 <translation id="6850233365366645553">Zariadenie je nevyhnutné pred obnovením pomocou funkcie Powerwash reštartovať. Funkcia Powerwash vo vašom zariadení <ph name="IDS_SHORT_PRODUCT_NAME"/> úplne obnoví počiatočné nastavenie.</translation>
+<translation id="4292622557427736684">Povoliť predvolené nastavenie ochrany MediaDrm pre šifrované rozšírenia médií.</translation>
 <translation id="1812514023095547458">Vyberte farbu</translation>
 <translation id="5089363139417863686">Zobraziť pomocou aplikácie Súbory</translation>
 <translation id="7047998246166230966">Kurzor</translation>
@@ -4461,6 +4467,7 @@
 <translation id="1728442818359004787">Zmeniť predvolenú aplikáciu...</translation>
 <translation id="7540972813190816353">Pri kontrole aktualizácií sa vyskytla chyba: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nepodporované zariadenie Bluetooth: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Zakázať rozhranie Media Source API bez predpony.</translation>
 <translation id="2225024820658613551">Nemali by ste pokračovať, &lt;strong&gt;najmä&lt;/strong&gt; ak sa toto upozornenie pre tieto stránky v minulosti nikdy nezobrazilo.</translation>
 <translation id="2049639323467105390">Toto zariadenie je spravované doménou <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Nie pred</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index 9b2c5de..20ed49a 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Pokaži črkovanje in slovnico</translation>
 <translation id="7017587484910029005">Vnesite znake, ki jih vidite na spodnji sliki</translation>
 <translation id="9013589315497579992">Napačno potrdilo preverjanja pristnosti odjemalca SSL.</translation>
+<translation id="2085245445866855859">Aplikacijo z atributom manifesta »kiosk_only« je treba namestiti v načinu kioska ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> želi trajno shranjevati podatke v vašo napravo.</translation>
 <translation id="8524066305376229396">Trajno shranjevanje:</translation>
 <translation id="7567293639574541773">P&amp;reglej element</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Če izbrišete strežniško potrdilo, znova vzpostavite običajna varnostna preverjanja za ta strežnik in zahtevate uporabo veljavnega potrdila.</translation>
 <translation id="9110235431257073974">Omogočanje integracije spletne trgovine in aplikacije Files.app.</translation>
+<translation id="6489433341782457580">Za razvijalce: za pozive API-ja za Google Denarnico za requestAutocomplete() uporabite storitev v peskovniku.</translation>
 <translation id="8186609076106987817">Strežnik ni mogel najti datoteke.</translation>
 <translation id="2846816712032308263">Omogoči hitro zapiranje zavihka/okna – zažene rutino za obravnavo onunload js za zavihek neodvisno od grafičnega uporabniškega vmesnika.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> ni mogel naložiti strani, ker se <ph name="HOST_NAME"/> predolgo ne odziva. Mesto morda ne deluje ali pa imate težave z internetno povezavo.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">Nadzorovani uporabnik bo potreboval to geslo za prijavo, zato izberite varno geslo in se ne pozabite o tem pogovoriti z nadzorovanim uporabnikom.</translation>
 <translation id="5154917547274118687">Pomnilnik</translation>
 <translation id="1493492096534259649">Tega jezika ni mogoče uporabiti za preverjanje črkovanja</translation>
+<translation id="2103866351350079276">Onemogoči predmet MediaSource brez predpone. Ta predmet omogoča JavaScriptu pošiljanje podatkov predstavnosti neposredno videoelementu.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Iskanje</translation>
 <translation id="6460423884798879930">To možnost omogočite, če želite za odjemalca, ki je že bil povezan, v začetnem paketu SYN poslati dodatne podatke za preverjanje pristnosti, tako da bo začetek pošiljanja podatkov hitrejši.</translation>
 <translation id="6563261555270336410">Podrobnosti o <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1590,6 +1593,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamščina</translation>
 <translation id="6423064450797205562">Meritve o hitrosti, s katero storitev <ph name="SHORT_PRODUCT_NAME"/> izvaja zahtevana dejanja</translation>
+<translation id="2048118585307365263">Omogoči MediaDrm.</translation>
 <translation id="4091434297613116013">listi papirja</translation>
 <translation id="7475671414023905704">Spletni naslov izgubljenega Netscapeovega gesla</translation>
 <translation id="3335947283844343239">Znova odpri zaprt zavihek</translation>
@@ -3853,6 +3857,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> želi trajno shraniti velike količine podatkov v vašem računalniku.</translation>
 <translation id="373572798843615002">1 zavihek</translation>
 <translation id="4806065163318322702">Preklopi glasovni vnos</translation>
+<translation id="6190185222845843088">Uporabi strežnike za Google Denarnico v peskovniku</translation>
 <translation id="3177048931975664371">Kliknite, če želite skriti geslo</translation>
 <translation id="5852137567692933493">Ponovni zagon in izvedba funkcije Powerwash</translation>
 <translation id="3092544800441494315">Vključuje ta posnetek zaslona:</translation>
@@ -4120,6 +4125,7 @@
 <translation id="1639239467298939599">Nalaganje</translation>
 <translation id="5457599981699367932">Brskajte kot gost</translation>
 <translation id="6850233365366645553">Pred ponastavitvijo s funkcijo Powerwash je treba napravo znova zagnati. S to funkcijo ponastavite napravo <ph name="IDS_SHORT_PRODUCT_NAME"/> na začetne nastavitve.</translation>
+<translation id="4292622557427736684">Privzeto omogoči MediaDrm za razširitve za šifrirane predstavnosti.</translation>
 <translation id="1812514023095547458">Izbira barve</translation>
 <translation id="5089363139417863686">Prikaz v aplikaciji Datoteke</translation>
 <translation id="7047998246166230966">Kazalec</translation>
@@ -4470,6 +4476,7 @@
 <translation id="1728442818359004787">Spremeni privzeto aplikacijo ...</translation>
 <translation id="7540972813190816353">Napaka pri preverjanju posodobitev: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Nepodprta naprava Bluetooth: »<ph name="DEVICE_NAME"/>«.</translation>
+<translation id="2990212470195050777">Onemogoči API za MediaSource brez predpone.</translation>
 <translation id="2225024820658613551">Priporočamo, da ne nadaljujete, &lt;strong&gt;zlasti&lt;/strong&gt; če za to spletno mesto še niste videli tega opozorila.</translation>
 <translation id="2049639323467105390">To napravo upravlja <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Ne pred</translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb
index e4177db..96d659f 100644
--- a/chrome/app/resources/generated_resources_sr.xtb
+++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Прикажи правопис и граматику</translation>
 <translation id="7017587484910029005">Унесите знакове које видите на слици испод.</translation>
 <translation id="9013589315497579992">Неисправaн сертификат за потврду идентитета SSL клијента.</translation>
+<translation id="2085245445866855859">Апликација са атрибутом манифеста „kiosk_only“ мора да се инсталира у режиму киоска у Chrome ОС-у.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> жели да трајно складишти податке на уређају.</translation>
 <translation id="8524066305376229396">Трајна меморија:</translation>
 <translation id="7567293639574541773">И&amp;спитај елемент</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Фриц</translation>
 <translation id="2231238007119540260">Уколико избришете серверски сертификат, враћате уобичајене безбедносне провере за тај сервер и захтевате да користи важећи сертификат.</translation>
 <translation id="9110235431257073974">Омогући интеграцију Веб-продавнице и апликације Датотеке.</translation>
+<translation id="6489433341782457580">За програмере: Користите услугу у заштићеном окружењу за позиве API-ја Новчаника за requestAutocomplete().</translation>
 <translation id="8186609076106987817">Сервер није могао да пронађе датотеку.</translation>
 <translation id="2846816712032308263">Омогућава брзо затварање картице/прозора – покреће js обрађивач onunload на картици независно од графичког корисничког интерфејса.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> није могао да учита веб-страницу јер је хосту <ph name="HOST_NAME"/> било потребно превише времена за одговор. Можда је веб сајт неисправан или имате проблема са интернет везом.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">Корисник под надзором ће морати да користи ову лозинку да би се пријављивао и зато изаберите безбедну лозинку и обавезно поразговарајте о њој са корисником под надзором.</translation>
 <translation id="5154917547274118687">Меморија</translation>
 <translation id="1493492096534259649">Није могуће користити овај језик за проверу правописа</translation>
+<translation id="2103866351350079276">Онемогућите MediaSource објекат без префикса. Овај објекат омогућава да JavaScript шаље медијске податке директно у видео елемент.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> претрага</translation>
 <translation id="6460423884798879930">Омогућите опцију за слање додатних информација за потврду аутентичности у почетном SYN пакету за претходно повезаног клијента, што омогућава бржи почетак слања података.</translation>
 <translation id="6563261555270336410">Детаљи о хосту <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1597,6 +1600,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">вијетнамски</translation>
 <translation id="6423064450797205562">Показатељи који се односе на брзину којом <ph name="SHORT_PRODUCT_NAME"/> обавља захтеване радње</translation>
+<translation id="2048118585307365263">Омогући MediaDrm.</translation>
 <translation id="4091434297613116013">листови папира</translation>
 <translation id="7475671414023905704">Netscape URL адреса за изгубљену лозинку</translation>
 <translation id="3335947283844343239">Поново отвори затворену картицу</translation>
@@ -3854,6 +3858,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> жели да трајно складишти велику количину података на локалном рачунару.</translation>
 <translation id="373572798843615002">1 картица</translation>
 <translation id="4806065163318322702">Укључује/искључује говорни унос</translation>
+<translation id="6190185222845843088">Користи сервере Новчаника у заштићеном окружењу</translation>
 <translation id="3177048931975664371">Кликните да бисте сакрили лозинку</translation>
 <translation id="5852137567692933493">Поново покрени и обави Powerwash</translation>
 <translation id="3092544800441494315">Укључи овај снимак екрана:</translation>
@@ -4123,6 +4128,7 @@
 <translation id="1639239467298939599">Учитавање</translation>
 <translation id="5457599981699367932">Прегледај као гост</translation>
 <translation id="6850233365366645553">Потребно је поновно покретање да би уређај могао да се врати на почетна подешавања помоћу Powerwash-а. Powerwash враћа <ph name="IDS_SHORT_PRODUCT_NAME"/> уређај на почетна подешавања тако да буде као нов.</translation>
+<translation id="4292622557427736684">Подразумевано омогућите MediaDrm за додатке за шифроване медије.</translation>
 <translation id="1812514023095547458">Избор боја</translation>
 <translation id="5089363139417863686">Прикажи помоћу апликације Датотеке</translation>
 <translation id="7047998246166230966">Показивач</translation>
@@ -4473,6 +4479,7 @@
 <translation id="1728442818359004787">Промени подразумевану апликацију...</translation>
 <translation id="7540972813190816353">Дошло је до грешке при провери ажурирања: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Неподржани Bluetooth уређај: „<ph name="DEVICE_NAME"/>“.</translation>
+<translation id="2990212470195050777">Онемогући API за извор медија без префикса.</translation>
 <translation id="2225024820658613551">Не би требало да наставите &lt;strong&gt;нарочито&lt;/strong&gt; ако никада раније нисте видели ово упозорење за овај сајт.</translation>
 <translation id="2049639323467105390">Овим уређајем управља домен <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Не пре</translation>
@@ -4627,7 +4634,7 @@
 <translation id="3366404380928138336">Захтев спољног протокола</translation>
 <translation id="5300589172476337783">Прикажи</translation>
 <translation id="3160041952246459240">На датотеци постоје сертификати који идентификују следеће сервере:</translation>
-<translation id="566920818739465183">Први пут сте посетили овај сајт дана <ph name="VISIT_DATE"/>.</translation>
+<translation id="566920818739465183">Први пут сте посетили овај сајт <ph name="VISIT_DATE"/></translation>
 <translation id="2961695502793809356">Кликните да бисте отишли напред, задржите да бисте видели историју</translation>
 <translation id="4092878864607680421">Најновија верзија апликације „<ph name="APP_NAME"/>“ захтева више дозвола па је онемогућена.</translation>
 <translation id="4242168008489677578">Омиљено:</translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index e807899..7052e53 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Visa stavning och grammatik</translation>
 <translation id="7017587484910029005">Skriv de tecken som du ser i bilden nedan.</translation>
 <translation id="9013589315497579992">Felaktigt SSL-klientautentiseringscertifikat.</translation>
+<translation id="2085245445866855859">En app med manifestattributet kiosk_only måste installeras i kioskläget i Chrome OS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> vill lagra data permanent på din enhet.</translation>
 <translation id="8524066305376229396">Beständig lagring:</translation>
 <translation id="7567293639574541773">&amp;Granska komponent</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Fotboll</translation>
 <translation id="2231238007119540260">Om du tar bort ett servercertifikat återställer du de vanliga säkerhetskontrollerna för servern. Därefter måste servern använda ett giltigt certifikat.</translation>
 <translation id="9110235431257073974">Aktivera integreringen av Webstore i appen Filer.</translation>
+<translation id="6489433341782457580">För utvecklare: använd sandlådstjänsten för anropet requestAutocomplete() för Wallets API.</translation>
 <translation id="8186609076106987817">Servern kunde inte hitta filen.</translation>
 <translation id="2846816712032308263">Aktiverar snabb stängning av flikar/fönster – kör en fliks js-hanterare som inte lästs in oberoende av GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -361,6 +363,7 @@
 <translation id="8959810181433034287">Den övervakade användaren behöver använda detta lösenord för att logga in, så välj ett säkert lösenord och kom ihåg att diskutera det med den övervakade användaren.</translation>
 <translation id="5154917547274118687">Minne</translation>
 <translation id="1493492096534259649">Stavningskontrollen kan inte utföras på detta språk</translation>
+<translation id="2103866351350079276">Inaktivera det icke-framförställda MediaSource-objektet. Med detta objekt kan mediedata skickas direkt till ett videoelement via JavaScript.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Sök</translation>
 <translation id="6460423884798879930">Aktiverar alternativet att skicka extra autentiseringsuppgifter i det första SYN-paketet för tidigare anslutna klienter, så att autentiseringen går snabbare.</translation>
 <translation id="6563261555270336410">Information om <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1601,6 +1604,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamesiska</translation>
 <translation id="6423064450797205562">Statistik för den hastighet med vilken <ph name="SHORT_PRODUCT_NAME"/> utför begärda åtgärder</translation>
+<translation id="2048118585307365263">Aktivera MediaDrm.</translation>
 <translation id="4091434297613116013">pappersark</translation>
 <translation id="7475671414023905704">Netscapes webbadress för förlorat lösenord</translation>
 <translation id="3335947283844343239">Öppna stängd flik igen</translation>
@@ -3846,6 +3850,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> vill lagra data permanent på din lokala dator.</translation>
 <translation id="373572798843615002">1 flik</translation>
 <translation id="4806065163318322702">Talindata av/på</translation>
+<translation id="6190185222845843088">Använd Wallets sandlådeservrar</translation>
 <translation id="3177048931975664371">Klicka om du vill dölja lösenordet</translation>
 <translation id="5852137567692933493">Starta om och gör en Powerwash</translation>
 <translation id="3092544800441494315">Ta med skärmdump:</translation>
@@ -4112,6 +4117,7 @@
 <translation id="1639239467298939599">Läser in</translation>
 <translation id="5457599981699367932">Läs som gäst</translation>
 <translation id="6850233365366645553">En omstart krävs innan enheten kan återställas med en powerwash. Med en powerwash återställs <ph name="IDS_SHORT_PRODUCT_NAME"/>-enheten så att den blir som ny.</translation>
+<translation id="4292622557427736684">Aktiverar MediaDrm som standard för krypterade medietillägg.</translation>
 <translation id="1812514023095547458">Välj färg</translation>
 <translation id="5089363139417863686">Visa med appen Filer</translation>
 <translation id="7047998246166230966">Pekare</translation>
@@ -4462,6 +4468,7 @@
 <translation id="1728442818359004787">Ändra standardapp ...</translation>
 <translation id="7540972813190816353">Det gick inte att söka efter uppdateringar: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Bluetooth-enhet som inte stöds: <ph name="DEVICE_NAME"/>.</translation>
+<translation id="2990212470195050777">Inaktivera det icke-framförställda API:et Media Source.</translation>
 <translation id="2225024820658613551">Fortsätt inte, &lt;strong&gt;i synnerhet inte&lt;/strong&gt; om  den här varningen aldrig har visats tidigare på webbplatsen.</translation>
 <translation id="2049639323467105390">Den här enheten hanteras av <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Inte före</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index 0a3c720..1ac7806 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -78,7 +78,7 @@
 <translation id="8546541260734613940">[*.]example.com</translation>
 <translation id="524759338601046922">Charaza tena PIN mpya</translation>
 <translation id="2580889980133367162">Ruhusu <ph name="HOST"/> kupakua faili nyingi wakati wote</translation>
-<translation id="8972513834460200407">Tafadhali wasiliana na msimamzi wako wa mtandao ili uhakikishe kuwa ngome haizuii vipakuzi kutoka kwenye seva za Google.</translation>
+<translation id="8972513834460200407">Tafadhali wasiliana na msimamzi wako wa mtandao ili uhakikishe kuwa ngome haizuii vipakuliwa kutoka seva za Google.</translation>
 <translation id="6562437808764959486">Inachopoa picha ya ufufuzi...</translation>
 <translation id="1260240842868558614">Onyesha:</translation>
 <translation id="2226449515541314767">Tovuti imezuiwa isiwe na udhibiti kamili wa vifaa vya MIDI.</translation>
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">Onyesha Tahajia na Sarufi</translation>
 <translation id="7017587484910029005">Chapa herufi unazoziona katika picha iliyo hapo chini.</translation>
 <translation id="9013589315497579992">Cheti kibaya cha uthibitishaji wa teja ya SSL</translation>
+<translation id="2085245445866855859">Programu iliyo na kipengee cha maelezo ya 'kiosk_only' lazima isakinishwe katika skrini nzima ya Mfumo wa Uendeshaji wa Chrome</translation>
 <translation id="1467999917853307373"><ph name="URL"/> inataka kuhifadhi data kwenye kifaa chako milele.</translation>
 <translation id="8524066305376229396">Hifadhi inayoendelea:</translation>
 <translation id="7567293639574541773">&amp;Kagua sehemu</translation>
@@ -183,6 +184,7 @@
 <translation id="4858913220355269194">Fritz</translation>
 <translation id="2231238007119540260">Ukifuta cheti cha seva, unarejesha upya ukaguzi salama wa kawaida kwa seva hiyo na unaihitaji kutumia cheti halali.</translation>
 <translation id="9110235431257073974">Washa muingiliano wa duka la Wavuti na Files.app.</translation>
+<translation id="6489433341782457580">Kwa wasanidi programu: tumia huduma ya sehemu ya majaribio kwa simu za API ya Google Wallet ili kukamilisha maombi Kiotomatiki().</translation>
 <translation id="8186609076106987817">Seva hii haikuweza kupata faili.</translation>
 <translation id="2846816712032308263">Huwasha ufungaji wa haraka wa kichupo/dirisha - huendesha vishikilizi vya onunload js vya kichupo kwa kujitegemea kando ya GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/>
@@ -354,6 +356,7 @@
 <translation id="8959810181433034287">Mtumiaji anayesimamiwa atahitaji kutumia nenosiri hili ili kuingia katika akaunti, hivyo chagua nenosiri salama na ukumbuke kulijadili npamoja na mtumiaji anayesimamiwa.</translation>
 <translation id="5154917547274118687">Kumbukumbu</translation>
 <translation id="1493492096534259649">Lugha hii haiwezi kutumika kwa kukagua tajahia</translation>
+<translation id="2103866351350079276">Zima kifaa cha Chanzo cha Maudhui kisichoambishwa. Kifaa hiki kinaruhusu JavaScript kutuma data ya maudhui moja kwa moja kwa kipengee cha video.</translation>
 <translation id="6628463337424475685">Utafutaji wa <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Washa chaguo la kutuma maelezo zaidi ya uthibitishaji katika furushi la kwanza la SYN kwa mteja aliyeunganishwa awali, ili kuruhusu kuanza haraka kutuma data kwa kasi.</translation>
 <translation id="6563261555270336410">Maelezo kuhusu <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -402,7 +405,7 @@
 <translation id="5516565854418269276">&amp;Onyesha upau wa alamisho kila wakati</translation>
 <translation id="6426222199977479699">Hitilafu ya SSL</translation>
 <translation id="2688196195245426394">Hitilafu wakati wa kusajili kifaa kwa seva: <ph name="CLIENT_ERROR"/>.</translation>
-<translation id="667115622929458276">Vipakuzi vya chini kwa chini vinendelea sasa. Je, ungependa kutoka kwenye modi ya chini kwa chini na kughairi vipakuzi?</translation>
+<translation id="667115622929458276">Kuna vipakuliwa vinavyoendelea chinichini. Je, ungependa kutoka kwenye modi ya chinichini na kukatiza vipakuliwa?</translation>
 <translation id="1528372117901087631">Muunganisho wa mtandao</translation>
 <translation id="1788636309517085411">Tumia chaguo-msingi</translation>
 <translation id="1228893227497259893">Kitambulisho cha huluki kisicho halali</translation>
@@ -1254,7 +1257,7 @@
 <translation id="14171126816530869">Utambulisho wa <ph name="ORGANIZATION"/> iliyo <ph name="LOCALITY"/> umethibitishwa na <ph name="ISSUER"/>.</translation>
 <translation id="220858061631308971">Tafadhali ingiza msimbo huu wa PIN kwenye &quot;<ph name="DEVICE_NAME"/>&quot;:</translation>
 <translation id="6263082573641595914">Toleo la Mamlaka ya Cheti la Microsoft</translation>
-<translation id="953345106084818179">Omba ruhusa</translation>
+<translation id="953345106084818179">Omba idhini</translation>
 <translation id="3105917916468784889">Piga picha kiwamba</translation>
 <translation id="6000902307058248087">Niulize wakati tovuti inapohitaji kuifikia maikrofoni yangu (imependekezwa)</translation>
 <translation id="1587275751631642843">Kidhibiti Hati&amp;Java</translation>
@@ -1386,13 +1389,13 @@
 <translation id="839736845446313156">Sajili</translation>
 <translation id="2660779039299703961">Tukio</translation>
 <translation id="4249248555939881673">Inasubiri muunganisho kwa mtandao...</translation>
-<translation id="8651130890368571179">Mtumiaji anayesimamiwa anaweza kungundua wavuti kwa uongozi wako. Kama mdhibiti wa mtumiaji anayesimamiwa katika Chrome, unaweza 
+<translation id="8651130890368571179">Mtumiaji anayesimamiwa anaweza kuvinjari wavuti chini ya uongozi wako. Kama mdhibiti wa mtumiaji anayesimamiwa katika Chrome, unaweza 
 
 • kuruhusu au kuzuia tovuti fulani, 
 • kukagua tovuti ambazo mtumiaji anayesimamiwa ametembelea, na 
 • kusimamia mipangilio mingine. 
 
-Kuunda mtumiaji anayesimamiwa huwa haiundi Akaunti ya Google, na mipangilio yake na data haitamfuata kwenye vifaa vingine vilivyo na Usawazishaji wa Chrome. Hivi sasa, mtumiaji anayesimamiwa anahusika tu na usanidi huu wa Chrome, kwenye kifaa hiki. 
+Kuunda mtumiaji anayesimamiwa huwa haiundi Akaunti ya Google. Pia mipangilio yake na data haitatumika kwenye vifaa vingine vilivyo na Usawazishaji wa Chrome. Hivi sasa, mtumiaji huyu anasimamiwa tu kwenye kivinjari hiki cha Chrome, kwenye kifaa hiki. 
 
 Baada ya kuunda mtumiaji mpya anayesimamiwa, unaweza kudhibiti mipangilio yake wakati wowote, kutoka kwenye kifaa chochote, katika www.chrome.com/manage.</translation>
 <translation id="2409527877874991071">Ingiza jina jipya</translation>
@@ -1589,6 +1592,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Kivietinamu</translation>
 <translation id="6423064450797205562">Metriki zinazohusiana na kasi ambayo <ph name="SHORT_PRODUCT_NAME"/> hutekelelza vitendo vilivyoombwa</translation>
+<translation id="2048118585307365263">Washa MediaDrm.</translation>
 <translation id="4091434297613116013">laha za karatasi</translation>
 <translation id="7475671414023905704">URL ya Nenosiri la Netscape Lililopotea</translation>
 <translation id="3335947283844343239">Fungua Tena Kichupo Kilichofugwa</translation>
@@ -1989,7 +1993,7 @@
 <translation id="6624687053722465643">Utamu</translation>
 <translation id="3021256392995617989">Niulize wakati tovuti inapojaribu kufuatilia mahali nilipo (imependekezwa)</translation>
 <translation id="8083739373364455075">Pata GB 100 bila malipo kwa Hifadhi ya Google</translation>
-<translation id="271083069174183365">Mipangilio ingizo ya Kijaapani</translation>
+<translation id="271083069174183365">Mipangilio ya Hati ya Kijapani</translation>
 <translation id="5185386675596372454">Toleo jipya zaidi la &quot;<ph name="EXTENSION_NAME"/>&quot; limezimwa kwa sababu linahitaji idhini zaidi.</translation>
 <translation id="4147376274874979956">Haiwezi kufikia faili..</translation>
 <translation id="4285669636069255873">Kibodi fonetiki ya Kirusi</translation>
@@ -2501,7 +2505,7 @@
 <translation id="4647090755847581616">&amp;Funga Kichupo</translation>
 <translation id="2649204054376361687"><ph name="CITY"/>, <ph name="COUNTRY"/></translation>
 <translation id="7886758531743562066"> Tovuti iliyo <ph name="HOST_NAME"/> ina sehemu kutoka tovuti zinazoonekana kupangisha programu-hasidi - programu zinazoweza kudhuru kompyuta yako au kufanya kazi bila idhini yako. Kutembelea tovuti iliyo na programu-hasidi tu kunaweza kuiambukiza kompyuta yako.</translation>
-<translation id="4012185032967847512">Lo! Inaonekana unahitaji ruhusa kutoka kwa <ph name="NAME"/> ili kufikia ukurasa huu.</translation>
+<translation id="4012185032967847512">Lo! Inaonekana unahitaji idhini kutoka kwa <ph name="NAME"/> ili uweze kuufikia ukurasa huu.</translation>
 <translation id="6593868448848741421">bora</translation>
 <translation id="7126604456862387217">'&lt;b&gt;<ph name="SEARCH_STRING"/>&lt;/b&gt;' - &lt;em&gt;Hifadhi ya utafutaji&lt;/em&gt;</translation>
 <translation id="6181431612547969857">Upakuaji umezuiwa</translation>
@@ -2829,7 +2833,7 @@
 <translation id="5618018737832496935">Washa kipengee cha 'adview'</translation>
 <translation id="8190193592390505034">Inaunganisha kwenye <ph name="PROVIDER_NAME"/></translation>
 <translation id="2433452467737464329">Ongeza hoja ya param katika URL ili uonyeshe ukurasa upya kiotomatiki: chrome://network/?refresh=&lt;sec&gt;</translation>
-<translation id="8712637175834984815">Ninayo</translation>
+<translation id="8712637175834984815">Nimeelewa</translation>
 <translation id="6144890426075165477"><ph name="PRODUCT_NAME"/> sio kivinjari chako chaguo-msingi kwa sasa.</translation>
 <translation id="4068506536726151626">Ukurasa huu una vipengee kutoka tovuti zifuatazo zinazofuatilia mahali ulipo:</translation>
 <translation id="4220128509585149162">Mivurugo</translation>
@@ -2867,7 +2871,7 @@
 <translation id="2912905526406334195"><ph name="HOST"/> inataka kutumia kipazasauti chako.</translation>
 <translation id="2805756323405976993">Programu</translation>
 <translation id="1608626060424371292">Ondoa mtumiaji huyu</translation>
-<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> imeundwa kama mtumiaji anayesimamiwa!</translation>
+<translation id="3075239840551149663"><ph name="NEW_PROFILE_NAME"/> ameongezwa kama mtumiaji anayesimamiwa!</translation>
 <translation id="3651020361689274926">Rasilimali iliyoombwa haipo tena, na hakuna anwani ya kusambaza. Hii itatarajiwa kuwa hali ya kudumu.</translation>
 <translation id="7541236596838501870">Imepakia kumbukumbu za WebRTC (<ph name="WEBRTC_LOG_COUNT"/>)</translation>
 <translation id="6003284010415283671">Ongeza Programu</translation>
@@ -2943,7 +2947,7 @@
 <translation id="2319236583141234177">Angalia mipangilio yako ya DNS.</translation>
 <translation id="114140604515785785">Saraka la shina la kiendelezi:</translation>
 <translation id="6664237456442406323">Kwa bahati mbaya, kompyuta yako imesanidiwa na kitambulisho cha maunzi kilichoharibika. Hii inazuia Chrome OS isisasishe na sasisho za usalama za hivi karibuni na kompyuta yako <ph name="BEGIN_BOLD"/>inaweza ikawa hatarini kutokana na mashambulizi hasidi<ph name="END_BOLD"/>.</translation>
-<translation id="785160701896930981">Mtumiaji anayesimamiwa aitwaye <ph name="NEW_PROFILE_NAME"/> ameundwa. Ili kuweka tovuti ambazo mtumiaji anayesimamiwa anaweza kuona, unaweza kuweka vikwazo na mipangilio kwa kutembelea <ph name="BEGIN_LINK"/> www.chrome.com/manage <ph name="END_LINK"/>. Kama hutabadilisha mipangilio ya msingi, <ph name="NEW_PROFILE_NAME"/> anaweza kuvinjari tovuti zote kwenye wavuti. Tafadhali angalia barua pepe yako katika <ph name="ACCOUNT_EMAIL"/> kwa maelekezo haya na zaidi.</translation>
+<translation id="785160701896930981">Mtumiaji anayesimamiwa aitwaye <ph name="NEW_PROFILE_NAME"/> ameundwa. Ili kuweka tovuti ambazo mtumiaji anayesimamiwa anaweza kuona, unaweza kuweka vikwazo na mipangilio kwa kutembelea <ph name="BEGIN_LINK"/> www.chrome.com/manage <ph name="END_LINK"/>. Kama hutabadilisha mipangilio ya msingi, <ph name="NEW_PROFILE_NAME"/> anaweza kuvinjari tovuti zote kwenye wavuti. Tafadhali angalia barua pepe yako katika <ph name="ACCOUNT_EMAIL"/> kwa maelekezo haya na mengine.</translation>
 <translation id="8493236660459102203">Maikrofoni:</translation>
 <translation id="4788968718241181184">Mbinu ingizo ya Kivietinamu (TCVN6064)</translation>
 <translation id="3254409185687681395">Alamisha ukurasa huu</translation>
@@ -3126,7 +3130,7 @@
 <translation id="5266113311903163739">Hitilafu ya Kuleta ya Mamlaka ya Utojai Vyeti</translation>
 <translation id="4240511609794012987">Kumbukumbu inayoshirikiwa</translation>
 <translation id="4756388243121344051">&amp;Historia</translation>
-<translation id="5488640658880603382">Je, una uhakika unataka kufuta &quot;<ph name="PROFILE_NAME"/>&quot; na data yote  inayohusiana nayo kutoka kwenye kompyuta? Hii haiwezi kutenduliwa!</translation>
+<translation id="5488640658880603382">Una uhakika unataka kufuta &quot;<ph name="PROFILE_NAME"/>&quot; na data yote inayohusishwa naye kutoka kompyuta hii? Kitendo hiki hakiwezi kutenduliwa!</translation>
 <translation id="8044899503464538266">Polepole</translation>
 <translation id="3789841737615482174">Sakinisha</translation>
 <translation id="4320697033624943677">Ongeza watumiaji</translation>
@@ -3531,7 +3535,7 @@
 <translation id="8663099077749055505">Zuia upakuaji otomatiki kwa wingi kwenye <ph name="HOST"/> wakati wote</translation>
 <translation id="778330624322499012">Haikuweza kupakia <ph name="PLUGIN_NAME"/></translation>
 <translation id="9026731007018893674">pakua</translation>
-<translation id="3370581770504921865">Je, una uhakika unataka kufuta &quot;<ph name="PROFILE_NAME"/>&quot;na data yote inayohusiana nayo kutoka kwenye kifaa hiki? Hii haiwezi kutenduliwa!</translation>
+<translation id="3370581770504921865">Una uhakika unataka kufuta &quot;<ph name="PROFILE_NAME"/>&quot; na data yote inayohusishwa naye kutoka kifaa hiki? Kitendo hiki hakiwezi kutenduliwa!</translation>
 <translation id="3212792897911394068">Zima toleo la jaribio la Viendelezi vya Vyombo vya Habari Vilivyosimbwa kwa njia fiche kwenye vipengee vya Video na Sauti.</translation>
 <translation id="6199775032047436064">Pakia upya ukurasa wa sasa</translation>
 <translation id="6981982820502123353">Ufikiaji</translation>
@@ -3834,6 +3838,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> inataka kuhifadhi kabisa data kubwa kwenye kompyuta yako ya ndani.</translation>
 <translation id="373572798843615002">Kichupo 1</translation>
 <translation id="4806065163318322702">Togoa ingizo la usemi</translation>
+<translation id="6190185222845843088">Tumia seva za sehemu ya majaribio ya Google Wallet</translation>
 <translation id="3177048931975664371">Bofya ili kuficha nenosiri</translation>
 <translation id="5852137567692933493">Anzisha upya na Powerwash</translation>
 <translation id="3092544800441494315">Jumuisha picha kiwamba hii:</translation>
@@ -4103,6 +4108,7 @@
 <translation id="1639239467298939599">Inapakia</translation>
 <translation id="5457599981699367932">Vinjari kama Mgeni</translation>
 <translation id="6850233365366645553">Inahitaji kuzima na kuwasha kabla kifaa chako hakijawekwa upya na Powerwash. Powerwash huweka upya kifaa chako cha <ph name="IDS_SHORT_PRODUCT_NAME"/> ili kikue kama kipya tu.</translation>
+<translation id="4292622557427736684">Washa MediaDrm kwa chaguo-msingi kwa Viendelezi vya Maudhui Yaliyosimbwa kwa njia fiche.</translation>
 <translation id="1812514023095547458">Chagua Rangi</translation>
 <translation id="5089363139417863686">Tazama na programu ya Faili</translation>
 <translation id="7047998246166230966">Kionyeshi</translation>
@@ -4133,7 +4139,7 @@
 <translation id="8156020606310233796">Mwonekano wa orodha</translation>
 <translation id="8002980609684534974">Nambari ya wimbo</translation>
 <translation id="146000042969587795">Fremu hii imezuiwa kwa sababu ina maudhui mengine yasiyo salama.</translation>
-<translation id="3258924582848461629">Mbinu ya uingizaji wa maandishi ya mikono kwa Kijapani</translation>
+<translation id="3258924582848461629">Mbinu ya kuandika Hati za Kijapani kwa mkono</translation>
 <translation id="8426564434439698958">Tafuta picha hii kwenye <ph name="SEARCH_ENGINE"/></translation>
 <translation id="4375035964737468845">Fungua faili zilizopakuliwa</translation>
 <translation id="5929159980875900327">Fikia vifaa vya Bluetooth vilivyooanishwa na mfumo wako.</translation>
@@ -4453,6 +4459,7 @@
 <translation id="1728442818359004787">Badilisha programu chaguo-msingi...</translation>
 <translation id="7540972813190816353">Hitilafu ilitokea wakati wa kukagua visasishi: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Kifaa cha Bluetooth kisichoweza kutumiwa: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Zima API za Chanzo cha Maudhui ambazo hazijaambishwa.</translation>
 <translation id="2225024820658613551">Usiendelee, &lt;strong&gt;hususan&lt;/strong&gt; ikiwa bado hujaona onyo hili kwa tovuti hii.</translation>
 <translation id="2049639323467105390">Kifaa hiki kinadhibitiwa na <ph name="DOMAIN"/> .</translation>
 <translation id="1932098463447129402">Sio Kabla</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index cfd953b..50df7bc 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -131,6 +131,7 @@
 <translation id="1589055389569595240">இலக்கணம் மற்றும் எழுத்துப்பிழையைக் காண்பி</translation>
 <translation id="7017587484910029005">கீழேயுள்ள படத்தில் நீங்கள் காணும் எழுத்துக்குறிகளைத் தட்டச்சு செய்க.</translation>
 <translation id="9013589315497579992">தவறான SSL கிளையன்ட் அங்கீகாரச் சான்றிதழ்.</translation>
+<translation id="2085245445866855859">ChromeOS கியோஸ்க் பயன்முறையில், 'kiosk_only' மேனிஃபெஸ்ட் பண்புக்கூற்றுடனான பயன்பாட்டை நிறுவியிருக்க வேண்டும்.</translation>
 <translation id="1467999917853307373"><ph name="URL"/>, உங்கள் சாதனத்தில் தரவை நிரந்தரமாக சேமிக்க விரும்புகிறது.</translation>
 <translation id="8524066305376229396">தொடர்நிலை சேமிப்பகம்:</translation>
 <translation id="7567293639574541773">கூறை&amp;ஆய்வு செய்க</translation>
@@ -184,6 +185,7 @@
 <translation id="4858913220355269194">ஃபிரிட்ஸ்</translation>
 <translation id="2231238007119540260">நீங்கள் ஒரு சேவையக சான்றிதழை நீக்கினால், அந்த சேவையகத்திற்கான வழக்கமான பாதுகாப்பு சரிபார்ப்புகளை மீட்டமைக்கிறீர்கள் மற்றும் அது செல்லுபடியாகும் சான்றிதழைப் பயன்படுத்துமாறும் கோருகிறீர்கள்.</translation>
 <translation id="9110235431257073974">இணைய அங்காடி மற்றும் Files.app ஆகியவற்றின் ஒருங்கிணைப்பை இயக்கு.</translation>
+<translation id="6489433341782457580">டெவெலப்பர்களுக்கானது: requestAutocomplete() க்கான Wallet API அழைப்புகளுக்காக சாண்ட்பாக்ஸ் சேவையைப் பயன்படுத்தவும்.</translation>
 <translation id="8186609076106987817">சேவையகத்தால் கோப்பை கண்டறிய முடியவில்லை.</translation>
 <translation id="2846816712032308263">வேகமான தாவல்/சாளரங்களை மூடுதல் ஆகியவற்றை இயக்குகிறது - GUI ஐச் சாராமலேயே தாவலின் onunload js ஹேண்ட்லரில் இயங்குகிறது.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>
@@ -345,6 +347,7 @@
 <translation id="8959810181433034287">கண்காணிக்கப்படும் பயனர் உள்நுழைவதற்கு இந்தக் கடவுச்சொல்லைப் பயன்படுத்த வேண்டியிருக்கும், அதனால் பாதுகாப்பான கடவுச்சொல்லைத் தேர்வுசெய்யவும், மேலும் கண்காணிக்கப்படும் பயனருடன் இதைப் பற்றி கலந்துரையாட மறக்க வேண்டாம்</translation>
 <translation id="5154917547274118687">நினைவகம்</translation>
 <translation id="1493492096534259649">எழுத்துப்பிழை சரிபார்ப்புக்கு இந்த மொழியைப் பயன்படுத்த முடியாது</translation>
+<translation id="2103866351350079276">முன்ஒட்டு இல்லாத MediaSource பொருளை முடக்கவும். இந்தப் பொருளானது வீடியோ கூறுக்கு நேரடியாக மீடியா தரவை அனுப்ப JavaScript ஐ அனுமதிக்கிறது.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> தேடல்</translation>
 <translation id="6460423884798879930">ஏற்கனவே இணைக்கப்பட்ட கிளையன்ட்டிற்கான துவக்க SYN தொகுப்பில் கூடுதல் அங்கீகாரத் தகவலை அனுப்ப விருப்பத்தை இயக்கவும், இது தரவை விரைவாக அனுப்ப அனுமதிக்கும்.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> பற்றிய விவரங்கள்</translation>
@@ -1586,6 +1589,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">வியட்நாமிஸ்</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> செயல்படுத்தும் கோரப்பட்ட செயல்பாடுகளின் வேகத்துடன் தொடர்பான அளவீடுகள்</translation>
+<translation id="2048118585307365263">MediaDrm ஐ இயக்கு.</translation>
 <translation id="4091434297613116013">தாள்கள்</translation>
 <translation id="7475671414023905704">Netscape தொலைந்த கடவுச்சொல் URL</translation>
 <translation id="3335947283844343239">மூடப்பட்ட தாவலை மீண்டும் திற</translation>
@@ -3818,6 +3822,7 @@
 <translation id="3672159315667503033">உங்கள் அகக் கணினியில், தரவை நிரந்தரமாக சேமிக்க <ph name="URL"/> விரும்புகிறது.</translation>
 <translation id="373572798843615002">1 தாவல்</translation>
 <translation id="4806065163318322702">பேச்சு உள்ளீட்டை நிலைமாற்று</translation>
+<translation id="6190185222845843088">Wallet சாண்ட்பாக்ஸ் சேவையகங்களைப் பயன்படுத்து</translation>
 <translation id="3177048931975664371">கடவுச்சொல்லை மறைக்க கிளிக் செய்க</translation>
 <translation id="5852137567692933493">மீண்டும் தொடங்கி, பவர்வாஷ் செய்க</translation>
 <translation id="3092544800441494315">இந்த திரைபிடிப்பைச் சேர்:</translation>
@@ -4082,6 +4087,7 @@
 <translation id="1639239467298939599">ஏற்றுகிறது</translation>
 <translation id="5457599981699367932">விருந்தினராக உலாவுங்கள்</translation>
 <translation id="6850233365366645553">உங்கள் சாதனத்தைப் பவர்வாஷ் மூலம் மீட்டமைக்கும் முன்பு மறுதொடக்கம் செய்தல் அவசியமாகும். பவர்வாஷ் ஆனது உங்கள் <ph name="IDS_SHORT_PRODUCT_NAME"/> சாதனத்தைப் புதியது போன்று மீட்டமைக்கும்.</translation>
+<translation id="4292622557427736684">முறைமையாக்கப்பட்ட மீடியா நீட்டிப்புகளுக்கான இயல்புநிலையாக MediaDrm ஐ இயக்கு.</translation>
 <translation id="1812514023095547458">வண்ணத்தைத் தேர்ந்தெடு</translation>
 <translation id="5089363139417863686">கோப்புகள் பயன்பாட்டின் மூலம் காட்டு</translation>
 <translation id="7047998246166230966">பாயிண்டர்</translation>
@@ -4432,6 +4438,7 @@
 <translation id="1728442818359004787">இயல்புநிலைப் பயன்பாட்டை மாற்று...</translation>
 <translation id="7540972813190816353">புதுப்பிப்பதற்கு தேர்வுசெய்யும்போது பிழை ஏற்பட்டது: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">ஆதரிக்கப்படாத Bluetooth சாதனம்: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">முன்ஒட்டு இல்லாத மீடியா ஆதார API ஐ முடக்கு.</translation>
 <translation id="2225024820658613551">இந்த தளத்தில் இதற்கு முன்பு இந்த எச்சரிக்கையைப் பார்க்கவில்லை எனில், &lt;strong&gt;குறிப்பாக&lt;/strong&gt; நீங்கள் தொடர முடியாது.</translation>
 <translation id="2049639323467105390"><ph name="DOMAIN"/> ஆல் இந்த சாதனம் நிர்வகிக்கப்படுகிறது.</translation>
 <translation id="1932098463447129402">இதற்குமுன் அல்ல</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index cc24e4d..8287ceb 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">అక్షరక్రమం మరియు వ్యాకరణం చూపించు</translation>
 <translation id="7017587484910029005">క్రింద ఉన్న చిత్రంలో మీరు చూస్తున్న అక్షరాలను టైప్ చెయ్యండి.</translation>
 <translation id="9013589315497579992">తప్పుడు SSL క్లయింట్ ప్రామాణీకరణ సర్టిఫికెట్.</translation>
+<translation id="2085245445866855859">'kiosk_only' మానిఫెస్ట్ లక్షణం గల అనువర్తనాన్ని తప్పనిసరిగా ChromeOS కియోస్క్ మోడ్‌లో ఇన్‌స్టాల్ చేయాలి.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> శాశ్వతంగా డేటాను మీ పరికరంలో నిల్వ చేయాలనుకుంటోంది.</translation>
 <translation id="8524066305376229396">శాశ్వత నిల్వ:</translation>
 <translation id="7567293639574541773">ఎలిమెంట్‌ను క్షుణ్ణంగా ప&amp;రిశీలించండి</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">ఫ్రిట్జ్</translation>
 <translation id="2231238007119540260">మీరు సర్వర్ ప్రమాణపత్రాన్ని తొలగిస్తే, సర్వర్ కోసం మీరు సాధారణ భద్రతా తనిఖీలను పునరుద్ధరించండి మరియు చెల్లుబాటు అయ్యే ప్రమాణపత్రాన్ని ఉపయోగించడానికి ఇది అవసరం.</translation>
 <translation id="9110235431257073974">వెబ్‌స్టోర్ మరియు Files.app యొక్క ఏకీకరణను ప్రారంభించండి.</translation>
+<translation id="6489433341782457580">డెవలపర్‌ల కోసం: requestAutocomplete()కి సంబంధించిన Wallet API కాల్‌ల కోసం శాండ్‌బాక్స్ సేవను ఉపయోగించండి.</translation>
 <translation id="8186609076106987817">సర్వర్ ఫైల్‌ని కనుగొనలేకపోయింది.</translation>
 <translation id="2846816712032308263">వేగంగా ట్యాబ్/విండో మూసివేతను ప్రారంభిస్తుంది - ట్యాబ్ యొక్క onunload js హ్యాండ్లర్‌ను GUI లేకుండా స్వతంత్రంగా అమలు చేస్తుంది.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>
@@ -349,6 +351,7 @@
 <translation id="8959810181433034287">పర్యవేక్షించబడే వినియోగదారు సైన్ ఇన్ చేయడానికి ఈ పాస్‌వర్డ్‌ను ఉపయోగించాల్సి ఉంటుంది, అందువల్ల సురక్షితమైన పాస్‌వర్డ్‌ను ఎంచుకుని, దాన్ని పర్యవేక్షించబడే వినియోగదారుతో చర్చించాలని గుర్తుంచుకోండి.</translation>
 <translation id="5154917547274118687">మెమరీ</translation>
 <translation id="1493492096534259649">అక్షర క్రమం తనిఖీ కోసం ఈ భాష ఉపయోగించబడదు</translation>
+<translation id="2103866351350079276">పూర్వప్రత్యయం లేని MediaSource ఆబ్జెట్‌ను నిలిపివేయండి. ఈ ఆబ్జెట్ మీడియా డేటాను నేరుగా వీడియో మూలకానికి పంపడానికి జావాస్క్రిప్ట్‌ని అనుమతిస్తుంది.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> శోధన</translation>
 <translation id="6460423884798879930">మునుపు కనెక్ట్ చేయబడిన క్లయింట్ కోసం వేగంగా డేటాను పంపడాన్ని ప్రారంభించడానికి అనుమతిస్తూ, ప్రాథమిక SYN ప్యాకెట్‌లో అదనపు ప్రామాణీకరణ సమాచారాన్ని పంపడానికి ఎంపికను ప్రారంభించండి.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> గురించి వివరాలు</translation>
@@ -1261,7 +1264,7 @@
 <translation id="14171126816530869"><ph name="LOCALITY"/> వద్ద <ph name="ORGANIZATION"/> యొక్క గుర్తింపు <ph name="ISSUER"/>చే ధ్రువీకరించబడింది.</translation>
 <translation id="220858061631308971">దయచేసి ఈ PIN కోడ్‌ని &quot;<ph name="DEVICE_NAME"/>&quot;లో నమోదు చేయండి:</translation>
 <translation id="6263082573641595914">Microsoft CA సంస్కరణ</translation>
-<translation id="953345106084818179">అనుమతిని అభ్యర్థించు</translation>
+<translation id="953345106084818179">అనుమతి అభ్యర్థించండి</translation>
 <translation id="3105917916468784889">స్క్రీన్‌షాట్‌ని తీయండి</translation>
 <translation id="6000902307058248087">సైట్ నా మైక్రోఫోన్‌కు ప్రాప్యతను కోరినప్పుడు నన్ను అడుగు (సిఫార్సు చేయబడింది)</translation>
 <translation id="1587275751631642843">&amp; JavaScript కన్‌సోల్</translation>
@@ -1592,6 +1595,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">వియత్నామీస్</translation>
 <translation id="6423064450797205562">అభ్యర్థించిన చర్యలను <ph name="SHORT_PRODUCT_NAME"/> అమలు చేయగల వేగానికి సంబంధించిన గణాంకాలు</translation>
+<translation id="2048118585307365263">MediaDrm ప్రారంభించండి.</translation>
 <translation id="4091434297613116013">పేపర్ షీట్‌లు</translation>
 <translation id="7475671414023905704">Netscape తప్పిపోయిన పాస్‌వర్డ్ URL</translation>
 <translation id="3335947283844343239">మూసిన టాబ్‌ను మళ్ళీ తెరువు</translation>
@@ -3838,6 +3842,7 @@
 <translation id="3672159315667503033">మీ స్థానిక కంప్యూటర్‌లో <ph name="URL"/> శాశ్వతంగా డేటాను నిల్వ చేయాలనుకుంటుంది.</translation>
 <translation id="373572798843615002">1 టాబ్</translation>
 <translation id="4806065163318322702">ప్రసంగం ఇన్‌పుట్‌ను టోగుల్ చేయి</translation>
+<translation id="6190185222845843088">Wallet శాండ్‌బాక్స్ సర్వర్‌లను ఉపయోగించండి</translation>
 <translation id="3177048931975664371">పాస్‌వర్డ్ దాచుటకు క్లిక్ చేయండి</translation>
 <translation id="5852137567692933493">పునఃప్రారంభించి, పవర్‌వాష్ చేయి</translation>
 <translation id="3092544800441494315">ఈ స్క్రీన్‌షాట్‌ని చేర్చు:</translation>
@@ -4104,6 +4109,7 @@
 <translation id="1639239467298939599">లోడ్ అవుతోంది</translation>
 <translation id="5457599981699367932">అతిథి వలె బ్రౌజ్ చెయ్యండి</translation>
 <translation id="6850233365366645553">మీ పరికరం పవర్‌వాష్‌తో రీసెట్ చేయబడటానికి ముందు పునఃప్రారంభించడం అవసరం. పవర్‌వాష్ మీ <ph name="IDS_SHORT_PRODUCT_NAME"/> పరికరాన్ని క్రొత్తదాని వలె రీసెట్ చేస్తుంది.</translation>
+<translation id="4292622557427736684">గుప్తీకరించిన మీడియా పొడిగింపుల కోసం డిఫాల్ట్‌గా MediaDrmను ప్రారంభించండి.</translation>
 <translation id="1812514023095547458">రంగుని ఎంచుకోండి</translation>
 <translation id="5089363139417863686">ఫైల్‌లు అనువర్తనంతో వీక్షించండి</translation>
 <translation id="7047998246166230966">పాయింటర్</translation>
@@ -4455,6 +4461,7 @@
 <translation id="1728442818359004787">డిఫాల్ట్ అనువర్తనాన్ని మార్చండి...</translation>
 <translation id="7540972813190816353">నవీకరణల కోసం తనిఖీ చేస్తున్నప్పుడు లోపం సంభవించింది: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">మద్దతు లేని బ్లూటూత్ పరికరం: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">పూర్వప్రత్యయం లేని మీడియా సోర్స్ APIని నిలిపివేయండి.</translation>
 <translation id="2225024820658613551">&lt;strong&gt;ముఖ్యంగా&lt;/strong&gt; ఈ సైట్ కోసం మీరు ఈ హెచ్చరికను ఇంతకు ముందు ఎప్పుడూ చూడకుంటే మీరు ఖచ్చితంగా కొనసాగకూడదు.</translation>
 <translation id="2049639323467105390">ఈ పరికరం <ph name="DOMAIN"/> ద్వారా నిర్వహించబడుతుంది.</translation>
 <translation id="1932098463447129402">ముందు కాదు</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 115774a..9fe59ea 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -125,6 +125,7 @@
 <translation id="1589055389569595240">แสดงตัวสะกดและไวยากรณ์</translation>
 <translation id="7017587484910029005">พิมพ์อักขระตามที่คุณเห็นในรูปด้านล่าง</translation>
 <translation id="9013589315497579992">ใบรับรองการตรวจสอบสิทธิ์ไคลเอนต์ SSL ใช้ไม่ได้</translation>
+<translation id="2085245445866855859">ต้องติดตั้งแอปที่มีแอตทริบิวต์ไฟล์ Manifest ที่ชื่อ &quot;kiosk_only&quot; ในโหมดคีออสก์ของ ChromeOS</translation>
 <translation id="1467999917853307373"><ph name="URL"/> ต้องการจัดเก็บข้อมูลอย่างถาวรในอุปกรณ์ของคุณ</translation>
 <translation id="8524066305376229396">พื้นที่จัดเก็บข้อมูลถาวร:</translation>
 <translation id="7567293639574541773">&amp;ตรวจสอบองค์ประกอบ</translation>
@@ -176,6 +177,7 @@
 <translation id="4858913220355269194">ฟริทซ์</translation>
 <translation id="2231238007119540260">หากคุณลบใบรับรองเซิร์ฟเวอร์ คุณจะเรียกคืนการตรวจสอบความปลอดภัยตามปกติสำหรับเซิร์ฟเวอร์นั้น และกำหนดให้เซิร์ฟเวอร์ใช้ใบรับรองที่ถูกต้อง</translation>
 <translation id="9110235431257073974">เปิดการรวมระบบ Webstore และ Files.app</translation>
+<translation id="6489433341782457580">สำหรับนักพัฒนาซอฟต์แวร์ ให้ใช้บริการแซนด์บ็อกซ์สำหรับ Wallet API เรียก requestAutocomplete()</translation>
 <translation id="8186609076106987817">เซิร์ฟเวอร์ไม่พบไฟล์</translation>
 <translation id="2846816712032308263">ช่วยให้ปิดแท็บ/หน้าต่างได้อย่างรวดเร็ว - เรียกใช้เครื่องจัดการ onunload js ของแท็บอย่างเป็นอิสระจาก GUI</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> ไม่สามารถโหลดหน้าเว็บเนื่องจาก <ph name="HOST_NAME"/> ใช้เวลาในการตอบสนองนานเกินไป เว็บไซต์อาจล่ม หรือคุณอาจประสบปัญหาในการเชื่อมต่ออินเทอร์เน็ต</translation>
@@ -333,6 +335,7 @@
 <translation id="8959810181433034287">ผู้ใช้ภายใต้การดูแลจะต้องใช้รหัสผ่านนี้ในการลงชื่อเข้าใช้ ดังนั้น เลือกรหัสผ่านที่ปลอดภัยและหารือเกี่ยวกับรหัสผ่านกับผู้ใช้ภายใต้การดูแล</translation>
 <translation id="5154917547274118687">หน่วยความจำ</translation>
 <translation id="1493492096534259649">ภาษานี้ใช้ในการตรวจสอบการสะกดไม่ได้</translation>
+<translation id="2103866351350079276">ปิดใช้วัตถุ MediaSource ที่ไม่มีคำนำหน้า ซึ่งวัตถุนี้ช่วยให้ JavaScript ส่งข้อมูลสื่อไปยังองค์ประกอบวิดีโอโดยตรง</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> ค้นหา</translation>
 <translation id="6460423884798879930">เปิดใช้งานตัวเลือกเพื่อส่งข้อมูลการตรวจสอบสิทธิ์เพิ่มเติมในแพ็คเก็ต SYN แรกสำหรับไคลเอ็นต์ที่เชื่อมต่อก่อนหน้า ทำให้การส่งข้อมูลแบบรวดเร็วเริ่มขึ้น</translation>
 <translation id="6563261555270336410">รายละเอียดเกี่ยวกับ <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1562,6 +1565,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">เวียดนาม</translation>
 <translation id="6423064450797205562">เมตริกที่เกี่ยวข้องกับความเร็วซึ่ง <ph name="SHORT_PRODUCT_NAME"/> ใช้เพื่อทำตามการทำงานที่ได้รับคำขอ</translation>
+<translation id="2048118585307365263">เปิดใช้ MediaDrm</translation>
 <translation id="4091434297613116013">หน้ากระดาษ</translation>
 <translation id="7475671414023905704">URL รหัสผ่านสูญหายของ Netscape</translation>
 <translation id="3335947283844343239">เปิดแท็บที่ปิดไปแล้วขึ้นใหม่</translation>
@@ -3784,6 +3788,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> ต้องการที่จะจัดเก็บข้อมูลขนาดใหญ่อย่างถาวรในเครื่องคอมพิวเตอร์ของคุณ</translation>
 <translation id="373572798843615002">1 แท็บ</translation>
 <translation id="4806065163318322702">สลับการป้อนคำพูด</translation>
+<translation id="6190185222845843088">ใช้เซิร์ฟเวอร์แซนด์บ็อกซ์ Wallet</translation>
 <translation id="3177048931975664371">คลิกเพื่อซ่อนรหัสผ่าน</translation>
 <translation id="5852137567692933493">รีสตาร์ทและ Powerwash</translation>
 <translation id="3092544800441494315">รวมภาพหน้าจอนี้:</translation>
@@ -4050,6 +4055,7 @@
 <translation id="1639239467298939599">กำลังโหลด</translation>
 <translation id="5457599981699367932">ท่องเว็บในฐานะผู้มาเยือน</translation>
 <translation id="6850233365366645553">จำเป็นต้องรีสตาร์ทอุปกรณ์ก่อนที่จะสามารถรีเซ็ตอุปกรณ์ด้วย Powerwash และ Powerwash จะรีเซ็ตอุปกรณ์ <ph name="IDS_SHORT_PRODUCT_NAME"/> ของคุณให้มีสภาพเหมือนใหม่</translation>
+<translation id="4292622557427736684">เปิดใช้ MediaDrm เป็นค่าเริ่มต้นสำหรับส่วนขยายสื่อที่เข้ารหัส</translation>
 <translation id="1812514023095547458">เลือกสี</translation>
 <translation id="5089363139417863686">ดูด้วยแอปไฟล์</translation>
 <translation id="7047998246166230966">ตัวชี้</translation>
@@ -4399,6 +4405,7 @@
 <translation id="1728442818359004787">เปลี่ยนแอปเริ่มต้น...</translation>
 <translation id="7540972813190816353">เกิดข้อผิดพลาดในขณะทำการตรวจสอบการอัปเดต: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">อุปกรณ์บลูทูธที่ไม่สนับสนุน: &quot;<ph name="DEVICE_NAME"/>&quot;</translation>
+<translation id="2990212470195050777">ปิดใช้ Media Source API ที่ไม่มีคำนำหน้า</translation>
 <translation id="2225024820658613551">คุณไม่ควรดำเนินการต่อ &lt;strong&gt;โดยเฉพาะอย่างยิ่ง&lt;/strong&gt;หากคุณไม่เคยเห็นคำเตือนนี้มาก่อนสำหรับไซต์นี้</translation>
 <translation id="2049639323467105390">อุปกรณ์นี้ได้รับการจัดการโดย <ph name="DOMAIN"/></translation>
 <translation id="1932098463447129402">หลังจาก</translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index f035a14..c265588 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -135,6 +135,7 @@
 <translation id="1589055389569595240">Yazım ve Dilbilgisi'ni Göster</translation>
 <translation id="7017587484910029005">Aşağıdaki resimde gördüğünüz karakterleri yazın.</translation>
 <translation id="9013589315497579992">Bozuk SSL istemci kimlik doğrulaması sertifikası.</translation>
+<translation id="2085245445866855859">&quot;kiosk_only&quot; manifest özelliğine sahip uygulama ChromeOS kiosk modunda yüklenmelidir.</translation>
 <translation id="1467999917853307373"><ph name="URL"/>, cihazınıza kalıcı olarak veri depolamak istiyor.</translation>
 <translation id="8524066305376229396">Kalıcı depolama:</translation>
 <translation id="7567293639574541773">Öğeyi de&amp;netle</translation>
@@ -188,6 +189,7 @@
 <translation id="4858913220355269194">Futbolcu</translation>
 <translation id="2231238007119540260">Bir sunucu sertifikasını silerseniz, söz konusu sunucuya yönelik olağan güvenlik denetimlerini geri yükler ve sunucunun geçerli bir sertifika kullanmasını gerekli kılarsınız.</translation>
 <translation id="9110235431257073974">Web Mağazası ve Dosyalar uygulaması entegrasyonunu etkinleştirin.</translation>
+<translation id="6489433341782457580">Geliştiriciler için: requestAutocomplete() için Cüzdan API çağrılarına ilişkin korumalı alan hizmetini kullanın.</translation>
 <translation id="8186609076106987817">Sunucu dosyayı bulamadı.</translation>
 <translation id="2846816712032308263">Hızlı sekme/pencere kapatmayı etkinleştirir - bir sekmenin &quot;onunload&quot; js işleyicisini GUI'den bağımsız olarak çalıştırır.</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/>
@@ -361,6 +363,7 @@
 <translation id="8959810181433034287">Denetlenen kullanıcının oturum açmak için bu şifreyi kullanması gerekecektir. Bu nedenle güvenli bir şifre seçin ve bunu, denetlenen kullanıcıya söylemeyi unutmayın.</translation>
 <translation id="5154917547274118687">Bellek</translation>
 <translation id="1493492096534259649">Bu dil yazım denetimi için kullanılamaz</translation>
+<translation id="2103866351350079276">Öneksiz MediaSource nesnesini devre dışı bırakın. Bu nesne, JavaScript'in, medya verilerini doğrudan bir video öğesine göndermesine olanak sağlar.</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> Arama</translation>
 <translation id="6460423884798879930">Veri gönderiminin daha hızlı başlatılması için, daha önce bağlanmış bir istemciye yönelik ilk SYN paketinde ekstra kimlik doğrulama bilgileri gönderme seçeneğini etkinleştirin.</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> ile ilgili ayrıntılar</translation>
@@ -1597,6 +1600,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamca</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> ürününün, istenen işlemleri gerçekleştirme hızı ile ilgili metrikler</translation>
+<translation id="2048118585307365263">MediaDrm'yi etkinleştir.</translation>
 <translation id="4091434297613116013">yaprak</translation>
 <translation id="7475671414023905704">Netscape Kayıp Şifre URL'si</translation>
 <translation id="3335947283844343239">Kapatılan Sekmeyi Tekrar Aç</translation>
@@ -3857,6 +3861,7 @@
 <translation id="3672159315667503033"><ph name="URL"/>, büyük miktarda veriyi yerel bilgisiayarınızda depolamak istiyor.</translation>
 <translation id="373572798843615002">1 Sekme</translation>
 <translation id="4806065163318322702">Sesli girişi aç/kapat</translation>
+<translation id="6190185222845843088">Cüzdan korumalı alan sunucularını kullan.</translation>
 <translation id="3177048931975664371">Şifreyi gizlemek için tıklayın</translation>
 <translation id="5852137567692933493">Tekrar başlat ve Powerwash uygula</translation>
 <translation id="3092544800441494315">Bu ekran görüntüsünü ekle:</translation>
@@ -4125,6 +4130,7 @@
 <translation id="1639239467298939599">Yükleniyor</translation>
 <translation id="5457599981699367932">Misafir olarak Göz At</translation>
 <translation id="6850233365366645553">Cihazınızın Powerwash ile sıfırlanmasından önce yeniden başlatılması gerekir. Powerwash <ph name="IDS_SHORT_PRODUCT_NAME"/> cihazınızı yeni alınmış gibi sıfırlar.</translation>
+<translation id="4292622557427736684">Şifrelenmiş Medya Uzantıları için MediaDrm'yi varsayılan olarak etkinleştirin.</translation>
 <translation id="1812514023095547458">Renk Seç</translation>
 <translation id="5089363139417863686">Dosyalar uygulaması ile görüntüle</translation>
 <translation id="7047998246166230966">İşaretçi</translation>
@@ -4475,6 +4481,7 @@
 <translation id="1728442818359004787">Varsayılan uygulamayı değiştir...</translation>
 <translation id="7540972813190816353">Güncelleme olup olmadığı kontrol edilirken bir hata oluştu: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Desteklenmeyen Bluetooth cihazı: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Öneksiz Media Source API'sını devre dışı bırak.</translation>
 <translation id="2225024820658613551">&lt;strong&gt;Özellikle&lt;/strong&gt; daha önce bu site için bu uyarıyla hiç karşılaşmadıysanız ilerlememelisiniz.</translation>
 <translation id="2049639323467105390">Bu cihaz <ph name="DOMAIN"/> tarafından yönetiliyor.</translation>
 <translation id="1932098463447129402">Şundan Önce Değil:</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index f6fef3c..a55f694 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -133,6 +133,7 @@
 <translation id="1589055389569595240">Показати опцію &quot;Правопис і граматика&quot;</translation>
 <translation id="7017587484910029005">Введіть зображені нижче символи.</translation>
 <translation id="9013589315497579992">Неправильний сертифікат перевірки автентичності клієнта SSL.</translation>
+<translation id="2085245445866855859">У режимі термінала в ОС Chrome потрібно встановити програму з атрибутом маніфесту &quot;kiosk_only&quot;.</translation>
 <translation id="1467999917853307373">Сторінка <ph name="URL"/> хоче постійно зберігати дані на вашому пристрої.</translation>
 <translation id="8524066305376229396">Постійна пам’ять:</translation>
 <translation id="7567293639574541773">П&amp;еревірити елемент</translation>
@@ -186,6 +187,7 @@
 <translation id="4858913220355269194">Футбол</translation>
 <translation id="2231238007119540260">Якщо видалити сертифікат сервера, відновлюються звичайні перевірки безпеки для цього сервера, що вимагає використання дійсного сертифіката.</translation>
 <translation id="9110235431257073974">Увімкнути інтеграцію Веб-магазину та Files.app.</translation>
+<translation id="6489433341782457580">Для розробників: використовуйте службу ізольованого програмного середовища для викликів API Wallet для запиту requestAutocomplete().</translation>
 <translation id="8186609076106987817">Серверу не вдалося знайти файл.</translation>
 <translation id="2846816712032308263">Дозволяє швидко закривати вкладки або вікна – використовує обробник JS під час закриття вкладок незалежно від GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> не вдалося завантажити веб-сторінку, оскільки хост <ph name="HOST_NAME"/> занадто довго не відповідає. Можливо, веб-сайт не працює або виникли проблеми з підключенням до Інтернету.</translation>
@@ -345,6 +347,7 @@
 <translation id="8959810181433034287">Контрольований користувач повинен буде використовувати цей пароль для входу, тому придумайте безпечний пароль і не забудьте повідомити його контрольованому користувачу.</translation>
 <translation id="5154917547274118687">Пам’ять</translation>
 <translation id="1493492096534259649">Цю мову не можна використовувати для перевірки орфографії</translation>
+<translation id="2103866351350079276">Вимкнути об’єкт MediaSource без префіксу. Цей об’єкт дозволяє JavaScript надсилати дані медіа-файлів безпосередньо в елемент &lt;video&gt;.</translation>
 <translation id="6628463337424475685">Пошук <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Вмикає опцію надсилання додаткової інформації про автентифікацію в початковому пакеті SYN для попередньо під’єднаного клієнта, пришвидшуючи час початку надсилання даних.</translation>
 <translation id="6563261555270336410">Докладно про хост <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1573,6 +1576,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">В'єтнамська</translation>
 <translation id="6423064450797205562">Показники, пов’язані зі швидкістю, з якою <ph name="SHORT_PRODUCT_NAME"/> виконує потрібні дії</translation>
+<translation id="2048118585307365263">Увімкнути MediaDrm.</translation>
 <translation id="4091434297613116013">аркуші паперу</translation>
 <translation id="7475671414023905704">URL-адреса втраченого пароля Netscape</translation>
 <translation id="3335947283844343239">Знову відкрити закриту вкладку</translation>
@@ -3786,6 +3790,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> хоче постійно зберігати дані на вашому локальному комп’ютері.</translation>
 <translation id="373572798843615002">1 вкладка</translation>
 <translation id="4806065163318322702">Увімкнення чи вимкнення голосового введення</translation>
+<translation id="6190185222845843088">Використовувати ізольоване програмне середовище Wallet</translation>
 <translation id="3177048931975664371">Натисніть, щоб сховати пароль</translation>
 <translation id="5852137567692933493">Перезапустити й виконати Powerwash</translation>
 <translation id="3092544800441494315">Включити цей знімок екрана:</translation>
@@ -3886,7 +3891,7 @@
 <translation id="9027603907212475920">Налаштувати синхронізацію...</translation>
 <translation id="6873213799448839504">Автоматично заповнювати рядок</translation>
 <translation id="7238585580608191973">Відбиток SHA-256</translation>
-<translation id="2501278716633472235">Повернутися</translation>
+<translation id="2501278716633472235">Назад</translation>
 <translation id="3588662957555259973">* Фото профілю Google</translation>
 <translation id="131461803491198646">Домашня мережа, без роумінгу</translation>
 <translation id="7377249249140280793"><ph name="RELATIVE_DATE"/> - <ph name="FULL_DATE"/></translation>
@@ -4052,6 +4057,7 @@
 <translation id="1639239467298939599">Завантаження</translation>
 <translation id="5457599981699367932">Переглядати в режимі гостя</translation>
 <translation id="6850233365366645553">Перш ніж скинути налаштування за допомогою функції Powerwash, потрібно перезапустити пристрій. Powerwash відновлює заводські налаштування вашого пристрою <ph name="IDS_SHORT_PRODUCT_NAME"/>.</translation>
+<translation id="4292622557427736684">Увімкнути MediaDrm за умовчанням для Encrypted Media Extensions.</translation>
 <translation id="1812514023095547458">Вибрати колір</translation>
 <translation id="5089363139417863686">Переглянути за допомогою програми &quot;Файли&quot;</translation>
 <translation id="7047998246166230966">Курсор</translation>
@@ -4402,6 +4408,7 @@
 <translation id="1728442818359004787">Змінити програму за умовчанням…</translation>
 <translation id="7540972813190816353">Під час перевірки наявності оновлень сталася помилка: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Непідтримуваний пристрій Bluetooth: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Вимкнути API Media Source без префіксу.</translation>
 <translation id="2225024820658613551">Радимо не продовжувати, &lt;strong&gt;особливо&lt;/strong&gt;, якщо ви ніколи раніше не бачили це попередження для цього сайту.</translation>
 <translation id="2049639323467105390">Цим пристроєм керує домен <ph name="DOMAIN"/>.</translation>
 <translation id="1932098463447129402">Не раніше</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index ba91c94..4b36cfa 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -134,6 +134,7 @@
 <translation id="1589055389569595240">Hiển thị Chính tả và Ngữ pháp</translation>
 <translation id="7017587484910029005">Nhập ký tự bạn thấy trong hình bên dưới.</translation>
 <translation id="9013589315497579992">Chứng chỉ xác thực ứng dụng khách SSL không hợp lệ.</translation>
+<translation id="2085245445866855859">Phải cài đặt ứng dụng có thuộc tính tệp kê khai 'kiosk_only' ở chế độ kiosk ChromeOS.</translation>
 <translation id="1467999917853307373"><ph name="URL"/> muốn lưu trữ vĩnh viễn dữ liệu trên thiết bị của bạn.</translation>
 <translation id="8524066305376229396">Bộ nhớ liên tục:</translation>
 <translation id="7567293639574541773">Kiểm tra phầ&amp;n tử</translation>
@@ -187,6 +188,7 @@
 <translation id="4858913220355269194">Nam cầu thủ Fritz</translation>
 <translation id="2231238007119540260">Nếu bạn xóa chứng chỉ máy chủ, nghĩa là bạn đã khôi phục việc kiểm tra bảo mật thường xuyên cho máy chủ đó và yêu cầu sử dụng chứng chỉ hợp lệ.</translation>
 <translation id="9110235431257073974">Bật tính năng tích hợp Cửa hàng trực tuyến và Files.app.</translation>
+<translation id="6489433341782457580">Đối với nhà phát triển: sử dụng dịch vụ hộp cát đối với cuộc gọi API Wallet cho requestAutocomplete().</translation>
 <translation id="8186609076106987817">Máy chủ không thể tìm thấy tệp.</translation>
 <translation id="2846816712032308263">Bật tính năng đóng tab/cửa sổ nhanh - chạy độc lập trình xử lý onunload.js cho tab của GUI.</translation>
 <translation id="9134410174832249455"><ph name="PRODUCT_NAME"/> không thể tải trang web vì <ph name="HOST_NAME"/> mất quá nhiều thời gian để phản hồi. Trang web có thể ngừng hoạt động hoặc bạn có thể gặp sự cố với kết nối Internet của mình.</translation>
@@ -357,6 +359,7 @@
 <translation id="8959810181433034287">Người dùng được giám sát sẽ cần sử dụng mật khẩu này để đăng nhập, vì vậy hãy chọn một mật khẩu an toàn và nhớ thảo luận mật khẩu đó với người dùng được giám sát.</translation>
 <translation id="5154917547274118687">Bộ nhớ</translation>
 <translation id="1493492096534259649">Không thể sử dụng ngôn ngữ này để kiểm tra chính tả</translation>
+<translation id="2103866351350079276">Vô hiệu hóa đối tượng MediaSource chưa được định sẵn. Đối tượng này cho phép Javascript gửi trực tiếp dữ liệu đa phương tiện đến phần tử video.</translation>
 <translation id="6628463337424475685">Tìm kiếm trên <ph name="ENGINE"/></translation>
 <translation id="6460423884798879930">Bật tùy chọn để gửi thêm thông tin xác thực trong gói SYN ban đầu cho một khách hàng đã kết nối trước đó, cho phép khởi động gửi dữ liệu nhanh hơn.</translation>
 <translation id="6563261555270336410">Thông tin chi tiết về <ph name="ELEMENTS_HOST_NAME"/></translation>
@@ -1598,6 +1601,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">Vietnamese</translation>
 <translation id="6423064450797205562">Số liệu liên quan đến tốc độ mà <ph name="SHORT_PRODUCT_NAME"/> thực hiện các tác vụ được yêu cầu</translation>
+<translation id="2048118585307365263">Bật MediaDrm.</translation>
 <translation id="4091434297613116013">trang giấy</translation>
 <translation id="7475671414023905704">URL Mật khẩu đã Mất của Netscape</translation>
 <translation id="3335947283844343239">Mở lại Tab đã Đóng</translation>
@@ -3865,6 +3869,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> muốn lưu trữ vĩnh viễn dữ liệu trên máy tính cục bộ của bạn.</translation>
 <translation id="373572798843615002">1 Tab</translation>
 <translation id="4806065163318322702">Bắt đầu/dừng nhập bằng giọng nói</translation>
+<translation id="6190185222845843088">Sử dụng máy chủ hộp cát Wallet</translation>
 <translation id="3177048931975664371">Nhấp để ẩn mật khẩu</translation>
 <translation id="5852137567692933493">Khởi động lại và Powerwash</translation>
 <translation id="3092544800441494315">Bao gồm ảnh chụp màn hình này:</translation>
@@ -4132,6 +4137,7 @@
 <translation id="1639239467298939599">Đang tải</translation>
 <translation id="5457599981699367932">Duyệt với tư cách Khách</translation>
 <translation id="6850233365366645553">Cần phải khởi động lại trước khi đặt lại thiết bị của bạn với Powerwash. Powerwash đặt lại thiết bị <ph name="IDS_SHORT_PRODUCT_NAME"/> của bạn giống như mới.</translation>
+<translation id="4292622557427736684">Bật MediaDrm theo mặc định cho Tiện ích mở rộng đa phương tiện đã mã hóa.</translation>
 <translation id="1812514023095547458">Chọn màu</translation>
 <translation id="5089363139417863686">Xem bằng ứng dụng Tệp</translation>
 <translation id="7047998246166230966">Con trỏ</translation>
@@ -4483,6 +4489,7 @@
 <translation id="1728442818359004787">Thay đổi ứng dụng mặc định...</translation>
 <translation id="7540972813190816353">Đã xảy ra lỗi khi kiểm tra cập nhật: <ph name="ERROR"/></translation>
 <translation id="7664620655576155379">Thiết bị Bluetooth không được hỗ trợ: &quot;<ph name="DEVICE_NAME"/>&quot;.</translation>
+<translation id="2990212470195050777">Vô hiệu hóa API nguồn đa phương tiện chưa được định sẵn.</translation>
 <translation id="2225024820658613551">Bạn không nên tiếp tục, &lt;strong&gt;đặc biệt&lt;/strong&gt; nếu trước đây bạn chưa từng thấy cảnh báo này trên trang web này.</translation>
 <translation id="2049639323467105390">Thiết bị này được <ph name="DOMAIN"/> quản lý.</translation>
 <translation id="1932098463447129402">Không được Trước</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index 915606d..8451a17 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -130,6 +130,7 @@
 <translation id="1589055389569595240">显示拼写和语法</translation>
 <translation id="7017587484910029005">键入下面图片中显示的字符。</translation>
 <translation id="9013589315497579992">SSL 客户端身份验证证书出错。</translation>
+<translation id="2085245445866855859">带有“kiosk_only”清单属性的应用必须安装在 Chrome 操作系统信息亭模式下。</translation>
 <translation id="1467999917853307373"><ph name="URL"/> 想在您的设备上永久存储数据。</translation>
 <translation id="8524066305376229396">持久存储:</translation>
 <translation id="7567293639574541773">审查元素(&amp;N)</translation>
@@ -181,6 +182,7 @@
 <translation id="4858913220355269194">足球</translation>
 <translation id="2231238007119540260">如果您删除了某个服务器的证书,则会恢复对该服务器的常规安全检查,并要求其使用有效证书。</translation>
 <translation id="9110235431257073974">启用网上应用店和“文件”应用之间的集成。</translation>
+<translation id="6489433341782457580">适用于开发者:为调用 requestAutocomplete() 的 Wallet API 使用沙盒服务。</translation>
 <translation id="8186609076106987817">服务器找不到该文件。</translation>
 <translation id="2846816712032308263">启用快速关闭标签页/窗口功能 - 将标签页的 onunload js 处理程序与 GUI 分开运行。</translation>
 <translation id="9134410174832249455">由于 <ph name="HOST_NAME"/> 响应时间过长,导致 <ph name="PRODUCT_NAME"/> 无法加载网页。该网站可能已崩溃,或者您的互联网连接出现了问题。</translation>
@@ -342,6 +344,7 @@
 <translation id="8959810181433034287">受监管用户必须使用此密码才能登录,因此请选择一个安全密码,同时务必将此密码告诉相应的受监管用户。</translation>
 <translation id="5154917547274118687">内存</translation>
 <translation id="1493492096534259649">该语言无法进行拼写检查</translation>
+<translation id="2103866351350079276">停用不带前缀的 MediaSource 对象。此对象允许 JavaScript 直接向视频元素发送媒体数据。</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> 搜索</translation>
 <translation id="6460423884798879930">启用该选项,即可在初始 SYN 包中为之前连接的客户端发送额外的身份验证信息,以便更快地开始发送数据。</translation>
 <translation id="6563261555270336410">有关 <ph name="ELEMENTS_HOST_NAME"/> 的详情</translation>
@@ -1567,6 +1570,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">越南文</translation>
 <translation id="6423064450797205562">与 <ph name="SHORT_PRODUCT_NAME"/>执行所请求操作的速度相关的指标</translation>
+<translation id="2048118585307365263">启用 MediaDrm。</translation>
 <translation id="4091434297613116013">纸张数</translation>
 <translation id="7475671414023905704">Netscape 忘了密码网址</translation>
 <translation id="3335947283844343239">重新打开关闭的标签页</translation>
@@ -1732,7 +1736,7 @@
 <translation id="894360074127026135">Netscape International Step-Up</translation>
 <translation id="8420060421540670057">显示 Google 文档文件</translation>
 <translation id="6075731018162044558">糟糕!系统无法为此设备获得长期的 API 访问令牌。</translation>
-<translation id="1201402288615127009">下一个</translation>
+<translation id="1201402288615127009">下一步</translation>
 <translation id="1335588927966684346">实用工具:</translation>
 <translation id="2710582058364740604">覆盖设备的显示密度,以强制使用高 DPI 模式和资源。</translation>
 <translation id="2220529011494928058">报告问题</translation>
@@ -2465,7 +2469,7 @@
 <translation id="2894654529758326923">信息</translation>
 <translation id="4135450933899346655">您的证书</translation>
 <translation id="3979395879372752341">已添加新扩展程序(<ph name="EXTENSION_NAME"/>)</translation>
-<translation id="2609632851001447353">其他版本</translation>
+<translation id="2609632851001447353">其他变体</translation>
 <translation id="2127166530420714525">无法更改蓝牙适配器的电源状态。</translation>
 <translation id="2824775600643448204">地址和搜索栏</translation>
 <translation id="7716781361494605745">Netscape 证书授权中心政策网址</translation>
@@ -3809,6 +3813,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> 想在您的本地计算机上永久保存大量数据。</translation>
 <translation id="373572798843615002">1 个标签页</translation>
 <translation id="4806065163318322702">切换语音输入</translation>
+<translation id="6190185222845843088">使用电子钱包沙盒服务器</translation>
 <translation id="3177048931975664371">点击以隐藏密码</translation>
 <translation id="5852137567692933493">重新启动,然后执行 Powerwash</translation>
 <translation id="3092544800441494315">包括此屏幕截图:</translation>
@@ -4074,6 +4079,7 @@
 <translation id="1639239467298939599">正在加载</translation>
 <translation id="5457599981699367932">以访客身份浏览</translation>
 <translation id="6850233365366645553">您需要先重新启动您的设备,然后才能通过 Powerwash 功能重置设备。Powerwash 可将您的 <ph name="IDS_SHORT_PRODUCT_NAME"/> 设备重置为初始状态。</translation>
+<translation id="4292622557427736684">默认情况下为已加密的媒体扩展程序启用 MediaDrm。</translation>
 <translation id="1812514023095547458">选择颜色</translation>
 <translation id="5089363139417863686">使用“文件”应用查看</translation>
 <translation id="7047998246166230966">指针</translation>
@@ -4322,7 +4328,7 @@
 <translation id="3508920295779105875">选择其他文件夹...</translation>
 <translation id="2159915644201199628">无法对图片解码:“<ph name="IMAGE_NAME"/>”</translation>
 <translation id="904451693890288097">请输入“<ph name="DEVICE_NAME"/>”的配对密钥:</translation>
-<translation id="2604467856256242911">允许支持由其他用户管理的用户个人资料,并可实施限制。</translation>
+<translation id="2604467856256242911">启用后,即允许添加由其他用户管理的用户个人资料并可对这些用户实施限制。</translation>
 <translation id="2987775926667433828">中文(繁体)</translation>
 <translation id="5210496856287228091">停用启动动画。</translation>
 <translation id="3954582159466790312">取消静音(&amp;M)</translation>
@@ -4423,6 +4429,7 @@
 <translation id="1728442818359004787">更改默认应用…</translation>
 <translation id="7540972813190816353">检查更新时出错:<ph name="ERROR"/></translation>
 <translation id="7664620655576155379">不支持的蓝牙设备:“<ph name="DEVICE_NAME"/>”。</translation>
+<translation id="2990212470195050777">停用不带前缀的 Media Source API。</translation>
 <translation id="2225024820658613551">您不应再继续,&lt;strong&gt;尤其&lt;/strong&gt;是如果您以前从未在此网站看到这一警告信息,则更不应继续操作。</translation>
 <translation id="2049639323467105390">此设备由 <ph name="DOMAIN"/> 管理。</translation>
 <translation id="1932098463447129402">不早于</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 0fb4cdc..93b95e3 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -128,11 +128,12 @@
 <translation id="528468243742722775">結束</translation>
 <translation id="1723824996674794290">新增視窗(&amp;N)</translation>
 <translation id="1313405956111467313">自動 Proxy 設定</translation>
-<translation id="3527276236624876118">已建立名稱為 <ph name="USER_DISPLAY_NAME"/> 的受監管使用者。</translation>
+<translation id="3527276236624876118">已建立名為「<ph name="USER_DISPLAY_NAME"/>」的受監管使用者。</translation>
 <translation id="4367782753568896354">無法安裝:</translation>
 <translation id="1589055389569595240">顯示拼字與文法</translation>
 <translation id="7017587484910029005">輸入下方圖片中的字元。</translation>
 <translation id="9013589315497579992">SSL 用戶端授權憑證錯誤。</translation>
+<translation id="2085245445866855859">含有「kiosk_only」資訊清單屬性的應用程式只能在 ChromeOS Kiosk 模式中安裝。</translation>
 <translation id="1467999917853307373"><ph name="URL"/> 要求在您的裝置上永久儲存資料。</translation>
 <translation id="8524066305376229396">永久儲存空間:</translation>
 <translation id="7567293639574541773">檢查元素(&amp;N)</translation>
@@ -184,6 +185,7 @@
 <translation id="4858913220355269194">飛球</translation>
 <translation id="2231238007119540260">如果您刪除了伺服器憑證,系統便會還原對該伺服器的定期安全性檢查,並要求使用有效的憑證。</translation>
 <translation id="9110235431257073974">將「線上應用程式商店」整合至「檔案」應用程式。</translation>
+<translation id="6489433341782457580">開發人員請注意,透過 Wallet API 呼叫 requestAutocomplete() 時,請使用沙箱服務。</translation>
 <translation id="8186609076106987817">伺服器找不到檔案。</translation>
 <translation id="2846816712032308263">快速關閉分頁/視窗,將分頁的 onunload js 處理常式與 GUI 分別執行。</translation>
 <translation id="9134410174832249455"><ph name="HOST_NAME"/> 的回應時間過長,因此 <ph name="PRODUCT_NAME"/> 無法載入網頁。網站可能無法使用,或是您可能遇到網際網路連線的相關問題。</translation>
@@ -347,6 +349,7 @@
 <translation id="8959810181433034287">受監管的使用者必須使用這組密碼才能登入,因此請選擇安全無虞的密碼;此外,別忘了與受監管的使用者討論這組密碼。</translation>
 <translation id="5154917547274118687">記憶體</translation>
 <translation id="1493492096534259649">不能選擇檢查這個語言的拼字</translation>
+<translation id="2103866351350079276">停用無前置字串的 MediaSource 物件。這個物件允許 JavaScript 直接將媒體資料傳送至影片元素。</translation>
 <translation id="6628463337424475685"><ph name="ENGINE"/> 搜尋</translation>
 <translation id="6460423884798879930">啟用這個選項即可傳送第一個 SYN 封包中上一次用戶端連線的額外驗證資訊,使系統能迅速開始傳送資料。</translation>
 <translation id="6563261555270336410"><ph name="ELEMENTS_HOST_NAME"/> 詳細資訊</translation>
@@ -681,7 +684,7 @@
 <translation id="8628085465172583869">伺服器主機名稱:</translation>
 <translation id="3633586230741134985">應用程式啟動器設定</translation>
 <translation id="1992397118740194946">尚未設定</translation>
-<translation id="6867678160199975333">切換至 <ph name="NEW_PROFILE_NAME"/></translation>
+<translation id="6867678160199975333">切換至<ph name="NEW_PROFILE_NAME"/></translation>
 <translation id="8556732995053816225">大小寫須相符(&amp;C)</translation>
 <translation id="3942420633017001071">診斷</translation>
 <translation id="3718720264653688555">虛擬鍵盤</translation>
@@ -1578,6 +1581,7 @@
 <translation id="6736329909263487977"><ph name="ISSUED_BY"/> [<ph name="ISSUED_TO"/>]</translation>
 <translation id="8899388739470541164">越南文</translation>
 <translation id="6423064450797205562"><ph name="SHORT_PRODUCT_NAME"/> 執行要求動作的速度相關數據</translation>
+<translation id="2048118585307365263">啟用 MediaDrm。</translation>
 <translation id="4091434297613116013">張數</translation>
 <translation id="7475671414023905704">Netscape 遺失密碼網址</translation>
 <translation id="3335947283844343239">重新開啟先前關閉的分頁</translation>
@@ -2932,7 +2936,7 @@
 <translation id="2319236583141234177">檢查 DNS 設定。</translation>
 <translation id="114140604515785785">擴充功能根目錄:</translation>
 <translation id="6664237456442406323">抱歉,您的電腦是由格式錯誤的硬體 ID 所設定。這樣會防止 Chrome 作業系統更新最新的安全性修復,您的電腦也可能<ph name="BEGIN_BOLD"/>容易遭受惡意攻擊<ph name="END_BOLD"/>。</translation>
-<translation id="785160701896930981">已建立名稱為 <ph name="NEW_PROFILE_NAME"/> 的受監管使用者。如要設定受監管的使用者可瀏覽哪些網站,您可以前往 <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/> 修改限制與設定。如果您並未變更預設設定,那麼 <ph name="NEW_PROFILE_NAME"/> 便可以瀏覽網路上的所有網站。
+<translation id="785160701896930981">已建立名稱為「<ph name="NEW_PROFILE_NAME"/>」的受監管使用者。如要設定受監管的使用者可瀏覽哪些網站,您可以前往 <ph name="BEGIN_LINK"/>www.chrome.com/manage<ph name="END_LINK"/> 修改限制與設定。如果您並未變更預設設定,那麼「<ph name="NEW_PROFILE_NAME"/>」將可以瀏覽網路上的所有網站。
 
 如需進一步指示,請前往 <ph name="ACCOUNT_EMAIL"/> 查看電子郵件。</translation>
 <translation id="8493236660459102203">麥克風:</translation>
@@ -3829,6 +3833,7 @@
 <translation id="3672159315667503033"><ph name="URL"/> 要求在您的本機電腦上永久儲存大量資料。</translation>
 <translation id="373572798843615002">1 個分頁</translation>
 <translation id="4806065163318322702">切換語音輸入</translation>
+<translation id="6190185222845843088">使用電子錢包沙箱伺服器</translation>
 <translation id="3177048931975664371">按這裡隱藏密碼</translation>
 <translation id="5852137567692933493">重新啟動並恢復原廠設定</translation>
 <translation id="3092544800441494315">包含這個螢幕擷取畫面:</translation>
@@ -4096,6 +4101,7 @@
 <translation id="1639239467298939599">載入中</translation>
 <translation id="5457599981699367932">以訪客身分瀏覽</translation>
 <translation id="6850233365366645553">您必須先重新啟動,才能透過 Powerwash 重設裝置。Powerwash 會將您的 <ph name="IDS_SHORT_PRODUCT_NAME"/> 裝置重設為出廠狀態。</translation>
+<translation id="4292622557427736684">針對 Encrypted Media Extensions 預設啟用 MediaDrm。</translation>
 <translation id="1812514023095547458">選取顏色</translation>
 <translation id="5089363139417863686">在檔案應用程式中查看。</translation>
 <translation id="7047998246166230966">指標裝置</translation>
@@ -4444,6 +4450,7 @@
 <translation id="1728442818359004787">變更預設應用程式...</translation>
 <translation id="7540972813190816353">檢查更新時發生錯誤:<ph name="ERROR"/></translation>
 <translation id="7664620655576155379">不支援的藍牙裝置:「<ph name="DEVICE_NAME"/>」。</translation>
+<translation id="2990212470195050777">停用無前置字串的 Media Source API。</translation>
 <translation id="2225024820658613551">請不要繼續瀏覽這個網站,&lt;strong&gt;尤其&lt;/strong&gt;如果您從未在這個網站看到過這項警告,就更不應該繼續。</translation>
 <translation id="2049639323467105390">這個裝置由 <ph name="DOMAIN"/> 管理。</translation>
 <translation id="1932098463447129402">此日期之後:</translation>
@@ -4864,7 +4871,7 @@
 <translation id="5075306601479391924">在播放媒體時停用使用者手勢需求。啟用這項設定將允許自動播放功能。</translation>
 <translation id="9112748030372401671">變更您的桌布</translation>
 <translation id="1735181657228649412">這是可用來開發應用程式/擴充功能的應用程式。</translation>
-<translation id="1832546148887467272">切換至 <ph name="NEW_GOOGLE_HOST"/></translation>
+<translation id="1832546148887467272">切換至<ph name="NEW_GOOGLE_HOST"/></translation>
 <translation id="2670965183549957348">新酷音輸入法</translation>
 <translation id="7839804798877833423">擷取這些檔案大約會使用 <ph name="FILE_SIZE"/> 行動數據流量。</translation>
 <translation id="3268451620468152448">開啟的分頁</translation>
diff --git a/chrome/app/resources/google_chrome_strings_bn.xtb b/chrome/app/resources/google_chrome_strings_bn.xtb
index c207253..72b58fb 100644
--- a/chrome/app/resources/google_chrome_strings_bn.xtb
+++ b/chrome/app/resources/google_chrome_strings_bn.xtb
@@ -87,7 +87,7 @@
 <translation id="7459554271817304652">ওয়েবে আপনার ব্যক্তিগতকৃত ব্রাউজার বিষয় সংরক্ষণ করতে এবং যেকোন কম্পিউটারে Google Chrome থেকে প্রবেশ করতে সিঙ্ক সেট আপ করুন৷ </translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="473775607612524610">আপডেট</translation>
-<translation id="1195935957447623558">Google Chrome সঠিকভাবে শাট ডাউন হয় নি৷ আপানার খোলা পৃষ্ঠাগুলি পুনঃখুলতে, পুনরুদ্ধার ক্লিক করুন৷</translation>
+<translation id="1195935957447623558">Google Chrome সঠিকভাবে বন্ধ হয় নি৷ আপানার খোলা পৃষ্ঠাগুলি পুনঃখুলতে, পুনরুদ্ধার ক্লিক করুন৷</translation>
 <translation id="2576431527583832481">Chrome আরো ভাল হয়েছে! একটি নতুন সংস্করণ উপলব্ধ আছে৷</translation>
 <translation id="2580411288591421699">বর্তমানে Google Chrome এর যে সংস্করণটি চলছে সেটি ইনস্টল করতে পারে না৷ দয়া করে Google Chrome বন্ধ করুন এবং আবার চেষ্টা করুন৷</translation>
 <translation id="8460191995881063249">Chrome বিজ্ঞপ্তি কেন্দ্র</translation>
diff --git a/chrome/app/theme/default_100_percent/cros/notification_alert.png b/chrome/app/theme/default_100_percent/common/notification_alert.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/cros/notification_alert.png
rename to chrome/app/theme/default_100_percent/common/notification_alert.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_welcome_learn_more.png b/chrome/app/theme/default_100_percent/common/notification_welcome_learn_more.png
new file mode 100644
index 0000000..752bd0a
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/common/notification_welcome_learn_more.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/translate.png b/chrome/app/theme/default_100_percent/translate.png
new file mode 100644
index 0000000..d9f3a1a
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/translate.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_alert.png b/chrome/app/theme/default_200_percent/common/notification_alert.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/cros/notification_alert.png
rename to chrome/app/theme/default_200_percent/common/notification_alert.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_welcome_learn_more.png b/chrome/app/theme/default_200_percent/common/notification_welcome_learn_more.png
new file mode 100644
index 0000000..84a2d83
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/common/notification_welcome_learn_more.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/translate.png b/chrome/app/theme/default_200_percent/translate.png
new file mode 100644
index 0000000..5f63a63
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/translate.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 524f3cc..840e912 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -508,8 +508,10 @@
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL" file="common/ntp_welcome_thumb.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_NEWTAB_WEBSTORE_THUMBNAIL" file="ntp_webstore_thumb.png" />
+      <if expr="pp_ifdef('use_ash')">
+        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ALERT" file="common/notification_alert.png" />
+      </if>
       <if expr="pp_ifdef('chromeos')">
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ALERT" file="cros/notification_alert.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_PERIPHERAL_BATTERY_LOW" file="cros/notification_peripheral_battery_low.png" />
       </if>
       <if expr="is_win or is_linux">
@@ -519,6 +521,7 @@
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_TRAY_EMPTY" file="common/notification_tray_empty.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" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_BORDER_BOTTOM" file="common/omnibox_border_bottom.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_BORDER_BOTTOM_LEFT" file="common/omnibox_border_bottom_left.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_BORDER_BOTTOM_RIGHT" file="common/omnibox_border_bottom_right.png" />
@@ -1033,6 +1036,7 @@
       <structure type="chrome_scaled_image" name="IDR_TOOLS_BAR_LOW" file="common/browser_tools_bar_low.png" />
       <structure type="chrome_scaled_image" name="IDR_TOOLS_BAR_MEDIUM" file="common/browser_tools_bar_medium.png" />
       <structure type="chrome_scaled_image" name="IDR_TOOLS_BAR_HIGH" file="common/browser_tools_bar_high.png" />
+      <structure type="chrome_scaled_image" name="IDR_TRANSLATE" file="translate.png" />
       <structure type="chrome_scaled_image" name="IDR_UP_ARROW" file="common/up_arrow.png" />
       <if expr="not is_macosx and not is_ios and not pp_ifdef('toolkit_views')">
         <structure type="chrome_scaled_image" name="IDR_UPDATE_BADGE" file="update_badge.png" />
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 8db4f1b..1916b28 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -1,27 +1,26 @@
 include_rules = [
   "+apps",
-  "+breakpad",
+  "+ash",
   "+chrome/app",
   "+chrome/installer",
-  "+chrome/tools/profiles",  # For history unit tests.
   "+chromeos",
   "+components/autofill/content/browser",
   "+components/autofill/core/browser",
   "+components/autofill/core/common",
-  "+components/auto_login_parser",
   "+components/breakpad",
   "+components/browser_context_keyed_service",
   "+components/nacl/common",
   "+components/navigation_interception",
+  "+components/navigation_metrics",
   "+components/policy",
+  "+components/sessions",
   "+components/startup_metric_utils",
   "+components/translate/common",
   "+components/user_prefs",
-  "+components/visitedlink/browser",
   "+components/webdata",
-  "+components/web_contents_delegate_android",
   "+components/web_modal",
   "+content/public/browser",
+  "+content/test/net",
   "+device/bluetooth",
   "+device/media_transfer_protocol",
   "+extensions/browser",
@@ -31,27 +30,28 @@
   "+google_update",
   "+grit",  # For generated headers
   "+installer_util_strings",  # For generated headers
+  "+jni",
   "+media/base",  # For media switches
-  "+media/audio",
+  "+native_client/src/shared/imc",
   "+policy",  # For generated headers and source
   "+ppapi/c",  # For various types.
   "+ppapi/host",
   "+ppapi/proxy",
-  "+ppapi/shared_impl/api_id.h",
   # Defines some types that are marshalled over IPC.
   "+ppapi/shared_impl/ppp_flash_browser_operations_shared.h",
   "+rlz",
-  "+sandbox/linux",
   "+sandbox/win/src",  # The path doesn't say it, but this is the Windows sandbox.
   "+skia/ext",
-  "+skia/include",
   "+sync/api",  # Sync API files.
   "+sync/notifier",  # Sync invalidation API files.
   "+sync/protocol",  # Sync protobuf files.
   "+third_party/cros_system_api",
   "+win8/util",
-  "+win8/viewer",
-  "+xib_localizers", # For generated mac localization helpers
+
+  # chrome only needs switches from cc. All usage of the compositor is from
+  # content. Definitely don't include generic stuff from cc/base here, if this
+  # is needed these files need to move to base/
+  "+cc/base/switches.h",
 
   # Unsafe to use from //chrome, see http://goo.gl/QQG5wo
   "-content/public/test/test_browser_context.h",
@@ -65,34 +65,18 @@
   "+webkit/browser",
   "+webkit/common",
 
-  # webkit/glue files are listed individually since they aren't conceptually
-  # grouped like the other webkit/ files, and can therefore be tackled one at
-  # a time.
-  "+webkit/glue/resource_type.h",
-  # DO NOT ADD ANY MORE ITEMS TO THE ABOVE LIST!
-
   "-chrome/browser/ui/views",
   "+chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h",
   "+chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h",
 
   # Other libraries.
-  "+chrome/third_party/mozilla_security_manager",
   "+libxml",  # For search engine definition parsing.
-  "+third_party/apple_sample_code",  # Apple code ImageAndTextCell.
-  "+third_party/bzip2",
-  "+third_party/expat",
-  "+third_party/iaccessible2",
   "+third_party/icu/source/common/unicode",
   "+third_party/icu/source/i18n/unicode",
-  "+third_party/isimpledom",
   "+third_party/leveldatabase",
-  "+third_party/libevent",  # For the remote V8 debugging server
-  "+third_party/libjingle",
-  "+third_party/libyuv",
   "+third_party/protobuf/src/google/protobuf",
   "+third_party/re2",
   "+third_party/sqlite",
-  "+third_party/undoview",
   "+third_party/zlib",
 
   # No inclusion of WebKit from the browser, other than strictly enum/POD,
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7730526..4e6f9d3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -261,6 +261,20 @@
     switches::kDefaultTileWidth, "1024"}
 };
 
+#if defined(USE_ASH)
+const Experiment::Choice kAshOverviewDelayChoices[] = {
+  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
+  { IDS_FLAGS_OVERVIEW_DELAY_INSTANT,
+    ash::switches::kAshOverviewDelayOnAltTab, "0" },
+  { IDS_FLAGS_OVERVIEW_DELAY_SHORT,
+    ash::switches::kAshOverviewDelayOnAltTab, "100" },
+  { IDS_FLAGS_OVERVIEW_DELAY_LONG,
+    ash::switches::kAshOverviewDelayOnAltTab, "500" },
+  { IDS_FLAGS_OVERVIEW_DELAY_NEVER,
+    ash::switches::kAshOverviewDelayOnAltTab, "10000" },
+};
+#endif
+
 const Experiment::Choice kDefaultTileHeightChoices[] = {
   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_SHORT,
@@ -809,13 +823,6 @@
     kOsAll,
     SINGLE_VALUE_TYPE(switches::kDisablePrefixedEncryptedMedia)
   },
-  {
-    "override-encrypted-media-canplaytype",
-    IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_NAME,
-    IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_DESCRIPTION,
-    kOsMac | kOsWin | kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kOverrideEncryptedMediaCanPlayType)
-  },
 #if defined(OS_ANDROID)
   {
     "disable-infobar-for-protected-media-identifier",
@@ -825,13 +832,6 @@
     SINGLE_VALUE_TYPE(switches::kDisableInfobarForProtectedMediaIdentifier)
   },
   {
-    "enable-mediadrm",
-    IDS_FLAGS_ENABLE_MEDIADRM_NAME,
-    IDS_FLAGS_ENABLE_MEDIADRM_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableMediaDrm)
-  },
-  {
     "mediadrm-enable-non-compositing",
     IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_NAME,
     IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_DESCRIPTION,
@@ -1002,13 +1002,6 @@
     SINGLE_VALUE_TYPE(chromeos::switches::kEnableBackgroundLoader)
   },
   {
-    "no-discard-tabs",
-    IDS_FLAGS_NO_DISCARD_TABS_NAME,
-    IDS_FLAGS_NO_DISCARD_TABS_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kNoDiscardTabs)
-  },
-  {
     "ash-enable-docked-windows",
     IDS_FLAGS_DOCKED_WINDOWS_NAME,
     IDS_FLAGS_DOCKED_WINDOWS_DESCRIPTION,
@@ -1078,6 +1071,13 @@
     SINGLE_VALUE_TYPE(ash::switches::kAshDisableOverviewMode)
   },
   {
+    "overview-delay-on-alt-tab",
+    IDS_FLAGS_OVERVIEW_DELAY_NAME,
+    IDS_FLAGS_OVERVIEW_DELAY_DESCRIPTION,
+    kOsCrOS,
+    MULTI_VALUE_TYPE(kAshOverviewDelayChoices)
+  },
+  {
     "show-touch-hud",
     IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
     IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
@@ -1206,13 +1206,6 @@
     kOsCrOS,
     SINGLE_VALUE_TYPE(ash::switches::kAshDisableDragAndDropAppListToLauncher),
   },
-  { "ash-immersive-fullscreen-2",
-    IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_NAME,
-    IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableImmersiveFullscreen,
-                              ash::switches::kAshDisableImmersiveFullscreen),
-  },
 #if defined(OS_LINUX)
   { "ash-enable-memory-monitor",
       IDS_FLAGS_ENABLE_MEMORY_MONITOR_NAME,
@@ -1270,11 +1263,11 @@
                               autofill::switches::kDisablePasswordGeneration)
   },
   {
-    "enable-people-search",
-    IDS_FLAGS_ENABLE_PEOPLE_SEARCH_NAME,
-    IDS_FLAGS_ENABLE_PEOPLE_SEARCH_DESCRIPTION,
-    kOsMac | kOsWin | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnablePeopleSearch)
+    "enable-password-manager-reauthentication",
+    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME,
+    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION,
+    kOsMac,
+    SINGLE_VALUE_TYPE(switches::kEnablePasswordManagerReauthentication)
   },
   {
     "password-autofill-public-suffix-domain-matching",
@@ -1521,6 +1514,13 @@
     kOsCrOS,
     SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)
   },
+  {
+    "enable-swipe-selection",
+    IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME,
+    IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(keyboard::switches::kEnableSwipeSelection)
+  },
 #endif
   {
     "enable-simple-cache-backend",
@@ -1566,6 +1566,13 @@
     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDeviceDiscoveryNotifications,
                               switches::kDisableDeviceDiscoveryNotifications)
   },
+  {
+    "enable-privet-local-printing",
+    IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_NAME,
+    IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_DESCRIPTION,
+    kOsWin | kOsLinux | kOsCrOS,
+    SINGLE_VALUE_TYPE(switches::kEnablePrivetLocalPrinting)
+  },
 #endif  // ENABLE_MDNS
 #if defined(OS_MACOSX)
   {
@@ -1654,13 +1661,6 @@
     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableStickyKeys,
                               switches::kDisableStickyKeys)
   },
-  {
-    "ash-enable-autoclick",
-    IDS_FLAGS_ENABLE_AUTOCLICK_NAME,
-    IDS_FLAGS_ENABLE_AUTOCLICK_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableAutoclick)
-  },
 #endif
   {
     "enable-web-midi",
@@ -1684,11 +1684,11 @@
     SINGLE_VALUE_TYPE(switches::kEnableInlineSignin)
   },
   {
-    "enable-gaia-profile-info",
-    IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_NAME,
-    IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_DESCRIPTION,
+    "enable-google-profile-info",
+    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME,
+    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION,
     kOsMac | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kGaiaProfileInfo)
+    SINGLE_VALUE_TYPE(switches::kGoogleProfileInfo)
   },
   {
     "disable-app-launcher",
@@ -1750,15 +1750,6 @@
     SINGLE_VALUE_TYPE("")
 #endif
   },
-#if defined(OS_ANDROID)
-  {
-    "enable-cast",
-    IDS_FLAGS_ENABLE_CAST_NAME,
-    IDS_FLAGS_ENABLE_CAST_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableCast)
-  },
-#endif
 #if defined(OS_CHROMEOS)
   {
     "enable-first-run-ui",
@@ -1812,6 +1803,32 @@
     kOsAll,
     SINGLE_VALUE_TYPE(switches::kEnableServiceWorker)
   },
+#if defined(OS_ANDROID)
+  {
+    "disable-click-delay",
+    IDS_FLAGS_DISABLE_CLICK_DELAY_NAME,
+    IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION,
+    kOsAndroid,
+    // Java-only switch: CommandLine.DISABLE_CLICK_DELAY
+    SINGLE_VALUE_TYPE("disable-click-delay")
+  },
+#endif
+#if defined(OS_CHROMEOS)
+  {
+    "enable-ime-mode-indicator",
+    IDS_FLAGS_ENABLE_IME_MODE_INDICATOR,
+    IDS_FLAGS_ENABLE_IME_MODE_INDICATOR_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(chromeos::switches::kEnableIMEModeIndicator)
+  },
+#endif
+  {
+    "enable-translate-new-ux",
+    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME,
+    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION,
+    kOsDesktop,
+    SINGLE_VALUE_TYPE(switches::kEnableTranslateNewUX)
+  },
 };
 
 const Experiment* experiments = kExperiments;
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index 9726a5d..5efdaec 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -221,8 +221,13 @@
   TabStripModel* tab_strip = NULL;
   content::WebContents* contents = NULL;
   int tab_index = -1;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
-                                    NULL, &tab_strip, &contents, &tab_index)) {
+  if (!ExtensionTabUtil::GetTabById(tab_id,
+                                    GetProfile(),
+                                    include_incognito(),
+                                    NULL,
+                                    &tab_strip,
+                                    &contents,
+                                    &tab_index)) {
     error_ = extensions::ErrorUtils::FormatErrorMessage(
         extensions::tabs_constants::kTabNotFoundError,
         base::IntToString(tab_id));
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h
index 61c3930..cf7508d 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -11,7 +11,7 @@
 #include "base/memory/singleton.h"
 #include "base/values.h"
 #include "chrome/browser/accessibility/accessibility_events.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "ui/base/accessibility/accessibility_types.h"
 
 // Observes the profile and routes accessibility notifications as events
@@ -85,7 +85,7 @@
 // listeners are only installed when accessibility support is enabled, to
 // minimize the impact.
 class AccessibilitySetAccessibilityEnabledFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
   virtual ~AccessibilitySetAccessibilityEnabledFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION(
@@ -95,7 +95,7 @@
 
 // API function that enables or disables web content accessibility support.
 class AccessibilitySetNativeAccessibilityEnabledFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
   virtual ~AccessibilitySetNativeAccessibilityEnabledFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION(
@@ -104,7 +104,8 @@
 };
 
 // API function that returns the most recent focused control.
-class AccessibilityGetFocusedControlFunction : public SyncExtensionFunction {
+class AccessibilityGetFocusedControlFunction
+    : public ChromeSyncExtensionFunction {
   virtual ~AccessibilityGetFocusedControlFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION(
@@ -113,7 +114,8 @@
 };
 
 // API function that returns alerts being shown on the give tab.
-class AccessibilityGetAlertsForTabFunction : public SyncExtensionFunction {
+class AccessibilityGetAlertsForTabFunction
+    : public ChromeSyncExtensionFunction {
   virtual ~AccessibilityGetAlertsForTabFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION(
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS
new file mode 100644
index 0000000..20699e0
--- /dev/null
+++ b/chrome/browser/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/web_contents_delegate_android",
+]
diff --git a/chrome/browser/android/OWNERS b/chrome/browser/android/OWNERS
index 427eba0..d854ed3 100644
--- a/chrome/browser/android/OWNERS
+++ b/chrome/browser/android/OWNERS
@@ -1,4 +1,5 @@
 bulach@chromium.org
+newt@chromium.org
 nyquist@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index cdbbbdf..fb2774a 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/android/most_visited_sites.h"
 #include "chrome/browser/android/omnibox/omnibox_prerender.h"
 #include "chrome/browser/android/provider/chrome_browser_provider.h"
+#include "chrome/browser/android/recently_closed_tabs_bridge.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/signin/signin_manager_android.h"
 #include "chrome/browser/android/tab_android.h"
@@ -75,7 +76,7 @@
     autofill::AutofillDialogResult::RegisterAutofillDialogResult },
   { "AutofillPopup",
     autofill::AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid },
-  {"AutoLoginDelegate", AutoLoginInfoBarDelegateAndroid::Register},
+  { "AutoLoginDelegate", AutoLoginInfoBarDelegateAndroid::Register },
   { "BookmarksBridge", BookmarksBridge::RegisterBookmarksBridge },
   { "CertificateViewer", RegisterCertificateViewer },
   { "ChromeBrowserProvider",
@@ -86,37 +87,38 @@
     RegisterChromeWebContentsDelegateAndroid },
   { "ChromiumApplication",
     ChromiumApplication::RegisterBindings },
-  {"ConfirmInfoBarDelegate", RegisterConfirmInfoBarDelegate},
+  { "ConfirmInfoBarDelegate", RegisterConfirmInfoBarDelegate },
   { "ContentViewUtil", RegisterContentViewUtil },
+  { "DataReductionProxySettings", DataReductionProxySettingsAndroid::Register },
   { "DevToolsServer", RegisterDevToolsServer },
   { "InvalidationController", invalidation::RegisterInvalidationController },
   { "FaviconHelper", FaviconHelper::RegisterFaviconHelper },
   { "FieldTrialHelper", RegisterFieldTrialHelper },
   { "ForeignSessionHelper",
     ForeignSessionHelper::RegisterForeignSessionHelper },
-  {"InfoBarContainer", RegisterInfoBarContainer},
+  { "InfoBarContainer", RegisterInfoBarContainer },
   { "ShortcutHelper", ShortcutHelper::RegisterShortcutHelper },
   { "IntentHelper", RegisterIntentHelper },
   { "JavascriptAppModalDialog",
     JavascriptAppModalDialogAndroid::RegisterJavascriptAppModalDialog },
   { "MostVisitedSites", RegisterMostVisitedSites },
-  {"NativeInfoBar", RegisterNativeInfoBar},
+  { "NativeInfoBar", RegisterNativeInfoBar },
   { "NavigationPopup", NavigationPopup::RegisterNavigationPopup },
   { "OmniboxPrerender", RegisterOmniboxPrerender },
   { "PersonalDataManagerAndroid",
     autofill::PersonalDataManagerAndroid::Register },
   { "ProfileAndroid", ProfileAndroid::RegisterProfileAndroid },
   { "ProfileSyncService", ProfileSyncServiceAndroid::Register },
-  { "DataReductionProxySettings", DataReductionProxySettingsAndroid::Register },
+  { "RecentlyClosedBridge", RecentlyClosedTabsBridge::Register },
   { "SigninManager", SigninManagerAndroid::Register },
   { "SqliteCursor", SQLiteCursor::RegisterSqliteCursor },
   { "SSLClientCertificateRequest", RegisterSSLClientCertificateRequestAndroid },
   { "StartupMetricUtils", RegisterStartupMetricUtils },
   { "TabAndroid", TabAndroid::RegisterTabAndroid },
   { "TemplateUrlServiceAndroid", TemplateUrlServiceAndroid::Register },
-  { "TranslateInfoBarDelegate", RegisterTranslateInfoBarDelegate},
+  { "TranslateInfoBarDelegate", RegisterTranslateInfoBarDelegate },
   { "TtsPlatformImpl", TtsPlatformImplAndroid::Register },
-  {"UrlUtilities", RegisterUrlUtilities},
+  { "UrlUtilities", RegisterUrlUtilities },
   { "ValidationMessageBubbleAndroid",
       ValidationMessageBubbleAndroid::Register },
   { "WebsiteSettingsPopupAndroid",
diff --git a/chrome/browser/android/chromium_application.cc b/chrome/browser/android/chromium_application.cc
index c6e64ca..270a3f1 100644
--- a/chrome/browser/android/chromium_application.cc
+++ b/chrome/browser/android/chromium_application.cc
@@ -21,5 +21,17 @@
       base::android::GetApplicationContext());
 }
 
+void ChromiumApplication::ShowSyncSettings() {
+  Java_ChromiumApplication_showSyncSettings(
+      base::android::AttachCurrentThread(),
+      base::android::GetApplicationContext());
+}
+
+void ChromiumApplication::ShowTermsOfServiceDialog() {
+  Java_ChromiumApplication_showTermsOfServiceDialog(
+      base::android::AttachCurrentThread(),
+      base::android::GetApplicationContext());
+}
+
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/chromium_application.h b/chrome/browser/android/chromium_application.h
index 3c43273..36d235d 100644
--- a/chrome/browser/android/chromium_application.h
+++ b/chrome/browser/android/chromium_application.h
@@ -22,6 +22,12 @@
   // Opens a protected content settings page, if available.
   static void OpenProtectedContentSettings();
 
+  // Opens the sync settings page.
+  static void ShowSyncSettings();
+
+  // Shows a dialog with the terms of service.
+  static void ShowTermsOfServiceDialog();
+
  private:
   ChromiumApplication() {}
   ~ChromiumApplication() {}
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index a716d0d..970c6a7 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -14,8 +14,8 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/browser_process.h"
@@ -32,19 +32,20 @@
 #include "content/public/browser/devtools_target.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "grit/devtools_discovery_page_resources.h"
 #include "jni/DevToolsServer_jni.h"
-#include "net/base/escape.h"
 #include "net/socket/unix_domain_socket_posix.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "webkit/common/user_agent/user_agent_util.h"
 
 using content::DevToolsAgentHost;
+using content::RenderViewHost;
 using content::WebContents;
 
 namespace {
@@ -55,123 +56,200 @@
 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
 
 const char kTargetTypePage[] = "page";
+const char kTargetTypeOther[] = "other";
 
-bool FindTab(const std::string& str_id,
-             TabModel** model_result,
-             int* index_result) {
-  int id;
-  if (!base::StringToInt(str_id, &id))
-    return false;
-
-  for (TabModelList::const_iterator iter = TabModelList::begin();
-      iter != TabModelList::end(); ++iter) {
-    TabModel* model = *iter;
-    for (int i = 0; i < model->GetTabCount(); ++i) {
-      TabAndroid* tab = model->GetTabAt(i);
-      if (id == tab->GetAndroidId()) {
-        *model_result = model;
-        *index_result = i;
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-
-class Target : public content::DevToolsTarget {
- public:
-  // Constructor for a tab with a valid WebContents.
-  Target(int id, WebContents* web_contents);
-
-  // Constructor for a tab unloaded from memory.
-  Target(int id, const string16& title, const GURL& url);
-
-  virtual std::string GetId() const OVERRIDE { return id_; }
-  virtual std::string GetType() const OVERRIDE { return kTargetTypePage; }
-  virtual std::string GetTitle() const OVERRIDE { return title_; }
-  virtual std::string GetDescription() const OVERRIDE { return std::string(); }
-  virtual GURL GetUrl() const OVERRIDE { return url_; }
-  virtual GURL GetFaviconUrl() const OVERRIDE { return favicon_url_; }
-  virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
-    return last_activity_time_;
-  }
-  virtual bool IsAttached() const OVERRIDE;
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE;
-  virtual bool Activate() const OVERRIDE;
-  virtual bool Close() const OVERRIDE;
-
- private:
-  std::string id_;
-  std::string title_;
-  GURL url_;
-  GURL favicon_url_;
-  base::TimeTicks last_activity_time_;
-};
-
-Target::Target(int id, WebContents* web_contents) {
-  id_ = base::IntToString(id);
-  title_ = UTF16ToUTF8(net::EscapeForHTML(web_contents->GetTitle()));
-  url_ = web_contents->GetURL();
+static GURL GetFaviconURL(WebContents* web_contents) {
   content::NavigationController& controller = web_contents->GetController();
   content::NavigationEntry* entry = controller.GetActiveEntry();
   if (entry != NULL && entry->GetURL().is_valid())
-    favicon_url_ = entry->GetFavicon().url;
-  last_activity_time_ = web_contents->GetLastSelectedTime();
+    return entry->GetFavicon().url;
+  return GURL();
 }
 
-Target::Target(int id, const string16& title, const GURL& url) {
-  id_ = base::IntToString(id);
-  title_ = UTF16ToUTF8(net::EscapeForHTML(title));
-  url_ = url;
-}
+class TargetBase : public content::DevToolsTarget {
+ public:
+  // content::DevToolsTarget implementation:
+  virtual std::string GetTitle() const OVERRIDE { return title_; }
 
-bool Target::IsAttached() const {
-  TabModel* model;
-  int index;
-  if (!FindTab(id_, &model, &index))
-    return false;
-  WebContents* web_contents = model->GetWebContentsAt(index);
-  if (!web_contents)
-    return false;
-  return DevToolsAgentHost::IsDebuggerAttached(web_contents);
-}
+  virtual std::string GetDescription() const OVERRIDE { return std::string(); }
 
-scoped_refptr<DevToolsAgentHost> Target::GetAgentHost() const {
-  TabModel* model;
-  int index;
-  if (!FindTab(id_, &model, &index))
-    return NULL;
-  WebContents* web_contents = model->GetWebContentsAt(index);
-  if (!web_contents) {
-    // The tab has been pushed out of memory, pull it back.
-    TabAndroid* tab = model->GetTabAt(index);
-    tab->RestoreIfNeeded();
-    web_contents = model->GetWebContentsAt(index);
-    if (!web_contents)
-      return NULL;
+  virtual GURL GetUrl() const OVERRIDE { return url_; }
+
+  virtual GURL GetFaviconUrl() const OVERRIDE { return favicon_url_; }
+
+  virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
+    return last_activity_time_;
   }
-  content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
-  return rvh ? DevToolsAgentHost::GetOrCreateFor(rvh) : NULL;
-}
 
-bool Target::Activate() const {
-  TabModel* model;
-  int index;
-  if (!FindTab(id_, &model, &index))
-    return false;
-  model->SetActiveIndex(index);
-  return true;
-}
+ protected:
+  explicit TargetBase(WebContents* web_contents)
+      : title_(UTF16ToUTF8(web_contents->GetTitle())),
+        url_(web_contents->GetURL()),
+        favicon_url_(GetFaviconURL(web_contents)),
+        last_activity_time_(web_contents->GetLastSelectedTime()) {
+  }
 
-bool Target::Close() const {
-  TabModel* model;
-  int index;
-  if (!FindTab(id_, &model, &index))
+  TargetBase(const string16& title, const GURL& url)
+      : title_(UTF16ToUTF8(title)),
+        url_(url)
+  {}
+
+ private:
+  const std::string title_;
+  const GURL url_;
+  const GURL favicon_url_;
+  const base::TimeTicks last_activity_time_;
+};
+
+class TabTarget : public TargetBase {
+ public:
+  static TabTarget* CreateForWebContents(int tab_id,
+                                         WebContents* web_contents) {
+    return new TabTarget(tab_id, web_contents);
+  }
+
+  static TabTarget* CreateForUnloadedTab(int tab_id,
+                                         const string16& title,
+                                         const GURL& url) {
+    return new TabTarget(tab_id, title, url);
+  }
+
+  // content::DevToolsTarget implementation:
+  virtual std::string GetId() const OVERRIDE {
+    return base::IntToString(tab_id_);
+  }
+
+  virtual std::string GetType() const OVERRIDE { return kTargetTypePage; }
+
+  virtual bool IsAttached() const OVERRIDE {
+    TabModel* model;
+    int index;
+    if (!FindTab(&model, &index))
+      return false;
+    WebContents* web_contents = model->GetWebContentsAt(index);
+    if (!web_contents)
+      return false;
+    return DevToolsAgentHost::IsDebuggerAttached(web_contents);
+  }
+
+  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
+    TabModel* model;
+    int index;
+    if (!FindTab(&model, &index))
+      return NULL;
+    WebContents* web_contents = model->GetWebContentsAt(index);
+    if (!web_contents) {
+      // The tab has been pushed out of memory, pull it back.
+      TabAndroid* tab = model->GetTabAt(index);
+      tab->RestoreIfNeeded();
+      web_contents = model->GetWebContentsAt(index);
+      if (!web_contents)
+        return NULL;
+    }
+    RenderViewHost* rvh = web_contents->GetRenderViewHost();
+    return rvh ? DevToolsAgentHost::GetOrCreateFor(rvh) : NULL;
+  }
+
+  virtual bool Activate() const OVERRIDE {
+    TabModel* model;
+    int index;
+    if (!FindTab(&model, &index))
+      return false;
+    model->SetActiveIndex(index);
+    return true;
+  }
+
+  virtual bool Close() const OVERRIDE {
+    TabModel* model;
+    int index;
+    if (!FindTab(&model, &index))
+      return false;
+    model->CloseTabAt(index);
+    return true;
+  }
+
+ private:
+  TabTarget(int tab_id, WebContents* web_contents)
+      : TargetBase(web_contents),
+        tab_id_(tab_id) {
+  }
+
+  TabTarget(int tab_id, const string16& title, const GURL& url)
+      : TargetBase(title, url),
+        tab_id_(tab_id) {
+  }
+
+  bool FindTab(TabModel** model_result, int* index_result) const {
+    for (TabModelList::const_iterator iter = TabModelList::begin();
+        iter != TabModelList::end(); ++iter) {
+      TabModel* model = *iter;
+      for (int i = 0; i < model->GetTabCount(); ++i) {
+        TabAndroid* tab = model->GetTabAt(i);
+        if (tab->GetAndroidId() == tab_id_) {
+          *model_result = model;
+          *index_result = i;
+          return true;
+        }
+      }
+    }
     return false;
-  model->CloseTabAt(index);
-  return true;
-}
+  }
+
+  const int tab_id_;
+};
+
+class NonTabTarget : public TargetBase {
+ public:
+  explicit NonTabTarget(WebContents* web_contents)
+      : TargetBase(web_contents),
+        agent_host_(DevToolsAgentHost::GetOrCreateFor(
+            web_contents->GetRenderViewHost())) {
+  }
+
+  // content::DevToolsTarget implementation:
+  virtual std::string GetId() const OVERRIDE {
+    return agent_host_->GetId();
+  }
+
+  virtual std::string GetType() const OVERRIDE {
+    if (TabModelList::begin() == TabModelList::end()) {
+      // If there are no tab models we must be running in ChromiumTestShell.
+      // Return the 'page' target type for backwards compatibility.
+      return kTargetTypePage;
+    }
+    return kTargetTypeOther;
+  }
+
+  virtual bool IsAttached() const OVERRIDE {
+    return agent_host_->IsAttached();
+  }
+
+  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
+    return agent_host_;
+  }
+
+  virtual bool Activate() const OVERRIDE {
+    RenderViewHost* rvh = agent_host_->GetRenderViewHost();
+    if (!rvh)
+      return false;
+    WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+    if (!web_contents)
+      return false;
+    web_contents->GetDelegate()->ActivateContents(web_contents);
+    return true;
+  }
+
+  virtual bool Close() const OVERRIDE {
+    RenderViewHost* rvh = agent_host_->GetRenderViewHost();
+    if (!rvh)
+      return false;
+    rvh->ClosePage();
+    return true;
+  }
+
+ private:
+  scoped_refptr<DevToolsAgentHost> agent_host_;
+};
 
 // Delegate implementation for the devtools http handler on android. A new
 // instance of this gets created each time devtools is enabled.
@@ -213,14 +291,14 @@
     return "";
   }
 
-  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget() OVERRIDE {
+  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
+      const GURL& url) OVERRIDE {
     Profile* profile =
         g_browser_process->profile_manager()->GetDefaultProfile();
     TabModel* tab_model = TabModelList::GetTabModelWithProfile(profile);
     if (!tab_model)
       return scoped_ptr<content::DevToolsTarget>();
-    WebContents* web_contents =
-        tab_model->CreateTabForTesting(GURL(content::kAboutBlankURL));
+    WebContents* web_contents = tab_model->CreateTabForTesting(url);
     if (!web_contents)
       return scoped_ptr<content::DevToolsTarget>();
 
@@ -229,27 +307,49 @@
         continue;
       TabAndroid* tab = tab_model->GetTabAt(i);
       return scoped_ptr<content::DevToolsTarget>(
-          new Target(tab->GetAndroidId(), web_contents));
+          TabTarget::CreateForWebContents(tab->GetAndroidId(), web_contents));
     }
 
+    // Newly created tab not found, return no target.
     return scoped_ptr<content::DevToolsTarget>();
   }
 
   virtual void EnumerateTargets(TargetCallback callback) OVERRIDE {
     TargetList targets;
+
+    // Enumerate existing tabs, including the ones with no WebContents.
+    std::set<WebContents*> tab_web_contents;
     for (TabModelList::const_iterator iter = TabModelList::begin();
         iter != TabModelList::end(); ++iter) {
       TabModel* model = *iter;
       for (int i = 0; i < model->GetTabCount(); ++i) {
         TabAndroid* tab = model->GetTabAt(i);
         WebContents* web_contents = model->GetWebContentsAt(i);
-        targets.push_back(
-            web_contents ?
-                new Target(tab->GetAndroidId(), web_contents) :
-                new Target(
-                    tab->GetAndroidId(), tab->GetTitle(), tab->GetURL()));
+        if (web_contents) {
+          tab_web_contents.insert(web_contents);
+          targets.push_back(TabTarget::CreateForWebContents(tab->GetAndroidId(),
+                                                            web_contents));
+        } else {
+          targets.push_back(TabTarget::CreateForUnloadedTab(tab->GetAndroidId(),
+                                                            tab->GetTitle(),
+                                                            tab->GetURL()));
+        }
       }
     }
+
+    // Add targets for WebContents not associated with any tabs.
+    std::vector<RenderViewHost*> rvh_list =
+        DevToolsAgentHost::GetValidRenderViewHosts();
+    for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
+         it != rvh_list.end(); ++it) {
+      WebContents* web_contents = WebContents::FromRenderViewHost(*it);
+      if (!web_contents)
+        continue;
+      if (tab_web_contents.find(web_contents) != tab_web_contents.end())
+        continue;
+      targets.push_back(new NonTabTarget(web_contents));
+    }
+
     callback.Run(targets);
   }
 
diff --git a/chrome/browser/android/foreign_session_helper.cc b/chrome/browser/android/foreign_session_helper.cc
index fa7ff24..7d7f486 100644
--- a/chrome/browser/android/foreign_session_helper.cc
+++ b/chrome/browser/android/foreign_session_helper.cc
@@ -7,8 +7,8 @@
 #include <jni.h>
 
 #include "base/android/jni_string.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/sync/glue/session_model_associator.h"
 #include "chrome/browser/sync/profile_sync_service.h"
@@ -52,6 +52,12 @@
         selected_index >= static_cast<int>(tab.navigations.size()))
       return true;
 
+    const ::sessions::SerializedNavigationEntry& current_navigation =
+        tab.navigations.at(selected_index);
+
+    if (current_navigation.virtual_url().is_empty())
+      return true;
+
     return false;
 }
 
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.cc b/chrome/browser/android/recently_closed_tabs_bridge.cc
new file mode 100644
index 0000000..737cbf0
--- /dev/null
+++ b/chrome/browser/android/recently_closed_tabs_bridge.cc
@@ -0,0 +1,165 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/recently_closed_tabs_bridge.h"
+
+#include "base/android/jni_string.h"
+#include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "chrome/browser/sessions/session_restore.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/RecentlyClosedBridge_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+const int kMaxTabCount = 10;
+
+void AddTabToList(JNIEnv* env,
+                  TabRestoreService::Entry* entry,
+                  jobject jtabs_list) {
+  const TabRestoreService::Tab* tab =
+      static_cast<TabRestoreService::Tab*>(entry);
+  const sessions::SerializedNavigationEntry& current_navigation =
+      tab->navigations.at(tab->current_navigation_index);
+  Java_RecentlyClosedBridge_pushTab(
+      env, jtabs_list, entry->id,
+      ConvertUTF16ToJavaString(env, current_navigation.title()).Release(),
+      ConvertUTF8ToJavaString(env, current_navigation.virtual_url().spec())
+          .Release());
+}
+
+void AddTabsToList(JNIEnv* env,
+                   const TabRestoreService::Entries& entries,
+                   jobject jtabs_list) {
+  int added_count = 0;
+  for (TabRestoreService::Entries::const_iterator it = entries.begin();
+       it != entries.end() && added_count < kMaxTabCount; ++it) {
+    TabRestoreService::Entry* entry = *it;
+    DCHECK_EQ(entry->type, TabRestoreService::TAB);
+    if (entry->type == TabRestoreService::TAB) {
+      AddTabToList(env, entry, jtabs_list);
+      ++added_count;
+    }
+  }
+}
+
+}  // namespace
+
+RecentlyClosedTabsBridge::RecentlyClosedTabsBridge(Profile* profile)
+    : profile_(profile),
+      tab_restore_service_(NULL) {
+}
+
+RecentlyClosedTabsBridge::~RecentlyClosedTabsBridge() {
+  if (tab_restore_service_)
+    tab_restore_service_->RemoveObserver(this);
+}
+
+void RecentlyClosedTabsBridge::Destroy(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+void RecentlyClosedTabsBridge::SetRecentlyClosedCallback(JNIEnv* env,
+                                                         jobject obj,
+                                                         jobject jcallback) {
+  callback_.Reset(env, jcallback);
+}
+
+jboolean RecentlyClosedTabsBridge::GetRecentlyClosedTabs(JNIEnv* env,
+                                                         jobject obj,
+                                                         jobject jtabs_list) {
+  EnsureTabRestoreService();
+  if (!tab_restore_service_)
+    return false;
+
+  AddTabsToList(env, tab_restore_service_->entries(), jtabs_list);
+  return true;
+}
+
+jboolean RecentlyClosedTabsBridge::OpenRecentlyClosedTab(JNIEnv* env,
+                                                         jobject obj,
+                                                         jobject jtab,
+                                                         jint recent_tab_id) {
+  if (!tab_restore_service_)
+    return false;
+
+  // Find and remove the corresponding tab entry from TabRestoreService.
+  // We take ownership of the returned tab.
+  scoped_ptr<TabRestoreService::Tab> tab_entry(
+      tab_restore_service_->RemoveTabEntryById(recent_tab_id));
+  if (!tab_entry)
+    return false;
+
+  TabAndroid* tab_android = TabAndroid::GetNativeTab(env, jtab);
+  if (!tab_android)
+    return false;
+  content::WebContents* web_contents = tab_android->web_contents();
+  if (!web_contents)
+    return false;
+
+  // RestoreForeignSessionTab needs a SessionTab.
+  SessionTab session_tab;
+  session_tab.current_navigation_index = tab_entry->current_navigation_index;
+  session_tab.navigations = tab_entry->navigations;
+
+  SessionRestore::RestoreForeignSessionTab(web_contents,
+                                           session_tab,
+                                           NEW_FOREGROUND_TAB);
+  return true;
+}
+
+void RecentlyClosedTabsBridge::ClearRecentlyClosedTabs(JNIEnv* env,
+                                                       jobject obj) {
+  EnsureTabRestoreService();
+  if (tab_restore_service_)
+    tab_restore_service_->ClearEntries();
+}
+
+void RecentlyClosedTabsBridge::TabRestoreServiceChanged(
+    TabRestoreService* service) {
+  if (callback_.is_null())
+    return;
+  JNIEnv* env = AttachCurrentThread();
+  Java_RecentlyClosedCallback_onUpdated(env, callback_.obj());
+}
+
+void RecentlyClosedTabsBridge::TabRestoreServiceDestroyed(
+    TabRestoreService* service) {
+  tab_restore_service_ = NULL;
+}
+
+void RecentlyClosedTabsBridge::EnsureTabRestoreService() {
+  if (tab_restore_service_)
+    return;
+
+  tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_);
+
+  // TabRestoreServiceFactory::GetForProfile() can return NULL (e.g. in
+  // incognito mode).
+  if (tab_restore_service_) {
+    // This does nothing if the tabs have already been loaded or they
+    // shouldn't be loaded.
+    tab_restore_service_->LoadTabsFromLastSession();
+    tab_restore_service_->AddObserver(this);
+  }
+}
+
+static jint Init(JNIEnv* env, jobject obj, jobject jprofile) {
+  RecentlyClosedTabsBridge* bridge = new RecentlyClosedTabsBridge(
+      ProfileAndroid::FromProfileAndroid(jprofile));
+  return reinterpret_cast<jint>(bridge);
+}
+
+// static
+bool RecentlyClosedTabsBridge::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.h b/chrome/browser/android/recently_closed_tabs_bridge.h
new file mode 100644
index 0000000..7ef64cf
--- /dev/null
+++ b/chrome/browser/android/recently_closed_tabs_bridge.h
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.h"
+
+class Profile;
+class TabRestoreService;
+
+// Provides the list of recently closed tabs to Java.
+class RecentlyClosedTabsBridge : public TabRestoreServiceObserver {
+ public:
+  explicit RecentlyClosedTabsBridge(Profile* profile);
+
+  void Destroy(JNIEnv* env, jobject obj);
+  void SetRecentlyClosedCallback(JNIEnv* env, jobject obj, jobject jcallback);
+  jboolean GetRecentlyClosedTabs(JNIEnv* env, jobject obj, jobject jtabs);
+  jboolean OpenRecentlyClosedTab(JNIEnv* env, jobject obj, jobject jtab,
+                                 jint tab_id);
+  void ClearRecentlyClosedTabs(JNIEnv* env, jobject obj);
+
+  // Observer callback for TabRestoreServiceObserver. Notifies the registered
+  // callback that the recently closed tabs list has changed.
+  virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE;
+
+  // Observer callback when our associated TabRestoreService is destroyed.
+  virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE;
+
+  // Registers JNI methods.
+  static bool Register(JNIEnv* env);
+
+ private:
+  virtual ~RecentlyClosedTabsBridge();
+
+  // Construct and initialize tab_restore_service_ if it's NULL.
+  // tab_restore_service_ may still be NULL, however, in incognito mode.
+  void EnsureTabRestoreService();
+
+  // The callback to be notified when the list of recently closed tabs changes.
+  base::android::ScopedJavaGlobalRef<jobject> callback_;
+
+  // The profile whose recently closed tabs are being monitored.
+  Profile* profile_;
+
+  // TabRestoreService that we are observing.
+  TabRestoreService* tab_restore_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(RecentlyClosedTabsBridge);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index b4b5931..562d2a9 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -25,11 +25,14 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/color_analysis.h"
+#include "ui/gfx/favicon_size.h"
 #include "url/gurl.h"
 
 ShortcutBuilder::ShortcutBuilder(content::WebContents* web_contents,
-                                 const string16& title)
-    : shortcut_type_(BOOKMARK) {
+                                 const string16& title,
+                                 int launcher_large_icon_size)
+    : launcher_large_icon_size_(launcher_large_icon_size),
+      shortcut_type_(BOOKMARK) {
   Observe(web_contents);
   url_ = web_contents->GetURL();
   if (title.length() > 0)
@@ -71,18 +74,17 @@
   // Grab the best, largest icon we can find to represent this bookmark.
   // TODO(dfalcantara): Try combining with the new BookmarksHandler once its
   //                    rewrite is further along.
-  FaviconService::FaviconForURLParams favicon_params(
-      profile,
-      url_,
-      chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON | chrome::FAVICON,
-      0);
-
+  std::vector<int> icon_types;
+  icon_types.push_back(chrome::FAVICON);
+  icon_types.push_back(chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON);
   FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
       profile, Profile::EXPLICIT_ACCESS);
 
-  favicon_service->GetRawFaviconForURL(
-      favicon_params,
-      ui::SCALE_FACTOR_100P,
+  // Using favicon if its size is not smaller than platform required size,
+  // otherwise using the largest icon among all avaliable icons.
+  int threshold_to_get_any_largest_icon = launcher_large_icon_size_ - 1;
+  favicon_service->GetLargestRawFaviconForURL(profile, url_, icon_types,
+      threshold_to_get_any_largest_icon,
       base::Bind(&ShortcutBuilder::FinishAddingShortcut,
                  base::Unretained(this)),
       &cancelable_task_tracker_);
@@ -123,9 +125,10 @@
 }
 
 void ShortcutHelper::AddShortcut(content::WebContents* web_contents,
-                                 const string16& title) {
+                                 const string16& title,
+                                 int launcher_large_icon_size) {
   // The ShortcutBuilder deletes itself when it's done.
-  new ShortcutBuilder(web_contents, title);
+  new ShortcutBuilder(web_contents, title, launcher_large_icon_size);
 }
 
 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
@@ -203,9 +206,11 @@
 static void AddShortcut(JNIEnv* env,
                         jclass clazz,
                         jint tab_android_ptr,
-                        jstring title) {
+                        jstring title,
+                        jint launcher_large_icon_size) {
   TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr);
   ShortcutHelper::AddShortcut(
       tab->web_contents(),
-      base::android::ConvertJavaStringToUTF16(env, title));
+      base::android::ConvertJavaStringToUTF16(env, title),
+      launcher_large_icon_size);
 }
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
index 2fa2735..323b409 100644
--- a/chrome/browser/android/shortcut_helper.h
+++ b/chrome/browser/android/shortcut_helper.h
@@ -43,7 +43,8 @@
   };
 
   explicit ShortcutBuilder(content::WebContents* web_contents,
-                           const string16& title);
+                           const string16& title,
+                           int launcher_large_icon_size);
   virtual ~ShortcutBuilder() {}
 
   void OnDidRetrieveWebappInformation(bool success,
@@ -63,6 +64,7 @@
 
   GURL url_;
   string16 title_;
+  int launcher_large_icon_size_;
   ShortcutType shortcut_type_;
   CancelableTaskTracker cancelable_task_tracker_;
 
@@ -74,7 +76,8 @@
   // Adds a shortcut to the current URL to the Android home screen, firing
   // background tasks to pull all the data required.
   static void AddShortcut(content::WebContents* web_contents,
-                          const string16& title);
+                          const string16& title,
+                          int launcher_larger_icon_size);
 
   // Adds a shortcut to the launcher.  Must be called from a WorkerPool task.
   static void AddShortcutInBackground(
diff --git a/chrome/browser/android/signin/google_auto_login_helper.cc b/chrome/browser/android/signin/google_auto_login_helper.cc
deleted file mode 100644
index ea4f4bd..0000000
--- a/chrome/browser/android/signin/google_auto_login_helper.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/signin/google_auto_login_helper.h"
-
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
-
-GoogleAutoLoginHelper::GoogleAutoLoginHelper(Profile* profile)
-    : profile_(profile) {}
-
-GoogleAutoLoginHelper::~GoogleAutoLoginHelper() {}
-
-void GoogleAutoLoginHelper::LogIn() {
-  uber_token_fetcher_.reset(new UbertokenFetcher(profile_, this));
-  uber_token_fetcher_->StartFetchingToken();
-}
-
-void GoogleAutoLoginHelper::OnUbertokenSuccess(const std::string& uber_token) {
-  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(
-      this, "ChromiumBrowser", profile_->GetRequestContext()));
-  gaia_auth_fetcher_->StartMergeSession(uber_token);
-}
-
-void GoogleAutoLoginHelper::OnUbertokenFailure(
-    const GoogleServiceAuthError& error) {
-  VLOG(1) << "Failed to retrieve ubertoken, error: " << error.ToString();
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-void GoogleAutoLoginHelper::OnMergeSessionSuccess(const std::string& data) {
-  DVLOG(1) << "MergeSession successful." << data;
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-void GoogleAutoLoginHelper::OnMergeSessionFailure(
-    const GoogleServiceAuthError& error) {
-  VLOG(1) << "Failed MergeSession request, error: " << error.ToString();
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
diff --git a/chrome/browser/android/signin/google_auto_login_helper.h b/chrome/browser/android/signin/google_auto_login_helper.h
deleted file mode 100644
index aa94945..0000000
--- a/chrome/browser/android/signin/google_auto_login_helper.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
-#define CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
-
-#include "chrome/browser/signin/ubertoken_fetcher.h"
-#include "google_apis/gaia/gaia_auth_consumer.h"
-
-class GaiaAuthFetcher;
-class Profile;
-
-// Logs in the current signed in user into Google services. Populates the cookie
-// jar with Google credentials of the signed in user.
-class GoogleAutoLoginHelper : public GaiaAuthConsumer,
-                              public UbertokenConsumer {
- public:
-  explicit GoogleAutoLoginHelper(Profile* profile);
-  virtual ~GoogleAutoLoginHelper();
-
-  void LogIn();
-
-  // Overridden from GaiaAuthConsumer.
-  virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE;
-  virtual void OnMergeSessionFailure(const GoogleServiceAuthError& error)
-      OVERRIDE;
-
-  // Overridden from UbertokenConsumer.
-  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
-  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
-
- private:
-  Profile* profile_;
-  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
-  scoped_ptr<UbertokenFetcher> uber_token_fetcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(GoogleAutoLoginHelper);
-};
-
-#endif  // CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index f4a249a..9a6dd5a 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -11,13 +11,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/android/signin/google_auto_login_helper.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/google_auto_login_helper.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 31e3266..2ef531f 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -96,12 +96,6 @@
   // Called when a bookmark node should be edited.
   virtual void EditBookmark(int64 node_id, bool is_folder) = 0;
 
-  // Called to show the sync settings menu.
-  virtual void ShowSyncSettings() = 0;
-
-  // Called to show a dialog with the terms of service.
-  virtual void ShowTermsOfService() = 0;
-
   // Called to determine if chrome://welcome should contain links to the terms
   // of service and the privacy notice.
   virtual bool ShouldWelcomePageLinkToTermsOfService() = 0;
diff --git a/chrome/browser/android/webapps/OWNERS b/chrome/browser/android/webapps/OWNERS
new file mode 100644
index 0000000..79becd2
--- /dev/null
+++ b/chrome/browser/android/webapps/OWNERS
@@ -0,0 +1 @@
+dfalcantara@chromium.org
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index bc10cd2..cf36c0a 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
+#include "base/time/time.h"
 #include "ui/base/work_area_watcher_observer.h"
 
 class AppControllerProfileObserver;
@@ -80,6 +81,10 @@
   // Indicates wheter an NSPopover is currently being shown.
   BOOL hasPopover_;
 
+  // If we are expecting a workspace change in response to a reopen
+  // event, the time we got the event. A null time otherwise.
+  base::TimeTicks reopenTime_;
+
   // Observers that listen to the work area changes.
   ObserverList<ui::WorkAreaWatcherObserver> workAreaChangeObservers_;
 
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 3895ceb..a90577a 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -106,6 +106,11 @@
 NSString* NSPopoverDidCloseNotification = @"NSPopoverDidCloseNotification";
 #endif
 
+// How long we allow a workspace change notification to wait to be
+// associated with a dock activation. The animation lasts 250ms. See
+// applicationShouldHandleReopen:hasVisibleWindows:.
+static const int kWorkspaceChangeTimeoutMs = 500;
+
 // True while AppController is calling chrome::NewEmptyWindow(). We need a
 // global flag here, analogue to StartupBrowserCreator::InProcessStartup()
 // because otherwise the SessionService will try to restore sessions when we
@@ -196,6 +201,7 @@
      withReply:(NSAppleEventDescriptor*)reply;
 - (void)submitCloudPrintJob:(NSAppleEventDescriptor*)event;
 - (void)windowLayeringDidChange:(NSNotification*)inNotification;
+- (void)activeSpaceDidChange:(NSNotification*)inNotification;
 - (void)windowChangedToProfile:(Profile*)profile;
 - (void)checkForAnyKeyWindows;
 - (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount;
@@ -314,6 +320,13 @@
              object:nil];
   }
 
+  // Register for space change notifications.
+  [[[NSWorkspace sharedWorkspace] notificationCenter]
+    addObserver:self
+       selector:@selector(activeSpaceDidChange:)
+           name:NSWorkspaceActiveSpaceDidChangeNotification
+         object:nil];
+
   // Set up the command updater for when there are no windows open
   [self initMenuState];
 
@@ -330,6 +343,7 @@
   [em removeEventHandlerForEventClass:'WWW!'
                            andEventID:'OURL'];
   [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
 }
 
 // (NSApplicationDelegate protocol) This is the Apple-approved place to override
@@ -359,14 +373,14 @@
 
   size_t num_browsers = chrome::GetTotalBrowserCount();
 
-  // Initiate a shutdown (via chrome::CloseAllBrowsers()) if we aren't
+  // Initiate a shutdown (via chrome::CloseAllBrowsersAndQuit()) if we aren't
   // already shutting down.
   if (!browser_shutdown::IsTryingToQuit()) {
     content::NotificationService::current()->Notify(
         chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
         content::NotificationService::AllSources(),
         content::NotificationService::NoDetails());
-    chrome::CloseAllBrowsers();
+    chrome::CloseAllBrowsersAndQuit();
   }
 
   return num_browsers == 0 ? YES : NO;
@@ -556,6 +570,28 @@
   }
 }
 
+- (void)activeSpaceDidChange:(NSNotification*)notify {
+  if (reopenTime_.is_null() ||
+      ![NSApp isActive] ||
+      (base::TimeTicks::Now() - reopenTime_).InMilliseconds() >
+      kWorkspaceChangeTimeoutMs) {
+    return;
+  }
+
+  // The last applicationShouldHandleReopen:hasVisibleWindows: call
+  // happened during a space change. Now that the change has
+  // completed, raise browser windows.
+  reopenTime_ = base::TimeTicks();
+  std::set<NSWindow*> browserWindows;
+  for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
+    Browser* browser = *iter;
+    browserWindows.insert(browser->window()->GetNativeWindow());
+  }
+  if (!browserWindows.empty()) {
+    ui::FocusWindowSet(browserWindows, false);
+  }
+}
+
 // Called on Lion and later when a popover (e.g. dictionary) is shown.
 - (void)popoverDidShow:(NSNotification*)notify {
   hasPopover_ = YES;
@@ -1083,9 +1119,26 @@
       browserWindows.insert(browser->window()->GetNativeWindow());
     }
     if (!browserWindows.empty()) {
-      ui::FocusWindowSet(browserWindows, false);
-      // Return NO; we've done the unminimize, so AppKit shouldn't do
-      // anything.
+      NSWindow* keyWindow = [NSApp keyWindow];
+      if (keyWindow && ![keyWindow isOnActiveSpace]) {
+        // The key window is not on the active space. We must be mid-animation
+        // for a space transition triggered by the dock. Delay the call to
+        // |ui::FocusWindowSet| until the transition completes. Otherwise, the
+        // wrong space's windows get raised, resulting in an off-screen key
+        // window. It does not work to |ui::FocusWindowSet| twice, once here
+        // and once in |activeSpaceDidChange:|, as that appears to break when
+        // the omnibox is focused.
+        //
+        // This check relies on OS X setting the key window to a window on the
+        // target space before calling this method.
+        //
+        // See http://crbug.com/309656.
+        reopenTime_ = base::TimeTicks::Now();
+      } else {
+        ui::FocusWindowSet(browserWindows, false);
+      }
+      // Return NO; we've done (or soon will do) the deminiaturize, so
+      // AppKit shouldn't do anything.
       return NO;
     }
   }
@@ -1100,7 +1153,8 @@
       doneOnce = YES;
       if (base::mac::WasLaunchedAsHiddenLoginItem()) {
         SessionService* sessionService =
-            SessionServiceFactory::GetForProfile([self lastProfile]);
+            SessionServiceFactory::GetForProfileForSessionRestore(
+                [self lastProfile]);
         if (sessionService &&
             sessionService->RestoreIfNecessary(std::vector<GURL>()))
           return NO;
diff --git a/chrome/browser/apps/app_launcher_util.cc b/chrome/browser/apps/app_launcher_util.cc
deleted file mode 100644
index ffe4441..0000000
--- a/chrome/browser/apps/app_launcher_util.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 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/apps/app_launcher_util.h"
-
-#include "base/metrics/field_trial.h"
-#include "base/prefs/pref_registry_simple.h"
-#include "base/prefs/pref_service.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-#if defined(ENABLE_APP_LIST)
-// The field trial group name that enables showing the promo.
-const char kShowLauncherPromoOnceGroupName[] = "ShowPromoUntilDismissed";
-
-// The field trial group name that resets the pref to show the app launcher
-// promo on every session startup.
-const char kResetShowLauncherPromoPrefGroupName[] = "ResetShowPromoPref";
-
-// The name of the field trial that controls showing the app launcher promo.
-const char kLauncherPromoTrialName[] = "ShowAppLauncherPromo";
-#endif  // defined(ENABLE_APP_LIST)
-
-}  // namespace
-
-void SetupShowAppLauncherPromoFieldTrial(PrefService* local_state) {
-#if defined(ENABLE_APP_LIST)
-  if (base::FieldTrialList::FindFullName(kLauncherPromoTrialName) ==
-      kResetShowLauncherPromoPrefGroupName) {
-    local_state->SetBoolean(prefs::kShowAppLauncherPromo, true);
-  }
-#endif
-}
-
-bool IsAppLauncherEnabled() {
-#if !defined(ENABLE_APP_LIST)
-  return false;
-
-#elif defined(OS_CHROMEOS)
-  return true;
-
-#else  // defined(ENABLE_APP_LIST) && !defined(OS_CHROMEOS)
-  if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
-    return true;
-
-  PrefService* prefs = g_browser_process->local_state();
-  // In some tests, the prefs aren't initialised.
-  return prefs && prefs->GetBoolean(prefs::kAppLauncherHasBeenEnabled);
-#endif
-}
-
-bool ShouldShowAppLauncherPromo() {
-#if !defined(ENABLE_APP_LIST)
-  return false;
-#else
-  PrefService* local_state = g_browser_process->local_state();
-  // In some tests, the prefs aren't initialised.
-  if (!local_state)
-    return false;
-  std::string app_launcher_promo_group_name =
-      base::FieldTrialList::FindFullName(kLauncherPromoTrialName);
-  return !IsAppLauncherEnabled() &&
-      local_state->GetBoolean(prefs::kShowAppLauncherPromo) &&
-      (app_launcher_promo_group_name == kShowLauncherPromoOnceGroupName ||
-       app_launcher_promo_group_name == kResetShowLauncherPromoPrefGroupName);
-#endif
-}  // namespace apps
diff --git a/chrome/browser/apps/app_launcher_util.h b/chrome/browser/apps/app_launcher_util.h
deleted file mode 100644
index 17c1b84..0000000
--- a/chrome/browser/apps/app_launcher_util.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2013 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_APPS_APP_LAUNCHER_UTIL_H_
-#define CHROME_BROWSER_APPS_APP_LAUNCHER_UTIL_H_
-
-#include "base/callback_forward.h"
-
-class PrefService;
-
-// Does initializiation for the ShowAppLauncherPromo field trial.
-void SetupShowAppLauncherPromoFieldTrial(PrefService* local_state);
-
-// Returns whether the app launcher has been enabled.
-bool IsAppLauncherEnabled();
-
-// Returns whether the app launcher promo should be shown.
-bool ShouldShowAppLauncherPromo();
-
-#endif  // CHROME_BROWSER_APPS_APP_LAUNCHER_UTIL_H_
diff --git a/chrome/browser/apps/web_view_browsertest.cc b/chrome/browser/apps/web_view_browsertest.cc
index 09f2352..d19f0fa 100644
--- a/chrome/browser/apps/web_view_browsertest.cc
+++ b/chrome/browser/apps/web_view_browsertest.cc
@@ -25,6 +25,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/fake_speech_recognition_manager.h"
+#include "extensions/common/extensions_client.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -1747,10 +1748,10 @@
 // extension which has content script whitelisted/forced.
 IN_PROC_BROWSER_TEST_F(WebViewTest, WhitelistedContentScript) {
   // Whitelist the extension for running content script we are going to load.
-  extensions::Extension::ScriptingWhitelist whitelist;
+  extensions::ExtensionsClient::ScriptingWhitelist whitelist;
   const std::string extension_id = "imeongpbjoodlnmlakaldhlcmijmhpbb";
   whitelist.push_back(extension_id);
-  extensions::Extension::SetScriptingWhitelist(whitelist);
+  extensions::ExtensionsClient::Get()->SetScriptingWhitelist(whitelist);
 
   // Load the extension.
   const extensions::Extension* content_script_whitelisted_extension =
diff --git a/chrome/browser/autocomplete/autocomplete_controller.cc b/chrome/browser/autocomplete/autocomplete_controller.cc
index 915df7e..3e7e3b4 100644
--- a/chrome/browser/autocomplete/autocomplete_controller.cc
+++ b/chrome/browser/autocomplete/autocomplete_controller.cc
@@ -529,7 +529,7 @@
           // name -- don't assume that the normal search keyword description is
           // applicable.
           i->description = template_url->AdjustedShortNameForLocaleDirection();
-          if (!template_url->IsExtensionKeyword()) {
+          if (template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION) {
             i->description = l10n_util::GetStringFUTF16(
                 IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, i->description);
           }
diff --git a/chrome/browser/autocomplete/autocomplete_result.cc b/chrome/browser/autocomplete/autocomplete_result.cc
index 54ced3f..3ae2ca9 100644
--- a/chrome/browser/autocomplete/autocomplete_result.cc
+++ b/chrome/browser/autocomplete/autocomplete_result.cc
@@ -8,6 +8,7 @@
 #include <iterator>
 
 #include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
@@ -181,14 +182,19 @@
   default_match_ = matches_.begin();
 
   if (default_match_ != matches_.end()) {
-    DCHECK(default_match_->allowed_to_be_default_match);
+    const string16 debug_info = ASCIIToUTF16("fill_into_edit=") +
+        default_match_->fill_into_edit + ASCIIToUTF16(", provider=") +
+        ((default_match_->provider != NULL) ?
+         ASCIIToUTF16(default_match_->provider->GetName()) : string16()) +
+        ASCIIToUTF16(", input=") + input.text();
+    DCHECK(default_match_->allowed_to_be_default_match) << debug_info;
     // We shouldn't get query matches for URL inputs, or non-query matches
     // for query inputs.
     if (AutocompleteMatch::IsSearchType(default_match_->type)) {
-      DCHECK_NE(AutocompleteInput::URL, input.type());
+      DCHECK_NE(AutocompleteInput::URL, input.type()) << debug_info;
     } else {
-      DCHECK_NE(AutocompleteInput::QUERY, input.type());
-      DCHECK_NE(AutocompleteInput::FORCED_QUERY, input.type());
+      DCHECK_NE(AutocompleteInput::QUERY, input.type()) << debug_info;
+      DCHECK_NE(AutocompleteInput::FORCED_QUERY, input.type()) << debug_info;
     }
   }
 
diff --git a/chrome/browser/autocomplete/builtin_provider.cc b/chrome/browser/autocomplete/builtin_provider.cc
index ed76f77..33151b1 100644
--- a/chrome/browser/autocomplete/builtin_provider.cc
+++ b/chrome/browser/autocomplete/builtin_provider.cc
@@ -57,8 +57,7 @@
   matches_.clear();
   if ((input.type() == AutocompleteInput::INVALID) ||
       (input.type() == AutocompleteInput::FORCED_QUERY) ||
-      (input.type() == AutocompleteInput::QUERY) ||
-      (input.matches_requested() == AutocompleteInput::BEST_MATCH))
+      (input.type() == AutocompleteInput::QUERY))
     return;
 
   const string16 kAbout = ASCIIToUTF16(chrome::kAboutScheme) +
@@ -88,7 +87,10 @@
   } else {
     // Match input about: or chrome: URL input against builtin chrome URLs.
     GURL url = URLFixerUpper::FixupURL(UTF16ToUTF8(text), std::string());
-    if (url.SchemeIs(chrome::kChromeUIScheme) && url.has_host()) {
+    // BuiltinProvider doesn't know how to suggest valid ?query or #fragment
+    // extensions to chrome: URLs.
+    if (url.SchemeIs(chrome::kChromeUIScheme) && url.has_host() &&
+        !url.has_query() && !url.has_ref()) {
       // Include the path for sub-pages (e.g. "chrome://settings/browser").
       string16 host_and_path = UTF8ToUTF16(url.host() + url.path());
       TrimString(host_and_path, ASCIIToUTF16("/").c_str(), &host_and_path);
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index 05e0017..789a3a5 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -204,7 +204,8 @@
   virtual std::string GetApplicationLocale() const OVERRIDE;
   virtual string16 GetRlzParameterValue() const OVERRIDE;
   virtual std::string GetSearchClient() const OVERRIDE;
-  virtual std::string InstantEnabledParam() const OVERRIDE;
+  virtual std::string ForceInstantResultsParam(
+      bool for_prerender) const OVERRIDE;
   virtual std::string InstantExtendedEnabledParam() const OVERRIDE;
   virtual std::string NTPIsThemedParam() const OVERRIDE;
 
@@ -213,7 +214,7 @@
   std::string application_locale_;
   string16 rlz_parameter_value_;
   std::string search_client_;
-  std::string instant_enabled_param_;
+  std::string force_instant_results_param_;
   std::string instant_extended_enabled_param_;
   std::string ntp_is_themed_param_;
 
@@ -226,7 +227,8 @@
       application_locale_(search_terms_data.GetApplicationLocale()),
       rlz_parameter_value_(search_terms_data.GetRlzParameterValue()),
       search_client_(search_terms_data.GetSearchClient()),
-      instant_enabled_param_(search_terms_data.InstantEnabledParam()),
+      force_instant_results_param_(
+          search_terms_data.ForceInstantResultsParam(false)),
       instant_extended_enabled_param_(
           search_terms_data.InstantExtendedEnabledParam()),
       ntp_is_themed_param_(search_terms_data.NTPIsThemedParam()) {}
@@ -250,8 +252,9 @@
   return search_client_;
 }
 
-std::string SearchTermsDataSnapshot::InstantEnabledParam() const {
-  return instant_enabled_param_;
+std::string SearchTermsDataSnapshot::ForceInstantResultsParam(
+    bool for_prerender) const {
+  return force_instant_results_param_;
 }
 
 std::string SearchTermsDataSnapshot::InstantExtendedEnabledParam() const {
@@ -700,14 +703,11 @@
   // Create the data structure for the autocomplete passes.  We'll save this off
   // onto the |params_| member for later deletion below if we need to run pass
   // 2.
-  std::string languages(languages_);
-  if (languages.empty()) {
-    languages =
-        profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
-  }
   scoped_ptr<HistoryURLProviderParams> params(
-      new HistoryURLProviderParams(input, trim_http, languages,
-                                   default_search_provider, data));
+      new HistoryURLProviderParams(
+          input, trim_http,
+          profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
+          default_search_provider, data));
 
   params->prevent_inline_autocomplete =
       PreventInlineAutocomplete(input);
diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h
index 0ae0030..6a6d2c4 100644
--- a/chrome/browser/autocomplete/history_url_provider.h
+++ b/chrome/browser/autocomplete/history_url_provider.h
@@ -162,19 +162,6 @@
 
   HistoryURLProvider(AutocompleteProviderListener* listener, Profile* profile);
 
-#ifdef UNIT_TEST
-  HistoryURLProvider(AutocompleteProviderListener* listener,
-                     Profile* profile,
-                     const std::string& languages)
-    : HistoryProvider(listener, profile,
-          AutocompleteProvider::TYPE_HISTORY_URL),
-      params_(NULL),
-      cull_redirects_(true),
-      create_shorter_match_(true),
-      search_url_database_(true),
-      languages_(languages) {}
-#endif
-
   // Returns a match corresponding to exactly what the user has typed.
   // |trim_http| should not be set to true if |input| contains an http
   // prefix.
@@ -332,10 +319,6 @@
   // It's used to aid the transition to get all URLs from history to
   // be scored in the HistoryQuick provider only.
   bool search_url_database_;
-
-  // Only used by unittests; if non-empty, overrides accept-languages in the
-  // profile's pref system.
-  std::string languages_;
 };
 
 #endif  // CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index a4b70cb..8ac9122 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/net/url_fixer_upper.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -217,11 +219,11 @@
     profile_->BlockUntilHistoryProcessesPendingRequests();
     profile_->BlockUntilHistoryIndexIsRefreshed();
   }
-  history_service_ =
-      HistoryServiceFactory::GetForProfile(profile_.get(),
-                                           Profile::EXPLICIT_ACCESS);
+  profile_->GetPrefs()->SetString(prefs::kAcceptLanguages, "en-US,en,ko");
+  history_service_ = HistoryServiceFactory::GetForProfile(
+      profile_.get(), Profile::EXPLICIT_ACCESS);
 
-  autocomplete_ = new HistoryURLProvider(this, profile_.get(), "en-US,en,ko");
+  autocomplete_ = new HistoryURLProvider(this, profile_.get());
   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
       profile_.get(), &HistoryURLProviderTest::CreateTemplateURLService);
   FillData();
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index 50020fc..8452c6e 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -198,7 +198,7 @@
     return string16();
 
   // Don't provide a keyword for inactive/disabled extension keywords.
-  if (template_url->IsExtensionKeyword()) {
+  if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) {
     ExtensionService* extension_service =
         extensions::ExtensionSystem::Get(profile_)->extension_service();
     const extensions::Extension* extension = extension_service->
@@ -276,7 +276,8 @@
 
     // Prune any extension keywords that are disallowed in incognito mode (if
     // we're incognito), or disabled.
-    if (profile_ && template_url->IsExtensionKeyword()) {
+    if (profile_ &&
+        (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
       ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->
           extension_service();
       const extensions::Extension* extension =
@@ -310,7 +311,8 @@
   // front of our vector.
   if (matches.front()->keyword() == keyword) {
     const TemplateURL* template_url = matches.front();
-    const bool is_extension_keyword = template_url->IsExtensionKeyword();
+    const bool is_extension_keyword =
+        template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
 
     // Only create an exact match if |remaining_input| is empty or if
     // this is an extension keyword.  If |remaining_input| is a
@@ -478,13 +480,14 @@
   DCHECK(!element->short_name().empty());
   const TemplateURLRef& element_ref = element->url_ref();
   DCHECK(element_ref.IsValid());
-  int message_id = element->IsExtensionKeyword() ?
+  int message_id = (element->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) ?
       IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH;
   if (remaining_input.empty()) {
     // Allow extension keyword providers to accept empty string input. This is
     // useful to allow extensions to do something in the case where no input is
     // entered.
-    if (element_ref.SupportsReplacement() && !element->IsExtensionKeyword()) {
+    if (element_ref.SupportsReplacement() &&
+        (element->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
       // No query input; return a generic, no-destination placeholder.
       match->contents.assign(
           l10n_util::GetStringFUTF16(message_id,
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index e9df2a1..d1e5998 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -97,6 +97,77 @@
   return false;
 }
 
+// Builds the match contents and classification for the contents, and updates
+// the given |AutocompleteMatch|.
+void SetAndClassifyMatchContents(const string16& query_string,
+                                 const string16& input_text,
+                                 const string16& match_contents,
+                                 const string16& annotation,
+                                 AutocompleteMatch* match) {
+  size_t match_contents_start = 0;
+  size_t annotation_start = match_contents.size();
+  // Append annotation if present.
+  if (annotation.empty()) {
+    match->contents = match_contents;
+  } else {
+    std::vector<size_t> positions;
+    match->contents = l10n_util::GetStringFUTF16(
+        IDS_ANNOTATED_SUGGESTION, match_contents, annotation, &positions);
+    match_contents_start = positions[0];
+    annotation_start = positions[1];
+  }
+  size_t match_contents_end = match_contents_start + match_contents.size();
+
+  if (!annotation.empty() && (annotation_start < match_contents_start))
+    match->contents_class.push_back(ACMatchClassification(
+        annotation_start, ACMatchClassification::DIM));
+
+  // We do intra-string highlighting for suggestions - the suggested segment
+  // will be highlighted, e.g. for input_text = "you" the suggestion may be
+  // "youtube", so we'll bold the "tube" section: you*tube*.
+  if (input_text != match_contents) {
+    size_t input_position = match->contents.substr(
+        match_contents_start, match_contents.length()).find(input_text);
+    if (input_position == string16::npos) {
+      // The input text is not a substring of the query string, e.g. input
+      // text is "slasdot" and the query string is "slashdot", so we bold the
+      // whole thing.
+      match->contents_class.push_back(ACMatchClassification(
+          match_contents_start, ACMatchClassification::MATCH));
+    } else {
+      input_position += match_contents_start;
+
+      // TODO(beng): ACMatchClassification::MATCH now seems to just mean
+      //             "bold" this. Consider modifying the terminology.
+      // We don't iterate over the string here annotating all matches because
+      // it looks odd to have every occurrence of a substring that may be as
+      // short as a single character highlighted in a query suggestion result,
+      // e.g. for input text "s" and query string "southwest airlines", it
+      // looks odd if both the first and last s are highlighted.
+      if (input_position != match_contents_start) {
+        match->contents_class.push_back(ACMatchClassification(
+            match_contents_start, ACMatchClassification::MATCH));
+      }
+      match->contents_class.push_back(
+          ACMatchClassification(input_position, ACMatchClassification::NONE));
+      size_t next_fragment_position = input_position + input_text.length();
+      if (next_fragment_position < query_string.length()) {
+        match->contents_class.push_back(ACMatchClassification(
+            next_fragment_position, ACMatchClassification::MATCH));
+      }
+    }
+  } else {
+    // Otherwise, |match| is a verbatim (what-you-typed) match, either for the
+    // default provider or a keyword search provider.
+    match->contents_class.push_back(ACMatchClassification(
+        match_contents_start, ACMatchClassification::NONE));
+  }
+
+  if (!annotation.empty() && (annotation_start >= match_contents_start))
+    match->contents_class.push_back(ACMatchClassification(
+        match_contents_end, ACMatchClassification::DIM));
+}
+
 }  // namespace
 
 
@@ -133,13 +204,20 @@
 
 // SearchProvider::SuggestResult ----------------------------------------------
 
-SearchProvider::SuggestResult::SuggestResult(const string16& suggestion,
-                                             bool from_keyword_provider,
-                                             int relevance,
-                                             bool relevance_from_server,
-                                             bool should_prefetch)
+SearchProvider::SuggestResult::SuggestResult(
+    const string16& suggestion,
+    const string16& match_contents,
+    const string16& annotation,
+    const std::string& suggest_query_params,
+    bool from_keyword_provider,
+    int relevance,
+    bool relevance_from_server,
+    bool should_prefetch)
     : Result(from_keyword_provider, relevance, relevance_from_server),
       suggestion_(suggestion),
+      match_contents_(match_contents),
+      annotation_(annotation),
+      suggest_query_params_(suggest_query_params),
       should_prefetch_(should_prefetch) {
 }
 
@@ -264,13 +342,16 @@
 // static
 AutocompleteMatch SearchProvider::CreateSearchSuggestion(
     AutocompleteProvider* autocomplete_provider,
+    const AutocompleteInput& input,
+    const string16& input_text,
     int relevance,
     AutocompleteMatch::Type type,
+    bool is_keyword,
+    const string16& match_contents,
+    const string16& annotation,
     const TemplateURL* template_url,
     const string16& query_string,
-    const string16& input_text,
-    const AutocompleteInput& input,
-    bool is_keyword,
+    const std::string& suggest_query_params,
     int accepted_suggestion,
     int omnibox_start_margin,
     bool append_extra_query_params) {
@@ -280,46 +361,10 @@
     return match;
   match.keyword = template_url->keyword();
 
-  match.contents.assign(query_string);
-  // We do intra-string highlighting for suggestions - the suggested segment
-  // will be highlighted, e.g. for input_text = "you" the suggestion may be
-  // "youtube", so we'll bold the "tube" section: you*tube*.
-  if (input_text != query_string) {
-    size_t input_position = match.contents.find(input_text);
-    if (input_position == string16::npos) {
-      // The input text is not a substring of the query string, e.g. input
-      // text is "slasdot" and the query string is "slashdot", so we bold the
-      // whole thing.
-      match.contents_class.push_back(
-          ACMatchClassification(0, ACMatchClassification::MATCH));
-    } else {
-      // TODO(beng): ACMatchClassification::MATCH now seems to just mean
-      //             "bold" this. Consider modifying the terminology.
-      // We don't iterate over the string here annotating all matches because
-      // it looks odd to have every occurrence of a substring that may be as
-      // short as a single character highlighted in a query suggestion result,
-      // e.g. for input text "s" and query string "southwest airlines", it
-      // looks odd if both the first and last s are highlighted.
-      if (input_position != 0) {
-        match.contents_class.push_back(
-            ACMatchClassification(0, ACMatchClassification::MATCH));
-      }
-      match.contents_class.push_back(
-          ACMatchClassification(input_position, ACMatchClassification::NONE));
-      size_t next_fragment_position = input_position + input_text.length();
-      if (next_fragment_position < query_string.length()) {
-        match.contents_class.push_back(
-            ACMatchClassification(next_fragment_position,
-                                  ACMatchClassification::MATCH));
-      }
-    }
-  } else {
-    // Otherwise, |match| is a verbatim (what-you-typed) match, either for the
-    // default provider or a keyword search provider.
-    match.contents_class.push_back(
-        ACMatchClassification(0, ACMatchClassification::NONE));
-    match.allowed_to_be_default_match = true;
-  }
+  SetAndClassifyMatchContents(
+      query_string, input_text, match_contents, annotation, &match);
+
+  match.allowed_to_be_default_match = (input_text == match_contents);
 
   // When the user forced a query, we need to make sure all the fill_into_edit
   // values preserve that property.  Otherwise, if the user starts editing a
@@ -342,6 +387,7 @@
   match.search_terms_args->original_query = input_text;
   match.search_terms_args->accepted_suggestion = accepted_suggestion;
   match.search_terms_args->omnibox_start_margin = omnibox_start_margin;
+  match.search_terms_args->suggest_query_params = suggest_query_params;
   match.search_terms_args->append_extra_query_params =
       append_extra_query_params;
   // This is the destination URL sans assisted query stats.  This must be set
@@ -554,24 +600,6 @@
   suggest_results_pending_--;
   LogOmniboxSuggestRequest(REPLY_RECEIVED);
   DCHECK_GE(suggest_results_pending_, 0);  // Should never go negative.
-  const net::HttpResponseHeaders* const response_headers =
-      source->GetResponseHeaders();
-  std::string json_data;
-  source->GetResponseAsString(&json_data);
-  // JSON is supposed to be UTF-8, but some suggest service providers send JSON
-  // files in non-UTF-8 encodings.  The actual encoding is usually specified in
-  // the Content-Type header field.
-  if (response_headers) {
-    std::string charset;
-    if (response_headers->GetCharset(&charset)) {
-      string16 data_16;
-      // TODO(jungshik): Switch to CodePageToUTF8 after it's added.
-      if (base::CodepageToUTF16(json_data, charset.c_str(),
-                                base::OnStringConversionError::FAIL,
-                                &data_16))
-        json_data = UTF16ToUTF8(data_16);
-    }
-  }
 
   const bool is_keyword = (source == keyword_fetcher_.get());
   // Ensure the request succeeded and that the provider used is still available.
@@ -602,10 +630,43 @@
 
   bool results_updated = false;
   if (request_succeeded) {
-    JSONStringValueSerializer deserializer(json_data);
-    deserializer.set_allow_trailing_comma(true);
-    scoped_ptr<Value> data(deserializer.Deserialize(NULL, NULL));
-    results_updated = data.get() && ParseSuggestResults(data.get(), is_keyword);
+    const net::HttpResponseHeaders* const response_headers =
+        source->GetResponseHeaders();
+    std::string json_data;
+    source->GetResponseAsString(&json_data);
+    // JSON is supposed to be UTF-8, but some suggest service providers send
+    // JSON files in non-UTF-8 encodings.  The actual encoding is usually
+    // specified in the Content-Type header field.
+    if (response_headers) {
+      std::string charset;
+      if (response_headers->GetCharset(&charset)) {
+        string16 data_16;
+        // TODO(jungshik): Switch to CodePageToUTF8 after it's added.
+        if (base::CodepageToUTF16(json_data, charset.c_str(),
+                                  base::OnStringConversionError::FAIL,
+                                  &data_16))
+          json_data = UTF16ToUTF8(data_16);
+      }
+    }
+
+    // The JSON response should be an array.
+    for (size_t response_start_index = json_data.find("["), i = 0;
+         response_start_index != std::string::npos && i < 5;
+         response_start_index = json_data.find("[", 1), i++) {
+      // Remove any XSSI guards to allow for JSON parsing.
+      if (response_start_index > 0)
+        json_data.erase(0, response_start_index);
+
+      JSONStringValueSerializer deserializer(json_data);
+      deserializer.set_allow_trailing_comma(true);
+      int error_code = 0;
+      scoped_ptr<Value> data(deserializer.Deserialize(&error_code, NULL));
+      if (error_code == 0) {
+        results_updated = data.get() &&
+            ParseSuggestResults(data.get(), is_keyword);
+        break;
+      }
+    }
   }
 
   UpdateMatches();
@@ -914,6 +975,7 @@
   // 5th element: Optional key-value pairs from the Suggest server.
   ListValue* types = NULL;
   ListValue* relevances = NULL;
+  ListValue* suggestion_details = NULL;
   DictionaryValue* extras = NULL;
   int prefetch_index = -1;
   if (root_list->GetDictionary(4, &extras)) {
@@ -921,7 +983,7 @@
 
     // Discard this list if its size does not match that of the suggestions.
     if (extras->GetList("google:suggestrelevance", &relevances) &&
-        relevances->GetSize() != results_list->GetSize())
+        (relevances->GetSize() != results_list->GetSize()))
       relevances = NULL;
     extras->GetInteger("google:verbatimrelevance",
                        &results->verbatim_relevance);
@@ -933,11 +995,14 @@
     field_trial_triggered_ |= triggered;
     field_trial_triggered_in_session_ |= triggered;
 
-    // Extract the prefetch hint.
     DictionaryValue* client_data = NULL;
     if (extras->GetDictionary("google:clientdata", &client_data) && client_data)
       client_data->GetInteger("phi", &prefetch_index);
 
+    if (extras->GetList("google:suggestdetail", &suggestion_details) &&
+        suggestion_details->GetSize() != results_list->GetSize())
+      suggestion_details = NULL;
+
     // Store the metadata that came with the response in case we need to pass it
     // along with the prefetch query to Instant.
     JSONStringValueSerializer json_serializer(&results->metadata);
@@ -948,13 +1013,13 @@
   results->suggest_results.clear();
   results->navigation_results.clear();
 
-  string16 result, title;
+  string16 suggestion;
   std::string type;
   int relevance = -1;
-  for (size_t index = 0; results_list->GetString(index, &result); ++index) {
+  for (size_t index = 0; results_list->GetString(index, &suggestion); ++index) {
     // Google search may return empty suggestions for weird input characters,
     // they make no sense at all and can cause problems in our code.
-    if (result.empty())
+    if (suggestion.empty())
       continue;
 
     // Apply valid suggested relevance scores; discard invalid lists.
@@ -962,8 +1027,9 @@
       relevances = NULL;
     if (types && types->GetString(index, &type) && (type == "NAVIGATION")) {
       // Do not blindly trust the URL coming from the server to be valid.
-      GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(result), std::string()));
+      GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion), std::string()));
       if (url.is_valid()) {
+        string16 title;
         if (descriptions != NULL)
           descriptions->GetString(index, &title);
         results->navigation_results.push_back(NavigationResult(
@@ -971,9 +1037,24 @@
       }
     } else {
       bool should_prefetch = static_cast<int>(index) == prefetch_index;
-      // TODO(kochi): Improve calculator result presentation.
-      results->suggest_results.push_back(
-          SuggestResult(result, is_keyword, relevance, true, should_prefetch));
+      DictionaryValue* suggestion_detail = NULL;
+      string16 match_contents = suggestion;
+      string16 disambiguating_query;
+      string16 annotation;
+      std::string suggest_query_params;
+      if (suggestion_details && (type == "ENTITY") &&
+          suggestion_details->GetDictionary(index, &suggestion_detail) &&
+          suggestion_detail) {
+        suggestion_detail->GetString("a", &annotation);
+        if (suggestion_detail->GetString("dq", &disambiguating_query) &&
+            !disambiguating_query.empty())
+          suggestion = disambiguating_query;
+        suggestion_detail->GetString("q", &suggest_query_params);
+      }
+      // TODO(kochi): Improve calculator suggestion presentation.
+      results->suggest_results.push_back(SuggestResult(
+          suggestion, match_contents, annotation, suggest_query_params,
+          is_keyword, relevance, true, should_prefetch));
     }
   }
 
@@ -1011,10 +1092,19 @@
       TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
       TemplateURLRef::NO_SUGGESTION_CHOSEN;
   if (verbatim_relevance > 0) {
-    AddMatchToMap(input_.text(), input_.text(), verbatim_relevance,
-                  relevance_from_server, false, std::string(),
+    AddMatchToMap(input_.text(),
+                  verbatim_relevance,
+                  relevance_from_server,
+                  false,
+                  std::string(),
                   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-                  did_not_accept_default_suggestion, false, &map);
+                  false,
+                  input_.text(),
+                  string16(),
+                  input_.text(),
+                  did_not_accept_default_suggestion,
+                  std::string(),
+                  &map);
   }
   if (!keyword_input_.text().empty()) {
     const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
@@ -1024,16 +1114,25 @@
     // Note: in this provider, SEARCH_OTHER_ENGINE must correspond
     // to the keyword verbatim search query.  Do not create other matches
     // of type SEARCH_OTHER_ENGINE.
-    if (keyword_url && !keyword_url->IsExtensionKeyword()) {
+    if (keyword_url &&
+        (keyword_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
       bool keyword_relevance_from_server;
       const int keyword_verbatim_relevance =
           GetKeywordVerbatimRelevance(&keyword_relevance_from_server);
       if (keyword_verbatim_relevance > 0) {
-        AddMatchToMap(keyword_input_.text(), keyword_input_.text(),
-                      keyword_verbatim_relevance, keyword_relevance_from_server,
-                      false, std::string(),
+        AddMatchToMap(keyword_input_.text(),
+                      keyword_verbatim_relevance,
+                      keyword_relevance_from_server,
+                      false,
+                      std::string(),
                       AutocompleteMatchType::SEARCH_OTHER_ENGINE,
-                      did_not_accept_keyword_suggestion, true, &map);
+                      true,
+                      keyword_input_.text(),
+                      string16(),
+                      keyword_input_.text(),
+                      did_not_accept_keyword_suggestion,
+                      std::string(),
+                      &map);
       }
     }
   }
@@ -1269,9 +1368,19 @@
                                          is_keyword);
   for (SuggestResults::const_iterator i(scored_results.begin());
        i != scored_results.end(); ++i) {
-    AddMatchToMap(i->suggestion(), input_text, i->relevance(), false,
-                  false, std::string(), AutocompleteMatchType::SEARCH_HISTORY,
-                  did_not_accept_suggestion, is_keyword, map);
+    AddMatchToMap(input_text,
+                  i->relevance(),
+                  false,
+                  false,
+                  std::string(),
+                  AutocompleteMatchType::SEARCH_HISTORY,
+                  is_keyword,
+                  i->suggestion(),
+                  string16(),
+                  i->suggestion(),
+                  did_not_accept_suggestion,
+                  std::string(),
+                  map);
   }
   UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
                       base::TimeTicks::Now() - start_time);
@@ -1320,7 +1429,8 @@
         i->time, is_keyword, !prevent_inline_autocomplete,
         prevent_search_history_inlining);
     scored_results.push_back(
-        SuggestResult(i->term, is_keyword, relevance, false, false));
+        SuggestResult(i->term, string16(), string16(), std::string(),
+                      is_keyword, relevance, false, false));
   }
 
   // History returns results sorted for us.  However, we may have docked some
@@ -1347,10 +1457,19 @@
   for (size_t i = 0; i < results.size(); ++i) {
     const bool is_keyword = results[i].from_keyword_provider();
     const string16& input = is_keyword ? keyword_input_.text() : input_.text();
-    AddMatchToMap(results[i].suggestion(), input, results[i].relevance(),
+    AddMatchToMap(input,
+                  results[i].relevance(),
                   results[i].relevance_from_server(),
-                  results[i].should_prefetch(), metadata,
-                  AutocompleteMatchType::SEARCH_SUGGEST, i, is_keyword, map);
+                  results[i].should_prefetch(),
+                  metadata,
+                  AutocompleteMatchType::SEARCH_SUGGEST,
+                  is_keyword,
+                  results[i].match_contents(),
+                  results[i].annotation(),
+                  results[i].suggestion(),
+                  i,
+                  results[i].suggest_query_params(),
+                  map);
   }
 }
 
@@ -1462,15 +1581,18 @@
   return std::max(0, base_score - score_discount);
 }
 
-void SearchProvider::AddMatchToMap(const string16& query_string,
-                                   const string16& input_text,
+void SearchProvider::AddMatchToMap(const string16& input_text,
                                    int relevance,
                                    bool relevance_from_server,
                                    bool should_prefetch,
                                    const std::string& metadata,
                                    AutocompleteMatch::Type type,
-                                   int accepted_suggestion,
                                    bool is_keyword,
+                                   const string16& match_contents,
+                                   const string16& annotation,
+                                   const string16& query_string,
+                                   int accepted_suggestion,
+                                   const std::string& suggest_query_params,
                                    MatchMap* map) {
   // On non-mobile, ask the instant controller for the appropriate start margin.
   // On mobile the start margin is unused, so leave the value as default there.
@@ -1489,8 +1611,9 @@
 
   const TemplateURL* template_url = is_keyword ?
       providers_.GetKeywordProviderURL() : providers_.GetDefaultProviderURL();
-  AutocompleteMatch match = CreateSearchSuggestion(this, relevance, type,
-      template_url, query_string, input_text, input_, is_keyword,
+  AutocompleteMatch match = CreateSearchSuggestion(
+      this, input_, input_text, relevance, type, is_keyword, match_contents,
+      annotation, template_url, query_string, suggest_query_params,
       accepted_suggestion, omnibox_start_margin,
       !is_keyword || providers_.default_provider().empty());
   if (!match.destination_url.is_valid())
@@ -1509,8 +1632,11 @@
   // Try to add |match| to |map|.  If a match for |query_string| is already in
   // |map|, replace it if |match| is more relevant.
   // NOTE: Keep this ToLower() call in sync with url_database.cc.
+  MatchKey match_key(
+      std::make_pair(base::i18n::ToLower(query_string),
+                     match.search_terms_args->suggest_query_params));
   const std::pair<MatchMap::iterator, bool> i(
-      map->insert(std::make_pair(base::i18n::ToLower(query_string), match)));
+      map->insert(std::make_pair(match_key, match)));
 
   if (!i.second) {
     // NOTE: We purposefully do a direct relevance comparison here instead of
diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h
index 5993a46..30e601c 100644
--- a/chrome/browser/autocomplete/search_provider.h
+++ b/chrome/browser/autocomplete/search_provider.h
@@ -79,13 +79,16 @@
   // command-line-specified query params.
   static AutocompleteMatch CreateSearchSuggestion(
       AutocompleteProvider* autocomplete_provider,
+      const AutocompleteInput& input,
+      const string16& input_text,
       int relevance,
       AutocompleteMatch::Type type,
+      bool is_keyword,
+      const string16& match_contents,
+      const string16& annotation,
       const TemplateURL* template_url,
       const string16& query_string,
-      const string16& input_text,
-      const AutocompleteInput& input,
-      bool is_keyword,
+      const std::string& suggest_query_params,
       int accepted_suggestion,
       int omnibox_start_margin,
       bool append_extra_query_params);
@@ -221,6 +224,9 @@
   class SuggestResult : public Result {
    public:
     SuggestResult(const string16& suggestion,
+                  const string16& match_contents,
+                  const string16& annotation,
+                  const std::string& suggest_query_params,
                   bool from_keyword_provider,
                   int relevance,
                   bool relevance_from_server,
@@ -228,6 +234,11 @@
     virtual ~SuggestResult();
 
     const string16& suggestion() const { return suggestion_; }
+    const string16& match_contents() const { return match_contents_; }
+    const string16& annotation() const { return annotation_; }
+    const std::string& suggest_query_params() const {
+      return suggest_query_params_;
+    }
     bool should_prefetch() const { return should_prefetch_; }
 
     // Result:
@@ -237,9 +248,20 @@
         bool keyword_provider_requested) const OVERRIDE;
 
    private:
-    // The search suggestion string.
+    // The search terms to be used for this suggestion.
     string16 suggestion_;
 
+    // The contents to be displayed in the autocomplete match.
+    string16 match_contents_;
+
+    // Optional annotation for the |match_contents_| for disambiguation.
+    // This may be displayed in the autocomplete match contents, but is defined
+    // separately to facilitate different formatting.
+    string16 annotation_;
+
+    // Optional additional parameters to be added to the search URL.
+    std::string suggest_query_params_;
+
     // Should this result be prefetched?
     bool should_prefetch_;
   };
@@ -283,7 +305,8 @@
   typedef std::vector<SuggestResult> SuggestResults;
   typedef std::vector<NavigationResult> NavigationResults;
   typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
-  typedef std::map<string16, AutocompleteMatch> MatchMap;
+  typedef std::pair<string16, std::string> MatchKey;
+  typedef std::map<MatchKey, AutocompleteMatch> MatchMap;
 
   // A simple structure bundling most of the information (including
   // both SuggestResults and NavigationResults) returned by a call to
@@ -465,15 +488,18 @@
   // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with
   // the supplied relevance.  Adds this match to |map|; if such a match already
   // exists, whichever one has lower relevance is eliminated.
-  void AddMatchToMap(const string16& query_string,
-                     const string16& input_text,
+  void AddMatchToMap(const string16& input_text,
                      int relevance,
                      bool relevance_from_server,
                      bool should_prefetch,
                      const std::string& metadata,
                      AutocompleteMatch::Type type,
-                     int accepted_suggestion,
                      bool is_keyword,
+                     const string16& match_contents,
+                     const string16& annotation,
+                     const string16& query_string,
+                     int accepted_suggestion,
+                     const std::string& suggest_query_params,
                      MatchMap* map);
 
   // Returns an AutocompleteMatch for a navigational suggestion.
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index 1850b8b..7df13f4 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -4,10 +4,14 @@
 
 #include "chrome/browser/autocomplete/search_provider.h"
 
+#include <string>
+
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -133,6 +137,8 @@
 
   void ResetFieldTrialList();
 
+  void ClearAllResults();
+
   // See description above class for details of these fields.
   TemplateURL* default_t_url_;
   const string16 term1_;
@@ -361,6 +367,10 @@
   trial->group();
 }
 
+void SearchProviderTest::ClearAllResults() {
+  provider_->ClearAllResults();
+}
+
 // Actual Tests ---------------------------------------------------------------
 
 // Make sure we query history for the default provider and a URLFetcher is
@@ -2472,7 +2482,8 @@
                 cases[i].results[j].relevance, false));
       } else {
         provider_->default_results_.suggest_results.push_back(
-            SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), false,
+            SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(),
+                                          string16(), std::string(), false,
                                           cases[i].results[j].relevance,
                                           false, false));
       }
@@ -2514,6 +2525,221 @@
   }
 }
 
+#if !defined(OS_WIN)
+// Verify entity suggestion parsing.
+TEST_F(SearchProviderTest, ParseEntitySuggestion) {
+  struct Match {
+    std::string contents;
+    std::string query_params;
+    std::string fill_into_edit;
+    AutocompleteMatchType::Type type;
+    size_t classification_offsets[3];
+    int classification_styles[3];
+  };
+  const size_t invalid_offset = 10;
+  const int invalid_style = -1;
+  const Match kEmptyMatch = {
+    kNotApplicable, kNotApplicable, kNotApplicable,
+    AutocompleteMatchType::NUM_TYPES,
+    { invalid_offset, invalid_offset, invalid_offset },
+    { invalid_style, invalid_style, invalid_style } };
+
+  struct {
+    const std::string input_text;
+    const std::string response_json;
+    const Match matches[5];
+  } cases[] = {
+    // A query and an entity suggestion with different search terms.
+    { "x",
+      "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
+      " {\"google:suggestdetail\":[{},"
+      "   {\"a\":\"A\",\"dq\":\"yy\",\"q\":\"p=v\"}],"
+      "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
+      { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+          { 0, invalid_offset, invalid_offset },
+          { ACMatchClassification::NONE, invalid_style, invalid_style } },
+        { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
+          { 0, 1, invalid_offset },
+          { ACMatchClassification::NONE, ACMatchClassification::MATCH,
+            invalid_style } },
+        { "xy - A", "p=v", "yy", AutocompleteMatchType::SEARCH_SUGGEST,
+          { 0, 1, 2 },
+          { ACMatchClassification::NONE, ACMatchClassification::MATCH,
+            ACMatchClassification::DIM } },
+        kEmptyMatch,
+        kEmptyMatch
+      },
+    },
+    // A query and an entity suggestion with same search terms.
+    { "x",
+      "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
+      " {\"google:suggestdetail\":[{},"
+      "   {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
+      "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
+      { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+          { 0, invalid_offset, invalid_offset },
+          { ACMatchClassification::NONE, invalid_style, invalid_style } },
+        { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
+          { 0, 1, invalid_offset },
+          { ACMatchClassification::NONE, ACMatchClassification::MATCH,
+            invalid_style } },
+        { "xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
+          { 0, 1, 2 },
+          { ACMatchClassification::NONE, ACMatchClassification::MATCH,
+            ACMatchClassification::DIM } },
+        kEmptyMatch,
+        kEmptyMatch
+      },
+    },
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+    QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
+
+    // Set up a default fetcher with provided results.
+    net::TestURLFetcher* fetcher =
+        test_factory_.GetFetcherByID(
+            SearchProvider::kDefaultProviderURLFetcherID);
+    ASSERT_TRUE(fetcher);
+    fetcher->set_response_code(200);
+    fetcher->SetResponseString(cases[i].response_json);
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+    RunTillProviderDone();
+
+    const ACMatches& matches = provider_->matches();
+    ASSERT_FALSE(matches.empty());
+
+    SCOPED_TRACE("for input with json = " + cases[i].response_json);
+
+    size_t j = 0;
+    // Ensure that the returned matches equal the expectations.
+    for (; j < matches.size(); ++j) {
+      const Match& match = cases[i].matches[j];
+      SCOPED_TRACE(" and match index: " + base::IntToString(j));
+      EXPECT_EQ(match.contents,
+                UTF16ToUTF8(matches[j].contents));
+      EXPECT_EQ(match.query_params,
+                matches[j].search_terms_args->suggest_query_params);
+      EXPECT_EQ(match.fill_into_edit,
+                UTF16ToUTF8(matches[j].fill_into_edit));
+      EXPECT_EQ(match.type, matches[j].type);
+
+      size_t k = 0;
+      for (; k < matches[j].contents_class.size(); k++) {
+        SCOPED_TRACE(" and contents class: " + base::IntToString(k));
+        EXPECT_EQ(match.classification_offsets[k],
+            matches[j].contents_class[k].offset);
+        EXPECT_EQ(match.classification_styles[k],
+            matches[j].contents_class[k].style);
+      }
+      for (; k < ARRAYSIZE_UNSAFE(match.classification_offsets); k++) {
+        SCOPED_TRACE(" and contents class: " + base::IntToString(k));
+        EXPECT_EQ(match.classification_offsets[k], invalid_offset);
+        EXPECT_EQ(match.classification_styles[k], invalid_style);
+      }
+    }
+    // Ensure that no expected matches are missing.
+    for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
+      SCOPED_TRACE(" and match index: " + base::IntToString(j));
+      EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
+    }
+  }
+}
+#endif  // !defined(OS_WIN)
+
+TEST_F(SearchProviderTest, SearchHistorySuppressesEntitySuggestion) {
+  struct Match {
+    std::string contents;
+    std::string query_params;
+    std::string fill_into_edit;
+    AutocompleteMatchType::Type type;
+  };
+  const Match kEmptyMatch = { kNotApplicable, kNotApplicable, kNotApplicable,
+                              AutocompleteMatchType::NUM_TYPES};
+
+  struct {
+    const std::string input_text;
+    const std::string history_search_term;
+    const std::string response_json;
+    const Match matches[5];
+  } cases[] = {
+    // Search history suppresses both query and entity suggestions.
+    { "x", "xy",
+      "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
+      " {\"google:suggestdetail\":[{},"
+      "   {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
+      "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
+      {
+        {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
+        {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+        {"xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
+        kEmptyMatch,
+        kEmptyMatch,
+      },
+    },
+    // Search history suppresses only query suggestion.
+    { "x", "xyy",
+      "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
+      " {\"google:suggestdetail\":[{},"
+      "   {\"a\":\"A\",\"dq\":\"xyy\",\"q\":\"p=v\"}],"
+      "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
+      {
+        {"xyy", "", "xyy", AutocompleteMatchType::SEARCH_HISTORY},
+        {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
+        {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+        {"xy - A", "p=v", "xyy", AutocompleteMatchType::SEARCH_SUGGEST},
+        kEmptyMatch,
+      },
+    }
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+    GURL term_url(AddSearchToHistory(
+        default_t_url_, ASCIIToUTF16(cases[i].history_search_term), 10));
+    profile_.BlockUntilHistoryProcessesPendingRequests();
+    QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
+
+    // Set up a default fetcher with provided results.
+    net::TestURLFetcher* fetcher =
+        test_factory_.GetFetcherByID(
+            SearchProvider::kDefaultProviderURLFetcherID);
+    ASSERT_TRUE(fetcher);
+    fetcher->set_response_code(200);
+    fetcher->SetResponseString(cases[i].response_json);
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+    RunTillProviderDone();
+
+    const ACMatches& matches = provider_->matches();
+    ASSERT_FALSE(matches.empty());
+    SCOPED_TRACE("for case: " + base::IntToString(i));
+
+    size_t j = 0;
+    // Ensure that the returned matches equal the expectations.
+    for (; j < matches.size(); ++j) {
+      SCOPED_TRACE(" and match index: " + base::IntToString(j));
+      EXPECT_EQ(cases[i].matches[j].contents,
+                UTF16ToUTF8(matches[j].contents));
+      EXPECT_EQ(cases[i].matches[j].query_params,
+                matches[j].search_terms_args->suggest_query_params);
+      EXPECT_EQ(cases[i].matches[j].fill_into_edit,
+                UTF16ToUTF8(matches[j].fill_into_edit));
+      EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
+    }
+    // Ensure that no expected matches are missing.
+    for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
+      SCOPED_TRACE(" and match index: " + base::IntToString(j));
+      EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
+    }
+  }
+}
+
 // A basic test that verifies the prefetch metadata parsing logic.
 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
   struct Match {
@@ -2648,6 +2874,93 @@
   }
 }
 
+// A basic test that verifies that the XSSI guarded JSON response is parsed
+// correctly.
+TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) {
+  struct Match {
+    std::string contents;
+    AutocompleteMatchType::Type type;
+  };
+  const Match kEmptyMatch = { kNotApplicable,
+                              AutocompleteMatchType::NUM_TYPES};
+
+  struct {
+    const std::string input_text;
+    const std::string default_provider_response_json;
+    const Match matches[4];
+  } cases[] = {
+    // No XSSI guard.
+    { "a",
+      "[\"a\",[\"b\", \"c\"],[],[],"
+      "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
+      "\"google:suggestrelevance\":[1, 2]}]",
+      { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        { "c", AutocompleteMatchType::SEARCH_SUGGEST },
+        { "b", AutocompleteMatchType::SEARCH_SUGGEST },
+        kEmptyMatch,
+      },
+    },
+    // Standard XSSI guard - )]}'\n.
+    { "a",
+      ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
+      "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
+      "\"google:suggestrelevance\":[1, 2]}]",
+      { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        { "c", AutocompleteMatchType::SEARCH_SUGGEST },
+        { "b", AutocompleteMatchType::SEARCH_SUGGEST },
+        kEmptyMatch,
+      },
+    },
+    // Modified XSSI guard - contains "[".
+    { "a",
+      ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
+      "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
+      "\"google:suggestrelevance\":[1, 2]}]",
+      { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        { "c", AutocompleteMatchType::SEARCH_SUGGEST },
+        { "b", AutocompleteMatchType::SEARCH_SUGGEST },
+        kEmptyMatch,
+      },
+    },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+    ClearAllResults();
+    QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
+
+    // Set up a default fetcher with provided results.
+    net::TestURLFetcher* fetcher =
+        test_factory_.GetFetcherByID(
+            SearchProvider::kDefaultProviderURLFetcherID);
+    ASSERT_TRUE(fetcher);
+    fetcher->set_response_code(200);
+    fetcher->SetResponseString(cases[i].default_provider_response_json);
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+    RunTillProviderDone();
+
+    const ACMatches& matches = provider_->matches();
+    // The top match must inline and score as highly as calculated verbatim.
+    ASSERT_FALSE(matches.empty());
+    EXPECT_GE(matches[0].relevance, 1300);
+
+    SCOPED_TRACE("for case: " + base::IntToString(i));
+    size_t j = 0;
+    // Ensure that the returned matches equal the expectations.
+    for (; j < matches.size(); ++j) {
+      SCOPED_TRACE("and match: " + base::IntToString(j));
+      EXPECT_EQ(cases[i].matches[j].contents, UTF16ToUTF8(matches[j].contents));
+      EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
+    }
+    for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
+      SCOPED_TRACE("and match: " + base::IntToString(j));
+      EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
+      EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
+    }
+  }
+}
+
+
 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
   profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
   string16 term = term1_.substr(0, term1_.length() - 1);
diff --git a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
index 4917a55..7a41932 100644
--- a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
+++ b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
@@ -617,7 +617,7 @@
           .SetID("cedabbhfglmiikkmdgcpjdkocfcmbkee")
           .Build();
   extensions::UnloadedExtensionInfo details(
-      extension.get(), extension_misc::UNLOAD_REASON_UNINSTALL);
+      extension.get(), extensions::UnloadedExtensionInfo::REASON_UNINSTALL);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(&profile_),
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.cc b/chrome/browser/autocomplete/zero_suggest_provider.cc
index 8e195f0..66b8658 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.cc
+++ b/chrome/browser/autocomplete/zero_suggest_provider.cc
@@ -316,7 +316,8 @@
       }
     } else {
       suggest_results->push_back(SearchProvider::SuggestResult(
-          result, false, relevance, relevances != NULL, false));
+          result, result, string16(), std::string(), false, relevance,
+          relevances != NULL, false));
     }
   }
 }
@@ -341,16 +342,19 @@
   // TODO(samarth|melevin): use the actual omnibox margin here as well instead
   // of passing in -1.
   AutocompleteMatch match = SearchProvider::CreateSearchSuggestion(
-      this, relevance, type, template_url, query_string, query_string,
-      AutocompleteInput(), false, accepted_suggestion, -1, true);
+      this, AutocompleteInput(), query_string, relevance, type, false,
+      query_string, string16(), template_url, query_string, std::string(),
+      accepted_suggestion, -1, true);
   if (!match.destination_url.is_valid())
     return;
 
   // Try to add |match| to |map|.  If a match for |query_string| is already in
   // |map|, replace it if |match| is more relevant.
   // NOTE: Keep this ToLower() call in sync with url_database.cc.
+  SearchProvider::MatchKey match_key(
+      std::make_pair(base::i18n::ToLower(query_string), std::string()));
   const std::pair<SearchProvider::MatchMap::iterator, bool> i(map->insert(
-      std::make_pair(base::i18n::ToLower(query_string), match)));
+      std::make_pair(match_key, match)));
   // NOTE: We purposefully do a direct relevance comparison here instead of
   // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
   // first" rather than "items alphabetically first" when the scores are equal.
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h
index b6639ec..57d5383 100644
--- a/chrome/browser/automation/automation_provider_observers.h
+++ b/chrome/browser/automation/automation_provider_observers.h
@@ -47,7 +47,6 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "ui/gfx/point.h"
 #include "ui/gfx/size.h"
 
diff --git a/chrome/browser/automation/chrome_frame_automation_provider_win_unittest.cc b/chrome/browser/automation/chrome_frame_automation_provider_win_unittest.cc
index 8559a6b..95f9fd2 100644
--- a/chrome/browser/automation/chrome_frame_automation_provider_win_unittest.cc
+++ b/chrome/browser/automation/chrome_frame_automation_provider_win_unittest.cc
@@ -35,7 +35,7 @@
   base::MessageLoop message_loop;
   content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
 
-  IPC::Message bad_msg(1, -1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, -1);
 
   scoped_refptr<MockChromeFrameAutomationProvider>
       mock(new MockChromeFrameAutomationProvider(NULL));
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index a15f5d3..a84f27c 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -116,7 +116,6 @@
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
@@ -140,6 +139,7 @@
 #include "content/public/common/ssl_status.h"
 #include "content/public/common/webplugininfo.h"
 #include "extensions/browser/view_type_utils.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
 #include "net/cookies/cookie_store.h"
@@ -161,10 +161,6 @@
 #include <mach/mach_vm.h>
 #endif
 
-#if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif  // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
-
 using automation_util::SendErrorIfModalDialogActive;
 using content::BrowserChildProcessHostIterator;
 using content::BrowserContext;
diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc
index a3b3999..efac3d6 100644
--- a/chrome/browser/automation/testing_automation_provider_chromeos.cc
+++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/automation/testing_automation_provider.h"
 
+#include "ash/new_window_delegate.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "base/command_line.h"
 #include "base/i18n/time_formatting.h"
@@ -600,7 +600,7 @@
                                           IPC::Message* reply_message) {
   new NavigationNotificationObserver(
       NULL, this, reply_message, 1, false, true);
-  ash::Shell::GetInstance()->delegate()->OpenCrosh();
+  ash::Shell::GetInstance()->new_window_delegate()->OpenCrosh();
 }
 
 void TestingAutomationProvider::AddChromeosObservers() {
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index 1661b39..ae34df73 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -7,7 +7,9 @@
 #include <algorithm>
 #include <set>
 
+#include "base/sha1.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/background/background_contents_service.h"
@@ -25,10 +27,10 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "ui/base/l10n/l10n_util_collator.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
@@ -267,6 +269,28 @@
 }
 
 // static
+bool BackgroundApplicationListModel::RequiresBackgroundModeForPushMessaging(
+    const Extension& extension) {
+  // No PushMessaging permission - does not require the background mode.
+  if (!extension.HasAPIPermission(APIPermission::kPushMessaging))
+    return false;
+
+  // If in the whitelist, then does not require background mode even if
+  // uses push messaging.
+  // TODO(dimich): remove this whitelist once we have a better way to keep
+  // listening for GCM. http://crbug.com/311268
+  std::string id_hash = base::SHA1HashString(extension.id());
+  std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
+                                                   id_hash.length());
+  // The id starting from "9A04..." is a one from unit test.
+  if (hexencoded_id_hash == "C41AD9DCD670210295614257EF8C9945AD68D86E" ||
+      hexencoded_id_hash == "9A0417016F345C934A1A88F55CA17C05014EEEBA")
+     return false;
+
+   return true;
+ }
+
+// static
 bool BackgroundApplicationListModel::IsBackgroundApp(
     const Extension& extension, Profile* profile) {
   // An extension is a "background app" if it has the "background API"
@@ -278,7 +302,7 @@
   // Not a background app if we don't have the background permission or
   // the push messaging permission
   if (!extension.HasAPIPermission(APIPermission::kBackground) &&
-      !extension.HasAPIPermission(APIPermission::kPushMessaging) )
+      !RequiresBackgroundModeForPushMessaging(extension))
     return false;
 
   // Extensions and packaged apps with background permission are always treated
diff --git a/chrome/browser/background/background_application_list_model.h b/chrome/browser/background/background_application_list_model.h
index e9be88a..1bc7d2d 100644
--- a/chrome/browser/background/background_application_list_model.h
+++ b/chrome/browser/background/background_application_list_model.h
@@ -139,6 +139,13 @@
   // Refresh the list of background applications and generate notifications.
   void Update();
 
+  // Determines if the given extension has to be considered a "background app"
+  // due to its use of PushMessaging. Normally every extension that expectes
+  // push messages is classified as "background app", however there are some
+  // rare exceptions, so this function implements a whitelist.
+  static bool RequiresBackgroundModeForPushMessaging(
+      const extensions::Extension& extension);
+
   ApplicationMap applications_;
   extensions::ExtensionList extensions_;
   ObserverList<Observer> observers_;
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index 0c35c59..a2a0b6d 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -19,12 +19,12 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_types.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // This value is used to seed the PRNG at the beginning of a sequence of
@@ -35,8 +35,9 @@
 using extensions::Extension;
 
 // For ExtensionService interface when it requires a path that is not used.
-base::FilePath bogus_file_path() {
-  return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"));
+base::FilePath bogus_file_pathname(const std::string& name) {
+  return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"))
+      .AppendASCII(name);
 }
 
 class BackgroundApplicationListModelTest : public ExtensionServiceTestBase {
@@ -56,32 +57,69 @@
   }
 };
 
+enum PushMessagingOption {
+  NO_PUSH_MESSAGING,
+  PUSH_MESSAGING_PERMISSION,
+  PUSH_MESSAGING_BUT_NOT_BACKGROUND
+};
+
 // Returns a barebones test Extension object with the specified |name|.  The
 // returned extension will include background permission iff
-// |background_permission| is true.
-static scoped_refptr<Extension> CreateExtension(const std::string& name,
-                                                bool background_permission) {
+// |background_permission| is true and pushMessaging permission if requested
+// by |push_messaging| value. Also the extension may have a specific id set
+// to test the case when it has a pushMessaging permission but is not
+// considered a background app based on a whitelist.
+static scoped_refptr<Extension> CreateExtensionBase(
+    const std::string& name,
+    bool background_permission,
+    PushMessagingOption push_messaging) {
   DictionaryValue manifest;
   manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
   manifest.SetString(extensions::manifest_keys::kName, name);
+  ListValue* permissions = new ListValue();
+  manifest.Set(extensions::manifest_keys::kPermissions, permissions);
   if (background_permission) {
-    ListValue* permissions = new ListValue();
-    manifest.Set(extensions::manifest_keys::kPermissions, permissions);
     permissions->Append(Value::CreateStringValue("background"));
   }
+  if (push_messaging == PUSH_MESSAGING_PERMISSION ||
+      push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) {
+    permissions->Append(Value::CreateStringValue("pushMessaging"));
+  }
+
   std::string error;
-  scoped_refptr<Extension> extension = Extension::Create(
-      bogus_file_path().AppendASCII(name),
-      extensions::Manifest::INVALID_LOCATION,
-      manifest,
-      Extension::NO_FLAGS,
-      &error);
+  scoped_refptr<Extension> extension;
+
+  // There is a whitelist for extensions that have pushMessaging permission but
+  // are not considered a background app. Create a test extension with a known
+  // test id if needed.
+  if (push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) {
+    extension = Extension::Create(
+        bogus_file_pathname(name),
+        extensions::Manifest::INVALID_LOCATION,
+        manifest,
+        Extension::NO_FLAGS,
+        "aaaabbbbccccddddeeeeffffgggghhhh",
+        &error);
+  } else {
+    extension = Extension::Create(
+        bogus_file_pathname(name),
+        extensions::Manifest::INVALID_LOCATION,
+        manifest,
+        Extension::NO_FLAGS,
+        &error);
+  }
+
   // Cannot ASSERT_* here because that attempts an illegitimate return.
   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
   EXPECT_TRUE(extension.get() != NULL) << error;
   return extension;
 }
 
+static scoped_refptr<Extension> CreateExtension(const std::string& name,
+                                                bool background_permission) {
+  return CreateExtensionBase(name, background_permission, NO_PUSH_MESSAGING);
+}
+
 namespace {
 std::string GenerateUniqueExtensionName() {
   static int uniqueness = 0;
@@ -192,6 +230,81 @@
   ASSERT_EQ(0U, model->size());
 }
 
+// Verifies that pushMessaging also triggers background detection, except
+// when extension is in a whitelist.
+TEST_F(BackgroundApplicationListModelTest, PushMessagingTest) {
+  InitializeAndLoadEmptyExtensionService();
+  ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())->
+      extension_service();
+  ASSERT_TRUE(service);
+  ASSERT_TRUE(service->is_ready());
+  ASSERT_TRUE(service->extensions());
+  ASSERT_TRUE(service->extensions()->is_empty());
+  scoped_ptr<BackgroundApplicationListModel> model(
+      new BackgroundApplicationListModel(profile_.get()));
+  ASSERT_EQ(0U, model->size());
+
+  scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
+  scoped_refptr<Extension> ext2 =
+      CreateExtensionBase("charlie", false, PUSH_MESSAGING_BUT_NOT_BACKGROUND);
+  scoped_refptr<Extension> bgapp1 =
+      CreateExtensionBase("bravo", false, PUSH_MESSAGING_PERMISSION);
+  scoped_refptr<Extension> bgapp2 =
+      CreateExtensionBase("delta", true, PUSH_MESSAGING_PERMISSION);
+  scoped_refptr<Extension> bgapp3 =
+      CreateExtensionBase("echo", true, PUSH_MESSAGING_BUT_NOT_BACKGROUND);
+  ASSERT_TRUE(service->extensions() != NULL);
+  ASSERT_EQ(0U, service->extensions()->size());
+  ASSERT_EQ(0U, model->size());
+
+  // Add alternating Extensions and Background Apps
+  ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
+  service->AddExtension(ext1.get());
+  ASSERT_EQ(1U, service->extensions()->size());
+  ASSERT_EQ(0U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
+  service->AddExtension(bgapp1.get());
+  ASSERT_EQ(2U, service->extensions()->size());
+  ASSERT_EQ(1U, model->size());
+  ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
+  service->AddExtension(ext2.get());
+  ASSERT_EQ(3U, service->extensions()->size());
+  ASSERT_EQ(1U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
+  service->AddExtension(bgapp2.get());
+  ASSERT_EQ(4U, service->extensions()->size());
+  ASSERT_EQ(2U, model->size());
+  // Need to remove ext2 because it uses same id as bgapp3.
+  ASSERT_FALSE(IsBackgroundApp(*ext2.get()));
+  service->UninstallExtension(ext2->id(), false, NULL);
+  ASSERT_EQ(3U, service->extensions()->size());
+  ASSERT_EQ(2U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp3.get()));
+  service->AddExtension(bgapp3.get());
+  ASSERT_EQ(4U, service->extensions()->size());
+  ASSERT_EQ(3U, model->size());
+
+  // Remove in FIFO order.
+  ASSERT_FALSE(IsBackgroundApp(*ext1.get()));
+  service->UninstallExtension(ext1->id(), false, NULL);
+  ASSERT_EQ(3U, service->extensions()->size());
+  ASSERT_EQ(3U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp1.get()));
+  service->UninstallExtension(bgapp1->id(), false, NULL);
+  ASSERT_EQ(2U, service->extensions()->size());
+  ASSERT_EQ(2U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp2.get()));
+  service->UninstallExtension(bgapp2->id(), false, NULL);
+  ASSERT_EQ(1U, service->extensions()->size());
+  ASSERT_EQ(1U, model->size());
+  ASSERT_TRUE(IsBackgroundApp(*bgapp3.get()));
+  service->UninstallExtension(bgapp3->id(), false, NULL);
+  ASSERT_EQ(0U, service->extensions()->size());
+  ASSERT_EQ(0U, model->size());
+}
+
+
+
 // With minimal test logic, verifies behavior with dynamic permissions.
 TEST_F(BackgroundApplicationListModelTest, AddRemovePermissionsTest) {
   InitializeAndLoadEmptyExtensionService();
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index 9ab995c..a46e4a1 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_delegate.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -428,16 +428,16 @@
     }
     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
       switch (content::Details<UnloadedExtensionInfo>(details)->reason) {
-        case extension_misc::UNLOAD_REASON_DISABLE:    // Fall through.
-        case extension_misc::UNLOAD_REASON_TERMINATE:  // Fall through.
-        case extension_misc::UNLOAD_REASON_UNINSTALL:  // Fall through.
-        case extension_misc::UNLOAD_REASON_BLACKLIST:
+        case UnloadedExtensionInfo::REASON_DISABLE:    // Fall through.
+        case UnloadedExtensionInfo::REASON_TERMINATE:  // Fall through.
+        case UnloadedExtensionInfo::REASON_UNINSTALL:  // Fall through.
+        case UnloadedExtensionInfo::REASON_BLACKLIST:
           ShutdownAssociatedBackgroundContents(
               ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)->
                   extension->id()));
           SendChangeNotification(content::Source<Profile>(source).ptr());
           break;
-        case extension_misc::UNLOAD_REASON_UPDATE: {
+        case UnloadedExtensionInfo::REASON_UPDATE: {
           // If there is a manifest specified background page, then shut it down
           // here, since if the updated extension still has the background page,
           // then it will be loaded from LOADED callback. Otherwise, leave
diff --git a/chrome/browser/background/background_contents_service_unittest.cc b/chrome/browser/background/background_contents_service_unittest.cc
index a58cfbc..41228c4 100644
--- a/chrome/browser/background/background_contents_service_unittest.cc
+++ b/chrome/browser/background/background_contents_service_unittest.cc
@@ -8,11 +8,11 @@
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/background/background_contents_service.h"
 #include "chrome/browser/background/background_contents_service_factory.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/tab_contents/background_contents.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index b1ffcd1..ccff276 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -37,10 +38,10 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "grit/chrome_unscaled_resources.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -148,6 +149,8 @@
       in_background_mode_(false),
       keep_alive_for_startup_(false),
       keep_alive_for_test_(false),
+      background_mode_suspended_(false),
+      keeping_alive_(false),
       current_command_id_(0) {
   // We should never start up if there is no browser process or if we are
   // currently quitting.
@@ -174,6 +177,11 @@
   if (command_line->HasSwitch(switches::kNoStartupWindow)) {
     keep_alive_for_startup_ = true;
     chrome::StartKeepAlive();
+  } else {
+    // Otherwise, start with background mode suspended in case we're launching
+    // in a mode that doesn't open a browser window. It will be resumed when the
+    // first browser window is opened.
+    SuspendBackgroundMode();
   }
 
   // If the -keep-alive-for-test flag is passed, then always keep chrome running
@@ -188,6 +196,7 @@
   // count.
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
+  BrowserList::AddObserver(this);
 }
 
 BackgroundModeManager::~BackgroundModeManager() {
@@ -199,6 +208,7 @@
        ++it) {
     it->second->applications_->RemoveObserver(this);
   }
+  BrowserList::RemoveObserver(this);
 
   // We're going away, so exit background mode (does nothing if we aren't in
   // background mode currently). This is primarily needed for unit tests,
@@ -457,7 +467,7 @@
       break;
     case IDC_EXIT:
       content::RecordAction(UserMetricsAction("Exit"));
-      chrome::AttemptExit();
+      chrome::CloseAllBrowsers();
       break;
     case IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND: {
       // Background mode must already be enabled (as otherwise this menu would
@@ -502,11 +512,7 @@
   // Mark ourselves as running in background mode.
   in_background_mode_ = true;
 
-  // Put ourselves in KeepAlive mode and create a status tray icon.
-  chrome::StartKeepAlive();
-
-  // Display a status icon to exit Chrome.
-  InitStatusTrayIcon();
+  UpdateKeepAliveAndTrayIcon();
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
@@ -514,22 +520,13 @@
       content::Details<bool>(&in_background_mode_));
 }
 
-void BackgroundModeManager::InitStatusTrayIcon() {
-  // Only initialize status tray icons for those profiles which actually
-  // have a background app running.
-  if (ShouldBeInBackgroundMode())
-    CreateStatusTrayIcon();
-}
-
 void BackgroundModeManager::EndBackgroundMode() {
   if (!in_background_mode_)
     return;
   in_background_mode_ = false;
 
-  // End KeepAlive mode and blow away our status tray icon.
-  chrome::EndKeepAlive();
+  UpdateKeepAliveAndTrayIcon();
 
-  RemoveStatusTrayIcon();
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
       content::Source<BackgroundModeManager>(this),
@@ -554,6 +551,37 @@
   }
 }
 
+void BackgroundModeManager::SuspendBackgroundMode() {
+  background_mode_suspended_ = true;
+  UpdateKeepAliveAndTrayIcon();
+}
+
+void BackgroundModeManager::ResumeBackgroundMode() {
+  background_mode_suspended_ = false;
+  UpdateKeepAliveAndTrayIcon();
+}
+
+void BackgroundModeManager::UpdateKeepAliveAndTrayIcon() {
+  if (in_background_mode_ && !background_mode_suspended_) {
+    if (!keeping_alive_) {
+      keeping_alive_ = true;
+      chrome::StartKeepAlive();
+    }
+    CreateStatusTrayIcon();
+    return;
+  }
+
+  RemoveStatusTrayIcon();
+  if (keeping_alive_) {
+    keeping_alive_ = false;
+    chrome::EndKeepAlive();
+  }
+}
+
+void BackgroundModeManager::OnBrowserAdded(Browser* browser) {
+  ResumeBackgroundMode();
+}
+
 int BackgroundModeManager::GetBackgroundAppCount() const {
   int count = 0;
   // Walk the BackgroundModeData for all profiles and count the number of apps.
@@ -584,9 +612,10 @@
   if (!IsBackgroundModePrefEnabled())
     return;
 
-  // Check if we need a status tray icon and make one if we do (needed so we
-  // can display the app-installed notification below).
-  CreateStatusTrayIcon();
+  // Ensure we have a tray icon (needed so we can display the app-installed
+  // notification below).
+  EnableBackgroundMode();
+  ResumeBackgroundMode();
 
   // Notify the user that a background app has been installed.
   if (extension) {  // NULL when called by unit tests.
@@ -640,11 +669,8 @@
 }
 
 void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
-  // If no status icon exists, it's either because one wasn't created when
-  // it should have been which can happen when extensions load after the
-  // profile has already been registered with the background mode manager.
-  if (in_background_mode_ && !status_icon_)
-     CreateStatusTrayIcon();
+  // Ensure we have a tray icon if appropriate.
+  UpdateKeepAliveAndTrayIcon();
 
   // If we don't have a status icon or one could not be created succesfully,
   // then no need to continue the update.
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index 0494f5a..b102743 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/status_icons/status_icon.h"
 #include "chrome/browser/status_icons/status_icon_menu_model.h"
+#include "chrome/browser/ui/browser_list_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -45,6 +46,7 @@
 // background.
 class BackgroundModeManager
     : public content::NotificationObserver,
+      public chrome::BrowserListObserver,
       public BackgroundApplicationListModel::Observer,
       public ProfileInfoCacheObserver,
       public StatusIconMenuModel::Delegate {
@@ -63,6 +65,15 @@
   // Returns true if background mode is active.
   virtual bool IsBackgroundModeActive();
 
+  // Suspends background mode until either ResumeBackgroundMode is called or
+  // Chrome is restarted. This has the same effect as ending background mode
+  // for the current browser session.
+  virtual void SuspendBackgroundMode();
+
+  // Resumes background mode. This ends a suspension of background mode, but
+  // will not start it if it is not enabled.
+  virtual void ResumeBackgroundMode();
+
   // For testing purposes.
   int NumberOfBackgroundModeData();
 
@@ -176,6 +187,9 @@
   // Overrides from StatusIconMenuModel::Delegate implementation.
   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
 
+  // chrome::BrowserListObserver implementation.
+  virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
+
   // Invoked when an extension is installed so we can ensure that
   // launch-on-startup is enabled if appropriate. |extension| can be NULL when
   // called from unit tests.
@@ -202,14 +216,14 @@
   // and has a status bar icon.
   void StartBackgroundMode();
 
-  // Invoked to create the status icon if any profiles currently running
-  // background apps so that there is a way to exit Chrome.
-  void InitStatusTrayIcon();
-
   // Invoked to take Chrome out of KeepAlive mode - chrome stops running in
   // the background and removes its status bar icon.
   void EndBackgroundMode();
 
+  // Enables keep alive and the status tray icon if and only if background mode
+  // is active and not suspended.
+  void UpdateKeepAliveAndTrayIcon();
+
   // If --no-startup-window is passed, BackgroundModeManager will manually keep
   // chrome running while waiting for apps to load. This is called when we no
   // longer need to do this (either because the user has chosen to exit chrome
@@ -302,6 +316,12 @@
   // app).
   bool keep_alive_for_test_;
 
+  // Set to true when background mode is suspended.
+  bool background_mode_suspended_;
+
+  // Set to true when background mode is keeping Chrome alive.
+  bool keeping_alive_;
+
   // Provides a command id for each profile as they are created.
   int current_command_id_;
 
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index 2f222f1..42281fa 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -38,7 +38,9 @@
         app_count_(0),
         profile_app_count_(0),
         have_status_tray_(false),
-        launch_on_startup_(false) {}
+        launch_on_startup_(false) {
+    ResumeBackgroundMode();
+  }
   virtual void EnableLaunchOnStartup(bool launch) OVERRIDE {
     launch_on_startup_ = launch;
   }
@@ -84,6 +86,13 @@
   EXPECT_FALSE(manager.IsLaunchOnStartup());
 }
 
+static void AssertBackgroundModeSuspended(
+    const TestBackgroundModeManager& manager) {
+  EXPECT_FALSE(chrome::WillKeepAlive());
+  EXPECT_FALSE(manager.HaveStatusTray());
+  EXPECT_TRUE(manager.IsLaunchOnStartup());
+}
+
 TEST_F(BackgroundModeManagerTest, BackgroundAppLoadUnload) {
   TestingProfile* profile = profile_manager_.CreateTestingProfile("p1");
   TestBackgroundModeManager manager(
@@ -97,10 +106,24 @@
   manager.OnApplicationListChanged(profile);
   AssertBackgroundModeActive(manager);
 
+  manager.SuspendBackgroundMode();
+  AssertBackgroundModeSuspended(manager);
+  manager.ResumeBackgroundMode();
+
   // Mimic app unload.
   manager.SetBackgroundAppCount(0);
   manager.OnApplicationListChanged(profile);
   AssertBackgroundModeInactive(manager);
+
+  manager.SuspendBackgroundMode();
+  AssertBackgroundModeInactive(manager);
+
+  // Mimic app load while suspended, e.g. from sync. This should enable and
+  // resume background mode.
+  manager.OnBackgroundAppInstalled(NULL);
+  manager.SetBackgroundAppCount(1);
+  manager.OnApplicationListChanged(profile);
+  AssertBackgroundModeActive(manager);
 }
 
 // App installs while background mode is disabled should do nothing.
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 51abfe8..934e528 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/devtools/remote_debugging_server.h"
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_status_updater.h"
+#include "chrome/browser/extensions/chrome_extensions_browser_client.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/extensions/extension_renderer_state.h"
 #include "chrome/browser/first_run/upgrade_util.h"
@@ -187,6 +188,8 @@
   apps::AppsClient::Set(ChromeAppsClient::GetInstance());
   extensions::ExtensionsClient::Set(
       extensions::ChromeExtensionsClient::GetInstance());
+  extensions::ExtensionsBrowserClient::Set(
+      extensions::ChromeExtensionsBrowserClient::GetInstance());
   extension_event_router_forwarder_ = new extensions::EventRouterForwarder;
   ExtensionRendererState::GetInstance()->Init();
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index e45cef6..db93304 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -131,6 +131,7 @@
       <include name="IDR_FEEDBACK_MANIFEST" file="resources\feedback\manifest.json" type="BINDATA" />
       <include name="IDR_FLAGS_HTML" file="resources\flags.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_FLAGS_JS" file="resources\flags.js" type="BINDATA" />
+      <include name="IDR_HANGOUT_SERVICES_MANIFEST" file="resources\hangout_services\manifest.json" type="BINDATA" />
       <include name="IDR_HELP_JS" file="resources\help\help.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_CHANNEL_CHANGE_PAGE_JS" file="resources\help\channel_change_page.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_HISTORY_HTML" file="resources\history\history.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index c22f495..891acad 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -60,7 +60,6 @@
   // The following trials are used from renderer process.
   // Mark here so they will be sync-ed.
   base::FieldTrialList::FindValue("CLD1VsCLD2");
-  base::FieldTrialList::FindValue("DateExtensionEnabled");
   base::FieldTrialList::FindValue("MouseEventPreconnect");
   // Activate the autocomplete dynamic field trials.
   OmniboxFieldTrial::ActivateDynamicTrials();
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
index c723802..80e3dcd 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -11,14 +11,13 @@
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/auto_launch_trial.h"
 #include "chrome/browser/google/google_util.h"
-#include "chrome/browser/gpu/chrome_gpu_util.h"
 #include "chrome/browser/omnibox/omnibox_field_trial.h"
 #include "chrome/browser/prerender/prerender_field_trial.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
@@ -130,7 +129,6 @@
                              PrefService* local_state) {
   prerender::ConfigurePrefetchAndPrerender(parsed_command_line);
   AutoLaunchChromeFieldTrial();
-  gpu_util::InitializeCompositingFieldTrial();
   OmniboxFieldTrial::ActivateStaticTrials();
   SetupInfiniteCacheFieldTrial();
   DisableShowProfileSwitcherTrialIfNecessary();
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 0e14596..0a33f91 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -26,6 +26,7 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/pref_value_store.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/process/process_info.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -59,7 +60,6 @@
 #include "chrome/browser/first_run/upgrade_util.h"
 #include "chrome/browser/google/google_search_counter.h"
 #include "chrome/browser/google/google_util.h"
-#include "chrome/browser/gpu/chrome_gpu_util.h"
 #include "chrome/browser/gpu/gl_string_manager.h"
 #include "chrome/browser/jankometer.h"
 #include "chrome/browser/language_usage_metrics.h"
@@ -85,7 +85,6 @@
 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
 #include "chrome/browser/prefs/command_line_pref_store.h"
 #include "chrome/browser/prefs/pref_metrics_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
 #include "chrome/browser/process_singleton.h"
@@ -314,8 +313,10 @@
 
   // If we are showing the app list then chrome isn't shown so load the app
   // list's profile rather than chrome's.
-  if (command_line.HasSwitch(switches::kShowAppList))
-    return AppListService::Get()->GetProfilePath(user_data_dir);
+  if (command_line.HasSwitch(switches::kShowAppList)) {
+    return AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->
+        GetProfilePath(user_data_dir);
+  }
 
   return g_browser_process->profile_manager()->GetLastUsedProfileDir(
       user_data_dir);
@@ -959,7 +960,7 @@
           master_prefs_->suppress_default_browser_prompt_for_version);
     }
 
-    AppListService::Get()->HandleFirstRun();
+    AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->HandleFirstRun();
   }
 #endif
 
@@ -1027,6 +1028,26 @@
 
 void ChromeBrowserMainParts::PreProfileInit() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreProfileInit");
+
+#if !defined(OS_ANDROID)
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+  // First check if any ephemeral profiles are left behind because of browser
+  // crash and schedule them for deletion and then proceed with getting the set
+  // of profiles to open.
+  ProfileInfoCache& profile_cache = profile_manager->GetProfileInfoCache();
+  size_t profiles_count = profile_cache.GetNumberOfProfiles();
+  std::vector<base::FilePath> profiles_to_delete;
+  for (size_t i = 0;i < profiles_count; ++i) {
+    if (profile_cache.ProfileIsEphemeralAtIndex(i))
+      profiles_to_delete.push_back(profile_cache.GetPathOfProfileAtIndex(i));
+  }
+  for (size_t i = 0;i < profiles_to_delete.size(); ++i) {
+    profile_manager->ScheduleProfileForDeletion(
+        profiles_to_delete[i], ProfileManager::CreateCallback());
+  }
+#endif  // OS_ANDROID
+
   for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
     chrome_extra_parts_[i]->PreProfileInit();
 }
@@ -1076,6 +1097,7 @@
   // application is in the foreground or not. Do not start here.
 #if !defined(OS_ANDROID)
   // Now that the file thread has been started, start recording.
+  MetricsService::SetExecutionPhase(MetricsService::START_METRICS_RECORDING);
   StartMetricsRecording();
 #endif
 
@@ -1222,6 +1244,7 @@
   // calls to GetDefaultProfile().
   ProfileManager::AllowGetDefaultProfile();
 
+  MetricsService::SetExecutionPhase(MetricsService::CREATE_PROFILE);
   profile_ = CreateProfile(parameters(), user_data_dir_, parsed_command_line());
   if (!profile_)
     return content::RESULT_CODE_NORMAL_EXIT;
@@ -1406,6 +1429,7 @@
   // Start watching for hangs during startup. We disarm this hang detector when
   // ThreadWatcher takes over or when browser is shutdown or when
   // startup_watcher_ is deleted.
+  MetricsService::SetExecutionPhase(MetricsService::STARTUP_TIMEBOMB_ARM);
   startup_watcher_->Arm(base::TimeDelta::FromSeconds(300));
 
   // On mobile, need for clean shutdown arises only when the application comes
@@ -1427,6 +1451,7 @@
 #endif
 
   // Start watching all browser threads for responsiveness.
+  MetricsService::SetExecutionPhase(MetricsService::THREAD_WATCHER_START);
   ThreadWatcherList::StartWatchingAll(parsed_command_line());
 
 #if !defined(DISABLE_NACL)
@@ -1598,6 +1623,7 @@
 
   performance_monitor::PerformanceMonitor::GetInstance()->StartGatherCycle();
 
+  MetricsService::SetExecutionPhase(MetricsService::MAIN_MESSAGE_LOOP_RUN);
   run_loop.Run();
 
   return true;
@@ -1614,6 +1640,7 @@
 
   // Start watching for jank during shutdown. It gets disarmed when
   // |shutdown_watcher_| object is destructed.
+  MetricsService::SetExecutionPhase(MetricsService::SHUTDOWN_TIMEBOMB_ARM);
   shutdown_watcher_->Arm(base::TimeDelta::FromSeconds(300));
 
   // Disarm the startup hang detector time bomb if it is still Arm'ed.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index e4347f8..6f8139a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -13,6 +13,7 @@
 #include "base/lazy_instance.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -57,7 +58,6 @@
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/plugins/plugin_info_message_filter.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
@@ -594,13 +594,7 @@
   SingleTabModeTabHelper::FromWebContents(web_contents)->HandleOpenUrl(params);
 }
 
-float GetFontScaleMultiplier(const PrefService* prefs) {
-  if (prefs->GetBoolean(prefs::kWebKitFontScaleFactorQuirk)) {
-    // The value of kWebKitFontScaleFactor passed by Chrome for Android already
-    // includes the multiplier.
-    return 1.0f;
-  }
-
+float GetFontScaleMultiplier() {
   static const float kMinFSM = 1.05f;
   static const int kWidthForMinFSM = 320;
   static const float kMaxFSM = 1.3f;
@@ -1437,8 +1431,12 @@
           extensions::ExtensionSystem::Get(profile)->extension_service();
       if (extension_service) {
         extensions::ProcessMap* process_map = extension_service->process_map();
-        if (process_map && process_map->Contains(process->GetID()))
+        if (process_map && process_map->Contains(process->GetID())) {
           command_line->AppendSwitch(switches::kExtensionProcess);
+#if defined(OS_WIN) && defined(USE_AURA)
+          command_line->AppendSwitch(switches::kDisableGpuCompositing);
+#endif
+        }
       }
 
       PrefService* prefs = profile->GetPrefs();
@@ -2223,7 +2221,7 @@
 #if defined(OS_ANDROID)
   web_prefs->text_autosizing_font_scale_factor =
       static_cast<float>(prefs->GetDouble(prefs::kWebKitFontScaleFactor)) *
-      GetFontScaleMultiplier(prefs);
+      GetFontScaleMultiplier();
   web_prefs->force_enable_zoom =
       prefs->GetBoolean(prefs::kWebKitForceEnableZoom);
 #endif
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 9eab34c..21243e5 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -4,4 +4,7 @@
   "+dbus",
   "+device/bluetooth",
   "+media/base/media_switches.h",  # For media command line switches.
+
+  # Other libraries.
+  "+third_party/libjingle",
 ]
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index a841988..176730e 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_service.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/accessibility/accessibility_extension_api.h"
 #include "chrome/browser/browser_process.h"
@@ -36,6 +37,7 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/login/login_state.h"
 #include "content/public/browser/browser_accessibility_state.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
@@ -50,7 +52,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
+using content::BrowserThread;
 using content::RenderViewHost;
+using extensions::api::braille_display_private::BrailleController;
+using extensions::api::braille_display_private::DisplayState;
 
 namespace chromeos {
 
@@ -58,6 +63,14 @@
 
 static chromeos::AccessibilityManager* g_accessibility_manager = NULL;
 
+static BrailleController* g_braille_controller_for_test = NULL;
+
+BrailleController* GetBrailleController() {
+  return g_braille_controller_for_test
+      ? g_braille_controller_for_test
+      : BrailleController::GetInstance();
+}
+
 // Helper class that directly loads an extension's content scripts into
 // all of the frames corresponding to a given RenderViewHost.
 class ContentScriptLoader {
@@ -266,11 +279,14 @@
       spoken_feedback_pref_handler_(prefs::kSpokenFeedbackEnabled),
       high_contrast_pref_handler_(prefs::kHighContrastEnabled),
       autoclick_pref_handler_(prefs::kAutoclickEnabled),
+      autoclick_delay_pref_handler_(prefs::kAutoclickDelayMs),
       large_cursor_enabled_(false),
       sticky_keys_enabled_(false),
       spoken_feedback_enabled_(false),
       high_contrast_enabled_(false),
-      spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE) {
+      autoclick_delay_ms_(ash::AutoclickController::kDefaultAutoclickDelayMs),
+      spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE),
+      weak_ptr_factory_(this) {
 
   notification_registrar_.Add(this,
                               chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
@@ -284,6 +300,7 @@
   notification_registrar_.Add(this,
                               chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
                               content::NotificationService::AllSources());
+  GetBrailleController()->AddObserver(this);
 }
 
 AccessibilityManager::~AccessibilityManager() {
@@ -576,6 +593,48 @@
 #endif
 }
 
+void AccessibilityManager::SetAutoclickDelay(int delay_ms) {
+  if (!profile_)
+    return;
+
+  PrefService* pref_service = profile_->GetPrefs();
+  pref_service->SetInteger(prefs::kAutoclickDelayMs, delay_ms);
+  pref_service->CommitPendingWrite();
+}
+
+int AccessibilityManager::GetAutoclickDelay() const {
+  return autoclick_delay_ms_;
+}
+
+void AccessibilityManager::UpdateAutoclickDelayFromPref() {
+  int autoclick_delay_ms =
+      profile_->GetPrefs()->GetInteger(prefs::kAutoclickDelayMs);
+
+  if (autoclick_delay_ms == autoclick_delay_ms_)
+    return;
+  autoclick_delay_ms_ = autoclick_delay_ms;
+
+#if defined(USE_ASH)
+  ash::Shell::GetInstance()->autoclick_controller()->SetAutoclickDelay(
+      autoclick_delay_ms_);
+#endif
+}
+
+void AccessibilityManager::CheckBrailleState() {
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::IO, FROM_HERE, base::Bind(
+          &BrailleController::GetDisplayState,
+          base::Unretained(GetBrailleController())),
+      base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void AccessibilityManager::ReceiveBrailleDisplayState(
+    scoped_ptr<extensions::api::braille_display_private::DisplayState> state) {
+  OnDisplayStateChanged(*state);
+}
+
+
 void AccessibilityManager::SetProfile(Profile* profile) {
   pref_change_registrar_.reset();
   local_state_pref_change_registrar_.reset();
@@ -604,6 +663,10 @@
         prefs::kAutoclickEnabled,
         base::Bind(&AccessibilityManager::UpdateAutoclickFromPref,
                    base::Unretained(this)));
+    pref_change_registrar_->Add(
+        prefs::kAutoclickDelayMs,
+        base::Bind(&AccessibilityManager::UpdateAutoclickDelayFromPref,
+                   base::Unretained(this)));
 
     local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
     local_state_pref_change_registrar_->Init(g_browser_process->local_state());
@@ -622,6 +685,10 @@
   spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile);
   high_contrast_pref_handler_.HandleProfileChanged(profile_, profile);
   autoclick_pref_handler_.HandleProfileChanged(profile_, profile);
+  autoclick_delay_pref_handler_.HandleProfileChanged(profile_, profile);
+
+  if (!profile_ && profile)
+    CheckBrailleState();
 
   profile_ = profile;
   UpdateLargeCursorFromPref();
@@ -629,12 +696,18 @@
   UpdateSpokenFeedbackFromPref();
   UpdateHighContrastFromPref();
   UpdateAutoclickFromPref();
+  UpdateAutoclickDelayFromPref();
 }
 
 void AccessibilityManager::SetProfileForTest(Profile* profile) {
   SetProfile(profile);
 }
 
+void AccessibilityManager::SetBrailleControllerForTest(
+    BrailleController* controller) {
+  g_braille_controller_for_test = controller;
+}
+
 void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
   UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
                         IsSpokenFeedbackEnabled());
@@ -657,6 +730,20 @@
     UMA_HISTOGRAM_BOOLEAN(
         "Accessibility.CrosAlwaysShowA11yMenu",
         prefs->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu));
+
+    bool autoclick_enabled = prefs->GetBoolean(prefs::kAutoclickEnabled);
+    UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
+    if (autoclick_enabled) {
+      // We only want to log the autoclick delay if the user has actually
+      // enabled autoclick.
+      UMA_HISTOGRAM_CUSTOM_TIMES(
+          "Accessibility.CrosAutoclickDelay",
+          base::TimeDelta::FromMilliseconds(
+              prefs->GetInteger(prefs::kAutoclickDelayMs)),
+          base::TimeDelta::FromMilliseconds(1),
+          base::TimeDelta::FromMilliseconds(3000),
+          50);
+    }
   }
 }
 
@@ -698,4 +785,9 @@
   }
 }
 
+void AccessibilityManager::OnDisplayStateChanged(
+    const DisplayState& display_state) {
+  if (display_state.available)
+    EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_SHOW);
+}
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 418eade..923ee3c 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -5,9 +5,11 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_ACCESSIBILITY_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_ACCESSIBILITY_MANAGER_H_
 
-#include "ash/shell_delegate.h"
+#include "ash/accessibility_delegate.h"
+#include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
+#include "chrome/browser/extensions/api/braille_display_private/braille_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -33,7 +35,8 @@
 // AccessibilityManager changes the statuses of accessibility features
 // watching profile notifications and pref-changes.
 // TODO(yoshiki): merge MagnificationManager with AccessibilityManager.
-class AccessibilityManager : public content::NotificationObserver {
+class AccessibilityManager : public content::NotificationObserver,
+    extensions::api::braille_display_private::BrailleObserver {
  public:
   // Creates an instance of AccessibilityManager, this should be called once,
   // because only one instance should exist at the same time.
@@ -100,8 +103,17 @@
   // Returns true if autoclick is enabled.
   bool IsAutoclickEnabled();
 
+  // Set the delay for autoclicking after stopping the cursor in milliseconds.
+  void SetAutoclickDelay(int delay_ms);
+
+  // Returns the autoclick delay in milliseconds.
+  int GetAutoclickDelay() const;
+
   void SetProfileForTest(Profile* profile);
 
+  static void SetBrailleControllerForTest(
+      extensions::api::braille_display_private::BrailleController* controller);
+
  protected:
   AccessibilityManager();
   virtual ~AccessibilityManager();
@@ -118,8 +130,14 @@
   void UpdateSpokenFeedbackFromPref();
   void UpdateHighContrastFromPref();
   void UpdateAutoclickFromPref();
+  void UpdateAutoclickDelayFromPref();
   void LocalePrefChanged();
 
+  void CheckBrailleState();
+  void ReceiveBrailleDisplayState(
+      scoped_ptr<extensions::api::braille_display_private::DisplayState> state);
+
+
   void SetProfile(Profile* profile);
 
   void UpdateChromeOSAccessibilityHistograms();
@@ -129,6 +147,12 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // extensions::api::braille_display_private::BrailleObserver implementation.
+  // Enables spoken feedback if a braille display becomes available.
+  virtual void OnDisplayStateChanged(
+      const extensions::api::braille_display_private::DisplayState&
+          display_state) OVERRIDE;
+
   // Profile which has the current a11y context.
   Profile* profile_;
 
@@ -145,15 +169,19 @@
   PrefHandler spoken_feedback_pref_handler_;
   PrefHandler high_contrast_pref_handler_;
   PrefHandler autoclick_pref_handler_;
+  PrefHandler autoclick_delay_pref_handler_;
 
   bool large_cursor_enabled_;
   bool sticky_keys_enabled_;
   bool spoken_feedback_enabled_;
   bool high_contrast_enabled_;
   bool autoclick_enabled_;
+  int autoclick_delay_ms_;
 
   ash::AccessibilityNotificationVisibility spoken_feedback_notification_;
 
+  base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(AccessibilityManager);
 };
 
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
index 1cf3328..1971904 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager_impl.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
@@ -25,12 +26,18 @@
 #include "content/public/browser/notification_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::api::braille_display_private::BrailleObserver;
+using extensions::api::braille_display_private::DisplayState;
+using extensions::api::braille_display_private::StubBrailleController;
+
 namespace chromeos {
 
 namespace {
 
 const char kTestUserName[] = "owner@invalid.domain";
 
+const int kTestAutoclickDelayMs = 2000;
+
 // Test user name for locally managed user. The domain part must be matched
 // with UserManager::kLocallyManagedUserDomain.
 const char kTestLocallyManagedUserName[] = "test@locally-managed.localhost";
@@ -90,6 +97,39 @@
   DISALLOW_COPY_AND_ASSIGN(MockAccessibilityObserver);
 };
 
+class MockBrailleController : public StubBrailleController {
+ public:
+
+  MockBrailleController() : available_(false), observer_(NULL) {}
+
+  virtual scoped_ptr<DisplayState> GetDisplayState() OVERRIDE {
+    scoped_ptr<DisplayState> state(new DisplayState());
+    state->available = available_;
+    return state.Pass();
+  }
+
+  virtual void AddObserver(BrailleObserver* observer) OVERRIDE {
+    ASSERT_EQ(NULL, observer_);
+    observer_ = observer;
+  }
+
+  virtual void RemoveObserver(BrailleObserver* observer) OVERRIDE {
+    ASSERT_EQ(observer_, observer);
+  }
+
+  void SetAvailable(bool available) {
+    available_ = available;
+  }
+
+  BrailleObserver* GetObserver() {
+    return observer_;
+  }
+
+ private:
+  bool available_;
+  BrailleObserver* observer_;
+};
+
 void SetLargeCursorEnabled(bool enabled) {
   return AccessibilityManager::Get()->EnableLargeCursor(enabled);
 }
@@ -123,6 +163,14 @@
   return AccessibilityManager::Get()->IsAutoclickEnabled();
 }
 
+void SetAutoclickDelay(int delay_ms) {
+  return AccessibilityManager::Get()->SetAutoclickDelay(delay_ms);
+}
+
+int GetAutoclickDelay() {
+  return AccessibilityManager::Get()->GetAutoclickDelay();
+}
+
 Profile* GetProfile() {
   Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
   DCHECK(profile);
@@ -149,6 +197,10 @@
   GetPrefs()->SetBoolean(prefs::kAutoclickEnabled, enabled);
 }
 
+void SetAutoclickDelayPref(int delay_ms) {
+  GetPrefs()->SetInteger(prefs::kAutoclickDelayMs, delay_ms);
+}
+
 bool GetLargeCursorEnabledFromPref() {
   return GetPrefs()->GetBoolean(prefs::kLargeCursorEnabled);
 }
@@ -165,11 +217,15 @@
   return GetPrefs()->GetBoolean(prefs::kAutoclickEnabled);
 }
 
+int GetAutoclickDelayFromPref() {
+  return GetPrefs()->GetInteger(prefs::kAutoclickDelayMs);
+}
+
 }  // anonymouse namespace
 
 class AccessibilityManagerTest : public InProcessBrowserTest {
  protected:
-  AccessibilityManagerTest() {}
+  AccessibilityManagerTest() : default_autoclick_delay_(0) {}
   virtual ~AccessibilityManagerTest() {}
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -178,13 +234,28 @@
                                     TestingProfile::kTestUserProfileDir);
   }
 
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+    AccessibilityManager::SetBrailleControllerForTest(&braille_controller_);
+  }
+
   virtual void SetUpOnMainThread() OVERRIDE {
     // Sets the login-screen profile.
     AccessibilityManager::Get()->
         SetProfileForTest(ProfileHelper::GetSigninProfile());
+    default_autoclick_delay_ = GetAutoclickDelay();
   }
 
+  virtual void CleanUpOnMainThread() OVERRIDE {
+    AccessibilityManager::SetBrailleControllerForTest(NULL);
+  }
+
+  int default_autoclick_delay() const { return default_autoclick_delay_; }
+
+  int default_autoclick_delay_;
+
   content::NotificationRegistrar registrar_;
+
+  MockBrailleController braille_controller_;
   DISALLOW_COPY_AND_ASSIGN(AccessibilityManagerTest);
 };
 
@@ -194,6 +265,7 @@
   EXPECT_FALSE(IsSpokenFeedbackEnabled());
   EXPECT_FALSE(IsHighContrastEnabled());
   EXPECT_FALSE(IsAutoclickEnabled());
+  EXPECT_EQ(default_autoclick_delay(), GetAutoclickDelay());
 
   // Logs in.
   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
@@ -203,6 +275,7 @@
   EXPECT_FALSE(IsSpokenFeedbackEnabled());
   EXPECT_FALSE(IsHighContrastEnabled());
   EXPECT_FALSE(IsAutoclickEnabled());
+  EXPECT_EQ(default_autoclick_delay(), GetAutoclickDelay());
 
   UserManager::Get()->SessionStarted();
 
@@ -211,6 +284,7 @@
   EXPECT_FALSE(IsSpokenFeedbackEnabled());
   EXPECT_FALSE(IsHighContrastEnabled());
   EXPECT_FALSE(IsAutoclickEnabled());
+  EXPECT_EQ(default_autoclick_delay(), GetAutoclickDelay());
 
   // Enables large cursor.
   SetLargeCursorEnabled(true);
@@ -231,6 +305,22 @@
   SetAutoclickEnabled(true);
   // Confirms that autoclick is enabled.
   EXPECT_TRUE(IsAutoclickEnabled());
+
+  // Test that autoclick delay is set properly.
+  SetAutoclickDelay(kTestAutoclickDelayMs);
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityManagerTest, BrailleOnLoginScreen) {
+  EXPECT_FALSE(IsSpokenFeedbackEnabled());
+
+  // Signal the accessibility manager that a braille display was connected.
+  braille_controller_.SetAvailable(true);
+  braille_controller_.GetObserver()->OnDisplayStateChanged(
+      *braille_controller_.GetDisplayState());
+
+  // Confirms that the spoken feedback is enabled.
+  EXPECT_TRUE(IsSpokenFeedbackEnabled());
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityManagerTest, TypePref) {
@@ -243,6 +333,7 @@
   EXPECT_FALSE(IsSpokenFeedbackEnabled());
   EXPECT_FALSE(IsHighContrastEnabled());
   EXPECT_FALSE(IsAutoclickEnabled());
+  EXPECT_EQ(default_autoclick_delay(), GetAutoclickDelay());
 
   // Sets the pref as true to enable the large cursor.
   SetLargeCursorEnabledPref(true);
@@ -264,6 +355,11 @@
   // Confirms that autoclick is enabled.
   EXPECT_TRUE(IsAutoclickEnabled());
 
+  // Set autoclick delay pref.
+  SetAutoclickDelayPref(kTestAutoclickDelayMs);
+  // Confirm that the correct value is set.
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
+
   SetLargeCursorEnabledPref(false);
   EXPECT_FALSE(IsLargeCursorEnabled());
 
@@ -297,6 +393,11 @@
   SetAutoclickEnabledPref(true);
   EXPECT_FALSE(IsAutoclickEnabled());
 
+  // Sets the autoclick delay pref before login but the
+  // initial value should not change.
+  SetAutoclickDelayPref(kTestAutoclickDelayMs);
+  EXPECT_EQ(default_autoclick_delay(), GetAutoclickDelay());
+
   // Logs in.
   UserManager::Get()->SessionStarted();
 
@@ -305,6 +406,7 @@
   EXPECT_TRUE(IsSpokenFeedbackEnabled());
   EXPECT_TRUE(IsHighContrastEnabled());
   EXPECT_TRUE(IsAutoclickEnabled());
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityManagerTest,
@@ -426,6 +528,9 @@
   // Enables autoclick.
   SetAutoclickEnabled(true);
   EXPECT_TRUE(IsAutoclickEnabled());
+  // Set autoclick delay.
+  SetAutoclickDelay(kTestAutoclickDelayMs);
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
 
   // Logs in.
   const char* user_name = GetParam();
@@ -436,6 +541,7 @@
   EXPECT_TRUE(IsSpokenFeedbackEnabled());
   EXPECT_TRUE(IsHighContrastEnabled());
   EXPECT_TRUE(IsAutoclickEnabled());
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
 
   UserManager::Get()->SessionStarted();
 
@@ -444,12 +550,14 @@
   EXPECT_TRUE(IsSpokenFeedbackEnabled());
   EXPECT_TRUE(IsHighContrastEnabled());
   EXPECT_TRUE(IsAutoclickEnabled());
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelay());
 
   // Confirms that the prefs have been copied to the user's profile.
   EXPECT_TRUE(GetLargeCursorEnabledFromPref());
   EXPECT_TRUE(GetSpokenFeedbackEnabledFromPref());
   EXPECT_TRUE(GetHighContrastEnabledFromPref());
   EXPECT_TRUE(GetAutoclickEnabledFromPref());
+  EXPECT_EQ(kTestAutoclickDelayMs, GetAutoclickDelayFromPref());
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/app_session_lifetime.cc b/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
index 6209fdb..c67a577 100644
--- a/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
+++ b/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
 
+#include "apps/shell_window.h"
 #include "apps/shell_window_registry.h"
+#include "ash/wm/window_state.h"
 #include "base/basictypes.h"
 #include "base/lazy_instance.h"
 #include "base/prefs/pref_service.h"
@@ -21,12 +23,14 @@
 
 namespace {
 
-// AppWindowWatcher watches for app window and exits the session when the
-// last app window is closed.
-class AppWindowWatcher : public ShellWindowRegistry::Observer {
+// AppWindowHandler watches for app window and exits the session when the
+// last app window is closed. It also initializes the kiosk app window so
+// that it receives all function keys as a temp solution before underlying
+// http:://crbug.com/166928 is fixed..
+class AppWindowHandler : public ShellWindowRegistry::Observer {
  public:
-  AppWindowWatcher() : window_registry_(NULL) {}
-  virtual ~AppWindowWatcher() {}
+  AppWindowHandler() : window_registry_(NULL) {}
+  virtual ~AppWindowHandler() {}
 
   void Init(Profile* profile) {
     DCHECK(!window_registry_);
@@ -37,7 +41,13 @@
 
  private:
   // apps::ShellWindowRegistry::Observer overrides:
-  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {}
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
+    // Set flags to allow kiosk app to receive all function keys.
+    // TODO(xiyuan): Remove this after http:://crbug.com/166928.
+    ash::wm::WindowState* window_state =
+        ash::wm::GetWindowState(shell_window->GetNativeWindow());
+    window_state->set_top_row_keys_are_function_keys(true);
+  }
   virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window)
     OVERRIDE {}
   virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {
@@ -49,18 +59,18 @@
 
   apps::ShellWindowRegistry* window_registry_;
 
-  DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
+  DISALLOW_COPY_AND_ASSIGN(AppWindowHandler);
 };
 
-base::LazyInstance<AppWindowWatcher> app_window_watcher
+base::LazyInstance<AppWindowHandler> app_window_handler
     = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
 void InitAppSession(Profile* profile, const std::string& app_id) {
   // Binds the session lifetime with app window counts.
-  CHECK(app_window_watcher == NULL);
-  app_window_watcher.Get().Init(profile);
+  CHECK(app_window_handler == NULL);
+  app_window_handler.Get().Init(profile);
 
   // Set the app_id for the current instance of KioskAppUpdateService.
   KioskAppUpdateService* update_service =
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
index 25f45dd..63f10be 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -11,6 +11,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/extensions/webstore_data_fetcher.h"
 #include "chrome/browser/extensions/webstore_install_helper.h"
 #include "chrome/browser/image_decoder.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/manifest.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_launch_error.cc b/chrome/browser/chromeos/app_mode/kiosk_app_launch_error.cc
index 4e0c076..3e8d320 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_launch_error.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_launch_error.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index 1682079..71bfa83 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -12,6 +12,7 @@
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/sys_info.h"
 #include "chrome/browser/browser_process.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/owner_key_util.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/cryptohome/async_method_caller.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
index 6aa658b..b60215c 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
index e9a0384..f5a68dd 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
@@ -56,7 +56,7 @@
 void KioskAppUpdateService::ForceAppUpdateRestart() {
   // Force a chrome restart (not a logout or reboot) by closing all browsers.
   LOG(WARNING) << "Force closing all browsers to update kiosk app.";
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
 }
 
 void KioskAppUpdateService::Shutdown() {
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index da60c3c..6418cff 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -27,7 +27,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
@@ -281,20 +280,6 @@
 }
 
 void StartupAppLauncher::OnReadyToLaunch() {
-  // Defer app launch until system salt is loaded to make sure that identity
-  // api works with the enterprise kiosk app.
-  // TODO(xiyuan): Use async GetSystemSalt after merging to M31.
-  const std::string system_salt = SystemSaltGetter::Get()->GetSystemSaltSync();
-  if (system_salt.empty()) {
-    const int64 kRequestSystemSaltDelayMs = 500;
-    BrowserThread::PostDelayedTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&StartupAppLauncher::OnReadyToLaunch, AsWeakPtr()),
-        base::TimeDelta::FromMilliseconds(kRequestSystemSaltDelayMs));
-    return;
-  }
-
   ready_to_launch_ = true;
   FOR_EACH_OBSERVER(Observer, observer_list_, OnReadyToLaunch());
 }
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
new file mode 100644
index 0000000..3aa70b0
--- /dev/null
+++ b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
@@ -0,0 +1,122 @@
+// Copyright 2013 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/bind.h"
+#include "base/run_loop.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using chromeos::attestation::PlatformVerificationFlow;
+
+namespace policy {
+
+class CustomFakeCryptohomeClient : public chromeos::FakeCryptohomeClient {
+ public:
+  virtual void TpmAttestationIsEnrolled(
+      const chromeos::BoolDBusMethodCallback& callback) OVERRIDE {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, chromeos::DBUS_METHOD_CALL_FAILURE, false));
+  }
+};
+
+class AttestationDevicePolicyTest
+    : public DevicePolicyCrosBrowserTest,
+      public chromeos::DeviceSettingsService::Observer {
+ public:
+    // DeviceSettingsService::Observer
+    virtual void OwnershipStatusChanged() OVERRIDE {}
+    virtual void DeviceSettingsUpdated() OVERRIDE {
+      operation_complete_ = true;
+    }
+
+ protected:
+  AttestationDevicePolicyTest() : operation_complete_(false) {}
+
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
+    InstallOwnerKey();
+    RefreshDevicePolicy();
+  }
+
+  // Refreshes device policy and waits for it to be applied.
+  virtual void SyncRefreshDevicePolicy() {
+    chromeos::DeviceSettingsService::Get()->AddObserver(this);
+    RefreshDevicePolicy();
+    WaitForAsyncOperation();
+    chromeos::DeviceSettingsService::Get()->RemoveObserver(this);
+  }
+
+  enterprise_management::AttestationSettingsProto* GetDevicePolicyProto() {
+    return device_policy()->payload().mutable_attestation_settings();
+  }
+
+  // A callback for PlatformVerificationFlow::ChallengePlatformKey.
+  void Callback(PlatformVerificationFlow::Result result,
+                const std::string& signed_data,
+                const std::string& signature,
+                const std::string& platform_key_certificate) {
+    result_ = result;
+    operation_complete_ = true;
+  }
+
+  // Synchronously do what the content protection code path does when it wants
+  // to verify a Chrome OS platform.
+  PlatformVerificationFlow::Result SyncContentProtectionAttestation() {
+    PlatformVerificationFlow verifier(NULL, NULL, &fake_cryptohome_client_,
+                                      NULL, NULL);
+    verifier.ChallengePlatformKey(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "fake_service_id",
+      "fake_challenge",
+      base::Bind(&AttestationDevicePolicyTest::Callback, this));
+    WaitForAsyncOperation();
+    return result_;
+  }
+
+ private:
+  bool operation_complete_;
+  PlatformVerificationFlow::Result result_;
+  CustomFakeCryptohomeClient fake_cryptohome_client_;
+
+  void WaitForAsyncOperation() {
+    while (!operation_complete_) {
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+      base::RunLoop pump;
+      pump.RunUntilIdle();
+    }
+    // Reset for the next call.
+    operation_complete_ = false;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(AttestationDevicePolicyTest);
+};
+
+IN_PROC_BROWSER_TEST_F(AttestationDevicePolicyTest, ContentProtectionTest) {
+  EXPECT_NE(PlatformVerificationFlow::POLICY_REJECTED,
+            SyncContentProtectionAttestation());
+
+  GetDevicePolicyProto()->set_content_protection_enabled(false);
+  SyncRefreshDevicePolicy();
+
+  EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED,
+            SyncContentProtectionAttestation());
+
+  GetDevicePolicyProto()->set_content_protection_enabled(true);
+  SyncRefreshDevicePolicy();
+
+  EXPECT_NE(PlatformVerificationFlow::POLICY_REJECTED,
+            SyncContentProtectionAttestation());
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
index 0aae2da..24ad09c 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/singleton_tabs.h"
@@ -35,8 +36,12 @@
 void PlatformVerificationDialog::ShowDialog(
     content::WebContents* web_contents,
     const PlatformVerificationFlow::Delegate::ConsentCallback& callback) {
+  std::string origin = web_contents->GetLastCommittedURL().GetOrigin().spec();
+
   PlatformVerificationDialog* dialog = new PlatformVerificationDialog(
-      chrome::FindBrowserWithWebContents(web_contents), callback);
+      chrome::FindBrowserWithWebContents(web_contents),
+      UTF8ToUTF16(origin),
+      callback);
 
   // Sets up the dialog widget and shows it.
   web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager =
@@ -47,8 +52,6 @@
       dialog, web_contents->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(widget->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      widget->GetNativeView(), true);
   widget->Show();
 }
 
@@ -57,19 +60,21 @@
 
 PlatformVerificationDialog::PlatformVerificationDialog(
     Browser* browser,
+    const base::string16& domain,
     const PlatformVerificationFlow::Delegate::ConsentCallback& callback)
-    : callback_(callback),
-      browser_(browser) {
+    : browser_(browser),
+      domain_(domain),
+      callback_(callback) {
   SetLayoutManager(new views::FillLayout());
   set_border(views::Border::CreateEmptyBorder(
       0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
   const base::string16 learn_more = l10n_util::GetStringUTF16(IDS_LEARN_MORE);
-  size_t offset = 0;
+  std::vector<size_t> offsets;
   base::string16 headline = l10n_util::GetStringFUTF16(
-      IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE, learn_more, &offset);
+      IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE, domain_, learn_more, &offsets);
   views::StyledLabel* headline_label = new views::StyledLabel(headline, this);
   headline_label->AddStyleRange(
-      gfx::Range(offset, offset + learn_more.size()),
+      gfx::Range(offsets[1], offsets[1] + learn_more.size()),
       views::StyledLabel::RangeStyleInfo::CreateForLink());
   AddChildView(headline_label);
 }
@@ -86,19 +91,16 @@
 
 base::string16 PlatformVerificationDialog::GetDialogButtonLabel(
     ui::DialogButton button) const {
-  int message_id = -1;
   switch (button) {
     case ui::DIALOG_BUTTON_OK:
-      message_id = IDS_PLATFORM_VERIFICATION_DIALOG_ALLOW;
-      break;
+      return l10n_util::GetStringUTF16(IDS_PLATFORM_VERIFICATION_DIALOG_ALLOW);
     case ui::DIALOG_BUTTON_CANCEL:
-      message_id = IDS_PLATFORM_VERIFICATION_DIALOG_DENY;
-      break;
+      return l10n_util::GetStringFUTF16(
+          IDS_PLATFORM_VERIFICATION_DIALOG_DENY, domain_);
     default:
       NOTREACHED();
-      return base::string16();
   }
-  return l10n_util::GetStringUTF16(message_id);
+  return base::string16();
 }
 
 ui::ModalType PlatformVerificationDialog::GetModalType() const {
diff --git a/chrome/browser/chromeos/attestation/platform_verification_dialog.h b/chrome/browser/chromeos/attestation/platform_verification_dialog.h
index bff9474..cff19ae 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_dialog.h
+++ b/chrome/browser/chromeos/attestation/platform_verification_dialog.h
@@ -36,6 +36,7 @@
  private:
   PlatformVerificationDialog(
       Browser* browser,
+      const base::string16& domain,
       const PlatformVerificationFlow::Delegate::ConsentCallback& callback);
 
   // Overridden from views::DialogDelegate:
@@ -54,8 +55,9 @@
   virtual void StyledLabelLinkClicked(const gfx::Range& range,
                                       int event_flags) OVERRIDE;
 
-  PlatformVerificationFlow::Delegate::ConsentCallback callback_;
   Browser* browser_;
+  base::string16 domain_;
+  PlatformVerificationFlow::Delegate::ConsentCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformVerificationDialog);
 };
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
index d6ef3ac..cbbc50c 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
@@ -7,13 +7,13 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/attestation/attestation_flow.h"
diff --git a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
index a5d7182..46029ea 100644
--- a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
+++ b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
@@ -11,9 +11,9 @@
 #include "base/logging.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/audio/audio_device.h"
 
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index e5559b1..0ea6beb 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -644,8 +644,7 @@
   // adjusting the oom priority.
   g_browser_process->platform_part()->oom_priority_manager()->Start();
 
-  // Turn on natural scroll if we have a touch screen.
-  if (ui::IsTouchDevicePresent()) {
+  if (ui::ShouldDefaultToNaturalScroll()) {
     CommandLine::ForCurrentProcess()->AppendSwitch(
         chromeos::switches::kNaturalScrollDefault);
     ui::SetNaturalScroll(true);
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
index 3dbcae3..ea4546c 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
@@ -78,10 +78,7 @@
         content::BrowserThread::GetMessageLoopProxyForThread(
             content::BrowserThread::IO));
 
-    test_server_.reset(
-        new net::test_server::EmbeddedTestServer(
-            content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::IO)));
+    test_server_.reset(new net::test_server::EmbeddedTestServer);
     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
     test_server_->RegisterRequestHandler(
         base::Bind(&GDataContactsServiceTest::HandleDownloadRequest,
@@ -156,7 +153,6 @@
   // returns the content.
   scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest(
       const net::test_server::HttpRequest& request) {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     // Requested url must not contain a query string.
     scoped_ptr<net::test_server::BasicHttpResponse> result =
         google_apis::test_util::CreateHttpResponseFromFile(
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index 09d6c39..d455b37 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -11,6 +11,7 @@
 #include "ash/shell.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -18,7 +19,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/display/output_configurator.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index 82f5ce1..2f2629f 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -11,13 +11,13 @@
 #include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/display/display_configuration_observer.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/display/output_configurator.h"
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.cc b/chrome/browser/chromeos/display/overscan_calibrator.cc
index ed4adae..de8f190 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.cc
+++ b/chrome/browser/chromeos/display/overscan_calibrator.cc
@@ -73,7 +73,7 @@
   ash::internal::DisplayInfo info = ash::Shell::GetInstance()->
       display_manager()->GetDisplayInfo(display_.id());
 
-  aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()->
+  aura::Window* root = ash::Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display_.id());
   ui::Layer* parent_layer = ash::Shell::GetContainer(
       root, ash::internal::kShellWindowId_OverlayContainer)->layer();
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 9e4dbd1..9589f06 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -115,12 +115,15 @@
       file_util::FILE_PERMISSION_EXECUTE_BY_GROUP |
       file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS);
 
+  internal::ResourceMetadataStorage::UpgradeOldDB(
+      metadata_storage->directory_path(), id_canonicalizer);
+
   if (!metadata_storage->Initialize()) {
     LOG(WARNING) << "Failed to initialize the metadata storage.";
     return FILE_ERROR_FAILED;
   }
 
-  if (!cache->Initialize() || !cache->CanonicalizeIDs(id_canonicalizer)) {
+  if (!cache->Initialize()) {
     LOG(WARNING) << "Failed to initialize the cache.";
     return FILE_ERROR_FAILED;
   }
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index ca614c3..f19abd0 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -420,21 +420,6 @@
       base::Bind(&FileCache::DestroyOnBlockingPool, base::Unretained(this)));
 }
 
-bool FileCache::CanonicalizeIDs(
-    const ResourceIdCanonicalizer& id_canonicalizer) {
-  scoped_ptr<Iterator> it = GetIterator();
-  for (; !it->IsAtEnd(); it->Advance()) {
-    const std::string id_canonicalized = id_canonicalizer.Run(it->GetID());
-    if (id_canonicalized != it->GetID()) {
-      // Replace the existing entry.
-      if (!storage_->RemoveCacheEntry(it->GetID()) ||
-          !storage_->PutCacheEntry(id_canonicalized, it->GetValue()))
-        return false;
-    }
-  }
-  return !it->HasError();
-}
-
 void FileCache::DestroyOnBlockingPool() {
   AssertOnSequencedWorkerPool();
   delete this;
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index ba6aa1a..e6a752a 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -15,7 +15,6 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
-#include "chrome/browser/drive/drive_service_interface.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -156,10 +155,6 @@
   // Must be called on the UI thread.
   void Destroy();
 
-  // Converts entry IDs and cache file names to the desired format.
-  // TODO(hashimoto): Remove this method at some point.
-  bool CanonicalizeIDs(const ResourceIdCanonicalizer& id_canonicalizer);
-
  private:
   friend class FileCacheTest;
   friend class FileCacheTestOnUIThread;
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index d2c8810..b3fa3ed 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/md5.h"
 #include "base/run_loop.h"
-#include "base/strings/string_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
@@ -895,30 +894,6 @@
   EXPECT_EQ(src_contents, contents);
 }
 
-TEST_F(FileCacheTest, CanonicalizeIDs) {
-  ResourceIdCanonicalizer id_canonicalizer = base::Bind(
-      (ResourceIdCanonicalizer::RunType*)(&StringToUpperASCII));
-  const std::string id("abc");
-  const std::string md5("abcdef0123456789");
-
-  const base::FilePath file_directory =
-      temp_dir_.path().AppendASCII(kCacheFileDirectory);
-
-  // Store a file to the cache.
-  base::FilePath file;
-  EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(), &file));
-  EXPECT_EQ(FILE_ERROR_OK,
-            cache_->Store(id, md5, file, FileCache::FILE_OPERATION_COPY));
-
-  // Canonicalize IDs.
-  EXPECT_TRUE(cache_->CanonicalizeIDs(id_canonicalizer));
-
-  const std::string canonicalized_id = id_canonicalizer.Run(id);
-  FileCacheEntry entry;
-  EXPECT_FALSE(cache_->GetCacheEntry(id, &entry));
-  EXPECT_TRUE(cache_->GetCacheEntry(canonicalized_id, &entry));
-}
-
 TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) {
   const base::FilePath file_directory =
       temp_dir_.path().AppendASCII(kCacheFileDirectory);
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index 40acfd7..bb87873 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -198,7 +198,7 @@
   if (!url.is_valid() || url.scheme() != chrome::kDriveScheme)
     return base::FilePath();
   std::string path_string = net::UnescapeURLComponent(
-      url.path(), net::UnescapeRule::NORMAL);
+      url.GetContent(), net::UnescapeRule::NORMAL);
   return base::FilePath::FromUTF8Unsafe(path_string);
 }
 
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc
index b0e5f87..742bb48 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc
@@ -167,24 +167,22 @@
   if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_LOCAL_SPACE;
 
-  // Multiple entries with the same resource ID should not be present.
-  std::string existing_entry_id;
-  if (!entry.resource_id().empty() &&
-      GetIdByResourceId(entry.resource_id(),
-                        &existing_entry_id) == FILE_ERROR_OK)
-    return FILE_ERROR_EXISTS;
-
   ResourceEntry parent;
   if (!storage_->GetEntry(entry.parent_local_id(), &parent) ||
       !parent.file_info().is_directory())
     return FILE_ERROR_NOT_FOUND;
 
-  // Generate unique local ID.
+  // Multiple entries with the same resource ID should not be present.
   std::string local_id;
   ResourceEntry existing_entry;
-  do {
+  if (!entry.resource_id().empty() &&
+      storage_->GetIdByResourceId(entry.resource_id(), &local_id) &&
+      storage_->GetEntry(local_id, &existing_entry))
+    return FILE_ERROR_EXISTS;
+
+  // Generate unique local ID when needed.
+  while (local_id.empty() || storage_->GetEntry(local_id, &existing_entry))
     local_id = base::GenerateGUID();
-  } while (storage_->GetEntry(local_id, &existing_entry));
 
   ResourceEntry new_entry(entry);
   new_entry.set_local_id(local_id);
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index 948e737..f633096 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -9,6 +9,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
@@ -33,9 +34,14 @@
   DB_INIT_MAX_VALUE,
 };
 
+// The name of the DB which stores the metadata.
 const base::FilePath::CharType kResourceMapDBName[] =
     FILE_PATH_LITERAL("resource_metadata_resource_map.db");
 
+// The name of the DB which couldn't be opened, but is preserved just in case.
+const base::FilePath::CharType kPreservedResourceMapDBName[] =
+    FILE_PATH_LITERAL("resource_metadata_preserved_resource_map.db");
+
 // Meant to be a character which never happen to be in real IDs.
 const char kDBKeyDelimeter = '\0';
 
@@ -80,6 +86,15 @@
   return key_substring.compare(expected_suffix) == 0;
 }
 
+// Returns ID extracted from a cache entry key.
+std::string GetIdFromCacheEntryKey(const leveldb::Slice& key) {
+  DCHECK(IsCacheEntryKey(key));
+  // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
+  const size_t kSuffixLength = arraysize(kCacheEntryKeySuffix) - 1;
+  const int id_length = key.size() - 1 - kSuffixLength;
+  return std::string(key.data(), id_length);
+}
+
 // Returns a string to be used as a key for a resource-ID-to-local-ID entry.
 std::string GetIdEntryKey(const std::string& resource_id) {
   std::string key;
@@ -279,15 +294,96 @@
     // TODO(hashimoto): Broken entries should be cleaned up at some point.
     if (IsCacheEntryKey(it_->key()) &&
         entry_.ParseFromArray(it_->value().data(), it_->value().size())) {
-      // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
-      const size_t kSuffixLength = arraysize(kCacheEntryKeySuffix) - 1;
-      const int id_length = it_->key().size() - 1 - kSuffixLength;
-      id_.assign(it_->key().data(), id_length);
+      id_ = GetIdFromCacheEntryKey(it_->key());
       break;
     }
   }
 }
 
+// static
+bool ResourceMetadataStorage::UpgradeOldDB(
+    const base::FilePath& directory_path,
+    const ResourceIdCanonicalizer& id_canonicalizer) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  COMPILE_ASSERT(
+      kDBVersion == 11,
+      db_version_and_this_function_should_be_updated_at_the_same_time);
+
+  const base::FilePath resource_map_path =
+      directory_path.Append(kResourceMapDBName);
+  const base::FilePath preserved_resource_map_path =
+      directory_path.Append(kPreservedResourceMapDBName);
+
+  if (base::PathExists(preserved_resource_map_path)) {
+    // Preserved DB is found. The previous attempt to create a new DB should not
+    // be successful. Discard the imperfect new DB and restore the old DB.
+    if (!base::DeleteFile(resource_map_path, false /* recursive */) ||
+        !base::Move(preserved_resource_map_path, resource_map_path))
+      return false;
+  }
+
+  // Open DB.
+  leveldb::DB* db = NULL;
+  leveldb::Options options;
+  options.max_open_files = 0;  // Use minimum.
+  options.create_if_missing = false;
+  if (!leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db).ok())
+    return false;
+  scoped_ptr<leveldb::DB> resource_map(db);
+
+  // Check DB version.
+  std::string serialized_header;
+  ResourceMetadataHeader header;
+  if (!resource_map->Get(leveldb::ReadOptions(),
+                         leveldb::Slice(GetHeaderDBKey()),
+                         &serialized_header).ok() ||
+      !header.ParseFromString(serialized_header))
+    return false;
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Drive.MetadataDBVersionBeforeUpgradeCheck",
+                              header.version());
+
+  if (header.version() == kDBVersion) {  // Nothing to do.
+    return true;
+  } else if (header.version() < 6) {  // Too old, nothing can be done.
+    return false;
+  } else if (header.version() < 11) {  // Cache entries can be reused.
+    leveldb::ReadOptions options;
+    options.verify_checksums = true;
+    scoped_ptr<leveldb::Iterator> it(resource_map->NewIterator(options));
+
+    leveldb::WriteBatch batch;
+    for (it->SeekToFirst(); it->Valid(); it->Next()) {
+      if (IsCacheEntryKey(it->key())) {
+        // The resource ID might be in old WAPI format. We need to canonicalize
+        // to the format of API service currently in use.
+        const std::string& id = GetIdFromCacheEntryKey(it->key());
+        const std::string& id_new = id_canonicalizer.Run(id);
+        if (id != id_new) {
+          batch.Delete(it->key());
+          batch.Put(GetCacheEntryKey(id_new), it->value());
+        }
+        // Before v11, resource ID was directly used as local ID. Such entries
+        // can be migrated by adding an identity ID mapping.
+        batch.Put(GetIdEntryKey(id_new), id_new);
+      } else {  // Remove all entries except cache entries.
+        batch.Delete(it->key());
+      }
+    }
+    if (!it->status().ok())
+      return false;
+
+    // Put header with the latest version number.
+    std::string serialized_header;
+    if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
+      return false;
+    batch.Put(GetHeaderDBKey(), serialized_header);
+
+    return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
+  }
+  LOG(WARNING) << "Unexpected DB version: " << header.version();
+  return false;
+}
+
 ResourceMetadataStorage::ResourceMetadataStorage(
     const base::FilePath& directory_path,
     base::SequencedTaskRunner* blocking_task_runner)
@@ -310,6 +406,8 @@
 
   const base::FilePath resource_map_path =
       directory_path_.Append(kResourceMapDBName);
+  const base::FilePath preserved_resource_map_path =
+      directory_path_.Append(kPreservedResourceMapDBName);
 
   // Try to open the existing DB.
   leveldb::DB* db = NULL;
@@ -336,25 +434,6 @@
     bool should_discard_db = true;
     if (db_version != kDBVersion) {
       open_existing_result = DB_INIT_INCOMPATIBLE;
-
-      // We can reuse cache entries when appropriate.
-      if (6 <= db_version && db_version < kDBVersion) {
-        // Remove all entries except cache entries.
-        leveldb::ReadOptions options;
-        options.verify_checksums = true;
-        scoped_ptr<leveldb::Iterator> it(resource_map_->NewIterator(options));
-
-        leveldb::WriteBatch batch;
-        for (it->SeekToFirst(); it->Valid(); it->Next()) {
-          if (!IsCacheEntryKey(it->key()))
-            batch.Delete(it->key());
-        }
-
-        should_discard_db =
-            !it->status().ok() ||
-            !resource_map_->Write(leveldb::WriteOptions(), &batch).ok() ||
-            !PutHeader(GetDefaultHeaderEntry());
-      }
       LOG(INFO) << "Reject incompatible DB.";
     } else if (!CheckValidity()) {
       open_existing_result = DB_INIT_BROKEN;
@@ -380,20 +459,25 @@
 
   // Failed to open the existing DB, create new DB.
   if (!resource_map_) {
-    // Clean up the destination.
-    const bool kRecursive = true;
-    base::DeleteFile(resource_map_path, kRecursive);
+    // Move the existing DB to the preservation path. The moved old DB is
+    // deleted once the new DB creation succeeds, or is restored later in
+    // UpgradeOldDB() when the creation fails.
+    if (base::PathExists(resource_map_path) &&
+        base::DeleteFile(preserved_resource_map_path, true /* recursive */))
+      base::Move(resource_map_path, preserved_resource_map_path);
 
     // Create DB.
     options.max_open_files = 0;  // Use minimum.
     options.create_if_missing = true;
+    options.error_if_exists = true;
 
     status = leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
     if (status.ok()) {
       resource_map_.reset(db);
 
-      // Set up header.
-      if (!PutHeader(GetDefaultHeaderEntry())) {
+      if (!PutHeader(GetDefaultHeaderEntry()) ||  // Set up header.
+          !base::DeleteFile(preserved_resource_map_path,
+                            true /* recursive */)) {  // Remove the old DB.
         init_result = DB_INIT_FAILED;
         resource_map_.reset();
       }
@@ -731,13 +815,16 @@
     // Check if resource-ID-to-local-ID mapping is stored correctly.
     if (IsIdEntryKey(it->key())) {
       leveldb::Status status = resource_map_->Get(
-          options,
-          it->value(),
-          &serialized_entry);
-      if (!status.ok() ||
-          !entry.ParseFromString(serialized_entry) ||
-          entry.resource_id().empty() ||
-          leveldb::Slice(GetIdEntryKey(entry.resource_id())) != it->key()) {
+          options, it->value(), &serialized_entry);
+      // Resource-ID-to-local-ID mapping without entry for the local ID is ok.
+      if (status.IsNotFound())
+        continue;
+      // When the entry exists, its resource ID must be consistent.
+      const bool ok = status.ok() &&
+          entry.ParseFromString(serialized_entry) &&
+          !entry.resource_id().empty() &&
+          leveldb::Slice(GetIdEntryKey(entry.resource_id())) == it->key();
+      if (!ok) {
         DLOG(ERROR) << "Broken ID entry. status = " << status.ToString();
         return false;
       }
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.h b/chrome/browser/chromeos/drive/resource_metadata_storage.h
index 04a2224..b19d977 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/drive/drive_service_interface.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -104,6 +105,10 @@
     DISALLOW_COPY_AND_ASSIGN(CacheEntryIterator);
   };
 
+  // Returns true if the DB was successfully upgraded to the newest version.
+  static bool UpgradeOldDB(const base::FilePath& directory_path,
+                           const ResourceIdCanonicalizer& id_canonicalizer);
+
   ResourceMetadataStorage(const base::FilePath& directory_path,
                           base::SequencedTaskRunner* blocking_task_runner);
 
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index f4cbfb6..7d73eb5 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -10,9 +10,11 @@
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
 namespace drive {
 namespace internal {
@@ -39,6 +41,8 @@
     return storage_->CheckValidity();
   }
 
+  leveldb::DB* resource_map() { return storage_->resource_map_.get(); }
+
   // Puts a child entry.
   void PutChild(const std::string& parent_id,
                 const std::string& child_base_name,
@@ -358,30 +362,44 @@
   EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1));
 }
 
-TEST_F(ResourceMetadataStorageTest, IncompatibleDB_Old) {
+TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M29) {
   const int64 kLargestChangestamp = 1234567890;
-  const std::string key1 = "abcd";
 
-  // Put some data.
+  // Construct M29 version DB.
+  SetDBVersion(6);
   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
-  ResourceEntry entry;
-  entry.set_local_id(key1);
-  EXPECT_TRUE(storage_->PutEntry(entry));
-  EXPECT_TRUE(storage_->GetEntry(key1, &entry));
-  FileCacheEntry cache_entry;
-  EXPECT_TRUE(storage_->PutCacheEntry(key1, FileCacheEntry()));
-  EXPECT_TRUE(storage_->GetCacheEntry(key1, &cache_entry));
 
-  // Set older version and reopen DB.
-  SetDBVersion(ResourceMetadataStorage::kDBVersion - 1);
+  leveldb::WriteBatch batch;
+
+  // Put a file entry and its cache entry.
+  ResourceEntry entry;
+  std::string serialized_entry;
+  entry.set_resource_id("file:abcd");
+  EXPECT_TRUE(entry.SerializeToString(&serialized_entry));
+  batch.Put("file:abcd", serialized_entry);
+
+  FileCacheEntry cache_entry;
+  EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry));
+  batch.Put(std::string("file:abcd") + '\0' + "CACHE", serialized_entry);
+
+  EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok());
+
+  // Upgrade and reopen.
+  storage_.reset();
+  EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(
+      temp_dir_.path(), base::Bind(&util::CanonicalizeResourceId)));
   storage_.reset(new ResourceMetadataStorage(
       temp_dir_.path(), base::MessageLoopProxy::current().get()));
   ASSERT_TRUE(storage_->Initialize());
 
-  // Data is erased, except cache entries, because of the incompatible version.
+  // Resource-ID-to-local-ID mapping is added.
+  std::string id;
+  EXPECT_TRUE(storage_->GetIdByResourceId("abcd", &id));  // "file:" is dropped.
+
+  // Data is erased, except cache entries.
   EXPECT_EQ(0, storage_->GetLargestChangestamp());
-  EXPECT_FALSE(storage_->GetEntry(key1, &entry));
-  EXPECT_TRUE(storage_->GetCacheEntry(key1, &cache_entry));
+  EXPECT_FALSE(storage_->GetEntry(id, &entry));
+  EXPECT_TRUE(storage_->GetCacheEntry(id, &cache_entry));
 }
 
 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_Unknown) {
@@ -393,13 +411,14 @@
   ResourceEntry entry;
   entry.set_local_id(key1);
   EXPECT_TRUE(storage_->PutEntry(entry));
-  EXPECT_TRUE(storage_->GetEntry(key1, &entry));
   FileCacheEntry cache_entry;
-  EXPECT_TRUE(storage_->PutCacheEntry(key1, FileCacheEntry()));
-  EXPECT_TRUE(storage_->GetCacheEntry(key1, &cache_entry));
+  EXPECT_TRUE(storage_->PutCacheEntry(key1, cache_entry));
 
-  // Set newer version and reopen DB.
+  // Set newer version, upgrade and reopen DB.
   SetDBVersion(ResourceMetadataStorage::kDBVersion + 1);
+  storage_.reset();
+  EXPECT_FALSE(ResourceMetadataStorage::UpgradeOldDB(
+      temp_dir_.path(), base::Bind(&util::CanonicalizeResourceId)));
   storage_.reset(new ResourceMetadataStorage(
       temp_dir_.path(), base::MessageLoopProxy::current().get()));
   ASSERT_TRUE(storage_->Initialize());
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index 06843f7..c436f0a 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -9,7 +9,9 @@
 
 #include "base/bind.h"
 #include "base/i18n/string_search.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
@@ -204,12 +206,17 @@
   return FILE_ERROR_OK;
 }
 
+// Runs the SearchMetadataCallback and updates the histogram.
 void RunSearchMetadataCallback(const SearchMetadataCallback& callback,
+                               const base::TimeTicks& start_time,
                                scoped_ptr<MetadataSearchResultVector> results,
                                FileError error) {
   if (error != FILE_ERROR_OK)
     results.reset();
   callback.Run(error, results.Pass());
+
+  UMA_HISTOGRAM_TIMES("Drive.SearchMetadataTime",
+                      base::TimeTicks::Now() - start_time);
 }
 
 }  // namespace
@@ -225,6 +232,8 @@
   DCHECK_LE(0, at_most_num_matches);
   DCHECK(!callback.is_null());
 
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+
   scoped_ptr<MetadataSearchResultVector> results(
       new MetadataSearchResultVector);
   MetadataSearchResultVector* results_ptr = results.get();
@@ -238,6 +247,7 @@
                                               results_ptr),
                                    base::Bind(&RunSearchMetadataCallback,
                                               callback,
+                                              start_time,
                                               base::Passed(&results)));
 }
 
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index fd25e9c..edbc9a0 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -19,7 +19,50 @@
 
 // Apps/extensions explicitly whitelisted for use in device-local accounts.
 const char* kDeviceLocalAccountWhitelist[] = {
-  "bpmcpldpdmajfigpchkicefoigmkfalc",  // QuickOffice
+  // Public sessions in general:
+  "cbkkbcmdlboombapidmoeolnmdacpkch",  // Chrome RDP
+  "djflhoibgkdhkhhcedjiklpkjnoahfmg",  // User Agent Switcher
+  "iabmpiboiopbgfabjmgeedhcmjenhbla",  // VNC Viewer
+
+  // Retail mode:
+  "ehcabepphndocfmgbdkbjibfodelmpbb",  // Angry Birds
+  "kgimkbnclbekdkabkpjhpakhhalfanda",  // Bejeweled
+  "joodangkbfjnajiiifokapkpmhfnpleo",  // Calculator
+  "fpgfohogebplgnamlafljlcidjedbdeb",  // Calendar
+  "hfhhnacclhffhdffklopdkcgdhifgngh",  // Camera
+  "cdjikkcakjcdjemakobkmijmikhkegcj",  // Chrome Remote Desktop
+  "jkoildpomkimndcphjpffmephmcmkfhn",  // Chromebook Demo App
+  "ielkookhdphmgbipcfmafkaiagademfp",  // Custom bookmarks
+  "kogjlbfgggambihdjcpijgcbmenblimd",  // Custom bookmarks
+  "ogbkmlkceflgpilgbmbcfbifckpkfacf",  // Custom bookmarks
+  "pbbbjjecobhljkkcenlakfnkmkfkfamd",  // Custom bookmarks
+  "jkbfjmnjcdmhlfpephomoiipbhcoiffb",  // Custom bookmarks
+  "dgmblbpgafgcgpkoiilhjifindhinmai",  // Custom bookmarks
+  "iggnealjakkgfofealilhkkclnbnfnmo",  // Custom bookmarks
+  "lplkobnahgbopmpkdapaihnnojkphahc",  // Custom bookmarks
+  "lejnflfhjpcannpaghnahbedlabpmhoh",  // Custom bookmarks
+  "ebkhfdfghngbimnpgelagnfacdafhaba",  // Deezer
+  "npnjdccdffhdndcbeappiamcehbhjibf",  // Docs.app
+  "iddohohhpmajlkbejjjcfednjnhlnenk",  // Evernote
+  "bjdhhokmhgelphffoafoejjmlfblpdha",  // Gmail
+  "mdhnphfgagkpdhndljccoackjjhghlif",  // Google Drive
+  "fgjnkhlabjcaajddbaenilcmpcidahll",  // Google+
+  "cgmlfbhkckbedohgdepgbkflommbfkep",  // Hangouts.app
+  "edhhaiphkklkcfcbnlbpbiepchnkgkpn",  // Helper.extension
+  "diehajhcjifpahdplfdkhiboknagmfii",  // Kindle
+  "nhpmmldpbfjofkipjaieeomhnmcgihfm",  // Menu.app
+  "onbhgdmifjebcabplolilidlpgeknifi",  // Music.app
+  "kkkbcoabfhgekpnddfkaphobhinociem",  // Netflix
+  "adlphlfdhhjenpgimjochcpelbijkich",  // New York Times
+  "cgefhjmlaifaamhhoojmpcnihlbddeki",  // Pandora
+  "kpjjigggmcjinapdeipapdcnmnjealll",  // Pixlr
+  "aleodiobpjillgfjdkblghiiaegggmcm",  // Quickoffice
+  "nifkmgcdokhkjghdlgflonppnefddien",  // Sheets
+  "hdmobeajeoanbanmdlabnbnlopepchip",  // Slides
+  "dgohlccohkojjgkkfholmobjjoledflp",  // Spotify
+  "dhmdaeekeihmajjnmichlhiffffdbpde",  // Store.app
+  "jeabmjjifhfcejonjjhccaeigpnnjaak",  // TweetDeck
+  "pbdihpaifchmclcmkfdgffnnpfbobefh",  // YouTube
 };
 
 }  // namespace
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
index 00802bf..56e5168 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -18,7 +18,7 @@
 
 namespace {
 
-const char kWhitelistedId[] = "bpmcpldpdmajfigpchkicefoigmkfalc";
+const char kWhitelistedId[] = "cbkkbcmdlboombapidmoeolnmdacpkch";
 
 scoped_refptr<const extensions::Extension> CreateExtensionFromValues(
     const std::string& id,
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.cc b/chrome/browser/chromeos/extensions/echo_private_api.cc
index 74c183c..1765b6f 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.cc
+++ b/chrome/browser/chromeos/extensions/echo_private_api.cc
@@ -11,6 +11,7 @@
 #include "base/location.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/ui/echo_dialog_view.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/extensions/api/echo_private.h"
@@ -213,9 +213,8 @@
 }
 
 void EchoPrivateGetUserConsentFunction::OnMoreInfoLinkClicked() {
-  chrome::NavigateParams params(profile(),
-                                GURL(kMoreInfoLink),
-                                content::PAGE_TRANSITION_LINK);
+  chrome::NavigateParams params(
+      GetProfile(), GURL(kMoreInfoLink), content::PAGE_TRANSITION_LINK);
   // Open the link in a new window. The echo dialog is modal, so the current
   // window is useless until the dialog is closed.
   params.disposition = NEW_WINDOW;
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.h b/chrome/browser/chromeos/extensions/echo_private_api.h
index 78f8d6c..b22f586 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.h
+++ b/chrome/browser/chromeos/extensions/echo_private_api.h
@@ -7,7 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/chromeos/ui/echo_dialog_listener.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class PrefRegistrySimple;
 
@@ -24,7 +24,8 @@
 
 }  // namespace chromeos
 
-class EchoPrivateGetRegistrationCodeFunction : public SyncExtensionFunction {
+class EchoPrivateGetRegistrationCodeFunction
+    : public ChromeSyncExtensionFunction {
  public:
   EchoPrivateGetRegistrationCodeFunction();
 
@@ -38,7 +39,8 @@
                              ECHOPRIVATE_GETREGISTRATIONCODE)
 };
 
-class EchoPrivateGetOobeTimestampFunction : public AsyncExtensionFunction {
+class EchoPrivateGetOobeTimestampFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   EchoPrivateGetOobeTimestampFunction();
 
@@ -52,7 +54,7 @@
                              ECHOPRIVATE_GETOOBETIMESTAMP)
 };
 
-class EchoPrivateSetOfferInfoFunction : public SyncExtensionFunction {
+class EchoPrivateSetOfferInfoFunction : public ChromeSyncExtensionFunction {
  public:
   EchoPrivateSetOfferInfoFunction();
 
@@ -65,7 +67,7 @@
                              ECHOPRIVATE_SETOFFERINFO)
 };
 
-class EchoPrivateGetOfferInfoFunction : public SyncExtensionFunction {
+class EchoPrivateGetOfferInfoFunction : public ChromeSyncExtensionFunction {
  public:
   EchoPrivateGetOfferInfoFunction();
 
@@ -83,9 +85,8 @@
 // either asks user's consent to verify the device's eligibility for the offer,
 // or informs the user that the offers redeeming is disabled.
 // It returns whether the user consent was given.
-class EchoPrivateGetUserConsentFunction
-    : public AsyncExtensionFunction,
-      public chromeos::EchoDialogListener {
+class EchoPrivateGetUserConsentFunction : public ChromeAsyncExtensionFunction,
+                                          public chromeos::EchoDialogListener {
  public:
   // Type for the dialog shown callback used in tests.
   typedef base::Callback<void(chromeos::EchoDialogView* dialog)>
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc
index ec31cba..ffc3e93 100644
--- a/chrome/browser/chromeos/extensions/external_cache.cc
+++ b/chrome/browser/chromeos/extensions/external_cache.cc
@@ -199,9 +199,12 @@
                                                 std::string* version) {
   DictionaryValue* extension_dictionary = NULL;
   if (cached_extensions_->GetDictionary(id, &extension_dictionary)) {
-    return extension_dictionary->GetString(
-        extensions::ExternalProviderImpl::kExternalVersion,
-        version);
+    if (extension_dictionary->GetString(
+            extensions::ExternalProviderImpl::kExternalVersion, version)) {
+      return true;
+    }
+    *version = delegate_->GetInstalledExtensionVersion(id);
+    return !version->empty();
   }
   return false;
 }
@@ -422,10 +425,11 @@
       continue;
     }
 
+    bool keep_if_present =
+        entry->HasKey(extensions::ExternalProviderImpl::kKeepIfPresent);
     // Check for updates for all extensions configured except for extensions
     // marked as keep_if_present.
-    if (downloader_ &&
-        !entry->HasKey(extensions::ExternalProviderImpl::kKeepIfPresent)) {
+    if (downloader_ && !keep_if_present) {
       GURL update_url;
       std::string external_update_url;
       if (entry->GetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
@@ -440,12 +444,12 @@
 
     base::DictionaryValue* cached_entry = NULL;
     if (prefs->GetDictionary(it.key(), &cached_entry)) {
-      std::string crx_path;
-      if (!downloader_ ||
-          cached_entry->GetString(
-              extensions::ExternalProviderImpl::kExternalCrx, &crx_path) ||
-          cached_entry->HasKey(
-              extensions::ExternalProviderImpl::kKeepIfPresent)) {
+      bool has_external_crx = cached_entry->HasKey(
+          extensions::ExternalProviderImpl::kExternalCrx);
+      bool is_already_installed =
+          !delegate_->GetInstalledExtensionVersion(it.key()).empty();
+      if (!downloader_ || keep_if_present || has_external_crx ||
+          is_already_installed) {
         scoped_ptr<base::Value> value;
         prefs->Remove(it.key(), &value);
         cached_extensions_->Set(it.key(), value.release());
@@ -551,4 +555,9 @@
                                    callback);
 }
 
+std::string ExternalCache::Delegate::GetInstalledExtensionVersion(
+    const std::string& id) {
+  return std::string();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/external_cache.h b/chrome/browser/chromeos/extensions/external_cache.h
index c39b444..66c9eae 100644
--- a/chrome/browser/chromeos/extensions/external_cache.h
+++ b/chrome/browser/chromeos/extensions/external_cache.h
@@ -43,6 +43,11 @@
     // Caller owns |prefs|.
     virtual void OnExtensionListsUpdated(
         const base::DictionaryValue* prefs) = 0;
+
+    // Cache needs to provide already installed extensions otherwise they
+    // will be removed. Cache calls this function to get version of installed
+    // extension or empty string if not installed.
+    virtual std::string GetInstalledExtensionVersion(const std::string& id);
   };
 
   // The |request_context| is used for update checks. All file I/O is done via
diff --git a/chrome/browser/chromeos/extensions/external_cache_unittest.cc b/chrome/browser/chromeos/extensions/external_cache_unittest.cc
index d70e497..3067b6a 100644
--- a/chrome/browser/chromeos/extensions/external_cache_unittest.cc
+++ b/chrome/browser/chromeos/extensions/external_cache_unittest.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/chromeos/extensions/external_cache.h"
 
+#include <map>
 #include <set>
+#include <string>
 
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -77,6 +79,13 @@
     prefs_.reset(prefs->DeepCopy());
   }
 
+  virtual std::string GetInstalledExtensionVersion(
+      const std::string& id) OVERRIDE {
+    std::map<std::string, std::string>::iterator it =
+        installed_extensions_.find(id);
+    return it != installed_extensions_.end() ? it->second : std::string();
+  }
+
   base::FilePath CreateCacheDir(bool initialized) {
     EXPECT_TRUE(cache_dir_.CreateUniqueTempDir());
     if (initialized)
@@ -124,6 +133,11 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void AddInstalledExtension(const std::string& id,
+                             const std::string& version) {
+    installed_extensions_[id] = version;
+  }
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
 
@@ -136,6 +150,7 @@
   base::ScopedTempDir cache_dir_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<base::DictionaryValue> prefs_;
+  std::map<std::string, std::string> installed_extensions_;
 
   DISALLOW_COPY_AND_ASSIGN(ExternalCacheTest);
 };
@@ -147,13 +162,9 @@
 
   scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
   base::DictionaryValue* dict = CreateEntryWithUpdateUrl(true);
-  dict->SetBoolean(
-      extensions::ExternalProviderImpl::kRequirePermissionsConsent, true);
   prefs->Set(kTestExtensionId1, dict);
   CreateExtensionFile(cache_dir, kTestExtensionId1, "1");
   dict = CreateEntryWithUpdateUrl(true);
-  dict->SetBoolean(
-      extensions::ExternalProviderImpl::kRequirePermissionsConsent, true);
   prefs->Set(kTestExtensionId2, dict);
   prefs->Set(kTestExtensionId3, CreateEntryWithUpdateUrl(false));
   CreateExtensionFile(cache_dir, kTestExtensionId3, "3");
@@ -178,11 +189,6 @@
   EXPECT_TRUE(entry1->GetBoolean(
       extensions::ExternalProviderImpl::kIsFromWebstore, &from_webstore));
   EXPECT_TRUE(from_webstore);
-  bool require_permissions_consent = false;
-  EXPECT_TRUE(entry1->GetBoolean(
-      extensions::ExternalProviderImpl::kRequirePermissionsConsent,
-      &require_permissions_consent));
-  EXPECT_TRUE(require_permissions_consent);
 
   // File in cache not from Webstore.
   const base::DictionaryValue* entry3 = NULL;
@@ -222,11 +228,6 @@
   EXPECT_TRUE(entry2->GetBoolean(
       extensions::ExternalProviderImpl::kIsFromWebstore, &from_webstore));
   EXPECT_TRUE(from_webstore);
-  require_permissions_consent = false;
-  EXPECT_TRUE(entry2->GetBoolean(
-      extensions::ExternalProviderImpl::kRequirePermissionsConsent,
-      &require_permissions_consent));
-  EXPECT_TRUE(require_permissions_consent);
   EXPECT_TRUE(base::PathExists(
       GetExtensionFile(cache_dir, kTestExtensionId2, "2")));
 
@@ -281,4 +282,32 @@
       GetExtensionFile(cache_dir, kTestExtensionId4, "4")));
 }
 
+TEST_F(ExternalCacheTest, PreserveInstalled) {
+  base::FilePath cache_dir(CreateCacheDir(false));
+  ExternalCache external_cache(cache_dir, request_context_getter(),
+      background_task_runner(), this, true, false);
+
+  scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
+  prefs->Set(kTestExtensionId1, CreateEntryWithUpdateUrl(true));
+  prefs->Set(kTestExtensionId2, CreateEntryWithUpdateUrl(true));
+
+  AddInstalledExtension(kTestExtensionId1, "1");
+
+  external_cache.UpdateExtensionsList(prefs.Pass());
+  WaitForCompletion();
+
+  ASSERT_TRUE(provided_prefs());
+  EXPECT_EQ(provided_prefs()->size(), 1ul);
+
+  // File not in cache but extension installed.
+  const base::DictionaryValue* entry1 = NULL;
+  ASSERT_TRUE(provided_prefs()->GetDictionary(kTestExtensionId1, &entry1));
+  EXPECT_TRUE(entry1->HasKey(
+      extensions::ExternalProviderImpl::kExternalUpdateUrl));
+  EXPECT_FALSE(entry1->HasKey(
+      extensions::ExternalProviderImpl::kExternalCrx));
+  EXPECT_FALSE(entry1->HasKey(
+      extensions::ExternalProviderImpl::kExternalVersion));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc
index dd89fb7..1e27680 100644
--- a/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc
+++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc
@@ -4,16 +4,22 @@
 
 #include "chrome/browser/chromeos/extensions/external_pref_cache_loader.h"
 
+#include <map>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
-#include "base/observer_list.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/values.h"
+#include "base/version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/extensions/external_cache.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace chromeos {
@@ -36,8 +42,30 @@
   virtual void OnExtensionListsUpdated(
       const base::DictionaryValue* prefs) OVERRIDE {
     is_extensions_list_ready_ = true;
-    FOR_EACH_OBSERVER(ExternalPrefCacheLoader, pref_loaders_,
-                      OnExtensionListsUpdated(prefs));
+    for (LoadersMap::iterator it = pref_loaders_.begin();
+         it != pref_loaders_.end(); ++it) {
+      it->first->OnExtensionListsUpdated(prefs);
+    }
+  }
+
+  virtual std::string GetInstalledExtensionVersion(
+      const std::string& id) OVERRIDE {
+    // Return lowest installed version. Updater will download an update if
+    // CWS has higher version. Version returned here matters only if file is
+    // missing in .crx cache.
+    base::Version version;
+    for (LoadersMap::iterator it = pref_loaders_.begin();
+         it != pref_loaders_.end(); ++it) {
+      ExtensionServiceInterface* extension_service =
+          extensions::ExtensionSystem::Get(it->second)->extension_service();
+      const extensions::Extension* extension = extension_service ?
+          extension_service->GetExtensionById(id, true) : NULL;
+      if (extension) {
+        if (!version.IsValid() || extension->version()->CompareTo(version) < 0)
+          version = *extension->version();
+      }
+    }
+    return version.IsValid() ? version.GetString() : std::string();
   }
 
   void UpdateExtensionsList(scoped_ptr<base::DictionaryValue> prefs) {
@@ -48,8 +76,9 @@
   // Return false if cache doesn't have list of extensions and it needs to
   // be provided via UpdateExtensionsList.
   bool RegisterExternalPrefCacheLoader(ExternalPrefCacheLoader* observer,
-                                       int base_path_id) {
-    pref_loaders_.AddObserver(observer);
+                                       int base_path_id,
+                                       Profile* profile) {
+    pref_loaders_.insert(std::make_pair(observer, profile));
 
     if (base_path_id_ == 0) {
       // First ExternalPrefCacheLoader is registered.
@@ -67,12 +96,14 @@
   }
 
   void UnregisterExternalPrefCacheLoader(ExternalPrefCacheLoader* observer) {
-    pref_loaders_.RemoveObserver(observer);
+    pref_loaders_.erase(observer);
   }
 
  private:
   friend struct DefaultSingletonTraits<ExternalCacheDispatcher>;
 
+  typedef std::map<ExternalPrefCacheLoader*, Profile*> LoadersMap;
+
   ExternalCacheDispatcher()
     : external_cache_(base::FilePath(kPreinstalledAppsCacheDir),
                       g_browser_process->system_request_context(),
@@ -89,7 +120,7 @@
   }
 
   ExternalCache external_cache_;
-  ObserverList<ExternalPrefCacheLoader> pref_loaders_;
+  LoadersMap pref_loaders_;
   int base_path_id_;
   bool is_extensions_list_ready_;
 
@@ -98,8 +129,10 @@
 
 }  // namespace
 
-ExternalPrefCacheLoader::ExternalPrefCacheLoader(int base_path_id)
-  : ExternalPrefLoader(base_path_id, ExternalPrefLoader::NONE) {
+ExternalPrefCacheLoader::ExternalPrefCacheLoader(int base_path_id,
+                                                 Profile* profile)
+  : ExternalPrefLoader(base_path_id, ExternalPrefLoader::NONE),
+    profile_(profile) {
 }
 
 ExternalPrefCacheLoader::~ExternalPrefCacheLoader() {
@@ -115,7 +148,7 @@
 
 void ExternalPrefCacheLoader::StartLoading() {
   if (!ExternalCacheDispatcher::GetInstance()->RegisterExternalPrefCacheLoader(
-          this, base_path_id_)) {
+          this, base_path_id_, profile_)) {
     // ExternalCacheDispatcher doesn't know list of extensions load it.
     ExternalPrefLoader::StartLoading();
   }
diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.h b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
index e448182..a020a03 100644
--- a/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
+++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
@@ -7,6 +7,8 @@
 
 #include "chrome/browser/extensions/external_pref_loader.h"
 
+class Profile;
+
 namespace chromeos {
 
 // A specialization of the ExternalPrefLoader that caches crx files for external
@@ -15,8 +17,9 @@
  public:
   // All instances of ExternalPrefCacheLoader use the same cache so
   // |base_path_id| must be the same for all profile in session.
-  // It is checked in run-time with CHECK.
-  explicit ExternalPrefCacheLoader(int base_path_id);
+  // It is checked in run-time with CHECK. |profile| is used to check if the
+  // extension is installed to keep providing.
+  ExternalPrefCacheLoader(int base_path_id, Profile* profile);
 
   void OnExtensionListsUpdated(const base::DictionaryValue* prefs);
 
@@ -28,6 +31,8 @@
   virtual void StartLoading() OVERRIDE;
   virtual void LoadFinished() OVERRIDE;
 
+  Profile* profile_;
+
   DISALLOW_COPY_AND_ASSIGN(ExternalPrefCacheLoader);
 };
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
index 3c1d392..f83b1e9 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
@@ -332,7 +332,7 @@
 void FileBrowserHandlerInternalSelectFileFunction::GrantPermissions() {
   fileapi::ExternalFileSystemBackend* external_backend =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile_, render_view_host())->external_backend();
+          GetProfile(), render_view_host())->external_backend();
   DCHECK(external_backend);
 
   external_backend->GetVirtualPath(full_path_, &virtual_path_);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.h b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.h
index eb1588b..6c67de0 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.h
@@ -16,7 +16,7 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class Browser;
 class FileBrowserHandlerInternalSelectFileFunction;
@@ -76,7 +76,7 @@
 // The fileBrowserHandlerInternal.selectFile extension function implementation.
 // See the file description for more info.
 class FileBrowserHandlerInternalSelectFileFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   // Default constructor used in production code.
   // It will create its own FileSelectorFactory implementation, and set the
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_base.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_base.cc
index 1ed47c8..808985d 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_base.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_base.cc
@@ -40,7 +40,7 @@
         base::Int64ToString(elapsed).c_str());
   }
 
-  AsyncExtensionFunction::SendResponse(success);
+  ChromeAsyncExtensionFunction::SendResponse(success);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_base.h b/chrome/browser/chromeos/extensions/file_manager/private_api_base.h
index 308713b..621e121 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_base.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_base.h
@@ -8,7 +8,7 @@
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_BASE_H_
 
 #include "base/time/time.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
@@ -20,7 +20,7 @@
 // set_log_on_completion(true) to enable it, if they want. However, even if
 // the logging is turned off, a warning is emitted when a function call is
 // very slow. See the implementation of SendResponse() for details.
-class LoggedAsyncExtensionFunction : public AsyncExtensionFunction {
+class LoggedAsyncExtensionFunction : public ChromeAsyncExtensionFunction {
  public:
   LoggedAsyncExtensionFunction();
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
index 07a36ab..b01cc0b 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
@@ -14,9 +14,21 @@
 
 namespace extensions {
 
+namespace {
+
+// Computes the routing ID for SelectFileDialogExtension from the |dispatcher|.
+SelectFileDialogExtension::RoutingID GetFileDialogRoutingID(
+    ExtensionFunctionDispatcher* dispatcher) {
+  return SelectFileDialogExtension::GetRoutingIDFromWebContents(
+      file_manager::util::GetWebContents(dispatcher));
+}
+
+}  // namespace
+
 bool FileBrowserPrivateCancelDialogFunction::RunImpl() {
-  const int32 tab_id = file_manager::util::GetTabId(dispatcher());
-  SelectFileDialogExtension::OnFileSelectionCanceled(tab_id);
+  const SelectFileDialogExtension::RoutingID routing_id =
+      GetFileDialogRoutingID(dispatcher());
+  SelectFileDialogExtension::OnFileSelectionCanceled(routing_id);
   SendResponse(true);
   return true;
 }
@@ -39,13 +51,13 @@
 
   file_manager::util::GetSelectedFileInfo(
       render_view_host(),
-      profile(),
+      GetProfile(),
       file_paths,
       option,
-      base::Bind(&FileBrowserPrivateSelectFileFunction::
-                     GetSelectedFileInfoResponse,
-                 this,
-                 params->index));
+      base::Bind(
+          &FileBrowserPrivateSelectFileFunction::GetSelectedFileInfoResponse,
+          this,
+          params->index));
   return true;
 }
 
@@ -57,8 +69,9 @@
     SendResponse(false);
     return;
   }
-  const int32 tab_id = file_manager::util::GetTabId(dispatcher());
-  SelectFileDialogExtension::OnFileSelected(tab_id, files[0], index);
+  const SelectFileDialogExtension::RoutingID routing_id =
+      GetFileDialogRoutingID(dispatcher());
+  SelectFileDialogExtension::OnFileSelected(routing_id, files[0], index);
   SendResponse(true);
 }
 
@@ -76,21 +89,23 @@
 
   file_manager::util::GetSelectedFileInfo(
       render_view_host(),
-      profile(),
+      GetProfile(),
       file_urls,
       params->should_return_local_path ?
           file_manager::util::NEED_LOCAL_PATH_FOR_OPENING :
           file_manager::util::NO_LOCAL_PATH_RESOLUTION,
-      base::Bind(&FileBrowserPrivateSelectFilesFunction::
-                     GetSelectedFileInfoResponse, this));
+      base::Bind(
+          &FileBrowserPrivateSelectFilesFunction::GetSelectedFileInfoResponse,
+          this));
   return true;
 }
 
 void FileBrowserPrivateSelectFilesFunction::GetSelectedFileInfoResponse(
     const std::vector<ui::SelectedFileInfo>& files) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  const int32 tab_id = file_manager::util::GetTabId(dispatcher());
-  SelectFileDialogExtension::OnMultiFilesSelected(tab_id, files);
+  const SelectFileDialogExtension::RoutingID routing_id =
+      GetFileDialogRoutingID(dispatcher());
+  SelectFileDialogExtension::OnMultiFilesSelected(routing_id, files);
   SendResponse(true);
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
index 342b815..6439a41 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -96,16 +96,16 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   const GURL file_url = GURL(params->file_url);
-  file_path_ = drive::util::ExtractDrivePath(
-      file_manager::util::GetLocalPathFromURL(
-          render_view_host(), profile(), file_url));
+  file_path_ =
+      drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
+          render_view_host(), GetProfile(), file_url));
 
   properties_.reset(new extensions::api::file_browser_private::
                     DriveEntryProperties);
 
   // Start getting the file info.
   drive::FileSystemInterface* file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system) {
     // |file_system| is NULL if Drive is disabled or not mounted.
     CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
@@ -133,9 +133,9 @@
   FillDriveEntryPropertiesValue(*entry, properties_.get());
 
   drive::FileSystemInterface* file_system =
-      drive::util::GetFileSystemByProfile(profile_);
+      drive::util::GetFileSystemByProfile(GetProfile());
   drive::DriveAppRegistry* app_registry =
-      drive::util::GetDriveAppRegistryByProfile(profile_);
+      drive::util::GetDriveAppRegistryByProfile(GetProfile());
   if (!file_system || !app_registry) {
     // |file_system| or |app_registry| is NULL if Drive is disabled.
     CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
@@ -161,7 +161,7 @@
   if (!drive_apps.empty()) {
     std::string default_task_id =
         file_manager::file_tasks::GetDefaultTaskIdFromPrefs(
-            *profile_->GetPrefs(),
+            *GetProfile()->GetPrefs(),
             file_specific_info.content_mime_type(),
             file_path_.Extension());
     file_manager::file_tasks::TaskDescriptor default_task;
@@ -211,13 +211,13 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   drive::FileSystemInterface* const file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system)  // |file_system| is NULL if Drive is disabled.
     return false;
 
   const base::FilePath drive_path =
       drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
-          render_view_host(), profile(), GURL(params->file_url)));
+          render_view_host(), GetProfile(), GURL(params->file_url)));
   if (params->pin) {
     file_system->Pin(drive_path,
                      base::Bind(&FileBrowserPrivatePinDriveFileFunction::
@@ -258,7 +258,7 @@
   // Convert the list of strings to a list of GURLs.
   for (size_t i = 0; i < params->file_urls.size(); ++i) {
     const base::FilePath path = file_manager::util::GetLocalPathFromURL(
-        render_view_host(), profile(), GURL(params->file_urls[i]));
+        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
     DCHECK(drive::util::IsUnderDriveMountPoint(path));
     base::FilePath drive_path = drive::util::ExtractDrivePath(path);
     remaining_drive_paths_.push(drive_path);
@@ -281,7 +281,7 @@
   base::FilePath drive_path = remaining_drive_paths_.front();
 
   drive::FileSystemInterface* file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system) {
     // |file_system| is NULL if Drive is disabled or not mounted.
     OnFileReady(drive::FILE_ERROR_FAILED, drive_path,
@@ -328,7 +328,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(profile_);
+      drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
   if (!integration_service || !integration_service->IsMounted())
     return false;
 
@@ -349,7 +349,7 @@
                          FileTransferCancelStatus> > responses;
   for (size_t i = 0; i < params->file_urls.size(); ++i) {
     base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
-        render_view_host(), profile(), GURL(params->file_urls[i]));
+        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
     if (file_path.empty())
       continue;
 
@@ -382,7 +382,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   drive::FileSystemInterface* const file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system) {
     // |file_system| is NULL if Drive is disabled.
     return false;
@@ -442,7 +442,7 @@
   set_log_on_completion(true);
 
   drive::FileSystemInterface* const file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system) {
     // |file_system| is NULL if Drive is disabled.
     return false;
@@ -517,7 +517,7 @@
 
 bool FileBrowserPrivateClearDriveCacheFunction::RunImpl() {
   drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(profile_);
+      drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
   if (!integration_service || !integration_service->IsMounted())
     return false;
 
@@ -532,7 +532,7 @@
 
 bool FileBrowserPrivateGetDriveConnectionStateFunction::RunImpl() {
   drive::DriveServiceInterface* const drive_service =
-      drive::util::GetDriveServiceByProfile(profile());
+      drive::util::GetDriveServiceByProfile(GetProfile());
 
   api::file_browser_private::GetDriveConnectionState::Results::Result result;
 
@@ -551,7 +551,8 @@
       result.reasons.push_back(kDriveConnectionReasonNoService);
   } else if (
       is_connection_cellular &&
-      profile_->GetPrefs()->GetBoolean(prefs::kDisableDriveOverCellular)) {
+      GetProfile()->GetPrefs()->GetBoolean(
+        prefs::kDisableDriveOverCellular)) {
     result.type = kDriveConnectionTypeMetered;
   } else {
     result.type = kDriveConnectionTypeOnline;
@@ -570,7 +571,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   drive::DriveServiceInterface* const drive_service =
-      drive::util::GetDriveServiceByProfile(profile());
+      drive::util::GetDriveServiceByProfile(GetProfile());
 
   if (!drive_service) {
     // DriveService is not available.
@@ -604,13 +605,13 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   const base::FilePath path = file_manager::util::GetLocalPathFromURL(
-      render_view_host(), profile(), GURL(params->url));
+      render_view_host(), GetProfile(), GURL(params->url));
   DCHECK(drive::util::IsUnderDriveMountPoint(path));
 
   const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
 
   drive::FileSystemInterface* const file_system =
-      drive::util::GetFileSystemByProfile(profile());
+      drive::util::GetFileSystemByProfile(GetProfile());
   if (!file_system) {
     // |file_system| is NULL if Drive is disabled.
     return false;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.h b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.h
index 2156e53..e119405 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.h
@@ -176,7 +176,7 @@
 
 // Implements the chrome.fileBrowserPrivate.getDriveConnectionState method.
 class FileBrowserPrivateGetDriveConnectionStateFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION(
       "fileBrowserPrivate.getDriveConnectionState",
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index 4f4858a..5c30cbc 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -352,7 +352,7 @@
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   // Set up file permission access.
   const int child_id = render_view_host()->GetProcess()->GetID();
@@ -370,7 +370,8 @@
   // Note that we call this function even when Drive is disabled by the
   // setting. Otherwise, we need to call this when the setting is changed at
   // a later time, which complicates the code.
-  SetDriveMountPointPermissions(profile_, extension_id(), render_view_host());
+  SetDriveMountPointPermissions(
+      GetProfile(), extension_id(), render_view_host());
 
   fileapi::FileSystemInfo info =
       fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin());
@@ -404,7 +405,7 @@
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url));
   base::FilePath local_path = file_watch_url.path();
@@ -425,7 +426,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   file_manager::EventRouter* event_router =
-      file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router();
+      file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
   event_router->AddFileWatch(
       local_path,
       virtual_path,
@@ -440,7 +441,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   file_manager::EventRouter* event_router =
-      file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router();
+      file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
   event_router->RemoveFileWatch(local_path, extension_id);
   Respond(true);
 }
@@ -451,13 +452,13 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
-      render_view_host(), profile(), GURL(params->mount_path));
+      render_view_host(), GetProfile(), GURL(params->mount_path));
   if (file_path.empty())
     return false;
 
   if (file_path == drive::util::GetDriveMountPointPath()) {
     drive::FileSystemInterface* file_system =
-        drive::util::GetFileSystemByProfile(profile());
+        drive::util::GetFileSystemByProfile(GetProfile());
     if (!file_system) {
       // |file_system| is NULL if Drive is disabled.
       // If stats couldn't be gotten for drive, result should be left
@@ -522,7 +523,7 @@
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   fileapi::FileSystemURL filesystem_url(
       file_system_context->CrackURL(GURL(params->parent_directory_url)));
@@ -560,7 +561,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
-      render_view_host(), profile(), GURL(params->mount_path));
+      render_view_host(), GetProfile(), GURL(params->mount_path));
   if (file_path.empty())
     return false;
 
@@ -585,7 +586,7 @@
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   fileapi::FileSystemURL source_url(
       file_system_context->CrackURL(GURL(params->source_url)));
@@ -602,7 +603,10 @@
       BrowserThread::IO,
       FROM_HERE,
       base::Bind(&StartCopyOnIOThread,
-                 profile(), file_system_context, source_url, destination_url),
+                 GetProfile(),
+                 file_system_context,
+                 source_url,
+                 destination_url),
       base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy,
                  this));
 }
@@ -624,7 +628,7 @@
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   // We don't much take care about the result of cancellation.
   BrowserThread::PostTask(
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 45c50e1..141721f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -38,9 +38,9 @@
 
 bool FileBrowserPrivateGetPreferencesFunction::RunImpl() {
   api::file_browser_private::GetPreferences::Results::Result result;
-  const PrefService* const service = profile_->GetPrefs();
+  const PrefService* const service = GetProfile()->GetPrefs();
 
-  result.drive_enabled = drive::util::IsDriveEnabledForProfile(profile_);
+  result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile());
   result.cellular_disabled =
       service->GetBoolean(prefs::kDisableDriveOverCellular);
   result.hosted_files_disabled =
@@ -64,7 +64,7 @@
   const scoped_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  PrefService* const service = profile_->GetPrefs();
+  PrefService* const service = GetProfile()->GetPrefs();
 
   if (params->change_info.cellular_disabled)
     service->SetBoolean(prefs::kDisableDriveOverCellular,
@@ -94,7 +94,7 @@
     return false;
 
   base::FilePath src_dir = file_manager::util::GetLocalPathFromURL(
-      render_view_host(), profile(), GURL(params->dir_url));
+      render_view_host(), GetProfile(), GURL(params->dir_url));
   if (src_dir.empty())
     return false;
 
@@ -105,7 +105,7 @@
   std::vector<base::FilePath> files;
   for (size_t i = 0; i < params->selection_urls.size(); ++i) {
     base::FilePath path = file_manager::util::GetLocalPathFromURL(
-        render_view_host(), profile(), GURL(params->selection_urls[i]));
+        render_view_host(), GetProfile(), GURL(params->selection_urls[i]));
     if (path.empty())
       return false;
     files.push_back(path);
@@ -192,7 +192,7 @@
       new file_manager::FileManagerInstaller(
           GetAssociatedWebContents(),  // web_contents(),
           params->item_id,
-          profile(),
+          GetProfile(),
           callback));
   // installer will be AddRef()'d in BeginInstall().
   installer->BeginInstall();
@@ -230,7 +230,7 @@
   scopes.push_back(kCWSScope);
 
   ProfileOAuth2TokenService* oauth_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   net::URLRequestContextGetter* url_request_context_getter =
       g_browser_process->system_request_context();
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index dda98b3..a584273 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -19,7 +19,8 @@
 namespace extensions {
 
 // Implements the chrome.fileBrowserPrivate.logoutUser method.
-class FileBrowserPrivateLogoutUserFunction : public SyncExtensionFunction {
+class FileBrowserPrivateLogoutUserFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.logoutUser",
                              FILEBROWSERPRIVATE_LOGOUTUSER)
@@ -33,7 +34,8 @@
 
 // Implements the chrome.fileBrowserPrivate.getPreferences method.
 // Gets settings for Files.app.
-class FileBrowserPrivateGetPreferencesFunction : public SyncExtensionFunction {
+class FileBrowserPrivateGetPreferencesFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.getPreferences",
                              FILEBROWSERPRIVATE_GETPREFERENCES)
@@ -46,7 +48,8 @@
 
 // Implements the chrome.fileBrowserPrivate.setPreferences method.
 // Sets settings for Files.app.
-class FileBrowserPrivateSetPreferencesFunction : public SyncExtensionFunction {
+class FileBrowserPrivateSetPreferencesFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.setPreferences",
                              FILEBROWSERPRIVATE_SETPREFERENCES)
@@ -85,7 +88,7 @@
 // Changes the zoom level of the file manager by internally calling
 // RenderViewHost::Zoom(). TODO(hirono): Remove this function once the zoom
 // level change is supported for all apps. crbug.com/227175.
-class FileBrowserPrivateZoomFunction : public SyncExtensionFunction {
+class FileBrowserPrivateZoomFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.zoom",
                              FILEBROWSERPRIVATE_ZOOM);
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
index 5e9c094..63cb6a8 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -39,7 +39,7 @@
   set_log_on_completion(true);
 
   const base::FilePath path = file_manager::util::GetLocalPathFromURL(
-      render_view_host(), profile(), GURL(params->source));
+      render_view_host(), GetProfile(), GURL(params->source));
 
   if (path.empty())
     return false;
@@ -47,7 +47,7 @@
   // Check if the source path is under Drive cache directory.
   if (drive::util::IsUnderDriveMountPoint(path)) {
     drive::FileSystemInterface* file_system =
-        drive::util::GetFileSystemByProfile(profile());
+        drive::util::GetFileSystemByProfile(GetProfile());
     if (!file_system)
       return false;
 
@@ -103,11 +103,12 @@
   file_paths.push_back(GURL(params->mount_path));
   file_manager::util::GetSelectedFileInfo(
       render_view_host(),
-      profile(),
+      GetProfile(),
       file_paths,
       file_manager::util::NEED_LOCAL_PATH_FOR_OPENING,
-      base::Bind(&FileBrowserPrivateRemoveMountFunction::
-                     GetSelectedFileInfoResponse, this));
+      base::Bind(
+          &FileBrowserPrivateRemoveMountFunction::GetSelectedFileInfoResponse,
+          this));
   return true;
 }
 
@@ -135,7 +136,7 @@
     return false;
 
   const std::vector<file_manager::VolumeInfo>& volume_info_list =
-      file_manager::VolumeManager::Get(profile_)->GetVolumeInfoList();
+      file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList();
 
   std::string log_string;
   std::vector<linked_ptr<file_browser_private::VolumeMetadata> > result;
@@ -143,7 +144,7 @@
     linked_ptr<file_browser_private::VolumeMetadata> volume_metadata(
         new file_browser_private::VolumeMetadata);
     file_manager::util::VolumeInfoToVolumeMetadata(
-        profile(), volume_info_list[i], volume_metadata.get());
+        GetProfile(), volume_info_list[i], volume_metadata.get());
     result.push_back(volume_metadata);
     if (!log_string.empty())
       log_string += ", ";
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 21a7759..d697ac6 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -522,11 +522,11 @@
 #undef SET_STRING
 
   dict->SetBoolean("PDF_VIEW_ENABLED",
-                   file_manager::util::ShouldBeOpenedWithPlugin(profile(),
-                                                  FILE_PATH_LITERAL(".pdf")));
+                   file_manager::util::ShouldBeOpenedWithPlugin(
+                       GetProfile(), FILE_PATH_LITERAL(".pdf")));
   dict->SetBoolean("SWF_VIEW_ENABLED",
-                   file_manager::util::ShouldBeOpenedWithPlugin(profile(),
-                                                  FILE_PATH_LITERAL(".swf")));
+                   file_manager::util::ShouldBeOpenedWithPlugin(
+                       GetProfile(), FILE_PATH_LITERAL(".swf")));
 
   webui::SetFontAndTextDirection(dict);
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.h b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.h
index 579632f..3546050 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.h
@@ -7,13 +7,14 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_STRINGS_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_STRINGS_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
 // Implements the chrome.fileBrowserPrivate.getStrings method.
 // Used to get strings for the file manager from JavaScript.
-class FileBrowserPrivateGetStringsFunction : public SyncExtensionFunction {
+class FileBrowserPrivateGetStringsFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.getStrings",
                              FILEBROWSERPRIVATE_GETSTRINGS)
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index ce988b9..cecd07f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -76,7 +76,7 @@
 
   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   std::vector<FileSystemURL> file_urls;
   for (size_t i = 0; i < params->file_urls.size(); i++) {
@@ -91,7 +91,7 @@
 
   const int32 tab_id = file_manager::util::GetTabId(dispatcher());
   return file_manager::file_tasks::ExecuteFileTask(
-      profile(),
+      GetProfile(),
       source_url(),
       extension_->id(),
       tab_id,
@@ -120,7 +120,7 @@
 
   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   // Collect all the URLs, convert them to GURLs, and crack all the urls into
   // file paths.
@@ -149,8 +149,8 @@
 
   std::vector<file_manager::file_tasks::FullTaskDescriptor> tasks;
   file_manager::file_tasks::FindAllTypesOfTasks(
-      profile_,
-      drive::util::GetDriveAppRegistryByProfile(profile_),
+      GetProfile(),
+      drive::util::GetDriveAppRegistryByProfile(GetProfile()),
       path_mime_set,
       file_urls,
       &tasks);
@@ -182,7 +182,7 @@
 
   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderViewHost(
-          profile(), render_view_host());
+          GetProfile(), render_view_host());
 
   const std::set<std::string> suffixes =
       GetUniqueSuffixes(params->file_urls, file_system_context.get());
@@ -206,10 +206,8 @@
     return true;
   }
 
-  file_manager::file_tasks::UpdateDefaultTask(profile_->GetPrefs(),
-                                              params->task_id,
-                                              suffixes,
-                                              mime_types);
+  file_manager::file_tasks::UpdateDefaultTask(
+      GetProfile()->GetPrefs(), params->task_id, suffixes, mime_types);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
index fd4a7bd..28898a6 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
@@ -53,7 +53,8 @@
 };
 
 // Implements the chrome.fileBrowserPrivate.setDefaultTask method.
-class FileBrowserPrivateSetDefaultTaskFunction : public SyncExtensionFunction {
+class FileBrowserPrivateSetDefaultTaskFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.setDefaultTask",
                              FILEBROWSERPRIVATE_SETDEFAULTTASK)
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
index 7b32237..5734d93 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -210,22 +210,27 @@
   }
 }
 
-int32 GetTabId(ExtensionFunctionDispatcher* dispatcher) {
+content::WebContents* GetWebContents(ExtensionFunctionDispatcher* dispatcher) {
   if (!dispatcher) {
     LOG(WARNING) << "No dispatcher";
-    return 0;
+    return NULL;
   }
   if (!dispatcher->delegate()) {
     LOG(WARNING) << "No delegate";
-    return 0;
+    return NULL;
   }
   content::WebContents* web_contents =
       dispatcher->delegate()->GetAssociatedWebContents();
   if (!web_contents) {
     LOG(WARNING) << "No associated tab contents";
-    return 0;
+    return NULL;
   }
-  return ExtensionTabUtil::GetTabId(web_contents);
+  return web_contents;
+}
+
+int32 GetTabId(ExtensionFunctionDispatcher* dispatcher) {
+  content::WebContents* web_contents = GetWebContents(dispatcher);
+  return web_contents ? ExtensionTabUtil::GetTabId(web_contents) : 0;
 }
 
 base::FilePath GetLocalPathFromURL(
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.h b/chrome/browser/chromeos/extensions/file_manager/private_api_util.h
index 1f587f2..afd9f95 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.h
@@ -16,6 +16,7 @@
 
 namespace content {
 class RenderViewHost;
+class WebContents;
 }
 
 namespace extensions {
@@ -43,6 +44,10 @@
     const VolumeInfo& volume_info,
     extensions::api::file_browser_private::VolumeMetadata* volume_metadata);
 
+// Returns the WebContents of the tab associated with the dispatcher. Returns
+// NULL on error.
+content::WebContents* GetWebContents(ExtensionFunctionDispatcher* dispatcher);
+
 // Returns the ID of the tab associated with the dispatcher. Returns 0 on
 // error.
 int32 GetTabId(ExtensionFunctionDispatcher* dispatcher);
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index b89dedf..1ee0521 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -6,11 +6,13 @@
 
 #include <vector>
 
+#include "ash/ash_switches.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
+#include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/memory/scoped_ptr.h"
@@ -53,6 +55,11 @@
     "com/chromeos-wallpaper-public/manifest_";
 #endif
 
+bool IsOEMDefaultWallpaper() {
+  return CommandLine::ForCurrentProcess()->
+      HasSwitch(ash::switches::kAshOemWallpaperSmall);
+}
+
 // Saves |data| as |file_name| to directory with |key|. Return false if the
 // directory can not be found/created or failed to write file.
 bool SaveData(int key, const std::string& file_name, const std::string& data) {
@@ -206,6 +213,7 @@
   dict->SetString("manifestBaseURL", kWallpaperManifestBaseURL);
 #endif
 
+  dict->SetBoolean("isOEMDefaultWallpaper", IsOEMDefaultWallpaper());
   return true;
 }
 
@@ -603,13 +611,17 @@
                            &thumbnail_path));
     thumbnail_path = thumbnail_path.Append(file_name);
   } else {
-    std::string file_name = params->url_or_file;
-    std::string username_hash =
-        chromeos::UserManager::Get()->GetLoggedInUser()->username_hash();
-    thumbnail_path = chromeos::WallpaperManager::Get()->
-        GetCustomWallpaperPath(chromeos::kThumbnailWallpaperSubDir,
-                               username_hash,
-                               file_name);
+    if (!IsOEMDefaultWallpaper()) {
+      SetError("No OEM wallpaper.");
+      SendResponse(false);
+      return false;
+    }
+
+    // TODO(bshe): Small resolution wallpaper is used here as wallpaper
+    // thumbnail. We should either resize it or include a wallpaper thumbnail in
+    // addition to large and small wallpaper resolutions.
+    thumbnail_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+        ash::switches::kAshOemWallpaperSmall);
   }
 
   sequence_token_ = BrowserThread::GetBlockingPool()->
diff --git a/chrome/browser/chromeos/file_manager/desktop_notifications_unittest.cc b/chrome/browser/chromeos/file_manager/desktop_notifications_unittest.cc
index 5862057..8a5633f 100644
--- a/chrome/browser/chromeos/file_manager/desktop_notifications_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/desktop_notifications_unittest.cc
@@ -9,236 +9,417 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "grit/generated_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-using ::testing::_;
-using ::testing::InSequence;
-using ::testing::StrEq;
-
 namespace file_manager {
 
 namespace {
 
-class MockFileManagerNotificationsOnMount : public DesktopNotifications {
+// This class records parameters for functions to show and hide
+// notifications.
+class RecordedDesktopNotifications : public DesktopNotifications {
  public:
-  explicit MockFileManagerNotificationsOnMount(Profile* profile)
+  explicit RecordedDesktopNotifications(Profile* profile)
       : DesktopNotifications(profile) {
   }
 
-  virtual ~MockFileManagerNotificationsOnMount() {}
+  virtual ~RecordedDesktopNotifications() {}
 
-  MOCK_METHOD3(ShowNotificationWithMessage,
-               void(NotificationType, const std::string&, const string16&));
-  MOCK_METHOD2(HideNotification, void(NotificationType, const std::string&));
+  virtual void ShowNotificationWithMessage(
+      NotificationType type,
+      const std::string& path,
+      const string16& message)  OVERRIDE {
+    ShowAndHideParams params;
+    params.event = SHOW;
+    params.type = type;
+    params.path = path;
+    params.message = message;
+    params_.push_back(params);
+  }
+
+  virtual void HideNotification(NotificationType type,
+                                const std::string& path) OVERRIDE {
+    ShowAndHideParams params;
+    params.event = HIDE;
+    params.type = type;
+    params.path = path;
+    params_.push_back(params);
+  }
+
+  enum Event {
+    SHOW,
+    HIDE,
+  };
+
+  // Used to record parameters passed to ShowNotificationWithMessage() and
+  // HideNotification().
+  struct ShowAndHideParams {
+    Event event;
+    NotificationType type;
+    std::string path;
+    string16 message;  // Empty for HideNotification().
+  };
+
+  // Returns parameters passed to ShowNotificationWithMessage() and
+  // HideNotificationParams().
+  const std::vector<ShowAndHideParams>& params() const {
+    return params_;
+  }
+
+ private:
+  std::vector<ShowAndHideParams> params_;
 };
 
-MATCHER_P2(String16Equals, id, label, "") {
-  return arg == l10n_util::GetStringFUTF16(id, UTF8ToUTF16(label));
-}
-
 }  // namespace
 
 TEST(FileManagerMountNotificationsTest, GoodDevice) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
+  notifications.RegisterDevice(notification_path);
 
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, true, true, false);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      true  /* is_parent */,
+      true  /* success */,
+      false  /* is_unsupported */);
+  // Should hide a DEVICE notification.
+  ASSERT_EQ(1U, notifications.params().size());
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
 };
 
 TEST(FileManagerMountNotificationsTest, GoodDeviceWithBadParent) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
+  notifications.RegisterDevice(notification_path);
 
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      true  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
 
-  {
-    InSequence s;
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      true  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(3U, notifications.params().size());
+  // Should hide a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[2].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[2].type);
+  EXPECT_EQ(notification_path, notifications.params()[2].path);
 
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path), _));
-    EXPECT_CALL(*mocked_notifications, HideNotification(
-        DesktopNotifications::DEVICE_FAIL,
-        StrEq(notification_path)));
-  }
-
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, true, false, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, true, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, true, false);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      true  /* success */,
+      false  /* is_unsupported */);
+  // Should do nothing this time.
+  ASSERT_EQ(3U, notifications.params().size());
 }
 
 TEST(FileManagerMountNotificationsTest, UnsupportedDevice) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
+  notifications.RegisterDevice(notification_path);
 
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-  EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-      DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-      String16Equals(IDS_DEVICE_UNSUPPORTED_MESSAGE, device_label)));
-
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, true);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      true  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // And should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNSUPPORTED_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[1].message);
 }
 
 TEST(FileManagerMountNotificationsTest, UnsupportedWithUnknownParent) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
+  notifications.RegisterDevice(notification_path);
 
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      true  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // And should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
 
-  {
-    InSequence s;
-
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path), _));
-    EXPECT_CALL(*mocked_notifications, HideNotification(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path)));
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-        String16Equals(IDS_DEVICE_UNSUPPORTED_MESSAGE,
-        device_label)));
-  }
-
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, true, false, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, true);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      true  /* is_unsupported */);
+  ASSERT_EQ(4U, notifications.params().size());
+  // Should hide DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[2].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[2].type);
+  EXPECT_EQ(notification_path, notifications.params()[2].path);
+  // Should show DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[3].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[3].type);
+  EXPECT_EQ(notification_path, notifications.params()[3].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNSUPPORTED_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[3].message);
 }
 
 TEST(FileManagerMountNotificationsTest, MountPartialSuccess) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-  EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-      DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-          String16Equals(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
-          device_label)));
+  notifications.RegisterDevice(notification_path);
 
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, true, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, true);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      true  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(1U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      true  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[1].message);
 }
 
 TEST(FileManagerMountNotificationsTest, Unknown) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-  EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-      DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-      String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
+  notifications.RegisterDevice(notification_path);
 
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, false);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[1].message);
 }
 
 TEST(FileManagerMountNotificationsTest, NonASCIILabel) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   // "RA (U+30E9) BE (U+30D9) RU (U+30EB)" in Katakana letters.
   std::string device_label("\xE3\x83\xA9\xE3\x83\x99\xE3\x83\xAB");
 
-  notifications->RegisterDevice(notification_path);
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-  EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-      DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-      String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
+  notifications.RegisterDevice(notification_path);
 
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, false);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  ASSERT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[1].message);
 }
 
 TEST(FileManagerMountNotificationsTest, MulitpleFail) {
-  MockFileManagerNotificationsOnMount* mocked_notifications =
-      new MockFileManagerNotificationsOnMount(NULL);
-  scoped_ptr<DesktopNotifications> notifications(mocked_notifications);
+  RecordedDesktopNotifications notifications(NULL);
 
   std::string notification_path("system_path_prefix");
   std::string device_label("label");
 
-  notifications->RegisterDevice(notification_path);
-  EXPECT_CALL(*mocked_notifications, HideNotification(
-              DesktopNotifications::DEVICE, StrEq(notification_path)));
-  {
-    InSequence s;
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-        String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)))
-        .RetiresOnSaturation();
-    EXPECT_CALL(*mocked_notifications, HideNotification(
-        DesktopNotifications::DEVICE_FAIL, notification_path));
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-        String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
-    EXPECT_CALL(*mocked_notifications, HideNotification(
-        DesktopNotifications::DEVICE_FAIL, notification_path));
-    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-        DesktopNotifications::DEVICE_FAIL, StrEq(notification_path),
-        String16Equals(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
-                       device_label)));
-  }
+  notifications.RegisterDevice(notification_path);
 
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, true, false, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, false);
-  notifications->ManageNotificationsOnMountCompleted(notification_path,
-      device_label, false, false, false);
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      true  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  EXPECT_EQ(2U, notifications.params().size());
+  // Should hide DEVICE notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[0].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE, notifications.params()[0].type);
+  EXPECT_EQ(notification_path, notifications.params()[0].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[1].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[1].type);
+  EXPECT_EQ(notification_path, notifications.params()[1].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[1].message);
+
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  EXPECT_EQ(4U, notifications.params().size());
+  // Should hide DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[2].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL, notifications.params()[2].type);
+  EXPECT_EQ(notification_path, notifications.params()[2].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[3].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[3].type);
+  EXPECT_EQ(notification_path, notifications.params()[3].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[3].message);
+
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  EXPECT_EQ(6U, notifications.params().size());
+  // Should hide DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::HIDE,
+            notifications.params()[4].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL, notifications.params()[4].type);
+  EXPECT_EQ(notification_path, notifications.params()[4].path);
+  // Should show a DEVICE_FAIL notification.
+  EXPECT_EQ(RecordedDesktopNotifications::SHOW,
+            notifications.params()[5].event);
+  EXPECT_EQ(DesktopNotifications::DEVICE_FAIL,
+            notifications.params()[5].type);
+  EXPECT_EQ(notification_path, notifications.params()[5].path);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF16(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
+                                 UTF8ToUTF16(device_label)),
+      notifications.params()[5].message);
+
+  notifications.ManageNotificationsOnMountCompleted(
+      notification_path,
+      device_label,
+      false  /* is_parent */,
+      false  /* success */,
+      false  /* is_unsupported */);
+  EXPECT_EQ(6U, notifications.params().size());
+  // Should do nothing this time.
 }
 
 }  // namespace file_manager.
diff --git a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
index 54ea3af..6d7956f 100644
--- a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
+++ b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
@@ -28,6 +27,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "net/base/escape.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc b/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
index 3fb2d1c..bd7d4f2 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
@@ -407,7 +407,7 @@
   return true;
 }
 
-void InputMethodEngineIBus::FocusIn() {
+void InputMethodEngineIBus::FocusIn(ibus::TextInputType text_input_type) {
   focused_ = true;
   if (!active_)
     return;
@@ -434,7 +434,7 @@
 void InputMethodEngineIBus::Enable() {
   active_ = true;
   observer_->OnActivate(engine_id_);
-  FocusIn();
+  FocusIn(ibus::TEXT_INPUT_TYPE_TEXT);
 
   // Calls RequireSurroundingText once here to notify ibus-daemon to send
   // surrounding text to this engine.
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_ibus.h b/chrome/browser/chromeos/input_method/input_method_engine_ibus.h
index 0d84306..1253613 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus.h
@@ -79,7 +79,7 @@
                                      std::string* error) OVERRIDE;
 
   // IBusEngineHandlerInterface overrides.
-  virtual void FocusIn() OVERRIDE;
+  virtual void FocusIn(ibus::TextInputType text_input_type) OVERRIDE;
   virtual void FocusOut() OVERRIDE;
   virtual void Enable() OVERRIDE;
   virtual void Disable() OVERRIDE;
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc b/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
index 3f7f8b5..4d7bde7 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
@@ -182,7 +182,7 @@
 
   // onFocus event should be fired if FocusIn function is called.
   ExtensionTestMessageListener focus_listener("onFocus", false);;
-  engine_handler->FocusIn();
+  engine_handler->FocusIn(ibus::TEXT_INPUT_TYPE_TEXT);
   ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
   ASSERT_TRUE(focus_listener.was_satisfied());
 
@@ -263,7 +263,7 @@
       1);
 
   engine_handler->Enable();
-  engine_handler->FocusIn();
+  engine_handler->FocusIn(ibus::TEXT_INPUT_TYPE_TEXT);
 
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
diff --git a/chrome/browser/chromeos/input_method/input_method_persistence.cc b/chrome/browser/chromeos/input_method/input_method_persistence.cc
index 47beee5..822b3b8 100644
--- a/chrome/browser/chromeos/input_method/input_method_persistence.cc
+++ b/chrome/browser/chromeos/input_method/input_method_persistence.cc
@@ -6,11 +6,11 @@
 
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/sys_info.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index 609dfb7..f1209d7 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -59,9 +59,9 @@
   // For traditional Chinese input methods
   { "mozc-chewing", "\xe9\x85\xb7" },  // U+9177
   { "_comp_ime_ekbifjdfhkmdeeajnolmgdlmkllopefizh-hant-t-i0-und",
-    "\xe9\x85\xb7" },  // U+9177
+    "\xE6\xB3\xA8" },  // U+6CE8
   { "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und",
-    "\xe9\x85\xb7" },  // U+9177
+    "\xE6\xB3\xA8" },  // U+6CE8
   { "m17n:zh:cangjie", "\xe5\x80\x89" },  // U+5009
   { "_comp_ime_aeebooiibjahgpgmhkeocbeekccfknbjzh-hant-t-i0-cangjie-1987",
     "\xe5\x80\x89" },  // U+5009
diff --git a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
index 692a38f..24e47da 100644
--- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
@@ -159,17 +159,7 @@
   }
   {
     InputMethodDescriptor desc = GetDesc(zhuyin_ime_id, "us", "zh-TW");
-    EXPECT_EQ(UTF8ToUTF16("\xe9\x85\xb7"),
-              util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc = GetDesc("m17n:zh:cangjie", "us", "zh-TW");
-    EXPECT_EQ(UTF8ToUTF16("\xe5\x80\x89"),
-              util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc = GetDesc("m17n:zh:quick", "us", "zh-TW");
-    EXPECT_EQ(UTF8ToUTF16("\xe9\x80\x9f"),
+    EXPECT_EQ(UTF8ToUTF16("\xE6\xB3\xA8"),
               util_.GetInputMethodShortName(desc));
   }
 }
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index 800b774..a6d6113 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
 
+#include "apps/shell_window_registry.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
@@ -41,6 +42,42 @@
 base::Closure* AppLaunchController::network_timeout_callback_ = NULL;
 UserManager* AppLaunchController::test_user_manager_ = NULL;
 
+////////////////////////////////////////////////////////////////////////////////
+// AppLaunchController::AppWindowWatcher
+
+class AppLaunchController::AppWindowWatcher
+    : public apps::ShellWindowRegistry::Observer {
+ public:
+  explicit AppWindowWatcher(AppLaunchController* controller)
+    : controller_(controller),
+      window_registry_(apps::ShellWindowRegistry::Get(controller->profile_)) {
+    window_registry_->AddObserver(this);
+  }
+  virtual ~AppWindowWatcher() {
+    window_registry_->RemoveObserver(this);
+  }
+
+ private:
+  // apps::ShellWindowRegistry::Observer overrides:
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
+    if (controller_) {
+      controller_->OnAppWindowCreated();
+      controller_= NULL;
+    }
+  }
+  virtual void OnShellWindowIconChanged(
+      apps::ShellWindow* shell_window) OVERRIDE {}
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {}
+
+  AppLaunchController* controller_;
+  apps::ShellWindowRegistry* window_registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// AppLaunchController
+
 AppLaunchController::AppLaunchController(const std::string& app_id,
                                          LoginDisplayHost* host,
                                          OobeDisplay* oobe_display)
@@ -161,7 +198,7 @@
   OnLaunchFailed(error);
 }
 
-void AppLaunchController::Cleanup() {
+void AppLaunchController::CleanUp() {
   kiosk_profile_loader_.reset();
   startup_app_launcher_.reset();
 
@@ -169,6 +206,25 @@
     host_->Finalize();
 }
 
+void AppLaunchController::OnNetworkWaitTimedout() {
+  DCHECK(waiting_for_network_);
+  LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
+               <<  net::NetworkChangeNotifier::GetConnectionType();
+  network_wait_timedout_ = true;
+  app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
+  if (network_timeout_callback_)
+    network_timeout_callback_->Run();
+}
+
+UserManager* AppLaunchController::GetUserManager() {
+  return test_user_manager_ ? test_user_manager_ : UserManager::Get();
+}
+
+void AppLaunchController::OnAppWindowCreated() {
+  DVLOG(1) << "App window created, closing splash screen.";
+  CleanUp();
+}
+
 void AppLaunchController::OnLoadingOAuthFile() {
   app_launch_splash_screen_actor_->UpdateAppLaunchState(
       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
@@ -192,16 +248,6 @@
       this, &AppLaunchController::OnNetworkWaitTimedout);
 }
 
-void AppLaunchController::OnNetworkWaitTimedout() {
-  DCHECK(waiting_for_network_);
-  LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
-               <<  net::NetworkChangeNotifier::GetConnectionType();
-  network_wait_timedout_ = true;
-  app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
-  if (network_timeout_callback_)
-    network_timeout_callback_->Run();
-}
-
 void AppLaunchController::OnInstallingApp() {
   app_launch_splash_screen_actor_->UpdateAppLaunchState(
       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
@@ -243,8 +289,12 @@
 }
 
 void AppLaunchController::OnLaunchSucceeded() {
-  DVLOG(1) << "Kiosk launch succeeded!";
-  Cleanup();
+  DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
+  app_launch_splash_screen_actor_->UpdateAppLaunchState(
+      AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
+
+  DCHECK(!app_window_watcher_);
+  app_window_watcher_.reset(new AppWindowWatcher(this));
 }
 
 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
@@ -254,11 +304,7 @@
   // Saves the error and ends the session to go back to login screen.
   KioskAppLaunchError::Save(error);
   chrome::AttemptUserExit();
-  Cleanup();
-}
-
-UserManager* AppLaunchController::GetUserManager() {
-  return test_user_manager_ ? test_user_manager_ : UserManager::Get();
+  CleanUp();
 }
 
 }   // namespace chromeos
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
index 27f3eb4..5c0c393 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.h
+++ b/chrome/browser/chromeos/login/app_launch_controller.h
@@ -59,10 +59,16 @@
   static void SetUserManagerForTesting(UserManager* user_manager);
 
  private:
-  void Cleanup();
+  // A class to watch app window creation.
+  class AppWindowWatcher;
+
+  void CleanUp();
   void OnNetworkWaitTimedout();
   UserManager* GetUserManager();
 
+  // Callback of AppWindowWatcher to notify an app window is created.
+  void OnAppWindowCreated();
+
   // KioskProfileLoader::Delegate overrides:
   virtual void OnProfileLoaded(Profile* profile) OVERRIDE;
   virtual void OnProfileLoadFailed(KioskAppLaunchError::Error error) OVERRIDE;
@@ -97,6 +103,7 @@
   scoped_ptr<KioskProfileLoader> kiosk_profile_loader_;
   scoped_ptr<StartupAppLauncher> startup_app_launcher_;
   scoped_ptr<AppLaunchSigninScreen> signin_screen_;
+  scoped_ptr<AppWindowWatcher> app_window_watcher_;
 
   content::NotificationRegistrar registrar_;
   bool webui_visible_;
diff --git a/chrome/browser/chromeos/login/captive_portal_window_proxy.cc b/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
index fc5d389..60da837 100644
--- a/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
+++ b/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
@@ -71,8 +71,6 @@
 
   widget_->AddObserver(this);
   web_contents_modal_dialog_manager->ShowDialog(widget_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      widget_->GetNativeView(), true);
   DCHECK(GetState() == STATE_DISPLAYED);
 }
 
diff --git a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc
index f6de0e0..0afd0a6 100644
--- a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc
+++ b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc
@@ -11,11 +11,11 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
index 8224331..016b904 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -264,6 +264,15 @@
     case policy::EnrollmentStatus::STATUS_LOCK_ERROR:
       UMAFailure(policy::kMetricEnrollmentOtherFailed);
       return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_AUTH_FETCH_FAILED:
+      UMAFailure(policy::kMetricEnrollmentRobotAuthCodeFetchFailed);
+      return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED:
+      UMAFailure(policy::kMetricEnrollmentRobotRefreshTokenFetchFailed);
+      return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED:
+      UMAFailure(policy::kMetricEnrollmentRobotRefreshTokenStoreFailed);
+      return;
   }
 
   NOTREACHED();
diff --git a/chrome/browser/chromeos/login/fake_user_manager.cc b/chrome/browser/chromeos/login/fake_user_manager.cc
index f5b1e7e..f32cc85 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.cc
+++ b/chrome/browser/chromeos/login/fake_user_manager.cc
@@ -81,8 +81,16 @@
 }
 
 User* FakeUserManager::GetActiveUserInternal() const {
-  if (user_list_.size())
+  if (user_list_.size()) {
+    if (!active_user_id_.empty()) {
+      for (UserList::const_iterator it = user_list_.begin();
+           it != user_list_.end(); ++it) {
+        if ((*it)->email() == active_user_id_)
+          return *it;
+      }
+    }
     return user_list_[0];
+  }
   return NULL;
 }
 
@@ -94,6 +102,10 @@
   return GetActiveUserInternal();
 }
 
+void FakeUserManager::SwitchActiveUser(const std::string& email) {
+  active_user_id_ = email;
+}
+
 void FakeUserManager::SaveUserDisplayName(
     const std::string& username,
     const string16& display_name) {
@@ -152,6 +164,12 @@
 }
 
 User* FakeUserManager::GetUserByProfile(Profile* profile) const {
+  const std::string& user_name = profile->GetProfileName();
+  for (UserList::const_iterator it = user_list_.begin();
+       it != user_list_.end(); ++it) {
+    if ((*it)->email() == user_name)
+      return *it;
+  }
   return primary_user_;
 }
 
diff --git a/chrome/browser/chromeos/login/fake_user_manager.h b/chrome/browser/chromeos/login/fake_user_manager.h
index 2423a6f..8c126d1 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.h
+++ b/chrome/browser/chromeos/login/fake_user_manager.h
@@ -45,6 +45,7 @@
 
   virtual const User* GetActiveUser() const OVERRIDE;
   virtual User* GetActiveUser() OVERRIDE;
+  virtual void SwitchActiveUser(const std::string& email) OVERRIDE;
   virtual void SaveUserDisplayName(const std::string& username,
       const string16& display_name) OVERRIDE;
   virtual void UpdateUserAccountData(const std::string&, const string16&,
@@ -57,7 +58,6 @@
   virtual const UserList& GetLRULoggedInUsers() OVERRIDE;
   virtual UserList GetUnlockUsers() const OVERRIDE;
   virtual const std::string& GetOwnerEmail() OVERRIDE;
-  virtual void SwitchActiveUser(const std::string& email) OVERRIDE {}
   virtual void SessionStarted() OVERRIDE {}
   virtual void RestoreActiveSessions() OVERRIDE {}
   virtual void RemoveUser(const std::string& email,
@@ -132,6 +132,10 @@
   std::string owner_email_;
   User* primary_user_;
 
+  // If set this is the active user. If empty, the first created user is the
+  // active user.
+  std::string active_user_id_;
+
   DISALLOW_COPY_AND_ASSIGN(FakeUserManager);
 };
 
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 5e3e9e1..2f3f8f4 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
@@ -24,6 +25,7 @@
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
@@ -36,13 +38,14 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/policy/cloud/policy_builder.h"
 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -61,6 +64,7 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/layer.h"
 
 namespace em = enterprise_management;
 
@@ -117,6 +121,12 @@
   runner_quit_task.Run();
 }
 
+// Helper function for DeviceOAuth2TokenServiceFactory::Get().
+void CopyTokenService(DeviceOAuth2TokenService** out_token_service,
+                      DeviceOAuth2TokenService* in_token_service) {
+  *out_token_service = in_token_service;
+}
+
 }  // namespace
 
 // Fake NetworkChangeNotifier used to simulate network connectivity.
@@ -149,56 +159,49 @@
   DISALLOW_COPY_AND_ASSIGN(FakeNetworkChangeNotifier);
 };
 
-// A waiter that blocks until the expected oobe screen is reached.
-class OobeScreenWaiter : public OobeUI::Observer {
+// Helper class that monitors app windows to wait for a window to appear.
+class ShellWindowObserver : public apps::ShellWindowRegistry::Observer {
  public:
-  explicit OobeScreenWaiter(OobeDisplay::Screen expected_screen)
-      : waiting_for_screen_(false),
-        expected_screen_(expected_screen) {
+  ShellWindowObserver(apps::ShellWindowRegistry* registry,
+                      const std::string& app_id)
+      : registry_(registry), app_id_(app_id), window_(NULL), running_(false) {
+    registry_->AddObserver(this);
+  }
+  virtual ~ShellWindowObserver() {
+    registry_->RemoveObserver(this);
   }
 
-  virtual ~OobeScreenWaiter() {
-    if (waiting_for_screen_) {
-      GetOobeUI()->RemoveObserver(this);
-    }
+  apps::ShellWindow* Wait() {
+    running_ = true;
+    message_loop_runner_ = new content::MessageLoopRunner;
+    message_loop_runner_->Run();
+    EXPECT_TRUE(window_);
+    return window_;
   }
 
-  void Wait() {
-    if (GetOobeUI()->current_screen() == expected_screen_) {
+  // ShellWindowRegistry::Observer
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
+    if (!running_)
       return;
-    }
 
-    waiting_for_screen_ = true;
-    GetOobeUI()->AddObserver(this);
-
-    runner_ = new content::MessageLoopRunner;
-    runner_->Run();
-    ASSERT_EQ(expected_screen_, GetOobeUI()->current_screen());
-    ASSERT_FALSE(waiting_for_screen_);
-  }
-
-  // OobeUI::Observer implementation:
-  virtual void OnCurrentScreenChanged(
-        OobeDisplay::Screen current_screen,
-        OobeDisplay::Screen new_screen) OVERRIDE {
-    if (waiting_for_screen_ && new_screen == expected_screen_) {
-      runner_->Quit();
-      waiting_for_screen_ = false;
-      GetOobeUI()->RemoveObserver(this);
+    if (shell_window->extension_id() == app_id_) {
+      window_ = shell_window;
+      message_loop_runner_->Quit();
+      running_ = false;
     }
   }
-
-  OobeUI* GetOobeUI() {
-    OobeUI* oobe_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-        chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI();
-    CHECK(oobe_ui);
-    return oobe_ui;
-  }
+  virtual void OnShellWindowIconChanged(
+      apps::ShellWindow* shell_window) OVERRIDE {}
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {}
 
  private:
-  bool waiting_for_screen_;
-  OobeDisplay::Screen expected_screen_;
-  scoped_refptr<content::MessageLoopRunner> runner_;
+  apps::ShellWindowRegistry* registry_;
+  std::string app_id_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  apps::ShellWindow* window_;
+  bool running_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellWindowObserver);
 };
 
 class KioskTest : public InProcessBrowserTest,
@@ -321,17 +324,33 @@
         chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
         content::NotificationService::AllSources()).Wait();
 
+    // Default profile switches to app profile after app is launched.
+    Profile* app_profile = ProfileManager::GetDefaultProfile();
+    ASSERT_TRUE(app_profile);
+
     // Check installer status.
     EXPECT_EQ(chromeos::KioskAppLaunchError::NONE,
               chromeos::KioskAppLaunchError::Get());
 
     // Check if the kiosk webapp is really installed for the default profile.
-    ASSERT_TRUE(ProfileManager::GetDefaultProfile());
     const extensions::Extension* app =
-        extensions::ExtensionSystem::Get(ProfileManager::GetDefaultProfile())->
+        extensions::ExtensionSystem::Get(app_profile)->
         extension_service()->GetInstalledExtension(kTestKioskApp);
     EXPECT_TRUE(app);
 
+    // App should appear with its window.
+    apps::ShellWindow* window = ShellWindowObserver(
+        apps::ShellWindowRegistry::Get(app_profile),
+        kTestKioskApp).Wait();
+    EXPECT_TRUE(window);
+
+    // Login screen should be fading out.
+    EXPECT_EQ(0.0f,
+              LoginDisplayHostImpl::default_host()
+                  ->GetNativeWindow()
+                  ->layer()
+                  ->GetTargetOpacity());
+
     // Wait until the app terminates.
     content::RunMessageLoop();
 
@@ -400,6 +419,13 @@
         chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui();
   }
 
+  SigninScreenHandler* GetSigninScreenHandler() {
+    return static_cast<chromeos::LoginDisplayHostImpl*>(
+        chromeos::LoginDisplayHostImpl::default_host())
+        ->GetOobeUI()
+        ->signin_screen_handler_for_test();
+  }
+
   AppLaunchController* GetAppLaunchController() {
     return chromeos::LoginDisplayHostImpl::default_host()
         ->GetAppLaunchController();
@@ -410,7 +436,7 @@
       disable_network_notifier_;
   scoped_ptr<FakeNetworkChangeNotifier> fake_network_notifier_;
   scoped_ptr<MockUserManager> mock_user_manager_;
- };
+};
 
 IN_PROC_BROWSER_TEST_P(KioskTest, InstallAndLaunchApp) {
   StartAppLaunchFromLoginScreen(true);
@@ -438,8 +464,8 @@
 
   // A network error screen should be shown after authenticating.
   OobeScreenWaiter error_screen_waiter(OobeDisplay::SCREEN_ERROR_MESSAGE);
-   static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
-     ->OnOwnerSigninSuccess();
+  static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
+      ->OnOwnerSigninSuccess();
   error_screen_waiter.Wait();
 
   ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
@@ -522,24 +548,7 @@
   EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
   EXPECT_TRUE(KioskAppManager::Get()->IsAutoLaunchEnabled());
 
-  // Wait for the Kiosk App to launch.
-  content::WindowedNotificationObserver(
-      chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
-      content::NotificationService::AllSources()).Wait();
-
-  // Check installer status.
-  EXPECT_EQ(chromeos::KioskAppLaunchError::NONE,
-            chromeos::KioskAppLaunchError::Get());
-
-  // Check if the kiosk webapp is really installed for the default profile.
-  ASSERT_TRUE(ProfileManager::GetDefaultProfile());
-  const extensions::Extension* app =
-      extensions::ExtensionSystem::Get(ProfileManager::GetDefaultProfile())->
-      extension_service()->GetInstalledExtension(kTestKioskApp);
-  EXPECT_TRUE(app);
-
-  // Wait until the app terminates.
-  content::RunMessageLoop();
+  WaitForAppLaunchSuccess();
 }
 
 IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableCancel) {
@@ -614,53 +623,45 @@
             GetConsumerKioskModeStatus());
 }
 
+IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableAbortedWithAutoEnrollment) {
+  // Fake an auto enrollment is going to be enforced.
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kEnterpriseEnrollmentInitialModulus, "1");
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kEnterpriseEnrollmentModulusLimit, "2");
+  g_browser_process->local_state()->SetBoolean(prefs::kShouldAutoEnroll, true);
+  g_browser_process->local_state()->SetInteger(
+      prefs::kAutoEnrollmentPowerLimit, 3);
+
+  // Start UI, find menu entry for this app and launch it.
+  chromeos::WizardController::SkipPostLoginScreensForTesting();
+  chromeos::WizardController* wizard_controller =
+      chromeos::WizardController::default_controller();
+  CHECK(wizard_controller);
+
+  // Check Kiosk mode status.
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+            GetConsumerKioskModeStatus());
+  wizard_controller->SkipToLoginForTesting();
+
+  // Wait for the login UI to come up and switch to the kiosk_enable screen.
+  wizard_controller->SkipToLoginForTesting();
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
+                                       base::StringValue("kiosk_enable"));
+
+  // The flow should be aborted due to auto enrollment enforcement.
+  scoped_refptr<content::MessageLoopRunner> runner =
+      new content::MessageLoopRunner;
+  GetSigninScreenHandler()->set_kiosk_enable_flow_aborted_callback_for_test(
+      runner->QuitClosure());
+  runner->Run();
+}
+
 INSTANTIATE_TEST_CASE_P(KioskTestInstantiation, KioskTest, testing::Bool());
 
-// Helper class that monitors app windows to wait for a window to appear.
-class ShellWindowObserver : public apps::ShellWindowRegistry::Observer {
- public:
-  ShellWindowObserver(apps::ShellWindowRegistry* registry,
-                      const std::string& app_id)
-      : registry_(registry), app_id_(app_id), window_(NULL), running_(false) {
-    registry_->AddObserver(this);
-  }
-  virtual ~ShellWindowObserver() {
-    registry_->RemoveObserver(this);
-  }
-
-  apps::ShellWindow* Wait() {
-    running_ = true;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-    EXPECT_TRUE(window_);
-    return window_;
-  }
-
-  // ShellWindowRegistry::Observer
-  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
-    if (!running_)
-      return;
-
-    if (shell_window->extension_id() == app_id_) {
-      window_ = shell_window;
-      message_loop_runner_->Quit();
-      running_ = false;
-    }
-  }
-  virtual void OnShellWindowIconChanged(
-      apps::ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {}
-
- private:
-  apps::ShellWindowRegistry* registry_;
-  std::string app_id_;
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  apps::ShellWindow* window_;
-  bool running_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellWindowObserver);
-};
-
 class KioskEnterpriseTest : public KioskTest {
  protected:
   KioskEnterpriseTest() {}
@@ -698,8 +699,12 @@
     token_info.token = kTestAccessToken;
     token_info.email = kTestEnterpriseServiceAccountId;
     fake_gaia_.IssueOAuthToken(kTestRefreshToken, token_info);
-    DeviceOAuth2TokenServiceFactory::Get()
-        ->SetAndSaveRefreshToken(kTestRefreshToken);
+    DeviceOAuth2TokenService* token_service = NULL;
+    DeviceOAuth2TokenServiceFactory::Get(
+        base::Bind(&CopyTokenService, &token_service));
+    base::RunLoop().RunUntilIdle();
+    ASSERT_TRUE(token_service);
+    token_service->SetAndSaveRefreshToken(kTestRefreshToken);
 
     KioskTest::SetUpOnMainThread();
   }
diff --git a/chrome/browser/chromeos/login/login_display_host.h b/chrome/browser/chromeos/login/login_display_host.h
index 2c4e93f..6c0eeab 100644
--- a/chrome/browser/chromeos/login/login_display_host.h
+++ b/chrome/browser/chromeos/login/login_display_host.h
@@ -29,6 +29,12 @@
 // UI implementation (such as LoginDisplay).
 class LoginDisplayHost {
  public:
+  // Callback for GetAutoEnrollmentCheckResult. It is invoked with when
+  // a decision is made for auto enrollment. It is invoked with "true" when
+  // auto enrollment check is finished and auto enrollment should be enforced.
+  // Otherwise, it is invoked with "false".
+  typedef base::Callback<void(bool)> GetAutoEnrollmentCheckResultCallback;
+
   virtual ~LoginDisplayHost() {}
 
   // Creates UI implementation specific login display instance (views/WebUI).
@@ -62,6 +68,12 @@
   // Auto-Enrollment checks now.
   virtual void CheckForAutoEnrollment() = 0;
 
+  // Gets the auto enrollment check results. If the check is still pending,
+  // |callback| will be invoked asynchronously after it is finished. Otherwise,
+  // |callback| is invoked synchronously before this call returns.
+  virtual void GetAutoEnrollmentCheckResult(
+      const GetAutoEnrollmentCheckResultCallback& callback) = 0;
+
   // Starts out-of-box-experience flow or shows other screen handled by
   // Wizard controller i.e. camera, recovery.
   // One could specify start screen with |first_screen_name|.
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index 5095ad8..eccaf7f 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -64,9 +64,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_element.h"
-#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/events/event_utils.h"
 #include "ui/gfx/rect.h"
@@ -148,6 +146,26 @@
   return widget->GetNativeView()->layer();
 }
 
+// A class to observe an implicit animation and invokes the callback after the
+// animation is completed.
+class AnimationObserver : public ui::ImplicitAnimationObserver {
+ public:
+  explicit AnimationObserver(const base::Closure& callback)
+      : callback_(callback) {}
+  virtual ~AnimationObserver() {}
+
+ private:
+  // ui::ImplicitAnimationObserver implementation:
+  virtual void OnImplicitAnimationsCompleted() OVERRIDE {
+    callback_.Run();
+    delete this;
+  }
+
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
+};
+
 }  // namespace
 
 namespace chromeos {
@@ -174,7 +192,10 @@
       is_wallpaper_loaded_(false),
       status_area_saved_visibility_(false),
       crash_count_(0),
-      restore_path_(RESTORE_UNKNOWN) {
+      restore_path_(RESTORE_UNKNOWN),
+      auto_enrollment_check_done_(false),
+      finalize_animation_type_(ANIMATION_WORKSPACE),
+      animation_weak_ptr_factory_(this) {
   // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
   // because/ APP_TERMINATING will never be fired as long as this keeps
   // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
@@ -314,14 +335,23 @@
   }
   if (wizard_controller_.get())
     wizard_controller_->OnSessionStart();
-  if (!IsRunningUserAdding()) {
-    // Display host is deleted once animation is completed
-    // since sign in screen widget has to stay alive.
-    if (ash::Shell::HasInstance()) {
-      StartAnimation();
-    }
+
+  switch (finalize_animation_type_) {
+    case ANIMATION_NONE:
+      ShutdownDisplayHost(false);
+      break;
+    case ANIMATION_WORKSPACE:
+      if (ash::Shell::HasInstance())
+        ScheduleWorkspaceAnimation();
+
+      ShutdownDisplayHost(false);
+      break;
+    case ANIMATION_FADE_OUT:
+      // Display host is deleted once animation is completed
+      // since sign in screen widget has to stay alive.
+      ScheduleFadeOutAnimation();
+      break;
   }
-  ShutdownDisplayHost(false);
 }
 
 void LoginDisplayHostImpl::OnCompleteLogin() {
@@ -350,6 +380,7 @@
 
   if (policy::AutoEnrollmentClient::IsDisabled()) {
     VLOG(1) << "CheckForAutoEnrollment: auto-enrollment disabled";
+    auto_enrollment_check_done_ = true;
     return;
   }
 
@@ -358,6 +389,20 @@
   DeviceSettingsService::Get()->GetOwnershipStatusAsync(
       base::Bind(&LoginDisplayHostImpl::OnOwnershipStatusCheckDone,
                  pointer_factory_.GetWeakPtr()));
+  auto_enrollment_check_done_ = false;
+}
+
+void LoginDisplayHostImpl::GetAutoEnrollmentCheckResult(
+    const GetAutoEnrollmentCheckResultCallback& callback) {
+  DCHECK(!callback.is_null());
+
+  if (auto_enrollment_check_done_) {
+    callback.Run(auto_enrollment_client_ &&
+                 auto_enrollment_client_->should_auto_enroll());
+    return;
+  }
+
+  get_auto_enrollment_result_callbacks_.push_back(callback);
 }
 
 void LoginDisplayHostImpl::StartWizard(
@@ -406,6 +451,7 @@
     const base::Closure& completion_callback) {
   restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
   completion_callback_ = completion_callback;
+  finalize_animation_type_ = ANIMATION_NONE;
   LOG(WARNING) << "Login WebUI >> user adding";
   if (!login_window_)
     LoadURL(GURL(kUserAddingURL));
@@ -434,6 +480,7 @@
 void LoginDisplayHostImpl::StartSignInScreen() {
   restore_path_ = RESTORE_SIGN_IN;
   is_showing_login_ = true;
+  finalize_animation_type_ = ANIMATION_WORKSPACE;
 
   PrewarmAuthentication();
 
@@ -515,6 +562,7 @@
 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id) {
   LOG(WARNING) << "Login WebUI >> start app launch.";
   SetStatusAreaVisible(false);
+  finalize_animation_type_ = ANIMATION_FADE_OUT;
   if (!login_window_)
     LoadURL(GURL(kAppLaunchSplashURL));
 
@@ -650,7 +698,7 @@
     completion_callback_.Run();
 }
 
-void LoginDisplayHostImpl::StartAnimation() {
+void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
   if (ash::Shell::GetContainer(
           ash::Shell::GetPrimaryRootWindow(),
           ash::internal::kShellWindowId_DesktopBackgroundContainer)->
@@ -665,11 +713,23 @@
     ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
 }
 
+void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
+  ui::Layer* layer = login_window_->GetLayer();
+  ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
+  animation.AddObserver(new AnimationObserver(
+      base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
+                 animation_weak_ptr_factory_.GetWeakPtr(),
+                 false)));
+  layer->SetOpacity(0);
+}
+
 void LoginDisplayHostImpl::OnOwnershipStatusCheckDone(
     DeviceSettingsService::OwnershipStatus status) {
   if (status != DeviceSettingsService::OWNERSHIP_NONE) {
     // The device is already owned. No need for auto-enrollment checks.
     VLOG(1) << "CheckForAutoEnrollment: device already owned";
+    auto_enrollment_check_done_ = true;
+    NotifyAutoEnrollmentCheckResult(false);
     return;
   }
 
@@ -702,6 +762,9 @@
 
   if (auto_enroll)
     ForceAutoEnrollment();
+
+  auto_enrollment_check_done_ = true;
+  NotifyAutoEnrollmentCheckResult(auto_enroll);
 }
 
 void LoginDisplayHostImpl::ForceAutoEnrollment() {
@@ -814,10 +877,6 @@
   login_view_ = NULL;
 }
 
-bool LoginDisplayHostImpl::IsRunningUserAdding() {
-  return restore_path_ == RESTORE_ADD_USER_INTO_SESSION;
-}
-
 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
   auth_prewarmer_.reset();
 }
@@ -826,6 +885,14 @@
   GetOobeUI()->ShowOobeUI(visible);
 }
 
+void LoginDisplayHostImpl::NotifyAutoEnrollmentCheckResult(
+    bool should_auto_enroll) {
+  std::vector<GetAutoEnrollmentCheckResultCallback> callbacks;
+  callbacks.swap(get_auto_enrollment_result_callbacks_);
+  for (size_t i = 0; i < callbacks.size(); ++i)
+    callbacks[i].Run(should_auto_enroll);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // external
 
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.h b/chrome/browser/chromeos/login/login_display_host_impl.h
index adcc674..9ff243b 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.h
+++ b/chrome/browser/chromeos/login/login_display_host_impl.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_DISPLAY_HOST_IMPL_H_
 
 #include <string>
+#include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
@@ -60,6 +61,8 @@
   virtual void OpenProxySettings() OVERRIDE;
   virtual void SetStatusAreaVisible(bool visible) OVERRIDE;
   virtual void CheckForAutoEnrollment() OVERRIDE;
+  virtual void GetAutoEnrollmentCheckResult(
+      const GetAutoEnrollmentCheckResultCallback& callback) OVERRIDE;
   virtual void StartWizard(
       const std::string& first_screen_name,
       scoped_ptr<DictionaryValue> screen_parameters) OVERRIDE;
@@ -88,6 +91,8 @@
   // WebUI at a time).
   static const int kShowLoginWebUIid;
 
+  views::Widget* login_window_for_test() { return login_window_; }
+
  protected:
   // content::NotificationObserver implementation:
   virtual void Observe(int type,
@@ -98,12 +103,31 @@
   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
 
  private:
+  // Way to restore if renderer have crashed.
+  enum RestorePath {
+    RESTORE_UNKNOWN,
+    RESTORE_WIZARD,
+    RESTORE_SIGN_IN,
+    RESTORE_ADD_USER_INTO_SESSION,
+  };
+
+  // Type of animations to run after the login screen.
+  enum FinalizeAnimationType {
+    ANIMATION_NONE,       // No animation.
+    ANIMATION_WORKSPACE,  // Use initial workspace animation (drop and
+                          // and fade in workspace). Used for user login.
+    ANIMATION_FADE_OUT,   // Fade out login screen. Used for app launch.
+  };
+
   // Marks display host for deletion.
   // If |post_quit_task| is true also posts Quit task to the MessageLoop.
   void ShutdownDisplayHost(bool post_quit_task);
 
-  // Start sign in transition animation.
-  void StartAnimation();
+  // Schedules workspace transition animation.
+  void ScheduleWorkspaceAnimation();
+
+  // Schedules fade out animation.
+  void ScheduleFadeOutAnimation();
 
   // Callback for the ownership status check.
   void OnOwnershipStatusCheckDone(
@@ -131,15 +155,15 @@
   // Closes |login_window_| and resets |login_window_| and |login_view_| fields.
   void ResetLoginWindowAndView();
 
-  // Returns true if hosr running UI for adding users into session.
-  bool IsRunningUserAdding();
-
   // Deletes |auth_prewarmer_|.
   void OnAuthPrewarmDone();
 
   // Toggles OOBE progress bar visibility, the bar is hidden by default.
   void SetOobeProgressBarVisible(bool visible);
 
+  // Notifies the interested parties of the auto enrollment check result.
+  void NotifyAutoEnrollmentCheckResult(bool should_auto_enroll);
+
   // Used to calculate position of the screens and background.
   gfx::Rect background_bounds_;
 
@@ -211,12 +235,7 @@
   int crash_count_;
 
   // Way to restore if renderer have crashed.
-  enum {
-    RESTORE_UNKNOWN,
-    RESTORE_WIZARD,
-    RESTORE_SIGN_IN,
-    RESTORE_ADD_USER_INTO_SESSION,
-  } restore_path_;
+  RestorePath restore_path_;
 
   // Stored parameters for StartWizard, required to restore in case of crash.
   std::string wizard_first_screen_name_;
@@ -236,6 +255,17 @@
   // driven oobe.
   scoped_ptr<FocusRingController> focus_ring_controller_;
 
+  // Whether auto enrollment client has done the check.
+  bool auto_enrollment_check_done_;
+
+  // Callbacks to notify when auto enrollment client has done the check.
+  std::vector<GetAutoEnrollmentCheckResultCallback>
+      get_auto_enrollment_result_callbacks_;
+
+  FinalizeAnimationType finalize_animation_type_;
+
+  base::WeakPtrFactory<LoginDisplayHostImpl> animation_weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginDisplayHostImpl);
 };
 
diff --git a/chrome/browser/chromeos/login/login_manager_test.cc b/chrome/browser/chromeos/login/login_manager_test.cc
index 4f7f4b8..338b292 100644
--- a/chrome/browser/chromeos/login/login_manager_test.cc
+++ b/chrome/browser/chromeos/login/login_manager_test.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/chromeos/login/login_manager_test.h"
 
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/webui_login_view.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
index 043a536..c9910c9 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
@@ -41,6 +41,8 @@
 // There is another supervised user with same name.
 const char kUserConflictName[] = "name";
 
+const char kUserNeedPassword[] = "needPassword";
+
 const char kAvatarURLKey[] = "avatarurl";
 const char kRandomAvatarKey[] = "randomAvatar";
 const char kNameOfIntroScreen[] = "intro";
@@ -243,6 +245,50 @@
                            master_key);
 }
 
+// TODO(antrim): Code duplication with previous method will be removed once
+// password sync is implemented.
+void LocallyManagedUserCreationScreen::ImportManagedUserWithPassword(
+    const std::string& user_id,
+    const std::string& password) {
+  DCHECK(controller_.get());
+  DCHECK(existing_users_.get());
+  VLOG(1) << "Importing user " << user_id;
+  DictionaryValue* user_info;
+  if (!existing_users_->GetDictionary(user_id, &user_info)) {
+    LOG(ERROR) << "Can not import non-existing user " << user_id;
+    return;
+  }
+  string16 display_name;
+  std::string master_key;
+  std::string avatar;
+  bool exists;
+  int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex;
+  user_info->GetString(ManagedUserSyncService::kName, &display_name);
+  user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key);
+  user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar);
+  user_info->GetBoolean(kUserExists, &exists);
+
+  // We should not get here with existing user selected, so just display error.
+  if (exists) {
+    actor_->ShowErrorPage(
+        l10n_util::GetStringUTF16(
+            IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE),
+        l10n_util::GetStringUTF16(
+            IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR),
+        l10n_util::GetStringUTF16(
+            IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON));
+    return;
+  }
+
+  ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
+
+  controller_->StartImport(display_name,
+                           password,
+                           avatar_index,
+                           user_id,
+                           master_key);
+}
+
 void LocallyManagedUserCreationScreen::OnManagerLoginFailure() {
   if (actor_)
     actor_->ShowManagerPasswordError();
@@ -262,10 +308,6 @@
 
   last_page_ = kNameOfNewUserParametersScreen;
 
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(::switches::kAllowCreateExistingManagedUsers))
-    return;
-
   ManagedUserSyncServiceFactory::GetForProfile(manager_profile)->
       GetManagedUsersAsync(base::Bind(
           &LocallyManagedUserCreationScreen::OnGetManagedUsers,
@@ -455,6 +497,8 @@
       ui_copy->SetString(kUserConflict, kUserConflictName);
     }
     ui_copy->SetString(ManagedUserSyncService::kName, display_name);
+    // TODO(antrim): For now mark all users as having no password.
+    ui_copy->SetBoolean(kUserNeedPassword, true);
     ui_copy->SetString("id", it.key());
 
     existing_users_->Set(it.key(), local_copy);
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
index 43be20b..4b870c2 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
@@ -71,6 +71,9 @@
       const string16& display_name,
       const std::string& managed_user_password) OVERRIDE;
   virtual void ImportManagedUser(const std::string& user_id) OVERRIDE;
+  virtual void ImportManagedUserWithPassword(
+      const std::string& user_id,
+      const std::string& password) OVERRIDE;
   virtual void AuthenticateManager(
       const std::string& manager_id,
       const std::string& manager_password) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/mock_login_display_host.h b/chrome/browser/chromeos/login/mock_login_display_host.h
index 5991c2f..5f239e8 100644
--- a/chrome/browser/chromeos/login/mock_login_display_host.h
+++ b/chrome/browser/chromeos/login/mock_login_display_host.h
@@ -27,6 +27,8 @@
   MOCK_METHOD1(SetStatusAreaVisible, void(bool));
   MOCK_METHOD0(ShowBackground, void(void));
   MOCK_METHOD0(CheckForAutoEnrollment, void(void));
+  MOCK_METHOD1(GetAutoEnrollmentCheckResult, void(
+      const GetAutoEnrollmentCheckResultCallback& callback));
   // GMock currently doesn't support move-only arguments, so we have
   // to use this hack here.
   MOCK_METHOD2(StartWizardPtr, void(const std::string&,
diff --git a/chrome/browser/chromeos/login/mock_user_manager.cc b/chrome/browser/chromeos/login/mock_user_manager.cc
index 59bb273..9d0b674 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.cc
+++ b/chrome/browser/chromeos/login/mock_user_manager.cc
@@ -9,12 +9,11 @@
 namespace chromeos {
 
 MockUserManager::MockUserManager()
-    : user_(NULL),
-      user_flow_(new DefaultUserFlow()),
+    : user_flow_(new DefaultUserFlow()),
       supervised_user_manager_(new FakeSupervisedUserManager()) {}
 
 MockUserManager::~MockUserManager() {
-  delete user_;
+  ClearUserList();
 }
 
 const UserList& MockUserManager::GetUsers() const {
@@ -22,11 +21,11 @@
 }
 
 const User* MockUserManager::GetLoggedInUser() const {
-  return user_;
+  return user_list_.empty() ? NULL : user_list_.front();
 }
 
 User* MockUserManager::GetLoggedInUser() {
-  return user_;
+  return user_list_.empty() ? NULL : user_list_.front();
 }
 
 UserList MockUserManager::GetUnlockUsers() const {
@@ -34,23 +33,23 @@
 }
 
 const std::string& MockUserManager::GetOwnerEmail() {
-  return user_->email();
+  return GetLoggedInUser()->email();
 }
 
 const User* MockUserManager::GetActiveUser() const {
-  return user_;
+  return GetLoggedInUser();
 }
 
 User* MockUserManager::GetActiveUser() {
-  return user_;
+  return GetLoggedInUser();
 }
 
 const User* MockUserManager::GetPrimaryUser() const {
-  return user_;
+  return GetLoggedInUser();
 }
 
 User* MockUserManager::GetUserByProfile(Profile* profile) const {
-  return user_;
+  return user_list_.empty() ? NULL : user_list_.front();
 }
 
 UserImageManager* MockUserManager::GetUserImageManager() {
@@ -63,10 +62,8 @@
 
 // Creates a new User instance.
 void MockUserManager::SetActiveUser(const std::string& email) {
-  delete user_;
-  user_ = User::CreateRegularUser(email);
-  user_list_.clear();
-  user_list_.push_back(user_);
+  ClearUserList();
+  AddUser(email);
 }
 
 UserFlow* MockUserManager::GetCurrentUserFlow() const {
@@ -78,11 +75,21 @@
 }
 
 User* MockUserManager::CreatePublicAccountUser(const std::string& email) {
-  delete user_;
-  user_ = User::CreatePublicAccountUser(email);
+  ClearUserList();
+  user_list_.push_back(User::CreatePublicAccountUser(email));
+  return user_list_.back();
+}
+
+void MockUserManager::AddUser(const std::string& email) {
+  user_list_.push_back(User::CreateRegularUser(email));
+}
+
+void MockUserManager::ClearUserList() {
+  // Can't use STLDeleteElements because of the protected destructor of User.
+  UserList::iterator user;
+  for (user = user_list_.begin(); user != user_list_.end(); ++user)
+    delete *user;
   user_list_.clear();
-  user_list_.push_back(user_);
-  return user_;
 }
 
 void MockUserManager::RespectLocalePreference(Profile* profile,
diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h
index eb3710c..c003769 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/mock_user_manager.h
@@ -103,14 +103,22 @@
   virtual void RespectLocalePreference(Profile* profile, const User* user) const
       OVERRIDE;
 
-  // Sets a new User instance.
+  // Sets a new User instance. Users previously created by this MockUserManager
+  // become invalid.
   void SetActiveUser(const std::string& email);
 
   // Creates a new public session user. Users previously created by this
   // MockUserManager become invalid.
   User* CreatePublicAccountUser(const std::string& email);
 
-  User* user_;
+  // Adds a new User instance to the back of the user list. Users previously
+  // created by this MockUserManager remain valid.
+  void AddUser(const std::string& email);
+
+  // Clears the user list and the active user. Users previously created by this
+  // MockUserManager become invalid.
+  void ClearUserList();
+
   scoped_ptr<UserFlow> user_flow_;
   scoped_ptr<MockUserImageManager> user_image_manager_;
   scoped_ptr<FakeSupervisedUserManager> supervised_user_manager_;
diff --git a/chrome/browser/chromeos/login/multi_profile_user_controller.cc b/chrome/browser/chromeos/login/multi_profile_user_controller.cc
index 8ba170d..1290663 100644
--- a/chrome/browser/chromeos/login/multi_profile_user_controller.cc
+++ b/chrome/browser/chromeos/login/multi_profile_user_controller.cc
@@ -9,10 +9,10 @@
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chromeos/login/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
diff --git a/chrome/browser/chromeos/login/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
index dca159f..60c31ca 100644
--- a/chrome/browser/chromeos/login/oauth2_login_verifier.cc
+++ b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
@@ -63,11 +63,10 @@
   const NetworkState* default_network =
       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
   NetworkPortalDetector* detector = NetworkPortalDetector::Get();
-  NetworkPortalDetector::CaptivePortalState state =
-      detector->GetCaptivePortalState(default_network);
   if (!default_network ||
       default_network->connection_state() == shill::kStatePortal ||
-      state.status != NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
+      (detector && detector->GetCaptivePortalState(default_network).status !=
+           NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
     // If network is offline, defer the token fetching until online.
     VLOG(1) << "Network is offline.  Deferring OAuth2 access token fetch.";
     BrowserThread::PostDelayedTask(
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index 8393329..9e6522b 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -3,130 +3,34 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
-#include "base/path_service.h"
-#include "chrome/browser/chrome_browser_main.h"
-#include "chrome/browser/chrome_browser_main_extra_parts.h"
-#include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_paths.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/chromeos_switches.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 #include "google_apis/gaia/fake_gaia.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_response.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/test/ui_controls.h"
+#include "ui/views/widget/widget.h"
 
 using namespace net::test_server;
 
-namespace {
-
-// Used to add an observer to NotificationService after it's created.
-class TestBrowserMainExtraParts
-    : public ChromeBrowserMainExtraParts,
-      public content::NotificationObserver {
- public:
-  TestBrowserMainExtraParts()
-      : webui_visible_(false),
-        browsing_data_removed_(false),
-        signin_screen_shown_(false) {}
-  virtual ~TestBrowserMainExtraParts() {}
-
-  // ChromeBrowserMainExtraParts implementation.
-  virtual void PreEarlyInitialization() OVERRIDE {
-    registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_BROWSING_DATA_REMOVED,
-                   content::NotificationService::AllSources());
-  }
-
-  void set_quit_task(const base::Closure& quit_task) { quit_task_ = quit_task; }
-
- private:
-  // Overridden from content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    if (type == chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE) {
-      LOG(INFO) << "NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE";
-      webui_visible_ = true;
-      if (browsing_data_removed_ && !signin_screen_shown_) {
-        signin_screen_shown_ = true;
-        ShowSigninScreen();
-      }
-    } else if (type == chrome::NOTIFICATION_BROWSING_DATA_REMOVED) {
-      LOG(INFO) << "chrome::NOTIFICATION_BROWSING_DATA_REMOVED";
-      browsing_data_removed_ = true;
-      if (webui_visible_ && !signin_screen_shown_) {
-        signin_screen_shown_ = true;
-        ShowSigninScreen();
-      }
-    } else if (type == chrome::NOTIFICATION_SESSION_STARTED) {
-      LOG(INFO) << "chrome::NOTIFICATION_SESSION_STARTED";
-      quit_task_.Run();
-    } else {
-      NOTREACHED();
-    }
-  }
-
-  void ShowSigninScreen() {
-    chromeos::ExistingUserController* controller =
-        chromeos::ExistingUserController::current_controller();
-    CHECK(controller);
-    chromeos::WebUILoginDisplay* webui_login_display =
-        static_cast<chromeos::WebUILoginDisplay*>(
-            controller->login_display());
-    CHECK(webui_login_display);
-    webui_login_display->ShowSigninScreenForCreds("username", "password");
-    // TODO(glotov): mock GAIA server (test_server()) should support
-    // username/password configuration.
-  }
-
-  bool webui_visible_, browsing_data_removed_, signin_screen_shown_;
-  content::NotificationRegistrar registrar_;
-  base::Closure quit_task_;
-  GURL gaia_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestBrowserMainExtraParts);
-};
-
-class TestContentBrowserClient : public chrome::ChromeContentBrowserClient {
- public:
-  TestContentBrowserClient() {}
-  virtual ~TestContentBrowserClient() {}
-
-  virtual content::BrowserMainParts* CreateBrowserMainParts(
-      const content::MainFunctionParams& parameters) OVERRIDE {
-    ChromeBrowserMainParts* main_parts = static_cast<ChromeBrowserMainParts*>(
-        ChromeContentBrowserClient::CreateBrowserMainParts(parameters));
-
-    browser_main_extra_parts_ = new TestBrowserMainExtraParts();
-    main_parts->AddParts(browser_main_extra_parts_);
-    return main_parts;
-  }
-
-  TestBrowserMainExtraParts* browser_main_extra_parts_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestContentBrowserClient);
-};
+namespace chromeos {
 
 class OobeTest : public InProcessBrowserTest {
- protected:
+ public:
+  OobeTest() {}
+  virtual ~OobeTest() {}
+
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     command_line->AppendSwitch(chromeos::switches::kLoginManager);
     command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
@@ -137,12 +41,6 @@
         chromeos::switches::kAuthExtensionPath, "gaia_auth");
   }
 
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    content_browser_client_.reset(new TestContentBrowserClient());
-    original_content_browser_client_ = content::SetBrowserClientForTesting(
-        content_browser_client_.get());
-  }
-
   virtual void SetUpOnMainThread() OVERRIDE {
     CHECK(embedded_test_server()->InitializeAndWaitUntilReady());
     embedded_test_server()->RegisterRequestHandler(
@@ -153,9 +51,32 @@
         ::switches::kGaiaUrl, embedded_test_server()->base_url().spec());
   }
 
-  scoped_ptr<TestContentBrowserClient> content_browser_client_;
-  content::ContentBrowserClient* original_content_browser_client_;
+  virtual void CleanUpOnMainThread() OVERRIDE {
+    // If the login display is still showing, exit gracefully.
+    if (LoginDisplayHostImpl::default_host()) {
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(&chrome::AttemptExit));
+      content::RunMessageLoop();
+    }
+  }
+
+  chromeos::WebUILoginDisplay* GetLoginDisplay() {
+    chromeos::ExistingUserController* controller =
+        chromeos::ExistingUserController::current_controller();
+    CHECK(controller);
+    return static_cast<chromeos::WebUILoginDisplay*>(
+        controller->login_display());
+  }
+
+  views::Widget* GetLoginWindowWidget() {
+    return static_cast<chromeos::LoginDisplayHostImpl*>(
+        chromeos::LoginDisplayHostImpl::default_host())
+        ->login_window_for_test();
+  }
+
+ private:
   FakeGaia fake_gaia_;
+  DISALLOW_COPY_AND_ASSIGN(OobeTest);
 };
 
 IN_PROC_BROWSER_TEST_F(OobeTest, NewUser) {
@@ -165,11 +86,39 @@
   CHECK(wizard_controller);
   wizard_controller->SkipToLoginForTesting();
 
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner->QuitClosure());
-  runner->Run();
+  content::WindowedNotificationObserver(
+    chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+    content::NotificationService::AllSources()).Wait();
+
+  // TODO(glotov): mock GAIA server (test_server()) should support
+  // username/password configuration.
+  GetLoginDisplay()->ShowSigninScreenForCreds("username", "password");
+
+  content::WindowedNotificationObserver(
+    chrome::NOTIFICATION_SESSION_STARTED,
+    content::NotificationService::AllSources()).Wait();
 }
 
-}  // namespace
+IN_PROC_BROWSER_TEST_F(OobeTest, Accelerator) {
+  chromeos::WizardController::SkipPostLoginScreensForTesting();
+  chromeos::WizardController* wizard_controller =
+      chromeos::WizardController::default_controller();
+  CHECK(wizard_controller);
+  wizard_controller->SkipToLoginForTesting();
+
+  content::WindowedNotificationObserver(
+    chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+    content::NotificationService::AllSources()).Wait();
+
+  gfx::NativeWindow login_window = GetLoginWindowWidget()->GetNativeWindow();
+
+  ui_controls::SendKeyPress(login_window,
+                            ui::VKEY_E,
+                            true,    // control
+                            false,   // shift
+                            true,    // alt
+                            false);  // command
+  OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_ENROLLMENT).Wait();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h b/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h
index 234ce71..9205444 100644
--- a/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h
+++ b/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h
@@ -17,6 +17,7 @@
     APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE,
     APP_LAUNCH_STATE_PREPARING_NETWORK,
     APP_LAUNCH_STATE_INSTALLING_APPLICATION,
+    APP_LAUNCH_STATE_WAITING_APP_WINDOW,
   };
 
   class Delegate {
diff --git a/chrome/browser/chromeos/login/supervised_user_manager_impl.cc b/chrome/browser/chromeos/login/supervised_user_manager_impl.cc
index d5533ec..b4f8485 100644
--- a/chrome/browser/chromeos/login/supervised_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/supervised_user_manager_impl.cc
@@ -6,13 +6,13 @@
 
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user_manager_impl.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_auth_util.h"
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc
new file mode 100644
index 0000000..456bd4c
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc
@@ -0,0 +1,55 @@
+// Copyright 2013 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/login/test/oobe_screen_waiter.h"
+
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+OobeScreenWaiter::OobeScreenWaiter(OobeDisplay::Screen expected_screen)
+    : waiting_for_screen_(false),
+      expected_screen_(expected_screen) {
+}
+
+OobeScreenWaiter::~OobeScreenWaiter() {
+  if (waiting_for_screen_) {
+    GetOobeUI()->RemoveObserver(this);
+  }
+}
+
+void OobeScreenWaiter::Wait() {
+  if (GetOobeUI()->current_screen() == expected_screen_) {
+    return;
+  }
+
+  waiting_for_screen_ = true;
+  GetOobeUI()->AddObserver(this);
+
+  runner_ = new content::MessageLoopRunner;
+  runner_->Run();
+  ASSERT_EQ(expected_screen_, GetOobeUI()->current_screen());
+  ASSERT_FALSE(waiting_for_screen_);
+}
+
+void OobeScreenWaiter::OnCurrentScreenChanged(
+    OobeDisplay::Screen current_screen,
+    OobeDisplay::Screen new_screen) {
+  if (waiting_for_screen_ && new_screen == expected_screen_) {
+    runner_->Quit();
+    waiting_for_screen_ = false;
+    GetOobeUI()->RemoveObserver(this);
+  }
+}
+
+OobeUI* OobeScreenWaiter::GetOobeUI() {
+  OobeUI* oobe_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
+      chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI();
+  CHECK(oobe_ui);
+  return oobe_ui;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.h b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h
new file mode 100644
index 0000000..4704f37
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_LOGIN_TEST_OOBE_SCREEN_WAITER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_OOBE_SCREEN_WAITER_H_
+
+#include "base/basictypes.h"
+#include "chrome/browser/chromeos/login/oobe_display.h"
+#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+
+namespace content {
+class MessageLoopRunner;
+}
+
+namespace chromeos {
+
+// A waiter that blocks until the expected oobe screen is reached.
+class OobeScreenWaiter : public OobeUI::Observer {
+ public:
+  explicit OobeScreenWaiter(OobeDisplay::Screen expected_screen);
+  virtual ~OobeScreenWaiter();
+
+  void Wait();
+
+  // OobeUI::Observer implementation:
+  virtual void OnCurrentScreenChanged(
+        OobeDisplay::Screen current_screen,
+        OobeDisplay::Screen new_screen) OVERRIDE;
+
+ private:
+  OobeUI* GetOobeUI();
+
+  bool waiting_for_screen_;
+  OobeDisplay::Screen expected_screen_;
+  scoped_refptr<content::MessageLoopRunner> runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(OobeScreenWaiter);
+};
+
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_OOBE_SCREEN_WAITER_H_
diff --git a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
index f89e905..3fba5fa 100644
--- a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
@@ -9,13 +9,13 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/default_user_images.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/user_image_manager_impl.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
index aeddcdc..b7e284f 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.cc
@@ -14,6 +14,7 @@
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/chromeos/login/user_image.h"
 #include "chrome/browser/chromeos/login/user_image_sync_observer.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_downloader.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/chromeos/login/user_image_sync_observer.cc b/chrome/browser/chromeos/login/user_image_sync_observer.cc
index 8f22012..6d1338c 100644
--- a/chrome/browser/chromeos/login/user_image_sync_observer.cc
+++ b/chrome/browser/chromeos/login/user_image_sync_observer.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/default_user_images.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index e332863..3f77240 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -44,7 +45,6 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service.h"
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index eead099..224d825 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -17,6 +17,7 @@
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -312,6 +312,7 @@
       break;
     }
     case chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED: {
+      NotifyAnimationFinished();
       if (should_cache_wallpaper_) {
         BrowserThread::PostDelayedTask(
             BrowserThread::UI, FROM_HERE,
@@ -605,6 +606,19 @@
   SetUserWallpaper(last_selected_user_);
 }
 
+void WallpaperManager::AddObserver(WallpaperManager::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WallpaperManager::RemoveObserver(WallpaperManager::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void WallpaperManager::NotifyAnimationFinished() {
+  FOR_EACH_OBSERVER(
+      Observer, observers_, OnWallpaperAnimationFinished(last_selected_user_));
+}
+
 // WallpaperManager, private: --------------------------------------------------
 
 void WallpaperManager::CacheUsersWallpapers() {
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h
index 3a6a0ff..ac8379c 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/wallpaper_manager.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/login/user.h"
@@ -80,6 +81,12 @@
     DISALLOW_COPY_AND_ASSIGN(TestApi);
   };
 
+  class Observer {
+   public:
+    virtual ~Observer() {}
+    virtual void OnWallpaperAnimationFinished(const std::string& email) = 0;
+  };
+
   static WallpaperManager* Get();
 
   WallpaperManager();
@@ -188,6 +195,12 @@
   // current display's resolution.
   void UpdateWallpaper();
 
+  // Adds given observer to the list.
+  void AddObserver(Observer* observer);
+
+  // Removes given observer from the list.
+  void RemoveObserver(Observer* observer);
+
  private:
   friend class TestApi;
   friend class WallpaperManagerBrowserTest;
@@ -306,6 +319,9 @@
                  bool update_wallpaper,
                  const base::FilePath& wallpaper_path);
 
+  // Notify all registed observers.
+  void NotifyAnimationFinished();
+
   // The number of loaded wallpapers.
   int loaded_wallpapers_;
 
@@ -342,6 +358,8 @@
 
   content::NotificationRegistrar registrar_;
 
+  ObserverList<Observer> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(WallpaperManager);
 };
 
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
index bf7c640..eec3a0f 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
@@ -13,12 +13,12 @@
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/chromeos/login/webui_login_display.cc b/chrome/browser/chromeos/login/webui_login_display.cc
index e9a8675..634b61a 100644
--- a/chrome/browser/chromeos/login/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/webui_login_display.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 
+#include "ash/shell.h"
 #include "ash/wm/user_activity_detector.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc
index 8bd3004..961f8a2 100644
--- a/chrome/browser/chromeos/login/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/webui_login_view.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
 #include "chrome/browser/media/media_stream_infobar_delegate.h"
 #include "chrome/browser/password_manager/password_manager.h"
 #include "chrome/browser/password_manager/password_manager_delegate_impl.h"
@@ -152,6 +153,7 @@
   Profile* signin_profile = ProfileHelper::GetSigninProfile();
   auth_extension_.reset(new ScopedGaiaAuthExtension(signin_profile));
   webui_login_ = new views::WebView(signin_profile);
+  webui_login_->set_allow_accelerators(true);
   AddChildView(webui_login_);
 
   WebContents* web_contents = webui_login_->GetWebContents();
@@ -167,6 +169,7 @@
       SetDelegate(this);
 
   web_contents->SetDelegate(this);
+  extensions::ExtensionWebContentsObserver::CreateForWebContents(web_contents);
   WebContentsObserver::Observe(web_contents);
   renderer_preferences_util::UpdateFromSystemSettings(
       web_contents->GetMutableRendererPrefs(),
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.cc b/chrome/browser/chromeos/login/webui_screen_locker.cc
index ee31aab..f66f9d5 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/webui_screen_locker.cc
@@ -27,6 +27,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/aura/client/capture_client.h"
+#include "ui/aura/root_window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/gfx/screen.h"
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc
index 352360a..8ad3a6b 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.cc
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.cc
@@ -169,13 +169,9 @@
 
 OomPriorityManager::OomPriorityManager()
     : focused_tab_pid_(0),
+      low_memory_listener_(new LowMemoryListener(this)),
       discard_count_(0),
       recent_tab_discard_(false) {
-  // We only need the low memory observer if we want to discard tabs.
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kNoDiscardTabs))
-    low_memory_listener_.reset(new LowMemoryListener(this));
-
   registrar_.Add(this,
       content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
       content::NotificationService::AllBrowserContextsAndSources());
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.h b/chrome/browser/chromeos/memory/oom_priority_manager.h
index 2834291..4fea9ed 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.h
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.h
@@ -143,8 +143,7 @@
   ProcessScoreMap pid_to_oom_score_;
   base::ProcessHandle focused_tab_pid_;
 
-  // Observer for the kernel low memory signal.  NULL if tab discarding is
-  // disabled.
+  // Observer for the kernel low memory signal.
   scoped_ptr<LowMemoryListener> low_memory_listener_;
 
   // Wall-clock time when the priority manager started running.
@@ -168,6 +167,6 @@
   DISALLOW_COPY_AND_ASSIGN(OomPriorityManager);
 };
 
-}  // namespace chrome
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc
index 32d88f4..0cd96b2 100644
--- a/chrome/browser/chromeos/net/onc_utils.cc
+++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -20,6 +20,7 @@
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_profile.h"
 #include "chromeos/network/network_profile_handler.h"
+#include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/network_ui_data.h"
 #include "chromeos/network/onc/onc_normalizer.h"
@@ -203,6 +204,7 @@
     return;
   }
 
+  bool ethernet_not_found = false;
   for (base::ListValue::const_iterator it = expanded_networks->begin();
        it != expanded_networks->end();
        ++it) {
@@ -232,11 +234,34 @@
     shill_dict->SetStringWithoutPathExpansion(shill::kProfileProperty,
                                               profile->path);
 
-    NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
-        *shill_dict,
-        network_handler::StringResultCallback(),
-        network_handler::ErrorCallback());
+    std::string type;
+    shill_dict->GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
+    NetworkConfigurationHandler* config_handler =
+        NetworkHandler::Get()->network_configuration_handler();
+    if (NetworkTypePattern::Ethernet().MatchesType(type)) {
+      // Ethernet has to be configured using an existing Ethernet service.
+      const NetworkState* ethernet =
+          NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
+              NetworkTypePattern::Ethernet());
+      if (ethernet) {
+        config_handler->SetProperties(ethernet->path(),
+                                      *shill_dict,
+                                      base::Closure(),
+                                      network_handler::ErrorCallback());
+      } else {
+        ethernet_not_found = true;
+      }
+
+    } else {
+      config_handler->CreateConfiguration(
+          *shill_dict,
+          network_handler::StringResultCallback(),
+          network_handler::ErrorCallback());
+    }
   }
+
+  if (ethernet_not_found)
+    *error = "No Ethernet available to configure.";
 }
 
 const base::DictionaryValue* FindPolicyForActiveUser(
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
index 761c82f..cc928d1 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/callback.h"
 #include "base/prefs/pref_value_map.h"
+#include "base/values.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
 #include "chrome/browser/policy/policy_error_map.h"
 #include "chrome/browser/policy/policy_map.h"
@@ -18,6 +19,58 @@
 
 namespace {
 
+// Test cases for the screen magnifier type policy setting.
+class ScreenMagnifierPolicyHandlerTest : public testing::Test {
+ protected:
+  PolicyMap policy_;
+  PrefValueMap prefs_;
+  ScreenMagnifierPolicyHandler handler_;
+};
+
+TEST_F(ScreenMagnifierPolicyHandlerTest, Default) {
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+  EXPECT_FALSE(prefs_.GetValue(prefs::kScreenMagnifierEnabled, NULL));
+  EXPECT_FALSE(prefs_.GetValue(prefs::kScreenMagnifierType, NULL));
+}
+
+TEST_F(ScreenMagnifierPolicyHandlerTest, Disabled) {
+  policy_.Set(key::kScreenMagnifierType,
+              POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER,
+              base::Value::CreateIntegerValue(0),
+              NULL);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+
+  const base::Value* enabled = NULL;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kScreenMagnifierEnabled, &enabled));
+  ASSERT_TRUE(enabled);
+  EXPECT_TRUE(base::FundamentalValue(false).Equals(enabled));
+
+  const base::Value* type = NULL;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kScreenMagnifierType, &type));
+  ASSERT_TRUE(type);
+  EXPECT_TRUE(base::FundamentalValue(0).Equals(type));
+}
+
+TEST_F(ScreenMagnifierPolicyHandlerTest, Enabled) {
+  policy_.Set(key::kScreenMagnifierType,
+              POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER,
+              base::Value::CreateIntegerValue(1),
+              NULL);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+
+  const base::Value* enabled = NULL;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kScreenMagnifierEnabled, &enabled));
+  ASSERT_TRUE(enabled);
+  EXPECT_TRUE(base::FundamentalValue(true).Equals(enabled));
+
+  const base::Value* type = NULL;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kScreenMagnifierType, &type));
+  ASSERT_TRUE(type);
+  EXPECT_TRUE(base::FundamentalValue(1).Equals(type));
+}
+
 const char kLoginScreenPowerManagementPolicy[] =
     "{"
     "  \"AC\": {"
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 7ee648e..ff40047 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -58,6 +58,11 @@
   loop->Quit();
 }
 
+void CopyTokenService(chromeos::DeviceOAuth2TokenService** out_token_service,
+                      chromeos::DeviceOAuth2TokenService* in_token_service) {
+  *out_token_service = in_token_service;
+}
+
 class DeviceCloudPolicyManagerChromeOSTest
     : public chromeos::DeviceSettingsTestBase {
  protected:
@@ -103,10 +108,9 @@
     TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(
         request_context_getter_.get());
     TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
-    chromeos::DeviceOAuth2TokenServiceFactory::Initialize();
-    // This is needed as SystemSaltGetter is used for encrypting tokens in
-    // CryptohomeTokenEncryptor.
+    // SystemSaltGetter is used in DeviceOAuth2TokenServiceFactory.
     chromeos::SystemSaltGetter::Initialize();
+    chromeos::DeviceOAuth2TokenServiceFactory::Initialize();
     url_fetcher_response_code_ = 200;
     url_fetcher_response_string_ = "{\"access_token\":\"accessToken4Test\","
                                    "\"expires_in\":1234,"
@@ -366,6 +370,17 @@
     }
     base::RunLoop().RunUntilIdle();
 
+    if (done_)
+      return;
+
+    // Process robot refresh token store.
+    chromeos::DeviceOAuth2TokenService* token_service = NULL;
+    chromeos::DeviceOAuth2TokenServiceFactory::Get(
+        base::Bind(&CopyTokenService, &token_service));
+    base::RunLoop().RunUntilIdle();
+    ASSERT_TRUE(token_service);
+    EXPECT_EQ("refreshToken4Test", token_service->GetRefreshToken(""));
+
     // Process policy store.
     device_settings_test_helper_.set_store_result(store_result_);
     device_settings_test_helper_.FlushStore();
@@ -375,21 +390,11 @@
     if (done_)
       return;
 
-    // Key installation, policy load and refresh token save.
+    // Key installation and policy load.
     device_settings_test_helper_.set_policy_blob(loaded_blob_);
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetNewSigningKey());
     ReloadDeviceSettings();
-
-    if (done_)
-      return;
-
-    chromeos::DeviceOAuth2TokenService* token_service =
-        chromeos::DeviceOAuth2TokenServiceFactory::Get();
-    // Process robot refresh token store.
-    EXPECT_EQ(
-        "refreshToken4Test",
-        token_service->GetRefreshToken(token_service->GetRobotAccountId()));
   }
 
   bool is_auto_enrollment_;
@@ -451,35 +456,45 @@
   EXPECT_EQ(DM_STATUS_REQUEST_FAILED, status_.client_status());
 }
 
-// Policy server implementations are not required to support robot auth
-// tokens, so the following 4 Robot* tests verify that enrollment succeeds
-// even if the robot auth token fetch fails.
 TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest,
        RobotAuthCodeFetchFailed) {
   robot_auth_fetch_status_ = DM_STATUS_REQUEST_FAILED;
   RunTest();
-  ExpectSuccessfulEnrollment();
+  ExpectFailedEnrollment(EnrollmentStatus::STATUS_ROBOT_AUTH_FETCH_FAILED);
 }
 
 TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest,
        RobotRefreshTokenFetchResponseCodeFailed) {
   url_fetcher_response_code_ = 400;
   RunTest();
-  ExpectSuccessfulEnrollment();
+  ExpectFailedEnrollment(EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED);
+  EXPECT_EQ(400, status_.http_status());
 }
 
 TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest,
        RobotRefreshTokenFetchResponseStringFailed) {
   url_fetcher_response_string_ = "invalid response json";
   RunTest();
-  ExpectSuccessfulEnrollment();
+  ExpectFailedEnrollment(EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED);
 }
 
 TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest, RobotRefreshSaveFailed) {
   // Without a DeviceOAuth2TokenService, the refresh token can't be saved.
   chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
   RunTest();
-  ExpectSuccessfulEnrollment();
+  ExpectFailedEnrollment(EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED);
+}
+
+TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest,
+       RobotRefreshEncryptionFailed) {
+  // The encryption lib is a noop for tests, but empty results from encryption
+  // is an error, so we simulate an encryption error by returning an empty
+  // refresh token.
+  url_fetcher_response_string_ = "{\"access_token\":\"accessToken4Test\","
+                                 "\"expires_in\":1234,"
+                                 "\"refresh_token\":\"\"}";
+  RunTest();
+  ExpectFailedEnrollment(EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED);
 }
 
 TEST_F(DeviceCloudPolicyManagerChromeOSEnrollmentTest, PolicyFetchFailed) {
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
index 4381ce4..8f331df 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/policy/cloud/cloud_policy_core.h"
 #include "chrome/browser/policy/cloud/cloud_policy_service.h"
 #include "chrome/browser/policy/policy_bundle.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index a02824c..68ebdd5 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -376,6 +376,13 @@
                         container.report_network_interfaces()),
                     NULL);
     }
+    if (container.has_report_users()) {
+      policies->Set(key::kReportDeviceUsers,
+                    POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_MACHINE,
+                    Value::CreateBooleanValue(container.report_users()),
+                    NULL);
+    }
   }
 }
 
@@ -675,6 +682,18 @@
                     NULL);
     }
   }
+  if (policy.has_auto_clean_up_settings()) {
+    const em::AutoCleanupSettigsProto& container(
+        policy.auto_clean_up_settings());
+    if (container.has_clean_up_strategy()) {
+      policies->Set(key::kAutoCleanUpStrategy,
+                    POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_MACHINE,
+                    Value::CreateStringValue(
+                        container.clean_up_strategy()),
+                    NULL);
+    }
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index c77d3cf..1fc6cb7 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -13,11 +13,16 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/network/device_state.h"
@@ -67,6 +72,9 @@
   return (Time::FromUTCExploded(exploded) - Time::UnixEpoch()).InMilliseconds();
 }
 
+// Maximum number of users to report.
+const int kMaxUserCount = 5;
+
 }  // namespace
 
 namespace policy {
@@ -130,6 +138,7 @@
       report_boot_mode_(false),
       report_location_(false),
       report_network_interfaces_(false),
+      report_users_(false),
       context_(new Context()) {
   if (location_update_requester) {
     location_update_requester_ = *location_update_requester;
@@ -158,6 +167,8 @@
       chromeos::kReportDeviceLocation, callback);
   network_interfaces_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kReportDeviceNetworkInterfaces, callback);
+  users_subscription_ = cros_settings_->AddSettingsObserver(
+      chromeos::kReportDeviceUsers, callback);
 
   // The last known location is persisted in local state. This makes location
   // information available immediately upon startup and avoids the need to
@@ -230,6 +241,8 @@
       chromeos::kReportDeviceLocation, &report_location_);
   cros_settings_->GetBoolean(
       chromeos::kReportDeviceNetworkInterfaces, &report_network_interfaces_);
+  cros_settings_->GetBoolean(
+      chromeos::kReportDeviceUsers, &report_users_);
 
   if (report_location_) {
     ScheduleGeolocationUpdateRequest();
@@ -448,6 +461,32 @@
   }
 }
 
+void DeviceStatusCollector::GetUsers(em::DeviceStatusReportRequest* request) {
+  BrowserPolicyConnector* connector =
+      g_browser_process->browser_policy_connector();
+  bool found_managed_user = false;
+  const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers();
+  chromeos::UserList::const_iterator user;
+  for (user = users.begin(); user != users.end(); ++user) {
+    em::DeviceUser* device_user = request->add_user();
+    const std::string& email = (*user)->email();
+    if (connector->GetUserAffiliation(email) == USER_AFFILIATION_MANAGED) {
+      device_user->set_type(em::DeviceUser::USER_TYPE_MANAGED);
+      device_user->set_email(email);
+      found_managed_user = true;
+    } else {
+      device_user->set_type(em::DeviceUser::USER_TYPE_UNMANAGED);
+      // Do not report the email address of unmanaged users.
+    }
+
+    // Add only kMaxUserCount entries, unless no managed users are found in the
+    // first kMaxUserCount users. In that case, continue until at least one
+    // managed user is found.
+    if (request->user_size() >= kMaxUserCount && found_managed_user)
+      break;
+  }
+}
+
 void DeviceStatusCollector::GetStatus(em::DeviceStatusReportRequest* request) {
   // TODO(mnissler): Remove once the old cloud policy stack is retired. The old
   // stack doesn't support reporting successful submissions back to here, so
@@ -473,6 +512,9 @@
   if (report_network_interfaces_)
     GetNetworkInterfaces(status);
 
+  if (report_users_)
+    GetUsers(status);
+
   return true;
 }
 
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h
index 95c24b0..6ee8df1 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -147,6 +147,8 @@
       enterprise_management::DeviceStatusReportRequest* request);
   void GetNetworkInterfaces(
       enterprise_management::DeviceStatusReportRequest* request);
+  void GetUsers(
+      enterprise_management::DeviceStatusReportRequest* request);
 
   // Update the cached values of the reporting settings.
   void UpdateReportingSettings();
@@ -201,6 +203,7 @@
   bool report_boot_mode_;
   bool report_location_;
   bool report_network_interfaces_;
+  bool report_users_;
 
   scoped_refptr<Context> context_;
 
@@ -214,6 +217,8 @@
       location_subscription_;
   scoped_ptr<chromeos::CrosSettings::ObserverSubscription>
       network_interfaces_subscription_;
+  scoped_ptr<chromeos::CrosSettings::ObserverSubscription>
+      users_subscription_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceStatusCollector);
 };
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
index 79ea72c..8c47dff 100644
--- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -12,9 +12,13 @@
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -147,7 +151,9 @@
     : message_loop_(base::MessageLoop::TYPE_UI),
       ui_thread_(content::BrowserThread::UI, &message_loop_),
       file_thread_(content::BrowserThread::FILE, &message_loop_),
-      io_thread_(content::BrowserThread::IO, &message_loop_) {
+      io_thread_(content::BrowserThread::IO, &message_loop_),
+      user_manager_(new chromeos::MockUserManager()),
+      user_manager_enabler_(user_manager_) {
     // Run this test with a well-known timezone so that Time::LocalMidnight()
     // returns the same values on all machines.
     scoped_ptr<base::Environment> env(base::Environment::Create());
@@ -167,6 +173,13 @@
         cros_settings_->RemoveSettingsProvider(device_settings_provider_));
     cros_settings_->AddSettingsProvider(&stub_settings_provider_);
 
+    // Set up fake install attributes.
+    StubEnterpriseInstallAttributes* attributes =
+        new StubEnterpriseInstallAttributes();
+    attributes->SetDomain("managed.com");
+    attributes->SetRegistrationUser("user@managed.com");
+    BrowserPolicyConnector::SetInstallAttributesForTesting(attributes);
+
     RestartStatusCollector();
   }
 
@@ -252,6 +265,8 @@
   chromeos::CrosSettings* cros_settings_;
   chromeos::CrosSettingsProvider* device_settings_provider_;
   chromeos::StubCrosSettingsProvider stub_settings_provider_;
+  chromeos::MockUserManager* user_manager_;
+  chromeos::ScopedUserManagerEnabler user_manager_enabler_;
   em::DeviceStatusReportRequest status_;
   scoped_ptr<TestingDeviceStatusCollector> status_collector_;
 };
@@ -586,6 +601,59 @@
   CheckThatALocationErrorIsReported();
 }
 
+TEST_F(DeviceStatusCollectorTest, ReportUsers) {
+  user_manager_->AddUser("user0@managed.com");
+  user_manager_->AddUser("user1@managed.com");
+  user_manager_->AddUser("user2@managed.com");
+  user_manager_->AddUser("user3@unmanaged.com");
+  user_manager_->AddUser("user4@managed.com");
+  user_manager_->AddUser("user5@managed.com");
+
+  // Verify that users are not reported by default.
+  GetStatus();
+  EXPECT_EQ(0, status_.user_size());
+
+  // Verify that users are reported after enabling the setting.
+  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, true);
+  GetStatus();
+  EXPECT_EQ(5, status_.user_size());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(0).type());
+  EXPECT_EQ("user0@managed.com", status_.user(0).email());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(1).type());
+  EXPECT_EQ("user1@managed.com", status_.user(1).email());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(2).type());
+  EXPECT_EQ("user2@managed.com", status_.user(2).email());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED, status_.user(3).type());
+  EXPECT_FALSE(status_.user(3).has_email());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(4).type());
+  EXPECT_EQ("user4@managed.com", status_.user(4).email());
+
+  // Verify that users are no longer reported if setting is disabled.
+  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, false);
+  GetStatus();
+  EXPECT_EQ(0, status_.user_size());
+}
+
+TEST_F(DeviceStatusCollectorTest, ReportManagedUser) {
+  // Verify that at least one managed user is reported regardless of list size.
+  user_manager_->AddUser("user0@unmanaged.com");
+  user_manager_->AddUser("user1@unmanaged.com");
+  user_manager_->AddUser("user2@unmanaged.com");
+  user_manager_->AddUser("user3@unmanaged.com");
+  user_manager_->AddUser("user4@unmanaged.com");
+  user_manager_->AddUser("user5@unmanaged.com");
+  user_manager_->AddUser("user6@managed.com");
+  user_manager_->AddUser("user7@managed.com");
+
+  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, true);
+  GetStatus();
+  EXPECT_EQ(7, status_.user_size());
+  for (int i = 0; i < 6; ++i)
+    EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED, status_.user(i).type());
+  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(6).type());
+  EXPECT_EQ("user6@managed.com", status_.user(6).email());
+}
+
 // Fake device state.
 struct FakeDeviceData {
   const char* device_path;
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index 182b46a..49f97a8 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "net/http/http_status_code.h"
 
 namespace em = enterprise_management;
 
@@ -53,7 +54,7 @@
       device_mode_(DEVICE_MODE_NOT_SET),
       enrollment_step_(STEP_PENDING),
       lockbox_init_duration_(0),
-      weak_factory_(this) {
+      weak_ptr_factory_(this) {
   CHECK(!client_->is_registered());
   CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
   store_->AddObserver(this);
@@ -110,7 +111,7 @@
   validator->ValidateInitialKey();
   validator.release()->StartValidation(
       base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated,
-                 weak_factory_.GetWeakPtr()));
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
@@ -139,12 +140,9 @@
   DCHECK_EQ(client_.get(), client);
 
   if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) {
-    LOG(WARNING) << "API authentication code fetch failed: "
-                 << client_->status();
-    // Robot auth tokens are currently optional.  Skip fetching the refresh
-    // token and jump directly to the lock device step.
-    robot_refresh_token_.clear();
-    DoLockDeviceStep();
+    LOG(ERROR) << "API authentication code fetch failed: "
+               << client_->status();
+    ReportResult(EnrollmentStatus::ForRobotAuthFetchError(client_->status()));
   } else if (enrollment_step_ < STEP_POLICY_FETCH) {
     ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
   } else {
@@ -161,14 +159,6 @@
     // registration rolling again after the store finishes loading.
     AttemptRegistration();
   } else if (enrollment_step_ == STEP_STORE_POLICY) {
-    // Store the robot API auth refresh token.
-    // Currently optional, so always return success.
-    chromeos::DeviceOAuth2TokenService* token_service =
-        chromeos::DeviceOAuth2TokenServiceFactory::Get();
-    if (token_service && !robot_refresh_token_.empty()) {
-      token_service->SetAndSaveRefreshToken(robot_refresh_token_);
-
-    }
     ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
   }
 }
@@ -233,12 +223,8 @@
     int expires_in_seconds) {
   CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
 
-  robot_refresh_token_ = refresh_token;
+  refresh_token_ = refresh_token;
 
-  DoLockDeviceStep();
-}
-
-void EnrollmentHandlerChromeOS::DoLockDeviceStep() {
   enrollment_step_ = STEP_LOCK_DEVICE,
   StartLockDevice(username_, device_mode_, device_id_);
 }
@@ -254,15 +240,20 @@
 // GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request.
 void EnrollmentHandlerChromeOS::OnOAuthError() {
   CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
-  DoLockDeviceStep();
+  // OnOAuthError is only called if the request is bad (malformed) or the
+  // response is bad (empty access token returned).
+  LOG(ERROR) << "OAuth protocol error while fetching API refresh token.";
+  ReportResult(
+      EnrollmentStatus::ForRobotRefreshFetchError(net::HTTP_BAD_REQUEST));
 }
 
 // GaiaOAuthClient::Delegate network error when fetching refresh token.
 void EnrollmentHandlerChromeOS::OnNetworkError(int response_code) {
+  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
   LOG(ERROR) << "Network error while fetching API refresh token: "
              << response_code;
-  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
-  DoLockDeviceStep();
+  ReportResult(
+      EnrollmentStatus::ForRobotRefreshFetchError(response_code));
 }
 
 void EnrollmentHandlerChromeOS::StartLockDevice(
@@ -271,12 +262,12 @@
     const std::string& device_id) {
   CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
   // Since this method is also called directly.
-  weak_factory_.InvalidateWeakPtrs();
+  weak_ptr_factory_.InvalidateWeakPtrs();
 
   install_attributes_->LockDevice(
       user, device_mode, device_id,
       base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
-                 weak_factory_.GetWeakPtr(),
+                 weak_ptr_factory_.GetWeakPtr(),
                  user,
                  device_mode,
                  device_id));
@@ -290,8 +281,11 @@
   CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
   switch (lock_result) {
     case EnterpriseInstallAttributes::LOCK_SUCCESS:
-      enrollment_step_ = STEP_STORE_POLICY;
-      store_->InstallInitialPolicy(*policy_);
+      // Get the token service so we can store our robot refresh token.
+      enrollment_step_ = STEP_STORE_ROBOT_AUTH;
+      chromeos::DeviceOAuth2TokenServiceFactory::Get(
+          base::Bind(&EnrollmentHandlerChromeOS::DidGetTokenService,
+                     weak_ptr_factory_.GetWeakPtr()));
       return;
     case EnterpriseInstallAttributes::LOCK_NOT_READY:
       // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
@@ -303,7 +297,7 @@
         base::MessageLoop::current()->PostDelayedTask(
             FROM_HERE,
             base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice,
-                       weak_factory_.GetWeakPtr(),
+                       weak_ptr_factory_.GetWeakPtr(),
                        user, device_mode, device_id),
             base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
         lockbox_init_duration_ += kLockRetryIntervalMs;
@@ -329,11 +323,33 @@
       EnrollmentStatus::STATUS_LOCK_ERROR));
 }
 
+void EnrollmentHandlerChromeOS::DidGetTokenService(
+    chromeos::DeviceOAuth2TokenService* token_service) {
+  CHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_);
+  // Store the robot API auth refresh token.
+  if (!token_service) {
+    LOG(ERROR) << "Failed to store API refresh token (no token service).";
+    ReportResult(EnrollmentStatus::ForStatus(
+        EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED));
+    return;
+  }
+
+  if (!token_service->SetAndSaveRefreshToken(refresh_token_)) {
+    LOG(ERROR) << "Failed to store API refresh token.";
+    ReportResult(EnrollmentStatus::ForStatus(
+        EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED));
+    return;
+  }
+
+  enrollment_step_ = STEP_STORE_POLICY;
+  store_->InstallInitialPolicy(*policy_);
+}
+
 void EnrollmentHandlerChromeOS::Stop() {
   if (client_.get())
     client_->RemoveObserver(this);
   enrollment_step_ = STEP_FINISHED;
-  weak_factory_.InvalidateWeakPtrs();
+  weak_ptr_factory_.InvalidateWeakPtrs();
   completion_callback_.Reset();
 }
 
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
index 74b0fd1..7730313 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -23,6 +23,10 @@
 class SequencedTaskRunner;
 }
 
+namespace chromeos {
+class DeviceOAuth2TokenService;
+}
+
 namespace enterprise_management {
 class PolicyFetchResponse;
 }
@@ -105,6 +109,7 @@
     STEP_ROBOT_AUTH_FETCH,    // Fetching device API auth code.
     STEP_ROBOT_AUTH_REFRESH,  // Fetching device API refresh token.
     STEP_LOCK_DEVICE,         // Writing installation-time attributes.
+    STEP_STORE_ROBOT_AUTH,    // Encrypting & writing robot refresh token.
     STEP_STORE_POLICY,        // Storing policy and API refresh token.
     STEP_FINISHED,            // Enrollment process finished, no further action.
   };
@@ -116,11 +121,6 @@
   // attributes locking if successful.
   void PolicyValidated(DeviceCloudPolicyValidator* validator);
 
-  // Method called to initiate the STEP_LOCK_DEVICE step.  Usually called after
-  // the STEP_ROBOT_AUTH_REFRESH, but may be called directly after a failed
-  // STEP_ROBOT_AUTH_FETCH, since robot tokens are currently optional.
-  void DoLockDeviceStep();
-
   // Calls LockDevice() and proceeds to policy installation. If unsuccessful,
   // reports the result. Actual installation or error report will be done in
   // HandleLockDeviceResult().
@@ -142,6 +142,9 @@
   // Reports the result of the enrollment process to the initiator.
   void ReportResult(EnrollmentStatus status);
 
+  // Continuation of OnStoreLoaded().
+  void DidGetTokenService(chromeos::DeviceOAuth2TokenService* token_service);
+
   DeviceCloudPolicyStoreChromeOS* store_;
   EnterpriseInstallAttributes* install_attributes_;
   scoped_ptr<CloudPolicyClient> client_;
@@ -150,9 +153,9 @@
 
   std::string auth_token_;
   std::string client_id_;
-  std::string robot_refresh_token_;
   bool is_auto_enrollment_;
   std::string requisition_;
+  std::string refresh_token_;
   AllowedDeviceModes allowed_device_modes_;
   EnrollmentCallback completion_callback_;
 
@@ -171,7 +174,8 @@
   // initialization.
   int lockbox_init_duration_;
 
-  base::WeakPtrFactory<EnrollmentHandlerChromeOS> weak_factory_;
+  // Used for locking the device and getting the OAuth2 token service.
+  base::WeakPtrFactory<EnrollmentHandlerChromeOS> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(EnrollmentHandlerChromeOS);
 };
diff --git a/chrome/browser/chromeos/policy/enrollment_status_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_status_chromeos.cc
index 02effb8..c460b35 100644
--- a/chrome/browser/chromeos/policy/enrollment_status_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_status_chromeos.cc
@@ -4,11 +4,13 @@
 
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
 
+#include "net/http/http_status_code.h"
+
 namespace policy {
 
 // static
 EnrollmentStatus EnrollmentStatus::ForStatus(Status status) {
-  return EnrollmentStatus(status, DM_STATUS_SUCCESS,
+  return EnrollmentStatus(status, DM_STATUS_SUCCESS, net::HTTP_OK,
                           CloudPolicyStore::STATUS_OK,
                           CloudPolicyValidatorBase::VALIDATION_OK);
 }
@@ -17,7 +19,22 @@
 EnrollmentStatus EnrollmentStatus::ForRegistrationError(
     DeviceManagementStatus client_status) {
   return EnrollmentStatus(STATUS_REGISTRATION_FAILED, client_status,
-                          CloudPolicyStore::STATUS_OK,
+                          net::HTTP_OK, CloudPolicyStore::STATUS_OK,
+                          CloudPolicyValidatorBase::VALIDATION_OK);
+}
+
+// static
+EnrollmentStatus EnrollmentStatus::ForRobotAuthFetchError(
+    DeviceManagementStatus client_status) {
+  return EnrollmentStatus(STATUS_ROBOT_AUTH_FETCH_FAILED, client_status,
+                          net::HTTP_OK, CloudPolicyStore::STATUS_OK,
+                          CloudPolicyValidatorBase::VALIDATION_OK);
+}
+
+// static
+EnrollmentStatus EnrollmentStatus::ForRobotRefreshFetchError(int http_status) {
+  return EnrollmentStatus(STATUS_ROBOT_REFRESH_FETCH_FAILED, DM_STATUS_SUCCESS,
+                          http_status, CloudPolicyStore::STATUS_OK,
                           CloudPolicyValidatorBase::VALIDATION_OK);
 }
 
@@ -25,7 +42,7 @@
 EnrollmentStatus EnrollmentStatus::ForFetchError(
     DeviceManagementStatus client_status) {
   return EnrollmentStatus(STATUS_POLICY_FETCH_FAILED, client_status,
-                          CloudPolicyStore::STATUS_OK,
+                          net::HTTP_OK, CloudPolicyStore::STATUS_OK,
                           CloudPolicyValidatorBase::VALIDATION_OK);
 }
 
@@ -33,7 +50,8 @@
 EnrollmentStatus EnrollmentStatus::ForValidationError(
     CloudPolicyValidatorBase::Status validation_status) {
   return EnrollmentStatus(STATUS_VALIDATION_FAILED, DM_STATUS_SUCCESS,
-                          CloudPolicyStore::STATUS_OK, validation_status);
+                          net::HTTP_OK, CloudPolicyStore::STATUS_OK,
+                          validation_status);
 }
 
 // static
@@ -41,16 +59,18 @@
     CloudPolicyStore::Status store_error,
     CloudPolicyValidatorBase::Status validation_status) {
   return EnrollmentStatus(STATUS_STORE_ERROR, DM_STATUS_SUCCESS,
-                          store_error, validation_status);
+                          net::HTTP_OK, store_error, validation_status);
 }
 
 EnrollmentStatus::EnrollmentStatus(
     EnrollmentStatus::Status status,
     DeviceManagementStatus client_status,
+    int http_status,
     CloudPolicyStore::Status store_status,
     CloudPolicyValidatorBase::Status validation_status)
     : status_(status),
       client_status_(client_status),
+      http_status_(http_status),
       store_status_(store_status),
       validation_status_(validation_status) {}
 
diff --git a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
index 4c00c89..5845c86 100644
--- a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
@@ -20,6 +20,9 @@
     STATUS_SUCCESS,                     // Enrollment succeeded.
     STATUS_REGISTRATION_FAILED,         // DM registration failed.
     STATUS_REGISTRATION_BAD_MODE,       // Bad device mode.
+    STATUS_ROBOT_AUTH_FETCH_FAILED,     // API OAuth2 auth code failure.
+    STATUS_ROBOT_REFRESH_FETCH_FAILED,  // API OAuth2 refresh token failure.
+    STATUS_ROBOT_REFRESH_STORE_FAILED,  // Failed to store API OAuth2 token.
     STATUS_POLICY_FETCH_FAILED,         // DM policy fetch failed.
     STATUS_VALIDATION_FAILED,           // Policy validation failed.
     STATUS_LOCK_ERROR,                  // Cryptohome failed to lock the device.
@@ -33,6 +36,9 @@
   static EnrollmentStatus ForRegistrationError(
       DeviceManagementStatus client_status);
   static EnrollmentStatus ForFetchError(DeviceManagementStatus client_status);
+  static EnrollmentStatus ForRobotAuthFetchError(
+      DeviceManagementStatus client_status);
+  static EnrollmentStatus ForRobotRefreshFetchError(int http_status);
   static EnrollmentStatus ForValidationError(
       CloudPolicyValidatorBase::Status validation_status);
   static EnrollmentStatus ForStoreError(
@@ -41,6 +47,7 @@
 
   Status status() const { return status_; }
   DeviceManagementStatus client_status() const { return client_status_; }
+  int http_status() const { return http_status_; }
   CloudPolicyStore::Status store_status() const { return store_status_; }
   CloudPolicyValidatorBase::Status validation_status() const {
     return validation_status_;
@@ -49,11 +56,13 @@
  private:
   EnrollmentStatus(Status status,
                    DeviceManagementStatus client_status,
+                   int http_status,
                    CloudPolicyStore::Status store_status,
                    CloudPolicyValidatorBase::Status validation_status);
 
   Status status_;
   DeviceManagementStatus client_status_;
+  int http_status_;
   CloudPolicyStore::Status store_status_;
   CloudPolicyValidatorBase::Status validation_status_;
 };
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index 28365d3..b1d556c 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -349,6 +349,7 @@
       pm::PowerManagementPolicy::STOP_SESSION);
   power_management_policy.set_presentation_screen_dim_delay_factor(3.0);
   power_management_policy.set_user_activity_screen_dim_delay_factor(3.0);
+  power_management_policy.set_wait_for_initial_user_activity(true);
 
   user_policy_.payload().mutable_screendimdelayac()->set_value(5000);
   user_policy_.payload().mutable_screenlockdelayac()->set_value(6000);
@@ -374,6 +375,7 @@
       300);
   user_policy_.payload().mutable_useractivityscreendimdelayscale()->set_value(
       300);
+  user_policy_.payload().mutable_waitforinitialuseractivity()->set_value(true);
   StoreAndReloadUserPolicy();
   EXPECT_EQ(GetDebugString(power_management_policy),
             GetDebugString(power_manager_client_->get_policy()));
diff --git a/chrome/browser/chromeos/power/power_prefs.cc b/chrome/browser/chromeos/power/power_prefs.cc
index c05f074..805e802 100644
--- a/chrome/browser/chromeos/power/power_prefs.cc
+++ b/chrome/browser/chromeos/power/power_prefs.cc
@@ -145,6 +145,8 @@
       prefs->GetDouble(prefs::kPowerPresentationScreenDimDelayFactor);
   values.user_activity_screen_dim_delay_factor =
       prefs->GetDouble(prefs::kPowerUserActivityScreenDimDelayFactor);
+  values.wait_for_initial_user_activity =
+      prefs->GetBoolean(prefs::kPowerWaitForInitialUserActivity);
 
   power_policy_controller_->ApplyPrefs(values);
 }
@@ -220,6 +222,10 @@
       prefs::kPowerUserActivityScreenDimDelayFactor,
       2.0,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kPowerWaitForInitialUserActivity,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 void PowerPrefs::SetProfile(Profile* profile) {
@@ -264,6 +270,8 @@
                               update_callback);
   pref_change_registrar_->Add(prefs::kPowerUserActivityScreenDimDelayFactor,
                               update_callback);
+  pref_change_registrar_->Add(prefs::kPowerWaitForInitialUserActivity,
+                              update_callback);
 
   UpdatePowerPolicyFromPrefs();
 }
diff --git a/chrome/browser/chromeos/power/power_prefs_unittest.cc b/chrome/browser/chromeos/power/power_prefs_unittest.cc
index 3c040e5..ea84d36 100644
--- a/chrome/browser/chromeos/power/power_prefs_unittest.cc
+++ b/chrome/browser/chromeos/power/power_prefs_unittest.cc
@@ -129,6 +129,8 @@
       prefs->GetDouble(prefs::kPowerPresentationScreenDimDelayFactor));
   expected_policy.set_user_activity_screen_dim_delay_factor(
       prefs->GetDouble(prefs::kPowerUserActivityScreenDimDelayFactor));
+  expected_policy.set_wait_for_initial_user_activity(
+      prefs->GetBoolean(prefs::kPowerWaitForInitialUserActivity));
   expected_policy.set_reason("Prefs");
   return PowerPolicyController::GetPolicyDebugString(expected_policy);
 }
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index b3e6262..2dcb3de 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/feedback/tracing_manager.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
@@ -244,6 +244,13 @@
       prefs::kLanguageRemapDiamondKeyTo,
       input_method::kControlKey,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+  // The following pref isn't synced since the user may desire a different value
+  // depending on whether an external keyboard is attached to a particular
+  // device.
+  registry->RegisterBooleanPref(
+      prefs::kLanguageSendFunctionKeys,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   // We don't sync the following keyboard prefs since they are not user-
   // configurable.
   registry->RegisterBooleanPref(
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
index bd311d9..60afc9c 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "ash/ash_switches.h"
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
@@ -300,7 +301,26 @@
   EXPECT_EQ(name3, item3.name);
 }
 
-TEST_F(ProfileListChromeOSTest, ShowAvatarMenu) {
+TEST_F(ProfileListChromeOSTest, DontShowAvatarMenu) {
+  // If in the new M-32 UX mode the icon gets shown, the menu will not.
+  string16 name1(ASCIIToUTF16("p1"));
+  string16 name2(ASCIIToUTF16("p2"));
+
+  AddProfile(name1, true);
+
+  // Should only show avatar menu with multiple users.
+  EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu());
+
+  AddProfile(name2, false);
+
+  EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu());
+}
+
+TEST_F(ProfileListChromeOSTest, ShowAvatarMenuInM31) {
+  // In M-31 mode, the menu will get shown.
+  CommandLine* cl = CommandLine::ForCurrentProcess();
+  cl->AppendSwitch(ash::switches::kAshEnableFullMultiProfileMode);
+
   string16 name1(ASCIIToUTF16("p1"));
   string16 name2(ASCIIToUTF16("p2"));
 
diff --git a/chrome/browser/chromeos/session_length_limiter.cc b/chrome/browser/chromeos/session_length_limiter.cc
index 14c901b..4ea224a 100644
--- a/chrome/browser/chromeos/session_length_limiter.cc
+++ b/chrome/browser/chromeos/session_length_limiter.cc
@@ -6,6 +6,8 @@
 
 #include <algorithm>
 
+#include "ash/shell.h"
+#include "ash/wm/user_activity_detector.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
@@ -15,6 +17,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/common/pref_names.h"
+#include "ui/events/event.h"
 
 namespace chromeos {
 
@@ -62,61 +65,126 @@
 
 // static
 void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(prefs::kSessionUserActivitySeen, false);
   registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
   registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
+  registry->RegisterBooleanPref(prefs::kSessionWaitForInitialUserActivity,
+                                false);
 }
 
 SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
                                            bool browser_restarted)
-    : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl) {
+    : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl),
+      user_activity_seen_(false) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // If this is a user login, set the session start time in local state to the
-  // current time. If this a browser restart after a crash, set the session
-  // start time only if its current value appears corrupted (value unset, value
-  // lying in the future).
   PrefService* local_state = g_browser_process->local_state();
-  int64 session_start_time = local_state->GetInt64(prefs::kSessionStartTime);
-  const int64 now = delegate_->GetCurrentTime().ToInternalValue();
-  if (!browser_restarted ||
-      !local_state->HasPrefPath(prefs::kSessionStartTime) ||
-      session_start_time > now) {
-    local_state->SetInt64(prefs::kSessionStartTime, now);
-    // Ensure that the session start time is persisted to local state.
-    local_state->CommitPendingWrite();
-    session_start_time = now;
-  }
-  session_start_time_ = base::TimeTicks::FromInternalValue(session_start_time);
-
-  // Listen for changes to the session length limit.
   pref_change_registrar_.Init(local_state);
+  pref_change_registrar_.Add(prefs::kSessionLengthLimit,
+                             base::Bind(&SessionLengthLimiter::UpdateLimit,
+                                        base::Unretained(this)));
   pref_change_registrar_.Add(
-      prefs::kSessionLengthLimit,
-      base::Bind(&SessionLengthLimiter::OnSessionLengthLimitChanged,
+      prefs::kSessionWaitForInitialUserActivity,
+      base::Bind(&SessionLengthLimiter::UpdateSessionStartTime,
                  base::Unretained(this)));
 
-  // Handle the current session length limit, if any.
-  OnSessionLengthLimitChanged();
+  // If this is a browser restart after a crash, try to restore the session
+  // start time and the boolean indicating user activity from local state. If
+  // this is not a browser restart after a crash or the attempt to restore
+  // fails, set  the session start time to the current time and clear the
+  // boolean indicating user activity.
+  if (!browser_restarted || !RestoreStateAfterCrash()) {
+    local_state->ClearPref(prefs::kSessionUserActivitySeen);
+    UpdateSessionStartTime();
+  }
+
+  if (!user_activity_seen_ && ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this);
 }
 
 SessionLengthLimiter::~SessionLengthLimiter() {
+  if (!user_activity_seen_ && ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
 }
 
-void SessionLengthLimiter::OnSessionLengthLimitChanged() {
+void SessionLengthLimiter::OnUserActivity(const ui::Event* event) {
+  if (user_activity_seen_)
+    return;
+  if (ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
+  user_activity_seen_ = true;
+
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetBoolean(prefs::kSessionUserActivitySeen, true);
+  if (session_start_time_.is_null()) {
+    // If instructed to wait for initial user activity and this is the first
+    // activity in the session, set the session start time to the current time
+    // and persist it in local state.
+    session_start_time_ = delegate_->GetCurrentTime();
+    local_state->SetInt64(prefs::kSessionStartTime,
+                          session_start_time_.ToInternalValue());
+  }
+  local_state->CommitPendingWrite();
+
+  UpdateLimit();
+}
+
+bool SessionLengthLimiter::RestoreStateAfterCrash() {
+  PrefService* local_state = g_browser_process->local_state();
+  const base::TimeTicks session_start_time =
+      base::TimeTicks::FromInternalValue(
+          local_state->GetInt64(prefs::kSessionStartTime));
+  if (session_start_time.is_null() ||
+      session_start_time >= delegate_->GetCurrentTime()) {
+    return false;
+  }
+
+  session_start_time_ = session_start_time;
+  user_activity_seen_ =
+      local_state->GetBoolean(prefs::kSessionUserActivitySeen);
+
+  UpdateLimit();
+  return true;
+}
+
+void SessionLengthLimiter::UpdateSessionStartTime() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (user_activity_seen_)
+    return;
+
+  PrefService* local_state = g_browser_process->local_state();
+  if (local_state->GetBoolean(prefs::kSessionWaitForInitialUserActivity)) {
+    session_start_time_ = base::TimeTicks();
+    local_state->ClearPref(prefs::kSessionStartTime);
+  } else {
+    session_start_time_ = delegate_->GetCurrentTime();
+    local_state->SetInt64(prefs::kSessionStartTime,
+                          session_start_time_.ToInternalValue());
+  }
+  local_state->CommitPendingWrite();
+
+  UpdateLimit();
+}
+
+void SessionLengthLimiter::UpdateLimit() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Stop any currently running timer.
-  if (timer_)
-    timer_->Stop();
+  timer_.reset();
 
+  // If instructed to wait for initial user activity and no user activity has
+  // occurred yet, do not start a timer.
+  if (session_start_time_.is_null())
+    return;
+
+  // If no session length limit is set, do not start a timer.
   int limit;
   const PrefService::Preference* session_length_limit_pref =
       pref_change_registrar_.prefs()->
           FindPreference(prefs::kSessionLengthLimit);
   if (session_length_limit_pref->IsDefaultValue() ||
       !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
-    // If no session length limit is set, destroy the timer.
-    timer_.reset();
     return;
   }
 
@@ -137,8 +205,7 @@
   }
 
   // Set a timer to log out the user when the session length limit is reached.
-  if (!timer_)
-    timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
+  timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
   timer_->Start(FROM_HERE, remaining, delegate_.get(),
                 &SessionLengthLimiter::Delegate::StopSession);
 }
diff --git a/chrome/browser/chromeos/session_length_limiter.h b/chrome/browser/chromeos/session_length_limiter.h
index 8c6d089..fb8216f 100644
--- a/chrome/browser/chromeos/session_length_limiter.h
+++ b/chrome/browser/chromeos/session_length_limiter.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SESSION_LENGTH_LIMITER_H_
 #define CHROME_BROWSER_CHROMEOS_SESSION_LENGTH_LIMITER_H_
 
+#include "ash/wm/user_activity_observer.h"
 #include "base/basictypes.h"
+#include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/threading/thread_checker.h"
@@ -19,7 +21,7 @@
 
 // Enforces a session length limit by terminating the session when the limit is
 // reached.
-class SessionLengthLimiter {
+class SessionLengthLimiter : public ash::UserActivityObserver {
  public:
   class Delegate {
    public:
@@ -33,10 +35,28 @@
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
   SessionLengthLimiter(Delegate* delegate, bool browser_restarted);
-  ~SessionLengthLimiter();
+  virtual ~SessionLengthLimiter();
+
+  // ash::UserActivityObserver:
+  virtual void OnUserActivity(const ui::Event* event) OVERRIDE;
 
  private:
-  void OnSessionLengthLimitChanged();
+  // Attempt to restore the session start time and the flag indicating user
+  // activity from local state. Return |true| if the restore is successful.
+  bool RestoreStateAfterCrash();
+
+  // Update the session start time if possible:
+  // * If instructed to wait for initial user activity, the session start time
+  //   advances every time this method is called as long as no user activity has
+  //   occurred yet. The time is not persisted in local state.
+  // * If instructed not to wait for initial user activity, the session start
+  //   time is set and persisted in local state the first time this method is
+  //   called.
+  // The pref indicating whether to wait for initial user activity may change at
+  // any time, switching between the two behaviors.
+  void UpdateSessionStartTime();
+
+  void UpdateLimit();
 
   base::ThreadChecker thread_checker_;
 
@@ -45,6 +65,7 @@
 
   scoped_ptr<base::OneShotTimer<SessionLengthLimiter::Delegate> > timer_;
   base::TimeTicks session_start_time_;
+  bool user_activity_seen_;
 
   DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiter);
 };
diff --git a/chrome/browser/chromeos/session_length_limiter_unittest.cc b/chrome/browser/chromeos/session_length_limiter_unittest.cc
index 39495a4..f522c95 100644
--- a/chrome/browser/chromeos/session_length_limiter_unittest.cc
+++ b/chrome/browser/chromeos/session_length_limiter_unittest.cc
@@ -56,7 +56,7 @@
 
   const base::TimeTicks& GetCurrentTime() const;
 
-  void FastForwardBy(int64 milliseconds);
+  void FastForwardBy(const base::TimeDelta& time_delta);
   void FastForwardUntilNoTasksRemain();
 
  private:
@@ -86,26 +86,49 @@
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
-  void SetSessionStartTimePref(int64 session_start_time);
-  void VerifySessionStartTimePref();
-  void SetSessionLengthLimitPref(int64 session_length_limit);
+  void SetSessionUserActivitySeenPref(bool user_activity_seen);
+  void ClearSessionUserActivitySeenPref();
+  bool IsSessionUserActivitySeenPrefSet();
+  bool GetSessionUserActivitySeenPref();
+
+  void SetSessionStartTimePref(const base::TimeTicks& session_start_time);
+  void ClearSessionStartTimePref();
+  bool IsSessionStartTimePrefSet();
+  base::TimeTicks GetSessionStartTimePref();
+
+  void SetSessionLengthLimitPref(const base::TimeDelta& session_length_limit);
+  void ClearSessionLengthLimitPref();
+
+  void SetWaitForInitialUserActivityPref(bool wait_for_initial_user_activity);
+
+  void SimulateUserActivity();
+
+  void UpdateSessionStartTimeIfWaitingForUserActivity();
 
   void ExpectStopSession();
-  void CheckStopSessionTime();
+  void SaveSessionStopTime();
 
+  // Clears the session state by resetting |user_activity_| and
+  // |session_start_time_| and creates a new SessionLengthLimiter.
   void CreateSessionLengthLimiter(bool browser_restarted);
 
-  TestingPrefServiceSimple local_state_;
+  void DestroySessionLengthLimiter();
+
   scoped_refptr<MockTimeSingleThreadTaskRunner> runner_;
   base::TimeTicks session_start_time_;
-  base::TimeTicks session_end_time_;
+  base::TimeTicks session_stop_time_;
+
+ private:
+  TestingPrefServiceSimple local_state_;
+  bool user_activity_seen_;
 
   MockSessionLengthLimiterDelegate* delegate_;  // Owned by
                                                 // session_length_limiter_.
   scoped_ptr<SessionLengthLimiter> session_length_limiter_;
 };
 
-MockTimeSingleThreadTaskRunner::MockTimeSingleThreadTaskRunner() {
+MockTimeSingleThreadTaskRunner::MockTimeSingleThreadTaskRunner()
+    : now_(base::TimeTicks::FromInternalValue(1000)) {
 }
 
 bool MockTimeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const {
@@ -132,9 +155,9 @@
   return now_;
 }
 
-void MockTimeSingleThreadTaskRunner::FastForwardBy(int64 delta) {
-  const base::TimeTicks latest =
-      now_ + base::TimeDelta::FromMilliseconds(delta);
+void MockTimeSingleThreadTaskRunner::FastForwardBy(
+    const base::TimeDelta& time_delta) {
+  const base::TimeTicks latest = now_ + time_delta;
   while (!tasks_.empty() && tasks_.top().first <= latest) {
     now_ = tasks_.top().first;
     base::Closure task = tasks_.top().second;
@@ -162,146 +185,591 @@
 MockTimeSingleThreadTaskRunner::~MockTimeSingleThreadTaskRunner() {
 }
 
-SessionLengthLimiterTest::SessionLengthLimiterTest() : delegate_(NULL) {
+SessionLengthLimiterTest::SessionLengthLimiterTest()
+    : user_activity_seen_(false),
+      delegate_(NULL) {
 }
 
 void SessionLengthLimiterTest::SetUp() {
   TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
   SessionLengthLimiter::RegisterPrefs(local_state_.registry());
   runner_ = new MockTimeSingleThreadTaskRunner;
-  session_start_time_ = runner_->GetCurrentTime();
-
-  delegate_ = new NiceMock<MockSessionLengthLimiterDelegate>;
-  ON_CALL(*delegate_, GetCurrentTime())
-      .WillByDefault(Invoke(runner_.get(),
-                            &MockTimeSingleThreadTaskRunner::GetCurrentTime));
-  EXPECT_CALL(*delegate_, StopSession()).Times(0);
 }
 
 void SessionLengthLimiterTest::TearDown() {
+  session_length_limiter_.reset();
   TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
 }
 
-void SessionLengthLimiterTest::SetSessionStartTimePref(
-    int64 session_start_time) {
-  local_state_.SetUserPref(prefs::kSessionStartTime,
-                           base::Value::CreateStringValue(
-                               base::Int64ToString(session_start_time)));
+void SessionLengthLimiterTest::SetSessionUserActivitySeenPref(
+    bool user_activity_seen) {
+  local_state_.SetUserPref(prefs::kSessionUserActivitySeen,
+                           new base::FundamentalValue(user_activity_seen));
 }
 
-void SessionLengthLimiterTest::VerifySessionStartTimePref() {
-  base::TimeTicks session_start_time(base::TimeTicks::FromInternalValue(
-      local_state_.GetInt64(prefs::kSessionStartTime)));
-  EXPECT_EQ(session_start_time_, session_start_time);
+void SessionLengthLimiterTest::ClearSessionUserActivitySeenPref() {
+  local_state_.ClearPref(prefs::kSessionUserActivitySeen);
+}
+
+bool SessionLengthLimiterTest::IsSessionUserActivitySeenPrefSet() {
+  return local_state_.HasPrefPath(prefs::kSessionUserActivitySeen);
+}
+
+bool SessionLengthLimiterTest::GetSessionUserActivitySeenPref() {
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  return local_state_.GetBoolean(prefs::kSessionUserActivitySeen);
+}
+
+void SessionLengthLimiterTest::SetSessionStartTimePref(
+    const base::TimeTicks& session_start_time) {
+  local_state_.SetUserPref(
+      prefs::kSessionStartTime,
+      new base::StringValue(
+          base::Int64ToString(session_start_time.ToInternalValue())));
+}
+
+void SessionLengthLimiterTest::ClearSessionStartTimePref() {
+  local_state_.ClearPref(prefs::kSessionStartTime);
+}
+
+bool SessionLengthLimiterTest::IsSessionStartTimePrefSet() {
+  return local_state_.HasPrefPath(prefs::kSessionStartTime);
+}
+
+base::TimeTicks SessionLengthLimiterTest::GetSessionStartTimePref() {
+  EXPECT_TRUE(IsSessionStartTimePrefSet());
+  return base::TimeTicks::FromInternalValue(
+      local_state_.GetInt64(prefs::kSessionStartTime));
 }
 
 void SessionLengthLimiterTest::SetSessionLengthLimitPref(
-    int64 session_length_limit) {
-  session_end_time_ = session_start_time_ +
-      base::TimeDelta::FromMilliseconds(session_length_limit);
-  // If the new session end time has passed already, the session should end now.
-  if (session_end_time_ < runner_->GetCurrentTime())
-    session_end_time_ = runner_->GetCurrentTime();
+    const base::TimeDelta& session_length_limit) {
   local_state_.SetUserPref(prefs::kSessionLengthLimit,
-                           base::Value::CreateIntegerValue(
-                               session_length_limit));
+      new base::FundamentalValue(
+          static_cast<int>(session_length_limit.InMilliseconds())));
+  UpdateSessionStartTimeIfWaitingForUserActivity();
+}
+
+void SessionLengthLimiterTest::ClearSessionLengthLimitPref() {
+  local_state_.RemoveUserPref(prefs::kSessionLengthLimit);
+  UpdateSessionStartTimeIfWaitingForUserActivity();
+}
+
+void SessionLengthLimiterTest::SetWaitForInitialUserActivityPref(
+    bool wait_for_initial_user_activity) {
+  UpdateSessionStartTimeIfWaitingForUserActivity();
+  local_state_.SetUserPref(
+      prefs::kSessionWaitForInitialUserActivity,
+      new base::FundamentalValue(wait_for_initial_user_activity));
+}
+
+void SessionLengthLimiterTest::SimulateUserActivity() {
+  if (session_length_limiter_)
+    session_length_limiter_->OnUserActivity(NULL);
+  UpdateSessionStartTimeIfWaitingForUserActivity();
+  user_activity_seen_ = true;
+}
+
+void SessionLengthLimiterTest::
+    UpdateSessionStartTimeIfWaitingForUserActivity() {
+  if (!user_activity_seen_ &&
+      local_state_.GetBoolean(prefs::kSessionWaitForInitialUserActivity)) {
+    session_start_time_ = runner_->GetCurrentTime();
+  }
 }
 
 void SessionLengthLimiterTest::ExpectStopSession() {
   Mock::VerifyAndClearExpectations(delegate_);
   EXPECT_CALL(*delegate_, StopSession())
-    .Times(1)
-    .WillOnce(Invoke(this, &SessionLengthLimiterTest::CheckStopSessionTime));
+      .Times(1)
+      .WillOnce(Invoke(this, &SessionLengthLimiterTest::SaveSessionStopTime));
 }
 
-void SessionLengthLimiterTest::CheckStopSessionTime() {
-  EXPECT_EQ(session_end_time_, runner_->GetCurrentTime());
+void SessionLengthLimiterTest::SaveSessionStopTime() {
+  session_stop_time_ = runner_->GetCurrentTime();
 }
 
 void SessionLengthLimiterTest::CreateSessionLengthLimiter(
     bool browser_restarted) {
+  user_activity_seen_ = false;
+  session_start_time_ = runner_->GetCurrentTime();
+
+  EXPECT_FALSE(delegate_);
+  delegate_ = new NiceMock<MockSessionLengthLimiterDelegate>;
+  ON_CALL(*delegate_, GetCurrentTime())
+      .WillByDefault(Invoke(runner_.get(),
+                            &MockTimeSingleThreadTaskRunner::GetCurrentTime));
+  EXPECT_CALL(*delegate_, StopSession()).Times(0);
   session_length_limiter_.reset(
       new SessionLengthLimiter(delegate_, browser_restarted));
 }
-// Verifies that the session start time in local state is updated during login
-// if no session start time has been stored before.
-TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeUnset) {
+
+void SessionLengthLimiterTest::DestroySessionLengthLimiter() {
+  session_length_limiter_.reset();
+  delegate_ = NULL;
+}
+
+// Verifies that when not instructed to wait for initial user activity, the
+// session start time is set and the pref indicating user activity is cleared
+// in local state during login.
+TEST_F(SessionLengthLimiterTest, StartDoNotWaitForInitialUserActivity) {
+  // Pref indicating user activity not set. Session start time not set.
+  ClearSessionUserActivitySeenPref();
+  ClearSessionStartTimePref();
   CreateSessionLengthLimiter(false);
-  VerifySessionStartTimePref();
-}
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
 
-// Verifies that the session start time in local state is updated during login
-// if a session start time lying in the future has been stored before.
-TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeFuture) {
-  SetSessionStartTimePref(
-      (session_start_time_ + base::TimeDelta::FromHours(2)).ToInternalValue());
+  // Pref indicating user activity set. Session start time not set.
+  SetSessionUserActivitySeenPref(true);
+  ClearSessionStartTimePref();
   CreateSessionLengthLimiter(false);
-  VerifySessionStartTimePref();
-}
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
 
-// Verifies that the session start time in local state is updated during login
-// if a valid session start time has been stored before.
-TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeValid) {
-  SetSessionStartTimePref(
-      (session_start_time_ - base::TimeDelta::FromHours(2)).ToInternalValue());
+  // Pref indicating user activity not set. Session start time in the future.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(session_start_time_ + base::TimeDelta::FromHours(2));
   CreateSessionLengthLimiter(false);
-  VerifySessionStartTimePref();
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time in the future.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(session_start_time_ + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity not set. Session start time valid.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(session_start_time_ - base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time valid.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(session_start_time_ - base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
 }
 
-// Verifies that the session start time in local state is updated during restart
-// after a crash if no session start time has been stored before.
-TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeUnset) {
-  CreateSessionLengthLimiter(true);
-  VerifySessionStartTimePref();
-}
+// Verifies that when instructed to wait for initial user activity, the session
+// start time and the pref indicating user activity are cleared in local state
+// during login.
+TEST_F(SessionLengthLimiterTest, StartWaitForInitialUserActivity) {
+   SetWaitForInitialUserActivityPref(true);
 
-// Verifies that the session start time in local state is updated during restart
-// after a crash if a session start time lying in the future has been stored
-// before.
-TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeFuture) {
+  // Pref indicating user activity not set. Session start time not set.
+  ClearSessionUserActivitySeenPref();
+  ClearSessionStartTimePref();
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time not set.
+  SetSessionUserActivitySeenPref(true);
+  ClearSessionStartTimePref();
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity not set. Session start time in the future.
+  ClearSessionUserActivitySeenPref();
   SetSessionStartTimePref(
-      (session_start_time_ + base::TimeDelta::FromHours(2)).ToInternalValue());
-  CreateSessionLengthLimiter(true);
-  VerifySessionStartTimePref();
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time in the future.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity not set. Session start time valid.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() - base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time valid.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() - base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
 }
 
-// Verifies that the session start time in local state is *not* updated during
-// restart after a crash if a valid session start time has been stored before.
-TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeValid) {
-  session_start_time_ -= base::TimeDelta::FromHours(2);
-  SetSessionStartTimePref(session_start_time_.ToInternalValue());
+// Verifies that when not instructed to wait for initial user activity, local
+// state is correctly updated during restart after a crash:
+// * If no valid session start time is found in local state, the session start
+//   time is set and the pref indicating user activity is cleared.
+// * If a valid session start time is found in local state, the session start
+//   time and the pref indicating user activity are *not* modified.
+TEST_F(SessionLengthLimiterTest, RestartDoNotWaitForInitialUserActivity) {
+  // Pref indicating user activity not set. Session start time not set.
+  ClearSessionUserActivitySeenPref();
+  ClearSessionStartTimePref();
   CreateSessionLengthLimiter(true);
-  VerifySessionStartTimePref();
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time not set.
+  SetSessionUserActivitySeenPref(true);
+  ClearSessionStartTimePref();
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity not set. Session start time in the future.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time in the future.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  const base::TimeTicks stored_session_start_time =
+      runner_->GetCurrentTime() - base::TimeDelta::FromHours(2);
+
+  // Pref indicating user activity not set. Session start time valid.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(stored_session_start_time);
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(stored_session_start_time, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time valid.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(stored_session_start_time);
+  CreateSessionLengthLimiter(true);
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(stored_session_start_time, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+}
+
+// Verifies that when instructed to wait for initial user activity, local state
+// is correctly updated during restart after a crash:
+// * If no valid session start time is found in local state, the session start
+//   time and the pref indicating user activity are cleared.
+// * If a valid session start time is found in local state, the session start
+//   time and the pref indicating user activity are *not* modified.
+TEST_F(SessionLengthLimiterTest, RestartWaitForInitialUserActivity) {
+  SetWaitForInitialUserActivityPref(true);
+
+  // Pref indicating user activity not set. Session start time not set.
+  ClearSessionUserActivitySeenPref();
+  ClearSessionStartTimePref();
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time not set.
+  SetSessionUserActivitySeenPref(true);
+  ClearSessionStartTimePref();
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity not set. Session start time in the future.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time in the future.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(
+      runner_->GetCurrentTime() + base::TimeDelta::FromHours(2));
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+  DestroySessionLengthLimiter();
+
+  const base::TimeTicks stored_session_start_time =
+      runner_->GetCurrentTime() - base::TimeDelta::FromHours(2);
+
+  // Pref indicating user activity not set. Session start time valid.
+  ClearSessionUserActivitySeenPref();
+  SetSessionStartTimePref(stored_session_start_time);
+  CreateSessionLengthLimiter(true);
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(stored_session_start_time, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+
+  // Pref indicating user activity set. Session start time valid.
+  SetSessionUserActivitySeenPref(true);
+  SetSessionStartTimePref(stored_session_start_time);
+  CreateSessionLengthLimiter(true);
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(stored_session_start_time, GetSessionStartTimePref());
+  DestroySessionLengthLimiter();
+}
+
+// Verifies that local state is correctly updated when waiting for initial user
+// activity is toggled and no user activity has occurred yet.
+TEST_F(SessionLengthLimiterTest, ToggleWaitForInitialUserActivity) {
+  CreateSessionLengthLimiter(false);
+
+  // Verify that the pref indicating user activity was not set and the session
+  // start time was set.
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Enable waiting for initial user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SetWaitForInitialUserActivityPref(true);
+
+  // Verify that the session start time was cleared and the pref indicating user
+  // activity was not set.
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+
+  // Disable waiting for initial user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SetWaitForInitialUserActivityPref(false);
+
+  // Verify that the pref indicating user activity was not set and the session
+  // start time was.
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+}
+
+// Verifies that local state is correctly updated when instructed not to wait
+// for initial user activity and user activity occurs. Also verifies that once
+// initial user activity has occurred, neither the session start time nor the
+// pref indicating user activity change in local state anymore.
+TEST_F(SessionLengthLimiterTest, UserActivityWhileNotWaiting) {
+  CreateSessionLengthLimiter(false);
+
+  // Verify that the pref indicating user activity was not set and the session
+  // start time was set.
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Simulate user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SimulateUserActivity();
+
+  // Verify that the pref indicating user activity and the session start time
+  // were set.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Simulate user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SimulateUserActivity();
+
+  // Verify that the pref indicating user activity and the session start time
+  // were not changed.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Enable waiting for initial user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SetWaitForInitialUserActivityPref(true);
+
+  // Verify that the pref indicating user activity and the session start time
+  // were not changed.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+}
+
+// Verifies that local state is correctly updated when instructed to wait for
+// initial user activity and user activity occurs. Also verifies that once
+// initial user activity has occurred, neither the session start time nor the
+// pref indicating user activity change in local state anymore.
+TEST_F(SessionLengthLimiterTest, UserActivityWhileWaiting) {
+  SetWaitForInitialUserActivityPref(true);
+
+  CreateSessionLengthLimiter(false);
+
+  // Verify that the pref indicating user activity and the session start time
+  // were not set.
+  EXPECT_FALSE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+
+  // Simulate user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SimulateUserActivity();
+
+  // Verify that the pref indicating user activity and the session start time
+  // were set.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Simulate user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SimulateUserActivity();
+
+  // Verify that the pref indicating user activity and the session start time
+  // were not changed.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Disable waiting for initial user activity.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  SetWaitForInitialUserActivityPref(false);
+
+  // Verify that the pref indicating user activity and the session start time
+  // were not changed.
+  EXPECT_TRUE(IsSessionUserActivitySeenPrefSet());
+  EXPECT_TRUE(GetSessionUserActivitySeenPref());
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
 }
 
 // Creates a SessionLengthLimiter without setting a limit. Verifies that the
 // limiter does not start a timer.
-TEST_F(SessionLengthLimiterTest, RunWithoutSessionLengthLimit) {
+TEST_F(SessionLengthLimiterTest, RunWithoutLimit) {
   base::ThreadTaskRunnerHandle runner_handler(runner_);
 
-  // Create a SessionLengthLimiter.
   CreateSessionLengthLimiter(false);
 
   // Verify that no timer fires to terminate the session.
   runner_->FastForwardUntilNoTasksRemain();
 }
 
-// Creates a SessionLengthLimiter after setting a limit. Verifies that the
-// limiter starts a timer and that when the session length reaches the limit,
-// the session is terminated.
-TEST_F(SessionLengthLimiterTest, RunWithSessionLengthLimit) {
+// Creates a SessionLengthLimiter after setting a limit and instructs it not to
+// wait for user activity. Verifies that the limiter starts a timer even if no
+// user activity occurs and that when the session length reaches the limit, the
+// session is terminated.
+TEST_F(SessionLengthLimiterTest, RunWithoutUserActivityWhileNotWaiting) {
   base::ThreadTaskRunnerHandle runner_handler(runner_);
 
   // Set a 60 second session time limit.
-  SetSessionLengthLimitPref(60 * 1000);  // 60 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
 
-  // Create a SessionLengthLimiter.
   CreateSessionLengthLimiter(false);
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
 
   // Verify that the timer fires and the session is terminated when the session
   // length limit is reached.
   ExpectStopSession();
   runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(session_start_time_ + base::TimeDelta::FromSeconds(60),
+            session_stop_time_);
+}
+
+// Creates a SessionLengthLimiter after setting a limit and instructs it to wait
+// for initial user activity. Verifies that if no user activity occurs, the
+// limiter does not start a timer.
+TEST_F(SessionLengthLimiterTest, RunWithoutUserActivityWhileWaiting) {
+  base::ThreadTaskRunnerHandle runner_handler(runner_);
+  SetWaitForInitialUserActivityPref(true);
+
+  // Set a 60 second session time limit.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
+
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+
+  // Verify that no timer fires to terminate the session.
+  runner_->FastForwardUntilNoTasksRemain();
+}
+
+// Creates a SessionLengthLimiter after setting a limit and instructs it not to
+// wait for user activity. Verifies that the limiter starts a timer and that
+// when the session length reaches the limit, the session is terminated. Also
+// verifies that user activity does not affect the timer.
+TEST_F(SessionLengthLimiterTest, RunWithUserActivityWhileNotWaiting) {
+  base::ThreadTaskRunnerHandle runner_handler(runner_);
+
+  // Set a 60 second session time limit.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
+
+  CreateSessionLengthLimiter(false);
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Simulate user activity after 20 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(20));
+  SimulateUserActivity();
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Verify that the timer fires and the session is terminated when the session
+  // length limit is reached.
+  ExpectStopSession();
+  runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(session_start_time_ + base::TimeDelta::FromSeconds(60),
+            session_stop_time_);
+}
+
+// Creates a SessionLengthLimiter after setting a limit and instructs it to wait
+// for initial user activity. Verifies that once user activity occurs, the
+// limiter starts a timer and that when the session length reaches the limit,
+// the session is terminated. Also verifies that further user activity does not
+// affect the timer.
+TEST_F(SessionLengthLimiterTest, RunWithUserActivityWhileWaiting) {
+  base::ThreadTaskRunnerHandle runner_handler(runner_);
+  SetWaitForInitialUserActivityPref(true);
+
+  // Set a 60 second session time limit.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
+
+  CreateSessionLengthLimiter(false);
+  EXPECT_FALSE(IsSessionStartTimePrefSet());
+
+  // Simulate user activity after 20 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(20));
+  SimulateUserActivity();
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Simulate user activity after 20 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(20));
+  SimulateUserActivity();
+  EXPECT_EQ(session_start_time_, GetSessionStartTimePref());
+
+  // Verify that the timer fires and the session is terminated when the session
+  // length limit is reached.
+  ExpectStopSession();
+  runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(session_start_time_ + base::TimeDelta::FromSeconds(60),
+            session_stop_time_);
 }
 
 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
@@ -312,22 +780,23 @@
   base::ThreadTaskRunnerHandle runner_handler(runner_);
 
   // Set a 60 second session time limit.
-  SetSessionLengthLimitPref(60 * 1000);  // 60 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
 
-  // Create a SessionLengthLimiter.
   CreateSessionLengthLimiter(false);
 
   // Fast forward the time by 50 seconds, verifying that no timer fires to
   // terminate the session.
-  runner_->FastForwardBy(50 * 1000);  // 50 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(50));
 
   // Increase the session length limit to 90 seconds.
-  SetSessionLengthLimitPref(90 * 1000);  // 90 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(90));
 
   // Verify that the the timer fires and the session is terminated when the
   // session length limit is reached.
   ExpectStopSession();
   runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(session_start_time_ + base::TimeDelta::FromSeconds(90),
+            session_stop_time_);
 }
 
 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
@@ -339,19 +808,20 @@
   base::ThreadTaskRunnerHandle runner_handler(runner_);
 
   // Set a 60 second session time limit.
-  SetSessionLengthLimitPref(60 * 1000);  // 60 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
 
-  // Create a SessionLengthLimiter.
   CreateSessionLengthLimiter(false);
 
   // Fast forward the time by 50 seconds, verifying that no timer fires to
   // terminate the session.
-  runner_->FastForwardBy(50 * 1000);  // 50 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(50));
 
   // Verify that reducing the session length limit below the 50 seconds that
   // have already elapsed causes the session to be terminated immediately.
   ExpectStopSession();
-  SetSessionLengthLimitPref(40 * 1000);  // 40 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(40));
+  EXPECT_EQ(session_start_time_ + base::TimeDelta::FromSeconds(50),
+            session_stop_time_);
 }
 
 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
@@ -362,17 +832,16 @@
   base::ThreadTaskRunnerHandle runner_handler(runner_);
 
   // Set a 60 second session time limit.
-  SetSessionLengthLimitPref(60 * 1000);  // 60 seconds.
+  SetSessionLengthLimitPref(base::TimeDelta::FromSeconds(60));
 
-  // Create a SessionLengthLimiter.
   CreateSessionLengthLimiter(false);
 
   // Fast forward the time by 50 seconds, verifying that no timer fires to
   // terminate the session.
-  runner_->FastForwardBy(50 * 1000);  // 50 seconds.
+  runner_->FastForwardBy(base::TimeDelta::FromSeconds(50));
 
   // Remove the session length limit.
-  local_state_.RemoveUserPref(prefs::kSessionLengthLimit);
+  ClearSessionLengthLimitPref();
 
   // Verify that no timer fires to terminate the session.
   runner_->FastForwardUntilNoTasksRemain();
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 64f2c84..3086e4d 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -233,44 +232,32 @@
                                std::string());
 }
 
-void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
+bool DeviceOAuth2TokenService::SetAndSaveRefreshToken(
     const std::string& refresh_token) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
-  // TODO(xiyuan): Use async GetSystemSalt after merging to M31.
-  const std::string system_salt = SystemSaltGetter::Get()->GetSystemSaltSync();
-  if (system_salt.empty()) {
-    const int64 kRequestSystemSaltDelayMs = 500;
-    content::BrowserThread::PostDelayedTask(
-        content::BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&DeviceOAuth2TokenService::SetAndSaveRefreshToken,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   refresh_token),
-        base::TimeDelta::FromMilliseconds(kRequestSystemSaltDelayMs));
-    return;
-  }
-
   std::string encrypted_refresh_token =
       token_encryptor_->EncryptWithSystemSalt(refresh_token);
+  if (encrypted_refresh_token.empty()) {
+    LOG(ERROR) << "Failed to encrypt refresh token; save aborted.";
+    return false;
+  }
 
   local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
                           encrypted_refresh_token);
+  return true;
 }
 
 std::string DeviceOAuth2TokenService::GetRefreshToken(
     const std::string& account_id) {
-  DCHECK_EQ(account_id, GetRobotAccountId());
   if (refresh_token_.empty()) {
     std::string encrypted_refresh_token =
         local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);
 
-    // TODO(xiyuan): This needs a proper fix after M31.
-    LOG_IF(ERROR, SystemSaltGetter::Get()->GetSystemSaltSync().empty())
-        << "System salt is not available for decryption";
-
     refresh_token_ = token_encryptor_->DecryptWithSystemSalt(
         encrypted_refresh_token);
+    if (!encrypted_refresh_token.empty() && refresh_token_.empty())
+      LOG(ERROR) << "Failed to decrypt refresh token.";
   }
   return refresh_token_;
 }
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
index 04809c9..9a364d1 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -44,8 +44,9 @@
 class DeviceOAuth2TokenService : public OAuth2TokenService {
  public:
   // Persist the given refresh token on the device.  Overwrites any previous
-  // value.  Should only be called during initial device setup.
-  void SetAndSaveRefreshToken(const std::string& refresh_token);
+  // value.  Should only be called during initial device setup.  Returns false
+  // if there was an error encrypting and persisting the value, else true.
+  bool SetAndSaveRefreshToken(const std::string& refresh_token);
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
index 57b6efb..253a833 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
@@ -4,41 +4,114 @@
 
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/tracked_objects.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/token_encryptor.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace chromeos {
+namespace {
 
-static DeviceOAuth2TokenService* g_device_oauth2_token_service_ = NULL;
+DeviceOAuth2TokenServiceFactory* g_factory = NULL;
 
-DeviceOAuth2TokenServiceFactory::DeviceOAuth2TokenServiceFactory() {
+}  // namespace
+
+DeviceOAuth2TokenServiceFactory::DeviceOAuth2TokenServiceFactory()
+    : initialized_(false),
+      token_service_(NULL),
+      weak_ptr_factory_(this) {
+}
+
+DeviceOAuth2TokenServiceFactory::~DeviceOAuth2TokenServiceFactory() {
+  delete token_service_;
 }
 
 // static
-DeviceOAuth2TokenService* DeviceOAuth2TokenServiceFactory::Get() {
+void DeviceOAuth2TokenServiceFactory::Get(const GetCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  return g_device_oauth2_token_service_;
+
+  if (!g_factory) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback,
+                   static_cast<DeviceOAuth2TokenService*>(NULL)));
+    return;
+  }
+
+  g_factory->RunAsync(callback);
 }
 
 // static
 void DeviceOAuth2TokenServiceFactory::Initialize() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  DCHECK(!g_device_oauth2_token_service_);
-  g_device_oauth2_token_service_ = new DeviceOAuth2TokenService(
-      g_browser_process->system_request_context(),
-      g_browser_process->local_state(),
-      new CryptohomeTokenEncryptor);
+
+  DCHECK(!g_factory);
+  g_factory = new DeviceOAuth2TokenServiceFactory;
+  g_factory->CreateTokenService();
 }
 
 // static
 void DeviceOAuth2TokenServiceFactory::Shutdown() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  if (g_device_oauth2_token_service_) {
-    delete g_device_oauth2_token_service_;
-    g_device_oauth2_token_service_ = NULL;
+
+  if (g_factory) {
+    delete g_factory;
+    g_factory = NULL;
   }
 }
 
+void DeviceOAuth2TokenServiceFactory::CreateTokenService() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  SystemSaltGetter::Get()->GetSystemSalt(
+      base::Bind(&DeviceOAuth2TokenServiceFactory::DidGetSystemSalt,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DeviceOAuth2TokenServiceFactory::DidGetSystemSalt(
+    const std::string& system_salt) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(!token_service_);
+
+  if (system_salt.empty()) {
+    LOG(ERROR) << "Failed to get the system salt";
+  } else {
+    token_service_= new DeviceOAuth2TokenService(
+        g_browser_process->system_request_context(),
+        g_browser_process->local_state(),
+        new CryptohomeTokenEncryptor(system_salt));
+  }
+  // Mark that the factory is initialized.
+  initialized_ = true;
+
+  // Run callbacks regardless of whether token_service_ is created or not,
+  // but don't run callbacks immediately. Each callback would cause an
+  // interesting action, hence running them consecutively could be
+  // potentially expensive and dangerous.
+  while (!pending_callbacks_.empty()) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(pending_callbacks_.front(), token_service_));
+    pending_callbacks_.pop();
+  }
+}
+
+void DeviceOAuth2TokenServiceFactory::RunAsync(const GetCallback& callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  if (initialized_) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, token_service_));
+    return;
+  }
+
+  pending_callbacks_.push(callback);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h
index f6c8637..cd68763 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h
@@ -5,7 +5,12 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
 
+#include <queue>
+#include <string>
+
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
 
 namespace chromeos {
 
@@ -13,12 +18,21 @@
 
 class DeviceOAuth2TokenServiceFactory {
  public:
-  // Returns the instance of the DeviceOAuth2TokenService singleton.
-  // May return null during browser startup and shutdown.  Do not hold
-  // the pointer returned by this method; call this method every time
-  // and check for null to handle the case where this instance is destroyed
-  // during shutdown.
-  static DeviceOAuth2TokenService* Get();
+  // Callback type used for Get() function.
+  typedef base::Callback<void(DeviceOAuth2TokenService*)> GetCallback;
+
+  // Returns the instance of the DeviceOAuth2TokenService singleton via the
+  // given callback. This function is asynchronous as initializing
+  // DeviceOAuth2TokenService involves asynchronous D-Bus method calls.
+  //
+  // May return NULL during browser startup and shutdown. May also return
+  // NULL if Initialize() is not called beforehand, which can happen in unit
+  // tests.
+  //
+  // Do not hold the pointer returned by this method; call this method every
+  // time and check for NULL to handle the case where this instance is
+  // destroyed during shutdown.
+  static void Get(const GetCallback& callback);
 
   // Called by ChromeBrowserMainPartsChromeOS in order to bootstrap the
   // DeviceOAuth2TokenService instance after the required global data is
@@ -33,6 +47,30 @@
 
  private:
   DeviceOAuth2TokenServiceFactory();
+  ~DeviceOAuth2TokenServiceFactory();
+
+  // Creates the token service asynchronously in the following steps:
+  // 1) Get the system salt from cryptohomed asynchronously
+  // 2) Create CryptohomeTokenEncryptor using the system salt
+  // 3) Create DeviceOAuth2TokenServiceFactory using the token encryptor
+  void CreateTokenService();
+
+  // Continuation of CreateTokenService(). Called when GetSystemSalt() is
+  // complete.
+  void DidGetSystemSalt(const std::string& system_salt);
+
+  // Runs the callback asynchronously. If |token_service_| is ready, the
+  // callback will be simply run via MessageLoop. Otherwise, the callback
+  // will be queued in |pending_callbacks_| and run when |token_service_| is
+  // ready.
+  void RunAsync(const GetCallback& callback);
+
+  // True if the factory is initialized (i.e. system salt retrieval is done
+  // regardless of whether it succeeded or failed).
+  bool initialized_;
+  DeviceOAuth2TokenService* token_service_;
+  std::queue<GetCallback> pending_callbacks_;
+  base::WeakPtrFactory<DeviceOAuth2TokenServiceFactory> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceOAuth2TokenServiceFactory);
 };
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory_unittest.cc
new file mode 100644
index 0000000..e7d5f32
--- /dev/null
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2013 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/settings/device_oauth2_token_service_factory.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace {
+
+// Copies the token service and increments the counter.
+void CopyTokenServiceAndCount(
+    chromeos::DeviceOAuth2TokenService** out_token_service,
+    int* counter,
+    chromeos::DeviceOAuth2TokenService* in_token_service) {
+  *out_token_service = in_token_service;
+  ++(*counter);
+}
+
+// Sets up and tears down DeviceOAuth2TokenServiceFactory and its
+// dependencies. Also exposes FakeDBusThreadManager.
+class ScopedDeviceOAuth2TokenServiceFactorySetUp {
+ public:
+  ScopedDeviceOAuth2TokenServiceFactorySetUp()
+      : fake_dbus_manager_(new FakeDBusThreadManager) {
+    // Take ownership of fake_dbus_manager_.
+    DBusThreadManager::InitializeForTesting(fake_dbus_manager_);
+    SystemSaltGetter::Initialize();
+    DeviceOAuth2TokenServiceFactory::Initialize();
+  }
+
+  ~ScopedDeviceOAuth2TokenServiceFactorySetUp() {
+    DeviceOAuth2TokenServiceFactory::Shutdown();
+    SystemSaltGetter::Shutdown();
+    DBusThreadManager::Shutdown();
+  }
+
+  FakeDBusThreadManager* fake_dbus_manager() {
+    return fake_dbus_manager_;
+  }
+
+ private:
+  FakeDBusThreadManager* fake_dbus_manager_;
+};
+
+}  // namespace
+
+class DeviceOAuth2TokenServiceFactoryTest : public testing::Test {
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+};
+
+// Test a case where Get() is called before the factory is initialized.
+TEST_F(DeviceOAuth2TokenServiceFactoryTest, Get_Uninitialized) {
+  DeviceOAuth2TokenService* token_service = NULL;
+  int counter = 0;
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service, &counter));
+  // The callback will be run asynchronously.
+  EXPECT_EQ(0, counter);
+  EXPECT_FALSE(token_service);
+
+  // This lets the factory run the callback with NULL.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, counter);
+  EXPECT_FALSE(token_service);
+}
+
+// Test a case where Get() is called from only one caller.
+TEST_F(DeviceOAuth2TokenServiceFactoryTest, Get_Simple) {
+  ScopedDeviceOAuth2TokenServiceFactorySetUp scoped_setup;
+
+  DeviceOAuth2TokenService* token_service = NULL;
+  int counter = 0;
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service, &counter));
+  // The callback will be run asynchronously.
+  EXPECT_EQ(0, counter);
+  EXPECT_FALSE(token_service);
+
+  // This lets FakeCryptohomeClient return the system salt.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, counter);
+  EXPECT_TRUE(token_service);
+
+  // Call Get() again, and confirm it works.
+  token_service = NULL;
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service, &counter));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, counter);
+  EXPECT_TRUE(token_service);
+}
+
+// Test a case where Get() is called from multiple callers, before the token
+// service is ready, and confirm that the callback of every caller is run.
+TEST_F(DeviceOAuth2TokenServiceFactoryTest, Get_MultipleCallers) {
+  ScopedDeviceOAuth2TokenServiceFactorySetUp scoped_setup;
+
+  DeviceOAuth2TokenService* token_service1 = NULL;
+  DeviceOAuth2TokenService* token_service2 = NULL;
+  DeviceOAuth2TokenService* token_service3 = NULL;
+  int counter = 0;
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service1, &counter));
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service2, &counter));
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service3, &counter));
+  // The token service will be returned asynchronously.
+  EXPECT_EQ(0, counter);
+  EXPECT_FALSE(token_service1);
+  EXPECT_FALSE(token_service2);
+  EXPECT_FALSE(token_service3);
+
+  // This lets FakeCryptohomeClient return the system salt.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(3, counter);
+  EXPECT_TRUE(token_service1);
+  EXPECT_TRUE(token_service2);
+  EXPECT_TRUE(token_service3);
+
+  // Make sure that token_service1,2,3 are the same one.
+  EXPECT_EQ(token_service1, token_service2);
+  EXPECT_EQ(token_service1, token_service3);
+}
+
+// Test a case where it failed to obtain the system salt.
+TEST_F(DeviceOAuth2TokenServiceFactoryTest, Get_NoSystemSalt) {
+  ScopedDeviceOAuth2TokenServiceFactorySetUp scoped_setup;
+  scoped_setup.fake_dbus_manager()->fake_cryptohome_client()->
+      set_system_salt(std::vector<uint8>());
+
+  DeviceOAuth2TokenService* token_service = NULL;
+  int counter = 0;
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service, &counter));
+  // The callback will be run asynchronously.
+  EXPECT_EQ(0, counter);
+  EXPECT_FALSE(token_service);
+
+  // This lets FakeCryptohomeClient return the system salt, which is empty.
+  // NULL should be returned to the callback in this case.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, counter);
+  EXPECT_FALSE(token_service);
+
+  // Try it again, but the result should remain the same (NULL returned).
+  DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&CopyTokenServiceAndCount, &token_service, &counter));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, counter);
+  EXPECT_FALSE(token_service);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 7c1d3b8..863a1dc 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -69,6 +69,7 @@
   kReportDeviceBootMode,
   kReportDeviceLocation,
   kReportDeviceNetworkInterfaces,
+  kReportDeviceUsers,
   kReportDeviceVersionInfo,
   kScreenSaverExtensionId,
   kScreenSaverTimeout,
@@ -403,6 +404,7 @@
     //   kReportDeviceLocation
     //   kReportDeviceVersionInfo
     //   kReportDeviceNetworkInterfaces
+    //   kReportDeviceUsers
     //   kScreenSaverExtensionId
     //   kScreenSaverTimeout
     //   kStartUpUrls
@@ -676,6 +678,11 @@
           kReportDeviceNetworkInterfaces,
           reporting_policy.report_network_interfaces());
     }
+    if (reporting_policy.has_report_users()) {
+      new_values_cache->SetBoolean(
+          kReportDeviceUsers,
+          reporting_policy.report_users());
+    }
   }
 }
 
diff --git a/chrome/browser/chromeos/settings/session_manager_operation.cc b/chrome/browser/chromeos/settings/session_manager_operation.cc
index 934c7a2..c4fc8d1 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation.cc
@@ -52,10 +52,14 @@
 
   // Abort previous load operations.
   weak_factory_.InvalidateWeakPtrs();
+  // Mark as not loading to start loading again.
+  is_loading_ = false;
   StartLoading();
 }
 
 void SessionManagerOperation::StartLoading() {
+  if (is_loading_)
+    return;
   is_loading_ = true;
   EnsureOwnerKey(base::Bind(&SessionManagerOperation::RetrieveDeviceSettings,
                             weak_factory_.GetWeakPtr()));
@@ -68,8 +72,12 @@
 
 void SessionManagerOperation::EnsureOwnerKey(const base::Closure& callback) {
   if (force_key_load_ || !owner_key_.get() || !owner_key_->public_key()) {
+    scoped_refptr<base::TaskRunner> task_runner =
+        content::BrowserThread::GetBlockingPool()->
+        GetTaskRunnerWithShutdownBehavior(
+            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
     base::PostTaskAndReplyWithResult(
-        content::BrowserThread::GetBlockingPool(),
+        task_runner.get(),
         FROM_HERE,
         base::Bind(&SessionManagerOperation::LoadOwnerKey,
                    owner_key_util_, owner_key_),
diff --git a/chrome/browser/chromeos/settings/token_encryptor.cc b/chrome/browser/chromeos/settings/token_encryptor.cc
index 269e8cb..fe555f9 100644
--- a/chrome/browser/chromeos/settings/token_encryptor.cc
+++ b/chrome/browser/chromeos/settings/token_encryptor.cc
@@ -22,7 +22,13 @@
 const size_t kNonceSize = 16;
 }  // namespace
 
-CryptohomeTokenEncryptor::CryptohomeTokenEncryptor() {
+CryptohomeTokenEncryptor::CryptohomeTokenEncryptor(
+    const std::string& system_salt)
+    : system_salt_(system_salt) {
+  DCHECK(!system_salt.empty());
+  // TODO(davidroche): should this use the system salt for both the password
+  // and the salt value, or should this use a separate salt value?
+  system_salt_key_.reset(PassphraseToKey(system_salt_, system_salt_));
 }
 
 CryptohomeTokenEncryptor::~CryptohomeTokenEncryptor() {
@@ -34,7 +40,7 @@
   if (!base::SysInfo::IsRunningOnChromeOS())
     return token;
 
-  if (!LoadSystemSaltKey()) {
+  if (!system_salt_key_) {
     LOG(WARNING) << "System salt key is not available for encrypt.";
     return std::string();
   }
@@ -49,7 +55,7 @@
   if (!base::SysInfo::IsRunningOnChromeOS())
     return encrypted_token_hex;
 
-  if (!LoadSystemSaltKey()) {
+  if (!system_salt_key_) {
     LOG(WARNING) << "System salt key is not available for decrypt.";
     return std::string();
   }
@@ -58,19 +64,6 @@
                              encrypted_token_hex);
 }
 
-// TODO: should this use the system salt for both the password and the salt
-// value, or should this use a separate salt value?
-bool CryptohomeTokenEncryptor::LoadSystemSaltKey() {
-  // Assume the system salt should be obtained beforehand at login time.
-  if (system_salt_.empty())
-    system_salt_ = SystemSaltGetter::Get()->GetCachedSystemSalt();
-  if (system_salt_.empty())
-    return false;
-  if (!system_salt_key_.get())
-    system_salt_key_.reset(PassphraseToKey(system_salt_, system_salt_));
-  return system_salt_key_.get();
-}
-
 crypto::SymmetricKey* CryptohomeTokenEncryptor::PassphraseToKey(
     const std::string& passphrase,
     const std::string& salt) {
diff --git a/chrome/browser/chromeos/settings/token_encryptor.h b/chrome/browser/chromeos/settings/token_encryptor.h
index 8892dc6..61d6d47 100644
--- a/chrome/browser/chromeos/settings/token_encryptor.h
+++ b/chrome/browser/chromeos/settings/token_encryptor.h
@@ -33,11 +33,11 @@
       const std::string& encrypted_token_hex) = 0;
 };
 
-// TokenEncryptor based on the cryptohome daemon. This implementation is used
-// in production.
+// TokenEncryptor based on the system salt from cryptohome daemon. This
+// implementation is used in production.
 class CryptohomeTokenEncryptor : public TokenEncryptor {
  public:
-  CryptohomeTokenEncryptor();
+  explicit CryptohomeTokenEncryptor(const std::string& system_salt);
   virtual ~CryptohomeTokenEncryptor();
 
   // TokenEncryptor overrides:
@@ -46,10 +46,6 @@
       const std::string& encrypted_token_hex) OVERRIDE;
 
  private:
-  // Loads the system salt key based on the system salt from the cryptohome
-  // daemon. Returns true on success.
-  bool LoadSystemSaltKey();
-
   // Converts |passphrase| to a SymmetricKey using the given |salt|.
   crypto::SymmetricKey* PassphraseToKey(const std::string& passphrase,
                                         const std::string& salt);
@@ -64,7 +60,8 @@
                                   const std::string& salt,
                                   const std::string& encrypted_token_hex);
 
-  // The cached system salt obtained from the cryptohome daemon.
+  // The cached system salt passed to the constructor, originally coming
+  // from cryptohome daemon.
   std::string system_salt_;
 
   // A key based on the system salt.  Useful for encrypting device-level
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index 49b6f1f..f83fc71 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -531,7 +531,10 @@
   }
 
   virtual void ShowHelp() OVERRIDE {
-    chrome::ShowHelp(GetAppropriateBrowser(), chrome::HELP_SOURCE_MENU);
+    chrome::ShowHelpForProfile(
+        ProfileManager::GetDefaultProfileOrOffTheRecord(),
+        chrome::HOST_DESKTOP_TYPE_ASH,
+        chrome::HELP_SOURCE_MENU);
   }
 
   virtual void ShowAccessibilityHelp() OVERRIDE {
@@ -747,8 +750,9 @@
   virtual void ManageBluetoothDevices() OVERRIDE {
     content::RecordAction(
         content::UserMetricsAction("ShowBluetoothSettingsPage"));
-    chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
-                                chrome::kBluetoothAddDeviceSubPage);
+    std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
+        l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
+    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
   }
 
   virtual void ToggleBluetooth() OVERRIDE {
@@ -865,6 +869,11 @@
                    base::Unretained(this),
                    ash::A11Y_NOTIFICATION_NONE));
     user_pref_registrar_->Add(
+        prefs::kAutoclickEnabled,
+        base::Bind(&SystemTrayDelegate::OnAccessibilityModeChanged,
+                   base::Unretained(this),
+                   ash::A11Y_NOTIFICATION_NONE));
+    user_pref_registrar_->Add(
         prefs::kShouldAlwaysShowAccessibilityMenu,
         base::Bind(&SystemTrayDelegate::OnAccessibilityModeChanged,
                    base::Unretained(this),
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
index 47649cf..6313f76 100644
--- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
+++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -31,7 +31,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/test/test_utils.h"
 #include "policy/policy_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -164,6 +163,12 @@
     tray()->detailed_menu_->OnViewClicked(button);
   }
 
+  void ClickAutoclickOnDetailMenu() {
+    views::View* button = tray()->detailed_menu_->autoclick_view_;
+    EXPECT_TRUE(button);
+    tray()->detailed_menu_->OnViewClicked(button);
+  }
+
   bool IsSpokenFeedbackEnabledOnDetailMenu() {
     return tray()->detailed_menu_->spoken_feedback_enabled_;
   }
@@ -180,6 +185,9 @@
     return tray()->detailed_menu_->large_cursor_enabled_;
   }
 
+  bool IsAutoclickEnabledOnDetailMenu() {
+    return tray()->detailed_menu_->autoclick_enabled_;
+  }
   bool IsSpokenFeedbackMenuShownOnDetailMenu() {
     return tray()->detailed_menu_->spoken_feedback_view_;
   }
@@ -196,6 +204,10 @@
     return tray()->detailed_menu_->large_cursor_view_;
   }
 
+  bool IsAutoclickMenuShownOnDetailMenu() {
+    return tray()->detailed_menu_->autoclick_view_;
+  }
+
   policy::MockConfigurationPolicyProvider provider_;
 };
 
@@ -298,6 +310,12 @@
   SetMagnifierEnabled(false);
   EXPECT_FALSE(CanCreateMenuItem());
 
+  // Toggling autoclick changes the visibility of the menu.
+  AccessibilityManager::Get()->EnableAutoclick(true);
+  EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(false);
+  EXPECT_FALSE(CanCreateMenuItem());
+
   // Enabling all accessibility features.
   SetMagnifierEnabled(true);
   EXPECT_TRUE(CanCreateMenuItem());
@@ -306,6 +324,10 @@
   AccessibilityManager::Get()->EnableSpokenFeedback(
       true, ash::A11Y_NOTIFICATION_NONE);
   EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(true);
+  EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(false);
+  EXPECT_TRUE(CanCreateMenuItem());
   AccessibilityManager::Get()->EnableSpokenFeedback(
       false, ash::A11Y_NOTIFICATION_NONE);
   EXPECT_TRUE(CanCreateMenuItem());
@@ -346,6 +368,12 @@
   SetMagnifierEnabled(false);
   EXPECT_TRUE(CanCreateMenuItem());
 
+  // The menu is keeping visible regardless of toggling autoclick.
+  AccessibilityManager::Get()->EnableAutoclick(true);
+  EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(false);
+  EXPECT_TRUE(CanCreateMenuItem());
+
   // Enabling all accessibility features.
   SetMagnifierEnabled(true);
   EXPECT_TRUE(CanCreateMenuItem());
@@ -354,6 +382,10 @@
   AccessibilityManager::Get()->EnableSpokenFeedback(
       true, ash::A11Y_NOTIFICATION_NONE);
   EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(true);
+  EXPECT_TRUE(CanCreateMenuItem());
+  AccessibilityManager::Get()->EnableAutoclick(false);
+  EXPECT_TRUE(CanCreateMenuItem());
   AccessibilityManager::Get()->EnableSpokenFeedback(
       false, ash::A11Y_NOTIFICATION_NONE);
   EXPECT_TRUE(CanCreateMenuItem());
@@ -477,6 +509,17 @@
   EXPECT_TRUE(CreateDetailedMenu());
   ClickScreenMagnifierOnDetailMenu();
   EXPECT_FALSE(MagnificationManager::Get()->IsMagnifierEnabled());
+
+  // Confirms that the check item toggles autoclick.
+  EXPECT_FALSE(AccessibilityManager::Get()->IsAutoclickEnabled());
+
+  EXPECT_TRUE(CreateDetailedMenu());
+  ClickAutoclickOnDetailMenu();
+  EXPECT_TRUE(AccessibilityManager::Get()->IsAutoclickEnabled());
+
+  EXPECT_TRUE(CreateDetailedMenu());
+  ClickAutoclickOnDetailMenu();
+  EXPECT_FALSE(AccessibilityManager::Get()->IsAutoclickEnabled());
 }
 
 IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, CheckMarksOnDetailMenu) {
@@ -488,6 +531,8 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Enabling spoken feedback.
@@ -498,6 +543,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Disabling spoken feedback.
@@ -508,6 +554,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Enabling high contrast.
@@ -517,6 +564,7 @@
   EXPECT_TRUE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Disabling high contrast.
@@ -526,6 +574,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Enabling full screen magnifier.
@@ -535,6 +584,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_TRUE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Disabling screen magnifier.
@@ -544,6 +594,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Enabling large cursor.
@@ -553,6 +604,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_TRUE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Disabling large cursor.
@@ -562,6 +614,7 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Enabling all of the a11y features.
@@ -575,6 +628,7 @@
   EXPECT_TRUE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_TRUE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_TRUE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 
   // Disabling all of the a11y features.
@@ -588,6 +642,30 @@
   EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
   EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
+  CloseDetailMenu();
+
+  // Autoclick is disabled on login screen.
+  SetLoginStatus(ash::user::LOGGED_IN_USER);
+
+  // Enabling autoclick.
+  AccessibilityManager::Get()->EnableAutoclick(true);
+  EXPECT_TRUE(CreateDetailedMenu());
+  EXPECT_FALSE(IsSpokenFeedbackEnabledOnDetailMenu());
+  EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
+  EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
+  EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_TRUE(IsAutoclickEnabledOnDetailMenu());
+  CloseDetailMenu();
+
+  // Disabling autoclick.
+  AccessibilityManager::Get()->EnableAutoclick(false);
+  EXPECT_TRUE(CreateDetailedMenu());
+  EXPECT_FALSE(IsSpokenFeedbackEnabledOnDetailMenu());
+  EXPECT_FALSE(IsHighContrastEnabledOnDetailMenu());
+  EXPECT_FALSE(IsScreenMagnifierEnabledOnDetailMenu());
+  EXPECT_FALSE(IsLargeCursorEnabledOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu());
   CloseDetailMenu();
 }
 
@@ -598,6 +676,7 @@
   EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu());
   EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu());
   EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu());
+  EXPECT_FALSE(IsAutoclickMenuShownOnDetailMenu());
   CloseDetailMenu();
 
   SetLoginStatus(ash::user::LOGGED_IN_USER);
@@ -606,6 +685,7 @@
   EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu());
   EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorMenuShownOnDetailMenu());
+  EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu());
   CloseDetailMenu();
 
   SetLoginStatus(ash::user::LOGGED_IN_LOCKED);
@@ -614,6 +694,7 @@
   EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu());
   EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu());
   EXPECT_FALSE(IsLargeCursorMenuShownOnDetailMenu());
+  EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu());
   CloseDetailMenu();
 }
 
diff --git a/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc b/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc
index 95f4640..8571363 100644
--- a/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc
+++ b/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.h"
 
+#include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/component_updater/component_unpacker.cc b/chrome/browser/component_updater/component_unpacker.cc
index d47bce8..5541a9b 100644
--- a/chrome/browser/component_updater/component_unpacker.cc
+++ b/chrome/browser/component_updater/component_unpacker.cc
@@ -9,9 +9,11 @@
 
 #include "base/file_util.h"
 #include "base/json/json_file_value_serializer.h"
+#include "base/logging.h"
 #include "base/memory/scoped_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/values.h"
 #include "chrome/browser/component_updater/component_patcher.h"
 #include "chrome/browser/component_updater/component_updater_service.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -85,27 +87,28 @@
   std::vector<uint8> public_key_;
 };
 
-// Deserialize the CRX manifest. The top level must be a dictionary.
+}  // namespace.
+
 // TODO(cpu): add a specific attribute check to a component json that the
 // extension unpacker will reject, so that a component cannot be installed
 // as an extension.
-base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) {
+scoped_ptr<base::DictionaryValue> ReadManifest(
+    const base::FilePath& unpack_path) {
   base::FilePath manifest =
       unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
   if (!base::PathExists(manifest))
-    return NULL;
+    return scoped_ptr<base::DictionaryValue>();
   JSONFileValueSerializer serializer(manifest);
   std::string error;
   scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
   if (!root.get())
-    return NULL;
+    return scoped_ptr<base::DictionaryValue>();
   if (!root->IsType(base::Value::TYPE_DICTIONARY))
-    return NULL;
-  return static_cast<base::DictionaryValue*>(root.release());
+    return scoped_ptr<base::DictionaryValue>();
+  return scoped_ptr<base::DictionaryValue>(
+      static_cast<base::DictionaryValue*>(root.release())).Pass();
 }
 
-}  // namespace.
-
 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
                                      const base::FilePath& path,
                                      const std::string& fingerprint,
diff --git a/chrome/browser/component_updater/component_unpacker.h b/chrome/browser/component_updater/component_unpacker.h
index 6ae7277..903b495 100644
--- a/chrome/browser/component_updater/component_unpacker.h
+++ b/chrome/browser/component_updater/component_unpacker.h
@@ -9,10 +9,16 @@
 #include <vector>
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/memory/scoped_ptr.h"
 
 class ComponentInstaller;
 class ComponentPatcher;
 
+// Deserializes the CRX manifest. The top level must be a dictionary.
+scoped_ptr<base::DictionaryValue> ReadManifest(
+    const base::FilePath& unpack_path);
+
 // In charge of unpacking the component CRX package and verifying that it is
 // well formed and the cryptographic signature is correct. If there is no
 // error the component specific installer will be invoked to proceed with
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc
index a4829d2..e7c5f9d 100644
--- a/chrome/browser/component_updater/component_updater_service.cc
+++ b/chrome/browser/component_updater/component_updater_service.cc
@@ -204,6 +204,7 @@
 
 CrxUpdateItem::CrxUpdateItem()
     : status(kNew),
+      on_demand(false),
       diff_update_failed(false),
       error_category(0),
       error_code(0),
@@ -258,7 +259,7 @@
   virtual Status Start() OVERRIDE;
   virtual Status Stop() OVERRIDE;
   virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
-  virtual Status CheckForUpdateSoon(const std::string& component_id) OVERRIDE;
+  virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
   virtual void GetComponents(
       std::vector<CrxComponentInfo>* components) OVERRIDE;
 
@@ -343,6 +344,14 @@
 
   void ProcessPendingItems();
 
+  CrxUpdateItem* FindReadyComponent();
+
+  void UpdateComponent(CrxUpdateItem* workitem);
+
+  void AddUpdateCheckItems(std::string* query);
+
+  void DoUpdateCheck(const std::string& query);
+
   void ScheduleNextRun(StepDelayInterval step_delay);
 
   void ParseManifest(const std::string& xml);
@@ -353,6 +362,8 @@
                       ComponentUnpacker::Error error,
                       int extended_error);
 
+  void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
+
   size_t ChangeItemStatus(CrxUpdateItem::Status from,
                           CrxUpdateItem::Status to);
 
@@ -361,6 +372,8 @@
   void NotifyComponentObservers(ComponentObserver::Events event,
                                 int extra) const;
 
+  bool HasOnDemandItems() const;
+
   scoped_ptr<ComponentUpdateService::Configurator> config_;
 
   scoped_ptr<ComponentPatcher> component_patcher_;
@@ -373,9 +386,6 @@
   typedef std::vector<CrxUpdateItem*> UpdateItems;
   UpdateItems work_items_;
 
-  // A particular set of items from work_items_, which should be checked ASAP.
-  std::set<CrxUpdateItem*> requested_work_items_;
-
   base::OneShotTimer<CrxUpdateService> timer_;
 
   const Version chrome_version_;
@@ -428,8 +438,20 @@
   return kOk;
 }
 
+bool CrxUpdateService::HasOnDemandItems() const {
+  class Helper {
+   public:
+    static bool IsOnDemand(CrxUpdateItem* item) {
+      return item->on_demand;
+    }
+  };
+  return std::find_if(work_items_.begin(),
+                      work_items_.end(),
+                      Helper::IsOnDemand) != work_items_.end();
+}
+
 // This function sets the timer which will call ProcessPendingItems() or
-// ProcessRequestedItem() if there is an important requested item.  There
+// ProcessRequestedItem() if there is an on_demand item.  There
 // are three kinds of waits:
 //  - a short delay, when there is immediate work to be done.
 //  - a medium delay, when there are updates to be applied within the current
@@ -449,7 +471,7 @@
   // Keep the delay short if in the middle of an update (step_delay),
   // or there are new requested_work_items_ that have not been processed yet.
   int64 delay_seconds = 0;
-  if (requested_work_items_.empty()) {
+  if (!HasOnDemandItems()) {
     switch (step_delay) {
       case kStepDelayShort:
         delay_seconds = config_->StepDelay();
@@ -489,6 +511,49 @@
   return (*it);
 }
 
+// Changes a component's status, clearing on_demand and firing notifications as
+// necessary. By convention, this is the only function that can change a
+// CrxUpdateItem's |status|.
+// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
+void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
+                                       CrxUpdateItem::Status to) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (to == CrxUpdateItem::kNoUpdate ||
+      to == CrxUpdateItem::kUpdated ||
+      to == CrxUpdateItem::kUpToDate) {
+    item->on_demand = false;
+  }
+
+  item->status = to;
+
+  ComponentObserver* observer = item->component.observer;
+  if (observer) {
+    switch (to) {
+      case CrxUpdateItem::kCanUpdate:
+        observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
+        break;
+      case CrxUpdateItem::kUpdatingDiff:
+      case CrxUpdateItem::kUpdating:
+        observer->OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0);
+        break;
+      case CrxUpdateItem::kUpdated:
+        observer->OnEvent(ComponentObserver::COMPONENT_UPDATED, 0);
+        break;
+      case CrxUpdateItem::kUpToDate:
+      case CrxUpdateItem::kNoUpdate:
+        observer->OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0);
+        break;
+      case CrxUpdateItem::kNew:
+      case CrxUpdateItem::kChecking:
+      case CrxUpdateItem::kDownloading:
+      case CrxUpdateItem::kDownloadingDiff:
+      case CrxUpdateItem::kLastStatus:
+        // No notification for these states.
+        break;
+    }
+  }
+}
+
 // Changes all the components in |work_items_| that have |from| status to
 // |to| status and returns how many have been changed.
 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
@@ -500,7 +565,7 @@
     CrxUpdateItem* item = *it;
     if (item->status != from)
       continue;
-    item->status = to;
+    ChangeItemState(item, to);
     ++count;
   }
   return count;
@@ -545,20 +610,17 @@
 // The component to add is |item| and the |query| string is modified with the
 // required omaha compatible query. Returns false when the query string is
 // longer than specified by UrlSizeLimit().
-// If the item is currently on the requested_work_items_ list, the update check
-// is considered to be "on-demand": the server may honor on-demand checks by
-// serving updates at 100% rather than a gated fraction.
 bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
                                             std::string* query) {
   if (!AddQueryString(item->id,
                       item->component.version.GetString(),
                       item->component.fingerprint,
-                      requested_work_items_.count(item) > 0,  // is_ondemand
+                      item->on_demand,
                       config_->UrlSizeLimit(),
                       query))
     return false;
 
-  item->status = CrxUpdateItem::kChecking;
+  ChangeItemState(item, CrxUpdateItem::kChecking);
   item->last_check = base::Time::Now();
   item->previous_version = item->component.version;
   item->next_version = Version();
@@ -577,7 +639,7 @@
 // Start the process of checking for an update, for a particular component
 // that was previously registered.
 // |component_id| is a value returned from GetCrxComponentID().
-ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
+ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
     const std::string& component_id) {
   CrxUpdateItem* uit;
   uit = FindUpdateItemById(component_id);
@@ -605,8 +667,8 @@
     case CrxUpdateItem::kUpdated:
     case CrxUpdateItem::kUpToDate:
     case CrxUpdateItem::kNoUpdate:
-      uit->status = CrxUpdateItem::kNew;
-      requested_work_items_.insert(uit);
+      ChangeItemState(uit, CrxUpdateItem::kNew);
+      uit->on_demand = true;
       break;
     case CrxUpdateItem::kLastStatus:
       NOTREACHED() << uit->status;
@@ -637,54 +699,75 @@
   }
 }
 
-// Here is where the work gets scheduled. Given that our |work_items_| list
-// is expected to be ten or less items, we simply loop several times.
+// This is the main loop of the component updater.
 void CrxUpdateService::ProcessPendingItems() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // First check for ready upgrades and do one. The first
-  // step is to fetch the crx package.
-  for (UpdateItems::const_iterator it = work_items_.begin();
-       it != work_items_.end(); ++it) {
-    CrxUpdateItem* item = *it;
-    if (item->status != CrxUpdateItem::kCanUpdate)
-      continue;
-    // Found component to update, start the process.
-    CRXContext* context = new CRXContext;
-    context->pk_hash = item->component.pk_hash;
-    context->id = item->id;
-    context->installer = item->component.installer;
-    context->fingerprint = item->next_fp;
-    GURL package_url;
-    if (CanTryDiffUpdate(item, *config_)) {
-      package_url = item->diff_crx_url;
-      item->status = CrxUpdateItem::kDownloadingDiff;
-    } else {
-      package_url = item->crx_url;
-      item->status = CrxUpdateItem::kDownloading;
-    }
-    url_fetcher_.reset(net::URLFetcher::Create(
-        0, package_url, net::URLFetcher::GET,
-        MakeContextDelegate(this, context)));
-    StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
+  CrxUpdateItem* ready_upgrade = FindReadyComponent();
+  if (ready_upgrade) {
+    UpdateComponent(ready_upgrade);
     return;
   }
-
   std::string query;
-  // If no pending upgrades, we check if there are new components we have not
-  // checked against the server. We can batch some in a single url request.
+  AddUpdateCheckItems(&query);
+  if (!query.empty()) {
+    DoUpdateCheck(query);
+    return;
+  }
+  // No components to update. The next check will be after a long sleep.
+  ScheduleNextRun(kStepDelayLong);
+}
+
+CrxUpdateItem* CrxUpdateService::FindReadyComponent() {
+  class Helper {
+   public:
+    static bool IsReadyOnDemand(CrxUpdateItem* item) {
+      return item->on_demand && IsReady(item);
+    }
+    static bool IsReady(CrxUpdateItem* item) {
+      return item->status == CrxUpdateItem::kCanUpdate;
+    }
+  };
+
+  std::vector<CrxUpdateItem*>::iterator it = std::find_if(
+      work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
+  if (it != work_items_.end())
+    return *it;
+  it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
+  if (it != work_items_.end())
+    return *it;
+  return NULL;
+}
+
+void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
+  CRXContext* context = new CRXContext;
+  context->pk_hash = workitem->component.pk_hash;
+  context->id = workitem->id;
+  context->installer = workitem->component.installer;
+  context->fingerprint = workitem->next_fp;
+  GURL package_url;
+  if (CanTryDiffUpdate(workitem, *config_)) {
+    package_url = workitem->diff_crx_url;
+    ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff);
+  } else {
+    package_url = workitem->crx_url;
+    ChangeItemState(workitem, CrxUpdateItem::kDownloading);
+  }
+  url_fetcher_.reset(net::URLFetcher::Create(
+      0, package_url, net::URLFetcher::GET,
+      MakeContextDelegate(this, context)));
+  StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
+}
+
+// Given that our |work_items_| list is expected to contain relatively few
+// items, we simply loop several times.
+void CrxUpdateService::AddUpdateCheckItems(std::string* query){
   for (UpdateItems::const_iterator it = work_items_.begin();
        it != work_items_.end(); ++it) {
     CrxUpdateItem* item = *it;
     if (item->status != CrxUpdateItem::kNew)
       continue;
-    if (!AddItemToUpdateCheck(item, &query))
+    if (!AddItemToUpdateCheck(item, query))
       break;
-    // Requested work items may speed up the update cycle up until
-    // the point that we start an update check. I.e., transition
-    // from kNew -> kChecking.  Since the service doesn't guarantee that
-    // the requested items make it any further than kChecking,
-    // forget them now.
-    requested_work_items_.erase(item);
   }
 
   // Next we can go back to components we already checked, here
@@ -702,7 +785,7 @@
     base::TimeDelta delta = base::Time::Now() - item->last_check;
     if (delta < min_delta_time)
       continue;
-    if (!AddItemToUpdateCheck(item, &query))
+    if (!AddItemToUpdateCheck(item, query))
       break;
   }
 
@@ -716,26 +799,21 @@
     base::TimeDelta delta = base::Time::Now() - item->last_check;
     if (delta < min_delta_time)
       continue;
-    if (!AddItemToUpdateCheck(item, &query))
+    if (!AddItemToUpdateCheck(item, query))
       break;
   }
+}
 
-  if (!query.empty()) {
-    // We got components to check. Start the url request and exit.
-    const std::string full_query =
-        MakeFinalQuery(config_->UpdateUrl().spec(),
-                       query,
-                       config_->ExtraRequestParams());
+void CrxUpdateService::DoUpdateCheck(const std::string& query) {
+  const std::string full_query =
+      MakeFinalQuery(config_->UpdateUrl().spec(),
+                     query,
+                     config_->ExtraRequestParams());
 
-    url_fetcher_.reset(net::URLFetcher::Create(
-        0, GURL(full_query), net::URLFetcher::GET,
-        MakeContextDelegate(this, new UpdateContext())));
-    StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
-    return;
-  }
-
-  // No components to update. Next check after the long sleep.
-  ScheduleNextRun(kStepDelayLong);
+  url_fetcher_.reset(net::URLFetcher::Create(
+      0, GURL(full_query), net::URLFetcher::GET,
+      MakeContextDelegate(this, new UpdateContext())));
+  StartFetch(url_fetcher_.get(), config_->RequestContext(), false);
 }
 
 // Called when we got a response from the update server. It consists of an xml
@@ -794,18 +872,18 @@
 
     if (it->version.empty()) {
       // No version means no update available.
-      crx->status = CrxUpdateItem::kNoUpdate;
+      ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
       continue;
     }
     if (!IsVersionNewer(crx->component.version, it->version)) {
       // Our component is up to date.
-      crx->status = CrxUpdateItem::kUpToDate;
+      ChangeItemState(crx, CrxUpdateItem::kUpToDate);
       continue;
     }
     if (!it->browser_min_version.empty()) {
       if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
         // Does not apply for this chrome version.
-        crx->status = CrxUpdateItem::kNoUpdate;
+        ChangeItemState(crx, CrxUpdateItem::kNoUpdate);
         continue;
       }
     }
@@ -813,15 +891,10 @@
     // notifications.
     crx->crx_url = it->crx_url;
     crx->diff_crx_url = it->diff_crx_url;
-    crx->status = CrxUpdateItem::kCanUpdate;
+    ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
     crx->next_version = Version(it->version);
     crx->next_fp = it->package_fingerprint;
     ++update_pending;
-
-    if (crx->component.observer) {
-      crx->component.observer->OnEvent(
-          ComponentObserver::COMPONENT_UPDATE_FOUND, 0);
-    }
   }
 
   // All the components that are not mentioned in the manifest we
@@ -897,11 +970,6 @@
 
     url_fetcher_.reset();
 
-    if (crx->component.observer) {
-      crx->component.observer->OnEvent(
-          ComponentObserver::COMPONENT_UPDATE_READY, 0);
-    }
-
     // Why unretained? See comment at top of file.
     BrowserThread::PostDelayedTask(
         BrowserThread::FILE,
@@ -975,11 +1043,11 @@
     }
 
   if (is_success) {
-    item->status = CrxUpdateItem::kUpdated;
+    ChangeItemState(item, CrxUpdateItem::kUpdated);
     item->component.version = item->next_version;
     item->component.fingerprint = item->next_fp;
   } else {
-    item->status = CrxUpdateItem::kNoUpdate;
+    ChangeItemState(item, CrxUpdateItem::kNoUpdate);
     item->error_category = error_category;
     item->error_code = error;
     item->extra_code1 = extra_code;
diff --git a/chrome/browser/component_updater/component_updater_service.h b/chrome/browser/component_updater/component_updater_service.h
index 027d30f..a4df001 100644
--- a/chrome/browser/component_updater/component_updater_service.h
+++ b/chrome/browser/component_updater/component_updater_service.h
@@ -66,6 +66,13 @@
     // Sent when the new component has been downloaded and an installation
     // or upgrade is about to be attempted.
     COMPONENT_UPDATE_READY,
+
+    // Sent when a component has been successfully updated.
+    COMPONENT_UPDATED,
+
+    // Sent when a component has not been updated following an update check:
+    // either there was no update available, or an update failed.
+    COMPONENT_NOT_UPDATED,
   };
 
   virtual ~ComponentObserver() {}
@@ -178,21 +185,25 @@
   // before calling Start().
   virtual Status RegisterComponent(const CrxComponent& component) = 0;
 
-  // Ask the component updater to do an update check for a previously
-  // registered component, soon. If an update or check is already in progress,
-  // returns |kInProgress|. The same component cannot be checked repeatedly
-  // in a short interval either (returns |kError| if so).
-  // There is no guarantee that the item will actually be updated,
-  // since another item may be chosen to be updated. Since there is
-  // no time guarantee, there is no notification if the item is not updated.
-  // However, the ComponentInstaller should know if an update succeeded
-  // via the Install() hook.
-  virtual Status CheckForUpdateSoon(const std::string& component_id) = 0;
-
   // Returns a list of registered components.
   virtual void GetComponents(std::vector<CrxComponentInfo>* components) = 0;
 
   virtual ~ComponentUpdateService() {}
+
+  // TODO(waffles): Remove PNaCl as a friend once an alternative on-demand
+  // trigger is available.
+  friend class ComponentsUI;
+  friend class PnaclComponentInstaller;
+  friend class OnDemandTester;
+
+ private:
+  // Ask the component updater to do an update check for a previously
+  // registered component, immediately. If an update or check is already
+  // in progress, returns |kInProgress|.
+  // There is no guarantee that the item will actually be updated,
+  // since an update may not be available. Listeners for the component will
+  // know the outcome of the check.
+  virtual Status OnDemandUpdate(const std::string& component_id) = 0;
 };
 
 // Creates the component updater. You must pass a valid |config| allocated on
diff --git a/chrome/browser/component_updater/crx_update_item.h b/chrome/browser/component_updater/crx_update_item.h
index 9378401..ba4e722 100644
--- a/chrome/browser/component_updater/crx_update_item.h
+++ b/chrome/browser/component_updater/crx_update_item.h
@@ -19,12 +19,13 @@
 // is modified as the item is processed by the update pipeline. The expected
 // transition graph is:
 //
-//                                 kNew
-//                                  |
-//                                  V
-//     +----------------------> kChecking -<---------+-----<-------+
-//     |                            |                |             |
-//     |              error         V       no       |             |
+//                  on-demand                on-demand
+//   +---------------------------> kNew <--------------+-------------+
+//   |                              |                  |             |
+//   |                              V                  |             |
+//   |   +--------------------> kChecking -<-------+---|---<-----+   |
+//   |   |                          |              |   |         |   |
+//   |   |            error         V       no     |   |         |   |
 //  kNoUpdate <---------------- [update?] ->---- kUpToDate     kUpdated
 //     ^                            |                              ^
 //     |                        yes |                              |
@@ -63,7 +64,10 @@
     kLastStatus
   };
 
+  // Call CrxUpdateService::ChangeItemState to change |status|. The function may
+  // enforce conditions or notify observers of the change.
   Status status;
+
   std::string id;
   CrxComponent component;
 
@@ -79,6 +83,9 @@
   std::string previous_fp;
   std::string next_fp;
 
+  // True if the current update check cycle is on-demand.
+  bool on_demand;
+
   // True if the differential update failed for any reason.
   bool diff_update_failed;
 
diff --git a/chrome/browser/component_updater/default_component_installer.cc b/chrome/browser/component_updater/default_component_installer.cc
index b610f2e..51b2df2 100644
--- a/chrome/browser/component_updater/default_component_installer.cc
+++ b/chrome/browser/component_updater/default_component_installer.cc
@@ -8,6 +8,8 @@
 #include "base/files/file_path.h"
 #include "base/values.h"
 #include "base/version.h"
+// TODO(ddorwin): Find a better place for ReadManifest.
+#include "chrome/browser/component_updater/component_unpacker.h"
 #include "chrome/browser/component_updater/default_component_installer.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -17,6 +19,9 @@
 const char kNullVersion[] = "0.0.0.0";
 }  // namespace
 
+ComponentInstallerTraits::~ComponentInstallerTraits() {
+}
+
 DefaultComponentInstaller::DefaultComponentInstaller(
     scoped_ptr<ComponentInstallerTraits> installer_traits)
     : current_version_(kNullVersion) {
@@ -76,7 +81,13 @@
     return false;
   }
   current_version_ = version;
-  installer_traits_->ComponentReady(current_version_, GetInstallDirectory());
+  // TODO(ddorwin): Change the parameter to scoped_ptr<base::DictionaryValue>
+  // so we can avoid this DeepCopy.
+  current_manifest_.reset(manifest.DeepCopy());
+  installer_traits_->ComponentReady(
+      current_version_,
+      GetInstallDirectory(),
+      scoped_ptr<base::DictionaryValue>(current_manifest_->DeepCopy()).Pass());
   return true;
 }
 
@@ -133,8 +144,17 @@
 
   if (found) {
     current_version_ = latest_version;
+    // TODO(ddorwin): Remove these members and pass them directly to
+    // FinishRegistration().
     base::ReadFileToString(latest_dir.AppendASCII("manifest.fingerprint"),
                            &current_fingerprint_);
+    current_manifest_= ReadManifest(latest_dir);
+    if (!current_manifest_) {
+      DLOG(ERROR) << "Failed to read manifest for "
+                  << installer_traits_->GetName() << " ("
+                  << base_dir.MaybeAsASCII() << ").";
+      return;
+    }
   }
 
   // Remove older versions of the component. None should be in use during
@@ -159,26 +179,33 @@
 void DefaultComponentInstaller::FinishRegistration(
     ComponentUpdateService* cus) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  CrxComponent crx;
-  crx.name = installer_traits_->GetName();
-  crx.installer = this;
-  crx.version = current_version_;
-  crx.fingerprint = current_fingerprint_;
-  installer_traits_->GetHash(&crx.pk_hash);
-  ComponentUpdateService::Status status = cus->RegisterComponent(crx);
-  if (status != ComponentUpdateService::kOk &&
-      status != ComponentUpdateService::kReplaced) {
-    NOTREACHED() << "Component registration failed for "
-                 << installer_traits_->GetName();
-    return;
+  if (installer_traits_->CanAutoUpdate()) {
+    CrxComponent crx;
+    crx.name = installer_traits_->GetName();
+    crx.installer = this;
+    crx.version = current_version_;
+    crx.fingerprint = current_fingerprint_;
+    installer_traits_->GetHash(&crx.pk_hash);
+    ComponentUpdateService::Status status = cus->RegisterComponent(crx);
+    if (status != ComponentUpdateService::kOk &&
+        status != ComponentUpdateService::kReplaced) {
+      NOTREACHED() << "Component registration failed for "
+                   << installer_traits_->GetName();
+      return;
+    }
   }
 
   if (current_version_.CompareTo(base::Version(kNullVersion)) > 0) {
+    // TODO(ddorwin): Call this function directly the UI thread. The only
+    // implementation posts back to the UI thread. Then post to UI in Install().
+    scoped_ptr<base::DictionaryValue> manifest_copy(
+        current_manifest_->DeepCopy());
     content::BrowserThread::PostTask(
         content::BrowserThread::FILE, FROM_HERE,
         base::Bind(&ComponentInstallerTraits::ComponentReady,
                    base::Unretained(installer_traits_.get()),
                    current_version_,
-                   GetInstallDirectory()));
+                   GetInstallDirectory(),
+                   base::Passed(&manifest_copy)));
   }
 }
diff --git a/chrome/browser/component_updater/default_component_installer.h b/chrome/browser/component_updater/default_component_installer.h
index 10bdcc3..a55537c 100644
--- a/chrome/browser/component_updater/default_component_installer.h
+++ b/chrome/browser/component_updater/default_component_installer.h
@@ -24,7 +24,7 @@
 // class.
 class ComponentInstallerTraits {
  public:
-  virtual ~ComponentInstallerTraits() {}
+  virtual ~ComponentInstallerTraits();
 
   // Verifies that a working installation resides within the directory specified
   // by |dir|. |dir| is of the form <base directory>/<version>.
@@ -49,10 +49,13 @@
   // notified of a successful install, and is meant to support follow-on work
   // such as updating paths elsewhere in Chrome. Called only from the FILE
   // thread.
-  // |version| is the version of the component, while |path| is the path to the
-  // install directory.
-  virtual void ComponentReady(const base::Version& version,
-                              const base::FilePath& install_dir) = 0;
+  // |version| is the version of the component.
+  // |install_dir| is the path to the install directory for this version.
+  // |manifest| is the manifest for this version of the component.
+  virtual void ComponentReady(
+      const base::Version& version,
+      const base::FilePath& install_dir,
+      scoped_ptr<base::DictionaryValue> manifest) = 0;
 
   // Returns the directory that the installer will place versioned installs of
   // the component into.
@@ -95,6 +98,7 @@
 
   base::Version current_version_;
   std::string current_fingerprint_;
+  scoped_ptr<base::DictionaryValue> current_manifest_;
   scoped_ptr<ComponentInstallerTraits> installer_traits_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultComponentInstaller);
diff --git a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
index e0147a9..590db14 100644
--- a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
+++ b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
@@ -489,7 +489,7 @@
   }
   set_current_version(Version(kNullVersion));
   CrxComponent pnacl_component = GetCrxComponent();
-  ComponentUpdateService::Status status = cus_->CheckForUpdateSoon(
+  ComponentUpdateService::Status status = cus_->OnDemandUpdate(
       GetCrxComponentID(pnacl_component));
   if (status != ComponentUpdateService::kOk) {
     cb.Run(false);
diff --git a/chrome/browser/component_updater/test/component_updater_service_unittest.cc b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
index 3e4fb5d..2839764 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.cc
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
@@ -53,18 +53,6 @@
     quit_closure_.Run();
     return 0;
   }
-
-  // Look for checks to issue in the middle of the loop.
-  for (std::list<CheckAtLoopCount>::iterator
-           i = components_to_check_.begin();
-       i != components_to_check_.end(); ) {
-    if (i->second == times_) {
-      cus_->CheckForUpdateSoon(GetCrxComponentID(*i->first));
-      i = components_to_check_.erase(i);
-    } else {
-      ++i;
-    }
-  }
   return 1;
 }
 
@@ -122,11 +110,6 @@
   ondemand_time_ = seconds;
 }
 
-void TestConfigurator::AddComponentToCheck(CrxComponent* com,
-                                           int at_loop_iter) {
-  components_to_check_.push_back(std::make_pair(com, at_loop_iter));
-}
-
 void TestConfigurator::SetComponentUpdateService(ComponentUpdateService* cus) {
   cus_ = cus;
 }
@@ -254,6 +237,11 @@
   return pings_str;
 }
 
+ComponentUpdateService::Status OnDemandTester::OnDemand(
+    ComponentUpdateService* cus, const std::string& component_id) {
+  return cus->OnDemandUpdate(component_id);
+}
+
 // Verify that our test fixture work and the component updater can
 // be created and destroyed with no side effects.
 TEST_F(ComponentUpdaterTest, VerifyFixture) {
@@ -303,6 +291,10 @@
   EXPECT_CALL(observer,
               OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
               .Times(2);
+
+  EXPECT_CALL(observer,
+              OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+              .Times(2);
   RunThreads();
 
   EXPECT_EQ(2, interceptor.GetHitCount());
@@ -328,6 +320,9 @@
   EXPECT_CALL(observer,
               OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
               .Times(2);
+  EXPECT_CALL(observer,
+              OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+              .Times(2);
   RunThreads();
 
   EXPECT_EQ(4, interceptor.GetHitCount());
@@ -370,8 +365,17 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
-                .Times(2);
+                .Times(1);
+    EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
+                .Times(1);
   }
 
   MockComponentObserver observer2;
@@ -381,8 +385,17 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
-                .Times(2);
+                .Times(1);
+    EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
+                .Times(1);
   }
 
   TestInstaller installer1;
@@ -469,7 +482,7 @@
 //    nothing happens.
 //  - We ping.
 //  - This triggers a second loop, which has a reply that triggers an install.
-TEST_F(ComponentUpdaterTest, CheckForUpdateSoon) {
+TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
   std::map<std::string, std::string> map;
   map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
   map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
@@ -487,9 +500,18 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -501,15 +523,24 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATE_FOUND, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -540,9 +571,17 @@
                           test_file("updatecheck_reply_1.xml"));
   interceptor.SetResponse(GURL(expected_crx_url),
                           test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-  // Test success.
-  test_configurator()->SetLoopCount(2);
-  test_configurator()->AddComponentToCheck(&com2, 1);
+  // No update normally.
+  test_configurator()->SetLoopCount(1);
+  component_updater()->Start();
+  RunThreads();
+  component_updater()->Stop();
+
+  // Update after an on-demand check is issued.
+  EXPECT_EQ(ComponentUpdateService::kOk,
+            OnDemandTester::OnDemand(component_updater(),
+                                     GetCrxComponentID(com2)));
+  test_configurator()->SetLoopCount(1);
   component_updater()->Start();
   RunThreads();
 
@@ -556,7 +595,8 @@
   // Also check what happens if previous check too soon.
   test_configurator()->SetOnDemandTime(60 * 60);
   EXPECT_EQ(ComponentUpdateService::kError,
-            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
+            OnDemandTester::OnDemand(component_updater(),
+                                     GetCrxComponentID(com2)));
   // Okay, now reset to 0 for the other tests.
   test_configurator()->SetOnDemandTime(0);
   component_updater()->Stop();
@@ -570,6 +610,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -580,6 +623,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -595,7 +641,8 @@
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
   EXPECT_EQ(ComponentUpdateService::kOk,
-            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
+            OnDemandTester::OnDemand(component_updater(),
+                                     GetCrxComponentID(com2)));
 
   RunThreads();
 
@@ -609,6 +656,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -619,6 +669,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -628,7 +681,8 @@
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
   EXPECT_EQ(ComponentUpdateService::kOk,
-            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
+            OnDemandTester::OnDemand(component_updater(),
+                                     GetCrxComponentID(com2)));
 
   RunThreads();
 
@@ -664,9 +718,15 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATE_READY, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -678,9 +738,15 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -738,6 +804,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer1,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer1,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
@@ -749,6 +818,9 @@
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_STARTED, 0))
                 .Times(1);
     EXPECT_CALL(observer2,
+                OnEvent(ComponentObserver::COMPONENT_NOT_UPDATED, 0))
+                .Times(1);
+    EXPECT_CALL(observer2,
                 OnEvent(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0))
                 .Times(1);
   }
diff --git a/chrome/browser/component_updater/test/component_updater_service_unittest.h b/chrome/browser/component_updater/test/component_updater_service_unittest.h
index c851aee..72ad67e 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.h
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.h
@@ -87,8 +87,6 @@
 
   void SetOnDemandTime(int seconds);
 
-  void AddComponentToCheck(CrxComponent* com, int at_loop_iter);
-
   void SetComponentUpdateService(ComponentUpdateService* cus);
 
   void SetQuitClosure(const base::Closure& quit_closure);
@@ -98,7 +96,6 @@
   int recheck_time_;
   int ondemand_time_;
 
-  std::list<CheckAtLoopCount> components_to_check_;
   ComponentUpdateService* cus_;
   scoped_refptr<net::TestURLRequestContextGetter> context_;
   base::Closure quit_closure_;
@@ -175,4 +172,10 @@
   MOCK_METHOD2(OnEvent, void(Events event, int extra));
 };
 
+class OnDemandTester {
+ public:
+  static ComponentUpdateService::Status OnDemand(
+      ComponentUpdateService* cus, const std::string& component_id);
+};
+
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index 60382d1..8cfbf33 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -13,7 +13,10 @@
 #include "base/compiler_specific.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
+#include "base/logging.h"
 #include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/component_updater/component_updater_service.h"
@@ -75,9 +78,12 @@
   return base_path.AppendASCII("_platform_specific").AppendASCII(platform_arch);
 }
 
-bool MakeWidevineCdmPluginInfo(const base::FilePath& path,
-                               const base::Version& version,
-                               content::PepperPluginInfo* plugin_info) {
+bool MakeWidevineCdmPluginInfo(
+    const base::Version& version,
+    const base::FilePath& path,
+    const std::vector<base::string16>& additional_param_names,
+    const std::vector<base::string16>& additional_param_values,
+    content::PepperPluginInfo* plugin_info) {
   if (!version.IsValid() ||
       version.components().size() !=
           static_cast<size_t>(kWidevineCdmVersionNumComponents)) {
@@ -95,19 +101,52 @@
       kWidevineCdmPluginMimeType,
       kWidevineCdmPluginExtension,
       kWidevineCdmPluginMimeTypeDescription);
+  widevine_cdm_mime_type.additional_param_names = additional_param_names;
+  widevine_cdm_mime_type.additional_param_values = additional_param_values;
   plugin_info->mime_types.push_back(widevine_cdm_mime_type);
   plugin_info->permissions = kWidevineCdmPluginPermissions;
 
   return true;
 }
 
-void RegisterWidevineCdmWithChrome(const base::FilePath& path,
-                                   const base::Version& version) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  content::PepperPluginInfo plugin_info;
-  if (!MakeWidevineCdmPluginInfo(path, version, &plugin_info))
-    return;
+void GetAdditionalParams(const base::DictionaryValue& manifest,
+                         std::vector<base::string16>* additional_param_names,
+                         std::vector<base::string16>* additional_param_values) {
+  base::string16 codecs;
+  if (manifest.GetString("x-cdm-codecs", &codecs)) {
+    DLOG_IF(WARNING, codecs.empty())
+        << "Widevine CDM component manifest has empty codecs list";
+    additional_param_names->push_back(
+        base::ASCIIToUTF16(kCdmSupportedCodecsParamName));
+    additional_param_values->push_back(codecs);
+  } else {
+    DLOG(WARNING) << "Widevine CDM component manifest is missing codecs";
+    // TODO(ddorwin): Remove this once all users have been updated.
+    // The original manifests did not include this string, so add the base set.
+    additional_param_names->push_back(
+        base::ASCIIToUTF16(kCdmSupportedCodecsParamName));
+    additional_param_values->push_back(base::ASCIIToUTF16("vp8,vorbis"));
+  }
+}
 
+void RegisterWidevineCdmWithChrome(const base::Version& version,
+                                   const base::FilePath& path,
+                                   scoped_ptr<base::DictionaryValue> manifest) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  std::vector<base::string16> additional_param_names;
+  std::vector<base::string16> additional_param_values;
+  GetAdditionalParams(
+      *manifest, &additional_param_names, &additional_param_values);
+  content::PepperPluginInfo plugin_info;
+  if (!MakeWidevineCdmPluginInfo(version,
+                                 path,
+                                 additional_param_names,
+                                 additional_param_values,
+                                 &plugin_info)) {
+    return;
+  }
+
+  // true = Add to beginning of list to override any existing registrations.
   PluginService::GetInstance()->RegisterInternalPlugin(
       plugin_info.ToWebPluginInfo(), true);
   PluginService::GetInstance()->RefreshPlugins();
@@ -127,8 +166,10 @@
                                const base::FilePath& install_dir) OVERRIDE;
   virtual bool VerifyInstallation(
       const base::FilePath& install_dir) const OVERRIDE;
-  virtual void ComponentReady(const base::Version& version,
-                              const base::FilePath& path) OVERRIDE;
+  virtual void ComponentReady(
+      const base::Version& version,
+      const base::FilePath& path,
+      scoped_ptr<base::DictionaryValue> manifest) OVERRIDE;
   virtual base::FilePath GetBaseDirectory() const OVERRIDE;
   virtual void GetHash(std::vector<uint8>* hash) const OVERRIDE;
   virtual std::string GetName() const OVERRIDE;
@@ -156,11 +197,14 @@
 // Once the component is installed, register the new version with Chrome.
 void WidevineCdmComponentInstallerTraits::ComponentReady(
     const base::Version& version,
-    const base::FilePath& path) {
+    const base::FilePath& path,
+    scoped_ptr<base::DictionaryValue> manifest) {
+  // TODO(ddorwin): Check API version compatibility. Return if fails.
   base::FilePath adapter_install_path = GetPlatformDirectory(path)
       .AppendASCII(kWidevineCdmAdapterFileName);
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
-      &RegisterWidevineCdmWithChrome, adapter_install_path, version));
+      &RegisterWidevineCdmWithChrome,
+      version, adapter_install_path, base::Passed(&manifest)));
 }
 
 bool WidevineCdmComponentInstallerTraits::VerifyInstallation(
diff --git a/chrome/browser/content_settings/content_settings_default_provider.cc b/chrome/browser/content_settings/content_settings_default_provider.cc
index 96f07fe..a09172c 100644
--- a/chrome/browser/content_settings/content_settings_default_provider.cc
+++ b/chrome/browser/content_settings/content_settings_default_provider.cc
@@ -12,10 +12,10 @@
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/content_settings_rule.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_pattern.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/content_settings/content_settings_pref_provider.cc b/chrome/browser/content_settings/content_settings_pref_provider.cc
index 482c3a5..3c26e24 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider.cc
@@ -13,11 +13,11 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/content_settings_rule.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_pattern.h"
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index 3646541..901776e 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/prefs/overlay_user_pref_store.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_store.h"
 #include "base/threading/platform_thread.h"
 #include "base/values.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/pref_service_mock_builder.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 078dab4..8801d22 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -8,11 +8,11 @@
 #include "base/json/json_writer.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/content_settings/content_settings_details.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/content_settings/mock_settings_observer.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/crash_upload_list_win.cc b/chrome/browser/crash_upload_list_win.cc
index 418cbcb..5e00525 100644
--- a/chrome/browser/crash_upload_list_win.cc
+++ b/chrome/browser/crash_upload_list_win.cc
@@ -16,6 +16,7 @@
   std::vector<uint8> buffer(1024);
   HANDLE event_log = OpenEventLog(NULL, L"Application");
   if (event_log) {
+    ClearUploads();
     while (true) {
       DWORD bytes_read;
       DWORD bytes_needed;
diff --git a/chrome/browser/devtools/adb_web_socket.cc b/chrome/browser/devtools/adb_web_socket.cc
index b740497..b31c722 100644
--- a/chrome/browser/devtools/adb_web_socket.cc
+++ b/chrome/browser/devtools/adb_web_socket.cc
@@ -24,7 +24,7 @@
     "\r\n";
 
 AdbWebSocket::AdbWebSocket(
-    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+    scoped_refptr<AndroidDevice> device,
     const std::string& socket_name,
     const std::string& url,
     base::MessageLoop* adb_message_loop,
diff --git a/chrome/browser/devtools/adb_web_socket.h b/chrome/browser/devtools/adb_web_socket.h
index 2c4d569..57a7fa8 100644
--- a/chrome/browser/devtools/adb_web_socket.h
+++ b/chrome/browser/devtools/adb_web_socket.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_ADB_WEB_SOCKET_H_
 #define CHROME_BROWSER_DEVTOOLS_ADB_WEB_SOCKET_H_
 
-#include "chrome/browser/devtools/devtools_adb_bridge.h"
+#include "chrome/browser/devtools/android_device.h"
 
 class AdbWebSocket : public base::RefCountedThreadSafe<AdbWebSocket> {
  public:
@@ -20,7 +20,7 @@
     virtual ~Delegate() {}
   };
 
-  AdbWebSocket(scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+  AdbWebSocket(scoped_refptr<AndroidDevice> device,
                const std::string& socket_name,
                const std::string& url,
                base::MessageLoop* adb_message_loop,
@@ -48,7 +48,7 @@
   void OnFrameRead(const std::string& message);
   void OnSocketClosed(bool closed_by_device);
 
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device_;
+  scoped_refptr<AndroidDevice> device_;
   std::string socket_name_;
   std::string url_;
   base::MessageLoop* adb_message_loop_;
diff --git a/chrome/browser/devtools/android_device.cc b/chrome/browser/devtools/android_device.cc
new file mode 100644
index 0000000..c2aa0ba
--- /dev/null
+++ b/chrome/browser/devtools/android_device.cc
@@ -0,0 +1,412 @@
+// Copyright 2013 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/devtools/android_device.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
+#include "chrome/browser/devtools/adb/android_rsa.h"
+#include "chrome/browser/devtools/adb/android_usb_device.h"
+#include "chrome/browser/devtools/adb_client_socket.h"
+#include "net/base/net_errors.h"
+
+using content::BrowserThread;
+
+namespace {
+
+const char kHostTransportCommand[] = "host:transport:%s|%s";
+const char kHostDevicesCommand[] = "host:devices";
+const char kLocalAbstractCommand[] = "localabstract:%s";
+
+const int kAdbPort = 5037;
+const int kBufferSize = 16 * 1024;
+
+// AdbDeviceImpl --------------------------------------------------------------
+
+class AdbDeviceImpl : public AndroidDevice {
+ public:
+  AdbDeviceImpl(const std::string& serial, bool is_connected);
+  virtual void RunCommand(const std::string& command,
+                          const CommandCallback& callback) OVERRIDE;
+  virtual void OpenSocket(const std::string& name,
+                          const SocketCallback& callback) OVERRIDE;
+ private:
+  virtual ~AdbDeviceImpl() {}
+};
+
+AdbDeviceImpl::AdbDeviceImpl(const std::string& serial, bool is_connected)
+    : AndroidDevice(serial, is_connected) {
+}
+
+void AdbDeviceImpl::RunCommand(const std::string& command,
+                               const CommandCallback& callback) {
+  std::string query = base::StringPrintf(kHostTransportCommand,
+                                         serial().c_str(), command.c_str());
+  AdbClientSocket::AdbQuery(kAdbPort, query, callback);
+}
+
+void AdbDeviceImpl::OpenSocket(const std::string& name,
+                               const SocketCallback& callback) {
+  std::string socket_name =
+      base::StringPrintf(kLocalAbstractCommand, name.c_str());
+  AdbClientSocket::TransportQuery(kAdbPort, serial(), socket_name, callback);
+}
+
+// UsbDeviceImpl --------------------------------------------------------------
+
+class UsbDeviceImpl : public AndroidDevice {
+ public:
+  explicit UsbDeviceImpl(AndroidUsbDevice* device);
+  virtual void RunCommand(const std::string& command,
+                          const CommandCallback& callback) OVERRIDE;
+  virtual void OpenSocket(const std::string& name,
+                          const SocketCallback& callback) OVERRIDE;
+ private:
+  void OnOpenSocket(const SocketCallback& callback,
+                    net::StreamSocket* socket,
+                    int result);
+  void OpenedForCommand(const CommandCallback& callback,
+                        net::StreamSocket* socket,
+                        int result);
+  void OnRead(net::StreamSocket* socket,
+              scoped_refptr<net::IOBuffer> buffer,
+              const std::string& data,
+              const CommandCallback& callback,
+              int result);
+
+  virtual ~UsbDeviceImpl() {}
+  scoped_refptr<AndroidUsbDevice> device_;
+};
+
+
+UsbDeviceImpl::UsbDeviceImpl(AndroidUsbDevice* device)
+    : AndroidDevice(device->serial(), device->is_connected()),
+      device_(device) {
+  device_->InitOnCallerThread();
+}
+
+void UsbDeviceImpl::RunCommand(const std::string& command,
+                               const CommandCallback& callback) {
+  net::StreamSocket* socket = device_->CreateSocket(command);
+  int result = socket->Connect(base::Bind(&UsbDeviceImpl::OpenedForCommand,
+                                          this, callback, socket));
+  if (result != net::ERR_IO_PENDING)
+    callback.Run(result, std::string());
+}
+
+void UsbDeviceImpl::OpenSocket(const std::string& name,
+                               const SocketCallback& callback) {
+  std::string socket_name =
+      base::StringPrintf(kLocalAbstractCommand, name.c_str());
+  net::StreamSocket* socket = device_->CreateSocket(socket_name);
+  int result = socket->Connect(base::Bind(&UsbDeviceImpl::OnOpenSocket, this,
+                                          callback, socket));
+  if (result != net::ERR_IO_PENDING)
+    callback.Run(result, NULL);
+}
+
+void UsbDeviceImpl::OnOpenSocket(const SocketCallback& callback,
+                  net::StreamSocket* socket,
+                  int result) {
+  callback.Run(result, result == net::OK ? socket : NULL);
+}
+
+void UsbDeviceImpl::OpenedForCommand(const CommandCallback& callback,
+                                     net::StreamSocket* socket,
+                                     int result) {
+  if (result != net::OK) {
+    callback.Run(result, std::string());
+    return;
+  }
+  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
+  result = socket->Read(buffer, kBufferSize,
+                        base::Bind(&UsbDeviceImpl::OnRead, this,
+                                   socket, buffer, std::string(), callback));
+  if (result != net::ERR_IO_PENDING)
+    OnRead(socket, buffer, std::string(), callback, result);
+}
+
+void UsbDeviceImpl::OnRead(net::StreamSocket* socket,
+                           scoped_refptr<net::IOBuffer> buffer,
+                           const std::string& data,
+                           const CommandCallback& callback,
+                           int result) {
+  if (result <= 0) {
+    callback.Run(result, result == 0 ? data : std::string());
+    delete socket;
+    return;
+  }
+
+  std::string new_data = data + std::string(buffer->data(), result);
+  result = socket->Read(buffer, kBufferSize,
+                        base::Bind(&UsbDeviceImpl::OnRead, this,
+                                   socket, buffer, new_data, callback));
+  if (result != net::ERR_IO_PENDING)
+    OnRead(socket, buffer, new_data, callback, result);
+}
+
+// AdbDeviceProvider -------------------------------------------
+
+class AdbDeviceProvider: public AndroidDeviceProvider {
+ public:
+  virtual void QueryDevices(const QueryDevicesCallback& callback) OVERRIDE;
+ private:
+  void QueryDevicesOnAdbThread(const QueryDevicesCallback& callback);
+  void ReceivedAdbDevices(const QueryDevicesCallback& callback, int result,
+                          const std::string& response);
+
+  virtual ~AdbDeviceProvider();
+};
+
+AdbDeviceProvider::~AdbDeviceProvider() {
+}
+
+void AdbDeviceProvider::QueryDevices(const QueryDevicesCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  adb_thread_->message_loop()->PostTask(
+        FROM_HERE, base::Bind(&AdbDeviceProvider::QueryDevicesOnAdbThread,
+        this, callback));
+}
+
+void AdbDeviceProvider::QueryDevicesOnAdbThread(
+    const QueryDevicesCallback& callback) {
+  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+
+  AdbClientSocket::AdbQuery(
+      kAdbPort, kHostDevicesCommand,
+      base::Bind(&AdbDeviceProvider::ReceivedAdbDevices, this, callback));
+}
+
+void AdbDeviceProvider::ReceivedAdbDevices(const QueryDevicesCallback& callback,
+                                           int result_code,
+                                           const std::string& response) {
+  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+
+  AndroidDevices result;
+
+#if defined(DEBUG_DEVTOOLS)
+  // For desktop remote debugging.
+  result.push_back(new AdbDeviceImpl("", true));
+#endif  // defined(DEBUG_DEVTOOLS)
+
+  std::vector<std::string> serials;
+  Tokenize(response, "\n", &serials);
+  for (size_t i = 0; i < serials.size(); ++i) {
+    std::vector<std::string> tokens;
+    Tokenize(serials[i], "\t ", &tokens);
+    bool offline = tokens.size() > 1 && tokens[1] == "offline";
+    result.push_back(new AdbDeviceImpl(tokens[0], !offline));
+  }
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&AdbDeviceProvider::RunCallbackOnUIThread,
+                          callback, result));
+}
+
+// UsbDeviceProvider -------------------------------------------
+
+class UsbDeviceProvider: public AndroidDeviceProvider {
+ public:
+  explicit UsbDeviceProvider(Profile* profile);
+
+  virtual void QueryDevices(const QueryDevicesCallback& callback) OVERRIDE;
+ private:
+  virtual ~UsbDeviceProvider();
+  void WrapDevicesOnAdbThread(const QueryDevicesCallback& callback,
+                              const AndroidUsbDevices& devices);
+  void EnumeratedDevices(const QueryDevicesCallback& callback,
+                         const AndroidUsbDevices& devices);
+
+  scoped_ptr<crypto::RSAPrivateKey>  rsa_key_;
+};
+
+UsbDeviceProvider::UsbDeviceProvider(Profile* profile){
+  rsa_key_.reset(AndroidRSAPrivateKey(profile));
+}
+
+UsbDeviceProvider::~UsbDeviceProvider() {
+}
+
+void UsbDeviceProvider::QueryDevices(const QueryDevicesCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  AndroidUsbDevice::Enumerate(rsa_key_.get(),
+                              base::Bind(&UsbDeviceProvider::EnumeratedDevices,
+                              this, callback));
+}
+
+void UsbDeviceProvider::EnumeratedDevices(const QueryDevicesCallback& callback,
+                                          const AndroidUsbDevices& devices) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  adb_thread_->message_loop()->PostTask(FROM_HERE,
+                          base::Bind(&UsbDeviceProvider::WrapDevicesOnAdbThread,
+                          this, callback, devices));
+}
+
+void UsbDeviceProvider::WrapDevicesOnAdbThread(
+    const QueryDevicesCallback& callback,const AndroidUsbDevices& devices) {
+  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+  AndroidDevices result;
+  for (AndroidUsbDevices::const_iterator it = devices.begin();
+      it != devices.end(); ++it)
+    result.push_back(new UsbDeviceImpl(*it));
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&UsbDeviceProvider::RunCallbackOnUIThread,
+                          callback, result));
+}
+
+} // namespace
+
+// AndroidDevice -------------------------------------------
+
+AndroidDevice::AndroidDevice(const std::string& serial, bool is_connected)
+    : serial_(serial),
+      is_connected_(is_connected) {
+}
+
+void AndroidDevice::HttpQuery(
+    const std::string& la_name,
+    const std::string& request,
+    const CommandCallback& callback) {
+  OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened, this,
+                                 request, callback));
+}
+
+void AndroidDevice::HttpUpgrade(
+    const std::string& la_name,
+    const std::string& request,
+    const SocketCallback& callback) {
+  OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened2, this,
+                                 request, callback));
+}
+
+AndroidDevice::~AndroidDevice() {
+}
+
+void AndroidDevice::OnHttpSocketOpened(
+    const std::string& request,
+    const CommandCallback& callback,
+    int result,
+    net::StreamSocket* socket) {
+  if (result != net::OK) {
+    callback.Run(result, std::string());
+    return;
+  }
+  AdbClientSocket::HttpQuery(socket, request, callback);
+}
+
+void AndroidDevice::OnHttpSocketOpened2(
+    const std::string& request,
+    const SocketCallback& callback,
+    int result,
+    net::StreamSocket* socket) {
+  if (result != net::OK) {
+    callback.Run(result, NULL);
+    return;
+  }
+  AdbClientSocket::HttpQuery(socket, request, callback);
+}
+
+// AdbCountDevicesCommand -----------------------------------------------------
+// TODO(zvorygin): Remove this class.
+class AdbCountDevicesCommand : public base::RefCountedThreadSafe<
+    AdbCountDevicesCommand, BrowserThread::DeleteOnUIThread> {
+ public:
+  typedef base::Callback<void(int)> Callback;
+
+  AdbCountDevicesCommand(
+      scoped_refptr<RefCountedAdbThread> adb_thread,
+      const Callback& callback);
+
+ private:
+  friend struct BrowserThread::DeleteOnThread<
+      BrowserThread::UI>;
+  friend class base::DeleteHelper<AdbCountDevicesCommand>;
+
+  virtual ~AdbCountDevicesCommand();
+  void RequestAdbDeviceCount();
+  void ReceivedAdbDeviceCount(int result, const std::string& response);
+  void Respond(int count);
+
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
+  Callback callback_;
+};
+
+AdbCountDevicesCommand::AdbCountDevicesCommand(
+    scoped_refptr<RefCountedAdbThread> adb_thread,
+    const Callback& callback)
+    : adb_thread_(adb_thread),
+      callback_(callback) {
+  adb_thread_->message_loop()->PostTask(
+      FROM_HERE, base::Bind(&AdbCountDevicesCommand::RequestAdbDeviceCount,
+                            this));
+}
+
+AdbCountDevicesCommand::~AdbCountDevicesCommand() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void AdbCountDevicesCommand::RequestAdbDeviceCount() {
+  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+  AdbClientSocket::AdbQuery(
+      kAdbPort, kHostDevicesCommand,
+      base::Bind(&AdbCountDevicesCommand::ReceivedAdbDeviceCount, this));
+}
+
+void AdbCountDevicesCommand::ReceivedAdbDeviceCount(
+    int result,
+    const std::string& response) {
+  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+  std::vector<std::string> serials;
+  Tokenize(response, "\n", &serials);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&AdbCountDevicesCommand::Respond, this, serials.size()));
+}
+
+void AdbCountDevicesCommand::Respond(int count) {
+  callback_.Run(count);
+}
+
+// AndroidDeviceProvider ---------------------------------------------------
+
+AndroidDeviceProvider::AndroidDeviceProvider()
+  : adb_thread_(RefCountedAdbThread::GetInstance()) {
+
+}
+
+AndroidDeviceProvider::~AndroidDeviceProvider() {
+}
+
+// static
+void AndroidDeviceProvider::RunCallbackOnUIThread(
+    const QueryDevicesCallback& callback,
+    const AndroidDevices& result) {
+  callback.Run(result);
+}
+
+// static
+void AndroidDeviceProvider::CountDevices(bool discover_usb_devices,
+    const base::Callback<void(int)>& callback) {
+  if (discover_usb_devices) {
+    AndroidUsbDevice::CountDevices(callback);
+    return;
+  }
+
+  new AdbCountDevicesCommand(RefCountedAdbThread::GetInstance(), callback);
+}
+
+// static
+scoped_refptr<AndroidDeviceProvider>
+    AndroidDeviceProvider::GetUsbDeviceProvider(Profile* profile) {
+  return new UsbDeviceProvider(profile);
+}
+
+// static
+scoped_refptr<AndroidDeviceProvider>
+    AndroidDeviceProvider::GetAdbDeviceProvider() {
+  return new AdbDeviceProvider();
+}
diff --git a/chrome/browser/devtools/android_device.h b/chrome/browser/devtools/android_device.h
new file mode 100644
index 0000000..9a1e616
--- /dev/null
+++ b/chrome/browser/devtools/android_device.h
@@ -0,0 +1,94 @@
+// Copyright 2013 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_DEVTOOLS_ANDROID_DEVICE_H_
+#define CHROME_BROWSER_DEVTOOLS_ANDROID_DEVICE_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/devtools/adb/android_usb_device.h"
+#include "chrome/browser/devtools/refcounted_adb_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/rsa_private_key.h"
+#include "net/socket/stream_socket.h"
+
+class AndroidDevice : public base::RefCounted<AndroidDevice> {
+ public:
+  typedef base::Callback<void(int, const std::string&)> CommandCallback;
+  typedef base::Callback<void(int result, net::StreamSocket*)> SocketCallback;
+
+  AndroidDevice(const std::string& serial, bool is_connected);
+
+  virtual void RunCommand(const std::string& command,
+                          const CommandCallback& callback) = 0;
+  virtual void OpenSocket(const std::string& socket_name,
+                          const SocketCallback& callback) = 0;
+  virtual void HttpQuery(const std::string& la_name,
+                         const std::string& request,
+                         const CommandCallback& callback);
+  void HttpUpgrade(const std::string& la_name,
+                   const std::string& request,
+                   const SocketCallback& callback);
+
+  std::string serial() { return serial_; }
+  bool is_connected() { return is_connected_; }
+
+  std::string model() { return model_; }
+  void set_model(const std::string& model) { model_ = model; }
+
+ protected:
+  friend class base::RefCounted<AndroidDevice>;
+  virtual ~AndroidDevice();
+
+ private:
+  void OnHttpSocketOpened(const std::string& request,
+                          const CommandCallback& callback,
+                          int result,
+                          net::StreamSocket* socket);
+  void OnHttpSocketOpened2(const std::string& request,
+                           const SocketCallback& callback,
+                           int result,
+                           net::StreamSocket* socket);
+
+  std::string serial_;
+  bool is_connected_;
+  std::string model_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidDevice);
+};
+
+
+class AndroidDeviceProvider
+    : public base::RefCountedThreadSafe<
+          AndroidDeviceProvider,
+          content::BrowserThread::DeleteOnUIThread> {
+ public:
+  typedef std::vector<scoped_refptr<AndroidDevice> > AndroidDevices;
+  typedef base::Callback<void(const AndroidDevices&)> QueryDevicesCallback;
+
+  virtual void QueryDevices(const QueryDevicesCallback& callback) = 0;
+
+  static void CountDevices(bool discover_usb_devices,
+                           const  base::Callback<void(int)>& callback);
+
+  static scoped_refptr<AndroidDeviceProvider> GetAdbDeviceProvider();
+  static scoped_refptr<AndroidDeviceProvider>
+      GetUsbDeviceProvider(Profile* profile);
+
+ protected:
+  friend struct
+      content::BrowserThread::DeleteOnThread<content::BrowserThread::UI>;
+  friend class base::DeleteHelper<AndroidDeviceProvider>;
+
+  AndroidDeviceProvider();
+  virtual ~AndroidDeviceProvider();
+  static void RunCallbackOnUIThread(const QueryDevicesCallback& callback,
+                                    const AndroidDevices& result);
+
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_ANDROID_DEVICE_H_
diff --git a/chrome/browser/devtools/browser_list_tabcontents_provider.cc b/chrome/browser/devtools/browser_list_tabcontents_provider.cc
index 28de085..ac75d40 100644
--- a/chrome/browser/devtools/browser_list_tabcontents_provider.cc
+++ b/chrome/browser/devtools/browser_list_tabcontents_provider.cc
@@ -6,11 +6,7 @@
 
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -19,158 +15,20 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/devtools_target.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "grit/devtools_discovery_page_resources.h"
-#include "net/base/escape.h"
 #include "net/socket/tcp_listen_socket.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/resource/resource_bundle.h"
 
-using content::DevToolsAgentHost;
-using content::DevToolsHttpHandlerDelegate;
 using content::DevToolsTarget;
 using content::RenderViewHost;
 using content::WebContents;
 
-namespace {
-
-const char kTargetTypePage[] = "page";
-const char kTargetTypeOther[] = "other";
-
-std::string GetExtensionName(WebContents* web_contents) {
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  if (!profile)
-    return std::string();
-
-  extensions::ExtensionHost* extension_host =
-      extensions::ExtensionSystem::Get(profile)->process_manager()->
-          GetBackgroundHostForExtension(web_contents->GetURL().host());
-
-  if (!extension_host || extension_host->host_contents() != web_contents)
-    return std::string();
-
-  return extension_host->extension()->name();
-}
-
-class Target : public content::DevToolsTarget {
- public:
-  Target(WebContents* web_contents, bool is_tab);
-
-  virtual std::string GetId() const OVERRIDE { return id_; }
-  virtual std::string GetType() const OVERRIDE { return type_; }
-  virtual std::string GetTitle() const OVERRIDE { return title_; }
-  virtual std::string GetDescription() const OVERRIDE { return description_; }
-  virtual GURL GetUrl() const OVERRIDE { return url_; }
-  virtual GURL GetFaviconUrl() const OVERRIDE { return favicon_url_; }
-  virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
-    return last_activity_time_;
-  }
-  virtual bool IsAttached() const OVERRIDE {
-    return agent_host_->IsAttached();
-  }
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
-    return agent_host_;
-  }
-  virtual bool Activate() const OVERRIDE;
-  virtual bool Close() const OVERRIDE;
-
- private:
-  scoped_refptr<DevToolsAgentHost> agent_host_;
-  std::string id_;
-  std::string type_;
-  std::string title_;
-  std::string description_;
-  GURL url_;
-  GURL favicon_url_;
-  base::TimeTicks last_activity_time_;
-};
-
-Target::Target(WebContents* web_contents, bool is_tab) {
-  agent_host_ =
-      DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost());
-  id_ = agent_host_->GetId();
-  type_ = is_tab ? kTargetTypePage : kTargetTypeOther;
-  description_ = GetExtensionName(web_contents);
-  title_ = UTF16ToUTF8(net::EscapeForHTML(web_contents->GetTitle()));
-  url_ = web_contents->GetURL();
-  content::NavigationController& controller = web_contents->GetController();
-  content::NavigationEntry* entry = controller.GetActiveEntry();
-  if (entry != NULL && entry->GetURL().is_valid())
-    favicon_url_ = entry->GetFavicon().url;
-  last_activity_time_ = web_contents->GetLastSelectedTime();
-}
-
-bool Target::Activate() const {
-  RenderViewHost* rvh = agent_host_->GetRenderViewHost();
-  if (!rvh)
-    return false;
-  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
-  if (!web_contents)
-    return false;
-  web_contents->GetDelegate()->ActivateContents(web_contents);
-  return true;
-}
-
-bool Target::Close() const {
-  RenderViewHost* rvh = agent_host_->GetRenderViewHost();
-  if (!rvh)
-    return false;
-  rvh->ClosePage();
-  return true;
-}
-
-class WorkerTarget : public content::DevToolsTarget {
- public:
-  explicit WorkerTarget(const content::WorkerService::WorkerInfo& worker_info);
-
-  virtual std::string GetId() const OVERRIDE { return id_; }
-  virtual std::string GetType() const OVERRIDE { return "other"; }
-  virtual std::string GetTitle() const OVERRIDE { return title_; }
-  virtual std::string GetDescription() const OVERRIDE { return description_; }
-  virtual GURL GetUrl() const OVERRIDE { return url_; }
-  virtual GURL GetFaviconUrl() const OVERRIDE { return GURL(); }
-  virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
-    return base::TimeTicks();
-  }
-  virtual bool IsAttached() const OVERRIDE {
-    return agent_host_->IsAttached();
-  }
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
-    return agent_host_;
-  }
-  virtual bool Activate() const OVERRIDE { return false; }
-  virtual bool Close() const OVERRIDE { return false; }
-
- private:
-  scoped_refptr<DevToolsAgentHost> agent_host_;
-  std::string id_;
-  std::string title_;
-  std::string description_;
-  GURL url_;
-};
-
-WorkerTarget::WorkerTarget(const content::WorkerService::WorkerInfo& worker) {
-  agent_host_ =
-      DevToolsAgentHost::GetForWorker(worker.process_id, worker.route_id);
-  id_ = agent_host_->GetId();
-  title_ = UTF16ToUTF8(net::EscapeForHTML(worker.name));
-  description_ =
-      base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle));
-  url_ = worker.url;
-}
-
-}  // namespace
-
 BrowserListTabContentsProvider::BrowserListTabContentsProvider(
     chrome::HostDesktopType host_desktop_type)
     : host_desktop_type_(host_desktop_type) {
@@ -228,7 +86,7 @@
 }
 
 scoped_ptr<DevToolsTarget>
-BrowserListTabContentsProvider::CreateNewTarget() {
+BrowserListTabContentsProvider::CreateNewTarget(const GURL& url) {
   const BrowserList* browser_list =
       BrowserList::GetInstance(host_desktop_type_);
   WebContents* web_contents;
@@ -239,23 +97,24 @@
       return scoped_ptr<DevToolsTarget>();
     web_contents =
         browser_list->get(0)->tab_strip_model()->GetActiveWebContents();
+    web_contents->GetController().LoadURL(url,
+        content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
   } else {
     web_contents = chrome::AddSelectedTabWithURL(
       browser_list->get(0),
-      GURL(content::kAboutBlankURL),
+      url,
       content::PAGE_TRANSITION_LINK);
   }
-  return scoped_ptr<DevToolsTarget>(new Target(web_contents, true));
+  content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
+  if (!rvh)
+    return scoped_ptr<DevToolsTarget>();
+  return scoped_ptr<DevToolsTarget>(
+      DevToolsTargetImpl::CreateForRenderViewHost(rvh, true));
 }
+
 void BrowserListTabContentsProvider::EnumerateTargets(TargetCallback callback) {
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&BrowserListTabContentsProvider::GetWorkerInfo,
-                 base::Unretained(this)),
-      base::Bind(&BrowserListTabContentsProvider::RespondWithTargetList,
-                 base::Unretained(this),
-                 callback));
+  DevToolsTargetImpl::EnumerateAllTargets(
+      *reinterpret_cast<DevToolsTargetImpl::Callback*>(&callback));
 }
 
 #if defined(DEBUG_DEVTOOLS)
@@ -280,33 +139,3 @@
   return scoped_ptr<net::StreamListenSocket>();
 }
 #endif  // defined(DEBUG_DEVTOOLS)
-
-BrowserListTabContentsProvider::WorkerInfoList
-BrowserListTabContentsProvider::GetWorkerInfo() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  return content::WorkerService::GetInstance()->GetWorkers();
-}
-
-void BrowserListTabContentsProvider::RespondWithTargetList(
-    TargetCallback callback, const WorkerInfoList& worker_info_list) {
-  std::set<RenderViewHost*> tab_rvhs;
-  for (TabContentsIterator it; !it.done(); it.Next())
-    tab_rvhs.insert(it->GetRenderViewHost());
-
-  TargetList targets;
-
-  std::vector<RenderViewHost*> rvh_list =
-      content::DevToolsAgentHost::GetValidRenderViewHosts();
-  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
-       it != rvh_list.end(); ++it) {
-    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
-    WebContents* web_contents = WebContents::FromRenderViewHost(*it);
-    if (web_contents)
-      targets.push_back(new Target(web_contents, is_tab));
-  }
-
-  for (size_t i = 0; i < worker_info_list.size(); ++i)
-    targets.push_back(new WorkerTarget(worker_info_list[i]));
-
-  callback.Run(targets);
-}
diff --git a/chrome/browser/devtools/browser_list_tabcontents_provider.h b/chrome/browser/devtools/browser_list_tabcontents_provider.h
index 957d6c0..3f557dd 100644
--- a/chrome/browser/devtools/browser_list_tabcontents_provider.h
+++ b/chrome/browser/devtools/browser_list_tabcontents_provider.h
@@ -12,7 +12,6 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "content/public/browser/devtools_http_handler_delegate.h"
-#include "content/public/browser/worker_service.h"
 
 class BrowserListTabContentsProvider
     : public content::DevToolsHttpHandlerDelegate {
@@ -26,18 +25,14 @@
   virtual bool BundlesFrontendResources() OVERRIDE;
   virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
   virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE;
-  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget() OVERRIDE;
+  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
+      const GURL& url) OVERRIDE;
   virtual void EnumerateTargets(TargetCallback callback) OVERRIDE;
   virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
       net::StreamListenSocket::Delegate* delegate,
       std::string* name) OVERRIDE;
 
  private:
-  typedef std::vector<content::WorkerService::WorkerInfo> WorkerInfoList;
-  WorkerInfoList GetWorkerInfo();
-  void RespondWithTargetList(TargetCallback callback,
-                             const WorkerInfoList& worker_info_list);
-
   chrome::HostDesktopType host_desktop_type_;
   DISALLOW_COPY_AND_ASSIGN(BrowserListTabContentsProvider);
 };
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 156bcf4..549116f 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -19,12 +19,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "chrome/browser/devtools/adb/android_rsa.h"
 #include "chrome/browser/devtools/adb_client_socket.h"
 #include "chrome/browser/devtools/adb_web_socket.h"
 #include "chrome/browser/devtools/devtools_protocol.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
@@ -34,259 +36,69 @@
 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
 #include "content/public/browser/devtools_manager.h"
 #include "crypto/rsa_private_key.h"
+#include "net/base/escape.h"
 #include "net/base/net_errors.h"
 
 using content::BrowserThread;
 
 namespace {
 
-const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
-const char kHostDevicesCommand[] = "host:devices";
-const char kHostTransportCommand[] = "host:transport:%s|%s";
-const char kLocalAbstractCommand[] = "localabstract:%s";
 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
 const char kListProcessesCommand[] = "shell:ps";
 const char kDumpsysCommand[] = "shell:dumpsys window policy";
 const char kDumpsysScreenSizePrefix[] = "mStable=";
 
+const char kUnknownModel[] = "Offline";
+
 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
 const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n";
 const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n";
+const char kNewPageRequestWithURL[] = "GET /json/new?%s HTTP/1.1\r\n\r\n";
 const char kActivatePageRequest[] =
     "GET /json/activate/%s HTTP/1.1\r\n\r\n";
-const int kAdbPort = 5037;
-const int kBufferSize = 16 * 1024;
 const int kAdbPollingIntervalMs = 1000;
 
 const char kUrlParam[] = "url";
 const char kPageReloadCommand[] = "Page.reload";
 const char kPageNavigateCommand[] = "Page.navigate";
 
+const char kChromeProductName[] = "Chrome";
+const int kMinVersionNewWithURL = 32;
+const int kNewPageNavigateDelayMs = 500;
+
 #if defined(DEBUG_DEVTOOLS)
-const char kChrome[] = "Chrome";
 const char kLocalChrome[] = "Local Chrome";
 #endif  // defined(DEBUG_DEVTOOLS)
 
 typedef DevToolsAdbBridge::Callback Callback;
-typedef std::vector<scoped_refptr<DevToolsAdbBridge::AndroidDevice> >
+typedef std::vector<scoped_refptr<AndroidDevice> >
     AndroidDevices;
 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
 
-
-// AdbDeviceImpl --------------------------------------------------------------
-
-class AdbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
- public:
-  AdbDeviceImpl(const std::string& serial, bool is_connected);
-  virtual void RunCommand(const std::string& command,
-                          const CommandCallback& callback) OVERRIDE;
-  virtual void OpenSocket(const std::string& name,
-                          const SocketCallback& callback) OVERRIDE;
- private:
-  virtual ~AdbDeviceImpl() {}
-};
-
-AdbDeviceImpl::AdbDeviceImpl(const std::string& serial, bool is_connected)
-    : AndroidDevice(serial, is_connected) {
-}
-
-void AdbDeviceImpl::RunCommand(const std::string& command,
-                               const CommandCallback& callback) {
-  std::string query = base::StringPrintf(kHostTransportCommand,
-                                         serial().c_str(), command.c_str());
-  AdbClientSocket::AdbQuery(kAdbPort, query, callback);
-}
-
-void AdbDeviceImpl::OpenSocket(const std::string& name,
-                               const SocketCallback& callback) {
-  std::string socket_name =
-      base::StringPrintf(kLocalAbstractCommand, name.c_str());
-  AdbClientSocket::TransportQuery(kAdbPort, serial(), socket_name, callback);
-}
-
-// UsbDeviceImpl --------------------------------------------------------------
-
-class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
- public:
-  explicit UsbDeviceImpl(AndroidUsbDevice* device);
-  virtual void RunCommand(const std::string& command,
-                          const CommandCallback& callback) OVERRIDE;
-  virtual void OpenSocket(const std::string& name,
-                          const SocketCallback& callback) OVERRIDE;
-
- private:
-  void OnOpenSocket(const SocketCallback& callback,
-                    net::StreamSocket* socket,
-                    int result);
-  void OpenedForCommand(const CommandCallback& callback,
-                        net::StreamSocket* socket,
-                        int result);
-  void OnRead(net::StreamSocket* socket,
-              scoped_refptr<net::IOBuffer> buffer,
-              const std::string& data,
-              const CommandCallback& callback,
-              int result);
-
-  virtual ~UsbDeviceImpl() {}
-  scoped_refptr<AndroidUsbDevice> device_;
-};
-
-
-UsbDeviceImpl::UsbDeviceImpl(AndroidUsbDevice* device)
-    : AndroidDevice(device->serial(), device->is_connected()),
-      device_(device) {
-  device_->InitOnCallerThread();
-}
-
-void UsbDeviceImpl::RunCommand(const std::string& command,
-                               const CommandCallback& callback) {
-  net::StreamSocket* socket = device_->CreateSocket(command);
-  int result = socket->Connect(base::Bind(&UsbDeviceImpl::OpenedForCommand,
-                                          this, callback, socket));
-  if (result != net::ERR_IO_PENDING)
-    callback.Run(result, std::string());
-}
-
-void UsbDeviceImpl::OpenSocket(const std::string& name,
-                               const SocketCallback& callback) {
-  std::string socket_name =
-      base::StringPrintf(kLocalAbstractCommand, name.c_str());
-  net::StreamSocket* socket = device_->CreateSocket(socket_name);
-  int result = socket->Connect(base::Bind(&UsbDeviceImpl::OnOpenSocket, this,
-                                          callback, socket));
-  if (result != net::ERR_IO_PENDING)
-    callback.Run(result, NULL);
-}
-
-void UsbDeviceImpl::OnOpenSocket(const SocketCallback& callback,
-                  net::StreamSocket* socket,
-                  int result) {
-  callback.Run(result, result == net::OK ? socket : NULL);
-}
-
-void UsbDeviceImpl::OpenedForCommand(const CommandCallback& callback,
-                                     net::StreamSocket* socket,
-                                     int result) {
-  if (result != net::OK) {
-    callback.Run(result, std::string());
-    return;
-  }
-  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
-  result = socket->Read(buffer, kBufferSize,
-                        base::Bind(&UsbDeviceImpl::OnRead, this,
-                                   socket, buffer, std::string(), callback));
-  if (result != net::ERR_IO_PENDING)
-    OnRead(socket, buffer, std::string(), callback, result);
-}
-
-void UsbDeviceImpl::OnRead(net::StreamSocket* socket,
-                           scoped_refptr<net::IOBuffer> buffer,
-                           const std::string& data,
-                           const CommandCallback& callback,
-                           int result) {
-  if (result <= 0) {
-    callback.Run(result, result == 0 ? data : std::string());
-    delete socket;
-    return;
-  }
-
-  std::string new_data = data + std::string(buffer->data(), result);
-  result = socket->Read(buffer, kBufferSize,
-                        base::Bind(&UsbDeviceImpl::OnRead, this,
-                                   socket, buffer, new_data, callback));
-  if (result != net::ERR_IO_PENDING)
-    OnRead(socket, buffer, new_data, callback, result);
-}
-
-
-// AdbCountDevicesCommand -----------------------------------------------------
-
-class AdbCountDevicesCommand : public base::RefCountedThreadSafe<
-    AdbCountDevicesCommand,
-    content::BrowserThread::DeleteOnUIThread> {
- public:
-  typedef base::Callback<void(int)> Callback;
-
-  AdbCountDevicesCommand(
-      scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-      const Callback& callback);
-
- private:
-  friend struct content::BrowserThread::DeleteOnThread<
-      content::BrowserThread::UI>;
-  friend class base::DeleteHelper<AdbCountDevicesCommand>;
-
-  virtual ~AdbCountDevicesCommand();
-  void RequestAdbDeviceCount();
-  void ReceivedAdbDeviceCount(int result, const std::string& response);
-  void Respond(int count);
-
-  scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
-  Callback callback_;
-};
-
-AdbCountDevicesCommand::AdbCountDevicesCommand(
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-    const Callback& callback)
-    : adb_thread_(adb_thread),
-      callback_(callback) {
-  adb_thread_->message_loop()->PostTask(
-      FROM_HERE, base::Bind(&AdbCountDevicesCommand::RequestAdbDeviceCount,
-                            this));
-}
-
-AdbCountDevicesCommand::~AdbCountDevicesCommand() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void AdbCountDevicesCommand::RequestAdbDeviceCount() {
-  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
-  AdbClientSocket::AdbQuery(
-      kAdbPort, kHostDevicesCommand,
-      base::Bind(&AdbCountDevicesCommand::ReceivedAdbDeviceCount, this));
-}
-
-void AdbCountDevicesCommand::ReceivedAdbDeviceCount(
-    int result,
-    const std::string& response) {
-  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
-  std::vector<std::string> serials;
-  Tokenize(response, "\n", &serials);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&AdbCountDevicesCommand::Respond, this, serials.size()));
-}
-
-void AdbCountDevicesCommand::Respond(int count) {
-  callback_.Run(count);
-}
-
-
 // AdbPagesCommand ------------------------------------------------------------
 
 class AdbPagesCommand : public base::RefCountedThreadSafe<
     AdbPagesCommand,
-    content::BrowserThread::DeleteOnUIThread> {
+    BrowserThread::DeleteOnUIThread> {
  public:
   typedef base::Callback<void(DevToolsAdbBridge::RemoteDevices*)> Callback;
 
   AdbPagesCommand(
-      scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-      crypto::RSAPrivateKey* rsa_key, bool discover_usb,
+      scoped_refptr<RefCountedAdbThread> adb_thread,
+      const DevToolsAdbBridge::DeviceProviders& device_providers,
       const Callback& callback);
 
  private:
-  friend struct content::BrowserThread::DeleteOnThread<
-      content::BrowserThread::UI>;
+  friend struct BrowserThread::DeleteOnThread<
+      BrowserThread::UI>;
   friend class base::DeleteHelper<AdbPagesCommand>;
 
   virtual ~AdbPagesCommand();
-  void ReceivedUsbDevices(const AndroidUsbDevices& usb_devices);
-  void WrapUsbDevices(const AndroidUsbDevices& usb_devices);
+  void ProcessDeviceProviders();
+  void ReceivedDevices(const AndroidDevices& devices);
 
-  void ReceivedAdbDevices(int result, const std::string& response);
   void ProcessSerials();
   void ReceivedModel(int result, const std::string& response);
   void ReceivedSockets(int result, const std::string& response);
@@ -301,70 +113,58 @@
   void ParseDumpsysResponse(const std::string& response);
   void ParseScreenSize(const std::string& str);
 
-  scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
   Callback callback_;
   AndroidDevices devices_;
   DevToolsAdbBridge::RemoteBrowsers browsers_;
   scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_;
+  DevToolsAdbBridge::DeviceProviders device_providers_;
 };
 
 AdbPagesCommand::AdbPagesCommand(
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-    crypto::RSAPrivateKey* rsa_key, bool discover_usb,
+    scoped_refptr<RefCountedAdbThread> adb_thread,
+    const DevToolsAdbBridge::DeviceProviders& device_providers,
     const Callback& callback)
     : adb_thread_(adb_thread),
-      callback_(callback) {
+      callback_(callback),
+      device_providers_(device_providers){
   remote_devices_.reset(new DevToolsAdbBridge::RemoteDevices());
 
-  if (discover_usb) {
-    AndroidUsbDevice::Enumerate(rsa_key,
-        base::Bind(&AdbPagesCommand::ReceivedUsbDevices, this));
-  } else {
-    ReceivedUsbDevices(AndroidUsbDevices());
-  }
+  ProcessDeviceProviders();
 }
 
 AdbPagesCommand::~AdbPagesCommand() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
-void AdbPagesCommand::ReceivedUsbDevices(const AndroidUsbDevices& usb_devices) {
+void AdbPagesCommand::ProcessDeviceProviders() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  adb_thread_->message_loop()->PostTask(
-      FROM_HERE, base::Bind(&AdbPagesCommand::WrapUsbDevices, this,
-                            usb_devices));
-}
-
-void AdbPagesCommand::WrapUsbDevices(const AndroidUsbDevices& usb_devices) {
-  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
-
-#if defined(DEBUG_DEVTOOLS)
-  devices_.push_back(new AdbDeviceImpl("", true));  // For desktop debugging.
-#endif  // defined(DEBUG_DEVTOOLS)
-
-  for (AndroidUsbDevices::const_iterator it = usb_devices.begin();
-       it != usb_devices.end(); ++it) {
-    devices_.push_back(new UsbDeviceImpl(*it));
+  if (device_providers_.empty()) {
+    adb_thread_->message_loop()->PostTask(
+              FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
+    return;
   }
 
-  AdbClientSocket::AdbQuery(
-      kAdbPort, kHostDevicesCommand,
-      base::Bind(&AdbPagesCommand::ReceivedAdbDevices, this));
+  const scoped_refptr<AndroidDeviceProvider>& device_provider =
+      device_providers_.back();
+
+  device_provider->QueryDevices(
+      base::Bind(&AdbPagesCommand::ReceivedDevices, this));
 }
 
-void AdbPagesCommand::ReceivedAdbDevices(
-    int result,
-    const std::string& response) {
-  DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
-  std::vector<std::string> serials;
-  Tokenize(response, "\n", &serials);
-  for (size_t i = 0; i < serials.size(); ++i) {
-    std::vector<std::string> tokens;
-    Tokenize(serials[i], "\t ", &tokens);
-    bool offline = tokens.size() > 1 && tokens[1] == "offline";
-    devices_.push_back(new AdbDeviceImpl(tokens[0], !offline));
+void AdbPagesCommand::ReceivedDevices(const AndroidDevices& devices) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!device_providers_.empty());
+  device_providers_.pop_back();
+
+  devices_.insert(devices_.end(), devices.begin(), devices.end());
+
+  if (!device_providers_.empty()) {
+    ProcessDeviceProviders();
+  } else {
+    adb_thread_->message_loop()->PostTask(
+          FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
   }
-  ProcessSerials();
 }
 
 void AdbPagesCommand::ProcessSerials() {
@@ -379,7 +179,7 @@
 #if defined(DEBUG_DEVTOOLS)
   // For desktop remote debugging.
   if (devices_.back()->serial().empty()) {
-    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device =
+    scoped_refptr<AndroidDevice> device =
         devices_.back();
     device->set_model(kLocalChrome);
     remote_devices_->push_back(
@@ -387,7 +187,7 @@
     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
         new DevToolsAdbBridge::RemoteBrowser(
             adb_thread_, device, std::string());
-    remote_browser->set_product(kChrome);
+    remote_browser->set_product(kChromeProductName);
     remote_devices_->back()->AddBrowser(remote_browser);
     browsers_.push_back(remote_browser);
     device->HttpQuery(
@@ -397,11 +197,12 @@
   }
 #endif  // defined(DEBUG_DEVTOOLS)
 
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+  scoped_refptr<AndroidDevice> device = devices_.back();
   if (device->is_connected()) {
     device->RunCommand(kDeviceModelCommand,
                        base::Bind(&AdbPagesCommand::ReceivedModel, this));
   } else {
+    device->set_model(kUnknownModel);
     remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
     devices_.pop_back();
     ProcessSerials();
@@ -415,7 +216,7 @@
     ProcessSerials();
     return;
   }
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+  scoped_refptr<AndroidDevice> device = devices_.back();
   device->set_model(response);
   remote_devices_->push_back(
       new DevToolsAdbBridge::RemoteDevice(device));
@@ -433,7 +234,7 @@
   }
 
   ParseSocketsList(response);
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+  scoped_refptr<AndroidDevice> device = devices_.back();
   device->RunCommand(kDumpsysCommand,
                      base::Bind(&AdbPagesCommand::ReceivedDumpsys, this));
 }
@@ -444,7 +245,7 @@
   if (result >= 0)
     ParseDumpsysResponse(response);
 
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+  scoped_refptr<AndroidDevice> device = devices_.back();
   device->RunCommand(kListProcessesCommand,
                      base::Bind(&AdbPagesCommand::ReceivedProcesses, this));
 }
@@ -468,7 +269,7 @@
     devices_.pop_back();
     ProcessSerials();
   } else {
-    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+    scoped_refptr<AndroidDevice> device = devices_.back();
     device->HttpQuery(browsers_.back()->socket(), kVersionRequest,
                       base::Bind(&AdbPagesCommand::ReceivedVersion, this));
   }
@@ -501,7 +302,7 @@
     }
   }
 
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+  scoped_refptr<AndroidDevice> device = devices_.back();
   device->HttpQuery(browsers_.back()->socket(), kPageListRequest,
                     base::Bind(&AdbPagesCommand::ReceivedPages, this));
 }
@@ -518,20 +319,8 @@
 
   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
   base::ListValue* list_value;
-  if (!value || !value->GetAsList(&list_value)) {
-    ProcessSockets();
-    return;
-  }
-
-  base::Value* item;
-
-  for (size_t i = 0; i < list_value->GetSize(); ++i) {
-    list_value->Get(i, &item);
-    base::DictionaryValue* dict;
-    if (!item || !item->GetAsDictionary(&dict))
-      continue;
-    browser->AddPage(new DevToolsAdbBridge::RemotePage(
-        adb_thread_, browser->device(), browser->socket(), *dict));
+  if (value && value->GetAsList(&list_value)) {
+    browser->SetPageDescriptors(*list_value);
   }
   ProcessSockets();
 }
@@ -654,8 +443,8 @@
 class AdbProtocolCommand : public AdbWebSocket::Delegate {
  public:
   AdbProtocolCommand(
-      scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-      scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+      scoped_refptr<RefCountedAdbThread> adb_thread,
+      scoped_refptr<AndroidDevice> device,
       const std::string& socket_name,
       const std::string& debug_url,
       const std::string& command);
@@ -666,7 +455,7 @@
   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
 
-  scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
   const std::string command_;
   scoped_refptr<AdbWebSocket> web_socket_;
 
@@ -674,8 +463,8 @@
 };
 
 AdbProtocolCommand::AdbProtocolCommand(
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+    scoped_refptr<RefCountedAdbThread> adb_thread,
+    scoped_refptr<AndroidDevice> device,
     const std::string& socket_name,
     const std::string& debug_url,
     const std::string& command)
@@ -711,8 +500,8 @@
 base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
     LAZY_INSTANCE_INITIALIZER;
 
-DevToolsAdbBridge::Wrapper::Wrapper(Profile* profile)
-    : bridge_(new DevToolsAdbBridge(profile)) {
+DevToolsAdbBridge::Wrapper::Wrapper() {
+  bridge_ = new DevToolsAdbBridge();
 }
 
 DevToolsAdbBridge::Wrapper::~Wrapper() {
@@ -746,59 +535,7 @@
 BrowserContextKeyedService*
 DevToolsAdbBridge::Factory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new DevToolsAdbBridge::Wrapper(Profile::FromBrowserContext(context));
-}
-
-
-// DevToolsAdbBridge::AndroidDevice -------------------------------------------
-
-DevToolsAdbBridge::AndroidDevice::AndroidDevice(const std::string& serial,
-                                                bool is_connected)
-    : serial_(serial),
-      is_connected_(is_connected) {
-}
-
-void DevToolsAdbBridge::AndroidDevice::HttpQuery(
-    const std::string& la_name,
-    const std::string& request,
-    const CommandCallback& callback) {
-  OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened, this,
-                                 request, callback));
-}
-
-void DevToolsAdbBridge::AndroidDevice::HttpUpgrade(
-    const std::string& la_name,
-    const std::string& request,
-    const SocketCallback& callback) {
-  OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened2, this,
-                                 request, callback));
-}
-
-DevToolsAdbBridge::AndroidDevice::~AndroidDevice() {
-}
-
-void DevToolsAdbBridge::AndroidDevice::OnHttpSocketOpened(
-    const std::string& request,
-    const CommandCallback& callback,
-    int result,
-    net::StreamSocket* socket) {
-  if (result != net::OK) {
-    callback.Run(result, std::string());
-    return;
-  }
-  AdbClientSocket::HttpQuery(socket, request, callback);
-}
-
-void DevToolsAdbBridge::AndroidDevice::OnHttpSocketOpened2(
-    const std::string& request,
-    const SocketCallback& callback,
-    int result,
-    net::StreamSocket* socket) {
-  if (result != net::OK) {
-    callback.Run(result, NULL);
-    return;
-  }
-  AdbClientSocket::HttpQuery(socket, request, callback);
+  return new DevToolsAdbBridge::Wrapper();
 }
 
 
@@ -807,16 +544,33 @@
 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate,
                           public AdbWebSocket::Delegate {
  public:
+   static void Create(const std::string& id,
+                      scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
+                      const std::string& debug_url,
+                      const std::string& frontend_url,
+                      Profile* profile) {
+    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+    AgentHostDelegates::iterator it =
+        g_host_delegates.Get().find(id);
+    if (it != g_host_delegates.Get().end()) {
+      it->second->OpenFrontend();
+    } else if (!frontend_url.empty()) {
+      new AgentHostDelegate(
+          id, browser->device(), browser->socket(), debug_url,
+          frontend_url, browser->adb_thread()->message_loop(), profile);
+    }
+  }
+
+ private:
   AgentHostDelegate(
       const std::string& id,
-      scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+      scoped_refptr<AndroidDevice> device,
       const std::string& socket_name,
       const std::string& debug_url,
       const std::string& frontend_url,
       base::MessageLoop* adb_message_loop,
       Profile* profile)
       : id_(id),
-        serial_(device->serial()),
         frontend_url_(frontend_url),
         adb_message_loop_(adb_message_loop),
         profile_(profile) {
@@ -832,7 +586,6 @@
         profile_, frontend_url_, proxy_->GetAgentHost().get());
   }
 
- private:
   virtual ~AgentHostDelegate() {
     g_host_delegates.Get().erase(id_);
   }
@@ -867,7 +620,6 @@
   }
 
   const std::string id_;
-  const std::string serial_;
   const std::string frontend_url_;
   base::MessageLoop* adb_message_loop_;
   Profile* profile_;
@@ -877,22 +629,48 @@
   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
 };
 
+//// RemotePageTarget ----------------------------------------------
 
-// DevToolsAdbBridge::RemotePage ----------------------------------------------
+class RemotePageTarget : public DevToolsTargetImpl {
+ public:
+  RemotePageTarget(scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
+                   const base::DictionaryValue& value);
+  virtual ~RemotePageTarget();
 
-DevToolsAdbBridge::RemotePage::RemotePage(
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-    scoped_refptr<AndroidDevice> device,
-    const std::string& socket,
+  // content::DevToolsTarget overrides:
+  virtual bool IsAttached() const OVERRIDE;
+  virtual bool Activate() const OVERRIDE;
+  virtual bool Close() const OVERRIDE;
+
+  // DevToolsTargetImpl overrides:
+  virtual void Inspect(Profile* profile) const OVERRIDE;
+  virtual void Reload() const OVERRIDE;
+
+  void Navigate(const std::string& url) const;
+
+ private:
+  scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser_;
+  std::string debug_url_;
+  std::string frontend_url_;
+  std::string agent_id_;
+  DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
+};
+
+RemotePageTarget::RemotePageTarget(
+    scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
     const base::DictionaryValue& value)
-    : adb_thread_(adb_thread),
-      device_(device),
-      socket_(socket) {
+    : browser_(browser) {
+  type_ = "adb_page";
   value.GetString("id", &id_);
-  value.GetString("url", &url_);
+  std::string url;
+  value.GetString("url", &url);
+  url_ = GURL(url);
   value.GetString("title", &title_);
+  title_ = UTF16ToUTF8(net::UnescapeForHTML(UTF8ToUTF16(title_)));
   value.GetString("description", &description_);
-  value.GetString("faviconUrl", &favicon_url_);
+  std::string favicon_url;
+  value.GetString("faviconUrl", &favicon_url);
+  favicon_url_ = GURL(favicon_url);
   value.GetString("webSocketDebuggerUrl", &debug_url_);
   value.GetString("devtoolsFrontendUrl", &frontend_url_);
 
@@ -916,108 +694,155 @@
     frontend_url_ = "https:" + frontend_url_.substr(5);
 
   agent_id_ = base::StringPrintf("%s:%s:%s",
-      device_->serial().c_str(), socket_.c_str(), id_.c_str());
+      browser_->device()->serial().c_str(),
+      browser_->socket().c_str(),
+      id_.c_str());
 }
 
-bool DevToolsAdbBridge::RemotePage::HasDevToolsWindow() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  return g_host_delegates.Get().find(agent_id_) != g_host_delegates.Get().end();
+RemotePageTarget::~RemotePageTarget() {
 }
 
-void DevToolsAdbBridge::RemotePage::Inspect(Profile* profile) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  RequestActivate(
-      base::Bind(&RemotePage::InspectOnHandlerThread, this, profile));
+bool RemotePageTarget::IsAttached() const {
+  return debug_url_.empty();
 }
 
-static void Noop(int, const std::string&) {}
-
-void DevToolsAdbBridge::RemotePage::Activate() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  RequestActivate(base::Bind(&Noop));
-}
-
-void DevToolsAdbBridge::RemotePage::Close() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (attached())
-    return;
-  std::string request = base::StringPrintf(kClosePageRequest, id_.c_str());
-  adb_thread_->message_loop()->PostTask(FROM_HERE,
-      base::Bind(&AndroidDevice::HttpQuery,
-          device_, socket_, request, base::Bind(&Noop)));
-}
-
-void DevToolsAdbBridge::RemotePage::Reload() {
-  SendProtocolCommand(kPageReloadCommand, NULL);
-}
-
-void DevToolsAdbBridge::RemotePage::SendProtocolCommand(
-    const std::string& method,
-    base::DictionaryValue* params) {
-  if (attached())
-    return;
-  DevToolsProtocol::Command command(1, method, params);
-  new AdbProtocolCommand(
-      adb_thread_, device_, socket_, debug_url_, command.Serialize());
-}
-
-DevToolsAdbBridge::RemotePage::~RemotePage() {
-}
-
-void DevToolsAdbBridge::RemotePage::RequestActivate(
-    const CommandCallback& callback) {
+void RemotePageTarget::Inspect(Profile* profile) const {
   std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
-  adb_thread_->message_loop()->PostTask(FROM_HERE,
-      base::Bind(&AndroidDevice::HttpQuery,
-          device_, socket_, request, callback));
+  base::Closure inspect_callback = base::Bind(&AgentHostDelegate::Create,
+      id_, browser_, debug_url_, frontend_url_, profile);
+  browser_->SendJsonRequest(request, inspect_callback);
 }
 
-void DevToolsAdbBridge::RemotePage::InspectOnHandlerThread(
-    Profile* profile, int result, const std::string& response) {
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&RemotePage::InspectOnUIThread, this, profile));
+bool RemotePageTarget::Activate() const {
+  std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
+  browser_->SendJsonRequest(request, base::Closure());
+  return true;
 }
 
-void DevToolsAdbBridge::RemotePage::InspectOnUIThread(Profile* profile) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  AgentHostDelegates::iterator it =
-      g_host_delegates.Get().find(agent_id_);
-  if (it != g_host_delegates.Get().end()) {
-    it->second->OpenFrontend();
-  } else if (!attached()) {
-    new AgentHostDelegate(
-        agent_id_, device_, socket_, debug_url_,
-        frontend_url_, adb_thread_->message_loop(), profile);
-  }
+bool RemotePageTarget::Close() const {
+  if (IsAttached())
+    return false;
+  std::string request = base::StringPrintf(kClosePageRequest, id_.c_str());
+  browser_->SendJsonRequest(request, base::Closure());
+  return true;
 }
 
+void RemotePageTarget::Reload() const {
+  browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL);
+}
+
+void RemotePageTarget::Navigate(const std::string& url) const {
+  base::DictionaryValue params;
+  params.SetString(kUrlParam, url);
+  browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, &params);
+}
 
 // DevToolsAdbBridge::RemoteBrowser -------------------------------------------
 
 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser(
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
+    scoped_refptr<RefCountedAdbThread> adb_thread,
     scoped_refptr<AndroidDevice> device,
     const std::string& socket)
     : adb_thread_(adb_thread),
       device_(device),
-      socket_(socket) {
+      socket_(socket),
+      page_descriptors_(new base::ListValue()) {
 }
 
-void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) {
+bool DevToolsAdbBridge::RemoteBrowser::IsChrome() const {
+  return product_.find(kChromeProductName) == 0;
+}
+
+DevToolsAdbBridge::RemoteBrowser::ParsedVersion
+DevToolsAdbBridge::RemoteBrowser::GetParsedVersion() const {
+  ParsedVersion result;
+  std::vector<std::string> parts;
+  Tokenize(version_, ".", &parts);
+  for (size_t i = 0; i != parts.size(); ++i) {
+    int value = 0;
+    base::StringToInt(parts[i], &value);
+    result.push_back(value);
+  }
+  return result;
+}
+
+std::vector<DevToolsTargetImpl*>
+DevToolsAdbBridge::RemoteBrowser::CreatePageTargets() {
+  std::vector<DevToolsTargetImpl*> result;
+  for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) {
+    base::Value* item;
+    page_descriptors_->Get(i, &item);
+    if (!item)
+      continue;
+    base::DictionaryValue* dict;
+    if (!item->GetAsDictionary(&dict))
+      continue;
+    result.push_back(new RemotePageTarget(this, *dict));
+  }
+  return result;
+}
+
+void DevToolsAdbBridge::RemoteBrowser::SetPageDescriptors(
+    const base::ListValue& list) {
+  page_descriptors_.reset(list.DeepCopy());
+}
+
+static void RespondOnUIThread(base::Closure callback, int, const std::string&) {
+  if (!callback.is_null())
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+}
+
+void DevToolsAdbBridge::RemoteBrowser::SendJsonRequest(
+    const std::string& request, base::Closure callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   adb_thread_->message_loop()->PostTask(FROM_HERE,
-      base::Bind(&AndroidDevice::HttpQuery,
-          device_, socket_, kNewPageRequest,
-          base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url)));
+      base::Bind(&AndroidDevice::HttpQuery, device_, socket_, request,
+          base::Bind(&RespondOnUIThread, callback)));
+}
+
+void DevToolsAdbBridge::RemoteBrowser::SendProtocolCommand(
+    const std::string& debug_url,
+    const std::string& method,
+    base::DictionaryValue* params) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (debug_url.empty())
+    return;
+  DevToolsProtocol::Command command(1, method, params);
+  new AdbProtocolCommand(
+      adb_thread_, device_, socket_, debug_url, command.Serialize());
+}
+
+static void NoOp(int, const std::string&) {}
+
+void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) {
+  ParsedVersion parsed_version = GetParsedVersion();
+  if (IsChrome() &&
+      !parsed_version.empty() &&
+      parsed_version[0] >= kMinVersionNewWithURL) {
+    std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
+    std::string request =
+        base::StringPrintf(kNewPageRequestWithURL, query.c_str());
+    adb_thread_->message_loop()->PostTask(FROM_HERE,
+        base::Bind(&AndroidDevice::HttpQuery,
+            device_, socket_, request, base::Bind(&NoOp)));
+  } else {
+    adb_thread_->message_loop()->PostTask(FROM_HERE,
+        base::Bind(&AndroidDevice::HttpQuery,
+            device_, socket_, kNewPageRequest,
+            base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url)));
+  }
 }
 
 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread(
     const std::string& url, int result, const std::string& response) {
   if (result < 0)
     return;
-  BrowserThread::PostTask(
+  // Navigating too soon after the page creation breaks navigation history
+  // (crbug.com/311014). This can be avoided by adding a moderate delay.
+  BrowserThread::PostDelayedTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url));
+      base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url),
+      base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs));
 }
 
 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread(
@@ -1025,11 +850,8 @@
   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
   base::DictionaryValue* dict;
   if (value && value->GetAsDictionary(&dict)) {
-    scoped_refptr<RemotePage> new_page =
-        new RemotePage(adb_thread_, device_, socket_, *dict);
-    base::DictionaryValue params;
-    params.SetString(kUrlParam, url);
-    new_page->SendProtocolCommand(kPageNavigateCommand, &params);
+    RemotePageTarget new_page(this, *dict);
+    new_page.Navigate(url);
   }
 }
 
@@ -1065,59 +887,11 @@
 }
 
 
-// DevToolsAdbBridge::RefCountedAdbThread -------------------------------------
-
-DevToolsAdbBridge::RefCountedAdbThread*
-DevToolsAdbBridge::RefCountedAdbThread::instance_ = NULL;
-
-// static
-scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread>
-DevToolsAdbBridge::RefCountedAdbThread::GetInstance() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (!instance_)
-    new RefCountedAdbThread();
-  return instance_;
-}
-
-DevToolsAdbBridge::RefCountedAdbThread::RefCountedAdbThread() {
-  instance_ = this;
-  thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  if (!thread_->StartWithOptions(options)) {
-    delete thread_;
-    thread_ = NULL;
-  }
-}
-
-base::MessageLoop* DevToolsAdbBridge::RefCountedAdbThread::message_loop() {
-  return thread_ ? thread_->message_loop() : NULL;
-}
-
-// static
-void DevToolsAdbBridge::RefCountedAdbThread::StopThread(base::Thread* thread) {
-  thread->Stop();
-}
-
-DevToolsAdbBridge::RefCountedAdbThread::~RefCountedAdbThread() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  instance_ = NULL;
-  if (!thread_)
-    return;
-  // Shut down thread on FILE thread to join into IO.
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&RefCountedAdbThread::StopThread, thread_));
-}
-
-
 // DevToolsAdbBridge ----------------------------------------------------------
 
-DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
+DevToolsAdbBridge::DevToolsAdbBridge()
     : adb_thread_(RefCountedAdbThread::GetInstance()),
-      has_message_loop_(adb_thread_->message_loop() != NULL),
-      discover_usb_devices_(false) {
-  rsa_key_.reset(AndroidRSAPrivateKey(profile));
+      has_message_loop_(adb_thread_->message_loop() != NULL) {
 }
 
 void DevToolsAdbBridge::AddListener(Listener* listener) {
@@ -1135,14 +909,9 @@
   listeners_.erase(it);
 }
 
-void DevToolsAdbBridge::CountDevices(
-    const base::Callback<void(int)>& callback) {
-  if (discover_usb_devices_) {
-    // Count raw devices, adb included.
-    AndroidUsbDevice::CountDevices(callback);
-    return;
-  }
-  new AdbCountDevicesCommand(adb_thread_, callback);
+bool DevToolsAdbBridge::HasDevToolsWindow(const std::string& agent_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end();
 }
 
 DevToolsAdbBridge::~DevToolsAdbBridge() {
@@ -1154,8 +923,9 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!has_message_loop_)
     return;
+
   new AdbPagesCommand(
-      adb_thread_, rsa_key_.get(), discover_usb_devices_,
+      adb_thread_, device_providers_,
       base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this));
 }
 
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index ccc3404..9343d53 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -11,7 +11,8 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/devtools/adb/android_usb_device.h"
+#include "chrome/browser/devtools/android_device.h"
+#include "chrome/browser/devtools/refcounted_adb_thread.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 #include "content/public/browser/browser_thread.h"
@@ -23,6 +24,7 @@
 namespace base {
 class MessageLoop;
 class DictionaryValue;
+class ListValue;
 class Thread;
 }
 
@@ -34,14 +36,12 @@
 class RSAPrivateKey;
 }
 
+class DevToolsTargetImpl;
 class Profile;
 
 // The format used for constructing DevTools server socket names.
 extern const char kDevToolsChannelNameFormat[];
 
-typedef base::Callback<void(int, const std::string&)> CommandCallback;
-typedef base::Callback<void(int result, net::StreamSocket*)> SocketCallback;
-
 class DevToolsAdbBridge
     : public base::RefCountedThreadSafe<
           DevToolsAdbBridge,
@@ -49,10 +49,12 @@
  public:
   typedef base::Callback<void(int result,
                               const std::string& response)> Callback;
+  typedef std::vector<scoped_refptr<AndroidDeviceProvider> > DeviceProviders;
+
 
   class Wrapper : public BrowserContextKeyedService {
    public:
-    explicit Wrapper(Profile* profile);
+    Wrapper();
     virtual ~Wrapper();
 
     DevToolsAdbBridge* Get();
@@ -80,67 +82,15 @@
     DISALLOW_COPY_AND_ASSIGN(Factory);
   };
 
-  class AndroidDevice;
-  class RefCountedAdbThread;
-
-  class RemotePage : public base::RefCounted<RemotePage> {
-   public:
-    RemotePage(scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
-               scoped_refptr<AndroidDevice> device,
-               const std::string& socket,
-               const base::DictionaryValue& value);
-
-    std::string id() { return id_; }
-    std::string url() { return url_; }
-    std::string title() { return title_; }
-    std::string description() { return description_; }
-    std::string favicon_url() { return favicon_url_; }
-    bool attached() { return debug_url_.empty(); }
-
-    bool HasDevToolsWindow();
-
-    void Inspect(Profile* profile);
-    void Activate();
-    void Close();
-    void Reload();
-
-    void SendProtocolCommand(const std::string& method,
-                             base::DictionaryValue* params);
-
-   private:
-    friend class base::RefCounted<RemotePage>;
-    virtual ~RemotePage();
-
-    void RequestActivate(const CommandCallback& callback);
-
-    void InspectOnHandlerThread(
-        Profile* profile, int result, const std::string& response);
-
-    void InspectOnUIThread(Profile* profile);
-
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
-    scoped_refptr<AndroidDevice> device_;
-    std::string socket_;
-    std::string id_;
-    std::string url_;
-    std::string title_;
-    std::string description_;
-    std::string favicon_url_;
-    std::string debug_url_;
-    std::string frontend_url_;
-    std::string agent_id_;
-    DISALLOW_COPY_AND_ASSIGN(RemotePage);
-  };
-
-  typedef std::vector<scoped_refptr<RemotePage> > RemotePages;
-
   class RemoteBrowser : public base::RefCounted<RemoteBrowser> {
    public:
     RemoteBrowser(
-        scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
+        scoped_refptr<RefCountedAdbThread> adb_thread,
         scoped_refptr<AndroidDevice> device,
         const std::string& socket);
 
+    scoped_refptr<RefCountedAdbThread> adb_thread() { return adb_thread_; }
+
     scoped_refptr<AndroidDevice> device() { return device_; }
     std::string socket() { return socket_; }
 
@@ -153,8 +103,18 @@
     std::string package() { return package_; }
     void set_package(const std::string& package) { package_ = package; }
 
-    RemotePages& pages() { return pages_; }
-    void AddPage(scoped_refptr<RemotePage> page) { pages_.push_back(page); }
+    bool IsChrome() const;
+
+    typedef std::vector<int> ParsedVersion;
+    ParsedVersion GetParsedVersion() const;
+
+    std::vector<DevToolsTargetImpl*> CreatePageTargets();
+    void SetPageDescriptors(const base::ListValue&);
+
+    void SendJsonRequest(const std::string& request, base::Closure callback);
+    void SendProtocolCommand(const std::string& debug_url,
+                             const std::string& method,
+                             base::DictionaryValue* params);
 
     void Open(const std::string& url);
 
@@ -168,14 +128,14 @@
     void PageCreatedOnUIThread(
         const std::string& response, const std::string& url);
 
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
+    scoped_refptr<RefCountedAdbThread> adb_thread_;
     scoped_refptr<AndroidDevice> device_;
     const std::string socket_;
     std::string product_;
     std::string version_;
     std::string pid_;
     std::string package_;
-    RemotePages pages_;
+    scoped_ptr<base::ListValue> page_descriptors_;
 
     DISALLOW_COPY_AND_ASSIGN(RemoteBrowser);
   };
@@ -209,48 +169,6 @@
 
   typedef std::vector<scoped_refptr<RemoteDevice> > RemoteDevices;
 
-  class AndroidDevice : public base::RefCounted<AndroidDevice> {
-   public:
-    AndroidDevice(const std::string& serial, bool is_connected);
-
-    virtual void RunCommand(const std::string& command,
-                            const CommandCallback& callback) = 0;
-    virtual void OpenSocket(const std::string& socket_name,
-                            const SocketCallback& callback) = 0;
-    void HttpQuery(const std::string& la_name,
-                   const std::string& request,
-                   const CommandCallback& callback);
-    void HttpUpgrade(const std::string& la_name,
-                     const std::string& request,
-                     const SocketCallback& callback);
-
-    std::string serial() { return serial_; }
-    bool is_connected() { return is_connected_; }
-
-    std::string model() { return model_; }
-    void set_model(const std::string& model) { model_ = model; }
-
-   protected:
-    friend class base::RefCounted<AndroidDevice>;
-    virtual ~AndroidDevice();
-
-   private:
-    void OnHttpSocketOpened(const std::string& request,
-                            const CommandCallback& callback,
-                            int result,
-                            net::StreamSocket* socket);
-    void OnHttpSocketOpened2(const std::string& request,
-                             const SocketCallback& callback,
-                             int result,
-                             net::StreamSocket* socket);
-
-    std::string serial_;
-    bool is_connected_;
-    std::string model_;
-
-    DISALLOW_COPY_AND_ASSIGN(AndroidDevice);
-  };
-
   typedef std::vector<scoped_refptr<AndroidDevice> > AndroidDevices;
   typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
 
@@ -261,28 +179,14 @@
     virtual ~Listener() {}
   };
 
-  class RefCountedAdbThread : public base::RefCounted<RefCountedAdbThread> {
-   public:
-    static scoped_refptr<RefCountedAdbThread> GetInstance();
-    base::MessageLoop* message_loop();
-
-   private:
-    friend class base::RefCounted<RefCountedAdbThread>;
-    static DevToolsAdbBridge::RefCountedAdbThread* instance_;
-    static void StopThread(base::Thread* thread);
-
-    RefCountedAdbThread();
-    virtual ~RefCountedAdbThread();
-    base::Thread* thread_;
-  };
-
-  explicit DevToolsAdbBridge(Profile* profile);
+  DevToolsAdbBridge();
   void AddListener(Listener* listener);
   void RemoveListener(Listener* listener);
-  void CountDevices(const base::Callback<void(int)>& callback);
-  void set_discover_usb_devices(bool enabled) {
-    discover_usb_devices_ = enabled;
+
+  void set_device_providers(DeviceProviders device_providers) {
+    device_providers_ = device_providers;
   }
+  static bool HasDevToolsWindow(const std::string& agent_id);
 
  private:
   friend struct content::BrowserThread::DeleteOnThread<
@@ -294,13 +198,11 @@
   void RequestRemoteDevices();
   void ReceivedRemoteDevices(RemoteDevices* devices);
 
-  Profile* profile_;
   scoped_refptr<RefCountedAdbThread> adb_thread_;
   bool has_message_loop_;
-  scoped_ptr<crypto::RSAPrivateKey> rsa_key_;
   typedef std::vector<Listener*> Listeners;
   Listeners listeners_;
-  bool discover_usb_devices_;
+  DeviceProviders device_providers_;
   DISALLOW_COPY_AND_ASSIGN(DevToolsAdbBridge);
 };
 
diff --git a/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc b/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc
new file mode 100644
index 0000000..e12ef50
--- /dev/null
+++ b/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc
@@ -0,0 +1,299 @@
+// Copyright 2013 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/devtools/android_device.h"
+#include "chrome/browser/devtools/devtools_adb_bridge.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/test_utils.h"
+
+const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
+const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
+const char kListProcessesCommand[] = "shell:ps";
+const char kDumpsysCommand[] = "shell:dumpsys window policy";
+
+const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
+const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
+
+const char kSampleOpenedUnixSockets[] =
+    "Num       RefCount Protocol Flags    Type St Inode Path\n"
+    "00000000: 00000004 00000000"
+    " 00000000 0002 01  3328 /dev/socket/wpa_wlan0\n"
+    "00000000: 00000002 00000000"
+    " 00010000 0001 01  5394 /dev/socket/vold\n"
+    "00000000: 00000002 00000000"
+    " 00010000 0001 01 11810 @webview_devtools_remote_2425\n"
+    "00000000: 00000002 00000000"
+    " 00010000 0001 01 20893 @chrome_devtools_remote\n";
+
+const char kSampleListProcesses[] =
+    "USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME\n"
+    "root      1     0     688    508   ffffffff 00000000 S /init\n"
+    "u0_a75    2425  123   933736 193024 ffffffff 00000000 S com.sample.feed\n"
+    "nfc       741   123   706448 26316 ffffffff 00000000 S com.android.nfc";
+
+const char kSampleDumpsysCommand[] =
+    "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
+    "    mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
+    "    mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
+    "    mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
+
+char kSampleChromeVersion[] = "{\n"
+    "   \"Browser\": \"Chrome/32.0.1679.0\",\n"
+    "   \"Protocol-Version\": \"1.0\",\n"
+    "   \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
+    "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
+    "   \"WebKit-Version\": \"537.36 (@160162)\"\n"
+    "}";
+
+char kSampleWebViewVersion[] = "{\n"
+    "   \"Browser\": \"Version/4.0\",\n"
+    "   \"Protocol-Version\": \"1.0\",\n"
+    "   \"User-Agent\": \"Mozilla/5.0 (Linux; Android 4.3; Build/KRS74B) "
+    "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Safari/537.36\",\n"
+    "   \"WebKit-Version\": \"537.36 (@157588)\"\n"
+    "}";
+
+char kSampleChromePages[] = "[ {\n"
+    "   \"description\": \"\",\n"
+    "   \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
+    "ws=/devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n"
+    "   \"id\": \"755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n"
+    "   \"title\": \"The Chromium Projects\",\n"
+    "   \"type\": \"page\",\n"
+    "   \"url\": \"http://www.chromium.org/\",\n"
+    "   \"webSocketDebuggerUrl\": \""
+    "ws:///devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\"\n"
+    "} ]";
+
+char kSampleWebViewPages[] = "[ {\n"
+    "   \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false,"
+    "\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0,"
+    "\\\"visible\\\":true,\\\"width\\\":800}\",\n"
+    "   \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
+    "serve_rev/@157588/devtools.html?ws="
+    "/devtools/page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
+    "   \"faviconUrl\": \"http://chromium.org/favicon.ico\",\n"
+    "   \"id\": \"3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
+    "   \"thumbnailUrl\": \"/thumb/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
+    "   \"title\": \"Blink - The Chromium Projects\",\n"
+    "   \"type\": \"page\",\n"
+    "   \"url\": \"http://www.chromium.org/blink\",\n"
+    "   \"webSocketDebuggerUrl\": \"ws:///devtools/"
+    "page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\"\n"
+    "}, {\n"
+    "   \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":true,"
+    "\\\"screenX\\\":0,\\\"screenY\\\":33,\\\"visible\\\":false}\",\n"
+    "   \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
+    "serve_rev/@157588/devtools.html?ws="
+    "/devtools/page/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
+    "   \"faviconUrl\": \"\",\n"
+    "   \"id\": \"44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
+    "   \"thumbnailUrl\": \"/thumb/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
+    "   \"title\": \"More Activity\",\n"
+    "   \"type\": \"page\",\n"
+    "   \"url\": \"about:blank\",\n"
+    "   \"webSocketDebuggerUrl\": \"ws:///devtools/page/"
+    "44681551-ADFD-2411-076B-3AB14C1C60E2\"\n"
+    "}]";
+
+class MockDeviceImpl : public AndroidDevice {
+ public:
+  MockDeviceImpl(const std::string& serial, int index,
+                 bool connected, const char* device_model)
+      : AndroidDevice(serial, connected),
+        device_model_(device_model)
+  {}
+
+  virtual void RunCommand(const std::string& command,
+                            const CommandCallback& callback) OVERRIDE {
+    const char* response;
+
+    if (command == kDeviceModelCommand) {
+      response = device_model_;
+    } else if (command == kOpenedUnixSocketsCommand) {
+      response = kSampleOpenedUnixSockets;
+    } else if (command == kListProcessesCommand) {
+      response = kSampleListProcesses;
+    } else if (command == kDumpsysCommand) {
+      response = kSampleDumpsysCommand;
+    } else {
+      NOTREACHED();
+      return;
+    }
+
+    base::MessageLoop::current()->PostTask( FROM_HERE,
+              base::Bind(&MockDeviceImpl::RunCommandCallback,
+                         this, callback, 0, response));
+  }
+
+  void RunCommandCallback(const CommandCallback& callback, int result,
+                          const std::string& response) {
+    callback.Run(result, response);
+  }
+
+  virtual void OpenSocket(const std::string& name,
+                          const SocketCallback& callback) OVERRIDE {
+    NOTREACHED();
+  }
+
+  virtual void HttpQuery(const std::string& la_name,
+                     const std::string& request,
+                     const CommandCallback& callback) OVERRIDE {
+    const char* response;
+
+    if (la_name == "chrome_devtools_remote") {
+      if (request == kVersionRequest) {
+        response = kSampleChromeVersion;
+      } else if (request == kPageListRequest) {
+        response = kSampleChromePages;
+      } else {
+        NOTREACHED();
+        return;
+      }
+    } else if (la_name == "webview_devtools_remote_2425") {
+      if (request == kVersionRequest) {
+        response = kSampleWebViewVersion;
+      } else if (request == kPageListRequest) {
+        response = kSampleWebViewPages;
+      } else {
+        NOTREACHED();
+        return;
+      }
+    } else {
+      NOTREACHED();
+      return;
+    }
+
+    base::MessageLoop::current()->PostTask( FROM_HERE,
+              base::Bind(&MockDeviceImpl::RunCommandCallback,
+                         this, callback, 0, response));
+  }
+
+  virtual void HttpUpgrade(const std::string& la_name,
+                       const std::string& request,
+                       const SocketCallback& callback) {
+    NOTREACHED();
+  }
+
+  virtual void HttpQueryCallback(const CommandCallback& next, int code,
+                                 const std::string& result) {
+    NOTREACHED();
+  }
+
+ private:
+  virtual ~MockDeviceImpl()
+  {}
+
+  const char* device_model_;
+};
+
+class MockDeviceProvider : public AndroidDeviceProvider {
+  virtual ~MockDeviceProvider()
+  {}
+
+  virtual void QueryDevices(const QueryDevicesCallback& callback) OVERRIDE {
+    AndroidDeviceProvider::AndroidDevices devices;
+    devices.push_back(new MockDeviceImpl("FirstDevice", 0, true, "Nexus 6"));
+    devices.push_back(new MockDeviceImpl("SecondDevice", 1, false, "Nexus 8"));
+    callback.Run(devices);
+  }
+};
+
+
+class DevToolsAdbBridgeTest : public InProcessBrowserTest,
+                               public DevToolsAdbBridge::Listener {
+  typedef DevToolsAdbBridge::RemoteDevices::const_iterator rdci;
+  typedef DevToolsAdbBridge::RemoteBrowsers::const_iterator rbci;
+public:
+  virtual void RemoteDevicesChanged(
+      DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE{
+    ASSERT_EQ(2U, devices->size());
+
+    scoped_refptr<DevToolsAdbBridge::RemoteDevice> connected =
+        (*devices)[0]->IsConnected() ? (*devices)[0] : (*devices)[1];
+
+    scoped_refptr<DevToolsAdbBridge::RemoteDevice> not_connected =
+        (*devices)[0]->IsConnected() ? (*devices)[1] : (*devices)[0];
+
+    ASSERT_TRUE(connected->IsConnected());
+    ASSERT_FALSE(not_connected->IsConnected());
+
+    ASSERT_EQ(720, connected->screen_size().width());
+    ASSERT_EQ(1184, connected->screen_size().height());
+
+    ASSERT_EQ("FirstDevice", connected->GetSerial());
+    ASSERT_EQ("Nexus 6", connected->GetModel());
+
+    ASSERT_EQ("SecondDevice", not_connected->GetSerial());
+    ASSERT_EQ("Offline", not_connected->GetModel());
+
+    const DevToolsAdbBridge::RemoteBrowsers& browsers = connected->browsers();
+    ASSERT_EQ(2U, browsers.size());
+
+    scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chrome =
+        browsers[0]->product() == "Chrome" ? browsers[0] : browsers[1];
+
+    scoped_refptr<DevToolsAdbBridge::RemoteBrowser> webview =
+            browsers[0]->product() == "Chrome" ? browsers[1] : browsers[0];
+
+    ASSERT_EQ("Chrome", chrome->product());
+    ASSERT_EQ("32.0.1679.0", chrome->version());
+
+    ASSERT_EQ("Webview", webview->product());
+    ASSERT_EQ("4.0", webview->version());
+
+    // Check that we parse process list properly.
+    ASSERT_EQ("com.sample.feed", webview->package());
+
+    std::vector<DevToolsTargetImpl*> chrome_pages =
+        chrome->CreatePageTargets();
+    std::vector<DevToolsTargetImpl*> webview_pages =
+        webview->CreatePageTargets();
+
+    ASSERT_EQ(1U, chrome_pages.size());
+    ASSERT_EQ(2U, webview_pages.size());
+
+    // Check that we have non-empty description for webview pages.
+    ASSERT_EQ(0U, chrome_pages[0]->GetDescription().size());
+    ASSERT_NE(0U, webview_pages[0]->GetDescription().size());
+    ASSERT_NE(0U, webview_pages[1]->GetDescription().size());
+
+    ASSERT_EQ(GURL("http://www.chromium.org/"), chrome_pages[0]->GetUrl());
+    ASSERT_EQ("The Chromium Projects", chrome_pages[0]->GetTitle());
+
+    STLDeleteElements(&chrome_pages);
+    STLDeleteElements(&webview_pages);
+
+    runner_->Quit();
+  }
+
+  void init() {
+    runner_ = new content::MessageLoopRunner;
+  }
+
+protected:
+  scoped_refptr<content::MessageLoopRunner> runner_;
+};
+
+IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, Main) {
+  init();
+
+  scoped_refptr<DevToolsAdbBridge> adb_bridge =
+      DevToolsAdbBridge::Factory::GetForProfile(browser()->profile());
+
+  DevToolsAdbBridge::DeviceProviders providers;
+  providers.push_back(new MockDeviceProvider());
+
+  adb_bridge->set_device_providers(providers);
+
+  if (!adb_bridge) {
+    FAIL() << "Failed to get DevToolsAdbBridge.";
+  }
+
+  adb_bridge->AddListener(this);
+
+  runner_->Run();
+}
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index d8372a4..c1541c4 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -13,12 +13,12 @@
 #include "base/lazy_instance.h"
 #include "base/md5.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/value_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/platform_util.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/devtools/devtools_target_impl.cc b/chrome/browser/devtools/devtools_target_impl.cc
new file mode 100644
index 0000000..3974f76
--- /dev/null
+++ b/chrome/browser/devtools/devtools_target_impl.cc
@@ -0,0 +1,355 @@
+// Copyright 2013 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/devtools/devtools_target_impl.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
+#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+
+using content::BrowserThread;
+using content::DevToolsAgentHost;
+using content::RenderViewHost;
+using content::WebContents;
+using content::WorkerService;
+
+namespace {
+
+const char kTargetTypeApp[] = "app";
+const char kTargetTypeBackgroundPage[] = "background_page";
+const char kTargetTypePage[] = "page";
+const char kTargetTypeWorker[] = "worker";
+const char kTargetTypeOther[] = "other";
+
+std::string GetExtensionName(WebContents* web_contents) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (!profile)
+    return std::string();
+
+  extensions::ExtensionHost* extension_host =
+      extensions::ExtensionSystem::Get(profile)->process_manager()->
+          GetBackgroundHostForExtension(web_contents->GetURL().host());
+
+  if (!extension_host || extension_host->host_contents() != web_contents)
+    return std::string();
+
+  return extension_host->extension()->name();
+}
+
+class RenderViewHostTarget : public DevToolsTargetImpl {
+ public:
+  explicit RenderViewHostTarget(RenderViewHost* rvh, bool is_tab);
+
+  // content::DevToolsTarget overrides:
+  virtual bool Activate() const OVERRIDE;
+  virtual bool Close() const OVERRIDE;
+
+  // DevToolsTargetImpl overrides:
+  virtual RenderViewHost* GetRenderViewHost() const OVERRIDE;
+  virtual int GetTabId() const OVERRIDE;
+  virtual std::string GetExtensionId() const OVERRIDE;
+  virtual void Inspect(Profile* profile) const OVERRIDE;
+
+ private:
+  int tab_id_;
+  std::string extension_id_;
+};
+
+RenderViewHostTarget::RenderViewHostTarget(RenderViewHost* rvh, bool is_tab) {
+  agent_host_ = DevToolsAgentHost::GetOrCreateFor(rvh);
+  id_ = agent_host_->GetId();
+  type_ = kTargetTypeOther;
+  tab_id_ = -1;
+
+  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+  if (!web_contents)
+    return;  // Orphan RVH will show up with no title/url/icon in clients.
+
+  title_ = UTF16ToUTF8(web_contents->GetTitle());
+  url_ = web_contents->GetURL();
+  content::NavigationController& controller = web_contents->GetController();
+  content::NavigationEntry* entry = controller.GetActiveEntry();
+  if (entry != NULL && entry->GetURL().is_valid())
+    favicon_url_ = entry->GetFavicon().url;
+  last_activity_time_ = web_contents->GetLastSelectedTime();
+
+  if (is_tab) {
+    type_ = kTargetTypePage;
+    tab_id_ = ExtensionTabUtil::GetTabId(web_contents);
+  } else {
+    Profile* profile =
+        Profile::FromBrowserContext(web_contents->GetBrowserContext());
+    if (profile) {
+      ExtensionService* extension_service = profile->GetExtensionService();
+      const extensions::Extension* extension = extension_service->
+          extensions()->GetByID(url_.host());
+      if (extension) {
+        title_ = extension->name();
+        if (extension->is_hosted_app()
+            || extension->is_legacy_packaged_app()
+            || extension->is_platform_app()) {
+          type_ = kTargetTypeApp;
+        } else {
+          extensions::ExtensionHost* extension_host =
+              extensions::ExtensionSystem::Get(profile)->process_manager()->
+                  GetBackgroundHostForExtension(extension->id());
+          if (extension_host &&
+              extension_host->host_contents() == web_contents) {
+            type_ = kTargetTypeBackgroundPage;
+            extension_id_ = extension->id();
+          }
+        }
+        favicon_url_ = extensions::ExtensionIconSource::GetIconURL(
+            extension, extension_misc::EXTENSION_ICON_SMALLISH,
+            ExtensionIconSet::MATCH_BIGGER, false, NULL);
+      }
+    }
+
+    std::string extension_name = GetExtensionName(web_contents);
+    if (!extension_name.empty()) {
+      type_ = kTargetTypeBackgroundPage;
+      title_ = extension_name;
+    }
+  }
+}
+
+bool RenderViewHostTarget::Activate() const {
+  RenderViewHost* rvh = GetRenderViewHost();
+  if (!rvh)
+    return false;
+  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+  if (!web_contents)
+    return false;
+  web_contents->GetDelegate()->ActivateContents(web_contents);
+  return true;
+}
+
+bool RenderViewHostTarget::Close() const {
+  RenderViewHost* rvh = GetRenderViewHost();
+  if (!rvh)
+    return false;
+  rvh->ClosePage();
+  return true;
+}
+
+RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
+  return agent_host_->GetRenderViewHost();
+}
+
+int RenderViewHostTarget::GetTabId() const {
+  return tab_id_;
+}
+
+std::string RenderViewHostTarget::GetExtensionId() const {
+  return extension_id_;
+}
+
+void RenderViewHostTarget::Inspect(Profile* profile) const {
+  RenderViewHost* rvh = GetRenderViewHost();
+  if (!rvh)
+    return;
+  DevToolsWindow::OpenDevToolsWindow(rvh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class WorkerTarget : public DevToolsTargetImpl {
+ public:
+  explicit WorkerTarget(const WorkerService::WorkerInfo& worker_info);
+
+  // content::DevToolsTarget overrides:
+  virtual bool Close() const OVERRIDE;
+
+  // DevToolsTargetImpl overrides:
+  virtual void Inspect(Profile* profile) const OVERRIDE;
+
+ private:
+  int process_id_;
+  int route_id_;
+};
+
+WorkerTarget::WorkerTarget(const WorkerService::WorkerInfo& worker) {
+  agent_host_ =
+      DevToolsAgentHost::GetForWorker(worker.process_id, worker.route_id);
+  id_ = agent_host_->GetId();
+  type_ = kTargetTypeWorker;
+  title_ = UTF16ToUTF8(worker.name);
+  description_ =
+      base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle));
+  url_ = worker.url;
+
+  process_id_ = worker.process_id;
+  route_id_ = worker.route_id;
+}
+
+static void TerminateWorker(int process_id, int route_id) {
+  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
+}
+
+bool WorkerTarget::Close() const {
+  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+      base::Bind(&TerminateWorker, process_id_, route_id_));
+  return true;
+}
+
+void WorkerTarget::Inspect(Profile* profile) const {
+  DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get());
+}
+
+}  // namespace
+
+DevToolsTargetImpl::~DevToolsTargetImpl() {
+}
+
+DevToolsTargetImpl::DevToolsTargetImpl() {
+}
+
+std::string DevToolsTargetImpl::GetId() const {
+  return id_;
+}
+
+std::string DevToolsTargetImpl::GetType() const {
+  return type_;
+}
+
+std::string DevToolsTargetImpl::GetTitle() const {
+  return title_;
+}
+
+std::string DevToolsTargetImpl::GetDescription() const {
+  return description_;
+}
+
+GURL DevToolsTargetImpl::GetUrl() const {
+  return url_;
+}
+
+GURL DevToolsTargetImpl::GetFaviconUrl() const {
+  return favicon_url_;
+}
+
+base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const {
+  return last_activity_time_;
+}
+
+scoped_refptr<content::DevToolsAgentHost>
+DevToolsTargetImpl::GetAgentHost() const {
+  return agent_host_;
+}
+
+bool DevToolsTargetImpl::IsAttached() const {
+  return agent_host_->IsAttached();
+}
+
+bool DevToolsTargetImpl::Activate() const {
+  return false;
+}
+
+bool DevToolsTargetImpl::Close() const {
+  return false;
+}
+
+int DevToolsTargetImpl::GetTabId() const {
+  return -1;
+}
+
+RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
+  return NULL;
+}
+
+std::string DevToolsTargetImpl::GetExtensionId() const {
+  return std::string();
+}
+
+void DevToolsTargetImpl::Inspect(Profile*) const {
+}
+
+void DevToolsTargetImpl::Reload() const {
+}
+
+// static
+scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForRenderViewHost(
+    content::RenderViewHost* rvh, bool is_tab) {
+  return scoped_ptr<DevToolsTargetImpl>(new RenderViewHostTarget(rvh, is_tab));
+}
+
+// static
+scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForWorker(
+    const WorkerService::WorkerInfo& worker_info) {
+  return scoped_ptr<DevToolsTargetImpl>(new WorkerTarget(worker_info));
+}
+
+// static
+DevToolsTargetImpl::List DevToolsTargetImpl::EnumerateRenderViewHostTargets() {
+  std::set<RenderViewHost*> tab_rvhs;
+  for (TabContentsIterator it; !it.done(); it.Next())
+    tab_rvhs.insert(it->GetRenderViewHost());
+
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DevToolsTargetImpl::List result;
+  std::vector<RenderViewHost*> rvh_list =
+      content::DevToolsAgentHost::GetValidRenderViewHosts();
+  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
+       it != rvh_list.end(); ++it) {
+    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
+    result.push_back(new RenderViewHostTarget(*it, is_tab));
+  }
+  return result;
+}
+
+static void CreateWorkerTargets(
+    const std::vector<WorkerService::WorkerInfo>& worker_info,
+    DevToolsTargetImpl::Callback callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DevToolsTargetImpl::List result;
+  for (size_t i = 0; i < worker_info.size(); ++i) {
+    result.push_back(new WorkerTarget(worker_info[i]));
+  }
+  callback.Run(result);
+}
+
+// static
+void DevToolsTargetImpl::EnumerateWorkerTargets(Callback callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&CreateWorkerTargets,
+                 WorkerService::GetInstance()->GetWorkers(),
+                 callback));
+}
+
+static void CollectAllTargets(
+    DevToolsTargetImpl::Callback callback,
+    const DevToolsTargetImpl::List& worker_targets) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DevToolsTargetImpl::List result =
+      DevToolsTargetImpl::EnumerateRenderViewHostTargets();
+  result.insert(result.begin(), worker_targets.begin(), worker_targets.end());
+  callback.Run(result);
+}
+
+// static
+void DevToolsTargetImpl::EnumerateAllTargets(Callback callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&DevToolsTargetImpl::EnumerateWorkerTargets,
+                 base::Bind(&CollectAllTargets, callback)));
+}
diff --git a/chrome/browser/devtools/devtools_target_impl.h b/chrome/browser/devtools/devtools_target_impl.h
new file mode 100644
index 0000000..d02be13
--- /dev/null
+++ b/chrome/browser/devtools/devtools_target_impl.h
@@ -0,0 +1,84 @@
+// Copyright 2013 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_DEVTOOLS_DEVTOOLS_TARGET_IMPL_H_
+#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TARGET_IMPL_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "content/public/browser/devtools_target.h"
+#include "content/public/browser/worker_service.h"
+
+class Profile;
+
+namespace content {
+class DevToolsAgentHost;
+class RenderViewHost;
+}
+
+class DevToolsTargetImpl : public content::DevToolsTarget {
+ public:
+
+  DevToolsTargetImpl();
+  virtual ~DevToolsTargetImpl();
+
+  // content::DevToolsTarget overrides:
+  virtual std::string GetId() const OVERRIDE;
+  virtual std::string GetType() const OVERRIDE;
+  virtual std::string GetTitle() const OVERRIDE;
+  virtual std::string GetDescription() const OVERRIDE;
+  virtual GURL GetUrl() const OVERRIDE;
+  virtual GURL GetFaviconUrl() const OVERRIDE;
+  virtual base::TimeTicks GetLastActivityTime() const OVERRIDE;
+  virtual bool IsAttached() const OVERRIDE;
+  virtual scoped_refptr<content::DevToolsAgentHost> GetAgentHost() const
+    OVERRIDE;
+  virtual bool Activate() const OVERRIDE;
+  virtual bool Close() const OVERRIDE;
+
+  // Returns the RenderViewHost associated with the target on NULL if there is
+  // not any.
+  virtual content::RenderViewHost* GetRenderViewHost() const;
+
+  // Returns the tab id if the target is associated with a tab, -1 otherwise.
+  virtual int GetTabId() const;
+
+  // Returns the extension id if the target is associated with an extension
+  // background page.
+  virtual std::string GetExtensionId() const;
+
+  // Open a new DevTools window or activate the existing one.
+  virtual void Inspect(Profile* profile) const;
+
+  // Reload the target page.
+  virtual void Reload() const;
+
+  // Creates a new target associated with RenderViewHost.
+  static scoped_ptr<DevToolsTargetImpl> CreateForRenderViewHost(
+      content::RenderViewHost*, bool is_tab);
+
+  // Creates a new target associated with a shared worker.
+  static scoped_ptr<DevToolsTargetImpl> CreateForWorker(
+      const content::WorkerService::WorkerInfo&);
+
+  typedef std::vector<DevToolsTargetImpl*> List;
+  typedef base::Callback<void(const List&)> Callback;
+
+  static List EnumerateRenderViewHostTargets();
+  static void EnumerateWorkerTargets(Callback callback);
+  static void EnumerateAllTargets(Callback callback);
+
+ protected:
+  scoped_refptr<content::DevToolsAgentHost> agent_host_;
+  std::string id_;
+  std::string type_;
+  std::string title_;
+  std::string description_;
+  GURL url_;
+  GURL favicon_url_;
+  base::TimeTicks last_activity_time_;
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TARGET_IMPL_H_
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index a3fa063..e5af37e 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -9,6 +9,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/file_select_helper.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/themes/theme_properties.h"
@@ -176,20 +176,23 @@
 class DevToolsWindow::FrontendWebContentsObserver
     : public content::WebContentsObserver {
  public:
-  explicit FrontendWebContentsObserver(content::WebContents* web_contents);
+  explicit FrontendWebContentsObserver(DevToolsWindow* window);
   virtual ~FrontendWebContentsObserver();
 
  private:
   // contents::WebContentsObserver:
   virtual void AboutToNavigateRenderView(
       content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void DocumentOnLoadCompletedInMainFrame(int32 page_id) OVERRIDE;
 
+  DevToolsWindow* devtools_window_;
   DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
 };
 
 DevToolsWindow::FrontendWebContentsObserver::FrontendWebContentsObserver(
-    content::WebContents* web_contents)
-    : WebContentsObserver(web_contents) {
+    DevToolsWindow* devtools_window)
+    : WebContentsObserver(devtools_window->web_contents()),
+      devtools_window_(devtools_window) {
 }
 
 DevToolsWindow::FrontendWebContentsObserver::~FrontendWebContentsObserver() {
@@ -200,6 +203,10 @@
   content::DevToolsClientHost::SetupDevToolsFrontendClient(render_view_host);
 }
 
+void DevToolsWindow::FrontendWebContentsObserver::
+    DocumentOnLoadCompletedInMainFrame(int32 page_id) {
+  devtools_window_->DocumentOnLoadCompletedInMainFrame();
+}
 
 // DevToolsWindow -------------------------------------------------------------
 
@@ -563,8 +570,7 @@
       weak_factory_(this) {
   web_contents_ =
       content::WebContents::Create(content::WebContents::CreateParams(profile));
-  frontend_contents_observer_.reset(
-      new FrontendWebContentsObserver(web_contents_));
+  frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
 
   web_contents_->GetController().LoadURL(url, content::Referrer(),
       content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
@@ -586,7 +592,6 @@
   // Register on-load actions.
   content::Source<content::NavigationController> nav_controller_source(
       &web_contents_->GetController());
-  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, nav_controller_source);
   registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, nav_controller_source);
   registrar_.Add(
       this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
@@ -724,14 +729,7 @@
 void DevToolsWindow::Observe(int type,
                              const content::NotificationSource& source,
                              const content::NotificationDetails& details) {
-  if (type == content::NOTIFICATION_LOAD_STOP) {
-    if (!is_loaded_) {
-      is_loaded_ = true;
-      UpdateTheme();
-      DoAction();
-      AddDevToolsExtensionsToClient();
-    }
-  } else if (type == chrome::NOTIFICATION_TAB_CLOSING) {
+  if (type == chrome::NOTIFICATION_TAB_CLOSING) {
     if (content::Source<content::NavigationController>(source).ptr() ==
         &web_contents_->GetController()) {
       // This happens when browser closes all of its tabs as a result
@@ -1383,3 +1381,10 @@
   return inspected_contents_observer_ ?
       inspected_contents_observer_->web_contents() : NULL;
 }
+
+void DevToolsWindow::DocumentOnLoadCompletedInMainFrame() {
+  is_loaded_ = true;
+  UpdateTheme();
+  DoAction();
+  AddDevToolsExtensionsToClient();
+}
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index 527bcc3..fcdaadb 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -248,10 +248,12 @@
   bool IsDocked();
   void Restore();
   content::WebContents* GetInspectedWebContents();
+  void DocumentOnLoadCompletedInMainFrame();
 
   class InspectedWebContentsObserver;
   scoped_ptr<InspectedWebContentsObserver> inspected_contents_observer_;
   class FrontendWebContentsObserver;
+  friend class FrontendWebContentsObserver;
   scoped_ptr<FrontendWebContentsObserver> frontend_contents_observer_;
 
   Profile* profile_;
diff --git a/chrome/browser/devtools/port_forwarding_controller.cc b/chrome/browser/devtools/port_forwarding_controller.cc
index f53d6b8..a733851 100644
--- a/chrome/browser/devtools/port_forwarding_controller.cc
+++ b/chrome/browser/devtools/port_forwarding_controller.cc
@@ -49,7 +49,6 @@
 static const char kTetheringBind[] = "Tethering.bind";
 static const char kTetheringUnbind[] = "Tethering.unbind";
 
-static const char kChromeProductName[] = "Chrome";
 static const char kDevToolsRemoteBrowserTarget[] = "/devtools/browser";
 const int kMinVersionPortForwarding = 28;
 
@@ -221,19 +220,7 @@
   bool about_to_destroy_;
 };
 
-typedef std::vector<int> ParsedVersion;
-
-static ParsedVersion ParseVersion(const std::string& version) {
-  ParsedVersion result;
-  std::vector<std::string> parts;
-  Tokenize(version, ".", &parts);
-  for (size_t i = 0; i != parts.size(); ++i) {
-    int value = 0;
-    base::StringToInt(parts[i], &value);
-    result.push_back(value);
-  }
-  return result;
-}
+typedef DevToolsAdbBridge::RemoteBrowser::ParsedVersion ParsedVersion;
 
 static bool IsVersionLower(const ParsedVersion& left,
                            const ParsedVersion& right) {
@@ -252,8 +239,8 @@
   for (DevToolsAdbBridge::RemoteBrowsers::const_iterator it = browsers.begin();
        it != browsers.end(); ++it) {
     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = *it;
-    ParsedVersion current_version = ParseVersion(browser->version());
-    if (browser->product() == kChromeProductName &&
+    ParsedVersion current_version = browser->GetParsedVersion();
+    if (browser->IsChrome() &&
         IsPortForwardingSupported(current_version) &&
         IsVersionLower(newest_version, current_version)) {
       socket = browser->socket();
@@ -272,9 +259,9 @@
           content::BrowserThread::DeleteOnUIThread> {
  public:
   Connection(Registry* registry,
-             scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+             scoped_refptr<AndroidDevice> device,
              const std::string& socket,
-             scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
+             scoped_refptr<RefCountedAdbThread> adb_thread,
              PrefService* pref_service);
 
   const PortStatusMap& GetPortStatusMap();
@@ -317,8 +304,8 @@
   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
 
   PortForwardingController::Registry* registry_;
-  scoped_refptr<DevToolsAdbBridge::AndroidDevice> device_;
-  scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
+  scoped_refptr<AndroidDevice> device_;
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
   PrefChangeRegistrar pref_change_registrar_;
   scoped_refptr<AdbWebSocket> web_socket_;
   int command_id_;
@@ -332,9 +319,9 @@
 
 PortForwardingController::Connection::Connection(
     Registry* registry,
-    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+    scoped_refptr<AndroidDevice> device,
     const std::string& socket,
-    scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
+    scoped_refptr<RefCountedAdbThread> adb_thread,
     PrefService* pref_service)
     : registry_(registry),
       device_(device),
@@ -579,7 +566,7 @@
 }
 
 PortForwardingController::PortForwardingController(PrefService* pref_service)
-    : adb_thread_(DevToolsAdbBridge::RefCountedAdbThread::GetInstance()),
+    : adb_thread_(RefCountedAdbThread::GetInstance()),
       pref_service_(pref_service) {
 }
 
diff --git a/chrome/browser/devtools/port_forwarding_controller.h b/chrome/browser/devtools/port_forwarding_controller.h
index 2b86310..fac4da5 100644
--- a/chrome/browser/devtools/port_forwarding_controller.h
+++ b/chrome/browser/devtools/port_forwarding_controller.h
@@ -50,7 +50,7 @@
   class Connection;
   typedef std::map<std::string, Connection* > Registry;
 
-  scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
+  scoped_refptr<RefCountedAdbThread> adb_thread_;
   PrefService* pref_service_;
   Registry registry_;
 
diff --git a/chrome/browser/devtools/refcounted_adb_thread.cc b/chrome/browser/devtools/refcounted_adb_thread.cc
new file mode 100644
index 0000000..4a202ae
--- /dev/null
+++ b/chrome/browser/devtools/refcounted_adb_thread.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/devtools/refcounted_adb_thread.h"
+
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
+
+RefCountedAdbThread* RefCountedAdbThread::instance_ = NULL;
+
+// static
+scoped_refptr<RefCountedAdbThread> RefCountedAdbThread::GetInstance() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!instance_)
+    new RefCountedAdbThread();
+  return instance_;
+}
+
+RefCountedAdbThread::RefCountedAdbThread() {
+  instance_ = this;
+  thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_IO;
+  if (!thread_->StartWithOptions(options)) {
+    delete thread_;
+    thread_ = NULL;
+  }
+}
+
+base::MessageLoop* RefCountedAdbThread::message_loop() {
+  return thread_ ? thread_->message_loop() : NULL;
+}
+
+// static
+void RefCountedAdbThread::StopThread(base::Thread* thread) {
+  thread->Stop();
+}
+
+RefCountedAdbThread::~RefCountedAdbThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  instance_ = NULL;
+  if (!thread_)
+    return;
+  // Shut down thread on FILE thread to join into IO.
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&RefCountedAdbThread::StopThread, thread_));
+}
diff --git a/chrome/browser/devtools/refcounted_adb_thread.h b/chrome/browser/devtools/refcounted_adb_thread.h
new file mode 100644
index 0000000..3dcf612
--- /dev/null
+++ b/chrome/browser/devtools/refcounted_adb_thread.h
@@ -0,0 +1,27 @@
+// Copyright 2013 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_DEVTOOLS_REFCOUNTED_ADB_THREAD_H_
+#define CHROME_BROWSER_DEVTOOLS_REFCOUNTED_ADB_THREAD_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread.h"
+
+class RefCountedAdbThread : public base::RefCounted<RefCountedAdbThread> {
+ public:
+  static scoped_refptr<RefCountedAdbThread> GetInstance();
+  base::MessageLoop* message_loop();
+
+ private:
+  friend class base::RefCounted<RefCountedAdbThread>;
+  static RefCountedAdbThread* instance_;
+  static void StopThread(base::Thread* thread);
+
+  RefCountedAdbThread();
+  virtual ~RefCountedAdbThread();
+  base::Thread* thread_;
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_REFCOUNTED_ADB_THREAD_H_
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc
index 9c62965..033d151 100644
--- a/chrome/browser/download/download_danger_prompt.cc
+++ b/chrome/browser/download/download_danger_prompt.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/metrics/field_trial.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
@@ -18,6 +19,10 @@
 
 namespace {
 
+// TODO(wittman): Create a native web contents modal dialog implementation of
+// this dialog for non-Views platforms, to support bold formatting of the
+// message lead.
+
 // Implements DownloadDangerPrompt using a TabModalConfirmDialog.
 class DownloadDangerPromptImpl : public DownloadDangerPrompt,
                                  public content::DownloadItem::Observer,
@@ -98,8 +103,19 @@
 string16 DownloadDangerPromptImpl::GetTitle() {
   if (show_context_)
     return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
-  else
-    return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+  switch (download_->GetDangerType()) {
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
+      return l10n_util::GetStringUTF16(
+          IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+    }
+    default: {
+      return l10n_util::GetStringUTF16(
+          IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+    }
+  }
 }
 
 string16 DownloadDangerPromptImpl::GetMessage() {
@@ -124,7 +140,7 @@
       }
       case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
         return l10n_util::GetStringFUTF16(
-            IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS,
+            IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
             download_->GetFileNameToReportUser().LossyDisplayName());
       }
       case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
@@ -140,7 +156,10 @@
       case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
       case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
         return l10n_util::GetStringUTF16(
-            IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD);
+            IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD) +
+            ASCIIToUTF16("\n\n") +
+            l10n_util::GetStringUTF16(
+                IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
       }
       default: {
         return l10n_util::GetStringUTF16(
@@ -158,7 +177,8 @@
   switch (download_->GetDangerType()) {
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
-    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
       return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
     }
     default:
@@ -172,7 +192,8 @@
   switch (download_->GetDangerType()) {
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
-    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
       return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
     }
     default:
@@ -208,6 +229,7 @@
 
 }  // namespace
 
+#if !(defined(OS_WIN) || defined(USE_AURA))
 // static
 DownloadDangerPrompt* DownloadDangerPrompt::Create(
     content::DownloadItem* item,
@@ -220,3 +242,4 @@
   TabModalConfirmDialog::Create(prompt, web_contents);
   return prompt;
 }
+#endif
diff --git a/chrome/browser/download/download_dir_policy_handler.cc b/chrome/browser/download/download_dir_policy_handler.cc
index f1d4932..109c0e3 100644
--- a/chrome/browser/download/download_dir_policy_handler.cc
+++ b/chrome/browser/download/download_dir_policy_handler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/download/download_dir_policy_handler.h"
 
 #include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_value_map.h"
 #include "base/values.h"
 #include "chrome/browser/download/download_prefs.h"
diff --git a/chrome/browser/download/download_dir_policy_handler_unittest.cc b/chrome/browser/download/download_dir_policy_handler_unittest.cc
index c4ff387..f4bef4f 100644
--- a/chrome/browser/download/download_dir_policy_handler_unittest.cc
+++ b/chrome/browser/download/download_dir_policy_handler_unittest.cc
@@ -12,7 +12,14 @@
 #include "policy/policy_constants.h"
 
 class DownloadDirPolicyHandlerTest
-    : public policy::ConfigurationPolicyPrefStoreTest {};
+    : public policy::ConfigurationPolicyPrefStoreTest {
+ public:
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<policy::ConfigurationPolicyHandler>(
+            new DownloadDirPolicyHandler));
+  }
+};
 
 TEST_F(DownloadDirPolicyHandlerTest, SetDownloadDirectory) {
   policy::PolicyMap policy;
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc
index 630d296..dc235b3 100644
--- a/chrome/browser/download/download_extensions.cc
+++ b/chrome/browser/download/download_extensions.cc
@@ -68,14 +68,6 @@
   { "jnlp", DANGEROUS },
 #endif
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-  // Relating to PDF.
-  { "pdf", ALLOW_ON_USER_GESTURE },
-  { "pdfxml", ALLOW_ON_USER_GESTURE },
-  { "mars", ALLOW_ON_USER_GESTURE },
-  { "fdf", ALLOW_ON_USER_GESTURE },
-  { "xfdf", ALLOW_ON_USER_GESTURE },
-  { "xdp", ALLOW_ON_USER_GESTURE },
-  { "xfd", ALLOW_ON_USER_GESTURE },
   // Relating to scripting languages.
   { "pl", ALLOW_ON_USER_GESTURE },
   { "py", ALLOW_ON_USER_GESTURE },
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 0823a40..2913b0e 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -367,7 +367,7 @@
     }
     case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
       return l10n_util::GetStringFUTF16(
-          IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS, elided_filename);
+          IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename);
     }
     case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
     case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
@@ -446,6 +446,7 @@
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
       return true;
 
     case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
@@ -457,7 +458,6 @@
       NOTREACHED();
       // Fallthrough.
     case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
-    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
       return false;
   }
   NOTREACHED();
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index 9bd9d6b..2964b58 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -322,7 +322,6 @@
   maybe_malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
   maybe_malicious_download_menu_model_->AddItemWithStringId(
       LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
-  LOG(INFO) << "GetMaybeMaliciousMenuModel";
   return maybe_malicious_download_menu_model_.get();
 }
 
@@ -341,7 +340,6 @@
     maybe_malicious_download_menu_model_->AddItemWithStringId(
         DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
   }
-  LOG(INFO) << "GetMaliciousMenuModel";
   malicious_download_menu_model_->AddItemWithStringId(
       LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
 
diff --git a/chrome/browser/download/download_started_animation_browsertest.cc b/chrome/browser/download/download_started_animation_browsertest.cc
new file mode 100644
index 0000000..f6163fb
--- /dev/null
+++ b/chrome/browser/download/download_started_animation_browsertest.cc
@@ -0,0 +1,26 @@
+// Copyright 2013 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/download/download_started_animation.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+
+class DownloadStartedAnimationTest : public InProcessBrowserTest {
+ public:
+  DownloadStartedAnimationTest() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationTest);
+};
+
+IN_PROC_BROWSER_TEST_F(DownloadStartedAnimationTest,
+                       InstantiateAndImmediatelyClose) {
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  DownloadStartedAnimation::Show(web_contents);
+  chrome::CloseWindow(browser());
+}
diff --git a/chrome/browser/download/drag_download_item_views.cc b/chrome/browser/download/drag_download_item_views.cc
index 872e1d5..7b94718 100644
--- a/chrome/browser/download/drag_download_item_views.cc
+++ b/chrome/browser/download/drag_download_item_views.cc
@@ -58,7 +58,7 @@
 
 #if !defined(TOOLKIT_GTK)
 #if defined(USE_AURA)
-  aura::RootWindow* root_window = view->GetRootWindow();
+  aura::Window* root_window = view->GetRootWindow();
   if (!root_window || !aura::client::GetDragDropClient(root_window))
     return;
 
diff --git a/chrome/browser/enumerate_modules_model_win.cc b/chrome/browser/enumerate_modules_model_win.cc
index a22f358..37574c4 100644
--- a/chrome/browser/enumerate_modules_model_win.cc
+++ b/chrome/browser/enumerate_modules_model_win.cc
@@ -441,7 +441,6 @@
 
   if (!limited_mode_) {
     CHECK(BrowserThread::GetCurrentThreadIdentifier(&callback_thread_id_));
-    DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE));
     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                             base::Bind(&ModuleEnumerator::ScanImpl, this));
   } else {
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 8e8c1dc..d8c0ce6 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
@@ -19,6 +18,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/user_script.h"
 
 using content::RenderProcessHost;
@@ -63,10 +63,15 @@
     PermissionsData::UpdateTabSpecificPermissions(extension,
                                                   tab_id_,
                                                   new_permissions);
-    Send(new ExtensionMsg_UpdateTabSpecificPermissions(GetPageID(),
-                                                       tab_id_,
-                                                       extension->id(),
-                                                       new_hosts));
+    const content::NavigationEntry* navigation_entry =
+        web_contents()->GetController().GetVisibleEntry();
+    if (navigation_entry) {
+      Send(new ExtensionMsg_UpdateTabSpecificPermissions(
+          navigation_entry->GetPageID(),
+          tab_id_,
+          extension->id(),
+          new_hosts));
+    }
   }
 }
 
@@ -112,8 +117,4 @@
   granted_extensions_.Clear();
 }
 
-int32 ActiveTabPermissionGranter::GetPageID() {
-  return web_contents()->GetController().GetVisibleEntry()->GetPageID();
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/extensions/active_tab_permission_granter.h b/chrome/browser/extensions/active_tab_permission_granter.h
index 0ef0336..fe43fb8 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.h
+++ b/chrome/browser/extensions/active_tab_permission_granter.h
@@ -55,9 +55,6 @@
   // notifies renderers.
   void ClearActiveExtensionsAndNotify();
 
-  // Gets the current page id.
-  int32 GetPageID();
-
   // The tab ID for this tab.
   int tab_id_;
 
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index ae16beb..d567d0c 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -270,7 +270,7 @@
 
   // Uninstalling the extension should clear its tab permissions.
   UnloadedExtensionInfo details(extension.get(),
-                                extension_misc::UNLOAD_REASON_DISABLE);
+                                UnloadedExtensionInfo::REASON_DISABLE);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(Profile::FromBrowserContext(
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
index 24a1886..b43227f 100644
--- a/chrome/browser/extensions/all_urls_apitest.cc
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -12,6 +12,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/id_util.h"
 
 const std::string kAllUrlsTarget =
@@ -39,10 +40,10 @@
                                           .AppendASCII("execute_script");
 
   // Then add the two extensions to the whitelist.
-  extensions::Extension::ScriptingWhitelist whitelist;
+  extensions::ExtensionsClient::ScriptingWhitelist whitelist;
   whitelist.push_back(extensions::id_util::GenerateIdForPath(extension_dir1));
   whitelist.push_back(extensions::id_util::GenerateIdForPath(extension_dir2));
-  extensions::Extension::SetScriptingWhitelist(whitelist);
+  extensions::ExtensionsClient::Get()->SetScriptingWhitelist(whitelist);
 
   // Then load extensions.
   ExtensionService* service = extensions::ExtensionSystem::Get(
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
index 04a6406..db3603a 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
@@ -144,7 +144,7 @@
     days_ago = *filter->days_ago;
 
   // Call the ActivityLog.
-  ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+  ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
   DCHECK(activity_log);
   activity_log->GetFilteredActions(
       extension_id,
@@ -181,7 +181,7 @@
 }
 
 bool ActivityLogPrivateDeleteDatabaseFunction::RunImpl() {
-  ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+  ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
   DCHECK(activity_log);
   activity_log->DeleteDatabase();
   return true;
@@ -201,7 +201,7 @@
     gurls.push_back(GURL(*it));
   }
 
-  ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+  ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
   DCHECK(activity_log);
   activity_log->RemoveURLs(gurls);
   return true;
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
index 45ec258..a2bf60b 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
@@ -13,8 +13,8 @@
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 
 namespace extensions {
 
@@ -66,7 +66,7 @@
 
 // The implementation of activityLogPrivate.getExtensionActivities
 class ActivityLogPrivateGetExtensionActivitiesFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("activityLogPrivate.getExtensionActivities",
                              ACTIVITYLOGPRIVATE_GETEXTENSIONACTIVITIES)
@@ -84,7 +84,7 @@
 
 // The implementation of activityLogPrivate.deleteDatabase
 class ActivityLogPrivateDeleteDatabaseFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("activityLogPrivate.deleteDatabase",
                              ACTIVITYLOGPRIVATE_DELETEDATABASE)
@@ -98,7 +98,7 @@
 
 // The implementation of activityLogPrivate.deleteUrls
 class ActivityLogPrivateDeleteUrlsFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("activityLogPrivate.deleteUrls",
                              ACTIVITYLOGPRIVATE_DELETEURLS)
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
index 9c1f7be..233565e 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
@@ -50,7 +50,9 @@
 // TODO(karenlees): fix flakiness on win debug - crbug.com/299393
 #define MAYBE_TriggerEvent DISABLED_TriggerEvent
 #else
-#define MAYBE_TriggerEvent TriggerEvent
+// Disabled while waiting for Blink roll to avoid
+// https://codereview.chromium.org/52203002
+#define MAYBE_TriggerEvent DISABLED_TriggerEvent
 #endif
 
 // The test extension sends a message to its 'friend'. The test completes
diff --git a/chrome/browser/extensions/api/alarms/alarms_api.cc b/chrome/browser/extensions/api/alarms/alarms_api.cc
index cc49b6e..7c06214 100644
--- a/chrome/browser/extensions/api/alarms/alarms_api.cc
+++ b/chrome/browser/extensions/api/alarms/alarms_api.cc
@@ -120,8 +120,8 @@
                   Manifest::IsUnpackedLocation(GetExtension()->location()) ?
                   kDevDelayMinimum : kReleaseDelayMinimum),
               clock_->Now());
-  AlarmManager::Get(profile())->AddAlarm(extension_id(), alarm, base::Bind(
-      &AlarmsCreateFunction::Callback, this));
+  AlarmManager::Get(GetProfile())->AddAlarm(
+      extension_id(), alarm, base::Bind(&AlarmsCreateFunction::Callback, this));
 
   return true;
 }
@@ -135,8 +135,10 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   std::string name = params->name.get() ? *params->name : kDefaultAlarmName;
-  AlarmManager::Get(profile())->GetAlarm(extension_id(), name, base::Bind(
-      &AlarmsGetFunction::Callback, this, name));
+  AlarmManager::Get(GetProfile())
+      ->GetAlarm(extension_id(),
+                 name,
+                 base::Bind(&AlarmsGetFunction::Callback, this, name));
 
   return true;
 }
@@ -153,8 +155,8 @@
 }
 
 bool AlarmsGetAllFunction::RunImpl() {
-  AlarmManager::Get(profile())->GetAllAlarms(extension_id(), base::Bind(
-      &AlarmsGetAllFunction::Callback, this));
+  AlarmManager::Get(GetProfile())->GetAllAlarms(
+      extension_id(), base::Bind(&AlarmsGetAllFunction::Callback, this));
   return true;
 }
 
@@ -178,8 +180,10 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   std::string name = params->name.get() ? *params->name : kDefaultAlarmName;
-  AlarmManager::Get(profile())->RemoveAlarm(extension_id(), name, base::Bind(
-      &AlarmsClearFunction::Callback, this, name));
+  AlarmManager::Get(GetProfile())
+      ->RemoveAlarm(extension_id(),
+                    name,
+                    base::Bind(&AlarmsClearFunction::Callback, this, name));
 
   return true;
 }
@@ -192,8 +196,8 @@
 }
 
 bool AlarmsClearAllFunction::RunImpl() {
-  AlarmManager::Get(profile())->RemoveAllAlarms(extension_id(), base::Bind(
-      &AlarmsClearAllFunction::Callback, this));
+  AlarmManager::Get(GetProfile())->RemoveAllAlarms(
+      extension_id(), base::Bind(&AlarmsClearAllFunction::Callback, this));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/alarms/alarms_api.h b/chrome/browser/extensions/api/alarms/alarms_api.h
index b14a166..3d971af 100644
--- a/chrome/browser/extensions/api/alarms/alarms_api.h
+++ b/chrome/browser/extensions/api/alarms/alarms_api.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace base {
 class Clock;
@@ -17,7 +17,7 @@
 struct Alarm;
 typedef std::vector<Alarm> AlarmList;
 
-class AlarmsCreateFunction : public AsyncExtensionFunction {
+class AlarmsCreateFunction : public ChromeAsyncExtensionFunction {
  public:
   AlarmsCreateFunction();
   // Use |clock| instead of the default clock. Does not take ownership
@@ -39,7 +39,7 @@
   bool owns_clock_;
 };
 
-class AlarmsGetFunction : public AsyncExtensionFunction {
+class AlarmsGetFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~AlarmsGetFunction() {}
 
@@ -51,7 +51,7 @@
   DECLARE_EXTENSION_FUNCTION("alarms.get", ALARMS_GET)
 };
 
-class AlarmsGetAllFunction : public AsyncExtensionFunction {
+class AlarmsGetAllFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~AlarmsGetAllFunction() {}
 
@@ -62,7 +62,7 @@
   DECLARE_EXTENSION_FUNCTION("alarms.getAll", ALARMS_GETALL)
 };
 
-class AlarmsClearFunction : public AsyncExtensionFunction {
+class AlarmsClearFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~AlarmsClearFunction() {}
 
@@ -73,7 +73,7 @@
   DECLARE_EXTENSION_FUNCTION("alarms.clear", ALARMS_CLEAR)
 };
 
-class AlarmsClearAllFunction : public AsyncExtensionFunction {
+class AlarmsClearAllFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~AlarmsClearAllFunction() {}
 
diff --git a/chrome/browser/extensions/api/api_function.h b/chrome/browser/extensions/api/api_function.h
index 0aacdad..5fb32a9 100644
--- a/chrome/browser/extensions/api/api_function.h
+++ b/chrome/browser/extensions/api/api_function.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_API_FUNCTION_H_
 #define CHROME_BROWSER_EXTENSIONS_API_API_FUNCTION_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace extensions {
@@ -13,7 +13,7 @@
 // Base class for API functions. TODO(miket): there isn't much here anymore
 // since the removal of ApiResourceEventRouter. Should we promote all its
 // subclasses to UIThreadExtensionFunctions?
-class ApiFunction : public UIThreadExtensionFunction {
+class ApiFunction : public ChromeAsyncExtensionFunction {
  protected:
   ApiFunction();
   virtual ~ApiFunction();
diff --git a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
index 8dbd8b6..ea09a83 100644
--- a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
+++ b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
@@ -16,17 +16,22 @@
 #include "extensions/common/switches.h"
 #include "third_party/skia/include/core/SkRegion.h"
 
-namespace SetBounds = extensions::api::app_current_window_internal::SetBounds;
-namespace SetIcon = extensions::api::app_current_window_internal::SetIcon;
-namespace SetInputRegion =
-    extensions::api::app_current_window_internal::SetInputRegion;
-namespace SetAlwaysOnTop =
-    extensions::api::app_current_window_internal::SetAlwaysOnTop;
+namespace app_current_window_internal =
+    extensions::api::app_current_window_internal;
+
+namespace SetBounds = app_current_window_internal::SetBounds;
+namespace SetMinWidth = app_current_window_internal::SetMinWidth;
+namespace SetMinHeight = app_current_window_internal::SetMinHeight;
+namespace SetMaxWidth = app_current_window_internal::SetMaxWidth;
+namespace SetMaxHeight = app_current_window_internal::SetMaxHeight;
+namespace SetIcon = app_current_window_internal::SetIcon;
+namespace SetInputRegion = app_current_window_internal::SetInputRegion;
+namespace SetAlwaysOnTop = app_current_window_internal::SetAlwaysOnTop;
 
 using apps::ShellWindow;
-using extensions::api::app_current_window_internal::Bounds;
-using extensions::api::app_current_window_internal::Region;
-using extensions::api::app_current_window_internal::RegionRect;
+using app_current_window_internal::Bounds;
+using app_current_window_internal::Region;
+using app_current_window_internal::RegionRect;
 
 namespace extensions {
 
@@ -39,11 +44,13 @@
 const char kDevChannelOnly[] =
     "This function is currently only available in the Dev channel.";
 
+const int kUnboundedSize = apps::ShellWindow::SizeConstraints::kUnboundedSize;
+
 }  // namespace
 
 bool AppCurrentWindowInternalExtensionFunction::RunImpl() {
   apps::ShellWindowRegistry* registry =
-      apps::ShellWindowRegistry::Get(profile());
+      apps::ShellWindowRegistry::Get(GetProfile());
   DCHECK(registry);
   content::RenderViewHost* rvh = render_view_host();
   if (!rvh)
@@ -132,6 +139,50 @@
   return true;
 }
 
+bool AppCurrentWindowInternalSetMinWidthFunction::RunWithWindow(
+    ShellWindow* window) {
+  scoped_ptr<SetMinWidth::Params> params(SetMinWidth::Params::Create(*args_));
+  CHECK(params.get());
+  gfx::Size min_size = window->size_constraints().GetMinimumSize();
+  min_size.set_width(params->min_width.get() ?
+      *(params->min_width) : kUnboundedSize);
+  window->SetMinimumSize(min_size);
+  return true;
+}
+
+bool AppCurrentWindowInternalSetMinHeightFunction::RunWithWindow(
+    ShellWindow* window) {
+  scoped_ptr<SetMinHeight::Params> params(SetMinHeight::Params::Create(*args_));
+  CHECK(params.get());
+  gfx::Size min_size = window->size_constraints().GetMinimumSize();
+  min_size.set_height(params->min_height.get() ?
+      *(params->min_height) : kUnboundedSize);
+  window->SetMinimumSize(min_size);
+  return true;
+}
+
+bool AppCurrentWindowInternalSetMaxWidthFunction::RunWithWindow(
+    ShellWindow* window) {
+  scoped_ptr<SetMaxWidth::Params> params(SetMaxWidth::Params::Create(*args_));
+  CHECK(params.get());
+  gfx::Size max_size = window->size_constraints().GetMaximumSize();
+  max_size.set_width(params->max_width.get() ?
+      *(params->max_width) : kUnboundedSize);
+  window->SetMaximumSize(max_size);
+  return true;
+}
+
+bool AppCurrentWindowInternalSetMaxHeightFunction::RunWithWindow(
+    ShellWindow* window) {
+  scoped_ptr<SetMaxHeight::Params> params(SetMaxHeight::Params::Create(*args_));
+  CHECK(params.get());
+  gfx::Size max_size = window->size_constraints().GetMaximumSize();
+  max_size.set_height(params->max_height.get() ?
+      *(params->max_height) : kUnboundedSize);
+  window->SetMaximumSize(max_size);
+  return true;
+}
+
 bool AppCurrentWindowInternalSetIconFunction::RunWithWindow(
     ShellWindow* window) {
   if (GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV &&
diff --git a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
index 648724f..37c2f7d 100644
--- a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
+++ b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace apps {
 class ShellWindow;
@@ -13,7 +13,8 @@
 
 namespace extensions {
 
-class AppCurrentWindowInternalExtensionFunction : public SyncExtensionFunction {
+class AppCurrentWindowInternalExtensionFunction
+    : public ChromeSyncExtensionFunction {
  protected:
   virtual ~AppCurrentWindowInternalExtensionFunction() {}
 
@@ -133,6 +134,46 @@
   virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
+class AppCurrentWindowInternalSetMinWidthFunction
+    : public AppCurrentWindowInternalExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setMinWidth",
+                             APP_CURRENTWINDOWINTERNAL_SETMINWIDTH)
+ protected:
+  virtual ~AppCurrentWindowInternalSetMinWidthFunction() {}
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
+};
+
+class AppCurrentWindowInternalSetMinHeightFunction
+    : public AppCurrentWindowInternalExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setMinHeight",
+                             APP_CURRENTWINDOWINTERNAL_SETMINHEIGHT)
+ protected:
+  virtual ~AppCurrentWindowInternalSetMinHeightFunction() {}
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
+};
+
+class AppCurrentWindowInternalSetMaxWidthFunction
+    : public AppCurrentWindowInternalExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setMaxWidth",
+                             APP_CURRENTWINDOWINTERNAL_SETMAXWIDTH)
+ protected:
+  virtual ~AppCurrentWindowInternalSetMaxWidthFunction() {}
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
+};
+
+class AppCurrentWindowInternalSetMaxHeightFunction
+    : public AppCurrentWindowInternalExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setMaxHeight",
+                             APP_CURRENTWINDOWINTERNAL_SETMAXHEIGHT)
+ protected:
+  virtual ~AppCurrentWindowInternalSetMaxHeightFunction() {}
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
+};
+
 class AppCurrentWindowInternalSetIconFunction
     : public AppCurrentWindowInternalExtensionFunction {
  public:
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.cc b/chrome/browser/extensions/api/app_window/app_window_api.cc
index d4cf282..b31b776 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_api.cc
@@ -52,6 +52,8 @@
 
 namespace {
 
+const int kUnboundedSize = apps::ShellWindow::SizeConstraints::kUnboundedSize;
+
 // Opens an inspector window and delays the response to the
 // AppWindowCreateFunction until the DevToolsWindow has finished loading, and is
 // ready to stop on breakpoints in the callback.
@@ -101,6 +103,19 @@
   boundsValue->SetInteger("width", bounds.width());
   boundsValue->SetInteger("height", bounds.height());
   result->Set("bounds", boundsValue);
+
+  const ShellWindow::SizeConstraints& size_constraints =
+      window->size_constraints();
+  gfx::Size min_size = size_constraints.GetMinimumSize();
+  gfx::Size max_size = size_constraints.GetMaximumSize();
+  if (min_size.width() != kUnboundedSize)
+    result->SetInteger("minWidth", min_size.width());
+  if (min_size.height() != kUnboundedSize)
+    result->SetInteger("minHeight", min_size.height());
+  if (max_size.width() != kUnboundedSize)
+    result->SetInteger("maxWidth", max_size.width());
+  if (max_size.height() != kUnboundedSize)
+    result->SetInteger("maxHeight", max_size.height());
 }
 
 }  // namespace
@@ -145,9 +160,9 @@
       create_params.window_key = *options->id;
 
       if (!options->singleton || *options->singleton) {
-        ShellWindow* window = apps::ShellWindowRegistry::Get(profile())->
-            GetShellWindowForAppAndKey(extension_id(),
-                                       create_params.window_key);
+        ShellWindow* window = apps::ShellWindowRegistry::Get(
+            GetProfile())->GetShellWindowForAppAndKey(extension_id(),
+                                                      create_params.window_key);
         if (window) {
           content::RenderViewHost* created_view =
               window->web_contents()->GetRenderViewHost();
@@ -247,10 +262,8 @@
     if (options->resizable.get())
       create_params.resizable = *options->resizable.get();
 
-    if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
-        options->always_on_top.get()) {
+    if (options->always_on_top.get())
       create_params.always_on_top = *options->always_on_top.get();
-    }
 
     if (options->type != extensions::api::app_window::WINDOW_TYPE_PANEL) {
       switch (options->state) {
@@ -273,9 +286,8 @@
   create_params.creator_process_id =
       render_view_host_->GetProcess()->GetID();
 
-  ShellWindow* shell_window = new ShellWindow(profile(),
-                                              new ChromeShellWindowDelegate(),
-                                              GetExtension());
+  ShellWindow* shell_window = new ShellWindow(
+      GetProfile(), new ChromeShellWindowDelegate(), GetExtension());
   shell_window->Init(url,
                      new apps::AppWindowContents(shell_window),
                      create_params);
@@ -297,8 +309,8 @@
   SetCreateResultFromShellWindow(shell_window, result);
   SetResult(result);
 
-  if (apps::ShellWindowRegistry::Get(profile())->
-          HadDevToolsAttached(created_view)) {
+  if (apps::ShellWindowRegistry::Get(GetProfile())
+          ->HadDevToolsAttached(created_view)) {
     new DevToolsRestorer(this, created_view);
     return true;
   }
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.h b/chrome/browser/extensions/api/app_window/app_window_api.h
index 72524d6..8aaac54 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.h
+++ b/chrome/browser/extensions/api/app_window/app_window_api.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_APP_WINDOW_APP_WINDOW_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_APP_WINDOW_APP_WINDOW_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
-class AppWindowCreateFunction : public AsyncExtensionFunction {
+class AppWindowCreateFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("app.window.create", APP_WINDOW_CREATE)
 
diff --git a/chrome/browser/extensions/api/audio/audio_api.cc b/chrome/browser/extensions/api/audio/audio_api.cc
index 359b48d..90415ae 100644
--- a/chrome/browser/extensions/api/audio/audio_api.cc
+++ b/chrome/browser/extensions/api/audio/audio_api.cc
@@ -50,7 +50,7 @@
 
 bool AudioGetInfoFunction::RunImpl() {
   AudioService* service =
-      AudioAPI::GetFactoryInstance()->GetForProfile(profile())->GetService();
+      AudioAPI::GetFactoryInstance()->GetForProfile(GetProfile())->GetService();
   DCHECK(service);
   service->StartGetInfo(base::Bind(&AudioGetInfoFunction::OnGetInfoCompleted,
                                    this));
@@ -73,7 +73,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   AudioService* service =
-      AudioAPI::GetFactoryInstance()->GetForProfile(profile())->GetService();
+      AudioAPI::GetFactoryInstance()->GetForProfile(GetProfile())->GetService();
   DCHECK(service);
 
   service->SetActiveDevices(params->ids);
@@ -86,7 +86,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   AudioService* service =
-      AudioAPI::GetFactoryInstance()->GetForProfile(profile())->GetService();
+      AudioAPI::GetFactoryInstance()->GetForProfile(GetProfile())->GetService();
   DCHECK(service);
 
   int volume_value = params->properties.volume.get() ?
diff --git a/chrome/browser/extensions/api/audio/audio_api.h b/chrome/browser/extensions/api/audio/audio_api.h
index ae9398a..e5a63ee 100644
--- a/chrome/browser/extensions/api/audio/audio_api.h
+++ b/chrome/browser/extensions/api/audio/audio_api.h
@@ -7,7 +7,7 @@
 
 #include "chrome/browser/extensions/api/audio/audio_service.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
@@ -39,7 +39,7 @@
   AudioService* service_;
 };
 
-class AudioGetInfoFunction : public AsyncExtensionFunction {
+class AudioGetInfoFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("audio.getInfo",
                              AUDIO_GETINFO);
@@ -54,7 +54,7 @@
                           bool success);
 };
 
-class AudioSetActiveDevicesFunction : public SyncExtensionFunction {
+class AudioSetActiveDevicesFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("audio.setActiveDevices",
                              AUDIO_SETACTIVEDEVICES);
@@ -64,7 +64,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class AudioSetPropertiesFunction : public SyncExtensionFunction {
+class AudioSetPropertiesFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("audio.setProperties",
                              AUDIO_SETPROPERTIES);
diff --git a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
index 2d152b7..260dfa6 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
@@ -21,14 +21,14 @@
 
 bool AutotestPrivateLogoutFunction::RunImpl() {
   DVLOG(1) << "AutotestPrivateLogoutFunction";
-  if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode())
+  if (!AutotestPrivateAPIFactory::GetForProfile(GetProfile())->test_mode())
     chrome::AttemptUserExit();
   return true;
 }
 
 bool AutotestPrivateRestartFunction::RunImpl() {
   DVLOG(1) << "AutotestPrivateRestartFunction";
-  if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode())
+  if (!AutotestPrivateAPIFactory::GetForProfile(GetProfile())->test_mode())
     chrome::AttemptRestart();
   return true;
 }
@@ -42,12 +42,12 @@
 
 #if defined(OS_CHROMEOS)
   if (params->force) {
-    if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode())
+    if (!AutotestPrivateAPIFactory::GetForProfile(GetProfile())->test_mode())
       chrome::ExitCleanly();
     return true;
   }
 #endif
-  if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode())
+  if (!AutotestPrivateAPIFactory::GetForProfile(GetProfile())->test_mode())
     chrome::AttemptExit();
   return true;
 }
@@ -113,7 +113,7 @@
 
 bool AutotestPrivateSimulateAsanMemoryBugFunction::RunImpl() {
   DVLOG(1) << "AutotestPrivateSimulateAsanMemoryBugFunction";
-  if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode()) {
+  if (!AutotestPrivateAPIFactory::GetForProfile(GetProfile())->test_mode()) {
     // This array is volatile not to let compiler optimize us out.
     volatile int testarray[3] = {0, 0, 0};
 
diff --git a/chrome/browser/extensions/api/autotest_private/autotest_private_api.h b/chrome/browser/extensions/api/autotest_private/autotest_private_api.h
index 8c3e117..fb1ba74 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.h
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.h
@@ -8,12 +8,12 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
 namespace extensions {
 
-class AutotestPrivateLogoutFunction : public SyncExtensionFunction {
+class AutotestPrivateLogoutFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.logout", AUTOTESTPRIVATE_LOGOUT)
 
@@ -22,7 +22,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class AutotestPrivateRestartFunction: public SyncExtensionFunction {
+class AutotestPrivateRestartFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.restart", AUTOTESTPRIVATE_RESTART)
 
@@ -31,7 +31,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class AutotestPrivateShutdownFunction: public SyncExtensionFunction {
+class AutotestPrivateShutdownFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.shutdown",
                              AUTOTESTPRIVATE_SHUTDOWN)
@@ -41,7 +41,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class AutotestPrivateLoginStatusFunction: public SyncExtensionFunction {
+class AutotestPrivateLoginStatusFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.loginStatus",
                              AUTOTESTPRIVATE_LOGINSTATUS)
@@ -51,7 +51,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class AutotestPrivateLockScreenFunction: public SyncExtensionFunction {
+class AutotestPrivateLockScreenFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.lockScreen",
                              AUTOTESTPRIVATE_LOCKSCREEN)
@@ -62,7 +62,7 @@
 };
 
 class AutotestPrivateSimulateAsanMemoryBugFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.simulateAsanMemoryBug",
                              AUTOTESTPRIVATE_SIMULATEASANMEMORYBUG)
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
index d48d2e8..b7fadfd 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
@@ -134,7 +134,7 @@
 
   uuid_ = device::bluetooth_utils::CanonicalUuid(params->profile.uuid);
 
-  if (GetEventRouter(profile())->HasProfile(uuid_)) {
+  if (GetEventRouter(GetProfile())->HasProfile(uuid_)) {
     SetError(kProfileAlreadyRegistered);
     return false;
   }
@@ -182,7 +182,7 @@
     return;
   }
 
-  if (GetEventRouter(profile())->HasProfile(uuid_)) {
+  if (GetEventRouter(GetProfile())->HasProfile(uuid_)) {
     bluetooth_profile->Unregister();
     SetError(kProfileAlreadyRegistered);
     SendResponse(false);
@@ -191,10 +191,10 @@
 
   bluetooth_profile->SetConnectionCallback(
       base::Bind(&ExtensionBluetoothEventRouter::DispatchConnectionEvent,
-                 base::Unretained(GetEventRouter(profile())),
+                 base::Unretained(GetEventRouter(GetProfile())),
                  extension_id(),
                  uuid_));
-  GetEventRouter(profile())->AddProfile(uuid_, bluetooth_profile);
+  GetEventRouter(GetProfile())->AddProfile(uuid_, bluetooth_profile);
   SendResponse(true);
 }
 
@@ -210,12 +210,12 @@
   std::string uuid =
       device::bluetooth_utils::CanonicalUuid(params->profile.uuid);
 
-  if (!GetEventRouter(profile())->HasProfile(uuid)) {
+  if (!GetEventRouter(GetProfile())->HasProfile(uuid)) {
     SetError(kProfileNotFound);
     return false;
   }
 
-  GetEventRouter(profile())->RemoveProfile(uuid);
+  GetEventRouter(GetProfile())->RemoveProfile(uuid);
   return true;
 }
 
@@ -266,7 +266,7 @@
     const BluetoothDevice& device) {
   bluetooth::Device extension_device;
   bluetooth::BluetoothDeviceToApiDevice(device, &extension_device);
-  GetEventRouter(profile())->DispatchDeviceEvent(
+  GetEventRouter(GetProfile())->DispatchDeviceEvent(
       extensions::event_names::kBluetoothOnDeviceSearchResult,
       extension_device);
 
@@ -281,8 +281,9 @@
 
   scoped_ptr<extensions::Event> event(new extensions::Event(
       extensions::event_names::kBluetoothOnDeviceSearchFinished, args.Pass()));
-  extensions::ExtensionSystem::Get(profile())->event_router()->
-      BroadcastEvent(event.Pass());
+  extensions::ExtensionSystem::Get(GetProfile())
+      ->event_router()
+      ->BroadcastEvent(event.Pass());
 
   SendResponse(true);
 }
@@ -398,7 +399,7 @@
       options.profile.uuid);
 
   BluetoothProfile* bluetooth_profile =
-      GetEventRouter(profile())->GetProfile(uuid);
+      GetEventRouter(GetProfile())->GetProfile(uuid);
   if (!bluetooth_profile) {
     SetError(kProfileNotFound);
     SendResponse(false);
@@ -417,7 +418,7 @@
   scoped_ptr<Disconnect::Params> params(Disconnect::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
   const bluetooth::DisconnectOptions& options = params->options;
-  return GetEventRouter(profile())->ReleaseSocket(options.socket.id);
+  return GetEventRouter(GetProfile())->ReleaseSocket(options.socket.id);
 }
 
 BluetoothReadFunction::BluetoothReadFunction() : success_(false) {}
@@ -428,7 +429,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
   const bluetooth::ReadOptions& options = params->options;
 
-  socket_ = GetEventRouter(profile())->GetSocket(options.socket.id);
+  socket_ = GetEventRouter(GetProfile())->GetSocket(options.socket.id);
   if (socket_.get() == NULL) {
     SetError(kSocketNotFoundError);
     return false;
@@ -476,7 +477,7 @@
   int socket_id;
   EXTENSION_FUNCTION_VALIDATE(socket->GetInteger("id", &socket_id));
 
-  socket_ = GetEventRouter(profile())->GetSocket(socket_id);
+  socket_ = GetEventRouter(GetProfile())->GetSocket(socket_id);
   if (socket_.get() == NULL) {
     SetError(kSocketNotFoundError);
     return false;
@@ -622,20 +623,20 @@
 
 void BluetoothStartDiscoveryFunction::OnErrorCallback() {
   SetError(kStartDiscoveryFailed);
-  GetEventRouter(profile())->SetResponsibleForDiscovery(false);
+  GetEventRouter(GetProfile())->SetResponsibleForDiscovery(false);
   SendResponse(false);
-  GetEventRouter(profile())->OnListenerRemoved();
+  GetEventRouter(GetProfile())->OnListenerRemoved();
 }
 
 bool BluetoothStartDiscoveryFunction::DoWork(
     scoped_refptr<BluetoothAdapter> adapter) {
-  GetEventRouter(profile())->SetSendDiscoveryEvents(true);
+  GetEventRouter(GetProfile())->SetSendDiscoveryEvents(true);
 
   // If this profile is already discovering devices, there should be nothing
   // else to do.
-  if (!GetEventRouter(profile())->IsResponsibleForDiscovery()) {
-    GetEventRouter(profile())->SetResponsibleForDiscovery(true);
-    GetEventRouter(profile())->OnListenerAdded();
+  if (!GetEventRouter(GetProfile())->IsResponsibleForDiscovery()) {
+    GetEventRouter(GetProfile())->SetResponsibleForDiscovery(true);
+    GetEventRouter(GetProfile())->OnListenerAdded();
     adapter->StartDiscovering(
         base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this),
         base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this));
@@ -646,20 +647,20 @@
 
 void BluetoothStopDiscoveryFunction::OnSuccessCallback() {
   SendResponse(true);
-  GetEventRouter(profile())->OnListenerRemoved();
+  GetEventRouter(GetProfile())->OnListenerRemoved();
 }
 
 void BluetoothStopDiscoveryFunction::OnErrorCallback() {
   SetError(kStopDiscoveryFailed);
-  GetEventRouter(profile())->SetResponsibleForDiscovery(true);
+  GetEventRouter(GetProfile())->SetResponsibleForDiscovery(true);
   SendResponse(false);
-  GetEventRouter(profile())->OnListenerRemoved();
+  GetEventRouter(GetProfile())->OnListenerRemoved();
 }
 
 bool BluetoothStopDiscoveryFunction::DoWork(
     scoped_refptr<BluetoothAdapter> adapter) {
-  GetEventRouter(profile())->SetSendDiscoveryEvents(false);
-  if (GetEventRouter(profile())->IsResponsibleForDiscovery()) {
+  GetEventRouter(GetProfile())->SetSendDiscoveryEvents(false);
+  if (GetEventRouter(GetProfile())->IsResponsibleForDiscovery()) {
     adapter->StopDiscovering(
         base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback, this),
         base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback, this));
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.h b/chrome/browser/extensions/api/bluetooth/bluetooth_api.h
index f97cf95..01dbe00 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.h
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.h
@@ -57,7 +57,7 @@
 
 namespace api {
 
-class BluetoothAddProfileFunction : public AsyncExtensionFunction {
+class BluetoothAddProfileFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("bluetooth.addProfile", BLUETOOTH_ADDPROFILE)
 
@@ -77,7 +77,7 @@
   std::string uuid_;
 };
 
-class BluetoothRemoveProfileFunction : public SyncExtensionFunction {
+class BluetoothRemoveProfileFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("bluetooth.removeProfile",
                              BLUETOOTH_REMOVEPROFILE)
@@ -161,7 +161,7 @@
   void OnErrorCallback();
 };
 
-class BluetoothDisconnectFunction : public SyncExtensionFunction {
+class BluetoothDisconnectFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("bluetooth.disconnect", BLUETOOTH_DISCONNECT)
 
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.cc
index 3b6baa8..f3f6073 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.cc
@@ -43,12 +43,12 @@
 }
 
 bool BluetoothExtensionFunction::RunImpl() {
-  if (!IsBluetoothSupported(profile())) {
+  if (!IsBluetoothSupported(GetProfile())) {
     SetError(kPlatformNotSupported);
     return false;
   }
   GetAdapter(base::Bind(&BluetoothExtensionFunction::RunOnAdapterReady, this),
-             profile());
+             GetProfile());
 
   return true;
 }
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h b/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h
index d24f654..44812db 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace device {
 
@@ -22,7 +22,7 @@
 // Base class for bluetooth extension functions. This class initializes
 // bluetooth adapter and calls DoWork() implemented by individual bluetooth
 // extension functions.
-class BluetoothExtensionFunction : public AsyncExtensionFunction {
+class BluetoothExtensionFunction : public ChromeAsyncExtensionFunction {
  public:
   BluetoothExtensionFunction();
 
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index c77899b..6697a47 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -235,7 +235,7 @@
 
 bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut,
     const std::vector<std::string>& id_list) {
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   std::vector<const BookmarkNode*> nodes;
   EXTENSION_FUNCTION_VALIDATE(GetNodesFromVector(model, id_list, &nodes));
   bookmark_utils::CopyToClipboard(model, nodes, cut);
@@ -263,7 +263,7 @@
 
   scoped_ptr<Paste::Params> params(Paste::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
   if (!parent_node) {
     error_ = bookmark_keys::kNoParentError;
@@ -297,7 +297,7 @@
   scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
   if (!parent_node) {
     error_ = bookmark_keys::kNoParentError;
@@ -315,7 +315,7 @@
   scoped_ptr<SortChildren::Params> params(SortChildren::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
   if (!parent_node) {
     error_ = bookmark_keys::kNoParentError;
@@ -411,7 +411,7 @@
   scoped_ptr<StartDrag::Params> params(StartDrag::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   std::vector<const BookmarkNode*> nodes;
   EXTENSION_FUNCTION_VALIDATE(
       GetNodesFromVector(model, params->id_list, &nodes));
@@ -422,8 +422,8 @@
     WebContents* web_contents =
         dispatcher()->delegate()->GetAssociatedWebContents();
     CHECK(web_contents);
-    chrome::DragBookmarks(profile(), nodes,
-                          web_contents->GetView()->GetNativeView());
+    chrome::DragBookmarks(
+        GetProfile(), nodes, web_contents->GetView()->GetNativeView());
 
     return true;
   } else {
@@ -439,7 +439,7 @@
   scoped_ptr<Drop::Params> params(Drop::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
 
   const BookmarkNode* drop_parent = GetNodeFromString(model, params->parent_id);
   if (!drop_parent) {
@@ -471,7 +471,7 @@
       NOTREACHED() <<"Somehow we're dropping null bookmark data";
       return false;
     }
-    chrome::DropBookmarks(profile(), *drag_data, drop_parent, drop_index);
+    chrome::DropBookmarks(GetProfile(), *drag_data, drop_parent, drop_index);
 
     router->ClearBookmarkNodeData();
     return true;
@@ -485,7 +485,7 @@
   scoped_ptr<GetSubtree::Params> params(GetSubtree::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* node = NULL;
 
   if (params->id == "") {
@@ -514,7 +514,7 @@
 }
 
 bool BookmarkManagerPrivateCanEditFunction::RunImpl() {
-  PrefService* prefs = user_prefs::UserPrefs::Get(profile_);
+  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
   SetResult(new base::FundamentalValue(
       prefs->GetBoolean(prefs::kEditBookmarksEnabled)));
   return true;
@@ -541,7 +541,7 @@
   scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   int64 id;
   for (size_t i = 0; i < params->id_list.size(); ++i) {
     if (!base::StringToInt64(params->id_list[i], &id)) {
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
index 1737525..fef3468 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
@@ -8,7 +8,7 @@
 #include "base/values.h"
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 
 struct BookmarkNodeData;
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index d3b3af5..1afca6a 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -97,7 +97,7 @@
 }  // namespace
 
 void BookmarksFunction::Run() {
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   if (!model->loaded()) {
     // Bookmarks are not ready yet.  We'll wait.
     model->AddObserver(this);
@@ -125,7 +125,7 @@
 }
 
 bool BookmarksFunction::EditBookmarksEnabled() {
-  PrefService* prefs = user_prefs::UserPrefs::Get(profile_);
+  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
   if (prefs->GetBoolean(prefs::kEditBookmarksEnabled))
     return true;
   error_ = keys::kEditBookmarksDisabled;
@@ -326,7 +326,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   std::vector<linked_ptr<BookmarkTreeNode> > nodes;
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   if (params->id_or_id_list.as_strings) {
     std::vector<std::string>& ids = *params->id_or_id_list.as_strings;
     size_t count = ids.size();
@@ -370,7 +370,7 @@
 
   std::vector<linked_ptr<BookmarkTreeNode> > nodes;
   const BookmarkNode* node =
-      BookmarkModelFactory::GetForProfile(profile())->GetNodeByID(id);
+      BookmarkModelFactory::GetForProfile(GetProfile())->GetNodeByID(id);
   if (!node) {
     error_ = keys::kNoNodeError;
     return false;
@@ -394,7 +394,7 @@
 
   std::vector<const BookmarkNode*> nodes;
   bookmark_utils::GetMostRecentlyAddedEntries(
-      BookmarkModelFactory::GetForProfile(profile()),
+      BookmarkModelFactory::GetForProfile(GetProfile()),
       params->number_of_items,
       &nodes);
 
@@ -412,7 +412,7 @@
 bool BookmarksGetTreeFunction::RunImpl() {
   std::vector<linked_ptr<BookmarkTreeNode> > nodes;
   const BookmarkNode* node =
-      BookmarkModelFactory::GetForProfile(profile())->root_node();
+      BookmarkModelFactory::GetForProfile(GetProfile())->root_node();
   bookmark_api_helpers::AddNode(node, &nodes, true);
   results_ = bookmarks::GetTree::Results::Create(nodes);
   return true;
@@ -428,7 +428,7 @@
     return false;
 
   const BookmarkNode* node =
-      BookmarkModelFactory::GetForProfile(profile())->GetNodeByID(id);
+      BookmarkModelFactory::GetForProfile(GetProfile())->GetNodeByID(id);
   if (!node) {
     error_ = keys::kNoNodeError;
     return false;
@@ -445,11 +445,11 @@
       bookmarks::Search::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  PrefService* prefs = user_prefs::UserPrefs::Get(profile_);
+  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
   std::string lang = prefs->GetString(prefs::kAcceptLanguages);
   std::vector<const BookmarkNode*> nodes;
   bookmark_utils::GetBookmarksContainingText(
-      BookmarkModelFactory::GetForProfile(profile()),
+      BookmarkModelFactory::GetForProfile(GetProfile()),
       UTF8ToUTF16(params->query),
       std::numeric_limits<int>::max(),
       lang,
@@ -498,7 +498,7 @@
   if (name() == BookmarksRemoveTreeFunction::function_name())
     recursive = true;
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   if (!bookmark_api_helpers::RemoveNode(model, id, recursive, &error_))
     return false;
 
@@ -513,7 +513,7 @@
       bookmarks::Create::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   int64 parentId;
 
   if (!params->bookmark.parent_id.get()) {
@@ -598,7 +598,7 @@
     return false;
   }
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* node = model->GetNodeByID(id);
   if (!node) {
     error_ = keys::kNoNodeError;
@@ -672,7 +672,7 @@
     return false;
   }
 
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
 
   // Optional but we need to distinguish non present from an empty title.
   string16 title;
@@ -877,7 +877,7 @@
 // And finally, building the individual heuristics for each function.
 void BookmarksRemoveFunction::GetQuotaLimitHeuristics(
     QuotaLimitHeuristics* heuristics) const {
-  BookmarksQuotaLimitFactory::BuildForRemove(heuristics, profile());
+  BookmarksQuotaLimitFactory::BuildForRemove(heuristics, GetProfile());
 }
 
 void BookmarksMoveFunction::GetQuotaLimitHeuristics(
@@ -892,7 +892,7 @@
 
 void BookmarksCreateFunction::GetQuotaLimitHeuristics(
     QuotaLimitHeuristics* heuristics) const {
-  BookmarksQuotaLimitFactory::BuildForCreate(heuristics, profile());
+  BookmarksQuotaLimitFactory::BuildForCreate(heuristics, GetProfile());
 }
 
 BookmarksIOFunction::BookmarksIOFunction() {}
@@ -996,9 +996,9 @@
   source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
   source_profile.source_path = path;
   importer_host->StartImportSettings(source_profile,
-                                     profile(),
+                                     GetProfile(),
                                      importer::FAVORITES,
-                                     new ProfileWriter(profile()));
+                                     new ProfileWriter(GetProfile()));
 
   importer::LogImporterUseToMetrics("BookmarksAPI",
                                     importer::TYPE_BOOKMARKS_FILE);
@@ -1018,7 +1018,7 @@
   // Android does not have support for the standard exporter.
   // TODO(jgreenwald): remove ifdef once extensions are no longer built on
   // Android.
-  bookmark_html_writer::WriteBookmarks(profile(), path, NULL);
+  bookmark_html_writer::WriteBookmarks(GetProfile(), path, NULL);
 #endif
   Release();  // Balanced in BookmarksIOFunction::SelectFile()
 }
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
index 4e7c978..4d673c5 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
@@ -13,8 +13,8 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
 class Profile;
@@ -100,7 +100,7 @@
   scoped_ptr<BookmarkEventRouter> bookmark_event_router_;
 };
 
-class BookmarksFunction : public AsyncExtensionFunction,
+class BookmarksFunction : public ChromeAsyncExtensionFunction,
                           public BaseBookmarkModelObserver {
  public:
   // AsyncExtensionFunction:
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller.h b/chrome/browser/extensions/api/braille_display_private/braille_controller.h
index dd0e8bd..ed7954d 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller.h
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller.h
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #ifndef CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_BRAILLE_CONTROLLER_H_
-
 #define CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_BRAILLE_CONTROLLER_H_
 
 #include <string>
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
index 0fe8566..0e70c5d 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
@@ -110,10 +110,12 @@
 
 void BrailleControllerImpl::AddObserver(BrailleObserver* observer) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                          base::Bind(
-                              &BrailleControllerImpl::StartConnecting,
-                              base::Unretained(this)));
+  if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                               base::Bind(
+                                   &BrailleControllerImpl::StartConnecting,
+                                   base::Unretained(this)))) {
+    NOTREACHED();
+  }
   observers_.AddObserver(observer);
 }
 
@@ -334,11 +336,13 @@
 void BrailleControllerImpl::DispatchOnDisplayStateChanged(
     scoped_ptr<DisplayState> new_state) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&BrailleControllerImpl::DispatchOnDisplayStateChanged,
-                   base::Unretained(this),
-                   base::Passed(&new_state)));
+    if (!BrowserThread::PostTask(
+            BrowserThread::UI, FROM_HERE,
+            base::Bind(&BrailleControllerImpl::DispatchOnDisplayStateChanged,
+                       base::Unretained(this),
+                       base::Passed(&new_state)))) {
+      NOTREACHED();
+    }
     return;
   }
   FOR_EACH_OBSERVER(BrailleObserver, observers_,
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 f74bf2e..06f6d42 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
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/login/screen_locker.h"
 #include "chrome/browser/chromeos/login/screen_locker_tester.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
@@ -17,6 +18,7 @@
 #include "chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h"
 #include "chrome/browser/extensions/api/braille_display_private/braille_display_private_api.h"
 #include "chrome/browser/extensions/api/braille_display_private/brlapi_connection.h"
+#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/test/base/testing_profile.h"
@@ -151,16 +153,27 @@
         base::Bind(
             &BrailleDisplayPrivateApiTest::CreateBrlapiConnection,
             base::Unretained(this)));
+    DisableAccessibilityManagerBraille();
   }
 
  protected:
   MockBrlapiConnectionData connection_data_;
 
+  // By default, don't let the accessibility manager interfere and
+  // steal events.  Some tests override this to keep the normal behaviour
+  // of the accessibility manager.
+  virtual void DisableAccessibilityManagerBraille() {
+    chromeos::AccessibilityManager::SetBrailleControllerForTest(
+        &stub_braille_controller_);
+  }
+
  private:
   scoped_ptr<BrlapiConnection> CreateBrlapiConnection() {
     return scoped_ptr<BrlapiConnection>(
         new MockBrlapiConnection(&connection_data_));
   }
+
+  StubBrailleController stub_braille_controller_;
 };
 
 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, WriteDots) {
@@ -245,6 +258,11 @@
       lock_state_observer.Wait();
     ASSERT_FALSE(tester->IsLocked());
   }
+
+ protected:
+  virtual void DisableAccessibilityManagerBraille() OVERRIDE {
+    // Let the accessibility manager behave as usual for these tests.
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest,
diff --git a/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc b/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc
new file mode 100644
index 0000000..8e9f312
--- /dev/null
+++ b/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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/extensions/api/braille_display_private/stub_braille_controller.h"
+
+namespace extensions {
+namespace api {
+namespace braille_display_private {
+
+StubBrailleController::StubBrailleController() {
+}
+
+scoped_ptr<DisplayState> StubBrailleController::GetDisplayState() {
+  return scoped_ptr<DisplayState>(new DisplayState);
+}
+
+void StubBrailleController::WriteDots(const std::string& cells) {
+}
+
+void StubBrailleController::AddObserver(BrailleObserver* observer) {
+}
+
+void StubBrailleController::RemoveObserver(BrailleObserver* observer) {
+}
+
+}  // namespace braille_display_private
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h b/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h
new file mode 100644
index 0000000..c90726e
--- /dev/null
+++ b/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h
@@ -0,0 +1,28 @@
+// Copyright 2013 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_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_STUB_BRAILLE_CONTROLLER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_STUB_BRAILLE_CONTROLLER_H_
+
+#include "chrome/browser/extensions/api/braille_display_private/braille_controller.h"
+
+namespace extensions {
+namespace api {
+namespace braille_display_private {
+
+// Stub implementation for the BrailleController interface.
+class StubBrailleController : public BrailleController {
+ public:
+  StubBrailleController();
+  virtual scoped_ptr<DisplayState> GetDisplayState() OVERRIDE;
+  virtual void WriteDots(const std::string& cells) OVERRIDE;
+  virtual void AddObserver(BrailleObserver* observer) OVERRIDE;
+  virtual void RemoveObserver(BrailleObserver* observer) OVERRIDE;
+};
+
+}  // namespace braille_display_private
+}  // namespace api
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_STUB_BRAILLE_CONTROLLER_H_
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
index b9a32c4..7078525 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -114,7 +114,7 @@
 
 
 bool BrowsingDataSettingsFunction::RunImpl() {
-  PrefService* prefs = profile()->GetPrefs();
+  PrefService* prefs = GetProfile()->GetPrefs();
 
   // Fill origin types.
   // The "cookies" and "hosted apps" UI checkboxes both map to
@@ -211,8 +211,8 @@
     base::DictionaryValue* permitted_dict,
     const char* data_type,
     bool is_selected) {
-  bool is_permitted = IsRemovalPermitted(MaskForKey(data_type),
-                                         profile()->GetPrefs());
+  bool is_permitted =
+      IsRemovalPermitted(MaskForKey(data_type), GetProfile()->GetPrefs());
   selected_dict->SetBoolean(data_type, is_selected && is_permitted);
   permitted_dict->SetBoolean(data_type, is_permitted);
 }
@@ -226,7 +226,7 @@
 
 bool BrowsingDataRemoverFunction::RunImpl() {
   // If we don't have a profile, something's pretty wrong.
-  DCHECK(profile());
+  DCHECK(GetProfile());
 
   // Grab the initial |options| parameter, and parse out the arguments.
   base::DictionaryValue* options;
@@ -254,7 +254,7 @@
     return false;
 
   // Check for prohibited data types.
-  if (!IsRemovalPermitted(removal_mask_, profile()->GetPrefs())) {
+  if (!IsRemovalPermitted(removal_mask_, GetProfile()->GetPrefs())) {
     error_ = extension_browsing_data_api_constants::kDeleteProhibitedError;
     return false;
   }
@@ -263,11 +263,12 @@
     // If we're being asked to remove plugin data, check whether it's actually
     // supported.
     BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
+        BrowserThread::FILE,
+        FROM_HERE,
         base::Bind(
             &BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported,
             this,
-            PluginPrefs::GetForProfile(profile())));
+            PluginPrefs::GetForProfile(GetProfile())));
   } else {
     StartRemoving();
   }
@@ -300,8 +301,8 @@
   // that we're notified after removal) and call remove() with the arguments
   // we've generated above. We can use a raw pointer here, as the browsing data
   // remover is responsible for deleting itself once data removal is complete.
-  BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(profile(),
-      remove_since_, base::Time::Max());
+  BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(
+      GetProfile(), remove_since_, base::Time::Max());
   remover->AddObserver(this);
   remover->Remove(removal_mask_, origin_set_mask_);
 }
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
index 1078ec2..4e1b7ce 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
@@ -12,7 +12,7 @@
 #include <string>
 
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class PluginPrefs;
 
@@ -51,8 +51,7 @@
 
 }  // namespace extension_browsing_data_api_constants
 
-
-class BrowsingDataSettingsFunction : public SyncExtensionFunction {
+class BrowsingDataSettingsFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("browsingData.settings", BROWSINGDATA_SETTINGS)
 
@@ -80,8 +79,8 @@
 //
 // Each child class must implement GetRemovalMask(), which returns the bitmask
 // of data types to remove.
-class BrowsingDataRemoverFunction : public AsyncExtensionFunction,
-                                   public BrowsingDataRemover::Observer {
+class BrowsingDataRemoverFunction : public ChromeAsyncExtensionFunction,
+                                    public BrowsingDataRemover::Observer {
  public:
   // BrowsingDataRemover::Observer interface method.
   virtual void OnBrowsingDataRemoverDone() OVERRIDE;
diff --git a/chrome/browser/extensions/api/cast_channel/cast_auth_util.h b/chrome/browser/extensions/api/cast_channel/cast_auth_util.h
new file mode 100644
index 0000000..c3d5da6
--- /dev/null
+++ b/chrome/browser/extensions/api/cast_channel/cast_auth_util.h
@@ -0,0 +1,26 @@
+// Copyright 2013 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_EXTENSIONS_API_CAST_CHANNEL_CAST_AUTH_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_API_CAST_CHANNEL_CAST_AUTH_UTIL_H_
+
+#include <string>
+
+namespace extensions {
+namespace api {
+namespace cast_channel {
+
+class CastMessage;
+
+// Authenticates the given |challenge_reply|:
+// 1. Signature contained in the reply is valid.
+// 2. Certficate used to sign is rooted to a trusted CA.
+bool AuthenticateChallengeReply(const CastMessage& challenge_reply,
+                                const std::string& peer_cert);
+
+}  // namespace cast_channel
+}  // namespace api
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_CAST_CHANNEL_CAST_AUTH_UTIL_H_
diff --git a/chrome/browser/extensions/api/cast_channel/cast_auth_util_nss.cc b/chrome/browser/extensions/api/cast_channel/cast_auth_util_nss.cc
new file mode 100644
index 0000000..fad5758
--- /dev/null
+++ b/chrome/browser/extensions/api/cast_channel/cast_auth_util_nss.cc
@@ -0,0 +1,167 @@
+// Copyright 2013 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/extensions/api/cast_channel/cast_auth_util.h"
+
+#include <cert.h>
+#include <cryptohi.h>
+#include <pk11pub.h>
+#include <seccomon.h>
+#include <string>
+
+#include "base/logging.h"
+#include "chrome/browser/extensions/api/cast_channel/cast_channel.pb.h"
+#include "chrome/browser/extensions/api/cast_channel/cast_message_util.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace {
+
+// Public key of the certificate with which the peer cert should be signed.
+static const unsigned char kCAPublicKeyDER[] = {
+    0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbc, 0x22, 0x80,
+    0xbd, 0x80, 0xf6, 0x3a, 0x21, 0x00, 0x3b, 0xae, 0x76, 0x5e, 0x35, 0x7f,
+    0x3d, 0xc3, 0x64, 0x5c, 0x55, 0x94, 0x86, 0x34, 0x2f, 0x05, 0x87, 0x28,
+    0xcd, 0xf7, 0x69, 0x8c, 0x17, 0xb3, 0x50, 0xa7, 0xb8, 0x82, 0xfa, 0xdf,
+    0xc7, 0x43, 0x2d, 0xd6, 0x7e, 0xab, 0xa0, 0x6f, 0xb7, 0x13, 0x72, 0x80,
+    0xa4, 0x47, 0x15, 0xc1, 0x20, 0x99, 0x50, 0xcd, 0xec, 0x14, 0x62, 0x09,
+    0x5b, 0xa4, 0x98, 0xcd, 0xd2, 0x41, 0xb6, 0x36, 0x4e, 0xff, 0xe8, 0x2e,
+    0x32, 0x30, 0x4a, 0x81, 0xa8, 0x42, 0xa3, 0x6c, 0x9b, 0x33, 0x6e, 0xca,
+    0xb2, 0xf5, 0x53, 0x66, 0xe0, 0x27, 0x53, 0x86, 0x1a, 0x85, 0x1e, 0xa7,
+    0x39, 0x3f, 0x4a, 0x77, 0x8e, 0xfb, 0x54, 0x66, 0x66, 0xfb, 0x58, 0x54,
+    0xc0, 0x5e, 0x39, 0xc7, 0xf5, 0x50, 0x06, 0x0b, 0xe0, 0x8a, 0xd4, 0xce,
+    0xe1, 0x6a, 0x55, 0x1f, 0x8b, 0x17, 0x00, 0xe6, 0x69, 0xa3, 0x27, 0xe6,
+    0x08, 0x25, 0x69, 0x3c, 0x12, 0x9d, 0x8d, 0x05, 0x2c, 0xd6, 0x2e, 0xa2,
+    0x31, 0xde, 0xb4, 0x52, 0x50, 0xd6, 0x20, 0x49, 0xde, 0x71, 0xa0, 0xf9,
+    0xad, 0x20, 0x40, 0x12, 0xf1, 0xdd, 0x25, 0xeb, 0xd5, 0xe6, 0xb8, 0x36,
+    0xf4, 0xd6, 0x8f, 0x7f, 0xca, 0x43, 0xdc, 0xd7, 0x10, 0x5b, 0xe6, 0x3f,
+    0x51, 0x8a, 0x85, 0xb3, 0xf3, 0xff, 0xf6, 0x03, 0x2d, 0xcb, 0x23, 0x4f,
+    0x9c, 0xad, 0x18, 0xe7, 0x93, 0x05, 0x8c, 0xac, 0x52, 0x9a, 0xf7, 0x4c,
+    0xe9, 0x99, 0x7a, 0xbe, 0x6e, 0x7e, 0x4d, 0x0a, 0xe3, 0xc6, 0x1c, 0xa9,
+    0x93, 0xfa, 0x3a, 0xa5, 0x91, 0x5d, 0x1c, 0xbd, 0x66, 0xeb, 0xcc, 0x60,
+    0xdc, 0x86, 0x74, 0xca, 0xcf, 0xf8, 0x92, 0x1c, 0x98, 0x7d, 0x57, 0xfa,
+    0x61, 0x47, 0x9e, 0xab, 0x80, 0xb7, 0xe4, 0x48, 0x80, 0x2a, 0x92, 0xc5,
+    0x1b, 0x02, 0x03, 0x01, 0x00, 0x01 };
+
+typedef scoped_ptr_malloc<
+    CERTCertificate,
+    crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> >
+ScopedCERTCertificate;
+
+// Parses out DeviceAuthMessage from CastMessage
+static bool ParseAuthMessage(
+    const extensions::api::cast_channel::CastMessage& challenge_reply,
+    extensions::api::cast_channel::DeviceAuthMessage* auth_message) {
+  if (challenge_reply.payload_type() !=
+      extensions::api::cast_channel::CastMessage_PayloadType_BINARY) {
+    DVLOG(1) << "Wrong payload type in challenge reply";
+    return false;
+  }
+  if (!challenge_reply.has_payload_binary()) {
+    DVLOG(1) << "Payload type is binary but payload_binary field not set";
+    return false;
+  }
+  if (!auth_message->ParseFromString(challenge_reply.payload_binary())) {
+    DVLOG(1) << "Cannot parse binary payload into DeviceAuthMessage";
+    return false;
+  }
+  DVLOG(1) << "Auth message: " << AuthMessageToString(*auth_message);
+  if (auth_message->has_error()) {
+    DVLOG(1) << "Auth message error: " << auth_message->error().error_type();
+    return false;
+  }
+  if (!auth_message->has_response()) {
+    DVLOG(1) << "Auth message has no response field";
+    return false;
+  }
+  return true;
+}
+
+// Authenticates the given credentials:
+// 1. |signature| verification of |data| using |certificate|.
+// 2. |certificate| is signed by a trusted CA.
+bool VerifyCredentials(const std::string& certificate,
+                       const std::string& signature,
+                       const std::string& data) {
+  crypto::EnsureNSSInit();
+  SECItem der_cert;
+  der_cert.type = siDERCertBuffer;
+  // Make a copy of certificate string so it is safe to type cast.
+  der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(
+      certificate.data()));
+  der_cert.len = certificate.length();
+
+  // Parse into a certificate structure.
+  ScopedCERTCertificate cert(CERT_NewTempCertificate(
+      CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
+  if (!cert.get()) {
+     DVLOG(1) << "Failed to parse certificate.";
+     return false;
+  }
+
+  // Check that the certificate is signed by trusted CA.
+  SECItem trusted_ca_key_der_item;
+  trusted_ca_key_der_item.type = siDERCertBuffer;
+  trusted_ca_key_der_item.data = const_cast<unsigned char*>(kCAPublicKeyDER);
+  trusted_ca_key_der_item.len = sizeof(kCAPublicKeyDER);
+  crypto::ScopedSECKEYPublicKey ca_public_key(
+      SECKEY_ImportDERPublicKey(&trusted_ca_key_der_item, CKK_RSA));
+  SECStatus verified = CERT_VerifySignedDataWithPublicKey(
+      &cert->signatureWrap, ca_public_key.get(), NULL);
+  if (verified != SECSuccess) {
+    DVLOG(1)<< "Cert not signed by trusted CA";
+    return false;
+  }
+
+  // Verify that the |signature| matches |data|.
+  crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get()));
+  if (!public_key.get()) {
+    DVLOG(1) << "Unable to extract public key from certificate.";
+    return false;
+  }
+  SECItem signature_item;
+  signature_item.type = siBuffer;
+  signature_item.data = reinterpret_cast<unsigned char*>(
+      const_cast<char*>(signature.data()));
+  signature_item.len = signature.length();
+  verified = VFY_VerifyDataDirect(
+      reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
+      data.size(),
+      public_key.get(),
+      &signature_item,
+      SEC_OID_PKCS1_RSA_ENCRYPTION,
+      SEC_OID_SHA1, NULL, NULL);
+
+  if (verified != SECSuccess) {
+    DVLOG(1) << "Signed blobs did not match.";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+namespace extensions {
+namespace api {
+namespace cast_channel {
+
+bool AuthenticateChallengeReply(const CastMessage& challenge_reply,
+                                const std::string& peer_cert) {
+  if (peer_cert.empty())
+    return false;
+
+  DVLOG(1) << "Challenge reply: " << CastMessageToString(challenge_reply);
+  DeviceAuthMessage auth_message;
+  if (!ParseAuthMessage(challenge_reply, &auth_message))
+    return false;
+
+  const AuthResponse& response = auth_message.response();
+  return VerifyCredentials(response.client_auth_certificate(),
+                           response.signature(),
+                           peer_cert);
+}
+
+}  // namespace cast_channel
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/cast_channel/cast_auth_util_openssl.cc b/chrome/browser/extensions/api/cast_channel/cast_auth_util_openssl.cc
new file mode 100644
index 0000000..18bc330
--- /dev/null
+++ b/chrome/browser/extensions/api/cast_channel/cast_auth_util_openssl.cc
@@ -0,0 +1,21 @@
+// Copyright 2013 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/extensions/api/cast_channel/cast_auth_util.h"
+
+#include "base/logging.h"
+
+namespace extensions {
+namespace api {
+namespace cast_channel {
+
+bool AuthenticateChallengeReply(const CastMessage& challenge_reply,
+                                const std::string& peer_cert) {
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace cast_channel
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/cast_channel/cast_channel.proto b/chrome/browser/extensions/api/cast_channel/cast_channel.proto
index 969a881..d321eaf 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_channel.proto
+++ b/chrome/browser/extensions/api/cast_channel/cast_channel.proto
@@ -53,3 +53,27 @@
   optional bytes payload_binary = 7;
 }
 
+// Messages for authentication protocol between a sender and a receiver.
+message AuthChallenge {
+}
+
+message AuthResponse {
+  required bytes signature = 1;
+  required bytes client_auth_certificate = 2;
+}
+
+message AuthError {
+  enum ErrorType {
+    INTERNAL_ERROR = 0;
+    NO_TLS = 1;  // The underlying connection is not TLS
+  }
+  required ErrorType error_type = 1;
+}
+
+message DeviceAuthMessage {
+  // Request fields
+  optional AuthChallenge challenge = 1;
+  // Response fields
+  optional AuthResponse response = 2;
+  optional AuthError error = 3;
+}
diff --git a/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc b/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
index 8a5db58..7362ab6 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
@@ -100,7 +100,7 @@
 CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
 
 bool CastChannelAsyncApiFunction::PrePrepare() {
-  manager_ = ApiResourceManager<CastSocket>::Get(profile());
+  manager_ = ApiResourceManager<CastSocket>::Get(GetProfile());
   return true;
 }
 
@@ -168,7 +168,7 @@
 CastChannelOpenFunction::~CastChannelOpenFunction() { }
 
 bool CastChannelOpenFunction::PrePrepare() {
-  api_ = CastChannelAPI::Get(profile());
+  api_ = CastChannelAPI::Get(GetProfile());
   return CastChannelAsyncApiFunction::PrePrepare();
 }
 
@@ -182,8 +182,8 @@
   DCHECK(api_);
   CastSocket* socket = new CastSocket(extension_->id(), GURL(params_->url),
                                       api_, g_browser_process->net_log());
-  int new_channel_id = AddSocket(socket);
-  socket->set_id(new_channel_id);
+  new_channel_id_ = AddSocket(socket);
+  socket->set_id(new_channel_id_);
   socket->Connect(base::Bind(&CastChannelOpenFunction::OnOpen, this));
 }
 
diff --git a/chrome/browser/extensions/api/cast_channel/cast_message_util.cc b/chrome/browser/extensions/api/cast_channel/cast_message_util.cc
index 14a02b8..892a9f5 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_message_util.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_message_util.cc
@@ -11,6 +11,14 @@
 #include "chrome/browser/extensions/api/cast_channel/cast_channel.pb.h"
 #include "chrome/common/extensions/api/cast_channel.h"
 
+namespace {
+static const char kAuthNamespace[] =
+    "urn:x-cast:com.google.cast.tp.deviceauth";
+// Sender and receiver IDs to use for platform messages.
+static const char kPlatformSenderId[] = "sender-0";
+static const char kPlatformReceiverId[] = "receiver-0";
+}  // namespace
+
 namespace extensions {
 namespace api {
 namespace cast_channel {
@@ -83,7 +91,7 @@
   }
 }
 
-const std::string MessageProtoToString(const CastMessage& message_proto) {
+std::string CastMessageToString(const CastMessage& message_proto) {
   std::string out("{");
   out += "namespace = " + message_proto.namespace_();
   out += ", sourceId = " + message_proto.source_id();
@@ -93,6 +101,46 @@
   return out;
 }
 
+std::string AuthMessageToString(const DeviceAuthMessage& message) {
+  std::string out("{");
+  if (message.has_challenge()) {
+    out += "\n  challenge = {},";
+  }
+  if (message.has_response()) {
+    out += "\n  response = {";
+    out += "\n    signature = " + message.response().signature();
+    out += "\n,   certificate = " +
+        message.response().client_auth_certificate();
+    out += "\n  }";
+  }
+  if (message.has_error()) {
+    out += "\n  error = {";
+    out += base::IntToString(message.error().error_type());
+    out += "}";
+  }
+  out += "}";
+  return out;
+}
+
+void CreateAuthChallengeMessage(CastMessage* message_proto) {
+  CHECK(message_proto);
+  DeviceAuthMessage auth_message;
+  auth_message.mutable_challenge();
+  std::string auth_message_string;
+  auth_message.SerializeToString(&auth_message_string);
+
+  message_proto->set_protocol_version(CastMessage_ProtocolVersion_CASTV2_1_0);
+  message_proto->set_source_id(kPlatformSenderId);
+  message_proto->set_destination_id(kPlatformReceiverId);
+  message_proto->set_namespace_(kAuthNamespace);
+  message_proto->set_payload_type(CastMessage_PayloadType_BINARY);
+  message_proto->set_payload_binary(auth_message_string);
+}
+
+bool IsAuthMessage(const CastMessage& message) {
+  return message.namespace_() == kAuthNamespace;
+}
+
 }  // namespace cast_channel
 }  // namespace api
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/cast_channel/cast_message_util.h b/chrome/browser/extensions/api/cast_channel/cast_message_util.h
index 6c1d55d..e270d82 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_message_util.h
+++ b/chrome/browser/extensions/api/cast_channel/cast_message_util.h
@@ -12,6 +12,7 @@
 namespace cast_channel {
 
 class CastMessage;
+class DeviceAuthMessage;
 struct MessageInfo;
 
 // Fills |message_proto| from |message| and returns true on success.
@@ -23,7 +24,16 @@
                               MessageInfo* message);
 
 // Returns a human readable string for |message_proto|.
-const std::string MessageProtoToString(const CastMessage& message_proto);
+std::string CastMessageToString(const CastMessage& message_proto);
+
+// Returns a human readable string for |message|.
+std::string AuthMessageToString(const DeviceAuthMessage& message);
+
+// Fills |message_proto| appropriately for an auth challenge request message.
+void CreateAuthChallengeMessage(CastMessage* message_proto);
+
+// Returns whether the given message is an auth handshake message.
+bool IsAuthMessage(const CastMessage& message);
 
 }  // namespace cast_channel
 }  // namespace api
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket.cc b/chrome/browser/extensions/api/cast_channel/cast_socket.cc
index e384587..630c72d 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket.cc
@@ -11,6 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
+#include "chrome/browser/extensions/api/cast_channel/cast_auth_util.h"
 #include "chrome/browser/extensions/api/cast_channel/cast_channel.pb.h"
 #include "chrome/browser/extensions/api/cast_channel/cast_message_util.h"
 #include "net/base/address_list.h"
@@ -65,13 +66,14 @@
 const uint32 kMaxMessageSize = 65536;
 
 CastSocket::CastSocket(const std::string& owner_extension_id,
-                       const GURL& url, CastSocket::Delegate* delegate,
+                       const GURL& url,
+                       CastSocket::Delegate* delegate,
                        net::NetLog* net_log) :
     ApiResource(owner_extension_id),
     channel_id_(0),
     url_(url),
     delegate_(delegate),
-    is_secure_(false),
+    auth_required_(false),
     error_state_(CHANNEL_ERROR_NONE),
     ready_state_(READY_STATE_NONE),
     write_callback_pending_(false),
@@ -97,18 +99,6 @@
   return url_;
 }
 
-bool CastSocket::ExtractPeerCert(std::string* cert) {
-  CHECK(peer_cert_.empty());
-  net::SSLInfo ssl_info;
-  if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get())
-    return false;
-  bool result = net::X509Certificate::GetDEREncoded(
-     ssl_info.cert->os_cert_handle(), cert);
-  if (result)
-    DVLOG(1) << "Successfully extracted peer certificate: " << *cert;
-  return result;
-}
-
 scoped_ptr<net::TCPClientSocket> CastSocket::CreateTcpSocket() {
   net::AddressList addresses(ip_endpoint_);
   scoped_ptr<net::TCPClientSocket> tcp_socket(
@@ -146,12 +136,45 @@
       connection.Pass(), host_and_port, ssl_config, context);
 }
 
+bool CastSocket::ExtractPeerCert(std::string* cert) {
+  DCHECK(cert);
+  DCHECK(peer_cert_.empty());
+  net::SSLInfo ssl_info;
+  if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get())
+    return false;
+  bool result = net::X509Certificate::GetDEREncoded(
+     ssl_info.cert->os_cert_handle(), cert);
+  if (result)
+    DVLOG(1) << "Successfully extracted peer certificate: " << *cert;
+  return result;
+}
+
+int CastSocket::SendAuthChallenge() {
+  CastMessage challenge_message;
+  CreateAuthChallengeMessage(&challenge_message);
+  DVLOG(1) << "Sending challenge: " << CastMessageToString(challenge_message);
+  return SendMessageInternal(
+      challenge_message,
+      base::Bind(&CastSocket::OnChallengeEvent, AsWeakPtr()));
+}
+
+int CastSocket::ReadAuthChallengeReply() {
+  return ReadData();
+}
+
 void CastSocket::OnConnectComplete(int result) {
   int rv = DoConnectLoop(result);
   if (rv != net::ERR_IO_PENDING)
     DoConnectCallback(rv);
 }
 
+void CastSocket::OnChallengeEvent(int result) {
+  // result >= 0 means read or write succeeded synchronously.
+  int rv = DoConnectLoop(result >= 0 ? net::OK : result);
+  if (rv != net::ERR_IO_PENDING)
+    DoConnectCallback(rv);
+}
+
 void CastSocket::Connect(const net::CompletionCallback& callback) {
   DCHECK(CalledOnValidThread());
   int result = net::ERR_CONNECTION_FAILED;
@@ -162,7 +185,6 @@
   }
   if (!ParseChannelUrl(url_)) {
     CloseWithError(cast_channel::CHANNEL_ERROR_CONNECT_ERROR);
-    // TODO(mfoltz): Signal channel errors via |callback|
     callback.Run(result);
     return;
   }
@@ -205,6 +227,16 @@
       case CONN_STATE_SSL_CONNECT_COMPLETE:
         rv = DoSslConnectComplete(rv);
         break;
+      case CONN_STATE_AUTH_CHALLENGE_SEND:
+        rv = DoAuthChallengeSend();
+        break;
+      case CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE:
+        rv = DoAuthChallengeSendComplete(rv);
+        break;
+      case CONN_STATE_AUTH_CHALLENGE_REPLY_COMPLETE:
+        rv = DoAuthChallengeReplyComplete(rv);
+        break;
+
       default:
         NOTREACHED() << "BUG in CastSocket state machine code";
         break;
@@ -218,6 +250,7 @@
 }
 
 int CastSocket::DoTcpConnect() {
+  DVLOG(1) << "DoTcpConnect";
   next_state_ = CONN_STATE_TCP_CONNECT_COMPLETE;
   tcp_socket_ = CreateTcpSocket();
   return tcp_socket_->Connect(
@@ -225,12 +258,14 @@
 }
 
 int CastSocket::DoTcpConnectComplete(int result) {
+  DVLOG(1) << "DoTcpConnectComplete: " << result;
   if (result == net::OK)
     next_state_ = CONN_STATE_SSL_CONNECT;
   return result;
 }
 
 int CastSocket::DoSslConnect() {
+  DVLOG(1) << "DoSslConnect";
   next_state_ = CONN_STATE_SSL_CONNECT_COMPLETE;
   socket_ = CreateSslSocket();
   return socket_->Connect(
@@ -238,21 +273,54 @@
 }
 
 int CastSocket::DoSslConnectComplete(int result) {
-  // TODO(mfoltz,munjal): Authenticate the channel if is_secure_ == true.
+  DVLOG(1) << "DoSslConnectComplete: " << result;
   if (result == net::ERR_CERT_AUTHORITY_INVALID &&
              peer_cert_.empty() &&
              ExtractPeerCert(&peer_cert_)) {
     next_state_ = CONN_STATE_TCP_CONNECT;
+  } else if (result == net::OK && auth_required_) {
+    next_state_ = CONN_STATE_AUTH_CHALLENGE_SEND;
   }
   return result;
 }
 
+int CastSocket::DoAuthChallengeSend() {
+  DVLOG(1) << "DoAuthChallengeSend";
+  next_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE;
+  return SendAuthChallenge();
+}
+
+int CastSocket::DoAuthChallengeSendComplete(int result) {
+  DVLOG(1) << "DoAuthChallengeSendComplete: " << result;
+  if (result != net::OK)
+    return result;
+  next_state_ = CONN_STATE_AUTH_CHALLENGE_REPLY_COMPLETE;
+  return ReadAuthChallengeReply();
+}
+
+int CastSocket::DoAuthChallengeReplyComplete(int result) {
+  DVLOG(1) << "DoAuthChallengeReplyComplete: " << result;
+  if (result != net::OK)
+    return result;
+  if (!VerifyChallengeReply())
+    return net::ERR_FAILED;
+  DVLOG(1) << "Auth challenge verification succeeded";
+  return net::OK;
+}
+
+bool CastSocket::VerifyChallengeReply() {
+  return AuthenticateChallengeReply(*challenge_reply_.get(), peer_cert_);
+}
+
 void CastSocket::DoConnectCallback(int result) {
   ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED;
   error_state_ = (result == net::OK) ?
       CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR;
   base::ResetAndReturn(&connect_callback_).Run(result);
-  if (result == net::OK)
+  // Start the ReadData loop if not already started.
+  // If auth_required_ is true we would've started a ReadData loop already.
+  // TODO(munjal): This is a bit ugly. Refactor read and write code.
+  if (result == net::OK && !auth_required_)
     ReadData();
 }
 
@@ -276,31 +344,33 @@
     callback.Run(result);
     return;
   }
-  WriteRequest write_request(callback);
   CastMessage message_proto;
-  if (!MessageInfoToCastMessage(message, &message_proto) ||
-      !write_request.SetContent(message_proto)) {
+  if (!MessageInfoToCastMessage(message, &message_proto)) {
     CloseWithError(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE);
     // TODO(mfoltz): Do a better job of signaling cast_channel errors to the
     // caller.
     callback.Run(net::OK);
     return;
   }
-  write_queue_.push(write_request);
-  WriteData();
+  SendMessageInternal(message_proto, callback);
 }
 
-void CastSocket::WriteData() {
+int CastSocket::SendMessageInternal(const CastMessage& message_proto,
+                                     const net::CompletionCallback& callback) {
+  WriteRequest write_request(callback);
+  if (!write_request.SetContent(message_proto))
+    return net::ERR_FAILED;
+  write_queue_.push(write_request);
+  return WriteData();
+}
+
+int CastSocket::WriteData() {
   DCHECK(CalledOnValidThread());
   DVLOG(1) << "WriteData q = " << write_queue_.size();
   if (write_queue_.empty() || write_callback_pending_)
-    return;
+    return net::ERR_FAILED;
 
   WriteRequest& request = write_queue_.front();
-  if (ready_state_ != READY_STATE_OPEN) {
-    request.callback.Run(net::ERR_FAILED);
-    return;
-  }
 
   DVLOG(1) << "WriteData byte_count = " << request.io_buffer->size() <<
     " bytes_written " << request.io_buffer->BytesConsumed();
@@ -311,10 +381,10 @@
       request.io_buffer->BytesRemaining(),
       base::Bind(&CastSocket::OnWriteData, AsWeakPtr()));
 
-  DVLOG(1) << "WriteData result = " << result;
-
   if (result != net::ERR_IO_PENDING)
     OnWriteData(result);
+
+  return result;
 }
 
 void CastSocket::OnWriteData(int result) {
@@ -358,11 +428,10 @@
     WriteData();
 }
 
-void CastSocket::ReadData() {
+int CastSocket::ReadData() {
   DCHECK(CalledOnValidThread());
-  if (!socket_.get() || ready_state_ != READY_STATE_OPEN) {
-    return;
-  }
+  if (!socket_.get())
+    return net::ERR_FAILED;
   DCHECK(!read_callback_pending_);
   read_callback_pending_ = true;
   // Figure out if we are reading the header or body, and the remaining bytes.
@@ -389,13 +458,14 @@
   } else if (result != net::ERR_IO_PENDING) {
     CloseWithError(CHANNEL_ERROR_SOCKET_ERROR);
   }
+  return result;
 }
 
 void CastSocket::OnReadData(int result) {
   DCHECK(CalledOnValidThread());
-  DVLOG(1) << "OnReadData result = " << result <<
-    " header offset = " << header_read_buffer_->offset() <<
-    " body offset = " << body_read_buffer_->offset();
+  DVLOG(1) << "OnReadData result = " << result
+           << " header offset = " << header_read_buffer_->offset()
+           << " body offset = " << body_read_buffer_->offset();
   read_callback_pending_ = false;
   if (result <= 0) {
     CloseWithError(CHANNEL_ERROR_SOCKET_ERROR);
@@ -458,8 +528,12 @@
       body_read_buffer_->StartOfBuffer(),
       current_message_size_))
     return false;
-  DVLOG(1) << "Parsed message " << MessageProtoToString(message_proto);
-  if (delegate_) {
+  DVLOG(1) << "Parsed message " << CastMessageToString(message_proto);
+  // If the message is an auth message then we handle it internally.
+  if (IsAuthMessage(message_proto)) {
+    challenge_reply_.reset(new CastMessage(message_proto));
+    OnChallengeEvent(net::OK);
+  } else if (delegate_) {
     MessageInfo message;
     if (!CastMessageToMessageInfo(message_proto, &message))
       return false;
@@ -496,9 +570,9 @@
 bool CastSocket::ParseChannelUrl(const GURL& url) {
   DVLOG(1) << "url = " + url.spec();
   if (url.SchemeIs(kCastInsecureScheme)) {
-    is_secure_ = false;
+    auth_required_ = false;
   } else if (url.SchemeIs(kCastSecureScheme)) {
-    is_secure_ = true;
+    auth_required_ = true;
   } else {
     return false;
   }
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket.h b/chrome/browser/extensions/api/cast_channel/cast_socket.h
index e9c5a82..1a5b93f 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket.h
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket.h
@@ -75,8 +75,8 @@
   // The URL for the channel.
   const GURL& url() const;
 
-  // True if the protocol is casts:
-  bool is_secure() const { return is_secure_; }
+  // Whether to perform receiver authentication.
+  bool auth_required() const { return auth_required_; }
 
   // Channel id for the ApiResourceManager.
   long id() const { return channel_id_; }
@@ -116,9 +116,19 @@
   // is in cert error state.
   // Returns whether certificate is successfully extracted.
   virtual bool ExtractPeerCert(std::string* cert);
+  // Sends a challenge request to the receiver.
+  virtual int SendAuthChallenge();
+  // Reads auth challenge reply from the receiver.
+  virtual int ReadAuthChallengeReply();
+  // Verifies whether the challenge reply received from the peer is valid:
+  // 1. Signature in the reply is valid.
+  // 2. Certificate is rooted to a trusted CA.
+  virtual bool VerifyChallengeReply();
 
  private:
   friend class ApiResourceManager<CastSocket>;
+  friend class CastSocketTest;
+
   static const char* service_name() {
     return "CastSocketManager";
   }
@@ -130,6 +140,9 @@
     CONN_STATE_TCP_CONNECT_COMPLETE,
     CONN_STATE_SSL_CONNECT,
     CONN_STATE_SSL_CONNECT_COMPLETE,
+    CONN_STATE_AUTH_CHALLENGE_SEND,
+    CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE,
+    CONN_STATE_AUTH_CHALLENGE_REPLY_COMPLETE,
   };
 
   /////////////////////////////////////////////////////////////////////////////
@@ -139,6 +152,9 @@
   // 3. If connection fails due to invalid cert authority, then extract the
   //    peer certificate from the error.
   // 4. Whitelist the peer certificate and try #1 and #2 again.
+  // 5. If SSL socket is connected successfully, and if protocol is casts://
+  //    then issue an auth challenge request.
+  // 6. Validate the auth challenge response.
 
   // Main method that performs connection state transitions.
   int DoConnectLoop(int result);
@@ -149,12 +165,17 @@
   int DoTcpConnectComplete(int result);
   int DoSslConnect();
   int DoSslConnectComplete(int result);
-  int DoSslConnectRetry();
+  int DoAuthChallengeSend();
+  int DoAuthChallengeSendComplete(int result);
+  int DoAuthChallengeReplyComplete(int result);
   /////////////////////////////////////////////////////////////////////////////
 
   // Callback method for callbacks from underlying sockets.
   void OnConnectComplete(int result);
 
+  // Callback method when a challenge request is sent or a reply is received.
+  void OnChallengeEvent(int result);
+
   // Runs the external connection callback and resets it.
   void DoConnectCallback(int result);
 
@@ -162,14 +183,18 @@
   // the result.
   bool ParseChannelUrl(const GURL& url);
 
+  // Sends the given |message| and invokes the given callback when done.
+  int SendMessageInternal(const CastMessage& message,
+                          const net::CompletionCallback& callback);
+
   // Writes data to the socket from the WriteRequest at the head of the queue.
   // Calls OnWriteData() on completion.
-  void WriteData();
+  int WriteData();
   void OnWriteData(int result);
 
   // Reads data from the socket into one of the read buffers. Calls
   // OnReadData() on completion.
-  void ReadData();
+  int ReadData();
   void OnReadData(int result);
 
   // Processes the contents of header_read_buffer_ and returns true on success.
@@ -195,8 +220,8 @@
   GURL url_;
   // Delegate to inform of incoming messages and errors.
   Delegate* delegate_;
-  // True if the channel is using a secure transport.
-  bool is_secure_;
+  // True if we should perform receiver authentication.
+  bool auth_required_;
   // The IP endpoint of the peer.
   net::IPEndPoint ip_endpoint_;
   // The last error encountered by the channel.
@@ -234,6 +259,8 @@
   std::string peer_cert_;
   scoped_ptr<net::CertVerifier> cert_verifier_;
   scoped_ptr<net::TransportSecurityState> transport_security_state_;
+  // Reply received from the receiver to a challenge request.
+  scoped_ptr<CastMessage> challenge_reply_;
 
   // Callback invoked when the socket is connected.
   net::CompletionCallback connect_callback_;
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc b/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
index fdb94f0..3076fe3 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
@@ -80,14 +80,30 @@
 
 class TestCastSocket : public CastSocket {
  public:
-  explicit TestCastSocket(MockCastSocketDelegate* delegate) :
-    CastSocket("abcdefg", GURL("cast://192.0.0.1:8009"), delegate,
+  static scoped_ptr<TestCastSocket> Create(
+      MockCastSocketDelegate* delegate) {
+    return scoped_ptr<TestCastSocket>(
+        new TestCastSocket(delegate, "cast://192.0.0.1:8009"));
+  }
+
+  static scoped_ptr<TestCastSocket> CreateSecure(
+      MockCastSocketDelegate* delegate) {
+    return scoped_ptr<TestCastSocket>(
+        new TestCastSocket(delegate, "casts://192.0.0.1:8009"));
+  }
+
+  explicit TestCastSocket(MockCastSocketDelegate* delegate,
+                          const std::string& url) :
+    CastSocket("abcdefg", GURL(url), delegate,
                &capturing_net_log_),
     mock_tcp_socket_(new MockTCPClientSocket()),
     mock_ssl_socket_(new MockSSLClientSocket()),
     owns_tcp_socket_(true),
     owns_ssl_socket_(true),
-    extract_cert_result_(true) {
+    extract_cert_result_(true),
+    send_auth_challenge_result_(net::ERR_IO_PENDING),
+    read_auth_challenge_reply_result_(net::ERR_IO_PENDING),
+    challenge_reply_result_(true) {
   }
 
   virtual ~TestCastSocket() {
@@ -120,6 +136,18 @@
     extract_cert_result_ = value;
   }
 
+  void SetSendAuthChallengeResult(int result) {
+    send_auth_challenge_result_ = result;
+  }
+
+  void SetReadAuthChallengeReplyResult(int result) {
+    read_auth_challenge_reply_result_ = result;
+  }
+
+  void SetChallengeReplyResult(bool value) {
+    challenge_reply_result_ = value;
+  }
+
   MockTCPClientSocket* mock_tcp_socket_;
   MockSSLClientSocket* mock_ssl_socket_;
 
@@ -140,6 +168,18 @@
     return extract_cert_result_;
   }
 
+  virtual int SendAuthChallenge() OVERRIDE {
+    return send_auth_challenge_result_;
+  }
+
+  virtual int ReadAuthChallengeReply() OVERRIDE {
+    return read_auth_challenge_reply_result_;
+  }
+
+  virtual bool VerifyChallengeReply() OVERRIDE {
+    return challenge_reply_result_;
+  }
+
  private:
   net::CapturingNetLog capturing_net_log_;
   // Whether this object or the parent owns |mock_tcp_socket_|.
@@ -148,6 +188,12 @@
   bool owns_ssl_socket_;
   // Simulated result of peer cert extraction.
   bool extract_cert_result_;
+  // Simulated result to be returned by SendAuthChallenge.
+  int send_auth_challenge_result_;
+  // Simulated result to be returned by ReadAuthChallengeReply.
+  int read_auth_challenge_reply_result_;
+  // Simulated result of verifying challenge reply.
+  bool challenge_reply_result_;
 };
 
 class CastSocketTest : public testing::Test {
@@ -156,7 +202,6 @@
   virtual ~CastSocketTest() {}
 
   virtual void SetUp() OVERRIDE {
-    socket_.reset(new TestCastSocket(&mock_delegate_));
     test_message_.namespace_ = "urn:test";
     test_message_.source_id = "1";
     test_message_.destination_id = "2";
@@ -170,27 +215,43 @@
                               base::Unretained(&handler_)));
   }
 
-  // Sets an expectation on the TCP socket Connect method. Connect method is
-  // setup to return net::ERR_IO_PENDING and store the callback passed to it
-  // in |callback|.
-  void ExpectTCPConnect(net::CompletionCallback* callback) {
+  void CreateCastSocket() {
+    socket_ = TestCastSocket::Create(&mock_delegate_);
+  }
+
+  void CreateCastSocketSecure() {
+    socket_ = TestCastSocket::CreateSecure(&mock_delegate_);
+  }
+
+  // Sets an expectation that TCPClientSocket::Connect is called and
+  // returns |result| and stores the callback passed to it in |callback|.
+  void ExpectTcpConnect(net::CompletionCallback* callback, int result) {
     EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
         .Times(1)
-        .WillOnce(DoAll(SaveArg<0>(callback), Return(net::ERR_IO_PENDING)));
+        .WillOnce(DoAll(SaveArg<0>(callback), Return(result)));
   }
 
-  // Sets an expectation on the SSL socket Connect method. Connect method is
-  // setup to return net::ERR_IO_PENDING and store the callback passed to it
-  // in |callback|.
-  void ExpectSSLConnect(net::CompletionCallback* callback) {
+  // Same as ExpectTcpConnect but to return net::ERR_IO_PENDING.
+  void ExpectTcpConnectPending(net::CompletionCallback* callback) {
+    ExpectTcpConnect(callback, net::ERR_IO_PENDING);
+  }
+
+  // Sets an expectation that SSLClientSocket::Connect is called and
+  // returns |result| and stores the callback passed to it in |callback|.
+  void ExpectSslConnect(net::CompletionCallback* callback, int result) {
     EXPECT_CALL(mock_ssl_socket(), Connect(A<const net::CompletionCallback&>()))
         .Times(1)
-        .WillOnce(DoAll(SaveArg<0>(callback), Return(net::ERR_IO_PENDING)));
+        .WillOnce(DoAll(SaveArg<0>(callback), Return(result)));
   }
 
-  // Sets an expectation on the SSL socket Read method. Read method is setup
-  // to return net::ERR_IO_PENDING and to be called |times| number of times.
-  void ExpectSSLRead(int times) {
+  // Same as ExpectSslConnect but to return net::ERR_IO_PENDING.
+  void ExpectSslConnectPending(net::CompletionCallback* callback) {
+    ExpectSslConnect(callback, net::ERR_IO_PENDING);
+  }
+
+  // Sets an expectation that SSLClientSocket::Read is called |times| number
+  // of times and returns net::ERR_IO_PENDING.
+  void ExpectSslRead(int times) {
     EXPECT_CALL(mock_ssl_socket(), Read(A<net::IOBuffer*>(),
                                         A<int>(),
                                         A<const net::CompletionCallback&>()))
@@ -198,22 +259,20 @@
         .WillOnce(Return(net::ERR_IO_PENDING));
   }
 
-  // Sets expectations when the socket is connected. Connecting the socket also
-  // starts the read loop; we expect the call to Read(), but never fire the read
-  // callback.
+  // Sets up CastSocket::Connect to succeed.
+  // Connecting the socket also starts the read loop; we expect the call to
+  // Read(), but never fire the read callback.
   void ConnectHelper() {
     net::CompletionCallback connect_callback1;
     net::CompletionCallback connect_callback2;
 
-    ExpectTCPConnect(&connect_callback1);
-    ExpectSSLConnect(&connect_callback2);
+    ExpectTcpConnect(&connect_callback1, net::OK);
+    ExpectSslConnect(&connect_callback2, net::OK);
     EXPECT_CALL(handler_, OnConnectComplete(net::OK));
-    ExpectSSLRead(1);
+    ExpectSslRead(1);
 
     socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                                 base::Unretained(&handler_)));
-    connect_callback1.Run(net::OK);
-    connect_callback2.Run(net::OK);
 
     EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
     EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
@@ -232,6 +291,10 @@
     return *mock_socket;
   }
 
+  void CallOnChallengeEvent(int result) {
+    socket_->OnChallengeEvent(result);
+  }
+
   MockCastSocketDelegate mock_delegate_;
   scoped_ptr<TestCastSocket> socket_;
   CompleteHandler handler_;
@@ -241,12 +304,13 @@
 
 // Tests URL parsing and validation.
 TEST_F(CastSocketTest, TestCastURLs) {
+  CreateCastSocket();
   EXPECT_TRUE(socket_->ParseChannelUrl(GURL("cast://192.0.0.1:8009")));
-  EXPECT_FALSE(socket_->is_secure_);
+  EXPECT_FALSE(socket_->auth_required());
   EXPECT_EQ(socket_->ip_endpoint_.ToString(), "192.0.0.1:8009");
 
   EXPECT_TRUE(socket_->ParseChannelUrl(GURL("casts://192.0.0.1:12345")));
-  EXPECT_TRUE(socket_->is_secure_);
+  EXPECT_TRUE(socket_->auth_required());
   EXPECT_EQ(socket_->ip_endpoint_.ToString(), "192.0.0.1:12345");
 
   EXPECT_FALSE(socket_->ParseChannelUrl(GURL("http://192.0.0.1:12345")));
@@ -266,6 +330,7 @@
 
 // Tests connecting and closing the socket.
 TEST_F(CastSocketTest, TestConnectAndClose) {
+  CreateCastSocket();
   ConnectHelper();
 
   EXPECT_CALL(handler_, OnCloseComplete(net::OK));
@@ -275,16 +340,44 @@
   EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
 }
 
-// Test that when first connection attempt fails with certificate authority
-// invalid error, a second connection attempt is made with peer cert
-// whitelisted.
+// Tests that the following connection flow works:
+// - TCP connection succeeds (async)
+// - SSL connection succeeds (async)
+TEST_F(CastSocketTest, TestConnect) {
+  CreateCastSocket();
+
+  net::CompletionCallback connect_callback1;
+  net::CompletionCallback connect_callback2;
+
+  ExpectTcpConnectPending(&connect_callback1);
+  ExpectSslConnectPending(&connect_callback2);
+  EXPECT_CALL(handler_, OnConnectComplete(net::OK));
+  ExpectSslRead(1);
+
+  socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+                              base::Unretained(&handler_)));
+  connect_callback1.Run(net::OK);
+  connect_callback2.Run(net::OK);
+
+  EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
+  EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
+}
+
+// Test that the following connection flow works:
+// - TCP connection succeeds (async)
+// - SSL connection fails with cert error (async)
+// - Cert is extracted successfully
+// - Second TCP connection succeeds (async)
+// - Second SSL connection succeeds (async)
 TEST_F(CastSocketTest, TestTwoStepConnect) {
+  CreateCastSocket();
+
   // Expectations for the initial connect call
   net::CompletionCallback tcp_connect_callback1;
   net::CompletionCallback ssl_connect_callback1;
 
-  ExpectTCPConnect(&tcp_connect_callback1);
-  ExpectSSLConnect(&ssl_connect_callback1);
+  ExpectTcpConnectPending(&tcp_connect_callback1);
+  ExpectSslConnectPending(&ssl_connect_callback1);
 
   // Start connect flow
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -295,10 +388,10 @@
   socket_->CreateNewSockets();
   net::CompletionCallback tcp_connect_callback2;
   net::CompletionCallback ssl_connect_callback2;
-  ExpectTCPConnect(&tcp_connect_callback2);
-  ExpectSSLConnect(&ssl_connect_callback2);
+  ExpectTcpConnectPending(&tcp_connect_callback2);
+  ExpectSslConnectPending(&ssl_connect_callback2);
   EXPECT_CALL(handler_, OnConnectComplete(net::OK));
-  ExpectSSLRead(1);
+  ExpectSslRead(1);
 
   // Trigger callbacks for the first connect
   ssl_connect_callback1.Run(net::ERR_CERT_AUTHORITY_INVALID);
@@ -311,15 +404,22 @@
   EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
 }
 
-// Test that connection will be attempted a maximum of 2 times even if the
-// second attempt also returns certificate authority invalid error.
+// Test that the following connection flow works:
+// - TCP connection succeeds (async)
+// - SSL connection fails with cert error (async)
+// - Cert is extracted successfully
+// - Second TCP connection succeeds (async)
+// - Second SSL connection fails (async)
+// - The flow should NOT be tried again
 TEST_F(CastSocketTest, TestMaxTwoConnectAttempts) {
+  CreateCastSocket();
+
   net::CompletionCallback tcp_connect_callback1;
   net::CompletionCallback ssl_connect_callback1;
 
   // Expectations for the initial connect call
-  ExpectTCPConnect(&tcp_connect_callback1);
-  ExpectSSLConnect(&ssl_connect_callback1);
+  ExpectTcpConnectPending(&tcp_connect_callback1);
+  ExpectSslConnectPending(&ssl_connect_callback1);
 
   // Start connect flow
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -331,8 +431,8 @@
   net::CompletionCallback ssl_connect_callback2;
 
   // Expectations for the second connect call
-  ExpectTCPConnect(&tcp_connect_callback2);
-  ExpectSSLConnect(&ssl_connect_callback2);
+  ExpectTcpConnectPending(&tcp_connect_callback2);
+  ExpectSslConnectPending(&ssl_connect_callback2);
   EXPECT_CALL(handler_, OnConnectComplete(net::ERR_CERT_AUTHORITY_INVALID));
 
   // Trigger callbacks for the first connect
@@ -346,12 +446,15 @@
   EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state());
 }
 
+// Test that when cert extraction fails the connection flow stops.
 TEST_F(CastSocketTest, TestCertExtractionFailure) {
+  CreateCastSocket();
+
   net::CompletionCallback connect_callback1;
   net::CompletionCallback connect_callback2;
 
-  ExpectTCPConnect(&connect_callback1);
-  ExpectSSLConnect(&connect_callback2);
+  ExpectTcpConnectPending(&connect_callback1);
+  ExpectSslConnectPending(&connect_callback2);
 
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
@@ -368,10 +471,83 @@
   EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state());
 }
 
+// Tests that the following connection flow works:
+// - TCP connection succeeds (async)
+// - SSL connection fails with cert error (async)
+// - Cert is extracted successfully
+// - Second TCP connection succeeds (async)
+// - Second SSL connection succeeds (async)
+// - Challenge request is sent (async)
+// - Challenge response is received (async)
+// - Credentials are verified successfuly
+TEST_F(CastSocketTest, TestFullSecureConnectionFlowAsync) {
+  CreateCastSocketSecure();
+
+  net::CompletionCallback tcp_connect_callback1;
+  net::CompletionCallback ssl_connect_callback1;
+
+  // Expectations for the initial connect call
+  ExpectTcpConnectPending(&tcp_connect_callback1);
+  ExpectSslConnectPending(&ssl_connect_callback1);
+
+  // Start connect flow
+  socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+                              base::Unretained(&handler_)));
+  tcp_connect_callback1.Run(net::OK);
+
+  socket_->CreateNewSockets();
+  net::CompletionCallback tcp_connect_callback2;
+  net::CompletionCallback ssl_connect_callback2;
+
+  // Expectations for the second connect call
+  ExpectTcpConnectPending(&tcp_connect_callback2);
+  ExpectSslConnectPending(&ssl_connect_callback2);
+  EXPECT_CALL(handler_, OnConnectComplete(net::OK));
+
+  // Trigger callbacks for the first connect
+  ssl_connect_callback1.Run(net::ERR_CERT_AUTHORITY_INVALID);
+
+  // Trigger callbacks for the second connect
+  tcp_connect_callback2.Run(net::OK);
+  ssl_connect_callback2.Run(net::OK);
+
+  // Trigger callbacks for auth events.
+  CallOnChallengeEvent(net::OK);  // Sent challenge
+  CallOnChallengeEvent(net::OK);  // Received reply
+
+  EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
+  EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
+}
+
+// Same as TestFullSecureConnectionFlowAsync, but operations are  synchronous.
+TEST_F(CastSocketTest, TestFullSecureConnectionFlowSync) {
+  CreateCastSocketSecure();
+
+  net::CompletionCallback tcp_connect_callback;
+  net::CompletionCallback ssl_connect_callback;
+
+  // Expectations for the connect calls
+  ExpectTcpConnect(&tcp_connect_callback, net::OK);
+  ExpectSslConnect(&ssl_connect_callback, net::OK);
+  EXPECT_CALL(handler_, OnConnectComplete(net::OK));
+
+  socket_->SetSendAuthChallengeResult(net::OK);
+  socket_->SetReadAuthChallengeReplyResult(net::OK);
+
+  // Start connect flow
+  socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+                              base::Unretained(&handler_)));
+
+  EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
+  EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
+}
+
 // Tests writing a single message where the completion is signaled via
 // callback.
 TEST_F(CastSocketTest, TestWriteViaCallback) {
+  CreateCastSocket();
   ConnectHelper();
+
   net::CompletionCallback write_callback;
 
   EXPECT_CALL(mock_ssl_socket(),
@@ -392,6 +568,7 @@
 
 // Tests writing a single message where the Write() returns directly.
 TEST_F(CastSocketTest, TestWrite) {
+  CreateCastSocket();
   ConnectHelper();
 
   EXPECT_CALL(mock_ssl_socket(),
@@ -410,6 +587,7 @@
 
 // Tests writing multiple messages.
 TEST_F(CastSocketTest, TestWriteMany) {
+  CreateCastSocket();
   ConnectHelper();
   std::string messages[4];
   messages[0] = "Hello, World!";
@@ -448,6 +626,7 @@
 
 // Tests error on writing.
 TEST_F(CastSocketTest, TestWriteError) {
+  CreateCastSocket();
   ConnectHelper();
   net::CompletionCallback write_callback;
 
@@ -470,6 +649,8 @@
 
 // Tests reading a single message.
 TEST_F(CastSocketTest, TestRead) {
+  CreateCastSocket();
+
   net::CompletionCallback connect_callback1;
   net::CompletionCallback connect_callback2;
   net::CompletionCallback read_callback;
@@ -518,6 +699,8 @@
 
 // Tests reading multiple messages.
 TEST_F(CastSocketTest, TestReadMany) {
+  CreateCastSocket();
+
   net::CompletionCallback connect_callback1;
   net::CompletionCallback connect_callback2;
   net::CompletionCallback read_callback;
@@ -580,6 +763,8 @@
 
 // Tests error on reading.
 TEST_F(CastSocketTest, TestReadError) {
+  CreateCastSocket();
+
   net::CompletionCallback connect_callback1;
   net::CompletionCallback connect_callback2;
   net::CompletionCallback read_callback;
diff --git a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
index e44a17d..ab18eae 100644
--- a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
+++ b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
@@ -49,15 +49,15 @@
         params->credentials,
         params->user_settings);
   } else {
-    if (!CloudPrintProxyServiceFactory::GetForProfile(profile_))
+    if (!CloudPrintProxyServiceFactory::GetForProfile(GetProfile()))
       return false;
     scoped_ptr<base::DictionaryValue> user_setings(
         params->user_settings.ToValue());
-    CloudPrintProxyServiceFactory::GetForProfile(profile_)->
-        EnableForUserWithRobot(params->credentials,
-                               params->robot_email,
-                               params->user_email,
-                               *user_setings);
+    CloudPrintProxyServiceFactory::GetForProfile(GetProfile())
+        ->EnableForUserWithRobot(params->credentials,
+                                 params->robot_email,
+                                 params->user_email,
+                                 *user_setings);
   }
   SendResponse(true);
 #endif
diff --git a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.h b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.h
index 53e824e..9da2d44 100644
--- a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.h
+++ b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
@@ -46,7 +46,8 @@
   static CloudPrintTestsDelegate* instance_;
 };
 
-class CloudPrintPrivateSetupConnectorFunction : public AsyncExtensionFunction {
+class CloudPrintPrivateSetupConnectorFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("cloudPrintPrivate.setupConnector",
                              CLOUDPRINTPRIVATE_SETUPCONNECTOR)
@@ -60,7 +61,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class CloudPrintPrivateGetHostNameFunction : public AsyncExtensionFunction {
+class CloudPrintPrivateGetHostNameFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("cloudPrintPrivate.getHostName",
                              CLOUDPRINTPRIVATE_GETHOSTNAME)
@@ -74,7 +76,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class CloudPrintPrivateGetPrintersFunction : public AsyncExtensionFunction {
+class CloudPrintPrivateGetPrintersFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("cloudPrintPrivate.getPrinters",
                              CLOUDPRINTPRIVATE_GETPRINTERS)
@@ -90,7 +93,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class CloudPrintPrivateGetClientIdFunction : public AsyncExtensionFunction {
+class CloudPrintPrivateGetClientIdFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("cloudPrintPrivate.getClientId",
                              CLOUDPRINTPRIVATE_GETCLIENTID);
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 5282cf0..16c366e 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/commands/command_service.h"
 
 #include "base/lazy_instance.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/extensions/extension_keybinding_registry.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/accelerator_utils.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
@@ -250,15 +250,19 @@
                     true, command.global());
 }
 
-void CommandService::ToggleScope(const std::string& extension_id,
-                                 const std::string& command_name) {
+bool CommandService::SetScope(const std::string& extension_id,
+                              const std::string& command_name,
+                              bool global) {
   extensions::Command command = FindCommandByName(extension_id, command_name);
+  if (global == command.global())
+    return false;
 
   // Pre-existing shortcuts must be removed before proceeding because the
   // handlers for global and non-global extensions are not one and the same.
   RemoveKeybindingPrefs(extension_id, command_name);
   AddKeybindingPref(command.accelerator(), extension_id,
-                    command_name, true, !command.global());
+                    command_name, true, global);
+  return true;
 }
 
 Command CommandService::FindCommandByName(
diff --git a/chrome/browser/extensions/api/commands/command_service.h b/chrome/browser/extensions/api/commands/command_service.h
index cedacd7..8224984 100644
--- a/chrome/browser/extensions/api/commands/command_service.h
+++ b/chrome/browser/extensions/api/commands/command_service.h
@@ -137,9 +137,12 @@
                              const std::string& command_name,
                              const std::string& keystroke);
 
-  // Toggles the scope of the keybinding.
-  void ToggleScope(const std::string& extension_id,
-                   const std::string& command_name);
+  // Set the scope of the keybinding. If |global| is true, the keybinding works
+  // even when Chrome does not have focus. If the scope requested is already
+  // set, the function returns false, otherwise true.
+  bool SetScope(const std::string& extension_id,
+                const std::string& command_name,
+                bool global);
 
   // Finds the command with the name |command_name| within an extension with id
   // |extension_id| . Returns an empty Command object (with keycode
diff --git a/chrome/browser/extensions/api/commands/commands.cc b/chrome/browser/extensions/api/commands/commands.cc
index 0b6f0e5..be1c95b 100644
--- a/chrome/browser/extensions/api/commands/commands.cc
+++ b/chrome/browser/extensions/api/commands/commands.cc
@@ -25,7 +25,7 @@
   base::ListValue* command_list = new base::ListValue();
 
   extensions::CommandService* command_service =
-      extensions::CommandService::Get(profile_);
+      extensions::CommandService::Get(GetProfile());
 
   extensions::Command browser_action;
   bool active = false;
diff --git a/chrome/browser/extensions/api/commands/commands.h b/chrome/browser/extensions/api/commands/commands.h
index 9acb762..26bf708 100644
--- a/chrome/browser/extensions/api/commands/commands.h
+++ b/chrome/browser/extensions/api/commands/commands.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMANDS_H_
 #define CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMANDS_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
-class GetAllCommandsFunction : public SyncExtensionFunction {
+class GetAllCommandsFunction : public ChromeSyncExtensionFunction {
   virtual ~GetAllCommandsFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("commands.getAll", COMMANDS_GETALL)
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
index d939436..db3e637 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -82,14 +82,15 @@
   } else {
     // Incognito profiles can't access regular mode ever, they only exist in
     // split mode.
-    if (profile()->IsOffTheRecord()) {
+    if (GetProfile()->IsOffTheRecord()) {
       error_ = keys::kIncognitoContextError;
       return false;
     }
   }
 
-  ContentSettingsStore* store = extensions::ExtensionSystem::Get(profile_)->
-      extension_service()->GetContentSettingsStore();
+  ContentSettingsStore* store = extensions::ExtensionSystem::Get(GetProfile())
+                                    ->extension_service()
+                                    ->GetContentSettingsStore();
   store->ClearContentSettingsForExtension(extension_id(), scope);
 
   return true;
@@ -134,18 +135,19 @@
   HostContentSettingsMap* map;
   CookieSettings* cookie_settings;
   if (incognito) {
-    if (!profile()->HasOffTheRecordProfile()) {
+    if (!GetProfile()->HasOffTheRecordProfile()) {
       // TODO(bauerb): Allow reading incognito content settings
       // outside of an incognito session.
       error_ = keys::kIncognitoSessionOnlyError;
       return false;
     }
-    map = profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap();
+    map = GetProfile()->GetOffTheRecordProfile()->GetHostContentSettingsMap();
     cookie_settings = CookieSettings::Factory::GetForProfile(
-        profile()->GetOffTheRecordProfile()).get();
+        GetProfile()->GetOffTheRecordProfile()).get();
   } else {
-    map = profile()->GetHostContentSettingsMap();
-    cookie_settings = CookieSettings::Factory::GetForProfile(profile()).get();
+    map = GetProfile()->GetHostContentSettingsMap();
+    cookie_settings =
+        CookieSettings::Factory::GetForProfile(GetProfile()).get();
   }
 
   ContentSetting setting;
@@ -206,10 +208,8 @@
   ContentSetting setting;
   EXTENSION_FUNCTION_VALIDATE(
       helpers::StringToContentSetting(setting_str, &setting));
-  EXTENSION_FUNCTION_VALIDATE(
-      HostContentSettingsMap::IsSettingAllowedForType(profile()->GetPrefs(),
-                                                      setting,
-                                                      content_type));
+  EXTENSION_FUNCTION_VALIDATE(HostContentSettingsMap::IsSettingAllowedForType(
+      GetProfile()->GetPrefs(), setting, content_type));
 
   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
   bool incognito = false;
@@ -221,27 +221,28 @@
 
   if (incognito) {
     // Regular profiles can't access incognito unless include_incognito is true.
-    if (!profile()->IsOffTheRecord() && !include_incognito()) {
+    if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
       error_ = pref_keys::kIncognitoErrorMessage;
       return false;
     }
   } else {
     // Incognito profiles can't access regular mode ever, they only exist in
     // split mode.
-    if (profile()->IsOffTheRecord()) {
+    if (GetProfile()->IsOffTheRecord()) {
       error_ = keys::kIncognitoContextError;
       return false;
     }
   }
 
   if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
-      !profile_->HasOffTheRecordProfile()) {
+      !GetProfile()->HasOffTheRecordProfile()) {
     error_ = pref_keys::kIncognitoSessionOnlyErrorMessage;
     return false;
   }
 
-  ContentSettingsStore* store = extensions::ExtensionSystem::Get(profile_)->
-      extension_service()->GetContentSettingsStore();
+  ContentSettingsStore* store = extensions::ExtensionSystem::Get(GetProfile())
+                                    ->extension_service()
+                                    ->GetContentSettingsStore();
   store->SetExtensionContentSetting(extension_id(), primary_pattern,
                                     secondary_pattern, content_type,
                                     resource_identifier, setting, scope);
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.h b/chrome/browser/extensions/api/content_settings/content_settings_api.h
index 820849f..b2e3beb 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.h
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_CONTENT_SETTINGS_CONTENT_SETTINGS_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_CONTENT_SETTINGS_CONTENT_SETTINGS_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class PluginFinder;
 
@@ -16,7 +16,7 @@
 namespace extensions {
 
 class ContentSettingsContentSettingClearFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contentSettings.clear", CONTENTSETTINGS_CLEAR)
 
@@ -27,7 +27,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ContentSettingsContentSettingGetFunction : public SyncExtensionFunction {
+class ContentSettingsContentSettingGetFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contentSettings.get", CONTENTSETTINGS_GET)
 
@@ -38,7 +39,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ContentSettingsContentSettingSetFunction : public SyncExtensionFunction {
+class ContentSettingsContentSettingSetFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contentSettings.set", CONTENTSETTINGS_SET)
 
@@ -50,7 +52,7 @@
 };
 
 class ContentSettingsContentSettingGetResourceIdentifiersFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contentSettings.getResourceIdentifiers",
                              CONTENTSETTINGS_GETRESOURCEIDENTIFIERS)
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api.cc b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
index de30534..1c3eb67 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api.cc
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
@@ -153,7 +153,7 @@
 namespace Update = api::context_menus::Update;
 
 bool ContextMenusCreateFunction::RunImpl() {
-  MenuItem::Id id(profile()->IsOffTheRecord(), extension_id());
+  MenuItem::Id id(GetProfile()->IsOffTheRecord(), extension_id());
   scoped_ptr<Create::Params> params(Create::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
@@ -176,7 +176,8 @@
   if (params->create_properties.title.get())
     title = *params->create_properties.title;
 
-  MenuManager* menu_manager = profile()->GetExtensionService()->menu_manager();
+  MenuManager* menu_manager =
+      GetProfile()->GetExtensionService()->menu_manager();
 
   if (menu_manager->GetItemById(id)) {
     error_ = ErrorUtils::FormatErrorMessage(kDuplicateIDError,
@@ -229,7 +230,7 @@
 
   bool success = true;
   scoped_ptr<MenuItem::Id> parent_id(GetParentId(params->create_properties,
-                                                 profile()->IsOffTheRecord(),
+                                                 GetProfile()->IsOffTheRecord(),
                                                  extension_id()));
   if (parent_id.get()) {
     MenuItem* parent = GetParent(*parent_id, menu_manager, &error_);
@@ -249,7 +250,7 @@
 
 bool ContextMenusUpdateFunction::RunImpl() {
   bool radio_item_updated = false;
-  MenuItem::Id item_id(profile()->IsOffTheRecord(), extension_id());
+  MenuItem::Id item_id(GetProfile()->IsOffTheRecord(), extension_id());
   scoped_ptr<Update::Params> params(Update::Params::Create(*args_));
 
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -260,7 +261,7 @@
   else
     NOTREACHED();
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   MenuManager* manager = service->menu_manager();
   MenuItem* item = manager->GetItemById(item_id);
   if (!item || item->extension_id() != extension_id()) {
@@ -328,7 +329,7 @@
   // Parent id.
   MenuItem* parent = NULL;
   scoped_ptr<MenuItem::Id> parent_id(GetParentId(params->update_properties,
-                                                 profile()->IsOffTheRecord(),
+                                                 GetProfile()->IsOffTheRecord(),
                                                  extension_id()));
   if (parent_id.get()) {
     MenuItem* parent = GetParent(*parent_id, manager, &error_);
@@ -356,10 +357,10 @@
   scoped_ptr<Remove::Params> params(Remove::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   MenuManager* manager = service->menu_manager();
 
-  MenuItem::Id id(profile()->IsOffTheRecord(), extension_id());
+  MenuItem::Id id(GetProfile()->IsOffTheRecord(), extension_id());
   if (params->menu_item_id.as_string)
     id.string_uid = *params->menu_item_id.as_string;
   else if (params->menu_item_id.as_integer)
@@ -382,7 +383,7 @@
 }
 
 bool ContextMenusRemoveAllFunction::RunImpl() {
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   MenuManager* manager = service->menu_manager();
   manager->RemoveAllContextItems(GetExtension()->id());
   manager->WriteToStorage(GetExtension());
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api.h b/chrome/browser/extensions/api/context_menus/context_menus_api.h
index 91d0728..2e05f26 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api.h
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
-class ContextMenusCreateFunction : public SyncExtensionFunction {
+class ContextMenusCreateFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contextMenus.create", CONTEXTMENUS_CREATE)
 
@@ -20,7 +20,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ContextMenusUpdateFunction : public SyncExtensionFunction {
+class ContextMenusUpdateFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contextMenus.update", CONTEXTMENUS_UPDATE)
 
@@ -31,7 +31,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ContextMenusRemoveFunction : public SyncExtensionFunction {
+class ContextMenusRemoveFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contextMenus.remove", CONTEXTMENUS_REMOVE)
 
@@ -42,7 +42,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ContextMenusRemoveAllFunction : public SyncExtensionFunction {
+class ContextMenusRemoveAllFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("contextMenus.removeAll", CONTEXTMENUS_REMOVEALL)
 
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 079be55..4a6138c 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -170,7 +170,7 @@
   Profile* store_profile = NULL;
   if (!store_id->empty()) {
     store_profile = cookies_helpers::ChooseProfileFromStoreId(
-        *store_id, profile(), include_incognito());
+        *store_id, GetProfile(), include_incognito());
     if (!store_profile) {
       error_ = ErrorUtils::FormatErrorMessage(
           keys::kInvalidStoreIdError, *store_id);
@@ -513,13 +513,13 @@
 }
 
 bool CookiesGetAllCookieStoresFunction::RunImpl() {
-  Profile* original_profile = profile();
+  Profile* original_profile = GetProfile();
   DCHECK(original_profile);
   scoped_ptr<base::ListValue> original_tab_ids(new base::ListValue());
   Profile* incognito_profile = NULL;
   scoped_ptr<base::ListValue> incognito_tab_ids;
-  if (include_incognito() && profile()->HasOffTheRecordProfile()) {
-    incognito_profile = profile()->GetOffTheRecordProfile();
+  if (include_incognito() && GetProfile()->HasOffTheRecordProfile()) {
+    incognito_profile = GetProfile()->GetOffTheRecordProfile();
     if (incognito_profile)
       incognito_tab_ids.reset(new base::ListValue());
   }
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.h b/chrome/browser/extensions/api/cookies/cookies_api.h
index 8dbc0a4..38e7438 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.h
+++ b/chrome/browser/extensions/api/cookies/cookies_api.h
@@ -14,8 +14,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/net/chrome_cookie_notification_details.h"
 #include "chrome/common/extensions/api/cookies.h"
 #include "content/public/browser/notification_observer.h"
@@ -67,7 +67,7 @@
 // concurrently accessed from multiple threads. They modify |result_| and other
 // member variables directly.
 // See chrome/browser/extensions/extension_function.h for more information.
-class CookiesFunction : public AsyncExtensionFunction {
+class CookiesFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~CookiesFunction() {}
 
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index 32abf2e..8450baa 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -14,10 +14,12 @@
 #include "base/json/json_writer.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/extensions/api/debugger/debugger_api_constants.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_host.h"
@@ -35,15 +37,12 @@
 #include "content/public/browser/devtools_client_host.h"
 #include "content/public/browser/devtools_http_handler.h"
 #include "content/public/browser/devtools_manager.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/worker_service.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_utils.h"
 #include "extensions/common/error_utils.h"
@@ -58,7 +57,6 @@
 using content::RenderViewHost;
 using content::RenderWidgetHost;
 using content::WebContents;
-using content::WorkerService;
 using extensions::ErrorUtils;
 
 namespace keys = debugger_api_constants;
@@ -487,9 +485,13 @@
 bool DebuggerFunction::InitAgentHost() {
   if (debuggee_.tab_id) {
     WebContents* web_contents = NULL;
-    bool result = ExtensionTabUtil::GetTabById(
-        *debuggee_.tab_id, profile(), include_incognito(), NULL, NULL,
-        &web_contents, NULL);
+    bool result = ExtensionTabUtil::GetTabById(*debuggee_.tab_id,
+                                               GetProfile(),
+                                               include_incognito(),
+                                               NULL,
+                                               NULL,
+                                               &web_contents,
+                                               NULL);
     if (result && web_contents) {
       if (content::HasWebUIScheme(web_contents->GetURL())) {
         error_ = ErrorUtils::FormatErrorMessage(
@@ -502,8 +504,9 @@
     }
   } else if (debuggee_.extension_id) {
     extensions::ExtensionHost* extension_host =
-        extensions::ExtensionSystem::Get(profile())->process_manager()->
-            GetBackgroundHostForExtension(*debuggee_.extension_id);
+        extensions::ExtensionSystem::Get(GetProfile())
+            ->process_manager()
+            ->GetBackgroundHostForExtension(*debuggee_.extension_id);
     if (extension_host) {
       agent_host_ = DevToolsAgentHost::GetOrCreateFor(
           extension_host->render_view_host());
@@ -581,9 +584,12 @@
     }
   }
 
-  new ExtensionDevToolsClientHost(profile(), agent_host_.get(),
-                                  GetExtension()->id(), GetExtension()->name(),
-                                  debuggee_, infobar);
+  new ExtensionDevToolsClientHost(GetProfile(),
+                                  agent_host_.get(),
+                                  GetExtension()->id(),
+                                  GetExtension()->name(),
+                                  debuggee_,
+                                  infobar);
   SendResponse(true);
   return true;
 }
@@ -668,75 +674,28 @@
 const char kTargetTabIdField[] = "tabId";
 const char kTargetExtensionIdField[] = "extensionId";
 
-extensions::ExtensionHost*
-    GetExtensionBackgroundHost(WebContents* web_contents) {
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  if (!profile)
-    return NULL;
-
-  extensions::ExtensionHost* extension_host =
-      extensions::ExtensionSystem::Get(profile)->process_manager()->
-          GetBackgroundHostForExtension(web_contents->GetURL().host());
-
-  return (extension_host && extension_host->host_contents() == web_contents) ?
-      extension_host : NULL;
-}
-
-base::Value* SerializePageInfo(RenderViewHost* rvh) {
-  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
-  if (!web_contents)
-    return NULL;
-
-  DevToolsAgentHost* agent_host = DevToolsAgentHost::GetOrCreateFor(rvh);
-
+base::Value* SerializeTarget(const DevToolsTargetImpl& target) {
   base::DictionaryValue* dictionary = new base::DictionaryValue();
 
-  dictionary->SetString(kTargetIdField, agent_host->GetId());
-  dictionary->SetBoolean(kTargetAttachedField, agent_host->IsAttached());
-  dictionary->SetString(kTargetUrlField, web_contents->GetURL().spec());
+  dictionary->SetString(kTargetIdField, target.GetId());
+  dictionary->SetString(kTargetTitleField, target.GetTitle());
+  dictionary->SetBoolean(kTargetAttachedField, target.IsAttached());
+  dictionary->SetString(kTargetUrlField, target.GetUrl().spec());
 
-  extensions::ExtensionHost* extension_host =
-      GetExtensionBackgroundHost(web_contents);
-  if (extension_host) {
-    // This RenderViewHost belongs to a background page.
-    dictionary->SetString(kTargetTypeField, kTargetTypeBackgroundPage);
-    dictionary->SetString(kTargetExtensionIdField,
-                          extension_host->extension()->id());
-    dictionary->SetString(kTargetTitleField,
-                          extension_host->extension()->name());
-  } else {
-    int tab_id = ExtensionTabUtil::GetTabId(web_contents);
-    if (tab_id != -1) {
-      // This RenderViewHost belongs to a regular page.
-      dictionary->SetString(kTargetTypeField, kTargetTypePage);
-      dictionary->SetInteger(kTargetTabIdField, tab_id);
-    } else {
-      dictionary->SetString(kTargetTypeField, kTargetTypeOther);
-    }
-    dictionary->SetString(kTargetTitleField, web_contents->GetTitle());
-
-    content::NavigationController& controller = web_contents->GetController();
-    content::NavigationEntry* entry = controller.GetVisibleEntry();
-    if (entry != NULL && entry->GetURL().is_valid()) {
-      dictionary->SetString(kTargetFaviconUrlField,
-                            entry->GetFavicon().url.spec());
-    }
+  std::string type = target.GetType();
+  if (type == kTargetTypePage) {
+    dictionary->SetInteger(kTargetTabIdField, target.GetTabId());
+  } else if (type == kTargetTypeBackgroundPage) {
+    dictionary->SetString(kTargetExtensionIdField, target.GetExtensionId());
+  } else if (type != kTargetTypeWorker) {
+    // DevToolsTargetImpl may support more types than the debugger API.
+    type = kTargetTypeOther;
   }
+  dictionary->SetString(kTargetTypeField, type);
 
-  return dictionary;
-}
-
-base::Value* SerializeWorkerInfo(const WorkerService::WorkerInfo& worker) {
-  base::DictionaryValue* dictionary = new base::DictionaryValue;
-
-  scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetForWorker(
-      worker.process_id, worker.route_id));
-  dictionary->SetString(kTargetIdField, agent->GetId());
-  dictionary->SetString(kTargetTypeField, kTargetTypeWorker);
-  dictionary->SetString(kTargetTitleField, worker.name);
-  dictionary->SetString(kTargetUrlField, worker.url.spec());
-  dictionary->SetBoolean(kTargetAttachedField, agent->IsAttached());
+  GURL favicon_url = target.GetFaviconUrl();
+  if (favicon_url.is_valid())
+    dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
 
   return dictionary;
 }
@@ -750,36 +709,17 @@
 }
 
 bool DebuggerGetTargetsFunction::RunImpl() {
-  base::ListValue* results_list = new base::ListValue();
-
-  std::vector<RenderViewHost*> rvh_list =
-      DevToolsAgentHost::GetValidRenderViewHosts();
-  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
-       it != rvh_list.end(); ++it) {
-    base::Value* value = SerializePageInfo(*it);
-    if (value)
-      results_list->Append(value);
-  }
-
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&DebuggerGetTargetsFunction::CollectWorkerInfo, this),
-      base::Bind(&DebuggerGetTargetsFunction::SendTargetList, this,
-                 results_list));
+  DevToolsTargetImpl::EnumerateAllTargets(
+      base::Bind(&DebuggerGetTargetsFunction::SendTargetList, this));
   return true;
 }
 
-DebuggerGetTargetsFunction::WorkerInfoList
-DebuggerGetTargetsFunction::CollectWorkerInfo() {
-  return WorkerService::GetInstance()->GetWorkers();
-}
-
 void DebuggerGetTargetsFunction::SendTargetList(
-    base::ListValue* list,
-    const WorkerInfoList& worker_info) {
-  for (size_t i = 0; i < worker_info.size(); ++i)
-    list->Append(SerializeWorkerInfo(worker_info[i]));
-  SetResult(list);
+    const std::vector<DevToolsTargetImpl*>& target_list) {
+  scoped_ptr<base::ListValue> result(new base::ListValue());
+  for (size_t i = 0; i < target_list.size(); ++i)
+    result->Append(SerializeTarget(*target_list[i]));
+  STLDeleteContainerPointers(target_list.begin(), target_list.end());
+  SetResult(result.release());
   SendResponse(true);
 }
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.h b/chrome/browser/extensions/api/debugger/debugger_api.h
index 8f3561b..e8a1048 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.h
+++ b/chrome/browser/extensions/api/debugger/debugger_api.h
@@ -9,16 +9,17 @@
 #define CHROME_BROWSER_EXTENSIONS_API_DEBUGGER_DEBUGGER_API_H_
 
 #include <string>
+#include <vector>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/debugger.h"
-#include "content/public/browser/worker_service.h"
 
 using extensions::api::debugger::Debuggee;
 
 // Base debugger function.
 
 class ExtensionDevToolsClientHost;
+class DevToolsTargetImpl;
 
 namespace base {
 class DictionaryValue;
@@ -29,7 +30,7 @@
 class WebContents;
 }
 
-class DebuggerFunction : public AsyncExtensionFunction {
+class DebuggerFunction : public ChromeAsyncExtensionFunction {
  protected:
   DebuggerFunction();
   virtual ~DebuggerFunction();
@@ -101,12 +102,7 @@
   virtual bool RunImpl() OVERRIDE;
 
  private:
-  typedef std::vector<content::WorkerService::WorkerInfo> WorkerInfoList;
-
-  WorkerInfoList CollectWorkerInfo();
-
-  void SendTargetList(base::ListValue* list,
-                      const WorkerInfoList& worker_info);
+  void SendTargetList(const std::vector<DevToolsTargetImpl*>& target_list);
 };
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_DEBUGGER_DEBUGGER_API_H_
diff --git a/chrome/browser/extensions/api/declarative/declarative_api.cc b/chrome/browser/extensions/api/declarative/declarative_api.cc
index 9f2f5cc..a77a6bd 100644
--- a/chrome/browser/extensions/api/declarative/declarative_api.cc
+++ b/chrome/browser/extensions/api/declarative/declarative_api.cc
@@ -42,7 +42,7 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
 
   RulesRegistryService* rules_registry_service =
-      RulesRegistryService::Get(profile());
+      RulesRegistryService::Get(GetProfile());
   rules_registry_ = rules_registry_service->GetRulesRegistry(event_name);
   // Raw access to this function is not available to extensions, therefore
   // there should never be a request for a nonexisting rules registry.
diff --git a/chrome/browser/extensions/api/declarative/declarative_api.h b/chrome/browser/extensions/api/declarative/declarative_api.h
index 90e0e99..f740a3e 100644
--- a/chrome/browser/extensions/api/declarative/declarative_api.h
+++ b/chrome/browser/extensions/api/declarative/declarative_api.h
@@ -8,11 +8,11 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/extensions/api/declarative/rules_registry.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
-class RulesFunction : public AsyncExtensionFunction {
+class RulesFunction : public ChromeAsyncExtensionFunction {
  public:
   RulesFunction();
 
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
index 4c00e25..0fe1a83 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
@@ -96,9 +96,13 @@
     }
 
     content::WebContents* web_contents = NULL;
-    if (!ExtensionTabUtil::GetTabById(
-            *(params->target_tab->id), profile(), false,
-            NULL, NULL, &web_contents, NULL)) {
+    if (!ExtensionTabUtil::GetTabById(*(params->target_tab->id),
+                                      GetProfile(),
+                                      false,
+                                      NULL,
+                                      NULL,
+                                      &web_contents,
+                                      NULL)) {
       error_ = kInvalidTabIdError;
       return false;
     }
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h
index 2073547..2621d07 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h
@@ -8,7 +8,7 @@
 #include <map>
 
 #include "base/memory/singleton.h"
-#include "chrome/browser/extensions/api/api_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/media/desktop_media_picker.h"
 #include "chrome/browser/media/desktop_media_picker_model.h"
 #include "chrome/common/extensions/api/desktop_capture.h"
@@ -16,7 +16,8 @@
 
 namespace extensions {
 
-class DesktopCaptureChooseDesktopMediaFunction : public AsyncExtensionFunction {
+class DesktopCaptureChooseDesktopMediaFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("desktopCapture.chooseDesktopMedia",
                              DESKTOPCAPTURE_CHOOSEDESKTOPMEDIA)
@@ -61,7 +62,7 @@
 };
 
 class DesktopCaptureCancelChooseDesktopMediaFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("desktopCapture.cancelChooseDesktopMedia",
                              DESKTOPCAPTURE_CANCELCHOOSEDESKTOPMEDIA)
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
index 99d8250..9291c2d 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
@@ -142,7 +142,13 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, ChooseDesktopMedia) {
+// Flaky on Windows: http://crbug.com/301887
+#if defined(OS_WIN)
+#define MAYBE_ChooseDesktopMedia DISABLED_ChooseDesktopMedia
+#else
+#define MAYBE_ChooseDesktopMedia ChooseDesktopMedia
+#endif
+IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, MAYBE_ChooseDesktopMedia) {
   // Each of the following expectations corresponds to one test in
   // chrome/test/data/extensions/api_test/desktop_capture/test.js .
   FakeDesktopMediaPickerFactory::Expectation picker_expectations[] = {
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index eb81a66..55b0709 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -288,7 +288,7 @@
 namespace api {
 
 bool DeveloperPrivateAutoUpdateFunction::RunImpl() {
-  ExtensionUpdater* updater = GetExtensionUpdater(profile());
+  ExtensionUpdater* updater = GetExtensionUpdater(GetProfile());
   if (updater)
     updater->CheckNow(ExtensionUpdater::CheckParams());
   SetResult(new base::FundamentalValue(true));
@@ -303,8 +303,8 @@
       bool item_is_enabled) {
   scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
 
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
+  ExtensionService* service = GetProfile()->GetExtensionService();
 
   info->id = item.id();
   info->name = item.name();
@@ -430,7 +430,7 @@
     GetShellWindowPagesForExtensionProfile(
         const Extension* extension,
         ItemInspectViewList* result) {
-  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
+  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
   if (!registry) return;
 
   const ShellWindowRegistry::ShellWindowList windows =
@@ -486,7 +486,7 @@
   ItemInspectViewList result;
   // Get the extension process's active views.
   ExtensionProcessManager* process_manager =
-      ExtensionSystem::Get(profile())->process_manager();
+      ExtensionSystem::Get(GetProfile())->process_manager();
   GetInspectablePagesForExtensionProcess(
       extension,
       process_manager->GetRenderViewHostsForExtension(extension->id()),
@@ -507,7 +507,7 @@
         BackgroundInfo::HasGeneratedBackgroundPage(extension)));
   }
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   // Repeat for the incognito process, if applicable. Don't try to get
   // shell windows for incognito process.
   if (service->profile()->HasOffTheRecordProfile() &&
@@ -544,7 +544,7 @@
 
   ExtensionSet items;
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
 
   items.InsertAll(*service->extensions());
 
@@ -596,9 +596,9 @@
 
   EXTENSION_FUNCTION_VALIDATE(user_gesture_);
 
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
   ManagementPolicy* management_policy = system->management_policy();
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   const Extension* extension = service->GetInstalledExtension(params->item_id);
   bool result = true;
 
@@ -625,7 +625,7 @@
       AllowIncognito::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   const Extension* extension = service->GetInstalledExtension(params->item_id);
   bool result = true;
 
@@ -646,7 +646,7 @@
   scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   CHECK(!params->item_id.empty());
   service->ReloadExtension(params->item_id);
   return true;
@@ -654,9 +654,9 @@
 
 bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() {
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   CHECK(!extension_id_.empty());
-  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
+  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
   DCHECK(registry);
   ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
       render_view_host());
@@ -671,8 +671,8 @@
   std::vector<base::FilePath> retained_file_paths;
   if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) {
     std::vector<apps::SavedFileEntry> retained_file_entries =
-        apps::SavedFilesService::Get(profile())->GetAllFileEntries(
-            extension_id_);
+        apps::SavedFilesService::Get(GetProfile())
+            ->GetAllFileEntries(extension_id_);
     for (size_t i = 0; i < retained_file_entries.size(); i++) {
       retained_file_paths.push_back(retained_file_entries[i].path);
     }
@@ -685,10 +685,12 @@
 
 // This is called when the user clicks "Revoke File Access."
 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
-  apps::SavedFilesService::Get(profile())->ClearQueue(
-      profile()->GetExtensionService()->GetExtensionById(extension_id_, true));
-  if (apps::AppRestoreService::Get(profile())->IsAppRestorable(extension_id_))
-    apps::AppLoadService::Get(profile())->RestartApplication(extension_id_);
+  apps::SavedFilesService::Get(GetProfile())
+      ->ClearQueue(GetProfile()->GetExtensionService()->GetExtensionById(
+            extension_id_, true));
+  if (apps::AppRestoreService::Get(GetProfile())
+          ->IsAppRestorable(extension_id_))
+    apps::AppLoadService::Get(GetProfile())->RestartApplication(extension_id_);
   SendResponse(true);
   Release();
 }
@@ -713,9 +715,9 @@
 
   std::string extension_id = params->item_id;
 
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
   ManagementPolicy* management_policy = system->management_policy();
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
 
   const Extension* extension = service->GetInstalledExtension(extension_id);
   if (!extension ||
@@ -728,7 +730,7 @@
   if (params->enable) {
     ExtensionPrefs* prefs = service->extension_prefs();
     if (prefs->DidExtensionEscalatePermissions(extension_id)) {
-      ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
+      ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
       CHECK(registry);
       ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
           render_view_host());
@@ -769,7 +771,7 @@
     std::string extension_id,
     std::vector<std::string> requirements_errors) {
   if (requirements_errors.empty()) {
-    ExtensionService* service = profile()->GetExtensionService();
+    ExtensionService* service = GetProfile()->GetExtensionService();
     service->EnableExtension(extension_id);
   } else {
     ExtensionErrorReporter::GetInstance()->ReportError(
@@ -793,7 +795,7 @@
   if (render_process_id == -1) {
     // This is a lazy background page. Identify if it is a normal
     // or incognito background page.
-    ExtensionService* service = profile()->GetExtensionService();
+    ExtensionService* service = GetProfile()->GetExtensionService();
     if (options.incognito)
       service = ExtensionSystem::Get(
           service->profile()->GetOffTheRecordProfile())->extension_service();
@@ -801,7 +803,7 @@
         options.extension_id);
     DCHECK(extension);
     // Wakes up the background page and  opens the inspect window.
-    devtools_util::InspectBackgroundPage(extension, profile());
+    devtools_util::InspectBackgroundPage(extension, GetProfile());
     return false;
   }
 
@@ -829,7 +831,7 @@
   AddRef();
   bool result = ShowPicker(
       ui::SelectFileDialog::SELECT_FOLDER,
-      DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(),
+      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
       select_title,
       ui::SelectFileDialog::FileTypeInfo(),
       0);
@@ -838,9 +840,9 @@
 
 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
     const base::FilePath& path) {
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   UnpackedInstaller::Create(service)->Load(path);
-  DeveloperPrivateAPI::Get(profile())->SetLastUnpackedDirectory(path);
+  DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path);
   SendResponse(true);
   Release();
 }
@@ -856,7 +858,7 @@
     const string16& select_title,
     const ui::SelectFileDialog::FileTypeInfo& info,
     int file_type_index) {
-  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
+  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
   DCHECK(registry);
   ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
       render_view_host());
@@ -970,10 +972,11 @@
     return false;
   }
 
-  context_ = content::BrowserContext::GetStoragePartition(profile(),
-      render_view_host()->GetSiteInstance())->GetFileSystemContext();
+  context_ = content::BrowserContext::GetStoragePartition(
+      GetProfile(), render_view_host()->GetSiteInstance())
+                 ->GetFileSystemContext();
 
-  base::FilePath project_path(profile()->GetPath());
+  base::FilePath project_path(GetProfile()->GetPath());
   project_path = project_path.Append(kUnpackedAppsFolder);
   project_path = project_path.Append(project_name);
 
@@ -1132,11 +1135,11 @@
     return false;
   }
 
-  base::FilePath path(profile()->GetPath());
+  base::FilePath path(GetProfile()->GetPath());
   path = path.Append(kUnpackedAppsFolder);
   // TODO(grv) : Sanitize / check project_name.
   path = path.Append(project_name);
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   UnpackedInstaller::Create(service)->Load(path);
 
   const ExtensionSet* extensions = service->extensions();
@@ -1204,7 +1207,7 @@
   AddRef();
   bool result = ShowPicker(
       type,
-      DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(),
+      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
       select_title,
       info,
       file_type_index);
@@ -1340,7 +1343,7 @@
 DeveloperPrivateGetStringsFunction::~DeveloperPrivateGetStringsFunction() {}
 
 bool DeveloperPrivateIsProfileManagedFunction::RunImpl() {
-  SetResult(new base::FundamentalValue(profile_->IsManaged()));
+  SetResult(new base::FundamentalValue(GetProfile()->IsManaged()));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index ac5dc5c..e5f0721 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -8,8 +8,8 @@
 #include "base/platform_file.h"
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/extensions/pack_extension_job.h"
@@ -116,7 +116,7 @@
 
 namespace api {
 
-class DeveloperPrivateAutoUpdateFunction : public SyncExtensionFunction {
+class DeveloperPrivateAutoUpdateFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.autoUpdate",
                              DEVELOPERPRIVATE_AUTOUPDATE)
@@ -128,7 +128,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DeveloperPrivateGetItemsInfoFunction : public AsyncExtensionFunction {
+class DeveloperPrivateGetItemsInfoFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.getItemsInfo",
                              DEVELOPERPRIVATE_GETITEMSINFO)
@@ -171,7 +172,7 @@
       bool generated_background_page);
 };
 
-class DeveloperPrivateInspectFunction : public SyncExtensionFunction {
+class DeveloperPrivateInspectFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.inspect",
                              DEVELOPERPRIVATE_INSPECT)
@@ -183,7 +184,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DeveloperPrivateAllowFileAccessFunction : public SyncExtensionFunction {
+class DeveloperPrivateAllowFileAccessFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.allowFileAccess",
                              DEVELOPERPRIVATE_ALLOWFILEACCESS);
@@ -195,7 +197,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DeveloperPrivateAllowIncognitoFunction : public SyncExtensionFunction {
+class DeveloperPrivateAllowIncognitoFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.allowIncognito",
                              DEVELOPERPRIVATE_ALLOWINCOGNITO);
@@ -207,7 +210,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DeveloperPrivateReloadFunction : public SyncExtensionFunction {
+class DeveloperPrivateReloadFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.reload",
                              DEVELOPERPRIVATE_RELOAD);
@@ -220,7 +223,7 @@
 };
 
 class DeveloperPrivateShowPermissionsDialogFunction
-    : public SyncExtensionFunction,
+    : public ChromeSyncExtensionFunction,
       public ExtensionInstallPrompt::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.showPermissionsDialog",
@@ -243,7 +246,7 @@
 };
 
 class DeveloperPrivateEnableFunction
-    : public SyncExtensionFunction,
+    : public ChromeSyncExtensionFunction,
       public base::SupportsWeakPtr<DeveloperPrivateEnableFunction> {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.enable",
@@ -264,7 +267,7 @@
   scoped_ptr<extensions::RequirementsChecker> requirements_checker_;
 };
 
-class DeveloperPrivateChooseEntryFunction : public AsyncExtensionFunction,
+class DeveloperPrivateChooseEntryFunction : public ChromeAsyncExtensionFunction,
                                             public EntryPickerClient {
  protected:
   virtual ~DeveloperPrivateChooseEntryFunction();
@@ -312,7 +315,7 @@
 };
 
 class DeveloperPrivatePackDirectoryFunction
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public extensions::PackExtensionJob::Client {
 
  public:
@@ -338,7 +341,7 @@
   std::string key_path_str_;
 };
 
-class DeveloperPrivateGetStringsFunction : public SyncExtensionFunction {
+class DeveloperPrivateGetStringsFunction : public ChromeSyncExtensionFunction {
   public:
    DECLARE_EXTENSION_FUNCTION("developerPrivate.getStrings",
                               DEVELOPERPRIVATE_GETSTRINGS);
@@ -350,7 +353,8 @@
    virtual bool RunImpl() OVERRIDE;
 };
 
-class DeveloperPrivateIsProfileManagedFunction : public SyncExtensionFunction {
+class DeveloperPrivateIsProfileManagedFunction
+    : public ChromeSyncExtensionFunction {
   public:
    DECLARE_EXTENSION_FUNCTION("developerPrivate.isProfileManaged",
                               DEVELOPERPRIVATE_ISPROFILEMANAGED);
@@ -363,7 +367,7 @@
 };
 
 class DeveloperPrivateExportSyncfsFolderToLocalfsFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
   public:
    DECLARE_EXTENSION_FUNCTION("developerPrivate.exportSyncfsFolderToLocalfs",
                               DEVELOPERPRIVATE_LOADUNPACKEDCROS);
@@ -408,7 +412,8 @@
    bool success_;
 };
 
-class DeveloperPrivateLoadProjectFunction : public AsyncExtensionFunction {
+class DeveloperPrivateLoadProjectFunction
+    : public ChromeAsyncExtensionFunction {
   public:
    DECLARE_EXTENSION_FUNCTION("developerPrivate.loadProject",
                               DEVELOPERPRIVATE_LOADPROJECT);
diff --git a/chrome/browser/extensions/api/dial/dial_api.cc b/chrome/browser/extensions/api/dial/dial_api.cc
index c018f31..303f8e7 100644
--- a/chrome/browser/extensions/api/dial/dial_api.cc
+++ b/chrome/browser/extensions/api/dial/dial_api.cc
@@ -153,8 +153,8 @@
 
 bool DialDiscoverNowFunction::Prepare() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(profile());
-  dial_ = DialAPIFactory::GetForProfile(profile()).get();
+  DCHECK(GetProfile());
+  dial_ = DialAPIFactory::GetForProfile(GetProfile()).get();
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/discovery/discovery_api.cc b/chrome/browser/extensions/api/discovery/discovery_api.cc
index 846e065..181ce56 100644
--- a/chrome/browser/extensions/api/discovery/discovery_api.cc
+++ b/chrome/browser/extensions/api/discovery/discovery_api.cc
@@ -40,7 +40,7 @@
     url_image = params->details.url_image.get();
 
   extensions::SuggestedLinksRegistry* registry =
-      extensions::SuggestedLinksRegistryFactory::GetForProfile(profile());
+      extensions::SuggestedLinksRegistryFactory::GetForProfile(GetProfile());
   scoped_ptr<extensions::SuggestedLink> suggested_link(
       new extensions::SuggestedLink(params->details.link_url,
                                     params->details.link_text,
@@ -56,7 +56,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   extensions::SuggestedLinksRegistry* registry =
-      extensions::SuggestedLinksRegistryFactory::GetForProfile(profile());
+      extensions::SuggestedLinksRegistryFactory::GetForProfile(GetProfile());
   registry->Remove(extension_id(), params->link_url);
 
   return true;
@@ -64,7 +64,7 @@
 
 bool DiscoveryClearAllSuggestionsFunction::RunImpl() {
   extensions::SuggestedLinksRegistry* registry =
-      extensions::SuggestedLinksRegistryFactory::GetForProfile(profile());
+      extensions::SuggestedLinksRegistryFactory::GetForProfile(GetProfile());
   registry->ClearAll(extension_id());
 
   return true;
diff --git a/chrome/browser/extensions/api/discovery/discovery_api.h b/chrome/browser/extensions/api/discovery/discovery_api.h
index 9336761..bc20095 100644
--- a/chrome/browser/extensions/api/discovery/discovery_api.h
+++ b/chrome/browser/extensions/api/discovery/discovery_api.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_DISCOVERY_DISCOVERY_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_DISCOVERY_DISCOVERY_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
-class DiscoverySuggestFunction : public SyncExtensionFunction {
+class DiscoverySuggestFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("experimental.discovery.suggest",
                              EXPERIMENTAL_DISCOVERY_SUGGEST)
@@ -19,7 +19,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DiscoveryRemoveSuggestionFunction : public SyncExtensionFunction {
+class DiscoveryRemoveSuggestionFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("experimental.discovery.removeSuggestion",
                              EXPERIMENTAL_DISCOVERY_REMOVESUGGESTION)
@@ -29,7 +29,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class DiscoveryClearAllSuggestionsFunction : public SyncExtensionFunction {
+class DiscoveryClearAllSuggestionsFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("experimental.discovery.clearAllSuggestions",
                              EXPERIMENTAL_DISCOVERY_CLEARALLSUGGESTIONS)
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index f172419..4544f58 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -967,9 +967,9 @@
   if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_))
     return false;
 
-  Profile* current_profile = profile();
-  if (include_incognito() && profile()->HasOffTheRecordProfile())
-    current_profile = profile()->GetOffTheRecordProfile();
+  Profile* current_profile = GetProfile();
+  if (include_incognito() && GetProfile()->HasOffTheRecordProfile())
+    current_profile = GetProfile()->GetOffTheRecordProfile();
 
   scoped_ptr<content::DownloadUrlParameters> download_params(
       new content::DownloadUrlParameters(
@@ -1077,7 +1077,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
-  GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+  GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager);
   ManagerDestructionObserver::CheckForHistoryFilesRemoval(incognito_manager);
   DownloadQuery::DownloadVector results;
@@ -1096,9 +1096,10 @@
     uint32 download_id = download_item->GetId();
     bool off_record = ((incognito_manager != NULL) &&
                        (incognito_manager->GetDownload(download_id) != NULL));
-    scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON(
-        *it, off_record ? profile()->GetOffTheRecordProfile()
-                        : profile()->GetOriginalProfile()));
+    scoped_ptr<base::DictionaryValue> json_item(
+        DownloadItemToJSON(*it,
+                           off_record ? GetProfile()->GetOffTheRecordProfile()
+                                      : GetProfile()->GetOriginalProfile()));
     json_results->Append(json_item.release());
   }
   SetResult(json_results);
@@ -1114,8 +1115,8 @@
   scoped_ptr<downloads::Pause::Params> params(
       downloads::Pause::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
             errors::kNotInProgress, &error_))
@@ -1135,8 +1136,8 @@
   scoped_ptr<downloads::Resume::Params> params(
       downloads::Resume::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->IsPaused() && !download_item->CanResume(),
             errors::kNotResumable, &error_))
@@ -1156,8 +1157,8 @@
   scoped_ptr<downloads::Resume::Params> params(
       downloads::Resume::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (download_item &&
       (download_item->GetState() == DownloadItem::IN_PROGRESS))
     download_item->Cancel(true);
@@ -1177,7 +1178,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
-  GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+  GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   DownloadQuery::DownloadVector results;
   RunDownloadQuery(params->query,
                    manager,
@@ -1211,8 +1212,8 @@
   scoped_ptr<downloads::RemoveFile::Params> params(
       downloads::RemoveFile::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_) ||
       Fault((download_item->GetState() != DownloadItem::COMPLETE),
             errors::kNotComplete, &error_) ||
@@ -1260,8 +1261,8 @@
 }
 
 void DownloadsAcceptDangerFunction::PromptOrWait(int download_id, int retries) {
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), download_id);
   content::WebContents* web_contents =
       dispatcher()->delegate()->GetVisibleWebContents();
   if (InvalidId(download_item, &error_) ||
@@ -1305,8 +1306,8 @@
 void DownloadsAcceptDangerFunction::DangerPromptCallback(
     int download_id, DownloadDangerPrompt::Action action) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), download_id);
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
             errors::kNotInProgress, &error_))
@@ -1332,8 +1333,8 @@
   scoped_ptr<downloads::Show::Params> params(
       downloads::Show::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_))
     return false;
   download_item->ShowDownloadInShell();
@@ -1348,7 +1349,7 @@
 bool DownloadsShowDefaultFolderFunction::RunImpl() {
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
-  GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+  GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   platform_util::OpenItem(DownloadPrefs::FromDownloadManager(
       manager)->DownloadPath());
   RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER);
@@ -1363,8 +1364,8 @@
   scoped_ptr<downloads::Open::Params> params(
       downloads::Open::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->GetState() != DownloadItem::COMPLETE,
             errors::kNotComplete, &error_) ||
@@ -1385,8 +1386,8 @@
   scoped_ptr<downloads::Drag::Params> params(
       downloads::Drag::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   content::WebContents* web_contents =
       dispatcher()->delegate()->GetVisibleWebContents();
   if (InvalidId(download_item, &error_) ||
@@ -1422,7 +1423,7 @@
   RecordApiFunctions(DOWNLOADS_FUNCTION_SET_SHELF_ENABLED);
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
-  GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+  GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   DownloadService* service = NULL;
   DownloadService* incognito_service = NULL;
   if (manager) {
@@ -1484,8 +1485,8 @@
   int icon_size = kDefaultIconSize;
   if (options && options->size.get())
     icon_size = *options->size.get();
-  DownloadItem* download_item = GetDownload(
-      profile(), include_incognito(), params->download_id);
+  DownloadItem* download_item =
+      GetDownload(GetProfile(), include_incognito(), params->download_id);
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->GetTargetFilePath().empty(),
             errors::kEmptyFile, &error_))
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 6dce424..5542058 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -15,8 +15,8 @@
 #include "chrome/browser/download/all_download_item_notifier.h"
 #include "chrome/browser/download/download_danger_prompt.h"
 #include "chrome/browser/download/download_path_reservation_tracker.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/extensions/extension_warning_set.h"
 #include "chrome/common/extensions/api/downloads.h"
 #include "content/public/browser/download_item.h"
@@ -85,7 +85,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadedByExtension);
 };
 
-class DownloadsDownloadFunction : public AsyncExtensionFunction {
+class DownloadsDownloadFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.download", DOWNLOADS_DOWNLOAD)
   DownloadsDownloadFunction();
@@ -105,7 +105,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsDownloadFunction);
 };
 
-class DownloadsSearchFunction : public SyncExtensionFunction {
+class DownloadsSearchFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.search", DOWNLOADS_SEARCH)
   DownloadsSearchFunction();
@@ -118,7 +118,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsSearchFunction);
 };
 
-class DownloadsPauseFunction : public SyncExtensionFunction {
+class DownloadsPauseFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.pause", DOWNLOADS_PAUSE)
   DownloadsPauseFunction();
@@ -131,7 +131,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsPauseFunction);
 };
 
-class DownloadsResumeFunction : public SyncExtensionFunction {
+class DownloadsResumeFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.resume", DOWNLOADS_RESUME)
   DownloadsResumeFunction();
@@ -144,7 +144,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsResumeFunction);
 };
 
-class DownloadsCancelFunction : public SyncExtensionFunction {
+class DownloadsCancelFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.cancel", DOWNLOADS_CANCEL)
   DownloadsCancelFunction();
@@ -157,7 +157,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsCancelFunction);
 };
 
-class DownloadsEraseFunction : public SyncExtensionFunction {
+class DownloadsEraseFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.erase", DOWNLOADS_ERASE)
   DownloadsEraseFunction();
@@ -170,7 +170,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsEraseFunction);
 };
 
-class DownloadsRemoveFileFunction : public AsyncExtensionFunction,
+class DownloadsRemoveFileFunction : public ChromeAsyncExtensionFunction,
                                     public content::DownloadItem::Observer {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.removeFile", DOWNLOADS_REMOVEFILE)
@@ -189,7 +189,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsRemoveFileFunction);
 };
 
-class DownloadsAcceptDangerFunction : public AsyncExtensionFunction {
+class DownloadsAcceptDangerFunction : public ChromeAsyncExtensionFunction {
  public:
   typedef base::Callback<void(DownloadDangerPrompt*)> OnPromptCreatedCallback;
   static void OnPromptCreatedForTesting(
@@ -213,7 +213,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsAcceptDangerFunction);
 };
 
-class DownloadsShowFunction : public AsyncExtensionFunction {
+class DownloadsShowFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.show", DOWNLOADS_SHOW)
   DownloadsShowFunction();
@@ -226,7 +226,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsShowFunction);
 };
 
-class DownloadsShowDefaultFolderFunction : public AsyncExtensionFunction {
+class DownloadsShowDefaultFolderFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION(
       "downloads.showDefaultFolder", DOWNLOADS_SHOWDEFAULTFOLDER)
@@ -240,7 +240,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsShowDefaultFolderFunction);
 };
 
-class DownloadsOpenFunction : public SyncExtensionFunction {
+class DownloadsOpenFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.open", DOWNLOADS_OPEN)
   DownloadsOpenFunction();
@@ -253,7 +253,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsOpenFunction);
 };
 
-class DownloadsSetShelfEnabledFunction : public SyncExtensionFunction {
+class DownloadsSetShelfEnabledFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
                              DOWNLOADS_SETSHELFENABLED)
@@ -267,7 +267,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsSetShelfEnabledFunction);
 };
 
-class DownloadsDragFunction : public AsyncExtensionFunction {
+class DownloadsDragFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.drag", DOWNLOADS_DRAG)
   DownloadsDragFunction();
@@ -280,7 +280,7 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsDragFunction);
 };
 
-class DownloadsGetFileIconFunction : public AsyncExtensionFunction {
+class DownloadsGetFileIconFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
   DownloadsGetFileIconFunction();
diff --git a/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.cc b/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.cc
index a362f9d..cb12918 100644
--- a/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.cc
+++ b/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.cc
@@ -26,13 +26,13 @@
   base::FilePath::StringType filename;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filename));
   return ExtensionDownloadsEventRouter::DetermineFilename(
-      profile(),
+      GetProfile(),
       include_incognito(),
       GetExtension()->id(),
       params->download_id,
       base::FilePath(filename),
       extensions::api::downloads::ParseFilenameConflictAction(
-        params->conflict_action),
+          params->conflict_action),
       &error_);
 }
 
diff --git a/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.h b/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.h
index 3459fbe..a88364e 100644
--- a/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.h
+++ b/chrome/browser/extensions/api/downloads_internal/downloads_internal_api.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_INTERNAL_DOWNLOADS_INTERNAL_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_INTERNAL_DOWNLOADS_INTERNAL_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
 class DownloadsInternalDetermineFilenameFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloadsInternal.determineFilename",
                              DOWNLOADSINTERNAL_DETERMINEFILENAME);
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
index b1078c6..58258ce 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -113,7 +113,7 @@
 
 bool EPKPChallengeKeyBase::IsExtensionWhitelisted() const {
   const base::ListValue* list =
-      profile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist);
+      GetProfile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist);
   StringValue value(extension_->id());
   return list->Find(value) != list->end();
 }
@@ -133,7 +133,7 @@
 
 std::string EPKPChallengeKeyBase::GetUserEmail() const {
   SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(profile());
+      SigninManagerFactory::GetForProfile(GetProfile());
   if (!signin_manager)
     return std::string();
 
@@ -521,7 +521,7 @@
 }
 
 bool EPKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const {
-  return profile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
+  return GetProfile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
index 80e6b9f..6c82979 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/enterprise_platform_keys_private.h"
 #include "chromeos/attestation/attestation_constants.h"
 #include "chromeos/attestation/attestation_flow.h"
@@ -38,7 +38,7 @@
 
 namespace extensions {
 
-class EPKPChallengeKeyBase : public AsyncExtensionFunction {
+class EPKPChallengeKeyBase : public ChromeAsyncExtensionFunction {
  public:
   static const char kChallengeBadBase64Error[];
   static const char kDevicePolicyDisabledError[];
diff --git a/chrome/browser/extensions/api/execute_code_function.h b/chrome/browser/extensions/api/execute_code_function.h
index 6d2d420..bd70ff9 100644
--- a/chrome/browser/extensions/api/execute_code_function.h
+++ b/chrome/browser/extensions/api/execute_code_function.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_EXECUTE_CODE_FUNCTION_H_
 #define CHROME_BROWSER_EXTENSIONS_API_EXECUTE_CODE_FUNCTION_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/script_executor.h"
 #include "chrome/common/extensions/api/tabs.h"
 
@@ -14,7 +14,7 @@
 // Base class for javascript code injection.
 // This is used by both chrome.webview.executeScript and
 // chrome.tabs.executeScript.
-class ExecuteCodeFunction : public AsyncExtensionFunction {
+class ExecuteCodeFunction : public ChromeAsyncExtensionFunction {
  public:
   ExecuteCodeFunction();
 
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
index 0236ca6..a1b0a3b 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -91,6 +91,10 @@
     frame_observer.Wait();
   }
 
+  EXPECT_TRUE(new_browser != NULL);
+
+// Flaky on non-aura linux http://crbug.com/309749
+#if !(defined(OS_LINUX) && !defined(USE_AURA))
   ResultCatcher catcher;
   {
     content::WindowedNotificationObserver frame_observer(
@@ -102,6 +106,7 @@
     EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
   }
   ASSERT_TRUE(catcher.GetNextResult()) << message_;
+#endif
 }
 
 // Tests opening a popup in an incognito window.
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 1024b83..470af85 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -494,7 +494,7 @@
 }
 
 bool ExtensionActionFunction::RunImpl() {
-  ExtensionActionManager* manager = ExtensionActionManager::Get(profile_);
+  ExtensionActionManager* manager = ExtensionActionManager::Get(GetProfile());
   const Extension* extension = GetExtension();
   if (StartsWithASCII(name(), "scriptBadge.", false)) {
     extension_action_ = manager->GetScriptBadge(*extension);
@@ -519,8 +519,13 @@
 
   // Find the WebContents that contains this tab id if one is required.
   if (tab_id_ != ExtensionAction::kDefaultTabId) {
-    ExtensionTabUtil::GetTabById(
-        tab_id_, profile(), include_incognito(), NULL, NULL, &contents_, NULL);
+    ExtensionTabUtil::GetTabById(tab_id_,
+                                 GetProfile(),
+                                 include_incognito(),
+                                 NULL,
+                                 NULL,
+                                 &contents_,
+                                 NULL);
     if (!contents_) {
       error_ = ErrorUtils::FormatErrorMessage(
           kNoTabError, base::IntToString(tab_id_));
@@ -587,10 +592,10 @@
   switch (extension_action_->action_type()) {
     case ActionInfo::TYPE_BROWSER:
     case ActionInfo::TYPE_PAGE:
-      if (ExtensionActionManager::Get(profile_)
+      if (ExtensionActionManager::Get(GetProfile())
               ->GetBrowserAction(*extension_.get())) {
         NotifyBrowserActionChange();
-      } else if (ExtensionActionManager::Get(profile_)
+      } else if (ExtensionActionManager::Get(GetProfile())
                      ->GetPageAction(*extension_.get())) {
         NotifyLocationBarChange();
       }
@@ -609,7 +614,7 @@
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
       content::Source<ExtensionAction>(extension_action_),
-      content::Details<Profile>(profile()));
+      content::Details<Profile>(GetProfile()));
 }
 
 void ExtensionActionFunction::NotifyLocationBarChange() {
@@ -620,7 +625,7 @@
 void ExtensionActionFunction::NotifySystemIndicatorChange() {
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED,
-      content::Source<Profile>(profile()),
+      content::Source<Profile>(GetProfile()),
       content::Details<ExtensionAction>(extension_action_));
 }
 
@@ -814,8 +819,9 @@
 }
 
 bool BrowserActionOpenPopupFunction::RunImpl() {
-  ExtensionToolbarModel* model = extensions::ExtensionSystem::Get(profile_)->
-      extension_service()->toolbar_model();
+  ExtensionToolbarModel* model = extensions::ExtensionSystem::Get(GetProfile())
+                                     ->extension_service()
+                                     ->toolbar_model();
   if (!model) {
     error_ = kInternalError;
     return false;
@@ -826,8 +832,9 @@
     return false;
   }
 
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
-      content::Source<Profile>(profile_));
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
+                 content::Source<Profile>(GetProfile()));
 
   // Set a timeout for waiting for the notification that the popup is loaded.
   // Waiting is required so that the popup view can be retrieved by the custom
@@ -911,9 +918,8 @@
           page_actions_keys::kTitleKey, &title));
   }
 
-  ExtensionAction* page_action =
-      extensions::ExtensionActionManager::Get(profile())->
-      GetPageAction(*GetExtension());
+  ExtensionAction* page_action = extensions::ExtensionActionManager::Get(
+      GetProfile())->GetPageAction(*GetExtension());
   if (!page_action) {
     error_ = extensions::kNoPageActionError;
     return false;
@@ -922,7 +928,7 @@
   // Find the WebContents that contains this tab id.
   WebContents* contents = NULL;
   bool result = ExtensionTabUtil::GetTabById(
-      tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL);
+      tab_id, GetProfile(), include_incognito(), NULL, NULL, &contents, NULL);
   if (!result || !contents) {
     error_ = extensions::ErrorUtils::FormatErrorMessage(
         extensions::kNoTabError, base::IntToString(tab_id));
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chrome/browser/extensions/api/extension_action/extension_action_api.h
index 8471ae3..a8e92dd 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.h
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -9,8 +9,8 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_action.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -120,7 +120,7 @@
 // have required tabIds while browserAction's are optional, they have different
 // internal browser notification requirements, and not all functions are defined
 // for all APIs).
-class ExtensionActionFunction : public SyncExtensionFunction {
+class ExtensionActionFunction : public ChromeSyncExtensionFunction {
  public:
   static bool ParseCSSColorString(const std::string& color_string,
                                   SkColor* result);
@@ -343,7 +343,7 @@
   virtual ~BrowserActionDisableFunction() {}
 };
 
-class BrowserActionOpenPopupFunction : public UIThreadExtensionFunction,
+class BrowserActionOpenPopupFunction : public ChromeAsyncExtensionFunction,
                                        public content::NotificationObserver {
  public:
   DECLARE_EXTENSION_FUNCTION("browserAction.openPopup",
@@ -467,7 +467,7 @@
 };
 
 // Base class for deprecated page actions APIs
-class PageActionsFunction : public SyncExtensionFunction {
+class PageActionsFunction : public ChromeSyncExtensionFunction {
  protected:
   PageActionsFunction();
   virtual ~PageActionsFunction();
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
index 8e7ecba..ce46532 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -7,6 +7,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/feedback_private/feedback_service.h"
@@ -18,6 +19,19 @@
 #include "ui/base/webui/web_ui_util.h"
 #include "url/url_util.h"
 
+namespace {
+
+// Getting the filename of a blob prepends a "C:\fakepath" to the filename.
+// This is undesirable, strip it if it exists.
+std::string StripFakepath(const std::string& path) {
+  const char kFakePathStr[] = "C:\\fakepath\\";
+  if (StartsWithASCII(path, kFakePathStr, false))
+    return path.substr(arraysize(kFakePathStr) - 1);
+  return path;
+}
+
+}  // namespace
+
 namespace extensions {
 
 namespace feedback_private = api::feedback_private;
@@ -117,9 +131,9 @@
 bool FeedbackPrivateGetUserEmailFunction::RunImpl() {
   // TODO(rkc): Remove logging once crbug.com/284662 is closed.
   LOG(WARNING) << "FEEDBACK_DEBUG: User e-mail requested.";
-  FeedbackService* service =
-      FeedbackPrivateAPI::GetFactoryInstance()->GetForProfile(
-          profile())->GetService();
+  FeedbackService* service = FeedbackPrivateAPI::GetFactoryInstance()
+                                 ->GetForProfile(GetProfile())
+                                 ->GetService();
   DCHECK(service);
   SetResult(new base::StringValue(service->GetUserEmail()));
   return true;
@@ -128,9 +142,9 @@
 bool FeedbackPrivateGetSystemInformationFunction::RunImpl() {
   // TODO(rkc): Remove logging once crbug.com/284662 is closed.
   LOG(WARNING) << "FEEDBACK_DEBUG: System information requested.";
-  FeedbackService* service =
-      FeedbackPrivateAPI::GetFactoryInstance()->GetForProfile(
-          profile())->GetService();
+  FeedbackService* service = FeedbackPrivateAPI::GetFactoryInstance()
+                                 ->GetForProfile(GetProfile())
+                                 ->GetService();
   DCHECK(service);
   service->GetSystemInformation(
       base::Bind(
@@ -164,7 +178,7 @@
 
   // Populate feedback data.
   scoped_refptr<FeedbackData> feedback_data(new FeedbackData());
-  feedback_data->set_profile(profile_);
+  feedback_data->set_profile(GetProfile());
   feedback_data->set_description(feedback_info.description);
 
   if (feedback_info.category_tag.get())
@@ -176,7 +190,7 @@
 
   if (!attached_file_uuid.empty()) {
     feedback_data->set_attached_filename(
-        (*feedback_info.attached_file.get()).name);
+        StripFakepath((*feedback_info.attached_file.get()).name));
     feedback_data->set_attached_file_uuid(attached_file_uuid);
   }
 
@@ -197,13 +211,14 @@
   }
   feedback_data->SetAndCompressSystemInfo(sys_logs.Pass());
 
-  FeedbackService* service = FeedbackPrivateAPI::GetFactoryInstance()->
-      GetForProfile(profile())->GetService();
+  FeedbackService* service = FeedbackPrivateAPI::GetFactoryInstance()
+                                 ->GetForProfile(GetProfile())
+                                 ->GetService();
   DCHECK(service);
-  service->SendFeedback(profile(),
-      feedback_data, base::Bind(
-          &FeedbackPrivateSendFeedbackFunction::OnCompleted,
-          this));
+  service->SendFeedback(
+      GetProfile(),
+      feedback_data,
+      base::Bind(&FeedbackPrivateSendFeedbackFunction::OnCompleted, this));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
index a4ac045..e11808e 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_API_H_
 
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/feedback_private.h"
 #include "ui/gfx/rect.h"
 
@@ -46,7 +46,7 @@
 };
 
 // Feedback strings.
-class FeedbackPrivateGetStringsFunction : public SyncExtensionFunction {
+class FeedbackPrivateGetStringsFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getStrings",
                              FEEDBACKPRIVATE_GETSTRINGS)
@@ -66,7 +66,7 @@
   static base::Closure* test_callback_;
 };
 
-class FeedbackPrivateGetUserEmailFunction : public SyncExtensionFunction {
+class FeedbackPrivateGetUserEmailFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getUserEmail",
                              FEEDBACKPRIVATE_GETUSEREMAIL);
@@ -77,7 +77,7 @@
 };
 
 class FeedbackPrivateGetSystemInformationFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getSystemInformation",
                              FEEDBACKPRIVATE_GETSYSTEMINFORMATION);
@@ -91,7 +91,8 @@
       const std::vector<linked_ptr<SystemInformation> >& sys_info);
 };
 
-class FeedbackPrivateSendFeedbackFunction : public AsyncExtensionFunction {
+class FeedbackPrivateSendFeedbackFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("feedbackPrivate.sendFeedback",
                              FEEDBACKPRIVATE_SENDFEEDBACK);
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service.cc b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
index b16f1ad..7e79275 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
@@ -67,7 +67,7 @@
   if (!data.get())
     feedback_data_->set_attached_file_uuid(std::string());
   else
-    feedback_data_->set_attached_filedata(data.Pass());
+    feedback_data_->AttachAndCompressFileData(data.Pass());
 
   CompleteSendFeedback();
 }
@@ -93,7 +93,7 @@
       feedback_data_->attached_file_uuid().empty() ||
       feedback_data_->attached_filedata();
   bool screenshot_completed =
-      !feedback_data_->screenshot_uuid().empty() ||
+      feedback_data_->screenshot_uuid().empty() ||
       feedback_data_->image();
 
   if (screenshot_completed && attached_file_completed) {
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index 93a2a2f..3397850 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -329,7 +329,7 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   app_file_handler_util::CheckWritableFiles(
       paths,
-      profile_,
+      GetProfile(),
       is_directory_,
       base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
                  this,
@@ -366,7 +366,7 @@
   DCHECK(response_);
   extensions::app_file_handler_util::GrantedFileEntry file_entry =
       extensions::app_file_handler_util::CreateFileEntry(
-          profile(),
+          GetProfile(),
           GetExtension(),
           render_view_host_->GetProcess()->GetID(),
           path,
@@ -587,7 +587,7 @@
   content::WebContents* web_contents = NULL;
   if (extension_->is_platform_app()) {
     apps::ShellWindowRegistry* registry =
-        apps::ShellWindowRegistry::Get(profile());
+        apps::ShellWindowRegistry::Get(GetProfile());
     DCHECK(registry);
     ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
         render_view_host());
@@ -697,14 +697,15 @@
   } else {
     last_choose_directory = paths[0].DirName();
   }
-  file_system_api::SetLastChooseEntryDirectory(ExtensionPrefs::Get(profile()),
-                                               GetExtension()->id(),
-                                               last_choose_directory);
+  file_system_api::SetLastChooseEntryDirectory(
+      ExtensionPrefs::Get(GetProfile()),
+      GetExtension()->id(),
+      last_choose_directory);
   if (is_directory_) {
     // Get the WebContents for the app window to be the parent window of the
     // confirmation dialog if necessary.
     apps::ShellWindowRegistry* registry =
-        apps::ShellWindowRegistry::Get(profile());
+        apps::ShellWindowRegistry::Get(GetProfile());
     DCHECK(registry);
     ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
         render_view_host());
@@ -915,9 +916,7 @@
 
   base::FilePath previous_path;
   file_system_api::GetLastChooseEntryDirectory(
-      ExtensionPrefs::Get(profile()),
-      GetExtension()->id(),
-      &previous_path);
+      ExtensionPrefs::Get(GetProfile()), GetExtension()->id(), &previous_path);
 
   content::BrowserThread::PostTaskAndReply(
       content::BrowserThread::FILE,
@@ -934,7 +933,7 @@
 bool FileSystemRetainEntryFunction::RunImpl() {
   std::string entry_id;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
-  SavedFilesService* saved_files_service = SavedFilesService::Get(profile());
+  SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
   // Add the file to the retain list if it is not already on there.
   if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) {
     std::string filesystem_name;
@@ -966,7 +965,7 @@
 
 void FileSystemRetainEntryFunction::RetainFileEntry(
     const std::string& entry_id) {
-  SavedFilesService* saved_files_service = SavedFilesService::Get(profile());
+  SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
   saved_files_service->RegisterFileEntry(
       extension_->id(), entry_id, path_, is_directory_);
   saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
@@ -981,7 +980,7 @@
   std::string entry_id;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
   SetResult(new base::FundamentalValue(SavedFilesService::Get(
-      profile())->IsRegistered(extension_->id(), entry_id)));
+      GetProfile())->IsRegistered(extension_->id(), entry_id)));
   return true;
 }
 
@@ -991,14 +990,14 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry));
   const SavedFileEntry* file_entry = SavedFilesService::Get(
-      profile())->GetFileEntry(extension_->id(), entry_id);
+      GetProfile())->GetFileEntry(extension_->id(), entry_id);
   if (!file_entry) {
     error_ = kUnknownIdError;
     return false;
   }
 
-  SavedFilesService::Get(profile())->EnqueueFileEntry(
-      extension_->id(), entry_id);
+  SavedFilesService::Get(GetProfile())
+      ->EnqueueFileEntry(extension_->id(), entry_id);
 
   // Only create a new file entry if the renderer requests one.
   // |needs_new_entry| will be false if the renderer already has an Entry for
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.h b/chrome/browser/extensions/api/file_system/file_system_api.h
index ce3ccea..52f516f 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.h
+++ b/chrome/browser/extensions/api/file_system/file_system_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/file_system.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
@@ -33,7 +33,7 @@
 
 }  // namespace file_system_api
 
-class FileSystemGetDisplayPathFunction : public SyncExtensionFunction {
+class FileSystemGetDisplayPathFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileSystem.getDisplayPath",
                              FILESYSTEM_GETDISPLAYPATH)
@@ -43,7 +43,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class FileSystemEntryFunction : public AsyncExtensionFunction {
+class FileSystemEntryFunction : public ChromeAsyncExtensionFunction {
  protected:
   FileSystemEntryFunction();
 
@@ -98,7 +98,7 @@
   base::FilePath path_;
 };
 
-class FileSystemIsWritableEntryFunction : public SyncExtensionFunction {
+class FileSystemIsWritableEntryFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileSystem.isWritableEntry",
                              FILESYSTEM_ISWRITABLEENTRY)
@@ -170,7 +170,7 @@
   base::FilePath initial_path_;
 };
 
-class FileSystemRetainEntryFunction : public AsyncExtensionFunction {
+class FileSystemRetainEntryFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileSystem.retainEntry", FILESYSTEM_RETAINENTRY)
 
@@ -192,7 +192,7 @@
   base::FilePath path_;
 };
 
-class FileSystemIsRestorableFunction : public SyncExtensionFunction {
+class FileSystemIsRestorableFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileSystem.isRestorable", FILESYSTEM_ISRESTORABLE)
 
diff --git a/chrome/browser/extensions/api/font_settings/font_settings_api.cc b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
index 2152270..8692336 100644
--- a/chrome/browser/extensions/api/font_settings/font_settings_api.cc
+++ b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
@@ -220,7 +220,7 @@
 }
 
 bool FontSettingsClearFontFunction::RunImpl() {
-  if (profile_->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = kSetFromIncognitoError;
     return false;
   }
@@ -234,9 +234,9 @@
 
   // Ensure |pref_path| really is for a registered per-script font pref.
   EXTENSION_FUNCTION_VALIDATE(
-      profile_->GetPrefs()->FindPreference(pref_path.c_str()));
+      GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
 
-  PreferenceAPI::Get(profile_)->RemoveExtensionControlledPref(
+  PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
       extension_id(), pref_path.c_str(), kExtensionPrefsScopeRegular);
   return true;
 }
@@ -249,7 +249,7 @@
   std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
                                               params->details.script);
 
-  PrefService* prefs = profile_->GetPrefs();
+  PrefService* prefs = GetProfile()->GetPrefs();
   const PrefService::Preference* pref =
       prefs->FindPreference(pref_path.c_str());
 
@@ -262,10 +262,8 @@
   // getting level of control.
   const bool kIncognito = false;
   std::string level_of_control =
-      extensions::preference_helpers::GetLevelOfControl(profile_,
-                                                        extension_id(),
-                                                        pref_path,
-                                                        kIncognito);
+      extensions::preference_helpers::GetLevelOfControl(
+          GetProfile(), extension_id(), pref_path, kIncognito);
 
   base::DictionaryValue* result = new base::DictionaryValue();
   result->SetString(kFontIdKey, font_name);
@@ -275,7 +273,7 @@
 }
 
 bool FontSettingsSetFontFunction::RunImpl() {
-  if (profile_->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = kSetFromIncognitoError;
     return false;
   }
@@ -289,9 +287,9 @@
 
   // Ensure |pref_path| really is for a registered font pref.
   EXTENSION_FUNCTION_VALIDATE(
-      profile_->GetPrefs()->FindPreference(pref_path.c_str()));
+      GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
 
-  PreferenceAPI::Get(profile_)->SetExtensionControlledPref(
+  PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
       extension_id(),
       pref_path.c_str(),
       kExtensionPrefsScopeRegular,
@@ -345,18 +343,18 @@
 }
 
 bool ClearFontPrefExtensionFunction::RunImpl() {
-  if (profile_->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = kSetFromIncognitoError;
     return false;
   }
 
-  PreferenceAPI::Get(profile_)->RemoveExtensionControlledPref(
+  PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
       extension_id(), GetPrefName(), kExtensionPrefsScopeRegular);
   return true;
 }
 
 bool GetFontPrefExtensionFunction::RunImpl() {
-  PrefService* prefs = profile_->GetPrefs();
+  PrefService* prefs = GetProfile()->GetPrefs();
   const PrefService::Preference* pref = prefs->FindPreference(GetPrefName());
   EXTENSION_FUNCTION_VALIDATE(pref);
 
@@ -365,10 +363,8 @@
   const bool kIncognito = false;
 
   std::string level_of_control =
-      extensions::preference_helpers::GetLevelOfControl(profile_,
-                                                        extension_id(),
-                                                        GetPrefName(),
-                                                        kIncognito);
+      extensions::preference_helpers::GetLevelOfControl(
+          GetProfile(), extension_id(), GetPrefName(), kIncognito);
 
   base::DictionaryValue* result = new base::DictionaryValue();
   result->Set(GetKey(), pref->GetValue()->DeepCopy());
@@ -378,7 +374,7 @@
 }
 
 bool SetFontPrefExtensionFunction::RunImpl() {
-  if (profile_->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = kSetFromIncognitoError;
     return false;
   }
@@ -389,11 +385,11 @@
   Value* value;
   EXTENSION_FUNCTION_VALIDATE(details->Get(GetKey(), &value));
 
-  PreferenceAPI::Get(profile_)->SetExtensionControlledPref(
-      extension_id(),
-      GetPrefName(),
-      kExtensionPrefsScopeRegular,
-      value->DeepCopy());
+  PreferenceAPI::Get(GetProfile())
+      ->SetExtensionControlledPref(extension_id(),
+                                   GetPrefName(),
+                                   kExtensionPrefsScopeRegular,
+                                   value->DeepCopy());
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/font_settings/font_settings_api.h b/chrome/browser/extensions/api/font_settings/font_settings_api.h
index 1955467..497ee35 100644
--- a/chrome/browser/extensions/api/font_settings/font_settings_api.h
+++ b/chrome/browser/extensions/api/font_settings/font_settings_api.h
@@ -14,8 +14,8 @@
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 
 class Profile;
 
@@ -91,7 +91,7 @@
 };
 
 // fontSettings.clearFont API function.
-class FontSettingsClearFontFunction : public SyncExtensionFunction {
+class FontSettingsClearFontFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fontSettings.clearFont", FONTSETTINGS_CLEARFONT)
 
@@ -105,7 +105,7 @@
 };
 
 // fontSettings.getFont API function.
-class FontSettingsGetFontFunction : public SyncExtensionFunction {
+class FontSettingsGetFontFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fontSettings.getFont", FONTSETTINGS_GETFONT)
 
@@ -117,7 +117,7 @@
 };
 
 // fontSettings.setFont API function.
-class FontSettingsSetFontFunction : public SyncExtensionFunction {
+class FontSettingsSetFontFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fontSettings.setFont", FONTSETTINGS_SETFONT)
 
@@ -129,7 +129,7 @@
 };
 
 // fontSettings.getFontList API function.
-class FontSettingsGetFontListFunction : public AsyncExtensionFunction {
+class FontSettingsGetFontListFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fontSettings.getFontList",
                              FONTSETTINGS_GETFONTLIST)
@@ -146,7 +146,7 @@
 };
 
 // Base class for extension API functions that clear a browser font pref.
-class ClearFontPrefExtensionFunction : public SyncExtensionFunction {
+class ClearFontPrefExtensionFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~ClearFontPrefExtensionFunction() {}
 
@@ -159,7 +159,7 @@
 };
 
 // Base class for extension API functions that get a browser font pref.
-class GetFontPrefExtensionFunction : public SyncExtensionFunction {
+class GetFontPrefExtensionFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~GetFontPrefExtensionFunction() {}
 
@@ -176,7 +176,7 @@
 };
 
 // Base class for extension API functions that set a browser font pref.
-class SetFontPrefExtensionFunction : public SyncExtensionFunction {
+class SetFontPrefExtensionFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~SetFontPrefExtensionFunction() {}
 
diff --git a/chrome/browser/extensions/api/history/history_api.cc b/chrome/browser/extensions/api/history/history_api.cc
index d6b08ca..cb75c96 100644
--- a/chrome/browser/extensions/api/history/history_api.cc
+++ b/chrome/browser/extensions/api/history/history_api.cc
@@ -253,7 +253,7 @@
 }
 
 bool HistoryFunction::VerifyDeleteAllowed() {
-  PrefService* prefs = profile()->GetPrefs();
+  PrefService* prefs = GetProfile()->GetPrefs();
   if (!prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory)) {
     error_ = kDeleteProhibitedError;
     return false;
@@ -313,8 +313,8 @@
   int max_results = 100;
   if (params->details.max_results.get())
     max_results = *params->details.max_results;
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(), Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->QueryFilteredURLs(max_results, filter, false, &cancelable_consumer_,
       base::Bind(&HistoryGetMostVisitedFunction::QueryComplete,
                  base::Unretained(this)));
@@ -344,9 +344,8 @@
   if (!ValidateUrl(params->details.url, &url))
     return false;
 
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->QueryURL(url,
                true,  // Retrieve full history of a URL.
                &cancelable_consumer_,
@@ -392,9 +391,8 @@
   if (params->query.max_results.get())
     options.max_count = *params->query.max_results;
 
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->QueryHistory(search_text, options, &cancelable_consumer_,
                    base::Bind(&HistorySearchFunction::SearchComplete,
                               base::Unretained(this)));
@@ -427,9 +425,8 @@
   if (!ValidateUrl(params->details.url, &url))
     return false;
 
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->AddPage(url, base::Time::Now(), history::SOURCE_EXTENSION);
 
   SendResponse(true);
@@ -447,9 +444,8 @@
   if (!ValidateUrl(params->details.url, &url))
     return false;
 
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->DeleteURL(url);
 
   // Also clean out from the activity log. If the activity log testing flag is
@@ -457,7 +453,7 @@
   // extensions have been trying to clean from their logs.
   if (!CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableExtensionActivityLogTesting)) {
-    ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+    ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
     DCHECK(activity_log);
     activity_log->RemoveURL(url);
   }
@@ -477,9 +473,8 @@
   base::Time end_time = GetTime(params->range.end_time);
 
   std::set<GURL> restrict_urls;
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->ExpireHistoryBetween(
       restrict_urls,
       start_time,
@@ -491,7 +486,7 @@
   // Also clean from the activity log unless in testing mode.
   if (!CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableExtensionActivityLogTesting)) {
-    ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+    ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
     DCHECK(activity_log);
     activity_log->RemoveURLs(restrict_urls);
   }
@@ -508,9 +503,8 @@
     return false;
 
   std::set<GURL> restrict_urls;
-  HistoryService* hs =
-      HistoryServiceFactory::GetForProfile(profile(),
-                                           Profile::EXPLICIT_ACCESS);
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      GetProfile(), Profile::EXPLICIT_ACCESS);
   hs->ExpireHistoryBetween(
       restrict_urls,
       base::Time(),      // Unbounded beginning...
@@ -522,7 +516,7 @@
   // Also clean from the activity log unless in testing mode.
   if (!CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableExtensionActivityLogTesting)) {
-    ActivityLog* activity_log = ActivityLog::GetInstance(profile_);
+    ActivityLog* activity_log = ActivityLog::GetInstance(GetProfile());
     DCHECK(activity_log);
     activity_log->RemoveURLs(restrict_urls);
   }
diff --git a/chrome/browser/extensions/api/history/history_api.h b/chrome/browser/extensions/api/history/history_api.h
index 619aed7..2106949 100644
--- a/chrome/browser/extensions/api/history/history_api.h
+++ b/chrome/browser/extensions/api/history/history_api.h
@@ -11,8 +11,8 @@
 #include "base/compiler_specific.h"
 #include "base/memory/linked_ptr.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/common/cancelable_task_tracker.h"
@@ -88,7 +88,7 @@
 void ProfileKeyedAPIFactory<HistoryAPI>::DeclareFactoryDependencies();
 
 // Base class for history function APIs.
-class HistoryFunction : public AsyncExtensionFunction {
+class HistoryFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~HistoryFunction() {}
   virtual void Run() OVERRIDE;
diff --git a/chrome/browser/extensions/api/i18n/i18n_api.cc b/chrome/browser/extensions/api/i18n/i18n_api.cc
index dbf3b71..e2a4578 100644
--- a/chrome/browser/extensions/api/i18n/i18n_api.cc
+++ b/chrome/browser/extensions/api/i18n/i18n_api.cc
@@ -29,7 +29,7 @@
 
 bool I18nGetAcceptLanguagesFunction::RunImpl() {
   std::string accept_languages =
-      profile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
+      GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
   // Currently, there are 2 ways to set browser's accept-languages: through UI
   // or directly modify the preference file. The accept-languages set through
   // UI is guranteed to be valid, and the accept-languages string returned from
diff --git a/chrome/browser/extensions/api/i18n/i18n_api.h b/chrome/browser/extensions/api/i18n/i18n_api.h
index 5d8c12e..79b4992 100644
--- a/chrome/browser/extensions/api/i18n/i18n_api.h
+++ b/chrome/browser/extensions/api/i18n/i18n_api.h
@@ -6,13 +6,13 @@
 #define CHROME_BROWSER_EXTENSIONS_API_I18N_I18N_API_H_
 
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class Profile;
 
 namespace extensions {
 
-class I18nGetAcceptLanguagesFunction : public SyncExtensionFunction {
+class I18nGetAcceptLanguagesFunction : public ChromeSyncExtensionFunction {
   virtual ~I18nGetAcceptLanguagesFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("i18n.getAcceptLanguages", I18N_GETACCEPTLANGUAGES)
diff --git a/chrome/browser/extensions/api/identity/account_tracker.cc b/chrome/browser/extensions/api/identity/account_tracker.cc
index 03db40a..ea09479 100644
--- a/chrome/browser/extensions/api/identity/account_tracker.cc
+++ b/chrome/browser/extensions/api/identity/account_tracker.cc
@@ -52,7 +52,7 @@
 
 void AccountTracker::OnRefreshTokenAvailable(const std::string& account_id) {
   DVLOG(1) << "AVAILABLE " << account_id;
-  account_errors_.erase(account_id);
+  ClearAuthError(account_id);
   UpdateSignInState(account_id, true);
 }
 
@@ -93,6 +93,11 @@
                     OnAccountSignInChanged(account.ids, account.is_signed_in));
 }
 
+void AccountTracker::ClearAuthError(const std::string& account_key) {
+  account_errors_.erase(account_key);
+  SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
+}
+
 void AccountTracker::UpdateSignInState(const std::string& account_key,
                                        bool is_signed_in) {
   StartTrackingAccount(account_key);
@@ -129,7 +134,7 @@
     accounts_.erase(account_key);
   }
 
-  account_errors_.erase(account_key);
+  ClearAuthError(account_key);
 
   if (ContainsKey(user_info_requests_, account_key))
     DeleteFetcher(user_info_requests_[account_key]);
diff --git a/chrome/browser/extensions/api/identity/account_tracker.h b/chrome/browser/extensions/api/identity/account_tracker.h
index de9b6d8..5ab52a6 100644
--- a/chrome/browser/extensions/api/identity/account_tracker.h
+++ b/chrome/browser/extensions/api/identity/account_tracker.h
@@ -87,6 +87,7 @@
   void NotifyAccountRemoved(const AccountState& account);
   void NotifySignInChanged(const AccountState& account);
 
+  void ClearAuthError(const std::string& account_key);
   void UpdateSignInState(const std::string& account_key, bool is_signed_in);
 
   void StartTrackingAccount(const std::string& account_key);
diff --git a/chrome/browser/extensions/api/identity/experimental_identity_api.cc b/chrome/browser/extensions/api/identity/experimental_identity_api.cc
index 5839991..bb6d1c2 100644
--- a/chrome/browser/extensions/api/identity/experimental_identity_api.cc
+++ b/chrome/browser/extensions/api/identity/experimental_identity_api.cc
@@ -53,7 +53,7 @@
     ~ExperimentalIdentityGetAuthTokenFunction() {}
 
 bool ExperimentalIdentityGetAuthTokenFunction::RunImpl() {
-  if (profile()->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
   }
@@ -144,7 +144,7 @@
     install_ui_.reset(
         GetAssociatedWebContents()
             ? new ExtensionInstallPrompt(GetAssociatedWebContents())
-            : new ExtensionInstallPrompt(profile(), NULL, NULL));
+            : new ExtensionInstallPrompt(GetProfile(), NULL, NULL));
     ShowOAuthApprovalDialog(issue_advice_);
   }
 }
@@ -160,8 +160,9 @@
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
     case GoogleServiceAuthError::ACCOUNT_DELETED:
     case GoogleServiceAuthError::ACCOUNT_DISABLED:
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
-          profile())->ReportAuthError(error);
+      extensions::IdentityAPI::GetFactoryInstance()
+          ->GetForProfile(GetProfile())
+          ->ReportAuthError(error);
       if (should_prompt_for_signin_) {
         // Display a login prompt and try again (once).
         StartSigninFlow();
@@ -227,7 +228,7 @@
 
 void ExperimentalIdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
   ProfileOAuth2TokenService* service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
 #if defined(OS_CHROMEOS)
   if (chrome::IsRunningInForcedAppMode()) {
     std::string app_client_id;
@@ -256,7 +257,7 @@
 }
 
 void ExperimentalIdentityGetAuthTokenFunction::ShowLoginPopup() {
-  signin_flow_.reset(new IdentitySigninFlow(this, profile()));
+  signin_flow_.reset(new IdentitySigninFlow(this, GetProfile()));
   signin_flow_->Start();
 }
 
@@ -275,22 +276,20 @@
 #endif
 
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  OAuth2MintTokenFlow* mint_token_flow =
-      new OAuth2MintTokenFlow(
-          profile()->GetRequestContext(),
-          this,
-          OAuth2MintTokenFlow::Parameters(
-              login_access_token,
-              GetExtension()->id(),
-              oauth2_info.client_id,
-              oauth2_info.scopes,
-              gaia_mint_token_mode_));
+  OAuth2MintTokenFlow* mint_token_flow = new OAuth2MintTokenFlow(
+      GetProfile()->GetRequestContext(),
+      this,
+      OAuth2MintTokenFlow::Parameters(login_access_token,
+                                      GetExtension()->id(),
+                                      oauth2_info.client_id,
+                                      oauth2_info.scopes,
+                                      gaia_mint_token_mode_));
   return mint_token_flow;
 }
 
 bool ExperimentalIdentityGetAuthTokenFunction::HasLoginToken() const {
   ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   return token_service->RefreshTokenIsAvailable(
       token_service->GetPrimaryAccountId());
 }
@@ -305,7 +304,7 @@
 }
 
 bool ExperimentalIdentityLaunchWebAuthFlowFunction::RunImpl() {
-  if (profile()->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
   }
@@ -342,8 +341,7 @@
   chrome::HostDesktopType host_desktop_type = current_browser ?
       current_browser->host_desktop_type() : chrome::GetActiveDesktop();
   auth_flow_.reset(new ExperimentalWebAuthFlow(
-      this, profile(), auth_url, mode, initial_bounds,
-      host_desktop_type));
+      this, GetProfile(), auth_url, mode, initial_bounds, host_desktop_type));
   auth_flow_->Start();
   return true;
 }
diff --git a/chrome/browser/extensions/api/identity/experimental_identity_api.h b/chrome/browser/extensions/api/identity/experimental_identity_api.h
index af57d18..0085b5f 100644
--- a/chrome/browser/extensions/api/identity/experimental_identity_api.h
+++ b/chrome/browser/extensions/api/identity/experimental_identity_api.h
@@ -13,7 +13,7 @@
 #include "chrome/browser/extensions/api/identity/experimental_web_auth_flow.h"
 #include "chrome/browser/extensions/api/identity/identity_mint_queue.h"
 #include "chrome/browser/extensions/api/identity/identity_signin_flow.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -42,7 +42,7 @@
 // new login token, there is a sign-in flow. If that flow completes
 // successfully, getAuthToken proceeds to the non-interactive flow.
 class ExperimentalIdentityGetAuthTokenFunction
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public ExtensionInstallPrompt::Delegate,
       public OAuth2MintTokenFlow::Delegate,
       public IdentitySigninFlow::Delegate,
@@ -124,7 +124,7 @@
 };
 
 class ExperimentalIdentityLaunchWebAuthFlowFunction
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public ExperimentalWebAuthFlow::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("experimental.identity.launchWebAuthFlow",
diff --git a/chrome/browser/extensions/api/identity/experimental_identity_apitest.cc b/chrome/browser/extensions/api/identity/experimental_identity_apitest.cc
index 0b8bcc7..19d537f 100644
--- a/chrome/browser/extensions/api/identity/experimental_identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/experimental_identity_apitest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
@@ -94,7 +95,7 @@
       function->set_extension(empty_extension.get());
     }
 
-    function->set_profile(browser()->profile());
+    function->set_context(browser()->profile());
     function->set_has_callback(true);
     function->Run();
   }
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
index c8f0371..2d7bac1 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -113,11 +113,11 @@
   // interpreted as a path, including the fragment.
 
   if (url.scheme() == redirect_scheme_ && !url.has_host() && !url.has_port() &&
-      StartsWithASCII(url.path(), redirect_path_prefix_, true)) {
+      StartsWithASCII(url.GetContent(), redirect_path_prefix_, true)) {
     web_flow_.release()->DetachDelegateAndDelete();
 
-    std::string fragment =
-        url.path().substr(redirect_path_prefix_.length(), std::string::npos);
+    std::string fragment = url.GetContent().substr(
+        redirect_path_prefix_.length(), std::string::npos);
     std::vector<std::pair<std::string, std::string> > pairs;
     base::SplitStringIntoKeyValuePairs(fragment, '=', '&', &pairs);
     std::string access_token;
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc
index 485711e..fbbdca0 100644
--- a/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -17,8 +17,10 @@
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service.h"
@@ -72,7 +74,7 @@
 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {}
 
 bool IdentityGetAuthTokenFunction::RunImpl() {
-  if (profile()->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
   }
@@ -144,7 +146,8 @@
 void IdentityGetAuthTokenFunction::StartSigninFlow() {
   // All cached tokens are invalid because the user is not signed in.
   IdentityAPI* id_api =
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(profile_);
+      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
+          GetProfile());
   id_api->EraseAllCachedTokens();
   // Display a login prompt. If the subsequent mint fails, don't display the
   // login prompt again.
@@ -162,7 +165,8 @@
   std::set<std::string> scopes(oauth2_info.scopes.begin(),
                                oauth2_info.scopes.end());
   IdentityAPI* id_api =
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(profile_);
+      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
+          GetProfile());
 
   if (!should_prompt_for_scopes_) {
     // Caller requested no interaction.
@@ -193,18 +197,17 @@
   std::set<std::string> scopes(oauth2_info.scopes.begin(),
                                oauth2_info.scopes.end());
 
-  extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
-      profile_)->mint_queue()->RequestComplete(type,
-                                               GetExtension()->id(),
-                                               scopes,
-                                               this);
+  extensions::IdentityAPI::GetFactoryInstance()
+      ->GetForProfile(GetProfile())
+      ->mint_queue()
+      ->RequestComplete(type, GetExtension()->id(), scopes, this);
 }
 
 void IdentityGetAuthTokenFunction::StartMintToken(
     IdentityMintRequestQueue::MintType type) {
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  IdentityAPI* id_api = IdentityAPI::GetFactoryInstance()->GetForProfile(
-      profile());
+  IdentityAPI* id_api =
+      IdentityAPI::GetFactoryInstance()->GetForProfile(GetProfile());
   IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(
       GetExtension()->id(), oauth2_info.scopes);
   IdentityTokenCacheValue::CacheValueStatus cache_status =
@@ -266,8 +269,9 @@
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
   IdentityTokenCacheValue token(access_token,
                                 base::TimeDelta::FromSeconds(time_to_live));
-  IdentityAPI::GetFactoryInstance()->GetForProfile(profile())->SetCachedToken(
-      GetExtension()->id(), oauth2_info.scopes, token);
+  IdentityAPI::GetFactoryInstance()
+      ->GetForProfile(GetProfile())
+      ->SetCachedToken(GetExtension()->id(), oauth2_info.scopes, token);
 
   CompleteMintTokenFlow();
   CompleteFunctionWithResult(access_token);
@@ -281,8 +285,9 @@
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
     case GoogleServiceAuthError::ACCOUNT_DELETED:
     case GoogleServiceAuthError::ACCOUNT_DISABLED:
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
-          profile())->ReportAuthError(error);
+      extensions::IdentityAPI::GetFactoryInstance()
+          ->GetForProfile(GetProfile())
+          ->ReportAuthError(error);
       if (should_prompt_for_signin_) {
         // Display a login prompt and try again (once).
         StartSigninFlow();
@@ -301,9 +306,11 @@
 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
     const IssueAdviceInfo& issue_advice) {
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  IdentityAPI::GetFactoryInstance()->GetForProfile(profile())->SetCachedToken(
-      GetExtension()->id(), oauth2_info.scopes,
-      IdentityTokenCacheValue(issue_advice));
+  IdentityAPI::GetFactoryInstance()
+      ->GetForProfile(GetProfile())
+      ->SetCachedToken(GetExtension()->id(),
+                       oauth2_info.scopes,
+                       IdentityTokenCacheValue(issue_advice));
   CompleteMintTokenFlow();
 
   should_prompt_for_signin_ = false;
@@ -368,7 +375,8 @@
     const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
     IdentityTokenCacheValue token_value(
         access_token, base::TimeDelta::FromSeconds(time_to_live));
-    IdentityAPI::GetFactoryInstance()->GetForProfile(profile())
+    IdentityAPI::GetFactoryInstance()
+        ->GetForProfile(GetProfile())
         ->SetCachedToken(GetExtension()->id(), oauth2_info.scopes, token_value);
   }
 
@@ -393,8 +401,17 @@
 
 #if defined(OS_CHROMEOS)
 void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
-  chromeos::DeviceOAuth2TokenService* service =
-      chromeos::DeviceOAuth2TokenServiceFactory::Get();
+  chromeos::DeviceOAuth2TokenServiceFactory::Get(
+      base::Bind(&IdentityGetAuthTokenFunction::DidGetTokenService,
+                 this));
+}
+
+void IdentityGetAuthTokenFunction::DidGetTokenService(
+    chromeos::DeviceOAuth2TokenService* service) {
+  if (!service) {
+    CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
+    return;
+  }
   // Since robot account refresh tokens are scoped down to [any-api] only,
   // request access token for [any-api] instead of login.
   OAuth2TokenService::ScopeSet scopes;
@@ -408,7 +425,7 @@
 
 void IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
   ProfileOAuth2TokenService* service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
 #if defined(OS_CHROMEOS)
   if (chrome::IsRunningInForcedAppMode()) {
     std::string app_client_id;
@@ -437,7 +454,7 @@
 }
 
 void IdentityGetAuthTokenFunction::ShowLoginPopup() {
-  signin_flow_.reset(new IdentitySigninFlow(this, profile()));
+  signin_flow_.reset(new IdentitySigninFlow(this, GetProfile()));
   signin_flow_->Start();
 }
 
@@ -448,7 +465,7 @@
       prefs::kApplicationLocale);
 
   gaia_web_auth_flow_.reset(new GaiaWebAuthFlow(
-      this, profile(), GetExtension()->id(), oauth2_info, locale));
+      this, GetProfile(), GetExtension()->id(), oauth2_info, locale));
   gaia_web_auth_flow_->Start();
 }
 
@@ -456,22 +473,20 @@
     const std::string& login_access_token) {
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
 
-  OAuth2MintTokenFlow* mint_token_flow =
-      new OAuth2MintTokenFlow(
-          profile()->GetRequestContext(),
-          this,
-          OAuth2MintTokenFlow::Parameters(
-              login_access_token,
-              GetExtension()->id(),
-              oauth2_client_id_,
-              oauth2_info.scopes,
-              gaia_mint_token_mode_));
+  OAuth2MintTokenFlow* mint_token_flow = new OAuth2MintTokenFlow(
+      GetProfile()->GetRequestContext(),
+      this,
+      OAuth2MintTokenFlow::Parameters(login_access_token,
+                                      GetExtension()->id(),
+                                      oauth2_client_id_,
+                                      oauth2_info.scopes,
+                                      gaia_mint_token_mode_));
   return mint_token_flow;
 }
 
 bool IdentityGetAuthTokenFunction::HasLoginToken() const {
   ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   return token_service->RefreshTokenIsAvailable(
       token_service->GetPrimaryAccountId());
 }
@@ -510,7 +525,7 @@
 }
 
 bool IdentityRemoveCachedAuthTokenFunction::RunImpl() {
-  if (profile()->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
   }
@@ -518,8 +533,9 @@
   scoped_ptr<identity::RemoveCachedAuthToken::Params> params(
       identity::RemoveCachedAuthToken::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  IdentityAPI::GetFactoryInstance()->GetForProfile(profile())->EraseCachedToken(
-      GetExtension()->id(), params->details.token);
+  IdentityAPI::GetFactoryInstance()
+      ->GetForProfile(GetProfile())
+      ->EraseCachedToken(GetExtension()->id(), params->details.token);
   return true;
 }
 
@@ -531,7 +547,7 @@
 }
 
 bool IdentityLaunchWebAuthFlowFunction::RunImpl() {
-  if (profile()->IsOffTheRecord()) {
+  if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
   }
@@ -551,7 +567,7 @@
 
   AddRef();  // Balanced in OnAuthFlowSuccess/Failure.
 
-  auth_flow_.reset(new WebAuthFlow(this, profile(), auth_url, mode));
+  auth_flow_.reset(new WebAuthFlow(this, GetProfile(), auth_url, mode));
   auth_flow_->Start();
   return true;
 }
@@ -655,8 +671,7 @@
 
 IdentityAPI::IdentityAPI(Profile* profile)
     : profile_(profile),
-      account_tracker_(profile),
-      identity_event_router_(profile) {
+      account_tracker_(profile) {
   account_tracker_.AddObserver(this);
 }
 
@@ -732,7 +747,15 @@
 
 void IdentityAPI::OnAccountSignInChanged(const AccountIds& ids,
                                          bool is_signed_in) {
-  identity_event_router_.DispatchSignInEvent(ids.gaia, ids.email, is_signed_in);
+  api::identity::AccountInfo account_info;
+  account_info.id = ids.gaia;
+
+  scoped_ptr<base::ListValue> args =
+      api::identity::OnSignInChanged::Create(account_info, is_signed_in);
+  scoped_ptr<Event> event(new Event(
+      api::identity::OnSignInChanged::kEventName, args.Pass(), profile_));
+
+  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
 }
 
 template <>
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h
index a9a7746..fc23788 100644
--- a/chrome/browser/extensions/api/identity/identity_api.h
+++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -15,12 +15,11 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/extensions/api/identity/account_tracker.h"
 #include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
-#include "chrome/browser/extensions/api/identity/identity_event_router.h"
 #include "chrome/browser/extensions/api/identity/identity_mint_queue.h"
 #include "chrome/browser/extensions/api/identity/identity_signin_flow.h"
 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/signin/signin_global_error.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -29,6 +28,12 @@
 class MockGetAuthTokenFunction;
 class Profile;
 
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+class DeviceOAuth2TokenService;
+}
+#endif
+
 namespace extensions {
 
 class GetAuthTokenFunctionTest;
@@ -64,7 +69,7 @@
 // profile will be signed in already, but if it turns out we need a
 // new login token, there is a sign-in flow. If that flow completes
 // successfully, getAuthToken proceeds to the non-interactive flow.
-class IdentityGetAuthTokenFunction : public AsyncExtensionFunction,
+class IdentityGetAuthTokenFunction : public ChromeAsyncExtensionFunction,
                                      public GaiaWebAuthFlow::Delegate,
                                      public IdentityMintRequestQueue::Request,
                                      public OAuth2MintTokenFlow::Delegate,
@@ -134,6 +139,9 @@
   // Starts a login access token request for device robot account. This method
   // will be called only in enterprise kiosk mode in ChromeOS.
   virtual void StartDeviceLoginAccessTokenRequest();
+
+  // Continuation of StartDeviceLoginAccessTokenRequest().
+  virtual void DidGetTokenService(chromeos::DeviceOAuth2TokenService* service);
 #endif
 
   // Starts a mint token request to GAIA.
@@ -170,7 +178,8 @@
   scoped_ptr<OAuth2TokenService::Request> login_token_request_;
 };
 
-class IdentityRemoveCachedAuthTokenFunction : public SyncExtensionFunction {
+class IdentityRemoveCachedAuthTokenFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("identity.removeCachedAuthToken",
                              EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN)
@@ -183,7 +192,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class IdentityLaunchWebAuthFlowFunction : public AsyncExtensionFunction,
+class IdentityLaunchWebAuthFlowFunction : public ChromeAsyncExtensionFunction,
                                           public WebAuthFlow::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("identity.launchWebAuthFlow",
@@ -297,7 +306,6 @@
   IdentityMintRequestQueue mint_queue_;
   CachedTokens token_cache_;
   AccountTracker account_tracker_;
-  IdentityEventRouter identity_event_router_;
 };
 
 template <>
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index a0708c6..3050998 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_switches.h"
@@ -104,7 +105,7 @@
       function->set_extension(empty_extension.get());
     }
 
-    function->set_profile(browser()->profile());
+    function->set_context(browser()->profile());
     function->set_has_callback(true);
     function->Run();
   }
diff --git a/chrome/browser/extensions/api/identity/identity_event_router.cc b/chrome/browser/extensions/api/identity/identity_event_router.cc
deleted file mode 100644
index 06a9ac8..0000000
--- a/chrome/browser/extensions/api/identity/identity_event_router.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2013 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/extensions/api/identity/identity_event_router.h"
-
-#include <set>
-
-#include "base/stl_util.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/common/extensions/api/identity.h"
-
-namespace extensions {
-
-IdentityEventRouter::IdentityEventRouter(Profile* profile)
-    : profile_(profile) {}
-
-IdentityEventRouter::~IdentityEventRouter() {}
-
-void IdentityEventRouter::DispatchSignInEvent(const std::string& id,
-                                              const std::string& email,
-                                              bool is_signed_in) {
-  const EventListenerMap::ListenerList& listeners =
-      extensions::ExtensionSystem::Get(profile_)->event_router()->listeners()
-      .GetEventListenersByName(api::identity::OnSignInChanged::kEventName);
-
-  ExtensionService* service =
-      ExtensionSystem::Get(profile_)->extension_service();
-  EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
-
-  api::identity::AccountInfo account_info;
-  account_info.id = id;
-
-  api::identity::AccountInfo account_info_email;
-  account_info_email.id = id;
-  account_info_email.email = scoped_ptr<std::string>(new std::string(email));
-
-  std::set<std::string> already_dispatched;
-
-  for (EventListenerMap::ListenerList::const_iterator it = listeners.begin();
-       it != listeners.end();
-       ++it) {
-
-    const std::string extension_id = (*it)->extension_id;
-    const Extension* extension = service->extensions()->GetByID(extension_id);
-
-    if (ContainsKey(already_dispatched, extension_id))
-      continue;
-
-    already_dispatched.insert(extension_id);
-
-    // Add the email address to AccountInfo only for extensions that
-    // have APIPermission::kIdentityEmail.
-    scoped_ptr<base::ListValue> args;
-    if (extension->HasAPIPermission(APIPermission::kIdentityEmail)) {
-      args = api::identity::OnSignInChanged::Create(account_info_email,
-                                                    is_signed_in);
-    } else {
-      args = api::identity::OnSignInChanged::Create(account_info,
-                                                    is_signed_in);
-    }
-
-    scoped_ptr<Event> event(
-        new Event(api::identity::OnSignInChanged::kEventName, args.Pass()));
-    event->restrict_to_profile = profile_;
-    event_router->DispatchEventToExtension(extension_id, event.Pass());
-  }
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_event_router.h b/chrome/browser/extensions/api/identity/identity_event_router.h
deleted file mode 100644
index 21bf2eb..0000000
--- a/chrome/browser/extensions/api/identity/identity_event_router.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 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_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-class Profile;
-
-namespace extensions {
-
-class IdentityEventRouter {
- public:
-  explicit IdentityEventRouter(Profile* profile);
-  ~IdentityEventRouter();
-
-  // Dispatch identity.onSignInChanged event, including email address
-  // for extensions with the identity.email permission.
-  void DispatchSignInEvent(const std::string& id,
-                           const std::string& email,
-                           bool is_signed_in);
-
- private:
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(IdentityEventRouter);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
diff --git a/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc b/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc
deleted file mode 100644
index 8b65c5c..0000000
--- a/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 2013 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/extensions/api/identity/identity_event_router.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_system_factory.h"
-#include "chrome/browser/extensions/test_extension_service.h"
-#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/api/identity.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_builder.h"
-#include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/permissions/permissions_data.h"
-#include "chrome/common/extensions/value_builder.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "extensions/common/permissions/api_permission.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-struct EventInfo {
-  std::string user_id;
-  std::string email;
-  bool is_signed_in;
-};
-
-class FakeEventRouter : public extensions::EventRouter {
- public:
-  explicit FakeEventRouter(Profile* profile) : EventRouter(profile, NULL) {}
-
-  virtual void DispatchEventToExtension(
-      const std::string& extension_id,
-      scoped_ptr<extensions::Event> event) OVERRIDE {
-    EventInfo event_info;
-    base::DictionaryValue* event_object = NULL;
-    EXPECT_TRUE(event->event_args->GetDictionary(0, &event_object));
-    EXPECT_TRUE(event_object->GetString("id", &event_info.user_id));
-    event_object->GetString("email", &event_info.email);
-
-    EXPECT_TRUE(event->event_args->GetBoolean(1, &event_info.is_signed_in));
-
-    EXPECT_FALSE(ContainsKey(extension_id_to_event_, extension_id));
-    extension_id_to_event_[extension_id] = event_info;
-  }
-
-  size_t GetEventCount() {
-    return extension_id_to_event_.size();
-  }
-
-  bool ContainsExtensionId(const std::string extension_id) {
-    return ContainsKey(extension_id_to_event_, extension_id);
-  }
-
-  const EventInfo& GetEventInfo(const std::string extension_id) {
-    return extension_id_to_event_[extension_id];
-  }
-
- private:
-  std::map<std::string, EventInfo> extension_id_to_event_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
-};
-
-class FakeExtensionService : public TestExtensionService {
- public:
-  FakeExtensionService() {}
-  virtual ~FakeExtensionService() {}
-
-  virtual const ExtensionSet* extensions() const OVERRIDE {
-    return &extensions_;
-  }
-
-  virtual void AddExtension(const extensions::Extension* extension) OVERRIDE {
-    extensions_.Insert(extension);
-  }
-
- private:
-  ExtensionSet extensions_;
-};
-
-class FakeExtensionSystem : public extensions::TestExtensionSystem {
- public:
-  explicit FakeExtensionSystem(Profile* profile)
-      : extensions::TestExtensionSystem(profile) {}
-
-  virtual extensions::EventRouter* event_router() OVERRIDE {
-    return fake_event_router();
-  }
-
-  virtual ExtensionService* extension_service() OVERRIDE {
-    ExtensionServiceInterface* as_interface =
-        static_cast<ExtensionServiceInterface*>(&fake_extension_service_);
-    return static_cast<ExtensionService*>(as_interface);
-  }
-
-  FakeEventRouter* fake_event_router() {
-    if (!fake_event_router_)
-      fake_event_router_.reset(new FakeEventRouter(profile_));
-    return fake_event_router_.get();
-  }
-
- private:
-  FakeExtensionService fake_extension_service_;
-  scoped_ptr<FakeEventRouter> fake_event_router_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeExtensionSystem);
-};
-
-BrowserContextKeyedService* BuildFakeExtensionSystem(
-    content::BrowserContext* profile) {
-  return new FakeExtensionSystem(static_cast<Profile*>(profile));
-}
-
-}  // namespace
-
-namespace extensions {
-
-class IdentityEventRouterTest : public testing::Test {
- public:
-  IdentityEventRouterTest()
-      : test_profile_(new TestingProfile()),
-        identity_event_router_(test_profile_.get()),
-        extension_counter_(0) {}
-
-  virtual void SetUp() OVERRIDE {
-    fake_extension_system_ = static_cast<FakeExtensionSystem*>(
-        ExtensionSystemFactory::GetInstance()->SetTestingFactoryAndUse(
-            test_profile_.get(), &BuildFakeExtensionSystem));
-  }
-
-  FakeEventRouter* fake_event_router() {
-    return fake_extension_system_->fake_event_router();
-  }
-
-  Profile* profile() {
-    return test_profile_.get();
-  }
-
- protected:
-  scoped_refptr<const Extension> CreateExtension(bool has_email_permission) {
-    ListBuilder permissions;
-    if (has_email_permission)
-      permissions.Append("identity.email");
-
-    std::string id = base::StringPrintf("id.%d", extension_counter_++);
-    scoped_refptr<const Extension> extension = ExtensionBuilder()
-        .SetID(id)
-        .SetManifest(DictionaryBuilder()
-                     .Set("name", "Extension with ID " + id)
-                     .Set("version", "1.0")
-                     .Set("manifest_version", 2)
-                     .Set("permissions", permissions))
-        .Build();
-    fake_extension_system_->extension_service()->AddExtension(extension.get());
-    fake_event_router()->AddEventListener(
-        api::identity::OnSignInChanged::kEventName, NULL, extension->id());
-    return extension;
-  }
-
-  scoped_ptr<TestingProfile> test_profile_;
-  IdentityEventRouter identity_event_router_;
-  FakeExtensionSystem* fake_extension_system_;
-  content::TestBrowserThreadBundle thread_bundle_;
-  int extension_counter_;
-};
-
-TEST_F(IdentityEventRouterTest, SignInNoListeners) {
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", true);
-  EXPECT_EQ(0ul, fake_event_router()->GetEventCount());
-}
-
-TEST_F(IdentityEventRouterTest, SignInNoEmailListener) {
-  scoped_refptr<const Extension> ext = CreateExtension(false);
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", true);
-  EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
-  EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
-  EXPECT_EQ("test_user_id",
-            fake_event_router()->GetEventInfo(ext->id()).user_id);
-  EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).email.empty());
-  EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
-}
-
-TEST_F(IdentityEventRouterTest, SignInWithEmailListener) {
-  scoped_refptr<const Extension> ext = CreateExtension(true);
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", true);
-  EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
-  EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
-  EXPECT_EQ("test_user_id",
-            fake_event_router()->GetEventInfo(ext->id()).user_id);
-  EXPECT_EQ("test_email", fake_event_router()->GetEventInfo(ext->id()).email);
-  EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
-}
-
-TEST_F(IdentityEventRouterTest, SignInMultipleListeners) {
-  typedef std::vector<scoped_refptr<const Extension> > ExtensionVector;
-  ExtensionVector with_email;
-  ExtensionVector no_email;
-
-  for (int i = 0; i < 3; i++)
-    with_email.push_back(CreateExtension(true));
-
-  for (int i = 0; i < 2; i++)
-    no_email.push_back(CreateExtension(false));
-
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", true);
-
-  EXPECT_EQ(with_email.size() + no_email.size(),
-            fake_event_router()->GetEventCount());
-
-  for (ExtensionVector::const_iterator it = with_email.begin();
-       it != with_email.end();
-       ++it) {
-    EXPECT_TRUE(fake_event_router()->ContainsExtensionId((*it)->id()));
-    EXPECT_EQ("test_user_id",
-              fake_event_router()->GetEventInfo((*it)->id()).user_id);
-    EXPECT_EQ("test_email",
-              fake_event_router()->GetEventInfo((*it)->id()).email);
-    EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).is_signed_in);
-  }
-
-  for (ExtensionVector::const_iterator it = no_email.begin();
-       it != no_email.end();
-       ++it) {
-    EXPECT_TRUE(fake_event_router()->ContainsExtensionId((*it)->id()));
-    EXPECT_EQ("test_user_id",
-              fake_event_router()->GetEventInfo((*it)->id()).user_id);
-    EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).email.empty());
-    EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).is_signed_in);
-  }
-}
-
-TEST_F(IdentityEventRouterTest, SignInWithTwoListenersOnOneExtension) {
-  scoped_refptr<const Extension> ext = CreateExtension(true);
-
-  scoped_ptr<content::MockRenderProcessHost> fake_render_process(
-      new content::MockRenderProcessHost(profile()));
-  fake_event_router()->AddEventListener(
-      api::identity::OnSignInChanged::kEventName,
-      fake_render_process.get(),
-      ext->id());
-
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", true);
-  EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
-  EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
-  EXPECT_EQ("test_user_id",
-            fake_event_router()->GetEventInfo(ext->id()).user_id);
-  EXPECT_EQ("test_email", fake_event_router()->GetEventInfo(ext->id()).email);
-  EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
-
-  fake_event_router()->RemoveEventListener(
-      api::identity::OnSignInChanged::kEventName,
-      fake_render_process.get(),
-      ext->id());
-}
-
-TEST_F(IdentityEventRouterTest, SignOut) {
-  scoped_refptr<const Extension> ext = CreateExtension(false);
-  identity_event_router_.DispatchSignInEvent(
-      "test_user_id", "test_email", false);
-  EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
-  EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
-  EXPECT_EQ("test_user_id",
-            fake_event_router()->GetEventInfo(ext->id()).user_id);
-  EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).email.empty());
-  EXPECT_FALSE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/idle/idle_api.cc b/chrome/browser/extensions/api/idle/idle_api.cc
index 1cd1fe4..2a0d2d8 100644
--- a/chrome/browser/extensions/api/idle/idle_api.cc
+++ b/chrome/browser/extensions/api/idle/idle_api.cc
@@ -35,9 +35,8 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
   threshold = ClampThreshold(threshold);
 
-  IdleManagerFactory::GetForProfile(profile())->QueryState(
-      threshold,
-      base::Bind(&IdleQueryStateFunction::IdleStateCallback, this));
+  IdleManagerFactory::GetForProfile(GetProfile())->QueryState(
+      threshold, base::Bind(&IdleQueryStateFunction::IdleStateCallback, this));
 
   // Don't send the response, it'll be sent by our callback
   return true;
@@ -53,8 +52,8 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
   threshold = ClampThreshold(threshold);
 
-  IdleManagerFactory::GetForProfile(profile())->SetThreshold(extension_id(),
-                                                             threshold);
+  IdleManagerFactory::GetForProfile(GetProfile())
+      ->SetThreshold(extension_id(), threshold);
 
   return true;
 }
diff --git a/chrome/browser/extensions/api/idle/idle_api.h b/chrome/browser/extensions/api/idle/idle_api.h
index e913835..e14f1de 100644
--- a/chrome/browser/extensions/api/idle/idle_api.h
+++ b/chrome/browser/extensions/api/idle/idle_api.h
@@ -5,13 +5,13 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_IDLE_IDLE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_IDLE_IDLE_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/idle.h"
 
 namespace extensions {
 
 // Implementation of the chrome.idle.queryState API.
-class IdleQueryStateFunction : public AsyncExtensionFunction {
+class IdleQueryStateFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("idle.queryState", IDLE_QUERYSTATE)
 
@@ -26,7 +26,7 @@
 };
 
 // Implementation of the chrome.idle.setDetectionInterval API.
-class IdleSetDetectionIntervalFunction : public SyncExtensionFunction {
+class IdleSetDetectionIntervalFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("idle.setDetectionInterval",
                              IDLE_SETDETECTIONINTERVAL)
diff --git a/chrome/browser/extensions/api/idle/idle_api_unittest.cc b/chrome/browser/extensions/api/idle/idle_api_unittest.cc
index cf6ee66..012ef6d 100644
--- a/chrome/browser/extensions/api/idle/idle_api_unittest.cc
+++ b/chrome/browser/extensions/api/idle/idle_api_unittest.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/common/extensions/api/idle.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
@@ -525,7 +524,7 @@
 
   // Threshold will reset after unload (and listen count == 0)
   UnloadedExtensionInfo details(extension_.get(),
-                                extension_misc::UNLOAD_REASON_UNINSTALL);
+                                UnloadedExtensionInfo::REASON_UNINSTALL);
   idle_manager_->Observe(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(browser()->profile()),
@@ -546,7 +545,7 @@
 // Verifies that unloading an extension with no listeners or threshold works.
 TEST_F(IdleTest, UnloadOnly) {
   UnloadedExtensionInfo details(extension_.get(),
-                                extension_misc::UNLOAD_REASON_UNINSTALL);
+                                UnloadedExtensionInfo::REASON_UNINSTALL);
   idle_manager_->Observe(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(browser()->profile()),
@@ -558,7 +557,7 @@
 TEST_F(IdleTest, UnloadWhileListening) {
   ScopedListen listen(idle_manager_, extension_->id());
   UnloadedExtensionInfo details(extension_.get(),
-                                extension_misc::UNLOAD_REASON_UNINSTALL);
+                                UnloadedExtensionInfo::REASON_UNINSTALL);
   idle_manager_->Observe(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(browser()->profile()),
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
index a9834be..6157489 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -46,7 +46,7 @@
     hash = *params->options->image_hash;
   }
 
-  image_writer::OperationManager::Get(profile())->StartWriteFromUrl(
+  image_writer::OperationManager::Get(GetProfile())->StartWriteFromUrl(
       extension_id(),
       url,
       render_view_host(),
@@ -81,7 +81,7 @@
       image_writer_api::WriteFromFile::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  image_writer::OperationManager::Get(profile())->StartWriteFromFile(
+  image_writer::OperationManager::Get(GetProfile())->StartWriteFromFile(
       extension_id(),
       params->storage_unit_id,
       base::Bind(&ImageWriterPrivateWriteFromFileFunction::OnWriteStarted,
@@ -106,11 +106,10 @@
 }
 
 bool ImageWriterPrivateCancelWriteFunction::RunImpl() {
-  image_writer::OperationManager::Get(profile())->
-      CancelWrite(
-          extension_id(),
-          base::Bind(&ImageWriterPrivateCancelWriteFunction::OnWriteCancelled,
-                     this));
+  image_writer::OperationManager::Get(GetProfile())->CancelWrite(
+      extension_id(),
+      base::Bind(&ImageWriterPrivateCancelWriteFunction::OnWriteCancelled,
+                 this));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
index 7a4860d..4789d18 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
@@ -5,12 +5,13 @@
 #define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_IMAGE_WRITER_PRIVATE_API_H_
 
 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/image_writer_private.h"
 
 namespace extensions {
 
-class ImageWriterPrivateWriteFromUrlFunction : public AsyncExtensionFunction {
+class ImageWriterPrivateWriteFromUrlFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("imageWriterPrivate.writeFromUrl",
                              IMAGEWRITER_WRITEFROMURL)
@@ -22,7 +23,8 @@
   void OnWriteStarted(bool success, const std::string& error);
 };
 
-class ImageWriterPrivateWriteFromFileFunction : public AsyncExtensionFunction {
+class ImageWriterPrivateWriteFromFileFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("imageWriterPrivate.writeFromFile",
                              IMAGEWRITER_WRITEFROMFILE)
@@ -34,7 +36,8 @@
   void OnWriteStarted(bool success, const std::string& error);
 };
 
-class ImageWriterPrivateCancelWriteFunction : public AsyncExtensionFunction {
+class ImageWriterPrivateCancelWriteFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("imageWriterPrivate.cancelWrite",
                              IMAGEWRITER_CANCELWRITE)
@@ -47,7 +50,7 @@
 };
 
 class ImageWriterPrivateDestroyPartitionsFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("imageWriterPrivate.destroyPartitions",
                              IMAGEWRITER_DESTROYPARTITIONS)
@@ -59,7 +62,7 @@
 };
 
 class ImageWriterPrivateListRemovableStorageDevicesFunction
-  : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
   public:
     DECLARE_EXTENSION_FUNCTION("imageWriterPrivate.listRemovableStorageDevices",
                                IMAGEWRITER_LISTREMOVABLESTORAGEDEVICES);
diff --git a/chrome/browser/extensions/api/input/input.cc b/chrome/browser/extensions/api/input/input.cc
index d550b8c..e8e7bf9 100644
--- a/chrome/browser/extensions/api/input/input.cc
+++ b/chrome/browser/extensions/api/input/input.cc
@@ -5,13 +5,16 @@
 #include "chrome/browser/extensions/api/input/input.h"
 
 #include "ash/root_window_controller.h"
+#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/extensions/extension_function_registry.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/user_metrics.h"
 #include "ui/events/event.h"
 #include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_switches.h"
 
 #if defined(USE_ASH)
 #include "ash/shell.h"
@@ -44,13 +47,20 @@
 #if defined(USE_ASH)
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+      keyboard::switches::kEnableSwipeSelection)) {
+    return false;
+  }
+
   int swipe_direction;
   int modifier_flags;
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &swipe_direction));
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &modifier_flags));
 
-  return keyboard::MoveCursor(swipe_direction, modifier_flags,
-                              ash::Shell::GetPrimaryRootWindow());
+  return keyboard::MoveCursor(
+      swipe_direction,
+      modifier_flags,
+      ash::Shell::GetPrimaryRootWindow()->GetDispatcher());
 #endif
   error_ = kNotYetImplementedError;
   return false;
@@ -65,20 +75,21 @@
   std::string type;
   int char_value;
   int key_code;
-  bool shift_modifier;
+  int modifiers;
 
   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &options_value));
   EXTENSION_FUNCTION_VALIDATE(options_value->GetAsDictionary(&params));
   EXTENSION_FUNCTION_VALIDATE(params->GetString("type", &type));
   EXTENSION_FUNCTION_VALIDATE(params->GetInteger("charValue", &char_value));
   EXTENSION_FUNCTION_VALIDATE(params->GetInteger("keyCode", &key_code));
-  EXTENSION_FUNCTION_VALIDATE(params->GetBoolean("shiftKey", &shift_modifier));
+  EXTENSION_FUNCTION_VALIDATE(params->GetInteger("modifiers", &modifiers));
 
-  return keyboard::SendKeyEvent(type,
-                                char_value,
-                                key_code,
-                                shift_modifier,
-                                ash::Shell::GetPrimaryRootWindow());
+  return keyboard::SendKeyEvent(
+      type,
+      char_value,
+      key_code,
+      modifiers,
+      ash::Shell::GetPrimaryRootWindow()->GetDispatcher());
 #endif
   error_ = kNotYetImplementedError;
   return false;
@@ -104,6 +115,20 @@
   return false;
 }
 
+bool VirtualKeyboardPrivateKeyboardLoadedFunction::RunImpl() {
+#if defined(USE_ASH)
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  keyboard::MarkKeyboardLoadFinished();
+
+  content::UserMetricsAction("VirtualKeyboardLoaded");
+
+  return true;
+#endif
+  error_ = kNotYetImplementedError;
+  return false;
+}
+
 InputAPI::InputAPI(Profile* profile) {
 }
 
diff --git a/chrome/browser/extensions/api/input/input.h b/chrome/browser/extensions/api/input/input.h
index 8116ca0..daef9b8 100644
--- a/chrome/browser/extensions/api/input/input.h
+++ b/chrome/browser/extensions/api/input/input.h
@@ -65,6 +65,20 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
+class VirtualKeyboardPrivateKeyboardLoadedFunction
+    : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION(
+      "virtualKeyboardPrivate.keyboardLoaded",
+      VIRTUALKEYBOARDPRIVATE_KEYBOARDLOADED);
+
+ protected:
+  virtual ~VirtualKeyboardPrivateKeyboardLoadedFunction() {}
+
+  // ExtensionFunction:
+  virtual bool RunImpl() OVERRIDE;
+};
+
 class InputAPI : public ProfileKeyedAPI {
  public:
   explicit InputAPI(Profile* profile);
diff --git a/chrome/browser/extensions/api/location/location_api.cc b/chrome/browser/extensions/api/location/location_api.cc
index 41a9917..cc17f70 100644
--- a/chrome/browser/extensions/api/location/location_api.cc
+++ b/chrome/browser/extensions/api/location/location_api.cc
@@ -48,11 +48,11 @@
   }
 
   // TODO(vadimt): validate and use params->request_info.maximumAge
-  LocationManager::Get(profile())->AddLocationRequest(
-      extension_id(),
-      params->name,
-      min_distance_in_meters,
-      min_time_in_milliseconds);
+  LocationManager::Get(GetProfile())
+      ->AddLocationRequest(extension_id(),
+                           params->name,
+                           min_distance_in_meters,
+                           min_time_in_milliseconds);
 
   return true;
 }
@@ -62,8 +62,8 @@
       ClearWatch::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  LocationManager::Get(profile())->RemoveLocationRequest(
-      extension_id(), params->name);
+  LocationManager::Get(GetProfile())
+      ->RemoveLocationRequest(extension_id(), params->name);
 
   return true;
 }
diff --git a/chrome/browser/extensions/api/location/location_api.h b/chrome/browser/extensions/api/location/location_api.h
index bb5e692..929287c 100644
--- a/chrome/browser/extensions/api/location/location_api.h
+++ b/chrome/browser/extensions/api/location/location_api.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_LOCATION_LOCATION_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_LOCATION_LOCATION_API_H_
 
-#include "chrome/browser/extensions/api/api_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
-class LocationWatchLocationFunction : public SyncExtensionFunction {
+class LocationWatchLocationFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("location.watchLocation",
                              LOCATION_WATCHLOCATION)
@@ -21,7 +21,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class LocationClearWatchFunction : public SyncExtensionFunction {
+class LocationClearWatchFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("location.clearWatch",
                              LOCATION_CLEARWATCH)
diff --git a/chrome/browser/extensions/api/location/location_manager.cc b/chrome/browser/extensions/api/location/location_manager.cc
index 95579a3..d07591c 100644
--- a/chrome/browser/extensions/api/location/location_manager.cc
+++ b/chrome/browser/extensions/api/location/location_manager.cc
@@ -15,12 +15,12 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/common/extensions/api/location.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/geolocation_provider.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/common/geoposition.h"
+#include "extensions/common/permissions/permission_set.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/extensions/api/management/management_api.cc b/chrome/browser/extensions/api/management/management_api.cc
index afad4c9..5119eb8 100644
--- a/chrome/browser/extensions/api/management/management_api.cc
+++ b/chrome/browser/extensions/api/management/management_api.cc
@@ -38,13 +38,13 @@
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/common/extensions/manifest_handlers/offline_enabled_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 
 #if !defined(OS_ANDROID)
@@ -225,16 +225,16 @@
 } // namespace
 
 ExtensionService* ManagementFunction::service() {
-  return profile()->GetExtensionService();
+  return GetProfile()->GetExtensionService();
 }
 
 ExtensionService* AsyncManagementFunction::service() {
-  return profile()->GetExtensionService();
+  return GetProfile()->GetExtensionService();
 }
 
 bool ManagementGetAllFunction::RunImpl() {
   ExtensionInfoList extensions;
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
 
   AddExtensionInfo(*service()->extensions(), system, &extensions);
   AddExtensionInfo(*service()->disabled_extensions(), system, &extensions);
@@ -256,8 +256,8 @@
     return false;
   }
 
-  scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
-      *extension, ExtensionSystem::Get(profile()));
+  scoped_ptr<management::ExtensionInfo> info =
+      CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
   results_ = management::Get::Results::Create(*info);
 
   return true;
@@ -348,7 +348,7 @@
   void ReportResultFromUIThread() {
     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     if (error_.empty() && parsed_manifest_.get())
-      client_->OnParseSuccess(parsed_manifest_.release());
+      client_->OnParseSuccess(parsed_manifest_.Pass());
     else
       client_->OnParseFailure(error_);
   }
@@ -387,8 +387,8 @@
 }
 
 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
-    base::DictionaryValue* parsed_manifest) {
-  CHECK(parsed_manifest);
+    scoped_ptr<base::DictionaryValue> parsed_manifest) {
+  CHECK(parsed_manifest.get());
 
   scoped_refptr<Extension> extension = Extension::Create(
       base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
@@ -438,8 +438,8 @@
   extension_misc::LaunchContainer launch_container =
       service()->extension_prefs()->GetLaunchContainer(
           extension, ExtensionPrefs::LAUNCH_DEFAULT);
-  OpenApplication(AppLaunchParams(profile(), extension, launch_container,
-                                  NEW_FOREGROUND_TAB));
+  OpenApplication(AppLaunchParams(
+      GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
 #if !defined(OS_ANDROID)
   CoreAppLauncherHandler::RecordAppLaunchType(
       extension_misc::APP_LAUNCH_EXTENSION_API,
@@ -469,8 +469,8 @@
     return false;
   }
 
-  const ManagementPolicy* policy = ExtensionSystem::Get(profile())->
-      management_policy();
+  const ManagementPolicy* policy =
+      ExtensionSystem::Get(GetProfile())->management_policy();
   if (!policy->UserMayModifySettings(extension, NULL)) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kUserCantModifyError, extension_id_);
@@ -534,8 +534,9 @@
     return false;
   }
 
-  if (!ExtensionSystem::Get(profile())->management_policy()->
-      UserMayModifySettings(extension, NULL)) {
+  if (!ExtensionSystem::Get(GetProfile())
+           ->management_policy()
+           ->UserMayModifySettings(extension, NULL)) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kUserCantModifyError, extension_id_);
     return false;
@@ -545,7 +546,7 @@
     if (show_confirm_dialog) {
       AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
       extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
-          profile(), GetCurrentBrowser(), this));
+          GetProfile(), GetCurrentBrowser(), this));
       extension_uninstall_dialog_->ConfirmUninstall(extension);
     } else {
       Finish(true);
diff --git a/chrome/browser/extensions/api/management/management_api.h b/chrome/browser/extensions/api/management/management_api.h
index f9566ea..1dcde84 100644
--- a/chrome/browser/extensions/api/management/management_api.h
+++ b/chrome/browser/extensions/api/management/management_api.h
@@ -7,8 +7,8 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
@@ -20,14 +20,14 @@
 
 namespace extensions {
 
-class ManagementFunction : public SyncExtensionFunction {
+class ManagementFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~ManagementFunction() {}
 
   ExtensionService* service();
 };
 
-class AsyncManagementFunction : public AsyncExtensionFunction {
+class AsyncManagementFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~AsyncManagementFunction() {}
 
@@ -69,14 +69,14 @@
 };
 
 class ManagementGetPermissionWarningsByManifestFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION(
       "management.getPermissionWarningsByManifest",
       MANAGEMENT_GETPERMISSIONWARNINGSBYMANIFEST);
 
   // Called when utility process finishes.
-  void OnParseSuccess(base::DictionaryValue* parsed_manifest);
+  void OnParseSuccess(scoped_ptr<base::DictionaryValue> parsed_manifest);
   void OnParseFailure(const std::string& error);
 
  protected:
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc
index e91c056..f0036ff 100644
--- a/chrome/browser/extensions/api/management/management_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/bind_helpers.h"
 #include "base/memory/ref_counted.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/extensions/external_policy_loader.h"
 #include "chrome/browser/extensions/updater/extension_downloader.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
index 2deea48..e764dee 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
+++ b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
@@ -45,8 +45,12 @@
   if (!started_) {
     device_lister_.Start();
     started_ = true;
+    VLOG(1) << "Started device lister for service type "
+             << device_lister_.service_type();
   }
   device_lister_.DiscoverNewDevices(force_update);
+  VLOG(1) << "Discovery new devices for service type "
+           << device_lister_.service_type();
 }
 
 void DnsSdDeviceLister::OnDeviceChanged(
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_registry.cc b/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
index e4e92dd..3edabe0 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
+++ b/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
@@ -47,16 +47,17 @@
 
 bool DnsSdRegistry::ServiceTypeData::UpdateService(
       bool added, const DnsSdService& service) {
-  if (added) {
-    service_list_.push_back(service);
-  } else {
-    DnsSdRegistry::DnsSdServiceList::iterator it =
-        std::find_if(service_list_.begin(),
-                     service_list_.end(),
-                     IsSameServiceName(service));
-    if (it == service_list_.end())
-      return false;
+  DnsSdRegistry::DnsSdServiceList::iterator it =
+      std::find_if(service_list_.begin(),
+                   service_list_.end(),
+                   IsSameServiceName(service));
+  if (it != service_list_.end()) {
+    // If added == true, but we still found the service in our cache, then just
+    // update the existing entry, but this should not happen!
+    DCHECK(!added);
     *it = service;
+  } else if (added) {
+    service_list_.push_back(service);
   }
   return true;
 };
@@ -148,11 +149,12 @@
   if (!IsRegistered(service_type))
     return;
 
+  VLOG(1) << "Service changed: " << service.service_name;
   if (service_data_map_[service_type]->UpdateService(added, service)) {
     DispatchApiEvent(service_type);
   } else {
-    DVLOG(1) << "Failed to find existing service to update: "
-             << service.service_name;
+    VLOG(1) << "Failed to find existing service to update: "
+            << service.service_name;
   }
 }
 
@@ -161,10 +163,11 @@
   if (!IsRegistered(service_type))
     return;
 
+  VLOG(1) << "Removing service: " << service_name;
   if (service_data_map_[service_type]->RemoveService(service_name)) {
     DispatchApiEvent(service_type);
   } else {
-    DVLOG(1) << "Failed to remove service: " << service_name;
+    VLOG(1) << "Failed to remove service: " << service_name;
   }
 }
 
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
index 0358fa3..63ccf71 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
@@ -218,8 +218,8 @@
     // If there is no WebContentsModalDialogManager, then this contents is
     // probably the background page for an app. Try to find a shell window to
     // host the dialog.
-    ShellWindow* window = apps::ShellWindowRegistry::Get(profile())->
-        GetCurrentShellWindowForApp(GetExtension()->id());
+    ShellWindow* window = apps::ShellWindowRegistry::Get(
+        GetProfile())->GetCurrentShellWindowForApp(GetExtension()->id());
     if (window) {
       contents = window->web_contents();
     } else {
@@ -241,8 +241,9 @@
     cb.Run(std::vector<MediaFileSystemInfo>());
     return;
   }
-  DCHECK(g_browser_process->media_file_system_registry()->
-             GetPreferences(profile_)->IsInitialized());
+  DCHECK(g_browser_process->media_file_system_registry()
+             ->GetPreferences(GetProfile())
+             ->IsInitialized());
   MediaFileSystemRegistry* registry =
       g_browser_process->media_file_system_registry();
   registry->GetMediaFileSystemsForExtension(
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.h b/chrome/browser/extensions/api/media_galleries/media_galleries_api.h
index 8c2703c..c9abd3f 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.h
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.h
@@ -10,7 +10,7 @@
 
 #include <vector>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #include "chrome/common/extensions/api/media_galleries.h"
 
@@ -19,7 +19,7 @@
 namespace extensions {
 
 class MediaGalleriesGetMediaFileSystemsFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleries.getMediaFileSystems",
                              MEDIAGALLERIES_GETMEDIAFILESYSTEMS)
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
index 1d6f6a7..916f007 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -161,11 +161,11 @@
   }
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
-  void PopulatePicasaTestData(const base::FilePath& metadata_root) {
+  void PopulatePicasaTestData(const base::FilePath& picasa_app_data_root) {
     base::FilePath picasa_database_path =
-        metadata_root.AppendASCII(picasa::kPicasaDatabaseDirName);
+        picasa::MakePicasaDatabasePath(picasa_app_data_root);
     base::FilePath picasa_temp_dir_path =
-        metadata_root.AppendASCII(picasa::kPicasaTempDirName);
+        picasa_database_path.DirName().AppendASCII(picasa::kPicasaTempDirName);
     ASSERT_TRUE(file_util::CreateDirectory(picasa_database_path));
     ASSERT_TRUE(file_util::CreateDirectory(picasa_temp_dir_path));
 
@@ -277,27 +277,22 @@
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
                        PicasaDefaultLocation) {
 #if defined(OS_WIN)
-  base::FilePath metadata_root = ensure_media_directories_exists()->
-      GetFakeLocalAppDataPath().AppendASCII("Google").AppendASCII("Picasa2");
+  PopulatePicasaTestData(
+      ensure_media_directories_exists()->GetFakeLocalAppDataPath());
 #elif defined(OS_MACOSX)
-  base::FilePath metadata_root = ensure_media_directories_exists()->
-      GetFakeAppDataPath().AppendASCII("Google").AppendASCII("Picasa3");
+  PopulatePicasaTestData(
+      ensure_media_directories_exists()->GetFakeAppDataPath());
 #endif
-  PopulatePicasaTestData(metadata_root);
+  ASSERT_TRUE(RunMediaGalleriesTest("picasa")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
+                       PicasaCustomLocation) {
+  base::ScopedTempDir custom_picasa_app_data_root;
+  ASSERT_TRUE(custom_picasa_app_data_root.CreateUniqueTempDir());
+  ensure_media_directories_exists()->SetCustomPicasaAppDataPath(
+      custom_picasa_app_data_root.path());
+  PopulatePicasaTestData(custom_picasa_app_data_root.path());
   ASSERT_TRUE(RunMediaGalleriesTest("picasa")) << message_;
 }
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
-
-#if defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
-                       PicasaCustomLocation) {
-  base::ScopedTempDir fake_alternate_app_data_dir;
-  ASSERT_TRUE(fake_alternate_app_data_dir.CreateUniqueTempDir());
-  ensure_media_directories_exists()->WriteCustomPicasaAppDataPathToRegistry(
-      fake_alternate_app_data_dir.path());
-  base::FilePath metadata_root = fake_alternate_app_data_dir.path()
-      .AppendASCII("Google").AppendASCII("Picasa2");
-  PopulatePicasaTestData(metadata_root);
-  ASSERT_TRUE(RunMediaGalleriesTest("picasa")) << message_;
-}
-#endif  // defined(OS_WIN)
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
index 2fb85d7..3cc95b0 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
@@ -164,7 +164,7 @@
 }
 
 bool MediaGalleriesPrivateAddGalleryWatchFunction::RunImpl() {
-  DCHECK(profile_);
+  DCHECK(GetProfile());
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   if (!render_view_host() || !render_view_host()->GetProcess())
     return false;
@@ -174,7 +174,8 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile_);
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
   preferences->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateAddGalleryWatchFunction::OnPreferencesInit,
       this,
@@ -187,8 +188,11 @@
     const std::string& pref_id) {
   base::FilePath gallery_file_path;
   MediaGalleryPrefId gallery_pref_id = 0;
-  if (!GetGalleryFilePathAndId(pref_id, profile_, GetExtension(),
-                               &gallery_file_path, &gallery_pref_id)) {
+  if (!GetGalleryFilePathAndId(pref_id,
+                               GetProfile(),
+                               GetExtension(),
+                               &gallery_file_path,
+                               &gallery_pref_id)) {
     error_ = kInvalidGalleryIDError;
     HandleResponse(gallery_pref_id, false);
     return;
@@ -196,13 +200,13 @@
 
 #if defined(OS_WIN)
   MediaGalleriesPrivateEventRouter* router =
-      MediaGalleriesPrivateAPI::Get(profile_)->GetEventRouter();
+      MediaGalleriesPrivateAPI::Get(GetProfile())->GetEventRouter();
   DCHECK(router);
   content::BrowserThread::PostTaskAndReplyWithResult(
       content::BrowserThread::FILE,
       FROM_HERE,
       base::Bind(&GalleryWatchManager::SetupGalleryWatch,
-                 profile_,
+                 GetProfile(),
                  gallery_pref_id,
                  gallery_file_path,
                  extension_id(),
@@ -226,10 +230,11 @@
   result.success = success;
   SetResult(result.ToValue().release());
   if (success) {
-    DCHECK(g_browser_process->media_file_system_registry()->
-               GetPreferences(profile_)->IsInitialized());
-    GalleryWatchStateTracker* state_tracker =
-        MediaGalleriesPrivateAPI::Get(profile_)->GetGalleryWatchStateTracker();
+    DCHECK(g_browser_process->media_file_system_registry()
+               ->GetPreferences(GetProfile())
+               ->IsInitialized());
+    GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get(
+        GetProfile())->GetGalleryWatchStateTracker();
     state_tracker->OnGalleryWatchAdded(extension_id(), gallery_id);
   }
   SendResponse(true);
@@ -256,7 +261,8 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile_);
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
   preferences->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateRemoveGalleryWatchFunction::OnPreferencesInit,
       this,
@@ -269,22 +275,26 @@
 #if defined(OS_WIN)
   base::FilePath gallery_file_path;
   MediaGalleryPrefId gallery_pref_id = 0;
-  if (!GetGalleryFilePathAndId(pref_id, profile_, GetExtension(),
-                               &gallery_file_path, &gallery_pref_id)) {
+  if (!GetGalleryFilePathAndId(pref_id,
+                               GetProfile(),
+                               GetExtension(),
+                               &gallery_file_path,
+                               &gallery_pref_id)) {
     error_ = kInvalidGalleryIDError;
     SendResponse(false);
     return;
   }
 
   content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
+      content::BrowserThread::FILE,
+      FROM_HERE,
       base::Bind(&GalleryWatchManager::RemoveGalleryWatch,
-                 profile_,
+                 GetProfile(),
                  gallery_file_path,
                  extension_id()));
 
-  GalleryWatchStateTracker* state_tracker =
-      MediaGalleriesPrivateAPI::Get(profile_)->GetGalleryWatchStateTracker();
+  GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get(
+      GetProfile())->GetGalleryWatchStateTracker();
   state_tracker->OnGalleryWatchRemoved(extension_id(), gallery_pref_id);
 #endif
   SendResponse(true);
@@ -304,7 +314,8 @@
     return false;
 
   MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile_);
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
   preferences->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateGetAllGalleryWatchFunction::OnPreferencesInit,
       this));
@@ -314,8 +325,8 @@
 void MediaGalleriesPrivateGetAllGalleryWatchFunction::OnPreferencesInit() {
   std::vector<std::string> result;
 #if defined(OS_WIN)
-  GalleryWatchStateTracker* state_tracker =
-      MediaGalleriesPrivateAPI::Get(profile_)->GetGalleryWatchStateTracker();
+  GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get(
+      GetProfile())->GetGalleryWatchStateTracker();
   MediaGalleryPrefIdSet gallery_ids =
       state_tracker->GetAllWatchedGalleryIDsForExtension(extension_id());
   for (MediaGalleryPrefIdSet::const_iterator iter = gallery_ids.begin();
@@ -341,7 +352,8 @@
     return false;
 
   MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile_);
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
   preferences->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateRemoveAllGalleryWatchFunction::OnPreferencesInit,
       this));
@@ -351,9 +363,10 @@
 void MediaGalleriesPrivateRemoveAllGalleryWatchFunction::OnPreferencesInit() {
 #if defined(OS_WIN)
   MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile_);
-  GalleryWatchStateTracker* state_tracker =
-      MediaGalleriesPrivateAPI::Get(profile_)->GetGalleryWatchStateTracker();
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
+  GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get(
+      GetProfile())->GetGalleryWatchStateTracker();
   state_tracker->RemoveAllGalleryWatchersForExtension(
       extension_id(), preferences);
 #endif
@@ -372,7 +385,7 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
   ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
+      extensions::ExtensionSystem::Get(GetProfile())->extension_service();
   DCHECK(service);
 
   ListValue* result_list = new ListValue;
@@ -381,7 +394,7 @@
        iter != service->extensions()->end();
        ++iter) {
     const Extension* extension = iter->get();
-    if (profile_->IsOffTheRecord() &&
+    if (GetProfile()->IsOffTheRecord() &&
         !extension_util::IsIncognitoEnabled(extension->id(), service))
       continue;
 
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h
index b2b27c2..129296f 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h
@@ -12,8 +12,8 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
 #include "chrome/common/extensions/api/media_galleries_private.h"
 
@@ -74,7 +74,7 @@
 
 // Implements the chrome.mediaGalleriesPrivate.addGalleryWatch method.
 class MediaGalleriesPrivateAddGalleryWatchFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.addGalleryWatch",
                              MEDIAGALLERIESPRIVATE_ADDGALLERYWATCH);
@@ -94,7 +94,7 @@
 
 // Implements the chrome.mediaGalleriesPrivate.removeGalleryWatch method.
 class MediaGalleriesPrivateRemoveGalleryWatchFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.removeGalleryWatch",
                              MEDIAGALLERIESPRIVATE_REMOVEGALLERYWATCH);
@@ -111,7 +111,7 @@
 
 // Implements the chrome.mediaGalleriesPrivate.getAllGalleryWatch method.
 class MediaGalleriesPrivateGetAllGalleryWatchFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.getAllGalleryWatch",
                              MEDIAGALLERIESPRIVATE_GETALLGALLERYWATCH);
@@ -127,7 +127,7 @@
 
 // Implements the chrome.mediaGalleriesPrivate.removeAllGalleryWatch method.
 class MediaGalleriesPrivateRemoveAllGalleryWatchFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.removeAllGalleryWatch",
                              MEDIAGALLERIESPRIVATE_REMOVEALLGALLERYWATCH);
@@ -143,7 +143,7 @@
 
 // Implements the chrome.mediaGalleriesPrivate.getHandlers method.
 class MediaGalleriesPrivateGetHandlersFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.getHandlers",
                              MEDIAGALLERIESPRIVATE_GETHANDLERS);
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc
index 9d14a6e..9e0ca61 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -47,10 +47,10 @@
       routing_id_, source_port_id, error_message));
 }
 
-void ExtensionMessagePort::DispatchOnMessage(const std::string& message,
+void ExtensionMessagePort::DispatchOnMessage(const Message& message,
                                              int target_port_id) {
-    process_->Send(new ExtensionMsg_DeliverMessage(
-        routing_id_, target_port_id, message));
+  process_->Send(new ExtensionMsg_DeliverMessage(
+      routing_id_, target_port_id, message));
 }
 
 void ExtensionMessagePort::IncrementLazyKeepaliveCount() {
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.h b/chrome/browser/extensions/api/messaging/extension_message_port.h
index 1e7b788..d0a6273 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.h
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.h
@@ -31,7 +31,7 @@
       const std::string& tls_channel_id) OVERRIDE;
   virtual void DispatchOnDisconnect(int source_port_id,
                                     const std::string& error_message) OVERRIDE;
-  virtual void DispatchOnMessage(const std::string& message,
+  virtual void DispatchOnMessage(const Message& message,
                                  int target_port_id) OVERRIDE;
   virtual void IncrementLazyKeepaliveCount() OVERRIDE;
   virtual void DecrementLazyKeepaliveCount() OVERRIDE;
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 754bc10..d2951ec 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/extensions/process_map.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tab_contents/tab_util.h"
@@ -38,6 +37,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "extensions/common/manifest_constants.h"
 #include "net/base/completion_callback.h"
 #include "url/gurl.h"
@@ -530,7 +530,7 @@
 }
 
 void MessageService::PostMessage(
-    int source_port_id, const std::string& message) {
+    int source_port_id, const Message& message) {
   int channel_id = GET_CHANNEL_ID(source_port_id);
   MessageChannelMap::iterator iter = channels_.find(channel_id);
   if (iter == channels_.end()) {
@@ -545,7 +545,7 @@
 
 void MessageService::PostMessageFromNativeProcess(int port_id,
                                                   const std::string& message) {
-  PostMessage(port_id, message);
+  PostMessage(port_id, Message(message, false /* user_gesture */));
 }
 
 void MessageService::Observe(int type,
@@ -593,7 +593,7 @@
 
 void MessageService::EnqueuePendingMessage(int source_port_id,
                                            int channel_id,
-                                           const std::string& message) {
+                                           const Message& message) {
   PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
       pending_tls_channel_id_channels_.find(channel_id);
   if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
@@ -611,7 +611,7 @@
 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
     int source_port_id,
     int channel_id,
-    const std::string& message) {
+    const Message& message) {
   PendingLazyBackgroundPageChannelMap::iterator pending =
       pending_lazy_background_page_channels_.find(channel_id);
   if (pending != pending_lazy_background_page_channels_.end()) {
@@ -624,7 +624,7 @@
 
 void MessageService::DispatchMessage(int source_port_id,
                                      MessageChannel* channel,
-                                     const std::string& message) {
+                                     const Message& message) {
   // Figure out which port the ID corresponds to.
   int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
   MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h
index 168da41..ed6eae9 100644
--- a/chrome/browser/extensions/api/messaging/message_service.h
+++ b/chrome/browser/extensions/api/messaging/message_service.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/extensions/api/messaging/message_property_provider.h"
 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/common/extensions/api/messaging/message.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -85,7 +86,7 @@
                                       const std::string& error_message) {}
 
     // Dispatch a message to this end of the communication.
-    virtual void DispatchOnMessage(const std::string& message,
+    virtual void DispatchOnMessage(const Message& message,
                                    int target_port_id) = 0;
 
     // MessagPorts that target extensions will need to adjust their keepalive
@@ -149,7 +150,7 @@
 
   // Enqueues a message on a pending channel, or sends a message to the given
   // port if the channel isn't pending.
-  void PostMessage(int port_id, const std::string& message);
+  void PostMessage(int port_id, const Message& message);
 
   // NativeMessageProcessHost::Client
   virtual void PostMessageFromNativeProcess(
@@ -164,7 +165,7 @@
   // A map of channel ID to its channel object.
   typedef std::map<int, MessageChannel*> MessageChannelMap;
 
-  typedef std::pair<int, std::string> PendingMessage;
+  typedef std::pair<int, Message> PendingMessage;
   typedef std::vector<PendingMessage> PendingMessagesQueue;
   // A set of channel IDs waiting for TLS channel IDs to complete opening,
   // and any pending messages queued to be sent on those channels.
@@ -202,16 +203,16 @@
 
   // Enqueues a message on a pending channel.
   void EnqueuePendingMessage(int port_id, int channel_id,
-                             const std::string& message);
+                             const Message& message);
 
   // Enqueues a message on a channel pending on a lazy background page load.
   void EnqueuePendingMessageForLazyBackgroundLoad(int port_id,
                                                   int channel_id,
-                                                  const std::string& message);
+                                                  const Message& message);
 
   // Immediately sends a message to the given port.
   void DispatchMessage(int port_id, MessageChannel* channel,
-                       const std::string& message);
+                       const Message& message);
 
   // Potentially registers a pending task with the LazyBackgroundTaskQueue
   // to open a channel. Returns true if a task was queued.
@@ -235,7 +236,7 @@
       CloseChannel(port_id, error_message);
   }
   void PendingLazyBackgroundPagePostMessage(int port_id,
-                                            const std::string& message,
+                                            const Message& message,
                                             extensions::ExtensionHost* host) {
     if (host)
       PostMessage(port_id, message);
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.cc b/chrome/browser/extensions/api/messaging/native_message_port.cc
index e746e29..a0a47d5 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_port.cc
@@ -19,12 +19,13 @@
       content::BrowserThread::IO, FROM_HERE, native_process_);
 }
 
-void NativeMessagePort::DispatchOnMessage(const std::string& message,
-                                          int target_port_id) {
+void NativeMessagePort::DispatchOnMessage(
+    const Message& message,
+    int target_port_id) {
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(&NativeMessageProcessHost::Send,
-                 base::Unretained(native_process_), message));
+                 base::Unretained(native_process_), message.data));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.h b/chrome/browser/extensions/api/messaging/native_message_port.h
index 6afce8a..f94db96 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.h
+++ b/chrome/browser/extensions/api/messaging/native_message_port.h
@@ -16,7 +16,7 @@
   // Takes ownership of |native_process|.
   explicit NativeMessagePort(NativeMessageProcessHost* native_process);
   virtual ~NativeMessagePort();
-  virtual void DispatchOnMessage(const std::string& message,
+  virtual void DispatchOnMessage(const Message& message,
                                  int target_port_id) OVERRIDE;
 
  private:
diff --git a/chrome/browser/extensions/api/module/module.cc b/chrome/browser/extensions/api/module/module.cc
index 31e849c..8847359 100644
--- a/chrome/browser/extensions/api/module/module.cc
+++ b/chrome/browser/extensions/api/module/module.cc
@@ -39,16 +39,14 @@
   std::string data;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &data));
 
-  ExtensionPrefs::Get(profile())->UpdateExtensionPref(
-      extension_id(),
-      extension::kUpdateURLData,
-      new base::StringValue(data));
+  ExtensionPrefs::Get(GetProfile())->UpdateExtensionPref(
+      extension_id(), extension::kUpdateURLData, new base::StringValue(data));
   return true;
 }
 
 bool ExtensionIsAllowedIncognitoAccessFunction::RunImpl() {
   ExtensionService* ext_service =
-      ExtensionSystem::Get(profile())->extension_service();
+      ExtensionSystem::Get(GetProfile())->extension_service();
   const Extension* extension = GetExtension();
 
   SetResult(new base::FundamentalValue(
@@ -58,7 +56,7 @@
 
 bool ExtensionIsAllowedFileSchemeAccessFunction::RunImpl() {
   ExtensionService* ext_service =
-      ExtensionSystem::Get(profile())->extension_service();
+      ExtensionSystem::Get(GetProfile())->extension_service();
   const Extension* extension = GetExtension();
 
   SetResult(new base::FundamentalValue(
diff --git a/chrome/browser/extensions/api/module/module.h b/chrome/browser/extensions/api/module/module.h
index 37f627d..4f4af03 100644
--- a/chrome/browser/extensions/api/module/module.h
+++ b/chrome/browser/extensions/api/module/module.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_MODULE_MODULE_H_
 #define CHROME_BROWSER_EXTENSIONS_API_MODULE_MODULE_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 class ExtensionPrefs;
@@ -16,7 +16,7 @@
                              const std::string& extension_id);
 }  // namespace extension
 
-class ExtensionSetUpdateUrlDataFunction : public SyncExtensionFunction {
+class ExtensionSetUpdateUrlDataFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("extension.setUpdateUrlData",
                              EXTENSION_SETUPDATEURLDATA)
@@ -28,7 +28,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class ExtensionIsAllowedIncognitoAccessFunction : public SyncExtensionFunction {
+class ExtensionIsAllowedIncognitoAccessFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("extension.isAllowedIncognitoAccess",
                              EXTENSION_ISALLOWEDINCOGNITOACCESS)
@@ -41,7 +42,7 @@
 };
 
 class ExtensionIsAllowedFileSchemeAccessFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("extension.isAllowedFileSchemeAccess",
                              EXTENSION_ISALLOWEDFILESCHEMEACCESS)
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
index 5d392b4..a6b7962 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 
-#include "base/message_loop/message_loop.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 
 namespace extensions {
@@ -13,18 +12,7 @@
 // ChromeOS: Use the System Salt.
 /* static */
 void DeviceId::GetMachineId(const IdCallback& callback) {
-  chromeos::SystemSaltGetter* c_home = chromeos::SystemSaltGetter::Get();
-  std::string result = c_home->GetSystemSaltSync();
-  if (result.empty()) {
-    // cryptohome must not be running; re-request after a delay.
-    const int64 kRequestSystemSaltDelayMs = 500;
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&DeviceId::GetMachineId, callback),
-        base::TimeDelta::FromMilliseconds(kRequestSystemSaltDelayMs));
-    return;
-  }
-  callback.Run(result);
+  chromeos::SystemSaltGetter::Get()->GetSystemSalt(callback);
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc b/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
index a408e5b..b804611 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_linux.cc
@@ -4,22 +4,67 @@
 
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 
+#include <map>
+
 #include "base/bind.h"
 #include "base/file_util.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace {
 
-const char kDBusFilename[] = "/var/lib/dbus/machine-id";
+const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
+const char* kDeviceNames[] = { "sda1", "hda1", "dm-0" };
 
-void GetDBusMachineId(const extensions::api::DeviceId::IdCallback& callback) {
+// Map from device name to disk uuid
+typedef std::map<base::FilePath, base::FilePath> DiskEntries;
+
+void GetDiskUuid(const extensions::api::DeviceId::IdCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
 
+  DiskEntries disk_uuids;
+
+  base::FileEnumerator files(base::FilePath(kDiskByUuidDirectoryName),
+                             false,  // Recursive.
+                             base::FileEnumerator::FILES);
+  do {
+    base::FilePath file_path = files.Next();
+    if (file_path.empty())
+      break;
+
+    base::FilePath target_path;
+    if (!file_util::ReadSymbolicLink(file_path, &target_path))
+      continue;
+
+    base::FilePath device_name = target_path.BaseName();
+    base::FilePath disk_uuid = file_path.BaseName();
+    disk_uuids[device_name] = disk_uuid;
+  } while (true);
+
+  // Look for first device name matching an entry of |kDeviceNames|.
   std::string result;
-  if (!base::ReadFileToString(base::FilePath(kDBusFilename), &result)) {
-    DLOG(WARNING) << "Error reading dbus machine id file.";
-    result = "";
+  for (size_t i = 0; i < arraysize(kDeviceNames); i++) {
+    DiskEntries::iterator it =
+        disk_uuids.find(base::FilePath(kDeviceNames[i]));
+    if (it != disk_uuids.end()) {
+      DVLOG(1) << "Returning uuid: \"" << it->second.value()
+               << "\" for device \"" << it->first.value() << "\"";
+      result = it->second.value();
+      break;
+    }
+  }
+
+  // Log failure (at most once) for diagnostic purposes.
+  static bool error_logged = false;
+  if (result.empty() && !error_logged) {
+    error_logged = true;
+    LOG(ERROR) << "Could not find appropriate disk uuid.";
+    for (DiskEntries::iterator it = disk_uuids.begin();
+        it != disk_uuids.end(); ++it) {
+      LOG(ERROR) << "  DeviceID=" << it->first.value() << ", uuid="
+                 << it->second.value();
+    }
   }
 
   content::BrowserThread::PostTask(
@@ -28,12 +73,12 @@
       base::Bind(callback, result));
 }
 
-}
+}  // namespace
 
 namespace extensions {
 namespace api {
 
-// Linux: Use the content of the "DBus" machine-id file.
+// Linux: Look for disk uuid
 /* static */
 void DeviceId::GetMachineId(const IdCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -41,7 +86,7 @@
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(GetDBusMachineId, callback));
+      base::Bind(GetDiskUuid, callback));
 }
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api.h b/chrome/browser/extensions/api/networking_private/networking_private_api.h
index 08b2708..2abe33e 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api.h
@@ -12,12 +12,13 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/values.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
 // Implements the chrome.networkingPrivate.getProperties method.
-class NetworkingPrivateGetPropertiesFunction : public AsyncExtensionFunction {
+class NetworkingPrivateGetPropertiesFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateGetPropertiesFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.getProperties",
@@ -39,7 +40,7 @@
 
 // Implements the chrome.networkingPrivate.getManagedProperties method.
 class NetworkingPrivateGetManagedPropertiesFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateGetManagedPropertiesFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.getManagedProperties",
@@ -62,7 +63,7 @@
 };
 
 // Implements the chrome.networkingPrivate.getState method.
-class NetworkingPrivateGetStateFunction : public AsyncExtensionFunction {
+class NetworkingPrivateGetStateFunction : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateGetStateFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.getState",
@@ -79,7 +80,8 @@
 };
 
 // Implements the chrome.networkingPrivate.setProperties method.
-class NetworkingPrivateSetPropertiesFunction : public AsyncExtensionFunction {
+class NetworkingPrivateSetPropertiesFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateSetPropertiesFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.setProperties",
@@ -99,7 +101,8 @@
 };
 
 // Implements the chrome.networkingPrivate.createNetwork method.
-class NetworkingPrivateCreateNetworkFunction : public AsyncExtensionFunction {
+class NetworkingPrivateCreateNetworkFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateCreateNetworkFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.createNetwork",
@@ -120,7 +123,7 @@
 
 // Implements the chrome.networkingPrivate.getVisibleNetworks method.
 class NetworkingPrivateGetVisibleNetworksFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   NetworkingPrivateGetVisibleNetworksFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.getVisibleNetworks",
@@ -138,7 +141,7 @@
 
 // Implements the chrome.networkingPrivate.getEnabledNetworkTypes method.
 class NetworkingPrivateGetEnabledNetworkTypesFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   NetworkingPrivateGetEnabledNetworkTypesFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.getEnabledNetworkTypes",
@@ -156,7 +159,7 @@
 
 // Implements the chrome.networkingPrivate.enableNetworkType method.
 class NetworkingPrivateEnableNetworkTypeFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   NetworkingPrivateEnableNetworkTypeFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.enableNetworkType",
@@ -174,7 +177,7 @@
 
 // Implements the chrome.networkingPrivate.disableNetworkType method.
 class NetworkingPrivateDisableNetworkTypeFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   NetworkingPrivateDisableNetworkTypeFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.disableNetworkType",
@@ -192,7 +195,7 @@
 
 // Implements the chrome.networkingPrivate.requestNetworkScan method.
 class NetworkingPrivateRequestNetworkScanFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   NetworkingPrivateRequestNetworkScanFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.requestNetworkScan",
@@ -210,7 +213,8 @@
 
 
 // Implements the chrome.networkingPrivate.startConnect method.
-class NetworkingPrivateStartConnectFunction : public AsyncExtensionFunction {
+class NetworkingPrivateStartConnectFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateStartConnectFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.startConnect",
@@ -236,7 +240,7 @@
 
 // Implements the chrome.networkingPrivate.startDisconnect method.
 class NetworkingPrivateStartDisconnectFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateStartDisconnectFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.startDisconnect",
@@ -262,7 +266,7 @@
 
 // Implements the chrome.networkingPrivate.verifyDestination method.
 class NetworkingPrivateVerifyDestinationFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateVerifyDestinationFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.verifyDestination",
@@ -283,7 +287,7 @@
 
 // Implements the chrome.networkingPrivate.verifyAndEncryptCredentials method.
 class NetworkingPrivateVerifyAndEncryptCredentialsFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateVerifyAndEncryptCredentialsFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.verifyAndEncryptCredentials",
@@ -305,7 +309,7 @@
 
 // Implements the chrome.networkingPrivate.verifyAndEncryptData method.
 class NetworkingPrivateVerifyAndEncryptDataFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   NetworkingPrivateVerifyAndEncryptDataFunction() {}
   DECLARE_EXTENSION_FUNCTION("networkingPrivate.verifyAndEncryptData",
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
index a2f6e79..82633a5 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
@@ -120,7 +120,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   std::string user_id_hash;
-  GetUserIdHash(profile());
+  GetUserIdHash(GetProfile());
   NetworkHandler::Get()->managed_network_configuration_handler()->
       GetManagedProperties(
           user_id_hash,
@@ -231,7 +231,7 @@
 
   std::string user_id_hash;
   if (!params->shared)
-    user_id_hash = GetUserIdHash(profile());
+    user_id_hash = GetUserIdHash(GetProfile());
 
   scoped_ptr<base::DictionaryValue> properties_dict(
       params->properties.ToValue());
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
index 467b9b7..03fcd4c 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
@@ -44,8 +44,8 @@
 
   // If there are properties set by SetProperties function, use those.
   NetworkingPrivatePropertiesData* stored_properties =
-    static_cast<NetworkingPrivatePropertiesData*> (
-        profile()->GetUserData(kNetworkingPrivateProperties));
+      static_cast<NetworkingPrivatePropertiesData*>(
+          GetProfile()->GetUserData(kNetworkingPrivateProperties));
   if (stored_properties != NULL) {
     SetResult(stored_properties->properties_.release());
     SendResponse(true);
@@ -185,8 +185,9 @@
       params->properties.ToValue());
 
   // Store properties_dict in profile to return from GetProperties.
-  profile()->SetUserData(kNetworkingPrivateProperties,
-    new NetworkingPrivatePropertiesData(properties_dict.get()));
+  GetProfile()->SetUserData(
+      kNetworkingPrivateProperties,
+      new NetworkingPrivatePropertiesData(properties_dict.get()));
   SendResponse(true);
   return true;
 }
@@ -207,7 +208,7 @@
   scoped_ptr<base::DictionaryValue> properties_dict(
       params->properties.ToValue());
   properties_dict->SetString("GUID", "fake_guid");
-  profile()->SetUserData(
+  GetProfile()->SetUserData(
       kNetworkingPrivateProperties,
       new NetworkingPrivatePropertiesData(properties_dict.get()));
 
@@ -351,7 +352,8 @@
   changes.push_back("stub_wifi2");
   changes.push_back("stub_cellular1");
 
-  EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+  EventRouter* event_router =
+      ExtensionSystem::Get(GetProfile())->event_router();
   scoped_ptr<base::ListValue> args(api::OnNetworkListChanged::Create(changes));
   scoped_ptr<extensions::Event> extension_event(new extensions::Event(
       api::OnNetworkListChanged::kEventName, args.Pass()));
@@ -388,13 +390,16 @@
          "\"SignalStrength\":80}}";
 
     // Store network_properties in profile to return from GetProperties.
-    profile()->SetUserData(kNetworkingPrivateProperties,
-      new NetworkingPrivatePropertiesData(
-        static_cast<DictionaryValue*>(
-          base::JSONReader::Read(network_properties))));
+    scoped_ptr<Value> network_properties_value(
+        base::JSONReader::Read(network_properties));
+    GetProfile()->SetUserData(
+        kNetworkingPrivateProperties,
+        new NetworkingPrivatePropertiesData(
+            static_cast<DictionaryValue*>(network_properties_value.get())));
 
     // Broadcast NetworksChanged Event that network is connected
-    EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+    EventRouter* event_router =
+        ExtensionSystem::Get(GetProfile())->event_router();
     scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
         std::vector<std::string>(1, params->network_guid)));
     scoped_ptr<extensions::Event> netchanged_event(
@@ -435,7 +440,8 @@
     SendResponse(true);
 
     // Send Event that network is disconnected. Listener will use GetProperties.
-    EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+    EventRouter* event_router =
+        ExtensionSystem::Get(GetProfile())->event_router();
     scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
         std::vector<std::string>(1, params->network_guid)));
     scoped_ptr<extensions::Event> extension_event(
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 1625432..56203e1 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -327,10 +327,8 @@
     optional_fields.clickable = *options->is_clickable;
 
   NotificationsApiDelegate* api_delegate(new NotificationsApiDelegate(
-      this,
-      profile(),
-      extension_->id(),
-      id));  // ownership is passed to Notification
+      this, GetProfile(), extension_->id(), id));  // ownership is passed to
+                                                   // Notification
   Notification notification(type,
                             extension_->url(),
                             title,
@@ -345,7 +343,7 @@
                             optional_fields,
                             api_delegate);
 
-  g_browser_process->notification_ui_manager()->Add(notification, profile());
+  g_browser_process->notification_ui_manager()->Add(notification, GetProfile());
   return true;
 }
 
@@ -442,16 +440,24 @@
   if (options->is_clickable.get())
     notification->set_clickable(*options->is_clickable);
 
-  g_browser_process->notification_ui_manager()->Update(
-      *notification, profile());
+  g_browser_process->notification_ui_manager()->Update(*notification,
+                                                       GetProfile());
   return true;
 }
 
-bool NotificationsApiFunction::IsNotificationsApiEnabled() {
+bool NotificationsApiFunction::AreExtensionNotificationsAllowed() const {
   DesktopNotificationService* service =
-      DesktopNotificationServiceFactory::GetForProfile(profile());
+      DesktopNotificationServiceFactory::GetForProfile(GetProfile());
   return service->IsNotifierEnabled(message_center::NotifierId(
-      message_center::NotifierId::APPLICATION, extension_->id()));
+             message_center::NotifierId::APPLICATION, extension_->id()));
+}
+
+bool NotificationsApiFunction::IsNotificationsApiEnabled() const {
+  return CanRunWhileDisabled() || AreExtensionNotificationsAllowed();
+}
+
+bool NotificationsApiFunction::CanRunWhileDisabled() const {
+  return false;
 }
 
 bool NotificationsApiFunction::RunImpl() {
@@ -585,7 +591,7 @@
       g_browser_process->notification_ui_manager();
   std::set<std::string> notification_ids =
       notification_ui_manager->GetAllIdsByProfileAndSourceOrigin(
-          profile_, extension_->url());
+          GetProfile(), extension_->url());
 
   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
 
@@ -601,4 +607,26 @@
   return true;
 }
 
+NotificationsGetPermissionLevelFunction::
+NotificationsGetPermissionLevelFunction() {}
+
+NotificationsGetPermissionLevelFunction::
+~NotificationsGetPermissionLevelFunction() {}
+
+bool NotificationsGetPermissionLevelFunction::CanRunWhileDisabled() const {
+  return true;
+}
+
+bool NotificationsGetPermissionLevelFunction::RunNotificationsApi() {
+  api::notifications::PermissionLevel result =
+      AreExtensionNotificationsAllowed()
+          ? api::notifications::PERMISSION_LEVEL_GRANTED
+          : api::notifications::PERMISSION_LEVEL_DENIED;
+
+  SetResult(new base::StringValue(api::notifications::ToString(result)));
+  SendResponse(true);
+
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.h b/chrome/browser/extensions/api/notifications/notifications_api.h
index a465604..1f5eb4c 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.h
+++ b/chrome/browser/extensions/api/notifications/notifications_api.h
@@ -33,7 +33,13 @@
                           api::notifications::NotificationOptions* options,
                           Notification* notification);
 
-  bool IsNotificationsApiEnabled();
+  bool IsNotificationsApiEnabled() const;
+
+  bool AreExtensionNotificationsAllowed() const;
+
+  // Returns true if the API function is still allowed to run even when the
+  // notifications for a notifier have been disabled.
+  virtual bool CanRunWhileDisabled() const;
 
   // Called inside of RunImpl.
   virtual bool RunNotificationsApi() = 0;
@@ -49,7 +55,7 @@
  public:
   NotificationsCreateFunction();
 
-  // UIThreadExtensionFunction:
+  // NotificationsApiFunction:
   virtual bool RunNotificationsApi() OVERRIDE;
 
  protected:
@@ -65,7 +71,7 @@
  public:
   NotificationsUpdateFunction();
 
-  // UIThreadExtensionFunction:
+  // NotificationsApiFunction:
   virtual bool RunNotificationsApi() OVERRIDE;
 
  protected:
@@ -81,7 +87,7 @@
  public:
   NotificationsClearFunction();
 
-  // UIThreadExtensionFunction:
+  // NotificationsApiFunction:
   virtual bool RunNotificationsApi() OVERRIDE;
 
  protected:
@@ -97,7 +103,7 @@
  public:
   NotificationsGetAllFunction();
 
-  // UIThreadExtensionFunction:
+  // NotificationsApiFunction:
   virtual bool RunNotificationsApi() OVERRIDE;
 
  protected:
@@ -107,6 +113,23 @@
   DECLARE_EXTENSION_FUNCTION("notifications.getAll", NOTIFICATIONS_GET_ALL)
 };
 
+class NotificationsGetPermissionLevelFunction :
+    public NotificationsApiFunction {
+ public:
+  NotificationsGetPermissionLevelFunction();
+
+  // NotificationsApiFunction:
+  virtual bool CanRunWhileDisabled() const OVERRIDE;
+  virtual bool RunNotificationsApi() OVERRIDE;
+
+ protected:
+  virtual ~NotificationsGetPermissionLevelFunction();
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("notifications.getPermissionLevel",
+                             NOTIFICATIONS_GET_ALL)
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_NOTIFICATIONS_NOTIFICATIONS_API_H_
diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index bd85021..a41b656 100644
--- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -14,6 +14,7 @@
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_switches.h"
 #include "ui/message_center/message_center_util.h"
+#include "ui/message_center/notifier_settings.h"
 
 using extensions::Extension;
 
@@ -700,3 +701,105 @@
     ASSERT_TRUE(copy_bool_value);
   }
 }
+
+// MessaceCenter-specific test.
+#if defined(RUN_MESSAGE_CENTER_TESTS)
+#define MAYBE_TestGetPermissionLevel TestGetPermissionLevel
+#else
+#define MAYBE_TestGetPermissionLevel DISABLED_TestGetPermissionLevel
+#endif
+
+IN_PROC_BROWSER_TEST_F(NotificationsApiTest, MAYBE_TestGetPermissionLevel) {
+  scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
+
+  // Get permission level for the extension whose notifications are enabled.
+  {
+    scoped_refptr<extensions::NotificationsGetPermissionLevelFunction>
+        notification_function(
+            new extensions::NotificationsGetPermissionLevelFunction());
+
+    notification_function->set_extension(empty_extension.get());
+    notification_function->set_has_callback(true);
+
+    scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+        notification_function.get(),
+        "[]",
+        browser(),
+        utils::NONE));
+
+    EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
+    std::string permission_level;
+    EXPECT_TRUE(result->GetAsString(&permission_level));
+    EXPECT_EQ("granted", permission_level);
+  }
+
+  // Get permission level for the extension whose notifications are disabled.
+  {
+    scoped_refptr<extensions::NotificationsGetPermissionLevelFunction>
+        notification_function(
+            new extensions::NotificationsGetPermissionLevelFunction());
+
+    notification_function->set_extension(empty_extension.get());
+    notification_function->set_has_callback(true);
+
+    message_center::NotifierId notifier_id(
+        message_center::NotifierId::APPLICATION,
+        empty_extension->id());
+    message_center::Notifier notifier(notifier_id, string16(), true);
+    g_browser_process->message_center()->GetNotifierSettingsProvider()->
+        SetNotifierEnabled(notifier, false);
+
+    scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+        notification_function.get(),
+        "[]",
+        browser(),
+        utils::NONE));
+
+    EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
+    std::string permission_level;
+    EXPECT_TRUE(result->GetAsString(&permission_level));
+    EXPECT_EQ("denied", permission_level);
+  }
+}
+
+// MessaceCenter-specific test.
+#if defined(RUN_MESSAGE_CENTER_TESTS)
+#define MAYBE_TestOnPermissionLevelChanged TestOnPermissionLevelChanged
+#else
+#define MAYBE_TestOnPermissionLevelChanged DISABLED_TestOnPermissionLevelChanged
+#endif
+
+IN_PROC_BROWSER_TEST_F(NotificationsApiTest,
+                       MAYBE_TestOnPermissionLevelChanged) {
+  const extensions::Extension* extension =
+      LoadExtensionAndWait("notifications/api/permission");
+  ASSERT_TRUE(extension) << message_;
+
+  // Test permission level changing from granted to denied.
+  {
+    ResultCatcher catcher;
+
+    message_center::NotifierId notifier_id(
+        message_center::NotifierId::APPLICATION,
+        extension->id());
+    message_center::Notifier notifier(notifier_id, string16(), true);
+    g_browser_process->message_center()->GetNotifierSettingsProvider()->
+        SetNotifierEnabled(notifier, false);
+
+    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+  }
+
+  // Test permission level changing from denied to granted.
+  {
+    ResultCatcher catcher;
+
+    message_center::NotifierId notifier_id(
+        message_center::NotifierId::APPLICATION,
+        extension->id());
+    message_center::Notifier notifier(notifier_id, string16(), false);
+    g_browser_process->message_center()->GetNotifierSettingsProvider()->
+        SetNotifierEnabled(notifier, true);
+
+    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+  }
+}
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 30a4fab..e13bd07 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -230,9 +230,9 @@
       if (url_service_) {
         url_service_->Load();
         if (url_service_->loaded()) {
-          url_service_->RegisterExtensionKeyword(extension->id(),
-                                                 extension->name(),
-                                                 keyword);
+          url_service_->RegisterOmniboxKeyword(extension->id(),
+                                               extension->name(),
+                                               keyword);
         } else {
           pending_extensions_.insert(extension);
         }
@@ -244,7 +244,7 @@
     if (!OmniboxInfo::GetKeyword(extension).empty()) {
       if (url_service_) {
         if (url_service_->loaded())
-          url_service_->UnregisterExtensionKeyword(extension->id());
+          url_service_->UnregisterOmniboxKeyword(extension->id());
         else
           pending_extensions_.erase(extension);
       }
@@ -269,9 +269,9 @@
   template_url_sub_.reset();
   for (PendingExtensions::const_iterator i(pending_extensions_.begin());
        i != pending_extensions_.end(); ++i) {
-    url_service_->RegisterExtensionKeyword((*i)->id(),
-                                           (*i)->name(),
-                                           OmniboxInfo::GetKeyword(*i));
+    url_service_->RegisterOmniboxKeyword((*i)->id(),
+                                         (*i)->name(),
+                                         OmniboxInfo::GetKeyword(*i));
   }
   pending_extensions_.clear();
 }
@@ -289,7 +289,7 @@
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
-      content::Source<Profile>(profile_->GetOriginalProfile()),
+      content::Source<Profile>(GetProfile()->GetOriginalProfile()),
       content::Details<SendSuggestions::Params>(params.get()));
 
   return true;
@@ -300,12 +300,11 @@
       SetDefaultSuggestion::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  if (SetOmniboxDefaultSuggestion(profile(),
-                                  extension_id(),
-                                  params->suggestion)) {
+  if (SetOmniboxDefaultSuggestion(
+          GetProfile(), extension_id(), params->suggestion)) {
     content::NotificationService::current()->Notify(
         chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
-        content::Source<Profile>(profile_->GetOriginalProfile()),
+        content::Source<Profile>(GetProfile()->GetOriginalProfile()),
         content::NotificationService::NoDetails());
   }
 
@@ -371,8 +370,7 @@
     const TemplateURL* keyword,
     const string16& remaining_input,
     AutocompleteMatch* match) {
-  DCHECK(keyword->IsExtensionKeyword());
-
+  DCHECK(keyword->GetType() == TemplateURL::OMNIBOX_API_EXTENSION);
 
   scoped_ptr<omnibox::SuggestResult> suggestion(
       GetOmniboxDefaultSuggestion(profile, keyword->GetExtensionId()));
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.h b/chrome/browser/extensions/api/omnibox/omnibox_api.h
index ca2d4b6..f5a7de7 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.h
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.h
@@ -13,7 +13,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_icon_manager.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/common/extensions/api/omnibox.h"
@@ -71,7 +71,7 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionOmniboxEventRouter);
 };
 
-class OmniboxSendSuggestionsFunction : public SyncExtensionFunction {
+class OmniboxSendSuggestionsFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("omnibox.sendSuggestions", OMNIBOX_SENDSUGGESTIONS)
 
@@ -144,7 +144,7 @@
 template <>
 void ProfileKeyedAPIFactory<OmniboxAPI>::DeclareFactoryDependencies();
 
-class OmniboxSetDefaultSuggestionFunction : public SyncExtensionFunction {
+class OmniboxSetDefaultSuggestionFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("omnibox.setDefaultSuggestion",
                              OMNIBOX_SETDEFAULTSUGGESTION)
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
index c40a19e..d520c4f 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -189,9 +189,13 @@
   Browser* browser = NULL;
   content::WebContents* web_contents = NULL;
 
-  if (!ExtensionTabUtil::GetTabById(params_->details.tab_id, profile(),
-                                    include_incognito(), &browser, NULL,
-                                    &web_contents, NULL)) {
+  if (!ExtensionTabUtil::GetTabById(params_->details.tab_id,
+                                    GetProfile(),
+                                    include_incognito(),
+                                    &browser,
+                                    NULL,
+                                    &web_contents,
+                                    NULL)) {
     return NULL;
   }
   return web_contents;
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.h b/chrome/browser/extensions/api/page_capture/page_capture_api.h
index aa76864..b7619c6 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_api.h
+++ b/chrome/browser/extensions/api/page_capture/page_capture_api.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/page_capture.h"
 #include "webkit/common/blob/shareable_file_reference.h"
 
@@ -22,7 +22,7 @@
 
 namespace extensions {
 
-class PageCaptureSaveAsMHTMLFunction : public AsyncExtensionFunction {
+class PageCaptureSaveAsMHTMLFunction : public ChromeAsyncExtensionFunction {
  public:
   PageCaptureSaveAsMHTMLFunction();
 
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc
index cf23aa0..e5ac3aa 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -54,11 +54,10 @@
   scoped_ptr<Contains::Params> params(Contains::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  scoped_refptr<PermissionSet> permissions =
-      helpers::UnpackPermissionSet(
-          params->permissions,
-          ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()),
-          &error_);
+  scoped_refptr<PermissionSet> permissions = helpers::UnpackPermissionSet(
+      params->permissions,
+      ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()),
+      &error_);
   if (!permissions.get())
     return false;
 
@@ -78,11 +77,10 @@
   scoped_ptr<Remove::Params> params(Remove::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  scoped_refptr<PermissionSet> permissions =
-      helpers::UnpackPermissionSet(
-          params->permissions,
-          ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()),
-          &error_);
+  scoped_refptr<PermissionSet> permissions = helpers::UnpackPermissionSet(
+      params->permissions,
+      ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()),
+      &error_);
   if (!permissions.get())
     return false;
 
@@ -109,7 +107,8 @@
     return false;
   }
 
-  PermissionsUpdater(profile()).RemovePermissions(extension, permissions.get());
+  PermissionsUpdater(GetProfile())
+      .RemovePermissions(extension, permissions.get());
   results_ = Remove::Results::Create(true);
   return true;
 }
@@ -128,7 +127,7 @@
 PermissionsRequestFunction::PermissionsRequestFunction() {}
 
 void PermissionsRequestFunction::InstallUIProceed() {
-  PermissionsUpdater perms_updater(profile());
+  PermissionsUpdater perms_updater(GetProfile());
   perms_updater.AddPermissions(GetExtension(), requested_permissions_.get());
 
   results_ = Request::Results::Create(true);
@@ -158,11 +157,10 @@
   scoped_ptr<Request::Params> params(Request::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  requested_permissions_ =
-      helpers::UnpackPermissionSet(
-          params->permissions,
-          ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()),
-          &error_);
+  requested_permissions_ = helpers::UnpackPermissionSet(
+      params->permissions,
+      ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()),
+      &error_);
   if (!requested_permissions_.get())
     return false;
 
@@ -186,11 +184,10 @@
 
   // We don't need to prompt the user if the requested permissions are a subset
   // of the granted permissions set.
-  scoped_refptr<const PermissionSet> granted =
-      ExtensionPrefs::Get(profile_)->
-          GetGrantedPermissions(GetExtension()->id());
+  scoped_refptr<const PermissionSet> granted = ExtensionPrefs::Get(
+      GetProfile())->GetGrantedPermissions(GetExtension()->id());
   if (granted.get() && granted->Contains(*requested_permissions_.get())) {
-    PermissionsUpdater perms_updater(profile());
+    PermissionsUpdater perms_updater(GetProfile());
     perms_updater.AddPermissions(GetExtension(), requested_permissions_.get());
     results_ = Request::Results::Create(true);
     SendResponse(true);
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.h b/chrome/browser/extensions/api/permissions/permissions_api.h
index a0d6ccb..d0d1d39 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.h
+++ b/chrome/browser/extensions/api/permissions/permissions_api.h
@@ -8,16 +8,16 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 
 class ExtensionService;
 
 namespace extensions {
 
 // chrome.permissions.contains
-class PermissionsContainsFunction : public SyncExtensionFunction {
+class PermissionsContainsFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("permissions.contains", PERMISSIONS_CONTAINS)
 
@@ -29,7 +29,7 @@
 };
 
 // chrome.permissions.getAll
-class PermissionsGetAllFunction : public SyncExtensionFunction {
+class PermissionsGetAllFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("permissions.getAll", PERMISSIONS_GETALL)
 
@@ -41,7 +41,7 @@
 };
 
 // chrome.permissions.remove
-class PermissionsRemoveFunction : public SyncExtensionFunction {
+class PermissionsRemoveFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("permissions.remove", PERMISSIONS_REMOVE)
 
@@ -53,7 +53,7 @@
 };
 
 // chrome.permissions.request
-class PermissionsRequestFunction : public AsyncExtensionFunction,
+class PermissionsRequestFunction : public ChromeAsyncExtensionFunction,
                                    public ExtensionInstallPrompt::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("permissions.request", PERMISSIONS_REQUEST)
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index 3b2e70d..620c8c5 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -9,9 +9,9 @@
 #include "base/values.h"
 #include "chrome/common/extensions/api/permissions.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/usb_device_permission.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/url_pattern_set.h"
 
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
index b327840..fe3e860 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
 #include "chrome/common/extensions/api/permissions.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index d2923d1..736112f 100644
--- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/switches.h"
 #include "net/dns/mock_host_resolver.h"
 
diff --git a/chrome/browser/extensions/api/power/power_api_unittest.cc b/chrome/browser/extensions/api/power/power_api_unittest.cc
index 2f55901..2014b48 100644
--- a/chrome/browser/extensions/api/power/power_api_unittest.cc
+++ b/chrome/browser/extensions/api/power/power_api_unittest.cc
@@ -164,7 +164,7 @@
   // been unloaded.
   void UnloadExtension(extensions::Extension* extension) {
     UnloadedExtensionInfo details(
-        extension, extension_misc::UNLOAD_REASON_UNINSTALL);
+        extension, UnloadedExtensionInfo::REASON_UNINSTALL);
     PowerApiManager::GetInstance()->Observe(
         chrome::NOTIFICATION_EXTENSION_UNLOADED,
         content::Source<Profile>(browser()->profile()),
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc b/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
index 6d1bd76..bcd13a5 100644
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
@@ -20,7 +20,7 @@
 DirectSettingFunctionBase::~DirectSettingFunctionBase() {}
 
 PrefService* DirectSettingFunctionBase::GetPrefService() {
-  return profile()->GetPrefs();
+  return GetProfile()->GetPrefs();
 }
 
 bool DirectSettingFunctionBase::IsCalledFromComponentExtension() {
@@ -34,8 +34,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(
-    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(GetProfile())
+                                  ->IsPreferenceOnWhitelist(pref_key));
 
   const PrefService::Preference* preference =
       GetPrefService()->FindPreference(pref_key.c_str());
@@ -58,8 +58,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(
-    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(GetProfile())
+                                  ->IsPreferenceOnWhitelist(pref_key));
 
   DictionaryValue* details = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
@@ -89,8 +89,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(
-    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(GetProfile())
+                                  ->IsPreferenceOnWhitelist(pref_key));
   GetPrefService()->ClearPref(pref_key.c_str());
 
   return true;
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.h b/chrome/browser/extensions/api/preference/chrome_direct_setting.h
index 7e36344..504bc66 100644
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.h
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_H__
 
 #include "base/lazy_instance.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 class PrefService;
 
@@ -14,7 +14,7 @@
 namespace chromedirectsetting {
 
 // Base class to host instance method helpers.
-class DirectSettingFunctionBase : public SyncExtensionFunction {
+class DirectSettingFunctionBase : public ChromeSyncExtensionFunction {
  protected:
   DirectSettingFunctionBase();
   virtual ~DirectSettingFunctionBase();
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc
index 87f9e1c..9711adf 100644
--- a/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -520,7 +520,7 @@
 }
 
 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
-  return ExtensionPrefValueMapFactory::GetForProfile(profile_);
+  return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
 }
 
 template <>
@@ -570,8 +570,8 @@
   std::string browser_pref;
   if (!ValidateBrowserPref(pref_key, &browser_pref))
     return false;
-  PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs()
-                                 : profile_->GetPrefs();
+  PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
+                                 : GetProfile()->GetPrefs();
   const PrefService::Preference* pref =
       prefs->FindPreference(browser_pref.c_str());
   CHECK(pref);
@@ -579,9 +579,8 @@
   scoped_ptr<DictionaryValue> result(new DictionaryValue);
 
   // Retrieve level of control.
-  std::string level_of_control =
-      helpers::GetLevelOfControl(profile_, extension_id(), browser_pref,
-                                 incognito);
+  std::string level_of_control = helpers::GetLevelOfControl(
+      GetProfile(), extension_id(), browser_pref, incognito);
   result->SetString(keys::kLevelOfControl, level_of_control);
 
   // Retrieve pref value.
@@ -599,7 +598,7 @@
 
   // Retrieve incognito status.
   if (incognito) {
-    ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
+    ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
     result->SetBoolean(keys::kIncognitoSpecific,
                        ep->HasIncognitoPrefValue(browser_pref));
   }
@@ -634,21 +633,21 @@
        scope == kExtensionPrefsScopeIncognitoSessionOnly);
   if (incognito) {
     // Regular profiles can't access incognito unless include_incognito is true.
-    if (!profile()->IsOffTheRecord() && !include_incognito()) {
+    if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
       error_ = keys::kIncognitoErrorMessage;
       return false;
     }
   } else {
     // Incognito profiles can't access regular mode ever, they only exist in
     // split mode.
-    if (profile()->IsOffTheRecord()) {
+    if (GetProfile()->IsOffTheRecord()) {
       error_ = "Can't modify regular settings from an incognito context.";
       return false;
     }
   }
 
   if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
-      !profile_->HasOffTheRecordProfile()) {
+      !GetProfile()->HasOffTheRecordProfile()) {
     error_ = keys::kIncognitoSessionOnlyErrorMessage;
     return false;
   }
@@ -657,7 +656,7 @@
   std::string browser_pref;
   if (!ValidateBrowserPref(pref_key, &browser_pref))
     return false;
-  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
   const PrefService::Preference* pref =
       prefs->pref_service()->FindPreference(browser_pref.c_str());
   CHECK(pref);
@@ -687,11 +686,8 @@
     return false;
   }
 
-  PreferenceAPI::Get(profile())->SetExtensionControlledPref(
-      extension_id(),
-      browser_pref,
-      scope,
-      browser_pref_value.release());
+  PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
+      extension_id(), browser_pref, scope, browser_pref_value.release());
   return true;
 }
 
@@ -722,7 +718,7 @@
   } else {
     // Incognito profiles can't access regular mode ever, they only exist in
     // split mode.
-    if (profile()->IsOffTheRecord()) {
+    if (GetProfile()->IsOffTheRecord()) {
       error_ = "Can't modify regular settings from an incognito context.";
       return false;
     }
@@ -732,8 +728,8 @@
   if (!ValidateBrowserPref(pref_key, &browser_pref))
     return false;
 
-  PreferenceAPI::Get(profile())->RemoveExtensionControlledPref(
-      extension_id(), browser_pref, scope);
+  PreferenceAPI::Get(GetProfile())
+      ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/preference/preference_api.h b/chrome/browser/extensions/api/preference/preference_api.h
index 6c955e1..b924126 100644
--- a/chrome/browser/extensions/api/preference/preference_api.h
+++ b/chrome/browser/extensions/api/preference/preference_api.h
@@ -10,8 +10,8 @@
 #include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/extensions/api/content_settings/content_settings_store.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "content/public/browser/notification_observer.h"
 #include "extensions/browser/extension_prefs_scope.h"
 
@@ -175,12 +175,12 @@
 
 // A base class to provide functionality common to the other *PreferenceFunction
 // classes.
-class PreferenceFunction : public SyncExtensionFunction {
+class PreferenceFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~PreferenceFunction();
 
   // Given an |extension_pref_key|, provides its |browser_pref_key| from the
-  // static map in extension_preference.cc. Returns true if the corresponding
+  // static map in preference_api.cc. Returns true if the corresponding
   // browser pref exists and the extension has the API permission needed to
   // modify that pref. Sets |error_| if the extension doesn't have the needed
   // permission.
diff --git a/chrome/browser/extensions/api/preference/preference_helpers.h b/chrome/browser/extensions/api/preference/preference_helpers.h
index f12d8e8..ba227af 100644
--- a/chrome/browser/extensions/api/preference/preference_helpers.h
+++ b/chrome/browser/extensions/api/preference/preference_helpers.h
@@ -7,8 +7,8 @@
 
 #include <string>
 
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "extensions/browser/extension_prefs_scope.h"
+#include "extensions/common/permissions/permission_set.h"
 
 class Profile;
 
diff --git a/chrome/browser/extensions/api/principals_private/principals_private_api.h b/chrome/browser/extensions/api/principals_private/principals_private_api.h
index bf1bdaa..78f5981 100644
--- a/chrome/browser/extensions/api/principals_private/principals_private_api.h
+++ b/chrome/browser/extensions/api/principals_private/principals_private_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_PRINCIPALS_PRIVATE_PRINCIPALS_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_PRINCIPALS_PRIVATE_PRINCIPALS_PRIVATE_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 // WARNING: chrome.principalsPrivate is a set of experimental APIs for the new
 // profile management flows. Every new API must extend
@@ -14,7 +14,7 @@
 
 namespace extensions {
 
-class PrincipalsPrivateExtensionFunction : public SyncExtensionFunction {
+class PrincipalsPrivateExtensionFunction : public ChromeSyncExtensionFunction {
  public:
   PrincipalsPrivateExtensionFunction() {}
 
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index d1032f6..42a4ab9 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -551,16 +551,18 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesAPI::Get(profile_)->processes_event_router()->
-      is_task_manager_listening()) {
+  if (ProcessesAPI::Get(GetProfile())
+          ->processes_event_router()
+          ->is_task_manager_listening()) {
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessIdForTabFunction::GetProcessIdForTab, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
 
-    ProcessesAPI::Get(profile_)->processes_event_router()->
-        StartTaskManagerListening();
+    ProcessesAPI::Get(GetProfile())
+        ->processes_event_router()
+        ->StartTaskManagerListening();
   }
 
   return true;
@@ -573,8 +575,13 @@
 void GetProcessIdForTabFunction::GetProcessIdForTab() {
   content::WebContents* contents = NULL;
   int tab_index = -1;
-  if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(),
-                                    NULL, NULL, &contents, &tab_index)) {
+  if (!ExtensionTabUtil::GetTabById(tab_id_,
+                                    GetProfile(),
+                                    include_incognito(),
+                                    NULL,
+                                    NULL,
+                                    &contents,
+                                    &tab_index)) {
     error_ = ErrorUtils::FormatErrorMessage(
         extensions::tabs_constants::kTabNotFoundError,
         base::IntToString(tab_id_));
@@ -605,16 +612,18 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesAPI::Get(profile_)->processes_event_router()->
-      is_task_manager_listening()) {
+  if (ProcessesAPI::Get(GetProfile())
+          ->processes_event_router()
+          ->is_task_manager_listening()) {
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &TerminateFunction::TerminateProcess, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&TerminateFunction::TerminateProcess, this));
 
-    ProcessesAPI::Get(profile_)->processes_event_router()->
-        StartTaskManagerListening();
+    ProcessesAPI::Get(GetProfile())
+        ->processes_event_router()
+        ->StartTaskManagerListening();
   }
 
   return true;
@@ -685,16 +694,18 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesAPI::Get(profile_)->processes_event_router()->
-      is_task_manager_listening()) {
+  if (ProcessesAPI::Get(GetProfile())
+          ->processes_event_router()
+          ->is_task_manager_listening()) {
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessInfoFunction::GatherProcessInfo, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&GetProcessInfoFunction::GatherProcessInfo, this));
 
-    ProcessesAPI::Get(profile_)->processes_event_router()->
-        StartTaskManagerListening();
+    ProcessesAPI::Get(GetProfile())
+        ->processes_event_router()
+        ->StartTaskManagerListening();
   }
   return true;
 
diff --git a/chrome/browser/extensions/api/processes/processes_api.h b/chrome/browser/extensions/api/processes/processes_api.h
index 21cabad..85455f9 100644
--- a/chrome/browser/extensions/api/processes/processes_api.h
+++ b/chrome/browser/extensions/api/processes/processes_api.h
@@ -10,8 +10,8 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_registrar.h"
@@ -131,7 +131,7 @@
 
 // This extension function returns the Process object for the renderer process
 // currently in use by the specified Tab.
-class GetProcessIdForTabFunction : public AsyncExtensionFunction {
+class GetProcessIdForTabFunction : public ChromeAsyncExtensionFunction {
  public:
   GetProcessIdForTabFunction();
 
@@ -153,7 +153,7 @@
 // Using unique IDs instead of OS process IDs allows two advantages:
 // * guaranteed uniqueness, since OS process IDs can be reused
 // * guards against killing non-Chrome processes
-class TerminateFunction : public AsyncExtensionFunction {
+class TerminateFunction : public ChromeAsyncExtensionFunction {
  public:
   TerminateFunction();
 
@@ -173,7 +173,7 @@
 
 // Extension function which returns a set of Process objects, containing the
 // details corresponding to the process IDs supplied as input.
-class GetProcessInfoFunction : public AsyncExtensionFunction {
+class GetProcessInfoFunction : public ChromeAsyncExtensionFunction {
  public:
   GetProcessInfoFunction();
 
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
index 0d5d6bf..34df716 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
@@ -102,9 +102,9 @@
 
   if (!IsUserLoggedIn()) {
     if (interactive_) {
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile())
           ->AddObserver(this);
-      LoginUIServiceFactory::GetForProfile(profile())->ShowLoginPopup();
+      LoginUIServiceFactory::GetForProfile(GetProfile())->ShowLoginPopup();
       return true;
     } else {
       error_ = kUserNotSignedIn;
@@ -113,7 +113,7 @@
     }
   }
 
-  DVLOG(2) << "Logged in profile name: " << profile()->GetProfileName();
+  DVLOG(2) << "Logged in profile name: " << GetProfile()->GetProfileName();
 
   StartAccessTokenFetch();
   return true;
@@ -124,16 +124,16 @@
       extensions::ObfuscatedGaiaIdFetcher::GetScopes();
   OAuth2TokenService::ScopeSet scopes(scope_vector.begin(), scope_vector.end());
   ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   fetcher_access_token_request_ = token_service->StartRequest(
       token_service->GetPrimaryAccountId(), scopes, this);
 }
 
 void PushMessagingGetChannelIdFunction::OnRefreshTokenAvailable(
     const std::string& account_id) {
-  ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
+  ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile())
       ->RemoveObserver(this);
-  DVLOG(2) << "Newly logged in: " << profile()->GetProfileName();
+  DVLOG(2) << "Newly logged in: " << GetProfile()->GetProfileName();
   StartAccessTokenFetch();
 }
 
@@ -166,12 +166,12 @@
     const std::string& access_token) {
   // Start the async fetch of the Gaia Id.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  net::URLRequestContextGetter* context = profile()->GetRequestContext();
+  net::URLRequestContextGetter* context = GetProfile()->GetRequestContext();
   fetcher_.reset(new ObfuscatedGaiaIdFetcher(context, this, access_token));
 
   // Get the token cache and see if we have already cached a Gaia Id.
   TokenCacheService* token_cache =
-      TokenCacheServiceFactory::GetForProfile(profile());
+      TokenCacheServiceFactory::GetForProfile(GetProfile());
 
   // Check the cache, if we already have a Gaia ID, use it instead of
   // fetching the ID over the network.
@@ -188,7 +188,7 @@
 // Check if the user is logged in.
 bool PushMessagingGetChannelIdFunction::IsUserLoggedIn() const {
   ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
+      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   return token_service->RefreshTokenIsAvailable(
       token_service->GetPrimaryAccountId());
 }
@@ -205,7 +205,7 @@
     base::TimeDelta timeout =
         base::TimeDelta::FromDays(kObfuscatedGaiaIdTimeoutInDays);
     TokenCacheService* token_cache =
-        TokenCacheServiceFactory::GetForProfile(profile());
+        TokenCacheServiceFactory::GetForProfile(GetProfile());
     token_cache->StoreToken(GaiaConstants::kObfuscatedGaiaId, gaia_id,
                             timeout);
   }
@@ -260,7 +260,7 @@
     case GoogleServiceAuthError::ACCOUNT_DISABLED: {
       if (interactive_) {
         LoginUIService* login_ui_service =
-            LoginUIServiceFactory::GetForProfile(profile());
+            LoginUIServiceFactory::GetForProfile(GetProfile());
         // content::NotificationObserver will be called if token is issued.
         login_ui_service->ShowLoginPopup();
       } else {
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_api.h b/chrome/browser/extensions/api/push_messaging/push_messaging_api.h
index d1f0a0c..60c66a0 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_api.h
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_api.h
@@ -14,7 +14,7 @@
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_delegate.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -52,7 +52,7 @@
 };
 
 class PushMessagingGetChannelIdFunction
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public ObfuscatedGaiaIdFetcher::Delegate,
       public OAuth2TokenService::Observer,
       public OAuth2TokenService::Consumer {
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.cc b/chrome/browser/extensions/api/runtime/runtime_api.cc
index 1af8642..185c2ce 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_api.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -31,6 +30,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "extensions/common/error_utils.h"
 #include "url/gurl.h"
 #include "webkit/browser/fileapi/isolated_context.h"
@@ -238,14 +238,15 @@
 }
 
 bool RuntimeGetBackgroundPageFunction::RunImpl() {
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
   ExtensionHost* host = system->process_manager()->
       GetBackgroundHostForExtension(extension_id());
-  if (system->lazy_background_task_queue()->ShouldEnqueueTask(
-          profile(), GetExtension())) {
+  if (system->lazy_background_task_queue()->ShouldEnqueueTask(GetProfile(),
+                                                              GetExtension())) {
     system->lazy_background_task_queue()->AddPendingTask(
-       profile(), extension_id(),
-       base::Bind(&RuntimeGetBackgroundPageFunction::OnPageLoaded, this));
+        GetProfile(),
+        extension_id(),
+        base::Bind(&RuntimeGetBackgroundPageFunction::OnPageLoaded, this));
   } else if (host) {
     OnPageLoaded(host);
   } else {
@@ -275,7 +276,8 @@
     return false;
   }
 
-  SetUninstallUrl(ExtensionPrefs::Get(profile()), extension_id(), url_string);
+  SetUninstallUrl(
+      ExtensionPrefs::Get(GetProfile()), extension_id(), url_string);
   return true;
 }
 
@@ -283,9 +285,10 @@
   // We can't call ReloadExtension directly, since when this method finishes
   // it tries to decrease the reference count for the extension, which fails
   // if the extension has already been reloaded; so instead we post a task.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
       base::Bind(&ExtensionService::ReloadExtension,
-                 profile()->GetExtensionService()->AsWeakPtr(),
+                 GetProfile()->GetExtensionService()->AsWeakPtr(),
                  extension_id()));
   return true;
 }
@@ -296,7 +299,7 @@
 }
 
 bool RuntimeRequestUpdateCheckFunction::RunImpl() {
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
   ExtensionService* service = system->extension_service();
   ExtensionUpdater* updater = service->updater();
   if (!updater) {
@@ -324,7 +327,7 @@
   // that no update is found, but a previous update check might have already
   // queued up an update, so check for that here to make sure we return the
   // right value.
-  ExtensionSystem* system = ExtensionSystem::Get(profile());
+  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
   ExtensionService* service = system->extension_service();
   const Extension* update = service->GetPendingExtensionUpdate(extension_id());
   if (update) {
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.h b/chrome/browser/extensions/api/runtime/runtime_api.h
index 10f35f2..b917ba4 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.h
+++ b/chrome/browser/extensions/api/runtime/runtime_api.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/runtime.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -54,7 +54,7 @@
                                      const std::string& extension_id);
 };
 
-class RuntimeGetBackgroundPageFunction : public AsyncExtensionFunction {
+class RuntimeGetBackgroundPageFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.getBackgroundPage",
                              RUNTIME_GETBACKGROUNDPAGE)
@@ -67,7 +67,7 @@
   void OnPageLoaded(ExtensionHost*);
 };
 
-class RuntimeSetUninstallUrlFunction : public SyncExtensionFunction {
+class RuntimeSetUninstallUrlFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.setUninstallUrl",
                              RUNTIME_SETUNINSTALLURL)
@@ -77,7 +77,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class RuntimeReloadFunction : public SyncExtensionFunction {
+class RuntimeReloadFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.reload", RUNTIME_RELOAD)
 
@@ -86,7 +86,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class RuntimeRequestUpdateCheckFunction : public AsyncExtensionFunction,
+class RuntimeRequestUpdateCheckFunction : public ChromeAsyncExtensionFunction,
                                           public content::NotificationObserver {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.requestUpdateCheck",
@@ -109,7 +109,7 @@
   bool did_reply_;
 };
 
-class RuntimeRestartFunction : public SyncExtensionFunction {
+class RuntimeRestartFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.restart", RUNTIME_RESTART)
 
@@ -118,7 +118,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class RuntimeGetPlatformInfoFunction : public SyncExtensionFunction {
+class RuntimeGetPlatformInfoFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.getPlatformInfo",
                              RUNTIME_GETPLATFORMINFO);
@@ -127,7 +127,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class RuntimeGetPackageDirectoryEntryFunction : public SyncExtensionFunction {
+class RuntimeGetPackageDirectoryEntryFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("runtime.getPackageDirectoryEntry",
                              RUNTIME_GETPACKAGEDIRECTORYENTRY)
diff --git a/chrome/browser/extensions/api/serial/serial_api.cc b/chrome/browser/extensions/api/serial/serial_api.cc
index 3f33da4..a15f7e1 100644
--- a/chrome/browser/extensions/api/serial/serial_api.cc
+++ b/chrome/browser/extensions/api/serial/serial_api.cc
@@ -41,7 +41,7 @@
 }
 
 bool SerialAsyncApiFunction::PrePrepare() {
-  manager_ = ApiResourceManager<SerialConnection>::Get(profile());
+  manager_ = ApiResourceManager<SerialConnection>::Get(GetProfile());
   DCHECK(manager_);
   return true;
 }
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.cc b/chrome/browser/extensions/api/sessions/sessions_api.cc
index 7115dcb..013afa3 100644
--- a/chrome/browser/extensions/api/sessions/sessions_api.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -141,7 +141,7 @@
 
 scoped_ptr<tabs::Tab> SessionsGetRecentlyClosedFunction::CreateTabModel(
     const TabRestoreService::Tab& tab, int session_id, int selected_index) {
-  return CreateTabModelHelper(profile(),
+  return CreateTabModelHelper(GetProfile(),
                               tab.navigations[tab.current_navigation_index],
                               base::IntToString(session_id),
                               tab.tabstrip_index,
@@ -204,7 +204,7 @@
 
   std::vector<linked_ptr<api::sessions::Session> > result;
   TabRestoreService* tab_restore_service =
-      TabRestoreServiceFactory::GetForProfile(profile());
+      TabRestoreServiceFactory::GetForProfile(GetProfile());
   DCHECK(tab_restore_service);
 
   // List of entries. They are ordered from most to least recent.
@@ -228,7 +228,7 @@
     int tab_index,
     int selected_index) {
   std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString();
-  return CreateTabModelHelper(profile(),
+  return CreateTabModelHelper(GetProfile(),
                               tab.navigations[tab.current_navigation_index],
                               session_id,
                               tab_index,
@@ -250,7 +250,7 @@
       continue;
     const sessions::SerializedNavigationEntry& current_navigation =
         tab->navigations.at(tab->normalized_navigation_index());
-    if (chrome::IsNTPURL(current_navigation.virtual_url(), profile())) {
+    if (chrome::IsNTPURL(current_navigation.virtual_url(), GetProfile())) {
       continue;
     }
     tabs_in_window.push_back(tab);
@@ -351,7 +351,7 @@
 
 bool SessionsGetDevicesFunction::RunImpl() {
   ProfileSyncService* service =
-      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
+      ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
   if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
     // Sync not enabled.
     results_ = GetDevices::Results::Create(
@@ -419,7 +419,7 @@
 
 bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) {
   TabRestoreService* tab_restore_service =
-      TabRestoreServiceFactory::GetForProfile(profile());
+      TabRestoreServiceFactory::GetForProfile(GetProfile());
   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
   TabRestoreService::Entries entries = tab_restore_service->entries();
 
@@ -448,7 +448,7 @@
 bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id,
                                                   Browser* browser) {
   TabRestoreService* tab_restore_service =
-      TabRestoreServiceFactory::GetForProfile(profile());
+      TabRestoreServiceFactory::GetForProfile(GetProfile());
   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
   TabRestoreService::Entries entries = tab_restore_service->entries();
 
@@ -496,7 +496,7 @@
 bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id,
                                                     Browser* browser) {
   ProfileSyncService* service =
-      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
+      ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
   if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
     SetError(kSessionSyncError);
     return false;
@@ -541,9 +541,8 @@
 
   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
   // Only restore one window at a time.
-  std::vector<Browser*> browsers =
-      SessionRestore::RestoreForeignSessionWindows(profile(), host_desktop_type,
-                                                   window, window + 1);
+  std::vector<Browser*> browsers = SessionRestore::RestoreForeignSessionWindows(
+      GetProfile(), host_desktop_type, window, window + 1);
   // Will always create one browser because we only restore one window per call.
   DCHECK_EQ(1u, browsers.size());
   return SetResultRestoredWindow(ExtensionTabUtil::GetWindowId(browsers[0]));
@@ -553,9 +552,8 @@
   scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  Browser* browser =
-      chrome::FindBrowserWithProfile(profile(),
-                                     chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser* browser = chrome::FindBrowserWithProfile(
+      GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
   if (!browser) {
     SetError(kNoBrowserToRestoreSession);
     return false;
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.h b/chrome/browser/extensions/api/sessions/sessions_api.h
index 0498b69..c7d9149 100644
--- a/chrome/browser/extensions/api/sessions/sessions_api.h
+++ b/chrome/browser/extensions/api/sessions/sessions_api.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/sessions/tab_restore_service.h"
 #include "chrome/browser/sessions/tab_restore_service_observer.h"
 #include "chrome/common/extensions/api/sessions.h"
@@ -25,7 +25,7 @@
 
 class SessionId;
 
-class SessionsGetRecentlyClosedFunction : public SyncExtensionFunction {
+class SessionsGetRecentlyClosedFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~SessionsGetRecentlyClosedFunction() {}
   virtual bool RunImpl() OVERRIDE;
@@ -43,7 +43,7 @@
       const TabRestoreService::Entry* entry);
 };
 
-class SessionsGetDevicesFunction : public SyncExtensionFunction {
+class SessionsGetDevicesFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~SessionsGetDevicesFunction() {}
   virtual bool RunImpl() OVERRIDE;
@@ -64,7 +64,7 @@
       const browser_sync::SyncedSession* session);
 };
 
-class SessionsRestoreFunction : public SyncExtensionFunction {
+class SessionsRestoreFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~SessionsRestoreFunction() {}
   virtual bool RunImpl() OVERRIDE;
diff --git a/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc b/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc
new file mode 100644
index 0000000..b27d983
--- /dev/null
+++ b/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc
@@ -0,0 +1,215 @@
+// Copyright 2013 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/extensions/api/settings_overrides/settings_overrides_api.h"
+
+#include "base/lazy_instance.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/api/preference/preference_api.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace {
+base::LazyInstance<ProfileKeyedAPIFactory<SettingsOverridesAPI> >
+    g_factory = LAZY_INSTANCE_INITIALIZER;
+
+const char kManyStartupPagesWarning[] = "* specifies more than 1 startup URL. "
+    "All but the first will be ignored.";
+
+using api::manifest_types::ChromeSettingsOverrides;
+
+TemplateURLData ConvertSearchProvider(
+    const ChromeSettingsOverrides::Search_provider& search_provider) {
+  TemplateURLData data;
+
+  data.short_name = UTF8ToUTF16(search_provider.name);
+  data.SetKeyword(UTF8ToUTF16(search_provider.keyword));
+  data.SetURL(search_provider.search_url);
+  if (search_provider.suggest_url)
+    data.suggestions_url = *search_provider.suggest_url;
+  if (search_provider.instant_url)
+    data.instant_url = *search_provider.instant_url;
+  if (search_provider.image_url)
+    data.image_url = *search_provider.image_url;
+  if (search_provider.search_url_post_params)
+    data.search_url_post_params = *search_provider.search_url_post_params;
+  if (search_provider.suggest_url_post_params)
+    data.suggestions_url_post_params = *search_provider.suggest_url_post_params;
+  if (search_provider.instant_url_post_params)
+    data.instant_url_post_params = *search_provider.instant_url_post_params;
+  if (search_provider.image_url_post_params)
+    data.image_url_post_params = *search_provider.image_url_post_params;
+  data.favicon_url = GURL(search_provider.favicon_url);
+  data.show_in_default_list = true;
+  data.safe_for_autoreplace = false;
+  data.input_encodings.push_back(search_provider.encoding);
+  data.date_created = base::Time();
+  data.last_modified = base::Time();
+  data.prepopulate_id = 0;
+  if (search_provider.alternate_urls) {
+    for (size_t i = 0; i < search_provider.alternate_urls->size(); ++i) {
+      if (!search_provider.alternate_urls->at(i).empty())
+        data.alternate_urls.push_back(search_provider.alternate_urls->at(i));
+    }
+  }
+  return data;
+}
+}  // namespace
+
+SettingsOverridesAPI::SettingsOverridesAPI(Profile* profile)
+    : profile_(profile),
+      url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
+  DCHECK(profile);
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
+                 content::Source<Profile>(profile));
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                 content::Source<Profile>(profile));
+}
+
+SettingsOverridesAPI::~SettingsOverridesAPI() {
+}
+
+ProfileKeyedAPIFactory<SettingsOverridesAPI>*
+    SettingsOverridesAPI::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
+void SettingsOverridesAPI::SetPref(const std::string& extension_id,
+                                   const std::string& pref_key,
+                                   base::Value* value) {
+  PreferenceAPI::Get(profile_)->SetExtensionControlledPref(
+      extension_id,
+      pref_key,
+      kExtensionPrefsScopeRegular,
+      value);
+}
+
+void SettingsOverridesAPI::UnsetPref(const std::string& extension_id,
+                                     const std::string& pref_key) {
+  PreferenceAPI::Get(profile_)->RemoveExtensionControlledPref(
+      extension_id,
+      pref_key,
+      kExtensionPrefsScopeRegular);
+}
+
+void SettingsOverridesAPI::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  switch (type) {
+    case chrome::NOTIFICATION_EXTENSION_LOADED: {
+      const Extension* extension =
+          content::Details<const Extension>(details).ptr();
+      const SettingsOverrides* settings =
+          SettingsOverrides::Get(extension);
+      if (settings) {
+        if (settings->homepage) {
+          SetPref(extension->id(), prefs::kHomePage,
+                  new base::StringValue(settings->homepage->spec()));
+          SetPref(extension->id(), prefs::kHomePageIsNewTabPage,
+                  new base::FundamentalValue(false));
+        }
+        if (!settings->startup_pages.empty()) {
+          SetPref(extension->id(), prefs::kRestoreOnStartup,
+                  new base::FundamentalValue(
+                      SessionStartupPref::kPrefValueURLs));
+          if (settings->startup_pages.size() > 1) {
+            VLOG(1) << extensions::ErrorUtils::FormatErrorMessage(
+                kManyStartupPagesWarning, manifest_keys::kSettingsOverride);
+          }
+          scoped_ptr<ListValue> url_list(new ListValue);
+          url_list->Append(new StringValue(settings->startup_pages[0].spec()));
+          SetPref(extension->id(), prefs::kURLsToRestoreOnStartup,
+                  url_list.release());
+        }
+        if (settings->search_engine) {
+          DCHECK(url_service_);
+          if (url_service_->loaded()) {
+            RegisterSearchProvider(extension);
+          } else {
+            if (!template_url_sub_) {
+              template_url_sub_ = url_service_->RegisterOnLoadedCallback(
+                  base::Bind(&SettingsOverridesAPI::OnTemplateURLsLoaded,
+                             base::Unretained(this)));
+            }
+            url_service_->Load();
+            pending_extensions_.insert(extension);
+          }
+        }
+      }
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+      const Extension* extension =
+          content::Details<UnloadedExtensionInfo>(details)->extension;
+      const SettingsOverrides* settings = SettingsOverrides::Get(extension);
+      if (settings) {
+        if (settings->homepage) {
+          UnsetPref(extension->id(), prefs::kHomePage);
+          UnsetPref(extension->id(), prefs::kHomePageIsNewTabPage);
+        }
+        if (!settings->startup_pages.empty()) {
+          UnsetPref(extension->id(), prefs::kRestoreOnStartup);
+          UnsetPref(extension->id(), prefs::kURLsToRestoreOnStartup);
+        }
+        if (settings->search_engine) {
+          DCHECK(url_service_);
+          if (url_service_->loaded())
+            url_service_->RemoveExtensionControlledTURL(extension->id());
+          else
+            pending_extensions_.erase(extension);
+        }
+      }
+      break;
+    }
+    default: {
+      NOTREACHED();
+      break;
+    }
+  }
+}
+
+void SettingsOverridesAPI::Shutdown() {
+  template_url_sub_.reset();
+}
+
+void SettingsOverridesAPI::OnTemplateURLsLoaded() {
+  // Register search providers for pending extensions.
+  template_url_sub_.reset();
+  for (PendingExtensions::const_iterator i(pending_extensions_.begin());
+       i != pending_extensions_.end(); ++i) {
+    RegisterSearchProvider(*i);
+  }
+  pending_extensions_.clear();
+}
+
+void SettingsOverridesAPI::RegisterSearchProvider(
+    const Extension* extension) const {
+  DCHECK(url_service_);
+  DCHECK(extension);
+  const SettingsOverrides* settings = SettingsOverrides::Get(extension);
+  DCHECK(settings);
+  DCHECK(settings->search_engine);
+  scoped_ptr<AssociatedExtensionInfo> info(new AssociatedExtensionInfo);
+  info->extension_id = extension->id();
+  info->wants_to_be_default_engine = settings->search_engine->is_default;
+  info->install_time =
+      ExtensionPrefs::Get(profile_)->GetInstallTime(extension->id());
+  TemplateURLData data = ConvertSearchProvider(*settings->search_engine);
+  url_service_->AddExtensionControlledTURL(new TemplateURL(profile_, data),
+                                           info.Pass());
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h b/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h
new file mode 100644
index 0000000..a65b339
--- /dev/null
+++ b/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h
@@ -0,0 +1,69 @@
+// Copyright 2013 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_EXTENSIONS_API_SETTINGS_OVERRIDES_SETTINGS_OVERRIDES_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SETTINGS_OVERRIDES_SETTINGS_OVERRIDES_API_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class TemplateURL;
+
+namespace extensions {
+
+class SettingsOverridesAPI : public ProfileKeyedAPI,
+                             public content::NotificationObserver {
+ public:
+  explicit SettingsOverridesAPI(Profile* profile);
+  virtual ~SettingsOverridesAPI();
+
+  // ProfileKeyedAPI implementation.
+  static ProfileKeyedAPIFactory<SettingsOverridesAPI>* GetFactoryInstance();
+
+ private:
+  friend class ProfileKeyedAPIFactory<SettingsOverridesAPI>;
+
+  typedef std::set<scoped_refptr<const Extension> > PendingExtensions;
+
+  // Wrappers around PreferenceAPI.
+  void SetPref(const std::string& extension_id,
+               const std::string& pref_key,
+               base::Value* value);
+  void UnsetPref(const std::string& extension_id,
+                 const std::string& pref_key);
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+  // BrowserContextKeyedService implementation.
+  virtual void Shutdown() OVERRIDE;
+
+  void OnTemplateURLsLoaded();
+
+  void RegisterSearchProvider(const Extension* extension) const;
+  // ProfileKeyedAPI implementation.
+  static const char* service_name() { return "SettingsOverridesAPI"; }
+
+  Profile* profile_;
+  TemplateURLService* url_service_;
+
+  // List of extensions waiting for the TemplateURLService to Load to
+  // have search provider registered.
+  PendingExtensions pending_extensions_;
+
+  content::NotificationRegistrar registrar_;
+  scoped_ptr<TemplateURLService::Subscription> template_url_sub_;
+
+  DISALLOW_COPY_AND_ASSIGN(SettingsOverridesAPI);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SETTINGS_OVERRIDES_SETTINGS_OVERRIDES_API_H_
diff --git a/chrome/browser/extensions/api/settings_overrides/settings_overrides_browsertest.cc b/chrome/browser/extensions/api/settings_overrides/settings_overrides_browsertest.cc
new file mode 100644
index 0000000..240bdd6
--- /dev/null
+++ b/chrome/browser/extensions/api/settings_overrides/settings_overrides_browsertest.cc
@@ -0,0 +1,101 @@
+// Copyright 2013 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/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+class TemplateURLServiceObserver {
+ public:
+  TemplateURLServiceObserver(TemplateURLService* service,
+                             base::RunLoop* loop)
+      : runner_(loop) {
+    DCHECK(loop);
+    template_url_sub_ = service->RegisterOnLoadedCallback(
+        base::Bind(&TemplateURLServiceObserver::StopLoop,
+                   base::Unretained(this)));
+    service->Load();
+  }
+  ~TemplateURLServiceObserver() {}
+
+ private:
+  void StopLoop() {
+    runner_->Quit();
+  }
+  base::RunLoop* runner_;
+  scoped_ptr<TemplateURLService::Subscription> template_url_sub_;
+
+  DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceObserver);
+};
+
+testing::AssertionResult VerifyTemplateURLServiceLoad(
+    TemplateURLService* service) {
+  if (service->loaded())
+    return testing::AssertionSuccess();
+  base::RunLoop runner;
+  TemplateURLServiceObserver observer(service, &runner);
+  runner.Run();
+  if (service->loaded())
+    return testing::AssertionSuccess();
+  return testing::AssertionFailure() << "TemplateURLService isn't loaded";
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, OverrideSettings) {
+  PrefService* prefs = profile()->GetPrefs();
+  ASSERT_TRUE(prefs);
+  prefs->SetString(prefs::kHomePage, "http://google.com/");
+  prefs->SetBoolean(prefs::kHomePageIsNewTabPage, true);
+  const GURL urls[] = {GURL("http://foo"), GURL("http://bar")};
+  SessionStartupPref startup_pref(SessionStartupPref::LAST);
+  startup_pref.urls.assign(urls, urls + arraysize(urls));
+  SessionStartupPref::SetStartupPref(prefs, startup_pref);
+  TemplateURLService* url_service =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  ASSERT_TRUE(url_service);
+  EXPECT_TRUE(VerifyTemplateURLServiceLoad(url_service));
+  TemplateURL* default_provider = url_service->GetDefaultSearchProvider();
+  ASSERT_TRUE(default_provider);
+  EXPECT_EQ(TemplateURL::NORMAL, default_provider->GetType());
+
+  const extensions::Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("settings_override"));
+  ASSERT_TRUE(extension);
+  EXPECT_EQ("http://www.homepage.com/", prefs->GetString(prefs::kHomePage));
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage));
+  startup_pref = SessionStartupPref::GetStartupPref(prefs);
+  EXPECT_EQ(SessionStartupPref::URLS, startup_pref.type);
+  EXPECT_EQ(std::vector<GURL>(1, GURL("http://www.startup.com")),
+            startup_pref.urls);
+  TemplateURL* extension_provider = url_service->GetDefaultSearchProvider();
+  EXPECT_EQ(TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION,
+            extension_provider->GetType());
+  EXPECT_EQ(ASCIIToUTF16("first"), extension_provider->short_name());
+  EXPECT_EQ(ASCIIToUTF16("firstkey"), extension_provider->keyword());
+  EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", extension_provider->url());
+  EXPECT_EQ(GURL("http://www.foo.com/favicon.ico"),
+            extension_provider->favicon_url());
+  EXPECT_EQ("http://www.foo.com/suggest?q={searchTerms}",
+            extension_provider->suggestions_url());
+  EXPECT_EQ(std::vector<std::string>(1, "UTF-8"),
+            extension_provider->input_encodings());
+
+  UnloadExtension(extension->id());
+  EXPECT_EQ("http://google.com/", prefs->GetString(prefs::kHomePage));
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage));
+  startup_pref = SessionStartupPref::GetStartupPref(prefs);
+  EXPECT_EQ(SessionStartupPref::LAST, startup_pref.type);
+  EXPECT_EQ(std::vector<GURL>(urls, urls + arraysize(urls)), startup_pref.urls);
+  EXPECT_EQ(default_provider, url_service->GetDefaultSearchProvider());
+}
+
+}  // namespace
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc
index 2a2aa0c..9a8f8f2 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc
@@ -107,8 +107,8 @@
   bool is_local = params->is_local.get() ? *params->is_local : false;
 
   if (is_local) {
-    scoped_ptr<DeviceInfo> device = GetLocalDeviceInfo(extension_id(),
-                                                       profile());
+    scoped_ptr<DeviceInfo> device =
+        GetLocalDeviceInfo(extension_id(), GetProfile());
     base::ListValue* result = new base::ListValue();
     if (device.get()) {
       result->Append(device->ToValue());
@@ -117,8 +117,8 @@
     return true;
   }
 
-  ScopedVector<DeviceInfo> devices = GetAllSignedInDevices(extension_id(),
-                                                           profile());
+  ScopedVector<DeviceInfo> devices =
+      GetAllSignedInDevices(extension_id(), GetProfile());
 
   scoped_ptr<base::ListValue> result(new base::ListValue());
 
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h
index f093ba2..c45f3e9 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/memory/scoped_vector.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace browser_sync {
 class DeviceInfo;
@@ -37,7 +37,7 @@
     ProfileSyncService* pss,
     ExtensionPrefs* extension_prefs);
 
-class SignedInDevicesGetFunction : public SyncExtensionFunction {
+class SignedInDevicesGetFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~SignedInDevicesGetFunction() {}
 
diff --git a/chrome/browser/extensions/api/socket/socket_api.cc b/chrome/browser/extensions/api/socket/socket_api.cc
index c59d97a..993d4ca 100644
--- a/chrome/browser/extensions/api/socket/socket_api.cc
+++ b/chrome/browser/extensions/api/socket/socket_api.cc
@@ -55,7 +55,7 @@
 
 bool SocketAsyncApiFunction::PrePrepare() {
   manager_ = CreateSocketResourceManager();
-  return manager_->SetProfile(profile());
+  return manager_->SetProfile(GetProfile());
 }
 
 bool SocketAsyncApiFunction::Respond() {
diff --git a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
index 1135799..729587f 100644
--- a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
+++ b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
@@ -158,7 +158,7 @@
   params_ = api::sockets_tcp::SetPaused::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(profile());
+  socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(GetProfile());
   DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
     "If this assertion is failing during a test, then it is likely that "
     "TestExtensionSystem is failing to provide an instance of "
@@ -243,7 +243,7 @@
   params_ = sockets_tcp::Connect::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(profile());
+  socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(GetProfile());
   DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
     "If this assertion is failing during a test, then it is likely that "
     "TestExtensionSystem is failing to provide an instance of "
@@ -358,13 +358,13 @@
   }
 }
 
-void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_written) {
+void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) {
   CHECK(net_result <= net::OK) << "Network status code must be <= net::OK";
 
   sockets_tcp::SendInfo send_info;
   send_info.result_code = net_result;
   if (net_result == net::OK) {
-    send_info.bytes_written.reset(new int(bytes_written));
+    send_info.bytes_sent.reset(new int(bytes_sent));
   }
 
   if (net_result != net::OK)
diff --git a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.h b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.h
index 19894ab..59413ae 100644
--- a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.h
+++ b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.h
@@ -184,7 +184,7 @@
 
  private:
   void OnCompleted(int net_result);
-  void SetSendResult(int net_result, int bytes_written);
+  void SetSendResult(int net_result, int bytes_sent);
 
   scoped_ptr<sockets_tcp::Send::Params> params_;
   scoped_refptr<net::IOBuffer> io_buffer_;
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
index 0827e29..cace238 100644
--- a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
@@ -129,7 +129,7 @@
   params_ = api::sockets_tcp_server::SetPaused::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(profile());
+  socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(GetProfile());
   DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
     "If this assertion is failing during a test, then it is likely that "
     "TestExtensionSystem is failing to provide an instance of "
@@ -164,7 +164,7 @@
   params_ = api::sockets_tcp_server::Listen::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(profile());
+  socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(GetProfile());
   DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
     "If this assertion is failing during a test, then it is likely that "
     "TestExtensionSystem is failing to provide an instance of "
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
index 295594e..5939c44 100644
--- a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
@@ -140,7 +140,7 @@
   params_ = sockets_udp::Bind::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(profile());
+  socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(GetProfile());
   DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
     "If this assertion is failing during a test, then it is likely that "
     "TestExtensionSystem is failing to provide an instance of "
@@ -237,13 +237,13 @@
   }
 }
 
-void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_written) {
+void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_sent) {
   CHECK(net_result <= net::OK) << "Network status code must be < 0";
 
   sockets_udp::SendInfo send_info;
-  send_info.result = net_result;
+  send_info.result_code = net_result;
   if (net_result == net::OK) {
-    send_info.bytes_written.reset(new int(bytes_written));
+    send_info.bytes_sent.reset(new int(bytes_sent));
   }
 
   if (net_result != net::OK)
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h
index 60fbe3b..547580a 100644
--- a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h
@@ -104,7 +104,7 @@
   virtual bool Prepare() OVERRIDE;
   virtual void AsyncWorkStart() OVERRIDE;
   void OnCompleted(int net_result);
-  void SetSendResult(int net_result, int bytes_written);
+  void SetSendResult(int net_result, int bytes_sent);
 
   // SocketExtensionWithDnsLookupFunction:
   virtual void AfterDnsLookup(int lookup_result) OVERRIDE;
diff --git a/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc b/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc
index 47e86b8..1f67872 100644
--- a/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc
+++ b/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc
@@ -120,7 +120,7 @@
     // potential infinite reads if we have a persistent network error.
     sockets_udp::ReceiveErrorInfo receive_error_info;
     receive_error_info.socket_id = params.socket_id;
-    receive_error_info.result = bytes_read;
+    receive_error_info.result_code = bytes_read;
     scoped_ptr<base::ListValue> args =
         sockets_udp::OnReceiveError::Create(receive_error_info);
     scoped_ptr<Event> event(
diff --git a/chrome/browser/extensions/api/storage/storage_api.cc b/chrome/browser/extensions/api/storage/storage_api.cc
index 3af4a34..e562d91 100644
--- a/chrome/browser/extensions/api/storage/storage_api.cc
+++ b/chrome/browser/extensions/api/storage/storage_api.cc
@@ -49,7 +49,7 @@
       settings_namespace_ != settings_namespace::INVALID);
 
   SettingsFrontend* frontend =
-      profile()->GetExtensionService()->settings_frontend();
+      GetProfile()->GetExtensionService()->settings_frontend();
   if (!frontend->IsStorageEnabled(settings_namespace_)) {
     error_ = base::StringPrintf(
         "\"%s\" is not available in this instance of Chrome",
diff --git a/chrome/browser/extensions/api/storage/storage_api.h b/chrome/browser/extensions/api/storage/storage_api.h
index b3a5b4e..a37ae6d 100644
--- a/chrome/browser/extensions/api/storage/storage_api.h
+++ b/chrome/browser/extensions/api/storage/storage_api.h
@@ -9,13 +9,13 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/extensions/api/storage/settings_namespace.h"
 #include "chrome/browser/extensions/api/storage/settings_observer.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/value_store/value_store.h"
 
 namespace extensions {
 
 // Superclass of all settings functions.
-class SettingsFunction : public AsyncExtensionFunction {
+class SettingsFunction : public ChromeAsyncExtensionFunction {
  protected:
   SettingsFunction();
   virtual ~SettingsFunction();
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
index 1d3011f..0e99edc 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
@@ -97,9 +97,7 @@
 
   virtual void SetUpOnMainThread() OVERRIDE {
     // Init test server.
-    test_server_.reset(new EmbeddedTestServer(
-                           content::BrowserThread::GetMessageLoopProxyForThread(
-                               content::BrowserThread::IO)));
+    test_server_.reset(new EmbeddedTestServer);
     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
     test_server_->RegisterRequestHandler(base::Bind(&HandleRequest));
 
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc b/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
index 76839f9..94d46c7 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_manifest_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/extensions/mime_types_handler.h"
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
index 86f6a94..40219a2 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
@@ -64,9 +64,9 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      BrowserContext::GetStoragePartition(
-          profile(),
-          render_view_host()->GetSiteInstance())->GetFileSystemContext();
+      BrowserContext::GetStoragePartition(GetProfile(),
+                                          render_view_host()->GetSiteInstance())
+          ->GetFileSystemContext();
   fileapi::FileSystemURL file_system_url(
       file_system_context->CrackURL(GURL(url)));
 
@@ -111,7 +111,7 @@
   // SyncFileSystem initialization is done in OpenFileSystem below, but we call
   // GetSyncFileSystemService here too to initialize sync event observer for
   // extensions API.
-  GetSyncFileSystemService(profile());
+  GetSyncFileSystemService(GetProfile());
 
   // Initializes sync context for this extension and continue to open
   // a new file system.
@@ -130,8 +130,8 @@
 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
   DCHECK(render_view_host());
   return BrowserContext::GetStoragePartition(
-      profile(),
-      render_view_host()->GetSiteInstance())->GetFileSystemContext();
+      GetProfile(), render_view_host()->GetSiteInstance())
+      ->GetFileSystemContext();
 }
 
 void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
@@ -167,16 +167,15 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      BrowserContext::GetStoragePartition(
-          profile(),
-          render_view_host()->GetSiteInstance())->GetFileSystemContext();
+      BrowserContext::GetStoragePartition(GetProfile(),
+                                          render_view_host()->GetSiteInstance())
+          ->GetFileSystemContext();
   fileapi::FileSystemURL file_system_url(
       file_system_context->CrackURL(GURL(url)));
 
-  GetSyncFileSystemService(profile())->GetFileSyncStatus(
+  GetSyncFileSystemService(GetProfile())->GetFileSyncStatus(
       file_system_url,
-      Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus,
-           this));
+      Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this));
   return true;
 }
 
@@ -208,9 +207,9 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      BrowserContext::GetStoragePartition(
-          profile(),
-          render_view_host()->GetSiteInstance())->GetFileSystemContext();
+      BrowserContext::GetStoragePartition(GetProfile(),
+                                          render_view_host()->GetSiteInstance())
+          ->GetFileSystemContext();
 
   // Map each file path->SyncFileStatus in the callback map.
   // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
@@ -218,7 +217,7 @@
   num_results_received_ = 0;
   file_sync_statuses_.clear();
   sync_file_system::SyncFileSystemService* sync_file_system_service =
-      GetSyncFileSystemService(profile());
+      GetSyncFileSystemService(GetProfile());
   for (unsigned int i = 0; i < num_expected_results_; i++) {
     std::string url;
     file_entry_urls->GetString(i, &url);
@@ -285,16 +284,16 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      BrowserContext::GetStoragePartition(
-          profile(),
-          render_view_host()->GetSiteInstance())->GetFileSystemContext();
+      BrowserContext::GetStoragePartition(GetProfile(),
+                                          render_view_host()->GetSiteInstance())
+          ->GetFileSystemContext();
   fileapi::FileSystemURL file_system_url(
       file_system_context->CrackURL(GURL(url)));
 
   scoped_refptr<quota::QuotaManager> quota_manager =
-      BrowserContext::GetStoragePartition(
-          profile(),
-          render_view_host()->GetSiteInstance())->GetQuotaManager();
+      BrowserContext::GetStoragePartition(GetProfile(),
+                                          render_view_host()->GetSiteInstance())
+          ->GetQuotaManager();
 
   BrowserThread::PostTask(
       BrowserThread::IO,
@@ -346,8 +345,8 @@
                                 policy_string.c_str()));
     return false;
   }
-  sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService(
-      profile());
+  sync_file_system::SyncFileSystemService* service =
+      GetSyncFileSystemService(GetProfile());
   DCHECK(service);
   SyncStatusCode status = service->SetConflictResolutionPolicy(policy);
   if (status != sync_file_system::SYNC_STATUS_OK) {
@@ -358,8 +357,8 @@
 }
 
 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunImpl() {
-  sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService(
-      profile());
+  sync_file_system::SyncFileSystemService* service =
+      GetSyncFileSystemService(GetProfile());
   DCHECK(service);
   api::sync_file_system::ConflictResolutionPolicy policy =
       ConflictResolutionPolicyToExtensionEnum(
@@ -370,8 +369,8 @@
 }
 
 bool SyncFileSystemGetServiceStatusFunction::RunImpl() {
-  sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService(
-      profile());
+  sync_file_system::SyncFileSystemService* service =
+      GetSyncFileSystemService(GetProfile());
   results_ = api::sync_file_system::GetServiceStatus::Results::Create(
       SyncServiceStateToExtensionEnum(service->GetSyncServiceState()));
   return true;
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h
index c3f7680..92aed63 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h
@@ -8,7 +8,7 @@
 #include <map>
 
 #include "base/platform_file.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
 #include "chrome/browser/sync_file_system/sync_file_status.h"
 #include "chrome/browser/sync_file_system/sync_status_code.h"
@@ -23,7 +23,7 @@
 namespace extensions {
 
 class SyncFileSystemDeleteFileSystemFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   // TODO(kinuko,calvinlo): Uncomment this or delete this class when
   // we decide if we want to revive this function.
@@ -38,9 +38,8 @@
   void DidDeleteFileSystem(base::PlatformFileError error);
 };
 
-
 class SyncFileSystemGetFileStatusFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.getFileStatus",
                              SYNCFILESYSTEM_GETFILESYNCSTATUS)
@@ -56,7 +55,7 @@
 };
 
 class SyncFileSystemGetFileStatusesFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.getFileStatuses",
                              SYNCFILESYSTEM_GETFILESYNCSTATUSES)
@@ -83,7 +82,7 @@
 };
 
 class SyncFileSystemGetUsageAndQuotaFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.getUsageAndQuota",
                              SYNCFILESYSTEM_GETUSAGEANDQUOTA)
@@ -99,7 +98,7 @@
 };
 
 class SyncFileSystemRequestFileSystemFunction
-    : public AsyncExtensionFunction {
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.requestFileSystem",
                              SYNCFILESYSTEM_REQUESTFILESYSTEM)
@@ -120,7 +119,7 @@
 };
 
 class SyncFileSystemSetConflictResolutionPolicyFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.setConflictResolutionPolicy",
                              SYNCFILESYSTEM_SETCONFLICTRESOLUTIONPOLICY)
@@ -131,7 +130,7 @@
 };
 
 class SyncFileSystemGetConflictResolutionPolicyFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.getConflictResolutionPolicy",
                              SYNCFILESYSTEM_GETCONFLICTRESOLUTIONPOLICY)
@@ -141,7 +140,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class SyncFileSystemGetServiceStatusFunction : public SyncExtensionFunction {
+class SyncFileSystemGetServiceStatusFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("syncFileSystem.getServiceStatus",
                              SYNCFILESYSTEM_GETSERVICESTATUS)
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
index 151b9bb..cac0a6e 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
@@ -369,7 +369,7 @@
   unit->name = display_manager->GetDisplayNameForId(display.id());
   if (display_manager->IsMirrored()) {
     unit->mirroring_source_id =
-        base::Int64ToString(display_manager->mirrored_display().id());
+        base::Int64ToString(display_manager->mirrored_display_id());
   }
 
   const float dpi = display.device_scale_factor() * kDpi96;
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_gtk.cc b/chrome/browser/extensions/api/system_display/display_info_provider_gtk.cc
index 9111ca5..216f76c 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider_gtk.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_gtk.cc
@@ -27,7 +27,8 @@
   gint monitor_num = static_cast<gint>(display.id());
   char* monitor_name = reinterpret_cast<char*>(gdk_screen_get_monitor_plug_name(
        screen, monitor_num));
-  unit->name = std::string(monitor_name);
+  if (monitor_name)
+    unit->name = std::string(monitor_name);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_private/system_private_api.cc b/chrome/browser/extensions/api/system_private/system_private_api.cc
index 4a5654b..20e3c37 100644
--- a/chrome/browser/extensions/api/system_private/system_private_api.cc
+++ b/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -62,7 +62,7 @@
 namespace system_private = api::system_private;
 
 bool SystemPrivateGetIncognitoModeAvailabilityFunction::RunImpl() {
-  PrefService* prefs = profile_->GetPrefs();
+  PrefService* prefs = GetProfile()->GetPrefs();
   int value = prefs->GetInteger(prefs::kIncognitoModeAvailability);
   EXTENSION_FUNCTION_VALIDATE(
       value >= 0 &&
diff --git a/chrome/browser/extensions/api/system_private/system_private_api.h b/chrome/browser/extensions/api/system_private/system_private_api.h
index 06194a8..33f91ba 100644
--- a/chrome/browser/extensions/api/system_private/system_private_api.h
+++ b/chrome/browser/extensions/api/system_private/system_private_api.h
@@ -8,12 +8,12 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_PRIVATE_SYSTEM_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_PRIVATE_SYSTEM_PRIVATE_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 
 class SystemPrivateGetIncognitoModeAvailabilityFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("systemPrivate.getIncognitoModeAvailability",
                              SYSTEMPRIVATE_GETINCOGNITOMODEAVAILABILITY)
@@ -26,7 +26,8 @@
 };
 
 // API function which returns the status of system update.
-class SystemPrivateGetUpdateStatusFunction : public SyncExtensionFunction {
+class SystemPrivateGetUpdateStatusFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("systemPrivate.getUpdateStatus",
                              SYSTEMPRIVATE_GETUPDATESTATUS)
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
index 4b3b165..b65ebc4 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
@@ -69,9 +69,8 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   // Figure out the active WebContents and retrieve the needed ids.
-  Browser* target_browser = chrome::FindAnyBrowser(profile(),
-                                                   include_incognito(),
-                                                   chrome::GetActiveDesktop());
+  Browser* target_browser = chrome::FindAnyBrowser(
+      GetProfile(), include_incognito(), chrome::GetActiveDesktop());
   if (!target_browser) {
     error_ = kFindingTabError;
     return false;
@@ -145,7 +144,7 @@
   }
 
   extensions::TabCaptureRegistry* registry =
-      extensions::TabCaptureRegistry::Get(profile());
+      extensions::TabCaptureRegistry::Get(GetProfile());
   if (!registry->AddRequest(render_process_id,
                             routing_id,
                             extension_id,
@@ -167,7 +166,7 @@
 
 bool TabCaptureGetCapturedTabsFunction::RunImpl() {
   extensions::TabCaptureRegistry* registry =
-      extensions::TabCaptureRegistry::Get(profile());
+      extensions::TabCaptureRegistry::Get(GetProfile());
 
   const TabCaptureRegistry::RegistryCaptureInfo& captured_tabs =
       registry->GetCapturedTabs(GetExtension()->id());
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_api.h b/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
index 4a708f4..cac9e16 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_api.h
@@ -8,13 +8,13 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_TAB_CAPTURE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_TAB_CAPTURE_API_H_
 
-#include "chrome/browser/extensions/api/api_function.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/tab_capture.h"
 
 namespace extensions {
 
-class TabCaptureCaptureFunction : public SyncExtensionFunction {
+class TabCaptureCaptureFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("tabCapture.capture", TABCAPTURE_CAPTURE)
 
@@ -25,7 +25,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class TabCaptureGetCapturedTabsFunction : public SyncExtensionFunction {
+class TabCaptureGetCapturedTabsFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("tabCapture.getCapturedTabs",
                              TABCAPTURE_GETCAPTUREDTABS)
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index 0067dfa..2a35257 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -26,6 +26,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/common/features/feature.h"
+#include "ui/compositor/compositor_switches.h"
 
 namespace {
 
@@ -40,6 +41,13 @@
     // crbug.com/269087
     UseRealGLBindings();
 
+    // These test should be using OSMesa on CrOS, which would make this
+    // unneeded.
+    // crbug.com/313128
+#if !defined(OS_CHROMEOS)
+    UseRealGLContexts();
+#endif
+
     ExtensionApiTest::SetUp();
   }
 
@@ -51,8 +59,8 @@
 
 }  // namespace
 
-// http://crbug.com/261493 and http://crbug.com/268644
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_AURA)
+// http://crbug.com/261493
+#if defined(OS_CHROMEOS)
 #define MAYBE_ApiTests DISABLED_ApiTests
 #else
 #define MAYBE_ApiTests ApiTests
@@ -76,13 +84,7 @@
                                   "api_tests.html")) << message_;
 }
 
-// http://crbug.com/268644
-#if defined(USE_AURA)
-#define MAYBE_ApiTestsAudio DISABLED_ApiTestsAudio
-#else
-#define MAYBE_ApiTestsAudio ApiTestsAudio
-#endif
-IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTestsAudio) {
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, ApiTestsAudio) {
 #if defined(OS_WIN)
   // TODO(justinlin): Disabled for WinXP due to timeout issues.
   if (base::win::GetVersion() < base::win::VERSION_VISTA) {
@@ -95,8 +97,8 @@
                                   "api_tests_audio.html")) << message_;
 }
 
-// http://crbug.com/177163 and http://crbug.com/268644
-#if defined(OS_WIN) && (!defined(NDEBUG) || defined(USE_AURA))
+// http://crbug.com/177163
+#if defined(OS_WIN) && !defined(NDEBUG)
 #define MAYBE_EndToEnd DISABLED_EndToEnd
 #else
 #define MAYBE_EndToEnd EndToEnd
@@ -152,7 +154,7 @@
 }
 
 // http://crbug.com/177163
-#if defined(OS_WIN)
+#if defined(OS_WIN) && !defined(NDEBUG)
 #define MAYBE_ActiveTabPermission DISABLED_ActiveTabPermission
 #else
 #define MAYBE_ActiveTabPermission ActiveTabPermission
@@ -287,7 +289,7 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) && !defined(NDEBUG)
 #define MAYBE_CaptureInSplitIncognitoMode DISABLED_CaptureInSplitIncognitoMode
 #else
 #define MAYBE_CaptureInSplitIncognitoMode CaptureInSplitIncognitoMode
@@ -300,3 +302,14 @@
                                   kFlagEnableIncognito | kFlagUseIncognito))
       << message_;
 }
+
+#if defined(OS_WIN) && !defined(NDEBUG)
+#define MAYBE_Constraints DISABLED_Constraints
+#else
+#define MAYBE_Constraints Constraints
+#endif
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_Constraints) {
+  AddExtensionToCommandLineWhitelist();
+  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
+                                  "constraints.html")) << message_;
+}
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
index 5bd5187..d9bc82f 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
@@ -125,12 +125,10 @@
       command_line->AppendSwitchASCII(switches::kWindowSize, "2000,1500");
     }
 
-    command_line->AppendSwitch(switches::kDisableTestCompositor);
+    UseRealGLContexts();
 
     if (!HasFlag(kUseGpu)) {
-      command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
-      command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
-      command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+      command_line->AppendSwitch(switches::kDisableGpu);
     } else {
       command_line->AppendSwitch(switches::kForceCompositingMode);
     }
@@ -216,7 +214,6 @@
                                    "frame_time");
     EXPECT_TRUE(sw_frames || gpu_frames);
     EXPECT_NE(sw_frames, gpu_frames);
-    EXPECT_EQ(gpu_frames, HasFlag(kUseGpu));
 
     // This prints out the average time between capture events.
     // As the capture frame rate is capped at 30fps, this score
@@ -230,16 +227,7 @@
 
 }  // namespace
 
-
-// This does not work on Aura and Mac GPU bots yet
-// http://crbug.com/308236
-#if defined(USE_AURA) || defined(OS_MACOSX)
-#define MAYBE_Performance DISABLED_Performance
-#else
-#define MAYBE_Performance Performance
-#endif
-
-IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, MAYBE_Performance) {
+IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, Performance) {
   RunTest("TabCapturePerformance");
 }
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index f99ef55..c4ba43b 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -148,8 +148,9 @@
   return NULL;
 }
 
-bool GetBrowserFromWindowID(
-    UIThreadExtensionFunction* function, int window_id, Browser** browser) {
+bool GetBrowserFromWindowID(ChromeAsyncExtensionFunction* function,
+                            int window_id,
+                            Browser** browser) {
   if (window_id == extension_misc::kCurrentWindowId) {
     *browser = function->GetCurrentBrowser();
     if (!(*browser) || !(*browser)->window()) {
@@ -158,8 +159,10 @@
     }
   } else {
     std::string error;
-    *browser = GetBrowserInProfileWithId(
-        function->profile(), window_id, function->include_incognito(), &error);
+    *browser = GetBrowserInProfileWithId(function->GetProfile(),
+                                         window_id,
+                                         function->include_incognito(),
+                                         &error);
     if (!*browser) {
       function->SetError(error);
       return false;
@@ -280,7 +283,7 @@
   // include other window types (e.g. panels), we will need to add logic to
   // WindowControllerList that mirrors the active behavior of BrowserList.
   Browser* browser = chrome::FindAnyBrowser(
-      profile(), include_incognito(), chrome::GetActiveDesktop());
+      GetProfile(), include_incognito(), chrome::GetActiveDesktop());
   if (!browser || !browser->window()) {
     error_ = keys::kNoLastFocusedWindowError;
     return false;
@@ -325,7 +328,7 @@
     std::vector<GURL>* urls, bool* is_error) {
   *is_error = false;
   const IncognitoModePrefs::Availability incognito_availability =
-      IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
+      IncognitoModePrefs::GetAvailability(GetProfile()->GetPrefs());
   bool incognito = false;
   if (create_data && create_data->incognito) {
     incognito = *create_data->incognito;
@@ -347,10 +350,10 @@
 
   // Remove all URLs that are not allowed in an incognito session. Note that a
   // ChromeOS guest session is not considered incognito in this case.
-  if (incognito && !profile_->IsGuestSession()) {
+  if (incognito && !GetProfile()->IsGuestSession()) {
     std::string first_url_erased;
     for (size_t i = 0; i < urls->size();) {
-      if (chrome::IsURLAllowedInIncognito((*urls)[i], profile())) {
+      if (chrome::IsURLAllowedInIncognito((*urls)[i], GetProfile())) {
         i++;
       } else {
         if (first_url_erased.empty())
@@ -409,12 +412,18 @@
   if (create_data && create_data->tab_id) {
     // Find the tab. |source_tab_strip| and |tab_index| will later be used to
     // move the tab into the created window.
-    if (!GetTabById(*create_data->tab_id, profile(), include_incognito(), NULL,
-                    &source_tab_strip, NULL, &tab_index, &error_))
+    if (!GetTabById(*create_data->tab_id,
+                    GetProfile(),
+                    include_incognito(),
+                    NULL,
+                    &source_tab_strip,
+                    NULL,
+                    &tab_index,
+                    &error_))
       return false;
   }
 
-  Profile* window_profile = profile();
+  Profile* window_profile = GetProfile();
   Browser::Type window_type = Browser::TYPE_TABBED;
   bool create_panel = false;
 
@@ -867,17 +876,17 @@
 
   base::ListValue* result = new base::ListValue();
   Browser* last_active_browser = chrome::FindAnyBrowser(
-      profile(), include_incognito(), chrome::GetActiveDesktop());
+      GetProfile(), include_incognito(), chrome::GetActiveDesktop());
   Browser* current_browser = GetCurrentBrowser();
   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     Browser* browser = *it;
-    if (!profile()->IsSameProfile(browser->profile()))
+    if (!GetProfile()->IsSameProfile(browser->profile()))
       continue;
 
     if (!browser->window())
       continue;
 
-    if (!include_incognito() && profile() != browser->profile())
+    if (!include_incognito() && GetProfile() != browser->profile())
       continue;
 
     if (window_id >= 0 && window_id != ExtensionTabUtil::GetWindowId(browser))
@@ -960,8 +969,8 @@
 
   // Ensure the selected browser is tabbed.
   if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser())
-    browser = chrome::FindTabbedBrowser(profile(), include_incognito(),
-                                        browser->host_desktop_type());
+    browser = chrome::FindTabbedBrowser(
+        GetProfile(), include_incognito(), browser->host_desktop_type());
 
   if (!browser || !browser->window())
     return false;
@@ -972,9 +981,13 @@
   if (params->create_properties.opener_tab_id.get()) {
     int opener_id = *params->create_properties.opener_tab_id;
 
-    if (!ExtensionTabUtil::GetTabById(
-            opener_id, profile(), include_incognito(),
-            NULL, NULL, &opener, NULL)) {
+    if (!ExtensionTabUtil::GetTabById(opener_id,
+                                      GetProfile(),
+                                      include_incognito(),
+                                      NULL,
+                                      NULL,
+                                      &opener,
+                                      NULL)) {
       return false;
     }
   }
@@ -1088,8 +1101,14 @@
   Browser* browser = NULL;
   TabStripModel* tab_strip = NULL;
   int tab_index = -1;
-  if (!GetTabById(tab_id, profile(), include_incognito(),
-                  &browser, &tab_strip, NULL, &tab_index, &error_)) {
+  if (!GetTabById(tab_id,
+                  GetProfile(),
+                  include_incognito(),
+                  &browser,
+                  &tab_strip,
+                  NULL,
+                  &tab_index,
+                  &error_)) {
     return false;
   }
 
@@ -1124,8 +1143,14 @@
   TabStripModel* tab_strip = NULL;
   WebContents* contents = NULL;
   int tab_index = -1;
-  if (!GetTabById(tab_id, profile(), include_incognito(),
-                  NULL, &tab_strip, &contents, &tab_index, &error_))
+  if (!GetTabById(tab_id,
+                  GetProfile(),
+                  include_incognito(),
+                  NULL,
+                  &tab_strip,
+                  &contents,
+                  &tab_index,
+                  &error_))
     return false;
 
   SetResult(ExtensionTabUtil::CreateTabValue(contents,
@@ -1240,8 +1265,14 @@
 
   int tab_index = -1;
   TabStripModel* tab_strip = NULL;
-  if (!GetTabById(tab_id, profile(), include_incognito(),
-                  NULL, &tab_strip, &contents, &tab_index, &error_)) {
+  if (!GetTabById(tab_id,
+                  GetProfile(),
+                  include_incognito(),
+                  NULL,
+                  &tab_strip,
+                  &contents,
+                  &tab_index,
+                  &error_)) {
     return false;
   }
 
@@ -1293,9 +1324,13 @@
     int opener_id = *params->update_properties.opener_tab_id;
 
     WebContents* opener_contents = NULL;
-    if (!ExtensionTabUtil::GetTabById(
-            opener_id, profile(), include_incognito(),
-            NULL, NULL, &opener_contents, NULL))
+    if (!ExtensionTabUtil::GetTabById(opener_id,
+                                      GetProfile(),
+                                      include_incognito(),
+                                      NULL,
+                                      NULL,
+                                      &opener_contents,
+                                      NULL))
       return false;
 
     tab_strip->SetOpenerOfWebContentsAt(tab_index, opener_contents);
@@ -1345,7 +1380,7 @@
         script_executor()->ExecuteScript(
             extension_id(),
             ScriptExecutor::JAVASCRIPT,
-            url.path(),
+            url.GetContent(),
             ScriptExecutor::TOP_FRAME,
             UserScript::DOCUMENT_IDLE,
             ScriptExecutor::MAIN_WORLD,
@@ -1439,9 +1474,14 @@
   TabStripModel* source_tab_strip = NULL;
   WebContents* contents = NULL;
   int tab_index = -1;
-  if (!GetTabById(tab_id, profile(), include_incognito(),
-                  &source_browser, &source_tab_strip, &contents,
-                  &tab_index, &error_)) {
+  if (!GetTabById(tab_id,
+                  GetProfile(),
+                  include_incognito(),
+                  &source_browser,
+                  &source_tab_strip,
+                  &contents,
+                  &tab_index,
+                  &error_)) {
     return false;
   }
 
@@ -1554,8 +1594,14 @@
     int tab_id = *params->tab_id;
 
     Browser* browser = NULL;
-    if (!GetTabById(tab_id, profile(), include_incognito(),
-                    &browser, NULL, &web_contents, NULL, &error_))
+    if (!GetTabById(tab_id,
+                    GetProfile(),
+                    include_incognito(),
+                    &browser,
+                    NULL,
+                    &web_contents,
+                    NULL,
+                    &error_))
     return false;
   }
 
@@ -1595,8 +1641,14 @@
 bool TabsRemoveFunction::RemoveTab(int tab_id) {
   Browser* browser = NULL;
   WebContents* contents = NULL;
-  if (!GetTabById(tab_id, profile(), include_incognito(),
-                  &browser, NULL, &contents, NULL, &error_)) {
+  if (!GetTabById(tab_id,
+                  GetProfile(),
+                  include_incognito(),
+                  &browser,
+                  NULL,
+                  &contents,
+                  NULL,
+                  &error_)) {
     return false;
   }
 
@@ -1643,7 +1695,7 @@
       tabs::CaptureVisibleTab::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  PrefService* service = profile()->GetPrefs();
+  PrefService* service = GetProfile()->GetPrefs();
   if (service->GetBoolean(prefs::kDisableScreenshots)) {
     error_ = keys::kScreenshotsDisabled;
     return false;
@@ -1816,8 +1868,14 @@
   // in the current window.
   if (params->tab_id.get()) {
     tab_id = *params->tab_id;
-    if (!GetTabById(tab_id, profile(), include_incognito(),
-                    &browser, NULL, &contents, NULL, &error_)) {
+    if (!GetTabById(tab_id,
+                    GetProfile(),
+                    include_incognito(),
+                    &browser,
+                    NULL,
+                    &contents,
+                    NULL,
+                    &error_)) {
       return false;
     }
     if (!browser || !contents)
@@ -1907,8 +1965,14 @@
   // If |tab_id| is specified, look for the tab. Otherwise default to selected
   // tab in the current window.
   CHECK_GE(execute_tab_id_, 0);
-  if (!GetTabById(execute_tab_id_, profile(), include_incognito(),
-                  NULL, NULL, &contents, NULL, &error_)) {
+  if (!GetTabById(execute_tab_id_,
+                  GetProfile(),
+                  include_incognito(),
+                  NULL,
+                  NULL,
+                  &contents,
+                  NULL,
+                  &error_)) {
     return false;
   }
 
@@ -1935,9 +1999,15 @@
   Browser* browser = NULL;
   content::WebContents* contents = NULL;
 
-  bool success = GetTabById(
-      execute_tab_id_, profile(), include_incognito(), &browser, NULL,
-      &contents, NULL, &error_) && contents && browser;
+  bool success = GetTabById(execute_tab_id_,
+                            GetProfile(),
+                            include_incognito(),
+                            &browser,
+                            NULL,
+                            &contents,
+                            NULL,
+                            &error_) &&
+                 contents && browser;
 
   if (!success)
     return NULL;
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.h b/chrome/browser/extensions/api/tabs/tabs_api.h
index a3ee038..97e5f1c 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -10,7 +10,7 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/extensions/api/execute_code_function.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/tabs.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -42,27 +42,27 @@
 namespace extensions {
 
 // Windows
-class WindowsGetFunction : public SyncExtensionFunction {
+class WindowsGetFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsGetFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.get", WINDOWS_GET)
 };
-class WindowsGetCurrentFunction : public SyncExtensionFunction {
+class WindowsGetCurrentFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsGetCurrentFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.getCurrent", WINDOWS_GETCURRENT)
 };
-class WindowsGetLastFocusedFunction : public SyncExtensionFunction {
+class WindowsGetLastFocusedFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsGetLastFocusedFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.getLastFocused", WINDOWS_GETLASTFOCUSED)
 };
-class WindowsGetAllFunction : public SyncExtensionFunction {
+class WindowsGetAllFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsGetAllFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.getAll", WINDOWS_GETALL)
 };
-class WindowsCreateFunction : public SyncExtensionFunction {
+class WindowsCreateFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsCreateFunction() {}
   virtual bool RunImpl() OVERRIDE;
   // Returns whether the window should be created in incognito mode.
@@ -78,54 +78,54 @@
       bool* is_error);
   DECLARE_EXTENSION_FUNCTION("windows.create", WINDOWS_CREATE)
 };
-class WindowsUpdateFunction : public SyncExtensionFunction {
+class WindowsUpdateFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsUpdateFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.update", WINDOWS_UPDATE)
 };
-class WindowsRemoveFunction : public SyncExtensionFunction {
+class WindowsRemoveFunction : public ChromeSyncExtensionFunction {
   virtual ~WindowsRemoveFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("windows.remove", WINDOWS_REMOVE)
 };
 
 // Tabs
-class TabsGetFunction : public SyncExtensionFunction {
+class TabsGetFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsGetFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.get", TABS_GET)
 };
-class TabsGetCurrentFunction : public SyncExtensionFunction {
+class TabsGetCurrentFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsGetCurrentFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.getCurrent", TABS_GETCURRENT)
 };
-class TabsGetSelectedFunction : public SyncExtensionFunction {
+class TabsGetSelectedFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsGetSelectedFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.getSelected", TABS_GETSELECTED)
 };
-class TabsGetAllInWindowFunction : public SyncExtensionFunction {
+class TabsGetAllInWindowFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsGetAllInWindowFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.getAllInWindow", TABS_GETALLINWINDOW)
 };
-class TabsQueryFunction : public SyncExtensionFunction {
+class TabsQueryFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsQueryFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.query", TABS_QUERY)
 };
-class TabsCreateFunction : public SyncExtensionFunction {
+class TabsCreateFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsCreateFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.create", TABS_CREATE)
 };
-class TabsDuplicateFunction : public SyncExtensionFunction {
+class TabsDuplicateFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsDuplicateFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.duplicate", TABS_DUPLICATE)
 };
-class TabsHighlightFunction : public SyncExtensionFunction {
+class TabsHighlightFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsHighlightFunction() {}
   virtual bool RunImpl() OVERRIDE;
   bool HighlightTab(TabStripModel* tabstrip,
@@ -134,7 +134,7 @@
                     int index);
   DECLARE_EXTENSION_FUNCTION("tabs.highlight", TABS_HIGHLIGHT)
 };
-class TabsUpdateFunction : public AsyncExtensionFunction {
+class TabsUpdateFunction : public ChromeAsyncExtensionFunction {
  public:
   TabsUpdateFunction();
 
@@ -156,7 +156,7 @@
 
   DECLARE_EXTENSION_FUNCTION("tabs.update", TABS_UPDATE)
 };
-class TabsMoveFunction : public SyncExtensionFunction {
+class TabsMoveFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsMoveFunction() {}
   virtual bool RunImpl() OVERRIDE;
   bool MoveTab(int tab_id,
@@ -166,19 +166,19 @@
                int* window_id);
   DECLARE_EXTENSION_FUNCTION("tabs.move", TABS_MOVE)
 };
-class TabsReloadFunction : public SyncExtensionFunction {
+class TabsReloadFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsReloadFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tabs.reload", TABS_RELOAD)
 };
-class TabsRemoveFunction : public SyncExtensionFunction {
+class TabsRemoveFunction : public ChromeSyncExtensionFunction {
   virtual ~TabsRemoveFunction() {}
   virtual bool RunImpl() OVERRIDE;
   bool RemoveTab(int tab_id);
   DECLARE_EXTENSION_FUNCTION("tabs.remove", TABS_REMOVE)
 };
-class TabsDetectLanguageFunction : public AsyncExtensionFunction,
-                                  public content::NotificationObserver {
+class TabsDetectLanguageFunction : public ChromeAsyncExtensionFunction,
+                                   public content::NotificationObserver {
  private:
   virtual ~TabsDetectLanguageFunction() {}
   virtual bool RunImpl() OVERRIDE;
@@ -190,7 +190,7 @@
   content::NotificationRegistrar registrar_;
   DECLARE_EXTENSION_FUNCTION("tabs.detectLanguage", TABS_DETECTLANGUAGE)
 };
-class TabsCaptureVisibleTabFunction : public AsyncExtensionFunction {
+class TabsCaptureVisibleTabFunction : public ChromeAsyncExtensionFunction {
  public:
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
diff --git a/chrome/browser/extensions/api/tabs/windows_util.cc b/chrome/browser/extensions/api/tabs/windows_util.cc
index 536609e..19972f6 100644
--- a/chrome/browser/extensions/api/tabs/windows_util.cc
+++ b/chrome/browser/extensions/api/tabs/windows_util.cc
@@ -6,15 +6,16 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/window_controller.h"
 #include "chrome/browser/extensions/window_controller_list.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "extensions/common/error_utils.h"
 
 namespace windows_util {
 
-bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
+bool GetWindowFromWindowID(ChromeAsyncExtensionFunction* function,
                            int window_id,
                            extensions::WindowController** controller) {
   if (window_id == extension_misc::kCurrentWindowId) {
diff --git a/chrome/browser/extensions/api/tabs/windows_util.h b/chrome/browser/extensions/api/tabs/windows_util.h
index 24ab44b..f3d6c5f 100644
--- a/chrome/browser/extensions/api/tabs/windows_util.h
+++ b/chrome/browser/extensions/api/tabs/windows_util.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_UTIL_H__
 #define CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_UTIL_H__
 
-class UIThreadExtensionFunction;
+class ChromeAsyncExtensionFunction;
 
 namespace extensions {
 class WindowController;
@@ -15,7 +15,7 @@
 
 // Populates |controller| for given |window_id|. If the window is not found,
 // returns false and sets UIThreadExtensionFunction error_.
-bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
+bool GetWindowFromWindowID(ChromeAsyncExtensionFunction* function,
                            int window_id,
                            extensions::WindowController** controller);
 
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index faeb3b5..5ac2492 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -114,8 +114,9 @@
       chromeos::ProcessProxyRegistry::Get();
   pid_t pid;
   if (!registry->OpenProcess(
-          command_, &pid,
-          base::Bind(&NotifyProcessOutput, profile_, extension_id()))) {
+           command_,
+           &pid,
+           base::Bind(&NotifyProcessOutput, GetProfile(), extension_id()))) {
     // If new process could not be opened, we return -1.
     pid = -1;
   }
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.h b/chrome/browser/extensions/api/terminal/terminal_private_api.h
index e544f12..ca79049 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.h
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.h
@@ -7,12 +7,12 @@
 
 #include <string>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 namespace extensions {
 // Base class for all terminalPrivate function classes. Main purpose is to run
 // permission check before calling actual function implementation.
-class TerminalPrivateFunction : public AsyncExtensionFunction {
+class TerminalPrivateFunction : public ChromeAsyncExtensionFunction {
  public:
   TerminalPrivateFunction();
 
diff --git a/chrome/browser/extensions/api/test/test_api.cc b/chrome/browser/extensions/api/test/test_api.cc
index 5cf8051..5a4f485 100644
--- a/chrome/browser/extensions/api/test/test_api.cc
+++ b/chrome/browser/extensions/api/test/test_api.cc
@@ -83,7 +83,7 @@
 TestResetQuotaFunction::~TestResetQuotaFunction() {}
 
 bool TestResetQuotaFunction::RunImpl() {
-  ExtensionService* service = profile()->GetExtensionService();
+  ExtensionService* service = GetProfile()->GetExtensionService();
   ExtensionsQuotaService* quota = service->quota_service();
   quota->Purge();
   quota->violation_errors_.clear();
@@ -97,8 +97,8 @@
   scoped_ptr<CreateIncognitoTab::Params> params(
       CreateIncognitoTab::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  chrome::OpenURLOffTheRecord(profile(), GURL(params->url),
-                              chrome::GetActiveDesktop());
+  chrome::OpenURLOffTheRecord(
+      GetProfile(), GURL(params->url), chrome::GetActiveDesktop());
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/test/test_api.h b/chrome/browser/extensions/api/test/test_api.h
index fa0c2ab..0916832 100644
--- a/chrome/browser/extensions/api/test/test_api.h
+++ b/chrome/browser/extensions/api/test/test_api.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_API_TEST_TEST_API_H_
 
 #include "base/values.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
 template <typename T> struct DefaultSingletonTraits;
 
@@ -14,7 +14,7 @@
 
 // A function that is only available in tests.
 // Prior to running, checks that we are in an extension process.
-class TestExtensionFunction : public SyncExtensionFunction {
+class TestExtensionFunction : public ChromeSyncExtensionFunction {
  protected:
   virtual ~TestExtensionFunction();
 
@@ -77,7 +77,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class TestSendMessageFunction : public AsyncExtensionFunction {
+class TestSendMessageFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("test.sendMessage", UNKNOWN)
 
@@ -92,7 +92,7 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class TestGetConfigFunction : public SyncExtensionFunction {
+class TestGetConfigFunction : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("test.getConfig", UNKNOWN)
 
diff --git a/chrome/browser/extensions/api/top_sites/top_sites_api.cc b/chrome/browser/extensions/api/top_sites/top_sites_api.cc
index 77d5a93..c6accaf 100644
--- a/chrome/browser/extensions/api/top_sites/top_sites_api.cc
+++ b/chrome/browser/extensions/api/top_sites/top_sites_api.cc
@@ -18,7 +18,7 @@
 TopSitesGetFunction::~TopSitesGetFunction() {}
 
 bool TopSitesGetFunction::RunImpl() {
-  history::TopSites* ts = profile()->GetTopSites();
+  history::TopSites* ts = GetProfile()->GetTopSites();
   if (!ts)
     return false;
 
diff --git a/chrome/browser/extensions/api/top_sites/top_sites_api.h b/chrome/browser/extensions/api/top_sites/top_sites_api.h
index 7acc608..9cd2b78 100644
--- a/chrome/browser/extensions/api/top_sites/top_sites_api.h
+++ b/chrome/browser/extensions/api/top_sites/top_sites_api.h
@@ -6,12 +6,12 @@
 #define CHROME_BROWSER_EXTENSIONS_API_TOP_SITES_TOP_SITES_API_H_
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/history/history_types.h"
 
 namespace extensions {
 
-class TopSitesGetFunction : public AsyncExtensionFunction {
+class TopSitesGetFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("topSites.get", TOPSITES_GET)
 
diff --git a/chrome/browser/extensions/api/usb/usb_api.cc b/chrome/browser/extensions/api/usb/usb_api.cc
index 48a6840..206c019 100644
--- a/chrome/browser/extensions/api/usb/usb_api.cc
+++ b/chrome/browser/extensions/api/usb/usb_api.cc
@@ -396,7 +396,7 @@
 }
 
 bool UsbAsyncApiFunction::PrePrepare() {
-  manager_ = ApiResourceManager<UsbDeviceResource>::Get(profile());
+  manager_ = ApiResourceManager<UsbDeviceResource>::Get(GetProfile());
   set_work_thread_id(BrowserThread::FILE);
   return manager_ != NULL;
 }
@@ -456,6 +456,13 @@
     CompleteWithError(kErrorNoDevice);
     return NULL;
   }
+
+  if (!resource->device() || !resource->device()->device()) {
+    CompleteWithError(kErrorDisconnect);
+    manager_->Remove(extension_->id(), input_device_handle.handle);
+    return NULL;
+  }
+
   if (resource->device()->device()->vendor_id() !=
           input_device_handle.vendor_id ||
       resource->device()->device()->product_id() !=
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
index 7616dcc..f4ecce5 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -723,9 +723,10 @@
 
   content::WebContents* web_contents;
   if (!ExtensionTabUtil::GetTabById(tab_id,
-                                    profile(),
+                                    GetProfile(),
                                     include_incognito(),
-                                    NULL, NULL,
+                                    NULL,
+                                    NULL,
                                     &web_contents,
                                     NULL) ||
       !web_contents) {
@@ -777,9 +778,10 @@
 
   content::WebContents* web_contents;
   if (!ExtensionTabUtil::GetTabById(tab_id,
-                                    profile(),
+                                    GetProfile(),
                                     include_incognito(),
-                                    NULL, NULL,
+                                    NULL,
+                                    NULL,
                                     &web_contents,
                                     NULL) ||
       !web_contents) {
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
index eeb25ec..00f17fe 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
@@ -14,8 +14,8 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -206,14 +206,14 @@
 };
 
 // API function that returns the state of a given frame.
-class WebNavigationGetFrameFunction : public SyncExtensionFunction {
+class WebNavigationGetFrameFunction : public ChromeSyncExtensionFunction {
   virtual ~WebNavigationGetFrameFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("webNavigation.getFrame", WEBNAVIGATION_GETFRAME)
 };
 
 // API function that returns the states of all frames in a given tab.
-class WebNavigationGetAllFramesFunction : public SyncExtensionFunction {
+class WebNavigationGetAllFramesFunction : public ChromeSyncExtensionFunction {
   virtual ~WebNavigationGetAllFramesFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("webNavigation.getAllFrames",
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc
index fce2f1f..d10d681 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api.cc
@@ -1120,11 +1120,17 @@
     if ((*it)->extra_info_spec &
         (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
       (*it)->blocked_requests.insert(request->identifier());
+      // If this is the first delegate blocking the request, go ahead and log
+      // it.
+      if (num_handlers_blocking == 0) {
+        std::string delegate_info =
+            l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
+                                      UTF8ToUTF16((*it)->extension_name));
+        request->SetDelegateInfo(
+            delegate_info.c_str(),
+            net::URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+      }
       ++num_handlers_blocking;
-
-      request->SetLoadStateParam(
-          l10n_util::GetStringFUTF16(IDS_LOAD_STATE_PARAMETER_EXTENSION,
-                                     UTF8ToUTF16((*it)->extension_name)));
     }
   }
 
@@ -1691,20 +1697,25 @@
   }
 
   if (num_handlers_blocking == 0) {
+    blocked_request.request->SetDelegateInfo(
+        NULL, net::URLRequest::DELEGATE_INFO_DEBUG_ONLY);
     ExecuteDeltas(profile, request_id, true);
   } else {
-    // Update the URLRequest to indicate it is now blocked on a different
-    // extension.
+    // Update the URLRequest to make sure it's tagged with an extension that's
+    // still blocking it.  This may end up being the same extension as before.
     std::set<EventListener>& listeners = listeners_[profile][event_name];
 
     for (std::set<EventListener>::iterator it = listeners.begin();
          it != listeners.end(); ++it) {
-      if (it->blocked_requests.count(request_id)) {
-        blocked_request.request->SetLoadStateParam(
-            l10n_util::GetStringFUTF16(IDS_LOAD_STATE_PARAMETER_EXTENSION,
-                                       UTF8ToUTF16(it->extension_name)));
-        break;
-      }
+      if (it->blocked_requests.count(request_id) == 0)
+        continue;
+      std::string delegate_info =
+          l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
+                                    UTF8ToUTF16(it->extension_name));
+      blocked_request.request->SetDelegateInfo(
+          delegate_info.c_str(),
+          net::URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+      break;
     }
   }
 }
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/DEPS b/chrome/browser/extensions/api/webrtc_audio_private/DEPS
new file mode 100644
index 0000000..67c01d0
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_audio_private/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+media/audio"
+]
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/OWNERS b/chrome/browser/extensions/api/webrtc_audio_private/OWNERS
new file mode 100644
index 0000000..4975363
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_audio_private/OWNERS
@@ -0,0 +1 @@
+joi@chromium.org
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
new file mode 100644
index 0000000..971dfe6
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
@@ -0,0 +1,319 @@
+// Copyright 2013 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/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h"
+
+#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "content/public/browser/media_device_id.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/error_utils.h"
+#include "media/audio/audio_manager_base.h"
+#include "media/audio/audio_output_controller.h"
+
+namespace extensions {
+
+using content::BrowserThread;
+using content::RenderViewHost;
+using media::AudioDeviceNames;
+using media::AudioManager;
+
+namespace wap = api::webrtc_audio_private;
+
+static base::LazyInstance<
+    ProfileKeyedAPIFactory<WebrtcAudioPrivateEventService> > g_factory =
+        LAZY_INSTANCE_INITIALIZER;
+
+WebrtcAudioPrivateEventService::WebrtcAudioPrivateEventService(
+    Profile* profile) : profile_(profile) {
+  // In unit tests, the SystemMonitor may not be created.
+  base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
+  if (system_monitor)
+    system_monitor->AddDevicesChangedObserver(this);
+}
+
+WebrtcAudioPrivateEventService::~WebrtcAudioPrivateEventService() {
+}
+
+void WebrtcAudioPrivateEventService::Shutdown() {
+  // In unit tests, the SystemMonitor may not be created.
+  base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
+  if (system_monitor)
+    system_monitor->RemoveDevicesChangedObserver(this);
+}
+
+// static
+ProfileKeyedAPIFactory<WebrtcAudioPrivateEventService>*
+WebrtcAudioPrivateEventService::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
+// static
+const char* WebrtcAudioPrivateEventService::service_name() {
+  return "WebrtcAudioPrivateEventService";
+}
+
+void WebrtcAudioPrivateEventService::OnDevicesChanged(
+    base::SystemMonitor::DeviceType device_type) {
+  switch (device_type) {
+    case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE:
+    case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE:
+      SignalEvent();
+      break;
+
+    default:
+      // No action needed.
+      break;
+  }
+}
+
+void WebrtcAudioPrivateEventService::SignalEvent() {
+  using api::webrtc_audio_private::OnSinksChanged::kEventName;
+
+  EventRouter* router =
+      ExtensionSystem::Get(profile_)->event_router();
+  if (!router || !router->HasEventListener(kEventName))
+    return;
+  ExtensionService* extension_service =
+      ExtensionSystem::Get(profile_)->extension_service();
+  const ExtensionSet* extensions = extension_service->extensions();
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
+    const std::string& extension_id = (*it)->id();
+    if (router->ExtensionHasEventListener(extension_id, kEventName) &&
+        (*it)->HasAPIPermission("webrtcAudioPrivate")) {
+      scoped_ptr<Event> event(
+          new Event(kEventName, make_scoped_ptr(new ListValue()).Pass()));
+      router->DispatchEventToExtension(extension_id, event.Pass());
+    }
+  }
+}
+
+bool WebrtcAudioPrivateGetSinksFunction::RunImpl() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  AudioManager::Get()->GetMessageLoop()->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&WebrtcAudioPrivateGetSinksFunction::DoQuery, this),
+      base::Bind(&WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread, this));
+  return true;
+}
+
+void WebrtcAudioPrivateGetSinksFunction::DoQuery() {
+  DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
+
+  AudioDeviceNames device_names;
+  AudioManager::Get()->GetAudioOutputDeviceNames(&device_names);
+
+  std::vector<linked_ptr<wap::SinkInfo> > results;
+  for (AudioDeviceNames::const_iterator it = device_names.begin();
+       it != device_names.end();
+       ++it) {
+    linked_ptr<wap::SinkInfo> info(new wap::SinkInfo);
+    info->sink_id = it->unique_id;
+    info->sink_label = it->device_name;
+    // TODO(joi): Add other parameters.
+    results.push_back(info);
+  }
+
+  // It's safe to directly set the results here (from a thread other
+  // than the UI thread, on which an AsyncExtensionFunction otherwise
+  // normally runs) because there is one instance of this object per
+  // function call, no actor outside of this object is modifying the
+  // results_ member, and the different method invocations on this
+  // object run strictly in sequence; first RunImpl on the UI thread,
+  // then DoQuery on the audio IO thread, then DoneOnUIThread on the
+  // UI thread.
+  results_.reset(wap::GetSinks::Results::Create(results).release());
+}
+
+void WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  SendResponse(true);
+}
+
+bool WebrtcAudioPrivateTabIdFunction::DoRunImpl(int tab_id) {
+  content::WebContents* contents = NULL;
+  if (!ExtensionTabUtil::GetTabById(
+           tab_id, GetProfile(), true, NULL, NULL, &contents, NULL)) {
+    error_ = extensions::ErrorUtils::FormatErrorMessage(
+        extensions::tabs_constants::kTabNotFoundError,
+        base::IntToString(tab_id));
+    return false;
+  }
+
+  RenderViewHost* rvh = contents->GetRenderViewHost();
+  if (!rvh)
+    return false;
+
+  rvh->GetAudioOutputControllers(base::Bind(
+      &WebrtcAudioPrivateTabIdFunction::OnControllerList, this));
+  return true;
+}
+
+bool WebrtcAudioPrivateGetActiveSinkFunction::RunImpl() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  scoped_ptr<wap::GetActiveSink::Params> params(
+      wap::GetActiveSink::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  return DoRunImpl(params->tab_id);
+}
+
+void WebrtcAudioPrivateGetActiveSinkFunction::OnControllerList(
+    const RenderViewHost::AudioOutputControllerList& controllers) {
+  if (controllers.empty()) {
+    // If there is no current audio stream for the rvh, we return an
+    // empty string as the sink ID.
+    DVLOG(2) << "chrome.webrtcAudioPrivate.getActiveSink: No controllers.";
+    results_.reset(
+        wap::GetActiveSink::Results::Create(std::string()).release());
+    SendResponse(true);
+  } else {
+    DVLOG(2) << "chrome.webrtcAudioPrivate.getActiveSink: "
+             << controllers.size() << " controllers.";
+    // TODO(joi): Debug-only, DCHECK that all items have the same ID.
+    (*controllers.begin())->GetOutputDeviceId(
+        base::Bind(&WebrtcAudioPrivateGetActiveSinkFunction::OnSinkId, this));
+  }
+}
+
+void WebrtcAudioPrivateGetActiveSinkFunction::OnSinkId(const std::string& id) {
+  std::string result = id;
+  if (result.empty()) {
+    DVLOG(2) << "Received empty ID, replacing with default ID.";
+    result = media::AudioManagerBase::kDefaultDeviceId;
+  }
+  results_.reset(wap::GetActiveSink::Results::Create(result).release());
+  SendResponse(true);
+}
+
+WebrtcAudioPrivateSetActiveSinkFunction::
+WebrtcAudioPrivateSetActiveSinkFunction()
+    : message_loop_(base::MessageLoopProxy::current()),
+      tab_id_(0),
+      num_remaining_sink_ids_(0) {
+}
+
+WebrtcAudioPrivateSetActiveSinkFunction::
+~WebrtcAudioPrivateSetActiveSinkFunction() {
+}
+
+bool WebrtcAudioPrivateSetActiveSinkFunction::RunImpl() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  scoped_ptr<wap::SetActiveSink::Params> params(
+      wap::SetActiveSink::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  tab_id_ = params->tab_id;
+  sink_id_ = params->sink_id;
+
+  if (sink_id_ == media::AudioManagerBase::kDefaultDeviceId) {
+    DVLOG(2) << "Received default ID, replacing with empty ID.";
+    sink_id_ = "";
+  }
+
+  return DoRunImpl(tab_id_);
+}
+
+void WebrtcAudioPrivateSetActiveSinkFunction::OnControllerList(
+    const RenderViewHost::AudioOutputControllerList& controllers) {
+  num_remaining_sink_ids_ = controllers.size();
+  if (num_remaining_sink_ids_ == 0) {
+    error_ = extensions::ErrorUtils::FormatErrorMessage(
+        "No active stream for tab with id: *.",
+        base::IntToString(tab_id_));
+    SendResponse(false);
+  } else {
+    RenderViewHost::AudioOutputControllerList::const_iterator it =
+        controllers.begin();
+    for (; it != controllers.end(); ++it) {
+      (*it)->SwitchOutputDevice(sink_id_, base::Bind(
+          &WebrtcAudioPrivateSetActiveSinkFunction::SwitchDone, this));
+    }
+  }
+}
+
+void WebrtcAudioPrivateSetActiveSinkFunction::SwitchDone() {
+  if (--num_remaining_sink_ids_ == 0) {
+    message_loop_->PostTask(
+        FROM_HERE,
+        base::Bind(&WebrtcAudioPrivateSetActiveSinkFunction::DoneOnUIThread,
+                   this));
+  }
+}
+
+void WebrtcAudioPrivateSetActiveSinkFunction::DoneOnUIThread() {
+  SendResponse(true);
+}
+
+WebrtcAudioPrivateGetAssociatedSinkFunction::
+~WebrtcAudioPrivateGetAssociatedSinkFunction() {
+}
+
+bool WebrtcAudioPrivateGetAssociatedSinkFunction::RunImpl() {
+  scoped_ptr<wap::GetAssociatedSink::Params> params(
+      wap::GetAssociatedSink::Params::Create(*args_));
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  base::PostTaskAndReplyWithResult(
+      AudioManager::Get()->GetMessageLoop(),
+      FROM_HERE,
+      base::Bind(
+          &WebrtcAudioPrivateGetAssociatedSinkFunction::DoWorkOnDeviceThread,
+          this, GURL(params->security_origin), params->source_id_in_origin),
+      base::Bind(
+          &WebrtcAudioPrivateGetAssociatedSinkFunction::DoneOnUIThread,
+          this));
+
+  return true;
+}
+
+std::string WebrtcAudioPrivateGetAssociatedSinkFunction::DoWorkOnDeviceThread(
+    GURL security_origin, std::string source_id_in_origin) {
+  AudioDeviceNames source_devices;
+  AudioManager::Get()->GetAudioInputDeviceNames(&source_devices);
+
+  // Find the raw source ID for source_id_in_origin.
+  std::string raw_source_id;
+  for (AudioDeviceNames::const_iterator it = source_devices.begin();
+       it != source_devices.end();
+       ++it) {
+    const std::string& id = it->unique_id;
+    if (content::DoesMediaDeviceIDMatchHMAC(
+            security_origin, source_id_in_origin, id)) {
+      raw_source_id = id;
+      DVLOG(2) << "Found raw ID " << raw_source_id
+               << " for source ID in origin " << source_id_in_origin;
+      break;
+    }
+  }
+
+  // We return an empty string if there is no associated output device.
+  std::string result;
+  if (!raw_source_id.empty()) {
+    result = AudioManager::Get()->GetAssociatedOutputDeviceID(raw_source_id);
+  }
+
+  return result;
+}
+
+void WebrtcAudioPrivateGetAssociatedSinkFunction::DoneOnUIThread(
+    const std::string& associated_sink_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  results_.reset(
+      wap::GetAssociatedSink::Results::Create(associated_sink_id).release());
+  SendResponse(true);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h
new file mode 100644
index 0000000..3f53056
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h
@@ -0,0 +1,141 @@
+// Copyright 2013 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_EXTENSIONS_API_WEBRTC_AUDIO_PRIVATE_WEBRTC_AUDIO_PRIVATE_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_WEBRTC_AUDIO_PRIVATE_WEBRTC_AUDIO_PRIVATE_API_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/system_monitor/system_monitor.h"
+#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/webrtc_audio_private.h"
+#include "content/public/browser/render_view_host.h"
+#include "media/audio/audio_device_name.h"
+#include "url/gurl.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace extensions {
+
+// Listens for device changes and forwards as an extension event.
+class WebrtcAudioPrivateEventService
+    : public ProfileKeyedAPI,
+      public base::SystemMonitor::DevicesChangedObserver {
+ public:
+  explicit WebrtcAudioPrivateEventService(Profile* profile);
+  virtual ~WebrtcAudioPrivateEventService();
+
+  // ProfileKeyedAPI implementation.
+  virtual void Shutdown() OVERRIDE;
+  static ProfileKeyedAPIFactory<WebrtcAudioPrivateEventService>*
+      GetFactoryInstance();
+  static const char* service_name();
+
+  // base::SystemMonitor::DevicesChangedObserver implementation.
+  virtual void OnDevicesChanged(
+      base::SystemMonitor::DeviceType device_type) OVERRIDE;
+
+ private:
+  friend class ProfileKeyedAPIFactory<WebrtcAudioPrivateEventService>;
+
+  void SignalEvent();
+
+  Profile* profile_;
+};
+
+class WebrtcAudioPrivateGetSinksFunction : public ChromeAsyncExtensionFunction {
+ protected:
+  virtual ~WebrtcAudioPrivateGetSinksFunction() {}
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("webrtcAudioPrivate.getSinks",
+                             WEBRTC_AUDIO_PRIVATE_GET_SINKS);
+
+  virtual bool RunImpl() OVERRIDE;
+  void DoQuery();
+  void DoneOnUIThread();
+};
+
+// Common base for functions that start by retrieving the list of
+// controllers for the specified tab.
+class WebrtcAudioPrivateTabIdFunction : public ChromeAsyncExtensionFunction {
+ protected:
+  virtual ~WebrtcAudioPrivateTabIdFunction() {}
+
+ protected:
+  bool DoRunImpl(int tab_id);
+  virtual void OnControllerList(
+      const content::RenderViewHost::AudioOutputControllerList& list) = 0;
+};
+
+class WebrtcAudioPrivateGetActiveSinkFunction
+    : public WebrtcAudioPrivateTabIdFunction {
+ protected:
+  virtual ~WebrtcAudioPrivateGetActiveSinkFunction() {}
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("webrtcAudioPrivate.getActiveSink",
+                             WEBRTC_AUDIO_PRIVATE_GET_ACTIVE_SINK);
+
+  virtual bool RunImpl() OVERRIDE;
+  virtual void OnControllerList(
+      const content::RenderViewHost::AudioOutputControllerList&
+      controllers) OVERRIDE;
+  void OnSinkId(const std::string&);
+};
+
+class WebrtcAudioPrivateSetActiveSinkFunction
+    : public WebrtcAudioPrivateTabIdFunction {
+ public:
+  WebrtcAudioPrivateSetActiveSinkFunction();
+
+ protected:
+  virtual ~WebrtcAudioPrivateSetActiveSinkFunction();
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("webrtcAudioPrivate.setActiveSink",
+                             WEBRTC_AUDIO_PRIVATE_SET_ACTIVE_SINK);
+
+  virtual bool RunImpl() OVERRIDE;
+  virtual void OnControllerList(
+      const content::RenderViewHost::AudioOutputControllerList&
+      controllers) OVERRIDE;
+  void SwitchDone();
+  void DoneOnUIThread();
+
+  // Message loop of the thread this class is constructed on.
+  const scoped_refptr<base::MessageLoopProxy> message_loop_;
+
+  int tab_id_;
+  std::string sink_id_;
+
+  // Number of sink IDs we are still waiting for. Can become greater
+  // than 0 in OnControllerList, decreases on every OnSinkId call.
+  size_t num_remaining_sink_ids_;
+};
+
+class WebrtcAudioPrivateGetAssociatedSinkFunction
+    : public ChromeAsyncExtensionFunction {
+ protected:
+  virtual ~WebrtcAudioPrivateGetAssociatedSinkFunction();
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("webrtcAudioPrivate.getAssociatedSink",
+                             WEBRTC_AUDIO_PRIVATE_GET_ASSOCIATED_SINK);
+
+  virtual bool RunImpl() OVERRIDE;
+
+  // Takes the parameters of the function, returns the associated sink
+  // ID, or the empty string if none.
+  std::string DoWorkOnDeviceThread(GURL security_origin,
+                                   std::string source_id_in_origin);
+  void DoneOnUIThread(const std::string& associated_sink_id);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_WEBRTC_AUDIO_PRIVATE_WEBRTC_AUDIO_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
new file mode 100644
index 0000000..7c03ea2
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -0,0 +1,296 @@
+// Copyright 2013 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/json/json_writer.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/media_device_id.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "media/audio/audio_manager.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::JSONWriter;
+using content::RenderViewHost;
+using content::WebContents;
+using media::AudioDeviceNames;
+using media::AudioManager;
+
+namespace extensions {
+
+using extension_function_test_utils::RunFunctionAndReturnError;
+using extension_function_test_utils::RunFunctionAndReturnSingleResult;
+
+class WebrtcAudioPrivateTest : public ExtensionApiTest {
+ public:
+  WebrtcAudioPrivateTest() : enumeration_event_(false, false) {
+  }
+
+ protected:
+  std::string InvokeGetActiveSink(int tab_id) {
+    ListValue parameters;
+    parameters.AppendInteger(tab_id);
+    std::string parameter_string;
+    JSONWriter::Write(&parameters, &parameter_string);
+
+    scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function =
+        new WebrtcAudioPrivateGetActiveSinkFunction();
+    scoped_ptr<base::Value> result(
+        RunFunctionAndReturnSingleResult(function.get(),
+                                         parameter_string,
+                                         browser()));
+    std::string device_id;
+    result->GetAsString(&device_id);
+    return device_id;
+  }
+
+  // Synchronously (from the calling thread's point of view) runs the
+  // given enumeration function on the device thread. On return,
+  // |device_names| has been filled with the device names resulting
+  // from that call.
+  void GetAudioDeviceNames(
+      void (AudioManager::*EnumerationFunc)(AudioDeviceNames*),
+      AudioDeviceNames* device_names) {
+    AudioManager* audio_manager = AudioManager::Get();
+
+    if (!audio_manager->GetMessageLoop()->BelongsToCurrentThread()) {
+      audio_manager->GetMessageLoop()->PostTask(
+          FROM_HERE,
+          base::Bind(&WebrtcAudioPrivateTest::GetAudioDeviceNames, this,
+                     EnumerationFunc, device_names));
+      enumeration_event_.Wait();
+    } else {
+      (audio_manager->*EnumerationFunc)(device_names);
+      enumeration_event_.Signal();
+    }
+  }
+
+  // Event used to signal completion of enumeration.
+  base::WaitableEvent enumeration_event_;
+};
+
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetSinks) {
+  AudioDeviceNames devices;
+  GetAudioDeviceNames(&AudioManager::GetAudioOutputDeviceNames, &devices);
+
+  scoped_refptr<WebrtcAudioPrivateGetSinksFunction> function =
+      new WebrtcAudioPrivateGetSinksFunction();
+  scoped_ptr<base::Value> result(
+      RunFunctionAndReturnSingleResult(function.get(), "[]", browser()));
+  base::ListValue* sink_list = NULL;
+  result->GetAsList(&sink_list);
+
+  std::string result_string;
+  JSONWriter::Write(result.get(), &result_string);
+  VLOG(2) << result_string;
+
+  EXPECT_EQ(devices.size(), sink_list->GetSize());
+
+  // Iterate through both lists in lockstep and compare. The order
+  // should be identical.
+  size_t ix = 0;
+  AudioDeviceNames::const_iterator it = devices.begin();
+  for (; ix < sink_list->GetSize() && it != devices.end();
+       ++ix, ++it) {
+    base::DictionaryValue* dict = NULL;
+    sink_list->GetDictionary(ix, &dict);
+    std::string sink_id;
+    dict->GetString("sinkId", &sink_id);
+    EXPECT_EQ(it->unique_id, sink_id);
+    std::string sink_label;
+    dict->GetString("sinkLabel", &sink_label);
+    EXPECT_EQ(it->device_name, sink_label);
+
+    // TODO(joi): Verify the contents of these once we start actually
+    // filling them in.
+    EXPECT_TRUE(dict->HasKey("isDefault"));
+    EXPECT_TRUE(dict->HasKey("isReady"));
+    EXPECT_TRUE(dict->HasKey("sampleRate"));
+  }
+}
+
+// This exercises the case where you have a tab with no active media
+// stream and try to retrieve the currently active audio sink.
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetActiveSinkNoMediaStream) {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  int tab_id = ExtensionTabUtil::GetTabId(tab);
+  base::ListValue parameters;
+  parameters.AppendInteger(tab_id);
+  std::string parameter_string;
+  JSONWriter::Write(&parameters, &parameter_string);
+
+  scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function =
+      new WebrtcAudioPrivateGetActiveSinkFunction();
+  scoped_ptr<base::Value> result(
+      RunFunctionAndReturnSingleResult(function.get(),
+                                       parameter_string,
+                                       browser()));
+
+  std::string result_string;
+  JSONWriter::Write(result.get(), &result_string);
+  EXPECT_EQ("\"\"", result_string);
+}
+
+// This exercises the case where you have a tab with no active media
+// stream and try to set the audio sink.
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, SetActiveSinkNoMediaStream) {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  int tab_id = ExtensionTabUtil::GetTabId(tab);
+  ListValue parameters;
+  parameters.AppendInteger(tab_id);
+  parameters.AppendString("no such id");
+  std::string parameter_string;
+  JSONWriter::Write(&parameters, &parameter_string);
+
+  scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function =
+      new WebrtcAudioPrivateSetActiveSinkFunction();
+  std::string error(RunFunctionAndReturnError(function.get(),
+                                              parameter_string,
+                                              browser()));
+  EXPECT_EQ(base::StringPrintf("No active stream for tab with id: %d.", tab_id),
+            error);
+}
+
+// Used by the test below to wait until audio is playing.
+static void OnAudioControllers(
+    bool* audio_playing,
+    const RenderViewHost::AudioOutputControllerList& list) {
+  if (!list.empty())
+    *audio_playing = true;
+}
+
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAndSetWithMediaStream) {
+  // First get the list of output devices, so that we can (if
+  // available) set the active device to a device other than the one
+  // it starts as. This function is not threadsafe and is normally
+  // called only from the audio IO thread, but we know no other code
+  // is currently running so we call it directly.
+  AudioDeviceNames devices;
+  GetAudioDeviceNames(&AudioManager::GetAudioOutputDeviceNames, &devices);
+
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  // Open a normal page that uses an audio sink.
+  ui_test_utils::NavigateToURL(
+      browser(),
+      GURL(embedded_test_server()->GetURL("/extensions/loop_audio.html")));
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  int tab_id = ExtensionTabUtil::GetTabId(tab);
+
+  // Wait for audio to start playing. We gate this on there being one
+  // or more AudioOutputController objects for our tab.
+  bool audio_playing = false;
+  for (size_t remaining_tries = 50; remaining_tries > 0; --remaining_tries) {
+    tab->GetRenderViewHost()->GetAudioOutputControllers(
+        base::Bind(OnAudioControllers, &audio_playing));
+    base::MessageLoop::current()->RunUntilIdle();
+    if (audio_playing)
+      break;
+
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  }
+
+  if (!audio_playing)
+    FAIL() << "Audio did not start playing within ~5 seconds.";
+
+  std::string current_device = InvokeGetActiveSink(tab_id);
+  VLOG(2) << "Before setting, current device: " << current_device;
+  EXPECT_NE("", current_device);
+
+  // Set to each of the other devices in turn.
+  for (AudioDeviceNames::const_iterator it = devices.begin();
+       it != devices.end();
+       ++it) {
+    std::string target_device(it->unique_id);
+
+    ListValue parameters;
+    parameters.AppendInteger(tab_id);
+    parameters.AppendString(target_device);
+    std::string parameter_string;
+    JSONWriter::Write(&parameters, &parameter_string);
+
+    scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function =
+      new WebrtcAudioPrivateSetActiveSinkFunction();
+    scoped_ptr<base::Value> result(RunFunctionAndReturnSingleResult(
+        function.get(), parameter_string, browser()));
+    // The function was successful if the above invocation doesn't
+    // fail. Just for kicks, also check that it returns no result.
+    EXPECT_EQ(NULL, result.get());
+
+    current_device = InvokeGetActiveSink(tab_id);
+    VLOG(2) << "After setting to " << target_device
+            << ", current device is " << current_device;
+    EXPECT_EQ(target_device, current_device);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAssociatedSink) {
+  // Get the list of input devices. We can cheat in the unit test and
+  // run this on the main thread since nobody else will be running at
+  // the same time.
+  AudioDeviceNames devices;
+  GetAudioDeviceNames(&AudioManager::GetAudioInputDeviceNames, &devices);
+
+  // Try to get an associated sink for each source.
+  for (AudioDeviceNames::const_iterator device = devices.begin();
+       device != devices.end();
+       ++device) {
+    std::string raw_source_id = device->unique_id;
+    VLOG(2) << "Trying to find associated sink for device " << raw_source_id;
+    GURL origin(GURL("http://www.google.com/").GetOrigin());
+    std::string source_id_in_origin =
+        content::GetHMACForMediaDeviceID(origin, raw_source_id);
+
+    ListValue parameters;
+    parameters.AppendString(origin.spec());
+    parameters.AppendString(source_id_in_origin);
+    std::string parameter_string;
+    JSONWriter::Write(&parameters, &parameter_string);
+
+    scoped_refptr<WebrtcAudioPrivateGetAssociatedSinkFunction> function =
+        new WebrtcAudioPrivateGetAssociatedSinkFunction();
+    scoped_ptr<base::Value> result(
+        RunFunctionAndReturnSingleResult(function.get(),
+                                         parameter_string,
+                                         browser()));
+    std::string result_string;
+    JSONWriter::Write(result.get(), &result_string);
+    VLOG(2) << "Results: " << result_string;
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, TriggerEvent) {
+  WebrtcAudioPrivateEventService* service =
+      WebrtcAudioPrivateEventService::GetFactoryInstance()->GetForProfile(
+          profile());
+
+  // Just trigger, without any extension listening.
+  service->OnDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
+
+  // Now load our test extension and do it again.
+  const extensions::Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("webrtc_audio_private_event_listener"));
+  service->OnDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
+
+  // Check that the extension got the notification.
+  std::string result = ExecuteScriptInBackgroundPage(extension->id(),
+                                                     "reportIfGot()");
+  EXPECT_EQ("true", result);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index 6909657..0100027 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -36,8 +36,8 @@
 WebrtcLoggingPrivateTabIdFunction::RphFromTabIdAndSecurityOrigin(
     int tab_id, const std::string& security_origin) {
   content::WebContents* contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile(), true,
-                                    NULL, NULL, &contents, NULL)) {
+  if (!ExtensionTabUtil::GetTabById(
+           tab_id, GetProfile(), true, NULL, NULL, &contents, NULL)) {
     error_ = extensions::ErrorUtils::FormatErrorMessage(
         extensions::tabs_constants::kTabNotFoundError,
         base::IntToString(tab_id));
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
index 27af5d5..9bf1326 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/webrtc_logging_private.h"
 
 namespace content {
@@ -17,7 +17,7 @@
 namespace extensions {
 
 // TODO(grunell). Merge this with WebrtcAudioPrivateTabIdFunction.
-class WebrtcLoggingPrivateTabIdFunction : public AsyncExtensionFunction {
+class WebrtcLoggingPrivateTabIdFunction : public ChromeAsyncExtensionFunction {
  protected:
   virtual ~WebrtcLoggingPrivateTabIdFunction() {}
 
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
new file mode 100644
index 0000000..1e9f189
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -0,0 +1,272 @@
+// Copyright 2013 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/json/json_writer.h"
+#include "base/strings/string_split.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc_log_uploader.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_utils.h"
+
+using extensions::Extension;
+
+namespace utils = extension_function_test_utils;
+
+namespace {
+
+static const char kTestLoggingSessionId[] = "0123456789abcdef";
+static const char kTestLoggingUrl[] = "dummy url string";
+
+class WebrtcLoggingPrivateApiTest : public ExtensionApiTest {
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(WebrtcLoggingPrivateApiTest, TestStartStopDiscard) {
+  scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
+
+  // Tell the uploader to save the multipart to a buffer instead of uploading.
+  std::string multipart;
+  g_browser_process->webrtc_log_uploader()->
+      OverrideUploadWithBufferForTesting(&multipart);
+
+  // Start
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateStartFunction>
+      start_function(new extensions::WebrtcLoggingPrivateStartFunction());
+  start_function->set_extension(empty_extension.get());
+  start_function->set_has_callback(true);
+
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ListValue parameters;
+  parameters.AppendInteger(ExtensionTabUtil::GetTabId(contents));
+  parameters.AppendString(contents->GetURL().GetOrigin().spec());
+  std::string parameter_string;
+  base::JSONWriter::Write(&parameters, &parameter_string);
+
+  // TODO(grunell): MaybeRunFunction is suitable for those calls not returning
+  // anything.
+  scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+      start_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  // Stop
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateStopFunction>
+      stop_function(new extensions::WebrtcLoggingPrivateStopFunction());
+  stop_function->set_extension(empty_extension.get());
+  stop_function->set_has_callback(true);
+
+  result.reset(utils::RunFunctionAndReturnSingleResult(
+      stop_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  // Discard
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateDiscardFunction>
+      discard_function(new extensions::WebrtcLoggingPrivateDiscardFunction());
+  discard_function->set_extension(empty_extension.get());
+  discard_function->set_has_callback(true);
+
+  result.reset(utils::RunFunctionAndReturnSingleResult(
+      discard_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  ASSERT_TRUE(multipart.empty());
+}
+
+// Tests WebRTC diagnostic logging. Sets up the browser to save the multipart
+// contents to a buffer instead of uploading it, then verifies it after a calls.
+// Example of multipart contents:
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="prod"
+//
+// Chrome_Linux
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="ver"
+//
+// 30.0.1554.0
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="guid"
+//
+// 0
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="type"
+//
+// webrtc_log
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="app_session_id"
+//
+// 0123456789abcdef
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="url"
+//
+// http://127.0.0.1:43213/webrtc/webrtc_jsep01_test.html
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
+// Content-Disposition: form-data; name="webrtc_log"; filename="webrtc_log.gz"
+// Content-Type: application/gzip
+//
+// <compressed data (zip)>
+// ------**--yradnuoBgoLtrapitluMklaTelgooG--**------
+//
+IN_PROC_BROWSER_TEST_F(WebrtcLoggingPrivateApiTest, TestStartStopUpload) {
+  scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
+
+  // Tell the uploader to save the multipart to a buffer instead of uploading.
+  std::string multipart;
+  g_browser_process->webrtc_log_uploader()->
+      OverrideUploadWithBufferForTesting(&multipart);
+
+  // SetMetaData.
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateSetMetaDataFunction>
+      set_meta_data_function(
+          new extensions::WebrtcLoggingPrivateSetMetaDataFunction());
+  set_meta_data_function->set_extension(empty_extension.get());
+  set_meta_data_function->set_has_callback(true);
+
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ListValue parameters;
+  parameters.AppendInteger(ExtensionTabUtil::GetTabId(contents));
+  parameters.AppendString(contents->GetURL().GetOrigin().spec());
+  DictionaryValue* meta_data_entry = new DictionaryValue();
+  meta_data_entry->SetString("key", "app_session_id");
+  meta_data_entry->SetString("value", kTestLoggingSessionId);
+  ListValue* meta_data = new ListValue();
+  meta_data->Append(meta_data_entry);
+  meta_data_entry = new DictionaryValue();
+  meta_data_entry->SetString("key", "url");
+  meta_data_entry->SetString("value", kTestLoggingUrl);
+  meta_data->Append(meta_data_entry);
+  parameters.Append(meta_data);
+
+  std::string parameter_string;
+  base::JSONWriter::Write(&parameters, &parameter_string);
+
+  // TODO(grunell): MaybeRunFunction is suitable for those calls not returning
+  // anything.
+  scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+      set_meta_data_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  // Start.
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateStartFunction>
+      start_function(new extensions::WebrtcLoggingPrivateStartFunction());
+  start_function->set_extension(empty_extension.get());
+  start_function->set_has_callback(true);
+
+  parameters.Clear();
+  parameters.AppendInteger(ExtensionTabUtil::GetTabId(contents));
+  parameters.AppendString(contents->GetURL().GetOrigin().spec());
+  base::JSONWriter::Write(&parameters, &parameter_string);
+
+  result.reset(utils::RunFunctionAndReturnSingleResult(
+      start_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  // Stop.
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateStopFunction>
+      stop_function(new extensions::WebrtcLoggingPrivateStopFunction());
+  stop_function->set_extension(empty_extension.get());
+  stop_function->set_has_callback(true);
+
+  result.reset(utils::RunFunctionAndReturnSingleResult(
+      stop_function.get(), parameter_string, browser()));
+  ASSERT_FALSE(result.get());
+
+  // Upload.
+
+  scoped_refptr<extensions::WebrtcLoggingPrivateUploadFunction>
+      upload_function(new extensions::WebrtcLoggingPrivateUploadFunction());
+  upload_function->set_extension(empty_extension.get());
+  upload_function->set_has_callback(true);
+
+  result.reset(utils::RunFunctionAndReturnSingleResult(
+      upload_function.get(), parameter_string, browser()));
+  ASSERT_TRUE(result.get());
+
+  ASSERT_FALSE(multipart.empty());
+
+  // Check multipart data.
+
+  const char boundary[] = "------**--yradnuoBgoLtrapitluMklaTelgooG--**----";
+
+  // Remove the compressed data, it may contain "\r\n". Just verify that its
+  // size is > 0.
+  const char zip_content_type[] = "Content-Type: application/gzip";
+  size_t zip_pos = multipart.find(&zip_content_type[0]);
+  ASSERT_NE(std::string::npos, zip_pos);
+  // Move pos to where the zip begins. - 1 to remove '\0', + 4 for two "\r\n".
+  zip_pos += sizeof(zip_content_type) + 3;
+  size_t zip_length = multipart.find(boundary, zip_pos);
+  ASSERT_NE(std::string::npos, zip_length);
+  // Calculate length, adjust for a "\r\n".
+  zip_length -= zip_pos + 2;
+  ASSERT_GT(zip_length, 0u);
+  multipart.erase(zip_pos, zip_length);
+
+  // Check the multipart contents.
+  std::vector<std::string> multipart_lines;
+  base::SplitStringUsingSubstr(multipart, "\r\n", &multipart_lines);
+  ASSERT_EQ(31, static_cast<int>(multipart_lines.size()));
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[0].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"prod\"",
+               multipart_lines[1].c_str());
+  EXPECT_TRUE(multipart_lines[2].empty());
+  EXPECT_NE(std::string::npos, multipart_lines[3].find("Chrome"));
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[4].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"ver\"",
+               multipart_lines[5].c_str());
+  EXPECT_TRUE(multipart_lines[6].empty());
+  // Just check that the version contains a dot.
+  EXPECT_NE(std::string::npos, multipart_lines[7].find('.'));
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[8].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"guid\"",
+               multipart_lines[9].c_str());
+  EXPECT_TRUE(multipart_lines[10].empty());
+  EXPECT_STREQ("0", multipart_lines[11].c_str());
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[12].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"type\"",
+               multipart_lines[13].c_str());
+  EXPECT_TRUE(multipart_lines[14].empty());
+  EXPECT_STREQ("webrtc_log", multipart_lines[15].c_str());
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[16].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"app_session_id\"",
+               multipart_lines[17].c_str());
+  EXPECT_TRUE(multipart_lines[18].empty());
+  EXPECT_STREQ(kTestLoggingSessionId, multipart_lines[19].c_str());
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[20].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"url\"",
+               multipart_lines[21].c_str());
+  EXPECT_TRUE(multipart_lines[22].empty());
+  EXPECT_STREQ(kTestLoggingUrl, multipart_lines[23].c_str());
+
+  EXPECT_STREQ(&boundary[0], multipart_lines[24].c_str());
+  EXPECT_STREQ("Content-Disposition: form-data; name=\"webrtc_log\";"
+               " filename=\"webrtc_log.gz\"",
+               multipart_lines[25].c_str());
+  EXPECT_STREQ("Content-Type: application/gzip",
+               multipart_lines[26].c_str());
+  EXPECT_TRUE(multipart_lines[27].empty());
+  EXPECT_TRUE(multipart_lines[28].empty());  // The removed zip part.
+  std::string final_delimiter = boundary;
+  final_delimiter += "--";
+  EXPECT_STREQ(final_delimiter.c_str(), multipart_lines[29].c_str());
+  EXPECT_TRUE(multipart_lines[30].empty());
+}
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index f01005f..3c664aa 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -13,7 +13,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/about_flags.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/crx_installer.h"
@@ -29,6 +28,8 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
@@ -292,9 +293,10 @@
       *params_->details.icon_data : std::string();
 
   ExtensionService* service =
-    extensions::ExtensionSystem::Get(profile_)->extension_service();
+      extensions::ExtensionSystem::Get(GetProfile())->extension_service();
   if (service->GetInstalledExtension(params_->details.id) ||
-      !g_pending_installs.Get().InsertInstall(profile_, params_->details.id)) {
+      !g_pending_installs.Get().InsertInstall(GetProfile(),
+                                              params_->details.id)) {
     SetResultCode(ALREADY_INSTALLED);
     error_ = kAlreadyInstalledError;
     return false;
@@ -302,7 +304,7 @@
 
   net::URLRequestContextGetter* context_getter = NULL;
   if (!icon_url.is_empty())
-    context_getter = profile()->GetRequestContext();
+    context_getter = GetProfile()->GetRequestContext();
 
   scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
       this, params_->details.id, params_->details.manifest, icon_data, icon_url,
@@ -383,12 +385,12 @@
   }
 
   SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(profile());
+      SigninManagerFactory::GetForProfile(GetProfile());
   if (dummy_extension_->is_platform_app() &&
       signin_manager &&
       signin_manager->GetAuthenticatedUsername().empty() &&
       signin_manager->AuthInProgress()) {
-    signin_tracker_.reset(new SigninTracker(profile(), this));
+    signin_tracker_.reset(new SigninTracker(GetProfile(), this));
     return;
   }
 
@@ -416,7 +418,7 @@
       CHECK(false);
   }
   error_ = error_message;
-  g_pending_installs.Get().EraseInstall(profile_, id);
+  g_pending_installs.Get().EraseInstall(GetProfile(), id);
   SendResponse(false);
 
   // Matches the AddRef in RunImpl().
@@ -429,7 +431,7 @@
 
   SetResultCode(SIGNIN_FAILED);
   error_ = error.ToString();
-  g_pending_installs.Get().EraseInstall(profile_, params_->details.id);
+  g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
   SendResponse(false);
 
   // Matches the AddRef in RunImpl().
@@ -462,7 +464,7 @@
   // entry is only valid for some number of minutes.
   scoped_ptr<WebstoreInstaller::Approval> approval(
       WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
-          profile(), params_->details.id, parsed_manifest_.Pass(), false));
+          GetProfile(), params_->details.id, parsed_manifest_.Pass(), false));
   approval->use_app_installed_bubble = params_->details.app_install_bubble;
   approval->enable_launcher = params_->details.enable_launcher;
   // If we are enabling the launcher, we should not show the app list in order
@@ -489,7 +491,7 @@
     bool user_initiated) {
   error_ = kUserCancelledError;
   SetResultCode(USER_CANCELLED);
-  g_pending_installs.Get().EraseInstall(profile_, params_->details.id);
+  g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
   SendResponse(false);
 
   // The web store install histograms are a subset of the install histograms.
@@ -526,8 +528,9 @@
     return false;
   }
 
-  approval_ = g_pending_approvals.Get().PopApproval(profile(),
-      params->expected_id).Pass();
+  approval_ = g_pending_approvals.Get()
+                  .PopApproval(GetProfile(), params->expected_id)
+                  .Pass();
   if (!approval_) {
     error_ = ErrorUtils::FormatErrorMessage(
         kNoPreviousBeginInstallWithManifestError, params->expected_id);
@@ -536,25 +539,29 @@
 
   // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
   AddRef();
+  AppListService* app_list_service =
+      AppListService::Get(GetCurrentBrowser()->host_desktop_type());
 
   if (approval_->enable_launcher)
-    AppListService::Get()->EnableAppList(profile());
+    app_list_service->EnableAppList(GetProfile());
 
   if (IsAppLauncherEnabled() && approval_->manifest->is_app()) {
     // Show the app list to show download is progressing. Don't show the app
     // list on first app install so users can be trained to open it themselves.
     if (approval_->enable_launcher)
-      AppListService::Get()->CreateForProfile(profile());
+      app_list_service->CreateForProfile(GetProfile());
     else
-      AppListService::Get()->ShowForProfile(profile());
+      app_list_service->ShowForProfile(GetProfile());
   }
 
   // The extension will install through the normal extension install flow, but
   // the whitelist entry will bypass the normal permissions install dialog.
   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
-      profile(), this,
+      GetProfile(),
+      this,
       &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()),
-      params->expected_id, approval_.Pass(),
+      params->expected_id,
+      approval_.Pass(),
       WebstoreInstaller::INSTALL_SOURCE_OTHER);
   installer->Start();
 
@@ -567,7 +574,7 @@
     test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
 
   LOG(INFO) << "Install success, sending response";
-  g_pending_installs.Get().EraseInstall(profile_, id);
+  g_pending_installs.Get().EraseInstall(GetProfile(), id);
   SendResponse(true);
 
   // Matches the AddRef in RunImpl().
@@ -585,7 +592,7 @@
 
   error_ = error;
   LOG(INFO) << "Install failed, sending response";
-  g_pending_installs.Get().EraseInstall(profile_, id);
+  g_pending_installs.Get().EraseInstall(GetProfile(), id);
   SendResponse(false);
 
   // Matches the AddRef in RunImpl().
@@ -599,20 +606,21 @@
     ~WebstorePrivateEnableAppLauncherFunction() {}
 
 bool WebstorePrivateEnableAppLauncherFunction::RunImpl() {
-  AppListService::Get()->EnableAppList(profile());
+  AppListService::Get(GetCurrentBrowser()->host_desktop_type())->
+      EnableAppList(GetProfile());
   return true;
 }
 
 bool WebstorePrivateGetBrowserLoginFunction::RunImpl() {
   GetBrowserLogin::Results::Info info;
-  info.login = profile_->GetOriginalProfile()->GetPrefs()->GetString(
+  info.login = GetProfile()->GetOriginalProfile()->GetPrefs()->GetString(
       prefs::kGoogleServicesUsername);
   results_ = GetBrowserLogin::Results::Create(info);
   return true;
 }
 
 bool WebstorePrivateGetStoreLoginFunction::RunImpl() {
-  results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(profile_));
+  results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(GetProfile()));
   return true;
 }
 
@@ -620,7 +628,7 @@
   scoped_ptr<SetStoreLogin::Params> params(
       SetStoreLogin::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
-  SetWebstoreLogin(profile_, params->login);
+  SetWebstoreLogin(GetProfile(), params->login);
   return true;
 }
 
@@ -657,7 +665,7 @@
 
 bool WebstorePrivateIsInIncognitoModeFunction::RunImpl() {
   results_ = IsInIncognitoMode::Results::Create(
-      profile_ != profile_->GetOriginalProfile());
+      GetProfile() != GetProfile()->GetOriginalProfile());
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
index a28fa79..a2df65d 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "chrome/browser/extensions/bundle_installer.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/webstore_install_helper.h"
 #include "chrome/browser/extensions/webstore_installer.h"
@@ -43,8 +43,9 @@
       Profile* profile, const std::string& extension_id);
 };
 
-class WebstorePrivateInstallBundleFunction : public AsyncExtensionFunction,
-                              public extensions::BundleInstaller::Delegate {
+class WebstorePrivateInstallBundleFunction
+    : public ChromeAsyncExtensionFunction,
+      public extensions::BundleInstaller::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.installBundle",
                              WEBSTOREPRIVATE_INSTALLBUNDLE)
@@ -72,7 +73,7 @@
 };
 
 class WebstorePrivateBeginInstallWithManifest3Function
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public ExtensionInstallPrompt::Delegate,
       public WebstoreInstallHelper::Delegate,
       public SigninTracker::Observer {
@@ -167,7 +168,7 @@
 };
 
 class WebstorePrivateCompleteInstallFunction
-    : public AsyncExtensionFunction,
+    : public ChromeAsyncExtensionFunction,
       public WebstoreInstaller::Delegate {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.completeInstall",
@@ -193,7 +194,7 @@
 };
 
 class WebstorePrivateEnableAppLauncherFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.enableAppLauncher",
                              WEBSTOREPRIVATE_ENABLEAPPLAUNCHER)
@@ -207,7 +208,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class WebstorePrivateGetBrowserLoginFunction : public SyncExtensionFunction {
+class WebstorePrivateGetBrowserLoginFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.getBrowserLogin",
                              WEBSTOREPRIVATE_GETBROWSERLOGIN)
@@ -219,7 +221,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class WebstorePrivateGetStoreLoginFunction : public SyncExtensionFunction {
+class WebstorePrivateGetStoreLoginFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.getStoreLogin",
                              WEBSTOREPRIVATE_GETSTORELOGIN)
@@ -231,7 +234,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class WebstorePrivateSetStoreLoginFunction : public SyncExtensionFunction {
+class WebstorePrivateSetStoreLoginFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.setStoreLogin",
                              WEBSTOREPRIVATE_SETSTORELOGIN)
@@ -243,7 +247,8 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-class WebstorePrivateGetWebGLStatusFunction : public AsyncExtensionFunction {
+class WebstorePrivateGetWebGLStatusFunction
+    : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.getWebGLStatus",
                              WEBSTOREPRIVATE_GETWEBGLSTATUS)
@@ -265,7 +270,7 @@
 };
 
 class WebstorePrivateGetIsLauncherEnabledFunction
-    : public SyncExtensionFunction {
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.getIsLauncherEnabled",
                              WEBSTOREPRIVATE_GETISLAUNCHERENABLED)
@@ -282,7 +287,8 @@
   void OnIsLauncherCheckCompleted(bool is_enabled);
 };
 
-class WebstorePrivateIsInIncognitoModeFunction : public SyncExtensionFunction {
+class WebstorePrivateIsInIncognitoModeFunction
+    : public ChromeSyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.isInIncognitoMode",
                              WEBSTOREPRIVATE_ISININCOGNITOMODEFUNCTION)
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 26308a6..d7fd051 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -587,15 +587,6 @@
       contents->GetRenderProcessHost()->GetID()));
 }
 
-namespace {
-
-void RenderViewHostCreated(std::vector<content::RenderViewHost*>* rvh_vector,
-                           content::RenderViewHost* rvh) {
-  rvh_vector->push_back(rvh);
-}
-
-}  // namespace
-
 // Tests that if we have a non-app process (path3/container.html) that has an
 // iframe with  a URL in the app's extent (path1/iframe.html), then opening a
 // link from that iframe to a new window to a URL in the app's extent (path1/
@@ -621,20 +612,21 @@
       LoadExtension(test_data_dir_.AppendASCII("app_process"));
   ASSERT_TRUE(app);
 
-  std::vector<content::RenderViewHost*> rvh_vector;
-  content::RenderViewHost::CreatedCallback rvh_callback(
-      base::Bind(&RenderViewHostCreated, &rvh_vector));
-  content::RenderViewHost::AddCreatedCallback(rvh_callback);
   ui_test_utils::NavigateToURL(browser(),
                                base_url.Resolve("path3/container.html"));
-  content::RenderViewHost::RemoveCreatedCallback(rvh_callback);
   EXPECT_FALSE(process_map->Contains(
       browser()->tab_strip_model()->GetWebContentsAt(0)->
           GetRenderProcessHost()->GetID()));
 
+  const BrowserList* active_browser_list =
+      BrowserList::GetInstance(chrome::GetActiveDesktop());
+  EXPECT_EQ(2U, active_browser_list->size());
+  content::WebContents* popup_contents =
+      active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
+  content::WaitForLoadStop(popup_contents);
+
   // Popup window should be in the app's process.
-  ASSERT_EQ(3U, rvh_vector.size());
-  RenderViewHost* popup_host = rvh_vector[2];
+  RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
   EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
 }
 
@@ -770,20 +762,21 @@
       LoadExtension(test_data_dir_.AppendASCII("app_process"));
   ASSERT_TRUE(app);
 
-  std::vector<content::RenderViewHost*> rvh_vector;
-  content::RenderViewHost::CreatedCallback rvh_callback(
-      base::Bind(&RenderViewHostCreated, &rvh_vector));
-  content::RenderViewHost::AddCreatedCallback(rvh_callback);
   ui_test_utils::NavigateToURL(browser(),
                                base_url.Resolve("path1/container.html"));
-  content::RenderViewHost::RemoveCreatedCallback(rvh_callback);
   content::RenderProcessHost* process =
       browser()->tab_strip_model()->GetWebContentsAt(0)->GetRenderProcessHost();
   EXPECT_TRUE(process_map->Contains(process->GetID()));
 
   // Popup window should be in the app's process.
-  ASSERT_EQ(2U, rvh_vector.size());
-  RenderViewHost* popup_host = rvh_vector[1];
+  const BrowserList* active_browser_list =
+      BrowserList::GetInstance(chrome::GetActiveDesktop());
+  EXPECT_EQ(2U, active_browser_list->size());
+  content::WebContents* popup_contents =
+      active_browser_list->get(1)->tab_strip_model()->GetActiveWebContents();
+  content::WaitForLoadStop(popup_contents);
+
+  RenderViewHost* popup_host = popup_contents->GetRenderViewHost();
   EXPECT_EQ(process, popup_host->GetProcess());
 }
 
diff --git a/chrome/browser/extensions/app_sync_bundle.cc b/chrome/browser/extensions/app_sync_bundle.cc
index 32dc919..69ec44b 100644
--- a/chrome/browser/extensions/app_sync_bundle.cc
+++ b/chrome/browser/extensions/app_sync_bundle.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/extensions/app_sync_bundle.h"
 
 #include "base/location.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_sorting.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_set.h"
 #include "chrome/common/extensions/sync_helper.h"
@@ -15,8 +15,8 @@
 
 namespace extensions {
 
-AppSyncBundle::AppSyncBundle(ExtensionService* extension_service)
-    : extension_service_(extension_service) {}
+AppSyncBundle::AppSyncBundle(ExtensionSyncService* extension_sync_service)
+    : extension_sync_service_(extension_sync_service) {}
 
 AppSyncBundle::~AppSyncBundle() {}
 
@@ -32,7 +32,7 @@
        ++i) {
     AppSyncData app_sync_data(*i);
     AddApp(app_sync_data.id());
-    extension_service_->ProcessAppSyncData(app_sync_data);
+    extension_sync_service_->ProcessAppSyncData(app_sync_data);
   }
 }
 
@@ -46,7 +46,7 @@
 syncer::SyncChange AppSyncBundle::CreateSyncChangeToDelete(
     const Extension* extension)
     const {
-  AppSyncData sync_data = extension_service_->GetAppSyncData(*extension);
+  AppSyncData sync_data = extension_sync_service_->GetAppSyncData(*extension);
   return sync_data.GetSyncChange(syncer::SyncChange::ACTION_DELETE);
 }
 
@@ -73,7 +73,7 @@
 
 syncer::SyncDataList AppSyncBundle::GetAllSyncData() const {
   std::vector<AppSyncData> app_sync_data =
-      extension_service_->GetAppSyncDataList();
+      extension_sync_service_->GetAppSyncDataList();
   syncer::SyncDataList result(app_sync_data.size());
   for (int i = 0; i < static_cast<int>(app_sync_data.size()); ++i) {
     result[i] = app_sync_data[i].GetSyncData();
@@ -86,13 +86,13 @@
     RemoveApp(app_sync_data.id());
   else
     AddApp(app_sync_data.id());
-  extension_service_->ProcessAppSyncData(app_sync_data);
+  extension_sync_service_->ProcessAppSyncData(app_sync_data);
 }
 
 void AppSyncBundle::ProcessSyncChangeList(
     syncer::SyncChangeList sync_change_list) {
   sync_processor_->ProcessSyncChanges(FROM_HERE, sync_change_list);
-  extension_service_->extension_prefs()->extension_sorting()->
+  extension_sync_service_->extension_prefs().extension_sorting()->
       FixNTPOrdinalCollisions();
 }
 
@@ -114,7 +114,8 @@
 }
 
 void AppSyncBundle::SyncChangeIfNeeded(const Extension& extension) {
-  AppSyncData app_sync_data = extension_service_->GetAppSyncData(extension);
+  AppSyncData app_sync_data = extension_sync_service_->GetAppSyncData(
+      extension);
 
   syncer::SyncChangeList sync_change_list(1, app_sync_data.GetSyncChange(
       HasExtensionId(extension.id()) ?
@@ -136,17 +137,18 @@
 }
 
 void AppSyncBundle::GetAppSyncDataListHelper(
-    const ExtensionSet& extensions,
+    const ExtensionSet* extensions,
     std::vector<AppSyncData>* sync_data_list) const {
-  for (ExtensionSet::const_iterator it = extensions.begin();
-       it != extensions.end(); ++it) {
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
     const Extension& extension = *it->get();
     // If we have pending app data for this app, then this
     // version is out of date.  We'll sync back the version we got from
     // sync.
     if (IsSyncing() && sync_helper::IsSyncableApp(&extension) &&
         !HasPendingExtensionId(extension.id())) {
-      sync_data_list->push_back(extension_service_->GetAppSyncData(extension));
+      sync_data_list->push_back(extension_sync_service_->GetAppSyncData(
+          extension));
     }
   }
 }
diff --git a/chrome/browser/extensions/app_sync_bundle.h b/chrome/browser/extensions/app_sync_bundle.h
index b613a13..7fa8d17 100644
--- a/chrome/browser/extensions/app_sync_bundle.h
+++ b/chrome/browser/extensions/app_sync_bundle.h
@@ -16,7 +16,7 @@
 #include "chrome/browser/extensions/sync_bundle.h"
 #include "sync/api/syncable_service.h"
 
-class ExtensionService;
+class ExtensionSyncService;
 class ExtensionSet;
 
 namespace syncer {
@@ -31,7 +31,7 @@
 // Bundle of app specific sync stuff.
 class AppSyncBundle : public SyncBundle {
  public:
-  explicit AppSyncBundle(ExtensionService* extension_service);
+  explicit AppSyncBundle(ExtensionSyncService* extension_sync_service);
   virtual ~AppSyncBundle();
 
   // Setup this bundle to be sync application data.
@@ -75,7 +75,7 @@
 
   // Appends sync data objects for every app in |extensions|.
   void GetAppSyncDataListHelper(
-      const ExtensionSet& extensions,
+      const ExtensionSet* extensions,
       std::vector<extensions::AppSyncData>* sync_data_list) const;
 
   // Overrides for SyncBundle.
@@ -95,7 +95,7 @@
   // Change an app from being pending to synced.
   void MarkPendingAppSynced(const std::string& id);
 
-  ExtensionService* extension_service_; // Own us.
+  ExtensionSyncService* extension_sync_service_; // Own us.
   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
   scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_;
 
diff --git a/chrome/browser/extensions/blacklist.cc b/chrome/browser/extensions/blacklist.cc
index d69f1d9..f39d113 100644
--- a/chrome/browser/extensions/blacklist.cc
+++ b/chrome/browser/extensions/blacklist.cc
@@ -115,10 +115,23 @@
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingClientImpl);
 };
 
-void IsNotEmpty(const Blacklist::IsBlacklistedCallback& callback,
-                const std::set<std::string>& set) {
-  callback.Run(set.empty() ? Blacklist::NOT_BLACKLISTED
-                           : Blacklist::BLACKLISTED);
+void CheckOneExtensionState(
+    const Blacklist::IsBlacklistedCallback& callback,
+    const Blacklist::BlacklistStateMap& state_map) {
+  callback.Run(state_map.empty() ? Blacklist::NOT_BLACKLISTED
+                                 : state_map.begin()->second);
+}
+
+void GetMalwareFromBlacklistStateMap(
+    const Blacklist::GetMalwareIDsCallback& callback,
+    const Blacklist::BlacklistStateMap& state_map) {
+  std::set<std::string> malware;
+  for (Blacklist::BlacklistStateMap::const_iterator it = state_map.begin();
+       it != state_map.end(); ++it) {
+    if (it->second == Blacklist::BLACKLISTED_MALWARE)
+      malware.insert(it->first);
+  }
+  callback.Run(malware);
 }
 
 }  // namespace
@@ -172,20 +185,93 @@
 
   if (ids.empty() || !g_database_manager.Get().get().get()) {
     base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE, base::Bind(callback, std::set<std::string>()));
+        FROM_HERE, base::Bind(callback, BlacklistStateMap()));
     return;
   }
 
   // Constructing the SafeBrowsingClientImpl begins the process of asking
-  // safebrowsing for the blacklisted extensions.
-  new SafeBrowsingClientImpl(ids, callback);
+  // safebrowsing for the blacklisted extensions. The set of blacklisted
+  // extensions returned by SafeBrowsing will then be passed to
+  // GetBlacklistStateIDs to get the particular BlacklistState for each id.
+  new SafeBrowsingClientImpl(
+      ids, base::Bind(&Blacklist::GetBlacklistStateForIDs, AsWeakPtr(),
+                      callback));
 }
 
+void Blacklist::GetMalwareIDs(const std::set<std::string>& ids,
+                              const GetMalwareIDsCallback& callback) {
+  GetBlacklistedIDs(ids, base::Bind(&GetMalwareFromBlacklistStateMap,
+                                    callback));
+}
+
+
 void Blacklist::IsBlacklisted(const std::string& extension_id,
                               const IsBlacklistedCallback& callback) {
   std::set<std::string> check;
   check.insert(extension_id);
-  GetBlacklistedIDs(check, base::Bind(&IsNotEmpty, callback));
+  GetBlacklistedIDs(check, base::Bind(&CheckOneExtensionState, callback));
+}
+
+void Blacklist::GetBlacklistStateForIDs(
+    const GetBlacklistedIDsCallback& callback,
+    const std::set<std::string>& blacklisted_ids) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  std::set<std::string> ids_unknown_state;
+  BlacklistStateMap extensions_state;
+  for (std::set<std::string>::const_iterator it = blacklisted_ids.begin();
+       it != blacklisted_ids.end(); ++it) {
+    BlacklistStateMap::const_iterator cache_it =
+        blacklist_state_cache_.find(*it);
+    if (cache_it == blacklist_state_cache_.end())
+      ids_unknown_state.insert(*it);
+    else
+      extensions_state[*it] = cache_it->second;
+  }
+
+  if (ids_unknown_state.empty()) {
+    callback.Run(extensions_state);
+  } else {
+    // After the extension blacklist states have been downloaded, call this
+    // functions again, but prevent infinite cycle in case server is offline
+    // or some other reason prevents us from receiving the blacklist state for
+    // these extensions.
+    RequestExtensionsBlacklistState(
+        ids_unknown_state,
+        base::Bind(&Blacklist::ReturnBlacklistStateMap, AsWeakPtr(),
+                   callback, blacklisted_ids));
+  }
+}
+
+void Blacklist::ReturnBlacklistStateMap(
+    const GetBlacklistedIDsCallback& callback,
+    const std::set<std::string>& blacklisted_ids) {
+  BlacklistStateMap extensions_state;
+  for (std::set<std::string>::const_iterator it = blacklisted_ids.begin();
+       it != blacklisted_ids.end(); ++it) {
+    BlacklistStateMap::const_iterator cache_it =
+        blacklist_state_cache_.find(*it);
+    if (cache_it != blacklist_state_cache_.end())
+      extensions_state[*it] = cache_it->second;
+    // If for some reason we still haven't cached the state of this extension,
+    // we silently skip it.
+  }
+
+  callback.Run(extensions_state);
+}
+
+void Blacklist::RequestExtensionsBlacklistState(
+    const std::set<std::string> ids, base::Callback<void()> callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  // This is a stub. The request will be made here, but the server is not up
+  // yet. For compatibility with current blacklist logic, mark all extensions
+  // as malicious.
+  for (std::set<std::string>::const_iterator it = ids.begin();
+       it != ids.end();
+       ++it) {
+    blacklist_state_cache_[*it] = BLACKLISTED_MALWARE;
+  }
+  callback.Run();
 }
 
 void Blacklist::AddObserver(Observer* observer) {
diff --git a/chrome/browser/extensions/blacklist.h b/chrome/browser/extensions/blacklist.h
index f005eaf..200b5e6 100644
--- a/chrome/browser/extensions/blacklist.h
+++ b/chrome/browser/extensions/blacklist.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_BLACKLIST_H_
 #define CHROME_BROWSER_EXTENSIONS_BLACKLIST_H_
 
+#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -52,14 +53,24 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedDatabaseManagerForTest);
   };
 
+  // The numeric values here match the values of the respective enum in proto
+  // received from SafeBrowsing server.
   enum BlacklistState {
-    NOT_BLACKLISTED,
-    BLACKLISTED,
+    NOT_BLACKLISTED = 0,
+    BLACKLISTED_MALWARE = 1,
+    BLACKLISTED_SECURITY_VULNERABILITY = 2,
+    BLACKLISTED_CWS_POLICY_VIOLATION = 3,
+    BLACKLISTED_POTENTIALLY_UNWANTED = 4
   };
 
-  typedef base::Callback<void(const std::set<std::string>&)>
+  typedef std::map<std::string, BlacklistState> BlacklistStateMap;
+
+  typedef base::Callback<void(const BlacklistStateMap&)>
       GetBlacklistedIDsCallback;
 
+  typedef base::Callback<void(const std::set<std::string>&)>
+      GetMalwareIDsCallback;
+
   typedef base::Callback<void(BlacklistState)> IsBlacklistedCallback;
 
   explicit Blacklist(ExtensionPrefs* prefs);
@@ -67,14 +78,23 @@
   virtual ~Blacklist();
 
   // From the set of extension IDs passed in via |ids|, asynchronously checks
-  // which are blacklisted and includes them in the resulting set passed
-  // via |callback|, which will be sent on the caller's message loop.
+  // which are blacklisted and includes them in the resulting map passed
+  // via |callback|, which will be sent on the caller's message loop. The values
+  // of the map are the blacklist state for each extension. Extensions with
+  // a BlacklistState of NOT_BLACKLISTED are not included in the result.
   //
   // For a synchronous version which ONLY CHECKS CURRENTLY INSTALLED EXTENSIONS
   // see ExtensionPrefs::IsExtensionBlacklisted.
   void GetBlacklistedIDs(const std::set<std::string>& ids,
                          const GetBlacklistedIDsCallback& callback);
 
+  // From the subset of extension IDs passed in via |ids|, select the ones
+  // marked in the blacklist as BLACKLISTED_MALWARE and asynchronously pass
+  // to |callback|. Basically, will call GetBlacklistedIDs and filter its
+  // results.
+  void GetMalwareIDs(const std::set<std::string>& ids,
+                     const GetMalwareIDsCallback& callback);
+
   // More convenient form of GetBlacklistedIDs for checking a single extension.
   void IsBlacklisted(const std::string& extension_id,
                      const IsBlacklistedCallback& callback);
@@ -94,10 +114,21 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  void GetBlacklistStateForIDs(const GetBlacklistedIDsCallback& callback,
+                               const std::set<std::string>& blacklisted_ids);
+
+  void RequestExtensionsBlacklistState(const std::set<std::string> ids,
+                                       base::Callback<void()> callback);
+
+  void ReturnBlacklistStateMap(const GetBlacklistedIDsCallback& callback,
+                               const std::set<std::string>& blacklisted_ids);
+
   ObserverList<Observer> observers_;
 
   content::NotificationRegistrar registrar_;
 
+  BlacklistStateMap blacklist_state_cache_;
+
   DISALLOW_COPY_AND_ASSIGN(Blacklist);
 };
 
diff --git a/chrome/browser/extensions/blacklist_unittest.cc b/chrome/browser/extensions/blacklist_unittest.cc
index 1ebf5e2..18d4bb8 100644
--- a/chrome/browser/extensions/blacklist_unittest.cc
+++ b/chrome/browser/extensions/blacklist_unittest.cc
@@ -87,12 +87,12 @@
   blacklist_db()->Enable();
   blacklist_db()->SetUnsafe(a, b);
 
-  EXPECT_TRUE(tester.IsBlacklisted(a));
-  EXPECT_TRUE(tester.IsBlacklisted(b));
-  EXPECT_FALSE(tester.IsBlacklisted(c));
+  EXPECT_EQ(Blacklist::BLACKLISTED_MALWARE, tester.GetBlacklistState(a));
+  EXPECT_EQ(Blacklist::BLACKLISTED_MALWARE, tester.GetBlacklistState(b));
+  EXPECT_EQ(Blacklist::NOT_BLACKLISTED, tester.GetBlacklistState(c));
 
   std::set<std::string> blacklisted_ids;
-  blacklist.GetBlacklistedIDs(Set(a, c), base::Bind(&Assign, &blacklisted_ids));
+  blacklist.GetMalwareIDs(Set(a, c), base::Bind(&Assign, &blacklisted_ids));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(Set(a), blacklisted_ids);
@@ -104,20 +104,20 @@
   Blacklist blacklist(prefs());
   TestBlacklist tester(&blacklist);
 
-  EXPECT_FALSE(tester.IsBlacklisted(a));
+  EXPECT_EQ(Blacklist::NOT_BLACKLISTED, tester.GetBlacklistState(a));
 
   blacklist_db()->SetUnsafe(a);
   // The manager is still disabled at this point, so it won't be blacklisted.
-  EXPECT_FALSE(tester.IsBlacklisted(a));
+  EXPECT_EQ(Blacklist::NOT_BLACKLISTED, tester.GetBlacklistState(a));
 
   blacklist_db()->Enable().NotifyUpdate();
   base::RunLoop().RunUntilIdle();
   // Now it should be.
-  EXPECT_TRUE(tester.IsBlacklisted(a));
+  EXPECT_EQ(Blacklist::BLACKLISTED_MALWARE, tester.GetBlacklistState(a));
 
   blacklist_db()->ClearUnsafe().NotifyUpdate();
   // Safe browsing blacklist empty, now enabled.
-  EXPECT_FALSE(tester.IsBlacklisted(a));
+  EXPECT_EQ(Blacklist::NOT_BLACKLISTED, tester.GetBlacklistState(a));
 }
 
 // Tests that Blacklist clears the old prefs blacklist on startup.
@@ -149,8 +149,8 @@
   // safebrowsing. Blacklist no longer reads from prefs. This is purely a
   // concern of somebody else (currently, ExtensionService).
   std::set<std::string> blacklisted_ids;
-  blacklist.GetBlacklistedIDs(Set(a, b, c, d),
-                              base::Bind(&Assign, &blacklisted_ids));
+  blacklist.GetMalwareIDs(Set(a, b, c, d),
+                          base::Bind(&Assign, &blacklisted_ids));
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(std::set<std::string>(), blacklisted_ids);
 
diff --git a/chrome/browser/extensions/bundle_installer.cc b/chrome/browser/extensions/bundle_installer.cc
index ec8b8e5..3bd45c0 100644
--- a/chrome/browser/extensions/bundle_installer.cc
+++ b/chrome/browser/extensions/bundle_installer.cc
@@ -20,10 +20,10 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/chrome/browser/extensions/chrome_extension_function.cc b/chrome/browser/extensions/chrome_extension_function.cc
new file mode 100644
index 0000000..9b99e47
--- /dev/null
+++ b/chrome/browser/extensions/chrome_extension_function.cc
@@ -0,0 +1,114 @@
+// Copyright 2013 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/extensions/chrome_extension_function.h"
+
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+
+using content::RenderViewHost;
+using content::WebContents;
+
+ChromeAsyncExtensionFunction::ChromeAsyncExtensionFunction() {}
+
+Profile* ChromeAsyncExtensionFunction::GetProfile() const {
+  return Profile::FromBrowserContext(context_);
+}
+
+bool ChromeAsyncExtensionFunction::CanOperateOnWindow(
+    const extensions::WindowController* window_controller) const {
+  const extensions::Extension* extension = GetExtension();
+  // |extension| is NULL for unit tests only.
+  if (extension != NULL && !window_controller->IsVisibleToExtension(extension))
+    return false;
+
+  if (GetProfile() == window_controller->profile())
+    return true;
+
+  if (!include_incognito())
+    return false;
+
+  return GetProfile()->HasOffTheRecordProfile() &&
+         GetProfile()->GetOffTheRecordProfile() == window_controller->profile();
+}
+
+// TODO(stevenjb): Replace this with GetExtensionWindowController().
+Browser* ChromeAsyncExtensionFunction::GetCurrentBrowser() {
+  // If the delegate has an associated browser, return it.
+  if (dispatcher()) {
+    extensions::WindowController* window_controller =
+        dispatcher()->delegate()->GetExtensionWindowController();
+    if (window_controller) {
+      Browser* browser = window_controller->GetBrowser();
+      if (browser)
+        return browser;
+    }
+  }
+
+  // Otherwise, try to default to a reasonable browser. If |include_incognito_|
+  // is true, we will also search browsers in the incognito version of this
+  // profile. Note that the profile may already be incognito, in which case
+  // we will search the incognito version only, regardless of the value of
+  // |include_incognito|. Look only for browsers on the active desktop as it is
+  // preferable to pretend no browser is open then to return a browser on
+  // another desktop.
+  if (render_view_host_) {
+    Profile* profile = Profile::FromBrowserContext(
+        render_view_host_->GetProcess()->GetBrowserContext());
+    Browser* browser = chrome::FindAnyBrowser(
+        profile, include_incognito_, chrome::GetActiveDesktop());
+    if (browser)
+      return browser;
+  }
+
+  // NOTE(rafaelw): This can return NULL in some circumstances. In particular,
+  // a background_page onload chrome.tabs api call can make it into here
+  // before the browser is sufficiently initialized to return here, or
+  // all of this profile's browser windows may have been closed.
+  // A similar situation may arise during shutdown.
+  // TODO(rafaelw): Delay creation of background_page until the browser
+  // is available. http://code.google.com/p/chromium/issues/detail?id=13284
+  return NULL;
+}
+
+extensions::WindowController*
+ChromeAsyncExtensionFunction::GetExtensionWindowController() {
+  // If the delegate has an associated window controller, return it.
+  if (dispatcher()) {
+    extensions::WindowController* window_controller =
+        dispatcher()->delegate()->GetExtensionWindowController();
+    if (window_controller)
+      return window_controller;
+  }
+
+  return extensions::WindowControllerList::GetInstance()
+      ->CurrentWindowForFunction(this);
+}
+
+content::WebContents* ChromeAsyncExtensionFunction::GetAssociatedWebContents() {
+  content::WebContents* web_contents =
+      UIThreadExtensionFunction::GetAssociatedWebContents();
+  if (web_contents)
+    return web_contents;
+
+  Browser* browser = GetCurrentBrowser();
+  if (!browser)
+    return NULL;
+  return browser->tab_strip_model()->GetActiveWebContents();
+}
+
+ChromeAsyncExtensionFunction::~ChromeAsyncExtensionFunction() {}
+
+ChromeSyncExtensionFunction::ChromeSyncExtensionFunction() {}
+
+void ChromeSyncExtensionFunction::Run() { SendResponse(RunImpl()); }
+
+ChromeSyncExtensionFunction::~ChromeSyncExtensionFunction() {}
diff --git a/chrome/browser/extensions/chrome_extension_function.h b/chrome/browser/extensions/chrome_extension_function.h
new file mode 100644
index 0000000..5da6855
--- /dev/null
+++ b/chrome/browser/extensions/chrome_extension_function.h
@@ -0,0 +1,77 @@
+// Copyright 2013 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_EXTENSIONS_CHROME_EXTENSION_FUNCTION_H_
+#define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FUNCTION_H_
+
+#include "chrome/browser/extensions/extension_function.h"
+
+class Browser;
+class Profile;
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+class WindowController;
+}
+
+// A chrome specific analog to AsyncExtensionFunction. This has access
+// the a chrome Profile.
+class ChromeAsyncExtensionFunction : public UIThreadExtensionFunction {
+ public:
+  ChromeAsyncExtensionFunction();
+
+  Profile* GetProfile() const;
+
+  // Returns true if this function (and the profile and extension that it was
+  // invoked from) can operate on the window wrapped by |window_controller|.
+  bool CanOperateOnWindow(const extensions::WindowController* window_controller)
+      const;
+
+  // Gets the "current" browser, if any.
+  //
+  // Many extension APIs operate relative to the current browser, which is the
+  // browser the calling code is running inside of. For example, popups, tabs,
+  // and infobars all have a containing browser, but background pages and
+  // notification bubbles do not.
+  //
+  // If there is no containing window, the current browser defaults to the
+  // foremost one.
+  //
+  // Incognito browsers are not considered unless the calling extension has
+  // incognito access enabled.
+  //
+  // This method can return NULL if there is no matching browser, which can
+  // happen if only incognito windows are open, or early in startup or shutdown
+  // shutdown when there are no active windows.
+  //
+  // TODO(stevenjb): Replace this with GetExtensionWindowController().
+  Browser* GetCurrentBrowser();
+
+  // Same as above but uses WindowControllerList instead of BrowserList.
+  extensions::WindowController* GetExtensionWindowController();
+
+  // Gets the "current" web contents if any. If there is no associated web
+  // contents then defaults to the foremost one.
+  virtual content::WebContents* GetAssociatedWebContents() OVERRIDE;
+
+ protected:
+  virtual ~ChromeAsyncExtensionFunction();
+};
+
+// A chrome specific analog to SyncExtensionFunction. This has access
+// the a chrome Profile.
+class ChromeSyncExtensionFunction : public ChromeAsyncExtensionFunction {
+ public:
+  ChromeSyncExtensionFunction();
+
+  virtual void Run() OVERRIDE;
+
+ protected:
+  virtual ~ChromeSyncExtensionFunction();
+};
+
+#endif  // CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FUNCTION_H_
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
new file mode 100644
index 0000000..e2ba427
--- /dev/null
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -0,0 +1,49 @@
+// Copyright 2013 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/extensions/chrome_extensions_browser_client.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace extensions {
+
+namespace {
+
+static base::LazyInstance<ChromeExtensionsBrowserClient> g_client =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+ChromeExtensionsBrowserClient::ChromeExtensionsBrowserClient() {}
+
+ChromeExtensionsBrowserClient::~ChromeExtensionsBrowserClient() {}
+
+bool ChromeExtensionsBrowserClient::IsShuttingDown() {
+  return g_browser_process->IsShuttingDown();
+}
+
+bool ChromeExtensionsBrowserClient::IsSameContext(
+    content::BrowserContext* first,
+    content::BrowserContext* second) {
+  return static_cast<Profile*>(first)->IsSameProfile(
+      static_cast<Profile*>(second));
+}
+
+bool ChromeExtensionsBrowserClient::HasOffTheRecordContext(
+    content::BrowserContext* context) {
+  return static_cast<Profile*>(context)->HasOffTheRecordProfile();
+}
+
+content::BrowserContext* ChromeExtensionsBrowserClient::GetOffTheRecordContext(
+    content::BrowserContext* context) {
+  return static_cast<Profile*>(context)->GetOffTheRecordProfile();
+}
+
+// static
+ChromeExtensionsBrowserClient* ChromeExtensionsBrowserClient::GetInstance() {
+  return g_client.Pointer();
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
new file mode 100644
index 0000000..ddcc4d7
--- /dev/null
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_CLIENT_H_
+#define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "extensions/browser/extensions_browser_client.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+// Implementation of extensions::BrowserClient for Chrome, which includes
+// knowledge of Profiles, BrowserContexts and incognito.
+//
+// NOTE: Methods that do not require knowledge of browser concepts should be
+// implemented in ChromeExtensionsClient even if they are only used in the
+// browser process (see chrome/common/extensions/chrome_extensions_client.h).
+class ChromeExtensionsBrowserClient : public ExtensionsBrowserClient {
+ public:
+  ChromeExtensionsBrowserClient();
+  virtual ~ChromeExtensionsBrowserClient();
+
+  // BrowserClient overrides:
+  virtual bool IsShuttingDown() OVERRIDE;
+  virtual bool IsSameContext(content::BrowserContext* first,
+                             content::BrowserContext* second) OVERRIDE;
+  virtual bool HasOffTheRecordContext(
+      content::BrowserContext* context) OVERRIDE;
+  virtual content::BrowserContext* GetOffTheRecordContext(
+      content::BrowserContext* context) OVERRIDE;
+
+  // Get the LazyInstance for ChromeBrowserClient.
+  static ChromeExtensionsBrowserClient* GetInstance();
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsBrowserClient>;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsBrowserClient);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_CLIENT_H_
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 1f802b5..b18ad91 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -285,6 +285,11 @@
 #endif  // defined(FILE_MANAGER_EXTENSION)
 }
 
+void ComponentLoader::AddHangoutServicesExtension() {
+  Add(IDR_HANGOUT_SERVICES_MANIFEST,
+      base::FilePath(FILE_PATH_LITERAL("hangout_services")));
+}
+
 void ComponentLoader::AddImageLoaderExtension() {
 #if defined(IMAGE_LOADER_EXTENSION)
 #ifndef NDEBUG
@@ -426,7 +431,9 @@
           base::FilePath(FILE_PATH_LITERAL("apps_debugger")));
     }
 
+
     AddFileManagerExtension();
+    AddHangoutServicesExtension();
     AddImageLoaderExtension();
 
 #if defined(ENABLE_SETTINGS_APP)
@@ -445,11 +452,7 @@
     Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
 
 #if defined(OS_CHROMEOS)
-  if (!skip_session_components &&
-      !command_line->HasSwitch(chromeos::switches::kGuestSession)) {
-    Add(IDR_WALLPAPERMANAGER_MANIFEST,
-        base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
-
+  if (!skip_session_components) {
 #if defined(GOOGLE_CHROME_BUILD)
     if (!command_line->HasSwitch(
             chromeos::switches::kDisableQuickofficeComponentApp)) {
@@ -482,6 +485,11 @@
     }
     Add(IDR_ECHO_MANIFEST, echo_extension_path);
 
+    if (!command_line->HasSwitch(chromeos::switches::kGuestSession)) {
+      Add(IDR_WALLPAPERMANAGER_MANIFEST,
+          base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
+    }
+
     Add(IDR_NETWORK_CONFIGURATION_MANIFEST,
         base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
 
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index c4892b7..8b1a961 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -112,6 +112,7 @@
   void AddDefaultComponentExtensionsWithBackgroundPages(
       bool skip_session_components);
   void AddFileManagerExtension();
+  void AddHangoutServicesExtension();
   void AddImageLoaderExtension();
   void AddBookmarksExtensions();
 
diff --git a/chrome/browser/extensions/component_loader_unittest.cc b/chrome/browser/extensions/component_loader_unittest.cc
index d305c97..831562c 100644
--- a/chrome/browser/extensions/component_loader_unittest.cc
+++ b/chrome/browser/extensions/component_loader_unittest.cc
@@ -42,7 +42,7 @@
 
   virtual void UnloadExtension(
       const std::string& extension_id,
-      extension_misc::UnloadedExtensionReason reason) OVERRIDE {
+      UnloadedExtensionInfo::Reason reason) OVERRIDE {
     ASSERT_TRUE(extension_set_.Contains(extension_id));
     // Remove the extension with the matching id.
     extension_set_.Remove(extension_id);
@@ -51,7 +51,7 @@
 
   virtual void RemoveComponentExtension(const std::string & extension_id)
       OVERRIDE {
-    UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_DISABLE);
+    UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_DISABLE);
   }
 
   virtual bool is_ready() OVERRIDE {
diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc
index 4294e3e..ec7d423 100644
--- a/chrome/browser/extensions/convert_web_app_browsertest.cc
+++ b/chrome/browser/extensions/convert_web_app_browsertest.cc
@@ -15,7 +15,6 @@
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -25,6 +24,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/permissions/permission_set.h"
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index fcf5948..936ed45 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -20,9 +20,9 @@
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/web_application_info.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/codec/png_codec.h"
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 5b45c47..9fdb2f4 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -41,7 +41,6 @@
 #include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h"
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -49,6 +48,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/user_script.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -523,7 +523,7 @@
 
   blacklist_state_ = blacklist_state;
 
-  if (blacklist_state_ == extensions::Blacklist::BLACKLISTED &&
+  if (blacklist_state_ == extensions::Blacklist::BLACKLISTED_MALWARE &&
       !allow_silent_install_) {
     // User tried to install a blacklisted extension. Show an error and
     // refuse to install it.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index d9c7114..a37be36 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -17,10 +17,10 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/test/download_test_observer.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/switches.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc
index 957a935..73fc05d 100644
--- a/chrome/browser/extensions/default_apps.cc
+++ b/chrome/browser/extensions/default_apps.cc
@@ -15,6 +15,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/chrome/browser/extensions/devtools_util.cc b/chrome/browser/extensions/devtools_util.cc
index b17530d..987fe9e 100644
--- a/chrome/browser/extensions/devtools_util.cc
+++ b/chrome/browser/extensions/devtools_util.cc
@@ -8,8 +8,9 @@
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 
 namespace extensions {
 namespace devtools_util {
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index b5e88bf..c1203f6 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/extensions/process_map.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -37,6 +36,7 @@
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "extensions/common/extension_urls.h"
 
 using base::DictionaryValue;
diff --git a/chrome/browser/extensions/extension_action_icon_factory.cc b/chrome/browser/extensions/extension_action_icon_factory.cc
index e7b84e0..cbffbbc 100644
--- a/chrome/browser/extensions/extension_action_icon_factory.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/extension_action_icon_factory.h"
 
 #include "chrome/browser/extensions/extension_action.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "grit/theme_resources.h"
diff --git a/chrome/browser/extensions/extension_action_icon_factory.h b/chrome/browser/extensions/extension_action_icon_factory.h
index 0dc681b..3d6142a 100644
--- a/chrome/browser/extensions/extension_action_icon_factory.h
+++ b/chrome/browser/extensions/extension_action_icon_factory.h
@@ -10,6 +10,7 @@
 
 class ExtensionAction;
 class ExtensionIconSet;
+class Profile;
 
 namespace extensions {
 class Extension;
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index 8ab9145..638b101 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -32,6 +32,7 @@
 const char kTestServerPort[] = "testServer.port";
 const char kTestDataDirectory[] = "testDataDirectory";
 const char kTestWebSocketPort[] = "testWebSocketPort";
+const char kSpawnedTestServerPort[] = "spawnedTestServer.port";
 
 scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
     const net::test_server::HttpRequest& request) {
@@ -439,6 +440,19 @@
   return true;
 }
 
+bool ExtensionApiTest::StartSpawnedTestServer() {
+  if (!test_server()->Start())
+    return false;
+
+  // Build a dictionary of values that tests can use to build URLs that
+  // access the test server and local file system.  Tests can see these values
+  // using the extension API function chrome.test.getConfig().
+  test_config_->SetInteger(kSpawnedTestServerPort,
+                           test_server()->host_port_pair().port());
+
+  return true;
+}
+
 void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
   ExtensionBrowserTest::SetUpCommandLine(command_line);
   test_data_dir_ = test_data_dir_.AppendASCII("api_test");
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index 1e79880..fc87dbb 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -168,6 +168,11 @@
   // chrome.test.getConfig().
   bool StartWebSocketServer(const base::FilePath& root_directory);
 
+  // Start the spawned test server, and store details of its state.  Those
+  // details will be available to javascript tests using
+  // chrome.test.getConfig().
+  bool StartSpawnedTestServer();
+
   // Test that exactly one extension loaded.  If so, return a pointer to
   // the extension.  If not, return NULL and set message_.
   const extensions::Extension* GetSingleLoadedExtension();
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 0d6fd91..6811bfc 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -487,7 +487,8 @@
 void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
   ExtensionService* service = extensions::ExtensionSystem::Get(
       profile())->extension_service();
-  service->UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_DISABLE);
+  service->UnloadExtension(extension_id,
+                           extensions::UnloadedExtensionInfo::REASON_DISABLE);
 }
 
 void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 0192142..738daf2 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -29,12 +29,12 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_source.h"
 #include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
index d2ca1c8..5dede6a 100644
--- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -24,13 +25,6 @@
 #include "net/url_request/url_fetcher.h"
 
 using extensions::Extension;
-using extensions::Manifest;
-
-namespace {
-
-const char kTestExtensionId[] = "pgdpcfcocojkjfbgpiianjngphoopgmo";
-
-}
 
 class ExtensionDisabledGlobalErrorTest : public ExtensionBrowserTest {
  protected:
@@ -192,8 +186,10 @@
   // Get data for extension v2 (disabled) into sync.
   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
   std::string extension_id = extension->id();
+  ExtensionSyncService* sync_service = ExtensionSyncService::Get(
+      browser()->profile());
   extensions::ExtensionSyncData sync_data =
-      service_->GetExtensionSyncData(*extension);
+      sync_service->GetExtensionSyncData(*extension);
   UninstallExtension(extension_id);
   extension = NULL;
 
@@ -215,7 +211,7 @@
   service_->updater()->set_default_check_params(params);
 
   // Sync is replacing an older version, so it pends.
-  EXPECT_FALSE(service_->ProcessExtensionSyncData(sync_data));
+  EXPECT_FALSE(sync_service->ProcessExtensionSyncData(sync_data));
 
   WaitForExtensionInstall();
   content::BrowserThread::GetBlockingPool()->FlushForTesting();
@@ -229,58 +225,3 @@
             service_->extension_prefs()->GetDisableReasons(extension_id));
   EXPECT_TRUE(GetExtensionDisabledGlobalError());
 }
-
-// Tests that default app with user consent are not enabled after install.
-IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, DefaultWithConsent) {
-  InstallExtensionWithSourceAndFlags(path_v1_, 0, Manifest::EXTERNAL_PREF,
-      Extension::InitFromValueFlags(Extension::FROM_WEBSTORE |
-          Extension::WAS_INSTALLED_BY_DEFAULT |
-          Extension::REQUIRE_PERMISSIONS_CONSENT));
-  ASSERT_FALSE(GetExtensionDisabledGlobalError());
-
-  // Should be disabled with no error after install.
-  const Extension* extension =
-      service_->GetExtensionById(kTestExtensionId, true);
-  ASSERT_TRUE(extension);
-  EXPECT_EQ("1", extension->VersionString());
-  EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
-  EXPECT_EQ(Extension::DISABLE_PERMISSIONS_CONSENT,
-            service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
-
-  // Update to v2 with more permissions, extension should stay disabled with
-  // the same reason, no error message.
-  UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
-  extension = service_->GetExtensionById(kTestExtensionId, true);
-  ASSERT_TRUE(extension);
-  EXPECT_EQ("2", extension->VersionString());
-  EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
-  EXPECT_EQ(Extension::DISABLE_PERMISSIONS_CONSENT |
-                Extension::DISABLE_PERMISSIONS_INCREASE,
-            service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
-
-  service_->GrantPermissionsAndEnableExtension(extension);
-  EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
-
-  // Update to v3 with more permissions, should be disabled with error.
-  UpdateIncreasingPermissionExtension(extension, path_v3_, -1);
-  extension = service_->GetExtensionById(kTestExtensionId, true);
-  ASSERT_TRUE(extension);
-  EXPECT_EQ("3", extension->VersionString());
-  ASSERT_TRUE(GetExtensionDisabledGlobalError());
-  EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
-  EXPECT_EQ(Extension::DISABLE_PERMISSIONS_INCREASE,
-            service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
-
-  // Enabled extension with granting permissions.
-  extension = UpdateExtension(kTestExtensionId, path_v3_, 0);
-  extension = service_->GetExtensionById(kTestExtensionId, true);
-  ASSERT_TRUE(extension);
-  service_->GrantPermissionsAndEnableExtension(extension);
-  EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
-
-  // Update again to v3 with the same permissions.
-  extension = UpdateExtension(kTestExtensionId, path_v3_, 0);
-  ASSERT_TRUE(extension);
-  ASSERT_FALSE(GetExtensionDisabledGlobalError());
-  EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
-}
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 5b5ea2a..f63d4fd 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -8,18 +8,11 @@
 #include "base/metrics/histogram.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/window_controller.h"
-#include "chrome/browser/extensions/window_controller_list.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/api/extension_api.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -154,10 +147,7 @@
 }
 
 UIThreadExtensionFunction::UIThreadExtensionFunction()
-    : render_view_host_(NULL),
-      profile_(NULL),
-      delegate_(NULL) {
-}
+    : render_view_host_(NULL), context_(NULL), delegate_(NULL) {}
 
 UIThreadExtensionFunction::~UIThreadExtensionFunction() {
   if (dispatcher() && render_view_host())
@@ -184,88 +174,12 @@
   tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL);
 }
 
-// TODO(stevenjb): Replace this with GetExtensionWindowController().
-Browser* UIThreadExtensionFunction::GetCurrentBrowser() {
-  // If the delegate has an associated browser, return it.
-  if (dispatcher()) {
-    extensions::WindowController* window_controller =
-        dispatcher()->delegate()->GetExtensionWindowController();
-    if (window_controller) {
-      Browser* browser = window_controller->GetBrowser();
-      if (browser)
-        return browser;
-    }
-  }
-
-  // Otherwise, try to default to a reasonable browser. If |include_incognito_|
-  // is true, we will also search browsers in the incognito version of this
-  // profile. Note that the profile may already be incognito, in which case
-  // we will search the incognito version only, regardless of the value of
-  // |include_incognito|. Look only for browsers on the active desktop as it is
-  // preferable to pretend no browser is open then to return a browser on
-  // another desktop.
-  if (render_view_host_) {
-    Profile* profile = Profile::FromBrowserContext(
-        render_view_host_->GetProcess()->GetBrowserContext());
-    Browser* browser = chrome::FindAnyBrowser(profile, include_incognito_,
-                                              chrome::GetActiveDesktop());
-    if (browser)
-      return browser;
-  }
-
-  // NOTE(rafaelw): This can return NULL in some circumstances. In particular,
-  // a background_page onload chrome.tabs api call can make it into here
-  // before the browser is sufficiently initialized to return here, or
-  // all of this profile's browser windows may have been closed.
-  // A similar situation may arise during shutdown.
-  // TODO(rafaelw): Delay creation of background_page until the browser
-  // is available. http://code.google.com/p/chromium/issues/detail?id=13284
-  return NULL;
-}
-
 content::WebContents* UIThreadExtensionFunction::GetAssociatedWebContents() {
-  if (dispatcher()) {
-    content::WebContents* web_contents =
-        dispatcher()->delegate()->GetAssociatedWebContents();
-    if (web_contents)
-      return web_contents;
-  }
+  content::WebContents* web_contents = NULL;
+  if (dispatcher())
+    web_contents = dispatcher()->delegate()->GetAssociatedWebContents();
 
-  Browser* browser = GetCurrentBrowser();
-  if (!browser)
-    return NULL;
-  return browser->tab_strip_model()->GetActiveWebContents();
-}
-
-extensions::WindowController*
-UIThreadExtensionFunction::GetExtensionWindowController() {
-  // If the delegate has an associated window controller, return it.
-  if (dispatcher()) {
-    extensions::WindowController* window_controller =
-        dispatcher()->delegate()->GetExtensionWindowController();
-    if (window_controller)
-      return window_controller;
-  }
-
-  return extensions::WindowControllerList::GetInstance()->
-      CurrentWindowForFunction(this);
-}
-
-bool UIThreadExtensionFunction::CanOperateOnWindow(
-    const extensions::WindowController* window_controller) const {
-  const extensions::Extension* extension = GetExtension();
-  // |extension| is NULL for unit tests only.
-  if (extension != NULL && !window_controller->IsVisibleToExtension(extension))
-    return false;
-
-  if (profile() == window_controller->profile())
-    return true;
-
-  if (!include_incognito())
-    return false;
-
-  return profile()->HasOffTheRecordProfile() &&
-      profile()->GetOffTheRecordProfile() == window_controller->profile();
+  return web_contents;
 }
 
 void UIThreadExtensionFunction::SendResponse(bool success) {
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index d26ae1e..2834823 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -22,13 +22,11 @@
 #include "content/public/common/console_message_level.h"
 #include "ipc/ipc_message.h"
 
-class Browser;
 class ChromeRenderMessageFilter;
 class ExtensionFunction;
 class ExtensionFunctionDispatcher;
 class UIThreadExtensionFunction;
 class IOThreadExtensionFunction;
-class Profile;
 class QuotaLimitHeuristic;
 
 namespace base {
@@ -37,14 +35,11 @@
 }
 
 namespace content {
+class BrowserContext;
 class RenderViewHost;
 class WebContents;
 }
 
-namespace extensions {
-class WindowController;
-}
-
 #ifdef NDEBUG
 #define EXTENSION_FUNCTION_VALIDATE(test) do { \
     if (!(test)) { \
@@ -218,7 +213,7 @@
   // Id of this request, used to map the response back to the caller.
   int request_id_;
 
-  // The Profile of this function's extension.
+  // The id of the profile of this function's extension.
   void* profile_id_;
 
   // The extension that called this function.
@@ -294,10 +289,10 @@
   // Should return true if it processed the message.
   virtual bool OnMessageReceivedFromRenderView(const IPC::Message& message);
 
-  // Set the profile which contains the extension that has originated this
-  // function call.
-  void set_profile(Profile* profile) { profile_ = profile; }
-  Profile* profile() const { return profile_; }
+  // Set the browser context which contains the extension that has originated
+  // this function call.
+  void set_context(content::BrowserContext* context) { context_ = context; }
+  content::BrowserContext* context() const { return context_; }
 
   void SetRenderViewHost(content::RenderViewHost* render_view_host);
   content::RenderViewHost* render_view_host() const {
@@ -312,37 +307,9 @@
     return dispatcher_.get();
   }
 
-  // Gets the "current" browser, if any.
-  //
-  // Many extension APIs operate relative to the current browser, which is the
-  // browser the calling code is running inside of. For example, popups, tabs,
-  // and infobars all have a containing browser, but background pages and
-  // notification bubbles do not.
-  //
-  // If there is no containing window, the current browser defaults to the
-  // foremost one.
-  //
-  // Incognito browsers are not considered unless the calling extension has
-  // incognito access enabled.
-  //
-  // This method can return NULL if there is no matching browser, which can
-  // happen if only incognito windows are open, or early in startup or shutdown
-  // shutdown when there are no active windows.
-  //
-  // TODO(stevenjb): Replace this with GetExtensionWindowController().
-  Browser* GetCurrentBrowser();
-
   // Gets the "current" web contents if any. If there is no associated web
   // contents then defaults to the foremost one.
-  content::WebContents* GetAssociatedWebContents();
-
-  // Same as above but uses WindowControllerList instead of BrowserList.
-  extensions::WindowController* GetExtensionWindowController();
-
-  // Returns true if this function (and the profile and extension that it was
-  // invoked from) can operate on the window wrapped by |window_controller|.
-  bool CanOperateOnWindow(
-      const extensions::WindowController* window_controller) const;
+  virtual content::WebContents* GetAssociatedWebContents();
 
  protected:
   // Emits a message to the extension's devtools console.
@@ -363,8 +330,8 @@
   // The RenderViewHost we will send responses too.
   content::RenderViewHost* render_view_host_;
 
-  // The Profile of this function's extension.
-  Profile* profile_;
+  // The content::BrowserContext of this function's extension.
+  content::BrowserContext* context_;
 
  private:
   class RenderViewHostTracker;
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 85961e3..a61348b 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -352,7 +352,7 @@
   }
   function_ui->SetRenderViewHost(render_view_host);
   function_ui->set_dispatcher(AsWeakPtr());
-  function_ui->set_profile(profile_);
+  function_ui->set_context(profile_);
   function->set_include_incognito(extension_util::CanCrossIncognito(extension,
                                                                     service));
 
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 59f7aae..14d357d 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -673,6 +673,15 @@
   SOCKETS_TCP_SERVER_GETSOCKETS,
   SYSTEM_STORAGE_GETAVAILABLECAPACITY,
   BROWSERACTION_OPEN_POPUP,
+  WEBRTC_AUDIO_PRIVATE_GET_SINKS,
+  WEBRTC_AUDIO_PRIVATE_GET_ACTIVE_SINK,
+  WEBRTC_AUDIO_PRIVATE_SET_ACTIVE_SINK,
+  WEBRTC_AUDIO_PRIVATE_GET_ASSOCIATED_SINK,
+  VIRTUALKEYBOARDPRIVATE_KEYBOARDLOADED,
+  APP_CURRENTWINDOWINTERNAL_SETMINWIDTH,
+  APP_CURRENTWINDOWINTERNAL_SETMINHEIGHT,
+  APP_CURRENTWINDOWINTERNAL_SETMAXWIDTH,
+  APP_CURRENTWINDOWINTERNAL_SETMAXHEIGHT,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc
index 40651a8..de33b9f 100644
--- a/chrome/browser/extensions/extension_function_test_utils.cc
+++ b/chrome/browser/extensions/extension_function_test_utils.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -254,7 +255,7 @@
       browser->profile(), &dispatcher_delegate);
   function->set_dispatcher(dispatcher.AsWeakPtr());
 
-  function->set_profile(browser->profile());
+  function->set_context(browser->profile());
   function->set_include_incognito(flags & INCLUDE_INCOGNITO);
   function->Run();
 
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index b859c41..e8da09d 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -258,6 +258,10 @@
       view()->browser()->extension_window_controller() : NULL;
 }
 
+content::BrowserContext* ExtensionHost::browser_context() {
+  return profile_;
+}
+
 const GURL& ExtensionHost::GetURL() const {
   return host_contents()->GetURL();
 }
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 376d388..b5501a7 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -39,6 +39,7 @@
 class PrefsTabHelper;
 
 namespace content {
+class BrowserContext;
 class RenderProcessHost;
 class RenderWidgetHostView;
 class SiteInstance;
@@ -115,6 +116,10 @@
 
   Profile* profile() const { return profile_; }
 
+  // Returns the same value as profile() but as a BrowserContext. Implemented
+  // in the .cc file to avoid including profile.h in this header.
+  content::BrowserContext* browser_context();
+
   ViewType extension_host_type() const { return extension_host_type_; }
   const GURL& GetURL() const;
 
diff --git a/chrome/browser/extensions/extension_icon_image.cc b/chrome/browser/extensions/extension_icon_image.cc
index 7b0b248..6c0b4b3 100644
--- a/chrome/browser/extensions/extension_icon_image.cc
+++ b/chrome/browser/extensions/extension_icon_image.cc
@@ -128,13 +128,13 @@
 // IconImage
 
 IconImage::IconImage(
-    Profile* profile,
+    content::BrowserContext* context,
     const Extension* extension,
     const ExtensionIconSet& icon_set,
     int resource_size_in_dip,
     const gfx::ImageSkia& default_icon,
     Observer* observer)
-    : profile_(profile),
+    : browser_context_(context),
       extension_(extension),
       icon_set_(icon_set),
       resource_size_in_dip_(resource_size_in_dip),
@@ -194,7 +194,8 @@
           gfx::Size(resource_size_in_dip_, resource_size_in_dip_), scale)),
       scale_factor));
 
-  extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile_);
+  extensions::ImageLoader* loader =
+      extensions::ImageLoader::Get(browser_context_);
   loader->LoadImagesAsync(extension_, info_list,
                           base::Bind(&IconImage::OnImageLoaded,
                                      weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/extensions/extension_icon_image.h b/chrome/browser/extensions/extension_icon_image.h
index 94cdae5..b6fc0c4 100644
--- a/chrome/browser/extensions/extension_icon_image.h
+++ b/chrome/browser/extensions/extension_icon_image.h
@@ -16,7 +16,9 @@
 #include "ui/base/layout.h"
 #include "ui/gfx/image/image_skia.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace extensions {
 class Extension;
@@ -58,10 +60,10 @@
     virtual ~Observer() {}
   };
 
-  // |profile| is required by the underlying implementation to retrieve the
-  // |ImageLoader| instance associated with the given profile. |ImageLoader| is
+  // |context| is required by the underlying implementation to retrieve the
+  // |ImageLoader| instance associated with the given context. |ImageLoader| is
   // used to perform the asynchronous image load work.
-  IconImage(Profile* profile,
+  IconImage(content::BrowserContext* context,
             const Extension* extension,
             const ExtensionIconSet& icon_set,
             int resource_size_in_dip,
@@ -89,7 +91,7 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  Profile* profile_;
+  content::BrowserContext* browser_context_;
   const Extension* extension_;
   const ExtensionIconSet& icon_set_;
   const int resource_size_in_dip_;
diff --git a/chrome/browser/extensions/extension_icon_manager.cc b/chrome/browser/extensions/extension_icon_manager.cc
index 475f4cb..e247da3 100644
--- a/chrome/browser/extensions/extension_icon_manager.cc
+++ b/chrome/browser/extensions/extension_icon_manager.cc
@@ -52,7 +52,7 @@
 ExtensionIconManager::~ExtensionIconManager() {
 }
 
-void ExtensionIconManager::LoadIcon(Profile* profile,
+void ExtensionIconManager::LoadIcon(content::BrowserContext* context,
                                     const extensions::Extension* extension) {
   extensions::ExtensionResource icon_resource =
       extensions::IconsInfo::GetIconResource(
@@ -63,7 +63,7 @@
     // Insert into pending_icons_ first because LoadImage can call us back
     // synchronously if the image is already cached.
     pending_icons_.insert(extension->id());
-    extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile);
+    extensions::ImageLoader* loader = extensions::ImageLoader::Get(context);
     loader->LoadImageAsync(extension, icon_resource,
                            gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize),
                            base::Bind(
diff --git a/chrome/browser/extensions/extension_icon_manager.h b/chrome/browser/extensions/extension_icon_manager.h
index 59f48a2..d8f1e78 100644
--- a/chrome/browser/extensions/extension_icon_manager.h
+++ b/chrome/browser/extensions/extension_icon_manager.h
@@ -14,7 +14,9 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/insets.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace extensions {
 class Extension;
@@ -30,7 +32,8 @@
   virtual ~ExtensionIconManager();
 
   // Start loading the icon for the given extension.
-  void LoadIcon(Profile* profile, const extensions::Extension* extension);
+  void LoadIcon(content::BrowserContext* context,
+                const extensions::Extension* extension);
 
   // This returns a bitmap of width/height kFaviconSize, loaded either from an
   // entry specified in the extension's 'icon' section of the manifest, or a
diff --git a/chrome/browser/extensions/extension_info_map.cc b/chrome/browser/extensions/extension_info_map.cc
index e7549d2..10fa8c3 100644
--- a/chrome/browser/extensions/extension_info_map.cc
+++ b/chrome/browser/extensions/extension_info_map.cc
@@ -13,6 +13,7 @@
 
 using content::BrowserThread;
 using extensions::Extension;
+using extensions::UnloadedExtensionInfo;
 
 namespace {
 
@@ -54,13 +55,14 @@
   extra_data_[extension->id()].incognito_enabled = incognito_enabled;
 }
 
-void ExtensionInfoMap::RemoveExtension(const std::string& extension_id,
-    const extension_misc::UnloadedExtensionReason reason) {
+void ExtensionInfoMap::RemoveExtension(
+    const std::string& extension_id,
+    const UnloadedExtensionInfo::Reason reason) {
   CheckOnValidThread();
   const Extension* extension = extensions_.GetByID(extension_id);
   extra_data_.erase(extension_id);  // we don't care about disabled extra data
-  bool was_uninstalled = (reason != extension_misc::UNLOAD_REASON_DISABLE &&
-                          reason != extension_misc::UNLOAD_REASON_TERMINATE);
+  bool was_uninstalled = (reason != UnloadedExtensionInfo::REASON_DISABLE &&
+                          reason != UnloadedExtensionInfo::REASON_TERMINATE);
   if (extension) {
     if (!was_uninstalled)
       disabled_extensions_.Insert(extension);
diff --git a/chrome/browser/extensions/extension_info_map.h b/chrome/browser/extensions/extension_info_map.h
index cfbf6c6..53c04f5 100644
--- a/chrome/browser/extensions/extension_info_map.h
+++ b/chrome/browser/extensions/extension_info_map.h
@@ -13,7 +13,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/extensions/extensions_quota_service.h"
 #include "chrome/browser/extensions/process_map.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_set.h"
 
 namespace extensions {
@@ -41,7 +40,7 @@
 
   // Callback for when an extension is unloaded.
   void RemoveExtension(const std::string& extension_id,
-                       const extension_misc::UnloadedExtensionReason reason);
+                       const extensions::UnloadedExtensionInfo::Reason reason);
 
   // Returns the time the extension was installed, or base::Time() if not found.
   base::Time GetInstallTime(const std::string& extension_id) const;
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index 9439cf3..dac4e0a 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -102,7 +102,7 @@
 
   // Remove extension2, and the extension2 object should have the only ref.
   info_map->RemoveExtension(
-      extension2->id(), extension_misc::UNLOAD_REASON_UNINSTALL);
+      extension2->id(), extensions::UnloadedExtensionInfo::REASON_UNINSTALL);
   EXPECT_TRUE(extension2->HasOneRef());
 
   // Delete the info map, and the extension3 object should have the only ref.
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 66c7ab9..286bec5 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -28,7 +28,6 @@
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/web_contents.h"
@@ -37,6 +36,7 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -60,7 +60,7 @@
   IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
   IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
   IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
-  IDS_EXTENSION_FIRST_RUN_PROMPT_TITLE,
+  IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
 };
 static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
   IDS_EXTENSION_INSTALL_PROMPT_HEADING,
@@ -70,7 +70,7 @@
   IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
   0,  // External installs use different strings for extensions/apps.
   IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
-  IDS_EXTENSION_FIRST_RUN_PROMPT_HEADING,
+  IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING,
 };
 static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
   ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
@@ -90,7 +90,7 @@
   IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
   0,  // External installs use different strings for extensions/apps.
   IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON,
-  IDS_EXTENSION_PROMPT_FIRST_RUN_ACCEPT_BUTTON
+  IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
 };
 static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
   0,  // These all use the platform's default cancel label.
@@ -111,7 +111,7 @@
   IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
   IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
   IDS_EXTENSION_PROMPT_CAN_ACCESS,
-  IDS_EXTENSION_PROMPT_CAN_ACCESS,
+  IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
 };
 static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
   IDS_EXTENSION_PROMPT_OAUTH_HEADER,
@@ -404,21 +404,18 @@
 
 string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
   CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
-  return l10n_util::GetStringFUTF16(
-        IDS_EXTENSION_RATING_COUNT,
-        UTF8ToUTF16(base::IntToString(rating_count_)));
+  return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
+                                    base::IntToString16(rating_count_));
 }
 
 string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
   CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
 
   if (show_user_count_) {
-    return l10n_util::GetStringFUTF16(
-        IDS_EXTENSION_USER_COUNT,
-        UTF8ToUTF16(localized_user_count_));
-  } else {
-    return string16();
+    return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
+                                      base::UTF8ToUTF16(localized_user_count_));
   }
+  return base::string16();
 }
 
 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
@@ -471,7 +468,7 @@
 
 string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index) const {
   CHECK_LT(index, retained_files_.size());
-  return base::UTF8ToUTF16(retained_files_[index].AsUTF8Unsafe());
+  return retained_files_[index].AsUTF16Unsafe();
 }
 
 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
@@ -631,17 +628,6 @@
   LoadImageIfNeeded();
 }
 
-void ExtensionInstallPrompt::ConfirmDefaultInstallFirstRun(
-    Delegate* delegate,
-    const Extension* extension) {
-  DCHECK(ui_loop_ == base::MessageLoop::current());
-  extension_ = extension;
-  permissions_ = extension->GetActivePermissions();
-  delegate_ = delegate;
-  prompt_.set_type(DEFAULT_INSTALL_FIRST_RUN_PROMPT);
-  LoadImageIfNeeded();
-}
-
 void ExtensionInstallPrompt::ConfirmExternalInstall(
     Delegate* delegate,
     const Extension* extension,
@@ -812,10 +798,10 @@
   switch (prompt_.type()) {
     case PERMISSIONS_PROMPT:
     case RE_ENABLE_PROMPT:
-    case DEFAULT_INSTALL_FIRST_RUN_PROMPT:
     case INLINE_INSTALL_PROMPT:
     case EXTERNAL_INSTALL_PROMPT:
     case INSTALL_PROMPT:
+    case LAUNCH_PROMPT:
     case POST_INSTALL_PERMISSIONS_PROMPT: {
       prompt_.set_extension(extension_);
       prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index c59f97d..35ecc2a 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -60,7 +60,7 @@
     PERMISSIONS_PROMPT,
     EXTERNAL_INSTALL_PROMPT,
     POST_INSTALL_PERMISSIONS_PROMPT,
-    DEFAULT_INSTALL_FIRST_RUN_PROMPT,
+    LAUNCH_PROMPT,
     NUM_PROMPT_TYPES
   };
 
@@ -306,13 +306,6 @@
   virtual void ConfirmReEnable(Delegate* delegate,
                                const extensions::Extension* extension);
 
-  // This is called by the app handler launcher to verify whether the app
-  // should be launched first time. This is declared virtual for testing.
-  //
-  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
-  virtual void ConfirmDefaultInstallFirstRun(Delegate* delegate,
-                               const extensions::Extension* extension);
-
   // This is called by the external install alert UI to verify whether the
   // extension should be enabled (external extensions are installed disabled).
   //
diff --git a/chrome/browser/extensions/extension_keybinding_apitest.cc b/chrome/browser/extensions/extension_keybinding_apitest.cc
index 8028194..4a376f1 100644
--- a/chrome/browser/extensions/extension_keybinding_apitest.cc
+++ b/chrome/browser/extensions/extension_keybinding_apitest.cc
@@ -192,17 +192,31 @@
   }
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_SynthesizedCommand DISABLED_SynthesizedCommand
+#else
+#define MAYBE_SynthesizedCommand SynthesizedCommand
+#endif
+
 // This test validates that the getAll query API function returns registered
 // commands as well as synthesized ones and that inactive commands (like the
 // synthesized ones are in nature) have no shortcuts.
-IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
+IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_SynthesizedCommand) {
   ASSERT_TRUE(test_server()->Start());
   ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_DontOverwriteSystemShortcuts DISABLED_DontOverwriteSystemShortcuts
+#else
+#define MAYBE_DontOverwriteSystemShortcuts DontOverwriteSystemShortcuts
+#endif
+
 // This test validates that an extension cannot request a shortcut that is
 // already in use by Chrome.
-IN_PROC_BROWSER_TEST_F(CommandsApiTest, DontOverwriteSystemShortcuts) {
+IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_DontOverwriteSystemShortcuts) {
   ASSERT_TRUE(test_server()->Start());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 131a743..b47e8ea 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -850,5 +850,50 @@
   EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingUserGesture) {
+  const char kManifest[] = "{"
+                          "  \"name\": \"user_gesture\","
+                          "  \"version\": \"1.0\","
+                          "  \"background\": {"
+                          "    \"scripts\": [\"background.js\"]"
+                          "  },"
+                          "  \"manifest_version\": 2"
+                          "}";
+
+  TestExtensionDir receiver_dir;
+  receiver_dir.WriteManifest(kManifest);
+  receiver_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
+      "chrome.runtime.onMessageExternal.addListener(\n"
+      "    function(msg, sender, reply) {\n"
+      "      reply({result:chrome.test.isProcessingUserGesture()});\n"
+      "    });");
+  const Extension* receiver = LoadExtension(receiver_dir.unpacked_path());
+  ASSERT_TRUE(receiver);
+
+  TestExtensionDir sender_dir;
+  sender_dir.WriteManifest(kManifest);
+  sender_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "");
+  const Extension* sender = LoadExtension(sender_dir.unpacked_path());
+  ASSERT_TRUE(sender);
+
+  EXPECT_EQ("false",
+      ExecuteScriptInBackgroundPage(sender->id(),
+                                    base::StringPrintf(
+          "chrome.test.runWithoutUserGesture(function() {\n"
+          "  chrome.runtime.sendMessage('%s', {}, function(response)  {\n"
+          "    window.domAutomationController.send('' + response.result);\n"
+          "  });\n"
+          "});", receiver->id().c_str())));
+
+  EXPECT_EQ("true",
+      ExecuteScriptInBackgroundPage(sender->id(),
+                                    base::StringPrintf(
+          "chrome.test.runWithUserGesture(function() {\n"
+          "  chrome.runtime.sendMessage('%s', {}, function(response)  {\n"
+          "    window.domAutomationController.send('' + response.result);\n"
+          "  });\n"
+          "});", receiver->id().c_str())));
+}
+
 }  // namespace
 };  // namespace extensions
diff --git a/chrome/browser/extensions/extension_notification_observer.cc b/chrome/browser/extensions/extension_notification_observer.cc
index 7f5baf9..b06c0bb 100644
--- a/chrome/browser/extensions/extension_notification_observer.cc
+++ b/chrome/browser/extensions/extension_notification_observer.cc
@@ -116,7 +116,7 @@
         notifications_.push_back(static_cast<chrome::NotificationType>(type));
         // The only way that extensions are unloaded in these tests is
         // by blacklisting.
-        EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST,
+        EXPECT_EQ(UnloadedExtensionInfo::REASON_BLACKLIST,
                   reason->reason);
       }
       break;
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index e25602d..13a330d 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -3,10 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_web_ui.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/extensions/extension_pref_value_map_factory.cc b/chrome/browser/extensions/extension_pref_value_map_factory.cc
index 20966a7..fdc9c5c 100644
--- a/chrome/browser/extensions/extension_pref_value_map_factory.cc
+++ b/chrome/browser/extensions/extension_pref_value_map_factory.cc
@@ -18,10 +18,10 @@
 }
 
 // static
-ExtensionPrefValueMap* ExtensionPrefValueMapFactory::GetForProfile(
-    Profile* profile) {
+ExtensionPrefValueMap* ExtensionPrefValueMapFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
   return static_cast<ExtensionPrefValueMap*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
+      GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
 // static
@@ -31,6 +31,6 @@
 
 BrowserContextKeyedService*
 ExtensionPrefValueMapFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
+    content::BrowserContext* context) const {
   return new ExtensionPrefValueMap();
 }
diff --git a/chrome/browser/extensions/extension_pref_value_map_factory.h b/chrome/browser/extensions/extension_pref_value_map_factory.h
index 8f6f194..5aefc38 100644
--- a/chrome/browser/extensions/extension_pref_value_map_factory.h
+++ b/chrome/browser/extensions/extension_pref_value_map_factory.h
@@ -11,9 +11,11 @@
 class ExtensionPrefValueMap;
 class Profile;
 
+// The usual factory boilerplate for ExtensionPrefValueMap.
 class ExtensionPrefValueMapFactory : public BrowserContextKeyedServiceFactory {
  public:
-  static ExtensionPrefValueMap* GetForProfile(Profile* profile);
+  static ExtensionPrefValueMap* GetForBrowserContext(
+      content::BrowserContext* context);
 
   static ExtensionPrefValueMapFactory* GetInstance();
 
@@ -24,7 +26,7 @@
   virtual ~ExtensionPrefValueMapFactory();
 
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const OVERRIDE;
+      content::BrowserContext* context) const OVERRIDE;
 };
 
 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_VALUE_MAP_FACTORY_H_
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index cc04550..93c43b2 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -24,13 +24,13 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/user_script.h"
@@ -1852,7 +1852,7 @@
   extension_dict->Set(kPrefInstallTime,
                       new base::StringValue(
                           base::Int64ToString(install_time.ToInternalValue())));
-  if (blacklist_state == Blacklist::BLACKLISTED)
+  if (blacklist_state == Blacklist::BLACKLISTED_MALWARE)
     extension_dict->Set(kPrefBlacklist, new base::FundamentalValue(true));
 
   base::FilePath::StringType path = MakePathRelative(install_directory_,
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index a079c0e..c549cfa 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -11,12 +11,13 @@
 
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/blacklist.h"
 #include "chrome/browser/extensions/extension_scoped_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "extensions/common/url_pattern_set.h"
 #include "sync/api/string_ordinal.h"
diff --git a/chrome/browser/extensions/extension_prefs_factory.cc b/chrome/browser/extensions/extension_prefs_factory.cc
index 9b8a2d4..c158a12 100644
--- a/chrome/browser/extensions/extension_prefs_factory.cc
+++ b/chrome/browser/extensions/extension_prefs_factory.cc
@@ -52,7 +52,7 @@
   return ExtensionPrefs::Create(
       profile->GetPrefs(),
       profile->GetPath().AppendASCII(extensions::kInstallDirectoryName),
-      ExtensionPrefValueMapFactory::GetForProfile(profile),
+      ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
       extensions_disabled);
 }
 
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 4d7cc5e..9f68634 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/path_service.h"
 #include "base/prefs/mock_pref_change_callback.h"
 #include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -16,14 +17,13 @@
 #include "chrome/browser/extensions/extension_pref_value_map.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/test/mock_notification_observer.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "sync/api/string_ordinal.h"
 
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 300ac1d..e323cd5 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -234,7 +234,7 @@
 
   // And then test it with the extension disabled.
   extension_info_map_->RemoveExtension(extension->id(),
-                                       extension_misc::UNLOAD_REASON_DISABLE);
+                                       UnloadedExtensionInfo::REASON_DISABLE);
   {
     net::URLRequest request(extension->GetResourceURL("webstore_icon_16.png"),
                             &test_delegate_,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c560220..2db9801 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -35,7 +35,6 @@
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/api/storage/settings_frontend.h"
-#include "chrome/browser/extensions/app_sync_data.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/data_deleter.h"
@@ -48,7 +47,7 @@
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_sorting.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
-#include "chrome/browser/extensions/extension_sync_data.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/external_install_ui.h"
@@ -63,7 +62,6 @@
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/sync/sync_prefs.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
@@ -83,7 +81,6 @@
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
-#include "chrome/common/extensions/sync_helper.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/startup_metric_utils/startup_metric_utils.h"
@@ -97,13 +94,12 @@
 #include "content/public/browser/url_data_source.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/permission_message_provider.h"
 #include "grit/generated_resources.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_error_factory.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "url/gurl.h"
 #include "webkit/browser/database/database_tracker.h"
@@ -327,6 +323,7 @@
       extension_prefs_(extension_prefs),
       blacklist_(blacklist),
       settings_frontend_(extensions::SettingsFrontend::Create(profile)),
+      extension_sync_service_(NULL),
       pending_extension_manager_(*this),
       install_directory_(install_directory),
       extensions_enabled_(extensions_enabled),
@@ -338,19 +335,7 @@
       update_once_all_providers_are_ready_(false),
       browser_terminating_(false),
       installs_delayed_for_gc_(false),
-      is_first_run_(false),
-      app_sync_bundle_(this),
-      extension_sync_bundle_(this),
-      pending_app_enables_(
-          make_scoped_ptr(new browser_sync::SyncPrefs(
-              extension_prefs_->pref_service())),
-          &app_sync_bundle_,
-          syncer::APPS),
-      pending_extension_enables_(
-          make_scoped_ptr(new browser_sync::SyncPrefs(
-              extension_prefs_->pref_service())),
-          &extension_sync_bundle_,
-          syncer::EXTENSIONS) {
+      is_first_run_(false) {
 #if defined(OS_CHROMEOS)
   disable_garbage_collection_ = false;
 #endif
@@ -409,8 +394,6 @@
 
   // Set this as the ExtensionService for extension sorting to ensure it
   // cause syncs if required.
-  extension_prefs_->extension_sorting()->SetExtensionService(this);
-
   is_first_run_ = !extension_prefs_->SetAlertSystemFirstRun();
 
 #if defined(ENABLE_EXTENSIONS)
@@ -472,11 +455,6 @@
   }
 }
 
-void ExtensionService::SetSyncStartFlare(
-    const syncer::SyncableService::StartSyncFlare& flare) {
-  flare_ = flare;
-}
-
 void ExtensionService::Shutdown() {
   system_->management_policy()->UnregisterProvider(
       shared_module_policy_provider_.get());
@@ -683,9 +661,6 @@
   if (extension && extension->was_installed_by_default())
     creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT;
 
-  if (extension && extension->requires_permissions_consent())
-    creation_flags |= Extension::REQUIRE_PERMISSIONS_CONSENT;
-
   installer->set_creation_flags(creation_flags);
 
   installer->set_delete_source(true);
@@ -794,23 +769,10 @@
     return false;
   }
 
-  // Extract the data we need for sync now, but don't actually sync until we've
-  // completed the uninstallation.
-  // TODO(tim): If we get here and IsSyncing is false, this will cause
-  // "back from the dead" style bugs, because sync will add-back the extension
-  // that was uninstalled here when MergeDataAndStartSyncing is called.
-  // See crbug.com/256795.
   syncer::SyncChange sync_change;
-  if (extensions::sync_helper::IsSyncableApp(extension.get())) {
-    if (app_sync_bundle_.IsSyncing())
-      sync_change = app_sync_bundle_.CreateSyncChangeToDelete(extension.get());
-    else if (is_ready() && !flare_.is_null())
-      flare_.Run(syncer::APPS);  // Tell sync to start ASAP.
-  } else if (extensions::sync_helper::IsSyncableExtension(extension.get())) {
-    if (extension_sync_bundle_.IsSyncing())
-      sync_change = extension_sync_bundle_.CreateSyncChangeToDelete(extension);
-    else if (is_ready() && !flare_.is_null())
-      flare_.Run(syncer::EXTENSIONS);  // Tell sync to start ASAP.
+  if (extension_sync_service_) {
+     sync_change = extension_sync_service_->PrepareToSyncUninstallExtension(
+        extension.get(), is_ready());
   }
 
   if (IsUnacknowledgedExternalExtension(extension.get())) {
@@ -834,7 +796,7 @@
 
   // Unload before doing more cleanup to ensure that nothing is hanging on to
   // any of these resources.
-  UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
+  UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_UNINSTALL);
 
   // Tell the backend to start deleting installed extensions on the file thread.
   if (!Manifest::IsUnpackedLocation(extension->location())) {
@@ -877,12 +839,9 @@
       content::Source<Profile>(profile_),
       content::Details<const Extension>(extension.get()));
 
-  if (app_sync_bundle_.HasExtensionId(extension_id) &&
-      sync_change.sync_data().GetDataType() == syncer::APPS) {
-    app_sync_bundle_.ProcessDeletion(extension_id, sync_change);
-  } else if (extension_sync_bundle_.HasExtensionId(extension_id) &&
-             sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) {
-    extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
+  if (extension_sync_service_) {
+    extension_sync_service_->ProcessSyncUninstallExtension(extension_id,
+                                                           sync_change);
   }
 
   delayed_installs_.Remove(extension_id);
@@ -927,13 +886,6 @@
       !GetTerminatedExtension(extension_id);
 }
 
-bool ExtensionService::DoesExtensionRequirePermissionConsent(
-      const std::string& extension_id) const {
-  return extension_prefs_->IsExtensionDisabled(extension_id) &&
-      (extension_prefs_->GetDisableReasons(extension_id) &
-          Extension::DISABLE_PERMISSIONS_CONSENT);
-}
-
 void ExtensionService::EnableExtension(const std::string& extension_id) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -967,8 +919,7 @@
 
   // Move it over to the enabled list.
   extensions_.Insert(make_scoped_refptr(extension));
-  if (disabled_extensions_.Remove(extension->id()))
-    extension_prefs_->SetKnownDisabled(disabled_extensions_.GetIDs());
+  disabled_extensions_.Remove(extension->id());
 
   NotifyExtensionLoaded(extension);
 
@@ -978,14 +929,8 @@
       content::Source<Profile>(profile_),
       content::Details<const Extension>(extension));
 
-  // Syncing may not have started yet, so handle pending enables.
-  if (extensions::sync_helper::IsSyncableApp(extension))
-    pending_app_enables_.OnExtensionEnabled(extension->id());
-
-  if (extensions::sync_helper::IsSyncableExtension(extension))
-    pending_extension_enables_.OnExtensionEnabled(extension->id());
-
-  SyncExtensionChangeIfNeeded(*extension);
+  if (extension_sync_service_)
+    extension_sync_service_->SyncEnableExtension(*extension);
 }
 
 void ExtensionService::DisableExtension(
@@ -1020,23 +965,16 @@
 
   // Move it over to the disabled list. Don't send a second unload notification
   // for terminated extensions being disabled.
-  if (disabled_extensions_.Insert(make_scoped_refptr(extension)))
-    extension_prefs_->SetKnownDisabled(disabled_extensions_.GetIDs());
+  disabled_extensions_.Insert(make_scoped_refptr(extension));
   if (extensions_.Contains(extension->id())) {
     extensions_.Remove(extension->id());
-    NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE);
+    NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::REASON_DISABLE);
   } else {
     terminated_extensions_.Remove(extension->id());
   }
 
-  // Syncing may not have started yet, so handle pending enables.
-  if (extensions::sync_helper::IsSyncableApp(extension))
-    pending_app_enables_.OnExtensionDisabled(extension->id());
-
-  if (extensions::sync_helper::IsSyncableExtension(extension))
-    pending_extension_enables_.OnExtensionDisabled(extension->id());
-
-  SyncExtensionChangeIfNeeded(*extension);
+  if (extension_sync_service_)
+    extension_sync_service_->SyncDisableExtension(*extension);
 }
 
 void ExtensionService::DisableUserExtensions(
@@ -1183,7 +1121,7 @@
 
 void ExtensionService::NotifyExtensionUnloaded(
     const Extension* extension,
-    extension_misc::UnloadedExtensionReason reason) {
+    UnloadedExtensionInfo::Reason reason) {
   UnloadedExtensionInfo details(extension, reason);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
@@ -1280,7 +1218,7 @@
   // UnloadExtension will change the extensions_ list. So, we should
   // call it outside the iterator loop.
   for (size_t i = 0; i < to_be_removed.size(); ++i)
-    UnloadExtension(to_be_removed[i], extension_misc::UNLOAD_REASON_DISABLE);
+    UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::REASON_DISABLE);
 }
 
 void ExtensionService::CheckForUpdatesSoon() {
@@ -1298,301 +1236,6 @@
   }
 }
 
-syncer::SyncMergeResult ExtensionService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
-  CHECK(sync_processor.get());
-  CHECK(sync_error_factory.get());
-
-  switch (type) {
-    case syncer::EXTENSIONS:
-      extension_sync_bundle_.SetupSync(sync_processor.release(),
-                                       sync_error_factory.release(),
-                                       initial_sync_data);
-      pending_extension_enables_.OnSyncStarted(this);
-      break;
-
-    case syncer::APPS:
-      app_sync_bundle_.SetupSync(sync_processor.release(),
-                                 sync_error_factory.release(),
-                                 initial_sync_data);
-      pending_app_enables_.OnSyncStarted(this);
-      break;
-
-    default:
-      LOG(FATAL) << "Got " << type << " ModelType";
-  }
-
-  // Process local extensions.
-  // TODO(yoz): Determine whether pending extensions should be considered too.
-  //            See crbug.com/104399.
-  syncer::SyncDataList sync_data_list = GetAllSyncData(type);
-  syncer::SyncChangeList sync_change_list;
-  for (syncer::SyncDataList::const_iterator i = sync_data_list.begin();
-       i != sync_data_list.end();
-       ++i) {
-    switch (type) {
-        case syncer::EXTENSIONS:
-          sync_change_list.push_back(
-              extension_sync_bundle_.CreateSyncChange(*i));
-          break;
-        case syncer::APPS:
-          sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i));
-          break;
-      default:
-        LOG(FATAL) << "Got " << type << " ModelType";
-    }
-  }
-
-
-  if (type == syncer::EXTENSIONS) {
-    extension_sync_bundle_.ProcessSyncChangeList(sync_change_list);
-  } else if (type == syncer::APPS) {
-    app_sync_bundle_.ProcessSyncChangeList(sync_change_list);
-  }
-
-  return syncer::SyncMergeResult(type);
-}
-
-void ExtensionService::StopSyncing(syncer::ModelType type) {
-  if (type == syncer::APPS) {
-    app_sync_bundle_.Reset();
-  } else if (type == syncer::EXTENSIONS) {
-    extension_sync_bundle_.Reset();
-  }
-}
-
-syncer::SyncDataList ExtensionService::GetAllSyncData(
-    syncer::ModelType type) const {
-  if (type == syncer::EXTENSIONS)
-    return extension_sync_bundle_.GetAllSyncData();
-  if (type == syncer::APPS)
-    return app_sync_bundle_.GetAllSyncData();
-
-  // We should only get sync data for extensions and apps.
-  NOTREACHED();
-
-  return syncer::SyncDataList();
-}
-
-syncer::SyncError ExtensionService::ProcessSyncChanges(
-    const tracked_objects::Location& from_here,
-    const syncer::SyncChangeList& change_list) {
-  for (syncer::SyncChangeList::const_iterator i = change_list.begin();
-      i != change_list.end();
-      ++i) {
-    syncer::ModelType type = i->sync_data().GetDataType();
-    if (type == syncer::EXTENSIONS) {
-      extension_sync_bundle_.ProcessSyncChange(
-          extensions::ExtensionSyncData(*i));
-    } else if (type == syncer::APPS) {
-      app_sync_bundle_.ProcessSyncChange(extensions::AppSyncData(*i));
-    }
-  }
-
-  extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions();
-
-  return syncer::SyncError();
-}
-
-extensions::ExtensionSyncData ExtensionService::GetExtensionSyncData(
-    const Extension& extension) const {
-  return extensions::ExtensionSyncData(
-      extension,
-      IsExtensionEnabled(extension.id()),
-      extension_util::IsIncognitoEnabled(extension.id(), this));
-}
-
-extensions::AppSyncData ExtensionService::GetAppSyncData(
-    const Extension& extension) const {
-  return extensions::AppSyncData(
-      extension,
-      IsExtensionEnabled(extension.id()),
-      extension_util::IsIncognitoEnabled(extension.id(), this),
-      extension_prefs_->extension_sorting()->GetAppLaunchOrdinal(
-          extension.id()),
-      extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id()));
-}
-
-std::vector<extensions::ExtensionSyncData>
-  ExtensionService::GetExtensionSyncDataList() const {
-  std::vector<extensions::ExtensionSyncData> extension_sync_list;
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(extensions_,
-                                                        &extension_sync_list);
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(disabled_extensions_,
-                                                        &extension_sync_list);
-  extension_sync_bundle_.GetExtensionSyncDataListHelper(terminated_extensions_,
-                                                        &extension_sync_list);
-
-  std::vector<extensions::ExtensionSyncData> pending_extensions =
-      extension_sync_bundle_.GetPendingData();
-  extension_sync_list.insert(extension_sync_list.begin(),
-                             pending_extensions.begin(),
-                             pending_extensions.end());
-
-  return extension_sync_list;
-}
-
-std::vector<extensions::AppSyncData> ExtensionService::GetAppSyncDataList()
-    const {
-  std::vector<extensions::AppSyncData> app_sync_list;
-  app_sync_bundle_.GetAppSyncDataListHelper(extensions_, &app_sync_list);
-  app_sync_bundle_.GetAppSyncDataListHelper(disabled_extensions_,
-                                            &app_sync_list);
-  app_sync_bundle_.GetAppSyncDataListHelper(terminated_extensions_,
-                                            &app_sync_list);
-
-  std::vector<extensions::AppSyncData> pending_apps =
-      app_sync_bundle_.GetPendingData();
-  app_sync_list.insert(app_sync_list.begin(),
-                       pending_apps.begin(),
-                       pending_apps.end());
-
-  return app_sync_list;
-}
-
-bool ExtensionService::ProcessExtensionSyncData(
-    const extensions::ExtensionSyncData& extension_sync_data) {
-  if (!ProcessExtensionSyncDataHelper(extension_sync_data,
-                                      syncer::EXTENSIONS)) {
-    extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(),
-                                               extension_sync_data);
-    CheckForUpdatesSoon();
-    return false;
-  }
-
-  return true;
-}
-
-bool ExtensionService::ProcessAppSyncData(
-    const extensions::AppSyncData& app_sync_data) {
-  const std::string& id = app_sync_data.id();
-
-  if (app_sync_data.app_launch_ordinal().IsValid() &&
-      app_sync_data.page_ordinal().IsValid()) {
-    extension_prefs_->extension_sorting()->SetAppLaunchOrdinal(
-        id,
-        app_sync_data.app_launch_ordinal());
-    extension_prefs_->extension_sorting()->SetPageOrdinal(
-        id,
-        app_sync_data.page_ordinal());
-  }
-
-  if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(),
-                                      syncer::APPS)) {
-    app_sync_bundle_.AddPendingApp(id, app_sync_data);
-    CheckForUpdatesSoon();
-    return false;
-  }
-
-  return true;
-}
-
-bool ExtensionService::IsCorrectSyncType(const Extension& extension,
-                                         syncer::ModelType type) const {
-  if (type == syncer::EXTENSIONS &&
-      extensions::sync_helper::IsSyncableExtension(&extension)) {
-    return true;
-  }
-
-  if (type == syncer::APPS &&
-      extensions::sync_helper::IsSyncableApp(&extension)) {
-    return true;
-  }
-
-  return false;
-}
-
-bool ExtensionService::IsPendingEnable(const std::string& extension_id) const {
-  return pending_app_enables_.Contains(extension_id) ||
-      pending_extension_enables_.Contains(extension_id);
-}
-
-bool ExtensionService::ProcessExtensionSyncDataHelper(
-    const extensions::ExtensionSyncData& extension_sync_data,
-    syncer::ModelType type) {
-  const std::string& id = extension_sync_data.id();
-  const Extension* extension = GetInstalledExtension(id);
-
-  // TODO(bolms): we should really handle this better.  The particularly bad
-  // case is where an app becomes an extension or vice versa, and we end up with
-  // a zombie extension that won't go away.
-  if (extension && !IsCorrectSyncType(*extension, type))
-    return true;
-
-  // Handle uninstalls first.
-  if (extension_sync_data.uninstalled()) {
-    if (!UninstallExtensionHelper(this, id)) {
-      LOG(WARNING) << "Could not uninstall extension " << id
-                   << " for sync";
-    }
-    return true;
-  }
-
-  // Extension from sync was uninstalled by the user as external extensions.
-  // Honor user choice and skip installation/enabling.
-  if (IsExternalExtensionUninstalled(id)) {
-    LOG(WARNING) << "Extension with id " << id
-                 << " from sync was uninstalled as external extension";
-    return true;
-  }
-
-  // Set user settings.
-  // If the extension has been disabled from sync, it may not have
-  // been installed yet, so we don't know if the disable reason was a
-  // permissions increase.  That will be updated once CheckPermissionsIncrease
-  // is called for it.
-  if (extension_sync_data.enabled())
-    EnableExtension(id);
-  else if (!IsPendingEnable(id))
-    DisableExtension(id, Extension::DISABLE_UNKNOWN_FROM_SYNC);
-
-  // We need to cache some version information here because setting the
-  // incognito flag invalidates the |extension| pointer (it reloads the
-  // extension).
-  bool extension_installed = (extension != NULL);
-  int result = extension ?
-      extension->version()->CompareTo(extension_sync_data.version()) : 0;
-  extension_util::SetIsIncognitoEnabled(
-      id, this, extension_sync_data.incognito_enabled());
-  extension = NULL;  // No longer safe to use.
-
-  if (extension_installed) {
-    // If the extension is already installed, check if it's outdated.
-    if (result < 0) {
-      // Extension is outdated.
-      return false;
-    }
-  } else {
-    // TODO(akalin): Replace silent update with a list of enabled
-    // permissions.
-    const bool kInstallSilently = true;
-
-    CHECK(type == syncer::EXTENSIONS || type == syncer::APPS);
-    extensions::PendingExtensionInfo::ShouldAllowInstallPredicate filter =
-        (type == syncer::APPS) ? extensions::sync_helper::IsSyncableApp :
-                                 extensions::sync_helper::IsSyncableExtension;
-
-    if (!pending_extension_manager()->AddFromSync(
-            id,
-            extension_sync_data.update_url(),
-            filter,
-            kInstallSilently)) {
-      LOG(WARNING) << "Could not add pending extension for " << id;
-      // This means that the extension is already pending installation, with a
-      // non-INTERNAL location.  Add to pending_sync_data, even though it will
-      // never be removed (we'll never install a syncable version of the
-      // extension), so that GetAllSyncData() continues to send it.
-    }
-    // Track pending extensions so that we can return them in GetAllSyncData().
-    return false;
-  }
-
-  return true;
-}
-
 void ExtensionService::OnExtensionMoved(
     const std::string& moved_extension_id,
     const std::string& predecessor_extension_id,
@@ -1603,8 +1246,9 @@
       successor_extension_id);
 
   const Extension* extension = GetInstalledExtension(moved_extension_id);
-  if (extension)
-    SyncExtensionChangeIfNeeded(*extension);
+  if (extension_sync_service_ && extension) {
+    extension_sync_service_->SyncExtensionChangeIfNeeded(*extension);
+  }
 }
 
 // Some extensions will autoupdate themselves externally from Chrome.  These
@@ -1806,6 +1450,12 @@
     UMA_HISTOGRAM_COUNTS_100("Extensions.KnownDisabledReDisabled",
                              known_disabled_count);
   }
+
+  // Update the list of known disabled to reflect every change to
+  // |disabled_extensions_| from this point forward.
+  disabled_extensions_.set_modification_callback(
+      base::Bind(&extensions::ExtensionPrefs::SetKnownDisabled,
+                 base::Unretained(extension_prefs_)));
 }
 
 void ExtensionService::HandleExtensionAlertDetails() {
@@ -1869,7 +1519,7 @@
 
 void ExtensionService::UnloadExtension(
     const std::string& extension_id,
-    extension_misc::UnloadedExtensionReason reason) {
+    UnloadedExtensionInfo::Reason reason) {
   // Make sure the extension gets deleted after we return from this function.
   int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_TERMINATED;
   scoped_refptr<const Extension> extension(
@@ -1885,7 +1535,7 @@
   }
 
   // If uninstalling let RuntimeEventRouter know.
-  if (reason == extension_misc::UNLOAD_REASON_UNINSTALL)
+  if (reason == UnloadedExtensionInfo::REASON_UNINSTALL)
     extensions::RuntimeEventRouter::OnExtensionUninstalled(
         profile_, extension_id);
 
@@ -1921,7 +1571,7 @@
     const std::string& extension_id) {
   scoped_refptr<const Extension> extension(
       GetExtensionById(extension_id, false));
-  UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
+  UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_UNINSTALL);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
       content::Source<Profile>(profile_),
@@ -1992,20 +1642,6 @@
   }
 }
 
-void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
-  if (extensions::sync_helper::IsSyncableApp(&extension)) {
-    if (app_sync_bundle_.IsSyncing())
-      app_sync_bundle_.SyncChangeIfNeeded(extension);
-    else if (is_ready() && !flare_.is_null())
-      flare_.Run(syncer::APPS);
-  } else if (extensions::sync_helper::IsSyncableExtension(&extension)) {
-    if (extension_sync_bundle_.IsSyncing())
-      extension_sync_bundle_.SyncChangeIfNeeded(extension);
-    else if (is_ready() && !flare_.is_null())
-      flare_.Run(syncer::EXTENSIONS);
-  }
-}
-
 void ExtensionService::SetReadyAndNotifyListeners() {
   ready_->Signal();
   content::NotificationService::current()->Notify(
@@ -2063,7 +1699,7 @@
   if (is_extension_installed && !reloading) {
     // To upgrade an extension in place, unload the old one and then load the
     // new one.  ReloadExtension disables the extension, which is sufficient.
-    UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_UPDATE);
+    UnloadExtension(extension->id(), UnloadedExtensionInfo::REASON_UPDATE);
   }
 
   if (extension_prefs_->IsExtensionBlacklisted(extension->id())) {
@@ -2075,7 +1711,8 @@
   } else if (!reloading &&
              extension_prefs_->IsExtensionDisabled(extension->id())) {
     disabled_extensions_.Insert(extension);
-    SyncExtensionChangeIfNeeded(*extension);
+    if (extension_sync_service_)
+      extension_sync_service_->SyncExtensionChangeIfNeeded(*extension);
     content::NotificationService::current()->Notify(
         chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
         content::Source<Profile>(profile_),
@@ -2104,7 +1741,8 @@
     }
 
     extensions_.Insert(extension);
-    SyncExtensionChangeIfNeeded(*extension);
+    if (extension_sync_service_)
+      extension_sync_service_->SyncExtensionChangeIfNeeded(*extension);
     NotifyExtensionLoaded(extension);
   }
   SetBeingUpgraded(extension, false);
@@ -2190,8 +1828,7 @@
   int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
 
   bool auto_grant_permission =
-      (!is_extension_installed && extension->was_installed_by_default() &&
-       !extension->requires_permissions_consent()) ||
+      (!is_extension_installed && extension->was_installed_by_default()) ||
       chrome::IsRunningInForcedAppMode();
   // Silently grant all active permissions to default apps only on install.
   // After install they should behave like other apps.
@@ -2235,6 +1872,7 @@
     }
     // Extensions that came to us disabled from sync need a similar inference,
     // except based on the new version's permissions.
+    // TODO(yoz): Since we no longer sync disabled state, simplify this.
     if (previously_disabled &&
         disable_reasons == Extension::DISABLE_UNKNOWN_FROM_SYNC) {
       // Remove the DISABLE_UNKNOWN_FROM_SYNC reason.
@@ -2243,9 +1881,6 @@
         disable_reasons |= Extension::DISABLE_USER_ACTION;
     }
     disable_reasons &= ~Extension::DISABLE_UNKNOWN_FROM_SYNC;
-  } else if (extension->requires_permissions_consent()) {
-    disable_reasons |= Extension::DISABLE_PERMISSIONS_CONSENT;
-    extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
   }
 
   // Extension has changed permissions significantly. Disable it. A
@@ -2256,8 +1891,7 @@
       RecordPermissionMessagesHistogram(
           extension, "Extensions.Permissions_AutoDisable");
     }
-    DisableExtension(extension->id(),
-                     static_cast<Extension::DisableReason>(disable_reasons));
+    extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
     extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
   }
   if (disable_reasons != Extension::DISABLE_NONE) {
@@ -2433,7 +2067,7 @@
     extension_prefs_->ClearDisableReasons(id);
   }
 
-  if (blacklist_state == extensions::Blacklist::BLACKLISTED) {
+  if (blacklist_state == extensions::Blacklist::BLACKLISTED_MALWARE) {
     // Installation of a blacklisted extension can happen from sync, policy,
     // etc, where to maintain consistency we need to install it, just never
     // load it (see AddExtension). Usually it should be the job of callers to
@@ -2635,7 +2269,7 @@
   if (!terminated_extensions_.Contains(extension->id()))
     terminated_extensions_.Insert(make_scoped_refptr(extension));
 
-  UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE);
+  UnloadExtension(extension->id(), UnloadedExtensionInfo::REASON_TERMINATE);
 }
 
 void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
@@ -2842,7 +2476,7 @@
       // Scripting whitelist. This is modified by tests and must be communicated
       // to renderers.
       process->Send(new ExtensionMsg_SetScriptingWhitelist(
-          *Extension::GetScriptingWhitelist()));
+          extensions::ExtensionsClient::Get()->GetScriptingWhitelist()));
 
       // Loaded extensions.
       std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
@@ -3079,7 +2713,7 @@
 }
 
 void ExtensionService::OnBlacklistUpdated() {
-  blacklist_->GetBlacklistedIDs(
+  blacklist_->GetMalwareIDs(
       GenerateInstalledExtensionsSet()->GetIDs(),
       base::Bind(&ExtensionService::ManageBlacklist, AsWeakPtr()));
 }
@@ -3120,7 +2754,7 @@
     }
     blacklisted_extensions_.Insert(extension);
     extension_prefs_->SetExtensionBlacklisted(extension->id(), true);
-    UnloadExtension(*it, extension_misc::UNLOAD_REASON_BLACKLIST);
+    UnloadExtension(*it, UnloadedExtensionInfo::REASON_BLACKLIST);
     UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlacklistInstalled",
                               extension->location(), Manifest::NUM_LOCATIONS);
   }
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index e9e7cba..39d641d 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -18,13 +18,12 @@
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/extensions/app_sync_bundle.h"
 #include "chrome/browser/extensions/blacklist.h"
 #include "chrome/browser/extensions/extension_function_histogram_value.h"
 #include "chrome/browser/extensions/extension_icon_manager.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_sync_bundle.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/extension_toolbar_model.h"
 #include "chrome/browser/extensions/extensions_quota_service.h"
 #include "chrome/browser/extensions/external_provider_interface.h"
@@ -43,13 +42,9 @@
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/one_shot_event.h"
-#include "sync/api/string_ordinal.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/syncable_service.h"
 
 class CommandLine;
 class ExtensionErrorUI;
-class ExtensionSyncData;
 class ExtensionToolbarModel;
 class GURL;
 class Profile;
@@ -60,13 +55,11 @@
 }
 
 namespace extensions {
-class AppSyncData;
 class BrowserEventRouter;
 class ComponentLoader;
 class ContentSettingsStore;
 class CrxInstaller;
 class ExtensionActionStorageManager;
-class ExtensionSyncData;
 class ExtensionSystem;
 class ExtensionUpdater;
 class PendingExtensionManager;
@@ -79,7 +72,8 @@
 
 // This is an interface class to encapsulate the dependencies that
 // various classes have on ExtensionService. This allows easy mocking.
-class ExtensionServiceInterface : public syncer::SyncableService {
+class ExtensionServiceInterface
+    : public base::SupportsWeakPtr<ExtensionServiceInterface> {
  public:
   virtual ~ExtensionServiceInterface() {}
   virtual const ExtensionSet* extensions() const = 0;
@@ -121,12 +115,9 @@
 
   virtual void UnloadExtension(
       const std::string& extension_id,
-      extension_misc::UnloadedExtensionReason reason) = 0;
+      extensions::UnloadedExtensionInfo::Reason reason) = 0;
   virtual void RemoveComponentExtension(const std::string& extension_id) = 0;
 
-  virtual void SyncExtensionChangeIfNeeded(
-      const extensions::Extension& extension) = 0;
-
   virtual bool is_ready() = 0;
 
   // Returns task runner for crx installation file I/O operations.
@@ -288,14 +279,9 @@
   virtual bool IsExternalExtensionUninstalled(
       const std::string& extension_id) const OVERRIDE;
 
-  // Whether the extension should be enabled for running.
+  // Whether the extension should show as enabled state in launcher.
   bool IsExtensionEnabledForLauncher(const std::string& extension_id) const;
 
-  // Whether the extension is waiting for permission consent. Such extensions
-  // technically disabled (can't be launched) but UI shows them as normal.
-  bool DoesExtensionRequirePermissionConsent(
-      const std::string& extension_id) const;
-
   // Enables the extension.  If the extension is already enabled, does
   // nothing.
   virtual void EnableExtension(const std::string& extension_id);
@@ -327,7 +313,7 @@
   // Unload the specified extension.
   virtual void UnloadExtension(
       const std::string& extension_id,
-      extension_misc::UnloadedExtensionReason reason) OVERRIDE;
+      extensions::UnloadedExtensionInfo::Reason reason) OVERRIDE;
 
   // Remove the specified component extension.
   virtual void RemoveComponentExtension(const std::string& extension_id)
@@ -343,11 +329,6 @@
   // Scan the extension directory and clean up the cruft.
   void GarbageCollectExtensions();
 
-  // Notifies Sync (if needed) of a newly-installed extension or a change to
-  // an existing extension.
-  virtual void SyncExtensionChangeIfNeeded(
-      const extensions::Extension& extension) OVERRIDE;
-
   // Returns true if |url| should get extension api bindings and be permitted
   // to make api calls. Note that this is independent of what extension
   // permissions the given extension has been granted.
@@ -435,44 +416,6 @@
 
   virtual void CheckForUpdatesSoon() OVERRIDE;
 
-  // syncer::SyncableService implementation.
-  virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-      scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) OVERRIDE;
-  virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
-  virtual syncer::SyncDataList GetAllSyncData(
-      syncer::ModelType type) const OVERRIDE;
-  virtual syncer::SyncError ProcessSyncChanges(
-      const tracked_objects::Location& from_here,
-      const syncer::SyncChangeList& change_list) OVERRIDE;
-
-  // Gets the sync data for the given extension, assuming that the extension is
-  // syncable.
-  extensions::ExtensionSyncData GetExtensionSyncData(
-      const extensions::Extension& extension) const;
-
-  // Gets the sync data for the given app, assuming that the app is
-  // syncable.
-  extensions::AppSyncData GetAppSyncData(
-      const extensions::Extension& extension) const;
-
-  // Gets the ExtensionSyncData for all extensions.
-  std::vector<extensions::ExtensionSyncData> GetExtensionSyncDataList() const;
-
-  // Gets the AppSyncData for all extensions.
-  std::vector<extensions::AppSyncData> GetAppSyncDataList() const;
-
-  // Applies the change specified passed in by either ExtensionSyncData or
-  // AppSyncData to the current system.
-  // Returns false if the changes were not completely applied and were added
-  // to the pending list to be tried again.
-  bool ProcessExtensionSyncData(
-      const extensions::ExtensionSyncData& extension_sync_data);
-  bool ProcessAppSyncData(const extensions::AppSyncData& app_sync_data);
-
-
   void set_extensions_enabled(bool enabled) { extensions_enabled_ = enabled; }
   bool extensions_enabled() { return extensions_enabled_; }
 
@@ -493,6 +436,11 @@
 
   extensions::SettingsFrontend* settings_frontend();
 
+  void set_extension_sync_service(
+      ExtensionSyncService* extension_sync_service) {
+    extension_sync_service_ = extension_sync_service;
+  }
+
   extensions::ContentSettingsStore* GetContentSettingsStore();
 
   // Whether the extension service is ready.
@@ -631,7 +579,6 @@
   }
 #endif
 
-  // Specialization of syncer::SyncableService::AsWeakPtr.
   base::WeakPtr<ExtensionService> AsWeakPtr() { return base::AsWeakPtr(this); }
 
   bool browser_terminating() const { return browser_terminating_; }
@@ -652,10 +599,6 @@
   void AddUpdateObserver(extensions::UpdateObserver* observer);
   void RemoveUpdateObserver(extensions::UpdateObserver* observer);
 
-  // |flare| provides a StartSyncFlare to the SyncableService. See
-  // sync_start_util for more.
-  void SetSyncStartFlare(const syncer::SyncableService::StartSyncFlare& flare);
-
 #if defined(OS_CHROMEOS)
   void disable_garbage_collection() {
     disable_garbage_collection_ = true;
@@ -687,23 +630,8 @@
   void SetReadyAndNotifyListeners();
 
   // Return true if the sync type of |extension| matches |type|.
-  bool IsCorrectSyncType(const extensions::Extension& extension,
-                         syncer::ModelType type)
-      const;
-
   void OnExtensionInstallPrefChanged();
 
-  // Whether the given extension has been enabled before sync has started.
-  bool IsPendingEnable(const std::string& extension_id) const;
-
-  // Handles setting the extension specific values in |extension_sync_data| to
-  // the current system.
-  // Returns false if the changes were not completely applied and need to be
-  // tried again later.
-  bool ProcessExtensionSyncDataHelper(
-      const extensions::ExtensionSyncData& extension_sync_data,
-      syncer::ModelType type);
-
   // Adds the given extension to the list of terminated extensions if
   // it is not already there and unloads it.
   void TrackTerminatedExtension(const extensions::Extension* extension);
@@ -726,8 +654,9 @@
   void NotifyExtensionLoaded(const extensions::Extension* extension);
 
   // Handles sending notification that |extension| was unloaded.
-  void NotifyExtensionUnloaded(const extensions::Extension* extension,
-                               extension_misc::UnloadedExtensionReason reason);
+  void NotifyExtensionUnloaded(
+      const extensions::Extension* extension,
+      extensions::UnloadedExtensionInfo::Reason reason);
 
   // Common helper to finish installing the given extension.
   void FinishInstallation(const extensions::Extension* extension);
@@ -793,6 +722,9 @@
   // Settings for the owning profile.
   scoped_ptr<extensions::SettingsFrontend> settings_frontend_;
 
+  // The ExtensionSyncService that is used by this ExtensionService.
+  ExtensionSyncService* extension_sync_service_;
+
   // The current list of installed extensions.
   ExtensionSet extensions_;
 
@@ -895,19 +827,12 @@
   // first time.
   bool is_first_run_;
 
-  extensions::AppSyncBundle app_sync_bundle_;
-  extensions::ExtensionSyncBundle extension_sync_bundle_;
-
   extensions::ProcessMap process_map_;
 
   // A set of the extension ids currently being reloaded.  We use this to
   // avoid showing a "new install" notice for an extension reinstall.
   std::set<std::string> extensions_being_reloaded_;
 
-  // Set of extensions/apps that have been enabled before sync has started.
-  extensions::PendingEnables pending_app_enables_;
-  extensions::PendingEnables pending_extension_enables_;
-
   scoped_ptr<ExtensionErrorUI> extension_error_ui_;
   // Sequenced task runner for extension related file operations.
   scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
@@ -921,11 +846,6 @@
 
   ObserverList<extensions::UpdateObserver, true> update_observers_;
 
-  // Run()ning tells sync to try and start soon, because syncable changes
-  // have started happening. It will cause sync to call us back
-  // asynchronously via MergeDataAndStartSyncing as soon as possible.
-  syncer::SyncableService::StartSyncFlare flare_;
-
 #if defined(OS_CHROMEOS)
   // TODO(rkc): HACK alert - this is only in place to allow the
   // kiosk_mode_screensaver to prevent its extension from getting garbage
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index b9e4dce..3d6d94f 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -66,7 +67,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/pref_service_mock_builder.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/chrome_constants.h"
@@ -80,7 +80,6 @@
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/value_builder.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -100,6 +99,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "gpu/config/gpu_info.h"
 #include "grit/browser_resources.h"
@@ -508,6 +508,7 @@
       CommandLine::ForCurrentProcess(),
       params.extensions_install_dir,
       params.autoupdate_enabled);
+
   service_->SetFileTaskRunnerForTesting(
       base::MessageLoopProxy::current().get());
   service_->set_extensions_enabled(true);
@@ -585,6 +586,25 @@
   service_->updater()->Start();
 }
 
+void ExtensionServiceTestBase::InitializeExtensionSyncService() {
+  extension_sync_service_.reset(new ExtensionSyncService(
+      profile_.get(), service_->extension_prefs(), service_));
+}
+
+// static
+void ExtensionServiceTestBase::SetUpTestCase() {
+  ExtensionErrorReporter::Init(false);  // no noisy errors
+}
+
+void ExtensionServiceTestBase::SetUp() {
+  ExtensionErrorReporter::GetInstance()->ClearErrors();
+  content::RenderProcessHost::SetRunRendererInProcess(true);
+}
+
+void ExtensionServiceTestBase::TearDown() {
+  content::RenderProcessHost::SetRunRendererInProcess(false);
+}
+
 ExtensionServiceTestBase::ExtensionServiceInitParams
 ExtensionServiceTestBase::CreateDefaultInitParams() {
   ExtensionServiceInitParams params;
@@ -608,20 +628,6 @@
   return params;
 }
 
-// static
-void ExtensionServiceTestBase::SetUpTestCase() {
-  ExtensionErrorReporter::Init(false);  // no noisy errors
-}
-
-void ExtensionServiceTestBase::SetUp() {
-  ExtensionErrorReporter::GetInstance()->ClearErrors();
-  content::RenderProcessHost::SetRunRendererInProcess(true);
-}
-
-void ExtensionServiceTestBase::TearDown() {
-  content::RenderProcessHost::SetRunRendererInProcess(false);
-}
-
 class ExtensionServiceTest
   : public ExtensionServiceTestBase, public content::NotificationObserver {
  public:
@@ -4942,21 +4948,6 @@
       "  }"
       "}";
   EXPECT_EQ(1, from_webstore_visitor.Visit(json_data));
-
-  // Test require_permissions_consent.
-  MockProviderVisitor permissions_consent_visitor(
-      base_path, Extension::REQUIRE_PERMISSIONS_CONSENT);
-  json_data =
-      "{"
-      "  \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
-      "    \"external_crx\": \"RandomExtension.crx\","
-      "    \"external_version\": \"1.0\","
-      "    \"require_permissions_consent\": true"
-      "  }"
-      "}";
-  {
-    EXPECT_EQ(1, permissions_consent_visitor.Visit(json_data));
-  }
 }
 
 // Test loading good extensions from the profile directory.
@@ -5204,11 +5195,12 @@
 
 TEST_F(ExtensionServiceTest, DeferredSyncStartupPreInstalledComponent) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
 
   bool flare_was_called = false;
   syncer::ModelType triggered_type(syncer::UNSPECIFIED);
   base::WeakPtrFactory<ExtensionServiceTest> factory(this);
-  service_->SetSyncStartFlare(
+  extension_sync_service_->SetSyncStartFlare(
       base::Bind(&ExtensionServiceTest::MockSyncStartFlare,
                  factory.GetWeakPtr(),
                  &flare_was_called,  // Safe due to WeakPtrFactory scope.
@@ -5230,11 +5222,12 @@
 
 TEST_F(ExtensionServiceTest, DeferredSyncStartupPreInstalledNormal) {
   InitializeGoodInstalledExtensionService();
+  InitializeExtensionSyncService();
 
   bool flare_was_called = false;
   syncer::ModelType triggered_type(syncer::UNSPECIFIED);
   base::WeakPtrFactory<ExtensionServiceTest> factory(this);
-  service_->SetSyncStartFlare(
+  extension_sync_service_->SetSyncStartFlare(
       base::Bind(&ExtensionServiceTest::MockSyncStartFlare,
                  factory.GetWeakPtr(),
                  &flare_was_called,  // Safe due to WeakPtrFactory scope.
@@ -5252,13 +5245,14 @@
 
 TEST_F(ExtensionServiceTest, DeferredSyncStartupOnInstall) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   service_->Init();
   ASSERT_TRUE(service_->is_ready());
 
   bool flare_was_called = false;
   syncer::ModelType triggered_type(syncer::UNSPECIFIED);
   base::WeakPtrFactory<ExtensionServiceTest> factory(this);
-  service_->SetSyncStartFlare(
+  extension_sync_service_->SetSyncStartFlare(
       base::Bind(&ExtensionServiceTest::MockSyncStartFlare,
                  factory.GetWeakPtr(),
                  &flare_was_called,  // Safe due to WeakPtrFactory scope.
@@ -5275,7 +5269,7 @@
   triggered_type = syncer::UNSPECIFIED;
 
   // Once sync starts, flare should no longer be invoked.
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5285,106 +5279,24 @@
   ASSERT_EQ(syncer::UNSPECIFIED, triggered_type);
 }
 
-TEST_F(ExtensionServiceTest, DisableExtensionFromSync) {
-  // Start the extensions service with one external extension already installed.
-  base::FilePath source_install_dir = data_dir_
-      .AppendASCII("good")
-      .AppendASCII("Extensions");
-  base::FilePath pref_path = source_install_dir
-      .DirName()
-      .AppendASCII("Preferences");
-
-  InitializeInstalledExtensionService(pref_path, source_install_dir);
-
-  // The user has enabled sync.
-  ProfileSyncService* sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_.get());
-  sync_service->SetSyncSetupCompleted();
-
-  service_->Init();
-  ASSERT_TRUE(service_->is_ready());
-
-  ASSERT_EQ(3u, loaded_.size());
-
-  // We start enabled.
-  const Extension* extension = service_->GetExtensionById(good0, true);
-  ASSERT_TRUE(extension);
-  ASSERT_TRUE(service_->IsExtensionEnabled(good0));
-  extensions::ExtensionSyncData disable_good_crx(*extension, false, false);
-
-  // Then sync data arrives telling us to disable |good0|.
-  syncer::SyncDataList sync_data;
-  sync_data.push_back(disable_good_crx.GetSyncData());
-  service_->MergeDataAndStartSyncing(
-      syncer::EXTENSIONS, sync_data,
-      scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
-      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
-  ASSERT_FALSE(service_->IsExtensionEnabled(good0));
-}
-
-TEST_F(ExtensionServiceTest, DontDisableExtensionWithPendingEnableFromSync) {
-  // Start the extensions service with one external extension already installed.
-  base::FilePath source_install_dir = data_dir_
-      .AppendASCII("good")
-      .AppendASCII("Extensions");
-  base::FilePath pref_path = source_install_dir
-      .DirName()
-      .AppendASCII("Preferences");
-
-  InitializeInstalledExtensionService(pref_path, source_install_dir);
-
-  // The user has enabled sync.
-  ProfileSyncService* sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_.get());
-  sync_service->SetSyncSetupCompleted();
-
-  service_->Init();
-  ASSERT_TRUE(service_->is_ready());
-  ASSERT_EQ(3u, loaded_.size());
-
-  const Extension* extension = service_->GetExtensionById(good0, true);
-  ASSERT_TRUE(service_->IsExtensionEnabled(good0));
-
-  // Disable extension before first sync data arrives.
-  service_->DisableExtension(good0, Extension::DISABLE_USER_ACTION);
-  ASSERT_FALSE(service_->IsExtensionEnabled(good0));
-
-  // Enable extension - this is now the most recent state.
-  service_->EnableExtension(good0);
-  ASSERT_TRUE(service_->IsExtensionEnabled(good0));
-
-  // Now sync data comes in that says to disable good0. This should be
-  // ignored.
-  extensions::ExtensionSyncData disable_good_crx(*extension, false, false);
-  syncer::SyncDataList sync_data;
-  sync_data.push_back(disable_good_crx.GetSyncData());
-  service_->MergeDataAndStartSyncing(
-      syncer::EXTENSIONS, sync_data,
-      scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
-      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
-
-  // The extension was enabled locally before the sync data arrived, so it
-  // should still be enabled now.
-  ASSERT_TRUE(service_->IsExtensionEnabled(good0));
-}
-
 TEST_F(ExtensionServiceTest, GetSyncData) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
   const Extension* extension = service_->GetInstalledExtension(good_crx);
   ASSERT_TRUE(extension);
 
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
-  syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
+  syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+      syncer::EXTENSIONS);
   ASSERT_EQ(list.size(), 1U);
   extensions::ExtensionSyncData data(list[0]);
   EXPECT_EQ(extension->id(), data.id());
   EXPECT_FALSE(data.uninstalled());
-  EXPECT_EQ(service_->IsExtensionEnabled(good_crx), data.enabled());
   EXPECT_EQ(extension_util::IsIncognitoEnabled(good_crx, service_),
             data.incognito_enabled());
   EXPECT_TRUE(data.version().Equals(*extension->version()));
@@ -5395,23 +5307,24 @@
 
 TEST_F(ExtensionServiceTest, GetSyncDataTerminated) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
   TerminateExtension(good_crx);
   const Extension* extension = service_->GetInstalledExtension(good_crx);
   ASSERT_TRUE(extension);
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
-  syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
+  syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+      syncer::EXTENSIONS);
   ASSERT_EQ(list.size(), 1U);
   extensions::ExtensionSyncData data(list[0]);
   EXPECT_EQ(extension->id(), data.id());
   EXPECT_FALSE(data.uninstalled());
-  EXPECT_EQ(service_->IsExtensionEnabled(good_crx), data.enabled());
   EXPECT_EQ(extension_util::IsIncognitoEnabled(good_crx, service_),
             data.incognito_enabled());
   EXPECT_TRUE(data.version().Equals(*extension->version()));
@@ -5422,76 +5335,64 @@
 
 TEST_F(ExtensionServiceTest, GetSyncDataFilter) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
   const Extension* extension = service_->GetInstalledExtension(good_crx);
   ASSERT_TRUE(extension);
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(syncer::APPS, syncer::SyncDataList(),
+  extension_sync_service_->MergeDataAndStartSyncing(syncer::APPS,
+      syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
-  syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
+  syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+      syncer::EXTENSIONS);
   ASSERT_EQ(list.size(), 0U);
 }
 
 TEST_F(ExtensionServiceTest, GetSyncExtensionDataUserSettings) {
   InitializeEmptyExtensionService();
+  InitializeExtensionProcessManager();
+  InitializeExtensionSyncService();
   InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
   const Extension* extension = service_->GetInstalledExtension(good_crx);
   ASSERT_TRUE(extension);
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::EXTENSIONS);
     ASSERT_EQ(list.size(), 1U);
     extensions::ExtensionSyncData data(list[0]);
-    EXPECT_TRUE(data.enabled());
-    EXPECT_FALSE(data.incognito_enabled());
-  }
-
-  service_->DisableExtension(good_crx, Extension::DISABLE_USER_ACTION);
-  {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
-    ASSERT_EQ(list.size(), 1U);
-    extensions::ExtensionSyncData data(list[0]);
-    EXPECT_FALSE(data.enabled());
     EXPECT_FALSE(data.incognito_enabled());
   }
 
   extension_util::SetIsIncognitoEnabled(good_crx, service_, true);
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::EXTENSIONS);
     ASSERT_EQ(list.size(), 1U);
     extensions::ExtensionSyncData data(list[0]);
-    EXPECT_FALSE(data.enabled());
-    EXPECT_TRUE(data.incognito_enabled());
-  }
-
-  service_->EnableExtension(good_crx);
-  {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
-    ASSERT_EQ(list.size(), 1U);
-    extensions::ExtensionSyncData data(list[0]);
-    EXPECT_TRUE(data.enabled());
     EXPECT_TRUE(data.incognito_enabled());
   }
 }
 
 TEST_F(ExtensionServiceTest, SyncForUninstalledExternalExtension) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   InstallCRXWithLocation(data_dir_.AppendASCII("good.crx"),
                          Manifest::EXTERNAL_PREF, INSTALL_NEW);
   const Extension* extension = service_->GetInstalledExtension(good_crx);
   ASSERT_TRUE(extension);
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5505,7 +5406,6 @@
       app_specifics->mutable_extension();
   extension_specifics->set_id(good_crx);
   extension_specifics->set_version("1.0");
-  extension_specifics->set_enabled(true);
 
   syncer::SyncData sync_data =
       syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
@@ -5515,26 +5415,29 @@
   syncer::SyncChangeList list(1);
   list[0] = sync_change;
 
-  service_->ProcessSyncChanges(FROM_HERE, list);
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_TRUE(service_->IsExternalExtensionUninstalled(good_crx));
 }
 
 TEST_F(ExtensionServiceTest, GetSyncAppDataUserSettings) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   const Extension* app =
       PackAndInstallCRX(data_dir_.AppendASCII("app"), INSTALL_NEW);
   ASSERT_TRUE(app);
   ASSERT_TRUE(app->is_app());
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(syncer::APPS, syncer::SyncDataList(),
+  extension_sync_service_->MergeDataAndStartSyncing(syncer::APPS,
+      syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
   syncer::StringOrdinal initial_ordinal =
       syncer::StringOrdinal::CreateInitialOrdinal();
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::APPS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::APPS);
     ASSERT_EQ(list.size(), 1U);
 
     extensions::AppSyncData app_sync_data(list[0]);
@@ -5545,7 +5448,8 @@
   ExtensionSorting* sorting = service_->extension_prefs()->extension_sorting();
   sorting->SetAppLaunchOrdinal(app->id(), initial_ordinal.CreateAfter());
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::APPS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::APPS);
     ASSERT_EQ(list.size(), 1U);
 
     extensions::AppSyncData app_sync_data(list[0]);
@@ -5555,7 +5459,8 @@
 
   sorting->SetPageOrdinal(app->id(), initial_ordinal.CreateAfter());
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::APPS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::APPS);
     ASSERT_EQ(list.size(), 1U);
 
     extensions::AppSyncData app_sync_data(list[0]);
@@ -5566,6 +5471,7 @@
 
 TEST_F(ExtensionServiceTest, GetSyncAppDataUserSettingsOnExtensionMoved) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   const size_t kAppCount = 3;
   const Extension* apps[kAppCount];
   apps[0] = PackAndInstallCRX(data_dir_.AppendASCII("app1"), INSTALL_NEW);
@@ -5577,13 +5483,15 @@
   }
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(syncer::APPS, syncer::SyncDataList(),
+  extension_sync_service_->MergeDataAndStartSyncing(syncer::APPS,
+      syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
   service_->OnExtensionMoved(apps[0]->id(), apps[1]->id(), apps[2]->id());
   {
-    syncer::SyncDataList list = service_->GetAllSyncData(syncer::APPS);
+    syncer::SyncDataList list = extension_sync_service_->GetAllSyncData(
+        syncer::APPS);
     ASSERT_EQ(list.size(), 3U);
 
     extensions::AppSyncData data[kAppCount];
@@ -5609,16 +5517,18 @@
 
 TEST_F(ExtensionServiceTest, GetSyncDataList) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
   InstallCRX(data_dir_.AppendASCII("page_action.crx"), INSTALL_NEW);
   InstallCRX(data_dir_.AppendASCII("theme.crx"), INSTALL_NEW);
   InstallCRX(data_dir_.AppendASCII("theme2.crx"), INSTALL_NEW);
 
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(syncer::APPS, syncer::SyncDataList(),
+  extension_sync_service_->MergeDataAndStartSyncing(
+      syncer::APPS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5626,14 +5536,16 @@
   service_->DisableExtension(page_action, Extension::DISABLE_USER_ACTION);
   TerminateExtension(theme2_crx);
 
-  EXPECT_EQ(0u, service_->GetAllSyncData(syncer::APPS).size());
-  EXPECT_EQ(2u, service_->GetAllSyncData(syncer::EXTENSIONS).size());
+  EXPECT_EQ(0u, extension_sync_service_->GetAllSyncData(syncer::APPS).size());
+  EXPECT_EQ(2u, extension_sync_service_->
+      GetAllSyncData(syncer::EXTENSIONS).size());
 }
 
 TEST_F(ExtensionServiceTest, ProcessSyncDataUninstall) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5651,7 +5563,7 @@
   list[0] = sync_change;
 
   // Should do nothing.
-  service_->ProcessSyncChanges(FROM_HERE, list);
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_FALSE(service_->GetExtensionById(good_crx, true));
 
   // Install the extension.
@@ -5660,16 +5572,17 @@
   EXPECT_TRUE(service_->GetExtensionById(good_crx, true));
 
   // Should uninstall the extension.
-  service_->ProcessSyncChanges(FROM_HERE, list);
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_FALSE(service_->GetExtensionById(good_crx, true));
 
   // Should again do nothing.
-  service_->ProcessSyncChanges(FROM_HERE, list);
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_FALSE(service_->GetExtensionById(good_crx, true));
 }
 
 TEST_F(ExtensionServiceTest, ProcessSyncDataWrongType) {
   InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
 
   // Install the extension.
   base::FilePath extension_path = data_dir_.AppendASCII("good.crx");
@@ -5685,7 +5598,6 @@
       service_->GetInstalledExtension(good_crx)->version()->GetString());
 
   {
-    extension_specifics->set_enabled(true);
     syncer::SyncData sync_data =
         syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
     syncer::SyncChange sync_change(FROM_HERE,
@@ -5695,12 +5607,11 @@
     list[0] = sync_change;
 
     // Should do nothing
-    service_->ProcessSyncChanges(FROM_HERE, list);
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_TRUE(service_->GetExtensionById(good_crx, true));
   }
 
   {
-    extension_specifics->set_enabled(false);
     syncer::SyncData sync_data =
         syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
     syncer::SyncChange sync_change(FROM_HERE,
@@ -5710,7 +5621,7 @@
     list[0] = sync_change;
 
     // Should again do nothing.
-    service_->ProcessSyncChanges(FROM_HERE, list);
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_TRUE(service_->GetExtensionById(good_crx, false));
   }
 }
@@ -5718,8 +5629,9 @@
 TEST_F(ExtensionServiceTest, ProcessSyncDataSettings) {
   InitializeEmptyExtensionService();
   InitializeExtensionProcessManager();
+  InitializeExtensionSyncService();
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5733,7 +5645,6 @@
   ext_specifics->set_id(good_crx);
   ext_specifics->set_version(
       service_->GetInstalledExtension(good_crx)->version()->GetString());
-  ext_specifics->set_enabled(false);
 
   {
     syncer::SyncData sync_data =
@@ -5743,27 +5654,13 @@
                                    sync_data);
     syncer::SyncChangeList list(1);
     list[0] = sync_change;
-    service_->ProcessSyncChanges(FROM_HERE, list);
-    EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
   }
 
   {
-    ext_specifics->set_enabled(true);
-    ext_specifics->set_incognito_enabled(true);
-    syncer::SyncData sync_data =
-        syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
-    syncer::SyncChange sync_change(FROM_HERE,
-                                   syncer::SyncChange::ACTION_UPDATE,
-                                   sync_data);
-    syncer::SyncChangeList list(1);
-    list[0] = sync_change;
-    service_->ProcessSyncChanges(FROM_HERE, list);
-    EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
-    EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
-  }
-
-  {
+    // Note: enabled is a deprecated field. Although clients may set it,
+    // we should ignore it.
     ext_specifics->set_enabled(false);
     ext_specifics->set_incognito_enabled(true);
     syncer::SyncData sync_data =
@@ -5773,8 +5670,8 @@
                                    sync_data);
     syncer::SyncChangeList list(1);
     list[0] = sync_change;
-    service_->ProcessSyncChanges(FROM_HERE, list);
-    EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
+    EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
     EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
   }
 
@@ -5783,8 +5680,9 @@
 
 TEST_F(ExtensionServiceTest, ProcessSyncDataTerminatedExtension) {
   InitializeExtensionServiceWithUpdater();
+  InitializeExtensionSyncService();
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5799,7 +5697,6 @@
   ext_specifics->set_id(good_crx);
   ext_specifics->set_version(
       service_->GetInstalledExtension(good_crx)->version()->GetString());
-  ext_specifics->set_enabled(false);
   ext_specifics->set_incognito_enabled(true);
   syncer::SyncData sync_data =
       syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
@@ -5809,8 +5706,7 @@
   syncer::SyncChangeList list(1);
   list[0] = sync_change;
 
-  service_->ProcessSyncChanges(FROM_HERE, list);
-  EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
 
   EXPECT_FALSE(service_->pending_extension_manager()->IsIdPending(good_crx));
@@ -5818,8 +5714,9 @@
 
 TEST_F(ExtensionServiceTest, ProcessSyncDataVersionCheck) {
   InitializeExtensionServiceWithUpdater();
+  InitializeExtensionSyncService();
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5831,7 +5728,6 @@
   sync_pb::EntitySpecifics specifics;
   sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
   ext_specifics->set_id(good_crx);
-  ext_specifics->set_enabled(true);
 
   {
     ext_specifics->set_version(
@@ -5845,7 +5741,7 @@
     list[0] = sync_change;
 
     // Should do nothing if extension version == sync version.
-    service_->ProcessSyncChanges(FROM_HERE, list);
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_FALSE(service_->updater()->WillCheckSoon());
   }
 
@@ -5861,7 +5757,7 @@
     syncer::SyncChangeList list(1);
     list[0] = sync_change;
 
-    service_->ProcessSyncChanges(FROM_HERE, list);
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_FALSE(service_->updater()->WillCheckSoon());
   }
 
@@ -5876,7 +5772,7 @@
     syncer::SyncChangeList list(1);
     list[0] = sync_change;
 
-    service_->ProcessSyncChanges(FROM_HERE, list);
+    extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_TRUE(service_->updater()->WillCheckSoon());
   }
 
@@ -5885,8 +5781,9 @@
 
 TEST_F(ExtensionServiceTest, ProcessSyncDataNotInstalled) {
   InitializeExtensionServiceWithUpdater();
+  InitializeExtensionSyncService();
   TestSyncProcessorStub processor;
-  service_->MergeDataAndStartSyncing(
+  extension_sync_service_->MergeDataAndStartSyncing(
       syncer::EXTENSIONS, syncer::SyncDataList(),
       scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessorStub),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
@@ -5894,7 +5791,6 @@
   sync_pb::EntitySpecifics specifics;
   sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
   ext_specifics->set_id(good_crx);
-  ext_specifics->set_enabled(false);
   ext_specifics->set_incognito_enabled(true);
   ext_specifics->set_update_url("http://www.google.com/");
   ext_specifics->set_version("1.2.3.4");
@@ -5909,9 +5805,8 @@
 
   EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
   EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
-  service_->ProcessSyncChanges(FROM_HERE, list);
+  extension_sync_service_->ProcessSyncChanges(FROM_HERE, list);
   EXPECT_TRUE(service_->updater()->WillCheckSoon());
-  EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
   EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
 
   const extensions::PendingExtensionInfo* info;
@@ -6568,7 +6463,7 @@
       extension.get(),
       syncer::StringOrdinal(),
       false /* has requirement errors */,
-      extensions::Blacklist::BLACKLISTED,
+      extensions::Blacklist::BLACKLISTED_MALWARE,
       false /* wait for idle */);
   base::RunLoop().RunUntilIdle();
 
diff --git a/chrome/browser/extensions/extension_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h
index 2972c6d..f58bdc4 100644
--- a/chrome/browser/extensions/extension_service_unittest.h
+++ b/chrome/browser/extensions/extension_service_unittest.h
@@ -58,6 +58,8 @@
 
   void InitializeExtensionServiceWithUpdater();
 
+  void InitializeExtensionSyncService();
+
   static void SetUpTestCase();
 
   virtual void SetUp() OVERRIDE;
@@ -81,6 +83,7 @@
   // Managed by extensions::ExtensionSystemFactory.
   ExtensionService* service_;
   extensions::ManagementPolicy* management_policy_;
+  scoped_ptr<ExtensionSyncService> extension_sync_service_;
   size_t expected_extensions_count_;
 
 #if defined OS_CHROMEOS
diff --git a/chrome/browser/extensions/extension_sorting.cc b/chrome/browser/extensions/extension_sorting.cc
index fa17dac..ab4cf2d 100644
--- a/chrome/browser/extensions/extension_sorting.cc
+++ b/chrome/browser/extensions/extension_sorting.cc
@@ -9,7 +9,7 @@
 
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_scoped_prefs.h"
-#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/notification_service.h"
 
@@ -47,16 +47,16 @@
 
 ExtensionSorting::ExtensionSorting(ExtensionScopedPrefs* extension_scoped_prefs)
     : extension_scoped_prefs_(extension_scoped_prefs),
-      extension_service_(NULL),
+      extension_sync_service_(NULL),
       default_ordinals_created_(false) {
 }
 
 ExtensionSorting::~ExtensionSorting() {
 }
 
-void ExtensionSorting::SetExtensionService(
-    ExtensionServiceInterface* extension_service) {
-  extension_service_ = extension_service;
+void ExtensionSorting::SetExtensionSyncService(
+    ExtensionSyncService* extension_sync_service) {
+  extension_sync_service_ = extension_sync_service;
 }
 
 void ExtensionSorting::Initialize(
@@ -523,19 +523,8 @@
 }
 
 void ExtensionSorting::SyncIfNeeded(const std::string& extension_id) {
-  if (extension_service_) {
-    const extensions::Extension* ext =
-        extension_service_->GetInstalledExtension(extension_id);
-
-    if (ext) {
-      // It is possible for old extension to have ordinal values, but they
-      // shouldn't so we clear them.
-      if (!ext->is_app())
-        ClearOrdinals(extension_id);
-
-      extension_service_->SyncExtensionChangeIfNeeded(*ext);
-    }
-  }
+  if (extension_sync_service_)
+    extension_sync_service_->SyncOrderingChange(extension_id);
 }
 
 void ExtensionSorting::CreateDefaultOrdinals() {
diff --git a/chrome/browser/extensions/extension_sorting.h b/chrome/browser/extensions/extension_sorting.h
index f387095..ea45fa4 100644
--- a/chrome/browser/extensions/extension_sorting.h
+++ b/chrome/browser/extensions/extension_sorting.h
@@ -15,7 +15,7 @@
 #include "sync/api/string_ordinal.h"
 
 class ExtensionScopedPrefs;
-class ExtensionServiceInterface;
+class ExtensionSyncService;
 class PrefService;
 
 class ExtensionSorting {
@@ -23,8 +23,8 @@
   explicit ExtensionSorting(ExtensionScopedPrefs* extension_scoped_prefs);
   ~ExtensionSorting();
 
-  // Set up the ExtensionService to inform of changes that require syncing.
-  void SetExtensionService(ExtensionServiceInterface* extension_service);
+  // Set up the ExtensionSyncService to inform of changes that require syncing.
+  void SetExtensionSyncService(ExtensionSyncService* extension_sync_service);
 
   // Properly initialize ExtensionSorting internal values that require
   // |extension_ids|.
@@ -197,7 +197,7 @@
   size_t CountItemsVisibleOnNtp(const AppLaunchOrdinalMap& m) const;
 
   ExtensionScopedPrefs* extension_scoped_prefs_;  // Weak, owns this instance.
-  ExtensionServiceInterface* extension_service_;  // Weak.
+  ExtensionSyncService* extension_sync_service_;  // Weak.
 
   // A map of all the StringOrdinal page ordinals mapping to the collections of
   // app launch ordinals that exist on that page. This is used for mapping
diff --git a/chrome/browser/extensions/extension_sync_bundle.cc b/chrome/browser/extensions/extension_sync_bundle.cc
index 8369c86..a43963d 100644
--- a/chrome/browser/extensions/extension_sync_bundle.cc
+++ b/chrome/browser/extensions/extension_sync_bundle.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/extensions/extension_sync_bundle.h"
 
 #include "base/location.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_sorting.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_set.h"
 #include "chrome/common/extensions/sync_helper.h"
@@ -15,8 +15,9 @@
 
 namespace extensions {
 
-ExtensionSyncBundle::ExtensionSyncBundle(ExtensionService* extension_service)
-    : extension_service_(extension_service) {}
+ExtensionSyncBundle::ExtensionSyncBundle(
+    ExtensionSyncService* extension_sync_service)
+    : extension_sync_service_(extension_sync_service) {}
 
 ExtensionSyncBundle::~ExtensionSyncBundle() {}
 
@@ -32,7 +33,7 @@
        ++i) {
     ExtensionSyncData extension_sync_data(*i);
     AddExtension(extension_sync_data.id());
-    extension_service_->ProcessExtensionSyncData(extension_sync_data);
+    extension_sync_service_->ProcessExtensionSyncData(extension_sync_data);
   }
 }
 
@@ -46,7 +47,7 @@
 syncer::SyncChange ExtensionSyncBundle::CreateSyncChangeToDelete(
     const Extension* extension) const {
   extensions::ExtensionSyncData sync_data =
-      extension_service_->GetExtensionSyncData(*extension);
+      extension_sync_service_->GetExtensionSyncData(*extension);
   return sync_data.GetSyncChange(syncer::SyncChange::ACTION_DELETE);
 }
 
@@ -73,7 +74,7 @@
 
 syncer::SyncDataList ExtensionSyncBundle::GetAllSyncData() const {
   std::vector<ExtensionSyncData> extension_sync_data =
-      extension_service_->GetExtensionSyncDataList();
+      extension_sync_service_->GetExtensionSyncDataList();
   syncer::SyncDataList result(extension_sync_data.size());
   for (int i = 0; i < static_cast<int>(extension_sync_data.size()); ++i) {
     result[i] = extension_sync_data[i].GetSyncData();
@@ -87,7 +88,7 @@
     RemoveExtension(extension_sync_data.id());
   else
     AddExtension(extension_sync_data.id());
-  extension_service_->ProcessExtensionSyncData(extension_sync_data);
+  extension_sync_service_->ProcessExtensionSyncData(extension_sync_data);
 }
 
 void ExtensionSyncBundle::ProcessSyncChangeList(
@@ -117,7 +118,7 @@
 
 void ExtensionSyncBundle::SyncChangeIfNeeded(const Extension& extension) {
   ExtensionSyncData extension_sync_data =
-      extension_service_->GetExtensionSyncData(extension);
+      extension_sync_service_->GetExtensionSyncData(extension);
 
   syncer::SyncChangeList sync_change_list(1, extension_sync_data.GetSyncChange(
       HasExtensionId(extension.id()) ?
@@ -139,10 +140,10 @@
 }
 
 void ExtensionSyncBundle::GetExtensionSyncDataListHelper(
-    const ExtensionSet& extensions,
+    const ExtensionSet* extensions,
     std::vector<ExtensionSyncData>* sync_data_list) const {
-  for (ExtensionSet::const_iterator it = extensions.begin();
-       it != extensions.end(); ++it) {
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
     const Extension& extension = *it->get();
     // If we have pending extension data for this extension, then this
     // version is out of date.  We'll sync back the version we got from
@@ -150,7 +151,7 @@
     if (IsSyncing() && sync_helper::IsSyncableExtension(&extension) &&
         !HasPendingExtensionId(extension.id())) {
       sync_data_list->push_back(
-          extension_service_->GetExtensionSyncData(extension));
+          extension_sync_service_->GetExtensionSyncData(extension));
     }
   }
 }
diff --git a/chrome/browser/extensions/extension_sync_bundle.h b/chrome/browser/extensions/extension_sync_bundle.h
index dab36a2..3dadc1e 100644
--- a/chrome/browser/extensions/extension_sync_bundle.h
+++ b/chrome/browser/extensions/extension_sync_bundle.h
@@ -16,7 +16,7 @@
 #include "chrome/browser/extensions/sync_bundle.h"
 #include "sync/api/syncable_service.h"
 
-class ExtensionService;
+class ExtensionSyncService;
 class ExtensionSet;
 
 namespace syncer {
@@ -31,7 +31,7 @@
 // Bundle of extension specific sync stuff.
 class ExtensionSyncBundle : public SyncBundle {
  public:
-  explicit ExtensionSyncBundle(ExtensionService* extension_service);
+  explicit ExtensionSyncBundle(ExtensionSyncService* extension_sync_service);
   virtual ~ExtensionSyncBundle();
 
   // Setup this bundle to be sync extension data.
@@ -75,7 +75,7 @@
 
   // Appends sync data objects for every extension in |extensions|.
   void GetExtensionSyncDataListHelper(
-      const ExtensionSet& extensions,
+      const ExtensionSet* extensions,
       std::vector<extensions::ExtensionSyncData>* sync_data_list) const;
 
   // Overrides for SyncBundle.
@@ -95,7 +95,7 @@
   // Change an extension from being pending to synced.
   void MarkPendingExtensionSynced(const std::string& id);
 
-  ExtensionService* extension_service_;  // Owns us.
+  ExtensionSyncService* extension_sync_service_;  // Owns us.
   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
   scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_;
 
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
new file mode 100644
index 0000000..5adab02
--- /dev/null
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -0,0 +1,443 @@
+// Copyright 2013 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/extensions/extension_sync_service.h"
+
+#include <iterator>
+
+#include "base/basictypes.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/extensions/app_sync_data.h"
+#include "chrome/browser/extensions/extension_error_ui.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sorting.h"
+#include "chrome/browser/extensions/extension_sync_data.h"
+#include "chrome/browser/extensions/extension_sync_service_factory.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/glue/sync_start_util.h"
+#include "chrome/browser/sync/sync_prefs.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/feature_switch.h"
+#include "chrome/common/extensions/sync_helper.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest_constants.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_error_factory.h"
+
+using extensions::Extension;
+using extensions::ExtensionPrefs;
+using extensions::FeatureSwitch;
+
+ExtensionSyncService::ExtensionSyncService(Profile* profile,
+                                           ExtensionPrefs* extension_prefs,
+                                           ExtensionService* extension_service)
+    : profile_(profile),
+      extension_prefs_(extension_prefs),
+      extension_service_(extension_service),
+      app_sync_bundle_(this),
+      extension_sync_bundle_(this),
+      pending_app_enables_(
+          make_scoped_ptr(new browser_sync::SyncPrefs(
+              extension_prefs_->pref_service())),
+          &app_sync_bundle_,
+          syncer::APPS),
+      pending_extension_enables_(
+          make_scoped_ptr(new browser_sync::SyncPrefs(
+              extension_prefs_->pref_service())),
+          &extension_sync_bundle_,
+          syncer::EXTENSIONS) {
+  SetSyncStartFlare(sync_start_util::GetFlareForSyncableService(
+      profile_->GetPath()));
+
+  extension_service_->set_extension_sync_service(this);
+  extension_prefs_->extension_sorting()->SetExtensionSyncService(this);
+}
+
+ExtensionSyncService::~ExtensionSyncService() {}
+
+// static
+ExtensionSyncService* ExtensionSyncService::Get(Profile* profile) {
+  return ExtensionSyncServiceFactory::GetForProfile(profile);
+}
+
+syncer::SyncChange ExtensionSyncService::PrepareToSyncUninstallExtension(
+    const extensions::Extension* extension, bool extensions_ready) {
+  // Extract the data we need for sync now, but don't actually sync until we've
+  // completed the uninstallation.
+  // TODO(tim): If we get here and IsSyncing is false, this will cause
+  // "back from the dead" style bugs, because sync will add-back the extension
+  // that was uninstalled here when MergeDataAndStartSyncing is called.
+  // See crbug.com/256795.
+  if (extensions::sync_helper::IsSyncableApp(extension)) {
+    if (app_sync_bundle_.IsSyncing())
+      return app_sync_bundle_.CreateSyncChangeToDelete(extension);
+    else if (extensions_ready && !flare_.is_null())
+      flare_.Run(syncer::APPS);  // Tell sync to start ASAP.
+  } else if (extensions::sync_helper::IsSyncableExtension(extension)) {
+    if (extension_sync_bundle_.IsSyncing())
+      return extension_sync_bundle_.CreateSyncChangeToDelete(extension);
+    else if (extensions_ready && !flare_.is_null())
+      flare_.Run(syncer::EXTENSIONS);  // Tell sync to start ASAP.
+  }
+
+  return syncer::SyncChange();
+}
+
+void ExtensionSyncService::ProcessSyncUninstallExtension(
+    const std::string& extension_id,
+    const syncer::SyncChange& sync_change) {
+  if (app_sync_bundle_.HasExtensionId(extension_id) &&
+      sync_change.sync_data().GetDataType() == syncer::APPS) {
+    app_sync_bundle_.ProcessDeletion(extension_id, sync_change);
+  } else if (extension_sync_bundle_.HasExtensionId(extension_id) &&
+             sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) {
+    extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
+  }
+}
+
+void ExtensionSyncService::SyncEnableExtension(
+    const extensions::Extension& extension) {
+
+  // Syncing may not have started yet, so handle pending enables.
+  if (extensions::sync_helper::IsSyncableApp(&extension))
+    pending_app_enables_.OnExtensionEnabled(extension.id());
+
+  if (extensions::sync_helper::IsSyncableExtension(&extension))
+    pending_extension_enables_.OnExtensionEnabled(extension.id());
+
+  SyncExtensionChangeIfNeeded(extension);
+}
+
+void ExtensionSyncService::SyncDisableExtension(
+    const extensions::Extension& extension) {
+
+  // Syncing may not have started yet, so handle pending enables.
+  if (extensions::sync_helper::IsSyncableApp(&extension))
+    pending_app_enables_.OnExtensionDisabled(extension.id());
+
+  if (extensions::sync_helper::IsSyncableExtension(&extension))
+    pending_extension_enables_.OnExtensionDisabled(extension.id());
+
+  SyncExtensionChangeIfNeeded(extension);
+}
+
+syncer::SyncMergeResult ExtensionSyncService::MergeDataAndStartSyncing(
+    syncer::ModelType type,
+    const syncer::SyncDataList& initial_sync_data,
+    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
+  CHECK(sync_processor.get());
+  CHECK(sync_error_factory.get());
+
+  switch (type) {
+    case syncer::EXTENSIONS:
+      extension_sync_bundle_.SetupSync(sync_processor.release(),
+                                       sync_error_factory.release(),
+                                       initial_sync_data);
+      pending_extension_enables_.OnSyncStarted(extension_service_);
+      break;
+
+    case syncer::APPS:
+      app_sync_bundle_.SetupSync(sync_processor.release(),
+                                 sync_error_factory.release(),
+                                 initial_sync_data);
+      pending_app_enables_.OnSyncStarted(extension_service_);
+      break;
+
+    default:
+      LOG(FATAL) << "Got " << type << " ModelType";
+  }
+
+  // Process local extensions.
+  // TODO(yoz): Determine whether pending extensions should be considered too.
+  //            See crbug.com/104399.
+  syncer::SyncDataList sync_data_list = GetAllSyncData(type);
+  syncer::SyncChangeList sync_change_list;
+  for (syncer::SyncDataList::const_iterator i = sync_data_list.begin();
+       i != sync_data_list.end();
+       ++i) {
+    switch (type) {
+        case syncer::EXTENSIONS:
+          sync_change_list.push_back(
+              extension_sync_bundle_.CreateSyncChange(*i));
+          break;
+        case syncer::APPS:
+          sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i));
+          break;
+      default:
+        LOG(FATAL) << "Got " << type << " ModelType";
+    }
+  }
+
+
+  if (type == syncer::EXTENSIONS) {
+    extension_sync_bundle_.ProcessSyncChangeList(sync_change_list);
+  } else if (type == syncer::APPS) {
+    app_sync_bundle_.ProcessSyncChangeList(sync_change_list);
+  }
+
+  return syncer::SyncMergeResult(type);
+}
+
+void ExtensionSyncService::StopSyncing(syncer::ModelType type) {
+  if (type == syncer::APPS) {
+    app_sync_bundle_.Reset();
+  } else if (type == syncer::EXTENSIONS) {
+    extension_sync_bundle_.Reset();
+  }
+}
+
+syncer::SyncDataList ExtensionSyncService::GetAllSyncData(
+    syncer::ModelType type) const {
+  if (type == syncer::EXTENSIONS)
+    return extension_sync_bundle_.GetAllSyncData();
+  if (type == syncer::APPS)
+    return app_sync_bundle_.GetAllSyncData();
+
+  // We should only get sync data for extensions and apps.
+  NOTREACHED();
+
+  return syncer::SyncDataList();
+}
+
+syncer::SyncError ExtensionSyncService::ProcessSyncChanges(
+    const tracked_objects::Location& from_here,
+    const syncer::SyncChangeList& change_list) {
+  for (syncer::SyncChangeList::const_iterator i = change_list.begin();
+      i != change_list.end();
+      ++i) {
+    syncer::ModelType type = i->sync_data().GetDataType();
+    if (type == syncer::EXTENSIONS) {
+      extension_sync_bundle_.ProcessSyncChange(
+          extensions::ExtensionSyncData(*i));
+    } else if (type == syncer::APPS) {
+      app_sync_bundle_.ProcessSyncChange(extensions::AppSyncData(*i));
+    }
+  }
+
+  extension_prefs_->extension_sorting()->FixNTPOrdinalCollisions();
+
+  return syncer::SyncError();
+}
+
+extensions::ExtensionSyncData ExtensionSyncService::GetExtensionSyncData(
+    const Extension& extension) const {
+  return extensions::ExtensionSyncData(
+      extension,
+      extension_service_->IsExtensionEnabled(extension.id()),
+      extension_util::IsIncognitoEnabled(extension.id(), extension_service_));
+}
+
+extensions::AppSyncData ExtensionSyncService::GetAppSyncData(
+    const Extension& extension) const {
+  return extensions::AppSyncData(
+      extension,
+      extension_service_->IsExtensionEnabled(extension.id()),
+      extension_util::IsIncognitoEnabled(extension.id(), extension_service_),
+      extension_prefs_->extension_sorting()->GetAppLaunchOrdinal(
+          extension.id()),
+      extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id()));
+}
+
+std::vector<extensions::ExtensionSyncData>
+  ExtensionSyncService::GetExtensionSyncDataList() const {
+  std::vector<extensions::ExtensionSyncData> extension_sync_list;
+  extension_sync_bundle_.GetExtensionSyncDataListHelper(
+      extension_service_->extensions(), &extension_sync_list);
+  extension_sync_bundle_.GetExtensionSyncDataListHelper(
+      extension_service_->disabled_extensions(), &extension_sync_list);
+  extension_sync_bundle_.GetExtensionSyncDataListHelper(
+      extension_service_->terminated_extensions(), &extension_sync_list);
+
+  std::vector<extensions::ExtensionSyncData> pending_extensions =
+      extension_sync_bundle_.GetPendingData();
+  extension_sync_list.insert(extension_sync_list.begin(),
+                             pending_extensions.begin(),
+                             pending_extensions.end());
+
+  return extension_sync_list;
+}
+
+std::vector<extensions::AppSyncData> ExtensionSyncService::GetAppSyncDataList()
+    const {
+  std::vector<extensions::AppSyncData> app_sync_list;
+  app_sync_bundle_.GetAppSyncDataListHelper(
+      extension_service_->extensions(), &app_sync_list);
+  app_sync_bundle_.GetAppSyncDataListHelper(
+      extension_service_->disabled_extensions(), &app_sync_list);
+  app_sync_bundle_.GetAppSyncDataListHelper(
+      extension_service_->terminated_extensions(), &app_sync_list);
+
+  std::vector<extensions::AppSyncData> pending_apps =
+      app_sync_bundle_.GetPendingData();
+  app_sync_list.insert(app_sync_list.begin(),
+                       pending_apps.begin(),
+                       pending_apps.end());
+
+  return app_sync_list;
+}
+
+bool ExtensionSyncService::ProcessExtensionSyncData(
+    const extensions::ExtensionSyncData& extension_sync_data) {
+  if (!ProcessExtensionSyncDataHelper(extension_sync_data,
+                                      syncer::EXTENSIONS)) {
+    extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(),
+                                               extension_sync_data);
+    extension_service_->CheckForUpdatesSoon();
+    return false;
+  }
+
+  return true;
+}
+
+bool ExtensionSyncService::ProcessAppSyncData(
+    const extensions::AppSyncData& app_sync_data) {
+  const std::string& id = app_sync_data.id();
+
+  if (app_sync_data.app_launch_ordinal().IsValid() &&
+      app_sync_data.page_ordinal().IsValid()) {
+    extension_prefs_->extension_sorting()->SetAppLaunchOrdinal(
+        id,
+        app_sync_data.app_launch_ordinal());
+    extension_prefs_->extension_sorting()->SetPageOrdinal(
+        id,
+        app_sync_data.page_ordinal());
+  }
+
+  if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(),
+                                      syncer::APPS)) {
+    app_sync_bundle_.AddPendingApp(id, app_sync_data);
+    extension_service_->CheckForUpdatesSoon();
+    return false;
+  }
+
+  return true;
+}
+
+void ExtensionSyncService::SyncOrderingChange(const std::string& extension_id) {
+  const extensions::Extension* ext = extension_service_->GetInstalledExtension(
+      extension_id);
+
+  if (ext)
+    SyncExtensionChangeIfNeeded(*ext);
+}
+
+void ExtensionSyncService::SetSyncStartFlare(
+    const syncer::SyncableService::StartSyncFlare& flare) {
+  flare_ = flare;
+}
+
+bool ExtensionSyncService::IsCorrectSyncType(const Extension& extension,
+                                         syncer::ModelType type) const {
+  if (type == syncer::EXTENSIONS &&
+      extensions::sync_helper::IsSyncableExtension(&extension)) {
+    return true;
+  }
+
+  if (type == syncer::APPS &&
+      extensions::sync_helper::IsSyncableApp(&extension)) {
+    return true;
+  }
+
+  return false;
+}
+
+bool ExtensionSyncService::IsPendingEnable(
+    const std::string& extension_id) const {
+  return pending_app_enables_.Contains(extension_id) ||
+      pending_extension_enables_.Contains(extension_id);
+}
+
+bool ExtensionSyncService::ProcessExtensionSyncDataHelper(
+    const extensions::ExtensionSyncData& extension_sync_data,
+    syncer::ModelType type) {
+  const std::string& id = extension_sync_data.id();
+  const Extension* extension = extension_service_->GetInstalledExtension(id);
+
+  // TODO(bolms): we should really handle this better.  The particularly bad
+  // case is where an app becomes an extension or vice versa, and we end up with
+  // a zombie extension that won't go away.
+  if (extension && !IsCorrectSyncType(*extension, type))
+    return true;
+
+  // Handle uninstalls first.
+  if (extension_sync_data.uninstalled()) {
+    if (!extension_service_->UninstallExtensionHelper(extension_service_, id)) {
+      LOG(WARNING) << "Could not uninstall extension " << id
+                   << " for sync";
+    }
+    return true;
+  }
+
+  // Extension from sync was uninstalled by the user as external extensions.
+  // Honor user choice and skip installation/enabling.
+  if (extension_service_->IsExternalExtensionUninstalled(id)) {
+    LOG(WARNING) << "Extension with id " << id
+                 << " from sync was uninstalled as external extension";
+    return true;
+  }
+
+  // Set user settings.
+
+  // We need to cache some version information here because setting the
+  // incognito flag invalidates the |extension| pointer (it reloads the
+  // extension).
+  bool extension_installed = (extension != NULL);
+  int result = extension ?
+      extension->version()->CompareTo(extension_sync_data.version()) : 0;
+  extension_util::SetIsIncognitoEnabled(
+      id, extension_service_, extension_sync_data.incognito_enabled());
+  extension = NULL;  // No longer safe to use.
+
+  if (extension_installed) {
+    // If the extension is already installed, check if it's outdated.
+    if (result < 0) {
+      // Extension is outdated.
+      return false;
+    }
+  } else {
+    // TODO(akalin): Replace silent update with a list of enabled
+    // permissions.
+    const bool kInstallSilently = true;
+
+    CHECK(type == syncer::EXTENSIONS || type == syncer::APPS);
+    extensions::PendingExtensionInfo::ShouldAllowInstallPredicate filter =
+        (type == syncer::APPS) ? extensions::sync_helper::IsSyncableApp :
+                                 extensions::sync_helper::IsSyncableExtension;
+
+    if (!extension_service_->pending_extension_manager()->AddFromSync(
+            id,
+            extension_sync_data.update_url(),
+            filter,
+            kInstallSilently)) {
+      LOG(WARNING) << "Could not add pending extension for " << id;
+      // This means that the extension is already pending installation, with a
+      // non-INTERNAL location.  Add to pending_sync_data, even though it will
+      // never be removed (we'll never install a syncable version of the
+      // extension), so that GetAllSyncData() continues to send it.
+    }
+    // Track pending extensions so that we can return them in GetAllSyncData().
+    return false;
+  }
+
+  return true;
+}
+
+void ExtensionSyncService::SyncExtensionChangeIfNeeded(
+    const Extension& extension) {
+  if (extensions::sync_helper::IsSyncableApp(&extension)) {
+    if (app_sync_bundle_.IsSyncing())
+      app_sync_bundle_.SyncChangeIfNeeded(extension);
+    else if (extension_service_->is_ready() && !flare_.is_null())
+      flare_.Run(syncer::APPS);
+  } else if (extensions::sync_helper::IsSyncableExtension(&extension)) {
+    if (extension_sync_bundle_.IsSyncing())
+      extension_sync_bundle_.SyncChangeIfNeeded(extension);
+    else if (extension_service_->is_ready() && !flare_.is_null())
+      flare_.Run(syncer::EXTENSIONS);
+  }
+}
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
new file mode 100644
index 0000000..65559e9
--- /dev/null
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -0,0 +1,157 @@
+// Copyright 2013 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_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/extensions/app_sync_bundle.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_sync_bundle.h"
+#include "chrome/browser/extensions/pending_enables.h"
+#include "chrome/common/extensions/extension.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "sync/api/string_ordinal.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/syncable_service.h"
+
+class ExtensionErrorUI;
+class ExtensionSyncData;
+class Profile;
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace extensions {
+class AppSyncData;
+class ExtensionPrefs;
+class ExtensionSyncData;
+}  // namespace extensions
+
+namespace syncer {
+class SyncErrorFactory;
+}
+
+class ExtensionSyncService : public syncer::SyncableService,
+                             public BrowserContextKeyedService  {
+ public:
+  ExtensionSyncService(Profile* profile,
+                       extensions::ExtensionPrefs* extension_prefs,
+                       ExtensionService* extension_service);
+
+  virtual ~ExtensionSyncService();
+
+  // Convenience function to get the ExtensionSyncService for a Profile.
+  static ExtensionSyncService* Get(Profile* profile);
+
+  const extensions::ExtensionPrefs& extension_prefs() const {
+    return *extension_prefs_;
+  }
+
+  // Notifies Sync (if needed) of a newly-installed extension or a change to
+  // an existing extension.
+  virtual void SyncExtensionChangeIfNeeded(
+      const extensions::Extension& extension);
+
+  // syncer::SyncableService implementation.
+  virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
+      syncer::ModelType type,
+      const syncer::SyncDataList& initial_sync_data,
+      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+      scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) OVERRIDE;
+  virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
+  virtual syncer::SyncDataList GetAllSyncData(
+      syncer::ModelType type) const OVERRIDE;
+  virtual syncer::SyncError ProcessSyncChanges(
+      const tracked_objects::Location& from_here,
+      const syncer::SyncChangeList& change_list) OVERRIDE;
+
+  // Gets the sync data for the given extension, assuming that the extension is
+  // syncable.
+  extensions::ExtensionSyncData GetExtensionSyncData(
+      const extensions::Extension& extension) const;
+
+  // Gets the sync data for the given app, assuming that the app is
+  // syncable.
+  extensions::AppSyncData GetAppSyncData(
+      const extensions::Extension& extension) const;
+
+  // Gets the ExtensionSyncData for all extensions.
+  std::vector<extensions::ExtensionSyncData> GetExtensionSyncDataList() const;
+
+  // Gets the AppSyncData for all extensions.
+  std::vector<extensions::AppSyncData> GetAppSyncDataList() const;
+
+  // Applies the change specified passed in by either ExtensionSyncData or
+  // AppSyncData to the current system.
+  // Returns false if the changes were not completely applied and were added
+  // to the pending list to be tried again.
+  bool ProcessExtensionSyncData(
+      const extensions::ExtensionSyncData& extension_sync_data);
+  bool ProcessAppSyncData(const extensions::AppSyncData& app_sync_data);
+
+  syncer::SyncChange PrepareToSyncUninstallExtension(
+      const extensions::Extension* extension,
+      bool extensions_ready);
+  void ProcessSyncUninstallExtension(const std::string& extension_id,
+                                     const syncer::SyncChange& sync_change);
+
+  void SyncEnableExtension(const extensions::Extension& extension);
+  void SyncDisableExtension(const extensions::Extension& extension);
+
+  void SyncOrderingChange(const std::string& extension_id);
+
+  // |flare| provides a StartSyncFlare to the SyncableService. See
+  // sync_start_util for more.
+  void SetSyncStartFlare(const syncer::SyncableService::StartSyncFlare& flare);
+
+ private:
+  // Return true if the sync type of |extension| matches |type|.
+  bool IsCorrectSyncType(const extensions::Extension& extension,
+                         syncer::ModelType type)
+      const;
+
+  // Whether the given extension has been enabled before sync has started.
+  bool IsPendingEnable(const std::string& extension_id) const;
+
+  // Handles setting the extension specific values in |extension_sync_data| to
+  // the current system.
+  // Returns false if the changes were not completely applied and need to be
+  // tried again later.
+  bool ProcessExtensionSyncDataHelper(
+      const extensions::ExtensionSyncData& extension_sync_data,
+      syncer::ModelType type);
+
+  // The normal profile associated with this ExtensionService.
+  Profile* profile_;
+
+  // Preferences for the owning profile.
+  extensions::ExtensionPrefs* extension_prefs_;
+
+  ExtensionService* extension_service_;
+
+  extensions::AppSyncBundle app_sync_bundle_;
+  extensions::ExtensionSyncBundle extension_sync_bundle_;
+
+  // Set of extensions/apps that have been enabled before sync has started.
+  extensions::PendingEnables pending_app_enables_;
+  extensions::PendingEnables pending_extension_enables_;
+
+  scoped_ptr<ExtensionErrorUI> extension_error_ui_;
+  // Sequenced task runner for extension related file operations.
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+
+  // Run()ning tells sync to try and start soon, because syncable changes
+  // have started happening. It will cause sync to call us back
+  // asynchronously via MergeDataAndStartSyncing as soon as possible.
+  syncer::SyncableService::StartSyncFlare flare_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionSyncService);
+};
+
+#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_H_
diff --git a/chrome/browser/extensions/extension_sync_service_factory.cc b/chrome/browser/extensions/extension_sync_service_factory.cc
new file mode 100644
index 0000000..5b9b9a4
--- /dev/null
+++ b/chrome/browser/extensions/extension_sync_service_factory.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/extensions/extension_sync_service_factory.h"
+
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/extensions/extension_prefs_factory.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+// static
+ExtensionSyncService* ExtensionSyncServiceFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<ExtensionSyncService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+ExtensionSyncServiceFactory* ExtensionSyncServiceFactory::GetInstance() {
+  return Singleton<ExtensionSyncServiceFactory>::get();
+}
+
+ExtensionSyncServiceFactory::ExtensionSyncServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+        "ExtensionSyncService",
+        BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
+  DependsOn(extensions::ExtensionSystemFactory::GetInstance());
+}
+
+ExtensionSyncServiceFactory::~ExtensionSyncServiceFactory() {}
+
+BrowserContextKeyedService*
+    ExtensionSyncServiceFactory::BuildServiceInstanceFor(
+        content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+  return new ExtensionSyncService(
+      profile,
+      extensions::ExtensionPrefsFactory::GetForProfile(profile),
+      extensions::ExtensionSystemFactory::GetForProfile(profile)->
+          extension_service());
+}
+
+content::BrowserContext* ExtensionSyncServiceFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
diff --git a/chrome/browser/extensions/extension_sync_service_factory.h b/chrome/browser/extensions/extension_sync_service_factory.h
new file mode 100644
index 0000000..0c9e838
--- /dev/null
+++ b/chrome/browser/extensions/extension_sync_service_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2013 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_EXTENSIONS_EXTENSION_SYNC_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class ExtensionSyncService;
+class Profile;
+
+class ExtensionSyncServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static ExtensionSyncService* GetForProfile(Profile* profile);
+
+  static ExtensionSyncServiceFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<ExtensionSyncServiceFactory>;
+
+  ExtensionSyncServiceFactory();
+  virtual ~ExtensionSyncServiceFactory();
+
+  virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const OVERRIDE;
+  virtual content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const OVERRIDE;
+};
+
+#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_SYNC_SERVICE_FACTORY_H_
diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc
index ddb687d..b7099d2 100644
--- a/chrome/browser/extensions/extension_system.cc
+++ b/chrome/browser/extensions/extension_system.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/extension_warning_badge_service.h"
 #include "chrome/browser/extensions/extension_warning_set.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/extensions/navigation_observer.h"
 #include "chrome/browser/extensions/standard_management_policy_provider.h"
@@ -36,7 +35,6 @@
 #include "chrome/browser/extensions/user_script_master.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
@@ -44,6 +42,7 @@
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/url_data_source.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/manifest.h"
 
@@ -79,6 +78,12 @@
   return ExtensionSystemFactory::GetForProfile(profile);
 }
 
+// static
+ExtensionSystem* ExtensionSystem::GetForBrowserContext(
+    content::BrowserContext* profile) {
+  return ExtensionSystemFactory::GetForProfile(static_cast<Profile*>(profile));
+}
+
 //
 // ExtensionSystemImpl::Shared
 //
@@ -171,8 +176,6 @@
       autoupdate_enabled,
       extensions_enabled,
       &ready_));
-  extension_service_->SetSyncStartFlare(
-      sync_start_util::GetFlareForSyncableService(profile_->GetPath()));
 
   // These services must be registered before the ExtensionService tries to
   // load any extensions.
@@ -406,7 +409,7 @@
 
 void ExtensionSystemImpl::UnregisterExtensionWithRequestContexts(
     const std::string& extension_id,
-    const extension_misc::UnloadedExtensionReason reason) {
+    const UnloadedExtensionInfo::Reason reason) {
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(&ExtensionInfoMap::RemoveExtension, info_map(),
diff --git a/chrome/browser/extensions/extension_system.h b/chrome/browser/extensions/extension_system.h
index c88fc74..663c176 100644
--- a/chrome/browser/extensions/extension_system.h
+++ b/chrome/browser/extensions/extension_system.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "extensions/common/one_shot_event.h"
 
@@ -24,6 +24,10 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
+namespace content {
+class BrowserContext;
+}
+
 namespace extensions {
 class Blacklist;
 class ErrorConsole;
@@ -53,6 +57,10 @@
   // a convenience wrapper around ExtensionSystemFactory::GetForProfile.
   static ExtensionSystem* Get(Profile* profile);
 
+  // Returns the same instance as Get() above.
+  static ExtensionSystem* GetForBrowserContext(
+      content::BrowserContext* profile);
+
   // BrowserContextKeyedService implementation.
   virtual void Shutdown() OVERRIDE {}
 
@@ -116,7 +124,7 @@
   // EXTENSION_UNLOADED notification have finished running.
   virtual void UnregisterExtensionWithRequestContexts(
       const std::string& extension_id,
-      const extension_misc::UnloadedExtensionReason reason) {}
+      const UnloadedExtensionInfo::Reason reason) {}
 
   // Signaled when the extension system has completed its startup tasks.
   virtual const OneShotEvent& ready() const = 0;
@@ -157,7 +165,7 @@
 
   virtual void UnregisterExtensionWithRequestContexts(
       const std::string& extension_id,
-      const extension_misc::UnloadedExtensionReason reason) OVERRIDE;
+      const UnloadedExtensionInfo::Reason reason) OVERRIDE;
 
   virtual const OneShotEvent& ready() const OVERRIDE;
 
diff --git a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
index a1d4037..4b3d734 100644
--- a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
+++ b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
@@ -107,7 +107,13 @@
   EXPECT_EQ(NULL, ExtensionAt(0));
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderAndReinsert) {
+#if defined(OS_MACOSX)
+// Flaky on Mac 10.8 Blink canary bots: http://crbug.com/166580
+#define MAYBE_ReorderAndReinsert DISABLED_ReorderAndReinsert
+#else
+#define MAYBE_ReorderAndReinsert ReorderAndReinsert
+#endif
+IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, MAYBE_ReorderAndReinsert) {
   // Load an extension with a browser action.
   base::FilePath extension_a_path(test_data_dir_.AppendASCII("api_test")
                                           .AppendASCII("browser_action")
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index fb6bc92..317ddac 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -9,6 +9,7 @@
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/image_loader.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index 71375dd..890d8d1 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/incognito_handler.h"
@@ -74,8 +75,10 @@
 
   // Reloading the extension invalidates the |extension| pointer.
   extension = service->GetInstalledExtension(id);
-  if (extension)
-    service->SyncExtensionChangeIfNeeded(*extension);
+  if (extension) {
+    ExtensionSyncService::Get(service->profile())->
+        SyncExtensionChangeIfNeeded(*extension);
+  }
 }
 
 bool CanCrossIncognito(const Extension* extension,
diff --git a/chrome/browser/extensions/extension_web_contents_observer.cc b/chrome/browser/extensions/extension_web_contents_observer.cc
index 8f648b6..fba7f6e 100644
--- a/chrome/browser/extensions/extension_web_contents_observer.cc
+++ b/chrome/browser/extensions/extension_web_contents_observer.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/messaging/message.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -100,7 +101,7 @@
 }
 
 void ExtensionWebContentsObserver::OnPostMessage(int port_id,
-                                                 const std::string& message) {
+                                                 const Message& message) {
   MessageService* message_service = MessageService::Get(profile_);
   if (message_service) {
     message_service->PostMessage(port_id, message);
diff --git a/chrome/browser/extensions/extension_web_contents_observer.h b/chrome/browser/extensions/extension_web_contents_observer.h
index dbac7f9..019dc88 100644
--- a/chrome/browser/extensions/extension_web_contents_observer.h
+++ b/chrome/browser/extensions/extension_web_contents_observer.h
@@ -12,6 +12,7 @@
 
 namespace extensions {
 class Extension;
+struct Message;
 
 // A web contents observer that's used for WebContents in renderer and extension
 // processes.
@@ -30,7 +31,7 @@
       content::RenderViewHost* render_view_host) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
-  void OnPostMessage(int port_id, const std::string& message);
+  void OnPostMessage(int port_id, const Message& message);
 
   // Gets the extension or app (if any) that is associated with a RVH.
   const Extension* GetExtension(content::RenderViewHost* render_view_host);
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index b2002c2..d6ef812 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -9,6 +9,7 @@
 
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/image_loader.h"
 #include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index df29f6a..67ef13a 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -62,8 +62,6 @@
 const char ExternalProviderImpl::kIsBookmarkApp[] = "is_bookmark_app";
 const char ExternalProviderImpl::kIsFromWebstore[] = "is_from_webstore";
 const char ExternalProviderImpl::kKeepIfPresent[] = "keep_if_present";
-const char ExternalProviderImpl::kRequirePermissionsConsent[] =
-    "require_permissions_consent";
 
 ExternalProviderImpl::ExternalProviderImpl(
     VisitorInterface* service,
@@ -221,12 +219,6 @@
         continue;
       }
     }
-    bool require_permissions_consent;
-    if (extension->GetBoolean(kRequirePermissionsConsent,
-                              &require_permissions_consent) &&
-        require_permissions_consent) {
-      creation_flags |= Extension::REQUIRE_PERMISSIONS_CONSENT;
-    }
 
     if (has_external_crx) {
       if (crx_location_ == Manifest::INVALID_LOCATION) {
@@ -444,7 +436,8 @@
         linked_ptr<ExternalProviderInterface>(
             new ExternalProviderImpl(
                 service,
-                new chromeos::ExternalPrefCacheLoader(external_apps_path_id),
+                new chromeos::ExternalPrefCacheLoader(
+                    external_apps_path_id, profile),
                 profile,
                 Manifest::EXTERNAL_PREF,
                 Manifest::EXTERNAL_PREF_DOWNLOAD,
diff --git a/chrome/browser/extensions/external_provider_impl.h b/chrome/browser/extensions/external_provider_impl.h
index 8d95e3e..5482582 100644
--- a/chrome/browser/extensions/external_provider_impl.h
+++ b/chrome/browser/extensions/external_provider_impl.h
@@ -72,7 +72,6 @@
   static const char kIsBookmarkApp[];
   static const char kIsFromWebstore[];
   static const char kKeepIfPresent[];
-  static const char kRequirePermissionsConsent[];
 
   void set_auto_acknowledge(bool auto_acknowledge) {
     auto_acknowledge_ = auto_acknowledge;
diff --git a/chrome/browser/extensions/image_loader.cc b/chrome/browser/extensions/image_loader.cc
index 2c8f77c..ee2567f 100644
--- a/chrome/browser/extensions/image_loader.cc
+++ b/chrome/browser/extensions/image_loader.cc
@@ -173,8 +173,8 @@
 }
 
 // static
-ImageLoader* ImageLoader::Get(Profile* profile) {
-  return ImageLoaderFactory::GetForProfile(profile);
+ImageLoader* ImageLoader::Get(content::BrowserContext* context) {
+  return ImageLoaderFactory::GetForBrowserContext(context);
 }
 
 // A map from a resource path to the resource ID.  Used only by
diff --git a/chrome/browser/extensions/image_loader.h b/chrome/browser/extensions/image_loader.h
index 5e6bc3e..7365269 100644
--- a/chrome/browser/extensions/image_loader.h
+++ b/chrome/browser/extensions/image_loader.h
@@ -16,7 +16,9 @@
 #include "ui/base/layout.h"
 #include "ui/gfx/size.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace gfx {
 class Image;
@@ -64,9 +66,9 @@
 
   struct LoadResult;
 
-  // Returns the instance for the given profile, or NULL if none. This is
-  // a convenience wrapper around ImageLoaderFactory::GetForProfile.
-  static ImageLoader* Get(Profile* profile);
+  // Returns the instance for the given |context| or NULL if none. This is
+  // a convenience wrapper around ImageLoaderFactory::GetForBrowserContext.
+  static ImageLoader* Get(content::BrowserContext* context);
 
   ImageLoader();
   virtual ~ImageLoader();
diff --git a/chrome/browser/extensions/image_loader_factory.cc b/chrome/browser/extensions/image_loader_factory.cc
index 6d08dd7..bc9c299 100644
--- a/chrome/browser/extensions/image_loader_factory.cc
+++ b/chrome/browser/extensions/image_loader_factory.cc
@@ -6,15 +6,15 @@
 
 #include "chrome/browser/extensions/image_loader.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
 namespace extensions {
 
 // static
-ImageLoader* ImageLoaderFactory::GetForProfile(Profile* profile) {
+ImageLoader* ImageLoaderFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
   return static_cast<ImageLoader*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
+      GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
 ImageLoaderFactory* ImageLoaderFactory::GetInstance() {
@@ -31,7 +31,7 @@
 }
 
 BrowserContextKeyedService* ImageLoaderFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
+    content::BrowserContext* context) const {
   return new ImageLoader;
 }
 
@@ -41,6 +41,8 @@
 
 content::BrowserContext* ImageLoaderFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
+  // TODO(jamescook): Find a more generic way to do this in the extensions
+  // system without being tied to Chrome code.
   return chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
diff --git a/chrome/browser/extensions/image_loader_factory.h b/chrome/browser/extensions/image_loader_factory.h
index f958265..55828da 100644
--- a/chrome/browser/extensions/image_loader_factory.h
+++ b/chrome/browser/extensions/image_loader_factory.h
@@ -8,18 +8,21 @@
 #include "base/memory/singleton.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace extensions {
 
 class ImageLoader;
 
 // Singleton that owns all ImageLoaders and associates them with
-// Profiles. Listens for the Profile's destruction notification and cleans up
-// the associated ImageLoader.
+// BrowserContexts. Listens for the BrowserContext's destruction notification
+// and cleans up the associated ImageLoader. Uses the original BrowserContext
+// for incognito contexts.
 class ImageLoaderFactory : public BrowserContextKeyedServiceFactory {
  public:
-  static ImageLoader* GetForProfile(Profile* profile);
+  static ImageLoader* GetForBrowserContext(content::BrowserContext* context);
 
   static ImageLoaderFactory* GetInstance();
 
@@ -31,7 +34,7 @@
 
   // BrowserContextKeyedServiceFactory:
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const OVERRIDE;
+      content::BrowserContext* context) const OVERRIDE;
   virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
   virtual content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const OVERRIDE;
diff --git a/chrome/browser/extensions/image_loader_unittest.cc b/chrome/browser/extensions/image_loader_unittest.cc
index 05cea06..a8f0d15 100644
--- a/chrome/browser/extensions/image_loader_unittest.cc
+++ b/chrome/browser/extensions/image_loader_unittest.cc
@@ -29,6 +29,7 @@
 using extensions::ExtensionResource;
 using extensions::ImageLoader;
 using extensions::Manifest;
+using extensions::UnloadedExtensionInfo;
 
 class ImageLoaderTest : public testing::Test {
  public:
@@ -169,12 +170,12 @@
   EXPECT_EQ(0, image_loaded_count());
 
   // Send out notification the extension was uninstalled.
-  extensions::UnloadedExtensionInfo details(extension.get(),
-      extension_misc::UNLOAD_REASON_UNINSTALL);
+  UnloadedExtensionInfo details(extension.get(),
+                                UnloadedExtensionInfo::REASON_UNINSTALL);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::NotificationService::AllSources(),
-      content::Details<extensions::UnloadedExtensionInfo>(&details));
+      content::Details<UnloadedExtensionInfo>(&details));
 
   // Chuck the extension, that way if anyone tries to access it we should crash
   // or get valgrind errors.
diff --git a/chrome/browser/extensions/lazy_background_task_queue.cc b/chrome/browser/extensions/lazy_background_task_queue.cc
deleted file mode 100644
index fdaab75..0000000
--- a/chrome/browser/extensions/lazy_background_task_queue.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright (c) 2012 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/extensions/lazy_background_task_queue.h"
-
-#include "base/callback.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/process_map.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/background_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/common/view_type.h"
-
-namespace extensions {
-
-LazyBackgroundTaskQueue::LazyBackgroundTaskQueue(Profile* profile)
-    : profile_(profile) {
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                 content::Source<Profile>(profile));
-}
-
-LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() {
-}
-
-bool LazyBackgroundTaskQueue::ShouldEnqueueTask(
-    Profile* profile, const Extension* extension) {
-  DCHECK(extension);
-  if (BackgroundInfo::HasBackgroundPage(extension)) {
-    ExtensionProcessManager* pm = ExtensionSystem::Get(profile)->
-        process_manager();
-    ExtensionHost* background_host =
-        pm->GetBackgroundHostForExtension(extension->id());
-    if (!background_host || !background_host->did_stop_loading())
-      return true;
-    if (pm->IsBackgroundHostClosing(extension->id()))
-      pm->CancelSuspend(extension);
-  }
-
-  return false;
-}
-
-void LazyBackgroundTaskQueue::AddPendingTask(
-    Profile* profile,
-    const std::string& extension_id,
-    const PendingTask& task) {
-  if (g_browser_process->IsShuttingDown()) {
-    task.Run(NULL);
-    return;
-  }
-  PendingTasksList* tasks_list = NULL;
-  PendingTasksKey key(profile, extension_id);
-  PendingTasksMap::iterator it = pending_tasks_.find(key);
-  if (it == pending_tasks_.end()) {
-    tasks_list = new PendingTasksList();
-    pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list);
-
-    const Extension* extension =
-        ExtensionSystem::Get(profile)->extension_service()->
-            extensions()->GetByID(extension_id);
-    if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) {
-      // If this is the first enqueued task, and we're not waiting for the
-      // background page to unload, ensure the background page is loaded.
-      ExtensionProcessManager* pm =
-          ExtensionSystem::Get(profile)->process_manager();
-      pm->IncrementLazyKeepaliveCount(extension);
-      // Creating the background host may fail, e.g. if |profile| is incognito
-      // but the extension isn't enabled in incognito mode.
-      if (!pm->CreateBackgroundHost(
-            extension, BackgroundInfo::GetBackgroundURL(extension))) {
-        task.Run(NULL);
-        return;
-      }
-    }
-  } else {
-    tasks_list = it->second.get();
-  }
-
-  tasks_list->push_back(task);
-}
-
-void LazyBackgroundTaskQueue::ProcessPendingTasks(
-    ExtensionHost* host,
-    Profile* profile,
-    const Extension* extension) {
-  if (!profile->IsSameProfile(profile_))
-    return;
-
-  PendingTasksKey key(profile, extension->id());
-  PendingTasksMap::iterator map_it = pending_tasks_.find(key);
-  if (map_it == pending_tasks_.end()) {
-    if (BackgroundInfo::HasLazyBackgroundPage(extension))
-      CHECK(!host);  // lazy page should not load without any pending tasks
-    return;
-  }
-
-  // Swap the pending tasks to a temporary, to avoid problems if the task
-  // list is modified during processing.
-  PendingTasksList tasks;
-  tasks.swap(*map_it->second);
-  for (PendingTasksList::const_iterator it = tasks.begin();
-       it != tasks.end(); ++it) {
-    it->Run(host);
-  }
-
-  pending_tasks_.erase(key);
-
-  // Balance the keepalive in AddPendingTask. Note we don't do this on a
-  // failure to load, because the keepalive count is reset in that case.
-  if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) {
-    ExtensionSystem::Get(profile)->process_manager()->
-        DecrementLazyKeepaliveCount(extension);
-  }
-}
-
-void LazyBackgroundTaskQueue::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
-      // If an on-demand background page finished loading, dispatch queued up
-      // events for it.
-      ExtensionHost* host =
-          content::Details<ExtensionHost>(details).ptr();
-      if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
-        CHECK(host->did_stop_loading());
-        ProcessPendingTasks(host, host->profile(), host->extension());
-      }
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
-      // Notify consumers about the load failure when the background host dies.
-      // This can happen if the extension crashes. This is not strictly
-      // necessary, since we also unload the extension in that case (which
-      // dispatches the tasks below), but is a good extra precaution.
-      Profile* profile = content::Source<Profile>(source).ptr();
-      ExtensionHost* host =
-           content::Details<ExtensionHost>(details).ptr();
-      if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
-        ProcessPendingTasks(NULL, profile, host->extension());
-      }
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      // Notify consumers that the page failed to load.
-      Profile* profile = content::Source<Profile>(source).ptr();
-      UnloadedExtensionInfo* unloaded =
-          content::Details<UnloadedExtensionInfo>(details).ptr();
-      ProcessPendingTasks(NULL, profile, unloaded->extension);
-      if (profile->HasOffTheRecordProfile()) {
-        ProcessPendingTasks(NULL, profile->GetOffTheRecordProfile(),
-                            unloaded->extension);
-      }
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/lazy_background_task_queue.h b/chrome/browser/extensions/lazy_background_task_queue.h
deleted file mode 100644
index cb302f8..0000000
--- a/chrome/browser/extensions/lazy_background_task_queue.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2012 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_EXTENSIONS_LAZY_BACKGROUND_TASK_QUEUE_H_
-#define CHROME_BROWSER_EXTENSIONS_LAZY_BACKGROUND_TASK_QUEUE_H_
-
-#include <map>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/callback_forward.h"
-#include "base/memory/linked_ptr.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class Profile;
-
-namespace extensions {
-class Extension;
-class ExtensionHost;
-
-// This class maintains a queue of tasks that should execute when an
-// extension's lazy background page is loaded. It is also in charge of loading
-// the page when the first task is queued.
-//
-// It is the consumer's responsibility to use this class when appropriate, i.e.
-// only with extensions that have not-yet-loaded lazy background pages.
-class LazyBackgroundTaskQueue : public content::NotificationObserver {
- public:
-  typedef base::Callback<void(ExtensionHost*)> PendingTask;
-
-  explicit LazyBackgroundTaskQueue(Profile* profile);
-  virtual ~LazyBackgroundTaskQueue();
-
-  // Returns true if the task should be added to the queue (that is, if the
-  // extension has a lazy background page that isn't ready yet). If the
-  // extension has a lazy background page that is being suspended this method
-  // cancels that suspension.
-  bool ShouldEnqueueTask(Profile* profile, const Extension* extension);
-
-  // Adds a task to the queue for a given extension. If this is the first
-  // task added for the extension, its lazy background page will be loaded.
-  // The task will be called either when the page is loaded, or when the
-  // page fails to load for some reason (e.g. a crash or browser
-  // shutdown). In the latter case, the ExtensionHost parameter is NULL.
-  void AddPendingTask(
-      Profile* profile,
-      const std::string& extension_id,
-      const PendingTask& task);
-
- private:
-  // A map between an extension_id,Profile pair and the queue of tasks pending
-  // the load of its background page.
-  typedef std::string ExtensionID;
-  typedef std::pair<Profile*, ExtensionID> PendingTasksKey;
-  typedef std::vector<PendingTask> PendingTasksList;
-  typedef std::map<PendingTasksKey,
-                   linked_ptr<PendingTasksList> > PendingTasksMap;
-
-  // content::NotificationObserver interface.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // Called when a lazy background page has finished loading, or has failed to
-  // load (host is NULL in that case). All enqueued tasks are run in order.
-  void ProcessPendingTasks(
-      ExtensionHost* host,
-      Profile* profile,
-      const Extension* extension);
-
-  Profile* profile_;
-  content::NotificationRegistrar registrar_;
-  PendingTasksMap pending_tasks_;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_LAZY_BACKGROUND_TASK_QUEUE_H_
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index 5fef312..d15097b 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -23,7 +23,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/api/context_menus.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/context_menu_params.h"
@@ -436,7 +435,7 @@
   // Notify that the extension was unloaded, and make sure the right item is
   // gone.
   UnloadedExtensionInfo details(
-      extension1, extension_misc::UNLOAD_REASON_DISABLE);
+      extension1, UnloadedExtensionInfo::REASON_DISABLE);
   notifier->Notify(chrome::NOTIFICATION_EXTENSION_UNLOADED,
                    content::Source<Profile>(&profile_),
                    content::Details<UnloadedExtensionInfo>(
diff --git a/chrome/browser/extensions/notifications_apitest.cc b/chrome/browser/extensions/notifications_apitest.cc
index b1299cf..10d95b6 100644
--- a/chrome/browser/extensions/notifications_apitest.cc
+++ b/chrome/browser/extensions/notifications_apitest.cc
@@ -41,7 +41,10 @@
 
 // This test verifies that on RichNotification-enabled platforms HTML
 // notificaitons are disabled.
-#if defined(RUN_MESSAGE_CENTER_TESTS)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_NoHTMLNotifications DISABLED_NoHTMLNotifications
+#elif defined(RUN_MESSAGE_CENTER_TESTS)
 #define MAYBE_NoHTMLNotifications NoHTMLNotifications
 #else
 #define MAYBE_NoHTMLNotifications DISABLED_NoHTMLNotifications
diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc
index 315f46b..30d71dc 100644
--- a/chrome/browser/extensions/permissions_updater_unittest.cc
+++ b/chrome/browser/extensions/permissions_updater_unittest.cc
@@ -15,11 +15,11 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_test_util.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extension_test_util::LoadManifest;
diff --git a/chrome/browser/extensions/test_blacklist.cc b/chrome/browser/extensions/test_blacklist.cc
index 77b75b2..40dcbef 100644
--- a/chrome/browser/extensions/test_blacklist.cc
+++ b/chrome/browser/extensions/test_blacklist.cc
@@ -19,20 +19,19 @@
 
 namespace {
 
-void Assign(std::set<std::string>* out, const std::set<std::string>& in) {
+void Assign(Blacklist::BlacklistState *out, Blacklist::BlacklistState in) {
   *out = in;
 }
 
 }  // namespace
 
-bool TestBlacklist::IsBlacklisted(const std::string& extension_id) {
-  std::set<std::string> id_set;
-  id_set.insert(extension_id);
-  std::set<std::string> blacklist_set;
-  blacklist_->GetBlacklistedIDs(id_set,
-                                base::Bind(&Assign, &blacklist_set));
+Blacklist::BlacklistState TestBlacklist::GetBlacklistState(
+    const std::string& extension_id) {
+  Blacklist::BlacklistState blacklist_state;
+  blacklist_->IsBlacklisted(extension_id,
+                            base::Bind(&Assign, &blacklist_state));
   base::RunLoop().RunUntilIdle();
-  return blacklist_set.count(extension_id) > 0;
+  return blacklist_state;
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/test_blacklist.h b/chrome/browser/extensions/test_blacklist.h
index a9b5690..9aa3041 100644
--- a/chrome/browser/extensions/test_blacklist.h
+++ b/chrome/browser/extensions/test_blacklist.h
@@ -8,11 +8,10 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "chrome/browser/extensions/blacklist.h"
 
 namespace extensions {
 
-class Blacklist;
-
 // A wrapper for an extensions::Blacklist that provides functionality for
 // testing.
 class TestBlacklist {
@@ -21,7 +20,7 @@
 
   Blacklist* blacklist() { return blacklist_; }
 
-  bool IsBlacklisted(const std::string& extension_id);
+  Blacklist::BlacklistState GetBlacklistState(const std::string& extension_id);
 
  private:
   Blacklist* blacklist_;
diff --git a/chrome/browser/extensions/test_extension_service.cc b/chrome/browser/extensions/test_extension_service.cc
index d274314..f506e96 100644
--- a/chrome/browser/extensions/test_extension_service.cc
+++ b/chrome/browser/extensions/test_extension_service.cc
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/extensions/crx_installer.h"
-#include "chrome/browser/extensions/extension_sync_data.h"
 #include "chrome/browser/extensions/test_extension_service.h"
-#include "sync/api/sync_error_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::Extension;
@@ -80,32 +78,6 @@
   ADD_FAILURE();
 }
 
-syncer::SyncMergeResult TestExtensionService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
-  ADD_FAILURE();
-  return syncer::SyncMergeResult(type);
-}
-
-void TestExtensionService::StopSyncing(syncer::ModelType type) {
-  ADD_FAILURE();
-}
-
-syncer::SyncDataList TestExtensionService::GetAllSyncData(
-    syncer::ModelType type) const {
-  ADD_FAILURE();
-  return syncer::SyncDataList();
-}
-
-syncer::SyncError TestExtensionService::ProcessSyncChanges(
-    const tracked_objects::Location& from_here,
-    const syncer::SyncChangeList& change_list) {
-  ADD_FAILURE();
-  return syncer::SyncError();
-}
-
 bool TestExtensionService::is_ready() {
   ADD_FAILURE();
   return false;
@@ -126,7 +98,7 @@
 
 void TestExtensionService::UnloadExtension(
     const std::string& extension_id,
-    extension_misc::UnloadedExtensionReason reason) {
+    extensions::UnloadedExtensionInfo::Reason reason) {
   ADD_FAILURE();
 }
 
@@ -134,8 +106,3 @@
     const std::string& extension_id) {
   ADD_FAILURE();
 }
-
-void TestExtensionService::SyncExtensionChangeIfNeeded(
-    const Extension& extension) {
-  ADD_FAILURE();
-}
diff --git a/chrome/browser/extensions/test_extension_service.h b/chrome/browser/extensions/test_extension_service.h
index 5373843..7824b41 100644
--- a/chrome/browser/extensions/test_extension_service.h
+++ b/chrome/browser/extensions/test_extension_service.h
@@ -10,10 +10,6 @@
 
 #include "chrome/browser/extensions/extension_service.h"
 
-namespace syncer {
-class SyncErrorFactory;
-}
-
 namespace extensions {
 class CrxInstaller;
 class Extension;
@@ -53,18 +49,6 @@
   virtual void CheckManagementPolicy() OVERRIDE;
   virtual void CheckForUpdatesSoon() OVERRIDE;
 
-  virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-      scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) OVERRIDE;
-  virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
-  virtual syncer::SyncDataList GetAllSyncData(
-      syncer::ModelType type) const OVERRIDE;
-  virtual syncer::SyncError ProcessSyncChanges(
-      const tracked_objects::Location& from_here,
-      const syncer::SyncChangeList& change_list) OVERRIDE;
-
   virtual bool is_ready() OVERRIDE;
 
   virtual base::SequencedTaskRunner* GetFileTaskRunner() OVERRIDE;
@@ -75,12 +59,9 @@
 
   virtual void UnloadExtension(
       const std::string& extension_id,
-      extension_misc::UnloadedExtensionReason reason) OVERRIDE;
+      extensions::UnloadedExtensionInfo::Reason reason) OVERRIDE;
   virtual void RemoveComponentExtension(const std::string & extension_id)
       OVERRIDE;
-
-  virtual void SyncExtensionChangeIfNeeded(
-      const extensions::Extension& extension) OVERRIDE;
 };
 
 #endif  // CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_SERVICE_H_
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc
index be59df2..a628a9f 100644
--- a/chrome/browser/extensions/test_extension_system.cc
+++ b/chrome/browser/extensions/test_extension_system.cc
@@ -48,6 +48,11 @@
   extension_process_manager_.reset(ExtensionProcessManager::Create(profile_));
 }
 
+void TestExtensionSystem::SetExtensionProcessManager(
+    ExtensionProcessManager* manager) {
+  extension_process_manager_.reset(manager);
+}
+
 ExtensionPrefs* TestExtensionSystem::CreateExtensionPrefs(
     const CommandLine* command_line,
     const base::FilePath& install_directory) {
@@ -62,7 +67,7 @@
   ExtensionPrefs* extension_prefs = ExtensionPrefs::Create(
       profile_->GetPrefs(),
       install_directory,
-      ExtensionPrefValueMapFactory::GetForProfile(profile_),
+      ExtensionPrefValueMapFactory::GetForBrowserContext(profile_),
       extensions_disabled);
     ExtensionPrefsFactory::GetInstance()->SetInstanceForTesting(
         profile_,
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h
index 67b8812..cab117b 100644
--- a/chrome/browser/extensions/test_extension_system.h
+++ b/chrome/browser/extensions/test_extension_system.h
@@ -48,6 +48,10 @@
   // ExtensionProcessManager is NULL.
   void CreateExtensionProcessManager();
 
+  // Allows the ExtensionProcessManager to be overriden, for example by a
+  // stub implementation. Takes ownership of |manager|.
+  void SetExtensionProcessManager(ExtensionProcessManager* manager);
+
   void CreateSocketManager();
 
   virtual void InitForRegularProfile(bool extensions_enabled,
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 1f5dc67..dfc81dd 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -193,7 +193,7 @@
   void UnloadTestExtension() {
     ASSERT_FALSE(service_->extensions()->is_empty());
     service_->UnloadExtension((*service_->extensions()->begin())->id(),
-                              extension_misc::UNLOAD_REASON_DISABLE);
+                              UnloadedExtensionInfo::REASON_DISABLE);
   }
 
   scoped_refptr<UserScriptListener> listener_;
diff --git a/chrome/browser/extensions/webrtc_cast_apitest.cc b/chrome/browser/extensions/webrtc_cast_apitest.cc
new file mode 100644
index 0000000..d551fe0
--- /dev/null
+++ b/chrome/browser/extensions/webrtc_cast_apitest.cc
@@ -0,0 +1,18 @@
+// Copyright 2013 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/extensions/extension_apitest.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class WebrtcCastApiTest : public ExtensionApiTest {
+};
+
+// Test running the test extension for Cast Mirroring API.
+IN_PROC_BROWSER_TEST_F(WebrtcCastApiTest, Basics) {
+  ASSERT_TRUE(RunExtensionSubtest("webrtc_cast", "basics.html"));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/webstore_ephemeral_installer.cc b/chrome/browser/extensions/webstore_ephemeral_installer.cc
new file mode 100644
index 0000000..1d1e2d5
--- /dev/null
+++ b/chrome/browser/extensions/webstore_ephemeral_installer.cc
@@ -0,0 +1,154 @@
+// Copyright 2013 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/extensions/webstore_ephemeral_installer.h"
+
+#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
+
+namespace extensions {
+
+namespace {
+
+// TODO(tmdiep): Launching the app will be moved downstream when an ephemeral
+// app service/manager is implemented.
+void LaunchApp(Profile* profile, const std::string& id) {
+  ExtensionService* service = extensions::ExtensionSystem::Get(profile)->
+      extension_service();
+  DCHECK(service);
+  const extensions::Extension* extension = service->GetExtensionById(id, false);
+  if (extension) {
+    AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB);
+    params.desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
+    OpenApplication(params);
+  }
+}
+
+void OnInstallDone(Profile* profile,
+                   const std::string& id,
+                   const WebstoreEphemeralInstaller::Callback& callback,
+                   bool success,
+                   const std::string& error) {
+  if (success)
+    content::BrowserThread::PostDelayedTask(
+        content::BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(&LaunchApp, profile, id),
+        base::TimeDelta());
+
+  callback.Run(success, error);
+}
+
+}  // namespace
+
+// static
+scoped_refptr<WebstoreEphemeralInstaller>
+WebstoreEphemeralInstaller::CreateForLauncher(
+    const std::string& webstore_item_id,
+    Profile* profile,
+    gfx::NativeWindow parent_window,
+    const Callback& callback) {
+  scoped_refptr<WebstoreEphemeralInstaller> installer =
+      new WebstoreEphemeralInstaller(webstore_item_id,
+                                     profile,
+                                     parent_window,
+                                     callback);
+  installer->set_install_source(
+      extensions::WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER);
+  return installer;
+}
+
+WebstoreEphemeralInstaller::WebstoreEphemeralInstaller(
+    const std::string& webstore_item_id,
+    Profile* profile,
+    gfx::NativeWindow parent_window,
+    const Callback& callback)
+        : WebstoreStandaloneInstaller(
+              webstore_item_id,
+              profile,
+              base::Bind(OnInstallDone, profile, webstore_item_id, callback)),
+          parent_window_(parent_window),
+          dummy_web_contents_(
+              WebContents::Create(WebContents::CreateParams(profile))) {}
+
+WebstoreEphemeralInstaller::~WebstoreEphemeralInstaller() {}
+
+bool WebstoreEphemeralInstaller::CheckRequestorAlive() const {
+  return true;
+}
+
+const GURL& WebstoreEphemeralInstaller::GetRequestorURL() const {
+  return GURL::EmptyGURL();
+}
+
+bool WebstoreEphemeralInstaller::ShouldShowPostInstallUI() const {
+  return false;
+}
+
+bool WebstoreEphemeralInstaller::ShouldShowAppInstalledBubble() const {
+  return false;
+}
+
+WebContents* WebstoreEphemeralInstaller::GetWebContents() const {
+  return dummy_web_contents_.get();
+}
+
+scoped_ptr<ExtensionInstallPrompt::Prompt>
+WebstoreEphemeralInstaller::CreateInstallPrompt() const {
+  DCHECK(manifest() != NULL);
+
+  // Skip the prompt by returning null if the app does not need to display
+  // permission warnings.
+  // Extension::Create() can return null when an error occurs, e.g. due to a bad
+  // manifest. In this case we should return a valid prompt and the bad manifest
+  // will be handled in WebstoreStandaloneInstaller::ShowInstallUI(). If null is
+  // returned here, the install will proceed.
+  std::string error;
+  scoped_refptr<Extension> extension = Extension::Create(
+      base::FilePath(),
+      Manifest::INTERNAL,
+      *manifest(),
+      Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
+      id(),
+      &error);
+  if (extension.get()) {
+    PermissionMessages permissions =
+        PermissionsData::GetPermissionMessages(extension.get());
+    if (permissions.empty())
+      return scoped_ptr<ExtensionInstallPrompt::Prompt>();
+  }
+
+  return make_scoped_ptr(new ExtensionInstallPrompt::Prompt(
+      ExtensionInstallPrompt::LAUNCH_PROMPT));
+}
+
+bool WebstoreEphemeralInstaller::CheckInlineInstallPermitted(
+    const base::DictionaryValue& webstore_data,
+    std::string* error) const {
+  *error = "";
+  return true;
+}
+
+bool WebstoreEphemeralInstaller::CheckRequestorPermitted(
+    const base::DictionaryValue& webstore_data,
+    std::string* error) const {
+  *error = "";
+  return true;
+}
+
+scoped_ptr<ExtensionInstallPrompt>
+WebstoreEphemeralInstaller::CreateInstallUI() {
+  return make_scoped_ptr(
+      new ExtensionInstallPrompt(profile(), parent_window_, NULL));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/webstore_ephemeral_installer.h b/chrome/browser/extensions/webstore_ephemeral_installer.h
new file mode 100644
index 0000000..895976b
--- /dev/null
+++ b/chrome/browser/extensions/webstore_ephemeral_installer.h
@@ -0,0 +1,67 @@
+// Copyright 2013 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_EXTENSIONS_WEBSTORE_EPHEMERAL_INSTALLER_H_
+#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_EPHEMERAL_INSTALLER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/extensions/webstore_standalone_installer.h"
+
+class Profile;
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+
+// WebstoreEphemeralInstaller handles the installation of ephemeral apps.
+class WebstoreEphemeralInstaller
+    : public extensions::WebstoreStandaloneInstaller {
+ public:
+  typedef WebstoreStandaloneInstaller::Callback Callback;
+
+  static scoped_refptr<WebstoreEphemeralInstaller> CreateForLauncher(
+      const std::string& webstore_item_id,
+      Profile* profile,
+      gfx::NativeWindow parent_window,
+      const Callback& callback);
+
+ private:
+  friend class base::RefCountedThreadSafe<WebstoreEphemeralInstaller>;
+
+  WebstoreEphemeralInstaller(const std::string& webstore_item_id,
+                             Profile* profile,
+                             gfx::NativeWindow parent_window,
+                             const Callback& callback);
+
+  virtual ~WebstoreEphemeralInstaller();
+
+  // WebstoreStandaloneInstaller implementation.
+  virtual bool CheckRequestorAlive() const OVERRIDE;
+  virtual const GURL& GetRequestorURL() const OVERRIDE;
+  virtual bool ShouldShowPostInstallUI() const OVERRIDE;
+  virtual bool ShouldShowAppInstalledBubble() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual scoped_ptr<ExtensionInstallPrompt::Prompt>
+      CreateInstallPrompt() const OVERRIDE;
+  virtual bool CheckInlineInstallPermitted(
+      const base::DictionaryValue& webstore_data,
+      std::string* error) const OVERRIDE;
+  virtual bool CheckRequestorPermitted(
+      const base::DictionaryValue& webstore_data,
+      std::string* error) const OVERRIDE;
+  virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE;
+
+  gfx::NativeWindow parent_window_;
+  scoped_ptr<content::WebContents> dummy_web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebstoreEphemeralInstaller);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_EPHEMERAL_INSTALLER_H_
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index 5bf00a9..5ef853c 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -318,10 +318,12 @@
       CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr()));
       const Extension* extension =
           content::Details<const InstalledExtensionInfo>(details)->extension;
-      CHECK(!pending_modules_.empty());
+      if (pending_modules_.empty())
+        return;
       SharedModuleInfo::ImportInfo info = pending_modules_.front();
+      if (extension->id() != info.extension_id)
+        return;
       pending_modules_.pop_front();
-      CHECK_EQ(extension->id(), info.extension_id);
 
       if (pending_modules_.empty()) {
         CHECK_EQ(extension->id(), id_);
diff --git a/chrome/browser/extensions/webstore_standalone_installer.h b/chrome/browser/extensions/webstore_standalone_installer.h
index 9175588..e102944 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.h
+++ b/chrome/browser/extensions/webstore_standalone_installer.h
@@ -124,6 +124,9 @@
   WebstoreInstaller::InstallSource install_source() const {
     return install_source_;
   }
+  Profile* profile() const { return profile_; }
+  const std::string& id() const { return id_; }
+  const DictionaryValue* manifest() const { return manifest_.get(); }
 
  private:
   friend class base::RefCountedThreadSafe<WebstoreStandaloneInstaller>;
diff --git a/chrome/browser/extensions/window_controller_list.cc b/chrome/browser/extensions/window_controller_list.cc
index 3c2b68b..608d3e5 100644
--- a/chrome/browser/extensions/window_controller_list.cc
+++ b/chrome/browser/extensions/window_controller_list.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/window_controller_list_observer.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "ui/base/base_window.h"
@@ -62,7 +62,7 @@
 }
 
 WindowController* WindowControllerList::FindWindowForFunctionById(
-    const UIThreadExtensionFunction* function,
+    const ChromeAsyncExtensionFunction* function,
     int id) const {
   WindowController* controller = FindWindowById(id);
   if (controller && function->CanOperateOnWindow(controller))
@@ -71,7 +71,7 @@
 }
 
 WindowController* WindowControllerList::CurrentWindowForFunction(
-    const UIThreadExtensionFunction* function) const {
+    const ChromeAsyncExtensionFunction* function) const {
   WindowController* result = NULL;
   // Returns either the focused window (if any), or the last window in the list.
   for (ControllerList::const_iterator iter = windows().begin();
diff --git a/chrome/browser/extensions/window_controller_list.h b/chrome/browser/extensions/window_controller_list.h
index 4b9b934..103069f 100644
--- a/chrome/browser/extensions/window_controller_list.h
+++ b/chrome/browser/extensions/window_controller_list.h
@@ -13,7 +13,7 @@
 #include "chrome/browser/extensions/window_controller.h"
 
 class Profile;
-class UIThreadExtensionFunction;
+class ChromeAsyncExtensionFunction;
 
 namespace extensions {
 
@@ -38,13 +38,13 @@
 
   // Returns a window matching the context the function was invoked in.
   WindowController* FindWindowForFunctionById(
-      const UIThreadExtensionFunction* function,
+      const ChromeAsyncExtensionFunction* function,
       int id) const;
 
   // Returns the focused or last added window matching the context the function
   // was invoked in.
   WindowController* CurrentWindowForFunction(
-      const UIThreadExtensionFunction* function) const;
+      const ChromeAsyncExtensionFunction* function) const;
 
   const ControllerList& windows() const { return windows_; }
 
diff --git a/chrome/browser/extensions/window_open_interactive_apitest.cc b/chrome/browser/extensions/window_open_interactive_apitest.cc
index 7cf4f66..ca82081 100644
--- a/chrome/browser/extensions/window_open_interactive_apitest.cc
+++ b/chrome/browser/extensions/window_open_interactive_apitest.cc
@@ -13,9 +13,8 @@
   }
 };
 
-// http://crbug.com/162912 || defined(OS_WIN)
 // http://crbug.com/253417 for NDEBUG
-#if defined(OS_MACOSX) && defined(NDEBUG)
+#if defined(OS_WIN) || (defined(OS_MACOSX) && defined(NDEBUG))
 // Focus test fails if there is no window manager on Linux.
 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, WindowOpenFocus) {
   ASSERT_TRUE(RunExtensionTest("window_open/focus")) << message_;
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index ac4f5f5..2f9b4d9 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -11,12 +11,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/platform_util.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
diff --git a/chrome/browser/favicon/favicon_handler.cc b/chrome/browser/favicon/favicon_handler.cc
index 5e1459c..57575cf 100644
--- a/chrome/browser/favicon/favicon_handler.cc
+++ b/chrome/browser/favicon/favicon_handler.cc
@@ -32,7 +32,7 @@
 
 // Size (along each axis) of a touch icon. This currently corresponds to
 // the apple touch icon for iPad.
-const int kTouchIconSize = 72;
+const int kTouchIconSize = 144;
 
 // Returns chrome::IconType the given icon_type corresponds to.
 chrome::IconType ToHistoryIconType(FaviconURL::IconType icon_type) {
@@ -47,27 +47,27 @@
       return chrome::INVALID_ICON;
   }
   NOTREACHED();
-  // Shouldn't reach here, just make compiler happy.
   return chrome::INVALID_ICON;
 }
 
 // Get the maximal icon size in pixels for a icon of type |icon_type| for the
 // current platform.
 int GetMaximalIconSize(chrome::IconType icon_type) {
-  int base_size = 0;
   switch (icon_type) {
     case chrome::FAVICON:
-      base_size = gfx::kFaviconSize;
-      break;
+#if defined(OS_ANDROID)
+      return 192;
+#else
+      return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
+#endif
     case chrome::TOUCH_ICON:
     case chrome::TOUCH_PRECOMPOSED_ICON:
-      base_size = kTouchIconSize;
-      break;
+      return kTouchIconSize;
     case chrome::INVALID_ICON:
-      base_size = 0;
-      break;
+      return 0;
   }
-  return gfx::ImageSkia::GetMaxSupportedScale() * base_size;
+  NOTREACHED();
+  return 0;
 }
 
 bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
diff --git a/chrome/browser/favicon/favicon_handler.h b/chrome/browser/favicon/favicon_handler.h
index 4feed38..91e8e8f 100644
--- a/chrome/browser/favicon/favicon_handler.h
+++ b/chrome/browser/favicon/favicon_handler.h
@@ -245,7 +245,11 @@
   // Returns the preferred_icon_size according icon_types_, 0 means no
   // preference.
   int preferred_icon_size() {
+#if defined(OS_ANDROID)
+    return 0;
+#else
     return icon_types_ == chrome::FAVICON ? gfx::kFaviconSize : 0;
+#endif
   }
 
   // Used for FaviconService requests.
diff --git a/chrome/browser/favicon/favicon_handler_unittest.cc b/chrome/browser/favicon/favicon_handler_unittest.cc
index 5671b73..40d0255 100644
--- a/chrome/browser/favicon/favicon_handler_unittest.cc
+++ b/chrome/browser/favicon/favicon_handler_unittest.cc
@@ -974,6 +974,8 @@
   EXPECT_FALSE(download_handler->HasDownload());
 }
 
+#if !defined(OS_ANDROID)
+
 // Test the favicon which is selected when the web page provides several
 // favicons and none of the favicons are cached in history.
 // The goal of this test is to be more of an integration test than
@@ -1063,6 +1065,8 @@
             handler4.GetEntry()->GetFavicon().url);
 }
 
+#endif
+
 static BrowserContextKeyedService* BuildFaviconService(
     content::BrowserContext* profile) {
   return new FaviconService(NULL);
diff --git a/chrome/browser/feedback/feedback_data.cc b/chrome/browser/feedback/feedback_data.cc
index 7c1aff7..95cb49f 100644
--- a/chrome/browser/feedback/feedback_data.cc
+++ b/chrome/browser/feedback/feedback_data.cc
@@ -7,6 +7,7 @@
 #include "base/file_util.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -34,6 +35,8 @@
 const char kTraceFilename[] = "tracing.zip\n";
 const char kPerformanceCategoryTag[] = "Performance";
 
+const char kZipExt[] = ".zip";
+
 const base::FilePath::CharType kLogsFilename[] =
     FILE_PATH_LITERAL("system_logs.txt");
 
@@ -67,12 +70,19 @@
   return syslogs_string;
 }
 
+void ZipFile(const base::FilePath& filename,
+             const std::string& data, std::string* compressed_data) {
+  if (!feedback_util::ZipString(filename, data, compressed_data))
+    compressed_data->clear();
+}
+
 void ZipLogs(FeedbackData::SystemLogsMap* sys_info,
              std::string* compressed_logs) {
   DCHECK(compressed_logs);
   std::string logs_string = LogsToString(sys_info);
   if (logs_string.empty() ||
-      !feedback_util::ZipString(kLogsFilename, logs_string, compressed_logs)) {
+      !feedback_util::ZipString(
+          base::FilePath(kLogsFilename), logs_string, compressed_logs)) {
     compressed_logs->clear();
   }
 }
@@ -93,6 +103,7 @@
                                trace_id_(0),
                                feedback_page_data_complete_(false),
                                syslogs_compression_complete_(false),
+                               attached_file_compression_complete_(false),
                                report_sent_(false) {
 }
 
@@ -133,6 +144,32 @@
   }
 }
 
+void FeedbackData::AttachAndCompressFileData(
+    scoped_ptr<std::string> attached_filedata) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  attached_filedata_ = attached_filedata.Pass();
+
+  if (!attached_filename_.empty() && attached_filedata_.get()) {
+    std::string* compressed_file_ptr = new std::string;
+    scoped_ptr<std::string> compressed_file(compressed_file_ptr);
+#if defined(OS_WIN)
+    base::FilePath attached_file(base::UTF8ToWide(attached_filename_));
+#else
+    base::FilePath attached_file(attached_filename_);
+#endif
+    BrowserThread::PostBlockingPoolTaskAndReply(
+        FROM_HERE,
+        base::Bind(&ZipFile,
+                   attached_file,
+                   *(attached_filedata_.get()),
+                   compressed_file_ptr),
+        base::Bind(&FeedbackData::OnCompressFileComplete,
+                   this,
+                   base::Passed(&compressed_file)));
+  }
+}
+
 void FeedbackData::OnGetTraceData(
     int trace_id_,
     scoped_refptr<base::RefCountedString> trace_data) {
@@ -143,8 +180,8 @@
 
   scoped_ptr<std::string> data(new std::string(trace_data->data()));
 
-  set_attached_filename(kTraceFilename);
-  set_attached_filedata(data.Pass());
+  attached_filename_ = kTraceFilename;
+  attached_filedata_ = data.Pass();
   trace_id_ = 0;
 
   set_category_tag(kPerformanceCategoryTag);
@@ -162,8 +199,25 @@
   SendReport();
 }
 
+void FeedbackData::OnCompressFileComplete(
+    scoped_ptr<std::string> compressed_file) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (compressed_file.get()) {
+    attached_filedata_ = compressed_file.Pass();
+    attached_filename_.append(kZipExt);
+    attached_file_compression_complete_ = true;
+  } else {
+    attached_filename_.clear();
+    attached_filedata_.reset(NULL);
+  }
+
+  SendReport();
+}
+
 bool FeedbackData::IsDataComplete() {
-  return (syslogs_compression_complete_ || !sys_info_.get()) &&
+  return (!sys_info_.get() || syslogs_compression_complete_) &&
+      (!attached_filedata_.get() || attached_file_compression_complete_) &&
       !trace_id_ &&
       feedback_page_data_complete_;
 }
diff --git a/chrome/browser/feedback/feedback_data.h b/chrome/browser/feedback/feedback_data.h
index a33ae12..49a6643 100644
--- a/chrome/browser/feedback/feedback_data.h
+++ b/chrome/browser/feedback/feedback_data.h
@@ -36,9 +36,16 @@
   // compression.
   void SetAndCompressSystemInfo(scoped_ptr<SystemLogsMap> sys_info);
 
+  // Sets the system information for this instance and kicks off its
+  // compression.
+  void AttachAndCompressFileData(scoped_ptr<std::string> attached_filedata);
+
   // Called once we have compressed our system logs.
   void OnCompressLogsComplete(scoped_ptr<std::string> compressed_logs);
 
+  // Called once we have compressed our attached file.
+  void OnCompressFileComplete(scoped_ptr<std::string> compressed_file);
+
   // Returns true if we've completed all the tasks needed before we can send
   // feedback - at this time this is includes getting the feedback page data
   // and compressing the system logs.
@@ -78,9 +85,6 @@
   void set_attached_filename(const std::string& attached_filename) {
     attached_filename_ = attached_filename;
   }
-  void set_attached_filedata(scoped_ptr<std::string> attached_filedata) {
-    attached_filedata_ = attached_filedata.Pass();
-  }
   void set_attached_file_uuid(const std::string& uuid) {
     attached_file_uuid_ = uuid;
   }
@@ -117,7 +121,7 @@
 
   bool feedback_page_data_complete_;
   bool syslogs_compression_complete_;
-
+  bool attached_file_compression_complete_;
   bool report_sent_;
 
   DISALLOW_COPY_AND_ASSIGN(FeedbackData);
diff --git a/chrome/browser/feedback/feedback_util.cc b/chrome/browser/feedback/feedback_util.cc
index 5df5fb3..43b13df 100644
--- a/chrome/browser/feedback/feedback_util.cc
+++ b/chrome/browser/feedback/feedback_util.cc
@@ -362,8 +362,8 @@
   DispatchFeedback(data->profile(), post_body, 0);
 }
 
-bool ZipString(const base::FilePath::CharType filename[],
-               const std::string& logs, std::string* compressed_logs) {
+bool ZipString(const base::FilePath& filename,
+               const std::string& data, std::string* compressed_logs) {
   base::FilePath temp_path;
   base::FilePath zip_file;
 
@@ -372,7 +372,7 @@
   if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &temp_path))
     return false;
   if (file_util::WriteFile(temp_path.Append(filename),
-                           logs.c_str(), logs.size()) == -1)
+                           data.c_str(), data.size()) == -1)
     return false;
   if (!file_util::CreateTemporaryFile(&zip_file))
     return false;
diff --git a/chrome/browser/feedback/feedback_util.h b/chrome/browser/feedback/feedback_util.h
index 2bf1b8a..1fc9e64 100644
--- a/chrome/browser/feedback/feedback_util.h
+++ b/chrome/browser/feedback/feedback_util.h
@@ -36,8 +36,8 @@
 namespace feedback_util {
 
   void SendReport(scoped_refptr<FeedbackData> data);
-  bool ZipString(const base::FilePath::CharType filename[],
-                 const std::string& logs, std::string* compressed_logs);
+  bool ZipString(const base::FilePath& filename,
+                 const std::string& data, std::string* compressed_data);
 
 }  // namespace feedback_util
 
diff --git a/chrome/browser/feedback/tracing_manager.cc b/chrome/browser/feedback/tracing_manager.cc
index 77fac8d..92dba45 100644
--- a/chrome/browser/feedback/tracing_manager.cc
+++ b/chrome/browser/feedback/tracing_manager.cc
@@ -99,7 +99,8 @@
   data_ = std::string("[") + data_ + "]";
 
   std::string output_val;
-  feedback_util::ZipString(kTracingFilename, data_, &output_val);
+  feedback_util::ZipString(
+      base::FilePath(kTracingFilename), data_, &output_val);
 
   scoped_refptr<base::RefCountedString> output(
       base::RefCountedString::TakeString(&output_val));
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index 017eb9a..e0fa43a 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -716,9 +716,6 @@
     int import_items,
     int dont_import_items,
     const std::string& import_bookmarks_path) {
-  // Deletes itself.
-  ExternalProcessImporterHost* importer_host = new ExternalProcessImporterHost;
-
   base::FilePath local_state_path;
   PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
   bool local_state_file_exists = base::PathExists(local_state_path);
@@ -729,10 +726,6 @@
 
   // Do import if there is an available profile for us to import.
   if (importer_list->count() > 0) {
-    // Don't show the warning dialog if import fails.
-    importer_host->set_headless();
-    int items = 0;
-
     if (internal::IsOrganicFirstRun()) {
       // Home page is imported in organic builds only unless turned off or
       // defined in master_preferences.
@@ -751,6 +744,7 @@
     }
 
     PrefService* user_prefs = profile->GetPrefs();
+    int items = 0;
 
     SetImportItem(user_prefs,
                   prefs::kImportHistory,
@@ -777,6 +771,13 @@
                   importer::FAVORITES,
                   &items);
 
+    // Deletes itself.
+    ExternalProcessImporterHost* importer_host =
+        new ExternalProcessImporterHost;
+
+    // Don't show the warning dialog if import fails.
+    importer_host->set_headless();
+
     importer::LogImporterUseToMetrics(
         "AutoImport", importer_list->GetSourceProfileAt(0).importer_type);
 
diff --git a/chrome/browser/first_run/try_chrome_dialog_view.cc b/chrome/browser/first_run/try_chrome_dialog_view.cc
index c8ef28c..430ce5b 100644
--- a/chrome/browser/first_run/try_chrome_dialog_view.cc
+++ b/chrome/browser/first_run/try_chrome_dialog_view.cc
@@ -283,7 +283,7 @@
   HWND toast_window;
 #if defined(USE_AURA)
   toast_window =
-      popup_->GetNativeView()->GetRootWindow()->GetAcceleratedWidget();
+      popup_->GetNativeView()->GetDispatcher()->GetAcceleratedWidget();
 #else
   toast_window = popup_->GetNativeView();
 #endif
diff --git a/chrome/browser/geolocation/chrome_access_token_store.cc b/chrome/browser/geolocation/chrome_access_token_store.cc
index cefb644..00b9098 100644
--- a/chrome/browser/geolocation/chrome_access_token_store.cc
+++ b/chrome/browser/geolocation/chrome_access_token_store.cc
@@ -7,11 +7,11 @@
 #include "base/bind.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/google_apis/base_requests.cc b/chrome/browser/google_apis/base_requests.cc
index 1336eec..e349517 100644
--- a/chrome/browser/google_apis/base_requests.cc
+++ b/chrome/browser/google_apis/base_requests.cc
@@ -11,6 +11,8 @@
 #include "base/task_runner_util.h"
 #include "base/values.h"
 #include "chrome/browser/google_apis/request_sender.h"
+#include "chrome/browser/google_apis/task_util.h"
+#include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
@@ -99,6 +101,56 @@
       callback);
 }
 
+//=========================== ResponseWriter ==================================
+ResponseWriter::ResponseWriter(base::TaskRunner* file_task_runner,
+                               const base::FilePath& file_path,
+                               const GetContentCallback& get_content_callback)
+    : get_content_callback_(get_content_callback) {
+  if (!file_path.empty()) {
+    file_writer_.reset(
+        new net::URLFetcherFileWriter(file_task_runner, file_path));
+  }
+}
+
+ResponseWriter::~ResponseWriter() {
+}
+
+void ResponseWriter::DisownFile() {
+  DCHECK(file_writer_);
+  file_writer_->DisownFile();
+}
+
+int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
+  if (file_writer_)
+    return file_writer_->Initialize(callback);
+
+  data_.clear();
+  return net::OK;
+}
+
+int ResponseWriter::Write(net::IOBuffer* buffer,
+                          int num_bytes,
+                          const net::CompletionCallback& callback) {
+  if (!get_content_callback_.is_null()) {
+    get_content_callback_.Run(
+        HTTP_SUCCESS,
+        make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
+  }
+
+  if (file_writer_)
+    return file_writer_->Write(buffer, num_bytes, callback);
+
+  data_.append(buffer->data(), num_bytes);
+  return num_bytes;
+}
+
+int ResponseWriter::Finish(const net::CompletionCallback& callback) {
+  if (file_writer_)
+    return file_writer_->Finish(callback);
+
+  return net::OK;
+}
+
 //============================ UrlFetchRequestBase ===========================
 
 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
@@ -139,11 +191,15 @@
       net::LOAD_DISABLE_CACHE);
 
   base::FilePath output_file_path;
-  if (GetOutputFilePath(&output_file_path)) {
-    url_fetcher_->SaveResponseToFileAtPath(
-        output_file_path,
-        blocking_task_runner());
-  }
+  GetContentCallback get_content_callback;
+  GetOutputFilePath(&output_file_path, &get_content_callback);
+  if (!get_content_callback.is_null())
+    get_content_callback = CreateRelayCallback(get_content_callback);
+  response_writer_ = new ResponseWriter(blocking_task_runner(),
+                                        output_file_path,
+                                        get_content_callback);
+  url_fetcher_->SaveResponseWithWriter(
+      scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
 
   // Add request headers.
   // Note that SetExtraRequestHeaders clears the current headers and sets it
@@ -215,11 +271,13 @@
   return false;
 }
 
-bool UrlFetchRequestBase::GetOutputFilePath(base::FilePath* local_file_path) {
-  return false;
+void UrlFetchRequestBase::GetOutputFilePath(
+    base::FilePath* local_file_path,
+    GetContentCallback* get_content_callback) {
 }
 
 void UrlFetchRequestBase::Cancel() {
+  response_writer_ = NULL;
   url_fetcher_.reset(NULL);
   RunCallbackOnPrematureFailure(GDATA_CANCELLED);
   sender_->RequestFinished(this);
@@ -329,15 +387,12 @@
 }
 
 void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) {
-  std::string data;
-  source->GetResponseAsString(&data);
-  scoped_ptr<base::Value> root_value;
   GDataErrorCode fetch_error_code = GetErrorCode(source);
 
   switch (fetch_error_code) {
     case HTTP_SUCCESS:
     case HTTP_CREATED:
-      ParseResponse(fetch_error_code, data);
+      ParseResponse(fetch_error_code, response_writer()->data());
       break;
     default:
       RunCallbackOnPrematureFailure(fetch_error_code);
@@ -490,11 +545,8 @@
   } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
     // The upload is successfully done. Parse the response which should be
     // the entry's metadata.
-    std::string response_content;
-    source->GetResponseAsString(&response_content);
-
     ParseJson(blocking_task_runner(),
-              response_content,
+              response_writer()->data(),
               base::Bind(&UploadRangeRequestBase::OnDataParsed,
                          weak_ptr_factory_.GetWeakPtr(),
                          code));
@@ -638,11 +690,12 @@
   return download_url_;
 }
 
-bool DownloadFileRequestBase::GetOutputFilePath(
-    base::FilePath* local_file_path) {
+void DownloadFileRequestBase::GetOutputFilePath(
+    base::FilePath* local_file_path,
+    GetContentCallback* get_content_callback) {
   // Configure so that the downloaded content is saved to |output_file_path_|.
   *local_file_path = output_file_path_;
-  return true;
+  *get_content_callback = get_content_callback_;
 }
 
 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
@@ -653,26 +706,14 @@
     progress_callback_.Run(current, total);
 }
 
-bool DownloadFileRequestBase::ShouldSendDownloadData() {
-  return !get_content_callback_.is_null();
-}
-
-void DownloadFileRequestBase::OnURLFetchDownloadData(
-    const URLFetcher* source,
-    scoped_ptr<std::string> download_data) {
-  if (!get_content_callback_.is_null())
-    get_content_callback_.Run(HTTP_SUCCESS, download_data.Pass());
-}
-
 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
   GDataErrorCode code = GetErrorCode(source);
 
   // Take over the ownership of the the downloaded temp file.
   base::FilePath temp_file;
-  if (code == HTTP_SUCCESS &&
-      !source->GetResponseAsFilePath(true,  // take_ownership
-                                     &temp_file)) {
-    code = GDATA_FILE_ERROR;
+  if (code == HTTP_SUCCESS) {
+    response_writer()->DisownFile();
+    temp_file = output_file_path_;
   }
 
   download_action_callback_.Run(code, temp_file);
diff --git a/chrome/browser/google_apis/base_requests.h b/chrome/browser/google_apis/base_requests.h
index b0eec46..6ebdcf6 100644
--- a/chrome/browser/google_apis/base_requests.h
+++ b/chrome/browser/google_apis/base_requests.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_fetcher_response_writer.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -35,6 +36,11 @@
 // Callback used for DownloadFileRequest and ResumeUploadRequestBase.
 typedef base::Callback<void(int64 progress, int64 total)> ProgressCallback;
 
+// Callback used to get the content from DownloadFileRequest.
+typedef base::Callback<void(
+    GDataErrorCode error,
+    scoped_ptr<std::string> content)> GetContentCallback;
+
 // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
 // the calling thread when finished with either success or failure.
 // The callback must not be null.
@@ -81,6 +87,38 @@
   virtual void Cancel() = 0;
 };
 
+//=========================== ResponseWriter ==================================
+
+// Saves the response for the request to a file or string.
+class ResponseWriter : public net::URLFetcherResponseWriter {
+ public:
+  // If file_path is not empty, the response will be saved with file_writer_,
+  // otherwise it will be saved to data_.
+  ResponseWriter(base::TaskRunner* file_task_runner,
+                 const base::FilePath& file_path,
+                 const GetContentCallback& get_content_callback);
+  virtual ~ResponseWriter();
+
+  const std::string& data() const { return data_; }
+
+  // Disowns the output file.
+  void DisownFile();
+
+  // URLFetcherResponseWriter overrides:
+  virtual int Initialize(const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Write(net::IOBuffer* buffer,
+                    int num_bytes,
+                    const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Finish(const net::CompletionCallback& callback) OVERRIDE;
+
+ private:
+  const GetContentCallback get_content_callback_;
+  std::string data_;
+  scoped_ptr<net::URLFetcherFileWriter> file_writer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
+};
+
 //============================ UrlFetchRequestBase ===========================
 
 // Base class for requests that are fetching URLs.
@@ -128,7 +166,10 @@
 
   // Used by a derived class to set an output file path if they want to save
   // the downloaded content to a file at a specific path.
-  virtual bool GetOutputFilePath(base::FilePath* local_file_path);
+  // Sets |get_content_callback|, which is called when some part of the response
+  // is read.
+  virtual void GetOutputFilePath(base::FilePath* local_file_path,
+                                 GetContentCallback* get_content_callback);
 
   // Invoked by OnURLFetchComplete when the request completes without an
   // authentication error. Must be implemented by a derived class.
@@ -148,6 +189,9 @@
   // Returns true if called on the thread where the constructor was called.
   bool CalledOnValidThread();
 
+  // Returns the writer which is used to save the response for the request.
+  ResponseWriter* response_writer() const { return response_writer_; }
+
   // Returns the task runner that should be used for blocking tasks.
   base::TaskRunner* blocking_task_runner() const;
 
@@ -161,6 +205,7 @@
   ReAuthenticateCallback re_authenticate_callback_;
   int re_authenticate_count_;
   scoped_ptr<net::URLFetcher> url_fetcher_;
+  ResponseWriter* response_writer_;  // Owned by |url_fetcher_|.
   RequestSender* sender_;
 
   base::ThreadChecker thread_checker_;
@@ -426,11 +471,6 @@
 
 //============================ DownloadFileRequest ===========================
 
-// Callback type for getting the content from DownloadFileRequest.
-typedef base::Callback<void(
-    GDataErrorCode error,
-    scoped_ptr<std::string> content)> GetContentCallback;
-
 // Callback type for receiving the completion of DownloadFileRequest.
 typedef base::Callback<void(GDataErrorCode error,
                             const base::FilePath& temp_file)>
@@ -468,17 +508,15 @@
  protected:
   // UrlFetchRequestBase overrides.
   virtual GURL GetURL() const OVERRIDE;
-  virtual bool GetOutputFilePath(base::FilePath* local_file_path) OVERRIDE;
+  virtual void GetOutputFilePath(
+      base::FilePath* local_file_path,
+      GetContentCallback* get_content_callback) OVERRIDE;
   virtual void ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE;
   virtual void RunCallbackOnPrematureFailure(GDataErrorCode code) OVERRIDE;
 
   // net::URLFetcherDelegate overrides.
   virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source,
                                           int64 current, int64 total) OVERRIDE;
-  virtual bool ShouldSendDownloadData() OVERRIDE;
-  virtual void OnURLFetchDownloadData(
-      const net::URLFetcher* source,
-      scoped_ptr<std::string> download_data) OVERRIDE;
 
  private:
   const DownloadActionCallback download_action_callback_;
diff --git a/chrome/browser/google_apis/base_requests_server_unittest.cc b/chrome/browser/google_apis/base_requests_server_unittest.cc
index 896ad0e..a66c25a 100644
--- a/chrome/browser/google_apis/base_requests_server_unittest.cc
+++ b/chrome/browser/google_apis/base_requests_server_unittest.cc
@@ -30,8 +30,7 @@
 
 class BaseRequestsServerTest : public testing::Test {
  protected:
-  BaseRequestsServerTest()
-      : test_server_(message_loop_.message_loop_proxy()) {
+  BaseRequestsServerTest() {
   }
 
   virtual void SetUp() OVERRIDE {
diff --git a/chrome/browser/google_apis/drive_api_requests_unittest.cc b/chrome/browser/google_apis/drive_api_requests_unittest.cc
index 99878d3..9a7c72c 100644
--- a/chrome/browser/google_apis/drive_api_requests_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_requests_unittest.cc
@@ -53,8 +53,7 @@
 
 class DriveApiRequestsTest : public testing::Test {
  public:
-  DriveApiRequestsTest()
-      : test_server_(message_loop_.message_loop_proxy()) {
+  DriveApiRequestsTest() {
   }
 
   virtual void SetUp() OVERRIDE {
diff --git a/chrome/browser/google_apis/gdata_contacts_requests.cc b/chrome/browser/google_apis/gdata_contacts_requests.cc
index 35d1a4a..eb1c51b 100644
--- a/chrome/browser/google_apis/gdata_contacts_requests.cc
+++ b/chrome/browser/google_apis/gdata_contacts_requests.cc
@@ -101,8 +101,7 @@
 void GetContactPhotoRequest::ProcessURLFetchResults(
     const net::URLFetcher* source) {
   GDataErrorCode code = GetErrorCode(source);
-  scoped_ptr<std::string> data(new std::string);
-  source->GetResponseAsString(data.get());
+  scoped_ptr<std::string> data(new std::string(response_writer()->data()));
   callback_.Run(code, data.Pass());
   OnProcessURLFetchResultsComplete();
 }
diff --git a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
index 399925b..cbf89d4 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
+++ b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
@@ -39,8 +39,7 @@
 
 class GDataWapiRequestsTest : public testing::Test {
  public:
-  GDataWapiRequestsTest()
-      : test_server_(message_loop_.message_loop_proxy()) {
+  GDataWapiRequestsTest() {
   }
 
   virtual void SetUp() OVERRIDE {
diff --git a/chrome/browser/gpu/chrome_gpu_util.cc b/chrome/browser/gpu/chrome_gpu_util.cc
deleted file mode 100644
index 5904713..0000000
--- a/chrome/browser/gpu/chrome_gpu_util.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2012 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/gpu/chrome_gpu_util.h"
-
-#include "base/command_line.h"
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#endif
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
-#include "base/version.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_list_observer.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/chrome_version_info.h"
-#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/content_switches.h"
-
-using content::GpuDataManager;
-
-namespace gpu_util {
-
-void DisableCompositingFieldTrial() {
-  base::FieldTrial* trial =
-      base::FieldTrialList::Find(content::kGpuCompositingFieldTrialName);
-  if (trial)
-    trial->Disable();
-}
-
-bool ShouldRunCompositingFieldTrial() {
-// Enable the field trial only on desktop OS's.
-#if !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
-  return false;
-#endif
-
-// Necessary for linux_chromeos build since it defines both OS_LINUX
-// and OS_CHROMEOS.
-#if defined(OS_CHROMEOS)
-  return false;
-#endif
-
-  // Don't activate the field trial if force-compositing-mode has been
-  // explicitly disabled from the command line.
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableForceCompositingMode) ||
-      CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableAcceleratedCompositing))
-    return false;
-
-  return true;
-}
-
-// Note 1: The compositing field trial may be created at startup time via the
-// Finch framework. In that case, all the Groups and probability values are
-// set before this function is called and any Field Trial setup calls
-// made here are simply ignored.
-// Note 2: Compositing field trials will be overwritten if accelerated
-// compositing is blacklisted. That check takes place in
-// IsThreadedCompositingEnabled() and IsForceCompositingModeEnabled() as
-// the blacklist information isn't available at the time the field trials
-// are initialized.
-// Early outs from this function intended to bypass activation of the field
-// trial must call DisableCompositingFieldTrial() before returning.
-void InitializeCompositingFieldTrial() {
-  // Early out in configurations that should not run the compositing
-  // field trial.
-  if (!ShouldRunCompositingFieldTrial()) {
-    DisableCompositingFieldTrial();
-    return;
-  }
-
-  const base::FieldTrial::Probability kDivisor = 3;
-  scoped_refptr<base::FieldTrial> trial(
-    base::FieldTrialList::FactoryGetFieldTrial(
-        content::kGpuCompositingFieldTrialName, kDivisor,  "disable",
-        2013, 12, 31, base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
-
-  base::FieldTrial::Probability force_compositing_mode_probability = 0;
-  base::FieldTrial::Probability threaded_compositing_probability = 0;
-
-  // Note: Threaded compositing mode isn't feature complete on mac or linux yet:
-  // http://crbug.com/133602 for mac
-  // http://crbug.com/140866 for linux
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  // Enable threaded compositing on Windows and Mac.
-  threaded_compositing_probability = kDivisor;
-#endif
-
-  int force_compositing_group = trial->AppendGroup(
-      content::kGpuCompositingFieldTrialForceCompositingEnabledName,
-      force_compositing_mode_probability);
-  int thread_group = trial->AppendGroup(
-      content::kGpuCompositingFieldTrialThreadEnabledName,
-      threaded_compositing_probability);
-
-  bool force_compositing = (trial->group() == force_compositing_group);
-  bool thread = (trial->group() == thread_group);
-  UMA_HISTOGRAM_BOOLEAN("GPU.InForceCompositingModeFieldTrial",
-                        force_compositing);
-  UMA_HISTOGRAM_BOOLEAN("GPU.InCompositorThreadFieldTrial", thread);
-}
-
-}  // namespace gpu_util
-
diff --git a/chrome/browser/gpu/chrome_gpu_util.h b/chrome/browser/gpu/chrome_gpu_util.h
deleted file mode 100644
index 1edff61..0000000
--- a/chrome/browser/gpu/chrome_gpu_util.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2012 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_GPU_CHROME_GPU_UTIL_H_
-#define CHROME_BROWSER_GPU_CHROME_GPU_UTIL_H_
-
-namespace gpu_util {
-
-// Sets up force-compositing-mode and threaded compositing field trials.
-void InitializeCompositingFieldTrial();
-
-}  // namespace gpu_util
-
-#endif  // CHROME_BROWSER_GPU_CHROME_GPU_UTIL_H_
-
diff --git a/chrome/browser/guestview/webview/webview_guest.cc b/chrome/browser/guestview/webview/webview_guest.cc
index aa23b9e..d5c66fb 100644
--- a/chrome/browser/guestview/webview/webview_guest.cc
+++ b/chrome/browser/guestview/webview/webview_guest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
 #include "chrome/browser/extensions/extension_renderer_state.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
 #include "chrome/browser/extensions/script_executor.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/guestview/guestview_constants.h"
@@ -98,6 +99,7 @@
 
 void AttachWebViewHelpers(WebContents* contents) {
   FaviconTabHelper::CreateForWebContents(contents);
+  extensions::ExtensionWebContentsObserver::CreateForWebContents(contents);
 #if defined(ENABLE_PLUGINS)
   PluginPermissionHelper::CreateForWebContents(contents);
 #endif
diff --git a/chrome/browser/history/DEPS b/chrome/browser/history/DEPS
index 2d684dc..ede6270 100644
--- a/chrome/browser/history/DEPS
+++ b/chrome/browser/history/DEPS
@@ -8,6 +8,8 @@
   "+chrome/browser/favicon",
   "+chrome/browser/history",
   "+chrome/browser/network_time",
+  "+chrome/tools/profiles",  # For history unit tests.
+  "+components/visitedlink/browser",
 
   # TODO(erikwright): Bring this list to zero.
   #
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index f766a0b..959d118 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.cc
@@ -287,6 +287,14 @@
       title(title) {
 }
 
+MostVisitedURL::MostVisitedURL(const GURL& url,
+                               const string16& title,
+                               const base::Time& last_forced_time)
+    : url(url),
+      title(title),
+      last_forced_time(last_forced_time) {
+}
+
 MostVisitedURL::~MostVisitedURL() {}
 
 // FilteredURL -----------------------------------------------------------------
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index f23a310..a24a79a 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -509,11 +509,19 @@
 struct MostVisitedURL {
   MostVisitedURL();
   MostVisitedURL(const GURL& url, const string16& title);
+  MostVisitedURL(const GURL& url,
+                 const string16& title,
+                 const base::Time& last_forced_time);
   ~MostVisitedURL();
 
   GURL url;
   string16 title;
 
+  // If this is a URL for which we want to force a thumbnail, records the last
+  // time it was forced so we can evict it when more recent URLs are requested.
+  // If it's not a forced thumbnail, keep a time of 0.
+  base::Time last_forced_time;
+
   RedirectList redirects;
 
   bool operator==(const MostVisitedURL& other) {
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 19788d9..fcce91f 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -668,140 +668,28 @@
 ThumbnailDatabase::ThumbnailDatabase() {
 }
 
-sql::InitStatus ThumbnailDatabase::CantUpgradeToVersion(int cur_version) {
-  LOG(WARNING) << "Unable to update to thumbnail database to version " <<
-               cur_version << ".";
-  db_.Close();
-  return sql::INIT_FAILURE;
-}
-
 ThumbnailDatabase::~ThumbnailDatabase() {
   // The DBCloseScoper will delete the DB and the cache.
 }
 
 sql::InitStatus ThumbnailDatabase::Init(const base::FilePath& db_name) {
-  sql::InitStatus status = OpenDatabase(&db_, db_name);
-  if (status != sql::INIT_OK)
-    return status;
+  // TODO(shess): Consider separating database open from schema setup.
+  // With that change, this code could Raze() from outside the
+  // transaction, rather than needing RazeAndClose() in InitImpl().
 
-  // Clear databases which are too old to process.
-  DCHECK_LT(kDeprecatedVersionNumber, kCurrentVersionNumber);
-  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
+  // Retry failed setup in case the recovery system fixed things.
+  const size_t kAttempts = 2;
 
-  // TODO(shess): Sqlite.Version.Thumbnail shows versions 22, 23, and
-  // 25.  Future versions are not destroyed because that could lead to
-  // data loss if the profile is opened by a later channel, but
-  // perhaps a heuristic like >kCurrentVersionNumber+3 could be used.
+  sql::InitStatus status = sql::INIT_FAILURE;
+  for (size_t i = 0; i < kAttempts; ++i) {
+    status = InitImpl(db_name);
+    if (status == sql::INIT_OK)
+      return status;
 
-  // Scope initialization in a transaction so we can't be partially initialized.
-  sql::Transaction transaction(&db_);
-  transaction.Begin();
-
-#if defined(OS_MACOSX)
-  // Exclude the thumbnails file from backups.
-  base::mac::SetFileBackupExclusion(db_name);
-#endif
-
-  // thumbnails table has been obsolete for a long time, remove any
-  // detrious.
-  ignore_result(db_.Execute("DROP TABLE IF EXISTS thumbnails"));
-
-  // Create the tables.
-  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
-                        kCompatibleVersionNumber) ||
-      !InitTables(&db_) ||
-      !InitIndices(&db_)) {
+    meta_table_.Reset();
     db_.Close();
-    return sql::INIT_FAILURE;
   }
-
-  // Version check. We should not encounter a database too old for us to handle
-  // in the wild, so we try to continue in that case.
-  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
-    LOG(WARNING) << "Thumbnail database is too new.";
-    return sql::INIT_TOO_NEW;
-  }
-
-  int cur_version = meta_table_.GetVersionNumber();
-
-  if (!db_.DoesColumnExist("favicons", "icon_type")) {
-    LOG(ERROR) << "Raze because of missing favicon.icon_type";
-    RecordInvalidStructure(STRUCTURE_EVENT_VERSION4);
-
-    db_.RazeAndClose();
-    return sql::INIT_FAILURE;
-  }
-
-  if (cur_version < 7 && !db_.DoesColumnExist("favicons", "sizes")) {
-    LOG(ERROR) << "Raze because of missing favicon.sizes";
-    RecordInvalidStructure(STRUCTURE_EVENT_VERSION5);
-
-    db_.RazeAndClose();
-    return sql::INIT_FAILURE;
-  }
-
-  if (cur_version == 5) {
-    ++cur_version;
-    if (!UpgradeToVersion6())
-      return CantUpgradeToVersion(cur_version);
-  }
-
-  if (cur_version == 6) {
-    ++cur_version;
-    if (!UpgradeToVersion7())
-      return CantUpgradeToVersion(cur_version);
-  }
-
-  LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
-      "Thumbnail database version " << cur_version << " is too old to handle.";
-
-  // Initialization is complete.
-  if (!transaction.Commit()) {
-    db_.Close();
-    return sql::INIT_FAILURE;
-  }
-
-  // Raze the database if the structure of the favicons database is not what
-  // it should be. This error cannot be detected via the SQL error code because
-  // the error code for running SQL statements against a database with missing
-  // columns is SQLITE_ERROR which is not unique enough to act upon.
-  // TODO(pkotwicz): Revisit this in M27 and see if the razing can be removed.
-  // (crbug.com/166453)
-  if (IsFaviconDBStructureIncorrect()) {
-    LOG(ERROR) << "Raze because of invalid favicon db structure.";
-    RecordInvalidStructure(STRUCTURE_EVENT_FAVICON);
-
-    db_.RazeAndClose();
-    return sql::INIT_FAILURE;
-  }
-
-  return sql::INIT_OK;
-}
-
-sql::InitStatus ThumbnailDatabase::OpenDatabase(sql::Connection* db,
-                                                const base::FilePath& db_name) {
-  size_t startup_kb = 0;
-  int64 size_64;
-  if (file_util::GetFileSize(db_name, &size_64))
-    startup_kb = static_cast<size_t>(size_64 / 1024);
-
-  db->set_histogram_tag("Thumbnail");
-  db->set_error_callback(base::Bind(&DatabaseErrorCallback,
-                                    db, db_name, startup_kb));
-
-  // Thumbnails db now only stores favicons, so we don't need that big a page
-  // size or cache.
-  db->set_page_size(2048);
-  db->set_cache_size(32);
-
-  // Run the database in exclusive mode. Nobody else should be accessing the
-  // database while we're running, and this will give somewhat improved perf.
-  db->set_exclusive_locking();
-
-  if (!db->Open(db_name))
-    return sql::INIT_FAILURE;
-
-  return sql::INIT_OK;
+  return status;
 }
 
 void ThumbnailDatabase::ComputeDatabaseMetrics() {
@@ -812,10 +700,6 @@
       favicon_count.Step() ? favicon_count.ColumnInt(0) : 0);
 }
 
-bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() {
-  return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons");
-}
-
 void ThumbnailDatabase::BeginTransaction() {
   db_.BeginTransaction();
 }
@@ -1126,6 +1010,20 @@
   return result;
 }
 
+IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
+                                                chrome::FaviconID icon_id) {
+  const char kSql[] =
+      "INSERT INTO icon_mapping (page_url, icon_id) VALUES (?, ?)";
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSql));
+  statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
+  statement.BindInt64(1, icon_id);
+
+  if (!statement.Run())
+    return 0;
+
+  return db_.GetLastInsertRowId();
+}
+
 bool ThumbnailDatabase::UpdateIconMapping(IconMappingID mapping_id,
                                           chrome::FaviconID icon_id) {
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
@@ -1227,6 +1125,7 @@
       statement.BindString(0, URLDatabase::GURLToDatabaseURL(*i));
       if (!statement.Run())
         return false;
+      statement.Reset(true);
     }
   }
 
@@ -1303,22 +1202,147 @@
   return transaction.Commit();
 }
 
-IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
-                                                chrome::FaviconID icon_id) {
-  const char kSql[] =
-      "INSERT INTO icon_mapping (page_url, icon_id) VALUES (?, ?)";
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
-  statement.BindInt64(1, icon_id);
+sql::InitStatus ThumbnailDatabase::OpenDatabase(sql::Connection* db,
+                                                const base::FilePath& db_name) {
+  size_t startup_kb = 0;
+  int64 size_64;
+  if (file_util::GetFileSize(db_name, &size_64))
+    startup_kb = static_cast<size_t>(size_64 / 1024);
 
-  if (!statement.Run())
-    return 0;
+  db->set_histogram_tag("Thumbnail");
+  db->set_error_callback(base::Bind(&DatabaseErrorCallback,
+                                    db, db_name, startup_kb));
 
-  return db_.GetLastInsertRowId();
+  // Thumbnails db now only stores favicons, so we don't need that big a page
+  // size or cache.
+  db->set_page_size(2048);
+  db->set_cache_size(32);
+
+  // Run the database in exclusive mode. Nobody else should be accessing the
+  // database while we're running, and this will give somewhat improved perf.
+  db->set_exclusive_locking();
+
+  if (!db->Open(db_name))
+    return sql::INIT_FAILURE;
+
+  return sql::INIT_OK;
 }
 
-bool ThumbnailDatabase::IsLatestVersion() {
-  return meta_table_.GetVersionNumber() == kCurrentVersionNumber;
+sql::InitStatus ThumbnailDatabase::InitImpl(const base::FilePath& db_name) {
+  sql::InitStatus status = OpenDatabase(&db_, db_name);
+  if (status != sql::INIT_OK)
+    return status;
+
+  // Clear databases which are too old to process.
+  DCHECK_LT(kDeprecatedVersionNumber, kCurrentVersionNumber);
+  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
+
+  // TODO(shess): Sqlite.Version.Thumbnail shows versions 22, 23, and
+  // 25.  Future versions are not destroyed because that could lead to
+  // data loss if the profile is opened by a later channel, but
+  // perhaps a heuristic like >kCurrentVersionNumber+3 could be used.
+
+  // Scope initialization in a transaction so we can't be partially initialized.
+  sql::Transaction transaction(&db_);
+  if (!transaction.Begin())
+    return sql::INIT_FAILURE;
+
+  // TODO(shess): Failing Begin() implies that something serious is
+  // wrong with the database.  Raze() may be in order.
+
+#if defined(OS_MACOSX)
+  // Exclude the thumbnails file from backups.
+  base::mac::SetFileBackupExclusion(db_name);
+#endif
+
+  // thumbnails table has been obsolete for a long time, remove any
+  // detrious.
+  ignore_result(db_.Execute("DROP TABLE IF EXISTS thumbnails"));
+
+  // At some point, operations involving temporary tables weren't done
+  // atomically and users have been stranded.  Drop those tables and
+  // move on.
+  // TODO(shess): Prove it?  Audit all cases and see if it's possible
+  // that this implies non-atomic update, and should thus be handled
+  // via the corruption handler.
+  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicons"));
+  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicon_bitmaps"));
+  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_icon_mapping"));
+
+  // Create the tables.
+  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
+                        kCompatibleVersionNumber) ||
+      !InitTables(&db_) ||
+      !InitIndices(&db_)) {
+    return sql::INIT_FAILURE;
+  }
+
+  // Version check. We should not encounter a database too old for us to handle
+  // in the wild, so we try to continue in that case.
+  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
+    LOG(WARNING) << "Thumbnail database is too new.";
+    return sql::INIT_TOO_NEW;
+  }
+
+  int cur_version = meta_table_.GetVersionNumber();
+
+  if (!db_.DoesColumnExist("favicons", "icon_type")) {
+    LOG(ERROR) << "Raze because of missing favicon.icon_type";
+    RecordInvalidStructure(STRUCTURE_EVENT_VERSION4);
+
+    db_.RazeAndClose();
+    return sql::INIT_FAILURE;
+  }
+
+  if (cur_version < 7 && !db_.DoesColumnExist("favicons", "sizes")) {
+    LOG(ERROR) << "Raze because of missing favicon.sizes";
+    RecordInvalidStructure(STRUCTURE_EVENT_VERSION5);
+
+    db_.RazeAndClose();
+    return sql::INIT_FAILURE;
+  }
+
+  if (cur_version == 5) {
+    ++cur_version;
+    if (!UpgradeToVersion6())
+      return CantUpgradeToVersion(cur_version);
+  }
+
+  if (cur_version == 6) {
+    ++cur_version;
+    if (!UpgradeToVersion7())
+      return CantUpgradeToVersion(cur_version);
+  }
+
+  LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
+      "Thumbnail database version " << cur_version << " is too old to handle.";
+
+  // Initialization is complete.
+  if (!transaction.Commit())
+    return sql::INIT_FAILURE;
+
+  // Raze the database if the structure of the favicons database is not what
+  // it should be. This error cannot be detected via the SQL error code because
+  // the error code for running SQL statements against a database with missing
+  // columns is SQLITE_ERROR which is not unique enough to act upon.
+  // TODO(pkotwicz): Revisit this in M27 and see if the razing can be removed.
+  // (crbug.com/166453)
+  if (IsFaviconDBStructureIncorrect()) {
+    LOG(ERROR) << "Raze because of invalid favicon db structure.";
+    RecordInvalidStructure(STRUCTURE_EVENT_FAVICON);
+
+    db_.RazeAndClose();
+    return sql::INIT_FAILURE;
+  }
+
+  return sql::INIT_OK;
+}
+
+sql::InitStatus ThumbnailDatabase::CantUpgradeToVersion(int cur_version) {
+  LOG(WARNING) << "Unable to update to thumbnail database to version " <<
+               cur_version << ".";
+  db_.Close();
+  return sql::INIT_FAILURE;
 }
 
 bool ThumbnailDatabase::UpgradeToVersion6() {
@@ -1338,6 +1362,7 @@
                   "SELECT id, url, icon_type FROM favicons") &&
       db_.Execute("DROP TABLE favicons") &&
       db_.Execute("ALTER TABLE temp_favicons RENAME TO favicons");
+  // NOTE(shess): v7 will re-create the index.
   if (!success)
     return false;
 
@@ -1369,4 +1394,8 @@
   return true;
 }
 
+bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() {
+  return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons");
+}
+
 }  // namespace history
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index 6ac1a2d..f5e9fd2 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -39,13 +39,6 @@
   // When not INIT_OK, no other functions should be called.
   sql::InitStatus Init(const base::FilePath& db_name);
 
-  // Open database on a given filename. If the file does not exist,
-  // it is created.
-  // |db| is the database to open.
-  // |db_name| is a path to the database file.
-  static sql::InitStatus OpenDatabase(sql::Connection* db,
-                                      const base::FilePath& db_name);
-
   // Computes and records various metrics for the database. Should only be
   // called once and only upon successful Init.
   void ComputeDatabaseMetrics();
@@ -237,16 +230,25 @@
   bool RetainDataForPageUrls(const std::vector<GURL>& urls_to_keep);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, RetainDataForPageUrls);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, Version3);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, Version4);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, Version5);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, Version6);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, Version7);
-  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, RetainDataForPageUrls);
+  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, WildSchema);
 
-  // Creates the thumbnail table, returning true if the table already exists
-  // or was successfully created.
-  bool InitThumbnailTable();
+  // Open database on a given filename. If the file does not exist,
+  // it is created.
+  // |db| is the database to open.
+  // |db_name| is a path to the database file.
+  static sql::InitStatus OpenDatabase(sql::Connection* db,
+                                      const base::FilePath& db_name);
+
+  // Helper function to implement internals of Init().  This allows
+  // Init() to retry in case of failure, since some failures run
+  // recovery code.
+  sql::InitStatus InitImpl(const base::FilePath& db_name);
 
   // Helper function to handle cleanup on upgrade failures.
   sql::InitStatus CantUpgradeToVersion(int cur_version);
@@ -260,9 +262,6 @@
   // Returns true if the |favicons| database is missing a column.
   bool IsFaviconDBStructureIncorrect();
 
-  // Returns True if the current database is latest.
-  bool IsLatestVersion();
-
   sql::Connection db_;
   sql::MetaTable meta_table_;
 };
diff --git a/chrome/browser/history/thumbnail_database_unittest.cc b/chrome/browser/history/thumbnail_database_unittest.cc
index 0d82b41..9d0dcaa 100644
--- a/chrome/browser/history/thumbnail_database_unittest.cc
+++ b/chrome/browser/history/thumbnail_database_unittest.cc
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/file_util.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted_memory.h"
@@ -42,10 +43,12 @@
 const GURL kPageUrl2 = GURL("http://yahoo.com/");
 const GURL kPageUrl3 = GURL("http://www.google.com/");
 const GURL kPageUrl4 = GURL("http://www.google.com/blank.html");
+const GURL kPageUrl5 = GURL("http://www.bing.com/");
 
 const GURL kIconUrl1 = GURL("http://www.google.com/favicon.ico");
 const GURL kIconUrl2 = GURL("http://www.yahoo.com/favicon.ico");
 const GURL kIconUrl3 = GURL("http://www.google.com/touch.ico");
+const GURL kIconUrl5 = GURL("http://www.bing.com/favicon.ico");
 
 const gfx::Size kSmallSize = gfx::Size(16, 16);
 const gfx::Size kLargeSize = gfx::Size(32, 32);
@@ -358,43 +361,51 @@
 
   db.BeginTransaction();
 
-  std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
-  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+  // Build a database mapping kPageUrl1 -> kIconUrl1, kPageUrl2 ->
+  // kIconUrl2, kPageUrl3 -> kIconUrl1, and kPageUrl5 -> kIconUrl5.
+  // Then retain kPageUrl1, kPageUrl3, and kPageUrl5.  kPageUrl2
+  // should go away, but the others should be retained correctly.
 
-  GURL unkept_url("http://google.com/favicon2.ico");
-  chrome::FaviconID unkept_id = db.AddFavicon(unkept_url, chrome::FAVICON);
-  db.AddFaviconBitmap(unkept_id, favicon, base::Time::Now(), kSmallSize);
+  // TODO(shess): This would probably make sense as a golden file.
 
-  GURL kept_url("http://google.com/favicon.ico");
-  chrome::FaviconID kept_id = db.AddFavicon(kept_url, chrome::FAVICON);
-  db.AddFaviconBitmap(kept_id, favicon, base::Time::Now(), kLargeSize);
+  scoped_refptr<base::RefCountedStaticMemory> favicon1(
+      new base::RefCountedStaticMemory(kBlob1, sizeof(kBlob1)));
+  scoped_refptr<base::RefCountedStaticMemory> favicon2(
+      new base::RefCountedStaticMemory(kBlob2, sizeof(kBlob2)));
 
-  GURL unkept_page_url("http://chromium.org");
-  db.AddIconMapping(unkept_page_url, unkept_id);
-  db.AddIconMapping(unkept_page_url, kept_id);
+  chrome::FaviconID kept_id1 = db.AddFavicon(kIconUrl1, chrome::FAVICON);
+  db.AddFaviconBitmap(kept_id1, favicon1, base::Time::Now(), kLargeSize);
+  db.AddIconMapping(kPageUrl1, kept_id1);
+  db.AddIconMapping(kPageUrl3, kept_id1);
 
-  GURL kept_page_url("http://google.com");
-  db.AddIconMapping(kept_page_url, kept_id);
+  chrome::FaviconID unkept_id = db.AddFavicon(kIconUrl2, chrome::FAVICON);
+  db.AddFaviconBitmap(unkept_id, favicon1, base::Time::Now(), kLargeSize);
+  db.AddIconMapping(kPageUrl2, unkept_id);
+
+  chrome::FaviconID kept_id2 = db.AddFavicon(kIconUrl5, chrome::FAVICON);
+  db.AddFaviconBitmap(kept_id2, favicon2, base::Time::Now(), kLargeSize);
+  db.AddIconMapping(kPageUrl5, kept_id2);
 
   // RetainDataForPageUrls() uses schema manipulations for efficiency.
   // Grab a copy of the schema to make sure the final schema matches.
   const std::string original_schema = db.db_.GetSchema();
 
-  EXPECT_TRUE(db.RetainDataForPageUrls(std::vector<GURL>(1, kept_page_url)));
+  std::vector<GURL> pages_to_keep;
+  pages_to_keep.push_back(kPageUrl1);
+  pages_to_keep.push_back(kPageUrl3);
+  pages_to_keep.push_back(kPageUrl5);
+  EXPECT_TRUE(db.RetainDataForPageUrls(pages_to_keep));
 
-  // Only copied data should be left.
-  std::vector<IconMapping> icon_mappings;
-  EXPECT_TRUE(db.GetIconMappingsForPageURL(
-                  kept_page_url, chrome::FAVICON, &icon_mappings));
-  EXPECT_EQ(1u, icon_mappings.size());
-  EXPECT_EQ(kept_page_url, icon_mappings[0].page_url);
+  // Mappings from the retained urls should be left.
+  EXPECT_TRUE(CheckPageHasIcon(&db, kPageUrl1, chrome::FAVICON,
+                               kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1));
+  EXPECT_TRUE(CheckPageHasIcon(&db, kPageUrl3, chrome::FAVICON,
+                               kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1));
+  EXPECT_TRUE(CheckPageHasIcon(&db, kPageUrl5, chrome::FAVICON,
+                               kIconUrl5, kLargeSize, sizeof(kBlob2), kBlob2));
 
-  std::vector<FaviconBitmap> favicon_bitmaps;
-  EXPECT_TRUE(db.GetFaviconBitmaps(icon_mappings[0].icon_id, &favicon_bitmaps));
-  EXPECT_EQ(1u, favicon_bitmaps.size());
-  EXPECT_EQ(kLargeSize, favicon_bitmaps[0].pixel_size);
-
-  EXPECT_FALSE(db.GetFaviconIDForFaviconURL(unkept_url, false, NULL));
+  // The one not retained should be missing.
+  EXPECT_FALSE(db.GetFaviconIDForFaviconURL(kPageUrl2, false, NULL));
 
   // Schema should be the same.
   EXPECT_EQ(original_schema, db.db_.GetSchema());
@@ -969,4 +980,33 @@
   }
 }
 
+// Test that various broken schema found in the wild can be opened
+// successfully, and result in the correct schema.
+TEST_F(ThumbnailDatabaseTest, WildSchema) {
+  base::FilePath sql_path;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &sql_path));
+  sql_path = sql_path.AppendASCII("History").AppendASCII("thumbnail_wild");
+
+  base::FileEnumerator fe(
+      sql_path, false, base::FileEnumerator::FILES, FILE_PATH_LITERAL("*.sql"));
+  for (base::FilePath name = fe.Next(); !name.empty(); name = fe.Next()) {
+    SCOPED_TRACE(name.BaseName().AsUTF8Unsafe());
+    // Generate a database path based on the golden's basename.
+    base::FilePath db_base_name =
+        name.BaseName().ReplaceExtension(FILE_PATH_LITERAL("db"));
+    base::FilePath db_path = file_name_.DirName().Append(db_base_name);
+    ASSERT_TRUE(sql::test::CreateDatabaseFromSQL(db_path, name));
+
+    // All schema flaws should be cleaned up by Init().
+    // TODO(shess): Differentiate between databases which need Raze()
+    // and those which can be salvaged.
+    ThumbnailDatabase db;
+    ASSERT_EQ(sql::INIT_OK, db.Init(db_path));
+
+    // Verify that the resulting schema is correct, whether it
+    // involved razing the file or fixing things in place.
+    VerifyTablesAndColumns(&db.db_);
+  }
+}
+
 }  // namespace history
diff --git a/chrome/browser/history/top_sites_cache.h b/chrome/browser/history/top_sites_cache.h
index ad0826f..0ce7308 100644
--- a/chrome/browser/history/top_sites_cache.h
+++ b/chrome/browser/history/top_sites_cache.h
@@ -146,12 +146,12 @@
   // description above typedef for details.
   CanonicalURLs canonical_urls_;
 
-  // Helper to clear "?query#ref" from any GURL. This is set in the contrustor
+  // Helper to clear "?query#ref" from any GURL. This is set in the constructor
   // and never modified after.
   GURL::Replacements clear_query_ref_;
 
   // Helper to clear "/path?query#ref" from any GURL. This is set in the
-  // contrustor and never modified after.
+  // constructor and never modified after.
   GURL::Replacements clear_path_query_ref_;
 
   DISALLOW_COPY_AND_ASSIGN(TopSitesCache);
diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc
index 5c1939f..db9156d 100644
--- a/chrome/browser/history/top_sites_database.cc
+++ b/chrome/browser/history/top_sites_database.cc
@@ -9,19 +9,44 @@
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/history/top_sites_database.h"
+#include "chrome/common/thumbnail_score.h"
 #include "sql/connection.h"
 #include "sql/transaction.h"
 
+// Description of database table:
+//
+// thumbnails
+//   url              URL of the sites for which we have a thumbnail.
+//   url_rank         Index of the URL in that thumbnail, 0-based. The thumbnail
+//                    with the highest rank will be the next one evicted. Forced
+//                    thumbnails have a rank of -1.
+//   title            The title to display under that thumbnail.
+//   redirects        A space separated list of URLs that are known to redirect
+//                    to this url.
+//   boring_score     How "boring" that thumbnail is. See ThumbnailScore.
+//   good_clipping    True if the thumbnail was clipped from the bottom, keeping
+//                    the entire width of the window. See ThumbnailScore.
+//   at_top           True if the thumbnail was captured at the top of the
+//                    website.
+//   last_updated     The time at which this thumbnail was last updated.
+//   load_completed   True if the thumbnail was captured after the page load was
+//                    completed.
+//   last_forced      If this is a forced thumbnail, records the last time it
+//                    was forced. If it's not a forced thumbnail, 0.
+
 namespace history {
 
+// TODO(beaudoin): Fill revision/date details of Version 3 after landing.
+// Version 3:  by beaudoin@chromium.org
 // Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31
 // Version 1: 809cc4d8/r64072 by sky@chromium.org on 2010-10-27
 
 // From the version 1 to 2, one column was added. Old versions of Chrome
-// should be able to read version 2 files just fine.
+// should be able to read version 2 files just fine. Same thing for version 2
+// to 3.
 // NOTE(shess): When changing the version, add a new golden file for
 // the new version and a test to verify that Init() works with it.
-static const int kVersionNumber = 2;
+static const int kVersionNumber = 3;
 
 TopSitesDatabase::TopSitesDatabase() {
 }
@@ -69,6 +94,13 @@
     }
   }
 
+  if (meta_table_.GetVersionNumber() == 2) {
+    if (!UpgradeToVersion3()) {
+      LOG(WARNING) << "Unable to upgrade top sites database to version 3.";
+      return false;
+    }
+  }
+
   // Version check.
   if (meta_table_.GetVersionNumber() != kVersionNumber)
     return false;
@@ -84,15 +116,16 @@
   if (!db_->DoesTableExist("thumbnails")) {
     if (!db_->Execute("CREATE TABLE thumbnails ("
                       "url LONGVARCHAR PRIMARY KEY,"
-                      "url_rank INTEGER ,"
+                      "url_rank INTEGER,"
                       "title LONGVARCHAR,"
                       "thumbnail BLOB,"
                       "redirects LONGVARCHAR,"
-                      "boring_score DOUBLE DEFAULT 1.0, "
-                      "good_clipping INTEGER DEFAULT 0, "
-                      "at_top INTEGER DEFAULT 0, "
-                      "last_updated INTEGER DEFAULT 0, "
-                      "load_completed INTEGER DEFAULT 0) ")) {
+                      "boring_score DOUBLE DEFAULT 1.0,"
+                      "good_clipping INTEGER DEFAULT 0,"
+                      "at_top INTEGER DEFAULT 0,"
+                      "last_updated INTEGER DEFAULT 0,"
+                      "load_completed INTEGER DEFAULT 0,"
+                      "last_forced INTEGER DEFAULT 0)")) {
       LOG(WARNING) << db_->GetErrorMessage();
       return false;
     }
@@ -111,13 +144,24 @@
   return true;
 }
 
+bool TopSitesDatabase::UpgradeToVersion3() {
+  // Add 'last_forced' column.
+  if (!db_->Execute(
+          "ALTER TABLE thumbnails ADD last_forced INTEGER DEFAULT 0")) {
+    NOTREACHED();
+    return false;
+  }
+  meta_table_.SetVersionNumber(3);
+  return true;
+}
+
 void TopSitesDatabase::GetPageThumbnails(MostVisitedURLList* urls,
                                          URLToImagesMap* thumbnails) {
   sql::Statement statement(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "SELECT url, url_rank, title, thumbnail, redirects, "
-      "boring_score, good_clipping, at_top, last_updated, load_completed "
-      "FROM thumbnails ORDER BY url_rank "));
+      "boring_score, good_clipping, at_top, last_updated, load_completed, "
+      "last_forced FROM thumbnails ORDER BY url_rank, last_forced"));
 
   if (!statement.is_valid()) {
     LOG(WARNING) << db_->GetErrorMessage();
@@ -128,11 +172,14 @@
   thumbnails->clear();
 
   while (statement.Step()) {
-    // Results are sorted by url_rank.
+    // Results are sorted by url_rank. For forced thumbnails with url_rank = -1,
+    // thumbnails are sorted by last_forced.
     MostVisitedURL url;
     GURL gurl(statement.ColumnString(0));
     url.url = gurl;
     url.title = statement.ColumnString16(2);
+    url.last_forced_time =
+        base::Time::FromInternalValue(statement.ColumnInt64(10));
     std::string redirects = statement.ColumnString(4);
     SetRedirects(redirects, &url);
     urls->push_back(url);
@@ -148,7 +195,6 @@
     thumbnail.thumbnail_score.time_at_snapshot =
         base::Time::FromInternalValue(statement.ColumnInt64(8));
     thumbnail.thumbnail_score.load_completed = statement.ColumnBool(9);
-
     (*thumbnails)[gurl] = thumbnail;
   }
 }
@@ -171,13 +217,13 @@
 }
 
 void TopSitesDatabase::SetPageThumbnail(const MostVisitedURL& url,
-                                            int new_rank,
-                                            const Images& thumbnail) {
+                                        int new_rank,
+                                        const Images& thumbnail) {
   sql::Transaction transaction(db_.get());
   transaction.Begin();
 
   int rank = GetURLRank(url);
-  if (rank == -1) {
+  if (rank == kRankOfNonExistingURL) {
     AddPageThumbnail(url, new_rank, thumbnail);
   } else {
     UpdatePageRankNoTransaction(url, new_rank);
@@ -194,7 +240,7 @@
       "UPDATE thumbnails SET "
       "title = ?, thumbnail = ?, redirects = ?, "
       "boring_score = ?, good_clipping = ?, at_top = ?, last_updated = ?, "
-      "load_completed = ? "
+      "load_completed = ?, last_forced = ?"
       "WHERE url = ? "));
   statement.BindString16(0, url.title);
   if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) {
@@ -208,24 +254,23 @@
   statement.BindBool(5, score.at_top);
   statement.BindInt64(6, score.time_at_snapshot.ToInternalValue());
   statement.BindBool(7, score.load_completed);
-  statement.BindString(8, url.url.spec());
+  statement.BindInt64(8, url.last_forced_time.ToInternalValue());
+  statement.BindString(9, url.url.spec());
 
   return statement.Run();
 }
 
 void TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url,
-                                            int new_rank,
-                                            const Images& thumbnail) {
-  int count = GetRowCount();
-
+                                        int new_rank,
+                                        const Images& thumbnail) {
   sql::Statement statement(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "INSERT OR REPLACE INTO thumbnails "
       "(url, url_rank, title, thumbnail, redirects, "
-      "boring_score, good_clipping, at_top, last_updated, load_completed) "
-      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+      "boring_score, good_clipping, at_top, last_updated, load_completed, "
+      "last_forced) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
   statement.BindString(0, url.url.spec());
-  statement.BindInt(1, count);  // Make it the last url.
+  statement.BindInt(1, kRankOfForcedURL);  // Fist make it a forced thumbnail.
   statement.BindString16(2, url.title);
   if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) {
     statement.BindBlob(3, thumbnail.thumbnail->front(),
@@ -238,14 +283,25 @@
   statement.BindBool(7, score.at_top);
   statement.BindInt64(8, score.time_at_snapshot.ToInternalValue());
   statement.BindBool(9, score.load_completed);
+  int64 last_forced = url.last_forced_time.ToInternalValue();
+  DCHECK((last_forced == 0) == (new_rank != kRankOfForcedURL))
+      << "Thumbnail without a forced time stamp has a forced rank, or the "
+      << "opposite.";
+  statement.BindInt64(10, last_forced);
   if (!statement.Run())
     return;
 
-  UpdatePageRankNoTransaction(url, new_rank);
+  // Update rank if this is not a forced thumbnail.
+  if (new_rank != kRankOfForcedURL)
+    UpdatePageRankNoTransaction(url, new_rank);
 }
 
 void TopSitesDatabase::UpdatePageRank(const MostVisitedURL& url,
-                                          int new_rank) {
+                                      int new_rank) {
+  DCHECK((url.last_forced_time.ToInternalValue() == 0) ==
+         (new_rank != kRankOfForcedURL))
+      << "Thumbnail without a forced time stamp has a forced rank, or the "
+      << "opposite.";
   sql::Transaction transaction(db_.get());
   transaction.Begin();
   UpdatePageRankNoTransaction(url, new_rank);
@@ -256,43 +312,76 @@
 void TopSitesDatabase::UpdatePageRankNoTransaction(
     const MostVisitedURL& url, int new_rank) {
   DCHECK_GT(db_->transaction_nesting(), 0);
+
   int prev_rank = GetURLRank(url);
-  if (prev_rank == -1) {
+  if (prev_rank == kRankOfNonExistingURL) {
     LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec();
     return;
   }
 
   // Shift the ranks.
   if (prev_rank > new_rank) {
-    // Shift up
-    sql::Statement shift_statement(db_->GetCachedStatement(
-        SQL_FROM_HERE,
-        "UPDATE thumbnails "
-        "SET url_rank = url_rank + 1 "
-        "WHERE url_rank >= ? AND url_rank < ?"));
-    shift_statement.BindInt(0, new_rank);
-    shift_statement.BindInt(1, prev_rank);
-    shift_statement.Run();
+    if (new_rank == kRankOfForcedURL) {
+      // From non-forced to forced, shift down.
+      // Example: 2 -> -1
+      // -1, -1, -1, 0, 1, [2 -> -1], [3 -> 2], [4 -> 3]
+      sql::Statement shift_statement(db_->GetCachedStatement(
+          SQL_FROM_HERE,
+          "UPDATE thumbnails "
+          "SET url_rank = url_rank - 1 "
+          "WHERE url_rank > ?"));
+      shift_statement.BindInt(0, prev_rank);
+      shift_statement.Run();
+    } else {
+      // From non-forced to non-forced, shift up.
+      // Example: 3 -> 1
+      // -1, -1, -1, 0, [1 -> 2], [2 -> 3], [3 -> 1], 4
+      sql::Statement shift_statement(db_->GetCachedStatement(
+          SQL_FROM_HERE,
+          "UPDATE thumbnails "
+          "SET url_rank = url_rank + 1 "
+          "WHERE url_rank >= ? AND url_rank < ?"));
+      shift_statement.BindInt(0, new_rank);
+      shift_statement.BindInt(1, prev_rank);
+      shift_statement.Run();
+    }
   } else if (prev_rank < new_rank) {
-    // Shift down
-    sql::Statement shift_statement(db_->GetCachedStatement(
-        SQL_FROM_HERE,
-        "UPDATE thumbnails "
-        "SET url_rank = url_rank - 1 "
-        "WHERE url_rank > ? AND url_rank <= ?"));
-    shift_statement.BindInt(0, prev_rank);
-    shift_statement.BindInt(1, new_rank);
-    shift_statement.Run();
+    if (prev_rank == kRankOfForcedURL) {
+      // From non-forced to forced, shift up.
+      // Example: -1 -> 2
+      // -1, [-1 -> 2], -1, 0, 1, [2 -> 3], [3 -> 4], [4 -> 5]
+      sql::Statement shift_statement(db_->GetCachedStatement(
+          SQL_FROM_HERE,
+          "UPDATE thumbnails "
+          "SET url_rank = url_rank + 1 "
+          "WHERE url_rank >= ?"));
+      shift_statement.BindInt(0, new_rank);
+      shift_statement.Run();
+    } else {
+      // From non-forced to non-forced, shift down.
+      // Example: 1 -> 3.
+      // -1, -1, -1, 0, [1 -> 3], [2 -> 1], [3 -> 2], 4
+      sql::Statement shift_statement(db_->GetCachedStatement(
+          SQL_FROM_HERE,
+          "UPDATE thumbnails "
+          "SET url_rank = url_rank - 1 "
+          "WHERE url_rank > ? AND url_rank <= ?"));
+      shift_statement.BindInt(0, prev_rank);
+      shift_statement.BindInt(1, new_rank);
+      shift_statement.Run();
+    }
   }
 
-  // Set the url's rank.
+  // Set the url's rank and last_forced, since the latter changes when a URL
+  // goes from forced to non-forced and vice-versa.
   sql::Statement set_statement(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "UPDATE thumbnails "
-      "SET url_rank = ? "
+      "SET url_rank = ?, last_forced = ? "
       "WHERE url == ?"));
   set_statement.BindInt(0, new_rank);
-  set_statement.BindString(1, url.url.spec());
+  set_statement.BindInt64(1, url.last_forced_time.ToInternalValue());
+  set_statement.BindString(2, url.url.spec());
   set_statement.Run();
 }
 
@@ -317,16 +406,6 @@
   return true;
 }
 
-int TopSitesDatabase::GetRowCount() {
-  sql::Statement select_statement(db_->GetCachedStatement(
-      SQL_FROM_HERE,
-      "SELECT COUNT (url) FROM thumbnails"));
-  if (select_statement.Step())
-    return select_statement.ColumnInt(0);
-
-  return 0;
-}
-
 int TopSitesDatabase::GetURLRank(const MostVisitedURL& url) {
   sql::Statement select_statement(db_->GetCachedStatement(
       SQL_FROM_HERE,
@@ -336,27 +415,29 @@
   if (select_statement.Step())
     return select_statement.ColumnInt(0);
 
-  return -1;
+  return kRankOfNonExistingURL;
 }
 
 // Remove the record for this URL. Returns true iff removed successfully.
 bool TopSitesDatabase::RemoveURL(const MostVisitedURL& url) {
   int old_rank = GetURLRank(url);
-  if (old_rank < 0)
+  if (old_rank == kRankOfNonExistingURL)
     return false;
 
   sql::Transaction transaction(db_.get());
   transaction.Begin();
-  // Decrement all following ranks.
-  sql::Statement shift_statement(db_->GetCachedStatement(
-      SQL_FROM_HERE,
-      "UPDATE thumbnails "
-      "SET url_rank = url_rank - 1 "
-      "WHERE url_rank > ?"));
-  shift_statement.BindInt(0, old_rank);
+  if (old_rank != kRankOfForcedURL) {
+    // Decrement all following ranks.
+    sql::Statement shift_statement(db_->GetCachedStatement(
+        SQL_FROM_HERE,
+        "UPDATE thumbnails "
+        "SET url_rank = url_rank - 1 "
+        "WHERE url_rank > ?"));
+    shift_statement.BindInt(0, old_rank);
 
-  if (!shift_statement.Run())
-    return false;
+    if (!shift_statement.Run())
+      return false;
+  }
 
   sql::Statement delete_statement(
       db_->GetCachedStatement(SQL_FROM_HERE,
diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h
index 053f03b..e1df910 100644
--- a/chrome/browser/history/top_sites_database.h
+++ b/chrome/browser/history/top_sites_database.h
@@ -60,6 +60,15 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(TopSitesDatabaseTest, Version1);
   FRIEND_TEST_ALL_PREFIXES(TopSitesDatabaseTest, Version2);
+  FRIEND_TEST_ALL_PREFIXES(TopSitesDatabaseTest, Version3);
+  FRIEND_TEST_ALL_PREFIXES(TopSitesDatabaseTest, AddRemoveEditThumbnails);
+
+  // Rank of all URLs that are forced and therefore cannot be automatically
+  // evicted.
+  static const int kRankOfForcedURL = -1;
+
+  // Rank used to indicate that a URL is not stored in the database.
+  static const int kRankOfNonExistingURL = -2;
 
   // Creates the thumbnail table, returning true if the table already exists
   // or was successfully created.
@@ -69,6 +78,10 @@
   // upgrade was successful.
   bool UpgradeToVersion2();
 
+  // Upgrades the thumbnail table to version 3, returning true if the
+  // upgrade was successful.
+  bool UpgradeToVersion3();
+
   // Adds a new URL to the database.
   void AddPageThumbnail(const MostVisitedURL& url,
                         int new_rank,
@@ -82,12 +95,9 @@
   bool UpdatePageThumbnail(const MostVisitedURL& url,
                            const Images& thumbnail);
 
-  // Returns the URL's current rank or -1 if it is not present.
+  // Returns |url|'s current rank or kRankOfNonExistingURL if not present.
   int GetURLRank(const MostVisitedURL& url);
 
-  // Returns the number of URLs (rows) in the database.
-  int GetRowCount();
-
   sql::Connection* CreateDB(const base::FilePath& db_name);
 
   // Encodes redirects into a string.
diff --git a/chrome/browser/history/top_sites_database_unittest.cc b/chrome/browser/history/top_sites_database_unittest.cc
index bcd119a..4004065 100644
--- a/chrome/browser/history/top_sites_database_unittest.cc
+++ b/chrome/browser/history/top_sites_database_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/history/top_sites_database.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/tools/profiles/thumbnail-inl.h"
@@ -46,8 +47,8 @@
 
   // [url], [url_rank], [title], [thumbnail], [redirects],
   // [boring_score], [good_clipping], [at_top], [last_updated], and
-  // [load_completed].
-  EXPECT_EQ(10u, sql::test::CountTableColumns(db, "thumbnails"));
+  // [load_completed], [last_forced]
+  EXPECT_EQ(11u, sql::test::CountTableColumns(db, "thumbnails"));
 }
 
 }  // namespace
@@ -120,4 +121,155 @@
   ASSERT_EQ(2u, thumbnails.size());
 }
 
+TEST_F(TopSitesDatabaseTest, Version3) {
+  ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql"));
+
+  TopSitesDatabase db;
+  ASSERT_TRUE(db.Init(file_name_));
+
+  VerifyTablesAndColumns(db.db_.get());
+
+  // Basic operational check.
+  MostVisitedURLList urls;
+  std::map<GURL, Images> thumbnails;
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(3u, urls.size());
+  ASSERT_EQ(3u, thumbnails.size());
+  EXPECT_EQ(kUrl, urls[0].url);  // [0] because of url_rank.
+  // kGoogleThumbnail includes nul terminator.
+  ASSERT_EQ(sizeof(kGoogleThumbnail) - 1,
+            thumbnails[urls[0].url].thumbnail->size());
+  EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(),
+                      kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1));
+
+  ASSERT_TRUE(db.RemoveURL(urls[1]));
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(2u, urls.size());
+  ASSERT_EQ(2u, thumbnails.size());
+}
+
+TEST_F(TopSitesDatabaseTest, AddRemoveEditThumbnails) {
+  ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v3.sql"));
+
+  TopSitesDatabase db;
+  ASSERT_TRUE(db.Init(file_name_));
+
+  // Add a new URL, not forced, rank = 1.
+  GURL mapsUrl = GURL("http://maps.google.com/");
+  MostVisitedURL url1(mapsUrl, ASCIIToUTF16("Google Maps"));
+  db.SetPageThumbnail(url1, 1, Images());
+
+  MostVisitedURLList urls;
+  std::map<GURL, Images> thumbnails;
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(4u, urls.size());
+  ASSERT_EQ(4u, thumbnails.size());
+  EXPECT_EQ(kUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);
+
+  // Add a new URL, forced.
+  GURL driveUrl = GURL("http://drive.google.com/");
+  MostVisitedURL url2(driveUrl, ASCIIToUTF16("Google Drive"));
+  url2.last_forced_time = base::Time::FromJsTime(789714000000);  // 10/1/1995
+  db.SetPageThumbnail(url2, TopSitesDatabase::kRankOfForcedURL, Images());
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(5u, urls.size());
+  ASSERT_EQ(5u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);  // Forced URLs always appear first.
+  EXPECT_EQ(kUrl, urls[1].url);
+  EXPECT_EQ(mapsUrl, urls[2].url);
+
+  // Add a new URL, forced (earlier).
+  GURL plusUrl = GURL("http://plus.google.com/");
+  MostVisitedURL url3(plusUrl, ASCIIToUTF16("Google Plus"));
+  url3.last_forced_time = base::Time::FromJsTime(787035600000);  // 10/12/1994
+  db.SetPageThumbnail(url3, TopSitesDatabase::kRankOfForcedURL, Images());
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(plusUrl, urls[0].url);  // New forced URL should appear first.
+  EXPECT_EQ(driveUrl, urls[1].url);
+  EXPECT_EQ(kUrl, urls[2].url);
+  EXPECT_EQ(mapsUrl, urls[3].url);
+
+  // Change the last_forced_time of a forced URL.
+  url3.last_forced_time = base::Time::FromJsTime(792392400000);  // 10/2/1995
+  db.SetPageThumbnail(url3, TopSitesDatabase::kRankOfForcedURL, Images());
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(plusUrl, urls[1].url);  // Forced URL should have moved second.
+  EXPECT_EQ(kUrl, urls[2].url);
+  EXPECT_EQ(mapsUrl, urls[3].url);
+
+  // Change a non-forced URL to forced using UpdatePageRank.
+  url1.last_forced_time = base::Time::FromJsTime(792219600000);  // 8/2/1995
+  db.UpdatePageRank(url1, TopSitesDatabase::kRankOfForcedURL);
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);  // Maps moves to second forced URL.
+  EXPECT_EQ(plusUrl, urls[2].url);
+  EXPECT_EQ(kUrl, urls[3].url);
+
+  // Change a forced URL to non-forced using SetPageThumbnail.
+  db.SetPageThumbnail(url3, 1, Images());
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);
+  EXPECT_EQ(kUrl, urls[2].url);
+  EXPECT_EQ(plusUrl, urls[3].url);  // Plus moves to second non-forced URL.
+
+  // Change a non-forced URL to earlier non-forced using UpdatePageRank.
+  url3.last_forced_time = base::Time();
+  db.UpdatePageRank(url3, 0);
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);
+  EXPECT_EQ(plusUrl, urls[2].url);  // Plus moves to first non-forced URL.
+  EXPECT_EQ(kUrl, urls[3].url);
+
+  // Change a non-forced URL to later non-forced using SetPageThumbnail.
+  db.SetPageThumbnail(url3, 2, Images());
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(6u, urls.size());
+  ASSERT_EQ(6u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);
+  EXPECT_EQ(kUrl, urls[2].url);
+  EXPECT_EQ(plusUrl, urls[4].url);  // Plus moves to third non-forced URL.
+
+  // Remove a non-forced URL.
+  db.RemoveURL(url3);
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(5u, urls.size());
+  ASSERT_EQ(5u, thumbnails.size());
+  EXPECT_EQ(driveUrl, urls[0].url);
+  EXPECT_EQ(mapsUrl, urls[1].url);
+  EXPECT_EQ(kUrl, urls[2].url);
+
+  // Remove a forced URL.
+  db.RemoveURL(url2);
+
+  db.GetPageThumbnails(&urls, &thumbnails);
+  ASSERT_EQ(4u, urls.size());
+  ASSERT_EQ(4u, thumbnails.size());
+  EXPECT_EQ(mapsUrl, urls[0].url);
+  EXPECT_EQ(kUrl, urls[1].url);
+}
+
 }  // namespace history
diff --git a/chrome/browser/history/top_sites_impl.cc b/chrome/browser/history/top_sites_impl.cc
index 7df73c4..a084716 100644
--- a/chrome/browser/history/top_sites_impl.cc
+++ b/chrome/browser/history/top_sites_impl.cc
@@ -15,6 +15,7 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner.h"
@@ -26,7 +27,7 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/page_usage_data.h"
 #include "chrome/browser/history/top_sites_cache.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/history/url_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
@@ -235,21 +236,30 @@
   }
 
   if (prefix_match) {
-    base::AutoLock lock(lock_);
+    // If http or https, search with |url| first, then try the other one.
+    std::vector<GURL> url_list;
+    url_list.push_back(url);
+    if (url.SchemeIsHTTPOrHTTPS())
+      url_list.push_back(ToggleHTTPAndHTTPS(url));
 
-    GURL canonical_url;
-    // Test whether |url| is prefix of any stored URL.
-    canonical_url = thread_safe_cache_->GetSpecializedCanonicalURL(url);
-    if (!canonical_url.is_empty() &&
-        thread_safe_cache_->GetPageThumbnail(canonical_url, bytes)) {
-      return true;
-    }
+    for (std::vector<GURL>::iterator it = url_list.begin();
+         it != url_list.end(); ++it) {
+      base::AutoLock lock(lock_);
 
-    // Test whether any stored URL is a prefix of |url|.
-    canonical_url = thread_safe_cache_->GetGeneralizedCanonicalURL(url);
-    if (!canonical_url.is_empty() &&
-        thread_safe_cache_->GetPageThumbnail(canonical_url, bytes)) {
-      return true;
+      GURL canonical_url;
+      // Test whether |url| is prefix of any stored URL.
+      canonical_url = thread_safe_cache_->GetSpecializedCanonicalURL(*it);
+      if (!canonical_url.is_empty() &&
+          thread_safe_cache_->GetPageThumbnail(canonical_url, bytes)) {
+        return true;
+      }
+
+      // Test whether any stored URL is a prefix of |url|.
+      canonical_url = thread_safe_cache_->GetGeneralizedCanonicalURL(*it);
+      if (!canonical_url.is_empty() &&
+          thread_safe_cache_->GetPageThumbnail(canonical_url, bytes)) {
+        return true;
+      }
     }
   }
 
diff --git a/chrome/browser/history/top_sites_impl_unittest.cc b/chrome/browser/history/top_sites_impl_unittest.cc
index a32a01f..0062968 100644
--- a/chrome/browser/history/top_sites_impl_unittest.cc
+++ b/chrome/browser/history/top_sites_impl_unittest.cc
@@ -512,7 +512,7 @@
   EXPECT_TRUE(top_sites()->GetPageThumbnail(url1.url, false, &result));
 
   EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://gmail.com"),
-                                           thumbnail, score));
+                                            thumbnail, score));
   EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://gmail.com"),
                                             false,
                                             &result));
@@ -522,7 +522,7 @@
                                             &result));
 
   EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://mail.google.com"),
-                                           thumbnail, score));
+                                            thumbnail, score));
   EXPECT_TRUE(top_sites()->GetPageThumbnail(url2.url, false, &result));
 
   EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
diff --git a/chrome/browser/history/url_utils.cc b/chrome/browser/history/url_utils.cc
index 7c96b8a..292fcd6 100644
--- a/chrome/browser/history/url_utils.cc
+++ b/chrome/browser/history/url_utils.cc
@@ -68,4 +68,19 @@
   return *(first_diff.second) == '/';
 }
 
+GURL ToggleHTTPAndHTTPS(const GURL& url) {
+  std::string new_scheme;
+  if (url.SchemeIs("http"))
+    new_scheme = "https";
+  else if (url.SchemeIs("https"))
+    new_scheme = "http";
+  else
+    return GURL::EmptyGURL();
+  url_parse::Component comp;
+  comp.len = new_scheme.length();
+  GURL::Replacements replacement;
+  replacement.SetScheme(new_scheme.c_str(), comp);
+  return url.ReplaceComponents(replacement);
+}
+
 }  // namespace history
diff --git a/chrome/browser/history/url_utils.h b/chrome/browser/history/url_utils.h
index 586d084..c5b74fe 100644
--- a/chrome/browser/history/url_utils.h
+++ b/chrome/browser/history/url_utils.h
@@ -37,6 +37,10 @@
 // prefix of "testing", even though "test" is a (string) prefix of "testing".
 bool IsPathPrefix(const std::string& p1, const std::string& p2);
 
+// Converts |url| from HTTP to HTTPS, and vice versa, then returns the result.
+// If |url| is neither HTTP nor HTTPS, returns an empty URL.
+GURL ToggleHTTPAndHTTPS(const GURL& url);
+
 }  // namespace history
 
 #endif  // CHROME_BROWSER_HISTORY_URL_UTILS_H_
diff --git a/chrome/browser/history/url_utils_unittest.cc b/chrome/browser/history/url_utils_unittest.cc
index 02b1ff9..b1ffb6a 100644
--- a/chrome/browser/history/url_utils_unittest.cc
+++ b/chrome/browser/history/url_utils_unittest.cc
@@ -116,6 +116,15 @@
   }
 }
 
+TEST(HistoryUrlUtilsTest, ToggleHTTPAndHTTPS) {
+  EXPECT_EQ(GURL("http://www.google.com/test?q#r"),
+            ToggleHTTPAndHTTPS(GURL("https://www.google.com/test?q#r")));
+  EXPECT_EQ(GURL("https://www.google.com:137/"),
+            ToggleHTTPAndHTTPS(GURL("http://www.google.com:137/")));
+  EXPECT_EQ(GURL::EmptyGURL(),
+            ToggleHTTPAndHTTPS(GURL("ftp://www.google.com/")));
+}
+
 }  // namespace
 
 }  // namespace history
diff --git a/chrome/browser/icon_loader_win.cc b/chrome/browser/icon_loader_win.cc
index fe826f0..09dd583 100644
--- a/chrome/browser/icon_loader_win.cc
+++ b/chrome/browser/icon_loader_win.cc
@@ -24,8 +24,9 @@
 }
 
 bool IconLoader::IsIconMutableFromFilepath(const base::FilePath& filepath) {
-  base::FilePath::StringType extension = filepath.Extension();
-  return extension == L".exe" || extension == L".dll" || extension == L".ico";
+  return filepath.MatchesExtension(L".exe") ||
+         filepath.MatchesExtension(L".dll") ||
+         filepath.MatchesExtension(L".ico");
 }
 
 void IconLoader::ReadIcon() {
diff --git a/chrome/browser/icon_manager.cc b/chrome/browser/icon_manager.cc
index 6c7f9fc..d0e2cbc 100644
--- a/chrome/browser/icon_manager.cc
+++ b/chrome/browser/icon_manager.cc
@@ -107,17 +107,21 @@
 
   const ClientRequest& client_request = rit->second;
 
-  // Cache the bitmap. Watch out: |result| or the cached bitmap may be NULL to
-  // indicate a current or past failure.
+  // Cache the bitmap. Watch out: |result| may be NULL to indicate a current
+  // failure. We assume that if we have an entry in |icon_cache_|
+  // it must not be NULL.
   CacheKey key(group, client_request.size);
   IconMap::iterator it = icon_cache_.find(key);
-  if (it != icon_cache_.end() && result && it->second) {
-    if (it->second != result) {
+  if (it != icon_cache_.end()) {
+    if (!result) {
+      delete it->second;
+      icon_cache_.erase(it);
+    } else if (result != it->second) {
       it->second->SwapRepresentations(result);
       delete result;
       result = it->second;
     }
-  } else {
+  } else if (result) {
     icon_cache_[key] = result;
   }
 
diff --git a/chrome/browser/infobars/infobar_extension_api.cc b/chrome/browser/infobars/infobar_extension_api.cc
index 5454b06..3868b56 100644
--- a/chrome/browser/infobars/infobar_extension_api.cc
+++ b/chrome/browser/infobars/infobar_extension_api.cc
@@ -50,14 +50,13 @@
 
   Browser* browser = NULL;
   content::WebContents* web_contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(
-      tab_id,
-      profile(),
-      include_incognito(),
-      &browser,
-      NULL,
-      &web_contents,
-      NULL)) {
+  if (!ExtensionTabUtil::GetTabById(tab_id,
+                                    GetProfile(),
+                                    include_incognito(),
+                                    &browser,
+                                    NULL,
+                                    &web_contents,
+                                    NULL)) {
     error_ = extensions::ErrorUtils::FormatErrorMessage(
         extensions::tabs_constants::kTabNotFoundError,
         base::IntToString(tab_id));
diff --git a/chrome/browser/infobars/infobar_extension_api.h b/chrome/browser/infobars/infobar_extension_api.h
index 80bd7f7..2ef2df7 100644
--- a/chrome/browser/infobars/infobar_extension_api.h
+++ b/chrome/browser/infobars/infobar_extension_api.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_INFOBARS_INFOBAR_EXTENSION_API_H_
 #define CHROME_BROWSER_INFOBARS_INFOBAR_EXTENSION_API_H_
 
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 
-class InfobarsShowFunction : public SyncExtensionFunction {
+class InfobarsShowFunction : public ChromeSyncExtensionFunction {
   virtual ~InfobarsShowFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("infobars.show", INFOBARS_SHOW)
diff --git a/chrome/browser/invalidation/DEPS b/chrome/browser/invalidation/DEPS
index f049819..206d3a8 100644
--- a/chrome/browser/invalidation/DEPS
+++ b/chrome/browser/invalidation/DEPS
@@ -5,5 +5,5 @@
   "+sync/internal_api/public/base",
 
   # Needed for InvalidationController JNI methods.
-  "+sync/jni/InvalidationController_jni.h",
+  "+chrome/jni/InvalidationController_jni.h",
 ]
diff --git a/chrome/browser/invalidation/invalidation_controller_android.cc b/chrome/browser/invalidation/invalidation_controller_android.cc
index 53aab59..c153df1 100644
--- a/chrome/browser/invalidation/invalidation_controller_android.cc
+++ b/chrome/browser/invalidation/invalidation_controller_android.cc
@@ -8,8 +8,8 @@
 #include <vector>
 
 #include "base/android/jni_array.h"
+#include "chrome/jni/InvalidationController_jni.h"
 #include "google/cacheinvalidation/include/types.h"
-#include "sync/jni/InvalidationController_jni.h"
 
 namespace invalidation {
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 3d958b8..b630a29 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -704,9 +704,6 @@
     if (command_line.HasSwitch(switches::kDisableIPPooling))
       globals_->enable_spdy_ip_pooling.set(false);
 
-    if (command_line.HasSwitch(switches::kEnableSpdyCredentialFrames))
-      globals_->enable_spdy_credential_frames.set(true);
-
     if (command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
       // Enable WebSocket over SPDY.
       net::WebSocketJob::set_websocket_over_spdy_enabled(true);
@@ -926,8 +923,6 @@
       &params->force_spdy_single_domain);
   globals_->enable_spdy_ip_pooling.CopyToIfSet(
       &params->enable_spdy_ip_pooling);
-  globals_->enable_spdy_credential_frames.CopyToIfSet(
-      &params->enable_spdy_credential_frames);
   globals_->enable_spdy_compression.CopyToIfSet(
       &params->enable_spdy_compression);
   globals_->enable_spdy_ping_based_connection_checking.CopyToIfSet(
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index e5187f4..3f68bdf 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -158,7 +158,6 @@
     Optional<size_t> max_spdy_concurrent_streams_limit;
     Optional<bool> force_spdy_single_domain;
     Optional<bool> enable_spdy_ip_pooling;
-    Optional<bool> enable_spdy_credential_frames;
     Optional<bool> enable_spdy_compression;
     Optional<bool> enable_spdy_ping_based_connection_checking;
     Optional<net::NextProto> spdy_default_protocol;
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index da12a42..a7a7df6 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -87,7 +87,13 @@
     it->profile()->SetExitType(Profile::EXIT_NORMAL);
 }
 
-void AttemptExitInternal() {
+void AttemptExitInternal(bool try_to_quit_application) {
+  // On Mac, the platform-specific part handles setting this.
+#if !defined(OS_MACOSX)
+  if (try_to_quit_application)
+    browser_shutdown::SetTryingToQuit(true);
+#endif
+
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
       content::NotificationService::AllSources(),
@@ -96,11 +102,20 @@
   g_browser_process->platform_part()->AttemptExit();
 }
 
+void CloseAllBrowsersAndQuit() {
+  browser_shutdown::SetTryingToQuit(true);
+  CloseAllBrowsers();
+}
+
 void CloseAllBrowsers() {
-  // If there are no browsers, send the APP_TERMINATING action here. Otherwise,
-  // it will be sent by RemoveBrowser() when the last browser has closed.
+  // If there are no browsers and closing the last browser would quit the
+  // application, send the APP_TERMINATING action here. Otherwise, it will be
+  // sent by RemoveBrowser() when the last browser has closed.
   if (browser_shutdown::ShuttingDownWithoutClosingBrowsers() ||
-      chrome::GetTotalBrowserCount() == 0) {
+      (chrome::GetTotalBrowserCount() == 0 &&
+       (browser_shutdown::IsTryingToQuit() || !chrome::WillKeepAlive() ||
+        CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableBatchedShutdown)))) {
     // Tell everyone that we are shutting down.
     browser_shutdown::SetTryingToQuit(true);
 
@@ -154,7 +169,7 @@
   // request.
   PrefService* pref_service = g_browser_process->local_state();
   pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false);
-  AttemptExitInternal();
+  AttemptExitInternal(false);
 #endif
 }
 
@@ -213,7 +228,7 @@
   if (AreAllBrowsersCloseable())
     MarkAsCleanShutdown();
 #endif
-  AttemptExitInternal();
+  AttemptExitInternal(true);
 }
 
 #if defined(OS_CHROMEOS)
@@ -228,7 +243,7 @@
   // screen locker.
   if (!AreAllBrowsersCloseable())
     browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION);
-  AttemptExitInternal();
+  AttemptExitInternal(true);
 }
 #endif
 
diff --git a/chrome/browser/lifetime/application_lifetime.h b/chrome/browser/lifetime/application_lifetime.h
index 2f25219..08afcd6 100644
--- a/chrome/browser/lifetime/application_lifetime.h
+++ b/chrome/browser/lifetime/application_lifetime.h
@@ -53,9 +53,13 @@
 void ExitCleanly();
 #endif
 
+// Closes all browsers and if successful, quits.
+void CloseAllBrowsersAndQuit();
+
 // Closes all browsers. If the session is ending the windows are closed
 // directly. Otherwise the windows are closed by way of posting a WM_CLOSE
-// message.
+// message. This will quit the application if there is nothing other than
+// browser windows keeping it alive or the application is quitting.
 void CloseAllBrowsers();
 
 // Begins shutdown of the application when the desktop session is ending.
diff --git a/chrome/browser/lifetime/application_lifetime_aura.cc b/chrome/browser/lifetime/application_lifetime_aura.cc
index e7e3e4a..15d1867 100644
--- a/chrome/browser/lifetime/application_lifetime_aura.cc
+++ b/chrome/browser/lifetime/application_lifetime_aura.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/common/chrome_switches.h"
+#include "ui/aura/root_window.h"
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_ASH)
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
index e26b73f..fed7d84 100644
--- a/chrome/browser/lifetime/browser_close_manager.cc
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/lifetime/browser_close_manager.h"
 
 #include "base/command_line.h"
+#include "chrome/browser/background/background_mode_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/download/download_service.h"
@@ -32,6 +33,8 @@
   if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION ||
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableBatchedShutdown)) {
+    // Tell everyone that we are shutting down.
+    browser_shutdown::SetTryingToQuit(true);
     CloseBrowsers();
     return;
   }
@@ -123,14 +126,17 @@
 }
 
 void BrowserCloseManager::CloseBrowsers() {
-  // Tell everyone that we are shutting down.
-  browser_shutdown::SetTryingToQuit(true);
-
 #if defined(ENABLE_SESSION_SERVICE)
   // Before we close the browsers shutdown all session services. That way an
   // exit can restore all browsers open before exiting.
   ProfileManager::ShutdownSessionServices();
 #endif
+  if (!browser_shutdown::IsTryingToQuit()) {
+    BackgroundModeManager* background_mode_manager =
+        g_browser_process->background_mode_manager();
+    if (background_mode_manager)
+      background_mode_manager->SuspendBackgroundMode();
+  }
 
   bool session_ending =
       browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index 3023e55..73c5226 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "chrome/browser/background/background_mode_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -20,6 +21,7 @@
 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -131,6 +133,7 @@
   static void AttemptClose(UserChoice user_choice) {
     scoped_refptr<BrowserCloseManager> browser_close_manager =
         new TestBrowserCloseManager(user_choice);
+    browser_shutdown::SetTryingToQuit(true);
     browser_close_manager->StartClosingBrowsers();
   }
 
@@ -195,6 +198,34 @@
   virtual ~TestDownloadManagerDelegate() {}
 };
 
+class FakeBackgroundModeManager : public BackgroundModeManager {
+ public:
+  FakeBackgroundModeManager()
+      : BackgroundModeManager(
+            CommandLine::ForCurrentProcess(),
+            &g_browser_process->profile_manager()->GetProfileInfoCache()),
+        suspended_(false) {}
+
+  virtual void SuspendBackgroundMode() OVERRIDE {
+    BackgroundModeManager::SuspendBackgroundMode();
+    suspended_ = true;
+  }
+
+  virtual void ResumeBackgroundMode() OVERRIDE {
+    BackgroundModeManager::ResumeBackgroundMode();
+    suspended_ = false;
+  }
+
+  bool IsBackgroundModeSuspended() {
+    return suspended_;
+  }
+
+ private:
+  bool suspended_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBackgroundModeManager);
+};
+
 }  // namespace
 
 class BrowserCloseManagerBrowserTest
@@ -242,7 +273,7 @@
       browser(), embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
   cancel_observer.Wait();
   EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
@@ -250,7 +281,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -264,8 +295,8 @@
       browser(), embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
   cancel_observer.Wait();
   EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
@@ -273,8 +304,8 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 1);
-  chrome::CloseAllBrowsers();
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -290,7 +321,7 @@
       ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAboutURL)));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
   cancel_observer.Wait();
   EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
@@ -309,7 +340,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
   EXPECT_TRUE(chrome::BrowserIterator().done());
@@ -340,7 +371,7 @@
   {
     RepeatedNotificationObserver cancel_observer(
         chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-    chrome::CloseAllBrowsers();
+    chrome::CloseAllBrowsersAndQuit();
     ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
     cancel_observer.Wait();
   }
@@ -352,7 +383,7 @@
   {
     RepeatedNotificationObserver cancel_observer(
         chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
-    chrome::CloseAllBrowsers();
+    chrome::CloseAllBrowsersAndQuit();
     ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
     ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
     cancel_observer.Wait();
@@ -364,7 +395,8 @@
   // Allow shutdown for both beforeunload events.
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -396,7 +428,7 @@
 
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
   cancel_observer.Wait();
   EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
@@ -405,7 +437,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -429,7 +461,7 @@
 
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
   cancel_observer.Wait();
   EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
@@ -440,7 +472,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 3);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -456,7 +488,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   browsers_.push_back(CreateBrowser(browser()->profile()));
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
@@ -474,7 +506,7 @@
 
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   browsers_.push_back(CreateBrowser(browser()->profile()));
   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
       browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
@@ -488,7 +520,8 @@
   // Allow shutdown for both beforeunload dialogs.
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
@@ -507,7 +540,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   AddBlankTabAndShow(browsers_[0]);
   AddBlankTabAndShow(browsers_[1]);
@@ -529,7 +562,7 @@
       browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   AddBlankTabAndShow(browsers_[0]);
   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
@@ -546,7 +579,9 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
 
@@ -562,7 +597,7 @@
       browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
 
   browsers_.push_back(CreateBrowser(browser()->profile()));
   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
@@ -577,7 +612,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   browsers_[1]->tab_strip_model()->CloseAllTabs();
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
@@ -602,7 +637,7 @@
       browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
 
   browsers_.push_back(CreateBrowser(browser()->profile()));
   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
@@ -617,7 +652,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_FALSE(browsers_[1]->ShouldCloseWindow());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
@@ -637,7 +672,7 @@
       browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
   RepeatedNotificationObserver cancel_observer(
       chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
 
   ASSERT_FALSE(browsers_[0]->ShouldCloseWindow());
   ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
@@ -648,7 +683,7 @@
 
   RepeatedNotificationObserver close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED, 2);
-  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsersAndQuit();
   ASSERT_FALSE(browsers_[0]->ShouldCloseWindow());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
@@ -792,6 +827,7 @@
       chrome::NOTIFICATION_BROWSER_CLOSED, 1);
   TestBrowserCloseManager::AttemptClose(
       TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE);
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
   close_observer.Wait();
   EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
   EXPECT_TRUE(chrome::BrowserIterator().done());
@@ -800,3 +836,98 @@
 INSTANTIATE_TEST_CASE_P(BrowserCloseManagerBrowserTest,
                         BrowserCloseManagerBrowserTest,
                         testing::Bool());
+
+class BrowserCloseManagerWithBackgroundModeBrowserTest
+    : public BrowserCloseManagerBrowserTest {
+ public:
+  BrowserCloseManagerWithBackgroundModeBrowserTest() {}
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    BrowserCloseManagerBrowserTest::SetUpOnMainThread();
+    g_browser_process->set_background_mode_manager_for_test(
+        scoped_ptr<BackgroundModeManager>(new FakeBackgroundModeManager));
+  }
+
+  bool IsBackgroundModeSuspended() {
+    return static_cast<FakeBackgroundModeManager*>(
+        g_browser_process->background_mode_manager())
+        ->IsBackgroundModeSuspended();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrowserCloseManagerWithBackgroundModeBrowserTest);
+};
+
+// Check that background mode is suspended when closing all browsers unless we
+// are quitting and that background mode is resumed when a new browser window is
+// opened.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest,
+                       CloseAllBrowsersWithBackgroundMode) {
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+  Profile* profile = browser()->profile();
+  {
+    RepeatedNotificationObserver close_observer(
+        chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+    chrome::StartKeepAlive();
+    chrome::CloseAllBrowsers();
+    close_observer.Wait();
+  }
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+  EXPECT_TRUE(IsBackgroundModeSuspended());
+
+  // Background mode should be resumed when a new browser window is opened.
+  ui_test_utils::BrowserAddedObserver new_browser_observer;
+  chrome::NewEmptyWindow(profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+  new_browser_observer.WaitForSingleNewBrowser();
+  chrome::EndKeepAlive();
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+
+  // Background mode should not be suspended when quitting.
+  chrome::CloseAllBrowsersAndQuit();
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+
+}
+
+// Check that closing the last browser window individually does not affect
+// background mode.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest,
+                       CloseSingleBrowserWithBackgroundMode) {
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+  browser()->window()->Close();
+  close_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+}
+
+// Check that closing all browsers with no browser windows open suspends
+// background mode but does not cause Chrome to quit.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest,
+                       CloseAllBrowsersWithNoOpenBrowsersWithBackgroundMode) {
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+  chrome::StartKeepAlive();
+  browser()->window()->Close();
+  close_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+  EXPECT_FALSE(IsBackgroundModeSuspended());
+
+  chrome::CloseAllBrowsers();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+  EXPECT_TRUE(IsBackgroundModeSuspended());
+}
+
+INSTANTIATE_TEST_CASE_P(BrowserCloseManagerWithBackgroundModeBrowserTest,
+                        BrowserCloseManagerWithBackgroundModeBrowserTest,
+                        testing::Bool());
diff --git a/chrome/browser/local_discovery/privet_constants.cc b/chrome/browser/local_discovery/privet_constants.cc
index 8a66145..11b430d 100644
--- a/chrome/browser/local_discovery/privet_constants.cc
+++ b/chrome/browser/local_discovery/privet_constants.cc
@@ -8,6 +8,8 @@
 
 const char kPrivetKeyError[] = "error";
 const char kPrivetInfoKeyToken[] = "x-privet-token";
+const char kPrivetInfoKeyAPIList[] = "api";
+const char kPrivetInfoKeyID[] = "id";
 const char kPrivetKeyDeviceID[] = "device_id";
 const char kPrivetKeyClaimURL[] = "claim_url";
 const char kPrivetKeyClaimToken[] = "token";
diff --git a/chrome/browser/local_discovery/privet_constants.h b/chrome/browser/local_discovery/privet_constants.h
index 9a04eef..729be5a 100644
--- a/chrome/browser/local_discovery/privet_constants.h
+++ b/chrome/browser/local_discovery/privet_constants.h
@@ -9,6 +9,8 @@
 
 extern const char kPrivetKeyError[];
 extern const char kPrivetInfoKeyToken[];
+extern const char kPrivetInfoKeyAPIList[];
+extern const char kPrivetInfoKeyID[];
 extern const char kPrivetKeyDeviceID[];
 extern const char kPrivetKeyClaimURL[];
 extern const char kPrivetKeyClaimToken[];
diff --git a/chrome/browser/local_discovery/privet_http.h b/chrome/browser/local_discovery/privet_http.h
index 6b1069c..0f4d333 100644
--- a/chrome/browser/local_discovery/privet_http.h
+++ b/chrome/browser/local_discovery/privet_http.h
@@ -24,6 +24,9 @@
     virtual ~Delegate() {}
 
     // In case of non-HTTP errors, |http_code| will be -1.
+
+    // TODO(noamsml): Remove http_code from this delegate; it's unnecessary in
+    // practice
     virtual void OnPrivetInfoDone(
         PrivetInfoOperation* operation,
         int http_code,
@@ -60,6 +63,7 @@
         const std::string& token,
         const GURL& url) = 0;
 
+    // TODO(noamsml): Remove all unnecessary parameters.
     // Called in case of an error while registering.  |action| is the
     // registration action taken during the error. |reason| is the reason for
     // the failure. |printer_http_code| is the http code returned from the
@@ -86,6 +90,63 @@
   virtual PrivetHTTPClient* GetHTTPClient() = 0;
 };
 
+class PrivetCapabilitiesOperation {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // |capabilities| will be NULL in case of an error.
+    virtual void OnPrivetCapabilities(
+        PrivetCapabilitiesOperation* capabilities_operation,
+        int http_error,
+        const base::DictionaryValue* capabilities) = 0;
+  };
+
+  virtual ~PrivetCapabilitiesOperation() {}
+  virtual void Start() = 0;
+
+  virtual PrivetHTTPClient* GetHTTPClient() = 0;
+};
+
+class PrivetLocalPrintOperation {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+    virtual void OnPrivetPrintingRequestPDF(
+        const PrivetLocalPrintOperation* print_operation) = 0;
+    virtual void OnPrivetPrintingRequestPWGRaster(
+        const PrivetLocalPrintOperation* print_operation) = 0;
+    virtual void OnPrivetPrintingDone(
+        const PrivetLocalPrintOperation* print_operation) = 0;
+    virtual void OnPrivetPrintingError(
+        const PrivetLocalPrintOperation* print_operation, int http_code) = 0;
+  };
+
+  virtual ~PrivetLocalPrintOperation() {}
+
+  virtual void Start() = 0;
+
+  // Should be called ONLY after |OnPrivetPrintingRequestPDF| or
+  // |OnPrivetPrintingRequestPWGRaster| are called on the delegate.  Data should
+  // be in PDF or PWG format depending on what is requested by the local print
+  // operation.
+  virtual void SendData(const std::string& data) = 0;
+
+  // Optional attributes for /submitdoc. Call before calling |Start()|
+  // |ticket| should be in CJT format.
+  virtual void SetTicket(const std::string& ticket) = 0;
+  // Username and jobname are for display only.
+  virtual void SetUsername(const std::string& username) = 0;
+  virtual void SetJobname(const std::string& jobname) = 0;
+  // If |offline| is true, we will indicate to the printer not to post the job
+  // to Google Cloud Print.
+  virtual void SetOffline(bool offline) = 0;
+
+  virtual PrivetHTTPClient* GetHTTPClient() = 0;
+};
+
 // Privet HTTP client. Must not outlive the operations it creates.
 class PrivetHTTPClient {
  public:
@@ -97,6 +158,10 @@
       PrivetRegisterOperation::Delegate* delegate) = 0;
   virtual scoped_ptr<PrivetInfoOperation> CreateInfoOperation(
       PrivetInfoOperation::Delegate* delegate) = 0;
+  virtual scoped_ptr<PrivetCapabilitiesOperation> CreateCapabilitiesOperation(
+      PrivetCapabilitiesOperation::Delegate* delegate) = 0;
+  virtual scoped_ptr<PrivetLocalPrintOperation> CreateLocalPrintOperation(
+      PrivetLocalPrintOperation::Delegate* delegate) = 0;
 
   // A name for the HTTP client, e.g. the device name for the privet device.
   virtual const std::string& GetName() = 0;
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/local_discovery/privet_http_impl.cc
index 3522107..3c13c3b 100644
--- a/chrome/browser/local_discovery/privet_http_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_impl.cc
@@ -6,24 +6,53 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
-#include "base/rand_util.h"
-#include "base/strings/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/local_discovery/privet_constants.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 
 namespace local_discovery {
 
 namespace {
-// First format argument (string) is the host, second format argument (int) is
-// the port.
-const char kPrivetInfoURLFormat[] = "http://%s:%d/privet/info";
-// First format argument (string) is the host, second format argument (int) is
-// the port, third argument (string) is the action name, fourth argument
-// (string) is the user name.
-const char kPrivetRegisterURLFormat[] =
-    "http://%s:%d/privet/register?action=%s&user=%s";
+const char kUrlPlaceHolder[] = "http://host/";
+const char kPrivetRegisterActionArgName[] = "action";
+const char kPrivetRegisterUserArgName[] = "user";
+
+const char kPrivetInfoPath[] = "/privet/info";
+const char kPrivetRegisterPath[] = "/privet/register";
+const char kPrivetCapabilitiesPath[] = "/privet/capabilities";
+const char kPrivetSubmitdocPath[] = "/privet/printer/submitdoc";
+const char kPrivetCreatejobPath[] = "/privet/printer/createjob";
+
+const char kPrivetURLKeyUser[] = "user";
+const char kPrivetURLKeyJobname[] = "jobname";
+const char kPrivetURLKeyOffline[] = "offline";
+const char kPrivetURLValueOffline[] = "1";
+
+const char kPrivetContentTypePDF[] = "application/pdf";
+const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
+
+const char kPrivetCDDKeySupportedContentTypes[] =
+    "printer.supported_content_type";
+
+const char kPrivetCDDKeyContentType[] = "content_type";
 
 const int kPrivetCancelationTimeoutSeconds = 3;
+
+GURL CreatePrivetURL(const std::string& path) {
+  GURL url(kUrlPlaceHolder);
+  GURL::Replacements replacements;
+  replacements.SetPathStr(path);
+  return url.ReplaceComponents(replacements);
+}
+
+GURL CreatePrivetRegisterURL(const std::string& action,
+                             const std::string& user) {
+  GURL url = CreatePrivetURL(kPrivetRegisterPath);
+  url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
+  return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
+}
+
 }  // namespace
 
 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
@@ -36,14 +65,8 @@
 }
 
 void PrivetInfoOperationImpl::Start() {
-  std::string url = base::StringPrintf(
-      kPrivetInfoURLFormat,
-      privet_client_->host_port().host().c_str(),
-      privet_client_->host_port().port());
-
-  url_fetcher_ = privet_client_->fetcher_factory().CreateURLFetcher(
-      GURL(url), net::URLFetcher::GET, this);
-
+  url_fetcher_ = privet_client_->CreateURLFetcher(
+      CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
   url_fetcher_->Start();
 }
 
@@ -73,14 +96,14 @@
     const std::string& user,
     PrivetRegisterOperation::Delegate* delegate)
     : user_(user), delegate_(delegate), privet_client_(privet_client),
-      ongoing_(false) {
+      ongoing_(false), info_for_confirmation_(false) {
 }
 
 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
 }
 
 void PrivetRegisterOperationImpl::Start() {
-  if (privet_client_->fetcher_factory().get_token() == "") {
+  if (!privet_client_->HasToken()) {
     StartInfoOperation();
     return;
   }
@@ -150,27 +173,6 @@
 
     if (error == kPrivetErrorInvalidXPrivetToken) {
       StartInfoOperation();
-
-      // Use a list of transient error names, but also detect if a "timeout"
-      // key is present as a fallback.
-    } else if (PrivetErrorTransient(error) ||
-               value->HasKey(kPrivetKeyTimeout)) {
-      int timeout_seconds;
-      double random_scaling_factor =
-          1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
-
-      if (!value->GetInteger(kPrivetKeyTimeout, &timeout_seconds)) {
-        timeout_seconds = kPrivetDefaultTimeout;
-      }
-
-      int timeout_seconds_randomized =
-          static_cast<int>(timeout_seconds * random_scaling_factor);
-
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&PrivetRegisterOperationImpl::SendRequest,
-                     AsWeakPtr(), current_action_),
-                     base::TimeDelta::FromSeconds(timeout_seconds_randomized));
     } else  {
       ongoing_ = false;
       delegate_->OnPrivetRegisterError(this,
@@ -190,11 +192,9 @@
 }
 
 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
-  GURL url = GetURLForActionAndUser(privet_client_, action, user_);
-
   current_action_ = action;
-  url_fetcher_ = privet_client_->fetcher_factory().CreateURLFetcher(
-      url, net::URLFetcher::POST, this);
+  url_fetcher_ = privet_client_->CreateURLFetcher(
+      CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
   url_fetcher_->Start();
 }
 
@@ -229,13 +229,26 @@
   std::string id;
   value.GetString(kPrivetKeyDeviceID, &id);
   ongoing_ = false;
-  delegate_->OnPrivetRegisterDone(this, id);
+  expected_id_ = id;
+  info_for_confirmation_ = true;
+  StartInfoOperation();
 }
 
 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
     PrivetInfoOperation* operation,
     int http_code,
     const base::DictionaryValue* value) {
+  if (!info_for_confirmation_) {
+    GetTokenFromInfoCall(operation, http_code, value);
+  } else {
+    VerifyIDFromInfoCall(operation, http_code, value);
+  }
+}
+
+void PrivetRegisterOperationImpl::GetTokenFromInfoCall(
+    PrivetInfoOperation* operation,
+    int http_code,
+    const base::DictionaryValue* value) {
   // TODO(noamsml): Distinguish between network errors and unparsable JSON in
   // this case.
   if (!value) {
@@ -274,37 +287,63 @@
   }
 }
 
+void PrivetRegisterOperationImpl::VerifyIDFromInfoCall(
+    PrivetInfoOperation* operation,
+    int http_code,
+    const base::DictionaryValue* value) {
+  // TODO (noamsml): Simplify error case.
+  if (!value) {
+    delegate_->OnPrivetRegisterError(this,
+                                     kPrivetActionNameInfo,
+                                     FAILURE_NETWORK,
+                                     -1,
+                                     NULL);
+    return;
+  }
+
+  if (!value->HasKey(kPrivetInfoKeyID)) {
+    if (value->HasKey(kPrivetKeyError)) {
+      delegate_->OnPrivetRegisterError(this,
+                                       kPrivetActionNameInfo,
+                                       FAILURE_JSON_ERROR,
+                                       http_code,
+                                       value);
+    } else {
+      delegate_->OnPrivetRegisterError(this,
+                                       kPrivetActionNameInfo,
+                                       FAILURE_MALFORMED_RESPONSE,
+                                       -1,
+                                       NULL);
+    }
+    return;
+  }
+
+  std::string id;
+
+  if (!value->GetString(kPrivetInfoKeyID, &id) ||
+      id != expected_id_) {
+    delegate_->OnPrivetRegisterError(this,
+                                     kPrivetActionNameInfo,
+                                     FAILURE_MALFORMED_RESPONSE,
+                                     -1,
+                                     NULL);
+  } else {
+    delegate_->OnPrivetRegisterDone(this, id);
+  }
+}
+
 void PrivetRegisterOperationImpl::StartInfoOperation() {
   info_operation_ = privet_client_->CreateInfoOperation(this);
   info_operation_->Start();
 }
 
-bool PrivetRegisterOperationImpl::PrivetErrorTransient(
-    const std::string& error) {
-  return (error == kPrivetErrorDeviceBusy) ||
-         (error == kPrivetErrorPendingUserAction);
-}
-
-// static
-GURL PrivetRegisterOperationImpl::GetURLForActionAndUser(
-    PrivetHTTPClientImpl* privet_client,
-    const std::string& action,
-    const std::string& user) {
-  return GURL(base::StringPrintf(kPrivetRegisterURLFormat,
-                                 privet_client->host_port().host().c_str(),
-                                 privet_client->host_port().port(),
-                                 action.c_str(),
-                                 user.c_str()));
-}
-
 PrivetRegisterOperationImpl::Cancelation::Cancelation(
     PrivetHTTPClientImpl* privet_client,
     const std::string& user) {
-  GURL url = GetURLForActionAndUser(privet_client,
-                                    kPrivetActionCancel,
-                                    user);
-  url_fetcher_ = privet_client->fetcher_factory().CreateURLFetcher(
-      url, net::URLFetcher::POST, this);
+  url_fetcher_ =
+      privet_client->CreateURLFetcher(
+          CreatePrivetRegisterURL(kPrivetActionCancel, user),
+          net::URLFetcher::POST, this);
   url_fetcher_->Start();
 }
 
@@ -328,6 +367,284 @@
   // the message loop.
 }
 
+PrivetCapabilitiesOperationImpl::PrivetCapabilitiesOperationImpl(
+    PrivetHTTPClientImpl* privet_client,
+    PrivetCapabilitiesOperation::Delegate* delegate)
+    : privet_client_(privet_client), delegate_(delegate) {
+}
+
+PrivetCapabilitiesOperationImpl::~PrivetCapabilitiesOperationImpl() {
+}
+
+void PrivetCapabilitiesOperationImpl::Start() {
+  if (!privet_client_->HasToken()) {
+    info_operation_ = privet_client_->CreateInfoOperation(this);
+    info_operation_->Start();
+  } else {
+    StartRequest();
+  }
+}
+
+void PrivetCapabilitiesOperationImpl::StartRequest() {
+  url_fetcher_ = privet_client_->CreateURLFetcher(
+      CreatePrivetURL(kPrivetCapabilitiesPath), net::URLFetcher::GET, this);
+
+  url_fetcher_->Start();
+}
+
+void PrivetCapabilitiesOperationImpl::OnPrivetInfoDone(
+    PrivetInfoOperation* operation,
+    int http_code,
+    const base::DictionaryValue* value) {
+  if (value && !value->HasKey(kPrivetKeyError)) {
+    StartRequest();
+  } else {
+    delegate_->OnPrivetCapabilities(this, http_code, NULL);
+  }
+}
+
+PrivetHTTPClient* PrivetCapabilitiesOperationImpl::GetHTTPClient() {
+  return privet_client_;
+}
+
+void PrivetCapabilitiesOperationImpl::OnError(
+    PrivetURLFetcher* fetcher,
+    PrivetURLFetcher::ErrorType error) {
+  delegate_->OnPrivetCapabilities(this, -1, NULL);
+}
+
+void PrivetCapabilitiesOperationImpl::OnParsedJson(
+    PrivetURLFetcher* fetcher,
+    const base::DictionaryValue* value,
+    bool has_error) {
+  std::string error;
+  if (value->GetString(kPrivetKeyError, &error) &&
+      error == kPrivetErrorInvalidXPrivetToken) {
+    info_operation_ = privet_client_->CreateInfoOperation(this);
+    info_operation_->Start();
+  } else {
+    delegate_->OnPrivetCapabilities(this, 200, value);
+  }
+}
+
+PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
+    PrivetHTTPClientImpl* privet_client,
+    PrivetLocalPrintOperation::Delegate* delegate)
+    : privet_client_(privet_client), delegate_(delegate),
+      use_pdf_(false), has_capabilities_(false), has_extended_workflow_(false),
+      processed_api_list_(false), started_(false), offline_(false) {
+}
+
+PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
+}
+
+void PrivetLocalPrintOperationImpl::Start() {
+  DCHECK(!started_);
+
+  current_request_ =
+      base::Bind(&PrivetLocalPrintOperationImpl::StartInitialRequest,
+                 base::Unretained(this));
+
+  // We need to get the /info response so we can know which APIs are available.
+  // TODO(noamsml): Use cached info when available.
+  info_operation_ = privet_client_->CreateInfoOperation(this);
+  info_operation_->Start();
+
+  started_ = true;
+}
+
+void PrivetLocalPrintOperationImpl::StartCurrentRequest() {
+  DCHECK(!current_request_.is_null());
+  current_request_.Run();
+}
+
+void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
+    PrivetInfoOperation* operation,
+    int http_code,
+    const base::DictionaryValue* value) {
+  if (value && !value->HasKey(kPrivetKeyError)) {
+    if (!processed_api_list_) {
+      has_capabilities_ = false;
+      has_extended_workflow_ = false;
+      bool has_printing = false;
+
+      const base::ListValue* api_list;
+      if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
+        for (size_t i = 0; i < api_list->GetSize(); i++) {
+          std::string api;
+          api_list->GetString(i, &api);
+          if (api == kPrivetCapabilitiesPath) {
+            has_capabilities_ = true;
+          } else if (api == kPrivetSubmitdocPath) {
+            has_printing = true;
+          } else if (api == kPrivetCreatejobPath) {
+            has_extended_workflow_ = true;
+          }
+        }
+      }
+
+      if (!has_printing) {
+        delegate_->OnPrivetPrintingError(this, -1);
+        return;
+      }
+    }
+    processed_api_list_ = true;
+
+    StartCurrentRequest();
+  } else {
+    delegate_->OnPrivetPrintingError(this, http_code);
+  }
+}
+
+void PrivetLocalPrintOperationImpl::StartInitialRequest() {
+  if (has_capabilities_) {
+    GetCapabilities();
+  } else {
+    // Since we have no capabiltties, the only reasonable format we can
+    // request is PWG Raster.
+    use_pdf_ = false;
+    delegate_->OnPrivetPrintingRequestPWGRaster(this);
+  }
+}
+
+void PrivetLocalPrintOperationImpl::GetCapabilities() {
+  current_response_ = base::Bind(
+      &PrivetLocalPrintOperationImpl::OnCapabilities,
+      base::Unretained(this));
+
+  url_fetcher_= privet_client_->CreateURLFetcher(
+      CreatePrivetURL(kPrivetCapabilitiesPath), net::URLFetcher::GET, this);
+  url_fetcher_->Start();
+}
+
+void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
+  current_response_ = base::Bind(
+      &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
+      base::Unretained(this));
+
+  GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
+
+  if (!user_.empty()) {
+    url = net::AppendQueryParameter(url,
+                                    kPrivetURLKeyUser,
+                                    user_);
+  }
+
+  if (!jobname_.empty()) {
+    url = net::AppendQueryParameter(url,
+                                    kPrivetURLKeyJobname,
+                                    jobname_);
+  }
+
+  if (offline_) {
+    url = net::AppendQueryParameter(url,
+                                    kPrivetURLKeyOffline,
+                                    kPrivetURLValueOffline);
+  }
+
+  url_fetcher_= privet_client_->CreateURLFetcher(
+      url, net::URLFetcher::POST, this);
+
+  DCHECK(!data_.empty());
+  url_fetcher_->SetUploadData(
+      use_pdf_ ? kPrivetContentTypePDF : kPrivetContentTypePWGRaster,
+      data_);
+
+  url_fetcher_->Start();
+}
+
+void PrivetLocalPrintOperationImpl::OnCapabilities(
+    const base::DictionaryValue* value) {
+  const base::ListValue* supported_content_types;
+  use_pdf_ = false;
+
+  if (value->GetList(kPrivetCDDKeySupportedContentTypes,
+                     &supported_content_types)) {
+    for (size_t i = 0; i < supported_content_types->GetSize();
+         i++) {
+      const base::DictionaryValue* content_type_value;
+      std::string content_type;
+
+      if (supported_content_types->GetDictionary(i, &content_type_value) &&
+          content_type_value->GetString(kPrivetCDDKeyContentType,
+                                        &content_type) &&
+          content_type == kPrivetContentTypePDF) {
+        use_pdf_ = true;
+      }
+    }
+  }
+
+  if (use_pdf_)
+    delegate_->OnPrivetPrintingRequestPDF(this);
+  else
+    delegate_->OnPrivetPrintingRequestPWGRaster(this);
+}
+
+void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
+    const base::DictionaryValue* value) {
+  // If we've gotten this far, there are no errors, so we've effectively
+  // succeeded.
+
+  delegate_->OnPrivetPrintingDone(this);
+}
+
+PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
+  return privet_client_;
+}
+
+void PrivetLocalPrintOperationImpl::OnError(
+    PrivetURLFetcher* fetcher,
+    PrivetURLFetcher::ErrorType error) {
+  delegate_->OnPrivetPrintingError(this, -1);
+}
+
+void PrivetLocalPrintOperationImpl::OnParsedJson(
+    PrivetURLFetcher* fetcher,
+    const base::DictionaryValue* value,
+    bool has_error) {
+  std::string error;
+  if (value->GetString(kPrivetKeyError, &error) &&
+      error == kPrivetErrorInvalidXPrivetToken) {
+    info_operation_ = privet_client_->CreateInfoOperation(this);
+    info_operation_->Start();
+  } else if (has_error) {
+    delegate_->OnPrivetPrintingError(this, -1);
+  } else {
+    DCHECK(!current_response_.is_null());
+    current_response_.Run(value);
+  }
+}
+
+void PrivetLocalPrintOperationImpl::SendData(const std::string& data) {
+  DCHECK(started_);
+  data_ = data;
+  current_request_ = base::Bind(
+      &PrivetLocalPrintOperationImpl::DoSubmitdoc,
+      base::Unretained(this));
+
+  StartCurrentRequest();
+}
+
+void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
+  DCHECK(!started_);
+  ticket_ = ticket;
+}
+
+void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
+  DCHECK(!started_);
+  user_= user;
+}
+
+void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
+  DCHECK(!started_);
+  jobname_ = jobname;
+}
+
+void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
+  DCHECK(!started_);
+  offline_ = offline;
+}
+
 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
     const std::string& name,
     const net::HostPortPair& host_port,
@@ -358,10 +675,36 @@
       new PrivetInfoOperationImpl(this, delegate));
 }
 
+scoped_ptr<PrivetCapabilitiesOperation>
+PrivetHTTPClientImpl::CreateCapabilitiesOperation(
+    PrivetCapabilitiesOperation::Delegate* delegate) {
+  return scoped_ptr<PrivetCapabilitiesOperation>(
+      new PrivetCapabilitiesOperationImpl(this, delegate));
+}
+
+scoped_ptr<PrivetLocalPrintOperation>
+PrivetHTTPClientImpl::CreateLocalPrintOperation(
+    PrivetLocalPrintOperation::Delegate* delegate) {
+  return scoped_ptr<PrivetLocalPrintOperation>(
+      new PrivetLocalPrintOperationImpl(this, delegate));
+}
+
 const std::string& PrivetHTTPClientImpl::GetName() {
   return name_;
 }
 
+scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
+    const GURL& url, net::URLFetcher::RequestType request_type,
+    PrivetURLFetcher::Delegate* delegate) const {
+  GURL::Replacements replacements;
+  replacements.SetHostStr(host_port_.host());
+  std::string port(base::IntToString(host_port_.port()));  // Keep string alive.
+  replacements.SetPortStr(port);
+  GURL url2 = url.ReplaceComponents(replacements);
+  return fetcher_factory_.CreateURLFetcher(url.ReplaceComponents(replacements),
+                                           request_type, delegate);
+}
+
 void PrivetHTTPClientImpl::CacheInfo(const base::DictionaryValue* cached_info) {
   cached_info_.reset(cached_info->DeepCopy());
   std::string token;
@@ -370,4 +713,8 @@
   }
 }
 
+bool PrivetHTTPClientImpl::HasToken() const {
+  return fetcher_factory_.get_token() != "";
+};
+
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_http_impl.h b/chrome/browser/local_discovery/privet_http_impl.h
index b8d5496..9956585 100644
--- a/chrome/browser/local_discovery/privet_http_impl.h
+++ b/chrome/browser/local_discovery/privet_http_impl.h
@@ -64,6 +64,14 @@
                                 int http_code,
                                 const base::DictionaryValue* value) OVERRIDE;
 
+  void GetTokenFromInfoCall(PrivetInfoOperation* operation,
+                            int http_code,
+                            const base::DictionaryValue* value);
+
+  void VerifyIDFromInfoCall(PrivetInfoOperation* operation,
+                            int http_code,
+                            const base::DictionaryValue* value);
+
   virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE;
  private:
   class Cancelation : public PrivetURLFetcher::Delegate {
@@ -97,13 +105,6 @@
 
   void SendRequest(const std::string& action);
 
-  bool PrivetErrorTransient(const std::string& error);
-
-  static GURL GetURLForActionAndUser(
-      PrivetHTTPClientImpl* privet_client,
-      const std::string& action,
-      const std::string& user);
-
   std::string user_;
   std::string current_action_;
   scoped_ptr<PrivetURLFetcher> url_fetcher_;
@@ -113,6 +114,112 @@
   // Required to ensure destroying completed register operations doesn't cause
   // extraneous cancelations.
   bool ongoing_;
+  // Whether the current /privet/info call is for the final confirmation or
+  // for initial token getting.
+  bool info_for_confirmation_;
+  scoped_ptr<PrivetInfoOperation> info_operation_;
+  std::string expected_id_;
+};
+
+// TODO(noamsml): Factor out some of this code into a PrivetBaseOperation
+class PrivetCapabilitiesOperationImpl : public PrivetCapabilitiesOperation,
+                                        public PrivetURLFetcher::Delegate,
+                                        public PrivetInfoOperation::Delegate {
+ public:
+  PrivetCapabilitiesOperationImpl(
+      PrivetHTTPClientImpl* privet_client,
+      PrivetCapabilitiesOperation::Delegate* delegate);
+  virtual ~PrivetCapabilitiesOperationImpl();
+  virtual void Start() OVERRIDE;
+
+  virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE;
+
+  virtual void OnError(PrivetURLFetcher* fetcher,
+                       PrivetURLFetcher::ErrorType error) OVERRIDE;
+  virtual void OnParsedJson(PrivetURLFetcher* fetcher,
+                            const base::DictionaryValue* value,
+                            bool has_error) OVERRIDE;
+
+  virtual void OnPrivetInfoDone(PrivetInfoOperation* operation,
+                                int http_code,
+                                const base::DictionaryValue* value) OVERRIDE;
+ private:
+  void StartRequest();
+
+  PrivetHTTPClientImpl* privet_client_;
+  PrivetCapabilitiesOperation::Delegate* delegate_;
+
+  scoped_ptr<PrivetURLFetcher> url_fetcher_;
+  scoped_ptr<PrivetInfoOperation> info_operation_;
+};
+
+class PrivetLocalPrintOperationImpl
+    : public PrivetLocalPrintOperation,
+      public PrivetURLFetcher::Delegate,
+      public PrivetInfoOperation::Delegate {
+ public:
+  PrivetLocalPrintOperationImpl(
+      PrivetHTTPClientImpl* privet_client,
+      PrivetLocalPrintOperation::Delegate* delegate);
+
+  virtual ~PrivetLocalPrintOperationImpl();
+  virtual void Start() OVERRIDE;
+
+  virtual void SendData(const std::string& data) OVERRIDE;
+
+  virtual void SetTicket(const std::string& ticket) OVERRIDE;
+
+  virtual void SetUsername(const std::string& user) OVERRIDE;
+
+  virtual void SetJobname(const std::string& jobname) OVERRIDE;
+
+  virtual  void SetOffline(bool offline) OVERRIDE;
+
+  virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE;
+
+  virtual void OnError(PrivetURLFetcher* fetcher,
+                       PrivetURLFetcher::ErrorType error) OVERRIDE;
+  virtual void OnParsedJson(PrivetURLFetcher* fetcher,
+                            const base::DictionaryValue* value,
+                            bool has_error) OVERRIDE;
+
+  virtual void OnPrivetInfoDone(PrivetInfoOperation* operation,
+                                int http_code,
+                                const base::DictionaryValue* value) OVERRIDE;
+ private:
+  typedef base::Callback<void(const base::DictionaryValue* value)>
+      ResponseCallback;
+
+  void StartCurrentRequest();
+
+  void StartInitialRequest();
+  void GetCapabilities();
+  // TODO(noamsml): void DoCreatejob();
+  void DoSubmitdoc();
+
+  void OnCapabilities(const base::DictionaryValue* value);
+  void OnSubmitdocResponse(const base::DictionaryValue* value);
+
+  PrivetHTTPClientImpl* privet_client_;
+  PrivetLocalPrintOperation::Delegate* delegate_;
+
+  base::Closure current_request_;
+  ResponseCallback current_response_;
+
+  std::string ticket_;
+  std::string data_;
+
+  bool use_pdf_;
+  bool has_capabilities_;
+  bool has_extended_workflow_;
+  bool processed_api_list_;
+  bool started_;
+  bool offline_;
+
+  std::string user_;
+  std::string jobname_;
+
+  scoped_ptr<PrivetURLFetcher> url_fetcher_;
   scoped_ptr<PrivetInfoOperation> info_operation_;
 };
 
@@ -133,15 +240,23 @@
   virtual scoped_ptr<PrivetInfoOperation> CreateInfoOperation(
       PrivetInfoOperation::Delegate* delegate) OVERRIDE;
 
+  virtual scoped_ptr<PrivetCapabilitiesOperation> CreateCapabilitiesOperation(
+      PrivetCapabilitiesOperation::Delegate* delegate) OVERRIDE;
+
+  virtual scoped_ptr<PrivetLocalPrintOperation> CreateLocalPrintOperation(
+      PrivetLocalPrintOperation::Delegate* delegate) OVERRIDE;
+
   virtual const std::string& GetName() OVERRIDE;
 
-  const PrivetURLFetcherFactory& fetcher_factory() const {
-    return fetcher_factory_;
-  }
-  const net::HostPortPair& host_port() const { return host_port_; }
+  scoped_ptr<PrivetURLFetcher> CreateURLFetcher(
+      const GURL& url,
+      net::URLFetcher::RequestType request_type,
+      PrivetURLFetcher::Delegate* delegate) const;
 
   void CacheInfo(const base::DictionaryValue* cached_info);
 
+  bool HasToken() const;
+
  private:
   std::string name_;
   PrivetURLFetcherFactory fetcher_factory_;
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index 784085e..9262b60 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -27,7 +27,7 @@
     "       \"type\": ["
     "               \"printer\""
     "       ],"
-    "       \"id\": \"11111111-2222-3333-4444-555555555555\","
+    "       \"id\": \"\","
     "       \"device_state\": \"idle\","
     "       \"connection_state\": \"online\","
     "       \"manufacturer\": \"Google\","
@@ -46,6 +46,34 @@
     "       ]"
     "}";
 
+const char kSampleInfoResponseRegistered[] = "{"
+    "       \"version\": \"1.0\","
+    "       \"name\": \"Common printer\","
+    "       \"description\": \"Printer connected through Chrome connector\","
+    "       \"url\": \"https://www.google.com/cloudprint\","
+    "       \"type\": ["
+    "               \"printer\""
+    "       ],"
+    "       \"id\": \"MyDeviceID\","
+    "       \"device_state\": \"idle\","
+    "       \"connection_state\": \"online\","
+    "       \"manufacturer\": \"Google\","
+    "       \"model\": \"Google Chrome\","
+    "       \"serial_number\": \"1111-22222-33333-4444\","
+    "       \"firmware\": \"24.0.1312.52\","
+    "       \"uptime\": 600,"
+    "       \"setup_url\": \"http://support.google.com/\","
+    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
+    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
+    "       \"x-privet-token\": \"SampleTokenForTesting\","
+    "       \"api\": ["
+    "               \"/privet/accesstoken\","
+    "               \"/privet/capabilities\","
+    "               \"/privet/printer/submitdoc\","
+    "       ]"
+    "}";
+
+
 const char kSampleRegisterStartResponse[] = "{"
     "\"user\": \"example@google.com\","
     "\"action\": \"start\""
@@ -80,6 +108,33 @@
     "\"action\": \"cancel\""
     "}";
 
+const char kSampleLocalPrintResponse[] = "{"
+    "\"job_id\": \"123\","
+    "\"expires_in\": 500,"
+    "\"job_type\": \"application/pdf\","
+    "\"job_size\": 16,"
+    "\"job_name\": \"Sample job name\","
+    "}";
+
+const char kSampleCapabilitiesResponse[] = "{"
+    "\"version\" : \"1.0\","
+    "\"printer\" : {"
+    "  \"supported_content_type\" : ["
+    "   { \"content_type\" : \"application/pdf\" },"
+    "   { \"content_type\" : \"image/pwg-raster\" }"
+    "  ]"
+    "}"
+    "}";
+
+const char kSampleCapabilitiesResponsePWGOnly[] = "{"
+    "\"version\" : \"1.0\","
+    "\"printer\" : {"
+    "  \"supported_content_type\" : ["
+    "   { \"content_type\" : \"image/pwg-raster\" }"
+    "  ]"
+    "}"
+    "}";
+
 class MockTestURLFetcherFactoryDelegate
     : public net::TestURLFetcher::DelegateForTests {
  public:
@@ -105,9 +160,38 @@
         request_context_.get()));
     fetcher_factory_.SetDelegateForTests(&fetcher_delegate_);
   }
+
   virtual ~PrivetHTTPTest() {
   }
 
+  bool SuccessfulResponseToURL(const GURL& url,
+                               const std::string& response) {
+    return SuccessfulResponseToURLAndData(url, "", response);
+  }
+
+  bool SuccessfulResponseToURLAndData(const GURL& url,
+                                      const std::string& data,
+                                      const std::string& response) {
+    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
+    EXPECT_TRUE(fetcher);
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
+
+    if (!data.empty()) {
+      EXPECT_EQ(data, fetcher->upload_data());
+    }
+
+    if (!fetcher || url != fetcher->GetOriginalURL() ||
+        (!data.empty() && data != fetcher->upload_data()))
+      return false;
+
+    fetcher->SetResponseString(response);
+    fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
+                                              net::OK));
+    fetcher->set_response_code(200);
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    return true;
+  }
+
  protected:
   base::MessageLoop loop_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
@@ -140,6 +224,31 @@
   scoped_ptr<base::DictionaryValue> value_;
 };
 
+class MockCapabilitiesDelegate : public PrivetCapabilitiesOperation::Delegate {
+ public:
+  MockCapabilitiesDelegate() {}
+  ~MockCapabilitiesDelegate() {}
+
+  virtual void OnPrivetCapabilities(
+      PrivetCapabilitiesOperation* operation,
+      int response_code,
+      const base::DictionaryValue* value) OVERRIDE {
+    if (!value) {
+      value_.reset();
+    } else {
+      value_.reset(value->DeepCopy());
+    }
+
+    OnPrivetCapabilitiesDoneInternal(response_code);
+  }
+
+  MOCK_METHOD1(OnPrivetCapabilitiesDoneInternal, void(int response_code));
+
+  const base::DictionaryValue* value() { return value_.get(); }
+ protected:
+  scoped_ptr<base::DictionaryValue> value_;
+};
+
 class MockRegisterDelegate : public PrivetRegisterOperation::Delegate {
  public:
   MockRegisterDelegate() {
@@ -183,6 +292,40 @@
                void(const std::string& device_id));
 };
 
+class MockLocalPrintDelegate : public PrivetLocalPrintOperation::Delegate {
+ public:
+  MockLocalPrintDelegate() {}
+  ~MockLocalPrintDelegate() {}
+
+  virtual void OnPrivetPrintingRequestPDF(
+      const PrivetLocalPrintOperation* print_operation) {
+    OnPrivetPrintingRequestPDFInternal();
+  }
+
+  MOCK_METHOD0(OnPrivetPrintingRequestPDFInternal, void());
+
+  virtual void OnPrivetPrintingRequestPWGRaster(
+      const PrivetLocalPrintOperation* print_operation) {
+    OnPrivetPrintingRequestPWGRasterInternal();
+  }
+
+  MOCK_METHOD0(OnPrivetPrintingRequestPWGRasterInternal, void());
+
+  virtual void OnPrivetPrintingDone(
+      const PrivetLocalPrintOperation* print_operation) {
+    OnPrivetPrintingDoneInternal();
+  }
+
+  MOCK_METHOD0(OnPrivetPrintingDoneInternal, void());
+
+  virtual void OnPrivetPrintingError(
+      const PrivetLocalPrintOperation* print_operation, int http_code) {
+    OnPrivetPrintingErrorInternal(http_code);
+  }
+
+  MOCK_METHOD1(OnPrivetPrintingErrorInternal, void(int http_code));
+};
+
 class PrivetInfoTest : public PrivetHTTPTest {
  public:
   PrivetInfoTest() {}
@@ -291,6 +434,8 @@
   bool SuccessfulResponseToURL(const GURL& url,
                                const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
+    EXPECT_TRUE(fetcher);
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
     if (!fetcher || url != fetcher->GetOriginalURL())
       return false;
 
@@ -334,7 +479,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 
   EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimTokenInternal(
@@ -343,18 +488,22 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=getClaimToken&user=example@google.com"),
+           "action=getClaimToken&user=example%40google.com"),
       kSampleRegisterGetClaimTokenResponse));
 
   register_operation_->CompleteRegistration();
 
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/register?"
+           "action=complete&user=example%40google.com"),
+      kSampleRegisterCompleteResponse));
+
   EXPECT_CALL(register_delegate_, OnPrivetRegisterDoneInternal(
       "MyDeviceID"));
 
   EXPECT_TRUE(SuccessfulResponseToURL(
-      GURL("http://10.0.0.8:6006/privet/register?"
-           "action=complete&user=example@google.com"),
-      kSampleRegisterCompleteResponse));
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponseRegistered));
 }
 
 TEST_F(PrivetRegisterTest, RegisterNoInfoCall) {
@@ -366,7 +515,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 }
 
@@ -379,12 +528,12 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=getClaimToken&user=example@google.com"),
+           "action=getClaimToken&user=example%40google.com"),
       kSampleXPrivetErrorResponse));
 
   EXPECT_TRUE(SuccessfulResponseToURL(
@@ -396,7 +545,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=getClaimToken&user=example@google.com"),
+           "action=getClaimToken&user=example%40google.com"),
       kSampleRegisterGetClaimTokenResponse));
 }
 
@@ -409,7 +558,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterErrorTransient));
 
   EXPECT_CALL(fetcher_delegate_, OnRequestStart(0));
@@ -420,7 +569,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 }
 
@@ -433,7 +582,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 
   EXPECT_CALL(register_delegate_,
@@ -444,7 +593,7 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=getClaimToken&user=example@google.com"),
+           "action=getClaimToken&user=example%40google.com"),
       kSampleRegisterErrorPermanent));
 }
 
@@ -462,7 +611,6 @@
       kSampleInfoResponseBadJson));
 }
 
-
 TEST_F(PrivetRegisterTest, RegisterCancel) {
   // Start with info request first to populate XSRF token.
   info_operation_->Start();
@@ -475,14 +623,14 @@
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=start&user=example@google.com"),
+           "action=start&user=example%40google.com"),
       kSampleRegisterStartResponse));
 
   register_operation_->Cancel();
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/register?"
-           "action=cancel&user=example@google.com"),
+           "action=cancel&user=example%40google.com"),
       kSampleRegisterCancelResponse));
 
   // Must keep mocks alive for 3 seconds so the cancelation object can be
@@ -490,6 +638,158 @@
   RunFor(base::TimeDelta::FromSeconds(3));
 }
 
+class PrivetCapabilitiesTest : public PrivetHTTPTest {
+ public:
+  PrivetCapabilitiesTest() {}
+
+  virtual ~PrivetCapabilitiesTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    capabilities_operation_ = privet_client_->CreateCapabilitiesOperation(
+        &capabilities_delegate_);
+  }
+
+ protected:
+  scoped_ptr<PrivetCapabilitiesOperation> capabilities_operation_;
+  StrictMock<MockCapabilitiesDelegate> capabilities_delegate_;
+};
+
+TEST_F(PrivetCapabilitiesTest, SuccessfulCapabilities) {
+  capabilities_operation_->Start();
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_CALL(capabilities_delegate_, OnPrivetCapabilitiesDoneInternal(200));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponse));
+
+  std::string version;
+  EXPECT_TRUE(capabilities_delegate_.value()->GetString("version", &version));
+  EXPECT_EQ("1.0", version);
+};
+
+TEST_F(PrivetCapabilitiesTest, CacheToken) {
+  capabilities_operation_->Start();
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_CALL(capabilities_delegate_, OnPrivetCapabilitiesDoneInternal(200));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponse));
+
+  capabilities_operation_ = privet_client_->CreateCapabilitiesOperation(
+      &capabilities_delegate_);
+
+  capabilities_operation_->Start();
+
+  EXPECT_CALL(capabilities_delegate_, OnPrivetCapabilitiesDoneInternal(200));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponse));
+};
+
+TEST_F(PrivetCapabilitiesTest, BadToken) {
+  capabilities_operation_->Start();
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleXPrivetErrorResponse));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_CALL(capabilities_delegate_, OnPrivetCapabilitiesDoneInternal(200));
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponse));
+};
+
+class PrivetLocalPrintTest : public PrivetHTTPTest {
+ public:
+  PrivetLocalPrintTest() {}
+
+  virtual ~PrivetLocalPrintTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    local_print_operation_ = privet_client_->CreateLocalPrintOperation(
+        &local_print_delegate_);
+  }
+
+ protected:
+  scoped_ptr<PrivetLocalPrintOperation> local_print_operation_;
+  StrictMock<MockLocalPrintDelegate> local_print_delegate_;
+};
+
+TEST_F(PrivetLocalPrintTest, SuccessfulLocalPrint) {
+  local_print_operation_->SetUsername("sample@gmail.com");
+  local_print_operation_->SetJobname("Sample job name");
+  local_print_operation_->Start();
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingRequestPDFInternal());
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponse));
+
+  local_print_operation_->SendData("Sample print data");
+
+  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
+
+  // TODO(noamsml): Is encoding spaces as pluses standard?
+  EXPECT_TRUE(SuccessfulResponseToURLAndData(
+      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
+           "user=sample%40gmail.com&jobname=Sample+job+name"),
+      "Sample print data",
+      kSampleLocalPrintResponse));
+};
+
+TEST_F(PrivetLocalPrintTest, SuccessfulPWGLocalPrint) {
+  local_print_operation_->SetUsername("sample@gmail.com");
+  local_print_operation_->SetJobname("Sample job name");
+  local_print_operation_->Start();
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponse));
+
+  EXPECT_CALL(local_print_delegate_,
+              OnPrivetPrintingRequestPWGRasterInternal());
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/capabilities"),
+      kSampleCapabilitiesResponsePWGOnly));
+
+  local_print_operation_->SendData("Sample print data");
+
+  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
+
+  // TODO(noamsml): Is encoding spaces as pluses standard?
+  EXPECT_TRUE(SuccessfulResponseToURLAndData(
+      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
+           "user=sample%40gmail.com&jobname=Sample+job+name"),
+      "Sample print data",
+      kSampleLocalPrintResponse));
+};
+
 }  // namespace
 
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_notifications.cc b/chrome/browser/local_discovery/privet_notifications.cc
index 5b26b21..33cbba7 100644
--- a/chrome/browser/local_discovery/privet_notifications.cc
+++ b/chrome/browser/local_discovery/privet_notifications.cc
@@ -267,8 +267,7 @@
         ui::ResourceBundle::GetSharedInstance().GetImageNamed(
             IDR_LOCAL_DISCOVERY_CLOUDPRINT_ICON),
         WebKit::WebTextDirectionDefault,
-        message_center::NotifierId(
-            message_center::NotifierId::SYSTEM_COMPONENT),
+        message_center::NotifierId(GURL(kPrivetNotificationOriginUrl)),
         product_name,
         UTF8ToUTF16(kPrivetNotificationID),
         rich_notification_data,
diff --git a/chrome/browser/local_discovery/privet_notifications_unittest.cc b/chrome/browser/local_discovery/privet_notifications_unittest.cc
index 01ecbd2..0b90215 100644
--- a/chrome/browser/local_discovery/privet_notifications_unittest.cc
+++ b/chrome/browser/local_discovery/privet_notifications_unittest.cc
@@ -29,6 +29,8 @@
   MOCK_METHOD0(PrivetRemoveNotification, void());
 };
 
+// TODO(noamsml): Migrate this test to use a real privet info operation and a
+// fake URL fetcher.
 class MockPrivetInfoOperation : public PrivetInfoOperation {
  public:
   class DelegateForTests {
@@ -84,6 +86,18 @@
         this, delegate_for_tests_, delegate));
   }
 
+  virtual scoped_ptr<PrivetCapabilitiesOperation> CreateCapabilitiesOperation(
+      PrivetCapabilitiesOperation::Delegate* delegate) OVERRIDE {
+    NOTIMPLEMENTED();
+    return scoped_ptr<PrivetCapabilitiesOperation>();
+  }
+
+  virtual scoped_ptr<PrivetLocalPrintOperation> CreateLocalPrintOperation(
+      PrivetLocalPrintOperation::Delegate* delegate) OVERRIDE {
+    NOTIMPLEMENTED();
+    return scoped_ptr<PrivetLocalPrintOperation>();
+  }
+
   virtual const std::string& GetName() OVERRIDE { return name_; }
 
   virtual const base::DictionaryValue* GetCachedInfo() const OVERRIDE {
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
index f45d477..4c773c5 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/local_discovery/privet_url_fetcher.h"
 
+#include "base/bind.h"
 #include "base/json/json_reader.h"
+#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/local_discovery/privet_constants.h"
 #include "net/http/http_status_code.h"
@@ -15,6 +18,7 @@
 namespace {
 const char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: ";
 const char kXPrivetEmptyToken[] = "\"\"";
+const int kPrivetMaxRetries = 20;
 }
 
 PrivetURLFetcher::PrivetURLFetcher(
@@ -23,26 +27,43 @@
     net::URLFetcher::RequestType request_type,
     net::URLRequestContextGetter* request_context,
     PrivetURLFetcher::Delegate* delegate)
-    : delegate_(delegate) {
-  std::string sent_token = token;
-  if (sent_token.empty())
-    sent_token = kXPrivetEmptyToken;
-
-  url_fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
-  url_fetcher_->SetRequestContext(request_context);
-  url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) +
-                                      sent_token);
-
-  // URLFetcher requires us to set upload data for POST requests.
-  if (request_type == net::URLFetcher::POST)
-      url_fetcher_->SetUploadData(std::string(), std::string());
+    : privet_access_token_(token), url_(url), request_type_(request_type),
+      request_context_(request_context), delegate_(delegate), tries_(0),
+      weak_factory_(this) {
+  if (privet_access_token_.empty())
+    privet_access_token_ = kXPrivetEmptyToken;
 }
 
 PrivetURLFetcher::~PrivetURLFetcher() {
 }
 
+void PrivetURLFetcher::Try() {
+  tries_++;
+  if (tries_ < kPrivetMaxRetries) {
+    url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this));
+    url_fetcher_->SetRequestContext(request_context_);
+    url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) +
+                                        privet_access_token_);
+
+    // URLFetcher requires us to set upload data for POST requests.
+    if (request_type_ == net::URLFetcher::POST)
+      url_fetcher_->SetUploadData(upload_content_type_, upload_data_);
+
+    url_fetcher_->Start();
+  } else {
+    delegate_->OnError(this, RETRY_ERROR);
+  }
+}
+
 void PrivetURLFetcher::Start() {
-  url_fetcher_->Start();
+  DCHECK_EQ(tries_, 0);  // We haven't called |Start()| yet.
+  Try();
+}
+
+void PrivetURLFetcher::SetUploadData(const std::string& upload_content_type,
+                                     const std::string& upload_data) {
+  upload_content_type_ = upload_content_type;
+  upload_data_ = upload_data;
 }
 
 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
@@ -80,10 +101,42 @@
     return;
   }
 
+  std::string error;
+  if (dictionary_value->GetString(kPrivetKeyError, &error)) {
+    if (PrivetErrorTransient(error) ||
+        dictionary_value->HasKey(kPrivetKeyTimeout)) {
+      int timeout_seconds;
+      if (!dictionary_value->GetInteger(kPrivetKeyTimeout, &timeout_seconds)) {
+        timeout_seconds = kPrivetDefaultTimeout;
+      }
+
+      ScheduleRetry(timeout_seconds);
+      return;
+    }
+  }
+
   delegate_->OnParsedJson(this, dictionary_value,
                           dictionary_value->HasKey(kPrivetKeyError));
 }
 
+void PrivetURLFetcher::ScheduleRetry(int timeout_seconds) {
+  double random_scaling_factor =
+      1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
+
+  int timeout_seconds_randomized =
+      static_cast<int>(timeout_seconds * random_scaling_factor);
+
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&PrivetURLFetcher::Try, weak_factory_.GetWeakPtr()),
+      base::TimeDelta::FromSeconds(timeout_seconds_randomized));
+}
+
+bool PrivetURLFetcher::PrivetErrorTransient(const std::string& error) {
+  return (error == kPrivetErrorDeviceBusy) ||
+         (error == kPrivetErrorPendingUserAction);
+}
+
 PrivetURLFetcherFactory::PrivetURLFetcherFactory(
     net::URLRequestContextGetter* request_context)
     : request_context_(request_context) {
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.h b/chrome/browser/local_discovery/privet_url_fetcher.h
index a99ea48..5f8ebdd 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.h
+++ b/chrome/browser/local_discovery/privet_url_fetcher.h
@@ -7,10 +7,12 @@
 
 #include <string>
 
+#include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
 
 namespace local_discovery {
 
@@ -24,7 +26,8 @@
   enum ErrorType {
     JSON_PARSE_ERROR,
     URL_FETCH_ERROR,
-    RESPONSE_CODE_ERROR
+    RESPONSE_CODE_ERROR,
+    RETRY_ERROR
   };
 
   class Delegate {
@@ -47,15 +50,31 @@
 
   void Start();
 
+  void SetUploadData(const std::string& upload_content_type,
+                     const std::string& upload_data);
+
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   const GURL& url() const { return url_fetcher_->GetOriginalURL(); }
   int response_code() const { return url_fetcher_->GetResponseCode(); }
 
  private:
-  scoped_ptr<net::URLFetcher> url_fetcher_;
+  void Try();
+  void ScheduleRetry(int timeout_seconds);
+  bool PrivetErrorTransient(const std::string& error);
+
+  std::string privet_access_token_;
+  GURL url_;
+  net::URLFetcher::RequestType request_type_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_;
   Delegate* delegate_;
 
+  int tries_;
+  std::string upload_data_;
+  std::string upload_content_type_;
+  scoped_ptr<net::URLFetcher> url_fetcher_;
+
+  base::WeakPtrFactory<PrivetURLFetcher> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(PrivetURLFetcher);
 };
 
@@ -66,7 +85,8 @@
   ~PrivetURLFetcherFactory();
 
   scoped_ptr<PrivetURLFetcher> CreateURLFetcher(
-      const GURL& url, net::URLFetcher::RequestType request_type,
+      const GURL& url,
+      net::URLFetcher::RequestType request_type,
       PrivetURLFetcher::Delegate* delegate) const;
 
   void set_token(const std::string& token) { token_ = token; }
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.cc b/chrome/browser/local_discovery/service_discovery_device_lister.cc
index a6c025a..0d90645 100644
--- a/chrome/browser/local_discovery/service_discovery_device_lister.cc
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.cc
@@ -8,16 +8,24 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/message_loop/message_loop.h"
 
 namespace local_discovery {
 
+namespace {
+#if defined(OS_MACOSX)
+const int kMacServiceResolvingIntervalSecs = 60;
+#endif
+}  // namespace
+
 ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister(
     Delegate* delegate,
     ServiceDiscoveryClient* service_discovery_client,
     const std::string& service_type)
     : delegate_(delegate),
       service_discovery_client_(service_discovery_client),
-      service_type_(service_type) {
+      service_type_(service_type),
+      weak_factory_(this) {
 }
 
 ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() {
@@ -54,8 +62,9 @@
           service_discovery_client_->CreateServiceResolver(
           service_name, base::Bind(
               &ServiceDiscoveryDeviceLister::OnResolveComplete,
-              base::Unretained(this),
-              added));
+              weak_factory_.GetWeakPtr(),
+              added,
+              service_name));
 
       insert_result.first->second.reset(resolver.release());
       insert_result.first->second->StartResolving();
@@ -65,19 +74,31 @@
   }
 }
 
+// TODO(noamsml): Update ServiceDiscoveryClient interface to match this.
 void ServiceDiscoveryDeviceLister::OnResolveComplete(
     bool added,
+    std::string service_name,
     ServiceResolver::RequestStatus status,
     const ServiceDescription& service_description) {
-  if (status != ServiceResolver::STATUS_SUCCESS) {
-    resolvers_.erase(service_description.service_name);
+  if (status == ServiceResolver::STATUS_SUCCESS) {
+    delegate_->OnDeviceChanged(added, service_description);
 
+#if defined(OS_MACOSX)
+    // On Mac, the Bonjour service does not seem to ever evict a service if a
+    // device is unplugged, so we need to continuously try to resolve the
+    // service to detect non-graceful shutdowns.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
+                   weak_factory_.GetWeakPtr(),
+                   ServiceWatcher::UPDATE_CHANGED,
+                   service_description.service_name),
+        base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs));
+#endif
+  } else {
     // TODO(noamsml): Add retry logic.
-    return;
   }
-
-  delegate_->OnDeviceChanged(added, service_description);
-  resolvers_.erase(service_description.service_name);
+  resolvers_.erase(service_name);
 }
 
 void ServiceDiscoveryDeviceLister::CreateServiceWatcher() {
@@ -85,7 +106,7 @@
       service_discovery_client_->CreateServiceWatcher(
           service_type_,
           base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
-                     base::Unretained(this)));
+                     weak_factory_.GetWeakPtr()));
   service_watcher_->Start();
 }
 
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.h b/chrome/browser/local_discovery/service_discovery_device_lister.h
index 2baab45..c767b6e 100644
--- a/chrome/browser/local_discovery/service_discovery_device_lister.h
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.h
@@ -10,6 +10,7 @@
 
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/common/local_discovery/service_discovery_client.h"
 
 namespace local_discovery {
@@ -44,6 +45,7 @@
 
   void OnResolveComplete(
       bool added,
+      std::string service_name,
       ServiceResolver::RequestStatus status,
       const ServiceDescription& description);
 
@@ -56,6 +58,10 @@
 
   scoped_ptr<ServiceWatcher> service_watcher_;
   ServiceResolverMap resolvers_;
+
+  base::WeakPtrFactory<ServiceDiscoveryDeviceLister> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryDeviceLister);
 };
 
 }  // namespace local_discovery
diff --git a/chrome/browser/mac/dock.h b/chrome/browser/mac/dock.h
index 34822ee..2e2bdd1 100644
--- a/chrome/browser/mac/dock.h
+++ b/chrome/browser/mac/dock.h
@@ -13,6 +13,12 @@
 
 namespace dock {
 
+enum AddIconStatus {
+  IconAddFailure,
+  IconAddSuccess,
+  IconAlreadyPresent
+};
+
 // Adds an icon to the Dock pointing to |installed_path| if one is not already
 // present. |dmg_app_path| is the path to the install source. Its tile will be
 // removed if present. If any changes are made to the Dock's configuration,
@@ -49,7 +55,7 @@
 // additional properties on the dock tile added to the Dock's plist, this
 // is not done. Upon relaunch, Dock.app will determine the correct values for
 // the properties it requires and add them to its configuration.
-void AddIcon(NSString* installed_path, NSString* dmg_app_path);
+AddIconStatus AddIcon(NSString* installed_path, NSString* dmg_app_path);
 
 }  // namespace dock
 
diff --git a/chrome/browser/mac/dock.mm b/chrome/browser/mac/dock.mm
index e55f4c8..70af224 100644
--- a/chrome/browser/mac/dock.mm
+++ b/chrome/browser/mac/dock.mm
@@ -98,8 +98,11 @@
 
     NSDictionary* file_data = [tile_data objectForKey:kDockFileDataKey];
     if (![file_data isKindOfClass:[NSDictionary class]]) {
-      LOG(ERROR) << "file_data not NSDictionary";
-      return nil;
+      // Some apps (e.g. Dashboard) have no file data, but instead have a
+      // special value for the tile-type key. For these, add an empty string to
+      // align indexes with the source array.
+      [app_paths addObject:@""];
+      continue;
     }
 
     NSURL* url = NSURLCreateFromDictionary(file_data);
@@ -140,7 +143,7 @@
 
 }  // namespace
 
-void AddIcon(NSString* installed_path, NSString* dmg_app_path) {
+AddIconStatus AddIcon(NSString* installed_path, NSString* dmg_app_path) {
   // ApplicationServices.framework/Frameworks/HIServices.framework contains an
   // undocumented function, CoreDockAddFileToDock, that is able to add items
   // to the Dock "live" without requiring a Dock restart. Under the hood, it
@@ -164,7 +167,7 @@
       [user_defaults persistentDomainForName:kDockDomain];
   if (![dock_plist_const isKindOfClass:[NSDictionary class]]) {
     LOG(ERROR) << "dock_plist_const not NSDictionary";
-    return;
+    return IconAddFailure;
   }
   NSMutableDictionary* dock_plist =
       [NSMutableDictionary dictionaryWithDictionary:dock_plist_const];
@@ -174,14 +177,14 @@
       [dock_plist objectForKey:kDockPersistentAppsKey];
   if (![persistent_apps_const isKindOfClass:[NSArray class]]) {
     LOG(ERROR) << "persistent_apps_const not NSArray";
-    return;
+    return IconAddFailure;
   }
   NSMutableArray* persistent_apps =
       [NSMutableArray arrayWithArray:persistent_apps_const];
 
   NSMutableArray* persistent_app_paths = PersistentAppPaths(persistent_apps);
   if (!persistent_app_paths) {
-    return;
+    return IconAddFailure;
   }
 
   NSUInteger already_installed_app_index = NSNotFound;
@@ -300,7 +303,7 @@
     NSDictionary* url_dict = NSURLCopyDictionary(url);
     if (!url_dict) {
       LOG(ERROR) << "couldn't create url_dict";
-      return;
+      return IconAddFailure;
     }
 
     NSDictionary* new_tile_data =
@@ -322,7 +325,7 @@
   if (!made_change) {
     // If no changes were made, there's no point in rewriting the Dock's
     // plist or restarting the Dock.
-    return;
+    return IconAlreadyPresent;
   }
 
   // Rewrite the plist.
@@ -330,6 +333,7 @@
   [user_defaults setPersistentDomain:dock_plist forName:kDockDomain];
 
   Restart();
+  return IconAddSuccess;
 }
 
 }  // namespace dock
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility.cc b/chrome/browser/managed_mode/managed_user_registration_utility.cc
index e2b75b5..c32311c 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_utility.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/signin/profile_oauth2_token_service.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/sync/glue/device_info.h"
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc b/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
index eb2ff61..0ef19b7 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -11,7 +12,6 @@
 #include "chrome/browser/managed_mode/managed_user_registration_utility.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/managed_mode/managed_user_service.cc b/chrome/browser/managed_mode/managed_user_service.cc
index fe204fa..bbfb9bd 100644
--- a/chrome/browser/managed_mode/managed_user_service.cc
+++ b/chrome/browser/managed_mode/managed_user_service.cc
@@ -8,6 +8,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -23,7 +24,6 @@
 #include "chrome/browser/managed_mode/managed_user_settings_service_factory.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_base.h"
@@ -623,7 +623,7 @@
                  weak_ptr_factory_.GetWeakPtr(), callback, custodian_profile));
 
   // Fetch the custodian's profile information, to store the name.
-  // TODO(pamg): If --gaia-profile-info (keyword: switches::kGaiaProfileInfo)
+  // TODO(pamg): If --google-profile-info (flag: switches::kGoogleProfileInfo)
   // is ever enabled, take the name from the ProfileInfoCache instead.
   CustodianProfileDownloaderService* profile_downloader_service =
       CustodianProfileDownloaderServiceFactory::GetForProfile(
diff --git a/chrome/browser/managed_mode/managed_user_service_unittest.cc b/chrome/browser/managed_mode/managed_user_service_unittest.cc
index 97183eb..804978e 100644
--- a/chrome/browser/managed_mode/managed_user_service_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_service_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service_unittest.h"
@@ -12,12 +13,12 @@
 #include "chrome/browser/managed_mode/custodian_profile_downloader_service_factory.h"
 #include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -153,7 +154,8 @@
 class ManagedUserServiceExtensionTestBase : public ExtensionServiceTestBase {
  public:
   explicit ManagedUserServiceExtensionTestBase(bool is_managed)
-      : is_managed_(is_managed) {}
+      : is_managed_(is_managed),
+        channel_(chrome::VersionInfo::CHANNEL_DEV) {}
   virtual ~ManagedUserServiceExtensionTestBase() {}
 
   virtual void SetUp() OVERRIDE {
@@ -194,6 +196,7 @@
   }
 
   bool is_managed_;
+  extensions::ScopedCurrentChannel channel_;
 };
 
 class ManagedUserServiceExtensionTestUnmanaged
diff --git a/chrome/browser/managed_mode/managed_user_sync_service.cc b/chrome/browser/managed_mode/managed_user_sync_service.cc
index 9b673a3..c14e62b 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service.cc
+++ b/chrome/browser/managed_mode/managed_user_sync_service.cc
@@ -6,10 +6,10 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
diff --git a/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc b/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
index fd0e156..dce07de 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
@@ -5,11 +5,11 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/media/DEPS b/chrome/browser/media/DEPS
index 2b87894..3417e64 100644
--- a/chrome/browser/media/DEPS
+++ b/chrome/browser/media/DEPS
@@ -1,5 +1,7 @@
 include_rules = [
+  "+media/audio",
   "+media/base",
+  "+third_party/libyuv",
   "+third_party/webrtc",
   "+third_party/zlib"
 ]
diff --git a/chrome/browser/media/chrome_midi_permission_context.cc b/chrome/browser/media/chrome_midi_permission_context.cc
index c233400..ae55f93 100644
--- a/chrome/browser/media/chrome_midi_permission_context.cc
+++ b/chrome/browser/media/chrome_midi_permission_context.cc
@@ -34,6 +34,7 @@
 void ChromeMIDIPermissionContext::RequestMIDISysExPermission(
     int render_process_id,
     int render_view_id,
+    int bridge_id,
     const GURL& requesting_frame,
     const content::BrowserContext::MIDISysExPermissionCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -49,7 +50,7 @@
   if (!web_contents)
     return;
 
-  const PermissionRequestID id(render_process_id, render_view_id, 0);
+  const PermissionRequestID id(render_process_id, render_view_id, bridge_id);
 
   GURL embedder = web_contents->GetURL();
   if (!requesting_frame.is_valid() || !embedder.is_valid()) {
@@ -63,6 +64,15 @@
   DecidePermission(id, requesting_frame, embedder, callback);
 }
 
+void ChromeMIDIPermissionContext::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+  CancelPendingInfoBarRequest(
+      PermissionRequestID(render_process_id, render_view_id, bridge_id));
+}
+
 void ChromeMIDIPermissionContext::DecidePermission(
     const PermissionRequestID& id,
     const GURL& requesting_frame,
@@ -129,3 +139,11 @@
   }
   return permission_queue_controller_.get();
 }
+
+void ChromeMIDIPermissionContext::CancelPendingInfoBarRequest(
+    const PermissionRequestID& id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (shutting_down_)
+    return;
+  GetQueueController()->CancelInfoBarRequest(id);
+}
diff --git a/chrome/browser/media/chrome_midi_permission_context.h b/chrome/browser/media/chrome_midi_permission_context.h
index 7f2ff32..cae2e76 100644
--- a/chrome/browser/media/chrome_midi_permission_context.h
+++ b/chrome/browser/media/chrome_midi_permission_context.h
@@ -27,9 +27,16 @@
   void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const content::BrowserContext::MIDISysExPermissionCallback& callback);
 
+  // Cancel a pending MIDI permission request.
+  void CancelMIDISysExPermissionRequest(int render_process_id,
+                                        int render_view_id,
+                                        int bridge_id,
+                                        const GURL& requesting_frame);
+
  private:
   // Decide whether the permission should be granted.
   // Calls PermissionDecided if permission can be decided non-interactively,
@@ -59,6 +66,9 @@
   // Return an instance of the infobar queue controller, creating it if needed.
   PermissionQueueController* GetQueueController();
 
+  // Removes any pending InfoBar request.
+  void CancelPendingInfoBarRequest(const PermissionRequestID& id);
+
   Profile* const profile_;
   bool shutting_down_;
   scoped_ptr<PermissionQueueController> permission_queue_controller_;
diff --git a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
index d0ba4c8..a94adc9 100644
--- a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
@@ -119,7 +119,7 @@
   base::ProcessHandle dev_appserver_;
 };
 
-#if defined (OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN)
 #define MAYBE_MANUAL_WorksOnApprtc DISABLED_MANUAL_WorksOnApprtc
 #else
 #define MAYBE_MANUAL_WorksOnApprtc MANUAL_WorksOnApprtc
@@ -135,6 +135,9 @@
 
   chrome::AddBlankTabAt(browser(), -1, true);
   content::WebContents* left_tab = OpenPageAndAcceptUserMedia(room_url);
+  // TODO(phoglund): Remove when this bug gets fixed:
+  // http://code.google.com/p/webrtc/issues/detail?id=1742
+  SleepInJavascript(left_tab, 5000);
   chrome::AddBlankTabAt(browser(), -1, true);
   content::WebContents* right_tab = OpenPageAndAcceptUserMedia(room_url);
 
diff --git a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
index d7a83a5..454beb0 100644
--- a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
@@ -418,7 +418,7 @@
   ConnectToPeerConnectionServer("peer 2", right_tab);
 
   EXPECT_EQ("ok-peerconnection-created",
-            ExecuteJavascript("preparePeerConnection(false, true)", left_tab));
+            ExecuteJavascript("preparePeerConnection()", left_tab));
 
   AddAudioFile(kReferenceFileRelativeUrl, left_tab);
 
diff --git a/chrome/browser/media/chrome_webrtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_browsertest.cc
index 07dd426..3aae51b 100644
--- a/chrome/browser/media/chrome_webrtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_browsertest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/webrtc_browsertest_base.h"
 #include "chrome/browser/media/webrtc_browsertest_common.h"
-#include "chrome/browser/media/webrtc_log_uploader.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -25,7 +24,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/ui/ui_test.h"
-#include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/test/browser_test_utils.h"
@@ -35,8 +33,6 @@
 static const char kMainWebrtcTestHtmlPage[] =
     "/webrtc/webrtc_jsep01_test.html";
 
-static const char kTestLoggingSessionId[] = "0123456789abcdef";
-
 // Top-level integration test for WebRTC. Requires a real webcam and microphone
 // on the running system. This test is not meant to run in the main browser
 // test suite since normal tester machines do not have webcams.
@@ -66,17 +62,12 @@
   }
 
   void EstablishCall(content::WebContents* from_tab,
-                     content::WebContents* to_tab,
-                     bool enable_logging = false) {
+                     content::WebContents* to_tab) {
     ConnectToPeerConnectionServer("peer 1", from_tab);
     ConnectToPeerConnectionServer("peer 2", to_tab);
 
-    std::string javascript = enable_logging ?
-        base::StringPrintf("preparePeerConnection(\"%s\", true)",
-            kTestLoggingSessionId) :
-        "preparePeerConnection(false, true)";
     EXPECT_EQ("ok-peerconnection-created",
-              ExecuteJavascript(javascript, from_tab));
+              ExecuteJavascript("preparePeerConnection()", from_tab));
     EXPECT_EQ("ok-added",
               ExecuteJavascript("addLocalStream()", from_tab));
     EXPECT_EQ("ok-negotiating",
@@ -363,190 +354,3 @@
 
   ASSERT_TRUE(peerconnection_server_.Stop());
 }
-
-// See comment in test where this class is used for purpose.
-class BrowserMessageFilter : public content::BrowserMessageFilter {
- public:
-  explicit BrowserMessageFilter(
-      const base::Closure& on_channel_closing)
-      : on_channel_closing_(on_channel_closing) {}
-
-  virtual void OnChannelClosing() OVERRIDE {
-    // Posting on the file thread ensures that the callback is run after
-    // WebRtcLogUploader::UploadLog has finished. See also comment in
-    // MANUAL_RunsAudioVideoWebRTCCallInTwoTabsWithLogging test.
-    content::BrowserThread::PostTask(content::BrowserThread::FILE,
-        FROM_HERE, on_channel_closing_);
-  }
-
-  virtual bool OnMessageReceived(const IPC::Message& message,
-                                 bool* message_was_ok) OVERRIDE {
-    return false;
-  }
-
-private:
-  virtual ~BrowserMessageFilter() {}
-
-  base::Closure on_channel_closing_;
-};
-
-// Tests WebRTC diagnostic logging. Sets up the browser to save the multipart
-// contents to a buffer instead of uploading it, then verifies it after a call.
-// Example of multipart contents:
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="prod"
-//
-// Chrome_Linux
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="ver"
-//
-// 30.0.1554.0
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="guid"
-//
-// 0
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="type"
-//
-// webrtc_log
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="app_session_id"
-//
-// 0123456789abcdef
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="url"
-//
-// http://127.0.0.1:43213/webrtc/webrtc_jsep01_test.html
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
-// Content-Disposition: form-data; name="webrtc_log"; filename="webrtc_log.gz"
-// Content-Type: application/gzip
-//
-// <compressed data (zip)>
-// ------**--yradnuoBgoLtrapitluMklaTelgooG--**------
-//
-// TODO(grunell): Test has been disabled due to the logging API being moved to
-// an extension API. Move test to extension tests.
-IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
-                       DISABLED_RunsAudioVideoWebRTCCallInTwoTabsWithLogging) {
-  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
-  ASSERT_TRUE(peerconnection_server_.Start());
-
-  // Add command line switch that forces allowing log uploads.
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(switches::kEnableMetricsReportingForTesting);
-
-  // Tell the uploader to save the multipart to a buffer instead of uploading.
-  std::string multipart;
-  g_browser_process->webrtc_log_uploader()->
-      OverrideUploadWithBufferForTesting(&multipart);
-
-  content::WebContents* left_tab = OpenTestPageAndGetUserMediaInNewTab();
-  content::WebContents* right_tab = OpenTestPageAndGetUserMediaInNewTab();
-
-  EstablishCall(left_tab, right_tab, true);
-
-  StartDetectingVideo(left_tab, "remote-view");
-  StartDetectingVideo(right_tab, "remote-view");
-
-  WaitForVideoToPlay(left_tab);
-  WaitForVideoToPlay(right_tab);
-
-  HangUp(left_tab);
-  WaitUntilHangupVerified(left_tab);
-  WaitUntilHangupVerified(right_tab);
-
-  AssertNoAsynchronousErrors(left_tab);
-  AssertNoAsynchronousErrors(right_tab);
-
-  // Uploading (or storing to our buffer in our test case) is triggered when
-  // the tab is closed. We must ensure that WebRtcLogUploader::UploadLog, which
-  // runs on the FILE thread, has finished after closing the tab before
-  // continuing.
-  // 1. Add a filter which just acts as a listener. It's added after
-  //    WebRtcLoggingHandlerHost, which is the filter that posts a task for
-  //    WebRtcLogUploader::UploadLog. So it's guarantueed to be removed after
-  //    WebRtcLoggingHandlerHost.
-  // 2. When the filter goes away post a task on the file thread to signal the
-  //    event.
-  base::WaitableEvent ipc_channel_closed(false, false);
-  left_tab->GetRenderProcessHost()->AddFilter(
-      new BrowserMessageFilter(base::Bind(
-          &base::WaitableEvent::Signal,
-          base::Unretained(&ipc_channel_closed))));
-  chrome::CloseWebContents(browser(), left_tab, false);
-  ASSERT_TRUE(ipc_channel_closed.TimedWait(TestTimeouts::action_timeout()));
-
-  const char boundary[] = "------**--yradnuoBgoLtrapitluMklaTelgooG--**----";
-
-  // Remove the compressed data, it may contain "\r\n". Just verify that its
-  // size is > 0.
-  const char zip_content_type[] = "Content-Type: application/gzip";
-  size_t zip_pos = multipart.find(&zip_content_type[0]);
-  ASSERT_NE(std::string::npos, zip_pos);
-  // Move pos to where the zip begins. - 1 to remove '\0', + 4 for two "\r\n".
-  zip_pos += sizeof(zip_content_type) + 3;
-  size_t zip_length = multipart.find(boundary, zip_pos);
-  ASSERT_NE(std::string::npos, zip_length);
-  // Calculate length, adjust for a "\r\n".
-  zip_length -= zip_pos + 2;
-  ASSERT_GT(zip_length, 0u);
-  multipart.erase(zip_pos, zip_length);
-
-  // Check the multipart contents.
-  std::vector<std::string> multipart_lines;
-  base::SplitStringUsingSubstr(multipart, "\r\n", &multipart_lines);
-  ASSERT_EQ(31, static_cast<int>(multipart_lines.size()));
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[0].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"prod\"",
-               multipart_lines[1].c_str());
-  EXPECT_TRUE(multipart_lines[2].empty());
-  EXPECT_NE(std::string::npos, multipart_lines[3].find("Chrome"));
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[4].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"ver\"",
-               multipart_lines[5].c_str());
-  EXPECT_TRUE(multipart_lines[6].empty());
-  // Just check that the version contains a dot.
-  EXPECT_NE(std::string::npos, multipart_lines[7].find('.'));
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[8].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"guid\"",
-               multipart_lines[9].c_str());
-  EXPECT_TRUE(multipart_lines[10].empty());
-  EXPECT_STREQ("0", multipart_lines[11].c_str());
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[12].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"type\"",
-               multipart_lines[13].c_str());
-  EXPECT_TRUE(multipart_lines[14].empty());
-  EXPECT_STREQ("webrtc_log", multipart_lines[15].c_str());
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[16].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"app_session_id\"",
-               multipart_lines[17].c_str());
-  EXPECT_TRUE(multipart_lines[18].empty());
-  EXPECT_STREQ(kTestLoggingSessionId, multipart_lines[19].c_str());
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[20].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"url\"",
-               multipart_lines[21].c_str());
-  EXPECT_TRUE(multipart_lines[22].empty());
-  EXPECT_NE(std::string::npos,
-            multipart_lines[23].find(&kMainWebrtcTestHtmlPage[0]));
-
-  EXPECT_STREQ(&boundary[0], multipart_lines[24].c_str());
-  EXPECT_STREQ("Content-Disposition: form-data; name=\"webrtc_log\";"
-               " filename=\"webrtc_log.gz\"",
-               multipart_lines[25].c_str());
-  EXPECT_STREQ("Content-Type: application/gzip",
-               multipart_lines[26].c_str());
-  EXPECT_TRUE(multipart_lines[27].empty());
-  EXPECT_TRUE(multipart_lines[28].empty());  // The removed zip part.
-  std::string final_delimiter = boundary;
-  final_delimiter += "--";
-  EXPECT_STREQ(final_delimiter.c_str(), multipart_lines[29].c_str());
-  EXPECT_TRUE(multipart_lines[30].empty());
-
-  ASSERT_TRUE(peerconnection_server_.Stop());
-}
diff --git a/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc b/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc
index a6aa242..3335c0c 100644
--- a/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc
@@ -138,7 +138,7 @@
   GetUserMediaWithSpecificConstraintsAndAccept(left_tab,
                                                kAudioOnlyCallConstraints);
   EXPECT_EQ("ok-peerconnection-created",
-            ExecuteJavascript("preparePeerConnection(false, true)", left_tab));
+            ExecuteJavascript("preparePeerConnection()", left_tab));
 
   AddAudioFile(kReferenceFileRelativeUrl, left_tab);
   MixLocalStreamWithPreviouslyLoadedAudioFile(left_tab);
diff --git a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
index c4a4d1b..22840d8 100644
--- a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
@@ -180,8 +180,7 @@
   void EstablishCall(content::WebContents* from_tab,
                      content::WebContents* to_tab) {
     EXPECT_EQ("ok-peerconnection-created",
-              ExecuteJavascript("preparePeerConnection(false, true)",
-                                from_tab));
+              ExecuteJavascript("preparePeerConnection()", from_tab));
     EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", from_tab));
     EXPECT_EQ("ok-negotiating", ExecuteJavascript("negotiateCall()", from_tab));
 
diff --git a/chrome/browser/media/desktop_media_picker_model.cc b/chrome/browser/media/desktop_media_picker_model.cc
index bcab694..4ce788a 100644
--- a/chrome/browser/media/desktop_media_picker_model.cc
+++ b/chrome/browser/media/desktop_media_picker_model.cc
@@ -44,7 +44,8 @@
 
   SkBitmap result;
   result.setConfig(SkBitmap::kARGB_8888_Config,
-                   scaled_rect.width(), scaled_rect.height());
+                   scaled_rect.width(), scaled_rect.height(), 0,
+                   kOpaque_SkAlphaType);
   result.allocPixels();
   result.lockPixels();
 
@@ -68,7 +69,6 @@
   }
 
   result.unlockPixels();
-  result.setIsOpaque(true);
 
   return gfx::ImageSkia::CreateFrom1xBitmap(result);
 }
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 9c24849..1998c93 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -17,10 +17,6 @@
 
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
 
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(OS_LINUX)
-#include <gnu/libc-version.h>
-#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(OS_LINUX)
-
 #if defined(ENABLE_PEPPER_CDMS)
 // Platform-specific filename relative to the chrome executable.
 const char kClearKeyCdmAdapterFileName[] =
@@ -116,16 +112,6 @@
       // - webkitGenerateKeyRequest() does not fail.
       // - webkitkeymessage is fired.
       // - webkitAddKey() triggers a WebKitKeyError since no real key is added.
-      // TODO(shadi): Remove after bots upgrade to precise.
-      // Don't run on lucid bots since the CDM is not compatible (glibc < 2.14)
-#if defined(OS_LINUX)
-      if (strcmp(gnu_get_libc_version(), "2.11.1") == 0) {
-        LOG(INFO) << "Skipping test; not supported on glibc version: "
-            << gnu_get_libc_version();
-        return;
-      }
-#endif  // defined(OS_LINUX)
-
       RunEncryptedMediaTest("encrypted_media_player.html", media_file,
                             media_type, key_system, src_type, kEmeKeyError);
 
@@ -156,12 +142,6 @@
     command_line->AppendSwitch(
         switches::kDisableGestureRequirementForMediaPlayback);
 #endif  // defined(OS_ANDROID)
-
-#if defined(OS_CHROMEOS)
-    // Disable GPU video decoder on ChromeOS since these tests run on
-    // linux_chromeos which does not support GPU video decoder.
-    command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
-#endif  // defined(OS_CHROMEOS)
   }
 
   void SetUpCommandLineForKeySystem(const char* key_system,
diff --git a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
index 1006a2f..9571aa7 100644
--- a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
@@ -21,11 +21,6 @@
 
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
 
-#if defined(WIDEVINE_CDM_AVAILABLE) && \
-    defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#include <gnu/libc-version.h>
-#endif
-
 #if defined(USE_PROPRIETARY_CODECS)
 #define EXPECT_PROPRIETARY EXPECT_TRUE
 #else
@@ -42,15 +37,12 @@
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
 // Expectations for Widevine.
-#if defined(WIDEVINE_CDM_AVAILABLE) && \
-    !defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)  // See http://crbug.com/237627
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-// TODO(ddorwin): Remove after bots switch to Precise.
-#define EXPECT_WV(a) \
-    EXPECT_EQ((std::string(gnu_get_libc_version()) != "2.11.1"), (a))
-#else
+// Note: Widevine is not available on platforms using components because
+// RegisterPepperCdm() cannot set the codecs.
+// TODO(ddorwin): Enable these tests after we have the ability to use the CUS
+// in these tests. See http://crbug.com/311724.
+#if defined(WIDEVINE_CDM_AVAILABLE) && !defined(WIDEVINE_CDM_IS_COMPONENT)
 #define EXPECT_WV EXPECT_TRUE
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
 
 #if defined(WIDEVINE_CDM_AVC1_SUPPORT_AVAILABLE)
 #define EXPECT_WVAVC1 EXPECT_TRUE
@@ -70,14 +62,13 @@
 #define EXPECT_WVAAC EXPECT_FALSE
 #endif
 
-#else  // defined(WIDEVINE_CDM_AVAILABLE) &&
-       // !defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)
+#else  // defined(WIDEVINE_CDM_AVAILABLE) && !defined(WIDEVINE_CDM_IS_COMPONENT)
 #define EXPECT_WV EXPECT_FALSE
 #define EXPECT_WVAVC1 EXPECT_FALSE
 #define EXPECT_WVAVC1AAC EXPECT_FALSE
 #define EXPECT_WVAAC EXPECT_FALSE
 #endif  // defined(WIDEVINE_CDM_AVAILABLE) &&
-        // !defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)
+        // !defined(WIDEVINE_CDM_IS_COMPONENT)
 
 namespace chrome {
 
@@ -94,7 +85,8 @@
 
 class EncryptedMediaIsTypeSupportedTest : public InProcessBrowserTest {
  protected:
-  EncryptedMediaIsTypeSupportedTest() : is_test_page_loaded_(false) {
+  EncryptedMediaIsTypeSupportedTest()
+      : is_test_page_loaded_(false), is_pepper_cdm_registered_(false) {
     vp8_codec_.push_back("vp8");
 
     vp80_codec_.push_back("vp8.0");
@@ -159,6 +151,10 @@
                          const std::string& adapter_name,
                          const std::string& pepper_type_for_key_system,
                          bool expect_adapter_exists = true) {
+    DCHECK(!is_pepper_cdm_registered_)
+        << "RegisterPepperCdm() can only be called once.";
+    is_pepper_cdm_registered_ = true;
+
     // Append the switch to register the appropriate adapter.
     base::FilePath plugin_dir;
     EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
@@ -258,6 +254,7 @@
   CodecVector unknown_codec_;
   CodecVector mixed_codecs_;
   bool is_test_page_loaded_;
+  bool is_pepper_cdm_registered_;
 };
 
 // For ExternalClearKey tests, ensure that the ClearKey adapter is loaded.
@@ -285,7 +282,8 @@
 // For Widevine tests, ensure that the Widevine adapter is loaded.
 class EncryptedMediaIsTypeSupportedWidevineTest
     : public EncryptedMediaIsTypeSupportedTest {
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \
+    defined(WIDEVINE_CDM_IS_COMPONENT)
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     // File name of the adapter on different platforms.
@@ -301,12 +299,13 @@
     const std::string pepper_name("application/x-ppapi-widevine-cdm");
     RegisterPepperCdm(command_line, adapter_file_name, pepper_name);
   }
-#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
+#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) &&
+        // defined(WIDEVINE_CDM_IS_COMPONENT)
 };
 
 #if defined(ENABLE_PEPPER_CDMS)
-// Registers all possibly supported Pepper CDMs with the wrong path (filename).
-class EncryptedMediaIsTypeSupportedPepperCDMRegisteredWithWrongPathTest
+// Registers ClearKey CDM with the wrong path (filename).
+class EncryptedMediaIsTypeSupportedClearKeyCDMRegisteredWithWrongPathTest
     : public EncryptedMediaIsTypeSupportedTest {
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -314,6 +313,14 @@
                      "clearkeycdmadapterwrongname.dll",
                      "application/x-ppapi-clearkey-cdm",
                      false);
+  }
+};
+
+// Registers Widevine CDM with the wrong path (filename).
+class EncryptedMediaIsTypeSupportedWidevineCDMRegisteredWithWrongPathTest
+    : public EncryptedMediaIsTypeSupportedTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    RegisterPepperCdm(command_line,
                      "widevinecdmadapterwrongname.dll",
                      "application/x-ppapi-widevine-cdm",
@@ -322,7 +329,6 @@
 };
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
-
 IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedTest, ClearKey_Basic) {
   EXPECT_TRUE(IsConcreteSupportedKeySystem(kPrefixedClearKey));
   EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
@@ -679,7 +685,7 @@
 
 IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedWidevineTest,
                        Widevine_Basic) {
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
   EXPECT_TRUE(IsConcreteSupportedKeySystem(kWidevineAlpha));
 #else
   EXPECT_WV(IsConcreteSupportedKeySystem(kWidevineAlpha));
@@ -925,20 +931,12 @@
 // check for the CDMs in chrome_key_systems.cc should fail, and they should not
 // be registered with KeySystems.
 IN_PROC_BROWSER_TEST_F(
-    EncryptedMediaIsTypeSupportedPepperCDMRegisteredWithWrongPathTest,
+    EncryptedMediaIsTypeSupportedClearKeyCDMRegisteredWithWrongPathTest,
     PepperCDMsRegisteredButAdapterNotPresent) {
   EXPECT_FALSE(IsConcreteSupportedKeySystem(kExternalClearKey));
   EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
       "video/webm", no_codecs(), kExternalClearKey));
 
-  // This will fail in all builds unless widevine is available but not a
-  // component, in which case it is registered internally
-#if !defined(WIDEVINE_CDM_AVAILABLE) || defined(WIDEVINE_CDM_IS_COMPONENT)
-  EXPECT_FALSE(IsConcreteSupportedKeySystem(kWidevineAlpha));
-  EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
-      "video/webm", no_codecs(), kWidevineAlpha));
-#endif
-
   // Clear Key should still be registered.
   EXPECT_TRUE(IsConcreteSupportedKeySystem(kPrefixedClearKey));
   EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
@@ -949,6 +947,19 @@
   EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
       "video/webm", no_codecs(), kUnprefixedClearKey));
 }
+
+// This will fail in all builds unless Widevine is available but not a
+// component, in which case it is registered internally.
+// TODO(xhwang): Define EXPECT_WV and run this test in all cases.
+#if !defined(WIDEVINE_CDM_AVAILABLE) || defined(WIDEVINE_CDM_IS_COMPONENT)
+IN_PROC_BROWSER_TEST_F(
+    EncryptedMediaIsTypeSupportedWidevineCDMRegisteredWithWrongPathTest,
+    PepperCDMsRegisteredButAdapterNotPresent) {
+  EXPECT_FALSE(IsConcreteSupportedKeySystem(kWidevineAlpha));
+  EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
+      "video/webm", no_codecs(), kWidevineAlpha));
+}
+#endif  // !defined(WIDEVINE_CDM_AVAILABLE) || defined(WIDEVINE_CDM_IS_COMPONENT)
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
 }  // namespace chrome
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 12b56b7..9c19064 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/media/desktop_streams_registry.h"
 #include "chrome/browser/media/media_stream_capture_indicator.h"
 #include "chrome/browser/media/media_stream_infobar_delegate.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/screen_capture_notification_ui.h"
 #include "chrome/browser/ui/simple_message_box.h"
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc
index ef4860e..e21f712 100644
--- a/chrome/browser/media/media_stream_devices_controller.cc
+++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -6,13 +6,13 @@
 
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/content_settings/content_settings_provider.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/media_stream_capture_indicator.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/media/webrtc_log_uploader.cc b/chrome/browser/media/webrtc_log_uploader.cc
index 15b2ba1..ecc91e0 100644
--- a/chrome/browser/media/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc_log_uploader.cc
@@ -39,6 +39,8 @@
 const char kMultipartBoundary[] =
     "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
 
+const int kHttpResponseOk = 200;
+
 }  // namespace
 
 WebRtcLogUploader::WebRtcLogUploader()
@@ -52,27 +54,14 @@
   DCHECK(upload_done_data_.find(source) != upload_done_data_.end());
   int response_code = source->GetResponseCode();
   std::string report_id;
-  if (response_code == 200 && source->GetResponseAsString(&report_id)) {
+  if (response_code == kHttpResponseOk &&
+      source->GetResponseAsString(&report_id)) {
     AddUploadedLogInfoToUploadListFile(
         WebRtcLogUploadList::GetFilePathForProfile(
             upload_done_data_[source].profile),
         report_id);
   }
-  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::UploadLogDone,
-                 upload_done_data_[source].host));
-  if (!upload_done_data_[source].callback.is_null()) {
-    bool success = response_code == 200;
-    std::string error_message;
-    if (!success) {
-      error_message = "Uploading failed, response code: " +
-                      base::IntToString(response_code);
-    }
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::Bind(upload_done_data_[source].callback, success, report_id,
-                   error_message));
-  }
+  NotifyUploadDone(response_code, report_id, upload_done_data_[source]);
   upload_done_data_.erase(source);
 }
 
@@ -109,10 +98,13 @@
                  length, meta_data);
 
   // If a test has set the test string pointer, write to it and skip uploading.
-  // This will be removed when the browser test for this feature is fully done
-  // according to the test plan. See http://crbug.com/257329.
+  // Still fire the upload callback so that we can run an extension API test
+  // using the test framework for that without hanging.
+  // TODO(grunell): Remove this when the api test for this feature is fully
+  // implemented according to the test plan. http://crbug.com/257329.
   if (post_data_) {
     *post_data_ = post_data;
+    NotifyUploadDone(kHttpResponseOk, "", upload_done_data);
     return;
   }
 
@@ -281,3 +273,24 @@
                                      contents.size());
   DPCHECK(written == static_cast<int>(contents.size()));
 }
+
+void WebRtcLogUploader::NotifyUploadDone(
+    int response_code,
+    const std::string& report_id,
+    const WebRtcLogUploadDoneData& upload_done_data) {
+  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+      base::Bind(&WebRtcLoggingHandlerHost::UploadLogDone,
+                 upload_done_data.host));
+  if (!upload_done_data.callback.is_null()) {
+    bool success = response_code == kHttpResponseOk;
+    std::string error_message;
+    if (!success) {
+      error_message = "Uploading failed, response code: " +
+                      base::IntToString(response_code);
+    }
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(upload_done_data.callback, success, report_id,
+                   error_message));
+  }
+}
diff --git a/chrome/browser/media/webrtc_log_uploader.h b/chrome/browser/media/webrtc_log_uploader.h
index 2eca66b..9be5198 100644
--- a/chrome/browser/media/webrtc_log_uploader.h
+++ b/chrome/browser/media/webrtc_log_uploader.h
@@ -108,6 +108,10 @@
       const base::FilePath& upload_list_path,
       const std::string& report_id);
 
+  void NotifyUploadDone(int response_code,
+                        const std::string& report_id,
+                        const WebRtcLogUploadDoneData& upload_done_data);
+
   int log_count_;
 
   // For testing purposes, see OverrideUploadWithBufferForTesting. Only accessed
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
index 7f9e150..7084e4c 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -77,4 +77,11 @@
   virtual ~MTPDeviceAsyncDelegate() {}
 };
 
+typedef base::Callback<void(MTPDeviceAsyncDelegate*)>
+    CreateMTPDeviceAsyncDelegateCallback;
+
+void CreateMTPDeviceAsyncDelegate(
+    const base::FilePath::StringType& device_location,
+    const CreateMTPDeviceAsyncDelegateCallback& callback);
+
 #endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_H_
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
index cf91196..69d8d07 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
@@ -9,6 +9,7 @@
 
 #include "base/stl_util.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
+#include "content/public/browser/browser_thread.h"
 #include "webkit/browser/fileapi/isolated_context.h"
 
 namespace {
@@ -23,13 +24,47 @@
   return g_mtp_device_map_service.Pointer();
 }
 
-/////////////////////////////////////////////////////////////////////////////
-//   Following methods are used to manage MTPDeviceAsyncDelegate objects.  //
-/////////////////////////////////////////////////////////////////////////////
+void MTPDeviceMapService::RegisterMTPFileSystem(
+    const base::FilePath::StringType& device_location,
+    const std::string& fsid) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+  if (!ContainsKey(mtp_device_usage_map_, device_location)) {
+    // Note that this initializes the delegate asynchronously, but since
+    // the delegate will only be used from the IO thread, it is guaranteed
+    // to be created before use of it expects it to be there.
+    CreateMTPDeviceAsyncDelegate(device_location,
+        base::Bind(&MTPDeviceMapService::AddAsyncDelegate,
+                   base::Unretained(this), device_location));
+    mtp_device_usage_map_[device_location] = 0;
+  }
+
+  mtp_device_usage_map_[device_location]++;
+  mtp_device_map_[fsid] = device_location;
+}
+
+void MTPDeviceMapService::RevokeMTPFileSystem(const std::string& fsid) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+  MTPDeviceFileSystemMap::iterator it = mtp_device_map_.find(fsid);
+  if (it != mtp_device_map_.end()) {
+    base::FilePath::StringType device_location = it->second;
+    mtp_device_map_.erase(it);
+    MTPDeviceUsageMap::iterator delegate_it =
+        mtp_device_usage_map_.find(device_location);
+    DCHECK(delegate_it != mtp_device_usage_map_.end());
+    mtp_device_usage_map_[device_location]--;
+    if (mtp_device_usage_map_[device_location] == 0) {
+      mtp_device_usage_map_.erase(delegate_it);
+      RemoveAsyncDelegate(device_location);
+    }
+  }
+}
+
 void MTPDeviceMapService::AddAsyncDelegate(
     const base::FilePath::StringType& device_location,
     MTPDeviceAsyncDelegate* delegate) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   DCHECK(delegate);
   DCHECK(!device_location.empty());
   if (ContainsKey(async_delegate_map_, device_location))
@@ -39,7 +74,7 @@
 
 void MTPDeviceMapService::RemoveAsyncDelegate(
     const base::FilePath::StringType& device_location) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   AsyncDelegateMap::iterator it = async_delegate_map_.find(device_location);
   DCHECK(it != async_delegate_map_.end());
   it->second->CancelPendingTasksAndDeleteDelegate();
@@ -48,7 +83,7 @@
 
 MTPDeviceAsyncDelegate* MTPDeviceMapService::GetMTPDeviceAsyncDelegate(
     const std::string& filesystem_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   base::FilePath device_path;
   if (!fileapi::IsolatedContext::GetInstance()->GetRegisteredPath(
           filesystem_id, &device_path)) {
@@ -62,9 +97,9 @@
   return (it != async_delegate_map_.end()) ? it->second : NULL;
 }
 
-
 MTPDeviceMapService::MTPDeviceMapService() {
 }
 
 MTPDeviceMapService::~MTPDeviceMapService() {
+  DCHECK(mtp_device_usage_map_.empty());
 }
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
index bd22463..d64742e 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
@@ -16,10 +16,31 @@
 // This class provides media transfer protocol (MTP) device delegate to
 // complete media file system operations.
 // Lives on the IO thread in production.
+// TODO(gbillock): Make this class owned by the MediaFileSystemRegistry.
 class MTPDeviceMapService {
  public:
   static MTPDeviceMapService* GetInstance();
 
+  // Gets the media device delegate associated with |filesystem_id|.
+  // Return NULL if the |filesystem_id| is no longer valid (e.g. because the
+  // corresponding device is detached, etc).
+  // Called on the IO thread.
+  MTPDeviceAsyncDelegate* GetMTPDeviceAsyncDelegate(
+      const std::string& filesystem_id);
+
+  // Register that an MTP filesystem is in use for the given |device_location|.
+  void RegisterMTPFileSystem(
+    const base::FilePath::StringType& device_location,
+    const std::string& fsid);
+
+  // Removes the MTP entry associated with the given
+  // |device_location|. Signals the MTPDeviceMapService to destroy the
+  // delegate if there are no more uses of it.
+  void RevokeMTPFileSystem(const std::string& fsid);
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<MTPDeviceMapService>;
+
   // Adds the MTP device delegate to the map service. |device_location|
   // specifies the mount location of the MTP device.
   // Called on the IO thread.
@@ -31,32 +52,31 @@
   // Called on the IO thread.
   void RemoveAsyncDelegate(const base::FilePath::StringType& device_location);
 
-  // Gets the media device delegate associated with |filesystem_id|.
-  // Return NULL if the |filesystem_id| is no longer valid (e.g. because the
-  // corresponding device is detached, etc).
-  // Called on the IO thread.
-  MTPDeviceAsyncDelegate* GetMTPDeviceAsyncDelegate(
-      const std::string& filesystem_id);
-
- private:
-  friend struct base::DefaultLazyInstanceTraits<MTPDeviceMapService>;
-
   // Mapping of device_location and MTPDeviceAsyncDelegate* object. It is safe
   // to store and access the raw pointer. This class operates on the IO thread.
   typedef std::map<base::FilePath::StringType, MTPDeviceAsyncDelegate*>
       AsyncDelegateMap;
 
+  // Map a filesystem id (fsid) to an MTP device location.
+  typedef std::map<std::string, base::FilePath::StringType>
+      MTPDeviceFileSystemMap;
+
+  // Map a MTP or PTP device location to a count of current uses of that
+  // location.
+  typedef std::map<const base::FilePath::StringType, int>
+      MTPDeviceUsageMap;
+
+
   // Get access to this class using GetInstance() method.
   MTPDeviceMapService();
   ~MTPDeviceMapService();
 
-  /////////////////////////////////////////////////////////////////////////////
-  // Following member variables are used to manage asynchronous              //
-  // MTP device delegate objects.                                            //
-  /////////////////////////////////////////////////////////////////////////////
   // Map of attached mtp device async delegates.
   AsyncDelegateMap async_delegate_map_;
-  base::ThreadChecker thread_checker_;
+
+  MTPDeviceFileSystemMap mtp_device_map_;
+
+  MTPDeviceUsageMap mtp_device_usage_map_;
 
   DISALLOW_COPY_AND_ASSIGN(MTPDeviceMapService);
 };
diff --git a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
index a4f6b61..8e78827 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
@@ -552,14 +552,8 @@
   }
 };
 
-// Flaky on Mac. crbug.com/309160.
-#if defined(OS_MACOSX)
-#define MAYBE_InvalidateInflightAlbumsIndexerTest DISABLED_InvalidateInflightAlbumsIndexerTest
-#else
-#define MAYBE_InvalidateInflightAlbumsIndexerTest InvalidateInflightAlbumsIndexerTest
-#endif
 IN_PROC_BROWSER_TEST_F(PicasaDataProviderInvalidateInflightAlbumsIndexerTest,
-                       MAYBE_InvalidateInflightAlbumsIndexerTest) {
+                       InvalidateInflightAlbumsIndexerTest) {
   RunTest();
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/picasa_finder.cc b/chrome/browser/media_galleries/fileapi/picasa_finder.cc
index ef58e90..87ec630 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_finder.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_finder.cc
@@ -11,7 +11,6 @@
 #include "base/base_paths.h"
 #include "base/bind.h"
 #include "base/file_util.h"
-#include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
@@ -27,13 +26,13 @@
 #if defined(OS_WIN)
 const wchar_t kPicasaRegistryPath[] =
     L"Software\\Google\\Picasa\\Picasa2\\Preferences";
-const wchar_t kPicasaRegistryAppDataKey[] = L"AppLocalDataPath";
+const wchar_t kPicasaRegistryAppDataPathKey[] = L"AppLocalDataPath";
 #endif
 
 namespace {
 
 #if defined(OS_WIN)
-base::FilePath GetCustomPicasaRoot() {
+base::FilePath GetCustomPicasaAppDataPathFromWinRegistry() {
   base::win::RegKey key;
   if (key.Open(HKEY_CURRENT_USER, kPicasaRegistryPath, KEY_READ) !=
           ERROR_SUCCESS || !key.Valid()) {
@@ -41,7 +40,7 @@
   }
 
   string16 value;
-  if (key.ReadValue(kPicasaRegistryAppDataKey, &value) != ERROR_SUCCESS)
+  if (key.ReadValue(kPicasaRegistryAppDataPathKey, &value) != ERROR_SUCCESS)
     return base::FilePath();
   if (value.empty())
     return base::FilePath();
@@ -49,45 +48,38 @@
   return base::FilePath(value);
 }
 
-base::FilePath GetPicasaDatabasePathWin() {
-  base::FilePath path = GetCustomPicasaRoot();
+base::FilePath GetPicasaDatabasePath() {
+  base::FilePath path = GetCustomPicasaAppDataPathFromWinRegistry();
   if (path.empty() && !PathService::Get(base::DIR_LOCAL_APP_DATA, &path))
     return base::FilePath();
-
-  return path.AppendASCII("Google").AppendASCII("Picasa2").AppendASCII(
-        kPicasaDatabaseDirName);
+  return MakePicasaDatabasePath(path);
 }
-#endif
+#endif  // OS_WIN
 
-#if defined (OS_MACOSX)
-base::FilePath GetPicasaDatabasePathMac() {
-  // TODO(tommycli): Support Picasa Mac's custom path.
-  base::FilePath path;
-  if (!PathService::Get(base::DIR_APP_DATA, &path))
+#if defined(OS_MACOSX)
+base::FilePath GetPicasaDatabasePath() {
+  base::FilePath path = GetCustomPicasaAppDataPathFromMacPreferences();
+  if (path.empty() && !PathService::Get(base::DIR_APP_DATA, &path))
     return base::FilePath();
-
-  // On Mac, the database is in "Picasa3", not "Picasa2".
-  return path.AppendASCII("Google").AppendASCII("Picasa3").AppendASCII(
-        kPicasaDatabaseDirName);
+  return MakePicasaDatabasePath(path);
 }
-#endif
+#endif  // OS_MACOSX
 
 // Returns path of Picasa's DB3 database directory. May only be called on
 // threads that allow for disk IO, like the FILE thread or MediaTaskRunner.
 base::FilePath FindPicasaDatabaseOnFileThread() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  base::FilePath path;
-  #if defined(OS_WIN)
-  path = GetPicasaDatabasePathWin();
-  #elif defined(OS_MACOSX)
-  path = GetPicasaDatabasePathMac();
-  #endif
 
-  // Verify actual existence
-  if (!base::DirectoryExists(path))
-    path.clear();
+#if defined(OS_WIN) || defined(OS_MACOSX)
+   base::FilePath path = GetPicasaDatabasePath();
+   // Verify actual existence
+   if (!base::DirectoryExists(path))
+     path.clear();
 
-  return path;
+   return path;
+#else
+   return base::FilePath();
+#endif
 }
 
 void FinishOnOriginalThread(const DeviceIDCallback& callback,
@@ -110,4 +102,17 @@
       base::Bind(&FinishOnOriginalThread, callback));
 }
 
+base::FilePath MakePicasaDatabasePath(
+    const base::FilePath& picasa_app_data_path) {
+#if defined(OS_WIN)
+  return picasa_app_data_path.AppendASCII("Google").AppendASCII("Picasa2")
+      .AppendASCII(kPicasaDatabaseDirName);
+#elif defined(OS_MACOSX)
+  return picasa_app_data_path.AppendASCII("Google").AppendASCII("Picasa3")
+      .AppendASCII(kPicasaDatabaseDirName);
+#else
+  return base::FilePath();
+#endif
+}
+
 }  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/picasa_finder.h b/chrome/browser/media_galleries/fileapi/picasa_finder.h
index 1c64273..109c90d 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_finder.h
+++ b/chrome/browser/media_galleries/fileapi/picasa_finder.h
@@ -8,12 +8,28 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
+
+#if defined(OS_MACOSX)
+
+class MacPreferences;
+#if defined(__OBJC__)
+@class NSString;
+#else  // __OBJC__
+class NSString;
+#endif  // __OBJC__
+
+#endif  // OS_MACOSX
 
 namespace picasa {
 
 #if defined(OS_WIN)
 extern const wchar_t kPicasaRegistryPath[];
-extern const wchar_t kPicasaRegistryAppDataKey[];
+extern const wchar_t kPicasaRegistryAppDataPathKey[];
+#endif
+
+#if defined(OS_MACOSX)
+extern NSString* const kPicasaAppDataPathMacPreferencesKey;
 #endif
 
 typedef base::Callback<void(const std::string&)> DeviceIDCallback;
@@ -24,6 +40,21 @@
 // with an empty string.
 void FindPicasaDatabase(const DeviceIDCallback& callback);
 
+// Builds the OS-dependent Picasa database path from the app-data path.
+// Used internally and by tests to construct an test environments.
+base::FilePath MakePicasaDatabasePath(
+    const base::FilePath& picasa_app_data_path);
+
+#if defined(OS_MACOSX)
+// Set the mac preferences to use for testing. The caller continues to own
+// |preferences| and should call this function again with NULL before freeing
+// it.
+void SetMacPreferencesForTesting(MacPreferences* preferences);
+
+// Used internally only.
+base::FilePath GetCustomPicasaAppDataPathFromMacPreferences();
+#endif  // OS_MACOSX
+
 }  // namespace picasa
 
 #endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_FINDER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa_finder_mac.mm b/chrome/browser/media_galleries/fileapi/picasa_finder_mac.mm
new file mode 100644
index 0000000..1a3dead
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa_finder_mac.mm
@@ -0,0 +1,52 @@
+// Copyright 2013 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/media_galleries/fileapi/picasa_finder.h"
+
+#include "base/files/file_path.h"
+#import "base/mac/foundation_util.h"
+#import "base/mac/scoped_nsobject.h"
+#include "chrome/browser/policy/preferences_mac.h"
+#include "content/public/browser/browser_thread.h"
+
+using base::mac::CFCast;
+using base::mac::CFToNSCast;
+using base::mac::NSToCFCast;
+
+namespace picasa {
+
+namespace {
+
+static MacPreferences* g_test_mac_preferences = NULL;
+
+}  // namespace
+
+NSString* const kPicasaAppDataPathMacPreferencesKey = @"AppLocalDataPath";
+
+void SetMacPreferencesForTesting(MacPreferences* preferences) {
+  g_test_mac_preferences = preferences;
+}
+
+base::FilePath GetCustomPicasaAppDataPathFromMacPreferences() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+
+  scoped_ptr<MacPreferences> real_preferences;
+  MacPreferences* prefs = g_test_mac_preferences;
+  if (!prefs) {
+    real_preferences.reset(new MacPreferences());
+    prefs = real_preferences.get();
+  }
+
+  CFStringRef picasa_app_id = CFSTR("com.google.picasa");
+  base::scoped_nsobject<NSString> database_path(
+      CFToNSCast(CFCast<CFStringRef>(prefs->CopyAppValue(
+          NSToCFCast(kPicasaAppDataPathMacPreferencesKey), picasa_app_id))));
+
+  if (database_path == NULL)
+    return base::FilePath();
+
+  return base::mac::NSStringToFilePath(database_path.get());
+}
+
+}  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/safe_picasa_album_table_reader.h b/chrome/browser/media_galleries/fileapi/safe_picasa_album_table_reader.h
index c5bfe52..7e32c79 100644
--- a/chrome/browser/media_galleries/fileapi/safe_picasa_album_table_reader.h
+++ b/chrome/browser/media_galleries/fileapi/safe_picasa_album_table_reader.h
@@ -36,6 +36,7 @@
                               const std::vector<AlbumInfo>&)>
       ParserCallback;
 
+  // This class takes ownership of |album_table_files| and will close them.
   explicit SafePicasaAlbumTableReader(const AlbumTableFiles& album_table_files);
 
   void Start(const ParserCallback& callback);
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
index 25a3b05..5a04bc7 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/platform_file.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
-#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
 #include "webkit/browser/fileapi/async_file_util.h"
 
 namespace base {
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index e977243..feee27c 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -8,7 +8,6 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
 #include "chrome/browser/storage_monitor/image_capture_device.h"
 #include "chrome/browser/storage_monitor/image_capture_device_manager.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/media_galleries/media_file_system_context.h b/chrome/browser/media_galleries/media_file_system_context.h
index 54b9a8e..0ecafd6 100644
--- a/chrome/browser/media_galleries/media_file_system_context.h
+++ b/chrome/browser/media_galleries/media_file_system_context.h
@@ -19,14 +19,9 @@
  public:
   virtual ~MediaFileSystemContext() {}
 
-  // Register a media file system (filtered to media files) for |path| and
-  // return the new file system id.
-  virtual std::string RegisterFileSystemForMassStorage(
-      const std::string& device_id, const base::FilePath& path) = 0;
-
-  // Registers and returns the file system id for the MTP or PTP device
-  // specified by |device_id| and |path|.
-  virtual std::string RegisterFileSystemForMTPDevice(
+  // Register a new media file system for |path| and return the corresponding
+  // filesystem ID.
+  virtual std::string RegisterFileSystem(
       const std::string& device_id, const base::FilePath& path) = 0;
 
   // Revoke the passed |fsid|.
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index 0eafc4c..0dcd520 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -57,24 +57,6 @@
   std::set<MediaGalleryPrefId> pref_ids;
 };
 
-void OnMTPDeviceAsyncDelegateCreated(
-    const base::FilePath::StringType& device_location,
-    MTPDeviceAsyncDelegate* delegate) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  MTPDeviceMapService::GetInstance()->AddAsyncDelegate(
-      device_location, delegate);
-}
-
-void InitMTPDeviceAsyncDelegate(
-    const base::FilePath::StringType& device_location) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE, base::Bind(
-          &CreateMTPDeviceAsyncDelegate,
-          device_location,
-          base::Bind(&OnMTPDeviceAsyncDelegateCreated, device_location)));
-}
-
 // Tracks the liveness of multiple RenderProcessHosts that the caller is
 // interested in. Once all of the RPHs have closed or been terminated a call
 // back informs the caller.
@@ -338,14 +320,8 @@
       if (!MediaStorageUtil::CanCreateFileSystem(device_id, path))
         continue;
 
-      std::string fsid;
-      if (StorageInfo::IsMassStorageDevice(device_id)) {
-        fsid = file_system_context_->RegisterFileSystemForMassStorage(
-            device_id, path);
-      } else {
-        fsid = file_system_context_->RegisterFileSystemForMTPDevice(
-            device_id, path);
-      }
+      std::string fsid =
+          file_system_context_->RegisterFileSystem(device_id, path);
       if (fsid.empty())
         continue;
 
@@ -524,10 +500,35 @@
   }
   virtual ~MediaFileSystemContextImpl() {}
 
+  virtual std::string RegisterFileSystem(
+      const std::string& device_id, const base::FilePath& path) OVERRIDE {
+    if (StorageInfo::IsMassStorageDevice(device_id)) {
+      return RegisterFileSystemForMassStorage(device_id, path);
+    } else {
+      return RegisterFileSystemForMTPDevice(device_id, path);
+    }
+  }
+
+  virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE {
+    ImportedMediaGalleryRegistry* imported_registry =
+        ImportedMediaGalleryRegistry::GetInstance();
+    if (imported_registry->RevokeImportedFilesystemOnUIThread(fsid))
+      return;
+
+    IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE, base::Bind(
+            &MTPDeviceMapService::RevokeMTPFileSystem,
+            base::Unretained(MTPDeviceMapService::GetInstance()),
+            fsid));
+  }
+
+ private:
   // Registers and returns the file system id for the mass storage device
   // specified by |device_id| and |path|.
-  virtual std::string RegisterFileSystemForMassStorage(
-      const std::string& device_id, const base::FilePath& path) OVERRIDE {
+  std::string RegisterFileSystemForMassStorage(
+      const std::string& device_id, const base::FilePath& path) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     DCHECK(StorageInfo::IsMassStorageDevice(device_id));
 
@@ -562,8 +563,8 @@
     return fsid;
   }
 
-  virtual std::string RegisterFileSystemForMTPDevice(
-      const std::string& device_id, const base::FilePath& path) OVERRIDE {
+  std::string RegisterFileSystemForMTPDevice(
+      const std::string& device_id, const base::FilePath& path) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     DCHECK(!StorageInfo::IsMassStorageDevice(device_id));
 
@@ -571,25 +572,17 @@
     CHECK(MediaStorageUtil::CanCreateFileSystem(device_id, path));
     std::string fs_name(extension_misc::kMediaFileSystemPathPart);
     const std::string fsid =
-        IsolatedContext::GetInstance()->RegisterFileSystemForPath(
-            fileapi::kFileSystemTypeDeviceMedia, path, &fs_name);
+        IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+            fileapi::kFileSystemTypeDeviceMedia, fs_name, path);
     CHECK(!fsid.empty());
-    registry_->RegisterMTPFileSystem(path.value(), fsid);
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE, base::Bind(
+            &MTPDeviceMapService::RegisterMTPFileSystem,
+            base::Unretained(MTPDeviceMapService::GetInstance()),
+            path.value(), fsid));
     return fsid;
   }
 
-  virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE {
-    ImportedMediaGalleryRegistry* imported_registry =
-        ImportedMediaGalleryRegistry::GetInstance();
-    if (imported_registry->RevokeImportedFilesystemOnUIThread(fsid))
-      return;
-
-    IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
-
-    registry_->RevokeMTPFileSystem(fsid);
-  }
-
- private:
   MediaFileSystemRegistry* registry_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaFileSystemContextImpl);
@@ -607,7 +600,6 @@
   // and then can remove this.
   if (StorageMonitor::GetInstance())
     StorageMonitor::GetInstance()->RemoveObserver(this);
-  DCHECK(mtp_device_usage_map_.empty());
 }
 
 void MediaFileSystemRegistry::OnPermissionRemoved(
@@ -661,45 +653,6 @@
   }
 }
 
-void MediaFileSystemRegistry::RegisterMTPFileSystem(
-    const base::FilePath::StringType& device_location,
-    const std::string& fsid) {
-  MTPDeviceUsageMap::iterator delegate_it =
-      mtp_device_usage_map_.find(device_location);
-  if (delegate_it == mtp_device_usage_map_.end()) {
-    // Note that this initializes the delegate asynchronously, but since
-    // the delegate will only be used from the IO thread, it is guaranteed
-    // to be created before use of it expects it to be there.
-    InitMTPDeviceAsyncDelegate(device_location);
-    mtp_device_usage_map_[device_location] = 0;
-  }
-
-  mtp_device_usage_map_[device_location]++;
-  mtp_device_map_[fsid] = device_location;
-}
-
-// TODO(gbillock): Move all this accounting to the MTPDeviceMapService.
-void MediaFileSystemRegistry::RevokeMTPFileSystem(const std::string& fsid) {
-  MTPDeviceFileSystemMap::iterator i = mtp_device_map_.find(fsid);
-  if (i != mtp_device_map_.end()) {
-    base::FilePath::StringType device_location = i->second;
-    mtp_device_map_.erase(i);
-    MTPDeviceUsageMap::iterator delegate_it =
-        mtp_device_usage_map_.find(device_location);
-    DCHECK(delegate_it != mtp_device_usage_map_.end());
-    mtp_device_usage_map_[device_location]--;
-    if (mtp_device_usage_map_[device_location] == 0) {
-      mtp_device_usage_map_.erase(delegate_it);
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO,
-          FROM_HERE,
-          base::Bind(&MTPDeviceMapService::RemoveAsyncDelegate,
-                     base::Unretained(MTPDeviceMapService::GetInstance()),
-                     device_location));
-    }
-  }
-}
-
 void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
     Profile* profile, const std::string& extension_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
diff --git a/chrome/browser/media_galleries/media_file_system_registry.h b/chrome/browser/media_galleries/media_file_system_registry.h
index 59523ef..d47a490 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.h
+++ b/chrome/browser/media_galleries/media_file_system_registry.h
@@ -16,8 +16,8 @@
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
-#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
 #include "chrome/browser/storage_monitor/removable_storage_observer.h"
 
 class ExtensionGalleriesHost;
@@ -100,41 +100,18 @@
   // Map a profile and extension to the ExtensionGalleriesHost.
   typedef std::map<Profile*, ExtensionHostMap> ExtensionGalleriesHostMap;
 
-  // Map a filesystem id (fsid) to an MTP device location.
-  typedef std::map<std::string, base::FilePath::StringType>
-      MTPDeviceFileSystemMap;
-
-  // Map a MTP or PTP device location to a count of current uses of that
-  // location.
-  typedef std::map<const base::FilePath::StringType, int>
-      MTPDeviceUsageMap;
-
   virtual void OnPermissionRemoved(MediaGalleriesPreferences* pref,
                                    const std::string& extension_id,
                                    MediaGalleryPrefId pref_id) OVERRIDE;
   virtual void OnGalleryRemoved(MediaGalleriesPreferences* pref,
                                 MediaGalleryPrefId pref_id) OVERRIDE;
 
-  // Register that an MTP filesystem is in use for the given |device_location|.
-  void RegisterMTPFileSystem(
-      const base::FilePath::StringType& device_location,
-      const std::string& fsid);
-
-  // Removes the MTP entry associated with the given
-  // |device_location|. Signals the MTPDeviceMapService to destroy the
-  // delegate if there are no more uses of it.
-  void RevokeMTPFileSystem(const std::string& fsid);
-
   void OnExtensionGalleriesHostEmpty(Profile* profile,
                                      const std::string& extension_id);
 
   // This map owns all the ExtensionGalleriesHost objects created.
   ExtensionGalleriesHostMap extension_hosts_map_;
 
-  MTPDeviceFileSystemMap mtp_device_map_;
-
-  MTPDeviceUsageMap mtp_device_usage_map_;
-
   scoped_ptr<MediaFileSystemContext> file_system_context_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaFileSystemRegistry);
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index d21fdeb..a122bf5 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -75,10 +75,7 @@
   virtual ~TestMediaFileSystemContext() {}
 
   // MediaFileSystemContext implementation.
-  virtual std::string RegisterFileSystemForMassStorage(
-      const std::string& device_id, const base::FilePath& path) OVERRIDE;
-
-  virtual std::string RegisterFileSystemForMTPDevice(
+  virtual std::string RegisterFileSystem(
       const std::string& device_id, const base::FilePath& path) OVERRIDE;
 
   virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE;
@@ -123,17 +120,9 @@
   registry_->file_system_context_.reset(this);
 }
 
-std::string TestMediaFileSystemContext::RegisterFileSystemForMassStorage(
+std::string TestMediaFileSystemContext::RegisterFileSystem(
     const std::string& device_id, const base::FilePath& path) {
-  CHECK(StorageInfo::IsMassStorageDevice(device_id));
-  return AddFSEntry(device_id, path);
-}
-
-std::string TestMediaFileSystemContext::RegisterFileSystemForMTPDevice(
-    const std::string& device_id, const base::FilePath& path) {
-  CHECK(!StorageInfo::IsMassStorageDevice(device_id));
   std::string fsid = AddFSEntry(device_id, path);
-  registry_->RegisterMTPFileSystem(path.value(), fsid);
   return fsid;
 }
 
@@ -141,7 +130,6 @@
   if (!ContainsKey(file_systems_by_id_, fsid))
     return;
   EXPECT_EQ(1U, file_systems_by_id_.erase(fsid));
-  registry_->RevokeMTPFileSystem(fsid);
 }
 
 base::FilePath TestMediaFileSystemContext::GetPathForId(
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
index 87e1ccb..5e9b259 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/web_contents_view.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
 #include "ui/base/text/bytes_formatting.h"
 
 using extensions::APIPermission;
@@ -44,6 +45,40 @@
 
 }  // namespace
 
+class GalleryContextMenuModel : public ui::SimpleMenuModel::Delegate {
+ public:
+  explicit GalleryContextMenuModel(MediaGalleriesDialogController* controller)
+      : controller_(controller), id_(kInvalidMediaGalleryPrefId) {}
+  virtual ~GalleryContextMenuModel() {}
+
+  void set_media_gallery_pref_id(MediaGalleryPrefId id) {
+    id_ = id;
+  }
+
+  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
+    return false;
+  }
+  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
+    return true;
+  }
+  virtual bool IsCommandIdVisible(int command_id) const OVERRIDE {
+    return true;
+  }
+
+  virtual bool GetAcceleratorForCommandId(
+      int command_id, ui::Accelerator* accelerator) OVERRIDE {
+    return false;
+  }
+
+  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
+    controller_->DidForgetGallery(id_);
+  }
+
+ private:
+  MediaGalleriesDialogController* controller_;
+  MediaGalleryPrefId id_;
+};
+
 MediaGalleriesDialogController::MediaGalleriesDialogController(
     content::WebContents* web_contents,
     const Extension& extension,
@@ -60,6 +95,13 @@
   preferences_->EnsureInitialized(
       base::Bind(&MediaGalleriesDialogController::OnPreferencesInitialized,
                  base::Unretained(this)));
+
+  gallery_menu_model_.reset(new GalleryContextMenuModel(this));
+  ui::SimpleMenuModel* menu_model =
+      new ui::SimpleMenuModel(gallery_menu_model_.get());
+  menu_model->AddItem(
+      1, l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_DELETE));
+  context_menu_model_.reset(menu_model);
 }
 
 void MediaGalleriesDialogController::OnPreferencesInitialized() {
@@ -139,17 +181,13 @@
     const {
   for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
        iter != known_galleries_.end(); ++iter) {
-    if ((attached && iter->second.pref_info.IsGalleryAvailable()) ||
-        (!attached && !iter->second.pref_info.IsGalleryAvailable())) {
+    if (attached == iter->second.pref_info.IsGalleryAvailable())
       permissions->push_back(iter->second);
-    }
   }
   for (GalleryPermissionsVector::const_iterator iter = new_galleries_.begin();
        iter != new_galleries_.end(); ++iter) {
-    if ((attached && iter->pref_info.IsGalleryAvailable()) ||
-        (!attached && !iter->pref_info.IsGalleryAvailable())) {
+    if (attached == iter->pref_info.IsGalleryAvailable())
       permissions->push_back(*iter);
-    }
   }
 
   std::sort(permissions->begin(), permissions->end(),
@@ -204,18 +242,28 @@
     return;
   }
 
-  // Check new galleries.
+  // Don't sort -- the dialog is open, and we don't want to adjust any
+  // positions for future updates to the dialog contents until they are
+  // redrawn.
+}
+
+void MediaGalleriesDialogController::DidToggleNewGallery(
+    const MediaGalleryPrefInfo& gallery,
+    bool enabled) {
   for (GalleryPermissionsVector::iterator iter = new_galleries_.begin();
        iter != new_galleries_.end(); ++iter) {
-    if (iter->pref_info.pref_id == gallery_id) {
+    if (iter->pref_info.path == gallery.path &&
+        iter->pref_info.device_id == gallery.device_id) {
       iter->allowed = enabled;
       return;
     }
   }
+}
 
-  // Don't sort -- the dialog is open, and we don't want to adjust any
-  // positions for future updates to the dialog contents until they are
-  // redrawn.
+void MediaGalleriesDialogController::DidForgetGallery(
+    MediaGalleryPrefId pref_id) {
+  DCHECK(preferences_);
+  preferences_->ForgetGalleryById(pref_id);
 }
 
 void MediaGalleriesDialogController::DialogFinished(bool accepted) {
@@ -246,10 +294,8 @@
     // The prefs are in sync with |known_galleries_|, so it should exist in
     // |known_galleries_| as well. User selecting a known gallery effectively
     // just sets the gallery to permitted.
-    KnownGalleryPermissions::const_iterator iter =
-        known_galleries_.find(gallery.pref_id);
-    DCHECK(iter != known_galleries_.end());
-    dialog_->UpdateGallery(iter->second.pref_info, true);
+    DCHECK(ContainsKey(known_galleries_, gallery.pref_id));
+    dialog_->UpdateGalleries();
     return;
   }
 
@@ -259,14 +305,15 @@
     if (iter->pref_info.path == gallery.path &&
         iter->pref_info.device_id == gallery.device_id) {
       iter->allowed = true;
-      dialog_->UpdateGallery(iter->pref_info, true);
+      dialog_->UpdateGalleries();
       return;
     }
   }
 
-  // Lastly, add a new gallery to |new_galleries_|.
+  // Lastly, if not found, add a new gallery to |new_galleries_|.
+  // Note that it will have prefId = kInvalidMediaGalleryPrefId.
   new_galleries_.push_back(GalleryPermission(gallery, true));
-  dialog_->UpdateGallery(new_galleries_.back().pref_info, true);
+  dialog_->UpdateGalleries();
 }
 
 void MediaGalleriesDialogController::OnRemovableStorageAttached(
@@ -323,13 +370,15 @@
 }
 
 void MediaGalleriesDialogController::InitializePermissions() {
+  known_galleries_.clear();
   const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
   for (MediaGalleriesPrefInfoMap::const_iterator iter = galleries.begin();
        iter != galleries.end();
        ++iter) {
     const MediaGalleryPrefInfo& gallery = iter->second;
-    if (gallery.type == MediaGalleryPrefInfo::kBlackListed)
+    if (gallery.type == MediaGalleryPrefInfo::kBlackListed) {
       continue;
+    }
 
     known_galleries_[iter->first] = GalleryPermission(gallery, false);
   }
@@ -383,30 +432,12 @@
   // but the code below will put |known_galleries_| back in a consistent state.
   InitializePermissions();
 
-  // If a gallery no longer belongs in |known_galleries_|, forget it in the
-  // model/view.
-  // If a gallery still belong in |known_galleries_|, check for a duplicate
-  // entry in |new_galleries_|, merge its permission and remove it. Then update
-  // the view.
-  const MediaGalleriesPrefInfoMap& pref_galleries =
-      preferences_->known_galleries();
-  MediaGalleryPrefIdSet galleries_to_forget;
+  // Look for duplicate entries in |new_galleries_| in case one was added
+  // in another dialog.
   for (KnownGalleryPermissions::iterator it = known_galleries_.begin();
        it != known_galleries_.end();
        ++it) {
-    const MediaGalleryPrefId& gallery_id = it->first;
     GalleryPermission& gallery = it->second;
-    MediaGalleriesPrefInfoMap::const_iterator pref_it =
-        pref_galleries.find(gallery_id);
-    // Check for lingering entry that should be removed.
-    if (pref_it == pref_galleries.end() ||
-        pref_it->second.type == MediaGalleryPrefInfo::kBlackListed) {
-      galleries_to_forget.insert(gallery_id);
-      dialog_->ForgetGallery(gallery.pref_info.pref_id);
-      continue;
-    }
-
-    // Look for duplicate entries in |new_galleries_|.
     for (GalleryPermissionsVector::iterator new_it = new_galleries_.begin();
          new_it != new_galleries_.end();
          ++new_it) {
@@ -415,36 +446,24 @@
         // Found duplicate entry. Get the existing permission from it and then
         // remove it.
         gallery.allowed = new_it->allowed;
-        dialog_->ForgetGallery(new_it->pref_info.pref_id);
         new_galleries_.erase(new_it);
         break;
       }
     }
-    dialog_->UpdateGallery(gallery.pref_info, gallery.allowed);
   }
 
-  // Remove the galleries to forget from |known_galleries_|. Doing it in the
-  // above loop would invalidate the iterator there.
-  for (MediaGalleryPrefIdSet::const_iterator it = galleries_to_forget.begin();
-       it != galleries_to_forget.end();
-       ++it) {
-    known_galleries_.erase(*it);
-  }
+  dialog_->UpdateGalleries();
 }
 
 void MediaGalleriesDialogController::UpdateGalleriesOnDeviceEvent(
     const std::string& device_id) {
-  for (KnownGalleryPermissions::iterator iter = known_galleries_.begin();
-       iter != known_galleries_.end(); ++iter) {
-    if (iter->second.pref_info.device_id == device_id)
-      dialog_->UpdateGallery(iter->second.pref_info, iter->second.allowed);
-  }
+  dialog_->UpdateGalleries();
+}
 
-  for (GalleryPermissionsVector::iterator iter = new_galleries_.begin();
-       iter != new_galleries_.end(); ++iter) {
-    if (iter->pref_info.device_id == device_id)
-      dialog_->UpdateGallery(iter->pref_info, iter->allowed);
-  }
+ui::MenuModel* MediaGalleriesDialogController::GetContextMenuModel(
+    MediaGalleryPrefId id) {
+  gallery_menu_model_->set_media_gallery_pref_id(id);
+  return context_menu_model_.get();
 }
 
 // MediaGalleries dialog -------------------------------------------------------
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller.h b/chrome/browser/media_galleries/media_galleries_dialog_controller.h
index 5e01f8b..b8829a5 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller.h
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller.h
@@ -24,6 +24,11 @@
 class Extension;
 }
 
+namespace ui {
+class MenuModel;
+}
+
+class GalleryContextMenuModel;
 class MediaGalleriesDialogController;
 
 // The view.
@@ -31,15 +36,8 @@
  public:
   virtual ~MediaGalleriesDialog();
 
-  // Updates the entry for |gallery| with the checkbox set to the value in
-  // |permitted|. |gallery| is owned by the controller and is guaranteed to
-  // live longer than the dialog. If the entry does not already exist, it
-  // should be created.
-  virtual void UpdateGallery(const MediaGalleryPrefInfo& gallery,
-                             bool permitted) = 0;
-
-  // If there exists an entry for |gallery|, it should be removed.
-  virtual void ForgetGallery(MediaGalleryPrefId gallery) = 0;
+  // Tell the dialog to update its display list of galleries.
+  virtual void UpdateGalleries() = 0;
 
   // Constructs a platform-specific dialog owned and controlled by |controller|.
   static MediaGalleriesDialog* Create(
@@ -95,12 +93,19 @@
   // of gallery permissions checkbox settings is sent on every checkbox toggle.
   virtual void DidToggleGalleryId(MediaGalleryPrefId pref_id,
                                   bool enabled);
+  virtual void DidToggleNewGallery(const MediaGalleryPrefInfo& gallery,
+                                   bool enabled);
+
+  // The forget command in the context menu was selected.
+  virtual void DidForgetGallery(MediaGalleryPrefId pref_id);
 
   // The dialog is being deleted.
   virtual void DialogFinished(bool accepted);
 
   virtual content::WebContents* web_contents();
 
+  ui::MenuModel* GetContextMenuModel(MediaGalleryPrefId id);
+
  protected:
   // For use with tests.
   explicit MediaGalleriesDialogController(
@@ -192,6 +197,9 @@
 
   scoped_refptr<ui::SelectFileDialog> select_folder_dialog_;
 
+  scoped_ptr<ui::MenuModel> context_menu_model_;
+  scoped_ptr<GalleryContextMenuModel> gallery_menu_model_;
+
   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesDialogController);
 };
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc
index 7200222..e6671fc 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -9,6 +9,7 @@
 #include "base/i18n/time_formatting.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/media_galleries/fileapi/picasa_finder.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/storage_monitor/media_storage_util.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index 6f172f5..6487930 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -262,6 +262,8 @@
   // Needed for extension service & friends to work.
   content::TestBrowserThreadBundle thread_bundle_;
 
+  EnsureMediaDirectoriesExists mock_gallery_locations_;
+
 #if defined OS_CHROMEOS
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
   chromeos::ScopedTestCrosSettings test_cros_settings_;
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index 8f5a661..d2f32a5 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -90,6 +90,10 @@
 }
 
 EnsureMediaDirectoriesExists::~EnsureMediaDirectoriesExists() {
+#if defined(OS_MACOSX)
+  iapps::SetMacPreferencesForTesting(NULL);
+  picasa::SetMacPreferencesForTesting(NULL);
+#endif  // OS_MACOSX
 }
 
 base::FilePath EnsureMediaDirectoriesExists::GetFakeAppDataPath() const {
@@ -103,14 +107,24 @@
   return fake_dir_.path().AppendASCII("localappdata");
 }
 
-void EnsureMediaDirectoriesExists::WriteCustomPicasaAppDataPathToRegistry(
+void EnsureMediaDirectoriesExists::SetCustomPicasaAppDataPath(
     const base::FilePath& path) {
   base::win::RegKey key(HKEY_CURRENT_USER, picasa::kPicasaRegistryPath,
                         KEY_SET_VALUE);
-  key.WriteValue(picasa::kPicasaRegistryAppDataKey, path.value().c_str());
+  key.WriteValue(picasa::kPicasaRegistryAppDataPathKey, path.value().c_str());
 }
 #endif  // OS_WIN
 
+#if defined(OS_MACOSX)
+void EnsureMediaDirectoriesExists::SetCustomPicasaAppDataPath(
+    const base::FilePath& path) {
+  mac_preferences_->AddTestItem(
+      base::mac::NSToCFCast(picasa::kPicasaAppDataPathMacPreferencesKey),
+      base::SysUTF8ToNSString(path.value()),
+      false);
+}
+#endif // OS_MACOSX
+
 #if defined(OS_WIN) || defined(OS_MACOSX)
 base::FilePath
 EnsureMediaDirectoriesExists::GetFakePicasaFoldersRootPath() const {
@@ -144,6 +158,7 @@
 #if defined(OS_MACOSX)
   mac_preferences_.reset(new MockPreferences);
   iapps::SetMacPreferencesForTesting(mac_preferences_.get());
+  picasa::SetMacPreferencesForTesting(mac_preferences_.get());
 
   // iTunes override.
   mac_preferences_->AddTestItem(
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.h b/chrome/browser/media_galleries/media_galleries_test_util.h
index 81e7de7..be22818 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.h
+++ b/chrome/browser/media_galleries/media_galleries_test_util.h
@@ -44,9 +44,9 @@
   base::FilePath GetFakeAppDataPath() const;
 #if defined(OS_WIN)
   base::FilePath GetFakeLocalAppDataPath() const;
-  void WriteCustomPicasaAppDataPathToRegistry(const base::FilePath& path);
 #endif
 #if defined(OS_WIN) || defined(OS_MACOSX)
+  void SetCustomPicasaAppDataPath(const base::FilePath& path);
   base::FilePath GetFakePicasaFoldersRootPath() const;
 #endif
 
diff --git a/chrome/browser/media_galleries/mtp_device_delegate_impl.h b/chrome/browser/media_galleries/mtp_device_delegate_impl.h
deleted file mode 100644
index 407f7b8..0000000
--- a/chrome/browser/media_galleries/mtp_device_delegate_impl.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 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_MEDIA_GALLERIES_MTP_DEVICE_DELEGATE_IMPL_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_MTP_DEVICE_DELEGATE_IMPL_H_
-
-#include "base/callback_forward.h"
-#include "base/files/file_path.h"
-#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-typedef base::Callback<void(MTPDeviceAsyncDelegate*)>
-    CreateMTPDeviceAsyncDelegateCallback;
-
-void CreateMTPDeviceAsyncDelegate(
-    const base::FilePath::StringType& device_location,
-    const CreateMTPDeviceAsyncDelegateCallback& callback);
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_MTP_DEVICE_DELEGATE_IMPL_H_
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
index 79672ea..6d31894 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -15,7 +15,6 @@
 #include "base/strings/string16.h"
 #include "base/win/scoped_comptr.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
-#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
 #include "webkit/browser/fileapi/async_file_util.h"
 
 namespace base {
diff --git a/chrome/browser/metrics/metrics_log_serializer.cc b/chrome/browser/metrics/metrics_log_serializer.cc
index 6e5c1a9..ad781ff 100644
--- a/chrome/browser/metrics/metrics_log_serializer.cc
+++ b/chrome/browser/metrics/metrics_log_serializer.cc
@@ -10,8 +10,8 @@
 #include "base/md5.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 
 namespace {
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 98bbf81..281049e 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -162,6 +162,7 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -185,7 +186,6 @@
 #include "chrome/browser/net/http_pipelining_compatibility_client.h"
 #include "chrome/browser/net/network_stats.h"
 #include "chrome/browser/omnibox/omnibox_log.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_otr_state.h"
@@ -228,6 +228,10 @@
 #include "base/win/registry.h"
 #endif
 
+#if !defined(OS_ANDROID)
+#include "chrome/browser/service/service_process_control.h"
+#endif
+
 using base::Time;
 using content::BrowserThread;
 using content::ChildProcessData;
@@ -325,6 +329,8 @@
 void MarkAppCleanShutdownAndCommit() {
   PrefService* pref = g_browser_process->local_state();
   pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
+  pref->SetInteger(prefs::kStabilityExecutionPhase,
+                   MetricsService::CLEAN_SHUTDOWN);
   // Start writing right away (write happens on a different thread).
   pref->CommitPendingWrite();
 }
@@ -335,6 +341,9 @@
 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ =
     MetricsService::CLEANLY_SHUTDOWN;
 
+MetricsService::ExecutionPhase MetricsService::execution_phase_ =
+    MetricsService::CLEAN_SHUTDOWN;
+
 // This is used to quickly log stats from child process related notifications in
 // MetricsService::child_stats_buffer_.  The buffer's contents are transferred
 // out when Local State is periodically saved.  The information is then
@@ -405,6 +414,8 @@
   registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
   registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
   registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
+  registry->RegisterIntegerPref(prefs::kStabilityExecutionPhase,
+                                CLEAN_SHUTDOWN);
   registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
   registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
   registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
@@ -441,6 +452,7 @@
 // static
 void MetricsService::DiscardOldStabilityStats(PrefService* local_state) {
   local_state->SetBoolean(prefs::kStabilityExitedCleanly, true);
+  local_state->SetInteger(prefs::kStabilityExecutionPhase, CLEAN_SHUTDOWN);
   local_state->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
 
   local_state->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
@@ -476,6 +488,7 @@
       self_ptr_factory_(this),
       state_saver_factory_(this),
       waiting_for_asynchronous_reporting_step_(false),
+      num_async_histogram_fetches_in_progress_(0),
       entropy_source_returned_(LAST_ENTROPY_NONE) {
   DCHECK(IsSingleThreaded());
   InitializeMetricsState();
@@ -768,6 +781,7 @@
 void MetricsService::OnAppEnterForeground() {
   PrefService* pref = g_browser_process->local_state();
   pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
+  pref->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
 
   StartSchedulerIfNecessary();
 }
@@ -775,6 +789,7 @@
 void MetricsService::LogNeedForCleanShutdown() {
   PrefService* pref = g_browser_process->local_state();
   pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
+  pref->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
   // Redundant setting to be sure we call for a clean shutdown.
   clean_shutdown_status_ = NEED_TO_SHUTDOWN;
 }
@@ -893,6 +908,13 @@
     // Reset flag, and wait until we call LogNeedForCleanShutdown() before
     // monitoring.
     pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
+
+    // TODO(rtenneti): On windows, consider saving/getting execution_phase from
+    // the registry.
+    int execution_phase = pref->GetInteger(prefs::kStabilityExecutionPhase);
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.ExecutionPhase",
+                                execution_phase);
+    pref->SetInteger(prefs::kStabilityExecutionPhase, CLEAN_SHUTDOWN);
   }
 
 #if defined(OS_WIN)
@@ -1306,12 +1328,32 @@
       &MetricsService::OnHistogramSynchronizationDone,
       self_ptr_factory_.GetWeakPtr());
 
+  base::TimeDelta timeout =
+      base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration);
+
+  DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
+
+#if defined(OS_ANDROID)
+  // Android has no service process.
+  num_async_histogram_fetches_in_progress_ = 1;
+#else  // OS_ANDROID
+  num_async_histogram_fetches_in_progress_ = 2;
+  // Run requests to service and content in parallel.
+  if (!ServiceProcessControl::GetInstance()->GetHistograms(callback, timeout)) {
+    // Assume |num_async_histogram_fetches_in_progress_| is not changed by
+    // |GetHistograms()|.
+    DCHECK_EQ(num_async_histogram_fetches_in_progress_, 2);
+    // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
+    // here to make code work even if |GetHistograms()| fired |callback|.
+    --num_async_histogram_fetches_in_progress_;
+  }
+#endif  // OS_ANDROID
+
   // Set up the callback to task to call after we receive histograms from all
   // child processes. Wait time specifies how long to wait before absolutely
   // calling us back on the task.
-  content::FetchHistogramsAsynchronously(
-      base::MessageLoop::current(), callback,
-      base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration));
+  content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback,
+                                         timeout);
 }
 
 void MetricsService::OnHistogramSynchronizationDone() {
@@ -1319,6 +1361,11 @@
   // This function should only be called as the callback from an ansynchronous
   // step.
   DCHECK(waiting_for_asynchronous_reporting_step_);
+  DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
+
+  // Check if all expected requests finished.
+  if (--num_async_histogram_fetches_in_progress_ > 0)
+    return;
 
   waiting_for_asynchronous_reporting_step_ = false;
   OnFinalLogInfoCollectionDone();
@@ -1640,6 +1687,9 @@
   clean_shutdown_status_ = CLEANLY_SHUTDOWN;
 
   RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
+  PrefService* pref = g_browser_process->local_state();
+  pref->SetInteger(prefs::kStabilityExecutionPhase,
+                   MetricsService::CLEAN_SHUTDOWN);
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index a827a7e..6dd2885 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -74,6 +74,17 @@
       public net::URLFetcherDelegate,
       public MetricsServiceBase {
  public:
+  // The execution phase of the browser.
+  enum ExecutionPhase {
+    CLEAN_SHUTDOWN = 0,
+    START_METRICS_RECORDING = 100,
+    CREATE_PROFILE = 200,
+    STARTUP_TIMEBOMB_ARM = 300,
+    THREAD_WATCHER_START = 400,
+    MAIN_MESSAGE_LOOP_RUN = 500,
+    SHUTDOWN_TIMEBOMB_ARM = 600,
+  };
+
   MetricsService();
   virtual ~MetricsService();
 
@@ -164,6 +175,9 @@
   static void LogNeedForCleanShutdown();
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
+  static void SetExecutionPhase(ExecutionPhase execution_phase) {
+    execution_phase_ = execution_phase;
+  }
   // Saves in the preferences if the crash report registration was successful.
   // This count is eventually send via UMA logs.
   void RecordBreakpadRegistration(bool success);
@@ -481,6 +495,9 @@
   // This is used only for debugging.
   bool waiting_for_asynchronous_reporting_step_;
 
+  // Number of async histogram fetch requests in progress.
+  int num_async_histogram_fetches_in_progress_;
+
 #if defined(OS_CHROMEOS)
   // The external metric service is used to log ChromeOS UMA events.
   scoped_refptr<chromeos::ExternalMetrics> external_metrics_;
@@ -492,6 +509,9 @@
   // Stores the time of the last call to |GetIncrementalUptime()|.
   base::TimeTicks last_updated_time_;
 
+  // Execution phase the browser is in.
+  static ExecutionPhase execution_phase_;
+
   // Reduntant marker to check that we completed our shutdown, and set the
   // exited-cleanly bit in the prefs.
   static ShutdownCleanliness clean_shutdown_status_;
diff --git a/chrome/browser/metro_viewer/DEPS b/chrome/browser/metro_viewer/DEPS
new file mode 100644
index 0000000..4199b39
--- /dev/null
+++ b/chrome/browser/metro_viewer/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+win8/viewer",
+]
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index b561432..6fd1b94 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -11,12 +11,10 @@
 #include "base/path_service.h"
 #include "base/pickle.h"
 #include "base/rand_util.h"
-#include "base/strings/string_split.h"
 #include "base/time/time.h"
 #include "base/win/windows_version.h"
 #include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/common/url_pattern.h"
 #include "url/gurl.h"
 
 namespace {
@@ -158,8 +156,6 @@
       irt_platform_file_(base::kInvalidPlatformFileValue),
       irt_filepath_(),
       irt_state_(NaClResourceUninitialized),
-      debug_patterns_(),
-      inverse_debug_patterns_(false),
       validation_cache_file_path_(),
       validation_cache_is_enabled_(
           CheckEnvVar("NACL_VALIDATION_CACHE",
@@ -292,50 +288,6 @@
   CheckWaiting();
 }
 
-void NaClBrowser::SetDebugPatterns(std::string debug_patterns) {
-  if (!debug_patterns.empty() && debug_patterns[0] == '!') {
-    inverse_debug_patterns_ = true;
-    debug_patterns.erase(0, 1);
-  }
-  if (debug_patterns.empty()) {
-    return;
-  }
-  std::vector<std::string> patterns;
-  base::SplitString(debug_patterns, ',', &patterns);
-  for (std::vector<std::string>::iterator iter = patterns.begin();
-       iter != patterns.end(); ++iter) {
-    URLPattern pattern;
-    if (pattern.Parse(*iter) == URLPattern::PARSE_SUCCESS) {
-      // If URL pattern has scheme equal to *, Parse method resets valid
-      // schemes mask to http and https only, so we need to reset it after
-      // Parse to include chrome-extension scheme that can be used by NaCl
-      // manifest files.
-      pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
-      debug_patterns_.push_back(pattern);
-    }
-  }
-}
-
-bool NaClBrowser::URLMatchesDebugPatterns(GURL manifest_url) {
-  // Empty patterns are forbidden so we ignore them.
-  if (debug_patterns_.empty()) {
-    return true;
-  }
-  bool matches = false;
-  for (std::vector<URLPattern>::iterator iter = debug_patterns_.begin();
-       iter != debug_patterns_.end(); ++iter) {
-    if (iter->MatchesURL(manifest_url)) {
-      matches = true;
-      break;
-    }
-  }
-  if (inverse_debug_patterns_) {
-    return !matches;
-  } else {
-    return matches;
-  }
-}
-
 void NaClBrowser::FireGdbDebugStubPortOpened(int port) {
   content::BrowserThread::PostTask(
       content::BrowserThread::IO,
diff --git a/chrome/browser/nacl_host/nacl_browser.h b/chrome/browser/nacl_host/nacl_browser.h
index 14263b7..48a64f1 100644
--- a/chrome/browser/nacl_host/nacl_browser.h
+++ b/chrome/browser/nacl_host/nacl_browser.h
@@ -60,12 +60,6 @@
   // IRT file handle, only available when IsReady().
   base::PlatformFile IrtFile() const;
 
-  // Set match patterns which will be checked before enabling debug stub.
-  void SetDebugPatterns(std::string debug_patterns);
-
-  // Returns whether NaCl application with this manifest URL should be debugged.
-  bool URLMatchesDebugPatterns(GURL manifest_url);
-
   // Methods for testing GDB debug stub in browser. If test adds debug stub
   // port listener, Chrome will allocate a currently-unused TCP port number for
   // debug stub server instead of a fixed one.
@@ -169,8 +163,6 @@
   base::PlatformFile irt_platform_file_;
   base::FilePath irt_filepath_;
   NaClResourceState irt_state_;
-  std::vector<URLPattern> debug_patterns_;
-  bool inverse_debug_patterns_;
   NaClValidationCache validation_cache_;
   NaClValidationCache off_the_record_validation_cache_;
   base::FilePath validation_cache_file_path_;
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
index 558c53e..b31daad 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
 
 #include "base/path_service.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
@@ -20,13 +21,15 @@
 #include "chrome/common/logging_chrome.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/url_pattern.h"
 #include "ppapi/c/private/ppb_nacl_private.h"
 
 using extensions::SharedModuleInfo;
 
 NaClBrowserDelegateImpl::NaClBrowserDelegateImpl(
     ExtensionInfoMap* extension_info_map)
-    : extension_info_map_(extension_info_map) {
+    : extension_info_map_(extension_info_map),
+      inverse_debug_patterns_(false) {
 }
 
 NaClBrowserDelegateImpl::~NaClBrowserDelegateImpl() {
@@ -85,6 +88,51 @@
     installed.Run(false);
 }
 
+void NaClBrowserDelegateImpl::SetDebugPatterns(std::string debug_patterns) {
+  if (!debug_patterns.empty() && debug_patterns[0] == '!') {
+    inverse_debug_patterns_ = true;
+    debug_patterns.erase(0, 1);
+  }
+  if (debug_patterns.empty()) {
+    return;
+  }
+  std::vector<std::string> patterns;
+  base::SplitString(debug_patterns, ',', &patterns);
+  for (std::vector<std::string>::iterator iter = patterns.begin();
+       iter != patterns.end(); ++iter) {
+    URLPattern pattern;
+    if (pattern.Parse(*iter) == URLPattern::PARSE_SUCCESS) {
+      // If URL pattern has scheme equal to *, Parse method resets valid
+      // schemes mask to http and https only, so we need to reset it after
+      // Parse to include chrome-extension scheme that can be used by NaCl
+      // manifest files.
+      pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
+      debug_patterns_.push_back(pattern);
+    }
+  }
+}
+
+bool NaClBrowserDelegateImpl::URLMatchesDebugPatterns(
+    const GURL& manifest_url) {
+  // Empty patterns are forbidden so we ignore them.
+  if (debug_patterns_.empty()) {
+    return true;
+  }
+  bool matches = false;
+  for (std::vector<URLPattern>::iterator iter = debug_patterns_.begin();
+       iter != debug_patterns_.end(); ++iter) {
+    if (iter->MatchesURL(manifest_url)) {
+      matches = true;
+      break;
+    }
+  }
+  if (inverse_debug_patterns_) {
+    return !matches;
+  } else {
+    return matches;
+  }
+}
+
 // This function is security sensitive.  Be sure to check with a security
 // person before you modify it.
 bool NaClBrowserDelegateImpl::MapUrlToLocalFilePath(
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
index e71fbdd..a91a35b 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
@@ -29,9 +29,13 @@
   virtual bool MapUrlToLocalFilePath(const GURL& url,
                                      bool is_blocking,
                                      base::FilePath* file_path) OVERRIDE;
+  virtual void SetDebugPatterns(std::string debug_patterns) OVERRIDE;
+  virtual bool URLMatchesDebugPatterns(const GURL& manifest_url) OVERRIDE;
 
  private:
   scoped_refptr<ExtensionInfoMap> extension_info_map_;
+  std::vector<URLPattern> debug_patterns_;
+  bool inverse_debug_patterns_;
   DISALLOW_COPY_AND_ASSIGN(NaClBrowserDelegateImpl);
 };
 
diff --git a/chrome/browser/nacl_host/nacl_file_host_unittest.cc b/chrome/browser/nacl_host/nacl_file_host_unittest.cc
index 8d74850..886c5c0 100644
--- a/chrome/browser/nacl_host/nacl_file_host_unittest.cc
+++ b/chrome/browser/nacl_host/nacl_file_host_unittest.cc
@@ -66,6 +66,13 @@
     return false;
   }
 
+  virtual void SetDebugPatterns(std::string debug_patterns) OVERRIDE {
+  }
+
+  virtual bool URLMatchesDebugPatterns(const GURL& manifest_url) OVERRIDE {
+    return false;
+  }
+
   virtual void TryInstallPnacl(
       const base::Callback<void(bool)>& installed) OVERRIDE {
     installed.Run(should_pnacl_install_succeed_);
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 68e5fd7..3201c14 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -329,7 +329,7 @@
   UMA_HISTOGRAM_BOOLEAN(
       "NaCl.enable-nacl-debug",
       cmd->HasSwitch(switches::kEnableNaClDebug));
-  NaClBrowser::GetInstance()->SetDebugPatterns(
+  NaClBrowser::GetDelegate()->SetDebugPatterns(
       cmd->GetSwitchValueASCII(switches::kNaClDebugMask));
 }
 
@@ -701,7 +701,7 @@
   params.version = NaClBrowser::GetDelegate()->GetVersionString();
   params.enable_exception_handling = enable_exception_handling_;
   params.enable_debug_stub = enable_debug_stub_ &&
-      NaClBrowser::GetInstance()->URLMatchesDebugPatterns(manifest_url_);
+      NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(manifest_url_);
   // Enable PPAPI proxy channel creation only for renderer processes.
   params.enable_ipc_proxy = enable_ppapi_proxy();
   params.uses_irt = uses_irt_;
diff --git a/chrome/browser/nacl_host/pnacl_host.cc b/chrome/browser/nacl_host/pnacl_host.cc
index 924f679..8230c60 100644
--- a/chrome/browser/nacl_host/pnacl_host.cc
+++ b/chrome/browser/nacl_host/pnacl_host.cc
@@ -27,9 +27,16 @@
 }
 
 PnaclHost::PnaclHost()
-    : cache_state_(CacheUninitialized), weak_factory_(this) {}
+    : pending_backend_operations_(0),
+      cache_state_(CacheUninitialized),
+      weak_factory_(this) {}
 
-PnaclHost::~PnaclHost() {}
+PnaclHost::~PnaclHost() {
+  // When PnaclHost is destroyed, it's too late to post anything to the cache
+  // thread (it will hang shutdown). So just leak the cache backend.
+  pnacl::PnaclTranslationCache* cache = disk_cache_.release();
+  (void)cache;
+}
 
 PnaclHost* PnaclHost::GetInstance() { return Singleton<PnaclHost>::get(); }
 
@@ -96,9 +103,11 @@
     return;
   disk_cache_.reset(new pnacl::PnaclTranslationCache());
   cache_state_ = CacheInitializing;
-  disk_cache_->InitOnDisk(
+  int rv = disk_cache_->InitOnDisk(
       cache_path,
       base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
+  if (rv != net::ERR_IO_PENDING)
+    OnCacheInitialized(rv);
 }
 
 // Initialize using the in-memory backend, and manually set the temporary file
@@ -108,8 +117,10 @@
   disk_cache_.reset(new pnacl::PnaclTranslationCache());
   cache_state_ = CacheInitializing;
   temp_dir_ = temp_dir;
-  disk_cache_->InitInMemory(
+  int rv = disk_cache_->InitInMemory(
       base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
+  if (rv != net::ERR_IO_PENDING)
+    OnCacheInitialized(rv);
 }
 
 ///////////////////////////////////////// Temp files
@@ -216,6 +227,7 @@
 // request hits.
 void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key,
                                                  const TranslationID& id) {
+  pending_backend_operations_++;
   disk_cache_->GetNexe(
       cache_key,
       base::Bind(
@@ -236,9 +248,11 @@
     int net_error,
     scoped_refptr<net::DrainableIOBuffer> buffer) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  pending_backend_operations_--;
   PendingTranslationMap::iterator entry(pending_translations_.find(id));
   if (entry == pending_translations_.end()) {
     LOG(ERROR) << "OnCacheQueryReturn: id not found";
+    DeInitIfSafe();
     return;
   }
   PendingTranslation* pt = &entry->second;
@@ -433,7 +447,7 @@
     LOG(ERROR) << "Error reading translated nexe";
     return;
   }
-
+  pending_backend_operations_++;
   disk_cache_->StoreNexe(it->second.cache_key,
                          buffer,
                          base::Bind(&PnaclHost::OnTranslatedNexeStored,
@@ -447,7 +461,11 @@
 // could be cancelled before they get called).
 void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) {
   PendingTranslationMap::iterator entry(pending_translations_.find(id));
+  pending_backend_operations_--;
   if (entry == pending_translations_.end()) {
+    // If the renderer closed while we were storing the nexe, we land here.
+    // Make sure we try to de-init.
+    DeInitIfSafe();
     return;
   }
   std::string key(entry->second.cache_key);
@@ -467,6 +485,7 @@
       // Re-send the cache read request. This time we expect a hit, but if
       // something goes wrong, it will just handle it like a miss.
       it->second.got_cache_reply = false;
+      pending_backend_operations_++;
       disk_cache_->GetNexe(key,
                            base::Bind(&PnaclHost::OnCacheQueryReturn,
                                       weak_factory_.GetWeakPtr(),
@@ -535,12 +554,10 @@
         RequeryMatchingTranslations(key);
     }
   }
-  if (pending_translations_.empty()) {
-    cache_state_ = CacheUninitialized;
-    // Freeing the backend causes it to flush to disk, so do it when the
-    // last renderer closes rather than on destruction.
-    disk_cache_.reset();
-  }
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
 }
 
 ////////////////// Cache data removal
@@ -566,15 +583,48 @@
             kTranslationCacheInitializationDelayMs));
     return;
   }
+  pending_backend_operations_++;
   int rv = disk_cache_->DoomEntriesBetween(
       initial_time,
       end_time,
-      base::Bind(&PnaclHost::OnEntriesDoomed, callback));
+      base::Bind(
+          &PnaclHost::OnEntriesDoomed, weak_factory_.GetWeakPtr(), callback));
   if (rv != net::ERR_IO_PENDING)
     OnEntriesDoomed(callback, rv);
 }
 
-// static
 void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
+  pending_backend_operations_--;
+  // When clearing the cache, the UI is blocked on all the cache-clearing
+  // operations, and freeing the backend actually blocks the IO thread. So
+  // instead of calling DeInitIfSafe directly, post it for later.
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
+}
+
+// Destroying the cache backend causes it to post tasks to the cache thread to
+// flush to disk. Because PnaclHost is a singleton, it does not get destroyed
+// until all the browser threads have gone away and it's too late to post
+// anything (attempting to do so hangs shutdown).  So we make sure to destroy it
+// when we no longer have any outstanding operations that need it. These include
+// pending translations, cache clear requests, and requests to read or write
+// translated nexes.  We check when renderers close, when cache clear requests
+// finish, and when backend operations complete.
+
+// It is not safe to delete the backend while it is initializing, nor if it has
+// outstanding entry open requests; it is in theory safe to delete it with
+// outstanding read/write requests, but because that distinction is hidden
+// inside PnaclTranslationCache, we do not delete the backend if there are any
+// backend requests in flight.  As a last resort in the destructor, we just leak
+// the backend to avoid hanging shutdown.
+void PnaclHost::DeInitIfSafe() {
+  DCHECK(pending_backend_operations_ >= 0);
+  if (pending_translations_.empty() && pending_backend_operations_ <= 0) {
+    cache_state_ = CacheUninitialized;
+    disk_cache_.reset();
+  }
 }
diff --git a/chrome/browser/nacl_host/pnacl_host.h b/chrome/browser/nacl_host/pnacl_host.h
index 91553f4..782499f 100644
--- a/chrome/browser/nacl_host/pnacl_host.h
+++ b/chrome/browser/nacl_host/pnacl_host.h
@@ -157,8 +157,13 @@
                               scoped_refptr<net::DrainableIOBuffer> buffer);
   void OnBufferCopiedToTempFile(const TranslationID& id, int file_error);
 
-  static void OnEntriesDoomed(const base::Closure& callback, int net_error);
+  void OnEntriesDoomed(const base::Closure& callback, int net_error);
 
+  void DeInitIfSafe();
+
+  // Operations which are pending with the cache backend, which we should
+  // wait for before destroying it (see comment on DeInitIfSafe).
+  int pending_backend_operations_;
   CacheState cache_state_;
   base::FilePath temp_dir_;
   scoped_ptr<pnacl::PnaclTranslationCache> disk_cache_;
diff --git a/chrome/browser/nacl_host/pnacl_host_unittest.cc b/chrome/browser/nacl_host/pnacl_host_unittest.cc
index fc26d1a..df4a32d 100644
--- a/chrome/browser/nacl_host/pnacl_host_unittest.cc
+++ b/chrome/browser/nacl_host/pnacl_host_unittest.cc
@@ -32,10 +32,15 @@
     host_ = new PnaclHost();
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     host_->InitForTest(temp_dir_.path());
-    EXPECT_EQ(host_->cache_state_, PnaclHost::CacheReady);
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(PnaclHost::CacheReady, host_->cache_state_);
   }
   virtual void TearDown() {
     EXPECT_EQ(0U, host_->pending_translations());
+    // Give the host a chance to de-init the backend, and then delete it.
+    host_->RendererClosing(0);
+    FlushQueues();
+    EXPECT_EQ(PnaclHost::CacheUninitialized, host_->cache_state_);
     delete host_;
   }
   // Flush the blocking pool first, then any tasks it posted to the IO thread.
@@ -48,6 +53,14 @@
     base::RunLoop().RunUntilIdle();
   }
   int GetCacheSize() { return host_->disk_cache_->Size(); }
+  int CacheIsInitialized() {
+    return host_->cache_state_ == PnaclHost::CacheReady;
+  }
+  void ReInitBackend() {
+    host_->InitForTest(temp_dir_.path());
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(PnaclHost::CacheReady, host_->cache_state_);
+  }
 
  public:  // Required for derived classes to bind this method
           // Callbacks used by tests which call GetNexeFd.
@@ -133,6 +146,9 @@
   EXPECT_EQ(2, temp_callback_count_);
   EXPECT_EQ(1U, host_->pending_translations());
   host_->RendererClosing(0);
+  FlushQueues();
+  // Check that the cache has de-initialized after the last renderer goes away.
+  EXPECT_FALSE(CacheIsInitialized());
 }
 
 TEST_F(PnaclHostTest, BadArguments) {
@@ -169,6 +185,10 @@
   FlushQueues();
   EXPECT_EQ(0U, host_->pending_translations());
   EXPECT_EQ(0, temp_callback_count_);
+  // The backend will have been freed when the query comes back and there
+  // are no pending translations.
+  EXPECT_FALSE(CacheIsInitialized());
+  ReInitBackend();
   // Check that another request for the same info misses successfully.
   GET_NEXE_FD(0, 0, false, info, false);
   FlushQueues();
@@ -401,10 +421,12 @@
   // Since we are using a memory backend, the clear should happen immediately.
   host_->ClearTranslationCacheEntriesBetween(
       base::Time(), base::Time(), base::Bind(cb.callback(), 0));
-  EXPECT_EQ(0, cb.GetResult(net::ERR_IO_PENDING));
-  // Check that the translation cache has been cleared
+  // Check that the translation cache has been cleared before flushing the
+  // queues, because the backend will be freed once it is.
   EXPECT_EQ(0, GetCacheSize());
-  host_->RendererClosing(0);
+  EXPECT_EQ(0, cb.GetResult(net::ERR_IO_PENDING));
+  // Now check that the backend has been freed.
+  EXPECT_FALSE(CacheIsInitialized());
 }
 
 }  // namespace pnacl
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.cc b/chrome/browser/nacl_host/pnacl_translation_cache.cc
index e3c8c20..5635479 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache.cc
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -67,7 +68,8 @@
     OPEN_ENTRY,
     CREATE_ENTRY,
     TRANSFER_ENTRY,
-    CLOSE_ENTRY
+    CLOSE_ENTRY,
+    FINISHED
   };
 
  private:
@@ -142,8 +144,21 @@
 
 PnaclTranslationCacheEntry::~PnaclTranslationCacheEntry() {
   // Ensure we have called the user's callback
-  DCHECK(read_callback_.is_null());
-  DCHECK(write_callback_.is_null());
+  if (step_ != FINISHED) {
+    if (!read_callback_.is_null()) {
+      BrowserThread::PostTask(
+          BrowserThread::IO,
+          FROM_HERE,
+          base::Bind(read_callback_,
+                     net::ERR_ABORTED,
+                     scoped_refptr<net::DrainableIOBuffer>()));
+    }
+    if (!write_callback_.is_null()) {
+      BrowserThread::PostTask(BrowserThread::IO,
+                              FROM_HERE,
+                              base::Bind(write_callback_, net::ERR_ABORTED));
+    }
+  }
 }
 
 void PnaclTranslationCacheEntry::Start() {
@@ -208,15 +223,17 @@
 }
 
 void PnaclTranslationCacheEntry::Finish(int rv) {
+  step_ = FINISHED;
   if (is_read_) {
     if (!read_callback_.is_null()) {
-      read_callback_.Run(rv, io_buf_);
-      read_callback_.Reset();
+      BrowserThread::PostTask(BrowserThread::IO,
+                              FROM_HERE,
+                              base::Bind(read_callback_, rv, io_buf_));
     }
   } else {
     if (!write_callback_.is_null()) {
-      write_callback_.Run(rv);
-      write_callback_.Reset();
+      BrowserThread::PostTask(
+          BrowserThread::IO, FROM_HERE, base::Bind(write_callback_, rv));
     }
   }
   cache_->OpComplete(this);
@@ -229,6 +246,7 @@
 
   switch (step_) {
     case UNINITIALIZED:
+    case FINISHED:
       LOG(ERROR) << "DispatchNext called uninitialized";
       break;
 
@@ -273,8 +291,8 @@
       if (rv < 0) {
         // We do not call DispatchNext directly if WriteEntry/ReadEntry returns
         // ERR_IO_PENDING, and the callback should not return that value either.
-        LOG(ERROR)
-            << "Failed to complete write to entry: " << net::ErrorToString(rv);
+        LOG(ERROR) << "Failed to complete write to entry: "
+                   << net::ErrorToString(rv);
         step_ = CLOSE_ENTRY;
         CloseEntry(rv);
         break;
@@ -326,9 +344,8 @@
       NULL, /* dummy net log */
       &disk_cache_,
       base::Bind(&PnaclTranslationCache::OnCreateBackendComplete, AsWeakPtr()));
-  init_callback_ = callback;
-  if (rv != net::ERR_IO_PENDING) {
-    OnCreateBackendComplete(rv);
+  if (rv == net::ERR_IO_PENDING) {
+    init_callback_ = callback;
   }
   return rv;
 }
@@ -339,8 +356,8 @@
   }
   // Invoke our client's callback function.
   if (!init_callback_.is_null()) {
-    init_callback_.Run(rv);
-    init_callback_.Reset();
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE, base::Bind(init_callback_, rv));
   }
 }
 
@@ -348,11 +365,6 @@
 // High-level API
 
 void PnaclTranslationCache::StoreNexe(const std::string& key,
-                                      net::DrainableIOBuffer* nexe_data) {
-  StoreNexe(key, nexe_data, CompletionCallback());
-}
-
-void PnaclTranslationCache::StoreNexe(const std::string& key,
                                       net::DrainableIOBuffer* nexe_data,
                                       const CompletionCallback& callback) {
   PnaclTranslationCacheEntry* entry = PnaclTranslationCacheEntry::GetWriteEntry(
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.h b/chrome/browser/nacl_host/pnacl_translation_cache.h
index 2baa53a..7ca4bcc 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache.h
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.h
@@ -42,19 +42,17 @@
   PnaclTranslationCache();
   virtual ~PnaclTranslationCache();
 
-  // Initialize the translation cache in |cache_dir|.
-  // Call |callback| with a 0 argument on sucess and <0 otherwise.
+  // Initialize the translation cache in |cache_dir|.  If the return value is
+  // net::ERR_IO_PENDING, |callback| will be called with a 0 argument on sucess
+  // and <0 otherwise.
   int InitOnDisk(const base::FilePath& cache_dir,
                  const CompletionCallback& callback);
 
-  // Initialize the translation cache in memory.
-  // Call |callback| with a 0 argument on sucess and <0 otherwise.
+  // Initialize the translation cache in memory.  If the return value is
+  // net::ERR_IO_PENDING, |callback| will be called with a 0 argument on sucess
+  // and <0 otherwise.
   int InitInMemory(const CompletionCallback& callback);
 
-  // Store the nexe in the translation cache. A reference to |nexe_data| is
-  // held until completion or cancellation.
-  void StoreNexe(const std::string& key, net::DrainableIOBuffer* nexe_data);
-
   // Store the nexe in the translation cache, and call |callback| with
   // the result. The result passed to the callback is 0 on success and
   // <0 otherwise. A reference to |nexe_data| is held until completion
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc b/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
index df98b3d..adcdd35 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
+++ b/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
@@ -27,7 +27,7 @@
   PnaclTranslationCacheTest()
       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
   virtual ~PnaclTranslationCacheTest() {}
-  virtual void SetUp() { cache_ = new PnaclTranslationCache(); }
+  virtual void SetUp() { cache_.reset(new PnaclTranslationCache()); }
   virtual void TearDown() {
     // The destructor of PnaclTranslationCacheWriteEntry posts a task to the IO
     // thread to close the backend cache entry. We want to make sure the entries
@@ -35,14 +35,14 @@
     // for the memory backend has a DCHECK to verify this), so we run the loop
     // here to ensure the task gets processed.
     base::RunLoop().RunUntilIdle();
-    delete cache_;
+    cache_.reset();
   }
 
   void InitBackend(bool in_mem);
   void StoreNexe(const std::string& key, const std::string& nexe);
   std::string GetNexe(const std::string& key);
 
-  PnaclTranslationCache* cache_;
+  scoped_ptr<PnaclTranslationCache> cache_;
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
 };
diff --git a/chrome/browser/net/chrome_network_data_saving_metrics.cc b/chrome/browser/net/chrome_network_data_saving_metrics.cc
index 656cc2a..6a71b77 100644
--- a/chrome/browser/net/chrome_network_data_saving_metrics.cc
+++ b/chrome/browser/net/chrome_network_data_saving_metrics.cc
@@ -6,8 +6,8 @@
 
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
diff --git a/chrome/browser/net/chrome_network_data_saving_metrics_unittest.cc b/chrome/browser/net/chrome_network_data_saving_metrics_unittest.cc
index 5a975b0..c4045a1 100644
--- a/chrome/browser/net/chrome_network_data_saving_metrics_unittest.cc
+++ b/chrome/browser/net/chrome_network_data_saving_metrics_unittest.cc
@@ -6,10 +6,10 @@
 #include "base/compiler_specific.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/net/chrome_network_data_saving_metrics.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 230b40b..4ec5a80 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -458,7 +458,7 @@
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
-  TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request, "SendRequest");
+  TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request, "SendRequest");
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
       profile_, extension_info_map_.get(), request, callback, headers);
 }
@@ -488,7 +488,7 @@
 
 
 void ChromeNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
-  TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request, "ResponseStarted");
+  TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request, "ResponseStarted");
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
       profile_, extension_info_map_.get(), request);
   ForwardProxyErrors(request, event_router_.get(), profile_);
@@ -496,8 +496,8 @@
 
 void ChromeNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
                                            int bytes_read) {
-  TRACE_EVENT_ASYNC_STEP1("net", "URLRequest", &request, "DidRead",
-                          "bytes_read", bytes_read);
+  TRACE_EVENT_ASYNC_STEP_PAST1("net", "URLRequest", &request, "DidRead",
+                               "bytes_read", bytes_read);
   performance_monitor::PerformanceMonitor::GetInstance()->BytesReadOnIOThread(
       request, bytes_read);
 
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index c12c5e3..ddb6afb 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -16,6 +16,7 @@
 #include "base/containers/mru_cache.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -26,7 +27,6 @@
 #include "base/values.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/net/preconnect.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/net/proxy_policy_handler_unittest.cc b/chrome/browser/net/proxy_policy_handler_unittest.cc
index 4ff300a..7224fca 100644
--- a/chrome/browser/net/proxy_policy_handler_unittest.cc
+++ b/chrome/browser/net/proxy_policy_handler_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/net/proxy_policy_handler.h"
 #include "chrome/browser/policy/configuration_policy_pref_store.h"
@@ -19,6 +20,12 @@
 // Test cases for the proxy policy settings.
 class ProxyPolicyHandlerTest
     : public ConfigurationPolicyPrefStoreTest {
+ public:
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new ProxyPolicyHandler));
+  }
+
  protected:
   // Verify that all the proxy prefs are set to the specified expected values.
   void VerifyProxyPrefs(
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc
index 4318d77..bafff52 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc
@@ -10,20 +10,25 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/proxy_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
+#include "crypto/random.h"
+#include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_auth_cache.h"
+#include "net/http/http_network_session.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_status.h"
@@ -47,6 +52,10 @@
 
 const char kEnabled[] = "Enabled";
 
+// TODO(marq): Factor this string out into a constant here and in
+//             http_auth_handler_spdyproxy.
+const char kAuthenticationRealmName[] = "SpdyProxy";
+
 int64 GetInt64PrefValue(const ListValue& list_value, size_t index) {
   int64 val = 0;
   std::string pref_value;
@@ -59,6 +68,11 @@
   return val;
 }
 
+bool IsProxyOriginSetOnCommandLine() {
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin);
+}
+
 }  // namespace
 
 DataReductionProxySettings::DataReductionProxySettings()
@@ -82,12 +96,12 @@
 }
 
 void DataReductionProxySettings::InitDataReductionProxySettings() {
+  InitPrefMembers();
+
   // Disable the proxy if it is not allowed to be used.
   if (!IsDataReductionProxyAllowed())
     return;
 
-  InitPrefMembers();
-
   AddDefaultProxyBypassRules();
   net::NetworkChangeNotifier::AddIPAddressObserver(this);
 
@@ -107,6 +121,54 @@
   }
 }
 
+void DataReductionProxySettings::InitDataReductionProxySession(
+    net::HttpNetworkSession* session) {
+// This is a no-op unless the authentication parameters are compiled in.
+// (even though values for them may be specified on the command line).
+// Authentication will still work if the command line parameters are used,
+// however there will be a round-trip overhead for each challenge/response
+// (typically once per session).
+#if defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE)
+  DCHECK(session);
+  net::HttpAuthCache* auth_cache = session->http_auth_cache();
+  DCHECK(auth_cache);
+  InitDataReductionAuthentication(auth_cache);
+#endif  // defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE)
+}
+
+void DataReductionProxySettings::InitDataReductionAuthentication(
+    net::HttpAuthCache* auth_cache) {
+  DCHECK(auth_cache);
+  int64 timestamp =
+      (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000;
+
+  DataReductionProxyList proxies = GetDataReductionProxies();
+  for (DataReductionProxyList::iterator it = proxies.begin();
+      it != proxies.end(); ++it) {
+    GURL auth_origin = (*it).GetOrigin();
+    int32 rand[3];
+    crypto::RandBytes(rand, 3 * sizeof(rand[0]));
+
+    std::string realm =
+        base::StringPrintf("%s%lld", kAuthenticationRealmName, timestamp);
+    std::string challenge = base::StringPrintf(
+        "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"", kAuthenticationRealmName,
+        realm.data(), timestamp, rand[0], rand[1], rand[2]);
+    base::string16 password = AuthHashForSalt(timestamp);
+
+    DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm
+        << "] challenge: [" << challenge << "] password: [" << password << "]";
+
+    net::AuthCredentials credentials(base::string16(), password);
+    auth_cache->Add(auth_origin,
+                    realm,
+                    net::HttpAuth::AUTH_SCHEME_SPDYPROXY,
+                    challenge,
+                    credentials,
+                    std::string()); // Proxy auth uses an empty path for lookup.
+  }
+}
+
 void DataReductionProxySettings::AddHostPatternToBypass(
     const std::string& pattern) {
   bypass_rules_.push_back(pattern);
@@ -150,26 +212,58 @@
 #endif
 }
 
-std::string DataReductionProxySettings::GetDataReductionProxyAuth() {
-  if (!IsDataReductionProxyAllowed())
+std::string DataReductionProxySettings::GetDataReductionProxyFallback() {
+  // Regardless of what else is defined, only return a value if the main proxy
+  // origin is defined.
+  if (GetDataReductionProxyOrigin().empty())
     return std::string();
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
-    // If an origin is provided via a switch, then only consider the value
-    // that is provided by a switch. Do not use the preprocessor constant.
-    // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command
-    // line.
-    if (command_line.HasSwitch(switches::kSpdyProxyAuthValue))
-      return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue);
-    return std::string();
-  }
-#if defined(SPDY_PROXY_AUTH_VALUE)
-  return SPDY_PROXY_AUTH_VALUE;
+  if (command_line.HasSwitch(switches::kSpdyProxyAuthFallback))
+    return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthFallback);
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+  return DATA_REDUCTION_FALLBACK_HOST;
 #else
   return std::string();
 #endif
 }
 
+bool DataReductionProxySettings::IsAcceptableAuthChallenge(
+    net::AuthChallengeInfo* auth_info) {
+  // Challenge realm must start with the authentication realm name.
+  std::string realm_prefix =
+      auth_info->realm.substr(0, strlen(kAuthenticationRealmName));
+  if (realm_prefix != kAuthenticationRealmName)
+    return false;
+
+  // The challenger must be one of the configured proxies.
+  DataReductionProxyList proxies = GetDataReductionProxies();
+  for (DataReductionProxyList::iterator it = proxies.begin();
+       it != proxies.end(); ++it) {
+    net::HostPortPair origin_host = net::HostPortPair::FromURL(*it);
+    if (origin_host.Equals(auth_info->challenger))
+      return true;
+  }
+  return false;
+}
+
+base::string16 DataReductionProxySettings::GetTokenForAuthChallenge(
+    net::AuthChallengeInfo* auth_info) {
+  if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) {
+    int64 salt;
+    std::string realm_suffix =
+        auth_info->realm.substr(strlen(kAuthenticationRealmName));
+    if (base::StringToInt64(realm_suffix, &salt)) {
+      return AuthHashForSalt(salt);
+    } else {
+      DVLOG(1) << "Unable to parse realm name " << auth_info->realm
+               << "into an int for salting.";
+      return base::string16();
+    }
+  } else {
+    return base::string16();
+  }
+}
+
 bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
   return spdy_proxy_auth_enabled_.GetValue();
 }
@@ -178,6 +272,24 @@
   return spdy_proxy_auth_enabled_.IsManaged();
 }
 
+DataReductionProxySettings::DataReductionProxyList
+DataReductionProxySettings::GetDataReductionProxies() {
+  DataReductionProxyList proxies;
+  std::string proxy = GetDataReductionProxyOrigin();
+  std::string fallback = GetDataReductionProxyFallback();
+
+  if (!proxy.empty())
+    proxies.push_back(GURL(proxy));
+
+  if (!fallback.empty()) {
+    // Sanity check: fallback isn't the only proxy.
+    DCHECK(!proxies.empty());
+    proxies.push_back(GURL(fallback));
+  }
+
+  return proxies;
+}
+
 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
   // Prevent configuring the proxy when it is not allowed to be used.
   if (!IsDataReductionProxyAllowed())
@@ -195,12 +307,12 @@
   return static_cast<int64>(last_update.ToJsTime());
 }
 
-std::vector<long long>
+DataReductionProxySettings::ContentLengthList
 DataReductionProxySettings::GetDailyOriginalContentLengths() {
   return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
 }
 
-std::vector<long long>
+DataReductionProxySettings::ContentLengthList
 DataReductionProxySettings::GetDailyReceivedContentLengths() {
   return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength);
 }
@@ -237,17 +349,6 @@
   disabled_by_carrier_ = true;
 }
 
-std::string DataReductionProxySettings::GetDataReductionProxyOriginHostPort() {
-  std::string spdy_proxy = GetDataReductionProxyOrigin();
-  if (spdy_proxy.empty()) {
-    DLOG(ERROR) << "A SPDY proxy has not been set.";
-    return spdy_proxy;
-  }
-  // Remove a trailing slash from the proxy string if one exists as well as
-  // leading HTTPS scheme.
-  return net::HostPortPair::FromURL(GURL(spdy_proxy)).ToString();
-}
-
 void DataReductionProxySettings::OnIPAddressChanged() {
   if (enabled_by_user_) {
     DCHECK(IsDataReductionProxyAllowed());
@@ -256,7 +357,7 @@
 }
 
 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
-  if (!IsDataReductionProxyAllowed())
+  if (!DataReductionProxySettings::IsDataReductionProxyAllowed())
     return;
   MaybeActivateDataReductionProxy(false);
 }
@@ -293,11 +394,6 @@
   return g_browser_process->local_state();
 }
 
-bool DataReductionProxySettings::IsProxyOriginSetOnCommandLine() {
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin);
-}
-
 void DataReductionProxySettings::ResetDataReductionStatistics() {
   PrefService* prefs = GetLocalStatePrefs();
   if (!prefs)
@@ -324,12 +420,10 @@
     ResetDataReductionStatistics();
   }
 
-  std::string spdy_proxy_origin = GetDataReductionProxyOriginHostPort();
-
+  std::string proxy = GetDataReductionProxyOrigin();
   // Configure use of the data reduction proxy if it is enabled and the proxy
   // origin is non-empty.
-  enabled_by_user_=
-      spdy_proxy_auth_enabled_.GetValue() && !spdy_proxy_origin.empty();
+  enabled_by_user_= spdy_proxy_auth_enabled_.GetValue() && !proxy.empty();
   SetProxyConfigs(enabled_by_user_ && !disabled_by_carrier_, at_startup);
 
   // Check if the proxy has been disabled explicitly by the carrier.
@@ -345,8 +439,11 @@
   DictionaryPrefUpdate update(prefs, prefs::kProxy);
   base::DictionaryValue* dict = update.Get();
   if (enabled) {
+    std::string fallback = GetDataReductionProxyFallback();
     std::string proxy_server_config =
-        "http=" + GetDataReductionProxyOrigin() + ",direct://;";
+        "http=" + GetDataReductionProxyOrigin() +
+        (fallback.empty() ? "" : "," + fallback) +
+        ",direct://;";
     dict->SetString("server", proxy_server_config);
     dict->SetString("mode",
                     ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
@@ -436,6 +533,36 @@
 #endif
 }
 
+base::string16 DataReductionProxySettings::AuthHashForSalt(int64 salt) {
+  if (!IsDataReductionProxyAllowed())
+    return base::string16();
+
+  std::string key;
+
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
+    // If an origin is provided via a switch, then only consider the value
+    // that is provided by a switch. Do not use the preprocessor constant.
+    // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command
+    // line.
+    if (!command_line.HasSwitch(switches::kSpdyProxyAuthValue))
+      return base::string16();
+    key = command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue);
+  } else {
+#if defined(SPDY_PROXY_AUTH_VALUE)
+    key = SPDY_PROXY_AUTH_VALUE;
+#else
+    return base::string16();
+#endif
+  }
+
+  DCHECK(!key.empty());
+
+  std::string salted_key =
+      base::StringPrintf("%lld%s%lld", salt, key.c_str(), salt);
+  return UTF8ToUTF16(base::MD5String(salted_key));
+}
+
 net::URLFetcher* DataReductionProxySettings::GetURLFetcher() {
   std::string url = GetProxyCheckURL();
   if (url.empty())
@@ -443,8 +570,7 @@
   net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url),
                                                      net::URLFetcher::GET,
                                                      this);
-  fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
-  fetcher->SetLoadFlags(net::LOAD_BYPASS_PROXY);
+  fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
   Profile* profile = g_browser_process->profile_manager()->
       GetDefaultProfile();
   fetcher->SetRequestContext(profile->GetRequestContext());
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h
index f066d66..3f003da 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h
@@ -18,6 +18,10 @@
 class PrefService;
 
 namespace net {
+class AuthChallengeInfo;
+class HostPortPair;
+class HttpAuthCache;
+class HttpNetworkSession;
 class URLFetcher;
 }
 
@@ -37,17 +41,25 @@
 // Central point for configuring the data reduction proxy.
 // This object lives on the UI thread and all of its methods are expected to
 // be called from there.
+// TODO(marq): Convert this to be a BrowserContextKeyedService with an
+// associated factory class, and refactor the Java call sites accordingly.
 class DataReductionProxySettings
     : public net::URLFetcherDelegate,
       public net::NetworkChangeNotifier::IPAddressObserver {
  public:
   typedef std::vector<long long> ContentLengthList;
+  // TODO(marq): Consider instead using a std::pair instead of a vector.
+  typedef std::vector<GURL> DataReductionProxyList;
 
   DataReductionProxySettings();
   virtual ~DataReductionProxySettings();
 
   void InitDataReductionProxySettings();
 
+  // If proxy authentication is compiled in, pre-cache authentication
+  // keys for all configured proxies in |session|.
+  static void InitDataReductionProxySession(net::HttpNetworkSession* session);
+
   // Add a host pattern to bypass. This should follow the same syntax used
   // in net::ProxyBypassRules; that is, a hostname pattern, a hostname suffix
   // pattern, an IP literal, a CIDR block, or the magic string '<local>'.
@@ -64,19 +76,31 @@
   // instance of Chrome. This could return false, for example, if this instance
   // is not part of the field trial, or if the proxy name is not configured
   // via gyp.
-  bool IsDataReductionProxyAllowed();
+  static bool IsDataReductionProxyAllowed();
 
   // Returns true if a screen promoting the data reduction proxy is allowed to
   // be shown. Logic that decides when to show the promo should check its
   // availability. This would return false if not part of a separate field
   // trial that governs the use of the promotion.
-  bool IsDataReductionProxyPromoAllowed();
+  static bool IsDataReductionProxyPromoAllowed();
 
   // Returns the URL of the data reduction proxy.
-  std::string GetDataReductionProxyOrigin();
+  static std::string GetDataReductionProxyOrigin();
 
-  // Returns a configuration string for the proxy.
-  std::string GetDataReductionProxyAuth();
+  // Returns the URL of the fallback data reduction proxy.
+  static std::string GetDataReductionProxyFallback();
+
+  // Returns a vector of GURLs for all configured proxies.
+  static DataReductionProxyList GetDataReductionProxies();
+
+  // Returns true if |auth_info| represents an authentication challenge from
+  // a compatible, configured proxy.
+  bool IsAcceptableAuthChallenge(net::AuthChallengeInfo* auth_info);
+
+  // Returns a UTF16 string suitable for use as an authentication token in
+  // response to the challenge represented by |auth_info|. If the token can't
+  // be correctly generated for |auth_info|, returns an empty UTF16 string.
+  base::string16 GetTokenForAuthChallenge(net::AuthChallengeInfo* auth_info);
 
   // Returns true if the proxy is enabled.
   bool IsDataReductionProxyEnabled();
@@ -107,15 +131,13 @@
 
  protected:
   void InitPrefMembers();
+
   virtual net::URLFetcher* GetURLFetcher();
 
   // Virtualized for unit test support.
   virtual PrefService* GetOriginalProfilePrefs();
   virtual PrefService* GetLocalStatePrefs();
 
-  std::string GetDataReductionProxyOriginHostPort();
-
-  bool IsProxyOriginSetOnCommandLine();
   void GetContentLengths(unsigned int days,
                          int64* original_content_length,
                          int64* received_content_length,
@@ -134,8 +156,8 @@
   virtual void AddDefaultProxyBypassRules();
 
   // Writes a warning to the log that is used in backend processing of
-  // customer feedback.
-  void LogProxyState(bool enabled, bool at_startup);
+  // customer feedback. Virtual so tests can mock it for verification.
+  virtual void LogProxyState(bool enabled, bool at_startup);
 
   bool HasTurnedOn() { return has_turned_on_; }
   bool HasTurnedOff() { return has_turned_off_; }
@@ -150,6 +172,12 @@
   friend class DataReductionProxySettingsTestBase;
   friend class DataReductionProxySettingsTest;
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestAuthenticationInit);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestAuthHashGeneration);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestAuthHashGenerationWithOriginSetViaSwitch);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
                            TestResetDataReductionStatistics);
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
                            TestIsProxyEnabledOrManaged);
@@ -173,6 +201,10 @@
   // NetworkChangeNotifier::IPAddressObserver:
   virtual void OnIPAddressChanged() OVERRIDE;
 
+  // Underlying implementation of InitDataReductionProxySession(), factored
+  // out to be testable without creating a full HttpNetworkSession.
+  static void InitDataReductionAuthentication(net::HttpAuthCache* auth_cache);
+
   void OnProxyEnabledPrefChange();
 
   void ResetDataReductionStatistics();
@@ -185,6 +217,11 @@
   void ProbeWhetherDataReductionProxyIsAvailable();
   std::string GetProxyCheckURL();
 
+  // Returns a UTF16 string that's the hash of the configured authentication
+  // key and |salt|. Returns an empty UTF16 string if no key is configured or
+  // the data reduction proxy feature isn't available.
+  static base::string16 AuthHashForSalt(int64 salt);
+
   std::vector<std::string> bypass_rules_;
 
   // Indicate whether a user has turned on the data reduction proxy previously
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
index 2c23fbf..51404cf 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
@@ -10,22 +10,22 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/proxy_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "jni/DataReductionProxySettings_jni.h"
+#include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -36,9 +36,9 @@
 
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ScopedJavaLocalRef;
-using base::FieldTrialList;
 using base::StringPrintf;
 
 namespace {
@@ -55,6 +55,21 @@
   NUM_SPDY_PROXY_AUTH_STATE
 };
 
+// Generates a PAC proxy string component, including trailing semicolon and
+// space, for |origin|. Eg:
+//     "http://foo.com/"        -> "HTTP foo.com:80; "
+//     "https://bar.com:10443"  -> "HTTPS bar.coom:10443; "
+// The returned strings are suitable for concatenating into a PAC string.
+// If |origin| is empty, returns an empty string.
+std::string ProtocolAndHostForPACString(const std::string& origin) {
+  if (origin.empty()) {
+    return std::string();
+  }
+  GURL url = GURL(origin);
+  std::string protocol = url.SchemeIsSecure() ? "HTTPS "  : "HTTP ";
+  return protocol + net::HostPortPair::FromURL(url).ToString() + "; ";
+}
+
 }  // namespace
 
 DataReductionProxySettingsAndroid::DataReductionProxySettingsAndroid(
@@ -102,13 +117,6 @@
       env, DataReductionProxySettings::GetDataReductionProxyOrigin());
 }
 
-ScopedJavaLocalRef<jstring>
-DataReductionProxySettingsAndroid::GetDataReductionProxyAuth(
-    JNIEnv* env, jobject obj) {
-  return ConvertUTF8ToJavaString(
-      env, DataReductionProxySettings::GetDataReductionProxyAuth());
-}
-
 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyEnabled(
     JNIEnv* env, jobject obj) {
   return DataReductionProxySettings::IsDataReductionProxyEnabled();
@@ -148,6 +156,34 @@
                                     received_content_length);
 }
 
+jboolean DataReductionProxySettingsAndroid::IsAcceptableAuthChallenge(
+    JNIEnv* env,
+    jobject obj,
+    jstring host,
+    jstring realm) {
+  scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
+  auth_info->realm = ConvertJavaStringToUTF8(env, realm);
+  auth_info->challenger =
+      net::HostPortPair::FromString(ConvertJavaStringToUTF8(env, host));
+  return DataReductionProxySettings::IsAcceptableAuthChallenge(auth_info.get());
+}
+
+ScopedJavaLocalRef<jstring>
+DataReductionProxySettingsAndroid::GetTokenForAuthChallenge(JNIEnv* env,
+                                                            jobject obj,
+                                                            jstring host,
+                                                            jstring realm) {
+  scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
+  auth_info->realm = ConvertJavaStringToUTF8(env, realm);
+  auth_info->challenger =
+      net::HostPortPair::FromString(ConvertJavaStringToUTF8(env, host));
+
+  // If an empty string != null in Java, then here we should test for the
+  // token being empty and return a java null.
+  return ConvertUTF16ToJavaString(env,
+      DataReductionProxySettings::GetTokenForAuthChallenge(auth_info.get()));
+ }
+
 ScopedJavaLocalRef<jlongArray>
 DataReductionProxySettingsAndroid::GetDailyOriginalContentLengths(
     JNIEnv* env, jobject obj) {
@@ -260,19 +296,18 @@
       "(" + JoinString(pac_bypass_rules_, ") || (") + ")";
 
   // Generate a proxy PAC that falls back to direct loading when the proxy is
-  // unavailable and only process HTTP traffic. (With a statically configured
-  // proxy, proxy failures will simply result in a connection error presented to
-  // users.)
+  // unavailable and only process HTTP traffic.
 
-  std::string proxy_host =
-      DataReductionProxySettings::GetDataReductionProxyOriginHostPort();
+  std::string proxy_host = ProtocolAndHostForPACString(
+      DataReductionProxySettings::GetDataReductionProxyOrigin());
+  std::string fallback_host = ProtocolAndHostForPACString(
+      DataReductionProxySettings::GetDataReductionProxyFallback());
   std::string pac = "function FindProxyForURL(url, host) {"
       "  if (" + bypass_clause + ") {"
       "    return 'DIRECT';"
       "  } "
       "  if (url.substring(0, 5) == 'http:') {"
-      "    return 'HTTPS " + proxy_host +
-      "; DIRECT';"
+      "    return '" + proxy_host + fallback_host + "DIRECT';"
       "  }"
       "  return 'DIRECT';"
       "}";
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
index 10a0020..f7d221c 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
@@ -29,7 +29,6 @@
 
   void InitDataReductionProxySettings(JNIEnv* env, jobject obj);
 
-
   void BypassHostPattern(JNIEnv* env, jobject obj, jstring pattern);
   // Add a URL pattern to bypass the proxy. Wildcards
   // should be compatible with the JavaScript function shExpMatch, which can be
@@ -44,8 +43,6 @@
   jboolean IsDataReductionProxyPromoAllowed(JNIEnv* env, jobject obj);
   ScopedJavaLocalRef<jstring> GetDataReductionProxyOrigin(JNIEnv* env,
                                                           jobject obj);
-  ScopedJavaLocalRef<jstring> GetDataReductionProxyAuth(JNIEnv* env,
-                                                        jobject obj);
   jboolean IsDataReductionProxyEnabled(JNIEnv* env, jobject obj);
   jboolean IsDataReductionProxyManaged(JNIEnv* env, jobject obj);
   void SetDataReductionProxyEnabled(JNIEnv* env, jobject obj, jboolean enabled);
@@ -61,6 +58,19 @@
   base::android::ScopedJavaLocalRef<jobject> GetContentLengths(JNIEnv* env,
                                                                jobject obj);
 
+  // Wrapper methods for handling auth challenges. In both of the following,
+  // a net::AuthChallengeInfo object is created from |host| and |realm| and
+  // passed in to the superclass method.
+  jboolean IsAcceptableAuthChallenge(JNIEnv* env,
+                                     jobject obj,
+                                     jstring host,
+                                     jstring realm);
+
+  ScopedJavaLocalRef<jstring> GetTokenForAuthChallenge(JNIEnv* env,
+                                                       jobject obj,
+                                                       jstring host,
+                                                       jstring realm);
+
   // Registers the native methods to be call from Java.
   static bool Register(JNIEnv* env);
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc
index 5721de9..6b34c3e 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc
@@ -5,23 +5,30 @@
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h"
 
 #include "base/command_line.h"
+#include "base/md5.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
 #include "chrome/browser/prefs/proxy_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/common/pref_names.h"
 #include "components/variations/entropy_provider.h"
+#include "net/base/auth.h"
+#include "net/base/host_port_pair.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_auth_cache.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-const char kDataReductionProxyOrigin[] = "https://foo:443/";
+const char kDataReductionProxyOrigin[] = "https://foo.com:443/";
+const char kDataReductionProxyFallback[] = "http://bar.com:80";
 const char kDataReductionProxyAuth[] = "12345";
 
 const char kProbeURLWithOKResponse[] = "http://ok.org/";
@@ -40,6 +47,7 @@
         local_state_prefs_(local_state_prefs) {
   }
 
+  // TODO(marq): Replace virtual methods with MOCKs. Also mock LogProxyState.
   // DataReductionProxySettings implementation:
   virtual net::URLFetcher* GetURLFetcher() OVERRIDE {
     if (test_url_.empty())
@@ -89,6 +97,8 @@
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kSpdyProxyAuthFallback, kDataReductionProxyFallback);
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kSpdyProxyAuthValue, kDataReductionProxyAuth);
 }
 
@@ -133,8 +143,10 @@
 void DataReductionProxySettingsTestBase::CheckProxyConfigs(
     bool expected_enabled) {
   if (expected_enabled) {
+    std::string main_proxy = kDataReductionProxyOrigin;
+    std::string fallback_proxy = kDataReductionProxyFallback;
     std::string servers =
-      "http=" + Settings()->GetDataReductionProxyOrigin() + ",direct://;";
+        "http=" + main_proxy + "," + fallback_proxy + ",direct://;";
     CheckProxyPref(servers,
                    ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
   } else {
@@ -214,32 +226,95 @@
   scoped_ptr<TestDataReductionProxySettings> settings_;
 };
 
+TEST_F(DataReductionProxySettingsTest, TestAuthenticationInit) {
+  AddProxyToCommandLine();
+  net::HttpAuthCache cache;
+  DataReductionProxySettings::InitDataReductionAuthentication(&cache);
+  DataReductionProxySettings::DataReductionProxyList proxies =
+      DataReductionProxySettings::GetDataReductionProxies();
+  for (DataReductionProxySettings::DataReductionProxyList::iterator it =
+          proxies.begin();  it != proxies.end(); ++it) {
+    //GURL server = (*it).GetOrigin();
+    net::HttpAuthCache::Entry* entry =
+        cache.LookupByPath(*it, std::string());
+    EXPECT_TRUE(entry != NULL);
+    EXPECT_EQ(net::HttpAuth::AUTH_SCHEME_SPDYPROXY, entry->scheme());
+    EXPECT_EQ("SpdyProxy", entry->auth_challenge().substr(0,9));
+  }
+  GURL bad_server = GURL("https://bad.proxy.com/");
+    net::HttpAuthCache::Entry* entry =
+        cache.LookupByPath(bad_server, std::string());
+    EXPECT_TRUE(entry == NULL);
+}
+
 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
   AddProxyToCommandLine();
   // SetUp() adds the origin to the command line, which should be returned here.
-  std::string result = settings_->GetDataReductionProxyOrigin();
+  std::string result =
+      DataReductionProxySettings::GetDataReductionProxyOrigin();
   EXPECT_EQ(kDataReductionProxyOrigin, result);
 }
 
-TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyAuth) {
-  AddProxyToCommandLine();
-  // SetUp() adds the auth string to the command line, which should be returned
-  // here.
-  std::string result = settings_->GetDataReductionProxyAuth();
-  EXPECT_EQ(kDataReductionProxyAuth, result);
+TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) {
+  DataReductionProxySettings::DataReductionProxyList proxies =
+      DataReductionProxySettings::GetDataReductionProxies();
+
+  unsigned int expected_proxy_size = 0u;
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+  ++expected_proxy_size;
+#endif
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+  ++expected_proxy_size;
+#endif
+
+  EXPECT_EQ(expected_proxy_size, proxies.size());
+
+  // Adding just the fallback on the command line shouldn't add a proxy unless
+  // there was already one compiled in.
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kSpdyProxyAuthFallback, kDataReductionProxyFallback);
+  proxies = DataReductionProxySettings::GetDataReductionProxies();
+
+  // So: if there weren't any proxies before, there still won't be.
+  // If there were one or two, there will be two now.
+  expected_proxy_size = expected_proxy_size == 0u ? 0u : 2u;
+
+  EXPECT_EQ(expected_proxy_size, proxies.size());
+
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+    switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
+  proxies = DataReductionProxySettings::GetDataReductionProxies();
+  EXPECT_EQ(2u, proxies.size());
+
+  // Command line proxies have precedence, so even if there were other values
+  // compiled in, these should be the ones in the list.
+  EXPECT_EQ("foo.com", proxies[0].host());
+  EXPECT_EQ(443 ,proxies[0].EffectiveIntPort());
+  EXPECT_EQ("bar.com", proxies[1].host());
+  EXPECT_EQ(80, proxies[1].EffectiveIntPort());
 }
 
-// Test that the auth value set by preprocessor directive is not returned
+TEST_F(DataReductionProxySettingsTest, TestAuthHashGeneration) {
+  AddProxyToCommandLine();
+  std::string salt = "8675309";  // Jenny's number to test the hash generator.
+  std::string salted_key = salt + kDataReductionProxyAuth + salt;
+  base::string16 expected_hash = UTF8ToUTF16(base::MD5String(salted_key));
+  EXPECT_EQ(expected_hash,
+            DataReductionProxySettings::AuthHashForSalt(8675309));
+}
+
+// Test that the auth key set by preprocessor directive is not used
 // when an origin is set via a switch. This test only does anything useful in
 // Chrome builds.
 TEST_F(DataReductionProxySettingsTest,
-       TestGetDataReductionProxyAuthWithOriginSetViaSwitch) {
+       TestAuthHashGenerationWithOriginSetViaSwitch) {
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
-  std::string result = settings_->GetDataReductionProxyAuth();
-  EXPECT_EQ("", result);
+  EXPECT_EQ(base::string16(),
+            DataReductionProxySettings::AuthHashForSalt(8675309));
 }
 
+
 TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
   settings_->InitPrefMembers();
   EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
@@ -255,6 +330,64 @@
   EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
 }
 
+
+TEST_F(DataReductionProxySettingsTest, TestAcceptableChallenges) {
+  AddProxyToCommandLine();
+  typedef struct {
+    std::string host;
+    std::string realm;
+    bool expected_to_succeed;
+  } challenge_test;
+
+  challenge_test tests[] = {
+    {"foo.com:443", "", false},                 // 0. No realm.
+    {"foo.com:443", "xxx", false},              // 1. Wrong realm.
+    {"foo.com:443", "spdyproxy", false},        // 2. Case matters.
+    {"foo.com:443", "SpdyProxy", true},         // 3. OK.
+    {"foo.com:443", "SpdyProxy1234567", true},  // 4. OK
+    {"bar.com:80", "SpdyProxy1234567", true},   // 5. OK.
+    {"foo.com:443", "SpdyProxyxxx", true},      // 6. OK
+    {"", "SpdyProxy1234567", false},            // 7. No challenger.
+    {"xxx.net:443", "SpdyProxy1234567", false}, // 8. Wrong host.
+    {"foo.com", "SpdyProxy1234567", false},     // 9. No port.
+    {"foo.com:80", "SpdyProxy1234567", false},  // 10.Wrong port.
+    {"bar.com:81", "SpdyProxy1234567", false},  // 11.Wrong port.
+  };
+
+  for (int i = 0; i <= 11; ++i) {
+    scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
+    auth_info->challenger = net::HostPortPair::FromString(tests[i].host);
+    auth_info->realm = tests[i].realm;
+    EXPECT_EQ(tests[i].expected_to_succeed,
+              settings_->IsAcceptableAuthChallenge(auth_info.get()));
+  }
+}
+
+TEST_F(DataReductionProxySettingsTest, TestChallengeTokens) {
+  AddProxyToCommandLine();
+  typedef struct {
+    std::string realm;
+    bool expected_empty_token;
+  } token_test;
+
+  token_test tests[] = {
+    {"", true},                  // 0. No realm.
+    {"xxx", true},               // 1. realm too short.
+    {"spdyproxy", true},         // 2. no salt.
+    {"SpdyProxyxxx", true},      // 3. Salt not an int.
+    {"SpdyProxy1234567", false}, // 4. OK
+  };
+
+  for (int i = 0; i <= 4; ++i) {
+    scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
+    auth_info->challenger =
+        net::HostPortPair::FromString(kDataReductionProxyOrigin);
+    auth_info->realm = tests[i].realm;
+    base::string16 token = settings_->GetTokenForAuthChallenge(auth_info.get());
+    EXPECT_EQ(tests[i].expected_empty_token, token.empty());
+  }
+}
+
 TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
   int64 original_content_length;
   int64 received_content_length;
@@ -415,4 +548,3 @@
     EXPECT_EQ(expected[i++], *it);
   }
 }
-
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
index 98a4275..fbe4650 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
@@ -12,11 +12,11 @@
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h"
 #include "chrome/browser/prefs/proxy_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/common/pref_names.h"
@@ -25,8 +25,9 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-const char kDataReductionProxyOrigin[] = "https://foo:443/";
-const char kDataReductionProxyAuth[] = "12345";
+const char kDataReductionProxyOrigin[] = "https://foo.com:443/";
+const char kDataReductionProxyOriginPAC[] = "HTTPS foo.com:443;";
+const char kDataReductionProxyFallbackPAC[] = "HTTP bar.com:80;";
 
 class TestDataReductionProxySettingsAndroid
     : public DataReductionProxySettingsAndroid {
@@ -42,7 +43,8 @@
         local_state_prefs_(local_state_prefs) {
   }
 
-  // DataReductionProxySettings implementation:
+  // TODO(marq): Replace virtual methods with MOCKs.
+  // DataReductionProxySettingsAndroid implementation:
   virtual net::URLFetcher* GetURLFetcher() OVERRIDE {
     if (test_url_.empty())
       return NULL;
@@ -55,6 +57,7 @@
   virtual PrefService* GetOriginalProfilePrefs() OVERRIDE {
     return profile_prefs_;
   }
+
   virtual PrefService* GetLocalStatePrefs() OVERRIDE {
     return local_state_prefs_;
   }
@@ -131,33 +134,6 @@
   EXPECT_EQ(kDataReductionProxyOrigin, ConvertJavaStringToUTF8(str_ref));
 }
 
-TEST_F(DataReductionProxySettingsAndroidTest, TestGetDataReductionProxyAuth) {
-  AddProxyToCommandLine();
-  // SetUp() adds the auth string to the command line, which should be returned
-  // here.
-  ScopedJavaLocalRef<jstring> result =
-      settings_->GetDataReductionProxyAuth(env_, NULL);
-  ASSERT_TRUE(result.obj());
-  const base::android::JavaRef<jstring>& str_ref = result;
-  EXPECT_EQ(kDataReductionProxyAuth, ConvertJavaStringToUTF8(str_ref));
-}
-
-// Test that the auth value set by preprocessor directive is not returned
-// when an origin is set via a switch. This test only does anything useful in
-// Chrome builds.
-TEST_F(DataReductionProxySettingsAndroidTest,
-       TestGetDataReductionProxyAuthWithOriginSetViaSwitch) {
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
-  // SetUp() adds the auth string to the command line, which should be returned
-  // here.
-  ScopedJavaLocalRef<jstring> result =
-      settings_->GetDataReductionProxyAuth(env_, NULL);
-  ASSERT_TRUE(result.obj());
-  const base::android::JavaRef<jstring>& str_ref = result;
-  EXPECT_EQ(std::string(), ConvertJavaStringToUTF8(str_ref));
-}
-
 // Confirm that the bypass rule functions generate the intended JavaScript
 // code for the Proxy PAC.
 TEST_F(DataReductionProxySettingsAndroidTest, TestBypassPACRules) {
@@ -173,9 +149,13 @@
 }
 
 TEST_F(DataReductionProxySettingsAndroidTest, TestSetProxyPac) {
+  AddProxyToCommandLine();
   settings_->AddDefaultProxyBypassRules();
+  std::string raw_pac = settings_->GetProxyPacScript();
+  EXPECT_NE(raw_pac.find(kDataReductionProxyOriginPAC), std::string::npos);
+  EXPECT_NE(raw_pac.find(kDataReductionProxyFallbackPAC), std::string::npos);;
   std::string pac;
-  base::Base64Encode(settings_->GetProxyPacScript(), &pac);
+  base::Base64Encode(raw_pac, &pac);
   std::string expected_pac_url =
       "data:application/x-ns-proxy-autoconfig;base64," + pac;
   // Test setting the PAC, without generating histograms.
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index a910ecb..9ff4d45 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/notifications/desktop_notification_service.h"
 
 #include "base/metrics/histogram.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/browser_process.h"
@@ -12,6 +13,8 @@
 #include "chrome/browser/content_settings/content_settings_details.h"
 #include "chrome/browser/content_settings/content_settings_provider.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/extensions/api/notifications/notifications_api.h"
+#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -23,7 +26,6 @@
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/content_settings.h"
@@ -587,6 +589,7 @@
       pref_name = prefs::kMessageCenterDisabledExtensionIds;
       add_new_item = !enabled;
       id.reset(new base::StringValue(notifier_id.id));
+      FirePermissionLevelChangedEvent(notifier_id, enabled);
       break;
     case NotifierId::SYSTEM_COMPONENT:
 #if defined(OS_CHROMEOS)
@@ -682,3 +685,19 @@
 
   SetNotifierEnabled(notifier_id, true);
 }
+
+void DesktopNotificationService::FirePermissionLevelChangedEvent(
+    const NotifierId& notifier_id, bool enabled) {
+  DCHECK_EQ(NotifierId::APPLICATION, notifier_id.type);
+  extensions::api::notifications::PermissionLevel permission =
+      enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
+              : extensions::api::notifications::PERMISSION_LEVEL_DENIED;
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Append(new base::StringValue(
+      extensions::api::notifications::ToString(permission)));
+  scoped_ptr<extensions::Event> event(new extensions::Event(
+      extensions::api::notifications::OnPermissionLevelChanged::kEventName,
+      args.Pass()));
+  extensions::ExtensionSystem::Get(profile_)->event_router()->
+      DispatchEventToExtension(notifier_id.id, event.Pass());
+}
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h
index 46defd4..cd9dbd0 100644
--- a/chrome/browser/notifications/desktop_notification_service.h
+++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -195,6 +195,10 @@
   // Called when the enabled_sync_notifier_id pref has been changed.
   void OnEnabledSyncNotifierIdsChanged();
 
+  void FirePermissionLevelChangedEvent(
+      const message_center::NotifierId& notifier_id,
+      bool enabled);
+
   // content::NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc
index 9d07c8b..c62ae50 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/notifications/desktop_notifications_unittest.cc
@@ -24,6 +24,7 @@
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #endif
 
 
@@ -107,6 +108,9 @@
   // The message center is notmally initialized on |g_browser_process| which
   // is not created for these tests.
   message_center::MessageCenter::Initialize();
+  // The ContextFactory must exist before any Compositors are created.
+  bool allow_test_contexts = true;
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
   // MockBalloonCollection retrieves information about the screen on creation.
   // So it is necessary to make sure the desktop gets created first.
   ash::Shell::CreateInstance(new ash::test::TestShellDelegate);
@@ -131,6 +135,7 @@
   // is not created for these tests.
   message_center::MessageCenter::Shutdown();
   aura::Env::DeleteInstance();
+  ui::TerminateContextFactoryForTests();
 #endif
   ui::ShutdownInputMethodForTesting();
 }
diff --git a/chrome/browser/notifications/fullscreen_notification_blocker.cc b/chrome/browser/notifications/fullscreen_notification_blocker.cc
index 0d5b350..bbfa582 100644
--- a/chrome/browser/notifications/fullscreen_notification_blocker.cc
+++ b/chrome/browser/notifications/fullscreen_notification_blocker.cc
@@ -13,7 +13,7 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/system_notifier.h"
-#include "ash/wm/window_properties.h"
+#include "ash/wm/window_state.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #endif
@@ -30,13 +30,14 @@
     if (!controller)
       return false;
 
+    // Block notifications if the shelf is hidden because of a fullscreen
+    // window.
     const aura::Window* fullscreen_window =
         controller->GetTopmostFullscreenWindow();
-
-    // Should appear notifications if kFullscreenUsesMinimalChromeKey is set,
-    // since shelf/message_center UI is visible in such situation.
-    return fullscreen_window && !fullscreen_window->GetProperty(
-        ash::internal::kFullscreenUsesMinimalChromeKey);
+    if (!fullscreen_window)
+      return false;
+    return ash::wm::GetWindowState(fullscreen_window)->
+        hide_shelf_when_fullscreen();
   }
 #endif
 
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
index 34f6207..c2024ab 100644
--- a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
@@ -7,7 +7,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/system_notifier.h"
-#include "ash/system/tray/system_tray_delegate.h"
 #include "ash/wm/window_properties.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
@@ -23,12 +22,18 @@
   // This class is created in the ctor of NotificationUIManager which is created
   // when a notification is created, so ash::Shell should be initialized.
   ash::Shell::GetInstance()->AddShellObserver(this);
+
+  // LoginState may not exist in some tests.
+  if (chromeos::LoginState::IsInitialized())
+    chromeos::LoginState::Get()->AddObserver(this);
 }
 
 LoginStateNotificationBlockerChromeOS::
     ~LoginStateNotificationBlockerChromeOS() {
   // In some tests, the notification blockers may be removed without calling
   // OnAppTerminating().
+  if (chromeos::LoginState::IsInitialized())
+    chromeos::LoginState::Get()->RemoveObserver(this);
   if (observing_ && ash::Shell::HasInstance())
     ash::Shell::GetInstance()->RemoveShellObserver(this);
 }
@@ -38,19 +43,13 @@
   if (ash::system_notifier::ShouldAlwaysShowPopups(notifier_id))
     return true;
 
-  if (!locked_)
-    return true;
+  if (locked_)
+    return false;
 
-  ash::user::LoginStatus login_status =
-      ash::Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
-  return login_status != ash::user::LOGGED_IN_NONE &&
-      login_status != ash::user::LOGGED_IN_LOCKED;
-}
+  if (chromeos::LoginState::IsInitialized())
+    return chromeos::LoginState::Get()->IsUserLoggedIn();
 
-void LoginStateNotificationBlockerChromeOS::OnLoginStateChanged(
-    ash::user::LoginStatus login_status) {
-  FOR_EACH_OBSERVER(
-      NotificationBlocker::Observer, observers(), OnBlockingStateChanged());
+  return true;
 }
 
 void LoginStateNotificationBlockerChromeOS::OnLockStateChanged(bool locked) {
@@ -63,3 +62,8 @@
   ash::Shell::GetInstance()->RemoveShellObserver(this);
   observing_ = false;
 }
+
+void LoginStateNotificationBlockerChromeOS::LoggedInStateChanged() {
+  FOR_EACH_OBSERVER(
+      NotificationBlocker::Observer, observers(), OnBlockingStateChanged());
+}
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos.h b/chrome/browser/notifications/login_state_notification_blocker_chromeos.h
index 7e66d71..97b3871 100644
--- a/chrome/browser/notifications/login_state_notification_blocker_chromeos.h
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_NOTIFICATIONS_LOGIN_STATE_NOTIFICATION_BLOCKER_CHROMEOS_H_
 
 #include "ash/shell_observer.h"
+#include "chromeos/login/login_state.h"
 #include "ui/message_center/notification_blocker.h"
 
 // A notification blocker which checks screen lock / login state for ChromeOS.
@@ -17,7 +18,8 @@
 //  - In ChromeOS, some system notifications are allowed to be shown as popups.
 class LoginStateNotificationBlockerChromeOS
     : public message_center::NotificationBlocker,
-      public ash::ShellObserver {
+      public ash::ShellObserver,
+      public chromeos::LoginState::Observer {
  public:
   explicit LoginStateNotificationBlockerChromeOS(
       message_center::MessageCenter* message_center);
@@ -29,11 +31,12 @@
       const message_center::NotifierId& notifier_id) const OVERRIDE;
 
   // ash::ShellObserver overrides:
-  virtual void OnLoginStateChanged(
-      ash::user::LoginStatus login_status) OVERRIDE;
   virtual void OnLockStateChanged(bool locked) OVERRIDE;
   virtual void OnAppTerminating() OVERRIDE;
 
+  // chromeos::LoginState::Observer overrides:
+  virtual void LoggedInStateChanged() OVERRIDE;
+
   bool locked_;
   bool observing_;
 
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
new file mode 100644
index 0000000..decbca5
--- /dev/null
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
@@ -0,0 +1,119 @@
+// Copyright 2013 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 "ash/shell.h"
+#include "ash/system/system_notifier.h"
+#include "ash/test/ash_test_base.h"
+#include "base/command_line.h"
+#include "chrome/browser/notifications/login_state_notification_blocker_chromeos.h"
+#include "chromeos/login/login_state.h"
+#include "ui/message_center/message_center.h"
+
+class LoginStateNotificationBlockerChromeOSTest
+    : public ash::test::AshTestBase,
+      public message_center::NotificationBlocker::Observer {
+ public:
+  LoginStateNotificationBlockerChromeOSTest()
+      : state_changed_count_(0) {}
+  virtual ~LoginStateNotificationBlockerChromeOSTest() {}
+
+  // ash::tests::AshTestBase overrides:
+  virtual void SetUp() OVERRIDE {
+    chromeos::LoginState::Initialize();
+    chromeos::LoginState::Get()->set_always_logged_in(false);
+    ash::test::AshTestBase::SetUp();
+    blocker_.reset(new LoginStateNotificationBlockerChromeOS(
+        message_center::MessageCenter::Get()));
+    blocker_->AddObserver(this);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    blocker_->RemoveObserver(this);
+    blocker_.reset();
+    ash::test::AshTestBase::TearDown();
+    chromeos::LoginState::Shutdown();
+  }
+
+  message_center::NotificationBlocker* blocker() { return blocker_.get(); }
+
+  // message_center::NotificationBlocker::Observer ovverrides:
+  virtual void OnBlockingStateChanged() OVERRIDE {
+    state_changed_count_++;
+  }
+
+  int GetStateChangedCountAndReset() {
+    int result = state_changed_count_;
+    state_changed_count_ = 0;
+    return result;
+  }
+
+ private:
+  int state_changed_count_;
+  scoped_ptr<LoginStateNotificationBlockerChromeOS> blocker_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoginStateNotificationBlockerChromeOSTest);
+};
+
+TEST_F(LoginStateNotificationBlockerChromeOSTest, BaseTest) {
+  // Default status: OOBE.
+  message_center::NotifierId notifier_id;
+  EXPECT_FALSE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Login screen.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_NONE,
+      chromeos::LoginState::LOGGED_IN_USER_NONE);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_FALSE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Logged in as a normal user.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_ACTIVE,
+      chromeos::LoginState::LOGGED_IN_USER_REGULAR);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Lock.
+  ash::Shell::GetInstance()->OnLockStateChanged(true);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_FALSE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Unlock.
+  ash::Shell::GetInstance()->OnLockStateChanged(false);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+}
+
+TEST_F(LoginStateNotificationBlockerChromeOSTest, AlwaysAllowedNotifier) {
+  // NOTIFIER_DISPLAY is allowed to shown in the login screen.
+  message_center::NotifierId notifier_id(
+      ash::system_notifier::NOTIFIER_DISPLAY);
+
+  // Default status: OOBE.
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Login screen.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_NONE,
+      chromeos::LoginState::LOGGED_IN_USER_NONE);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Logged in as a normal user.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_ACTIVE,
+      chromeos::LoginState::LOGGED_IN_USER_REGULAR);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Lock.
+  ash::Shell::GetInstance()->OnLockStateChanged(true);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+
+  // Unlock.
+  ash::Shell::GetInstance()->OnLockStateChanged(false);
+  EXPECT_EQ(1, GetStateChangedCountAndReset());
+  EXPECT_TRUE(blocker()->ShouldShowNotificationAsPopup(notifier_id));
+}
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index b21fb16..b59967c 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -162,14 +162,9 @@
 void MessageCenterSettingsController::GetNotifierList(
     std::vector<Notifier*>* notifiers) {
   DCHECK(notifiers);
-  if (notifier_groups_.empty())
-    return;
-
   // Temporarily use the last used profile to prevent chrome from crashing when
   // the default profile is not loaded.
-  message_center::ProfileNotifierGroup* group =
-      notifier_groups_[current_notifier_group_];
-  Profile* profile = group->profile();
+  Profile* profile = GetCurrentProfile();
   if (!profile)
     return;
 
@@ -213,12 +208,14 @@
     notifier::ChromeNotifierService* sync_notifier_service =
         notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
             profile, Profile::EXPLICIT_ACCESS);
-    sync_notifier_service->GetSyncedNotificationServices(notifiers);
+    if (sync_notifier_service) {
+      sync_notifier_service->GetSyncedNotificationServices(notifiers);
 
-    if (comparator)
-      std::sort(notifiers->begin(), notifiers->end(), *comparator);
-    else
-      std::sort(notifiers->begin(), notifiers->end(), SimpleCompareNotifiers);
+      if (comparator)
+        std::sort(notifiers->begin(), notifiers->end(), *comparator);
+      else
+        std::sort(notifiers->begin(), notifiers->end(), SimpleCompareNotifiers);
+    }
   }
 
   int app_count = notifiers->size();
@@ -287,7 +284,7 @@
 void MessageCenterSettingsController::SetNotifierEnabled(
     const Notifier& notifier,
     bool enabled) {
-  Profile* profile = notifier_groups_[current_notifier_group_]->profile();
+  Profile* profile = GetCurrentProfile();
   DCHECK(profile);
 
   DesktopNotificationService* notification_service =
@@ -368,6 +365,18 @@
                     NotifierGroupChanged());
 }
 
+Profile* MessageCenterSettingsController::GetCurrentProfile() {
+  if (notifier_groups_.size() > current_notifier_group_)
+    return notifier_groups_[current_notifier_group_]->profile();
+
+#if defined(OS_CHROMEOS)
+  return ProfileManager::GetDefaultProfileOrOffTheRecord();
+#else
+  NOTREACHED();
+  return NULL;
+#endif
+}
+
 void MessageCenterSettingsController::RebuildNotifierGroups() {
   notifier_groups_.clear();
   current_notifier_group_ = 0;
diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h
index 03f7552..d4fecc6 100644
--- a/chrome/browser/notifications/message_center_settings_controller.h
+++ b/chrome/browser/notifications/message_center_settings_controller.h
@@ -21,6 +21,7 @@
 #include "ui/message_center/notifier_settings.h"
 
 class CancelableTaskTracker;
+class Profile;
 class ProfileInfoCache;
 
 namespace chrome {
@@ -73,6 +74,8 @@
   void OnFaviconLoaded(const GURL& url,
                        const chrome::FaviconImageResult& favicon_result);
 
+  Profile* GetCurrentProfile();
+
   void RebuildNotifierGroups();
 
   // The views displaying notifier settings.
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
index 362da5e..9f7a7f8 100644
--- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -70,14 +70,6 @@
             UTF8ToUTF16("Profile-1"));
 }
 
-TEST_F(MessageCenterSettingsControllerTest, GuestNoBreak) {
-  // In the guest mode of ChromeOS, there're no notifier groups but
-  // GetNotifierList() shouldn't cause crash.
-  scoped_ptr<MessageCenterSettingsController> controller(
-      new MessageCenterSettingsController(GetCache()));
-
-  EXPECT_EQ(controller->GetNotifierGroupCount(), 0u);
-  std::vector<message_center::Notifier*> notifiers;
-  controller->GetNotifierList(&notifiers);
-  EXPECT_TRUE(notifiers.empty());
-}
+// TODO(mukai): write a test case to reproduce the actual guest session scenario
+// in ChromeOS -- no profiles in the profile_info_cache but GetDefaultProfile
+// returns a new one.
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
index 9585d81..f049276 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/notifications/sync_notifier/synced_notification.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/user_metrics.h"
 
@@ -47,7 +48,8 @@
 
   GURL destination = notification->GetDefaultDestinationUrl();
   NavigateToUrl(destination);
-  chrome_notifier_->MarkNotificationAsRead(notification_id_);
+  // TODO(petewil): Once the service protobuf supports a viewed state, mark the
+  // notification as viewed here.
 
   // Record the action in UMA statistics.
   CollectAction(SYNCED_NOTIFICATION_ACTION_CLICK);
@@ -60,7 +62,8 @@
   if (notification) {
     GURL destination = notification->GetButtonUrl(button_index);
     NavigateToUrl(destination);
-    chrome_notifier_->MarkNotificationAsRead(notification_id_);
+    // TODO(petewil): Once the service protobuf supports a viewed state, mark
+    // the notification as viewed here.
   }
 
   // Now record the UMA statistics for this action.
@@ -74,12 +77,16 @@
   content::OpenURLParams openParams(destination, content::Referrer(),
                                     NEW_FOREGROUND_TAB,
                                     content::PAGE_TRANSITION_LINK, false);
-  Browser* browser = chrome::FindLastActiveWithProfile(
+  Browser* browser = chrome::FindOrCreateTabbedBrowser(
       chrome_notifier_->profile(),
       chrome::GetActiveDesktop());
   // Navigate to the URL in a new tab.
-  if (browser != NULL)
+  if (browser != NULL) {
     browser->OpenURL(openParams);
+    browser->window()->Activate();
+  } else {
+    DVLOG(2) << "NavigateToUrl failed to create a browser.";
+  }
 
 }
 
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc
index acd0f25..50e7ebd 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc
@@ -140,9 +140,6 @@
   GURL url2(kButtonTwoUrl);
   tab = browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_EQ(url2, tab->GetController().GetActiveEntry()->GetVirtualURL());
-
-  // Also verify that the click dismissed the notification.
-  ASSERT_EQ(kTestNotificationId, notifier.read_id());
 }
 
 IN_PROC_BROWSER_TEST_F(ChromeNotifierDelegateBrowserTest, CloseTest) {
diff --git a/chrome/browser/notifications/welcome_notification.cc b/chrome/browser/notifications/welcome_notification.cc
index ac48b75..b5adb41 100644
--- a/chrome/browser/notifications/welcome_notification.cc
+++ b/chrome/browser/notifications/welcome_notification.cc
@@ -47,7 +47,10 @@
   }
 
   virtual void Click() OVERRIDE {}
-  virtual void ButtonClick(int index) OVERRIDE {}
+  virtual void ButtonClick(int index) OVERRIDE {
+    DCHECK(index == 0);
+    OpenNotificationLearnMoreTab();
+  }
 
  private:
   void MarkAsDismissed() {
@@ -55,6 +58,18 @@
         SetBoolean(prefs::kWelcomeNotificationDismissed, true);
   }
 
+  void OpenNotificationLearnMoreTab() {
+    Browser* browser = chrome::FindOrCreateTabbedBrowser(
+        profile_, chrome::GetActiveDesktop());
+    chrome::NavigateParams params(
+        browser,
+        GURL(chrome::kNotificationWelcomeLearnMoreURL),
+        content::PAGE_TRANSITION_LINK);
+    params.disposition = NEW_FOREGROUND_TAB;
+    params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+    chrome::Navigate(&params);
+  }
+
   virtual ~WelcomeNotificationDelegate() {}
 
   Profile* const profile_;
@@ -81,8 +96,19 @@
     const Notification& notification) {
   if (notification.notifier_id().id == kChromeNowExtensionID) {
     PrefService* pref_service = profile_->GetPrefs();
-    if (!pref_service->GetBoolean(prefs::kWelcomeNotificationDismissed))
-      ShowWelcomeNotification();
+    if (!pref_service->GetBoolean(prefs::kWelcomeNotificationDismissed)) {
+      PopUpRequest popUpRequest =
+          pref_service->GetBoolean(
+              prefs::kWelcomeNotificationPreviouslyPoppedUp)
+          ? POP_UP_HIDDEN
+          : POP_UP_SHOWN;
+      if (popUpRequest == POP_UP_SHOWN) {
+        pref_service->SetBoolean(
+            prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
+      }
+
+      ShowWelcomeNotification(popUpRequest);
+    }
   }
 }
 
@@ -93,11 +119,21 @@
       prefs::kWelcomeNotificationDismissed,
       false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  prefs->RegisterBooleanPref(
+      prefs::kWelcomeNotificationPreviouslyPoppedUp,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
-void WelcomeNotification::ShowWelcomeNotification() {
+void WelcomeNotification::ShowWelcomeNotification(PopUpRequest popUpRequest) {
+  message_center::ButtonInfo learn_more(
+      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
+  learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+      IDR_NOTIFICATION_WELCOME_LEARN_MORE);
+
   message_center::RichNotificationData rich_notification_data;
   rich_notification_data.priority = 2;
+  rich_notification_data.buttons.push_back(learn_more);
 
   if (welcome_notification_id_.empty())
     welcome_notification_id_ = base::GenerateGUID();
@@ -117,6 +153,10 @@
             rich_notification_data,
             new WelcomeNotificationDelegate(
                 welcome_notification_id_, profile_)));
+
+    if (popUpRequest == POP_UP_HIDDEN)
+      message_center_notification->set_shown_as_popup(true);
+
     message_center_->AddNotification(message_center_notification.Pass());
   }
 }
diff --git a/chrome/browser/notifications/welcome_notification.h b/chrome/browser/notifications/welcome_notification.h
index 54e1c43..e421f68 100644
--- a/chrome/browser/notifications/welcome_notification.h
+++ b/chrome/browser/notifications/welcome_notification.h
@@ -39,8 +39,14 @@
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
 
  private:
+
+  enum PopUpRequest {
+    POP_UP_HIDDEN = 0,
+    POP_UP_SHOWN = 1,
+  };
+
   // Unconditionally shows the welcome notification.
-  void ShowWelcomeNotification();
+  void ShowWelcomeNotification(PopUpRequest popUpRequest);
 
   // Hides the welcome notification.
   void HideWelcomeNotification();
diff --git a/chrome/browser/notifications/welcome_notification_unittest.cc b/chrome/browser/notifications/welcome_notification_unittest.cc
index 71d5435..d2b3492 100644
--- a/chrome/browser/notifications/welcome_notification_unittest.cc
+++ b/chrome/browser/notifications/welcome_notification_unittest.cc
@@ -25,10 +25,14 @@
  public:
   MockMessageCenter()
     : add_notification_calls_(0),
-      remove_notification_calls_(0) {};
+      remove_notification_calls_(0),
+      notifications_with_shown_as_popup_(0) {};
 
   int add_notification_calls() { return add_notification_calls_; }
   int remove_notification_calls() { return remove_notification_calls_; }
+  int notifications_with_shown_as_popup() {
+    return notifications_with_shown_as_popup_;
+  }
 
   // message_center::FakeMessageCenter Overrides
   virtual bool HasNotification(const std::string& id) OVERRIDE {
@@ -41,6 +45,8 @@
     EXPECT_FALSE(last_notification.get());
     last_notification.swap(notification);
     add_notification_calls_++;
+    if (last_notification->shown_as_popup())
+      notifications_with_shown_as_popup_++;
   }
 
   virtual void RemoveNotification(const std::string& id, bool by_user)
@@ -60,6 +66,7 @@
   scoped_ptr<message_center::Notification> last_notification;
   int add_notification_calls_;
   int remove_notification_calls_;
+  int notifications_with_shown_as_popup_;
 };
 
 class WelcomeNotificationTest : public testing::Test {
@@ -166,13 +173,20 @@
 TEST_F(WelcomeNotificationTest, FirstRunShowRegularNotification) {
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 
   ShowRegularNotification();
 
   EXPECT_TRUE(message_center()->add_notification_calls() == 0);
   EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 }
 
 // Show a Chrome Now notification. Expect that WelcomeNotification will
@@ -180,13 +194,42 @@
 TEST_F(WelcomeNotificationTest, FirstRunChromeNowNotification) {
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 
   ShowChromeNowNotification();
 
   EXPECT_TRUE(message_center()->add_notification_calls() == 1);
   EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
+}
+
+// Show a Chrome Now notification that was already shown before.
+TEST_F(WelcomeNotificationTest, ShowWelcomeNotificationAgain) {
+  profile()->GetPrefs()->SetBoolean(
+      prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
+
+  ShowChromeNowNotification();
+
+  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
+  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 1);
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 }
 
 // Don't show a welcome notification if it was previously dismissed
@@ -194,13 +237,20 @@
   profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
   EXPECT_TRUE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 
   ShowChromeNowNotification();
 
   EXPECT_TRUE(message_center()->add_notification_calls() == 0);
   EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
   EXPECT_TRUE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 }
 
 // Show a Chrome Now notification and dismiss it.
@@ -208,6 +258,9 @@
 TEST_F(WelcomeNotificationTest, DismissWelcomeNotification) {
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 
   ShowChromeNowNotification();
   message_center()->CloseCurrentNotification();
@@ -215,8 +268,12 @@
 
   EXPECT_TRUE(message_center()->add_notification_calls() == 1);
   EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
   EXPECT_TRUE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 }
 
 // Show a Chrome Now notification and dismiss it via a synced preference change.
@@ -224,12 +281,19 @@
 TEST_F(WelcomeNotificationTest, SyncedDismissalWelcomeNotification) {
   EXPECT_FALSE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_FALSE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 
   ShowChromeNowNotification();
   profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
 
   EXPECT_TRUE(message_center()->add_notification_calls() == 1);
   EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
+  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
   EXPECT_TRUE(
       profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+  EXPECT_TRUE(
+      profile()->GetPrefs()->GetBoolean(
+          prefs::kWelcomeNotificationPreviouslyPoppedUp));
 }
diff --git a/chrome/browser/password_manager/password_manager_metrics_util.cc b/chrome/browser/password_manager/password_manager_metrics_util.cc
index 471ea2c..4650123 100644
--- a/chrome/browser/password_manager/password_manager_metrics_util.cc
+++ b/chrome/browser/password_manager/password_manager_metrics_util.cc
@@ -7,13 +7,13 @@
 #include "base/basictypes.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/safe_numerics.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/password_manager/password_manager_metrics_util_unittest.cc b/chrome/browser/password_manager/password_manager_metrics_util_unittest.cc
index 08938c0..3d23d1c 100644
--- a/chrome/browser/password_manager/password_manager_metrics_util_unittest.cc
+++ b/chrome/browser/password_manager/password_manager_metrics_util_unittest.cc
@@ -8,8 +8,8 @@
 #include <map>
 
 #include "base/basictypes.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/password_manager/password_manager_util.h b/chrome/browser/password_manager/password_manager_util.h
new file mode 100644
index 0000000..4c6441d
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_util.h
@@ -0,0 +1,18 @@
+// Copyright 2013 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_PASSWORD_MANAGER_PASSWORD_MANAGER_UTIL_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_UTIL_H_
+
+namespace password_manager_util {
+
+// Attempts to (re-)authenticate the user of the OS account. Returns true if
+// the user was successfully authenticated, or if authentication was not
+// possible. On platforms where reauthentication is not possible or does not
+// make sense, the default implementation always returns true.
+bool AuthenticateUser();
+
+}  // namespace password_manager_util
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_UTIL_H_
diff --git a/chrome/browser/password_manager/password_manager_util_mac.mm b/chrome/browser/password_manager/password_manager_util_mac.mm
new file mode 100644
index 0000000..edb03a2
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_util_mac.mm
@@ -0,0 +1,39 @@
+// Copyright 2013 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/password_manager/password_manager_util.h"
+
+#import <Foundation/Foundation.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Authorization.h>
+
+#include "base/basictypes.h"
+#include "base/mac/authorization_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_authorizationref.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace password_manager_util {
+
+bool AuthenticateUser() {
+  AuthorizationItem right_items[] = {
+    {"com.google.Chrome.show-passwords", 0, NULL, 0}
+  };
+  AuthorizationRights rights = {arraysize(right_items), right_items};
+
+  NSString* prompt =
+      l10n_util::GetNSString(IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT);
+
+  // Pass kAuthorizationFlagDestroyRights to prevent the OS from saving the
+  // authorization and not prompting the user when future requests are made.
+  base::mac::ScopedAuthorizationRef authorization(
+      base::mac::GetAuthorizationRightsWithPrompt(
+          &rights, base::mac::NSToCFCast(prompt),
+          kAuthorizationFlagDestroyRights));
+  return authorization.get() != NULL;
+}
+
+}  // namespace password_manager_util
diff --git a/chrome/browser/password_manager/password_manager_util_stub.cc b/chrome/browser/password_manager/password_manager_util_stub.cc
new file mode 100644
index 0000000..caf654a
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_util_stub.cc
@@ -0,0 +1,11 @@
+// Copyright 2013 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.
+
+namespace password_manager_util {
+
+bool AuthenticateUser() {
+  return true;
+}
+
+}  // namespace password_manager_util
diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc
index aba1173..aa96324 100644
--- a/chrome/browser/performance_monitor/performance_monitor.cc
+++ b/chrome/browser/performance_monitor/performance_monitor.cc
@@ -45,6 +45,7 @@
 
 using content::BrowserThread;
 using extensions::Extension;
+using extensions::UnloadedExtensionInfo;
 
 namespace performance_monitor {
 
@@ -564,11 +565,11 @@
       break;
     }
     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const extensions::UnloadedExtensionInfo* info =
-          content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
+      const UnloadedExtensionInfo* info =
+          content::Details<UnloadedExtensionInfo>(details).ptr();
 
       // Check if the extension was unloaded because it was disabled.
-      if (info->reason == extension_misc::UNLOAD_REASON_DISABLE) {
+      if (info->reason == UnloadedExtensionInfo::REASON_DISABLE) {
         AddExtensionEvent(EVENT_EXTENSION_DISABLE,
                           info->extension);
       }
diff --git a/chrome/browser/performance_monitor/process_metrics_history.cc b/chrome/browser/performance_monitor/process_metrics_history.cc
index 9ac206f..38c1e41 100644
--- a/chrome/browser/performance_monitor/process_metrics_history.cc
+++ b/chrome/browser/performance_monitor/process_metrics_history.cc
@@ -52,7 +52,7 @@
 }
 
 void ProcessMetricsHistory::SampleMetrics() {
-  double cpu_usage = process_metrics_->GetCPUUsage();
+  double cpu_usage = process_metrics_->GetPlatformIndependentCPUUsage();
   min_cpu_usage_ = std::min(min_cpu_usage_, cpu_usage);
   accumulated_cpu_usage_ += cpu_usage;
 
@@ -74,9 +74,15 @@
 
 void ProcessMetricsHistory::RunPerformanceTriggers() {
   // As an initial step, we only care about browser processes.
-  if (process_type_ != content::PROCESS_TYPE_BROWSER)
+  if (process_type_ != content::PROCESS_TYPE_BROWSER || sample_count_ == 0)
     return;
 
+  // We scale up to the equivalent of 64 CPU cores fully loaded. More than this
+  // doesn't really matter, as we're already in a terrible place.
+  UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.BrowserProcess",
+                              accumulated_cpu_usage_ / sample_count_,
+                              0, 6400, 50);
+
   // If CPU usage has consistently been above our threshold,
   // we *may* have an issue.
   if (min_cpu_usage_ > kHighCPUUtilizationThreshold)
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 9f7b799..38525fe 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -49,13 +49,7 @@
   if (!plugin.name.empty())
     return plugin.name;
 
-  base::FilePath::StringType path =
-      plugin.path.BaseName().RemoveExtension().value();
-#if defined(OS_POSIX)
-  return UTF8ToUTF16(path);
-#elif defined(OS_WIN)
-  return WideToUTF16(path);
-#endif
+  return plugin.path.BaseName().RemoveExtension().AsUTF16Unsafe();
 }
 
 void LoadMimeTypes(bool matching_mime_types,
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index d75fe33..83cc51f 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -173,21 +173,25 @@
 
 void PluginInfoMessageFilter::OnIsInternalPluginRegisteredForMimeType(
     const std::string& mime_type,
-    bool* is_registered) {
-   std::vector<WebPluginInfo> plugins;
-   PluginService::GetInstance()->GetInternalPlugins(&plugins);
-   for (size_t i = 0; i < plugins.size(); ++i) {
-     const std::vector<content::WebPluginMimeType>& mime_types =
-         plugins[i].mime_types;
-     for (size_t j = 0; j < mime_types.size(); ++j) {
-       if (mime_types[j].mime_type == mime_type) {
-         *is_registered = true;
-         return;
-       }
-     }
-   }
+    bool* is_registered,
+    std::vector<base::string16>* additional_param_names,
+    std::vector<base::string16>* additional_param_values) {
+  std::vector<WebPluginInfo> plugins;
+  PluginService::GetInstance()->GetInternalPlugins(&plugins);
+  for (size_t i = 0; i < plugins.size(); ++i) {
+    const std::vector<content::WebPluginMimeType>& mime_types =
+        plugins[i].mime_types;
+    for (size_t j = 0; j < mime_types.size(); ++j) {
+      if (mime_types[j].mime_type == mime_type) {
+        *is_registered = true;
+        *additional_param_names = mime_types[j].additional_param_names;
+        *additional_param_values = mime_types[j].additional_param_values;
+        return;
+      }
+    }
+  }
 
-   *is_registered = false;
+  *is_registered = false;
 }
 
 void PluginInfoMessageFilter::Context::DecidePluginStatus(
diff --git a/chrome/browser/plugins/plugin_info_message_filter.h b/chrome/browser/plugins/plugin_info_message_filter.h
index bfdece0..0f961a5 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.h
+++ b/chrome/browser/plugins/plugin_info_message_filter.h
@@ -103,8 +103,14 @@
   // Returns whether any internal plugin supporting |mime_type| is registered.
   // Does not determine whether the plugin can actually be instantiated
   // (e.g. whether it is allowed or has all its dependencies).
-  void OnIsInternalPluginRegisteredForMimeType(const std::string& mime_type,
-                                               bool* is_registered);
+  // When the returned *|is_registered| is true, |additional_param_names| and
+  // |additional_param_values| contain the name-value pairs, if any, specified
+  // for the *first* plugin found that is registered for |mime_type|.
+  void OnIsInternalPluginRegisteredForMimeType(
+      const std::string& mime_type,
+      bool* is_registered,
+      std::vector<base::string16>* additional_param_names,
+      std::vector<base::string16>* additional_param_values);
 
   Context context_;
 
diff --git a/chrome/browser/plugins/plugin_prefs.cc b/chrome/browser/plugins/plugin_prefs.cc
index a88e151..73b390c 100644
--- a/chrome/browser/plugins/plugin_prefs.cc
+++ b/chrome/browser/plugins/plugin_prefs.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/plugins/plugin_installer.h"
 #include "chrome/browser/plugins/plugin_metadata.h"
 #include "chrome/browser/plugins/plugin_prefs_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_content_client.h"
diff --git a/chrome/browser/policy/DEPS b/chrome/browser/policy/DEPS
index 0532c01..b7f2536 100644
--- a/chrome/browser/policy/DEPS
+++ b/chrome/browser/policy/DEPS
@@ -9,12 +9,17 @@
   "-chromeos",
   "-content",
   "+chrome/browser/policy",
+  "+components/json_schema",
 ]
 
 specific_include_rules = {
   # These files will stay.
   r"(browser_policy_connector|"
   r"configuration_policy_handler_list|"
+  r"file_selection_dialogs_policy_handler|"
+  r"file_selection_dialogs_policy_handler_unittest|"
+  r"javascript_policy_handler|"
+  r"javascript_policy_handler_unittest|"
   r"managed_mode_policy_provider|"
   r"policy_browsertest|"
   r"policy_path_parser|"
@@ -26,7 +31,9 @@
   r"profile_policy_connector|"
   r"profile_policy_connector_factory|"
   r"url_blacklist_manager|"
-  r"url_blacklist_manager_unittest)"
+  r"url_blacklist_manager_unittest|"
+  r"url_blacklist_policy_handler|"
+  r"url_blacklist_policy_handler_unittest)"
   r"\.(cc|h)": [
     "+chrome",
     "+chromeos",
@@ -45,17 +52,9 @@
   r"configuration_policy_handler\.cc": [
     "+chrome/browser/chrome_notification_types.h",
     "+chrome/browser/policy/policy_path_parser.h",
-    "+chrome/browser/prefs/session_startup_pref.h",
-  ],
-
-  r"configuration_policy_handler\.h": [
-    "+chrome/browser/prefs/incognito_mode_prefs.h",
-    "+chrome/common/content_settings.h",
   ],
 
   r"configuration_policy_pref_store_unittest\.cc": [
-    "+chrome/browser/prefs/incognito_mode_prefs.h",
-    "+chrome/common/content_settings.h",
     "+chrome/common/pref_names.h",
   ],
 }
diff --git a/chrome/browser/policy/async_policy_loader.h b/chrome/browser/policy/async_policy_loader.h
index 2da0a33..57f346c 100644
--- a/chrome/browser/policy/async_policy_loader.h
+++ b/chrome/browser/policy/async_policy_loader.h
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace base {
 class SequencedTaskRunner;
diff --git a/chrome/browser/policy/autofill_policy_handler.cc b/chrome/browser/policy/autofill_policy_handler.cc
new file mode 100644
index 0000000..e996497
--- /dev/null
+++ b/chrome/browser/policy/autofill_policy_handler.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 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/policy/autofill_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+AutofillPolicyHandler::AutofillPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kAutoFillEnabled,
+                                base::Value::TYPE_BOOLEAN) {}
+
+AutofillPolicyHandler::~AutofillPolicyHandler() {
+}
+
+void AutofillPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+                                                PrefValueMap* prefs) {
+  const base::Value* value = policies.GetValue(policy_name());
+  bool auto_fill_enabled;
+  if (value && value->GetAsBoolean(&auto_fill_enabled) && !auto_fill_enabled) {
+    prefs->SetValue(autofill::prefs::kAutofillEnabled,
+                    base::Value::CreateBooleanValue(false));
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/autofill_policy_handler.h b/chrome/browser/policy/autofill_policy_handler.h
new file mode 100644
index 0000000..a43908a
--- /dev/null
+++ b/chrome/browser/policy/autofill_policy_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2013 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_POLICY_AUTOFILL_POLICY_HANDLER_H_
+#define CHROME_BROWSER_POLICY_AUTOFILL_POLICY_HANDLER_H_
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace policy {
+
+class PolicyMap;
+
+// ConfigurationPolicyHandler for the AutofillEnabled policy.
+class AutofillPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  AutofillPolicyHandler();
+  virtual ~AutofillPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_AUTOFILL_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/autofill_policy_handler_unittest.cc b/chrome/browser/policy/autofill_policy_handler_unittest.cc
new file mode 100644
index 0000000..218c8e4
--- /dev/null
+++ b/chrome/browser/policy/autofill_policy_handler_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 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/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/autofill_policy_handler.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+// Test cases for the Autofill policy setting.
+class AutofillPolicyHandlerTest : public testing::Test {};
+
+TEST_F(AutofillPolicyHandlerTest, Default) {
+  PolicyMap policy;
+  PrefValueMap prefs;
+  AutofillPolicyHandler handler;
+  handler.ApplyPolicySettings(policy, &prefs);
+  EXPECT_FALSE(prefs.GetValue(autofill::prefs::kAutofillEnabled, NULL));
+}
+
+TEST_F(AutofillPolicyHandlerTest, Enabled) {
+  PolicyMap policy;
+  policy.Set(key::kAutoFillEnabled,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(true),
+             NULL);
+  PrefValueMap prefs;
+  AutofillPolicyHandler handler;
+  handler.ApplyPolicySettings(policy, &prefs);
+
+  // Enabling Autofill should not set the pref.
+  EXPECT_FALSE(prefs.GetValue(autofill::prefs::kAutofillEnabled, NULL));
+}
+
+TEST_F(AutofillPolicyHandlerTest, Disabled) {
+  PolicyMap policy;
+  policy.Set(key::kAutoFillEnabled,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(false),
+             NULL);
+  PrefValueMap prefs;
+  AutofillPolicyHandler handler;
+  handler.ApplyPolicySettings(policy, &prefs);
+
+  // Disabling Autofill should switch the pref to managed.
+  const base::Value* value = NULL;
+  EXPECT_TRUE(prefs.GetValue(autofill::prefs::kAutofillEnabled, &value));
+  ASSERT_TRUE(value);
+  bool autofill_enabled = true;
+  bool result = value->GetAsBoolean(&autofill_enabled);
+  ASSERT_TRUE(result);
+  EXPECT_FALSE(autofill_enabled);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index 4d99d09..a405c31 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -98,6 +98,11 @@
 const char kDefaultDeviceManagementServerUrl[] =
     "https://m.google.com/devicemanagement/data/api";
 
+#if defined(OS_CHROMEOS)
+// Install attributes for tests.
+EnterpriseInstallAttributes* g_testing_install_attributes = NULL;
+#endif  // defined(OS_CHROMEOS)
+
 // Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
 ConfigurationPolicyProvider* g_testing_provider = NULL;
 
@@ -200,6 +205,7 @@
 BrowserPolicyConnector::BrowserPolicyConnector()
     : is_initialized_(false),
       local_state_(NULL),
+      handler_list_(BuildHandlerList().Pass()),
       weak_ptr_factory_(this) {
   // GetPolicyService() must be ready after the constructor is done.
   // The connector is created very early during startup, when the browser
@@ -209,6 +215,9 @@
   platform_provider_.reset(CreatePlatformProvider());
 
 #if defined(OS_CHROMEOS)
+  if (g_testing_install_attributes)
+    install_attributes_.reset(g_testing_install_attributes);
+
   // SystemSaltGetter or DBusThreadManager may be uninitialized on unit tests.
 
   // TODO(satorux): Remove SystemSaltGetter::IsInitialized() when it's ready
@@ -217,8 +226,10 @@
       chromeos::DBusThreadManager::IsInitialized()) {
     chromeos::CryptohomeClient* cryptohome_client =
         chromeos::DBusThreadManager::Get()->GetCryptohomeClient();
-    install_attributes_.reset(
-        new EnterpriseInstallAttributes(cryptohome_client));
+    if (!g_testing_install_attributes) {
+      install_attributes_.reset(
+          new EnterpriseInstallAttributes(cryptohome_client));
+    }
     base::FilePath install_attrs_file;
     CHECK(PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES,
                            &install_attrs_file));
@@ -415,7 +426,7 @@
 
 const ConfigurationPolicyHandlerList*
     BrowserPolicyConnector::GetHandlerList() const {
-  return &handler_list_;
+  return handler_list_.get();
 }
 
 UserAffiliation BrowserPolicyConnector::GetUserAffiliation(
@@ -452,6 +463,12 @@
     ConfigurationPolicyProvider* user_policy_provider) {
   global_user_cloud_policy_provider_.SetDelegate(user_policy_provider);
 }
+
+void BrowserPolicyConnector::SetInstallAttributesForTesting(
+    EnterpriseInstallAttributes* attributes) {
+  DCHECK(!g_testing_install_attributes);
+  g_testing_install_attributes = attributes;
+}
 #endif
 
 // static
diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h
index b72b4e5..733b516 100644
--- a/chrome/browser/policy/browser_policy_connector.h
+++ b/chrome/browser/policy/browser_policy_connector.h
@@ -130,6 +130,11 @@
   // previously set delegate is removed. Passing NULL removes the current
   // delegate, if there is one.
   void SetUserPolicyDelegate(ConfigurationPolicyProvider* user_policy_provider);
+
+  // Sets the install attributes for testing. Must be called before the browser
+  // is created. Takes ownership of |attributes|.
+  static void SetInstallAttributesForTesting(
+      EnterpriseInstallAttributes* attributes);
 #endif
 
   // Sets a |provider| that will be included in PolicyServices returned by
@@ -165,7 +170,7 @@
   // may trigger policy updates during shutdown, which will result in
   // |handler_list_| being consulted for policy translation.
   // Therefore, it's important to destroy |handler_list_| after the providers.
-  ConfigurationPolicyHandlerList handler_list_;
+  scoped_ptr<ConfigurationPolicyHandlerList> handler_list_;
 
   scoped_ptr<ConfigurationPolicyProvider> platform_provider_;
 
diff --git a/chrome/browser/policy/cloud/DEPS b/chrome/browser/policy/cloud/DEPS
index cab579f..a91f2ca 100644
--- a/chrome/browser/policy/cloud/DEPS
+++ b/chrome/browser/policy/cloud/DEPS
@@ -18,6 +18,7 @@
   r"cloud_policy_manager_browsertest|"
   r"component_cloud_policy_browsertest|"
   r"device_management_service_browsertest|"
+  r"test_request_interceptor|"
   r"user_policy_signin_service_android|"
   r"user_policy_signin_service_base|"
   r"user_policy_signin_service|"
@@ -49,10 +50,6 @@
     "+chrome/browser/invalidation/fake_invalidation_service.h",
   ],
 
-  r"test_request_interceptor\.cc": [
-    "+content/test/net/url_request_mock_http_job.h",
-  ],
-
   r"user_cloud_policy_invalidator\.cc": [
     "+chrome/browser/chrome_notification_types.h",
     "+chrome/browser/invalidation/invalidation_service_factory.h",
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_service.h b/chrome/browser/policy/cloud/component_cloud_policy_service.h
index dbe3913..876739c 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_service.h
+++ b/chrome/browser/policy/cloud/component_cloud_policy_service.h
@@ -18,7 +18,7 @@
 #include "chrome/browser/policy/cloud/cloud_policy_client.h"
 #include "chrome/browser/policy/cloud/cloud_policy_store.h"
 #include "chrome/browser/policy/policy_bundle.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace base {
 class SequencedTaskRunner;
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_store.h b/chrome/browser/policy/cloud/component_cloud_policy_store.h
index 5b4a0bc..3e5285e 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_store.h
+++ b/chrome/browser/policy/cloud/component_cloud_policy_store.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/policy/policy_bundle.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace enterprise_management {
 class ExternalPolicyData;
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_updater.cc b/chrome/browser/policy/cloud/component_cloud_policy_updater.cc
index 5423361..28c4d68 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_updater.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_updater.cc
@@ -13,9 +13,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/policy/cloud/component_cloud_policy_store.h"
 #include "chrome/browser/policy/cloud/external_policy_data_fetcher.h"
-#include "chrome/browser/policy/policy_service.h"
 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace em = enterprise_management;
 
diff --git a/chrome/browser/policy/cloud/enterprise_metrics.h b/chrome/browser/policy/cloud/enterprise_metrics.h
index bb33453..1b0c920 100644
--- a/chrome/browser/policy/cloud/enterprise_metrics.h
+++ b/chrome/browser/policy/cloud/enterprise_metrics.h
@@ -152,9 +152,15 @@
   // DM server reported that the licenses for the domain has expired or been
   // exhausted.
   kMetricMissingLicensesError,
-  // Enrollment failed because the robot account auth token couldn't be
+  // Enrollment failed because the robot account auth code couldn't be
+  // fetched from the DM Server.
+  kMetricEnrollmentRobotAuthCodeFetchFailed,
+  // Enrollment failed because the robot account auth code couldn't be
   // exchanged for a refresh token.
   kMetricEnrollmentRobotRefreshTokenFetchFailed,
+  // Enrollment failed because the robot account refresh token couldn't be
+  // persisted on the device.
+  kMetricEnrollmentRobotRefreshTokenStoreFailed,
 
   kMetricEnrollmentSize  // Must be the last.
 };
diff --git a/chrome/browser/policy/configuration_policy_handler.cc b/chrome/browser/policy/configuration_policy_handler.cc
index b1565be..1a8780f 100644
--- a/chrome/browser/policy/configuration_policy_handler.cc
+++ b/chrome/browser/policy/configuration_policy_handler.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/policy/external_data_fetcher.h"
 #include "chrome/browser/policy/policy_error_map.h"
 #include "chrome/browser/policy/policy_map.h"
-#include "chrome/browser/prefs/session_startup_pref.h"
 #include "grit/generated_resources.h"
 #include "policy/policy_constants.h"
 #include "url/gurl.h"
@@ -347,41 +346,6 @@
 }
 
 
-// SyncPolicyHandler implementation --------------------------------------------
-
-SyncPolicyHandler::SyncPolicyHandler(const char* pref_name)
-    : TypeCheckingPolicyHandler(key::kSyncDisabled, Value::TYPE_BOOLEAN),
-      pref_name_(pref_name) {}
-
-SyncPolicyHandler::~SyncPolicyHandler() {
-}
-
-void SyncPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                            PrefValueMap* prefs) {
-  const Value* value = policies.GetValue(policy_name());
-  bool disable_sync;
-  if (value && value->GetAsBoolean(&disable_sync) && disable_sync)
-    prefs->SetValue(pref_name_, value->DeepCopy());
-}
-
-
-// AutofillPolicyHandler implementation ----------------------------------------
-
-AutofillPolicyHandler::AutofillPolicyHandler(const char* pref_name)
-    : TypeCheckingPolicyHandler(key::kAutoFillEnabled, Value::TYPE_BOOLEAN),
-      pref_name_(pref_name) {}
-
-AutofillPolicyHandler::~AutofillPolicyHandler() {
-}
-
-void AutofillPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                                PrefValueMap* prefs) {
-  const Value* value = policies.GetValue(policy_name());
-  bool auto_fill_enabled;
-  if (value && value->GetAsBoolean(&auto_fill_enabled) && !auto_fill_enabled)
-    prefs->SetValue(pref_name_, Value::CreateBooleanValue(false));
-}
-
 // Android doesn't support these policies, and doesn't have a policy_path_parser
 // implementation.
 #if !defined(OS_ANDROID)
@@ -408,352 +372,4 @@
 
 #endif  // !defined(OS_ANDROID)
 
-
-// FileSelectionDialogsHandler implementation ----------------------------------
-
-FileSelectionDialogsHandler::FileSelectionDialogsHandler(
-    const char* allow_dialogs_pref_name,
-    const char* prompt_for_download_pref_name)
-    : TypeCheckingPolicyHandler(key::kAllowFileSelectionDialogs,
-                                Value::TYPE_BOOLEAN),
-      allow_dialogs_pref_name_(allow_dialogs_pref_name),
-      prompt_for_download_pref_name_(prompt_for_download_pref_name) {}
-
-FileSelectionDialogsHandler::~FileSelectionDialogsHandler() {
-}
-
-void FileSelectionDialogsHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                                      PrefValueMap* prefs) {
-  bool allow_dialogs;
-  const Value* value = policies.GetValue(policy_name());
-  if (value && value->GetAsBoolean(&allow_dialogs)) {
-    prefs->SetValue(allow_dialogs_pref_name_,
-                    Value::CreateBooleanValue(allow_dialogs));
-    // Disallow selecting the download location if file dialogs are disabled.
-    if (!allow_dialogs) {
-      prefs->SetValue(prompt_for_download_pref_name_,
-                      Value::CreateBooleanValue(false));
-    }
-  }
-}
-
-
-// IncognitoModePolicyHandler implementation -----------------------------------
-
-IncognitoModePolicyHandler::IncognitoModePolicyHandler(const char* pref_name)
-    : pref_name_(pref_name) {}
-
-IncognitoModePolicyHandler::~IncognitoModePolicyHandler() {
-}
-
-bool IncognitoModePolicyHandler::CheckPolicySettings(const PolicyMap& policies,
-                                                     PolicyErrorMap* errors) {
-  int int_value = IncognitoModePrefs::ENABLED;
-  const Value* availability =
-      policies.GetValue(key::kIncognitoModeAvailability);
-
-  if (availability) {
-    if (availability->GetAsInteger(&int_value)) {
-      IncognitoModePrefs::Availability availability_enum_value;
-      if (!IncognitoModePrefs::IntToAvailability(int_value,
-                                                 &availability_enum_value)) {
-        errors->AddError(key::kIncognitoModeAvailability,
-                         IDS_POLICY_OUT_OF_RANGE_ERROR,
-                         base::IntToString(int_value));
-        return false;
-      }
-    } else {
-      errors->AddError(key::kIncognitoModeAvailability,
-                       IDS_POLICY_TYPE_ERROR,
-                       ValueTypeToString(Value::TYPE_INTEGER));
-      return false;
-    }
-  } else {
-    const Value* deprecated_enabled = policies.GetValue(key::kIncognitoEnabled);
-    if (deprecated_enabled &&
-        !deprecated_enabled->IsType(Value::TYPE_BOOLEAN)) {
-      errors->AddError(key::kIncognitoEnabled,
-                       IDS_POLICY_TYPE_ERROR,
-                       ValueTypeToString(Value::TYPE_BOOLEAN));
-      return false;
-    }
-  }
-  return true;
-}
-
-void IncognitoModePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                                     PrefValueMap* prefs) {
-  const Value* availability =
-      policies.GetValue(key::kIncognitoModeAvailability);
-  const Value* deprecated_enabled = policies.GetValue(key::kIncognitoEnabled);
-  if (availability) {
-    int int_value = IncognitoModePrefs::ENABLED;
-    IncognitoModePrefs::Availability availability_enum_value;
-    if (availability->GetAsInteger(&int_value) &&
-        IncognitoModePrefs::IntToAvailability(int_value,
-                                              &availability_enum_value)) {
-      prefs->SetValue(pref_name_,
-                      Value::CreateIntegerValue(availability_enum_value));
-    } else {
-      NOTREACHED();
-    }
-  } else if (deprecated_enabled) {
-    // If kIncognitoModeAvailability is not specified, check the obsolete
-    // kIncognitoEnabled.
-    bool enabled = true;
-    if (deprecated_enabled->GetAsBoolean(&enabled)) {
-      prefs->SetInteger(
-          pref_name_,
-          enabled ? IncognitoModePrefs::ENABLED : IncognitoModePrefs::DISABLED);
-    } else {
-      NOTREACHED();
-    }
-  }
-}
-
-
-// JavascriptPolicyHandler implementation --------------------------------------
-
-JavascriptPolicyHandler::JavascriptPolicyHandler(const char* pref_name)
-    : pref_name_(pref_name) {}
-
-JavascriptPolicyHandler::~JavascriptPolicyHandler() {
-}
-
-bool JavascriptPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
-                                                  PolicyErrorMap* errors) {
-  const Value* javascript_enabled = policies.GetValue(key::kJavascriptEnabled);
-  const Value* default_setting =
-      policies.GetValue(key::kDefaultJavaScriptSetting);
-
-  if (javascript_enabled && !javascript_enabled->IsType(Value::TYPE_BOOLEAN)) {
-    errors->AddError(key::kJavascriptEnabled,
-                     IDS_POLICY_TYPE_ERROR,
-                     ValueTypeToString(Value::TYPE_BOOLEAN));
-  }
-
-  if (default_setting && !default_setting->IsType(Value::TYPE_INTEGER)) {
-    errors->AddError(key::kDefaultJavaScriptSetting,
-                     IDS_POLICY_TYPE_ERROR,
-                     ValueTypeToString(Value::TYPE_INTEGER));
-  }
-
-  if (javascript_enabled && default_setting) {
-    errors->AddError(key::kJavascriptEnabled,
-                     IDS_POLICY_OVERRIDDEN,
-                     key::kDefaultJavaScriptSetting);
-  }
-
-  return true;
-}
-
-void JavascriptPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                                  PrefValueMap* prefs) {
-  int setting = CONTENT_SETTING_DEFAULT;
-  const Value* default_setting =
-      policies.GetValue(key::kDefaultJavaScriptSetting);
-
-  if (default_setting) {
-    default_setting->GetAsInteger(&setting);
-  } else {
-    const Value* javascript_enabled =
-        policies.GetValue(key::kJavascriptEnabled);
-    bool enabled = true;
-    if (javascript_enabled &&
-        javascript_enabled->GetAsBoolean(&enabled) &&
-        !enabled) {
-      setting = CONTENT_SETTING_BLOCK;
-    }
-  }
-
-  if (setting != CONTENT_SETTING_DEFAULT)
-    prefs->SetValue(pref_name_, Value::CreateIntegerValue(setting));
-}
-
-
-// URLBlacklistPolicyHandler implementation ------------------------------------
-
-URLBlacklistPolicyHandler::URLBlacklistPolicyHandler(const char* pref_name)
-    : pref_name_(pref_name) {}
-
-URLBlacklistPolicyHandler::~URLBlacklistPolicyHandler() {
-}
-
-bool URLBlacklistPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
-                                                    PolicyErrorMap* errors) {
-  const Value* disabled_schemes = policies.GetValue(key::kDisabledSchemes);
-  const Value* url_blacklist = policies.GetValue(key::kURLBlacklist);
-
-  if (disabled_schemes && !disabled_schemes->IsType(Value::TYPE_LIST)) {
-    errors->AddError(key::kDisabledSchemes,
-                     IDS_POLICY_TYPE_ERROR,
-                     ValueTypeToString(Value::TYPE_LIST));
-  }
-
-  if (url_blacklist && !url_blacklist->IsType(Value::TYPE_LIST)) {
-      errors->AddError(key::kURLBlacklist,
-                       IDS_POLICY_TYPE_ERROR,
-                       ValueTypeToString(Value::TYPE_LIST));
-  }
-
-  return true;
-}
-
-void URLBlacklistPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
-                                                    PrefValueMap* prefs) {
-  const base::Value* url_blacklist_policy =
-      policies.GetValue(key::kURLBlacklist);
-  const base::ListValue* url_blacklist = NULL;
-  if (url_blacklist_policy)
-    url_blacklist_policy->GetAsList(&url_blacklist);
-  const base::Value* disabled_schemes_policy =
-      policies.GetValue(key::kDisabledSchemes);
-  const base::ListValue* disabled_schemes = NULL;
-  if (disabled_schemes_policy)
-    disabled_schemes_policy->GetAsList(&disabled_schemes);
-
-  scoped_ptr<base::ListValue> merged_url_blacklist(new base::ListValue());
-
-  // We start with the DisabledSchemes because we have size limit when
-  // handling URLBacklists.
-  if (disabled_schemes_policy) {
-    for (base::ListValue::const_iterator entry(disabled_schemes->begin());
-         entry != disabled_schemes->end(); ++entry) {
-      std::string entry_value;
-      if ((*entry)->GetAsString(&entry_value)) {
-        entry_value.append("://*");
-        merged_url_blacklist->AppendString(entry_value);
-      }
-    }
-  }
-
-  if (url_blacklist_policy) {
-    for (base::ListValue::const_iterator entry(url_blacklist->begin());
-         entry != url_blacklist->end(); ++entry) {
-      if ((*entry)->IsType(Value::TYPE_STRING))
-        merged_url_blacklist->Append((*entry)->DeepCopy());
-    }
-  }
-
-  if (disabled_schemes_policy || url_blacklist_policy)
-    prefs->SetValue(pref_name_, merged_url_blacklist.release());
-}
-
-
-// RestoreOnStartupPolicyHandler implementation --------------------------------
-
-RestoreOnStartupPolicyHandler::RestoreOnStartupPolicyHandler(
-    const char* restore_on_startup_pref_name,
-    const char* startup_url_list_pref_name)
-    : TypeCheckingPolicyHandler(key::kRestoreOnStartup, Value::TYPE_INTEGER),
-      restore_on_startup_pref_name_(restore_on_startup_pref_name),
-      startup_url_list_pref_name_(startup_url_list_pref_name) {}
-
-RestoreOnStartupPolicyHandler::~RestoreOnStartupPolicyHandler() {
-}
-
-void RestoreOnStartupPolicyHandler::ApplyPolicySettings(
-    const PolicyMap& policies,
-    PrefValueMap* prefs) {
-  const Value* restore_on_startup_value = policies.GetValue(policy_name());
-  if (restore_on_startup_value) {
-    int restore_on_startup;
-    if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
-      return;
-
-    if (restore_on_startup == SessionStartupPref::kPrefValueHomePage)
-      ApplyPolicySettingsFromHomePage(policies, prefs);
-    else
-      prefs->SetInteger(restore_on_startup_pref_name_, restore_on_startup);
-  }
-}
-
-void RestoreOnStartupPolicyHandler::ApplyPolicySettingsFromHomePage(
-    const PolicyMap& policies,
-    PrefValueMap* prefs) {
-  const base::Value* homepage_is_new_tab_page_value =
-      policies.GetValue(key::kHomepageIsNewTabPage);
-  if (!homepage_is_new_tab_page_value) {
-    // The policy is enforcing 'open the homepage on startup' but not
-    // enforcing what the homepage should be. Don't set any prefs.
-    return;
-  }
-
-  bool homepage_is_new_tab_page;
-  if (!homepage_is_new_tab_page_value->GetAsBoolean(&homepage_is_new_tab_page))
-    return;
-
-  if (homepage_is_new_tab_page) {
-    prefs->SetInteger(restore_on_startup_pref_name_,
-                      SessionStartupPref::kPrefValueNewTab);
-  } else {
-    const base::Value* homepage_value =
-        policies.GetValue(key::kHomepageLocation);
-    if (!homepage_value || !homepage_value->IsType(base::Value::TYPE_STRING)) {
-      // The policy is enforcing 'open the homepage on startup' but not
-      // enforcing what the homepage should be. Don't set any prefs.
-      return;
-    }
-    ListValue* url_list = new ListValue();
-    url_list->Append(homepage_value->DeepCopy());
-    prefs->SetInteger(restore_on_startup_pref_name_,
-                      SessionStartupPref::kPrefValueURLs);
-    prefs->SetValue(startup_url_list_pref_name_, url_list);
-  }
-}
-
-bool RestoreOnStartupPolicyHandler::CheckPolicySettings(
-    const PolicyMap& policies,
-    PolicyErrorMap* errors) {
-  if (!TypeCheckingPolicyHandler::CheckPolicySettings(policies, errors))
-    return false;
-
-  const base::Value* restore_policy = policies.GetValue(key::kRestoreOnStartup);
-
-  if (restore_policy) {
-    int restore_value;
-    if (restore_policy->GetAsInteger(&restore_value)) {
-      switch (restore_value) {
-        case SessionStartupPref::kPrefValueHomePage:
-          errors->AddError(policy_name(), IDS_POLICY_VALUE_DEPRECATED);
-          break;
-        case SessionStartupPref::kPrefValueLast: {
-          // If the "restore last session" policy is set, session cookies are
-          // treated as permanent cookies and site data needed to restore the
-          // session is not cleared so we have to warn the user in that case.
-          const base::Value* cookies_policy =
-              policies.GetValue(key::kCookiesSessionOnlyForUrls);
-          const base::ListValue *cookies_value;
-          if (cookies_policy && cookies_policy->GetAsList(&cookies_value) &&
-              !cookies_value->empty()) {
-            errors->AddError(key::kCookiesSessionOnlyForUrls,
-                             IDS_POLICY_OVERRIDDEN,
-                             key::kRestoreOnStartup);
-          }
-
-          const base::Value* exit_policy =
-              policies.GetValue(key::kClearSiteDataOnExit);
-          bool exit_value;
-          if (exit_policy &&
-              exit_policy->GetAsBoolean(&exit_value) && exit_value) {
-            errors->AddError(key::kClearSiteDataOnExit,
-                             IDS_POLICY_OVERRIDDEN,
-                             key::kRestoreOnStartup);
-          }
-          break;
-        }
-        case SessionStartupPref::kPrefValueURLs:
-        case SessionStartupPref::kPrefValueNewTab:
-          // No error
-          break;
-        default:
-          errors->AddError(policy_name(),
-                           IDS_POLICY_OUT_OF_RANGE_ERROR,
-                           base::IntToString(restore_value));
-      }
-    }
-  }
-  return true;
-}
-
 }  // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_handler.h b/chrome/browser/policy/configuration_policy_handler.h
index 668be54..8e1b420 100644
--- a/chrome/browser/policy/configuration_policy_handler.h
+++ b/chrome/browser/policy/configuration_policy_handler.h
@@ -11,8 +11,6 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/common/content_settings.h"
 
 class PrefValueMap;
 
@@ -228,36 +226,6 @@
   DISALLOW_COPY_AND_ASSIGN(IntPercentageToDoublePolicyHandler);
 };
 
-// ConfigurationPolicyHandler for the SyncDisabled policy.
-class SyncPolicyHandler : public TypeCheckingPolicyHandler {
- public:
-  explicit SyncPolicyHandler(const char* pref_name);
-  virtual ~SyncPolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  const char* pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(SyncPolicyHandler);
-};
-
-// ConfigurationPolicyHandler for the AutofillEnabled policy.
-class AutofillPolicyHandler : public TypeCheckingPolicyHandler {
- public:
-  explicit AutofillPolicyHandler(const char* pref_name);
-  virtual ~AutofillPolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  const char* pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(AutofillPolicyHandler);
-};
-
 #if !defined(OS_ANDROID)
 
 // ConfigurationPolicyHandler for the DiskCacheDir policy.
@@ -277,99 +245,6 @@
 
 #endif  // !defined(OS_ANDROID)
 
-// ConfigurationPolicyHandler for the FileSelectionDialogsHandler policy.
-class FileSelectionDialogsHandler : public TypeCheckingPolicyHandler {
- public:
-  FileSelectionDialogsHandler(const char* allow_dialogs_pref_name,
-                              const char* prompt_for_download_pref_name);
-  virtual ~FileSelectionDialogsHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  const char* allow_dialogs_pref_name_;
-  const char* prompt_for_download_pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(FileSelectionDialogsHandler);
-};
-
-// ConfigurationPolicyHandler for the incognito mode policies.
-class IncognitoModePolicyHandler : public ConfigurationPolicyHandler {
- public:
-  explicit IncognitoModePolicyHandler(const char* pref_name);
-  virtual ~IncognitoModePolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual bool CheckPolicySettings(const PolicyMap& policies,
-                                   PolicyErrorMap* errors) OVERRIDE;
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  IncognitoModePrefs::Availability GetAvailabilityValueAsEnum(
-      const Value* availability);
-
-  const char* pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(IncognitoModePolicyHandler);
-};
-
-// Handles JavaScript policies.
-class JavascriptPolicyHandler : public ConfigurationPolicyHandler {
- public:
-  explicit JavascriptPolicyHandler(const char* pref_name);
-  virtual ~JavascriptPolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual bool CheckPolicySettings(const PolicyMap& policies,
-                                   PolicyErrorMap* errors) OVERRIDE;
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  const char* pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(JavascriptPolicyHandler);
-};
-
-// Handles URLBlacklist policies.
-class URLBlacklistPolicyHandler : public ConfigurationPolicyHandler {
- public:
-  explicit URLBlacklistPolicyHandler(const char* pref_name);
-  virtual ~URLBlacklistPolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual bool CheckPolicySettings(const PolicyMap& policies,
-                                   PolicyErrorMap* errors) OVERRIDE;
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  const char* pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(URLBlacklistPolicyHandler);
-};
-
-// Handles RestoreOnStartup policy.
-class RestoreOnStartupPolicyHandler : public TypeCheckingPolicyHandler {
- public:
-  RestoreOnStartupPolicyHandler(const char* restore_on_startup_pref_name,
-                                const char* startup_url_list_pref_name);
-  virtual ~RestoreOnStartupPolicyHandler();
-
-  // ConfigurationPolicyHandler methods:
-  virtual bool CheckPolicySettings(const PolicyMap& policies,
-                                   PolicyErrorMap* errors) OVERRIDE;
-  virtual void ApplyPolicySettings(const PolicyMap& policies,
-                                   PrefValueMap* prefs) OVERRIDE;
-
- private:
-  void ApplyPolicySettingsFromHomePage(const PolicyMap& policies,
-                                       PrefValueMap* prefs);
-
-  const char* restore_on_startup_pref_name_;
-  const char* startup_url_list_pref_name_;
-  DISALLOW_COPY_AND_ASSIGN(RestoreOnStartupPolicyHandler);
-};
-
 }  // namespace policy
 
 #endif  // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index 47d7a15..30b1489 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -12,10 +12,17 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/policy_handlers.h"
 #include "chrome/browser/net/proxy_policy_handler.h"
+#include "chrome/browser/policy/autofill_policy_handler.h"
 #include "chrome/browser/policy/configuration_policy_handler.h"
+#include "chrome/browser/policy/file_selection_dialogs_policy_handler.h"
+#include "chrome/browser/policy/javascript_policy_handler.h"
 #include "chrome/browser/policy/policy_error_map.h"
 #include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/url_blacklist_policy_handler.h"
+#include "chrome/browser/profiles/incognito_mode_policy_handler.h"
 #include "chrome/browser/search_engines/default_search_policy_handler.h"
+#include "chrome/browser/sessions/restore_on_startup_policy_handler.h"
+#include "chrome/browser/sync/sync_policy_handler.h"
 #include "chrome/common/pref_names.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "extensions/common/manifest.h"
@@ -379,6 +386,9 @@
   { key::kSessionLengthLimit,
     prefs::kSessionLengthLimit,
     Value::TYPE_INTEGER },
+  { key::kWaitForInitialUserActivity,
+    prefs::kSessionWaitForInitialUserActivity,
+    Value::TYPE_BOOLEAN },
   { key::kPowerManagementUsesAudioActivity,
     prefs::kPowerUseAudioActivity,
     Value::TYPE_BOOLEAN },
@@ -388,6 +398,9 @@
   { key::kAllowScreenWakeLocks,
     prefs::kPowerAllowScreenWakeLocks,
     Value::TYPE_BOOLEAN },
+  { key::kWaitForInitialUserActivity,
+    prefs::kPowerWaitForInitialUserActivity,
+    Value::TYPE_BOOLEAN },
   { key::kTermsOfServiceURL,
     prefs::kTermsOfServiceURL,
     Value::TYPE_STRING },
@@ -449,162 +462,17 @@
 }  // namespace
 
 ConfigurationPolicyHandlerList::ConfigurationPolicyHandlerList() {
-  for (size_t i = 0; i < arraysize(kSimplePolicyMap); ++i) {
-    handlers_.push_back(
-        new SimplePolicyHandler(kSimplePolicyMap[i].policy_name,
-                                kSimplePolicyMap[i].preference_path,
-                                kSimplePolicyMap[i].value_type));
-  }
-
-  handlers_.push_back(
-      new AutofillPolicyHandler(autofill::prefs::kAutofillEnabled));
-  handlers_.push_back(new DefaultSearchPolicyHandler());
-  handlers_.push_back(new FileSelectionDialogsHandler(
-      prefs::kAllowFileSelectionDialogs, prefs::kPromptForDownload));
-  handlers_.push_back(
-      new IncognitoModePolicyHandler(prefs::kIncognitoModeAvailability));
-  handlers_.push_back(
-      new JavascriptPolicyHandler(prefs::kManagedDefaultJavaScriptSetting));
-  handlers_.push_back(new ProxyPolicyHandler());
-  handlers_.push_back(new RestoreOnStartupPolicyHandler(
-      prefs::kRestoreOnStartup, prefs::kURLsToRestoreOnStartup));
-  handlers_.push_back(new SyncPolicyHandler(prefs::kSyncManaged));
-  handlers_.push_back(new URLBlacklistPolicyHandler(prefs::kUrlBlacklist));
-
-  handlers_.push_back(new extensions::ExtensionListPolicyHandler(
-      key::kExtensionInstallWhitelist,
-      prefs::kExtensionInstallAllowList,
-      false));
-  handlers_.push_back(new extensions::ExtensionListPolicyHandler(
-      key::kExtensionInstallBlacklist, prefs::kExtensionInstallDenyList, true));
-  handlers_.push_back(new extensions::ExtensionInstallForcelistPolicyHandler());
-  handlers_.push_back(new extensions::ExtensionURLPatternListPolicyHandler(
-      key::kExtensionInstallSources, prefs::kExtensionAllowedInstallSites));
-  handlers_.push_back(new StringToIntEnumListPolicyHandler(
-      key::kExtensionAllowedTypes,
-      prefs::kExtensionAllowedTypes,
-      kExtensionAllowedTypesMap,
-      kExtensionAllowedTypesMap + arraysize(kExtensionAllowedTypesMap)));
-#if defined(OS_CHROMEOS)
-  handlers_.push_back(new extensions::ExtensionListPolicyHandler(
-      key::kAttestationExtensionWhitelist,
-      prefs::kAttestationExtensionWhitelist,
-      false));
-#endif  // defined(OS_CHROMEOS)
-
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
-  handlers_.push_back(new DiskCacheDirPolicyHandler(prefs::kDiskCacheDir));
-  handlers_.push_back(new DownloadDirPolicyHandler);
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-
-#if defined(OS_CHROMEOS)
-  handlers_.push_back(
-      NetworkConfigurationPolicyHandler::CreateForDevicePolicy());
-  handlers_.push_back(NetworkConfigurationPolicyHandler::CreateForUserPolicy());
-  handlers_.push_back(new PinnedLauncherAppsPolicyHandler());
-  handlers_.push_back(new ScreenMagnifierPolicyHandler());
-  handlers_.push_back(new LoginScreenPowerManagementPolicyHandler);
-
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenDimDelayAC,
-          prefs::kPowerAcScreenDimDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenOffDelayAC,
-          prefs::kPowerAcScreenOffDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenLockDelayAC,
-          prefs::kPowerAcScreenLockDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleWarningDelayAC,
-          prefs::kPowerAcIdleWarningDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleDelayAC,
-          prefs::kPowerAcIdleDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenDimDelayBattery,
-          prefs::kPowerBatteryScreenDimDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenOffDelayBattery,
-          prefs::kPowerBatteryScreenOffDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kScreenLockDelayBattery,
-          prefs::kPowerBatteryScreenLockDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleWarningDelayBattery,
-          prefs::kPowerBatteryIdleWarningDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleDelayBattery,
-          prefs::kPowerBatteryIdleDelayMs,
-          0, INT_MAX, true));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleActionAC,
-          prefs::kPowerAcIdleAction,
-          chromeos::PowerPolicyController::ACTION_SUSPEND,
-          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
-          false));
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kIdleActionBattery,
-          prefs::kPowerBatteryIdleAction,
-          chromeos::PowerPolicyController::ACTION_SUSPEND,
-          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
-          false));
-  handlers_.push_back(new DeprecatedIdleActionHandler());
-  handlers_.push_back(
-      new IntRangePolicyHandler(
-          key::kLidCloseAction,
-          prefs::kPowerLidClosedAction,
-          chromeos::PowerPolicyController::ACTION_SUSPEND,
-          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
-          false));
-  handlers_.push_back(
-      new IntPercentageToDoublePolicyHandler(
-          key::kPresentationScreenDimDelayScale,
-          prefs::kPowerPresentationScreenDimDelayFactor,
-          100, INT_MAX, true));
-  handlers_.push_back(
-      new IntPercentageToDoublePolicyHandler(
-          key::kUserActivityScreenDimDelayScale,
-          prefs::kPowerUserActivityScreenDimDelayFactor,
-          100, INT_MAX, true));
-  handlers_.push_back(new IntRangePolicyHandler(key::kUptimeLimit,
-                                                prefs::kUptimeLimit,
-                                                3600, INT_MAX, true));
-  handlers_.push_back(new IntRangePolicyHandler(
-      key::kDeviceLoginScreenDefaultScreenMagnifierType,
-      NULL,
-      0, ash::MAGNIFIER_FULL, false));
-#endif  // defined(OS_CHROMEOS)
-
-#if defined(OS_ANDROID)
-  handlers_.push_back(new ManagedBookmarksPolicyHandler());
-#endif
 }
 
 ConfigurationPolicyHandlerList::~ConfigurationPolicyHandlerList() {
   STLDeleteElements(&handlers_);
 }
 
+void ConfigurationPolicyHandlerList::AddHandler(
+    scoped_ptr<ConfigurationPolicyHandler> handler) {
+  handlers_.push_back(handler.release());
+}
+
 void ConfigurationPolicyHandlerList::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs,
@@ -634,4 +502,197 @@
     (*handler)->PrepareForDisplaying(policies);
 }
 
+#if !defined(OS_IOS)
+scoped_ptr<ConfigurationPolicyHandlerList> BuildHandlerList() {
+  scoped_ptr<ConfigurationPolicyHandlerList> handlers(
+      new ConfigurationPolicyHandlerList);
+  for (size_t i = 0; i < arraysize(kSimplePolicyMap); ++i) {
+    handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+        new SimplePolicyHandler(kSimplePolicyMap[i].policy_name,
+                                kSimplePolicyMap[i].preference_path,
+                                kSimplePolicyMap[i].value_type)));
+  }
+
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new AutofillPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new DefaultSearchPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new FileSelectionDialogsPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IncognitoModePolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new JavascriptPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new ProxyPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new RestoreOnStartupPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new browser_sync::SyncPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new URLBlacklistPolicyHandler()));
+
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new extensions::ExtensionListPolicyHandler(
+          key::kExtensionInstallWhitelist,
+          prefs::kExtensionInstallAllowList,
+          false)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new extensions::ExtensionListPolicyHandler(
+          key::kExtensionInstallBlacklist,
+          prefs::kExtensionInstallDenyList,
+          true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new extensions::ExtensionInstallForcelistPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new extensions::ExtensionURLPatternListPolicyHandler(
+          key::kExtensionInstallSources,
+          prefs::kExtensionAllowedInstallSites)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new StringToIntEnumListPolicyHandler(
+          key::kExtensionAllowedTypes,
+          prefs::kExtensionAllowedTypes,
+          kExtensionAllowedTypesMap,
+          kExtensionAllowedTypesMap + arraysize(kExtensionAllowedTypesMap))));
+#if defined(OS_CHROMEOS)
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new extensions::ExtensionListPolicyHandler(
+          key::kAttestationExtensionWhitelist,
+          prefs::kAttestationExtensionWhitelist,
+          false)));
+#endif  // defined(OS_CHROMEOS)
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new DiskCacheDirPolicyHandler(prefs::kDiskCacheDir)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new DownloadDirPolicyHandler));
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      NetworkConfigurationPolicyHandler::CreateForDevicePolicy()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      NetworkConfigurationPolicyHandler::CreateForUserPolicy()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new PinnedLauncherAppsPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new ScreenMagnifierPolicyHandler()));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new LoginScreenPowerManagementPolicyHandler));
+
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenDimDelayAC,
+                                prefs::kPowerAcScreenDimDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenOffDelayAC,
+                                prefs::kPowerAcScreenOffDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenLockDelayAC,
+                                prefs::kPowerAcScreenLockDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kIdleWarningDelayAC,
+                                prefs::kPowerAcIdleWarningDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kIdleDelayAC, prefs::kPowerAcIdleDelayMs, 0, INT_MAX, true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenDimDelayBattery,
+                                prefs::kPowerBatteryScreenDimDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenOffDelayBattery,
+                                prefs::kPowerBatteryScreenOffDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kScreenLockDelayBattery,
+                                prefs::kPowerBatteryScreenLockDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kIdleWarningDelayBattery,
+                                prefs::kPowerBatteryIdleWarningDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntRangePolicyHandler(key::kIdleDelayBattery,
+                                prefs::kPowerBatteryIdleDelayMs,
+                                0,
+                                INT_MAX,
+                                true)));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kIdleActionAC,
+          prefs::kPowerAcIdleAction,
+          chromeos::PowerPolicyController::ACTION_SUSPEND,
+          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
+          false)));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kIdleActionBattery,
+          prefs::kPowerBatteryIdleAction,
+          chromeos::PowerPolicyController::ACTION_SUSPEND,
+          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
+          false)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new DeprecatedIdleActionHandler()));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kLidCloseAction,
+          prefs::kPowerLidClosedAction,
+          chromeos::PowerPolicyController::ACTION_SUSPEND,
+          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
+          false)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntPercentageToDoublePolicyHandler(
+          key::kPresentationScreenDimDelayScale,
+          prefs::kPowerPresentationScreenDimDelayFactor,
+          100,
+          INT_MAX,
+          true)));
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new IntPercentageToDoublePolicyHandler(
+          key::kUserActivityScreenDimDelayScale,
+          prefs::kPowerUserActivityScreenDimDelayFactor,
+          100,
+          INT_MAX,
+          true)));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kUptimeLimit, prefs::kUptimeLimit, 3600, INT_MAX, true)));
+  handlers->AddHandler(
+      make_scoped_ptr<ConfigurationPolicyHandler>(new IntRangePolicyHandler(
+          key::kDeviceLoginScreenDefaultScreenMagnifierType,
+          NULL,
+          0,
+          ash::MAGNIFIER_FULL,
+          false)));
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+  handlers->AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+      new ManagedBookmarksPolicyHandler()));
+#endif
+  return handlers.Pass();
+}
+#endif  // !defined(OS_IOS)
+
 }  // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_handler_list.h b/chrome/browser/policy/configuration_policy_handler_list.h
index 8ecde65..022cb8c 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.h
+++ b/chrome/browser/policy/configuration_policy_handler_list.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 
 class PrefValueMap;
 
@@ -18,13 +19,17 @@
 class PolicyMap;
 struct PolicyToPreferenceMapEntry;
 
-// Converts policies to their corresponding preferences. Also does error
-// checking and cleans up policy values for displaying.
+// Converts policies to their corresponding preferences by applying a list of
+// ConfigurationPolicyHandler objects. This includes error checking and
+// cleaning up policy values for displaying.
 class ConfigurationPolicyHandlerList {
  public:
   ConfigurationPolicyHandlerList();
   ~ConfigurationPolicyHandlerList();
 
+  // Adds a policy handler to the list.
+  void AddHandler(scoped_ptr<ConfigurationPolicyHandler> handler);
+
   // Translates |policies| to their corresponding preferences in |prefs|.
   // Any errors found while processing the policies are stored in |errors|.
   // |prefs| or |errors| can be NULL, and won't be filled in that case.
@@ -41,6 +46,9 @@
   DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyHandlerList);
 };
 
+// Builds a platform-specific handler list.
+scoped_ptr<ConfigurationPolicyHandlerList> BuildHandlerList();
+
 }  // namespace policy
 
 #endif  // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_HANDLER_LIST_H_
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index cc68d69..2e707c5 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -15,17 +15,19 @@
 #include "chrome/browser/policy/external_data_fetcher.h"
 #include "chrome/browser/policy/policy_map.h"
 #include "chrome/browser/policy/policy_service_impl.h"
-#include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/common/content_settings.h"
 #include "chrome/common/pref_names.h"
 #include "components/policy/core/common/policy_pref_names.h"
-#include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::Mock;
 using testing::Return;
 using testing::_;
 
+namespace {
+const char kTestPolicy[] = "test.policy";
+const char kTestPref[] = "test.pref";
+}  // namespace
+
 namespace policy {
 
 // Holds a set of test parameters, consisting of pref name and policy name.
@@ -69,545 +71,133 @@
 
 // Test cases for list-valued policy settings.
 class ConfigurationPolicyPrefStoreListTest
-    : public ConfigurationPolicyPrefStoreTest,
-      public testing::WithParamInterface<PolicyAndPref> {};
+    : public ConfigurationPolicyPrefStoreTest {
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new SimplePolicyHandler(
+            kTestPolicy, kTestPref, base::Value::TYPE_LIST)));
+  }
+};
 
-TEST_P(ConfigurationPolicyPrefStoreListTest, GetDefault) {
-  EXPECT_FALSE(store_->GetValue(GetParam().pref_name(), NULL));
+TEST_F(ConfigurationPolicyPrefStoreListTest, GetDefault) {
+  EXPECT_FALSE(store_->GetValue(kTestPref, NULL));
 }
 
-TEST_P(ConfigurationPolicyPrefStoreListTest, SetValue) {
+TEST_F(ConfigurationPolicyPrefStoreListTest, SetValue) {
   base::ListValue* in_value = new base::ListValue();
   in_value->Append(base::Value::CreateStringValue("test1"));
   in_value->Append(base::Value::CreateStringValue("test2,"));
   PolicyMap policy;
-  policy.Set(GetParam().policy_name(), POLICY_LEVEL_MANDATORY,
+  policy.Set(kTestPolicy, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, in_value, NULL);
   UpdateProviderPolicy(policy);
   const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(GetParam().pref_name(), &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
   ASSERT_TRUE(value);
   EXPECT_TRUE(in_value->Equals(value));
 }
 
-INSTANTIATE_TEST_CASE_P(
-    ConfigurationPolicyPrefStoreListTestInstance,
-    ConfigurationPolicyPrefStoreListTest,
-    testing::Values(
-        PolicyAndPref(key::kRestoreOnStartupURLs,
-                      prefs::kURLsToRestoreOnStartup),
-        PolicyAndPref(key::kDisabledPlugins,
-                      prefs::kPluginsDisabledPlugins),
-        PolicyAndPref(key::kDisabledPluginsExceptions,
-                      prefs::kPluginsDisabledPluginsExceptions),
-        PolicyAndPref(key::kEnabledPlugins,
-                      prefs::kPluginsEnabledPlugins),
-        PolicyAndPref(key::kAutoSelectCertificateForUrls,
-                      prefs::kManagedAutoSelectCertificateForUrls),
-        PolicyAndPref(key::kURLBlacklist,
-                      prefs::kUrlBlacklist),
-        PolicyAndPref(key::kURLWhitelist,
-                      prefs::kUrlWhitelist)));
-
 // Test cases for string-valued policy settings.
 class ConfigurationPolicyPrefStoreStringTest
-    : public ConfigurationPolicyPrefStoreTest,
-      public testing::WithParamInterface<PolicyAndPref> {};
+    : public ConfigurationPolicyPrefStoreTest {
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new SimplePolicyHandler(
+            kTestPolicy, kTestPref, base::Value::TYPE_STRING)));
+  }
+};
 
-TEST_P(ConfigurationPolicyPrefStoreStringTest, GetDefault) {
-  EXPECT_FALSE(store_->GetValue(GetParam().pref_name(), NULL));
+TEST_F(ConfigurationPolicyPrefStoreStringTest, GetDefault) {
+  EXPECT_FALSE(store_->GetValue(kTestPref, NULL));
 }
 
-TEST_P(ConfigurationPolicyPrefStoreStringTest, SetValue) {
+TEST_F(ConfigurationPolicyPrefStoreStringTest, SetValue) {
   PolicyMap policy;
-  policy.Set(GetParam().policy_name(), POLICY_LEVEL_MANDATORY,
+  policy.Set(kTestPolicy, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER,
              base::Value::CreateStringValue("http://chromium.org"), NULL);
   UpdateProviderPolicy(policy);
   const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(GetParam().pref_name(), &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
   ASSERT_TRUE(value);
   EXPECT_TRUE(base::StringValue("http://chromium.org").Equals(value));
 }
 
-INSTANTIATE_TEST_CASE_P(
-    ConfigurationPolicyPrefStoreStringTestInstance,
-    ConfigurationPolicyPrefStoreStringTest,
-    testing::Values(
-        PolicyAndPref(key::kRestrictSigninToPattern,
-                      prefs::kGoogleServicesUsernamePattern),
-        PolicyAndPref(key::kHomepageLocation,
-                      prefs::kHomePage),
-        PolicyAndPref(key::kApplicationLocaleValue,
-                      prefs::kApplicationLocale),
-        PolicyAndPref(key::kAuthSchemes,
-                      prefs::kAuthSchemes),
-        PolicyAndPref(key::kAuthServerWhitelist,
-                      prefs::kAuthServerWhitelist),
-        PolicyAndPref(key::kAuthNegotiateDelegateWhitelist,
-                      prefs::kAuthNegotiateDelegateWhitelist),
-        PolicyAndPref(key::kGSSAPILibraryName,
-                      prefs::kGSSAPILibraryName),
-        PolicyAndPref(key::kVariationsRestrictParameter,
-                      prefs::kVariationsRestrictParameter)));
-
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-INSTANTIATE_TEST_CASE_P(
-    ConfigurationPolicyPrefStoreDownloadDirectoryInstance,
-    ConfigurationPolicyPrefStoreStringTest,
-    testing::Values(
-        PolicyAndPref(key::kDiskCacheDir,
-                      prefs::kDiskCacheDir),
-        PolicyAndPref(key::kDownloadDirectory,
-                      prefs::kDownloadDefaultDirectory)));
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-
 // Test cases for boolean-valued policy settings.
 class ConfigurationPolicyPrefStoreBooleanTest
-    : public ConfigurationPolicyPrefStoreTest,
-      public testing::WithParamInterface<PolicyAndPref> {};
+    : public ConfigurationPolicyPrefStoreTest {
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new SimplePolicyHandler(
+            kTestPolicy, kTestPref, base::Value::TYPE_BOOLEAN)));
+  }
+};
 
-TEST_P(ConfigurationPolicyPrefStoreBooleanTest, GetDefault) {
-  EXPECT_FALSE(store_->GetValue(GetParam().pref_name(), NULL));
+TEST_F(ConfigurationPolicyPrefStoreBooleanTest, GetDefault) {
+  EXPECT_FALSE(store_->GetValue(kTestPref, NULL));
 }
 
-TEST_P(ConfigurationPolicyPrefStoreBooleanTest, SetValue) {
+TEST_F(ConfigurationPolicyPrefStoreBooleanTest, SetValue) {
   PolicyMap policy;
-  policy.Set(GetParam().policy_name(), POLICY_LEVEL_MANDATORY,
+  policy.Set(kTestPolicy, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
   UpdateProviderPolicy(policy);
   const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(GetParam().pref_name(), &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
   ASSERT_TRUE(value);
   bool boolean_value = true;
   bool result = value->GetAsBoolean(&boolean_value);
   ASSERT_TRUE(result);
   EXPECT_FALSE(boolean_value);
 
-  policy.Set(GetParam().policy_name(), POLICY_LEVEL_MANDATORY,
+  policy.Set(kTestPolicy, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
   UpdateProviderPolicy(policy);
   value = NULL;
-  EXPECT_TRUE(store_->GetValue(GetParam().pref_name(), &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
   boolean_value = false;
   result = value->GetAsBoolean(&boolean_value);
   ASSERT_TRUE(result);
   EXPECT_TRUE(boolean_value);
 }
 
-INSTANTIATE_TEST_CASE_P(
-    ConfigurationPolicyPrefStoreBooleanTestInstance,
-    ConfigurationPolicyPrefStoreBooleanTest,
-    testing::Values(
-        PolicyAndPref(key::kHomepageIsNewTabPage,
-                      prefs::kHomePageIsNewTabPage),
-        PolicyAndPref(key::kAlternateErrorPagesEnabled,
-                      prefs::kAlternateErrorPagesEnabled),
-        PolicyAndPref(key::kSearchSuggestEnabled,
-                      prefs::kSearchSuggestEnabled),
-        PolicyAndPref(key::kDnsPrefetchingEnabled,
-                      prefs::kNetworkPredictionEnabled),
-        PolicyAndPref(key::kBuiltInDnsClientEnabled,
-                      prefs::kBuiltInDnsClientEnabled),
-        PolicyAndPref(key::kDisableSpdy,
-                      prefs::kDisableSpdy),
-        PolicyAndPref(key::kSafeBrowsingEnabled,
-                      prefs::kSafeBrowsingEnabled),
-        PolicyAndPref(key::kForceSafeSearch,
-                      prefs::kForceSafeSearch),
-        PolicyAndPref(key::kMetricsReportingEnabled,
-                      prefs::kMetricsReportingEnabled),
-        PolicyAndPref(key::kPasswordManagerEnabled,
-                      prefs::kPasswordManagerEnabled),
-        PolicyAndPref(key::kPasswordManagerAllowShowPasswords,
-                      prefs::kPasswordManagerAllowShowPasswords),
-        PolicyAndPref(key::kShowHomeButton,
-                      prefs::kShowHomeButton),
-        PolicyAndPref(key::kPrintingEnabled,
-                      prefs::kPrintingEnabled),
-        PolicyAndPref(key::kRemoteAccessHostFirewallTraversal,
-                      prefs::kRemoteAccessHostFirewallTraversal),
-        PolicyAndPref(key::kCloudPrintProxyEnabled,
-                      prefs::kCloudPrintProxyEnabled),
-        PolicyAndPref(key::kCloudPrintSubmitEnabled,
-                      prefs::kCloudPrintSubmitEnabled),
-        PolicyAndPref(key::kSavingBrowserHistoryDisabled,
-                      prefs::kSavingBrowserHistoryDisabled),
-        PolicyAndPref(key::kEnableOriginBoundCerts,
-                      prefs::kEnableOriginBoundCerts),
-        PolicyAndPref(key::kDisableSSLRecordSplitting,
-                      prefs::kDisableSSLRecordSplitting),
-        PolicyAndPref(key::kEnableOnlineRevocationChecks,
-                      prefs::kCertRevocationCheckingEnabled),
-        PolicyAndPref(key::kRequireOnlineRevocationChecksForLocalAnchors,
-                      prefs::kCertRevocationCheckingRequiredLocalAnchors),
-        PolicyAndPref(key::kDisableAuthNegotiateCnameLookup,
-                      prefs::kDisableAuthNegotiateCnameLookup),
-        PolicyAndPref(key::kEnableAuthNegotiatePort,
-                      prefs::kEnableAuthNegotiatePort),
-        PolicyAndPref(key::kDisablePluginFinder,
-                      prefs::kDisablePluginFinder),
-        PolicyAndPref(key::kDefaultBrowserSettingEnabled,
-                      prefs::kDefaultBrowserSettingEnabled),
-        PolicyAndPref(key::kDisable3DAPIs,
-                      prefs::kDisable3DAPIs),
-        PolicyAndPref(key::kTranslateEnabled,
-                      prefs::kEnableTranslate),
-        PolicyAndPref(key::kAllowOutdatedPlugins,
-                      prefs::kPluginsAllowOutdated),
-        PolicyAndPref(key::kAlwaysAuthorizePlugins,
-                      prefs::kPluginsAlwaysAuthorize),
-        PolicyAndPref(key::kBookmarkBarEnabled,
-                      prefs::kShowBookmarkBar),
-        PolicyAndPref(key::kEditBookmarksEnabled,
-                      prefs::kEditBookmarksEnabled),
-        PolicyAndPref(key::kAllowFileSelectionDialogs,
-                      prefs::kAllowFileSelectionDialogs),
-        PolicyAndPref(key::kAllowCrossOriginAuthPrompt,
-                      prefs::kAllowCrossOriginAuthPrompt),
-        PolicyAndPref(key::kImportBookmarks,
-                      prefs::kImportBookmarks),
-        PolicyAndPref(key::kImportHistory,
-                      prefs::kImportHistory),
-        PolicyAndPref(key::kImportHomepage,
-                      prefs::kImportHomepage),
-        PolicyAndPref(key::kImportSearchEngine,
-                      prefs::kImportSearchEngine),
-        PolicyAndPref(key::kImportSavedPasswords,
-                      prefs::kImportSavedPasswords),
-        PolicyAndPref(key::kEnableMemoryInfo,
-                      prefs::kEnableMemoryInfo),
-        PolicyAndPref(key::kDisablePrintPreview,
-                      prefs::kPrintPreviewDisabled),
-        PolicyAndPref(key::kDeveloperToolsDisabled,
-                      prefs::kDevToolsDisabled),
-        PolicyAndPref(key::kHideWebStoreIcon,
-                      prefs::kHideWebStoreIcon)));
-
-#if defined(OS_CHROMEOS)
-INSTANTIATE_TEST_CASE_P(
-    CrosConfigurationPolicyPrefStoreBooleanTestInstance,
-    ConfigurationPolicyPrefStoreBooleanTest,
-    testing::Values(
-        PolicyAndPref(key::kChromeOsLockOnIdleSuspend,
-                      prefs::kEnableScreenLock),
-        PolicyAndPref(key::kDriveDisabled,
-                      prefs::kDisableDrive),
-        PolicyAndPref(key::kDriveDisabledOverCellular,
-                      prefs::kDisableDriveOverCellular),
-        PolicyAndPref(key::kExternalStorageDisabled,
-                      prefs::kExternalStorageDisabled),
-        PolicyAndPref(key::kShowAccessibilityOptionsInSystemTrayMenu,
-                      prefs::kShouldAlwaysShowAccessibilityMenu),
-        PolicyAndPref(key::kLargeCursorEnabled,
-                      prefs::kLargeCursorEnabled),
-        PolicyAndPref(key::kSpokenFeedbackEnabled,
-                      prefs::kSpokenFeedbackEnabled),
-        PolicyAndPref(key::kHighContrastEnabled,
-                      prefs::kHighContrastEnabled),
-        PolicyAndPref(key::kAudioOutputAllowed,
-                      prefs::kAudioOutputAllowed),
-        PolicyAndPref(key::kAudioCaptureAllowed,
-                      prefs::kAudioCaptureAllowed),
-        PolicyAndPref(key::kAttestationEnabledForUser,
-                      prefs::kAttestationEnabled)));
-#endif  // defined(OS_CHROMEOS)
-
 // Test cases for integer-valued policy settings.
 class ConfigurationPolicyPrefStoreIntegerTest
-    : public ConfigurationPolicyPrefStoreTest,
-      public testing::WithParamInterface<PolicyAndPref> {};
-
-TEST_P(ConfigurationPolicyPrefStoreIntegerTest, GetDefault) {
-  EXPECT_FALSE(store_->GetValue(GetParam().pref_name(), NULL));
-}
-
-TEST_P(ConfigurationPolicyPrefStoreIntegerTest, SetValue) {
-  PolicyMap policy;
-  policy.Set(GetParam().policy_name(), POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateIntegerValue(2), NULL);
-  UpdateProviderPolicy(policy);
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(GetParam().pref_name(), &value));
-  EXPECT_TRUE(base::FundamentalValue(2).Equals(value));
-}
-
-INSTANTIATE_TEST_CASE_P(
-    ConfigurationPolicyPrefStoreIntegerTestInstance,
-    ConfigurationPolicyPrefStoreIntegerTest,
-    testing::Values(
-        PolicyAndPref(key::kDefaultCookiesSetting,
-                      prefs::kManagedDefaultCookiesSetting),
-        PolicyAndPref(key::kDefaultImagesSetting,
-                      prefs::kManagedDefaultImagesSetting),
-        PolicyAndPref(key::kDefaultPluginsSetting,
-                      prefs::kManagedDefaultPluginsSetting),
-        PolicyAndPref(key::kDefaultPopupsSetting,
-                      prefs::kManagedDefaultPopupsSetting),
-        PolicyAndPref(key::kDefaultNotificationsSetting,
-                      prefs::kManagedDefaultNotificationsSetting),
-        PolicyAndPref(key::kDefaultGeolocationSetting,
-                      prefs::kManagedDefaultGeolocationSetting),
-        PolicyAndPref(key::kRestoreOnStartup,
-                      prefs::kRestoreOnStartup),
-        PolicyAndPref(key::kDiskCacheSize,
-                      prefs::kDiskCacheSize),
-        PolicyAndPref(key::kMediaCacheSize,
-                      prefs::kMediaCacheSize),
-        PolicyAndPref(key::kPolicyRefreshRate,
-                      policy_prefs::kUserPolicyRefreshRate),
-        PolicyAndPref(key::kMaxConnectionsPerProxy,
-                      prefs::kMaxConnectionsPerProxy)));
-
-// Tests Incognito mode availability preference setting.
-class ConfigurationPolicyPrefStoreIncognitoModeTest
     : public ConfigurationPolicyPrefStoreTest {
- protected:
-  static const int kIncognitoModeAvailabilityNotSet = -1;
-
-  enum ObsoleteIncognitoEnabledValue {
-    INCOGNITO_ENABLED_UNKNOWN,
-    INCOGNITO_ENABLED_TRUE,
-    INCOGNITO_ENABLED_FALSE
-  };
-
-  void SetPolicies(ObsoleteIncognitoEnabledValue incognito_enabled,
-                   int availability) {
-    PolicyMap policy;
-    if (incognito_enabled != INCOGNITO_ENABLED_UNKNOWN) {
-      policy.Set(key::kIncognitoEnabled, POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER,
-                 base::Value::CreateBooleanValue(
-                     incognito_enabled == INCOGNITO_ENABLED_TRUE),
-                 NULL);
-    }
-    if (availability >= 0) {
-      policy.Set(key::kIncognitoModeAvailability, POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER,
-                 base::Value::CreateIntegerValue(availability),
-                 NULL);
-    }
-    UpdateProviderPolicy(policy);
-  }
-
-  void VerifyValues(IncognitoModePrefs::Availability availability) {
-    const base::Value* value = NULL;
-    EXPECT_TRUE(store_->GetValue(prefs::kIncognitoModeAvailability, &value));
-    EXPECT_TRUE(base::FundamentalValue(availability).Equals(value));
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new SimplePolicyHandler(
+            kTestPolicy, kTestPref, base::Value::TYPE_INTEGER)));
   }
 };
 
-// The following testcases verify that if the obsolete IncognitoEnabled
-// policy is not set, the IncognitoModeAvailability values should be copied
-// from IncognitoModeAvailability policy to pref "as is".
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       NoObsoletePolicyAndIncognitoEnabled) {
-  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::ENABLED);
-  VerifyValues(IncognitoModePrefs::ENABLED);
+TEST_F(ConfigurationPolicyPrefStoreIntegerTest, GetDefault) {
+  EXPECT_FALSE(store_->GetValue(kTestPref, NULL));
 }
 
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       NoObsoletePolicyAndIncognitoDisabled) {
-  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::DISABLED);
-  VerifyValues(IncognitoModePrefs::DISABLED);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       NoObsoletePolicyAndIncognitoForced) {
-  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::FORCED);
-  VerifyValues(IncognitoModePrefs::FORCED);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       NoObsoletePolicyAndNoIncognitoAvailability) {
-  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, kIncognitoModeAvailabilityNotSet);
+TEST_F(ConfigurationPolicyPrefStoreIntegerTest, SetValue) {
+  PolicyMap policy;
+  policy.Set(kTestPolicy, POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER, base::Value::CreateIntegerValue(2), NULL);
+  UpdateProviderPolicy(policy);
   const base::Value* value = NULL;
-  EXPECT_FALSE(store_->GetValue(prefs::kIncognitoModeAvailability, &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
+  EXPECT_TRUE(base::FundamentalValue(2).Equals(value));
 }
 
-// Checks that if the obsolete IncognitoEnabled policy is set, if sets
-// the IncognitoModeAvailability preference only in case
-// the IncognitoModeAvailability policy is not specified.
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       ObsoletePolicyDoesNotAffectAvailabilityEnabled) {
-  SetPolicies(INCOGNITO_ENABLED_FALSE, IncognitoModePrefs::ENABLED);
-  VerifyValues(IncognitoModePrefs::ENABLED);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       ObsoletePolicyDoesNotAffectAvailabilityForced) {
-  SetPolicies(INCOGNITO_ENABLED_TRUE, IncognitoModePrefs::FORCED);
-  VerifyValues(IncognitoModePrefs::FORCED);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       ObsoletePolicySetsPreferenceToEnabled) {
-  SetPolicies(INCOGNITO_ENABLED_TRUE, kIncognitoModeAvailabilityNotSet);
-  VerifyValues(IncognitoModePrefs::ENABLED);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreIncognitoModeTest,
-       ObsoletePolicySetsPreferenceToDisabled) {
-  SetPolicies(INCOGNITO_ENABLED_FALSE, kIncognitoModeAvailabilityNotSet);
-  VerifyValues(IncognitoModePrefs::DISABLED);
-}
-
-// Test cases for the Sync policy setting.
-class ConfigurationPolicyPrefStoreSyncTest
-    : public ConfigurationPolicyPrefStoreTest {};
-
-TEST_F(ConfigurationPolicyPrefStoreSyncTest, Default) {
-  EXPECT_FALSE(store_->GetValue(prefs::kSyncManaged, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreSyncTest, Enabled) {
-  PolicyMap policy;
-  policy.Set(key::kSyncDisabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             base::Value::CreateBooleanValue(false), NULL);
-  UpdateProviderPolicy(policy);
-  // Enabling Sync should not set the pref.
-  EXPECT_FALSE(store_->GetValue(prefs::kSyncManaged, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreSyncTest, Disabled) {
-  PolicyMap policy;
-  policy.Set(key::kSyncDisabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             base::Value::CreateBooleanValue(true), NULL);
-  UpdateProviderPolicy(policy);
-  // Sync should be flagged as managed.
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kSyncManaged, &value));
-  ASSERT_TRUE(value);
-  bool sync_managed = false;
-  bool result = value->GetAsBoolean(&sync_managed);
-  ASSERT_TRUE(result);
-  EXPECT_TRUE(sync_managed);
-}
-
-// Test cases for how the AllowFileSelectionDialogs policy influences the
-// PromptForDownload preference.
-class ConfigurationPolicyPrefStorePromptDownloadTest
-    : public ConfigurationPolicyPrefStoreTest {};
-
-TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest, Default) {
-  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest,
-       EnableFileSelectionDialogs) {
-  PolicyMap policy;
-  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
-  policy.Set(key::kAllowFileSelectionDialogs, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
-  UpdateProviderPolicy(policy);
-
-  // Allowing file-selection dialogs should not influence the PromptForDownload
-  // pref.
-  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest,
-       DisableFileSelectionDialogs) {
-  PolicyMap policy;
-  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
-  policy.Set(key::kAllowFileSelectionDialogs, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
-  UpdateProviderPolicy(policy);
-
-  // Disabling file-selection dialogs should disable the PromptForDownload pref.
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kPromptForDownload,
-                                                 &value));
-  ASSERT_TRUE(value);
-  bool prompt_for_download = true;
-  bool result = value->GetAsBoolean(&prompt_for_download);
-  ASSERT_TRUE(result);
-  EXPECT_FALSE(prompt_for_download);
-}
-
-// Test cases for the Autofill policy setting.
-class ConfigurationPolicyPrefStoreAutofillTest
-    : public ConfigurationPolicyPrefStoreTest {};
-
-TEST_F(ConfigurationPolicyPrefStoreAutofillTest, Default) {
-  EXPECT_FALSE(store_->GetValue(autofill::prefs::kAutofillEnabled, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreAutofillTest, Enabled) {
-  PolicyMap policy;
-  policy.Set(key::kAutoFillEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             base::Value::CreateBooleanValue(true), NULL);
-  UpdateProviderPolicy(policy);
-  // Enabling Autofill should not set the pref.
-  EXPECT_FALSE(store_->GetValue(autofill::prefs::kAutofillEnabled, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreAutofillTest, Disabled) {
-  PolicyMap policy;
-  policy.Set(key::kAutoFillEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             base::Value::CreateBooleanValue(false), NULL);
-  UpdateProviderPolicy(policy);
-  // Disabling Autofill should switch the pref to managed.
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(autofill::prefs::kAutofillEnabled, &value));
-  ASSERT_TRUE(value);
-  bool autofill_enabled = true;
-  bool result = value->GetAsBoolean(&autofill_enabled);
-  ASSERT_TRUE(result);
-  EXPECT_FALSE(autofill_enabled);
-}
-
-#if defined(OS_CHROMEOS)
-// Test cases for the screen magnifier type policy setting.
-class ConfigurationPolicyPrefStoreScreenMagnifierTypeTest
-    : public ConfigurationPolicyPrefStoreTest {};
-
-TEST_F(ConfigurationPolicyPrefStoreScreenMagnifierTypeTest, Default) {
-  EXPECT_FALSE(store_->GetValue(prefs::kScreenMagnifierEnabled, NULL));
-  EXPECT_FALSE(store_->GetValue(prefs::kScreenMagnifierType, NULL));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreScreenMagnifierTypeTest, Disabled) {
-  PolicyMap policy;
-  policy.Set(key::kScreenMagnifierType, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateIntegerValue(0), NULL);
-  UpdateProviderPolicy(policy);
-  const base::Value* enabled = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kScreenMagnifierEnabled, &enabled));
-  ASSERT_TRUE(enabled);
-  EXPECT_TRUE(base::FundamentalValue(false).Equals(enabled));
-  const base::Value* type = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kScreenMagnifierType, &type));
-  ASSERT_TRUE(type);
-  EXPECT_TRUE(base::FundamentalValue(0).Equals(type));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreScreenMagnifierTypeTest, Enabled) {
-  PolicyMap policy;
-  policy.Set(key::kScreenMagnifierType, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateIntegerValue(1), NULL);
-  UpdateProviderPolicy(policy);
-  const base::Value* enabled = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kScreenMagnifierEnabled, &enabled));
-  ASSERT_TRUE(enabled);
-  EXPECT_TRUE(base::FundamentalValue(true).Equals(enabled));
-  const base::Value* type = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kScreenMagnifierType, &type));
-  ASSERT_TRUE(type);
-  EXPECT_TRUE(base::FundamentalValue(1).Equals(type));
-}
-#endif  // defined(OS_CHROMEOS)
-
 // Exercises the policy refresh mechanism.
 class ConfigurationPolicyPrefStoreRefreshTest
     : public ConfigurationPolicyPrefStoreTest {
  protected:
-  virtual void SetUp() {
+  virtual void SetUp() OVERRIDE {
     ConfigurationPolicyPrefStoreTest::SetUp();
     store_->AddObserver(&observer_);
+    handler_list_.AddHandler(
+        make_scoped_ptr<ConfigurationPolicyHandler>(new SimplePolicyHandler(
+            kTestPolicy, kTestPref, base::Value::TYPE_STRING)));
   }
 
-  virtual void TearDown() {
+  virtual void TearDown() OVERRIDE {
     store_->RemoveObserver(&observer_);
     ConfigurationPolicyPrefStoreTest::TearDown();
   }
@@ -617,26 +207,29 @@
 
 TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Refresh) {
   const base::Value* value = NULL;
-  EXPECT_FALSE(store_->GetValue(prefs::kHomePage, NULL));
+  EXPECT_FALSE(store_->GetValue(kTestPolicy, NULL));
 
-  EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1);
+  EXPECT_CALL(observer_, OnPrefValueChanged(kTestPref)).Times(1);
   PolicyMap policy;
-  policy.Set(key::kHomepageLocation, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             base::Value::CreateStringValue("http://www.chromium.org"), NULL);
+  policy.Set(kTestPolicy,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateStringValue("http://www.chromium.org"),
+             NULL);
   UpdateProviderPolicy(policy);
   Mock::VerifyAndClearExpectations(&observer_);
-  EXPECT_TRUE(store_->GetValue(prefs::kHomePage, &value));
+  EXPECT_TRUE(store_->GetValue(kTestPref, &value));
   EXPECT_TRUE(base::StringValue("http://www.chromium.org").Equals(value));
 
   EXPECT_CALL(observer_, OnPrefValueChanged(_)).Times(0);
   UpdateProviderPolicy(policy);
   Mock::VerifyAndClearExpectations(&observer_);
 
-  EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1);
-  policy.Erase(key::kHomepageLocation);
+  EXPECT_CALL(observer_, OnPrefValueChanged(kTestPref)).Times(1);
+  policy.Erase(kTestPolicy);
   UpdateProviderPolicy(policy);
   Mock::VerifyAndClearExpectations(&observer_);
-  EXPECT_FALSE(store_->GetValue(prefs::kHomePage, NULL));
+  EXPECT_FALSE(store_->GetValue(kTestPref, NULL));
 }
 
 TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Initialization) {
@@ -650,46 +243,4 @@
   EXPECT_TRUE(store_->IsInitializationComplete());
 }
 
-// Tests for policies that don't quite fit the previous patterns.
-class ConfigurationPolicyPrefStoreOthersTest
-    : public ConfigurationPolicyPrefStoreTest {};
-
-TEST_F(ConfigurationPolicyPrefStoreOthersTest, JavascriptEnabled) {
-  // This is a boolean policy, but affects an integer preference.
-  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
-  PolicyMap policy;
-  policy.Set(key::kJavascriptEnabled, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
-  UpdateProviderPolicy(policy);
-  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
-  policy.Set(key::kJavascriptEnabled, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
-  UpdateProviderPolicy(policy);
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
-                               &value));
-  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_BLOCK).Equals(value));
-}
-
-TEST_F(ConfigurationPolicyPrefStoreOthersTest, JavascriptEnabledOverridden) {
-  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
-  PolicyMap policy;
-  policy.Set(key::kJavascriptEnabled, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
-  UpdateProviderPolicy(policy);
-  const base::Value* value = NULL;
-  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
-                               &value));
-  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_BLOCK).Equals(value));
-  // DefaultJavaScriptSetting overrides JavascriptEnabled.
-  policy.Set(key::kDefaultJavaScriptSetting, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER,
-             base::Value::CreateIntegerValue(CONTENT_SETTING_ALLOW),
-             NULL);
-  UpdateProviderPolicy(policy);
-  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
-                               &value));
-  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_ALLOW).Equals(value));
-}
-
 }  // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h
index 2d7372a..3fef214 100644
--- a/chrome/browser/policy/configuration_policy_provider.h
+++ b/chrome/browser/policy/configuration_policy_provider.h
@@ -10,7 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/policy/policy_bundle.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace policy {
 
diff --git a/chrome/browser/policy/file_selection_dialogs_policy_handler.cc b/chrome/browser/policy/file_selection_dialogs_policy_handler.cc
new file mode 100644
index 0000000..050e431
--- /dev/null
+++ b/chrome/browser/policy/file_selection_dialogs_policy_handler.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 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/policy/file_selection_dialogs_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+FileSelectionDialogsPolicyHandler::FileSelectionDialogsPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kAllowFileSelectionDialogs,
+                                base::Value::TYPE_BOOLEAN) {}
+
+FileSelectionDialogsPolicyHandler::~FileSelectionDialogsPolicyHandler() {}
+
+void FileSelectionDialogsPolicyHandler::ApplyPolicySettings(
+    const PolicyMap& policies,
+    PrefValueMap* prefs) {
+  bool allow_dialogs;
+  const base::Value* value = policies.GetValue(policy_name());
+  if (value && value->GetAsBoolean(&allow_dialogs)) {
+    prefs->SetValue(prefs::kAllowFileSelectionDialogs,
+                    base::Value::CreateBooleanValue(allow_dialogs));
+    // Disallow selecting the download location if file dialogs are disabled.
+    if (!allow_dialogs) {
+      prefs->SetValue(prefs::kPromptForDownload,
+                      base::Value::CreateBooleanValue(false));
+    }
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/file_selection_dialogs_policy_handler.h b/chrome/browser/policy/file_selection_dialogs_policy_handler.h
new file mode 100644
index 0000000..6208fe7
--- /dev/null
+++ b/chrome/browser/policy/file_selection_dialogs_policy_handler.h
@@ -0,0 +1,30 @@
+// Copyright 2013 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_POLICY_FILE_SELECTION_DIALOGS_POLICY_HANDLER_H_
+#define CHROME_BROWSER_POLICY_FILE_SELECTION_DIALOGS_POLICY_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+namespace policy {
+
+// ConfigurationPolicyHandler for the FileSelectionDialogs policy.
+class FileSelectionDialogsPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  FileSelectionDialogsPolicyHandler();
+  virtual ~FileSelectionDialogsPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FileSelectionDialogsPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_FILE_SELECTION_DIALOGS_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/file_selection_dialogs_policy_handler_unittest.cc b/chrome/browser/policy/file_selection_dialogs_policy_handler_unittest.cc
new file mode 100644
index 0000000..166185b
--- /dev/null
+++ b/chrome/browser/policy/file_selection_dialogs_policy_handler_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2013 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/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/file_selection_dialogs_policy_handler.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+// Test cases for how the AllowFileSelectionDialogs policy influences the
+// PromptForDownload preference.
+class FileSelectionDialogsPolicyTest : public testing::Test {
+ protected:
+  PolicyMap policy_;
+  FileSelectionDialogsPolicyHandler handler_;
+  PrefValueMap prefs_;
+};
+
+TEST_F(FileSelectionDialogsPolicyTest, Default) {
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+  EXPECT_FALSE(prefs_.GetValue(prefs::kPromptForDownload, NULL));
+}
+
+TEST_F(FileSelectionDialogsPolicyTest, EnableFileSelectionDialogs) {
+  policy_.Set(key::kAllowFileSelectionDialogs,
+              POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER,
+              base::Value::CreateBooleanValue(true),
+              NULL);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+
+  // Allowing file-selection dialogs should not influence the PromptForDownload
+  // pref.
+  EXPECT_FALSE(prefs_.GetValue(prefs::kPromptForDownload, NULL));
+}
+
+TEST_F(FileSelectionDialogsPolicyTest, DisableFileSelectionDialogs) {
+  policy_.Set(key::kAllowFileSelectionDialogs,
+              POLICY_LEVEL_MANDATORY,
+              POLICY_SCOPE_USER,
+              base::Value::CreateBooleanValue(false),
+              NULL);
+  handler_.ApplyPolicySettings(policy_, &prefs_);
+
+  // Disabling file-selection dialogs should disable the PromptForDownload pref.
+  const base::Value* value = NULL;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kPromptForDownload, &value));
+  ASSERT_TRUE(value);
+  bool prompt_for_download = true;
+  bool result = value->GetAsBoolean(&prompt_for_download);
+  EXPECT_TRUE(result);
+  EXPECT_FALSE(prompt_for_download);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/javascript_policy_handler.cc b/chrome/browser/policy/javascript_policy_handler.cc
new file mode 100644
index 0000000..c6e682e
--- /dev/null
+++ b/chrome/browser/policy/javascript_policy_handler.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/policy/javascript_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+JavascriptPolicyHandler::JavascriptPolicyHandler() {}
+
+JavascriptPolicyHandler::~JavascriptPolicyHandler() {}
+
+bool JavascriptPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
+                                                  PolicyErrorMap* errors) {
+  const base::Value* javascript_enabled =
+      policies.GetValue(key::kJavascriptEnabled);
+  const base::Value* default_setting =
+      policies.GetValue(key::kDefaultJavaScriptSetting);
+
+  if (javascript_enabled &&
+      !javascript_enabled->IsType(base::Value::TYPE_BOOLEAN)) {
+    errors->AddError(key::kJavascriptEnabled,
+                     IDS_POLICY_TYPE_ERROR,
+                     ValueTypeToString(base::Value::TYPE_BOOLEAN));
+  }
+
+  if (default_setting && !default_setting->IsType(base::Value::TYPE_INTEGER)) {
+    errors->AddError(key::kDefaultJavaScriptSetting,
+                     IDS_POLICY_TYPE_ERROR,
+                     ValueTypeToString(base::Value::TYPE_INTEGER));
+  }
+
+  if (javascript_enabled && default_setting) {
+    errors->AddError(key::kJavascriptEnabled,
+                     IDS_POLICY_OVERRIDDEN,
+                     key::kDefaultJavaScriptSetting);
+  }
+
+  return true;
+}
+
+void JavascriptPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+                                                  PrefValueMap* prefs) {
+  int setting = CONTENT_SETTING_DEFAULT;
+  const base::Value* default_setting =
+      policies.GetValue(key::kDefaultJavaScriptSetting);
+
+  if (default_setting) {
+    default_setting->GetAsInteger(&setting);
+  } else {
+    const base::Value* javascript_enabled =
+        policies.GetValue(key::kJavascriptEnabled);
+    bool enabled = true;
+    if (javascript_enabled &&
+        javascript_enabled->GetAsBoolean(&enabled) &&
+        !enabled) {
+      setting = CONTENT_SETTING_BLOCK;
+    }
+  }
+
+  if (setting != CONTENT_SETTING_DEFAULT) {
+    prefs->SetValue(prefs::kManagedDefaultJavaScriptSetting,
+                    base::Value::CreateIntegerValue(setting));
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/javascript_policy_handler.h b/chrome/browser/policy/javascript_policy_handler.h
new file mode 100644
index 0000000..a1b4b3d
--- /dev/null
+++ b/chrome/browser/policy/javascript_policy_handler.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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_POLICY_JAVASCRIPT_POLICY_HANDLER_H_
+#define CHROME_BROWSER_POLICY_JAVASCRIPT_POLICY_HANDLER_H_
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace policy {
+
+class PolicyErrorMap;
+class PolicyMap;
+
+// Handles JavaScript policies.
+class JavascriptPolicyHandler : public ConfigurationPolicyHandler {
+ public:
+  JavascriptPolicyHandler();
+  virtual ~JavascriptPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual bool CheckPolicySettings(const PolicyMap& policies,
+                                   PolicyErrorMap* errors) OVERRIDE;
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(JavascriptPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_JAVASCRIPT_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/javascript_policy_handler_unittest.cc b/chrome/browser/policy/javascript_policy_handler_unittest.cc
new file mode 100644
index 0000000..ee9c903
--- /dev/null
+++ b/chrome/browser/policy/javascript_policy_handler_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2013 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/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+#include "chrome/browser/policy/javascript_policy_handler.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+class JavascriptPolicyHandlerTest : public ConfigurationPolicyPrefStoreTest {
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+          new JavascriptPolicyHandler));
+  }
+};
+
+TEST_F(JavascriptPolicyHandlerTest, JavascriptEnabled) {
+  // This is a boolean policy, but affects an integer preference.
+  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
+  PolicyMap policy;
+  policy.Set(key::kJavascriptEnabled,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(true),
+             NULL);
+  UpdateProviderPolicy(policy);
+  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
+  policy.Set(key::kJavascriptEnabled,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(false),
+             NULL);
+  UpdateProviderPolicy(policy);
+  const base::Value* value = NULL;
+  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
+                               &value));
+  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_BLOCK).Equals(value));
+}
+
+TEST_F(JavascriptPolicyHandlerTest, JavascriptEnabledOverridden) {
+  EXPECT_FALSE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting, NULL));
+  PolicyMap policy;
+  policy.Set(key::kJavascriptEnabled,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(false),
+             NULL);
+  UpdateProviderPolicy(policy);
+  const base::Value* value = NULL;
+  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
+                               &value));
+  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_BLOCK).Equals(value));
+  // DefaultJavaScriptSetting overrides JavascriptEnabled.
+  policy.Set(key::kDefaultJavaScriptSetting,
+             POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER,
+             base::Value::CreateIntegerValue(CONTENT_SETTING_ALLOW),
+             NULL);
+  UpdateProviderPolicy(policy);
+  EXPECT_TRUE(store_->GetValue(prefs::kManagedDefaultJavaScriptSetting,
+                               &value));
+  EXPECT_TRUE(base::FundamentalValue(CONTENT_SETTING_ALLOW).Equals(value));
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 95fe37c..0a6b9b9 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -161,6 +161,11 @@
 
 namespace {
 
+#if defined(OS_CHROMEOS)
+const int kOneHourInMs = 60 * 60 * 1000;
+const int kThreeHoursInMs = 180 * 60 * 1000;
+#endif
+
 const char kURL[] = "http://example.com";
 const char kCookieValue[] = "converted=true";
 // Assigned to Philip J. Fry to fix eventually.
@@ -2092,7 +2097,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, PRE_SessionLengthLimit) {
-  // Set the session start time to 2 hours ago.
+  // Indicate that the session started 2 hours ago and no user activity has
+  // occurred yet.
   g_browser_process->local_state()->SetInt64(
       prefs::kSessionStartTime,
       (base::TimeTicks::Now() - base::TimeDelta::FromHours(2))
@@ -2113,7 +2119,7 @@
   PolicyMap policies;
   policies.Set(key::kSessionLengthLimit, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER,
-               base::Value::CreateIntegerValue(180 * 60 * 1000),  // 3 hours.
+               base::Value::CreateIntegerValue(kThreeHoursInMs),
                NULL);
   UpdateProviderPolicy(policies);
   base::RunLoop().RunUntilIdle();
@@ -2124,7 +2130,92 @@
   EXPECT_CALL(observer, Observe(chrome::NOTIFICATION_APP_TERMINATING, _, _));
   policies.Set(key::kSessionLengthLimit, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER,
-               base::Value::CreateIntegerValue(60 * 60 * 1000),  // 1 hour.
+               base::Value::CreateIntegerValue(kOneHourInMs),
+               NULL);
+  UpdateProviderPolicy(policies);
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&observer);
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyTest, PRE_WaitForInitialUserActivityUsatisfied) {
+  // Indicate that the session started 2 hours ago and no user activity has
+  // occurred yet.
+  g_browser_process->local_state()->SetInt64(
+      prefs::kSessionStartTime,
+      (base::TimeTicks::Now() - base::TimeDelta::FromHours(2))
+          .ToInternalValue());
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyTest, WaitForInitialUserActivityUsatisfied) {
+  content::MockNotificationObserver observer;
+  content::NotificationRegistrar registrar;
+  registrar.Add(&observer,
+                chrome::NOTIFICATION_APP_TERMINATING,
+                content::NotificationService::AllSources());
+
+  // Require initial user activity.
+  PolicyMap policies;
+  policies.Set(key::kWaitForInitialUserActivity, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER,
+               new base::FundamentalValue(true),
+               NULL);
+  UpdateProviderPolicy(policies);
+  base::RunLoop().RunUntilIdle();
+
+  // Set the session length limit to 1 hour. Verify that the session is not
+  // terminated.
+  EXPECT_CALL(observer, Observe(chrome::NOTIFICATION_APP_TERMINATING, _, _))
+      .Times(0);
+  policies.Set(key::kSessionLengthLimit, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER,
+               base::Value::CreateIntegerValue(kOneHourInMs),
+               NULL);
+  UpdateProviderPolicy(policies);
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&observer);
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyTest, PRE_WaitForInitialUserActivitySatisfied) {
+  // Indicate that initial user activity in this session occurred 2 hours ago.
+  g_browser_process->local_state()->SetInt64(
+      prefs::kSessionStartTime,
+      (base::TimeTicks::Now() - base::TimeDelta::FromHours(2))
+          .ToInternalValue());
+  g_browser_process->local_state()->SetBoolean(
+      prefs::kSessionUserActivitySeen,
+      true);
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyTest, WaitForInitialUserActivitySatisfied) {
+  content::MockNotificationObserver observer;
+  content::NotificationRegistrar registrar;
+  registrar.Add(&observer,
+                chrome::NOTIFICATION_APP_TERMINATING,
+                content::NotificationService::AllSources());
+
+  // Require initial user activity and set the session length limit to 3 hours.
+  // Verify that the session is not terminated.
+  EXPECT_CALL(observer, Observe(chrome::NOTIFICATION_APP_TERMINATING, _, _))
+      .Times(0);
+  PolicyMap policies;
+  policies.Set(key::kWaitForInitialUserActivity, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER,
+               new base::FundamentalValue(true),
+               NULL);
+  policies.Set(key::kSessionLengthLimit, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER,
+               base::Value::CreateIntegerValue(kThreeHoursInMs),
+               NULL);
+  UpdateProviderPolicy(policies);
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&observer);
+
+  // Decrease the session length limit to 1 hour. Verify that the session is
+  // terminated immediately.
+  EXPECT_CALL(observer, Observe(chrome::NOTIFICATION_APP_TERMINATING, _, _));
+  policies.Set(key::kSessionLengthLimit, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER,
+               base::Value::CreateIntegerValue(kOneHourInMs),
                NULL);
   UpdateProviderPolicy(policies);
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/policy/policy_bundle.cc b/chrome/browser/policy/policy_bundle.cc
index eecca17..90e4a0a 100644
--- a/chrome/browser/policy/policy_bundle.cc
+++ b/chrome/browser/policy/policy_bundle.cc
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "chrome/browser/policy/policy_map.h"
 
 namespace policy {
 
diff --git a/chrome/browser/policy/policy_bundle.h b/chrome/browser/policy/policy_bundle.h
index a7149ca..339d6b4 100644
--- a/chrome/browser/policy/policy_bundle.h
+++ b/chrome/browser/policy/policy_bundle.h
@@ -9,12 +9,11 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace policy {
 
-class PolicyMap;
-
 // Maps policy namespaces to PolicyMaps.
 class PolicyBundle {
  public:
diff --git a/chrome/browser/policy/policy_domain_descriptor.h b/chrome/browser/policy/policy_domain_descriptor.h
index 2106633..6293900 100644
--- a/chrome/browser/policy/policy_domain_descriptor.h
+++ b/chrome/browser/policy/policy_domain_descriptor.h
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/policy/policy_service.h"
+#include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/schema.h"
 
 namespace policy {
diff --git a/chrome/browser/policy/policy_service.cc b/chrome/browser/policy/policy_service.cc
index 0f65c3b..cd07867 100644
--- a/chrome/browser/policy/policy_service.cc
+++ b/chrome/browser/policy/policy_service.cc
@@ -8,38 +8,6 @@
 
 namespace policy {
 
-PolicyNamespace::PolicyNamespace() {}
-
-PolicyNamespace::PolicyNamespace(PolicyDomain domain,
-                                 const std::string& component_id)
-    : domain(domain),
-      component_id(component_id) {}
-
-PolicyNamespace::PolicyNamespace(const PolicyNamespace& other)
-    : domain(other.domain),
-      component_id(other.component_id) {}
-
-PolicyNamespace::~PolicyNamespace() {}
-
-PolicyNamespace& PolicyNamespace::operator=(const PolicyNamespace& other) {
-  domain = other.domain;
-  component_id = other.component_id;
-  return *this;
-}
-
-bool PolicyNamespace::operator<(const PolicyNamespace& other) const {
-  return domain < other.domain ||
-         (domain == other.domain && component_id < other.component_id);
-}
-
-bool PolicyNamespace::operator==(const PolicyNamespace& other) const {
-  return domain == other.domain && component_id == other.component_id;
-}
-
-bool PolicyNamespace::operator!=(const PolicyNamespace& other) const {
-  return !(*this == other);
-}
-
 PolicyChangeRegistrar::PolicyChangeRegistrar(PolicyService* policy_service,
                                              const PolicyNamespace& ns)
     : policy_service_(policy_service),
diff --git a/chrome/browser/policy/policy_service.h b/chrome/browser/policy/policy_service.h
index 1d8d135..b6c6c0e 100644
--- a/chrome/browser/policy/policy_service.h
+++ b/chrome/browser/policy/policy_service.h
@@ -12,44 +12,12 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/policy/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
 
 namespace policy {
 
 class PolicyDomainDescriptor;
 
-// Policies are namespaced by a (PolicyDomain, ID) pair. The meaning of the ID
-// string depends on the domain; for example, if the PolicyDomain is
-// "extensions" then the ID identifies the extension that the policies control.
-enum PolicyDomain {
-  // The component ID for chrome policies is always the empty string.
-  POLICY_DOMAIN_CHROME,
-
-  // The extensions policy domain is a work in progress. Included here for
-  // tests.
-  POLICY_DOMAIN_EXTENSIONS,
-
-  // Must be the last entry.
-  POLICY_DOMAIN_SIZE,
-};
-
-// Groups a policy domain and a component ID in a single object representing
-// a policy namespace. Objects of this class can be used as keys in std::maps.
-struct PolicyNamespace {
- public:
-  PolicyNamespace();
-  PolicyNamespace(PolicyDomain domain, const std::string& component_id);
-  PolicyNamespace(const PolicyNamespace& other);
-  ~PolicyNamespace();
-
-  PolicyNamespace& operator=(const PolicyNamespace& other);
-  bool operator<(const PolicyNamespace& other) const;
-  bool operator==(const PolicyNamespace& other) const;
-  bool operator!=(const PolicyNamespace& other) const;
-
-  PolicyDomain domain;
-  std::string component_id;
-};
-
 // The PolicyService merges policies from all available sources, taking into
 // account their priorities. Policy clients can retrieve policy for their domain
 // and register for notifications on policy updates.
diff --git a/chrome/browser/policy/policy_statistics_collector.cc b/chrome/browser/policy/policy_statistics_collector.cc
index e972c94..e2f59b9 100644
--- a/chrome/browser/policy/policy_statistics_collector.cc
+++ b/chrome/browser/policy/policy_statistics_collector.cc
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/task_runner.h"
@@ -26,8 +26,7 @@
     PolicyService* policy_service,
     PrefService* prefs,
     const scoped_refptr<base::TaskRunner>& task_runner)
-    : max_policy_id_(-1),
-      policy_service_(policy_service),
+    : policy_service_(policy_service),
       prefs_(prefs),
       task_runner_(task_runner) {
 }
@@ -55,21 +54,7 @@
 }
 
 void PolicyStatisticsCollector::RecordPolicyUse(int id) {
-  if (max_policy_id_ == -1) {
-    const policy::PolicyDefinitionList* policy_list =
-        policy::GetChromePolicyDefinitionList();
-    for (const policy::PolicyDefinitionList::Entry* policy = policy_list->begin;
-         policy != policy_list->end; ++policy) {
-      if (policy->id > max_policy_id_)
-        max_policy_id_ = policy->id;
-    }
-  }
-
-  // Set the boundary to be max policy id + 1. Note that this may decrease in
-  // future builds if the policy with maximum id is removed. This does not
-  // pose a problem.
-  DCHECK_LE(id, max_policy_id_);
-  UMA_HISTOGRAM_ENUMERATION("Enterprise.Policies", id, max_policy_id_ + 1);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Enterprise.Policies", id);
 }
 
 void PolicyStatisticsCollector::CollectStatistics() {
diff --git a/chrome/browser/policy/policy_statistics_collector.h b/chrome/browser/policy/policy_statistics_collector.h
index 352a591..326d7d9 100644
--- a/chrome/browser/policy/policy_statistics_collector.h
+++ b/chrome/browser/policy/policy_statistics_collector.h
@@ -47,8 +47,6 @@
   void CollectStatistics();
   void ScheduleUpdate(base::TimeDelta delay);
 
-  int max_policy_id_;
-
   PolicyService* policy_service_;
   PrefService* prefs_;
 
diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
index 3623b8f..911866b 100644
--- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
+++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
@@ -64,9 +64,8 @@
   optional string proxy_bypass_list = 4;
 }
 
-// This was added to the protobuf definition but never implemented. Chrome can
-// meanwhile lock down access to media devices via a user policy, so the
-// device-level setting is deprecated for good.
+// This is used by chromeos, make sure to do cleanup there before marking it as
+// obsolette.
 message CameraEnabledProto {
   optional bool camera_enabled = 1;
 }
@@ -97,6 +96,7 @@
   optional bool report_boot_mode = 3;
   optional bool report_location = 4;
   optional bool report_network_interfaces = 5;
+  optional bool report_users = 6;
 }
 
 message EphemeralUsersEnabledProto {
@@ -534,12 +534,18 @@
   optional string login_screen_power_management = 1;
 }
 
+message AutoCleanupSettigsProto {
+  // Configures strategy for automatic clean-up process that is run when device
+  // runs out of free disk space. One of "remove-lru", "remove-lru-if-dormant".
+  optional string clean_up_strategy = 1;
+}
+
 message ChromeDeviceSettingsProto {
   optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1;
   optional UserWhitelistProto user_whitelist = 2;
   optional GuestModeEnabledProto guest_mode_enabled = 3;
   optional DeviceProxySettingsProto device_proxy_settings = 4;
-  optional CameraEnabledProto OBSOLETE_camera_enabled = 5 [deprecated = true];
+  optional CameraEnabledProto camera_enabled = 5;
   optional ShowUserNamesOnSigninProto show_user_names = 6;
   optional DataRoamingEnabledProto data_roaming_enabled = 7;
   optional AllowNewUsersProto allow_new_users = 8;
@@ -565,4 +571,5 @@
   optional SupervisedUsersSettingsProto supervised_users_settings = 28;
   optional LoginScreenPowerManagementProto login_screen_power_management = 29;
   optional SystemUse24HourClockProto use_24hour_clock = 30;
+  optional AutoCleanupSettigsProto auto_clean_up_settings = 31;
 }
diff --git a/chrome/browser/policy/proto/cloud/device_management_backend.proto b/chrome/browser/policy/proto/cloud/device_management_backend.proto
index f4645f7..1b0bb35 100644
--- a/chrome/browser/policy/proto/cloud/device_management_backend.proto
+++ b/chrome/browser/policy/proto/cloud/device_management_backend.proto
@@ -408,6 +408,24 @@
   optional string imei = 4;
 }
 
+// Details about a device user.
+message DeviceUser {
+  // Types of device users which can be reported.
+  enum UserType {
+    // A user managed by the same domain as the device.
+    USER_TYPE_MANAGED = 0;
+
+    // A user not managed by the same domain as the device.
+    USER_TYPE_UNMANAGED = 1;
+  }
+
+  // The type of the user.
+  required UserType type = 1;
+
+  // Email address of the user. Present only if the user type is managed.
+  optional string email = 2;
+}
+
 // Report device level status.
 message DeviceStatusReportRequest {
   // The OS version reported by the device is a platform version
@@ -435,6 +453,9 @@
 
   // List of network interfaces.
   repeated NetworkInterface network_interface = 8;
+
+  // List of recent device users, in descending order by last login time.
+  repeated DeviceUser user = 9;
 }
 
 // Report session (a user on one device) level status.
diff --git a/chrome/browser/policy/url_blacklist_policy_handler.cc b/chrome/browser/policy/url_blacklist_policy_handler.cc
new file mode 100644
index 0000000..9fe7708
--- /dev/null
+++ b/chrome/browser/policy/url_blacklist_policy_handler.cc
@@ -0,0 +1,83 @@
+// Copyright 2013 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/policy/url_blacklist_policy_handler.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+URLBlacklistPolicyHandler::URLBlacklistPolicyHandler() {}
+
+URLBlacklistPolicyHandler::~URLBlacklistPolicyHandler() {}
+
+bool URLBlacklistPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
+                                                    PolicyErrorMap* errors) {
+  const base::Value* disabled_schemes =
+      policies.GetValue(key::kDisabledSchemes);
+  const base::Value* url_blacklist = policies.GetValue(key::kURLBlacklist);
+
+  if (disabled_schemes && !disabled_schemes->IsType(base::Value::TYPE_LIST)) {
+    errors->AddError(key::kDisabledSchemes,
+                     IDS_POLICY_TYPE_ERROR,
+                     ValueTypeToString(base::Value::TYPE_LIST));
+  }
+
+  if (url_blacklist && !url_blacklist->IsType(base::Value::TYPE_LIST)) {
+    errors->AddError(key::kURLBlacklist,
+                     IDS_POLICY_TYPE_ERROR,
+                     ValueTypeToString(base::Value::TYPE_LIST));
+  }
+
+  return true;
+}
+
+void URLBlacklistPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+                                                    PrefValueMap* prefs) {
+  const base::Value* url_blacklist_policy =
+      policies.GetValue(key::kURLBlacklist);
+  const base::ListValue* url_blacklist = NULL;
+  if (url_blacklist_policy)
+    url_blacklist_policy->GetAsList(&url_blacklist);
+  const base::Value* disabled_schemes_policy =
+      policies.GetValue(key::kDisabledSchemes);
+  const base::ListValue* disabled_schemes = NULL;
+  if (disabled_schemes_policy)
+    disabled_schemes_policy->GetAsList(&disabled_schemes);
+
+  scoped_ptr<base::ListValue> merged_url_blacklist(new base::ListValue());
+
+  // We start with the DisabledSchemes because we have size limit when
+  // handling URLBlacklists.
+  if (disabled_schemes) {
+    for (base::ListValue::const_iterator entry(disabled_schemes->begin());
+         entry != disabled_schemes->end(); ++entry) {
+      std::string entry_value;
+      if ((*entry)->GetAsString(&entry_value)) {
+        entry_value.append("://*");
+        merged_url_blacklist->AppendString(entry_value);
+      }
+    }
+  }
+
+  if (url_blacklist) {
+    for (base::ListValue::const_iterator entry(url_blacklist->begin());
+         entry != url_blacklist->end(); ++entry) {
+      if ((*entry)->IsType(Value::TYPE_STRING))
+        merged_url_blacklist->Append((*entry)->DeepCopy());
+    }
+  }
+
+  if (disabled_schemes || url_blacklist)
+    prefs->SetValue(prefs::kUrlBlacklist, merged_url_blacklist.release());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/url_blacklist_policy_handler.h b/chrome/browser/policy/url_blacklist_policy_handler.h
new file mode 100644
index 0000000..36670fa
--- /dev/null
+++ b/chrome/browser/policy/url_blacklist_policy_handler.h
@@ -0,0 +1,37 @@
+// Copyright 2013 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_POLICY_URL_BLACKLIST_POLICY_HANDLER_H_
+#define CHROME_BROWSER_POLICY_URL_BLACKLIST_POLICY_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace policy {
+
+class PolicyErrorMap;
+class PolicyMap;
+
+// Handles URLBlacklist policies.
+class URLBlacklistPolicyHandler : public ConfigurationPolicyHandler {
+ public:
+  URLBlacklistPolicyHandler();
+  virtual ~URLBlacklistPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual bool CheckPolicySettings(const PolicyMap& policies,
+                                   PolicyErrorMap* errors) OVERRIDE;
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(URLBlacklistPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_URL_BLACKLIST_POLICY_HANDLER_H_
diff --git a/chrome/browser/policy/url_blacklist_policy_handler_unittest.cc b/chrome/browser/policy/url_blacklist_policy_handler_unittest.cc
new file mode 100644
index 0000000..58b5504
--- /dev/null
+++ b/chrome/browser/policy/url_blacklist_policy_handler_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright 2013 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/memory/scoped_ptr.h"
+#include "base/prefs/pref_value_map.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/url_blacklist_policy_handler.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+const char kTestDisabledScheme[] = "kTestDisabledScheme";
+const char kTestBlacklistValue[] = "kTestBlacklistValue";
+}  // namespace
+
+class URLBlacklistPolicyHandlerTest : public testing::Test {
+ protected:
+  void SetPolicy(const std::string& key, base::Value* value) {
+    policies_.Set(key, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, value, NULL);
+  }
+  bool CheckPolicy(const std::string& key, base::Value* value) {
+    SetPolicy(key, value);
+    return handler_.CheckPolicySettings(policies_, &errors_);
+  }
+  void ApplyPolicies() {
+    handler_.ApplyPolicySettings(policies_, &prefs_);
+  }
+
+  URLBlacklistPolicyHandler handler_;
+  PolicyErrorMap errors_;
+  PolicyMap policies_;
+  PrefValueMap prefs_;
+};
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       CheckPolicySettings_DisabledSchemesUnspecified) {
+  EXPECT_TRUE(CheckPolicy(key::kURLBlacklist, new base::ListValue));
+  EXPECT_EQ(0U, errors_.size());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       CheckPolicySettings_URLBlacklistUnspecified) {
+  EXPECT_TRUE(CheckPolicy(key::kDisabledSchemes, new base::ListValue));
+  EXPECT_EQ(0U, errors_.size());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       CheckPolicySettings_DisabledSchemesWrongType) {
+  // The policy expects a list. Give it a boolean.
+  EXPECT_TRUE(CheckPolicy(key::kDisabledSchemes,
+                          base::Value::CreateBooleanValue(false)));
+  EXPECT_EQ(1U, errors_.size());
+  const std::string expected = key::kDisabledSchemes;
+  const std::string actual = errors_.begin()->first;
+  EXPECT_EQ(expected, actual);
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       CheckPolicySettings_URLBlacklistWrongType) {
+  // The policy expects a list. Give it a boolean.
+  EXPECT_TRUE(CheckPolicy(key::kURLBlacklist,
+                          base::Value::CreateBooleanValue(false)));
+  EXPECT_EQ(1U, errors_.size());
+  const std::string expected = key::kURLBlacklist;
+  const std::string actual = errors_.begin()->first;
+  EXPECT_EQ(expected, actual);
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest, ApplyPolicySettings_NothingSpecified) {
+  ApplyPolicies();
+  EXPECT_FALSE(prefs_.GetValue(prefs::kUrlBlacklist, NULL));
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_DisabledSchemesWrongType) {
+  // The policy expects a list. Give it a boolean.
+  SetPolicy(key::kDisabledSchemes, base::Value::CreateBooleanValue(false));
+  ApplyPolicies();
+  EXPECT_FALSE(prefs_.GetValue(prefs::kUrlBlacklist, NULL));
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_URLBlacklistWrongType) {
+  // The policy expects a list. Give it a boolean.
+  SetPolicy(key::kURLBlacklist, base::Value::CreateBooleanValue(false));
+  ApplyPolicies();
+  EXPECT_FALSE(prefs_.GetValue(prefs::kUrlBlacklist, NULL));
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_DisabledSchemesEmpty) {
+  SetPolicy(key::kDisabledSchemes, new base::ListValue);
+  ApplyPolicies();
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(0U, out_list->GetSize());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_URLBlacklistEmpty) {
+  SetPolicy(key::kURLBlacklist, new base::ListValue);
+  ApplyPolicies();
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(0U, out_list->GetSize());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_DisabledSchemesWrongElementType) {
+  // The policy expects string-valued elements. Give it booleans.
+  scoped_ptr<base::ListValue> in(new base::ListValue);
+  in->AppendBoolean(false);
+  SetPolicy(key::kDisabledSchemes, in.release());
+  ApplyPolicies();
+
+  // The element should be skipped.
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(0U, out_list->GetSize());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_URLBlacklistWrongElementType) {
+  // The policy expects string-valued elements. Give it booleans.
+  scoped_ptr<base::ListValue> in(new base::ListValue);
+  in->AppendBoolean(false);
+  SetPolicy(key::kURLBlacklist, in.release());
+  ApplyPolicies();
+
+  // The element should be skipped.
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(0U, out_list->GetSize());
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_DisabledSchemesSuccessful) {
+  scoped_ptr<base::ListValue> in_disabled_schemes(new base::ListValue);
+  in_disabled_schemes->AppendString(kTestDisabledScheme);
+  SetPolicy(key::kDisabledSchemes, in_disabled_schemes.release());
+  ApplyPolicies();
+
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(1U, out_list->GetSize());
+
+  std::string out_string;
+  EXPECT_TRUE(out_list->GetString(0U, &out_string));
+  EXPECT_EQ(kTestDisabledScheme + std::string("://*"), out_string);
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest,
+       ApplyPolicySettings_URLBlacklistSuccessful) {
+  scoped_ptr<base::ListValue> in_url_blacklist(new base::ListValue);
+  in_url_blacklist->AppendString(kTestBlacklistValue);
+  SetPolicy(key::kURLBlacklist, in_url_blacklist.release());
+  ApplyPolicies();
+
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(1U, out_list->GetSize());
+
+  std::string out_string;
+  EXPECT_TRUE(out_list->GetString(0U, &out_string));
+  EXPECT_EQ(kTestBlacklistValue, out_string);
+}
+
+TEST_F(URLBlacklistPolicyHandlerTest, ApplyPolicySettings_MergeSuccessful) {
+  scoped_ptr<base::ListValue> in_disabled_schemes(new base::ListValue);
+  in_disabled_schemes->AppendString(kTestDisabledScheme);
+  SetPolicy(key::kDisabledSchemes, in_disabled_schemes.release());
+
+  scoped_ptr<base::ListValue> in_url_blacklist(new base::ListValue);
+  in_url_blacklist->AppendString(kTestBlacklistValue);
+  SetPolicy(key::kURLBlacklist, in_url_blacklist.release());
+
+  ApplyPolicies();
+
+  base::Value* out;
+  EXPECT_TRUE(prefs_.GetValue(prefs::kUrlBlacklist, &out));
+  base::ListValue* out_list;
+  EXPECT_TRUE(out->GetAsList(&out_list));
+  EXPECT_EQ(2U, out_list->GetSize());
+
+  std::string out1;
+  EXPECT_TRUE(out_list->GetString(0U, &out1));
+  EXPECT_EQ(kTestDisabledScheme + std::string("://*"), out1);
+
+  std::string out2;
+  EXPECT_TRUE(out_list->GetString(1U, &out2));
+  EXPECT_EQ(kTestBlacklistValue, out2);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/pref_service_flags_storage.cc b/chrome/browser/pref_service_flags_storage.cc
index ddd6705..751ac1e 100644
--- a/chrome/browser/pref_service_flags_storage.cc
+++ b/chrome/browser/pref_service_flags_storage.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/pref_service_flags_storage.h"
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 
 namespace about_flags {
diff --git a/chrome/browser/prefs/chrome_pref_service_unittest.cc b/chrome/browser/prefs/chrome_pref_service_unittest.cc
index 39d9786..4373792 100644
--- a/chrome/browser/prefs/chrome_pref_service_unittest.cc
+++ b/chrome/browser/prefs/chrome_pref_service_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/policy/configuration_policy_pref_store.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/command_line_pref_store.h"
 #include "chrome/browser/prefs/pref_service_mock_builder.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/prefs/pref_functional_browsertest.cc b/chrome/browser/prefs/pref_functional_browsertest.cc
index 86bc5ee..d33faef 100644
--- a/chrome/browser/prefs/pref_functional_browsertest.cc
+++ b/chrome/browser/prefs/pref_functional_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
@@ -158,3 +159,97 @@
       prefs::kShowBookmarkBar));
   EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state());
 }
+
+// Verify images are not blocked in incognito mode.
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestImagesNotBlockedInIncognito) {
+  ASSERT_TRUE(test_server()->Start());
+  GURL url = test_server()->GetURL("files/settings/image_page.html");
+  Browser* incognito_browser = CreateIncognitoBrowser();
+  ui_test_utils::NavigateToURLWithDisposition(
+      incognito_browser,
+      url,
+      CURRENT_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  bool result = false;
+  std::string script =
+      "for (i=0; i < document.images.length; i++) {"
+      "  if ((document.images[i].naturalWidth != 0) &&"
+      "      (document.images[i].naturalHeight != 0)) {"
+      "    window.domAutomationController.send(true);"
+      "  }"
+      "}"
+      "window.domAutomationController.send(false);";
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      incognito_browser->tab_strip_model()->GetActiveWebContents(),
+      script,
+      &result));
+  EXPECT_TRUE(result);
+}
+
+// Verify setting homepage preference to newtabpage across restarts. Part1
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, PRE_TestHomepageNewTabpagePrefs) {
+  browser()->profile()->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage,
+                                               true);
+}
+
+// Verify setting homepage preference to newtabpage across restarts. Part2
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestHomepageNewTabpagePrefs) {
+  EXPECT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
+      prefs::kHomePageIsNewTabPage));
+}
+
+// Verify setting homepage preference to specific url. Part1
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, PRE_TestHomepagePrefs) {
+  GURL home_page_url("http://www.google.com");
+
+  PrefService* prefs = browser()->profile()->GetPrefs();
+  prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false);
+  const PrefService::Preference* pref =
+      prefs->FindPreference(prefs::kHomePage);
+  if (pref && !pref->IsManaged()) {
+    prefs->SetString(prefs::kHomePage, home_page_url.spec());
+  }
+}
+
+// Verify setting homepage preference to specific url. Part2
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestHomepagePrefs) {
+  GURL home_page_url("http://www.google.com");
+
+  PrefService* prefs = browser()->profile()->GetPrefs();
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage));
+  EXPECT_EQ(home_page_url.spec(), prefs->GetString(prefs::kHomePage));
+}
+
+// Verify the security preference under privacy across restarts. Part1
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, PRE_TestPrivacySecurityPrefs) {
+  PrefService* prefs = browser()->profile()->GetPrefs();
+
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kNetworkPredictionEnabled));
+  prefs->SetBoolean(prefs::kNetworkPredictionEnabled, false);
+
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
+  prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false);
+
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
+  prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
+
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
+  prefs->SetBoolean(prefs::kSearchSuggestEnabled, false);
+}
+
+// Verify the security preference under privacy across restarts. Part2
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestPrivacySecurityPrefs) {
+  PrefService* prefs = browser()->profile()->GetPrefs();
+
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kNetworkPredictionEnabled));
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kSafeBrowsingEnabled));
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
+  EXPECT_FALSE(prefs->GetBoolean(prefs::kSearchSuggestEnabled));
+}
+
+// Verify that we have some Local State prefs.
+IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestHaveLocalStatePrefs) {
+  EXPECT_TRUE(g_browser_process->local_state()->GetPreferenceValues());
+}
+
diff --git a/chrome/browser/prefs/pref_metrics_service.cc b/chrome/browser/prefs/pref_metrics_service.cc
index 18153bf..ff6dcfa 100644
--- a/chrome/browser/prefs/pref_metrics_service.cc
+++ b/chrome/browser/prefs/pref_metrics_service.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
@@ -18,7 +19,6 @@
 // http://crbug.com/276485
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/prefs/synced_pref_change_registrar.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
diff --git a/chrome/browser/prefs/pref_metrics_service_unittest.cc b/chrome/browser/prefs/pref_metrics_service_unittest.cc
index df8fd5d..2b7f313 100644
--- a/chrome/browser/prefs/pref_metrics_service_unittest.cc
+++ b/chrome/browser/prefs/pref_metrics_service_unittest.cc
@@ -5,10 +5,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/statistics_recorder.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/prefs/pref_metrics_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/prefs/pref_model_associator.cc b/chrome/browser/prefs/pref_model_associator.cc
index 42cbae2..80f34ed 100644
--- a/chrome/browser/prefs/pref_model_associator.cc
+++ b/chrome/browser/prefs/pref_model_associator.cc
@@ -105,9 +105,6 @@
       pref_name.c_str());
   VLOG(1) << "Associating preference " << pref_name;
 
-  // Set if a migrated pref name has been added to the synced_preferences_ list.
-  bool remembered_migrated_synced_preference = false;
-
   if (sync_pref.IsValid()) {
     const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref);
     DCHECK(pref_name == preference.name() ||
@@ -123,6 +120,7 @@
     }
 
     if (user_pref_value) {
+      DVLOG(1) << "Found user pref value for " << pref_name;
       // We have both server and local values. Merge them.
       scoped_ptr<Value> new_value(
           MergePreference(pref_name, *user_pref_value, *sync_value));
@@ -180,12 +178,6 @@
           }
           if (migrated_preference_list)
             (*migrated_preference_list)[old_pref_name] = old_sync_data;
-
-          // Keep track of the name of the synced pref. This will be idempotent
-          // with the insertion of pref_name below when the migrated value has
-          // already been synced, not so when it has not.
-          synced_preferences_.insert(preference.name());
-          remembered_migrated_synced_preference = true;
         } else {
           sync_changes->push_back(
             syncer::SyncChange(FROM_HERE,
@@ -199,6 +191,7 @@
     } else {
       LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
     }
+    synced_preferences_.insert(preference.name());
   } else if (user_pref_value) {
     // The server does not know about this preference and should be added
     // to the syncer's database.
@@ -211,19 +204,13 @@
         syncer::SyncChange(FROM_HERE,
                            syncer::SyncChange::ACTION_ADD,
                            sync_data));
-  } else {
-    // This pref does not have a sync value but also does not have a user
-    // controlled value (either it's a default value or it's policy controlled,
-    // either way it's not interesting). We can ignore it. Once it gets changed,
-    // we'll send the new user controlled value to the syncer.
-    return;
+    synced_preferences_.insert(pref_name);
   }
 
-  // Make sure we add it to our list of synced preferences so we know what
-  // the server is aware of.
-  if (!remembered_migrated_synced_preference)
-    synced_preferences_.insert(pref_name);
-  return;
+  // Else this pref does not have a sync value but also does not have a user
+  // controlled value (either it's a default value or it's policy controlled,
+  // either way it's not interesting). We can ignore it. Once it gets changed,
+  // we'll send the new user controlled value to the syncer.
 }
 
 syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
@@ -302,6 +289,7 @@
             syncer::SyncChange::ACTION_UPDATE;
     new_changes.push_back(
         syncer::SyncChange(FROM_HERE, change_type, migrated_pref_iter->second));
+    synced_preferences_.insert(migrated_pref_iter->first);
   }
 
   // Push updates to sync.
diff --git a/chrome/browser/prefs/pref_model_associator.h b/chrome/browser/prefs/pref_model_associator.h
index 0c0cb66..5dc98da 100644
--- a/chrome/browser/prefs/pref_model_associator.h
+++ b/chrome/browser/prefs/pref_model_associator.h
@@ -111,12 +111,6 @@
 
  protected:
   friend class ProfileSyncServicePreferenceTest;
-  FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
-                           ModelAssociationCloudHasOldMigratedData);
-  FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
-                           ModelAssociationCloudHasNewMigratedData);
-  FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
-                           ModelAssociationCloudAddsOldAndNewMigratedData);
 
   typedef std::map<std::string, syncer::SyncData> SyncDataMap;
 
diff --git a/chrome/browser/prefs/pref_model_associator_unittest.cc b/chrome/browser/prefs/pref_model_associator_unittest.cc
index 74c985e..08884c7 100644
--- a/chrome/browser/prefs/pref_model_associator_unittest.cc
+++ b/chrome/browser/prefs/pref_model_associator_unittest.cc
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/memory/scoped_ptr.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/prefs/pref_model_associator.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/prefs/scoped_user_pref_update.cc b/chrome/browser/prefs/scoped_user_pref_update.cc
deleted file mode 100644
index 0030029..0000000
--- a/chrome/browser/prefs/scoped_user_pref_update.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2011 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/prefs/scoped_user_pref_update.h"
-
-#include "base/logging.h"
-#include "base/prefs/pref_notifier.h"
-#include "base/prefs/pref_service.h"
-
-namespace subtle {
-
-ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
-                                                   const char* path)
-    : service_(service),
-      path_(path),
-      value_(NULL) {}
-
-ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
-  Notify();
-}
-
-Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
-  if (!value_)
-    value_ = service_->GetMutableUserPref(path_.c_str(), type);
-  return value_;
-}
-
-void ScopedUserPrefUpdateBase::Notify() {
-  if (value_) {
-    service_->ReportUserPrefChanged(path_);
-    value_ = NULL;
-  }
-}
-
-}  // namespace subtle
diff --git a/chrome/browser/prefs/scoped_user_pref_update.h b/chrome/browser/prefs/scoped_user_pref_update.h
deleted file mode 100644
index e83595b..0000000
--- a/chrome/browser/prefs/scoped_user_pref_update.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2012 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.
-//
-// A helper class that assists preferences in firing notifications when lists
-// or dictionaries are changed.
-
-#ifndef CHROME_BROWSER_PREFS_SCOPED_USER_PREF_UPDATE_H_
-#define CHROME_BROWSER_PREFS_SCOPED_USER_PREF_UPDATE_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/prefs/pref_service.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/values.h"
-
-class PrefService;
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
-namespace subtle {
-
-// Base class for ScopedUserPrefUpdateTemplate that contains the parts
-// that do not depend on ScopedUserPrefUpdateTemplate's template parameter.
-//
-// We need this base class mostly for making it a friend of PrefService
-// and getting access to PrefService::GetMutableUserPref and
-// PrefService::ReportUserPrefChanged.
-class ScopedUserPrefUpdateBase : public base::NonThreadSafe {
- protected:
-  ScopedUserPrefUpdateBase(PrefService* service, const char* path);
-
-  // Calls Notify().
-  ~ScopedUserPrefUpdateBase();
-
-  // Sets |value_| to |service_|->GetMutableUserPref and returns it.
-  base::Value* GetValueOfType(base::Value::Type type);
-
- private:
-  // If |value_| is not null, triggers a notification of PrefObservers and
-  // resets |value_|.
-  void Notify();
-
-  // Weak pointer.
-  PrefService* service_;
-  // Path of the preference being updated.
-  std::string path_;
-  // Cache of value from user pref store (set between Get() and Notify() calls).
-  base::Value* value_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase);
-};
-
-}  // namespace subtle
-
-// Class to support modifications to DictionaryValues and ListValues while
-// guaranteeing that PrefObservers are notified of changed values.
-//
-// This class may only be used on the UI thread as it requires access to the
-// PrefService.
-template <typename T, base::Value::Type type_enum_value>
-class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
- public:
-  ScopedUserPrefUpdate(PrefService* service, const char* path)
-      : ScopedUserPrefUpdateBase(service, path) {}
-
-  // Triggers an update notification if Get() was called.
-  virtual ~ScopedUserPrefUpdate() {}
-
-  // Returns a mutable |T| instance that
-  // - is already in the user pref store, or
-  // - is (silently) created and written to the user pref store if none existed
-  //   before.
-  //
-  // Calling Get() implies that an update notification is necessary at
-  // destruction time.
-  //
-  // The ownership of the return value remains with the user pref store.
-  // Virtual so it can be overriden in subclasses that transform the value
-  // before returning it (for example to return a subelement of a dictionary).
-  virtual T* Get() {
-    return static_cast<T*>(GetValueOfType(type_enum_value));
-  }
-
-  T& operator*() {
-    return *Get();
-  }
-
-  T* operator->() {
-    return Get();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
-};
-
-typedef ScopedUserPrefUpdate<base::DictionaryValue,
-                             base::Value::TYPE_DICTIONARY>
-    DictionaryPrefUpdate;
-typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
-    ListPrefUpdate;
-
-#endif  // CHROME_BROWSER_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/chrome/browser/prefs/scoped_user_pref_update_unittest.cc b/chrome/browser/prefs/scoped_user_pref_update_unittest.cc
deleted file mode 100644
index e38c12f..0000000
--- a/chrome/browser/prefs/scoped_user_pref_update_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2011 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/prefs/mock_pref_change_callback.h"
-#include "base/prefs/pref_change_registrar.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
-#include "chrome/test/base/testing_pref_service_syncable.h"
-#include "components/user_prefs/pref_registry_syncable.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::Mock;
-
-class ScopedUserPrefUpdateTest : public testing::Test {
- public:
-  ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
-  virtual ~ScopedUserPrefUpdateTest() {}
-
- protected:
-  virtual void SetUp() {
-    prefs_.registry()->RegisterDictionaryPref(
-        kPref,
-        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-    registrar_.Init(&prefs_);
-    registrar_.Add(kPref, observer_.GetCallback());
-  }
-
-  static const char kPref[];
-  static const char kKey[];
-  static const char kValue[];
-
-  TestingPrefServiceSyncable prefs_;
-  MockPrefChangeCallback observer_;
-  PrefChangeRegistrar registrar_;
-};
-
-const char ScopedUserPrefUpdateTest::kPref[] = "name";
-const char ScopedUserPrefUpdateTest::kKey[] = "key";
-const char ScopedUserPrefUpdateTest::kValue[] = "value";
-
-TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
-  // Dictionary that will be expected to be set at the end.
-  DictionaryValue expected_dictionary;
-  expected_dictionary.SetString(kKey, kValue);
-
-  {
-    EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
-    DictionaryPrefUpdate update(&prefs_, kPref);
-    DictionaryValue* value = update.Get();
-    ASSERT_TRUE(value);
-    value->SetString(kKey, kValue);
-
-    // The dictionary was created for us but the creation should have happened
-    // silently without notifications.
-    Mock::VerifyAndClearExpectations(&observer_);
-
-    // Modifications happen online and are instantly visible, though.
-    const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
-    ASSERT_TRUE(current_value);
-    EXPECT_TRUE(expected_dictionary.Equals(current_value));
-
-    // Now we are leaving the scope of the update so we should be notified.
-    observer_.Expect(kPref, &expected_dictionary);
-  }
-  Mock::VerifyAndClearExpectations(&observer_);
-
-  const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
-  ASSERT_TRUE(current_value);
-  EXPECT_TRUE(expected_dictionary.Equals(current_value));
-}
-
-TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
-  const DictionaryValue* old_value = prefs_.GetDictionary(kPref);
-  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
-  {
-    DictionaryPrefUpdate update(&prefs_, kPref);
-  }
-  const DictionaryValue* new_value = prefs_.GetDictionary(kPref);
-  EXPECT_EQ(old_value, new_value);
-  Mock::VerifyAndClearExpectations(&observer_);
-}
diff --git a/chrome/browser/prefs/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc
index 3ce2fa6..c884187 100644
--- a/chrome/browser/prefs/session_startup_pref.cc
+++ b/chrome/browser/prefs/session_startup_pref.cc
@@ -8,10 +8,10 @@
 
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/net/url_fixer_upper.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index cf25d05..363f2f5 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -2626,8 +2626,7 @@
 
 // Checks that when the cache is cleared, prerenders are cancelled but
 // prerendering history is not cleared.
-// Flaky/times out on linux_aura, win, mac - http://crbug.com/270948
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, DISABLED_PrerenderClearCache) {
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderClearCache) {
   PrerenderTestURL("files/prerender/prerender_page.html",
                    FINAL_STATUS_CACHE_OR_HISTORY_CLEARED,
                    1);
@@ -2905,6 +2904,12 @@
 class PrerenderBrowserTestWithExtensions : public PrerenderBrowserTest,
                                            public ExtensionApiTest {
  public:
+  PrerenderBrowserTestWithExtensions() {
+    // The individual tests start the test server through ExtensionApiTest, so
+    // the port number can be passed through to the extension.
+    autostart_test_server_ = false;
+  }
+
   virtual void SetUp() OVERRIDE {
     PrerenderBrowserTest::SetUp();
   }
@@ -2930,9 +2935,14 @@
 };
 
 // http://crbug.com/177163
+#if defined(OS_WIN) && !defined(NDEBUG)
+#define MAYBE_WebNavigation DISABLED_WebNavigation
+#else
+#define MAYBE_WebNavigation WebNavigation
+#endif  // defined(OS_WIN) && !defined(NDEBUG)
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithExtensions,
-                       DISABLED_WebNavigation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
+                       MAYBE_WebNavigation) {
+  ASSERT_TRUE(StartSpawnedTestServer());
   extensions::FrameNavigationState::set_allow_extension_scheme(true);
 
   CommandLine::ForCurrentProcess()->AppendSwitch(
@@ -2957,13 +2967,13 @@
 }
 
 // Fails often on Windows dbg bots. http://crbug.com/177163
-#if defined(OS_WIN)
+#if defined(OS_WIN) && !defined(NDEBUG)
 #define MAYBE_TabsApi DISABLED_TabsApi
 #else
 #define MAYBE_TabsApi TabsApi
-#endif  // defined(OS_WIN)
+#endif  // defined(OS_WIN) && !defined(NDEBUG)
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithExtensions, MAYBE_TabsApi) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(StartSpawnedTestServer());
   extensions::FrameNavigationState::set_allow_extension_scheme(true);
 
   // Wait for the extension to set itself up and return control to us.
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 1d4d672..fb82491 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -308,11 +308,6 @@
       this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
       content::Source<WebContents>(prerender_contents_.get()));
 
-  // Register for redirect notifications sourced from |this|.
-  notification_registrar_.Add(
-      this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
-      content::Source<WebContents>(prerender_contents_.get()));
-
   // Transfer over the user agent override.
   prerender_contents_.get()->SetUserAgentOverride(
       prerender_manager_->config().user_agent_override);
@@ -395,25 +390,6 @@
       Destroy(FINAL_STATUS_APP_TERMINATING);
       return;
 
-    case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
-      // RESOURCE_RECEIVED_REDIRECT can come for any resource on a page.
-      // If it's a redirect on the top-level resource, the name needs
-      // to be remembered for future matching, and if it redirects to
-      // an https resource, it needs to be canceled. If a subresource
-      // is redirected, nothing changes.
-      DCHECK_EQ(content::Source<WebContents>(source).ptr(),
-                prerender_contents_.get());
-      ResourceRedirectDetails* resource_redirect_details =
-          content::Details<ResourceRedirectDetails>(details).ptr();
-      CHECK(resource_redirect_details);
-      if (resource_redirect_details->resource_type ==
-          ResourceType::MAIN_FRAME) {
-        if (!AddAliasURL(resource_redirect_details->new_url))
-          return;
-      }
-      break;
-    }
-
     case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
       if (prerender_contents_.get()) {
         DCHECK_EQ(content::Source<WebContents>(source).ptr(),
@@ -599,6 +575,17 @@
     has_finished_loading_ = true;
 }
 
+void PrerenderContents::DidGetRedirectForResourceRequest(
+    const content::ResourceRedirectDetails& details) {
+  // DidGetRedirectForResourceRequest can come for any resource on a page.  If
+  // it's a redirect on the top-level resource, the name needs to be remembered
+  // for future matching, and if it redirects to an https resource, it needs to
+  // be canceled. If a subresource is redirected, nothing changes.
+  if (details.resource_type != ResourceType::MAIN_FRAME)
+    return;
+  AddAliasURL(details.new_url);
+}
+
 void PrerenderContents::Destroy(FinalStatus final_status) {
   DCHECK_NE(final_status, FINAL_STATUS_USED);
 
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index 8669cd9..1412427 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -228,6 +228,8 @@
       const GURL& validated_url,
       bool is_main_frame,
       content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void DidGetRedirectForResourceRequest(
+      const content::ResourceRedirectDetails& details) OVERRIDE;
   virtual void DidUpdateFaviconURL(int32 page_id,
       const std::vector<content::FaviconURL>& urls) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index 9c972b1..7726016 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -90,16 +90,7 @@
   if (!prerender)
     return;
 
-  // Remove the handle from the PrerenderLinkManager before we cancel this
-  // prerender, to avoid reentering the PrerenderLinkManager, sending events to
-  // the underlying prerender and making a second erase.
-  scoped_ptr<PrerenderHandle> own_prerender_handle(prerender->handle);
-  prerender->handle = NULL;
-  RemovePrerender(prerender);
-
-  if (own_prerender_handle)
-    own_prerender_handle->OnCancel();
-
+  CancelPrerender(prerender);
   StartPrerenders();
 }
 
@@ -114,6 +105,7 @@
     return;
   }
 
+  prerender->has_been_abandoned = true;
   prerender->handle->OnNavigateAway();
   DCHECK(prerender->handle);
 
@@ -154,7 +146,8 @@
                                render_view_route_id(render_view_route_id),
                                creation_time(creation_time),
                                handle(NULL),
-                               is_match_complete_replacement(false) {
+                               is_match_complete_replacement(false),
+                               has_been_abandoned(false) {
 }
 
 PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
@@ -181,6 +174,8 @@
     return;
 
   size_t total_started_prerender_count = 0;
+  std::list<LinkPrerender*> abandoned_prerenders;
+  std::list<std::list<LinkPrerender>::iterator> pending_prerenders;
   std::multiset<std::pair<int, int> >
       running_launcher_and_render_view_routes;
 
@@ -189,53 +184,48 @@
   // also per launcher.
   for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
        i != prerenders_.end(); ++i) {
-    if (i->handle) {
+    if (!i->handle) {
+      pending_prerenders.push_back(i);
+    } else {
       ++total_started_prerender_count;
-      std::pair<int, int> launcher_and_render_view_route(
-          i->launcher_child_id, i->render_view_route_id);
-      running_launcher_and_render_view_routes.insert(
-          launcher_and_render_view_route);
-      DCHECK_GE(manager_->config().max_link_concurrency_per_launcher,
-                running_launcher_and_render_view_routes.count(
-                    launcher_and_render_view_route));
+      if (i->has_been_abandoned) {
+        abandoned_prerenders.push_back(&(*i));
+      } else {
+        // We do not count abandoned prerenders towards their launcher, since it
+        // has already navigated on to another page.
+        std::pair<int, int> launcher_and_render_view_route(
+            i->launcher_child_id, i->render_view_route_id);
+        running_launcher_and_render_view_routes.insert(
+            launcher_and_render_view_route);
+        DCHECK_GE(manager_->config().max_link_concurrency_per_launcher,
+                  running_launcher_and_render_view_routes.count(
+                      launcher_and_render_view_route));
+      }
     }
 
     DCHECK_EQ(&(*i), FindByLauncherChildIdAndPrerenderId(i->launcher_child_id,
                                                          i->prerender_id));
   }
+  DCHECK_LE(abandoned_prerenders.size(), total_started_prerender_count);
   DCHECK_GE(manager_->config().max_link_concurrency,
             total_started_prerender_count);
   DCHECK_LE(CountRunningPrerenders(), total_started_prerender_count);
 
   TimeTicks now = manager_->GetCurrentTimeTicks();
 
-  // Scan the list again, starting prerenders as our counts allow.
-  std::list<LinkPrerender>::iterator next = prerenders_.begin();
-  while (next != prerenders_.end()) {
-    std::list<LinkPrerender>::iterator i = next;
-    ++next;
-
-    if (total_started_prerender_count >=
-            manager_->config().max_link_concurrency ||
-        total_started_prerender_count >= prerenders_.size()) {
-      // The system is already at its prerender concurrency limit.
-      return;
-    }
-
-    if (i->handle) {
-      // This prerender has already been added to the prerender manager.
-      continue;
-    }
-
-    TimeDelta prerender_age = now - i->creation_time;
+  // Scan the pending prerenders, starting prerenders as we can.
+  for (std::list<std::list<LinkPrerender>::iterator>::const_iterator
+           i = pending_prerenders.begin(), end = pending_prerenders.end();
+       i != end; ++i) {
+    TimeDelta prerender_age = now - (*i)->creation_time;
     if (prerender_age >= manager_->config().max_wait_to_launch) {
       // This prerender waited too long in the queue before launching.
-      prerenders_.erase(i);
+      prerenders_.erase(*i);
       continue;
     }
 
     std::pair<int, int> launcher_and_render_view_route(
-        i->launcher_child_id, i->render_view_route_id);
+        (*i)->launcher_child_id, (*i)->render_view_route_id);
     if (manager_->config().max_link_concurrency_per_launcher <=
         running_launcher_and_render_view_routes.count(
             launcher_and_render_view_route)) {
@@ -243,17 +233,31 @@
       continue;
     }
 
+    if (total_started_prerender_count >=
+            manager_->config().max_link_concurrency ||
+        total_started_prerender_count >= prerenders_.size()) {
+      // The system is already at its prerender concurrency limit. Can we kill
+      // an abandoned prerender to make room?
+      if (!abandoned_prerenders.empty()) {
+        CancelPrerender(abandoned_prerenders.front());
+        --total_started_prerender_count;
+        abandoned_prerenders.pop_front();
+      } else {
+        return;
+      }
+    }
+
     PrerenderHandle* handle = manager_->AddPrerenderFromLinkRelPrerender(
-        i->launcher_child_id, i->render_view_route_id,
-        i->url, i->referrer, i->size);
+        (*i)->launcher_child_id, (*i)->render_view_route_id,
+        (*i)->url, (*i)->referrer, (*i)->size);
     if (!handle) {
       // This prerender couldn't be launched, it's gone.
-      prerenders_.erase(i);
+      prerenders_.erase(*i);
       continue;
     }
 
     // We have successfully started a new prerender.
-    i->handle = handle;
+    (*i)->handle = handle;
     ++total_started_prerender_count;
     handle->SetObserver(this);
     if (handle->IsPrerendering())
@@ -301,6 +305,21 @@
   NOTREACHED();
 }
 
+void PrerenderLinkManager::CancelPrerender(LinkPrerender* prerender) {
+  for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+       i != prerenders_.end(); ++i) {
+    if (&(*i) == prerender) {
+      scoped_ptr<PrerenderHandle> own_handle(i->handle);
+      i->handle = NULL;
+      prerenders_.erase(i);
+      if (own_handle)
+        own_handle->OnCancel();
+      return;
+    }
+  }
+  NOTREACHED();
+}
+
 void PrerenderLinkManager::Shutdown() {
   has_shutdown_ = true;
 }
diff --git a/chrome/browser/prerender/prerender_link_manager.h b/chrome/browser/prerender/prerender_link_manager.h
index eae7919..0047a4d 100644
--- a/chrome/browser/prerender/prerender_link_manager.h
+++ b/chrome/browser/prerender/prerender_link_manager.h
@@ -99,6 +99,9 @@
     // True if this prerender has become a MatchComplete replacement. This state
     // is maintained so the renderer is not notified of a stop twice.
     bool is_match_complete_replacement;
+
+    // True if this prerender has been abandoned by its launcher.
+    bool has_been_abandoned;
   };
 
   bool IsEmpty() const;
@@ -115,8 +118,14 @@
 
   LinkPrerender* FindByPrerenderHandle(PrerenderHandle* prerender_handle);
 
+  // Removes |prerender| from the the prerender link manager. Deletes the
+  // PrerenderHandle as needed.
   void RemovePrerender(LinkPrerender* prerender);
 
+  // Cancels |prerender| and removes |prerender| from the prerender link
+  // manager.
+  void CancelPrerender(LinkPrerender* prerender);
+
   // From BrowserContextKeyedService:
   virtual void Shutdown() OVERRIDE;
 
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index 5c1a466..810d0f3 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -498,6 +498,38 @@
   EXPECT_EQ(null, prerender_manager()->FindEntry(url));
 }
 
+// When the user navigates away from a page, and then launches a new prerender,
+// the new prerender should preempt the abandoned prerender even if the
+// abandoned prerender hasn't expired.
+TEST_F(PrerenderTest, LinkManagerNavigateAwayLaunchAnother) {
+  const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
+  const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
+  const TimeDelta test_advance = TimeDelta::FromSeconds(5);
+  ASSERT_LT(test_advance, time_to_live);
+  ASSERT_GT(abandon_time_to_live, test_advance);
+
+  prerender_manager()->mutable_config().time_to_live = time_to_live;
+  prerender_manager()->mutable_config().abandon_time_to_live =
+      abandon_time_to_live;
+
+  GURL url("http://example.com");
+  prerender_manager()->CreateNextPrerenderContents(url, FINAL_STATUS_CANCELLED);
+  EXPECT_TRUE(AddSimplePrerender(url));
+  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
+                                               last_prerender_id());
+
+  prerender_manager()->AdvanceTimeTicks(test_advance);
+
+  GURL second_url("http://example2.com");
+  DummyPrerenderContents* second_prerender_contents =
+      prerender_manager()->CreateNextPrerenderContents(
+          second_url, FINAL_STATUS_MANAGER_SHUTDOWN);
+  EXPECT_TRUE(AddSimplePrerender(second_url));
+  EXPECT_EQ(second_prerender_contents,
+            prerender_manager()->FindEntry(second_url));
+}
+
+
 // Make sure that if we prerender more requests than we support, that we launch
 // them in the order given up until we reach MaxConcurrency, at which point we
 // queue them and launch them in the order given. As well, insure that limits
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
index ab9b70b..66d6b47 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/testing_pref_service.h"
+#include "base/run_loop.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
 #include "chrome/browser/service/service_process_control.h"
@@ -154,14 +155,16 @@
 bool MockServiceProcessControl::SendEnabledInfo() {
   info_.enabled = true;
   info_.email = EnabledUserId();
-  OnCloudPrintProxyInfo(info_);
+  PostTask(base::Bind(&MockServiceProcessControl::OnCloudPrintProxyInfo,
+                      base::Unretained(this), info_));
   return true;
 }
 
 bool MockServiceProcessControl::SendDisabledInfo() {
   info_.enabled = false;
   info_.email = std::string();
-  OnCloudPrintProxyInfo(info_);
+  PostTask(base::Bind(&MockServiceProcessControl::OnCloudPrintProxyInfo,
+                      base::Unretained(this), info_));
   return true;
 }
 
@@ -170,6 +173,16 @@
   explicit TestCloudPrintProxyService(Profile* profile)
       : CloudPrintProxyService(profile) { }
 
+  void Initialize() {
+    CloudPrintProxyService::Initialize();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void RefreshStatusFromService() {
+    CloudPrintProxyService::RefreshStatusFromService();
+    base::RunLoop().RunUntilIdle();
+  }
+
   virtual ServiceProcessControl* GetServiceProcessControl() OVERRIDE {
     return &process_control_;
   }
@@ -435,7 +448,6 @@
   service->GetMockServiceProcessControl()->SetWillBeDisabledExpectations();
 
   service->Initialize();
-  base::MessageLoop::current()->RunUntilIdle();
   return service;
 }
 
@@ -453,5 +465,5 @@
   command_line.AppendSwitch(switches::kCheckCloudPrintConnectorPolicy);
 
   EXPECT_FALSE(LaunchBrowser(command_line, &profile_));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
diff --git a/chrome/browser/printing/print_dialog_cloud.cc b/chrome/browser/printing/print_dialog_cloud.cc
index 187dac6..4f9c5f9 100644
--- a/chrome/browser/printing/print_dialog_cloud.cc
+++ b/chrome/browser/printing/print_dialog_cloud.cc
@@ -636,7 +636,7 @@
   if (window) {
     HWND dialog_handle;
 #if defined(USE_AURA)
-    dialog_handle = window->GetRootWindow()->GetAcceleratedWidget();
+    dialog_handle = window->GetDispatcher()->GetAcceleratedWidget();
 #else
     dialog_handle = window;
 #endif
diff --git a/chrome/browser/printing/print_dialog_gtk.cc b/chrome/browser/printing/print_dialog_gtk.cc
index ff22fe3..1ebcbdb 100644
--- a/chrome/browser/printing/print_dialog_gtk.cc
+++ b/chrome/browser/printing/print_dialog_gtk.cc
@@ -162,43 +162,21 @@
       gtk_print_settings_copy(g_last_used_settings.Get().settings());
   page_setup_ = gtk_page_setup_new();
 
-  // No page range to initialize for default settings.
-  PageRanges ranges_vector;
   PrintSettings settings;
-  InitPrintSettings(ranges_vector, &settings);
+  InitPrintSettings(&settings);
 }
 
-bool PrintDialogGtk::UpdateSettings(const base::DictionaryValue& job_settings,
-                                    const printing::PageRanges& ranges,
+bool PrintDialogGtk::UpdateSettings(bool target_is_pdf,
                                     printing::PrintSettings* settings) {
-  bool collate;
-  int color;
-  bool landscape;
-  bool print_to_pdf;
-  int copies;
-  int duplex_mode;
-  std::string device_name;
-
-  if (!job_settings.GetBoolean(printing::kSettingLandscape, &landscape) ||
-      !job_settings.GetBoolean(printing::kSettingCollate, &collate) ||
-      !job_settings.GetInteger(printing::kSettingColor, &color) ||
-      !job_settings.GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf) ||
-      !job_settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode) ||
-      !job_settings.GetInteger(printing::kSettingCopies, &copies) ||
-      !job_settings.GetString(printing::kSettingDeviceName, &device_name)) {
-    return false;
-  }
-
-  bool is_cloud_print = job_settings.HasKey(printing::kSettingCloudPrintId);
-
   if (!gtk_settings_) {
     gtk_settings_ =
         gtk_print_settings_copy(g_last_used_settings.Get().settings());
   }
 
-  if (!print_to_pdf && !is_cloud_print) {
+  if (!target_is_pdf) {
     scoped_ptr<GtkPrinterList> printer_list(new GtkPrinterList);
-    printer_ = printer_list->GetPrinterWithName(device_name);
+    printer_ = printer_list->GetPrinterWithName(
+        UTF16ToUTF8(settings->device_name()));
     if (printer_) {
       g_object_ref(printer_);
       gtk_print_settings_set_printer(gtk_settings_,
@@ -208,19 +186,20 @@
       }
     }
 
-    gtk_print_settings_set_n_copies(gtk_settings_, copies);
-    gtk_print_settings_set_collate(gtk_settings_, collate);
+    gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
+    gtk_print_settings_set_collate(gtk_settings_, settings->collate());
 
 #if defined(USE_CUPS)
     std::string color_value;
     std::string color_setting_name;
-    printing::GetColorModelForMode(color, &color_setting_name, &color_value);
+    printing::GetColorModelForMode(settings->color(), &color_setting_name,
+                                   &color_value);
     gtk_print_settings_set(gtk_settings_, color_setting_name.c_str(),
                            color_value.c_str());
 
-    if (duplex_mode != printing::UNKNOWN_DUPLEX_MODE) {
+    if (settings->duplex_mode() != printing::UNKNOWN_DUPLEX_MODE) {
       const char* cups_duplex_mode = NULL;
-      switch (duplex_mode) {
+      switch (settings->duplex_mode()) {
         case printing::LONG_EDGE:
           cups_duplex_mode = kDuplexNoTumble;
           break;
@@ -243,10 +222,10 @@
 
   gtk_print_settings_set_orientation(
       gtk_settings_,
-      landscape ? GTK_PAGE_ORIENTATION_LANDSCAPE :
-                  GTK_PAGE_ORIENTATION_PORTRAIT);
+      settings->landscape() ? GTK_PAGE_ORIENTATION_LANDSCAPE :
+                              GTK_PAGE_ORIENTATION_PORTRAIT);
 
-  InitPrintSettings(ranges, settings);
+  InitPrintSettings(settings);
   return true;
 }
 
@@ -387,9 +366,10 @@
       }
 
       PrintSettings settings;
+      settings.set_ranges(ranges_vector);
+      settings.set_selection_only(print_selection_only);
       printing::PrintSettingsInitializerGtk::InitPrintSettings(
-          gtk_settings_, page_setup_, ranges_vector, print_selection_only,
-          &settings);
+          gtk_settings_, page_setup_, &settings);
       context_->InitWithSettings(settings);
       callback_.Run(PrintingContextGtk::OK);
       callback_.Reset();
@@ -452,9 +432,8 @@
   Release();
 }
 
-void PrintDialogGtk::InitPrintSettings(const PageRanges& page_ranges,
-                                       PrintSettings* settings) {
+void PrintDialogGtk::InitPrintSettings(PrintSettings* settings) {
   printing::PrintSettingsInitializerGtk::InitPrintSettings(
-      gtk_settings_, page_setup_, page_ranges, false, settings);
+      gtk_settings_, page_setup_, settings);
   context_->InitWithSettings(*settings);
 }
diff --git a/chrome/browser/printing/print_dialog_gtk.h b/chrome/browser/printing/print_dialog_gtk.h
index 06a14c7..9c22af4 100644
--- a/chrome/browser/printing/print_dialog_gtk.h
+++ b/chrome/browser/printing/print_dialog_gtk.h
@@ -36,8 +36,7 @@
 
   // printing::PrintDialogGtkInterface implementation.
   virtual void UseDefaultSettings() OVERRIDE;
-  virtual bool UpdateSettings(const base::DictionaryValue& job_settings,
-                              const printing::PageRanges& ranges,
+  virtual bool UpdateSettings(bool target_is_pdf,
                               printing::PrintSettings* settings) OVERRIDE;
   virtual void ShowDialog(
       gfx::NativeView parent_view,
@@ -69,9 +68,8 @@
   void OnJobCompleted(GtkPrintJob* print_job, GError* error);
 
   // Helper function for initializing |context_|'s PrintSettings with a given
-  // set of |page_ranges| and |settings|.
-  void InitPrintSettings(const printing::PageRanges& page_ranges,
-                         printing::PrintSettings* settings);
+  // |settings|.
+  void InitPrintSettings(printing::PrintSettings* settings);
 
   // Printing dialog callback.
   PrintingContextGtk::PrintSettingsCallback callback_;
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 66477b1..050be2e 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -208,7 +208,6 @@
   DCHECK_EQ(page_number_, PageNumber::npos());
   DCHECK_EQ(document_, new_document);
   DCHECK(document_.get());
-  DCHECK(new_document->settings().Equals(printing_context_->settings()));
 
   if (!document_.get() || page_number_ != PageNumber::npos() ||
       document_.get() != new_document) {
@@ -240,8 +239,6 @@
 void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   DCHECK_EQ(page_number_, PageNumber::npos());
-  DCHECK(!new_document ||
-         new_document->settings().Equals(printing_context_->settings()));
 
   if (page_number_ != PageNumber::npos())
     return;
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 799ae5b..4231ee7 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -127,14 +127,18 @@
   const int kBorder = 25;
   *size = kMinDialogSize;
 
+  web_modal::WebContentsModalDialogHost* host = NULL;
   Browser* browser = chrome::FindBrowserWithWebContents(initiator_);
-  if (browser) {
-    web_modal::WebContentsModalDialogHost* host =
-        browser->window()->GetWebContentsModalDialogHost();
-    if (host)
-      size->SetToMax(host->GetMaximumDialogSize());
+  if (browser)
+    host = browser->window()->GetWebContentsModalDialogHost();
+
+  if (host) {
+    size->SetToMax(host->GetMaximumDialogSize());
+    size->Enlarge(-2 * kBorder, -kBorder);
+  } else {
+    size->SetToMax(initiator_->GetView()->GetContainerSize());
+    size->Enlarge(-2 * kBorder, -2 * kBorder);
   }
-  size->Enlarge(-2 * kBorder, -kBorder);
 
 #if defined(OS_MACOSX)
   // Limit the maximum size on MacOS X.
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index 5b48b89..262ed79 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -71,20 +71,19 @@
   params->margin_left = settings.page_setup_device_units().content_area().x();
   params->dpi = settings.dpi();
   // Currently hardcoded at 1.25. See PrintSettings' constructor.
-  params->min_shrink = settings.min_shrink;
+  params->min_shrink = settings.min_shrink();
   // Currently hardcoded at 2.0. See PrintSettings' constructor.
-  params->max_shrink = settings.max_shrink;
+  params->max_shrink = settings.max_shrink();
   // Currently hardcoded at 72dpi. See PrintSettings' constructor.
-  params->desired_dpi = settings.desired_dpi;
+  params->desired_dpi = settings.desired_dpi();
   // Always use an invalid cookie.
   params->document_cookie = 0;
-  params->selection_only = settings.selection_only;
+  params->selection_only = settings.selection_only();
   params->supports_alpha_blend = settings.supports_alpha_blend();
-  params->should_print_backgrounds = settings.should_print_backgrounds;
-  params->display_header_footer = settings.display_header_footer;
-  params->date = settings.date;
-  params->title = settings.title;
-  params->url = settings.url;
+  params->should_print_backgrounds = settings.should_print_backgrounds();
+  params->display_header_footer = settings.display_header_footer();
+  params->title = settings.title();
+  params->url = settings.url();
 }
 
 }  // namespace
@@ -394,7 +393,7 @@
     RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
     params.params.document_cookie = printer_query->cookie();
     params.pages =
-        printing::PageRange::GetPages(printer_query->settings().ranges);
+        printing::PageRange::GetPages(printer_query->settings().ranges());
   }
   PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
   Send(reply_msg);
@@ -456,7 +455,7 @@
     RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
     params.params.document_cookie = printer_query->cookie();
     params.pages =
-        printing::PageRange::GetPages(printer_query->settings().ranges);
+        printing::PageRange::GetPages(printer_query->settings().ranges());
   }
   PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params);
   Send(reply_msg);
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter.cc b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
index c0f7d25..5cb6d10 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter.cc
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
@@ -4,103 +4,29 @@
 
 #include "chrome/browser/profile_resetter/automatic_profile_resetter.h"
 
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h"
 #include "chrome/browser/profile_resetter/jtl_interpreter.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "grit/browser_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 
-namespace {
-
-// Number of bits, and maximum value (exclusive) for the mask whose bits
-// indicate which of reset criteria were satisfied.
-const size_t kSatisfiedCriteriaMaskBits = 2;
-const uint32 kSatisfiedCriteriaMaskMaximumValue =
-    (1 << kSatisfiedCriteriaMaskBits);
-
-// Number of bits, and maximum value (exclusive) for the mask whose bits
-// indicate if any of reset criteria were satisfied, and which of the mementos
-// were already present.
-const size_t kCombinedStatusMaskBits = 4;
-const uint32 kCombinedStatusMaskMaximumValue = (1 << kCombinedStatusMaskBits);
-
-// Name constants for the field trial behind which we enable this feature.
-const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
-const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun";
-const char kAutomaticProfileResetStudyEnabledGroupName[] = "Enabled";
-
-// Keys used in the input dictionary of the program.
-// TODO(engedy): Add these here on an as-needed basis.
-
-// Keys used in the output dictionary of the program.
-const char kHadPromptedAlreadyKey[] = "had_prompted_already";
-const char kSatisfiedCriteriaMaskKeys[][29] = {"satisfied_criteria_mask_bit1",
-                                               "satisfied_criteria_mask_bit2"};
-const char kCombinedStatusMaskKeys[][26] = {
-    "combined_status_mask_bit1", "combined_status_mask_bit2",
-    "combined_status_mask_bit3", "combined_status_mask_bit4"};
-
-// Keys used in both the input and output dictionary of the program.
-const char kMementoValueInPrefsKey[] = "memento_value_in_prefs";
-const char kMementoValueInLocalStateKey[] = "memento_value_in_local_state";
-const char kMementoValueInFileKey[] = "memento_value_in_file";
-
-COMPILE_ASSERT(
-    arraysize(kSatisfiedCriteriaMaskKeys) == kSatisfiedCriteriaMaskBits,
-    satisfied_criteria_mask_bits_mismatch);
-COMPILE_ASSERT(arraysize(kCombinedStatusMaskKeys) == kCombinedStatusMaskBits,
-               combined_status_mask_bits_mismatch);
-
-// Implementation detail classes ---------------------------------------------
-
-class AutomaticProfileResetterDelegateImpl
-    : public AutomaticProfileResetterDelegate {
- public:
-  AutomaticProfileResetterDelegateImpl() {}
-  virtual ~AutomaticProfileResetterDelegateImpl() {}
-
-  // AutomaticProfileResetterDelegate overrides:
-
-  virtual void ShowPrompt() OVERRIDE {
-    // TODO(engedy): Call the UI from here once we have it.
-  }
-
-  virtual void ReportStatistics(uint32 satisfied_criteria_mask,
-                                uint32 combined_status_mask) OVERRIDE {
-    UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.SatisfiedCriteriaMask",
-                              satisfied_criteria_mask,
-                              kSatisfiedCriteriaMaskMaximumValue);
-    UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.CombinedStatusMask",
-                              combined_status_mask,
-                              kCombinedStatusMaskMaximumValue);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateImpl);
-};
-
-// Enumeration of the possible outcomes of showing the profile reset prompt.
-enum PromptResult {
-  // Prompt was not shown because only a dry-run was performed.
-  PROMPT_NOT_SHOWN,
-  PROMPT_ACTION_RESET,
-  PROMPT_ACTION_NO_RESET,
-  PROMPT_DISMISSED,
-  // Prompt was still shown (not dismissed by the user) when Chrome was closed.
-  PROMPT_IGNORED,
-  PROMPT_RESULT_MAX
-};
-
-}  // namespace
 
 // AutomaticProfileResetter::EvaluationResults -------------------------------
 
@@ -120,20 +46,181 @@
   uint32 combined_status_mask;
 };
 
+
+// Helpers -------------------------------------------------------------------
+
+namespace {
+
+// Name constants for the field trial behind which we enable this feature.
+const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
+const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun";
+const char kAutomaticProfileResetStudyEnabledGroupName[] = "Enabled";
+
+// How long to wait after start-up before unleashing the evaluation flow.
+const int64 kEvaluationFlowDelayInSeconds = 55;
+
+// Keys used in the input dictionary of the program.
+const char kDefaultSearchProviderKey[] = "default_search_provider";
+const char kDefaultSearchProviderIsUserControlledKey[] =
+    "default_search_provider_iuc";
+const char kLoadedModuleDigestsKey[] = "loaded_modules";
+const char kLocalStateKey[] = "local_state";
+const char kLocalStateIsUserControlledKey[] = "local_state_iuc";
+const char kSearchProvidersKey[] = "search_providers";
+const char kUserPreferencesKey[] = "preferences";
+const char kUserPreferencesIsUserControlledKey[] = "preferences_iuc";
+
+// Keys used in the output dictionary of the program.
+const char kCombinedStatusMaskKeys[][26] = {
+    "combined_status_mask_bit1", "combined_status_mask_bit2",
+    "combined_status_mask_bit3", "combined_status_mask_bit4"};
+const char kHadPromptedAlreadyKey[] = "had_prompted_already";
+const char kSatisfiedCriteriaMaskKeys[][29] = {"satisfied_criteria_mask_bit1",
+                                               "satisfied_criteria_mask_bit2"};
+
+// Keys used in both the input and output dictionary of the program.
+const char kMementoValueInFileKey[] = "memento_value_in_file";
+const char kMementoValueInLocalStateKey[] = "memento_value_in_local_state";
+const char kMementoValueInPrefsKey[] = "memento_value_in_prefs";
+
+// Number of bits, and maximum value (exclusive) for the mask whose bits
+// indicate which of reset criteria were satisfied.
+const size_t kSatisfiedCriteriaMaskNumberOfBits = 2u;
+const uint32 kSatisfiedCriteriaMaskMaximumValue =
+    (1u << kSatisfiedCriteriaMaskNumberOfBits);
+
+// Number of bits, and maximum value (exclusive) for the mask whose bits
+// indicate if any of reset criteria were satisfied, and which of the mementos
+// were already present.
+const size_t kCombinedStatusMaskNumberOfBits = 4u;
+const uint32 kCombinedStatusMaskMaximumValue =
+    (1u << kCombinedStatusMaskNumberOfBits);
+
+COMPILE_ASSERT(
+    arraysize(kSatisfiedCriteriaMaskKeys) == kSatisfiedCriteriaMaskNumberOfBits,
+    satisfied_criteria_mask_bits_mismatch);
+COMPILE_ASSERT(
+    arraysize(kCombinedStatusMaskKeys) == kCombinedStatusMaskNumberOfBits,
+    combined_status_mask_bits_mismatch);
+
+// Enumeration of the possible outcomes of showing the profile reset prompt.
+enum PromptResult {
+  // Prompt was not shown because only a dry-run was performed.
+  PROMPT_NOT_SHOWN,
+  PROMPT_ACTION_RESET,
+  PROMPT_ACTION_NO_RESET,
+  PROMPT_DISMISSED,
+  // Prompt was still shown (not dismissed by the user) when Chrome was closed.
+  PROMPT_IGNORED,
+  PROMPT_RESULT_MAX
+};
+
+// Returns whether or not a dry-run shall be performed.
+bool ShouldPerformDryRun() {
+  return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
+         kAutomaticProfileResetStudyDryRunGroupName;
+}
+
+// Returns whether or not a live-run shall be performed.
+bool ShouldPerformLiveRun() {
+  return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
+         kAutomaticProfileResetStudyEnabledGroupName;
+}
+
+// Deep-copies all preferences in |source| to a sub-tree named |value_tree_key|
+// in |target_dictionary|, with path expansion, and also creates an isomorphic
+// sub-tree under the key |is_user_controlled_tree_key| that contains only
+// Boolean values, indicating whether or not the corresponding preferences are
+// coming from the 'user' PrefStore.
+void BuildSubTreesFromPreferences(const PrefService* source,
+                                  const char* value_tree_key,
+                                  const char* is_user_controlled_tree_key,
+                                  base::DictionaryValue* target_dictionary) {
+  scoped_ptr<base::DictionaryValue> pref_name_to_value_map(
+      source->GetPreferenceValuesWithoutPathExpansion());
+  std::vector<std::string> pref_names;
+  pref_names.reserve(pref_name_to_value_map->size());
+  for (base::DictionaryValue::Iterator it(*pref_name_to_value_map);
+       !it.IsAtEnd(); it.Advance())
+    pref_names.push_back(it.key());
+
+  base::DictionaryValue* value_tree = new base::DictionaryValue;
+  base::DictionaryValue* is_user_controlled_tree = new base::DictionaryValue;
+  for (std::vector<std::string>::const_iterator it = pref_names.begin();
+       it != pref_names.end(); ++it) {
+    scoped_ptr<Value> pref_value_owned;
+    if (pref_name_to_value_map->RemoveWithoutPathExpansion(*it,
+                                                           &pref_value_owned)) {
+      value_tree->Set(*it, pref_value_owned.release());
+      const PrefService::Preference* pref = source->FindPreference(it->c_str());
+      is_user_controlled_tree->Set(
+          *it, new base::FundamentalValue(pref->IsUserControlled()));
+    }
+  }
+  target_dictionary->Set(value_tree_key, value_tree);
+  target_dictionary->Set(is_user_controlled_tree_key, is_user_controlled_tree);
+}
+
+}  // namespace
+
+
 // AutomaticProfileResetter --------------------------------------------------
 
 AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile)
     : profile_(profile),
       state_(STATE_UNINITIALIZED),
+      enumeration_of_loaded_modules_ready_(false),
+      template_url_service_ready_(false),
       memento_in_prefs_(profile_),
       memento_in_local_state_(profile_),
       memento_in_file_(profile_),
       weak_ptr_factory_(this) {
   DCHECK(profile_);
+  Initialize();
 }
 
 AutomaticProfileResetter::~AutomaticProfileResetter() {}
 
+void AutomaticProfileResetter::Activate() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(state_ == STATE_INITIALIZED || state_ == STATE_DISABLED);
+
+  if (state_ == STATE_INITIALIZED) {
+    if (!program_.empty()) {
+      // Some steps in the flow (e.g. loaded modules, file-based memento) are
+      // IO-intensive, so defer execution until some time later.
+      task_runner_for_waiting_->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&AutomaticProfileResetter::PrepareEvaluationFlow,
+                     weak_ptr_factory_.GetWeakPtr()),
+          base::TimeDelta::FromSeconds(kEvaluationFlowDelayInSeconds));
+    } else {
+      // Terminate early if there is no program included (nor set by tests).
+      state_ = STATE_DISABLED;
+    }
+  }
+}
+
+void AutomaticProfileResetter::SetHashSeedForTesting(
+    const base::StringPiece& hash_key) {
+  hash_seed_ = hash_key;
+}
+
+void AutomaticProfileResetter::SetProgramForTesting(
+    const base::StringPiece& program) {
+  program_ = program;
+}
+
+void AutomaticProfileResetter::SetDelegateForTesting(
+    scoped_ptr<AutomaticProfileResetterDelegate> delegate) {
+  delegate_ = delegate.Pass();
+}
+
+void AutomaticProfileResetter::SetTaskRunnerForWaitingForTesting(
+    const scoped_refptr<base::TaskRunner>& task_runner) {
+  task_runner_for_waiting_ = task_runner;
+}
+
 void AutomaticProfileResetter::Initialize() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -151,55 +238,115 @@
       hash_seed_ = resources.GetRawDataResource(
           IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY);
     }
-    delegate_.reset(new AutomaticProfileResetterDelegateImpl());
+    delegate_.reset(new AutomaticProfileResetterDelegateImpl(
+        TemplateURLServiceFactory::GetForProfile(profile_)));
+    task_runner_for_waiting_ =
+        content::BrowserThread::GetMessageLoopProxyForThread(
+            content::BrowserThread::UI);
+    state_ = STATE_INITIALIZED;
+  } else {
+    state_ = STATE_DISABLED;
+  }
+}
 
+void AutomaticProfileResetter::PrepareEvaluationFlow() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_EQ(state_, STATE_INITIALIZED);
+
+  state_ = STATE_WAITING_ON_DEPENDENCIES;
+
+  delegate_->RequestCallbackWhenTemplateURLServiceIsLoaded(
+      base::Bind(&AutomaticProfileResetter::OnTemplateURLServiceIsLoaded,
+                 weak_ptr_factory_.GetWeakPtr()));
+  delegate_->RequestCallbackWhenLoadedModulesAreEnumerated(
+      base::Bind(&AutomaticProfileResetter::OnLoadedModulesAreEnumerated,
+                 weak_ptr_factory_.GetWeakPtr()));
+  delegate_->LoadTemplateURLServiceIfNeeded();
+  delegate_->EnumerateLoadedModulesIfNeeded();
+}
+
+void AutomaticProfileResetter::OnTemplateURLServiceIsLoaded() {
+  template_url_service_ready_ = true;
+  OnDependencyIsReady();
+}
+
+void AutomaticProfileResetter::OnLoadedModulesAreEnumerated() {
+  enumeration_of_loaded_modules_ready_ = true;
+  OnDependencyIsReady();
+}
+
+void AutomaticProfileResetter::OnDependencyIsReady() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_EQ(state_, STATE_WAITING_ON_DEPENDENCIES);
+
+  if (template_url_service_ready_ && enumeration_of_loaded_modules_ready_) {
     state_ = STATE_READY;
-
     content::BrowserThread::PostTask(
         content::BrowserThread::UI,
         FROM_HERE,
         base::Bind(&AutomaticProfileResetter::BeginEvaluationFlow,
                    weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    state_ = STATE_DISABLED;
   }
 }
 
-bool AutomaticProfileResetter::ShouldPerformDryRun() const {
-  return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
-         kAutomaticProfileResetStudyDryRunGroupName;
-}
-
-bool AutomaticProfileResetter::ShouldPerformLiveRun() const {
-  return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
-         kAutomaticProfileResetStudyEnabledGroupName;
-}
-
 void AutomaticProfileResetter::BeginEvaluationFlow() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK_EQ(state_, STATE_READY);
+  DCHECK(!program_.empty());
 
-  if (!program_.empty()) {
-    state_ = STATE_WORKING;
-    memento_in_file_.ReadValue(
-        base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow,
-                   weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    // Terminate early if there is no program included (nor set by tests).
-    state_ = STATE_DISABLED;
-  }
+  state_ = STATE_WORKING;
+  memento_in_file_.ReadValue(
+      base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 scoped_ptr<base::DictionaryValue>
-AutomaticProfileResetter::BuildEvaluatorProgramInput(
+    AutomaticProfileResetter::BuildEvaluatorProgramInput(
     const std::string& memento_value_in_file) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  // TODO(engedy): Add any additional state here that is needed by the program.
+
   scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
+
+  // Include memento values (or empty strings in case mementos are not there).
   input->SetString(kMementoValueInPrefsKey, memento_in_prefs_.ReadValue());
   input->SetString(kMementoValueInLocalStateKey,
                    memento_in_local_state_.ReadValue());
   input->SetString(kMementoValueInFileKey, memento_value_in_file);
+
+  // Include all user (i.e. profile-specific) preferences, along with
+  // information about whether the value is coming from the 'user' PrefStore.
+  PrefService* prefs = profile_->GetPrefs();
+  DCHECK(prefs);
+  BuildSubTreesFromPreferences(prefs,
+                               kUserPreferencesKey,
+                               kUserPreferencesIsUserControlledKey,
+                               input.get());
+
+  // Include all local state (i.e. shared) preferences, along with information
+  // about whether the value is coming from the 'user' PrefStore.
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+  BuildSubTreesFromPreferences(
+      local_state, kLocalStateKey, kLocalStateIsUserControlledKey, input.get());
+
+  // Include all information related to search engines.
+  scoped_ptr<base::DictionaryValue> default_search_provider_details(
+      delegate_->GetDefaultSearchProviderDetails());
+  input->Set(kDefaultSearchProviderKey,
+             default_search_provider_details.release());
+
+  scoped_ptr<base::ListValue> search_providers_details(
+      delegate_->GetPrepopulatedSearchProvidersDetails());
+  input->Set(kSearchProvidersKey, search_providers_details.release());
+
+  input->SetBoolean(kDefaultSearchProviderIsUserControlledKey,
+                    !delegate_->IsDefaultSearchProviderManaged());
+
+  // Include information about loaded modules.
+  scoped_ptr<base::ListValue> loaded_module_digests(
+      delegate_->GetLoadedModuleNameDigests());
+  input->Set(kLoadedModuleDigestsKey, loaded_module_digests.release());
+
   return input.Pass();
 }
 
@@ -232,13 +379,12 @@
 
 // static
 scoped_ptr<AutomaticProfileResetter::EvaluationResults>
-AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
+    AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
     const base::StringPiece& hash_seed,
     const base::StringPiece& program,
     scoped_ptr<base::DictionaryValue> program_input) {
-  std::string hash_seed_str(hash_seed.as_string());
-  std::string program_str(program.as_string());
-  JtlInterpreter interpreter(hash_seed_str, program_str, program_input.get());
+  JtlInterpreter interpreter(
+      hash_seed.as_string(), program.as_string(), program_input.get());
   interpreter.Execute();
   UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.InterpreterResult",
                             interpreter.result(),
@@ -246,7 +392,7 @@
 
   // In each case below, the respective field in result originally contains the
   // default, so if the getter fails, we still have the correct value there.
-  scoped_ptr<EvaluationResults> results(new EvaluationResults());
+  scoped_ptr<EvaluationResults> results(new EvaluationResults);
   interpreter.GetOutputBoolean(kHadPromptedAlreadyKey,
                                &results->had_prompted_already);
   interpreter.GetOutputString(kMementoValueInPrefsKey,
@@ -274,8 +420,8 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK_EQ(state_, STATE_WORKING);
 
-  delegate_->ReportStatistics(results->satisfied_criteria_mask,
-                              results->combined_status_mask);
+  ReportStatistics(results->satisfied_criteria_mask,
+                   results->combined_status_mask);
 
   if (results->satisfied_criteria_mask != 0 && !results->had_prompted_already) {
     memento_in_prefs_.StoreValue(results->memento_value_in_prefs);
@@ -294,19 +440,14 @@
   state_ = STATE_DONE;
 }
 
-void AutomaticProfileResetter::SetHashSeedForTesting(
-    const base::StringPiece& hash_key) {
-  hash_seed_ = hash_key;
-}
-
-void AutomaticProfileResetter::SetProgramForTesting(
-    const base::StringPiece& program) {
-  program_ = program;
-}
-
-void AutomaticProfileResetter::SetDelegateForTesting(
-    AutomaticProfileResetterDelegate* delegate) {
-  delegate_.reset(delegate);
+void AutomaticProfileResetter::ReportStatistics(uint32 satisfied_criteria_mask,
+                                                uint32 combined_status_mask) {
+  UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.SatisfiedCriteriaMask",
+                            satisfied_criteria_mask,
+                            kSatisfiedCriteriaMaskMaximumValue);
+  UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.CombinedStatusMask",
+                            combined_status_mask,
+                            kCombinedStatusMaskMaximumValue);
 }
 
 void AutomaticProfileResetter::Shutdown() {
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter.h b/chrome/browser/profile_resetter/automatic_profile_resetter.h
index 8dc9176..9be4ee6 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter.h
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter.h
@@ -8,91 +8,111 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_piece.h"
-#include "base/values.h"
+#include "base/task_runner.h"
 #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
+class AutomaticProfileResetterDelegate;
 class Profile;
 
-// Defines the interface for the delegate that will actually show the prompt
-// and/or report statistics on behalf of the AutomaticProfileResetter.
-// The primary reason for this separation is to facilitate unit testing.
-class AutomaticProfileResetterDelegate {
- public:
-  virtual ~AutomaticProfileResetterDelegate() {}
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
 
-  // Triggers showing the one-time profile settings reset prompt.
-  virtual void ShowPrompt() = 0;
-
-  // Reports the given metrics through UMA.
-  virtual void ReportStatistics(uint32 satisfied_criteria_mask,
-                                uint32 combined_status_mask) = 0;
-};
-
-// This service becomes busy shortly after start-up, and is responsible for
-// evaluating if the criteria for showing the one-time profile reset prompt
-// are satisfied, and will potentially trigger the prompt, but only a single
-// time during the lifetime of a profile on disk (this is achieved by storing
-// "mementos"). All methods in this class shall be called on the UI thread.
+// This service is responsible for evaluating whether the criteria for showing
+// the one-time profile reset prompt are satisfied, and for potentially
+// triggering the prompt. To ensure that the prompt only appears at most once
+// for any given profile, a "memento" that the prompt has appeared is written to
+// the profile on disk; see automatic_profile_resetter_mementos.h for details.
+// The service is created automatically with the Profile and is activated right
+// away by its factory. To avoid delaying start-up, however, it will only start
+// working after a short delay.
+// All methods in this class shall be called on the UI thread, except when noted
+// otherwise.
 class AutomaticProfileResetter : public BrowserContextKeyedService {
  public:
   explicit AutomaticProfileResetter(Profile* profile);
   virtual ~AutomaticProfileResetter();
 
-  // Initializes the service, and sets up the asynchronous evaluation flow.
-  // Called by AutomaticProfileResetterFactory.
-  void Initialize();
+  // Fires up the service by unleashing the asynchronous evaluation flow, unless
+  // the service has been already disabled in Initialize() or there is no
+  // |program_| to run (in which case the service also gets disabled).
+  // Called by the AutomaticProfileResetterFactory.
+  void Activate();
 
-  // Should be called after Initialize().
+  // Should be called before Activate().
   void SetHashSeedForTesting(const base::StringPiece& hash_seed);
 
-  // Should be called after Initialize().
+  // Should be called before Activate().
   void SetProgramForTesting(const base::StringPiece& program);
 
-  // Should be called after Initialize(). Takes ownership.
-  void SetDelegateForTesting(AutomaticProfileResetterDelegate* delegate);
+  // Should be called before Activate().
+  void SetDelegateForTesting(
+      scoped_ptr<AutomaticProfileResetterDelegate> delegate);
+
+  // Should be called before Activate(). Sets the task runner to be used to post
+  // task |PrepareEvaluationFlow| in a delayed manner.
+  void SetTaskRunnerForWaitingForTesting(
+      const scoped_refptr<base::TaskRunner>& task_runner);
 
  private:
   struct EvaluationResults;
 
   enum State {
     STATE_UNINITIALIZED,
+    STATE_INITIALIZED,
     STATE_DISABLED,
+    STATE_WAITING_ON_DEPENDENCIES,
     STATE_READY,
     STATE_WORKING,
     STATE_DONE
   };
 
-  // Returns whether or not a dry-run shall be performed.
-  bool ShouldPerformDryRun() const;
+  // Initializes the service if it is enabled in the field trial, otherwise,
+  // skips the initialization steps and also permanently disables the service.
+  void Initialize();
 
-  // Returns whether or not a live-run shall be performed.
-  bool ShouldPerformLiveRun() const;
+  // Prepares the asynchronous evaluation flow by requesting services that it
+  // depends on to make themselves ready.
+  void PrepareEvaluationFlow();
+
+  // Called back by |resetter_delegate_| when the template URL service is ready.
+  void OnTemplateURLServiceIsLoaded();
+
+  // Called back by |resetter_delegate_| when the loaded modules have been
+  // enumerated.
+  void OnLoadedModulesAreEnumerated();
+
+  // Invoked by the above two methods. Kicks off the actual evaluation flow.
+  void OnDependencyIsReady();
 
   // Begins the asynchronous evaluation flow, which will assess whether the
   // criteria for showing the reset prompt are met, whether we have already
   // shown the prompt, and, in the end, will potentially trigger the prompt.
   void BeginEvaluationFlow();
 
+  // Prepares the input of the evaluator program. This will contain all the
+  // state information required to assess whether or not the conditions for
+  // showing the reset prompt are met.
+  scoped_ptr<base::DictionaryValue> BuildEvaluatorProgramInput(
+      const std::string& memento_value_in_file);
+
   // Called back by |memento_in_file_| once it has finished reading the value of
   // the file-based memento. Continues the evaluation flow with collecting state
   // information and assembling it as the input for the evaluator program.
   void ContinueWithEvaluationFlow(const std::string& memento_value_in_file);
 
-  // Prepare the input of the evaluator program. This will contain all the state
-  // information required to assess whether or not the conditions for showing
-  // the reset prompt are met.
-  scoped_ptr<base::DictionaryValue> BuildEvaluatorProgramInput(
-      const std::string& memento_value_in_file);
-
-  // Performs the bulk of the work. Invokes the interpreter to run the |program|
-  // that will evaluate whether the conditions are met for showing the reset
-  // prompt. The program will make this decision based on the state information
-  // contained in |input| in the form of key-value pairs. The program will only
-  // see hashed keys and values that are produced using |hash_seed| as a key.
+  // Performs the bulk of the work. Invokes the JTL interpreter to run the
+  // |program| that will evaluate whether the conditions are met for showing the
+  // reset prompt. The program will make this decision based on the state
+  // information contained in |input| in the form of key-value pairs. The
+  // program will only see hashed keys and values that are produced using
+  // |hash_seed| as a key.
   static scoped_ptr<EvaluationResults> EvaluateConditionsOnWorkerPoolThread(
       const base::StringPiece& hash_seed,
       const base::StringPiece& program,
@@ -103,12 +123,19 @@
   // result, will potentially show the reset prompt.
   void FinishEvaluationFlow(scoped_ptr<EvaluationResults> results);
 
-  // BrowserContextKeyedService overrides:
+  // Reports the given metrics through UMA. Virtual, so it can be mocked out in
+  // tests to verify that the correct value are being reported.
+  virtual void ReportStatistics(uint32 satisfied_criteria_mask,
+                                uint32 combined_status_mask);
+
+  // BrowserContextKeyedService:
   virtual void Shutdown() OVERRIDE;
 
   Profile* profile_;
 
   State state_;
+  bool enumeration_of_loaded_modules_ready_;
+  bool template_url_service_ready_;
 
   base::StringPiece hash_seed_;
   base::StringPiece program_;
@@ -118,6 +145,7 @@
   FileHostedPromptMemento memento_in_file_;
 
   scoped_ptr<AutomaticProfileResetterDelegate> delegate_;
+  scoped_refptr<base::TaskRunner> task_runner_for_waiting_;
 
   base::WeakPtrFactory<AutomaticProfileResetter> weak_ptr_factory_;
 
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.cc b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.cc
new file mode 100644
index 0000000..45441d1
--- /dev/null
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.cc
@@ -0,0 +1,200 @@
+// Copyright 2013 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/profile_resetter/automatic_profile_resetter_delegate.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+
+#if defined(OS_WIN)
+#include "chrome/browser/enumerate_modules_model_win.h"
+#include "chrome/browser/install_module_verifier_win.h"
+#endif
+
+namespace {
+
+scoped_ptr<base::DictionaryValue> BuildSubTreeFromTemplateURL(
+    const TemplateURL* template_url) {
+  scoped_ptr<base::DictionaryValue> tree(new base::DictionaryValue);
+  tree->SetString("search_url", template_url->url());
+  tree->SetString("search_terms_replacement_key",
+                  template_url->search_terms_replacement_key());
+  tree->SetString("suggest_url", template_url->suggestions_url());
+  tree->SetString("instant_url", template_url->instant_url());
+  tree->SetString("image_url", template_url->image_url());
+  tree->SetString("new_tab_url", template_url->new_tab_url());
+  tree->SetString("search_url_post_params",
+                  template_url->search_url_post_params());
+  tree->SetString("suggest_url_post_params",
+                  template_url->suggestions_url_post_params());
+  tree->SetString("instant_url_post_params",
+                  template_url->instant_url_post_params());
+  tree->SetString("image_url_post_params",
+                  template_url->image_url_post_params());
+  tree->SetString("icon_url", template_url->favicon_url().spec());
+  tree->SetString("name", template_url->short_name());
+  tree->SetString("keyword", template_url->keyword());
+  base::ListValue* input_encodings = new base::ListValue;
+  input_encodings->AppendStrings(template_url->input_encodings());
+  tree->Set("encodings", input_encodings);
+  tree->SetString("id", base::Int64ToString(template_url->id()));
+  tree->SetString("prepopulate_id",
+                  base::IntToString(template_url->prepopulate_id()));
+  base::ListValue* alternate_urls = new base::ListValue;
+  alternate_urls->AppendStrings(template_url->alternate_urls());
+  tree->Set("alternate_urls", alternate_urls);
+  return tree.Pass();
+}
+
+}  // namespace
+
+
+// AutomaticProfileResetterDelegateImpl --------------------------------------
+
+AutomaticProfileResetterDelegateImpl::AutomaticProfileResetterDelegateImpl(
+    TemplateURLService* template_url_service)
+    : template_url_service_(template_url_service) {
+  if (template_url_service_) {
+    template_url_service_->AddObserver(this);
+    // Needed so that |template_url_service_ready_event_| will be signaled even
+    // when TemplateURLService had been already initialized before this point.
+    OnTemplateURLServiceChanged();
+  }
+
+#if defined(OS_WIN)
+  module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
+#endif
+  if (module_list_) {
+    // Having a non-empty module list proves that enumeration had been already
+    // performed before this point.
+    modules_have_been_enumerated_event_.Signal();
+  }
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
+                 content::NotificationService::AllSources());
+}
+
+AutomaticProfileResetterDelegateImpl::~AutomaticProfileResetterDelegateImpl() {
+  if (template_url_service_)
+    template_url_service_->RemoveObserver(this);
+}
+
+void AutomaticProfileResetterDelegateImpl::EnumerateLoadedModulesIfNeeded() {
+  if (!modules_have_been_enumerated_event_.is_signaled()) {
+#if defined(OS_WIN)
+    EnumerateModulesModel::GetInstance()->ScanNow();
+#else
+    modules_have_been_enumerated_event_.Signal();
+#endif
+  }
+}
+
+void AutomaticProfileResetterDelegateImpl::
+    RequestCallbackWhenLoadedModulesAreEnumerated(
+    const base::Closure& ready_callback) const {
+  DCHECK(!ready_callback.is_null());
+  modules_have_been_enumerated_event_.Post(FROM_HERE, ready_callback);
+}
+
+void AutomaticProfileResetterDelegateImpl::LoadTemplateURLServiceIfNeeded() {
+  DCHECK(template_url_service_);
+  template_url_service_->Load();  // Safe to call even if it has loaded already.
+}
+
+void AutomaticProfileResetterDelegateImpl::
+    RequestCallbackWhenTemplateURLServiceIsLoaded(
+    const base::Closure& ready_callback) const {
+  DCHECK(!ready_callback.is_null());
+  template_url_service_ready_event_.Post(FROM_HERE, ready_callback);
+}
+
+scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
+    GetLoadedModuleNameDigests() const {
+  DCHECK(modules_have_been_enumerated_event_.is_signaled());
+  std::set<std::string> module_name_digests;
+#if defined(OS_WIN)
+  if (module_list_)
+    ExtractLoadedModuleNameDigests(*module_list_, &module_name_digests);
+#endif
+  scoped_ptr<base::ListValue> result(new base::ListValue);
+  for (std::set<std::string>::const_iterator it = module_name_digests.begin();
+       it != module_name_digests.end(); ++it)
+    result->AppendString(*it);
+  return result.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> AutomaticProfileResetterDelegateImpl::
+    GetDefaultSearchProviderDetails() const {
+  DCHECK(template_url_service_);
+  DCHECK(template_url_service_->loaded());
+
+  const TemplateURL* default_search_provider =
+      template_url_service_->GetDefaultSearchProvider();
+
+  // Having a NULL default search provider is due to either:
+  //  1.) default search providers being disabled by policy,
+  //  2.) directly tampering with the Preferences and/or the SQLite DBs.
+  // In this state, Omnibox non-keyword search functionality is disabled.
+  return default_search_provider ?
+      BuildSubTreeFromTemplateURL(default_search_provider) :
+      scoped_ptr<base::DictionaryValue>(new base::DictionaryValue);
+}
+
+bool AutomaticProfileResetterDelegateImpl::
+    IsDefaultSearchProviderManaged() const {
+  DCHECK(template_url_service_);
+  DCHECK(template_url_service_->loaded());
+  return template_url_service_->is_default_search_managed();
+}
+
+scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
+    GetPrepopulatedSearchProvidersDetails() const {
+  DCHECK(template_url_service_);
+  size_t default_search_index = 0;
+  ScopedVector<TemplateURL> engines(
+      TemplateURLPrepopulateData::GetPrepopulatedEngines(
+          template_url_service_->profile(), &default_search_index));
+  scoped_ptr<base::ListValue> engines_details_list(new base::ListValue);
+  for (ScopedVector<TemplateURL>::const_iterator it = engines.begin();
+       it != engines.end(); ++it)
+    engines_details_list->Append(BuildSubTreeFromTemplateURL(*it).release());
+  return engines_details_list.Pass();
+}
+
+void AutomaticProfileResetterDelegateImpl::ShowPrompt() {
+  // TODO(engedy): Call the UI from here once we have it.
+}
+
+void AutomaticProfileResetterDelegateImpl::OnTemplateURLServiceChanged() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(template_url_service_);
+  if (template_url_service_->loaded() &&
+      !template_url_service_ready_event_.is_signaled())
+    template_url_service_ready_event_.Signal();
+}
+
+void AutomaticProfileResetterDelegateImpl::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (type == chrome::NOTIFICATION_MODULE_LIST_ENUMERATED &&
+      !modules_have_been_enumerated_event_.is_signaled()) {
+#if defined(OS_WIN)
+    module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
+#endif
+    modules_have_been_enumerated_event_.Signal();
+  }
+}
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h
new file mode 100644
index 0000000..dc8a613
--- /dev/null
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h
@@ -0,0 +1,143 @@
+// Copyright 2013 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_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_DELEGATE_H_
+#define CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/search_engines/template_url_service_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "extensions/common/one_shot_event.h"
+
+class TemplateURLService;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+// Defines the interface for the delegate that will interact with the rest of
+// the browser on behalf of the AutomaticProfileResetter.
+// The primary reason for this separation is to facilitate unit testing.
+class AutomaticProfileResetterDelegate {
+ public:
+  virtual ~AutomaticProfileResetterDelegate() {}
+
+  // Requests the module enumerator to start scanning for loaded modules now, if
+  // it has not done so already.
+  virtual void EnumerateLoadedModulesIfNeeded() = 0;
+
+  // Requests |ready_callback| to be posted on the UI thread once the module
+  // enumerator has finished scanning for loaded modules.
+  virtual void RequestCallbackWhenLoadedModulesAreEnumerated(
+      const base::Closure& ready_callback) const = 0;
+
+  // Requests the template URL service to load its database (asynchronously).
+  virtual void LoadTemplateURLServiceIfNeeded() = 0;
+
+  // Requests |ready_callback| to be posted on the UI thread once the template
+  // URL service has finished loading its database.
+  virtual void RequestCallbackWhenTemplateURLServiceIsLoaded(
+      const base::Closure& ready_callback) const = 0;
+
+  // Returns a list of loaded module name digests.
+  virtual scoped_ptr<base::ListValue> GetLoadedModuleNameDigests() const = 0;
+
+  // Returns attributes of the search engine currently set as the default (or
+  // an empty dictionary if there is none).
+  // The returned attributes correspond in meaning and format to the user
+  // preferences stored by TemplateURLService::SaveDefaultSearchProviderToPrefs,
+  // and will be named after the second path name segment of the respective
+  // preference (i.e. the part after "default_search_provider.").
+  // Note that:
+  //  1.) the "enabled" attribute will not be present, as it is not technically
+  //      an attribute of a search provider,
+  //  2.) "encodings" will be a list of strings, in contrast to a single string
+  //      with tokens delimited by semicolons, but the order will be the same.
+  virtual scoped_ptr<base::DictionaryValue>
+      GetDefaultSearchProviderDetails() const = 0;
+
+  // Returns whether or not the default search provider is set by policy.
+  virtual bool IsDefaultSearchProviderManaged() const = 0;
+
+  // Returns a list of dictionaries, each containing attributes for each of the
+  // pre-populated search engines, in the format described above.
+  virtual scoped_ptr<base::ListValue>
+      GetPrepopulatedSearchProvidersDetails() const = 0;
+
+  // Triggers showing the one-time profile settings reset prompt.
+  virtual void ShowPrompt() = 0;
+};
+
+// Implementation for AutomaticProfileResetterDelegate.
+// To facilitate unit testing, having the TemplateURLService available is only
+// required when using search engine related methods.
+class AutomaticProfileResetterDelegateImpl
+    : public AutomaticProfileResetterDelegate,
+      public TemplateURLServiceObserver,
+      public content::NotificationObserver {
+ public:
+  // The |template_url_service| may be NULL in unit tests. Must be non-NULL for
+  // callers who wish to call:
+  //  * LoadTemplateURLServiceIfNeeded(),
+  //  * GetDefaultSearchProviderDetails(),
+  //  * GetPrepopulatedSearchProvidersDetails(), or
+  //  * IsDefaultSearchManaged().
+  explicit AutomaticProfileResetterDelegateImpl(
+      TemplateURLService* template_url_service);
+  virtual ~AutomaticProfileResetterDelegateImpl();
+
+  // AutomaticProfileResetterDelegate:
+  virtual void EnumerateLoadedModulesIfNeeded() OVERRIDE;
+  virtual void RequestCallbackWhenLoadedModulesAreEnumerated(
+      const base::Closure& ready_callback) const OVERRIDE;
+  virtual void LoadTemplateURLServiceIfNeeded() OVERRIDE;
+  virtual void RequestCallbackWhenTemplateURLServiceIsLoaded(
+      const base::Closure& ready_callback) const OVERRIDE;
+  virtual scoped_ptr<base::ListValue>
+      GetLoadedModuleNameDigests() const OVERRIDE;
+  virtual scoped_ptr<base::DictionaryValue>
+      GetDefaultSearchProviderDetails() const OVERRIDE;
+  virtual bool IsDefaultSearchProviderManaged() const OVERRIDE;
+  virtual scoped_ptr<base::ListValue>
+      GetPrepopulatedSearchProvidersDetails() const OVERRIDE;
+  virtual void ShowPrompt() OVERRIDE;
+
+  // TemplateURLServiceObserver:
+  virtual void OnTemplateURLServiceChanged() OVERRIDE;
+
+  // content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+ private:
+  TemplateURLService* template_url_service_;
+
+  content::NotificationRegistrar registrar_;
+
+  // The list of modules found. Even when |modules_have_been_enumerated_event_|
+  // is signaled, this may still be NULL.
+  scoped_ptr<base::ListValue> module_list_;
+
+  // This event is signaled once module enumeration has been attempted.  If
+  // during construction, EnumerateModulesModel can supply a non-empty list of
+  // modules, module enumeration has clearly already happened, so the event will
+  // be signaled immediately; otherwise, when EnumerateLoadedModulesIfNeeded()
+  // is called, it will ask the model to scan the modules, and then signal the
+  // event once this process is completed.
+  extensions::OneShotEvent modules_have_been_enumerated_event_;
+
+  // This event is signaled once the TemplateURLService has loaded.  If the
+  // TemplateURLService was already loaded prior to the creation of this class,
+  // the event will be signaled during construction.
+  extensions::OneShotEvent template_url_service_ready_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateImpl);
+};
+
+#endif  // CHROME_BROWSER_PROFILE_RESETTER_AUTOMATIC_PROFILE_RESETTER_DELEGATE_H_
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_delegate_unittest.cc b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate_unittest.cc
new file mode 100644
index 0000000..ee89773
--- /dev/null
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_delegate_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright 2013 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/profile_resetter/automatic_profile_resetter_delegate.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/template_url_service_test_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/notification_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "chrome/browser/enumerate_modules_model_win.h"
+#endif
+
+namespace {
+
+// Test fixtures -------------------------------------------------------------
+
+class AutomaticProfileResetterDelegateTest : public testing::Test {
+ protected:
+  AutomaticProfileResetterDelegateTest() {}
+  virtual ~AutomaticProfileResetterDelegateTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    resetter_delegate_.reset(new AutomaticProfileResetterDelegateImpl(NULL));
+  }
+
+  virtual void TearDown() OVERRIDE { resetter_delegate_.reset(); }
+
+  AutomaticProfileResetterDelegate* resetter_delegate() {
+    return resetter_delegate_.get();
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  scoped_ptr<AutomaticProfileResetterDelegate> resetter_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateTest);
+};
+
+class AutomaticProfileResetterDelegateTestTemplateURLs : public testing::Test {
+ protected:
+  AutomaticProfileResetterDelegateTestTemplateURLs() {}
+  virtual ~AutomaticProfileResetterDelegateTestTemplateURLs() {}
+
+  virtual void SetUp() OVERRIDE {
+    test_util_.SetUp();
+    resetter_delegate_.reset(
+        new AutomaticProfileResetterDelegateImpl(test_util_.model()));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    resetter_delegate_.reset();
+    test_util_.TearDown();
+  }
+
+  TestingProfile* profile() { return test_util_.profile(); }
+
+  AutomaticProfileResetterDelegate* resetter_delegate() {
+    return resetter_delegate_.get();
+  }
+
+  scoped_ptr<TemplateURL> CreateTestTemplateURL() {
+    TemplateURLData data;
+
+    data.SetURL("http://example.com/search?q={searchTerms}");
+    data.suggestions_url = "http://example.com/suggest?q={searchTerms}";
+    data.instant_url = "http://example.com/instant?q={searchTerms}";
+    data.image_url = "http://example.com/image?q={searchTerms}";
+    data.search_url_post_params = "search-post-params";
+    data.suggestions_url_post_params = "suggest-post-params";
+    data.instant_url_post_params = "instant-post-params";
+    data.image_url_post_params = "image-post-params";
+
+    data.favicon_url = GURL("http://example.com/favicon.ico");
+    data.new_tab_url = "http://example.com/newtab.html";
+    data.alternate_urls.push_back("http://example.com/s?q={searchTerms}");
+
+    data.short_name = base::ASCIIToUTF16("name");
+    data.SetKeyword(base::ASCIIToUTF16("keyword"));
+    data.search_terms_replacement_key = "search-terms-replacment-key";
+    data.prepopulate_id = 42;
+    data.input_encodings.push_back("UTF-8");
+    data.safe_for_autoreplace = true;
+
+    return scoped_ptr<TemplateURL>(new TemplateURL(profile(), data));
+  }
+
+  TemplateURLServiceTestUtil test_util_;
+
+ private:
+  scoped_ptr<AutomaticProfileResetterDelegate> resetter_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateTestTemplateURLs);
+};
+
+// Helper classes and functions ----------------------------------------------
+
+// Returns the details of the default search provider from |prefs| in a format
+// suitable for usage as |expected_details| in ExpectDetailsMatch().
+scoped_ptr<base::DictionaryValue> GetDefaultSearchProviderDetailsFromPrefs(
+    const PrefService* prefs) {
+  const char kDefaultSearchProviderPrefix[] = "default_search_provider";
+  scoped_ptr<base::DictionaryValue> pref_values_with_path_expansion(
+      prefs->GetPreferenceValues());
+  const base::DictionaryValue* dsp_details = NULL;
+  EXPECT_TRUE(pref_values_with_path_expansion->GetDictionary(
+      kDefaultSearchProviderPrefix, &dsp_details));
+  return scoped_ptr<base::DictionaryValue>(
+      dsp_details ? dsp_details->DeepCopy() : new base::DictionaryValue);
+}
+
+// Verifies that the |details| of a search engine as provided by the delegate
+// are correct in comparison to the |expected_details| coming from the Prefs.
+void ExpectDetailsMatch(const base::DictionaryValue& expected_details,
+                        const base::DictionaryValue& details) {
+  for (base::DictionaryValue::Iterator it(expected_details); !it.IsAtEnd();
+       it.Advance()) {
+    SCOPED_TRACE(testing::Message("Key: ") << it.key());
+    if (it.key() == "enabled" || it.key() == "synced_guid") {
+      // These attributes should not be present.
+      EXPECT_FALSE(details.HasKey(it.key()));
+      continue;
+    }
+    const base::Value* expected_value = &it.value();
+    const base::Value* actual_value = NULL;
+    ASSERT_TRUE(details.Get(it.key(), &actual_value));
+    if (it.key() == "id") {
+      // Ignore ID as it is dynamically assigned by the TemplateURLService.
+    } else if (it.key() == "encodings") {
+      // Encoding list is stored in Prefs as a single string with tokens
+      // delimited by semicolons.
+      std::string expected_encodings;
+      ASSERT_TRUE(expected_value->GetAsString(&expected_encodings));
+      const base::ListValue* actual_encodings_list = NULL;
+      ASSERT_TRUE(actual_value->GetAsList(&actual_encodings_list));
+      std::vector<std::string> actual_encodings_vector;
+      for (base::ListValue::const_iterator it = actual_encodings_list->begin();
+           it != actual_encodings_list->end(); ++it) {
+        std::string encoding;
+        ASSERT_TRUE((*it)->GetAsString(&encoding));
+        actual_encodings_vector.push_back(encoding);
+      }
+      EXPECT_EQ(expected_encodings, JoinString(actual_encodings_vector, ';'));
+    } else {
+      // Everything else is the same format.
+      EXPECT_TRUE(actual_value->Equals(expected_value));
+    }
+  }
+}
+
+class MockCallbackTarget {
+ public:
+  MockCallbackTarget() {}
+  ~MockCallbackTarget() {}
+
+  MOCK_CONST_METHOD0(Run, void(void));
+
+  base::Closure CreateClosure() {
+    return base::Closure(
+        base::Bind(&MockCallbackTarget::Run, base::Unretained(this)));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockCallbackTarget);
+};
+
+// Tests ---------------------------------------------------------------------
+
+TEST_F(AutomaticProfileResetterDelegateTest,
+       TriggerAndWaitOnModuleEnumeration) {
+  testing::StrictMock<MockCallbackTarget> mock_target;
+
+  // Expect ready_callback to be called just after the modules have been
+  // enumerated. Fail if it is not called. Note: as the EnumerateModulesModel is
+  // a global singleton, the callback might be invoked immediately if another
+  // test-case (e.g. the one below) has already performed module enumeration.
+  EXPECT_CALL(mock_target, Run());
+  resetter_delegate()->RequestCallbackWhenLoadedModulesAreEnumerated(
+      mock_target.CreateClosure());
+  resetter_delegate()->EnumerateLoadedModulesIfNeeded();
+  base::RunLoop().RunUntilIdle();
+
+  testing::Mock::VerifyAndClearExpectations(&mock_target);
+
+  // Expect ready_callback to be posted immediately when the modules have
+  // already been enumerated.
+  EXPECT_CALL(mock_target, Run());
+  resetter_delegate()->RequestCallbackWhenLoadedModulesAreEnumerated(
+      mock_target.CreateClosure());
+  base::RunLoop().RunUntilIdle();
+
+#if defined(OS_WIN)
+  testing::Mock::VerifyAndClearExpectations(&mock_target);
+
+  // Expect ready_callback to be posted immediately even when the modules had
+  // already been enumerated when the delegate was constructed.
+  scoped_ptr<AutomaticProfileResetterDelegate> late_resetter_delegate(
+      new AutomaticProfileResetterDelegateImpl(NULL));
+
+  EXPECT_CALL(mock_target, Run());
+  late_resetter_delegate->RequestCallbackWhenLoadedModulesAreEnumerated(
+      mock_target.CreateClosure());
+  base::RunLoop().RunUntilIdle();
+#endif
+}
+
+TEST_F(AutomaticProfileResetterDelegateTest, GetLoadedModuleNameDigests) {
+  resetter_delegate()->EnumerateLoadedModulesIfNeeded();
+  base::RunLoop().RunUntilIdle();
+  scoped_ptr<base::ListValue> module_name_digests(
+      resetter_delegate()->GetLoadedModuleNameDigests());
+
+  // Just verify that each element looks like an MD5 hash in hexadecimal, and
+  // also that we have at least one element on Win.
+  ASSERT_TRUE(module_name_digests);
+  for (base::ListValue::const_iterator it = module_name_digests->begin();
+       it != module_name_digests->end(); ++it) {
+    std::string digest_hex;
+    std::vector<uint8> digest_raw;
+
+    ASSERT_TRUE((*it)->GetAsString(&digest_hex));
+    ASSERT_TRUE(base::HexStringToBytes(digest_hex, &digest_raw));
+    EXPECT_EQ(16u, digest_raw.size());
+  }
+#if defined(OS_WIN)
+  EXPECT_LE(1u, module_name_digests->GetSize());
+#endif
+}
+
+TEST_F(AutomaticProfileResetterDelegateTestTemplateURLs,
+       LoadAndWaitOnTemplateURLService) {
+  testing::StrictMock<MockCallbackTarget> mock_target;
+
+  // Expect ready_callback to be called just after the template URL service gets
+  // initialized. Fail if it is not called, or called too early.
+  resetter_delegate()->RequestCallbackWhenTemplateURLServiceIsLoaded(
+      mock_target.CreateClosure());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(mock_target, Run());
+  resetter_delegate()->LoadTemplateURLServiceIfNeeded();
+  base::RunLoop().RunUntilIdle();
+
+  testing::Mock::VerifyAndClearExpectations(&mock_target);
+
+  // Expect ready_callback to be posted immediately when the template URL
+  // service is already initialized.
+  EXPECT_CALL(mock_target, Run());
+  resetter_delegate()->RequestCallbackWhenTemplateURLServiceIsLoaded(
+      mock_target.CreateClosure());
+  base::RunLoop().RunUntilIdle();
+
+  testing::Mock::VerifyAndClearExpectations(&mock_target);
+
+  // Expect ready_callback to be posted immediately even when the template URL
+  // service had already been initialized when the delegate was constructed.
+  scoped_ptr<AutomaticProfileResetterDelegate> late_resetter_delegate(
+      new AutomaticProfileResetterDelegateImpl(test_util_.model()));
+
+  EXPECT_CALL(mock_target, Run());
+  late_resetter_delegate->RequestCallbackWhenTemplateURLServiceIsLoaded(
+      mock_target.CreateClosure());
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(AutomaticProfileResetterDelegateTestTemplateURLs,
+       DefaultSearchProviderDataWhenNotManaged) {
+  TemplateURLService* template_url_service = test_util_.model();
+  test_util_.VerifyLoad();
+
+  // Check that the "managed state" and the details returned by the delegate are
+  // correct. We verify the details against the data stored by
+  // TemplateURLService into Prefs.
+  scoped_ptr<TemplateURL> owned_custom_dsp(CreateTestTemplateURL());
+  TemplateURL* custom_dsp = owned_custom_dsp.get();
+  template_url_service->Add(owned_custom_dsp.release());
+  template_url_service->SetDefaultSearchProvider(custom_dsp);
+
+  PrefService* prefs = profile()->GetPrefs();
+  ASSERT_TRUE(prefs);
+  scoped_ptr<base::DictionaryValue> dsp_details(
+      resetter_delegate()->GetDefaultSearchProviderDetails());
+  scoped_ptr<base::DictionaryValue> expected_dsp_details(
+      GetDefaultSearchProviderDetailsFromPrefs(prefs));
+
+  ExpectDetailsMatch(*expected_dsp_details, *dsp_details);
+  EXPECT_FALSE(resetter_delegate()->IsDefaultSearchProviderManaged());
+}
+
+TEST_F(AutomaticProfileResetterDelegateTestTemplateURLs,
+       DefaultSearchProviderDataWhenManaged) {
+  const char kTestSearchURL[] = "http://example.com/search?q={searchTerms}";
+  const char kTestName[] = "name";
+  const char kTestKeyword[] = "keyword";
+
+  test_util_.VerifyLoad();
+
+  EXPECT_FALSE(resetter_delegate()->IsDefaultSearchProviderManaged());
+
+  // Set managed preferences to emulate a default search provider set by policy.
+  test_util_.SetManagedDefaultSearchPreferences(
+      true, kTestName, kTestKeyword, kTestSearchURL, std::string(),
+      std::string(), std::string(), std::string(), std::string());
+
+  EXPECT_TRUE(resetter_delegate()->IsDefaultSearchProviderManaged());
+  scoped_ptr<base::DictionaryValue> dsp_details(
+      resetter_delegate()->GetDefaultSearchProviderDetails());
+  // Checking that all details are correct is already done by the above test.
+  // Just make sure details are reported about the correct engine.
+  base::ExpectDictStringValue(kTestSearchURL, *dsp_details, "search_url");
+
+  // Set managed preferences to emulate that having a default search provider is
+  // disabled by policy.
+  test_util_.RemoveManagedDefaultSearchPreferences();
+  test_util_.SetManagedDefaultSearchPreferences(
+      true, std::string(), std::string(), std::string(), std::string(),
+      std::string(), std::string(), std::string(), std::string());
+
+  dsp_details = resetter_delegate()->GetDefaultSearchProviderDetails();
+  EXPECT_TRUE(resetter_delegate()->IsDefaultSearchProviderManaged());
+  EXPECT_TRUE(dsp_details->empty());
+}
+
+TEST_F(AutomaticProfileResetterDelegateTestTemplateURLs,
+       GetPrepopulatedSearchProvidersDetails) {
+  TemplateURLService* template_url_service = test_util_.model();
+  test_util_.VerifyLoad();
+
+  scoped_ptr<base::ListValue> search_engines_details(
+      resetter_delegate()->GetPrepopulatedSearchProvidersDetails());
+
+  // Do the same kind of verification as for GetDefaultSearchEngineDetails:
+  // subsequently set each pre-populated engine as the default, so we can verify
+  // that the details returned by the delegate about one particular engine are
+  // correct in comparison to what has been stored to the Prefs.
+  std::vector<TemplateURL*> prepopulated_engines =
+      template_url_service->GetTemplateURLs();
+
+  ASSERT_EQ(prepopulated_engines.size(), search_engines_details->GetSize());
+
+  for (size_t i = 0; i < search_engines_details->GetSize(); ++i) {
+    const base::DictionaryValue* details = NULL;
+    ASSERT_TRUE(search_engines_details->GetDictionary(i, &details));
+
+    std::string keyword;
+    ASSERT_TRUE(details->GetString("keyword", &keyword));
+    TemplateURL* search_engine =
+        template_url_service->GetTemplateURLForKeyword(ASCIIToUTF16(keyword));
+    ASSERT_TRUE(search_engine);
+    template_url_service->SetDefaultSearchProvider(prepopulated_engines[i]);
+
+    PrefService* prefs = profile()->GetPrefs();
+    ASSERT_TRUE(prefs);
+    scoped_ptr<base::DictionaryValue> expected_dsp_details(
+        GetDefaultSearchProviderDetailsFromPrefs(prefs));
+    ExpectDetailsMatch(*expected_dsp_details, *details);
+  }
+}
+
+}  // namespace
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_factory.cc b/chrome/browser/profile_resetter/automatic_profile_resetter_factory.cc
index 90971de..10bd7c3 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter_factory.cc
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_factory.cc
@@ -40,7 +40,9 @@
 AutomaticProfileResetterFactory::AutomaticProfileResetterFactory()
     : BrowserContextKeyedServiceFactory(
           "AutomaticProfileResetter",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(TemplateURLServiceFactory::GetInstance());
+}
 
 AutomaticProfileResetterFactory::~AutomaticProfileResetterFactory() {}
 
@@ -49,7 +51,7 @@
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   AutomaticProfileResetter* service = new AutomaticProfileResetter(profile);
-  service->Initialize();
+  service->Activate();
   return service;
 }
 
@@ -61,8 +63,8 @@
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
-bool AutomaticProfileResetterFactory::ServiceIsCreatedWithBrowserContext()
-    const {
+bool AutomaticProfileResetterFactory::
+    ServiceIsCreatedWithBrowserContext() const {
   return true;
 }
 
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_factory.h b/chrome/browser/profile_resetter/automatic_profile_resetter_factory.h
index e874722..6e155f4 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter_factory.h
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_factory.h
@@ -39,11 +39,11 @@
   AutomaticProfileResetterFactory();
   virtual ~AutomaticProfileResetterFactory();
 
-  // BrowserContextKeyedServiceFactory overrides:
+  // BrowserContextKeyedServiceFactory:
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const OVERRIDE;
 
-  // BrowserContextKeyedBaseFactory overrides:
+  // BrowserContextKeyedBaseFactory:
   virtual void RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable* registry) OVERRIDE;
   virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_mementos.cc b/chrome/browser/profile_resetter/automatic_profile_resetter_mementos.cc
index 84524b9..af7fa4d 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter_mementos.cc
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_mementos.cc
@@ -4,14 +4,15 @@
 
 #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h"
 
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/pref_names.h"
@@ -19,10 +20,12 @@
 
 using base::DictionaryValue;
 
+
 // AutomaticProfileResetter::PreferenceHostedPromptMemento -------------------
 
 PreferenceHostedPromptMemento::PreferenceHostedPromptMemento(Profile* profile)
     : profile_(profile) {}
+
 PreferenceHostedPromptMemento::~PreferenceHostedPromptMemento() {}
 
 std::string PreferenceHostedPromptMemento::ReadValue() const {
@@ -37,10 +40,12 @@
   prefs->SetString(prefs::kProfileResetPromptMemento, value);
 }
 
+
 // AutomaticProfileResetter::LocalStateHostedPromptMemento -------------------
 
 LocalStateHostedPromptMemento::LocalStateHostedPromptMemento(Profile* profile)
     : profile_(profile) {}
+
 LocalStateHostedPromptMemento::~LocalStateHostedPromptMemento() {}
 
 std::string LocalStateHostedPromptMemento::ReadValue() const {
@@ -52,12 +57,11 @@
   std::string profile_key = GetProfileKey();
   if (!prompt_shown_dict || profile_key.empty()) {
     NOTREACHED();
-    return "";
+    return std::string();
   }
   std::string value;
-  return prompt_shown_dict->GetStringWithoutPathExpansion(profile_key, &value)
-             ? value
-             : "";
+  return prompt_shown_dict->GetStringWithoutPathExpansion(profile_key, &value) ?
+      value : std::string();
 }
 
 void LocalStateHostedPromptMemento::StoreValue(const std::string& value) {
@@ -79,10 +83,12 @@
   return profile_->GetPath().BaseName().MaybeAsASCII();
 }
 
+
 // AutomaticProfileResetter::FileHostedPromptMemento -------------------------
 
 FileHostedPromptMemento::FileHostedPromptMemento(Profile* profile)
     : profile_(profile) {}
+
 FileHostedPromptMemento::~FileHostedPromptMemento() {}
 
 void FileHostedPromptMemento::ReadValue(
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter_unittest.cc b/chrome/browser/profile_resetter/automatic_profile_resetter_unittest.cc
index f71af0c..084a686 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter_unittest.cc
@@ -2,26 +2,37 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/profile_resetter/automatic_profile_resetter.h"
+
 #include <string>
 
-#include "base/basictypes.h"
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/metrics/field_trial.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/profile_resetter/automatic_profile_resetter.h"
+#include "base/values.h"
+#include "chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h"
 #include "chrome/browser/profile_resetter/automatic_profile_resetter_factory.h"
 #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h"
 #include "chrome/browser/profile_resetter/jtl_foundation.h"
 #include "chrome/browser/profile_resetter/jtl_instructions.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using testing::_;
+using testing::Invoke;
+
 namespace {
 
 const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
@@ -33,17 +44,119 @@
 const char kTestMementoValue[] = "01234567890123456789012345678901";
 const char kTestInvalidMementoValue[] = "12345678901234567890123456789012";
 
+const char kTestPreferencePath[] = "testing.preference";
+const char kTestPreferenceValue[] = "testing-preference-value";
+
+const char kSearchURLAttributeKey[] = "search_url";
+const char kTestSearchURL[] = "http://example.com/search?q={searchTerms}";
+const char kTestSearchURL2[] = "http://google.com/?q={searchTerms}";
+
+const char kTestModuleDigest[] = "01234567890123456789012345678901";
+const char kTestModuleDigest2[] = "12345678901234567890123456789012";
+
 // Helpers ------------------------------------------------------------------
 
-class MockProfileResetterDelegate : public AutomaticProfileResetterDelegate {
+// A testing version of the AutomaticProfileResetter that differs from the real
+// one only in that it has its statistics reporting mocked out for verification.
+class AutomaticProfileResetterUnderTest : public AutomaticProfileResetter {
  public:
-  MockProfileResetterDelegate() {}
-  virtual ~MockProfileResetterDelegate() {}
+  explicit AutomaticProfileResetterUnderTest(Profile* profile)
+      : AutomaticProfileResetter(profile) {}
+  virtual ~AutomaticProfileResetterUnderTest() {}
 
-  MOCK_METHOD0(ShowPrompt, void());
   MOCK_METHOD2(ReportStatistics, void(uint32, uint32));
 
  private:
+  DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterUnderTest);
+};
+
+class MockProfileResetterDelegate : public AutomaticProfileResetterDelegate {
+ public:
+  MockProfileResetterDelegate()
+      : emulated_default_search_provider_is_managed_(false) {}
+  virtual ~MockProfileResetterDelegate() {}
+
+  MOCK_METHOD0(EnumerateLoadedModulesIfNeeded, void());
+  MOCK_CONST_METHOD1(RequestCallbackWhenLoadedModulesAreEnumerated,
+                     void(const base::Closure&));
+
+  MOCK_METHOD0(LoadTemplateURLServiceIfNeeded, void());
+  MOCK_CONST_METHOD1(RequestCallbackWhenTemplateURLServiceIsLoaded,
+                     void(const base::Closure&));
+
+  MOCK_CONST_METHOD0(OnGetLoadedModuleNameDigestsCalled, void());
+  MOCK_CONST_METHOD0(OnGetDefaultSearchProviderDetailsCalled, void());
+  MOCK_CONST_METHOD0(OnIsDefaultSearchProviderManagedCalled, void());
+  MOCK_CONST_METHOD0(OnGetPrepopulatedSearchProvidersDetailsCalled, void());
+
+  MOCK_METHOD0(ShowPrompt, void());
+
+  virtual scoped_ptr<base::ListValue>
+      GetLoadedModuleNameDigests() const OVERRIDE {
+    OnGetLoadedModuleNameDigestsCalled();
+    return scoped_ptr<base::ListValue>(
+        emulated_loaded_module_digests_.DeepCopy());
+  }
+
+  virtual scoped_ptr<base::DictionaryValue>
+      GetDefaultSearchProviderDetails() const OVERRIDE {
+    OnGetDefaultSearchProviderDetailsCalled();
+    return scoped_ptr<base::DictionaryValue>(
+        emulated_default_search_provider_details_.DeepCopy());
+  }
+
+  virtual bool IsDefaultSearchProviderManaged() const OVERRIDE {
+    OnIsDefaultSearchProviderManagedCalled();
+    return emulated_default_search_provider_is_managed_;
+  }
+
+  virtual scoped_ptr<base::ListValue>
+      GetPrepopulatedSearchProvidersDetails() const OVERRIDE {
+    OnGetPrepopulatedSearchProvidersDetailsCalled();
+    return scoped_ptr<base::ListValue>(
+        emulated_search_providers_details_.DeepCopy());
+  }
+
+  static void ClosureInvoker(const base::Closure& closure) { closure.Run(); }
+
+  void ExpectCallsToDependenciesSetUpMethods() {
+    EXPECT_CALL(*this, EnumerateLoadedModulesIfNeeded());
+    EXPECT_CALL(*this, LoadTemplateURLServiceIfNeeded());
+    EXPECT_CALL(*this, RequestCallbackWhenLoadedModulesAreEnumerated(_))
+        .WillOnce(Invoke(ClosureInvoker));
+    EXPECT_CALL(*this, RequestCallbackWhenTemplateURLServiceIsLoaded(_))
+        .WillOnce(Invoke(ClosureInvoker));
+  }
+
+  void ExpectCallsToGetterMethods() {
+    EXPECT_CALL(*this, OnGetLoadedModuleNameDigestsCalled());
+    EXPECT_CALL(*this, OnGetDefaultSearchProviderDetailsCalled());
+    EXPECT_CALL(*this, OnIsDefaultSearchProviderManagedCalled());
+    EXPECT_CALL(*this, OnGetPrepopulatedSearchProvidersDetailsCalled());
+  }
+
+  base::DictionaryValue& emulated_default_search_provider_details() {
+    return emulated_default_search_provider_details_;
+  }
+
+  base::ListValue& emulated_search_providers_details() {
+    return emulated_search_providers_details_;
+  }
+
+  base::ListValue& emulated_loaded_module_digests() {
+    return emulated_loaded_module_digests_;
+  }
+
+  void set_emulated_default_search_provider_is_managed(bool value) {
+    emulated_default_search_provider_is_managed_ = value;
+  }
+
+ private:
+  base::DictionaryValue emulated_default_search_provider_details_;
+  base::ListValue emulated_search_providers_details_;
+  base::ListValue emulated_loaded_module_digests_;
+  bool emulated_default_search_provider_is_managed_;
+
   DISALLOW_COPY_AND_ASSIGN(MockProfileResetterDelegate);
 };
 
@@ -79,8 +192,8 @@
 // Encodes a Boolean argument value into JTL bytecode.
 std::string EncodeBool(bool value) { return value ? VALUE_TRUE : VALUE_FALSE; }
 
-// Constructs a simple evaluation program to test that input/output works well.
-// It will emulate a scenario in which the reset criteria are satisfied as
+// Constructs a simple evaluation program to test that basic input/output works
+// well. It will emulate a scenario in which the reset criteria are satisfied as
 // prescribed by |emulate_satisfied_criterion_{1|2}|, and will set bits in the
 // combined status mask according to whether or not the memento values received
 // in the input were as expected.
@@ -142,26 +255,192 @@
   return bytecode;
 }
 
+// Constructs another evaluation program to specifically test that local state
+// and user preference values are included in the input as expected. We will
+// re-purpose the output bitmasks to channel out information about the outcome
+// of the checks.
+//
+// More specifically, the output of the program will be as follows:
+// {
+//   "combined_status_mask_bit1":
+//       (input["preferences.testing.preference"] == kTestPreferenceValue)
+//   "combined_status_mask_bit2":
+//       (input["local_state.testing.preference"] == kTestPreferenceValue)
+//   "combined_status_mask_bit3": input["preferences_iuc.testing.preference"]
+//   "combined_status_mask_bit4": input["local_state_iuc.testing.preference"]
+// }
+std::string ConstructProgramToCheckPreferences() {
+  std::string bytecode;
+  bytecode += OP_NAVIGATE(GetHash("preferences"));
+  bytecode += OP_NAVIGATE(GetHash("testing"));
+  bytecode += OP_NAVIGATE(GetHash("preference"));
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestPreferenceValue));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit1"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("local_state"));
+  bytecode += OP_NAVIGATE(GetHash("testing"));
+  bytecode += OP_NAVIGATE(GetHash("preference"));
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestPreferenceValue));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit2"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("preferences_iuc"));
+  bytecode += OP_NAVIGATE(GetHash("testing"));
+  bytecode += OP_NAVIGATE(GetHash("preference"));
+  bytecode += OP_COMPARE_NODE_BOOL(EncodeBool(true));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit3"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("local_state_iuc"));
+  bytecode += OP_NAVIGATE(GetHash("testing"));
+  bytecode += OP_NAVIGATE(GetHash("preference"));
+  bytecode += OP_COMPARE_NODE_BOOL(EncodeBool(true));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit4"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  return bytecode;
+}
+
+// Legend for the bitmask returned by the above program.
+enum CombinedStatusMaskLegendForCheckingPreferences {
+  HAS_EXPECTED_USER_PREFERENCE = 1 << 0,
+  HAS_EXPECTED_LOCAL_STATE_PREFERENCE = 1 << 1,
+  USER_PREFERENCE_IS_USER_CONTROLLED = 1 << 2,
+  LOCAL_STATE_IS_USER_CONTROLLED = 1 << 3,
+};
+
+// Constructs yet another evaluation program to specifically test that default
+// and pre-populated search engines are included in the input as expected. We
+// will re-purpose the output bitmasks to channel out information about the
+// outcome of the checks.
+//
+// More specifically, the output of the program will be as follows:
+// {
+//   "combined_status_mask_bit1":
+//       (input["default_search_provider.search_url"] == kTestSearchURL)
+//   "combined_status_mask_bit2": input["default_search_provider_iuc"]
+//   "combined_status_mask_bit3":
+//       (input["search_providers.*.search_url"] == kTestSearchURL)
+//   "combined_status_mask_bit4":
+//       (input["search_providers.*.search_url"] == kTestSearchURL2)
+// }
+std::string ConstructProgramToCheckSearchEngines() {
+  std::string bytecode;
+  bytecode += OP_NAVIGATE(GetHash("default_search_provider"));
+  bytecode += OP_NAVIGATE(GetHash("search_url"));
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestSearchURL));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit1"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("default_search_provider_iuc"));
+  bytecode += OP_COMPARE_NODE_BOOL(EncodeBool(true));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit2"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("search_providers"));
+  bytecode += OP_NAVIGATE_ANY;
+  bytecode += OP_NAVIGATE(GetHash("search_url"));
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestSearchURL));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit3"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("search_providers"));
+  bytecode += OP_NAVIGATE_ANY;
+  bytecode += OP_NAVIGATE(GetHash("search_url"));
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestSearchURL2));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit4"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  return bytecode;
+}
+
+// Legend for the bitmask returned by the above program.
+enum CombinedStatusMaskLegendForCheckingSearchEngines {
+  HAS_EXPECTED_DEFAULT_SEARCH_PROVIDER = 1 << 0,
+  DEFAULT_SEARCH_PROVIDER_IS_USER_CONTROLLED = 1 << 1,
+  HAS_EXPECTED_PREPOPULATED_SEARCH_PROVIDER_1 = 1 << 2,
+  HAS_EXPECTED_PREPOPULATED_SEARCH_PROVIDER_2 = 1 << 3,
+};
+
+// Constructs yet another evaluation program to specifically test that loaded
+// module digests are included in the input as expected. We will re-purpose the
+// output bitmasks to channel out information about the outcome of the checks.
+//
+// More specifically, the output of the program will be as follows:
+// {
+//   "combined_status_mask_bit1":
+//       (input["loaded_modules.*"] == kTestModuleDigest)
+//   "combined_status_mask_bit2":
+//       (input["loaded_modules.*"] == kTestModuleDigest2)
+// }
+std::string ConstructProgramToCheckLoadedModuleDigests() {
+  std::string bytecode;
+  bytecode += OP_NAVIGATE(GetHash("loaded_modules"));
+  bytecode += OP_NAVIGATE_ANY;
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestModuleDigest));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit1"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  bytecode += OP_NAVIGATE(GetHash("loaded_modules"));
+  bytecode += OP_NAVIGATE_ANY;
+  bytecode += OP_COMPARE_NODE_HASH(GetHash(kTestModuleDigest2));
+  bytecode += OP_STORE_BOOL(GetHash("combined_status_mask_bit2"),
+                            EncodeBool(true));
+  bytecode += OP_END_OF_SENTENCE;
+  return bytecode;
+}
+
+// Legend for the bitmask returned by the above program.
+enum CombinedStatusMaskLegendForCheckingLoadedModules {
+  HAS_EXPECTED_MODULE_DIGEST_1 = 1 << 0,
+  HAS_EXPECTED_MODULE_DIGEST_2 = 1 << 1,
+};
+
 // Test fixtures -------------------------------------------------------------
 
 class AutomaticProfileResetterTestBase : public testing::Test {
  protected:
   explicit AutomaticProfileResetterTestBase(
       const std::string& experiment_group_name)
-      : local_state_(TestingBrowserProcess::GetGlobal()),
+      : waiting_task_runner_(new base::TestSimpleTaskRunner),
+        local_state_(TestingBrowserProcess::GetGlobal()),
+        profile_(new TestingProfile()),
         experiment_group_name_(experiment_group_name),
         mock_delegate_(NULL) {
-    // Make sure the factory is not optimized away, so prefs get registered.
+    // Make sure the factory is not optimized away, so whatever preferences it
+    // wants to register will actually get registered.
     AutomaticProfileResetterFactory::GetInstance();
+
+    // Register some additional local state preferences for testing purposes.
+    PrefRegistrySimple* local_state_registry = local_state_.Get()->registry();
+    DCHECK(local_state_registry);
+    local_state_registry->RegisterStringPref(kTestPreferencePath, "");
+
+    // Register some additional user preferences for testing purposes.
+    user_prefs::PrefRegistrySyncable* user_prefs_registry =
+        profile_->GetTestingPrefService()->registry();
+    DCHECK(user_prefs_registry);
+    user_prefs_registry->RegisterStringPref(
+        kTestPreferencePath,
+        "",
+        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   }
 
   virtual void SetUp() OVERRIDE {
-    profile_.reset(new TestingProfile());
     field_trials_.reset(new base::FieldTrialList(NULL));
     base::FieldTrialList::CreateFieldTrial(kAutomaticProfileResetStudyName,
                                            experiment_group_name_);
-    mock_delegate_ = new testing::StrictMock<MockProfileResetterDelegate>();
-    resetter_.reset(new AutomaticProfileResetter(profile_.get()));
+
+    resetter_.reset(new testing::StrictMock<AutomaticProfileResetterUnderTest>(
+        profile_.get()));
+
+    scoped_ptr<MockProfileResetterDelegate> mock_delegate(
+        new testing::StrictMock<MockProfileResetterDelegate>());
+    mock_delegate_ = mock_delegate.get();
+    resetter_->SetDelegateForTesting(
+        mock_delegate.PassAs<AutomaticProfileResetterDelegate>());
+    resetter_->SetTaskRunnerForWaitingForTesting(waiting_task_runner_);
   }
 
   void SetTestingHashSeed(const std::string& hash_seed) {
@@ -173,22 +452,30 @@
   }
 
   void UnleashResetterAndWait() {
-    resetter_->Initialize();
-    resetter_->SetDelegateForTesting(mock_delegate_);  // Takes ownership.
     resetter_->SetHashSeedForTesting(testing_hash_seed_);
     resetter_->SetProgramForTesting(testing_program_);
+
+    resetter_->Activate();
+
+    if (waiting_task_runner_->HasPendingTask()) {
+      EXPECT_EQ(base::TimeDelta::FromSeconds(55),
+                waiting_task_runner_->NextPendingTaskDelay());
+      waiting_task_runner_->RunPendingTasks();
+    }
     base::RunLoop().RunUntilIdle();
     content::BrowserThread::GetBlockingPool()->FlushForTesting();
     base::RunLoop().RunUntilIdle();
   }
 
   TestingProfile* profile() { return profile_.get(); }
+  TestingPrefServiceSimple* local_state() { return local_state_.Get(); }
 
   MockProfileResetterDelegate& mock_delegate() { return *mock_delegate_; }
-  AutomaticProfileResetter* resetter() { return resetter_.get(); }
+  AutomaticProfileResetterUnderTest& resetter() { return *resetter_; }
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
+  scoped_refptr<base::TestSimpleTaskRunner> waiting_task_runner_;
   ScopedTestingLocalState local_state_;
   scoped_ptr<TestingProfile> profile_;
   scoped_ptr<base::FieldTrialList> field_trials_;
@@ -196,7 +483,7 @@
   std::string testing_program_;
   std::string testing_hash_seed_;
 
-  scoped_ptr<AutomaticProfileResetter> resetter_;
+  scoped_ptr<AutomaticProfileResetterUnderTest> resetter_;
   MockProfileResetterDelegate* mock_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterTestBase);
@@ -257,7 +544,9 @@
   SetTestingProgram(ConstructProgram(false, false));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x00u, 0x00u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, 0x00u));
 
   UnleashResetterAndWait();
 
@@ -278,7 +567,9 @@
   SetTestingProgram(ConstructProgram(true, false));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x01u, 0x01u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x01u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -299,7 +590,9 @@
   SetTestingProgram(ConstructProgram(false, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x02u, 0x01u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x02u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -321,7 +614,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x01u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -340,7 +635,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x03u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x03u));
 
   UnleashResetterAndWait();
 
@@ -359,7 +656,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x05u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x05u));
 
   UnleashResetterAndWait();
 
@@ -378,7 +677,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x09u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x09u));
 
   UnleashResetterAndWait();
 
@@ -416,7 +717,9 @@
   SetTestingProgram(ConstructProgram(false, false));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x00u, 0x00u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, 0x00u));
 
   UnleashResetterAndWait();
 
@@ -437,8 +740,10 @@
   SetTestingProgram(ConstructProgram(true, false));
   SetTestingHashSeed(kTestHashSeed);
 
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
   EXPECT_CALL(mock_delegate(), ShowPrompt());
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x01u, 0x01u));
+  EXPECT_CALL(resetter(), ReportStatistics(0x01u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -459,8 +764,10 @@
   SetTestingProgram(ConstructProgram(false, true));
   SetTestingHashSeed(kTestHashSeed);
 
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
   EXPECT_CALL(mock_delegate(), ShowPrompt());
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x02u, 0x01u));
+  EXPECT_CALL(resetter(), ReportStatistics(0x02u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -481,8 +788,10 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
   EXPECT_CALL(mock_delegate(), ShowPrompt());
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x01u));
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x01u));
 
   UnleashResetterAndWait();
 
@@ -501,7 +810,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x03u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x03u));
 
   UnleashResetterAndWait();
 
@@ -520,7 +831,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x05u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x05u));
 
   UnleashResetterAndWait();
 
@@ -539,7 +852,9 @@
   SetTestingProgram(ConstructProgram(true, true));
   SetTestingHashSeed(kTestHashSeed);
 
-  EXPECT_CALL(mock_delegate(), ReportStatistics(0x03u, 0x09u));
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x09u));
 
   UnleashResetterAndWait();
 
@@ -565,4 +880,148 @@
   EXPECT_EQ("", memento_in_file.ReadValue());
 }
 
+// Please see comments above ConstructProgramToCheckPreferences() to understand
+// how the following tests work.
+
+TEST_F(AutomaticProfileResetterTest, InputUserPreferencesCorrect) {
+  SetTestingProgram(ConstructProgramToCheckPreferences());
+  SetTestingHashSeed(kTestHashSeed);
+
+  PrefService* prefs = profile()->GetPrefs();
+  prefs->SetString(kTestPreferencePath, kTestPreferenceValue);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask =
+      HAS_EXPECTED_USER_PREFERENCE | USER_PREFERENCE_IS_USER_CONTROLLED;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+TEST_F(AutomaticProfileResetterTest, InputLocalStateCorrect) {
+  SetTestingProgram(ConstructProgramToCheckPreferences());
+  SetTestingHashSeed(kTestHashSeed);
+
+  PrefService* prefs = local_state();
+  prefs->SetString(kTestPreferencePath, kTestPreferenceValue);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask =
+      HAS_EXPECTED_LOCAL_STATE_PREFERENCE | LOCAL_STATE_IS_USER_CONTROLLED;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+TEST_F(AutomaticProfileResetterTest, InputManagedUserPreferencesCorrect) {
+  SetTestingProgram(ConstructProgramToCheckPreferences());
+  SetTestingHashSeed(kTestHashSeed);
+
+  TestingPrefServiceSyncable* prefs = profile()->GetTestingPrefService();
+  prefs->SetManagedPref(kTestPreferencePath,
+                        new base::StringValue(kTestPreferenceValue));
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask = HAS_EXPECTED_USER_PREFERENCE;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+TEST_F(AutomaticProfileResetterTest, InputManagedLocalStateCorrect) {
+  SetTestingProgram(ConstructProgramToCheckPreferences());
+  SetTestingHashSeed(kTestHashSeed);
+
+  TestingPrefServiceSimple* prefs = local_state();
+  prefs->SetManagedPref(kTestPreferencePath,
+                        new base::StringValue(kTestPreferenceValue));
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask = HAS_EXPECTED_LOCAL_STATE_PREFERENCE;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+// Please see comments above ConstructProgramToCheckSearchEngines() to
+// understand how the following tests work.
+
+TEST_F(AutomaticProfileResetterTest, InputDefaultSearchProviderCorrect) {
+  SetTestingProgram(ConstructProgramToCheckSearchEngines());
+  SetTestingHashSeed(kTestHashSeed);
+
+  mock_delegate().emulated_default_search_provider_details().SetString(
+      kSearchURLAttributeKey, kTestSearchURL);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask = HAS_EXPECTED_DEFAULT_SEARCH_PROVIDER |
+                         DEFAULT_SEARCH_PROVIDER_IS_USER_CONTROLLED;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+TEST_F(AutomaticProfileResetterTest, InputSearchProviderManagedCorrect) {
+  SetTestingProgram(ConstructProgramToCheckSearchEngines());
+  SetTestingHashSeed(kTestHashSeed);
+
+  mock_delegate().emulated_default_search_provider_details().SetString(
+      kSearchURLAttributeKey, kTestSearchURL);
+  mock_delegate().set_emulated_default_search_provider_is_managed(true);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask = HAS_EXPECTED_DEFAULT_SEARCH_PROVIDER;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+TEST_F(AutomaticProfileResetterTest, InputSearchProvidersCorrect) {
+  SetTestingProgram(ConstructProgramToCheckSearchEngines());
+  SetTestingHashSeed(kTestHashSeed);
+
+  base::DictionaryValue* search_provider_1 = new base::DictionaryValue;
+  base::DictionaryValue* search_provider_2 = new base::DictionaryValue;
+  search_provider_1->SetString(kSearchURLAttributeKey, kTestSearchURL);
+  search_provider_2->SetString(kSearchURLAttributeKey, kTestSearchURL2);
+  mock_delegate().emulated_search_providers_details().Append(search_provider_1);
+  mock_delegate().emulated_search_providers_details().Append(search_provider_2);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask = DEFAULT_SEARCH_PROVIDER_IS_USER_CONTROLLED |
+                         HAS_EXPECTED_PREPOPULATED_SEARCH_PROVIDER_1 |
+                         HAS_EXPECTED_PREPOPULATED_SEARCH_PROVIDER_2;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
+// Please see comments above ConstructProgramToCheckLoadedModuleDigests() to
+// understand how the following tests work.
+
+TEST_F(AutomaticProfileResetterTest, InputModuleDigestsCorrect) {
+  SetTestingProgram(ConstructProgramToCheckLoadedModuleDigests());
+  SetTestingHashSeed(kTestHashSeed);
+
+  mock_delegate().emulated_loaded_module_digests().AppendString(
+      kTestModuleDigest);
+  mock_delegate().emulated_loaded_module_digests().AppendString(
+      kTestModuleDigest2);
+
+  mock_delegate().ExpectCallsToDependenciesSetUpMethods();
+  mock_delegate().ExpectCallsToGetterMethods();
+  uint32 expected_mask =
+      HAS_EXPECTED_MODULE_DIGEST_1 | HAS_EXPECTED_MODULE_DIGEST_2;
+  EXPECT_CALL(resetter(), ReportStatistics(0x00u, expected_mask));
+
+  UnleashResetterAndWait();
+}
+
 }  // namespace
diff --git a/chrome/browser/profile_resetter/jtl_foundation.cc b/chrome/browser/profile_resetter/jtl_foundation.cc
index 013cca1..0739040 100644
--- a/chrome/browser/profile_resetter/jtl_foundation.cc
+++ b/chrome/browser/profile_resetter/jtl_foundation.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 
 namespace jtl_foundation {
 
@@ -20,7 +21,7 @@
   if (cached_hashes_.find(input) == cached_hashes_.end()) {
     // Calculate value.
     unsigned char digest[kHashSizeInBytes];
-    if (!hmac_.Sign(input, digest, kHashSizeInBytes)) {
+    if (!hmac_.Sign(input, digest, arraysize(digest))) {
       NOTREACHED();
       return std::string();
     }
@@ -32,4 +33,16 @@
   return cached_hashes_[input];
 }
 
+// static
+bool Hasher::IsHash(const std::string& maybe_hash) {
+  if (maybe_hash.size() != kHashSizeInBytes)
+    return false;
+  for (std::string::const_iterator it = maybe_hash.begin();
+       it != maybe_hash.end(); ++it) {
+    if (!IsHexDigit(*it))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace jtl_foundation
diff --git a/chrome/browser/profile_resetter/jtl_foundation.h b/chrome/browser/profile_resetter/jtl_foundation.h
index 0b4953d..0ff3041 100644
--- a/chrome/browser/profile_resetter/jtl_foundation.h
+++ b/chrome/browser/profile_resetter/jtl_foundation.h
@@ -20,12 +20,12 @@
 // The execution of each sentence starts at the root of an input dictionary. The
 // operations include navigation in the JSON data structure, as well as
 // comparing the current (leaf) node to fixed values. The program also has a
-// spearate dictionary as working memory, into which it can memorize data, then
+// separate dictionary as working memory, into which it can memorize data, then
 // later recall it for comparisons.
 //
 // Example program:
 // NAVIGATE_ANY
-// NAVIGATE("bar")
+// NAVIGATE(hash("bar"))
 // COMPARE_NODE_BOOL(1)
 // STORE_BOOL(hash("found_foo"), 1)
 // STOP_EXECUTING_SENTENCE
@@ -51,22 +51,25 @@
 // of the interpreter. Next the interpreter executes STOP_EXECUTING_SENTENCE
 // which prevents the traversal from descending into the "key4" branch from the
 // NAVIGATE_ANY operation and can therefore speedup the processing.
+//
+// All node names, and node values of type string, integer and double are hashed
+// before being compared to hash values listed in |program|.
 
 // JTL byte code consists of uint8 opcodes followed by parameters. Parameters
-// are either boolean (uint8 with value \x00 or \x01), uint8s or hash strings
-// which consist of 32 bytes.
+// are either boolean (uint8 with value \x00 or \x01), uint8s, or hash strings
+// of 32 bytes.
 // The following opcodes are defined:
 enum OpCodes {
   // Continues execution with the next operation on the element of a
   // dictionary that matches the passed key parameter. If no such element
-  // exists, the command execution returns from the current node/instruction.
+  // exists, the command execution returns from the current instruction.
   // Parameters:
-  // - the hash value of a dictionary key.
+  // - a 32 byte hash of the target dictionary key.
   NAVIGATE = 0x00,
   // Continues execution with the next operation on each element of a
   // dictionary or list. If no such element exists or the current element is
   // neither a dictionary or list, the command execution returns from the
-  // current node/instruction.
+  // current instruction.
   NAVIGATE_ANY = 0x01,
   // Continues execution with the next operation on the parent node of the
   // current node. If the current node is the root of the input dictionary, the
@@ -74,15 +77,15 @@
   NAVIGATE_BACK = 0x02,
   // Stores a boolean value in the working memory.
   // Parameters:
-  // - a 32 ASCII character parameter name.
+  // - a 32 byte hash of the parameter name,
   // - the value to store (\x00 or \x01)
   STORE_BOOL = 0x10,
   // Checks whether a boolean stored in working memory matches the expected
   // value and continues execution with the next operation in case of a match.
   // Parameters:
-  // - a 32 ASCII character parameter name.
-  // - the expected value (\x00 or \x01).
-  // - the default value in case the working memory contains no stored
+  // - a 32 byte hash of the parameter name,
+  // - the expected value (\x00 or \x01),
+  // - the default value in case the working memory contains no corresponding
   //   entry (\x00 or\x01).
   COMPARE_STORED_BOOL = 0x11,
   // Same as STORE_BOOL but takes a hash instead of a boolean value as
@@ -91,27 +94,58 @@
   // Same as COMPARE_STORED_BOOL but takes a hash instead of two boolean values
   // as parameters.
   COMPARE_STORED_HASH = 0x13,
-  // Compares the current node against a boolean value and continues
-  // execution with the next operation in case of a match. If the current
-  // node does not match or is not a boolean value, the program execution
-  // returns from the current node/instruction.
+  // Stores the current node into the working memory. If the current node is not
+  // a boolean value, the program execution returns from the current
+  // instruction.
   // Parameters:
-  // - a boolen value (\x00 or \x01).
+  // - a 32 byte hash of the parameter name.
+  STORE_NODE_BOOL = 0x14,
+  // Stores the hashed value of the current node into the working memory. If
+  // the current node is not a string, integer or double, the program execution
+  // returns from the current instruction.
+  // Parameters:
+  // - a 32 byte hash of the parameter name.
+  STORE_NODE_HASH = 0x15,
+  // Compares the current node against a boolean value and continues execution
+  // with the next operation in case of a match. If the current node does not
+  // match or is not a boolean value, the program execution returns from the
+  // current instruction.
+  // Parameters:
+  // - a boolean value (\x00 or \x01).
   COMPARE_NODE_BOOL = 0x20,
-  // Compares the current node against a hash value and continues execution
-  // with the next operation in case of a match. If the current node is not
-  // a string, integer or double, or if it is either but does not match, the
-  // program execution stops for the current node.
+  // Compares the hashed value of the current node against the given hash, and
+  // continues execution with the next operation in case of a match. If the
+  // current node is not a string, integer or double, or if it is either, but
+  // its hash does not match, the program execution returns from the current
+  // instruction.
   // Parameters:
-  // - a hash string of 32 bytes.
+  // - a 32 byte hash of the expected value.
   COMPARE_NODE_HASH = 0x21,
+  // The negation of the above.
+  COMPARE_NODE_HASH_NOT = 0x22,
+  // Compares the current node against a boolean value stored in working memory,
+  // and continues with the next operation in case of a match. If the current
+  // node is not a boolean value, the working memory contains no corresponding
+  // boolean value, or if they do not match, the program execution returns from
+  // the current instruction.
+  // Parameters:
+  // - a 32 byte hash of the parameter name.
+  COMPARE_NODE_TO_STORED_BOOL = 0x23,
+  // Compares the hashed value of the current node against a hash value stored
+  // in working memory, and continues with the next operation in case of a
+  // match. If the current node is not a string, integer or double, or if the
+  // working memory contains no corresponding hash string, or if the hashes do
+  // not match, the program execution returns from the current instruction.
+  // Parameters:
+  // - a 32 byte hash of the parameter name.
+  COMPARE_NODE_TO_STORED_HASH = 0x24,
   // Stop execution in this specific sentence.
   STOP_EXECUTING_SENTENCE = 0x30,
   // Separator between sentences, starts a new sentence.
   END_OF_SENTENCE = 0x31
 };
 
-static const size_t kHashSizeInBytes = 32;
+const size_t kHashSizeInBytes = 32u;
 
 // A class that provides SHA256 hash values for strings using a fixed hash seed.
 class Hasher {
@@ -121,6 +155,8 @@
 
   std::string GetHash(const std::string& input) const;
 
+  static bool IsHash(const std::string& maybe_hash);
+
  private:
   crypto::HMAC hmac_;
   mutable std::map<std::string, std::string> cached_hashes_;
diff --git a/chrome/browser/profile_resetter/jtl_instructions.h b/chrome/browser/profile_resetter/jtl_instructions.h
index 11c3f6c..3114107 100644
--- a/chrome/browser/profile_resetter/jtl_instructions.h
+++ b/chrome/browser/profile_resetter/jtl_instructions.h
@@ -9,21 +9,26 @@
 
 // These are instructions to generate binary code for JTL programs.
 
-#define VALUE_FALSE std::string("\x00", 1)
-#define VALUE_TRUE std::string("\x01", 1)
+#define VALUE_FALSE std::string(1, '\x00')
+#define VALUE_TRUE std::string(1, '\x01')
 
-#define OP_NAVIGATE(key) std::string("\x00", 1) + key
-#define OP_NAVIGATE_ANY std::string("\x01", 1)
-#define OP_NAVIGATE_BACK std::string("\x02", 1)
-#define OP_STORE_BOOL(name, value) std::string("\x10") + name + value
+#define OP_NAVIGATE(key) std::string(1, '\x00') + key
+#define OP_NAVIGATE_ANY std::string(1, '\x01')
+#define OP_NAVIGATE_BACK std::string(1, '\x02')
+#define OP_STORE_BOOL(name, value) std::string(1, '\x10') + name + value
 #define OP_COMPARE_STORED_BOOL(name, value, default_value) \
-    std::string("\x11", 1) + name + value + default_value
-#define OP_STORE_HASH(name, value) std::string("\x12") + name + value
+    std::string(1, '\x11') + name + value + default_value
+#define OP_STORE_HASH(name, value) std::string(1, '\x12') + name + value
 #define OP_COMPARE_STORED_HASH(name, value, default_value) \
-    std::string("\x13", 1) + name + value + default_value
-#define OP_COMPARE_NODE_BOOL(value) std::string("\x20", 1) + value
-#define OP_COMPARE_NODE_HASH(value) std::string("\x21", 1) + value
-#define OP_STOP_EXECUTING_SENTENCE std::string("\x30", 1)
-#define OP_END_OF_SENTENCE std::string("\x31", 1)
+    std::string(1, '\x13') + name + value + default_value
+#define OP_STORE_NODE_BOOL(name) std::string(1, '\x14') + name
+#define OP_STORE_NODE_HASH(name) std::string(1, '\x15') + name
+#define OP_COMPARE_NODE_BOOL(value) std::string(1, '\x20') + value
+#define OP_COMPARE_NODE_HASH(value) std::string(1, '\x21') + value
+#define OP_COMPARE_NODE_HASH_NOT(value) std::string(1, '\x22') + value
+#define OP_COMPARE_NODE_TO_STORED_BOOL(name) std::string(1, '\x23') + name
+#define OP_COMPARE_NODE_TO_STORED_HASH(name) std::string(1, '\x24') + name
+#define OP_STOP_EXECUTING_SENTENCE std::string(1, '\x30')
+#define OP_END_OF_SENTENCE std::string(1, '\x31')
 
 #endif  // CHROME_BROWSER_PROFILE_RESETTER_JTL_INSTRUCTIONS_H_
diff --git a/chrome/browser/profile_resetter/jtl_interpreter.cc b/chrome/browser/profile_resetter/jtl_interpreter.cc
index df3e48a..964c76b 100644
--- a/chrome/browser/profile_resetter/jtl_interpreter.cc
+++ b/chrome/browser/profile_resetter/jtl_interpreter.cc
@@ -63,6 +63,23 @@
     return hasher_->GetHash(input);
   }
 
+  // Calculates the |hash| of a string, integer or double |value|, and returns
+  // true. Returns false otherwise.
+  bool GetValueHash(const Value& value, std::string* hash) {
+    DCHECK(hash);
+    std::string value_as_string;
+    int tmp_int = 0;
+    double tmp_double = 0.0;
+    if (value.GetAsInteger(&tmp_int))
+      value_as_string = base::IntToString(tmp_int);
+    else if (value.GetAsDouble(&tmp_double))
+      value_as_string = base::DoubleToString(tmp_double);
+    else if (!value.GetAsString(&value_as_string))
+      return false;
+    *hash = GetHash(value_as_string);
+    return true;
+  }
+
   const Value* current_node() const { return stack_.back(); }
   std::vector<const Value*>* stack() { return &stack_; }
   DictionaryValue* working_memory() { return working_memory_; }
@@ -88,7 +105,7 @@
 
 class NavigateOperation : public Operation {
  public:
-  explicit NavigateOperation(const std::string hashed_key)
+  explicit NavigateOperation(const std::string& hashed_key)
       : hashed_key_(hashed_key) {}
   virtual ~NavigateOperation() {}
   virtual bool Execute(ExecutionContext* context) OVERRIDE {
@@ -168,7 +185,7 @@
 
 class StoreValue : public Operation {
  public:
-  StoreValue(const std::string hashed_name, scoped_ptr<Value> value)
+  StoreValue(const std::string& hashed_name, scoped_ptr<Value> value)
       : hashed_name_(hashed_name),
         value_(value.Pass()) {
     DCHECK(IsStringUTF8(hashed_name));
@@ -188,7 +205,7 @@
 
 class CompareStoredValue : public Operation {
  public:
-  CompareStoredValue(const std::string hashed_name,
+  CompareStoredValue(const std::string& hashed_name,
                      scoped_ptr<Value> value,
                      scoped_ptr<Value> default_value)
       : hashed_name_(hashed_name),
@@ -215,6 +232,35 @@
   DISALLOW_COPY_AND_ASSIGN(CompareStoredValue);
 };
 
+template<bool ExpectedTypeIsBooleanNotHashable>
+class StoreNodeValue : public Operation {
+ public:
+  explicit StoreNodeValue(const std::string& hashed_name)
+      : hashed_name_(hashed_name) {
+    DCHECK(IsStringUTF8(hashed_name));
+  }
+  virtual ~StoreNodeValue() {}
+  virtual bool Execute(ExecutionContext* context) OVERRIDE {
+    scoped_ptr<base::Value> value;
+    if (ExpectedTypeIsBooleanNotHashable) {
+      if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN))
+        return true;
+      value.reset(context->current_node()->DeepCopy());
+    } else {
+      std::string hash;
+      if (!context->GetValueHash(*context->current_node(), &hash))
+        return true;
+      value.reset(new base::StringValue(hash));
+    }
+    context->working_memory()->Set(hashed_name_, value.release());
+    return context->ContinueExecution();
+  }
+
+ private:
+  std::string hashed_name_;
+  DISALLOW_COPY_AND_ASSIGN(StoreNodeValue);
+};
+
 class CompareNodeBool : public Operation {
  public:
   explicit CompareNodeBool(bool value) : value_(value) {}
@@ -239,19 +285,9 @@
       : hashed_value_(hashed_value) {}
   virtual ~CompareNodeHash() {}
   virtual bool Execute(ExecutionContext* context) OVERRIDE {
-    std::string actual_value;
-    int tmp_int = 0;
-    double tmp_double = 0.0;
-    if (context->current_node()->GetAsInteger(&tmp_int)) {
-      actual_value = base::IntToString(tmp_int);
-    } else if (context->current_node()->GetAsDouble(&tmp_double)) {
-      actual_value = base::DoubleToString(tmp_double);
-    } else {
-      if (!context->current_node()->GetAsString(&actual_value))
-        return true;
-    }
-    actual_value = context->GetHash(actual_value);
-    if (actual_value != hashed_value_)
+    std::string actual_hash;
+    if (!context->GetValueHash(*context->current_node(), &actual_hash) ||
+        actual_hash != hashed_value_)
       return true;
     return context->ContinueExecution();
   }
@@ -261,6 +297,54 @@
   DISALLOW_COPY_AND_ASSIGN(CompareNodeHash);
 };
 
+class CompareNodeHashNot : public Operation {
+ public:
+  explicit CompareNodeHashNot(const std::string& hashed_value)
+      : hashed_value_(hashed_value) {}
+  virtual ~CompareNodeHashNot() {}
+  virtual bool Execute(ExecutionContext* context) OVERRIDE {
+    std::string actual_hash;
+    if (context->GetValueHash(*context->current_node(), &actual_hash) &&
+        actual_hash == hashed_value_)
+      return true;
+    return context->ContinueExecution();
+  }
+
+ private:
+  std::string hashed_value_;
+  DISALLOW_COPY_AND_ASSIGN(CompareNodeHashNot);
+};
+
+template<bool ExpectedTypeIsBooleanNotHashable>
+class CompareNodeToStored : public Operation {
+ public:
+  explicit CompareNodeToStored(const std::string& hashed_name)
+      : hashed_name_(hashed_name) {}
+  virtual ~CompareNodeToStored() {}
+  virtual bool Execute(ExecutionContext* context) OVERRIDE {
+    const Value* stored_value = NULL;
+    if (!context->working_memory()->Get(hashed_name_, &stored_value))
+      return true;
+    if (ExpectedTypeIsBooleanNotHashable) {
+      if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN) ||
+          !context->current_node()->Equals(stored_value))
+        return true;
+    } else {
+      std::string actual_hash;
+      std::string stored_hash;
+      if (!context->GetValueHash(*context->current_node(), &actual_hash) ||
+          !stored_value->GetAsString(&stored_hash) ||
+          actual_hash != stored_hash)
+        return true;
+    }
+    return context->ContinueExecution();
+  }
+
+ private:
+  std::string hashed_name_;
+  DISALLOW_COPY_AND_ASSIGN(CompareNodeToStored);
+};
+
 class StopExecutingSentenceOperation : public Operation {
  public:
   StopExecutingSentenceOperation() {}
@@ -356,6 +440,20 @@
               scoped_ptr<Value>(new base::StringValue(hashed_default_value))));
           break;
         }
+        case jtl_foundation::STORE_NODE_BOOL: {
+          std::string hashed_name;
+          if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name))
+            return false;
+          operators.push_back(new StoreNodeValue<true>(hashed_name));
+          break;
+        }
+        case jtl_foundation::STORE_NODE_HASH: {
+          std::string hashed_name;
+          if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name))
+            return false;
+          operators.push_back(new StoreNodeValue<false>(hashed_name));
+          break;
+        }
         case jtl_foundation::COMPARE_NODE_BOOL: {
           bool value = false;
           if (!ReadBool(&value))
@@ -370,6 +468,27 @@
           operators.push_back(new CompareNodeHash(hashed_value));
           break;
         }
+        case jtl_foundation::COMPARE_NODE_HASH_NOT: {
+          std::string hashed_value;
+          if (!ReadHash(&hashed_value))
+            return false;
+          operators.push_back(new CompareNodeHashNot(hashed_value));
+          break;
+        }
+        case jtl_foundation::COMPARE_NODE_TO_STORED_BOOL: {
+          std::string hashed_name;
+          if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name))
+            return false;
+          operators.push_back(new CompareNodeToStored<true>(hashed_name));
+          break;
+        }
+        case jtl_foundation::COMPARE_NODE_TO_STORED_HASH: {
+          std::string hashed_name;
+          if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name))
+            return false;
+          operators.push_back(new CompareNodeToStored<false>(hashed_name));
+          break;
+        }
         case jtl_foundation::STOP_EXECUTING_SENTENCE:
           operators.push_back(new StopExecutingSentenceOperation);
           break;
@@ -403,15 +522,12 @@
 
   bool ReadHash(std::string* out) {
     if (next_instruction_index_ + jtl_foundation::kHashSizeInBytes >
-        program_.size()) {
+        program_.size())
       return false;
-    }
-    char buffer[jtl_foundation::kHashSizeInBytes];
-    for (size_t i = 0; i < arraysize(buffer); ++i) {
-      buffer[i] = program_[next_instruction_index_];
-      ++next_instruction_index_;
-    }
-    *out = std::string(buffer, arraysize(buffer));
+    *out = program_.substr(next_instruction_index_,
+                           jtl_foundation::kHashSizeInBytes);
+    next_instruction_index_ += jtl_foundation::kHashSizeInBytes;
+    DCHECK(jtl_foundation::Hasher::IsHash(*out));
     return true;
   }
 
diff --git a/chrome/browser/profile_resetter/jtl_interpreter_unittest.cc b/chrome/browser/profile_resetter/jtl_interpreter_unittest.cc
index b4fb448..26f69a6 100644
--- a/chrome/browser/profile_resetter/jtl_interpreter_unittest.cc
+++ b/chrome/browser/profile_resetter/jtl_interpreter_unittest.cc
@@ -196,7 +196,7 @@
   EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
 }
 
-TEST(JtlInterpreter, CompareBoolMatch) {
+TEST(JtlInterpreter, CompareBool) {
   struct TestCase {
     std::string expected_value;
     const char* json;
@@ -204,6 +204,7 @@
   } cases[] = {
     { VALUE_TRUE, "{ 'KEY_HASH_1': true }", true },
     { VALUE_FALSE, "{ 'KEY_HASH_1': false }", true },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': false }", false },
     { VALUE_TRUE, "{ 'KEY_HASH_1': 'abc' }", false },
     { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false },
     { VALUE_TRUE, "{ 'KEY_HASH_1': 1.2 }", false },
@@ -274,6 +275,212 @@
       EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1));
     }
   }
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Negated, Iteration " << i);
+    INIT_INTERPRETER(
+        OP_NAVIGATE(KEY_HASH_1) +
+        OP_COMPARE_NODE_HASH_NOT(cases[i].expected_value) +
+        OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE),
+        cases[i].json);
+    EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
+    if (!cases[i].expected_success) {
+      base::ExpectDictBooleanValue(
+          true, *interpreter.working_memory(), VAR_HASH_1);
+    } else {
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1));
+    }
+  }
+}
+
+TEST(JtlInterpreter, StoreNodeBool) {
+  struct TestCase {
+    bool expected_value;
+    const char* json;
+    bool expected_success;
+  } cases[] = {
+    { true, "{ 'KEY_HASH_1': true }", true },
+    { false, "{ 'KEY_HASH_1': false }", true },
+    { false, "{ 'KEY_HASH_1': 'abc' }", false },
+    { false, "{ 'KEY_HASH_1': 1 }", false },
+    { false, "{ 'KEY_HASH_1': 1.2 }", false },
+    { false, "{ 'KEY_HASH_1': [1] }", false },
+    { false, "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Iteration " << i);
+    INIT_INTERPRETER(
+        OP_NAVIGATE(KEY_HASH_1) +
+        OP_STORE_NODE_BOOL(VAR_HASH_1) +
+        OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
+        cases[i].json);
+    EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
+    if (cases[i].expected_success) {
+      base::ExpectDictBooleanValue(
+          cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1);
+      base::ExpectDictBooleanValue(
+          true, *interpreter.working_memory(), VAR_HASH_2);
+    } else {
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1));
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
+    }
+  }
+}
+
+TEST(JtlInterpreter, CompareNodeToStoredBool) {
+  struct TestCase {
+    std::string stored_value;
+    const char* json;
+    bool expected_success;
+  } cases[] = {
+    { VALUE_TRUE, "{ 'KEY_HASH_1': true }", true },
+    { VALUE_FALSE, "{ 'KEY_HASH_1': false }", true },
+    { VALUE_FALSE, "{ 'KEY_HASH_1': true }", false },
+    { std::string(), "{ 'KEY_HASH_1': true }", false },
+
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': 1 }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", false },
+
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': true }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': true }", false },
+
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 1.2 }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': [1] }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Iteration " << i);
+    std::string store_op;
+    if (cases[i].stored_value == VALUE_TRUE ||
+        cases[i].stored_value == VALUE_FALSE)
+      store_op = OP_STORE_BOOL(VAR_HASH_1, cases[i].stored_value);
+    else if (!cases[i].stored_value.empty())
+      store_op = OP_STORE_HASH(VAR_HASH_1, cases[i].stored_value);
+    INIT_INTERPRETER(
+        store_op +
+        OP_NAVIGATE(KEY_HASH_1) +
+        OP_COMPARE_NODE_TO_STORED_BOOL(VAR_HASH_1) +
+        OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
+        cases[i].json);
+    EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
+    if (cases[i].expected_success) {
+      base::ExpectDictBooleanValue(
+          true, *interpreter.working_memory(), VAR_HASH_2);
+    } else {
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
+    }
+  }
+}
+
+TEST(JtlInterpreter, StoreNodeHash) {
+  struct TestCase {
+    std::string expected_value;
+    const char* json;
+    bool expected_success;
+  } cases[] = {
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", true },
+    { VALUE_HASH_2, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", true },
+    { GetHash("1"), "{ 'KEY_HASH_1': 1 }", true },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", true },
+    { std::string(), "{ 'KEY_HASH_1': true }", false },
+    { std::string(), "{ 'KEY_HASH_1': [1] }", false },
+    { std::string(), "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Iteration " << i);
+    INIT_INTERPRETER(
+        OP_NAVIGATE(KEY_HASH_1) +
+        OP_STORE_NODE_HASH(VAR_HASH_1) +
+        OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
+        cases[i].json);
+    EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
+    if (cases[i].expected_success) {
+      base::ExpectDictStringValue(
+          cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1);
+      base::ExpectDictBooleanValue(
+          true, *interpreter.working_memory(), VAR_HASH_2);
+    } else {
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1));
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
+    }
+  }
+}
+
+TEST(JtlInterpreter, CompareNodeToStoredHash) {
+  struct TestCase {
+    std::string stored_value;
+    const char* json;
+    bool expected_success;
+  } cases[] = {
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", true },
+    { VALUE_HASH_2, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", true },
+    { std::string(), "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 1 }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': 1.1 }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': [1] }", false },
+    { VALUE_HASH_1, "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", true },
+    { GetHash("1.3"), "{ 'KEY_HASH_1': 1.3 }", true },
+    { std::string(), "{ 'KEY_HASH_1': 1.2 }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': true }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 1 }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': 1.3 }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': [1] }", false },
+    { GetHash("1.2"), "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+
+    { GetHash("1"), "{ 'KEY_HASH_1': 1 }", true },
+    { GetHash("2"), "{ 'KEY_HASH_1': 2 }", true },
+    { std::string(), "{ 'KEY_HASH_1': 2 }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': true }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': 2 }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': 1.1 }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': [1] }", false },
+    { GetHash("1"), "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': 1.3 }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': [1] }", false },
+    { VALUE_TRUE, "{ 'KEY_HASH_1': {'a': 'b'} }", false },
+
+    { VALUE_TRUE, "{ 'KEY_HASH_1': true }", false },
+    { VALUE_FALSE, "{ 'KEY_HASH_1': false }", false },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Iteration " << i);
+    std::string store_op;
+    if (cases[i].stored_value == VALUE_TRUE ||
+        cases[i].stored_value == VALUE_FALSE)
+      store_op = OP_STORE_BOOL(VAR_HASH_1, cases[i].stored_value);
+    else if (!cases[i].stored_value.empty())
+      store_op = OP_STORE_HASH(VAR_HASH_1, cases[i].stored_value);
+    INIT_INTERPRETER(
+        store_op +
+        OP_NAVIGATE(KEY_HASH_1) +
+        OP_COMPARE_NODE_TO_STORED_HASH(VAR_HASH_1) +
+        OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
+        cases[i].json);
+    EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
+    if (cases[i].expected_success) {
+      base::ExpectDictBooleanValue(
+          true, *interpreter.working_memory(), VAR_HASH_2);
+    } else {
+      EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
+    }
+  }
 }
 
 TEST(JtlInterpreter, Stop) {
@@ -327,10 +534,18 @@
     OP_COMPARE_STORED_BOOL(VAR_HASH_1, invalid_bool, VALUE_TRUE),
     OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, invalid_bool),
     OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, missing_bool),
+    OP_STORE_NODE_BOOL(missing_hash),
+    OP_STORE_NODE_BOOL(invalid_hash),
+    OP_STORE_NODE_HASH(missing_hash),
+    OP_STORE_NODE_HASH(invalid_hash),
     OP_COMPARE_NODE_BOOL(missing_bool),
     OP_COMPARE_NODE_BOOL(invalid_bool),
     OP_COMPARE_NODE_HASH(missing_hash),
     OP_COMPARE_NODE_HASH(invalid_hash),
+    OP_COMPARE_NODE_TO_STORED_BOOL(missing_hash),
+    OP_COMPARE_NODE_TO_STORED_BOOL(invalid_hash),
+    OP_COMPARE_NODE_TO_STORED_HASH(missing_hash),
+    OP_COMPARE_NODE_TO_STORED_HASH(invalid_hash),
     invalid_operation,
   };
   for (size_t i = 0; i < arraysize(programs); ++i) {
diff --git a/chrome/browser/profiles/OWNERS b/chrome/browser/profiles/OWNERS
index cdccba3..8f1b0cc 100644
--- a/chrome/browser/profiles/OWNERS
+++ b/chrome/browser/profiles/OWNERS
@@ -6,3 +6,6 @@
 willchan@chromium.org
 mmenke@chromium.org
 ajwong@chromium.org
+
+per-file incognito_mode_policy_handler*=dconnelly@chromium.org
+per-file incognito_mode_policy_handler*=joaodasilva@chromium.org
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc
index 5fe2b72..a32bf72 100644
--- a/chrome/browser/profiles/avatar_menu.cc
+++ b/chrome/browser/profiles/avatar_menu.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/profiles/avatar_menu.h"
 
+#include "ash/ash_switches.h"
 #include "base/bind.h"
 #include "base/i18n/case_conversion.h"
 #include "base/metrics/field_trial.h"
@@ -109,9 +110,10 @@
   // implementations.
   if (profiles::IsMultipleProfilesEnabled()) {
 #if defined(OS_CHROMEOS)
-    // On ChromeOS the menu will be always visible when it is possible to have
-    // two users logged in at the same time.
-    return ChromeShellDelegate::instance() &&
+    // On ChromeOS the menu will be shown in M-31 mode when it is possible to
+    // have two users logged in at the same time.
+    return ash::switches::UseFullMultiProfileMode() &&
+           ChromeShellDelegate::instance() &&
            ChromeShellDelegate::instance()->IsMultiProfilesEnabled();
 #else
     return profiles::IsNewProfileManagementEnabled() ||
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index b19122c..80b972a 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
 
+#include "apps/app_keep_alive_service_factory.h"
 #include "apps/app_load_service_factory.h"
 #include "apps/app_restore_service_factory.h"
 #include "apps/shell_window_geometry_cache.h"
@@ -85,6 +86,7 @@
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
 #include "chrome/browser/extensions/api/serial/serial_connection.h"
 #include "chrome/browser/extensions/api/sessions/sessions_api.h"
+#include "chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h"
 #include "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager.h"
 #include "chrome/browser/extensions/api/socket/socket.h"
 #include "chrome/browser/extensions/api/socket/tcp_socket.h"
@@ -98,6 +100,7 @@
 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
 #include "chrome/browser/extensions/api/usb/usb_device_resource.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
+#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h"
 #include "chrome/browser/extensions/extension_prefs_factory.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
@@ -214,6 +217,7 @@
   DownloadServiceFactory::GetInstance();
 #if defined(ENABLE_EXTENSIONS)
   AppShortcutManagerFactory::GetInstance();
+  apps::AppKeepAliveServiceFactory::GetInstance();
   apps::AppLoadServiceFactory::GetInstance();
   apps::AppRestoreServiceFactory::GetInstance();
   apps::ShellWindowGeometryCache::Factory::GetInstance();
@@ -275,6 +279,7 @@
   extensions::ProcessesAPI::GetFactoryInstance();
   extensions::PushMessagingAPI::GetFactoryInstance();
   extensions::SessionsAPI::GetFactoryInstance();
+  extensions::SettingsOverridesAPI::GetFactoryInstance();
   extensions::SignedInDevicesManager::GetFactoryInstance();
 #if defined(ENABLE_SPELLCHECK)
   extensions::SpellcheckAPI::GetFactoryInstance();
@@ -286,6 +291,7 @@
   extensions::TabsWindowsAPI::GetFactoryInstance();
   extensions::TtsAPI::GetFactoryInstance();
   extensions::WebNavigationAPI::GetFactoryInstance();
+  extensions::WebrtcAudioPrivateEventService::GetFactoryInstance();
 #endif  // defined(ENABLE_EXTENSIONS)
   FaviconServiceFactory::GetInstance();
 #if defined(OS_CHROMEOS) && defined(FILE_MANAGER_EXTENSION)
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index f88f33d..7901303 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -67,9 +67,9 @@
   if (!profile->GetOriginalProfile()->IsSyncAccessible())
     return false;
 
-  // To enable this feature for testing pass "--gaia-profile-info".
+  // To enable this feature for testing pass "--google-profile-info".
   if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kGaiaProfileInfo)) {
+      switches::kGoogleProfileInfo)) {
     return true;
   }
 
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler.cc b/chrome/browser/profiles/incognito_mode_policy_handler.cc
new file mode 100644
index 0000000..94f1908
--- /dev/null
+++ b/chrome/browser/profiles/incognito_mode_policy_handler.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 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/profiles/incognito_mode_policy_handler.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+IncognitoModePolicyHandler::IncognitoModePolicyHandler() {}
+
+IncognitoModePolicyHandler::~IncognitoModePolicyHandler() {}
+
+bool IncognitoModePolicyHandler::CheckPolicySettings(const PolicyMap& policies,
+                                                     PolicyErrorMap* errors) {
+  int int_value = IncognitoModePrefs::ENABLED;
+  const base::Value* availability =
+      policies.GetValue(key::kIncognitoModeAvailability);
+
+  if (availability) {
+    if (availability->GetAsInteger(&int_value)) {
+      IncognitoModePrefs::Availability availability_enum_value;
+      if (!IncognitoModePrefs::IntToAvailability(int_value,
+                                                 &availability_enum_value)) {
+        errors->AddError(key::kIncognitoModeAvailability,
+                         IDS_POLICY_OUT_OF_RANGE_ERROR,
+                         base::IntToString(int_value));
+        return false;
+      }
+    } else {
+      errors->AddError(key::kIncognitoModeAvailability,
+                       IDS_POLICY_TYPE_ERROR,
+                       ValueTypeToString(base::Value::TYPE_INTEGER));
+      return false;
+    }
+  } else {
+    const base::Value* deprecated_enabled =
+        policies.GetValue(key::kIncognitoEnabled);
+    if (deprecated_enabled &&
+        !deprecated_enabled->IsType(base::Value::TYPE_BOOLEAN)) {
+      errors->AddError(key::kIncognitoEnabled,
+                       IDS_POLICY_TYPE_ERROR,
+                       ValueTypeToString(base::Value::TYPE_BOOLEAN));
+      return false;
+    }
+  }
+  return true;
+}
+
+void IncognitoModePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+                                                     PrefValueMap* prefs) {
+  const base::Value* availability =
+      policies.GetValue(key::kIncognitoModeAvailability);
+  const base::Value* deprecated_enabled =
+      policies.GetValue(key::kIncognitoEnabled);
+  if (availability) {
+    int int_value = IncognitoModePrefs::ENABLED;
+    IncognitoModePrefs::Availability availability_enum_value;
+    if (availability->GetAsInteger(&int_value) &&
+        IncognitoModePrefs::IntToAvailability(int_value,
+                                              &availability_enum_value)) {
+      prefs->SetValue(prefs::kIncognitoModeAvailability,
+                      base::Value::CreateIntegerValue(availability_enum_value));
+    } else {
+      NOTREACHED();
+    }
+  } else if (deprecated_enabled) {
+    // If kIncognitoModeAvailability is not specified, check the obsolete
+    // kIncognitoEnabled.
+    bool enabled = true;
+    if (deprecated_enabled->GetAsBoolean(&enabled)) {
+      prefs->SetInteger(
+          prefs::kIncognitoModeAvailability,
+          enabled ? IncognitoModePrefs::ENABLED : IncognitoModePrefs::DISABLED);
+    } else {
+      NOTREACHED();
+    }
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler.h b/chrome/browser/profiles/incognito_mode_policy_handler.h
new file mode 100644
index 0000000..96b6c4f
--- /dev/null
+++ b/chrome/browser/profiles/incognito_mode_policy_handler.h
@@ -0,0 +1,39 @@
+// Copyright 2013 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_PROFILES_INCOGNITO_MODE_POLICY_HANDLER_H_
+#define CHROME_BROWSER_PROFILES_INCOGNITO_MODE_POLICY_HANDLER_H_
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace base {
+class Value;
+}
+
+namespace policy {
+
+class PolicyErrorMap;
+class PolicyMap;
+
+// ConfigurationPolicyHandler for the incognito mode policies.
+class IncognitoModePolicyHandler : public ConfigurationPolicyHandler {
+ public:
+  IncognitoModePolicyHandler();
+  virtual ~IncognitoModePolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual bool CheckPolicySettings(const PolicyMap& policies,
+                                   PolicyErrorMap* errors) OVERRIDE;
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IncognitoModePolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_PROFILES_INCOGNITO_MODE_POLICY_HANDLER_H_
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc b/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc
new file mode 100644
index 0000000..30869cc
--- /dev/null
+++ b/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2013 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/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
+#include "chrome/browser/profiles/incognito_mode_policy_handler.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+// Tests Incognito mode availability preference setting.
+class IncognitoModePolicyHandlerTest
+    : public ConfigurationPolicyPrefStoreTest {
+ public:
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+          new IncognitoModePolicyHandler));
+  }
+ protected:
+  static const int kIncognitoModeAvailabilityNotSet = -1;
+
+  enum ObsoleteIncognitoEnabledValue {
+    INCOGNITO_ENABLED_UNKNOWN,
+    INCOGNITO_ENABLED_TRUE,
+    INCOGNITO_ENABLED_FALSE
+  };
+
+  void SetPolicies(ObsoleteIncognitoEnabledValue incognito_enabled,
+                   int availability) {
+    PolicyMap policy;
+    if (incognito_enabled != INCOGNITO_ENABLED_UNKNOWN) {
+      policy.Set(key::kIncognitoEnabled, POLICY_LEVEL_MANDATORY,
+                 POLICY_SCOPE_USER,
+                 base::Value::CreateBooleanValue(
+                     incognito_enabled == INCOGNITO_ENABLED_TRUE),
+                 NULL);
+    }
+    if (availability >= 0) {
+      policy.Set(key::kIncognitoModeAvailability, POLICY_LEVEL_MANDATORY,
+                 POLICY_SCOPE_USER,
+                 base::Value::CreateIntegerValue(availability),
+                 NULL);
+    }
+    UpdateProviderPolicy(policy);
+  }
+
+  void VerifyValues(IncognitoModePrefs::Availability availability) {
+    const base::Value* value = NULL;
+    EXPECT_TRUE(store_->GetValue(prefs::kIncognitoModeAvailability, &value));
+    EXPECT_TRUE(base::FundamentalValue(availability).Equals(value));
+  }
+};
+
+// The following testcases verify that if the obsolete IncognitoEnabled
+// policy is not set, the IncognitoModeAvailability values should be copied
+// from IncognitoModeAvailability policy to pref "as is".
+TEST_F(IncognitoModePolicyHandlerTest,
+       NoObsoletePolicyAndIncognitoEnabled) {
+  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::ENABLED);
+  VerifyValues(IncognitoModePrefs::ENABLED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       NoObsoletePolicyAndIncognitoDisabled) {
+  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::DISABLED);
+  VerifyValues(IncognitoModePrefs::DISABLED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       NoObsoletePolicyAndIncognitoForced) {
+  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, IncognitoModePrefs::FORCED);
+  VerifyValues(IncognitoModePrefs::FORCED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       NoObsoletePolicyAndNoIncognitoAvailability) {
+  SetPolicies(INCOGNITO_ENABLED_UNKNOWN, kIncognitoModeAvailabilityNotSet);
+  const base::Value* value = NULL;
+  EXPECT_FALSE(store_->GetValue(prefs::kIncognitoModeAvailability, &value));
+}
+
+// Checks that if the obsolete IncognitoEnabled policy is set, if sets
+// the IncognitoModeAvailability preference only in case
+// the IncognitoModeAvailability policy is not specified.
+TEST_F(IncognitoModePolicyHandlerTest,
+       ObsoletePolicyDoesNotAffectAvailabilityEnabled) {
+  SetPolicies(INCOGNITO_ENABLED_FALSE, IncognitoModePrefs::ENABLED);
+  VerifyValues(IncognitoModePrefs::ENABLED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       ObsoletePolicyDoesNotAffectAvailabilityForced) {
+  SetPolicies(INCOGNITO_ENABLED_TRUE, IncognitoModePrefs::FORCED);
+  VerifyValues(IncognitoModePrefs::FORCED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       ObsoletePolicySetsPreferenceToEnabled) {
+  SetPolicies(INCOGNITO_ENABLED_TRUE, kIncognitoModeAvailabilityNotSet);
+  VerifyValues(IncognitoModePrefs::ENABLED);
+}
+
+TEST_F(IncognitoModePolicyHandlerTest,
+       ObsoletePolicySetsPreferenceToDisabled) {
+  SetPolicies(INCOGNITO_ENABLED_FALSE, kIncognitoModeAvailabilityNotSet);
+  VerifyValues(IncognitoModePrefs::DISABLED);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index af3c60c..ee7661d 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -57,8 +57,8 @@
 #include "webkit/browser/database/database_tracker.h"
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prefs/proxy_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
 #if defined(OS_CHROMEOS)
@@ -288,16 +288,29 @@
 void OffTheRecordProfileImpl::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   ChromeMIDIPermissionContext* context =
       ChromeMIDIPermissionContextFactory::GetForProfile(this);
   context->RequestMIDISysExPermission(render_process_id,
                                       render_view_id,
+                                      bridge_id,
                                       requesting_frame,
                                       callback);
 }
 
+void OffTheRecordProfileImpl::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+  ChromeMIDIPermissionContext* context =
+      ChromeMIDIPermissionContextFactory::GetForProfile(this);
+  context->CancelMIDISysExPermissionRequest(
+      render_process_id, render_view_id, bridge_id, requesting_frame);
+}
+
 net::URLRequestContextGetter*
     OffTheRecordProfileImpl::GetRequestContextForExtensions() {
   return io_data_.GetExtensionsRequestContextGetter().get();
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index c4b793e..57c127b 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -101,8 +101,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+      int render_process_id,
+      int render_view_id,
+      int bridge_id,
+      const GURL& requesting_frame) OVERRIDE;
   virtual content::ResourceContext* GetResourceContext() OVERRIDE;
   virtual content::GeolocationPermissionContext*
       GetGeolocationPermissionContext() OVERRIDE;
diff --git a/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc b/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc
index 1b40fcf..2f90e07 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc
@@ -6,10 +6,10 @@
 
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/run_loop.h"
 #include "chrome/browser/net/ssl_config_service_manager.h"
 #include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 063c13e..affbc3a 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/chrome_version_service.h"
 #include "chrome/browser/profiles/profile_impl.h"
+#include "chrome/browser/profiles/startup_task_runner_service.h"
+#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
@@ -73,6 +75,8 @@
       temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
   ASSERT_TRUE(profile.get());
   CheckChromeVersion(profile.get(), true);
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 }
 
 // Test OnProfileCreate is called with is_new_profile set to false when
@@ -91,6 +95,8 @@
       temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
   ASSERT_TRUE(profile.get());
   CheckChromeVersion(profile.get(), false);
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 }
 
 // Test OnProfileCreate is called with is_new_profile set to true when
@@ -107,6 +113,8 @@
   scoped_ptr<Profile> profile(Profile::CreateProfile(
       temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
   ASSERT_TRUE(profile.get());
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 
   // Wait for the profile to be created.
   content::WindowedNotificationObserver observer(
@@ -130,6 +138,8 @@
   scoped_ptr<Profile> profile(Profile::CreateProfile(
       temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
   ASSERT_TRUE(profile.get());
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 
   // Wait for the profile to be created.
   content::WindowedNotificationObserver observer(
@@ -154,6 +164,8 @@
   scoped_ptr<Profile> profile(Profile::CreateProfile(
       temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
   ASSERT_TRUE(profile.get());
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 
   // Wait for the profile to be created.
   content::WindowedNotificationObserver observer(
@@ -182,6 +194,8 @@
   scoped_ptr<Profile> profile(Profile::CreateProfile(
       temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
   ASSERT_TRUE(profile.get());
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 
   // Delete the Profile instance and run pending tasks (this includes the task
   // for README creation).
@@ -208,6 +222,8 @@
   scoped_ptr<Profile> profile(Profile::CreateProfile(
       temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
   ASSERT_TRUE(profile.get());
+  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
+              StartDeferredTaskRunners();
 
   PrefService* prefs = profile->GetPrefs();
   // The initial state is crashed; store for later reference.
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 9c9c1de..359ce71 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -15,6 +15,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/prefs/json_pref_store.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -60,7 +61,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/bookmark_model_loaded_observer.h"
 #include "chrome/browser/profiles/chrome_version_service.h"
@@ -450,7 +450,7 @@
         profile_policy_connector_->policy_service(),
         managed_user_settings,
         new ExtensionPrefStore(
-            ExtensionPrefValueMapFactory::GetForProfile(this), false),
+            ExtensionPrefValueMapFactory::GetForBrowserContext(this), false),
         pref_registry_,
         async_prefs));
     // Register on BrowserContext.
@@ -672,7 +672,7 @@
     ProfileDestroyer::DestroyOffTheRecordProfileNow(
         off_the_record_profile_.get());
   } else {
-    ExtensionPrefValueMapFactory::GetForProfile(this)->
+    ExtensionPrefValueMapFactory::GetForBrowserContext(this)->
         ClearAllIncognitoSessionOnlyPreferences();
   }
 
@@ -725,7 +725,7 @@
 
 void ProfileImpl::DestroyOffTheRecordProfile() {
   off_the_record_profile_.reset();
-  ExtensionPrefValueMapFactory::GetForProfile(this)->
+  ExtensionPrefValueMapFactory::GetForBrowserContext(this)->
       ClearAllIncognitoSessionOnlyPreferences();
 }
 
@@ -854,7 +854,7 @@
     // stores a reference so that we do not leak memory here.
     otr_prefs_.reset(prefs_->CreateIncognitoPrefService(
         new ExtensionPrefStore(
-            ExtensionPrefValueMapFactory::GetForProfile(this), true)));
+            ExtensionPrefValueMapFactory::GetForBrowserContext(this), true)));
   }
   return otr_prefs_.get();
 }
@@ -911,16 +911,29 @@
 void ProfileImpl::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   ChromeMIDIPermissionContext* context =
       ChromeMIDIPermissionContextFactory::GetForProfile(this);
   context->RequestMIDISysExPermission(render_process_id,
                                       render_view_id,
+                                      bridge_id,
                                       requesting_frame,
                                       callback);
 }
 
+void ProfileImpl::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+  ChromeMIDIPermissionContext* context =
+      ChromeMIDIPermissionContextFactory::GetForProfile(this);
+  context->CancelMIDISysExPermissionRequest(
+      render_process_id, render_view_id, bridge_id, requesting_frame);
+}
+
 content::ResourceContext* ProfileImpl::GetResourceContext() {
   return io_data_.GetResourceContext();
 }
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 1401d1b..1ac5746 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -76,8 +76,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+      int render_process_id,
+      int render_view_id,
+      int bridge_id,
+      const GURL& requesting_frame) OVERRIDE;
   virtual content::ResourceContext* GetResourceContext() OVERRIDE;
   virtual content::GeolocationPermissionContext*
       GetGeolocationPermissionContext() OVERRIDE;
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 4a5958b..cf82956 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -45,8 +45,8 @@
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "webkit/browser/quota/special_storage_policy.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/app/android/chrome_data_reduction_proxy_android.h"
+#if defined(OS_ANDROID) || defined(OS_IOS)
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
 #endif
 
 namespace {
@@ -63,11 +63,19 @@
   }
   const std::string experiment_name =
       base::FieldTrialList::FindFullName("SimpleCacheTrial");
+#if defined(OS_ANDROID)
+  if (experiment_name == "ExperimentNo" ||
+      experiment_name == "ExperimentControl") {
+    return net::CACHE_BACKEND_BLOCKFILE;
+  }
+  return net::CACHE_BACKEND_SIMPLE;
+#else
   if (experiment_name == "ExperimentYes" ||
       experiment_name == "ExperimentYes2") {
     return net::CACHE_BACKEND_SIMPLE;
   }
   return net::CACHE_BACKEND_BLOCKFILE;
+#endif
 }
 
 }  // namespace
@@ -432,8 +440,9 @@
       network_session_params, main_backend);
   main_cache->InitializeInfiniteCache(lazy_params_->infinite_cache_path);
 
-#if defined(OS_ANDROID)
-  ChromeDataReductionProxyAndroid::Init(main_cache->GetSession());
+#if defined(OS_ANDROID) || defined(OS_IOS)
+  DataReductionProxySettings::InitDataReductionProxySession(
+      main_cache->GetSession());
 #endif
 
   if (record_mode || playback_mode) {
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index f57205e..ae5703c 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -21,7 +22,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 99f3793..ff66f91 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -71,6 +71,8 @@
 #include "net/proxy/proxy_config_service_fixed.h"
 #include "net/proxy/proxy_script_fetcher_impl.h"
 #include "net/proxy/proxy_service.h"
+#include "net/ssl/client_cert_store.h"
+#include "net/ssl/client_cert_store_impl.h"
 #include "net/ssl/server_bound_cert_service.h"
 #include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/file_protocol_handler.h"
@@ -710,6 +712,18 @@
   return request_context_;
 }
 
+scoped_ptr<net::ClientCertStore>
+ProfileIOData::ResourceContext::CreateClientCertStore() {
+#if !defined(USE_OPENSSL)
+  return scoped_ptr<net::ClientCertStore>(new net::ClientCertStoreImpl());
+#else
+  // OpenSSL does not use the ClientCertStore infrastructure. On Android client
+  // cert matching is done by the OS as part of the call to show the cert
+  // selection dialog.
+  return scoped_ptr<net::ClientCertStore>();
+#endif
+}
+
 bool ProfileIOData::ResourceContext::AllowMicAccess(const GURL& origin) {
   return AllowContentAccess(origin, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
 }
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 724a728..fcdf2a9 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -361,6 +361,7 @@
     // ResourceContext implementation:
     virtual net::HostResolver* GetHostResolver() OVERRIDE;
     virtual net::URLRequestContext* GetRequestContext() OVERRIDE;
+    virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore() OVERRIDE;
     virtual bool AllowMicAccess(const GURL& origin) OVERRIDE;
     virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE;
 
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 43ca4f9..602766e 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/bookmark_model_loaded_observer.h"
 #include "chrome/browser/profiles/profile_destroyer.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -227,7 +227,7 @@
 // TODO(nkostylev): Remove this method once all clients are migrated.
 Profile* ProfileManager::GetDefaultProfile() {
   CHECK(s_allow_get_default_profile)
-      << "GetDefaultProfile() caled befofre allowed.";
+      << "GetDefaultProfile() called before allowed.";
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   return profile_manager->GetDefaultProfile(profile_manager->user_data_dir_);
 }
@@ -236,7 +236,7 @@
 // TODO(nkostylev): Remove this method once all clients are migrated.
 Profile* ProfileManager::GetDefaultProfileOrOffTheRecord() {
   CHECK(s_allow_get_default_profile)
-      << "GetDefaultProfileOrOffTheRecord() caled befofre allowed.";
+      << "GetDefaultProfileOrOffTheRecord() called before allowed.";
   // TODO (mukai,nkostylev): In the long term we should fix those cases that
   // crash on Guest mode and have only one GetDefaultProfile() method.
   Profile* profile = GetDefaultProfile();
@@ -608,6 +608,7 @@
     case chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST: {
       // Ignore any browsers closing from now on.
       closing_all_browsers_ = true;
+      save_active_profiles = true;
       break;
     }
     case chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED: {
@@ -672,7 +673,9 @@
     std::vector<Profile*>::const_iterator it;
     for (it = active_profiles_.begin(); it != active_profiles_.end(); ++it) {
       std::string profile_path = (*it)->GetPath().BaseName().MaybeAsASCII();
-      if (profile_paths.find(profile_path) == profile_paths.end()) {
+      // Some profiles might become ephemeral after they are created.
+      if (!(*it)->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles) &&
+          profile_paths.find(profile_path) == profile_paths.end()) {
         profile_paths.insert(profile_path);
         profile_list->Append(new StringValue(profile_path));
       }
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index de575a9..102c2f8 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -635,7 +635,7 @@
   Profile* last_used_profile = profile_manager->GetLastUsedProfile();
   EXPECT_NE(profile, last_used_profile);
 
-  // Create a browser for profile2.
+  // Create a browser for the profile.
   Browser::CreateParams profile_params(profile, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
@@ -653,7 +653,10 @@
   dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("Normal Profile"));
 
   base::FilePath dest_path2 = temp_dir_.path();
-  dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("Ephemeral Profile"));
+  dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("Ephemeral Profile 1"));
+
+  base::FilePath dest_path3 = temp_dir_.path();
+  dest_path3 = dest_path3.Append(FILE_PATH_LITERAL("Ephemeral Profile 2"));
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
 
@@ -663,11 +666,16 @@
   ASSERT_TRUE(normal_profile);
 
   // Add one ephemeral profile which should not end up in this list.
-  TestingProfile* ephemeral_profile =
+  TestingProfile* ephemeral_profile1 =
       static_cast<TestingProfile*>(profile_manager->GetProfile(dest_path2));
-  ASSERT_TRUE(ephemeral_profile);
-  ephemeral_profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles,
-                                            true);
+  ASSERT_TRUE(ephemeral_profile1);
+  ephemeral_profile1->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles,
+                                             true);
+
+  // Add second ephemeral profile but don't mark it as such yet.
+  TestingProfile* ephemeral_profile2 =
+      static_cast<TestingProfile*>(profile_manager->GetProfile(dest_path3));
+  ASSERT_TRUE(ephemeral_profile2);
 
   // Create a browser for profile1.
   Browser::CreateParams profile1_params(normal_profile,
@@ -675,16 +683,26 @@
   scoped_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
-  // Create a browser for the ephemeral profile.
-  Browser::CreateParams profile2_params(ephemeral_profile,
+  // Create browsers for the ephemeral profile.
+  Browser::CreateParams profile2_params(ephemeral_profile1,
                                         chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
+  Browser::CreateParams profile3_params(ephemeral_profile2,
+                                        chrome::GetActiveDesktop());
+  scoped_ptr<Browser> browser3(
+      chrome::CreateBrowserWithTestWindowForParams(&profile3_params));
+
   std::vector<Profile*> last_opened_profiles =
       profile_manager->GetLastOpenedProfiles();
-  ASSERT_EQ(1U, last_opened_profiles.size());
+  ASSERT_EQ(2U, last_opened_profiles.size());
   EXPECT_EQ(normal_profile, last_opened_profiles[0]);
+  EXPECT_EQ(ephemeral_profile2, last_opened_profiles[1]);
+
+  // Mark the second profile ephemeral.
+  ephemeral_profile2->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles,
+                                             true);
 
   // Simulate a shutdown.
   content::NotificationService::current()->Notify(
@@ -693,6 +711,7 @@
       content::NotificationService::NoDetails());
   browser1.reset();
   browser2.reset();
+  browser3.reset();
 
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(1U, last_opened_profiles.size());
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index e4802c3..0e75466 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -313,8 +313,7 @@
   const string16 kSanitizedProfileName = L"Harry";
   BrowserDistribution* distribution = GetDistribution();
   const string16 expected_name = kSanitizedProfileName + L" - " +
-      distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
-          installer::kLnkExt;
+      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME) + installer::kLnkExt;
   EXPECT_EQ(expected_name,
             profiles::internal::GetShortcutFilenameForProfile(kProfileName,
                                                               distribution));
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
index b23dcad..d0448f6 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
@@ -15,15 +15,15 @@
 }
 
 namespace ChromeRenderWidgetHostViewMacDelegateInternal {
-class SpellCheckRenderViewObserver;
+class SpellCheckObserver;
 }
 
 @interface ChromeRenderWidgetHostViewMacDelegate
     : NSObject<RenderWidgetHostViewMacDelegate> {
  @private
   content::RenderWidgetHost* renderWidgetHost_;  // weak
-  scoped_ptr<ChromeRenderWidgetHostViewMacDelegateInternal::
-      SpellCheckRenderViewObserver> spellingObserver_;
+  scoped_ptr<ChromeRenderWidgetHostViewMacDelegateInternal::SpellCheckObserver>
+      spellingObserver_;
 
   // If the viewport is scrolled all the way to the left or right.
   // Used for history swiping.
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
index 2961093..af317b4 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
@@ -23,10 +23,10 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 
 using content::RenderViewHost;
 
@@ -37,32 +37,25 @@
 
 namespace ChromeRenderWidgetHostViewMacDelegateInternal {
 
-// Filters the message sent to RenderViewHost to know if spellchecking is
-// enabled or not for the currently focused element.
-class SpellCheckRenderViewObserver : public content::RenderViewHostObserver {
+// Filters the message sent by the renderer to know if spellchecking is enabled
+// or not for the currently focused element.
+class SpellCheckObserver : public content::WebContentsObserver {
  public:
-  SpellCheckRenderViewObserver(
+  SpellCheckObserver(
       RenderViewHost* host,
       ChromeRenderWidgetHostViewMacDelegate* view_delegate)
-      : content::RenderViewHostObserver(host),
+      : content::WebContentsObserver(
+            content::WebContents::FromRenderViewHost(host)),
         view_delegate_(view_delegate) {
   }
 
-  virtual ~SpellCheckRenderViewObserver() {
+  virtual ~SpellCheckObserver() {
   }
 
  private:
-  // content::RenderViewHostObserver implementation.
-  virtual void RenderViewHostDestroyed(RenderViewHost* rvh) OVERRIDE {
-    // The parent implementation destroys the observer, scoping the lifetime of
-    // the observer to the RenderViewHost. Since this class is acting as a
-    // bridge to the view for the delegate below, and is owned by that delegate,
-    // undo the scoping by not calling through to the parent implementation.
-  }
-
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
     bool handled = true;
-    IPC_BEGIN_MESSAGE_MAP(SpellCheckRenderViewObserver, message)
+    IPC_BEGIN_MESSAGE_MAP(SpellCheckObserver, message)
       IPC_MESSAGE_HANDLER(SpellCheckHostMsg_ToggleSpellCheck,
                           OnToggleSpellCheck)
       IPC_MESSAGE_UNHANDLED(handled = false)
@@ -90,9 +83,8 @@
 
     if (renderWidgetHost_->IsRenderView()) {
       spellingObserver_.reset(
-          new ChromeRenderWidgetHostViewMacDelegateInternal::
-              SpellCheckRenderViewObserver(
-                  RenderViewHost::From(renderWidgetHost_), self));
+          new ChromeRenderWidgetHostViewMacDelegateInternal::SpellCheckObserver(
+              RenderViewHost::From(renderWidgetHost_), self));
     }
   }
   return self;
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 69dba1c..767b069 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/ui/auto_login_prompter.h"
 #include "chrome/browser/ui/login/login_prompt.h"
 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/mime_types_handler.h"
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc
index dcfb013..cc03c08 100644
--- a/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc
+++ b/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc
@@ -110,6 +110,18 @@
             host_->GetPpapiHost(), instance, params.pp_resource(),
             clipboard_filter));
       }
+    }
+  }
+
+  // PepperFlashDRMHost is also used by the PPB_Flash_DeviceID interface
+  // which has private permission.
+  // TODO(xhwang): Once PPB_Flash_DeviceID is removed, remove the check
+  // for private permissions.
+  if (host_->GetPpapiHost()->permissions().HasPermission(
+          ppapi::PERMISSION_FLASH) ||
+      host_->GetPpapiHost()->permissions().HasPermission(
+          ppapi::PERMISSION_PRIVATE)) {
+    switch (message.type()) {
       case PpapiHostMsg_FlashDRM_Create::ID:
         return scoped_ptr<ResourceHost>(new PepperFlashDRMHost(
             host_, instance, params.pp_resource()));
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
index 5f3a1c2..2c288ee 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
@@ -37,26 +37,19 @@
 
 const uint32_t kSaltLength = 32;
 
-void GetMachineIDAsync(const DeviceIDFetcher::IDCallback& callback) {
-  std::string result;
+void GetMachineIDAsync(
+    const base::Callback<void(const std::string&)>& callback) {
 #if defined(OS_WIN) && defined(ENABLE_RLZ)
+  std::string result;
   rlz_lib::GetMachineId(&result);
+  callback.Run(result);
 #elif defined(OS_CHROMEOS)
-  result = chromeos::SystemSaltGetter::Get()->GetSystemSaltSync();
-  if (result.empty()) {
-    // cryptohome must not be running; re-request after a delay.
-    const int64 kRequestSystemSaltDelayMs = 500;
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&GetMachineIDAsync, callback),
-        base::TimeDelta::FromMilliseconds(kRequestSystemSaltDelayMs));
-    return;
-  }
+  chromeos::SystemSaltGetter::Get()->GetSystemSalt(callback);
 #else
   // Not implemented for other platforms.
   NOTREACHED();
+  callback.Run(std::string());
 #endif
-  callback.Run(result, result.empty() ? PP_ERROR_FAILED : PP_OK);
 }
 
 }  // namespace
@@ -147,13 +140,12 @@
 }
 
 void DeviceIDFetcher::ComputeOnUIThread(const std::string& salt,
-                                        const std::string& machine_id,
-                                        int32_t result) {
+                                        const std::string& machine_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  if (result != PP_OK) {
+  if (machine_id.empty()) {
     LOG(ERROR) << "Empty machine id";
-    RunCallbackOnIOThread(std::string(), result);
+    RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED);
     return;
   }
 
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.h b/chrome/browser/renderer_host/pepper/device_id_fetcher.h
index c1f308a..21acb10 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.h
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.h
@@ -55,8 +55,7 @@
 
   // Compute the device ID on the UI thread with the given salt and machine ID.
   void ComputeOnUIThread(const std::string& salt,
-                         const std::string& machine_id,
-                         int32_t result);
+                         const std::string& machine_id);
 
   // Legacy method used to get the device ID for ChromeOS.
   void LegacyComputeOnBlockingPool(const base::FilePath& profile_path,
diff --git a/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc b/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc
index 7f0f4bb..c7f47e5 100644
--- a/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc
@@ -80,10 +80,10 @@
       return;
     gfx::NativeView native_view = view->GetNativeView();
 #if defined(USE_AURA)
-    aura::RootWindow* root = native_view->GetRootWindow();
-    if (!root)
+    aura::WindowEventDispatcher* dispatcher = native_view->GetDispatcher();
+    if (!dispatcher)
       return;
-    HWND window = root->GetAcceleratedWidget();
+    HWND window = dispatcher->GetAcceleratedWidget();
 #else
     HWND window = native_view;
 #endif
diff --git a/chrome/browser/resources/bookmark_manager/js/dnd.js b/chrome/browser/resources/bookmark_manager/js/dnd.js
index b4859a6..f920eb3 100644
--- a/chrome/browser/resources/bookmark_manager/js/dnd.js
+++ b/chrome/browser/resources/bookmark_manager/js/dnd.js
@@ -145,7 +145,7 @@
   }
 
   /**
-    * Stores the information abou the bookmark and folders being dragged.
+    * Stores the information about the bookmark and folders being dragged.
     * @type {Object}
     */
   var dragData = null;
@@ -319,6 +319,13 @@
     // We manage starting the drag by using the extension API.
     e.preventDefault();
 
+    // Do not allow dragging if there is an ephemeral item being edited at the
+    // moment.
+    for (var i = 0; i < draggedNodes.length; i++) {
+      if (draggedNodes[i].id === 'new')
+        return;
+    }
+
     if (draggedNodes.length) {
       // If we are dragging a single link, we can do the *Link* effect.
       // Otherwise, we only allow copy and move.
diff --git a/chrome/browser/resources/bookmark_manager/js/main.js b/chrome/browser/resources/bookmark_manager/js/main.js
index f0b2654..4036b48 100644
--- a/chrome/browser/resources/bookmark_manager/js/main.js
+++ b/chrome/browser/resources/bookmark_manager/js/main.js
@@ -153,6 +153,8 @@
  *     displayed specified folder.
  */
 function navigateTo(id, callback) {
+  updateHash(id);
+
   if (list.parentId == id) {
     callback();
     return;
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay_data.js b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
index 780705a..02d6c51 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay_data.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
@@ -15764,7 +15764,6 @@
     '+<>ALT<>SHIFT': 'keyboardOverlayCenterWindow',
     '+<>CTRL': 'keyboardOverlayZoomIn',
     '+<>CTRL<>SHIFT': 'keyboardOverlayZoomScreenIn',
-    '-<>ALT': 'keyboardOverlayMinimizeWindow',
     '-<>CTRL': 'keyboardOverlayZoomOut',
     '-<>CTRL<>SHIFT': 'keyboardOverlayZoomScreenOut',
     '-<>SEARCH': 'keyboardOverlayF11',
@@ -15874,6 +15873,7 @@
     'o<>CTRL': 'keyboardOverlayOpen',
     'o<>CTRL<>SHIFT': 'keyboardOverlayBookmarkManager',
     'p<>CTRL': 'keyboardOverlayPrint',
+    'p<>CTRL<>SHIFT': 'keyboardOverlayOpenGoogleCloudPrint',
     'power': 'keyboardOverlayLockScreenOrPowerOff',
     'q<>CTRL<>SHIFT': 'keyboardOverlaySignOut',
     'r<>CTRL': 'keyboardOverlayReloadCurrentPage',
diff --git a/chrome/browser/resources/chromeos/login/screen_account_picker.js b/chrome/browser/resources/chromeos/login/screen_account_picker.js
index ab2d4ec..dcbc0aa 100644
--- a/chrome/browser/resources/chromeos/login/screen_account_picker.js
+++ b/chrome/browser/resources/chromeos/login/screen_account_picker.js
@@ -26,7 +26,8 @@
       'updateUserImage',
       'updateUserGaiaNeeded',
       'setCapsLockState',
-      'forceLockedUserPodFocus'
+      'forceLockedUserPodFocus',
+      'onWallpaperLoaded'
     ],
 
     /** @override */
@@ -179,6 +180,13 @@
       var row = $('pod-row');
       if (row.lockedPod)
         row.focusPod(row.lockedPod, true);
+    },
+
+    /**
+     * Mark wallpaper loaded
+     */
+    onWallpaperLoaded: function(email) {
+      $('pod-row').onWallpaperLoaded(email);
     }
   };
 });
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
index 15ed19c..6e96620 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
@@ -179,6 +179,13 @@
   overflow-y: auto;
 }
 
+/* This class will be set for elements with hide-on-import class by JS when
+ * page is used in 'import' mode
+ */
+#managed-user-creation .hidden-on-import {
+  display: none;
+}
+
 #managed-user-creation-error {
   padding: 175px 120px 0;
   text-align: center;
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
index a3bbf47..6c1676a 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
@@ -27,13 +27,13 @@
     </div>
     <div id="managed-user-creation-username" class="page-no-marketing" hidden>
       <div class="logo-padded-text">
-        <div>
+        <div class="hide-on-import">
           <div class="page-title inline"
               i18n-content="createManagedUserNameTitle"></div>
           <div id="managed-user-creation-name-explanation"
               class="page-title-explanation inline"></div>
         </div>
-        <div id="managed-user-creation-name-block">
+        <div id="managed-user-creation-name-block" class="hide-on-import">
           <input id="managed-user-creation-name" type="text" maxlength="50" />
           <span id="managed-user-creation-name-error" class="no-error">
           </span>
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
index 950415e..d6f318a 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
@@ -693,7 +693,7 @@
           'import',
           'managedUserCreationFlow',
           this.importButtonPressed_.bind(this),
-          ['import'],
+          ['import', 'import-password'],
           []));
 
       buttons.push(this.makeButton(
@@ -759,16 +759,38 @@
      * @private
      */
     importSupervisedUser_: function() {
-      var selectedPod = this.importList_.selectedPod_;
-      if (!selectedPod)
+      if (this.disabled)
         return;
-      var userId = selectedPod.user.id;
+      if (this.currentPage_ == 'import-password') {
+        var firstPassword = this.getScreenElement('password').value;
+        var secondPassword = this.getScreenElement('password-confirm').value;
+        if (firstPassword != secondPassword) {
+          this.showPasswordError(
+              loadTimeData.getString('createManagedUserPasswordMismatchError'));
+          return;
+        }
+        var userId = this.context_.importUserId;
+        this.disabled = true;
+        chrome.send('importSupervisedUserWithPassword',
+            [userId, firstPassword]);
+        return;
+      } else {
+        var selectedPod = this.importList_.selectedPod_;
+        if (!selectedPod)
+          return;
+        var user = selectedPod.user;
+        var userId = user.id;
 
-      this.disabled = true;
-      this.context_.importUserId = userId;
-      this.context_.managedName = selectedPod.user.name;
-
-      chrome.send('importSupervisedUser', [userId]);
+        this.context_.importUserId = userId;
+        this.context_.managedName = user.name;
+        this.context_.selectedImageUrl = user.avatarurl;
+        if (!user.needPassword) {
+          this.disabled = true;
+          chrome.send('importSupervisedUser', [userId]);
+        } else {
+          this.setVisiblePage_('import-password');
+        }
+      }
     },
 
     /**
@@ -922,10 +944,16 @@
       var secondPassword = this.getScreenElement('password-confirm').value;
       var userName = this.getScreenElement('name').value;
 
+      var passwordOk = (firstPassword.length > 0) &&
+          (firstPassword.length == secondPassword.length);
+
+      if (this.currentPage_ == 'import-password') {
+        this.setButtonDisabledStatus('import', !passwordOk);
+        return passwordOk;
+      }
       var canProceed =
+          passwordOk &&
           (userName.length > 0) &&
-          (firstPassword.length > 0) &&
-          (firstPassword.length == secondPassword.length) &&
            this.lastVerifiedName_ &&
            (userName == this.lastVerifiedName_);
 
@@ -963,13 +991,18 @@
       var pageButtons = {'intro' : 'start',
                          'error' : 'error',
                          'import' : 'import',
+                         'import-password' : 'import',
                          'created' : 'gotit'};
       this.hideStatus_();
+      var pageToDisplay = visiblePage;
+      if (visiblePage == 'import-password')
+        pageToDisplay = 'username';
+
       for (i in pageNames) {
         var pageName = pageNames[i];
         var page = $('managed-user-creation-' + pageName);
-        page.hidden = (pageName != visiblePage);
-        if (pageName == visiblePage)
+        page.hidden = (pageName != pageToDisplay);
+        if (pageName == pageToDisplay)
           $('step-logo').hidden = page.classList.contains('step-no-logo');
       }
 
@@ -979,7 +1012,8 @@
         button.disabled = false;
       }
 
-      var pagesWithCancel = ['intro', 'manager', 'username', 'error', 'import'];
+      var pagesWithCancel = ['intro', 'manager', 'username', 'import-password',
+          'error', 'import'];
       var cancelButton = $('cancel-add-user-button');
       cancelButton.hidden = pagesWithCancel.indexOf(visiblePage) < 0;
       cancelButton.disabled = false;
@@ -999,11 +1033,20 @@
           this.managerList_.selectPod(this.managerList_.pods[0]);
       }
 
+      if (visiblePage == 'username' || visiblePage == 'import-password') {
+        var elements = this.getScreenElement(pageToDisplay).
+            querySelectorAll('.hide-on-import');
+        for (var i = 0; i < elements.length; i++) {
+          elements[i].classList.toggle('hidden-on-import',
+              visiblePage == 'import-password');
+        }
+      }
       if (visiblePage == 'username') {
         var imageGrid = this.getScreenElement('image-grid');
         // select some image.
         var selected = this.imagesData_[
             Math.floor(Math.random() * this.imagesData_.length)];
+        this.context_.selectedImageUrl = selected.url;
         imageGrid.selectedItemUrl = selected.url;
         chrome.send('supervisedUserSelectImage',
                     [selected.url, 'default']);
@@ -1013,6 +1056,25 @@
         this.getScreenElement('name').focus();
         this.getScreenElement('import-link').hidden =
             this.importList_.pods.length == 0;
+      } else if (visiblePage == 'import-password') {
+        var imageGrid = this.getScreenElement('image-grid');
+        var selected;
+        if ('selectedImageUrl' in this.context_) {
+          selected = this.context_.selectedImageUrl;
+        } else {
+          // select some image.
+          selected = this.imagesData_[
+              Math.floor(Math.random() * this.imagesData_.length)].url;
+          chrome.send('supervisedUserSelectImage',
+                      [selected, 'default']);
+        }
+        imageGrid.selectedItemUrl = selected;
+        this.getScreenElement('image-grid').redraw();
+
+        this.updateNextButtonForUser_();
+
+        this.getScreenElement('password').focus();
+        this.getScreenElement('import-link').hidden = true;
       } else {
         this.getScreenElement('image-grid').stopCamera();
       }
@@ -1306,6 +1368,7 @@
     handleSelect_: function(e) {
       var imageGrid = this.getScreenElement('image-grid');
       if (!(imageGrid.selectionType == 'camera' && imageGrid.cameraLive)) {
+        this.context_.selectedImageUrl = imageGrid.selectedItemUrl;
         chrome.send('supervisedUserSelectImage',
                     [imageGrid.selectedItemUrl, imageGrid.selectionType]);
       }
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.css b/chrome/browser/resources/chromeos/login/user_pod_row.css
index 428288f..0e28bbd 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.css
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.css
@@ -349,7 +349,7 @@
 .pod.public-account .name,
 .side-pane-name {
   -webkit-padding-end: 16px;
-  height: 42px;
+  max-height: 42px;
   outline: none;
   overflow: hidden;
   text-overflow: ellipsis;
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index f5d24c8..952cda7 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+<include src="wallpaper_loader.js"></include>
+
 /**
  * @fileoverview User pod row implementation.
  */
@@ -22,20 +24,6 @@
   var PRESELECT_FIRST_POD = true;
 
   /**
-   * Wallpaper load delay in milliseconds.
-   * @type {number}
-   * @const
-   */
-  var WALLPAPER_LOAD_DELAY_MS = 500;
-
-  /**
-   * Wallpaper load delay in milliseconds. TODO(nkostylev): Tune this constant.
-   * @type {number}
-   * @const
-   */
-  var WALLPAPER_BOOT_LOAD_DELAY_MS = 100;
-
-  /**
    * Maximum time for which the pod row remains hidden until all user images
    * have been loaded.
    * @type {number}
@@ -959,17 +947,9 @@
     // Whether this user pod row is shown for the first time.
     firstShown_: true,
 
-    // Whether the initial wallpaper load after boot has been requested. Used
-    // only if |Oobe.getInstance().shouldLoadWallpaperOnBoot()| is true.
-    bootWallpaperLoaded_: false,
-
     // True if inside focusPod().
     insideFocusPod_: false,
 
-    // True if user pod has been activated with keyboard.
-    // In case of activation with keyboard we delay wallpaper change.
-    keyboardActivated_: false,
-
     // Focused pod.
     focusedPod_: undefined,
 
@@ -979,9 +959,8 @@
     // Pod that was most recently focused, if any.
     lastFocusedPod_: undefined,
 
-    // When moving through users quickly at login screen, set a timeout to
-    // prevent loading intermediate wallpapers.
-    loadWallpaperTimeout_: null,
+    // Note: created only in decorate() !
+    wallpaperLoader_: undefined,
 
     // Pods whose initial images haven't been loaded yet.
     podsWithPendingImages_: [],
@@ -998,6 +977,7 @@
         mousemove: [this.handleMouseMove_.bind(this), false],
         keydown: [this.handleKeyDown.bind(this), false]
       };
+      this.wallpaperLoader_ = new login.WallpaperLoader();
     },
 
     /**
@@ -1242,7 +1222,7 @@
       }
       this.insideFocusPod_ = true;
 
-      clearTimeout(this.loadWallpaperTimeout_);
+      this.wallpaperLoader_.reset();
       for (var i = 0, pod; pod = this.pods[i]; ++i) {
         if (!this.isSinglePod) {
           pod.isActionBoxMenuActive = false;
@@ -1266,15 +1246,8 @@
         podToFocus.classList.add('focused');
         podToFocus.reset(true);  // Reset and give focus.
         chrome.send('focusPod', [podToFocus.user.emailAddress]);
-        if (hadFocus && this.keyboardActivated_) {
-          // Delay wallpaper loading to let user tab through pods without lag.
-          this.loadWallpaperTimeout_ = window.setTimeout(
-              this.loadWallpaper_.bind(this), WALLPAPER_LOAD_DELAY_MS);
-        } else if (!this.firstShown_) {
-          // Load wallpaper immediately if there no pod was focused
-          // previously, and it is not a boot into user pod list case.
-          this.loadWallpaper_();
-        }
+
+        this.wallpaperLoader_.scheduleLoad(podToFocus.user.emailAddress);
         this.firstShown_ = false;
         this.lastFocusedPod_ = podToFocus;
       }
@@ -1283,20 +1256,19 @@
     },
 
     /**
-     * Loads wallpaper for the active user pod, if any.
-     * @private
-     */
-    loadWallpaper_: function() {
-      if (this.focusedPod_)
-        chrome.send('loadWallpaper', [this.focusedPod_.user.username]);
-    },
-
-    /**
      * Resets wallpaper to the last active user's wallpaper, if any.
      */
     loadLastWallpaper: function() {
       if (this.lastFocusedPod_)
-        chrome.send('loadWallpaper', [this.lastFocusedPod_.user.username]);
+        this.wallpaperLoader_.scheduleLoad(this.lastFocusedPod_.user.username);
+    },
+
+    /**
+     * Handles 'onWallpaperLoaded' event. Recalculates statistics and
+     * [re]schedules next wallpaper load.
+     */
+    onWallpaperLoaded: function(email) {
+      this.wallpaperLoader_.onWallpaperLoaded(email);
     },
 
     /**
@@ -1560,13 +1532,7 @@
             focusedPod.reset(true);
             // Notify screen that it is ready.
             screen.onShow();
-            // Boot transition: load wallpaper.
-            if (!self.bootWallpaperLoaded_ &&
-                Oobe.getInstance().shouldLoadWallpaperOnBoot()) {
-              self.loadWallpaperTimeout_ = window.setTimeout(
-                  self.loadWallpaper_.bind(self), WALLPAPER_BOOT_LOAD_DELAY_MS);
-              self.bootWallpaperLoaded_ = true;
-            }
+            self.wallpaperLoader_.scheduleLoad(focusedPod.user.username);
           }
         });
         // Guard timer for 1 second -- it would conver all possible animations.
diff --git a/chrome/browser/resources/chromeos/login/wallpaper_loader.js b/chrome/browser/resources/chromeos/login/wallpaper_loader.js
new file mode 100644
index 0000000..899b06b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/wallpaper_loader.js
@@ -0,0 +1,185 @@
+// Copyright 2013 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.
+
+cr.define('login', function() {
+
+  /**
+   * Minimum wallpaper load delay in milliseconds.
+   * @type {number}
+   * @const
+   */
+  var WALLPAPER_LOAD_MIN_DELAY_MS = 100;
+
+  /**
+   * If last walpaper load time cannot be calculated, assume this value.
+   * @type {number}
+   * @const
+   */
+  var WALLPAPER_DEFAULT_LOAD_TIME_MS = 200;
+
+  /**
+   * Min and Max average wallpaper load time.
+   * Delay to next wallpaper load is 2 * <average load time>.
+   * @type {number}
+   * @const
+   */
+  var WALLPAPER_MIN_LOAD_TIME_MS = 50;
+  var WALLPAPER_MAX_LOAD_TIME_MS = 2000;
+
+  /**
+   * Number last wallpaper load times to remember.
+   * @type {number}
+   * @const
+   */
+  var WALLPAPER_LOAD_STATS_MAX_LENGTH = 4;
+
+
+  /**
+   * Creates a new pod row element.
+   * @constructor
+   * @extends {HTMLDivElement}
+   */
+  var WallpaperLoader = function() {
+    this.wallpaperLoadInProgress_ = {
+        name: '',
+        date: undefined
+    };
+    this.loadStats_ = [];
+  };
+
+  WallpaperLoader.prototype = {
+    // When moving through users quickly at login screen, set a timeout to
+    // prevent loading intermediate wallpapers.
+    loadWallpaperTimeout_: null,
+
+    // When waiting for wallpaper load, remember load start time.
+    // wallpaperLoadInProgress_: { name: '', date: undefined }
+    wallpaperLoadInProgress_: undefined,
+
+    // Wait a delay and then load this wallpaper. Value = username.
+    wallpaperLoadPending_: undefined,
+
+    // Wait untill this Date before loading next wallpaper.
+    wallpaperLoadTryNextAfter_: undefined,
+
+    // Username, owner of current wallpaper.
+    currentWallpaper_: '',
+
+    // Array of times (in milliseconds) of last wallpaper load attempts.
+    // Length is limited by WALLPAPER_LOAD_STATS_MAX_LENGTH.
+    loadStats_: undefined,
+
+    /**
+     * Stop load timer. Clear pending record.
+     */
+    reset: function() {
+      delete this.wallpaperLoadPending_;
+      if (this.loadWallpaperTimeout_ != null)
+        window.clearTimeout(this.loadWallpaperTimeout_);
+      this.loadWallpaperTimeout_ = null;
+    },
+
+    /**
+     * Schedules wallpaper load.
+     */
+    scheduleLoad: function(email) {
+      if (this.wallpaperLoadPending_ && this.wallpaperLoadPending_ == email)
+        return;
+      this.reset();
+      if (this.wallpaperLoadInProgress_.name == email)
+        return;
+      if ((this.wallpaperLoadInProgress_.name == '') &&
+          (this.currentWallpaper_ == email))
+        return;
+
+      this.wallpaperLoadPending_ = email;
+      var now = new Date();
+      var timeout = WALLPAPER_LOAD_MIN_DELAY_MS;
+      if (this.wallpaperLoadTryNextAfter_)
+        timeout = Math.max(timeout, this.wallpaperLoadTryNextAfter_ - now);
+
+      this.loadWallpaperTimeout_ = window.setTimeout(
+        this.loadWallpaper_.bind(this), timeout);
+     },
+
+
+    /**
+     * Loads pending wallpaper, if any.
+     * @private
+     */
+    loadWallpaper_: function() {
+      this.loadWallpaperTimeout_ = null;
+      if (!this.wallpaperLoadPending_)
+        return;
+      if (this.wallpaperLoadInProgress_.name != '')
+        return;
+      var email = this.wallpaperLoadPending_;
+      delete this.wallpaperLoadPending_;
+      if (email == this.currentWallpaper_)
+        return;
+      this.wallpaperLoadInProgress_.name = email;
+      this.wallpaperLoadInProgress_.date = new Date();
+      chrome.send('loadWallpaper', [email]);
+    },
+
+    /**
+     * Calculates average wallpaper load time.
+     */
+    calcLoadStatsAvg: function() {
+        return this.loadStats_.reduce(
+            function(previousValue, currentValue) {
+              return previousValue + currentValue;
+            }) / this.loadStats_.length;
+    },
+
+    /**
+     * Calculates average next wallpaper load delay time.
+     */
+    getWallpaperLoadTime_: function() {
+      var avg = WALLPAPER_DEFAULT_LOAD_TIME_MS;
+
+      if (this.loadStats_.length == 0)
+        return avg;
+
+      avg = this.calcLoadStatsAvg();
+      if (avg < WALLPAPER_MIN_LOAD_TIME_MS)
+        avg = WALLPAPER_MIN_LOAD_TIME_MS;
+
+      if (avg > WALLPAPER_MAX_LOAD_TIME_MS)
+        avg = WALLPAPER_MAX_LOAD_TIME_MS;
+
+      return avg;
+    },
+
+    /**
+     * Handles 'onWallpaperLoaded' event. Recalculates statistics and
+     * [re]schedules next wallpaper load.
+     */
+    onWallpaperLoaded: function(email) {
+      this.currentWallpaper_ = email;
+      if (email != this.wallpaperLoadInProgress_.name)
+          return;
+      this.wallpaperLoadInProgress_.name = '';
+      var started = this.wallpaperLoadInProgress_.date;
+      var finished = new Date();
+      var elapsed = started ? finished - started :
+          WALLPAPER_DEFAULT_LOAD_TIME_MS;
+      this.loadStats_.push(elapsed);
+      if (this.loadStats_.length > WALLPAPER_LOAD_STATS_MAX_LENGTH)
+        this.loadStats_.shift();
+
+      this.wallpaperLoadTryNextAfter_ = new Date(Date.now() + 2 *
+          this.getWallpaperLoadTime_());
+      if (this.wallpaperLoadPending_) {
+        var newWallpaperEmail = this.wallpaperLoadPending_;
+        this.reset();
+        this.scheduleLoad(newWallpaperEmail);
+      }
+    }
+  };
+
+  return {
+    WallpaperLoader: WallpaperLoader
+  };
+});
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js
index 9a6cb38..cddb7c4 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js
@@ -57,6 +57,7 @@
    */
   WallpaperSourceEnum: {
       Online: 'ONLINE',
+      OEM: 'OEM',
       Custom: 'CUSTOM',
       AddNew: 'ADDNEW'
   },
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
index ba8710a..b2b2a9c 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
@@ -73,6 +73,7 @@
           }
           getThumbnail(self.dataItem.baseURL);
           break;
+        case Constants.WallpaperSourceEnum.OEM:
         case Constants.WallpaperSourceEnum.Online:
           chrome.wallpaperPrivate.getThumbnail(this.dataItem.baseURL,
                                                this.dataItem.source,
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
index b7a19ed..14100d6 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -481,6 +481,14 @@
         this.wallpaperDirs_.getDirectory(WallpaperDirNameEnum.ORIGINAL,
                                          success, errorHandler);
         break;
+      case Constants.WallpaperSourceEnum.OEM:
+        // Resets back to default wallpaper.
+        chrome.wallpaperPrivate.resetWallpaper();
+        this.currentWallpaper_ = selectedItem.baseURL;
+        this.wallpaperGrid_.activeItem = selectedItem;
+        WallpaperUtil.saveWallpaperInfo(wallpaperURL, selectedItem.layout,
+                                        selectedItem.source);
+        break;
       case Constants.WallpaperSourceEnum.Online:
         var wallpaperURL = selectedItem.baseURL +
             Constants.HighResolutionSuffix;
@@ -614,7 +622,10 @@
    * @private
    */
   WallpaperManager.prototype.setWallpaperAttribution_ = function(selectedItem) {
-    if (selectedItem && selectedItem.source != 'ADDNEW') {
+    // Only online wallpapers have author and website attributes. All other type
+    // of wallpapers should not show attributions.
+    if (selectedItem &&
+        selectedItem.source == Constants.WallpaperSourceEnum.Online) {
       $('author-name').textContent = selectedItem.author;
       $('author-website').textContent = $('author-website').href =
           selectedItem.authorWebsite;
@@ -938,14 +949,25 @@
                 source: Constants.WallpaperSourceEnum.Custom,
                 availableOffline: true
           };
-          if (self.currentWallpaper_ == entry.name)
-            selectedItem = wallpaperInfo;
           wallpapersDataModel.push(wallpaperInfo);
         }
+        if (loadTimeData.getBoolean('isOEMDefaultWallpaper')) {
+          var oemDefaultWallpaperElement = {
+              baseURL: 'OemDefaultWallpaper',
+              layout: 'CENTER_CROPPED',
+              source: Constants.WallpaperSourceEnum.OEM,
+              availableOffline: true
+          };
+          wallpapersDataModel.push(oemDefaultWallpaperElement);
+        }
+        for (var i = 0; i < wallpapersDataModel.length; i++) {
+          if (self.currentWallpaper_ == wallpapersDataModel.item(i).baseURL)
+            selectedItem = wallpapersDataModel.item(i);
+        }
         var lastElement = {
             baseURL: '',
             layout: '',
-            source: 'ADDNEW',
+            source: Constants.WallpaperSourceEnum.AddNew,
             availableOffline: true
         };
         wallpapersDataModel.push(lastElement);
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 2cb63c7..a1346bf 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -55,6 +55,9 @@
       <include name="IDR_GAIA_AUTH_CHANNEL_JS" file="gaia_auth/channel.js" type="BINDATA" />
       <include name="IDR_GAIA_AUTH_INLINE_INJECTED_JS" file="gaia_auth/inline_injected.js" type="BINDATA" />
       <include name="IDR_GAIA_AUTH_INLINE_MAIN" file="gaia_auth/inline_main.html" allowexternalscript="true" type="BINDATA" />
+      <!-- Hangout Services extension -->
+      <include name="IDR_HANGOUT_SERVICES_BACKGROUND_HTML" file="hangout_services/background.html" type="BINDATA" />
+      <include name="IDR_HANGOUT_SERVICES_THUNK_JS" file="hangout_services/thunk.js" type="BINDATA" />
       <if expr="pp_ifdef('chromeos')">
         <!-- Background page loader  -->
         <include name="IDR_BACKLOADER_BACKGROUND_HTML" file="backloader/background.html" type="BINDATA" />
@@ -72,44 +75,42 @@
       <if expr="pp_ifdef('file_manager_extension')">
         <!-- App pages and scripts. -->
         <include name="IDR_FILE_MANAGER_MAIN" file="file_manager/main.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_MAIN_JS" file="file_manager/js/main_scripts.js" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_BKGND_JS" file="file_manager/js/background.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_MAIN_JS" file="file_manager/foreground/js/main_scripts.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_BKGND_JS" file="file_manager/background/js/background.js" type="BINDATA" />
 
         <include name="IDR_FILE_MANAGER_MEDIAPLAYER" file="file_manager/mediaplayer.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_MEDIAPLAYER_JS" file="file_manager/js/media/mediaplayer_scripts.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_MEDIAPLAYER_JS" file="file_manager/foreground/js/media/mediaplayer_scripts.js" flattenhtml="true" type="BINDATA" />
 
         <include name="IDR_FILE_MANAGER_VIDEO_PLAYER" file="file_manager/video_player.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_VIDEO_PLAYER_JS" file="file_manager/js/media/video_player_scripts.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_VIDEO_PLAYER_JS" file="file_manager/foreground/js/media/video_player_scripts.js" flattenhtml="true" type="BINDATA" />
 
         <include name="IDR_FILE_MANAGER_GALLERY" file="file_manager/gallery.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_GALLERY_JS" file="file_manager/js/photo/gallery_scripts.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_GALLERY_JS" file="file_manager/foreground/js/photo/gallery_scripts.js" flattenhtml="true" type="BINDATA" />
 
-        <include name="IDR_FILE_MANAGER_PHOTO_IMPORT" file="file_manager/photo_import.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_PHOTO_IMPORT_JS" file="file_manager/js/photo/photo_import_scripts.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_FILE_MANAGER_ACTION_CHOICE" file="file_manager/action_choice.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_ACTION_CHOICE_SCRIPT_JS" file="file_manager/js/action_choice_scripts.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ACTION_CHOICE_SCRIPT_JS" file="file_manager/foreground/js/action_choice/action_choice_scripts.js" flattenhtml="true" type="BINDATA" />
 
         <!-- Scripts working in background page. -->
-        <include name="IDR_FILE_MANAGER_VOLUME_MANAGER_JS" file="file_manager/js/volume_manager.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_FILE_OPERATION_MANAGER_JS" file="file_manager/js/file_operation_manager.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_PROGRESS_CENTER_JS" file="file_manager/js/progress_center.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_PROGRESS_CENTER_COMMON_JS" file="file_manager/js/progress_center_common.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_ASYNC_UTIL_JS" file="file_manager/js/async_util.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_PATH_UTIL_JS" file="file_manager/js/path_util.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_UTIL_JS" file="file_manager/js/util.js" flattenhtml="false" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_TEST_UTIL_JS" file="file_manager/js/test_util.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_VOLUME_MANAGER_JS" file="file_manager/background/js/volume_manager.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_FILE_OPERATION_MANAGER_JS" file="file_manager/background/js/file_operation_manager.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_PROGRESS_CENTER_JS" file="file_manager/background/js/progress_center.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_PROGRESS_CENTER_COMMON_JS" file="file_manager/common/js/progress_center_common.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ASYNC_UTIL_JS" file="file_manager/common/js/async_util.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_PATH_UTIL_JS" file="file_manager/common/js/path_util.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_UTIL_JS" file="file_manager/common/js/util.js" flattenhtml="false" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_TEST_UTIL_JS" file="file_manager/background/js/test_util.js" flattenhtml="false" type="BINDATA" />
 
         <!-- Scripts required by the metadata parser worker. -->
-        <include name="IDR_FILE_MANAGER_UTIL" file="file_manager/js/util.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_METADATA_DISPATCHER" file="file_manager/js/metadata/metadata_dispatcher.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_METADATA_READER" file="file_manager/js/metadata/byte_reader.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_METADATA_PARSER" file="file_manager/js/metadata/metadata_parser.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_EXIF_PARSER" file="file_manager/js/metadata/exif_parser.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_MPEG_PARSER" file="file_manager/js/metadata/mpeg_parser.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_IMAGE_PARSERS" file="file_manager/js/metadata/image_parsers.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_ID3_PARSER" file="file_manager/js/metadata/id3_parser.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_PARALLEL" file="file_manager/js/metadata/function_parallel.js" type="BINDATA" />
-        <include name="IDR_FILE_MANAGER_SEQUENCE" file="file_manager/js/metadata/function_sequence.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_UTIL" file="file_manager/common/js/util.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_METADATA_DISPATCHER" file="file_manager/foreground/js/metadata/metadata_dispatcher.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_METADATA_READER" file="file_manager/foreground/js/metadata/byte_reader.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_METADATA_PARSER" file="file_manager/foreground/js/metadata/metadata_parser.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_EXIF_PARSER" file="file_manager/foreground/js/metadata/exif_parser.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_MPEG_PARSER" file="file_manager/foreground/js/metadata/mpeg_parser.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_IMAGE_PARSERS" file="file_manager/foreground/js/metadata/image_parsers.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ID3_PARSER" file="file_manager/foreground/js/metadata/id3_parser.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_PARALLEL" file="file_manager/foreground/js/metadata/function_parallel.js" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_SEQUENCE" file="file_manager/foreground/js/metadata/function_sequence.js" type="BINDATA" />
 
         <!-- Images referenced from the manifest or the code -->
         <include name="IDR_FILE_MANAGER_ICON_16" file="file_manager/images/icon16.png" type="BINDATA" />
diff --git a/chrome/browser/resources/downloads/downloads.js b/chrome/browser/resources/downloads/downloads.js
index ecbb73c..a024866 100644
--- a/chrome/browser/resources/downloads/downloads.js
+++ b/chrome/browser/resources/downloads/downloads.js
@@ -590,7 +590,7 @@
     }
     case Download.DangerType.POTENTIALLY_UNWANTED: {
       this.dangerDesc_.textContent = loadTimeData.getStringF(
-          'danger_potentially_unwanted_desc', this.fileName_);
+          'danger_settings_desc', this.fileName_);
       break;
     }
   }
@@ -609,7 +609,8 @@
 
   if (this.dangerType_ == Download.DangerType.DANGEROUS_CONTENT ||
       this.dangerType_ == Download.DangerType.DANGEROUS_HOST ||
-      this.dangerType_ == Download.DangerType.DANGEROUS_URL) {
+      this.dangerType_ == Download.DangerType.DANGEROUS_URL ||
+      this.dangerType_ == Download.DangerType.POTENTIALLY_UNWANTED) {
     this.malwareNodeControls_.style.display = 'block';
     this.dangerDiscard_.style.display = 'none';
     this.dangerSave_.style.display = 'none';
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
index 3d6d779..935d9c9 100644
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ b/chrome/browser/resources/extensions/extension_command_list.js
@@ -263,26 +263,29 @@
       commandClear.addEventListener('click', this.handleClear_.bind(this));
 
       if (command.scope_ui_visible) {
-        var commandScope = node.querySelector('.command-scope');
-        commandScope.hidden = false;
-        commandScope.id = this.createElementId_(
-            'toggleCommandScope', command.extension_id, command.command_name);
-        if (command.global) {
-          // TODO(finnur): Use another icon, this is just a placeholder.
-          commandScope.src = 'chrome://theme/IDR_ACCESSED_COOKIES';
-          commandScope.title =
-              loadTimeData.getString('extensionCommandsGlobalTooltip');
+        var select = node.querySelector('.command-scope');
+        select.id = this.createElementId_(
+            'setCommandScope', command.extension_id, command.command_name);
+        select.hidden = false;
+        // Add the 'In Chrome' option.
+        var option = document.createElement('option');
+        option.textContent = loadTimeData.getString('extensionCommandsRegular');
+        select.appendChild(option);
+        if (command.extension_action) {
+          // Extension actions cannot be global, so we might as well disable the
+          // combo box, to signify that.
+          select.disabled = true;
         } else {
-          commandScope.src = 'chrome://theme/IDR_PRODUCT_LOGO_16';
-          var tooltip = command.extension_action ?
-              'extensionCommandsNotGlobalPermanentTooltip' :
-              'extensionCommandsNotGlobalTooltip';
-          commandScope.title = loadTimeData.getString(tooltip);
+          // Add the 'Global' option.
+          option = document.createElement('option');
+          option.textContent =
+              loadTimeData.getString('extensionCommandsGlobal');
+          select.appendChild(option);
+          select.selectedIndex = command.global ? 1 : 0;
         }
-        if (!command.extension_action) {
-          commandScope.addEventListener(
-              'click', this.handleToggleCommandScope_.bind(this));
-        }
+
+        select.addEventListener(
+            'click', this.handleSetCommandScope_.bind(this));
       }
 
       this.appendChild(node);
@@ -446,14 +449,16 @@
     },
 
     /**
-     * A handler for the toggling the scope of the command.
+     * A handler for the setting the scope of the command.
      * @param {Event} event The mouse event to consider.
      * @private
      */
-    handleToggleCommandScope_: function(event) {
-      var parsed = this.parseElementId_('toggleCommandScope', event.target.id);
-      chrome.send('toggleCommandScope',
-          [parsed.extensionId, parsed.commandName]);
+    handleSetCommandScope_: function(event) {
+      var parsed = this.parseElementId_('setCommandScope', event.target.id);
+      var element = document.getElementById(
+          'setCommandScope-' + parsed.extensionId + '-' + parsed.commandName);
+      chrome.send('setCommandScope',
+          [parsed.extensionId, parsed.commandName, element.selectedIndex == 1]);
     },
 
     /**
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.css b/chrome/browser/resources/extensions/extension_commands_overlay.css
index 098619d..0e6efb6 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.css
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.css
@@ -57,8 +57,8 @@
 }
 
 .command-scope {
-  padding-left: 0.3em;
-  padding-top: 0.6em;
+  margin-left: 0.25em;
+  margin-top: 0.24em;
 }
 
 .capturing {
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.html b/chrome/browser/resources/extensions/extension_commands_overlay.html
index b07e838..086ba45 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.html
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.html
@@ -46,7 +46,7 @@
                         src="chrome://theme/IDR_EXTENSION_COMMAND_CLOSE"
                   ><span class="command-shortcut-text" tabindex="0"
               ></span></span></span>
-          <img class="command-scope" width="16" height="16" hidden>
+          <select class="command-scope" hidden></select>
         </div>
       </div>
     </div>
diff --git a/chrome/browser/resources/feedback/js/event_handler.js b/chrome/browser/resources/feedback/js/event_handler.js
index 0d347c1..a283571 100644
--- a/chrome/browser/resources/feedback/js/event_handler.js
+++ b/chrome/browser/resources/feedback/js/event_handler.js
@@ -11,7 +11,7 @@
  * @type {number}
  * @const
  */
-var FEEDBACK_HEIGHT = 610;
+var FEEDBACK_HEIGHT = 620;
 /**
  * @type {number}
  * @const
@@ -23,6 +23,7 @@
 var whitelistedExtensionIds = [
   'bpmcpldpdmajfigpchkicefoigmkfalc', // QuickOffice
   'ehibbfinohgbchlgdbfpikodjaojhccn', // QuickOffice
+  'gbkeegbaiigmenfmjfclcdgdpimamgkj', // QuickOffice
   'efjnaogkjbogokcnohkmnjdojkikgobo', // G+ Photos
   'ebpbnabdhheoknfklmpddcdijjkmklkp', // G+ Photoes
   'endkpmfloggdajndjpoekmkjnkolfdbf', // Feedback Extension
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js
index a559be6..ef2adc4 100644
--- a/chrome/browser/resources/feedback/js/feedback.js
+++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -94,6 +94,8 @@
     return false;
   }
 
+  // Prevent double clicking from sending additional reports.
+  $('send-report-button').disabled = true;
   console.log('Feedback: Sending report');
   if (!feedbackInfo.attachedFile && attachedFileBlob) {
     feedbackInfo.attachedFile = { name: $('attach-file').value,
diff --git a/chrome/browser/resources/file_manager/action_choice.html b/chrome/browser/resources/file_manager/action_choice.html
index 13ced34..0d0041b 100644
--- a/chrome/browser/resources/file_manager/action_choice.html
+++ b/chrome/browser/resources/file_manager/action_choice.html
@@ -12,7 +12,7 @@
 
   <!-- Don't load action_choice_scripts.js when flattening is disabled. -->
   <if expr="0"><!-- </if>
-    <script src="js/action_choice_scripts.js"></script>
+    <script src="foreground/js/action_choice/action_choice_scripts.js"></script>
   <if expr="0"> --></if>
 
   <if expr="0">
@@ -38,18 +38,19 @@
     <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
     <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
 
-    <script src="js/async_util.js"></script>
-    <script src="js/util.js"></script>
-    <script src="js/file_type.js"></script>
-    <script src="js/path_util.js"></script>
-    <script src="js/volume_manager_wrapper.js"></script>
-    <script src="js/metadata/metadata_cache.js"></script>
-    <script src="js/metrics.js"></script>
-    <script src="js/image_editor/image_util.js"></script>
-    <script src="js/media/media_util.js"></script>
-    <script src="js/action_choice_util.js"></script>
+    <script src="common/js/async_util.js"></script>
+    <script src="common/js/util.js"></script>
+    <script src="common/js/path_util.js"></script>
 
-    <script src="js/action_choice.js"></script>
+    <script src="foreground/js/file_type.js"></script>
+    <script src="foreground/js/volume_manager_wrapper.js"></script>
+    <script src="foreground/js/metadata/metadata_cache.js"></script>
+    <script src="foreground/js/metrics.js"></script>
+    <script src="foreground/js/image_editor/image_util.js"></script>
+    <script src="foreground/js/media/media_util.js"></script>
+
+    <script src="foreground/js/action_choice/action_choice_util.js"></script>
+    <script src="foreground/js/action_choice/action_choice.js"></script>
   </if>
   <title>&#xFEFF;</title>
 </head>
diff --git a/chrome/browser/resources/file_manager/background/js/background.js b/chrome/browser/resources/file_manager/background/js/background.js
new file mode 100644
index 0000000..01565ad
--- /dev/null
+++ b/chrome/browser/resources/file_manager/background/js/background.js
@@ -0,0 +1,621 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Number of runtime errors catched in the background page.
+ * @type {number}
+ */
+var JSErrorCount = 0;
+
+/**
+ * Counts runtime JavaScript errors.
+ */
+window.onerror = function() { JSErrorCount++; };
+
+/**
+ * Type of a Files.app's instance launch.
+ * @enum {number}
+ */
+var LaunchType = Object.freeze({
+  ALWAYS_CREATE: 0,
+  FOCUS_ANY_OR_CREATE: 1,
+  FOCUS_SAME_OR_CREATE: 2
+});
+
+/**
+ * Root class of the background page.
+ * @constructor
+ */
+function Background() {
+  /**
+   * Map of all currently open app windows. The key is an app id.
+   * @type {Object.<string, AppWindow>}
+   */
+  this.appWindows = {};
+
+  /**
+   * Synchronous queue for asynchronous calls.
+   * @type {AsyncUtil.Queue}
+   */
+  this.queue = new AsyncUtil.Queue();
+
+  /**
+   * Progress center of the background page.
+   * @type {ProgressCenter}
+   */
+  this.progressCenter = new ProgressCenter();
+
+  /**
+   * Event handler for progress center.
+   * @type {ProgressCenter}
+   * @private
+   */
+  this.progressCenterHandler_ = new ProgressCenterHandler(
+      FileOperationManager.getInstance(),
+      this.progressCenter);
+
+  // Freeze self.
+  Object.freeze(this);
+
+  // Initialize handlers.
+  chrome.fileBrowserHandler.onExecute.addListener(this.onExecute_.bind(this));
+  chrome.app.runtime.onLaunched.addListener(this.onLaunched_.bind(this));
+  chrome.app.runtime.onRestarted.addListener(this.onRestarted_.bind(this));
+  chrome.contextMenus.onClicked.addListener(
+      this.onContextMenuClicked_.bind(this));
+
+  // Fetch strings and initialize the context menu.
+  this.queue.run(function(callback) {
+    chrome.fileBrowserPrivate.getStrings(function(strings) {
+      loadTimeData.data = strings;
+      this.initContextMenu_();
+      chrome.storage.local.set({strings: strings}, callback);
+    }.bind(this));
+  }.bind(this));
+}
+
+/**
+ * Wrapper for an app window.
+ *
+ * Expects the following from the app scripts:
+ * 1. The page load handler should initialize the app using |window.appState|
+ *    and call |util.platform.saveAppState|.
+ * 2. Every time the app state changes the app should update |window.appState|
+ *    and call |util.platform.saveAppState| .
+ * 3. The app may have |unload| function to persist the app state that does not
+ *    fit into |window.appState|.
+ *
+ * @param {string} url App window content url.
+ * @param {string} id App window id.
+ * @param {Object} options Options object to create it.
+ * @constructor
+ */
+function AppWindowWrapper(url, id, options) {
+  this.url_ = url;
+  this.id_ = id;
+  // Do deep copy for the template of options to assign own ID to the option
+  // params.
+  this.options_ = JSON.parse(JSON.stringify(options));
+  this.options_.id = url; // This is to make Chrome reuse window geometries.
+  this.window_ = null;
+  this.appState_ = null;
+  this.openingOrOpened_ = false;
+  this.queue = new AsyncUtil.Queue();
+  Object.seal(this);
+}
+
+/**
+ * Shift distance to avoid overlapping windows.
+ * @type {number}
+ * @const
+ */
+AppWindowWrapper.SHIFT_DISTANCE = 40;
+
+/**
+ * Gets similar windows, it means with the same initial url.
+ * @return {Array.<AppWindow>} List of similar windows.
+ * @private
+ */
+AppWindowWrapper.prototype.getSimilarWindows_ = function() {
+  var result = [];
+  for (var appID in background.appWindows) {
+    if (background.appWindows[appID].contentWindow.appInitialURL == this.url_)
+      result.push(background.appWindows[appID]);
+  }
+  return result;
+};
+
+/**
+ * Opens the window.
+ *
+ * @param {Object} appState App state.
+ * @param {function()=} opt_callback Completion callback.
+ */
+AppWindowWrapper.prototype.launch = function(appState, opt_callback) {
+  // Check if the window is opened or not.
+  if (this.openingOrOpened_) {
+    console.error('The window is already opened.');
+    if (opt_callback)
+      opt_callback();
+    return;
+  }
+  this.openingOrOpened_ = true;
+
+  // Save application state.
+  this.appState_ = appState;
+
+  // Get similar windows, it means with the same initial url, eg. different
+  // main windows of Files.app.
+  var similarWindows = this.getSimilarWindows_();
+
+  // Restore maximized windows, to avoid hiding them to tray, which can be
+  // confusing for users.
+  this.queue.run(function(nextStep) {
+    for (var index = 0; index < similarWindows.length; index++) {
+      if (similarWindows[index].isMaximized()) {
+        var createWindowAndRemoveListener = function() {
+          similarWindows[index].onRestored.removeListener(
+              createWindowAndRemoveListener);
+          nextStep();
+        };
+        similarWindows[index].onRestored.addListener(
+            createWindowAndRemoveListener);
+        similarWindows[index].restore();
+        return;
+      }
+    }
+    // If no maximized windows, then create the window immediately.
+    nextStep();
+  });
+
+  // Closure creating the window, once all preprocessing tasks are finished.
+  this.queue.run(function(nextStep) {
+    chrome.app.window.create(this.url_, this.options_, function(appWindow) {
+      this.window_ = appWindow;
+      nextStep();
+    }.bind(this));
+  }.bind(this));
+
+  // After creating.
+  this.queue.run(function(nextStep) {
+    var appWindow = this.window_;
+    if (similarWindows.length) {
+      // If we have already another window of the same kind, then shift this
+      // window to avoid overlapping with the previous one.
+
+      var bounds = appWindow.getBounds();
+      appWindow.moveTo(bounds.left + AppWindowWrapper.SHIFT_DISTANCE,
+                       bounds.top + AppWindowWrapper.SHIFT_DISTANCE);
+    }
+
+    background.appWindows[this.id_] = appWindow;
+    var contentWindow = appWindow.contentWindow;
+    contentWindow.appID = this.id_;
+    contentWindow.appState = this.appState_;
+    contentWindow.appInitialURL = this.url_;
+    if (window.IN_TEST)
+      contentWindow.IN_TEST = true;
+
+    appWindow.onClosed.addListener(function() {
+      if (contentWindow.unload)
+        contentWindow.unload();
+      if (contentWindow.saveOnExit) {
+        contentWindow.saveOnExit.forEach(function(entry) {
+          util.AppCache.update(entry.key, entry.value);
+        });
+      }
+      delete background.appWindows[this.id_];
+      chrome.storage.local.remove(this.id_);  // Forget the persisted state.
+      this.window_ = null;
+      this.openingOrOpened_ = false;
+      maybeCloseBackgroundPage();
+    }.bind(this));
+
+    if (opt_callback)
+      opt_callback();
+
+    nextStep();
+  }.bind(this));
+};
+
+/**
+ * Wrapper for a singleton app window.
+ *
+ * In addition to the AppWindowWrapper requirements the app scripts should
+ * have |reload| method that re-initializes the app based on a changed
+ * |window.appState|.
+ *
+ * @param {string} url App window content url.
+ * @param {Object|function()} options Options object or a function to return it.
+ * @constructor
+ */
+function SingletonAppWindowWrapper(url, options) {
+  AppWindowWrapper.call(this, url, url, options);
+}
+
+/**
+ * Inherits from AppWindowWrapper.
+ */
+SingletonAppWindowWrapper.prototype = {__proto__: AppWindowWrapper.prototype};
+
+/**
+ * Open the window.
+ *
+ * Activates an existing window or creates a new one.
+ *
+ * @param {Object} appState App state.
+ * @param {function()=} opt_callback Completion callback.
+ */
+SingletonAppWindowWrapper.prototype.launch = function(appState, opt_callback) {
+  // If the window is not opened yet, just call the parent method.
+  if (!this.openingOrOpened_) {
+    AppWindowWrapper.prototype.launch.call(this, appState, opt_callback);
+    return;
+  }
+
+  // If the window is already opened, reload the window.
+  // The queue is used to wait until the window is opened.
+  this.queue.run(function(nextStep) {
+    this.window_.contentWindow.appState = appState;
+    this.window_.contentWindow.reload();
+    this.window_.focus();
+    if (opt_callback)
+      opt_callback();
+    nextStep();
+  }.bind(this));
+};
+
+/**
+ * Reopen a window if its state is saved in the local storage.
+ */
+SingletonAppWindowWrapper.prototype.reopen = function() {
+  chrome.storage.local.get(this.id_, function(items) {
+    var value = items[this.id_];
+    if (!value)
+      return;  // No app state persisted.
+
+    try {
+      var appState = JSON.parse(value);
+    } catch (e) {
+      console.error('Corrupt launch data for ' + this.id_, value);
+      return;
+    }
+    this.launch(appState);
+  }.bind(this));
+};
+
+/**
+ * Prefix for the file manager window ID.
+ */
+var FILES_ID_PREFIX = 'files#';
+
+/**
+ * Regexp matching a file manager window ID.
+ */
+var FILES_ID_PATTERN = new RegExp('^' + FILES_ID_PREFIX + '(\\d*)$');
+
+/**
+ * Value of the next file manager window ID.
+ */
+var nextFileManagerWindowID = 0;
+
+/**
+ * File manager window create options.
+ * @type {Object}
+ * @const
+ */
+var FILE_MANAGER_WINDOW_CREATE_OPTIONS = Object.freeze({
+  defaultLeft: Math.round(window.screen.availWidth * 0.1),
+  defaultTop: Math.round(window.screen.availHeight * 0.1),
+  defaultWidth: Math.round(window.screen.availWidth * 0.8),
+  defaultHeight: Math.round(window.screen.availHeight * 0.8),
+  minWidth: 320,
+  minHeight: 240,
+  frame: 'none',
+  hidden: true,
+  transparentBackground: true,
+  singleton: false
+});
+
+/**
+ * @param {Object=} opt_appState App state.
+ * @param {number=} opt_id Window id.
+ * @param {LaunchType=} opt_type Launch type. Default: ALWAYS_CREATE.
+ * @param {function(string)=} opt_callback Completion callback with the App ID.
+ */
+function launchFileManager(opt_appState, opt_id, opt_type, opt_callback) {
+  var type = opt_type || LaunchType.ALWAYS_CREATE;
+
+  // Wait until all windows are created.
+  background.queue.run(function(onTaskCompleted) {
+    // Check if there is already a window with the same path. If so, then
+    // reuse it instead of opening a new one.
+    if (type == LaunchType.FOCUS_SAME_OR_CREATE ||
+        type == LaunchType.FOCUS_ANY_OR_CREATE) {
+      if (opt_appState && opt_appState.defaultPath) {
+        for (var key in background.appWindows) {
+          var contentWindow = background.appWindows[key].contentWindow;
+          if (contentWindow.appState &&
+              opt_appState.defaultPath == contentWindow.appState.defaultPath) {
+            background.appWindows[key].focus();
+            if (opt_callback)
+              opt_callback(key);
+            onTaskCompleted();
+            return;
+          }
+        }
+      }
+    }
+
+    // Focus any window if none is focused. Try restored first.
+    if (type == LaunchType.FOCUS_ANY_OR_CREATE) {
+      // If there is already a focused window, then finish.
+      for (var key in background.appWindows) {
+        // The isFocused() method should always be available, but in case
+        // Files.app's failed on some error, wrap it with try catch.
+        try {
+          if (background.appWindows[key].contentWindow.isFocused()) {
+            if (opt_callback)
+              opt_callback(key);
+            onTaskCompleted();
+            return;
+          }
+        } catch (e) {
+          console.error(e.message);
+        }
+      }
+      // Try to focus the first non-minimized window.
+      for (var key in background.appWindows) {
+        if (!background.appWindows[key].isMinimized()) {
+          background.appWindows[key].focus();
+          if (opt_callback)
+            opt_callback(key);
+          onTaskCompleted();
+          return;
+        }
+      }
+      // Restore and focus any window.
+      for (var key in background.appWindows) {
+        background.appWindows[key].focus();
+        if (opt_callback)
+          opt_callback(key);
+        onTaskCompleted();
+        return;
+      }
+    }
+
+    // Create a new instance in case of ALWAYS_CREATE type, or as a fallback
+    // for other types.
+
+    var id = opt_id || nextFileManagerWindowID;
+    nextFileManagerWindowID = Math.max(nextFileManagerWindowID, id + 1);
+    var appId = FILES_ID_PREFIX + id;
+
+    var appWindow = new AppWindowWrapper(
+        'main.html',
+        appId,
+        FILE_MANAGER_WINDOW_CREATE_OPTIONS);
+    appWindow.launch(opt_appState || {}, function() {
+      if (opt_callback)
+        opt_callback(appId);
+      onTaskCompleted();
+    });
+  });
+}
+
+/**
+ * Executes a file browser task.
+ *
+ * @param {string} action Task id.
+ * @param {Object} details Details object.
+ * @private
+ */
+Background.prototype.onExecute_ = function(action, details) {
+  var urls = details.entries.map(function(e) { return e.toURL(); });
+
+  switch (action) {
+    case 'play':
+      launchAudioPlayer({items: urls, position: 0});
+      break;
+
+    case 'watch':
+      launchVideoPlayer(urls[0]);
+      break;
+
+    default:
+      var launchEnable = null;
+      var queue = new AsyncUtil.Queue();
+      queue.run(function(nextStep) {
+        // If it is not auto-open (triggered by mounting external devices), we
+        // always launch Files.app.
+        if (action != 'auto-open') {
+          launchEnable = true;
+          nextStep();
+          return;
+        }
+        // If the disable-default-apps flag is on, Files.app is not opened
+        // automatically on device mount because it obstculs the manual test.
+        chrome.commandLinePrivate.hasSwitch('disable-default-apps',
+                                            function(flag) {
+          launchEnable = !flag;
+          nextStep();
+        });
+      });
+      queue.run(function(nextStep) {
+        if (!launchEnable) {
+          nextStep();
+          return;
+        }
+
+        // Every other action opens a Files app window.
+        var appState = {
+          params: {
+            action: action
+          },
+          defaultPath: details.entries[0].fullPath
+        };
+        // For mounted devices just focus any Files.app window. The mounted
+        // volume will appear on the navigation list.
+        var type = action == 'auto-open' ? LaunchType.FOCUS_ANY_OR_CREATE :
+            LaunchType.FOCUS_SAME_OR_CREATE;
+        launchFileManager(appState, /* App ID */ undefined, type, nextStep);
+      });
+      break;
+  }
+};
+
+/**
+ * Audio player window create options.
+ * @type {Object}
+ * @const
+ */
+var AUDIO_PLAYER_CREATE_OPTIONS = Object.freeze({
+  type: 'panel',
+  hidden: true,
+  minHeight: 35 + 58,
+  minWidth: 280,
+  height: 35 + 58,
+  width: 280,
+  singleton: false
+});
+
+var audioPlayer = new SingletonAppWindowWrapper('mediaplayer.html',
+                                                AUDIO_PLAYER_CREATE_OPTIONS);
+
+/**
+ * Launch the audio player.
+ * @param {Object} playlist Playlist.
+ */
+function launchAudioPlayer(playlist) {
+  audioPlayer.launch(playlist);
+}
+
+var videoPlayer = new SingletonAppWindowWrapper('video_player.html',
+                                                {hidden: true});
+
+/**
+ * Launch the video player.
+ * @param {string} url Video url.
+ */
+function launchVideoPlayer(url) {
+  videoPlayer.launch({url: url});
+}
+
+/**
+ * Launches the app.
+ * @private
+ */
+Background.prototype.onLaunched_ = function() {
+  if (nextFileManagerWindowID == 0) {
+    // The app just launched. Remove window state records that are not needed
+    // any more.
+    chrome.storage.local.get(function(items) {
+      for (var key in items) {
+        if (items.hasOwnProperty(key)) {
+          if (key.match(FILES_ID_PATTERN))
+            chrome.storage.local.remove(key);
+        }
+      }
+    });
+  }
+  launchFileManager(null, null, LaunchType.FOCUS_ANY_OR_CREATE);
+};
+
+/**
+ * Restarted the app, restore windows.
+ * @private
+ */
+Background.prototype.onRestarted_ = function() {
+  // Reopen file manager windows.
+  chrome.storage.local.get(function(items) {
+    for (var key in items) {
+      if (items.hasOwnProperty(key)) {
+        var match = key.match(FILES_ID_PATTERN);
+        if (match) {
+          var id = Number(match[1]);
+          try {
+            var appState = JSON.parse(items[key]);
+            launchFileManager(appState, id);
+          } catch (e) {
+            console.error('Corrupt launch data for ' + id);
+          }
+        }
+      }
+    }
+  });
+
+  // Reopen sub-applications.
+  audioPlayer.reopen();
+  videoPlayer.reopen();
+};
+
+/**
+ * Handles clicks on a custom item on the launcher context menu.
+ * @param {OnClickData} info Event details.
+ * @private
+ */
+Background.prototype.onContextMenuClicked_ = function(info) {
+  if (info.menuItemId == 'new-window') {
+    // Find the focused window (if any) and use it's current path for the
+    // new window. If not found, then launch with the default path.
+    for (var key in background.appWindows) {
+      try {
+        if (background.appWindows[key].contentWindow.isFocused()) {
+          var appState = {
+            defaultPath: background.appWindows[key].contentWindow.
+                appState.defaultPath
+          };
+          launchFileManager(appState);
+          return;
+        }
+      } catch (ignore) {
+        // The isFocused method may not be defined during initialization.
+        // Therefore, wrapped with a try-catch block.
+      }
+    }
+
+    // Launch with the default path.
+    launchFileManager();
+  }
+};
+
+/**
+ * Closes the background page, if it is not needed.
+ */
+function maybeCloseBackgroundPage() {
+  if (FileOperationManager.getInstance().hasQueuedTasks())
+    return;
+  var views = chrome.extension.getViews();
+  for (var i = 0; i < views.length; i++) {
+    if (views[i] !== window && !views[i].closing)
+      return;
+  }
+  close();
+}
+
+/**
+ * Initializes the context menu. Recreates if already exists.
+ * @private
+ */
+Background.prototype.initContextMenu_ = function() {
+  try {
+    chrome.contextMenus.remove('new-window');
+  } catch (ignore) {
+    // There is no way to detect if the context menu is already added, therefore
+    // try to recreate it every time.
+  }
+  chrome.contextMenus.create({
+    id: 'new-window',
+    contexts: ['launcher'],
+    title: str('NEW_WINDOW_BUTTON_LABEL')
+  });
+};
+
+/**
+ * Singleton instance of Background.
+ * @type {Background}
+ */
+window.background = new Background();
diff --git a/chrome/browser/resources/file_manager/background/js/file_operation_manager.js b/chrome/browser/resources/file_manager/background/js/file_operation_manager.js
new file mode 100644
index 0000000..023f831
--- /dev/null
+++ b/chrome/browser/resources/file_manager/background/js/file_operation_manager.js
@@ -0,0 +1,1434 @@
+// Copyright 2013 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.
+
+'use strict';
+
+/**
+ * Utilities for FileOperationManager.
+ */
+var fileOperationUtil = {};
+
+/**
+ * Simple wrapper for util.deduplicatePath. On error, this method translates
+ * the FileError to FileOperationManager.Error object.
+ *
+ * @param {DirectoryEntry} dirEntry The target directory entry.
+ * @param {string} relativePath The path to be deduplicated.
+ * @param {function(string)} successCallback Callback run with the deduplicated
+ *     path on success.
+ * @param {function(FileOperationManager.Error)} errorCallback Callback run on
+ *     error.
+ */
+fileOperationUtil.deduplicatePath = function(
+    dirEntry, relativePath, successCallback, errorCallback) {
+  util.deduplicatePath(
+      dirEntry, relativePath, successCallback,
+      function(err) {
+        var onFileSystemError = function(error) {
+          errorCallback(new FileOperationManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+        };
+
+        if (err.code == FileError.PATH_EXISTS_ERR) {
+          // Failed to uniquify the file path. There should be an existing
+          // entry, so return the error with it.
+          util.resolvePath(
+              dirEntry, relativePath,
+              function(entry) {
+                errorCallback(new FileOperationManager.Error(
+                    util.FileOperationErrorType.TARGET_EXISTS, entry));
+              },
+              onFileSystemError);
+          return;
+        }
+        onFileSystemError(err);
+      });
+};
+
+/**
+ * Traverses files/subdirectories of the given entry, and returns them.
+ * In addition, this method annotate the size of each entry. The result will
+ * include the entry itself.
+ *
+ * @param {Entry} entry The root Entry for traversing.
+ * @param {function(Array.<Entry>)} successCallback Called when the traverse
+ *     is successfully done with the array of the entries.
+ * @param {function(FileError)} errorCallback Called on error with the first
+ *     occurred error (i.e. following errors will just be discarded).
+ */
+fileOperationUtil.resolveRecursively = function(
+    entry, successCallback, errorCallback) {
+  var result = [];
+  var error = null;
+  var numRunningTasks = 0;
+
+  var maybeInvokeCallback = function() {
+    // If there still remain some running tasks, wait their finishing.
+    if (numRunningTasks > 0)
+      return;
+
+    if (error)
+      errorCallback(error);
+    else
+      successCallback(result);
+  };
+
+  // The error handling can be shared.
+  var onError = function(fileError) {
+    // If this is the first error, remember it.
+    if (!error)
+      error = fileError;
+    --numRunningTasks;
+    maybeInvokeCallback();
+  };
+
+  var process = function(entry) {
+    numRunningTasks++;
+    result.push(entry);
+    if (entry.isDirectory) {
+      // The size of a directory is 1 bytes here, so that the progress bar
+      // will work smoother.
+      // TODO(hidehiko): Remove this hack.
+      entry.size = 1;
+
+      // Recursively traverse children.
+      var reader = entry.createReader();
+      reader.readEntries(
+          function processSubEntries(subEntries) {
+            if (error || subEntries.length == 0) {
+              // If an error is found already, or this is the completion
+              // callback, then finish the process.
+              --numRunningTasks;
+              maybeInvokeCallback();
+              return;
+            }
+
+            for (var i = 0; i < subEntries.length; i++)
+              process(subEntries[i]);
+
+            // Continue to read remaining children.
+            reader.readEntries(processSubEntries, onError);
+          },
+          onError);
+    } else {
+      // For a file, annotate the file size.
+      entry.getMetadata(function(metadata) {
+        entry.size = metadata.size;
+        --numRunningTasks;
+        maybeInvokeCallback();
+      }, onError);
+    }
+  };
+
+  process(entry);
+};
+
+/**
+ * Copies source to parent with the name newName recursively.
+ * This should work very similar to FileSystem API's copyTo. The difference is;
+ * - The progress callback is supported.
+ * - The cancellation is supported.
+ *
+ * @param {Entry} source The entry to be copied.
+ * @param {DirectoryEntry} parent The entry of the destination directory.
+ * @param {string} newName The name of copied file.
+ * @param {function(string, string)} entryChangedCallback
+ *     Callback invoked when an entry is created with the source url and
+ *     the destination url.
+ * @param {function(string, number)} progressCallback Callback invoked
+ *     periodically during the copying. It takes the source url and the
+ *     processed bytes of it.
+ * @param {function(string)} successCallback Callback invoked when the copy
+ *     is successfully done with the url of the created entry.
+ * @param {function(FileError)} errorCallback Callback invoked when an error
+ *     is found.
+ * @return {function()} Callback to cancel the current file copy operation.
+ *     When the cancel is done, errorCallback will be called. The returned
+ *     callback must not be called more than once.
+ */
+fileOperationUtil.copyTo = function(
+    source, parent, newName, entryChangedCallback, progressCallback,
+    successCallback, errorCallback) {
+  var copyId = null;
+  var pendingCallbacks = [];
+
+  var onCopyProgress = function(progressCopyId, status) {
+    if (copyId == null) {
+      // If the copyId is not yet available, wait for it.
+      pendingCallbacks.push(
+          onCopyProgress.bind(null, progressCopyId, status));
+      return;
+    }
+
+    // This is not what we're interested in.
+    if (progressCopyId != copyId)
+      return;
+
+    switch (status.type) {
+      case 'begin_copy_entry':
+        break;
+
+      case 'end_copy_entry':
+        entryChangedCallback(status.sourceUrl, status.destinationUrl);
+        break;
+
+      case 'progress':
+        progressCallback(status.sourceUrl, status.size);
+        break;
+
+      case 'success':
+        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
+        successCallback(status.destinationUrl);
+        break;
+
+      case 'error':
+        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
+        errorCallback(util.createFileError(status.error));
+        break;
+
+      default:
+        // Found unknown state. Cancel the task, and return an error.
+        console.error('Unknown progress type: ' + status.type);
+        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
+        chrome.fileBrowserPrivate.cancelCopy(copyId);
+        errorCallback(util.createFileError(FileError.INVALID_STATE_ERR));
+    }
+  };
+
+  // Register the listener before calling startCopy. Otherwise some events
+  // would be lost.
+  chrome.fileBrowserPrivate.onCopyProgress.addListener(onCopyProgress);
+
+  // Then starts the copy.
+  chrome.fileBrowserPrivate.startCopy(
+      source.toURL(), parent.toURL(), newName, function(startCopyId) {
+        // last error contains the FileError code on error.
+        if (chrome.runtime.lastError) {
+          // Unsubscribe the progress listener.
+          chrome.fileBrowserPrivate.onCopyProgress.removeListener(
+              onCopyProgress);
+          errorCallback(util.createFileError(
+              Integer.parseInt(chrome.runtime.lastError, 10)));
+          return;
+        }
+
+        copyId = startCopyId;
+        for (var i = 0; i < pendingCallbacks.length; i++) {
+          pendingCallbacks[i]();
+        }
+      });
+
+  return function() {
+    // If copyId is not yet available, wait for it.
+    if (copyId == null) {
+      pendingCallbacks.push(function() {
+        chrome.fileBrowserPrivate.cancelCopy(copyId);
+      });
+      return;
+    }
+
+    chrome.fileBrowserPrivate.cancelCopy(copyId);
+  };
+};
+
+/**
+ * Thin wrapper of chrome.fileBrowserPrivate.zipSelection to adapt its
+ * interface similar to copyTo().
+ *
+ * @param {Array.<Entry>} sources The array of entries to be archived.
+ * @param {DirectoryEntry} parent The entry of the destination directory.
+ * @param {string} newName The name of the archive to be created.
+ * @param {function(FileEntry)} successCallback Callback invoked when the
+ *     operation is successfully done with the entry of the created archive.
+ * @param {function(FileError)} errorCallback Callback invoked when an error
+ *     is found.
+ */
+fileOperationUtil.zipSelection = function(
+    sources, parent, newName, successCallback, errorCallback) {
+  chrome.fileBrowserPrivate.zipSelection(
+      parent.toURL(),
+      sources.map(function(e) { return e.toURL(); }),
+      newName, function(success) {
+        if (!success) {
+          // Failed to create a zip archive.
+          errorCallback(
+              util.createFileError(FileError.INVALID_MODIFICATION_ERR));
+          return;
+        }
+
+        // Returns the created entry via callback.
+        parent.getFile(
+            newName, {create: false}, successCallback, errorCallback);
+      });
+};
+
+/**
+ * @constructor
+ */
+function FileOperationManager() {
+  this.copyTasks_ = [];
+  this.deleteTasks_ = [];
+  this.unloadTimeout_ = null;
+  this.taskIdCounter_ = 0;
+
+  this.eventRouter_ = new FileOperationManager.EventRouter();
+
+  Object.seal(this);
+}
+
+/**
+ * Get FileOperationManager instance. In case is hasn't been initialized, a new
+ * instance is created.
+ *
+ * @return {FileOperationManager} A FileOperationManager instance.
+ */
+FileOperationManager.getInstance = function() {
+  if (!FileOperationManager.instance_)
+    FileOperationManager.instance_ = new FileOperationManager();
+
+  return FileOperationManager.instance_;
+};
+
+/**
+ * Manages Event dispatching.
+ * Currently this can send three types of events: "copy-progress",
+ * "copy-operation-completed" and "delete".
+ *
+ * TODO(hidehiko): Reorganize the event dispatching mechanism.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+FileOperationManager.EventRouter = function() {
+};
+
+/**
+ * Extends cr.EventTarget.
+ */
+FileOperationManager.EventRouter.prototype.__proto__ = cr.EventTarget.prototype;
+
+/**
+ * Dispatches a simple "copy-progress" event with reason and current
+ * FileOperationManager status. If it is an ERROR event, error should be set.
+ *
+ * @param {string} reason Event type. One of "BEGIN", "PROGRESS", "SUCCESS",
+ *     "ERROR" or "CANCELLED". TODO(hidehiko): Use enum.
+ * @param {Object} status Current FileOperationManager's status. See also
+ *     FileOperationManager.getStatus().
+ * @param {string} taskId ID of task related with the event.
+ * @param {FileOperationManager.Error=} opt_error The info for the error. This
+ *     should be set iff the reason is "ERROR".
+ */
+FileOperationManager.EventRouter.prototype.sendProgressEvent = function(
+    reason, status, taskId, opt_error) {
+  var event = new Event('copy-progress');
+  event.reason = reason;
+  event.status = status;
+  event.taskId = taskId;
+  if (opt_error)
+    event.error = opt_error;
+  this.dispatchEvent(event);
+};
+
+/**
+ * Dispatches an event to notify that an entry is changed (created or deleted).
+ * @param {util.EntryChangedKind} kind The enum to represent if the entry is
+ *     created or deleted.
+ * @param {Entry} entry The changed entry.
+ */
+FileOperationManager.EventRouter.prototype.sendEntryChangedEvent = function(
+    kind, entry) {
+  var event = new Event('entry-changed');
+  event.kind = kind;
+  event.entry = entry;
+  this.dispatchEvent(event);
+};
+
+/**
+ * Dispatches an event to notify entries are changed for delete task.
+ *
+ * @param {string} reason Event type. One of "BEGIN", "PROGRESS", "SUCCESS",
+ *     or "ERROR". TODO(hidehiko): Use enum.
+ * @param {Array.<string>} urls An array of URLs which are affected by delete
+ *     operation.
+ * @param {string} taskId ID of task related with the event.
+ */
+FileOperationManager.EventRouter.prototype.sendDeleteEvent = function(
+    reason, urls, taskId) {
+  var event = new Event('delete');
+  event.reason = reason;
+  event.urls = urls;
+  this.dispatchEvent(event);
+};
+
+/**
+ * A record of a queued copy operation.
+ *
+ * Multiple copy operations may be queued at any given time.  Additional
+ * Tasks may be added while the queue is being serviced.  Though a
+ * cancel operation cancels everything in the queue.
+ *
+ * @param {util.FileOperationType} operationType The type of this operation.
+ * @param {Array.<Entry>} sourceEntries Array of source entries.
+ * @param {DirectoryEntry} targetDirEntry Target directory.
+ * @constructor
+ */
+FileOperationManager.Task = function(
+    operationType, sourceEntries, targetDirEntry) {
+  this.operationType = operationType;
+  this.sourceEntries = sourceEntries;
+  this.targetDirEntry = targetDirEntry;
+
+  /**
+   * An array of map from url to Entry being processed.
+   * @type {Array.<Object<string, Entry>>}
+   */
+  this.processingEntries = null;
+
+  /**
+   * Total number of bytes to be processed. Filled in initialize().
+   * @type {number}
+   */
+  this.totalBytes = 0;
+
+  /**
+   * Total number of already processed bytes. Updated periodically.
+   * @type {number}
+   */
+  this.processedBytes = 0;
+
+  this.deleteAfterCopy = false;
+
+  /**
+   * Set to true when cancel is requested.
+   * @private {boolean}
+   */
+  this.cancelRequested_ = false;
+
+  /**
+   * Callback to cancel the running process.
+   * @private {function()}
+   */
+  this.cancelCallback_ = null;
+
+  // TODO(hidehiko): After we support recursive copy, we don't need this.
+  // If directory already exists, we try to make a copy named 'dir (X)',
+  // where X is a number. When we do this, all subsequent copies from
+  // inside the subtree should be mapped to the new directory name.
+  // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should
+  // become 'dir (1)\file.txt'.
+  this.renamedDirectories_ = [];
+};
+
+/**
+ * @param {function()} callback When entries resolved.
+ */
+FileOperationManager.Task.prototype.initialize = function(callback) {
+};
+
+/**
+ * Updates copy progress status for the entry.
+ *
+ * @param {number} size Number of bytes that has been copied since last update.
+ */
+FileOperationManager.Task.prototype.updateFileCopyProgress = function(size) {
+  this.completedBytes += size;
+};
+
+/**
+ * Requests cancellation of this task.
+ * When the cancellation is done, it is notified via callbacks of run().
+ */
+FileOperationManager.Task.prototype.requestCancel = function() {
+  this.cancelRequested_ = true;
+  if (this.cancelCallback_) {
+    this.cancelCallback_();
+    this.cancelCallback_ = null;
+  }
+};
+
+/**
+ * Runs the task. Sub classes must implement this method.
+ *
+ * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function()} progressCallback Callback invoked periodically during
+ *     the operation.
+ * @param {function()} successCallback Callback run on success.
+ * @param {function(FileOperationManager.Error)} errorCallback Callback run on
+ *     error.
+ */
+FileOperationManager.Task.prototype.run = function(
+    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+};
+
+/**
+ * Get states of the task.
+ * TOOD(hirono): Removes this method and sets a task to progress events.
+ * @return {object} Status object.
+ */
+FileOperationManager.Task.prototype.getStatus = function() {
+  var numRemainingItems = this.countRemainingItems();
+  return {
+    operationType: this.operationType,
+    numRemainingItems: numRemainingItems,
+    totalBytes: this.totalBytes,
+    processedBytes: this.processedBytes,
+    processingEntry: this.getSingleEntry()
+  };
+};
+
+/**
+ * Counts the number of remaining items.
+ * @return {number} Number of remaining items.
+ */
+FileOperationManager.Task.prototype.countRemainingItems = function() {
+  var count = 0;
+  for (var i = 0; i < this.processingEntries.length; i++) {
+    for (var url in this.processingEntries[i]) {
+      count++;
+    }
+  }
+  return count;
+};
+
+/**
+ * Obtains the single processing entry. If there are multiple processing
+ * entries, it returns null.
+ * @return {Entry} First entry.
+ */
+FileOperationManager.Task.prototype.getSingleEntry = function() {
+  if (this.countRemainingItems() !== 1)
+    return null;
+  for (var i = 0; i < this.processingEntries.length; i++) {
+    var entryMap = this.processingEntries[i];
+    for (var name in entryMap)
+      return entryMap[name];
+  }
+  return null;
+};
+
+/**
+ * Task to copy entries.
+ *
+ * @param {Array.<Entry>} sourceEntries Array of source entries.
+ * @param {DirectoryEntry} targetDirEntry Target directory.
+ * @constructor
+ * @extends {FileOperationManager.Task}
+ */
+FileOperationManager.CopyTask = function(sourceEntries, targetDirEntry) {
+  FileOperationManager.Task.call(
+      this, util.FileOperationType.COPY, sourceEntries, targetDirEntry);
+};
+
+/**
+ * Extends FileOperationManager.Task.
+ */
+FileOperationManager.CopyTask.prototype.__proto__ =
+    FileOperationManager.Task.prototype;
+
+/**
+ * Initializes the CopyTask.
+ * @param {function()} callback Called when the initialize is completed.
+ */
+FileOperationManager.CopyTask.prototype.initialize = function(callback) {
+  var group = new AsyncUtil.Group();
+  // Correct all entries to be copied for status update.
+  this.processingEntries = [];
+  for (var i = 0; i < this.sourceEntries.length; i++) {
+    group.add(function(index, callback) {
+      fileOperationUtil.resolveRecursively(
+          this.sourceEntries[index],
+          function(resolvedEntries) {
+            var resolvedEntryMap = {};
+            for (var j = 0; j < resolvedEntries.length; ++j) {
+              var entry = resolvedEntries[j];
+              entry.processedBytes = 0;
+              resolvedEntryMap[entry.toURL()] = entry;
+            }
+            this.processingEntries[index] = resolvedEntryMap;
+            callback();
+          }.bind(this),
+          function(error) {
+            console.error(
+                'Failed to resolve for copy: %s',
+                util.getFileErrorMnemonic(error.code));
+          });
+    }.bind(this, i));
+  }
+
+  group.run(function() {
+    // Fill totalBytes.
+    this.totalBytes = 0;
+    for (var i = 0; i < this.processingEntries.length; i++) {
+      for (var url in this.processingEntries[i])
+        this.totalBytes += this.processingEntries[i][url].size;
+    }
+
+    callback();
+  }.bind(this));
+};
+
+/**
+ * Copies all entries to the target directory.
+ * Note: this method contains also the operation of "Move" due to historical
+ * reason.
+ *
+ * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function()} progressCallback Callback invoked periodically during
+ *     the copying.
+ * @param {function()} successCallback On success.
+ * @param {function(FileOperationManager.Error)} errorCallback On error.
+ * @override
+ */
+FileOperationManager.CopyTask.prototype.run = function(
+    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+  // TODO(hidehiko): We should be able to share the code to iterate on entries
+  // with serviceMoveTask_().
+  if (this.sourceEntries.length == 0) {
+    successCallback();
+    return;
+  }
+
+  // TODO(hidehiko): Delete after copy is the implementation of Move.
+  // Migrate the part into MoveTask.run().
+  var deleteOriginals = function() {
+    var count = this.sourceEntries.length;
+
+    var onEntryDeleted = function(entry) {
+      entryChangedCallback(util.EntryChangedKind.DELETED, entry);
+      count--;
+      if (!count)
+        successCallback();
+    };
+
+    var onFilesystemError = function(err) {
+      errorCallback(new FileOperationManager.Error(
+          util.FileOperationErrorType.FILESYSTEM_ERROR, err));
+    };
+
+    for (var i = 0; i < this.sourceEntries.length; i++) {
+      var entry = this.sourceEntries[i];
+      util.removeFileOrDirectory(
+          entry, onEntryDeleted.bind(null, entry), onFilesystemError);
+    }
+  }.bind(this);
+
+  AsyncUtil.forEach(
+      this.sourceEntries,
+      function(callback, entry, index) {
+        if (this.cancelRequested_) {
+          errorCallback(new FileOperationManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+        progressCallback();
+        this.processEntry_(
+            entry, this.targetDirEntry,
+            function(sourceUrl, destinationUrl) {
+              // Finalize the entry's progress state.
+              var entry = this.processingEntries[index][sourceUrl];
+              if (entry) {
+                this.processedBytes += entry.size - entry.processedBytes;
+                progressCallback();
+                delete this.processingEntries[index][sourceUrl];
+              }
+
+              webkitResolveLocalFileSystemURL(
+                  destinationUrl, function(destinationEntry) {
+                    entryChangedCallback(
+                        util.EntryChangedKind.CREATED, destinationEntry);
+                  });
+            }.bind(this),
+            function(source_url, size) {
+              var entry = this.processingEntries[index][source_url];
+              if (entry) {
+                this.processedBytes += size - entry.processedBytes;
+                entry.processedBytes = size;
+                progressCallback();
+              }
+            }.bind(this),
+            callback,
+            errorCallback);
+      },
+      function() {
+        if (this.deleteAfterCopy) {
+          deleteOriginals();
+        } else {
+          successCallback();
+        }
+      }.bind(this),
+      this);
+};
+
+/**
+ * Copies the source entry to the target directory.
+ *
+ * @param {Entry} sourceEntry An entry to be copied.
+ * @param {DirectoryEntry} destinationEntry The entry which will contain the
+ *     copied entry.
+ * @param {function(string, string)} entryChangedCallback
+ *     Callback invoked when an entry is created with the source url and
+ *     the destination url.
+ * @param {function(string, number)} progressCallback Callback invoked
+ *     periodically during the copying.
+ * @param {function()} successCallback On success.
+ * @param {function(FileOperationManager.Error)} errorCallback On error.
+ * @private
+ */
+FileOperationManager.CopyTask.prototype.processEntry_ = function(
+    sourceEntry, destinationEntry, entryChangedCallback, progressCallback,
+    successCallback, errorCallback) {
+  fileOperationUtil.deduplicatePath(
+      destinationEntry, sourceEntry.name,
+      function(destinationName) {
+        if (this.cancelRequested_) {
+          errorCallback(new FileOperationManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+        this.cancelCallback_ = fileOperationUtil.copyTo(
+            sourceEntry, destinationEntry, destinationName,
+            entryChangedCallback, progressCallback,
+            function(entry) {
+              this.cancelCallback_ = null;
+              successCallback();
+            }.bind(this),
+            function(error) {
+              this.cancelCallback_ = null;
+              errorCallback(new FileOperationManager.Error(
+                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+            }.bind(this));
+      }.bind(this),
+      errorCallback);
+};
+
+/**
+ * Task to move entries.
+ *
+ * @param {Array.<Entry>} sourceEntries Array of source entries.
+ * @param {DirectoryEntry} targetDirEntry Target directory.
+ * @constructor
+ * @extends {FileOperationManager.Task}
+ */
+FileOperationManager.MoveTask = function(sourceEntries, targetDirEntry) {
+  FileOperationManager.Task.call(
+      this, util.FileOperationType.MOVE, sourceEntries, targetDirEntry);
+};
+
+/**
+ * Extends FileOperationManager.Task.
+ */
+FileOperationManager.MoveTask.prototype.__proto__ =
+    FileOperationManager.Task.prototype;
+
+/**
+ * Initializes the MoveTask.
+ * @param {function()} callback Called when the initialize is completed.
+ */
+FileOperationManager.MoveTask.prototype.initialize = function(callback) {
+  // This may be moving from search results, where it fails if we
+  // move parent entries earlier than child entries. We should
+  // process the deepest entry first. Since move of each entry is
+  // done by a single moveTo() call, we don't need to care about the
+  // recursive traversal order.
+  this.sourceEntries.sort(function(entry1, entry2) {
+    return entry2.fullPath.length - entry1.fullPath.length;
+  });
+
+  this.processingEntries = [];
+  for (var i = 0; i < this.sourceEntries.length; i++) {
+    var processingEntryMap = {};
+    var entry = this.sourceEntries[i];
+
+    // The move should be done with updating the metadata. So here we assume
+    // all the file size is 1 byte. (Avoiding 0, so that progress bar can
+    // move smoothly).
+    // TODO(hidehiko): Remove this hack.
+    entry.size = 1;
+    processingEntryMap[entry.toURL()] = entry;
+    this.processingEntries[i] = processingEntryMap;
+  }
+
+  callback();
+};
+
+/**
+ * Moves all entries in the task.
+ *
+ * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function()} progressCallback Callback invoked periodically during
+ *     the moving.
+ * @param {function()} successCallback On success.
+ * @param {function(FileOperationManager.Error)} errorCallback On error.
+ * @override
+ */
+FileOperationManager.MoveTask.prototype.run = function(
+    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+  if (this.sourceEntries.length == 0) {
+    successCallback();
+    return;
+  }
+
+  AsyncUtil.forEach(
+      this.sourceEntries,
+      function(callback, entry, index) {
+        if (this.cancelRequested_) {
+          errorCallback(new FileOperationManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+        progressCallback();
+        FileOperationManager.MoveTask.processEntry_(
+            entry, this.targetDirEntry, entryChangedCallback,
+            function() {
+              // Erase the processing entry.
+              this.processingEntries[index] = {};
+              this.processedBytes++;
+              callback();
+            }.bind(this),
+            errorCallback);
+      },
+      function() {
+        successCallback();
+      }.bind(this),
+      this);
+};
+
+/**
+ * Moves the sourceEntry to the targetDirEntry in this task.
+ *
+ * @param {Entry} sourceEntry An entry to be moved.
+ * @param {DirectoryEntry} destinationEntry The entry of the destination
+ *     directory.
+ * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function()} successCallback On success.
+ * @param {function(FileOperationManager.Error)} errorCallback On error.
+ * @private
+ */
+FileOperationManager.MoveTask.processEntry_ = function(
+    sourceEntry, destinationEntry, entryChangedCallback, successCallback,
+    errorCallback) {
+  fileOperationUtil.deduplicatePath(
+      destinationEntry,
+      sourceEntry.name,
+      function(destinationName) {
+        sourceEntry.moveTo(
+            destinationEntry, destinationName,
+            function(movedEntry) {
+              entryChangedCallback(util.EntryChangedKind.CREATED, movedEntry);
+              entryChangedCallback(util.EntryChangedKind.DELETED, sourceEntry);
+              successCallback();
+            },
+            function(error) {
+              errorCallback(new FileOperationManager.Error(
+                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+            });
+      },
+      errorCallback);
+};
+
+/**
+ * Task to create a zip archive.
+ *
+ * @param {Array.<Entry>} sourceEntries Array of source entries.
+ * @param {DirectoryEntry} targetDirEntry Target directory.
+ * @param {DirectoryEntry} zipBaseDirEntry Base directory dealt as a root
+ *     in ZIP archive.
+ * @constructor
+ * @extends {FileOperationManager.Task}
+ */
+FileOperationManager.ZipTask = function(
+    sourceEntries, targetDirEntry, zipBaseDirEntry) {
+  FileOperationManager.Task.call(
+      this, util.FileOperationType.ZIP, sourceEntries, targetDirEntry);
+  this.zipBaseDirEntry = zipBaseDirEntry;
+};
+
+/**
+ * Extends FileOperationManager.Task.
+ */
+FileOperationManager.ZipTask.prototype.__proto__ =
+    FileOperationManager.Task.prototype;
+
+
+/**
+ * Initializes the ZipTask.
+ * @param {function()} callback Called when the initialize is completed.
+ */
+FileOperationManager.ZipTask.prototype.initialize = function(callback) {
+  var resolvedEntryMap = {};
+  var group = new AsyncUtil.Group();
+  for (var i = 0; i < this.sourceEntries.length; i++) {
+    group.add(function(index, callback) {
+      fileOperationUtil.resolveRecursively(
+          this.sourceEntries[index],
+          function(entries) {
+            for (var j = 0; j < entries.length; j++)
+              resolvedEntryMap[entries[j].toURL()] = entries[j];
+            callback();
+          },
+          function(error) {});
+    }.bind(this, i));
+  }
+
+  group.run(function() {
+    // For zip archiving, all the entries are processed at once.
+    this.processingEntries = [resolvedEntryMap];
+
+    this.totalBytes = 0;
+    for (var url in resolvedEntryMap)
+      this.totalBytes += resolvedEntryMap[url].size;
+
+    callback();
+  }.bind(this));
+};
+
+/**
+ * Runs a zip file creation task.
+ *
+ * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function()} progressCallback Callback invoked periodically during
+ *     the moving.
+ * @param {function()} successCallback On complete.
+ * @param {function(FileOperationManager.Error)} errorCallback On error.
+ * @override
+ */
+FileOperationManager.ZipTask.prototype.run = function(
+    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+  // TODO(hidehiko): we should localize the name.
+  var destName = 'Archive';
+  if (this.sourceEntries.length == 1) {
+    var entryPath = this.sourceEntries[0].fullPath;
+    var i = entryPath.lastIndexOf('/');
+    var basename = (i < 0) ? entryPath : entryPath.substr(i + 1);
+    i = basename.lastIndexOf('.');
+    destName = ((i < 0) ? basename : basename.substr(0, i));
+  }
+
+  fileOperationUtil.deduplicatePath(
+      this.targetDirEntry, destName + '.zip',
+      function(destPath) {
+        // TODO: per-entry zip progress update with accurate byte count.
+        // For now just set completedBytes to same value as totalBytes so
+        // that the progress bar is full.
+        this.processedBytes = this.totalBytes;
+        progressCallback();
+
+        // The number of elements in processingEntries is 1. See also
+        // initialize().
+        var entries = [];
+        for (var url in this.processingEntries[0])
+          entries.push(this.processingEntries[0][url]);
+
+        fileOperationUtil.zipSelection(
+            entries,
+            this.zipBaseDirEntry,
+            destPath,
+            function(entry) {
+              entryChangedCallback(util.EntryChangedKind.CREATE, entry);
+              successCallback();
+            },
+            function(error) {
+              errorCallback(new FileOperationManager.Error(
+                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+            });
+      }.bind(this),
+      errorCallback);
+};
+
+/**
+ * Error class used to report problems with a copy operation.
+ * If the code is UNEXPECTED_SOURCE_FILE, data should be a path of the file.
+ * If the code is TARGET_EXISTS, data should be the existing Entry.
+ * If the code is FILESYSTEM_ERROR, data should be the FileError.
+ *
+ * @param {util.FileOperationErrorType} code Error type.
+ * @param {string|Entry|FileError} data Additional data.
+ * @constructor
+ */
+FileOperationManager.Error = function(code, data) {
+  this.code = code;
+  this.data = data;
+};
+
+// FileOperationManager methods.
+
+/**
+ * Called before a new method is run in the manager. Prepares the manager's
+ * state for running a new method.
+ */
+FileOperationManager.prototype.willRunNewMethod = function() {
+  // Cancel any pending close actions so the file copy manager doesn't go away.
+  if (this.unloadTimeout_)
+    clearTimeout(this.unloadTimeout_);
+  this.unloadTimeout_ = null;
+};
+
+/**
+ * @return {Object} Status object.
+ */
+FileOperationManager.prototype.getStatus = function() {
+  // TODO(hidehiko): Reorganize the structure when delete queue is merged
+  // into copy task queue.
+  var result = {
+    // Set to util.FileOperationType if all the running/pending tasks is
+    // the same kind of task.
+    operationType: null,
+
+    // The number of entries to be processed.
+    numRemainingItems: 0,
+
+    // The total number of bytes to be processed.
+    totalBytes: 0,
+
+    // The number of bytes.
+    processedBytes: 0,
+
+    // Available if numRemainingItems == 1. Pointing to an Entry which is
+    // begin processed.
+    processingEntry: task.getSingleEntry()
+  };
+
+  var operationType =
+      this.copyTasks_.length > 0 ? this.copyTasks_[0].operationType : null;
+  var task = null;
+  for (var i = 0; i < this.copyTasks_.length; i++) {
+    task = this.copyTasks_[i];
+    if (task.operationType != operationType)
+      operationType = null;
+
+    // Assuming the number of entries is small enough, count every time.
+    result.numRemainingItems += task.countRemainingItems();
+    result.totalBytes += task.totalBytes;
+    result.processedBytes += task.processedBytes;
+  }
+
+  result.operationType = operationType;
+  return result;
+};
+
+/**
+ * Adds an event listener for the tasks.
+ * @param {string} type The name of the event.
+ * @param {function(Event)} handler The handler for the event.
+ *     This is called when the event is dispatched.
+ */
+FileOperationManager.prototype.addEventListener = function(type, handler) {
+  this.eventRouter_.addEventListener(type, handler);
+};
+
+/**
+ * Removes an event listener for the tasks.
+ * @param {string} type The name of the event.
+ * @param {function(Event)} handler The handler to be removed.
+ */
+FileOperationManager.prototype.removeEventListener = function(type, handler) {
+  this.eventRouter_.removeEventListener(type, handler);
+};
+
+/**
+ * Says if there are any tasks in the queue.
+ * @return {boolean} True, if there are any tasks.
+ */
+FileOperationManager.prototype.hasQueuedTasks = function() {
+  return this.copyTasks_.length > 0 || this.deleteTasks_.length > 0;
+};
+
+/**
+ * Unloads the host page in 5 secs of idling. Need to be called
+ * each time this.copyTasks_.length or this.deleteTasks_.length
+ * changed.
+ *
+ * @private
+ */
+FileOperationManager.prototype.maybeScheduleCloseBackgroundPage_ = function() {
+  if (!this.hasQueuedTasks()) {
+    if (this.unloadTimeout_ === null)
+      this.unloadTimeout_ = setTimeout(maybeCloseBackgroundPage, 5000);
+  } else if (this.unloadTimeout_) {
+    clearTimeout(this.unloadTimeout_);
+    this.unloadTimeout_ = null;
+  }
+};
+
+/**
+ * Completely clear out the copy queue, either because we encountered an error
+ * or completed successfully.
+ *
+ * @private
+ */
+FileOperationManager.prototype.resetQueue_ = function() {
+  this.copyTasks_ = [];
+  this.maybeScheduleCloseBackgroundPage_();
+};
+
+/**
+ * Requests the specified task to be canceled.
+ * @param {string} taskId ID of task to be canceled.
+ */
+FileOperationManager.prototype.requestTaskCancel = function(taskId) {
+  console.debug('requestTaskCancel', taskId);
+  var task = null;
+  for (var i = 0; i < this.copyTasks_.length; i++) {
+    task = this.copyTasks_[i];
+    if (task.taskId !== taskId)
+      continue;
+    task.requestCancel();
+    // If the task is not on progress, remove it immediately.
+    if (i !== 0) {
+      this.eventRouter_.sendProgressEvent('CANCELED',
+                                          task.getStatus(),
+                                          task.taskId);
+      this.copyTasks_.splice(i, 1);
+    }
+  }
+  for (var i = 0; i < this.deleteTasks_.length; i++) {
+    task = this.deleteTasks_[i];
+    if (task.taskId !== taskId)
+      continue;
+    task.requestCancel();
+    // If the task is not on progress, remove it immediately.
+    if (i != 0) {
+      this.eventRouter_.sendDeleteEvent(
+          'CANCELED',
+          task.entries.map(function(entry) {
+                             return util.makeFilesystemUrl(entry.fullPath);
+                           }),
+          task.taskId);
+      this.deleteTasks_.splice(i, 1);
+    }
+  }
+};
+
+/**
+ * Kick off pasting.
+ *
+ * @param {Array.<string>} sourcePaths Path of the source files.
+ * @param {string} targetPath The destination path of the target directory.
+ * @param {boolean} isMove True if the operation is "move", otherwise (i.e.
+ *     if the operation is "copy") false.
+ */
+FileOperationManager.prototype.paste = function(
+    sourcePaths, targetPath, isMove) {
+  // Do nothing if sourcePaths is empty.
+  if (sourcePaths.length == 0)
+    return;
+
+  var errorCallback = function(error) {
+    this.eventRouter_.sendProgressEvent(
+        'ERROR',
+        this.getStatus(),
+        this.generateTaskId_(null),
+        new FileOperationManager.Error(
+            util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+  }.bind(this);
+
+  var targetEntry = null;
+  var entries = [];
+
+  // Resolve paths to entries.
+  var resolveGroup = new AsyncUtil.Group();
+  resolveGroup.add(function(callback) {
+    webkitResolveLocalFileSystemURL(
+        util.makeFilesystemUrl(targetPath),
+        function(entry) {
+          if (!entry.isDirectory) {
+            // Found a non directory entry.
+            errorCallback(util.createFileError(FileError.TYPE_MISMATCH_ERR));
+            return;
+          }
+
+          targetEntry = entry;
+          callback();
+        },
+        errorCallback);
+  });
+
+  for (var i = 0; i < sourcePaths.length; i++) {
+    resolveGroup.add(function(sourcePath, callback) {
+      webkitResolveLocalFileSystemURL(
+          util.makeFilesystemUrl(sourcePath),
+          function(entry) {
+            entries.push(entry);
+            callback();
+          },
+          errorCallback);
+    }.bind(this, sourcePaths[i]));
+  }
+
+  resolveGroup.run(function() {
+    if (isMove) {
+      // Moving to the same directory is a redundant operation.
+      entries = entries.filter(function(entry) {
+        return targetEntry.fullPath + '/' + entry.name != entry.fullPath;
+      });
+
+      // Do nothing, if we have no entries to be moved.
+      if (entries.length == 0)
+        return;
+    }
+
+    this.queueCopy_(targetEntry, entries, isMove);
+  }.bind(this));
+};
+
+/**
+ * Checks if the move operation is available between the given two locations.
+ *
+ * @param {DirectoryEntry} sourceEntry An entry from the source.
+ * @param {DirectoryEntry} targetDirEntry Directory entry for the target.
+ * @return {boolean} Whether we can move from the source to the target.
+ */
+FileOperationManager.prototype.isMovable = function(sourceEntry,
+                                               targetDirEntry) {
+  return (PathUtil.isDriveBasedPath(sourceEntry.fullPath) &&
+          PathUtil.isDriveBasedPath(targetDirEntry.fullPath)) ||
+         (PathUtil.getRootPath(sourceEntry.fullPath) ==
+          PathUtil.getRootPath(targetDirEntry.fullPath));
+};
+
+/**
+ * Initiate a file copy.
+ *
+ * @param {DirectoryEntry} targetDirEntry Target directory.
+ * @param {Array.<Entry>} entries Entries to copy.
+ * @param {boolean} isMove In case of move.
+ * @return {FileOperationManager.Task} Copy task.
+ * @private
+ */
+FileOperationManager.prototype.queueCopy_ = function(
+    targetDirEntry, entries, isMove) {
+  // When copying files, null can be specified as source directory.
+  var task;
+  if (isMove) {
+    if (this.isMovable(entries[0], targetDirEntry)) {
+      task = new FileOperationManager.MoveTask(entries, targetDirEntry);
+    } else {
+      task = new FileOperationManager.CopyTask(entries, targetDirEntry);
+      task.deleteAfterCopy = true;
+    }
+  } else {
+    task = new FileOperationManager.CopyTask(entries, targetDirEntry);
+  }
+
+  task.taskId = this.generateTaskId_();
+  task.initialize(function() {
+    this.copyTasks_.push(task);
+    this.maybeScheduleCloseBackgroundPage_();
+    this.eventRouter_.sendProgressEvent('BEGIN', task.getStatus(), task.taskId);
+    if (this.copyTasks_.length == 1)
+      this.serviceAllTasks_();
+  }.bind(this));
+
+  return task;
+};
+
+/**
+ * Service all pending tasks, as well as any that might appear during the
+ * copy.
+ *
+ * @private
+ */
+FileOperationManager.prototype.serviceAllTasks_ = function() {
+  if (!this.copyTasks_.length) {
+    // All tasks have been serviced, clean up and exit.
+    this.resetQueue_();
+    return;
+  }
+
+  var onTaskProgress = function() {
+    this.eventRouter_.sendProgressEvent('PROGRESS',
+                                        this.copyTasks_[0].getStatus(),
+                                        this.copyTasks_[0].taskId);
+  }.bind(this);
+
+  var onEntryChanged = function(kind, entry) {
+    this.eventRouter_.sendEntryChangedEvent(kind, entry);
+  }.bind(this);
+
+  var onTaskError = function(err) {
+    var task = this.copyTasks_.shift();
+    var reason = err.data.code === FileError.ABORT_ERR ? 'CANCELED' : 'ERROR';
+    this.eventRouter_.sendProgressEvent(reason,
+                                        task.getStatus(),
+                                        task.taskId,
+                                        err);
+    this.serviceAllTasks_();
+  }.bind(this);
+
+  var onTaskSuccess = function() {
+    // The task at the front of the queue is completed. Pop it from the queue.
+    var task = this.copyTasks_.shift();
+    this.maybeScheduleCloseBackgroundPage_();
+    this.eventRouter_.sendProgressEvent('SUCCESS',
+                                        task.getStatus(),
+                                        task.taskId);
+    this.serviceAllTasks_();
+  }.bind(this);
+
+  var nextTask = this.copyTasks_[0];
+  this.eventRouter_.sendProgressEvent('PROGRESS',
+                                      nextTask.getStatus(),
+                                      nextTask.taskId);
+  nextTask.run(onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
+};
+
+/**
+ * Timeout before files are really deleted (to allow undo).
+ */
+FileOperationManager.DELETE_TIMEOUT = 30 * 1000;
+
+/**
+ * Schedules the files deletion.
+ *
+ * @param {Array.<Entry>} entries The entries.
+ */
+FileOperationManager.prototype.deleteEntries = function(entries) {
+  var task = {
+    entries: entries,
+    taskId: this.generateTaskId_()
+  };
+  this.deleteTasks_.push(task);
+  this.eventRouter_.sendDeleteEvent('BEGIN', entries.map(function(entry) {
+    return util.makeFilesystemUrl(entry.fullPath);
+  }), task.taskId);
+  this.maybeScheduleCloseBackgroundPage_();
+  if (this.deleteTasks_.length == 1)
+    this.serviceAllDeleteTasks_();
+};
+
+/**
+ * Service all pending delete tasks, as well as any that might appear during the
+ * deletion.
+ *
+ * Must not be called if there is an in-flight delete task.
+ *
+ * @private
+ */
+FileOperationManager.prototype.serviceAllDeleteTasks_ = function() {
+  // Returns the urls of the given task's entries.
+  var getTaskUrls = function(task) {
+    return task.entries.map(function(entry) {
+      return util.makeFilesystemUrl(entry.fullPath);
+    });
+  };
+
+  var onTaskSuccess = function() {
+    var urls = getTaskUrls(this.deleteTasks_[0]);
+    var taskId = this.deleteTasks_[0].taskId;
+    this.deleteTasks_.shift();
+    this.eventRouter_.sendDeleteEvent('SUCCESS', urls, taskId);
+
+    if (!this.deleteTasks_.length) {
+      // All tasks have been serviced, clean up and exit.
+      this.maybeScheduleCloseBackgroundPage_();
+      return;
+    }
+
+    var nextTask = this.deleteTasks_[0];
+    this.eventRouter_.sendDeleteEvent('PROGRESS',
+                                      urls,
+                                      nextTask.taskId);
+    this.serviceDeleteTask_(nextTask, onTaskSuccess, onTaskFailure);
+  }.bind(this);
+
+  var onTaskFailure = function(error) {
+    var urls = getTaskUrls(this.deleteTasks_[0]);
+    var taskId = this.deleteTasks_[0].taskId;
+    this.deleteTasks_ = [];
+    this.eventRouter_.sendDeleteEvent('ERROR',
+                                      urls,
+                                      taskId);
+    this.maybeScheduleCloseBackgroundPage_();
+  }.bind(this);
+
+  this.serviceDeleteTask_(this.deleteTasks_[0], onTaskSuccess, onTaskFailure);
+};
+
+/**
+ * Performs the deletion.
+ *
+ * @param {Object} task The delete task (see deleteEntries function).
+ * @param {function()} successCallback Callback run on success.
+ * @param {function(FileOperationManager.Error)} errorCallback Callback run on
+ *     error.
+ * @private
+ */
+FileOperationManager.prototype.serviceDeleteTask_ = function(
+    task, successCallback, errorCallback) {
+  var downcount = task.entries.length;
+  if (downcount == 0) {
+    successCallback();
+    return;
+  }
+
+  var filesystemError = null;
+  var onComplete = function() {
+    if (--downcount > 0)
+      return;
+
+    // All remove operations are processed. Run callback.
+    if (filesystemError) {
+      errorCallback(new FileOperationManager.Error(
+          util.FileOperationErrorType.FILESYSTEM_ERROR, filesystemError));
+    } else {
+      successCallback();
+    }
+  };
+
+  for (var i = 0; i < task.entries.length; i++) {
+    var entry = task.entries[i];
+    util.removeFileOrDirectory(
+        entry,
+        function(currentEntry) {
+          this.eventRouter_.sendEntryChangedEvent(
+              util.EntryChangedKind.DELETED, currentEntry);
+          onComplete();
+        }.bind(this, entry),
+        function(error) {
+          if (!filesystemError)
+            filesystemError = error;
+          onComplete();
+        });
+  }
+};
+
+/**
+ * Creates a zip file for the selection of files.
+ *
+ * @param {Entry} dirEntry The directory containing the selection.
+ * @param {Array.<Entry>} selectionEntries The selected entries.
+ */
+FileOperationManager.prototype.zipSelection = function(
+    dirEntry, selectionEntries) {
+  var zipTask = new FileOperationManager.ZipTask(
+      selectionEntries, dirEntry, dirEntry);
+  zipTask.taskId = this.generateTaskId_(this.copyTasks_);
+  zipTask.zip = true;
+  zipTask.initialize(function() {
+    this.copyTasks_.push(zipTask);
+    this.eventRouter_.sendProgressEvent('BEGIN',
+                                        zipTask.getStatus(),
+                                        zipTask.taskId);
+    if (this.copyTasks_.length == 1)
+      this.serviceAllTasks_();
+  }.bind(this));
+};
+
+/**
+ * Generates new task ID.
+ *
+ * @return {string} New task ID.
+ * @private
+ */
+FileOperationManager.prototype.generateTaskId_ = function() {
+  return 'file-operation-' + this.taskIdCounter_++;
+};
diff --git a/chrome/browser/resources/file_manager/background/js/progress_center.js b/chrome/browser/resources/file_manager/background/js/progress_center.js
new file mode 100644
index 0000000..de087aa
--- /dev/null
+++ b/chrome/browser/resources/file_manager/background/js/progress_center.js
@@ -0,0 +1,471 @@
+// Copyright 2013 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.
+
+'use strict';
+
+/**
+ * Progress center at the background page.
+ * @constructor
+ */
+var ProgressCenter = function() {
+  cr.EventTarget.call(this);
+
+  /**
+   * Default container.
+   * @type {ProgressItemContainer}
+   * @private
+   */
+  this.targetContainer_ = ProgressItemContainer.CLIENT;
+
+  /**
+   * Current items managed by the progress center.
+   * @type {Array.<ProgressItem>}
+   * @private
+   */
+  this.items_ = [];
+
+  /**
+   * Timeout callback to remove items.
+   * @type {TimeoutManager}
+   * @private
+   */
+  this.resetTimeout_ = new ProgressCenter.TimeoutManager(
+      this.reset_.bind(this));
+};
+
+/**
+ * The default amount of milliseconds time, before a progress item will reset
+ * after the last complete.
+ * @type {number}
+ * @private
+ * @const
+ */
+ProgressCenter.RESET_DELAY_TIME_MS_ = 5000;
+
+/**
+ * Utility for timeout callback.
+ *
+ * @param {function(*):*} callback Callbakc function.
+ * @constructor
+ */
+ProgressCenter.TimeoutManager = function(callback) {
+  this.callback_ = callback;
+  this.id_ = null;
+  Object.seal(this);
+};
+
+/**
+ * Requests timeout. Previous request is canceled.
+ * @param {number} milliseconds Time to invoke the callback function.
+ */
+ProgressCenter.TimeoutManager.prototype.request = function(milliseconds) {
+  if (this.id_)
+    clearTimeout(this.id_);
+  this.id_ = setTimeout(function() {
+    this.id_ = null;
+    this.callback_();
+  }.bind(this), milliseconds);
+};
+
+ProgressCenter.prototype = {
+  __proto__: cr.EventTarget.prototype,
+
+  /**
+   * Obtains the items to be displayed in the application window.
+   * @private
+   */
+  get applicationItems() {
+    return this.items_.filter(function(item) {
+      return item.container == ProgressItemContainer.CLIENT;
+    });
+  }
+};
+
+/**
+ * Updates the item in the progress center.
+ * If the item has a new ID, the item is added to the item list.
+ *
+ * @param {ProgressCenterItem} item Updated item.
+ */
+ProgressCenter.prototype.updateItem = function(item) {
+  var index = this.getItemIndex_(item.id);
+  if (index === -1) {
+    item.container = this.targetContainer_;
+    this.items_.push(item);
+  } else {
+    this.items_[index] = item;
+  }
+
+  if (item.status !== ProgressItemState.PROGRESSING)
+    this.resetTimeout_.request(ProgressCenter.RESET_DELAY_TIME_MS_);
+
+  var event = new Event(ProgressCenterEvent.ITEM_UPDATED);
+  event.item = item;
+  this.dispatchEvent(event);
+};
+
+/**
+ * Requests to cancel the progress item.
+ * @param {string} id Progress ID to be requested to cancel.
+ */
+ProgressCenter.prototype.requestCancel = function(id) {
+  var item = this.getItemById(id);
+  if (item && item.cancelCallback)
+    item.cancelCallback();
+};
+
+/**
+ * Switches the default container.
+ * @param {ProgressItemContainer} newContainer New value of the default
+ *     container.
+ */
+ProgressCenter.prototype.switchContainer = function(newContainer) {
+  if (this.targetContainer_ === newContainer)
+    return;
+
+  // Current items to be moved to the notification center.
+  if (newContainer == ProgressItemContainer.NOTIFICATION) {
+    var items = this.applicationItems;
+    for (var i = 0; i < items.length; i++) {
+      items[i].container = ProgressItemContainer.NOTIFICATION;
+      this.postItemToNotification_(items);
+    }
+  }
+
+  // The items in the notification center does not come back to the Files.app
+  // clients.
+
+  // Assign the new value.
+  this.targetContainer_ = newContainer;
+};
+
+/**
+ * Obtains the summarized item to be displayed in the closed progress center
+ * panel.
+ * @return {ProgressCenterItem} Summarized item. Returns null if there is no
+ *     item.
+ */
+ProgressCenter.prototype.getSummarizedItem = function() {
+  var applicationItems = this.applicationItems;
+  if (applicationItems.length == 0)
+    return null;
+  if (applicationItems.length == 1)
+    return applicationItems[0];
+  var summarizedItem = new ProgressCenterItem();
+  summarizedItem.summarized = true;
+  var completeCount = 0;
+  var progressingCount = 0;
+  var canceledCount = 0;
+  var errorCount = 0;
+  for (var i = 0; i < applicationItems.length; i++) {
+    switch (applicationItems[i].state) {
+      case ProgressItemState.COMPLETE:
+        completeCount++;
+        break;
+      case ProgressItemState.PROGRESSING:
+        progressingCount++;
+        break;
+      case ProgressItemState.ERROR:
+        errorCount++;
+        continue;
+      case ProgressItemState.CANCELED:
+        canceledCount++;
+        continue;
+    }
+    summarizedItem.progressMax += applicationItems[i].progressMax;
+    summarizedItem.progressValue += applicationItems[i].progressValue;
+  }
+  var messages = [];
+  if (completeCount)
+    messages.push(completeCount + ' complete');
+  if (progressingCount)
+    messages.push(progressingCount + ' active');
+  if (canceledCount)
+    messages.push(canceledCount + ' canceled');
+  if (errorCount)
+    messages.push(errorCount + ' error');
+  summarizedItem.message = messages.join(', ') + '.';
+  summarizedItem.state =
+      completeCount + progressingCount == 0 ? ProgressItemState.CANCELED :
+      progressingCount > 0 ? ProgressItemState.PROGRESSING :
+      ProgressItemState.COMPLETE;
+  return summarizedItem;
+};
+
+/**
+ * Obtains item by ID.
+ * @param {string} id ID of progress item.
+ * @return {ProgressCenterItem} Progress center item having the specified
+ *     ID. Null if the item is not found.
+ */
+ProgressCenter.prototype.getItemById = function(id) {
+  return this.items_[this.getItemIndex_(id)];
+};
+
+/**
+ * Obtains item index that have the specifying ID.
+ * @param {string} id Item ID.
+ * @return {number} Item index. Returns -1 If the item is not found.
+ * @private
+ */
+ProgressCenter.prototype.getItemIndex_ = function(id) {
+  for (var i = 0; i < this.items_.length; i++) {
+    if (this.items_[i].id === id)
+      return i;
+  }
+  return -1;
+};
+
+/**
+ * Passes the item to the ChromeOS's message center.
+ *
+ * TODO(hirono): Implement the method.
+ *
+ * @private
+ */
+ProgressCenter.prototype.passItemsToNotification_ = function() {
+
+};
+
+/**
+ * Hides the progress center if there is no progressing items.
+ * @private
+ */
+ProgressCenter.prototype.reset_ = function() {
+  // If we have a progressing item, stop reset.
+  for (var i = 0; i < this.items_.length; i++) {
+    if (this.items_[i].state == ProgressItemState.PROGRESSING)
+      return;
+  }
+
+  // Reset items.
+  this.items_.splice(0, this.items_.length);
+
+  // Dispatch a event.
+  this.dispatchEvent(new Event(ProgressCenterEvent.RESET));
+};
+
+/**
+ * An event handler for progress center.
+ * @param {FileOperationManager} fileOperationManager File operation manager.
+ * @param {ProgressCenter} progressCenter Progress center.
+ * @constructor
+ */
+var ProgressCenterHandler = function(fileOperationManager, progressCenter) {
+  /**
+   * Number of deleted files.
+   * @type {number}
+   * @private
+   */
+  this.totalDeleted_ = 0;
+
+  /**
+   * File operation manager.
+   * @type {FileOperationManager}
+   * @private
+   */
+  this.fileOperationManager_ = fileOperationManager;
+
+  /**
+   * Progress center.
+   * @type {progressCenter}
+   * @private
+   */
+  this.progressCenter_ = progressCenter;
+
+  // Seal the object.
+  Object.seal(this);
+
+  // Register event.
+  fileOperationManager.addEventListener('copy-progress',
+                                        this.onCopyProgress_.bind(this));
+  fileOperationManager.addEventListener('delete',
+                                        this.onDeleteProgress_.bind(this));
+};
+
+/**
+ * Generate a progress message from the event.
+ * @param {Event} event Progress event.
+ * @return {string} message.
+ * @private
+ */
+ProgressCenterHandler.getMessage_ = function(event) {
+  if (event.reason === 'ERROR') {
+    switch (event.error.code) {
+      case util.FileOperationErrorType.TARGET_EXISTS:
+        var name = event.error.data.name;
+        if (event.error.data.isDirectory)
+          name += '/';
+        switch (event.status.operationType) {
+          case 'COPY': return strf('COPY_TARGET_EXISTS_ERROR', name);
+          case 'MOVE': return strf('MOVE_TARGET_EXISTS_ERROR', name);
+          case 'ZIP': return strf('ZIP_TARGET_EXISTS_ERROR', name);
+          default: return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
+        }
+
+      case util.FileOperationErrorType.FILESYSTEM_ERROR:
+        var detail = util.getFileErrorString(event.error.data.code);
+        switch (event.status.operationType) {
+          case 'COPY': return strf('COPY_FILESYSTEM_ERROR', detail);
+          case 'MOVE': return strf('MOVE_FILESYSTEM_ERROR', detail);
+          case 'ZIP': return strf('ZIP_FILESYSTEM_ERROR', detail);
+          default: return strf('TRANSFER_FILESYSTEM_ERROR', detail);
+        }
+
+      default:
+        switch (event.status.operationType) {
+          case 'COPY': return strf('COPY_UNEXPECTED_ERROR', event.error);
+          case 'MOVE': return strf('MOVE_UNEXPECTED_ERROR', event.error);
+          case 'ZIP': return strf('ZIP_UNEXPECTED_ERROR', event.error);
+          default: return strf('TRANSFER_UNEXPECTED_ERROR', event.error);
+        }
+    }
+  } else if (event.status.numRemainingItems === 1) {
+    var name = event.status.processingEntry.name;
+    switch (event.status.operationType) {
+      case 'COPY': return strf('COPY_FILE_NAME', name);
+      case 'MOVE': return strf('MOVE_FILE_NAME', name);
+      case 'ZIP': return strf('ZIP_FILE_NAME', name);
+      default: return strf('TRANSFER_FILE_NAME', name);
+    }
+  } else {
+    var remainNumber = event.status.numRemainingItems;
+    switch (event.status.operationType) {
+      case 'COPY': return strf('COPY_ITEMS_REMAINING', remainNumber);
+      case 'MOVE': return strf('MOVE_ITEMS_REMAINING', remainNumber);
+      case 'ZIP': return strf('ZIP_ITEMS_REMAINING', remainNumber);
+      default: return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
+    }
+  }
+};
+
+/**
+ * Generate a delete message from the event.
+ * @param {Event} event Progress event.
+ * @param {number} totalDeleted Total number of deleted files.
+ * @return {string} message.
+ * @private
+ */
+ProgressCenterHandler.getDeleteMessage_ = function(event, totalDeleted) {
+  if (totalDeleted === 1) {
+    var fullPath = util.extractFilePath(event.urls[0]);
+    var fileName = PathUtil.split(fullPath).pop();
+    return strf('DELETED_MESSAGE', fileName);
+  } else {
+    return strf('DELETED_MESSAGE_PLURAL', totalDeleted);
+  }
+};
+
+/**
+ * Handles the copy-progress event.
+ * @param {Event} event The copy-progress event.
+ * @private
+ */
+ProgressCenterHandler.prototype.onCopyProgress_ = function(event) {
+  var progressCenter = this.progressCenter_;
+  var item;
+  switch (event.reason) {
+    case 'BEGIN':
+      item = new ProgressCenterItem();
+      item.id = event.taskId;
+      item.message = ProgressCenterHandler.getMessage_(event);
+      item.progressMax = event.status.totalBytes;
+      item.progressValue = event.status.processedBytes;
+      item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind(
+          this.fileOperationManager_,
+          event.taskId);
+      progressCenter.updateItem(item);
+      break;
+
+    case 'PROGRESS':
+      item = progressCenter.getItemById(event.taskId);
+      if (!item) {
+        console.error('Cannot find copying item.');
+        return;
+      }
+      item.message = ProgressCenterHandler.getMessage_(event);
+      item.progressValue = event.status.processedBytes;
+      progressCenter.updateItem(item);
+      break;
+
+    case 'SUCCESS':
+    case 'CANCELED':
+    case 'ERROR':
+      item = progressCenter.getItemById(event.taskId);
+      if (!item) {
+        // ERROR events can be dispatched before BEGIN events.
+        item = new ProgressCenterItem();
+        item.id = event.taskId;
+        item.progressMax = 1;
+      }
+      if (event.reason === 'SUCCESS') {
+        // TODO(hirono): Add a message for complete.
+        item.state = ProgressItemState.COMPLETE;
+        item.progressValue = item.progressMax;
+      } else if (event.reason === 'CANCELED') {
+        item.message = strf('COPY_CANCELLED');
+        item.state = ProgressItemState.CANCELED;
+      } else {
+        item.message = ProgressCenterHandler.getMessage_(event);
+        item.state = ProgressItemState.ERROR;
+      }
+      progressCenter.updateItem(item);
+      break;
+  }
+};
+
+/**
+ * Handles the delete event.
+ * @param {Event} event The delete event.
+ * @private
+ */
+ProgressCenterHandler.prototype.onDeleteProgress_ = function(event) {
+  var progressCenter = this.progressCenter_;
+  var item;
+  switch (event.reason) {
+    case 'BEGIN':
+      this.totalDeleted_ = 0;
+      item = new ProgressCenterItem();
+      item.id = event.taskId;
+      // TODO(hirono): Specifying the correct message.
+      item.message =
+          ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+      item.progressMax = 100;
+      // TODO(hirono): Specify the cancel handler to the item.
+      progressCenter.updateItem(item);
+      break;
+
+    case 'PROGRESS':
+      item = progressCenter.getItemById(event.taskId);
+      if (!item) {
+        console.error('Cannot find deleting item.');
+        return;
+      }
+      this.totalDeleted_ += event.urls.length;
+      item.message =
+          ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+      progressCenter.updateItem(item);
+      break;
+
+    case 'SUCCESS':
+    case 'ERROR':
+      item = progressCenter.getItemById(event.taskId);
+      if (!item) {
+        console.error('Cannot find deleting item.');
+        return;
+      }
+      if (event.reason === 'SUCCESS') {
+        this.totalDeleted_ += event.urls.length;
+        item.message =
+            ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+        item.state = ProgressItemState.COMPLETE;
+        item.progressValue = item.progressMax;
+      } else {
+        item.message = str('DELETE_ERROR');
+        item.state = ProgressItemState.ERROR;
+      }
+      progressCenter.updateItem(item);
+      break;
+  }
+};
diff --git a/chrome/browser/resources/file_manager/background/js/test_util.js b/chrome/browser/resources/file_manager/background/js/test_util.js
new file mode 100644
index 0000000..e43569e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/background/js/test_util.js
@@ -0,0 +1,771 @@
+// Copyright (c) 2013 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.
+
+/**
+ * Namespace for test related things.
+ */
+var test = test || {};
+
+/**
+ * Namespace for test utility functions.
+ *
+ * Public functions in the test.util.sync and the test.util.async namespaces are
+ * published to test cases and can be called by using callRemoteTestUtil. The
+ * arguments are serialized as JSON internally. If application ID is passed to
+ * callRemoteTestUtil, the content window of the application is added as the
+ * first argument. The functions in the test.util.async namespace are passed the
+ * callback function as the last argument.
+ */
+test.util = {};
+
+/**
+ * Namespace for synchronous utility functions.
+ */
+test.util.sync = {};
+
+/**
+ * Namespace for asynchronous utility functions.
+ */
+test.util.async = {};
+
+/**
+ * Extension ID of the testing extension.
+ * @type {string}
+ * @const
+ */
+test.util.TESTING_EXTENSION_ID = 'oobinhbdbiehknkpbpejbbpdbkdjmoco';
+
+/**
+ * Interval of checking a condition in milliseconds.
+ * @type {number}
+ * @const
+ * @private
+ */
+test.util.WAITTING_INTERVAL_ = 50;
+
+/**
+ * Repeats the function until it returns true.
+ * @param {function()} closure Function expected to return true.
+ * @private
+ */
+test.util.repeatUntilTrue_ = function(closure) {
+  var step = function() {
+    if (closure())
+      return;
+    setTimeout(step, test.util.WAITTING_INTERVAL_);
+  };
+  step();
+};
+
+/**
+ * Opens the main Files.app's window and waits until it is ready.
+ *
+ * @param {Object} appState App state.
+ * @param {function(string)} callback Completion callback with the new window's
+ *     App ID.
+ */
+test.util.async.openMainWindow = function(appState, callback) {
+  var steps = [
+    function() {
+      launchFileManager(appState,
+                        undefined,  // opt_type
+                        undefined,  // opt_id
+                        steps.shift());
+    },
+    function(appId) {
+      test.util.repeatUntilTrue_(function() {
+        if (!background.appWindows[appId])
+          return false;
+        var contentWindow = background.appWindows[appId].contentWindow;
+        var table = contentWindow.document.querySelector('#detail-table');
+        if (!table)
+          return false;
+        callback(appId);
+        return true;
+      });
+    }
+  ];
+  steps.shift()();
+};
+
+/**
+ * Waits for a window with the specified App ID prefix. Eg. `files` will match
+ * windows such as files#0, files#1, etc.
+ *
+ * @param {string} appIdPrefix ID prefix of the requested window.
+ * @param {function(string)} callback Completion callback with the new window's
+ *     App ID.
+ */
+test.util.async.waitForWindow = function(appIdPrefix, callback) {
+  test.util.repeatUntilTrue_(function() {
+    for (var appId in background.appWindows) {
+      if (appId.indexOf(appIdPrefix) == 0 &&
+          background.appWindows[appId].contentWindow) {
+        callback(appId);
+        return true;
+      }
+    }
+    return false;
+  });
+};
+
+/**
+ * Gets a document in the Files.app's window, including iframes.
+ *
+ * @param {Window} contentWindow Window to be used.
+ * @param {string=} opt_iframeQuery Query for the iframe.
+ * @return {Document=} Returns the found document or undefined if not found.
+ * @private
+ */
+test.util.sync.getDocument_ = function(contentWindow, opt_iframeQuery) {
+  if (opt_iframeQuery) {
+    var iframe = contentWindow.document.querySelector(opt_iframeQuery);
+    return iframe && iframe.contentWindow && iframe.contentWindow.document;
+  }
+
+  return contentWindow.document;
+};
+
+/**
+ * Gets total Javascript error count from each app window.
+ * @return {number} Error count.
+ */
+test.util.sync.getErrorCount = function() {
+  var totalCount = JSErrorCount;
+  for (var appId in background.appWindows) {
+    var contentWindow = background.appWindows[appId].contentWindow;
+    if (contentWindow.JSErrorCount)
+      totalCount += contentWindow.JSErrorCount;
+  }
+  return totalCount;
+};
+
+/**
+ * Resizes the window to the specified dimensions.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {number} width Window width.
+ * @param {number} height Window height.
+ * @return {boolean} True for success.
+ */
+test.util.sync.resizeWindow = function(contentWindow, width, height) {
+  background.appWindows[contentWindow.appID].resizeTo(width, height);
+  return true;
+};
+
+/**
+ * Returns an array with the files currently selected in the file manager.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @return {Array.<string>} Array of selected files.
+ */
+test.util.sync.getSelectedFiles = function(contentWindow) {
+  var table = contentWindow.document.querySelector('#detail-table');
+  var rows = table.querySelectorAll('li');
+  var selected = [];
+  for (var i = 0; i < rows.length; ++i) {
+    if (rows[i].hasAttribute('selected')) {
+      selected.push(
+          rows[i].querySelector('.filename-label').textContent);
+    }
+  }
+  return selected;
+};
+
+/**
+ * Returns an array with the files on the file manager's file list.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @return {Array.<Array.<string>>} Array of rows.
+ */
+test.util.sync.getFileList = function(contentWindow) {
+  var table = contentWindow.document.querySelector('#detail-table');
+  var rows = table.querySelectorAll('li');
+  var fileList = [];
+  for (var j = 0; j < rows.length; ++j) {
+    var row = rows[j];
+    fileList.push([
+      row.querySelector('.filename-label').textContent,
+      row.querySelector('.size').textContent,
+      row.querySelector('.type').textContent,
+      row.querySelector('.date').textContent
+    ]);
+  }
+  return fileList;
+};
+
+/**
+ * Checkes if the given label and path of the volume are selected.
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} label Correct label the selected volume should have.
+ * @param {string} path Correct path the selected volume should have.
+ * @return {boolean} True for success.
+ */
+test.util.sync.checkSelectedVolume = function(contentWindow, label, path) {
+  var list = contentWindow.document.querySelector('#navigation-list');
+  var rows = list.querySelectorAll('li');
+  var selected = [];
+  for (var i = 0; i < rows.length; ++i) {
+    if (rows[i].hasAttribute('selected'))
+      selected.push(rows[i]);
+  }
+  // Selected item must be one.
+  if (selected.length !== 1)
+    return false;
+
+  if (selected[0].modelItem.path !== path ||
+      selected[0].querySelector('.root-label').textContent !== label) {
+    return false;
+  }
+
+  return true;
+};
+
+/**
+ * Waits until the window is set to the specified dimensions.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {number} width Requested width.
+ * @param {number} height Requested height.
+ * @param {function(Object)} callback Success callback with the dimensions.
+ */
+test.util.async.waitForWindowGeometry = function(
+    contentWindow, width, height, callback) {
+  test.util.repeatUntilTrue_(function() {
+    if (contentWindow.innerWidth == width &&
+        contentWindow.innerHeight == height) {
+      callback({width: width, height: height});
+      return true;
+    }
+    return false;
+  });
+};
+
+/**
+ * Waits for an element and returns it as an array of it's attributes.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {?string} iframeQuery Iframe selector or null if no iframe.
+ * @param {boolean=} opt_inverse True if the function should return if the
+ *    element disappears, instead of appearing.
+ * @param {function(Object)} callback Callback with a hash array of attributes
+ *     and contents as text.
+ */
+test.util.async.waitForElement = function(
+    contentWindow, targetQuery, iframeQuery, opt_inverse, callback) {
+  test.util.repeatUntilTrue_(function() {
+    var doc = test.util.sync.getDocument_(contentWindow, iframeQuery);
+    if (!doc)
+      return false;
+    var element = doc.querySelector(targetQuery);
+    if (!element)
+      return !!opt_inverse;
+    var attributes = {};
+    for (var i = 0; i < element.attributes.length; i++) {
+      attributes[element.attributes[i].nodeName] =
+          element.attributes[i].nodeValue;
+    }
+    var text = element.textContent;
+    callback({attributes: attributes, text: text});
+    return !opt_inverse;
+  });
+};
+
+/**
+ * Calls getFileList until the number of displayed files is different from
+ * lengthBefore.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {number} lengthBefore Number of items visible before.
+ * @param {function(Array.<Array.<string>>)} callback Change callback.
+ */
+test.util.async.waitForFileListChange = function(
+    contentWindow, lengthBefore, callback) {
+  test.util.repeatUntilTrue_(function() {
+    var files = test.util.sync.getFileList(contentWindow);
+    files.sort();
+    var notReadyRows = files.filter(function(row) {
+      return row.filter(function(cell) { return cell == '...'; }).length;
+    });
+    if (notReadyRows.length === 0 &&
+        files.length !== lengthBefore &&
+        files.length !== 0) {
+      callback(files);
+      return true;
+    } else {
+      return false;
+    }
+  });
+};
+
+/**
+ * Returns an array of items on the file manager's autocomplete list.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @return {Array.<string>} Array of items.
+ */
+test.util.sync.getAutocompleteList = function(contentWindow) {
+  var list = contentWindow.document.querySelector('#autocomplete-list');
+  var lines = list.querySelectorAll('li');
+  var items = [];
+  for (var j = 0; j < lines.length; ++j) {
+    var line = lines[j];
+    items.push(line.innerText);
+  }
+  return items;
+};
+
+/**
+ * Performs autocomplete with the given query and waits until at least
+ * |numExpectedItems| items are shown, including the first item which
+ * always looks like "'<query>' - search Drive".
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} query Query used for autocomplete.
+ * @param {number} numExpectedItems number of items to be shown.
+ * @param {function(Array.<string>)} callback Change callback.
+ */
+test.util.async.performAutocompleteAndWait = function(
+    contentWindow, query, numExpectedItems, callback) {
+  // Dispatch a 'focus' event to the search box so that the autocomplete list
+  // is attached to the search box. Note that calling searchBox.focus() won't
+  // dispatch a 'focus' event.
+  var searchBox = contentWindow.document.querySelector('#search-box input');
+  var focusEvent = contentWindow.document.createEvent('Event');
+  focusEvent.initEvent('focus', true /* bubbles */, true /* cancelable */);
+  searchBox.dispatchEvent(focusEvent);
+
+  // Change the value of the search box and dispatch an 'input' event so that
+  // the autocomplete query is processed.
+  searchBox.value = query;
+  var inputEvent = contentWindow.document.createEvent('Event');
+  inputEvent.initEvent('input', true /* bubbles */, true /* cancelable */);
+  searchBox.dispatchEvent(inputEvent);
+
+  test.util.repeatUntilTrue_(function() {
+    var items = test.util.sync.getAutocompleteList(contentWindow);
+    if (items.length >= numExpectedItems) {
+      callback(items);
+      return true;
+    } else {
+      return false;
+    }
+  });
+};
+
+/**
+ * Waits until a dialog with an OK button is shown and accepts it.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {function()} callback Success callback.
+ */
+test.util.async.waitAndAcceptDialog = function(contentWindow, callback) {
+  test.util.repeatUntilTrue_(function() {
+    var button = contentWindow.document.querySelector('.cr-dialog-ok');
+    if (!button)
+      return false;
+    button.click();
+    // Wait until the dialog is removed from the DOM.
+    test.util.repeatUntilTrue_(function() {
+      if (contentWindow.document.querySelector('.cr-dialog-container'))
+        return false;
+      callback();
+      return true;
+    });
+    return true;
+  });
+};
+
+/**
+ * Fakes pressing the down arrow until the given |filename| is selected.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} filename Name of the file to be selected.
+ * @return {boolean} True if file got selected, false otherwise.
+ */
+test.util.sync.selectFile = function(contentWindow, filename) {
+  var table = contentWindow.document.querySelector('#detail-table');
+  var rows = table.querySelectorAll('li');
+  for (var index = 0; index < rows.length; ++index) {
+    test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'Down', false);
+    var selection = test.util.sync.getSelectedFiles(contentWindow);
+    if (selection.length === 1 && selection[0] === filename)
+      return true;
+  }
+  console.error('Failed to select file "' + filename + '"');
+  return false;
+};
+
+/**
+ * Open the file by selectFile and fakeMouseDoubleClick.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} filename Name of the file to be opened.
+ * @return {boolean} True if file got selected and a double click message is
+ *     sent, false otherwise.
+ */
+test.util.sync.openFile = function(contentWindow, filename) {
+  var query = '#file-list li.table-row[selected] .filename-label span';
+  return test.util.sync.selectFile(contentWindow, filename) &&
+         test.util.sync.fakeMouseDoubleClick(contentWindow, query);
+};
+
+/**
+ * Selects a volume specified by its icon name
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} iconName Name of the volume icon.
+ * @param {function(boolean)} callback Callback function to notify the caller
+ *     whether the target is found and mousedown and click events are sent.
+ */
+test.util.async.selectVolume = function(contentWindow, iconName, callback) {
+  var query = '[volume-type-icon=' + iconName + ']';
+  var driveQuery = '[volume-type-icon=drive]';
+  var isDriveSubVolume = iconName == 'drive_recent' ||
+                         iconName == 'drive_shared_with_me' ||
+                         iconName == 'drive_offline';
+  var preSelection = false;
+  var steps = {
+    checkQuery: function() {
+      if (contentWindow.document.querySelector(query)) {
+        steps.sendEvents();
+        return;
+      }
+      // If the target volume is sub-volume of drive, we must click 'drive'
+      // before clicking the sub-item.
+      if (!preSelection) {
+        if (!isDriveSubVolume) {
+          callback(false);
+          return;
+        }
+        if (!(test.util.sync.fakeMouseDown(contentWindow, driveQuery) &&
+              test.util.sync.fakeMouseClick(contentWindow, driveQuery))) {
+          callback(false);
+          return;
+        }
+        preSelection = true;
+      }
+      setTimeout(steps.checkQuery, 50);
+    },
+    sendEvents: function() {
+      // To change the selected volume, we have to send both events 'mousedown'
+      // and 'click' to the navigation list.
+      callback(test.util.sync.fakeMouseDown(contentWindow, query) &&
+               test.util.sync.fakeMouseClick(contentWindow, query));
+    }
+  };
+  steps.checkQuery();
+};
+
+/**
+ * Waits the contents of file list becomes to equal to expected contents.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {Array.<Array.<string>>} expected Expected contents of file list.
+ * @param {{orderCheck:boolean=, ignoreLastModifiedTime:boolean=}=} opt_options
+ *     Options of the comparison. If orderCheck is true, it also compares the
+ *     order of files. If ignoreLastModifiedTime is true, it compares the file
+ *     without its last modified time.
+ * @param {function()} callback Callback function to notify the caller that
+ *     expected files turned up.
+ */
+test.util.async.waitForFiles = function(
+    contentWindow, expected, opt_options, callback) {
+  var options = opt_options || {};
+  test.util.repeatUntilTrue_(function() {
+    var files = test.util.sync.getFileList(contentWindow);
+    if (!options.orderCheck) {
+      files.sort();
+      expected.sort();
+    }
+    if (options.ignoreLastModifiedTime) {
+      for (var i = 0; i < Math.min(files.length, expected.length); i++) {
+        files[i][3] = '';
+        expected[i][3] = '';
+      }
+    }
+    if (chrome.test.checkDeepEq(expected, files)) {
+      callback(true);
+      return true;
+    }
+    return false;
+  });
+};
+
+/**
+ * Executes Javascript code on a webview and returns the result.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} webViewQuery Selector for the web view.
+ * @param {string} code Javascript code to be executed within the web view.
+ * @param {function(*)} callback Callback function with results returned by the
+ *     script.
+ */
+test.util.async.executeScriptInWebView = function(
+    contentWindow, webViewQuery, code, callback) {
+  var webView = contentWindow.document.querySelector(webViewQuery);
+  webView.executeScript({code: code}, callback);
+};
+
+/**
+ * Sends an event to the element specified by |targetQuery|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {Event} event Event to be sent.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.sendEvent = function(
+    contentWindow, targetQuery, event, opt_iframeQuery) {
+  var doc = test.util.sync.getDocument_(contentWindow, opt_iframeQuery);
+  if (doc) {
+    var target = doc.querySelector(targetQuery);
+    if (target) {
+      target.dispatchEvent(event);
+      return true;
+    }
+  }
+  console.error('Target element for ' + targetQuery + ' not found.');
+  return false;
+};
+
+/**
+ * Sends an fake event having the specified type to the target query.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string} event Type of event.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeEvent = function(contentWindow, targetQuery, event) {
+  return test.util.sync.sendEvent(
+      contentWindow, targetQuery, new Event(event));
+};
+
+/**
+ * Sends a fake key event to the element specified by |targetQuery| with the
+ * given |keyIdentifier| and optional |ctrl| modifier to the file manager.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string} keyIdentifier Identifier of the emulated key.
+ * @param {boolean} ctrl Whether CTRL should be pressed, or not.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeKeyDown = function(
+    contentWindow, targetQuery, keyIdentifier, ctrl, opt_iframeQuery) {
+  var event = new KeyboardEvent(
+      'keydown',
+      { bubbles: true, keyIdentifier: keyIdentifier, ctrlKey: ctrl });
+  return test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery);
+};
+
+/**
+ * Sends a fake mouse click event (left button, single click) to the element
+ * specified by |targetQuery|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeMouseClick = function(
+    contentWindow, targetQuery, opt_iframeQuery) {
+  var event = new MouseEvent('click', { bubbles: true, detail: 1 });
+  return test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery);
+};
+
+/**
+ * Simulates a fake double click event (left button) to the element specified by
+ * |targetQuery|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeMouseDoubleClick = function(
+    contentWindow, targetQuery, opt_iframeQuery) {
+  // Double click is always preceded with a single click.
+  if (!test.util.sync.fakeMouseClick(
+      contentWindow, targetQuery, opt_iframeQuery)) {
+    return false;
+  }
+
+  // Send the second click event, but with detail equal to 2 (number of clicks)
+  // in a row.
+  var event = new MouseEvent('click', { bubbles: true, detail: 2 });
+  if (!test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery)) {
+    return false;
+  }
+
+  // Send the double click event.
+  var event = new MouseEvent('dblclick', { bubbles: true });
+  if (!test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery)) {
+    return false;
+  }
+
+  return true;
+};
+
+/**
+ * Sends a fake mouse down event to the element specified by |targetQuery|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeMouseDown = function(
+    contentWindow, targetQuery, opt_iframeQuery) {
+  var event = new MouseEvent('mousedown', { bubbles: true });
+  return test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery);
+};
+
+/**
+ * Sends a fake mouse up event to the element specified by |targetQuery|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} targetQuery Query to specify the element.
+ * @param {string=} opt_iframeQuery Optional iframe selector.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeMouseUp = function(
+    contentWindow, targetQuery, opt_iframeQuery) {
+  var event = new MouseEvent('mouseup', { bubbles: true });
+  return test.util.sync.sendEvent(
+      contentWindow, targetQuery, event, opt_iframeQuery);
+};
+
+/**
+ * Selects |filename| and fakes pressing Ctrl+C, Ctrl+V (copy, paste).
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} filename Name of the file to be copied.
+ * @return {boolean} True if copying got simulated successfully. It does not
+ *     say if the file got copied, or not.
+ */
+test.util.sync.copyFile = function(contentWindow, filename) {
+  if (!test.util.sync.selectFile(contentWindow, filename))
+    return false;
+  // Ctrl+C and Ctrl+V
+  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0043', true);
+  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0056', true);
+  return true;
+};
+
+/**
+ * Selects |filename| and fakes pressing the Delete key.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} filename Name of the file to be deleted.
+ * @return {boolean} True if deleting got simulated successfully. It does not
+ *     say if the file got deleted, or not.
+ */
+test.util.sync.deleteFile = function(contentWindow, filename) {
+  if (!test.util.sync.selectFile(contentWindow, filename))
+    return false;
+  // Delete
+  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+007F', false);
+  return true;
+};
+
+/**
+ * Wait for the elements' style to be changed as the expected values.  The
+ * queries argument is a list of object that have the query property and the
+ * styles property. The query property is a string query to specify the
+ * element. The styles property is a string map of the style name and its
+ * expected value.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {Array.<object>} queries Queries that specifies the elements and
+ *   expected styles.
+ * @param {function()} callback Callback function to be notified the change of
+ *     the styles.
+ */
+test.util.async.waitForStyles = function(contentWindow, queries, callback) {
+  test.util.repeatUntilTrue_(function() {
+    for (var i = 0; i < queries.length; i++) {
+      var element = contentWindow.document.querySelector(queries[i].query);
+      var styles = queries[i].styles;
+      for (var name in styles) {
+        if (contentWindow.getComputedStyle(element)[name] != styles[name])
+          return false;
+      }
+    }
+    callback();
+    return true;
+  });
+};
+
+/**
+ * Execute a command on the document in the specified window.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} command Command name.
+ * @return {boolean} True if the command is executed successfully.
+ */
+test.util.sync.execCommand = function(contentWindow, command) {
+  return contentWindow.document.execCommand(command);
+};
+
+/**
+ * Registers message listener, which runs test utility functions.
+ */
+test.util.registerRemoteTestUtils = function() {
+  // Register the message listener.
+  var onMessage = chrome.runtime ? chrome.runtime.onMessageExternal :
+      chrome.extension.onMessageExternal;
+  // Return true for asynchronous functions and false for synchronous.
+  onMessage.addListener(function(request, sender, sendResponse) {
+    // Check the sender.
+    if (sender.id != test.util.TESTING_EXTENSION_ID) {
+      console.error('The testing extension must be white-listed.');
+      return false;
+    }
+    // Set a global flag that we are in tests, so other components are aware
+    // of it.
+    window.IN_TEST = true;
+    // Check the function name.
+    if (!request.func || request.func[request.func.length - 1] == '_') {
+      request.func = '';
+    }
+    // Prepare arguments.
+    var args = request.args.slice();  // shallow copy
+    if (request.appId) {
+      if (!background.appWindows[request.appId]) {
+        console.error('Specified window not found.');
+        return false;
+      }
+      args.unshift(background.appWindows[request.appId].contentWindow);
+    }
+    // Call the test utility function and respond the result.
+    if (test.util.async[request.func]) {
+      args[test.util.async[request.func].length - 1] = function() {
+        console.debug('Received the result of ' + request.func);
+        sendResponse.apply(null, arguments);
+      };
+      console.debug('Waiting for the result of ' + request.func);
+      test.util.async[request.func].apply(null, args);
+      return true;
+    } else if (test.util.sync[request.func]) {
+      sendResponse(test.util.sync[request.func].apply(null, args));
+      return false;
+    } else {
+      console.error('Invalid function name.');
+      return false;
+    }
+  });
+};
+
+// Register the test utils.
+test.util.registerRemoteTestUtils();
diff --git a/chrome/browser/resources/file_manager/background/js/volume_manager.js b/chrome/browser/resources/file_manager/background/js/volume_manager.js
new file mode 100644
index 0000000..ff2ccf5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/background/js/volume_manager.js
@@ -0,0 +1,636 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Represents each volume, such as "drive", "download directory", each "USB
+ * flush storage", or "mounted zip archive" etc.
+ *
+ * @param {util.VolumeType} volumeType The type of the volume.
+ * @param {string} mountPath Where the volume is mounted.
+ * @param {DirectoryEntry} root The root directory entry of this volume.
+ * @param {string} error The error if an error is found.
+ * @param {string} deviceType The type of device ('usb'|'sd'|'optical'|'mobile'
+ *     |'unknown') (as defined in chromeos/disks/disk_mount_manager.cc).
+ *     Can be null.
+ * @param {boolean} isReadOnly True if the volume is read only.
+ * @constructor
+ */
+function VolumeInfo(
+    volumeType, mountPath, root, error, deviceType, isReadOnly) {
+  this.volumeType = volumeType;
+  // TODO(hidehiko): This should include FileSystem instance.
+  this.mountPath = mountPath;
+  this.root = root;
+
+  // Note: This represents if the mounting of the volume is successfully done
+  // or not. (If error is empty string, the mount is successfully done).
+  // TODO(hidehiko): Rename to make this more understandable.
+  this.error = error;
+  this.deviceType = deviceType;
+  this.isReadOnly = isReadOnly;
+
+  // VolumeInfo is immutable.
+  Object.freeze(this);
+}
+
+/**
+ * Utilities for volume manager implementation.
+ */
+var volumeManagerUtil = {};
+
+/**
+ * Throws an Error when the given error is not in util.VolumeError.
+ * @param {util.VolumeError} error Status string usually received from APIs.
+ */
+volumeManagerUtil.validateError = function(error) {
+  for (var key in util.VolumeError) {
+    if (error == util.VolumeError[key])
+      return;
+  }
+
+  throw new Error('Invalid mount error: ' + error);
+};
+
+/**
+ * The regex pattern which matches valid mount paths.
+ * The valid paths are:
+ * - Either of '/drive', '/drive_shared_with_me', '/drive_offline',
+ *   '/drive_recent' or '/Download'
+ * - For archive, drive, removable can have (exactly one) sub directory in the
+ *  root path. E.g. '/archive/foo', '/removable/usb1' etc.
+ *
+ * @type {RegExp}
+ * @private
+ */
+volumeManagerUtil.validateMountPathRegExp_ = new RegExp(
+    '^/(drive|drive_shared_with_me|drive_offline|drive_recent|Downloads|' +
+    '((archive|drive|removable)\/[^/]+))$');
+
+/**
+ * Throws an Error if the validation fails.
+ * @param {string} mountPath The target path of the validation.
+ */
+volumeManagerUtil.validateMountPath = function(mountPath) {
+  if (!volumeManagerUtil.validateMountPathRegExp_.test(mountPath))
+    throw new Error('Invalid mount path: ' + mountPath);
+};
+
+/**
+ * Returns the root entry of a volume mounted at mountPath.
+ *
+ * @param {string} mountPath The mounted path of the volume.
+ * @param {function(DirectoryEntry)} successCallback Called when the root entry
+ *     is found.
+ * @param {function(FileError)} errorCallback Called when an error is found.
+ * @private
+ */
+volumeManagerUtil.getRootEntry_ = function(
+    mountPath, successCallback, errorCallback) {
+  // We always request FileSystem here, because requestFileSystem() grants
+  // permissions if necessary, especially for Drive File System at first mount
+  // time.
+  // Note that we actually need to request FileSystem after multi file system
+  // support, so this will be more natural code then.
+  chrome.fileBrowserPrivate.requestFileSystem(
+      'compatible',
+      function(fileSystem) {
+        // TODO(hidehiko): chrome.runtime.lastError should have error reason.
+        if (!fileSystem) {
+          errorCallback(util.createFileError(FileError.NOT_FOUND_ERR));
+          return;
+        }
+
+        fileSystem.root.getDirectory(
+            mountPath.substring(1),  // Strip leading '/'.
+            {create: false}, successCallback, errorCallback);
+      });
+};
+
+/**
+ * Builds the VolumeInfo data from VolumeMetadata.
+ * @param {VolumeMetadata} volumeMetadata Metadata instance for the volume.
+ * @param {function(VolumeInfo)} callback Called on completion.
+ */
+volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) {
+  volumeManagerUtil.getRootEntry_(
+      volumeMetadata.mountPath,
+      function(entry) {
+        if (volumeMetadata.volumeType === util.VolumeType.DRIVE) {
+          // After file system is mounted, we "read" drive grand root
+          // entry at first. This triggers full feed fetch on background.
+          // Note: we don't need to handle errors here, because even if
+          // it fails, accessing to some path later will just become
+          // a fast-fetch and it re-triggers full-feed fetch.
+          entry.createReader().readEntries(
+              function() { /* do nothing */ },
+              function(error) {
+                console.error(
+                    'Triggering full feed fetch is failed: ' +
+                        util.getFileErrorMnemonic(error.code));
+              });
+        }
+        callback(new VolumeInfo(
+            volumeMetadata.volumeType,
+            volumeMetadata.mountPath,
+            entry,
+            volumeMetadata.mountCondition,
+            volumeMetadata.deviceType,
+            volumeMetadata.isReadOnly));
+      },
+      function(fileError) {
+        console.error('Root entry is not found: ' +
+            volumeMetadata.mountPath + ', ' +
+            util.getFileErrorMnemonic(fileError.code));
+        callback(new VolumeInfo(
+            volumeMetadata.volumeType,
+            volumeMetadata.mountPath,
+            null,  // Root entry is not found.
+            volumeMetadata.mountCondition,
+            volumeMetadata.deviceType,
+            volumeMetadata.isReadOnly));
+      });
+};
+
+/**
+ * The order of the volume list based on root type.
+ * @type {Array.<string>}
+ * @const
+ * @private
+ */
+volumeManagerUtil.volumeListOrder_ = [
+  RootType.DRIVE, RootType.DOWNLOADS, RootType.ARCHIVE, RootType.REMOVABLE
+];
+
+/**
+ * Compares mount paths to sort the volume list order.
+ * @param {string} mountPath1 The mount path for the first volume.
+ * @param {string} mountPath2 The mount path for the second volume.
+ * @return {number} 0 if mountPath1 and mountPath2 are same, -1 if VolumeInfo
+ *     mounted at mountPath1 should be listed before the one mounted at
+ *     mountPath2, otherwise 1.
+ */
+volumeManagerUtil.compareMountPath = function(mountPath1, mountPath2) {
+  var order1 = volumeManagerUtil.volumeListOrder_.indexOf(
+      PathUtil.getRootType(mountPath1));
+  var order2 = volumeManagerUtil.volumeListOrder_.indexOf(
+      PathUtil.getRootType(mountPath2));
+  if (order1 != order2)
+    return order1 < order2 ? -1 : 1;
+
+  if (mountPath1 != mountPath2)
+    return mountPath1 < mountPath2 ? -1 : 1;
+
+  // The path is same.
+  return 0;
+};
+
+/**
+ * The container of the VolumeInfo for each mounted volume.
+ * @constructor
+ */
+function VolumeInfoList() {
+  /**
+   * Holds VolumeInfo instances.
+   * @type {cr.ui.ArrayDataModel}
+   * @private
+   */
+  this.model_ = new cr.ui.ArrayDataModel([]);
+
+  Object.freeze(this);
+}
+
+VolumeInfoList.prototype = {
+  get length() { return this.model_.length; }
+};
+
+/**
+ * Adds the event listener to listen the change of volume info.
+ * @param {string} type The name of the event.
+ * @param {function(Event)} handler The handler for the event.
+ */
+VolumeInfoList.prototype.addEventListener = function(type, handler) {
+  this.model_.addEventListener(type, handler);
+};
+
+/**
+ * Removes the event listener.
+ * @param {string} type The name of the event.
+ * @param {function(Event)} handler The handler to be removed.
+ */
+VolumeInfoList.prototype.removeEventListener = function(type, handler) {
+  this.model_.removeEventListener(type, handler);
+};
+
+/**
+ * Adds the volumeInfo to the appropriate position. If there already exists,
+ * just replaces it.
+ * @param {VolumeInfo} volumeInfo The information of the new volume.
+ */
+VolumeInfoList.prototype.add = function(volumeInfo) {
+  var index = this.findLowerBoundIndex_(volumeInfo.mountPath);
+  if (index < this.length &&
+      this.item(index).mountPath == volumeInfo.mountPath) {
+    // Replace the VolumeInfo.
+    this.model_.splice(index, 1, volumeInfo);
+  } else {
+    // Insert the VolumeInfo.
+    this.model_.splice(index, 0, volumeInfo);
+  }
+};
+
+/**
+ * Removes the VolumeInfo of the volume mounted at mountPath.
+ * @param {string} mountPath The path to the location where the volume is
+ *     mounted.
+ */
+VolumeInfoList.prototype.remove = function(mountPath) {
+  var index = this.findLowerBoundIndex_(mountPath);
+  if (index < this.length && this.item(index).mountPath == mountPath)
+    this.model_.splice(index, 1);
+};
+
+/**
+ * Searches the information of the volume mounted at mountPath.
+ * @param {string} mountPath The path to the location where the volume is
+ *     mounted.
+ * @return {VolumeInfo} The volume's information, or null if not found.
+ */
+VolumeInfoList.prototype.find = function(mountPath) {
+  var index = this.findLowerBoundIndex_(mountPath);
+  if (index < this.length && this.item(index).mountPath == mountPath)
+    return this.item(index);
+
+  // Not found.
+  return null;
+};
+
+/**
+ * @param {string} mountPath The mount path of searched volume.
+ * @return {number} The index of the volume if found, or the inserting
+ *     position of the volume.
+ * @private
+ */
+VolumeInfoList.prototype.findLowerBoundIndex_ = function(mountPath) {
+  // Assuming the number of elements in the array data model is very small
+  // in most cases, use simple linear search, here.
+  for (var i = 0; i < this.length; i++) {
+    if (volumeManagerUtil.compareMountPath(
+            this.item(i).mountPath, mountPath) >= 0)
+      return i;
+  }
+  return this.length;
+};
+
+/**
+ * @param {number} index The index of the volume in the list.
+ * @return {VolumeInfo} The VolumeInfo instance.
+ */
+VolumeInfoList.prototype.item = function(index) {
+  return this.model_.item(index);
+};
+
+/**
+ * VolumeManager is responsible for tracking list of mounted volumes.
+ *
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+function VolumeManager() {
+  /**
+   * The list of archives requested to mount. We will show contents once
+   * archive is mounted, but only for mounts from within this filebrowser tab.
+   * @type {Object.<string, Object>}
+   * @private
+   */
+  this.requests_ = {};
+
+  /**
+   * The list of VolumeInfo instances for each mounted volume.
+   * @type {VolumeInfoList}
+   */
+  this.volumeInfoList = new VolumeInfoList();
+
+  // The status should be merged into VolumeManager.
+  // TODO(hidehiko): Remove them after the migration.
+  this.driveConnectionState_ = {
+    type: util.DriveConnectionType.OFFLINE,
+    reasons: [util.DriveConnectionReason.NO_SERVICE]
+  };
+
+  chrome.fileBrowserPrivate.onDriveConnectionStatusChanged.addListener(
+      this.onDriveConnectionStatusChanged_.bind(this));
+  this.onDriveConnectionStatusChanged_();
+}
+
+/**
+ * Invoked when the drive connection status is changed.
+ * @private_
+ */
+VolumeManager.prototype.onDriveConnectionStatusChanged_ = function() {
+  chrome.fileBrowserPrivate.getDriveConnectionState(function(state) {
+    this.driveConnectionState_ = state;
+    cr.dispatchSimpleEvent(this, 'drive-connection-changed');
+  }.bind(this));
+};
+
+/**
+ * Returns the drive connection state.
+ * @return {util.DriveConnectionType} Connection type.
+ */
+VolumeManager.prototype.getDriveConnectionState = function() {
+  return this.driveConnectionState_;
+};
+
+/**
+ * VolumeManager extends cr.EventTarget.
+ */
+VolumeManager.prototype.__proto__ = cr.EventTarget.prototype;
+
+/**
+ * Time in milliseconds that we wait a response for. If no response on
+ * mount/unmount received the request supposed failed.
+ */
+VolumeManager.TIMEOUT = 15 * 60 * 1000;
+
+/**
+ * Queue to run getInstance sequentially.
+ * @type {AsyncUtil.Queue}
+ * @private
+ */
+VolumeManager.getInstanceQueue_ = new AsyncUtil.Queue();
+
+/**
+ * The singleton instance of VolumeManager. Initialized by the first invocation
+ * of getInstance().
+ * @type {VolumeManager}
+ * @private
+ */
+VolumeManager.instance_ = null;
+
+/**
+ * Returns the VolumeManager instance asynchronously. If it is not created or
+ * under initialization, it will waits for the finish of the initialization.
+ * @param {function(VolumeManager)} callback Called with the VolumeManager
+ *     instance.
+ */
+VolumeManager.getInstance = function(callback) {
+  VolumeManager.getInstanceQueue_.run(function(continueCallback) {
+    if (VolumeManager.instance_) {
+      callback(VolumeManager.instance_);
+      continueCallback();
+      return;
+    }
+
+    VolumeManager.instance_ = new VolumeManager();
+    VolumeManager.instance_.initialize_(function() {
+      callback(VolumeManager.instance_);
+      continueCallback();
+    });
+  });
+};
+
+/**
+ * Initializes mount points.
+ * @param {function()} callback Called upon the completion of the
+ *     initialization.
+ * @private
+ */
+VolumeManager.prototype.initialize_ = function(callback) {
+  chrome.fileBrowserPrivate.getVolumeMetadataList(function(volumeMetadataList) {
+    // Create VolumeInfo for each volume.
+    var group = new AsyncUtil.Group();
+    for (var i = 0; i < volumeMetadataList.length; i++) {
+      group.add(function(volumeMetadata, continueCallback) {
+        volumeManagerUtil.createVolumeInfo(
+            volumeMetadata,
+            function(volumeInfo) {
+              this.volumeInfoList.add(volumeInfo);
+              if (volumeMetadata.volumeType === util.VolumeType.DRIVE)
+                this.onDriveConnectionStatusChanged_();
+              continueCallback();
+            }.bind(this));
+      }.bind(this, volumeMetadataList[i]));
+    }
+
+    // Then, finalize the initialization.
+    group.run(function() {
+      // Subscribe to the mount completed event when mount points initialized.
+      chrome.fileBrowserPrivate.onMountCompleted.addListener(
+          this.onMountCompleted_.bind(this));
+      callback();
+    }.bind(this));
+  }.bind(this));
+};
+
+/**
+ * Event handler called when some volume was mounted or unmounted.
+ * @param {MountCompletedEvent} event Received event.
+ * @private
+ */
+VolumeManager.prototype.onMountCompleted_ = function(event) {
+  if (event.eventType === 'mount') {
+    if (event.volumeMetadata.mountPath) {
+      var requestKey = this.makeRequestKey_(
+          'mount',
+          event.volumeMetadata.sourcePath);
+
+      var error = event.status === 'success' ? '' : event.status;
+
+      volumeManagerUtil.createVolumeInfo(
+          event.volumeMetadata,
+          function(volumeInfo) {
+            this.volumeInfoList.add(volumeInfo);
+            this.finishRequest_(requestKey, event.status, volumeInfo.mountPath);
+
+            if (volumeInfo.volumeType === util.VolumeType.DRIVE) {
+              // Update the network connection status, because until the
+              // drive is initialized, the status is set to not ready.
+              // TODO(hidehiko): The connection status should be migrated into
+              // VolumeMetadata.
+              this.onDriveConnectionStatusChanged_();
+            }
+          }.bind(this));
+    } else {
+      console.warn('No mount path.');
+      this.finishRequest_(requestKey, event.status);
+    }
+  } else if (event.eventType === 'unmount') {
+    var mountPath = event.volumeMetadata.mountPath;
+    volumeManagerUtil.validateMountPath(mountPath);
+    var status = event.status;
+    if (status === util.VolumeError.PATH_UNMOUNTED) {
+      console.warn('Volume already unmounted: ', mountPath);
+      status = 'success';
+    }
+    var requestKey = this.makeRequestKey_('unmount', mountPath);
+    var requested = requestKey in this.requests_;
+    if (event.status === 'success' && !requested &&
+        this.volumeInfoList.find(mountPath)) {
+      console.warn('Mounted volume without a request: ', mountPath);
+      var e = new Event('externally-unmounted');
+      e.mountPath = mountPath;
+      this.dispatchEvent(e);
+    }
+    this.finishRequest_(requestKey, status);
+
+    if (event.status === 'success')
+      this.volumeInfoList.remove(mountPath);
+  }
+};
+
+/**
+ * Creates string to match mount events with requests.
+ * @param {string} requestType 'mount' | 'unmount'. TODO(hidehiko): Replace by
+ *     enum.
+ * @param {string} path Source path provided by API for mount request, or
+ *     mount path for unmount request.
+ * @return {string} Key for |this.requests_|.
+ * @private
+ */
+VolumeManager.prototype.makeRequestKey_ = function(requestType, path) {
+  return requestType + ':' + path;
+};
+
+/**
+ * @param {string} fileUrl File url to the archive file.
+ * @param {function(string)} successCallback Success callback.
+ * @param {function(util.VolumeError)} errorCallback Error callback.
+ */
+VolumeManager.prototype.mountArchive = function(
+    fileUrl, successCallback, errorCallback) {
+  chrome.fileBrowserPrivate.addMount(fileUrl, function(sourcePath) {
+    console.info(
+        'Mount request: url=' + fileUrl + '; sourceUrl=' + sourcePath);
+    var requestKey = this.makeRequestKey_('mount', sourcePath);
+    this.startRequest_(requestKey, successCallback, errorCallback);
+  }.bind(this));
+};
+
+/**
+ * Unmounts volume.
+ * @param {string} mountPath Volume mounted path.
+ * @param {function(string)} successCallback Success callback.
+ * @param {function(util.VolumeError)} errorCallback Error callback.
+ */
+VolumeManager.prototype.unmount = function(mountPath,
+                                           successCallback,
+                                           errorCallback) {
+  volumeManagerUtil.validateMountPath(mountPath);
+  var volumeInfo = this.volumeInfoList.find(mountPath);
+  if (!volumeInfo) {
+    errorCallback(util.VolumeError.NOT_MOUNTED);
+    return;
+  }
+
+  chrome.fileBrowserPrivate.removeMount(util.makeFilesystemUrl(mountPath));
+  var requestKey = this.makeRequestKey_('unmount', volumeInfo.mountPath);
+  this.startRequest_(requestKey, successCallback, errorCallback);
+};
+
+/**
+ * Resolve the path to its entry.
+ * @param {string} path The path to be resolved.
+ * @param {function(Entry)} successCallback Called with the resolved entry on
+ *     success.
+ * @param {function(FileError)} errorCallback Called on error.
+ */
+VolumeManager.prototype.resolvePath = function(
+    path, successCallback, errorCallback) {
+  // Make sure the path is in the mounted volume.
+  var mountPath = PathUtil.isDriveBasedPath(path) ?
+      RootDirectory.DRIVE : PathUtil.getRootPath(path);
+  var volumeInfo = this.getVolumeInfo(mountPath);
+  if (!volumeInfo || !volumeInfo.root) {
+    errorCallback(util.createFileError(FileError.NOT_FOUND_ERR));
+    return;
+  }
+
+  webkitResolveLocalFileSystemURL(
+      util.makeFilesystemUrl(path), successCallback, errorCallback);
+};
+
+/**
+ * @param {string} mountPath Volume mounted path.
+ * @return {VolumeInfo} The data about the volume.
+ */
+VolumeManager.prototype.getVolumeInfo = function(mountPath) {
+  volumeManagerUtil.validateMountPath(mountPath);
+  return this.volumeInfoList.find(mountPath);
+};
+
+/**
+ * @param {string} key Key produced by |makeRequestKey_|.
+ * @param {function(string)} successCallback To be called when request finishes
+ *     successfully.
+ * @param {function(util.VolumeError)} errorCallback To be called when
+ *     request fails.
+ * @private
+ */
+VolumeManager.prototype.startRequest_ = function(key,
+    successCallback, errorCallback) {
+  if (key in this.requests_) {
+    var request = this.requests_[key];
+    request.successCallbacks.push(successCallback);
+    request.errorCallbacks.push(errorCallback);
+  } else {
+    this.requests_[key] = {
+      successCallbacks: [successCallback],
+      errorCallbacks: [errorCallback],
+
+      timeout: setTimeout(this.onTimeout_.bind(this, key),
+                          VolumeManager.TIMEOUT)
+    };
+  }
+};
+
+/**
+ * Called if no response received in |TIMEOUT|.
+ * @param {string} key Key produced by |makeRequestKey_|.
+ * @private
+ */
+VolumeManager.prototype.onTimeout_ = function(key) {
+  this.invokeRequestCallbacks_(this.requests_[key],
+                               util.VolumeError.TIMEOUT);
+  delete this.requests_[key];
+};
+
+/**
+ * @param {string} key Key produced by |makeRequestKey_|.
+ * @param {util.VolumeError|'success'} status Status received from the API.
+ * @param {string=} opt_mountPath Mount path.
+ * @private
+ */
+VolumeManager.prototype.finishRequest_ = function(key, status, opt_mountPath) {
+  var request = this.requests_[key];
+  if (!request)
+    return;
+
+  clearTimeout(request.timeout);
+  this.invokeRequestCallbacks_(request, status, opt_mountPath);
+  delete this.requests_[key];
+};
+
+/**
+ * @param {Object} request Structure created in |startRequest_|.
+ * @param {util.VolumeError|string} status If status == 'success'
+ *     success callbacks are called.
+ * @param {string=} opt_mountPath Mount path. Required if success.
+ * @private
+ */
+VolumeManager.prototype.invokeRequestCallbacks_ = function(request, status,
+                                                           opt_mountPath) {
+  var callEach = function(callbacks, self, args) {
+    for (var i = 0; i < callbacks.length; i++) {
+      callbacks[i].apply(self, args);
+    }
+  };
+  if (status == 'success') {
+    callEach(request.successCallbacks, this, [opt_mountPath]);
+  } else {
+    volumeManagerUtil.validateError(status);
+    callEach(request.errorCallbacks, this, [status]);
+  }
+};
diff --git a/chrome/browser/resources/file_manager/js/async_util.js b/chrome/browser/resources/file_manager/common/js/async_util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/async_util.js
rename to chrome/browser/resources/file_manager/common/js/async_util.js
diff --git a/chrome/browser/resources/file_manager/js/path_util.js b/chrome/browser/resources/file_manager/common/js/path_util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/path_util.js
rename to chrome/browser/resources/file_manager/common/js/path_util.js
diff --git a/chrome/browser/resources/file_manager/js/progress_center_common.js b/chrome/browser/resources/file_manager/common/js/progress_center_common.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/progress_center_common.js
rename to chrome/browser/resources/file_manager/common/js/progress_center_common.js
diff --git a/chrome/browser/resources/file_manager/common/js/util.js b/chrome/browser/resources/file_manager/common/js/util.js
new file mode 100644
index 0000000..a0ad8d8
--- /dev/null
+++ b/chrome/browser/resources/file_manager/common/js/util.js
@@ -0,0 +1,1212 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Namespace for utility functions.
+ */
+var util = {};
+
+/**
+ * Returns a function that console.log's its arguments, prefixed by |msg|.
+ *
+ * @param {string} msg The message prefix to use in the log.
+ * @param {function(...string)=} opt_callback A function to invoke after
+ *     logging.
+ * @return {function(...string)} Function that logs.
+ */
+util.flog = function(msg, opt_callback) {
+  return function() {
+    var ary = Array.apply(null, arguments);
+    console.log(msg + ': ' + ary.join(', '));
+    if (opt_callback)
+      opt_callback.apply(null, arguments);
+  };
+};
+
+/**
+ * Returns a function that throws an exception that includes its arguments
+ * prefixed by |msg|.
+ *
+ * @param {string} msg The message prefix to use in the exception.
+ * @return {function(...string)} Function that throws.
+ */
+util.ferr = function(msg) {
+  return function() {
+    var ary = Array.apply(null, arguments);
+    throw new Error(msg + ': ' + ary.join(', '));
+  };
+};
+
+/**
+ * Install a sensible toString() on the FileError object.
+ *
+ * FileError.prototype.code is a numeric code describing the cause of the
+ * error.  The FileError constructor has a named property for each possible
+ * error code, but provides no way to map the code to the named property.
+ * This toString() implementation fixes that.
+ */
+util.installFileErrorToString = function() {
+  FileError.prototype.toString = function() {
+    return '[object FileError: ' + util.getFileErrorMnemonic(this.code) + ']';
+  };
+};
+
+/**
+ * @param {number} code The file error code.
+ * @return {string} The file error mnemonic.
+ */
+util.getFileErrorMnemonic = function(code) {
+  for (var key in FileError) {
+    if (key.search(/_ERR$/) != -1 && FileError[key] == code)
+      return key;
+  }
+
+  return code;
+};
+
+/**
+ * @param {number} code File error code (from FileError object).
+ * @return {string} Translated file error string.
+ */
+util.getFileErrorString = function(code) {
+  for (var key in FileError) {
+    var match = /(.*)_ERR$/.exec(key);
+    if (match && FileError[key] == code) {
+      // This would convert 1 to 'NOT_FOUND'.
+      code = match[1];
+      break;
+    }
+  }
+  console.warn('File error: ' + code);
+  return loadTimeData.getString('FILE_ERROR_' + code) ||
+      loadTimeData.getString('FILE_ERROR_GENERIC');
+};
+
+/**
+ * @param {string} str String to escape.
+ * @return {string} Escaped string.
+ */
+util.htmlEscape = function(str) {
+  return str.replace(/[<>&]/g, function(entity) {
+    switch (entity) {
+      case '<': return '&lt;';
+      case '>': return '&gt;';
+      case '&': return '&amp;';
+    }
+  });
+};
+
+/**
+ * @param {string} str String to unescape.
+ * @return {string} Unescaped string.
+ */
+util.htmlUnescape = function(str) {
+  return str.replace(/&(lt|gt|amp);/g, function(entity) {
+    switch (entity) {
+      case '&lt;': return '<';
+      case '&gt;': return '>';
+      case '&amp;': return '&';
+    }
+  });
+};
+
+/**
+ * Iterates the entries contained by dirEntry, and invokes callback once for
+ * each entry. On completion, successCallback will be invoked.
+ *
+ * @param {DirectoryEntry} dirEntry The entry of the directory.
+ * @param {function(Entry, function())} callback Invoked for each entry.
+ * @param {function()} successCallback Invoked on completion.
+ * @param {function(FileError)} errorCallback Invoked if an error is found on
+ *     directory entry reading.
+ */
+util.forEachDirEntry = function(
+    dirEntry, callback, successCallback, errorCallback) {
+  var reader = dirEntry.createReader();
+  var iterate = function() {
+    reader.readEntries(function(entries) {
+      if (entries.length == 0) {
+        successCallback();
+        return;
+      }
+
+      AsyncUtil.forEach(
+          entries,
+          function(forEachCallback, entry) {
+            // Do not pass index nor entries.
+            callback(entry, forEachCallback);
+          },
+          iterate);
+    }, errorCallback);
+  };
+  iterate();
+};
+
+/**
+ * Reads contents of directory.
+ * @param {DirectoryEntry} root Root entry.
+ * @param {string} path Directory path.
+ * @param {function(Array.<Entry>)} callback List of entries passed to callback.
+ */
+util.readDirectory = function(root, path, callback) {
+  var onError = function(e) {
+    callback([], e);
+  };
+  root.getDirectory(path, {create: false}, function(entry) {
+    var reader = entry.createReader();
+    var r = [];
+    var readNext = function() {
+      reader.readEntries(function(results) {
+        if (results.length == 0) {
+          callback(r, null);
+          return;
+        }
+        r.push.apply(r, results);
+        readNext();
+      }, onError);
+    };
+    readNext();
+  }, onError);
+};
+
+/**
+ * Utility function to resolve multiple directories with a single call.
+ *
+ * The successCallback will be invoked once for each directory object
+ * found.  The errorCallback will be invoked once for each
+ * path that could not be resolved.
+ *
+ * The successCallback is invoked with a null entry when all paths have
+ * been processed.
+ *
+ * @param {DirEntry} dirEntry The base directory.
+ * @param {Object} params The parameters to pass to the underlying
+ *     getDirectory calls.
+ * @param {Array.<string>} paths The list of directories to resolve.
+ * @param {function(!DirEntry)} successCallback The function to invoke for
+ *     each DirEntry found.  Also invoked once with null at the end of the
+ *     process.
+ * @param {function(FileError)} errorCallback The function to invoke
+ *     for each path that cannot be resolved.
+ */
+util.getDirectories = function(dirEntry, params, paths, successCallback,
+                               errorCallback) {
+
+  // Copy the params array, since we're going to destroy it.
+  params = [].slice.call(params);
+
+  var onComplete = function() {
+    successCallback(null);
+  };
+
+  var getNextDirectory = function() {
+    var path = paths.shift();
+    if (!path)
+      return onComplete();
+
+    dirEntry.getDirectory(
+      path, params,
+      function(entry) {
+        successCallback(entry);
+        getNextDirectory();
+      },
+      function(err) {
+        errorCallback(err);
+        getNextDirectory();
+      });
+  };
+
+  getNextDirectory();
+};
+
+/**
+ * Utility function to resolve multiple files with a single call.
+ *
+ * The successCallback will be invoked once for each directory object
+ * found.  The errorCallback will be invoked once for each
+ * path that could not be resolved.
+ *
+ * The successCallback is invoked with a null entry when all paths have
+ * been processed.
+ *
+ * @param {DirEntry} dirEntry The base directory.
+ * @param {Object} params The parameters to pass to the underlying
+ *     getFile calls.
+ * @param {Array.<string>} paths The list of files to resolve.
+ * @param {function(!FileEntry)} successCallback The function to invoke for
+ *     each FileEntry found.  Also invoked once with null at the end of the
+ *     process.
+ * @param {function(FileError)} errorCallback The function to invoke
+ *     for each path that cannot be resolved.
+ */
+util.getFiles = function(dirEntry, params, paths, successCallback,
+                         errorCallback) {
+  // Copy the params array, since we're going to destroy it.
+  params = [].slice.call(params);
+
+  var onComplete = function() {
+    successCallback(null);
+  };
+
+  var getNextFile = function() {
+    var path = paths.shift();
+    if (!path)
+      return onComplete();
+
+    dirEntry.getFile(
+      path, params,
+      function(entry) {
+        successCallback(entry);
+        getNextFile();
+      },
+      function(err) {
+        errorCallback(err);
+        getNextFile();
+      });
+  };
+
+  getNextFile();
+};
+
+/**
+ * Resolve a path to either a DirectoryEntry or a FileEntry, regardless of
+ * whether the path is a directory or file.
+ *
+ * @param {DirectoryEntry} root The root of the filesystem to search.
+ * @param {string} path The path to be resolved.
+ * @param {function(Entry)} resultCallback Called back when a path is
+ *     successfully resolved. Entry will be either a DirectoryEntry or
+ *     a FileEntry.
+ * @param {function(FileError)} errorCallback Called back if an unexpected
+ *     error occurs while resolving the path.
+ */
+util.resolvePath = function(root, path, resultCallback, errorCallback) {
+  if (path == '' || path == '/') {
+    resultCallback(root);
+    return;
+  }
+
+  root.getFile(
+      path, {create: false},
+      resultCallback,
+      function(err) {
+        if (err.code == FileError.TYPE_MISMATCH_ERR) {
+          // Bah.  It's a directory, ask again.
+          root.getDirectory(
+              path, {create: false},
+              resultCallback,
+              errorCallback);
+        } else {
+          errorCallback(err);
+        }
+      });
+};
+
+/**
+ * Locate the file referred to by path, creating directories or the file
+ * itself if necessary.
+ * @param {DirEntry} root The root entry.
+ * @param {string} path The file path.
+ * @param {function(FileEntry)} successCallback The callback.
+ * @param {function(FileError)} errorCallback The callback.
+ */
+util.getOrCreateFile = function(root, path, successCallback, errorCallback) {
+  var dirname = null;
+  var basename = null;
+
+  var onDirFound = function(dirEntry) {
+    dirEntry.getFile(basename, { create: true },
+                     successCallback, errorCallback);
+  };
+
+  var i = path.lastIndexOf('/');
+  if (i > -1) {
+    dirname = path.substr(0, i);
+    basename = path.substr(i + 1);
+  } else {
+    basename = path;
+  }
+
+  if (!dirname) {
+    onDirFound(root);
+    return;
+  }
+
+  util.getOrCreateDirectory(root, dirname, onDirFound, errorCallback);
+};
+
+/**
+ * Locate the directory referred to by path, creating directories along the
+ * way.
+ * @param {DirEntry} root The root entry.
+ * @param {string} path The directory path.
+ * @param {function(FileEntry)} successCallback The callback.
+ * @param {function(FileError)} errorCallback The callback.
+ */
+util.getOrCreateDirectory = function(root, path, successCallback,
+                                     errorCallback) {
+  var names = path.split('/');
+
+  var getOrCreateNextName = function(dir) {
+    if (!names.length)
+      return successCallback(dir);
+
+    var name;
+    do {
+      name = names.shift();
+    } while (!name || name == '.');
+
+    dir.getDirectory(name, { create: true }, getOrCreateNextName,
+                     errorCallback);
+  };
+
+  getOrCreateNextName(root);
+};
+
+/**
+ * Renames the entry to newName.
+ * @param {Entry} entry The entry to be renamed.
+ * @param {string} newName The new name.
+ * @param {function(Entry)} successCallback Callback invoked when the rename
+ *     is successfully done.
+ * @param {function(FileError)} errorCallback Callback invoked when an error
+ *     is found.
+ */
+util.rename = function(entry, newName, successCallback, errorCallback) {
+  entry.getParent(function(parent) {
+    // Before moving, we need to check if there is an existing entry at
+    // parent/newName, since moveTo will overwrite it.
+    // Note that this way has some timing issue. After existing check,
+    // a new entry may be create on background. However, there is no way not to
+    // overwrite the existing file, unfortunately. The risk should be low,
+    // assuming the unsafe period is very short.
+    (entry.isFile ? parent.getFile : parent.getDirectory).call(
+        parent, newName, {create: false},
+        function(entry) {
+          // The entry with the name already exists.
+          errorCallback(util.createFileError(FileError.PATH_EXISTS_ERR));
+        },
+        function(error) {
+          if (error.code != FileError.NOT_FOUND_ERR) {
+            // Unexpected error is found.
+            errorCallback(error);
+            return;
+          }
+
+          // No existing entry is found.
+          entry.moveTo(parent, newName, successCallback, errorCallback);
+        });
+  }, errorCallback);
+};
+
+/**
+ * Remove a file or a directory.
+ * @param {Entry} entry The entry to remove.
+ * @param {function()} onSuccess The success callback.
+ * @param {function(FileError)} onError The error callback.
+ */
+util.removeFileOrDirectory = function(entry, onSuccess, onError) {
+  if (entry.isDirectory)
+    entry.removeRecursively(onSuccess, onError);
+  else
+    entry.remove(onSuccess, onError);
+};
+
+/**
+ * Checks if an entry exists at |relativePath| in |dirEntry|.
+ * If exists, tries to deduplicate the path by inserting parenthesized number,
+ * such as " (1)", before the extension. If it still exists, tries the
+ * deduplication again by increasing the number up to 10 times.
+ * For example, suppose "file.txt" is given, "file.txt", "file (1).txt",
+ * "file (2).txt", ..., "file (9).txt" will be tried.
+ *
+ * @param {DirectoryEntry} dirEntry The target directory entry.
+ * @param {string} relativePath The path to be deduplicated.
+ * @param {function(string)} onSuccess Called with the deduplicated path on
+ *     success.
+ * @param {function(FileError)} onError Called on error.
+ */
+util.deduplicatePath = function(dirEntry, relativePath, onSuccess, onError) {
+  // The trial is up to 10.
+  var MAX_RETRY = 10;
+
+  // Crack the path into three part. The parenthesized number (if exists) will
+  // be replaced by incremented number for retry. For example, suppose
+  // |relativePath| is "file (10).txt", the second check path will be
+  // "file (11).txt".
+  var match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath);
+  var prefix = match[1];
+  var copyNumber = match[2] ? parseInt(match[2], 10) : 0;
+  var ext = match[3] ? match[3] : '';
+
+  // The path currently checking the existence.
+  var trialPath = relativePath;
+
+  var onNotResolved = function(err) {
+    // We expect to be unable to resolve the target file, since we're going
+    // to create it during the copy.  However, if the resolve fails with
+    // anything other than NOT_FOUND, that's trouble.
+    if (err.code != FileError.NOT_FOUND_ERR) {
+      onError(err);
+      return;
+    }
+
+    // Found a path that doesn't exist.
+    onSuccess(trialPath);
+  }
+
+  var numRetry = MAX_RETRY;
+  var onResolved = function(entry) {
+    if (--numRetry == 0) {
+      // Hit the limit of the number of retrial.
+      // Note that we cannot create FileError object directly, so here we use
+      // Object.create instead.
+      onError(util.createFileError(FileError.PATH_EXISTS_ERR));
+      return;
+    }
+
+    ++copyNumber;
+    trialPath = prefix + ' (' + copyNumber + ')' + ext;
+    util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
+  };
+
+  // Check to see if the target exists.
+  util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
+};
+
+/**
+ * Convert a number of bytes into a human friendly format, using the correct
+ * number separators.
+ *
+ * @param {number} bytes The number of bytes.
+ * @return {string} Localized string.
+ */
+util.bytesToString = function(bytes) {
+  // Translation identifiers for size units.
+  var UNITS = ['SIZE_BYTES',
+               'SIZE_KB',
+               'SIZE_MB',
+               'SIZE_GB',
+               'SIZE_TB',
+               'SIZE_PB'];
+
+  // Minimum values for the units above.
+  var STEPS = [0,
+               Math.pow(2, 10),
+               Math.pow(2, 20),
+               Math.pow(2, 30),
+               Math.pow(2, 40),
+               Math.pow(2, 50)];
+
+  var str = function(n, u) {
+    // TODO(rginda): Switch to v8Locale's number formatter when it's
+    // available.
+    return strf(u, n.toLocaleString());
+  };
+
+  var fmt = function(s, u) {
+    var rounded = Math.round(bytes / s * 10) / 10;
+    return str(rounded, u);
+  };
+
+  // Less than 1KB is displayed like '80 bytes'.
+  if (bytes < STEPS[1]) {
+    return str(bytes, UNITS[0]);
+  }
+
+  // Up to 1MB is displayed as rounded up number of KBs.
+  if (bytes < STEPS[2]) {
+    var rounded = Math.ceil(bytes / STEPS[1]);
+    return str(rounded, UNITS[1]);
+  }
+
+  // This loop index is used outside the loop if it turns out |bytes|
+  // requires the largest unit.
+  var i;
+
+  for (i = 2 /* MB */; i < UNITS.length - 1; i++) {
+    if (bytes < STEPS[i + 1])
+      return fmt(STEPS[i], UNITS[i]);
+  }
+
+  return fmt(STEPS[i], UNITS[i]);
+};
+
+/**
+ * Utility function to read specified range of bytes from file
+ * @param {File} file The file to read.
+ * @param {number} begin Starting byte(included).
+ * @param {number} end Last byte(excluded).
+ * @param {function(File, Uint8Array)} callback Callback to invoke.
+ * @param {function(FileError)} onError Error handler.
+ */
+util.readFileBytes = function(file, begin, end, callback, onError) {
+  var fileReader = new FileReader();
+  fileReader.onerror = onError;
+  fileReader.onloadend = function() {
+    callback(file, new ByteReader(fileReader.result));
+  };
+  fileReader.readAsArrayBuffer(file.slice(begin, end));
+};
+
+/**
+ * Write a blob to a file.
+ * Truncates the file first, so the previous content is fully overwritten.
+ * @param {FileEntry} entry File entry.
+ * @param {Blob} blob The blob to write.
+ * @param {function(Event)} onSuccess Completion callback. The first argument is
+ *     a 'writeend' event.
+ * @param {function(FileError)} onError Error handler.
+ */
+util.writeBlobToFile = function(entry, blob, onSuccess, onError) {
+  var truncate = function(writer) {
+    writer.onerror = onError;
+    writer.onwriteend = write.bind(null, writer);
+    writer.truncate(0);
+  };
+
+  var write = function(writer) {
+    writer.onwriteend = onSuccess;
+    writer.write(blob);
+  };
+
+  entry.createWriter(truncate, onError);
+};
+
+/**
+ * Returns a string '[Ctrl-][Alt-][Shift-][Meta-]' depending on the event
+ * modifiers. Convenient for writing out conditions in keyboard handlers.
+ *
+ * @param {Event} event The keyboard event.
+ * @return {string} Modifiers.
+ */
+util.getKeyModifiers = function(event) {
+  return (event.ctrlKey ? 'Ctrl-' : '') +
+         (event.altKey ? 'Alt-' : '') +
+         (event.shiftKey ? 'Shift-' : '') +
+         (event.metaKey ? 'Meta-' : '');
+};
+
+/**
+ * @param {HTMLElement} element Element to transform.
+ * @param {Object} transform Transform object,
+ *                           contains scaleX, scaleY and rotate90 properties.
+ */
+util.applyTransform = function(element, transform) {
+  element.style.webkitTransform =
+      transform ? 'scaleX(' + transform.scaleX + ') ' +
+                  'scaleY(' + transform.scaleY + ') ' +
+                  'rotate(' + transform.rotate90 * 90 + 'deg)' :
+      '';
+};
+
+/**
+ * Makes filesystem: URL from the path.
+ * @param {string} path File or directory path.
+ * @return {string} URL.
+ */
+util.makeFilesystemUrl = function(path) {
+  path = path.split('/').map(encodeURIComponent).join('/');
+  var prefix = 'external';
+  return 'filesystem:' + chrome.runtime.getURL(prefix + path);
+};
+
+/**
+ * Extracts path from filesystem: URL.
+ * @param {string} url Filesystem URL.
+ * @return {string} The path.
+ */
+util.extractFilePath = function(url) {
+  var match =
+      /^filesystem:[\w-]*:\/\/[\w]*\/(external|persistent|temporary)(\/.*)$/.
+      exec(url);
+  var path = match && match[2];
+  if (!path) return null;
+  return decodeURIComponent(path);
+};
+
+/**
+ * Traverses a directory tree whose root is the given entry, and invokes
+ * callback for each entry. Upon completion, successCallback will be called.
+ * On error, errorCallback will be called.
+ *
+ * @param {Entry} entry The root entry.
+ * @param {function(Entry):boolean} callback Callback invoked for each entry.
+ *     If this returns false, entries under it won't be traversed. Note that
+ *     its siblings (and their children) will be still traversed.
+ * @param {function()} successCallback Called upon successful completion.
+ * @param {function(error)} errorCallback Called upon error.
+ */
+util.traverseTree = function(entry, callback, successCallback, errorCallback) {
+  if (!callback(entry)) {
+    successCallback();
+    return;
+  }
+
+  util.forEachDirEntry(
+      entry,
+      function(child, iterationCallback) {
+        util.traverseTree(child, callback, iterationCallback, errorCallback);
+      },
+      successCallback,
+      errorCallback);
+};
+
+/**
+ * A shortcut function to create a child element with given tag and class.
+ *
+ * @param {HTMLElement} parent Parent element.
+ * @param {string=} opt_className Class name.
+ * @param {string=} opt_tag Element tag, DIV is omitted.
+ * @return {Element} Newly created element.
+ */
+util.createChild = function(parent, opt_className, opt_tag) {
+  var child = parent.ownerDocument.createElement(opt_tag || 'div');
+  if (opt_className)
+    child.className = opt_className;
+  parent.appendChild(child);
+  return child;
+};
+
+/**
+ * Update the app state.
+ *
+ * @param {string} path Path to be put in the address bar after the hash.
+ *   If null the hash is left unchanged.
+ * @param {string|Object=} opt_param Search parameter. Used directly if string,
+ *   stringified if object. If omitted the search query is left unchanged.
+ */
+util.updateAppState = function(path, opt_param) {
+  window.appState = window.appState || {};
+  if (typeof opt_param == 'string')
+    window.appState.params = {};
+  else if (typeof opt_param == 'object')
+    window.appState.params = opt_param;
+  if (path)
+    window.appState.defaultPath = path;
+  util.saveAppState();
+  return;
+};
+
+/**
+ * Return a translated string.
+ *
+ * Wrapper function to make dealing with translated strings more concise.
+ * Equivalent to loadTimeData.getString(id).
+ *
+ * @param {string} id The id of the string to return.
+ * @return {string} The translated string.
+ */
+function str(id) {
+  return loadTimeData.getString(id);
+}
+
+/**
+ * Return a translated string with arguments replaced.
+ *
+ * Wrapper function to make dealing with translated strings more concise.
+ * Equivalent to loadTimeData.getStringF(id, ...).
+ *
+ * @param {string} id The id of the string to return.
+ * @param {...string} var_args The values to replace into the string.
+ * @return {string} The translated string with replaced values.
+ */
+function strf(id, var_args) {
+  return loadTimeData.getStringF.apply(loadTimeData, arguments);
+}
+
+/**
+ * Adapter object that abstracts away the the difference between Chrome app APIs
+ * v1 and v2. Is only necessary while the migration to v2 APIs is in progress.
+ * TODO(mtomasz): Clean up this. crbug.com/240606.
+ */
+util.platform = {
+  /**
+   * @return {boolean} True if Files.app is running as an open files or a select
+   *     folder dialog. False otherwise.
+   */
+  runningInBrowser: function() {
+    return !window.appID;
+  },
+
+  /**
+   * @param {function(Object)} callback Function accepting a preference map.
+   */
+  getPreferences: function(callback) {
+    chrome.storage.local.get(callback);
+  },
+
+  /**
+   * @param {string} key Preference name.
+   * @param {function(string)} callback Function accepting the preference value.
+   */
+  getPreference: function(key, callback) {
+    chrome.storage.local.get(key, function(items) {
+      callback(items[key]);
+    });
+  },
+
+  /**
+   * @param {string} key Preference name.
+   * @param {string|Object} value Preference value.
+   * @param {function()=} opt_callback Completion callback.
+   */
+  setPreference: function(key, value, opt_callback) {
+    if (typeof value != 'string')
+      value = JSON.stringify(value);
+
+    var items = {};
+    items[key] = value;
+    chrome.storage.local.set(items, opt_callback);
+  }
+};
+
+/**
+ * Attach page load handler.
+ * @param {function()} handler Application-specific load handler.
+ */
+util.addPageLoadHandler = function(handler) {
+  document.addEventListener('DOMContentLoaded', function() {
+    handler();
+  });
+};
+
+/**
+ * Save app launch data to the local storage.
+ */
+util.saveAppState = function() {
+  if (window.appState)
+    util.platform.setPreference(window.appID, window.appState);
+};
+
+/**
+ *  AppCache is a persistent timestamped key-value storage backed by
+ *  HTML5 local storage.
+ *
+ *  It is not designed for frequent access. In order to avoid costly
+ *  localStorage iteration all data is kept in a single localStorage item.
+ *  There is no in-memory caching, so concurrent access is _almost_ safe.
+ *
+ *  TODO(kaznacheev) Reimplement this based on Indexed DB.
+ */
+util.AppCache = function() {};
+
+/**
+ * Local storage key.
+ */
+util.AppCache.KEY = 'AppCache';
+
+/**
+ * Max number of items.
+ */
+util.AppCache.CAPACITY = 100;
+
+/**
+ * Default lifetime.
+ */
+util.AppCache.LIFETIME = 30 * 24 * 60 * 60 * 1000;  // 30 days.
+
+/**
+ * @param {string} key Key.
+ * @param {function(number)} callback Callback accepting a value.
+ */
+util.AppCache.getValue = function(key, callback) {
+  util.AppCache.read_(function(map) {
+    var entry = map[key];
+    callback(entry && entry.value);
+  });
+};
+
+/**
+ * Update the cache.
+ *
+ * @param {string} key Key.
+ * @param {string} value Value. Remove the key if value is null.
+ * @param {number=} opt_lifetime Maximum time to keep an item (in milliseconds).
+ */
+util.AppCache.update = function(key, value, opt_lifetime) {
+  util.AppCache.read_(function(map) {
+    if (value != null) {
+      map[key] = {
+        value: value,
+        expire: Date.now() + (opt_lifetime || util.AppCache.LIFETIME)
+      };
+    } else if (key in map) {
+      delete map[key];
+    } else {
+      return;  // Nothing to do.
+    }
+    util.AppCache.cleanup_(map);
+    util.AppCache.write_(map);
+  });
+};
+
+/**
+ * @param {function(Object)} callback Callback accepting a map of timestamped
+ *   key-value pairs.
+ * @private
+ */
+util.AppCache.read_ = function(callback) {
+  util.platform.getPreference(util.AppCache.KEY, function(json) {
+    if (json) {
+      try {
+        callback(JSON.parse(json));
+      } catch (e) {
+        // The local storage item somehow got messed up, start fresh.
+      }
+    }
+    callback({});
+  });
+};
+
+/**
+ * @param {Object} map A map of timestamped key-value pairs.
+ * @private
+ */
+util.AppCache.write_ = function(map) {
+  util.platform.setPreference(util.AppCache.KEY, JSON.stringify(map));
+};
+
+/**
+ * Remove over-capacity and obsolete items.
+ *
+ * @param {Object} map A map of timestamped key-value pairs.
+ * @private
+ */
+util.AppCache.cleanup_ = function(map) {
+  // Sort keys by ascending timestamps.
+  var keys = [];
+  for (var key in map) {
+    if (map.hasOwnProperty(key))
+      keys.push(key);
+  }
+  keys.sort(function(a, b) { return map[a].expire > map[b].expire });
+
+  var cutoff = Date.now();
+
+  var obsolete = 0;
+  while (obsolete < keys.length &&
+         map[keys[obsolete]].expire < cutoff) {
+    obsolete++;
+  }
+
+  var overCapacity = Math.max(0, keys.length - util.AppCache.CAPACITY);
+
+  var itemsToDelete = Math.max(obsolete, overCapacity);
+  for (var i = 0; i != itemsToDelete; i++) {
+    delete map[keys[i]];
+  }
+};
+
+/**
+ * Load an image.
+ *
+ * @param {Image} image Image element.
+ * @param {string} url Source url.
+ * @param {Object=} opt_options Hash array of options, eg. width, height,
+ *     maxWidth, maxHeight, scale, cache.
+ * @param {function()=} opt_isValid Function returning false iff the task
+ *     is not valid and should be aborted.
+ * @return {?number} Task identifier or null if fetched immediately from
+ *     cache.
+ */
+util.loadImage = function(image, url, opt_options, opt_isValid) {
+  return ImageLoaderClient.loadToImage(url,
+                                      image,
+                                      opt_options || {},
+                                      function() {},
+                                      function() { image.onerror(); },
+                                      opt_isValid);
+};
+
+/**
+ * Cancels loading an image.
+ * @param {number} taskId Task identifier returned by util.loadImage().
+ */
+util.cancelLoadImage = function(taskId) {
+  ImageLoaderClient.getInstance().cancel(taskId);
+};
+
+/**
+ * Finds proerty descriptor in the object prototype chain.
+ * @param {Object} object The object.
+ * @param {string} propertyName The property name.
+ * @return {Object} Property descriptor.
+ */
+util.findPropertyDescriptor = function(object, propertyName) {
+  for (var p = object; p; p = Object.getPrototypeOf(p)) {
+    var d = Object.getOwnPropertyDescriptor(p, propertyName);
+    if (d)
+      return d;
+  }
+  return null;
+};
+
+/**
+ * Calls inherited property setter (useful when property is
+ * overriden).
+ * @param {Object} object The object.
+ * @param {string} propertyName The property name.
+ * @param {*} value Value to set.
+ */
+util.callInheritedSetter = function(object, propertyName, value) {
+  var d = util.findPropertyDescriptor(Object.getPrototypeOf(object),
+                                      propertyName);
+  d.set.call(object, value);
+};
+
+/**
+ * Returns true if the board of the device matches the given prefix.
+ * @param {string} boardPrefix The board prefix to match against.
+ *     (ex. "x86-mario". Prefix is used as the actual board name comes with
+ *     suffix like "x86-mario-something".
+ * @return {boolean} True if the board of the device matches the given prefix.
+ */
+util.boardIs = function(boardPrefix) {
+  // The board name should be lower-cased, but making it case-insensitive for
+  // backward compatibility just in case.
+  var board = str('CHROMEOS_RELEASE_BOARD');
+  var pattern = new RegExp('^' + boardPrefix, 'i');
+  return board.match(pattern) != null;
+};
+
+/**
+ * Adds an isFocused method to the current window object.
+ */
+util.addIsFocusedMethod = function() {
+  var focused = true;
+
+  window.addEventListener('focus', function() {
+    focused = true;
+  });
+
+  window.addEventListener('blur', function() {
+    focused = false;
+  });
+
+  /**
+   * @return {boolean} True if focused.
+   */
+  window.isFocused = function() {
+    return focused;
+  };
+};
+
+/**
+ * Makes a redirect to the specified Files.app's window from another window.
+ * @param {number} id Window id.
+ * @param {string} url Target url.
+ * @return {boolean} True if the window has been found. False otherwise.
+ */
+util.redirectMainWindow = function(id, url) {
+  // TODO(mtomasz): Implement this for Apps V2, once the photo importer is
+  // restored.
+  return false;
+};
+
+/**
+ * Checks, if the Files.app's window is in a full screen mode.
+ *
+ * @param {AppWindow} appWindow App window to be maximized.
+ * @return {boolean} True if the full screen mode is enabled.
+ */
+util.isFullScreen = function(appWindow) {
+  if (appWindow) {
+    return appWindow.isFullscreen();
+  } else {
+    console.error('App window not passed. Unable to check status of ' +
+                  'the full screen mode.');
+    return false;
+  }
+};
+
+/**
+ * Toggles the full screen mode.
+ *
+ * @param {AppWindow} appWindow App window to be maximized.
+ * @param {boolean} enabled True for enabling, false for disabling.
+ */
+util.toggleFullScreen = function(appWindow, enabled) {
+  if (appWindow) {
+    if (enabled)
+      appWindow.fullscreen();
+    else
+      appWindow.restore();
+    return;
+  }
+
+  console.error(
+      'App window not passed. Unable to toggle the full screen mode.');
+};
+
+/**
+ * The type of a file operation.
+ * @enum {string}
+ */
+util.FileOperationType = {
+  COPY: 'COPY',
+  MOVE: 'MOVE',
+  ZIP: 'ZIP',
+};
+
+/**
+ * The type of a file operation error.
+ * @enum {number}
+ */
+util.FileOperationErrorType = {
+  UNEXPECTED_SOURCE_FILE: 0,
+  TARGET_EXISTS: 1,
+  FILESYSTEM_ERROR: 2,
+};
+
+/**
+ * The kind of an entry changed event.
+ * @enum {number}
+ */
+util.EntryChangedKind = {
+  CREATED: 0,
+  DELETED: 1,
+};
+
+/**
+ * @param {DirectoryEntry|Object} entry DirectoryEntry to be checked.
+ * @return {boolean} True if the given entry is fake.
+ */
+util.isFakeDirectoryEntry = function(entry) {
+  // Currently, fake entry doesn't support createReader.
+  return !('createReader' in entry);
+};
+
+/**
+ * Creates a FileError instance with given code.
+ * Note that we cannot create FileError instance by "new FileError(code)",
+ * unfortunately, so here we use Object.create.
+ * @param {number} code Error code for the FileError.
+ * @return {FileError} FileError instance
+ */
+util.createFileError = function(code) {
+  return Object.create(FileError.prototype, {
+    code: { get: function() { return code; } }
+  });
+};
+
+/**
+ * @param {Entry|Object} entry1 The entry to be compared. Can be a fake.
+ * @param {Entry|Object} entry2 The entry to be compared. Can be a fake.
+ * @return {boolean} True if the both entry represents a same file or directory.
+ */
+util.isSameEntry = function(entry1, entry2) {
+  // Currently, we can assume there is only one root.
+  // When we support multi-file system, we need to look at filesystem, too.
+  return entry1 === null ? entry2 === null : entry1.fullPath == entry2.fullPath;
+};
+
+/**
+ * @param {Entry|Object} parent The parent entry. Can be a fake.
+ * @param {Entry|Object} child The child entry. Can be a fake.
+ * @return {boolean} True if parent entry is actualy the parent of the child
+ *     entry.
+ */
+util.isParentEntry = function(parent, child) {
+  // Currently, we can assume there is only one root.
+  // When we support multi-file system, we need to look at filesystem, too.
+  return PathUtil.isParentPath(parent.fullPath, child.fullPath);
+};
+
+/**
+ * Views files in the browser.
+ *
+ * @param {Array.<string>} urls URLs of files to view.
+ * @param {function(bool)} callback Callback notifying success or not.
+ */
+util.viewFilesInBrowser = function(urls, callback) {
+  var taskId = chrome.runtime.id + '|file|view-in-browser';
+  chrome.fileBrowserPrivate.executeTask(taskId, urls, callback);
+};
+
+/**
+ * Visit the URL.
+ *
+ * If the browser is opening, the url is opened in a new tag, otherwise the url
+ * is opened in a new window.
+ *
+ * @param {string} url URL to visit.
+ */
+util.visitURL = function(url) {
+  var params = {url: url};
+  chrome.tabs.create(params, function() {
+    if (chrome.runtime.lastError)
+      chrome.windows.create(params);
+  });
+};
+
+/**
+ * Returns normalized current locale, or default locale - 'en'.
+ * @return {string} Current locale
+ */
+util.getCurrentLocaleOrDefault = function() {
+  // chrome.i18n.getMessage('@@ui_locale') can't be used in packed app.
+  // Instead, we pass it from C++-side with strings.
+  return str('UI_LOCALE') || 'en';
+};
+
+/**
+ * Error type of VolumeManager.
+ * @enum {string}
+ */
+util.VolumeError = Object.freeze({
+  /* Internal errors */
+  NOT_MOUNTED: 'not_mounted',
+  TIMEOUT: 'timeout',
+
+  /* System events */
+  UNKNOWN: 'error_unknown',
+  INTERNAL: 'error_internal',
+  UNKNOWN_FILESYSTEM: 'error_unknown_filesystem',
+  UNSUPPORTED_FILESYSTEM: 'error_unsupported_filesystem',
+  INVALID_ARCHIVE: 'error_invalid_archive',
+  AUTHENTICATION: 'error_authentication',
+  PATH_UNMOUNTED: 'error_path_unmounted'
+});
+
+/**
+ * List of connection types of drive.
+ *
+ * Keep this in sync with the kDriveConnectionType* constants in
+ * file_browser_private_api.cc.
+ *
+ * @enum {string}
+ */
+util.DriveConnectionType = Object.freeze({
+  OFFLINE: 'offline',  // Connection is offline or drive is unavailable.
+  METERED: 'metered',  // Connection is metered. Should limit traffic.
+  ONLINE: 'online'     // Connection is online.
+});
+
+/**
+ * List of reasons of DriveConnectionType.
+ *
+ * Keep this in sync with the kDriveConnectionReason constants in
+ * file_browser_private_api.cc.
+ *
+ * @enum {string}
+ */
+util.DriveConnectionReason = Object.freeze({
+  NOT_READY: 'not_ready',    // Drive is not ready or authentication is failed.
+  NO_NETWORK: 'no_network',  // Network connection is unavailable.
+  NO_SERVICE: 'no_service'   // Drive service is unavailable.
+});
+
+/**
+ * The type of each volume.
+ * @enum {string}
+ */
+util.VolumeType = Object.freeze({
+  DRIVE: 'drive',
+  DOWNLOADS: 'downloads',
+  REMOVABLE: 'removable',
+  ARCHIVE: 'archive'
+});
diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css
index 5bba9a9..6e58a0d 100644
--- a/chrome/browser/resources/file_manager/css/file_manager.css
+++ b/chrome/browser/resources/file_manager/css/file_manager.css
@@ -7,6 +7,7 @@
  * - 3: preview-panel
  * - 500: scrollbar
  * - 500: splitter
+ * - 525: spinner
  * - 550: autocomplete-suggestions
  * - 600: menus
  * - 600: tooltip
@@ -724,28 +725,14 @@
   width: 16px;
 }
 
-#spinner-container,
-.spinner-container {
-  -webkit-box-align: center;
-  -webkit-box-pack: center;
+.spinner-layer {
+  background: url(../images/common/spinner.svg) center / 16px no-repeat;
   bottom: 0;
-  display: -webkit-box;
   left: 0;
-  pointer-events: none;
   position: absolute;
   right: 0;
   top: 0;
-}
-
-#spinner-with-text {
-  background: no-repeat url(../images/common/spinner.svg);
-  font-size: 16px;
-  height: 16px;
-  line-height: 16px;
-  min-width: 16px;
-  padding-left: 26px;
-  position: relative;
-  z-index: 10;
+  z-index: 525;
 }
 
 .downloads-warning {
@@ -1408,6 +1395,7 @@
 
 /* Overlay pane covering the entire file manager window (e.g. image editor)*/
 .overlay-pane {
+  -webkit-app-region: no-drag;
   border: none;
   height: 100%;
   left: 0;
@@ -1802,10 +1790,10 @@
 
 #iframe-drag-area {
   -webkit-app-region: drag;
-  height: 45px;
+  height: 48px;
   left: 64px;
   position: absolute;
-  right: 70px;
+  right: 92px;
   top: 0;
   width: auto;
   z-index: 101;
@@ -1829,17 +1817,18 @@
 #suggest-app-dialog #webview-container {
   border-bottom: solid 1px #bbb;
   border-top: solid 1px #bbb;
+  position: relative;
 }
 
 #suggest-app-dialog.show-spinner #webview-container webview {
   pointer-events: none;
 }
 
-#suggest-app-dialog:not(.show-spinner) .spinner-container {
+#suggest-app-dialog:not(.show-spinner) .spinner-layer {
   display: none;
 }
 
-#suggest-app-dialog .spinner-container {
+#suggest-app-dialog .spinner-layer {
   background-color: rgba(255, 255, 255, 0.7);
   top: 45px;  /* Title: 44px, border: 1px */
 }
diff --git a/chrome/browser/resources/file_manager/css/photo_import.css b/chrome/browser/resources/file_manager/css/photo_import.css
deleted file mode 100644
index 7505ff6..0000000
--- a/chrome/browser/resources/file_manager/css/photo_import.css
+++ /dev/null
@@ -1,237 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.photo-import {
-  -webkit-user-select: none;
-  bottom: 0;
-  font-family: Noto Sans UI, Droid Sans Fallback, sans-serif;
-  font-size: 84%;
-  left: 0;
-  margin: 0;
-  overflow: hidden;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
-.photo-import[loading] grid,
-.photo-import:not([loading]) .spinner {
-  display: none;
-}
-
-.grid-container {
-  -webkit-box-orient: vertical;
-  bottom: 0;
-  display: -webkit-box;
-  left: 0;
-  padding: 0 20px;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
-.spinner {
-  background-image: url(../images/common/spinner.svg);
-  background-size: 100%;
-  height: 16px;
-  left: 50%;
-  margin-left: -8px;
-  margin-top: -8px;
-  position: absolute;
-  top: 50%;
-  width: 16px;
-}
-
-/* The top and bottom bars with buttons */
-
-.topbar,
-.bottombar {
-  -webkit-box-align: center;
-  -webkit-box-orient: horizontal;
-  display: -webkit-box;
-  height: 65px;
-  width: 100%;
-}
-
-.caption {
-  font-size: 150%;
-  margin-left: 8px;
-}
-
-.select {
-  -webkit-margin-start: 15px;
-  color: blue;
-  cursor: pointer;
-  padding-top: 5px;
-}
-
-.bottombar label {
-  -webkit-box-flex: 1;
-  display: block;
-}
-
-.bottombar input {
-  margin-top: 10px;
-}
-
-button.import {
-  min-width: 100px;
-}
-
-/* The cr.ui.Grid representing the files. */
-.photo-import grid {
-  -webkit-box-flex: 1;
-  overflow-y: auto;
-  width: 100%;
-}
-
-
-.photo-import grid::-webkit-scrollbar {
-  background: white;
-  width: 8px;
-}
-
-.photo-import grid::-webkit-scrollbar-thumb {
-  background: rgb(200, 200, 200);
-}
-
-/* Keep width in sync with PhotoImport.ITEM_WIDTH */
-.grid-container grid {
-  line-height: 0;
-}
-
-.grid-item {
-  border: 2px solid transparent;  /* Selection will make the border visible. */
-  border-radius: 0;
-  height: 120px;
-  margin-bottom: 5px;
-  margin-right: 6px;
-  margin-top: 1px;
-  overflow: visible;
-  padding: 0;
-  position: relative;
-  width: 160px;
-}
-
-.grid-frame {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/hashed_bg.gif') 1x,
-    url('../images/files/ui/2x/hashed_bg.gif') 2x);
-  border: 1px solid #d9d9d9;
-  bottom: 0;
-  left: 0;
-  overflow: hidden;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
-.grid-item .check {
-  background: -webkit-image-set(
-    url('../images/common/check_blue.png') 1x,
-    url('../images/common/2x/check_blue.png') 2x) no-repeat;
-  bottom: -3px;
-  display: none;
-  height: 26px;
-  left: -4px;
-  position: absolute;
-  width: 26px;
-}
-
-.img-container {
-  height: 100%;
-  position: relative;
-  width: 100%;
-}
-
-.img-container > img {
-  -webkit-user-drag: none;
-  box-sizing: border-box;
-  position: absolute;
-}
-
-.img-container > img:not(.cached) {
-  -webkit-animation: fadeIn ease-in 1;
-  -webkit-animation-duration: 100ms;
-  -webkit-animation-fill-mode: forwards;
-}
-
-@-webkit-keyframes fadeIn {
-  from {
-    opacity: 0;
-  }
-  to {
-    opacity: 1;
-  }
-}
-
-.grid-item[lead] {
-  border: 2px solid transparent !important;
-}
-
-.grid-item[selected],
-.grid-item[lead][selected],
-.grid-item:hover {
-  border: 2px solid rgb(51, 153, 255) !important;
-}
-
-.grid-item[selected] .check {
-  display: block;
-}
-
-/* Importing dialog styles */
-.importing-dialog .cr-dialog-frame {
-  -webkit-box-orient: horizontal;
-  padding: 14px;
-}
-
-.importing-dialog .cr-dialog-frame .progress-container {
-  -webkit-box-flex: 1;
-  -webkit-box-orient: vertical;
-  display: -webkit-box;
-}
-
-.importing-dialog .img-container {
-  display: -webkit-box;
-  height: 120px;
-  overflow: hidden;
-  width: 120px;
-}
-
-.importing-dialog .content {
-  -webkit-box-flex: 1;
-  -webkit-box-orient: vertical;
-  -webkit-margin-before: 14px;
-  -webkit-margin-start: 15px;
-  display: -webkit-box;
-}
-
-.importing-dialog .cr-dialog-title {
-  display: none;
-}
-
-.importing-dialog .img-container[state=success]::after {
-  background: -webkit-image-set(
-    url('../images/common/check_circled.png') 1x,
-    url('../images/common/2x/check_circled.png') 2x)
-    no-repeat center rgba(20, 20, 22, 0.5);
-  content: '';
-  height: 120px;
-  left: 0;
-  opacity: 0.9;
-  position: absolute;
-  top: 0;
-  width: 120px;
-}
-
-.importing-dialog .img-container[state=error]::after {
-  background: rgba(20, 20, 22, 0.5);
-  content: '';
-  height: 120px;
-  left: 0;
-  opacity: 0.9;
-  position: absolute;
-  top: 0;
-  width: 120px;
-}
diff --git a/chrome/browser/resources/file_manager/css/select_album_dialog.css b/chrome/browser/resources/file_manager/css/select_album_dialog.css
deleted file mode 100644
index 4ce584a..0000000
--- a/chrome/browser/resources/file_manager/css/select_album_dialog.css
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.select-album-dialog-container {
-  -webkit-box-align: center;
-  -webkit-box-pack: center;
-  -webkit-user-select: none;
-  display: -webkit-box;
-  height: 100%;
-  left: 0;
-  overflow: hidden;
-  position: absolute;
-  top: 0;
-  width: 100%;
-  z-index: 9999;
-}
-
-.select-album-dialog-shield {
-  background-color: rgba(0, 0, 0, 0);
-  bottom: 0;
-  display: block;
-  left: 0;
-  opacity: 0;
-  pointer-events: none;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
-.select-album-dialog-frame {
-  -webkit-box-orient: vertical;
-  background-color: black;
-  border: 1px solid rgba(255, 255, 255, 0.3);
-  border-radius: 0;
-  color: white;
-  cursor: default;
-  display: -webkit-box;
-  padding: 14px 17px;
-  position: relative;
-  width: 460px;
-}
-
-.select-album-dialog-caption {
-  margin: 10px 0;
-}
-
-.select-album-dialog-buttons {
-  -webkit-box-orient: horizontal;
-  -webkit-box-pack: end;
-  display: -webkit-box;
-  padding-top: 10px;
-}
-
-.select-album-list {
-  max-height: 390px;
-}
-
-.select-album-list::-webkit-scrollbar {
-  background: black;
-}
-
-.select-album-list::-webkit-scrollbar-thumb {
-  background: rgb(31, 31, 31);
-}
-
-.select-album-list > li {
-  -webkit-box-align: center;
-  -webkit-box-orient: horizontal;
-  -webkit-box-pack: start;
-  background: black;
-  border: none !important;
-  display: -webkit-box;
-  height: 130px;
-  margin: 0;
-  padding: 0;
-}
-
-.select-album-list > li:hover,
-.select-album-list > li[selected],
-.select-album-list > li[lead] {
-  background: rgb(50, 50, 50) !important;
-}
-
-.select-album-list > li > .img-frame {
-  height: 120px;
-  margin: 5px;
-  width: 160px;
-}
-
-.select-album-list > li > .name {
-  -webkit-box-flex: 1;
-  font-size: 120%;
-  margin-left: 15px;
-  margin-right: 15px;
-}
-
-.select-album-list > li > input {
-  -webkit-appearance: none;
-  background: rgba(0, 0, 0, 0);
-  border: none;
-  color: white;
-  height: 26px;
-  padding: 1px 3px;
-}
-
-.select-album-list > li > input:focus,
-.select-album-list > li > input:hover {
-  background: rgb(31, 31, 31);
-  outline: none;
-}
diff --git a/chrome/browser/resources/file_manager/css/tile_view.css b/chrome/browser/resources/file_manager/css/tile_view.css
deleted file mode 100644
index eafb3bf..0000000
--- a/chrome/browser/resources/file_manager/css/tile_view.css
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.tile-view {
-  -webkit-box-align: center;
-  -webkit-box-orient: horizontal;
-  -webkit-box-pack: start;
-  display: -webkit-box;
-  overflow-x: scroll;
-  overflow-y: hidden;
-  position: relative;
-}
-
-.tile-box {
-  background: gray;
-  border: solid 1px red;
-  display: block;
-  position: absolute;
-  transition: all ease 300ms;
-}
-
-.tile-box > img {
-  height: 100%;
-  width: 100%;
-}
diff --git a/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice.js b/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice.js
new file mode 100644
index 0000000..4704da8
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice.js
@@ -0,0 +1,516 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+document.addEventListener('DOMContentLoaded', function() {
+  ActionChoice.load();
+});
+
+/**
+ * The main ActionChoice object.
+ *
+ * @param {HTMLElement} dom Container.
+ * @param {Object} params Parameters.
+ * @constructor
+ */
+function ActionChoice(dom, params) {
+  this.dom_ = dom;
+  this.params_ = params;
+  this.document_ = this.dom_.ownerDocument;
+  this.metadataCache_ = this.params_.metadataCache;
+  this.volumeManager_ = new VolumeManagerWrapper(
+      VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED);
+  this.volumeManager_.addEventListener('externally-unmounted',
+     this.onDeviceUnmounted_.bind(this));
+  this.initDom_();
+
+  // Load defined actions and remembered choice, then initialize volumes.
+  this.actions_ = [];
+  this.actionsById_ = {};
+  this.rememberedChoice_ = null;
+
+  ActionChoiceUtil.getDefinedActions(loadTimeData, function(actions) {
+    for (var i = 0; i < actions.length; i++) {
+      this.registerAction_(actions[i]);
+    }
+
+    this.viewFilesAction_ = this.actionsById_['view-files'];
+    this.importPhotosToDriveAction_ =
+        this.actionsById_['import-photos-to-drive'];
+    this.watchSingleVideoAction_ =
+        this.actionsById_['watch-single-video'];
+
+    // Special case: if Google+ Photos is installed, then do not show Drive.
+    for (var i = 0; i < actions.length; i++) {
+      if (actions[i].extensionId == ActionChoice.GPLUS_PHOTOS_EXTENSION_ID) {
+        this.importPhotosToDriveAction_.hidden = true;
+        break;
+      }
+    }
+
+    if (this.params_.advancedMode) {
+      // In the advanced mode, skip auto-choice.
+      this.initializeVolumes_();
+    } else {
+      // Get the remembered action before initializing volumes.
+      ActionChoiceUtil.getRememberedActionId(function(actionId) {
+        this.rememberedChoice_ = actionId;
+        this.initializeVolumes_();
+      }.bind(this));
+    }
+    this.renderList_();
+  }.bind(this));
+
+  // Try to render, what is already available.
+  this.renderList_();
+}
+
+ActionChoice.prototype = { __proto__: cr.EventTarget.prototype };
+
+/**
+ * The number of previews shown.
+ * @type {number}
+ * @const
+ */
+ActionChoice.PREVIEW_COUNT = 3;
+
+/**
+ * Extension id of Google+ Photos app.
+ * @type {string}
+ * @const
+ */
+ActionChoice.GPLUS_PHOTOS_EXTENSION_ID = 'efjnaogkjbogokcnohkmnjdojkikgobo';
+
+/**
+ * Loads app in the document body.
+ * @param {Object=} opt_params Parameters.
+ */
+ActionChoice.load = function(opt_params) {
+  ImageUtil.metrics = metrics;
+
+  var hash = location.hash ? decodeURIComponent(location.hash.substr(1)) : '';
+  var query =
+      location.search ? decodeURIComponent(location.search.substr(1)) : '';
+  var params = opt_params || {};
+  if (!params.source) params.source = hash;
+  if (!params.advancedMode) params.advancedMode = (query == 'advanced-mode');
+  if (!params.metadataCache) params.metadataCache = MetadataCache.createFull();
+
+  var group = new Async.Group();
+
+  chrome.fileBrowserPrivate.getStrings(function(strings) {
+    loadTimeData.data = strings;
+    i18nTemplate.process(document, loadTimeData);
+    var dom = document.querySelector('.action-choice');
+    ActionChoice.instance = new ActionChoice(dom, params);
+  });
+};
+
+/**
+ * Registers an action.
+ * @param {Object} action Action item.
+ * @private
+ */
+ActionChoice.prototype.registerAction_ = function(action) {
+  this.actions_.push(action);
+  this.actionsById_[action.id] = action;
+};
+
+/**
+ * Initializes the source and Drive. If the remembered choice is available,
+ * then performs the action.
+ * @private
+ */
+ActionChoice.prototype.initializeVolumes_ = function() {
+  var checkDriveFinished = false;
+  var loadSourceFinished = false;
+
+  var maybeRunRememberedAction = function() {
+    if (!checkDriveFinished || !loadSourceFinished)
+      return;
+
+    // Run the remembered action if it is available.
+    if (this.rememberedChoice_) {
+      var action = this.actionsById_[this.rememberedChoice_];
+      if (action && !action.disabled)
+        this.runAction_(action);
+    }
+  }.bind(this);
+
+  var onCheckDriveFinished = function() {
+    checkDriveFinished = true;
+    maybeRunRememberedAction();
+  };
+
+  var onLoadSourceFinished = function() {
+    loadSourceFinished = true;
+    maybeRunRememberedAction();
+  };
+
+  this.checkDrive_(onCheckDriveFinished);
+  this.loadSource_(this.params_.source, onLoadSourceFinished);
+};
+
+/**
+ * One-time initialization of dom elements.
+ * @private
+ */
+ActionChoice.prototype.initDom_ = function() {
+  this.list_ = new cr.ui.List();
+  this.list_.id = 'actions-list';
+  this.document_.querySelector('.choices').appendChild(this.list_);
+
+  var self = this;  // .bind(this) doesn't work on constructors.
+  this.list_.itemConstructor = function(item) {
+    return self.renderItem(item);
+  };
+
+  this.list_.selectionModel = new cr.ui.ListSingleSelectionModel();
+  this.list_.dataModel = new cr.ui.ArrayDataModel([]);
+  this.list_.autoExpands = true;
+
+  var acceptActionBound = function() {
+    this.acceptAction_();
+  }.bind(this);
+  this.list_.activateItemAtIndex = acceptActionBound;
+  this.list_.addEventListener('click', acceptActionBound);
+
+  this.previews_ = this.document_.querySelector('.previews');
+  this.counter_ = this.document_.querySelector('.counter');
+  this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
+
+  metrics.startInterval('PhotoImport.Load');
+  this.dom_.setAttribute('loading', '');
+};
+
+/**
+ * Renders the list.
+ * @private
+ */
+ActionChoice.prototype.renderList_ = function() {
+  var currentItem = this.list_.dataModel.item(
+      this.list_.selectionModel.selectedIndex);
+
+  this.list_.startBatchUpdates();
+  this.list_.dataModel.splice(0, this.list_.dataModel.length);
+
+  for (var i = 0; i < this.actions_.length; i++) {
+    if (!this.actions_[i].hidden)
+      this.list_.dataModel.push(this.actions_[i]);
+  }
+
+  for (var i = 0; i < this.list_.dataModel.length; i++) {
+    if (this.list_.dataModel.item(i) == currentItem) {
+      this.list_.selectionModel.selectedIndex = i;
+      break;
+    }
+  }
+
+  this.list_.endBatchUpdates();
+};
+
+/**
+ * Renders an item in the list.
+ * @param {Object} item Item to render.
+ * @return {Element} DOM element with representing the item.
+ */
+ActionChoice.prototype.renderItem = function(item) {
+  var result = this.document_.createElement('li');
+
+  var div = this.document_.createElement('div');
+  if (item.disabled && item.disabledTitle)
+    div.textContent = item.disabledTitle;
+  else
+    div.textContent = item.title;
+
+  if (item.class)
+    div.classList.add(item.class);
+  if (item.icon100 && item.icon200)
+    div.style.backgroundImage = '-webkit-image-set(' +
+        'url(' + item.icon100 + ') 1x,' +
+        'url(' + item.icon200 + ') 2x)';
+  if (item.disabled)
+    div.classList.add('disabled');
+
+  cr.defineProperty(result, 'lead', cr.PropertyKind.BOOL_ATTR);
+  cr.defineProperty(result, 'selected', cr.PropertyKind.BOOL_ATTR);
+  result.appendChild(div);
+
+  return result;
+};
+
+/**
+ * Checks whether Drive is reachable.
+ *
+ * @param {function()} callback Completion callback.
+ * @private
+ */
+ActionChoice.prototype.checkDrive_ = function(callback) {
+  this.volumeManager_.ensureInitialized(function() {
+    this.importPhotosToDriveAction_.disabled =
+        !this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
+    this.renderList_();
+    callback();
+  }.bind(this));
+};
+
+/**
+ * Load the source contents.
+ *
+ * @param {string} source Path to source.
+ * @param {function()} callback Completion callback.
+ * @private
+ */
+ActionChoice.prototype.loadSource_ = function(source, callback) {
+  var onTraversed = function(results) {
+    metrics.recordInterval('PhotoImport.Scan');
+    var videos = results.filter(FileType.isVideo);
+    if (videos.length == 1) {
+      this.singleVideo_ = videos[0];
+      this.watchSingleVideoAction_.title = loadTimeData.getStringF(
+          'ACTION_CHOICE_WATCH_SINGLE_VIDEO', videos[0].name);
+      this.watchSingleVideoAction_.hidden = false;
+      this.watchSingleVideoAction_.disabled = false;
+      this.renderList_();
+    }
+
+    var mediaFiles = results.filter(FileType.isImageOrVideo);
+    if (mediaFiles.length == 0) {
+      // If we have no media files, the only choice is view files. So, don't
+      // confuse user with a single choice, and just open file manager.
+      this.viewFiles_();
+      this.recordAction_('view-files-auto');
+      this.close_();
+    }
+
+    if (mediaFiles.length < ActionChoice.PREVIEW_COUNT) {
+      this.counter_.textContent = loadTimeData.getStringF(
+          'ACTION_CHOICE_COUNTER_NO_MEDIA', results.length);
+    } else {
+      this.counter_.textContent = loadTimeData.getStringF(
+          'ACTION_CHOICE_COUNTER', mediaFiles.length);
+    }
+    var previews = mediaFiles.length ? mediaFiles : results;
+    var previewsCount = Math.min(ActionChoice.PREVIEW_COUNT, previews.length);
+    this.renderPreview_(previews, previewsCount);
+    callback();
+  }.bind(this);
+
+  var onEntry = function(entry) {
+    this.sourceEntry_ = entry;
+    this.document_.querySelector('title').textContent = entry.name;
+
+    var volumeInfo = this.volumeManager_.getVolumeInfo(entry.fullPath);
+    var deviceType = volumeInfo && volumeInfo.deviceType;
+    if (deviceType != 'sd') deviceType = 'usb';
+    this.dom_.querySelector('.device-type').setAttribute('device-type',
+        deviceType);
+    this.dom_.querySelector('.loading-text').textContent =
+        loadTimeData.getString('ACTION_CHOICE_LOADING_' +
+                               deviceType.toUpperCase());
+
+    var entryList = [];
+    util.traverseTree(
+        entry,
+        function(traversedEntry) {
+          if (!FileType.isVisible(traversedEntry))
+            return false;
+          entryList.push(traversedEntry);
+          return true;
+        },
+        function() {
+          onTraversed(entryList);
+        },
+        function(error) {
+          console.error(
+              'Failed to traverse [' + entry.fullPath + ']: ' + error.code);
+        });
+  }.bind(this);
+
+  this.sourceEntry_ = null;
+  metrics.startInterval('PhotoImport.Scan');
+  this.volumeManager_.ensureInitialized(function() {
+    this.volumeManager_.resolvePath(
+        source, onEntry,
+        function(error) {
+          this.recordAction_('error');
+          this.close_();
+        }.bind(this));
+  }.bind(this));
+};
+
+/**
+ * Renders a preview for a media entry.
+ * @param {Array.<FileEntry>} entries The entries.
+ * @param {number} count Remaining count.
+ * @private
+ */
+ActionChoice.prototype.renderPreview_ = function(entries, count) {
+  var entry = entries.shift();
+  var box = this.document_.createElement('div');
+  box.className = 'img-container';
+
+  var done = function() {
+    this.dom_.removeAttribute('loading');
+    metrics.recordInterval('PhotoImport.Load');
+  }.bind(this);
+
+  var onSuccess = function() {
+    this.previews_.appendChild(box);
+    if (--count == 0) {
+      done();
+    } else {
+      this.renderPreview_(entries, count);
+    }
+  }.bind(this);
+
+  var onError = function() {
+    if (entries.length == 0) {
+      // Append one image with generic thumbnail.
+      this.previews_.appendChild(box);
+      done();
+    } else {
+      this.renderPreview_(entries, count);
+    }
+  }.bind(this);
+
+  this.metadataCache_.get(entry, 'thumbnail|filesystem',
+      function(metadata) {
+        new ThumbnailLoader(entry.toURL(),
+                            ThumbnailLoader.LoaderType.IMAGE,
+                            metadata).load(
+            box,
+            ThumbnailLoader.FillMode.FILL,
+            ThumbnailLoader.OptimizationMode.NEVER_DISCARD,
+            onSuccess,
+            onError,
+            onError);
+      });
+};
+
+/**
+ * Closes the window.
+ * @private
+ */
+ActionChoice.prototype.close_ = function() {
+  window.close();
+};
+
+/**
+ * Keydown event handler.
+ * @param {Event} e The event.
+ * @private
+ */
+ActionChoice.prototype.onKeyDown_ = function(e) {
+  switch (util.getKeyModifiers(e) + e.keyCode) {
+    case '13':
+      this.acceptAction_();
+      break;
+    case '27':
+      this.recordAction_('close');
+      this.close_();
+      break;
+  }
+};
+
+/**
+ * Runs an action.
+ * @param {Object} action Action item to perform.
+ * @private
+ */
+ActionChoice.prototype.runAction_ = function(action) {
+  // TODO(mtomasz): Remove these predefined actions in Apps v2.
+  if (action == this.importPhotosToDriveAction_)
+    return;
+
+  if (action == this.watchSingleVideoAction_) {
+    util.viewFilesInBrowser([this.singleVideo_.toURL()],
+                            function(success) {});
+    this.recordAction_('watch-single-video');
+    this.close_();
+    return;
+  }
+
+  if (action == this.viewFilesAction_) {
+    this.viewFiles_();
+    this.recordAction_('view-files');
+    this.close_();
+    return;
+  }
+
+  if (!action.extensionId) {
+    console.error('Unknown predefined action.');
+    return;
+  }
+
+  // Run the media galleries handler.
+  chrome.mediaGalleriesPrivate.launchHandler(action.extensionId,
+                                             action.actionId,
+                                             this.params_.source);
+  this.close_();
+};
+
+/**
+ * Handles accepting an action. Checks if the action is available, remembers
+ * and runs it.
+ * @private
+ */
+ActionChoice.prototype.acceptAction_ = function() {
+  var action =
+      this.list_.dataModel.item(this.list_.selectionModel.selectedIndex);
+  if (!action || action.hidden || action.disabled)
+    return;
+
+  this.runAction_(action);
+  ActionChoiceUtil.setRememberedActionId(action.id);
+};
+
+/**
+ * Called when some device is unmounted.
+ * @param {Event} event Event object.
+ * @private
+ */
+ActionChoice.prototype.onDeviceUnmounted_ = function(event) {
+  if (this.sourceEntry_ && event.mountPath == this.sourceEntry_.fullPath)
+    window.close();
+};
+
+/**
+ * Perform the 'view files' action.
+ * @private
+ */
+ActionChoice.prototype.viewFiles_ = function() {
+  var path = this.sourceEntry_.fullPath;
+  chrome.runtime.getBackgroundPage(function(bg) {
+    bg.launchFileManager({defaultPath: path});
+  });
+};
+
+/**
+ * Records an action chosen.
+ * @param {string} action Action name.
+ * @private
+ */
+ActionChoice.prototype.recordAction_ = function(action) {
+  metrics.recordEnum('PhotoImport.Action', action,
+      ['import-photos-to-drive',
+       'view-files',
+       'view-files-auto',
+       'watch-single-video',
+       'error',
+       'close']);
+};
+
+/**
+ * Called when the page is unloaded.
+ */
+ActionChoice.prototype.onUnload = function() {
+  this.volumeManager_.dispose();
+};
+
+function unload() {
+  if (ActionChoice.instance)
+    ActionChoice.instance.onUnload();
+}
diff --git a/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_scripts.js b/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_scripts.js
new file mode 100644
index 0000000..0befc3c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_scripts.js
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 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.
+
+// The include directives are put into Javascript-style comments to prevent
+// parsing errors in non-flattened mode. The flattener still sees them.
+// Note that this makes the flattener to comment out the first line of the
+// included file but that's all right since any javascript file should start
+// with a copyright comment anyway.
+
+//<include src="../../../../image_loader/image_loader_client.js"/>
+
+//<include src="../../../../../../../ui/webui/resources/js/load_time_data.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/util.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/i18n_template_no_process.js"/>
+
+//<include src="../../../../../../../ui/webui/resources/js/cr.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/event_tracker.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_item.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list.js"/>
+
+(function() {
+// 'strict mode' is invoked for this scope.
+
+//<include src="../../../common/js/async_util.js"/>
+//<include src="../../../common/js/util.js"/>
+//<include src="../../../common/js/path_util.js"/>
+
+//<include src="../file_type.js"/>
+//<include src="../volume_manager_wrapper.js"/>
+//<include src="../metadata/metadata_cache.js"/>
+//<include src="../metrics.js"/>
+//<include src="../image_editor/image_util.js"/>
+//<include src="../media/media_util.js"/>
+
+//<include src="action_choice_util.js"/>
+//<include src="action_choice.js"/>
+
+// Exports
+window.ImageUtil = ImageUtil;
+
+})();
diff --git a/chrome/browser/resources/file_manager/js/action_choice_util.js b/chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/action_choice_util.js
rename to chrome/browser/resources/file_manager/foreground/js/action_choice/action_choice_util.js
diff --git a/chrome/browser/resources/file_manager/js/app_installer.js b/chrome/browser/resources/file_manager/foreground/js/app_installer.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/app_installer.js
rename to chrome/browser/resources/file_manager/foreground/js/app_installer.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/butter_bar.js b/chrome/browser/resources/file_manager/foreground/js/butter_bar.js
new file mode 100644
index 0000000..6df734a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/butter_bar.js
@@ -0,0 +1,367 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Butter bar is shown on top of the file list and is used to show the copy
+ * progress and other messages.
+ * @param {HTMLElement} dialogDom FileManager top-level div.
+ * @param {FileOperationManagerWrapper} fileOperationManager The operation
+ *     manager.
+ * @constructor
+ */
+function ButterBar(dialogDom, fileOperationManager) {
+  this.dialogDom_ = dialogDom;
+  this.butter_ = this.dialogDom_.querySelector('#butter-bar');
+  this.document_ = this.butter_.ownerDocument;
+  this.fileOperationManager_ = fileOperationManager;
+  this.hideTimeout_ = null;
+  this.showTimeout_ = null;
+  this.lastShowTime_ = 0;
+  this.deleteTaskId_ = null;
+  this.currentMode_ = null;
+  this.totalDeleted_ = 0;
+  this.lastProgressValue_ = 0;
+  this.alert_ = new ErrorDialog(this.dialogDom_);
+
+  this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
+  this.fileOperationManager_.addEventListener(
+      'copy-progress', this.onCopyProgressBound_);
+  this.onDeleteBound_ = this.onDelete_.bind(this);
+  this.fileOperationManager_.addEventListener('delete', this.onDeleteBound_);
+}
+
+/**
+ * The default amount of milliseconds time, before a butter bar will hide after
+ * the last update.
+ * @type {number}
+ * @private
+ * @const
+ */
+ButterBar.HIDE_DELAY_TIME_MS_ = 2000;
+
+/**
+ * Name of action which should be displayed as an 'x' button instead of
+ * link with text.
+ * @const
+ */
+ButterBar.ACTION_X = '--action--x--';
+
+/**
+ * Butter bar mode.
+ * @const
+ */
+ButterBar.Mode = {
+  COPY: 1,
+  DELETE: 2
+};
+
+/**
+ * Disposes the instance. No methods should be called after this method's
+ * invocation.
+ */
+ButterBar.prototype.dispose = function() {
+  // Unregister listeners from FileOperationManager.
+  this.fileOperationManager_.removeEventListener(
+      'copy-progress', this.onCopyProgressBound_);
+  this.fileOperationManager_.removeEventListener('delete', this.onDeleteBound_);
+};
+
+/**
+ * @return {boolean} True if visible.
+ * @private
+ */
+ButterBar.prototype.isVisible_ = function() {
+  return this.butter_.classList.contains('visible');
+};
+
+/**
+ * Show butter bar.
+ * @param {ButterBar.Mode} mode Butter bar mode.
+ * @param {string} message The message to be shown.
+ * @param {Object=} opt_options Options: 'actions', 'progress', 'timeout'. If
+ *     'timeout' is not specified, HIDE_DELAY_TIME_MS_ is used. If 'timeout' is
+ *     false, the butter bar will not be hidden.
+ */
+ButterBar.prototype.show = function(mode, message, opt_options) {
+  this.currentMode_ = mode;
+
+  this.clearShowTimeout_();
+  this.clearHideTimeout_();
+
+  var actions = this.butter_.querySelector('.actions');
+  actions.textContent = '';
+  if (opt_options && 'actions' in opt_options) {
+    for (var label in opt_options.actions) {
+      var link = this.document_.createElement('a');
+      link.addEventListener('click', function(callback) {
+        callback();
+        return false;
+      }.bind(null, opt_options.actions[label]));
+      if (label == ButterBar.ACTION_X) {
+        link.className = 'x';
+      } else {
+        link.textContent = label;
+      }
+      actions.appendChild(link);
+    }
+    actions.hidden = false;
+  } else {
+    actions.hidden = true;
+  }
+
+  this.butter_.querySelector('.progress-bar').hidden =
+    !(opt_options && 'progress' in opt_options);
+
+  this.butter_.classList.remove('error');
+  this.butter_.classList.remove('visible');  // Will be shown in update_
+  this.update_(message, opt_options);
+};
+
+/**
+ * Show an error message in a popup dialog.
+ * @param {string} message Message.
+ * @private
+ */
+ButterBar.prototype.showError_ = function(message) {
+  // Wait in case there are previous dialogs being closed.
+  setTimeout(function() {
+    this.alert_.showHtml('',  // Title.
+                         message);
+    this.hide_();
+  }.bind(this), cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION);
+};
+
+/**
+ * Set message and/or progress.
+ * @param {string} message Message.
+ * @param {Object=} opt_options Same as in show().
+ * @private
+ */
+ButterBar.prototype.update_ = function(message, opt_options) {
+  if (!opt_options)
+    opt_options = {};
+
+  this.clearHideTimeout_();
+
+  var butterMessage = this.butter_.querySelector('.butter-message');
+   butterMessage.textContent = message;
+  if (message && !this.isVisible_()) {
+    // The butter bar is made visible on the first non-empty message.
+    this.butter_.classList.add('visible');
+  }
+  if (opt_options && 'progress' in opt_options) {
+    butterMessage.classList.add('single-line');
+    var progressTrack = this.butter_.querySelector('.progress-track');
+    // Smoothen the progress only when it goes forward. Especially do not
+    // do the transition effect if resetting to 0.
+    if (opt_options.progress > this.lastProgressValue_)
+      progressTrack.classList.add('smoothed');
+    else
+      progressTrack.classList.remove('smoothed');
+    progressTrack.style.width = (opt_options.progress * 100) + '%';
+    this.lastProgressValue_ = opt_options.progress;
+  } else {
+    butterMessage.classList.remove('single-line');
+  }
+
+  if (opt_options.timeout !== false)
+    this.hide_(opt_options.timeout);
+};
+
+/**
+ * Hide butter bar. There might be the delay before hiding so that butter bar
+ * would be shown for no less than the minimal time.
+ * @param {number=} opt_timeout Delay time in milliseconds before hidding. If it
+ *     is zero, butter bar is hidden immediatelly. If it is not specified,
+ *     HIDE_DELAY_TIME_MS_ is used.
+ * @private
+ */
+ButterBar.prototype.hide_ = function(opt_timeout) {
+  this.clearHideTimeout_();
+
+  if (!this.isVisible_())
+    return;
+
+  var delay = typeof opt_timeout != 'undefined' ?
+    opt_timeout : ButterBar.HIDE_DELAY_TIME_MS_;
+  if (delay <= 0) {
+    this.currentMode_ = null;
+    this.butter_.classList.remove('visible');
+    this.butter_.querySelector('.progress-bar').hidden = true;
+  } else {
+    // Reschedule hide to comply with the minimal display time.
+    this.hideTimeout_ = setTimeout(function() {
+      this.hideTimeout_ = null;
+      this.hide_(0);
+    }.bind(this), delay);
+  }
+};
+
+/**
+ * Clear the show timeout if it is set.
+ * @private
+ */
+ButterBar.prototype.clearShowTimeout_ = function() {
+  if (this.showTimeout_) {
+    clearTimeout(this.showTimeout_);
+    this.showTimeout_ = null;
+  }
+};
+
+/**
+ * Clear the hide timeout if it is set.
+ * @private
+ */
+ButterBar.prototype.clearHideTimeout_ = function() {
+  if (this.hideTimeout_) {
+    clearTimeout(this.hideTimeout_);
+    this.hideTimeout_ = null;
+  }
+};
+
+/**
+ * @return {string} The type of operation.
+ * @private
+ */
+ButterBar.prototype.transferType_ = function() {
+  var progress = this.progress_;
+  if (progress && progress.operationType)
+    return progress.operationType;
+
+  return 'TRANSFER';
+};
+
+/**
+ * Set up butter bar for showing copy progress.
+ *
+ * @param {Object} progress Copy status object created by
+ *     FileOperationManager.getStatus().
+ * @private
+ */
+ButterBar.prototype.showProgress_ = function(progress) {
+  this.progress_ = progress;
+  var options = {
+    progress: progress.processedBytes / progress.totalBytes,
+    actions: {},
+    timeout: false
+  };
+
+  var pendingItems = progress.numRemainingItems;
+  var type = this.transferType_();
+  var progressString = (pendingItems === 1) ?
+          strf(type + '_FILE_NAME', progress.processingEntry.name) :
+          strf(type + '_ITEMS_REMAINING', pendingItems);
+
+  if (this.currentMode_ == ButterBar.Mode.COPY) {
+    this.update_(progressString, options);
+  } else {
+    // Ignore the cancel behavior because the butter bar is already obsoleted.
+    options.actions[ButterBar.ACTION_X] = function() {
+    };
+    this.show(ButterBar.Mode.COPY, progressString, options);
+  }
+};
+
+/**
+ * 'copy-progress' event handler. Show progress or an appropriate message.
+ * @param {Event} event A 'copy-progress' event from FileOperationManager.
+ * @private
+ */
+ButterBar.prototype.onCopyProgress_ = function(event) {
+  // Delete operation has higher priority.
+  if (this.currentMode_ == ButterBar.Mode.DELETE)
+    return;
+
+  if (event.reason != 'PROGRESS')
+    this.clearShowTimeout_();
+
+  switch (event.reason) {
+    case 'BEGIN':
+      this.showTimeout_ = setTimeout(function() {
+        this.showTimeout_ = null;
+        this.showProgress_(event.status);
+      }.bind(this), 500);
+      break;
+
+    case 'PROGRESS':
+      this.showProgress_(event.status);
+      break;
+
+    case 'SUCCESS':
+      this.hide_();
+      break;
+
+    case 'CANCELLED':
+      this.show(ButterBar.Mode.DELETE,
+                str(this.transferType_() + '_CANCELLED'));
+      break;
+
+    case 'ERROR':
+      this.progress_ = event.status;
+      var error = event.error;
+      if (error.code === util.FileOperationErrorType.TARGET_EXISTS) {
+        var name = error.data.name;
+        if (error.data.isDirectory)
+          name += '/';
+        this.showError_(
+            strf(this.transferType_() + '_TARGET_EXISTS_ERROR', name));
+      } else if (error.code === util.FileOperationErrorType.FILESYSTEM_ERROR) {
+        if (error.data.toDrive &&
+            error.data.code === FileError.QUOTA_EXCEEDED_ERR) {
+          // The alert will be shown in FileManager.onCopyProgress_.
+          this.hide_();
+        } else {
+          this.showError_(strf(this.transferType_() + '_FILESYSTEM_ERROR',
+                               util.getFileErrorString(error.data.code)));
+          }
+      } else {
+        this.showError_(
+            strf(this.transferType_() + '_UNEXPECTED_ERROR', error));
+      }
+      break;
+
+    default:
+      console.warn('Unknown "copy-progress" event reason: ' + event.code);
+  }
+};
+
+/**
+ * 'delete' event handler. Shows information about deleting files.
+ * @param {Event} event A 'delete' event from FileOperationManager.
+ * @private
+ */
+ButterBar.prototype.onDelete_ = function(event) {
+  switch (event.reason) {
+    case 'BEGIN':
+      if (this.currentMode_ != ButterBar.Mode.DELETE)
+        this.totalDeleted_ = 0;
+
+    case 'PROGRESS':
+      this.totalDeleted_ += event.urls.length;
+      var title = strf('DELETED_MESSAGE_PLURAL', this.totalDeleted_);
+      if (this.totalDeleted_ == 1) {
+        var fullPath = util.extractFilePath(event.urls[0]);
+        var fileName = PathUtil.split(fullPath).pop();
+        title = strf('DELETED_MESSAGE', fileName);
+      }
+
+      if (this.currentMode_ == ButterBar.Mode.DELETE)
+        this.update_(title);
+      else
+        this.show(ButterBar.Mode.DELETE, title);
+      break;
+
+    case 'SUCCESS':
+      break;
+
+    case 'ERROR':
+      this.showError_(str('DELETE_ERROR'));
+      break;
+
+    default:
+      console.warn('Unknown "delete" event reason: ' + event.reason);
+  }
+};
diff --git a/chrome/browser/resources/file_manager/js/combobutton.js b/chrome/browser/resources/file_manager/foreground/js/combobutton.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/combobutton.js
rename to chrome/browser/resources/file_manager/foreground/js/combobutton.js
diff --git a/chrome/browser/resources/file_manager/js/commandbutton.js b/chrome/browser/resources/file_manager/foreground/js/commandbutton.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/commandbutton.js
rename to chrome/browser/resources/file_manager/foreground/js/commandbutton.js
diff --git a/chrome/browser/resources/file_manager/js/cws_container_client.js b/chrome/browser/resources/file_manager/foreground/js/cws_container_client.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/cws_container_client.js
rename to chrome/browser/resources/file_manager/foreground/js/cws_container_client.js
diff --git a/chrome/browser/resources/file_manager/js/default_action_dialog.js b/chrome/browser/resources/file_manager/foreground/js/default_action_dialog.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/default_action_dialog.js
rename to chrome/browser/resources/file_manager/foreground/js/default_action_dialog.js
diff --git a/chrome/browser/resources/file_manager/js/directory_contents.js b/chrome/browser/resources/file_manager/foreground/js/directory_contents.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/directory_contents.js
rename to chrome/browser/resources/file_manager/foreground/js/directory_contents.js
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/foreground/js/directory_model.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/directory_model.js
rename to chrome/browser/resources/file_manager/foreground/js/directory_model.js
diff --git a/chrome/browser/resources/file_manager/js/directory_tree.js b/chrome/browser/resources/file_manager/foreground/js/directory_tree.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/directory_tree.js
rename to chrome/browser/resources/file_manager/foreground/js/directory_tree.js
diff --git a/chrome/browser/resources/file_manager/js/drag_selector.js b/chrome/browser/resources/file_manager/foreground/js/drag_selector.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/drag_selector.js
rename to chrome/browser/resources/file_manager/foreground/js/drag_selector.js
diff --git a/chrome/browser/resources/file_manager/js/drive_banners.js b/chrome/browser/resources/file_manager/foreground/js/drive_banners.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/drive_banners.js
rename to chrome/browser/resources/file_manager/foreground/js/drive_banners.js
diff --git a/chrome/browser/resources/file_manager/js/error_counter.js b/chrome/browser/resources/file_manager/foreground/js/error_counter.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/error_counter.js
rename to chrome/browser/resources/file_manager/foreground/js/error_counter.js
diff --git a/chrome/browser/resources/file_manager/js/error_dialog.js b/chrome/browser/resources/file_manager/foreground/js/error_dialog.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/error_dialog.js
rename to chrome/browser/resources/file_manager/foreground/js/error_dialog.js
diff --git a/chrome/browser/resources/file_manager/js/file_grid.js b/chrome/browser/resources/file_manager/foreground/js/file_grid.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/file_grid.js
rename to chrome/browser/resources/file_manager/foreground/js/file_grid.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_manager.js b/chrome/browser/resources/file_manager/foreground/js/file_manager.js
new file mode 100644
index 0000000..96a8ee4
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/file_manager.js
@@ -0,0 +1,3640 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * FileManager constructor.
+ *
+ * FileManager objects encapsulate the functionality of the file selector
+ * dialogs, as well as the full screen file manager application (though the
+ * latter is not yet implemented).
+ *
+ * @constructor
+ */
+function FileManager() {
+  this.initializeQueue_ = new AsyncUtil.Group();
+
+  /**
+   * Current list type.
+   * @type {ListType}
+   * @private
+   */
+  this.listType_ = null;
+
+  /**
+   * Whether to suppress the focus moving or not.
+   * This is used to filter out focusing by mouse.
+   * @type {boolean}
+   * @private
+   */
+  this.suppressFocus_ = false;
+
+  /**
+   * SelectionHandler.
+   * @type {SelectionHandler}
+   * @private
+   */
+  this.selectionHandler_ = null;
+}
+
+/**
+ * Maximum delay in milliseconds for updating thumbnails in the bottom panel
+ * to mitigate flickering. If images load faster then the delay they replace
+ * old images smoothly. On the other hand we don't want to keep old images
+ * too long.
+ *
+ * @type {number}
+ * @const
+ */
+FileManager.THUMBNAIL_SHOW_DELAY = 100;
+
+FileManager.prototype = {
+  __proto__: cr.EventTarget.prototype,
+  get directoryModel() {
+    return this.directoryModel_;
+  },
+  get navigationList() {
+    return this.navigationList_;
+  },
+  get document() {
+    return this.document_;
+  },
+  get fileTransferController() {
+    return this.fileTransferController_;
+  },
+  get backgroundPage() {
+    return this.backgroundPage_;
+  }
+};
+
+/**
+ * Unload the file manager.
+ * Used by background.js (when running in the packaged mode).
+ */
+function unload() {
+  fileManager.onBeforeUnload_();
+  fileManager.onUnload_();
+}
+
+/**
+ * List of dialog types.
+ *
+ * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except
+ * FULL_PAGE which is specific to this code.
+ *
+ * @enum {string}
+ */
+var DialogType = {
+  SELECT_FOLDER: 'folder',
+  SELECT_UPLOAD_FOLDER: 'upload-folder',
+  SELECT_SAVEAS_FILE: 'saveas-file',
+  SELECT_OPEN_FILE: 'open-file',
+  SELECT_OPEN_MULTI_FILE: 'open-multi-file',
+  FULL_PAGE: 'full-page'
+};
+
+/**
+ * @param {string} type Dialog type.
+ * @return {boolean} Whether the type is modal.
+ */
+DialogType.isModal = function(type) {
+  return type == DialogType.SELECT_FOLDER ||
+      type == DialogType.SELECT_UPLOAD_FOLDER ||
+      type == DialogType.SELECT_SAVEAS_FILE ||
+      type == DialogType.SELECT_OPEN_FILE ||
+      type == DialogType.SELECT_OPEN_MULTI_FILE;
+};
+
+/**
+ * @param {string} type Dialog type.
+ * @return {boolean} Whether the type is open dialog.
+ */
+DialogType.isOpenDialog = function(type) {
+  return type == DialogType.SELECT_OPEN_FILE ||
+         type == DialogType.SELECT_OPEN_MULTI_FILE;
+};
+
+/**
+ * Bottom margin of the list and tree for transparent preview panel.
+ * @const
+ */
+var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
+
+// Anonymous "namespace".
+(function() {
+
+  // Private variables and helper functions.
+
+  /**
+   * Number of milliseconds in a day.
+   */
+  var MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
+
+  /**
+   * Some UI elements react on a single click and standard double click handling
+   * leads to confusing results. We ignore a second click if it comes soon
+   * after the first.
+   */
+  var DOUBLE_CLICK_TIMEOUT = 200;
+
+  /**
+   * Update the element to display the information about remaining space for
+   * the storage.
+   * @param {!Element} spaceInnerBar Block element for a percentage bar
+   *                                 representing the remaining space.
+   * @param {!Element} spaceInfoLabel Inline element to contain the message.
+   * @param {!Element} spaceOuterBar Block element around the percentage bar.
+   */
+   var updateSpaceInfo = function(
+      sizeStatsResult, spaceInnerBar, spaceInfoLabel, spaceOuterBar) {
+    spaceInnerBar.removeAttribute('pending');
+    if (sizeStatsResult) {
+      var sizeStr = util.bytesToString(sizeStatsResult.remainingSize);
+      spaceInfoLabel.textContent = strf('SPACE_AVAILABLE', sizeStr);
+
+      var usedSpace =
+          sizeStatsResult.totalSize - sizeStatsResult.remainingSize;
+      spaceInnerBar.style.width =
+          (100 * usedSpace / sizeStatsResult.totalSize) + '%';
+
+      spaceOuterBar.hidden = false;
+    } else {
+      spaceOuterBar.hidden = true;
+      spaceInfoLabel.textContent = str('FAILED_SPACE_INFO');
+    }
+  };
+
+  // Public statics.
+
+  FileManager.ListType = {
+    DETAIL: 'detail',
+    THUMBNAIL: 'thumb'
+  };
+
+  FileManager.prototype.initPreferences_ = function(callback) {
+    var group = new AsyncUtil.Group();
+
+    // DRIVE preferences should be initialized before creating DirectoryModel
+    // to rebuild the roots list.
+    group.add(this.getPreferences_.bind(this));
+
+    // Get startup preferences.
+    this.viewOptions_ = {};
+    group.add(function(done) {
+      util.platform.getPreference(this.startupPrefName_, function(value) {
+        // Load the global default options.
+        try {
+          this.viewOptions_ = JSON.parse(value);
+        } catch (ignore) {}
+        // Override with window-specific options.
+        if (window.appState && window.appState.viewOptions) {
+          for (var key in window.appState.viewOptions) {
+            if (window.appState.viewOptions.hasOwnProperty(key))
+              this.viewOptions_[key] = window.appState.viewOptions[key];
+          }
+        }
+        done();
+      }.bind(this));
+    }.bind(this));
+
+    // Get the command line option.
+    group.add(function(done) {
+      chrome.commandLinePrivate.hasSwitch(
+          'file-manager-show-checkboxes', function(flag) {
+        this.showCheckboxes_ = flag;
+        done();
+      }.bind(this));
+    }.bind(this));
+
+    // TODO(yoshiki): Remove the flag when the feature is launched.
+    this.enableExperimentalWebstoreIntegration_ = true;
+
+    group.run(callback);
+  };
+
+  /**
+   * One time initialization for the file system and related things.
+   *
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initFileSystemUI_ = function(callback) {
+    this.table_.startBatchUpdates();
+    this.grid_.startBatchUpdates();
+
+    this.initFileList_();
+    this.setupCurrentDirectory_();
+
+    // PyAuto tests monitor this state by polling this variable
+    this.__defineGetter__('workerInitialized_', function() {
+       return this.metadataCache_.isInitialized();
+    }.bind(this));
+
+    this.initDateTimeFormatters_();
+
+    var self = this;
+
+    // Get the 'allowRedeemOffers' preference before launching
+    // FileListBannerController.
+    this.getPreferences_(function(pref) {
+      /** @type {boolean} */
+      var showOffers = pref['allowRedeemOffers'];
+      self.bannersController_ = new FileListBannerController(
+          self.directoryModel_, self.volumeManager_, self.document_,
+          showOffers);
+      self.bannersController_.addEventListener('relayout',
+                                               self.onResize_.bind(self));
+    });
+
+    var dm = this.directoryModel_;
+    dm.addEventListener('directory-changed',
+                        this.onDirectoryChanged_.bind(this));
+    dm.addEventListener('begin-update-files', function() {
+      self.currentList_.startBatchUpdates();
+    });
+    dm.addEventListener('end-update-files', function() {
+      self.restoreItemBeingRenamed_();
+      self.currentList_.endBatchUpdates();
+    });
+    dm.addEventListener('scan-started', this.onScanStarted_.bind(this));
+    dm.addEventListener('scan-completed', this.onScanCompleted_.bind(this));
+    dm.addEventListener('scan-failed', this.onScanCancelled_.bind(this));
+    dm.addEventListener('scan-cancelled', this.onScanCancelled_.bind(this));
+    dm.addEventListener('scan-updated', this.onScanUpdated_.bind(this));
+    dm.addEventListener('rescan-completed',
+                        this.onRescanCompleted_.bind(this));
+
+    var sm = this.directoryModel_.getFileListSelection();
+    sm.addEventListener('change', function() {
+      if (sm.selectedIndexes.length != 1)
+        return;
+      var view = (this.listType_ == FileManager.ListType.DETAIL) ?
+          this.table_.list : this.grid_;
+      var selectedItem = view.getListItemByIndex(sm.selectedIndex);
+      if (!selectedItem)
+        return;
+      this.ensureItemNotBehindPreviewPanel_(selectedItem, view);
+    }.bind(this));
+
+    this.directoryTree_.addEventListener('change', function() {
+      var selectedSubTree = this.directoryTree_.selectedItem;
+      if (!selectedSubTree)
+        return;
+      var selectedItem = selectedSubTree.rowElement;
+      this.ensureItemNotBehindPreviewPanel_(selectedItem, this.directoryTree_);
+    }.bind(this));
+
+    var stateChangeHandler =
+        this.onPreferencesChanged_.bind(this);
+    chrome.fileBrowserPrivate.onPreferencesChanged.addListener(
+        stateChangeHandler);
+    stateChangeHandler();
+
+    var driveConnectionChangedHandler =
+        this.onDriveConnectionChanged_.bind(this);
+    this.volumeManager_.addEventListener('drive-connection-changed',
+        driveConnectionChangedHandler);
+    driveConnectionChangedHandler();
+
+    // Set the initial focus.
+    this.refocus();
+    // Set it as a fallback when there is no focus.
+    this.document_.addEventListener('focusout', function(e) {
+      setTimeout(function() {
+        // When there is no focus, the active element is the <body>.
+        if (this.document_.activeElement == this.document_.body)
+          this.refocus();
+      }.bind(this), 0);
+    }.bind(this));
+
+    this.initDataTransferOperations_();
+
+    this.initContextMenus_();
+    this.initCommands_();
+
+    this.updateFileTypeFilter_();
+
+    this.selectionHandler_.onFileSelectionChanged();
+
+    this.table_.endBatchUpdates();
+    this.grid_.endBatchUpdates();
+
+    callback();
+  };
+
+  /**
+   * If |item| in |parentView| is behind the preview panel, scrolls up the
+   * parent view and make the item visible. This should be called when:
+   *  - the selected item is changed.
+   *  - the visibility of the the preview panel is changed.
+   *
+   * @param {HTMLElement} item Item to be visible in the parent.
+   * @param {HTMLElement} parentView View contains |selectedItem|.
+   * @private
+   */
+  FileManager.prototype.ensureItemNotBehindPreviewPanel_ =
+      function(item, parentView) {
+    var itemRect = item.getBoundingClientRect();
+    if (!itemRect)
+      return;
+
+    var listRect = parentView.getBoundingClientRect();
+    if (!listRect)
+      return;
+
+    var previewPanel = this.dialogDom_.querySelector('.preview-panel');
+    var previewPanelRect = previewPanel.getBoundingClientRect();
+    var panelHeight = previewPanelRect ? previewPanelRect.height : 0;
+
+    var itemBottom = itemRect.bottom;
+    var listBottom = listRect.bottom - panelHeight;
+
+    if (itemBottom > listBottom) {
+      var scrollOffset = itemBottom - listBottom;
+      parentView.scrollTop += scrollOffset;
+    }
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.initDateTimeFormatters_ = function() {
+    var use12hourClock = !this.preferences_['use24hourClock'];
+    this.table_.setDateTimeFormat(use12hourClock);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.initDataTransferOperations_ = function() {
+    this.fileOperationManager_ = FileOperationManagerWrapper.getInstance(
+        this.backgroundPage_);
+
+    this.butterBar_ = new ButterBar(
+        this.dialogDom_, this.fileOperationManager_);
+
+    // CopyManager and ButterBar are required for 'Delete' operation in
+    // Open and Save dialogs. But drag-n-drop and copy-paste are not needed.
+    if (this.dialogType != DialogType.FULL_PAGE) return;
+
+    // TODO(hidehiko): Extract FileOperationManager related code from
+    // FileManager to simplify it.
+    this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
+    this.fileOperationManager_.addEventListener(
+        'copy-progress', this.onCopyProgressBound_);
+
+    this.onEntryChangedBound_ = this.onEntryChanged_.bind(this);
+    this.fileOperationManager_.addEventListener(
+        'entry-changed', this.onEntryChangedBound_);
+
+    var controller = this.fileTransferController_ =
+        new FileTransferController(this.document_,
+                                   this.fileOperationManager_,
+                                   this.metadataCache_,
+                                   this.directoryModel_);
+    controller.attachDragSource(this.table_.list);
+    controller.attachFileListDropTarget(this.table_.list);
+    controller.attachDragSource(this.grid_);
+    controller.attachFileListDropTarget(this.grid_);
+    controller.attachTreeDropTarget(this.directoryTree_);
+    controller.attachNavigationListDropTarget(this.navigationList_, true);
+    controller.attachCopyPasteHandlers();
+    controller.addEventListener('selection-copied',
+        this.blinkSelection.bind(this));
+    controller.addEventListener('selection-cut',
+        this.blinkSelection.bind(this));
+  };
+
+  /**
+   * One-time initialization of context menus.
+   * @private
+   */
+  FileManager.prototype.initContextMenus_ = function() {
+    this.fileContextMenu_ = this.dialogDom_.querySelector('#file-context-menu');
+    cr.ui.Menu.decorate(this.fileContextMenu_);
+
+    cr.ui.contextMenuHandler.setContextMenu(this.grid_, this.fileContextMenu_);
+    cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'),
+        this.fileContextMenu_);
+    cr.ui.contextMenuHandler.setContextMenu(
+        this.document_.querySelector('.drive-welcome.page'),
+        this.fileContextMenu_);
+
+    this.rootsContextMenu_ =
+        this.dialogDom_.querySelector('#roots-context-menu');
+    cr.ui.Menu.decorate(this.rootsContextMenu_);
+    this.navigationList_.setContextMenu(this.rootsContextMenu_);
+
+    this.directoryTreeContextMenu_ =
+        this.dialogDom_.querySelector('#directory-tree-context-menu');
+    cr.ui.Menu.decorate(this.directoryTreeContextMenu_);
+    this.directoryTree_.contextMenuForSubitems = this.directoryTreeContextMenu_;
+
+    this.textContextMenu_ =
+        this.dialogDom_.querySelector('#text-context-menu');
+    cr.ui.Menu.decorate(this.textContextMenu_);
+
+    this.gearButton_ = this.dialogDom_.querySelector('#gear-button');
+    this.gearButton_.addEventListener('menushow',
+        this.refreshRemainingSpace_.bind(this,
+                                         false /* Without loading caption. */));
+    this.dialogDom_.querySelector('#gear-menu').menuItemSelector =
+        'menuitem, hr';
+    cr.ui.decorate(this.gearButton_, cr.ui.MenuButton);
+
+    if (this.dialogType == DialogType.FULL_PAGE) {
+      // This is to prevent the buttons from stealing focus on mouse down.
+      var preventFocus = function(event) {
+        event.preventDefault();
+      };
+
+      var maximizeButton = this.dialogDom_.querySelector('#maximize-button');
+      maximizeButton.addEventListener('click', this.onMaximize.bind(this));
+      maximizeButton.addEventListener('mousedown', preventFocus);
+
+      var closeButton = this.dialogDom_.querySelector('#close-button');
+      closeButton.addEventListener('click', this.onClose.bind(this));
+      closeButton.addEventListener('mousedown', preventFocus);
+    }
+
+    this.syncButton.checkable = true;
+    this.hostedButton.checkable = true;
+    this.detailViewButton_.checkable = true;
+    this.thumbnailViewButton_.checkable = true;
+
+    if (util.platform.runningInBrowser()) {
+      // Suppresses the default context menu.
+      this.dialogDom_.addEventListener('contextmenu', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+      });
+    }
+  };
+
+  FileManager.prototype.onMaximize = function() {
+    var appWindow = chrome.app.window.current();
+    if (appWindow.isMaximized())
+      appWindow.restore();
+    else
+      appWindow.maximize();
+  };
+
+  FileManager.prototype.onClose = function() {
+    window.close();
+  };
+
+  /**
+   * One-time initialization of commands.
+   * @private
+   */
+  FileManager.prototype.initCommands_ = function() {
+    this.commandHandler = new CommandHandler(this);
+
+    // TODO(hirono): Move the following block to the UI part.
+    var commandButtons = this.dialogDom_.querySelectorAll('button[command]');
+    for (var j = 0; j < commandButtons.length; j++)
+      CommandButton.decorate(commandButtons[j]);
+
+    var inputs = this.dialogDom_.querySelectorAll(
+        'input[type=text], input[type=search], textarea');
+    for (var i = 0; i < inputs.length; i++) {
+      cr.ui.contextMenuHandler.setContextMenu(inputs[i], this.textContextMenu_);
+      this.registerInputCommands_(inputs[i]);
+    }
+
+    cr.ui.contextMenuHandler.setContextMenu(this.renameInput_,
+                                            this.textContextMenu_);
+    this.registerInputCommands_(this.renameInput_);
+    this.document_.addEventListener('command',
+                                    this.setNoHover_.bind(this, true));
+  };
+
+  /**
+   * Registers cut, copy, paste and delete commands on input element.
+   *
+   * @param {Node} node Text input element to register on.
+   * @private
+   */
+  FileManager.prototype.registerInputCommands_ = function(node) {
+    CommandUtil.forceDefaultHandler(node, 'cut');
+    CommandUtil.forceDefaultHandler(node, 'copy');
+    CommandUtil.forceDefaultHandler(node, 'paste');
+    CommandUtil.forceDefaultHandler(node, 'delete');
+    node.addEventListener('keydown', function(e) {
+      if (util.getKeyModifiers(e) + e.keyCode == '191') {
+        // If this key event is propagated, this is handled search command,
+        // which calls 'preventDefault' method.
+        e.stopPropagation();
+      }
+    });
+  };
+
+  /**
+   * Entry point of the initialization.
+   * This method is called from main.js.
+   */
+  FileManager.prototype.initializeCore = function() {
+    this.initializeQueue_.add(this.initGeneral_.bind(this), [], 'initGeneral');
+    this.initializeQueue_.add(this.initStrings_.bind(this), [], 'initStrings');
+    this.initializeQueue_.add(this.initBackgroundPage_.bind(this),
+                              [], 'initBackgroundPage');
+    this.initializeQueue_.add(this.initPreferences_.bind(this),
+                              ['initGeneral'], 'initPreferences');
+    this.initializeQueue_.add(this.initVolumeManager_.bind(this),
+                              ['initGeneral', 'initBackgroundPage'],
+                              'initVolumeManager');
+
+    this.initializeQueue_.run();
+  };
+
+  FileManager.prototype.initializeUI = function(dialogDom, callback) {
+    this.dialogDom_ = dialogDom;
+    this.document_ = this.dialogDom_.ownerDocument;
+
+    this.initializeQueue_.add(
+        this.initEssentialUI_.bind(this),
+        ['initGeneral', 'initStrings'],
+        'initEssentialUI');
+    this.initializeQueue_.add(this.initAdditionalUI_.bind(this),
+        ['initEssentialUI', 'initBackgroundPage'], 'initAdditionalUI');
+    this.initializeQueue_.add(
+        this.initFileSystemUI_.bind(this),
+        ['initAdditionalUI', 'initPreferences'], 'initFileSystemUI');
+
+    // Run again just in case if all pending closures have completed and the
+    // queue has stopped and monitor the completion.
+    this.initializeQueue_.run(callback);
+  };
+
+  /**
+   * Initializes general purpose basic things, which are used by other
+   * initializing methods.
+   *
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initGeneral_ = function(callback) {
+    // Initialize the application state.
+    if (window.appState) {
+      this.params_ = window.appState.params || {};
+      this.defaultPath = window.appState.defaultPath;
+    } else {
+      this.params_ = location.search ?
+                     JSON.parse(decodeURIComponent(location.search.substr(1))) :
+                     {};
+      this.defaultPath = this.params_.defaultPath;
+    }
+
+    // Initialize the member variables that depend this.params_.
+    this.dialogType = this.params_.type || DialogType.FULL_PAGE;
+    this.startupPrefName_ = 'file-manager-' + this.dialogType;
+    this.fileTypes_ = this.params_.typeList || [];
+
+    callback();
+  };
+
+  /**
+   * One time initialization of strings (mostly i18n).
+   *
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initStrings_ = function(callback) {
+    // Fetch the strings via the private api if running in the browser window.
+    // Otherwise, read cached strings from the local storage.
+    if (util.platform.runningInBrowser()) {
+      chrome.fileBrowserPrivate.getStrings(function(strings) {
+        loadTimeData.data = strings;
+        callback();
+      });
+    } else {
+      chrome.storage.local.get('strings', function(items) {
+        loadTimeData.data = items['strings'];
+        callback();
+      });
+    }
+  };
+
+  /**
+   * Initialize the background page.
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initBackgroundPage_ = function(callback) {
+    chrome.runtime.getBackgroundPage(function(backgroundPage) {
+      this.backgroundPage_ = backgroundPage;
+      callback();
+    }.bind(this));
+  };
+
+  /**
+   * Initializes the VolumeManager instance.
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initVolumeManager_ = function(callback) {
+    // Auto resolving to local path does not work for folders (e.g., dialog for
+    // loading unpacked extensions).
+    var noLocalPathResolution =
+      this.params_.type == DialogType.SELECT_FOLDER ||
+      this.params_.type == DialogType.SELECT_UPLOAD_FOLDER;
+
+    // If this condition is false, VolumeManagerWrapper hides all drive
+    // related event and data, even if Drive is enabled on preference.
+    // In other words, even if Drive is disabled on preference but Files.app
+    // should show Drive when it is re-enabled, then the value should be set to
+    // true.
+    // Note that the Drive enabling preference change is listened by
+    // DriveIntegrationService, so here we don't need to take care about it.
+    var driveEnabled =
+        !noLocalPathResolution || !this.params_.shouldReturnLocalPath;
+    this.volumeManager_ = new VolumeManagerWrapper(
+        driveEnabled, this.backgroundPage_);
+    callback();
+  };
+
+  /**
+   * One time initialization of the Files.app's essential UI elements. These
+   * elements will be shown to the user. Only visible elements should be
+   * initialized here. Any heavy operation should be avoided. Files.app's
+   * window is shown at the end of this routine.
+   *
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initEssentialUI_ = function(callback) {
+    // Optional list of file types.
+    metrics.recordEnum('Create', this.dialogType,
+        [DialogType.SELECT_FOLDER,
+         DialogType.SELECT_UPLOAD_FOLDER,
+         DialogType.SELECT_SAVEAS_FILE,
+         DialogType.SELECT_OPEN_FILE,
+         DialogType.SELECT_OPEN_MULTI_FILE,
+         DialogType.FULL_PAGE]);
+
+    // Create the metadata cache.
+    this.metadataCache_ = MetadataCache.createFull();
+
+    // Create the root view of FileManager.
+    this.ui_ = new FileManagerUI(this.dialogDom_, this.dialogType);
+    this.fileTypeSelector_ = this.ui_.fileTypeSelector;
+    this.okButton_ = this.ui_.okButton;
+    this.cancelButton_ = this.ui_.cancelButton;
+
+    // Show the window as soon as the UI pre-initialization is done.
+    if (this.dialogType == DialogType.FULL_PAGE &&
+        !util.platform.runningInBrowser()) {
+      chrome.app.window.current().show();
+      setTimeout(callback, 100);  // Wait until the animation is finished.
+    } else {
+      callback();
+    }
+  };
+
+  /**
+   * One-time initialization of dialogs.
+   * @private
+   */
+  FileManager.prototype.initDialogs_ = function() {
+    // Initialize the dialog.
+    this.ui_.initDialogs();
+    FileManagerDialogBase.setFileManager(this);
+
+    // Obtains the dialog instances from FileManagerUI.
+    // TODO(hirono): Remove the properties from the FileManager class.
+    this.error = this.ui_.errorDialog;
+    this.alert = this.ui_.alertDialog;
+    this.confirm = this.ui_.confirmDialog;
+    this.prompt = this.ui_.promptDialog;
+    this.shareDialog_ = this.ui_.shareDialog;
+    this.defaultTaskPicker = this.ui_.defaultTaskPicker;
+    this.suggestAppsDialog = this.ui_.suggestAppsDialog;
+  };
+
+  /**
+   * One-time initialization of various DOM nodes. Loads the additional DOM
+   * elements visible to the user. Initialize here elements, which are expensive
+   * or hidden in the beginning.
+   *
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initAdditionalUI_ = function(callback) {
+    this.initDialogs_();
+    this.ui_.initAdditionalUI();
+
+    this.dialogDom_.addEventListener('drop', function(e) {
+      // Prevent opening an URL by dropping it onto the page.
+      e.preventDefault();
+    });
+
+    this.dialogDom_.addEventListener('click',
+                                     this.onExternalLinkClick_.bind(this));
+    // Cache nodes we'll be manipulating.
+    var dom = this.dialogDom_;
+
+    this.filenameInput_ = dom.querySelector('#filename-input-box input');
+    this.taskItems_ = dom.querySelector('#tasks');
+
+    this.table_ = dom.querySelector('.detail-table');
+    this.grid_ = dom.querySelector('.thumbnail-grid');
+    this.spinner_ = dom.querySelector('#list-container > .spinner-layer');
+    this.showSpinner_(true);
+
+    // Check the option to hide the selecting checkboxes.
+    this.table_.showCheckboxes = this.showCheckboxes_;
+
+    var fullPage = this.dialogType == DialogType.FULL_PAGE;
+    FileTable.decorate(this.table_, this.metadataCache_, fullPage);
+    FileGrid.decorate(this.grid_, this.metadataCache_);
+
+    this.previewPanel_ = new PreviewPanel(
+        dom.querySelector('.preview-panel'),
+        DialogType.isOpenDialog(this.dialogType) ?
+            PreviewPanel.VisibilityType.ALWAYS_VISIBLE :
+            PreviewPanel.VisibilityType.AUTO,
+        this.getCurrentDirectory(),
+        this.metadataCache_);
+    this.previewPanel_.addEventListener(
+        PreviewPanel.Event.VISIBILITY_CHANGE,
+        this.onPreviewPanelVisibilityChange_.bind(this));
+    this.previewPanel_.initialize();
+
+    this.previewPanel_.breadcrumbs.addEventListener(
+         'pathclick', this.onBreadcrumbClick_.bind(this));
+
+    // Initialize progress center panel.
+    this.progressCenterPanel_ = new ProgressCenterPanel(
+        dom.querySelector('#progress-center'),
+        this.backgroundPage_.background.progressCenter.requestCancel.bind(
+            this.backgroundPage_.background.progressCenter));
+    var initialItems =
+        this.backgroundPage_.background.progressCenter.applicationItems;
+    for (var i = 0; i < initialItems.length; i++) {
+      this.progressCenterPanel_.updateItem(
+          initialItems[i],
+          this.backgroundPage_.background.progressCenter.getSummarizedItem());
+    }
+    this.backgroundPage_.background.progressCenter.addEventListener(
+        ProgressCenterEvent.ITEM_UPDATED,
+        function(event) {
+          this.progressCenterPanel_.updateItem(
+              event.item,
+              this.backgroundPage_.background.progressCenter.
+                  getSummarizedItem());
+        }.bind(this));
+    this.backgroundPage_.background.progressCenter.addEventListener(
+        ProgressCenterEvent.RESET,
+        function(event) {
+          this.progressCenterPanel_.reset();
+        }.bind(this));
+
+    this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
+
+    // This capturing event is only used to distinguish focusing using
+    // keyboard from focusing using mouse.
+    this.document_.addEventListener('mousedown', function() {
+      this.suppressFocus_ = true;
+    }.bind(this), true);
+
+    this.renameInput_ = this.document_.createElement('input');
+    this.renameInput_.className = 'rename';
+
+    this.renameInput_.addEventListener(
+        'keydown', this.onRenameInputKeyDown_.bind(this));
+    this.renameInput_.addEventListener(
+        'blur', this.onRenameInputBlur_.bind(this));
+
+    this.filenameInput_.addEventListener(
+        'keydown', this.onFilenameInputKeyDown_.bind(this));
+    this.filenameInput_.addEventListener(
+        'focus', this.onFilenameInputFocus_.bind(this));
+
+    this.listContainer_ = this.dialogDom_.querySelector('#list-container');
+    this.listContainer_.addEventListener(
+        'keydown', this.onListKeyDown_.bind(this));
+    this.listContainer_.addEventListener(
+        'keypress', this.onListKeyPress_.bind(this));
+    this.listContainer_.addEventListener(
+        'mousemove', this.onListMouseMove_.bind(this));
+
+    this.okButton_.addEventListener('click', this.onOk_.bind(this));
+    this.onCancelBound_ = this.onCancel_.bind(this);
+    this.cancelButton_.addEventListener('click', this.onCancelBound_);
+
+    this.decorateSplitter(
+        this.dialogDom_.querySelector('#navigation-list-splitter'));
+    this.decorateSplitter(
+        this.dialogDom_.querySelector('#middlebar-splitter'));
+
+    this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container');
+
+    this.syncButton = this.dialogDom_.querySelector('#drive-sync-settings');
+    this.syncButton.addEventListener('click', this.onDrivePrefClick_.bind(
+        this, 'cellularDisabled', false /* not inverted */));
+
+    this.hostedButton = this.dialogDom_.querySelector('#drive-hosted-settings');
+    this.hostedButton.addEventListener('click', this.onDrivePrefClick_.bind(
+        this, 'hostedFilesDisabled', true /* inverted */));
+
+    this.detailViewButton_ =
+        this.dialogDom_.querySelector('#detail-view');
+    this.detailViewButton_.addEventListener('click',
+        this.onDetailViewButtonClick_.bind(this));
+
+    this.thumbnailViewButton_ =
+        this.dialogDom_.querySelector('#thumbnail-view');
+    this.thumbnailViewButton_.addEventListener('click',
+        this.onThumbnailViewButtonClick_.bind(this));
+
+    cr.ui.ComboButton.decorate(this.taskItems_);
+    this.taskItems_.showMenu = function(shouldSetFocus) {
+      // Prevent the empty menu from opening.
+      if (!this.menu.length)
+        return;
+      cr.ui.ComboButton.prototype.showMenu.call(this, shouldSetFocus);
+    };
+    this.taskItems_.addEventListener('select',
+        this.onTaskItemClicked_.bind(this));
+
+    this.dialogDom_.ownerDocument.defaultView.addEventListener(
+        'resize', this.onResize_.bind(this));
+
+    this.filePopup_ = null;
+
+    this.searchBoxWrapper_ = this.ui_.searchBox.element;
+    this.searchBox_ = this.ui_.searchBox.inputElement;
+    this.searchBox_.addEventListener(
+        'input', this.onSearchBoxUpdate_.bind(this));
+    this.ui_.searchBox.clearButton.addEventListener(
+        'click', this.onSearchClearButtonClick_.bind(this));
+
+    this.lastSearchQuery_ = '';
+
+    this.autocompleteList_ = this.ui_.searchBox.autocompleteList;
+    this.autocompleteList_.requestSuggestions =
+        this.requestAutocompleteSuggestions_.bind(this);
+
+    // Instead, open the suggested item when Enter key is pressed or
+    // mouse-clicked.
+    this.autocompleteList_.handleEnterKeydown = function(event) {
+      this.openAutocompleteSuggestion_();
+      this.lastAutocompleteQuery_ = '';
+      this.autocompleteList_.suggestions = [];
+    }.bind(this);
+    this.autocompleteList_.addEventListener('mousedown', function(event) {
+      this.openAutocompleteSuggestion_();
+      this.lastAutocompleteQuery_ = '';
+      this.autocompleteList_.suggestions = [];
+    }.bind(this));
+
+    this.defaultActionMenuItem_ =
+        this.dialogDom_.querySelector('#default-action');
+
+    this.openWithCommand_ =
+        this.dialogDom_.querySelector('#open-with');
+
+    this.driveBuyMoreStorageCommand_ =
+        this.dialogDom_.querySelector('#drive-buy-more-space');
+
+    this.defaultActionMenuItem_.addEventListener('click',
+        this.dispatchSelectionAction_.bind(this));
+
+    this.initFileTypeFilter_();
+
+    util.addIsFocusedMethod();
+
+    // Populate the static localized strings.
+    i18nTemplate.process(this.document_, loadTimeData);
+
+    // Arrange the file list.
+    this.table_.normalizeColumns();
+    this.table_.redraw();
+
+    callback();
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onBreadcrumbClick_ = function(event) {
+    this.directoryModel_.changeDirectory(event.path);
+  };
+
+  /**
+   * Constructs table and grid (heavy operation).
+   * @private
+   **/
+  FileManager.prototype.initFileList_ = function() {
+    // Always sharing the data model between the detail/thumb views confuses
+    // them.  Instead we maintain this bogus data model, and hook it up to the
+    // view that is not in use.
+    this.emptyDataModel_ = new cr.ui.ArrayDataModel([]);
+    this.emptySelectionModel_ = new cr.ui.ListSelectionModel();
+
+    var singleSelection =
+        this.dialogType == DialogType.SELECT_OPEN_FILE ||
+        this.dialogType == DialogType.SELECT_FOLDER ||
+        this.dialogType == DialogType.SELECT_UPLOAD_FOLDER ||
+        this.dialogType == DialogType.SELECT_SAVEAS_FILE;
+
+    var showSpecialSearchRoots =
+        this.dialogType == DialogType.SELECT_OPEN_FILE ||
+        this.dialogType == DialogType.SELECT_OPEN_MULTI_FILE ||
+        this.dialogType == DialogType.FULL_PAGE;
+
+    this.fileFilter_ = new FileFilter(
+        this.metadataCache_,
+        false  /* Don't show dot files by default. */);
+
+    this.fileWatcher_ = new FileWatcher(this.metadataCache_);
+    this.fileWatcher_.addEventListener(
+        'watcher-metadata-changed',
+        this.onWatcherMetadataChanged_.bind(this));
+
+    this.directoryModel_ = new DirectoryModel(
+        singleSelection,
+        this.fileFilter_,
+        this.fileWatcher_,
+        this.metadataCache_,
+        this.volumeManager_,
+        showSpecialSearchRoots);
+
+    this.folderShortcutsModel_ = new FolderShortcutsDataModel();
+
+    this.selectionHandler_ = new FileSelectionHandler(this);
+
+    var dataModel = this.directoryModel_.getFileList();
+
+    this.table_.setupCompareFunctions(dataModel);
+
+    dataModel.addEventListener('permuted',
+                               this.updateStartupPrefs_.bind(this));
+
+    this.directoryModel_.getFileListSelection().addEventListener('change',
+        this.selectionHandler_.onFileSelectionChanged.bind(
+            this.selectionHandler_));
+
+    this.initList_(this.grid_);
+    this.initList_(this.table_.list);
+
+    var fileListFocusBound = this.onFileListFocus_.bind(this);
+    var fileListBlurBound = this.onFileListBlur_.bind(this);
+
+    this.table_.list.addEventListener('focus', fileListFocusBound);
+    this.grid_.addEventListener('focus', fileListFocusBound);
+
+    this.table_.list.addEventListener('blur', fileListBlurBound);
+    this.grid_.addEventListener('blur', fileListBlurBound);
+
+    var dragStartBound = this.onDragStart_.bind(this);
+    this.table_.list.addEventListener('dragstart', dragStartBound);
+    this.grid_.addEventListener('dragstart', dragStartBound);
+
+    var dragEndBound = this.onDragEnd_.bind(this);
+    this.table_.list.addEventListener('dragend', dragEndBound);
+    this.grid_.addEventListener('dragend', dragEndBound);
+    // This event is published by DragSelector because drag end event is not
+    // published at the end of drag selection.
+    this.table_.list.addEventListener('dragselectionend', dragEndBound);
+    this.grid_.addEventListener('dragselectionend', dragEndBound);
+
+    // TODO(mtomasz, yoshiki): Create navigation list earlier, and here just
+    // attach the directory model.
+    this.initNavigationList_();
+
+    this.table_.addEventListener('column-resize-end',
+                                 this.updateStartupPrefs_.bind(this));
+
+    // Restore preferences.
+    this.directoryModel_.sortFileList(
+        this.viewOptions_.sortField || 'modificationTime',
+        this.viewOptions_.sortDirection || 'desc');
+    if (this.viewOptions_.columns) {
+      var cm = this.table_.columnModel;
+      for (var i = 0; i < cm.totalSize; i++) {
+        if (this.viewOptions_.columns[i] > 0)
+          cm.setWidth(i, this.viewOptions_.columns[i]);
+      }
+    }
+    this.setListType(this.viewOptions_.listType || FileManager.ListType.DETAIL);
+
+    this.textSearchState_ = {text: '', date: new Date()};
+    this.closeOnUnmount_ = (this.params_.action == 'auto-open');
+
+    if (this.closeOnUnmount_) {
+      this.volumeManager_.addEventListener('externally-unmounted',
+         this.onExternallyUnmounted_.bind(this));
+    }
+
+    // Update metadata to change 'Today' and 'Yesterday' dates.
+    var today = new Date();
+    today.setHours(0);
+    today.setMinutes(0);
+    today.setSeconds(0);
+    today.setMilliseconds(0);
+    setTimeout(this.dailyUpdateModificationTime_.bind(this),
+               today.getTime() + MILLISECONDS_IN_DAY - Date.now() + 1000);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.initNavigationList_ = function() {
+    this.directoryTree_ = this.dialogDom_.querySelector('#directory-tree');
+    DirectoryTree.decorate(this.directoryTree_, this.directoryModel_);
+
+    this.navigationList_ = this.dialogDom_.querySelector('#navigation-list');
+    NavigationList.decorate(this.navigationList_,
+                            this.volumeManager_,
+                            this.directoryModel_);
+    this.navigationList_.fileManager = this;
+    this.navigationList_.dataModel = new NavigationListModel(
+        this.volumeManager_, this.folderShortcutsModel_);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.updateMiddleBarVisibility_ = function() {
+    var entry = this.directoryModel_.getCurrentDirEntry();
+    if (!entry)
+      return;
+
+    var driveVolume = this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
+    var visible =
+        DirectoryTreeUtil.isEligiblePathForDirectoryTree(entry.fullPath) &&
+        driveVolume && !driveVolume.error;
+    this.dialogDom_.
+        querySelector('.dialog-middlebar-contents').hidden = !visible;
+    this.dialogDom_.querySelector('#middlebar-splitter').hidden = !visible;
+    this.onResize_();
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.updateStartupPrefs_ = function() {
+    var sortStatus = this.directoryModel_.getFileList().sortStatus;
+    var prefs = {
+      sortField: sortStatus.field,
+      sortDirection: sortStatus.direction,
+      columns: [],
+      listType: this.listType_
+    };
+    var cm = this.table_.columnModel;
+    for (var i = 0; i < cm.totalSize; i++) {
+      prefs.columns.push(cm.getWidth(i));
+    }
+    // Save the global default.
+    util.platform.setPreference(this.startupPrefName_, JSON.stringify(prefs));
+
+    // Save the window-specific preference.
+    if (window.appState) {
+      window.appState.viewOptions = prefs;
+      util.saveAppState();
+    }
+  };
+
+  FileManager.prototype.refocus = function() {
+    var targetElement;
+    if (this.dialogType == DialogType.SELECT_SAVEAS_FILE)
+      targetElement = this.filenameInput_;
+    else
+      targetElement = this.currentList_;
+
+    // Hack: if the tabIndex is disabled, we can assume a modal dialog is
+    // shown. Focus to a button on the dialog instead.
+    if (!targetElement.hasAttribute('tabIndex') || targetElement.tabIndex == -1)
+      targetElement = document.querySelector('button:not([tabIndex="-1"])');
+
+    if (targetElement)
+      targetElement.focus();
+  };
+
+  /**
+   * File list focus handler. Used to select the top most element on the list
+   * if nothing was selected.
+   *
+   * @private
+   */
+  FileManager.prototype.onFileListFocus_ = function() {
+    // Do not select default item if focused using mouse.
+    if (this.suppressFocus_)
+      return;
+
+    var selection = this.getSelection();
+    if (!selection || selection.totalCount != 0)
+      return;
+
+    this.directoryModel_.selectIndex(0);
+  };
+
+  /**
+   * File list blur handler.
+   *
+   * @private
+   */
+  FileManager.prototype.onFileListBlur_ = function() {
+    this.suppressFocus_ = false;
+  };
+
+  /**
+   * Index of selected item in the typeList of the dialog params.
+   *
+   * @return {number} 1-based index of selected type or 0 if no type selected.
+   * @private
+   */
+  FileManager.prototype.getSelectedFilterIndex_ = function() {
+    var index = Number(this.fileTypeSelector_.selectedIndex);
+    if (index < 0)  // Nothing selected.
+      return 0;
+    if (this.params_.includeAllFiles)  // Already 1-based.
+      return index;
+    return index + 1;  // Convert to 1-based;
+  };
+
+  FileManager.prototype.setListType = function(type) {
+    if (type && type == this.listType_)
+      return;
+
+    this.table_.list.startBatchUpdates();
+    this.grid_.startBatchUpdates();
+
+    // TODO(dzvorygin): style.display and dataModel setting order shouldn't
+    // cause any UI bugs. Currently, the only right way is first to set display
+    // style and only then set dataModel.
+
+    if (type == FileManager.ListType.DETAIL) {
+      this.table_.dataModel = this.directoryModel_.getFileList();
+      this.table_.selectionModel = this.directoryModel_.getFileListSelection();
+      this.table_.hidden = false;
+      this.grid_.hidden = true;
+      this.grid_.selectionModel = this.emptySelectionModel_;
+      this.grid_.dataModel = this.emptyDataModel_;
+      this.table_.hidden = false;
+      /** @type {cr.ui.List} */
+      this.currentList_ = this.table_.list;
+      this.detailViewButton_.setAttribute('checked', '');
+      this.thumbnailViewButton_.removeAttribute('checked');
+      this.detailViewButton_.setAttribute('disabled', '');
+      this.thumbnailViewButton_.removeAttribute('disabled');
+    } else if (type == FileManager.ListType.THUMBNAIL) {
+      this.grid_.dataModel = this.directoryModel_.getFileList();
+      this.grid_.selectionModel = this.directoryModel_.getFileListSelection();
+      this.grid_.hidden = false;
+      this.table_.hidden = true;
+      this.table_.selectionModel = this.emptySelectionModel_;
+      this.table_.dataModel = this.emptyDataModel_;
+      this.grid_.hidden = false;
+      /** @type {cr.ui.List} */
+      this.currentList_ = this.grid_;
+      this.thumbnailViewButton_.setAttribute('checked', '');
+      this.detailViewButton_.removeAttribute('checked');
+      this.thumbnailViewButton_.setAttribute('disabled', '');
+      this.detailViewButton_.removeAttribute('disabled');
+    } else {
+      throw new Error('Unknown list type: ' + type);
+    }
+
+    this.listType_ = type;
+    this.updateStartupPrefs_();
+    this.onResize_();
+
+    this.table_.list.endBatchUpdates();
+    this.grid_.endBatchUpdates();
+  };
+
+  /**
+   * Initialize the file list table or grid.
+   *
+   * @param {cr.ui.List} list The list.
+   * @private
+   */
+  FileManager.prototype.initList_ = function(list) {
+    // Overriding the default role 'list' to 'listbox' for better accessibility
+    // on ChromeOS.
+    list.setAttribute('role', 'listbox');
+    list.addEventListener('click', this.onDetailClick_.bind(this));
+    list.id = 'file-list';
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onCopyProgress_ = function(event) {
+    if (event.reason == 'ERROR' &&
+        event.error.code == util.FileOperationErrorType.FILESYSTEM_ERROR &&
+        event.error.data.toDrive &&
+        event.error.data.code == FileError.QUOTA_EXCEEDED_ERR) {
+      this.alert.showHtml(
+          strf('DRIVE_SERVER_OUT_OF_SPACE_HEADER'),
+          strf('DRIVE_SERVER_OUT_OF_SPACE_MESSAGE',
+              decodeURIComponent(
+                  event.error.data.sourceFileUrl.split('/').pop()),
+              urlConstants.GOOGLE_DRIVE_BUY_STORAGE));
+    }
+
+    // TODO(benchan): Currently, there is no FileWatcher emulation for
+    // drive::FileSystem, so we need to manually trigger the directory rescan
+    // after paste operations complete. Remove this once we emulate file
+    // watching functionalities in drive::FileSystem.
+    if (this.isOnDrive()) {
+      if (event.reason == 'SUCCESS' || event.reason == 'ERROR' ||
+          event.reason == 'CANCELLED') {
+        this.directoryModel_.rescanLater();
+      }
+    }
+  };
+
+  /**
+   * Handler of file manager operations. Called when an entry has been
+   * changed.
+   * This updates directory model to reflect operation result immediately (not
+   * waiting for directory update event). Also, preloads thumbnails for the
+   * images of new entries.
+   * See also FileOperationManager.EventRouter.
+   *
+   * @param {Event} event An event for the entry change.
+   * @private
+   */
+  FileManager.prototype.onEntryChanged_ = function(event) {
+    var kind = event.kind;
+    var entry = event.entry;
+    this.directoryModel_.onEntryChanged(kind, entry);
+    this.selectionHandler_.onFileSelectionChanged();
+
+    if (kind == util.EntryChangedKind.CREATE && FileType.isImage(entry)) {
+      // Preload a thumbnail if the new copied entry an image.
+      var metadata = entry.getMetadata(function(metadata) {
+        var url = entry.toURL();
+        var thumbnailLoader_ = new ThumbnailLoader(
+            url,
+            ThumbnailLoader.LoaderType.CANVAS,
+            metadata,
+            undefined,  // Media type.
+            FileType.isOnDrive(url) ?
+                ThumbnailLoader.UseEmbedded.USE_EMBEDDED :
+                ThumbnailLoader.UseEmbedded.NO_EMBEDDED,
+            10);  // Very low priority.
+        thumbnailLoader_.loadDetachedImage(function(success) {});
+      });
+    }
+  };
+
+  /**
+   * Fills the file type list or hides it.
+   * @private
+   */
+  FileManager.prototype.initFileTypeFilter_ = function() {
+    if (this.params_.includeAllFiles) {
+      var option = this.document_.createElement('option');
+      option.innerText = str('ALL_FILES_FILTER');
+      this.fileTypeSelector_.appendChild(option);
+      option.value = 0;
+    }
+
+    for (var i = 0; i < this.fileTypes_.length; i++) {
+      var fileType = this.fileTypes_[i];
+      var option = this.document_.createElement('option');
+      var description = fileType.description;
+      if (!description) {
+        // See if all the extensions in the group have the same description.
+        for (var j = 0; j != fileType.extensions.length; j++) {
+          var currentDescription =
+              FileType.getTypeString('.' + fileType.extensions[j]);
+          if (!description)  // Set the first time.
+            description = currentDescription;
+          else if (description != currentDescription) {
+            // No single description, fall through to the extension list.
+            description = null;
+            break;
+          }
+        }
+
+        if (!description)
+          // Convert ['jpg', 'png'] to '*.jpg, *.png'.
+          description = fileType.extensions.map(function(s) {
+           return '*.' + s;
+          }).join(', ');
+       }
+       option.innerText = description;
+
+       option.value = i + 1;
+
+       if (fileType.selected)
+         option.selected = true;
+
+       this.fileTypeSelector_.appendChild(option);
+    }
+
+    var options = this.fileTypeSelector_.querySelectorAll('option');
+    if (options.length < 2) {
+      // There is in fact no choice, hide the selector.
+      this.fileTypeSelector_.hidden = true;
+      return;
+    }
+
+    this.fileTypeSelector_.addEventListener('change',
+        this.updateFileTypeFilter_.bind(this));
+  };
+
+  /**
+   * Filters file according to the selected file type.
+   * @private
+   */
+  FileManager.prototype.updateFileTypeFilter_ = function() {
+    this.fileFilter_.removeFilter('fileType');
+    var selectedIndex = this.getSelectedFilterIndex_();
+    if (selectedIndex > 0) { // Specific filter selected.
+      var regexp = new RegExp('.*(' +
+          this.fileTypes_[selectedIndex - 1].extensions.join('|') + ')$', 'i');
+      var filter = function(entry) {
+        return entry.isDirectory || regexp.test(entry.name);
+      };
+      this.fileFilter_.addFilter('fileType', filter);
+    }
+  };
+
+  /**
+   * Resize details and thumb views to fit the new window size.
+   * @private
+   */
+  FileManager.prototype.onResize_ = function() {
+    if (this.listType_ == FileManager.ListType.THUMBNAIL)
+      this.grid_.relayout();
+    else
+      this.table_.relayout();
+
+    // May not be available during initialization.
+    if (this.directoryTree_)
+      this.directoryTree_.relayout();
+
+    // TODO(mtomasz, yoshiki): Initialize navigation list earlier, before
+    // file system is available.
+    if (this.navigationList_)
+      this.navigationList_.redraw();
+
+    this.ui_.searchBox.updateSizeRelatedStyle();
+
+    this.previewPanel_.breadcrumbs.truncate();
+  };
+
+  /**
+   * Handles local metadata changes in the currect directory.
+   * @param {Event} event Change event.
+   * @private
+   */
+  FileManager.prototype.onWatcherMetadataChanged_ = function(event) {
+    this.updateMetadataInUI_(event.metadataType, event.urls, event.properties);
+  };
+
+  /**
+   * Resize details and thumb views to fit the new window size.
+   * @private
+   */
+  FileManager.prototype.onPreviewPanelVisibilityChange_ = function() {
+    // This method may be called on initialization. Some object may not be
+    // initialized.
+
+    var panelHeight = this.previewPanel_.visible ?
+        this.previewPanel_.height : 0;
+    if (this.grid_)
+      this.grid_.setBottomMarginForPanel(panelHeight);
+    if (this.table_)
+      this.table_.setBottomMarginForPanel(panelHeight);
+    if (this.directoryTree_)
+      this.directoryTree_.setBottomMarginForPanel(panelHeight);
+
+    // Make sure that the selected item is not behind the preview panel.
+    if (this.directoryModel_) {
+      var sm = this.directoryModel_.getFileListSelection();
+      var view = (this.listType_ == FileManager.ListType.DETAIL) ?
+          this.table_.list : this.grid_;
+      var selectedItem = view.getListItemByIndex(sm.selectedIndex);
+      if (!selectedItem)
+        return;
+      this.ensureItemNotBehindPreviewPanel_(selectedItem, view);
+    }
+  };
+
+  /**
+   * Invoked when the drag is started on the list or the grid.
+   * @private
+   */
+  FileManager.prototype.onDragStart_ = function() {
+    // On open file dialog, the preview panel is always shown.
+    if (DialogType.isOpenDialog(this.dialogType))
+      return;
+    this.previewPanel_.visibilityType =
+        PreviewPanel.VisibilityType.ALWAYS_HIDDEN;
+  };
+
+  /**
+   * Invoked when the drag is ended on the list or the grid.
+   * @private
+   */
+  FileManager.prototype.onDragEnd_ = function() {
+    // On open file dialog, the preview panel is always shown.
+    if (DialogType.isOpenDialog(this.dialogType))
+      return;
+    this.previewPanel_.visibilityType = PreviewPanel.VisibilityType.AUTO;
+  };
+
+  /**
+   * Restores current directory and may be a selected item after page load (or
+   * reload) or popping a state (after click on back/forward). If location.hash
+   * is present it means that the user has navigated somewhere and that place
+   * will be restored. defaultPath primarily is used with save/open dialogs.
+   * Default path may also contain a file name. Freshly opened file manager
+   * window has neither.
+   *
+   * @private
+   */
+  FileManager.prototype.setupCurrentDirectory_ = function() {
+    var path = location.hash ?  // Location hash has the highest priority.
+        decodeURIComponent(location.hash.substr(1)) :
+        this.defaultPath;
+
+    if (!path) {
+      path = PathUtil.DEFAULT_DIRECTORY;
+    } else if (path.indexOf('/') == -1) {
+      // Path is a file name.
+      path = PathUtil.DEFAULT_DIRECTORY + '/' + path;
+    }
+
+    var tracker = this.directoryModel_.createDirectoryChangeTracker();
+    tracker.start();
+    this.volumeManager_.ensureInitialized(function() {
+      tracker.stop();
+      if (tracker.hasChanged)
+        return;
+
+      // If Drive is disabled but the path points to Drive's entry,
+      // fallback to DEFAULT_DIRECTORY.
+      if (PathUtil.isDriveBasedPath(path) &&
+          !this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE))
+        path = PathUtil.DEFAULT_DIRECTORY + '/' + PathUtil.basename(path);
+
+      this.finishSetupCurrentDirectory_(path);
+    }.bind(this));
+  };
+
+  /**
+   * @param {string} path Path to setup.
+   * @private
+   */
+  FileManager.prototype.finishSetupCurrentDirectory_ = function(path) {
+    this.directoryModel_.setupPath(path, function(baseName, leafName, exists) {
+      if (this.dialogType == DialogType.FULL_PAGE) {
+        // In the FULL_PAGE mode if the hash path points to a file we might have
+        // to invoke a task after selecting it.
+        // If the file path is in params_ we only want to select the file.
+        if (this.params_.action == 'select')
+          return;
+
+        var task = null;
+        if (!exists || leafName == '') {
+          // Non-existent file or a directory.
+          if (this.params_.gallery) {
+            // Reloading while the Gallery is open with empty or multiple
+            // selection. Open the Gallery when the directory is scanned.
+            task = function() {
+              new FileTasks(this, this.params_).openGallery([]);
+            }.bind(this);
+          }
+        } else {
+          // There are 3 ways we can get here:
+          // 1. Invoked from file_manager_util::ViewFile. This can only
+          //    happen for 'gallery' and 'mount-archive' actions.
+          // 2. Reloading a Gallery page. Must be an image or a video file.
+          // 3. A user manually entered a URL pointing to a file.
+          // We call the appropriate methods of FileTasks directly as we do
+          // not need any of the preparations that |execute| method does.
+          var mediaType = FileType.getMediaType(path);
+          if (mediaType == 'image' || mediaType == 'video') {
+            task = function() {
+              new FileTasks(this, this.params_).openGallery(
+                  [util.makeFilesystemUrl(path)]);
+            }.bind(this);
+          } else if (mediaType == 'archive') {
+            task = function() {
+              new FileTasks(this, this.params_).mountArchives(
+                  [util.makeFilesystemUrl(path)]);
+            }.bind(this);
+          }
+        }
+
+        // If there is a task to be run, run it after the scan is completed.
+        if (task) {
+          var listener = function() {
+            this.directoryModel_.removeEventListener(
+                'scan-completed', listener);
+            task();
+          }.bind(this);
+          this.directoryModel_.addEventListener('scan-completed', listener);
+        }
+        return;
+      }
+
+      if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
+        this.filenameInput_.value = leafName;
+        this.selectDefaultPathInFilenameInput_();
+        return;
+      }
+    }.bind(this));
+  };
+
+  /**
+   * Unmounts device.
+   * @param {string} path Path to a volume to unmount.
+   */
+  FileManager.prototype.unmountVolume = function(path) {
+    var onError = function(error) {
+      this.alert.showHtml('', str('UNMOUNT_FAILED'));
+    };
+    this.volumeManager_.unmount(path, function() {}, onError.bind(this));
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.refreshCurrentDirectoryMetadata_ = function() {
+    var entries = this.directoryModel_.getFileList().slice();
+    var directoryEntry = this.directoryModel_.getCurrentDirEntry();
+    if (!directoryEntry)
+      return;
+    // We don't pass callback here. When new metadata arrives, we have an
+    // observer registered to update the UI.
+
+    // TODO(dgozman): refresh content metadata only when modificationTime
+    // changed.
+    var isFakeEntry = typeof directoryEntry.toURL !== 'function';
+    var getEntries = (isFakeEntry ? [] : [directoryEntry]).concat(entries);
+    this.metadataCache_.clearRecursively(directoryEntry, '*');
+    this.metadataCache_.get(getEntries, 'filesystem', null);
+
+    if (this.isOnDrive())
+      this.metadataCache_.get(getEntries, 'drive', null);
+
+    var visibleItems = this.currentList_.items;
+    var visibleEntries = [];
+    for (var i = 0; i < visibleItems.length; i++) {
+      var index = this.currentList_.getIndexOfListItem(visibleItems[i]);
+      var entry = this.directoryModel_.getFileList().item(index);
+      // The following check is a workaround for the bug in list: sometimes item
+      // does not have listIndex, and therefore is not found in the list.
+      if (entry) visibleEntries.push(entry);
+    }
+    this.metadataCache_.get(visibleEntries, 'thumbnail', null);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.dailyUpdateModificationTime_ = function() {
+    var fileList = this.directoryModel_.getFileList();
+    var urls = [];
+    for (var i = 0; i < fileList.length; i++) {
+      urls.push(fileList.item(i).toURL());
+    }
+    this.metadataCache_.get(
+        fileList.slice(), 'filesystem',
+        this.updateMetadataInUI_.bind(this, 'filesystem', urls));
+
+    setTimeout(this.dailyUpdateModificationTime_.bind(this),
+               MILLISECONDS_IN_DAY);
+  };
+
+  /**
+   * @param {string} type Type of metadata changed.
+   * @param {Array.<string>} urls Array of urls.
+   * @param {Object.<string, Object>} props Map from entry URLs to metadata
+   *     props.
+   * @private
+   */
+  FileManager.prototype.updateMetadataInUI_ = function(
+      type, urls, properties) {
+    var propertyByUrl = urls.reduce(function(map, url, index) {
+      map[url] = properties[index];
+      return map;
+    }, {});
+
+    if (this.listType_ == FileManager.ListType.DETAIL)
+      this.table_.updateListItemsMetadata(type, propertyByUrl);
+    else
+      this.grid_.updateListItemsMetadata(type, propertyByUrl);
+    // TODO: update bottom panel thumbnails.
+  };
+
+  /**
+   * Restore the item which is being renamed while refreshing the file list. Do
+   * nothing if no item is being renamed or such an item disappeared.
+   *
+   * While refreshing file list it gets repopulated with new file entries.
+   * There is not a big difference whether DOM items stay the same or not.
+   * Except for the item that the user is renaming.
+   *
+   * @private
+   */
+  FileManager.prototype.restoreItemBeingRenamed_ = function() {
+    if (!this.isRenamingInProgress())
+      return;
+
+    var dm = this.directoryModel_;
+    var leadIndex = dm.getFileListSelection().leadIndex;
+    if (leadIndex < 0)
+      return;
+
+    var leadEntry = dm.getFileList().item(leadIndex);
+    if (this.renameInput_.currentEntry.fullPath != leadEntry.fullPath)
+      return;
+
+    var leadListItem = this.findListItemForNode_(this.renameInput_);
+    if (this.currentList_ == this.table_.list) {
+      this.table_.updateFileMetadata(leadListItem, leadEntry);
+    }
+    this.currentList_.restoreLeadItem(leadListItem);
+  };
+
+  /**
+   * @return {boolean} True if the current directory content is from Google
+   *     Drive.
+   */
+  FileManager.prototype.isOnDrive = function() {
+    var rootType = this.directoryModel_.getCurrentRootType();
+    return rootType === RootType.DRIVE ||
+           rootType === RootType.DRIVE_SHARED_WITH_ME ||
+           rootType === RootType.DRIVE_RECENT ||
+           rootType === RootType.DRIVE_OFFLINE;
+  };
+
+  /**
+   * 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.
+   *
+   * @param {Event} event Click event.
+   * @private
+   */
+  FileManager.prototype.onExternalLinkClick_ = function(event) {
+    if (event.target.tagName != 'A' || !event.target.href)
+      return;
+
+    if (this.dialogType != DialogType.FULL_PAGE)
+      this.onCancel_();
+  };
+
+  /**
+   * Task combobox handler.
+   *
+   * @param {Object} event Event containing task which was clicked.
+   * @private
+   */
+  FileManager.prototype.onTaskItemClicked_ = function(event) {
+    var selection = this.getSelection();
+    if (!selection.tasks) return;
+
+    if (event.item.task) {
+      // Task field doesn't exist on change-default dropdown item.
+      selection.tasks.execute(event.item.task.taskId);
+    } else {
+      var extensions = [];
+
+      for (var i = 0; i < selection.urls.length; i++) {
+        var match = /\.(\w+)$/g.exec(selection.urls[i]);
+        if (match) {
+          var ext = match[1].toUpperCase();
+          if (extensions.indexOf(ext) == -1) {
+            extensions.push(ext);
+          }
+        }
+      }
+
+      var format = '';
+
+      if (extensions.length == 1) {
+        format = extensions[0];
+      }
+
+      // Change default was clicked. We should open "change default" dialog.
+      selection.tasks.showTaskPicker(this.defaultTaskPicker,
+          loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
+          strf('CHANGE_DEFAULT_CAPTION', format),
+          this.onDefaultTaskDone_.bind(this));
+    }
+  };
+
+
+  /**
+   * Sets the given task as default, when this task is applicable.
+   *
+   * @param {Object} task Task to set as default.
+   * @private
+   */
+  FileManager.prototype.onDefaultTaskDone_ = function(task) {
+    // TODO(dgozman): move this method closer to tasks.
+    var selection = this.getSelection();
+    chrome.fileBrowserPrivate.setDefaultTask(task.taskId,
+      selection.urls, selection.mimeTypes);
+    selection.tasks = new FileTasks(this);
+    selection.tasks.init(selection.urls, selection.mimeTypes);
+    selection.tasks.display(this.taskItems_);
+    this.refreshCurrentDirectoryMetadata_();
+    this.selectionHandler_.onFileSelectionChanged();
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onPreferencesChanged_ = function() {
+    var self = this;
+    this.getPreferences_(function(prefs) {
+      self.initDateTimeFormatters_();
+      self.refreshCurrentDirectoryMetadata_();
+
+      if (prefs.cellularDisabled)
+        self.syncButton.setAttribute('checked', '');
+      else
+        self.syncButton.removeAttribute('checked');
+
+      if (self.hostedButton.hasAttribute('checked') !=
+          prefs.hostedFilesDisabled && self.isOnDrive()) {
+        self.directoryModel_.rescan();
+      }
+
+      if (!prefs.hostedFilesDisabled)
+        self.hostedButton.setAttribute('checked', '');
+      else
+        self.hostedButton.removeAttribute('checked');
+    },
+    true /* refresh */);
+  };
+
+  FileManager.prototype.onDriveConnectionChanged_ = function() {
+    var connection = this.volumeManager_.getDriveConnectionState();
+    if (this.commandHandler)
+      this.commandHandler.updateAvailability();
+    if (this.dialogContainer_)
+      this.dialogContainer_.setAttribute('connection', connection.type);
+    this.shareDialog_.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
+    this.suggestAppsDialog.onDriveConnectionChanged(connection.type);
+  };
+
+  /**
+   * Get the metered status of Drive connection.
+   *
+   * @return {boolean} Returns true if drive should limit the traffic because
+   * the connection is metered and the 'disable-sync-on-metered' setting is
+   * enabled. Otherwise, returns false.
+   */
+  FileManager.prototype.isDriveOnMeteredConnection = function() {
+    var connection = this.volumeManager_.getDriveConnectionState();
+    return connection.type == util.DriveConnectionType.METERED;
+  };
+
+  /**
+   * Get the online/offline status of drive.
+   *
+   * @return {boolean} Returns true if the connection is offline. Otherwise,
+   * returns false.
+   */
+  FileManager.prototype.isDriveOffline = function() {
+    var connection = this.volumeManager_.getDriveConnectionState();
+    return connection.type == util.DriveConnectionType.OFFLINE;
+  };
+
+  FileManager.prototype.isOnReadonlyDirectory = function() {
+    return this.directoryModel_.isReadOnly();
+  };
+
+  /**
+   * @param {Event} Unmount event.
+   * @private
+   */
+  FileManager.prototype.onExternallyUnmounted_ = function(event) {
+    if (event.mountPath == this.directoryModel_.getCurrentRootPath()) {
+      if (this.closeOnUnmount_) {
+        // If the file manager opened automatically when a usb drive inserted,
+        // user have never changed current volume (that implies the current
+        // directory is still on the device) then close this window.
+        window.close();
+      }
+    }
+  };
+
+  /**
+   * Show a modal-like file viewer/editor on top of the File Manager UI.
+   *
+   * @param {HTMLElement} popup Popup element.
+   * @param {function()} closeCallback Function to call after the popup is
+   *     closed.
+   */
+  FileManager.prototype.openFilePopup = function(popup, closeCallback) {
+    this.closeFilePopup();
+    this.filePopup_ = popup;
+    this.filePopupCloseCallback_ = closeCallback;
+    this.dialogDom_.insertBefore(
+        this.filePopup_, this.dialogDom_.querySelector('#iframe-drag-area'));
+    this.filePopup_.focus();
+    this.document_.querySelector('#iframe-drag-area').hidden = false;
+  };
+
+  /**
+   * Closes the modal-like file viewer/editor popup.
+   */
+  FileManager.prototype.closeFilePopup = function() {
+    if (this.filePopup_) {
+      this.document_.body.removeAttribute('overlay-visible');
+      this.document_.querySelector('#iframe-drag-area').hidden = true;
+      // The window resize would not be processed properly while the relevant
+      // divs had 'display:none', force resize after the layout fired.
+      setTimeout(this.onResize_.bind(this), 0);
+      if (this.filePopup_.contentWindow &&
+          this.filePopup_.contentWindow.unload) {
+        this.filePopup_.contentWindow.unload();
+      }
+
+      if (this.filePopupCloseCallback_) {
+        this.filePopupCloseCallback_();
+        this.filePopupCloseCallback_ = null;
+      }
+
+      // These operations have to be in the end, otherwise v8 crashes on an
+      // assert. See: crbug.com/224174.
+      this.dialogDom_.removeChild(this.filePopup_);
+      this.filePopup_ = null;
+    }
+  };
+
+  /**
+   * Updates visibility of the draggable app region in the modal-like file
+   * viewer/editor.
+   *
+   * @param {boolean} visible True for visible, false otherwise.
+   */
+  FileManager.prototype.onFilePopupAppRegionChanged = function(visible) {
+    if (!this.filePopup_)
+      return;
+
+    this.document_.querySelector('#iframe-drag-area').hidden = !visible;
+  };
+
+  FileManager.prototype.getAllUrlsInCurrentDirectory = function() {
+    var urls = [];
+    var fileList = this.directoryModel_.getFileList();
+    for (var i = 0; i != fileList.length; i++) {
+      urls.push(fileList.item(i).toURL());
+    }
+    return urls;
+  };
+
+  FileManager.prototype.isRenamingInProgress = function() {
+    return !!this.renameInput_.currentEntry;
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.focusCurrentList_ = function() {
+    if (this.listType_ == FileManager.ListType.DETAIL)
+      this.table_.focus();
+    else  // this.listType_ == FileManager.ListType.THUMBNAIL)
+      this.grid_.focus();
+  };
+
+  /**
+   * Return full path of the current directory or null.
+   * @return {?string} The full path of the current directory.
+   */
+  FileManager.prototype.getCurrentDirectory = function() {
+    return this.directoryModel_ && this.directoryModel_.getCurrentDirPath();
+  };
+
+  /**
+   * Return URL of the current directory or null.
+   * @return {string} URL representing the current directory.
+   */
+  FileManager.prototype.getCurrentDirectoryURL = function() {
+    return this.directoryModel_ &&
+           this.directoryModel_.getCurrentDirectoryURL();
+  };
+
+  /**
+   * Return DirectoryEntry of the current directory or null.
+   * @return {DirectoryEntry} DirectoryEntry of the current directory. Returns
+   *     null if the directory model is not ready or the current directory is
+   *     not set.
+   */
+  FileManager.prototype.getCurrentDirectoryEntry = function() {
+    return this.directoryModel_ && this.directoryModel_.getCurrentDirEntry();
+  };
+
+  /**
+   * Deletes the selected file and directories recursively.
+   */
+  FileManager.prototype.deleteSelection = function() {
+    // TODO(mtomasz): Remove this temporary dialog. crbug.com/167364
+    var entries = this.getSelection().entries;
+    var message = entries.length == 1 ?
+        strf('GALLERY_CONFIRM_DELETE_ONE', entries[0].name) :
+        strf('GALLERY_CONFIRM_DELETE_SOME', entries.length);
+    this.confirm.show(message, function() {
+      this.fileOperationManager_.deleteEntries(entries);
+    }.bind(this));
+  };
+
+  /**
+   * Shows the share dialog for the selected file or directory.
+   */
+  FileManager.prototype.shareSelection = function() {
+    var entries = this.getSelection().entries;
+    if (entries.length != 1) {
+      console.warn('Unable to share multiple items at once.');
+      return;
+    }
+    // Add the overlapped class to prevent the applicaiton window from
+    // captureing mouse events.
+    this.shareDialog_.show(entries[0], function(result) {
+      if (result == ShareDialog.Result.NETWORK_ERROR)
+        this.error.show(str('SHARE_ERROR'));
+    }.bind(this));
+  };
+
+  /**
+   * Creates a folder shortcut.
+   * @param {string} path A shortcut which refers to |path| to be created.
+   */
+  FileManager.prototype.createFolderShortcut = function(path) {
+    // Duplicate entry.
+    if (this.folderShortcutExists(path))
+      return;
+
+    this.folderShortcutsModel_.add(path);
+  };
+
+  /**
+   * Checkes if the shortcut which refers to the given folder exists or not.
+   * @param {string} path Path of the folder to be checked.
+   */
+  FileManager.prototype.folderShortcutExists = function(path) {
+    return this.folderShortcutsModel_.exists(path);
+  };
+
+  /**
+   * Removes the folder shortcut.
+   * @param {string} path The shortcut which refers to |path| is to be removed.
+   */
+  FileManager.prototype.removeFolderShortcut = function(path) {
+    this.folderShortcutsModel_.remove(path);
+  };
+
+  /**
+   * Blinks the selection. Used to give feedback when copying or cutting the
+   * selection.
+   */
+  FileManager.prototype.blinkSelection = function() {
+    var selection = this.getSelection();
+    if (!selection || selection.totalCount == 0)
+      return;
+
+    for (var i = 0; i < selection.entries.length; i++) {
+      var selectedIndex = selection.indexes[i];
+      var listItem = this.currentList_.getListItemByIndex(selectedIndex);
+      if (listItem)
+        this.blinkListItem_(listItem);
+    }
+  };
+
+  /**
+   * @param {Element} listItem List item element.
+   * @private
+   */
+  FileManager.prototype.blinkListItem_ = function(listItem) {
+    listItem.classList.add('blink');
+    setTimeout(function() {
+      listItem.classList.remove('blink');
+    }, 100);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.selectDefaultPathInFilenameInput_ = function() {
+    var input = this.filenameInput_;
+    input.focus();
+    var selectionEnd = input.value.lastIndexOf('.');
+    if (selectionEnd == -1) {
+      input.select();
+    } else {
+      input.selectionStart = 0;
+      input.selectionEnd = selectionEnd;
+    }
+    // Clear, so we never do this again.
+    this.defaultPath = '';
+  };
+
+  /**
+   * Handles mouse click or tap.
+   *
+   * @param {Event} event The click event.
+   * @private
+   */
+  FileManager.prototype.onDetailClick_ = function(event) {
+    if (this.isRenamingInProgress()) {
+      // Don't pay attention to clicks during a rename.
+      return;
+    }
+
+    var listItem = this.findListItemForEvent_(event);
+    var selection = this.getSelection();
+    if (!listItem || !listItem.selected || selection.totalCount != 1) {
+      return;
+    }
+
+    // React on double click, but only if both clicks hit the same item.
+    // TODO(mtomasz): Simplify it, and use a double click handler if possible.
+    var clickNumber = (this.lastClickedItem_ == listItem) ? 2 : undefined;
+    this.lastClickedItem_ = listItem;
+
+    if (event.detail != clickNumber)
+      return;
+
+    var entry = selection.entries[0];
+    if (entry.isDirectory) {
+      this.onDirectoryAction_(entry);
+    } else {
+      this.dispatchSelectionAction_();
+    }
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.dispatchSelectionAction_ = function() {
+    if (this.dialogType == DialogType.FULL_PAGE) {
+      var selection = this.getSelection();
+      var tasks = selection.tasks;
+      var urls = selection.urls;
+      var mimeTypes = selection.mimeTypes;
+      if (tasks)
+        tasks.executeDefault();
+      return true;
+    }
+    if (!this.okButton_.disabled) {
+      this.onOk_();
+      return true;
+    }
+    return false;
+  };
+
+  /**
+   * Opens the suggest file dialog.
+   *
+   * @param {string} url URL of files.
+   * @param {function()} onSuccess Success callback.
+   * @param {function()} onCancelled User-cancelled callback.
+   * @param {function()} onFailure Failure callback.
+   * @private
+   */
+  FileManager.prototype.openSuggestAppsDialog =
+      function(url, onSuccess, onCancelled, onFailure) {
+    if (!url) {
+      onFailure();
+      return;
+    }
+
+    this.metadataCache_.get([url], 'drive', function(props) {
+      if (!props || !props[0] || !props[0].contentMimeType) {
+        onFailure();
+        return;
+      }
+
+      var filename = util.extractFilePath(url);
+      var extension = PathUtil.extractExtension(filename);
+      var mime = props[0].contentMimeType;
+
+      // Returns with failure if the file has neither extension nor mime.
+      if (!extension || !mime) {
+        onFailure();
+        return;
+      }
+
+      this.suggestAppsDialog.show(
+          extension, mime,
+          function(result) {
+            switch (result) {
+              case SuggestAppsDialog.Result.INSTALL_SUCCESSFUL:
+                onSuccess();
+                break;
+              case SuggestAppsDialog.Result.FAILED:
+                onFailure();
+                break;
+              default:
+                onCancelled();
+            }
+          });
+    }.bind(this));
+  };
+
+  /**
+   * Called when a dialog is shown or hidden.
+   * @param {boolean} flag True if a dialog is shown, false if hidden.   */
+  FileManager.prototype.onDialogShownOrHidden = function(show) {
+    // Set/unset a flag to disable dragging on the title area.
+    this.dialogContainer_.classList.toggle('disable-header-drag', show);
+  };
+
+  /**
+   * Executes directory action (i.e. changes directory).
+   *
+   * @param {DirectoryEntry} entry Directory entry to which directory should be
+   *                               changed.
+   * @private
+   */
+  FileManager.prototype.onDirectoryAction_ = function(entry) {
+    return this.directoryModel_.changeDirectory(entry.fullPath);
+  };
+
+  /**
+   * Update the window title.
+   * @private
+   */
+  FileManager.prototype.updateTitle_ = function() {
+    if (this.dialogType != DialogType.FULL_PAGE)
+      return;
+
+    var path = this.getCurrentDirectory();
+    var rootPath = PathUtil.getRootPath(path);
+    this.document_.title = PathUtil.getRootLabel(rootPath) +
+                           path.substring(rootPath.length);
+  };
+
+  /**
+   * Update the gear menu.
+   * @private
+   */
+  FileManager.prototype.updateGearMenu_ = function() {
+    var hideItemsForDrive = !this.isOnDrive();
+    this.syncButton.hidden = hideItemsForDrive;
+    this.hostedButton.hidden = hideItemsForDrive;
+    this.document_.getElementById('drive-separator').hidden =
+        hideItemsForDrive;
+
+    // If volume has changed, then fetch remaining space data.
+    if (this.previousRootUrl_ != this.directoryModel_.getCurrentMountPointUrl())
+      this.refreshRemainingSpace_(true);  // Show loading caption.
+
+    this.previousRootUrl_ = this.directoryModel_.getCurrentMountPointUrl();
+  };
+
+  /**
+   * Refreshes space info of the current volume.
+   * @param {boolean} showLoadingCaption Whether show loading caption or not.
+   * @private
+   */
+  FileManager.prototype.refreshRemainingSpace_ = function(showLoadingCaption) {
+    var volumeSpaceInfoLabel =
+        this.dialogDom_.querySelector('#volume-space-info-label');
+    var volumeSpaceInnerBar =
+        this.dialogDom_.querySelector('#volume-space-info-bar');
+    var volumeSpaceOuterBar =
+        this.dialogDom_.querySelector('#volume-space-info-bar').parentNode;
+
+    volumeSpaceInnerBar.setAttribute('pending', '');
+
+    if (showLoadingCaption) {
+      volumeSpaceInfoLabel.innerText = str('WAITING_FOR_SPACE_INFO');
+      volumeSpaceInnerBar.style.width = '100%';
+    }
+
+    var currentMountPointUrl = this.directoryModel_.getCurrentMountPointUrl();
+    chrome.fileBrowserPrivate.getSizeStats(
+        currentMountPointUrl, function(result) {
+          if (this.directoryModel_.getCurrentMountPointUrl() !=
+              currentMountPointUrl)
+            return;
+          updateSpaceInfo(result,
+                          volumeSpaceInnerBar,
+                          volumeSpaceInfoLabel,
+                          volumeSpaceOuterBar);
+        }.bind(this));
+  };
+
+  /**
+   * Update the UI when the current directory changes.
+   *
+   * @param {Event} event The directory-changed event.
+   * @private
+   */
+  FileManager.prototype.onDirectoryChanged_ = function(event) {
+    this.selectionHandler_.onFileSelectionChanged();
+    this.ui_.searchBox.clear();
+    util.updateAppState(this.getCurrentDirectory());
+
+    // If the current directory is moved from the device's volume, do not
+    // automatically close the window on device removal.
+    if (event.previousDirEntry &&
+        PathUtil.getRootPath(event.previousDirEntry.fullPath) !=
+            PathUtil.getRootPath(event.newDirEntry.fullPath))
+      this.closeOnUnmount_ = false;
+
+    if (this.commandHandler)
+      this.commandHandler.updateAvailability();
+    this.updateUnformattedDriveStatus_();
+    this.updateTitle_();
+    this.updateGearMenu_();
+    this.previewPanel_.currentPath_ = this.getCurrentDirectory();
+  };
+
+  // TODO(haruki): Rename this method. "Drive" here does not refer
+  // "Google Drive".
+  FileManager.prototype.updateUnformattedDriveStatus_ = function() {
+    var volumeInfo = this.volumeManager_.getVolumeInfo(
+        PathUtil.getRootPath(this.directoryModel_.getCurrentRootPath()));
+
+    if (volumeInfo && volumeInfo.error) {
+      this.dialogDom_.setAttribute('unformatted', '');
+
+      var errorNode = this.dialogDom_.querySelector('#format-panel > .error');
+      if (volumeInfo.error == util.VolumeError.UNSUPPORTED_FILESYSTEM) {
+        errorNode.textContent = str('UNSUPPORTED_FILESYSTEM_WARNING');
+      } else {
+        errorNode.textContent = str('UNKNOWN_FILESYSTEM_WARNING');
+      }
+
+      // Update 'canExecute' for format command so the format button's disabled
+      // property is properly set.
+      if (this.commandHandler)
+        this.commandHandler.updateAvailability();
+    } else {
+      this.dialogDom_.removeAttribute('unformatted');
+    }
+  };
+
+  FileManager.prototype.findListItemForEvent_ = function(event) {
+    return this.findListItemForNode_(event.touchedElement || event.srcElement);
+  };
+
+  FileManager.prototype.findListItemForNode_ = function(node) {
+    var item = this.currentList_.getListItemAncestor(node);
+    // TODO(serya): list should check that.
+    return item && this.currentList_.isItem(item) ? item : null;
+  };
+
+  /**
+   * Unload handler for the page.  May be called manually for the file picker
+   * dialog, because it closes by calling extension API functions that do not
+   * return.
+   *
+   * TODO(hirono): This method is not called when Files.app is opend as a dialog
+   *     and is closed by the close button in the dialog frame. crbug.com/309967
+   * @private
+   */
+  FileManager.prototype.onUnload_ = function() {
+    if (this.directoryModel_)
+      this.directoryModel_.dispose();
+    if (this.volumeManager_)
+      this.volumeManager_.dispose();
+    if (this.filePopup_ &&
+        this.filePopup_.contentWindow &&
+        this.filePopup_.contentWindow.unload)
+      this.filePopup_.contentWindow.unload(true /* exiting */);
+    if (this.butterBar_)
+      this.butterBar_.dispose();
+    if (this.fileOperationManager_) {
+      if (this.onCopyProgressBound_) {
+        this.fileOperationManager_.removeEventListener(
+            'copy-progress', this.onCopyProgressBound_);
+      }
+      if (this.onEntryChangedBound_) {
+        this.fileOperationManager_.removeEventListener(
+            'entry-changed', this.onEntryChangedBound_);
+      }
+    }
+    window.closing = true;
+    if (this.backgroundPage_ && util.platform.runningInBrowser())
+      this.backgroundPage_.maybeCloseBackgroundPage();
+  };
+
+  FileManager.prototype.initiateRename = function() {
+    var item = this.currentList_.ensureLeadItemExists();
+    if (!item)
+      return;
+    var label = item.querySelector('.filename-label');
+    var input = this.renameInput_;
+
+    input.value = label.textContent;
+    label.parentNode.setAttribute('renaming', '');
+    label.parentNode.appendChild(input);
+    input.focus();
+    var selectionEnd = input.value.lastIndexOf('.');
+    if (selectionEnd == -1) {
+      input.select();
+    } else {
+      input.selectionStart = 0;
+      input.selectionEnd = selectionEnd;
+    }
+
+    // This has to be set late in the process so we don't handle spurious
+    // blur events.
+    input.currentEntry = this.currentList_.dataModel.item(item.listIndex);
+  };
+
+  /**
+   * @type {Event} Key event.
+   * @private
+   */
+  FileManager.prototype.onRenameInputKeyDown_ = function(event) {
+    if (!this.isRenamingInProgress())
+      return;
+
+    // Do not move selection or lead item in list during rename.
+    if (event.keyIdentifier == 'Up' || event.keyIdentifier == 'Down') {
+      event.stopPropagation();
+    }
+
+    switch (util.getKeyModifiers(event) + event.keyCode) {
+      case '27':  // Escape
+        this.cancelRename_();
+        event.preventDefault();
+        break;
+
+      case '13':  // Enter
+        this.commitRename_();
+        event.preventDefault();
+        break;
+    }
+  };
+
+  /**
+   * @type {Event} Blur event.
+   * @private
+   */
+  FileManager.prototype.onRenameInputBlur_ = function(event) {
+    if (this.isRenamingInProgress() && !this.renameInput_.validation_)
+      this.commitRename_();
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.commitRename_ = function() {
+    var input = this.renameInput_;
+    var entry = input.currentEntry;
+    var newName = input.value;
+
+    if (newName == entry.name) {
+      this.cancelRename_();
+      return;
+    }
+
+    var nameNode = this.findListItemForNode_(this.renameInput_).
+                   querySelector('.filename-label');
+
+    input.validation_ = true;
+    var validationDone = function(valid) {
+      input.validation_ = false;
+      // Alert dialog restores focus unless the item removed from DOM.
+      if (this.document_.activeElement != input)
+        this.cancelRename_();
+      if (!valid)
+        return;
+
+      // Validation succeeded. Do renaming.
+
+      this.cancelRename_();
+      // Optimistically apply new name immediately to avoid flickering in
+      // case of success.
+      nameNode.textContent = newName;
+
+      util.rename(
+          entry, newName,
+          function(newEntry) {
+            this.directoryModel_.onRenameEntry(entry, newEntry);
+          }.bind(this),
+          function(error) {
+            // Write back to the old name.
+            nameNode.textContent = entry.name;
+
+            // Show error dialog.
+            var message;
+            if (error.code == FileError.PATH_EXISTS_ERR ||
+                error.code == FileError.TYPE_MISMATCH_ERR) {
+              // Check the existing entry is file or not.
+              // 1) If the entry is a file:
+              //   a) If we get PATH_EXISTS_ERR, a file exists.
+              //   b) If we get TYPE_MISMATCH_ERR, a directory exists.
+              // 2) If the entry is a directory:
+              //   a) If we get PATH_EXISTS_ERR, a directory exists.
+              //   b) If we get TYPE_MISMATCH_ERR, a file exists.
+              message = strf(
+                  (entry.isFile && error.code == FileError.PATH_EXISTS_ERR) ||
+                  (!entry.isFile && error.code == FileError.TYPE_MISMATCH_ERR) ?
+                      'FILE_ALREADY_EXISTS' :
+                      'DIRECTORY_ALREADY_EXISTS',
+                  newName);
+            } else {
+              message = strf('ERROR_RENAMING', entry.name,
+                             util.getFileErrorString(err.code));
+            }
+
+            this.alert.show(message);
+          }.bind(this));
+    };
+
+    // TODO(haruki): this.getCurrentDirectoryURL() might not return the actual
+    // parent if the directory content is a search result. Fix it to do proper
+    // validation.
+    this.validateFileName_(this.getCurrentDirectoryURL(),
+                           newName,
+                           validationDone.bind(this));
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.cancelRename_ = function() {
+    this.renameInput_.currentEntry = null;
+
+    var parent = this.renameInput_.parentNode;
+    if (parent) {
+      parent.removeAttribute('renaming');
+      parent.removeChild(this.renameInput_);
+    }
+  };
+
+  /**
+   * @param {Event} Key event.
+   * @private
+   */
+  FileManager.prototype.onFilenameInputKeyDown_ = function(event) {
+    var enabled = this.selectionHandler_.updateOkButton();
+    if (enabled &&
+        (util.getKeyModifiers(event) + event.keyCode) == '13' /* Enter */)
+      this.onOk_();
+  };
+
+  /**
+   * @param {Event} Focus event.
+   * @private
+   */
+  FileManager.prototype.onFilenameInputFocus_ = function(event) {
+    var input = this.filenameInput_;
+
+    // On focus we want to select everything but the extension, but
+    // Chrome will select-all after the focus event completes.  We
+    // schedule a timeout to alter the focus after that happens.
+    setTimeout(function() {
+        var selectionEnd = input.value.lastIndexOf('.');
+        if (selectionEnd == -1) {
+          input.select();
+        } else {
+          input.selectionStart = 0;
+          input.selectionEnd = selectionEnd;
+        }
+    }, 0);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onScanStarted_ = function() {
+    if (this.scanInProgress_) {
+      this.table_.list.endBatchUpdates();
+      this.grid_.endBatchUpdates();
+    }
+
+    if (this.commandHandler)
+      this.commandHandler.updateAvailability();
+    this.table_.list.startBatchUpdates();
+    this.grid_.startBatchUpdates();
+    this.scanInProgress_ = true;
+
+    this.scanUpdatedAtLeastOnceOrCompleted_ = false;
+    if (this.scanCompletedTimer_) {
+      clearTimeout(this.scanCompletedTimer_);
+      this.scanCompletedTimer_ = null;
+    }
+
+    if (this.scanUpdatedTimer_) {
+      clearTimeout(this.scanUpdatedTimer_);
+      this.scanUpdatedTimer_ = null;
+    }
+
+    if (this.spinner_.hidden) {
+      this.cancelSpinnerTimeout_();
+      this.showSpinnerTimeout_ =
+          setTimeout(this.showSpinner_.bind(this, true), 500);
+    }
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onScanCompleted_ = function() {
+    if (!this.scanInProgress_) {
+      console.error('Scan-completed event recieved. But scan is not started.');
+      return;
+    }
+
+    if (this.commandHandler)
+      this.commandHandler.updateAvailability();
+    this.hideSpinnerLater_();
+    this.refreshCurrentDirectoryMetadata_();
+
+    if (this.scanUpdatedTimer_) {
+      clearTimeout(this.scanUpdatedTimer_);
+      this.scanUpdatedTimer_ = null;
+    }
+
+    // To avoid flickering postpone updating the ui by a small amount of time.
+    // There is a high chance, that metadata will be received within 50 ms.
+    this.scanCompletedTimer_ = setTimeout(function() {
+      // Check if batch updates are already finished by onScanUpdated_().
+      if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
+        this.scanUpdatedAtLeastOnceOrCompleted_ = true;
+        this.updateMiddleBarVisibility_();
+      }
+
+      this.scanInProgress_ = false;
+      this.table_.list.endBatchUpdates();
+      this.grid_.endBatchUpdates();
+      this.scanCompletedTimer_ = null;
+    }.bind(this), 50);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onScanUpdated_ = function() {
+    if (!this.scanInProgress_) {
+      console.error('Scan-updated event recieved. But scan is not started.');
+      return;
+    }
+
+    if (this.scanUpdatedTimer_ || this.scanCompletedTimer_)
+      return;
+
+    // Show contents incrementally by finishing batch updated, but only after
+    // 200ms elapsed, to avoid flickering when it is not necessary.
+    this.scanUpdatedTimer_ = setTimeout(function() {
+      // We need to hide the spinner only once.
+      if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
+        this.scanUpdatedAtLeastOnceOrCompleted_ = true;
+        this.hideSpinnerLater_();
+        this.updateMiddleBarVisibility_();
+      }
+
+      // Update the UI.
+      if (this.scanInProgress_) {
+        this.table_.list.endBatchUpdates();
+        this.grid_.endBatchUpdates();
+        this.table_.list.startBatchUpdates();
+        this.grid_.startBatchUpdates();
+      }
+      this.scanUpdatedTimer_ = null;
+    }.bind(this), 200);
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.onScanCancelled_ = function() {
+    if (!this.scanInProgress_) {
+      console.error('Scan-cancelled event recieved. But scan is not started.');
+      return;
+    }
+
+    if (this.commandHandler)
+      this.commandHandler.updateAvailability();
+    this.hideSpinnerLater_();
+    if (this.scanCompletedTimer_) {
+      clearTimeout(this.scanCompletedTimer_);
+      this.scanCompletedTimer_ = null;
+    }
+    if (this.scanUpdatedTimer_) {
+      clearTimeout(this.scanUpdatedTimer_);
+      this.scanUpdatedTimer_ = null;
+    }
+    // Finish unfinished batch updates.
+    if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
+      this.scanUpdatedAtLeastOnceOrCompleted_ = true;
+      this.updateMiddleBarVisibility_();
+    }
+
+    this.scanInProgress_ = false;
+    this.table_.list.endBatchUpdates();
+    this.grid_.endBatchUpdates();
+  };
+
+  /**
+   * Handle the 'rescan-completed' from the DirectoryModel.
+   * @private
+   */
+  FileManager.prototype.onRescanCompleted_ = function() {
+    this.refreshCurrentDirectoryMetadata_();
+    this.selectionHandler_.onFileSelectionChanged();
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.cancelSpinnerTimeout_ = function() {
+    if (this.showSpinnerTimeout_) {
+      clearTimeout(this.showSpinnerTimeout_);
+      this.showSpinnerTimeout_ = null;
+    }
+  };
+
+  /**
+   * @private
+   */
+  FileManager.prototype.hideSpinnerLater_ = function() {
+    this.cancelSpinnerTimeout_();
+    this.showSpinner_(false);
+  };
+
+  /**
+   * @param {boolean} on True to show, false to hide.
+   * @private
+   */
+  FileManager.prototype.showSpinner_ = function(on) {
+    if (on && this.directoryModel_ && this.directoryModel_.isScanning())
+      this.spinner_.hidden = false;
+
+    if (!on && (!this.directoryModel_ ||
+                !this.directoryModel_.isScanning() ||
+                this.directoryModel_.getFileList().length != 0)) {
+      this.spinner_.hidden = true;
+    }
+  };
+
+  FileManager.prototype.createNewFolder = function() {
+    var defaultName = str('DEFAULT_NEW_FOLDER_NAME');
+
+    // Find a name that doesn't exist in the data model.
+    var files = this.directoryModel_.getFileList();
+    var hash = {};
+    for (var i = 0; i < files.length; i++) {
+      var name = files.item(i).name;
+      // Filtering names prevents from conflicts with prototype's names
+      // and '__proto__'.
+      if (name.substring(0, defaultName.length) == defaultName)
+        hash[name] = 1;
+    }
+
+    var baseName = defaultName;
+    var separator = '';
+    var suffix = '';
+    var index = '';
+
+    var advance = function() {
+      separator = ' (';
+      suffix = ')';
+      index++;
+    };
+
+    var current = function() {
+      return baseName + separator + index + suffix;
+    };
+
+    // Accessing hasOwnProperty is safe since hash properties filtered.
+    while (hash.hasOwnProperty(current())) {
+      advance();
+    }
+
+    var self = this;
+    var list = self.currentList_;
+    var tryCreate = function() {
+      self.directoryModel_.createDirectory(current(),
+                                           onSuccess, onError);
+    };
+
+    var onSuccess = function(entry) {
+      metrics.recordUserAction('CreateNewFolder');
+      list.selectedItem = entry;
+      self.initiateRename();
+    };
+
+    var onError = function(error) {
+      self.alert.show(strf('ERROR_CREATING_FOLDER', current(),
+                           util.getFileErrorString(error.code)));
+    };
+
+    tryCreate();
+  };
+
+  /**
+   * @param {Event} event Click event.
+   * @private
+   */
+  FileManager.prototype.onDetailViewButtonClick_ = function(event) {
+    this.setListType(FileManager.ListType.DETAIL);
+    this.currentList_.focus();
+  };
+
+  /**
+   * @param {Event} event Click event.
+   * @private
+   */
+  FileManager.prototype.onThumbnailViewButtonClick_ = function(event) {
+    this.setListType(FileManager.ListType.THUMBNAIL);
+    this.currentList_.focus();
+  };
+
+  /**
+   * KeyDown event handler for the document.
+   * @param {Event} event Key event.
+   * @private
+   */
+  FileManager.prototype.onKeyDown_ = function(event) {
+    if (event.srcElement === this.renameInput_) {
+      // Ignore keydown handler in the rename input box.
+      return;
+    }
+
+    switch (util.getKeyModifiers(event) + event.keyCode) {
+      case 'Ctrl-190':  // Ctrl-. => Toggle filter files.
+        this.fileFilter_.setFilterHidden(
+            !this.fileFilter_.isFilterHiddenOn());
+        event.preventDefault();
+        return;
+
+      case '27':  // Escape => Cancel dialog.
+        if (this.dialogType != DialogType.FULL_PAGE) {
+          // If there is nothing else for ESC to do, then cancel the dialog.
+          event.preventDefault();
+          this.cancelButton_.click();
+        }
+        break;
+    }
+  };
+
+  /**
+   * KeyDown event handler for the div#list-container element.
+   * @param {Event} event Key event.
+   * @private
+   */
+  FileManager.prototype.onListKeyDown_ = function(event) {
+    if (event.srcElement.tagName == 'INPUT') {
+      // Ignore keydown handler in the rename input box.
+      return;
+    }
+
+    switch (util.getKeyModifiers(event) + event.keyCode) {
+      case '8':  // Backspace => Up one directory.
+        event.preventDefault();
+        var path = this.getCurrentDirectory();
+        if (path && !PathUtil.isRootPath(path)) {
+          var path = path.replace(/\/[^\/]+$/, '');
+          this.directoryModel_.changeDirectory(path);
+        }
+        break;
+
+      case '13':  // Enter => Change directory or perform default action.
+        // TODO(dgozman): move directory action to dispatchSelectionAction.
+        var selection = this.getSelection();
+        if (selection.totalCount == 1 &&
+            selection.entries[0].isDirectory &&
+            this.dialogType != DialogType.SELECT_FOLDER &&
+            this.dialogType != DialogType.SELECT_UPLOAD_FOLDER) {
+          event.preventDefault();
+          this.onDirectoryAction_(selection.entries[0]);
+        } else if (this.dispatchSelectionAction_()) {
+          event.preventDefault();
+        }
+        break;
+    }
+
+    switch (event.keyIdentifier) {
+      case 'Home':
+      case 'End':
+      case 'Up':
+      case 'Down':
+      case 'Left':
+      case 'Right':
+        // When navigating with keyboard we hide the distracting mouse hover
+        // highlighting until the user moves the mouse again.
+        this.setNoHover_(true);
+        break;
+    }
+  };
+
+  /**
+   * Suppress/restore hover highlighting in the list container.
+   * @param {boolean} on True to temporarity hide hover state.
+   * @private
+   */
+  FileManager.prototype.setNoHover_ = function(on) {
+    if (on) {
+      this.listContainer_.classList.add('nohover');
+    } else {
+      this.listContainer_.classList.remove('nohover');
+    }
+  };
+
+  /**
+   * KeyPress event handler for the div#list-container element.
+   * @param {Event} event Key event.
+   * @private
+   */
+  FileManager.prototype.onListKeyPress_ = function(event) {
+    if (event.srcElement.tagName == 'INPUT') {
+      // Ignore keypress handler in the rename input box.
+      return;
+    }
+
+    if (event.ctrlKey || event.metaKey || event.altKey)
+      return;
+
+    var now = new Date();
+    var char = String.fromCharCode(event.charCode).toLowerCase();
+    var text = now - this.textSearchState_.date > 1000 ? '' :
+        this.textSearchState_.text;
+    this.textSearchState_ = {text: text + char, date: now};
+
+    this.doTextSearch_();
+  };
+
+  /**
+   * Mousemove event handler for the div#list-container element.
+   * @param {Event} event Mouse event.
+   * @private
+   */
+  FileManager.prototype.onListMouseMove_ = function(event) {
+    // The user grabbed the mouse, restore the hover highlighting.
+    this.setNoHover_(false);
+  };
+
+  /**
+   * Performs a 'text search' - selects a first list entry with name
+   * starting with entered text (case-insensitive).
+   * @private
+   */
+  FileManager.prototype.doTextSearch_ = function() {
+    var text = this.textSearchState_.text;
+    if (!text)
+      return;
+
+    var dm = this.directoryModel_.getFileList();
+    for (var index = 0; index < dm.length; ++index) {
+      var name = dm.item(index).name;
+      if (name.substring(0, text.length).toLowerCase() == text) {
+        this.currentList_.selectionModel.selectedIndexes = [index];
+        return;
+      }
+    }
+
+    this.textSearchState_.text = '';
+  };
+
+  /**
+   * Handle a click of the cancel button.  Closes the window.
+   * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
+   *
+   * @param {Event} event The click event.
+   * @private
+   */
+  FileManager.prototype.onCancel_ = function(event) {
+    chrome.fileBrowserPrivate.cancelDialog();
+    this.onUnload_();
+    window.close();
+  };
+
+  /**
+   * Resolves selected file urls returned from an Open dialog.
+   *
+   * For drive files this involves some special treatment.
+   * Starts getting drive files if needed.
+   *
+   * @param {Array.<string>} fileUrls Drive URLs.
+   * @param {function(Array.<string>)} callback To be called with fixed URLs.
+   * @private
+   */
+  FileManager.prototype.resolveSelectResults_ = function(fileUrls, callback) {
+    if (this.isOnDrive()) {
+      chrome.fileBrowserPrivate.getDriveFiles(
+        fileUrls,
+        function(localPaths) {
+          callback(fileUrls);
+        });
+    } else {
+      callback(fileUrls);
+    }
+  };
+
+  /**
+   * Closes this modal dialog with some files selected.
+   * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
+   * @param {Object} selection Contains urls, filterIndex and multiple fields.
+   * @private
+   */
+  FileManager.prototype.callSelectFilesApiAndClose_ = function(selection) {
+    var self = this;
+    function callback() {
+      self.onUnload_();
+      window.close();
+    }
+    if (selection.multiple) {
+      chrome.fileBrowserPrivate.selectFiles(
+          selection.urls, this.params_.shouldReturnLocalPath, callback);
+    } else {
+      var forOpening = (this.dialogType != DialogType.SELECT_SAVEAS_FILE);
+      chrome.fileBrowserPrivate.selectFile(
+          selection.urls[0], selection.filterIndex, forOpening,
+          this.params_.shouldReturnLocalPath, callback);
+    }
+  };
+
+  /**
+   * Tries to close this modal dialog with some files selected.
+   * Performs preprocessing if needed (e.g. for Drive).
+   * @param {Object} selection Contains urls, filterIndex and multiple fields.
+   * @private
+   */
+  FileManager.prototype.selectFilesAndClose_ = function(selection) {
+    if (!this.isOnDrive() ||
+        this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
+      setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
+      return;
+    }
+
+    var shade = this.document_.createElement('div');
+    shade.className = 'shade';
+    var footer = this.dialogDom_.querySelector('.button-panel');
+    var progress = footer.querySelector('.progress-track');
+    progress.style.width = '0%';
+    var cancelled = false;
+
+    var progressMap = {};
+    var filesStarted = 0;
+    var filesTotal = selection.urls.length;
+    for (var index = 0; index < selection.urls.length; index++) {
+      progressMap[selection.urls[index]] = -1;
+    }
+    var lastPercent = 0;
+    var bytesTotal = 0;
+    var bytesDone = 0;
+
+    var onFileTransfersUpdated = function(statusList) {
+      for (var index = 0; index < statusList.length; index++) {
+        var status = statusList[index];
+        var escaped = encodeURI(status.fileUrl);
+        if (!(escaped in progressMap)) continue;
+        if (status.total == -1) continue;
+
+        var old = progressMap[escaped];
+        if (old == -1) {
+          // -1 means we don't know file size yet.
+          bytesTotal += status.total;
+          filesStarted++;
+          old = 0;
+        }
+        bytesDone += status.processed - old;
+        progressMap[escaped] = status.processed;
+      }
+
+      var percent = bytesTotal == 0 ? 0 : bytesDone / bytesTotal;
+      // For files we don't have information about, assume the progress is zero.
+      percent = percent * filesStarted / filesTotal * 100;
+      // Do not decrease the progress. This may happen, if first downloaded
+      // file is small, and the second one is large.
+      lastPercent = Math.max(lastPercent, percent);
+      progress.style.width = lastPercent + '%';
+    }.bind(this);
+
+    var setup = function() {
+      this.document_.querySelector('.dialog-container').appendChild(shade);
+      setTimeout(function() { shade.setAttribute('fadein', 'fadein') }, 100);
+      footer.setAttribute('progress', 'progress');
+      this.cancelButton_.removeEventListener('click', this.onCancelBound_);
+      this.cancelButton_.addEventListener('click', onCancel);
+      chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener(
+          onFileTransfersUpdated);
+    }.bind(this);
+
+    var cleanup = function() {
+      shade.parentNode.removeChild(shade);
+      footer.removeAttribute('progress');
+      this.cancelButton_.removeEventListener('click', onCancel);
+      this.cancelButton_.addEventListener('click', this.onCancelBound_);
+      chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener(
+          onFileTransfersUpdated);
+    }.bind(this);
+
+    var onCancel = function() {
+      cancelled = true;
+      // According to API cancel may fail, but there is no proper UI to reflect
+      // this. So, we just silently assume that everything is cancelled.
+      chrome.fileBrowserPrivate.cancelFileTransfers(
+          selection.urls, function(response) {});
+      cleanup();
+    }.bind(this);
+
+    var onResolved = function(resolvedUrls) {
+      if (cancelled) return;
+      cleanup();
+      selection.urls = resolvedUrls;
+      // Call next method on a timeout, as it's unsafe to
+      // close a window from a callback.
+      setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
+    }.bind(this);
+
+    var onProperties = function(properties) {
+      for (var i = 0; i < properties.length; i++) {
+        if (!properties[i] || properties[i].present) {
+          // For files already in GCache, we don't get any transfer updates.
+          filesTotal--;
+        }
+      }
+      this.resolveSelectResults_(selection.urls, onResolved);
+    }.bind(this);
+
+    setup();
+    this.metadataCache_.get(selection.urls, 'drive', onProperties);
+  };
+
+  /**
+   * Handle a click of the ok button.
+   *
+   * The ok button has different UI labels depending on the type of dialog, but
+   * in code it's always referred to as 'ok'.
+   *
+   * @param {Event} event The click event.
+   * @private
+   */
+  FileManager.prototype.onOk_ = function(event) {
+    if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
+      // Save-as doesn't require a valid selection from the list, since
+      // we're going to take the filename from the text input.
+      var filename = this.filenameInput_.value;
+      if (!filename)
+        throw new Error('Missing filename!');
+
+      var directory = this.getCurrentDirectoryEntry();
+      var currentDirUrl = directory.toURL();
+      if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/')
+        currentDirUrl += '/';
+      this.validateFileName_(currentDirUrl, filename, function(isValid) {
+        if (!isValid)
+          return;
+
+        if (util.isFakeDirectoryEntry(directory)) {
+          // Can't save a file into a fake directory.
+          return;
+        }
+
+        var selectFileAndClose = function() {
+          this.selectFilesAndClose_({
+            urls: [currentDirUrl + encodeURIComponent(filename)],
+            multiple: false,
+            filterIndex: this.getSelectedFilterIndex_(filename)
+          });
+        }.bind(this);
+
+        directory.getFile(
+            filename, {create: false},
+            function(entry) {
+              // An existing file is found. Show confirmation dialog to
+              // overwrite it. If the user select "OK" on the dialog, save it.
+              this.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename),
+                                selectFileAndClose);
+            }.bind(this),
+            function(error) {
+              if (error.code == FileError.NOT_FOUND_ERR) {
+                // The file does not exist, so it should be ok to create a
+                // new file.
+                selectFileAndClose();
+                return;
+              }
+              if (error.code == FileError.TYPE_MISMATCH_ERR) {
+                // An directory is found.
+                // Do not allow to overwrite directory.
+                this.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename));
+                return;
+              }
+
+              // Unexpected error.
+              console.error('File save failed: ' + error.code);
+            }.bind(this));
+      }.bind(this));
+      return;
+    }
+
+    var files = [];
+    var selectedIndexes = this.currentList_.selectionModel.selectedIndexes;
+
+    if ((this.dialogType == DialogType.SELECT_FOLDER ||
+         this.dialogType == DialogType.SELECT_UPLOAD_FOLDER) &&
+        selectedIndexes.length == 0) {
+      var url = this.getCurrentDirectoryURL();
+      var singleSelection = {
+        urls: [url],
+        multiple: false,
+        filterIndex: this.getSelectedFilterIndex_()
+      };
+      this.selectFilesAndClose_(singleSelection);
+      return;
+    }
+
+    // All other dialog types require at least one selected list item.
+    // The logic to control whether or not the ok button is enabled should
+    // prevent us from ever getting here, but we sanity check to be sure.
+    if (!selectedIndexes.length)
+      throw new Error('Nothing selected!');
+
+    var dm = this.directoryModel_.getFileList();
+    for (var i = 0; i < selectedIndexes.length; i++) {
+      var entry = dm.item(selectedIndexes[i]);
+      if (!entry) {
+        console.error('Error locating selected file at index: ' + i);
+        continue;
+      }
+
+      files.push(entry.toURL());
+    }
+
+    // Multi-file selection has no other restrictions.
+    if (this.dialogType == DialogType.SELECT_OPEN_MULTI_FILE) {
+      var multipleSelection = {
+        urls: files,
+        multiple: true
+      };
+      this.selectFilesAndClose_(multipleSelection);
+      return;
+    }
+
+    // Everything else must have exactly one.
+    if (files.length > 1)
+      throw new Error('Too many files selected!');
+
+    var selectedEntry = dm.item(selectedIndexes[0]);
+
+    if (this.dialogType == DialogType.SELECT_FOLDER ||
+        this.dialogType == DialogType.SELECT_UPLOAD_FOLDER) {
+      if (!selectedEntry.isDirectory)
+        throw new Error('Selected entry is not a folder!');
+    } else if (this.dialogType == DialogType.SELECT_OPEN_FILE) {
+      if (!selectedEntry.isFile)
+        throw new Error('Selected entry is not a file!');
+    }
+
+    var singleSelection = {
+      urls: [files[0]],
+      multiple: false,
+      filterIndex: this.getSelectedFilterIndex_()
+    };
+    this.selectFilesAndClose_(singleSelection);
+  };
+
+  /**
+   * Verifies the user entered name for file or folder to be created or
+   * renamed to. Name restrictions must correspond to File API restrictions
+   * (see DOMFilePath::isValidPath). Curernt WebKit implementation is
+   * out of date (spec is
+   * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to
+   * be fixed. Shows message box if the name is invalid.
+   *
+   * It also verifies if the name length is in the limit of the filesystem.
+   *
+   * @param {string} parentUrl The URL of the parent directory entry.
+   * @param {string} name New file or folder name.
+   * @param {function} onDone Function to invoke when user closes the
+   *    warning box or immediatelly if file name is correct. If the name was
+   *    valid it is passed true, and false otherwise.
+   * @private
+   */
+  FileManager.prototype.validateFileName_ = function(parentUrl, name, onDone) {
+    var msg;
+    var testResult = /[\/\\\<\>\:\?\*\"\|]/.exec(name);
+    if (testResult) {
+      msg = strf('ERROR_INVALID_CHARACTER', testResult[0]);
+    } else if (/^\s*$/i.test(name)) {
+      msg = str('ERROR_WHITESPACE_NAME');
+    } else if (/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(name)) {
+      msg = str('ERROR_RESERVED_NAME');
+    } else if (this.fileFilter_.isFilterHiddenOn() && name[0] == '.') {
+      msg = str('ERROR_HIDDEN_NAME');
+    }
+
+    if (msg) {
+      this.alert.show(msg, function() {
+        onDone(false);
+      });
+      return;
+    }
+
+    var self = this;
+    chrome.fileBrowserPrivate.validatePathNameLength(
+        parentUrl, name, function(valid) {
+          if (!valid) {
+            self.alert.show(str('ERROR_LONG_NAME'),
+                            function() { onDone(false); });
+          } else {
+            onDone(true);
+          }
+        });
+  };
+
+  /**
+   * Handler invoked on preference setting in drive context menu.
+   *
+   * @param {string} pref  The preference to alter.
+   * @param {boolean} inverted Invert the value if true.
+   * @param {Event}  event The click event.
+   * @private
+   */
+  FileManager.prototype.onDrivePrefClick_ = function(pref, inverted, event) {
+    var newValue = !event.target.hasAttribute('checked');
+    if (newValue)
+      event.target.setAttribute('checked', 'checked');
+    else
+      event.target.removeAttribute('checked');
+
+    var changeInfo = {};
+    changeInfo[pref] = inverted ? !newValue : newValue;
+    chrome.fileBrowserPrivate.setPreferences(changeInfo);
+  };
+
+  /**
+   * Invoked when the search box is changed.
+   *
+   * @param {Event} event The changed event.
+   * @private
+   */
+  FileManager.prototype.onSearchBoxUpdate_ = function(event) {
+    var searchString = this.searchBox_.value;
+
+    if (this.isOnDrive()) {
+      // When the search text is changed, finishes the search and showes back
+      // the last directory by passing an empty string to
+      // {@code DirectoryModel.search()}.
+      if (this.directoryModel_.isSearching() &&
+          this.lastSearchQuery_ != searchString) {
+        this.doSearch('');
+      }
+
+      // On drive, incremental search is not invoked since we have an auto-
+      // complete suggestion instead.
+      return;
+    }
+
+    this.search_(searchString);
+  };
+
+  /**
+   * Handle the search clear button click.
+   * @private
+   */
+  FileManager.prototype.onSearchClearButtonClick_ = function() {
+    this.ui_.searchBox.clear();
+    this.onSearchBoxUpdate_();
+  };
+
+  /**
+   * Search files and update the list with the search result.
+   *
+   * @param {string} searchString String to be searched with.
+   * @private
+   */
+  FileManager.prototype.search_ = function(searchString) {
+    var noResultsDiv = this.document_.getElementById('no-search-results');
+
+    var reportEmptySearchResults = function() {
+      if (this.directoryModel_.getFileList().length === 0) {
+        // The string 'SEARCH_NO_MATCHING_FILES_HTML' may contain HTML tags,
+        // hence we escapes |searchString| here.
+        var html = strf('SEARCH_NO_MATCHING_FILES_HTML',
+                        util.htmlEscape(searchString));
+        noResultsDiv.innerHTML = html;
+        noResultsDiv.setAttribute('show', 'true');
+      } else {
+        noResultsDiv.removeAttribute('show');
+      }
+    };
+
+    var hideNoResultsDiv = function() {
+      noResultsDiv.removeAttribute('show');
+    };
+
+    this.doSearch(searchString,
+                  reportEmptySearchResults.bind(this),
+                  hideNoResultsDiv.bind(this));
+  };
+
+  /**
+   * Performs search and displays results.
+   *
+   * @param {string} query Query that will be searched for.
+   * @param {function()=} opt_onSearchRescan Function that will be called when
+   *     the search directory is rescanned (i.e. search results are displayed).
+   * @param {function()=} opt_onClearSearch Function to be called when search
+   *     state gets cleared.
+   */
+  FileManager.prototype.doSearch = function(
+      searchString, opt_onSearchRescan, opt_onClearSearch) {
+    var onSearchRescan = opt_onSearchRescan || function() {};
+    var onClearSearch = opt_onClearSearch || function() {};
+
+    this.lastSearchQuery_ = searchString;
+    this.directoryModel_.search(searchString, onSearchRescan, onClearSearch);
+  };
+
+  /**
+   * Requests autocomplete suggestions for files on Drive.
+   * Once the suggestions are returned, the autocomplete popup will show up.
+   *
+   * @param {string} query The text to autocomplete from.
+   * @private
+   */
+  FileManager.prototype.requestAutocompleteSuggestions_ = function(query) {
+    query = query.trimLeft();
+
+    // Only Drive supports auto-compelete
+    if (!this.isOnDrive())
+      return;
+
+    // Remember the most recent query. If there is an other request in progress,
+    // then it's result will be discarded and it will call a new request for
+    // this query.
+    this.lastAutocompleteQuery_ = query;
+    if (this.autocompleteSuggestionsBusy_)
+      return;
+
+    // The autocomplete list should be resized and repositioned here as the
+    // search box is resized when it's focused.
+    this.autocompleteList_.syncWidthAndPositionToInput();
+
+    if (!query) {
+      this.autocompleteList_.suggestions = [];
+      return;
+    }
+
+    var headerItem = {isHeaderItem: true, searchQuery: query};
+    if (!this.autocompleteList_.dataModel ||
+        this.autocompleteList_.dataModel.length == 0)
+      this.autocompleteList_.suggestions = [headerItem];
+    else
+      // Updates only the head item to prevent a flickering on typing.
+      this.autocompleteList_.dataModel.splice(0, 1, headerItem);
+
+    this.autocompleteSuggestionsBusy_ = true;
+
+    var searchParams = {
+      'query': query,
+      'types': 'ALL',
+      'maxResults': 4
+    };
+    chrome.fileBrowserPrivate.searchDriveMetadata(
+      searchParams,
+      function(suggestions) {
+        this.autocompleteSuggestionsBusy_ = false;
+
+        // Discard results for previous requests and fire a new search
+        // for the most recent query.
+        if (query != this.lastAutocompleteQuery_) {
+          this.requestAutocompleteSuggestions_(this.lastAutocompleteQuery_);
+          return;
+        }
+
+        // Keeps the items in the suggestion list.
+        this.autocompleteList_.suggestions = [headerItem].concat(suggestions);
+      }.bind(this));
+  };
+
+  /**
+   * Opens the currently selected suggestion item.
+   * @private
+   */
+  FileManager.prototype.openAutocompleteSuggestion_ = function() {
+    var selectedItem = this.autocompleteList_.selectedItem;
+
+    // If the entry is the search item or no entry is selected, just change to
+    // the search result.
+    if (!selectedItem || selectedItem.isHeaderItem) {
+      var query = selectedItem ?
+          selectedItem.searchQuery : this.searchBox_.value;
+      this.search_(query);
+      return;
+    }
+
+    var entry = selectedItem.entry;
+    // If the entry is a directory, just change the directory.
+    if (entry.isDirectory) {
+      this.onDirectoryAction_(entry);
+      return;
+    }
+
+    var urls = [entry.toURL()];
+    var self = this;
+
+    // To open a file, first get the mime type.
+    this.metadataCache_.get(urls, 'drive', function(props) {
+      var mimeType = props[0].contentMimeType || '';
+      var mimeTypes = [mimeType];
+      var openIt = function() {
+        if (self.dialogType == DialogType.FULL_PAGE) {
+          var tasks = new FileTasks(self);
+          tasks.init(urls, mimeTypes);
+          tasks.executeDefault();
+        } else {
+          self.onOk_();
+        }
+      };
+
+      // Change the current directory to the directory that contains the
+      // selected file. Note that this is necessary for an image or a video,
+      // which should be opened in the gallery mode, as the gallery mode
+      // requires the entry to be in the current directory model. For
+      // consistency, the current directory is always changed regardless of
+      // the file type.
+      entry.getParent(function(parent) {
+        var onDirectoryChanged = function(event) {
+          self.directoryModel_.removeEventListener('scan-completed',
+                                                   onDirectoryChanged);
+          self.directoryModel_.selectEntry(entry.name);
+          openIt();
+        };
+        // changeDirectory() returns immediately. We should wait until the
+        // directory scan is complete.
+        self.directoryModel_.addEventListener('scan-completed',
+                                              onDirectoryChanged);
+        self.directoryModel_.changeDirectory(
+          parent.fullPath,
+          function() {
+            // Remove the listner if the change directory failed.
+            self.directoryModel_.removeEventListener('scan-completed',
+                                                     onDirectoryChanged);
+          });
+      });
+    });
+  };
+
+  /**
+   * Opens the default app change dialog.
+   */
+  FileManager.prototype.showChangeDefaultAppPicker = function() {
+    var onActionsReady = function(actions, rememberedActionId) {
+      var items = [];
+      var defaultIndex = -1;
+      for (var i = 0; i < actions.length; i++) {
+        if (actions[i].hidden)
+          continue;
+        var title = actions[i].title;
+        if (actions[i].id == rememberedActionId) {
+          title += ' ' + loadTimeData.getString('DEFAULT_ACTION_LABEL');
+          defaultIndex = i;
+        }
+        var item = {
+          id: actions[i].id,
+          label: title,
+          class: actions[i].class,
+          iconUrl: actions[i].icon100
+        };
+        items.push(item);
+      }
+      var show = this.defaultTaskPicker.showOkCancelDialog(
+          str('CHANGE_DEFAULT_APP_BUTTON_LABEL'),
+          '',
+          items,
+          defaultIndex,
+          function(action) {
+            ActionChoiceUtil.setRememberedActionId(action.id);
+          });
+      if (!show)
+        console.error('DefaultTaskPicker can\'t be shown.');
+    }.bind(this);
+
+    ActionChoiceUtil.getDefinedActions(loadTimeData, function(actions) {
+      ActionChoiceUtil.getRememberedActionId(function(actionId) {
+        onActionsReady(actions, actionId);
+      });
+    });
+  };
+
+  FileManager.prototype.decorateSplitter = function(splitterElement) {
+    var self = this;
+
+    var Splitter = cr.ui.Splitter;
+
+    var customSplitter = cr.ui.define('div');
+
+    customSplitter.prototype = {
+      __proto__: Splitter.prototype,
+
+      handleSplitterDragStart: function(e) {
+        Splitter.prototype.handleSplitterDragStart.apply(this, arguments);
+        this.ownerDocument.documentElement.classList.add('col-resize');
+      },
+
+      handleSplitterDragMove: function(deltaX) {
+        Splitter.prototype.handleSplitterDragMove.apply(this, arguments);
+        self.onResize_();
+      },
+
+      handleSplitterDragEnd: function(e) {
+        Splitter.prototype.handleSplitterDragEnd.apply(this, arguments);
+        this.ownerDocument.documentElement.classList.remove('col-resize');
+      }
+    };
+
+    customSplitter.decorate(splitterElement);
+  };
+
+  /**
+   * Updates default action menu item to match passed taskItem (icon,
+   * label and action).
+   *
+   * @param {Object} defaultItem - taskItem to match.
+   * @param {boolean} isMultiple - if multiple tasks available.
+   */
+  FileManager.prototype.updateContextMenuActionItems = function(defaultItem,
+                                                                isMultiple) {
+    if (defaultItem) {
+      if (defaultItem.iconType) {
+        this.defaultActionMenuItem_.style.backgroundImage = '';
+        this.defaultActionMenuItem_.setAttribute('file-type-icon',
+                                                 defaultItem.iconType);
+      } else if (defaultItem.iconUrl) {
+        this.defaultActionMenuItem_.style.backgroundImage =
+            'url(' + defaultItem.iconUrl + ')';
+      } else {
+        this.defaultActionMenuItem_.style.backgroundImage = '';
+      }
+
+      this.defaultActionMenuItem_.label = defaultItem.title;
+      this.defaultActionMenuItem_.disabled = !!defaultItem.disabled;
+      this.defaultActionMenuItem_.taskId = defaultItem.taskId;
+    }
+
+    var defaultActionSeparator =
+        this.dialogDom_.querySelector('#default-action-separator');
+
+    this.openWithCommand_.canExecuteChange();
+    this.openWithCommand_.setHidden(!(defaultItem && isMultiple));
+    this.openWithCommand_.disabled = defaultItem && !!defaultItem.disabled;
+
+    this.defaultActionMenuItem_.hidden = !defaultItem;
+    defaultActionSeparator.hidden = !defaultItem;
+  };
+
+  /**
+   * Window beforeunload handler.
+   * @return {string} Message to show. Ignored when running as a packaged app.
+   * @private
+   */
+  FileManager.prototype.onBeforeUnload_ = function() {
+    if (this.filePopup_ &&
+        this.filePopup_.contentWindow &&
+        this.filePopup_.contentWindow.beforeunload) {
+      // The gallery might want to prevent the unload if it is busy.
+      return this.filePopup_.contentWindow.beforeunload();
+    }
+    return null;
+  };
+
+  /**
+   * @return {FileSelection} Selection object.
+   */
+  FileManager.prototype.getSelection = function() {
+    return this.selectionHandler_.selection;
+  };
+
+  /**
+   * @return {ArrayDataModel} File list.
+   */
+  FileManager.prototype.getFileList = function() {
+    return this.directoryModel_.getFileList();
+  };
+
+  /**
+   * @return {cr.ui.List} Current list object.
+   */
+  FileManager.prototype.getCurrentList = function() {
+    return this.currentList_;
+  };
+
+  /**
+   * Retrieve the preferences of the files.app. This method caches the result
+   * and returns it unless opt_update is true.
+   * @param {function(Object.<string, *>)} callback Callback to get the
+   *     preference.
+   * @param {boolean=} opt_update If is's true, don't use the cache and
+   *     retrieve latest preference. Default is false.
+   * @private
+   */
+  FileManager.prototype.getPreferences_ = function(callback, opt_update) {
+    if (!opt_update && this.preferences_ !== undefined) {
+      callback(this.preferences_);
+      return;
+    }
+
+    chrome.fileBrowserPrivate.getPreferences(function(prefs) {
+      this.preferences_ = prefs;
+      callback(prefs);
+    }.bind(this));
+  };
+})();
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js b/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js
new file mode 100644
index 0000000..8cb4e3f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js
@@ -0,0 +1,876 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * TODO(dzvorygin): Here we use this hack, since 'hidden' is standard
+ * attribute and we can't use it's setter as usual.
+ * @param {boolean} value New value of hidden property.
+ */
+cr.ui.Command.prototype.setHidden = function(value) {
+  this.__lookupSetter__('hidden').call(this, value);
+};
+
+/**
+ * A command.
+ * @interface
+ */
+var Command = function() {};
+
+/**
+ * Handles the execute event.
+ * @param {Event} event Command event.
+ * @param {FileManager} fileManager FileManager.
+ */
+Command.prototype.execute = function(event, fileManager) {};
+
+/**
+ * Handles the can execute event.
+ * @param {Event} event Can execute event.
+ * @param {FileManager} fileManager FileManager.
+ */
+Command.prototype.canExecute = function(event, fileManager) {};
+
+/**
+ * Utility for commands.
+ */
+var CommandUtil = {};
+
+/**
+ * Extracts entry on which command event was dispatched.
+ *
+ * @param {DirectoryTree|DirectoryItem|NavigationList|HTMLLIElement|cr.ui.List}
+ *     element Directory to extract a path from.
+ * @return {Entry} Entry of the found node.
+ */
+CommandUtil.getCommandEntry = function(element) {
+  if (element instanceof NavigationList) {
+    // element is a NavigationList.
+
+    /** @type {NavigationModelItem} */
+    var selectedItem = element.selectedItem;
+    return selectedItem && selectedItem.getCachedEntry();
+  } else if (element instanceof NavigationListItem) {
+    // element is a subitem of NavigationList.
+    /** @type {NavigationList} */
+    var navigationList = element.parentElement;
+    var index = navigationList.getIndexOfListItem(element);
+    /** @type {NavigationModelItem} */
+    var item = (index != -1) ? navigationList.dataModel.item(index) : null;
+    return item && item.getCachedEntry();
+  } else if (element instanceof DirectoryTree) {
+    // element is a DirectoryTree.
+    return element.selectedItem;
+  } else if (element instanceof DirectoryItem) {
+    // element is a sub item in DirectoryTree.
+
+    // DirectoryItem.fullPath is set on initialization, but entry is lazily.
+    // We may use fullPath just in case that the entry has not been set yet.
+    return element.entry;
+  } else if (element instanceof cr.ui.List) {
+    // element is a normal List (eg. the file list on the right panel).
+    var entry = element.selectedItem;
+    // Check if it is Entry or not by referring the fullPath member variable.
+    return entry && entry.fullPath ? entry : null;
+  } else {
+    console.warn('Unsupported element');
+    return null;
+  }
+};
+
+/**
+ * @param {NavigationList} navigationList navigation list to extract root node.
+ * @return {?RootType} Type of the found root.
+ */
+CommandUtil.getCommandRootType = function(navigationList) {
+  var root = CommandUtil.getCommandEntry(navigationList);
+  return root &&
+         PathUtil.isRootPath(root.fullPath) &&
+         PathUtil.getRootType(root.fullPath);
+};
+
+/**
+ * Checks if command can be executed on drive.
+ * @param {Event} event Command event to mark.
+ * @param {FileManager} fileManager FileManager to use.
+ */
+CommandUtil.canExecuteEnabledOnDriveOnly = function(event, fileManager) {
+  event.canExecute = fileManager.isOnDrive();
+};
+
+/**
+ * Checks if command should be visible on drive.
+ * @param {Event} event Command event to mark.
+ * @param {FileManager} fileManager FileManager to use.
+ */
+CommandUtil.canExecuteVisibleOnDriveOnly = function(event, fileManager) {
+  event.canExecute = fileManager.isOnDrive();
+  event.command.setHidden(!fileManager.isOnDrive());
+};
+
+/**
+ * Sets as the command as always enabled.
+ * @param {Event} event Command event to mark.
+ */
+CommandUtil.canExecuteAlways = function(event) {
+  event.canExecute = true;
+};
+
+/**
+ * Returns a single selected/passed entry or null.
+ * @param {Event} event Command event.
+ * @param {FileManager} fileManager FileManager to use.
+ * @return {FileEntry} The entry or null.
+ */
+CommandUtil.getSingleEntry = function(event, fileManager) {
+  if (event.target.entry) {
+    return event.target.entry;
+  }
+  var selection = fileManager.getSelection();
+  if (selection.totalCount == 1) {
+    return selection.entries[0];
+  }
+  return null;
+};
+
+/**
+ * Obtains target entries that can be pinned from the selection.
+ * If directories are included in the selection, it just returns an empty
+ * array to avoid confusing because pinning directory is not supported
+ * currently.
+ *
+ * @return {Array.<Entry>} Target entries.
+ */
+CommandUtil.getPinTargetEntries = function() {
+  var hasDirectory = false;
+  var results = fileManager.getSelection().entries.filter(function(entry) {
+    hasDirectory = hasDirectory || entry.isDirectory;
+    if (!entry || hasDirectory)
+      return false;
+    var metadata = fileManager.metadataCache_.getCached(entry, 'drive');
+    if (!metadata || metadata.hosted)
+      return false;
+    entry.pinned = metadata.pinned;
+    return true;
+  });
+  return hasDirectory ? [] : results;
+};
+
+/**
+ * Sets the default handler for the commandId and prevents handling
+ * the keydown events for this command. Not doing that breaks relationship
+ * of original keyboard event and the command. WebKit would handle it
+ * differently in some cases.
+ * @param {Node} node to register command handler on.
+ * @param {string} commandId Command id to respond to.
+ */
+CommandUtil.forceDefaultHandler = function(node, commandId) {
+  var doc = node.ownerDocument;
+  var command = doc.querySelector('command[id="' + commandId + '"]');
+  node.addEventListener('keydown', function(e) {
+    if (command.matchesEvent(e)) {
+      // Prevent cr.ui.CommandManager of handling it and leave it
+      // for the default handler.
+      e.stopPropagation();
+    }
+  });
+  node.addEventListener('command', function(event) {
+    if (event.command.id !== commandId)
+      return;
+    document.execCommand(event.command.id);
+    event.cancelBubble = true;
+  });
+  node.addEventListener('canExecute', function(event) {
+    if (event.command.id === commandId)
+      event.canExecute = document.queryCommandEnabled(event.command.id);
+  });
+};
+
+/**
+ * Default command.
+ * @type {Command}
+ */
+CommandUtil.defaultCommand = {
+  execute: function(event, fileManager) {
+    fileManager.document.execCommand(event.command.id);
+  },
+  canExecute: function(event, fileManager) {
+    event.canExecute = fileManager.document.queryCommandEnabled(
+        event.command.id);
+  }
+};
+
+/**
+ * Creates the volume switch command with index.
+ * @param {number} index Volume index from 1 to 9.
+ * @return {Command} Volume switch command.
+ */
+CommandUtil.createVolumeSwitchCommand = function(index) {
+  return {
+    execute: function(event, fileManager) {
+      fileManager.navigationList.selectByIndex(index - 1);
+    },
+    canExecute: function(event, fileManager) {
+      event.canExecute = index > 0 &&
+          index <= fileManager.navigationList.dataModel.length;
+    }
+  };
+};
+
+/**
+ * Handle of the command events.
+ * @param {FileManager} fileManager FileManager.
+ * @constructor
+ */
+var CommandHandler = function(fileManager) {
+  /**
+   * FileManager.
+   * @type {FileManager}
+   * @private
+   */
+  this.fileManager_ = fileManager;
+
+  /**
+   * Command elements.
+   * @type {Object.<string, cr.ui.Command>}
+   * @private
+   */
+  this.commands_ = {};
+
+  /**
+   * Whether the ctrl key is pressed or not.
+   * @type {boolean}
+   * @private
+   */
+  this.ctrlKeyPressed_ = false;
+
+  Object.seal(this);
+
+  // Decorate command tags in the document.
+  var commands = fileManager.document.querySelectorAll('command');
+  for (var i = 0; i < commands.length; i++) {
+    cr.ui.Command.decorate(commands[i]);
+    this.commands_[commands[i].id] = commands[i];
+  }
+
+  // Register events.
+  fileManager.document.addEventListener('command', this.onCommand_.bind(this));
+  fileManager.document.addEventListener('canExecute',
+                                        this.onCanExecute_.bind(this));
+  fileManager.document.addEventListener('keydown', this.onKeyDown_.bind(this));
+  fileManager.document.addEventListener('keyup', this.onKeyUp_.bind(this));
+};
+
+/**
+ * Updates the availability of all commands.
+ */
+CommandHandler.prototype.updateAvailability = function() {
+  for (var id in this.commands_) {
+    this.commands_[id].canExecuteChange();
+  }
+};
+
+/**
+ * Checks if the handler should ignore the current event, eg. since there is
+ * a popup dialog currently opened.
+ *
+ * @return {boolean} True if the event should be ignored, false otherwise.
+ * @private
+ */
+CommandHandler.prototype.shouldIgnoreEvents_ = function() {
+  // Do not handle commands, when a dialog is shown.
+  if (this.fileManager_.document.querySelector('.cr-dialog-container.shown'))
+    return true;
+
+  return false;  // Do not ignore.
+};
+
+/**
+ * Handles command events.
+ * @param {Event} event Command event.
+ * @private
+ */
+CommandHandler.prototype.onCommand_ = function(event) {
+  if (this.shouldIgnoreEvents_())
+    return;
+  var handler = CommandHandler.COMMANDS_[event.command.id];
+  handler.execute.call(this, event, this.fileManager_);
+};
+
+/**
+ * Handles canExecute events.
+ * @param {Event} event Can execute event.
+ * @private
+ */
+CommandHandler.prototype.onCanExecute_ = function(event) {
+  if (this.shouldIgnoreEvents_())
+    return;
+  var handler = CommandHandler.COMMANDS_[event.command.id];
+  handler.canExecute.call(this, event, this.fileManager_);
+};
+
+/**
+ * Handle key down event.
+ * @param {Event} event Key down event.
+ * @private
+ */
+CommandHandler.prototype.onKeyDown_ = function(event) {
+  // 17 is the keycode of Ctrl key and it means the event is not for other keys
+  // with Ctrl modifier but for ctrl key itself.
+  if (util.getKeyModifiers(event) + event.keyCode == 'Ctrl-17') {
+    this.ctrlKeyPressed_ = true;
+    this.updateAvailability();
+  }
+};
+
+/**
+ * Handle key up event.
+ * @param {Event} event Key up event.
+ * @private
+ */
+CommandHandler.prototype.onKeyUp_ = function(event) {
+  // 17 is the keycode of Ctrl key and it means the event is not for other keys
+  // with Ctrl modifier but for ctrl key itself.
+  if (util.getKeyModifiers(event) + event.keyCode == '17') {
+    this.ctrlKeyPressed_ = false;
+    this.updateAvailability();
+  }
+};
+
+/**
+ * Commands.
+ * @type {Object.<string, Command>}
+ * @const
+ * @private
+ */
+CommandHandler.COMMANDS_ = {};
+
+/**
+ * Unmounts external drive.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['unmount'] = {
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  execute: function(event, fileManager) {
+    var root = CommandUtil.getCommandEntry(event.target);
+    if (root)
+      fileManager.unmountVolume(PathUtil.getRootPath(root.fullPath));
+  },
+  /**
+   * @param {Event} event Command event.
+   */
+  canExecute: function(event, fileManager) {
+    var rootType = CommandUtil.getCommandRootType(event.target);
+
+    event.canExecute = (rootType == RootType.ARCHIVE ||
+                        rootType == RootType.REMOVABLE);
+    event.command.setHidden(!event.canExecute);
+    event.command.label = rootType == RootType.ARCHIVE ?
+        str('CLOSE_ARCHIVE_BUTTON_LABEL') :
+        str('UNMOUNT_DEVICE_BUTTON_LABEL');
+  }
+};
+
+/**
+ * Formats external drive.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['format'] = {
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  execute: function(event, fileManager) {
+    var root = CommandUtil.getCommandEntry(event.target);
+
+    if (root) {
+      var url = util.makeFilesystemUrl(PathUtil.getRootPath(root.fullPath));
+      fileManager.confirm.show(
+          loadTimeData.getString('FORMATTING_WARNING'),
+          chrome.fileBrowserPrivate.formatDevice.bind(null, url));
+    }
+  },
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  canExecute: function(event, fileManager) {
+    var directoryModel = fileManager.directoryModel;
+    var root = CommandUtil.getCommandEntry(event.target);
+    var removable = root &&
+                    PathUtil.getRootType(root.fullPath) == RootType.REMOVABLE;
+    var isReadOnly = root && directoryModel.isPathReadOnly(root.fullPath);
+    event.canExecute = removable && !isReadOnly;
+    event.command.setHidden(!removable);
+  }
+};
+
+/**
+ * Imports photos from external drive.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['import-photos'] = {
+  /**
+   * @param {Event} event Command event.
+   * @param {NavigationList} navigationList Target navigation list.
+   */
+  execute: function(event, fileManager) {
+    var navigationList = fileManager.navigationList;
+    var root = CommandUtil.getCommandEntry(navigationList);
+    if (!root)
+      return;
+
+    // TODO(mtomasz): Implement launching Photo Importer.
+  },
+  /**
+   * @param {Event} event Command event.
+   * @param {NavigationList} navigationList Target navigation list.
+   */
+  canExecute: function(event, fileManager) {
+    var navigationList = fileManager.navigationList;
+    var rootType = CommandUtil.getCommandRootType(navigationList);
+    event.canExecute = (rootType != RootType.DRIVE);
+  }
+};
+
+/**
+ * Initiates new folder creation.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['new-folder'] = {
+  execute: function(event, fileManager) {
+    fileManager.createNewFolder();
+  },
+  canExecute: function(event, fileManager) {
+    var directoryModel = fileManager.directoryModel;
+    event.canExecute = !fileManager.isOnReadonlyDirectory() &&
+                       !fileManager.isRenamingInProgress() &&
+                       !directoryModel.isSearching() &&
+                       !directoryModel.isScanning();
+  }
+};
+
+/**
+ * Initiates new window creation.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['new-window'] = {
+  execute: function(event, fileManager) {
+    fileManager.backgroundPage.launchFileManager({
+      defaultPath: fileManager.getCurrentDirectory()
+    });
+  },
+  canExecute: function(event, fileManager) {
+    event.canExecute =
+        fileManager.getCurrentDirectoryEntry() &&
+        (fileManager.dialogType === DialogType.FULL_PAGE);
+  }
+};
+
+/**
+ * Changed the default app handling inserted media.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['change-default-app'] = {
+  execute: function(event, fileManager) {
+    fileManager.showChangeDefaultAppPicker();
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Deletes selected files.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['delete'] = {
+  execute: function(event, fileManager) {
+    fileManager.deleteSelection();
+  },
+  canExecute: function(event, fileManager) {
+    var selection = fileManager.getSelection();
+    event.canExecute = !fileManager.isOnReadonlyDirectory() &&
+                       selection &&
+                       selection.totalCount > 0;
+  }
+};
+
+/**
+ * Pastes files from clipboard.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['paste'] = {
+  execute: function() {
+    document.execCommand(event.command.id);
+  },
+  canExecute: function(event, fileManager) {
+    var document = fileManager.document;
+    var fileTransferController = fileManager.fileTransferController;
+    event.canExecute = (fileTransferController &&
+        fileTransferController.queryPasteCommandEnabled());
+  }
+};
+
+CommandHandler.COMMANDS_['cut'] = CommandUtil.defaultCommand;
+CommandHandler.COMMANDS_['copy'] = CommandUtil.defaultCommand;
+
+/**
+ * Initiates file renaming.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['rename'] = {
+  execute: function(event, fileManager) {
+    fileManager.initiateRename();
+  },
+  canExecute: function(event, fileManager) {
+    var selection = fileManager.getSelection();
+    event.canExecute =
+        !fileManager.isRenamingInProgress() &&
+        !fileManager.isOnReadonlyDirectory() &&
+        selection &&
+        selection.totalCount == 1;
+  }
+};
+
+/**
+ * Opens drive help.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['volume-help'] = {
+  execute: function(event, fileManager) {
+    if (fileManager.isOnDrive())
+      util.visitURL(urlConstants.GOOGLE_DRIVE_HELP);
+    else
+      util.visitURL(urlConstants.FILES_APP_HELP);
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Opens drive buy-more-space url.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['drive-buy-more-space'] = {
+  execute: function(event, fileManager) {
+    util.visitURL(urlConstants.GOOGLE_DRIVE_BUY_STORAGE);
+  },
+  canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
+};
+
+/**
+ * Clears drive cache.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['drive-clear-local-cache'] = {
+  execute: function(event, fileManager) {
+    chrome.fileBrowserPrivate.clearDriveCache();
+  },
+  canExecute: function(event, fileManager) {
+    event.canExecute = fileManager.isOnDrive() && this.ctrlKeyPressed_;
+    event.command.setHidden(!event.canExecute);
+  }
+};
+
+/**
+ * Opens drive.google.com.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['drive-go-to-drive'] = {
+  execute: function(event, fileManager) {
+    util.visitURL(urlConstants.GOOGLE_DRIVE_ROOT);
+  },
+  canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
+};
+
+/**
+ * Displays open with dialog for current selection.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['open-with'] = {
+  execute: function(event, fileManager) {
+    var tasks = fileManager.getSelection().tasks;
+    if (tasks) {
+      tasks.showTaskPicker(fileManager.defaultTaskPicker,
+          str('OPEN_WITH_BUTTON_LABEL'),
+          null,
+          function(task) {
+            tasks.execute(task.taskId);
+          });
+    }
+  },
+  canExecute: function(event, fileManager) {
+    var tasks = fileManager.getSelection().tasks;
+    event.canExecute = tasks && tasks.size() > 1;
+  }
+};
+
+/**
+ * Focuses search input box.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['search'] = {
+  execute: function(event, fileManager) {
+    var element = fileManager.document.querySelector('#search-box input');
+    element.focus();
+    element.select();
+  },
+  canExecute: function(event, fileManager) {
+    event.canExecute = !fileManager.isRenamingInProgress();
+  }
+};
+
+/**
+ * Activates the n-th volume.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['volume-switch-1'] =
+    CommandUtil.createVolumeSwitchCommand(1);
+CommandHandler.COMMANDS_['volume-switch-2'] =
+    CommandUtil.createVolumeSwitchCommand(2);
+CommandHandler.COMMANDS_['volume-switch-3'] =
+    CommandUtil.createVolumeSwitchCommand(3);
+CommandHandler.COMMANDS_['volume-switch-4'] =
+    CommandUtil.createVolumeSwitchCommand(4);
+CommandHandler.COMMANDS_['volume-switch-5'] =
+    CommandUtil.createVolumeSwitchCommand(5);
+CommandHandler.COMMANDS_['volume-switch-6'] =
+    CommandUtil.createVolumeSwitchCommand(6);
+CommandHandler.COMMANDS_['volume-switch-7'] =
+    CommandUtil.createVolumeSwitchCommand(7);
+CommandHandler.COMMANDS_['volume-switch-8'] =
+    CommandUtil.createVolumeSwitchCommand(8);
+CommandHandler.COMMANDS_['volume-switch-9'] =
+    CommandUtil.createVolumeSwitchCommand(9);
+
+/**
+ * Flips 'available offline' flag on the file.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['toggle-pinned'] = {
+  execute: function(event, fileManager) {
+    var pin = !event.command.checked;
+    event.command.checked = pin;
+    var entries = CommandUtil.getPinTargetEntries();
+    var currentEntry;
+    var error = false;
+    var steps = {
+      // Pick an entry and pin it.
+      start: function() {
+        // Check if all the entries are pinned or not.
+        if (entries.length == 0)
+          return;
+        currentEntry = entries.shift();
+        chrome.fileBrowserPrivate.pinDriveFile(
+            currentEntry.toURL(),
+            pin,
+            steps.entryPinned);
+      },
+
+      // Check the result of pinning
+      entryPinned: function() {
+        // Convert to boolean.
+        error = !!chrome.runtime.lastError;
+        if (error && pin) {
+          fileManager.metadataCache_.get(
+              currentEntry, 'filesystem', steps.showError);
+        }
+        fileManager.metadataCache_.clear(currentEntry, 'drive');
+        fileManager.metadataCache_.get(
+            currentEntry, 'drive', steps.updateUI.bind(this));
+      },
+
+      // Update the user interface accoding to the cache state.
+      updateUI: function(drive) {
+        fileManager.updateMetadataInUI_(
+            'drive', [currentEntry.toURL()], [drive]);
+        if (!error)
+          steps.start();
+      },
+
+      // Show the error
+      showError: function(filesystem) {
+        fileManager.alert.showHtml(str('DRIVE_OUT_OF_SPACE_HEADER'),
+                                   strf('DRIVE_OUT_OF_SPACE_MESSAGE',
+                                        unescape(currentEntry.name),
+                                        util.bytesToString(filesystem.size)));
+      }
+    };
+    steps.start();
+  },
+
+  canExecute: function(event, fileManager) {
+    var entries = CommandUtil.getPinTargetEntries();
+    var checked = true;
+    for (var i = 0; i < entries.length; i++) {
+      checked = checked && entries[i].pinned;
+    }
+    if (entries.length > 0) {
+      event.canExecute = true;
+      event.command.setHidden(false);
+      event.command.checked = checked;
+    } else {
+      event.canExecute = false;
+      event.command.setHidden(true);
+    }
+  }
+};
+
+/**
+ * Creates zip file for current selection.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['zip-selection'] = {
+  execute: function(event, fileManager) {
+    var dirEntry = fileManager.getCurrentDirectoryEntry();
+    var selectionEntries = fileManager.getSelection().entries;
+    fileManager.fileOperationManager_.zipSelection(dirEntry, selectionEntries);
+  },
+  canExecute: function(event, fileManager) {
+    var dirEntry = fileManager.getCurrentDirectoryEntry();
+    var selection = fileManager.getSelection();
+    event.canExecute =
+        dirEntry &&
+        !fileManager.isOnReadonlyDirectory() &&
+        !fileManager.isOnDrive() &&
+        selection && selection.totalCount > 0;
+  }
+};
+
+/**
+ * Shows the share dialog for the current selection (single only).
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['share'] = {
+  execute: function(event, fileManager) {
+    fileManager.shareSelection();
+  },
+  canExecute: function(event, fileManager) {
+    var selection = fileManager.getSelection();
+    event.canExecute = fileManager.isOnDrive() &&
+        !fileManager.isDriveOffline() &&
+        selection && selection.totalCount == 1;
+    event.command.setHidden(!fileManager.isOnDrive());
+  }
+};
+
+/**
+ * Creates a shortcut of the selected folder (single only).
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['create-folder-shortcut'] = {
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  execute: function(event, fileManager) {
+    var entry = CommandUtil.getCommandEntry(event.target);
+    if (entry)
+      fileManager.createFolderShortcut(entry.fullPath);
+  },
+
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  canExecute: function(event, fileManager) {
+    var target = event.target;
+    if (!(target instanceof NavigationListItem) &&
+        !(target instanceof DirectoryItem)) {
+      event.command.setHidden(true);
+      return;
+    }
+
+    var entry = CommandUtil.getCommandEntry(event.target);
+    var folderShortcutExists = entry &&
+                               fileManager.folderShortcutExists(entry.fullPath);
+
+    var onlyOneFolderSelected = true;
+    // Only on list, user can select multiple files. The command is enabled only
+    // when a single file is selected.
+    if (event.target instanceof cr.ui.List &&
+        !(event.target instanceof NavigationList)) {
+      var items = event.target.selectedItems;
+      onlyOneFolderSelected = (items.length == 1 && items[0].isDirectory);
+    }
+
+    var eligible = entry &&
+                   PathUtil.isEligibleForFolderShortcut(entry.fullPath);
+    event.canExecute =
+        eligible && onlyOneFolderSelected && !folderShortcutExists;
+    event.command.setHidden(!eligible || !onlyOneFolderSelected);
+  }
+};
+
+/**
+ * Removes the folder shortcut.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['remove-folder-shortcut'] = {
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  execute: function(event, fileManager) {
+    var entry = CommandUtil.getCommandEntry(event.target);
+    if (entry && entry.fullPath)
+      fileManager.removeFolderShortcut(entry.fullPath);
+  },
+
+  /**
+   * @param {Event} event Command event.
+   * @param {FileManager} fileManager The file manager instance.
+   */
+  canExecute: function(event, fileManager) {
+    var target = event.target;
+    if (!target instanceof NavigationListItem &&
+        !target instanceof DirectoryItem) {
+      event.command.setHidden(true);
+      return;
+    }
+
+    var entry = CommandUtil.getCommandEntry(target);
+    var path = entry && entry.fullPath;
+
+    var eligible = path && PathUtil.isEligibleForFolderShortcut(path);
+    var isShortcut = path && fileManager.folderShortcutExists(path);
+    event.canExecute = isShortcut && eligible;
+    event.command.setHidden(!event.canExecute);
+  }
+};
+
+/**
+ * Zoom in to the Files.app.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['zoom-in'] = {
+  execute: function(event, fileManager) {
+    chrome.fileBrowserPrivate.zoom('in');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Zoom out from the Files.app.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['zoom-out'] = {
+  execute: function(event, fileManager) {
+    chrome.fileBrowserPrivate.zoom('out');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Reset the zoom factor.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['zoom-reset'] = {
+  execute: function(event, fileManager) {
+    chrome.fileBrowserPrivate.zoom('reset');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js b/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js
new file mode 100644
index 0000000..2def1c4
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js
@@ -0,0 +1,57 @@
+// Copyright 2013 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.
+
+'use strict';
+
+/**
+ * While FileOperationManager is run in the background page, this class is
+ * used to communicate with it.
+ * @param {DOMWindow} backgroundPage Window object of the background page.
+ * @constructor
+ */
+function FileOperationManagerWrapper(backgroundPage) {
+  this.fileOperationManager_ =
+      backgroundPage.FileOperationManager.getInstance();
+}
+
+/**
+ * Create a new instance or get existing instance of FCMW.
+ * @param {DOMWindow} backgroundPage Window object of the background page.
+ * @return {FileOperationManagerWrapper}  FileOperationManagerWrapper instance.
+ */
+FileOperationManagerWrapper.getInstance = function(backgroundPage) {
+  if (!FileOperationManagerWrapper.instance_)
+    FileOperationManagerWrapper.instance_ =
+        new FileOperationManagerWrapper(backgroundPage);
+
+  return FileOperationManagerWrapper.instance_;
+};
+
+/**
+ * @return {boolean} True if there is a running task.
+ */
+FileOperationManagerWrapper.prototype.isRunning = function() {
+  return this.fileOperationManager_.hasQueuedTasks();
+};
+
+/**
+ * Decorates a FileOperationManager method, so it will be executed after
+ * initializing the FileOperationManager instance in background page.
+ * @param {string} method The method name.
+ */
+FileOperationManagerWrapper.decorateAsyncMethod = function(method) {
+  FileOperationManagerWrapper.prototype[method] = function() {
+    this.fileOperationManager_.willRunNewMethod();
+    this.fileOperationManager_[method].apply(
+        this.fileOperationManager_, arguments);
+  };
+};
+
+FileOperationManagerWrapper.decorateAsyncMethod('paste');
+FileOperationManagerWrapper.decorateAsyncMethod('deleteEntries');
+FileOperationManagerWrapper.decorateAsyncMethod('forceDeleteTask');
+FileOperationManagerWrapper.decorateAsyncMethod('cancelDeleteTask');
+FileOperationManagerWrapper.decorateAsyncMethod('zipSelection');
+FileOperationManagerWrapper.decorateAsyncMethod('addEventListener');
+FileOperationManagerWrapper.decorateAsyncMethod('removeEventListener');
diff --git a/chrome/browser/resources/file_manager/js/file_selection.js b/chrome/browser/resources/file_manager/foreground/js/file_selection.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/file_selection.js
rename to chrome/browser/resources/file_manager/foreground/js/file_selection.js
diff --git a/chrome/browser/resources/file_manager/js/file_table.js b/chrome/browser/resources/file_manager/foreground/js/file_table.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/file_table.js
rename to chrome/browser/resources/file_manager/foreground/js/file_table.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_tasks.js b/chrome/browser/resources/file_manager/foreground/js/file_tasks.js
new file mode 100644
index 0000000..e7ce7a5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/file_tasks.js
@@ -0,0 +1,804 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * This object encapsulates everything related to tasks execution.
+ *
+ * @param {FileManager} fileManager FileManager instance.
+ * @param {Object=} opt_params File manager load parameters.
+ * @constructor
+ */
+function FileTasks(fileManager, opt_params) {
+  this.fileManager_ = fileManager;
+  this.params_ = opt_params;
+  this.tasks_ = null;
+  this.defaultTask_ = null;
+
+  /**
+   * List of invocations to be called once tasks are available.
+   *
+   * @private
+   * @type {Array.<Object>}
+   */
+  this.pendingInvocations_ = [];
+}
+
+/**
+ * Location of the FAQ about the file actions.
+ *
+ * @const
+ * @type {string}
+ */
+FileTasks.NO_ACTION_FOR_FILE_URL = 'http://support.google.com/chromeos/bin/' +
+    'answer.py?answer=1700055&topic=29026&ctx=topic';
+
+/**
+ * Location of the Chrome Web Store.
+ *
+ * @const
+ * @type {string}
+ */
+FileTasks.CHROME_WEB_STORE_URL = 'https://chrome.google.com/webstore';
+
+/**
+ * Base URL of apps list in the Chrome Web Store. This constant is used in
+ * FileTasks.createWebStoreLink().
+ *
+ * @const
+ * @type {string}
+ */
+FileTasks.WEB_STORE_HANDLER_BASE_URL =
+    'https://chrome.google.com/webstore/category/collection/file_handlers';
+
+/**
+ * Returns URL of the Chrome Web Store which show apps supporting the given
+ * file-extension and mime-type.
+ *
+ * @param {string} extension Extension of the file.
+ * @param {string} mimeType Mime type of the file.
+ * @return {string} URL
+ */
+FileTasks.createWebStoreLink = function(extension, mimeType) {
+  if (!extension)
+    return FileTasks.CHROME_WEB_STORE_URL;
+
+  var url = FileTasks.WEB_STORE_HANDLER_BASE_URL;
+  url += '?_fe=' + extension.toLowerCase().replace(/[^\w]/g, '');
+
+  // If a mime is given, add it into the URL.
+  if (mimeType)
+    url += '&_fmt=' + mimeType.replace(/[^-\w\/]/g, '');
+  return url;
+};
+
+/**
+ * Complete the initialization.
+ *
+ * @param {Array.<string>} urls List of file urls.
+ * @param {Array.<string>=} opt_mimeTypes List of MIME types for each
+ *     of the files.
+ */
+FileTasks.prototype.init = function(urls, opt_mimeTypes) {
+  this.urls_ = urls;
+  this.mimeTypes_ = opt_mimeTypes || [];
+  if (urls.length > 0) {
+    chrome.fileBrowserPrivate.getFileTasks(urls, this.mimeTypes_,
+        this.onTasks_.bind(this));
+  }
+};
+
+/**
+ * Returns amount of tasks.
+ *
+ * @return {number} amount of tasks.
+ */
+FileTasks.prototype.size = function() {
+  return (this.tasks_ && this.tasks_.length) || 0;
+};
+
+/**
+ * Callback when tasks found.
+ *
+ * @param {Array.<Object>} tasks The tasks.
+ * @private
+ */
+FileTasks.prototype.onTasks_ = function(tasks) {
+  this.processTasks_(tasks);
+  for (var index = 0; index < this.pendingInvocations_.length; index++) {
+    var name = this.pendingInvocations_[index][0];
+    var args = this.pendingInvocations_[index][1];
+    this[name].apply(this, args);
+  }
+  this.pendingInvocations_ = [];
+};
+
+/**
+ * The list of known extensions to record UMA.
+ * Note: Because the data is recorded by the index, so new item shouldn't be
+ * inserted.
+ *
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+FileTasks.knownExtensions_ = [
+  'other', '.3ga', '.3gp', '.aac', '.alac', '.asf', '.avi', '.bmp', '.csv',
+  '.doc', '.docx', '.flac', '.gif', '.jpeg', '.jpg', '.log', '.m3u', '.m3u8',
+  '.m4a', '.m4v', '.mid', '.mkv', '.mov', '.mp3', '.mp4', '.mpg', '.odf',
+  '.odp', '.ods', '.odt', '.oga', '.ogg', '.ogv', '.pdf', '.png', '.ppt',
+  '.pptx', '.ra', '.ram', '.rar', '.rm', '.rtf', '.wav', '.webm', '.webp',
+  '.wma', '.wmv', '.xls', '.xlsx',
+];
+
+/**
+ * The list of extensions to skip the suggest app dialog.
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+FileTasks.EXTENSIONS_TO_SKIP_SUGGEST_APPS_ = Object.freeze([
+  'crdownload', 'dsc', 'inf',
+]);
+
+/**
+ * Records trial of opening file grouped by extensions.
+ *
+ * @param {Array.<string>} urls The path to be opened.
+ * @private
+ */
+FileTasks.recordViewingFileTypeUMA_ = function(urls) {
+  for (var i = 0; i < urls.length; i++) {
+    var url = urls[i];
+    var extension = FileType.getExtension(url).toLowerCase();
+    if (FileTasks.knownExtensions_.indexOf(extension) < 0) {
+      extension = 'other';
+    }
+    metrics.recordEnum(
+        'ViewingFileType', extension, FileTasks.knownExtensions_);
+  }
+};
+
+/**
+ * Returns true if the taskId is for an internal task.
+ *
+ * @param {string} taskId Task identifier.
+ * @return {boolean} True if the task ID is for an internal task.
+ * @private
+ */
+FileTasks.isInternalTask_ = function(taskId) {
+  var taskParts = taskId.split('|');
+  var appId = taskParts[0];
+  var taskType = taskParts[1];
+  var actionId = taskParts[2];
+  // The action IDs here should match ones used in executeInternalTask_().
+  return (appId == chrome.runtime.id &&
+          taskType == 'file' &&
+          (actionId == 'play' ||
+           actionId == 'watch' ||
+           actionId == 'mount-archive' ||
+           actionId == 'format-device' ||
+           actionId == 'gallery'));
+};
+
+/**
+ * Processes internal tasks.
+ *
+ * @param {Array.<Object>} tasks The tasks.
+ * @private
+ */
+FileTasks.prototype.processTasks_ = function(tasks) {
+  this.tasks_ = [];
+  var id = chrome.runtime.id;
+  var isOnDrive = false;
+  for (var index = 0; index < this.urls_.length; ++index) {
+    if (FileType.isOnDrive(this.urls_[index])) {
+      isOnDrive = true;
+      break;
+    }
+  }
+
+  for (var i = 0; i < tasks.length; i++) {
+    var task = tasks[i];
+    var taskParts = task.taskId.split('|');
+
+    // Skip internal Files.app's handlers.
+    if (taskParts[0] == id && (taskParts[2] == 'auto-open' ||
+        taskParts[2] == 'select' || taskParts[2] == 'open')) {
+      continue;
+    }
+
+    // Tweak images, titles of internal tasks.
+    if (taskParts[0] == id && taskParts[1] == 'file') {
+      if (taskParts[2] == 'play') {
+        // TODO(serya): This hack needed until task.iconUrl is working
+        //             (see GetFileTasksFileBrowserFunction::RunImpl).
+        task.iconType = 'audio';
+        task.title = loadTimeData.getString('ACTION_LISTEN');
+      } else if (taskParts[2] == 'mount-archive') {
+        task.iconType = 'archive';
+        task.title = loadTimeData.getString('MOUNT_ARCHIVE');
+      } else if (taskParts[2] == 'gallery') {
+        task.iconType = 'image';
+        task.title = loadTimeData.getString('ACTION_OPEN');
+      } else if (taskParts[2] == 'watch') {
+        task.iconType = 'video';
+        task.title = loadTimeData.getString('ACTION_WATCH');
+      } else if (taskParts[2] == 'open-hosted-generic') {
+        if (this.urls_.length > 1)
+          task.iconType = 'generic';
+        else // Use specific icon.
+          task.iconType = FileType.getIcon(this.urls_[0]);
+        task.title = loadTimeData.getString('ACTION_OPEN');
+      } else if (taskParts[2] == 'open-hosted-gdoc') {
+        task.iconType = 'gdoc';
+        task.title = loadTimeData.getString('ACTION_OPEN_GDOC');
+      } else if (taskParts[2] == 'open-hosted-gsheet') {
+        task.iconType = 'gsheet';
+        task.title = loadTimeData.getString('ACTION_OPEN_GSHEET');
+      } else if (taskParts[2] == 'open-hosted-gslides') {
+        task.iconType = 'gslides';
+        task.title = loadTimeData.getString('ACTION_OPEN_GSLIDES');
+      } else if (taskParts[2] == 'view-swf') {
+        // Do not render this task if disabled.
+        if (!loadTimeData.getBoolean('SWF_VIEW_ENABLED'))
+          continue;
+        task.iconType = 'generic';
+        task.title = loadTimeData.getString('ACTION_VIEW');
+      } else if (taskParts[2] == 'view-pdf') {
+        // Do not render this task if disabled.
+        if (!loadTimeData.getBoolean('PDF_VIEW_ENABLED'))
+          continue;
+        task.iconType = 'pdf';
+        task.title = loadTimeData.getString('ACTION_VIEW');
+      } else if (taskParts[2] == 'view-in-browser') {
+        task.iconType = 'generic';
+        task.title = loadTimeData.getString('ACTION_VIEW');
+      }
+    }
+
+    if (!task.iconType && taskParts[1] == 'web-intent') {
+      task.iconType = 'generic';
+    }
+
+    this.tasks_.push(task);
+    if (this.defaultTask_ == null && task.isDefault) {
+      this.defaultTask_ = task;
+    }
+  }
+  if (!this.defaultTask_ && this.tasks_.length > 0) {
+    // If we haven't picked a default task yet, then just pick the first one.
+    // This is not the preferred way we want to pick this, but better this than
+    // no default at all if the C++ code didn't set one.
+    this.defaultTask_ = this.tasks_[0];
+  }
+};
+
+/**
+ * Executes default task.
+ *
+ * @param {function(boolean, Array.<string>)=} opt_callback Called when the
+ *     default task is executed, or the error is occurred.
+ * @private
+ */
+FileTasks.prototype.executeDefault_ = function(opt_callback) {
+  var urls = this.urls_;
+  FileTasks.recordViewingFileTypeUMA_(urls);
+  this.executeDefaultInternal_(urls, opt_callback);
+};
+
+/**
+ * Executes default task.
+ *
+ * @param {Array.<string>} urls Urls to execute.
+ * @param {function(boolean, Array.<string>)=} opt_callback Called when the
+ *     default task is executed, or the error is occurred.
+ * @private
+ */
+FileTasks.prototype.executeDefaultInternal_ = function(urls, opt_callback) {
+  var callback = opt_callback || function(arg1, arg2) {};
+
+  if (this.defaultTask_ != null) {
+    this.executeInternal_(this.defaultTask_.taskId, urls);
+    callback(true, urls);
+    return;
+  }
+
+  // We don't have tasks, so try to show a file in a browser tab.
+  // We only do that for single selection to avoid confusion.
+  if (urls.length != 1 || !urls[0])
+    return;
+
+  var filename = decodeURIComponent(urls[0]);
+  if (filename.indexOf('/') != -1)
+    filename = filename.substr(filename.lastIndexOf('/') + 1);
+  var extension = filename.lastIndexOf('.') != -1 ?
+      filename.substr(filename.lastIndexOf('.') + 1) : '';
+  var mimeType = this.mimeTypes_[0];
+
+  var showAlert = function() {
+    var messageString =
+        extension == 'exe' ? 'NO_ACTION_FOR_EXECUTABLE' :
+                             'NO_ACTION_FOR_FILE';
+    var webStoreUrl = FileTasks.createWebStoreLink(extension, mimeType);
+    var text = loadTimeData.getStringF(
+        messageString,
+        webStoreUrl,
+        FileTasks.NO_ACTION_FOR_FILE_URL);
+    this.fileManager_.alert.showHtml(filename, text, function() {});
+    callback(false, urls);
+  }.bind(this);
+
+  var onViewFilesFailure = function() {
+    var fm = this.fileManager_;
+    if (fm.enableExperimentalWebStoreIntegration_) {
+      showAlert();
+      return;
+    }
+
+    if (!fm.isOnDrive() ||
+        !urls[0] ||
+        FileTasks.EXTENSIONS_TO_SKIP_SUGGEST_APPS_.indexOf(extension) != -1) {
+      showAlert();
+      return;
+    }
+
+    fm.openSuggestAppsDialog(
+        urls[0],
+        function() {
+          var newTasks = new FileTasks(fm);
+          tasks.init(urls, this.mimeTypes_);
+          tasks.executeDefault();
+          callback(true, urls);
+        }.bind(this),
+        // Cancelled callback.
+        function() {
+          callback(false, urls);
+        },
+        showAlert);
+  }.bind(this);
+
+  var onViewFiles = function(success) {
+    if (success)
+      callback(success, urls);
+    else
+      onViewFilesFailure();
+  }.bind(this);
+
+  this.checkAvailability_(function() {
+    util.viewFilesInBrowser(urls, onViewFiles);
+  }.bind(this));
+};
+
+/**
+ * Executes a single task.
+ *
+ * @param {string} taskId Task identifier.
+ * @param {Array.<string>=} opt_urls Urls to execute on instead of |this.urls_|.
+ * @private
+ */
+FileTasks.prototype.execute_ = function(taskId, opt_urls) {
+  var urls = opt_urls || this.urls_;
+  FileTasks.recordViewingFileTypeUMA_(urls);
+  this.executeInternal_(taskId, urls);
+};
+
+/**
+ * The core implementation to execute a single task.
+ *
+ * @param {string} taskId Task identifier.
+ * @param {Array.<string>} urls Urls to execute.
+ * @private
+ */
+FileTasks.prototype.executeInternal_ = function(taskId, urls) {
+  this.checkAvailability_(function() {
+    if (FileTasks.isInternalTask_(taskId)) {
+      var taskParts = taskId.split('|');
+      this.executeInternalTask_(taskParts[2], urls);
+    } else {
+      chrome.fileBrowserPrivate.executeTask(taskId, urls);
+    }
+  }.bind(this));
+};
+
+/**
+ * Checks whether the remote files are available right now.
+ *
+ * @param {function} callback The callback.
+ * @private
+ */
+FileTasks.prototype.checkAvailability_ = function(callback) {
+  var areAll = function(props, name) {
+    var isOne = function(e) {
+      // If got no properties, we safely assume that item is unavailable.
+      return e && e[name];
+    };
+    return props.filter(isOne).length == props.length;
+  };
+
+  var fm = this.fileManager_;
+  var urls = this.urls_;
+
+  if (fm.isOnDrive() && fm.isDriveOffline()) {
+    fm.metadataCache_.get(urls, 'drive', function(props) {
+      if (areAll(props, 'availableOffline')) {
+        callback();
+        return;
+      }
+
+      fm.alert.showHtml(
+          loadTimeData.getString('OFFLINE_HEADER'),
+          props[0].hosted ?
+            loadTimeData.getStringF(
+                urls.length == 1 ?
+                    'HOSTED_OFFLINE_MESSAGE' :
+                    'HOSTED_OFFLINE_MESSAGE_PLURAL') :
+            loadTimeData.getStringF(
+                urls.length == 1 ?
+                    'OFFLINE_MESSAGE' :
+                    'OFFLINE_MESSAGE_PLURAL',
+                loadTimeData.getString('OFFLINE_COLUMN_LABEL')));
+    });
+    return;
+  }
+
+  if (fm.isOnDrive() && fm.isDriveOnMeteredConnection()) {
+    fm.metadataCache_.get(urls, 'drive', function(driveProps) {
+      if (areAll(driveProps, 'availableWhenMetered')) {
+        callback();
+        return;
+      }
+
+      fm.metadataCache_.get(urls, 'filesystem', function(fileProps) {
+        var sizeToDownload = 0;
+        for (var i = 0; i != urls.length; i++) {
+          if (!driveProps[i].availableWhenMetered)
+            sizeToDownload += fileProps[i].size;
+        }
+        fm.confirm.show(
+            loadTimeData.getStringF(
+                urls.length == 1 ?
+                    'CONFIRM_MOBILE_DATA_USE' :
+                    'CONFIRM_MOBILE_DATA_USE_PLURAL',
+                util.bytesToString(sizeToDownload)),
+            callback);
+      });
+    });
+    return;
+  }
+
+  callback();
+};
+
+/**
+ * Executes an internal task.
+ *
+ * @param {string} id The short task id.
+ * @param {Array.<string>} urls The urls to execute on.
+ * @private
+ */
+FileTasks.prototype.executeInternalTask_ = function(id, urls) {
+  var fm = this.fileManager_;
+
+  if (id == 'play') {
+    var position = 0;
+    if (urls.length == 1) {
+      // If just a single audio file is selected pass along every audio file
+      // in the directory.
+      var selectedUrl = urls[0];
+      urls = fm.getAllUrlsInCurrentDirectory().filter(FileType.isAudio);
+      position = urls.indexOf(selectedUrl);
+    }
+    fm.backgroundPage.launchAudioPlayer({ items: urls, position: position });
+    return;
+  }
+
+  if (id == 'watch') {
+    console.assert(urls.length == 1, 'Cannot open multiple videos');
+    fm.backgroundPage.launchVideoPlayer(urls[0]);
+    return;
+  }
+
+  if (id == 'mount-archive') {
+    this.mountArchivesInternal_(urls);
+    return;
+  }
+
+  if (id == 'format-device') {
+    fm.confirm.show(loadTimeData.getString('FORMATTING_WARNING'), function() {
+      chrome.fileBrowserPrivate.formatDevice(urls[0]);
+    });
+    return;
+  }
+
+  if (id == 'gallery') {
+    this.openGalleryInternal_(urls);
+    return;
+  }
+
+  console.error('Unexpected action ID: ' + id);
+};
+
+/**
+ * Mounts archives.
+ *
+ * @param {Array.<string>} urls Mount file urls list.
+ */
+FileTasks.prototype.mountArchives = function(urls) {
+  FileTasks.recordViewingFileTypeUMA_(urls);
+  this.mountArchivesInternal_(urls);
+};
+
+/**
+ * The core implementation of mounts archives.
+ *
+ * @param {Array.<string>} urls Mount file urls list.
+ * @private
+ */
+FileTasks.prototype.mountArchivesInternal_ = function(urls) {
+  var fm = this.fileManager_;
+
+  var tracker = fm.directoryModel_.createDirectoryChangeTracker();
+  tracker.start();
+
+  fm.resolveSelectResults_(urls, function(urls) {
+    for (var index = 0; index < urls.length; ++index) {
+      fm.volumeManager_.mountArchive(urls[index], function(mountPath) {
+        tracker.stop();
+        if (!tracker.hasChanged)
+          fm.directoryModel_.changeDirectory(mountPath);
+      }, function(url, error) {
+        var path = util.extractFilePath(url);
+        tracker.stop();
+        var namePos = path.lastIndexOf('/');
+        fm.alert.show(strf('ARCHIVE_MOUNT_FAILED',
+                           path.substr(namePos + 1), error));
+      }.bind(null, urls[index]));
+    }
+  });
+};
+
+/**
+ * Open the Gallery.
+ *
+ * @param {Array.<string>} urls List of selected urls.
+ */
+FileTasks.prototype.openGallery = function(urls) {
+  FileTasks.recordViewingFileTypeUMA_(urls);
+  this.openGalleryInternal_(urls);
+};
+
+/**
+ * The core implementation to open the Gallery.
+ *
+ * @param {Array.<string>} urls List of selected urls.
+ * @private
+ */
+FileTasks.prototype.openGalleryInternal_ = function(urls) {
+  var fm = this.fileManager_;
+
+  var allUrls =
+      fm.getAllUrlsInCurrentDirectory().filter(FileType.isImageOrVideo);
+
+  var galleryFrame = fm.document_.createElement('iframe');
+  galleryFrame.className = 'overlay-pane';
+  galleryFrame.scrolling = 'no';
+  galleryFrame.setAttribute('webkitallowfullscreen', true);
+
+  if (this.params_ && this.params_.gallery) {
+    // Remove the Gallery state from the location, we do not need it any more.
+    util.updateAppState(null /* keep path */, '' /* remove search. */);
+  }
+
+  var savedAppState = window.appState;
+  var savedTitle = document.title;
+
+  // Push a temporary state which will be replaced every time the selection
+  // changes in the Gallery and popped when the Gallery is closed.
+  util.updateAppState();
+
+  var onBack = function(selectedUrls) {
+    fm.directoryModel_.selectUrls(selectedUrls);
+    fm.closeFilePopup();  // Will call Gallery.unload.
+    window.appState = savedAppState;
+    util.saveAppState();
+    document.title = savedTitle;
+  };
+
+  var onClose = function() {
+    fm.onClose();
+  };
+
+  var onMaximize = function() {
+    fm.onMaximize();
+  };
+
+  var onAppRegionChanged = function(visible) {
+    fm.onFilePopupAppRegionChanged(visible);
+  };
+
+  galleryFrame.onload = function() {
+    galleryFrame.contentWindow.ImageUtil.metrics = metrics;
+
+    // TODO(haruki): isOnReadonlyDirectory() only checks the permission for the
+    // root. We should check more granular permission to know whether the file
+    // is writable or not.
+    var readonly = fm.isOnReadonlyDirectory();
+    var currentDir = fm.getCurrentDirectoryEntry();
+    var downloadsVolume =
+        fm.volumeManager_.getVolumeInfo(RootDirectory.DOWNLOADS);
+    var downloadsDir = downloadsVolume && downloadsVolume.root;
+    var readonlyDirName = null;
+    if (readonly && currentDir) {
+      var rootPath = PathUtil.getRootPath(currentDir.fullPath);
+      readonlyDirName = fm.isOnDrive() ?
+          PathUtil.getRootLabel(rootPath) :
+          PathUtil.basename(rootPath);
+    }
+
+    var context = {
+      // We show the root label in readonly warning (e.g. archive name).
+      readonlyDirName: readonlyDirName,
+      curDirEntry: currentDir,
+      saveDirEntry: readonly ? downloadsDir : null,
+      searchResults: fm.directoryModel_.isSearching(),
+      metadataCache: fm.metadataCache_,
+      pageState: this.params_,
+      appWindow: chrome.app.window.current(),
+      onBack: onBack,
+      onClose: onClose,
+      onMaximize: onMaximize,
+      onAppRegionChanged: onAppRegionChanged,
+      displayStringFunction: strf
+    };
+    galleryFrame.contentWindow.Gallery.open(
+        context, fm.volumeManager_, allUrls, urls);
+  }.bind(this);
+
+  galleryFrame.src = 'gallery.html';
+  fm.openFilePopup(galleryFrame, fm.updateTitle_.bind(fm));
+};
+
+/**
+ * Displays the list of tasks in a task picker combobutton.
+ *
+ * @param {cr.ui.ComboButton} combobutton The task picker element.
+ * @private
+ */
+FileTasks.prototype.display_ = function(combobutton) {
+  if (this.tasks_.length == 0) {
+    combobutton.hidden = true;
+    return;
+  }
+
+  combobutton.clear();
+  combobutton.hidden = false;
+  combobutton.defaultItem = this.createCombobuttonItem_(this.defaultTask_);
+
+  var items = this.createItems_();
+
+  if (items.length > 1) {
+    var defaultIdx = 0;
+
+    for (var j = 0; j < items.length; j++) {
+      combobutton.addDropDownItem(items[j]);
+      if (items[j].task.taskId == this.defaultTask_.taskId)
+        defaultIdx = j;
+    }
+
+    combobutton.addSeparator();
+    var changeDefaultMenuItem = combobutton.addDropDownItem({
+        label: loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM')
+    });
+    changeDefaultMenuItem.classList.add('change-default');
+  }
+};
+
+/**
+ * Creates sorted array of available task descriptions such as title and icon.
+ *
+ * @return {Array} created array can be used to feed combobox, menus and so on.
+ * @private
+ */
+FileTasks.prototype.createItems_ = function() {
+  var items = [];
+  var title = this.defaultTask_.title + ' ' +
+              loadTimeData.getString('DEFAULT_ACTION_LABEL');
+  items.push(this.createCombobuttonItem_(this.defaultTask_, title, true));
+
+  for (var index = 0; index < this.tasks_.length; index++) {
+    var task = this.tasks_[index];
+    if (task != this.defaultTask_)
+      items.push(this.createCombobuttonItem_(task));
+  }
+
+  items.sort(function(a, b) {
+    return a.label.localeCompare(b.label);
+  });
+
+  return items;
+};
+
+/**
+ * Updates context menu with default item.
+ * @private
+ */
+
+FileTasks.prototype.updateMenuItem_ = function() {
+  this.fileManager_.updateContextMenuActionItems(this.defaultTask_,
+      this.tasks_.length > 1);
+};
+
+/**
+ * Creates combobutton item based on task.
+ *
+ * @param {Object} task Task to convert.
+ * @param {string=} opt_title Title.
+ * @param {boolean=} opt_bold Make a menu item bold.
+ * @return {Object} Item appendable to combobutton drop-down list.
+ * @private
+ */
+FileTasks.prototype.createCombobuttonItem_ = function(task, opt_title,
+                                                      opt_bold) {
+  return {
+    label: opt_title || task.title,
+    iconUrl: task.iconUrl,
+    iconType: task.iconType,
+    task: task,
+    bold: opt_bold || false
+  };
+};
+
+
+/**
+ * Decorates a FileTasks method, so it will be actually executed after the tasks
+ * are available.
+ * This decorator expects an implementation called |method + '_'|.
+ *
+ * @param {string} method The method name.
+ */
+FileTasks.decorate = function(method) {
+  var privateMethod = method + '_';
+  FileTasks.prototype[method] = function() {
+    if (this.tasks_) {
+      this[privateMethod].apply(this, arguments);
+    } else {
+      this.pendingInvocations_.push([privateMethod, arguments]);
+    }
+    return this;
+  };
+};
+
+/**
+ * Shows modal action picker dialog with currently available list of tasks.
+ *
+ * @param {DefaultActionDialog} actionDialog Action dialog to show and update.
+ * @param {string} title Title to use.
+ * @param {string} message Message to use.
+ * @param {function(Object)} onSuccess Callback to pass selected task.
+ */
+FileTasks.prototype.showTaskPicker = function(actionDialog, title, message,
+                                              onSuccess) {
+  var items = this.createItems_();
+
+  var defaultIdx = 0;
+  for (var j = 0; j < items.length; j++) {
+    if (items[j].task.taskId == this.defaultTask_.taskId)
+      defaultIdx = j;
+  }
+
+  actionDialog.show(
+      title,
+      message,
+      items, defaultIdx,
+      function(item) {
+        onSuccess(item.task);
+      });
+};
+
+FileTasks.decorate('display');
+FileTasks.decorate('updateMenuItem');
+FileTasks.decorate('execute');
+FileTasks.decorate('executeDefault');
diff --git a/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js b/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js
new file mode 100644
index 0000000..ffe7c33
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js
@@ -0,0 +1,862 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Global (placed in the window object) variable name to hold internal
+ * file dragging information. Needed to show visual feedback while dragging
+ * since DataTransfer object is in protected state. Reachable from other
+ * file manager instances.
+ */
+var DRAG_AND_DROP_GLOBAL_DATA = '__drag_and_drop_global_data';
+
+/**
+ * @param {HTMLDocument} doc Owning document.
+ * @param {FileOperationManager} fileOperationManager File operation manager
+ *     instance.
+ * @param {MetadataCache} metadataCache Metadata cache service.
+ * @param {DirectoryModel} directoryModel Directory model instance.
+ * @constructor
+ */
+function FileTransferController(doc,
+                                fileOperationManager,
+                                metadataCache,
+                                directoryModel) {
+  this.document_ = doc;
+  this.fileOperationManager_ = fileOperationManager;
+  this.metadataCache_ = metadataCache;
+  this.directoryModel_ = directoryModel;
+
+  this.directoryModel_.getFileListSelection().addEventListener('change',
+      this.onSelectionChanged_.bind(this));
+
+  /**
+   * DOM element to represent selected file in drag operation. Used if only
+   * one element is selected.
+   * @type {HTMLElement}
+   * @private
+   */
+  this.preloadedThumbnailImageNode_ = null;
+
+  /**
+   * File objects for selected files.
+   *
+   * @type {Array.<File>}
+   * @private
+   */
+  this.selectedFileObjects_ = [];
+
+  /**
+   * Drag selector.
+   * @type {DragSelector}
+   * @private
+   */
+  this.dragSelector_ = new DragSelector();
+
+  /**
+   * Whether a user is touching the device or not.
+   * @type {boolean}
+   * @private
+   */
+  this.touching_ = false;
+}
+
+FileTransferController.prototype = {
+  __proto__: cr.EventTarget.prototype,
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list Items in the list will be draggable.
+   */
+  attachDragSource: function(list) {
+    list.style.webkitUserDrag = 'element';
+    list.addEventListener('dragstart', this.onDragStart_.bind(this, list));
+    list.addEventListener('dragend', this.onDragEnd_.bind(this, list));
+    list.addEventListener('touchstart', this.onTouchStart_.bind(this));
+    list.addEventListener('touchend', this.onTouchEnd_.bind(this));
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list List itself and its directory items will could
+   *                          be drop target.
+   * @param {boolean=} opt_onlyIntoDirectories If true only directory list
+   *     items could be drop targets. Otherwise any other place of the list
+   *     accetps files (putting it into the current directory).
+   */
+  attachFileListDropTarget: function(list, opt_onlyIntoDirectories) {
+    list.addEventListener('dragover', this.onDragOver_.bind(this,
+        !!opt_onlyIntoDirectories, list));
+    list.addEventListener('dragenter',
+        this.onDragEnterFileList_.bind(this, list));
+    list.addEventListener('dragleave', this.onDragLeave_.bind(this, list));
+    list.addEventListener('drop',
+        this.onDrop_.bind(this, !!opt_onlyIntoDirectories));
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {DirectoryTree} tree Its sub items will could be drop target.
+   */
+  attachTreeDropTarget: function(tree) {
+    tree.addEventListener('dragover', this.onDragOver_.bind(this, true, tree));
+    tree.addEventListener('dragenter', this.onDragEnterTree_.bind(this, tree));
+    tree.addEventListener('dragleave', this.onDragLeave_.bind(this, tree));
+    tree.addEventListener('drop', this.onDrop_.bind(this, true));
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {NavigationList} tree Its sub items will could be drop target.
+   */
+  attachNavigationListDropTarget: function(list) {
+    list.addEventListener('dragover',
+        this.onDragOver_.bind(this, true /* onlyIntoDirectories */, list));
+    list.addEventListener('dragenter',
+        this.onDragEnterVolumesList_.bind(this, list));
+    list.addEventListener('dragleave', this.onDragLeave_.bind(this, list));
+    list.addEventListener('drop',
+        this.onDrop_.bind(this, true /* onlyIntoDirectories */));
+  },
+
+  /**
+   * Attach handlers of copy, cut and paste operations to the document.
+   *
+   * @this {FileTransferController}
+   */
+  attachCopyPasteHandlers: function() {
+    this.document_.addEventListener('beforecopy',
+                                    this.onBeforeCopy_.bind(this));
+    this.document_.addEventListener('copy',
+                                    this.onCopy_.bind(this));
+    this.document_.addEventListener('beforecut',
+                                    this.onBeforeCut_.bind(this));
+    this.document_.addEventListener('cut',
+                                    this.onCut_.bind(this));
+    this.document_.addEventListener('beforepaste',
+                                    this.onBeforePaste_.bind(this));
+    this.document_.addEventListener('paste',
+                                    this.onPaste_.bind(this));
+    this.copyCommand_ = this.document_.querySelector('command#copy');
+  },
+
+  /**
+   * Write the current selection to system clipboard.
+   *
+   * @this {FileTransferController}
+   * @param {DataTransfer} dataTransfer DataTransfer from the event.
+   * @param {string} effectAllowed Value must be valid for the
+   *     |dataTransfer.effectAllowed| property ('move', 'copy', 'copyMove').
+   */
+  cutOrCopy_: function(dataTransfer, effectAllowed) {
+    // Tag to check it's filemanager data.
+    dataTransfer.setData('fs/tag', 'filemanager-data');
+    dataTransfer.setData('fs/sourceRoot',
+                         this.directoryModel_.getCurrentRootPath());
+    var sourcePaths =
+        this.selectedEntries_.map(function(e) { return e.fullPath; });
+    dataTransfer.setData('fs/sources', sourcePaths.join('\n'));
+    dataTransfer.effectAllowed = effectAllowed;
+    dataTransfer.setData('fs/effectallowed', effectAllowed);
+
+    for (var i = 0; i < this.selectedFileObjects_.length; i++) {
+      dataTransfer.items.add(this.selectedFileObjects_[i]);
+    }
+  },
+
+  /**
+   * Extracts source root from the |dataTransfer| object.
+   *
+   * @this {FileTransferController}
+   * @param {DataTransfer} dataTransfer DataTransfer object from the event.
+   * @return {string} Path or empty string (if unknown).
+   */
+  getSourceRoot_: function(dataTransfer) {
+    var sourceRoot = dataTransfer.getData('fs/sourceRoot');
+    if (sourceRoot)
+      return sourceRoot;
+
+    // |dataTransfer| in protected mode.
+    if (window[DRAG_AND_DROP_GLOBAL_DATA])
+      return window[DRAG_AND_DROP_GLOBAL_DATA].sourceRoot;
+
+    // Dragging from other tabs/windows.
+    var views = chrome && chrome.extension ? chrome.extension.getViews() : [];
+    for (var i = 0; i < views.length; i++) {
+      if (views[i][DRAG_AND_DROP_GLOBAL_DATA])
+        return views[i][DRAG_AND_DROP_GLOBAL_DATA].sourceRoot;
+    }
+
+    // Unknown source.
+    return '';
+  },
+
+  /**
+   * Queue up a file copy operation based on the current system clipboard.
+   *
+   * @this {FileTransferController}
+   * @param {DataTransfer} dataTransfer System data transfer object.
+   * @param {string=} opt_destinationPath Paste destination.
+   * @param {string=} opt_effect Desired drop/paste effect. Could be
+   *     'move'|'copy' (default is copy). Ignored if conflicts with
+   *     |dataTransfer.effectAllowed|.
+   * @return {string} Either "copy" or "move".
+   */
+  paste: function(dataTransfer, opt_destinationPath, opt_effect) {
+    var sourcePaths = (dataTransfer.getData('fs/sources') || '').split('\n');
+    var destinationPath = opt_destinationPath ||
+                          this.currentDirectoryContentPath;
+    // effectAllowed set in copy/paste handlers stay uninitialized. DnD handlers
+    // work fine.
+    var effectAllowed = dataTransfer.effectAllowed != 'uninitialized' ?
+        dataTransfer.effectAllowed : dataTransfer.getData('fs/effectallowed');
+    var toMove = effectAllowed == 'move' ||
+        (effectAllowed == 'copyMove' && opt_effect == 'move');
+
+    // Start the pasting operation.
+    this.fileOperationManager_.paste(sourcePaths, destinationPath, toMove);
+    return toMove ? 'move' : 'copy';
+  },
+
+  /**
+   * Preloads an image thumbnail for the specified file entry.
+   *
+   * @this {FileTransferController}
+   * @param {Entry} entry Entry to preload a thumbnail for.
+   */
+  preloadThumbnailImage_: function(entry) {
+    var imageUrl = entry.toURL();
+    var metadataTypes = 'thumbnail|filesystem';
+    var thumbnailContainer = this.document_.createElement('div');
+    this.preloadedThumbnailImageNode_ = thumbnailContainer;
+    this.preloadedThumbnailImageNode_.className = 'img-container';
+    this.metadataCache_.get(
+        imageUrl,
+        metadataTypes,
+        function(metadata) {
+          new ThumbnailLoader(imageUrl,
+                              ThumbnailLoader.LoaderType.IMAGE,
+                              metadata).
+              load(thumbnailContainer,
+                   ThumbnailLoader.FillMode.FILL);
+        }.bind(this));
+  },
+
+  /**
+   * Renders a drag-and-drop thumbnail.
+   *
+   * @this {FileTransferController}
+   * @return {HTMLElement} Element containing the thumbnail.
+   */
+  renderThumbnail_: function() {
+    var length = this.selectedEntries_.length;
+
+    var container = this.document_.querySelector('#drag-container');
+    var contents = this.document_.createElement('div');
+    contents.className = 'drag-contents';
+    container.appendChild(contents);
+
+    var thumbnailImage;
+    if (this.preloadedThumbnailImageNode_)
+      thumbnailImage = this.preloadedThumbnailImageNode_.querySelector('img');
+
+    // Option 1. Multiple selection, render only a label.
+    if (length > 1) {
+      var label = this.document_.createElement('div');
+      label.className = 'label';
+      label.textContent = strf('DRAGGING_MULTIPLE_ITEMS', length);
+      contents.appendChild(label);
+      return container;
+    }
+
+    // Option 2. Thumbnail image available, then render it without
+    // a label.
+    if (thumbnailImage) {
+      thumbnailImage.classList.add('drag-thumbnail');
+      contents.classList.add('for-image');
+      contents.appendChild(this.preloadedThumbnailImageNode_);
+      return container;
+    }
+
+    // Option 3. Thumbnail not available. Render an icon and a label.
+    var entry = this.selectedEntries_[0];
+    var icon = this.document_.createElement('div');
+    icon.className = 'detail-icon';
+    icon.setAttribute('file-type-icon', FileType.getIcon(entry));
+    contents.appendChild(icon);
+    var label = this.document_.createElement('div');
+    label.className = 'label';
+    label.textContent = entry.name;
+    contents.appendChild(label);
+    return container;
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list Drop target list
+   * @param {Event} event A dragstart event of DOM.
+   */
+  onDragStart_: function(list, event) {
+    // If a user is touching, Files.app does not receive drag operations.
+    if (this.touching_) {
+      event.preventDefault();
+      return;
+    }
+
+    // Check if a drag selection should be initiated or not.
+    if (list.shouldStartDragSelection(event)) {
+      this.dragSelector_.startDragSelection(list, event);
+      return;
+    }
+
+    // Nothing selected.
+    if (!this.selectedEntries_.length) {
+      event.preventDefault();
+      return;
+    }
+
+    var dt = event.dataTransfer;
+
+    if (this.canCopyOrDrag_(dt)) {
+      if (this.canCutOrDrag_(dt))
+        this.cutOrCopy_(dt, 'copyMove');
+      else
+        this.cutOrCopy_(dt, 'copy');
+    } else {
+      event.preventDefault();
+      return;
+    }
+
+    var dragThumbnail = this.renderThumbnail_();
+    dt.setDragImage(dragThumbnail, 1000, 1000);
+
+    window[DRAG_AND_DROP_GLOBAL_DATA] = {
+      sourceRoot: this.directoryModel_.getCurrentRootPath()
+    };
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list Drop target list.
+   * @param {Event} event A dragend event of DOM.
+   */
+  onDragEnd_: function(list, event) {
+    var container = this.document_.querySelector('#drag-container');
+    container.textContent = '';
+    this.clearDropTarget_();
+    delete window[DRAG_AND_DROP_GLOBAL_DATA];
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {boolean} onlyIntoDirectories True if the drag is only into
+   *     directories.
+   * @param {cr.ui.List} list Drop target list.
+   * @param {Event} event A dragover event of DOM.
+   */
+  onDragOver_: function(onlyIntoDirectories, list, event) {
+    event.preventDefault();
+    var path = this.destinationPath_ ||
+        (!onlyIntoDirectories && this.currentDirectoryContentPath);
+    event.dataTransfer.dropEffect = this.selectDropEffect_(event, path);
+    event.preventDefault();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list Drop target list.
+   * @param {Event} event A dragenter event of DOM.
+   */
+  onDragEnterFileList_: function(list, event) {
+    event.preventDefault();  // Required to prevent the cursor flicker.
+    this.lastEnteredTarget_ = event.target;
+    var item = list.getListItemAncestor(event.target);
+    item = item && list.isItem(item) ? item : null;
+    if (item == this.dropTarget_)
+      return;
+
+    var entry = item && list.dataModel.item(item.listIndex);
+    if (entry) {
+      this.setDropTarget_(item, entry.isDirectory, event.dataTransfer,
+          entry.fullPath);
+    } else {
+      this.clearDropTarget_();
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {DirectoryTree} tree Drop target tree.
+   * @param {Event} event A dragenter event of DOM.
+   */
+  onDragEnterTree_: function(tree, event) {
+    event.preventDefault();  // Required to prevent the cursor flicker.
+    this.lastEnteredTarget_ = event.target;
+    var item = event.target;
+    while (item && !(item instanceof DirectoryItem)) {
+      item = item.parentNode;
+    }
+
+    if (item == this.dropTarget_)
+      return;
+
+    var entry = item && item.entry;
+    if (entry) {
+      this.setDropTarget_(item, entry.isDirectory, event.dataTransfer,
+          entry.fullPath);
+    } else {
+      this.clearDropTarget_();
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {NavigationList} list Drop target list.
+   * @param {Event} event A dragenter event of DOM.
+   */
+  onDragEnterVolumesList_: function(list, event) {
+    event.preventDefault();  // Required to prevent the cursor flicker.
+    this.lastEnteredTarget_ = event.target;
+    var item = list.getListItemAncestor(event.target);
+    item = item && list.isItem(item) ? item : null;
+    if (item == this.dropTarget_)
+      return;
+
+    var path = item && list.dataModel.item(item.listIndex).path;
+    if (path)
+      this.setDropTarget_(item, true /* directory */, event.dataTransfer, path);
+    else
+      this.clearDropTarget_();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {cr.ui.List} list Drop target list.
+   * @param {Event} event A dragleave event of DOM.
+   */
+  onDragLeave_: function(list, event) {
+    // If mouse moves from one element to another the 'dragenter'
+    // event for the new element comes before the 'dragleave' event for
+    // the old one. In this case event.target != this.lastEnteredTarget_
+    // and handler of the 'dragenter' event has already caried of
+    // drop target. So event.target == this.lastEnteredTarget_
+    // could only be if mouse goes out of listened element.
+    if (event.target == this.lastEnteredTarget_) {
+      this.clearDropTarget_();
+      this.lastEnteredTarget_ = null;
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {boolean} onlyIntoDirectories True if the drag is only into
+   *     directories.
+   * @param {Event} event A dragleave event of DOM.
+   */
+  onDrop_: function(onlyIntoDirectories, event) {
+    if (onlyIntoDirectories && !this.dropTarget_)
+      return;
+    var destinationPath = this.destinationPath_ ||
+                          this.currentDirectoryContentPath;
+    if (!this.canPasteOrDrop_(event.dataTransfer, destinationPath))
+      return;
+    event.preventDefault();
+    this.paste(event.dataTransfer, destinationPath,
+               this.selectDropEffect_(event, destinationPath));
+    this.clearDropTarget_();
+  },
+
+  /**
+   * Sets the drop target.
+   * @this {FileTransferController}
+   * @param {Element} domElement Target of the drop.
+   * @param {boolean} isDirectory If the target is a directory.
+   * @param {DataTransfer} dataTransfer Data transfer object.
+   * @param {string} destinationPath Destination path.
+   */
+  setDropTarget_: function(domElement, isDirectory, dataTransfer,
+                           destinationPath) {
+    if (this.dropTarget_ == domElement)
+      return;
+
+    // Remove the old drop target.
+    this.clearDropTarget_();
+
+    // Set the new drop target.
+    this.dropTarget_ = domElement;
+
+    if (!domElement ||
+        !isDirectory ||
+        !this.canPasteOrDrop_(dataTransfer, destinationPath)) {
+      return;
+    }
+
+    // Add accept class if the domElement can accept the drag.
+    domElement.classList.add('accepts');
+    this.destinationPath_ = destinationPath;
+
+    // Start timer changing the directory.
+    this.navigateTimer_ = setTimeout(function() {
+      if (domElement instanceof DirectoryItem)
+        // Do custom action.
+        (/** @type {DirectoryItem} */ domElement).doDropTargetAction();
+      this.directoryModel_.changeDirectory(destinationPath);
+    }.bind(this), 2000);
+  },
+
+  /**
+   * Handles touch start.
+   */
+  onTouchStart_: function() {
+    this.touching_ = true;
+  },
+
+  /**
+   * Handles touch end.
+   */
+  onTouchEnd_: function(event) {
+    if (event.touches.length === 0)
+      this.touching_ = false;
+  },
+
+  /**
+   * Clears the drop target.
+   * @this {FileTransferController}
+   */
+  clearDropTarget_: function() {
+    if (this.dropTarget_ && this.dropTarget_.classList.contains('accepts'))
+      this.dropTarget_.classList.remove('accepts');
+    this.dropTarget_ = null;
+    this.destinationPath_ = null;
+    if (this.navigateTimer_ !== undefined) {
+      clearTimeout(this.navigateTimer_);
+      this.navigateTimer_ = undefined;
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {boolean} Returns false if {@code <input type="text">} element is
+   *     currently active. Otherwise, returns true.
+   */
+  isDocumentWideEvent_: function() {
+    return this.document_.activeElement.nodeName.toLowerCase() != 'input' ||
+        this.document_.activeElement.type.toLowerCase() != 'text';
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onCopy_: function(event) {
+    if (!this.isDocumentWideEvent_() ||
+        !this.canCopyOrDrag_()) {
+      return;
+    }
+    event.preventDefault();
+    this.cutOrCopy_(event.clipboardData, 'copy');
+    this.notify_('selection-copied');
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onBeforeCopy_: function(event) {
+    if (!this.isDocumentWideEvent_())
+      return;
+
+    // queryCommandEnabled returns true if event.defaultPrevented is true.
+    if (this.canCopyOrDrag_())
+      event.preventDefault();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {boolean} Returns true if some files are selected and all the file
+   *     on drive is available to be copied. Otherwise, returns false.
+   */
+  canCopyOrDrag_: function() {
+    if (this.isOnDrive &&
+        this.directoryModel_.isDriveOffline() &&
+        !this.allDriveFilesAvailable)
+      return false;
+    return this.selectedEntries_.length > 0;
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onCut_: function(event) {
+    if (!this.isDocumentWideEvent_() ||
+        !this.canCutOrDrag_()) {
+      return;
+    }
+    event.preventDefault();
+    this.cutOrCopy_(event.clipboardData, 'move');
+    this.notify_('selection-cut');
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onBeforeCut_: function(event) {
+    if (!this.isDocumentWideEvent_())
+      return;
+    // queryCommandEnabled returns true if event.defaultPrevented is true.
+    if (this.canCutOrDrag_())
+      event.preventDefault();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {boolean} Returns true if some files are selected and all the file
+   *     on drive is available to be cut. Otherwise, returns false.
+   */
+  canCutOrDrag_: function() {
+    return !this.readonly && this.canCopyOrDrag_();
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onPaste_: function(event) {
+    // Need to update here since 'beforepaste' doesn't fire.
+    if (!this.isDocumentWideEvent_() ||
+        !this.canPasteOrDrop_(event.clipboardData,
+                              this.currentDirectoryContentPath)) {
+      return;
+    }
+    event.preventDefault();
+    var effect = this.paste(event.clipboardData);
+
+    // On cut, we clear the clipboard after the file is pasted/moved so we don't
+    // try to move/delete the original file again.
+    if (effect == 'move') {
+      this.simulateCommand_('cut', function(event) {
+        event.preventDefault();
+        event.clipboardData.setData('fs/clear', '');
+      });
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onBeforePaste_: function(event) {
+    if (!this.isDocumentWideEvent_())
+      return;
+    // queryCommandEnabled returns true if event.defaultPrevented is true.
+    if (this.canPasteOrDrop_(event.clipboardData,
+                             this.currentDirectoryContentPath)) {
+      event.preventDefault();
+    }
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @param {DataTransfer} dataTransfer Data transfer object.
+   * @param {string?} destinationPath Destination path.
+   * @return {boolean} Returns true if items stored in {@code dataTransfer} can
+   *     be pasted to {@code destinationPath}. Otherwise, returns false.
+   */
+  canPasteOrDrop_: function(dataTransfer, destinationPath) {
+    if (!destinationPath) {
+      return false;
+    }
+    if (this.directoryModel_.isPathReadOnly(destinationPath)) {
+      return false;
+    }
+    if (!dataTransfer.types || dataTransfer.types.indexOf('fs/tag') == -1) {
+      return false;  // Unsupported type of content.
+    }
+    if (dataTransfer.getData('fs/tag') == '') {
+      // Data protected. Other checks are not possible but it makes sense to
+      // let the user try.
+      return true;
+    }
+
+    var directories = dataTransfer.getData('fs/directories').split('\n').
+                      filter(function(d) { return d != ''; });
+
+    for (var i = 0; i < directories.length; i++) {
+      if (destinationPath.substr(0, directories[i].length) == directories[i])
+        return false;  // recursive paste.
+    }
+
+    return true;
+  },
+
+  /**
+   * Execute paste command.
+   *
+   * @this {FileTransferController}
+   * @return {boolean}  Returns true, the paste is success. Otherwise, returns
+   *     false.
+   */
+  queryPasteCommandEnabled: function() {
+    if (!this.isDocumentWideEvent_()) {
+      return false;
+    }
+
+    // HACK(serya): return this.document_.queryCommandEnabled('paste')
+    // should be used.
+    var result;
+    this.simulateCommand_('paste', function(event) {
+      result = this.canPasteOrDrop_(event.clipboardData,
+                                    this.currentDirectoryContentPath);
+    }.bind(this));
+    return result;
+  },
+
+  /**
+   * Allows to simulate commands to get access to clipboard.
+   *
+   * @this {FileTransferController}
+   * @param {string} command 'copy', 'cut' or 'paste'.
+   * @param {function} handler Event handler.
+   */
+  simulateCommand_: function(command, handler) {
+    var iframe = this.document_.querySelector('#command-dispatcher');
+    var doc = iframe.contentDocument;
+    doc.addEventListener(command, handler);
+    doc.execCommand(command);
+    doc.removeEventListener(command, handler);
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  onSelectionChanged_: function(event) {
+    var entries = this.selectedEntries_;
+    var files = this.selectedFileObjects_ = [];
+    this.preloadedThumbnailImageNode_ = null;
+
+    var fileEntries = [];
+    for (var i = 0; i < entries.length; i++) {
+      if (entries[i].isFile)
+        fileEntries.push(entries[i]);
+    }
+
+    if (entries.length == 1) {
+      // For single selection, the dragged element is created in advance,
+      // otherwise an image may not be loaded at the time the 'dragstart' event
+      // comes.
+      this.preloadThumbnailImage_(entries[0]);
+    }
+
+    // File object must be prepeared in advance for clipboard operations
+    // (copy, paste and drag). DataTransfer object closes for write after
+    // returning control from that handlers so they may not have
+    // asynchronous operations.
+    var prepareFileObjects = function() {
+      for (var i = 0; i < fileEntries.length; i++) {
+        fileEntries[i].file(function(file) { files.push(file); });
+      }
+    };
+
+    if (this.isOnDrive) {
+      this.allDriveFilesAvailable = false;
+      var urls = entries.map(function(e) { return e.toURL() });
+      this.metadataCache_.get(
+          urls, 'drive', function(props) {
+        // We consider directories not available offline for the purposes of
+        // file transfer since we cannot afford to recursive traversal.
+        this.allDriveFilesAvailable =
+            entries.filter(function(e) {return e.isDirectory}).length == 0 &&
+            props.filter(function(p) {return !p.availableOffline}).length == 0;
+        // |Copy| is the only menu item affected by allDriveFilesAvailable.
+        // It could be open right now, update its UI.
+        this.copyCommand_.disabled = !this.canCopyOrDrag_();
+
+        if (this.allDriveFilesAvailable)
+          prepareFileObjects();
+      }.bind(this));
+    } else {
+      prepareFileObjects();
+    }
+  },
+
+  /**
+   * Path of directory that is displaying now.
+   * If search result is displaying now, this is null.
+   * @this {FileTransferController}
+   * @return {string} Path of directry that is displaying now.
+   */
+  get currentDirectoryContentPath() {
+    return this.directoryModel_.isSearching() ?
+        null : this.directoryModel_.getCurrentDirPath();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {boolean} True if the current directory is read only.
+   */
+  get readonly() {
+    return this.directoryModel_.isReadOnly();
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {boolean} True if the current directory is on Drive.
+   */
+  get isOnDrive() {
+    return PathUtil.isDriveBasedPath(this.directoryModel_.getCurrentRootPath());
+  },
+
+  /**
+   * @this {FileTransferController}
+   */
+  notify_: function(eventName) {
+    var self = this;
+    // Set timeout to avoid recursive events.
+    setTimeout(function() {
+      cr.dispatchSimpleEvent(self, eventName);
+    }, 0);
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {Array.<Entry>} Array of the selected entries.
+   */
+  get selectedEntries_() {
+    var list = this.directoryModel_.getFileList();
+    var selectedIndexes = this.directoryModel_.getFileListSelection().
+                               selectedIndexes;
+    var entries = selectedIndexes.map(function(index) {
+      return list.item(index);
+    });
+
+    // TODO(serya): Diagnostics for http://crbug/129642
+    if (entries.indexOf(undefined) != -1) {
+      var index = entries.indexOf(undefined);
+      entries = entries.filter(function(e) { return !!e; });
+      console.error('Invalid selection found: list items: ', list.length,
+                    'wrong indexe value: ', selectedIndexes[index],
+                    'Stack trace: ', new Error().stack);
+    }
+    return entries;
+  },
+
+  /**
+   * @this {FileTransferController}
+   * @return {string}  Returns the appropriate drop query type ('none', 'move'
+   *     or copy') to the current modifiers status and the destination.
+   */
+  selectDropEffect_: function(event, destinationPath) {
+    if (!destinationPath ||
+        this.directoryModel_.isPathReadOnly(destinationPath))
+      return 'none';
+    if (event.dataTransfer.effectAllowed == 'copyMove' &&
+        this.getSourceRoot_(event.dataTransfer) ==
+            PathUtil.getRootPath(destinationPath) &&
+        !event.ctrlKey) {
+      return 'move';
+    }
+    if (event.dataTransfer.effectAllowed == 'copyMove' &&
+        event.shiftKey) {
+      return 'move';
+    }
+    return 'copy';
+  },
+};
diff --git a/chrome/browser/resources/file_manager/js/file_type.js b/chrome/browser/resources/file_manager/foreground/js/file_type.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/file_type.js
rename to chrome/browser/resources/file_manager/foreground/js/file_type.js
diff --git a/chrome/browser/resources/file_manager/js/file_watcher.js b/chrome/browser/resources/file_manager/foreground/js/file_watcher.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/file_watcher.js
rename to chrome/browser/resources/file_manager/foreground/js/file_watcher.js
diff --git a/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js b/chrome/browser/resources/file_manager/foreground/js/folder_shortcuts_data_model.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
rename to chrome/browser/resources/file_manager/foreground/js/folder_shortcuts_data_model.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/commands.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/commands.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/commands.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/commands.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/exif_encoder.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/exif_encoder.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/exif_encoder.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/exif_encoder.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/filter.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/filter.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/filter.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/filter.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_adjust.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_adjust.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_adjust.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_adjust.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_buffer.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_buffer.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_buffer.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_buffer.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js
new file mode 100644
index 0000000..2107388
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js
@@ -0,0 +1,1175 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * ImageEditor is the top level object that holds together and connects
+ * everything needed for image editing.
+ *
+ * @param {Viewport} viewport The viewport.
+ * @param {ImageView} imageView The ImageView containing the images to edit.
+ * @param {ImageEditor.Prompt} prompt Prompt instance.
+ * @param {Object} DOMContainers Various DOM containers required for the editor.
+ * @param {Array.<ImageEditor.Mode>} modes Available editor modes.
+ * @param {function} displayStringFunction String formatting function.
+ * @param {function()} onToolsVisibilityChanged Callback to be called, when
+ *     some of the UI elements have been dimmed or revealed.
+ * @constructor
+ */
+function ImageEditor(
+    viewport, imageView, prompt, DOMContainers, modes, displayStringFunction,
+    onToolsVisibilityChanged) {
+  this.rootContainer_ = DOMContainers.root;
+  this.container_ = DOMContainers.image;
+  this.modes_ = modes;
+  this.displayStringFunction_ = displayStringFunction;
+  this.onToolsVisibilityChanged_ = onToolsVisibilityChanged;
+
+  ImageUtil.removeChildren(this.container_);
+
+  var document = this.container_.ownerDocument;
+
+  this.viewport_ = viewport;
+  this.viewport_.sizeByFrame(this.container_);
+
+  this.buffer_ = new ImageBuffer();
+  this.viewport_.addRepaintCallback(this.buffer_.draw.bind(this.buffer_));
+
+  this.imageView_ = imageView;
+  this.imageView_.addContentCallback(this.onContentUpdate_.bind(this));
+  this.buffer_.addOverlay(this.imageView_);
+
+  this.panControl_ = new ImageEditor.MouseControl(
+      this.rootContainer_, this.container_, this.getBuffer());
+
+  this.panControl_.setDoubleTapCallback(this.onDoubleTap_.bind(this));
+
+  this.mainToolbar_ = new ImageEditor.Toolbar(
+      DOMContainers.toolbar, displayStringFunction);
+
+  this.modeToolbar_ = new ImageEditor.Toolbar(
+      DOMContainers.mode, displayStringFunction,
+      this.onOptionsChange.bind(this));
+
+  this.prompt_ = prompt;
+
+  this.createToolButtons();
+
+  this.commandQueue_ = null;
+}
+
+/**
+ * @return {boolean} True if no user commands are to be accepted.
+ */
+ImageEditor.prototype.isLocked = function() {
+  return !this.commandQueue_ || this.commandQueue_.isBusy();
+};
+
+/**
+ * @return {boolean} True if the command queue is busy.
+ */
+ImageEditor.prototype.isBusy = function() {
+  return this.commandQueue_ && this.commandQueue_.isBusy();
+};
+
+/**
+ * Reflect the locked state of the editor in the UI.
+ * @param {boolean} on True if locked.
+ */
+ImageEditor.prototype.lockUI = function(on) {
+  ImageUtil.setAttribute(this.rootContainer_, 'locked', on);
+};
+
+/**
+ * Report the tool use to the metrics subsystem.
+ * @param {string} name Action name.
+ */
+ImageEditor.prototype.recordToolUse = function(name) {
+  ImageUtil.metrics.recordEnum(
+      ImageUtil.getMetricName('Tool'), name, this.actionNames_);
+};
+
+/**
+ * Content update handler.
+ * @private
+ */
+ImageEditor.prototype.onContentUpdate_ = function() {
+  for (var i = 0; i != this.modes_.length; i++) {
+    var mode = this.modes_[i];
+    ImageUtil.setAttribute(mode.button_, 'disabled', !mode.isApplicable());
+  }
+};
+
+/**
+ * Open the editing session for a new image.
+ *
+ * @param {string} url Image url.
+ * @param {Object} metadata Metadata.
+ * @param {Object} effect Transition effect object.
+ * @param {function(function)} saveFunction Image save function.
+ * @param {function} displayCallback Display callback.
+ * @param {function} loadCallback Load callback.
+ */
+ImageEditor.prototype.openSession = function(
+    url, metadata, effect, saveFunction, displayCallback, loadCallback) {
+  if (this.commandQueue_)
+    throw new Error('Session not closed');
+
+  this.lockUI(true);
+
+  var self = this;
+  this.imageView_.load(
+      url, metadata, effect, displayCallback, function(loadType, delay, error) {
+    self.lockUI(false);
+    self.commandQueue_ = new CommandQueue(
+        self.container_.ownerDocument,
+        self.imageView_.getCanvas(),
+        saveFunction);
+    self.commandQueue_.attachUI(
+        self.getImageView(), self.getPrompt(), self.lockUI.bind(self));
+    self.updateUndoRedo();
+    loadCallback(loadType, delay, error);
+  });
+};
+
+/**
+ * Close the current image editing session.
+ * @param {function} callback Callback.
+ */
+ImageEditor.prototype.closeSession = function(callback) {
+  this.getPrompt().hide();
+  if (this.imageView_.isLoading()) {
+    if (this.commandQueue_) {
+      console.warn('Inconsistent image editor state');
+      this.commandQueue_ = null;
+    }
+    this.imageView_.cancelLoad();
+    this.lockUI(false);
+    callback();
+    return;
+  }
+  if (!this.commandQueue_) {
+    // Session is already closed.
+    callback();
+    return;
+  }
+
+  this.executeWhenReady(callback);
+  this.commandQueue_.close();
+  this.commandQueue_ = null;
+};
+
+/**
+ * Commit the current operation and execute the action.
+ *
+ * @param {function} callback Callback.
+ */
+ImageEditor.prototype.executeWhenReady = function(callback) {
+  if (this.commandQueue_) {
+    this.leaveModeGently();
+    this.commandQueue_.executeWhenReady(callback);
+  } else {
+    if (!this.imageView_.isLoading())
+      console.warn('Inconsistent image editor state');
+    callback();
+  }
+};
+
+/**
+ * @return {boolean} True if undo queue is not empty.
+ */
+ImageEditor.prototype.canUndo = function() {
+  return this.commandQueue_ && this.commandQueue_.canUndo();
+};
+
+/**
+ * Undo the recently executed command.
+ */
+ImageEditor.prototype.undo = function() {
+  if (this.isLocked()) return;
+  this.recordToolUse('undo');
+
+  // First undo click should dismiss the uncommitted modifications.
+  if (this.currentMode_ && this.currentMode_.isUpdated()) {
+    this.currentMode_.reset();
+    return;
+  }
+
+  this.getPrompt().hide();
+  this.leaveMode(false);
+  this.commandQueue_.undo();
+  this.updateUndoRedo();
+};
+
+/**
+ * Redo the recently un-done command.
+ */
+ImageEditor.prototype.redo = function() {
+  if (this.isLocked()) return;
+  this.recordToolUse('redo');
+  this.getPrompt().hide();
+  this.leaveMode(false);
+  this.commandQueue_.redo();
+  this.updateUndoRedo();
+};
+
+/**
+ * Update Undo/Redo buttons state.
+ */
+ImageEditor.prototype.updateUndoRedo = function() {
+  var canUndo = this.commandQueue_ && this.commandQueue_.canUndo();
+  var canRedo = this.commandQueue_ && this.commandQueue_.canRedo();
+  ImageUtil.setAttribute(this.undoButton_, 'disabled', !canUndo);
+  this.redoButton_.hidden = !canRedo;
+};
+
+/**
+ * @return {HTMLCanvasElement} The current image canvas.
+ */
+ImageEditor.prototype.getCanvas = function() {
+  return this.getImageView().getCanvas();
+};
+
+/**
+ * @return {ImageBuffer} ImageBuffer instance.
+ */
+ImageEditor.prototype.getBuffer = function() { return this.buffer_ };
+
+/**
+ * @return {ImageView} ImageView instance.
+ */
+ImageEditor.prototype.getImageView = function() { return this.imageView_ };
+
+/**
+ * @return {Viewport} Viewport instance.
+ */
+ImageEditor.prototype.getViewport = function() { return this.viewport_ };
+
+/**
+ * @return {ImageEditor.Prompt} Prompt instance.
+ */
+ImageEditor.prototype.getPrompt = function() { return this.prompt_ };
+
+/**
+ * Handle the toolbar controls update.
+ * @param {Object} options A map of options.
+ */
+ImageEditor.prototype.onOptionsChange = function(options) {
+  ImageUtil.trace.resetTimer('update');
+  if (this.currentMode_) {
+    this.currentMode_.update(options);
+  }
+  ImageUtil.trace.reportTimer('update');
+};
+
+/**
+ * ImageEditor.Mode represents a modal state dedicated to a specific operation.
+ * Inherits from ImageBuffer. Overlay to simplify the drawing of mode-specific
+ * tools.
+ *
+ * @param {string} name The mode name.
+ * @param {string} title The mode title.
+ * @constructor
+ */
+
+ImageEditor.Mode = function(name, title) {
+  this.name = name;
+  this.title = title;
+  this.message_ = 'GALLERY_ENTER_WHEN_DONE';
+};
+
+ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype };
+
+/**
+ * @return {Viewport} Viewport instance.
+ */
+ImageEditor.Mode.prototype.getViewport = function() { return this.viewport_ };
+
+/**
+ * @return {ImageView} ImageView instance.
+ */
+ImageEditor.Mode.prototype.getImageView = function() { return this.imageView_ };
+
+/**
+ * @return {string} The mode-specific message to be displayed when entering.
+ */
+ImageEditor.Mode.prototype.getMessage = function() { return this.message_ };
+
+/**
+ * @return {boolean} True if the mode is applicable in the current context.
+ */
+ImageEditor.Mode.prototype.isApplicable = function() { return true };
+
+/**
+ * Called once after creating the mode button.
+ *
+ * @param {ImageEditor} editor The editor instance.
+ * @param {HTMLElement} button The mode button.
+ */
+
+ImageEditor.Mode.prototype.bind = function(editor, button) {
+  this.editor_ = editor;
+  this.editor_.registerAction_(this.name);
+  this.button_ = button;
+  this.viewport_ = editor.getViewport();
+  this.imageView_ = editor.getImageView();
+};
+
+/**
+ * Called before entering the mode.
+ */
+ImageEditor.Mode.prototype.setUp = function() {
+  this.editor_.getBuffer().addOverlay(this);
+  this.updated_ = false;
+};
+
+/**
+ * Create mode-specific controls here.
+ * @param {ImageEditor.Toolbar} toolbar The toolbar to populate.
+ */
+ImageEditor.Mode.prototype.createTools = function(toolbar) {};
+
+/**
+ * Called before exiting the mode.
+ */
+ImageEditor.Mode.prototype.cleanUpUI = function() {
+  this.editor_.getBuffer().removeOverlay(this);
+};
+
+/**
+ * Called after exiting the mode.
+ */
+ImageEditor.Mode.prototype.cleanUpCaches = function() {};
+
+/**
+ * Called when any of the controls changed its value.
+ * @param {Object} options A map of options.
+ */
+ImageEditor.Mode.prototype.update = function(options) {
+  this.markUpdated();
+};
+
+/**
+ * Mark the editor mode as updated.
+ */
+ImageEditor.Mode.prototype.markUpdated = function() {
+  this.updated_ = true;
+};
+
+/**
+ * @return {boolean} True if the mode controls changed.
+ */
+ImageEditor.Mode.prototype.isUpdated = function() { return this.updated_ };
+
+/**
+ * Resets the mode to a clean state.
+ */
+ImageEditor.Mode.prototype.reset = function() {
+  this.editor_.modeToolbar_.reset();
+  this.updated_ = false;
+};
+
+/**
+ * One-click editor tool, requires no interaction, just executes the command.
+ *
+ * @param {string} name The mode name.
+ * @param {string} title The mode title.
+ * @param {Command} command The command to execute on click.
+ * @constructor
+ */
+ImageEditor.Mode.OneClick = function(name, title, command) {
+  ImageEditor.Mode.call(this, name, title);
+  this.instant = true;
+  this.command_ = command;
+};
+
+ImageEditor.Mode.OneClick.prototype = {__proto__: ImageEditor.Mode.prototype};
+
+/**
+ * @return {Command} command.
+ */
+ImageEditor.Mode.OneClick.prototype.getCommand = function() {
+  return this.command_;
+};
+
+/**
+ * Register the action name. Required for metrics reporting.
+ * @param {string} name Button name.
+ * @private
+ */
+ImageEditor.prototype.registerAction_ = function(name) {
+  this.actionNames_.push(name);
+};
+
+/**
+ * Populate the toolbar.
+ */
+ImageEditor.prototype.createToolButtons = function() {
+  this.mainToolbar_.clear();
+  this.actionNames_ = [];
+
+  var self = this;
+  function createButton(name, title, handler) {
+    return self.mainToolbar_.addButton(name,
+                                       title,
+                                       handler,
+                                       name /* opt_className */);
+  }
+
+  for (var i = 0; i != this.modes_.length; i++) {
+    var mode = this.modes_[i];
+    mode.bind(this, createButton(mode.name,
+                                 mode.title,
+                                 this.enterMode.bind(this, mode)));
+  }
+
+  this.undoButton_ = createButton('undo',
+                                  'GALLERY_UNDO',
+                                  this.undo.bind(this));
+  this.registerAction_('undo');
+
+  this.redoButton_ = createButton('redo',
+                                  'GALLERY_REDO',
+                                  this.redo.bind(this));
+  this.registerAction_('redo');
+};
+
+/**
+ * @return {ImageEditor.Mode} The current mode.
+ */
+ImageEditor.prototype.getMode = function() { return this.currentMode_ };
+
+/**
+ * The user clicked on the mode button.
+ *
+ * @param {ImageEditor.Mode} mode The new mode.
+ */
+ImageEditor.prototype.enterMode = function(mode) {
+  if (this.isLocked()) return;
+
+  if (this.currentMode_ == mode) {
+    // Currently active editor tool clicked, commit if modified.
+    this.leaveMode(this.currentMode_.updated_);
+    return;
+  }
+
+  this.recordToolUse(mode.name);
+
+  this.leaveModeGently();
+  // The above call could have caused a commit which might have initiated
+  // an asynchronous command execution. Wait for it to complete, then proceed
+  // with the mode set up.
+  this.commandQueue_.executeWhenReady(this.setUpMode_.bind(this, mode));
+};
+
+/**
+ * Set up the new editing mode.
+ *
+ * @param {ImageEditor.Mode} mode The mode.
+ * @private
+ */
+ImageEditor.prototype.setUpMode_ = function(mode) {
+  this.currentTool_ = mode.button_;
+
+  ImageUtil.setAttribute(this.currentTool_, 'pressed', true);
+
+  this.currentMode_ = mode;
+  this.currentMode_.setUp();
+
+  if (this.currentMode_.instant) {  // Instant tool.
+    this.leaveMode(true);
+    return;
+  }
+
+  this.getPrompt().show(this.currentMode_.getMessage());
+
+  this.modeToolbar_.clear();
+  this.currentMode_.createTools(this.modeToolbar_);
+  this.modeToolbar_.show(true);
+};
+
+/**
+ * The user clicked on 'OK' or 'Cancel' or on a different mode button.
+ * @param {boolean} commit True if commit is required.
+ */
+ImageEditor.prototype.leaveMode = function(commit) {
+  if (!this.currentMode_) return;
+
+  if (!this.currentMode_.instant) {
+    this.getPrompt().hide();
+  }
+
+  this.modeToolbar_.show(false);
+
+  this.currentMode_.cleanUpUI();
+  if (commit) {
+    var self = this;
+    var command = this.currentMode_.getCommand();
+    if (command) {  // Could be null if the user did not do anything.
+      this.commandQueue_.execute(command);
+      this.updateUndoRedo();
+    }
+  }
+  this.currentMode_.cleanUpCaches();
+  this.currentMode_ = null;
+
+  ImageUtil.setAttribute(this.currentTool_, 'pressed', false);
+  this.currentTool_ = null;
+};
+
+/**
+ * Leave the mode, commit only if required by the current mode.
+ */
+ImageEditor.prototype.leaveModeGently = function() {
+  this.leaveMode(this.currentMode_ &&
+                 this.currentMode_.updated_ &&
+                 this.currentMode_.implicitCommit);
+};
+
+/**
+ * Enter the editor mode with the given name.
+ *
+ * @param {string} name Mode name.
+ * @private
+ */
+ImageEditor.prototype.enterModeByName_ = function(name) {
+  for (var i = 0; i != this.modes_.length; i++) {
+    var mode = this.modes_[i];
+    if (mode.name == name) {
+      if (!mode.button_.hasAttribute('disabled'))
+        this.enterMode(mode);
+      return;
+    }
+  }
+  console.error('Mode "' + name + '" not found.');
+};
+
+/**
+ * Key down handler.
+ * @param {Event} event The keydown event.
+ * @return {boolean} True if handled.
+ */
+ImageEditor.prototype.onKeyDown = function(event) {
+  switch (util.getKeyModifiers(event) + event.keyIdentifier) {
+    case 'U+001B': // Escape
+    case 'Enter':
+      if (this.getMode()) {
+        this.leaveMode(event.keyIdentifier == 'Enter');
+        return true;
+      }
+      break;
+
+    case 'Ctrl-U+005A':  // Ctrl+Z
+      if (this.commandQueue_.canUndo()) {
+        this.undo();
+        return true;
+      }
+      break;
+
+    case 'Ctrl-U+0059':  // Ctrl+Y
+      if (this.commandQueue_.canRedo()) {
+        this.redo();
+        return true;
+      }
+      break;
+
+    case 'U+0041':  // 'a'
+      this.enterModeByName_('autofix');
+      return true;
+
+    case 'U+0042':  // 'b'
+      this.enterModeByName_('exposure');
+      return true;
+
+    case 'U+0043':  // 'c'
+      this.enterModeByName_('crop');
+      return true;
+
+    case 'U+004C':  // 'l'
+      this.enterModeByName_('rotate_left');
+      return true;
+
+    case 'U+0052':  // 'r'
+      this.enterModeByName_('rotate_right');
+      return true;
+
+  }
+  return false;
+};
+
+/**
+ * Double tap handler.
+ * @param {number} x X coordinate of the event.
+ * @param {number} y Y coordinate of the event.
+ * @private
+ */
+ImageEditor.prototype.onDoubleTap_ = function(x, y) {
+  if (this.getMode()) {
+    var action = this.buffer_.getDoubleTapAction(x, y);
+    if (action == ImageBuffer.DoubleTapAction.COMMIT)
+      this.leaveMode(true);
+    else if (action == ImageBuffer.DoubleTapAction.CANCEL)
+      this.leaveMode(false);
+  }
+};
+
+/**
+ * Hide the tools that overlap the given rectangular frame.
+ *
+ * @param {Rect} frame Hide the tool that overlaps this rect.
+ * @param {Rect} transparent But do not hide the tool that is completely inside
+ *                           this rect.
+ */
+ImageEditor.prototype.hideOverlappingTools = function(frame, transparent) {
+  var tools = this.rootContainer_.ownerDocument.querySelectorAll('.dimmable');
+  var changed = false;
+  for (var i = 0; i != tools.length; i++) {
+    var tool = tools[i];
+    var toolRect = tool.getBoundingClientRect();
+    var overlapping =
+        (frame && frame.intersects(toolRect)) &&
+        !(transparent && transparent.contains(toolRect));
+    if (overlapping && !tool.hasAttribute('dimmed') ||
+        !overlapping && tool.hasAttribute('dimmed')) {
+      ImageUtil.setAttribute(tool, 'dimmed', overlapping);
+      changed = true;
+    }
+  }
+  if (changed)
+    this.onToolsVisibilityChanged_();
+};
+
+/**
+ * A helper object for panning the ImageBuffer.
+ *
+ * @param {HTMLElement} rootContainer The top-level container.
+ * @param {HTMLElement} container The container for mouse events.
+ * @param {ImageBuffer} buffer Image buffer.
+ * @constructor
+ */
+ImageEditor.MouseControl = function(rootContainer, container, buffer) {
+  this.rootContainer_ = rootContainer;
+  this.container_ = container;
+  this.buffer_ = buffer;
+
+  var handlers = {
+    'touchstart': this.onTouchStart,
+    'touchend': this.onTouchEnd,
+    'touchcancel': this.onTouchCancel,
+    'touchmove': this.onTouchMove,
+    'mousedown': this.onMouseDown,
+    'mouseup': this.onMouseUp
+  };
+
+  for (var eventName in handlers) {
+    container.addEventListener(
+        eventName, handlers[eventName].bind(this), false);
+  }
+
+  // Mouse move handler has to be attached to the window to receive events
+  // from outside of the window. See: http://crbug.com/155705
+  window.addEventListener('mousemove', this.onMouseMove.bind(this), false);
+};
+
+/**
+ * Maximum movement for touch to be detected as a tap (in pixels).
+ * @private
+ */
+ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_ = 8;
+
+/**
+ * Maximum time for touch to be detected as a tap (in milliseconds).
+ * @private
+ */
+ImageEditor.MouseControl.MAX_TAP_DURATION_ = 500;
+
+/**
+ * Maximum distance from the first tap to the second tap to be considered
+ * as a double tap.
+ * @private
+ */
+ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_ = 32;
+
+/**
+ * Maximum time for touch to be detected as a double tap (in milliseconds).
+ * @private
+ */
+ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_ = 1000;
+
+/**
+ * Returns an event's position.
+ *
+ * @param {MouseEvent|Touch} e Pointer position.
+ * @return {Object} A pair of x,y in page coordinates.
+ * @private
+ */
+ImageEditor.MouseControl.getPosition_ = function(e) {
+  return {
+    x: e.pageX,
+    y: e.pageY
+  };
+};
+
+/**
+ * Returns touch position or null if there is more than one touch position.
+ *
+ * @param {TouchEvent} e Event.
+ * @return {object?} A pair of x,y in page coordinates.
+ * @private
+ */
+ImageEditor.MouseControl.prototype.getTouchPosition_ = function(e) {
+  if (e.targetTouches.length == 1)
+    return ImageEditor.MouseControl.getPosition_(e.targetTouches[0]);
+  else
+    return null;
+};
+
+/**
+ * Touch start handler.
+ * @param {TouchEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onTouchStart = function(e) {
+  var position = this.getTouchPosition_(e);
+  if (position) {
+    this.touchStartInfo_ = {
+      x: position.x,
+      y: position.y,
+      time: Date.now()
+    };
+    this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y,
+                                                    true /* touch */);
+    this.dragHappened_ = false;
+  }
+  e.preventDefault();
+};
+
+/**
+ * Touch end handler.
+ * @param {TouchEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onTouchEnd = function(e) {
+  if (!this.dragHappened_ && Date.now() - this.touchStartInfo_.time <=
+                             ImageEditor.MouseControl.MAX_TAP_DURATION_) {
+    this.buffer_.onClick(this.touchStartInfo_.x, this.touchStartInfo_.y);
+    if (this.previousTouchStartInfo_ &&
+        Date.now() - this.previousTouchStartInfo_.time <
+            ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_) {
+      var prevTouchCircle = new Circle(
+          this.previousTouchStartInfo_.x,
+          this.previousTouchStartInfo_.y,
+          ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_);
+      if (prevTouchCircle.inside(this.touchStartInfo_.x,
+                                 this.touchStartInfo_.y)) {
+        this.doubleTapCallback_(this.touchStartInfo_.x, this.touchStartInfo_.y);
+      }
+    }
+    this.previousTouchStartInfo_ = this.touchStartInfo_;
+  } else {
+    this.previousTouchStartInfo_ = null;
+  }
+  this.onTouchCancel(e);
+  e.preventDefault();
+};
+
+/**
+ * Default double tap handler.
+ * @param {number} x X coordinate of the event.
+ * @param {number} y Y coordinate of the event.
+ * @private
+ */
+ImageEditor.MouseControl.prototype.doubleTapCallback_ = function(x, y) {};
+
+/**
+ * Sets callback to be called when double tap detected.
+ * @param {function(number, number)} callback New double tap callback.
+ */
+ImageEditor.MouseControl.prototype.setDoubleTapCallback = function(callback) {
+  this.doubleTapCallback_ = callback;
+};
+
+/**
+ * Touch chancel handler.
+ */
+ImageEditor.MouseControl.prototype.onTouchCancel = function() {
+  this.dragHandler_ = null;
+  this.dragHappened_ = false;
+  this.touchStartInfo_ = null;
+  this.lockMouse_(false);
+};
+
+/**
+ * Touch move handler.
+ * @param {TouchEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onTouchMove = function(e) {
+  var position = this.getTouchPosition_(e);
+  if (!position)
+    return;
+
+  if (this.touchStartInfo_ && !this.dragHappened_) {
+    var tapCircle = new Circle(this.touchStartInfo_.x, this.touchStartInfo_.y,
+                    ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_);
+    this.dragHappened_ = !tapCircle.inside(position.x, position.y);
+  }
+  if (this.dragHandler_ && this.dragHappened_) {
+    this.dragHandler_(position.x, position.y);
+    this.lockMouse_(true);
+  }
+  e.preventDefault();
+};
+
+/**
+ * Mouse down handler.
+ * @param {MouseEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onMouseDown = function(e) {
+  var position = ImageEditor.MouseControl.getPosition_(e);
+
+  this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y,
+                                                  false /* mouse */);
+  this.dragHappened_ = false;
+  this.updateCursor_(position);
+  e.preventDefault();
+};
+
+/**
+ * Mouse up handler.
+ * @param {MouseEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onMouseUp = function(e) {
+  var position = ImageEditor.MouseControl.getPosition_(e);
+
+  if (!this.dragHappened_) {
+    this.buffer_.onClick(position.x, position.y);
+  }
+  this.dragHandler_ = null;
+  this.dragHappened_ = false;
+  this.lockMouse_(false);
+  e.preventDefault();
+};
+
+/**
+ * Mouse move handler.
+ * @param {MouseEvent} e Event.
+ */
+ImageEditor.MouseControl.prototype.onMouseMove = function(e) {
+  var position = ImageEditor.MouseControl.getPosition_(e);
+
+  if (this.dragHandler_ && !e.which) {
+    // mouseup must have happened while the mouse was outside our window.
+    this.dragHandler_ = null;
+    this.lockMouse_(false);
+  }
+
+  this.updateCursor_(position);
+  if (this.dragHandler_) {
+    this.dragHandler_(position.x, position.y);
+    this.dragHappened_ = true;
+    this.lockMouse_(true);
+  }
+  e.preventDefault();
+};
+
+/**
+ * Update the UI to reflect mouse drag state.
+ * @param {boolean} on True if dragging.
+ * @private
+ */
+ImageEditor.MouseControl.prototype.lockMouse_ = function(on) {
+  ImageUtil.setAttribute(this.rootContainer_, 'mousedrag', on);
+};
+
+/**
+ * Update the cursor.
+ *
+ * @param {Object} position An object holding x and y properties.
+ * @private
+ */
+ImageEditor.MouseControl.prototype.updateCursor_ = function(position) {
+  var oldCursor = this.container_.getAttribute('cursor');
+  var newCursor = this.buffer_.getCursorStyle(
+      position.x, position.y, !!this.dragHandler_);
+  if (newCursor != oldCursor)  // Avoid flicker.
+    this.container_.setAttribute('cursor', newCursor);
+};
+
+/**
+ * A toolbar for the ImageEditor.
+ * @param {HTMLElement} parent The parent element.
+ * @param {function} displayStringFunction A string formatting function.
+ * @param {function} updateCallback The callback called when controls change.
+ * @constructor
+ */
+ImageEditor.Toolbar = function(parent, displayStringFunction, updateCallback) {
+  this.wrapper_ = parent;
+  this.displayStringFunction_ = displayStringFunction;
+  this.updateCallback_ = updateCallback;
+};
+
+/**
+ * Clear the toolbar.
+ */
+ImageEditor.Toolbar.prototype.clear = function() {
+  ImageUtil.removeChildren(this.wrapper_);
+};
+
+/**
+ * Create a control.
+ * @param {string} tagName The element tag name.
+ * @return {HTMLElement} The created control element.
+ * @private
+ */
+ImageEditor.Toolbar.prototype.create_ = function(tagName) {
+  return this.wrapper_.ownerDocument.createElement(tagName);
+};
+
+/**
+ * Add a control.
+ * @param {HTMLElement} element The control to add.
+ * @return {HTMLElement} The added element.
+ */
+ImageEditor.Toolbar.prototype.add = function(element) {
+  this.wrapper_.appendChild(element);
+  return element;
+};
+
+/**
+ * Add a text label.
+ * @param {string} name Label name.
+ * @return {HTMLElement} The added label.
+ */
+ImageEditor.Toolbar.prototype.addLabel = function(name) {
+  var label = this.create_('span');
+  label.textContent = this.displayStringFunction_(name);
+  return this.add(label);
+};
+
+/**
+ * Add a button.
+ *
+ * @param {string} name Button name.
+ * @param {string} title Button title.
+ * @param {function} handler onClick handler.
+ * @param {string=} opt_class Extra class name.
+ * @return {HTMLElement} The added button.
+ */
+ImageEditor.Toolbar.prototype.addButton = function(
+    name, title, handler, opt_class) {
+  var button = this.create_('button');
+  if (opt_class) button.classList.add(opt_class);
+  var label = this.create_('span');
+  label.textContent = this.displayStringFunction_(title);
+  button.appendChild(label);
+  button.label = this.displayStringFunction_(title);
+  button.addEventListener('click', handler, false);
+  return this.add(button);
+};
+
+/**
+ * Add a range control (scalar value picker).
+ *
+ * @param {string} name An option name.
+ * @param {string} title An option title.
+ * @param {number} min Min value of the option.
+ * @param {number} value Default value of the option.
+ * @param {number} max Max value of the options.
+ * @param {number} scale A number to multiply by when setting
+ *                       min/value/max in DOM.
+ * @param {boolean=} opt_showNumeric True if numeric value should be displayed.
+ * @return {HTMLElement} Range element.
+ */
+ImageEditor.Toolbar.prototype.addRange = function(
+    name, title, min, value, max, scale, opt_showNumeric) {
+  var self = this;
+
+  scale = scale || 1;
+
+  var range = this.create_('input');
+
+  range.className = 'range';
+  range.type = 'range';
+  range.name = name;
+  range.min = Math.ceil(min * scale);
+  range.max = Math.floor(max * scale);
+
+  var numeric = this.create_('div');
+  numeric.className = 'numeric';
+  function mirror() {
+    numeric.textContent = Math.round(range.getValue() * scale) / scale;
+  }
+
+  range.setValue = function(newValue) {
+    range.value = Math.round(newValue * scale);
+    mirror();
+  };
+
+  range.getValue = function() {
+    return Number(range.value) / scale;
+  };
+
+  range.reset = function() {
+    range.setValue(value);
+  };
+
+  range.addEventListener('change',
+      function() {
+        mirror();
+        self.updateCallback_(self.getOptions());
+      },
+      false);
+
+  range.setValue(value);
+
+  var label = this.create_('div');
+  label.textContent = this.displayStringFunction_(title);
+  label.className = 'label ' + name;
+  this.add(label);
+  this.add(range);
+  if (opt_showNumeric) this.add(numeric);
+
+  return range;
+};
+
+/**
+ * @return {Object} options A map of options.
+ */
+ImageEditor.Toolbar.prototype.getOptions = function() {
+  var values = {};
+  for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) {
+    if (child.name)
+      values[child.name] = child.getValue();
+  }
+  return values;
+};
+
+/**
+ * Reset the toolbar.
+ */
+ImageEditor.Toolbar.prototype.reset = function() {
+  for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) {
+    if (child.reset) child.reset();
+  }
+};
+
+/**
+ * Show/hide the toolbar.
+ * @param {boolean} on True if show.
+ */
+ImageEditor.Toolbar.prototype.show = function(on) {
+  if (!this.wrapper_.firstChild)
+    return;  // Do not show empty toolbar;
+
+  this.wrapper_.hidden = !on;
+};
+
+/** A prompt panel for the editor.
+ *
+ * @param {HTMLElement} container Container element.
+ * @param {function} displayStringFunction A formatting function.
+ * @constructor
+ */
+ImageEditor.Prompt = function(container, displayStringFunction) {
+  this.container_ = container;
+  this.displayStringFunction_ = displayStringFunction;
+};
+
+/**
+ * Reset the prompt.
+ */
+ImageEditor.Prompt.prototype.reset = function() {
+  this.cancelTimer();
+  if (this.wrapper_) {
+    this.container_.removeChild(this.wrapper_);
+    this.wrapper_ = null;
+    this.prompt_ = null;
+  }
+};
+
+/**
+ * Cancel the delayed action.
+ */
+ImageEditor.Prompt.prototype.cancelTimer = function() {
+  if (this.timer_) {
+    clearTimeout(this.timer_);
+    this.timer_ = null;
+  }
+};
+
+/**
+ * Schedule the delayed action.
+ * @param {function} callback Callback.
+ * @param {number} timeout Timeout.
+ */
+ImageEditor.Prompt.prototype.setTimer = function(callback, timeout) {
+  this.cancelTimer();
+  var self = this;
+  this.timer_ = setTimeout(function() {
+    self.timer_ = null;
+    callback();
+  }, timeout);
+};
+
+/**
+ * Show the prompt.
+ *
+ * @param {string} text The prompt text.
+ * @param {number} timeout Timeout in ms.
+ * @param {Object} formatArgs varArgs for the formatting fuction.
+ */
+ImageEditor.Prompt.prototype.show = function(text, timeout, formatArgs) {
+  this.showAt.apply(this,
+      ['center'].concat(Array.prototype.slice.call(arguments)));
+};
+
+/**
+ *
+ * @param {string} pos The 'pos' attribute value.
+ * @param {string} text The prompt text.
+ * @param {number} timeout Timeout in ms.
+ * @param {Object} formatArgs varArgs for the formatting function.
+ */
+ImageEditor.Prompt.prototype.showAt = function(pos, text, timeout, formatArgs) {
+  this.reset();
+  if (!text) return;
+
+  var document = this.container_.ownerDocument;
+  this.wrapper_ = document.createElement('div');
+  this.wrapper_.className = 'prompt-wrapper';
+  this.wrapper_.setAttribute('pos', pos);
+  this.container_.appendChild(this.wrapper_);
+
+  this.prompt_ = document.createElement('div');
+  this.prompt_.className = 'prompt';
+
+  // Create an extra wrapper which opacity can be manipulated separately.
+  var tool = document.createElement('div');
+  tool.className = 'dimmable';
+  this.wrapper_.appendChild(tool);
+  tool.appendChild(this.prompt_);
+
+  var args = [text].concat(Array.prototype.slice.call(arguments, 3));
+  this.prompt_.textContent = this.displayStringFunction_.apply(null, args);
+
+  var close = document.createElement('div');
+  close.className = 'close';
+  close.addEventListener('click', this.hide.bind(this));
+  this.prompt_.appendChild(close);
+
+  setTimeout(
+      this.prompt_.setAttribute.bind(this.prompt_, 'state', 'fadein'), 0);
+
+  if (timeout)
+    this.setTimer(this.hide.bind(this), timeout);
+};
+
+/**
+ * Hide the prompt.
+ */
+ImageEditor.Prompt.prototype.hide = function() {
+  if (!this.prompt_) return;
+  this.prompt_.setAttribute('state', 'fadeout');
+  // Allow some time for the animation to play out.
+  this.setTimer(this.reset.bind(this), 500);
+};
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_encoder.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_encoder.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_encoder.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_encoder.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_transform.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_transform.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_transform.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_transform.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_util.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_util.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_util.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_view.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/image_view.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/image_view.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/image_view.js
diff --git a/chrome/browser/resources/file_manager/js/image_editor/viewport.js b/chrome/browser/resources/file_manager/foreground/js/image_editor/viewport.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/image_editor/viewport.js
rename to chrome/browser/resources/file_manager/foreground/js/image_editor/viewport.js
diff --git a/chrome/browser/resources/file_manager/js/main.js b/chrome/browser/resources/file_manager/foreground/js/main.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/main.js
rename to chrome/browser/resources/file_manager/foreground/js/main.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/main_scripts.js b/chrome/browser/resources/file_manager/foreground/js/main_scripts.js
new file mode 100644
index 0000000..4cd1069
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/main_scripts.js
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 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.
+
+// The include directives are put into Javascript-style comments to prevent
+// parsing errors in non-flattened mode. The flattener still sees them.
+// Note that this makes the flattener to comment out the first line of the
+// included file but that's all right since any javascript file should start
+// with a copyright comment anyway.
+
+// If you add a new dependency, you should update build files by rerunning
+// gyp. Otherwise, you'll be bitten by a dependency issue like:
+//
+// 1) You add a new dependency to "whatever.js"
+// 2) You make changes in "whatever.js"
+// 3) Rebuild "resources.pak" and open Files.app
+// 4) You don't see the changes in "whatever.js". Why is that?
+//
+// Because the dependencies are computed at gyp time, the existing build
+// files don't know that "resources.pak" now has a dependency to
+// "whatever.js". You should rerun gyp to let the build files know.
+//
+// //metrics.js initiates load performance tracking
+// //so we want to parse it as early as possible.
+//<include src="metrics.js"/>
+//
+//<include src="../../../image_loader/image_loader_client.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/load_time_data.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr.js"/>
+//<include src="../../../../../../ui/webui/resources/js/util.js"/>
+//<include src="../../../../../../ui/webui/resources/js/i18n_template_no_process.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/event_tracker.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/dialogs.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_item.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/list.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/tree.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/autocomplete_list.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/splitter.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_splitter.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_column.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_column_model.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_header.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_list.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/table.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/grid.js"/>
+//
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/command.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/position_util.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu_item.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu_button.js"/>
+//<include src="../../../../../../ui/webui/resources/js/cr/ui/context_menu_handler.js"/>
+
+(function() {
+// 'strict mode' is invoked for this scope.
+
+// // This script must be loaded before all other Files.app's scripts.
+//<include src="error_counter.js"/>
+//
+//<include src="../../common/js/async_util.js"/>
+//<include src="../../common/js/path_util.js"/>
+//<include src="../../common/js/util.js"/>
+//<include src="../../common/js/progress_center_common.js">
+//
+//<include src="combobutton.js"/>
+//<include src="commandbutton.js"/>
+//<include src="ui/file_manager_dialog_base.js"/>
+//
+//<include src="action_choice/action_choice_util.js"/>
+//<include src="app_installer.js"/>
+//<include src="butter_bar.js"/>
+//<include src="cws_container_client.js"/>
+//<include src="directory_contents.js"/>
+//<include src="directory_model.js"/>
+//<include src="directory_tree.js"/>
+//<include src="drag_selector.js"/>
+//<include src="drive_banners.js" />
+//<include src="error_dialog.js"/>
+//<include src="file_operation_manager_wrapper.js"/>
+//<include src="file_grid.js"/>
+//<include src="file_manager.js"/>
+//<include src="file_selection.js"/>
+//<include src="file_table.js"/>
+//<include src="file_tasks.js"/>
+//<include src="file_transfer_controller.js"/>
+//<include src="file_type.js"/>
+//<include src="file_watcher.js"/>
+//<include src="folder_shortcuts_data_model.js"/>
+//<include src="navigation_list_model.js"/>
+//<include src="scrollbar.js"/>
+//<include src="share_client.js"/>
+//<include src="share_dialog.js"/>
+//<include src="suggest_apps_dialog.js"/>
+//<include src="text_measure.js"/>
+//<include src="tree.css.js"/>
+//<include src="ui/breadcrumbs_controller.js"/>
+//<include src="ui/conflict_dialog.js"/>
+//<include src="ui/file_manager_ui.js"/>
+//<include src="ui/navigation_list.js"/>
+//<include src="ui/preview_panel.js"/>
+//<include src="ui/progress_center_panel.js"/>
+//<include src="ui/search_box.js"/>
+//<include src="url_constants.js"/>
+//<include src="volume_manager_wrapper.js"/>
+//<include src="media/media_util.js"/>
+//<include src="metadata/metadata_cache.js"/>
+//<include src="default_action_dialog.js"/>
+//<include src="file_manager_commands.js"/>
+
+// // For accurate load performance tracking place main.js should be
+// // the last include to include.
+//<include src="main.js"/>
+
+// Global fileManager reference useful for poking at from the console.
+window.fileManager = fileManager;
+
+// Exports
+window.util = util;
+window.FileOperationManagerWrapper = FileOperationManagerWrapper;
+
+window.unload = unload;
+
+})();
diff --git a/chrome/browser/resources/file_manager/js/media/audio_player.js b/chrome/browser/resources/file_manager/foreground/js/media/audio_player.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/audio_player.js
rename to chrome/browser/resources/file_manager/foreground/js/media/audio_player.js
diff --git a/chrome/browser/resources/file_manager/js/media/media_controls.js b/chrome/browser/resources/file_manager/foreground/js/media/media_controls.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/media_controls.js
rename to chrome/browser/resources/file_manager/foreground/js/media/media_controls.js
diff --git a/chrome/browser/resources/file_manager/js/media/media_util.js b/chrome/browser/resources/file_manager/foreground/js/media/media_util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/media_util.js
rename to chrome/browser/resources/file_manager/foreground/js/media/media_util.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js b/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js
new file mode 100644
index 0000000..496a8d0
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 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.
+
+// The include directives are put into Javascript-style comments to prevent
+// parsing errors in non-flattened mode. The flattener still sees them.
+// Note that this makes the flattener to comment out the first line of the
+// included file but that's all right since any javascript file should start
+// with a copyright comment anyway.
+
+
+//<include src="../../../../../../../ui/webui/resources/js/cr.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
+
+(function() {
+// 'strict mode' is invoked for this scope.
+
+//<include src="../../../common/js/async_util.js"/>
+//<include src="../../../common/js/util.js"/>
+//<include src="../../../common/js/path_util.js"/>
+//<include src="../file_type.js"/>
+//<include src="../volume_manager_wrapper.js">
+//<include src="../metadata/metadata_cache.js"/>
+
+//<include src="media_controls.js"/>
+//<include src="audio_player.js"/>
+//<include src="player_testapi.js"/>
+
+window.reload = reload;
+window.unload = unload;
+
+})();
diff --git a/chrome/browser/resources/file_manager/js/media/player_testapi.js b/chrome/browser/resources/file_manager/foreground/js/media/player_testapi.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/player_testapi.js
rename to chrome/browser/resources/file_manager/foreground/js/media/player_testapi.js
diff --git a/chrome/browser/resources/file_manager/js/media/util.js b/chrome/browser/resources/file_manager/foreground/js/media/util.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/util.js
rename to chrome/browser/resources/file_manager/foreground/js/media/util.js
diff --git a/chrome/browser/resources/file_manager/js/media/video_player.js b/chrome/browser/resources/file_manager/foreground/js/media/video_player.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/media/video_player.js
rename to chrome/browser/resources/file_manager/foreground/js/media/video_player.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js b/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js
new file mode 100644
index 0000000..54ea178
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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.
+
+// The include directives are put into Javascript-style comments to prevent
+// parsing errors in non-flattened mode. The flattener still sees them.
+// Note that this makes the flattener to comment out the first line of the
+// included file but that's all right since any javascript file should start
+// with a copyright comment anyway.
+
+//<include src="../../../../../../../ui/webui/resources/js/cr.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
+//<include src="../../../../../../../ui/webui/resources/js/load_time_data.js"/>
+
+(function() {
+// 'strict mode' is invoked for this scope.
+
+//<include src="../../../common/js/async_util.js"/>
+//<include src="../../../common/js/util.js"/>
+//<include src="../../../common/js/path_util.js"/>
+//<include src="../file_type.js"/>
+//<include src="../volume_manager_wrapper.js">
+//<include src="../metadata/metadata_cache.js"/>
+
+//<include src="media_controls.js"/>
+//<include src="util.js"/>
+//<include src="video_player.js"/>
+//<include src="player_testapi.js"/>
+
+window.reload = reload;
+window.unload = unload;
+
+})();
diff --git a/chrome/browser/resources/file_manager/js/metadata/byte_reader.js b/chrome/browser/resources/file_manager/foreground/js/metadata/byte_reader.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/byte_reader.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/byte_reader.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/exif_parser.js b/chrome/browser/resources/file_manager/foreground/js/metadata/exif_parser.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/exif_parser.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/exif_parser.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/function_parallel.js b/chrome/browser/resources/file_manager/foreground/js/metadata/function_parallel.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/function_parallel.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/function_parallel.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/function_sequence.js b/chrome/browser/resources/file_manager/foreground/js/metadata/function_sequence.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/function_sequence.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/function_sequence.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/id3_parser.js b/chrome/browser/resources/file_manager/foreground/js/metadata/id3_parser.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/id3_parser.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/id3_parser.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/image_parsers.js b/chrome/browser/resources/file_manager/foreground/js/metadata/image_parsers.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/image_parsers.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/image_parsers.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js b/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js
new file mode 100644
index 0000000..272ebbc
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js
@@ -0,0 +1,1050 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * MetadataCache is a map from url to an object containing properties.
+ * Properties are divided by types, and all properties of one type are accessed
+ * at once.
+ * Some of the properties:
+ * {
+ *   filesystem: size, modificationTime
+ *   internal: presence
+ *   drive: pinned, present, hosted, availableOffline
+ *   streaming: (no property)
+ *
+ *   Following are not fetched for non-present drive files.
+ *   media: artist, album, title, width, height, imageTransform, etc.
+ *   thumbnail: url, transform
+ *
+ *   Following are always fetched from content, and so force the downloading
+ *   of remote drive files. One should use this for required content metadata,
+ *   i.e. image orientation.
+ *   fetchedMedia: width, height, etc.
+ * }
+ *
+ * Typical usages:
+ * {
+ *   cache.get([entry1, entry2], 'drive|filesystem', function(metadata) {
+ *     if (metadata[0].drive.pinned && metadata[1].filesystem.size == 0)
+ *       alert("Pinned and empty!");
+ *   });
+ *
+ *   cache.set(entry, 'internal', {presence: 'deleted'});
+ *
+ *   cache.clear([fileUrl1, fileUrl2], 'filesystem');
+ *
+ *   // Getting fresh value.
+ *   cache.clear(entry, 'thumbnail');
+ *   cache.get(entry, 'thumbnail', function(thumbnail) {
+ *     img.src = thumbnail.url;
+ *   });
+ *
+ *   var cached = cache.getCached(entry, 'filesystem');
+ *   var size = (cached && cached.size) || UNKNOWN_SIZE;
+ * }
+ *
+ * @constructor
+ */
+function MetadataCache() {
+  /**
+   * Map from urls to entries. Entry contains |properties| - an hierarchical
+   * object of values, and an object for each metadata provider:
+   * <prodiver-id>: { time, callbacks }
+   * @private
+   */
+  this.cache_ = {};
+
+  /**
+   * List of metadata providers.
+   * @private
+   */
+  this.providers_ = [];
+
+  /**
+   * List of observers added. Each one is an object with fields:
+   *   re - regexp of urls;
+   *   type - metadata type;
+   *   callback - the callback.
+   * TODO(dgozman): pass entries to observer if present.
+   * @private
+   */
+  this.observers_ = [];
+  this.observerId_ = 0;
+
+  this.batchCount_ = 0;
+  this.totalCount_ = 0;
+
+  /**
+   * Time of first get query of the current batch. Items updated later than this
+   * will not be evicted.
+   * @private
+   */
+  this.lastBatchStart_ = new Date();
+}
+
+/**
+ * Observer type: it will be notified if the url changed is exactly the same
+ * as the url passed.
+ */
+MetadataCache.EXACT = 0;
+
+/**
+ * Observer type: it will be notified if the url changed is an immediate child
+ * of the url passed.
+ */
+MetadataCache.CHILDREN = 1;
+
+/**
+ * Observer type: it will be notified if the url changed is any descendant
+ * of the url passed.
+ */
+MetadataCache.DESCENDANTS = 2;
+
+/**
+ * Minimum number of items in cache to start eviction.
+ */
+MetadataCache.EVICTION_NUMBER = 1000;
+
+/**
+ * @return {MetadataCache!} The cache with all providers.
+ */
+MetadataCache.createFull = function() {
+  var cache = new MetadataCache();
+  cache.providers_.push(new FilesystemProvider());
+  cache.providers_.push(new DriveProvider());
+  cache.providers_.push(new ContentProvider());
+  return cache;
+};
+
+/**
+ * Clones metadata entry. Metadata entries may contain scalars, arrays,
+ * hash arrays and Date object. Other objects are not supported.
+ * @param {Object} metadata Metadata object.
+ * @return {Object} Cloned entry.
+ */
+MetadataCache.cloneMetadata = function(metadata) {
+  if (metadata instanceof Array) {
+    var result = [];
+    for (var index = 0; index < metadata.length; index++) {
+      result[index] = MetadataCache.cloneMetadata(metadata[index]);
+    }
+    return result;
+  } else if (metadata instanceof Date) {
+    var result = new Date();
+    result.setTime(metadata.getTime());
+    return result;
+  } else if (metadata instanceof Object) {  // Hash array only.
+    var result = {};
+    for (var property in metadata) {
+      if (metadata.hasOwnProperty(property))
+        result[property] = MetadataCache.cloneMetadata(metadata[property]);
+    }
+    return result;
+  } else {
+    return metadata;
+  }
+};
+
+/**
+ * @return {boolean} Whether all providers are ready.
+ */
+MetadataCache.prototype.isInitialized = function() {
+  for (var index = 0; index < this.providers_.length; index++) {
+    if (!this.providers_[index].isInitialized()) return false;
+  }
+  return true;
+};
+
+/**
+ * Fetches the metadata, puts it in the cache, and passes to callback.
+ * If required metadata is already in the cache, does not fetch it again.
+ * @param {string|Entry|Array.<string|Entry>} items The list of entries or
+ *     file urls. May be just a single item.
+ * @param {string} type The metadata type.
+ * @param {function(Object)} callback The metadata is passed to callback.
+ */
+MetadataCache.prototype.get = function(items, type, callback) {
+  if (!(items instanceof Array)) {
+    this.getOne(items, type, callback);
+    return;
+  }
+
+  if (items.length == 0) {
+    if (callback) callback([]);
+    return;
+  }
+
+  var result = [];
+  var remaining = items.length;
+  this.startBatchUpdates();
+
+  var onOneItem = function(index, value) {
+    result[index] = value;
+    remaining--;
+    if (remaining == 0) {
+      this.endBatchUpdates();
+      if (callback) setTimeout(callback, 0, result);
+    }
+  };
+
+  for (var index = 0; index < items.length; index++) {
+    result.push(null);
+    this.getOne(items[index], type, onOneItem.bind(this, index));
+  }
+};
+
+/**
+ * Fetches the metadata for one Entry/FileUrl. See comments to |get|.
+ * @param {Entry|string} item The entry or url.
+ * @param {string} type Metadata type.
+ * @param {function(Object)} callback The callback.
+ */
+MetadataCache.prototype.getOne = function(item, type, callback) {
+  if (type.indexOf('|') != -1) {
+    var types = type.split('|');
+    var result = {};
+    var typesLeft = types.length;
+
+    var onOneType = function(requestedType, metadata) {
+      result[requestedType] = metadata;
+      typesLeft--;
+      if (typesLeft == 0) callback(result);
+    };
+
+    for (var index = 0; index < types.length; index++) {
+      this.getOne(item, types[index], onOneType.bind(null, types[index]));
+    }
+    return;
+  }
+
+  var url = this.itemToUrl_(item);
+
+  // Passing entry to fetchers may save one round-trip to APIs.
+  var fsEntry = item === url ? null : item;
+  callback = callback || function() {};
+
+  if (!(url in this.cache_)) {
+    this.cache_[url] = this.createEmptyEntry_();
+    this.totalCount_++;
+  }
+
+  var entry = this.cache_[url];
+
+  if (type in entry.properties) {
+    callback(entry.properties[type]);
+    return;
+  }
+
+  this.startBatchUpdates();
+  var providers = this.providers_.slice();
+  var currentProvider;
+  var self = this;
+
+  var onFetched = function() {
+    if (type in entry.properties) {
+      self.endBatchUpdates();
+      // Got properties from provider.
+      callback(entry.properties[type]);
+    } else {
+      tryNextProvider();
+    }
+  };
+
+  var onProviderProperties = function(properties) {
+    var id = currentProvider.getId();
+    var fetchedCallbacks = entry[id].callbacks;
+    delete entry[id].callbacks;
+    entry.time = new Date();
+    self.mergeProperties_(url, properties);
+
+    for (var index = 0; index < fetchedCallbacks.length; index++) {
+      fetchedCallbacks[index]();
+    }
+  };
+
+  var queryProvider = function() {
+    var id = currentProvider.getId();
+    if ('callbacks' in entry[id]) {
+      // We are querying this provider now.
+      entry[id].callbacks.push(onFetched);
+    } else {
+      entry[id].callbacks = [onFetched];
+      currentProvider.fetch(url, type, onProviderProperties, fsEntry);
+    }
+  };
+
+  var tryNextProvider = function() {
+    if (providers.length == 0) {
+      self.endBatchUpdates();
+      callback(entry.properties[type] || null);
+      return;
+    }
+
+    currentProvider = providers.shift();
+    if (currentProvider.supportsUrl(url) &&
+        currentProvider.providesType(type)) {
+      queryProvider();
+    } else {
+      tryNextProvider();
+    }
+  };
+
+  tryNextProvider();
+};
+
+/**
+ * Returns the cached metadata value, or |null| if not present.
+ * @param {string|Entry|Array.<string|Entry>} items The list of entries or
+ *     file urls. May be just a single item.
+ * @param {string} type The metadata type.
+ * @return {Object} The metadata or null.
+ */
+MetadataCache.prototype.getCached = function(items, type) {
+  var single = false;
+  if (!(items instanceof Array)) {
+    single = true;
+    items = [items];
+  }
+
+  var result = [];
+  for (var index = 0; index < items.length; index++) {
+    var url = this.itemToUrl_(items[index]);
+    result.push(url in this.cache_ ?
+        (this.cache_[url].properties[type] || null) : null);
+  }
+
+  return single ? result[0] : result;
+};
+
+/**
+ * Puts the metadata into cache
+ * @param {string|Entry|Array.<string|Entry>} items The list of entries or
+ *     file urls. May be just a single item.
+ * @param {string} type The metadata type.
+ * @param {Array.<Object>} values List of corresponding metadata values.
+ */
+MetadataCache.prototype.set = function(items, type, values) {
+  if (!(items instanceof Array)) {
+    items = [items];
+    values = [values];
+  }
+
+  this.startBatchUpdates();
+  for (var index = 0; index < items.length; index++) {
+    var url = this.itemToUrl_(items[index]);
+    if (!(url in this.cache_)) {
+      this.cache_[url] = this.createEmptyEntry_();
+      this.totalCount_++;
+    }
+    this.cache_[url].properties[type] = values[index];
+    this.notifyObservers_(url, type);
+  }
+  this.endBatchUpdates();
+};
+
+/**
+ * Clears the cached metadata values.
+ * @param {string|Entry|Array.<string|Entry>} items The list of entries or
+ *     file urls. May be just a single item.
+ * @param {string} type The metadata types or * for any type.
+ */
+MetadataCache.prototype.clear = function(items, type) {
+  if (!(items instanceof Array))
+    items = [items];
+
+  var types = type.split('|');
+
+  for (var index = 0; index < items.length; index++) {
+    var url = this.itemToUrl_(items[index]);
+    if (url in this.cache_) {
+      if (type === '*') {
+        this.cache_[url].properties = {};
+      } else {
+        for (var j = 0; j < types.length; j++) {
+          var type = types[j];
+          delete this.cache_[url].properties[type];
+        }
+      }
+    }
+  }
+};
+
+/**
+ * Clears the cached metadata values recursively.
+ * @param {Entry|string} item An entry or a url.
+ * @param {string} type The metadata types or * for any type.
+ */
+MetadataCache.prototype.clearRecursively = function(item, type) {
+  var types = type.split('|');
+  var keys = Object.keys(this.cache_);
+  var url = this.itemToUrl_(item);
+
+  for (var index = 0; index < keys.length; index++) {
+    var entryUrl = keys[index];
+    if (entryUrl.substring(0, url.length) === url) {
+      if (type === '*') {
+        this.cache_[entryUrl].properties = {};
+      } else {
+        for (var j = 0; j < types.length; j++) {
+          var type = types[j];
+          delete this.cache_[entryUrl].properties[type];
+        }
+      }
+    }
+  }
+};
+
+/**
+ * Adds an observer, which will be notified when metadata changes.
+ * @param {string|Entry} item The root item to look at.
+ * @param {number} relation This defines, which items will trigger the observer.
+ *     See comments to |MetadataCache.EXACT| and others.
+ * @param {string} type The metadata type.
+ * @param {function(Array.<string>, Array.<Object>)} observer List of file urls
+ *     and corresponding metadata values are passed to this callback.
+ * @return {number} The observer id, which can be used to remove it.
+ */
+MetadataCache.prototype.addObserver = function(item, relation, type, observer) {
+  var url = this.itemToUrl_(item);
+  var re = url;
+  if (relation == MetadataCache.CHILDREN) {
+    re += '(/[^/]*)?';
+  } else if (relation == MetadataCache.DESCENDANTS) {
+    re += '(/.*)?';
+  }
+  var id = ++this.observerId_;
+  this.observers_.push({
+    re: new RegExp('^' + re + '$'),
+    type: type,
+    callback: observer,
+    id: id,
+    pending: {}
+  });
+  return id;
+};
+
+/**
+ * Removes the observer.
+ * @param {number} id Observer id.
+ * @return {boolean} Whether observer was removed or not.
+ */
+MetadataCache.prototype.removeObserver = function(id) {
+  for (var index = 0; index < this.observers_.length; index++) {
+    if (this.observers_[index].id == id) {
+      this.observers_.splice(index, 1);
+      return true;
+    }
+  }
+  return false;
+};
+
+/**
+ * Start batch updates.
+ */
+MetadataCache.prototype.startBatchUpdates = function() {
+  this.batchCount_++;
+  if (this.batchCount_ == 1)
+    this.lastBatchStart_ = new Date();
+};
+
+/**
+ * End batch updates. Notifies observers if all nested updates are finished.
+ */
+MetadataCache.prototype.endBatchUpdates = function() {
+  this.batchCount_--;
+  if (this.batchCount_ != 0) return;
+  if (this.totalCount_ > MetadataCache.EVICTION_NUMBER)
+    this.evict_();
+  for (var index = 0; index < this.observers_.length; index++) {
+    var observer = this.observers_[index];
+    var urls = [];
+    var properties = [];
+    for (var url in observer.pending) {
+      if (observer.pending.hasOwnProperty(url) && url in this.cache_) {
+        urls.push(url);
+        properties.push(this.cache_[url].properties[observer.type] || null);
+      }
+    }
+    observer.pending = {};
+    if (urls.length > 0) {
+      observer.callback(urls, properties);
+    }
+  }
+};
+
+/**
+ * Notifies observers or puts the data to pending list.
+ * @param {string} url Url of entry changed.
+ * @param {string} type Metadata type.
+ * @private
+ */
+MetadataCache.prototype.notifyObservers_ = function(url, type) {
+  for (var index = 0; index < this.observers_.length; index++) {
+    var observer = this.observers_[index];
+    if (observer.type == type && observer.re.test(url)) {
+      if (this.batchCount_ == 0) {
+        // Observer expects array of urls and array of properties.
+        observer.callback([url], [this.cache_[url].properties[type] || null]);
+      } else {
+        observer.pending[url] = true;
+      }
+    }
+  }
+};
+
+/**
+ * Removes the oldest items from the cache.
+ * This method never removes the items from last batch.
+ * @private
+ */
+MetadataCache.prototype.evict_ = function() {
+  var toRemove = [];
+
+  // We leave only a half of items, so we will not call evict_ soon again.
+  var desiredCount = Math.round(MetadataCache.EVICTION_NUMBER / 2);
+  var removeCount = this.totalCount_ - desiredCount;
+  for (var url in this.cache_) {
+    if (this.cache_.hasOwnProperty(url) &&
+        this.cache_[url].time < this.lastBatchStart_) {
+      toRemove.push(url);
+    }
+  }
+
+  toRemove.sort(function(a, b) {
+    var aTime = this.cache_[a].time;
+    var bTime = this.cache_[b].time;
+    return aTime < bTime ? -1 : aTime > bTime ? 1 : 0;
+  }.bind(this));
+
+  removeCount = Math.min(removeCount, toRemove.length);
+  this.totalCount_ -= removeCount;
+  for (var index = 0; index < removeCount; index++) {
+    delete this.cache_[toRemove[index]];
+  }
+};
+
+/**
+ * Converts Entry or file url to url.
+ * @param {string|Entry} item Item to convert.
+ * @return {string} File url.
+ * @private
+ */
+MetadataCache.prototype.itemToUrl_ = function(item) {
+  if (typeof(item) == 'string')
+    return item;
+
+  if (!item._URL_) {
+    // Is a fake entry.
+    if (typeof item.toURL !== 'function')
+      item._URL_ = util.makeFilesystemUrl(item.fullPath);
+    else
+      item._URL_ = item.toURL();
+  }
+
+  return item._URL_;
+};
+
+/**
+ * @return {Object} Empty cache entry.
+ * @private
+ */
+MetadataCache.prototype.createEmptyEntry_ = function() {
+  var entry = {properties: {}};
+  for (var index = 0; index < this.providers_.length; index++) {
+    entry[this.providers_[index].getId()] = {};
+  }
+  return entry;
+};
+
+/**
+ * Caches all the properties from data to cache entry for url.
+ * @param {string} url The url.
+ * @param {Object} data The properties.
+ * @private
+ */
+MetadataCache.prototype.mergeProperties_ = function(url, data) {
+  if (data == null) return;
+  var properties = this.cache_[url].properties;
+  for (var type in data) {
+    if (data.hasOwnProperty(type) && !properties.hasOwnProperty(type)) {
+      properties[type] = data[type];
+      this.notifyObservers_(url, type);
+    }
+  }
+};
+
+/**
+ * Base class for metadata providers.
+ * @constructor
+ */
+function MetadataProvider() {
+}
+
+/**
+ * @param {string} url The url.
+ * @return {boolean} Whether this provider supports the url.
+ */
+MetadataProvider.prototype.supportsUrl = function(url) { return false; };
+
+/**
+ * @param {string} type The metadata type.
+ * @return {boolean} Whether this provider provides this metadata.
+ */
+MetadataProvider.prototype.providesType = function(type) { return false; };
+
+/**
+ * @return {string} Unique provider id.
+ */
+MetadataProvider.prototype.getId = function() { return ''; };
+
+/**
+ * @return {boolean} Whether provider is ready.
+ */
+MetadataProvider.prototype.isInitialized = function() { return true; };
+
+/**
+ * Fetches the metadata. It's suggested to return all the metadata this provider
+ * can fetch at once.
+ * @param {string} url File url.
+ * @param {string} type Requested metadata type.
+ * @param {function(Object)} callback Callback expects a map from metadata type
+ *     to metadata value.
+ * @param {Entry=} opt_entry The file entry if present.
+ */
+MetadataProvider.prototype.fetch = function(url, type, callback, opt_entry) {
+  throw new Error('Default metadata provider cannot fetch.');
+};
+
+
+/**
+ * Provider of filesystem metadata.
+ * This provider returns the following objects:
+ * filesystem: { size, modificationTime }
+ * @constructor
+ */
+function FilesystemProvider() {
+  MetadataProvider.call(this);
+}
+
+FilesystemProvider.prototype = {
+  __proto__: MetadataProvider.prototype
+};
+
+/**
+ * @param {string} url The url.
+ * @return {boolean} Whether this provider supports the url.
+ */
+FilesystemProvider.prototype.supportsUrl = function(url) {
+  return true;
+};
+
+/**
+ * @param {string} type The metadata type.
+ * @return {boolean} Whether this provider provides this metadata.
+ */
+FilesystemProvider.prototype.providesType = function(type) {
+  return type == 'filesystem';
+};
+
+/**
+ * @return {string} Unique provider id.
+ */
+FilesystemProvider.prototype.getId = function() { return 'filesystem'; };
+
+/**
+ * Fetches the metadata.
+ * @param {string} url File url.
+ * @param {string} type Requested metadata type.
+ * @param {function(Object)} callback Callback expects a map from metadata type
+ *     to metadata value.
+ * @param {Entry=} opt_entry The file entry if present.
+ */
+FilesystemProvider.prototype.fetch = function(url, type, callback, opt_entry) {
+  function onError(error) {
+    callback(null);
+  }
+
+  function onMetadata(entry, metadata) {
+    callback({
+      filesystem: {
+        size: entry.isFile ? (metadata.size || 0) : -1,
+        modificationTime: metadata.modificationTime
+      }
+    });
+  }
+
+  function onEntry(entry) {
+    entry.getMetadata(onMetadata.bind(null, entry), onError);
+  }
+
+  if (opt_entry)
+    onEntry(opt_entry);
+  else
+    window.webkitResolveLocalFileSystemURL(url, onEntry, onError);
+};
+
+/**
+ * Provider of drive metadata.
+ * This provider returns the following objects:
+ *     drive: { pinned, hosted, present, customIconUrl, etc. }
+ *     thumbnail: { url, transform }
+ *     streaming: { }
+ * @constructor
+ */
+function DriveProvider() {
+  MetadataProvider.call(this);
+
+  // We batch metadata fetches into single API call.
+  this.urls_ = [];
+  this.callbacks_ = [];
+  this.scheduled_ = false;
+
+  this.callApiBound_ = this.callApi_.bind(this);
+}
+
+DriveProvider.prototype = {
+  __proto__: MetadataProvider.prototype
+};
+
+/**
+ * @param {string} url The url.
+ * @return {boolean} Whether this provider supports the url.
+ */
+DriveProvider.prototype.supportsUrl = function(url) {
+  return FileType.isOnDrive(url);
+};
+
+/**
+ * @param {string} type The metadata type.
+ * @return {boolean} Whether this provider provides this metadata.
+ */
+DriveProvider.prototype.providesType = function(type) {
+  return type == 'drive' || type == 'thumbnail' ||
+      type == 'streaming' || type == 'media';
+};
+
+/**
+ * @return {string} Unique provider id.
+ */
+DriveProvider.prototype.getId = function() { return 'drive'; };
+
+/**
+ * Fetches the metadata.
+ * @param {string} url File url.
+ * @param {string} type Requested metadata type.
+ * @param {function(Object)} callback Callback expects a map from metadata type
+ *     to metadata value.
+ * @param {Entry=} opt_entry The file entry if present.
+ */
+DriveProvider.prototype.fetch = function(url, type, callback, opt_entry) {
+  this.urls_.push(url);
+  this.callbacks_.push(callback);
+  if (!this.scheduled_) {
+    this.scheduled_ = true;
+    setTimeout(this.callApiBound_, 0);
+  }
+};
+
+/**
+ * Schedules the API call.
+ * @private
+ */
+DriveProvider.prototype.callApi_ = function() {
+  this.scheduled_ = false;
+
+  var urls = this.urls_;
+  var callbacks = this.callbacks_;
+  this.urls_ = [];
+  this.callbacks_ = [];
+  var self = this;
+
+  var task = function(url, callback) {
+    chrome.fileBrowserPrivate.getDriveEntryProperties(url,
+        function(properties) {
+          callback(self.convert_(properties, url));
+        });
+  };
+
+  for (var i = 0; i < urls.length; i++)
+    task(urls[i], callbacks[i]);
+};
+
+/**
+ * @param {DriveEntryProperties} data Drive entry properties.
+ * @param {string} url File url.
+ * @return {boolean} True if the file is available offline.
+ */
+DriveProvider.isAvailableOffline = function(data, url) {
+  if (data.isPresent)
+    return true;
+
+  if (!data.isHosted)
+    return false;
+
+  // What's available offline? See the 'Web' column at:
+  // http://support.google.com/drive/bin/answer.py?hl=en&answer=1628467
+  var subtype = FileType.getType(url).subtype;
+  return (subtype == 'doc' ||
+          subtype == 'draw' ||
+          subtype == 'sheet' ||
+          subtype == 'slides');
+};
+
+/**
+ * @param {DriveEntryProperties} data Drive entry properties.
+ * @return {boolean} True if opening the file does not require downloading it
+ *    via a metered connection.
+ */
+DriveProvider.isAvailableWhenMetered = function(data) {
+  return data.isPresent || data.isHosted;
+};
+
+/**
+ * Converts API metadata to internal format.
+ * @param {Object} data Metadata from API call.
+ * @param {string} url File url.
+ * @return {Object} Metadata in internal format.
+ * @private
+ */
+DriveProvider.prototype.convert_ = function(data, url) {
+  var result = {};
+  result.drive = {
+    present: data.isPresent,
+    pinned: data.isPinned,
+    hosted: data.isHosted,
+    imageWidth: data.imageWidth,
+    imageHeight: data.imageHeight,
+    imageRotation: data.imageRotation,
+    availableOffline: DriveProvider.isAvailableOffline(data, url),
+    availableWhenMetered: DriveProvider.isAvailableWhenMetered(data),
+    customIconUrl: data.customIconUrl || '',
+    contentMimeType: data.contentMimeType || '',
+    sharedWithMe: data.sharedWithMe
+  };
+
+  if (!data.isPresent) {
+    // Block the local fetch for drive files, which require downloading.
+    result.thumbnail = {url: '', transform: null};
+    result.media = {};
+  }
+
+  if ('thumbnailUrl' in data) {
+    result.thumbnail = {
+      url: data.thumbnailUrl.replace(/s220/, 's500'),
+      transform: null
+    };
+  }
+  if (!data.isPresent) {
+    // Indicate that the data is not available in local cache.
+    // It used to have a field 'url' for streaming play, but it is
+    // derprecated. See crbug.com/174560.
+    result.streaming = {};
+  }
+  return result;
+};
+
+
+/**
+ * Provider of content metadata.
+ * This provider returns the following objects:
+ * thumbnail: { url, transform }
+ * media: { artist, album, title, width, height, imageTransform, etc. }
+ * fetchedMedia: { same fields here }
+ * @constructor
+ */
+function ContentProvider() {
+  MetadataProvider.call(this);
+
+  // Pass all URLs to the metadata reader until we have a correct filter.
+  this.urlFilter_ = /.*/;
+
+  var path = document.location.pathname;
+  var workerPath = document.location.origin +
+      path.substring(0, path.lastIndexOf('/') + 1) +
+      'foreground/js/metadata/metadata_dispatcher.js';
+
+  if (ContentProvider.USE_SHARED_WORKER) {
+    this.dispatcher_ = new SharedWorker(workerPath).port;
+    this.dispatcher_.start();
+  } else {
+    this.dispatcher_ = new Worker(workerPath);
+  }
+
+  this.dispatcher_.onmessage = this.onMessage_.bind(this);
+  this.dispatcher_.postMessage({verb: 'init'});
+
+  // Initialization is not complete until the Worker sends back the
+  // 'initialized' message.  See below.
+  this.initialized_ = false;
+
+  // Map from url to callback.
+  // Note that simultaneous requests for same url are handled in MetadataCache.
+  this.callbacks_ = {};
+}
+
+/**
+ * Flag defining which kind of a worker to use.
+ * TODO(kaznacheev): Observe for some time and remove if SharedWorker does not
+ * cause any problems.
+ */
+ContentProvider.USE_SHARED_WORKER = true;
+
+ContentProvider.prototype = {
+  __proto__: MetadataProvider.prototype
+};
+
+/**
+ * @param {string} url The url.
+ * @return {boolean} Whether this provider supports the url.
+ */
+ContentProvider.prototype.supportsUrl = function(url) {
+  return url.match(this.urlFilter_);
+};
+
+/**
+ * @param {string} type The metadata type.
+ * @return {boolean} Whether this provider provides this metadata.
+ */
+ContentProvider.prototype.providesType = function(type) {
+  return type == 'thumbnail' || type == 'fetchedMedia' || type == 'media';
+};
+
+/**
+ * @return {string} Unique provider id.
+ */
+ContentProvider.prototype.getId = function() { return 'content'; };
+
+/**
+ * Fetches the metadata.
+ * @param {string} url File url.
+ * @param {string} type Requested metadata type.
+ * @param {function(Object)} callback Callback expects a map from metadata type
+ *     to metadata value.
+ * @param {Entry=} opt_entry The file entry if present.
+ */
+ContentProvider.prototype.fetch = function(url, type, callback, opt_entry) {
+  if (opt_entry && opt_entry.isDirectory) {
+    callback({});
+    return;
+  }
+  this.callbacks_[url] = callback;
+  this.dispatcher_.postMessage({verb: 'request', arguments: [url]});
+};
+
+/**
+ * Dispatch a message from a metadata reader to the appropriate on* method.
+ * @param {Object} event The event.
+ * @private
+ */
+ContentProvider.prototype.onMessage_ = function(event) {
+  var data = event.data;
+
+  var methodName =
+      'on' + data.verb.substr(0, 1).toUpperCase() + data.verb.substr(1) + '_';
+
+  if (!(methodName in this)) {
+    console.error('Unknown message from metadata reader: ' + data.verb, data);
+    return;
+  }
+
+  this[methodName].apply(this, data.arguments);
+};
+
+/**
+ * @return {boolean} Whether provider is ready.
+ */
+ContentProvider.prototype.isInitialized = function() {
+  return this.initialized_;
+};
+
+/**
+ * Handles the 'initialized' message from the metadata reader Worker.
+ * @param {Object} regexp Regexp of supported urls.
+ * @private
+ */
+ContentProvider.prototype.onInitialized_ = function(regexp) {
+  this.urlFilter_ = regexp;
+
+  // Tests can monitor for this state with
+  // ExtensionTestMessageListener listener("worker-initialized");
+  // ASSERT_TRUE(listener.WaitUntilSatisfied());
+  // Automated tests need to wait for this, otherwise we crash in
+  // browser_test cleanup because the worker process still has
+  // URL requests in-flight.
+  var test = chrome.test || window.top.chrome.test;
+  test.sendMessage('worker-initialized');
+  this.initialized_ = true;
+};
+
+/**
+ * Converts content metadata from parsers to the internal format.
+ * @param {Object} metadata The content metadata.
+ * @param {Object=} opt_result The internal metadata object ot put result in.
+ * @return {Object!} Converted metadata.
+ */
+ContentProvider.ConvertContentMetadata = function(metadata, opt_result) {
+  var result = opt_result || {};
+
+  if ('thumbnailURL' in metadata) {
+    metadata.thumbnailTransform = metadata.thumbnailTransform || null;
+    result.thumbnail = {
+      url: metadata.thumbnailURL,
+      transform: metadata.thumbnailTransform
+    };
+  }
+
+  for (var key in metadata) {
+    if (metadata.hasOwnProperty(key)) {
+      if (!('media' in result)) result.media = {};
+      result.media[key] = metadata[key];
+    }
+  }
+
+  if ('media' in result) {
+    result.fetchedMedia = result.media;
+  }
+
+  return result;
+};
+
+/**
+ * Handles the 'result' message from the worker.
+ * @param {string} url File url.
+ * @param {Object} metadata The metadata.
+ * @private
+ */
+ContentProvider.prototype.onResult_ = function(url, metadata) {
+  var callback = this.callbacks_[url];
+  delete this.callbacks_[url];
+  callback(ContentProvider.ConvertContentMetadata(metadata));
+};
+
+/**
+ * Handles the 'error' message from the worker.
+ * @param {string} url File url.
+ * @param {string} step Step failed.
+ * @param {string} error Error description.
+ * @param {Object?} metadata The metadata, if available.
+ * @private
+ */
+ContentProvider.prototype.onError_ = function(url, step, error, metadata) {
+  if (MetadataCache.log)  // Avoid log spam by default.
+    console.warn('metadata: ' + url + ': ' + step + ': ' + error);
+  metadata = metadata || {};
+  // Prevent asking for thumbnail again.
+  metadata.thumbnailURL = '';
+  this.onResult_(url, metadata);
+};
+
+/**
+ * Handles the 'log' message from the worker.
+ * @param {Array.<*>} arglist Log arguments.
+ * @private
+ */
+ContentProvider.prototype.onLog_ = function(arglist) {
+  if (MetadataCache.log)  // Avoid log spam by default.
+    console.log.apply(console, ['metadata:'].concat(arglist));
+};
diff --git a/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js b/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js
new file mode 100644
index 0000000..b711d75
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js
@@ -0,0 +1,226 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+// All of these scripts could be imported with a single call to importScripts,
+// but then load and compile time errors would all be reported from the same
+// line.
+importScripts('metadata_parser.js');
+importScripts('byte_reader.js');
+importScripts('../../../common/js/util.js');
+
+/**
+ * Dispatches metadata requests to the correct parser.
+ *
+ * @param {Object} port Worker port.
+ * @constructor
+ */
+function MetadataDispatcher(port) {
+  this.port_ = port;
+  this.port_.onmessage = this.onMessage.bind(this);
+
+  // Make sure to update component_extension_resources.grd
+  // when adding new parsers.
+  importScripts('exif_parser.js');
+  importScripts('image_parsers.js');
+  importScripts('mpeg_parser.js');
+  importScripts('id3_parser.js');
+
+  var patterns = [];
+
+  this.parserInstances_ = [];
+  for (var i = 0; i < MetadataDispatcher.parserClasses_.length; i++) {
+    var parserClass = MetadataDispatcher.parserClasses_[i];
+    var parser = new parserClass(this);
+    this.parserInstances_.push(parser);
+    patterns.push(parser.urlFilter.source);
+  }
+
+  this.parserRegexp_ = new RegExp('(' + patterns.join('|') + ')', 'i');
+
+  this.messageHandlers_ = {
+    init: this.init_.bind(this),
+    request: this.request_.bind(this)
+  };
+}
+
+/**
+ * List of registered parser classes.
+ * @private
+ */
+MetadataDispatcher.parserClasses_ = [];
+
+/**
+ * @param {function} parserClass Parser constructor function.
+ */
+MetadataDispatcher.registerParserClass = function(parserClass) {
+  MetadataDispatcher.parserClasses_.push(parserClass);
+};
+
+/**
+ * Verbose logging for the dispatcher.
+ *
+ * Individual parsers also take this as their default verbosity setting.
+ */
+MetadataDispatcher.prototype.verbose = false;
+
+/**
+ * |init| message handler.
+ * @private
+ */
+MetadataDispatcher.prototype.init_ = function() {
+  // Inform our owner that we're done initializing.
+  // If we need to pass more data back, we can add it to the param array.
+  this.postMessage('initialized', [this.parserRegexp_]);
+  this.log('initialized with URL filter ' + this.parserRegexp_);
+};
+
+/**
+ * |request| message handler.
+ * @param {string} fileURL File URL.
+ * @private
+ */
+MetadataDispatcher.prototype.request_ = function(fileURL) {
+  try {
+    this.processOneFile(fileURL, function callback(metadata) {
+        this.postMessage('result', [fileURL, metadata]);
+    }.bind(this));
+  } catch (ex) {
+    this.error(fileURL, ex);
+  }
+};
+
+/**
+ * Indicate to the caller that an operation has failed.
+ *
+ * No other messages relating to the failed operation should be sent.
+ * @param {...Object} var_args Arguments.
+ */
+MetadataDispatcher.prototype.error = function(var_args) {
+  var ary = Array.apply(null, arguments);
+  this.postMessage('error', ary);
+};
+
+/**
+ * Send a log message to the caller.
+ *
+ * Callers must not parse log messages for control flow.
+ * @param {...Object} var_args Arguments.
+ */
+MetadataDispatcher.prototype.log = function(var_args) {
+  var ary = Array.apply(null, arguments);
+  this.postMessage('log', ary);
+};
+
+/**
+ * Send a log message to the caller only if this.verbose is true.
+ * @param {...Object} var_args Arguments.
+ */
+MetadataDispatcher.prototype.vlog = function(var_args) {
+  if (this.verbose)
+    this.log.apply(this, arguments);
+};
+
+/**
+ * Post a properly formatted message to the caller.
+ * @param {string} verb Message type descriptor.
+ * @param {Array.<Object>} args Arguments array.
+ */
+MetadataDispatcher.prototype.postMessage = function(verb, args) {
+  this.port_.postMessage({verb: verb, arguments: args});
+};
+
+/**
+ * Message handler.
+ * @param {Event} event Event object.
+ */
+MetadataDispatcher.prototype.onMessage = function(event) {
+  var data = event.data;
+
+  if (this.messageHandlers_.hasOwnProperty(data.verb)) {
+    this.messageHandlers_[data.verb].apply(this, data.arguments);
+  } else {
+    this.log('Unknown message from client: ' + data.verb, data);
+  }
+};
+
+/**
+ * @param {string} fileURL File URL.
+ * @param {function(Object)} callback Completion callback.
+ */
+MetadataDispatcher.prototype.processOneFile = function(fileURL, callback) {
+  var self = this;
+  var currentStep = -1;
+
+  function nextStep(var_args) {
+    self.vlog('nextStep: ' + steps[currentStep + 1].name);
+    steps[++currentStep].apply(self, arguments);
+  }
+
+  var metadata;
+
+  function onError(err, stepName) {
+    self.error(fileURL, stepName || steps[currentStep].name, err.toString(),
+        metadata);
+  }
+
+  var steps =
+  [ // Step one, find the parser matching the url.
+    function detectFormat() {
+      for (var i = 0; i != self.parserInstances_.length; i++) {
+        var parser = self.parserInstances_[i];
+        if (fileURL.match(parser.urlFilter)) {
+          // Create the metadata object as early as possible so that we can
+          // pass it with the error message.
+          metadata = parser.createDefaultMetadata();
+          nextStep(parser);
+          return;
+        }
+      }
+      onError('unsupported format');
+    },
+
+    // Step two, turn the url into an entry.
+    function getEntry(parser) {
+      webkitResolveLocalFileSystemURL(
+          fileURL,
+          function(entry) { nextStep(entry, parser) },
+          onError);
+    },
+
+    // Step three, turn the entry into a file.
+    function getFile(entry, parser) {
+      entry.file(function(file) { nextStep(file, parser) }, onError);
+    },
+
+    // Step four, parse the file content.
+    function parseContent(file, parser) {
+      metadata.fileSize = file.size;
+      try {
+        parser.parse(file, metadata, callback, onError);
+      } catch (e) {
+        onError(e.stack);
+      }
+    }
+  ];
+
+  nextStep();
+};
+
+// Webworker spec says that the worker global object is called self.  That's
+// a terrible name since we use it all over the chrome codebase to capture
+// the 'this' keyword in lambdas.
+var global = self;
+
+if (global.constructor.name == 'SharedWorkerGlobalScope') {
+  global.addEventListener('connect', function(e) {
+    var port = e.ports[0];
+    new MetadataDispatcher(port);
+    port.start();
+  });
+} else {
+  // Non-shared worker.
+  new MetadataDispatcher(global);
+}
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_parser.js b/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_parser.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/metadata_parser.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/metadata_parser.js
diff --git a/chrome/browser/resources/file_manager/js/metadata/mpeg_parser.js b/chrome/browser/resources/file_manager/foreground/js/metadata/mpeg_parser.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metadata/mpeg_parser.js
rename to chrome/browser/resources/file_manager/foreground/js/metadata/mpeg_parser.js
diff --git a/chrome/browser/resources/file_manager/js/metrics.js b/chrome/browser/resources/file_manager/foreground/js/metrics.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/metrics.js
rename to chrome/browser/resources/file_manager/foreground/js/metrics.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js b/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js
new file mode 100644
index 0000000..713df5f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js
@@ -0,0 +1,348 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Entry of NavigationListModel. This constructor should be called only from
+ * the helper methods (NavigationModelItem.createFromPath/createFromEntry).
+ *
+ * @param {string} path Path.
+ * @param {DirectoryEntry} entry Entry. Can be null.
+ * @constructor
+ */
+function NavigationModelItem(path, entry) {
+  this.path_ = path;
+  this.entry_ = entry;
+  this.resolvingQueue_ = new AsyncUtil.Queue();
+
+  Object.seal(this);
+}
+
+NavigationModelItem.prototype = {
+  get path() { return this.path_; },
+};
+
+/**
+ * Returns the cached entry of the item. This may return NULL if the target is
+ * not available on the filesystem, is not resolved or is under resolving the
+ * entry.
+ *
+ * @return {Entry} Cached entry.
+ */
+NavigationModelItem.prototype.getCachedEntry = function() {
+  return this.entry_;
+};
+
+/**
+ * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
+ * @param {string} path Path.
+ * @param {function(FileError)} errorCallback Called when the resolving is
+ *     failed with the error.
+ * @return {NavigationModelItem} Created NavigationModelItem.
+ */
+NavigationModelItem.createFromPath = function(
+    volumeManager, path, errorCallback) {
+  var item = new NavigationModelItem(path, null);
+  item.resolvingQueue_.run(function(continueCallback) {
+    volumeManager.resolvePath(
+        path,
+        function(entry) {
+          if (entry.isDirectory)
+            item.entry_ = entry;
+          else
+            errorCallback(util.createFileError(FileError.TYPE_MISMATCH_ERR));
+          continueCallback();
+        },
+        function(error) {
+          errorCallback(error);
+          continueCallback();
+        });
+  });
+  return item;
+};
+
+/**
+ * @param {DirectoryEntry} entry Entry. Can be null.
+ * @return {NavigationModelItem} Created NavigationModelItem.
+ */
+NavigationModelItem.createFromEntry = function(entry) {
+  if (!entry)
+    return null;
+  return new NavigationModelItem(entry.fullPath, entry);
+};
+
+/**
+ * Retrieves the entry. If the entry is being retrieved, waits until it
+ * finishes.
+ * @param {function(Entry)} callback Called with the resolved entry. The entry
+ *     may be NULL if resolving is failed.
+ */
+NavigationModelItem.prototype.getEntryAsync = function(callback) {
+  // If resolving the entry is running, wait until it finishes.
+  this.resolvingQueue_.run(function(continueCallback) {
+    callback(this.entry_);
+    continueCallback();
+  }.bind(this));
+};
+
+/**
+ * Returns if this item is a shortcut or a volume root.
+ * @return {boolean} True if a shortcut, false if a volume root.
+ */
+NavigationModelItem.prototype.isShortcut = function() {
+  return !PathUtil.isRootPath(this.path_);
+};
+
+/**
+ * A navigation list model. This model combines the 2 lists.
+ * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
+ * @param {cr.ui.ArrayDataModel} shortcutListModel The list of folder shortcut.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+function NavigationListModel(volumeManager, shortcutListModel) {
+  cr.EventTarget.call(this);
+
+  this.volumeManager_ = volumeManager;
+  this.shortcutListModel_ = shortcutListModel;
+
+  var volumeInfoToModelItem = function(volumeInfo) {
+    if (volumeInfo.volumeType == util.VolumeType.DRIVE) {
+      // For drive volume, we assign the path to "My Drive".
+      return NavigationModelItem.createFromPath(
+          this.volumeManager_,
+          volumeInfo.mountPath + '/root',
+          function() {});
+    } else {
+      return NavigationModelItem.createFromEntry(volumeInfo.root);
+    }
+  }.bind(this);
+
+  var pathToModelItem = function(path) {
+    var item = NavigationModelItem.createFromPath(
+        this.volumeManager_,
+        path,
+        function(error) {
+          if (error.code == FileError.NOT_FOUND_ERR)
+            this.onItemNotFoundError(item);
+         }.bind(this));
+    return item;
+  }.bind(this);
+
+  /**
+   * Type of updated list.
+   * @enum {number}
+   * @const
+   */
+  var ListType = {
+    VOLUME_LIST: 1,
+    SHORTCUT_LIST: 2
+  };
+  Object.freeze(ListType);
+
+  // Generates this.volumeList_ and this.shortcutList_ from the models.
+  this.volumeList_ =
+      this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem);
+
+  this.shortcutList_ = [];
+  for (var i = 0; i < this.shortcutListModel_.length; i++) {
+    var shortcutPath = this.shortcutListModel_.item(i);
+    var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
+        RootDirectory.DRIVE :
+        PathUtil.getRootPath(shortcutPath);
+    var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
+    var isMounted = volumeInfo && !volumeInfo.error;
+    if (isMounted)
+      this.shortcutList_.push(pathToModelItem(shortcutPath));
+  }
+
+  // Generates a combined 'permuted' event from an event of either list.
+  var permutedHandler = function(listType, event) {
+    var permutation;
+
+    // Build the volumeList.
+    if (listType == ListType.VOLUME_LIST) {
+      // The volume is mounted or unmounted.
+      var newList = [];
+
+      // Use the old instances if they just move.
+      for (var i = 0; i < event.permutation.length; i++) {
+        if (event.permutation[i] >= 0)
+          newList[event.permutation[i]] = this.volumeList_[i];
+      }
+
+      // Create missing instances.
+      for (var i = 0; i < event.newLength; i++) {
+        if (!newList[i]) {
+          newList[i] = volumeInfoToModelItem(
+              this.volumeManager_.volumeInfoList.item(i));
+        }
+      }
+      this.volumeList_ = newList;
+
+      permutation = event.permutation.slice();
+    } else {
+      // volumeList part has not been changed, so the permutation should be
+      // idenetity mapping.
+      permutation = [];
+      for (var i = 0; i < this.volumeList_.length; i++)
+        permutation[i] = i;
+    }
+
+    // Build the shortcutList. Even if the event is for the volumeInfoList
+    // update, the short cut path may be unmounted or newly mounted. So, here
+    // shortcutList will always be re-built.
+    // Currently this code may be redundant, as shortcut folder is supported
+    // only on Drive File System and we can assume single-profile, but
+    // multi-profile will be supported later.
+    // The shortcut list is sorted in case-insensitive lexicographical order.
+    // So we just can traverse the two list linearly.
+    var modelIndex = 0;
+    var oldListIndex = 0;
+    var newList = [];
+    while (modelIndex < this.shortcutListModel_.length &&
+           oldListIndex < this.shortcutList_.length) {
+      var shortcutPath = this.shortcutListModel_.item(modelIndex);
+      var cmp = this.shortcutListModel_.compare(
+          shortcutPath, this.shortcutList_[oldListIndex].path);
+      if (cmp > 0) {
+        // The shortcut at shortcutList_[oldListIndex] is removed.
+        permutation.push(-1);
+        oldListIndex++;
+        continue;
+      }
+
+      // Check if the volume where the shortcutPath is is mounted or not.
+      var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
+          RootDirectory.DRIVE :
+          PathUtil.getRootPath(shortcutPath);
+      var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
+      var isMounted = volumeInfo && !volumeInfo.error;
+      if (cmp == 0) {
+        // There exists an old NavigationModelItem instance.
+        if (isMounted) {
+          // Reuse the old instance.
+          permutation.push(newList.length + this.volumeList_.length);
+          newList.push(this.shortcutList_[oldListIndex]);
+        } else {
+          permutation.push(-1);
+        }
+        oldListIndex++;
+      } else {
+        // We needs to create a new instance for the shortcut path.
+        if (isMounted)
+          newList.push(pathToModelItem(shortcutPath));
+      }
+      modelIndex++;
+    }
+
+    // Add remaining (new) shortcuts if necessary.
+    for (; modelIndex < this.shortcutListModel_.length; modelIndex++) {
+      var shortcutPath = this.shortcutListModel_.item(modelIndex);
+      var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
+          RootDirectory.DRIVE :
+          PathUtil.getRootPath(shortcutPath);
+      var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
+      var isMounted = volumeInfo && !volumeInfo.error;
+      if (isMounted)
+        newList.push(pathToModelItem(shortcutPath));
+    }
+
+    // Fill remaining permutation if necessary.
+    for (; oldListIndex < this.shortcutList_.length; oldListIndex++)
+      permutation.push(-1);
+
+    this.shortcutList_ = newList;
+
+    // Dispatch permuted event.
+    var permutedEvent = new Event('permuted');
+    permutedEvent.newLength =
+        this.volumeList_.length + this.shortcutList_.length;
+    permutedEvent.permutation = permutation;
+    this.dispatchEvent(permutedEvent);
+  };
+
+  this.volumeManager_.volumeInfoList.addEventListener(
+      'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST));
+  this.shortcutListModel_.addEventListener(
+      'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST));
+
+  // 'change' event is just ignored, because it is not fired neither in
+  // the folder shortcut list nor in the volume info list.
+  // 'splice' and 'sorted' events are not implemented, since they are not used
+  // in list.js.
+}
+
+/**
+ * NavigationList inherits cr.EventTarget.
+ */
+NavigationListModel.prototype = {
+  __proto__: cr.EventTarget.prototype,
+  get length() { return this.length_(); },
+  get folderShortcutList() { return this.shortcutList_; }
+};
+
+/**
+ * Returns the item at the given index.
+ * @param {number} index The index of the entry to get.
+ * @return {?string} The path at the given index.
+ */
+NavigationListModel.prototype.item = function(index) {
+  var offset = this.volumeList_.length;
+  if (index < offset)
+    return this.volumeList_[index];
+  return this.shortcutList_[index - offset];
+};
+
+/**
+ * Returns the number of items in the model.
+ * @return {number} The length of the model.
+ * @private
+ */
+NavigationListModel.prototype.length_ = function() {
+  return this.volumeList_.length + this.shortcutList_.length;
+};
+
+/**
+ * Returns the first matching item.
+ * @param {NavigationModelItem} modelItem The entry to find.
+ * @param {number=} opt_fromIndex If provided, then the searching start at
+ *     the {@code opt_fromIndex}.
+ * @return {number} The index of the first found element or -1 if not found.
+ */
+NavigationListModel.prototype.indexOf = function(modelItem, opt_fromIndex) {
+  for (var i = opt_fromIndex || 0; i < this.length; i++) {
+    if (modelItem === this.item(i))
+      return i;
+  }
+  return -1;
+};
+
+/**
+ * Called when one od the items is not found on the filesystem.
+ * @param {NavigationModelItem} modelItem The entry which is not found.
+ */
+NavigationListModel.prototype.onItemNotFoundError = function(modelItem) {
+  var index = this.indexOf(modelItem);
+  if (index === -1) {
+    // Invalid modelItem.
+  } else if (index < this.volumeList_.length) {
+    // The item is in the volume list.
+    // Not implemented.
+    // TODO(yoshiki): Implement it when necessary.
+  } else {
+    // The item is in the folder shortcut list.
+    if (this.isDriveMounted())
+      this.shortcutListModel_.remove(modelItem.path);
+  }
+};
+
+/**
+ * Returns if the drive is mounted or not.
+ * @return {boolean} True if the drive is mounted, false otherwise.
+ */
+NavigationListModel.prototype.isDriveMounted = function() {
+  return !!this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
+};
diff --git a/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js b/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js
new file mode 100644
index 0000000..b54221c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js
@@ -0,0 +1,871 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Called from the main frame when unloading.
+ * @return {string?} User-visible message on null if it is OK to close.
+ */
+function beforeunload() { return Gallery.instance.onBeforeUnload() }
+
+/**
+ * Called from the main frame when unloading.
+ * @param {boolean=} opt_exiting True if the app is exiting.
+ */
+function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting) }
+
+/**
+ * Gallery for viewing and editing image files.
+ *
+ * @param {Object} context Object containing the following:
+ *     {function(string)} onNameChange Called every time a selected
+ *         item name changes (on rename and on selection change).
+ *     {AppWindow} appWindow
+ *     {function(string)} onBack
+ *     {function()} onClose
+ *     {function()} onMaximize
+ *     {function(boolean)} onAppRegionChanged
+ *     {MetadataCache} metadataCache
+ *     {Array.<Object>} shareActions
+ *     {string} readonlyDirName Directory name for readonly warning or null.
+ *     {DirEntry} saveDirEntry Directory to save to.
+ *     {function(string)} displayStringFunction.
+ * @param {VolumeManagerWrapper} volumeManager The VolumeManager instance of
+ *      the system.
+ * @class
+ * @constructor
+ */
+function Gallery(context, volumeManager) {
+  this.container_ = document.querySelector('.gallery');
+  this.document_ = document;
+  this.context_ = context;
+  this.metadataCache_ = context.metadataCache;
+  this.volumeManager_ = volumeManager;
+
+  this.dataModel_ = new cr.ui.ArrayDataModel([]);
+  this.selectionModel_ = new cr.ui.ListSelectionModel();
+  this.displayStringFunction_ = context.displayStringFunction;
+
+  this.initDom_();
+  this.initListeners_();
+}
+
+/**
+ * Gallery extends cr.EventTarget.
+ */
+Gallery.prototype.__proto__ = cr.EventTarget.prototype;
+
+/**
+ * Create and initialize a Gallery object based on a context.
+ *
+ * @param {Object} context Gallery context.
+ * @param {VolumeManagerWrapper} volumeManager VolumeManager of the system.
+ * @param {Array.<string>} urls Array of urls.
+ * @param {Array.<string>} selectedUrls Array of selected urls.
+ */
+Gallery.open = function(context, volumeManager, urls, selectedUrls) {
+  Gallery.instance = new Gallery(context, volumeManager);
+  Gallery.instance.load(urls, selectedUrls);
+};
+
+/**
+ * Tools fade-out timeout im milliseconds.
+ * @const
+ * @type {number}
+ */
+Gallery.FADE_TIMEOUT = 3000;
+
+/**
+ * First time tools fade-out timeout im milliseconds.
+ * @const
+ * @type {number}
+ */
+Gallery.FIRST_FADE_TIMEOUT = 1000;
+
+/**
+ * Time until mosaic is initialized in the background. Used to make gallery
+ * in the slide mode load faster. In miiliseconds.
+ * @const
+ * @type {number}
+ */
+Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000;
+
+/**
+ * Types of metadata Gallery uses (to query the metadata cache).
+ * @const
+ * @type {string}
+ */
+Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|streaming|drive';
+
+/**
+ * Initialize listeners.
+ * @private
+ */
+Gallery.prototype.initListeners_ = function() {
+  this.document_.oncontextmenu = function(e) { e.preventDefault(); };
+  this.keyDownBound_ = this.onKeyDown_.bind(this);
+  this.document_.body.addEventListener('keydown', this.keyDownBound_);
+
+  this.inactivityWatcher_ = new MouseInactivityWatcher(
+      this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this));
+
+  // Search results may contain files from different subdirectories so
+  // the observer is not going to work.
+  if (!this.context_.searchResults && this.context_.curDirEntry) {
+    this.thumbnailObserverId_ = this.metadataCache_.addObserver(
+        this.context_.curDirEntry,
+        MetadataCache.CHILDREN,
+        'thumbnail',
+        this.updateThumbnails_.bind(this));
+  }
+
+  this.volumeManager_.addEventListener('externally-unmounted',
+      this.onExternallyUnmounted_.bind(this));
+};
+
+/**
+ * Closes gallery when a volume containing the selected item is unmounted.
+ * @param {Event} event The unmount event.
+ * @private
+ */
+Gallery.prototype.onExternallyUnmounted_ = function(event) {
+  if (!this.selectedItemFilesystemPath_)
+    return;
+  if (this.selectedItemFilesystemPath_.indexOf(event.mountPath) == 0)
+    this.onBack_();
+};
+
+/**
+ * Beforeunload handler.
+ * @return {string?} User-visible message on null if it is OK to close.
+ */
+Gallery.prototype.onBeforeUnload = function() {
+  return this.slideMode_.onBeforeUnload();
+};
+
+/**
+ * Unload the Gallery.
+ * @param {boolean} exiting True if the app is exiting.
+ */
+Gallery.prototype.onUnload = function(exiting) {
+  if (!this.context_.searchResults) {
+    this.metadataCache_.removeObserver(this.thumbnailObserverId_);
+  }
+  this.slideMode_.onUnload(exiting);
+};
+
+/**
+ * Initializes DOM UI
+ * @private
+ */
+Gallery.prototype.initDom_ = function() {
+  var content = util.createChild(this.container_, 'content');
+  content.addEventListener('click', this.onContentClick_.bind(this));
+
+  this.header_ = util.createChild(this.container_, 'header tool dimmable');
+  this.toolbar_ = util.createChild(this.container_, 'toolbar tool dimmable');
+
+  var backButton = util.createChild(this.container_,
+                                    'back-button tool dimmable');
+  util.createChild(backButton);
+  backButton.addEventListener('click', this.onBack_.bind(this));
+
+  var preventDefault = function(event) { event.preventDefault(); };
+
+  var maximizeButton = util.createChild(this.header_,
+                                        'maximize-button tool dimmable',
+                                        'button');
+  maximizeButton.tabIndex = -1;
+  maximizeButton.addEventListener('click', this.onMaximize_.bind(this));
+  maximizeButton.addEventListener('mousedown', preventDefault);
+
+  var closeButton = util.createChild(this.header_,
+                                     'close-button tool dimmable',
+                                     'button');
+  closeButton.tabIndex = -1;
+  closeButton.addEventListener('click', this.onClose_.bind(this));
+  closeButton.addEventListener('mousedown', preventDefault);
+
+  this.filenameSpacer_ = util.createChild(this.toolbar_, 'filename-spacer');
+  this.filenameEdit_ = util.createChild(this.filenameSpacer_,
+                                        'namebox', 'input');
+
+  this.filenameEdit_.setAttribute('type', 'text');
+  this.filenameEdit_.addEventListener('blur',
+      this.onFilenameEditBlur_.bind(this));
+
+  this.filenameEdit_.addEventListener('focus',
+      this.onFilenameFocus_.bind(this));
+
+  this.filenameEdit_.addEventListener('keydown',
+      this.onFilenameEditKeydown_.bind(this));
+
+  util.createChild(this.toolbar_, 'button-spacer');
+
+  this.prompt_ = new ImageEditor.Prompt(
+      this.container_, this.displayStringFunction_);
+
+  this.modeButton_ = util.createChild(this.toolbar_, 'button mode', 'button');
+  this.modeButton_.addEventListener('click',
+      this.toggleMode_.bind(this, null));
+
+  this.mosaicMode_ = new MosaicMode(content,
+                                    this.dataModel_,
+                                    this.selectionModel_,
+                                    this.metadataCache_,
+                                    this.toggleMode_.bind(this, null));
+
+  this.slideMode_ = new SlideMode(this.container_,
+                                  content,
+                                  this.toolbar_,
+                                  this.prompt_,
+                                  this.dataModel_,
+                                  this.selectionModel_,
+                                  this.context_,
+                                  this.toggleMode_.bind(this),
+                                  this.displayStringFunction_);
+
+  this.slideMode_.addEventListener('image-displayed', function() {
+    cr.dispatchSimpleEvent(this, 'image-displayed');
+  }.bind(this));
+  this.slideMode_.addEventListener('image-saved', function() {
+    cr.dispatchSimpleEvent(this, 'image-saved');
+  }.bind(this));
+
+  var deleteButton = this.createToolbarButton_('delete', 'GALLERY_DELETE');
+  deleteButton.addEventListener('click', this.delete_.bind(this));
+
+  this.shareButton_ = this.createToolbarButton_('share', 'GALLERY_SHARE');
+  this.shareButton_.setAttribute('disabled', '');
+  this.shareButton_.addEventListener('click', this.toggleShare_.bind(this));
+
+  this.shareMenu_ = util.createChild(this.container_, 'share-menu');
+  this.shareMenu_.hidden = true;
+  util.createChild(this.shareMenu_, 'bubble-point');
+
+  this.dataModel_.addEventListener('splice', this.onSplice_.bind(this));
+  this.dataModel_.addEventListener('content', this.onContentChange_.bind(this));
+
+  this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
+  this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this));
+};
+
+/**
+ * Creates toolbar button.
+ *
+ * @param {string} className Class to add.
+ * @param {string} title Button title.
+ * @return {HTMLElement} Newly created button.
+ * @private
+ */
+Gallery.prototype.createToolbarButton_ = function(className, title) {
+  var button = util.createChild(this.toolbar_, className, 'button');
+  button.title = this.displayStringFunction_(title);
+  return button;
+};
+
+/**
+ * Load the content.
+ *
+ * @param {Array.<string>} urls Array of urls.
+ * @param {Array.<string>} selectedUrls Array of selected urls.
+ */
+Gallery.prototype.load = function(urls, selectedUrls) {
+  var items = [];
+  for (var index = 0; index < urls.length; ++index) {
+    items.push(new Gallery.Item(urls[index]));
+  }
+  this.dataModel_.push.apply(this.dataModel_, items);
+
+  this.selectionModel_.adjustLength(this.dataModel_.length);
+
+  for (var i = 0; i != selectedUrls.length; i++) {
+    var selectedIndex = urls.indexOf(selectedUrls[i]);
+    if (selectedIndex >= 0)
+      this.selectionModel_.setIndexSelected(selectedIndex, true);
+    else
+      console.error('Cannot select ' + selectedUrls[i]);
+  }
+
+  if (this.selectionModel_.selectedIndexes.length == 0)
+    this.onSelection_();
+
+  var mosaic = this.mosaicMode_ && this.mosaicMode_.getMosaic();
+
+  // Mosaic view should show up if most of the selected files are images.
+  var imagesCount = 0;
+  for (var i = 0; i != selectedUrls.length; i++) {
+    if (FileType.getMediaType(selectedUrls[i]) == 'image')
+      imagesCount++;
+  }
+  var mostlyImages = imagesCount > (selectedUrls.length / 2.0);
+
+  var forcedMosaic = (this.context_.pageState &&
+       this.context_.pageState.gallery == 'mosaic');
+
+  var showMosaic = (mostlyImages && selectedUrls.length > 1) || forcedMosaic;
+  if (mosaic && showMosaic) {
+    this.setCurrentMode_(this.mosaicMode_);
+    mosaic.init();
+    mosaic.show();
+    this.inactivityWatcher_.check();  // Show the toolbar.
+    cr.dispatchSimpleEvent(this, 'loaded');
+  } else {
+    this.setCurrentMode_(this.slideMode_);
+    var maybeLoadMosaic = function() {
+      if (mosaic)
+        mosaic.init();
+      cr.dispatchSimpleEvent(this, 'loaded');
+    }.bind(this);
+    /* TODO: consider nice blow-up animation for the first image */
+    this.slideMode_.enter(null, function() {
+        // Flash the toolbar briefly to show it is there.
+        this.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT);
+      }.bind(this),
+      maybeLoadMosaic);
+  }
+};
+
+/**
+ * Close the Gallery and go to Files.app.
+ * @private
+ */
+Gallery.prototype.back_ = function() {
+  if (util.isFullScreen(this.context_.appWindow)) {
+    util.toggleFullScreen(this.context_.appWindow,
+                          false);  // Leave the full screen mode.
+  }
+  this.context_.onBack(this.getSelectedUrls());
+};
+
+/**
+ * Handle user's 'Back' action (Escape or a click on the X icon).
+ * @private
+ */
+Gallery.prototype.onBack_ = function() {
+  this.executeWhenReady(this.back_.bind(this));
+};
+
+/**
+ * Handle user's 'Close' action.
+ * @private
+ */
+Gallery.prototype.onClose_ = function() {
+  this.executeWhenReady(this.context_.onClose);
+};
+
+/**
+ * Handle user's 'Maximize' action (Escape or a click on the X icon).
+ * @private
+ */
+Gallery.prototype.onMaximize_ = function() {
+  this.executeWhenReady(this.context_.onMaximize);
+};
+
+/**
+ * Execute a function when the editor is done with the modifications.
+ * @param {function} callback Function to execute.
+ */
+Gallery.prototype.executeWhenReady = function(callback) {
+  this.currentMode_.executeWhenReady(callback);
+};
+
+/**
+ * @return {Object} File browser private API.
+ */
+Gallery.getFileBrowserPrivate = function() {
+  return chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate;
+};
+
+/**
+ * @return {boolean} True if some tool is currently active.
+ */
+Gallery.prototype.hasActiveTool = function() {
+  return this.currentMode_.hasActiveTool() ||
+      this.isSharing_() || this.isRenaming_();
+};
+
+/**
+* External user action event handler.
+* @private
+*/
+Gallery.prototype.onUserAction_ = function() {
+  this.closeShareMenu_();
+  // Show the toolbar and hide it after the default timeout.
+  this.inactivityWatcher_.kick();
+};
+
+/**
+ * Set the current mode, update the UI.
+ * @param {Object} mode Current mode.
+ * @private
+ */
+Gallery.prototype.setCurrentMode_ = function(mode) {
+  if (mode != this.slideMode_ && mode != this.mosaicMode_)
+    console.error('Invalid Gallery mode');
+
+  this.currentMode_ = mode;
+  this.container_.setAttribute('mode', this.currentMode_.getName());
+  this.updateSelectionAndState_();
+  this.updateButtons_();
+};
+
+/**
+ * Mode toggle event handler.
+ * @param {function=} opt_callback Callback.
+ * @param {Event=} opt_event Event that caused this call.
+ * @private
+ */
+Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) {
+  if (!this.modeButton_)
+    return;
+
+  if (this.changingMode_) // Do not re-enter while changing the mode.
+    return;
+
+  if (opt_event)
+    this.onUserAction_();
+
+  this.changingMode_ = true;
+
+  var onModeChanged = function() {
+    this.changingMode_ = false;
+    if (opt_callback) opt_callback();
+  }.bind(this);
+
+  var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
+
+  var mosaic = this.mosaicMode_.getMosaic();
+  var tileRect = mosaic.getTileRect(tileIndex);
+
+  if (this.currentMode_ == this.slideMode_) {
+    this.setCurrentMode_(this.mosaicMode_);
+    mosaic.transform(
+        tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
+    this.slideMode_.leave(tileRect,
+        function() {
+          // Animate back to normal position.
+          mosaic.transform();
+          mosaic.show();
+          onModeChanged();
+        }.bind(this));
+  } else {
+    this.setCurrentMode_(this.slideMode_);
+    this.slideMode_.enter(tileRect,
+        function() {
+          // Animate to zoomed position.
+          mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
+          mosaic.hide();
+        }.bind(this),
+        onModeChanged);
+  }
+};
+
+/**
+ * Deletes the selected items.
+ * @private
+ */
+Gallery.prototype.delete_ = function() {
+  this.onUserAction_();
+
+  // Clone the sorted selected indexes array.
+  var indexesToRemove = this.selectionModel_.selectedIndexes.slice();
+  if (!indexesToRemove.length)
+    return;
+
+  /* TODO(dgozman): Implement Undo delete, Remove the confirmation dialog. */
+
+  var itemsToRemove = this.getSelectedItems();
+  var plural = itemsToRemove.length > 1;
+  var param = plural ? itemsToRemove.length : itemsToRemove[0].getFileName();
+
+  function deleteNext() {
+    if (!itemsToRemove.length)
+      return;  // All deleted.
+
+    var url = itemsToRemove.pop().getUrl();
+    webkitResolveLocalFileSystemURL(url,
+        function(entry) {
+          entry.remove(deleteNext,
+              util.flog('Error deleting ' + url, deleteNext));
+        },
+        util.flog('Error resolving ' + url, deleteNext));
+  }
+
+  // Prevent the Gallery from handling Esc and Enter.
+  this.document_.body.removeEventListener('keydown', this.keyDownBound_);
+  var restoreListener = function() {
+    this.document_.body.addEventListener('keydown', this.keyDownBound_);
+  }.bind(this);
+
+  cr.ui.dialogs.BaseDialog.OK_LABEL = this.displayStringFunction_(
+      'GALLERY_OK_LABEL');
+  cr.ui.dialogs.BaseDialog.CANCEL_LABEL =
+      this.displayStringFunction_('GALLERY_CANCEL_LABEL');
+  var confirm = new cr.ui.dialogs.ConfirmDialog(this.container_);
+  confirm.show(
+      this.displayStringFunction_(plural ? 'GALLERY_CONFIRM_DELETE_SOME' :
+          'GALLERY_CONFIRM_DELETE_ONE', param),
+      function() {
+        restoreListener();
+        this.selectionModel_.unselectAll();
+        this.selectionModel_.leadIndex = -1;
+        // Remove items from the data model, starting from the highest index.
+        while (indexesToRemove.length)
+          this.dataModel_.splice(indexesToRemove.pop(), 1);
+        // Delete actual files.
+        deleteNext();
+      }.bind(this),
+      function() {
+        // Restore the listener after a timeout so that ESC is processed.
+        setTimeout(restoreListener, 0);
+      });
+};
+
+/**
+ * @return {Array.<Gallery.Item>} Current selection.
+ */
+Gallery.prototype.getSelectedItems = function() {
+  return this.selectionModel_.selectedIndexes.map(
+      this.dataModel_.item.bind(this.dataModel_));
+};
+
+/**
+ * @return {Array.<string>} Array of currently selected urls.
+ */
+Gallery.prototype.getSelectedUrls = function() {
+  return this.selectionModel_.selectedIndexes.map(function(index) {
+    return this.dataModel_.item(index).getUrl();
+  }.bind(this));
+};
+
+/**
+ * @return {Gallery.Item} Current single selection.
+ */
+Gallery.prototype.getSingleSelectedItem = function() {
+  var items = this.getSelectedItems();
+  if (items.length > 1)
+    throw new Error('Unexpected multiple selection');
+  return items[0];
+};
+
+/**
+  * Selection change event handler.
+  * @private
+  */
+Gallery.prototype.onSelection_ = function() {
+  this.updateSelectionAndState_();
+  this.updateShareMenu_();
+};
+
+/**
+  * Data model splice event handler.
+  * @private
+  */
+Gallery.prototype.onSplice_ = function() {
+  this.selectionModel_.adjustLength(this.dataModel_.length);
+};
+
+/**
+ * Content change event handler.
+ * @param {Event} event Event.
+ * @private
+*/
+Gallery.prototype.onContentChange_ = function(event) {
+  var index = this.dataModel_.indexOf(event.item);
+  if (index != this.selectionModel_.selectedIndex)
+    console.error('Content changed for unselected item');
+  this.updateSelectionAndState_();
+};
+
+/**
+ * Keydown handler.
+ *
+ * @param {Event} event Event.
+ * @private
+ */
+Gallery.prototype.onKeyDown_ = function(event) {
+  var wasSharing = this.isSharing_();
+  this.closeShareMenu_();
+
+  if (this.currentMode_.onKeyDown(event))
+    return;
+
+  switch (util.getKeyModifiers(event) + event.keyIdentifier) {
+    case 'U+0008': // Backspace.
+      // The default handler would call history.back and close the Gallery.
+      event.preventDefault();
+      break;
+
+    case 'U+001B':  // Escape
+      // Swallow Esc if it closed the Share menu, otherwise close the Gallery.
+      if (!wasSharing)
+        this.onBack_();
+      break;
+
+    case 'U+004D':  // 'm' switches between Slide and Mosaic mode.
+      this.toggleMode_(null, event);
+      break;
+
+    case 'U+0056':  // 'v'
+      this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event);
+      break;
+
+    case 'U+007F':  // Delete
+    case 'Shift-U+0033':  // Shift+'3' (Delete key might be missing).
+      this.delete_();
+      break;
+  }
+};
+
+// Name box and rename support.
+
+/**
+ * Update the UI related to the selected item and the persistent state.
+ *
+ * @private
+ */
+Gallery.prototype.updateSelectionAndState_ = function() {
+  var path;
+  var displayName = '';
+
+  var selectedItems = this.getSelectedItems();
+  if (selectedItems.length == 1) {
+    var item = selectedItems[0];
+    path = util.extractFilePath(item.getUrl());
+    var fullName = item.getFileName();
+    window.top.document.title = fullName;
+    displayName = ImageUtil.getFileNameFromFullName(fullName);
+  } else if (selectedItems.length > 1 && this.context_.curDirEntry) {
+    // If the Gallery was opened on search results the search query will not be
+    // recorded in the app state and the relaunch will just open the gallery
+    // in the curDirEntry directory.
+    path = this.context_.curDirEntry.fullPath;
+    window.top.document.title = this.context_.curDirEntry.name;
+    displayName =
+        this.displayStringFunction_('GALLERY_ITEMS_SELECTED',
+                                    selectedItems.length);
+  }
+
+  window.top.util.updateAppState(path,
+      {gallery: (this.currentMode_ == this.mosaicMode_ ? 'mosaic' : 'slide')});
+
+  // We can't rename files in readonly directory.
+  // We can only rename a single file.
+  this.filenameEdit_.disabled = selectedItems.length != 1 ||
+                                this.context_.readonlyDirName;
+
+  this.filenameEdit_.value = displayName;
+
+  // Resolve real filesystem path of the current file.
+  if (this.selectionModel_.selectedIndexes.length) {
+    var selectedIndex = this.selectionModel_.selectedIndex;
+    var selectedItem =
+        this.dataModel_.item(this.selectionModel_.selectedIndex);
+
+    this.selectedItemFilesystemPath_ = null;
+    webkitResolveLocalFileSystemURL(selectedItem.getUrl(),
+      function(entry) {
+        if (this.selectionModel_.selectedIndex != selectedIndex)
+          return;
+        this.selectedItemFilesystemPath_ = entry.fullPath;
+      }.bind(this));
+  }
+};
+
+/**
+ * Click event handler on filename edit box
+ * @private
+ */
+Gallery.prototype.onFilenameFocus_ = function() {
+  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true);
+  this.filenameEdit_.originalValue = this.filenameEdit_.value;
+  setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0);
+  this.onUserAction_();
+};
+
+/**
+ * Blur event handler on filename edit box.
+ *
+ * @param {Event} event Blur event.
+ * @return {boolean} if default action should be prevented.
+ * @private
+ */
+Gallery.prototype.onFilenameEditBlur_ = function(event) {
+  if (this.filenameEdit_.value && this.filenameEdit_.value[0] == '.') {
+    this.prompt_.show('file_hidden_name', 5000);
+    this.filenameEdit_.focus();
+    event.stopPropagation();
+    event.preventDefault();
+    return false;
+  }
+
+  var item = this.getSingleSelectedItem();
+  var oldUrl = item.getUrl();
+
+  var onFileExists = function() {
+    this.prompt_.show('file_exists', 3000);
+    this.filenameEdit_.value = name;
+    this.filenameEdit_.focus();
+  }.bind(this);
+
+  var onSuccess = function() {
+    var e = new Event('content');
+    e.item = item;
+    e.oldUrl = oldUrl;
+    e.metadata = null;  // Metadata unchanged.
+    this.dataModel_.dispatchEvent(e);
+  }.bind(this);
+
+  if (this.filenameEdit_.value) {
+    this.getSingleSelectedItem().rename(
+        this.filenameEdit_.value, onSuccess, onFileExists);
+  }
+
+  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false);
+  this.onUserAction_();
+};
+
+/**
+ * Keydown event handler on filename edit box
+ * @private
+ */
+Gallery.prototype.onFilenameEditKeydown_ = function() {
+  switch (event.keyCode) {
+    case 27:  // Escape
+      this.filenameEdit_.value = this.filenameEdit_.originalValue;
+      this.filenameEdit_.blur();
+      break;
+
+    case 13:  // Enter
+      this.filenameEdit_.blur();
+      break;
+  }
+  event.stopPropagation();
+};
+
+/**
+ * @return {boolean} True if file renaming is currently in progress.
+ * @private
+ */
+Gallery.prototype.isRenaming_ = function() {
+  return this.filenameSpacer_.hasAttribute('renaming');
+};
+
+/**
+ * Content area click handler.
+ * @private
+ */
+Gallery.prototype.onContentClick_ = function() {
+  this.closeShareMenu_();
+  this.filenameEdit_.blur();
+};
+
+// Share button support.
+
+/**
+ * @return {boolean} True if the Share menu is active.
+ * @private
+ */
+Gallery.prototype.isSharing_ = function() {
+  return !this.shareMenu_.hidden;
+};
+
+/**
+ * Close Share menu if it is open.
+ * @private
+ */
+Gallery.prototype.closeShareMenu_ = function() {
+  if (this.isSharing_())
+    this.toggleShare_();
+};
+
+/**
+ * Share button handler.
+ * @private
+ */
+Gallery.prototype.toggleShare_ = function() {
+  if (!this.shareButton_.hasAttribute('disabled'))
+    this.shareMenu_.hidden = !this.shareMenu_.hidden;
+  this.inactivityWatcher_.check();
+};
+
+/**
+ * Updates available actions list based on the currently selected urls.
+ * @private.
+ */
+Gallery.prototype.updateShareMenu_ = function() {
+  var urls = this.getSelectedUrls();
+
+  function isShareAction(task) {
+    var taskParts = task.taskId.split('|');
+    return taskParts[0] != chrome.runtime.id;
+  }
+
+  var api = Gallery.getFileBrowserPrivate();
+  var mimeTypes = [];  // TODO(kaznacheev) Collect mime types properly.
+
+  var createShareMenu = function(tasks) {
+    var wasHidden = this.shareMenu_.hidden;
+    this.shareMenu_.hidden = true;
+    var items = this.shareMenu_.querySelectorAll('.item');
+    for (var i = 0; i != items.length; i++) {
+      items[i].parentNode.removeChild(items[i]);
+    }
+
+    for (var t = 0; t != tasks.length; t++) {
+      var task = tasks[t];
+      if (!isShareAction(task)) continue;
+
+      var item = util.createChild(this.shareMenu_, 'item');
+      item.textContent = task.title;
+      item.style.backgroundImage = 'url(' + task.iconUrl + ')';
+      item.addEventListener('click', function(taskId) {
+        this.toggleShare_();  // Hide the menu.
+        this.executeWhenReady(api.executeTask.bind(api, taskId, urls));
+      }.bind(this, task.taskId));
+    }
+
+    var empty = this.shareMenu_.querySelector('.item') == null;
+    ImageUtil.setAttribute(this.shareButton_, 'disabled', empty);
+    this.shareMenu_.hidden = wasHidden || empty;
+  }.bind(this);
+
+  // Create or update the share menu with a list of sharing tasks and show
+  // or hide the share button.
+  if (!urls.length)
+    createShareMenu([]);  // Empty list of tasks, since there is no selection.
+  else
+    api.getFileTasks(urls, mimeTypes, createShareMenu);
+};
+
+/**
+ * Updates thumbnails.
+ * @private
+ */
+Gallery.prototype.updateThumbnails_ = function() {
+  if (this.currentMode_ == this.slideMode_)
+    this.slideMode_.updateThumbnails();
+
+  if (this.mosaicMode_) {
+    var mosaic = this.mosaicMode_.getMosaic();
+    if (mosaic.isInitialized())
+      mosaic.reload();
+  }
+};
+
+/**
+ * Updates buttons.
+ * @private
+ */
+Gallery.prototype.updateButtons_ = function() {
+  if (this.modeButton_) {
+    var oppositeMode =
+        this.currentMode_ == this.slideMode_ ? this.mosaicMode_ :
+                                               this.slideMode_;
+    this.modeButton_.title =
+        this.displayStringFunction_(oppositeMode.getTitle());
+  }
+};
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery_item.js b/chrome/browser/resources/file_manager/foreground/js/photo/gallery_item.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/photo/gallery_item.js
rename to chrome/browser/resources/file_manager/foreground/js/photo/gallery_item.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js b/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js
new file mode 100644
index 0000000..336fa20
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 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.
+
+// The include directives are put into Javascript-style comments to prevent
+// parsing errors in non-flattened mode. The flattener still sees them.
+// Note that this makes the flattener to comment out the first line of the
+// included file but that's all right since any javascript file should start
+// with a copyright comment anyway.
+
+//<include src="../metrics.js">
+
+//<include src="../../../../image_loader/image_loader_client.js"/>
+
+//<include src="../../../../../../../ui/webui/resources/js/cr.js">
+//<include src="../../../../../../../ui/webui/resources/js/event_tracker.js">
+//<include src="../../../../../../../ui/webui/resources/js/load_time_data.js">
+
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/dialogs.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_item.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list.js">
+//<include src="../../../../../../../ui/webui/resources/js/cr/ui/grid.js">
+
+(function() {
+// 'strict mode' is invoked for this scope.
+
+//<include src="../../../common/js/async_util.js">
+//<include src="../../../common/js/util.js">
+//<include src="../../../common/js/path_util.js">
+//<include src="../file_type.js">
+//<include src="../volume_manager_wrapper.js">
+
+//<include src="../image_editor/image_util.js"/>
+//<include src="../image_editor/viewport.js"/>
+//<include src="../image_editor/image_buffer.js"/>
+//<include src="../image_editor/image_view.js"/>
+//<include src="../image_editor/commands.js"/>
+//<include src="../image_editor/image_editor.js"/>
+//<include src="../image_editor/image_transform.js"/>
+//<include src="../image_editor/image_adjust.js"/>
+//<include src="../image_editor/filter.js"/>
+//<include src="../image_editor/image_encoder.js"/>
+//<include src="../image_editor/exif_encoder.js"/>
+
+//<include src="../media/media_controls.js"/>
+//<include src="../media/media_util.js"/>
+//<include src="../media/util.js"/>
+
+//<include src="../metadata/metadata_cache.js"/>
+
+//<include src="gallery.js">
+//<include src="gallery_item.js">
+//<include src="mosaic_mode.js">
+//<include src="slide_mode.js">
+//<include src="ribbon.js">
+
+// Exports
+window.ImageUtil = ImageUtil;
+window.Gallery = Gallery;
+window.beforeunload = beforeunload;
+window.unload = unload;
+
+})();
diff --git a/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js b/chrome/browser/resources/file_manager/foreground/js/photo/mosaic_mode.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
rename to chrome/browser/resources/file_manager/foreground/js/photo/mosaic_mode.js
diff --git a/chrome/browser/resources/file_manager/js/photo/ribbon.js b/chrome/browser/resources/file_manager/foreground/js/photo/ribbon.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/photo/ribbon.js
rename to chrome/browser/resources/file_manager/foreground/js/photo/ribbon.js
diff --git a/chrome/browser/resources/file_manager/js/photo/select_album_dialog.js b/chrome/browser/resources/file_manager/foreground/js/photo/select_album_dialog.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/photo/select_album_dialog.js
rename to chrome/browser/resources/file_manager/foreground/js/photo/select_album_dialog.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js b/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js
new file mode 100644
index 0000000..347d89e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js
@@ -0,0 +1,1356 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * Slide mode displays a single image and has a set of controls to navigate
+ * between the images and to edit an image.
+ *
+ * TODO(kaznacheev): Introduce a parameter object.
+ *
+ * @param {Element} container Main container element.
+ * @param {Element} content Content container element.
+ * @param {Element} toolbar Toolbar element.
+ * @param {ImageEditor.Prompt} prompt Prompt.
+ * @param {cr.ui.ArrayDataModel} dataModel Data model.
+ * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
+ * @param {Object} context Context.
+ * @param {function(function())} toggleMode Function to toggle the Gallery mode.
+ * @param {function(string):string} displayStringFunction String formatting
+ *     function.
+ * @constructor
+ */
+function SlideMode(container, content, toolbar, prompt,
+                   dataModel, selectionModel, context,
+                   toggleMode, displayStringFunction) {
+  this.container_ = container;
+  this.document_ = container.ownerDocument;
+  this.content = content;
+  this.toolbar_ = toolbar;
+  this.prompt_ = prompt;
+  this.dataModel_ = dataModel;
+  this.selectionModel_ = selectionModel;
+  this.context_ = context;
+  this.metadataCache_ = context.metadataCache;
+  this.toggleMode_ = toggleMode;
+  this.displayStringFunction_ = displayStringFunction;
+
+  this.onSelectionBound_ = this.onSelection_.bind(this);
+  this.onSpliceBound_ = this.onSplice_.bind(this);
+  this.onContentBound_ = this.onContentChange_.bind(this);
+
+  // Unique numeric key, incremented per each load attempt used to discard
+  // old attempts. This can happen especially when changing selection fast or
+  // Internet connection is slow.
+  this.currentUniqueKey_ = 0;
+
+  this.initListeners_();
+  this.initDom_();
+}
+
+/**
+ * SlideMode extends cr.EventTarget.
+ */
+SlideMode.prototype.__proto__ = cr.EventTarget.prototype;
+
+/**
+ * List of available editor modes.
+ * @type {Array.<ImageEditor.Mode>}
+ */
+SlideMode.editorModes = [
+  new ImageEditor.Mode.InstantAutofix(),
+  new ImageEditor.Mode.Crop(),
+  new ImageEditor.Mode.Exposure(),
+  new ImageEditor.Mode.OneClick(
+      'rotate_left', 'GALLERY_ROTATE_LEFT', new Command.Rotate(-1)),
+  new ImageEditor.Mode.OneClick(
+      'rotate_right', 'GALLERY_ROTATE_RIGHT', new Command.Rotate(1))
+];
+
+/**
+ * @return {string} Mode name.
+ */
+SlideMode.prototype.getName = function() { return 'slide' };
+
+/**
+ * @return {string} Mode title.
+ */
+SlideMode.prototype.getTitle = function() { return 'GALLERY_SLIDE' };
+
+/**
+ * Initialize the listeners.
+ * @private
+ */
+SlideMode.prototype.initListeners_ = function() {
+  window.addEventListener('resize', this.onResize_.bind(this), false);
+};
+
+/**
+ * Initialize the UI.
+ * @private
+ */
+SlideMode.prototype.initDom_ = function() {
+  // Container for displayed image or video.
+  this.imageContainer_ = util.createChild(
+      this.document_.querySelector('.content'), 'image-container');
+  this.imageContainer_.addEventListener('click', this.onClick_.bind(this));
+
+  this.document_.addEventListener('click', this.onDocumentClick_.bind(this));
+
+  // Overwrite options and info bubble.
+  this.options_ = util.createChild(
+      this.toolbar_.querySelector('.filename-spacer'), 'options');
+
+  this.savedLabel_ = util.createChild(this.options_, 'saved');
+  this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED');
+
+  var overwriteOriginalBox =
+      util.createChild(this.options_, 'overwrite-original');
+
+  this.overwriteOriginal_ = util.createChild(
+      overwriteOriginalBox, 'common white', 'input');
+  this.overwriteOriginal_.type = 'checkbox';
+  this.overwriteOriginal_.id = 'overwrite-checkbox';
+  util.platform.getPreference(SlideMode.OVERWRITE_KEY, function(value) {
+    // Out-of-the box default is 'true'
+    this.overwriteOriginal_.checked =
+        (typeof value != 'string' || value == 'true');
+  }.bind(this));
+  this.overwriteOriginal_.addEventListener('click',
+      this.onOverwriteOriginalClick_.bind(this));
+
+  var overwriteLabel = util.createChild(overwriteOriginalBox, '', 'label');
+  overwriteLabel.textContent =
+      this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL');
+  overwriteLabel.setAttribute('for', 'overwrite-checkbox');
+
+  this.bubble_ = util.createChild(this.toolbar_, 'bubble');
+  this.bubble_.hidden = true;
+
+  var bubbleContent = util.createChild(this.bubble_);
+  bubbleContent.innerHTML = this.displayStringFunction_(
+      'GALLERY_OVERWRITE_BUBBLE');
+
+  util.createChild(this.bubble_, 'pointer bottom', 'span');
+
+  var bubbleClose = util.createChild(this.bubble_, 'close-x');
+  bubbleClose.addEventListener('click', this.onCloseBubble_.bind(this));
+
+  // Video player controls.
+  this.mediaSpacer_ =
+      util.createChild(this.container_, 'video-controls-spacer');
+  this.mediaToolbar_ = util.createChild(this.mediaSpacer_, 'tool');
+  this.mediaControls_ = new VideoControls(
+      this.mediaToolbar_,
+      this.showErrorBanner_.bind(this, 'GALLERY_VIDEO_ERROR'),
+      this.displayStringFunction_.bind(this),
+      this.toggleFullScreen_.bind(this),
+      this.container_);
+
+  // Ribbon and related controls.
+  this.arrowBox_ = util.createChild(this.container_, 'arrow-box');
+
+  this.arrowLeft_ =
+      util.createChild(this.arrowBox_, 'arrow left tool dimmable');
+  this.arrowLeft_.addEventListener('click',
+      this.advanceManually.bind(this, -1));
+  util.createChild(this.arrowLeft_);
+
+  util.createChild(this.arrowBox_, 'arrow-spacer');
+
+  this.arrowRight_ =
+      util.createChild(this.arrowBox_, 'arrow right tool dimmable');
+  this.arrowRight_.addEventListener('click',
+      this.advanceManually.bind(this, 1));
+  util.createChild(this.arrowRight_);
+
+  this.ribbonSpacer_ = util.createChild(this.toolbar_, 'ribbon-spacer');
+  this.ribbon_ = new Ribbon(this.document_,
+      this.metadataCache_, this.dataModel_, this.selectionModel_);
+  this.ribbonSpacer_.appendChild(this.ribbon_);
+
+  // Error indicator.
+  var errorWrapper = util.createChild(this.container_, 'prompt-wrapper');
+  errorWrapper.setAttribute('pos', 'center');
+
+  this.errorBanner_ = util.createChild(errorWrapper, 'error-banner');
+
+  util.createChild(this.container_, 'spinner');
+
+  var slideShowButton = util.createChild(this.toolbar_,
+      'button slideshow', 'button');
+  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
+  slideShowButton.addEventListener('click',
+      this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
+
+  var slideShowToolbar =
+      util.createChild(this.container_, 'tool slideshow-toolbar');
+  util.createChild(slideShowToolbar, 'slideshow-play').
+      addEventListener('click', this.toggleSlideshowPause_.bind(this));
+  util.createChild(slideShowToolbar, 'slideshow-end').
+      addEventListener('click', this.stopSlideshow_.bind(this));
+
+  // Editor.
+
+  this.editButton_ = util.createChild(this.toolbar_, 'button edit', 'button');
+  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
+  this.editButton_.setAttribute('disabled', '');  // Disabled by default.
+  this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
+
+  this.printButton_ = util.createChild(this.toolbar_, 'button print', 'button');
+  this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT');
+  this.printButton_.setAttribute('disabled', '');  // Disabled by default.
+  this.printButton_.addEventListener('click', this.print_.bind(this));
+
+  this.editBarSpacer_ = util.createChild(this.toolbar_, 'edit-bar-spacer');
+  this.editBarMain_ = util.createChild(this.editBarSpacer_, 'edit-main');
+
+  this.editBarMode_ = util.createChild(this.container_, 'edit-modal');
+  this.editBarModeWrapper_ = util.createChild(
+      this.editBarMode_, 'edit-modal-wrapper');
+  this.editBarModeWrapper_.hidden = true;
+
+  // Objects supporting image display and editing.
+  this.viewport_ = new Viewport();
+
+  this.imageView_ = new ImageView(
+      this.imageContainer_,
+      this.viewport_,
+      this.metadataCache_);
+
+  this.editor_ = new ImageEditor(
+      this.viewport_,
+      this.imageView_,
+      this.prompt_,
+      {
+        root: this.container_,
+        image: this.imageContainer_,
+        toolbar: this.editBarMain_,
+        mode: this.editBarModeWrapper_
+      },
+      SlideMode.editorModes,
+      this.displayStringFunction_,
+      this.onToolsVisibilityChanged_.bind(this));
+
+  this.editor_.getBuffer().addOverlay(
+      new SwipeOverlay(this.advanceManually.bind(this)));
+};
+
+/**
+ * Load items, display the selected item.
+ * @param {Rect} zoomFromRect Rectangle for zoom effect.
+ * @param {function} displayCallback Called when the image is displayed.
+ * @param {function} loadCallback Called when the image is displayed.
+ */
+SlideMode.prototype.enter = function(
+    zoomFromRect, displayCallback, loadCallback) {
+  this.sequenceDirection_ = 0;
+  this.sequenceLength_ = 0;
+
+  var loadDone = function(loadType, delay) {
+    this.active_ = true;
+
+    this.selectionModel_.addEventListener('change', this.onSelectionBound_);
+    this.dataModel_.addEventListener('splice', this.onSpliceBound_);
+    this.dataModel_.addEventListener('content', this.onContentBound_);
+
+    ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
+    this.ribbon_.enable();
+
+    // Wait 1000ms after the animation is done, then prefetch the next image.
+    this.requestPrefetch(1, delay + 1000);
+
+    if (loadCallback) loadCallback();
+  }.bind(this);
+
+  // The latest |leave| call might have left the image animating. Remove it.
+  this.unloadImage_();
+
+  if (this.getItemCount_() == 0) {
+    this.displayedIndex_ = -1;
+    //TODO(kaznacheev) Show this message in the grid mode too.
+    this.showErrorBanner_('GALLERY_NO_IMAGES');
+    loadDone();
+  } else {
+    // Remember the selection if it is empty or multiple. It will be restored
+    // in |leave| if the user did not changing the selection manually.
+    var currentSelection = this.selectionModel_.selectedIndexes;
+    if (currentSelection.length == 1)
+      this.savedSelection_ = null;
+    else
+      this.savedSelection_ = currentSelection;
+
+    // Ensure valid single selection.
+    // Note that the SlideMode object is not listening to selection change yet.
+    this.select(Math.max(0, this.getSelectedIndex()));
+    this.displayedIndex_ = this.getSelectedIndex();
+
+    var selectedItem = this.getSelectedItem();
+    var selectedUrl = selectedItem.getUrl();
+    // Show the selected item ASAP, then complete the initialization
+    // (loading the ribbon thumbnails can take some time).
+    this.metadataCache_.get(selectedUrl, Gallery.METADATA_TYPE,
+        function(metadata) {
+          this.loadItem_(selectedUrl, metadata,
+              zoomFromRect && this.imageView_.createZoomEffect(zoomFromRect),
+              displayCallback, loadDone);
+        }.bind(this));
+
+  }
+};
+
+/**
+ * Leave the mode.
+ * @param {Rect} zoomToRect Rectangle for zoom effect.
+ * @param {function} callback Called when the image is committed and
+ *   the zoom-out animation has started.
+ */
+SlideMode.prototype.leave = function(zoomToRect, callback) {
+  var commitDone = function() {
+      this.stopEditing_();
+      this.stopSlideshow_();
+      ImageUtil.setAttribute(this.arrowBox_, 'active', false);
+      this.selectionModel_.removeEventListener(
+          'change', this.onSelectionBound_);
+      this.dataModel_.removeEventListener('splice', this.onSpliceBound_);
+      this.dataModel_.removeEventListener('content', this.onContentBound_);
+      this.ribbon_.disable();
+      this.active_ = false;
+      if (this.savedSelection_)
+        this.selectionModel_.selectedIndexes = this.savedSelection_;
+      this.unloadImage_(zoomToRect);
+      callback();
+    }.bind(this);
+
+  if (this.getItemCount_() == 0) {
+    this.showErrorBanner_(false);
+    commitDone();
+  } else {
+    this.commitItem_(commitDone);
+  }
+
+  // Disable the slide-mode only buttons when leaving.
+  this.editButton_.setAttribute('disabled', '');
+  this.printButton_.setAttribute('disabled', '');
+};
+
+
+/**
+ * Execute an action when the editor is not busy.
+ *
+ * @param {function} action Function to execute.
+ */
+SlideMode.prototype.executeWhenReady = function(action) {
+  this.editor_.executeWhenReady(action);
+};
+
+/**
+ * @return {boolean} True if the mode has active tools (that should not fade).
+ */
+SlideMode.prototype.hasActiveTool = function() {
+  return this.isEditing();
+};
+
+/**
+ * @return {number} Item count.
+ * @private
+ */
+SlideMode.prototype.getItemCount_ = function() {
+  return this.dataModel_.length;
+};
+
+/**
+ * @param {number} index Index.
+ * @return {Gallery.Item} Item.
+ */
+SlideMode.prototype.getItem = function(index) {
+  return this.dataModel_.item(index);
+};
+
+/**
+ * @return {Gallery.Item} Selected index.
+ */
+SlideMode.prototype.getSelectedIndex = function() {
+  return this.selectionModel_.selectedIndex;
+};
+
+/**
+ * @return {Rect} Screen rectangle of the selected image.
+ */
+SlideMode.prototype.getSelectedImageRect = function() {
+  if (this.getSelectedIndex() < 0)
+    return null;
+  else
+    return this.viewport_.getScreenClipped();
+};
+
+/**
+ * @return {Gallery.Item} Selected item.
+ */
+SlideMode.prototype.getSelectedItem = function() {
+  return this.getItem(this.getSelectedIndex());
+};
+
+/**
+ * Toggles the full screen mode.
+ * @private
+ */
+SlideMode.prototype.toggleFullScreen_ = function() {
+  util.toggleFullScreen(this.context_.appWindow,
+                        !util.isFullScreen(this.context_.appWindow));
+};
+
+/**
+ * Selection change handler.
+ *
+ * Commits the current image and displays the newly selected image.
+ * @private
+ */
+SlideMode.prototype.onSelection_ = function() {
+  if (this.selectionModel_.selectedIndexes.length == 0)
+    return;  // Temporary empty selection.
+
+  // Forget the saved selection if the user changed the selection manually.
+  if (!this.isSlideshowOn_())
+    this.savedSelection_ = null;
+
+  if (this.getSelectedIndex() == this.displayedIndex_)
+    return;  // Do not reselect.
+
+  this.commitItem_(this.loadSelectedItem_.bind(this));
+};
+
+/**
+ * Handles changes in tools visibility, and if the header is dimmed, then
+ * requests disabling the draggable app region.
+ *
+ * @private
+ */
+SlideMode.prototype.onToolsVisibilityChanged_ = function() {
+  var headerDimmed =
+      this.document_.querySelector('.header').hasAttribute('dimmed');
+  this.context_.onAppRegionChanged(!headerDimmed);
+};
+
+/**
+ * Change the selection.
+ *
+ * @param {number} index New selected index.
+ * @param {number=} opt_slideHint Slide animation direction (-1|1).
+ */
+SlideMode.prototype.select = function(index, opt_slideHint) {
+  this.slideHint_ = opt_slideHint;
+  this.selectionModel_.selectedIndex = index;
+  this.selectionModel_.leadIndex = index;
+};
+
+/**
+ * Load the selected item.
+ *
+ * @private
+ */
+SlideMode.prototype.loadSelectedItem_ = function() {
+  var slideHint = this.slideHint_;
+  this.slideHint_ = undefined;
+
+  var index = this.getSelectedIndex();
+  if (index == this.displayedIndex_)
+    return;  // Do not reselect.
+
+  var step = slideHint || (index - this.displayedIndex_);
+
+  if (Math.abs(step) != 1) {
+    // Long leap, the sequence is broken, we have no good prefetch candidate.
+    this.sequenceDirection_ = 0;
+    this.sequenceLength_ = 0;
+  } else if (this.sequenceDirection_ == step) {
+    // Keeping going in sequence.
+    this.sequenceLength_++;
+  } else {
+    // Reversed the direction. Reset the counter.
+    this.sequenceDirection_ = step;
+    this.sequenceLength_ = 1;
+  }
+
+  if (this.sequenceLength_ <= 1) {
+    // We have just broke the sequence. Touch the current image so that it stays
+    // in the cache longer.
+    this.imageView_.prefetch(this.imageView_.contentID_);
+  }
+
+  this.displayedIndex_ = index;
+
+  function shouldPrefetch(loadType, step, sequenceLength) {
+    // Never prefetch when selecting out of sequence.
+    if (Math.abs(step) != 1)
+      return false;
+
+    // Never prefetch after a video load (decoding the next image can freeze
+    // the UI for a second or two).
+    if (loadType == ImageView.LOAD_TYPE_VIDEO_FILE)
+      return false;
+
+    // Always prefetch if the previous load was from cache.
+    if (loadType == ImageView.LOAD_TYPE_CACHED_FULL)
+      return true;
+
+    // Prefetch if we have been going in the same direction for long enough.
+    return sequenceLength >= 3;
+  }
+
+  var selectedItem = this.getSelectedItem();
+  this.currentUniqueKey_++;
+  var selectedUniqueKey = this.currentUniqueKey_;
+  var onMetadata = function(metadata) {
+    // Discard, since another load has been invoked after this one.
+    if (selectedUniqueKey != this.currentUniqueKey_) return;
+    this.loadItem_(selectedItem.getUrl(), metadata,
+        new ImageView.Effect.Slide(step, this.isSlideshowPlaying_()),
+        function() {} /* no displayCallback */,
+        function(loadType, delay) {
+          // Discard, since another load has been invoked after this one.
+          if (selectedUniqueKey != this.currentUniqueKey_) return;
+          if (shouldPrefetch(loadType, step, this.sequenceLength_)) {
+            this.requestPrefetch(step, delay);
+          }
+          if (this.isSlideshowPlaying_())
+            this.scheduleNextSlide_();
+        }.bind(this));
+  }.bind(this);
+  this.metadataCache_.get(
+      selectedItem.getUrl(), Gallery.METADATA_TYPE, onMetadata);
+};
+
+/**
+ * Unload the current image.
+ *
+ * @param {Rect} zoomToRect Rectangle for zoom effect.
+ * @private
+ */
+SlideMode.prototype.unloadImage_ = function(zoomToRect) {
+  this.imageView_.unload(zoomToRect);
+  this.container_.removeAttribute('video');
+};
+
+/**
+ * Data model 'splice' event handler.
+ * @param {Event} event Event.
+ * @private
+ */
+SlideMode.prototype.onSplice_ = function(event) {
+  ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
+
+  // Splice invalidates saved indices, drop the saved selection.
+  this.savedSelection_ = null;
+
+  if (event.removed.length != 1)
+    return;
+
+  // Delay the selection to let the ribbon splice handler work first.
+  setTimeout(function() {
+    if (event.index < this.dataModel_.length) {
+      // There is the next item, select it.
+      // The next item is now at the same index as the removed one, so we need
+      // to correct displayIndex_ so that loadSelectedItem_ does not think
+      // we are re-selecting the same item (and does right-to-left slide-in
+      // animation).
+      this.displayedIndex_ = event.index - 1;
+      this.select(event.index);
+    } else if (this.dataModel_.length) {
+      // Removed item is the rightmost, but there are more items.
+      this.select(event.index - 1);  // Select the new last index.
+    } else {
+      // No items left. Unload the image and show the banner.
+      this.commitItem_(function() {
+        this.unloadImage_();
+        this.showErrorBanner_('GALLERY_NO_IMAGES');
+      }.bind(this));
+    }
+  }.bind(this), 0);
+};
+
+/**
+ * @param {number} direction -1 for left, 1 for right.
+ * @return {number} Next index in the given direction, with wrapping.
+ * @private
+ */
+SlideMode.prototype.getNextSelectedIndex_ = function(direction) {
+  function advance(index, limit) {
+    index += (direction > 0 ? 1 : -1);
+    if (index < 0)
+      return limit - 1;
+    if (index == limit)
+      return 0;
+    return index;
+  }
+
+  // If the saved selection is multiple the Slideshow should cycle through
+  // the saved selection.
+  if (this.isSlideshowOn_() &&
+      this.savedSelection_ && this.savedSelection_.length > 1) {
+    var pos = advance(this.savedSelection_.indexOf(this.getSelectedIndex()),
+        this.savedSelection_.length);
+    return this.savedSelection_[pos];
+  } else {
+    return advance(this.getSelectedIndex(), this.getItemCount_());
+  }
+};
+
+/**
+ * Advance the selection based on the pressed key ID.
+ * @param {string} keyID Key identifier.
+ */
+SlideMode.prototype.advanceWithKeyboard = function(keyID) {
+  this.advanceManually(keyID == 'Up' || keyID == 'Left' ? -1 : 1);
+};
+
+/**
+ * Advance the selection as a result of a user action (as opposed to an
+ * automatic change in the slideshow mode).
+ * @param {number} direction -1 for left, 1 for right.
+ */
+SlideMode.prototype.advanceManually = function(direction) {
+  if (this.isSlideshowPlaying_()) {
+    this.pauseSlideshow_();
+    cr.dispatchSimpleEvent(this, 'useraction');
+  }
+  this.selectNext(direction);
+};
+
+/**
+ * Select the next item.
+ * @param {number} direction -1 for left, 1 for right.
+ */
+SlideMode.prototype.selectNext = function(direction) {
+  this.select(this.getNextSelectedIndex_(direction), direction);
+};
+
+/**
+ * Select the first item.
+ */
+SlideMode.prototype.selectFirst = function() {
+  this.select(0);
+};
+
+/**
+ * Select the last item.
+ */
+SlideMode.prototype.selectLast = function() {
+  this.select(this.getItemCount_() - 1);
+};
+
+// Loading/unloading
+
+/**
+ * Load and display an item.
+ *
+ * @param {string} url Item url.
+ * @param {Object} metadata Item metadata.
+ * @param {Object} effect Transition effect object.
+ * @param {function} displayCallback Called when the image is displayed
+ *     (which can happen before the image load due to caching).
+ * @param {function} loadCallback Called when the image is fully loaded.
+ * @private
+ */
+SlideMode.prototype.loadItem_ = function(
+    url, metadata, effect, displayCallback, loadCallback) {
+  this.selectedImageMetadata_ = MetadataCache.cloneMetadata(metadata);
+
+  this.showSpinner_(true);
+
+  var loadDone = function(loadType, delay, error) {
+    var video = this.isShowingVideo_();
+    ImageUtil.setAttribute(this.container_, 'video', video);
+
+    this.showSpinner_(false);
+    if (loadType == ImageView.LOAD_TYPE_ERROR) {
+      // if we have a specific error, then display it
+      if (error) {
+        this.showErrorBanner_('GALLERY_' + error);
+      } else {
+        // otherwise try to infer general error
+        this.showErrorBanner_(
+            video ? 'GALLERY_VIDEO_ERROR' : 'GALLERY_IMAGE_ERROR');
+      }
+    } else if (loadType == ImageView.LOAD_TYPE_OFFLINE) {
+      this.showErrorBanner_(
+          video ? 'GALLERY_VIDEO_OFFLINE' : 'GALLERY_IMAGE_OFFLINE');
+    }
+
+    if (video) {
+      // The editor toolbar does not make sense for video, hide it.
+      this.stopEditing_();
+      this.mediaControls_.attachMedia(this.imageView_.getVideo());
+
+      // TODO(kaznacheev): Add metrics for video playback.
+    } else {
+      ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View'));
+
+      var toMillions = function(number) {
+        return Math.round(number / (1000 * 1000));
+      };
+
+      ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'),
+          toMillions(metadata.filesystem.size));
+
+      var canvas = this.imageView_.getCanvas();
+      ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'),
+          toMillions(canvas.width * canvas.height));
+
+      var extIndex = url.lastIndexOf('.');
+      var ext = extIndex < 0 ? '' : url.substr(extIndex + 1).toLowerCase();
+      if (ext == 'jpeg') ext = 'jpg';
+      ImageUtil.metrics.recordEnum(
+          ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES);
+    }
+
+    // Enable or disable buttons for editing and printing.
+    if (video || error) {
+      this.editButton_.setAttribute('disabled', '');
+      this.printButton_.setAttribute('disabled', '');
+    } else {
+      this.editButton_.removeAttribute('disabled');
+      this.printButton_.removeAttribute('disabled');
+    }
+
+    // For once edited image, disallow the 'overwrite' setting change.
+    ImageUtil.setAttribute(this.options_, 'saved',
+        !this.getSelectedItem().isOriginal());
+
+    util.platform.getPreference(SlideMode.OVERWRITE_BUBBLE_KEY,
+        function(value) {
+          var times = typeof value == 'string' ? parseInt(value, 10) : 0;
+          if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) {
+            this.bubble_.hidden = false;
+            if (this.isEditing()) {
+              util.platform.setPreference(
+                  SlideMode.OVERWRITE_BUBBLE_KEY, times + 1);
+            }
+          }
+        }.bind(this));
+
+    loadCallback(loadType, delay);
+  }.bind(this);
+
+  var displayDone = function() {
+    cr.dispatchSimpleEvent(this, 'image-displayed');
+    displayCallback();
+  }.bind(this);
+
+  this.editor_.openSession(url, metadata, effect,
+      this.saveCurrentImage_.bind(this), displayDone, loadDone);
+};
+
+/**
+ * Commit changes to the current item and reset all messages/indicators.
+ *
+ * @param {function} callback Callback.
+ * @private
+ */
+SlideMode.prototype.commitItem_ = function(callback) {
+  this.showSpinner_(false);
+  this.showErrorBanner_(false);
+  this.editor_.getPrompt().hide();
+
+  // Detach any media attached to the controls.
+  if (this.mediaControls_.getMedia())
+    this.mediaControls_.detachMedia();
+
+  // If showing the video, then pause it. Note, that it may not be attached
+  // to the media controls yet.
+  if (this.isShowingVideo_()) {
+    this.imageView_.getVideo().pause();
+    // Force stop downloading, if uncached on Drive.
+    this.imageView_.getVideo().src = '';
+    this.imageView_.getVideo().load();
+  }
+
+  this.editor_.closeSession(callback);
+};
+
+/**
+ * Request a prefetch for the next image.
+ *
+ * @param {number} direction -1 or 1.
+ * @param {number} delay Delay in ms. Used to prevent the CPU-heavy image
+ *   loading from disrupting the animation that might be still in progress.
+ */
+SlideMode.prototype.requestPrefetch = function(direction, delay) {
+  if (this.getItemCount_() <= 1) return;
+
+  var index = this.getNextSelectedIndex_(direction);
+  var nextItemUrl = this.getItem(index).getUrl();
+  this.imageView_.prefetch(nextItemUrl, delay);
+};
+
+// Event handlers.
+
+/**
+ * Unload handler, to be called from the top frame.
+ * @param {boolean} exiting True if the app is exiting.
+ */
+SlideMode.prototype.onUnload = function(exiting) {
+  if (this.isShowingVideo_() && this.mediaControls_.isPlaying()) {
+    this.mediaControls_.savePosition(exiting);
+  }
+};
+
+/**
+ * beforeunload handler, to be called from the top frame.
+ * @return {string} Message to show if there are unsaved changes.
+ */
+SlideMode.prototype.onBeforeUnload = function() {
+  if (this.editor_.isBusy())
+    return this.displayStringFunction_('GALLERY_UNSAVED_CHANGES');
+  return null;
+};
+
+/**
+ * Click handler for the image container.
+ *
+ * @param {Event} event Mouse click event.
+ * @private
+ */
+SlideMode.prototype.onClick_ = function(event) {
+  if (!this.isShowingVideo_() || !this.mediaControls_.getMedia())
+    return;
+  if (event.ctrlKey) {
+    this.mediaControls_.toggleLoopedModeWithFeedback(true);
+    if (!this.mediaControls_.isPlaying())
+      this.mediaControls_.togglePlayStateWithFeedback();
+  } else {
+    this.mediaControls_.togglePlayStateWithFeedback();
+  }
+};
+
+/**
+ * Click handler for the entire document.
+ * @param {Event} e Mouse click event.
+ * @private
+ */
+SlideMode.prototype.onDocumentClick_ = function(e) {
+  // Close the bubble if clicked outside of it and if it is visible.
+  if (!this.bubble_.contains(e.target) &&
+      !this.editButton_.contains(e.target) &&
+      !this.arrowLeft_.contains(e.target) &&
+      !this.arrowRight_.contains(e.target) &&
+      !this.bubble_.hidden) {
+    this.bubble_.hidden = true;
+  }
+};
+
+/**
+ * Keydown handler.
+ *
+ * @param {Event} event Event.
+ * @return {boolean} True if handled.
+ */
+SlideMode.prototype.onKeyDown = function(event) {
+  var keyID = util.getKeyModifiers(event) + event.keyIdentifier;
+
+  if (this.isSlideshowOn_()) {
+    switch (keyID) {
+      case 'U+001B':  // Escape exits the slideshow.
+        this.stopSlideshow_(event);
+        break;
+
+      case 'U+0020':  // Space pauses/resumes the slideshow.
+        this.toggleSlideshowPause_();
+        break;
+
+      case 'Up':
+      case 'Down':
+      case 'Left':
+      case 'Right':
+        this.advanceWithKeyboard(keyID);
+        break;
+    }
+    return true;  // Consume all keystrokes in the slideshow mode.
+  }
+
+  if (this.isEditing() && this.editor_.onKeyDown(event))
+    return true;
+
+  switch (keyID) {
+    case 'U+0020':  // Space toggles the video playback.
+      if (this.isShowingVideo_() && this.mediaControls_.getMedia())
+        this.mediaControls_.togglePlayStateWithFeedback();
+      break;
+
+    case 'Ctrl-U+0050':  // Ctrl+'p' prints the current image.
+      if (!this.printButton_.hasAttribute('disabled'))
+        this.print_();
+      break;
+
+    case 'U+0045':  // 'e' toggles the editor.
+      if (!this.editButton_.hasAttribute('disabled'))
+        this.toggleEditor(event);
+      break;
+
+    case 'U+001B':  // Escape
+      if (!this.isEditing())
+        return false;  // Not handled.
+      this.toggleEditor(event);
+      break;
+
+    case 'Home':
+      this.selectFirst();
+      break;
+    case 'End':
+      this.selectLast();
+      break;
+    case 'Up':
+    case 'Down':
+    case 'Left':
+    case 'Right':
+      this.advanceWithKeyboard(keyID);
+      break;
+
+    default: return false;
+  }
+
+  return true;
+};
+
+/**
+ * Resize handler.
+ * @private
+ */
+SlideMode.prototype.onResize_ = function() {
+  this.viewport_.sizeByFrameAndFit(this.container_);
+  this.viewport_.repaint();
+};
+
+/**
+ * Update thumbnails.
+ */
+SlideMode.prototype.updateThumbnails = function() {
+  this.ribbon_.reset();
+  if (this.active_)
+    this.ribbon_.redraw();
+};
+
+// Saving
+
+/**
+ * Save the current image to a file.
+ *
+ * @param {function} callback Callback.
+ * @private
+ */
+SlideMode.prototype.saveCurrentImage_ = function(callback) {
+  var item = this.getSelectedItem();
+  var oldUrl = item.getUrl();
+  var canvas = this.imageView_.getCanvas();
+
+  this.showSpinner_(true);
+  var metadataEncoder = ImageEncoder.encodeMetadata(
+      this.selectedImageMetadata_.media, canvas, 1 /* quality */);
+
+  this.selectedImageMetadata_ = ContentProvider.ConvertContentMetadata(
+      metadataEncoder.getMetadata(), this.selectedImageMetadata_);
+
+  item.saveToFile(
+      this.context_.saveDirEntry,
+      this.shouldOverwriteOriginal_(),
+      canvas,
+      metadataEncoder,
+      function(success) {
+        // TODO(kaznacheev): Implement write error handling.
+        // Until then pretend that the save succeeded.
+        this.showSpinner_(false);
+        this.flashSavedLabel_();
+
+        var e = new Event('content');
+        e.item = item;
+        e.oldUrl = oldUrl;
+        e.metadata = this.selectedImageMetadata_;
+        this.dataModel_.dispatchEvent(e);
+
+        // Allow changing the 'Overwrite original' setting only if the user
+        // used Undo to restore the original image AND it is not a copy.
+        // Otherwise lock the setting in its current state.
+        var mayChangeOverwrite = !this.editor_.canUndo() && item.isOriginal();
+        ImageUtil.setAttribute(this.options_, 'saved', !mayChangeOverwrite);
+
+        if (this.imageView_.getContentRevision() == 1) {  // First edit.
+          ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit'));
+        }
+
+        if (oldUrl != item.getUrl()) {
+          this.dataModel_.splice(
+              this.getSelectedIndex(), 0, new Gallery.Item(oldUrl));
+          // The ribbon will ignore the splice above and redraw after the
+          // select call below (while being obscured by the Editor toolbar,
+          // so there is no need for nice animation here).
+          // SlideMode will ignore the selection change as the displayed item
+          // index has not changed.
+          this.select(++this.displayedIndex_);
+        }
+        callback();
+        cr.dispatchSimpleEvent(this, 'image-saved');
+      }.bind(this));
+};
+
+/**
+ * Update caches when the selected item url has changed.
+ *
+ * @param {Event} event Event.
+ * @private
+ */
+SlideMode.prototype.onContentChange_ = function(event) {
+  var newUrl = event.item.getUrl();
+  if (newUrl != event.oldUrl) {
+    this.imageView_.changeUrl(newUrl);
+  }
+  this.metadataCache_.clear(event.oldUrl, Gallery.METADATA_TYPE);
+};
+
+/**
+ * Flash 'Saved' label briefly to indicate that the image has been saved.
+ * @private
+ */
+SlideMode.prototype.flashSavedLabel_ = function() {
+  var setLabelHighlighted =
+      ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted');
+  setTimeout(setLabelHighlighted.bind(null, true), 0);
+  setTimeout(setLabelHighlighted.bind(null, false), 300);
+};
+
+/**
+ * Local storage key for the 'Overwrite original' setting.
+ * @type {string}
+ */
+SlideMode.OVERWRITE_KEY = 'gallery-overwrite-original';
+
+/**
+ * Local storage key for the number of times that
+ * the overwrite info bubble has been displayed.
+ * @type {string}
+ */
+SlideMode.OVERWRITE_BUBBLE_KEY = 'gallery-overwrite-bubble';
+
+/**
+ * Max number that the overwrite info bubble is shown.
+ * @type {number}
+ */
+SlideMode.OVERWRITE_BUBBLE_MAX_TIMES = 5;
+
+/**
+ * @return {boolean} True if 'Overwrite original' is set.
+ * @private
+ */
+SlideMode.prototype.shouldOverwriteOriginal_ = function() {
+   return this.overwriteOriginal_.checked;
+};
+
+/**
+ * 'Overwrite original' checkbox handler.
+ * @param {Event} event Event.
+ * @private
+ */
+SlideMode.prototype.onOverwriteOriginalClick_ = function(event) {
+  util.platform.setPreference(SlideMode.OVERWRITE_KEY, event.target.checked);
+};
+
+/**
+ * Overwrite info bubble close handler.
+ * @private
+ */
+SlideMode.prototype.onCloseBubble_ = function() {
+  this.bubble_.hidden = true;
+  util.platform.setPreference(SlideMode.OVERWRITE_BUBBLE_KEY,
+      SlideMode.OVERWRITE_BUBBLE_MAX_TIMES);
+};
+
+// Slideshow
+
+/**
+ * Slideshow interval in ms.
+ */
+SlideMode.SLIDESHOW_INTERVAL = 5000;
+
+/**
+ * First slideshow interval in ms. It should be shorter so that the user
+ * is not guessing whether the button worked.
+ */
+SlideMode.SLIDESHOW_INTERVAL_FIRST = 1000;
+
+/**
+ * Empirically determined duration of the fullscreen toggle animation.
+ */
+SlideMode.FULLSCREEN_TOGGLE_DELAY = 500;
+
+/**
+ * @return {boolean} True if the slideshow is on.
+ * @private
+ */
+SlideMode.prototype.isSlideshowOn_ = function() {
+  return this.container_.hasAttribute('slideshow');
+};
+
+/**
+ * Start the slideshow.
+ * @param {number=} opt_interval First interval in ms.
+ * @param {Event=} opt_event Event.
+ */
+SlideMode.prototype.startSlideshow = function(opt_interval, opt_event) {
+  // Set the attribute early to prevent the toolbar from flashing when
+  // the slideshow is being started from the mosaic view.
+  this.container_.setAttribute('slideshow', 'playing');
+
+  if (this.active_) {
+    this.stopEditing_();
+  } else {
+    // We are in the Mosaic mode. Toggle the mode but remember to return.
+    this.leaveAfterSlideshow_ = true;
+    this.toggleMode_(this.startSlideshow.bind(
+        this, SlideMode.SLIDESHOW_INTERVAL, opt_event));
+    return;
+  }
+
+  if (opt_event)  // Caused by user action, notify the Gallery.
+    cr.dispatchSimpleEvent(this, 'useraction');
+
+  this.fullscreenBeforeSlideshow_ = util.isFullScreen(this.context_.appWindow);
+  if (!this.fullscreenBeforeSlideshow_) {
+    // Wait until the zoom animation from the mosaic mode is done.
+    setTimeout(this.toggleFullScreen_.bind(this),
+               ImageView.ZOOM_ANIMATION_DURATION);
+    opt_interval = (opt_interval || SlideMode.SLIDESHOW_INTERVAL) +
+        SlideMode.FULLSCREEN_TOGGLE_DELAY;
+  }
+
+  this.resumeSlideshow_(opt_interval);
+};
+
+/**
+ * Stop the slideshow.
+ * @param {Event=} opt_event Event.
+ * @private
+ */
+SlideMode.prototype.stopSlideshow_ = function(opt_event) {
+  if (!this.isSlideshowOn_())
+    return;
+
+  if (opt_event)  // Caused by user action, notify the Gallery.
+    cr.dispatchSimpleEvent(this, 'useraction');
+
+  this.pauseSlideshow_();
+  this.container_.removeAttribute('slideshow');
+
+  // Do not restore fullscreen if we exited fullscreen while in slideshow.
+  var fullscreen = util.isFullScreen(this.context_.appWindow);
+  var toggleModeDelay = 0;
+  if (!this.fullscreenBeforeSlideshow_ && fullscreen) {
+    this.toggleFullScreen_();
+    toggleModeDelay = SlideMode.FULLSCREEN_TOGGLE_DELAY;
+  }
+  if (this.leaveAfterSlideshow_) {
+    this.leaveAfterSlideshow_ = false;
+    setTimeout(this.toggleMode_.bind(this), toggleModeDelay);
+  }
+};
+
+/**
+ * @return {boolean} True if the slideshow is playing (not paused).
+ * @private
+ */
+SlideMode.prototype.isSlideshowPlaying_ = function() {
+  return this.container_.getAttribute('slideshow') == 'playing';
+};
+
+/**
+ * Pause/resume the slideshow.
+ * @private
+ */
+SlideMode.prototype.toggleSlideshowPause_ = function() {
+  cr.dispatchSimpleEvent(this, 'useraction');  // Show the tools.
+  if (this.isSlideshowPlaying_()) {
+    this.pauseSlideshow_();
+  } else {
+    this.resumeSlideshow_(SlideMode.SLIDESHOW_INTERVAL_FIRST);
+  }
+};
+
+/**
+ * @param {number=} opt_interval Slideshow interval in ms.
+ * @private
+ */
+SlideMode.prototype.scheduleNextSlide_ = function(opt_interval) {
+  console.assert(this.isSlideshowPlaying_(), 'Inconsistent slideshow state');
+
+  if (this.slideShowTimeout_)
+    clearTimeout(this.slideShowTimeout_);
+
+  this.slideShowTimeout_ = setTimeout(function() {
+        this.slideShowTimeout_ = null;
+        this.selectNext(1);
+      }.bind(this),
+      opt_interval || SlideMode.SLIDESHOW_INTERVAL);
+};
+
+/**
+ * Resume the slideshow.
+ * @param {number=} opt_interval Slideshow interval in ms.
+ * @private
+ */
+SlideMode.prototype.resumeSlideshow_ = function(opt_interval) {
+  this.container_.setAttribute('slideshow', 'playing');
+  this.scheduleNextSlide_(opt_interval);
+};
+
+/**
+ * Pause the slideshow.
+ * @private
+ */
+SlideMode.prototype.pauseSlideshow_ = function() {
+  this.container_.setAttribute('slideshow', 'paused');
+  if (this.slideShowTimeout_) {
+    clearTimeout(this.slideShowTimeout_);
+    this.slideShowTimeout_ = null;
+  }
+};
+
+/**
+ * @return {boolean} True if the editor is active.
+ */
+SlideMode.prototype.isEditing = function() {
+  return this.container_.hasAttribute('editing');
+};
+
+/**
+ * Stop editing.
+ * @private
+ */
+SlideMode.prototype.stopEditing_ = function() {
+  if (this.isEditing())
+    this.toggleEditor();
+};
+
+/**
+ * Activate/deactivate editor.
+ * @param {Event=} opt_event Event.
+ */
+SlideMode.prototype.toggleEditor = function(opt_event) {
+  if (opt_event)  // Caused by user action, notify the Gallery.
+    cr.dispatchSimpleEvent(this, 'useraction');
+
+  if (!this.active_) {
+    this.toggleMode_(this.toggleEditor.bind(this));
+    return;
+  }
+
+  this.stopSlideshow_();
+  if (!this.isEditing() && this.isShowingVideo_())
+    return;  // No editing for videos.
+
+  ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing());
+
+  if (this.isEditing()) { // isEditing has just been flipped to a new value.
+    if (this.context_.readonlyDirName) {
+      this.editor_.getPrompt().showAt(
+          'top', 'readonly_warning', 0, this.context_.readonlyDirName);
+    }
+  } else {
+    this.editor_.getPrompt().hide();
+    this.editor_.leaveModeGently();
+  }
+};
+
+/**
+ * Prints the current item.
+ * @private
+ */
+SlideMode.prototype.print_ = function() {
+  cr.dispatchSimpleEvent(this, 'useraction');
+  window.print();
+};
+
+/**
+ * Display the error banner.
+ * @param {string} message Message.
+ * @private
+ */
+SlideMode.prototype.showErrorBanner_ = function(message) {
+  if (message) {
+    this.errorBanner_.textContent = this.displayStringFunction_(message);
+  }
+  ImageUtil.setAttribute(this.container_, 'error', !!message);
+};
+
+/**
+ * Show/hide the busy spinner.
+ *
+ * @param {boolean} on True if show, false if hide.
+ * @private
+ */
+SlideMode.prototype.showSpinner_ = function(on) {
+  if (this.spinnerTimer_) {
+    clearTimeout(this.spinnerTimer_);
+    this.spinnerTimer_ = null;
+  }
+
+  if (on) {
+    this.spinnerTimer_ = setTimeout(function() {
+      this.spinnerTimer_ = null;
+      ImageUtil.setAttribute(this.container_, 'spinner', true);
+    }.bind(this), 1000);
+  } else {
+    ImageUtil.setAttribute(this.container_, 'spinner', false);
+  }
+};
+
+/**
+ * @return {boolean} True if the current item is a video.
+ * @private
+ */
+SlideMode.prototype.isShowingVideo_ = function() {
+  return !!this.imageView_.getVideo();
+};
+
+/**
+ * Overlay that handles swipe gestures. Changes to the next or previous file.
+ * @param {function(number)} callback A callback accepting the swipe direction
+ *    (1 means left, -1 right).
+ * @constructor
+ * @implements {ImageBuffer.Overlay}
+ */
+function SwipeOverlay(callback) {
+  this.callback_ = callback;
+}
+
+/**
+ * Inherit ImageBuffer.Overlay.
+ */
+SwipeOverlay.prototype.__proto__ = ImageBuffer.Overlay.prototype;
+
+/**
+ * @param {number} x X pointer position.
+ * @param {number} y Y pointer position.
+ * @param {boolean} touch True if dragging caused by touch.
+ * @return {function} The closure to call on drag.
+ */
+SwipeOverlay.prototype.getDragHandler = function(x, y, touch) {
+  if (!touch)
+    return null;
+  var origin = x;
+  var done = false;
+  return function(x, y) {
+    if (!done && origin - x > SwipeOverlay.SWIPE_THRESHOLD) {
+      this.callback_(1);
+      done = true;
+    } else if (!done && x - origin > SwipeOverlay.SWIPE_THRESHOLD) {
+      this.callback_(-1);
+      done = true;
+    }
+  }.bind(this);
+};
+
+/**
+ * If the user touched the image and moved the finger more than SWIPE_THRESHOLD
+ * horizontally it's considered as a swipe gesture (change the current image).
+ */
+SwipeOverlay.SWIPE_THRESHOLD = 100;
diff --git a/chrome/browser/resources/file_manager/js/scrollbar.js b/chrome/browser/resources/file_manager/foreground/js/scrollbar.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/scrollbar.js
rename to chrome/browser/resources/file_manager/foreground/js/scrollbar.js
diff --git a/chrome/browser/resources/file_manager/js/share_client.js b/chrome/browser/resources/file_manager/foreground/js/share_client.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/share_client.js
rename to chrome/browser/resources/file_manager/foreground/js/share_client.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/share_dialog.js b/chrome/browser/resources/file_manager/foreground/js/share_dialog.js
new file mode 100644
index 0000000..ff7fbf6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/share_dialog.js
@@ -0,0 +1,314 @@
+// Copyright 2013 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.
+
+'use strict';
+
+/**
+ * @param {HTMLElement} parentNode Node to be parent for this dialog.
+ * @constructor
+ * @extends {FileManagerDialogBase}
+ * @implements {ShareClient.Observer}
+ */
+function ShareDialog(parentNode) {
+  this.queue_ = new AsyncUtil.Queue();
+  this.onQueueTaskFinished_ = null;
+  this.shareClient_ = null;
+  this.spinner_ = null;
+  this.spinnerLayer_ = null;
+  this.webViewWrapper_ = null;
+  this.webView_ = null;
+  this.failureTimeout_ = null;
+  this.callback_ = null;
+
+  FileManagerDialogBase.call(this, parentNode);
+}
+
+/**
+ * Timeout for loading the share dialog before giving up.
+ * @type {number}
+ * @const
+ */
+ShareDialog.FAILURE_TIMEOUT = 10000;
+
+/**
+ * The result of opening the dialog.
+ * @enum {string}
+ * @const
+ */
+ShareDialog.Result = Object.freeze({
+  // The dialog is closed normally. This includes user cancel.
+  SUCCESS: 'success',
+  // The dialog is closed by network error.
+  NETWORK_ERROR: 'networkError',
+  // The dialog is not opened because it is already showing.
+  ALREADY_SHOWING: 'alreadyShowing'
+});
+
+/**
+ * Wraps a Web View element and adds authorization headers to it.
+ * @param {string} urlPattern Pattern of urls to be authorized.
+ * @param {WebView} webView Web View element to be wrapped.
+ * @constructor
+ */
+ShareDialog.WebViewAuthorizer = function(urlPattern, webView) {
+  this.urlPattern_ = urlPattern;
+  this.webView_ = webView;
+  this.initialized_ = false;
+  this.accessToken_ = null;
+};
+
+/**
+ * Initializes the web view by installing hooks injecting the authorization
+ * headers.
+ * @param {function()} callback Completion callback.
+ */
+ShareDialog.WebViewAuthorizer.prototype.initialize = function(callback) {
+  if (this.initialized_) {
+    callback();
+    return;
+  }
+
+  var registerInjectionHooks = function() {
+    this.webView_.removeEventListener('loadstop', registerInjectionHooks);
+    this.webView_.request.onBeforeSendHeaders.addListener(
+      this.authorizeRequest_.bind(this),
+      {urls: [this.urlPattern_]},
+      ['blocking', 'requestHeaders']);
+    this.initialized_ = true;
+    callback();
+  }.bind(this);
+
+  this.webView_.addEventListener('loadstop', registerInjectionHooks);
+  this.webView_.setAttribute('src', 'data:text/html,');
+};
+
+/**
+ * Authorizes the web view by fetching the freshest access tokens.
+ * @param {function()} callback Completion callback.
+ */
+ShareDialog.WebViewAuthorizer.prototype.authorize = function(callback) {
+  // Fetch or update the access token.
+  chrome.fileBrowserPrivate.requestAccessToken(false,  // force_refresh
+      function(inAccessToken) {
+        this.accessToken_ = inAccessToken;
+        callback();
+      }.bind(this));
+};
+
+/**
+ * Injects headers into the passed request.
+ * @param {Event} e Request event.
+ * @return {{requestHeaders: HttpHeaders}} Modified headers.
+ * @private
+ */
+ShareDialog.WebViewAuthorizer.prototype.authorizeRequest_ = function(e) {
+  e.requestHeaders.push({
+    name: 'Authorization',
+    value: 'Bearer ' + this.accessToken_
+  });
+  return {requestHeaders: e.requestHeaders};
+};
+
+ShareDialog.prototype = {
+  __proto__: FileManagerDialogBase.prototype
+};
+
+/**
+ * One-time initialization of DOM.
+ * @private
+ */
+ShareDialog.prototype.initDom_ = function() {
+  FileManagerDialogBase.prototype.initDom_.call(this);
+  this.frame_.classList.add('share-dialog-frame');
+
+  this.spinnerLayer_ = this.document_.createElement('div');
+  this.spinnerLayer_.className = 'spinner-layer';
+  this.frame_.appendChild(this.spinnerLayer_);
+
+  this.webViewWrapper_ = this.document_.createElement('div');
+  this.webViewWrapper_.className = 'share-dialog-webview-wrapper';
+  this.cancelButton_.hidden = true;
+  this.okButton_.hidden = true;
+  this.frame_.insertBefore(this.webViewWrapper_,
+                           this.frame_.querySelector('.cr-dialog-buttons'));
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onResized = function(width, height, callback) {
+  if (width && height) {
+    this.webViewWrapper_.style.width = width + 'px';
+    this.webViewWrapper_.style.height = height + 'px';
+    this.webView_.style.width = width + 'px';
+    this.webView_.style.height = height + 'px';
+  }
+  setTimeout(callback, 0);
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onClosed = function() {
+  this.hide();
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onLoaded = function() {
+  if (this.failureTimeout_) {
+    clearTimeout(this.failureTimeout_);
+    this.failureTimeout_ = null;
+  }
+
+  // Logs added temporarily to track crbug.com/288783.
+  console.debug('Loaded.');
+
+  this.okButton_.hidden = false;
+  this.spinnerLayer_.hidden = true;
+  this.webViewWrapper_.classList.add('loaded');
+  this.webView_.focus();
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onLoadFailed = function() {
+  this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.hide = function(opt_onHide) {
+  this.hideWithResult(ShareDialog.Result.SUCCESS, opt_onHide);
+};
+
+/**
+ * Hide the dialog with the result and the callback.
+ * @param {ShareDialog.Result} result Result passed to the closing callback.
+ * @param {function()=} opt_onHide Callback called at the end of hiding.
+ */
+ShareDialog.prototype.hideWithResult = function(result, opt_onHide) {
+  if (!this.isShowing())
+    return;
+
+  if (this.shareClient_) {
+    this.shareClient_.dispose();
+    this.shareClient_ = null;
+  }
+
+  this.webViewWrapper_.textContent = '';
+  if (this.failureTimeout_) {
+    clearTimeout(this.failureTimeout_);
+    this.failureTimeout_ = null;
+  }
+
+  FileManagerDialogBase.prototype.hide.call(
+      this,
+      function() {
+        if (opt_onHide)
+          opt_onHide();
+        this.callback_(result);
+        this.callback_ = null;
+      }.bind(this));
+};
+
+/**
+ * Shows the dialog.
+ * @param {FileEntry} entry Entry to share.
+ * @param {function(boolean)} callback Callback to be called when the showing
+ *     task is completed. The argument is whether to succeed or not. Note that
+ *     cancel is regarded as success.
+ */
+ShareDialog.prototype.show = function(entry, callback) {
+  // If the dialog is already showing, return the error.
+  if (this.isShowing()) {
+    callback(ShareDialog.Result.ALREADY_SHOWING);
+    return;
+  }
+
+  // Initialize the variables.
+  this.callback_ = callback;
+  this.spinnerLayer_.hidden = false;
+  this.webViewWrapper_.style.width = '';
+  this.webViewWrapper_.style.height = '';
+
+  // If the embedded share dialog is not started within some time, then
+  // give up and show an error message.
+  this.failureTimeout_ = setTimeout(function() {
+    this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
+
+    // Logs added temporarily to track crbug.com/288783.
+    console.debug('Timeout. Web View points at: ' + this.webView_.src);
+  }.bind(this), ShareDialog.FAILURE_TIMEOUT);
+
+  // TODO(mtomasz): Move to initDom_() once and reuse <webview> once it gets
+  // fixed. See: crbug.com/260622.
+  this.webView_ = util.createChild(
+      this.webViewWrapper_, 'share-dialog-webview', 'webview');
+  this.webView_.setAttribute('tabIndex', '-1');
+  this.webViewAuthorizer_ = new ShareDialog.WebViewAuthorizer(
+      !window.IN_TEST ? (ShareClient.SHARE_TARGET + '/*') : '<all_urls>',
+      this.webView_);
+  this.webView_.addEventListener('newwindow', function(e) {
+    // Discard the window object and reopen in an external window.
+    e.window.discard();
+    util.visitURL(e.targetUrl);
+    e.preventDefault();
+  });
+  var show = FileManagerDialogBase.prototype.showBlankDialog.call(this);
+  if (!show) {
+    // The code shoundn't get here, since already-showing was handled before.
+    console.error('ShareDialog can\'t be shown.');
+    return;
+  }
+
+  // Initialize and authorize the Web View tag asynchronously.
+  var group = new AsyncUtil.Group();
+
+  // Fetches an url to the sharing dialog.
+  var shareUrl;
+  group.add(function(inCallback) {
+    chrome.fileBrowserPrivate.getShareUrl(
+        entry.toURL(),
+        function(inShareUrl) {
+          if (!chrome.runtime.lastError)
+            shareUrl = inShareUrl;
+          inCallback();
+        });
+  });
+  group.add(this.webViewAuthorizer_.initialize.bind(this.webViewAuthorizer_));
+  group.add(this.webViewAuthorizer_.authorize.bind(this.webViewAuthorizer_));
+
+  // Loads the share widget once all the previous async calls are finished.
+  group.run(function() {
+    // If the url is not obtained, return the network error.
+    if (!shareUrl) {
+       // Logs added temporarily to track crbug.com/288783.
+       console.debug('URL not available.');
+
+       this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
+      return;
+    }
+    // Already inactive, therefore ignore.
+    if (!this.isShowing())
+      return;
+    this.shareClient_ = new ShareClient(this.webView_,
+                                        shareUrl,
+                                        this);
+    this.shareClient_.load();
+  }.bind(this));
+};
+
+/**
+ * Tells whether the share dialog is showing or not.
+ *
+ * @return {boolean} True since the show method is called and until the closing
+ *     callback is invoked.
+ */
+ShareDialog.prototype.isShowing = function() {
+  return !!this.callback_;
+};
diff --git a/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js b/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js
new file mode 100644
index 0000000..b05bd23
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js
@@ -0,0 +1,510 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+/**
+ * SuggestAppsDialog contains a list box to select an app to be opened the file
+ * with. This dialog should be used as action picker for file operations.
+ */
+
+/**
+ * The width of the widget (in pixel).
+ * @type {number}
+ * @const
+ */
+var WEBVIEW_WIDTH = 735;
+/**
+ * The height of the widget (in pixel).
+ * @type {number}
+ * @const
+ */
+var WEBVIEW_HEIGHT = 480;
+
+/**
+ * The URL of the widget.
+ * @type {string}
+ * @const
+ */
+var CWS_WIDGET_URL =
+    'https://clients5.google.com/webstore/wall/cros-widget-container';
+/**
+ * The origin of the widget.
+ * @type {string}
+ * @const
+ */
+var CWS_WIDGET_ORIGIN = 'https://clients5.google.com';
+
+/**
+ * Creates dialog in DOM tree.
+ *
+ * @param {HTMLElement} parentNode Node to be parent for this dialog.
+ * @param {Object} state Static state of suggest app dialog.
+ * @constructor
+ * @extends {FileManagerDialogBase}
+ */
+function SuggestAppsDialog(parentNode, state) {
+  FileManagerDialogBase.call(this, parentNode);
+
+  this.frame_.id = 'suggest-app-dialog';
+
+  this.webviewContainer_ = this.document_.createElement('div');
+  this.webviewContainer_.id = 'webview-container';
+  this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px';
+  this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px';
+  this.frame_.insertBefore(this.webviewContainer_, this.text_.nextSibling);
+
+  var spinnerLayer = this.document_.createElement('div');
+  spinnerLayer.className = 'spinner-layer';
+  this.webviewContainer_.appendChild(spinnerLayer);
+
+  this.buttons_ = this.document_.createElement('div');
+  this.buttons_.id = 'buttons';
+  this.frame_.appendChild(this.buttons_);
+
+  this.webstoreButton_ = this.document_.createElement('div');
+  this.webstoreButton_.id = 'webstore-button';
+  this.webstoreButton_.innerHTML = str('SUGGEST_DIALOG_LINK_TO_WEBSTORE');
+  this.webstoreButton_.addEventListener(
+      'click', this.onWebstoreLinkClicked_.bind(this));
+  this.buttons_.appendChild(this.webstoreButton_);
+
+  this.initialFocusElement_ = this.webviewContainer_;
+
+  this.webview_ = null;
+  this.accessToken_ = null;
+  this.widgetUrl_ =
+      state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL;
+  this.widgetOrigin_ =
+      state.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN;
+
+  this.extension_ = null;
+  this.mime_ = null;
+  this.installingItemId_ = null;
+  this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
+
+  this.initializationTask_ = new AsyncUtil.Group();
+  this.initializationTask_.add(this.retrieveAuthorizeToken_.bind(this));
+  this.initializationTask_.run();
+}
+
+SuggestAppsDialog.prototype = {
+  __proto__: FileManagerDialogBase.prototype
+};
+
+/**
+ * @enum {string}
+ * @const
+ */
+SuggestAppsDialog.State = {
+  UNINITIALIZED: 'SuggestAppsDialog.State.UNINITIALIZED',
+  INITIALIZING: 'SuggestAppsDialog.State.INITIALIZING',
+  INITIALIZE_FAILED_CLOSING:
+      'SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING',
+  INITIALIZED: 'SuggestAppsDialog.State.INITIALIZED',
+  INSTALLING: 'SuggestAppsDialog.State.INSTALLING',
+  INSTALLED_CLOSING: 'SuggestAppsDialog.State.INSTALLED_CLOSING',
+  OPENING_WEBSTORE_CLOSING: 'SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING',
+  CANCELED_CLOSING: 'SuggestAppsDialog.State.CANCELED_CLOSING'
+};
+Object.freeze(SuggestAppsDialog.State);
+
+/**
+ * @enum {string}
+ * @const
+ */
+SuggestAppsDialog.Result = {
+  // Install is done. The install app should be opened.
+  INSTALL_SUCCESSFUL: 'SuggestAppsDialog.Result.INSTALL_SUCCESSFUL',
+  // User cancelled the suggest app dialog. No message should be shown.
+  USER_CANCELL: 'SuggestAppsDialog.Result.USER_CANCELL',
+  // User clicked the link to web store so the dialog is closed.
+  WEBSTORE_LINK_OPENED: 'SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED',
+  // Failed to load the widget. Error message should be shown.
+  FAILED: 'SuggestAppsDialog.Result.FAILED'
+};
+Object.freeze(SuggestAppsDialog.Result);
+
+/**
+ * @override
+ */
+SuggestAppsDialog.prototype.onInputFocus = function() {
+  this.webviewContainer_.select();
+};
+
+/**
+ * Injects headers into the passed request.
+ *
+ * @param {Event} e Request event.
+ * @return {{requestHeaders: HttpHeaders}} Modified headers.
+ * @private
+ */
+SuggestAppsDialog.prototype.authorizeRequest_ = function(e) {
+  e.requestHeaders.push({
+    name: 'Authorization',
+    value: 'Bearer ' + this.accessToken_
+  });
+  return {requestHeaders: e.requestHeaders};
+};
+
+/**
+ * Retrieves the authorize token. This method should be called in
+ * initialization of the dialog.
+ *
+ * @param {function()} callback Called when the token is retrieved.
+ * @private
+ */
+SuggestAppsDialog.prototype.retrieveAuthorizeToken_ = function(callback) {
+  if (window.IN_TEST) {
+    // In test, use a dummy string as token. This must be a non-empty string.
+    this.accessToken_ = 'DUMMY_ACCESS_TOKEN_FOR_TEST';
+  }
+
+  if (this.accessToken_) {
+    callback();
+    return;
+  }
+
+  // Fetch or update the access token.
+  chrome.fileBrowserPrivate.requestWebStoreAccessToken(
+      function(accessToken) {
+        // In case of error, this.accessToken_ will be set to null.
+        this.accessToken_ = accessToken;
+        callback();
+      }.bind(this));
+};
+
+/**
+ * Shows dialog.
+ *
+ * @param {string} extension Extension of the file.
+ * @param {string} mime Mime of the file.
+ * @param {function(boolean)} onDialogClosed Called when the dialog is closed.
+ *     The argument is the result of installation: true if an app is installed,
+ *     false otherwise.
+ */
+SuggestAppsDialog.prototype.show = function(extension, mime, onDialogClosed) {
+  if (this.state_ != SuggestAppsDialog.State.UNINITIALIZED) {
+    console.error('Invalid state.');
+    return;
+  }
+
+  this.extension_ = extension;
+  this.mimeType_ = mime;
+  this.onDialogClosed_ = onDialogClosed;
+  this.state_ = SuggestAppsDialog.State.INITIALIZING;
+
+  SuggestAppsDialog.Metrics.recordShowDialog();
+  SuggestAppsDialog.Metrics.startLoad();
+
+  // Makes it sure that the initialization is completed.
+  this.initializationTask_.run(function() {
+    if (!this.accessToken_) {
+      this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
+      this.onHide_();
+      return;
+    }
+
+    var title = str('SUGGEST_DIALOG_TITLE');
+
+    var show =
+        FileManagerDialogBase.prototype.showTitleOnlyDialog.call(this, title);
+    if (!show) {
+      console.error('SuggestAppsDialog can\'t be shown');
+      this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
+      this.onHide();
+      return;
+    }
+
+    this.webview_ = this.document_.createElement('webview');
+    this.webview_.id = 'cws-widget';
+    this.webview_.partition = 'persist:cwswidgets';
+    this.webview_.style.width = WEBVIEW_WIDTH + 'px';
+    this.webview_.style.height = WEBVIEW_HEIGHT + 'px';
+    this.webview_.request.onBeforeSendHeaders.addListener(
+        this.authorizeRequest_.bind(this),
+        {urls: [this.widgetOrigin_ + '/*']},
+        ['blocking', 'requestHeaders']);
+    this.webview_.addEventListener('newwindow', function(event) {
+      // Discard the window object and reopen in an external window.
+      event.window.discard();
+      util.visitURL(event.targetUrl);
+      event.preventDefault();
+    });
+    this.webviewContainer_.appendChild(this.webview_);
+
+    this.frame_.classList.add('show-spinner');
+
+    this.webviewClient_ = new CWSContainerClient(
+        this.webview_,
+        extension, mime,
+        WEBVIEW_WIDTH, WEBVIEW_HEIGHT,
+        this.widgetUrl_, this.widgetOrigin_);
+    this.webviewClient_.addEventListener(CWSContainerClient.Events.LOADED,
+                                         this.onWidgetLoaded_.bind(this));
+    this.webviewClient_.addEventListener(CWSContainerClient.Events.LOAD_FAILED,
+                                         this.onWidgetLoadFailed_.bind(this));
+    this.webviewClient_.addEventListener(
+        CWSContainerClient.Events.REQUEST_INSTALL,
+        this.onInstallRequest_.bind(this));
+    this.webviewClient_.load();
+  }.bind(this));
+};
+
+/**
+ * Called when the 'See more...' link is clicked to be navigated to Webstore.
+ * @param {Event} e Event.
+ * @private
+ */
+SuggestAppsDialog.prototype.onWebstoreLinkClicked_ = function(e) {
+  var webStoreUrl =
+      FileTasks.createWebStoreLink(this.extension_, this.mimeType_);
+  chrome.windows.create({url: webStoreUrl});
+  this.state_ = SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING;
+  this.hide();
+};
+
+/**
+ * Called when the widget is loaded successfully.
+ * @param {Event} event Event.
+ * @private
+ */
+SuggestAppsDialog.prototype.onWidgetLoaded_ = function(event) {
+  SuggestAppsDialog.Metrics.finishLoad();
+  SuggestAppsDialog.Metrics.recordLoad(
+      SuggestAppsDialog.Metrics.LOAD.SUCCEEDED);
+
+  this.frame_.classList.remove('show-spinner');
+  this.state_ = SuggestAppsDialog.State.INITIALIZED;
+
+  this.webview_.focus();
+};
+
+/**
+ * Called when the widget is failed to load.
+ * @param {Event} event Event.
+ * @private
+ */
+SuggestAppsDialog.prototype.onWidgetLoadFailed_ = function(event) {
+  SuggestAppsDialog.Metrics.recordLoad(SuggestAppsDialog.Metrics.LOAD.FAILURE);
+
+  this.frame_.classList.remove('show-spinner');
+  this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
+
+  this.hide();
+};
+
+/**
+ * Called when the connection status is changed.
+ * @param {util.DriveConnectionType} connectionType Current connection type.
+ */
+SuggestAppsDialog.prototype.onDriveConnectionChanged =
+    function(connectionType) {
+  if (this.state_ !== SuggestAppsDialog.State.UNINITIALIZED &&
+      connectionType === util.DriveConnectionType.OFFLINE) {
+    this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
+    this.hide();
+  }
+};
+
+/**
+ * Called when receiving the install request from the webview client.
+ * @param {Event} e Event.
+ * @private
+ */
+SuggestAppsDialog.prototype.onInstallRequest_ = function(e) {
+  var itemId = e.itemId;
+  this.installingItemId_ = itemId;
+
+  this.appInstaller_ = new AppInstaller(itemId);
+  this.appInstaller_.install(this.onInstallCompleted_.bind(this));
+
+  this.frame_.classList.add('show-spinner');
+  this.state_ = SuggestAppsDialog.State.INSTALLING;
+};
+
+/**
+ * Called when the installation is completed from the app installer.
+ * @param {AppInstaller.Result} result Result of the installation.
+ * @param {string} error Detail of the error.
+ * @private
+ */
+SuggestAppsDialog.prototype.onInstallCompleted_ = function(result, error) {
+  var success = (result === AppInstaller.Result.SUCCESS);
+
+  this.frame_.classList.remove('show-spinner');
+  this.state_ = success ?
+                SuggestAppsDialog.State.INSTALLED_CLOSING :
+                SuggestAppsDialog.State.INITIALIZED;  // Back to normal state.
+  this.webviewClient_.onInstallCompleted(success, this.installingItemId_);
+  this.installingItemId_ = null;
+
+  switch (result) {
+  case AppInstaller.Result.SUCCESS:
+    SuggestAppsDialog.Metrics.recordInstall(
+        SuggestAppsDialog.Metrics.INSTALL.SUCCESS);
+    this.hide();
+    break;
+  case AppInstaller.Result.CANCELLED:
+    SuggestAppsDialog.Metrics.recordInstall(
+        SuggestAppsDialog.Metrics.INSTALL.CANCELLED);
+    // User cancelled the installation. Do nothing.
+    break;
+  case AppInstaller.Result.ERROR:
+    SuggestAppsDialog.Metrics.recordInstall(
+        SuggestAppsDialog.Metrics.INSTALL.FAILED);
+    fileManager.error.show(str('SUGGEST_DIALOG_INSTALLATION_FAILED'));
+    break;
+  }
+};
+
+/**
+ * @override
+ */
+SuggestAppsDialog.prototype.hide = function(opt_originalOnHide) {
+  switch (this.state_) {
+    case SuggestAppsDialog.State.INSTALLING:
+      // Install is being aborted. Send the failure result.
+      // Cancels the install.
+      if (this.webviewClient_)
+        this.webviewClient_.onInstallCompleted(false, this.installingItemId_);
+      this.installingItemId_ = null;
+
+      // Assumes closing the dialog as canceling the install.
+      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
+      break;
+    case SuggestAppsDialog.State.INITIALIZING:
+      SuggestAppsDialog.Metrics.recordLoad(
+          SuggestAppsDialog.Metrics.LOAD.CANCELLED);
+      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
+      break;
+    case SuggestAppsDialog.State.INSTALLED_CLOSING:
+    case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
+    case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING:
+      // Do nothing.
+      break;
+    case SuggestAppsDialog.State.INITIALIZED:
+      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
+      break;
+    default:
+      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
+      console.error('Invalid state.');
+  }
+
+  if (this.webviewClient_) {
+    this.webviewClient_.dispose();
+    this.webviewClient_ = null;
+  }
+
+  this.webviewContainer_.removeChild(this.webview_);
+  this.webview_ = null;
+  this.extension_ = null;
+  this.mime_ = null;
+
+  FileManagerDialogBase.prototype.hide.call(
+      this,
+      this.onHide_.bind(this, opt_originalOnHide));
+};
+
+/**
+ * @param {function()=} opt_originalOnHide Original onHide function passed to
+ *     SuggestAppsDialog.hide().
+ * @private
+ */
+SuggestAppsDialog.prototype.onHide_ = function(opt_originalOnHide) {
+  // Calls the callback after the dialog hides.
+  if (opt_originalOnHide)
+    opt_originalOnHide();
+
+  var result;
+  switch (this.state_) {
+    case SuggestAppsDialog.State.INSTALLED_CLOSING:
+      result = SuggestAppsDialog.Result.INSTALL_SUCCESSFUL;
+      SuggestAppsDialog.Metrics.recordCloseDialog(
+          SuggestAppsDialog.Metrics.CLOSE_DIALOG.ITEM_INSTALLED);
+      break;
+    case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
+      result = SuggestAppsDialog.Result.FAILED;
+      break;
+    case SuggestAppsDialog.State.CANCELED_CLOSING:
+      result = SuggestAppsDialog.Result.USER_CANCELL;
+      SuggestAppsDialog.Metrics.recordCloseDialog(
+          SuggestAppsDialog.Metrics.CLOSE_DIALOG.USER_CANCELL);
+      break;
+    case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING:
+      result = SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED;
+      SuggestAppsDialog.Metrics.recordCloseDialog(
+          SuggestAppsDialog.Metrics.CLOSE_DIALOG.WEB_STORE_LINK);
+      break;
+    default:
+      result = SuggestAppsDialog.Result.USER_CANCELL;
+      SuggestAppsDialog.Metrics.recordCloseDialog(
+          SuggestAppsDialog.Metrics.CLOSE_DIALOG.UNKNOWN_ERROR);
+      console.error('Invalid state.');
+  }
+  this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
+
+  this.onDialogClosed_(result);
+};
+
+/**
+ * Utility methods and constants to record histograms.
+ */
+SuggestAppsDialog.Metrics = Object.freeze({
+  LOAD: Object.freeze({
+    SUCCEEDED: 0,
+    CANCELLED: 1,
+    FAILED: 2,
+  }),
+
+  /**
+   * @param {SuggestAppsDialog.Metrics.LOAD} result Result of load.
+   */
+  recordLoad: function(result) {
+    if (0 <= result && result < 3)
+      metrics.recordEnum('SuggestApps.Load', result, 3);
+  },
+
+  CLOSE_DIALOG: Object.freeze({
+    UNKOWN_ERROR: 0,
+    ITEM_INSTALLED: 1,
+    USER_CANCELLED: 2,
+    WEBSTORE_LINK_OPENED: 3,
+  }),
+
+  /**
+   * @param {SuggestAppsDialog.Metrics.CLOSE_DIALOG} reason Reason of closing
+   * dialog.
+   */
+  recordCloseDialog: function(reason) {
+    if (0 <= reason && reason < 4)
+      metrics.recordEnum('SuggestApps.CloseDialog', reason, 4);
+  },
+
+  INSTALL: Object.freeze({
+    SUCCEEDED: 0,
+    CANCELLED: 1,
+    FAILED: 2,
+  }),
+
+  /**
+   * @param {SuggestAppsDialog.Metrics.INSTALL} result Result of installation.
+   */
+  recordInstall: function(result) {
+    if (0 <= result && result < 3)
+      metrics.recordEnum('SuggestApps.Install', result, 3);
+  },
+
+  recordShowDialog: function() {
+    metrics.recordUserAction('SuggestApps.ShowDialog');
+  },
+
+  startLoad: function() {
+    metrics.startInterval('SuggestApps.LoadTime');
+  },
+
+  finishLoad: function() {
+    metrics.recordInterval('SuggestApps.LoadTime');
+  },
+});
diff --git a/chrome/browser/resources/file_manager/js/text_measure.js b/chrome/browser/resources/file_manager/foreground/js/text_measure.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/text_measure.js
rename to chrome/browser/resources/file_manager/foreground/js/text_measure.js
diff --git a/chrome/browser/resources/file_manager/js/tree.css.js b/chrome/browser/resources/file_manager/foreground/js/tree.css.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/tree.css.js
rename to chrome/browser/resources/file_manager/foreground/js/tree.css.js
diff --git a/chrome/browser/resources/file_manager/js/ui/breadcrumbs_controller.js b/chrome/browser/resources/file_manager/foreground/js/ui/breadcrumbs_controller.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/breadcrumbs_controller.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/breadcrumbs_controller.js
diff --git a/chrome/browser/resources/file_manager/js/ui/conflict_dialog.js b/chrome/browser/resources/file_manager/foreground/js/ui/conflict_dialog.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/conflict_dialog.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/conflict_dialog.js
diff --git a/chrome/browser/resources/file_manager/js/ui/file_manager_dialog_base.js b/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_dialog_base.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/file_manager_dialog_base.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/file_manager_dialog_base.js
diff --git a/chrome/browser/resources/file_manager/js/ui/file_manager_ui.js b/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_ui.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/file_manager_ui.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/file_manager_ui.js
diff --git a/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js b/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js
new file mode 100644
index 0000000..6ff21fd
--- /dev/null
+++ b/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js
@@ -0,0 +1,386 @@
+// Copyright (c) 2012 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.
+
+'use strict';
+
+/**
+ * A navigation list item.
+ * @constructor
+ * @extends {HTMLLIElement}
+ */
+var NavigationListItem = cr.ui.define('li');
+
+NavigationListItem.prototype = {
+  __proto__: HTMLLIElement.prototype,
+  get modelItem() { return this.modelItem_; }
+};
+
+/**
+ * Decorate the item.
+ */
+NavigationListItem.prototype.decorate = function() {
+  // decorate() may be called twice: from the constructor and from
+  // List.createItem(). This check prevents double-decorating.
+  if (this.className)
+    return;
+
+  this.className = 'root-item';
+  this.setAttribute('role', 'option');
+
+  this.iconDiv_ = cr.doc.createElement('div');
+  this.iconDiv_.className = 'volume-icon';
+  this.appendChild(this.iconDiv_);
+
+  this.label_ = cr.doc.createElement('div');
+  this.label_.className = 'root-label';
+  this.appendChild(this.label_);
+
+  cr.defineProperty(this, 'lead', cr.PropertyKind.BOOL_ATTR);
+  cr.defineProperty(this, 'selected', cr.PropertyKind.BOOL_ATTR);
+};
+
+/**
+ * Associate a path with this item.
+ * @param {NavigationModelItem} modelItem NavigationModelItem of this item.
+ * @param {string=} opt_deviceType The type of the device. Available iff the
+ *     path represents removable storage.
+ */
+NavigationListItem.prototype.setModelItem =
+    function(modelItem, opt_deviceType) {
+  if (this.modelItem_)
+    console.warn('NavigationListItem.setModelItem should be called only once.');
+
+  this.modelItem_ = modelItem;
+
+  var rootType = PathUtil.getRootType(modelItem.path);
+  this.iconDiv_.setAttribute('volume-type-icon', rootType);
+  if (opt_deviceType) {
+    this.iconDiv_.setAttribute('volume-subtype', opt_deviceType);
+  }
+
+  this.label_.textContent = PathUtil.getFolderLabel(modelItem.path);
+
+  if (rootType === RootType.ARCHIVE || rootType === RootType.REMOVABLE) {
+    this.eject_ = cr.doc.createElement('div');
+    // Block other mouse handlers.
+    this.eject_.addEventListener(
+        'mouseup', function(event) { event.stopPropagation() });
+    this.eject_.addEventListener(
+        'mousedown', function(event) { event.stopPropagation() });
+
+    this.eject_.className = 'root-eject';
+    this.eject_.addEventListener('click', function(event) {
+      event.stopPropagation();
+      cr.dispatchSimpleEvent(this, 'eject');
+    }.bind(this));
+
+    this.appendChild(this.eject_);
+  }
+};
+
+/**
+ * Associate a context menu with this item.
+ * @param {cr.ui.Menu} menu Menu this item.
+ */
+NavigationListItem.prototype.maybeSetContextMenu = function(menu) {
+  if (!this.modelItem_.path) {
+    console.error('NavigationListItem.maybeSetContextMenu must be called ' +
+                  'after setModelItem().');
+    return;
+  }
+
+  var isRoot = PathUtil.isRootPath(this.modelItem_.path);
+  var rootType = PathUtil.getRootType(this.modelItem_.path);
+  // The context menu is shown on the following items:
+  // - Removable and Archive volumes
+  // - Folder shortcuts
+  if (!isRoot ||
+      (rootType != RootType.DRIVE && rootType != RootType.DOWNLOADS))
+    cr.ui.contextMenuHandler.setContextMenu(this, menu);
+};
+
+/**
+ * A navigation list.
+ * @constructor
+ * @extends {cr.ui.List}
+ */
+function NavigationList() {
+}
+
+/**
+ * NavigationList inherits cr.ui.List.
+ */
+NavigationList.prototype = {
+  __proto__: cr.ui.List.prototype,
+
+  set dataModel(dataModel) {
+    if (!this.onListContentChangedBound_)
+      this.onListContentChangedBound_ = this.onListContentChanged_.bind(this);
+
+    if (this.dataModel_) {
+      this.dataModel_.removeEventListener(
+          'change', this.onListContentChangedBound_);
+      this.dataModel_.removeEventListener(
+          'permuted', this.onListContentChangedBound_);
+    }
+
+    var parentSetter = cr.ui.List.prototype.__lookupSetter__('dataModel');
+    parentSetter.call(this, dataModel);
+
+    // This must be placed after the parent method is called, in order to make
+    // it sure that the list was changed.
+    dataModel.addEventListener('change', this.onListContentChangedBound_);
+    dataModel.addEventListener('permuted', this.onListContentChangedBound_);
+  },
+
+  get dataModel() {
+    return this.dataModel_;
+  },
+
+  // TODO(yoshiki): Add a setter of 'directoryModel'.
+};
+
+/**
+ * @param {HTMLElement} el Element to be DirectoryItem.
+ * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ *     folders.
+ */
+NavigationList.decorate = function(el, volumeManager, directoryModel) {
+  el.__proto__ = NavigationList.prototype;
+  el.decorate(volumeManager, directoryModel);
+};
+
+/**
+ * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ */
+NavigationList.prototype.decorate = function(volumeManager, directoryModel) {
+  cr.ui.List.decorate(this);
+  this.__proto__ = NavigationList.prototype;
+
+  this.directoryModel_ = directoryModel;
+  this.volumeManager_ = volumeManager;
+  this.selectionModel = new cr.ui.ListSingleSelectionModel();
+
+  this.directoryModel_.addEventListener('directory-changed',
+      this.onCurrentDirectoryChanged_.bind(this));
+  this.selectionModel.addEventListener(
+      'change', this.onSelectionChange_.bind(this));
+  this.selectionModel.addEventListener(
+      'beforeChange', this.onBeforeSelectionChange_.bind(this));
+
+  this.scrollBar_ = new ScrollBar();
+  this.scrollBar_.initialize(this.parentNode, this);
+
+  // Overriding default role 'list' set by cr.ui.List.decorate() to 'listbox'
+  // role for better accessibility on ChromeOS.
+  this.setAttribute('role', 'listbox');
+
+  var self = this;
+  this.itemConstructor = function(modelItem) {
+    return self.renderRoot_(modelItem);
+  };
+};
+
+/**
+ * This overrides cr.ui.List.measureItem().
+ * In the method, a temporary element is added/removed from the list, and we
+ * need to omit animations for such temporary items.
+ *
+ * @param {ListItem=} opt_item The list item to be measured.
+ * @return {{height: number, marginTop: number, marginBottom:number,
+ *     width: number, marginLeft: number, marginRight:number}} Size.
+ * @override
+ */
+NavigationList.prototype.measureItem = function(opt_item) {
+  this.measuringTemporaryItemNow_ = true;
+  var result = cr.ui.List.prototype.measureItem.call(this, opt_item);
+  this.measuringTemporaryItemNow_ = false;
+  return result;
+};
+
+/**
+ * Creates an element of a navigation list. This method is called from
+ * cr.ui.List internally.
+ *
+ * @param {NavigationModelItem} modelItem NavigationModelItem to be rendered.
+ * @return {NavigationListItem} Rendered element.
+ * @private
+ */
+NavigationList.prototype.renderRoot_ = function(modelItem) {
+  var item = new NavigationListItem();
+  var volumeInfo =
+      PathUtil.isRootPath(modelItem.path) &&
+      this.volumeManager_.getVolumeInfo(modelItem.path);
+  item.setModelItem(modelItem, volumeInfo && volumeInfo.deviceType);
+
+  var handleClick = function() {
+    if (item.selected &&
+        modelItem.path !== this.directoryModel_.getCurrentDirPath()) {
+      metrics.recordUserAction('FolderShortcut.Navigate');
+      this.changeDirectory_(modelItem);
+    }
+  }.bind(this);
+  item.addEventListener('click', handleClick);
+
+  var handleEject = function() {
+    var unmountCommand = cr.doc.querySelector('command#unmount');
+    // Let's make sure 'canExecute' state of the command is properly set for
+    // the root before executing it.
+    unmountCommand.canExecuteChange(item);
+    unmountCommand.execute(item);
+  };
+  item.addEventListener('eject', handleEject);
+
+  if (this.contextMenu_)
+    item.maybeSetContextMenu(this.contextMenu_);
+
+  return item;
+};
+
+/**
+ * Changes the current directory to the given path.
+ * If the given path is not found, a 'shortcut-target-not-found' event is
+ * fired.
+ *
+ * @param {NavigationModelItem} modelItem Directory to be chagned to.
+ * @private
+ */
+NavigationList.prototype.changeDirectory_ = function(modelItem) {
+  var onErrorCallback = function(error) {
+    if (error.code === FileError.NOT_FOUND_ERR)
+      this.dataModel.onItemNotFoundError(modelItem);
+  }.bind(this);
+
+  this.directoryModel_.changeDirectory(modelItem.path, onErrorCallback);
+};
+
+/**
+ * Sets a context menu. Context menu is enabled only on archive and removable
+ * volumes as of now.
+ *
+ * @param {cr.ui.Menu} menu Context menu.
+ */
+NavigationList.prototype.setContextMenu = function(menu) {
+  this.contextMenu_ = menu;
+
+  for (var i = 0; i < this.dataModel.length; i++) {
+    this.getListItemByIndex(i).maybeSetContextMenu(this.contextMenu_);
+  }
+};
+
+/**
+ * Selects the n-th item from the list.
+ *
+ * @param {number} index Item index.
+ * @return {boolean} True for success, otherwise false.
+ */
+NavigationList.prototype.selectByIndex = function(index) {
+  if (index < 0 || index > this.dataModel.length - 1)
+    return false;
+
+  var newModelItem = this.dataModel.item(index);
+  var newPath = newModelItem.path;
+  if (!newPath)
+    return false;
+
+  // Prevents double-moving to the current directory.
+  // eg. When user clicks the item, changing directory has already been done in
+  //     click handler.
+  var entry = this.directoryModel_.getCurrentDirEntry();
+  if (entry && entry.fullPath == newPath)
+    return false;
+
+  metrics.recordUserAction('FolderShortcut.Navigate');
+  this.changeDirectory_(newModelItem);
+  return true;
+};
+
+/**
+ * Handler before root item change.
+ * @param {Event} event The event.
+ * @private
+ */
+NavigationList.prototype.onBeforeSelectionChange_ = function(event) {
+  if (event.changes.length == 1 && !event.changes[0].selected)
+    event.preventDefault();
+};
+
+/**
+ * Handler for root item being clicked.
+ * @param {Event} event The event.
+ * @private
+ */
+NavigationList.prototype.onSelectionChange_ = function(event) {
+  // This handler is invoked even when the navigation list itself changes the
+  // selection. In such case, we shouldn't handle the event.
+  if (this.dontHandleSelectionEvent_)
+    return;
+
+  this.selectByIndex(this.selectionModel.selectedIndex);
+};
+
+/**
+ * Invoked when the current directory is changed.
+ * @param {Event} event The event.
+ * @private
+ */
+NavigationList.prototype.onCurrentDirectoryChanged_ = function(event) {
+  this.selectBestMatchItem_();
+};
+
+/**
+ * Invoked when the content in the data model is changed.
+ * @param {Event} event The event.
+ * @private
+ */
+NavigationList.prototype.onListContentChanged_ = function(event) {
+  this.selectBestMatchItem_();
+};
+
+/**
+ * Synchronizes the volume list selection with the current directory, after
+ * it is changed outside of the volume list.
+ * @private
+ */
+NavigationList.prototype.selectBestMatchItem_ = function() {
+  var entry = this.directoryModel_.getCurrentDirEntry();
+  var path = entry && entry.fullPath;
+  if (!path)
+    return;
+
+  // (1) Select the nearest parent directory (including the shortcut folders).
+  var bestMatchIndex = -1;
+  var bestMatchSubStringLen = 0;
+  for (var i = 0; i < this.dataModel.length; i++) {
+    var itemPath = this.dataModel.item(i).path;
+    if (path.indexOf(itemPath) == 0) {
+      if (bestMatchSubStringLen < itemPath.length) {
+        bestMatchIndex = i;
+        bestMatchSubStringLen = itemPath.length;
+      }
+    }
+  }
+  if (bestMatchIndex != -1) {
+    // Not to invoke the handler of this instance, sets the guard.
+    this.dontHandleSelectionEvent_ = true;
+    this.selectionModel.selectedIndex = bestMatchIndex;
+    this.dontHandleSelectionEvent_ = false;
+    return;
+  }
+
+  // (2) Selects the volume of the current directory.
+  var newRootPath = PathUtil.getRootPath(path);
+  for (var i = 0; i < this.dataModel.length; i++) {
+    var itemPath = this.dataModel.item(i).path;
+    if (PathUtil.getRootPath(itemPath) == newRootPath) {
+      // Not to invoke the handler of this instance, sets the guard.
+      this.dontHandleSelectionEvent_ = true;
+      this.selectionModel.selectedIndex = i;
+      this.dontHandleSelectionEvent_ = false;
+      return;
+    }
+  }
+};
diff --git a/chrome/browser/resources/file_manager/js/ui/preview_panel.js b/chrome/browser/resources/file_manager/foreground/js/ui/preview_panel.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/preview_panel.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/preview_panel.js
diff --git a/chrome/browser/resources/file_manager/js/ui/progress_center_panel.js b/chrome/browser/resources/file_manager/foreground/js/ui/progress_center_panel.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/progress_center_panel.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/progress_center_panel.js
diff --git a/chrome/browser/resources/file_manager/js/ui/search_box.js b/chrome/browser/resources/file_manager/foreground/js/ui/search_box.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/ui/search_box.js
rename to chrome/browser/resources/file_manager/foreground/js/ui/search_box.js
diff --git a/chrome/browser/resources/file_manager/js/url_constants.js b/chrome/browser/resources/file_manager/foreground/js/url_constants.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/url_constants.js
rename to chrome/browser/resources/file_manager/foreground/js/url_constants.js
diff --git a/chrome/browser/resources/file_manager/js/volume_manager_wrapper.js b/chrome/browser/resources/file_manager/foreground/js/volume_manager_wrapper.js
similarity index 100%
rename from chrome/browser/resources/file_manager/js/volume_manager_wrapper.js
rename to chrome/browser/resources/file_manager/foreground/js/volume_manager_wrapper.js
diff --git a/chrome/browser/resources/file_manager/gallery.html b/chrome/browser/resources/file_manager/gallery.html
index 3b3d7b0..7bf6c2c 100644
--- a/chrome/browser/resources/file_manager/gallery.html
+++ b/chrome/browser/resources/file_manager/gallery.html
@@ -13,14 +13,14 @@
 
   <!-- Don't load gallery_scripts.js when flattening is disabled -->
   <if expr="0"><!-- </if>
-    <script src="js/photo/gallery_scripts.js"></script>
+    <script src="foreground/js/photo/gallery_scripts.js"></script>
   <if expr="0"> --></if>
 
   <if expr="0">
     <!-- This section is used when the file manager is loaded with
          'filemgr-ext-path' command-line flag. -->
     <!-- Keep the list in sync with gallery_scripts.js. -->
-    <script src="js/metrics.js"></script>
+    <script src="foreground/js/metrics.js"></script>
 
     <!-- Loads the client of the image loader extension -->
     <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
@@ -41,35 +41,36 @@
     <script src="chrome://resources/js/cr/ui/list.js"></script>
     <script src="chrome://resources/js/cr/ui/grid.js"></script>
 
-    <script src="js/file_type.js"></script>
-    <script src="js/async_util.js"></script>
-    <script src="js/util.js"></script>
-    <script src="js/path_util.js"></script>
-    <script src="js/volume_manager_wrapper.js"></script>
+    <script src="common/js/async_util.js"></script>
+    <script src="common/js/util.js"></script>
+    <script src="common/js/path_util.js"></script>
 
-    <script src="js/image_editor/image_util.js"></script>
-    <script src="js/image_editor/viewport.js"></script>
-    <script src="js/image_editor/image_buffer.js"></script>
-    <script src="js/image_editor/image_view.js"></script>
-    <script src="js/image_editor/commands.js"></script>
-    <script src="js/image_editor/image_editor.js"></script>
-    <script src="js/image_editor/image_transform.js"></script>
-    <script src="js/image_editor/image_adjust.js"></script>
-    <script src="js/image_editor/filter.js"></script>
-    <script src="js/image_editor/image_encoder.js"></script>
-    <script src="js/image_editor/exif_encoder.js"></script>
+    <script src="foreground/js/file_type.js"></script>
+    <script src="foreground/js/volume_manager_wrapper.js"></script>
 
-    <script src="js/media/media_controls.js"></script>
-    <script src="js/media/media_util.js"></script>
-    <script src="js/media/util.js"></script>
+    <script src="foreground/js/image_editor/image_util.js"></script>
+    <script src="foreground/js/image_editor/viewport.js"></script>
+    <script src="foreground/js/image_editor/image_buffer.js"></script>
+    <script src="foreground/js/image_editor/image_view.js"></script>
+    <script src="foreground/js/image_editor/commands.js"></script>
+    <script src="foreground/js/image_editor/image_editor.js"></script>
+    <script src="foreground/js/image_editor/image_transform.js"></script>
+    <script src="foreground/js/image_editor/image_adjust.js"></script>
+    <script src="foreground/js/image_editor/filter.js"></script>
+    <script src="foreground/js/image_editor/image_encoder.js"></script>
+    <script src="foreground/js/image_editor/exif_encoder.js"></script>
 
-    <script src="js/metadata/metadata_cache.js"></script>
+    <script src="foreground/js/media/media_controls.js"></script>
+    <script src="foreground/js/media/media_util.js"></script>
+    <script src="foreground/js/media/util.js"></script>
 
-    <script src="js/photo/gallery.js"></script>
-    <script src="js/photo/gallery_item.js"></script>
-    <script src="js/photo/mosaic_mode.js"></script>
-    <script src="js/photo/slide_mode.js"></script>
-    <script src="js/photo/ribbon.js"></script>
+    <script src="foreground/js/metadata/metadata_cache.js"></script>
+
+    <script src="foreground/js/photo/gallery.js"></script>
+    <script src="foreground/js/photo/gallery_item.js"></script>
+    <script src="foreground/js/photo/mosaic_mode.js"></script>
+    <script src="foreground/js/photo/slide_mode.js"></script>
+    <script src="foreground/js/photo/ribbon.js"></script>
   </if>
 </head>
 <body>
diff --git a/chrome/browser/resources/file_manager/images/common/2x/check_blue.png b/chrome/browser/resources/file_manager/images/common/2x/check_blue.png
deleted file mode 100644
index 404d14f..0000000
--- a/chrome/browser/resources/file_manager/images/common/2x/check_blue.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/check_circled.png b/chrome/browser/resources/file_manager/images/common/2x/check_circled.png
deleted file mode 100644
index 5567ac2..0000000
--- a/chrome/browser/resources/file_manager/images/common/2x/check_circled.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/check_blue.png b/chrome/browser/resources/file_manager/images/common/check_blue.png
deleted file mode 100644
index eedcd4d..0000000
--- a/chrome/browser/resources/file_manager/images/common/check_blue.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/check_circled.png b/chrome/browser/resources/file_manager/images/common/check_circled.png
deleted file mode 100644
index 27dde79..0000000
--- a/chrome/browser/resources/file_manager/images/common/check_circled.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/js/action_choice.js b/chrome/browser/resources/file_manager/js/action_choice.js
deleted file mode 100644
index 4c5bec5..0000000
--- a/chrome/browser/resources/file_manager/js/action_choice.js
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright (c) 2013 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.
-
-'use strict';
-
-document.addEventListener('DOMContentLoaded', function() {
-  ActionChoice.load();
-});
-
-/**
- * The main ActionChoice object.
- *
- * @param {HTMLElement} dom Container.
- * @param {Object} params Parameters.
- * @constructor
- */
-function ActionChoice(dom, params) {
-  this.dom_ = dom;
-  this.params_ = params;
-  this.document_ = this.dom_.ownerDocument;
-  this.metadataCache_ = this.params_.metadataCache;
-  this.volumeManager_ = new VolumeManagerWrapper(
-      VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED);
-  this.volumeManager_.addEventListener('externally-unmounted',
-     this.onDeviceUnmounted_.bind(this));
-  this.initDom_();
-
-  // Load defined actions and remembered choice, then initialize volumes.
-  this.actions_ = [];
-  this.actionsById_ = {};
-  this.rememberedChoice_ = null;
-
-  ActionChoiceUtil.getDefinedActions(loadTimeData, function(actions) {
-    for (var i = 0; i < actions.length; i++) {
-      this.registerAction_(actions[i]);
-    }
-
-    this.viewFilesAction_ = this.actionsById_['view-files'];
-    this.importPhotosToDriveAction_ =
-        this.actionsById_['import-photos-to-drive'];
-    this.watchSingleVideoAction_ =
-        this.actionsById_['watch-single-video'];
-
-    // Special case: if Google+ Photos is installed, then do not show Drive.
-    for (var i = 0; i < actions.length; i++) {
-      if (actions[i].extensionId == ActionChoice.GPLUS_PHOTOS_EXTENSION_ID) {
-        this.importPhotosToDriveAction_.hidden = true;
-        break;
-      }
-    }
-
-    if (this.params_.advancedMode) {
-      // In the advanced mode, skip auto-choice.
-      this.initializeVolumes_();
-    } else {
-      // Get the remembered action before initializing volumes.
-      ActionChoiceUtil.getRememberedActionId(function(actionId) {
-        this.rememberedChoice_ = actionId;
-        this.initializeVolumes_();
-      }.bind(this));
-    }
-    this.renderList_();
-  }.bind(this));
-
-  // Try to render, what is already available.
-  this.renderList_();
-}
-
-ActionChoice.prototype = { __proto__: cr.EventTarget.prototype };
-
-/**
- * The number of previews shown.
- * @type {number}
- * @const
- */
-ActionChoice.PREVIEW_COUNT = 3;
-
-/**
- * Extension id of Google+ Photos app.
- * @type {string}
- * @const
- */
-ActionChoice.GPLUS_PHOTOS_EXTENSION_ID = 'efjnaogkjbogokcnohkmnjdojkikgobo';
-
-/**
- * Loads app in the document body.
- * @param {Object=} opt_params Parameters.
- */
-ActionChoice.load = function(opt_params) {
-  ImageUtil.metrics = metrics;
-
-  var hash = location.hash ? decodeURIComponent(location.hash.substr(1)) : '';
-  var query =
-      location.search ? decodeURIComponent(location.search.substr(1)) : '';
-  var params = opt_params || {};
-  if (!params.source) params.source = hash;
-  if (!params.advancedMode) params.advancedMode = (query == 'advanced-mode');
-  if (!params.metadataCache) params.metadataCache = MetadataCache.createFull();
-
-  chrome.fileBrowserPrivate.getStrings(function(strings) {
-    loadTimeData.data = strings;
-    i18nTemplate.process(document, loadTimeData);
-    var dom = document.querySelector('.action-choice');
-    ActionChoice.instance = new ActionChoice(dom, params);
-  });
-};
-
-/**
- * Registers an action.
- * @param {Object} action Action item.
- * @private
- */
-ActionChoice.prototype.registerAction_ = function(action) {
-  this.actions_.push(action);
-  this.actionsById_[action.id] = action;
-};
-
-/**
- * Initializes the source and Drive. If the remembered choice is available,
- * then performs the action.
- * @private
- */
-ActionChoice.prototype.initializeVolumes_ = function() {
-  var checkDriveFinished = false;
-  var loadSourceFinished = false;
-
-  var maybeRunRememberedAction = function() {
-    if (!checkDriveFinished || !loadSourceFinished)
-      return;
-
-    // Run the remembered action if it is available.
-    if (this.rememberedChoice_) {
-      var action = this.actionsById_[this.rememberedChoice_];
-      if (action && !action.disabled)
-        this.runAction_(action);
-    }
-  }.bind(this);
-
-  var onCheckDriveFinished = function() {
-    checkDriveFinished = true;
-    maybeRunRememberedAction();
-  };
-
-  var onLoadSourceFinished = function() {
-    loadSourceFinished = true;
-    maybeRunRememberedAction();
-  };
-
-  this.checkDrive_(onCheckDriveFinished);
-  this.loadSource_(this.params_.source, onLoadSourceFinished);
-};
-
-/**
- * One-time initialization of dom elements.
- * @private
- */
-ActionChoice.prototype.initDom_ = function() {
-  this.list_ = new cr.ui.List();
-  this.list_.id = 'actions-list';
-  this.document_.querySelector('.choices').appendChild(this.list_);
-
-  var self = this;  // .bind(this) doesn't work on constructors.
-  this.list_.itemConstructor = function(item) {
-    return self.renderItem(item);
-  };
-
-  this.list_.selectionModel = new cr.ui.ListSingleSelectionModel();
-  this.list_.dataModel = new cr.ui.ArrayDataModel([]);
-  this.list_.autoExpands = true;
-
-  var acceptActionBound = function() {
-    this.acceptAction_();
-  }.bind(this);
-  this.list_.activateItemAtIndex = acceptActionBound;
-  this.list_.addEventListener('click', acceptActionBound);
-
-  this.previews_ = this.document_.querySelector('.previews');
-  this.counter_ = this.document_.querySelector('.counter');
-  this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
-
-  metrics.startInterval('PhotoImport.Load');
-  this.dom_.setAttribute('loading', '');
-};
-
-/**
- * Renders the list.
- * @private
- */
-ActionChoice.prototype.renderList_ = function() {
-  var currentItem = this.list_.dataModel.item(
-      this.list_.selectionModel.selectedIndex);
-
-  this.list_.startBatchUpdates();
-  this.list_.dataModel.splice(0, this.list_.dataModel.length);
-
-  for (var i = 0; i < this.actions_.length; i++) {
-    if (!this.actions_[i].hidden)
-      this.list_.dataModel.push(this.actions_[i]);
-  }
-
-  for (var i = 0; i < this.list_.dataModel.length; i++) {
-    if (this.list_.dataModel.item(i) == currentItem) {
-      this.list_.selectionModel.selectedIndex = i;
-      break;
-    }
-  }
-
-  this.list_.endBatchUpdates();
-};
-
-/**
- * Renders an item in the list.
- * @param {Object} item Item to render.
- * @return {Element} DOM element with representing the item.
- */
-ActionChoice.prototype.renderItem = function(item) {
-  var result = this.document_.createElement('li');
-
-  var div = this.document_.createElement('div');
-  if (item.disabled && item.disabledTitle)
-    div.textContent = item.disabledTitle;
-  else
-    div.textContent = item.title;
-
-  if (item.class)
-    div.classList.add(item.class);
-  if (item.icon100 && item.icon200)
-    div.style.backgroundImage = '-webkit-image-set(' +
-        'url(' + item.icon100 + ') 1x,' +
-        'url(' + item.icon200 + ') 2x)';
-  if (item.disabled)
-    div.classList.add('disabled');
-
-  cr.defineProperty(result, 'lead', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(result, 'selected', cr.PropertyKind.BOOL_ATTR);
-  result.appendChild(div);
-
-  return result;
-};
-
-/**
- * Checks whether Drive is reachable.
- *
- * @param {function()} callback Completion callback.
- * @private
- */
-ActionChoice.prototype.checkDrive_ = function(callback) {
-  this.volumeManager_.ensureInitialized(function() {
-    this.importPhotosToDriveAction_.disabled =
-        !this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
-    this.renderList_();
-    callback();
-  }.bind(this));
-};
-
-/**
- * Load the source contents.
- *
- * @param {string} source Path to source.
- * @param {function()} callback Completion callback.
- * @private
- */
-ActionChoice.prototype.loadSource_ = function(source, callback) {
-  var onTraversed = function(results) {
-    metrics.recordInterval('PhotoImport.Scan');
-    var videos = results.filter(FileType.isVideo);
-    if (videos.length == 1) {
-      this.singleVideo_ = videos[0];
-      this.watchSingleVideoAction_.title = loadTimeData.getStringF(
-          'ACTION_CHOICE_WATCH_SINGLE_VIDEO', videos[0].name);
-      this.watchSingleVideoAction_.hidden = false;
-      this.watchSingleVideoAction_.disabled = false;
-      this.renderList_();
-    }
-
-    var mediaFiles = results.filter(FileType.isImageOrVideo);
-    if (mediaFiles.length == 0) {
-      // If we have no media files, the only choice is view files. So, don't
-      // confuse user with a single choice, and just open file manager.
-      this.viewFiles_();
-      this.recordAction_('view-files-auto');
-      this.close_();
-    }
-
-    if (mediaFiles.length < ActionChoice.PREVIEW_COUNT) {
-      this.counter_.textContent = loadTimeData.getStringF(
-          'ACTION_CHOICE_COUNTER_NO_MEDIA', results.length);
-    } else {
-      this.counter_.textContent = loadTimeData.getStringF(
-          'ACTION_CHOICE_COUNTER', mediaFiles.length);
-    }
-    var previews = mediaFiles.length ? mediaFiles : results;
-    var previewsCount = Math.min(ActionChoice.PREVIEW_COUNT, previews.length);
-    this.renderPreview_(previews, previewsCount);
-    callback();
-  }.bind(this);
-
-  var onEntry = function(entry) {
-    this.sourceEntry_ = entry;
-    this.document_.querySelector('title').textContent = entry.name;
-
-    var volumeInfo = this.volumeManager_.getVolumeInfo(entry.fullPath);
-    var deviceType = volumeInfo && volumeInfo.deviceType;
-    if (deviceType != 'sd') deviceType = 'usb';
-    this.dom_.querySelector('.device-type').setAttribute('device-type',
-        deviceType);
-    this.dom_.querySelector('.loading-text').textContent =
-        loadTimeData.getString('ACTION_CHOICE_LOADING_' +
-                               deviceType.toUpperCase());
-
-    var entryList = [];
-    util.traverseTree(
-        entry,
-        function(traversedEntry) {
-          if (!FileType.isVisible(traversedEntry))
-            return false;
-          entryList.push(traversedEntry);
-          return true;
-        },
-        function() {
-          onTraversed(entryList);
-        },
-        function(error) {
-          console.error(
-              'Failed to traverse [' + entry.fullPath + ']: ' + error.code);
-        });
-  }.bind(this);
-
-  this.sourceEntry_ = null;
-  metrics.startInterval('PhotoImport.Scan');
-  this.volumeManager_.ensureInitialized(function() {
-    this.volumeManager_.resolvePath(
-        source, onEntry,
-        function(error) {
-          this.recordAction_('error');
-          this.close_();
-        }.bind(this));
-  }.bind(this));
-};
-
-/**
- * Renders a preview for a media entry.
- * @param {Array.<FileEntry>} entries The entries.
- * @param {number} count Remaining count.
- * @private
- */
-ActionChoice.prototype.renderPreview_ = function(entries, count) {
-  var entry = entries.shift();
-  var box = this.document_.createElement('div');
-  box.className = 'img-container';
-
-  var done = function() {
-    this.dom_.removeAttribute('loading');
-    metrics.recordInterval('PhotoImport.Load');
-  }.bind(this);
-
-  var onSuccess = function() {
-    this.previews_.appendChild(box);
-    if (--count == 0) {
-      done();
-    } else {
-      this.renderPreview_(entries, count);
-    }
-  }.bind(this);
-
-  var onError = function() {
-    if (entries.length == 0) {
-      // Append one image with generic thumbnail.
-      this.previews_.appendChild(box);
-      done();
-    } else {
-      this.renderPreview_(entries, count);
-    }
-  }.bind(this);
-
-  this.metadataCache_.get(entry, 'thumbnail|filesystem',
-      function(metadata) {
-        new ThumbnailLoader(entry.toURL(),
-                            ThumbnailLoader.LoaderType.IMAGE,
-                            metadata).load(
-            box,
-            ThumbnailLoader.FillMode.FILL,
-            ThumbnailLoader.OptimizationMode.NEVER_DISCARD,
-            onSuccess,
-            onError,
-            onError);
-      });
-};
-
-/**
- * Closes the window.
- * @private
- */
-ActionChoice.prototype.close_ = function() {
-  window.close();
-};
-
-/**
- * Keydown event handler.
- * @param {Event} e The event.
- * @private
- */
-ActionChoice.prototype.onKeyDown_ = function(e) {
-  switch (util.getKeyModifiers(e) + e.keyCode) {
-    case '13':
-      this.acceptAction_();
-      break;
-    case '27':
-      this.recordAction_('close');
-      this.close_();
-      break;
-  }
-};
-
-/**
- * Runs an action.
- * @param {Object} action Action item to perform.
- * @private
- */
-ActionChoice.prototype.runAction_ = function(action) {
-  // TODO(mtomasz): Remove these predefined actions in Apps v2.
-  if (action == this.importPhotosToDriveAction_) {
-    var url = chrome.runtime.getURL('photo_import.html') +
-        '#' + this.sourceEntry_.fullPath;
-    var width = 728;
-    var height = 656;
-    var top = Math.round((window.screen.availHeight - height) / 2);
-    var left = Math.round((window.screen.availWidth - width) / 2);
-    chrome.app.window.create(url,
-        {height: height, width: width, left: left, top: top});
-    this.recordAction_('import-photos-to-drive');
-    this.close_();
-    return;
-  }
-
-  if (action == this.watchSingleVideoAction_) {
-    util.viewFilesInBrowser([this.singleVideo_.toURL()],
-                            function(success) {});
-    this.recordAction_('watch-single-video');
-    this.close_();
-    return;
-  }
-
-  if (action == this.viewFilesAction_) {
-    this.viewFiles_();
-    this.recordAction_('view-files');
-    this.close_();
-    return;
-  }
-
-  if (!action.extensionId) {
-    console.error('Unknown predefined action.');
-    return;
-  }
-
-  // Run the media galleries handler.
-  chrome.mediaGalleriesPrivate.launchHandler(action.extensionId,
-                                             action.actionId,
-                                             this.params_.source);
-  this.close_();
-};
-
-/**
- * Handles accepting an action. Checks if the action is available, remembers
- * and runs it.
- * @private
- */
-ActionChoice.prototype.acceptAction_ = function() {
-  var action =
-      this.list_.dataModel.item(this.list_.selectionModel.selectedIndex);
-  if (!action || action.hidden || action.disabled)
-    return;
-
-  this.runAction_(action);
-  ActionChoiceUtil.setRememberedActionId(action.id);
-};
-
-/**
- * Called when some device is unmounted.
- * @param {Event} event Event object.
- * @private
- */
-ActionChoice.prototype.onDeviceUnmounted_ = function(event) {
-  if (this.sourceEntry_ && event.mountPath == this.sourceEntry_.fullPath)
-    window.close();
-};
-
-/**
- * Perform the 'view files' action.
- * @private
- */
-ActionChoice.prototype.viewFiles_ = function() {
-  var path = this.sourceEntry_.fullPath;
-  chrome.runtime.getBackgroundPage(function(bg) {
-    bg.launchFileManager({defaultPath: path});
-  });
-};
-
-/**
- * Records an action chosen.
- * @param {string} action Action name.
- * @private
- */
-ActionChoice.prototype.recordAction_ = function(action) {
-  metrics.recordEnum('PhotoImport.Action', action,
-      ['import-photos-to-drive',
-       'view-files',
-       'view-files-auto',
-       'watch-single-video',
-       'error',
-       'close']);
-};
-
-/**
- * Called when the page is unloaded.
- */
-ActionChoice.prototype.onUnload = function() {
-  this.volumeManager_.dispose();
-};
-
-function unload() {
-  if (ActionChoice.instance)
-    ActionChoice.instance.onUnload();
-}
diff --git a/chrome/browser/resources/file_manager/js/action_choice_scripts.js b/chrome/browser/resources/file_manager/js/action_choice_scripts.js
deleted file mode 100644
index eb4c112..0000000
--- a/chrome/browser/resources/file_manager/js/action_choice_scripts.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-//<include src="../../image_loader/image_loader_client.js"/>
-
-//<include src="../../../../../ui/webui/resources/js/load_time_data.js"/>
-//<include src="../../../../../ui/webui/resources/js/util.js"/>
-//<include src="../../../../../ui/webui/resources/js/i18n_template_no_process.js"/>
-
-//<include src="../../../../../ui/webui/resources/js/cr.js"/>
-//<include src="../../../../../ui/webui/resources/js/event_tracker.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/event_target.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_item.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list.js"/>
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-//<include src="async_util.js"/>
-//<include src="util.js"/>
-//<include src="file_type.js"/>
-//<include src="path_util.js"/>
-//<include src="volume_manager_wrapper.js"/>
-//<include src="metadata/metadata_cache.js"/>
-//<include src="metrics.js"/>
-//<include src="image_editor/image_util.js"/>
-//<include src="media/media_util.js"/>
-//<include src="action_choice_util.js"/>
-
-//<include src="action_choice.js"/>
-
-// Exports
-window.ImageUtil = ImageUtil;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/background.js b/chrome/browser/resources/file_manager/js/background.js
deleted file mode 100644
index 379b2fd..0000000
--- a/chrome/browser/resources/file_manager/js/background.js
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Number of runtime errors catched in the background page.
- * @type {number}
- */
-var JSErrorCount = 0;
-
-/**
- * Map of all currently open app window. The key is an app id.
- * @type {Object.<string, AppWindow>}
- */
-var appWindows = {};
-
-/**
- * Synchronous queue for asynchronous calls.
- * @type {AsyncUtil.Queue}
- */
-var queue = new AsyncUtil.Queue();
-
-/**
- * @return {Array.<DOMWindow>} Array of content windows for all currently open
- *   app windows.
- */
-function getContentWindows() {
-  var views = [];
-  for (var key in appWindows) {
-    if (appWindows.hasOwnProperty(key))
-      views.push(appWindows[key].contentWindow);
-  }
-  return views;
-}
-
-/**
- * Type of a Files.app's instance launch.
- * @enum {number}
- */
-var LaunchType = {
-  ALWAYS_CREATE: 0,
-  FOCUS_ANY_OR_CREATE: 1,
-  FOCUS_SAME_OR_CREATE: 2
-};
-
-/**
- * Wrapper for an app window.
- *
- * Expects the following from the app scripts:
- * 1. The page load handler should initialize the app using |window.appState|
- *    and call |util.platform.saveAppState|.
- * 2. Every time the app state changes the app should update |window.appState|
- *    and call |util.platform.saveAppState| .
- * 3. The app may have |unload| function to persist the app state that does not
- *    fit into |window.appState|.
- *
- * @param {string} url App window content url.
- * @param {string} id App window id.
- * @param {Object|function()} options Options object or a function to create it.
- * @constructor
- */
-function AppWindowWrapper(url, id, options) {
-  this.url_ = url;
-  this.id_ = id;
-  this.options_ = options;
-  this.window_ = null;
-  this.appState_ = null;
-  this.openingOrOpened_ = false;
-  this.queue = new AsyncUtil.Queue();
-  Object.seal(this);
-}
-
-/**
- * Shift distance to avoid overlapping windows.
- * @type {number}
- * @const
- */
-AppWindowWrapper.SHIFT_DISTANCE = 40;
-
-/**
- * Gets similar windows, it means with the same initial url.
- * @return {Array.<AppWindow>} List of similar windows.
- * @private
- */
-AppWindowWrapper.prototype.getSimilarWindows_ = function() {
-  var result = [];
-  for (var appID in appWindows) {
-    if (appWindows[appID].contentWindow.appInitialURL == this.url_)
-      result.push(appWindows[appID]);
-  }
-  return result;
-};
-
-/**
- * Opens the window.
- *
- * @param {Object} appState App state.
- * @param {function()=} opt_callback Completion callback.
- */
-AppWindowWrapper.prototype.launch = function(appState, opt_callback) {
-  // Check if the window is opened or not.
-  if (this.openingOrOpened_) {
-    console.error('The window is already opened.');
-    if (opt_callback)
-      opt_callback();
-    return;
-  }
-  this.openingOrOpened_ = true;
-
-  // Save application state.
-  this.appState_ = appState;
-
-  // Window options.
-  var options = this.options_;
-  if (typeof options == 'function')
-    options = options();
-  options.id = this.url_;  // This is to make Chrome reuse window geometries.
-  options.singleton = false;
-
-  // Get similar windows, it means with the same initial url, eg. different
-  // main windows of Files.app.
-  var similarWindows = this.getSimilarWindows_();
-
-  // Restore maximized windows, to avoid hiding them to tray, which can be
-  // confusing for users.
-  this.queue.run(function(nextStep) {
-    for (var index = 0; index < similarWindows.length; index++) {
-      if (similarWindows[index].isMaximized()) {
-        var createWindowAndRemoveListener = function() {
-          similarWindows[index].onRestored.removeListener(
-              createWindowAndRemoveListener);
-          nextStep();
-        };
-        similarWindows[index].onRestored.addListener(
-            createWindowAndRemoveListener);
-        similarWindows[index].restore();
-        return;
-      }
-    }
-    // If no maximized windows, then create the window immediately.
-    nextStep();
-  });
-
-  // Closure creating the window, once all preprocessing tasks are finished.
-  this.queue.run(function(nextStep) {
-    chrome.app.window.create(this.url_, options, function(appWindow) {
-      this.window_ = appWindow;
-      nextStep();
-    }.bind(this));
-  }.bind(this));
-
-  // After creating.
-  this.queue.run(function(nextStep) {
-    var appWindow = this.window_;
-    if (similarWindows.length) {
-      // If we have already another window of the same kind, then shift this
-      // window to avoid overlapping with the previous one.
-
-      var bounds = appWindow.getBounds();
-      appWindow.moveTo(bounds.left + AppWindowWrapper.SHIFT_DISTANCE,
-                       bounds.top + AppWindowWrapper.SHIFT_DISTANCE);
-    }
-
-    appWindows[this.id_] = appWindow;
-    var contentWindow = appWindow.contentWindow;
-    contentWindow.appID = this.id_;
-    contentWindow.appState = this.appState_;
-    contentWindow.appInitialURL = this.url_;
-    if (window.IN_TEST)
-      contentWindow.IN_TEST = true;
-
-    appWindow.onClosed.addListener(function() {
-      if (contentWindow.unload)
-        contentWindow.unload();
-      if (contentWindow.saveOnExit) {
-        contentWindow.saveOnExit.forEach(function(entry) {
-          util.AppCache.update(entry.key, entry.value);
-        });
-      }
-      delete appWindows[this.id_];
-      chrome.storage.local.remove(this.id_);  // Forget the persisted state.
-      this.window_ = null;
-      this.openingOrOpened_ = false;
-      maybeCloseBackgroundPage();
-    }.bind(this));
-
-    if (opt_callback)
-      opt_callback();
-
-    nextStep();
-  }.bind(this));
-};
-
-/**
- * Wrapper for a singleton app window.
- *
- * In addition to the AppWindowWrapper requirements the app scripts should
- * have |reload| method that re-initializes the app based on a changed
- * |window.appState|.
- *
- * @param {string} url App window content url.
- * @param {Object|function()} options Options object or a function to return it.
- * @constructor
- */
-function SingletonAppWindowWrapper(url, options) {
-  AppWindowWrapper.call(this, url, url, options);
-}
-
-/**
- * Inherits from AppWindowWrapper.
- */
-SingletonAppWindowWrapper.prototype = {__proto__: AppWindowWrapper.prototype};
-
-/**
- * Open the window.
- *
- * Activates an existing window or creates a new one.
- *
- * @param {Object} appState App state.
- * @param {function()=} opt_callback Completion callback.
- */
-SingletonAppWindowWrapper.prototype.launch = function(appState, opt_callback) {
-  // If the window is not opened yet, just call the parent method.
-  if (!this.openingOrOpened_) {
-    AppWindowWrapper.prototype.launch.call(this, appState, opt_callback);
-    return;
-  }
-
-  // If the window is already opened, reload the window.
-  // The queue is used to wait until the window is opened.
-  this.queue.run(function(nextStep) {
-    this.window_.contentWindow.appState = appState;
-    this.window_.contentWindow.reload();
-    this.window_.focus();
-    if (opt_callback)
-      opt_callback();
-    nextStep();
-  }.bind(this));
-};
-
-/**
- * Reopen a window if its state is saved in the local storage.
- */
-SingletonAppWindowWrapper.prototype.reopen = function() {
-  chrome.storage.local.get(this.id_, function(items) {
-    var value = items[this.id_];
-    if (!value)
-      return;  // No app state persisted.
-
-    try {
-      var appState = JSON.parse(value);
-    } catch (e) {
-      console.error('Corrupt launch data for ' + this.id_, value);
-      return;
-    }
-    this.launch(appState);
-  }.bind(this));
-};
-
-/**
- * Prefix for the file manager window ID.
- */
-var FILES_ID_PREFIX = 'files#';
-
-/**
- * Regexp matching a file manager window ID.
- */
-var FILES_ID_PATTERN = new RegExp('^' + FILES_ID_PREFIX + '(\\d*)$');
-
-/**
- * Value of the next file manager window ID.
- */
-var nextFileManagerWindowID = 0;
-
-/**
- * @return {Object} File manager window create options.
- */
-function createFileManagerOptions() {
-  return {
-    defaultLeft: Math.round(window.screen.availWidth * 0.1),
-    defaultTop: Math.round(window.screen.availHeight * 0.1),
-    defaultWidth: Math.round(window.screen.availWidth * 0.8),
-    defaultHeight: Math.round(window.screen.availHeight * 0.8),
-    minWidth: 320,
-    minHeight: 240,
-    frame: 'none',
-    hidden: true,
-    transparentBackground: true
-  };
-}
-
-/**
- * @param {Object=} opt_appState App state.
- * @param {number=} opt_id Window id.
- * @param {LaunchType=} opt_type Launch type. Default: ALWAYS_CREATE.
- * @param {function(string)=} opt_callback Completion callback with the App ID.
- */
-function launchFileManager(opt_appState, opt_id, opt_type, opt_callback) {
-  var type = opt_type || LaunchType.ALWAYS_CREATE;
-
-  // Wait until all windows are created.
-  queue.run(function(onTaskCompleted) {
-    // Check if there is already a window with the same path. If so, then
-    // reuse it instead of opening a new one.
-    if (type == LaunchType.FOCUS_SAME_OR_CREATE ||
-        type == LaunchType.FOCUS_ANY_OR_CREATE) {
-      if (opt_appState && opt_appState.defaultPath) {
-        for (var key in appWindows) {
-          var contentWindow = appWindows[key].contentWindow;
-          if (contentWindow.appState &&
-              opt_appState.defaultPath == contentWindow.appState.defaultPath) {
-            appWindows[key].focus();
-            if (opt_callback)
-              opt_callback(key);
-            onTaskCompleted();
-            return;
-          }
-        }
-      }
-    }
-
-    // Focus any window if none is focused. Try restored first.
-    if (type == LaunchType.FOCUS_ANY_OR_CREATE) {
-      // If there is already a focused window, then finish.
-      for (var key in appWindows) {
-        // The isFocused() method should always be available, but in case
-        // Files.app's failed on some error, wrap it with try catch.
-        try {
-          if (appWindows[key].contentWindow.isFocused()) {
-            if (opt_callback)
-              opt_callback(key);
-            onTaskCompleted();
-            return;
-          }
-        } catch (e) {
-          console.error(e.message);
-        }
-      }
-      // Try to focus the first non-minimized window.
-      for (var key in appWindows) {
-        if (!appWindows[key].isMinimized()) {
-          appWindows[key].focus();
-          if (opt_callback)
-            opt_callback(key);
-          onTaskCompleted();
-          return;
-        }
-      }
-      // Restore and focus any window.
-      for (var key in appWindows) {
-        appWindows[key].focus();
-        if (opt_callback)
-          opt_callback(key);
-        onTaskCompleted();
-        return;
-      }
-    }
-
-    // Create a new instance in case of ALWAYS_CREATE type, or as a fallback
-    // for other types.
-
-    var id = opt_id || nextFileManagerWindowID;
-    nextFileManagerWindowID = Math.max(nextFileManagerWindowID, id + 1);
-    var appId = FILES_ID_PREFIX + id;
-
-    var appWindow = new AppWindowWrapper(
-        'main.html',
-        appId,
-        createFileManagerOptions);
-    appWindow.launch(opt_appState || {}, function() {
-      if (opt_callback)
-        opt_callback(appId);
-      onTaskCompleted();
-    });
-  });
-}
-
-/**
- * Relaunch file manager windows based on the persisted state.
- */
-function reopenFileManagers() {
-  chrome.storage.local.get(function(items) {
-    for (var key in items) {
-      if (items.hasOwnProperty(key)) {
-        var match = key.match(FILES_ID_PATTERN);
-        if (match) {
-          var id = Number(match[1]);
-          try {
-            var appState = JSON.parse(items[key]);
-            launchFileManager(appState, id);
-          } catch (e) {
-            console.error('Corrupt launch data for ' + id);
-          }
-        }
-      }
-    }
-  });
-}
-
-/**
- * Executes a file browser task.
- *
- * @param {string} action Task id.
- * @param {Object} details Details object.
- */
-function onExecute(action, details) {
-  var urls = details.entries.map(function(e) { return e.toURL(); });
-
-  switch (action) {
-    case 'play':
-      launchAudioPlayer({items: urls, position: 0});
-      break;
-
-    case 'watch':
-      launchVideoPlayer(urls[0]);
-      break;
-
-    default:
-      var launchEnable = null;
-      var queue = new AsyncUtil.Queue();
-      queue.run(function(nextStep) {
-        // If it is not auto-open (triggered by mounting external devices), we
-        // always launch Files.app.
-        if (action != 'auto-open') {
-          launchEnable = true;
-          nextStep();
-          return;
-        }
-        // If the disable-default-apps flag is on, Files.app is not opened
-        // automatically on device mount because it obstculs the manual test.
-        chrome.commandLinePrivate.hasSwitch('disable-default-apps',
-                                            function(flag) {
-          launchEnable = !flag;
-          nextStep();
-        });
-      });
-      queue.run(function(nextStep) {
-        if (!launchEnable) {
-          nextStep();
-          return;
-        }
-
-        // Every other action opens a Files app window.
-        var appState = {
-          params: {
-            action: action
-          },
-          defaultPath: details.entries[0].fullPath
-        };
-        // For mounted devices just focus any Files.app window. The mounted
-        // volume will appear on the navigation list.
-        var type = action == 'auto-open' ? LaunchType.FOCUS_ANY_OR_CREATE :
-            LaunchType.FOCUS_SAME_OR_CREATE;
-        launchFileManager(appState, /* App ID */ undefined, type, nextStep);
-      });
-      break;
-  }
-}
-
-/**
- * @return {Object} Audio player window create options.
- */
-function createAudioPlayerOptions() {
-  var WIDTH = 280;
-  var HEIGHT = 35 + 58;
-  return {
-    type: 'panel',
-    hidden: true,
-    minHeight: HEIGHT,
-    minWidth: WIDTH,
-    height: HEIGHT,
-    width: WIDTH
-  };
-}
-
-var audioPlayer = new SingletonAppWindowWrapper('mediaplayer.html',
-                                                createAudioPlayerOptions);
-
-/**
- * Launch the audio player.
- * @param {Object} playlist Playlist.
- */
-function launchAudioPlayer(playlist) {
-  audioPlayer.launch(playlist);
-}
-
-var videoPlayer = new SingletonAppWindowWrapper('video_player.html',
-                                                {hidden: true});
-
-/**
- * Launch the video player.
- * @param {string} url Video url.
- */
-function launchVideoPlayer(url) {
-  videoPlayer.launch({url: url});
-}
-
-/**
- * Launches the app.
- */
-function onLaunched() {
-  if (nextFileManagerWindowID == 0) {
-    // The app just launched. Remove window state records that are not needed
-    // any more.
-    chrome.storage.local.get(function(items) {
-      for (var key in items) {
-        if (items.hasOwnProperty(key)) {
-          if (key.match(FILES_ID_PATTERN))
-            chrome.storage.local.remove(key);
-        }
-      }
-    });
-  }
-
-  launchFileManager();
-}
-
-/**
- * Restarted the app, restore windows.
- */
-function onRestarted() {
-  reopenFileManagers();
-  audioPlayer.reopen();
-  videoPlayer.reopen();
-}
-
-/**
- * Handles clicks on a custom item on the launcher context menu.
- * @param {OnClickData} info Event details.
- */
-function onContextMenuClicked(info) {
-  if (info.menuItemId == 'new-window') {
-    // Find the focused window (if any) and use it's current path for the
-    // new window. If not found, then launch with the default path.
-    for (var key in appWindows) {
-      try {
-        if (appWindows[key].contentWindow.isFocused()) {
-          var appState = {
-            defaultPath: appWindows[key].contentWindow.appState.defaultPath
-          };
-          launchFileManager(appState);
-          return;
-        }
-      } catch (ignore) {
-        // The isFocused method may not be defined during initialization.
-        // Therefore, wrapped with a try-catch block.
-      }
-    }
-
-    // Launch with the default path.
-    launchFileManager();
-  }
-}
-
-/**
- * Closes the background page, if it is not needed.
- */
-function maybeCloseBackgroundPage() {
-  if (Object.keys(appWindows).length === 0 &&
-      !FileOperationManager.getInstance().hasQueuedTasks())
-    close();
-}
-
-/**
- * Initializes the context menu. Recreates if already exists.
- * @param {Object} strings Hash array of strings.
- */
-function initContextMenu(strings) {
-  try {
-    chrome.contextMenus.remove('new-window');
-  } catch (ignore) {
-    // There is no way to detect if the context menu is already added, therefore
-    // try to recreate it every time.
-  }
-  chrome.contextMenus.create({
-    id: 'new-window',
-    contexts: ['launcher'],
-    title: strings['NEW_WINDOW_BUTTON_LABEL']
-  });
-}
-
-/**
- * Initializes the background page of Files.app.
- */
-function initApp() {
-  // Initialize handlers.
-  chrome.fileBrowserHandler.onExecute.addListener(onExecute);
-  chrome.app.runtime.onLaunched.addListener(onLaunched);
-  chrome.app.runtime.onRestarted.addListener(onRestarted);
-  chrome.contextMenus.onClicked.addListener(onContextMenuClicked);
-
-  // Fetch strings and initialize the context menu.
-  queue.run(function(callback) {
-    chrome.fileBrowserPrivate.getStrings(function(strings) {
-      loadTimeData.data = strings;
-      initContextMenu(strings);
-      chrome.storage.local.set({strings: strings}, callback);
-    });
-  });
-
-  // Count runtime JavaScript errors.
-  window.onerror = function() {
-    JSErrorCount++;
-  };
-}
-
-// Initialize Files.app.
-initApp();
-
-/**
- * Progress center of the background page.
- * @type {ProgressCenter}
- */
-window.progressCenter = new ProgressCenter();
-
-/**
- * Event handler for progress center.
- * @type {ProgressCenter}
- */
-var progressCenterHandler = new ProgressCenterHandler(
-    FileOperationManager.getInstance(),
-    window.progressCenter);
diff --git a/chrome/browser/resources/file_manager/js/butter_bar.js b/chrome/browser/resources/file_manager/js/butter_bar.js
deleted file mode 100644
index 40d0b33..0000000
--- a/chrome/browser/resources/file_manager/js/butter_bar.js
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Butter bar is shown on top of the file list and is used to show the copy
- * progress and other messages.
- * @param {HTMLElement} dialogDom FileManager top-level div.
- * @param {FileOperationManagerWrapper} fileOperationManager The operation
- *     manager.
- * @constructor
- */
-function ButterBar(dialogDom, fileOperationManager) {
-  this.dialogDom_ = dialogDom;
-  this.butter_ = this.dialogDom_.querySelector('#butter-bar');
-  this.document_ = this.butter_.ownerDocument;
-  this.fileOperationManager_ = fileOperationManager;
-  this.hideTimeout_ = null;
-  this.showTimeout_ = null;
-  this.lastShowTime_ = 0;
-  this.deleteTaskId_ = null;
-  this.currentMode_ = null;
-  this.totalDeleted_ = 0;
-  this.lastProgressValue_ = 0;
-  this.alert_ = new ErrorDialog(this.dialogDom_);
-
-  this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
-  this.fileOperationManager_.addEventListener(
-      'copy-progress', this.onCopyProgressBound_);
-  this.onDeleteBound_ = this.onDelete_.bind(this);
-  this.fileOperationManager_.addEventListener('delete', this.onDeleteBound_);
-}
-
-/**
- * The default amount of milliseconds time, before a butter bar will hide after
- * the last update.
- * @type {number}
- * @private
- * @const
- */
-ButterBar.HIDE_DELAY_TIME_MS_ = 2000;
-
-/**
- * Name of action which should be displayed as an 'x' button instead of
- * link with text.
- * @const
- */
-ButterBar.ACTION_X = '--action--x--';
-
-/**
- * Butter bar mode.
- * @const
- */
-ButterBar.Mode = {
-  COPY: 1,
-  DELETE: 2
-};
-
-/**
- * Disposes the instance. No methods should be called after this method's
- * invocation.
- */
-ButterBar.prototype.dispose = function() {
-  // Unregister listeners from FileOperationManager.
-  this.fileOperationManager_.removeEventListener(
-      'copy-progress', this.onCopyProgressBound_);
-  this.fileOperationManager_.removeEventListener('delete', this.onDeleteBound_);
-};
-
-/**
- * @return {boolean} True if visible.
- * @private
- */
-ButterBar.prototype.isVisible_ = function() {
-  return this.butter_.classList.contains('visible');
-};
-
-/**
- * Show butter bar.
- * @param {ButterBar.Mode} mode Butter bar mode.
- * @param {string} message The message to be shown.
- * @param {Object=} opt_options Options: 'actions', 'progress', 'timeout'. If
- *     'timeout' is not specified, HIDE_DELAY_TIME_MS_ is used. If 'timeout' is
- *     false, the butter bar will not be hidden.
- */
-ButterBar.prototype.show = function(mode, message, opt_options) {
-  this.currentMode_ = mode;
-
-  this.clearShowTimeout_();
-  this.clearHideTimeout_();
-
-  var actions = this.butter_.querySelector('.actions');
-  actions.textContent = '';
-  if (opt_options && 'actions' in opt_options) {
-    for (var label in opt_options.actions) {
-      var link = this.document_.createElement('a');
-      link.addEventListener('click', function(callback) {
-        callback();
-        return false;
-      }.bind(null, opt_options.actions[label]));
-      if (label == ButterBar.ACTION_X) {
-        link.className = 'x';
-      } else {
-        link.textContent = label;
-      }
-      actions.appendChild(link);
-    }
-    actions.hidden = false;
-  } else {
-    actions.hidden = true;
-  }
-
-  this.butter_.querySelector('.progress-bar').hidden =
-    !(opt_options && 'progress' in opt_options);
-
-  this.butter_.classList.remove('error');
-  this.butter_.classList.remove('visible');  // Will be shown in update_
-  this.update_(message, opt_options);
-};
-
-/**
- * Show an error message in a popup dialog.
- * @param {string} message Message.
- * @private
- */
-ButterBar.prototype.showError_ = function(message) {
-  // Wait in case there are previous dialogs being closed.
-  setTimeout(function() {
-    this.alert_.showHtml('',  // Title.
-                         message);
-    this.hide_();
-  }.bind(this), cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION);
-};
-
-/**
- * Set message and/or progress.
- * @param {string} message Message.
- * @param {Object=} opt_options Same as in show().
- * @private
- */
-ButterBar.prototype.update_ = function(message, opt_options) {
-  if (!opt_options)
-    opt_options = {};
-
-  this.clearHideTimeout_();
-
-  var butterMessage = this.butter_.querySelector('.butter-message');
-   butterMessage.textContent = message;
-  if (message && !this.isVisible_()) {
-    // The butter bar is made visible on the first non-empty message.
-    this.butter_.classList.add('visible');
-  }
-  if (opt_options && 'progress' in opt_options) {
-    butterMessage.classList.add('single-line');
-    var progressTrack = this.butter_.querySelector('.progress-track');
-    // Smoothen the progress only when it goes forward. Especially do not
-    // do the transition effect if resetting to 0.
-    if (opt_options.progress > this.lastProgressValue_)
-      progressTrack.classList.add('smoothed');
-    else
-      progressTrack.classList.remove('smoothed');
-    progressTrack.style.width = (opt_options.progress * 100) + '%';
-    this.lastProgressValue_ = opt_options.progress;
-  } else {
-    butterMessage.classList.remove('single-line');
-  }
-
-  if (opt_options.timeout !== false)
-    this.hide_(opt_options.timeout);
-};
-
-/**
- * Hide butter bar. There might be the delay before hiding so that butter bar
- * would be shown for no less than the minimal time.
- * @param {number=} opt_timeout Delay time in milliseconds before hidding. If it
- *     is zero, butter bar is hidden immediatelly. If it is not specified,
- *     HIDE_DELAY_TIME_MS_ is used.
- * @private
- */
-ButterBar.prototype.hide_ = function(opt_timeout) {
-  this.clearHideTimeout_();
-
-  if (!this.isVisible_())
-    return;
-
-  var delay = typeof opt_timeout != 'undefined' ?
-    opt_timeout : ButterBar.HIDE_DELAY_TIME_MS_;
-  if (delay <= 0) {
-    this.currentMode_ = null;
-    this.butter_.classList.remove('visible');
-    this.butter_.querySelector('.progress-bar').hidden = true;
-  } else {
-    // Reschedule hide to comply with the minimal display time.
-    this.hideTimeout_ = setTimeout(function() {
-      this.hideTimeout_ = null;
-      this.hide_(0);
-    }.bind(this), delay);
-  }
-};
-
-/**
- * Clear the show timeout if it is set.
- * @private
- */
-ButterBar.prototype.clearShowTimeout_ = function() {
-  if (this.showTimeout_) {
-    clearTimeout(this.showTimeout_);
-    this.showTimeout_ = null;
-  }
-};
-
-/**
- * Clear the hide timeout if it is set.
- * @private
- */
-ButterBar.prototype.clearHideTimeout_ = function() {
-  if (this.hideTimeout_) {
-    clearTimeout(this.hideTimeout_);
-    this.hideTimeout_ = null;
-  }
-};
-
-/**
- * @return {string} The type of operation.
- * @private
- */
-ButterBar.prototype.transferType_ = function() {
-  var progress = this.progress_;
-  if (progress && progress.operationType)
-    return progress.operationType;
-
-  return 'TRANSFER';
-};
-
-/**
- * Set up butter bar for showing copy progress.
- *
- * @param {Object} progress Copy status object created by
- *     FileOperationManager.getStatus().
- * @private
- */
-ButterBar.prototype.showProgress_ = function(progress) {
-  this.progress_ = progress;
-  var options = {
-    progress: progress.processedBytes / progress.totalBytes,
-    actions: {},
-    timeout: false
-  };
-
-  var pendingItems = progress.numRemainingItems;
-  var type = this.transferType_();
-  var progressString = (pendingItems === 1) ?
-          strf(type + '_FILE_NAME', progress.processingEntry.name) :
-          strf(type + '_ITEMS_REMAINING', pendingItems);
-
-  if (this.currentMode_ == ButterBar.Mode.COPY) {
-    this.update_(progressString, options);
-  } else {
-    options.actions[ButterBar.ACTION_X] =
-        this.fileOperationManager_.requestCancel.bind(
-            this.fileOperationManager_);
-    this.show(ButterBar.Mode.COPY, progressString, options);
-  }
-};
-
-/**
- * 'copy-progress' event handler. Show progress or an appropriate message.
- * @param {Event} event A 'copy-progress' event from FileOperationManager.
- * @private
- */
-ButterBar.prototype.onCopyProgress_ = function(event) {
-  // Delete operation has higher priority.
-  if (this.currentMode_ == ButterBar.Mode.DELETE)
-    return;
-
-  if (event.reason != 'PROGRESS')
-    this.clearShowTimeout_();
-
-  switch (event.reason) {
-    case 'BEGIN':
-      this.showTimeout_ = setTimeout(function() {
-        this.showTimeout_ = null;
-        this.showProgress_(event.status);
-      }.bind(this), 500);
-      break;
-
-    case 'PROGRESS':
-      this.showProgress_(event.status);
-      break;
-
-    case 'SUCCESS':
-      this.hide_();
-      break;
-
-    case 'CANCELLED':
-      this.show(ButterBar.Mode.DELETE,
-                str(this.transferType_() + '_CANCELLED'));
-      break;
-
-    case 'ERROR':
-      this.progress_ = event.status;
-      var error = event.error;
-      if (error.code === util.FileOperationErrorType.TARGET_EXISTS) {
-        var name = error.data.name;
-        if (error.data.isDirectory)
-          name += '/';
-        this.showError_(
-            strf(this.transferType_() + '_TARGET_EXISTS_ERROR', name));
-      } else if (error.code === util.FileOperationErrorType.FILESYSTEM_ERROR) {
-        if (error.data.toDrive &&
-            error.data.code === FileError.QUOTA_EXCEEDED_ERR) {
-          // The alert will be shown in FileManager.onCopyProgress_.
-          this.hide_();
-        } else {
-          this.showError_(strf(this.transferType_() + '_FILESYSTEM_ERROR',
-                               util.getFileErrorString(error.data.code)));
-          }
-      } else {
-        this.showError_(
-            strf(this.transferType_() + '_UNEXPECTED_ERROR', error));
-      }
-      break;
-
-    default:
-      console.warn('Unknown "copy-progress" event reason: ' + event.code);
-  }
-};
-
-/**
- * 'delete' event handler. Shows information about deleting files.
- * @param {Event} event A 'delete' event from FileOperationManager.
- * @private
- */
-ButterBar.prototype.onDelete_ = function(event) {
-  switch (event.reason) {
-    case 'BEGIN':
-      if (this.currentMode_ != ButterBar.Mode.DELETE)
-        this.totalDeleted_ = 0;
-
-    case 'PROGRESS':
-      this.totalDeleted_ += event.urls.length;
-      var title = strf('DELETED_MESSAGE_PLURAL', this.totalDeleted_);
-      if (this.totalDeleted_ == 1) {
-        var fullPath = util.extractFilePath(event.urls[0]);
-        var fileName = PathUtil.split(fullPath).pop();
-        title = strf('DELETED_MESSAGE', fileName);
-      }
-
-      if (this.currentMode_ == ButterBar.Mode.DELETE)
-        this.update_(title);
-      else
-        this.show(ButterBar.Mode.DELETE, title);
-      break;
-
-    case 'SUCCESS':
-      break;
-
-    case 'ERROR':
-      this.showError_(str('DELETE_ERROR'));
-      break;
-
-    default:
-      console.warn('Unknown "delete" event reason: ' + event.reason);
-  }
-};
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
deleted file mode 100644
index 95c76b4..0000000
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ /dev/null
@@ -1,3683 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * FileManager constructor.
- *
- * FileManager objects encapsulate the functionality of the file selector
- * dialogs, as well as the full screen file manager application (though the
- * latter is not yet implemented).
- *
- * @constructor
- */
-function FileManager() {
-  this.initializeQueue_ = new AsyncUtil.Group();
-
-  /**
-   * Current list type.
-   * @type {ListType}
-   * @private
-   */
-  this.listType_ = null;
-
-  /**
-   * Whether to suppress the focus moving or not.
-   * This is used to filter out focusing by mouse.
-   * @type {boolean}
-   * @private
-   */
-  this.suppressFocus_ = false;
-
-  /**
-   * SelectionHandler.
-   * @type {SelectionHandler}
-   * @private
-   */
-  this.selectionHandler_ = null;
-}
-
-/**
- * Maximum delay in milliseconds for updating thumbnails in the bottom panel
- * to mitigate flickering. If images load faster then the delay they replace
- * old images smoothly. On the other hand we don't want to keep old images
- * too long.
- *
- * @type {number}
- * @const
- */
-FileManager.THUMBNAIL_SHOW_DELAY = 100;
-
-FileManager.prototype = {
-  __proto__: cr.EventTarget.prototype,
-  get directoryModel() {
-    return this.directoryModel_;
-  },
-  get navigationList() {
-    return this.navigationList_;
-  },
-  get document() {
-    return this.document_;
-  },
-  get fileTransferController() {
-    return this.fileTransferController_;
-  },
-  get backgroundPage() {
-    return this.backgroundPage_;
-  }
-};
-
-/**
- * Unload the file manager.
- * Used by background.js (when running in the packaged mode).
- */
-function unload() {
-  fileManager.onBeforeUnload_();
-  fileManager.onUnload_();
-}
-
-/**
- * List of dialog types.
- *
- * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except
- * FULL_PAGE which is specific to this code.
- *
- * @enum {string}
- */
-var DialogType = {
-  SELECT_FOLDER: 'folder',
-  SELECT_UPLOAD_FOLDER: 'upload-folder',
-  SELECT_SAVEAS_FILE: 'saveas-file',
-  SELECT_OPEN_FILE: 'open-file',
-  SELECT_OPEN_MULTI_FILE: 'open-multi-file',
-  FULL_PAGE: 'full-page'
-};
-
-/**
- * @param {string} type Dialog type.
- * @return {boolean} Whether the type is modal.
- */
-DialogType.isModal = function(type) {
-  return type == DialogType.SELECT_FOLDER ||
-      type == DialogType.SELECT_UPLOAD_FOLDER ||
-      type == DialogType.SELECT_SAVEAS_FILE ||
-      type == DialogType.SELECT_OPEN_FILE ||
-      type == DialogType.SELECT_OPEN_MULTI_FILE;
-};
-
-/**
- * @param {string} type Dialog type.
- * @return {boolean} Whether the type is open dialog.
- */
-DialogType.isOpenDialog = function(type) {
-  return type == DialogType.SELECT_OPEN_FILE ||
-         type == DialogType.SELECT_OPEN_MULTI_FILE;
-};
-
-/**
- * Bottom margin of the list and tree for transparent preview panel.
- * @const
- */
-var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
-
-// Anonymous "namespace".
-(function() {
-
-  // Private variables and helper functions.
-
-  /**
-   * Number of milliseconds in a day.
-   */
-  var MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
-
-  /**
-   * Some UI elements react on a single click and standard double click handling
-   * leads to confusing results. We ignore a second click if it comes soon
-   * after the first.
-   */
-  var DOUBLE_CLICK_TIMEOUT = 200;
-
-  /**
-   * Update the element to display the information about remaining space for
-   * the storage.
-   * @param {!Element} spaceInnerBar Block element for a percentage bar
-   *                                 representing the remaining space.
-   * @param {!Element} spaceInfoLabel Inline element to contain the message.
-   * @param {!Element} spaceOuterBar Block element around the percentage bar.
-   */
-   var updateSpaceInfo = function(
-      sizeStatsResult, spaceInnerBar, spaceInfoLabel, spaceOuterBar) {
-    spaceInnerBar.removeAttribute('pending');
-    if (sizeStatsResult) {
-      var sizeStr = util.bytesToString(sizeStatsResult.remainingSize);
-      spaceInfoLabel.textContent = strf('SPACE_AVAILABLE', sizeStr);
-
-      var usedSpace =
-          sizeStatsResult.totalSize - sizeStatsResult.remainingSize;
-      spaceInnerBar.style.width =
-          (100 * usedSpace / sizeStatsResult.totalSize) + '%';
-
-      spaceOuterBar.hidden = false;
-    } else {
-      spaceOuterBar.hidden = true;
-      spaceInfoLabel.textContent = str('FAILED_SPACE_INFO');
-    }
-  };
-
-  // Public statics.
-
-  FileManager.ListType = {
-    DETAIL: 'detail',
-    THUMBNAIL: 'thumb'
-  };
-
-  FileManager.prototype.initPreferences_ = function(callback) {
-    var group = new AsyncUtil.Group();
-
-    // DRIVE preferences should be initialized before creating DirectoryModel
-    // to rebuild the roots list.
-    group.add(this.getPreferences_.bind(this));
-
-    // Get startup preferences.
-    this.viewOptions_ = {};
-    group.add(function(done) {
-      util.platform.getPreference(this.startupPrefName_, function(value) {
-        // Load the global default options.
-        try {
-          this.viewOptions_ = JSON.parse(value);
-        } catch (ignore) {}
-        // Override with window-specific options.
-        if (window.appState && window.appState.viewOptions) {
-          for (var key in window.appState.viewOptions) {
-            if (window.appState.viewOptions.hasOwnProperty(key))
-              this.viewOptions_[key] = window.appState.viewOptions[key];
-          }
-        }
-        done();
-      }.bind(this));
-    }.bind(this));
-
-    // Get the command line option.
-    group.add(function(done) {
-      chrome.commandLinePrivate.hasSwitch(
-          'file-manager-show-checkboxes', function(flag) {
-        this.showCheckboxes_ = flag;
-        done();
-      }.bind(this));
-    }.bind(this));
-
-    // TODO(yoshiki): Remove the flag when the feature is launched.
-    this.enableExperimentalWebstoreIntegration_ = false;
-    group.add(function(done) {
-      chrome.commandLinePrivate.hasSwitch(
-          'file-manager-enable-webstore-integration', function(flag) {
-        this.enableExperimentalWebstoreIntegration_ = flag;
-        done();
-      }.bind(this));
-    }.bind(this));
-
-    group.run(callback);
-  };
-
-  /**
-   * One time initialization for the file system and related things.
-   *
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initFileSystemUI_ = function(callback) {
-    this.table_.startBatchUpdates();
-    this.grid_.startBatchUpdates();
-
-    this.initFileList_();
-    this.setupCurrentDirectory_();
-
-    // PyAuto tests monitor this state by polling this variable
-    this.__defineGetter__('workerInitialized_', function() {
-       return this.metadataCache_.isInitialized();
-    }.bind(this));
-
-    this.initDateTimeFormatters_();
-
-    var self = this;
-
-    // Get the 'allowRedeemOffers' preference before launching
-    // FileListBannerController.
-    this.getPreferences_(function(pref) {
-      /** @type {boolean} */
-      var showOffers = pref['allowRedeemOffers'];
-      self.bannersController_ = new FileListBannerController(
-          self.directoryModel_, self.volumeManager_, self.document_,
-          showOffers);
-      self.bannersController_.addEventListener('relayout',
-                                               self.onResize_.bind(self));
-    });
-
-    var dm = this.directoryModel_;
-    dm.addEventListener('directory-changed',
-                        this.onDirectoryChanged_.bind(this));
-    dm.addEventListener('begin-update-files', function() {
-      self.currentList_.startBatchUpdates();
-    });
-    dm.addEventListener('end-update-files', function() {
-      self.restoreItemBeingRenamed_();
-      self.currentList_.endBatchUpdates();
-    });
-    dm.addEventListener('scan-started', this.onScanStarted_.bind(this));
-    dm.addEventListener('scan-completed', this.onScanCompleted_.bind(this));
-    dm.addEventListener('scan-failed', this.onScanCancelled_.bind(this));
-    dm.addEventListener('scan-cancelled', this.onScanCancelled_.bind(this));
-    dm.addEventListener('scan-updated', this.onScanUpdated_.bind(this));
-    dm.addEventListener('rescan-completed',
-                        this.onRescanCompleted_.bind(this));
-
-    var sm = this.directoryModel_.getFileListSelection();
-    sm.addEventListener('change', function() {
-      if (sm.selectedIndexes.length != 1)
-        return;
-      var view = (this.listType_ == FileManager.ListType.DETAIL) ?
-          this.table_.list : this.grid_;
-      var selectedItem = view.getListItemByIndex(sm.selectedIndex);
-      if (!selectedItem)
-        return;
-      this.ensureItemNotBehindPreviewPanel_(selectedItem, view);
-    }.bind(this));
-
-    this.directoryTree_.addEventListener('change', function() {
-      var selectedSubTree = this.directoryTree_.selectedItem;
-      if (!selectedSubTree)
-        return;
-      var selectedItem = selectedSubTree.rowElement;
-      this.ensureItemNotBehindPreviewPanel_(selectedItem, this.directoryTree_);
-    }.bind(this));
-
-    var stateChangeHandler =
-        this.onPreferencesChanged_.bind(this);
-    chrome.fileBrowserPrivate.onPreferencesChanged.addListener(
-        stateChangeHandler);
-    stateChangeHandler();
-
-    var driveConnectionChangedHandler =
-        this.onDriveConnectionChanged_.bind(this);
-    this.volumeManager_.addEventListener('drive-connection-changed',
-        driveConnectionChangedHandler);
-    driveConnectionChangedHandler();
-
-    // Set the initial focus.
-    this.refocus();
-    // Set it as a fallback when there is no focus.
-    this.document_.addEventListener('focusout', function(e) {
-      setTimeout(function() {
-        // When there is no focus, the active element is the <body>.
-        if (this.document_.activeElement == this.document_.body)
-          this.refocus();
-      }.bind(this), 0);
-    }.bind(this));
-
-    this.initDataTransferOperations_();
-
-    this.initContextMenus_();
-    this.initCommands_();
-
-    this.updateFileTypeFilter_();
-
-    this.selectionHandler_.onFileSelectionChanged();
-
-    this.table_.endBatchUpdates();
-    this.grid_.endBatchUpdates();
-
-    callback();
-  };
-
-  /**
-   * If |item| in |parentView| is behind the preview panel, scrolls up the
-   * parent view and make the item visible. This should be called when:
-   *  - the selected item is changed.
-   *  - the visibility of the the preview panel is changed.
-   *
-   * @param {HTMLElement} item Item to be visible in the parent.
-   * @param {HTMLElement} parentView View contains |selectedItem|.
-   * @private
-   */
-  FileManager.prototype.ensureItemNotBehindPreviewPanel_ =
-      function(item, parentView) {
-    var itemRect = item.getBoundingClientRect();
-    if (!itemRect)
-      return;
-
-    var listRect = parentView.getBoundingClientRect();
-    if (!listRect)
-      return;
-
-    var previewPanel = this.dialogDom_.querySelector('.preview-panel');
-    var previewPanelRect = previewPanel.getBoundingClientRect();
-    var panelHeight = previewPanelRect ? previewPanelRect.height : 0;
-
-    var itemBottom = itemRect.bottom;
-    var listBottom = listRect.bottom - panelHeight;
-
-    if (itemBottom > listBottom) {
-      var scrollOffset = itemBottom - listBottom;
-      parentView.scrollTop += scrollOffset;
-    }
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.initDateTimeFormatters_ = function() {
-    var use12hourClock = !this.preferences_['use24hourClock'];
-    this.table_.setDateTimeFormat(use12hourClock);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.initDataTransferOperations_ = function() {
-    this.fileOperationManager_ = FileOperationManagerWrapper.getInstance(
-        this.backgroundPage_);
-
-    this.butterBar_ = new ButterBar(
-        this.dialogDom_, this.fileOperationManager_);
-
-    // CopyManager and ButterBar are required for 'Delete' operation in
-    // Open and Save dialogs. But drag-n-drop and copy-paste are not needed.
-    if (this.dialogType != DialogType.FULL_PAGE) return;
-
-    // TODO(hidehiko): Extract FileOperationManager related code from
-    // FileManager to simplify it.
-    this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
-    this.fileOperationManager_.addEventListener(
-        'copy-progress', this.onCopyProgressBound_);
-
-    this.onEntryChangedBound_ = this.onEntryChanged_.bind(this);
-    this.fileOperationManager_.addEventListener(
-        'entry-changed', this.onEntryChangedBound_);
-
-    var controller = this.fileTransferController_ =
-        new FileTransferController(this.document_,
-                                   this.fileOperationManager_,
-                                   this.metadataCache_,
-                                   this.directoryModel_);
-    controller.attachDragSource(this.table_.list);
-    controller.attachFileListDropTarget(this.table_.list);
-    controller.attachDragSource(this.grid_);
-    controller.attachFileListDropTarget(this.grid_);
-    controller.attachTreeDropTarget(this.directoryTree_);
-    controller.attachNavigationListDropTarget(this.navigationList_, true);
-    controller.attachCopyPasteHandlers();
-    controller.addEventListener('selection-copied',
-        this.blinkSelection.bind(this));
-    controller.addEventListener('selection-cut',
-        this.blinkSelection.bind(this));
-  };
-
-  /**
-   * One-time initialization of context menus.
-   * @private
-   */
-  FileManager.prototype.initContextMenus_ = function() {
-    this.fileContextMenu_ = this.dialogDom_.querySelector('#file-context-menu');
-    cr.ui.Menu.decorate(this.fileContextMenu_);
-
-    cr.ui.contextMenuHandler.setContextMenu(this.grid_, this.fileContextMenu_);
-    cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'),
-        this.fileContextMenu_);
-    cr.ui.contextMenuHandler.setContextMenu(
-        this.document_.querySelector('.drive-welcome.page'),
-        this.fileContextMenu_);
-
-    this.rootsContextMenu_ =
-        this.dialogDom_.querySelector('#roots-context-menu');
-    cr.ui.Menu.decorate(this.rootsContextMenu_);
-    this.navigationList_.setContextMenu(this.rootsContextMenu_);
-
-    this.directoryTreeContextMenu_ =
-        this.dialogDom_.querySelector('#directory-tree-context-menu');
-    cr.ui.Menu.decorate(this.directoryTreeContextMenu_);
-    this.directoryTree_.contextMenuForSubitems = this.directoryTreeContextMenu_;
-
-    this.textContextMenu_ =
-        this.dialogDom_.querySelector('#text-context-menu');
-    cr.ui.Menu.decorate(this.textContextMenu_);
-
-    this.gearButton_ = this.dialogDom_.querySelector('#gear-button');
-    this.gearButton_.addEventListener('menushow',
-        this.refreshRemainingSpace_.bind(this,
-                                         false /* Without loading caption. */));
-    this.dialogDom_.querySelector('#gear-menu').menuItemSelector =
-        'menuitem, hr';
-    cr.ui.decorate(this.gearButton_, cr.ui.MenuButton);
-
-    if (this.dialogType == DialogType.FULL_PAGE) {
-      // This is to prevent the buttons from stealing focus on mouse down.
-      var preventFocus = function(event) {
-        event.preventDefault();
-      };
-
-      var maximizeButton = this.dialogDom_.querySelector('#maximize-button');
-      maximizeButton.addEventListener('click', this.onMaximize.bind(this));
-      maximizeButton.addEventListener('mousedown', preventFocus);
-
-      var closeButton = this.dialogDom_.querySelector('#close-button');
-      closeButton.addEventListener('click', this.onClose.bind(this));
-      closeButton.addEventListener('mousedown', preventFocus);
-    }
-
-    this.syncButton.checkable = true;
-    this.hostedButton.checkable = true;
-    this.detailViewButton_.checkable = true;
-    this.thumbnailViewButton_.checkable = true;
-
-    if (util.platform.runningInBrowser()) {
-      // Suppresses the default context menu.
-      this.dialogDom_.addEventListener('contextmenu', function(e) {
-        e.preventDefault();
-        e.stopPropagation();
-      });
-    }
-  };
-
-  FileManager.prototype.onMaximize = function() {
-    var appWindow = chrome.app.window.current();
-    if (appWindow.isMaximized())
-      appWindow.restore();
-    else
-      appWindow.maximize();
-  };
-
-  FileManager.prototype.onClose = function() {
-    window.close();
-  };
-
-  /**
-   * One-time initialization of commands.
-   * @private
-   */
-  FileManager.prototype.initCommands_ = function() {
-    this.commandHandler = new CommandHandler(this);
-
-    // TODO(hirono): Move the following block to the UI part.
-    var commandButtons = this.dialogDom_.querySelectorAll('button[command]');
-    for (var j = 0; j < commandButtons.length; j++)
-      CommandButton.decorate(commandButtons[j]);
-
-    var inputs = this.dialogDom_.querySelectorAll(
-        'input[type=text], input[type=search], textarea');
-    for (var i = 0; i < inputs.length; i++) {
-      cr.ui.contextMenuHandler.setContextMenu(inputs[i], this.textContextMenu_);
-      this.registerInputCommands_(inputs[i]);
-    }
-
-    cr.ui.contextMenuHandler.setContextMenu(this.renameInput_,
-                                            this.textContextMenu_);
-    this.registerInputCommands_(this.renameInput_);
-    this.document_.addEventListener('command',
-                                    this.setNoHover_.bind(this, true));
-  };
-
-  /**
-   * Registers cut, copy, paste and delete commands on input element.
-   *
-   * @param {Node} node Text input element to register on.
-   * @private
-   */
-  FileManager.prototype.registerInputCommands_ = function(node) {
-    CommandUtil.forceDefaultHandler(node, 'cut');
-    CommandUtil.forceDefaultHandler(node, 'copy');
-    CommandUtil.forceDefaultHandler(node, 'paste');
-    CommandUtil.forceDefaultHandler(node, 'delete');
-    node.addEventListener('keydown', function(e) {
-      if (util.getKeyModifiers(e) + e.keyCode == '191') {
-        // If this key event is propagated, this is handled search command,
-        // which calls 'preventDefault' method.
-        e.stopPropagation();
-      }
-    });
-  };
-
-  /**
-   * Entry point of the initialization.
-   * This method is called from main.js.
-   */
-  FileManager.prototype.initializeCore = function() {
-    this.initializeQueue_.add(this.initGeneral_.bind(this), [], 'initGeneral');
-    this.initializeQueue_.add(this.initStrings_.bind(this), [], 'initStrings');
-    this.initializeQueue_.add(this.initBackgroundPage_.bind(this),
-                              [], 'initBackgroundPage');
-    this.initializeQueue_.add(this.initPreferences_.bind(this),
-                              ['initGeneral'], 'initPreferences');
-    this.initializeQueue_.add(this.initVolumeManager_.bind(this),
-                              ['initGeneral', 'initBackgroundPage'],
-                              'initVolumeManager');
-
-    this.initializeQueue_.run();
-  };
-
-  FileManager.prototype.initializeUI = function(dialogDom, callback) {
-    this.dialogDom_ = dialogDom;
-    this.document_ = this.dialogDom_.ownerDocument;
-
-    this.initializeQueue_.add(
-        this.initEssentialUI_.bind(this),
-        ['initGeneral', 'initStrings'],
-        'initEssentialUI');
-    this.initializeQueue_.add(this.initAdditionalUI_.bind(this),
-        ['initEssentialUI', 'initBackgroundPage'], 'initAdditionalUI');
-    this.initializeQueue_.add(
-        this.initFileSystemUI_.bind(this),
-        ['initAdditionalUI', 'initPreferences'], 'initFileSystemUI');
-
-    // Run again just in case if all pending closures have completed and the
-    // queue has stopped and monitor the completion.
-    this.initializeQueue_.run(callback);
-  };
-
-  /**
-   * Initializes general purpose basic things, which are used by other
-   * initializing methods.
-   *
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initGeneral_ = function(callback) {
-    // Initialize the application state.
-    if (window.appState) {
-      this.params_ = window.appState.params || {};
-      this.defaultPath = window.appState.defaultPath;
-    } else {
-      this.params_ = location.search ?
-                     JSON.parse(decodeURIComponent(location.search.substr(1))) :
-                     {};
-      this.defaultPath = this.params_.defaultPath;
-    }
-
-    // Initialize the member variables that depend this.params_.
-    this.dialogType = this.params_.type || DialogType.FULL_PAGE;
-    this.startupPrefName_ = 'file-manager-' + this.dialogType;
-    this.fileTypes_ = this.params_.typeList || [];
-
-    callback();
-  };
-
-  /**
-   * One time initialization of strings (mostly i18n).
-   *
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initStrings_ = function(callback) {
-    // Fetch the strings via the private api if running in the browser window.
-    // Otherwise, read cached strings from the local storage.
-    if (util.platform.runningInBrowser()) {
-      chrome.fileBrowserPrivate.getStrings(function(strings) {
-        loadTimeData.data = strings;
-        callback();
-      });
-    } else {
-      chrome.storage.local.get('strings', function(items) {
-        loadTimeData.data = items['strings'];
-        callback();
-      });
-    }
-  };
-
-  /**
-   * Initialize the background page.
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initBackgroundPage_ = function(callback) {
-    chrome.runtime.getBackgroundPage(function(backgroundPage) {
-      this.backgroundPage_ = backgroundPage;
-      callback();
-    }.bind(this));
-  };
-
-  /**
-   * Initializes the VolumeManager instance.
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initVolumeManager_ = function(callback) {
-    // Auto resolving to local path does not work for folders (e.g., dialog for
-    // loading unpacked extensions).
-    var noLocalPathResolution =
-      this.params_.type == DialogType.SELECT_FOLDER ||
-      this.params_.type == DialogType.SELECT_UPLOAD_FOLDER;
-
-    // If this condition is false, VolumeManagerWrapper hides all drive
-    // related event and data, even if Drive is enabled on preference.
-    // In other words, even if Drive is disabled on preference but Files.app
-    // should show Drive when it is re-enabled, then the value should be set to
-    // true.
-    // Note that the Drive enabling preference change is listened by
-    // DriveIntegrationService, so here we don't need to take care about it.
-    var driveEnabled =
-        !noLocalPathResolution || !this.params_.shouldReturnLocalPath;
-    this.volumeManager_ = new VolumeManagerWrapper(
-        driveEnabled, this.backgroundPage_);
-    callback();
-  };
-
-  /**
-   * One time initialization of the Files.app's essential UI elements. These
-   * elements will be shown to the user. Only visible elements should be
-   * initialized here. Any heavy operation should be avoided. Files.app's
-   * window is shown at the end of this routine.
-   *
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initEssentialUI_ = function(callback) {
-    // Optional list of file types.
-    metrics.recordEnum('Create', this.dialogType,
-        [DialogType.SELECT_FOLDER,
-         DialogType.SELECT_UPLOAD_FOLDER,
-         DialogType.SELECT_SAVEAS_FILE,
-         DialogType.SELECT_OPEN_FILE,
-         DialogType.SELECT_OPEN_MULTI_FILE,
-         DialogType.FULL_PAGE]);
-
-    // Create the metadata cache.
-    this.metadataCache_ = MetadataCache.createFull();
-
-    // Create the root view of FileManager.
-    this.ui_ = new FileManagerUI(this.dialogDom_, this.dialogType);
-    this.fileTypeSelector_ = this.ui_.fileTypeSelector;
-    this.okButton_ = this.ui_.okButton;
-    this.cancelButton_ = this.ui_.cancelButton;
-
-    // Show the window as soon as the UI pre-initialization is done.
-    if (this.dialogType == DialogType.FULL_PAGE &&
-        !util.platform.runningInBrowser()) {
-      chrome.app.window.current().show();
-      setTimeout(callback, 100);  // Wait until the animation is finished.
-    } else {
-      callback();
-    }
-  };
-
-  /**
-   * One-time initialization of dialogs.
-   * @private
-   */
-  FileManager.prototype.initDialogs_ = function() {
-    // Initialize the dialog.
-    this.ui_.initDialogs();
-    FileManagerDialogBase.setFileManager(this);
-
-    // Obtains the dialog instances from FileManagerUI.
-    // TODO(hirono): Remove the properties from the FileManager class.
-    this.error = this.ui_.errorDialog;
-    this.alert = this.ui_.alertDialog;
-    this.confirm = this.ui_.confirmDialog;
-    this.prompt = this.ui_.promptDialog;
-    this.shareDialog_ = this.ui_.shareDialog;
-    this.defaultTaskPicker = this.ui_.defaultTaskPicker;
-    this.suggestAppsDialog = this.ui_.suggestAppsDialog;
-  };
-
-  /**
-   * One-time initialization of various DOM nodes. Loads the additional DOM
-   * elements visible to the user. Initialize here elements, which are expensive
-   * or hidden in the beginning.
-   *
-   * @param {function()} callback Completion callback.
-   * @private
-   */
-  FileManager.prototype.initAdditionalUI_ = function(callback) {
-    this.initDialogs_();
-    this.ui_.initAdditionalUI();
-
-    this.dialogDom_.addEventListener('drop', function(e) {
-      // Prevent opening an URL by dropping it onto the page.
-      e.preventDefault();
-    });
-
-    this.dialogDom_.addEventListener('click',
-                                     this.onExternalLinkClick_.bind(this));
-    // Cache nodes we'll be manipulating.
-    var dom = this.dialogDom_;
-
-    this.filenameInput_ = dom.querySelector('#filename-input-box input');
-    this.taskItems_ = dom.querySelector('#tasks');
-
-    this.table_ = dom.querySelector('.detail-table');
-    this.grid_ = dom.querySelector('.thumbnail-grid');
-    this.spinner_ = dom.querySelector('#spinner-with-text');
-    this.showSpinner_(true);
-
-    // Check the option to hide the selecting checkboxes.
-    this.table_.showCheckboxes = this.showCheckboxes_;
-
-    var fullPage = this.dialogType == DialogType.FULL_PAGE;
-    FileTable.decorate(this.table_, this.metadataCache_, fullPage);
-    FileGrid.decorate(this.grid_, this.metadataCache_);
-
-    this.previewPanel_ = new PreviewPanel(
-        dom.querySelector('.preview-panel'),
-        DialogType.isOpenDialog(this.dialogType) ?
-            PreviewPanel.VisibilityType.ALWAYS_VISIBLE :
-            PreviewPanel.VisibilityType.AUTO,
-        this.getCurrentDirectory(),
-        this.metadataCache_);
-    this.previewPanel_.addEventListener(
-        PreviewPanel.Event.VISIBILITY_CHANGE,
-        this.onPreviewPanelVisibilityChange_.bind(this));
-    this.previewPanel_.initialize();
-
-    this.previewPanel_.breadcrumbs.addEventListener(
-         'pathclick', this.onBreadcrumbClick_.bind(this));
-
-    // Initialize progress center panel.
-    this.progressCenterPanel_ = new ProgressCenterPanel(
-        dom.querySelector('#progress-center'),
-        this.backgroundPage_.progressCenter.requestCancel.bind(
-            this.backgroundPage_.progressCenter));
-    var initialItems = this.backgroundPage_.progressCenter.applicationItems;
-    for (var i = 0; i < initialItems.length; i++) {
-      this.progressCenterPanel_.updateItem(
-          initialItems[i],
-          this.backgroundPage_.progressCenter.getSummarizedItem());
-    }
-    this.backgroundPage_.progressCenter.addEventListener(
-        ProgressCenterEvent.ITEM_UPDATED,
-        function(event) {
-          this.progressCenterPanel_.updateItem(
-              event.item,
-              this.backgroundPage_.progressCenter.getSummarizedItem());
-        }.bind(this));
-    this.backgroundPage_.progressCenter.addEventListener(
-        ProgressCenterEvent.RESET,
-        function(event) {
-          this.progressCenterPanel_.reset();
-        }.bind(this));
-
-    this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
-
-    // This capturing event is only used to distinguish focusing using
-    // keyboard from focusing using mouse.
-    this.document_.addEventListener('mousedown', function() {
-      this.suppressFocus_ = true;
-    }.bind(this), true);
-
-    this.renameInput_ = this.document_.createElement('input');
-    this.renameInput_.className = 'rename';
-
-    this.renameInput_.addEventListener(
-        'keydown', this.onRenameInputKeyDown_.bind(this));
-    this.renameInput_.addEventListener(
-        'blur', this.onRenameInputBlur_.bind(this));
-
-    this.filenameInput_.addEventListener(
-        'keydown', this.onFilenameInputKeyDown_.bind(this));
-    this.filenameInput_.addEventListener(
-        'focus', this.onFilenameInputFocus_.bind(this));
-
-    this.listContainer_ = this.dialogDom_.querySelector('#list-container');
-    this.listContainer_.addEventListener(
-        'keydown', this.onListKeyDown_.bind(this));
-    this.listContainer_.addEventListener(
-        'keypress', this.onListKeyPress_.bind(this));
-    this.listContainer_.addEventListener(
-        'mousemove', this.onListMouseMove_.bind(this));
-
-    this.okButton_.addEventListener('click', this.onOk_.bind(this));
-    this.onCancelBound_ = this.onCancel_.bind(this);
-    this.cancelButton_.addEventListener('click', this.onCancelBound_);
-
-    this.decorateSplitter(
-        this.dialogDom_.querySelector('#navigation-list-splitter'));
-    this.decorateSplitter(
-        this.dialogDom_.querySelector('#middlebar-splitter'));
-
-    this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container');
-
-    this.syncButton = this.dialogDom_.querySelector('#drive-sync-settings');
-    this.syncButton.addEventListener('click', this.onDrivePrefClick_.bind(
-        this, 'cellularDisabled', false /* not inverted */));
-
-    this.hostedButton = this.dialogDom_.querySelector('#drive-hosted-settings');
-    this.hostedButton.addEventListener('click', this.onDrivePrefClick_.bind(
-        this, 'hostedFilesDisabled', true /* inverted */));
-
-    this.detailViewButton_ =
-        this.dialogDom_.querySelector('#detail-view');
-    this.detailViewButton_.addEventListener('click',
-        this.onDetailViewButtonClick_.bind(this));
-
-    this.thumbnailViewButton_ =
-        this.dialogDom_.querySelector('#thumbnail-view');
-    this.thumbnailViewButton_.addEventListener('click',
-        this.onThumbnailViewButtonClick_.bind(this));
-
-    cr.ui.ComboButton.decorate(this.taskItems_);
-    this.taskItems_.showMenu = function(shouldSetFocus) {
-      // Prevent the empty menu from opening.
-      if (!this.menu.length)
-        return;
-      cr.ui.ComboButton.prototype.showMenu.call(this, shouldSetFocus);
-    };
-    this.taskItems_.addEventListener('select',
-        this.onTaskItemClicked_.bind(this));
-
-    this.dialogDom_.ownerDocument.defaultView.addEventListener(
-        'resize', this.onResize_.bind(this));
-
-    this.filePopup_ = null;
-
-    this.searchBoxWrapper_ = this.ui_.searchBox.element;
-    this.searchBox_ = this.ui_.searchBox.inputElement;
-    this.searchBox_.addEventListener(
-        'input', this.onSearchBoxUpdate_.bind(this));
-    this.ui_.searchBox.clearButton.addEventListener(
-        'click', this.onSearchClearButtonClick_.bind(this));
-
-    this.lastSearchQuery_ = '';
-
-    this.autocompleteList_ = this.ui_.searchBox.autocompleteList;
-    this.autocompleteList_.requestSuggestions =
-        this.requestAutocompleteSuggestions_.bind(this);
-
-    // Instead, open the suggested item when Enter key is pressed or
-    // mouse-clicked.
-    this.autocompleteList_.handleEnterKeydown = function(event) {
-      this.openAutocompleteSuggestion_();
-      this.lastAutocompleteQuery_ = '';
-      this.autocompleteList_.suggestions = [];
-    }.bind(this);
-    this.autocompleteList_.addEventListener('mousedown', function(event) {
-      this.openAutocompleteSuggestion_();
-      this.lastAutocompleteQuery_ = '';
-      this.autocompleteList_.suggestions = [];
-    }.bind(this));
-
-    this.defaultActionMenuItem_ =
-        this.dialogDom_.querySelector('#default-action');
-
-    this.openWithCommand_ =
-        this.dialogDom_.querySelector('#open-with');
-
-    this.driveBuyMoreStorageCommand_ =
-        this.dialogDom_.querySelector('#drive-buy-more-space');
-
-    this.defaultActionMenuItem_.addEventListener('click',
-        this.dispatchSelectionAction_.bind(this));
-
-    this.initFileTypeFilter_();
-
-    util.addIsFocusedMethod();
-
-    // Populate the static localized strings.
-    i18nTemplate.process(this.document_, loadTimeData);
-
-    // Arrange the file list.
-    this.table_.normalizeColumns();
-    this.table_.redraw();
-
-    callback();
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onBreadcrumbClick_ = function(event) {
-    this.directoryModel_.changeDirectory(event.path);
-  };
-
-  /**
-   * Constructs table and grid (heavy operation).
-   * @private
-   **/
-  FileManager.prototype.initFileList_ = function() {
-    // Always sharing the data model between the detail/thumb views confuses
-    // them.  Instead we maintain this bogus data model, and hook it up to the
-    // view that is not in use.
-    this.emptyDataModel_ = new cr.ui.ArrayDataModel([]);
-    this.emptySelectionModel_ = new cr.ui.ListSelectionModel();
-
-    var singleSelection =
-        this.dialogType == DialogType.SELECT_OPEN_FILE ||
-        this.dialogType == DialogType.SELECT_FOLDER ||
-        this.dialogType == DialogType.SELECT_UPLOAD_FOLDER ||
-        this.dialogType == DialogType.SELECT_SAVEAS_FILE;
-
-    var showSpecialSearchRoots =
-        this.dialogType == DialogType.SELECT_OPEN_FILE ||
-        this.dialogType == DialogType.SELECT_OPEN_MULTI_FILE ||
-        this.dialogType == DialogType.FULL_PAGE;
-
-    this.fileFilter_ = new FileFilter(
-        this.metadataCache_,
-        false  /* Don't show dot files by default. */);
-
-    this.fileWatcher_ = new FileWatcher(this.metadataCache_);
-    this.fileWatcher_.addEventListener(
-        'watcher-metadata-changed',
-        this.onWatcherMetadataChanged_.bind(this));
-
-    this.directoryModel_ = new DirectoryModel(
-        singleSelection,
-        this.fileFilter_,
-        this.fileWatcher_,
-        this.metadataCache_,
-        this.volumeManager_,
-        showSpecialSearchRoots);
-
-    this.folderShortcutsModel_ = new FolderShortcutsDataModel();
-
-    this.selectionHandler_ = new FileSelectionHandler(this);
-
-    var dataModel = this.directoryModel_.getFileList();
-
-    this.table_.setupCompareFunctions(dataModel);
-
-    dataModel.addEventListener('permuted',
-                               this.updateStartupPrefs_.bind(this));
-
-    this.directoryModel_.getFileListSelection().addEventListener('change',
-        this.selectionHandler_.onFileSelectionChanged.bind(
-            this.selectionHandler_));
-
-    this.initList_(this.grid_);
-    this.initList_(this.table_.list);
-
-    var fileListFocusBound = this.onFileListFocus_.bind(this);
-    var fileListBlurBound = this.onFileListBlur_.bind(this);
-
-    this.table_.list.addEventListener('focus', fileListFocusBound);
-    this.grid_.addEventListener('focus', fileListFocusBound);
-
-    this.table_.list.addEventListener('blur', fileListBlurBound);
-    this.grid_.addEventListener('blur', fileListBlurBound);
-
-    var dragStartBound = this.onDragStart_.bind(this);
-    this.table_.list.addEventListener('dragstart', dragStartBound);
-    this.grid_.addEventListener('dragstart', dragStartBound);
-
-    var dragEndBound = this.onDragEnd_.bind(this);
-    this.table_.list.addEventListener('dragend', dragEndBound);
-    this.grid_.addEventListener('dragend', dragEndBound);
-    // This event is published by DragSelector because drag end event is not
-    // published at the end of drag selection.
-    this.table_.list.addEventListener('dragselectionend', dragEndBound);
-    this.grid_.addEventListener('dragselectionend', dragEndBound);
-
-    // TODO(mtomasz, yoshiki): Create navigation list earlier, and here just
-    // attach the directory model.
-    this.initNavigationList_();
-
-    this.table_.addEventListener('column-resize-end',
-                                 this.updateStartupPrefs_.bind(this));
-
-    // Restore preferences.
-    this.directoryModel_.sortFileList(
-        this.viewOptions_.sortField || 'modificationTime',
-        this.viewOptions_.sortDirection || 'desc');
-    if (this.viewOptions_.columns) {
-      var cm = this.table_.columnModel;
-      for (var i = 0; i < cm.totalSize; i++) {
-        if (this.viewOptions_.columns[i] > 0)
-          cm.setWidth(i, this.viewOptions_.columns[i]);
-      }
-    }
-    this.setListType(this.viewOptions_.listType || FileManager.ListType.DETAIL);
-
-    this.textSearchState_ = {text: '', date: new Date()};
-    this.closeOnUnmount_ = (this.params_.action == 'auto-open');
-
-    if (this.closeOnUnmount_) {
-      this.volumeManager_.addEventListener('externally-unmounted',
-         this.onExternallyUnmounted_.bind(this));
-    }
-
-    // Update metadata to change 'Today' and 'Yesterday' dates.
-    var today = new Date();
-    today.setHours(0);
-    today.setMinutes(0);
-    today.setSeconds(0);
-    today.setMilliseconds(0);
-    setTimeout(this.dailyUpdateModificationTime_.bind(this),
-               today.getTime() + MILLISECONDS_IN_DAY - Date.now() + 1000);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.initNavigationList_ = function() {
-    this.directoryTree_ = this.dialogDom_.querySelector('#directory-tree');
-    DirectoryTree.decorate(this.directoryTree_, this.directoryModel_);
-
-    this.navigationList_ = this.dialogDom_.querySelector('#navigation-list');
-    NavigationList.decorate(this.navigationList_,
-                            this.volumeManager_,
-                            this.directoryModel_);
-    this.navigationList_.fileManager = this;
-    this.navigationList_.dataModel = new NavigationListModel(
-        this.volumeManager_, this.folderShortcutsModel_);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.updateMiddleBarVisibility_ = function() {
-    var entry = this.directoryModel_.getCurrentDirEntry();
-    if (!entry)
-      return;
-
-    var driveVolume = this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
-    var visible =
-        DirectoryTreeUtil.isEligiblePathForDirectoryTree(entry.fullPath) &&
-        driveVolume && !driveVolume.error;
-    this.dialogDom_.
-        querySelector('.dialog-middlebar-contents').hidden = !visible;
-    this.dialogDom_.querySelector('#middlebar-splitter').hidden = !visible;
-    this.onResize_();
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.updateStartupPrefs_ = function() {
-    var sortStatus = this.directoryModel_.getFileList().sortStatus;
-    var prefs = {
-      sortField: sortStatus.field,
-      sortDirection: sortStatus.direction,
-      columns: [],
-      listType: this.listType_
-    };
-    var cm = this.table_.columnModel;
-    for (var i = 0; i < cm.totalSize; i++) {
-      prefs.columns.push(cm.getWidth(i));
-    }
-    // Save the global default.
-    util.platform.setPreference(this.startupPrefName_, JSON.stringify(prefs));
-
-    // Save the window-specific preference.
-    if (window.appState) {
-      window.appState.viewOptions = prefs;
-      util.saveAppState();
-    }
-  };
-
-  FileManager.prototype.refocus = function() {
-    var targetElement;
-    if (this.dialogType == DialogType.SELECT_SAVEAS_FILE)
-      targetElement = this.filenameInput_;
-    else
-      targetElement = this.currentList_;
-
-    // Hack: if the tabIndex is disabled, we can assume a modal dialog is
-    // shown. Focus to a button on the dialog instead.
-    if (!targetElement.hasAttribute('tabIndex') || targetElement.tabIndex == -1)
-      targetElement = document.querySelector('button:not([tabIndex="-1"])');
-
-    if (targetElement)
-      targetElement.focus();
-  };
-
-  /**
-   * File list focus handler. Used to select the top most element on the list
-   * if nothing was selected.
-   *
-   * @private
-   */
-  FileManager.prototype.onFileListFocus_ = function() {
-    // Do not select default item if focused using mouse.
-    if (this.suppressFocus_)
-      return;
-
-    var selection = this.getSelection();
-    if (!selection || selection.totalCount != 0)
-      return;
-
-    this.directoryModel_.selectIndex(0);
-  };
-
-  /**
-   * File list blur handler.
-   *
-   * @private
-   */
-  FileManager.prototype.onFileListBlur_ = function() {
-    this.suppressFocus_ = false;
-  };
-
-  /**
-   * Index of selected item in the typeList of the dialog params.
-   *
-   * @return {number} 1-based index of selected type or 0 if no type selected.
-   * @private
-   */
-  FileManager.prototype.getSelectedFilterIndex_ = function() {
-    var index = Number(this.fileTypeSelector_.selectedIndex);
-    if (index < 0)  // Nothing selected.
-      return 0;
-    if (this.params_.includeAllFiles)  // Already 1-based.
-      return index;
-    return index + 1;  // Convert to 1-based;
-  };
-
-  FileManager.prototype.setListType = function(type) {
-    if (type && type == this.listType_)
-      return;
-
-    this.table_.list.startBatchUpdates();
-    this.grid_.startBatchUpdates();
-
-    // TODO(dzvorygin): style.display and dataModel setting order shouldn't
-    // cause any UI bugs. Currently, the only right way is first to set display
-    // style and only then set dataModel.
-
-    if (type == FileManager.ListType.DETAIL) {
-      this.table_.dataModel = this.directoryModel_.getFileList();
-      this.table_.selectionModel = this.directoryModel_.getFileListSelection();
-      this.table_.hidden = false;
-      this.grid_.hidden = true;
-      this.grid_.selectionModel = this.emptySelectionModel_;
-      this.grid_.dataModel = this.emptyDataModel_;
-      this.table_.hidden = false;
-      /** @type {cr.ui.List} */
-      this.currentList_ = this.table_.list;
-      this.detailViewButton_.setAttribute('checked', '');
-      this.thumbnailViewButton_.removeAttribute('checked');
-      this.detailViewButton_.setAttribute('disabled', '');
-      this.thumbnailViewButton_.removeAttribute('disabled');
-    } else if (type == FileManager.ListType.THUMBNAIL) {
-      this.grid_.dataModel = this.directoryModel_.getFileList();
-      this.grid_.selectionModel = this.directoryModel_.getFileListSelection();
-      this.grid_.hidden = false;
-      this.table_.hidden = true;
-      this.table_.selectionModel = this.emptySelectionModel_;
-      this.table_.dataModel = this.emptyDataModel_;
-      this.grid_.hidden = false;
-      /** @type {cr.ui.List} */
-      this.currentList_ = this.grid_;
-      this.thumbnailViewButton_.setAttribute('checked', '');
-      this.detailViewButton_.removeAttribute('checked');
-      this.thumbnailViewButton_.setAttribute('disabled', '');
-      this.detailViewButton_.removeAttribute('disabled');
-    } else {
-      throw new Error('Unknown list type: ' + type);
-    }
-
-    this.listType_ = type;
-    this.updateStartupPrefs_();
-    this.onResize_();
-
-    this.table_.list.endBatchUpdates();
-    this.grid_.endBatchUpdates();
-  };
-
-  /**
-   * Initialize the file list table or grid.
-   *
-   * @param {cr.ui.List} list The list.
-   * @private
-   */
-  FileManager.prototype.initList_ = function(list) {
-    // Overriding the default role 'list' to 'listbox' for better accessibility
-    // on ChromeOS.
-    list.setAttribute('role', 'listbox');
-    list.addEventListener('click', this.onDetailClick_.bind(this));
-    list.id = 'file-list';
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onCopyProgress_ = function(event) {
-    if (event.reason == 'ERROR' &&
-        event.error.code == util.FileOperationErrorType.FILESYSTEM_ERROR &&
-        event.error.data.toDrive &&
-        event.error.data.code == FileError.QUOTA_EXCEEDED_ERR) {
-      this.alert.showHtml(
-          strf('DRIVE_SERVER_OUT_OF_SPACE_HEADER'),
-          strf('DRIVE_SERVER_OUT_OF_SPACE_MESSAGE',
-              decodeURIComponent(
-                  event.error.data.sourceFileUrl.split('/').pop()),
-              urlConstants.GOOGLE_DRIVE_BUY_STORAGE));
-    }
-
-    // TODO(benchan): Currently, there is no FileWatcher emulation for
-    // drive::FileSystem, so we need to manually trigger the directory rescan
-    // after paste operations complete. Remove this once we emulate file
-    // watching functionalities in drive::FileSystem.
-    if (this.isOnDrive()) {
-      if (event.reason == 'SUCCESS' || event.reason == 'ERROR' ||
-          event.reason == 'CANCELLED') {
-        this.directoryModel_.rescanLater();
-      }
-    }
-  };
-
-  /**
-   * Handler of file manager operations. Called when an entry has been
-   * changed.
-   * This updates directory model to reflect operation result immediately (not
-   * waiting for directory update event). Also, preloads thumbnails for the
-   * images of new entries.
-   * See also FileOperationManager.EventRouter.
-   *
-   * @param {Event} event An event for the entry change.
-   * @private
-   */
-  FileManager.prototype.onEntryChanged_ = function(event) {
-    var kind = event.kind;
-    var entry = event.entry;
-    this.directoryModel_.onEntryChanged(kind, entry);
-    this.selectionHandler_.onFileSelectionChanged();
-
-    if (kind == util.EntryChangedKind.CREATE && FileType.isImage(entry)) {
-      // Preload a thumbnail if the new copied entry an image.
-      var metadata = entry.getMetadata(function(metadata) {
-        var url = entry.toURL();
-        var thumbnailLoader_ = new ThumbnailLoader(
-            url,
-            ThumbnailLoader.LoaderType.CANVAS,
-            metadata,
-            undefined,  // Media type.
-            FileType.isOnDrive(url) ?
-                ThumbnailLoader.UseEmbedded.USE_EMBEDDED :
-                ThumbnailLoader.UseEmbedded.NO_EMBEDDED,
-            10);  // Very low priority.
-        thumbnailLoader_.loadDetachedImage(function(success) {});
-      });
-    }
-  };
-
-  /**
-   * Fills the file type list or hides it.
-   * @private
-   */
-  FileManager.prototype.initFileTypeFilter_ = function() {
-    if (this.params_.includeAllFiles) {
-      var option = this.document_.createElement('option');
-      option.innerText = str('ALL_FILES_FILTER');
-      this.fileTypeSelector_.appendChild(option);
-      option.value = 0;
-    }
-
-    for (var i = 0; i < this.fileTypes_.length; i++) {
-      var fileType = this.fileTypes_[i];
-      var option = this.document_.createElement('option');
-      var description = fileType.description;
-      if (!description) {
-        // See if all the extensions in the group have the same description.
-        for (var j = 0; j != fileType.extensions.length; j++) {
-          var currentDescription =
-              FileType.getTypeString('.' + fileType.extensions[j]);
-          if (!description)  // Set the first time.
-            description = currentDescription;
-          else if (description != currentDescription) {
-            // No single description, fall through to the extension list.
-            description = null;
-            break;
-          }
-        }
-
-        if (!description)
-          // Convert ['jpg', 'png'] to '*.jpg, *.png'.
-          description = fileType.extensions.map(function(s) {
-           return '*.' + s;
-          }).join(', ');
-       }
-       option.innerText = description;
-
-       option.value = i + 1;
-
-       if (fileType.selected)
-         option.selected = true;
-
-       this.fileTypeSelector_.appendChild(option);
-    }
-
-    var options = this.fileTypeSelector_.querySelectorAll('option');
-    if (options.length < 2) {
-      // There is in fact no choice, hide the selector.
-      this.fileTypeSelector_.hidden = true;
-      return;
-    }
-
-    this.fileTypeSelector_.addEventListener('change',
-        this.updateFileTypeFilter_.bind(this));
-  };
-
-  /**
-   * Filters file according to the selected file type.
-   * @private
-   */
-  FileManager.prototype.updateFileTypeFilter_ = function() {
-    this.fileFilter_.removeFilter('fileType');
-    var selectedIndex = this.getSelectedFilterIndex_();
-    if (selectedIndex > 0) { // Specific filter selected.
-      var regexp = new RegExp('.*(' +
-          this.fileTypes_[selectedIndex - 1].extensions.join('|') + ')$', 'i');
-      var filter = function(entry) {
-        return entry.isDirectory || regexp.test(entry.name);
-      };
-      this.fileFilter_.addFilter('fileType', filter);
-    }
-  };
-
-  /**
-   * Resize details and thumb views to fit the new window size.
-   * @private
-   */
-  FileManager.prototype.onResize_ = function() {
-    if (this.listType_ == FileManager.ListType.THUMBNAIL)
-      this.grid_.relayout();
-    else
-      this.table_.relayout();
-
-    // May not be available during initialization.
-    if (this.directoryTree_)
-      this.directoryTree_.relayout();
-
-    // TODO(mtomasz, yoshiki): Initialize navigation list earlier, before
-    // file system is available.
-    if (this.navigationList_)
-      this.navigationList_.redraw();
-
-    this.ui_.searchBox.updateSizeRelatedStyle();
-
-    this.previewPanel_.breadcrumbs.truncate();
-  };
-
-  /**
-   * Handles local metadata changes in the currect directory.
-   * @param {Event} event Change event.
-   * @private
-   */
-  FileManager.prototype.onWatcherMetadataChanged_ = function(event) {
-    this.updateMetadataInUI_(event.metadataType, event.urls, event.properties);
-  };
-
-  /**
-   * Resize details and thumb views to fit the new window size.
-   * @private
-   */
-  FileManager.prototype.onPreviewPanelVisibilityChange_ = function() {
-    // This method may be called on initialization. Some object may not be
-    // initialized.
-
-    var panelHeight = this.previewPanel_.visible ?
-        this.previewPanel_.height : 0;
-    if (this.grid_)
-      this.grid_.setBottomMarginForPanel(panelHeight);
-    if (this.table_)
-      this.table_.setBottomMarginForPanel(panelHeight);
-    if (this.directoryTree_)
-      this.directoryTree_.setBottomMarginForPanel(panelHeight);
-
-    // Make sure that the selected item is not behind the preview panel.
-    if (this.directoryModel_) {
-      var sm = this.directoryModel_.getFileListSelection();
-      var view = (this.listType_ == FileManager.ListType.DETAIL) ?
-          this.table_.list : this.grid_;
-      var selectedItem = view.getListItemByIndex(sm.selectedIndex);
-      if (!selectedItem)
-        return;
-      this.ensureItemNotBehindPreviewPanel_(selectedItem, view);
-    }
-  };
-
-  /**
-   * Invoked when the drag is started on the list or the grid.
-   * @private
-   */
-  FileManager.prototype.onDragStart_ = function() {
-    // On open file dialog, the preview panel is always shown.
-    if (DialogType.isOpenDialog(this.dialogType))
-      return;
-    this.previewPanel_.visibilityType =
-        PreviewPanel.VisibilityType.ALWAYS_HIDDEN;
-  };
-
-  /**
-   * Invoked when the drag is ended on the list or the grid.
-   * @private
-   */
-  FileManager.prototype.onDragEnd_ = function() {
-    // On open file dialog, the preview panel is always shown.
-    if (DialogType.isOpenDialog(this.dialogType))
-      return;
-    this.previewPanel_.visibilityType = PreviewPanel.VisibilityType.AUTO;
-  };
-
-  /**
-   * Restores current directory and may be a selected item after page load (or
-   * reload) or popping a state (after click on back/forward). If location.hash
-   * is present it means that the user has navigated somewhere and that place
-   * will be restored. defaultPath primarily is used with save/open dialogs.
-   * Default path may also contain a file name. Freshly opened file manager
-   * window has neither.
-   *
-   * @private
-   */
-  FileManager.prototype.setupCurrentDirectory_ = function() {
-    var path = location.hash ?  // Location hash has the highest priority.
-        decodeURIComponent(location.hash.substr(1)) :
-        this.defaultPath;
-
-    if (!path) {
-      path = PathUtil.DEFAULT_DIRECTORY;
-    } else if (path.indexOf('/') == -1) {
-      // Path is a file name.
-      path = PathUtil.DEFAULT_DIRECTORY + '/' + path;
-    }
-
-    var tracker = this.directoryModel_.createDirectoryChangeTracker();
-    tracker.start();
-    this.volumeManager_.ensureInitialized(function() {
-      tracker.stop();
-      if (tracker.hasChanged)
-        return;
-
-      // If Drive is disabled but the path points to Drive's entry,
-      // fallback to DEFAULT_DIRECTORY.
-      if (PathUtil.isDriveBasedPath(path) &&
-          !this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE))
-        path = PathUtil.DEFAULT_DIRECTORY + '/' + PathUtil.basename(path);
-
-      this.finishSetupCurrentDirectory_(path);
-    }.bind(this));
-  };
-
-  /**
-   * @param {string} path Path to setup.
-   * @private
-   */
-  FileManager.prototype.finishSetupCurrentDirectory_ = function(path) {
-    this.directoryModel_.setupPath(path, function(baseName, leafName, exists) {
-      if (this.dialogType == DialogType.FULL_PAGE) {
-        // In the FULL_PAGE mode if the hash path points to a file we might have
-        // to invoke a task after selecting it.
-        // If the file path is in params_ we only want to select the file.
-        if (this.params_.action == 'select')
-          return;
-
-        var task = null;
-        if (!exists || leafName == '') {
-          // Non-existent file or a directory.
-          if (this.params_.gallery) {
-            // Reloading while the Gallery is open with empty or multiple
-            // selection. Open the Gallery when the directory is scanned.
-            task = function() {
-              new FileTasks(this, this.params_).openGallery([]);
-            }.bind(this);
-          }
-        } else {
-          // There are 3 ways we can get here:
-          // 1. Invoked from file_manager_util::ViewFile. This can only
-          //    happen for 'gallery' and 'mount-archive' actions.
-          // 2. Reloading a Gallery page. Must be an image or a video file.
-          // 3. A user manually entered a URL pointing to a file.
-          // We call the appropriate methods of FileTasks directly as we do
-          // not need any of the preparations that |execute| method does.
-          var mediaType = FileType.getMediaType(path);
-          if (mediaType == 'image' || mediaType == 'video') {
-            task = function() {
-              new FileTasks(this, this.params_).openGallery(
-                  [util.makeFilesystemUrl(path)]);
-            }.bind(this);
-          } else if (mediaType == 'archive') {
-            task = function() {
-              new FileTasks(this, this.params_).mountArchives(
-                  [util.makeFilesystemUrl(path)]);
-            }.bind(this);
-          }
-        }
-
-        // If there is a task to be run, run it after the scan is completed.
-        if (task) {
-          var listener = function() {
-            this.directoryModel_.removeEventListener(
-                'scan-completed', listener);
-            task();
-          }.bind(this);
-          this.directoryModel_.addEventListener('scan-completed', listener);
-        }
-        return;
-      }
-
-      if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
-        this.filenameInput_.value = leafName;
-        this.selectDefaultPathInFilenameInput_();
-        return;
-      }
-    }.bind(this));
-  };
-
-  /**
-   * Unmounts device.
-   * @param {string} path Path to a volume to unmount.
-   */
-  FileManager.prototype.unmountVolume = function(path) {
-    var onError = function(error) {
-      this.alert.showHtml('', str('UNMOUNT_FAILED'));
-    };
-    this.volumeManager_.unmount(path, function() {}, onError.bind(this));
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.refreshCurrentDirectoryMetadata_ = function() {
-    var entries = this.directoryModel_.getFileList().slice();
-    var directoryEntry = this.directoryModel_.getCurrentDirEntry();
-    if (!directoryEntry)
-      return;
-    // We don't pass callback here. When new metadata arrives, we have an
-    // observer registered to update the UI.
-
-    // TODO(dgozman): refresh content metadata only when modificationTime
-    // changed.
-    var isFakeEntry = typeof directoryEntry.toURL !== 'function';
-    var getEntries = (isFakeEntry ? [] : [directoryEntry]).concat(entries);
-    this.metadataCache_.clearRecursively(directoryEntry, '*');
-    this.metadataCache_.get(getEntries, 'filesystem', null);
-
-    if (this.isOnDrive())
-      this.metadataCache_.get(getEntries, 'drive', null);
-
-    var visibleItems = this.currentList_.items;
-    var visibleEntries = [];
-    for (var i = 0; i < visibleItems.length; i++) {
-      var index = this.currentList_.getIndexOfListItem(visibleItems[i]);
-      var entry = this.directoryModel_.getFileList().item(index);
-      // The following check is a workaround for the bug in list: sometimes item
-      // does not have listIndex, and therefore is not found in the list.
-      if (entry) visibleEntries.push(entry);
-    }
-    this.metadataCache_.get(visibleEntries, 'thumbnail', null);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.dailyUpdateModificationTime_ = function() {
-    var fileList = this.directoryModel_.getFileList();
-    var urls = [];
-    for (var i = 0; i < fileList.length; i++) {
-      urls.push(fileList.item(i).toURL());
-    }
-    this.metadataCache_.get(
-        fileList.slice(), 'filesystem',
-        this.updateMetadataInUI_.bind(this, 'filesystem', urls));
-
-    setTimeout(this.dailyUpdateModificationTime_.bind(this),
-               MILLISECONDS_IN_DAY);
-  };
-
-  /**
-   * @param {string} type Type of metadata changed.
-   * @param {Array.<string>} urls Array of urls.
-   * @param {Object.<string, Object>} props Map from entry URLs to metadata
-   *     props.
-   * @private
-   */
-  FileManager.prototype.updateMetadataInUI_ = function(
-      type, urls, properties) {
-    var propertyByUrl = urls.reduce(function(map, url, index) {
-      map[url] = properties[index];
-      return map;
-    }, {});
-
-    if (this.listType_ == FileManager.ListType.DETAIL)
-      this.table_.updateListItemsMetadata(type, propertyByUrl);
-    else
-      this.grid_.updateListItemsMetadata(type, propertyByUrl);
-    // TODO: update bottom panel thumbnails.
-  };
-
-  /**
-   * Restore the item which is being renamed while refreshing the file list. Do
-   * nothing if no item is being renamed or such an item disappeared.
-   *
-   * While refreshing file list it gets repopulated with new file entries.
-   * There is not a big difference whether DOM items stay the same or not.
-   * Except for the item that the user is renaming.
-   *
-   * @private
-   */
-  FileManager.prototype.restoreItemBeingRenamed_ = function() {
-    if (!this.isRenamingInProgress())
-      return;
-
-    var dm = this.directoryModel_;
-    var leadIndex = dm.getFileListSelection().leadIndex;
-    if (leadIndex < 0)
-      return;
-
-    var leadEntry = dm.getFileList().item(leadIndex);
-    if (this.renameInput_.currentEntry.fullPath != leadEntry.fullPath)
-      return;
-
-    var leadListItem = this.findListItemForNode_(this.renameInput_);
-    if (this.currentList_ == this.table_.list) {
-      this.table_.updateFileMetadata(leadListItem, leadEntry);
-    }
-    this.currentList_.restoreLeadItem(leadListItem);
-  };
-
-  /**
-   * @return {boolean} True if the current directory content is from Google
-   *     Drive.
-   */
-  FileManager.prototype.isOnDrive = function() {
-    var rootType = this.directoryModel_.getCurrentRootType();
-    return rootType === RootType.DRIVE ||
-           rootType === RootType.DRIVE_SHARED_WITH_ME ||
-           rootType === RootType.DRIVE_RECENT ||
-           rootType === RootType.DRIVE_OFFLINE;
-  };
-
-  /**
-   * 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.
-   *
-   * @param {Event} event Click event.
-   * @private
-   */
-  FileManager.prototype.onExternalLinkClick_ = function(event) {
-    if (event.target.tagName != 'A' || !event.target.href)
-      return;
-
-    if (this.dialogType != DialogType.FULL_PAGE)
-      this.onCancel_();
-  };
-
-  /**
-   * Task combobox handler.
-   *
-   * @param {Object} event Event containing task which was clicked.
-   * @private
-   */
-  FileManager.prototype.onTaskItemClicked_ = function(event) {
-    var selection = this.getSelection();
-    if (!selection.tasks) return;
-
-    if (event.item.task) {
-      // Task field doesn't exist on change-default dropdown item.
-      selection.tasks.execute(event.item.task.taskId);
-    } else {
-      var extensions = [];
-
-      for (var i = 0; i < selection.urls.length; i++) {
-        var match = /\.(\w+)$/g.exec(selection.urls[i]);
-        if (match) {
-          var ext = match[1].toUpperCase();
-          if (extensions.indexOf(ext) == -1) {
-            extensions.push(ext);
-          }
-        }
-      }
-
-      var format = '';
-
-      if (extensions.length == 1) {
-        format = extensions[0];
-      }
-
-      // Change default was clicked. We should open "change default" dialog.
-      selection.tasks.showTaskPicker(this.defaultTaskPicker,
-          loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
-          strf('CHANGE_DEFAULT_CAPTION', format),
-          this.onDefaultTaskDone_.bind(this));
-    }
-  };
-
-
-  /**
-   * Sets the given task as default, when this task is applicable.
-   *
-   * @param {Object} task Task to set as default.
-   * @private
-   */
-  FileManager.prototype.onDefaultTaskDone_ = function(task) {
-    // TODO(dgozman): move this method closer to tasks.
-    var selection = this.getSelection();
-    chrome.fileBrowserPrivate.setDefaultTask(task.taskId,
-      selection.urls, selection.mimeTypes);
-    selection.tasks = new FileTasks(this);
-    selection.tasks.init(selection.urls, selection.mimeTypes);
-    selection.tasks.display(this.taskItems_);
-    this.refreshCurrentDirectoryMetadata_();
-    this.selectionHandler_.onFileSelectionChanged();
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onPreferencesChanged_ = function() {
-    var self = this;
-    this.getPreferences_(function(prefs) {
-      self.initDateTimeFormatters_();
-      self.refreshCurrentDirectoryMetadata_();
-
-      if (prefs.cellularDisabled)
-        self.syncButton.setAttribute('checked', '');
-      else
-        self.syncButton.removeAttribute('checked');
-
-      if (self.hostedButton.hasAttribute('checked') !=
-          prefs.hostedFilesDisabled && self.isOnDrive()) {
-        self.directoryModel_.rescan();
-      }
-
-      if (!prefs.hostedFilesDisabled)
-        self.hostedButton.setAttribute('checked', '');
-      else
-        self.hostedButton.removeAttribute('checked');
-    },
-    true /* refresh */);
-  };
-
-  FileManager.prototype.onDriveConnectionChanged_ = function() {
-    var connection = this.volumeManager_.getDriveConnectionState();
-    if (this.commandHandler)
-      this.commandHandler.updateAvailability();
-    if (this.dialogContainer_)
-      this.dialogContainer_.setAttribute('connection', connection.type);
-    this.shareDialog_.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
-    this.suggestAppsDialog.onDriveConnectionChanged(connection.type);
-  };
-
-  /**
-   * Get the metered status of Drive connection.
-   *
-   * @return {boolean} Returns true if drive should limit the traffic because
-   * the connection is metered and the 'disable-sync-on-metered' setting is
-   * enabled. Otherwise, returns false.
-   */
-  FileManager.prototype.isDriveOnMeteredConnection = function() {
-    var connection = this.volumeManager_.getDriveConnectionState();
-    return connection.type == util.DriveConnectionType.METERED;
-  };
-
-  /**
-   * Get the online/offline status of drive.
-   *
-   * @return {boolean} Returns true if the connection is offline. Otherwise,
-   * returns false.
-   */
-  FileManager.prototype.isDriveOffline = function() {
-    var connection = this.volumeManager_.getDriveConnectionState();
-    return connection.type == util.DriveConnectionType.OFFLINE;
-  };
-
-  FileManager.prototype.isOnReadonlyDirectory = function() {
-    return this.directoryModel_.isReadOnly();
-  };
-
-  /**
-   * @param {Event} Unmount event.
-   * @private
-   */
-  FileManager.prototype.onExternallyUnmounted_ = function(event) {
-    if (event.mountPath == this.directoryModel_.getCurrentRootPath()) {
-      if (this.closeOnUnmount_) {
-        // If the file manager opened automatically when a usb drive inserted,
-        // user have never changed current volume (that implies the current
-        // directory is still on the device) then close this window.
-        window.close();
-      }
-    }
-  };
-
-  /**
-   * Show a modal-like file viewer/editor on top of the File Manager UI.
-   *
-   * @param {HTMLElement} popup Popup element.
-   * @param {function} closeCallback Function to call after the popup is closed.
-   *
-   * @private
-   */
-  FileManager.prototype.openFilePopup_ = function(popup, closeCallback) {
-    this.closeFilePopup_();
-    this.filePopup_ = popup;
-    this.filePopupCloseCallback_ = closeCallback;
-    this.dialogDom_.appendChild(this.filePopup_);
-    this.filePopup_.focus();
-    this.document_.body.setAttribute('overlay-visible', '');
-    this.document_.querySelector('#iframe-drag-area').hidden = false;
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.closeFilePopup_ = function() {
-    if (this.filePopup_) {
-      this.document_.body.removeAttribute('overlay-visible');
-      this.document_.querySelector('#iframe-drag-area').hidden = true;
-      // The window resize would not be processed properly while the relevant
-      // divs had 'display:none', force resize after the layout fired.
-      setTimeout(this.onResize_.bind(this), 0);
-      if (this.filePopup_.contentWindow &&
-          this.filePopup_.contentWindow.unload) {
-        this.filePopup_.contentWindow.unload();
-      }
-
-      if (this.filePopupCloseCallback_) {
-        this.filePopupCloseCallback_();
-        this.filePopupCloseCallback_ = null;
-      }
-
-      // These operations have to be in the end, otherwise v8 crashes on an
-      // assert. See: crbug.com/224174.
-      this.dialogDom_.removeChild(this.filePopup_);
-      this.filePopup_ = null;
-    }
-  };
-
-  FileManager.prototype.getAllUrlsInCurrentDirectory = function() {
-    var urls = [];
-    var fileList = this.directoryModel_.getFileList();
-    for (var i = 0; i != fileList.length; i++) {
-      urls.push(fileList.item(i).toURL());
-    }
-    return urls;
-  };
-
-  FileManager.prototype.isRenamingInProgress = function() {
-    return !!this.renameInput_.currentEntry;
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.focusCurrentList_ = function() {
-    if (this.listType_ == FileManager.ListType.DETAIL)
-      this.table_.focus();
-    else  // this.listType_ == FileManager.ListType.THUMBNAIL)
-      this.grid_.focus();
-  };
-
-  /**
-   * Return full path of the current directory or null.
-   * @return {?string} The full path of the current directory.
-   */
-  FileManager.prototype.getCurrentDirectory = function() {
-    return this.directoryModel_ && this.directoryModel_.getCurrentDirPath();
-  };
-
-  /**
-   * Return URL of the current directory or null.
-   * @return {string} URL representing the current directory.
-   */
-  FileManager.prototype.getCurrentDirectoryURL = function() {
-    return this.directoryModel_ &&
-           this.directoryModel_.getCurrentDirectoryURL();
-  };
-
-  /**
-   * Return DirectoryEntry of the current directory or null.
-   * @return {DirectoryEntry} DirectoryEntry of the current directory. Returns
-   *     null if the directory model is not ready or the current directory is
-   *     not set.
-   */
-  FileManager.prototype.getCurrentDirectoryEntry = function() {
-    return this.directoryModel_ && this.directoryModel_.getCurrentDirEntry();
-  };
-
-  /**
-   * Deletes the selected file and directories recursively.
-   */
-  FileManager.prototype.deleteSelection = function() {
-    // TODO(mtomasz): Remove this temporary dialog. crbug.com/167364
-    var entries = this.getSelection().entries;
-    var message = entries.length == 1 ?
-        strf('GALLERY_CONFIRM_DELETE_ONE', entries[0].name) :
-        strf('GALLERY_CONFIRM_DELETE_SOME', entries.length);
-    this.confirm.show(message, function() {
-      this.fileOperationManager_.deleteEntries(entries);
-    }.bind(this));
-  };
-
-  /**
-   * Shows the share dialog for the selected file or directory.
-   */
-  FileManager.prototype.shareSelection = function() {
-    var entries = this.getSelection().entries;
-    if (entries.length != 1) {
-      console.warn('Unable to share multiple items at once.');
-      return;
-    }
-    // Add the overlapped class to prevent the applicaiton window from
-    // captureing mouse events.
-    this.shareDialog_.show(entries[0], function(result) {
-      if (result == ShareDialog.Result.NETWORK_ERROR)
-        this.error.show(str('SHARE_ERROR'));
-    }.bind(this));
-  };
-
-  /**
-   * Creates a folder shortcut.
-   * @param {string} path A shortcut which refers to |path| to be created.
-   */
-  FileManager.prototype.createFolderShortcut = function(path) {
-    // Duplicate entry.
-    if (this.folderShortcutExists(path))
-      return;
-
-    this.folderShortcutsModel_.add(path);
-  };
-
-  /**
-   * Checkes if the shortcut which refers to the given folder exists or not.
-   * @param {string} path Path of the folder to be checked.
-   */
-  FileManager.prototype.folderShortcutExists = function(path) {
-    return this.folderShortcutsModel_.exists(path);
-  };
-
-  /**
-   * Removes the folder shortcut.
-   * @param {string} path The shortcut which refers to |path| is to be removed.
-   */
-  FileManager.prototype.removeFolderShortcut = function(path) {
-    this.folderShortcutsModel_.remove(path);
-  };
-
-  /**
-   * Blinks the selection. Used to give feedback when copying or cutting the
-   * selection.
-   */
-  FileManager.prototype.blinkSelection = function() {
-    var selection = this.getSelection();
-    if (!selection || selection.totalCount == 0)
-      return;
-
-    for (var i = 0; i < selection.entries.length; i++) {
-      var selectedIndex = selection.indexes[i];
-      var listItem = this.currentList_.getListItemByIndex(selectedIndex);
-      if (listItem)
-        this.blinkListItem_(listItem);
-    }
-  };
-
-  /**
-   * @param {Element} listItem List item element.
-   * @private
-   */
-  FileManager.prototype.blinkListItem_ = function(listItem) {
-    listItem.classList.add('blink');
-    setTimeout(function() {
-      listItem.classList.remove('blink');
-    }, 100);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.selectDefaultPathInFilenameInput_ = function() {
-    var input = this.filenameInput_;
-    input.focus();
-    var selectionEnd = input.value.lastIndexOf('.');
-    if (selectionEnd == -1) {
-      input.select();
-    } else {
-      input.selectionStart = 0;
-      input.selectionEnd = selectionEnd;
-    }
-    // Clear, so we never do this again.
-    this.defaultPath = '';
-  };
-
-  /**
-   * Handles mouse click or tap.
-   *
-   * @param {Event} event The click event.
-   * @private
-   */
-  FileManager.prototype.onDetailClick_ = function(event) {
-    if (this.isRenamingInProgress()) {
-      // Don't pay attention to clicks during a rename.
-      return;
-    }
-
-    var listItem = this.findListItemForEvent_(event);
-    var selection = this.getSelection();
-    if (!listItem || !listItem.selected || selection.totalCount != 1) {
-      return;
-    }
-
-    // React on double click, but only if both clicks hit the same item.
-    // TODO(mtomasz): Simplify it, and use a double click handler if possible.
-    var clickNumber = (this.lastClickedItem_ == listItem) ? 2 : undefined;
-    this.lastClickedItem_ = listItem;
-
-    if (event.detail != clickNumber)
-      return;
-
-    var entry = selection.entries[0];
-    if (entry.isDirectory) {
-      this.onDirectoryAction_(entry);
-    } else {
-      this.dispatchSelectionAction_();
-    }
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.dispatchSelectionAction_ = function() {
-    if (this.dialogType == DialogType.FULL_PAGE) {
-      var selection = this.getSelection();
-      var tasks = selection.tasks;
-      var urls = selection.urls;
-      var mimeTypes = selection.mimeTypes;
-      if (tasks) {
-        tasks.executeDefault(function(result) {
-          if (result)
-            return;
-
-          var showAlert = function() {
-            var filename = decodeURIComponent(urls[0]);
-            if (filename.indexOf('/') != -1)
-              filename = filename.substr(filename.lastIndexOf('/') + 1);
-            var extension = filename.lastIndexOf('.') != -1 ?
-                filename.substr(filename.lastIndexOf('.') + 1) : '';
-            var mimeType = mimeTypes && mimeTypes[0];
-
-            var messageString =
-                extension == 'exe' ? 'NO_ACTION_FOR_EXECUTABLE' :
-                                     'NO_ACTION_FOR_FILE';
-            var webStoreUrl = FileTasks.createWebStoreLink(extension, mimeType);
-            var text = loadTimeData.getStringF(
-                messageString,
-                webStoreUrl,
-                FileTasks.NO_ACTION_FOR_FILE_URL);
-            this.alert.showHtml(filename, text, function() {});
-          }.bind(this);
-
-          // TODO(yoshiki): Remove the flag when the feature is launched.
-          if (!this.enableExperimentalWebstoreIntegration_) {
-            showAlert();
-            return;
-          }
-
-          if (this.isDriveOffline()) {
-            showAlert();
-            return;
-          }
-
-          this.openSuggestAppsDialog_(urls,
-            // Success callback.
-            function() {
-              var tasks = new FileTasks(this);
-              tasks.init(urls, mimeTypes);
-              tasks.executeDefault();
-            }.bind(this),
-            // Cancelled callback.
-            function() {},
-            // Failure callback.
-            showAlert);
-        }.bind(this));
-      }
-      return true;
-    }
-    if (!this.okButton_.disabled) {
-      this.onOk_();
-      return true;
-    }
-    return false;
-  };
-
-  /**
-   * Opens the suggest file dialog.
-   *
-   * @param {Array.<string>} urls List of URLs of files.
-   * @param {function()} onSuccess Success callback.
-   * @param {function()} onCancelled User-cancelled callback.
-   * @param {function()} onFailure Failure callback.
-   * @private
-   */
-  FileManager.prototype.openSuggestAppsDialog_ =
-      function(urls, onSuccess, onCancelled, onFailure) {
-    if (!urls || urls.length != 1) {
-      onFailure();
-      return;
-    }
-
-    this.metadataCache_.get(urls, 'drive', function(props) {
-      if (!props || !props[0] || !props[0].contentMimeType) {
-        onFailure();
-        return;
-      }
-
-      var filename = util.extractFilePath(urls[0]);
-      var extension = PathUtil.extractExtension(filename);
-      var mime = props[0].contentMimeType;
-
-      // Returns with failure if the file has neither extension nor mime.
-      if (!extension || !mime) {
-        onFailure();
-        return;
-      }
-
-      this.suggestAppsDialog.show(
-          extension, mime,
-          function(result) {
-            switch (result) {
-              case SuggestAppsDialog.Result.INSTALL_SUCCESSFUL:
-                onSuccess();
-                break;
-              case SuggestAppsDialog.Result.FAILED:
-                onFailure();
-                break;
-              default:
-                onCancelled();
-            }
-          });
-    }.bind(this));
-  };
-
-  /**
-   * Called when a dialog is shown or hidden.
-   * @param {boolean} flag True if a dialog is shown, false if hidden.   */
-  FileManager.prototype.onDialogShownOrHidden = function(show) {
-    // Set/unset a flag to disable dragging on the title area.
-    this.dialogContainer_.classList.toggle('disable-header-drag', show);
-  };
-
-  /**
-   * Executes directory action (i.e. changes directory).
-   *
-   * @param {DirectoryEntry} entry Directory entry to which directory should be
-   *                               changed.
-   * @private
-   */
-  FileManager.prototype.onDirectoryAction_ = function(entry) {
-    return this.directoryModel_.changeDirectory(entry.fullPath);
-  };
-
-  /**
-   * Update the window title.
-   * @private
-   */
-  FileManager.prototype.updateTitle_ = function() {
-    if (this.dialogType != DialogType.FULL_PAGE)
-      return;
-
-    var path = this.getCurrentDirectory();
-    var rootPath = PathUtil.getRootPath(path);
-    this.document_.title = PathUtil.getRootLabel(rootPath) +
-                           path.substring(rootPath.length);
-  };
-
-  /**
-   * Update the gear menu.
-   * @private
-   */
-  FileManager.prototype.updateGearMenu_ = function() {
-    var hideItemsForDrive = !this.isOnDrive();
-    this.syncButton.hidden = hideItemsForDrive;
-    this.hostedButton.hidden = hideItemsForDrive;
-    this.document_.getElementById('drive-separator').hidden =
-        hideItemsForDrive;
-
-    // If volume has changed, then fetch remaining space data.
-    if (this.previousRootUrl_ != this.directoryModel_.getCurrentMountPointUrl())
-      this.refreshRemainingSpace_(true);  // Show loading caption.
-
-    this.previousRootUrl_ = this.directoryModel_.getCurrentMountPointUrl();
-  };
-
-  /**
-   * Refreshes space info of the current volume.
-   * @param {boolean} showLoadingCaption Whether show loading caption or not.
-   * @private
-   */
-  FileManager.prototype.refreshRemainingSpace_ = function(showLoadingCaption) {
-    var volumeSpaceInfoLabel =
-        this.dialogDom_.querySelector('#volume-space-info-label');
-    var volumeSpaceInnerBar =
-        this.dialogDom_.querySelector('#volume-space-info-bar');
-    var volumeSpaceOuterBar =
-        this.dialogDom_.querySelector('#volume-space-info-bar').parentNode;
-
-    volumeSpaceInnerBar.setAttribute('pending', '');
-
-    if (showLoadingCaption) {
-      volumeSpaceInfoLabel.innerText = str('WAITING_FOR_SPACE_INFO');
-      volumeSpaceInnerBar.style.width = '100%';
-    }
-
-    var currentMountPointUrl = this.directoryModel_.getCurrentMountPointUrl();
-    chrome.fileBrowserPrivate.getSizeStats(
-        currentMountPointUrl, function(result) {
-          if (this.directoryModel_.getCurrentMountPointUrl() !=
-              currentMountPointUrl)
-            return;
-          updateSpaceInfo(result,
-                          volumeSpaceInnerBar,
-                          volumeSpaceInfoLabel,
-                          volumeSpaceOuterBar);
-        }.bind(this));
-  };
-
-  /**
-   * Update the UI when the current directory changes.
-   *
-   * @param {Event} event The directory-changed event.
-   * @private
-   */
-  FileManager.prototype.onDirectoryChanged_ = function(event) {
-    this.selectionHandler_.onFileSelectionChanged();
-    this.ui_.searchBox.clear();
-    util.updateAppState(this.getCurrentDirectory());
-
-    // If the current directory is moved from the device's volume, do not
-    // automatically close the window on device removal.
-    if (event.previousDirEntry &&
-        PathUtil.getRootPath(event.previousDirEntry.fullPath) !=
-            PathUtil.getRootPath(event.newDirEntry.fullPath))
-      this.closeOnUnmount_ = false;
-
-    if (this.commandHandler)
-      this.commandHandler.updateAvailability();
-    this.updateUnformattedDriveStatus_();
-    this.updateTitle_();
-    this.updateGearMenu_();
-    this.previewPanel_.currentPath_ = this.getCurrentDirectory();
-  };
-
-  // TODO(haruki): Rename this method. "Drive" here does not refer
-  // "Google Drive".
-  FileManager.prototype.updateUnformattedDriveStatus_ = function() {
-    var volumeInfo = this.volumeManager_.getVolumeInfo(
-        PathUtil.getRootPath(this.directoryModel_.getCurrentRootPath()));
-
-    if (volumeInfo && volumeInfo.error) {
-      this.dialogDom_.setAttribute('unformatted', '');
-
-      var errorNode = this.dialogDom_.querySelector('#format-panel > .error');
-      if (volumeInfo.error == util.VolumeError.UNSUPPORTED_FILESYSTEM) {
-        errorNode.textContent = str('UNSUPPORTED_FILESYSTEM_WARNING');
-      } else {
-        errorNode.textContent = str('UNKNOWN_FILESYSTEM_WARNING');
-      }
-
-      // Update 'canExecute' for format command so the format button's disabled
-      // property is properly set.
-      if (this.commandHandler)
-        this.commandHandler.updateAvailability();
-    } else {
-      this.dialogDom_.removeAttribute('unformatted');
-    }
-  };
-
-  FileManager.prototype.findListItemForEvent_ = function(event) {
-    return this.findListItemForNode_(event.touchedElement || event.srcElement);
-  };
-
-  FileManager.prototype.findListItemForNode_ = function(node) {
-    var item = this.currentList_.getListItemAncestor(node);
-    // TODO(serya): list should check that.
-    return item && this.currentList_.isItem(item) ? item : null;
-  };
-
-  /**
-   * Unload handler for the page.  May be called manually for the file picker
-   * dialog, because it closes by calling extension API functions that do not
-   * return.
-   *
-   * @private
-   */
-  FileManager.prototype.onUnload_ = function() {
-    if (this.directoryModel_)
-      this.directoryModel_.dispose();
-    if (this.volumeManager_)
-      this.volumeManager_.dispose();
-    if (this.filePopup_ &&
-        this.filePopup_.contentWindow &&
-        this.filePopup_.contentWindow.unload)
-      this.filePopup_.contentWindow.unload(true /* exiting */);
-    if (this.butterBar_)
-      this.butterBar_.dispose();
-    if (this.fileOperationManager_) {
-      if (this.onCopyProgressBound_) {
-        this.fileOperationManager_.removeEventListener(
-            'copy-progress', this.onCopyProgressBound_);
-      }
-      if (this.onEntryChangedBound_) {
-        this.fileOperationManager_.removeEventListener(
-            'entry-changed', this.onEntryChangedBound_);
-      }
-    }
-  };
-
-  FileManager.prototype.initiateRename = function() {
-    var item = this.currentList_.ensureLeadItemExists();
-    if (!item)
-      return;
-    var label = item.querySelector('.filename-label');
-    var input = this.renameInput_;
-
-    input.value = label.textContent;
-    label.parentNode.setAttribute('renaming', '');
-    label.parentNode.appendChild(input);
-    input.focus();
-    var selectionEnd = input.value.lastIndexOf('.');
-    if (selectionEnd == -1) {
-      input.select();
-    } else {
-      input.selectionStart = 0;
-      input.selectionEnd = selectionEnd;
-    }
-
-    // This has to be set late in the process so we don't handle spurious
-    // blur events.
-    input.currentEntry = this.currentList_.dataModel.item(item.listIndex);
-  };
-
-  /**
-   * @type {Event} Key event.
-   * @private
-   */
-  FileManager.prototype.onRenameInputKeyDown_ = function(event) {
-    if (!this.isRenamingInProgress())
-      return;
-
-    // Do not move selection or lead item in list during rename.
-    if (event.keyIdentifier == 'Up' || event.keyIdentifier == 'Down') {
-      event.stopPropagation();
-    }
-
-    switch (util.getKeyModifiers(event) + event.keyCode) {
-      case '27':  // Escape
-        this.cancelRename_();
-        event.preventDefault();
-        break;
-
-      case '13':  // Enter
-        this.commitRename_();
-        event.preventDefault();
-        break;
-    }
-  };
-
-  /**
-   * @type {Event} Blur event.
-   * @private
-   */
-  FileManager.prototype.onRenameInputBlur_ = function(event) {
-    if (this.isRenamingInProgress() && !this.renameInput_.validation_)
-      this.commitRename_();
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.commitRename_ = function() {
-    var input = this.renameInput_;
-    var entry = input.currentEntry;
-    var newName = input.value;
-
-    if (newName == entry.name) {
-      this.cancelRename_();
-      return;
-    }
-
-    var nameNode = this.findListItemForNode_(this.renameInput_).
-                   querySelector('.filename-label');
-
-    input.validation_ = true;
-    var validationDone = function(valid) {
-      input.validation_ = false;
-      // Alert dialog restores focus unless the item removed from DOM.
-      if (this.document_.activeElement != input)
-        this.cancelRename_();
-      if (!valid)
-        return;
-
-      // Validation succeeded. Do renaming.
-
-      this.cancelRename_();
-      // Optimistically apply new name immediately to avoid flickering in
-      // case of success.
-      nameNode.textContent = newName;
-
-      util.rename(
-          entry, newName,
-          function(newEntry) {
-            this.directoryModel_.onRenameEntry(entry, newEntry);
-          }.bind(this),
-          function(error) {
-            // Write back to the old name.
-            nameNode.textContent = entry.name;
-
-            // Show error dialog.
-            var message;
-            if (error.code == FileError.PATH_EXISTS_ERR ||
-                error.code == FileError.TYPE_MISMATCH_ERR) {
-              // Check the existing entry is file or not.
-              // 1) If the entry is a file:
-              //   a) If we get PATH_EXISTS_ERR, a file exists.
-              //   b) If we get TYPE_MISMATCH_ERR, a directory exists.
-              // 2) If the entry is a directory:
-              //   a) If we get PATH_EXISTS_ERR, a directory exists.
-              //   b) If we get TYPE_MISMATCH_ERR, a file exists.
-              message = strf(
-                  (entry.isFile && error.code == FileError.PATH_EXISTS_ERR) ||
-                  (!entry.isFile && error.code == FileError.TYPE_MISMATCH_ERR) ?
-                      'FILE_ALREADY_EXISTS' :
-                      'DIRECTORY_ALREADY_EXISTS',
-                  newName);
-            } else {
-              message = strf('ERROR_RENAMING', entry.name,
-                             util.getFileErrorString(err.code));
-            }
-
-            this.alert.show(message);
-          }.bind(this));
-    };
-
-    // TODO(haruki): this.getCurrentDirectoryURL() might not return the actual
-    // parent if the directory content is a search result. Fix it to do proper
-    // validation.
-    this.validateFileName_(this.getCurrentDirectoryURL(),
-                           newName,
-                           validationDone.bind(this));
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.cancelRename_ = function() {
-    this.renameInput_.currentEntry = null;
-
-    var parent = this.renameInput_.parentNode;
-    if (parent) {
-      parent.removeAttribute('renaming');
-      parent.removeChild(this.renameInput_);
-    }
-  };
-
-  /**
-   * @param {Event} Key event.
-   * @private
-   */
-  FileManager.prototype.onFilenameInputKeyDown_ = function(event) {
-    var enabled = this.selectionHandler_.updateOkButton();
-    if (enabled &&
-        (util.getKeyModifiers(event) + event.keyCode) == '13' /* Enter */)
-      this.onOk_();
-  };
-
-  /**
-   * @param {Event} Focus event.
-   * @private
-   */
-  FileManager.prototype.onFilenameInputFocus_ = function(event) {
-    var input = this.filenameInput_;
-
-    // On focus we want to select everything but the extension, but
-    // Chrome will select-all after the focus event completes.  We
-    // schedule a timeout to alter the focus after that happens.
-    setTimeout(function() {
-        var selectionEnd = input.value.lastIndexOf('.');
-        if (selectionEnd == -1) {
-          input.select();
-        } else {
-          input.selectionStart = 0;
-          input.selectionEnd = selectionEnd;
-        }
-    }, 0);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onScanStarted_ = function() {
-    if (this.scanInProgress_) {
-      this.table_.list.endBatchUpdates();
-      this.grid_.endBatchUpdates();
-    }
-
-    if (this.commandHandler)
-      this.commandHandler.updateAvailability();
-    this.table_.list.startBatchUpdates();
-    this.grid_.startBatchUpdates();
-    this.scanInProgress_ = true;
-
-    this.scanUpdatedAtLeastOnceOrCompleted_ = false;
-    if (this.scanCompletedTimer_) {
-      clearTimeout(this.scanCompletedTimer_);
-      this.scanCompletedTimer_ = null;
-    }
-
-    if (this.scanUpdatedTimer_) {
-      clearTimeout(this.scanUpdatedTimer_);
-      this.scanUpdatedTimer_ = null;
-    }
-
-    if (this.spinner_.hidden) {
-      this.cancelSpinnerTimeout_();
-      this.showSpinnerTimeout_ =
-          setTimeout(this.showSpinner_.bind(this, true), 500);
-    }
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onScanCompleted_ = function() {
-    if (!this.scanInProgress_) {
-      console.error('Scan-completed event recieved. But scan is not started.');
-      return;
-    }
-
-    if (this.commandHandler)
-      this.commandHandler.updateAvailability();
-    this.hideSpinnerLater_();
-    this.refreshCurrentDirectoryMetadata_();
-
-    if (this.scanUpdatedTimer_) {
-      clearTimeout(this.scanUpdatedTimer_);
-      this.scanUpdatedTimer_ = null;
-    }
-
-    // To avoid flickering postpone updating the ui by a small amount of time.
-    // There is a high chance, that metadata will be received within 50 ms.
-    this.scanCompletedTimer_ = setTimeout(function() {
-      // Check if batch updates are already finished by onScanUpdated_().
-      if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
-        this.scanUpdatedAtLeastOnceOrCompleted_ = true;
-        this.updateMiddleBarVisibility_();
-      }
-
-      this.scanInProgress_ = false;
-      this.table_.list.endBatchUpdates();
-      this.grid_.endBatchUpdates();
-      this.scanCompletedTimer_ = null;
-    }.bind(this), 50);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onScanUpdated_ = function() {
-    if (!this.scanInProgress_) {
-      console.error('Scan-updated event recieved. But scan is not started.');
-      return;
-    }
-
-    if (this.scanUpdatedTimer_ || this.scanCompletedTimer_)
-      return;
-
-    // Show contents incrementally by finishing batch updated, but only after
-    // 200ms elapsed, to avoid flickering when it is not necessary.
-    this.scanUpdatedTimer_ = setTimeout(function() {
-      // We need to hide the spinner only once.
-      if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
-        this.scanUpdatedAtLeastOnceOrCompleted_ = true;
-        this.hideSpinnerLater_();
-        this.updateMiddleBarVisibility_();
-      }
-
-      // Update the UI.
-      if (this.scanInProgress_) {
-        this.table_.list.endBatchUpdates();
-        this.grid_.endBatchUpdates();
-        this.table_.list.startBatchUpdates();
-        this.grid_.startBatchUpdates();
-      }
-      this.scanUpdatedTimer_ = null;
-    }.bind(this), 200);
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.onScanCancelled_ = function() {
-    if (!this.scanInProgress_) {
-      console.error('Scan-cancelled event recieved. But scan is not started.');
-      return;
-    }
-
-    if (this.commandHandler)
-      this.commandHandler.updateAvailability();
-    this.hideSpinnerLater_();
-    if (this.scanCompletedTimer_) {
-      clearTimeout(this.scanCompletedTimer_);
-      this.scanCompletedTimer_ = null;
-    }
-    if (this.scanUpdatedTimer_) {
-      clearTimeout(this.scanUpdatedTimer_);
-      this.scanUpdatedTimer_ = null;
-    }
-    // Finish unfinished batch updates.
-    if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
-      this.scanUpdatedAtLeastOnceOrCompleted_ = true;
-      this.updateMiddleBarVisibility_();
-    }
-
-    this.scanInProgress_ = false;
-    this.table_.list.endBatchUpdates();
-    this.grid_.endBatchUpdates();
-  };
-
-  /**
-   * Handle the 'rescan-completed' from the DirectoryModel.
-   * @private
-   */
-  FileManager.prototype.onRescanCompleted_ = function() {
-    this.refreshCurrentDirectoryMetadata_();
-    this.selectionHandler_.onFileSelectionChanged();
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.cancelSpinnerTimeout_ = function() {
-    if (this.showSpinnerTimeout_) {
-      clearTimeout(this.showSpinnerTimeout_);
-      this.showSpinnerTimeout_ = null;
-    }
-  };
-
-  /**
-   * @private
-   */
-  FileManager.prototype.hideSpinnerLater_ = function() {
-    this.cancelSpinnerTimeout_();
-    this.showSpinner_(false);
-  };
-
-  /**
-   * @param {boolean} on True to show, false to hide.
-   * @private
-   */
-  FileManager.prototype.showSpinner_ = function(on) {
-    if (on && this.directoryModel_ && this.directoryModel_.isScanning())
-      this.spinner_.hidden = false;
-
-    if (!on && (!this.directoryModel_ ||
-                !this.directoryModel_.isScanning() ||
-                this.directoryModel_.getFileList().length != 0)) {
-      this.spinner_.hidden = true;
-    }
-  };
-
-  FileManager.prototype.createNewFolder = function() {
-    var defaultName = str('DEFAULT_NEW_FOLDER_NAME');
-
-    // Find a name that doesn't exist in the data model.
-    var files = this.directoryModel_.getFileList();
-    var hash = {};
-    for (var i = 0; i < files.length; i++) {
-      var name = files.item(i).name;
-      // Filtering names prevents from conflicts with prototype's names
-      // and '__proto__'.
-      if (name.substring(0, defaultName.length) == defaultName)
-        hash[name] = 1;
-    }
-
-    var baseName = defaultName;
-    var separator = '';
-    var suffix = '';
-    var index = '';
-
-    var advance = function() {
-      separator = ' (';
-      suffix = ')';
-      index++;
-    };
-
-    var current = function() {
-      return baseName + separator + index + suffix;
-    };
-
-    // Accessing hasOwnProperty is safe since hash properties filtered.
-    while (hash.hasOwnProperty(current())) {
-      advance();
-    }
-
-    var self = this;
-    var list = self.currentList_;
-    var tryCreate = function() {
-      self.directoryModel_.createDirectory(current(),
-                                           onSuccess, onError);
-    };
-
-    var onSuccess = function(entry) {
-      metrics.recordUserAction('CreateNewFolder');
-      list.selectedItem = entry;
-      self.initiateRename();
-    };
-
-    var onError = function(error) {
-      self.alert.show(strf('ERROR_CREATING_FOLDER', current(),
-                           util.getFileErrorString(error.code)));
-    };
-
-    tryCreate();
-  };
-
-  /**
-   * @param {Event} event Click event.
-   * @private
-   */
-  FileManager.prototype.onDetailViewButtonClick_ = function(event) {
-    this.setListType(FileManager.ListType.DETAIL);
-    this.currentList_.focus();
-  };
-
-  /**
-   * @param {Event} event Click event.
-   * @private
-   */
-  FileManager.prototype.onThumbnailViewButtonClick_ = function(event) {
-    this.setListType(FileManager.ListType.THUMBNAIL);
-    this.currentList_.focus();
-  };
-
-  /**
-   * KeyDown event handler for the document.
-   * @param {Event} event Key event.
-   * @private
-   */
-  FileManager.prototype.onKeyDown_ = function(event) {
-    if (event.srcElement === this.renameInput_) {
-      // Ignore keydown handler in the rename input box.
-      return;
-    }
-
-    switch (util.getKeyModifiers(event) + event.keyCode) {
-      case 'Ctrl-190':  // Ctrl-. => Toggle filter files.
-        this.fileFilter_.setFilterHidden(
-            !this.fileFilter_.isFilterHiddenOn());
-        event.preventDefault();
-        return;
-
-      case '27':  // Escape => Cancel dialog.
-        if (this.fileOperationManager_ &&
-            this.fileOperationManager_.isRunning()) {
-          // If there is a copy in progress, ESC will cancel it.
-          event.preventDefault();
-          this.fileOperationManager_.requestCancel();
-          return;
-        }
-
-        if (this.dialogType != DialogType.FULL_PAGE) {
-          // If there is nothing else for ESC to do, then cancel the dialog.
-          event.preventDefault();
-          this.cancelButton_.click();
-        }
-        break;
-    }
-  };
-
-  /**
-   * KeyDown event handler for the div#list-container element.
-   * @param {Event} event Key event.
-   * @private
-   */
-  FileManager.prototype.onListKeyDown_ = function(event) {
-    if (event.srcElement.tagName == 'INPUT') {
-      // Ignore keydown handler in the rename input box.
-      return;
-    }
-
-    switch (util.getKeyModifiers(event) + event.keyCode) {
-      case '8':  // Backspace => Up one directory.
-        event.preventDefault();
-        var path = this.getCurrentDirectory();
-        if (path && !PathUtil.isRootPath(path)) {
-          var path = path.replace(/\/[^\/]+$/, '');
-          this.directoryModel_.changeDirectory(path);
-        }
-        break;
-
-      case '13':  // Enter => Change directory or perform default action.
-        // TODO(dgozman): move directory action to dispatchSelectionAction.
-        var selection = this.getSelection();
-        if (selection.totalCount == 1 &&
-            selection.entries[0].isDirectory &&
-            this.dialogType != DialogType.SELECT_FOLDER &&
-            this.dialogType != DialogType.SELECT_UPLOAD_FOLDER) {
-          event.preventDefault();
-          this.onDirectoryAction_(selection.entries[0]);
-        } else if (this.dispatchSelectionAction_()) {
-          event.preventDefault();
-        }
-        break;
-    }
-
-    switch (event.keyIdentifier) {
-      case 'Home':
-      case 'End':
-      case 'Up':
-      case 'Down':
-      case 'Left':
-      case 'Right':
-        // When navigating with keyboard we hide the distracting mouse hover
-        // highlighting until the user moves the mouse again.
-        this.setNoHover_(true);
-        break;
-    }
-  };
-
-  /**
-   * Suppress/restore hover highlighting in the list container.
-   * @param {boolean} on True to temporarity hide hover state.
-   * @private
-   */
-  FileManager.prototype.setNoHover_ = function(on) {
-    if (on) {
-      this.listContainer_.classList.add('nohover');
-    } else {
-      this.listContainer_.classList.remove('nohover');
-    }
-  };
-
-  /**
-   * KeyPress event handler for the div#list-container element.
-   * @param {Event} event Key event.
-   * @private
-   */
-  FileManager.prototype.onListKeyPress_ = function(event) {
-    if (event.srcElement.tagName == 'INPUT') {
-      // Ignore keypress handler in the rename input box.
-      return;
-    }
-
-    if (event.ctrlKey || event.metaKey || event.altKey)
-      return;
-
-    var now = new Date();
-    var char = String.fromCharCode(event.charCode).toLowerCase();
-    var text = now - this.textSearchState_.date > 1000 ? '' :
-        this.textSearchState_.text;
-    this.textSearchState_ = {text: text + char, date: now};
-
-    this.doTextSearch_();
-  };
-
-  /**
-   * Mousemove event handler for the div#list-container element.
-   * @param {Event} event Mouse event.
-   * @private
-   */
-  FileManager.prototype.onListMouseMove_ = function(event) {
-    // The user grabbed the mouse, restore the hover highlighting.
-    this.setNoHover_(false);
-  };
-
-  /**
-   * Performs a 'text search' - selects a first list entry with name
-   * starting with entered text (case-insensitive).
-   * @private
-   */
-  FileManager.prototype.doTextSearch_ = function() {
-    var text = this.textSearchState_.text;
-    if (!text)
-      return;
-
-    var dm = this.directoryModel_.getFileList();
-    for (var index = 0; index < dm.length; ++index) {
-      var name = dm.item(index).name;
-      if (name.substring(0, text.length).toLowerCase() == text) {
-        this.currentList_.selectionModel.selectedIndexes = [index];
-        return;
-      }
-    }
-
-    this.textSearchState_.text = '';
-  };
-
-  /**
-   * Handle a click of the cancel button.  Closes the window.
-   * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
-   *
-   * @param {Event} event The click event.
-   * @private
-   */
-  FileManager.prototype.onCancel_ = function(event) {
-    chrome.fileBrowserPrivate.cancelDialog();
-    this.onUnload_();
-    window.close();
-  };
-
-  /**
-   * Resolves selected file urls returned from an Open dialog.
-   *
-   * For drive files this involves some special treatment.
-   * Starts getting drive files if needed.
-   *
-   * @param {Array.<string>} fileUrls Drive URLs.
-   * @param {function(Array.<string>)} callback To be called with fixed URLs.
-   * @private
-   */
-  FileManager.prototype.resolveSelectResults_ = function(fileUrls, callback) {
-    if (this.isOnDrive()) {
-      chrome.fileBrowserPrivate.getDriveFiles(
-        fileUrls,
-        function(localPaths) {
-          callback(fileUrls);
-        });
-    } else {
-      callback(fileUrls);
-    }
-  };
-
-  /**
-   * Closes this modal dialog with some files selected.
-   * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
-   * @param {Object} selection Contains urls, filterIndex and multiple fields.
-   * @private
-   */
-  FileManager.prototype.callSelectFilesApiAndClose_ = function(selection) {
-    var self = this;
-    function callback() {
-      self.onUnload_();
-      window.close();
-    }
-    if (selection.multiple) {
-      chrome.fileBrowserPrivate.selectFiles(
-          selection.urls, this.params_.shouldReturnLocalPath, callback);
-    } else {
-      var forOpening = (this.dialogType != DialogType.SELECT_SAVEAS_FILE);
-      chrome.fileBrowserPrivate.selectFile(
-          selection.urls[0], selection.filterIndex, forOpening,
-          this.params_.shouldReturnLocalPath, callback);
-    }
-  };
-
-  /**
-   * Tries to close this modal dialog with some files selected.
-   * Performs preprocessing if needed (e.g. for Drive).
-   * @param {Object} selection Contains urls, filterIndex and multiple fields.
-   * @private
-   */
-  FileManager.prototype.selectFilesAndClose_ = function(selection) {
-    if (!this.isOnDrive() ||
-        this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
-      setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
-      return;
-    }
-
-    var shade = this.document_.createElement('div');
-    shade.className = 'shade';
-    var footer = this.dialogDom_.querySelector('.button-panel');
-    var progress = footer.querySelector('.progress-track');
-    progress.style.width = '0%';
-    var cancelled = false;
-
-    var progressMap = {};
-    var filesStarted = 0;
-    var filesTotal = selection.urls.length;
-    for (var index = 0; index < selection.urls.length; index++) {
-      progressMap[selection.urls[index]] = -1;
-    }
-    var lastPercent = 0;
-    var bytesTotal = 0;
-    var bytesDone = 0;
-
-    var onFileTransfersUpdated = function(statusList) {
-      for (var index = 0; index < statusList.length; index++) {
-        var status = statusList[index];
-        var escaped = encodeURI(status.fileUrl);
-        if (!(escaped in progressMap)) continue;
-        if (status.total == -1) continue;
-
-        var old = progressMap[escaped];
-        if (old == -1) {
-          // -1 means we don't know file size yet.
-          bytesTotal += status.total;
-          filesStarted++;
-          old = 0;
-        }
-        bytesDone += status.processed - old;
-        progressMap[escaped] = status.processed;
-      }
-
-      var percent = bytesTotal == 0 ? 0 : bytesDone / bytesTotal;
-      // For files we don't have information about, assume the progress is zero.
-      percent = percent * filesStarted / filesTotal * 100;
-      // Do not decrease the progress. This may happen, if first downloaded
-      // file is small, and the second one is large.
-      lastPercent = Math.max(lastPercent, percent);
-      progress.style.width = lastPercent + '%';
-    }.bind(this);
-
-    var setup = function() {
-      this.document_.querySelector('.dialog-container').appendChild(shade);
-      setTimeout(function() { shade.setAttribute('fadein', 'fadein') }, 100);
-      footer.setAttribute('progress', 'progress');
-      this.cancelButton_.removeEventListener('click', this.onCancelBound_);
-      this.cancelButton_.addEventListener('click', onCancel);
-      chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener(
-          onFileTransfersUpdated);
-    }.bind(this);
-
-    var cleanup = function() {
-      shade.parentNode.removeChild(shade);
-      footer.removeAttribute('progress');
-      this.cancelButton_.removeEventListener('click', onCancel);
-      this.cancelButton_.addEventListener('click', this.onCancelBound_);
-      chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener(
-          onFileTransfersUpdated);
-    }.bind(this);
-
-    var onCancel = function() {
-      cancelled = true;
-      // According to API cancel may fail, but there is no proper UI to reflect
-      // this. So, we just silently assume that everything is cancelled.
-      chrome.fileBrowserPrivate.cancelFileTransfers(
-          selection.urls, function(response) {});
-      cleanup();
-    }.bind(this);
-
-    var onResolved = function(resolvedUrls) {
-      if (cancelled) return;
-      cleanup();
-      selection.urls = resolvedUrls;
-      // Call next method on a timeout, as it's unsafe to
-      // close a window from a callback.
-      setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
-    }.bind(this);
-
-    var onProperties = function(properties) {
-      for (var i = 0; i < properties.length; i++) {
-        if (!properties[i] || properties[i].present) {
-          // For files already in GCache, we don't get any transfer updates.
-          filesTotal--;
-        }
-      }
-      this.resolveSelectResults_(selection.urls, onResolved);
-    }.bind(this);
-
-    setup();
-    this.metadataCache_.get(selection.urls, 'drive', onProperties);
-  };
-
-  /**
-   * Handle a click of the ok button.
-   *
-   * The ok button has different UI labels depending on the type of dialog, but
-   * in code it's always referred to as 'ok'.
-   *
-   * @param {Event} event The click event.
-   * @private
-   */
-  FileManager.prototype.onOk_ = function(event) {
-    if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
-      // Save-as doesn't require a valid selection from the list, since
-      // we're going to take the filename from the text input.
-      var filename = this.filenameInput_.value;
-      if (!filename)
-        throw new Error('Missing filename!');
-
-      var directory = this.getCurrentDirectoryEntry();
-      var currentDirUrl = directory.toURL();
-      if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/')
-        currentDirUrl += '/';
-      this.validateFileName_(currentDirUrl, filename, function(isValid) {
-        if (!isValid)
-          return;
-
-        if (util.isFakeDirectoryEntry(directory)) {
-          // Can't save a file into a fake directory.
-          return;
-        }
-
-        var selectFileAndClose = function() {
-          this.selectFilesAndClose_({
-            urls: [currentDirUrl + encodeURIComponent(filename)],
-            multiple: false,
-            filterIndex: this.getSelectedFilterIndex_(filename)
-          });
-        }.bind(this);
-
-        directory.getFile(
-            filename, {create: false},
-            function(entry) {
-              // An existing file is found. Show confirmation dialog to
-              // overwrite it. If the user select "OK" on the dialog, save it.
-              this.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename),
-                                selectFileAndClose);
-            }.bind(this),
-            function(error) {
-              if (error.code == FileError.NOT_FOUND_ERR) {
-                // The file does not exist, so it should be ok to create a
-                // new file.
-                selectFileAndClose();
-                return;
-              }
-              if (error.code == FileError.TYPE_MISMATCH_ERR) {
-                // An directory is found.
-                // Do not allow to overwrite directory.
-                this.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename));
-                return;
-              }
-
-              // Unexpected error.
-              console.error('File save failed: ' + error.code);
-            }.bind(this));
-      }.bind(this));
-      return;
-    }
-
-    var files = [];
-    var selectedIndexes = this.currentList_.selectionModel.selectedIndexes;
-
-    if ((this.dialogType == DialogType.SELECT_FOLDER ||
-         this.dialogType == DialogType.SELECT_UPLOAD_FOLDER) &&
-        selectedIndexes.length == 0) {
-      var url = this.getCurrentDirectoryURL();
-      var singleSelection = {
-        urls: [url],
-        multiple: false,
-        filterIndex: this.getSelectedFilterIndex_()
-      };
-      this.selectFilesAndClose_(singleSelection);
-      return;
-    }
-
-    // All other dialog types require at least one selected list item.
-    // The logic to control whether or not the ok button is enabled should
-    // prevent us from ever getting here, but we sanity check to be sure.
-    if (!selectedIndexes.length)
-      throw new Error('Nothing selected!');
-
-    var dm = this.directoryModel_.getFileList();
-    for (var i = 0; i < selectedIndexes.length; i++) {
-      var entry = dm.item(selectedIndexes[i]);
-      if (!entry) {
-        console.error('Error locating selected file at index: ' + i);
-        continue;
-      }
-
-      files.push(entry.toURL());
-    }
-
-    // Multi-file selection has no other restrictions.
-    if (this.dialogType == DialogType.SELECT_OPEN_MULTI_FILE) {
-      var multipleSelection = {
-        urls: files,
-        multiple: true
-      };
-      this.selectFilesAndClose_(multipleSelection);
-      return;
-    }
-
-    // Everything else must have exactly one.
-    if (files.length > 1)
-      throw new Error('Too many files selected!');
-
-    var selectedEntry = dm.item(selectedIndexes[0]);
-
-    if (this.dialogType == DialogType.SELECT_FOLDER ||
-        this.dialogType == DialogType.SELECT_UPLOAD_FOLDER) {
-      if (!selectedEntry.isDirectory)
-        throw new Error('Selected entry is not a folder!');
-    } else if (this.dialogType == DialogType.SELECT_OPEN_FILE) {
-      if (!selectedEntry.isFile)
-        throw new Error('Selected entry is not a file!');
-    }
-
-    var singleSelection = {
-      urls: [files[0]],
-      multiple: false,
-      filterIndex: this.getSelectedFilterIndex_()
-    };
-    this.selectFilesAndClose_(singleSelection);
-  };
-
-  /**
-   * Verifies the user entered name for file or folder to be created or
-   * renamed to. Name restrictions must correspond to File API restrictions
-   * (see DOMFilePath::isValidPath). Curernt WebKit implementation is
-   * out of date (spec is
-   * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to
-   * be fixed. Shows message box if the name is invalid.
-   *
-   * It also verifies if the name length is in the limit of the filesystem.
-   *
-   * @param {string} parentUrl The URL of the parent directory entry.
-   * @param {string} name New file or folder name.
-   * @param {function} onDone Function to invoke when user closes the
-   *    warning box or immediatelly if file name is correct. If the name was
-   *    valid it is passed true, and false otherwise.
-   * @private
-   */
-  FileManager.prototype.validateFileName_ = function(parentUrl, name, onDone) {
-    var msg;
-    var testResult = /[\/\\\<\>\:\?\*\"\|]/.exec(name);
-    if (testResult) {
-      msg = strf('ERROR_INVALID_CHARACTER', testResult[0]);
-    } else if (/^\s*$/i.test(name)) {
-      msg = str('ERROR_WHITESPACE_NAME');
-    } else if (/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(name)) {
-      msg = str('ERROR_RESERVED_NAME');
-    } else if (this.fileFilter_.isFilterHiddenOn() && name[0] == '.') {
-      msg = str('ERROR_HIDDEN_NAME');
-    }
-
-    if (msg) {
-      this.alert.show(msg, function() {
-        onDone(false);
-      });
-      return;
-    }
-
-    var self = this;
-    chrome.fileBrowserPrivate.validatePathNameLength(
-        parentUrl, name, function(valid) {
-          if (!valid) {
-            self.alert.show(str('ERROR_LONG_NAME'),
-                            function() { onDone(false); });
-          } else {
-            onDone(true);
-          }
-        });
-  };
-
-  /**
-   * Handler invoked on preference setting in drive context menu.
-   *
-   * @param {string} pref  The preference to alter.
-   * @param {boolean} inverted Invert the value if true.
-   * @param {Event}  event The click event.
-   * @private
-   */
-  FileManager.prototype.onDrivePrefClick_ = function(pref, inverted, event) {
-    var newValue = !event.target.hasAttribute('checked');
-    if (newValue)
-      event.target.setAttribute('checked', 'checked');
-    else
-      event.target.removeAttribute('checked');
-
-    var changeInfo = {};
-    changeInfo[pref] = inverted ? !newValue : newValue;
-    chrome.fileBrowserPrivate.setPreferences(changeInfo);
-  };
-
-  /**
-   * Invoked when the search box is changed.
-   *
-   * @param {Event} event The changed event.
-   * @private
-   */
-  FileManager.prototype.onSearchBoxUpdate_ = function(event) {
-    var searchString = this.searchBox_.value;
-
-    if (this.isOnDrive()) {
-      // When the search text is changed, finishes the search and showes back
-      // the last directory by passing an empty string to
-      // {@code DirectoryModel.search()}.
-      if (this.directoryModel_.isSearching() &&
-          this.lastSearchQuery_ != searchString) {
-        this.doSearch('');
-      }
-
-      // On drive, incremental search is not invoked since we have an auto-
-      // complete suggestion instead.
-      return;
-    }
-
-    this.search_(searchString);
-  };
-
-  /**
-   * Handle the search clear button click.
-   * @private
-   */
-  FileManager.prototype.onSearchClearButtonClick_ = function() {
-    this.ui_.searchBox.clear();
-    this.onSearchBoxUpdate_();
-  };
-
-  /**
-   * Search files and update the list with the search result.
-   *
-   * @param {string} searchString String to be searched with.
-   * @private
-   */
-  FileManager.prototype.search_ = function(searchString) {
-    var noResultsDiv = this.document_.getElementById('no-search-results');
-
-    var reportEmptySearchResults = function() {
-      if (this.directoryModel_.getFileList().length === 0) {
-        // The string 'SEARCH_NO_MATCHING_FILES_HTML' may contain HTML tags,
-        // hence we escapes |searchString| here.
-        var html = strf('SEARCH_NO_MATCHING_FILES_HTML',
-                        util.htmlEscape(searchString));
-        noResultsDiv.innerHTML = html;
-        noResultsDiv.setAttribute('show', 'true');
-      } else {
-        noResultsDiv.removeAttribute('show');
-      }
-    };
-
-    var hideNoResultsDiv = function() {
-      noResultsDiv.removeAttribute('show');
-    };
-
-    this.doSearch(searchString,
-                  reportEmptySearchResults.bind(this),
-                  hideNoResultsDiv.bind(this));
-  };
-
-  /**
-   * Performs search and displays results.
-   *
-   * @param {string} query Query that will be searched for.
-   * @param {function()=} opt_onSearchRescan Function that will be called when
-   *     the search directory is rescanned (i.e. search results are displayed).
-   * @param {function()=} opt_onClearSearch Function to be called when search
-   *     state gets cleared.
-   */
-  FileManager.prototype.doSearch = function(
-      searchString, opt_onSearchRescan, opt_onClearSearch) {
-    var onSearchRescan = opt_onSearchRescan || function() {};
-    var onClearSearch = opt_onClearSearch || function() {};
-
-    this.lastSearchQuery_ = searchString;
-    this.directoryModel_.search(searchString, onSearchRescan, onClearSearch);
-  };
-
-  /**
-   * Requests autocomplete suggestions for files on Drive.
-   * Once the suggestions are returned, the autocomplete popup will show up.
-   *
-   * @param {string} query The text to autocomplete from.
-   * @private
-   */
-  FileManager.prototype.requestAutocompleteSuggestions_ = function(query) {
-    query = query.trimLeft();
-
-    // Only Drive supports auto-compelete
-    if (!this.isOnDrive())
-      return;
-
-    // Remember the most recent query. If there is an other request in progress,
-    // then it's result will be discarded and it will call a new request for
-    // this query.
-    this.lastAutocompleteQuery_ = query;
-    if (this.autocompleteSuggestionsBusy_)
-      return;
-
-    // The autocomplete list should be resized and repositioned here as the
-    // search box is resized when it's focused.
-    this.autocompleteList_.syncWidthAndPositionToInput();
-
-    if (!query) {
-      this.autocompleteList_.suggestions = [];
-      return;
-    }
-
-    var headerItem = {isHeaderItem: true, searchQuery: query};
-    if (!this.autocompleteList_.dataModel ||
-        this.autocompleteList_.dataModel.length == 0)
-      this.autocompleteList_.suggestions = [headerItem];
-    else
-      // Updates only the head item to prevent a flickering on typing.
-      this.autocompleteList_.dataModel.splice(0, 1, headerItem);
-
-    this.autocompleteSuggestionsBusy_ = true;
-
-    var searchParams = {
-      'query': query,
-      'types': 'ALL',
-      'maxResults': 4
-    };
-    chrome.fileBrowserPrivate.searchDriveMetadata(
-      searchParams,
-      function(suggestions) {
-        this.autocompleteSuggestionsBusy_ = false;
-
-        // Discard results for previous requests and fire a new search
-        // for the most recent query.
-        if (query != this.lastAutocompleteQuery_) {
-          this.requestAutocompleteSuggestions_(this.lastAutocompleteQuery_);
-          return;
-        }
-
-        // Keeps the items in the suggestion list.
-        this.autocompleteList_.suggestions = [headerItem].concat(suggestions);
-      }.bind(this));
-  };
-
-  /**
-   * Opens the currently selected suggestion item.
-   * @private
-   */
-  FileManager.prototype.openAutocompleteSuggestion_ = function() {
-    var selectedItem = this.autocompleteList_.selectedItem;
-
-    // If the entry is the search item or no entry is selected, just change to
-    // the search result.
-    if (!selectedItem || selectedItem.isHeaderItem) {
-      var query = selectedItem ?
-          selectedItem.searchQuery : this.searchBox_.value;
-      this.search_(query);
-      return;
-    }
-
-    var entry = selectedItem.entry;
-    // If the entry is a directory, just change the directory.
-    if (entry.isDirectory) {
-      this.onDirectoryAction_(entry);
-      return;
-    }
-
-    var urls = [entry.toURL()];
-    var self = this;
-
-    // To open a file, first get the mime type.
-    this.metadataCache_.get(urls, 'drive', function(props) {
-      var mimeType = props[0].contentMimeType || '';
-      var mimeTypes = [mimeType];
-      var openIt = function() {
-        if (self.dialogType == DialogType.FULL_PAGE) {
-          var tasks = new FileTasks(self);
-          tasks.init(urls, mimeTypes);
-          tasks.executeDefault();
-        } else {
-          self.onOk_();
-        }
-      };
-
-      // Change the current directory to the directory that contains the
-      // selected file. Note that this is necessary for an image or a video,
-      // which should be opened in the gallery mode, as the gallery mode
-      // requires the entry to be in the current directory model. For
-      // consistency, the current directory is always changed regardless of
-      // the file type.
-      entry.getParent(function(parent) {
-        var onDirectoryChanged = function(event) {
-          self.directoryModel_.removeEventListener('scan-completed',
-                                                   onDirectoryChanged);
-          self.directoryModel_.selectEntry(entry.name);
-          openIt();
-        };
-        // changeDirectory() returns immediately. We should wait until the
-        // directory scan is complete.
-        self.directoryModel_.addEventListener('scan-completed',
-                                              onDirectoryChanged);
-        self.directoryModel_.changeDirectory(
-          parent.fullPath,
-          function() {
-            // Remove the listner if the change directory failed.
-            self.directoryModel_.removeEventListener('scan-completed',
-                                                     onDirectoryChanged);
-          });
-      });
-    });
-  };
-
-  /**
-   * Opens the default app change dialog.
-   */
-  FileManager.prototype.showChangeDefaultAppPicker = function() {
-    var onActionsReady = function(actions, rememberedActionId) {
-      var items = [];
-      var defaultIndex = -1;
-      for (var i = 0; i < actions.length; i++) {
-        if (actions[i].hidden)
-          continue;
-        var title = actions[i].title;
-        if (actions[i].id == rememberedActionId) {
-          title += ' ' + loadTimeData.getString('DEFAULT_ACTION_LABEL');
-          defaultIndex = i;
-        }
-        var item = {
-          id: actions[i].id,
-          label: title,
-          class: actions[i].class,
-          iconUrl: actions[i].icon100
-        };
-        items.push(item);
-      }
-      var show = this.defaultTaskPicker.showOkCancelDialog(
-          str('CHANGE_DEFAULT_APP_BUTTON_LABEL'),
-          '',
-          items,
-          defaultIndex,
-          function(action) {
-            ActionChoiceUtil.setRememberedActionId(action.id);
-          });
-      if (!show)
-        console.error('DefaultTaskPicker can\'t be shown.');
-    }.bind(this);
-
-    ActionChoiceUtil.getDefinedActions(loadTimeData, function(actions) {
-      ActionChoiceUtil.getRememberedActionId(function(actionId) {
-        onActionsReady(actions, actionId);
-      });
-    });
-  };
-
-  FileManager.prototype.decorateSplitter = function(splitterElement) {
-    var self = this;
-
-    var Splitter = cr.ui.Splitter;
-
-    var customSplitter = cr.ui.define('div');
-
-    customSplitter.prototype = {
-      __proto__: Splitter.prototype,
-
-      handleSplitterDragStart: function(e) {
-        Splitter.prototype.handleSplitterDragStart.apply(this, arguments);
-        this.ownerDocument.documentElement.classList.add('col-resize');
-      },
-
-      handleSplitterDragMove: function(deltaX) {
-        Splitter.prototype.handleSplitterDragMove.apply(this, arguments);
-        self.onResize_();
-      },
-
-      handleSplitterDragEnd: function(e) {
-        Splitter.prototype.handleSplitterDragEnd.apply(this, arguments);
-        this.ownerDocument.documentElement.classList.remove('col-resize');
-      }
-    };
-
-    customSplitter.decorate(splitterElement);
-  };
-
-  /**
-   * Updates default action menu item to match passed taskItem (icon,
-   * label and action).
-   *
-   * @param {Object} defaultItem - taskItem to match.
-   * @param {boolean} isMultiple - if multiple tasks available.
-   */
-  FileManager.prototype.updateContextMenuActionItems = function(defaultItem,
-                                                                isMultiple) {
-    if (defaultItem) {
-      if (defaultItem.iconType) {
-        this.defaultActionMenuItem_.style.backgroundImage = '';
-        this.defaultActionMenuItem_.setAttribute('file-type-icon',
-                                                 defaultItem.iconType);
-      } else if (defaultItem.iconUrl) {
-        this.defaultActionMenuItem_.style.backgroundImage =
-            'url(' + defaultItem.iconUrl + ')';
-      } else {
-        this.defaultActionMenuItem_.style.backgroundImage = '';
-      }
-
-      this.defaultActionMenuItem_.label = defaultItem.title;
-      this.defaultActionMenuItem_.disabled = !!defaultItem.disabled;
-      this.defaultActionMenuItem_.taskId = defaultItem.taskId;
-    }
-
-    var defaultActionSeparator =
-        this.dialogDom_.querySelector('#default-action-separator');
-
-    this.openWithCommand_.canExecuteChange();
-    this.openWithCommand_.setHidden(!(defaultItem && isMultiple));
-    this.openWithCommand_.disabled = defaultItem && !!defaultItem.disabled;
-
-    this.defaultActionMenuItem_.hidden = !defaultItem;
-    defaultActionSeparator.hidden = !defaultItem;
-  };
-
-
-  /**
-   * Window beforeunload handler.
-   * @return {string} Message to show. Ignored when running as a packaged app.
-   * @private
-   */
-  FileManager.prototype.onBeforeUnload_ = function() {
-    if (this.filePopup_ &&
-        this.filePopup_.contentWindow &&
-        this.filePopup_.contentWindow.beforeunload) {
-      // The gallery might want to prevent the unload if it is busy.
-      return this.filePopup_.contentWindow.beforeunload();
-    }
-    return null;
-  };
-
-  /**
-   * @return {FileSelection} Selection object.
-   */
-  FileManager.prototype.getSelection = function() {
-    return this.selectionHandler_.selection;
-  };
-
-  /**
-   * @return {ArrayDataModel} File list.
-   */
-  FileManager.prototype.getFileList = function() {
-    return this.directoryModel_.getFileList();
-  };
-
-  /**
-   * @return {cr.ui.List} Current list object.
-   */
-  FileManager.prototype.getCurrentList = function() {
-    return this.currentList_;
-  };
-
-  /**
-   * Retrieve the preferences of the files.app. This method caches the result
-   * and returns it unless opt_update is true.
-   * @param {function(Object.<string, *>)} callback Callback to get the
-   *     preference.
-   * @param {boolean=} opt_update If is's true, don't use the cache and
-   *     retrieve latest preference. Default is false.
-   * @private
-   */
-  FileManager.prototype.getPreferences_ = function(callback, opt_update) {
-    if (!opt_update && this.preferences_ !== undefined) {
-      callback(this.preferences_);
-      return;
-    }
-
-    chrome.fileBrowserPrivate.getPreferences(function(prefs) {
-      this.preferences_ = prefs;
-      callback(prefs);
-    }.bind(this));
-  };
-})();
diff --git a/chrome/browser/resources/file_manager/js/file_manager_commands.js b/chrome/browser/resources/file_manager/js/file_manager_commands.js
deleted file mode 100644
index 3f8de8c..0000000
--- a/chrome/browser/resources/file_manager/js/file_manager_commands.js
+++ /dev/null
@@ -1,857 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * TODO(dzvorygin): Here we use this hack, since 'hidden' is standard
- * attribute and we can't use it's setter as usual.
- * @param {boolean} value New value of hidden property.
- */
-cr.ui.Command.prototype.setHidden = function(value) {
-  this.__lookupSetter__('hidden').call(this, value);
-};
-
-/**
- * A command.
- * @interface
- */
-var Command = function() {};
-
-/**
- * Handles the execute event.
- * @param {Event} event Command event.
- * @param {FileManager} fileManager FileManager.
- */
-Command.prototype.execute = function(event, fileManager) {};
-
-/**
- * Handles the can execute event.
- * @param {Event} event Can execute event.
- * @param {FileManager} fileManager FileManager.
- */
-Command.prototype.canExecute = function(event, fileManager) {};
-
-/**
- * Utility for commands.
- */
-var CommandUtil = {};
-
-/**
- * Extracts entry on which command event was dispatched.
- *
- * @param {DirectoryTree|DirectoryItem|NavigationList|HTMLLIElement|cr.ui.List}
- *     element Directory to extract a path from.
- * @return {Entry} Entry of the found node.
- */
-CommandUtil.getCommandEntry = function(element) {
-  if (element instanceof NavigationList) {
-    // element is a NavigationList.
-
-    /** @type {NavigationModelItem} */
-    var selectedItem = element.selectedItem;
-    return selectedItem && selectedItem.getCachedEntry();
-  } else if (element instanceof NavigationListItem) {
-    // element is a subitem of NavigationList.
-    /** @type {NavigationList} */
-    var navigationList = element.parentElement;
-    var index = navigationList.getIndexOfListItem(element);
-    /** @type {NavigationModelItem} */
-    var item = (index != -1) ? navigationList.dataModel.item(index) : null;
-    return item && item.getCachedEntry();
-  } else if (element instanceof DirectoryTree) {
-    // element is a DirectoryTree.
-    return element.selectedItem;
-  } else if (element instanceof DirectoryItem) {
-    // element is a sub item in DirectoryTree.
-
-    // DirectoryItem.fullPath is set on initialization, but entry is lazily.
-    // We may use fullPath just in case that the entry has not been set yet.
-    return element.entry;
-  } else if (element instanceof cr.ui.List) {
-    // element is a normal List (eg. the file list on the right panel).
-    var entry = element.selectedItem;
-    // Check if it is Entry or not by referring the fullPath member variable.
-    return entry && entry.fullPath ? entry : null;
-  } else {
-    console.warn('Unsupported element');
-    return null;
-  }
-};
-
-/**
- * @param {NavigationList} navigationList navigation list to extract root node.
- * @return {?RootType} Type of the found root.
- */
-CommandUtil.getCommandRootType = function(navigationList) {
-  var root = CommandUtil.getCommandEntry(navigationList);
-  return root &&
-         PathUtil.isRootPath(root.fullPath) &&
-         PathUtil.getRootType(root.fullPath);
-};
-
-/**
- * Checks if command can be executed on drive.
- * @param {Event} event Command event to mark.
- * @param {FileManager} fileManager FileManager to use.
- */
-CommandUtil.canExecuteEnabledOnDriveOnly = function(event, fileManager) {
-  event.canExecute = fileManager.isOnDrive();
-};
-
-/**
- * Checks if command should be visible on drive.
- * @param {Event} event Command event to mark.
- * @param {FileManager} fileManager FileManager to use.
- */
-CommandUtil.canExecuteVisibleOnDriveOnly = function(event, fileManager) {
-  event.canExecute = fileManager.isOnDrive();
-  event.command.setHidden(!fileManager.isOnDrive());
-};
-
-/**
- * Sets as the command as always enabled.
- * @param {Event} event Command event to mark.
- */
-CommandUtil.canExecuteAlways = function(event) {
-  event.canExecute = true;
-};
-
-/**
- * Returns a single selected/passed entry or null.
- * @param {Event} event Command event.
- * @param {FileManager} fileManager FileManager to use.
- * @return {FileEntry} The entry or null.
- */
-CommandUtil.getSingleEntry = function(event, fileManager) {
-  if (event.target.entry) {
-    return event.target.entry;
-  }
-  var selection = fileManager.getSelection();
-  if (selection.totalCount == 1) {
-    return selection.entries[0];
-  }
-  return null;
-};
-
-/**
- * Obtains target entries that can be pinned from the selection.
- * If directories are included in the selection, it just returns an empty
- * array to avoid confusing because pinning directory is not supported
- * currently.
- *
- * @return {Array.<Entry>} Target entries.
- */
-CommandUtil.getPinTargetEntries = function() {
-  var hasDirectory = false;
-  var results = fileManager.getSelection().entries.filter(function(entry) {
-    hasDirectory = hasDirectory || entry.isDirectory;
-    if (!entry || hasDirectory)
-      return false;
-    var metadata = fileManager.metadataCache_.getCached(entry, 'drive');
-    if (!metadata || metadata.hosted)
-      return false;
-    entry.pinned = metadata.pinned;
-    return true;
-  });
-  return hasDirectory ? [] : results;
-};
-
-/**
- * Sets the default handler for the commandId and prevents handling
- * the keydown events for this command. Not doing that breaks relationship
- * of original keyboard event and the command. WebKit would handle it
- * differently in some cases.
- * @param {Node} node to register command handler on.
- * @param {string} commandId Command id to respond to.
- */
-CommandUtil.forceDefaultHandler = function(node, commandId) {
-  var doc = node.ownerDocument;
-  var command = doc.querySelector('command[id="' + commandId + '"]');
-  node.addEventListener('keydown', function(e) {
-    if (command.matchesEvent(e)) {
-      // Prevent cr.ui.CommandManager of handling it and leave it
-      // for the default handler.
-      e.stopPropagation();
-    }
-  });
-  node.addEventListener('command', function(event) {
-    if (event.command.id !== commandId)
-      return;
-    document.execCommand(event.command.id);
-    event.cancelBubble = true;
-  });
-  node.addEventListener('canExecute', function(event) {
-    if (event.command.id === commandId)
-      event.canExecute = document.queryCommandEnabled(event.command.id);
-  });
-};
-
-/**
- * Default command.
- * @type {Command}
- */
-CommandUtil.defaultCommand = {
-  execute: function(event, fileManager) {
-    fileManager.document.execCommand(event.command.id);
-  },
-  canExecute: function(event, fileManager) {
-    event.canExecute = fileManager.document.queryCommandEnabled(
-        event.command.id);
-  }
-};
-
-/**
- * Creates the volume switch command with index.
- * @param {number} index Volume index from 1 to 9.
- * @return {Command} Volume switch command.
- */
-CommandUtil.createVolumeSwitchCommand = function(index) {
-  return {
-    execute: function(event, fileManager) {
-      fileManager.navigationList.selectByIndex(index - 1);
-    },
-    canExecute: function(event, fileManager) {
-      event.canExecute = index > 0 &&
-          index <= fileManager.navigationList.dataModel.length;
-    }
-  };
-};
-
-/**
- * Handle of the command events.
- * @param {FileManager} fileManager FileManager.
- * @constructor
- */
-var CommandHandler = function(fileManager) {
-  /**
-   * FileManager.
-   * @type {FileManager}
-   * @private
-   */
-  this.fileManager_ = fileManager;
-
-  /**
-   * Command elements.
-   * @type {Object.<string, cr.ui.Command>}
-   * @private
-   */
-  this.commands_ = {};
-
-  /**
-   * Whether the ctrl key is pressed or not.
-   * @type {boolean}
-   * @private
-   */
-  this.ctrlKeyPressed_ = false;
-
-  Object.seal(this);
-
-  // Decorate command tags in the document.
-  var commands = fileManager.document.querySelectorAll('command');
-  for (var i = 0; i < commands.length; i++) {
-    cr.ui.Command.decorate(commands[i]);
-    this.commands_[commands[i].id] = commands[i];
-  }
-
-  // Register events.
-  fileManager.document.addEventListener('command', this.onCommand_.bind(this));
-  fileManager.document.addEventListener('canExecute',
-                                        this.onCanExecute_.bind(this));
-  fileManager.document.addEventListener('keydown', this.onKeyDown_.bind(this));
-  fileManager.document.addEventListener('keyup', this.onKeyUp_.bind(this));
-};
-
-/**
- * Updates the availability of all commands.
- */
-CommandHandler.prototype.updateAvailability = function() {
-  for (var id in this.commands_) {
-    this.commands_[id].canExecuteChange();
-  }
-};
-
-/**
- * Handles command events.
- * @param {Event} event Command event.
- * @private
- */
-CommandHandler.prototype.onCommand_ = function(event) {
-  var handler = CommandHandler.COMMANDS_[event.command.id];
-  handler.execute.call(this, event, this.fileManager_);
-};
-
-/**
- * Handles canExecute events.
- * @param {Event} event Can execute event.
- * @private
- */
-CommandHandler.prototype.onCanExecute_ = function(event) {
-  var handler = CommandHandler.COMMANDS_[event.command.id];
-  handler.canExecute.call(this, event, this.fileManager_);
-};
-
-/**
- * Handle key down event.
- * @param {Event} event Key down event.
- * @private
- */
-CommandHandler.prototype.onKeyDown_ = function(event) {
-  // 17 is the keycode of Ctrl key and it means the event is not for other keys
-  // with Ctrl modifier but for ctrl key itself.
-  if (util.getKeyModifiers(event) + event.keyCode == 'Ctrl-17') {
-    this.ctrlKeyPressed_ = true;
-    this.updateAvailability();
-  }
-};
-
-/**
- * Handle key up event.
- * @param {Event} event Key up event.
- * @private
- */
-CommandHandler.prototype.onKeyUp_ = function(event) {
-  // 17 is the keycode of Ctrl key and it means the event is not for other keys
-  // with Ctrl modifier but for ctrl key itself.
-  if (util.getKeyModifiers(event) + event.keyCode == '17') {
-    this.ctrlKeyPressed_ = false;
-    this.updateAvailability();
-  }
-};
-
-/**
- * Commands.
- * @type {Object.<string, Command>}
- * @const
- * @private
- */
-CommandHandler.COMMANDS_ = {};
-
-/**
- * Unmounts external drive.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['unmount'] = {
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  execute: function(event, fileManager) {
-    var root = CommandUtil.getCommandEntry(event.target);
-    if (root)
-      fileManager.unmountVolume(PathUtil.getRootPath(root.fullPath));
-  },
-  /**
-   * @param {Event} event Command event.
-   */
-  canExecute: function(event, fileManager) {
-    var rootType = CommandUtil.getCommandRootType(event.target);
-
-    event.canExecute = (rootType == RootType.ARCHIVE ||
-                        rootType == RootType.REMOVABLE);
-    event.command.setHidden(!event.canExecute);
-    event.command.label = rootType == RootType.ARCHIVE ?
-        str('CLOSE_ARCHIVE_BUTTON_LABEL') :
-        str('UNMOUNT_DEVICE_BUTTON_LABEL');
-  }
-};
-
-/**
- * Formats external drive.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['format'] = {
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  execute: function(event, fileManager) {
-    var root = CommandUtil.getCommandEntry(event.target);
-
-    if (root) {
-      var url = util.makeFilesystemUrl(PathUtil.getRootPath(root.fullPath));
-      fileManager.confirm.show(
-          loadTimeData.getString('FORMATTING_WARNING'),
-          chrome.fileBrowserPrivate.formatDevice.bind(null, url));
-    }
-  },
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  canExecute: function(event, fileManager) {
-    var directoryModel = fileManager.directoryModel;
-    var root = CommandUtil.getCommandEntry(event.target);
-    var removable = root &&
-                    PathUtil.getRootType(root.fullPath) == RootType.REMOVABLE;
-    var isReadOnly = root && directoryModel.isPathReadOnly(root.fullPath);
-    event.canExecute = removable && !isReadOnly;
-    event.command.setHidden(!removable);
-  }
-};
-
-/**
- * Imports photos from external drive.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['import-photos'] = {
-  /**
-   * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
-   */
-  execute: function(event, fileManager) {
-    var navigationList = fileManager.navigationList;
-    var root = CommandUtil.getCommandEntry(navigationList);
-    if (!root)
-      return;
-
-    // TODO(mtomasz): Implement launching Photo Importer.
-  },
-  /**
-   * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
-   */
-  canExecute: function(event, fileManager) {
-    var navigationList = fileManager.navigationList;
-    var rootType = CommandUtil.getCommandRootType(navigationList);
-    event.canExecute = (rootType != RootType.DRIVE);
-  }
-};
-
-/**
- * Initiates new folder creation.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['new-folder'] = {
-  execute: function(event, fileManager) {
-    fileManager.createNewFolder();
-  },
-  canExecute: function(event, fileManager) {
-    var directoryModel = fileManager.directoryModel;
-    event.canExecute = !fileManager.isOnReadonlyDirectory() &&
-                       !fileManager.isRenamingInProgress() &&
-                       !directoryModel.isSearching() &&
-                       !directoryModel.isScanning();
-  }
-};
-
-/**
- * Initiates new window creation.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['new-window'] = {
-  execute: function(event, fileManager) {
-    fileManager.backgroundPage.launchFileManager({
-      defaultPath: fileManager.getCurrentDirectory()
-    });
-  },
-  canExecute: function(event, fileManager) {
-    event.canExecute =
-        fileManager.getCurrentDirectoryEntry() &&
-        (fileManager.dialogType === DialogType.FULL_PAGE);
-  }
-};
-
-/**
- * Changed the default app handling inserted media.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['change-default-app'] = {
-  execute: function(event, fileManager) {
-    fileManager.showChangeDefaultAppPicker();
-  },
-  canExecute: CommandUtil.canExecuteAlways
-};
-
-/**
- * Deletes selected files.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['delete'] = {
-  execute: function(event, fileManager) {
-    fileManager.deleteSelection();
-  },
-  canExecute: function(event, fileManager) {
-    var selection = fileManager.getSelection();
-    event.canExecute = !fileManager.isOnReadonlyDirectory() &&
-                       selection &&
-                       selection.totalCount > 0;
-  }
-};
-
-/**
- * Pastes files from clipboard.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['paste'] = {
-  execute: function() {
-    document.execCommand(event.command.id);
-  },
-  canExecute: function(event, fileManager) {
-    var document = fileManager.document;
-    var fileTransferController = fileManager.fileTransferController;
-    event.canExecute = (fileTransferController &&
-        fileTransferController.queryPasteCommandEnabled());
-  }
-};
-
-CommandHandler.COMMANDS_['cut'] = CommandUtil.defaultCommand;
-CommandHandler.COMMANDS_['copy'] = CommandUtil.defaultCommand;
-
-/**
- * Initiates file renaming.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['rename'] = {
-  execute: function(event, fileManager) {
-    fileManager.initiateRename();
-  },
-  canExecute: function(event, fileManager) {
-    var selection = fileManager.getSelection();
-    event.canExecute =
-        !fileManager.isRenamingInProgress() &&
-        !fileManager.isOnReadonlyDirectory() &&
-        selection &&
-        selection.totalCount == 1;
-  }
-};
-
-/**
- * Opens drive help.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['volume-help'] = {
-  execute: function(event, fileManager) {
-    if (fileManager.isOnDrive())
-      util.visitURL(urlConstants.GOOGLE_DRIVE_HELP);
-    else
-      util.visitURL(urlConstants.FILES_APP_HELP);
-  },
-  canExecute: CommandUtil.canExecuteAlways
-};
-
-/**
- * Opens drive buy-more-space url.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['drive-buy-more-space'] = {
-  execute: function(event, fileManager) {
-    util.visitURL(urlConstants.GOOGLE_DRIVE_BUY_STORAGE);
-  },
-  canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
-};
-
-/**
- * Clears drive cache.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['drive-clear-local-cache'] = {
-  execute: function(event, fileManager) {
-    chrome.fileBrowserPrivate.clearDriveCache();
-  },
-  canExecute: function(event, fileManager) {
-    event.canExecute = fileManager.isOnDrive() && this.ctrlKeyPressed_;
-    event.command.setHidden(!event.canExecute);
-  }
-};
-
-/**
- * Opens drive.google.com.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['drive-go-to-drive'] = {
-  execute: function(event, fileManager) {
-    util.visitURL(urlConstants.GOOGLE_DRIVE_ROOT);
-  },
-  canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
-};
-
-/**
- * Displays open with dialog for current selection.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['open-with'] = {
-  execute: function(event, fileManager) {
-    var tasks = fileManager.getSelection().tasks;
-    if (tasks) {
-      tasks.showTaskPicker(fileManager.defaultTaskPicker,
-          str('OPEN_WITH_BUTTON_LABEL'),
-          null,
-          function(task) {
-            tasks.execute(task.taskId);
-          });
-    }
-  },
-  canExecute: function(event, fileManager) {
-    var tasks = fileManager.getSelection().tasks;
-    event.canExecute = tasks && tasks.size() > 1;
-  }
-};
-
-/**
- * Focuses search input box.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['search'] = {
-  execute: function(event, fileManager) {
-    var element = fileManager.document.querySelector('#search-box input');
-    element.focus();
-    element.select();
-  },
-  canExecute: function(event, fileManager) {
-    event.canExecute = !fileManager.isRenamingInProgress();
-  }
-};
-
-/**
- * Activates the n-th volume.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['volume-switch-1'] =
-    CommandUtil.createVolumeSwitchCommand(1);
-CommandHandler.COMMANDS_['volume-switch-2'] =
-    CommandUtil.createVolumeSwitchCommand(2);
-CommandHandler.COMMANDS_['volume-switch-3'] =
-    CommandUtil.createVolumeSwitchCommand(3);
-CommandHandler.COMMANDS_['volume-switch-4'] =
-    CommandUtil.createVolumeSwitchCommand(4);
-CommandHandler.COMMANDS_['volume-switch-5'] =
-    CommandUtil.createVolumeSwitchCommand(5);
-CommandHandler.COMMANDS_['volume-switch-6'] =
-    CommandUtil.createVolumeSwitchCommand(6);
-CommandHandler.COMMANDS_['volume-switch-7'] =
-    CommandUtil.createVolumeSwitchCommand(7);
-CommandHandler.COMMANDS_['volume-switch-8'] =
-    CommandUtil.createVolumeSwitchCommand(8);
-CommandHandler.COMMANDS_['volume-switch-9'] =
-    CommandUtil.createVolumeSwitchCommand(9);
-
-/**
- * Flips 'available offline' flag on the file.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['toggle-pinned'] = {
-  execute: function(event, fileManager) {
-    var pin = !event.command.checked;
-    event.command.checked = pin;
-    var entries = CommandUtil.getPinTargetEntries();
-    var currentEntry;
-    var error = false;
-    var steps = {
-      // Pick an entry and pin it.
-      start: function() {
-        // Check if all the entries are pinned or not.
-        if (entries.length == 0)
-          return;
-        currentEntry = entries.shift();
-        chrome.fileBrowserPrivate.pinDriveFile(
-            currentEntry.toURL(),
-            pin,
-            steps.entryPinned);
-      },
-
-      // Check the result of pinning
-      entryPinned: function() {
-        // Convert to boolean.
-        error = !!chrome.runtime.lastError;
-        if (error && pin) {
-          fileManager.metadataCache_.get(
-              currentEntry, 'filesystem', steps.showError);
-        }
-        fileManager.metadataCache_.clear(currentEntry, 'drive');
-        fileManager.metadataCache_.get(
-            currentEntry, 'drive', steps.updateUI.bind(this));
-      },
-
-      // Update the user interface accoding to the cache state.
-      updateUI: function(drive) {
-        fileManager.updateMetadataInUI_(
-            'drive', [currentEntry.toURL()], [drive]);
-        if (!error)
-          steps.start();
-      },
-
-      // Show the error
-      showError: function(filesystem) {
-        fileManager.alert.showHtml(str('DRIVE_OUT_OF_SPACE_HEADER'),
-                                   strf('DRIVE_OUT_OF_SPACE_MESSAGE',
-                                        unescape(currentEntry.name),
-                                        util.bytesToString(filesystem.size)));
-      }
-    };
-    steps.start();
-  },
-
-  canExecute: function(event, fileManager) {
-    var entries = CommandUtil.getPinTargetEntries();
-    var checked = true;
-    for (var i = 0; i < entries.length; i++) {
-      checked = checked && entries[i].pinned;
-    }
-    if (entries.length > 0) {
-      event.canExecute = true;
-      event.command.setHidden(false);
-      event.command.checked = checked;
-    } else {
-      event.canExecute = false;
-      event.command.setHidden(true);
-    }
-  }
-};
-
-/**
- * Creates zip file for current selection.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['zip-selection'] = {
-  execute: function(event, fileManager) {
-    var dirEntry = fileManager.getCurrentDirectoryEntry();
-    var selectionEntries = fileManager.getSelection().entries;
-    fileManager.fileOperationManager_.zipSelection(dirEntry, selectionEntries);
-  },
-  canExecute: function(event, fileManager) {
-    var dirEntry = fileManager.getCurrentDirectoryEntry();
-    var selection = fileManager.getSelection();
-    event.canExecute =
-        dirEntry &&
-        !fileManager.isOnReadonlyDirectory() &&
-        !fileManager.isOnDrive() &&
-        selection && selection.totalCount > 0;
-  }
-};
-
-/**
- * Shows the share dialog for the current selection (single only).
- * @type {Command}
- */
-CommandHandler.COMMANDS_['share'] = {
-  execute: function(event, fileManager) {
-    fileManager.shareSelection();
-  },
-  canExecute: function(event, fileManager) {
-    var selection = fileManager.getSelection();
-    event.canExecute = fileManager.isOnDrive() &&
-        !fileManager.isDriveOffline() &&
-        selection && selection.totalCount == 1;
-    event.command.setHidden(!fileManager.isOnDrive());
-  }
-};
-
-/**
- * Creates a shortcut of the selected folder (single only).
- * @type {Command}
- */
-CommandHandler.COMMANDS_['create-folder-shortcut'] = {
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  execute: function(event, fileManager) {
-    var entry = CommandUtil.getCommandEntry(event.target);
-    if (entry)
-      fileManager.createFolderShortcut(entry.fullPath);
-  },
-
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  canExecute: function(event, fileManager) {
-    var target = event.target;
-    if (!(target instanceof NavigationListItem) &&
-        !(target instanceof DirectoryItem)) {
-      event.command.setHidden(true);
-      return;
-    }
-
-    var entry = CommandUtil.getCommandEntry(event.target);
-    var folderShortcutExists = entry &&
-                               fileManager.folderShortcutExists(entry.fullPath);
-
-    var onlyOneFolderSelected = true;
-    // Only on list, user can select multiple files. The command is enabled only
-    // when a single file is selected.
-    if (event.target instanceof cr.ui.List &&
-        !(event.target instanceof NavigationList)) {
-      var items = event.target.selectedItems;
-      onlyOneFolderSelected = (items.length == 1 && items[0].isDirectory);
-    }
-
-    var eligible = entry &&
-                   PathUtil.isEligibleForFolderShortcut(entry.fullPath);
-    event.canExecute =
-        eligible && onlyOneFolderSelected && !folderShortcutExists;
-    event.command.setHidden(!eligible || !onlyOneFolderSelected);
-  }
-};
-
-/**
- * Removes the folder shortcut.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['remove-folder-shortcut'] = {
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  execute: function(event, fileManager) {
-    var entry = CommandUtil.getCommandEntry(event.target);
-    if (entry && entry.fullPath)
-      fileManager.removeFolderShortcut(entry.fullPath);
-  },
-
-  /**
-   * @param {Event} event Command event.
-   * @param {FileManager} fileManager The file manager instance.
-   */
-  canExecute: function(event, fileManager) {
-    var target = event.target;
-    if (!target instanceof NavigationListItem &&
-        !target instanceof DirectoryItem) {
-      event.command.setHidden(true);
-      return;
-    }
-
-    var entry = CommandUtil.getCommandEntry(target);
-    var path = entry && entry.fullPath;
-
-    var eligible = path && PathUtil.isEligibleForFolderShortcut(path);
-    var isShortcut = path && fileManager.folderShortcutExists(path);
-    event.canExecute = isShortcut && eligible;
-    event.command.setHidden(!event.canExecute);
-  }
-};
-
-/**
- * Zoom in to the Files.app.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['zoom-in'] = {
-  execute: function(event, fileManager) {
-    chrome.fileBrowserPrivate.zoom('in');
-  },
-  canExecute: CommandUtil.canExecuteAlways
-};
-
-/**
- * Zoom out from the Files.app.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['zoom-out'] = {
-  execute: function(event, fileManager) {
-    chrome.fileBrowserPrivate.zoom('out');
-  },
-  canExecute: CommandUtil.canExecuteAlways
-};
-
-/**
- * Reset the zoom factor.
- * @type {Command}
- */
-CommandHandler.COMMANDS_['zoom-reset'] = {
-  execute: function(event, fileManager) {
-    chrome.fileBrowserPrivate.zoom('reset');
-  },
-  canExecute: CommandUtil.canExecuteAlways
-};
diff --git a/chrome/browser/resources/file_manager/js/file_operation_manager.js b/chrome/browser/resources/file_manager/js/file_operation_manager.js
deleted file mode 100644
index 3f17f51..0000000
--- a/chrome/browser/resources/file_manager/js/file_operation_manager.js
+++ /dev/null
@@ -1,1482 +0,0 @@
-// Copyright 2013 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.
-
-'use strict';
-
-/**
- * Utilities for FileOperationManager.
- */
-var fileOperationUtil = {};
-
-/**
- * Simple wrapper for util.deduplicatePath. On error, this method translates
- * the FileError to FileOperationManager.Error object.
- *
- * @param {DirectoryEntry} dirEntry The target directory entry.
- * @param {string} relativePath The path to be deduplicated.
- * @param {function(string)} successCallback Callback run with the deduplicated
- *     path on success.
- * @param {function(FileOperationManager.Error)} errorCallback Callback run on
- *     error.
- */
-fileOperationUtil.deduplicatePath = function(
-    dirEntry, relativePath, successCallback, errorCallback) {
-  util.deduplicatePath(
-      dirEntry, relativePath, successCallback,
-      function(err) {
-        var onFileSystemError = function(error) {
-          errorCallback(new FileOperationManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-        };
-
-        if (err.code == FileError.PATH_EXISTS_ERR) {
-          // Failed to uniquify the file path. There should be an existing
-          // entry, so return the error with it.
-          util.resolvePath(
-              dirEntry, relativePath,
-              function(entry) {
-                errorCallback(new FileOperationManager.Error(
-                    util.FileOperationErrorType.TARGET_EXISTS, entry));
-              },
-              onFileSystemError);
-          return;
-        }
-        onFileSystemError(err);
-      });
-};
-
-/**
- * Traverses files/subdirectories of the given entry, and returns them.
- * In addition, this method annotate the size of each entry. The result will
- * include the entry itself.
- *
- * @param {Entry} entry The root Entry for traversing.
- * @param {function(Array.<Entry>)} successCallback Called when the traverse
- *     is successfully done with the array of the entries.
- * @param {function(FileError)} errorCallback Called on error with the first
- *     occurred error (i.e. following errors will just be discarded).
- */
-fileOperationUtil.resolveRecursively = function(
-    entry, successCallback, errorCallback) {
-  var result = [];
-  var error = null;
-  var numRunningTasks = 0;
-
-  var maybeInvokeCallback = function() {
-    // If there still remain some running tasks, wait their finishing.
-    if (numRunningTasks > 0)
-      return;
-
-    if (error)
-      errorCallback(error);
-    else
-      successCallback(result);
-  };
-
-  // The error handling can be shared.
-  var onError = function(fileError) {
-    // If this is the first error, remember it.
-    if (!error)
-      error = fileError;
-    --numRunningTasks;
-    maybeInvokeCallback();
-  };
-
-  var process = function(entry) {
-    numRunningTasks++;
-    result.push(entry);
-    if (entry.isDirectory) {
-      // The size of a directory is 1 bytes here, so that the progress bar
-      // will work smoother.
-      // TODO(hidehiko): Remove this hack.
-      entry.size = 1;
-
-      // Recursively traverse children.
-      var reader = entry.createReader();
-      reader.readEntries(
-          function processSubEntries(subEntries) {
-            if (error || subEntries.length == 0) {
-              // If an error is found already, or this is the completion
-              // callback, then finish the process.
-              --numRunningTasks;
-              maybeInvokeCallback();
-              return;
-            }
-
-            for (var i = 0; i < subEntries.length; i++)
-              process(subEntries[i]);
-
-            // Continue to read remaining children.
-            reader.readEntries(processSubEntries, onError);
-          },
-          onError);
-    } else {
-      // For a file, annotate the file size.
-      entry.getMetadata(function(metadata) {
-        entry.size = metadata.size;
-        --numRunningTasks;
-        maybeInvokeCallback();
-      }, onError);
-    }
-  };
-
-  process(entry);
-};
-
-/**
- * Copies source to parent with the name newName recursively.
- * This should work very similar to FileSystem API's copyTo. The difference is;
- * - The progress callback is supported.
- * - The cancellation is supported.
- *
- * @param {Entry} source The entry to be copied.
- * @param {DirectoryEntry} parent The entry of the destination directory.
- * @param {string} newName The name of copied file.
- * @param {function(string, string)} entryChangedCallback
- *     Callback invoked when an entry is created with the source url and
- *     the destination url.
- * @param {function(string, number)} progressCallback Callback invoked
- *     periodically during the copying. It takes the source url and the
- *     processed bytes of it.
- * @param {function(string)} successCallback Callback invoked when the copy
- *     is successfully done with the url of the created entry.
- * @param {function(FileError)} errorCallback Callback invoked when an error
- *     is found.
- * @return {function()} Callback to cancel the current file copy operation.
- *     When the cancel is done, errorCallback will be called. The returned
- *     callback must not be called more than once.
- */
-fileOperationUtil.copyTo = function(
-    source, parent, newName, entryChangedCallback, progressCallback,
-    successCallback, errorCallback) {
-  var copyId = null;
-  var pendingCallbacks = [];
-
-  var onCopyProgress = function(progressCopyId, status) {
-    if (copyId == null) {
-      // If the copyId is not yet available, wait for it.
-      pendingCallbacks.push(
-          onCopyProgress.bind(null, progressCopyId, status));
-      return;
-    }
-
-    // This is not what we're interested in.
-    if (progressCopyId != copyId)
-      return;
-
-    switch (status.type) {
-      case 'begin_copy_entry':
-        break;
-
-      case 'end_copy_entry':
-        entryChangedCallback(status.sourceUrl, status.destinationUrl);
-        break;
-
-      case 'progress':
-        progressCallback(status.sourceUrl, status.size);
-        break;
-
-      case 'success':
-        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
-        successCallback(status.destinationUrl);
-        break;
-
-      case 'error':
-        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
-        errorCallback(util.createFileError(status.error));
-        break;
-
-      default:
-        // Found unknown state. Cancel the task, and return an error.
-        console.error('Unknown progress type: ' + status.type);
-        chrome.fileBrowserPrivate.onCopyProgress.removeListener(onCopyProgress);
-        chrome.fileBrowserPrivate.cancelCopy(copyId);
-        errorCallback(util.createFileError(FileError.INVALID_STATE_ERR));
-    }
-  };
-
-  // Register the listener before calling startCopy. Otherwise some events
-  // would be lost.
-  chrome.fileBrowserPrivate.onCopyProgress.addListener(onCopyProgress);
-
-  // Then starts the copy.
-  chrome.fileBrowserPrivate.startCopy(
-      source.toURL(), parent.toURL(), newName, function(startCopyId) {
-        // last error contains the FileError code on error.
-        if (chrome.runtime.lastError) {
-          // Unsubscribe the progress listener.
-          chrome.fileBrowserPrivate.onCopyProgress.removeListener(
-              onCopyProgress);
-          errorCallback(util.createFileError(
-              Integer.parseInt(chrome.runtime.lastError, 10)));
-          return;
-        }
-
-        copyId = startCopyId;
-        for (var i = 0; i < pendingCallbacks.length; i++) {
-          pendingCallbacks[i]();
-        }
-      });
-
-  return function() {
-    // If copyId is not yet available, wait for it.
-    if (copyId == null) {
-      pendingCallbacks.push(function() {
-        chrome.fileBrowserPrivate.cancelCopy(copyId);
-      });
-      return;
-    }
-
-    chrome.fileBrowserPrivate.cancelCopy(copyId);
-  };
-};
-
-/**
- * Thin wrapper of chrome.fileBrowserPrivate.zipSelection to adapt its
- * interface similar to copyTo().
- *
- * @param {Array.<Entry>} sources The array of entries to be archived.
- * @param {DirectoryEntry} parent The entry of the destination directory.
- * @param {string} newName The name of the archive to be created.
- * @param {function(FileEntry)} successCallback Callback invoked when the
- *     operation is successfully done with the entry of the created archive.
- * @param {function(FileError)} errorCallback Callback invoked when an error
- *     is found.
- */
-fileOperationUtil.zipSelection = function(
-    sources, parent, newName, successCallback, errorCallback) {
-  chrome.fileBrowserPrivate.zipSelection(
-      parent.toURL(),
-      sources.map(function(e) { return e.toURL(); }),
-      newName, function(success) {
-        if (!success) {
-          // Failed to create a zip archive.
-          errorCallback(
-              util.createFileError(FileError.INVALID_MODIFICATION_ERR));
-          return;
-        }
-
-        // Returns the created entry via callback.
-        parent.getFile(
-            newName, {create: false}, successCallback, errorCallback);
-      });
-};
-
-/**
- * @constructor
- */
-function FileOperationManager() {
-  this.copyTasks_ = [];
-  this.deleteTasks_ = [];
-  this.cancelObservers_ = [];
-  this.cancelRequested_ = false;
-  this.cancelCallback_ = null;
-  this.unloadTimeout_ = null;
-
-  this.eventRouter_ = new FileOperationManager.EventRouter();
-
-  Object.seal(this);
-}
-
-/**
- * Get FileOperationManager instance. In case is hasn't been initialized, a new
- * instance is created.
- *
- * @return {FileOperationManager} A FileOperationManager instance.
- */
-FileOperationManager.getInstance = function() {
-  if (!FileOperationManager.instance_)
-    FileOperationManager.instance_ = new FileOperationManager();
-
-  return FileOperationManager.instance_;
-};
-
-/**
- * Manages Event dispatching.
- * Currently this can send three types of events: "copy-progress",
- * "copy-operation-completed" and "delete".
- *
- * TODO(hidehiko): Reorganize the event dispatching mechanism.
- * @constructor
- * @extends {cr.EventTarget}
- */
-FileOperationManager.EventRouter = function() {
-};
-
-/**
- * Extends cr.EventTarget.
- */
-FileOperationManager.EventRouter.prototype.__proto__ = cr.EventTarget.prototype;
-
-/**
- * Dispatches a simple "copy-progress" event with reason and current
- * FileOperationManager status. If it is an ERROR event, error should be set.
- *
- * @param {string} reason Event type. One of "BEGIN", "PROGRESS", "SUCCESS",
- *     "ERROR" or "CANCELLED". TODO(hidehiko): Use enum.
- * @param {Object} status Current FileOperationManager's status. See also
- *     FileOperationManager.getStatus().
- * @param {string} taskId ID of task related with the event.
- * @param {FileOperationManager.Error=} opt_error The info for the error. This
- *     should be set iff the reason is "ERROR".
- */
-FileOperationManager.EventRouter.prototype.sendProgressEvent = function(
-    reason, status, taskId, opt_error) {
-  var event = new Event('copy-progress');
-  event.reason = reason;
-  event.status = status;
-  event.taskId = taskId;
-  if (opt_error)
-    event.error = opt_error;
-  this.dispatchEvent(event);
-};
-
-/**
- * Dispatches an event to notify that an entry is changed (created or deleted).
- * @param {util.EntryChangedKind} kind The enum to represent if the entry is
- *     created or deleted.
- * @param {Entry} entry The changed entry.
- */
-FileOperationManager.EventRouter.prototype.sendEntryChangedEvent = function(
-    kind, entry) {
-  var event = new Event('entry-changed');
-  event.kind = kind;
-  event.entry = entry;
-  this.dispatchEvent(event);
-};
-
-/**
- * Dispatches an event to notify entries are changed for delete task.
- *
- * @param {string} reason Event type. One of "BEGIN", "PROGRESS", "SUCCESS",
- *     or "ERROR". TODO(hidehiko): Use enum.
- * @param {Array.<string>} urls An array of URLs which are affected by delete
- *     operation.
- * @param {string} taskId ID of task related with the event.
- */
-FileOperationManager.EventRouter.prototype.sendDeleteEvent = function(
-    reason, urls, taskId) {
-  var event = new Event('delete');
-  event.reason = reason;
-  event.urls = urls;
-  this.dispatchEvent(event);
-};
-
-/**
- * A record of a queued copy operation.
- *
- * Multiple copy operations may be queued at any given time.  Additional
- * Tasks may be added while the queue is being serviced.  Though a
- * cancel operation cancels everything in the queue.
- *
- * @param {util.FileOperationType} operationType The type of this operation.
- * @param {Array.<Entry>} sourceEntries Array of source entries.
- * @param {DirectoryEntry} targetDirEntry Target directory.
- * @constructor
- */
-FileOperationManager.Task = function(
-    operationType, sourceEntries, targetDirEntry) {
-  this.operationType = operationType;
-  this.sourceEntries = sourceEntries;
-  this.targetDirEntry = targetDirEntry;
-
-  /**
-   * An array of map from url to Entry being processed.
-   * @type {Array.<Object<string, Entry>>}
-   */
-  this.processingEntries = null;
-
-  /**
-   * Total number of bytes to be processed. Filled in initialize().
-   * @type {number}
-   */
-  this.totalBytes = 0;
-
-  /**
-   * Total number of already processed bytes. Updated periodically.
-   * @type {number}
-   */
-  this.processedBytes = 0;
-
-  this.deleteAfterCopy = false;
-
-  /**
-   * Set to true when cancel is requested.
-   * @private {boolean}
-   */
-  this.cancelRequested_ = false;
-
-  /**
-   * Callback to cancel the running process.
-   * @private {function()}
-   */
-  this.cancelCallback_ = null;
-
-  // TODO(hidehiko): After we support recursive copy, we don't need this.
-  // If directory already exists, we try to make a copy named 'dir (X)',
-  // where X is a number. When we do this, all subsequent copies from
-  // inside the subtree should be mapped to the new directory name.
-  // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should
-  // become 'dir (1)\file.txt'.
-  this.renamedDirectories_ = [];
-};
-
-/**
- * @param {function()} callback When entries resolved.
- */
-FileOperationManager.Task.prototype.initialize = function(callback) {
-};
-
-/**
- * Updates copy progress status for the entry.
- *
- * @param {number} size Number of bytes that has been copied since last update.
- */
-FileOperationManager.Task.prototype.updateFileCopyProgress = function(size) {
-  this.completedBytes += size;
-};
-
-/**
- * Requests cancellation of this task.
- * When the cancellation is done, it is notified via callbacks of run().
- */
-FileOperationManager.Task.prototype.requestCancel = function() {
-  this.cancelRequested_ = true;
-  if (this.cancelCallback_) {
-    this.cancelCallback_();
-    this.cancelCallback_ = null;
-  }
-};
-
-/**
- * Runs the task. Sub classes must implement this method.
- *
- * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
- *     Callback invoked when an entry is changed.
- * @param {function()} progressCallback Callback invoked periodically during
- *     the operation.
- * @param {function()} successCallback Callback run on success.
- * @param {function(FileOperationManager.Error)} errorCallback Callback run on
- *     error.
- */
-FileOperationManager.Task.prototype.run = function(
-    entryChangedCallback, progressCallback, successCallback, errorCallback) {
-};
-
-/**
- * Task to copy entries.
- *
- * @param {Array.<Entry>} sourceEntries Array of source entries.
- * @param {DirectoryEntry} targetDirEntry Target directory.
- * @constructor
- * @extends {FileOperationManager.Task}
- */
-FileOperationManager.CopyTask = function(sourceEntries, targetDirEntry) {
-  FileOperationManager.Task.call(
-      this, util.FileOperationType.COPY, sourceEntries, targetDirEntry);
-};
-
-/**
- * Extends FileOperationManager.Task.
- */
-FileOperationManager.CopyTask.prototype.__proto__ =
-    FileOperationManager.Task.prototype;
-
-/**
- * Initializes the CopyTask.
- * @param {function()} callback Called when the initialize is completed.
- */
-FileOperationManager.CopyTask.prototype.initialize = function(callback) {
-  var group = new AsyncUtil.Group();
-  // Correct all entries to be copied for status update.
-  this.processingEntries = [];
-  for (var i = 0; i < this.sourceEntries.length; i++) {
-    group.add(function(index, callback) {
-      fileOperationUtil.resolveRecursively(
-          this.sourceEntries[index],
-          function(resolvedEntries) {
-            var resolvedEntryMap = {};
-            for (var j = 0; j < resolvedEntries.length; ++j) {
-              var entry = resolvedEntries[j];
-              entry.processedBytes = 0;
-              resolvedEntryMap[entry.toURL()] = entry;
-            }
-            this.processingEntries[index] = resolvedEntryMap;
-            callback();
-          }.bind(this),
-          function(error) {
-            console.error(
-                'Failed to resolve for copy: %s',
-                util.getFileErrorMnemonic(error.code));
-          });
-    }.bind(this, i));
-  }
-
-  group.run(function() {
-    // Fill totalBytes.
-    this.totalBytes = 0;
-    for (var i = 0; i < this.processingEntries.length; i++) {
-      for (var url in this.processingEntries[i])
-        this.totalBytes += this.processingEntries[i][url].size;
-    }
-
-    callback();
-  }.bind(this));
-};
-
-/**
- * Copies all entries to the target directory.
- * Note: this method contains also the operation of "Move" due to historical
- * reason.
- *
- * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
- *     Callback invoked when an entry is changed.
- * @param {function()} progressCallback Callback invoked periodically during
- *     the copying.
- * @param {function()} successCallback On success.
- * @param {function(FileOperationManager.Error)} errorCallback On error.
- * @override
- */
-FileOperationManager.CopyTask.prototype.run = function(
-    entryChangedCallback, progressCallback, successCallback, errorCallback) {
-  // TODO(hidehiko): We should be able to share the code to iterate on entries
-  // with serviceMoveTask_().
-  if (this.sourceEntries.length == 0) {
-    successCallback();
-    return;
-  }
-
-  // TODO(hidehiko): Delete after copy is the implementation of Move.
-  // Migrate the part into MoveTask.run().
-  var deleteOriginals = function() {
-    var count = this.sourceEntries.length;
-
-    var onEntryDeleted = function(entry) {
-      entryChangedCallback(util.EntryChangedKind.DELETED, entry);
-      count--;
-      if (!count)
-        successCallback();
-    };
-
-    var onFilesystemError = function(err) {
-      errorCallback(new FileOperationManager.Error(
-          util.FileOperationErrorType.FILESYSTEM_ERROR, err));
-    };
-
-    for (var i = 0; i < this.sourceEntries.length; i++) {
-      var entry = this.sourceEntries[i];
-      util.removeFileOrDirectory(
-          entry, onEntryDeleted.bind(null, entry), onFilesystemError);
-    }
-  }.bind(this);
-
-  AsyncUtil.forEach(
-      this.sourceEntries,
-      function(callback, entry, index) {
-        if (this.cancelRequested_) {
-          errorCallback(new FileOperationManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR,
-              util.createFileError(FileError.ABORT_ERR)));
-          return;
-        }
-        progressCallback();
-        this.cancelCallback_ = FileOperationManager.CopyTask.processEntry_(
-            entry, this.targetDirEntry,
-            function(sourceUrl, destinationUrl) {
-              // Finalize the entry's progress state.
-              var entry = this.processingEntries[index][sourceUrl];
-              if (entry) {
-                this.processedBytes += entry.size - entry.processedBytes;
-                progressCallback();
-                delete this.processingEntries[index][sourceUrl];
-              }
-
-              webkitResolveLocalFileSystemURL(
-                  destinationUrl, function(destinationEntry) {
-                    entryChangedCallback(
-                        util.EntryChangedKind.CREATED, destinationEntry);
-                  });
-            }.bind(this),
-            function(source_url, size) {
-              var entry = this.processingEntries[index][source_url];
-              if (entry) {
-                this.processedBytes += size - entry.processedBytes;
-                entry.processedBytes = size;
-                progressCallback();
-              }
-            }.bind(this),
-            function() {
-              this.cancelCallback_ = null;
-              callback();
-            }.bind(this),
-            function(error) {
-              this.cancelCallback_ = null;
-              errorCallback(error);
-            }.bind(this));
-      },
-      function() {
-        if (this.deleteAfterCopy) {
-          deleteOriginals();
-        } else {
-          successCallback();
-        }
-      }.bind(this),
-      this);
-};
-
-/**
- * Copies the source entry to the target directory.
- *
- * @param {Entry} sourceEntry An entry to be copied.
- * @param {DirectoryEntry} destinationEntry The entry which will contain the
- *     copied entry.
- * @param {function(string, string)} entryChangedCallback
- *     Callback invoked when an entry is created with the source url and
- *     the destination url.
- * @param {function(string, number)} progressCallback Callback invoked
- *     periodically during the copying.
- * @param {function()} successCallback On success.
- * @param {function(FileOperationManager.Error)} errorCallback On error.
- * @return {function()} Callback to cancel the current file copy operation.
- *     When the cancel is done, errorCallback will be called. The returned
- *     callback must not be called more than once.
- * @private
- */
-FileOperationManager.CopyTask.processEntry_ = function(
-    sourceEntry, destinationEntry, entryChangedCallback, progressCallback,
-    successCallback, errorCallback) {
-  var cancelRequested = false;
-  var cancelCallback = null;
-  fileOperationUtil.deduplicatePath(
-      destinationEntry, sourceEntry.name,
-      function(destinationName) {
-        if (cancelRequested) {
-          errorCallback(new FileOperationManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR,
-              util.createFileError(FileError.ABORT_ERR)));
-          return;
-        }
-
-        cancelCallback = fileOperationUtil.copyTo(
-            sourceEntry, destinationEntry, destinationName,
-            entryChangedCallback, progressCallback,
-            function(entry) {
-              cancelCallback = null;
-              successCallback();
-            },
-            function(error) {
-              cancelCallback = null;
-              errorCallback(new FileOperationManager.Error(
-                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-            });
-      },
-      errorCallback);
-
-  return function() {
-    cancelRequested = true;
-    if (cancelCallback) {
-      cancelCallback();
-      cancelCallback = null;
-    }
-  };
-};
-
-/**
- * Task to move entries.
- *
- * @param {Array.<Entry>} sourceEntries Array of source entries.
- * @param {DirectoryEntry} targetDirEntry Target directory.
- * @constructor
- * @extends {FileOperationManager.Task}
- */
-FileOperationManager.MoveTask = function(sourceEntries, targetDirEntry) {
-  FileOperationManager.Task.call(
-      this, util.FileOperationType.MOVE, sourceEntries, targetDirEntry);
-};
-
-/**
- * Extends FileOperationManager.Task.
- */
-FileOperationManager.MoveTask.prototype.__proto__ =
-    FileOperationManager.Task.prototype;
-
-/**
- * Initializes the MoveTask.
- * @param {function()} callback Called when the initialize is completed.
- */
-FileOperationManager.MoveTask.prototype.initialize = function(callback) {
-  // This may be moving from search results, where it fails if we
-  // move parent entries earlier than child entries. We should
-  // process the deepest entry first. Since move of each entry is
-  // done by a single moveTo() call, we don't need to care about the
-  // recursive traversal order.
-  this.sourceEntries.sort(function(entry1, entry2) {
-    return entry2.fullPath.length - entry1.fullPath.length;
-  });
-
-  this.processingEntries = [];
-  for (var i = 0; i < this.sourceEntries.length; i++) {
-    var processingEntryMap = {};
-    var entry = this.sourceEntries[i];
-
-    // The move should be done with updating the metadata. So here we assume
-    // all the file size is 1 byte. (Avoiding 0, so that progress bar can
-    // move smoothly).
-    // TODO(hidehiko): Remove this hack.
-    entry.size = 1;
-    processingEntryMap[entry.toURL()] = entry;
-    this.processingEntries[i] = processingEntryMap;
-  }
-
-  callback();
-};
-
-/**
- * Moves all entries in the task.
- *
- * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
- *     Callback invoked when an entry is changed.
- * @param {function()} progressCallback Callback invoked periodically during
- *     the moving.
- * @param {function()} successCallback On success.
- * @param {function(FileOperationManager.Error)} errorCallback On error.
- * @override
- */
-FileOperationManager.MoveTask.prototype.run = function(
-    entryChangedCallback, progressCallback, successCallback, errorCallback) {
-  if (this.sourceEntries.length == 0) {
-    successCallback();
-    return;
-  }
-
-  AsyncUtil.forEach(
-      this.sourceEntries,
-      function(callback, entry, index) {
-        if (this.cancelRequested_) {
-          errorCallback(new FileOperationManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR,
-              util.createFileError(FileError.ABORT_ERR)));
-          return;
-        }
-        progressCallback();
-        FileOperationManager.MoveTask.processEntry_(
-            entry, this.targetDirEntry, entryChangedCallback,
-            function() {
-              // Erase the processing entry.
-              this.processingEntries[index] = {};
-              this.processedBytes++;
-              callback();
-            }.bind(this),
-            errorCallback);
-      },
-      function() {
-        successCallback();
-      }.bind(this),
-      this);
-};
-
-/**
- * Moves the sourceEntry to the targetDirEntry in this task.
- *
- * @param {Entry} sourceEntry An entry to be moved.
- * @param {DirectoryEntry} destinationEntry The entry of the destination
- *     directory.
- * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
- *     Callback invoked when an entry is changed.
- * @param {function()} successCallback On success.
- * @param {function(FileOperationManager.Error)} errorCallback On error.
- * @private
- */
-FileOperationManager.MoveTask.processEntry_ = function(
-    sourceEntry, destinationEntry, entryChangedCallback, successCallback,
-    errorCallback) {
-  fileOperationUtil.deduplicatePath(
-      destinationEntry,
-      sourceEntry.name,
-      function(destinationName) {
-        sourceEntry.moveTo(
-            destinationEntry, destinationName,
-            function(movedEntry) {
-              entryChangedCallback(util.EntryChangedKind.CREATED, movedEntry);
-              entryChangedCallback(util.EntryChangedKind.DELETED, sourceEntry);
-              successCallback();
-            },
-            function(error) {
-              errorCallback(new FileOperationManager.Error(
-                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-            });
-      },
-      errorCallback);
-};
-
-/**
- * Task to create a zip archive.
- *
- * @param {Array.<Entry>} sourceEntries Array of source entries.
- * @param {DirectoryEntry} targetDirEntry Target directory.
- * @param {DirectoryEntry} zipBaseDirEntry Base directory dealt as a root
- *     in ZIP archive.
- * @constructor
- * @extends {FileOperationManager.Task}
- */
-FileOperationManager.ZipTask = function(
-    sourceEntries, targetDirEntry, zipBaseDirEntry) {
-  FileOperationManager.Task.call(
-      this, util.FileOperationType.ZIP, sourceEntries, targetDirEntry);
-  this.zipBaseDirEntry = zipBaseDirEntry;
-};
-
-/**
- * Extends FileOperationManager.Task.
- */
-FileOperationManager.ZipTask.prototype.__proto__ =
-    FileOperationManager.Task.prototype;
-
-
-/**
- * Initializes the ZipTask.
- * @param {function()} callback Called when the initialize is completed.
- */
-FileOperationManager.ZipTask.prototype.initialize = function(callback) {
-  var resolvedEntryMap = {};
-  var group = new AsyncUtil.Group();
-  for (var i = 0; i < this.sourceEntries.length; i++) {
-    group.add(function(index, callback) {
-      fileOperationUtil.resolveRecursively(
-          this.sourceEntries[index],
-          function(entries) {
-            for (var j = 0; j < entries.length; j++)
-              resolvedEntryMap[entries[j].toURL()] = entries[j];
-            callback();
-          },
-          function(error) {});
-    }.bind(this, i));
-  }
-
-  group.run(function() {
-    // For zip archiving, all the entries are processed at once.
-    this.processingEntries = [resolvedEntryMap];
-
-    this.totalBytes = 0;
-    for (var url in resolvedEntryMap)
-      this.totalBytes += resolvedEntryMap[url].size;
-
-    callback();
-  }.bind(this));
-};
-
-/**
- * Runs a zip file creation task.
- *
- * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback
- *     Callback invoked when an entry is changed.
- * @param {function()} progressCallback Callback invoked periodically during
- *     the moving.
- * @param {function()} successCallback On complete.
- * @param {function(FileOperationManager.Error)} errorCallback On error.
- * @override
- */
-FileOperationManager.ZipTask.prototype.run = function(
-    entryChangedCallback, progressCallback, successCallback, errorCallback) {
-  // TODO(hidehiko): we should localize the name.
-  var destName = 'Archive';
-  if (this.sourceEntries.length == 1) {
-    var entryPath = this.sourceEntries[0].fullPath;
-    var i = entryPath.lastIndexOf('/');
-    var basename = (i < 0) ? entryPath : entryPath.substr(i + 1);
-    i = basename.lastIndexOf('.');
-    destName = ((i < 0) ? basename : basename.substr(0, i));
-  }
-
-  fileOperationUtil.deduplicatePath(
-      this.targetDirEntry, destName + '.zip',
-      function(destPath) {
-        // TODO: per-entry zip progress update with accurate byte count.
-        // For now just set completedBytes to same value as totalBytes so
-        // that the progress bar is full.
-        this.processedBytes = this.totalBytes;
-        progressCallback();
-
-        // The number of elements in processingEntries is 1. See also
-        // initialize().
-        var entries = [];
-        for (var url in this.processingEntries[0])
-          entries.push(this.processingEntries[0][url]);
-
-        fileOperationUtil.zipSelection(
-            entries,
-            this.zipBaseDirEntry,
-            destPath,
-            function(entry) {
-              entryChangedCallback(util.EntryChangedKind.CREATE, entry);
-              successCallback();
-            },
-            function(error) {
-              errorCallback(new FileOperationManager.Error(
-                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-            });
-      }.bind(this),
-      errorCallback);
-};
-
-/**
- * Error class used to report problems with a copy operation.
- * If the code is UNEXPECTED_SOURCE_FILE, data should be a path of the file.
- * If the code is TARGET_EXISTS, data should be the existing Entry.
- * If the code is FILESYSTEM_ERROR, data should be the FileError.
- *
- * @param {util.FileOperationErrorType} code Error type.
- * @param {string|Entry|FileError} data Additional data.
- * @constructor
- */
-FileOperationManager.Error = function(code, data) {
-  this.code = code;
-  this.data = data;
-};
-
-// FileOperationManager methods.
-
-/**
- * Called before a new method is run in the manager. Prepares the manager's
- * state for running a new method.
- */
-FileOperationManager.prototype.willRunNewMethod = function() {
-  // Cancel any pending close actions so the file copy manager doesn't go away.
-  if (this.unloadTimeout_)
-    clearTimeout(this.unloadTimeout_);
-  this.unloadTimeout_ = null;
-};
-
-/**
- * @return {Object} Status object.
- */
-FileOperationManager.prototype.getStatus = function() {
-  // TODO(hidehiko): Reorganize the structure when delete queue is merged
-  // into copy task queue.
-  var result = {
-    // Set to util.FileOperationType if all the running/pending tasks is
-    // the same kind of task.
-    operationType: null,
-
-    // The number of entries to be processed.
-    numRemainingItems: 0,
-
-    // The total number of bytes to be processed.
-    totalBytes: 0,
-
-    // The number of bytes.
-    processedBytes: 0,
-
-    // Available if numRemainingItems == 1. Pointing to an Entry which is
-    // begin processed.
-    processingEntry: null,
-  };
-
-  var operationType =
-      this.copyTasks_.length > 0 ? this.copyTasks_[0].operationType : null;
-  var processingEntry = null;
-  for (var i = 0; i < this.copyTasks_.length; i++) {
-    var task = this.copyTasks_[i];
-    if (task.operationType != operationType)
-      operationType = null;
-
-    // Assuming the number of entries is small enough, count every time.
-    for (var j = 0; j < task.processingEntries.length; j++) {
-      for (var url in task.processingEntries[j]) {
-        ++result.numRemainingItems;
-        processingEntry = task.processingEntries[j][url];
-      }
-    }
-
-    result.totalBytes += task.totalBytes;
-    result.processedBytes += task.processedBytes;
-  }
-
-  result.operationType = operationType;
-
-  if (result.numRemainingItems == 1)
-    result.processingEntry = processingEntry;
-
-  return result;
-};
-
-/**
- * Adds an event listener for the tasks.
- * @param {string} type The name of the event.
- * @param {function(Event)} handler The handler for the event.
- *     This is called when the event is dispatched.
- */
-FileOperationManager.prototype.addEventListener = function(type, handler) {
-  this.eventRouter_.addEventListener(type, handler);
-};
-
-/**
- * Removes an event listener for the tasks.
- * @param {string} type The name of the event.
- * @param {function(Event)} handler The handler to be removed.
- */
-FileOperationManager.prototype.removeEventListener = function(type, handler) {
-  this.eventRouter_.removeEventListener(type, handler);
-};
-
-/**
- * Says if there are any tasks in the queue.
- * @return {boolean} True, if there are any tasks.
- */
-FileOperationManager.prototype.hasQueuedTasks = function() {
-  return this.copyTasks_.length > 0 || this.deleteTasks_.length > 0;
-};
-
-/**
- * Unloads the host page in 5 secs of idling. Need to be called
- * each time this.copyTasks_.length or this.deleteTasks_.length
- * changed.
- *
- * @private
- */
-FileOperationManager.prototype.maybeScheduleCloseBackgroundPage_ = function() {
-  if (!this.hasQueuedTasks()) {
-    if (this.unloadTimeout_ === null)
-      this.unloadTimeout_ = setTimeout(maybeCloseBackgroundPage, 5000);
-  } else if (this.unloadTimeout_) {
-    clearTimeout(this.unloadTimeout_);
-    this.unloadTimeout_ = null;
-  }
-};
-
-/**
- * Completely clear out the copy queue, either because we encountered an error
- * or completed successfully.
- *
- * @private
- */
-FileOperationManager.prototype.resetQueue_ = function() {
-  for (var i = 0; i < this.cancelObservers_.length; i++)
-    this.cancelObservers_[i]();
-
-  this.copyTasks_ = [];
-  this.cancelObservers_ = [];
-  this.maybeScheduleCloseBackgroundPage_();
-};
-
-/**
- * Request that the current copy queue be abandoned.
- *
- * @param {function()=} opt_callback On cancel.
- */
-FileOperationManager.prototype.requestCancel = function(opt_callback) {
-  this.cancelRequested_ = true;
-  if (this.cancelCallback_) {
-    this.cancelCallback_();
-    this.cancelCallback_ = null;
-  }
-  if (opt_callback)
-    this.cancelObservers_.push(opt_callback);
-
-  // If there is any active task it will eventually call maybeCancel_.
-  // Otherwise call it right now.
-  if (this.copyTasks_.length == 0)
-    this.doCancel_();
-  else
-    this.copyTasks_[0].requestCancel();
-};
-
-/**
- * Perform the bookkeeping required to cancel.
- *
- * @private
- */
-FileOperationManager.prototype.doCancel_ = function() {
-  var taskId = this.copyTasks_[0].taskId;
-  this.resetQueue_();
-  this.cancelRequested_ = false;
-  this.eventRouter_.sendProgressEvent('CANCELLED', this.getStatus(), taskId);
-};
-
-/**
- * Used internally to check if a cancel has been requested, and handle
- * it if so.
- *
- * @return {boolean} If canceled.
- * @private
- */
-FileOperationManager.prototype.maybeCancel_ = function() {
-  if (!this.cancelRequested_)
-    return false;
-
-  this.doCancel_();
-  return true;
-};
-
-/**
- * Kick off pasting.
- *
- * @param {Array.<string>} sourcePaths Path of the source files.
- * @param {string} targetPath The destination path of the target directory.
- * @param {boolean} isMove True if the operation is "move", otherwise (i.e.
- *     if the operation is "copy") false.
- */
-FileOperationManager.prototype.paste = function(
-    sourcePaths, targetPath, isMove) {
-  // Do nothing if sourcePaths is empty.
-  if (sourcePaths.length == 0)
-    return;
-
-  var errorCallback = function(error) {
-    this.eventRouter_.sendProgressEvent(
-        'ERROR',
-        this.getStatus(),
-        this.generateTaskId_(null),
-        new FileOperationManager.Error(
-            util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-  }.bind(this);
-
-  var targetEntry = null;
-  var entries = [];
-
-  // Resolve paths to entries.
-  var resolveGroup = new AsyncUtil.Group();
-  resolveGroup.add(function(callback) {
-    webkitResolveLocalFileSystemURL(
-        util.makeFilesystemUrl(targetPath),
-        function(entry) {
-          if (!entry.isDirectory) {
-            // Found a non directory entry.
-            errorCallback(util.createFileError(FileError.TYPE_MISMATCH_ERR));
-            return;
-          }
-
-          targetEntry = entry;
-          callback();
-        },
-        errorCallback);
-  });
-
-  for (var i = 0; i < sourcePaths.length; i++) {
-    resolveGroup.add(function(sourcePath, callback) {
-      webkitResolveLocalFileSystemURL(
-          util.makeFilesystemUrl(sourcePath),
-          function(entry) {
-            entries.push(entry);
-            callback();
-          },
-          errorCallback);
-    }.bind(this, sourcePaths[i]));
-  }
-
-  resolveGroup.run(function() {
-    if (isMove) {
-      // Moving to the same directory is a redundant operation.
-      entries = entries.filter(function(entry) {
-        return targetEntry.fullPath + '/' + entry.name != entry.fullPath;
-      });
-
-      // Do nothing, if we have no entries to be moved.
-      if (entries.length == 0)
-        return;
-    }
-
-    this.queueCopy_(targetEntry, entries, isMove);
-  }.bind(this));
-};
-
-/**
- * Checks if the move operation is available between the given two locations.
- *
- * @param {DirectoryEntry} sourceEntry An entry from the source.
- * @param {DirectoryEntry} targetDirEntry Directory entry for the target.
- * @return {boolean} Whether we can move from the source to the target.
- */
-FileOperationManager.prototype.isMovable = function(sourceEntry,
-                                               targetDirEntry) {
-  return (PathUtil.isDriveBasedPath(sourceEntry.fullPath) &&
-          PathUtil.isDriveBasedPath(targetDirEntry.fullPath)) ||
-         (PathUtil.getRootPath(sourceEntry.fullPath) ==
-          PathUtil.getRootPath(targetDirEntry.fullPath));
-};
-
-/**
- * Initiate a file copy.
- *
- * @param {DirectoryEntry} targetDirEntry Target directory.
- * @param {Array.<Entry>} entries Entries to copy.
- * @param {boolean} isMove In case of move.
- * @return {FileOperationManager.Task} Copy task.
- * @private
- */
-FileOperationManager.prototype.queueCopy_ = function(
-    targetDirEntry, entries, isMove) {
-  // When copying files, null can be specified as source directory.
-  var task;
-  if (isMove) {
-    if (this.isMovable(entries[0], targetDirEntry)) {
-      task = new FileOperationManager.MoveTask(entries, targetDirEntry);
-    } else {
-      task = new FileOperationManager.CopyTask(entries, targetDirEntry);
-      task.deleteAfterCopy = true;
-    }
-  } else {
-    task = new FileOperationManager.CopyTask(entries, targetDirEntry);
-  }
-
-  task.taskId = this.generateTaskId_(this.copyTasks_);
-  task.initialize(function() {
-    this.copyTasks_.push(task);
-    this.maybeScheduleCloseBackgroundPage_();
-    if (this.copyTasks_.length == 1) {
-      // Assume this.cancelRequested_ == false.
-      // This moved us from 0 to 1 active tasks, let the servicing begin!
-      this.serviceAllTasks_();
-    } else {
-      // Force to update the progress of butter bar when there are new tasks
-      // coming while servicing current task.
-      this.eventRouter_.sendProgressEvent('PROGRESS',
-                                          this.getStatus(),
-                                          task.taskId);
-    }
-  }.bind(this));
-
-  return task;
-};
-
-/**
- * Service all pending tasks, as well as any that might appear during the
- * copy.
- *
- * @private
- */
-FileOperationManager.prototype.serviceAllTasks_ = function() {
-  var self = this;
-
-  var onTaskProgress = function() {
-    self.eventRouter_.sendProgressEvent('PROGRESS',
-                                        self.getStatus(),
-                                        self.copyTasks_[0].taskId);
-  };
-
-  var onEntryChanged = function(kind, entry) {
-    self.eventRouter_.sendEntryChangedEvent(kind, entry);
-  };
-
-  var onTaskError = function(err) {
-    var taskId = self.copyTasks_[0].taskId;
-    if (self.maybeCancel_())
-      return;
-    self.eventRouter_.sendProgressEvent('ERROR',
-                                        self.getStatus(),
-                                        taskId,
-                                        err);
-    self.resetQueue_();
-  };
-
-  var onTaskSuccess = function() {
-    if (self.maybeCancel_())
-      return;
-
-    // The task at the front of the queue is completed. Pop it from the queue.
-    var taskId = self.copyTasks_[0].taskId;
-    self.copyTasks_.shift();
-    self.maybeScheduleCloseBackgroundPage_();
-
-    if (!self.copyTasks_.length) {
-      // All tasks have been serviced, clean up and exit.
-      self.eventRouter_.sendProgressEvent('SUCCESS',
-                                          self.getStatus(),
-                                          taskId);
-      self.resetQueue_();
-      return;
-    }
-
-    // We want to dispatch a PROGRESS event when there are more tasks to serve
-    // right after one task finished in the queue. We treat all tasks as one
-    // big task logically, so there is only one BEGIN/SUCCESS event pair for
-    // these continuous tasks.
-    self.eventRouter_.sendProgressEvent('PROGRESS',
-                                        self.getStatus(),
-                                        self.copyTasks_[0].taskId);
-    self.copyTasks_[0].run(
-        onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
-  };
-
-  // If the queue size is 1 after pushing our task, it was empty before,
-  // so we need to kick off queue processing and dispatch BEGIN event.
-  this.eventRouter_.sendProgressEvent('BEGIN',
-                                      this.getStatus(),
-                                      self.copyTasks_[0].taskId);
-  this.copyTasks_[0].run(
-      onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
-};
-
-/**
- * Timeout before files are really deleted (to allow undo).
- */
-FileOperationManager.DELETE_TIMEOUT = 30 * 1000;
-
-/**
- * Schedules the files deletion.
- *
- * @param {Array.<Entry>} entries The entries.
- */
-FileOperationManager.prototype.deleteEntries = function(entries) {
-  var task = {
-    entries: entries,
-    taskId: this.generateTaskId_(this.deleteTasks_)
-  };
-  this.deleteTasks_.push(task);
-  this.maybeScheduleCloseBackgroundPage_();
-  if (this.deleteTasks_.length == 1)
-    this.serviceAllDeleteTasks_();
-};
-
-/**
- * Service all pending delete tasks, as well as any that might appear during the
- * deletion.
- *
- * Must not be called if there is an in-flight delete task.
- *
- * @private
- */
-FileOperationManager.prototype.serviceAllDeleteTasks_ = function() {
-  // Returns the urls of the given task's entries.
-  var getTaskUrls = function(task) {
-    return task.entries.map(function(entry) {
-      return util.makeFilesystemUrl(entry.fullPath);
-    });
-  };
-
-  var onTaskSuccess = function() {
-    var urls = getTaskUrls(this.deleteTasks_[0]);
-    var taskId = this.deleteTasks_[0].taskId;
-    this.deleteTasks_.shift();
-    if (!this.deleteTasks_.length) {
-      // All tasks have been serviced, clean up and exit.
-      this.eventRouter_.sendDeleteEvent('SUCCESS', urls, taskId);
-      this.maybeScheduleCloseBackgroundPage_();
-      return;
-    }
-
-    // We want to dispatch a PROGRESS event when there are more tasks to serve
-    // right after one task finished in the queue. We treat all tasks as one
-    // big task logically, so there is only one BEGIN/SUCCESS event pair for
-    // these continuous tasks.
-    this.eventRouter_.sendDeleteEvent('PROGRESS',
-                                      urls,
-                                      this.deleteTasks_[0].taskId);
-
-    this.serviceDeleteTask_(this.deleteTasks_[0], onTaskSuccess, onTaskFailure);
-  }.bind(this);
-
-  var onTaskFailure = function(error) {
-    var urls = getTaskUrls(this.deleteTasks_[0]);
-    var taskId = this.deleteTasks_[0].taskId;
-    this.deleteTasks_ = [];
-    this.eventRouter_.sendDeleteEvent('ERROR',
-                                      urls,
-                                      taskId);
-    this.maybeScheduleCloseBackgroundPage_();
-  }.bind(this);
-
-  // If the queue size is 1 after pushing our task, it was empty before,
-  // so we need to kick off queue processing and dispatch BEGIN event.
-  this.eventRouter_.sendDeleteEvent('BEGIN',
-                                    getTaskUrls(this.deleteTasks_[0]),
-                                    this.deleteTasks_[0].taskId);
-  this.serviceDeleteTask_(this.deleteTasks_[0], onTaskSuccess, onTaskFailure);
-};
-
-/**
- * Performs the deletion.
- *
- * @param {Object} task The delete task (see deleteEntries function).
- * @param {function()} successCallback Callback run on success.
- * @param {function(FileOperationManager.Error)} errorCallback Callback run on
- *     error.
- * @private
- */
-FileOperationManager.prototype.serviceDeleteTask_ = function(
-    task, successCallback, errorCallback) {
-  var downcount = task.entries.length;
-  if (downcount == 0) {
-    successCallback();
-    return;
-  }
-
-  var filesystemError = null;
-  var onComplete = function() {
-    if (--downcount > 0)
-      return;
-
-    // All remove operations are processed. Run callback.
-    if (filesystemError) {
-      errorCallback(new FileOperationManager.Error(
-          util.FileOperationErrorType.FILESYSTEM_ERROR, filesystemError));
-    } else {
-      successCallback();
-    }
-  };
-
-  for (var i = 0; i < task.entries.length; i++) {
-    var entry = task.entries[i];
-    util.removeFileOrDirectory(
-        entry,
-        function(currentEntry) {
-          this.eventRouter_.sendEntryChangedEvent(
-              util.EntryChangedKind.DELETED, currentEntry);
-          onComplete();
-        }.bind(this, entry),
-        function(error) {
-          if (!filesystemError)
-            filesystemError = error;
-          onComplete();
-        });
-  }
-};
-
-/**
- * Creates a zip file for the selection of files.
- *
- * @param {Entry} dirEntry The directory containing the selection.
- * @param {Array.<Entry>} selectionEntries The selected entries.
- */
-FileOperationManager.prototype.zipSelection = function(
-    dirEntry, selectionEntries) {
-  var self = this;
-  var zipTask = new FileOperationManager.ZipTask(
-      selectionEntries, dirEntry, dirEntry);
-  zipTask.taskId = this.generateTaskId_(this.copyTasks_);
-  zipTask.zip = true;
-  zipTask.initialize(function() {
-    self.copyTasks_.push(zipTask);
-    if (self.copyTasks_.length == 1) {
-      // Assume self.cancelRequested_ == false.
-      // This moved us from 0 to 1 active tasks, let the servicing begin!
-      self.serviceAllTasks_();
-    } else {
-      // Force to update the progress of butter bar when there are new tasks
-      // coming while servicing current task.
-      self.eventRouter_.sendProgressEvent('PROGRESS',
-                                          self.getStatus(),
-                                          self.copyTasks_[0].taskId);
-    }
-  });
-};
-
-/**
- * Generates new task ID.
- *
- * TODO(hirono): Remove the queue argument. The ID should be generated
- *     independenting on the queue.
- * @param {Array.<FileOperationManager.Task>} queue Qeueu that the task is
- *     inserted to.
- * @return {string} New task ID.
- * @private
- */
-FileOperationManager.prototype.generateTaskId_ = function(queue) {
-  if (queue) {
-    queue.taskIdCounter = queue.taskIdCounter || 0;
-    if (!queue.length)
-      queue.taskIdCounter++;
-  }
-  return 'file-operation-' + queue.taskIdCounter;
-};
diff --git a/chrome/browser/resources/file_manager/js/file_operation_manager_wrapper.js b/chrome/browser/resources/file_manager/js/file_operation_manager_wrapper.js
deleted file mode 100644
index 45c89c6..0000000
--- a/chrome/browser/resources/file_manager/js/file_operation_manager_wrapper.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 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.
-
-'use strict';
-
-/**
- * While FileOperationManager is run in the background page, this class is
- * used to communicate with it.
- * @param {DOMWindow} backgroundPage Window object of the background page.
- * @constructor
- */
-function FileOperationManagerWrapper(backgroundPage) {
-  this.fileOperationManager_ =
-      backgroundPage.FileOperationManager.getInstance();
-}
-
-/**
- * Create a new instance or get existing instance of FCMW.
- * @param {DOMWindow} backgroundPage Window object of the background page.
- * @return {FileOperationManagerWrapper}  FileOperationManagerWrapper instance.
- */
-FileOperationManagerWrapper.getInstance = function(backgroundPage) {
-  if (!FileOperationManagerWrapper.instance_)
-    FileOperationManagerWrapper.instance_ =
-        new FileOperationManagerWrapper(backgroundPage);
-
-  return FileOperationManagerWrapper.instance_;
-};
-
-/**
- * @return {boolean} True if there is a running task.
- */
-FileOperationManagerWrapper.prototype.isRunning = function() {
-  return this.fileOperationManager_.hasQueuedTasks();
-};
-
-/**
- * Decorates a FileOperationManager method, so it will be executed after
- * initializing the FileOperationManager instance in background page.
- * @param {string} method The method name.
- */
-FileOperationManagerWrapper.decorateAsyncMethod = function(method) {
-  FileOperationManagerWrapper.prototype[method] = function() {
-    this.fileOperationManager_.willRunNewMethod();
-    this.fileOperationManager_[method].apply(
-        this.fileOperationManager_, arguments);
-  };
-};
-
-FileOperationManagerWrapper.decorateAsyncMethod('requestCancel');
-FileOperationManagerWrapper.decorateAsyncMethod('paste');
-FileOperationManagerWrapper.decorateAsyncMethod('deleteEntries');
-FileOperationManagerWrapper.decorateAsyncMethod('forceDeleteTask');
-FileOperationManagerWrapper.decorateAsyncMethod('cancelDeleteTask');
-FileOperationManagerWrapper.decorateAsyncMethod('zipSelection');
-FileOperationManagerWrapper.decorateAsyncMethod('addEventListener');
-FileOperationManagerWrapper.decorateAsyncMethod('removeEventListener');
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
deleted file mode 100644
index 2584d06..0000000
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ /dev/null
@@ -1,735 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * This object encapsulates everything related to tasks execution.
- *
- * @param {FileManager} fileManager FileManager instance.
- * @param {Object=} opt_params File manager load parameters.
- * @constructor
- */
-function FileTasks(fileManager, opt_params) {
-  this.fileManager_ = fileManager;
-  this.params_ = opt_params;
-  this.tasks_ = null;
-  this.defaultTask_ = null;
-
-  /**
-   * List of invocations to be called once tasks are available.
-   *
-   * @private
-   * @type {Array.<Object>}
-   */
-  this.pendingInvocations_ = [];
-}
-
-/**
- * Location of the FAQ about the file actions.
- *
- * @const
- * @type {string}
- */
-FileTasks.NO_ACTION_FOR_FILE_URL = 'http://support.google.com/chromeos/bin/' +
-    'answer.py?answer=1700055&topic=29026&ctx=topic';
-
-/**
- * Location of the Chrome Web Store.
- *
- * @const
- * @type {string}
- */
-FileTasks.CHROME_WEB_STORE_URL = 'https://chrome.google.com/webstore';
-
-/**
- * Base URL of apps list in the Chrome Web Store. This constant is used in
- * FileTasks.createWebStoreLink().
- *
- * @const
- * @type {string}
- */
-FileTasks.WEB_STORE_HANDLER_BASE_URL =
-    'https://chrome.google.com/webstore/category/collection/file_handlers';
-
-/**
- * Returns URL of the Chrome Web Store which show apps supporting the given
- * file-extension and mime-type.
- *
- * @param {string} extension Extension of the file.
- * @param {string} mimeType Mime type of the file.
- * @return {string} URL
- */
-FileTasks.createWebStoreLink = function(extension, mimeType) {
-  if (!extension)
-    return FileTasks.CHROME_WEB_STORE_URL;
-
-  var url = FileTasks.WEB_STORE_HANDLER_BASE_URL;
-  url += '?_fe=' + extension.toLowerCase().replace(/[^\w]/g, '');
-
-  // If a mime is given, add it into the URL.
-  if (mimeType)
-    url += '&_fmt=' + mimeType.replace(/[^-\w\/]/g, '');
-  return url;
-};
-
-/**
- * Complete the initialization.
- *
- * @param {Array.<string>} urls List of file urls.
- * @param {Array.<string>=} opt_mimeTypes List of MIME types for each
- *     of the files.
- */
-FileTasks.prototype.init = function(urls, opt_mimeTypes) {
-  this.urls_ = urls;
-  if (urls.length > 0)
-    chrome.fileBrowserPrivate.getFileTasks(urls, opt_mimeTypes || [],
-      this.onTasks_.bind(this));
-};
-
-/**
- * Returns amount of tasks.
- *
- * @return {number} amount of tasks.
- */
-FileTasks.prototype.size = function() {
-  return (this.tasks_ && this.tasks_.length) || 0;
-};
-
-/**
- * Callback when tasks found.
- *
- * @param {Array.<Object>} tasks The tasks.
- * @private
- */
-FileTasks.prototype.onTasks_ = function(tasks) {
-  this.processTasks_(tasks);
-  for (var index = 0; index < this.pendingInvocations_.length; index++) {
-    var name = this.pendingInvocations_[index][0];
-    var args = this.pendingInvocations_[index][1];
-    this[name].apply(this, args);
-  }
-  this.pendingInvocations_ = [];
-};
-
-/**
- * The list of known extensions to record UMA.
- * Note: Because the data is recorded by the index, so new item shouldn't be
- * inserted.
- *
- * @const
- * @type {Array.<string>}
- * @private
- */
-FileTasks.knownExtensions_ = [
-  'other', '.3ga', '.3gp', '.aac', '.alac', '.asf', '.avi', '.bmp', '.csv',
-  '.doc', '.docx', '.flac', '.gif', '.jpeg', '.jpg', '.log', '.m3u', '.m3u8',
-  '.m4a', '.m4v', '.mid', '.mkv', '.mov', '.mp3', '.mp4', '.mpg', '.odf',
-  '.odp', '.ods', '.odt', '.oga', '.ogg', '.ogv', '.pdf', '.png', '.ppt',
-  '.pptx', '.ra', '.ram', '.rar', '.rm', '.rtf', '.wav', '.webm', '.webp',
-  '.wma', '.wmv', '.xls', '.xlsx',
-];
-
-/**
- * Records trial of opening file grouped by extensions.
- *
- * @param {Array.<string>} urls The path to be opened.
- * @private
- */
-FileTasks.recordViewingFileTypeUMA_ = function(urls) {
-  for (var i = 0; i < urls.length; i++) {
-    var url = urls[i];
-    var extension = FileType.getExtension(url).toLowerCase();
-    if (FileTasks.knownExtensions_.indexOf(extension) < 0) {
-      extension = 'other';
-    }
-    metrics.recordEnum(
-        'ViewingFileType', extension, FileTasks.knownExtensions_);
-  }
-};
-
-/**
- * Returns true if the taskId is for an internal task.
- *
- * @param {string} taskId Task identifier.
- * @return {boolean} True if the task ID is for an internal task.
- * @private
- */
-FileTasks.isInternalTask_ = function(taskId) {
-  var taskParts = taskId.split('|');
-  var appId = taskParts[0];
-  var taskType = taskParts[1];
-  var actionId = taskParts[2];
-  // The action IDs here should match ones used in executeInternalTask_().
-  return (appId == chrome.runtime.id &&
-          taskType == 'file' &&
-          (actionId == 'play' ||
-           actionId == 'watch' ||
-           actionId == 'mount-archive' ||
-           actionId == 'format-device' ||
-           actionId == 'gallery'));
-};
-
-/**
- * Processes internal tasks.
- *
- * @param {Array.<Object>} tasks The tasks.
- * @private
- */
-FileTasks.prototype.processTasks_ = function(tasks) {
-  this.tasks_ = [];
-  var id = chrome.runtime.id;
-  var isOnDrive = false;
-  for (var index = 0; index < this.urls_.length; ++index) {
-    if (FileType.isOnDrive(this.urls_[index])) {
-      isOnDrive = true;
-      break;
-    }
-  }
-
-  for (var i = 0; i < tasks.length; i++) {
-    var task = tasks[i];
-    var taskParts = task.taskId.split('|');
-
-    // Skip internal Files.app's handlers.
-    if (taskParts[0] == id && (taskParts[2] == 'auto-open' ||
-        taskParts[2] == 'select' || taskParts[2] == 'open')) {
-      continue;
-    }
-
-    // Tweak images, titles of internal tasks.
-    if (taskParts[0] == id && taskParts[1] == 'file') {
-      if (taskParts[2] == 'play') {
-        // TODO(serya): This hack needed until task.iconUrl is working
-        //             (see GetFileTasksFileBrowserFunction::RunImpl).
-        task.iconType = 'audio';
-        task.title = loadTimeData.getString('ACTION_LISTEN');
-      } else if (taskParts[2] == 'mount-archive') {
-        task.iconType = 'archive';
-        task.title = loadTimeData.getString('MOUNT_ARCHIVE');
-      } else if (taskParts[2] == 'gallery') {
-        task.iconType = 'image';
-        task.title = loadTimeData.getString('ACTION_OPEN');
-      } else if (taskParts[2] == 'watch') {
-        task.iconType = 'video';
-        task.title = loadTimeData.getString('ACTION_WATCH');
-      } else if (taskParts[2] == 'open-hosted-generic') {
-        if (this.urls_.length > 1)
-          task.iconType = 'generic';
-        else // Use specific icon.
-          task.iconType = FileType.getIcon(this.urls_[0]);
-        task.title = loadTimeData.getString('ACTION_OPEN');
-      } else if (taskParts[2] == 'open-hosted-gdoc') {
-        task.iconType = 'gdoc';
-        task.title = loadTimeData.getString('ACTION_OPEN_GDOC');
-      } else if (taskParts[2] == 'open-hosted-gsheet') {
-        task.iconType = 'gsheet';
-        task.title = loadTimeData.getString('ACTION_OPEN_GSHEET');
-      } else if (taskParts[2] == 'open-hosted-gslides') {
-        task.iconType = 'gslides';
-        task.title = loadTimeData.getString('ACTION_OPEN_GSLIDES');
-      } else if (taskParts[2] == 'view-swf') {
-        // Do not render this task if disabled.
-        if (!loadTimeData.getBoolean('SWF_VIEW_ENABLED'))
-          continue;
-        task.iconType = 'generic';
-        task.title = loadTimeData.getString('ACTION_VIEW');
-      } else if (taskParts[2] == 'view-pdf') {
-        // Do not render this task if disabled.
-        if (!loadTimeData.getBoolean('PDF_VIEW_ENABLED'))
-          continue;
-        task.iconType = 'pdf';
-        task.title = loadTimeData.getString('ACTION_VIEW');
-      } else if (taskParts[2] == 'view-in-browser') {
-        task.iconType = 'generic';
-        task.title = loadTimeData.getString('ACTION_VIEW');
-      }
-    }
-
-    if (!task.iconType && taskParts[1] == 'web-intent') {
-      task.iconType = 'generic';
-    }
-
-    this.tasks_.push(task);
-    if (this.defaultTask_ == null && task.isDefault) {
-      this.defaultTask_ = task;
-    }
-  }
-  if (!this.defaultTask_ && this.tasks_.length > 0) {
-    // If we haven't picked a default task yet, then just pick the first one.
-    // This is not the preferred way we want to pick this, but better this than
-    // no default at all if the C++ code didn't set one.
-    this.defaultTask_ = this.tasks_[0];
-  }
-};
-
-/**
- * Executes default task.
- *
- * @param {function(boolean, Array.<string>)=} opt_callback Called when the
- *     default task is executed, or the error is occurred.
- * @private
- */
-FileTasks.prototype.executeDefault_ = function(opt_callback) {
-  var urls = this.urls_;
-  FileTasks.recordViewingFileTypeUMA_(urls);
-  this.executeDefaultInternal_(urls, opt_callback);
-};
-
-/**
- * Executes default task.
- *
- * @param {Array.<string>} urls Urls to execute.
- * @param {function(boolean, Array.<string>)=} opt_callback Called when the
- *     default task is executed, or the error is occurred.
- * @private
- */
-FileTasks.prototype.executeDefaultInternal_ = function(urls, opt_callback) {
-  var callback = opt_callback || function(arg1, arg2) {};
-
-  if (this.defaultTask_ != null) {
-    this.executeInternal_(this.defaultTask_.taskId, urls);
-    callback(true, urls);
-    return;
-  }
-
-  // We don't have tasks, so try to show a file in a browser tab.
-  // We only do that for single selection to avoid confusion.
-  if (urls.length != 1)
-    return;
-
-  var onViewFiles = function(success) {
-    callback(success, urls);
-  }.bind(this);
-
-  this.checkAvailability_(function() {
-    util.viewFilesInBrowser(urls, onViewFiles);
-  }.bind(this));
-};
-
-/**
- * Executes a single task.
- *
- * @param {string} taskId Task identifier.
- * @param {Array.<string>=} opt_urls Urls to execute on instead of |this.urls_|.
- * @private
- */
-FileTasks.prototype.execute_ = function(taskId, opt_urls) {
-  var urls = opt_urls || this.urls_;
-  FileTasks.recordViewingFileTypeUMA_(urls);
-  this.executeInternal_(taskId, urls);
-};
-
-/**
- * The core implementation to execute a single task.
- *
- * @param {string} taskId Task identifier.
- * @param {Array.<string>} urls Urls to execute.
- * @private
- */
-FileTasks.prototype.executeInternal_ = function(taskId, urls) {
-  this.checkAvailability_(function() {
-    if (FileTasks.isInternalTask_(taskId)) {
-      var taskParts = taskId.split('|');
-      this.executeInternalTask_(taskParts[2], urls);
-    } else {
-      chrome.fileBrowserPrivate.executeTask(taskId, urls);
-    }
-  }.bind(this));
-};
-
-/**
- * Checks whether the remote files are available right now.
- *
- * @param {function} callback The callback.
- * @private
- */
-FileTasks.prototype.checkAvailability_ = function(callback) {
-  var areAll = function(props, name) {
-    var isOne = function(e) {
-      // If got no properties, we safely assume that item is unavailable.
-      return e && e[name];
-    };
-    return props.filter(isOne).length == props.length;
-  };
-
-  var fm = this.fileManager_;
-  var urls = this.urls_;
-
-  if (fm.isOnDrive() && fm.isDriveOffline()) {
-    fm.metadataCache_.get(urls, 'drive', function(props) {
-      if (areAll(props, 'availableOffline')) {
-        callback();
-        return;
-      }
-
-      fm.alert.showHtml(
-          loadTimeData.getString('OFFLINE_HEADER'),
-          props[0].hosted ?
-            loadTimeData.getStringF(
-                urls.length == 1 ?
-                    'HOSTED_OFFLINE_MESSAGE' :
-                    'HOSTED_OFFLINE_MESSAGE_PLURAL') :
-            loadTimeData.getStringF(
-                urls.length == 1 ?
-                    'OFFLINE_MESSAGE' :
-                    'OFFLINE_MESSAGE_PLURAL',
-                loadTimeData.getString('OFFLINE_COLUMN_LABEL')));
-    });
-    return;
-  }
-
-  if (fm.isOnDrive() && fm.isDriveOnMeteredConnection()) {
-    fm.metadataCache_.get(urls, 'drive', function(driveProps) {
-      if (areAll(driveProps, 'availableWhenMetered')) {
-        callback();
-        return;
-      }
-
-      fm.metadataCache_.get(urls, 'filesystem', function(fileProps) {
-        var sizeToDownload = 0;
-        for (var i = 0; i != urls.length; i++) {
-          if (!driveProps[i].availableWhenMetered)
-            sizeToDownload += fileProps[i].size;
-        }
-        fm.confirm.show(
-            loadTimeData.getStringF(
-                urls.length == 1 ?
-                    'CONFIRM_MOBILE_DATA_USE' :
-                    'CONFIRM_MOBILE_DATA_USE_PLURAL',
-                util.bytesToString(sizeToDownload)),
-            callback);
-      });
-    });
-    return;
-  }
-
-  callback();
-};
-
-/**
- * Executes an internal task.
- *
- * @param {string} id The short task id.
- * @param {Array.<string>} urls The urls to execute on.
- * @private
- */
-FileTasks.prototype.executeInternalTask_ = function(id, urls) {
-  var fm = this.fileManager_;
-
-  if (id == 'play') {
-    var position = 0;
-    if (urls.length == 1) {
-      // If just a single audio file is selected pass along every audio file
-      // in the directory.
-      var selectedUrl = urls[0];
-      urls = fm.getAllUrlsInCurrentDirectory().filter(FileType.isAudio);
-      position = urls.indexOf(selectedUrl);
-    }
-    fm.backgroundPage.launchAudioPlayer({ items: urls, position: position });
-    return;
-  }
-
-  if (id == 'watch') {
-    console.assert(urls.length == 1, 'Cannot open multiple videos');
-    fm.backgroundPage.launchVideoPlayer(urls[0]);
-    return;
-  }
-
-  if (id == 'mount-archive') {
-    this.mountArchivesInternal_(urls);
-    return;
-  }
-
-  if (id == 'format-device') {
-    fm.confirm.show(loadTimeData.getString('FORMATTING_WARNING'), function() {
-      chrome.fileBrowserPrivate.formatDevice(urls[0]);
-    });
-    return;
-  }
-
-  if (id == 'gallery') {
-    this.openGalleryInternal_(urls);
-    return;
-  }
-
-  console.error('Unexpected action ID: ' + id);
-};
-
-/**
- * Mounts archives.
- *
- * @param {Array.<string>} urls Mount file urls list.
- */
-FileTasks.prototype.mountArchives = function(urls) {
-  FileTasks.recordViewingFileTypeUMA_(urls);
-  this.mountArchivesInternal_(urls);
-};
-
-/**
- * The core implementation of mounts archives.
- *
- * @param {Array.<string>} urls Mount file urls list.
- * @private
- */
-FileTasks.prototype.mountArchivesInternal_ = function(urls) {
-  var fm = this.fileManager_;
-
-  var tracker = fm.directoryModel_.createDirectoryChangeTracker();
-  tracker.start();
-
-  fm.resolveSelectResults_(urls, function(urls) {
-    for (var index = 0; index < urls.length; ++index) {
-      fm.volumeManager_.mountArchive(urls[index], function(mountPath) {
-        tracker.stop();
-        if (!tracker.hasChanged)
-          fm.directoryModel_.changeDirectory(mountPath);
-      }, function(url, error) {
-        var path = util.extractFilePath(url);
-        tracker.stop();
-        var namePos = path.lastIndexOf('/');
-        fm.alert.show(strf('ARCHIVE_MOUNT_FAILED',
-                           path.substr(namePos + 1), error));
-      }.bind(null, urls[index]));
-    }
-  });
-};
-
-/**
- * Open the Gallery.
- *
- * @param {Array.<string>} urls List of selected urls.
- */
-FileTasks.prototype.openGallery = function(urls) {
-  FileTasks.recordViewingFileTypeUMA_(urls);
-  this.openGalleryInternal_(urls);
-};
-
-/**
- * The core implementation to open the Gallery.
- *
- * @param {Array.<string>} urls List of selected urls.
- * @private
- */
-FileTasks.prototype.openGalleryInternal_ = function(urls) {
-  var fm = this.fileManager_;
-
-  var allUrls =
-      fm.getAllUrlsInCurrentDirectory().filter(FileType.isImageOrVideo);
-
-  var galleryFrame = fm.document_.createElement('iframe');
-  galleryFrame.className = 'overlay-pane';
-  galleryFrame.scrolling = 'no';
-  galleryFrame.setAttribute('webkitallowfullscreen', true);
-
-  if (this.params_ && this.params_.gallery) {
-    // Remove the Gallery state from the location, we do not need it any more.
-    util.updateAppState(null /* keep path */, '' /* remove search. */);
-  }
-
-  var savedAppState = window.appState;
-  var savedTitle = document.title;
-
-  // Push a temporary state which will be replaced every time the selection
-  // changes in the Gallery and popped when the Gallery is closed.
-  util.updateAppState();
-
-  var onBack = function(selectedUrls) {
-    fm.directoryModel_.selectUrls(selectedUrls);
-    fm.closeFilePopup_();  // Will call Gallery.unload.
-    window.appState = savedAppState;
-    util.saveAppState();
-    document.title = savedTitle;
-  };
-
-  var onClose = function() {
-    fm.onClose();
-  };
-
-  var onMaximize = function() {
-    fm.onMaximize();
-  };
-
-  galleryFrame.onload = function() {
-    galleryFrame.contentWindow.ImageUtil.metrics = metrics;
-
-    // TODO(haruki): isOnReadonlyDirectory() only checks the permission for the
-    // root. We should check more granular permission to know whether the file
-    // is writable or not.
-    var readonly = fm.isOnReadonlyDirectory();
-    var currentDir = fm.getCurrentDirectoryEntry();
-    var downloadsVolume =
-        fm.volumeManager_.getVolumeInfo(RootDirectory.DOWNLOADS);
-    var downloadsDir = downloadsVolume && downloadsVolume.root;
-    var readonlyDirName = null;
-    if (readonly && currentDir) {
-      var rootPath = PathUtil.getRootPath(currentDir.fullPath);
-      readonlyDirName = fm.isOnDrive() ?
-          PathUtil.getRootLabel(rootPath) :
-          PathUtil.basename(rootPath);
-    }
-
-    var context = {
-      // We show the root label in readonly warning (e.g. archive name).
-      readonlyDirName: readonlyDirName,
-      curDirEntry: currentDir,
-      saveDirEntry: readonly ? downloadsDir : null,
-      searchResults: fm.directoryModel_.isSearching(),
-      metadataCache: fm.metadataCache_,
-      pageState: this.params_,
-      appWindow: chrome.app.window.current(),
-      onBack: onBack,
-      onClose: onClose,
-      onMaximize: onMaximize,
-      displayStringFunction: strf
-    };
-    galleryFrame.contentWindow.Gallery.open(
-        context, fm.volumeManager_, allUrls, urls);
-  }.bind(this);
-
-  galleryFrame.src = 'gallery.html';
-  fm.openFilePopup_(galleryFrame, fm.updateTitle_.bind(fm));
-};
-
-/**
- * Displays the list of tasks in a task picker combobutton.
- *
- * @param {cr.ui.ComboButton} combobutton The task picker element.
- * @private
- */
-FileTasks.prototype.display_ = function(combobutton) {
-  if (this.tasks_.length == 0) {
-    combobutton.hidden = true;
-    return;
-  }
-
-  combobutton.clear();
-  combobutton.hidden = false;
-  combobutton.defaultItem = this.createCombobuttonItem_(this.defaultTask_);
-
-  var items = this.createItems_();
-
-  if (items.length > 1) {
-    var defaultIdx = 0;
-
-    for (var j = 0; j < items.length; j++) {
-      combobutton.addDropDownItem(items[j]);
-      if (items[j].task.taskId == this.defaultTask_.taskId)
-        defaultIdx = j;
-    }
-
-    combobutton.addSeparator();
-    var changeDefaultMenuItem = combobutton.addDropDownItem({
-        label: loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM')
-    });
-    changeDefaultMenuItem.classList.add('change-default');
-  }
-};
-
-/**
- * Creates sorted array of available task descriptions such as title and icon.
- *
- * @return {Array} created array can be used to feed combobox, menus and so on.
- * @private
- */
-FileTasks.prototype.createItems_ = function() {
-  var items = [];
-  var title = this.defaultTask_.title + ' ' +
-              loadTimeData.getString('DEFAULT_ACTION_LABEL');
-  items.push(this.createCombobuttonItem_(this.defaultTask_, title, true));
-
-  for (var index = 0; index < this.tasks_.length; index++) {
-    var task = this.tasks_[index];
-    if (task != this.defaultTask_)
-      items.push(this.createCombobuttonItem_(task));
-  }
-
-  items.sort(function(a, b) {
-    return a.label.localeCompare(b.label);
-  });
-
-  return items;
-};
-
-/**
- * Updates context menu with default item.
- * @private
- */
-
-FileTasks.prototype.updateMenuItem_ = function() {
-  this.fileManager_.updateContextMenuActionItems(this.defaultTask_,
-      this.tasks_.length > 1);
-};
-
-/**
- * Creates combobutton item based on task.
- *
- * @param {Object} task Task to convert.
- * @param {string=} opt_title Title.
- * @param {boolean=} opt_bold Make a menu item bold.
- * @return {Object} Item appendable to combobutton drop-down list.
- * @private
- */
-FileTasks.prototype.createCombobuttonItem_ = function(task, opt_title,
-                                                      opt_bold) {
-  return {
-    label: opt_title || task.title,
-    iconUrl: task.iconUrl,
-    iconType: task.iconType,
-    task: task,
-    bold: opt_bold || false
-  };
-};
-
-
-/**
- * Decorates a FileTasks method, so it will be actually executed after the tasks
- * are available.
- * This decorator expects an implementation called |method + '_'|.
- *
- * @param {string} method The method name.
- */
-FileTasks.decorate = function(method) {
-  var privateMethod = method + '_';
-  FileTasks.prototype[method] = function() {
-    if (this.tasks_) {
-      this[privateMethod].apply(this, arguments);
-    } else {
-      this.pendingInvocations_.push([privateMethod, arguments]);
-    }
-    return this;
-  };
-};
-
-/**
- * Shows modal action picker dialog with currently available list of tasks.
- *
- * @param {DefaultActionDialog} actionDialog Action dialog to show and update.
- * @param {string} title Title to use.
- * @param {string} message Message to use.
- * @param {function(Object)} onSuccess Callback to pass selected task.
- */
-FileTasks.prototype.showTaskPicker = function(actionDialog, title, message,
-                                              onSuccess) {
-  var items = this.createItems_();
-
-  var defaultIdx = 0;
-  for (var j = 0; j < items.length; j++) {
-    if (items[j].task.taskId == this.defaultTask_.taskId)
-      defaultIdx = j;
-  }
-
-  actionDialog.show(
-      title,
-      message,
-      items, defaultIdx,
-      function(item) {
-        onSuccess(item.task);
-      });
-};
-
-FileTasks.decorate('display');
-FileTasks.decorate('updateMenuItem');
-FileTasks.decorate('execute');
-FileTasks.decorate('executeDefault');
diff --git a/chrome/browser/resources/file_manager/js/file_transfer_controller.js b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
deleted file mode 100644
index 106ac0d..0000000
--- a/chrome/browser/resources/file_manager/js/file_transfer_controller.js
+++ /dev/null
@@ -1,832 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Global (placed in the window object) variable name to hold internal
- * file dragging information. Needed to show visual feedback while dragging
- * since DataTransfer object is in protected state. Reachable from other
- * file manager instances.
- */
-var DRAG_AND_DROP_GLOBAL_DATA = '__drag_and_drop_global_data';
-
-/**
- * @param {HTMLDocument} doc Owning document.
- * @param {FileOperationManager} fileOperationManager File operation manager
- *     instance.
- * @param {MetadataCache} metadataCache Metadata cache service.
- * @param {DirectoryModel} directoryModel Directory model instance.
- * @constructor
- */
-function FileTransferController(doc,
-                                fileOperationManager,
-                                metadataCache,
-                                directoryModel) {
-  this.document_ = doc;
-  this.fileOperationManager_ = fileOperationManager;
-  this.metadataCache_ = metadataCache;
-  this.directoryModel_ = directoryModel;
-
-  this.directoryModel_.getFileListSelection().addEventListener('change',
-      this.onSelectionChanged_.bind(this));
-
-  /**
-   * DOM element to represent selected file in drag operation. Used if only
-   * one element is selected.
-   * @type {HTMLElement}
-   * @private
-   */
-  this.preloadedThumbnailImageNode_ = null;
-
-  /**
-   * File objects for selected files.
-   *
-   * @type {Array.<File>}
-   * @private
-   */
-  this.selectedFileObjects_ = [];
-
-  /**
-   * Drag selector.
-   * @type {DragSelector}
-   * @private
-   */
-  this.dragSelector_ = new DragSelector();
-}
-
-FileTransferController.prototype = {
-  __proto__: cr.EventTarget.prototype,
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list Items in the list will be draggable.
-   */
-  attachDragSource: function(list) {
-    list.style.webkitUserDrag = 'element';
-    list.addEventListener('dragstart', this.onDragStart_.bind(this, list));
-    list.addEventListener('dragend', this.onDragEnd_.bind(this, list));
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list List itself and its directory items will could
-   *                          be drop target.
-   * @param {boolean=} opt_onlyIntoDirectories If true only directory list
-   *     items could be drop targets. Otherwise any other place of the list
-   *     accetps files (putting it into the current directory).
-   */
-  attachFileListDropTarget: function(list, opt_onlyIntoDirectories) {
-    list.addEventListener('dragover', this.onDragOver_.bind(this,
-        !!opt_onlyIntoDirectories, list));
-    list.addEventListener('dragenter',
-        this.onDragEnterFileList_.bind(this, list));
-    list.addEventListener('dragleave', this.onDragLeave_.bind(this, list));
-    list.addEventListener('drop',
-        this.onDrop_.bind(this, !!opt_onlyIntoDirectories));
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {DirectoryTree} tree Its sub items will could be drop target.
-   */
-  attachTreeDropTarget: function(tree) {
-    tree.addEventListener('dragover', this.onDragOver_.bind(this, true, tree));
-    tree.addEventListener('dragenter', this.onDragEnterTree_.bind(this, tree));
-    tree.addEventListener('dragleave', this.onDragLeave_.bind(this, tree));
-    tree.addEventListener('drop', this.onDrop_.bind(this, true));
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {NavigationList} tree Its sub items will could be drop target.
-   */
-  attachNavigationListDropTarget: function(list) {
-    list.addEventListener('dragover',
-        this.onDragOver_.bind(this, true /* onlyIntoDirectories */, list));
-    list.addEventListener('dragenter',
-        this.onDragEnterVolumesList_.bind(this, list));
-    list.addEventListener('dragleave', this.onDragLeave_.bind(this, list));
-    list.addEventListener('drop',
-        this.onDrop_.bind(this, true /* onlyIntoDirectories */));
-  },
-
-  /**
-   * Attach handlers of copy, cut and paste operations to the document.
-   *
-   * @this {FileTransferController}
-   */
-  attachCopyPasteHandlers: function() {
-    this.document_.addEventListener('beforecopy',
-                                    this.onBeforeCopy_.bind(this));
-    this.document_.addEventListener('copy',
-                                    this.onCopy_.bind(this));
-    this.document_.addEventListener('beforecut',
-                                    this.onBeforeCut_.bind(this));
-    this.document_.addEventListener('cut',
-                                    this.onCut_.bind(this));
-    this.document_.addEventListener('beforepaste',
-                                    this.onBeforePaste_.bind(this));
-    this.document_.addEventListener('paste',
-                                    this.onPaste_.bind(this));
-    this.copyCommand_ = this.document_.querySelector('command#copy');
-  },
-
-  /**
-   * Write the current selection to system clipboard.
-   *
-   * @this {FileTransferController}
-   * @param {DataTransfer} dataTransfer DataTransfer from the event.
-   * @param {string} effectAllowed Value must be valid for the
-   *     |dataTransfer.effectAllowed| property ('move', 'copy', 'copyMove').
-   */
-  cutOrCopy_: function(dataTransfer, effectAllowed) {
-    // Tag to check it's filemanager data.
-    dataTransfer.setData('fs/tag', 'filemanager-data');
-    dataTransfer.setData('fs/sourceRoot',
-                         this.directoryModel_.getCurrentRootPath());
-    var sourcePaths =
-        this.selectedEntries_.map(function(e) { return e.fullPath; });
-    dataTransfer.setData('fs/sources', sourcePaths.join('\n'));
-    dataTransfer.effectAllowed = effectAllowed;
-    dataTransfer.setData('fs/effectallowed', effectAllowed);
-
-    for (var i = 0; i < this.selectedFileObjects_.length; i++) {
-      dataTransfer.items.add(this.selectedFileObjects_[i]);
-    }
-  },
-
-  /**
-   * Extracts source root from the |dataTransfer| object.
-   *
-   * @this {FileTransferController}
-   * @param {DataTransfer} dataTransfer DataTransfer object from the event.
-   * @return {string} Path or empty string (if unknown).
-   */
-  getSourceRoot_: function(dataTransfer) {
-    var sourceRoot = dataTransfer.getData('fs/sourceRoot');
-    if (sourceRoot)
-      return sourceRoot;
-
-    // |dataTransfer| in protected mode.
-    if (window[DRAG_AND_DROP_GLOBAL_DATA])
-      return window[DRAG_AND_DROP_GLOBAL_DATA].sourceRoot;
-
-    // Dragging from other tabs/windows.
-    var views = chrome && chrome.extension ? chrome.extension.getViews() : [];
-    for (var i = 0; i < views.length; i++) {
-      if (views[i][DRAG_AND_DROP_GLOBAL_DATA])
-        return views[i][DRAG_AND_DROP_GLOBAL_DATA].sourceRoot;
-    }
-
-    // Unknown source.
-    return '';
-  },
-
-  /**
-   * Queue up a file copy operation based on the current system clipboard.
-   *
-   * @this {FileTransferController}
-   * @param {DataTransfer} dataTransfer System data transfer object.
-   * @param {string=} opt_destinationPath Paste destination.
-   * @param {string=} opt_effect Desired drop/paste effect. Could be
-   *     'move'|'copy' (default is copy). Ignored if conflicts with
-   *     |dataTransfer.effectAllowed|.
-   * @return {string} Either "copy" or "move".
-   */
-  paste: function(dataTransfer, opt_destinationPath, opt_effect) {
-    var sourcePaths = (dataTransfer.getData('fs/sources') || '').split('\n');
-    var destinationPath = opt_destinationPath ||
-                          this.currentDirectoryContentPath;
-    // effectAllowed set in copy/paste handlers stay uninitialized. DnD handlers
-    // work fine.
-    var effectAllowed = dataTransfer.effectAllowed != 'uninitialized' ?
-        dataTransfer.effectAllowed : dataTransfer.getData('fs/effectallowed');
-    var toMove = effectAllowed == 'move' ||
-        (effectAllowed == 'copyMove' && opt_effect == 'move');
-
-    // Start the pasting operation.
-    this.fileOperationManager_.paste(sourcePaths, destinationPath, toMove);
-    return toMove ? 'move' : 'copy';
-  },
-
-  /**
-   * Preloads an image thumbnail for the specified file entry.
-   *
-   * @this {FileTransferController}
-   * @param {Entry} entry Entry to preload a thumbnail for.
-   */
-  preloadThumbnailImage_: function(entry) {
-    var imageUrl = entry.toURL();
-    var metadataTypes = 'thumbnail|filesystem';
-    var thumbnailContainer = this.document_.createElement('div');
-    this.preloadedThumbnailImageNode_ = thumbnailContainer;
-    this.preloadedThumbnailImageNode_.className = 'img-container';
-    this.metadataCache_.get(
-        imageUrl,
-        metadataTypes,
-        function(metadata) {
-          new ThumbnailLoader(imageUrl,
-                              ThumbnailLoader.LoaderType.IMAGE,
-                              metadata).
-              load(thumbnailContainer,
-                   ThumbnailLoader.FillMode.FILL);
-        }.bind(this));
-  },
-
-  /**
-   * Renders a drag-and-drop thumbnail.
-   *
-   * @this {FileTransferController}
-   * @return {HTMLElement} Element containing the thumbnail.
-   */
-  renderThumbnail_: function() {
-    var length = this.selectedEntries_.length;
-
-    var container = this.document_.querySelector('#drag-container');
-    var contents = this.document_.createElement('div');
-    contents.className = 'drag-contents';
-    container.appendChild(contents);
-
-    var thumbnailImage;
-    if (this.preloadedThumbnailImageNode_)
-      thumbnailImage = this.preloadedThumbnailImageNode_.querySelector('img');
-
-    // Option 1. Multiple selection, render only a label.
-    if (length > 1) {
-      var label = this.document_.createElement('div');
-      label.className = 'label';
-      label.textContent = strf('DRAGGING_MULTIPLE_ITEMS', length);
-      contents.appendChild(label);
-      return container;
-    }
-
-    // Option 2. Thumbnail image available, then render it without
-    // a label.
-    if (thumbnailImage) {
-      thumbnailImage.classList.add('drag-thumbnail');
-      contents.classList.add('for-image');
-      contents.appendChild(this.preloadedThumbnailImageNode_);
-      return container;
-    }
-
-    // Option 3. Thumbnail not available. Render an icon and a label.
-    var entry = this.selectedEntries_[0];
-    var icon = this.document_.createElement('div');
-    icon.className = 'detail-icon';
-    icon.setAttribute('file-type-icon', FileType.getIcon(entry));
-    contents.appendChild(icon);
-    var label = this.document_.createElement('div');
-    label.className = 'label';
-    label.textContent = entry.name;
-    contents.appendChild(label);
-    return container;
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list Drop target list
-   * @param {Event} event A dragstart event of DOM.
-   */
-  onDragStart_: function(list, event) {
-    // Check if a drag selection should be initiated or not.
-    if (list.shouldStartDragSelection(event)) {
-      this.dragSelector_.startDragSelection(list, event);
-      return;
-    }
-
-    // Nothing selected.
-    if (!this.selectedEntries_.length) {
-      event.preventDefault();
-      return;
-    }
-
-    var dt = event.dataTransfer;
-
-    if (this.canCopyOrDrag_(dt)) {
-      if (this.canCutOrDrag_(dt))
-        this.cutOrCopy_(dt, 'copyMove');
-      else
-        this.cutOrCopy_(dt, 'copy');
-    } else {
-      event.preventDefault();
-      return;
-    }
-
-    var dragThumbnail = this.renderThumbnail_();
-    dt.setDragImage(dragThumbnail, 1000, 1000);
-
-    window[DRAG_AND_DROP_GLOBAL_DATA] = {
-      sourceRoot: this.directoryModel_.getCurrentRootPath()
-    };
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list Drop target list.
-   * @param {Event} event A dragend event of DOM.
-   */
-  onDragEnd_: function(list, event) {
-    var container = this.document_.querySelector('#drag-container');
-    container.textContent = '';
-    this.clearDropTarget_();
-    delete window[DRAG_AND_DROP_GLOBAL_DATA];
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {boolean} onlyIntoDirectories True if the drag is only into
-   *     directories.
-   * @param {cr.ui.List} list Drop target list.
-   * @param {Event} event A dragover event of DOM.
-   */
-  onDragOver_: function(onlyIntoDirectories, list, event) {
-    event.preventDefault();
-    var path = this.destinationPath_ ||
-        (!onlyIntoDirectories && this.currentDirectoryContentPath);
-    event.dataTransfer.dropEffect = this.selectDropEffect_(event, path);
-    event.preventDefault();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list Drop target list.
-   * @param {Event} event A dragenter event of DOM.
-   */
-  onDragEnterFileList_: function(list, event) {
-    event.preventDefault();  // Required to prevent the cursor flicker.
-    this.lastEnteredTarget_ = event.target;
-    var item = list.getListItemAncestor(event.target);
-    item = item && list.isItem(item) ? item : null;
-    if (item == this.dropTarget_)
-      return;
-
-    var entry = item && list.dataModel.item(item.listIndex);
-    if (entry) {
-      this.setDropTarget_(item, entry.isDirectory, event.dataTransfer,
-          entry.fullPath);
-    } else {
-      this.clearDropTarget_();
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {DirectoryTree} tree Drop target tree.
-   * @param {Event} event A dragenter event of DOM.
-   */
-  onDragEnterTree_: function(tree, event) {
-    event.preventDefault();  // Required to prevent the cursor flicker.
-    this.lastEnteredTarget_ = event.target;
-    var item = event.target;
-    while (item && !(item instanceof DirectoryItem)) {
-      item = item.parentNode;
-    }
-
-    if (item == this.dropTarget_)
-      return;
-
-    var entry = item && item.entry;
-    if (entry) {
-      this.setDropTarget_(item, entry.isDirectory, event.dataTransfer,
-          entry.fullPath);
-    } else {
-      this.clearDropTarget_();
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {NavigationList} list Drop target list.
-   * @param {Event} event A dragenter event of DOM.
-   */
-  onDragEnterVolumesList_: function(list, event) {
-    event.preventDefault();  // Required to prevent the cursor flicker.
-    this.lastEnteredTarget_ = event.target;
-    var item = list.getListItemAncestor(event.target);
-    item = item && list.isItem(item) ? item : null;
-    if (item == this.dropTarget_)
-      return;
-
-    var path = item && list.dataModel.item(item.listIndex).path;
-    if (path)
-      this.setDropTarget_(item, true /* directory */, event.dataTransfer, path);
-    else
-      this.clearDropTarget_();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {cr.ui.List} list Drop target list.
-   * @param {Event} event A dragleave event of DOM.
-   */
-  onDragLeave_: function(list, event) {
-    // If mouse moves from one element to another the 'dragenter'
-    // event for the new element comes before the 'dragleave' event for
-    // the old one. In this case event.target != this.lastEnteredTarget_
-    // and handler of the 'dragenter' event has already caried of
-    // drop target. So event.target == this.lastEnteredTarget_
-    // could only be if mouse goes out of listened element.
-    if (event.target == this.lastEnteredTarget_) {
-      this.clearDropTarget_();
-      this.lastEnteredTarget_ = null;
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {boolean} onlyIntoDirectories True if the drag is only into
-   *     directories.
-   * @param {Event} event A dragleave event of DOM.
-   */
-  onDrop_: function(onlyIntoDirectories, event) {
-    if (onlyIntoDirectories && !this.dropTarget_)
-      return;
-    var destinationPath = this.destinationPath_ ||
-                          this.currentDirectoryContentPath;
-    if (!this.canPasteOrDrop_(event.dataTransfer, destinationPath))
-      return;
-    event.preventDefault();
-    this.paste(event.dataTransfer, destinationPath,
-               this.selectDropEffect_(event, destinationPath));
-    this.clearDropTarget_();
-  },
-
-  /**
-   * Sets the drop target.
-   * @this {FileTransferController}
-   * @param {Element} domElement Target of the drop.
-   * @param {boolean} isDirectory If the target is a directory.
-   * @param {DataTransfer} dataTransfer Data transfer object.
-   * @param {string} destinationPath Destination path.
-   */
-  setDropTarget_: function(domElement, isDirectory, dataTransfer,
-                           destinationPath) {
-    if (this.dropTarget_ == domElement)
-      return;
-
-    // Remove the old drop target.
-    this.clearDropTarget_();
-
-    // Set the new drop target.
-    this.dropTarget_ = domElement;
-
-    if (!domElement ||
-        !isDirectory ||
-        !this.canPasteOrDrop_(dataTransfer, destinationPath)) {
-      return;
-    }
-
-    // Add accept class if the domElement can accept the drag.
-    domElement.classList.add('accepts');
-    this.destinationPath_ = destinationPath;
-
-    // Start timer changing the directory.
-    this.navigateTimer_ = setTimeout(function() {
-      if (domElement instanceof DirectoryItem)
-        // Do custom action.
-        (/** @type {DirectoryItem} */ domElement).doDropTargetAction();
-      this.directoryModel_.changeDirectory(destinationPath);
-    }.bind(this), 2000);
-  },
-
-  /**
-   * Clears the drop target.
-   * @this {FileTransferController}
-   */
-  clearDropTarget_: function() {
-    if (this.dropTarget_ && this.dropTarget_.classList.contains('accepts'))
-      this.dropTarget_.classList.remove('accepts');
-    this.dropTarget_ = null;
-    this.destinationPath_ = null;
-    if (this.navigateTimer_ !== undefined) {
-      clearTimeout(this.navigateTimer_);
-      this.navigateTimer_ = undefined;
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {boolean} Returns false if {@code <input type="text">} element is
-   *     currently active. Otherwise, returns true.
-   */
-  isDocumentWideEvent_: function() {
-    return this.document_.activeElement.nodeName.toLowerCase() != 'input' ||
-        this.document_.activeElement.type.toLowerCase() != 'text';
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onCopy_: function(event) {
-    if (!this.isDocumentWideEvent_() ||
-        !this.canCopyOrDrag_()) {
-      return;
-    }
-    event.preventDefault();
-    this.cutOrCopy_(event.clipboardData, 'copy');
-    this.notify_('selection-copied');
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onBeforeCopy_: function(event) {
-    if (!this.isDocumentWideEvent_())
-      return;
-
-    // queryCommandEnabled returns true if event.defaultPrevented is true.
-    if (this.canCopyOrDrag_())
-      event.preventDefault();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {boolean} Returns true if some files are selected and all the file
-   *     on drive is available to be copied. Otherwise, returns false.
-   */
-  canCopyOrDrag_: function() {
-    if (this.isOnDrive &&
-        this.directoryModel_.isDriveOffline() &&
-        !this.allDriveFilesAvailable)
-      return false;
-    return this.selectedEntries_.length > 0;
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onCut_: function(event) {
-    if (!this.isDocumentWideEvent_() ||
-        !this.canCutOrDrag_()) {
-      return;
-    }
-    event.preventDefault();
-    this.cutOrCopy_(event.clipboardData, 'move');
-    this.notify_('selection-cut');
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onBeforeCut_: function(event) {
-    if (!this.isDocumentWideEvent_())
-      return;
-    // queryCommandEnabled returns true if event.defaultPrevented is true.
-    if (this.canCutOrDrag_())
-      event.preventDefault();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {boolean} Returns true if some files are selected and all the file
-   *     on drive is available to be cut. Otherwise, returns false.
-   */
-  canCutOrDrag_: function() {
-    return !this.readonly && this.canCopyOrDrag_();
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onPaste_: function(event) {
-    // Need to update here since 'beforepaste' doesn't fire.
-    if (!this.isDocumentWideEvent_() ||
-        !this.canPasteOrDrop_(event.clipboardData,
-                              this.currentDirectoryContentPath)) {
-      return;
-    }
-    event.preventDefault();
-    var effect = this.paste(event.clipboardData);
-
-    // On cut, we clear the clipboard after the file is pasted/moved so we don't
-    // try to move/delete the original file again.
-    if (effect == 'move') {
-      this.simulateCommand_('cut', function(event) {
-        event.preventDefault();
-        event.clipboardData.setData('fs/clear', '');
-      });
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onBeforePaste_: function(event) {
-    if (!this.isDocumentWideEvent_())
-      return;
-    // queryCommandEnabled returns true if event.defaultPrevented is true.
-    if (this.canPasteOrDrop_(event.clipboardData,
-                             this.currentDirectoryContentPath)) {
-      event.preventDefault();
-    }
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @param {DataTransfer} dataTransfer Data transfer object.
-   * @param {string?} destinationPath Destination path.
-   * @return {boolean} Returns true if items stored in {@code dataTransfer} can
-   *     be pasted to {@code destinationPath}. Otherwise, returns false.
-   */
-  canPasteOrDrop_: function(dataTransfer, destinationPath) {
-    if (!destinationPath) {
-      return false;
-    }
-    if (this.directoryModel_.isPathReadOnly(destinationPath)) {
-      return false;
-    }
-    if (!dataTransfer.types || dataTransfer.types.indexOf('fs/tag') == -1) {
-      return false;  // Unsupported type of content.
-    }
-    if (dataTransfer.getData('fs/tag') == '') {
-      // Data protected. Other checks are not possible but it makes sense to
-      // let the user try.
-      return true;
-    }
-
-    var directories = dataTransfer.getData('fs/directories').split('\n').
-                      filter(function(d) { return d != ''; });
-
-    for (var i = 0; i < directories.length; i++) {
-      if (destinationPath.substr(0, directories[i].length) == directories[i])
-        return false;  // recursive paste.
-    }
-
-    return true;
-  },
-
-  /**
-   * Execute paste command.
-   *
-   * @this {FileTransferController}
-   * @return {boolean}  Returns true, the paste is success. Otherwise, returns
-   *     false.
-   */
-  queryPasteCommandEnabled: function() {
-    if (!this.isDocumentWideEvent_()) {
-      return false;
-    }
-
-    // HACK(serya): return this.document_.queryCommandEnabled('paste')
-    // should be used.
-    var result;
-    this.simulateCommand_('paste', function(event) {
-      result = this.canPasteOrDrop_(event.clipboardData,
-                                    this.currentDirectoryContentPath);
-    }.bind(this));
-    return result;
-  },
-
-  /**
-   * Allows to simulate commands to get access to clipboard.
-   *
-   * @this {FileTransferController}
-   * @param {string} command 'copy', 'cut' or 'paste'.
-   * @param {function} handler Event handler.
-   */
-  simulateCommand_: function(command, handler) {
-    var iframe = this.document_.querySelector('#command-dispatcher');
-    var doc = iframe.contentDocument;
-    doc.addEventListener(command, handler);
-    doc.execCommand(command);
-    doc.removeEventListener(command, handler);
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  onSelectionChanged_: function(event) {
-    var entries = this.selectedEntries_;
-    var files = this.selectedFileObjects_ = [];
-    this.preloadedThumbnailImageNode_ = null;
-
-    var fileEntries = [];
-    for (var i = 0; i < entries.length; i++) {
-      if (entries[i].isFile)
-        fileEntries.push(entries[i]);
-    }
-
-    if (entries.length == 1) {
-      // For single selection, the dragged element is created in advance,
-      // otherwise an image may not be loaded at the time the 'dragstart' event
-      // comes.
-      this.preloadThumbnailImage_(entries[0]);
-    }
-
-    // File object must be prepeared in advance for clipboard operations
-    // (copy, paste and drag). DataTransfer object closes for write after
-    // returning control from that handlers so they may not have
-    // asynchronous operations.
-    var prepareFileObjects = function() {
-      for (var i = 0; i < fileEntries.length; i++) {
-        fileEntries[i].file(function(file) { files.push(file); });
-      }
-    };
-
-    if (this.isOnDrive) {
-      this.allDriveFilesAvailable = false;
-      var urls = entries.map(function(e) { return e.toURL() });
-      this.metadataCache_.get(
-          urls, 'drive', function(props) {
-        // We consider directories not available offline for the purposes of
-        // file transfer since we cannot afford to recursive traversal.
-        this.allDriveFilesAvailable =
-            entries.filter(function(e) {return e.isDirectory}).length == 0 &&
-            props.filter(function(p) {return !p.availableOffline}).length == 0;
-        // |Copy| is the only menu item affected by allDriveFilesAvailable.
-        // It could be open right now, update its UI.
-        this.copyCommand_.disabled = !this.canCopyOrDrag_();
-
-        if (this.allDriveFilesAvailable)
-          prepareFileObjects();
-      }.bind(this));
-    } else {
-      prepareFileObjects();
-    }
-  },
-
-  /**
-   * Path of directory that is displaying now.
-   * If search result is displaying now, this is null.
-   * @this {FileTransferController}
-   * @return {string} Path of directry that is displaying now.
-   */
-  get currentDirectoryContentPath() {
-    return this.directoryModel_.isSearching() ?
-        null : this.directoryModel_.getCurrentDirPath();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {boolean} True if the current directory is read only.
-   */
-  get readonly() {
-    return this.directoryModel_.isReadOnly();
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {boolean} True if the current directory is on Drive.
-   */
-  get isOnDrive() {
-    return PathUtil.isDriveBasedPath(this.directoryModel_.getCurrentRootPath());
-  },
-
-  /**
-   * @this {FileTransferController}
-   */
-  notify_: function(eventName) {
-    var self = this;
-    // Set timeout to avoid recursive events.
-    setTimeout(function() {
-      cr.dispatchSimpleEvent(self, eventName);
-    }, 0);
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {Array.<Entry>} Array of the selected entries.
-   */
-  get selectedEntries_() {
-    var list = this.directoryModel_.getFileList();
-    var selectedIndexes = this.directoryModel_.getFileListSelection().
-                               selectedIndexes;
-    var entries = selectedIndexes.map(function(index) {
-      return list.item(index);
-    });
-
-    // TODO(serya): Diagnostics for http://crbug/129642
-    if (entries.indexOf(undefined) != -1) {
-      var index = entries.indexOf(undefined);
-      entries = entries.filter(function(e) { return !!e; });
-      console.error('Invalid selection found: list items: ', list.length,
-                    'wrong indexe value: ', selectedIndexes[index],
-                    'Stack trace: ', new Error().stack);
-    }
-    return entries;
-  },
-
-  /**
-   * @this {FileTransferController}
-   * @return {string}  Returns the appropriate drop query type ('none', 'move'
-   *     or copy') to the current modifiers status and the destination.
-   */
-  selectDropEffect_: function(event, destinationPath) {
-    if (!destinationPath ||
-        this.directoryModel_.isPathReadOnly(destinationPath))
-      return 'none';
-    if (event.dataTransfer.effectAllowed == 'copyMove' &&
-        this.getSourceRoot_(event.dataTransfer) ==
-            PathUtil.getRootPath(destinationPath) &&
-        !event.ctrlKey) {
-      return 'move';
-    }
-    if (event.dataTransfer.effectAllowed == 'copyMove' &&
-        event.shiftKey) {
-      return 'move';
-    }
-    return 'copy';
-  },
-};
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js b/chrome/browser/resources/file_manager/js/image_editor/image_editor.js
deleted file mode 100644
index 29858cf..0000000
--- a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js
+++ /dev/null
@@ -1,1162 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * ImageEditor is the top level object that holds together and connects
- * everything needed for image editing.
- * @param {Viewport} viewport The viewport.
- * @param {ImageView} imageView The ImageView containing the images to edit.
- * @param {ImageEditor.Prompt} prompt Prompt instance.
- * @param {Object} DOMContainers Various DOM containers required for the editor.
- * @param {Array.<ImageEditor.Mode>} modes Available editor modes.
- * @param {function} displayStringFunction String formatting function.
- * @constructor
- */
-function ImageEditor(
-    viewport, imageView, prompt, DOMContainers, modes, displayStringFunction) {
-  this.rootContainer_ = DOMContainers.root;
-  this.container_ = DOMContainers.image;
-  this.modes_ = modes;
-  this.displayStringFunction_ = displayStringFunction;
-
-  ImageUtil.removeChildren(this.container_);
-
-  var document = this.container_.ownerDocument;
-
-  this.viewport_ = viewport;
-  this.viewport_.sizeByFrame(this.container_);
-
-  this.buffer_ = new ImageBuffer();
-  this.viewport_.addRepaintCallback(this.buffer_.draw.bind(this.buffer_));
-
-  this.imageView_ = imageView;
-  this.imageView_.addContentCallback(this.onContentUpdate_.bind(this));
-  this.buffer_.addOverlay(this.imageView_);
-
-  this.panControl_ = new ImageEditor.MouseControl(
-      this.rootContainer_, this.container_, this.getBuffer());
-
-  this.panControl_.setDoubleTapCallback(this.onDoubleTap_.bind(this));
-
-  this.mainToolbar_ = new ImageEditor.Toolbar(
-      DOMContainers.toolbar, displayStringFunction);
-
-  this.modeToolbar_ = new ImageEditor.Toolbar(
-      DOMContainers.mode, displayStringFunction,
-      this.onOptionsChange.bind(this));
-
-  this.prompt_ = prompt;
-
-  this.createToolButtons();
-
-  this.commandQueue_ = null;
-}
-
-/**
- * @return {boolean} True if no user commands are to be accepted.
- */
-ImageEditor.prototype.isLocked = function() {
-  return !this.commandQueue_ || this.commandQueue_.isBusy();
-};
-
-/**
- * @return {boolean} True if the command queue is busy.
- */
-ImageEditor.prototype.isBusy = function() {
-  return this.commandQueue_ && this.commandQueue_.isBusy();
-};
-
-/**
- * Reflect the locked state of the editor in the UI.
- * @param {boolean} on True if locked.
- */
-ImageEditor.prototype.lockUI = function(on) {
-  ImageUtil.setAttribute(this.rootContainer_, 'locked', on);
-};
-
-/**
- * Report the tool use to the metrics subsystem.
- * @param {string} name Action name.
- */
-ImageEditor.prototype.recordToolUse = function(name) {
-  ImageUtil.metrics.recordEnum(
-      ImageUtil.getMetricName('Tool'), name, this.actionNames_);
-};
-
-/**
- * Content update handler.
- * @private
- */
-ImageEditor.prototype.onContentUpdate_ = function() {
-  for (var i = 0; i != this.modes_.length; i++) {
-    var mode = this.modes_[i];
-    ImageUtil.setAttribute(mode.button_, 'disabled', !mode.isApplicable());
-  }
-};
-
-/**
- * Open the editing session for a new image.
- *
- * @param {string} url Image url.
- * @param {Object} metadata Metadata.
- * @param {Object} effect Transition effect object.
- * @param {function(function)} saveFunction Image save function.
- * @param {function} displayCallback Display callback.
- * @param {function} loadCallback Load callback.
- */
-ImageEditor.prototype.openSession = function(
-    url, metadata, effect, saveFunction, displayCallback, loadCallback) {
-  if (this.commandQueue_)
-    throw new Error('Session not closed');
-
-  this.lockUI(true);
-
-  var self = this;
-  this.imageView_.load(
-      url, metadata, effect, displayCallback, function(loadType, delay, error) {
-    self.lockUI(false);
-    self.commandQueue_ = new CommandQueue(
-        self.container_.ownerDocument,
-        self.imageView_.getCanvas(),
-        saveFunction);
-    self.commandQueue_.attachUI(
-        self.getImageView(), self.getPrompt(), self.lockUI.bind(self));
-    self.updateUndoRedo();
-    loadCallback(loadType, delay, error);
-  });
-};
-
-/**
- * Close the current image editing session.
- * @param {function} callback Callback.
- */
-ImageEditor.prototype.closeSession = function(callback) {
-  this.getPrompt().hide();
-  if (this.imageView_.isLoading()) {
-    if (this.commandQueue_) {
-      console.warn('Inconsistent image editor state');
-      this.commandQueue_ = null;
-    }
-    this.imageView_.cancelLoad();
-    this.lockUI(false);
-    callback();
-    return;
-  }
-  if (!this.commandQueue_) {
-    // Session is already closed.
-    callback();
-    return;
-  }
-
-  this.executeWhenReady(callback);
-  this.commandQueue_.close();
-  this.commandQueue_ = null;
-};
-
-/**
- * Commit the current operation and execute the action.
- *
- * @param {function} callback Callback.
- */
-ImageEditor.prototype.executeWhenReady = function(callback) {
-  if (this.commandQueue_) {
-    this.leaveModeGently();
-    this.commandQueue_.executeWhenReady(callback);
-  } else {
-    if (!this.imageView_.isLoading())
-      console.warn('Inconsistent image editor state');
-    callback();
-  }
-};
-
-/**
- * @return {boolean} True if undo queue is not empty.
- */
-ImageEditor.prototype.canUndo = function() {
-  return this.commandQueue_ && this.commandQueue_.canUndo();
-};
-
-/**
- * Undo the recently executed command.
- */
-ImageEditor.prototype.undo = function() {
-  if (this.isLocked()) return;
-  this.recordToolUse('undo');
-
-  // First undo click should dismiss the uncommitted modifications.
-  if (this.currentMode_ && this.currentMode_.isUpdated()) {
-    this.currentMode_.reset();
-    return;
-  }
-
-  this.getPrompt().hide();
-  this.leaveMode(false);
-  this.commandQueue_.undo();
-  this.updateUndoRedo();
-};
-
-/**
- * Redo the recently un-done command.
- */
-ImageEditor.prototype.redo = function() {
-  if (this.isLocked()) return;
-  this.recordToolUse('redo');
-  this.getPrompt().hide();
-  this.leaveMode(false);
-  this.commandQueue_.redo();
-  this.updateUndoRedo();
-};
-
-/**
- * Update Undo/Redo buttons state.
- */
-ImageEditor.prototype.updateUndoRedo = function() {
-  var canUndo = this.commandQueue_ && this.commandQueue_.canUndo();
-  var canRedo = this.commandQueue_ && this.commandQueue_.canRedo();
-  ImageUtil.setAttribute(this.undoButton_, 'disabled', !canUndo);
-  this.redoButton_.hidden = !canRedo;
-};
-
-/**
- * @return {HTMLCanvasElement} The current image canvas.
- */
-ImageEditor.prototype.getCanvas = function() {
-  return this.getImageView().getCanvas();
-};
-
-/**
- * @return {ImageBuffer} ImageBuffer instance.
- */
-ImageEditor.prototype.getBuffer = function() { return this.buffer_ };
-
-/**
- * @return {ImageView} ImageView instance.
- */
-ImageEditor.prototype.getImageView = function() { return this.imageView_ };
-
-/**
- * @return {Viewport} Viewport instance.
- */
-ImageEditor.prototype.getViewport = function() { return this.viewport_ };
-
-/**
- * @return {ImageEditor.Prompt} Prompt instance.
- */
-ImageEditor.prototype.getPrompt = function() { return this.prompt_ };
-
-/**
- * Handle the toolbar controls update.
- * @param {Object} options A map of options.
- */
-ImageEditor.prototype.onOptionsChange = function(options) {
-  ImageUtil.trace.resetTimer('update');
-  if (this.currentMode_) {
-    this.currentMode_.update(options);
-  }
-  ImageUtil.trace.reportTimer('update');
-};
-
-/**
- * ImageEditor.Mode represents a modal state dedicated to a specific operation.
- * Inherits from ImageBuffer. Overlay to simplify the drawing of mode-specific
- * tools.
- *
- * @param {string} name The mode name.
- * @param {string} title The mode title.
- * @constructor
- */
-
-ImageEditor.Mode = function(name, title) {
-  this.name = name;
-  this.title = title;
-  this.message_ = 'GALLERY_ENTER_WHEN_DONE';
-};
-
-ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype };
-
-/**
- * @return {Viewport} Viewport instance.
- */
-ImageEditor.Mode.prototype.getViewport = function() { return this.viewport_ };
-
-/**
- * @return {ImageView} ImageView instance.
- */
-ImageEditor.Mode.prototype.getImageView = function() { return this.imageView_ };
-
-/**
- * @return {string} The mode-specific message to be displayed when entering.
- */
-ImageEditor.Mode.prototype.getMessage = function() { return this.message_ };
-
-/**
- * @return {boolean} True if the mode is applicable in the current context.
- */
-ImageEditor.Mode.prototype.isApplicable = function() { return true };
-
-/**
- * Called once after creating the mode button.
- *
- * @param {ImageEditor} editor The editor instance.
- * @param {HTMLElement} button The mode button.
- */
-
-ImageEditor.Mode.prototype.bind = function(editor, button) {
-  this.editor_ = editor;
-  this.editor_.registerAction_(this.name);
-  this.button_ = button;
-  this.viewport_ = editor.getViewport();
-  this.imageView_ = editor.getImageView();
-};
-
-/**
- * Called before entering the mode.
- */
-ImageEditor.Mode.prototype.setUp = function() {
-  this.editor_.getBuffer().addOverlay(this);
-  this.updated_ = false;
-};
-
-/**
- * Create mode-specific controls here.
- * @param {ImageEditor.Toolbar} toolbar The toolbar to populate.
- */
-ImageEditor.Mode.prototype.createTools = function(toolbar) {};
-
-/**
- * Called before exiting the mode.
- */
-ImageEditor.Mode.prototype.cleanUpUI = function() {
-  this.editor_.getBuffer().removeOverlay(this);
-};
-
-/**
- * Called after exiting the mode.
- */
-ImageEditor.Mode.prototype.cleanUpCaches = function() {};
-
-/**
- * Called when any of the controls changed its value.
- * @param {Object} options A map of options.
- */
-ImageEditor.Mode.prototype.update = function(options) {
-  this.markUpdated();
-};
-
-/**
- * Mark the editor mode as updated.
- */
-ImageEditor.Mode.prototype.markUpdated = function() {
-  this.updated_ = true;
-};
-
-/**
- * @return {boolean} True if the mode controls changed.
- */
-ImageEditor.Mode.prototype.isUpdated = function() { return this.updated_ };
-
-/**
- * Resets the mode to a clean state.
- */
-ImageEditor.Mode.prototype.reset = function() {
-  this.editor_.modeToolbar_.reset();
-  this.updated_ = false;
-};
-
-/**
- * One-click editor tool, requires no interaction, just executes the command.
- *
- * @param {string} name The mode name.
- * @param {string} title The mode title.
- * @param {Command} command The command to execute on click.
- * @constructor
- */
-ImageEditor.Mode.OneClick = function(name, title, command) {
-  ImageEditor.Mode.call(this, name, title);
-  this.instant = true;
-  this.command_ = command;
-};
-
-ImageEditor.Mode.OneClick.prototype = {__proto__: ImageEditor.Mode.prototype};
-
-/**
- * @return {Command} command.
- */
-ImageEditor.Mode.OneClick.prototype.getCommand = function() {
-  return this.command_;
-};
-
-/**
- * Register the action name. Required for metrics reporting.
- * @param {string} name Button name.
- * @private
- */
-ImageEditor.prototype.registerAction_ = function(name) {
-  this.actionNames_.push(name);
-};
-
-/**
- * Populate the toolbar.
- */
-ImageEditor.prototype.createToolButtons = function() {
-  this.mainToolbar_.clear();
-  this.actionNames_ = [];
-
-  var self = this;
-  function createButton(name, title, handler) {
-    return self.mainToolbar_.addButton(name,
-                                       title,
-                                       handler,
-                                       name /* opt_className */);
-  }
-
-  for (var i = 0; i != this.modes_.length; i++) {
-    var mode = this.modes_[i];
-    mode.bind(this, createButton(mode.name,
-                                 mode.title,
-                                 this.enterMode.bind(this, mode)));
-  }
-
-  this.undoButton_ = createButton('undo',
-                                  'GALLERY_UNDO',
-                                  this.undo.bind(this));
-  this.registerAction_('undo');
-
-  this.redoButton_ = createButton('redo',
-                                  'GALLERY_REDO',
-                                  this.redo.bind(this));
-  this.registerAction_('redo');
-};
-
-/**
- * @return {ImageEditor.Mode} The current mode.
- */
-ImageEditor.prototype.getMode = function() { return this.currentMode_ };
-
-/**
- * The user clicked on the mode button.
- *
- * @param {ImageEditor.Mode} mode The new mode.
- */
-ImageEditor.prototype.enterMode = function(mode) {
-  if (this.isLocked()) return;
-
-  if (this.currentMode_ == mode) {
-    // Currently active editor tool clicked, commit if modified.
-    this.leaveMode(this.currentMode_.updated_);
-    return;
-  }
-
-  this.recordToolUse(mode.name);
-
-  this.leaveModeGently();
-  // The above call could have caused a commit which might have initiated
-  // an asynchronous command execution. Wait for it to complete, then proceed
-  // with the mode set up.
-  this.commandQueue_.executeWhenReady(this.setUpMode_.bind(this, mode));
-};
-
-/**
- * Set up the new editing mode.
- *
- * @param {ImageEditor.Mode} mode The mode.
- * @private
- */
-ImageEditor.prototype.setUpMode_ = function(mode) {
-  this.currentTool_ = mode.button_;
-
-  ImageUtil.setAttribute(this.currentTool_, 'pressed', true);
-
-  this.currentMode_ = mode;
-  this.currentMode_.setUp();
-
-  if (this.currentMode_.instant) {  // Instant tool.
-    this.leaveMode(true);
-    return;
-  }
-
-  this.getPrompt().show(this.currentMode_.getMessage());
-
-  this.modeToolbar_.clear();
-  this.currentMode_.createTools(this.modeToolbar_);
-  this.modeToolbar_.show(true);
-};
-
-/**
- * The user clicked on 'OK' or 'Cancel' or on a different mode button.
- * @param {boolean} commit True if commit is required.
- */
-ImageEditor.prototype.leaveMode = function(commit) {
-  if (!this.currentMode_) return;
-
-  if (!this.currentMode_.instant) {
-    this.getPrompt().hide();
-  }
-
-  this.modeToolbar_.show(false);
-
-  this.currentMode_.cleanUpUI();
-  if (commit) {
-    var self = this;
-    var command = this.currentMode_.getCommand();
-    if (command) {  // Could be null if the user did not do anything.
-      this.commandQueue_.execute(command);
-      this.updateUndoRedo();
-    }
-  }
-  this.currentMode_.cleanUpCaches();
-  this.currentMode_ = null;
-
-  ImageUtil.setAttribute(this.currentTool_, 'pressed', false);
-  this.currentTool_ = null;
-};
-
-/**
- * Leave the mode, commit only if required by the current mode.
- */
-ImageEditor.prototype.leaveModeGently = function() {
-  this.leaveMode(this.currentMode_ &&
-                 this.currentMode_.updated_ &&
-                 this.currentMode_.implicitCommit);
-};
-
-/**
- * Enter the editor mode with the given name.
- *
- * @param {string} name Mode name.
- * @private
- */
-ImageEditor.prototype.enterModeByName_ = function(name) {
-  for (var i = 0; i != this.modes_.length; i++) {
-    var mode = this.modes_[i];
-    if (mode.name == name) {
-      if (!mode.button_.hasAttribute('disabled'))
-        this.enterMode(mode);
-      return;
-    }
-  }
-  console.error('Mode "' + name + '" not found.');
-};
-
-/**
- * Key down handler.
- * @param {Event} event The keydown event.
- * @return {boolean} True if handled.
- */
-ImageEditor.prototype.onKeyDown = function(event) {
-  switch (util.getKeyModifiers(event) + event.keyIdentifier) {
-    case 'U+001B': // Escape
-    case 'Enter':
-      if (this.getMode()) {
-        this.leaveMode(event.keyIdentifier == 'Enter');
-        return true;
-      }
-      break;
-
-    case 'Ctrl-U+005A':  // Ctrl+Z
-      if (this.commandQueue_.canUndo()) {
-        this.undo();
-        return true;
-      }
-      break;
-
-    case 'Ctrl-U+0059':  // Ctrl+Y
-      if (this.commandQueue_.canRedo()) {
-        this.redo();
-        return true;
-      }
-      break;
-
-    case 'U+0041':  // 'a'
-      this.enterModeByName_('autofix');
-      return true;
-
-    case 'U+0042':  // 'b'
-      this.enterModeByName_('exposure');
-      return true;
-
-    case 'U+0043':  // 'c'
-      this.enterModeByName_('crop');
-      return true;
-
-    case 'U+004C':  // 'l'
-      this.enterModeByName_('rotate_left');
-      return true;
-
-    case 'U+0052':  // 'r'
-      this.enterModeByName_('rotate_right');
-      return true;
-
-  }
-  return false;
-};
-
-/**
- * Double tap handler.
- * @param {number} x X coordinate of the event.
- * @param {number} y Y coordinate of the event.
- * @private
- */
-ImageEditor.prototype.onDoubleTap_ = function(x, y) {
-  if (this.getMode()) {
-    var action = this.buffer_.getDoubleTapAction(x, y);
-    if (action == ImageBuffer.DoubleTapAction.COMMIT)
-      this.leaveMode(true);
-    else if (action == ImageBuffer.DoubleTapAction.CANCEL)
-      this.leaveMode(false);
-  }
-};
-
-/**
- * Hide the tools that overlap the given rectangular frame.
- *
- * @param {Rect} frame Hide the tool that overlaps this rect.
- * @param {Rect} transparent But do not hide the tool that is completely inside
- *                           this rect.
- */
-ImageEditor.prototype.hideOverlappingTools = function(frame, transparent) {
-  var tools = this.rootContainer_.ownerDocument.querySelectorAll('.dimmable');
-  for (var i = 0; i != tools.length; i++) {
-    var tool = tools[i];
-    var toolRect = tool.getBoundingClientRect();
-    ImageUtil.setAttribute(tool, 'dimmed',
-        (frame && frame.intersects(toolRect)) &&
-        !(transparent && transparent.contains(toolRect)));
-  }
-};
-
-/**
- * A helper object for panning the ImageBuffer.
- *
- * @param {HTMLElement} rootContainer The top-level container.
- * @param {HTMLElement} container The container for mouse events.
- * @param {ImageBuffer} buffer Image buffer.
- * @constructor
- */
-ImageEditor.MouseControl = function(rootContainer, container, buffer) {
-  this.rootContainer_ = rootContainer;
-  this.container_ = container;
-  this.buffer_ = buffer;
-
-  var handlers = {
-    'touchstart': this.onTouchStart,
-    'touchend': this.onTouchEnd,
-    'touchcancel': this.onTouchCancel,
-    'touchmove': this.onTouchMove,
-    'mousedown': this.onMouseDown,
-    'mouseup': this.onMouseUp
-  };
-
-  for (var eventName in handlers) {
-    container.addEventListener(
-        eventName, handlers[eventName].bind(this), false);
-  }
-
-  // Mouse move handler has to be attached to the window to receive events
-  // from outside of the window. See: http://crbug.com/155705
-  window.addEventListener('mousemove', this.onMouseMove.bind(this), false);
-};
-
-/**
- * Maximum movement for touch to be detected as a tap (in pixels).
- * @private
- */
-ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_ = 8;
-
-/**
- * Maximum time for touch to be detected as a tap (in milliseconds).
- * @private
- */
-ImageEditor.MouseControl.MAX_TAP_DURATION_ = 500;
-
-/**
- * Maximum distance from the first tap to the second tap to be considered
- * as a double tap.
- * @private
- */
-ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_ = 32;
-
-/**
- * Maximum time for touch to be detected as a double tap (in milliseconds).
- * @private
- */
-ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_ = 1000;
-
-/**
- * Returns an event's position.
- *
- * @param {MouseEvent|Touch} e Pointer position.
- * @return {Object} A pair of x,y in page coordinates.
- * @private
- */
-ImageEditor.MouseControl.getPosition_ = function(e) {
-  return {
-    x: e.pageX,
-    y: e.pageY
-  };
-};
-
-/**
- * Returns touch position or null if there is more than one touch position.
- *
- * @param {TouchEvent} e Event.
- * @return {object?} A pair of x,y in page coordinates.
- * @private
- */
-ImageEditor.MouseControl.prototype.getTouchPosition_ = function(e) {
-  if (e.targetTouches.length == 1)
-    return ImageEditor.MouseControl.getPosition_(e.targetTouches[0]);
-  else
-    return null;
-};
-
-/**
- * Touch start handler.
- * @param {TouchEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onTouchStart = function(e) {
-  var position = this.getTouchPosition_(e);
-  if (position) {
-    this.touchStartInfo_ = {
-      x: position.x,
-      y: position.y,
-      time: Date.now()
-    };
-    this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y,
-                                                    true /* touch */);
-    this.dragHappened_ = false;
-  }
-  e.preventDefault();
-};
-
-/**
- * Touch end handler.
- * @param {TouchEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onTouchEnd = function(e) {
-  if (!this.dragHappened_ && Date.now() - this.touchStartInfo_.time <=
-                             ImageEditor.MouseControl.MAX_TAP_DURATION_) {
-    this.buffer_.onClick(this.touchStartInfo_.x, this.touchStartInfo_.y);
-    if (this.previousTouchStartInfo_ &&
-        Date.now() - this.previousTouchStartInfo_.time <
-            ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_) {
-      var prevTouchCircle = new Circle(
-          this.previousTouchStartInfo_.x,
-          this.previousTouchStartInfo_.y,
-          ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_);
-      if (prevTouchCircle.inside(this.touchStartInfo_.x,
-                                 this.touchStartInfo_.y)) {
-        this.doubleTapCallback_(this.touchStartInfo_.x, this.touchStartInfo_.y);
-      }
-    }
-    this.previousTouchStartInfo_ = this.touchStartInfo_;
-  } else {
-    this.previousTouchStartInfo_ = null;
-  }
-  this.onTouchCancel(e);
-  e.preventDefault();
-};
-
-/**
- * Default double tap handler.
- * @param {number} x X coordinate of the event.
- * @param {number} y Y coordinate of the event.
- * @private
- */
-ImageEditor.MouseControl.prototype.doubleTapCallback_ = function(x, y) {};
-
-/**
- * Sets callback to be called when double tap detected.
- * @param {function(number, number)} callback New double tap callback.
- */
-ImageEditor.MouseControl.prototype.setDoubleTapCallback = function(callback) {
-  this.doubleTapCallback_ = callback;
-};
-
-/**
- * Touch chancel handler.
- */
-ImageEditor.MouseControl.prototype.onTouchCancel = function() {
-  this.dragHandler_ = null;
-  this.dragHappened_ = false;
-  this.touchStartInfo_ = null;
-  this.lockMouse_(false);
-};
-
-/**
- * Touch move handler.
- * @param {TouchEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onTouchMove = function(e) {
-  var position = this.getTouchPosition_(e);
-  if (!position)
-    return;
-
-  if (this.touchStartInfo_ && !this.dragHappened_) {
-    var tapCircle = new Circle(this.touchStartInfo_.x, this.touchStartInfo_.y,
-                    ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_);
-    this.dragHappened_ = !tapCircle.inside(position.x, position.y);
-  }
-  if (this.dragHandler_ && this.dragHappened_) {
-    this.dragHandler_(position.x, position.y);
-    this.lockMouse_(true);
-  }
-  e.preventDefault();
-};
-
-/**
- * Mouse down handler.
- * @param {MouseEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onMouseDown = function(e) {
-  var position = ImageEditor.MouseControl.getPosition_(e);
-
-  this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y,
-                                                  false /* mouse */);
-  this.dragHappened_ = false;
-  this.updateCursor_(position);
-  e.preventDefault();
-};
-
-/**
- * Mouse up handler.
- * @param {MouseEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onMouseUp = function(e) {
-  var position = ImageEditor.MouseControl.getPosition_(e);
-
-  if (!this.dragHappened_) {
-    this.buffer_.onClick(position.x, position.y);
-  }
-  this.dragHandler_ = null;
-  this.dragHappened_ = false;
-  this.lockMouse_(false);
-  e.preventDefault();
-};
-
-/**
- * Mouse move handler.
- * @param {MouseEvent} e Event.
- */
-ImageEditor.MouseControl.prototype.onMouseMove = function(e) {
-  var position = ImageEditor.MouseControl.getPosition_(e);
-
-  if (this.dragHandler_ && !e.which) {
-    // mouseup must have happened while the mouse was outside our window.
-    this.dragHandler_ = null;
-    this.lockMouse_(false);
-  }
-
-  this.updateCursor_(position);
-  if (this.dragHandler_) {
-    this.dragHandler_(position.x, position.y);
-    this.dragHappened_ = true;
-    this.lockMouse_(true);
-  }
-  e.preventDefault();
-};
-
-/**
- * Update the UI to reflect mouse drag state.
- * @param {boolean} on True if dragging.
- * @private
- */
-ImageEditor.MouseControl.prototype.lockMouse_ = function(on) {
-  ImageUtil.setAttribute(this.rootContainer_, 'mousedrag', on);
-};
-
-/**
- * Update the cursor.
- *
- * @param {Object} position An object holding x and y properties.
- * @private
- */
-ImageEditor.MouseControl.prototype.updateCursor_ = function(position) {
-  var oldCursor = this.container_.getAttribute('cursor');
-  var newCursor = this.buffer_.getCursorStyle(
-      position.x, position.y, !!this.dragHandler_);
-  if (newCursor != oldCursor)  // Avoid flicker.
-    this.container_.setAttribute('cursor', newCursor);
-};
-
-/**
- * A toolbar for the ImageEditor.
- * @param {HTMLElement} parent The parent element.
- * @param {function} displayStringFunction A string formatting function.
- * @param {function} updateCallback The callback called when controls change.
- * @constructor
- */
-ImageEditor.Toolbar = function(parent, displayStringFunction, updateCallback) {
-  this.wrapper_ = parent;
-  this.displayStringFunction_ = displayStringFunction;
-  this.updateCallback_ = updateCallback;
-};
-
-/**
- * Clear the toolbar.
- */
-ImageEditor.Toolbar.prototype.clear = function() {
-  ImageUtil.removeChildren(this.wrapper_);
-};
-
-/**
- * Create a control.
- * @param {string} tagName The element tag name.
- * @return {HTMLElement} The created control element.
- * @private
- */
-ImageEditor.Toolbar.prototype.create_ = function(tagName) {
-  return this.wrapper_.ownerDocument.createElement(tagName);
-};
-
-/**
- * Add a control.
- * @param {HTMLElement} element The control to add.
- * @return {HTMLElement} The added element.
- */
-ImageEditor.Toolbar.prototype.add = function(element) {
-  this.wrapper_.appendChild(element);
-  return element;
-};
-
-/**
- * Add a text label.
- * @param {string} name Label name.
- * @return {HTMLElement} The added label.
- */
-ImageEditor.Toolbar.prototype.addLabel = function(name) {
-  var label = this.create_('span');
-  label.textContent = this.displayStringFunction_(name);
-  return this.add(label);
-};
-
-/**
- * Add a button.
- *
- * @param {string} name Button name.
- * @param {string} title Button title.
- * @param {function} handler onClick handler.
- * @param {string=} opt_class Extra class name.
- * @return {HTMLElement} The added button.
- */
-ImageEditor.Toolbar.prototype.addButton = function(
-    name, title, handler, opt_class) {
-  var button = this.create_('button');
-  if (opt_class) button.classList.add(opt_class);
-  var label = this.create_('span');
-  label.textContent = this.displayStringFunction_(title);
-  button.appendChild(label);
-  button.label = this.displayStringFunction_(title);
-  button.addEventListener('click', handler, false);
-  return this.add(button);
-};
-
-/**
- * Add a range control (scalar value picker).
- *
- * @param {string} name An option name.
- * @param {string} title An option title.
- * @param {number} min Min value of the option.
- * @param {number} value Default value of the option.
- * @param {number} max Max value of the options.
- * @param {number} scale A number to multiply by when setting
- *                       min/value/max in DOM.
- * @param {boolean=} opt_showNumeric True if numeric value should be displayed.
- * @return {HTMLElement} Range element.
- */
-ImageEditor.Toolbar.prototype.addRange = function(
-    name, title, min, value, max, scale, opt_showNumeric) {
-  var self = this;
-
-  scale = scale || 1;
-
-  var range = this.create_('input');
-
-  range.className = 'range';
-  range.type = 'range';
-  range.name = name;
-  range.min = Math.ceil(min * scale);
-  range.max = Math.floor(max * scale);
-
-  var numeric = this.create_('div');
-  numeric.className = 'numeric';
-  function mirror() {
-    numeric.textContent = Math.round(range.getValue() * scale) / scale;
-  }
-
-  range.setValue = function(newValue) {
-    range.value = Math.round(newValue * scale);
-    mirror();
-  };
-
-  range.getValue = function() {
-    return Number(range.value) / scale;
-  };
-
-  range.reset = function() {
-    range.setValue(value);
-  };
-
-  range.addEventListener('change',
-      function() {
-        mirror();
-        self.updateCallback_(self.getOptions());
-      },
-      false);
-
-  range.setValue(value);
-
-  var label = this.create_('div');
-  label.textContent = this.displayStringFunction_(title);
-  label.className = 'label ' + name;
-  this.add(label);
-  this.add(range);
-  if (opt_showNumeric) this.add(numeric);
-
-  return range;
-};
-
-/**
- * @return {Object} options A map of options.
- */
-ImageEditor.Toolbar.prototype.getOptions = function() {
-  var values = {};
-  for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) {
-    if (child.name)
-      values[child.name] = child.getValue();
-  }
-  return values;
-};
-
-/**
- * Reset the toolbar.
- */
-ImageEditor.Toolbar.prototype.reset = function() {
-  for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) {
-    if (child.reset) child.reset();
-  }
-};
-
-/**
- * Show/hide the toolbar.
- * @param {boolean} on True if show.
- */
-ImageEditor.Toolbar.prototype.show = function(on) {
-  if (!this.wrapper_.firstChild)
-    return;  // Do not show empty toolbar;
-
-  this.wrapper_.hidden = !on;
-};
-
-/** A prompt panel for the editor.
- *
- * @param {HTMLElement} container Container element.
- * @param {function} displayStringFunction A formatting function.
- * @constructor
- */
-ImageEditor.Prompt = function(container, displayStringFunction) {
-  this.container_ = container;
-  this.displayStringFunction_ = displayStringFunction;
-};
-
-/**
- * Reset the prompt.
- */
-ImageEditor.Prompt.prototype.reset = function() {
-  this.cancelTimer();
-  if (this.wrapper_) {
-    this.container_.removeChild(this.wrapper_);
-    this.wrapper_ = null;
-    this.prompt_ = null;
-  }
-};
-
-/**
- * Cancel the delayed action.
- */
-ImageEditor.Prompt.prototype.cancelTimer = function() {
-  if (this.timer_) {
-    clearTimeout(this.timer_);
-    this.timer_ = null;
-  }
-};
-
-/**
- * Schedule the delayed action.
- * @param {function} callback Callback.
- * @param {number} timeout Timeout.
- */
-ImageEditor.Prompt.prototype.setTimer = function(callback, timeout) {
-  this.cancelTimer();
-  var self = this;
-  this.timer_ = setTimeout(function() {
-    self.timer_ = null;
-    callback();
-  }, timeout);
-};
-
-/**
- * Show the prompt.
- *
- * @param {string} text The prompt text.
- * @param {number} timeout Timeout in ms.
- * @param {Object} formatArgs varArgs for the formatting fuction.
- */
-ImageEditor.Prompt.prototype.show = function(text, timeout, formatArgs) {
-  this.showAt.apply(this,
-      ['center'].concat(Array.prototype.slice.call(arguments)));
-};
-
-/**
- *
- * @param {string} pos The 'pos' attribute value.
- * @param {string} text The prompt text.
- * @param {number} timeout Timeout in ms.
- * @param {Object} formatArgs varArgs for the formatting function.
- */
-ImageEditor.Prompt.prototype.showAt = function(pos, text, timeout, formatArgs) {
-  this.reset();
-  if (!text) return;
-
-  var document = this.container_.ownerDocument;
-  this.wrapper_ = document.createElement('div');
-  this.wrapper_.className = 'prompt-wrapper';
-  this.wrapper_.setAttribute('pos', pos);
-  this.container_.appendChild(this.wrapper_);
-
-  this.prompt_ = document.createElement('div');
-  this.prompt_.className = 'prompt';
-
-  // Create an extra wrapper which opacity can be manipulated separately.
-  var tool = document.createElement('div');
-  tool.className = 'dimmable';
-  this.wrapper_.appendChild(tool);
-  tool.appendChild(this.prompt_);
-
-  var args = [text].concat(Array.prototype.slice.call(arguments, 3));
-  this.prompt_.textContent = this.displayStringFunction_.apply(null, args);
-
-  var close = document.createElement('div');
-  close.className = 'close';
-  close.addEventListener('click', this.hide.bind(this));
-  this.prompt_.appendChild(close);
-
-  setTimeout(
-      this.prompt_.setAttribute.bind(this.prompt_, 'state', 'fadein'), 0);
-
-  if (timeout)
-    this.setTimer(this.hide.bind(this), timeout);
-};
-
-/**
- * Hide the prompt.
- */
-ImageEditor.Prompt.prototype.hide = function() {
-  if (!this.prompt_) return;
-  this.prompt_.setAttribute('state', 'fadeout');
-  // Allow some time for the animation to play out.
-  this.setTimer(this.reset.bind(this), 500);
-};
diff --git a/chrome/browser/resources/file_manager/js/main_scripts.js b/chrome/browser/resources/file_manager/js/main_scripts.js
deleted file mode 100644
index eb335f5..0000000
--- a/chrome/browser/resources/file_manager/js/main_scripts.js
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-// If you add a new dependency, you should update build files by rerunning
-// gyp. Otherwise, you'll be bitten by a dependency issue like:
-//
-// 1) You add a new dependency to "whatever.js"
-// 2) You make changes in "whatever.js"
-// 3) Rebuild "resources.pak" and open Files.app
-// 4) You don't see the changes in "whatever.js". Why is that?
-//
-// Because the dependencies are computed at gyp time, the existing build
-// files don't know that "resources.pak" now has a dependency to
-// "whatever.js". You should rerun gyp to let the build files know.
-//
-// //metrics.js initiates load performance tracking
-// //so we want to parse it as early as possible.
-//<include src="metrics.js"/>
-//
-//<include src="../../image_loader/image_loader_client.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/load_time_data.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr.js"/>
-//<include src="../../../../../ui/webui/resources/js/util.js"/>
-//<include src="../../../../../ui/webui/resources/js/i18n_template_no_process.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/event_tracker.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/event_target.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/dialogs.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_item.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/list.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/tree.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/autocomplete_list.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/cr/ui/splitter.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table/table_splitter.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table/table_column.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table/table_column_model.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table/table_header.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table/table_list.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/table.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/cr/ui/grid.js"/>
-//
-//<include src="../../../../../ui/webui/resources/js/cr/ui/command.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/position_util.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/menu_item.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/menu.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/menu_button.js"/>
-//<include src="../../../../../ui/webui/resources/js/cr/ui/context_menu_handler.js"/>
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-// // This script must be loaded before all other Files.app's scripts.
-//<include src="error_counter.js"/>
-//
-//<include src="combobutton.js"/>
-//<include src="commandbutton.js"/>
-//<include src="ui/file_manager_dialog_base.js"/>
-//
-//<include src="app_installer.js"/>
-//<include src="async_util.js"/>
-//<include src="path_util.js"/>
-//<include src="util.js"/>
-//<include src="action_choice_util.js"/>
-//<include src="butter_bar.js"/>
-//<include src="cws_container_client.js"/>
-//<include src="directory_contents.js"/>
-//<include src="directory_model.js"/>
-//<include src="directory_tree.js"/>
-//<include src="drag_selector.js"/>
-//<include src="drive_banners.js" />
-//<include src="error_dialog.js"/>
-//<include src="file_operation_manager_wrapper.js"/>
-//<include src="file_grid.js"/>
-//<include src="file_manager.js"/>
-//<include src="file_selection.js"/>
-//<include src="file_table.js"/>
-//<include src="file_tasks.js"/>
-//<include src="file_transfer_controller.js"/>
-//<include src="file_type.js"/>
-//<include src="file_watcher.js"/>
-//<include src="folder_shortcuts_data_model.js"/>
-//<include src="navigation_list.js"/>
-//<include src="progress_center_common.js">
-//<include src="scrollbar.js"/>
-//<include src="share_client.js"/>
-//<include src="share_dialog.js"/>
-//<include src="suggest_apps_dialog.js"/>
-//<include src="text_measure.js"/>
-//<include src="tree.css.js"/>
-//<include src="ui/breadcrumbs_controller.js"/>
-//<include src="ui/conflict_dialog.js"/>
-//<include src="ui/file_manager_ui.js"/>
-//<include src="ui/preview_panel.js"/>
-//<include src="ui/progress_center_panel.js"/>
-//<include src="ui/search_box.js"/>
-//<include src="url_constants.js"/>
-//<include src="volume_manager_wrapper.js"/>
-//<include src="media/media_util.js"/>
-//<include src="metadata/metadata_cache.js"/>
-//<include src="default_action_dialog.js"/>
-//<include src="file_manager_commands.js"/>
-
-// // For accurate load performance tracking place main.js should be
-// // the last include to include.
-//<include src="main.js"/>
-
-// Global fileManager reference useful for poking at from the console.
-window.fileManager = fileManager;
-
-// Exports
-window.util = util;
-window.FileOperationManagerWrapper = FileOperationManagerWrapper;
-
-window.unload = unload;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js b/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
deleted file mode 100644
index 892075a..0000000
--- a/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-
-//<include src="../../../../../../ui/webui/resources/js/cr.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-//<include src="../async_util.js"/>
-//<include src="../util.js"/>
-//<include src="../path_util.js"/>
-//<include src="../file_type.js"/>
-//<include src="../volume_manager_wrapper.js">
-//<include src="../metadata/metadata_cache.js"/>
-
-//<include src="media_controls.js"/>
-//<include src="audio_player.js"/>
-//<include src="player_testapi.js"/>
-
-window.reload = reload;
-window.unload = unload;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/media/video_player_scripts.js b/chrome/browser/resources/file_manager/js/media/video_player_scripts.js
deleted file mode 100644
index 71dfae0..0000000
--- a/chrome/browser/resources/file_manager/js/media/video_player_scripts.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-//<include src="../../../../../../ui/webui/resources/js/cr.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
-//<include src="../../../../../../ui/webui/resources/js/load_time_data.js"/>
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-//<include src="../async_util.js"/>
-//<include src="../util.js"/>
-//<include src="../path_util.js"/>
-//<include src="../file_type.js"/>
-//<include src="../volume_manager_wrapper.js">
-//<include src="../metadata/metadata_cache.js"/>
-
-//<include src="media_controls.js"/>
-//<include src="util.js"/>
-//<include src="video_player.js"/>
-//<include src="player_testapi.js"/>
-
-window.reload = reload;
-window.unload = unload;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js b/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js
deleted file mode 100644
index 7734c13..0000000
--- a/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js
+++ /dev/null
@@ -1,1050 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * MetadataCache is a map from url to an object containing properties.
- * Properties are divided by types, and all properties of one type are accessed
- * at once.
- * Some of the properties:
- * {
- *   filesystem: size, modificationTime
- *   internal: presence
- *   drive: pinned, present, hosted, availableOffline
- *   streaming: (no property)
- *
- *   Following are not fetched for non-present drive files.
- *   media: artist, album, title, width, height, imageTransform, etc.
- *   thumbnail: url, transform
- *
- *   Following are always fetched from content, and so force the downloading
- *   of remote drive files. One should use this for required content metadata,
- *   i.e. image orientation.
- *   fetchedMedia: width, height, etc.
- * }
- *
- * Typical usages:
- * {
- *   cache.get([entry1, entry2], 'drive|filesystem', function(metadata) {
- *     if (metadata[0].drive.pinned && metadata[1].filesystem.size == 0)
- *       alert("Pinned and empty!");
- *   });
- *
- *   cache.set(entry, 'internal', {presence: 'deleted'});
- *
- *   cache.clear([fileUrl1, fileUrl2], 'filesystem');
- *
- *   // Getting fresh value.
- *   cache.clear(entry, 'thumbnail');
- *   cache.get(entry, 'thumbnail', function(thumbnail) {
- *     img.src = thumbnail.url;
- *   });
- *
- *   var cached = cache.getCached(entry, 'filesystem');
- *   var size = (cached && cached.size) || UNKNOWN_SIZE;
- * }
- *
- * @constructor
- */
-function MetadataCache() {
-  /**
-   * Map from urls to entries. Entry contains |properties| - an hierarchical
-   * object of values, and an object for each metadata provider:
-   * <prodiver-id>: { time, callbacks }
-   * @private
-   */
-  this.cache_ = {};
-
-  /**
-   * List of metadata providers.
-   * @private
-   */
-  this.providers_ = [];
-
-  /**
-   * List of observers added. Each one is an object with fields:
-   *   re - regexp of urls;
-   *   type - metadata type;
-   *   callback - the callback.
-   * TODO(dgozman): pass entries to observer if present.
-   * @private
-   */
-  this.observers_ = [];
-  this.observerId_ = 0;
-
-  this.batchCount_ = 0;
-  this.totalCount_ = 0;
-
-  /**
-   * Time of first get query of the current batch. Items updated later than this
-   * will not be evicted.
-   * @private
-   */
-  this.lastBatchStart_ = new Date();
-}
-
-/**
- * Observer type: it will be notified if the url changed is exactly the same
- * as the url passed.
- */
-MetadataCache.EXACT = 0;
-
-/**
- * Observer type: it will be notified if the url changed is an immediate child
- * of the url passed.
- */
-MetadataCache.CHILDREN = 1;
-
-/**
- * Observer type: it will be notified if the url changed is any descendant
- * of the url passed.
- */
-MetadataCache.DESCENDANTS = 2;
-
-/**
- * Minimum number of items in cache to start eviction.
- */
-MetadataCache.EVICTION_NUMBER = 1000;
-
-/**
- * @return {MetadataCache!} The cache with all providers.
- */
-MetadataCache.createFull = function() {
-  var cache = new MetadataCache();
-  cache.providers_.push(new FilesystemProvider());
-  cache.providers_.push(new DriveProvider());
-  cache.providers_.push(new ContentProvider());
-  return cache;
-};
-
-/**
- * Clones metadata entry. Metadata entries may contain scalars, arrays,
- * hash arrays and Date object. Other objects are not supported.
- * @param {Object} metadata Metadata object.
- * @return {Object} Cloned entry.
- */
-MetadataCache.cloneMetadata = function(metadata) {
-  if (metadata instanceof Array) {
-    var result = [];
-    for (var index = 0; index < metadata.length; index++) {
-      result[index] = MetadataCache.cloneMetadata(metadata[index]);
-    }
-    return result;
-  } else if (metadata instanceof Date) {
-    var result = new Date();
-    result.setTime(metadata.getTime());
-    return result;
-  } else if (metadata instanceof Object) {  // Hash array only.
-    var result = {};
-    for (var property in metadata) {
-      if (metadata.hasOwnProperty(property))
-        result[property] = MetadataCache.cloneMetadata(metadata[property]);
-    }
-    return result;
-  } else {
-    return metadata;
-  }
-};
-
-/**
- * @return {boolean} Whether all providers are ready.
- */
-MetadataCache.prototype.isInitialized = function() {
-  for (var index = 0; index < this.providers_.length; index++) {
-    if (!this.providers_[index].isInitialized()) return false;
-  }
-  return true;
-};
-
-/**
- * Fetches the metadata, puts it in the cache, and passes to callback.
- * If required metadata is already in the cache, does not fetch it again.
- * @param {string|Entry|Array.<string|Entry>} items The list of entries or
- *     file urls. May be just a single item.
- * @param {string} type The metadata type.
- * @param {function(Object)} callback The metadata is passed to callback.
- */
-MetadataCache.prototype.get = function(items, type, callback) {
-  if (!(items instanceof Array)) {
-    this.getOne(items, type, callback);
-    return;
-  }
-
-  if (items.length == 0) {
-    if (callback) callback([]);
-    return;
-  }
-
-  var result = [];
-  var remaining = items.length;
-  this.startBatchUpdates();
-
-  var onOneItem = function(index, value) {
-    result[index] = value;
-    remaining--;
-    if (remaining == 0) {
-      this.endBatchUpdates();
-      if (callback) setTimeout(callback, 0, result);
-    }
-  };
-
-  for (var index = 0; index < items.length; index++) {
-    result.push(null);
-    this.getOne(items[index], type, onOneItem.bind(this, index));
-  }
-};
-
-/**
- * Fetches the metadata for one Entry/FileUrl. See comments to |get|.
- * @param {Entry|string} item The entry or url.
- * @param {string} type Metadata type.
- * @param {function(Object)} callback The callback.
- */
-MetadataCache.prototype.getOne = function(item, type, callback) {
-  if (type.indexOf('|') != -1) {
-    var types = type.split('|');
-    var result = {};
-    var typesLeft = types.length;
-
-    var onOneType = function(requestedType, metadata) {
-      result[requestedType] = metadata;
-      typesLeft--;
-      if (typesLeft == 0) callback(result);
-    };
-
-    for (var index = 0; index < types.length; index++) {
-      this.getOne(item, types[index], onOneType.bind(null, types[index]));
-    }
-    return;
-  }
-
-  var url = this.itemToUrl_(item);
-
-  // Passing entry to fetchers may save one round-trip to APIs.
-  var fsEntry = item === url ? null : item;
-  callback = callback || function() {};
-
-  if (!(url in this.cache_)) {
-    this.cache_[url] = this.createEmptyEntry_();
-    this.totalCount_++;
-  }
-
-  var entry = this.cache_[url];
-
-  if (type in entry.properties) {
-    callback(entry.properties[type]);
-    return;
-  }
-
-  this.startBatchUpdates();
-  var providers = this.providers_.slice();
-  var currentProvider;
-  var self = this;
-
-  var onFetched = function() {
-    if (type in entry.properties) {
-      self.endBatchUpdates();
-      // Got properties from provider.
-      callback(entry.properties[type]);
-    } else {
-      tryNextProvider();
-    }
-  };
-
-  var onProviderProperties = function(properties) {
-    var id = currentProvider.getId();
-    var fetchedCallbacks = entry[id].callbacks;
-    delete entry[id].callbacks;
-    entry.time = new Date();
-    self.mergeProperties_(url, properties);
-
-    for (var index = 0; index < fetchedCallbacks.length; index++) {
-      fetchedCallbacks[index]();
-    }
-  };
-
-  var queryProvider = function() {
-    var id = currentProvider.getId();
-    if ('callbacks' in entry[id]) {
-      // We are querying this provider now.
-      entry[id].callbacks.push(onFetched);
-    } else {
-      entry[id].callbacks = [onFetched];
-      currentProvider.fetch(url, type, onProviderProperties, fsEntry);
-    }
-  };
-
-  var tryNextProvider = function() {
-    if (providers.length == 0) {
-      self.endBatchUpdates();
-      callback(entry.properties[type] || null);
-      return;
-    }
-
-    currentProvider = providers.shift();
-    if (currentProvider.supportsUrl(url) &&
-        currentProvider.providesType(type)) {
-      queryProvider();
-    } else {
-      tryNextProvider();
-    }
-  };
-
-  tryNextProvider();
-};
-
-/**
- * Returns the cached metadata value, or |null| if not present.
- * @param {string|Entry|Array.<string|Entry>} items The list of entries or
- *     file urls. May be just a single item.
- * @param {string} type The metadata type.
- * @return {Object} The metadata or null.
- */
-MetadataCache.prototype.getCached = function(items, type) {
-  var single = false;
-  if (!(items instanceof Array)) {
-    single = true;
-    items = [items];
-  }
-
-  var result = [];
-  for (var index = 0; index < items.length; index++) {
-    var url = this.itemToUrl_(items[index]);
-    result.push(url in this.cache_ ?
-        (this.cache_[url].properties[type] || null) : null);
-  }
-
-  return single ? result[0] : result;
-};
-
-/**
- * Puts the metadata into cache
- * @param {string|Entry|Array.<string|Entry>} items The list of entries or
- *     file urls. May be just a single item.
- * @param {string} type The metadata type.
- * @param {Array.<Object>} values List of corresponding metadata values.
- */
-MetadataCache.prototype.set = function(items, type, values) {
-  if (!(items instanceof Array)) {
-    items = [items];
-    values = [values];
-  }
-
-  this.startBatchUpdates();
-  for (var index = 0; index < items.length; index++) {
-    var url = this.itemToUrl_(items[index]);
-    if (!(url in this.cache_)) {
-      this.cache_[url] = this.createEmptyEntry_();
-      this.totalCount_++;
-    }
-    this.cache_[url].properties[type] = values[index];
-    this.notifyObservers_(url, type);
-  }
-  this.endBatchUpdates();
-};
-
-/**
- * Clears the cached metadata values.
- * @param {string|Entry|Array.<string|Entry>} items The list of entries or
- *     file urls. May be just a single item.
- * @param {string} type The metadata types or * for any type.
- */
-MetadataCache.prototype.clear = function(items, type) {
-  if (!(items instanceof Array))
-    items = [items];
-
-  var types = type.split('|');
-
-  for (var index = 0; index < items.length; index++) {
-    var url = this.itemToUrl_(items[index]);
-    if (url in this.cache_) {
-      if (type === '*') {
-        this.cache_[url].properties = {};
-      } else {
-        for (var j = 0; j < types.length; j++) {
-          var type = types[j];
-          delete this.cache_[url].properties[type];
-        }
-      }
-    }
-  }
-};
-
-/**
- * Clears the cached metadata values recursively.
- * @param {Entry|string} item An entry or a url.
- * @param {string} type The metadata types or * for any type.
- */
-MetadataCache.prototype.clearRecursively = function(item, type) {
-  var types = type.split('|');
-  var keys = Object.keys(this.cache_);
-  var url = this.itemToUrl_(item);
-
-  for (var index = 0; index < keys.length; index++) {
-    var entryUrl = keys[index];
-    if (entryUrl.substring(0, url.length) === url) {
-      if (type === '*') {
-        this.cache_[entryUrl].properties = {};
-      } else {
-        for (var j = 0; j < types.length; j++) {
-          var type = types[j];
-          delete this.cache_[entryUrl].properties[type];
-        }
-      }
-    }
-  }
-};
-
-/**
- * Adds an observer, which will be notified when metadata changes.
- * @param {string|Entry} item The root item to look at.
- * @param {number} relation This defines, which items will trigger the observer.
- *     See comments to |MetadataCache.EXACT| and others.
- * @param {string} type The metadata type.
- * @param {function(Array.<string>, Array.<Object>)} observer List of file urls
- *     and corresponding metadata values are passed to this callback.
- * @return {number} The observer id, which can be used to remove it.
- */
-MetadataCache.prototype.addObserver = function(item, relation, type, observer) {
-  var url = this.itemToUrl_(item);
-  var re = url;
-  if (relation == MetadataCache.CHILDREN) {
-    re += '(/[^/]*)?';
-  } else if (relation == MetadataCache.DESCENDANTS) {
-    re += '(/.*)?';
-  }
-  var id = ++this.observerId_;
-  this.observers_.push({
-    re: new RegExp('^' + re + '$'),
-    type: type,
-    callback: observer,
-    id: id,
-    pending: {}
-  });
-  return id;
-};
-
-/**
- * Removes the observer.
- * @param {number} id Observer id.
- * @return {boolean} Whether observer was removed or not.
- */
-MetadataCache.prototype.removeObserver = function(id) {
-  for (var index = 0; index < this.observers_.length; index++) {
-    if (this.observers_[index].id == id) {
-      this.observers_.splice(index, 1);
-      return true;
-    }
-  }
-  return false;
-};
-
-/**
- * Start batch updates.
- */
-MetadataCache.prototype.startBatchUpdates = function() {
-  this.batchCount_++;
-  if (this.batchCount_ == 1)
-    this.lastBatchStart_ = new Date();
-};
-
-/**
- * End batch updates. Notifies observers if all nested updates are finished.
- */
-MetadataCache.prototype.endBatchUpdates = function() {
-  this.batchCount_--;
-  if (this.batchCount_ != 0) return;
-  if (this.totalCount_ > MetadataCache.EVICTION_NUMBER)
-    this.evict_();
-  for (var index = 0; index < this.observers_.length; index++) {
-    var observer = this.observers_[index];
-    var urls = [];
-    var properties = [];
-    for (var url in observer.pending) {
-      if (observer.pending.hasOwnProperty(url) && url in this.cache_) {
-        urls.push(url);
-        properties.push(this.cache_[url].properties[observer.type] || null);
-      }
-    }
-    observer.pending = {};
-    if (urls.length > 0) {
-      observer.callback(urls, properties);
-    }
-  }
-};
-
-/**
- * Notifies observers or puts the data to pending list.
- * @param {string} url Url of entry changed.
- * @param {string} type Metadata type.
- * @private
- */
-MetadataCache.prototype.notifyObservers_ = function(url, type) {
-  for (var index = 0; index < this.observers_.length; index++) {
-    var observer = this.observers_[index];
-    if (observer.type == type && observer.re.test(url)) {
-      if (this.batchCount_ == 0) {
-        // Observer expects array of urls and array of properties.
-        observer.callback([url], [this.cache_[url].properties[type] || null]);
-      } else {
-        observer.pending[url] = true;
-      }
-    }
-  }
-};
-
-/**
- * Removes the oldest items from the cache.
- * This method never removes the items from last batch.
- * @private
- */
-MetadataCache.prototype.evict_ = function() {
-  var toRemove = [];
-
-  // We leave only a half of items, so we will not call evict_ soon again.
-  var desiredCount = Math.round(MetadataCache.EVICTION_NUMBER / 2);
-  var removeCount = this.totalCount_ - desiredCount;
-  for (var url in this.cache_) {
-    if (this.cache_.hasOwnProperty(url) &&
-        this.cache_[url].time < this.lastBatchStart_) {
-      toRemove.push(url);
-    }
-  }
-
-  toRemove.sort(function(a, b) {
-    var aTime = this.cache_[a].time;
-    var bTime = this.cache_[b].time;
-    return aTime < bTime ? -1 : aTime > bTime ? 1 : 0;
-  }.bind(this));
-
-  removeCount = Math.min(removeCount, toRemove.length);
-  this.totalCount_ -= removeCount;
-  for (var index = 0; index < removeCount; index++) {
-    delete this.cache_[toRemove[index]];
-  }
-};
-
-/**
- * Converts Entry or file url to url.
- * @param {string|Entry} item Item to convert.
- * @return {string} File url.
- * @private
- */
-MetadataCache.prototype.itemToUrl_ = function(item) {
-  if (typeof(item) == 'string')
-    return item;
-
-  if (!item._URL_) {
-    // Is a fake entry.
-    if (typeof item.toURL !== 'function')
-      item._URL_ = util.makeFilesystemUrl(item.fullPath);
-    else
-      item._URL_ = item.toURL();
-  }
-
-  return item._URL_;
-};
-
-/**
- * @return {Object} Empty cache entry.
- * @private
- */
-MetadataCache.prototype.createEmptyEntry_ = function() {
-  var entry = {properties: {}};
-  for (var index = 0; index < this.providers_.length; index++) {
-    entry[this.providers_[index].getId()] = {};
-  }
-  return entry;
-};
-
-/**
- * Caches all the properties from data to cache entry for url.
- * @param {string} url The url.
- * @param {Object} data The properties.
- * @private
- */
-MetadataCache.prototype.mergeProperties_ = function(url, data) {
-  if (data == null) return;
-  var properties = this.cache_[url].properties;
-  for (var type in data) {
-    if (data.hasOwnProperty(type) && !properties.hasOwnProperty(type)) {
-      properties[type] = data[type];
-      this.notifyObservers_(url, type);
-    }
-  }
-};
-
-/**
- * Base class for metadata providers.
- * @constructor
- */
-function MetadataProvider() {
-}
-
-/**
- * @param {string} url The url.
- * @return {boolean} Whether this provider supports the url.
- */
-MetadataProvider.prototype.supportsUrl = function(url) { return false; };
-
-/**
- * @param {string} type The metadata type.
- * @return {boolean} Whether this provider provides this metadata.
- */
-MetadataProvider.prototype.providesType = function(type) { return false; };
-
-/**
- * @return {string} Unique provider id.
- */
-MetadataProvider.prototype.getId = function() { return ''; };
-
-/**
- * @return {boolean} Whether provider is ready.
- */
-MetadataProvider.prototype.isInitialized = function() { return true; };
-
-/**
- * Fetches the metadata. It's suggested to return all the metadata this provider
- * can fetch at once.
- * @param {string} url File url.
- * @param {string} type Requested metadata type.
- * @param {function(Object)} callback Callback expects a map from metadata type
- *     to metadata value.
- * @param {Entry=} opt_entry The file entry if present.
- */
-MetadataProvider.prototype.fetch = function(url, type, callback, opt_entry) {
-  throw new Error('Default metadata provider cannot fetch.');
-};
-
-
-/**
- * Provider of filesystem metadata.
- * This provider returns the following objects:
- * filesystem: { size, modificationTime }
- * @constructor
- */
-function FilesystemProvider() {
-  MetadataProvider.call(this);
-}
-
-FilesystemProvider.prototype = {
-  __proto__: MetadataProvider.prototype
-};
-
-/**
- * @param {string} url The url.
- * @return {boolean} Whether this provider supports the url.
- */
-FilesystemProvider.prototype.supportsUrl = function(url) {
-  return true;
-};
-
-/**
- * @param {string} type The metadata type.
- * @return {boolean} Whether this provider provides this metadata.
- */
-FilesystemProvider.prototype.providesType = function(type) {
-  return type == 'filesystem';
-};
-
-/**
- * @return {string} Unique provider id.
- */
-FilesystemProvider.prototype.getId = function() { return 'filesystem'; };
-
-/**
- * Fetches the metadata.
- * @param {string} url File url.
- * @param {string} type Requested metadata type.
- * @param {function(Object)} callback Callback expects a map from metadata type
- *     to metadata value.
- * @param {Entry=} opt_entry The file entry if present.
- */
-FilesystemProvider.prototype.fetch = function(url, type, callback, opt_entry) {
-  function onError(error) {
-    callback(null);
-  }
-
-  function onMetadata(entry, metadata) {
-    callback({
-      filesystem: {
-        size: entry.isFile ? (metadata.size || 0) : -1,
-        modificationTime: metadata.modificationTime
-      }
-    });
-  }
-
-  function onEntry(entry) {
-    entry.getMetadata(onMetadata.bind(null, entry), onError);
-  }
-
-  if (opt_entry)
-    onEntry(opt_entry);
-  else
-    window.webkitResolveLocalFileSystemURL(url, onEntry, onError);
-};
-
-/**
- * Provider of drive metadata.
- * This provider returns the following objects:
- *     drive: { pinned, hosted, present, customIconUrl, etc. }
- *     thumbnail: { url, transform }
- *     streaming: { }
- * @constructor
- */
-function DriveProvider() {
-  MetadataProvider.call(this);
-
-  // We batch metadata fetches into single API call.
-  this.urls_ = [];
-  this.callbacks_ = [];
-  this.scheduled_ = false;
-
-  this.callApiBound_ = this.callApi_.bind(this);
-}
-
-DriveProvider.prototype = {
-  __proto__: MetadataProvider.prototype
-};
-
-/**
- * @param {string} url The url.
- * @return {boolean} Whether this provider supports the url.
- */
-DriveProvider.prototype.supportsUrl = function(url) {
-  return FileType.isOnDrive(url);
-};
-
-/**
- * @param {string} type The metadata type.
- * @return {boolean} Whether this provider provides this metadata.
- */
-DriveProvider.prototype.providesType = function(type) {
-  return type == 'drive' || type == 'thumbnail' ||
-      type == 'streaming' || type == 'media';
-};
-
-/**
- * @return {string} Unique provider id.
- */
-DriveProvider.prototype.getId = function() { return 'drive'; };
-
-/**
- * Fetches the metadata.
- * @param {string} url File url.
- * @param {string} type Requested metadata type.
- * @param {function(Object)} callback Callback expects a map from metadata type
- *     to metadata value.
- * @param {Entry=} opt_entry The file entry if present.
- */
-DriveProvider.prototype.fetch = function(url, type, callback, opt_entry) {
-  this.urls_.push(url);
-  this.callbacks_.push(callback);
-  if (!this.scheduled_) {
-    this.scheduled_ = true;
-    setTimeout(this.callApiBound_, 0);
-  }
-};
-
-/**
- * Schedules the API call.
- * @private
- */
-DriveProvider.prototype.callApi_ = function() {
-  this.scheduled_ = false;
-
-  var urls = this.urls_;
-  var callbacks = this.callbacks_;
-  this.urls_ = [];
-  this.callbacks_ = [];
-  var self = this;
-
-  var task = function(url, callback) {
-    chrome.fileBrowserPrivate.getDriveEntryProperties(url,
-        function(properties) {
-          callback(self.convert_(properties, url));
-        });
-  };
-
-  for (var i = 0; i < urls.length; i++)
-    task(urls[i], callbacks[i]);
-};
-
-/**
- * @param {DriveEntryProperties} data Drive entry properties.
- * @param {string} url File url.
- * @return {boolean} True if the file is available offline.
- */
-DriveProvider.isAvailableOffline = function(data, url) {
-  if (data.isPresent)
-    return true;
-
-  if (!data.isHosted)
-    return false;
-
-  // What's available offline? See the 'Web' column at:
-  // http://support.google.com/drive/bin/answer.py?hl=en&answer=1628467
-  var subtype = FileType.getType(url).subtype;
-  return (subtype == 'doc' ||
-          subtype == 'draw' ||
-          subtype == 'sheet' ||
-          subtype == 'slides');
-};
-
-/**
- * @param {DriveEntryProperties} data Drive entry properties.
- * @return {boolean} True if opening the file does not require downloading it
- *    via a metered connection.
- */
-DriveProvider.isAvailableWhenMetered = function(data) {
-  return data.isPresent || data.isHosted;
-};
-
-/**
- * Converts API metadata to internal format.
- * @param {Object} data Metadata from API call.
- * @param {string} url File url.
- * @return {Object} Metadata in internal format.
- * @private
- */
-DriveProvider.prototype.convert_ = function(data, url) {
-  var result = {};
-  result.drive = {
-    present: data.isPresent,
-    pinned: data.isPinned,
-    hosted: data.isHosted,
-    imageWidth: data.imageWidth,
-    imageHeight: data.imageHeight,
-    imageRotation: data.imageRotation,
-    availableOffline: DriveProvider.isAvailableOffline(data, url),
-    availableWhenMetered: DriveProvider.isAvailableWhenMetered(data),
-    customIconUrl: data.customIconUrl || '',
-    contentMimeType: data.contentMimeType || '',
-    sharedWithMe: data.sharedWithMe
-  };
-
-  if (!data.isPresent) {
-    // Block the local fetch for drive files, which require downloading.
-    result.thumbnail = {url: '', transform: null};
-    result.media = {};
-  }
-
-  if ('thumbnailUrl' in data) {
-    result.thumbnail = {
-      url: data.thumbnailUrl.replace(/s220/, 's500'),
-      transform: null
-    };
-  }
-  if (!data.isPresent) {
-    // Indicate that the data is not available in local cache.
-    // It used to have a field 'url' for streaming play, but it is
-    // derprecated. See crbug.com/174560.
-    result.streaming = {};
-  }
-  return result;
-};
-
-
-/**
- * Provider of content metadata.
- * This provider returns the following objects:
- * thumbnail: { url, transform }
- * media: { artist, album, title, width, height, imageTransform, etc. }
- * fetchedMedia: { same fields here }
- * @constructor
- */
-function ContentProvider() {
-  MetadataProvider.call(this);
-
-  // Pass all URLs to the metadata reader until we have a correct filter.
-  this.urlFilter_ = /.*/;
-
-  var path = document.location.pathname;
-  var workerPath = document.location.origin +
-      path.substring(0, path.lastIndexOf('/') + 1) +
-      'js/metadata/metadata_dispatcher.js';
-
-  if (ContentProvider.USE_SHARED_WORKER) {
-    this.dispatcher_ = new SharedWorker(workerPath).port;
-    this.dispatcher_.start();
-  } else {
-    this.dispatcher_ = new Worker(workerPath);
-  }
-
-  this.dispatcher_.onmessage = this.onMessage_.bind(this);
-  this.dispatcher_.postMessage({verb: 'init'});
-
-  // Initialization is not complete until the Worker sends back the
-  // 'initialized' message.  See below.
-  this.initialized_ = false;
-
-  // Map from url to callback.
-  // Note that simultaneous requests for same url are handled in MetadataCache.
-  this.callbacks_ = {};
-}
-
-/**
- * Flag defining which kind of a worker to use.
- * TODO(kaznacheev): Observe for some time and remove if SharedWorker does not
- * cause any problems.
- */
-ContentProvider.USE_SHARED_WORKER = true;
-
-ContentProvider.prototype = {
-  __proto__: MetadataProvider.prototype
-};
-
-/**
- * @param {string} url The url.
- * @return {boolean} Whether this provider supports the url.
- */
-ContentProvider.prototype.supportsUrl = function(url) {
-  return url.match(this.urlFilter_);
-};
-
-/**
- * @param {string} type The metadata type.
- * @return {boolean} Whether this provider provides this metadata.
- */
-ContentProvider.prototype.providesType = function(type) {
-  return type == 'thumbnail' || type == 'fetchedMedia' || type == 'media';
-};
-
-/**
- * @return {string} Unique provider id.
- */
-ContentProvider.prototype.getId = function() { return 'content'; };
-
-/**
- * Fetches the metadata.
- * @param {string} url File url.
- * @param {string} type Requested metadata type.
- * @param {function(Object)} callback Callback expects a map from metadata type
- *     to metadata value.
- * @param {Entry=} opt_entry The file entry if present.
- */
-ContentProvider.prototype.fetch = function(url, type, callback, opt_entry) {
-  if (opt_entry && opt_entry.isDirectory) {
-    callback({});
-    return;
-  }
-  this.callbacks_[url] = callback;
-  this.dispatcher_.postMessage({verb: 'request', arguments: [url]});
-};
-
-/**
- * Dispatch a message from a metadata reader to the appropriate on* method.
- * @param {Object} event The event.
- * @private
- */
-ContentProvider.prototype.onMessage_ = function(event) {
-  var data = event.data;
-
-  var methodName =
-      'on' + data.verb.substr(0, 1).toUpperCase() + data.verb.substr(1) + '_';
-
-  if (!(methodName in this)) {
-    console.error('Unknown message from metadata reader: ' + data.verb, data);
-    return;
-  }
-
-  this[methodName].apply(this, data.arguments);
-};
-
-/**
- * @return {boolean} Whether provider is ready.
- */
-ContentProvider.prototype.isInitialized = function() {
-  return this.initialized_;
-};
-
-/**
- * Handles the 'initialized' message from the metadata reader Worker.
- * @param {Object} regexp Regexp of supported urls.
- * @private
- */
-ContentProvider.prototype.onInitialized_ = function(regexp) {
-  this.urlFilter_ = regexp;
-
-  // Tests can monitor for this state with
-  // ExtensionTestMessageListener listener("worker-initialized");
-  // ASSERT_TRUE(listener.WaitUntilSatisfied());
-  // Automated tests need to wait for this, otherwise we crash in
-  // browser_test cleanup because the worker process still has
-  // URL requests in-flight.
-  var test = chrome.test || window.top.chrome.test;
-  test.sendMessage('worker-initialized');
-  this.initialized_ = true;
-};
-
-/**
- * Converts content metadata from parsers to the internal format.
- * @param {Object} metadata The content metadata.
- * @param {Object=} opt_result The internal metadata object ot put result in.
- * @return {Object!} Converted metadata.
- */
-ContentProvider.ConvertContentMetadata = function(metadata, opt_result) {
-  var result = opt_result || {};
-
-  if ('thumbnailURL' in metadata) {
-    metadata.thumbnailTransform = metadata.thumbnailTransform || null;
-    result.thumbnail = {
-      url: metadata.thumbnailURL,
-      transform: metadata.thumbnailTransform
-    };
-  }
-
-  for (var key in metadata) {
-    if (metadata.hasOwnProperty(key)) {
-      if (!('media' in result)) result.media = {};
-      result.media[key] = metadata[key];
-    }
-  }
-
-  if ('media' in result) {
-    result.fetchedMedia = result.media;
-  }
-
-  return result;
-};
-
-/**
- * Handles the 'result' message from the worker.
- * @param {string} url File url.
- * @param {Object} metadata The metadata.
- * @private
- */
-ContentProvider.prototype.onResult_ = function(url, metadata) {
-  var callback = this.callbacks_[url];
-  delete this.callbacks_[url];
-  callback(ContentProvider.ConvertContentMetadata(metadata));
-};
-
-/**
- * Handles the 'error' message from the worker.
- * @param {string} url File url.
- * @param {string} step Step failed.
- * @param {string} error Error description.
- * @param {Object?} metadata The metadata, if available.
- * @private
- */
-ContentProvider.prototype.onError_ = function(url, step, error, metadata) {
-  if (MetadataCache.log)  // Avoid log spam by default.
-    console.warn('metadata: ' + url + ': ' + step + ': ' + error);
-  metadata = metadata || {};
-  // Prevent asking for thumbnail again.
-  metadata.thumbnailURL = '';
-  this.onResult_(url, metadata);
-};
-
-/**
- * Handles the 'log' message from the worker.
- * @param {Array.<*>} arglist Log arguments.
- * @private
- */
-ContentProvider.prototype.onLog_ = function(arglist) {
-  if (MetadataCache.log)  // Avoid log spam by default.
-    console.log.apply(console, ['metadata:'].concat(arglist));
-};
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js b/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js
deleted file mode 100644
index 270282f..0000000
--- a/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-// All of these scripts could be imported with a single call to importScripts,
-// but then load and compile time errors would all be reported from the same
-// line.
-importScripts('metadata_parser.js');
-importScripts('byte_reader.js');
-importScripts('../util.js');
-
-/**
- * Dispatches metadata requests to the correct parser.
- *
- * @param {Object} port Worker port.
- * @constructor
- */
-function MetadataDispatcher(port) {
-  this.port_ = port;
-  this.port_.onmessage = this.onMessage.bind(this);
-
-  // Make sure to update component_extension_resources.grd
-  // when adding new parsers.
-  importScripts('exif_parser.js');
-  importScripts('image_parsers.js');
-  importScripts('mpeg_parser.js');
-  importScripts('id3_parser.js');
-
-  var patterns = [];
-
-  this.parserInstances_ = [];
-  for (var i = 0; i < MetadataDispatcher.parserClasses_.length; i++) {
-    var parserClass = MetadataDispatcher.parserClasses_[i];
-    var parser = new parserClass(this);
-    this.parserInstances_.push(parser);
-    patterns.push(parser.urlFilter.source);
-  }
-
-  this.parserRegexp_ = new RegExp('(' + patterns.join('|') + ')', 'i');
-
-  this.messageHandlers_ = {
-    init: this.init_.bind(this),
-    request: this.request_.bind(this)
-  };
-}
-
-/**
- * List of registered parser classes.
- * @private
- */
-MetadataDispatcher.parserClasses_ = [];
-
-/**
- * @param {function} parserClass Parser constructor function.
- */
-MetadataDispatcher.registerParserClass = function(parserClass) {
-  MetadataDispatcher.parserClasses_.push(parserClass);
-};
-
-/**
- * Verbose logging for the dispatcher.
- *
- * Individual parsers also take this as their default verbosity setting.
- */
-MetadataDispatcher.prototype.verbose = false;
-
-/**
- * |init| message handler.
- * @private
- */
-MetadataDispatcher.prototype.init_ = function() {
-  // Inform our owner that we're done initializing.
-  // If we need to pass more data back, we can add it to the param array.
-  this.postMessage('initialized', [this.parserRegexp_]);
-  this.log('initialized with URL filter ' + this.parserRegexp_);
-};
-
-/**
- * |request| message handler.
- * @param {string} fileURL File URL.
- * @private
- */
-MetadataDispatcher.prototype.request_ = function(fileURL) {
-  try {
-    this.processOneFile(fileURL, function callback(metadata) {
-        this.postMessage('result', [fileURL, metadata]);
-    }.bind(this));
-  } catch (ex) {
-    this.error(fileURL, ex);
-  }
-};
-
-/**
- * Indicate to the caller that an operation has failed.
- *
- * No other messages relating to the failed operation should be sent.
- * @param {...Object} var_args Arguments.
- */
-MetadataDispatcher.prototype.error = function(var_args) {
-  var ary = Array.apply(null, arguments);
-  this.postMessage('error', ary);
-};
-
-/**
- * Send a log message to the caller.
- *
- * Callers must not parse log messages for control flow.
- * @param {...Object} var_args Arguments.
- */
-MetadataDispatcher.prototype.log = function(var_args) {
-  var ary = Array.apply(null, arguments);
-  this.postMessage('log', ary);
-};
-
-/**
- * Send a log message to the caller only if this.verbose is true.
- * @param {...Object} var_args Arguments.
- */
-MetadataDispatcher.prototype.vlog = function(var_args) {
-  if (this.verbose)
-    this.log.apply(this, arguments);
-};
-
-/**
- * Post a properly formatted message to the caller.
- * @param {string} verb Message type descriptor.
- * @param {Array.<Object>} args Arguments array.
- */
-MetadataDispatcher.prototype.postMessage = function(verb, args) {
-  this.port_.postMessage({verb: verb, arguments: args});
-};
-
-/**
- * Message handler.
- * @param {Event} event Event object.
- */
-MetadataDispatcher.prototype.onMessage = function(event) {
-  var data = event.data;
-
-  if (this.messageHandlers_.hasOwnProperty(data.verb)) {
-    this.messageHandlers_[data.verb].apply(this, data.arguments);
-  } else {
-    this.log('Unknown message from client: ' + data.verb, data);
-  }
-};
-
-/**
- * @param {string} fileURL File URL.
- * @param {function(Object)} callback Completion callback.
- */
-MetadataDispatcher.prototype.processOneFile = function(fileURL, callback) {
-  var self = this;
-  var currentStep = -1;
-
-  function nextStep(var_args) {
-    self.vlog('nextStep: ' + steps[currentStep + 1].name);
-    steps[++currentStep].apply(self, arguments);
-  }
-
-  var metadata;
-
-  function onError(err, stepName) {
-    self.error(fileURL, stepName || steps[currentStep].name, err.toString(),
-        metadata);
-  }
-
-  var steps =
-  [ // Step one, find the parser matching the url.
-    function detectFormat() {
-      for (var i = 0; i != self.parserInstances_.length; i++) {
-        var parser = self.parserInstances_[i];
-        if (fileURL.match(parser.urlFilter)) {
-          // Create the metadata object as early as possible so that we can
-          // pass it with the error message.
-          metadata = parser.createDefaultMetadata();
-          nextStep(parser);
-          return;
-        }
-      }
-      onError('unsupported format');
-    },
-
-    // Step two, turn the url into an entry.
-    function getEntry(parser) {
-      webkitResolveLocalFileSystemURL(
-          fileURL,
-          function(entry) { nextStep(entry, parser) },
-          onError);
-    },
-
-    // Step three, turn the entry into a file.
-    function getFile(entry, parser) {
-      entry.file(function(file) { nextStep(file, parser) }, onError);
-    },
-
-    // Step four, parse the file content.
-    function parseContent(file, parser) {
-      metadata.fileSize = file.size;
-      try {
-        parser.parse(file, metadata, callback, onError);
-      } catch (e) {
-        onError(e.stack);
-      }
-    }
-  ];
-
-  nextStep();
-};
-
-// Webworker spec says that the worker global object is called self.  That's
-// a terrible name since we use it all over the chrome codebase to capture
-// the 'this' keyword in lambdas.
-var global = self;
-
-if (global.constructor.name == 'SharedWorkerGlobalScope') {
-  global.addEventListener('connect', function(e) {
-    var port = e.ports[0];
-    new MetadataDispatcher(port);
-    port.start();
-  });
-} else {
-  // Non-shared worker.
-  new MetadataDispatcher(global);
-}
diff --git a/chrome/browser/resources/file_manager/js/navigation_list.js b/chrome/browser/resources/file_manager/js/navigation_list.js
deleted file mode 100644
index deb08a4..0000000
--- a/chrome/browser/resources/file_manager/js/navigation_list.js
+++ /dev/null
@@ -1,729 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Entry of NavigationListModel. This constructor should be called only from
- * the helper methods (NavigationModelItem.createFromPath/createFromEntry).
- *
- * @param {string} path Path.
- * @param {DirectoryEntry} entry Entry. Can be null.
- * @constructor
- */
-function NavigationModelItem(path, entry) {
-  this.path_ = path;
-  this.entry_ = entry;
-  this.resolvingQueue_ = new AsyncUtil.Queue();
-
-  Object.seal(this);
-}
-
-NavigationModelItem.prototype = {
-  get path() { return this.path_; },
-};
-
-/**
- * Returns the cached entry of the item. This may return NULL if the target is
- * not available on the filesystem, is not resolved or is under resolving the
- * entry.
- *
- * @return {Entry} Cached entry.
- */
-NavigationModelItem.prototype.getCachedEntry = function() {
-  return this.entry_;
-};
-
-/**
- * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
- * @param {string} path Path.
- * @param {function(FileError)} errorCallback Called when the resolving is
- *     failed with the error.
- * @return {NavigationModelItem} Created NavigationModelItem.
- */
-NavigationModelItem.createFromPath = function(
-    volumeManager, path, errorCallback) {
-  var item = new NavigationModelItem(path, null);
-  item.resolvingQueue_.run(function(continueCallback) {
-    volumeManager.resolvePath(
-        path,
-        function(entry) {
-          if (entry.isDirectory)
-            item.entry_ = entry;
-          else
-            errorCallback(util.createFileError(FileError.TYPE_MISMATCH_ERR));
-          continueCallback();
-        },
-        function(error) {
-          errorCallback(error);
-          continueCallback();
-        });
-  });
-  return item;
-};
-
-/**
- * @param {DirectoryEntry} entry Entry. Can be null.
- * @return {NavigationModelItem} Created NavigationModelItem.
- */
-NavigationModelItem.createFromEntry = function(entry) {
-  if (!entry)
-    return null;
-  return new NavigationModelItem(entry.fullPath, entry);
-};
-
-/**
- * Retrieves the entry. If the entry is being retrieved, waits until it
- * finishes.
- * @param {function(Entry)} callback Called with the resolved entry. The entry
- *     may be NULL if resolving is failed.
- */
-NavigationModelItem.prototype.getEntryAsync = function(callback) {
-  // If resolving the entry is running, wait until it finishes.
-  this.resolvingQueue_.run(function(continueCallback) {
-    callback(this.entry_);
-    continueCallback();
-  }.bind(this));
-};
-
-/**
- * Returns if this item is a shortcut or a volume root.
- * @return {boolean} True if a shortcut, false if a volume root.
- */
-NavigationModelItem.prototype.isShortcut = function() {
-  return !PathUtil.isRootPath(this.path_);
-};
-
-/**
- * A navigation list model. This model combines the 2 lists.
- * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
- * @param {cr.ui.ArrayDataModel} shortcutListModel The list of folder shortcut.
- * @constructor
- * @extends {cr.EventTarget}
- */
-function NavigationListModel(volumeManager, shortcutListModel) {
-  cr.EventTarget.call(this);
-
-  this.volumeManager_ = volumeManager;
-  this.shortcutListModel_ = shortcutListModel;
-
-  var volumeInfoToModelItem = function(volumeInfo) {
-    if (volumeInfo.volumeType == util.VolumeType.DRIVE) {
-      // For drive volume, we assign the path to "My Drive".
-      return NavigationModelItem.createFromPath(
-          this.volumeManager_,
-          volumeInfo.mountPath + '/root',
-          function() {});
-    } else {
-      return NavigationModelItem.createFromEntry(volumeInfo.root);
-    }
-  }.bind(this);
-
-  var pathToModelItem = function(path) {
-    var item = NavigationModelItem.createFromPath(
-        this.volumeManager_,
-        path,
-        function(error) {
-          if (error.code == FileError.NOT_FOUND_ERR)
-            this.onItemNotFoundError(item);
-         }.bind(this));
-    return item;
-  }.bind(this);
-
-  /**
-   * Type of updated list.
-   * @enum {number}
-   * @const
-   */
-  var ListType = {
-    VOLUME_LIST: 1,
-    SHORTCUT_LIST: 2
-  };
-  Object.freeze(ListType);
-
-  // Generates this.volumeList_ and this.shortcutList_ from the models.
-  this.volumeList_ =
-      this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem);
-
-  this.shortcutList_ = [];
-  for (var i = 0; i < this.shortcutListModel_.length; i++) {
-    var shortcutPath = this.shortcutListModel_.item(modelIndex);
-    var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
-        RootDirectory.DRIVE :
-        PathUtil.getRootPath(shortcutPath);
-    var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
-    var isMounted = volumeInfo && !volumeInfo.error;
-    if (isMounted)
-      this.shortcutList_.push(pathToModelItem(shortcutPath));
-  }
-
-  // Generates a combined 'permuted' event from an event of either list.
-  var permutedHandler = function(listType, event) {
-    var permutation;
-
-    // Build the volumeList.
-    if (listType == ListType.VOLUME_LIST) {
-      // The volume is mounted or unmounted.
-      var newList = [];
-
-      // Use the old instances if they just move.
-      for (var i = 0; i < event.permutation.length; i++) {
-        if (event.permutation[i] >= 0)
-          newList[event.permutation[i]] = this.volumeList_[i];
-      }
-
-      // Create missing instances.
-      for (var i = 0; i < event.newLength; i++) {
-        if (!newList[i]) {
-          newList[i] = volumeInfoToModelItem(
-              this.volumeManager_.volumeInfoList.item(i));
-        }
-      }
-      this.volumeList_ = newList;
-
-      permutation = event.permutation.slice();
-    } else {
-      // volumeList part has not been changed, so the permutation should be
-      // idenetity mapping.
-      permutation = [];
-      for (var i = 0; i < this.volumeList_.length; i++)
-        permutation[i] = i;
-    }
-
-    // Build the shortcutList. Even if the event is for the volumeInfoList
-    // update, the short cut path may be unmounted or newly mounted. So, here
-    // shortcutList will always be re-built.
-    // Currently this code may be redundant, as shortcut folder is supported
-    // only on Drive File System and we can assume single-profile, but
-    // multi-profile will be supported later.
-    // The shortcut list is sorted in case-insensitive lexicographical order.
-    // So we just can traverse the two list linearly.
-    var modelIndex = 0;
-    var oldListIndex = 0;
-    var newList = [];
-    while (modelIndex < this.shortcutListModel_.length &&
-           oldListIndex < this.shortcutList_.length) {
-      var shortcutPath = this.shortcutListModel_.item(modelIndex);
-      var cmp = this.shortcutListModel_.compare(
-          shortcutPath, this.shortcutList_[oldListIndex].path);
-      if (cmp > 0) {
-        // The shortcut at shortcutList_[oldListIndex] is removed.
-        permutation.push(-1);
-        oldListIndex++;
-        continue;
-      }
-
-      // Check if the volume where the shortcutPath is is mounted or not.
-      var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
-          RootDirectory.DRIVE :
-          PathUtil.getRootPath(shortcutPath);
-      var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
-      var isMounted = volumeInfo && !volumeInfo.error;
-      if (cmp == 0) {
-        // There exists an old NavigationModelItem instance.
-        if (isMounted) {
-          // Reuse the old instance.
-          permutation.push(newList.length + this.volumeList_.length);
-          newList.push(this.shortcutList_[oldListIndex]);
-        } else {
-          permutation.push(-1);
-        }
-        oldListIndex++;
-      } else {
-        // We needs to create a new instance for the shortcut path.
-        if (isMounted)
-          newList.push(pathToModelItem(shortcutPath));
-      }
-      modelIndex++;
-    }
-
-    // Add remaining (new) shortcuts if necessary.
-    for (; modelIndex < this.shortcutListModel_.length; modelIndex++) {
-      var shortcutPath = this.shortcutListModel_.item(modelIndex);
-      var mountPath = PathUtil.isDriveBasedPath(shortcutPath) ?
-          RootDirectory.DRIVE :
-          PathUtil.getRootPath(shortcutPath);
-      var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath);
-      var isMounted = volumeInfo && !volumeInfo.error;
-      if (isMounted)
-        newList.push(pathToModelItem(shortcutPath));
-    }
-
-    // Fill remaining permutation if necessary.
-    for (; oldListIndex < this.shortcutList_.length; oldListIndex++)
-      permutation.push(-1);
-
-    this.shortcutList_ = newList;
-
-    // Dispatch permuted event.
-    var permutedEvent = new Event('permuted');
-    permutedEvent.newLength =
-        this.volumeList_.length + this.shortcutList_.length;
-    permutedEvent.permutation = permutation;
-    this.dispatchEvent(permutedEvent);
-  };
-
-  this.volumeManager_.volumeInfoList.addEventListener(
-      'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST));
-  this.shortcutListModel_.addEventListener(
-      'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST));
-
-  // 'change' event is just ignored, because it is not fired neither in
-  // the folder shortcut list nor in the volume info list.
-  // 'splice' and 'sorted' events are not implemented, since they are not used
-  // in list.js.
-}
-
-/**
- * NavigationList inherits cr.EventTarget.
- */
-NavigationListModel.prototype = {
-  __proto__: cr.EventTarget.prototype,
-  get length() { return this.length_(); },
-  get folderShortcutList() { return this.shortcutList_; }
-};
-
-/**
- * Returns the item at the given index.
- * @param {number} index The index of the entry to get.
- * @return {?string} The path at the given index.
- */
-NavigationListModel.prototype.item = function(index) {
-  var offset = this.volumeList_.length;
-  if (index < offset)
-    return this.volumeList_[index];
-  return this.shortcutList_[index - offset];
-};
-
-/**
- * Returns the number of items in the model.
- * @return {number} The length of the model.
- * @private
- */
-NavigationListModel.prototype.length_ = function() {
-  return this.volumeList_.length + this.shortcutList_.length;
-};
-
-/**
- * Returns the first matching item.
- * @param {NavigationModelItem} modelItem The entry to find.
- * @param {number=} opt_fromIndex If provided, then the searching start at
- *     the {@code opt_fromIndex}.
- * @return {number} The index of the first found element or -1 if not found.
- */
-NavigationListModel.prototype.indexOf = function(modelItem, opt_fromIndex) {
-  for (var i = opt_fromIndex || 0; i < this.length; i++) {
-    if (modelItem === this.item(i))
-      return i;
-  }
-  return -1;
-};
-
-/**
- * Called when one od the items is not found on the filesystem.
- * @param {NavigationModelItem} modelItem The entry which is not found.
- */
-NavigationListModel.prototype.onItemNotFoundError = function(modelItem) {
-  var index = this.indexOf(modelItem);
-  if (index === -1) {
-    // Invalid modelItem.
-  } else if (index < this.volumeList_.length) {
-    // The item is in the volume list.
-    // Not implemented.
-    // TODO(yoshiki): Implement it when necessary.
-  } else {
-    // The item is in the folder shortcut list.
-    if (this.isDriveMounted())
-      this.shortcutListModel_.remove(modelItem.path);
-  }
-};
-
-/**
- * Returns if the drive is mounted or not.
- * @return {boolean} True if the drive is mounted, false otherwise.
- */
-NavigationListModel.prototype.isDriveMounted = function() {
-  return !!this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
-};
-
-/**
- * A navigation list item.
- * @constructor
- * @extends {HTMLLIElement}
- */
-var NavigationListItem = cr.ui.define('li');
-
-NavigationListItem.prototype = {
-  __proto__: HTMLLIElement.prototype,
-  get modelItem() { return this.modelItem_; }
-};
-
-/**
- * Decorate the item.
- */
-NavigationListItem.prototype.decorate = function() {
-  // decorate() may be called twice: from the constructor and from
-  // List.createItem(). This check prevents double-decorating.
-  if (this.className)
-    return;
-
-  this.className = 'root-item';
-  this.setAttribute('role', 'option');
-
-  this.iconDiv_ = cr.doc.createElement('div');
-  this.iconDiv_.className = 'volume-icon';
-  this.appendChild(this.iconDiv_);
-
-  this.label_ = cr.doc.createElement('div');
-  this.label_.className = 'root-label';
-  this.appendChild(this.label_);
-
-  cr.defineProperty(this, 'lead', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(this, 'selected', cr.PropertyKind.BOOL_ATTR);
-};
-
-/**
- * Associate a path with this item.
- * @param {NavigationModelItem} modelItem NavigationModelItem of this item.
- * @param {string=} opt_deviceType The type of the device. Available iff the
- *     path represents removable storage.
- */
-NavigationListItem.prototype.setModelItem =
-    function(modelItem, opt_deviceType) {
-  if (this.modelItem_)
-    console.warn('NavigationListItem.setModelItem should be called only once.');
-
-  this.modelItem_ = modelItem;
-
-  var rootType = PathUtil.getRootType(modelItem.path);
-  this.iconDiv_.setAttribute('volume-type-icon', rootType);
-  if (opt_deviceType) {
-    this.iconDiv_.setAttribute('volume-subtype', opt_deviceType);
-  }
-
-  this.label_.textContent = PathUtil.getFolderLabel(modelItem.path);
-
-  if (rootType === RootType.ARCHIVE || rootType === RootType.REMOVABLE) {
-    this.eject_ = cr.doc.createElement('div');
-    // Block other mouse handlers.
-    this.eject_.addEventListener(
-        'mouseup', function(event) { event.stopPropagation() });
-    this.eject_.addEventListener(
-        'mousedown', function(event) { event.stopPropagation() });
-
-    this.eject_.className = 'root-eject';
-    this.eject_.addEventListener('click', function(event) {
-      event.stopPropagation();
-      cr.dispatchSimpleEvent(this, 'eject');
-    }.bind(this));
-
-    this.appendChild(this.eject_);
-  }
-};
-
-/**
- * Associate a context menu with this item.
- * @param {cr.ui.Menu} menu Menu this item.
- */
-NavigationListItem.prototype.maybeSetContextMenu = function(menu) {
-  if (!this.modelItem_.path) {
-    console.error('NavigationListItem.maybeSetContextMenu must be called ' +
-                  'after setModelItem().');
-    return;
-  }
-
-  var isRoot = PathUtil.isRootPath(this.modelItem_.path);
-  var rootType = PathUtil.getRootType(this.modelItem_.path);
-  // The context menu is shown on the following items:
-  // - Removable and Archive volumes
-  // - Folder shortcuts
-  if (!isRoot ||
-      (rootType != RootType.DRIVE && rootType != RootType.DOWNLOADS))
-    cr.ui.contextMenuHandler.setContextMenu(this, menu);
-};
-
-/**
- * A navigation list.
- * @constructor
- * @extends {cr.ui.List}
- */
-function NavigationList() {
-}
-
-/**
- * NavigationList inherits cr.ui.List.
- */
-NavigationList.prototype = {
-  __proto__: cr.ui.List.prototype,
-
-  set dataModel(dataModel) {
-    if (!this.onListContentChangedBound_)
-      this.onListContentChangedBound_ = this.onListContentChanged_.bind(this);
-
-    if (this.dataModel_) {
-      this.dataModel_.removeEventListener(
-          'change', this.onListContentChangedBound_);
-      this.dataModel_.removeEventListener(
-          'permuted', this.onListContentChangedBound_);
-    }
-
-    var parentSetter = cr.ui.List.prototype.__lookupSetter__('dataModel');
-    parentSetter.call(this, dataModel);
-
-    // This must be placed after the parent method is called, in order to make
-    // it sure that the list was changed.
-    dataModel.addEventListener('change', this.onListContentChangedBound_);
-    dataModel.addEventListener('permuted', this.onListContentChangedBound_);
-  },
-
-  get dataModel() {
-    return this.dataModel_;
-  },
-
-  // TODO(yoshiki): Add a setter of 'directoryModel'.
-};
-
-/**
- * @param {HTMLElement} el Element to be DirectoryItem.
- * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- *     folders.
- */
-NavigationList.decorate = function(el, volumeManager, directoryModel) {
-  el.__proto__ = NavigationList.prototype;
-  el.decorate(volumeManager, directoryModel);
-};
-
-/**
- * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- */
-NavigationList.prototype.decorate = function(volumeManager, directoryModel) {
-  cr.ui.List.decorate(this);
-  this.__proto__ = NavigationList.prototype;
-
-  this.directoryModel_ = directoryModel;
-  this.volumeManager_ = volumeManager;
-  this.selectionModel = new cr.ui.ListSingleSelectionModel();
-
-  this.directoryModel_.addEventListener('directory-changed',
-      this.onCurrentDirectoryChanged_.bind(this));
-  this.selectionModel.addEventListener(
-      'change', this.onSelectionChange_.bind(this));
-  this.selectionModel.addEventListener(
-      'beforeChange', this.onBeforeSelectionChange_.bind(this));
-
-  this.scrollBar_ = new ScrollBar();
-  this.scrollBar_.initialize(this.parentNode, this);
-
-  // Overriding default role 'list' set by cr.ui.List.decorate() to 'listbox'
-  // role for better accessibility on ChromeOS.
-  this.setAttribute('role', 'listbox');
-
-  var self = this;
-  this.itemConstructor = function(modelItem) {
-    return self.renderRoot_(modelItem);
-  };
-};
-
-/**
- * This overrides cr.ui.List.measureItem().
- * In the method, a temporary element is added/removed from the list, and we
- * need to omit animations for such temporary items.
- *
- * @param {ListItem=} opt_item The list item to be measured.
- * @return {{height: number, marginTop: number, marginBottom:number,
- *     width: number, marginLeft: number, marginRight:number}} Size.
- * @override
- */
-NavigationList.prototype.measureItem = function(opt_item) {
-  this.measuringTemporaryItemNow_ = true;
-  var result = cr.ui.List.prototype.measureItem.call(this, opt_item);
-  this.measuringTemporaryItemNow_ = false;
-  return result;
-};
-
-/**
- * Creates an element of a navigation list. This method is called from
- * cr.ui.List internally.
- *
- * @param {NavigationModelItem} modelItem NavigationModelItem to be rendered.
- * @return {NavigationListItem} Rendered element.
- * @private
- */
-NavigationList.prototype.renderRoot_ = function(modelItem) {
-  var item = new NavigationListItem();
-  var volumeInfo =
-      PathUtil.isRootPath(modelItem.path) &&
-      this.volumeManager_.getVolumeInfo(modelItem.path);
-  item.setModelItem(modelItem, volumeInfo && volumeInfo.deviceType);
-
-  var handleClick = function() {
-    if (item.selected &&
-        modelItem.path !== this.directoryModel_.getCurrentDirPath()) {
-      metrics.recordUserAction('FolderShortcut.Navigate');
-      this.changeDirectory_(modelItem);
-    }
-  }.bind(this);
-  item.addEventListener('click', handleClick);
-
-  var handleEject = function() {
-    var unmountCommand = cr.doc.querySelector('command#unmount');
-    // Let's make sure 'canExecute' state of the command is properly set for
-    // the root before executing it.
-    unmountCommand.canExecuteChange(item);
-    unmountCommand.execute(item);
-  };
-  item.addEventListener('eject', handleEject);
-
-  if (this.contextMenu_)
-    item.maybeSetContextMenu(this.contextMenu_);
-
-  return item;
-};
-
-/**
- * Changes the current directory to the given path.
- * If the given path is not found, a 'shortcut-target-not-found' event is
- * fired.
- *
- * @param {NavigationModelItem} modelItem Directory to be chagned to.
- * @private
- */
-NavigationList.prototype.changeDirectory_ = function(modelItem) {
-  var onErrorCallback = function(error) {
-    if (error.code === FileError.NOT_FOUND_ERR)
-      this.dataModel.onItemNotFoundError(modelItem);
-  }.bind(this);
-
-  this.directoryModel_.changeDirectory(modelItem.path, onErrorCallback);
-};
-
-/**
- * Sets a context menu. Context menu is enabled only on archive and removable
- * volumes as of now.
- *
- * @param {cr.ui.Menu} menu Context menu.
- */
-NavigationList.prototype.setContextMenu = function(menu) {
-  this.contextMenu_ = menu;
-
-  for (var i = 0; i < this.dataModel.length; i++) {
-    this.getListItemByIndex(i).maybeSetContextMenu(this.contextMenu_);
-  }
-};
-
-/**
- * Selects the n-th item from the list.
- *
- * @param {number} index Item index.
- * @return {boolean} True for success, otherwise false.
- */
-NavigationList.prototype.selectByIndex = function(index) {
-  if (index < 0 || index > this.dataModel.length - 1)
-    return false;
-
-  var newModelItem = this.dataModel.item(index);
-  var newPath = newModelItem.path;
-  if (!newPath)
-    return false;
-
-  // Prevents double-moving to the current directory.
-  // eg. When user clicks the item, changing directory has already been done in
-  //     click handler.
-  var entry = this.directoryModel_.getCurrentDirEntry();
-  if (entry && entry.fullPath == newPath)
-    return false;
-
-  metrics.recordUserAction('FolderShortcut.Navigate');
-  this.changeDirectory_(newModelItem);
-  return true;
-};
-
-/**
- * Handler before root item change.
- * @param {Event} event The event.
- * @private
- */
-NavigationList.prototype.onBeforeSelectionChange_ = function(event) {
-  if (event.changes.length == 1 && !event.changes[0].selected)
-    event.preventDefault();
-};
-
-/**
- * Handler for root item being clicked.
- * @param {Event} event The event.
- * @private
- */
-NavigationList.prototype.onSelectionChange_ = function(event) {
-  // This handler is invoked even when the navigation list itself changes the
-  // selection. In such case, we shouldn't handle the event.
-  if (this.dontHandleSelectionEvent_)
-    return;
-
-  this.selectByIndex(this.selectionModel.selectedIndex);
-};
-
-/**
- * Invoked when the current directory is changed.
- * @param {Event} event The event.
- * @private
- */
-NavigationList.prototype.onCurrentDirectoryChanged_ = function(event) {
-  this.selectBestMatchItem_();
-};
-
-/**
- * Invoked when the content in the data model is changed.
- * @param {Event} event The event.
- * @private
- */
-NavigationList.prototype.onListContentChanged_ = function(event) {
-  this.selectBestMatchItem_();
-};
-
-/**
- * Synchronizes the volume list selection with the current directory, after
- * it is changed outside of the volume list.
- * @private
- */
-NavigationList.prototype.selectBestMatchItem_ = function() {
-  var entry = this.directoryModel_.getCurrentDirEntry();
-  var path = entry && entry.fullPath;
-  if (!path)
-    return;
-
-  // (1) Select the nearest parent directory (including the shortcut folders).
-  var bestMatchIndex = -1;
-  var bestMatchSubStringLen = 0;
-  for (var i = 0; i < this.dataModel.length; i++) {
-    var itemPath = this.dataModel.item(i).path;
-    if (path.indexOf(itemPath) == 0) {
-      if (bestMatchSubStringLen < itemPath.length) {
-        bestMatchIndex = i;
-        bestMatchSubStringLen = itemPath.length;
-      }
-    }
-  }
-  if (bestMatchIndex != -1) {
-    // Not to invoke the handler of this instance, sets the guard.
-    this.dontHandleSelectionEvent_ = true;
-    this.selectionModel.selectedIndex = bestMatchIndex;
-    this.dontHandleSelectionEvent_ = false;
-    return;
-  }
-
-  // (2) Selects the volume of the current directory.
-  var newRootPath = PathUtil.getRootPath(path);
-  for (var i = 0; i < this.dataModel.length; i++) {
-    var itemPath = this.dataModel.item(i).path;
-    if (PathUtil.getRootPath(itemPath) == newRootPath) {
-      // Not to invoke the handler of this instance, sets the guard.
-      this.dontHandleSelectionEvent_ = true;
-      this.selectionModel.selectedIndex = i;
-      this.dontHandleSelectionEvent_ = false;
-      return;
-    }
-  }
-};
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery.js b/chrome/browser/resources/file_manager/js/photo/gallery.js
deleted file mode 100644
index 1a40749..0000000
--- a/chrome/browser/resources/file_manager/js/photo/gallery.js
+++ /dev/null
@@ -1,870 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Called from the main frame when unloading.
- * @return {string?} User-visible message on null if it is OK to close.
- */
-function beforeunload() { return Gallery.instance.onBeforeUnload() }
-
-/**
- * Called from the main frame when unloading.
- * @param {boolean=} opt_exiting True if the app is exiting.
- */
-function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting) }
-
-/**
- * Gallery for viewing and editing image files.
- *
- * @param {Object} context Object containing the following:
- *     {function(string)} onNameChange Called every time a selected
- *         item name changes (on rename and on selection change).
- *     {AppWindow} appWindow
- *     {function(string)} onBack
- *     {function()} onClose
- *     {function()} onMaximize
- *     {MetadataCache} metadataCache
- *     {Array.<Object>} shareActions
- *     {string} readonlyDirName Directory name for readonly warning or null.
- *     {DirEntry} saveDirEntry Directory to save to.
- *     {function(string)} displayStringFunction.
- * @param {VolumeManagerWrapper} volumeManager The VolumeManager instance of
- *      the system.
- * @class
- * @constructor
- */
-function Gallery(context, volumeManager) {
-  this.container_ = document.querySelector('.gallery');
-  this.document_ = document;
-  this.context_ = context;
-  this.metadataCache_ = context.metadataCache;
-  this.volumeManager_ = volumeManager;
-
-  this.dataModel_ = new cr.ui.ArrayDataModel([]);
-  this.selectionModel_ = new cr.ui.ListSelectionModel();
-  this.displayStringFunction_ = context.displayStringFunction;
-
-  this.initDom_();
-  this.initListeners_();
-}
-
-/**
- * Gallery extends cr.EventTarget.
- */
-Gallery.prototype.__proto__ = cr.EventTarget.prototype;
-
-/**
- * Create and initialize a Gallery object based on a context.
- *
- * @param {Object} context Gallery context.
- * @param {VolumeManagerWrapper} volumeManager VolumeManager of the system.
- * @param {Array.<string>} urls Array of urls.
- * @param {Array.<string>} selectedUrls Array of selected urls.
- */
-Gallery.open = function(context, volumeManager, urls, selectedUrls) {
-  Gallery.instance = new Gallery(context, volumeManager);
-  Gallery.instance.load(urls, selectedUrls);
-};
-
-/**
- * Tools fade-out timeout im milliseconds.
- * @const
- * @type {number}
- */
-Gallery.FADE_TIMEOUT = 3000;
-
-/**
- * First time tools fade-out timeout im milliseconds.
- * @const
- * @type {number}
- */
-Gallery.FIRST_FADE_TIMEOUT = 1000;
-
-/**
- * Time until mosaic is initialized in the background. Used to make gallery
- * in the slide mode load faster. In miiliseconds.
- * @const
- * @type {number}
- */
-Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000;
-
-/**
- * Types of metadata Gallery uses (to query the metadata cache).
- * @const
- * @type {string}
- */
-Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|streaming|drive';
-
-/**
- * Initialize listeners.
- * @private
- */
-Gallery.prototype.initListeners_ = function() {
-  this.document_.oncontextmenu = function(e) { e.preventDefault(); };
-  this.keyDownBound_ = this.onKeyDown_.bind(this);
-  this.document_.body.addEventListener('keydown', this.keyDownBound_);
-
-  this.inactivityWatcher_ = new MouseInactivityWatcher(
-      this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this));
-
-  // Search results may contain files from different subdirectories so
-  // the observer is not going to work.
-  if (!this.context_.searchResults && this.context_.curDirEntry) {
-    this.thumbnailObserverId_ = this.metadataCache_.addObserver(
-        this.context_.curDirEntry,
-        MetadataCache.CHILDREN,
-        'thumbnail',
-        this.updateThumbnails_.bind(this));
-  }
-
-  this.volumeManager_.addEventListener('externally-unmounted',
-      this.onExternallyUnmounted_.bind(this));
-};
-
-/**
- * Closes gallery when a volume containing the selected item is unmounted.
- * @param {Event} event The unmount event.
- * @private
- */
-Gallery.prototype.onExternallyUnmounted_ = function(event) {
-  if (!this.selectedItemFilesystemPath_)
-    return;
-  if (this.selectedItemFilesystemPath_.indexOf(event.mountPath) == 0)
-    this.onBack_();
-};
-
-/**
- * Beforeunload handler.
- * @return {string?} User-visible message on null if it is OK to close.
- */
-Gallery.prototype.onBeforeUnload = function() {
-  return this.slideMode_.onBeforeUnload();
-};
-
-/**
- * Unload the Gallery.
- * @param {boolean} exiting True if the app is exiting.
- */
-Gallery.prototype.onUnload = function(exiting) {
-  if (!this.context_.searchResults) {
-    this.metadataCache_.removeObserver(this.thumbnailObserverId_);
-  }
-  this.slideMode_.onUnload(exiting);
-};
-
-/**
- * Initializes DOM UI
- * @private
- */
-Gallery.prototype.initDom_ = function() {
-  var content = util.createChild(this.container_, 'content');
-  content.addEventListener('click', this.onContentClick_.bind(this));
-
-  this.header_ = util.createChild(this.container_, 'header tool dimmable');
-  this.toolbar_ = util.createChild(this.container_, 'toolbar tool dimmable');
-
-  var backButton = util.createChild(this.container_,
-                                    'back-button tool dimmable');
-  util.createChild(backButton);
-  backButton.addEventListener('click', this.onBack_.bind(this));
-
-  var preventDefault = function(event) { event.preventDefault(); };
-
-  var maximizeButton = util.createChild(this.header_,
-                                        'maximize-button tool dimmable',
-                                        'button');
-  maximizeButton.tabIndex = -1;
-  maximizeButton.addEventListener('click', this.onMaximize_.bind(this));
-  maximizeButton.addEventListener('mousedown', preventDefault);
-
-  var closeButton = util.createChild(this.header_,
-                                     'close-button tool dimmable',
-                                     'button');
-  closeButton.tabIndex = -1;
-  closeButton.addEventListener('click', this.onClose_.bind(this));
-  closeButton.addEventListener('mousedown', preventDefault);
-
-  this.filenameSpacer_ = util.createChild(this.toolbar_, 'filename-spacer');
-  this.filenameEdit_ = util.createChild(this.filenameSpacer_,
-                                        'namebox', 'input');
-
-  this.filenameEdit_.setAttribute('type', 'text');
-  this.filenameEdit_.addEventListener('blur',
-      this.onFilenameEditBlur_.bind(this));
-
-  this.filenameEdit_.addEventListener('focus',
-      this.onFilenameFocus_.bind(this));
-
-  this.filenameEdit_.addEventListener('keydown',
-      this.onFilenameEditKeydown_.bind(this));
-
-  util.createChild(this.toolbar_, 'button-spacer');
-
-  this.prompt_ = new ImageEditor.Prompt(
-      this.container_, this.displayStringFunction_);
-
-  this.modeButton_ = util.createChild(this.toolbar_, 'button mode', 'button');
-  this.modeButton_.addEventListener('click',
-      this.toggleMode_.bind(this, null));
-
-  this.mosaicMode_ = new MosaicMode(content,
-                                    this.dataModel_,
-                                    this.selectionModel_,
-                                    this.metadataCache_,
-                                    this.toggleMode_.bind(this, null));
-
-  this.slideMode_ = new SlideMode(this.container_,
-                                  content,
-                                  this.toolbar_,
-                                  this.prompt_,
-                                  this.dataModel_,
-                                  this.selectionModel_,
-                                  this.context_,
-                                  this.toggleMode_.bind(this),
-                                  this.displayStringFunction_);
-
-  this.slideMode_.addEventListener('image-displayed', function() {
-    cr.dispatchSimpleEvent(this, 'image-displayed');
-  }.bind(this));
-  this.slideMode_.addEventListener('image-saved', function() {
-    cr.dispatchSimpleEvent(this, 'image-saved');
-  }.bind(this));
-
-  var deleteButton = this.createToolbarButton_('delete', 'GALLERY_DELETE');
-  deleteButton.addEventListener('click', this.delete_.bind(this));
-
-  this.shareButton_ = this.createToolbarButton_('share', 'GALLERY_SHARE');
-  this.shareButton_.setAttribute('disabled', '');
-  this.shareButton_.addEventListener('click', this.toggleShare_.bind(this));
-
-  this.shareMenu_ = util.createChild(this.container_, 'share-menu');
-  this.shareMenu_.hidden = true;
-  util.createChild(this.shareMenu_, 'bubble-point');
-
-  this.dataModel_.addEventListener('splice', this.onSplice_.bind(this));
-  this.dataModel_.addEventListener('content', this.onContentChange_.bind(this));
-
-  this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
-  this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this));
-};
-
-/**
- * Creates toolbar button.
- *
- * @param {string} className Class to add.
- * @param {string} title Button title.
- * @return {HTMLElement} Newly created button.
- * @private
- */
-Gallery.prototype.createToolbarButton_ = function(className, title) {
-  var button = util.createChild(this.toolbar_, className, 'button');
-  button.title = this.displayStringFunction_(title);
-  return button;
-};
-
-/**
- * Load the content.
- *
- * @param {Array.<string>} urls Array of urls.
- * @param {Array.<string>} selectedUrls Array of selected urls.
- */
-Gallery.prototype.load = function(urls, selectedUrls) {
-  var items = [];
-  for (var index = 0; index < urls.length; ++index) {
-    items.push(new Gallery.Item(urls[index]));
-  }
-  this.dataModel_.push.apply(this.dataModel_, items);
-
-  this.selectionModel_.adjustLength(this.dataModel_.length);
-
-  for (var i = 0; i != selectedUrls.length; i++) {
-    var selectedIndex = urls.indexOf(selectedUrls[i]);
-    if (selectedIndex >= 0)
-      this.selectionModel_.setIndexSelected(selectedIndex, true);
-    else
-      console.error('Cannot select ' + selectedUrls[i]);
-  }
-
-  if (this.selectionModel_.selectedIndexes.length == 0)
-    this.onSelection_();
-
-  var mosaic = this.mosaicMode_ && this.mosaicMode_.getMosaic();
-
-  // Mosaic view should show up if most of the selected files are images.
-  var imagesCount = 0;
-  for (var i = 0; i != selectedUrls.length; i++) {
-    if (FileType.getMediaType(selectedUrls[i]) == 'image')
-      imagesCount++;
-  }
-  var mostlyImages = imagesCount > (selectedUrls.length / 2.0);
-
-  var forcedMosaic = (this.context_.pageState &&
-       this.context_.pageState.gallery == 'mosaic');
-
-  var showMosaic = (mostlyImages && selectedUrls.length > 1) || forcedMosaic;
-  if (mosaic && showMosaic) {
-    this.setCurrentMode_(this.mosaicMode_);
-    mosaic.init();
-    mosaic.show();
-    this.inactivityWatcher_.check();  // Show the toolbar.
-    cr.dispatchSimpleEvent(this, 'loaded');
-  } else {
-    this.setCurrentMode_(this.slideMode_);
-    var maybeLoadMosaic = function() {
-      if (mosaic)
-        mosaic.init();
-      cr.dispatchSimpleEvent(this, 'loaded');
-    }.bind(this);
-    /* TODO: consider nice blow-up animation for the first image */
-    this.slideMode_.enter(null, function() {
-        // Flash the toolbar briefly to show it is there.
-        this.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT);
-      }.bind(this),
-      maybeLoadMosaic);
-  }
-};
-
-/**
- * Close the Gallery and go to Files.app.
- * @private
- */
-Gallery.prototype.back_ = function() {
-  if (util.isFullScreen(this.context_.appWindow)) {
-    util.toggleFullScreen(this.context_.appWindow,
-                          false);  // Leave the full screen mode.
-  }
-  this.context_.onBack(this.getSelectedUrls());
-};
-
-/**
- * Handle user's 'Back' action (Escape or a click on the X icon).
- * @private
- */
-Gallery.prototype.onBack_ = function() {
-  this.executeWhenReady(this.back_.bind(this));
-};
-
-/**
- * Handle user's 'Close' action.
- * @private
- */
-Gallery.prototype.onClose_ = function() {
-  this.executeWhenReady(this.context_.onClose);
-};
-
-/**
- * Handle user's 'Maximize' action (Escape or a click on the X icon).
- * @private
- */
-Gallery.prototype.onMaximize_ = function() {
-  this.executeWhenReady(this.context_.onMaximize);
-};
-
-/**
- * Execute a function when the editor is done with the modifications.
- * @param {function} callback Function to execute.
- */
-Gallery.prototype.executeWhenReady = function(callback) {
-  this.currentMode_.executeWhenReady(callback);
-};
-
-/**
- * @return {Object} File browser private API.
- */
-Gallery.getFileBrowserPrivate = function() {
-  return chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate;
-};
-
-/**
- * @return {boolean} True if some tool is currently active.
- */
-Gallery.prototype.hasActiveTool = function() {
-  return this.currentMode_.hasActiveTool() ||
-      this.isSharing_() || this.isRenaming_();
-};
-
-/**
-* External user action event handler.
-* @private
-*/
-Gallery.prototype.onUserAction_ = function() {
-  this.closeShareMenu_();
-  // Show the toolbar and hide it after the default timeout.
-  this.inactivityWatcher_.kick();
-};
-
-/**
- * Set the current mode, update the UI.
- * @param {Object} mode Current mode.
- * @private
- */
-Gallery.prototype.setCurrentMode_ = function(mode) {
-  if (mode != this.slideMode_ && mode != this.mosaicMode_)
-    console.error('Invalid Gallery mode');
-
-  this.currentMode_ = mode;
-  this.container_.setAttribute('mode', this.currentMode_.getName());
-  this.updateSelectionAndState_();
-  this.updateButtons_();
-};
-
-/**
- * Mode toggle event handler.
- * @param {function=} opt_callback Callback.
- * @param {Event=} opt_event Event that caused this call.
- * @private
- */
-Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) {
-  if (!this.modeButton_)
-    return;
-
-  if (this.changingMode_) // Do not re-enter while changing the mode.
-    return;
-
-  if (opt_event)
-    this.onUserAction_();
-
-  this.changingMode_ = true;
-
-  var onModeChanged = function() {
-    this.changingMode_ = false;
-    if (opt_callback) opt_callback();
-  }.bind(this);
-
-  var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
-
-  var mosaic = this.mosaicMode_.getMosaic();
-  var tileRect = mosaic.getTileRect(tileIndex);
-
-  if (this.currentMode_ == this.slideMode_) {
-    this.setCurrentMode_(this.mosaicMode_);
-    mosaic.transform(
-        tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
-    this.slideMode_.leave(tileRect,
-        function() {
-          // Animate back to normal position.
-          mosaic.transform();
-          mosaic.show();
-          onModeChanged();
-        }.bind(this));
-  } else {
-    this.setCurrentMode_(this.slideMode_);
-    this.slideMode_.enter(tileRect,
-        function() {
-          // Animate to zoomed position.
-          mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
-          mosaic.hide();
-        }.bind(this),
-        onModeChanged);
-  }
-};
-
-/**
- * Deletes the selected items.
- * @private
- */
-Gallery.prototype.delete_ = function() {
-  this.onUserAction_();
-
-  // Clone the sorted selected indexes array.
-  var indexesToRemove = this.selectionModel_.selectedIndexes.slice();
-  if (!indexesToRemove.length)
-    return;
-
-  /* TODO(dgozman): Implement Undo delete, Remove the confirmation dialog. */
-
-  var itemsToRemove = this.getSelectedItems();
-  var plural = itemsToRemove.length > 1;
-  var param = plural ? itemsToRemove.length : itemsToRemove[0].getFileName();
-
-  function deleteNext() {
-    if (!itemsToRemove.length)
-      return;  // All deleted.
-
-    var url = itemsToRemove.pop().getUrl();
-    webkitResolveLocalFileSystemURL(url,
-        function(entry) {
-          entry.remove(deleteNext,
-              util.flog('Error deleting ' + url, deleteNext));
-        },
-        util.flog('Error resolving ' + url, deleteNext));
-  }
-
-  // Prevent the Gallery from handling Esc and Enter.
-  this.document_.body.removeEventListener('keydown', this.keyDownBound_);
-  var restoreListener = function() {
-    this.document_.body.addEventListener('keydown', this.keyDownBound_);
-  }.bind(this);
-
-  cr.ui.dialogs.BaseDialog.OK_LABEL = this.displayStringFunction_(
-      'GALLERY_OK_LABEL');
-  cr.ui.dialogs.BaseDialog.CANCEL_LABEL =
-      this.displayStringFunction_('GALLERY_CANCEL_LABEL');
-  var confirm = new cr.ui.dialogs.ConfirmDialog(this.container_);
-  confirm.show(
-      this.displayStringFunction_(plural ? 'GALLERY_CONFIRM_DELETE_SOME' :
-          'GALLERY_CONFIRM_DELETE_ONE', param),
-      function() {
-        restoreListener();
-        this.selectionModel_.unselectAll();
-        this.selectionModel_.leadIndex = -1;
-        // Remove items from the data model, starting from the highest index.
-        while (indexesToRemove.length)
-          this.dataModel_.splice(indexesToRemove.pop(), 1);
-        // Delete actual files.
-        deleteNext();
-      }.bind(this),
-      function() {
-        // Restore the listener after a timeout so that ESC is processed.
-        setTimeout(restoreListener, 0);
-      });
-};
-
-/**
- * @return {Array.<Gallery.Item>} Current selection.
- */
-Gallery.prototype.getSelectedItems = function() {
-  return this.selectionModel_.selectedIndexes.map(
-      this.dataModel_.item.bind(this.dataModel_));
-};
-
-/**
- * @return {Array.<string>} Array of currently selected urls.
- */
-Gallery.prototype.getSelectedUrls = function() {
-  return this.selectionModel_.selectedIndexes.map(function(index) {
-    return this.dataModel_.item(index).getUrl();
-  }.bind(this));
-};
-
-/**
- * @return {Gallery.Item} Current single selection.
- */
-Gallery.prototype.getSingleSelectedItem = function() {
-  var items = this.getSelectedItems();
-  if (items.length > 1)
-    throw new Error('Unexpected multiple selection');
-  return items[0];
-};
-
-/**
-  * Selection change event handler.
-  * @private
-  */
-Gallery.prototype.onSelection_ = function() {
-  this.updateSelectionAndState_();
-  this.updateShareMenu_();
-};
-
-/**
-  * Data model splice event handler.
-  * @private
-  */
-Gallery.prototype.onSplice_ = function() {
-  this.selectionModel_.adjustLength(this.dataModel_.length);
-};
-
-/**
- * Content change event handler.
- * @param {Event} event Event.
- * @private
-*/
-Gallery.prototype.onContentChange_ = function(event) {
-  var index = this.dataModel_.indexOf(event.item);
-  if (index != this.selectionModel_.selectedIndex)
-    console.error('Content changed for unselected item');
-  this.updateSelectionAndState_();
-};
-
-/**
- * Keydown handler.
- *
- * @param {Event} event Event.
- * @private
- */
-Gallery.prototype.onKeyDown_ = function(event) {
-  var wasSharing = this.isSharing_();
-  this.closeShareMenu_();
-
-  if (this.currentMode_.onKeyDown(event))
-    return;
-
-  switch (util.getKeyModifiers(event) + event.keyIdentifier) {
-    case 'U+0008': // Backspace.
-      // The default handler would call history.back and close the Gallery.
-      event.preventDefault();
-      break;
-
-    case 'U+001B':  // Escape
-      // Swallow Esc if it closed the Share menu, otherwise close the Gallery.
-      if (!wasSharing)
-        this.onBack_();
-      break;
-
-    case 'U+004D':  // 'm' switches between Slide and Mosaic mode.
-      this.toggleMode_(null, event);
-      break;
-
-    case 'U+0056':  // 'v'
-      this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event);
-      break;
-
-    case 'U+007F':  // Delete
-    case 'Shift-U+0033':  // Shift+'3' (Delete key might be missing).
-      this.delete_();
-      break;
-  }
-};
-
-// Name box and rename support.
-
-/**
- * Update the UI related to the selected item and the persistent state.
- *
- * @private
- */
-Gallery.prototype.updateSelectionAndState_ = function() {
-  var path;
-  var displayName = '';
-
-  var selectedItems = this.getSelectedItems();
-  if (selectedItems.length == 1) {
-    var item = selectedItems[0];
-    path = util.extractFilePath(item.getUrl());
-    var fullName = item.getFileName();
-    window.top.document.title = fullName;
-    displayName = ImageUtil.getFileNameFromFullName(fullName);
-  } else if (selectedItems.length > 1 && this.context_.curDirEntry) {
-    // If the Gallery was opened on search results the search query will not be
-    // recorded in the app state and the relaunch will just open the gallery
-    // in the curDirEntry directory.
-    path = this.context_.curDirEntry.fullPath;
-    window.top.document.title = this.context_.curDirEntry.name;
-    displayName =
-        this.displayStringFunction_('GALLERY_ITEMS_SELECTED',
-                                    selectedItems.length);
-  }
-
-  window.top.util.updateAppState(path,
-      {gallery: (this.currentMode_ == this.mosaicMode_ ? 'mosaic' : 'slide')});
-
-  // We can't rename files in readonly directory.
-  // We can only rename a single file.
-  this.filenameEdit_.disabled = selectedItems.length != 1 ||
-                                this.context_.readonlyDirName;
-
-  this.filenameEdit_.value = displayName;
-
-  // Resolve real filesystem path of the current file.
-  if (this.selectionModel_.selectedIndexes.length) {
-    var selectedIndex = this.selectionModel_.selectedIndex;
-    var selectedItem =
-        this.dataModel_.item(this.selectionModel_.selectedIndex);
-
-    this.selectedItemFilesystemPath_ = null;
-    webkitResolveLocalFileSystemURL(selectedItem.getUrl(),
-      function(entry) {
-        if (this.selectionModel_.selectedIndex != selectedIndex)
-          return;
-        this.selectedItemFilesystemPath_ = entry.fullPath;
-      }.bind(this));
-  }
-};
-
-/**
- * Click event handler on filename edit box
- * @private
- */
-Gallery.prototype.onFilenameFocus_ = function() {
-  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true);
-  this.filenameEdit_.originalValue = this.filenameEdit_.value;
-  setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0);
-  this.onUserAction_();
-};
-
-/**
- * Blur event handler on filename edit box.
- *
- * @param {Event} event Blur event.
- * @return {boolean} if default action should be prevented.
- * @private
- */
-Gallery.prototype.onFilenameEditBlur_ = function(event) {
-  if (this.filenameEdit_.value && this.filenameEdit_.value[0] == '.') {
-    this.prompt_.show('file_hidden_name', 5000);
-    this.filenameEdit_.focus();
-    event.stopPropagation();
-    event.preventDefault();
-    return false;
-  }
-
-  var item = this.getSingleSelectedItem();
-  var oldUrl = item.getUrl();
-
-  var onFileExists = function() {
-    this.prompt_.show('file_exists', 3000);
-    this.filenameEdit_.value = name;
-    this.filenameEdit_.focus();
-  }.bind(this);
-
-  var onSuccess = function() {
-    var e = new Event('content');
-    e.item = item;
-    e.oldUrl = oldUrl;
-    e.metadata = null;  // Metadata unchanged.
-    this.dataModel_.dispatchEvent(e);
-  }.bind(this);
-
-  if (this.filenameEdit_.value) {
-    this.getSingleSelectedItem().rename(
-        this.filenameEdit_.value, onSuccess, onFileExists);
-  }
-
-  ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false);
-  this.onUserAction_();
-};
-
-/**
- * Keydown event handler on filename edit box
- * @private
- */
-Gallery.prototype.onFilenameEditKeydown_ = function() {
-  switch (event.keyCode) {
-    case 27:  // Escape
-      this.filenameEdit_.value = this.filenameEdit_.originalValue;
-      this.filenameEdit_.blur();
-      break;
-
-    case 13:  // Enter
-      this.filenameEdit_.blur();
-      break;
-  }
-  event.stopPropagation();
-};
-
-/**
- * @return {boolean} True if file renaming is currently in progress.
- * @private
- */
-Gallery.prototype.isRenaming_ = function() {
-  return this.filenameSpacer_.hasAttribute('renaming');
-};
-
-/**
- * Content area click handler.
- * @private
- */
-Gallery.prototype.onContentClick_ = function() {
-  this.closeShareMenu_();
-  this.filenameEdit_.blur();
-};
-
-// Share button support.
-
-/**
- * @return {boolean} True if the Share menu is active.
- * @private
- */
-Gallery.prototype.isSharing_ = function() {
-  return !this.shareMenu_.hidden;
-};
-
-/**
- * Close Share menu if it is open.
- * @private
- */
-Gallery.prototype.closeShareMenu_ = function() {
-  if (this.isSharing_())
-    this.toggleShare_();
-};
-
-/**
- * Share button handler.
- * @private
- */
-Gallery.prototype.toggleShare_ = function() {
-  if (!this.shareButton_.hasAttribute('disabled'))
-    this.shareMenu_.hidden = !this.shareMenu_.hidden;
-  this.inactivityWatcher_.check();
-};
-
-/**
- * Updates available actions list based on the currently selected urls.
- * @private.
- */
-Gallery.prototype.updateShareMenu_ = function() {
-  var urls = this.getSelectedUrls();
-
-  function isShareAction(task) {
-    var taskParts = task.taskId.split('|');
-    return taskParts[0] != chrome.runtime.id;
-  }
-
-  var api = Gallery.getFileBrowserPrivate();
-  var mimeTypes = [];  // TODO(kaznacheev) Collect mime types properly.
-
-  var createShareMenu = function(tasks) {
-    var wasHidden = this.shareMenu_.hidden;
-    this.shareMenu_.hidden = true;
-    var items = this.shareMenu_.querySelectorAll('.item');
-    for (var i = 0; i != items.length; i++) {
-      items[i].parentNode.removeChild(items[i]);
-    }
-
-    for (var t = 0; t != tasks.length; t++) {
-      var task = tasks[t];
-      if (!isShareAction(task)) continue;
-
-      var item = util.createChild(this.shareMenu_, 'item');
-      item.textContent = task.title;
-      item.style.backgroundImage = 'url(' + task.iconUrl + ')';
-      item.addEventListener('click', function(taskId) {
-        this.toggleShare_();  // Hide the menu.
-        this.executeWhenReady(api.executeTask.bind(api, taskId, urls));
-      }.bind(this, task.taskId));
-    }
-
-    var empty = this.shareMenu_.querySelector('.item') == null;
-    ImageUtil.setAttribute(this.shareButton_, 'disabled', empty);
-    this.shareMenu_.hidden = wasHidden || empty;
-  }.bind(this);
-
-  // Create or update the share menu with a list of sharing tasks and show
-  // or hide the share button.
-  if (!urls.length)
-    createShareMenu([]);  // Empty list of tasks, since there is no selection.
-  else
-    api.getFileTasks(urls, mimeTypes, createShareMenu);
-};
-
-/**
- * Updates thumbnails.
- * @private
- */
-Gallery.prototype.updateThumbnails_ = function() {
-  if (this.currentMode_ == this.slideMode_)
-    this.slideMode_.updateThumbnails();
-
-  if (this.mosaicMode_) {
-    var mosaic = this.mosaicMode_.getMosaic();
-    if (mosaic.isInitialized())
-      mosaic.reload();
-  }
-};
-
-/**
- * Updates buttons.
- * @private
- */
-Gallery.prototype.updateButtons_ = function() {
-  if (this.modeButton_) {
-    var oppositeMode =
-        this.currentMode_ == this.slideMode_ ? this.mosaicMode_ :
-                                               this.slideMode_;
-    this.modeButton_.title =
-        this.displayStringFunction_(oppositeMode.getTitle());
-  }
-};
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js b/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
deleted file mode 100644
index 5c01498..0000000
--- a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-//<include src="../metrics.js">
-
-//<include src="../../../image_loader/image_loader_client.js"/>
-
-//<include src="../../../../../../ui/webui/resources/js/cr.js">
-//<include src="../../../../../../ui/webui/resources/js/event_tracker.js">
-//<include src="../../../../../../ui/webui/resources/js/load_time_data.js">
-
-//<include src="../../../../../../ui/webui/resources/js/cr/ui.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/dialogs.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_item.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list.js">
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/grid.js">
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-//<include src="../file_type.js">
-//<include src="../async_util.js">
-//<include src="../util.js">
-//<include src="../path_util.js">
-//<include src="../volume_manager_wrapper.js">
-
-//<include src="../image_editor/image_util.js"/>
-//<include src="../image_editor/viewport.js"/>
-//<include src="../image_editor/image_buffer.js"/>
-//<include src="../image_editor/image_view.js"/>
-//<include src="../image_editor/commands.js"/>
-//<include src="../image_editor/image_editor.js"/>
-//<include src="../image_editor/image_transform.js"/>
-//<include src="../image_editor/image_adjust.js"/>
-//<include src="../image_editor/filter.js"/>
-//<include src="../image_editor/image_encoder.js"/>
-//<include src="../image_editor/exif_encoder.js"/>
-
-//<include src="../media/media_controls.js"/>
-//<include src="../media/media_util.js"/>
-//<include src="../media/util.js"/>
-
-//<include src="../metadata/metadata_cache.js"/>
-
-//<include src="gallery.js">
-//<include src="gallery_item.js">
-//<include src="mosaic_mode.js">
-//<include src="slide_mode.js">
-//<include src="ribbon.js">
-
-// Exports
-window.ImageUtil = ImageUtil;
-window.Gallery = Gallery;
-window.beforeunload = beforeunload;
-window.unload = unload;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/photo/importing_dialog.js b/chrome/browser/resources/file_manager/js/photo/importing_dialog.js
deleted file mode 100644
index e81b23f..0000000
--- a/chrome/browser/resources/file_manager/js/photo/importing_dialog.js
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * ImportingDialog manages the import process (which is really a copying).
- * @param {HTMLElement} parentNode Node to be parent for this dialog.
- * @param {FileOperationManager} fileOperationManager File operation manager
- *     instance.
- * @param {MetadataCache} metadataCache Metadata cache.
- * @param {number=} opt_parentWindowId Id of the parent window.
- * @constructor
- */
-function ImportingDialog(
-    parentNode, fileOperationManager, metadataCache, opt_parentWindowId) {
-  cr.ui.dialogs.BaseDialog.call(this, parentNode);
-  this.parentWindowId_ = opt_parentWindowId;
-  this.fileOperationManager_ = fileOperationManager;
-  this.metadataCache_ = metadataCache;
-  this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
-}
-
-ImportingDialog.prototype = {
-  __proto__: cr.ui.dialogs.BaseDialog.prototype
-};
-
-/**
- * One-time initialization of DOM.
- * @private
- */
-ImportingDialog.prototype.initDom_ = function() {
-  cr.ui.dialogs.BaseDialog.prototype.initDom_.call(this);
-
-  this.container_.classList.add('importing-dialog');
-
-  this.content_ = util.createChild(this.frame_, 'content');
-  this.frame_.insertBefore(this.content_, this.frame_.firstChild);
-  this.content_.appendChild(this.text_);
-
-  this.imageBox_ = util.createChild(this.frame_, 'img-container');
-  this.imageBox_.setAttribute('state', 'progress');
-  this.frame_.insertBefore(this.imageBox_, this.frame_.firstChild);
-
-  var progressContainer = util.createChild(this.content_, 'progress-container');
-  this.progress_ = util.createChild(progressContainer, 'progress-bar');
-  util.createChild(this.progress_, 'progress-track smoothed');
-
-  this.buttons_ = this.frame_.querySelector('.cr-dialog-buttons');
-  this.content_.appendChild(this.buttons_);
-
-  this.viewButton_ = util.createChild(
-      this.buttons_, 'cr-dialog-view', 'button');
-  this.viewButton_.addEventListener('click',
-                                    this.onViewClick_.bind(this));
-  this.buttons_.insertBefore(this.viewButton_, this.buttons_.firstChild);
-
-  this.viewButton_.textContent =
-      loadTimeData.getString('VIEW_LABEL');
-  this.viewButton_.hidden = true;
-  this.cancelButton_.textContent =
-      loadTimeData.getString('PHOTO_IMPORT_CANCEL_BUTTON');
-  this.okButton_.textContent =
-      loadTimeData.getString('OK_LABEL');
-  this.okButton_.hidden = true;
-};
-
-/**
- * Shows dialog.
- * @param {Array.<FileEntry>} entries Entries to import.
- * @param {boolean} move Whether to move files instead of copying them.
- */
-ImportingDialog.prototype.show = function(entries, move) {
-  var message = loadTimeData.getString('PHOTO_IMPORT_IMPORTING');
-  cr.ui.dialogs.BaseDialog.prototype.show.call(this, message, null, null, null);
-
-  this.error_ = false;
-  this.entries_ = entries;
-  this.move_ = move;
-
-  this.progress_.querySelector('.progress-track').style.width = '0';
-  this.fileOperationManager_.addEventListener('copy-progress',
-      this.onCopyProgressBound_);
-
-  this.previewEntry_(0);
-};
-
-/**
- * Starts copying.
- * @param {DirectoryEntry} destination Directory to import to.
- */
-ImportingDialog.prototype.start = function(destination) {
-  this.destination_ = destination;
-  this.fileOperationManager_.paste(
-      this.entries_.map(function(e) { return e.fullPath }),
-      this.destination_.fullPath,
-      this.move_);
-};
-
-/**
- * Shows entry preview.
- * @param {number} index Entry index.
- * @private
- */
-ImportingDialog.prototype.previewEntry_ = function(index) {
-  var box = this.imageBox_;
-  var entry = this.entries_[index];
-  this.metadataCache_.get(entry, 'thumbnail|filesystem',
-      function(metadata) {
-        new ThumbnailLoader(entry.toURL(),
-                            ThumbnailLoader.LoaderType.IMAGE,
-                            metadata).
-            load(box, ThumbnailLoader.FillMode.FILL);
-      });
-};
-
-/**
- * Closes dialog.
- * @param {function()=} opt_onHide Completion callback.
- */
-ImportingDialog.prototype.hide = function(opt_onHide) {
-  this.fileOperationManager_.removeEventListener('copy-progress',
-      this.onCopyProgressBound_);
-  cr.ui.dialogs.BaseDialog.prototype.hide.call(this, opt_onHide);
-};
-
-/**
- * Cancel button click event handler.
- * @private
- */
-ImportingDialog.prototype.onCancelClick_ = function() {
-  this.fileOperationManager_.requestCancel();
-  this.hide();
-};
-
-/**
- * OK button click event handler.
- * @private
- */
-ImportingDialog.prototype.onOkClick_ = function() {
-  this.hide();
-  if (!this.error_)
-    window.close();
-};
-
-/**
- * View button click event handler. Invokes the mosaic view.
- * @private
- */
-ImportingDialog.prototype.onViewClick_ = function() {
-  var url = chrome.runtime.getURL('main.html') +
-      '?{%22gallery%22:%22mosaic%22}#' + this.destination_.fullPath;
-  if (!this.parentWindowId_ ||
-      !util.redirectMainWindow(this.parentWindowId_, url)) {
-    // The parent window hasn't been found. Launch the url as a new window.
-    // TODO(mtomasz): Change it to chrome.fileBrowserPrivate.openNewWindow.
-    chrome.app.window.create(url);
-  }
-  this.hide();
-  window.close();
-};
-
-/**
- * Event handler for keydown event.
- * @param {Event} event The event.
- * @private
- */
-ImportingDialog.prototype.onContainerKeyDown_ = function(event) {
-  // Handle Escape.
-  if (event.keyCode == 27) {
-    this.onCancelClick_(event);
-    event.preventDefault();
-  }
-};
-
-/**
- * 'copy-progress' event handler. Show progress.
- * @param {Event} event A 'copy-progress' event from FileOperationManager.
- * @private
- */
-ImportingDialog.prototype.onCopyProgress_ = function(event) {
-  switch (event.reason) {
-    case 'BEGIN':
-    case 'PROGRESS':
-      var progress = this.fileOperationManager_.getStatus().percentage;
-      this.progress_.querySelector('.progress-track').style.width =
-          (progress * 100) + '%';
-      var index = Math.round(this.entries_.length * progress);
-      if (index == this.entries_.length) index--;
-      this.previewEntry_(index);
-      break;
-
-    case 'SUCCESS':
-      this.text_.textContent =
-          loadTimeData.getString('PHOTO_IMPORT_IMPORT_COMPLETE');
-      this.imageBox_.setAttribute('state', 'success');
-      this.cancelButton_.hidden = true;
-      this.viewButton_.hidden = false;
-      this.okButton_.hidden = false;
-      break;
-
-    case 'CANCELLED':
-      this.hide();
-      break;
-
-    case 'ERROR':
-      this.error_ = true;
-      this.text_.textContent =
-          loadTimeData.getString('PHOTO_IMPORT_IMPORTING_ERROR');
-      this.imageBox_.setAttribute('state', 'error');
-      this.cancelButton_.hidden = true;
-      this.viewButton_.hidden = true;
-      this.okButton_.hidden = false;
-      break;
-
-    default:
-      console.error('Unknown "copy-progress" event reason: ' + event.reason);
-  }
-};
diff --git a/chrome/browser/resources/file_manager/js/photo/photo_import.js b/chrome/browser/resources/file_manager/js/photo/photo_import.js
deleted file mode 100644
index 346e13c..0000000
--- a/chrome/browser/resources/file_manager/js/photo/photo_import.js
+++ /dev/null
@@ -1,582 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-document.addEventListener('DOMContentLoaded', function() {
-  PhotoImport.load();
-});
-
-/**
- * The main Photo App object.
- * @param {HTMLElement} dom Container.
- * @param {VolumeManagerWrapper} volumeManager The initialized
- *     VolumeManagerWrapper instance.
- * @param {Object} params Parameters.
- * @constructor
- */
-function PhotoImport(dom, volumeManager, params) {
-  this.dom_ = dom;
-  this.document_ = this.dom_.ownerDocument;
-  this.metadataCache_ = params.metadataCache;
-  this.volumeManager_ = volumeManager;
-  this.fileOperationManager_ = FileOperationManagerWrapper.getInstance();
-  this.mediaFilesList_ = null;
-  this.destination_ = null;
-  this.myPhotosDirectory_ = null;
-  this.parentWindowId_ = params.parentWindowId;
-
-  this.initDom_();
-  this.initMyPhotos_();
-  this.loadSource_(params.source);
-}
-
-PhotoImport.prototype = { __proto__: cr.EventTarget.prototype };
-
-/**
- * Single item width.
- * Keep in sync with .grid-item rule in photo_import.css.
- */
-PhotoImport.ITEM_WIDTH = 164 + 8;
-
-/**
- * Number of tries in creating a destination directory.
- */
-PhotoImport.CREATE_DESTINATION_TRIES = 100;
-
-/**
- * Loads app in the document body.
- * @param {Object=} opt_params Parameters.
- */
-PhotoImport.load = function(opt_params) {
-  ImageUtil.metrics = metrics;
-
-  var hash = location.hash ? location.hash.substr(1) : '';
-  var query = location.search ? location.search.substr(1) : '';
-  var params = opt_params || {};
-  if (!params.source) params.source = hash;
-  if (!params.parentWindowId && query) params.parentWindowId = query;
-  if (!params.metadataCache) params.metadataCache = MetadataCache.createFull();
-
-  var api = chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate;
-  api.getStrings(function(strings) {
-    loadTimeData.data = strings;
-    var dom = document.querySelector('.photo-import');
-
-    var volumeManager = new VolumeManagerWrapper(
-        VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED);
-    volumeManager.ensureInitialized(function() {
-      new PhotoImport(dom, volumeManager, params);
-    });
-  });
-};
-
-/**
- * One-time initialization of dom elements.
- * @private
- */
-PhotoImport.prototype.initDom_ = function() {
-  this.dom_.setAttribute('loading', '');
-  this.dom_.ownerDocument.defaultView.addEventListener(
-      'resize', this.onResize_.bind(this));
-
-  this.spinner_ = this.dom_.querySelector('.spinner');
-
-  this.document_.querySelector('title').textContent =
-      loadTimeData.getString('PHOTO_IMPORT_TITLE');
-  this.dom_.querySelector('.caption').textContent =
-      loadTimeData.getString('PHOTO_IMPORT_CAPTION');
-  this.selectAllNone_ = this.dom_.querySelector('.select');
-  this.selectAllNone_.addEventListener('click',
-      this.onSelectAllNone_.bind(this));
-
-  this.dom_.querySelector('label[for=delete-after-checkbox]').textContent =
-      loadTimeData.getString('PHOTO_IMPORT_DELETE_AFTER');
-  this.selectedCount_ = this.dom_.querySelector('.selected-count');
-
-  this.importButton_ = this.dom_.querySelector('button.import');
-  this.importButton_.textContent =
-      loadTimeData.getString('PHOTO_IMPORT_IMPORT_BUTTON');
-  this.importButton_.addEventListener('click', this.onImportClick_.bind(this));
-
-  this.cancelButton_ = this.dom_.querySelector('button.cancel');
-  this.cancelButton_.textContent = str('CANCEL_LABEL');
-  this.cancelButton_.addEventListener('click', this.onCancelClick_.bind(this));
-
-  this.grid_ = this.dom_.querySelector('grid');
-  cr.ui.Grid.decorate(this.grid_);
-  this.grid_.itemConstructor = GridItem.bind(null, this);
-  this.fileList_ = new cr.ui.ArrayDataModel([]);
-  this.grid_.selectionModel = new cr.ui.ListSelectionModel();
-  this.grid_.dataModel = this.fileList_;
-  this.grid_.selectionModel.addEventListener('change',
-      this.onSelectionChanged_.bind(this));
-  this.onSelectionChanged_();
-
-  this.importingDialog_ = new ImportingDialog(
-      this.dom_, this.fileOperationManager_,
-      this.metadataCache_, this.parentWindowId_);
-
-  var dialogs = cr.ui.dialogs;
-  dialogs.BaseDialog.OK_LABEL = str('OK_LABEL');
-  dialogs.BaseDialog.CANCEL_LABEL = str('CANCEL_LABEL');
-  this.alert_ = new dialogs.AlertDialog(this.dom_);
-};
-
-/**
- * One-time initialization of the My Photos directory.
- * @private
- */
-PhotoImport.prototype.initMyPhotos_ = function() {
-  var driveVolume = this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
-  if (!driveVolume || driveVolume.error || !driveVolume.root) {
-    this.onError_(loadTimeData.getString('PHOTO_IMPORT_DRIVE_ERROR'));
-    return;
-  }
-
-  util.getOrCreateDirectory(
-      driveVolume.root,
-      loadTimeData.getString('PHOTO_IMPORT_MY_PHOTOS_DIRECTORY_NAME'),
-      function(entry) {
-        // This may enable the import button, so check that.
-        this.myPhotosDirectory_ = entry;
-        this.onSelectionChanged_();
-      },
-      function(error) {
-        this.onError_(loadTimeData.getString('PHOTO_IMPORT_DRIVE_ERROR'));
-      }.bind(this));
-};
-
-/**
- * Creates the destination directory.
- * @param {function} onSuccess Callback on success.
- * @private
- */
-PhotoImport.prototype.createDestination_ = function(onSuccess) {
-  var onError = this.onError_.bind(
-      this, loadTimeData.getString('PHOTO_IMPORT_DESTINATION_ERROR'));
-
-  var dateFormatter = Intl.DateTimeFormat(
-      [] /* default locale */,
-      {year: 'numeric', month: 'short', day: 'numeric'});
-
-  var baseName = PathUtil.join(
-      RootDirectory.DRIVE,
-      loadTimeData.getString('PHOTO_IMPORT_MY_PHOTOS_DIRECTORY_NAME'),
-      dateFormatter.format(new Date()));
-
-  var driveVolume = this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE);
-  if (!driveVolume || driveVolume.error || !driveVolume.root) {
-    onError();
-    return;
-  }
-
-  var tryNext = function(number) {
-    if (number > PhotoImport.CREATE_DESTINATION_TRIES) {
-      console.error('Too many directories with the same base name exist.');
-      onError();
-      return;
-    }
-
-    var directoryName = baseName;
-    if (number > 1)
-      directoryName += ' (' + (tryNumber) + ')';
-    driveVolume.root.getDirectory(
-        directoryName,
-        {create: true, exclusive: true},
-        function(entry) {
-          this.destination_ = entry;
-          onSuccess();
-        }.bind(this),
-        function(error) {
-          if (error.code === FileError.PATH_EXISTS_ERR) {
-            // If there already exists an entry, retry with incrementing the
-            // number.
-            tryNext(number + 1);
-            return;
-          }
-          onError();
-        }.bind(this));
-  }.bind(this);
-
-  tryNext(1);
-};
-
-
-/**
- * Load the source contents.
- * @param {string} source Path to source.
- * @private
- */
-PhotoImport.prototype.loadSource_ = function(source) {
-  var onError = this.onError_.bind(
-      this, loadTimeData.getString('PHOTO_IMPORT_SOURCE_ERROR'));
-
-  var result = [];
-  this.volumeManager_.resolvePath(
-      source,
-      function(sourceEntry) {
-        util.traverseTree(
-            entry,
-            function(entry) {
-              if (!FileType.isVisible(entry))
-                return false;
-              if (FileType.isImageOrVideo(entry))
-                result.push(entry);
-              return true;
-            },
-            function() {
-              this.dom_.removeAttribute('loading');
-              this.mediaFilesList_ = result;
-              this.fillGrid_();
-            }.bind(this),
-            onError);
-      }.bind(this),
-      onError);
-};
-
-/**
- * Renders files into grid.
- * @private
- */
-PhotoImport.prototype.fillGrid_ = function() {
-  if (!this.mediaFilesList_) return;
-  this.fileList_.splice(0, this.fileList_.length);
-  this.fileList_.push.apply(this.fileList_, this.mediaFilesList_);
-};
-
-/**
- * Creates groups for files based on modification date.
- * @param {Array.<Entry>} files File list.
- * @param {Object} filesystem Filesystem metadata.
- * @return {Array.<Object>} List of grouped items.
- * @private
- */
-PhotoImport.prototype.createGroups_ = function(files, filesystem) {
-  var dateFormatter = Intl.DateTimeFormat(
-      [] /* default locale */,
-      {year: 'numeric', month: 'short', day: 'numeric'});
-
-  var columns = this.grid_.columns;
-
-  var unknownGroup = {
-    type: 'group',
-    date: 0,
-    title: loadTimeData.getString('PHOTO_IMPORT_UNKNOWN_DATE'),
-    items: []
-  };
-
-  var groupsMap = {};
-
-  for (var index = 0; index < files.length; index++) {
-    var props = filesystem[index];
-    var item = { type: 'entry', entry: files[index] };
-
-    if (!props || !props.modificationTime) {
-      item.group = unknownGroup;
-      unknownGroup.items.push(item);
-      continue;
-    }
-
-    var date = new Date(props.modificationTime);
-    date.setHours(0);
-    date.setMinutes(0);
-    date.setSeconds(0);
-    date.setMilliseconds(0);
-
-    var time = date.getTime();
-    if (!(time in groupsMap)) {
-      groupsMap[time] = {
-        type: 'group',
-        date: date,
-        title: dateFormatter.format(date),
-        items: []
-      };
-    }
-
-    var group = groupsMap[time];
-    group.items.push(item);
-    item.group = group;
-  }
-
-  var groups = [];
-  for (var time in groupsMap) {
-    if (groupsMap.hasOwnProperty(time)) {
-      groups.push(groupsMap[time]);
-    }
-  }
-  if (unknownGroup.items.length > 0)
-    groups.push(unknownGroup);
-
-  groups.sort(function(a, b) {
-    return b.date.getTime() - a.date.getTime();
-  });
-
-  var list = [];
-  for (var index = 0; index < groups.length; index++) {
-    var group = groups[index];
-
-    list.push(group);
-    for (var t = 1; t < columns; t++) {
-      list.push({ type: 'empty' });
-    }
-
-    for (var j = 0; j < group.items.length; j++) {
-      list.push(group.items[j]);
-    }
-
-    var count = group.items.length;
-    while (count % columns != 0) {
-      list.push({ type: 'empty' });
-      count++;
-    }
-  }
-
-  return list;
-};
-
-/**
- * Decorates grid item.
- * @param {HTMLLIElement} li The list item.
- * @param {FileEntry} entry The file entry.
- * @private
- */
-PhotoImport.prototype.decorateGridItem_ = function(li, entry) {
-  li.className = 'grid-item';
-  li.entry = entry;
-
-  var frame = this.document_.createElement('div');
-  frame.className = 'grid-frame';
-  li.appendChild(frame);
-
-  var box = this.document_.createElement('div');
-  box.className = 'img-container';
-  this.metadataCache_.get(entry, 'thumbnail|filesystem',
-      function(metadata) {
-        new ThumbnailLoader(entry.toURL(),
-                            ThumbnailLoader.LoaderType.IMAGE,
-                            metadata).
-            load(box, ThumbnailLoader.FillMode.FIT,
-            ThumbnailLoader.OptimizationMode.DISCARD_DETACHED);
-      });
-  frame.appendChild(box);
-
-  var check = this.document_.createElement('div');
-  check.className = 'check';
-  li.appendChild(check);
-};
-
-/**
- * Handles the 'pick all/none' action.
- * @private
- */
-PhotoImport.prototype.onSelectAllNone_ = function() {
-  var sm = this.grid_.selectionModel;
-  if (sm.selectedIndexes.length == this.fileList_.length) {
-    sm.unselectAll();
-  } else {
-    sm.selectAll();
-  }
-};
-
-/**
- * Show error message.
- * @param {string} message Error message.
- * @private
- */
-PhotoImport.prototype.onError_ = function(message) {
-  this.importingDialog_.hide(function() {
-    this.alert_.show(message,
-                     function() {
-                       window.close();
-                     });
-  }.bind(this));
-};
-
-/**
- * Resize event handler.
- * @private
- */
-PhotoImport.prototype.onResize_ = function() {
-  var g = this.grid_;
-  g.startBatchUpdates();
-  setTimeout(function() {
-    g.columns = 0;
-    g.redraw();
-    g.endBatchUpdates();
-  }, 0);
-};
-
-/**
- * @return {Array.<Object>} The list of selected entries.
- * @private
- */
-PhotoImport.prototype.getSelectedItems_ = function() {
-  var indexes = this.grid_.selectionModel.selectedIndexes;
-  var list = [];
-  for (var i = 0; i < indexes.length; i++) {
-    list.push(this.fileList_.item(indexes[i]));
-  }
-  return list;
-};
-
-/**
- * Event handler for picked items change.
- * @private
- */
-PhotoImport.prototype.onSelectionChanged_ = function() {
-  var count = this.grid_.selectionModel.selectedIndexes.length;
-  this.selectedCount_.textContent = count == 0 ? '' :
-      count == 1 ? loadTimeData.getString('PHOTO_IMPORT_ONE_SELECTED') :
-                   loadTimeData.getStringF('PHOTO_IMPORT_MANY_SELECTED', count);
-  this.importButton_.disabled = count == 0 || this.myPhotosDirectory_ == null;
-  this.selectAllNone_.textContent = loadTimeData.getString(
-      count == this.fileList_.length && count > 0 ?
-          'PHOTO_IMPORT_SELECT_NONE' : 'PHOTO_IMPORT_SELECT_ALL');
-};
-
-/**
- * Event handler for import button click.
- * @param {Event} event The event.
- * @private
- */
-PhotoImport.prototype.onImportClick_ = function(event) {
-  var entries = this.getSelectedItems_();
-  var move = this.dom_.querySelector('#delete-after-checkbox').checked;
-  this.importingDialog_.show(entries, move);
-
-  this.createDestination_(function() {
-    var percentage = Math.round(entries.length / this.fileList_.length * 100);
-    metrics.recordMediumCount('PhotoImport.ImportCount', entries.length);
-    metrics.recordSmallCount('PhotoImport.ImportPercentage', percentage);
-
-    this.importingDialog_.start(this.destination_);
-  }.bind(this));
-};
-
-/**
- * Click event handler for the cancel button.
- * @param {Event} event The event.
- * @private
- */
-PhotoImport.prototype.onCancelClick_ = function(event) {
-  window.close();
-};
-
-/**
- * Item in the grid.
- * @param {PhotoImport} app Application instance.
- * @param {Entry} entry File entry.
- * @constructor
- */
-function GridItem(app, entry) {
-  var li = app.document_.createElement('li');
-  li.__proto__ = GridItem.prototype;
-  app.decorateGridItem_(li, entry);
-  return li;
-}
-
-GridItem.prototype = {
-  __proto__: cr.ui.ListItem.prototype,
-  get label() {},
-  set label(value) {}
-};
-
-/**
- * Creates a selection controller that is to be used with grid.
- * @param {cr.ui.ListSelectionModel} selectionModel The selection model to
- *     interact with.
- * @param {cr.ui.Grid} grid The grid to interact with.
- * @constructor
- * @extends {!cr.ui.ListSelectionController}
- */
-function GridSelectionController(selectionModel, grid) {
-  this.selectionModel_ = selectionModel;
-  this.grid_ = grid;
-}
-
-/**
- * Extends cr.ui.ListSelectionController.
- */
-GridSelectionController.prototype.__proto__ =
-    cr.ui.ListSelectionController.prototype;
-
-/** @override */
-GridSelectionController.prototype.getIndexBelow = function(index) {
-  if (index == this.getLastIndex()) {
-    return -1;
-  }
-
-  var dm = this.grid_.dataModel;
-  var columns = this.grid_.columns;
-  var min = (Math.floor(index / columns) + 1) * columns;
-
-  for (var row = 1; true; row++) {
-    var end = index + columns * row;
-    var start = Math.max(min, index + columns * (row - 1));
-    if (start > dm.length) break;
-
-    for (var i = end; i > start; i--) {
-      if (i < dm.length && dm.item(i).type == 'entry')
-        return i;
-    }
-  }
-
-  return this.getLastIndex();
-};
-
-/** @override */
-GridSelectionController.prototype.getIndexAbove = function(index) {
-  if (index == this.getFirstIndex()) {
-    return -1;
-  }
-
-  var dm = this.grid_.dataModel;
-  index -= this.grid_.columns;
-  while (index >= 0 && dm.item(index).type != 'entry') {
-    index--;
-  }
-
-  return index < 0 ? this.getFirstIndex() : index;
-};
-
-/** @override */
-GridSelectionController.prototype.getIndexBefore = function(index) {
-  var dm = this.grid_.dataModel;
-  index--;
-  while (index >= 0 && dm.item(index).type != 'entry') {
-    index--;
-  }
-  return index;
-};
-
-/** @override */
-GridSelectionController.prototype.getIndexAfter = function(index) {
-  var dm = this.grid_.dataModel;
-  index++;
-  while (index < dm.length && dm.item(index).type != 'entry') {
-    index++;
-  }
-  return index == dm.length ? -1 : index;
-};
-
-/** @override */
-GridSelectionController.prototype.getFirstIndex = function() {
-  var dm = this.grid_.dataModel;
-  for (var index = 0; index < dm.length; index++) {
-    if (dm.item(index).type == 'entry')
-      return index;
-  }
-  return -1;
-};
-
-/** @override */
-GridSelectionController.prototype.getLastIndex = function() {
-  var dm = this.grid_.dataModel;
-  for (var index = dm.length - 1; index >= 0; index--) {
-    if (dm.item(index).type == 'entry')
-      return index;
-  }
-  return -1;
-};
diff --git a/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js b/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
deleted file mode 100644
index dd09c39..0000000
--- a/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The include directives are put into Javascript-style comments to prevent
-// parsing errors in non-flattened mode. The flattener still sees them.
-// Note that this makes the flattener to comment out the first line of the
-// included file but that's all right since any javascript file should start
-// with a copyright comment anyway.
-
-//<include src="../../../image_loader/image_loader_client.js"/>
-
-//<include src="../../../../../../ui/webui/resources/js/load_time_data.js"/>
-//<include src="../../../../../../ui/webui/resources/js/util.js"/>
-//<include src="../../../../../../ui/webui/resources/js/i18n_template_no_process.js"/>
-
-//<include src="../../../../../../ui/webui/resources/js/cr.js"/>
-//<include src="../../../../../../ui/webui/resources/js/event_tracker.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/dialogs.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_item.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/list.js"/>
-//<include src="../../../../../../ui/webui/resources/js/cr/ui/grid.js"/>
-
-(function() {
-// 'strict mode' is invoked for this scope.
-
-//<include src="../async_util.js"/>
-//<include src="../util.js"/>
-//<include src="../path_util.js"/>
-//<include src="../file_type.js"/>
-//<include src="../directory_contents.js"/>
-//<include src="../volume_manager_wrapper.js"/>
-//<include src="../file_operation_manager_wrapper.js"/>
-//<include src="../metadata/metadata_cache.js"/>
-//<include src="../metrics.js"/>
-//<include src="../image_editor/image_util.js"/>
-//<include src="../media/media_util.js"/>
-
-//<include src="importing_dialog.js"/>
-//<include src="tile_view.js"/>
-//<include src="photo_import.js"/>
-
-// Exports
-window.ImageUtil = ImageUtil;
-window.FileOperationManagerWrapper = FileOperationManagerWrapper;
-
-})();
diff --git a/chrome/browser/resources/file_manager/js/photo/slide_mode.js b/chrome/browser/resources/file_manager/js/photo/slide_mode.js
deleted file mode 100644
index fe07754..0000000
--- a/chrome/browser/resources/file_manager/js/photo/slide_mode.js
+++ /dev/null
@@ -1,1343 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Slide mode displays a single image and has a set of controls to navigate
- * between the images and to edit an image.
- *
- * TODO(kaznacheev): Introduce a parameter object.
- *
- * @param {Element} container Main container element.
- * @param {Element} content Content container element.
- * @param {Element} toolbar Toolbar element.
- * @param {ImageEditor.Prompt} prompt Prompt.
- * @param {cr.ui.ArrayDataModel} dataModel Data model.
- * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
- * @param {Object} context Context.
- * @param {function(function())} toggleMode Function to toggle the Gallery mode.
- * @param {function(string):string} displayStringFunction String formatting
- *     function.
- * @constructor
- */
-function SlideMode(container, content, toolbar, prompt,
-                   dataModel, selectionModel, context,
-                   toggleMode, displayStringFunction) {
-  this.container_ = container;
-  this.document_ = container.ownerDocument;
-  this.content = content;
-  this.toolbar_ = toolbar;
-  this.prompt_ = prompt;
-  this.dataModel_ = dataModel;
-  this.selectionModel_ = selectionModel;
-  this.context_ = context;
-  this.metadataCache_ = context.metadataCache;
-  this.toggleMode_ = toggleMode;
-  this.displayStringFunction_ = displayStringFunction;
-
-  this.onSelectionBound_ = this.onSelection_.bind(this);
-  this.onSpliceBound_ = this.onSplice_.bind(this);
-  this.onContentBound_ = this.onContentChange_.bind(this);
-
-  // Unique numeric key, incremented per each load attempt used to discard
-  // old attempts. This can happen especially when changing selection fast or
-  // Internet connection is slow.
-  this.currentUniqueKey_ = 0;
-
-  this.initListeners_();
-  this.initDom_();
-}
-
-/**
- * SlideMode extends cr.EventTarget.
- */
-SlideMode.prototype.__proto__ = cr.EventTarget.prototype;
-
-/**
- * List of available editor modes.
- * @type {Array.<ImageEditor.Mode>}
- */
-SlideMode.editorModes = [
-  new ImageEditor.Mode.InstantAutofix(),
-  new ImageEditor.Mode.Crop(),
-  new ImageEditor.Mode.Exposure(),
-  new ImageEditor.Mode.OneClick(
-      'rotate_left', 'GALLERY_ROTATE_LEFT', new Command.Rotate(-1)),
-  new ImageEditor.Mode.OneClick(
-      'rotate_right', 'GALLERY_ROTATE_RIGHT', new Command.Rotate(1))
-];
-
-/**
- * @return {string} Mode name.
- */
-SlideMode.prototype.getName = function() { return 'slide' };
-
-/**
- * @return {string} Mode title.
- */
-SlideMode.prototype.getTitle = function() { return 'GALLERY_SLIDE' };
-
-/**
- * Initialize the listeners.
- * @private
- */
-SlideMode.prototype.initListeners_ = function() {
-  window.addEventListener('resize', this.onResize_.bind(this), false);
-};
-
-/**
- * Initialize the UI.
- * @private
- */
-SlideMode.prototype.initDom_ = function() {
-  // Container for displayed image or video.
-  this.imageContainer_ = util.createChild(
-      this.document_.querySelector('.content'), 'image-container');
-  this.imageContainer_.addEventListener('click', this.onClick_.bind(this));
-
-  this.document_.addEventListener('click', this.onDocumentClick_.bind(this));
-
-  // Overwrite options and info bubble.
-  this.options_ = util.createChild(
-      this.toolbar_.querySelector('.filename-spacer'), 'options');
-
-  this.savedLabel_ = util.createChild(this.options_, 'saved');
-  this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED');
-
-  var overwriteOriginalBox =
-      util.createChild(this.options_, 'overwrite-original');
-
-  this.overwriteOriginal_ = util.createChild(
-      overwriteOriginalBox, 'common white', 'input');
-  this.overwriteOriginal_.type = 'checkbox';
-  this.overwriteOriginal_.id = 'overwrite-checkbox';
-  util.platform.getPreference(SlideMode.OVERWRITE_KEY, function(value) {
-    // Out-of-the box default is 'true'
-    this.overwriteOriginal_.checked =
-        (typeof value != 'string' || value == 'true');
-  }.bind(this));
-  this.overwriteOriginal_.addEventListener('click',
-      this.onOverwriteOriginalClick_.bind(this));
-
-  var overwriteLabel = util.createChild(overwriteOriginalBox, '', 'label');
-  overwriteLabel.textContent =
-      this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL');
-  overwriteLabel.setAttribute('for', 'overwrite-checkbox');
-
-  this.bubble_ = util.createChild(this.toolbar_, 'bubble');
-  this.bubble_.hidden = true;
-
-  var bubbleContent = util.createChild(this.bubble_);
-  bubbleContent.innerHTML = this.displayStringFunction_(
-      'GALLERY_OVERWRITE_BUBBLE');
-
-  util.createChild(this.bubble_, 'pointer bottom', 'span');
-
-  var bubbleClose = util.createChild(this.bubble_, 'close-x');
-  bubbleClose.addEventListener('click', this.onCloseBubble_.bind(this));
-
-  // Video player controls.
-  this.mediaSpacer_ =
-      util.createChild(this.container_, 'video-controls-spacer');
-  this.mediaToolbar_ = util.createChild(this.mediaSpacer_, 'tool');
-  this.mediaControls_ = new VideoControls(
-      this.mediaToolbar_,
-      this.showErrorBanner_.bind(this, 'GALLERY_VIDEO_ERROR'),
-      this.displayStringFunction_.bind(this),
-      this.toggleFullScreen_.bind(this),
-      this.container_);
-
-  // Ribbon and related controls.
-  this.arrowBox_ = util.createChild(this.container_, 'arrow-box');
-
-  this.arrowLeft_ =
-      util.createChild(this.arrowBox_, 'arrow left tool dimmable');
-  this.arrowLeft_.addEventListener('click',
-      this.advanceManually.bind(this, -1));
-  util.createChild(this.arrowLeft_);
-
-  util.createChild(this.arrowBox_, 'arrow-spacer');
-
-  this.arrowRight_ =
-      util.createChild(this.arrowBox_, 'arrow right tool dimmable');
-  this.arrowRight_.addEventListener('click',
-      this.advanceManually.bind(this, 1));
-  util.createChild(this.arrowRight_);
-
-  this.ribbonSpacer_ = util.createChild(this.toolbar_, 'ribbon-spacer');
-  this.ribbon_ = new Ribbon(this.document_,
-      this.metadataCache_, this.dataModel_, this.selectionModel_);
-  this.ribbonSpacer_.appendChild(this.ribbon_);
-
-  // Error indicator.
-  var errorWrapper = util.createChild(this.container_, 'prompt-wrapper');
-  errorWrapper.setAttribute('pos', 'center');
-
-  this.errorBanner_ = util.createChild(errorWrapper, 'error-banner');
-
-  util.createChild(this.container_, 'spinner');
-
-  var slideShowButton = util.createChild(this.toolbar_,
-      'button slideshow', 'button');
-  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
-  slideShowButton.addEventListener('click',
-      this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
-
-  var slideShowToolbar =
-      util.createChild(this.container_, 'tool slideshow-toolbar');
-  util.createChild(slideShowToolbar, 'slideshow-play').
-      addEventListener('click', this.toggleSlideshowPause_.bind(this));
-  util.createChild(slideShowToolbar, 'slideshow-end').
-      addEventListener('click', this.stopSlideshow_.bind(this));
-
-  // Editor.
-
-  this.editButton_ = util.createChild(this.toolbar_, 'button edit', 'button');
-  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
-  this.editButton_.setAttribute('disabled', '');  // Disabled by default.
-  this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
-
-  this.printButton_ = util.createChild(this.toolbar_, 'button print', 'button');
-  this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT');
-  this.printButton_.setAttribute('disabled', '');  // Disabled by default.
-  this.printButton_.addEventListener('click', this.print_.bind(this));
-
-  this.editBarSpacer_ = util.createChild(this.toolbar_, 'edit-bar-spacer');
-  this.editBarMain_ = util.createChild(this.editBarSpacer_, 'edit-main');
-
-  this.editBarMode_ = util.createChild(this.container_, 'edit-modal');
-  this.editBarModeWrapper_ = util.createChild(
-      this.editBarMode_, 'edit-modal-wrapper');
-  this.editBarModeWrapper_.hidden = true;
-
-  // Objects supporting image display and editing.
-  this.viewport_ = new Viewport();
-
-  this.imageView_ = new ImageView(
-      this.imageContainer_,
-      this.viewport_,
-      this.metadataCache_);
-
-  this.editor_ = new ImageEditor(
-      this.viewport_,
-      this.imageView_,
-      this.prompt_,
-      {
-        root: this.container_,
-        image: this.imageContainer_,
-        toolbar: this.editBarMain_,
-        mode: this.editBarModeWrapper_
-      },
-      SlideMode.editorModes,
-      this.displayStringFunction_);
-
-  this.editor_.getBuffer().addOverlay(
-      new SwipeOverlay(this.advanceManually.bind(this)));
-};
-
-/**
- * Load items, display the selected item.
- * @param {Rect} zoomFromRect Rectangle for zoom effect.
- * @param {function} displayCallback Called when the image is displayed.
- * @param {function} loadCallback Called when the image is displayed.
- */
-SlideMode.prototype.enter = function(
-    zoomFromRect, displayCallback, loadCallback) {
-  this.sequenceDirection_ = 0;
-  this.sequenceLength_ = 0;
-
-  var loadDone = function(loadType, delay) {
-    this.active_ = true;
-
-    this.selectionModel_.addEventListener('change', this.onSelectionBound_);
-    this.dataModel_.addEventListener('splice', this.onSpliceBound_);
-    this.dataModel_.addEventListener('content', this.onContentBound_);
-
-    ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
-    this.ribbon_.enable();
-
-    // Wait 1000ms after the animation is done, then prefetch the next image.
-    this.requestPrefetch(1, delay + 1000);
-
-    if (loadCallback) loadCallback();
-  }.bind(this);
-
-  // The latest |leave| call might have left the image animating. Remove it.
-  this.unloadImage_();
-
-  if (this.getItemCount_() == 0) {
-    this.displayedIndex_ = -1;
-    //TODO(kaznacheev) Show this message in the grid mode too.
-    this.showErrorBanner_('GALLERY_NO_IMAGES');
-    loadDone();
-  } else {
-    // Remember the selection if it is empty or multiple. It will be restored
-    // in |leave| if the user did not changing the selection manually.
-    var currentSelection = this.selectionModel_.selectedIndexes;
-    if (currentSelection.length == 1)
-      this.savedSelection_ = null;
-    else
-      this.savedSelection_ = currentSelection;
-
-    // Ensure valid single selection.
-    // Note that the SlideMode object is not listening to selection change yet.
-    this.select(Math.max(0, this.getSelectedIndex()));
-    this.displayedIndex_ = this.getSelectedIndex();
-
-    var selectedItem = this.getSelectedItem();
-    var selectedUrl = selectedItem.getUrl();
-    // Show the selected item ASAP, then complete the initialization
-    // (loading the ribbon thumbnails can take some time).
-    this.metadataCache_.get(selectedUrl, Gallery.METADATA_TYPE,
-        function(metadata) {
-          this.loadItem_(selectedUrl, metadata,
-              zoomFromRect && this.imageView_.createZoomEffect(zoomFromRect),
-              displayCallback, loadDone);
-        }.bind(this));
-
-  }
-};
-
-/**
- * Leave the mode.
- * @param {Rect} zoomToRect Rectangle for zoom effect.
- * @param {function} callback Called when the image is committed and
- *   the zoom-out animation has started.
- */
-SlideMode.prototype.leave = function(zoomToRect, callback) {
-  var commitDone = function() {
-      this.stopEditing_();
-      this.stopSlideshow_();
-      ImageUtil.setAttribute(this.arrowBox_, 'active', false);
-      this.selectionModel_.removeEventListener(
-          'change', this.onSelectionBound_);
-      this.dataModel_.removeEventListener('splice', this.onSpliceBound_);
-      this.dataModel_.removeEventListener('content', this.onContentBound_);
-      this.ribbon_.disable();
-      this.active_ = false;
-      if (this.savedSelection_)
-        this.selectionModel_.selectedIndexes = this.savedSelection_;
-      this.unloadImage_(zoomToRect);
-      callback();
-    }.bind(this);
-
-  if (this.getItemCount_() == 0) {
-    this.showErrorBanner_(false);
-    commitDone();
-  } else {
-    this.commitItem_(commitDone);
-  }
-
-  // Disable the slide-mode only buttons when leaving.
-  this.editButton_.setAttribute('disabled', '');
-  this.printButton_.setAttribute('disabled', '');
-};
-
-
-/**
- * Execute an action when the editor is not busy.
- *
- * @param {function} action Function to execute.
- */
-SlideMode.prototype.executeWhenReady = function(action) {
-  this.editor_.executeWhenReady(action);
-};
-
-/**
- * @return {boolean} True if the mode has active tools (that should not fade).
- */
-SlideMode.prototype.hasActiveTool = function() {
-  return this.isEditing();
-};
-
-/**
- * @return {number} Item count.
- * @private
- */
-SlideMode.prototype.getItemCount_ = function() {
-  return this.dataModel_.length;
-};
-
-/**
- * @param {number} index Index.
- * @return {Gallery.Item} Item.
- */
-SlideMode.prototype.getItem = function(index) {
-  return this.dataModel_.item(index);
-};
-
-/**
- * @return {Gallery.Item} Selected index.
- */
-SlideMode.prototype.getSelectedIndex = function() {
-  return this.selectionModel_.selectedIndex;
-};
-
-/**
- * @return {Rect} Screen rectangle of the selected image.
- */
-SlideMode.prototype.getSelectedImageRect = function() {
-  if (this.getSelectedIndex() < 0)
-    return null;
-  else
-    return this.viewport_.getScreenClipped();
-};
-
-/**
- * @return {Gallery.Item} Selected item.
- */
-SlideMode.prototype.getSelectedItem = function() {
-  return this.getItem(this.getSelectedIndex());
-};
-
-/**
- * Toggles the full screen mode.
- * @private
- */
-SlideMode.prototype.toggleFullScreen_ = function() {
-  util.toggleFullScreen(this.context_.appWindow,
-                        !util.isFullScreen(this.context_.appWindow));
-};
-
-/**
- * Selection change handler.
- *
- * Commits the current image and displays the newly selected image.
- * @private
- */
-SlideMode.prototype.onSelection_ = function() {
-  if (this.selectionModel_.selectedIndexes.length == 0)
-    return;  // Temporary empty selection.
-
-  // Forget the saved selection if the user changed the selection manually.
-  if (!this.isSlideshowOn_())
-    this.savedSelection_ = null;
-
-  if (this.getSelectedIndex() == this.displayedIndex_)
-    return;  // Do not reselect.
-
-  this.commitItem_(this.loadSelectedItem_.bind(this));
-};
-
-/**
- * Change the selection.
- *
- * @param {number} index New selected index.
- * @param {number=} opt_slideHint Slide animation direction (-1|1).
- */
-SlideMode.prototype.select = function(index, opt_slideHint) {
-  this.slideHint_ = opt_slideHint;
-  this.selectionModel_.selectedIndex = index;
-  this.selectionModel_.leadIndex = index;
-};
-
-/**
- * Load the selected item.
- *
- * @private
- */
-SlideMode.prototype.loadSelectedItem_ = function() {
-  var slideHint = this.slideHint_;
-  this.slideHint_ = undefined;
-
-  var index = this.getSelectedIndex();
-  if (index == this.displayedIndex_)
-    return;  // Do not reselect.
-
-  var step = slideHint || (index - this.displayedIndex_);
-
-  if (Math.abs(step) != 1) {
-    // Long leap, the sequence is broken, we have no good prefetch candidate.
-    this.sequenceDirection_ = 0;
-    this.sequenceLength_ = 0;
-  } else if (this.sequenceDirection_ == step) {
-    // Keeping going in sequence.
-    this.sequenceLength_++;
-  } else {
-    // Reversed the direction. Reset the counter.
-    this.sequenceDirection_ = step;
-    this.sequenceLength_ = 1;
-  }
-
-  if (this.sequenceLength_ <= 1) {
-    // We have just broke the sequence. Touch the current image so that it stays
-    // in the cache longer.
-    this.imageView_.prefetch(this.imageView_.contentID_);
-  }
-
-  this.displayedIndex_ = index;
-
-  function shouldPrefetch(loadType, step, sequenceLength) {
-    // Never prefetch when selecting out of sequence.
-    if (Math.abs(step) != 1)
-      return false;
-
-    // Never prefetch after a video load (decoding the next image can freeze
-    // the UI for a second or two).
-    if (loadType == ImageView.LOAD_TYPE_VIDEO_FILE)
-      return false;
-
-    // Always prefetch if the previous load was from cache.
-    if (loadType == ImageView.LOAD_TYPE_CACHED_FULL)
-      return true;
-
-    // Prefetch if we have been going in the same direction for long enough.
-    return sequenceLength >= 3;
-  }
-
-  var selectedItem = this.getSelectedItem();
-  this.currentUniqueKey_++;
-  var selectedUniqueKey = this.currentUniqueKey_;
-  var onMetadata = function(metadata) {
-    // Discard, since another load has been invoked after this one.
-    if (selectedUniqueKey != this.currentUniqueKey_) return;
-    this.loadItem_(selectedItem.getUrl(), metadata,
-        new ImageView.Effect.Slide(step, this.isSlideshowPlaying_()),
-        function() {} /* no displayCallback */,
-        function(loadType, delay) {
-          // Discard, since another load has been invoked after this one.
-          if (selectedUniqueKey != this.currentUniqueKey_) return;
-          if (shouldPrefetch(loadType, step, this.sequenceLength_)) {
-            this.requestPrefetch(step, delay);
-          }
-          if (this.isSlideshowPlaying_())
-            this.scheduleNextSlide_();
-        }.bind(this));
-  }.bind(this);
-  this.metadataCache_.get(
-      selectedItem.getUrl(), Gallery.METADATA_TYPE, onMetadata);
-};
-
-/**
- * Unload the current image.
- *
- * @param {Rect} zoomToRect Rectangle for zoom effect.
- * @private
- */
-SlideMode.prototype.unloadImage_ = function(zoomToRect) {
-  this.imageView_.unload(zoomToRect);
-  this.container_.removeAttribute('video');
-};
-
-/**
- * Data model 'splice' event handler.
- * @param {Event} event Event.
- * @private
- */
-SlideMode.prototype.onSplice_ = function(event) {
-  ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
-
-  // Splice invalidates saved indices, drop the saved selection.
-  this.savedSelection_ = null;
-
-  if (event.removed.length != 1)
-    return;
-
-  // Delay the selection to let the ribbon splice handler work first.
-  setTimeout(function() {
-    if (event.index < this.dataModel_.length) {
-      // There is the next item, select it.
-      // The next item is now at the same index as the removed one, so we need
-      // to correct displayIndex_ so that loadSelectedItem_ does not think
-      // we are re-selecting the same item (and does right-to-left slide-in
-      // animation).
-      this.displayedIndex_ = event.index - 1;
-      this.select(event.index);
-    } else if (this.dataModel_.length) {
-      // Removed item is the rightmost, but there are more items.
-      this.select(event.index - 1);  // Select the new last index.
-    } else {
-      // No items left. Unload the image and show the banner.
-      this.commitItem_(function() {
-        this.unloadImage_();
-        this.showErrorBanner_('GALLERY_NO_IMAGES');
-      }.bind(this));
-    }
-  }.bind(this), 0);
-};
-
-/**
- * @param {number} direction -1 for left, 1 for right.
- * @return {number} Next index in the given direction, with wrapping.
- * @private
- */
-SlideMode.prototype.getNextSelectedIndex_ = function(direction) {
-  function advance(index, limit) {
-    index += (direction > 0 ? 1 : -1);
-    if (index < 0)
-      return limit - 1;
-    if (index == limit)
-      return 0;
-    return index;
-  }
-
-  // If the saved selection is multiple the Slideshow should cycle through
-  // the saved selection.
-  if (this.isSlideshowOn_() &&
-      this.savedSelection_ && this.savedSelection_.length > 1) {
-    var pos = advance(this.savedSelection_.indexOf(this.getSelectedIndex()),
-        this.savedSelection_.length);
-    return this.savedSelection_[pos];
-  } else {
-    return advance(this.getSelectedIndex(), this.getItemCount_());
-  }
-};
-
-/**
- * Advance the selection based on the pressed key ID.
- * @param {string} keyID Key identifier.
- */
-SlideMode.prototype.advanceWithKeyboard = function(keyID) {
-  this.advanceManually(keyID == 'Up' || keyID == 'Left' ? -1 : 1);
-};
-
-/**
- * Advance the selection as a result of a user action (as opposed to an
- * automatic change in the slideshow mode).
- * @param {number} direction -1 for left, 1 for right.
- */
-SlideMode.prototype.advanceManually = function(direction) {
-  if (this.isSlideshowPlaying_()) {
-    this.pauseSlideshow_();
-    cr.dispatchSimpleEvent(this, 'useraction');
-  }
-  this.selectNext(direction);
-};
-
-/**
- * Select the next item.
- * @param {number} direction -1 for left, 1 for right.
- */
-SlideMode.prototype.selectNext = function(direction) {
-  this.select(this.getNextSelectedIndex_(direction), direction);
-};
-
-/**
- * Select the first item.
- */
-SlideMode.prototype.selectFirst = function() {
-  this.select(0);
-};
-
-/**
- * Select the last item.
- */
-SlideMode.prototype.selectLast = function() {
-  this.select(this.getItemCount_() - 1);
-};
-
-// Loading/unloading
-
-/**
- * Load and display an item.
- *
- * @param {string} url Item url.
- * @param {Object} metadata Item metadata.
- * @param {Object} effect Transition effect object.
- * @param {function} displayCallback Called when the image is displayed
- *     (which can happen before the image load due to caching).
- * @param {function} loadCallback Called when the image is fully loaded.
- * @private
- */
-SlideMode.prototype.loadItem_ = function(
-    url, metadata, effect, displayCallback, loadCallback) {
-  this.selectedImageMetadata_ = MetadataCache.cloneMetadata(metadata);
-
-  this.showSpinner_(true);
-
-  var loadDone = function(loadType, delay, error) {
-    var video = this.isShowingVideo_();
-    ImageUtil.setAttribute(this.container_, 'video', video);
-
-    this.showSpinner_(false);
-    if (loadType == ImageView.LOAD_TYPE_ERROR) {
-      // if we have a specific error, then display it
-      if (error) {
-        this.showErrorBanner_('GALLERY_' + error);
-      } else {
-        // otherwise try to infer general error
-        this.showErrorBanner_(
-            video ? 'GALLERY_VIDEO_ERROR' : 'GALLERY_IMAGE_ERROR');
-      }
-    } else if (loadType == ImageView.LOAD_TYPE_OFFLINE) {
-      this.showErrorBanner_(
-          video ? 'GALLERY_VIDEO_OFFLINE' : 'GALLERY_IMAGE_OFFLINE');
-    }
-
-    if (video) {
-      // The editor toolbar does not make sense for video, hide it.
-      this.stopEditing_();
-      this.mediaControls_.attachMedia(this.imageView_.getVideo());
-
-      // TODO(kaznacheev): Add metrics for video playback.
-    } else {
-      ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View'));
-
-      var toMillions = function(number) {
-        return Math.round(number / (1000 * 1000));
-      };
-
-      ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'),
-          toMillions(metadata.filesystem.size));
-
-      var canvas = this.imageView_.getCanvas();
-      ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'),
-          toMillions(canvas.width * canvas.height));
-
-      var extIndex = url.lastIndexOf('.');
-      var ext = extIndex < 0 ? '' : url.substr(extIndex + 1).toLowerCase();
-      if (ext == 'jpeg') ext = 'jpg';
-      ImageUtil.metrics.recordEnum(
-          ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES);
-    }
-
-    // Enable or disable buttons for editing and printing.
-    if (video || error) {
-      this.editButton_.setAttribute('disabled', '');
-      this.printButton_.setAttribute('disabled', '');
-    } else {
-      this.editButton_.removeAttribute('disabled');
-      this.printButton_.removeAttribute('disabled');
-    }
-
-    // For once edited image, disallow the 'overwrite' setting change.
-    ImageUtil.setAttribute(this.options_, 'saved',
-        !this.getSelectedItem().isOriginal());
-
-    util.platform.getPreference(SlideMode.OVERWRITE_BUBBLE_KEY,
-        function(value) {
-          var times = typeof value == 'string' ? parseInt(value, 10) : 0;
-          if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) {
-            this.bubble_.hidden = false;
-            if (this.isEditing()) {
-              util.platform.setPreference(
-                  SlideMode.OVERWRITE_BUBBLE_KEY, times + 1);
-            }
-          }
-        }.bind(this));
-
-    loadCallback(loadType, delay);
-  }.bind(this);
-
-  var displayDone = function() {
-    cr.dispatchSimpleEvent(this, 'image-displayed');
-    displayCallback();
-  }.bind(this);
-
-  this.editor_.openSession(url, metadata, effect,
-      this.saveCurrentImage_.bind(this), displayDone, loadDone);
-};
-
-/**
- * Commit changes to the current item and reset all messages/indicators.
- *
- * @param {function} callback Callback.
- * @private
- */
-SlideMode.prototype.commitItem_ = function(callback) {
-  this.showSpinner_(false);
-  this.showErrorBanner_(false);
-  this.editor_.getPrompt().hide();
-
-  // Detach any media attached to the controls.
-  if (this.mediaControls_.getMedia())
-    this.mediaControls_.detachMedia();
-
-  // If showing the video, then pause it. Note, that it may not be attached
-  // to the media controls yet.
-  if (this.isShowingVideo_()) {
-    this.imageView_.getVideo().pause();
-    // Force stop downloading, if uncached on Drive.
-    this.imageView_.getVideo().src = '';
-    this.imageView_.getVideo().load();
-  }
-
-  this.editor_.closeSession(callback);
-};
-
-/**
- * Request a prefetch for the next image.
- *
- * @param {number} direction -1 or 1.
- * @param {number} delay Delay in ms. Used to prevent the CPU-heavy image
- *   loading from disrupting the animation that might be still in progress.
- */
-SlideMode.prototype.requestPrefetch = function(direction, delay) {
-  if (this.getItemCount_() <= 1) return;
-
-  var index = this.getNextSelectedIndex_(direction);
-  var nextItemUrl = this.getItem(index).getUrl();
-  this.imageView_.prefetch(nextItemUrl, delay);
-};
-
-// Event handlers.
-
-/**
- * Unload handler, to be called from the top frame.
- * @param {boolean} exiting True if the app is exiting.
- */
-SlideMode.prototype.onUnload = function(exiting) {
-  if (this.isShowingVideo_() && this.mediaControls_.isPlaying()) {
-    this.mediaControls_.savePosition(exiting);
-  }
-};
-
-/**
- * beforeunload handler, to be called from the top frame.
- * @return {string} Message to show if there are unsaved changes.
- */
-SlideMode.prototype.onBeforeUnload = function() {
-  if (this.editor_.isBusy())
-    return this.displayStringFunction_('GALLERY_UNSAVED_CHANGES');
-  return null;
-};
-
-/**
- * Click handler for the image container.
- *
- * @param {Event} event Mouse click event.
- * @private
- */
-SlideMode.prototype.onClick_ = function(event) {
-  if (!this.isShowingVideo_() || !this.mediaControls_.getMedia())
-    return;
-  if (event.ctrlKey) {
-    this.mediaControls_.toggleLoopedModeWithFeedback(true);
-    if (!this.mediaControls_.isPlaying())
-      this.mediaControls_.togglePlayStateWithFeedback();
-  } else {
-    this.mediaControls_.togglePlayStateWithFeedback();
-  }
-};
-
-/**
- * Click handler for the entire document.
- * @param {Event} e Mouse click event.
- * @private
- */
-SlideMode.prototype.onDocumentClick_ = function(e) {
-  // Close the bubble if clicked outside of it and if it is visible.
-  if (!this.bubble_.contains(e.target) &&
-      !this.editButton_.contains(e.target) &&
-      !this.arrowLeft_.contains(e.target) &&
-      !this.arrowRight_.contains(e.target) &&
-      !this.bubble_.hidden) {
-    this.bubble_.hidden = true;
-  }
-};
-
-/**
- * Keydown handler.
- *
- * @param {Event} event Event.
- * @return {boolean} True if handled.
- */
-SlideMode.prototype.onKeyDown = function(event) {
-  var keyID = util.getKeyModifiers(event) + event.keyIdentifier;
-
-  if (this.isSlideshowOn_()) {
-    switch (keyID) {
-      case 'U+001B':  // Escape exits the slideshow.
-        this.stopSlideshow_(event);
-        break;
-
-      case 'U+0020':  // Space pauses/resumes the slideshow.
-        this.toggleSlideshowPause_();
-        break;
-
-      case 'Up':
-      case 'Down':
-      case 'Left':
-      case 'Right':
-        this.advanceWithKeyboard(keyID);
-        break;
-    }
-    return true;  // Consume all keystrokes in the slideshow mode.
-  }
-
-  if (this.isEditing() && this.editor_.onKeyDown(event))
-    return true;
-
-  switch (keyID) {
-    case 'U+0020':  // Space toggles the video playback.
-      if (this.isShowingVideo_() && this.mediaControls_.getMedia())
-        this.mediaControls_.togglePlayStateWithFeedback();
-      break;
-
-    case 'Ctrl-U+0050':  // Ctrl+'p' prints the current image.
-      if (!this.printButton_.hasAttribute('disabled'))
-        this.print_();
-      break;
-
-    case 'U+0045':  // 'e' toggles the editor.
-      if (!this.editButton_.hasAttribute('disabled'))
-        this.toggleEditor(event);
-      break;
-
-    case 'U+001B':  // Escape
-      if (!this.isEditing())
-        return false;  // Not handled.
-      this.toggleEditor(event);
-      break;
-
-    case 'Home':
-      this.selectFirst();
-      break;
-    case 'End':
-      this.selectLast();
-      break;
-    case 'Up':
-    case 'Down':
-    case 'Left':
-    case 'Right':
-      this.advanceWithKeyboard(keyID);
-      break;
-
-    default: return false;
-  }
-
-  return true;
-};
-
-/**
- * Resize handler.
- * @private
- */
-SlideMode.prototype.onResize_ = function() {
-  this.viewport_.sizeByFrameAndFit(this.container_);
-  this.viewport_.repaint();
-};
-
-/**
- * Update thumbnails.
- */
-SlideMode.prototype.updateThumbnails = function() {
-  this.ribbon_.reset();
-  if (this.active_)
-    this.ribbon_.redraw();
-};
-
-// Saving
-
-/**
- * Save the current image to a file.
- *
- * @param {function} callback Callback.
- * @private
- */
-SlideMode.prototype.saveCurrentImage_ = function(callback) {
-  var item = this.getSelectedItem();
-  var oldUrl = item.getUrl();
-  var canvas = this.imageView_.getCanvas();
-
-  this.showSpinner_(true);
-  var metadataEncoder = ImageEncoder.encodeMetadata(
-      this.selectedImageMetadata_.media, canvas, 1 /* quality */);
-
-  this.selectedImageMetadata_ = ContentProvider.ConvertContentMetadata(
-      metadataEncoder.getMetadata(), this.selectedImageMetadata_);
-
-  item.saveToFile(
-      this.context_.saveDirEntry,
-      this.shouldOverwriteOriginal_(),
-      canvas,
-      metadataEncoder,
-      function(success) {
-        // TODO(kaznacheev): Implement write error handling.
-        // Until then pretend that the save succeeded.
-        this.showSpinner_(false);
-        this.flashSavedLabel_();
-
-        var e = new Event('content');
-        e.item = item;
-        e.oldUrl = oldUrl;
-        e.metadata = this.selectedImageMetadata_;
-        this.dataModel_.dispatchEvent(e);
-
-        // Allow changing the 'Overwrite original' setting only if the user
-        // used Undo to restore the original image AND it is not a copy.
-        // Otherwise lock the setting in its current state.
-        var mayChangeOverwrite = !this.editor_.canUndo() && item.isOriginal();
-        ImageUtil.setAttribute(this.options_, 'saved', !mayChangeOverwrite);
-
-        if (this.imageView_.getContentRevision() == 1) {  // First edit.
-          ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit'));
-        }
-
-        if (oldUrl != item.getUrl()) {
-          this.dataModel_.splice(
-              this.getSelectedIndex(), 0, new Gallery.Item(oldUrl));
-          // The ribbon will ignore the splice above and redraw after the
-          // select call below (while being obscured by the Editor toolbar,
-          // so there is no need for nice animation here).
-          // SlideMode will ignore the selection change as the displayed item
-          // index has not changed.
-          this.select(++this.displayedIndex_);
-        }
-        callback();
-        cr.dispatchSimpleEvent(this, 'image-saved');
-      }.bind(this));
-};
-
-/**
- * Update caches when the selected item url has changed.
- *
- * @param {Event} event Event.
- * @private
- */
-SlideMode.prototype.onContentChange_ = function(event) {
-  var newUrl = event.item.getUrl();
-  if (newUrl != event.oldUrl) {
-    this.imageView_.changeUrl(newUrl);
-  }
-  this.metadataCache_.clear(event.oldUrl, Gallery.METADATA_TYPE);
-};
-
-/**
- * Flash 'Saved' label briefly to indicate that the image has been saved.
- * @private
- */
-SlideMode.prototype.flashSavedLabel_ = function() {
-  var setLabelHighlighted =
-      ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted');
-  setTimeout(setLabelHighlighted.bind(null, true), 0);
-  setTimeout(setLabelHighlighted.bind(null, false), 300);
-};
-
-/**
- * Local storage key for the 'Overwrite original' setting.
- * @type {string}
- */
-SlideMode.OVERWRITE_KEY = 'gallery-overwrite-original';
-
-/**
- * Local storage key for the number of times that
- * the overwrite info bubble has been displayed.
- * @type {string}
- */
-SlideMode.OVERWRITE_BUBBLE_KEY = 'gallery-overwrite-bubble';
-
-/**
- * Max number that the overwrite info bubble is shown.
- * @type {number}
- */
-SlideMode.OVERWRITE_BUBBLE_MAX_TIMES = 5;
-
-/**
- * @return {boolean} True if 'Overwrite original' is set.
- * @private
- */
-SlideMode.prototype.shouldOverwriteOriginal_ = function() {
-   return this.overwriteOriginal_.checked;
-};
-
-/**
- * 'Overwrite original' checkbox handler.
- * @param {Event} event Event.
- * @private
- */
-SlideMode.prototype.onOverwriteOriginalClick_ = function(event) {
-  util.platform.setPreference(SlideMode.OVERWRITE_KEY, event.target.checked);
-};
-
-/**
- * Overwrite info bubble close handler.
- * @private
- */
-SlideMode.prototype.onCloseBubble_ = function() {
-  this.bubble_.hidden = true;
-  util.platform.setPreference(SlideMode.OVERWRITE_BUBBLE_KEY,
-      SlideMode.OVERWRITE_BUBBLE_MAX_TIMES);
-};
-
-// Slideshow
-
-/**
- * Slideshow interval in ms.
- */
-SlideMode.SLIDESHOW_INTERVAL = 5000;
-
-/**
- * First slideshow interval in ms. It should be shorter so that the user
- * is not guessing whether the button worked.
- */
-SlideMode.SLIDESHOW_INTERVAL_FIRST = 1000;
-
-/**
- * Empirically determined duration of the fullscreen toggle animation.
- */
-SlideMode.FULLSCREEN_TOGGLE_DELAY = 500;
-
-/**
- * @return {boolean} True if the slideshow is on.
- * @private
- */
-SlideMode.prototype.isSlideshowOn_ = function() {
-  return this.container_.hasAttribute('slideshow');
-};
-
-/**
- * Start the slideshow.
- * @param {number=} opt_interval First interval in ms.
- * @param {Event=} opt_event Event.
- */
-SlideMode.prototype.startSlideshow = function(opt_interval, opt_event) {
-  // Set the attribute early to prevent the toolbar from flashing when
-  // the slideshow is being started from the mosaic view.
-  this.container_.setAttribute('slideshow', 'playing');
-
-  if (this.active_) {
-    this.stopEditing_();
-  } else {
-    // We are in the Mosaic mode. Toggle the mode but remember to return.
-    this.leaveAfterSlideshow_ = true;
-    this.toggleMode_(this.startSlideshow.bind(
-        this, SlideMode.SLIDESHOW_INTERVAL, opt_event));
-    return;
-  }
-
-  if (opt_event)  // Caused by user action, notify the Gallery.
-    cr.dispatchSimpleEvent(this, 'useraction');
-
-  this.fullscreenBeforeSlideshow_ = util.isFullScreen(this.context_.appWindow);
-  if (!this.fullscreenBeforeSlideshow_) {
-    // Wait until the zoom animation from the mosaic mode is done.
-    setTimeout(this.toggleFullScreen_.bind(this),
-               ImageView.ZOOM_ANIMATION_DURATION);
-    opt_interval = (opt_interval || SlideMode.SLIDESHOW_INTERVAL) +
-        SlideMode.FULLSCREEN_TOGGLE_DELAY;
-  }
-
-  this.resumeSlideshow_(opt_interval);
-};
-
-/**
- * Stop the slideshow.
- * @param {Event=} opt_event Event.
- * @private
- */
-SlideMode.prototype.stopSlideshow_ = function(opt_event) {
-  if (!this.isSlideshowOn_())
-    return;
-
-  if (opt_event)  // Caused by user action, notify the Gallery.
-    cr.dispatchSimpleEvent(this, 'useraction');
-
-  this.pauseSlideshow_();
-  this.container_.removeAttribute('slideshow');
-
-  // Do not restore fullscreen if we exited fullscreen while in slideshow.
-  var fullscreen = util.isFullScreen(this.context_.appWindow);
-  var toggleModeDelay = 0;
-  if (!this.fullscreenBeforeSlideshow_ && fullscreen) {
-    this.toggleFullScreen_();
-    toggleModeDelay = SlideMode.FULLSCREEN_TOGGLE_DELAY;
-  }
-  if (this.leaveAfterSlideshow_) {
-    this.leaveAfterSlideshow_ = false;
-    setTimeout(this.toggleMode_.bind(this), toggleModeDelay);
-  }
-};
-
-/**
- * @return {boolean} True if the slideshow is playing (not paused).
- * @private
- */
-SlideMode.prototype.isSlideshowPlaying_ = function() {
-  return this.container_.getAttribute('slideshow') == 'playing';
-};
-
-/**
- * Pause/resume the slideshow.
- * @private
- */
-SlideMode.prototype.toggleSlideshowPause_ = function() {
-  cr.dispatchSimpleEvent(this, 'useraction');  // Show the tools.
-  if (this.isSlideshowPlaying_()) {
-    this.pauseSlideshow_();
-  } else {
-    this.resumeSlideshow_(SlideMode.SLIDESHOW_INTERVAL_FIRST);
-  }
-};
-
-/**
- * @param {number=} opt_interval Slideshow interval in ms.
- * @private
- */
-SlideMode.prototype.scheduleNextSlide_ = function(opt_interval) {
-  console.assert(this.isSlideshowPlaying_(), 'Inconsistent slideshow state');
-
-  if (this.slideShowTimeout_)
-    clearTimeout(this.slideShowTimeout_);
-
-  this.slideShowTimeout_ = setTimeout(function() {
-        this.slideShowTimeout_ = null;
-        this.selectNext(1);
-      }.bind(this),
-      opt_interval || SlideMode.SLIDESHOW_INTERVAL);
-};
-
-/**
- * Resume the slideshow.
- * @param {number=} opt_interval Slideshow interval in ms.
- * @private
- */
-SlideMode.prototype.resumeSlideshow_ = function(opt_interval) {
-  this.container_.setAttribute('slideshow', 'playing');
-  this.scheduleNextSlide_(opt_interval);
-};
-
-/**
- * Pause the slideshow.
- * @private
- */
-SlideMode.prototype.pauseSlideshow_ = function() {
-  this.container_.setAttribute('slideshow', 'paused');
-  if (this.slideShowTimeout_) {
-    clearTimeout(this.slideShowTimeout_);
-    this.slideShowTimeout_ = null;
-  }
-};
-
-/**
- * @return {boolean} True if the editor is active.
- */
-SlideMode.prototype.isEditing = function() {
-  return this.container_.hasAttribute('editing');
-};
-
-/**
- * Stop editing.
- * @private
- */
-SlideMode.prototype.stopEditing_ = function() {
-  if (this.isEditing())
-    this.toggleEditor();
-};
-
-/**
- * Activate/deactivate editor.
- * @param {Event=} opt_event Event.
- */
-SlideMode.prototype.toggleEditor = function(opt_event) {
-  if (opt_event)  // Caused by user action, notify the Gallery.
-    cr.dispatchSimpleEvent(this, 'useraction');
-
-  if (!this.active_) {
-    this.toggleMode_(this.toggleEditor.bind(this));
-    return;
-  }
-
-  this.stopSlideshow_();
-  if (!this.isEditing() && this.isShowingVideo_())
-    return;  // No editing for videos.
-
-  ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing());
-
-  if (this.isEditing()) { // isEditing has just been flipped to a new value.
-    if (this.context_.readonlyDirName) {
-      this.editor_.getPrompt().showAt(
-          'top', 'readonly_warning', 0, this.context_.readonlyDirName);
-    }
-  } else {
-    this.editor_.getPrompt().hide();
-    this.editor_.leaveModeGently();
-  }
-};
-
-/**
- * Prints the current item.
- * @private
- */
-SlideMode.prototype.print_ = function() {
-  cr.dispatchSimpleEvent(this, 'useraction');
-  window.print();
-};
-
-/**
- * Display the error banner.
- * @param {string} message Message.
- * @private
- */
-SlideMode.prototype.showErrorBanner_ = function(message) {
-  if (message) {
-    this.errorBanner_.textContent = this.displayStringFunction_(message);
-  }
-  ImageUtil.setAttribute(this.container_, 'error', !!message);
-};
-
-/**
- * Show/hide the busy spinner.
- *
- * @param {boolean} on True if show, false if hide.
- * @private
- */
-SlideMode.prototype.showSpinner_ = function(on) {
-  if (this.spinnerTimer_) {
-    clearTimeout(this.spinnerTimer_);
-    this.spinnerTimer_ = null;
-  }
-
-  if (on) {
-    this.spinnerTimer_ = setTimeout(function() {
-      this.spinnerTimer_ = null;
-      ImageUtil.setAttribute(this.container_, 'spinner', true);
-    }.bind(this), 1000);
-  } else {
-    ImageUtil.setAttribute(this.container_, 'spinner', false);
-  }
-};
-
-/**
- * @return {boolean} True if the current item is a video.
- * @private
- */
-SlideMode.prototype.isShowingVideo_ = function() {
-  return !!this.imageView_.getVideo();
-};
-
-/**
- * Overlay that handles swipe gestures. Changes to the next or previous file.
- * @param {function(number)} callback A callback accepting the swipe direction
- *    (1 means left, -1 right).
- * @constructor
- * @implements {ImageBuffer.Overlay}
- */
-function SwipeOverlay(callback) {
-  this.callback_ = callback;
-}
-
-/**
- * Inherit ImageBuffer.Overlay.
- */
-SwipeOverlay.prototype.__proto__ = ImageBuffer.Overlay.prototype;
-
-/**
- * @param {number} x X pointer position.
- * @param {number} y Y pointer position.
- * @param {boolean} touch True if dragging caused by touch.
- * @return {function} The closure to call on drag.
- */
-SwipeOverlay.prototype.getDragHandler = function(x, y, touch) {
-  if (!touch)
-    return null;
-  var origin = x;
-  var done = false;
-  return function(x, y) {
-    if (!done && origin - x > SwipeOverlay.SWIPE_THRESHOLD) {
-      this.callback_(1);
-      done = true;
-    } else if (!done && x - origin > SwipeOverlay.SWIPE_THRESHOLD) {
-      this.callback_(-1);
-      done = true;
-    }
-  }.bind(this);
-};
-
-/**
- * If the user touched the image and moved the finger more than SWIPE_THRESHOLD
- * horizontally it's considered as a swipe gesture (change the current image).
- */
-SwipeOverlay.SWIPE_THRESHOLD = 100;
diff --git a/chrome/browser/resources/file_manager/js/photo/tile_view.js b/chrome/browser/resources/file_manager/js/photo/tile_view.js
deleted file mode 100644
index 26543b0..0000000
--- a/chrome/browser/resources/file_manager/js/photo/tile_view.js
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Tile view displays images/videos tiles.
- *
- * @param {HTMLDocument} document Document.
- * @param {function(TailBox, callback)} prepareBox This function should provide
- *     the passed box with width and height properties of the image.
- * @param {function(TailBox, callback)} loadBox This function should display
- *     the image in the box respecting clientWidth and clientHeight.
- * @constructor
- */
-function TileView(document, prepareBox, loadBox) {
-  var self = document.createElement('div');
-  TileView.decorate(self, prepareBox, loadBox);
-  return self;
-}
-
-TileView.prototype = { __proto__: HTMLDivElement.prototype };
-
-/**
- * The number of boxes updated at once after loading.
- */
-TileView.LOAD_CHUNK = 10;
-
-/**
- * The margin between the boxes (in pixels).
- */
-TileView.MARGIN = 10;
-
-/**
- * The delay between loading of two consecutive images.
- */
-TileView.LOAD_DELAY = 100;
-
-/**
- * @param {HTMLDivElement} self Element to decorate.
- * @param {function(TailBox, callback)} prepareBox See constructor.
- * @param {function(TailBox, callback)} loadBox See constructor.
- */
-TileView.decorate = function(self, prepareBox, loadBox) {
-  self.__proto__ = TileView.prototype;
-  self.classList.add('tile-view');
-  self.prepareBox_ = prepareBox;
-  self.loadBox_ = loadBox;
-};
-
-/**
- * Load and display media entries.
- * @param {Array.<FileEntry>} entries Entries list.
- */
-TileView.prototype.load = function(entries) {
-  this.boxes_ = [];
-
-  /**
-   * The number of boxes for which the image size is already known.
-   */
-  this.preparedCount_ = 0;
-
-  /**
-   * The number of boxes already displaying the image.
-   */
-  this.loadedCount_ = 0;
-
-  for (var index = 0; index < entries.length; index++) {
-    var box = new TileBox(this, entries[index]);
-    box.index = index;
-    this.boxes_.push(box);
-    this.prepareBox_(box, this.onBoxPrepared_.bind(this, box));
-  }
-
-  this.redraw();
-};
-
-/**
- * Redraws everything.
- */
-TileView.prototype.redraw = function() {
-  // TODO(dgozman): if we decide to support resize or virtual scrolling,
-  // we should save the chosen position for ready boxes, so they will not
-  // move around.
-
-  this.cellSize_ = Math.floor((this.clientHeight - 3 * TileView.MARGIN) / 2);
-  this.textContent = '';
-  for (var index = 0; index < this.boxes_.length; index++) {
-    this.appendChild(this.boxes_[index]);
-  }
-  this.repositionBoxes_(0);
-};
-
-/**
- * This function sets positions for boxes.
- *
- * To do this we keep a 2x4 array of cells marked busy or empty.
- * When trying to put the next box, we choose a pattern (horizontal, vertical,
- * square, etc.) which fits into the empty cells and place an image there.
- * The preferred pattern has the same orientation as image itself. Images
- * with unknown size are always shown in 1x1 cell.
- *
- * @param {number} from First index.
- * @private
- */
-TileView.prototype.repositionBoxes_ = function(from) {
-
-  var cellSize = this.cellSize_;
-  var margin = TileView.MARGIN;
-  var baseColAndEmpty = this.getBaseColAndEmpty_();
-
-  // |empty| is a 2x4 array of busy/empty cells.
-  var empty = baseColAndEmpty.empty;
-
-  // |baseCol| is the (tileview-wide) number of first column in |empty| array.
-  var baseCol = baseColAndEmpty.baseCol;
-
-  for (var index = from; index < this.boxes_.length; index++) {
-    while (!empty[0][0] && !empty[1][0]) {
-      // Skip the full columns at the start.
-      empty[0].shift();
-      empty[0].push(true);
-      empty[1].shift();
-      empty[1].push(true);
-      baseCol++;
-    }
-    // Here we always have an empty cell in the first column fo |empty| array,
-    // and |baseCol| is the column number of it.
-
-    var box = this.boxes_[index];
-    var imageWidth = box.width || 0;
-    var imageHeight = box.height || 0;
-
-    // Possible positions of the box:
-    //   p - the probability of this pattern to be used;
-    //   w - the width of resulting image (in columns);
-    //   h - the height of resulting image (in rows);
-    //   allowed - whether this pattern is allowed for this particular box.
-    var patterns = [
-      {p: 0.2, w: 2, h: 2, allowed: index < this.preparedCount_},
-      {p: 0.6, w: 1, h: 2, allowed: imageHeight > imageWidth &&
-                                    index < this.preparedCount_},
-      {p: 0.3, w: 2, h: 1, allowed: imageHeight < imageWidth &&
-                                    index < this.preparedCount_},
-      {p: 1.0, w: 1, h: 1, allowed: true} // Every image can be shown as 1x1.
-    ];
-
-    // The origin point is top-left empty cell, which must be in the
-    // first column.
-    var col = 0;
-    var row = empty[0][0] ? 0 : 1;
-
-    for (var pIndex = 0; pIndex < patterns.length; pIndex++) {
-      var pattern = patterns[pIndex];
-      if (Math.random() > pattern.p || !pattern.allowed) continue;
-      if (!this.canUsePattern_(empty, row, col, pattern)) continue;
-
-      // Found a pattern to use.
-      box.rect.row = row;
-      box.rect.col = col + baseCol;
-      box.rect.width = pattern.w;
-      box.rect.height = pattern.h;
-
-      // Now mark the cells as busy and stop.
-      this.usePattern_(empty, row, col, pattern);
-      break;
-    }
-
-    box.setPositionFromRect(margin, cellSize);
-  }
-};
-
-/**
- * @param {number} from Starting index.
- * @return {Object} An object containing the array of cells marked empty/busy
- *   and a base (left one) column number.
- * @private
- */
-TileView.prototype.getBaseColAndEmpty_ = function(from) {
-  // 2x4 array indicating whether the place is empty or not.
-  var empty = [[true, true, true, true], [true, true, true, true]];
-  var baseCol = 0;
-
-  if (from > 0) {
-    baseCol = this.boxes_[from - 1].rect.col;
-    if (from > 1) {
-      baseCol = Math.min(baseCol, this.boxes_[from - 2].rect.col);
-    }
-
-    for (var b = from - 2; b < from; b++) {
-      if (b < 0) continue;
-      var rect = this.boxes_[b].rect;
-      for (var i = 0; i < rect.height; i++) {
-        for (var j = 0; j < rect.width; j++) {
-          empty[i + rect.row][j + rect.col - baseCol] = false;
-        }
-      }
-    }
-  }
-
-  return {empty: empty, baseCol: baseCol};
-};
-
-/**
- * @param {Array} empty The empty/busy cells array.
- * @param {number} row The origin row.
- * @param {number} col The origin column.
- * @param {Object} pattern The pattern (see |repositionBoxes_|).
- * @return {boolean} Whether the pattern may be used at this origin.
- * @private
- */
-TileView.prototype.canUsePattern_ = function(empty, row, col, pattern) {
-  if (row + pattern.h > 2 || col + pattern.w > 4)
-    return false;
-
-  var can = true;
-  for (var r = 0; r < pattern.h; r++) {
-    for (var c = 0; c < pattern.w; c++) {
-      can = can && empty[row + r][col + c];
-    }
-  }
-  return can;
-};
-
-/**
- * Marks pattern's cells as busy.
- * @param {Array} empty The empty/busy cells array.
- * @param {number} row The origin row.
- * @param {number} col The origin column.
- * @param {Object} pattern The pattern (see |repositionBoxes_|).
- * @private
- */
-TileView.prototype.usePattern_ = function(empty, row, col, pattern) {
-  for (var r = 0; r < pattern.h; r++) {
-    for (var c = 0; c < pattern.w; c++) {
-      empty[row + r][col + c] = false;
-    }
-  }
-};
-
-/**
- * Called when box is ready.
- * @param {TileBox} box The box.
- * @private
- */
-TileView.prototype.onBoxPrepared_ = function(box) {
-  box.ready = true;
-  var to = this.preparedCount_;
-  while (to < this.boxes_.length && this.boxes_[to].ready) {
-    to++;
-  }
-
-  if (to >= Math.min(this.preparedCount_ + TileView.LOAD_CHUNK,
-                     this.boxes_.length)) {
-    var last = this.preparedCount_;
-    this.preparedCount_ = to;
-    this.repositionBoxes_(last);
-
-    if (this.loadedCount_ == last) {
-      // All previously prepared boxes have been loaded - start the next one.
-      var nextBox = this.boxes_[this.loadedCount_];
-      setTimeout(this.loadBox_, TileView.LOAD_DELAY,
-                 nextBox, this.onBoxLoaded.bind(this, nextBox));
-    }
-  }
-};
-
-/**
- * Called when box is loaded.
- * @param {TileBox} box The box.
- */
-TileView.prototype.onBoxLoaded = function(box) {
-  if (this.loadedCount_ != box.index)
-    console.error('inconsistent loadedCount');
-  this.loadedCount_ = box.index + 1;
-
-  var nextIndex = box.index + 1;
-  if (nextIndex < this.preparedCount_) {
-    var nextBox = this.boxes_[nextIndex];
-    setTimeout(this.loadBox_, TileView.LOAD_DELAY,
-               nextBox, this.onBoxLoaded.bind(this, nextBox));
-  }
-};
-
-
-
-/**
- * Container for functions to work with local TileView.
- */
-TileView.local = {};
-
-/**
- * Decorates a TileView to show local files.
- * @param {HTMLDivElement} view The view.
- * @param {MetadataCache} metadataCache Metadata cache.
- */
-TileView.local.decorate = function(view, metadataCache) {
-  TileView.decorate(view, TileView.local.prepareBox, TileView.local.loadBox);
-  view.metadataCache = metadataCache;
-};
-
-/**
- * Prepares image for local tile view box.
- * @param {TileBox} box The box.
- * @param {function} callback The callback.
- */
-TileView.local.prepareBox = function(box, callback) {
-  box.view_.metadataCache.get(box.entry, 'media', function(media) {
-    if (!media) {
-      box.width = 0;
-      box.height = 0;
-      box.imageTransform = null;
-    } else {
-      if (media.imageTransform && media.imageTransform.rotate90 % 2 == 1) {
-        box.width = media.height;
-        box.height = media.width;
-      } else {
-        box.width = media.width;
-        box.height = media.height;
-      }
-      box.imageTransform = media.imageTransform;
-    }
-
-    callback();
-  });
-};
-
-/**
- * Loads the image for local tile view box.
- * @param {TileBox} box The box.
- * @param {function} callback The callback.
- */
-TileView.local.loadBox = function(box, callback) {
-  var onLoaded = function(fullCanvas) {
-    try {
-      var canvas = box.ownerDocument.createElement('canvas');
-      canvas.width = box.clientWidth;
-      canvas.height = box.clientHeight;
-      var context = canvas.getContext('2d');
-      context.drawImage(fullCanvas, 0, 0, canvas.width, canvas.height);
-      box.appendChild(canvas);
-    } catch (e) {
-      // TODO(dgozman): classify possible exceptions here and reraise others.
-    }
-    callback();
-  };
-
-  var transformFetcher = function(url, onFetched) {
-    onFetched(box.imageTransform);
-  };
-
-  var imageLoader = new ImageUtil.ImageLoader(box.ownerDocument);
-  imageLoader.load(box.entry.toURL(), transformFetcher, onLoaded);
-};
-
-
-
-/**
- * Container for functions to work with drive TileView.
- */
-TileView.drive = {};
-
-/**
- * Decorates a TileView to show drive files.
- * @param {HTMLDivElement} view The view.
- * @param {MetadataCache} metadataCache Metadata cache.
- */
-TileView.drive.decorate = function(view, metadataCache) {
-  TileView.decorate(view, TileView.drive.prepareBox, TileView.drive.loadBox);
-  view.metadataCache = metadataCache;
-};
-
-/**
- * Prepares image for drive tile view box.
- * @param {TileBox} box The box.
- * @param {function} callback The callback.
- */
-TileView.drive.prepareBox = function(box, callback) {
-  box.view_.metadataCache.get(box.entry, 'thumbnail', function(thumbnail) {
-    if (!thumbnail) {
-      box.width = 0;
-      box.height = 0;
-      callback();
-      return;
-    }
-
-    // TODO(dgozman): remove this hack if we ask for larger thumbnails in
-    // drive code.
-    var thumbnailUrl = thumbnail.url.replace(/240$/, '512');
-
-    box.image = new Image();
-    box.image.onload = function(e) {
-      box.width = box.image.width;
-      box.height = box.image.height;
-      callback();
-    };
-    box.image.onerror = function() {
-      box.image = null;
-      callback();
-    };
-    box.image.src = thumbnailUrl;
-  });
-};
-
-/**
- * Loads the image for drive tile view box.
- * @param {TileBox} box The box.
- * @param {function} callback The callback.
- */
-TileView.drive.loadBox = function(box, callback) {
-  box.appendChild(box.image);
-  callback();
-};
-
-
-
-
-/**
- * Tile box is a part of tile view.
- * @param {TailView} view The parent view.
- * @param {Entry} entry Image file entry.
- * @constructor
- */
-function TileBox(view, entry) {
-  var self = view.ownerDocument.createElement('div');
-  TileBox.decorate(self, view, entry);
-  return self;
-}
-
-TileBox.prototype = { __proto__: HTMLDivElement.prototype };
-
-/**
- * @param {HTMLDivElement} self Element to decorate.
- * @param {TailView} view The parent view.
- * @param {Entry} entry Image file entry.
- */
-TileBox.decorate = function(self, view, entry) {
-  self.__proto__ = TileBox.prototype;
-  self.classList.add('tile-box');
-
-  self.view_ = view;
-  self.entry = entry;
-
-  self.ready = false;
-  self.rect = {row: 0, col: 0, width: 0, height: 0};
-
-  self.index = null;
-  self.height = null;
-  self.width = null;
-};
-
-/**
- * Sets box position according to the |rect| property and given sizes.
- * @param {number} margin Margin between cells.
- * @param {number} cellSize The size of one cell.
- * @constructor
- */
-TileBox.setPositionFromRect = function(margin, cellSize) {
-  this.style.top = margin + (cellSize + margin) * this.rect.row + 'px';
-  this.style.left = margin + (cellSize + margin) * this.rect.col + 'px';
-  this.style.height = (cellSize + margin) * this.rect.height - margin + 'px';
-  this.style.width = (cellSize + margin) * this.rect.width - margin + 'px';
-};
diff --git a/chrome/browser/resources/file_manager/js/progress_center.js b/chrome/browser/resources/file_manager/js/progress_center.js
deleted file mode 100644
index 43c8b5c..0000000
--- a/chrome/browser/resources/file_manager/js/progress_center.js
+++ /dev/null
@@ -1,471 +0,0 @@
-// Copyright 2013 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.
-
-'use strict';
-
-/**
- * Progress center at the background page.
- * @constructor
- */
-var ProgressCenter = function() {
-  cr.EventTarget.call(this);
-
-  /**
-   * Default container.
-   * @type {ProgressItemContainer}
-   * @private
-   */
-  this.targetContainer_ = ProgressItemContainer.CLIENT;
-
-  /**
-   * Current items managed by the progress center.
-   * @type {Array.<ProgressItem>}
-   * @private
-   */
-  this.items_ = [];
-
-  /**
-   * Timeout callback to remove items.
-   * @type {TimeoutManager}
-   * @private
-   */
-  this.resetTimeout_ = new ProgressCenter.TimeoutManager(
-      this.reset_.bind(this));
-};
-
-/**
- * The default amount of milliseconds time, before a progress item will reset
- * after the last complete.
- * @type {number}
- * @private
- * @const
- */
-ProgressCenter.RESET_DELAY_TIME_MS_ = 5000;
-
-/**
- * Utility for timeout callback.
- *
- * @param {function(*):*} callback Callbakc function.
- * @constructor
- */
-ProgressCenter.TimeoutManager = function(callback) {
-  this.callback_ = callback;
-  this.id_ = null;
-  Object.seal(this);
-};
-
-/**
- * Requests timeout. Previous request is canceled.
- * @param {number} milliseconds Time to invoke the callback function.
- */
-ProgressCenter.TimeoutManager.prototype.request = function(milliseconds) {
-  if (this.id_)
-    clearTimeout(this.id_);
-  this.id_ = setTimeout(function() {
-    this.id_ = null;
-    this.callback_();
-  }.bind(this), milliseconds);
-};
-
-ProgressCenter.prototype = {
-  __proto__: cr.EventTarget.prototype,
-
-  /**
-   * Obtains the items to be displayed in the application window.
-   * @private
-   */
-  get applicationItems() {
-    return this.items_.filter(function(item) {
-      return item.container == ProgressItemContainer.CLIENT;
-    });
-  }
-};
-
-/**
- * Updates the item in the progress center.
- * If the item has a new ID, the item is added to the item list.
- *
- * @param {ProgressCenterItem} item Updated item.
- */
-ProgressCenter.prototype.updateItem = function(item) {
-  var index = this.getItemIndex_(item.id);
-  if (index === -1) {
-    item.container = this.targetContainer_;
-    this.items_.push(item);
-  } else {
-    this.items_[index] = item;
-  }
-
-  if (item.status !== ProgressItemState.PROGRESSING)
-    this.resetTimeout_.request(ProgressCenter.RESET_DELAY_TIME_MS_);
-
-  var event = new Event(ProgressCenterEvent.ITEM_UPDATED);
-  event.item = item;
-  this.dispatchEvent(event);
-};
-
-/**
- * Requests to cancel the progress item.
- * @param {string} id Progress ID to be requested to cancel.
- */
-ProgressCenter.prototype.requestCancel = function(id) {
-  var item = this.getItemById(id);
-  if (item && item.cancelCallback)
-    item.cancelCallback();
-};
-
-/**
- * Switches the default container.
- * @param {ProgressItemContainer} newContainer New value of the default
- *     container.
- */
-ProgressCenter.prototype.switchContainer = function(newContainer) {
-  if (this.targetContainer_ === newContainer)
-    return;
-
-  // Current items to be moved to the notification center.
-  if (newContainer == ProgressItemContainer.NOTIFICATION) {
-    var items = this.applicationItems;
-    for (var i = 0; i < items.length; i++) {
-      items[i].container = ProgressItemContainer.NOTIFICATION;
-      this.postItemToNotification_(items);
-    }
-  }
-
-  // The items in the notification center does not come back to the Files.app
-  // clients.
-
-  // Assign the new value.
-  this.targetContainer_ = newContainer;
-};
-
-/**
- * Obtains the summarized item to be displayed in the closed progress center
- * panel.
- * @return {ProgressCenterItem} Summarized item. Returns null if there is no
- *     item.
- */
-ProgressCenter.prototype.getSummarizedItem = function() {
-  var applicationItems = this.applicationItems;
-  if (applicationItems.length == 0)
-    return null;
-  if (applicationItems.length == 1)
-    return applicationItems[0];
-  var summarizedItem = new ProgressCenterItem();
-  summarizedItem.summarized = true;
-  var completeCount = 0;
-  var progressingCount = 0;
-  var canceledCount = 0;
-  var errorCount = 0;
-  for (var i = 0; i < applicationItems.length; i++) {
-    switch (applicationItems[i].state) {
-      case ProgressItemState.COMPLETE:
-        completeCount++;
-        break;
-      case ProgressItemState.PROGRESSING:
-        progressingCount++;
-        break;
-      case ProgressItemState.ERROR:
-        errorCount++;
-        continue;
-      case ProgressItemState.CANCELED:
-        canceledCount++;
-        continue;
-    }
-    summarizedItem.progressMax += applicationItems[i].progressMax;
-    summarizedItem.progressValue += applicationItems[i].progressValue;
-  }
-  var messages = [];
-  if (completeCount)
-    messages.push(completeCount + ' complete');
-  if (progressingCount)
-    messages.push(progressingCount + ' active');
-  if (canceledCount)
-    messages.push(canceledCount + ' canceled');
-  if (errorCount)
-    messages.push(errorCount + ' error');
-  summarizedItem.message = messages.join(', ') + '.';
-  summarizedItem.state =
-      completeCount + progressingCount == 0 ? ProgressItemState.CANCELED :
-      progressingCount > 0 ? ProgressItemState.PROGRESSING :
-      ProgressItemState.COMPLETE;
-  return summarizedItem;
-};
-
-/**
- * Obtains item by ID.
- * @param {string} id ID of progress item.
- * @return {ProgressCenterItem} Progress center item having the specified
- *     ID. Null if the item is not found.
- */
-ProgressCenter.prototype.getItemById = function(id) {
-  return this.items_[this.getItemIndex_(id)];
-};
-
-/**
- * Obtains item index that have the specifying ID.
- * @param {string} id Item ID.
- * @return {number} Item index. Returns -1 If the item is not found.
- * @private
- */
-ProgressCenter.prototype.getItemIndex_ = function(id) {
-  for (var i = 0; i < this.items_.length; i++) {
-    if (this.items_[i].id === id)
-      return i;
-  }
-  return -1;
-};
-
-/**
- * Passes the item to the ChromeOS's message center.
- *
- * TODO(hirono): Implement the method.
- *
- * @private
- */
-ProgressCenter.prototype.passItemsToNotification_ = function() {
-
-};
-
-/**
- * Hides the progress center if there is no progressing items.
- * @private
- */
-ProgressCenter.prototype.reset_ = function() {
-  // If we have a progressing item, stop reset.
-  for (var i = 0; i < this.items_.length; i++) {
-    if (this.items_[i].state == ProgressItemState.PROGRESSING)
-      return;
-  }
-
-  // Reset items.
-  this.items_.splice(0, this.items_.length);
-
-  // Dispatch a event.
-  this.dispatchEvent(new Event(ProgressCenterEvent.RESET));
-};
-
-/**
- * An event handler for progress center.
- * @param {FileOperationManager} fileOperationManager File operation manager.
- * @param {ProgressCenter} progressCenter Progress center.
- * @constructor
- */
-var ProgressCenterHandler = function(fileOperationManager, progressCenter) {
-  /**
-   * Number of deleted files.
-   * @type {number}
-   * @private
-   */
-  this.totalDeleted_ = 0;
-
-  /**
-   * File operation manager.
-   * @type {FileOperationManager}
-   * @private
-   */
-  this.fileOperationManager_ = fileOperationManager;
-
-  /**
-   * Progress center.
-   * @type {progressCenter}
-   * @private
-   */
-  this.progressCenter_ = progressCenter;
-
-  // Seal the object.
-  Object.seal(this);
-
-  // Register event.
-  fileOperationManager.addEventListener('copy-progress',
-                                        this.onCopyProgress_.bind(this));
-  fileOperationManager.addEventListener('delete',
-                                        this.onDeleteProgress_.bind(this));
-};
-
-/**
- * Generate a progress message from the event.
- * @param {Event} event Progress event.
- * @return {string} message.
- * @private
- */
-ProgressCenterHandler.getMessage_ = function(event) {
-  if (event.reason === 'ERROR') {
-    switch (event.error.code) {
-      case util.FileOperationErrorType.TARGET_EXISTS:
-        var name = event.error.data.name;
-        if (event.error.data.isDirectory)
-          name += '/';
-        switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_TARGET_EXISTS_ERROR', name);
-          case 'MOVE': return strf('MOVE_TARGET_EXISTS_ERROR', name);
-          case 'ZIP': return strf('ZIP_TARGET_EXISTS_ERROR', name);
-          default: return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
-        }
-
-      case util.FileOperationErrorType.FILESYSTEM_ERROR:
-        var detail = util.getFileErrorString(event.error.data.code);
-        switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_FILESYSTEM_ERROR', detail);
-          case 'MOVE': return strf('MOVE_FILESYSTEM_ERROR', detail);
-          case 'ZIP': return strf('ZIP_FILESYSTEM_ERROR', detail);
-          default: return strf('TRANSFER_FILESYSTEM_ERROR', detail);
-        }
-
-      default:
-        switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_UNEXPECTED_ERROR', event.error);
-          case 'MOVE': return strf('MOVE_UNEXPECTED_ERROR', event.error);
-          case 'ZIP': return strf('ZIP_UNEXPECTED_ERROR', event.error);
-          default: return strf('TRANSFER_UNEXPECTED_ERROR', event.error);
-        }
-    }
-  } else if (event.status.numRemainingItems === 1) {
-    var name = event.status.processingEntry.name;
-    switch (event.status.operationType) {
-      case 'COPY': return strf('COPY_FILE_NAME', name);
-      case 'MOVE': return strf('MOVE_FILE_NAME', name);
-      case 'ZIP': return strf('ZIP_FILE_NAME', name);
-      default: return strf('TRANSFER_FILE_NAME', name);
-    }
-  } else {
-    var remainNumber = event.status.numRemainingItems;
-    switch (event.status.operationType) {
-      case 'COPY': return strf('COPY_ITEMS_REMAINING', remainNumber);
-      case 'MOVE': return strf('MOVE_ITEMS_REMAINING', remainNumber);
-      case 'ZIP': return strf('ZIP_ITEMS_REMAINING', remainNumber);
-      default: return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
-    }
-  }
-};
-
-/**
- * Generate a delete message from the event.
- * @param {Event} event Progress event.
- * @param {number} totalDeleted Total number of deleted files.
- * @return {string} message.
- * @private
- */
-ProgressCenterHandler.getDeleteMessage_ = function(event, totalDeleted) {
-  if (totalDeleted === 1) {
-    var fullPath = util.extractFilePath(event.urls[0]);
-    var fileName = PathUtil.split(fullPath).pop();
-    return strf('DELETED_MESSAGE', fileName);
-  } else {
-    return strf('DELETED_MESSAGE_PLURAL', totalDeleted);
-  }
-};
-
-/**
- * Handles the copy-progress event.
- * @param {Event} event The copy-progress event.
- * @private
- */
-ProgressCenterHandler.prototype.onCopyProgress_ = function(event) {
-  var progressCenter = this.progressCenter_;
-  var item;
-  switch (event.reason) {
-    case 'BEGIN':
-      item = new ProgressCenterItem();
-      item.id = event.taskId;
-      item.message = ProgressCenterHandler.getMessage_(event);
-      item.progressMax = event.status.totalBytes;
-      item.progressValue = event.status.processedBytes;
-      item.cancelCallback = function(inItem) {
-        this.fileOperationManager_.requestCancel(function() {
-          inItem.message = strf('COPY_CANCELLED');
-          inItem.state = ProgressItemState.CANCELED;
-          progressCenter.updateItem(inItem);
-        }.bind(this));
-      }.bind(this, item);
-
-      progressCenter.updateItem(item);
-      break;
-
-    case 'PROGRESS':
-      item = progressCenter.getItemById(event.taskId);
-      if (!item) {
-        console.error('Cannot find copying item.');
-        return;
-      }
-      item.message = ProgressCenterHandler.getMessage_(event);
-      item.progressValue = event.status.processedBytes;
-      progressCenter.updateItem(item);
-      break;
-
-    case 'SUCCESS':
-    case 'ERROR':
-      item = progressCenter.getItemById(event.taskId);
-      if (!item) {
-        // ERROR events can be dispatched before BEGIN events.
-        item = new ProgressCenterItem();
-        item.id = event.taskId;
-        item.progressMax = 1;
-      }
-      if (event.reason === 'SUCCESS') {
-        // TODO(hirono): Add a message for complete.
-        item.state = ProgressItemState.COMPLETE;
-        item.progressValue = item.progressMax;
-      } else {
-        item.message = ProgressCenterHandler.getMessage_(event);
-        item.state = ProgressItemState.ERROR;
-      }
-      progressCenter.updateItem(item);
-      break;
-  }
-};
-
-/**
- * Handles the delete event.
- * @param {Event} event The delete event.
- * @private
- */
-ProgressCenterHandler.prototype.onDeleteProgress_ = function(event) {
-  var progressCenter = this.progressCenter_;
-  var item;
-  switch (event.reason) {
-    case 'BEGIN':
-      this.totalDeleted_ = 0;
-      item = new ProgressCenterItem();
-      item.id = event.taskId;
-      // TODO(hirono): Specifying the correct message.
-      item.message =
-          ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
-      item.progressMax = 100;
-      progressCenter.updateItem(item);
-      break;
-
-    case 'PROGRESS':
-      item = progressCenter.getItemById(event.taskId);
-      if (!item) {
-        console.error('Cannot find deleting item.');
-        return;
-      }
-      this.totalDeleted_ += event.urls.length;
-      item.message =
-          ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
-      progressCenter.updateItem(item);
-      break;
-
-    case 'SUCCESS':
-    case 'ERROR':
-      item = progressCenter.getItemById(event.taskId);
-      if (!item) {
-        console.error('Cannot find deleting item.');
-        return;
-      }
-      if (event.reason === 'SUCCESS') {
-        this.totalDeleted_ += event.urls.length;
-        item.message =
-            ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
-        item.state = ProgressItemState.COMPLETE;
-        item.progressValue = item.progressMax;
-      } else {
-        item.message = str('DELETE_ERROR');
-        item.state = ProgressItemState.ERROR;
-      }
-      progressCenter.updateItem(item);
-      break;
-  }
-};
diff --git a/chrome/browser/resources/file_manager/js/share_dialog.js b/chrome/browser/resources/file_manager/js/share_dialog.js
deleted file mode 100644
index 19eb07e..0000000
--- a/chrome/browser/resources/file_manager/js/share_dialog.js
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2013 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.
-
-'use strict';
-
-/**
- * @param {HTMLElement} parentNode Node to be parent for this dialog.
- * @constructor
- * @extends {FileManagerDialogBase}
- * @implements {ShareClient.Observer}
- */
-function ShareDialog(parentNode) {
-  this.queue_ = new AsyncUtil.Queue();
-  this.onQueueTaskFinished_ = null;
-  this.shareClient_ = null;
-  this.spinner_ = null;
-  this.spinnerWrapper_ = null;
-  this.webViewWrapper_ = null;
-  this.webView_ = null;
-  this.failureTimeout_ = null;
-  this.callback_ = null;
-
-  FileManagerDialogBase.call(this, parentNode);
-}
-
-/**
- * Timeout for loading the share dialog before giving up.
- * @type {number}
- * @const
- */
-ShareDialog.FAILURE_TIMEOUT = 10000;
-
-/**
- * The result of opening the dialog.
- * @enum {string}
- * @const
- */
-ShareDialog.Result = Object.freeze({
-  // The dialog is closed normally. This includes user cancel.
-  SUCCESS: 'success',
-  // The dialog is closed by network error.
-  NETWORK_ERROR: 'networkError',
-  // The dialog is not opened because it is already showing.
-  ALREADY_SHOWING: 'alreadyShowing'
-});
-
-/**
- * Wraps a Web View element and adds authorization headers to it.
- * @param {string} urlPattern Pattern of urls to be authorized.
- * @param {WebView} webView Web View element to be wrapped.
- * @constructor
- */
-ShareDialog.WebViewAuthorizer = function(urlPattern, webView) {
-  this.urlPattern_ = urlPattern;
-  this.webView_ = webView;
-  this.initialized_ = false;
-  this.accessToken_ = null;
-};
-
-/**
- * Initializes the web view by installing hooks injecting the authorization
- * headers.
- * @param {function()} callback Completion callback.
- */
-ShareDialog.WebViewAuthorizer.prototype.initialize = function(callback) {
-  if (this.initialized_) {
-    callback();
-    return;
-  }
-
-  var registerInjectionHooks = function() {
-    this.webView_.removeEventListener('loadstop', registerInjectionHooks);
-    this.webView_.request.onBeforeSendHeaders.addListener(
-      this.authorizeRequest_.bind(this),
-      {urls: [this.urlPattern_]},
-      ['blocking', 'requestHeaders']);
-    this.initialized_ = true;
-    callback();
-  }.bind(this);
-
-  this.webView_.addEventListener('loadstop', registerInjectionHooks);
-  this.webView_.setAttribute('src', 'data:text/html,');
-};
-
-/**
- * Authorizes the web view by fetching the freshest access tokens.
- * @param {function()} callback Completion callback.
- */
-ShareDialog.WebViewAuthorizer.prototype.authorize = function(callback) {
-  // Fetch or update the access token.
-  chrome.fileBrowserPrivate.requestAccessToken(false,  // force_refresh
-      function(inAccessToken) {
-        this.accessToken_ = inAccessToken;
-        callback();
-      }.bind(this));
-};
-
-/**
- * Injects headers into the passed request.
- * @param {Event} e Request event.
- * @return {{requestHeaders: HttpHeaders}} Modified headers.
- * @private
- */
-ShareDialog.WebViewAuthorizer.prototype.authorizeRequest_ = function(e) {
-  e.requestHeaders.push({
-    name: 'Authorization',
-    value: 'Bearer ' + this.accessToken_
-  });
-  return {requestHeaders: e.requestHeaders};
-};
-
-ShareDialog.prototype = {
-  __proto__: FileManagerDialogBase.prototype
-};
-
-/**
- * One-time initialization of DOM.
- * @private
- */
-ShareDialog.prototype.initDom_ = function() {
-  FileManagerDialogBase.prototype.initDom_.call(this);
-  this.frame_.classList.add('share-dialog-frame');
-
-  this.spinnerWrapper_ = this.document_.createElement('div');
-  this.spinnerWrapper_.className = 'spinner-container';
-  this.frame_.appendChild(this.spinnerWrapper_);
-
-  this.spinner_ = this.document_.createElement('div');
-  this.spinner_.className = 'spinner';
-  this.spinnerWrapper_.appendChild(this.spinner_);
-
-  this.webViewWrapper_ = this.document_.createElement('div');
-  this.webViewWrapper_.className = 'share-dialog-webview-wrapper';
-  this.cancelButton_.hidden = true;
-  this.okButton_.hidden = true;
-  this.frame_.insertBefore(this.webViewWrapper_,
-                           this.frame_.querySelector('.cr-dialog-buttons'));
-};
-
-/**
- * @override
- */
-ShareDialog.prototype.onResized = function(width, height, callback) {
-  if (width && height) {
-    this.webViewWrapper_.style.width = width + 'px';
-    this.webViewWrapper_.style.height = height + 'px';
-    this.webView_.style.width = width + 'px';
-    this.webView_.style.height = height + 'px';
-  }
-  setTimeout(callback, 0);
-};
-
-/**
- * @override
- */
-ShareDialog.prototype.onClosed = function() {
-  this.hide();
-};
-
-/**
- * @override
- */
-ShareDialog.prototype.onLoaded = function() {
-  if (this.failureTimeout_) {
-    clearTimeout(this.failureTimeout_);
-    this.failureTimeout_ = null;
-  }
-
-  // Logs added temporarily to track crbug.com/288783.
-  console.debug('Loaded.');
-
-  this.okButton_.hidden = false;
-  this.spinnerWrapper_.hidden = true;
-  this.webViewWrapper_.classList.add('loaded');
-  this.webView_.focus();
-};
-
-/**
- * @override
- */
-ShareDialog.prototype.onLoadFailed = function() {
-  this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
-};
-
-/**
- * @override
- */
-ShareDialog.prototype.hide = function(opt_onHide) {
-  this.hideWithResult(ShareDialog.Result.SUCCESS, opt_onHide);
-};
-
-/**
- * Hide the dialog with the result and the callback.
- * @param {ShareDialog.Result} result Result passed to the closing callback.
- * @param {function()=} opt_onHide Callback called at the end of hiding.
- */
-ShareDialog.prototype.hideWithResult = function(result, opt_onHide) {
-  if (!this.isShowing())
-    return;
-
-  if (this.shareClient_) {
-    this.shareClient_.dispose();
-    this.shareClient_ = null;
-  }
-
-  this.webViewWrapper_.textContent = '';
-  if (this.failureTimeout_) {
-    clearTimeout(this.failureTimeout_);
-    this.failureTimeout_ = null;
-  }
-
-  FileManagerDialogBase.prototype.hide.call(
-      this,
-      function() {
-        if (opt_onHide)
-          opt_onHide();
-        this.callback_(result);
-        this.callback_ = null;
-      }.bind(this));
-};
-
-/**
- * Shows the dialog.
- * @param {FileEntry} entry Entry to share.
- * @param {function(boolean)} callback Callback to be called when the showing
- *     task is completed. The argument is whether to succeed or not. Note that
- *     cancel is regarded as success.
- */
-ShareDialog.prototype.show = function(entry, callback) {
-  // If the dialog is already showing, return the error.
-  if (this.isShowing()) {
-    callback(ShareDialog.Result.ALREADY_SHOWING);
-    return;
-  }
-
-  // Initialize the variables.
-  this.callback_ = callback;
-  this.spinnerWrapper_.hidden = false;
-  this.webViewWrapper_.style.width = '';
-  this.webViewWrapper_.style.height = '';
-
-  // If the embedded share dialog is not started within some time, then
-  // give up and show an error message.
-  this.failureTimeout_ = setTimeout(function() {
-    this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
-
-    // Logs added temporarily to track crbug.com/288783.
-    console.debug('Timeout. Web View points at: ' + this.webView_.src);
-  }.bind(this), ShareDialog.FAILURE_TIMEOUT);
-
-  // TODO(mtomasz): Move to initDom_() once and reuse <webview> once it gets
-  // fixed. See: crbug.com/260622.
-  this.webView_ = util.createChild(
-      this.webViewWrapper_, 'share-dialog-webview', 'webview');
-  this.webView_.setAttribute('tabIndex', '-1');
-  this.webViewAuthorizer_ = new ShareDialog.WebViewAuthorizer(
-      !window.IN_TEST ? (ShareClient.SHARE_TARGET + '/*') : '<all_urls>',
-      this.webView_);
-  this.webView_.addEventListener('newwindow', function(e) {
-    // Discard the window object and reopen in an external window.
-    e.window.discard();
-    util.visitURL(e.targetUrl);
-    e.preventDefault();
-  });
-  var show = FileManagerDialogBase.prototype.showBlankDialog.call(this);
-  if (!show) {
-    // The code shoundn't get here, since already-showing was handled before.
-    console.error('ShareDialog can\'t be shown.');
-    return;
-  }
-
-  // Initialize and authorize the Web View tag asynchronously.
-  var group = new AsyncUtil.Group();
-
-  // Fetches an url to the sharing dialog.
-  var shareUrl;
-  group.add(function(inCallback) {
-    chrome.fileBrowserPrivate.getShareUrl(
-        entry.toURL(),
-        function(inShareUrl) {
-          if (!chrome.runtime.lastError)
-            shareUrl = inShareUrl;
-          inCallback();
-        });
-  });
-  group.add(this.webViewAuthorizer_.initialize.bind(this.webViewAuthorizer_));
-  group.add(this.webViewAuthorizer_.authorize.bind(this.webViewAuthorizer_));
-
-  // Loads the share widget once all the previous async calls are finished.
-  group.run(function() {
-    // If the url is not obtained, return the network error.
-    if (!shareUrl) {
-       // Logs added temporarily to track crbug.com/288783.
-       console.debug('URL not available.');
-
-       this.hideWithResult(ShareDialog.Result.NETWORK_ERROR);
-      return;
-    }
-    // Already inactive, therefore ignore.
-    if (!this.isShowing())
-      return;
-    this.shareClient_ = new ShareClient(this.webView_,
-                                        shareUrl,
-                                        this);
-    this.shareClient_.load();
-  }.bind(this));
-};
-
-/**
- * Tells whether the share dialog is showing or not.
- *
- * @return {boolean} True since the show method is called and until the closing
- *     callback is invoked.
- */
-ShareDialog.prototype.isShowing = function() {
-  return !!this.callback_;
-};
diff --git a/chrome/browser/resources/file_manager/js/suggest_apps_dialog.js b/chrome/browser/resources/file_manager/js/suggest_apps_dialog.js
deleted file mode 100644
index 7e02b6b..0000000
--- a/chrome/browser/resources/file_manager/js/suggest_apps_dialog.js
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright (c) 2013 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.
-
-'use strict';
-
-/**
- * SuggestAppsDialog contains a list box to select an app to be opened the file
- * with. This dialog should be used as action picker for file operations.
- */
-
-/**
- * The width of the widget (in pixel).
- * @type {number}
- * @const
- */
-var WEBVIEW_WIDTH = 735;
-/**
- * The height of the widget (in pixel).
- * @type {number}
- * @const
- */
-var WEBVIEW_HEIGHT = 480;
-
-/**
- * The URL of the widget.
- * @type {string}
- * @const
- */
-var CWS_WIDGET_URL =
-    'https://clients5.google.com/webstore/wall/cros-widget-container';
-/**
- * The origin of the widget.
- * @type {string}
- * @const
- */
-var CWS_WIDGET_ORIGIN = 'https://clients5.google.com';
-
-/**
- * Creates dialog in DOM tree.
- *
- * @param {HTMLElement} parentNode Node to be parent for this dialog.
- * @param {Object} state Static state of suggest app dialog.
- * @constructor
- * @extends {FileManagerDialogBase}
- */
-function SuggestAppsDialog(parentNode, state) {
-  FileManagerDialogBase.call(this, parentNode);
-
-  this.frame_.id = 'suggest-app-dialog';
-
-  this.spinner_ = this.document_.createElement('div');
-  this.spinner_.className = 'spinner';
-
-  this.spinnerWrapper_ = this.document_.createElement('div');
-  this.spinnerWrapper_.className = 'spinner-container';
-  this.spinnerWrapper_.style.width = WEBVIEW_WIDTH + 'px';
-  this.spinnerWrapper_.style.height = WEBVIEW_HEIGHT + 'px';
-  this.spinnerWrapper_.appendChild(this.spinner_);
-  this.frame_.insertBefore(this.spinnerWrapper_, this.text_.nextSibling);
-
-  this.webviewContainer_ = this.document_.createElement('div');
-  this.webviewContainer_.id = 'webview-container';
-  this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px';
-  this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px';
-  this.frame_.insertBefore(this.webviewContainer_, this.text_.nextSibling);
-
-  this.buttons_ = this.document_.createElement('div');
-  this.buttons_.id = 'buttons';
-  this.frame_.appendChild(this.buttons_);
-
-  this.webstoreButton_ = this.document_.createElement('div');
-  this.webstoreButton_.id = 'webstore-button';
-  this.webstoreButton_.innerHTML = str('SUGGEST_DIALOG_LINK_TO_WEBSTORE');
-  this.webstoreButton_.addEventListener(
-      'click', this.onWebstoreLinkClicked_.bind(this));
-  this.buttons_.appendChild(this.webstoreButton_);
-
-  this.initialFocusElement_ = this.webviewContainer_;
-
-  this.webview_ = null;
-  this.accessToken_ = null;
-  this.widgetUrl_ =
-      state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL;
-  this.widgetOrigin_ =
-      state.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN;
-
-  this.extension_ = null;
-  this.mime_ = null;
-  this.installingItemId_ = null;
-  this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
-
-  this.initializationTask_ = new AsyncUtil.Group();
-  this.initializationTask_.add(this.retrieveAuthorizeToken_.bind(this));
-  this.initializationTask_.run();
-}
-
-SuggestAppsDialog.prototype = {
-  __proto__: FileManagerDialogBase.prototype
-};
-
-/**
- * @enum {string}
- * @const
- */
-SuggestAppsDialog.State = {
-  UNINITIALIZED: 'SuggestAppsDialog.State.UNINITIALIZED',
-  INITIALIZING: 'SuggestAppsDialog.State.INITIALIZING',
-  INITIALIZE_FAILED_CLOSING:
-      'SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING',
-  INITIALIZED: 'SuggestAppsDialog.State.INITIALIZED',
-  INSTALLING: 'SuggestAppsDialog.State.INSTALLING',
-  INSTALLED_CLOSING: 'SuggestAppsDialog.State.INSTALLED_CLOSING',
-  CANCELED_CLOSING: 'SuggestAppsDialog.State.CANCELED_CLOSING'
-};
-Object.freeze(SuggestAppsDialog.State);
-
-/**
- * @enum {string}
- * @const
- */
-SuggestAppsDialog.Result = {
-  // Install is done. The install app should be opened.
-  INSTALL_SUCCESSFUL: 'SuggestAppsDialog.Result.INSTALL_SUCCESSFUL',
-  // User cancelled the suggest app dialog. No message should be shown.
-  USER_CANCELL: 'SuggestAppsDialog.Result.USER_CANCELL',
-  // Failed to load the widget. Error message should be shown.
-  FAILED: 'SuggestAppsDialog.Result.FAILED'
-};
-Object.freeze(SuggestAppsDialog.Result);
-
-/**
- * @override
- */
-SuggestAppsDialog.prototype.onInputFocus = function() {
-  this.webviewContainer_.select();
-};
-
-/**
- * Injects headers into the passed request.
- *
- * @param {Event} e Request event.
- * @return {{requestHeaders: HttpHeaders}} Modified headers.
- * @private
- */
-SuggestAppsDialog.prototype.authorizeRequest_ = function(e) {
-  e.requestHeaders.push({
-    name: 'Authorization',
-    value: 'Bearer ' + this.accessToken_
-  });
-  return {requestHeaders: e.requestHeaders};
-};
-
-/**
- * Retrieves the authorize token. This method should be called in
- * initialization of the dialog.
- *
- * @param {function()} callback Called when the token is retrieved.
- * @private
- */
-SuggestAppsDialog.prototype.retrieveAuthorizeToken_ = function(callback) {
-  if (window.IN_TEST) {
-    // In test, use a dummy string as token. This must be a non-empty string.
-    this.accessToken_ = 'DUMMY_ACCESS_TOKEN_FOR_TEST';
-  }
-
-  if (this.accessToken_) {
-    callback();
-    return;
-  }
-
-  // Fetch or update the access token.
-  chrome.fileBrowserPrivate.requestWebStoreAccessToken(
-      function(accessToken) {
-        // In case of error, this.accessToken_ will be set to null.
-        this.accessToken_ = accessToken;
-        callback();
-      }.bind(this));
-};
-
-/**
- * Shows dialog.
- *
- * @param {string} extension Extension of the file.
- * @param {string} mime Mime of the file.
- * @param {function(boolean)} onDialogClosed Called when the dialog is closed.
- *     The argument is the result of installation: true if an app is installed,
- *     false otherwise.
- */
-SuggestAppsDialog.prototype.show = function(extension, mime, onDialogClosed) {
-  if (this.state_ != SuggestAppsDialog.State.UNINITIALIZED) {
-    console.error('Invalid state.');
-    return;
-  }
-
-  this.extension_ = extension;
-  this.mimeType_ = mime;
-  this.onDialogClosed_ = onDialogClosed;
-  this.state_ = SuggestAppsDialog.State.INITIALIZING;
-
-  // Makes it sure that the initialization is completed.
-  this.initializationTask_.run(function() {
-    if (!this.accessToken_) {
-      this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
-      this.onHide_();
-      return;
-    }
-
-    var title = str('SUGGEST_DIALOG_TITLE');
-
-    var show =
-        FileManagerDialogBase.prototype.showTitleOnlyDialog.call(this, title);
-    if (!show) {
-      console.error('SuggestAppsDialog can\'t be shown');
-      this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
-      this.onHide();
-      return;
-    }
-
-    this.webviewContainer_.innerHTML =
-        '<webview id="cws-widget" partition="persist:cwswidgets"></webview>';
-
-    this.webview_ = this.container_.querySelector('#cws-widget');
-    this.webview_.style.width = WEBVIEW_WIDTH + 'px';
-    this.webview_.style.height = WEBVIEW_HEIGHT + 'px';
-    this.webview_.request.onBeforeSendHeaders.addListener(
-        this.authorizeRequest_.bind(this),
-        {urls: [this.widgetOrigin_ + '/*']},
-        ['blocking', 'requestHeaders']);
-    this.webview_.addEventListener('newwindow', function(event) {
-      // Discard the window object and reopen in an external window.
-      event.window.discard();
-      util.visitURL(event.targetUrl);
-      event.preventDefault();
-    });
-
-    this.frame_.classList.add('show-spinner');
-
-    this.webviewClient_ = new CWSContainerClient(
-        this.webview_,
-        extension, mime,
-        WEBVIEW_WIDTH, WEBVIEW_HEIGHT,
-        this.widgetUrl_, this.widgetOrigin_);
-    this.webviewClient_.addEventListener(CWSContainerClient.Events.LOADED,
-                                         this.onWidgetLoaded_.bind(this));
-    this.webviewClient_.addEventListener(CWSContainerClient.Events.LOAD_FAILED,
-                                         this.onWidgetLoadFailed_.bind(this));
-    this.webviewClient_.addEventListener(
-        CWSContainerClient.Events.REQUEST_INSTALL,
-        this.onInstallRequest_.bind(this));
-    this.webviewClient_.load();
-  }.bind(this));
-};
-
-/**
- * Called when the 'See more...' link is clicked to be navigated to Webstore.
- * @param {Event} e Event.
- * @private
- */
-SuggestAppsDialog.prototype.onWebstoreLinkClicked_ = function(e) {
-  var webStoreUrl =
-      FileTasks.createWebStoreLink(this.extension_, this.mimeType_);
-  chrome.windows.create({url: webStoreUrl});
-  this.hide();
-};
-
-/**
- * Called when the widget is loaded successfully.
- * @param {Event} event Event.
- * @private
- */
-SuggestAppsDialog.prototype.onWidgetLoaded_ = function(event) {
-  this.frame_.classList.remove('show-spinner');
-  this.state_ = SuggestAppsDialog.State.INITIALIZED;
-
-  this.webview_.focus();
-};
-
-/**
- * Called when the widget is failed to load.
- * @param {Event} event Event.
- * @private
- */
-SuggestAppsDialog.prototype.onWidgetLoadFailed_ = function(event) {
-  this.frame_.classList.remove('show-spinner');
-  this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
-
-  this.hide();
-};
-
-/**
- * Called when the connection status is changed.
- * @param {util.DriveConnectionType} connectionType Current connection type.
- */
-SuggestAppsDialog.prototype.onDriveConnectionChanged =
-    function(connectionType) {
-  if (this.state_ !== SuggestAppsDialog.State.UNINITIALIZED &&
-      connectionType === util.DriveConnectionType.OFFLINE) {
-    this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
-    this.hide();
-  }
-};
-
-/**
- * Called when receiving the install request from the webview client.
- * @param {Event} e Event.
- * @private
- */
-SuggestAppsDialog.prototype.onInstallRequest_ = function(e) {
-  var itemId = e.itemId;
-  this.installingItemId_ = itemId;
-
-  this.appInstaller_ = new AppInstaller(itemId);
-  this.appInstaller_.install(this.onInstallCompleted_.bind(this));
-
-  this.frame_.classList.add('show-spinner');
-  this.state_ = SuggestAppsDialog.State.INSTALLING;
-};
-
-/**
- * Called when the installation is completed from the app installer.
- * @param {AppInstaller.Result} result Result of the installation.
- * @param {string} error Detail of the error.
- * @private
- */
-SuggestAppsDialog.prototype.onInstallCompleted_ = function(result, error) {
-  var success = (result === AppInstaller.Result.SUCCESS);
-
-  this.frame_.classList.remove('show-spinner');
-  this.state_ = success ?
-                SuggestAppsDialog.State.INSTALLED_CLOSING :
-                SuggestAppsDialog.State.INITIALIZED;  // Back to normal state.
-  this.webviewClient_.onInstallCompleted(success, this.installingItemId_);
-  this.installingItemId_ = null;
-
-  switch (result) {
-  case AppInstaller.Result.SUCCESS:
-    this.hide();
-    break;
-  case AppInstaller.Result.CANCELLED:
-    // User cancelled the installation. Do nothing.
-    break;
-  case AppInstaller.Result.ERROR:
-    fileManager.error.show(str('SUGGEST_DIALOG_INSTALLATION_FAILED'));
-    break;
-  }
-};
-
-/**
- * @override
- */
-SuggestAppsDialog.prototype.hide = function(opt_originalOnHide) {
-  switch (this.state_) {
-    case SuggestAppsDialog.State.INSTALLING:
-      // Install is being aborted. Send the failure result.
-      // Cancels the install.
-      if (this.webviewClient_)
-        this.webviewClient_.onInstallCompleted(false, this.installingItemId_);
-      this.installingItemId_ = null;
-
-      // Assumes closing the dialog as canceling the install.
-      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
-      break;
-    case SuggestAppsDialog.State.INSTALLED_CLOSING:
-    case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
-      // Do nothing.
-      break;
-    case SuggestAppsDialog.State.INITIALIZED:
-      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
-      break;
-    default:
-      this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
-      console.error('Invalid state.');
-  }
-
-  if (this.webviewClient_) {
-    this.webviewClient_.dispose();
-    this.webviewClient_ = null;
-  }
-
-  this.webviewContainer_.innerHTML = '';
-  this.extension_ = null;
-  this.mime_ = null;
-
-  FileManagerDialogBase.prototype.hide.call(
-      this,
-      this.onHide_.bind(this, opt_originalOnHide));
-};
-
-/**
- * @param {function()=} opt_originalOnHide Original onHide function passed to
- *     SuggestAppsDialog.hide().
- * @private
- */
-SuggestAppsDialog.prototype.onHide_ = function(opt_originalOnHide) {
-  // Calls the callback after the dialog hides.
-  if (opt_originalOnHide)
-    opt_originalOnHide();
-
-  var result;
-  switch (this.state_) {
-    case SuggestAppsDialog.State.INSTALLED_CLOSING:
-      result = SuggestAppsDialog.Result.INSTALL_SUCCESSFUL;
-      break;
-    case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
-      result = SuggestAppsDialog.Result.FAILED;
-      break;
-    case SuggestAppsDialog.State.CANCELED_CLOSING:
-      result = SuggestAppsDialog.Result.USER_CANCELL;
-      break;
-    default:
-      result = SuggestAppsDialog.Result.USER_CANCELL;
-      console.error('Invalid state.');
-  }
-  this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
-
-  this.onDialogClosed_(result);
-};
diff --git a/chrome/browser/resources/file_manager/js/test_util.js b/chrome/browser/resources/file_manager/js/test_util.js
deleted file mode 100644
index ee6ef3e..0000000
--- a/chrome/browser/resources/file_manager/js/test_util.js
+++ /dev/null
@@ -1,771 +0,0 @@
-// Copyright (c) 2013 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.
-
-/**
- * Namespace for test related things.
- */
-var test = test || {};
-
-/**
- * Namespace for test utility functions.
- *
- * Public functions in the test.util.sync and the test.util.async namespaces are
- * published to test cases and can be called by using callRemoteTestUtil. The
- * arguments are serialized as JSON internally. If application ID is passed to
- * callRemoteTestUtil, the content window of the application is added as the
- * first argument. The functions in the test.util.async namespace are passed the
- * callback function as the last argument.
- */
-test.util = {};
-
-/**
- * Namespace for synchronous utility functions.
- */
-test.util.sync = {};
-
-/**
- * Namespace for asynchronous utility functions.
- */
-test.util.async = {};
-
-/**
- * Extension ID of the testing extension.
- * @type {string}
- * @const
- */
-test.util.TESTING_EXTENSION_ID = 'oobinhbdbiehknkpbpejbbpdbkdjmoco';
-
-/**
- * Interval of checking a condition in milliseconds.
- * @type {number}
- * @const
- * @private
- */
-test.util.WAITTING_INTERVAL_ = 50;
-
-/**
- * Repeats the function until it returns true.
- * @param {function()} closure Function expected to return true.
- * @private
- */
-test.util.repeatUntilTrue_ = function(closure) {
-  var step = function() {
-    if (closure())
-      return;
-    setTimeout(step, test.util.WAITTING_INTERVAL_);
-  };
-  step();
-};
-
-/**
- * Opens the main Files.app's window and waits until it is ready.
- *
- * @param {Object} appState App state.
- * @param {function(string)} callback Completion callback with the new window's
- *     App ID.
- */
-test.util.async.openMainWindow = function(appState, callback) {
-  var steps = [
-    function() {
-      launchFileManager(appState,
-                        undefined,  // opt_type
-                        undefined,  // opt_id
-                        steps.shift());
-    },
-    function(appId) {
-      test.util.repeatUntilTrue_(function() {
-        if (!appWindows[appId])
-          return false;
-        var contentWindow = appWindows[appId].contentWindow;
-        var table = contentWindow.document.querySelector('#detail-table');
-        if (!table)
-          return false;
-        callback(appId);
-        return true;
-      });
-    }
-  ];
-  steps.shift()();
-};
-
-/**
- * Waits for a window with the specified App ID prefix. Eg. `files` will match
- * windows such as files#0, files#1, etc.
- *
- * @param {string} appIdPrefix ID prefix of the requested window.
- * @param {function(string)} callback Completion callback with the new window's
- *     App ID.
- */
-test.util.async.waitForWindow = function(appIdPrefix, callback) {
-  test.util.repeatUntilTrue_(function() {
-    for (var appId in appWindows) {
-      if (appId.indexOf(appIdPrefix) == 0 &&
-          appWindows[appId].contentWindow) {
-        callback(appId);
-        return true;
-      }
-    }
-    return false;
-  });
-};
-
-/**
- * Gets a document in the Files.app's window, including iframes.
- *
- * @param {Window} contentWindow Window to be used.
- * @param {string=} opt_iframeQuery Query for the iframe.
- * @return {Document=} Returns the found document or undefined if not found.
- * @private
- */
-test.util.sync.getDocument_ = function(contentWindow, opt_iframeQuery) {
-  if (opt_iframeQuery) {
-    var iframe = contentWindow.document.querySelector(opt_iframeQuery);
-    return iframe && iframe.contentWindow && iframe.contentWindow.document;
-  }
-
-  return contentWindow.document;
-};
-
-/**
- * Gets total Javascript error count from each app window.
- * @return {number} Error count.
- */
-test.util.sync.getErrorCount = function() {
-  var totalCount = JSErrorCount;
-  for (var appId in appWindows) {
-    var contentWindow = appWindows[appId].contentWindow;
-    if (contentWindow.JSErrorCount)
-      totalCount += contentWindow.JSErrorCount;
-  }
-  return totalCount;
-};
-
-/**
- * Resizes the window to the specified dimensions.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {number} width Window width.
- * @param {number} height Window height.
- * @return {boolean} True for success.
- */
-test.util.sync.resizeWindow = function(contentWindow, width, height) {
-  appWindows[contentWindow.appID].resizeTo(width, height);
-  return true;
-};
-
-/**
- * Returns an array with the files currently selected in the file manager.
- *
- * @param {Window} contentWindow Window to be tested.
- * @return {Array.<string>} Array of selected files.
- */
-test.util.sync.getSelectedFiles = function(contentWindow) {
-  var table = contentWindow.document.querySelector('#detail-table');
-  var rows = table.querySelectorAll('li');
-  var selected = [];
-  for (var i = 0; i < rows.length; ++i) {
-    if (rows[i].hasAttribute('selected')) {
-      selected.push(
-          rows[i].querySelector('.filename-label').textContent);
-    }
-  }
-  return selected;
-};
-
-/**
- * Returns an array with the files on the file manager's file list.
- *
- * @param {Window} contentWindow Window to be tested.
- * @return {Array.<Array.<string>>} Array of rows.
- */
-test.util.sync.getFileList = function(contentWindow) {
-  var table = contentWindow.document.querySelector('#detail-table');
-  var rows = table.querySelectorAll('li');
-  var fileList = [];
-  for (var j = 0; j < rows.length; ++j) {
-    var row = rows[j];
-    fileList.push([
-      row.querySelector('.filename-label').textContent,
-      row.querySelector('.size').textContent,
-      row.querySelector('.type').textContent,
-      row.querySelector('.date').textContent
-    ]);
-  }
-  return fileList;
-};
-
-/**
- * Checkes if the given label and path of the volume are selected.
- * @param {Window} contentWindow Window to be tested.
- * @param {string} label Correct label the selected volume should have.
- * @param {string} path Correct path the selected volume should have.
- * @return {boolean} True for success.
- */
-test.util.sync.checkSelectedVolume = function(contentWindow, label, path) {
-  var list = contentWindow.document.querySelector('#navigation-list');
-  var rows = list.querySelectorAll('li');
-  var selected = [];
-  for (var i = 0; i < rows.length; ++i) {
-    if (rows[i].hasAttribute('selected'))
-      selected.push(rows[i]);
-  }
-  // Selected item must be one.
-  if (selected.length !== 1)
-    return false;
-
-  if (selected[0].modelItem.path !== path ||
-      selected[0].querySelector('.root-label').textContent !== label) {
-    return false;
-  }
-
-  return true;
-};
-
-/**
- * Waits until the window is set to the specified dimensions.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {number} width Requested width.
- * @param {number} height Requested height.
- * @param {function(Object)} callback Success callback with the dimensions.
- */
-test.util.async.waitForWindowGeometry = function(
-    contentWindow, width, height, callback) {
-  test.util.repeatUntilTrue_(function() {
-    if (contentWindow.innerWidth == width &&
-        contentWindow.innerHeight == height) {
-      callback({width: width, height: height});
-      return true;
-    }
-    return false;
-  });
-};
-
-/**
- * Waits for an element and returns it as an array of it's attributes.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {?string} iframeQuery Iframe selector or null if no iframe.
- * @param {boolean=} opt_inverse True if the function should return if the
- *    element disappears, instead of appearing.
- * @param {function(Object)} callback Callback with a hash array of attributes
- *     and contents as text.
- */
-test.util.async.waitForElement = function(
-    contentWindow, targetQuery, iframeQuery, opt_inverse, callback) {
-  test.util.repeatUntilTrue_(function() {
-    var doc = test.util.sync.getDocument_(contentWindow, iframeQuery);
-    if (!doc)
-      return false;
-    var element = doc.querySelector(targetQuery);
-    if (!element)
-      return !!opt_inverse;
-    var attributes = {};
-    for (var i = 0; i < element.attributes.length; i++) {
-      attributes[element.attributes[i].nodeName] =
-          element.attributes[i].nodeValue;
-    }
-    var text = element.textContent;
-    callback({attributes: attributes, text: text});
-    return !opt_inverse;
-  });
-};
-
-/**
- * Calls getFileList until the number of displayed files is different from
- * lengthBefore.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {number} lengthBefore Number of items visible before.
- * @param {function(Array.<Array.<string>>)} callback Change callback.
- */
-test.util.async.waitForFileListChange = function(
-    contentWindow, lengthBefore, callback) {
-  test.util.repeatUntilTrue_(function() {
-    var files = test.util.sync.getFileList(contentWindow);
-    files.sort();
-    var notReadyRows = files.filter(function(row) {
-      return row.filter(function(cell) { return cell == '...'; }).length;
-    });
-    if (notReadyRows.length === 0 &&
-        files.length !== lengthBefore &&
-        files.length !== 0) {
-      callback(files);
-      return true;
-    } else {
-      return false;
-    }
-  });
-};
-
-/**
- * Returns an array of items on the file manager's autocomplete list.
- *
- * @param {Window} contentWindow Window to be tested.
- * @return {Array.<string>} Array of items.
- */
-test.util.sync.getAutocompleteList = function(contentWindow) {
-  var list = contentWindow.document.querySelector('#autocomplete-list');
-  var lines = list.querySelectorAll('li');
-  var items = [];
-  for (var j = 0; j < lines.length; ++j) {
-    var line = lines[j];
-    items.push(line.innerText);
-  }
-  return items;
-};
-
-/**
- * Performs autocomplete with the given query and waits until at least
- * |numExpectedItems| items are shown, including the first item which
- * always looks like "'<query>' - search Drive".
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} query Query used for autocomplete.
- * @param {number} numExpectedItems number of items to be shown.
- * @param {function(Array.<string>)} callback Change callback.
- */
-test.util.async.performAutocompleteAndWait = function(
-    contentWindow, query, numExpectedItems, callback) {
-  // Dispatch a 'focus' event to the search box so that the autocomplete list
-  // is attached to the search box. Note that calling searchBox.focus() won't
-  // dispatch a 'focus' event.
-  var searchBox = contentWindow.document.querySelector('#search-box input');
-  var focusEvent = contentWindow.document.createEvent('Event');
-  focusEvent.initEvent('focus', true /* bubbles */, true /* cancelable */);
-  searchBox.dispatchEvent(focusEvent);
-
-  // Change the value of the search box and dispatch an 'input' event so that
-  // the autocomplete query is processed.
-  searchBox.value = query;
-  var inputEvent = contentWindow.document.createEvent('Event');
-  inputEvent.initEvent('input', true /* bubbles */, true /* cancelable */);
-  searchBox.dispatchEvent(inputEvent);
-
-  test.util.repeatUntilTrue_(function() {
-    var items = test.util.sync.getAutocompleteList(contentWindow);
-    if (items.length >= numExpectedItems) {
-      callback(items);
-      return true;
-    } else {
-      return false;
-    }
-  });
-};
-
-/**
- * Waits until a dialog with an OK button is shown and accepts it.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {function()} callback Success callback.
- */
-test.util.async.waitAndAcceptDialog = function(contentWindow, callback) {
-  test.util.repeatUntilTrue_(function() {
-    var button = contentWindow.document.querySelector('.cr-dialog-ok');
-    if (!button)
-      return false;
-    button.click();
-    // Wait until the dialog is removed from the DOM.
-    test.util.repeatUntilTrue_(function() {
-      if (contentWindow.document.querySelector('.cr-dialog-container'))
-        return false;
-      callback();
-      return true;
-    });
-    return true;
-  });
-};
-
-/**
- * Fakes pressing the down arrow until the given |filename| is selected.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} filename Name of the file to be selected.
- * @return {boolean} True if file got selected, false otherwise.
- */
-test.util.sync.selectFile = function(contentWindow, filename) {
-  var table = contentWindow.document.querySelector('#detail-table');
-  var rows = table.querySelectorAll('li');
-  for (var index = 0; index < rows.length; ++index) {
-    test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'Down', false);
-    var selection = test.util.sync.getSelectedFiles(contentWindow);
-    if (selection.length === 1 && selection[0] === filename)
-      return true;
-  }
-  console.error('Failed to select file "' + filename + '"');
-  return false;
-};
-
-/**
- * Open the file by selectFile and fakeMouseDoubleClick.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} filename Name of the file to be opened.
- * @return {boolean} True if file got selected and a double click message is
- *     sent, false otherwise.
- */
-test.util.sync.openFile = function(contentWindow, filename) {
-  var query = '#file-list li.table-row[selected] .filename-label span';
-  return test.util.sync.selectFile(contentWindow, filename) &&
-         test.util.sync.fakeMouseDoubleClick(contentWindow, query);
-};
-
-/**
- * Selects a volume specified by its icon name
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} iconName Name of the volume icon.
- * @param {function(boolean)} callback Callback function to notify the caller
- *     whether the target is found and mousedown and click events are sent.
- */
-test.util.async.selectVolume = function(contentWindow, iconName, callback) {
-  var query = '[volume-type-icon=' + iconName + ']';
-  var driveQuery = '[volume-type-icon=drive]';
-  var isDriveSubVolume = iconName == 'drive_recent' ||
-                         iconName == 'drive_shared_with_me' ||
-                         iconName == 'drive_offline';
-  var preSelection = false;
-  var steps = {
-    checkQuery: function() {
-      if (contentWindow.document.querySelector(query)) {
-        steps.sendEvents();
-        return;
-      }
-      // If the target volume is sub-volume of drive, we must click 'drive'
-      // before clicking the sub-item.
-      if (!preSelection) {
-        if (!isDriveSubVolume) {
-          callback(false);
-          return;
-        }
-        if (!(test.util.sync.fakeMouseDown(contentWindow, driveQuery) &&
-              test.util.sync.fakeMouseClick(contentWindow, driveQuery))) {
-          callback(false);
-          return;
-        }
-        preSelection = true;
-      }
-      setTimeout(steps.checkQuery, 50);
-    },
-    sendEvents: function() {
-      // To change the selected volume, we have to send both events 'mousedown'
-      // and 'click' to the navigation list.
-      callback(test.util.sync.fakeMouseDown(contentWindow, query) &&
-               test.util.sync.fakeMouseClick(contentWindow, query));
-    }
-  };
-  steps.checkQuery();
-};
-
-/**
- * Waits the contents of file list becomes to equal to expected contents.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {Array.<Array.<string>>} expected Expected contents of file list.
- * @param {{orderCheck:boolean=, ignoreLastModifiedTime:boolean=}=} opt_options
- *     Options of the comparison. If orderCheck is true, it also compares the
- *     order of files. If ignoreLastModifiedTime is true, it compares the file
- *     without its last modified time.
- * @param {function()} callback Callback function to notify the caller that
- *     expected files turned up.
- */
-test.util.async.waitForFiles = function(
-    contentWindow, expected, opt_options, callback) {
-  var options = opt_options || {};
-  test.util.repeatUntilTrue_(function() {
-    var files = test.util.sync.getFileList(contentWindow);
-    if (!options.orderCheck) {
-      files.sort();
-      expected.sort();
-    }
-    if (options.ignoreLastModifiedTime) {
-      for (var i = 0; i < Math.min(files.length, expected.length); i++) {
-        files[i][3] = '';
-        expected[i][3] = '';
-      }
-    }
-    if (chrome.test.checkDeepEq(expected, files)) {
-      callback(true);
-      return true;
-    }
-    return false;
-  });
-};
-
-/**
- * Executes Javascript code on a webview and returns the result.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} webViewQuery Selector for the web view.
- * @param {string} code Javascript code to be executed within the web view.
- * @param {function(*)} callback Callback function with results returned by the
- *     script.
- */
-test.util.async.executeScriptInWebView = function(
-    contentWindow, webViewQuery, code, callback) {
-  var webView = contentWindow.document.querySelector(webViewQuery);
-  webView.executeScript({code: code}, callback);
-};
-
-/**
- * Sends an event to the element specified by |targetQuery|.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {Event} event Event to be sent.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.sendEvent = function(
-    contentWindow, targetQuery, event, opt_iframeQuery) {
-  var doc = test.util.sync.getDocument_(contentWindow, opt_iframeQuery);
-  if (doc) {
-    var target = doc.querySelector(targetQuery);
-    if (target) {
-      target.dispatchEvent(event);
-      return true;
-    }
-  }
-  console.error('Target element for ' + targetQuery + ' not found.');
-  return false;
-};
-
-/**
- * Sends an fake event having the specified type to the target query.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string} event Type of event.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeEvent = function(contentWindow, targetQuery, event) {
-  return test.util.sync.sendEvent(
-      contentWindow, targetQuery, new Event(event));
-};
-
-/**
- * Sends a fake key event to the element specified by |targetQuery| with the
- * given |keyIdentifier| and optional |ctrl| modifier to the file manager.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string} keyIdentifier Identifier of the emulated key.
- * @param {boolean} ctrl Whether CTRL should be pressed, or not.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeKeyDown = function(
-    contentWindow, targetQuery, keyIdentifier, ctrl, opt_iframeQuery) {
-  var event = new KeyboardEvent(
-      'keydown',
-      { bubbles: true, keyIdentifier: keyIdentifier, ctrlKey: ctrl });
-  return test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery);
-};
-
-/**
- * Sends a fake mouse click event (left button, single click) to the element
- * specified by |targetQuery|.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeMouseClick = function(
-    contentWindow, targetQuery, opt_iframeQuery) {
-  var event = new MouseEvent('click', { bubbles: true, detail: 1 });
-  return test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery);
-};
-
-/**
- * Simulates a fake double click event (left button) to the element specified by
- * |targetQuery|.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeMouseDoubleClick = function(
-    contentWindow, targetQuery, opt_iframeQuery) {
-  // Double click is always preceded with a single click.
-  if (!test.util.sync.fakeMouseClick(
-      contentWindow, targetQuery, opt_iframeQuery)) {
-    return false;
-  }
-
-  // Send the second click event, but with detail equal to 2 (number of clicks)
-  // in a row.
-  var event = new MouseEvent('click', { bubbles: true, detail: 2 });
-  if (!test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery)) {
-    return false;
-  }
-
-  // Send the double click event.
-  var event = new MouseEvent('dblclick', { bubbles: true });
-  if (!test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery)) {
-    return false;
-  }
-
-  return true;
-};
-
-/**
- * Sends a fake mouse down event to the element specified by |targetQuery|.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeMouseDown = function(
-    contentWindow, targetQuery, opt_iframeQuery) {
-  var event = new MouseEvent('mousedown', { bubbles: true });
-  return test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery);
-};
-
-/**
- * Sends a fake mouse up event to the element specified by |targetQuery|.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} targetQuery Query to specify the element.
- * @param {string=} opt_iframeQuery Optional iframe selector.
- * @return {boolean} True if the event is sent to the target, false otherwise.
- */
-test.util.sync.fakeMouseUp = function(
-    contentWindow, targetQuery, opt_iframeQuery) {
-  var event = new MouseEvent('mouseup', { bubbles: true });
-  return test.util.sync.sendEvent(
-      contentWindow, targetQuery, event, opt_iframeQuery);
-};
-
-/**
- * Selects |filename| and fakes pressing Ctrl+C, Ctrl+V (copy, paste).
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} filename Name of the file to be copied.
- * @return {boolean} True if copying got simulated successfully. It does not
- *     say if the file got copied, or not.
- */
-test.util.sync.copyFile = function(contentWindow, filename) {
-  if (!test.util.sync.selectFile(contentWindow, filename))
-    return false;
-  // Ctrl+C and Ctrl+V
-  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0043', true);
-  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+0056', true);
-  return true;
-};
-
-/**
- * Selects |filename| and fakes pressing the Delete key.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} filename Name of the file to be deleted.
- * @return {boolean} True if deleting got simulated successfully. It does not
- *     say if the file got deleted, or not.
- */
-test.util.sync.deleteFile = function(contentWindow, filename) {
-  if (!test.util.sync.selectFile(contentWindow, filename))
-    return false;
-  // Delete
-  test.util.sync.fakeKeyDown(contentWindow, '#file-list', 'U+007F', false);
-  return true;
-};
-
-/**
- * Wait for the elements' style to be changed as the expected values.  The
- * queries argument is a list of object that have the query property and the
- * styles property. The query property is a string query to specify the
- * element. The styles property is a string map of the style name and its
- * expected value.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {Array.<object>} queries Queries that specifies the elements and
- *   expected styles.
- * @param {function()} callback Callback function to be notified the change of
- *     the styles.
- */
-test.util.async.waitForStyles = function(contentWindow, queries, callback) {
-  test.util.repeatUntilTrue_(function() {
-    for (var i = 0; i < queries.length; i++) {
-      var element = contentWindow.document.querySelector(queries[i].query);
-      var styles = queries[i].styles;
-      for (var name in styles) {
-        if (contentWindow.getComputedStyle(element)[name] != styles[name])
-          return false;
-      }
-    }
-    callback();
-    return true;
-  });
-};
-
-/**
- * Execute a command on the document in the specified window.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} command Command name.
- * @return {boolean} True if the command is executed successfully.
- */
-test.util.sync.execCommand = function(contentWindow, command) {
-  return contentWindow.document.execCommand(command);
-};
-
-/**
- * Registers message listener, which runs test utility functions.
- */
-test.util.registerRemoteTestUtils = function() {
-  // Register the message listener.
-  var onMessage = chrome.runtime ? chrome.runtime.onMessageExternal :
-      chrome.extension.onMessageExternal;
-  // Return true for asynchronous functions and false for synchronous.
-  onMessage.addListener(function(request, sender, sendResponse) {
-    // Check the sender.
-    if (sender.id != test.util.TESTING_EXTENSION_ID) {
-      console.error('The testing extension must be white-listed.');
-      return false;
-    }
-    // Set a global flag that we are in tests, so other components are aware
-    // of it.
-    window.IN_TEST = true;
-    // Check the function name.
-    if (!request.func || request.func[request.func.length - 1] == '_') {
-      request.func = '';
-    }
-    // Prepare arguments.
-    var args = request.args.slice();  // shallow copy
-    if (request.appId) {
-      if (!appWindows[request.appId]) {
-        console.error('Specified window not found.');
-        return false;
-      }
-      args.unshift(appWindows[request.appId].contentWindow);
-    }
-    // Call the test utility function and respond the result.
-    if (test.util.async[request.func]) {
-      args[test.util.async[request.func].length - 1] = function() {
-        console.debug('Received the result of ' + request.func);
-        sendResponse.apply(null, arguments);
-      };
-      console.debug('Waiting for the result of ' + request.func);
-      test.util.async[request.func].apply(null, args);
-      return true;
-    } else if (test.util.sync[request.func]) {
-      sendResponse(test.util.sync[request.func].apply(null, args));
-      return false;
-    } else {
-      console.error('Invalid function name.');
-      return false;
-    }
-  });
-};
-
-// Register the test utils.
-test.util.registerRemoteTestUtils();
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
deleted file mode 100644
index 9f6e88f..0000000
--- a/chrome/browser/resources/file_manager/js/util.js
+++ /dev/null
@@ -1,1212 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Namespace for utility functions.
- */
-var util = {};
-
-/**
- * Returns a function that console.log's its arguments, prefixed by |msg|.
- *
- * @param {string} msg The message prefix to use in the log.
- * @param {function(...string)=} opt_callback A function to invoke after
- *     logging.
- * @return {function(...string)} Function that logs.
- */
-util.flog = function(msg, opt_callback) {
-  return function() {
-    var ary = Array.apply(null, arguments);
-    console.log(msg + ': ' + ary.join(', '));
-    if (opt_callback)
-      opt_callback.apply(null, arguments);
-  };
-};
-
-/**
- * Returns a function that throws an exception that includes its arguments
- * prefixed by |msg|.
- *
- * @param {string} msg The message prefix to use in the exception.
- * @return {function(...string)} Function that throws.
- */
-util.ferr = function(msg) {
-  return function() {
-    var ary = Array.apply(null, arguments);
-    throw new Error(msg + ': ' + ary.join(', '));
-  };
-};
-
-/**
- * Install a sensible toString() on the FileError object.
- *
- * FileError.prototype.code is a numeric code describing the cause of the
- * error.  The FileError constructor has a named property for each possible
- * error code, but provides no way to map the code to the named property.
- * This toString() implementation fixes that.
- */
-util.installFileErrorToString = function() {
-  FileError.prototype.toString = function() {
-    return '[object FileError: ' + util.getFileErrorMnemonic(this.code) + ']';
-  };
-};
-
-/**
- * @param {number} code The file error code.
- * @return {string} The file error mnemonic.
- */
-util.getFileErrorMnemonic = function(code) {
-  for (var key in FileError) {
-    if (key.search(/_ERR$/) != -1 && FileError[key] == code)
-      return key;
-  }
-
-  return code;
-};
-
-/**
- * @param {number} code File error code (from FileError object).
- * @return {string} Translated file error string.
- */
-util.getFileErrorString = function(code) {
-  for (var key in FileError) {
-    var match = /(.*)_ERR$/.exec(key);
-    if (match && FileError[key] == code) {
-      // This would convert 1 to 'NOT_FOUND'.
-      code = match[1];
-      break;
-    }
-  }
-  console.warn('File error: ' + code);
-  return loadTimeData.getString('FILE_ERROR_' + code) ||
-      loadTimeData.getString('FILE_ERROR_GENERIC');
-};
-
-/**
- * @param {string} str String to escape.
- * @return {string} Escaped string.
- */
-util.htmlEscape = function(str) {
-  return str.replace(/[<>&]/g, function(entity) {
-    switch (entity) {
-      case '<': return '&lt;';
-      case '>': return '&gt;';
-      case '&': return '&amp;';
-    }
-  });
-};
-
-/**
- * @param {string} str String to unescape.
- * @return {string} Unescaped string.
- */
-util.htmlUnescape = function(str) {
-  return str.replace(/&(lt|gt|amp);/g, function(entity) {
-    switch (entity) {
-      case '&lt;': return '<';
-      case '&gt;': return '>';
-      case '&amp;': return '&';
-    }
-  });
-};
-
-/**
- * Iterates the entries contained by dirEntry, and invokes callback once for
- * each entry. On completion, successCallback will be invoked.
- *
- * @param {DirectoryEntry} dirEntry The entry of the directory.
- * @param {function(Entry, function())} callback Invoked for each entry.
- * @param {function()} successCallback Invoked on completion.
- * @param {function(FileError)} errorCallback Invoked if an error is found on
- *     directory entry reading.
- */
-util.forEachDirEntry = function(
-    dirEntry, callback, successCallback, errorCallback) {
-  var reader = dirEntry.createReader();
-  var iterate = function() {
-    reader.readEntries(function(entries) {
-      if (entries.length == 0) {
-        successCallback();
-        return;
-      }
-
-      AsyncUtil.forEach(
-          entries,
-          function(forEachCallback, entry) {
-            // Do not pass index nor entries.
-            callback(entry, forEachCallback);
-          },
-          iterate);
-    }, errorCallback);
-  };
-  iterate();
-};
-
-/**
- * Reads contents of directory.
- * @param {DirectoryEntry} root Root entry.
- * @param {string} path Directory path.
- * @param {function(Array.<Entry>)} callback List of entries passed to callback.
- */
-util.readDirectory = function(root, path, callback) {
-  var onError = function(e) {
-    callback([], e);
-  };
-  root.getDirectory(path, {create: false}, function(entry) {
-    var reader = entry.createReader();
-    var r = [];
-    var readNext = function() {
-      reader.readEntries(function(results) {
-        if (results.length == 0) {
-          callback(r, null);
-          return;
-        }
-        r.push.apply(r, results);
-        readNext();
-      }, onError);
-    };
-    readNext();
-  }, onError);
-};
-
-/**
- * Utility function to resolve multiple directories with a single call.
- *
- * The successCallback will be invoked once for each directory object
- * found.  The errorCallback will be invoked once for each
- * path that could not be resolved.
- *
- * The successCallback is invoked with a null entry when all paths have
- * been processed.
- *
- * @param {DirEntry} dirEntry The base directory.
- * @param {Object} params The parameters to pass to the underlying
- *     getDirectory calls.
- * @param {Array.<string>} paths The list of directories to resolve.
- * @param {function(!DirEntry)} successCallback The function to invoke for
- *     each DirEntry found.  Also invoked once with null at the end of the
- *     process.
- * @param {function(FileError)} errorCallback The function to invoke
- *     for each path that cannot be resolved.
- */
-util.getDirectories = function(dirEntry, params, paths, successCallback,
-                               errorCallback) {
-
-  // Copy the params array, since we're going to destroy it.
-  params = [].slice.call(params);
-
-  var onComplete = function() {
-    successCallback(null);
-  };
-
-  var getNextDirectory = function() {
-    var path = paths.shift();
-    if (!path)
-      return onComplete();
-
-    dirEntry.getDirectory(
-      path, params,
-      function(entry) {
-        successCallback(entry);
-        getNextDirectory();
-      },
-      function(err) {
-        errorCallback(err);
-        getNextDirectory();
-      });
-  };
-
-  getNextDirectory();
-};
-
-/**
- * Utility function to resolve multiple files with a single call.
- *
- * The successCallback will be invoked once for each directory object
- * found.  The errorCallback will be invoked once for each
- * path that could not be resolved.
- *
- * The successCallback is invoked with a null entry when all paths have
- * been processed.
- *
- * @param {DirEntry} dirEntry The base directory.
- * @param {Object} params The parameters to pass to the underlying
- *     getFile calls.
- * @param {Array.<string>} paths The list of files to resolve.
- * @param {function(!FileEntry)} successCallback The function to invoke for
- *     each FileEntry found.  Also invoked once with null at the end of the
- *     process.
- * @param {function(FileError)} errorCallback The function to invoke
- *     for each path that cannot be resolved.
- */
-util.getFiles = function(dirEntry, params, paths, successCallback,
-                         errorCallback) {
-  // Copy the params array, since we're going to destroy it.
-  params = [].slice.call(params);
-
-  var onComplete = function() {
-    successCallback(null);
-  };
-
-  var getNextFile = function() {
-    var path = paths.shift();
-    if (!path)
-      return onComplete();
-
-    dirEntry.getFile(
-      path, params,
-      function(entry) {
-        successCallback(entry);
-        getNextFile();
-      },
-      function(err) {
-        errorCallback(err);
-        getNextFile();
-      });
-  };
-
-  getNextFile();
-};
-
-/**
- * Resolve a path to either a DirectoryEntry or a FileEntry, regardless of
- * whether the path is a directory or file.
- *
- * @param {DirectoryEntry} root The root of the filesystem to search.
- * @param {string} path The path to be resolved.
- * @param {function(Entry)} resultCallback Called back when a path is
- *     successfully resolved. Entry will be either a DirectoryEntry or
- *     a FileEntry.
- * @param {function(FileError)} errorCallback Called back if an unexpected
- *     error occurs while resolving the path.
- */
-util.resolvePath = function(root, path, resultCallback, errorCallback) {
-  if (path == '' || path == '/') {
-    resultCallback(root);
-    return;
-  }
-
-  root.getFile(
-      path, {create: false},
-      resultCallback,
-      function(err) {
-        if (err.code == FileError.TYPE_MISMATCH_ERR) {
-          // Bah.  It's a directory, ask again.
-          root.getDirectory(
-              path, {create: false},
-              resultCallback,
-              errorCallback);
-        } else {
-          errorCallback(err);
-        }
-      });
-};
-
-/**
- * Locate the file referred to by path, creating directories or the file
- * itself if necessary.
- * @param {DirEntry} root The root entry.
- * @param {string} path The file path.
- * @param {function(FileEntry)} successCallback The callback.
- * @param {function(FileError)} errorCallback The callback.
- */
-util.getOrCreateFile = function(root, path, successCallback, errorCallback) {
-  var dirname = null;
-  var basename = null;
-
-  var onDirFound = function(dirEntry) {
-    dirEntry.getFile(basename, { create: true },
-                     successCallback, errorCallback);
-  };
-
-  var i = path.lastIndexOf('/');
-  if (i > -1) {
-    dirname = path.substr(0, i);
-    basename = path.substr(i + 1);
-  } else {
-    basename = path;
-  }
-
-  if (!dirname) {
-    onDirFound(root);
-    return;
-  }
-
-  util.getOrCreateDirectory(root, dirname, onDirFound, errorCallback);
-};
-
-/**
- * Locate the directory referred to by path, creating directories along the
- * way.
- * @param {DirEntry} root The root entry.
- * @param {string} path The directory path.
- * @param {function(FileEntry)} successCallback The callback.
- * @param {function(FileError)} errorCallback The callback.
- */
-util.getOrCreateDirectory = function(root, path, successCallback,
-                                     errorCallback) {
-  var names = path.split('/');
-
-  var getOrCreateNextName = function(dir) {
-    if (!names.length)
-      return successCallback(dir);
-
-    var name;
-    do {
-      name = names.shift();
-    } while (!name || name == '.');
-
-    dir.getDirectory(name, { create: true }, getOrCreateNextName,
-                     errorCallback);
-  };
-
-  getOrCreateNextName(root);
-};
-
-/**
- * Renames the entry to newName.
- * @param {Entry} entry The entry to be renamed.
- * @param {string} newName The new name.
- * @param {function(Entry)} successCallback Callback invoked when the rename
- *     is successfully done.
- * @param {function(FileError)} errorCallback Callback invoked when an error
- *     is found.
- */
-util.rename = function(entry, newName, successCallback, errorCallback) {
-  entry.getParent(function(parent) {
-    // Before moving, we need to check if there is an existing entry at
-    // parent/newName, since moveTo will overwrite it.
-    // Note that this way has some timing issue. After existing check,
-    // a new entry may be create on background. However, there is no way not to
-    // overwrite the existing file, unfortunately. The risk should be low,
-    // assuming the unsafe period is very short.
-    (entry.isFile ? parent.getFile : parent.getDirectory).call(
-        parent, newName, {create: false},
-        function(entry) {
-          // The entry with the name already exists.
-          errorCallback(util.createFileError(FileError.PATH_EXISTS_ERR));
-        },
-        function(error) {
-          if (error.code != FileError.NOT_FOUND_ERR) {
-            // Unexpected error is found.
-            errorCallback(error);
-            return;
-          }
-
-          // No existing entry is found.
-          entry.moveTo(parent, newName, successCallback, errorCallback);
-        });
-  }, errorCallback);
-};
-
-/**
- * Remove a file or a directory.
- * @param {Entry} entry The entry to remove.
- * @param {function()} onSuccess The success callback.
- * @param {function(FileError)} onError The error callback.
- */
-util.removeFileOrDirectory = function(entry, onSuccess, onError) {
-  if (entry.isDirectory)
-    entry.removeRecursively(onSuccess, onError);
-  else
-    entry.remove(onSuccess, onError);
-};
-
-/**
- * Checks if an entry exists at |relativePath| in |dirEntry|.
- * If exists, tries to deduplicate the path by inserting parenthesized number,
- * such as " (1)", before the extension. If it still exists, tries the
- * deduplication again by increasing the number up to 10 times.
- * For example, suppose "file.txt" is given, "file.txt", "file (1).txt",
- * "file (2).txt", ..., "file (9).txt" will be tried.
- *
- * @param {DirectoryEntry} dirEntry The target directory entry.
- * @param {string} relativePath The path to be deduplicated.
- * @param {function(string)} onSuccess Called with the deduplicated path on
- *     success.
- * @param {function(FileError)} onError Called on error.
- */
-util.deduplicatePath = function(dirEntry, relativePath, onSuccess, onError) {
-  // The trial is up to 10.
-  var MAX_RETRY = 10;
-
-  // Crack the path into three part. The parenthesized number (if exists) will
-  // be replaced by incremented number for retry. For example, suppose
-  // |relativePath| is "file (10).txt", the second check path will be
-  // "file (11).txt".
-  var match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath);
-  var prefix = match[1];
-  var copyNumber = match[2] ? parseInt(match[2], 10) : 0;
-  var ext = match[3] ? match[3] : '';
-
-  // The path currently checking the existence.
-  var trialPath = relativePath;
-
-  var onNotResolved = function(err) {
-    // We expect to be unable to resolve the target file, since we're going
-    // to create it during the copy.  However, if the resolve fails with
-    // anything other than NOT_FOUND, that's trouble.
-    if (err.code != FileError.NOT_FOUND_ERR) {
-      onError(err);
-      return;
-    }
-
-    // Found a path that doesn't exist.
-    onSuccess(trialPath);
-  }
-
-  var numRetry = MAX_RETRY;
-  var onResolved = function(entry) {
-    if (--numRetry == 0) {
-      // Hit the limit of the number of retrial.
-      // Note that we cannot create FileError object directly, so here we use
-      // Object.create instead.
-      onError(util.createFileError(FileError.PATH_EXISTS_ERR));
-      return;
-    }
-
-    ++copyNumber;
-    trialPath = prefix + ' (' + copyNumber + ')' + ext;
-    util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
-  };
-
-  // Check to see if the target exists.
-  util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
-};
-
-/**
- * Convert a number of bytes into a human friendly format, using the correct
- * number separators.
- *
- * @param {number} bytes The number of bytes.
- * @return {string} Localized string.
- */
-util.bytesToString = function(bytes) {
-  // Translation identifiers for size units.
-  var UNITS = ['SIZE_BYTES',
-               'SIZE_KB',
-               'SIZE_MB',
-               'SIZE_GB',
-               'SIZE_TB',
-               'SIZE_PB'];
-
-  // Minimum values for the units above.
-  var STEPS = [0,
-               Math.pow(2, 10),
-               Math.pow(2, 20),
-               Math.pow(2, 30),
-               Math.pow(2, 40),
-               Math.pow(2, 50)];
-
-  var str = function(n, u) {
-    // TODO(rginda): Switch to v8Locale's number formatter when it's
-    // available.
-    return strf(u, n.toLocaleString());
-  };
-
-  var fmt = function(s, u) {
-    var rounded = Math.round(bytes / s * 10) / 10;
-    return str(rounded, u);
-  };
-
-  // Less than 1KB is displayed like '80 bytes'.
-  if (bytes < STEPS[1]) {
-    return str(bytes, UNITS[0]);
-  }
-
-  // Up to 1MB is displayed as rounded up number of KBs.
-  if (bytes < STEPS[2]) {
-    var rounded = Math.ceil(bytes / STEPS[1]);
-    return str(rounded, UNITS[1]);
-  }
-
-  // This loop index is used outside the loop if it turns out |bytes|
-  // requires the largest unit.
-  var i;
-
-  for (i = 2 /* MB */; i < UNITS.length - 1; i++) {
-    if (bytes < STEPS[i + 1])
-      return fmt(STEPS[i], UNITS[i]);
-  }
-
-  return fmt(STEPS[i], UNITS[i]);
-};
-
-/**
- * Utility function to read specified range of bytes from file
- * @param {File} file The file to read.
- * @param {number} begin Starting byte(included).
- * @param {number} end Last byte(excluded).
- * @param {function(File, Uint8Array)} callback Callback to invoke.
- * @param {function(FileError)} onError Error handler.
- */
-util.readFileBytes = function(file, begin, end, callback, onError) {
-  var fileReader = new FileReader();
-  fileReader.onerror = onError;
-  fileReader.onloadend = function() {
-    callback(file, new ByteReader(fileReader.result));
-  };
-  fileReader.readAsArrayBuffer(file.slice(begin, end));
-};
-
-/**
- * Write a blob to a file.
- * Truncates the file first, so the previous content is fully overwritten.
- * @param {FileEntry} entry File entry.
- * @param {Blob} blob The blob to write.
- * @param {function(Event)} onSuccess Completion callback. The first argument is
- *     a 'writeend' event.
- * @param {function(FileError)} onError Error handler.
- */
-util.writeBlobToFile = function(entry, blob, onSuccess, onError) {
-  var truncate = function(writer) {
-    writer.onerror = onError;
-    writer.onwriteend = write.bind(null, writer);
-    writer.truncate(0);
-  };
-
-  var write = function(writer) {
-    writer.onwriteend = onSuccess;
-    writer.write(blob);
-  };
-
-  entry.createWriter(truncate, onError);
-};
-
-/**
- * Returns a string '[Ctrl-][Alt-][Shift-][Meta-]' depending on the event
- * modifiers. Convenient for writing out conditions in keyboard handlers.
- *
- * @param {Event} event The keyboard event.
- * @return {string} Modifiers.
- */
-util.getKeyModifiers = function(event) {
-  return (event.ctrlKey ? 'Ctrl-' : '') +
-         (event.altKey ? 'Alt-' : '') +
-         (event.shiftKey ? 'Shift-' : '') +
-         (event.metaKey ? 'Meta-' : '');
-};
-
-/**
- * @param {HTMLElement} element Element to transform.
- * @param {Object} transform Transform object,
- *                           contains scaleX, scaleY and rotate90 properties.
- */
-util.applyTransform = function(element, transform) {
-  element.style.webkitTransform =
-      transform ? 'scaleX(' + transform.scaleX + ') ' +
-                  'scaleY(' + transform.scaleY + ') ' +
-                  'rotate(' + transform.rotate90 * 90 + 'deg)' :
-      '';
-};
-
-/**
- * Makes filesystem: URL from the path.
- * @param {string} path File or directory path.
- * @return {string} URL.
- */
-util.makeFilesystemUrl = function(path) {
-  path = path.split('/').map(encodeURIComponent).join('/');
-  var prefix = 'external';
-  return 'filesystem:' + document.location.origin + '/' + prefix + path;
-};
-
-/**
- * Extracts path from filesystem: URL.
- * @param {string} url Filesystem URL.
- * @return {string} The path.
- */
-util.extractFilePath = function(url) {
-  var match =
-      /^filesystem:[\w-]*:\/\/[\w]*\/(external|persistent|temporary)(\/.*)$/.
-      exec(url);
-  var path = match && match[2];
-  if (!path) return null;
-  return decodeURIComponent(path);
-};
-
-/**
- * Traverses a directory tree whose root is the given entry, and invokes
- * callback for each entry. Upon completion, successCallback will be called.
- * On error, errorCallback will be called.
- *
- * @param {Entry} entry The root entry.
- * @param {function(Entry):boolean} callback Callback invoked for each entry.
- *     If this returns false, entries under it won't be traversed. Note that
- *     its siblings (and their children) will be still traversed.
- * @param {function()} successCallback Called upon successful completion.
- * @param {function(error)} errorCallback Called upon error.
- */
-util.traverseTree = function(entry, callback, successCallback, errorCallback) {
-  if (!callback(entry)) {
-    successCallback();
-    return;
-  }
-
-  util.forEachDirEntry(
-      entry,
-      function(child, iterationCallback) {
-        util.traverseTree(child, callback, iterationCallback, errorCallback);
-      },
-      successCallback,
-      errorCallback);
-};
-
-/**
- * A shortcut function to create a child element with given tag and class.
- *
- * @param {HTMLElement} parent Parent element.
- * @param {string=} opt_className Class name.
- * @param {string=} opt_tag Element tag, DIV is omitted.
- * @return {Element} Newly created element.
- */
-util.createChild = function(parent, opt_className, opt_tag) {
-  var child = parent.ownerDocument.createElement(opt_tag || 'div');
-  if (opt_className)
-    child.className = opt_className;
-  parent.appendChild(child);
-  return child;
-};
-
-/**
- * Update the app state.
- *
- * @param {string} path Path to be put in the address bar after the hash.
- *   If null the hash is left unchanged.
- * @param {string|Object=} opt_param Search parameter. Used directly if string,
- *   stringified if object. If omitted the search query is left unchanged.
- */
-util.updateAppState = function(path, opt_param) {
-  window.appState = window.appState || {};
-  if (typeof opt_param == 'string')
-    window.appState.params = {};
-  else if (typeof opt_param == 'object')
-    window.appState.params = opt_param;
-  if (path)
-    window.appState.defaultPath = path;
-  util.saveAppState();
-  return;
-};
-
-/**
- * Return a translated string.
- *
- * Wrapper function to make dealing with translated strings more concise.
- * Equivalent to loadTimeData.getString(id).
- *
- * @param {string} id The id of the string to return.
- * @return {string} The translated string.
- */
-function str(id) {
-  return loadTimeData.getString(id);
-}
-
-/**
- * Return a translated string with arguments replaced.
- *
- * Wrapper function to make dealing with translated strings more concise.
- * Equivalent to loadTimeData.getStringF(id, ...).
- *
- * @param {string} id The id of the string to return.
- * @param {...string} var_args The values to replace into the string.
- * @return {string} The translated string with replaced values.
- */
-function strf(id, var_args) {
-  return loadTimeData.getStringF.apply(loadTimeData, arguments);
-}
-
-/**
- * Adapter object that abstracts away the the difference between Chrome app APIs
- * v1 and v2. Is only necessary while the migration to v2 APIs is in progress.
- * TODO(mtomasz): Clean up this. crbug.com/240606.
- */
-util.platform = {
-  /**
-   * @return {boolean} True if Files.app is running as an open files or a select
-   *     folder dialog. False otherwise.
-   */
-  runningInBrowser: function() {
-    return !window.appID;
-  },
-
-  /**
-   * @param {function(Object)} callback Function accepting a preference map.
-   */
-  getPreferences: function(callback) {
-    chrome.storage.local.get(callback);
-  },
-
-  /**
-   * @param {string} key Preference name.
-   * @param {function(string)} callback Function accepting the preference value.
-   */
-  getPreference: function(key, callback) {
-    chrome.storage.local.get(key, function(items) {
-      callback(items[key]);
-    });
-  },
-
-  /**
-   * @param {string} key Preference name.
-   * @param {string|Object} value Preference value.
-   * @param {function()=} opt_callback Completion callback.
-   */
-  setPreference: function(key, value, opt_callback) {
-    if (typeof value != 'string')
-      value = JSON.stringify(value);
-
-    var items = {};
-    items[key] = value;
-    chrome.storage.local.set(items, opt_callback);
-  }
-};
-
-/**
- * Attach page load handler.
- * @param {function()} handler Application-specific load handler.
- */
-util.addPageLoadHandler = function(handler) {
-  document.addEventListener('DOMContentLoaded', function() {
-    handler();
-  });
-};
-
-/**
- * Save app launch data to the local storage.
- */
-util.saveAppState = function() {
-  if (window.appState)
-    util.platform.setPreference(window.appID, window.appState);
-};
-
-/**
- *  AppCache is a persistent timestamped key-value storage backed by
- *  HTML5 local storage.
- *
- *  It is not designed for frequent access. In order to avoid costly
- *  localStorage iteration all data is kept in a single localStorage item.
- *  There is no in-memory caching, so concurrent access is _almost_ safe.
- *
- *  TODO(kaznacheev) Reimplement this based on Indexed DB.
- */
-util.AppCache = function() {};
-
-/**
- * Local storage key.
- */
-util.AppCache.KEY = 'AppCache';
-
-/**
- * Max number of items.
- */
-util.AppCache.CAPACITY = 100;
-
-/**
- * Default lifetime.
- */
-util.AppCache.LIFETIME = 30 * 24 * 60 * 60 * 1000;  // 30 days.
-
-/**
- * @param {string} key Key.
- * @param {function(number)} callback Callback accepting a value.
- */
-util.AppCache.getValue = function(key, callback) {
-  util.AppCache.read_(function(map) {
-    var entry = map[key];
-    callback(entry && entry.value);
-  });
-};
-
-/**
- * Update the cache.
- *
- * @param {string} key Key.
- * @param {string} value Value. Remove the key if value is null.
- * @param {number=} opt_lifetime Maximum time to keep an item (in milliseconds).
- */
-util.AppCache.update = function(key, value, opt_lifetime) {
-  util.AppCache.read_(function(map) {
-    if (value != null) {
-      map[key] = {
-        value: value,
-        expire: Date.now() + (opt_lifetime || util.AppCache.LIFETIME)
-      };
-    } else if (key in map) {
-      delete map[key];
-    } else {
-      return;  // Nothing to do.
-    }
-    util.AppCache.cleanup_(map);
-    util.AppCache.write_(map);
-  });
-};
-
-/**
- * @param {function(Object)} callback Callback accepting a map of timestamped
- *   key-value pairs.
- * @private
- */
-util.AppCache.read_ = function(callback) {
-  util.platform.getPreference(util.AppCache.KEY, function(json) {
-    if (json) {
-      try {
-        callback(JSON.parse(json));
-      } catch (e) {
-        // The local storage item somehow got messed up, start fresh.
-      }
-    }
-    callback({});
-  });
-};
-
-/**
- * @param {Object} map A map of timestamped key-value pairs.
- * @private
- */
-util.AppCache.write_ = function(map) {
-  util.platform.setPreference(util.AppCache.KEY, JSON.stringify(map));
-};
-
-/**
- * Remove over-capacity and obsolete items.
- *
- * @param {Object} map A map of timestamped key-value pairs.
- * @private
- */
-util.AppCache.cleanup_ = function(map) {
-  // Sort keys by ascending timestamps.
-  var keys = [];
-  for (var key in map) {
-    if (map.hasOwnProperty(key))
-      keys.push(key);
-  }
-  keys.sort(function(a, b) { return map[a].expire > map[b].expire });
-
-  var cutoff = Date.now();
-
-  var obsolete = 0;
-  while (obsolete < keys.length &&
-         map[keys[obsolete]].expire < cutoff) {
-    obsolete++;
-  }
-
-  var overCapacity = Math.max(0, keys.length - util.AppCache.CAPACITY);
-
-  var itemsToDelete = Math.max(obsolete, overCapacity);
-  for (var i = 0; i != itemsToDelete; i++) {
-    delete map[keys[i]];
-  }
-};
-
-/**
- * Load an image.
- *
- * @param {Image} image Image element.
- * @param {string} url Source url.
- * @param {Object=} opt_options Hash array of options, eg. width, height,
- *     maxWidth, maxHeight, scale, cache.
- * @param {function()=} opt_isValid Function returning false iff the task
- *     is not valid and should be aborted.
- * @return {?number} Task identifier or null if fetched immediately from
- *     cache.
- */
-util.loadImage = function(image, url, opt_options, opt_isValid) {
-  return ImageLoaderClient.loadToImage(url,
-                                      image,
-                                      opt_options || {},
-                                      function() {},
-                                      function() { image.onerror(); },
-                                      opt_isValid);
-};
-
-/**
- * Cancels loading an image.
- * @param {number} taskId Task identifier returned by util.loadImage().
- */
-util.cancelLoadImage = function(taskId) {
-  ImageLoaderClient.getInstance().cancel(taskId);
-};
-
-/**
- * Finds proerty descriptor in the object prototype chain.
- * @param {Object} object The object.
- * @param {string} propertyName The property name.
- * @return {Object} Property descriptor.
- */
-util.findPropertyDescriptor = function(object, propertyName) {
-  for (var p = object; p; p = Object.getPrototypeOf(p)) {
-    var d = Object.getOwnPropertyDescriptor(p, propertyName);
-    if (d)
-      return d;
-  }
-  return null;
-};
-
-/**
- * Calls inherited property setter (useful when property is
- * overriden).
- * @param {Object} object The object.
- * @param {string} propertyName The property name.
- * @param {*} value Value to set.
- */
-util.callInheritedSetter = function(object, propertyName, value) {
-  var d = util.findPropertyDescriptor(Object.getPrototypeOf(object),
-                                      propertyName);
-  d.set.call(object, value);
-};
-
-/**
- * Returns true if the board of the device matches the given prefix.
- * @param {string} boardPrefix The board prefix to match against.
- *     (ex. "x86-mario". Prefix is used as the actual board name comes with
- *     suffix like "x86-mario-something".
- * @return {boolean} True if the board of the device matches the given prefix.
- */
-util.boardIs = function(boardPrefix) {
-  // The board name should be lower-cased, but making it case-insensitive for
-  // backward compatibility just in case.
-  var board = str('CHROMEOS_RELEASE_BOARD');
-  var pattern = new RegExp('^' + boardPrefix, 'i');
-  return board.match(pattern) != null;
-};
-
-/**
- * Adds an isFocused method to the current window object.
- */
-util.addIsFocusedMethod = function() {
-  var focused = true;
-
-  window.addEventListener('focus', function() {
-    focused = true;
-  });
-
-  window.addEventListener('blur', function() {
-    focused = false;
-  });
-
-  /**
-   * @return {boolean} True if focused.
-   */
-  window.isFocused = function() {
-    return focused;
-  };
-};
-
-/**
- * Makes a redirect to the specified Files.app's window from another window.
- * @param {number} id Window id.
- * @param {string} url Target url.
- * @return {boolean} True if the window has been found. False otherwise.
- */
-util.redirectMainWindow = function(id, url) {
-  // TODO(mtomasz): Implement this for Apps V2, once the photo importer is
-  // restored.
-  return false;
-};
-
-/**
- * Checks, if the Files.app's window is in a full screen mode.
- *
- * @param {AppWindow} appWindow App window to be maximized.
- * @return {boolean} True if the full screen mode is enabled.
- */
-util.isFullScreen = function(appWindow) {
-  if (appWindow) {
-    return appWindow.isFullscreen();
-  } else {
-    console.error('App window not passed. Unable to check status of ' +
-                  'the full screen mode.');
-    return false;
-  }
-};
-
-/**
- * Toggles the full screen mode.
- *
- * @param {AppWindow} appWindow App window to be maximized.
- * @param {boolean} enabled True for enabling, false for disabling.
- */
-util.toggleFullScreen = function(appWindow, enabled) {
-  if (appWindow) {
-    if (enabled)
-      appWindow.fullscreen();
-    else
-      appWindow.restore();
-    return;
-  }
-
-  console.error(
-      'App window not passed. Unable to toggle the full screen mode.');
-};
-
-/**
- * The type of a file operation.
- * @enum {string}
- */
-util.FileOperationType = {
-  COPY: 'COPY',
-  MOVE: 'MOVE',
-  ZIP: 'ZIP',
-};
-
-/**
- * The type of a file operation error.
- * @enum {number}
- */
-util.FileOperationErrorType = {
-  UNEXPECTED_SOURCE_FILE: 0,
-  TARGET_EXISTS: 1,
-  FILESYSTEM_ERROR: 2,
-};
-
-/**
- * The kind of an entry changed event.
- * @enum {number}
- */
-util.EntryChangedKind = {
-  CREATED: 0,
-  DELETED: 1,
-};
-
-/**
- * @param {DirectoryEntry|Object} entry DirectoryEntry to be checked.
- * @return {boolean} True if the given entry is fake.
- */
-util.isFakeDirectoryEntry = function(entry) {
-  // Currently, fake entry doesn't support createReader.
-  return !('createReader' in entry);
-};
-
-/**
- * Creates a FileError instance with given code.
- * Note that we cannot create FileError instance by "new FileError(code)",
- * unfortunately, so here we use Object.create.
- * @param {number} code Error code for the FileError.
- * @return {FileError} FileError instance
- */
-util.createFileError = function(code) {
-  return Object.create(FileError.prototype, {
-    code: { get: function() { return code; } }
-  });
-};
-
-/**
- * @param {Entry|Object} entry1 The entry to be compared. Can be a fake.
- * @param {Entry|Object} entry2 The entry to be compared. Can be a fake.
- * @return {boolean} True if the both entry represents a same file or directory.
- */
-util.isSameEntry = function(entry1, entry2) {
-  // Currently, we can assume there is only one root.
-  // When we support multi-file system, we need to look at filesystem, too.
-  return entry1 === null ? entry2 === null : entry1.fullPath == entry2.fullPath;
-};
-
-/**
- * @param {Entry|Object} parent The parent entry. Can be a fake.
- * @param {Entry|Object} child The child entry. Can be a fake.
- * @return {boolean} True if parent entry is actualy the parent of the child
- *     entry.
- */
-util.isParentEntry = function(parent, child) {
-  // Currently, we can assume there is only one root.
-  // When we support multi-file system, we need to look at filesystem, too.
-  return PathUtil.isParentPath(parent.fullPath, child.fullPath);
-};
-
-/**
- * Views files in the browser.
- *
- * @param {Array.<string>} urls URLs of files to view.
- * @param {function(bool)} callback Callback notifying success or not.
- */
-util.viewFilesInBrowser = function(urls, callback) {
-  var taskId = chrome.runtime.id + '|file|view-in-browser';
-  chrome.fileBrowserPrivate.executeTask(taskId, urls, callback);
-};
-
-/**
- * Visit the URL.
- *
- * If the browser is opening, the url is opened in a new tag, otherwise the url
- * is opened in a new window.
- *
- * @param {string} url URL to visit.
- */
-util.visitURL = function(url) {
-  var params = {url: url};
-  chrome.tabs.create(params, function() {
-    if (chrome.runtime.lastError)
-      chrome.windows.create(params);
-  });
-};
-
-/**
- * Returns normalized current locale, or default locale - 'en'.
- * @return {string} Current locale
- */
-util.getCurrentLocaleOrDefault = function() {
-  // chrome.i18n.getMessage('@@ui_locale') can't be used in packed app.
-  // Instead, we pass it from C++-side with strings.
-  return str('UI_LOCALE') || 'en';
-};
-
-/**
- * Error type of VolumeManager.
- * @enum {string}
- */
-util.VolumeError = Object.freeze({
-  /* Internal errors */
-  NOT_MOUNTED: 'not_mounted',
-  TIMEOUT: 'timeout',
-
-  /* System events */
-  UNKNOWN: 'error_unknown',
-  INTERNAL: 'error_internal',
-  UNKNOWN_FILESYSTEM: 'error_unknown_filesystem',
-  UNSUPPORTED_FILESYSTEM: 'error_unsupported_filesystem',
-  INVALID_ARCHIVE: 'error_invalid_archive',
-  AUTHENTICATION: 'error_authentication',
-  PATH_UNMOUNTED: 'error_path_unmounted'
-});
-
-/**
- * List of connection types of drive.
- *
- * Keep this in sync with the kDriveConnectionType* constants in
- * file_browser_private_api.cc.
- *
- * @enum {string}
- */
-util.DriveConnectionType = Object.freeze({
-  OFFLINE: 'offline',  // Connection is offline or drive is unavailable.
-  METERED: 'metered',  // Connection is metered. Should limit traffic.
-  ONLINE: 'online'     // Connection is online.
-});
-
-/**
- * List of reasons of DriveConnectionType.
- *
- * Keep this in sync with the kDriveConnectionReason constants in
- * file_browser_private_api.cc.
- *
- * @enum {string}
- */
-util.DriveConnectionReason = Object.freeze({
-  NOT_READY: 'not_ready',    // Drive is not ready or authentication is failed.
-  NO_NETWORK: 'no_network',  // Network connection is unavailable.
-  NO_SERVICE: 'no_service'   // Drive service is unavailable.
-});
-
-/**
- * The type of each volume.
- * @enum {string}
- */
-util.VolumeType = Object.freeze({
-  DRIVE: 'drive',
-  DOWNLOADS: 'downloads',
-  REMOVABLE: 'removable',
-  ARCHIVE: 'archive'
-});
diff --git a/chrome/browser/resources/file_manager/js/volume_manager.js b/chrome/browser/resources/file_manager/js/volume_manager.js
deleted file mode 100644
index f55b849..0000000
--- a/chrome/browser/resources/file_manager/js/volume_manager.js
+++ /dev/null
@@ -1,635 +0,0 @@
-// Copyright (c) 2012 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.
-
-'use strict';
-
-/**
- * Represents each volume, such as "drive", "download directory", each "USB
- * flush storage", or "mounted zip archive" etc.
- *
- * @param {util.VolumeType} volumeType The type of the volume.
- * @param {string} mountPath Where the volume is mounted.
- * @param {DirectoryEntry} root The root directory entry of this volume.
- * @param {string} error The error if an error is found.
- * @param {string} deviceType The type of device ('usb'|'sd'|'optical'|'mobile'
- *     |'unknown') (as defined in chromeos/disks/disk_mount_manager.cc).
- *     Can be null.
- * @param {boolean} isReadOnly True if the volume is read only.
- * @constructor
- */
-function VolumeInfo(
-    volumeType, mountPath, root, error, deviceType, isReadOnly) {
-  this.volumeType = volumeType;
-  // TODO(hidehiko): This should include FileSystem instance.
-  this.mountPath = mountPath;
-  this.root = root;
-
-  // Note: This represents if the mounting of the volume is successfully done
-  // or not. (If error is empty string, the mount is successfully done).
-  // TODO(hidehiko): Rename to make this more understandable.
-  this.error = error;
-  this.deviceType = deviceType;
-  this.isReadOnly = isReadOnly;
-
-  // VolumeInfo is immutable.
-  Object.freeze(this);
-}
-
-/**
- * Utilities for volume manager implementation.
- */
-var volumeManagerUtil = {};
-
-/**
- * Throws an Error when the given error is not in util.VolumeError.
- * @param {util.VolumeError} error Status string usually received from APIs.
- */
-volumeManagerUtil.validateError = function(error) {
-  for (var key in util.VolumeError) {
-    if (error == util.VolumeError[key])
-      return;
-  }
-
-  throw new Error('Invalid mount error: ' + error);
-};
-
-/**
- * The regex pattern which matches valid mount paths.
- * The valid paths are:
- * - Either of '/drive', '/drive_shared_with_me', '/drive_offline',
- *   '/drive_recent' or '/Download'
- * - For archive, drive, removable can have (exactly one) sub directory in the
- *  root path. E.g. '/archive/foo', '/removable/usb1' etc.
- *
- * @type {RegExp}
- * @private
- */
-volumeManagerUtil.validateMountPathRegExp_ = new RegExp(
-    '^/(drive|drive_shared_with_me|drive_offline|drive_recent|Downloads|' +
-    '((archive|drive|removable)\/[^/]+))$');
-
-/**
- * Throws an Error if the validation fails.
- * @param {string} mountPath The target path of the validation.
- */
-volumeManagerUtil.validateMountPath = function(mountPath) {
-  if (!volumeManagerUtil.validateMountPathRegExp_.test(mountPath))
-    throw new Error('Invalid mount path: ' + mountPath);
-};
-
-/**
- * Returns the root entry of a volume mounted at mountPath.
- *
- * @param {string} mountPath The mounted path of the volume.
- * @param {function(DirectoryEntry)} successCallback Called when the root entry
- *     is found.
- * @param {function(FileError)} errorCallback Called when an error is found.
- * @private
- */
-volumeManagerUtil.getRootEntry_ = function(
-    mountPath, successCallback, errorCallback) {
-  // We always request FileSystem here, because requestFileSystem() grants
-  // permissions if necessary, especially for Drive File System at first mount
-  // time.
-  // Note that we actually need to request FileSystem after multi file system
-  // support, so this will be more natural code then.
-  chrome.fileBrowserPrivate.requestFileSystem(
-      'compatible',
-      function(fileSystem) {
-        // TODO(hidehiko): chrome.runtime.lastError should have error reason.
-        if (!fileSystem) {
-          errorCallback(util.createFileError(FileError.NOT_FOUND_ERR));
-          return;
-        }
-
-        fileSystem.root.getDirectory(
-            mountPath.substring(1),  // Strip leading '/'.
-            {create: false}, successCallback, errorCallback);
-      });
-};
-
-/**
- * Builds the VolumeInfo data from VolumeMetadata.
- * @param {VolumeMetadata} volumeMetadata Metadata instance for the volume.
- * @param {function(VolumeInfo)} callback Called on completion.
- */
-volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) {
-  volumeManagerUtil.getRootEntry_(
-      volumeMetadata.mountPath,
-      function(entry) {
-        if (volumeMetadata.volumeType === util.VolumeType.DRIVE) {
-          // After file system is mounted, we "read" drive grand root
-          // entry at first. This triggers full feed fetch on background.
-          // Note: we don't need to handle errors here, because even if
-          // it fails, accessing to some path later will just become
-          // a fast-fetch and it re-triggers full-feed fetch.
-          entry.createReader().readEntries(
-              function() { /* do nothing */ },
-              function(error) {
-                console.error(
-                    'Triggering full feed fetch is failed: ' +
-                        util.getFileErrorMnemonic(error.code));
-              });
-        }
-        callback(new VolumeInfo(
-            volumeMetadata.volumeType,
-            volumeMetadata.mountPath,
-            entry,
-            volumeMetadata.mountCondition,
-            volumeMetadata.deviceType,
-            volumeMetadata.isReadOnly));
-      },
-      function(fileError) {
-        console.error('Root entry is not found: ' +
-            mountPath + ', ' + util.getFileErrorMnemonic(fileError.code));
-        callback(new VolumeInfo(
-            volumeMetadata.volumeType,
-            volumeMetadata.mountPath,
-            null,  // Root entry is not found.
-            volumeMetadata.mountCondition,
-            volumeMetadata.deviceType,
-            volumeMetadata.isReadOnly));
-      });
-};
-
-/**
- * The order of the volume list based on root type.
- * @type {Array.<string>}
- * @const
- * @private
- */
-volumeManagerUtil.volumeListOrder_ = [
-  RootType.DRIVE, RootType.DOWNLOADS, RootType.ARCHIVE, RootType.REMOVABLE
-];
-
-/**
- * Compares mount paths to sort the volume list order.
- * @param {string} mountPath1 The mount path for the first volume.
- * @param {string} mountPath2 The mount path for the second volume.
- * @return {number} 0 if mountPath1 and mountPath2 are same, -1 if VolumeInfo
- *     mounted at mountPath1 should be listed before the one mounted at
- *     mountPath2, otherwise 1.
- */
-volumeManagerUtil.compareMountPath = function(mountPath1, mountPath2) {
-  var order1 = volumeManagerUtil.volumeListOrder_.indexOf(
-      PathUtil.getRootType(mountPath1));
-  var order2 = volumeManagerUtil.volumeListOrder_.indexOf(
-      PathUtil.getRootType(mountPath2));
-  if (order1 != order2)
-    return order1 < order2 ? -1 : 1;
-
-  if (mountPath1 != mountPath2)
-    return mountPath1 < mountPath2 ? -1 : 1;
-
-  // The path is same.
-  return 0;
-};
-
-/**
- * The container of the VolumeInfo for each mounted volume.
- * @constructor
- */
-function VolumeInfoList() {
-  /**
-   * Holds VolumeInfo instances.
-   * @type {cr.ui.ArrayDataModel}
-   * @private
-   */
-  this.model_ = new cr.ui.ArrayDataModel([]);
-
-  Object.freeze(this);
-}
-
-VolumeInfoList.prototype = {
-  get length() { return this.model_.length; }
-};
-
-/**
- * Adds the event listener to listen the change of volume info.
- * @param {string} type The name of the event.
- * @param {function(Event)} handler The handler for the event.
- */
-VolumeInfoList.prototype.addEventListener = function(type, handler) {
-  this.model_.addEventListener(type, handler);
-};
-
-/**
- * Removes the event listener.
- * @param {string} type The name of the event.
- * @param {function(Event)} handler The handler to be removed.
- */
-VolumeInfoList.prototype.removeEventListener = function(type, handler) {
-  this.model_.removeEventListener(type, handler);
-};
-
-/**
- * Adds the volumeInfo to the appropriate position. If there already exists,
- * just replaces it.
- * @param {VolumeInfo} volumeInfo The information of the new volume.
- */
-VolumeInfoList.prototype.add = function(volumeInfo) {
-  var index = this.findLowerBoundIndex_(volumeInfo.mountPath);
-  if (index < this.length &&
-      this.item(index).mountPath == volumeInfo.mountPath) {
-    // Replace the VolumeInfo.
-    this.model_.splice(index, 1, volumeInfo);
-  } else {
-    // Insert the VolumeInfo.
-    this.model_.splice(index, 0, volumeInfo);
-  }
-};
-
-/**
- * Removes the VolumeInfo of the volume mounted at mountPath.
- * @param {string} mountPath The path to the location where the volume is
- *     mounted.
- */
-VolumeInfoList.prototype.remove = function(mountPath) {
-  var index = this.findLowerBoundIndex_(mountPath);
-  if (index < this.length && this.item(index).mountPath == mountPath)
-    this.model_.splice(index, 1);
-};
-
-/**
- * Searches the information of the volume mounted at mountPath.
- * @param {string} mountPath The path to the location where the volume is
- *     mounted.
- * @return {VolumeInfo} The volume's information, or null if not found.
- */
-VolumeInfoList.prototype.find = function(mountPath) {
-  var index = this.findLowerBoundIndex_(mountPath);
-  if (index < this.length && this.item(index).mountPath == mountPath)
-    return this.item(index);
-
-  // Not found.
-  return null;
-};
-
-/**
- * @param {string} mountPath The mount path of searched volume.
- * @return {number} The index of the volume if found, or the inserting
- *     position of the volume.
- * @private
- */
-VolumeInfoList.prototype.findLowerBoundIndex_ = function(mountPath) {
-  // Assuming the number of elements in the array data model is very small
-  // in most cases, use simple linear search, here.
-  for (var i = 0; i < this.length; i++) {
-    if (volumeManagerUtil.compareMountPath(
-            this.item(i).mountPath, mountPath) >= 0)
-      return i;
-  }
-  return this.length;
-};
-
-/**
- * @param {number} index The index of the volume in the list.
- * @return {VolumeInfo} The VolumeInfo instance.
- */
-VolumeInfoList.prototype.item = function(index) {
-  return this.model_.item(index);
-};
-
-/**
- * VolumeManager is responsible for tracking list of mounted volumes.
- *
- * @constructor
- * @extends {cr.EventTarget}
- */
-function VolumeManager() {
-  /**
-   * The list of archives requested to mount. We will show contents once
-   * archive is mounted, but only for mounts from within this filebrowser tab.
-   * @type {Object.<string, Object>}
-   * @private
-   */
-  this.requests_ = {};
-
-  /**
-   * The list of VolumeInfo instances for each mounted volume.
-   * @type {VolumeInfoList}
-   */
-  this.volumeInfoList = new VolumeInfoList();
-
-  // The status should be merged into VolumeManager.
-  // TODO(hidehiko): Remove them after the migration.
-  this.driveConnectionState_ = {
-    type: util.DriveConnectionType.OFFLINE,
-    reasons: [util.DriveConnectionReason.NO_SERVICE]
-  };
-
-  chrome.fileBrowserPrivate.onDriveConnectionStatusChanged.addListener(
-      this.onDriveConnectionStatusChanged_.bind(this));
-  this.onDriveConnectionStatusChanged_();
-}
-
-/**
- * Invoked when the drive connection status is changed.
- * @private_
- */
-VolumeManager.prototype.onDriveConnectionStatusChanged_ = function() {
-  chrome.fileBrowserPrivate.getDriveConnectionState(function(state) {
-    this.driveConnectionState_ = state;
-    cr.dispatchSimpleEvent(this, 'drive-connection-changed');
-  }.bind(this));
-};
-
-/**
- * Returns the drive connection state.
- * @return {util.DriveConnectionType} Connection type.
- */
-VolumeManager.prototype.getDriveConnectionState = function() {
-  return this.driveConnectionState_;
-};
-
-/**
- * VolumeManager extends cr.EventTarget.
- */
-VolumeManager.prototype.__proto__ = cr.EventTarget.prototype;
-
-/**
- * Time in milliseconds that we wait a response for. If no response on
- * mount/unmount received the request supposed failed.
- */
-VolumeManager.TIMEOUT = 15 * 60 * 1000;
-
-/**
- * Queue to run getInstance sequentially.
- * @type {AsyncUtil.Queue}
- * @private
- */
-VolumeManager.getInstanceQueue_ = new AsyncUtil.Queue();
-
-/**
- * The singleton instance of VolumeManager. Initialized by the first invocation
- * of getInstance().
- * @type {VolumeManager}
- * @private
- */
-VolumeManager.instance_ = null;
-
-/**
- * Returns the VolumeManager instance asynchronously. If it is not created or
- * under initialization, it will waits for the finish of the initialization.
- * @param {function(VolumeManager)} callback Called with the VolumeManager
- *     instance.
- */
-VolumeManager.getInstance = function(callback) {
-  VolumeManager.getInstanceQueue_.run(function(continueCallback) {
-    if (VolumeManager.instance_) {
-      callback(VolumeManager.instance_);
-      continueCallback();
-      return;
-    }
-
-    VolumeManager.instance_ = new VolumeManager();
-    VolumeManager.instance_.initialize_(function() {
-      callback(VolumeManager.instance_);
-      continueCallback();
-    });
-  });
-};
-
-/**
- * Initializes mount points.
- * @param {function()} callback Called upon the completion of the
- *     initialization.
- * @private
- */
-VolumeManager.prototype.initialize_ = function(callback) {
-  chrome.fileBrowserPrivate.getVolumeMetadataList(function(volumeMetadataList) {
-    // Create VolumeInfo for each volume.
-    var group = new AsyncUtil.Group();
-    for (var i = 0; i < volumeMetadataList.length; i++) {
-      group.add(function(volumeMetadata, continueCallback) {
-        volumeManagerUtil.createVolumeInfo(
-            volumeMetadata,
-            function(volumeInfo) {
-              this.volumeInfoList.add(volumeInfo);
-              if (volumeMetadata.volumeType === util.VolumeType.DRIVE)
-                this.onDriveConnectionStatusChanged_();
-              continueCallback();
-            }.bind(this));
-      }.bind(this, volumeMetadataList[i]));
-    }
-
-    // Then, finalize the initialization.
-    group.run(function() {
-      // Subscribe to the mount completed event when mount points initialized.
-      chrome.fileBrowserPrivate.onMountCompleted.addListener(
-          this.onMountCompleted_.bind(this));
-      callback();
-    }.bind(this));
-  }.bind(this));
-};
-
-/**
- * Event handler called when some volume was mounted or unmounted.
- * @param {MountCompletedEvent} event Received event.
- * @private
- */
-VolumeManager.prototype.onMountCompleted_ = function(event) {
-  if (event.eventType === 'mount') {
-    if (event.volumeMetadata.mountPath) {
-      var requestKey = this.makeRequestKey_(
-          'mount',
-          event.volumeMetadata.sourcePath);
-
-      var error = event.status === 'success' ? '' : event.status;
-
-      volumeManagerUtil.createVolumeInfo(
-          event.volumeMetadata,
-          function(volumeInfo) {
-            this.volumeInfoList.add(volumeInfo);
-            this.finishRequest_(requestKey, event.status, volumeInfo.mountPath);
-
-            if (volumeInfo.volumeType === util.VolumeType.DRIVE) {
-              // Update the network connection status, because until the
-              // drive is initialized, the status is set to not ready.
-              // TODO(hidehiko): The connection status should be migrated into
-              // VolumeMetadata.
-              this.onDriveConnectionStatusChanged_();
-            }
-          }.bind(this));
-    } else {
-      console.warn('No mount path.');
-      this.finishRequest_(requestKey, event.status);
-    }
-  } else if (event.eventType === 'unmount') {
-    var mountPath = event.volumeMetadata.mountPath;
-    volumeManagerUtil.validateMountPath(mountPath);
-    var status = event.status;
-    if (status === util.VolumeError.PATH_UNMOUNTED) {
-      console.warn('Volume already unmounted: ', mountPath);
-      status = 'success';
-    }
-    var requestKey = this.makeRequestKey_('unmount', mountPath);
-    var requested = requestKey in this.requests_;
-    if (event.status === 'success' && !requested &&
-        this.volumeInfoList.find(mountPath)) {
-      console.warn('Mounted volume without a request: ', mountPath);
-      var e = new Event('externally-unmounted');
-      e.mountPath = mountPath;
-      this.dispatchEvent(e);
-    }
-    this.finishRequest_(requestKey, status);
-
-    if (event.status === 'success')
-      this.volumeInfoList.remove(mountPath);
-  }
-};
-
-/**
- * Creates string to match mount events with requests.
- * @param {string} requestType 'mount' | 'unmount'. TODO(hidehiko): Replace by
- *     enum.
- * @param {string} path Source path provided by API for mount request, or
- *     mount path for unmount request.
- * @return {string} Key for |this.requests_|.
- * @private
- */
-VolumeManager.prototype.makeRequestKey_ = function(requestType, path) {
-  return requestType + ':' + path;
-};
-
-/**
- * @param {string} fileUrl File url to the archive file.
- * @param {function(string)} successCallback Success callback.
- * @param {function(util.VolumeError)} errorCallback Error callback.
- */
-VolumeManager.prototype.mountArchive = function(
-    fileUrl, successCallback, errorCallback) {
-  chrome.fileBrowserPrivate.addMount(fileUrl, function(sourcePath) {
-    console.info(
-        'Mount request: url=' + fileUrl + '; sourceUrl=' + sourcePath);
-    var requestKey = this.makeRequestKey_('mount', sourcePath);
-    this.startRequest_(requestKey, successCallback, errorCallback);
-  }.bind(this));
-};
-
-/**
- * Unmounts volume.
- * @param {string} mountPath Volume mounted path.
- * @param {function(string)} successCallback Success callback.
- * @param {function(util.VolumeError)} errorCallback Error callback.
- */
-VolumeManager.prototype.unmount = function(mountPath,
-                                           successCallback,
-                                           errorCallback) {
-  volumeManagerUtil.validateMountPath(mountPath);
-  var volumeInfo = this.volumeInfoList.find(mountPath);
-  if (!volumeInfo) {
-    errorCallback(util.VolumeError.NOT_MOUNTED);
-    return;
-  }
-
-  chrome.fileBrowserPrivate.removeMount(util.makeFilesystemUrl(mountPath));
-  var requestKey = this.makeRequestKey_('unmount', volumeInfo.mountPath);
-  this.startRequest_(requestKey, successCallback, errorCallback);
-};
-
-/**
- * Resolve the path to its entry.
- * @param {string} path The path to be resolved.
- * @param {function(Entry)} successCallback Called with the resolved entry on
- *     success.
- * @param {function(FileError)} errorCallback Called on error.
- */
-VolumeManager.prototype.resolvePath = function(
-    path, successCallback, errorCallback) {
-  // Make sure the path is in the mounted volume.
-  var mountPath = PathUtil.isDriveBasedPath(path) ?
-      RootDirectory.DRIVE : PathUtil.getRootPath(path);
-  var volumeInfo = this.getVolumeInfo(mountPath);
-  if (!volumeInfo || !volumeInfo.root) {
-    errorCallback(util.createFileError(FileError.NOT_FOUND_ERR));
-    return;
-  }
-
-  webkitResolveLocalFileSystemURL(
-      util.makeFilesystemUrl(path), successCallback, errorCallback);
-};
-
-/**
- * @param {string} mountPath Volume mounted path.
- * @return {VolumeInfo} The data about the volume.
- */
-VolumeManager.prototype.getVolumeInfo = function(mountPath) {
-  volumeManagerUtil.validateMountPath(mountPath);
-  return this.volumeInfoList.find(mountPath);
-};
-
-/**
- * @param {string} key Key produced by |makeRequestKey_|.
- * @param {function(string)} successCallback To be called when request finishes
- *     successfully.
- * @param {function(util.VolumeError)} errorCallback To be called when
- *     request fails.
- * @private
- */
-VolumeManager.prototype.startRequest_ = function(key,
-    successCallback, errorCallback) {
-  if (key in this.requests_) {
-    var request = this.requests_[key];
-    request.successCallbacks.push(successCallback);
-    request.errorCallbacks.push(errorCallback);
-  } else {
-    this.requests_[key] = {
-      successCallbacks: [successCallback],
-      errorCallbacks: [errorCallback],
-
-      timeout: setTimeout(this.onTimeout_.bind(this, key),
-                          VolumeManager.TIMEOUT)
-    };
-  }
-};
-
-/**
- * Called if no response received in |TIMEOUT|.
- * @param {string} key Key produced by |makeRequestKey_|.
- * @private
- */
-VolumeManager.prototype.onTimeout_ = function(key) {
-  this.invokeRequestCallbacks_(this.requests_[key],
-                               util.VolumeError.TIMEOUT);
-  delete this.requests_[key];
-};
-
-/**
- * @param {string} key Key produced by |makeRequestKey_|.
- * @param {util.VolumeError|'success'} status Status received from the API.
- * @param {string=} opt_mountPath Mount path.
- * @private
- */
-VolumeManager.prototype.finishRequest_ = function(key, status, opt_mountPath) {
-  var request = this.requests_[key];
-  if (!request)
-    return;
-
-  clearTimeout(request.timeout);
-  this.invokeRequestCallbacks_(request, status, opt_mountPath);
-  delete this.requests_[key];
-};
-
-/**
- * @param {Object} request Structure created in |startRequest_|.
- * @param {util.VolumeError|string} status If status == 'success'
- *     success callbacks are called.
- * @param {string=} opt_mountPath Mount path. Required if success.
- * @private
- */
-VolumeManager.prototype.invokeRequestCallbacks_ = function(request, status,
-                                                           opt_mountPath) {
-  var callEach = function(callbacks, self, args) {
-    for (var i = 0; i < callbacks.length; i++) {
-      callbacks[i].apply(self, args);
-    }
-  };
-  if (status == 'success') {
-    callEach(request.successCallbacks, this, [opt_mountPath]);
-  } else {
-    volumeManagerUtil.validateError(status);
-    callEach(request.errorCallbacks, this, [status]);
-  }
-};
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index af0940b..065b2dd 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -27,7 +27,7 @@
 
     <!-- Don't load main_scripts.js when flattening is disabled. -->
     <if expr="0"><!-- </if>
-      <script src="js/main_scripts.js"></script>
+      <script src="foreground/js/main_scripts.js"></script>
     <if expr="0"> --></if>
 
     <if expr="0">
@@ -80,59 +80,59 @@
       <script src="chrome://resources/js/cr/ui/context_menu_handler.js"></script>
 
       <!-- This script must be loaded before all other Files.app's scripts. -->
-      <script src="js/error_counter.js"></script>
+      <script src="foreground/js/error_counter.js"></script>
 
-      <script src="js/combobutton.js"></script>
-      <script src="js/commandbutton.js"></script>
-      <script src="js/ui/file_manager_dialog_base.js"></script>
+      <script src="common/js/async_util.js"></script>
+      <script src="common/js/path_util.js"></script>
+      <script src="common/js/util.js"></script>
+      <script src="common/js/progress_center_common.js"></script>
 
-      <script src="js/app_installer.js"></script>
-      <script src="js/async_util.js"></script>
-      <script src="js/path_util.js"></script>
-      <script src="js/util.js"></script>
-      <script src="js/action_choice_util.js"></script>
-      <script src="js/butter_bar.js"></script>
-      <script src="js/cws_container_client.js"></script>
-      <script src="js/directory_contents.js"></script>
-      <script src="js/directory_model.js"></script>
-      <script src="js/directory_tree.js"></script>
-      <script src="js/drag_selector.js"></script>
-      <script src="js/drive_banners.js"></script>
-      <script src="js/error_dialog.js"></script>
-      <script src="js/file_operation_manager_wrapper.js"></script>
-      <script src="js/file_grid.js"></script>
-      <script src="js/file_manager.js"></script>
-      <script src="js/file_selection.js"></script>
-      <script src="js/file_table.js"></script>
-      <script src="js/file_tasks.js"></script>
-      <script src="js/file_transfer_controller.js"></script>
-      <script src="js/file_type.js"></script>
-      <script src="js/file_watcher.js"></script>
-      <script src="js/folder_shortcuts_data_model.js"></script>
-      <script src="js/navigation_list.js"></script>
-      <script src="js/progress_center_common.js"></script>
-      <script src="js/scrollbar.js"></script>
-      <script src="js/share_client.js"></script>
-      <script src="js/share_dialog.js"></script>
-      <script src="js/suggest_apps_dialog.js"></script>
-      <script src="js/text_measure.js"></script>
-      <script src="js/tree.css.js"></script>
-      <script src="js/ui/breadcrumbs_controller.js"></script>
-      <script src="js/ui/conflict_dialog.js"></script>
-      <script src="js/ui/file_manager_ui.js"></script>
-      <script src="js/ui/preview_panel.js"></script>
-      <script src="js/ui/progress_center_panel.js"></script>
-      <script src="js/ui/search_box.js"></script>
-      <script src="js/url_constants.js"></script>
-      <script src="js/volume_manager_wrapper.js"></script>
-      <script src="js/media/media_util.js"></script>
-      <script src="js/metadata/metadata_cache.js"></script>
-      <script src="js/default_action_dialog.js"></script>
-      <script src="js/file_manager_commands.js"></script>
+      <script src="foreground/js/combobutton.js"></script>
+      <script src="foreground/js/commandbutton.js"></script>
+      <script src="foreground/js/ui/file_manager_dialog_base.js"></script>
+
+      <script src="foreground/js/action_choice/action_choice_util.js"></script>
+      <script src="foreground/js/app_installer.js"></script>
+      <script src="foreground/js/butter_bar.js"></script>
+      <script src="foreground/js/cws_container_client.js"></script>
+      <script src="foreground/js/directory_contents.js"></script>
+      <script src="foreground/js/directory_model.js"></script>
+      <script src="foreground/js/directory_tree.js"></script>
+      <script src="foreground/js/drag_selector.js"></script>
+      <script src="foreground/js/drive_banners.js"></script>
+      <script src="foreground/js/error_dialog.js"></script>
+      <script src="foreground/js/file_operation_manager_wrapper.js"></script>
+      <script src="foreground/js/file_grid.js"></script>
+      <script src="foreground/js/file_manager.js"></script>
+      <script src="foreground/js/file_selection.js"></script>
+      <script src="foreground/js/file_table.js"></script>
+      <script src="foreground/js/file_tasks.js"></script>
+      <script src="foreground/js/file_transfer_controller.js"></script>
+      <script src="foreground/js/file_type.js"></script>
+      <script src="foreground/js/file_watcher.js"></script>
+      <script src="foreground/js/folder_shortcuts_data_model.js"></script>
+      <script src="foreground/js/navigation_list_model.js"></script>
+      <script src="foreground/js/scrollbar.js"></script>
+      <script src="foreground/js/share_client.js"></script>
+      <script src="foreground/js/share_dialog.js"></script>
+      <script src="foreground/js/suggest_apps_dialog.js"></script>
+      <script src="foreground/js/text_measure.js"></script>
+      <script src="foreground/js/tree.css.js"></script>
+      <script src="foreground/js/ui/breadcrumbs_controller.js"></script>
+      <script src="foreground/js/ui/conflict_dialog.js"></script>
+      <script src="foreground/js/ui/file_manager_ui.js"></script>
+      <script src="foreground/js/ui/navigation_list.js"></script>
+      <script src="foreground/js/ui/preview_panel.js"></script>
+      <script src="foreground/js/ui/progress_center_panel.js"></script>
+      <script src="foreground/js/ui/search_box.js"></script>
+      <script src="foreground/js/url_constants.js"></script>
+      <script src="foreground/js/volume_manager_wrapper.js"></script>
+      <script src="foreground/js/default_action_dialog.js"></script>
+      <script src="foreground/js/file_manager_commands.js"></script>
 
       <!-- For accurate load performance tracking main.js should be
            the last script to include. -->
-      <script src="js/main.js"></script>
+      <script src="foreground/js/main.js"></script>
     </if>
 
   </head>
@@ -362,9 +362,7 @@
                 <div class="detail-table" id="detail-table" tabindex="1" autofocus>
                 </div>
                 <grid class="thumbnail-grid" tabindex="2"></grid>
-                <div id="spinner-container">
-                  <div id="spinner-with-text"></div>
-                </div>
+                <div class="spinner-layer"></div>
                 <div class="drive-welcome page"></div>
                 <div id="no-search-results"></div>
               </div>
diff --git a/chrome/browser/resources/file_manager/manifest.json b/chrome/browser/resources/file_manager/manifest.json
index 07b6d88..1eae729 100644
--- a/chrome/browser/resources/file_manager/manifest.json
+++ b/chrome/browser/resources/file_manager/manifest.json
@@ -209,7 +209,7 @@
   // Required to import scripts in a web worker. Note, that in Apps v2, it is
   // enough that anything is passed to web_accessible_resources. If there is
   // at least any file, then all files are allowed. http://crbug.com/179127.
-  "web_accessible_resources": ["js/metadata/byte_reader.js"],
+  "web_accessible_resources": ["foreground/js/metadata/byte_reader.js"],
   "app": {
     "background": {
       "scripts": [
@@ -217,15 +217,15 @@
         "chrome://resources/js/cr.js",
         "chrome://resources/js/cr/event_target.js",
         "chrome://resources/js/cr/ui/array_data_model.js",
-        "js/util.js",
-        "js/path_util.js",
-        "js/async_util.js",
-        "js/volume_manager.js",
-        "js/file_operation_manager.js",
-        "js/test_util.js",
-        "js/progress_center_common.js",
-        "js/progress_center.js",
-        "js/background.js"]
+        "common/js/async_util.js",
+        "common/js/path_util.js",
+        "common/js/progress_center_common.js",
+        "common/js/util.js",
+        "background/js/volume_manager.js",
+        "background/js/file_operation_manager.js",
+        "background/js/test_util.js",
+        "background/js/progress_center.js",
+        "background/js/background.js"]
     },
     // chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp is the image loader extension.
     "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp; style-src 'self' 'unsafe-inline' chrome://resources; frame-src 'self' about:; img-src 'self' chrome://resources chrome://theme data: https://docs.google.com https://*.googleusercontent.com chrome://extension-icon; media-src 'self' https://*.googleusercontent.com; connect-src https://drive.google.com; object-src 'self'"
diff --git a/chrome/browser/resources/file_manager/mediaplayer.html b/chrome/browser/resources/file_manager/mediaplayer.html
index 324db27..484d0e0 100644
--- a/chrome/browser/resources/file_manager/mediaplayer.html
+++ b/chrome/browser/resources/file_manager/mediaplayer.html
@@ -17,7 +17,7 @@
 
   <!-- Don't load mediaplayer_scripts.js when flattening is disabled -->
   <if expr="0"><!-- </if>
-    <script src="js/media/mediaplayer_scripts.js"></script>
+    <script src="foreground/js/media/mediaplayer_scripts.js"></script>
   <if expr="0"> --></if>
 
   <if expr="0">
@@ -27,16 +27,18 @@
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/event_target.js"></script>
     <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-    <script src="js/async_util.js"></script>
-    <script src="js/util.js"></script>
-    <script src="js/path_util.js"></script>
-    <script src="js/file_type.js"></script>
-    <script src="js/volume_manager_wrapper.js"></script>
-    <script src="js/metadata/metadata_cache.js"></script>
 
-    <script src="js/media/media_controls.js"></script>
-    <script src="js/media/audio_player.js"></script>
-    <script src="js/media/player_testapi.js"></script>
+    <script src="common/js/async_util.js"></script>
+    <script src="common/js/util.js"></script>
+    <script src="common/js/path_util.js"></script>
+
+    <script src="foreground/js/file_type.js"></script>
+    <script src="foreground/js/volume_manager_wrapper.js"></script>
+    <script src="foreground/js/metadata/metadata_cache.js"></script>
+
+    <script src="foreground/js/media/media_controls.js"></script>
+    <script src="foreground/js/media/audio_player.js"></script>
+    <script src="foreground/js/media/player_testapi.js"></script>
   </if>
 </head>
 <body>
diff --git a/chrome/browser/resources/file_manager/photo_import.html b/chrome/browser/resources/file_manager/photo_import.html
deleted file mode 100644
index db18243..0000000
--- a/chrome/browser/resources/file_manager/photo_import.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE HTML>
-<!--
-  -- Copyright (c) 2012 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.
-  -->
-<html>
-<head>
-  <link rel="stylesheet" href="chrome://resources/css/list.css"></link>
-  <link rel="stylesheet" href="chrome://resources/css/dialogs.css"></link>
-
-  <link rel="stylesheet" type="text/css" href="css/common.css">
-  <link rel="stylesheet" type="text/css" href="css/file_types.css">
-  <link rel="stylesheet" type="text/css" href="css/media_controls.css">
-  <link rel="stylesheet" type="text/css" href="css/select_album_dialog.css">
-  <link rel="stylesheet" type="text/css" href="css/tile_view.css">
-  <link rel="stylesheet" type="text/css" href="css/photo_import.css">
-
-  <!-- Don't load photo_import_scripts.js when flattening is disabled -->
-  <if expr="0"><!-- </if>
-    <script src="js/photo/photo_import_scripts.js"></script>
-  <if expr="0"> --></if>
-
-  <if expr="0">
-    <!-- This section is used when the file manager is loaded with
-         'filemgr-ext-path' command-line flag. -->
-    <!-- Keep the list in sync with photo_import_scripts.js. -->
-
-    <!-- Loads the client of the image loader extension -->
-    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
-
-    <script src="chrome://resources/js/load_time_data.js"></script>
-    <script src="chrome://resources/js/util.js"></script>
-    <script src="chrome://resources/js/i18n_template_no_process.js"></script>
-
-    <script src="chrome://resources/js/cr.js"></script>
-    <script src="chrome://resources/js/event_tracker.js"></script>
-    <script src="chrome://resources/js/cr/ui.js"></script>
-    <script src="chrome://resources/js/cr/event_target.js"></script>
-    <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
-    <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_item.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-    <script src="chrome://resources/js/cr/ui/list.js"></script>
-    <script src="chrome://resources/js/cr/ui/grid.js"></script>
-
-    <script src="js/async_util.js"></script>
-    <script src="js/util.js"></script>
-    <script src="js/path_util.js"></script>
-    <script src="js/file_type.js"></script>
-    <script src="js/directory_contents.js"></script>
-    <script src="js/volume_manager_wrapper.js"></script>
-    <script src="js/file_operation_manager_wrapper.js"></script>
-    <script src="js/metadata/metadata_cache.js"></script>
-    <script src="js/metrics.js"></script>
-    <script src="js/image_editor/image_util.js"></script>
-    <script src="js/media/media_util.js"></script>
-
-    <script src="js/photo/importing_dialog.js"></script>
-    <script src="js/photo/tile_view.js"></script>
-    <script src="js/photo/photo_import.js"></script>
-  </if>
-  <title>&#xFEFF;</title>
-</head>
-
-<body>
-  <div class="photo-import">
-    <div class="grid-container">
-      <div class="topbar">
-        <div class="caption"></div>
-        <div class="select"></div>
-      </div>
-      <grid></grid>
-      <div class="bottombar buttonbar">
-        <input type="checkbox" id="delete-after-checkbox">
-        <label for="delete-after-checkbox"></label>
-        <div class="selected-count"></div>
-        <button class="cancel"></button>
-        <button class="import action"></button>
-      </div>
-    </div>
-    <div class="spinner"></div>
-  </div>
-</body>
-</html>
diff --git a/chrome/browser/resources/file_manager/video_player.html b/chrome/browser/resources/file_manager/video_player.html
index 7f49bc8..3fa7464 100644
--- a/chrome/browser/resources/file_manager/video_player.html
+++ b/chrome/browser/resources/file_manager/video_player.html
@@ -16,7 +16,7 @@
 
   <!-- Don't load video_player_scripts.js when flattening is disabled -->
   <if expr="0"><!-- </if>
-    <script src="js/media/video_player_scripts.js"></script>
+    <script src="foreground/js/media/video_player_scripts.js"></script>
   <if expr="0"> --></if>
 
   <if expr="0">
@@ -28,17 +28,18 @@
     <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
     <script src="chrome://resources/js/load_time_data.js"></script>
 
-    <script src="js/async_util.js"></script>
-    <script src="js/util.js"></script>
-    <script src="js/path_util.js"></script>
-    <script src="js/file_type.js"></script>
-    <script src="js/volume_manager_wrapper.js"></script>
-    <script src="js/metadata/metadata_cache.js"></script>
+    <script src="common/js/async_util.js"></script>
+    <script src="common/js/util.js"></script>
+    <script src="common/js/path_util.js"></script>
 
-    <script src="js/media/media_controls.js"></script>
-    <script src="js/media/util.js"></script>
-    <script src="js/media/video_player.js"></script>
-    <script src="js/media/player_testapi.js"></script>
+    <script src="foreground/js/file_type.js"></script>
+    <script src="foreground/js/volume_manager_wrapper.js"></script>
+    <script src="foreground/js/metadata/metadata_cache.js"></script>
+
+    <script src="foreground/js/media/media_controls.js"></script>
+    <script src="foreground/js/media/util.js"></script>
+    <script src="foreground/js/media/video_player.js"></script>
+    <script src="foreground/js/media/player_testapi.js"></script>
   </if>
 </head>
 <body>
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js
index 1f41917..c0364e8 100644
--- a/chrome/browser/resources/gaia_auth/main.js
+++ b/chrome/browser/resources/gaia_auth/main.js
@@ -91,6 +91,14 @@
 
   /** Callback when all loads in the gaia webview is complete. */
   onWebviewLoadstop_: function(gaiaFrame) {
+    // Report the current state to the parent which will then update the
+    // browser history so that later it could respond properly to back/forward.
+    var msg = {
+      'method': 'reportState',
+      'src': gaiaFrame.src
+    };
+    window.parent.postMessage(msg, this.parentPage_);
+
     if (gaiaFrame.src.lastIndexOf(
         this.gaiaUrl_ + this.GAIA_PAGE_PATH, 0) == 0) {
       gaiaFrame.executeScript({file: 'inline_injected.js'}, function() {
@@ -105,17 +113,27 @@
       // URL. Cannot reuse the login complete flow in success.html, because
       // webview does not support extension pages yet.
       gaiaFrame.hidden = true;
-      var msg = {'method': 'completeLogin'};
+      msg = {'method': 'completeLogin'};
       window.parent.postMessage(msg, this.parentPage_);
     }
   },
 
+  /**
+   * Callback when the gaia webview attempts to open a new window.
+  */
+  onWebviewNewWindow_: function(gaiaFrame, e) {
+    window.open(e.targetUrl, '_blank');
+    e.window.discard();
+  },
+
   loadFrame_: function() {
     var gaiaFrame = $('gaia-frame');
     gaiaFrame.src = this.getFrameUrl_();
     if (this.inlineMode_) {
       gaiaFrame.addEventListener(
           'loadstop', this.onWebviewLoadstop_.bind(this, gaiaFrame));
+      gaiaFrame.addEventListener(
+          'newwindow', this.onWebviewNewWindow_.bind(this, gaiaFrame));
     }
   },
 
@@ -230,6 +248,9 @@
     } else if (msg.method == 'verifyConfirmedPassword' &&
                this.isParentMessage_(e)) {
       this.onVerifyConfirmedPassword_(msg.password);
+    } else if (msg.method == 'navigate' &&
+               this.isParentMessage_(e)) {
+       $('gaia-frame').src = msg.src;
     } else {
       console.error('Authenticator.onMessage: unknown message + origin!?');
     }
diff --git a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
index 20eb832..9ad26dd 100644
--- a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
+++ b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
@@ -98,6 +98,8 @@
     assert(this.frame_);
     window.addEventListener('message',
                             this.onMessage_.bind(this), false);
+    window.addEventListener('popstate',
+                            this.onPopState_.bind(this), false);
   }
 
   GaiaAuthHost.prototype = {
@@ -334,7 +336,31 @@
         return;
       }
 
+      if (msg.method == 'reportState') {
+        if (history.state) {
+          history.state.src == msg.src || history.pushState({src: msg.src});
+        } else {
+          history.replaceState({src: msg.src});
+        }
+        return;
+      }
+
       console.error('Unknown message method=' + msg.method);
+    },
+
+    /**
+     * Event handler that is invoked when the history state is changed.
+     * @param {object} e The popstate event being triggered.
+     */
+    onPopState_: function(e) {
+      var state = e.state;
+      if (state) {
+        var msg = {
+          method: 'navigate',
+          src: state.src
+        };
+        this.frame_.contentWindow.postMessage(msg, AUTH_URL_BASE);
+      }
     }
   };
 
diff --git a/chrome/browser/resources/gesture_config.js b/chrome/browser/resources/gesture_config.js
index e00090b..a12c783 100644
--- a/chrome/browser/resources/gesture_config.js
+++ b/chrome/browser/resources/gesture_config.js
@@ -179,6 +179,11 @@
       step: 0.1
     },
     {
+      key: 'show_press_delay_in_ms',
+      label: 'Delay before show press event is fired',
+      units: 'milliseconds',
+    },
+    {
       key: 'max_seconds_between_double_click',
       label: 'Maximum Double Click Interval',
       units: 'seconds',
@@ -367,34 +372,6 @@
 }
 
 /**
- * Returns a GeneralConfig for configuring immersive.* preferences for
- * immersive fullscreen in Ash.
- * @return {object} A GeneralConfig object.
- */
-function ImmersiveConfig() {
-  /** @const */ var IMMERSIVE_TITLE = 'Immersive Fullscreen Configuration';
-
-  /** @const */ var IMMERSIVE_PREFIX = 'immersive_mode.';
-
-  var IMMERSIVE_FIELDS = [
-    {
-      key: 'reveal_delay_ms',
-      label: 'Top-of-screen reveal delay',
-      units: 'milliseconds'
-    },
-    {
-      key: 'reveal_x_threshold_pixels',
-      label: 'Top-of-screen mouse x threshold',
-      units: 'pixels'
-    },
-  ];
-
-  return new GeneralConfig(IMMERSIVE_TITLE,
-                           IMMERSIVE_PREFIX,
-                           IMMERSIVE_FIELDS);
-}
-
-/**
  * Returns a GeneralConfig for configuring flingcurve.* preferences.
  * @return {object} A GeneralConfig object.
  */
@@ -462,14 +439,10 @@
     var f = FlingConfig();
     f.buildAll();
 
-    var i = ImmersiveConfig();
-    i.buildAll();
-
     $('reset-all-button').onclick = function() {
       g.onReset();
       o.onReset();
       f.onReset();
-      i.onReset();
     };
   },
 
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index ef01369..f45018c 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -86,12 +86,6 @@
 var LOCATION_WATCH_NAME = 'location-watch';
 
 /**
- * Chrome push messaging subchannel for messages causing an immediate poll.
- */
-var SUBCHANNEL_ID_POLL_NOW = 0;
-
-/**
-/**
  * Notification as it's sent by the server.
  *
  * @typedef {{
@@ -108,12 +102,15 @@
 
 /**
  * Notification group as the client stores it. |cardsTimestamp| and |rank| are
- * defined if |cards| is non-empty.
+ * defined if |cards| is non-empty. |nextPollTime| is undefined if the server
+ * (1) never sent 'nextPollSeconds' for the group or
+ * (2) didn't send 'nextPollSeconds' with the last group update containing a
+ *     cards update and all the times after that.
  *
  * @typedef {{
  *   cards: Array.<UnmergedNotification>,
  *   cardsTimestamp: number=,
- *   nextPollTime: number,
+ *   nextPollTime: number=,
  *   rank: number=
  * }}
  */
@@ -153,6 +150,7 @@
 wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1);
 wrapper.instrumentChromeApiFunction('notifications.clear', 1);
 wrapper.instrumentChromeApiFunction('notifications.create', 2);
+wrapper.instrumentChromeApiFunction('notifications.getPermissionLevel', 0);
 wrapper.instrumentChromeApiFunction('notifications.update', 2);
 wrapper.instrumentChromeApiFunction('notifications.getAll', 0);
 wrapper.instrumentChromeApiFunction(
@@ -160,6 +158,8 @@
 wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0);
 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0);
 wrapper.instrumentChromeApiFunction(
+    'notifications.onPermissionLevelChanged.addListener', 0);
+wrapper.instrumentChromeApiFunction(
     'preferencesPrivate.googleGeolocationAccessEnabled.get',
     1);
 wrapper.instrumentChromeApiFunction(
@@ -229,7 +229,7 @@
  *     parameter.
  */
 function setAuthorization(request, callbackBoolean) {
-  authenticationManager.isSignedIn(function(token) {
+  authenticationManager.getAuthToken(function(token) {
     if (!token) {
       callbackBoolean(false);
       return;
@@ -273,8 +273,6 @@
         instrumented.notifications.getAll(function(notifications) {
           console.log('showNotificationCards-getAll ' +
               JSON.stringify(notifications));
-          // TODO(vadimt): Figure out what to do when notifications are
-          // disabled for our extension.
           notifications = notifications || {};
 
           // Build a set of non-expired recent dismissals. It will be used for
@@ -431,10 +429,13 @@
 
   for (var groupName in groups) {
     var group = groups[groupName];
-    nextPollTime = nextPollTime == null ?
-        group.nextPollTime : Math.min(group.nextPollTime, nextPollTime);
+    if (group.nextPollTime !== undefined) {
+      nextPollTime = nextPollTime == null ?
+          group.nextPollTime : Math.min(group.nextPollTime, nextPollTime);
+    }
   }
 
+  // At least one of the groups must have nextPollTime.
   verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null');
 
   var nextPollDelaySeconds = Math.max(
@@ -493,7 +494,7 @@
       var storageGroup = items.notificationGroups[groupName] || {
         cards: [],
         cardsTimestamp: undefined,
-        nextPollTime: now,
+        nextPollTime: undefined,
         rank: undefined
       };
 
@@ -501,11 +502,20 @@
         receivedGroup.cards = receivedGroup.cards || [];
 
       if (receivedGroup.cards) {
+        // If the group contains a cards update, all its fields will get new
+        // values.
         storageGroup.cards = receivedGroup.cards;
         storageGroup.cardsTimestamp = now;
         storageGroup.rank = receivedGroup.rank;
+        storageGroup.nextPollTime = undefined;
+        // The code below assigns nextPollTime a defined value if
+        // nextPollSeconds is specified in the received group.
+        // If the group's cards are not updated, and nextPollSeconds is
+        // unspecified, this method doesn't change group's nextPollTime.
       }
 
+      // 'nextPollSeconds' may be sent even for groups that don't contain cards
+      // updates.
       if (receivedGroup.nextPollSeconds !== undefined) {
         storageGroup.nextPollTime =
             now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
@@ -575,7 +585,7 @@
 
       for (var groupName in items.notificationGroups) {
         var group = items.notificationGroups[groupName];
-        if (group.nextPollTime <= now)
+        if (group.nextPollTime !== undefined && group.nextPollTime <= now)
           groupsToRequest.push(groupName);
       }
     }
@@ -920,14 +930,19 @@
  *     the geolocation option is enabled.
  * @param {boolean} enableBackground true if
  *     the background permission should be requested.
+ * @param {boolean} notificationEnabled true if
+ *     Google Now for Chrome is allowed to show notifications.
  */
 function updateRunningState(
     signedIn,
     geolocationEnabled,
-    enableBackground) {
+    enableBackground,
+    notificationEnabled) {
   console.log(
       'State Update signedIn=' + signedIn + ' ' +
-      'geolocationEnabled=' + geolocationEnabled);
+      'geolocationEnabled=' + geolocationEnabled + ' ' +
+      'enableBackground=' + enableBackground + ' ' +
+      'notificationEnabled=' + notificationEnabled);
 
   // TODO(vadimt): Remove this line once state machine design is finalized.
   geolocationEnabled = true;
@@ -935,7 +950,7 @@
   var shouldPollCards = false;
   var shouldSetBackground = false;
 
-  if (signedIn) {
+  if (signedIn && notificationEnabled) {
     if (geolocationEnabled) {
       if (enableBackground)
         shouldSetBackground = true;
@@ -960,14 +975,15 @@
  */
 function onStateChange() {
   tasks.add(STATE_CHANGED_TASK_NAME, function() {
-    authenticationManager.isSignedIn(function(token) {
-      var signedIn = !!token;
+    authenticationManager.isSignedIn(function(signedIn) {
       instrumented.metricsPrivate.getVariationParams(
           'GoogleNow',
           function(response) {
             var enableBackground =
                 (!response || (response.enableBackground != 'false'));
-            instrumented.
+            instrumented.notifications.getPermissionLevel(function(level) {
+              var notificationEnabled = (level == 'granted');
+              instrumented.
                 preferencesPrivate.
                 googleGeolocationAccessEnabled.
                 get({}, function(prefValue) {
@@ -975,8 +991,10 @@
                   updateRunningState(
                       signedIn,
                       geolocationEnabled,
-                      enableBackground);
+                      enableBackground,
+                      notificationEnabled);
                 });
+            });
           });
     });
   });
@@ -1044,6 +1062,12 @@
 
 instrumented.notifications.onClosed.addListener(onNotificationClosed);
 
+instrumented.notifications.onPermissionLevelChanged.addListener(
+    function(permissionLevel) {
+      console.log('Notifications permissionLevel Change');
+      onStateChange();
+    });
+
 instrumented.location.onLocationUpdate.addListener(function(position) {
   recordEvent(GoogleNowEvent.LOCATION_UPDATE);
   updateNotificationsCards(position);
@@ -1055,15 +1079,26 @@
   // So, we need to poll the server only when the payload is non-empty and has
   // changed.
   console.log('pushMessaging.onMessage ' + JSON.stringify(message));
-  if (message.subchannelId == SUBCHANNEL_ID_POLL_NOW && message.payload) {
+  if (message.payload.indexOf('REQUEST_CARDS') == 0) {
     tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
-      instrumented.storage.local.get('lastPollNowPayload', function(items) {
-        if (items && items.lastPollNowPayload != message.payload) {
-          chrome.storage.local.set({lastPollNowPayload: message.payload});
+      instrumented.storage.local.get('lastPollNowPayloads', function(items) {
+        // If storage.get fails, it's safer to do nothing, preventing polling
+        // the server when the payload really didn't change.
+        if (!items)
+          return;
+
+        // If this is the first time we get lastPollNowPayloads, initialize it.
+        items.lastPollNowPayloads = items.lastPollNowPayloads || {};
+
+        if (items.lastPollNowPayloads[message.subchannelId] !=
+            message.payload) {
+          items.lastPollNowPayloads[message.subchannelId] = message.payload;
+          chrome.storage.local.set(
+              {lastPollNowPayloads: items.lastPollNowPayloads});
 
           updateCardsAttempts.isRunning(function(running) {
             if (running)
-              requestNotificationGroups([]);
+              requestNotificationGroups(['PUSH' + message.subchannelId]);
           });
         }
       });
diff --git a/chrome/browser/resources/google_now/background_test_util.js b/chrome/browser/resources/google_now/background_test_util.js
index 2d7109e..d7fafd5 100644
--- a/chrome/browser/resources/google_now/background_test_util.js
+++ b/chrome/browser/resources/google_now/background_test_util.js
@@ -22,6 +22,7 @@
 mockChromeEvent(instrumented, 'notifications.onButtonClicked');
 mockChromeEvent(instrumented, 'notifications.onClicked');
 mockChromeEvent(instrumented, 'notifications.onClosed');
+mockChromeEvent(instrumented, 'notifications.onPermissionLevelChanged');
 mockChromeEvent(
     instrumented, 'preferencesPrivate.googleGeolocationAccessEnabled.onChange');
 mockChromeEvent(instrumented, 'pushMessaging.onMessage');
diff --git a/chrome/browser/resources/google_now/background_unittest.gtestjs b/chrome/browser/resources/google_now/background_unittest.gtestjs
index a0c41ca..cc8e2da 100644
--- a/chrome/browser/resources/google_now/background_unittest.gtestjs
+++ b/chrome/browser/resources/google_now/background_unittest.gtestjs
@@ -320,6 +320,134 @@
           JSON.stringify(mergedCards));
     });
 
+TEST_F(
+    'GoogleNowBackgroundUnitTest',
+    'MergeAndShowNotificationCards',
+    function() {
+      // Tests mergeAndShowNotificationCards function.
+      // The test passes 2 groups to mergeAndShowNotificationCards, checks that
+      // it calls mergeGroup() for each of these groups and calls
+      // showNotificationCards() with the results of these mergeGroup() calls.
+
+      // Setup and expectations.
+      var testGroups = {
+        'TEST GROUP 1': {testField: 'TEST VALUE 1'},
+        'TEST GROUP 2': {testField: 'TEST VALUE 2'}
+      };
+
+      this.makeAndRegisterMockGlobals(['mergeGroup', 'showNotificationCards']);
+
+      var mergeGroupSavedArgs = new SaveMockArguments();
+      this.mockGlobals.expects(once()).
+          mergeGroup(
+              mergeGroupSavedArgs.match(eqJSON({})),
+              mergeGroupSavedArgs.match(eqJSON({testField: 'TEST VALUE 1'}))).
+          will(callFunction(function() {
+            mergeGroupSavedArgs.arguments[0].card1 = {
+              testValue: 'TEST CARD VALUE 1'
+            };
+          }));
+      this.mockGlobals.expects(once()).
+          mergeGroup(
+              mergeGroupSavedArgs.match(
+                  eqJSON({card1: {testValue: 'TEST CARD VALUE 1'}})),
+              mergeGroupSavedArgs.match(
+                  eqJSON({testField: 'TEST VALUE 2'}))).
+          will(callFunction(function() {
+              mergeGroupSavedArgs.arguments[0].card2 = {
+                testValue: 'TEST CARD VALUE 2'
+              };
+          }));
+      this.mockGlobals.expects(once()).
+          showNotificationCards(eqJSON({
+            card1: {testValue: 'TEST CARD VALUE 1'},
+            card2: {testValue: 'TEST CARD VALUE 2'}
+          }));
+
+      // Invoking the tested function.
+      mergeAndShowNotificationCards(testGroups);
+    });
+
+// TODO(vadimt): Add more tests for parseAndShowNotificationCards().
+TEST_F(
+    'GoogleNowBackgroundUnitTest',
+    'ParseAndShowNotificationCardsAdd1Remove1',
+    function() {
+      // Tests parseAndShowNotificationCards function for the case when the
+      // extension has 2 groups, and the server sends update with 2 groups, one
+      // of which is new, and another one matches a stored group. The client
+      // has to delete the group that didn't receive an update, keep the
+      // existing group that received an update, and add a new stored group for
+      // the new group from the server.
+
+      // Setup and expectations.
+      var serverResponse = {
+        groups: {
+          GROUP1: {},
+          GROUP2: {}
+        }
+      };
+
+      var storedGroups = {
+        GROUP2: {
+          cards: ['c2'],
+          cardsTimestamp: 239,
+          nextPollTime: 10000,
+          rank: 1
+        },
+        GROUP3: {
+          cards: ['c3'],
+          cardsTimestamp: 240,
+          nextPollTime: 10001,
+          rank: 2
+        }
+      };
+
+      var expectedUpdatedGroups = {
+        GROUP1: {
+          cards: []
+        },
+        GROUP2: {
+          cards: ['c2'],
+          cardsTimestamp: 239,
+          nextPollTime: 10000,
+          rank: 1
+        }
+      };
+
+      this.makeAndRegisterMockGlobals(
+          ['scheduleNextPoll', 'mergeAndShowNotificationCards', 'recordEvent']);
+
+      this.makeAndRegisterMockApis([
+        'chrome.storage.local.set',
+        'instrumented.storage.local.get'
+      ]);
+
+      var storageGetSavedArgs = new SaveMockArguments();
+      this.mockApis.expects(once()).
+          instrumented_storage_local_get(
+              storageGetSavedArgs.match(eq('notificationGroups')),
+              storageGetSavedArgs.match(ANYTHING)).
+          will(invokeCallback(
+              storageGetSavedArgs, 1, {notificationGroups: storedGroups}));
+
+      this.mockGlobals.expects(once()).
+          scheduleNextPoll(eqJSON(expectedUpdatedGroups));
+
+      this.mockApis.expects(once()).
+          chrome_storage_local_set(
+              eqJSON({notificationGroups: expectedUpdatedGroups}));
+
+      this.mockGlobals.expects(once()).
+          mergeAndShowNotificationCards(eqJSON(expectedUpdatedGroups));
+
+      this.mockGlobals.expects(once()).
+          recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
+
+      // Invoking the tested function.
+      parseAndShowNotificationCards(JSON.stringify(serverResponse));
+    });
+
 /**
  * Mocks global functions and APIs that initialize() depends upon.
  * @param {Test} fixture Test fixture.
@@ -336,6 +464,7 @@
     'chrome.storage.local.remove',
     'instrumented.metricsPrivate.getVariationParams',
     'instrumented.notifications.getAll',
+    'instrumented.notifications.getPermissionLevel',
     'instrumented.preferencesPrivate.googleGeolocationAccessEnabled.get',
     'instrumented.storage.local.get',
     'tasks.add',
@@ -354,13 +483,16 @@
  * @param {string} testIdentityToken getAuthToken callback token.
  * @param {boolean} testGeolocationPref Geolocation Preference callback value.
  * @param {object} testExperimentVariationParams Response of
- *     metricsPrivate.getVariationParams
+ *     metricsPrivate.getVariationParams.
+ * @param {string} testExperimentVariationParams Response of
+ *     notifications.getPermissionLevel.
  */
 function expectStateMachineCalls(
     fixture,
     testIdentityToken,
     testGeolocationPref,
-    testExperimentVariationParams) {
+    testExperimentVariationParams,
+    testNotificationPermissionLevel) {
   var authenticationManagerIsSignedInSavedArgs = new SaveMockArguments();
   fixture.mockApis.expects(once()).
       authenticationManager_isSignedIn(
@@ -386,6 +518,15 @@
       will(invokeCallback(
           googleGeolocationPrefGetSavedArgs, 1, {value: testGeolocationPref}));
 
+  var notificationGetPermissionLevelSavedArgs = new SaveMockArguments();
+  fixture.mockApis.expects(once()).
+      instrumented_notifications_getPermissionLevel(
+          notificationGetPermissionLevelSavedArgs.match(ANYTHING)).
+      will(invokeCallback(
+          notificationGetPermissionLevelSavedArgs,
+          0,
+          testNotificationPermissionLevel))
+
   fixture.mockGlobals.expects(once()).
       setBackgroundEnable(ANYTHING);
 }
@@ -425,6 +566,7 @@
       var testIdentityToken = undefined;
       var testGeolocationPref = false;
       var testExperimentVariationParams = {};
+      var testNotificationPermissionLevel = 'denied';
 
       mockInitializeDependencies(this);
 
@@ -440,7 +582,8 @@
           this,
           testIdentityToken,
           testGeolocationPref,
-          testExperimentVariationParams);
+          testExperimentVariationParams,
+          testNotificationPermissionLevel);
 
       // Invoking the tested function.
       initialize();
@@ -458,6 +601,7 @@
       var testIdentityToken = 'some identity token';
       var testGeolocationPref = false;
       var testExperimentVariationParams = {};
+      var testNotificationPermissionLevel = 'denied';
 
       mockInitializeDependencies(this);
 
@@ -470,7 +614,8 @@
           this,
           testIdentityToken,
           testGeolocationPref,
-          testExperimentVariationParams);
+          testExperimentVariationParams,
+          testNotificationPermissionLevel);
 
       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
       this.mockApis.expects(exactly(1)).
@@ -492,6 +637,7 @@
   var testIdentityToken = 'some identity token';
   var testGeolocationPref = true;
   var testExperimentVariationParams = {};
+  var testNotificationPermissionLevel = 'granted';
 
   mockInitializeDependencies(this);
 
@@ -504,7 +650,8 @@
       this,
       testIdentityToken,
       testGeolocationPref,
-      testExperimentVariationParams);
+      testExperimentVariationParams,
+      testNotificationPermissionLevel);
 
   this.mockGlobals.expects(once()).startPollingCards();
 
@@ -523,6 +670,7 @@
   var testIdentityToken = 'some identity token';
   var testGeolocationPref = false;
   var testExperimentVariationParams = {};
+  var testNotificationPermissionLevel = 'denied';
 
   mockInitializeDependencies(this);
 
@@ -538,7 +686,9 @@
       this,
       testIdentityToken,
       testGeolocationPref,
-      testExperimentVariationParams);
+      testExperimentVariationParams,
+      testNotificationPermissionLevel,
+      testNotificationPermissionLevel);
 
   var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
   this.mockApis.expects(exactly(2)).
diff --git a/chrome/browser/resources/google_now/manifest.json b/chrome/browser/resources/google_now/manifest.json
index d0668ef..2fd0aed 100644
--- a/chrome/browser/resources/google_now/manifest.json
+++ b/chrome/browser/resources/google_now/manifest.json
@@ -14,6 +14,7 @@
     "pushMessaging",
     "storage",
     "tabs",
+    "webstorePrivate",
     // TODO(vadimt): Replace <all_urls> with real URL patterns once we know
     // them.
     "<all_urls>"
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index 418b6f3..ab337ef 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -141,7 +141,13 @@
   request.onloadend = function(event) {
     console.log('sendErrorReport status: ' + request.status);
   };
-  request.send(JSON.stringify(errorObject));
+
+  chrome.identity.getAuthToken({interactive: false}, function(token) {
+    if (token) {
+      request.setRequestHeader('Authorization', 'Bearer ' + token);
+      request.send(JSON.stringify(errorObject));
+    }
+  });
 }
 
 // Limiting 1 error report per background page load.
@@ -393,7 +399,9 @@
 wrapper.instrumentChromeApiFunction('alarms.get', 1);
 wrapper.instrumentChromeApiFunction('alarms.onAlarm.addListener', 0);
 wrapper.instrumentChromeApiFunction('identity.getAuthToken', 1);
+wrapper.instrumentChromeApiFunction('identity.onSignInChanged.addListener', 0);
 wrapper.instrumentChromeApiFunction('identity.removeCachedAuthToken', 1);
+wrapper.instrumentChromeApiFunction('webstorePrivate.getBrowserLogin', 0);
 
 /**
  * Builds the object to manage tasks (mutually exclusive chains of events).
@@ -663,10 +671,7 @@
   };
 }
 
-// TODO(robliao): Ideally, the authentication watcher infrastructure
-// below would be an API change to chrome.identity.
-// When this happens, remove the code below.
-
+// TODO(robliao): Use signed-in state change watch API when it's available.
 /**
  * Wraps chrome.identity to provide limited listening support for
  * the sign in state by polling periodically for the auth token.
@@ -676,15 +681,24 @@
   var alarmName = 'sign-in-alarm';
 
   /**
-   * Determines if the user is signed in and provides a token if signed in.
+   * Gets an OAuth2 access token.
    * @param {function(string=)} callback Called on completion.
-   *     If the user is signed in, the string contains the token.
+   *     The string contains the token. It's undefined if there was an error.
    */
-  function isSignedIn(callback) {
+  function getAuthToken(callback) {
     instrumented.identity.getAuthToken({interactive: false}, function(token) {
       token = chrome.runtime.lastError ? undefined : token;
       callback(token);
-      checkAndNotifyListeners(!!token);
+    });
+  }
+
+  /**
+   * Determines whether there is an account attached to the profile.
+   * @param {function(boolean)} callback Called on completion.
+   */
+  function isSignedIn(callback) {
+    instrumented.webstorePrivate.getBrowserLogin(function(accountInfo) {
+      callback(!!accountInfo.login);
     });
   }
 
@@ -695,10 +709,8 @@
    */
   function removeToken(token, callback) {
     instrumented.identity.removeCachedAuthToken({token: token}, function() {
-      // Removing the token from the cache will change the sign in state.
-      // Repoll now to check the state and notify listeners.
-      // This also lets Chrome now about a possible problem with the token.
-      isSignedIn(function() {});
+      // Let Chrome now about a possible problem with the token.
+      getAuthToken(function() {});
       callback();
     });
   }
@@ -715,28 +727,33 @@
   }
 
   /**
-   * Checks if the last signed in state matches the specified one.
+   * Checks if the last signed in state matches the current one.
    * If it doesn't, it notifies the listeners of the change.
-   * @param {boolean} currentSignedInState The current signed in state.
    */
-  function checkAndNotifyListeners(currentSignedInState) {
-    instrumented.storage.local.get('lastSignedInState', function(items) {
-      items = items || {};
-      if (items.lastSignedInState != currentSignedInState) {
-        chrome.storage.local.set(
-            {lastSignedInState: currentSignedInState});
-        if (items.lastSignedInState != undefined) {
-          listeners.forEach(function(callback) {
-            callback();
-          });
+  function checkAndNotifyListeners() {
+    isSignedIn(function(signedIn) {
+      instrumented.storage.local.get('lastSignedInState', function(items) {
+        items = items || {};
+        if (items.lastSignedInState != signedIn) {
+          chrome.storage.local.set(
+              {lastSignedInState: signedIn});
+          if (items.lastSignedInState != undefined) {
+            listeners.forEach(function(callback) {
+              callback();
+            });
+          }
         }
-      }
+      });
     });
   }
 
+  instrumented.identity.onSignInChanged.addListener(function() {
+    checkAndNotifyListeners();
+  });
+
   instrumented.alarms.onAlarm.addListener(function(alarm) {
     if (alarm.name == alarmName)
-      isSignedIn(function() {});
+      checkAndNotifyListeners();
   });
 
   // Poll for the sign in state every hour.
@@ -745,6 +762,7 @@
 
   return {
     addListener: addListener,
+    getAuthToken: getAuthToken,
     isSignedIn: isSignedIn,
     removeToken: removeToken
   };
diff --git a/chrome/browser/resources/google_now/utility_test_util.js b/chrome/browser/resources/google_now/utility_test_util.js
index 3ef36d1..d06f43c 100644
--- a/chrome/browser/resources/google_now/utility_test_util.js
+++ b/chrome/browser/resources/google_now/utility_test_util.js
@@ -13,6 +13,10 @@
   getAuthToken: emptyMock,
   removeCachedAuthToken: emptyMock
 };
+chrome['webstorePrivate'] = {
+  getBrowserLogin: emptyMock
+};
 
 mockChromeEvent(chrome, 'alarms.onAlarm');
+mockChromeEvent(chrome, 'identity.onSignInChanged');
 mockChromeEvent(chrome, 'runtime.onSuspend');
diff --git a/chrome/browser/resources/google_now/utility_unittest.gtestjs b/chrome/browser/resources/google_now/utility_unittest.gtestjs
index c8638f6..64ba1d8 100644
--- a/chrome/browser/resources/google_now/utility_unittest.gtestjs
+++ b/chrome/browser/resources/google_now/utility_unittest.gtestjs
@@ -41,10 +41,16 @@
     message: 'TEST ERROR MESSAGE'
   };
 
-  this.makeAndRegisterMockGlobals(['buildServerRequest']);
-  this.makeMockLocalFunctions(['sendRequest']);
+  var testIdentityToken = 'test identity token';
 
-  var mockRequest = {send: this.mockLocalFunctions.functions().sendRequest};
+  this.makeAndRegisterMockGlobals(['buildServerRequest']);
+  this.makeMockLocalFunctions(['sendRequest', 'setRequestHeader']);
+  this.makeAndRegisterMockApis(['chrome.identity.getAuthToken']);
+
+  var mockRequest = {
+    send: this.mockLocalFunctions.functions().sendRequest,
+    setRequestHeader: this.mockLocalFunctions.functions().setRequestHeader
+  };
 
   var expectedRequestObject = {
     message: 'TEST ERROR NAME: TEST ERROR MESSAGE',
@@ -62,6 +68,20 @@
   this.mockGlobals.expects(once()).
       buildServerRequest('POST', 'jserrors', 'application/json').
       will(returnValue(mockRequest));
+
+  var chromeIdentityGetAuthTokenSavedArgs = new SaveMockArguments();
+  this.mockApis.expects(once()).
+      chrome_identity_getAuthToken(
+          chromeIdentityGetAuthTokenSavedArgs.match(
+              eqJSON({interactive: false})),
+          chromeIdentityGetAuthTokenSavedArgs.match(ANYTHING)).
+      will(invokeCallback(
+          chromeIdentityGetAuthTokenSavedArgs,
+          1,
+          testIdentityToken));
+
+  this.mockLocalFunctions.expects(once()).setRequestHeader(
+      'Authorization', 'Bearer test identity token');
   this.mockLocalFunctions.expects(once()).sendRequest(
       JSON.stringify(expectedRequestObject));
 
@@ -84,10 +104,16 @@
     name: 'TypeError'
   };
 
-  this.makeAndRegisterMockGlobals(['buildServerRequest']);
-  this.makeMockLocalFunctions(['sendRequest']);
+  var testIdentityToken = 'test identity token';
 
-  var mockRequest = {send: this.mockLocalFunctions.functions().sendRequest};
+  this.makeAndRegisterMockGlobals(['buildServerRequest']);
+  this.makeMockLocalFunctions(['sendRequest', 'setRequestHeader']);
+  this.makeAndRegisterMockApis(['chrome.identity.getAuthToken']);
+
+  var mockRequest = {
+    send: this.mockLocalFunctions.functions().sendRequest,
+    setRequestHeader: this.mockLocalFunctions.functions().setRequestHeader
+  };
 
   var expectedRequestObject = {
     message: 'TypeError',
@@ -101,6 +127,20 @@
   this.mockGlobals.expects(once()).
       buildServerRequest('POST', 'jserrors', 'application/json').
       will(returnValue(mockRequest));
+
+  var chromeIdentityGetAuthTokenSavedArgs = new SaveMockArguments();
+  this.mockApis.expects(once()).
+      chrome_identity_getAuthToken(
+          chromeIdentityGetAuthTokenSavedArgs.match(
+              eqJSON({interactive: false})),
+          chromeIdentityGetAuthTokenSavedArgs.match(ANYTHING)).
+      will(invokeCallback(
+          chromeIdentityGetAuthTokenSavedArgs,
+          1,
+          testIdentityToken));
+
+  this.mockLocalFunctions.expects(once()).setRequestHeader(
+      'Authorization', 'Bearer test identity token');
   this.mockLocalFunctions.expects(once()).sendRequest(
       JSON.stringify(expectedRequestObject));
 
diff --git a/chrome/browser/resources/hangout_services/background.html b/chrome/browser/resources/hangout_services/background.html
new file mode 100644
index 0000000..08424b1
--- /dev/null
+++ b/chrome/browser/resources/hangout_services/background.html
@@ -0,0 +1,17 @@
+<!--
+Copyright 2013 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.
+
+We use an HTML page just to have access to the DOM, for URL
+parsing. An alternative would be to include a URL parsing JavaScript
+library with the extension but this approach is likely smaller and
+faster.
+-->
+<html>
+<head>
+<script src="thunk.js"></script>
+</head>
+<body>
+</body>
+</html>
diff --git a/chrome/browser/resources/hangout_services/manifest.json b/chrome/browser/resources/hangout_services/manifest.json
new file mode 100644
index 0000000..0e511dd
--- /dev/null
+++ b/chrome/browser/resources/hangout_services/manifest.json
@@ -0,0 +1,25 @@
+{
+  // Extension ID: nkeimhogjdpnpccoofpliimaahmaaome
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAQt2ZDdPfoSe/JI6ID5bgLHRCnCu9T36aYczmhw/tnv6QZB2I6WnOCMZXJZlRdqWc7w9jo4BWhYS50Vb4weMfh/I0On7VcRwJUgfAxW2cHB+EkmtI1v4v/OU24OqIa1Nmv9uRVeX0GjhQukdLNhAE6ACWooaf5kqKlCeK+1GOkQIDAQAB",
+
+  "name": "Hangout Services",
+  "version": "1.0",
+  "manifest_version": 2,
+  "externally_connectable": {
+    "matches": [
+      "https://*.google.com/hangouts*",
+      // For tests.
+      "*://localhost/*"
+    ]
+  },
+  "background": {
+    "page": "background.html",
+    "persistent": false
+  },
+  "permissions": [
+    "desktopCapture",
+    "system.cpu",
+    "webrtcAudioPrivate",
+    "webrtcLoggingPrivate"
+  ]
+}
diff --git a/chrome/browser/resources/hangout_services/thunk.js b/chrome/browser/resources/hangout_services/thunk.js
new file mode 100644
index 0000000..b2ef655
--- /dev/null
+++ b/chrome/browser/resources/hangout_services/thunk.js
@@ -0,0 +1,77 @@
+// Copyright 2013 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.
+
+chrome.runtime.onMessageExternal.addListener(
+    function(message, sender, sendResponse) {
+  function doSendResponse(value, error) {
+    var errorMessage = error || chrome.extension.lastError;
+    sendResponse({'value': value, 'error': errorMessage});
+  }
+
+  function getHost(url) {
+    if (!url)
+      return '';
+    // Use the DOM to parse the URL. Since we don't add the anchor to
+    // the page, this is the only reference to it and it will be
+    // deleted once it's gone out of scope.
+    var a = document.createElement('a');
+    a.href = url;
+    return a.hostname;
+  }
+
+  try {
+    var method = message['method'];
+    var origin = getHost(sender.url);
+    if (method == 'chooseDesktopMedia') {
+      chrome.desktopCapture.chooseDesktopMedia(
+          ['screen', 'window'], sender.tab, doSendResponse);
+      return true;
+    } else if (method == 'cpu.getInfo') {
+      chrome.system.cpu.getInfo(doSendResponse);
+      return true;
+    } else if (method == 'logging.setMetadata') {
+      var metaData = message['metaData'];
+      chrome.webrtcLoggingPrivate.setMetaData(
+          sender.tab.id, origin, metaData, doSendResponse);
+      return true;
+    } else if (method == 'logging.start') {
+      chrome.webrtcLoggingPrivate.start(sender.tab.id, origin, doSendResponse);
+      return true;
+    } else if (method == 'logging.uploadOnRenderClose') {
+      chrome.webrtcLoggingPrivate.setUploadOnRenderClose(
+          sender.tab.id, origin, true);
+      doSendResponse();
+      return false;
+    } else if (method == 'logging.stop') {
+      chrome.webrtcLoggingPrivate.stop(sender.tab.id, origin, doSendResponse);
+      return true;
+    } else if (method == 'logging.upload') {
+      chrome.webrtcLoggingPrivate.upload(sender.tab.id, origin, doSendResponse);
+      return true;
+    } else if (method == 'logging.discard') {
+      chrome.webrtcLoggingPrivate.discard(
+          sender.tab.id, origin, doSendResponse);
+      return true;
+    } else if (method == 'getSinks') {
+      chrome.webrtcAudioPrivate.getSinks(doSendResponse);
+      return true;
+    } else if (method == 'getActiveSink') {
+      chrome.webrtcAudioPrivate.getActiveSink(sender.tab.id, doSendResponse);
+      return true;
+    } else if (method == 'setActiveSink') {
+      var sinkId = message['sinkId'];
+      chrome.webrtcAudioPrivate.setActiveSink(
+          sender.tab.id, sinkId, doSendResponse);
+      return true;
+    } else if (method == 'getAssociatedSink') {
+      var sourceId = message['sourceId'];
+      chrome.webrtcAudioPrivate.getAssociatedSink(
+          origin, sourceId, doSendResponse);
+      return true;
+    }
+    throw new Error('Unknown method: ' + method);
+  } catch (e) {
+    doSendResponse(null, e.name + ': ' + e.message);
+  }
+});
diff --git a/chrome/browser/resources/history/history.css b/chrome/browser/resources/history/history.css
index 61bddb3..d0ed9ce 100644
--- a/chrome/browser/resources/history/history.css
+++ b/chrome/browser/resources/history/history.css
@@ -289,19 +289,6 @@
   font-size: 1.5em;
 }
 
-.snippet {
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-  -webkit-margin-start: 136px;
-  clear: both;
-  color: rgb(34, 34, 34);
-  display: -webkit-box;
-  line-height: 1.6em;
-  margin-bottom: 1em;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
 .entry .domain {
   color: rgb(151, 156, 160);
   min-width: -webkit-min-content;
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index a524b7e..4dd7ed2 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -93,7 +93,6 @@
   this.url_ = result.url;
   this.domain_ = result.domain;
   this.starred_ = result.starred;
-  this.snippet_ = result.snippet || '';
 
   // These identify the name and type of the device on which this visit
   // occurred. They will be empty if the visit occurred on the current device.
@@ -213,6 +212,8 @@
 
   if (isMobileVersion()) {
     var removeButton = createElementWithClassName('button', 'remove-entry');
+    removeButton.setAttribute('aria-label',
+                              loadTimeData.getString('removeFromHistory'));
     removeButton.classList.add('custom-appearance');
     removeButton.addEventListener('click', function(e) {
       self.removeFromHistory();
@@ -253,14 +254,7 @@
   node.appendChild(entryBoxContainer);
   entryBoxContainer.appendChild(entryBox);
 
-  if (isSearchResult) {
-    time.appendChild(document.createTextNode(this.dateShort));
-    var snippet = createElementWithClassName('div', 'snippet');
-    this.addHighlightedText_(snippet,
-                             this.snippet_,
-                             this.model_.getSearchText());
-    node.appendChild(snippet);
-  } else if (useMonthDate) {
+  if (isSearchResult || useMonthDate) {
     // Show the day instead of the time.
     time.appendChild(document.createTextNode(this.dateShort));
   } else {
diff --git a/chrome/browser/resources/history/history_mobile.css b/chrome/browser/resources/history/history_mobile.css
index df6d6e1..fef07f3 100644
--- a/chrome/browser/resources/history/history_mobile.css
+++ b/chrome/browser/resources/history/history_mobile.css
@@ -102,8 +102,7 @@
 
 #remove-selected,
 #search-button,
-.gap,
-.snippet {
+.gap {
   display: none;
 }
 
@@ -312,6 +311,7 @@
 }
 
 .ios-keyboard-visible #scrolling-container {
-  bottom: 0;
+  /* Should be 0, but that breaks scrolling -- see crbug.com/292715. */
+  bottom: -1px;
 }
 </if> /* is_ios */
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 6c4c680..c334844 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -17,7 +17,7 @@
   height: 16px;
   padding-left: 2px;
   padding-right: 5px;
-  position: absolute;
+  vertical-align: top;
   width: 16px;
 }
 
@@ -139,12 +139,15 @@
 }
 
 .row {
-  -webkit-flex-direction: row;
-  display: -webkit-flex;
   padding: 6px 0;
   position: relative;
 }
 
+.subrow-box {
+  display: inline-block;
+  vertical-align: top;
+}
+
 .subrow {
   -webkit-box-orient: horizontal;
   display: -webkit-box;
@@ -154,23 +157,17 @@
   margin-right: 0.5em;
 }
 
-.subrow.main {
-  margin-left: 21px;
-}
-
 .webview-thumbnail {
-  -webkit-box-align: center;
-  -webkit-box-orient: horizontal;
-  -webkit-box-pack: center;
-  display: -webkit-box;
-  height: 60px;
-  margin: 0 1px;
+  display: inline-block;
+  margin-right: 5px;
   overflow: hidden;
+  position: relative;
+  vertical-align: top;
 }
 
 .screen-rect {
   background-color: #eee;
-  position: relative;
+  position: absolute;
 }
 
 .view-rect {
@@ -184,12 +181,7 @@
   background-color: #ddd;
 }
 
-#apps-list > .row {
-  -webkit-flex-direction: column;
-}
-
 .guest {
-  -webkit-flex-direction: row;
   padding-left: 20px;
 }
 
@@ -207,7 +199,10 @@
 
 a {
   color: rgb(17, 85, 204);
-  margin-right: 6px;
+  margin-right: 15px;
+}
+
+a:not(:hover) {
   text-decoration: none;
 }
 
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 988b425..9a1e34f 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -15,8 +15,8 @@
   chrome.send('activate', [data]);
 }
 
-function terminate(data) {
-  chrome.send('terminate', [data]);
+function close(data) {
+  chrome.send('close', [data]);
 }
 
 function reload(data) {
@@ -69,7 +69,7 @@
   window.location.hash = id;
 }
 
-function populateLists(data) {
+function populateWebContentsTargets(data) {
   removeChildren('pages-list');
   removeChildren('extensions-list');
   removeChildren('apps-list');
@@ -78,7 +78,7 @@
   for (var i = 0; i < data.length; i++) {
     if (data[i].type === 'page')
       addToPagesList(data[i]);
-    else if (data[i].type === 'extension')
+    else if (data[i].type === 'background_page')
       addToExtensionsList(data[i]);
     else if (data[i].type === 'app')
       addToAppsList(data[i]);
@@ -87,17 +87,22 @@
   }
 }
 
-function populateWorkersList(data) {
+function populateWorkerTargets(data) {
   removeChildren('workers-list');
 
   for (var i = 0; i < data.length; i++)
     addToWorkersList(data[i]);
 }
 
-function populateDeviceLists(devices) {
+function populateRemoteTargets(devices) {
   if (!devices)
     return;
 
+  if (window.modal) {
+    window.holdDevices = devices;
+    return;
+  }
+
   function alreadyDisplayed(element, data) {
     var json = JSON.stringify(data);
     if (element.cachedJSON == json)
@@ -294,12 +299,12 @@
           addFavicon(row, page);
         if (isChrome) {
           if (majorChromeVersion >= MIN_VERSION_TAB_ACTIVATE) {
-            addActionLink(row, 'activate', activate.bind(null, page), false);
+            addActionLink(row, 'focus tab', activate.bind(null, page), false);
           }
           addActionLink(row, 'reload', reload.bind(null, page), page.attached);
           if (majorChromeVersion >= MIN_VERSION_TAB_CLOSE) {
             addActionLink(
-                row, 'close', terminate.bind(null, page), page.attached);
+                row, 'close', close.bind(null, page), page.attached);
           }
         }
       }
@@ -330,8 +335,9 @@
 }
 
 function addToWorkersList(data) {
-  var row = addTargetToList(data, $('workers-list'), ['pid', 'url']);
-  addActionLink(row, 'terminate', terminate.bind(null, data), data.attached);
+  var row =
+      addTargetToList(data, $('workers-list'), ['name', 'description', 'url']);
+  addActionLink(row, 'terminate', close.bind(null, data), data.attached);
 }
 
 function addToOthersList(data) {
@@ -349,9 +355,6 @@
   if (text.length > 100)
     text = text.substring(0, 100) + '\u2026';
 
-  if (property == 'pid')
-    text = 'Pid:' + text;
-
   var span = document.createElement('div');
   span.textContent = text;
   span.className = property;
@@ -426,10 +429,14 @@
   var thumbnail = document.createElement('div');
   thumbnail.className = 'webview-thumbnail';
   var thumbnailWidth = 3 * screenRectWidth;
+  var thumbnailHeight = 60;
   thumbnail.style.width = thumbnailWidth + 'px';
+  thumbnail.style.height = thumbnailHeight + 'px';
 
   var screenRect = document.createElement('div');
   screenRect.className = 'screen-rect';
+  screenRect.style.left = screenRectWidth + 'px';
+  screenRect.style.top = (thumbnailHeight - screenRectHeight) / 2 + 'px';
   screenRect.style.width = screenRectWidth + 'px';
   screenRect.style.height = screenRectHeight + 'px';
   thumbnail.appendChild(screenRect);
@@ -457,6 +464,7 @@
   row.className = 'row';
 
   var subrowBox = document.createElement('div');
+  subrowBox.className = 'subrow-box';
   row.appendChild(subrowBox);
 
   var subrow = document.createElement('div');
@@ -505,7 +513,7 @@
   $('port-forwarding-config-close').addEventListener(
       'click', closePortForwardingConfig);
   $('port-forwarding-config-done').addEventListener(
-      'click', commitPortForwardingConfig);
+      'click', commitPortForwardingConfig.bind(true));
 }
 
 function enableDiscoverUsbDevices(event) {
@@ -522,21 +530,56 @@
       if (event.target.nodeName == 'INPUT') {
         var line = event.target.parentNode;
         if (!line.classList.contains('fresh') ||
-            line.classList.contains('empty'))
-          commitPortForwardingConfig();
-        else
+            line.classList.contains('empty')) {
+          commitPortForwardingConfig(true);
+        } else {
           commitFreshLineIfValid(true /* select new line */);
+          commitPortForwardingConfig(false);
+        }
       } else {
-        commitPortForwardingConfig();
+        commitPortForwardingConfig(true);
       }
       break;
 
     case 27:
-      closePortForwardingConfig();
+      commitPortForwardingConfig(true);
       break;
   }
 }
 
+function setModal(dialog) {
+  dialog.deactivatedNodes = Array.prototype.filter.call(
+      document.querySelectorAll('*'),
+      function(n) {
+        return n != dialog && !dialog.contains(n) && n.tabIndex >= 0;
+      });
+
+  dialog.tabIndexes = dialog.deactivatedNodes.map(
+    function(n) { return n.getAttribute('tabindex'); });
+
+  dialog.deactivatedNodes.forEach(function(n) { n.tabIndex = -1; });
+  window.modal = dialog;
+}
+
+function unsetModal(dialog) {
+  for (var i = 0; i < dialog.deactivatedNodes.length; i++) {
+    var node = dialog.deactivatedNodes[i];
+    if (dialog.tabIndexes[i] === null)
+      node.removeAttribute('tabindex');
+    else
+      node.setAttribute('tabindex', tabIndexes[i]);
+  }
+
+  if (window.holdDevices) {
+    populateDeviceLists(window.holdDevices);
+    delete window.holdDevices;
+  }
+
+  delete dialog.deactivatedNodes;
+  delete dialog.tabIndexes;
+  delete window.modal;
+}
+
 function openPortForwardingConfig() {
   loadPortForwardingConfig(window.portForwardingConfig);
 
@@ -548,11 +591,14 @@
     freshPort.focus();
   else
     $('port-forwarding-config-done').focus();
+
+  setModal($('port-forwarding-overlay'));
 }
 
 function closePortForwardingConfig() {
   $('port-forwarding-overlay').classList.remove('open');
   document.removeEventListener('keyup', handleKey);
+  unsetModal($('port-forwarding-overlay'));
 }
 
 function loadPortForwardingConfig(config) {
@@ -563,25 +609,28 @@
   list.appendChild(createEmptyConfigLine());
 }
 
-function commitPortForwardingConfig() {
-  if (document.querySelector(
-      '.port-forwarding-pair:not(.fresh) input.invalid'))
-    return;
+function commitPortForwardingConfig(closeConfig) {
+  if (closeConfig)
+    closePortForwardingConfig();
 
-  if (document.querySelector(
-      '.port-forwarding-pair.fresh:not(.empty) input.invalid'))
-    return;
-
-  closePortForwardingConfig();
   commitFreshLineIfValid();
   var lines = document.querySelectorAll('.port-forwarding-pair');
   var config = {};
   for (var i = 0; i != lines.length; i++) {
     var line = lines[i];
-    var portInput = line.querySelector('.port:not(.invalid)');
-    var locationInput = line.querySelector('.location:not(.invalid)');
-    if (portInput && locationInput)
-      config[portInput.value] = locationInput.value;
+    var portInput = line.querySelector('.port');
+    var locationInput = line.querySelector('.location');
+
+    var port = portInput.classList.contains('invalid') ?
+               portInput.lastValidValue :
+               portInput.value;
+
+    var location = locationInput.classList.contains('invalid') ?
+                   locationInput.lastValidValue :
+                   locationInput.value;
+
+    if (port && location)
+      config[port] = location;
   }
   chrome.send('set-port-forwarding-config', [config]);
 }
@@ -679,6 +728,7 @@
   input.type = 'text';
   input.placeholder = hint;
   input.value = value;
+  input.lastValidValue = value;
 
   function checkInput() {
     if (validate(input))
@@ -695,6 +745,11 @@
     selectLine(input.parentNode);
   });
 
+  input.addEventListener('blur', function() {
+    if (validate(input))
+      input.lastValidValue = input.value;
+  });
+
   return input;
 }
 
diff --git a/chrome/browser/resources/net_internals/prerender_view.html b/chrome/browser/resources/net_internals/prerender_view.html
index dc4ab95..9d254f6 100644
--- a/chrome/browser/resources/net_internals/prerender_view.html
+++ b/chrome/browser/resources/net_internals/prerender_view.html
@@ -29,7 +29,7 @@
     </thead>
     <tbody id=prerender-view-active-table>
       <tr jsselect="active">
-        <td><a jsvalues=".href:url" jscontent="url" target="_blank"></a></td>
+        <td jscontent="url"></td>
         <td jscontent="duration"></td>
         <td jscontent="is_loaded"></td>
       </tr>
@@ -48,7 +48,7 @@
     <tbody id=prerender-view-history-table>
       <tr jsselect="$this.history" jsvalues=".className: final_status.toLowerCase()">
         <td jscontent="origin"></td>
-        <td><a jsvalues=".href:url" jscontent="url" target="_blank"></a></td>
+        <td jscontent="url"></td>
         <td jscontent="final_status"></td>
         <td jscontent="timeutil.dateToString(new Date(parseInt(end_time)))"></td>
       </tr>
diff --git a/chrome/browser/resources/net_internals/quic_view.html b/chrome/browser/resources/net_internals/quic_view.html
index b40cedd..24fdbc4 100644
--- a/chrome/browser/resources/net_internals/quic_view.html
+++ b/chrome/browser/resources/net_internals/quic_view.html
@@ -20,6 +20,7 @@
               <th>GUID</th>
               <th>Active streams</th>
               <th>Total streams</th>
+              <th>Connected</th>
             </tr>
           </thead>
           <tbody>
@@ -32,6 +33,7 @@
               <td jscontent="guid"></td>
               <td jscontent="open_streams"></td>
               <td jscontent="total_streams"></td>
+              <td jscontent="connected"></td>
             </tr>
           </tbody>
         </table>
diff --git a/chrome/browser/resources/net_internals/socket_pool_wrapper.js b/chrome/browser/resources/net_internals/socket_pool_wrapper.js
index 0a9b455..77e4933 100644
--- a/chrome/browser/resources/net_internals/socket_pool_wrapper.js
+++ b/chrome/browser/resources/net_internals/socket_pool_wrapper.js
@@ -131,7 +131,7 @@
       tablePrinter.addHeaderCell('Active');
       tablePrinter.addHeaderCell('Idle');
       tablePrinter.addHeaderCell('Connect Jobs');
-      tablePrinter.addHeaderCell('Backup Job');
+      tablePrinter.addHeaderCell('Backup Timer');
       tablePrinter.addHeaderCell('Stalled');
 
       for (var groupName in this.origPool.groups) {
@@ -152,7 +152,8 @@
         idleCell.link = sourceListLink(group.idle_sockets);
         connectingCell.link = sourceListLink(group.connect_jobs);
 
-        tablePrinter.addCell(group.has_backup_job);
+        tablePrinter.addCell(
+            group.backup_job_timer_is_running ? 'started' : 'stopped');
         tablePrinter.addCell(group.is_stalled);
       }
       return tablePrinter;
diff --git a/chrome/browser/resources/ntp4/apps_page.js b/chrome/browser/resources/ntp4/apps_page.js
index b20cca8..210e305 100644
--- a/chrome/browser/resources/ntp4/apps_page.js
+++ b/chrome/browser/resources/ntp4/apps_page.js
@@ -49,7 +49,10 @@
       this.launch_.addEventListener('activate', this.onLaunch_.bind(this));
 
       menu.appendChild(cr.ui.MenuItem.createSeparator());
-      this.launchRegularTab_ = this.appendMenuItem_('applaunchtyperegular');
+      if (loadTimeData.getBoolean('enableStreamlinedHostedApps'))
+        this.launchRegularTab_ = this.appendMenuItem_('applaunchtypetab');
+      else
+        this.launchRegularTab_ = this.appendMenuItem_('applaunchtyperegular');
       this.launchPinnedTab_ = this.appendMenuItem_('applaunchtypepinned');
       if (!cr.isMac)
         this.launchNewWindow_ = this.appendMenuItem_('applaunchtypewindow');
@@ -128,10 +131,14 @@
 
       this.launch_.textContent = app.appData.title;
 
+      var launchTypeRegularTab = this.launchRegularTab_;
       this.forAllLaunchTypes_(function(launchTypeButton, id) {
         launchTypeButton.disabled = false;
         launchTypeButton.checked = app.appData.launch_type == id;
-        launchTypeButton.hidden = app.appData.packagedApp;
+        // Streamlined hosted apps should only show the "Open as tab" button.
+        launchTypeButton.hidden = app.appData.packagedApp ||
+            (loadTimeData.getBoolean('enableStreamlinedHostedApps') &&
+             launchTypeButton != launchTypeRegularTab);
       });
 
       this.launchTypeMenuSeparator_.hidden = app.appData.packagedApp;
@@ -163,8 +170,15 @@
     onLaunchTypeChanged_: function(e) {
       var pressed = e.currentTarget;
       var app = this.app_;
+      var targetLaunchType = pressed;
+      // Streamlined hosted apps can only toggle between open as window and open
+      // as tab.
+      if (loadTimeData.getBoolean('enableStreamlinedHostedApps')) {
+        targetLaunchType = this.launchRegularTab_.checked ?
+            this.launchNewWindow_ : this.launchRegularTab_;
+      }
       this.forAllLaunchTypes_(function(launchTypeButton, id) {
-        if (launchTypeButton == pressed) {
+        if (launchTypeButton == targetLaunchType) {
           chrome.send('setLaunchType', [app.appId, id]);
           // Manually update the launch type. We will only get
           // appsPrefChangeCallback calls after changes to other NTP instances.
diff --git a/chrome/browser/resources/ntp4/most_visited_page.js b/chrome/browser/resources/ntp4/most_visited_page.js
index 0ec1124..f2fef81 100644
--- a/chrome/browser/resources/ntp4/most_visited_page.js
+++ b/chrome/browser/resources/ntp4/most_visited_page.js
@@ -146,6 +146,9 @@
         // Records the index of this tile.
         chrome.send('metricsHandler:recordInHistogram',
                     ['NewTabPage.MostVisited', this.index, 8]);
+        // Records the action. This will be available as a time-stamped stream
+        // server-side and can be used to compute time-to-long-dwell.
+        chrome.send('metricsHandler:recordAction', ['MostVisited_Clicked']);
         chrome.send('mostVisitedAction',
                     [ntp.NtpFollowAction.CLICKED_TILE]);
       }
diff --git a/chrome/browser/resources/ntp_android/OWNERS b/chrome/browser/resources/ntp_android/OWNERS
index c7eba94..bd8e785 100644
--- a/chrome/browser/resources/ntp_android/OWNERS
+++ b/chrome/browser/resources/ntp_android/OWNERS
@@ -1,2 +1,3 @@
+newt@chromium.org
 tedchoc@chromium.org
-yfriedman@chromium.org
+
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 5fd32d5..136d733 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -331,7 +331,7 @@
       </div>
 <if expr="pp_ifdef('chromeos')">
       <div class="checkbox">
-        <span class="controlled-settings-with-label">
+        <span class="controlled-setting-with-label">
           <input id="content-protection-attestation-enabled" type="checkbox"
               pref="cros.device.attestation_for_content_protection_enabled">
           <span>
@@ -341,9 +341,9 @@
             <a target="_blank" i18n-content="learnMore"
                 i18n-values="href:contentProtectionAttestationLearnMoreURL">
             </a>
-          </span>
-          <span class="controlled-setting-indicator"
-              pref="cros.device.attestation_for_content_protection_enabled">
+            <span class="controlled-setting-indicator"
+                pref="cros.device.attestation_for_content_protection_enabled">
+            </span>
           </span>
         </span>
       </div>
@@ -747,7 +747,7 @@
           </label>
         </div>
       </div>
-      <div class="option-name" id="accessibility-autoclick" hidden>
+      <div class="option-name" id="accessibility-autoclick">
         <div class="checkbox">
           <span class="controlled-setting-with-label">
             <input id="accessibility-autoclick-check"
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 270ac8b..b93cf67 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -445,8 +445,6 @@
         };
         $('accessibility-sticky-keys').hidden =
             !loadTimeData.getBoolean('enableStickyKeys');
-        $('accessibility-autoclick').hidden =
-            !loadTimeData.getBoolean('enableAutoclick');
       }
 
       // Display management section (CrOS only).
@@ -734,9 +732,13 @@
 
       // If the user gets signed out while the advanced sync settings dialog is
       // visible, say, due to a dashboard clear, close the dialog.
+      // However, if the user gets signed out as a result of abandoning first
+      // time sync setup, do not call closeOverlay as it will redirect the
+      // browser to the main settings page and override any in-progress
+      // user-initiated navigation. See crbug.com/278030.
       // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is
       // already hidden.
-      if (this.signedIn_ && !syncData.signedIn)
+      if (this.signedIn_ && !syncData.signedIn && !syncData.setupInProgress)
         SyncSetupOverlay.closeOverlay();
 
       this.signedIn_ = syncData.signedIn;
diff --git a/chrome/browser/resources/options/browser_options_startup_page_list.js b/chrome/browser/resources/options/browser_options_startup_page_list.js
index 23f7c1a..6afed9a 100644
--- a/chrome/browser/resources/options/browser_options_startup_page_list.js
+++ b/chrome/browser/resources/options/browser_options_startup_page_list.js
@@ -246,8 +246,19 @@
       if (this.dropPos == 'below')
         newIndex += 1;
 
-      chrome.send('dragDropStartupPage',
-                  [newIndex, this.selectionModel.selectedIndexes]);
+      // If there are selected indexes, it was a re-order.
+      if (this.selectionModel.selectedIndexes.length > 0) {
+        chrome.send('dragDropStartupPage',
+                    [newIndex, this.selectionModel.selectedIndexes]);
+        return;
+      }
+
+      // Otherwise it was potentially a drop of new data (e.g. a bookmark).
+      var url = e.dataTransfer.getData('url');
+      if (url) {
+        e.preventDefault();
+        chrome.send('addStartupPage', [url, newIndex]);
+      }
     },
 
     /**
diff --git a/chrome/browser/resources/options/chromeos/keyboard_overlay.css b/chrome/browser/resources/options/chromeos/keyboard_overlay.css
new file mode 100644
index 0000000..316e07a
--- /dev/null
+++ b/chrome/browser/resources/options/chromeos/keyboard_overlay.css
@@ -0,0 +1,7 @@
+/* Copyright 2013 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. */
+
+#send-function-keys-description {
+  color: gray;
+}
diff --git a/chrome/browser/resources/options/chromeos/keyboard_overlay.html b/chrome/browser/resources/options/chromeos/keyboard_overlay.html
index 36c29f9..039c52e 100644
--- a/chrome/browser/resources/options/chromeos/keyboard_overlay.html
+++ b/chrome/browser/resources/options/chromeos/keyboard_overlay.html
@@ -72,6 +72,18 @@
          </td>
        </tr>
     </table>
+    <div class="settings-row">
+      <div class="checkbox">
+        <label>
+          <input id="send-function-keys" type="checkbox"
+              pref="settings.language.send_function_keys" dialog-pref>
+          <span i18n-content="sendFunctionKeys"></span>
+        </label>
+      </div>
+      <label id="send-function-keys-description" for="send-function-keys"
+          i18n-content="sendFunctionKeysDescription">
+      </label>
+    </div>
   </div>
   <div class="content-area">
     <button id="languages-and-input-settings" class="link-button"
diff --git a/chrome/browser/resources/options/font_settings.css b/chrome/browser/resources/options/font_settings.css
index 6cd5ca4..f999c58 100644
--- a/chrome/browser/resources/options/font_settings.css
+++ b/chrome/browser/resources/options/font_settings.css
@@ -6,6 +6,19 @@
   overflow: hidden;
 }
 
+#font-settings .action-area {
+  -webkit-box-pack: start;
+}
+
+#font-settings .action-area .spacer {
+  -webkit-box-flex: 1;
+  display: -webkit-box;
+}
+
+#font-settings .button-strip {
+  width: 100%;
+}
+
 .font-setting-container {
   display: -webkit-box;
 }
diff --git a/chrome/browser/resources/options/font_settings.html b/chrome/browser/resources/options/font_settings.html
index f9f4274..da31060 100644
--- a/chrome/browser/resources/options/font_settings.html
+++ b/chrome/browser/resources/options/font_settings.html
@@ -100,6 +100,11 @@
   </div>
   <div class="action-area">
     <div class="button-strip">
+      <span id="advanced-font-settings-install" hidden
+          i18n-values=".innerHTML:advancedFontSettingsInstall"></span>
+      <a id="advanced-font-settings-options" href="#" hidden
+          i18n-content="advancedFontSettingsOptions"></a>
+      <span class="spacer"></span>
       <button id="font-settings-confirm" class="default-button"
           i18n-content="done">
       </button>
diff --git a/chrome/browser/resources/options/font_settings.js b/chrome/browser/resources/options/font_settings.js
index 965df6e..0b3f3f7 100644
--- a/chrome/browser/resources/options/font_settings.js
+++ b/chrome/browser/resources/options/font_settings.js
@@ -57,6 +57,10 @@
       $('font-settings-confirm').onclick = function() {
         OptionsPage.closeOverlay();
       };
+
+      $('advanced-font-settings-options').onclick = function() {
+        chrome.send('openAdvancedFontSettingsOptions');
+      };
     },
 
     /**
@@ -234,6 +238,15 @@
                                                 null, true);
   };
 
+  /**
+   * @param {boolean} available Whether the Advanced Font Settings Extension
+   *     is installed and enabled.
+   */
+  FontSettings.notifyAdvancedFontSettingsAvailability = function(available) {
+    $('advanced-font-settings-install').hidden = available;
+    $('advanced-font-settings-options').hidden = !available;
+  };
+
   // Export
   return {
     FontSettings: FontSettings
diff --git a/chrome/browser/resources/options/managed_user_learn_more.html b/chrome/browser/resources/options/managed_user_learn_more.html
index 0698546..5eea881 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.html
+++ b/chrome/browser/resources/options/managed_user_learn_more.html
@@ -6,7 +6,7 @@
       i18n-content="managedUserLearnMoreTitle">
   </h1>
   <div id="managed-user-learn-more-text" class="content-area"
-      i18n-content="managedUserLearnMoreText">
+      i18n-values=".innerHTML:managedUserLearnMoreText">
   </div>
   <div id="managed-user-learn-more-action-area"
       class="action-area button-strip">
diff --git a/chrome/browser/resources/options/media_galleries_manager_overlay.html b/chrome/browser/resources/options/media_galleries_manager_overlay.html
index de2cc75..05c4db1 100644
--- a/chrome/browser/resources/options/media_galleries_manager_overlay.html
+++ b/chrome/browser/resources/options/media_galleries_manager_overlay.html
@@ -6,8 +6,8 @@
   </div>
   <div class="action-area">
     <div class="stretch">
-      <button id="new-media-gallery" i18n-content="addNewGalleryButton">
-      </button>
+      <button id="new-media-gallery" i18n-content="addNewGalleryButton"
+          disabled></button>
     </div>
     </stretch>
     <div class="button-strip">
diff --git a/chrome/browser/resources/options/media_galleries_manager_overlay.js b/chrome/browser/resources/options/media_galleries_manager_overlay.js
index 5549924..ac8e527 100644
--- a/chrome/browser/resources/options/media_galleries_manager_overlay.js
+++ b/chrome/browser/resources/options/media_galleries_manager_overlay.js
@@ -42,15 +42,13 @@
       this.addEventListener('visibleChange', this.handleVisibleChange_);
     },
 
-    /**
-     * TODO(dbeam): why is a private method being overridden?
-     * @override
-     * @private
-     */
+    /** @private */
     handleVisibleChange_: function() {
       if (!this.visible)
         return;
 
+      chrome.send('initializeMediaGalleries');
+
       if (this.availableGalleriesList_)
         this.availableGalleriesList_.redraw();
     },
@@ -61,7 +59,7 @@
      */
     setAvailableMediaGalleries_: function(galleries) {
       $('available-galleries-list').dataModel = new ArrayDataModel(galleries);
-      // TODO(estade): show this section by default.
+      $('new-media-gallery').disabled = false;
       $('media-galleries-section').hidden = false;
     },
   },
diff --git a/chrome/browser/resources/options/options.html b/chrome/browser/resources/options/options.html
index f96f5f8..a2c84c2 100644
--- a/chrome/browser/resources/options/options.html
+++ b/chrome/browser/resources/options/options.html
@@ -52,6 +52,7 @@
 <link rel="stylesheet" href="chromeos/display_options.css">
 <link rel="stylesheet" href="chromeos/display_overscan.css">
 <link rel="stylesheet" href="chromeos/internet_detail.css">
+<link rel="stylesheet" href="chromeos/keyboard_overlay.css">
 <link rel="stylesheet" href="chromeos/pointer_overlay.css">
 <link rel="stylesheet" href="factory_reset_overlay.css">
 </if>
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index c0a1787..8ed9f3b 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -907,12 +907,14 @@
                                                              true);
         }
         container.classList.remove('transparent');
+        this.onVisibilityChanged_();
       } else {
         // Kick change events for text fields.
         if (pageDiv.contains(document.activeElement))
           document.activeElement.blur();
         container.classList.add('transparent');
       }
+
       if (loading)
         this.fadeCompleted_();
     },
@@ -925,13 +927,15 @@
       if (this.container.classList.contains('transparent')) {
         this.pageDiv.hidden = true;
         this.container.hidden = true;
+
         if (this.parentPage)
           this.parentPage.pageDiv.parentElement.removeAttribute('aria-hidden');
 
         if (this.nestingLevel == 1)
           uber.invokeMethodOnParent('stopInterceptingEvents');
+
+        this.onVisibilityChanged_();
       }
-      this.onVisibilityChanged_();
     },
 
     /**
diff --git a/chrome/browser/resources/options/password_manager_list.js b/chrome/browser/resources/options/password_manager_list.js
index 089133b..60a1a34 100644
--- a/chrome/browser/resources/options/password_manager_list.js
+++ b/chrome/browser/resources/options/password_manager_list.js
@@ -78,6 +78,12 @@
         button.className = 'list-inline-button custom-appearance';
         button.textContent = loadTimeData.getString('passwordShowButton');
         button.addEventListener('click', this.onClick_.bind(this), true);
+        button.addEventListener('mousedown', function(event) {
+          // Don't focus on this button by mousedown.
+          event.preventDefault();
+          // Don't handle list item selection. It causes focus change.
+          event.stopPropagation();
+        }, false);
         passwordInputDiv.appendChild(button);
         this.passwordShowButton = button;
       }
@@ -107,6 +113,7 @@
      */
     showPassword: function() {
       this.passwordField.type = 'text';
+      this.passwordField.focus();
 
       var button = this.passwordShowButton;
       if (button)
diff --git a/chrome/browser/resources/options/reset_profile_settings_overlay.css b/chrome/browser/resources/options/reset_profile_settings_overlay.css
index 78db551..3614e0a 100644
--- a/chrome/browser/resources/options/reset_profile_settings_overlay.css
+++ b/chrome/browser/resources/options/reset_profile_settings_overlay.css
@@ -49,7 +49,7 @@
 
 #expand-feedback {
   background: center bottom no-repeat;
-  background-image: url('chrome://resources/images/question_mark.png');
+  background-image: url('chrome://theme/IDR_QUESTION_MARK');
   display: inline-block;
   height: 14px;
   opacity: 0.33;
diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json
index bed9d95..39294a3 100644
--- a/chrome/browser/resources/plugin_metadata/plugins_win.json
+++ b/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@
 {
-  "x-version": 11,
+  "x-version": 12,
   "google-talk": {
     "mime_types": [
     ],
@@ -187,7 +187,7 @@
       },
       {
         "version": "11.0.5",
-        "status": "up_to_date",
+        "status": "requires_authorization",
         "reference": "https://www.adobe.com/support/security/bulletins/apsb13-25.html"
       }
     ],
diff --git a/chrome/browser/resources/print_preview/images/gcp_logo.png b/chrome/browser/resources/print_preview/images/gcp_logo.png
deleted file mode 100644
index 6c485ba..0000000
--- a/chrome/browser/resources/print_preview/images/gcp_logo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/print_preview/no_destinations_promo.css b/chrome/browser/resources/print_preview/no_destinations_promo.css
index 3d4afde..f1d8de8 100644
--- a/chrome/browser/resources/print_preview/no_destinations_promo.css
+++ b/chrome/browser/resources/print_preview/no_destinations_promo.css
@@ -3,57 +3,18 @@
  * found in the LICENSE file. */
 
 #no-destinations-promo {
-  -webkit-user-select: none;
   z-index: 2;
 }
 
 #no-destinations-promo .page {
-  padding: 20px;
-  width: 640px;
+  width: 510px;
 }
 
-#no-destinations-promo .dialog-title {
-  font-size: 16pt;
-  margin-bottom: 18px;
+.hbox {
+  -webkit-box-orient: horizontal;
+  display: -webkit-box;
 }
 
-#no-destinations-promo p {
-  margin-bottom: 14px;
-}
-
-#no-destinations-promo .gcp-logo {
-  -webkit-margin-end: 12px;
-  float: left;
-}
-
-[dir='rtl'] #no-destinations-promo .gcp-logo {
-  float: right;
-}
-
-#no-destinations-promo .text-content {
+.stretch {
   -webkit-box-flex: 1;
-  font-size: 10pt;
-  margin-bottom: 18px;
-}
-
-#no-destinations-promo .close-button {
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG');
-  background-position: center;
-  background-repeat: no-repeat;
-  height: 16px;
-  right: 14px;
-  top: 14px;
-  width: 16px;
-}
-
-#no-destinations-promo .close-button:hover {
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG_H');
-}
-
-#no-destinations-promo .close-button:active {
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG_P');
-}
-
-#no-destinations-promo .action-button-container {
-  text-align: right;
 }
diff --git a/chrome/browser/resources/print_preview/no_destinations_promo.html b/chrome/browser/resources/print_preview/no_destinations_promo.html
index 19cf2f2..9ff23ba 100644
--- a/chrome/browser/resources/print_preview/no_destinations_promo.html
+++ b/chrome/browser/resources/print_preview/no_destinations_promo.html
@@ -1,19 +1,29 @@
 <div id="no-destinations-promo" class="overlay" hidden>
   <div class="page">
-    <div class="dialog-title" i18n-content="noDestsPromoTitle"></div>
-    <div class="text-content">
-      <img class="gcp-logo" src="images/gcp_logo.png" />
-      <p i18n-content="noDestsPromoBody"></p>
-      <p class="gcp-description"></p>
-    </div>
-    <div class="action-button-container">
-      <button
-          class="add-printer-button"
-          i18n-content="noDestsPromoAddPrinterButtonLabel"></button>
-      <button
-          class="not-now-button"
-          i18n-content="noDestsPromoNotNowButtonLabel"></button>
-    </div>
     <div class="close-button"></div>
+    <h1 i18n-content="noDestsPromoTitle"></h1>
+    <div class="content-area">
+      <div i18n-content="noDestsPromoBody"></div>
+    </div>
+    <div class="content-area">
+      <div i18n-content="noDestsPromoGcpDesc"></div>
+    </div>
+    <div class="action-area">
+       <div class="hbox stretch">
+         <a target="_blank" i18n-content="learnMore"
+             i18n-values="href:noDestsPromoLearnMoreUrl">
+         </a>
+       </div>
+      <div class="action-area-right">
+        <div class="button-strip">
+          <button
+              class="add-printer-button default-button"
+              i18n-content="noDestsPromoAddPrinterButtonLabel"></button>
+          <button
+              class="not-now-button"
+              i18n-content="noDestsPromoNotNowButtonLabel"></button>
+        </div>
+      </div>
+    </div>
   </div>
 </div>
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index d430924..0aa97a8 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -267,7 +267,7 @@
 }
 
 /* TODO(estade): unfork this code. */
-.button-strip {
+#print-header .button-strip {
 <if expr="not pp_ifdef('toolkit_views')">
   -webkit-box-direction: reverse;
 </if>
@@ -276,7 +276,7 @@
   display: -webkit-box;
 }
 
-#print-preview .button-strip button {
+#print-header .button-strip button {
   -webkit-margin-start: 9px;
   display: block;
 }
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 0d236d0..2fc242b 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -364,14 +364,6 @@
       this.otherOptionsSettings_.decorate($('other-options-settings'));
       this.previewArea_.decorate($('preview-area'));
 
-      // Set some of the parameterized text in the no-destinations promotion.
-      var noDestsPromoGcpDescription =
-          this.getChildElement('#no-destinations-promo .gcp-description');
-      noDestsPromoGcpDescription.innerHTML = localStrings.getStringF(
-          'noDestsPromoGcpDesc',
-          '<a target="_blank" href="http://www.google.com/cloudprint/learn/">',
-          '</a>');
-
       setIsVisible($('open-pdf-in-preview-link'), cr.isMac);
     },
 
diff --git a/chrome/browser/resources/print_preview/print_preview_page.html b/chrome/browser/resources/print_preview/print_preview_page.html
index 0eab31f..d7a9de8 100644
--- a/chrome/browser/resources/print_preview/print_preview_page.html
+++ b/chrome/browser/resources/print_preview/print_preview_page.html
@@ -73,8 +73,10 @@
                                 options['bottomMargin']);
   footer.style.height = pixels(options['bottomMargin']);
 
-  document.querySelector('#date span').innerText = options['date'];
+  document.querySelector('#date span').innerText =
+      new Date(options['date']).toLocaleDateString();
   document.querySelector('#title span').innerText = options['title'];
+
   document.querySelector('#url span').innerText = options['url'];
   document.querySelector('#page_number span').innerText = options['pageNumber'];
 
diff --git a/chrome/browser/resources/print_preview/search/destination_search.css b/chrome/browser/resources/print_preview/search/destination_search.css
index f45bbab..f736b57 100644
--- a/chrome/browser/resources/print_preview/search/destination_search.css
+++ b/chrome/browser/resources/print_preview/search/destination_search.css
@@ -77,7 +77,9 @@
 
 #destination-search .cloudprint-promo .close-button {
   -webkit-margin-start: 12px;
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG');
+  background-image: -webkit-image-set(
+    url('chrome://theme/IDR_CLOSE_DIALOG') 1x,
+    url('chrome://theme/IDR_CLOSE_DIALOG@2x') 2x);
   background-repeat: no-repeat;
   background-size: 14px;
   height: 14px;
@@ -85,9 +87,13 @@
 }
 
 #destination-search .cloudprint-promo .close-button:hover {
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG_H');
+  background-image: -webkit-image-set(
+    url('chrome://theme/IDR_CLOSE_DIALOG_H') 1x,
+    url('chrome://theme/IDR_CLOSE_DIALOG_H@2x') 2x);
 }
 
 #destination-search .cloudprint-promo .close-button:active {
-  background-image: url('chrome://theme/IDR_CLOSE_DIALOG_P');
+  background-image: -webkit-image-set(
+    url('chrome://theme/IDR_CLOSE_DIALOG_P') 1x,
+    url('chrome://theme/IDR_CLOSE_DIALOG_P@2x') 2x);
 }
diff --git a/chrome/browser/resources/quick_office/manifest_editor.json b/chrome/browser/resources/quick_office/manifest_editor.json
index 1cea1fd..08691d3 100644
--- a/chrome/browser/resources/quick_office/manifest_editor.json
+++ b/chrome/browser/resources/quick_office/manifest_editor.json
@@ -6,7 +6,7 @@
       "scripts/configs/experimentalFeatures.js"
     ]
   },
-  "content_security_policy": "default-src 'self'; connect-src blob: chrome-extension:; style-src 'self' 'unsafe-inline' chrome-extension:; img-src 'self' blob: data:; frame-src chrome-extension:; script-src 'self'",
+  "content_security_policy": "default-src 'self'; connect-src https://www.google-analytics.com/ blob: chrome-extension:; style-src 'self' 'unsafe-inline' chrome-extension:; img-src 'self' blob: data:; frame-src chrome-extension:; script-src 'self'",
   "default_locale": "en",
   "description": "Quickoffice (Beta)",
   "file_browser_handlers": [
@@ -63,7 +63,9 @@
     "fileBrowserHandler",
     "fileSystem",
     "fileSystem.write",
+    "https://www.google-analytics.com/",
     "metricsPrivate",
+    "storage",
     "streamsPrivate",
     "unlimitedStorage"
   ],
@@ -81,7 +83,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "31.91.1417.13",
+  "version": "32.92.1530.4",
   "web_accessible_resources": [
     "views/qowt.html"
   ]
diff --git a/chrome/browser/resources/quick_office/manifest_viewing.json b/chrome/browser/resources/quick_office/manifest_viewing.json
index 6ac0905..37dbecc 100644
--- a/chrome/browser/resources/quick_office/manifest_viewing.json
+++ b/chrome/browser/resources/quick_office/manifest_viewing.json
@@ -5,7 +5,7 @@
       "scripts/background/register.js"
     ]
   },
-  "content_security_policy": "default-src 'self'; connect-src blob: chrome-extension:; style-src 'self' 'unsafe-inline' chrome-extension:; img-src 'self' blob: data:; frame-src chrome-extension:; script-src 'self'",
+  "content_security_policy": "default-src 'self'; connect-src https://www.google-analytics.com/ blob: chrome-extension:; style-src 'self' 'unsafe-inline' chrome-extension:; img-src 'self' blob: data:; frame-src chrome-extension:; script-src 'self'",
   "default_locale": "en",
   "description": "Chrome Office Viewer (Beta)",
   "file_browser_handlers": [
@@ -62,7 +62,9 @@
     "fileBrowserHandler",
     "fileSystem",
     "fileSystem.write",
+    "https://www.google-analytics.com/",
     "metricsPrivate",
+    "storage",
     "streamsPrivate",
     "unlimitedStorage"
   ],
@@ -80,7 +82,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "31.91.1417.13",
+  "version": "32.92.1530.4",
   "web_accessible_resources": [
     "views/qowt.html"
   ]
diff --git a/chrome/browser/resources/sync_internals/chrome_sync.js b/chrome/browser/resources/sync_internals/chrome_sync.js
index 4b55afb..8867c62 100644
--- a/chrome/browser/resources/sync_internals/chrome_sync.js
+++ b/chrome/browser/resources/sync_internals/chrome_sync.js
@@ -85,7 +85,6 @@
     'onChangesComplete',
     'onSyncCycleCompleted',
     'onConnectionStatusChange',
-    'onUpdatedToken',
     'onPassphraseRequired',
     'onPassphraseAccepted',
     'onInitializationComplete',
diff --git a/chrome/browser/resources/sync_setup_overlay.js b/chrome/browser/resources/sync_setup_overlay.js
index 07ec814..5070899 100644
--- a/chrome/browser/resources/sync_setup_overlay.js
+++ b/chrome/browser/resources/sync_setup_overlay.js
@@ -26,6 +26,11 @@
   // the boxes are restored to their most recent checked state from this cache.
   var dataTypeBoxes_ = {};
 
+  // Used to determine whether to bring the OK button / passphrase field into
+  // focus.
+  var confirmPageVisible_ = false;
+  var customizePageVisible_ = false;
+
   /**
    * The user's selection in the synced data type drop-down menu, as an index.
    * @enum {number}
@@ -91,11 +96,6 @@
       this.syncConfigureArgs_ = null;
       this.dataTypeBoxes_ = {};
 
-      // Required in order to determine whether to give focus to the OK button
-      // or passphrase field. See crbug.com/279770.
-      $('confirm-sync-preferences').hidden = true;
-      $('customize-sync-preferences').hidden = true;
-
       var overlay = $('sync-setup-overlay');
       if (!overlay.hidden)
         OptionsPage.closeOverlay();
@@ -421,6 +421,11 @@
       if (args)
         this.syncConfigureArgs_ = args;
 
+      // Required in order to determine whether to give focus to the OK button
+      // or passphrase field. See crbug.com/310555 and crbug.com/306353.
+      this.confirmPageVisible_ = false;
+      this.customizePageVisible_ = false;
+
       // Once the advanced sync settings dialog is visible, we transition
       // between its drop-down menu items as follows:
       // "Sync everything": Show encryption and passphrase sections, and disable
@@ -485,7 +490,8 @@
 
     showSyncEverythingPage_: function() {
       // Determine whether to bring the OK button into focus.
-      var wasConfirmPageHidden = $('confirm-sync-preferences').hidden;
+      var wasConfirmPageHidden = !this.confirmPageVisible_;
+      this.confirmPageVisible_ = true;
 
       $('confirm-sync-preferences').hidden = false;
       $('customize-sync-preferences').hidden = true;
@@ -580,7 +586,8 @@
      */
     showCustomizePage_: function(args, index) {
       // Determine whether to bring the OK button field into focus.
-      var wasCustomizePageHidden = $('customize-sync-preferences').hidden;
+      var wasCustomizePageHidden = !this.customizePageVisible_;
+      this.customizePageVisible_ = true;
 
       $('confirm-sync-preferences').hidden = true;
       $('customize-sync-preferences').hidden = false;
@@ -624,6 +631,14 @@
      *     section.
      */
     showSyncSetupPage_: function(page, args) {
+      // If the user clicks the OK button, dismiss the dialog immediately, and
+      // do not go through the process of hiding elements of the overlay.
+      // See crbug.com/308873.
+      if (page == 'done') {
+        this.closeOverlay_();
+        return;
+      }
+
       this.setThrobbersVisible_(false);
 
       // Hide an existing visible overlay (ensuring the close button is not
@@ -649,10 +664,7 @@
       // focus, we need to ensure that the overlay container and dialog aren't
       // [hidden] (as trying to focus() nodes inside of a [hidden] DOM section
       // doesn't work).
-      if (page == 'done')
-        this.closeOverlay_();
-      else
-        this.showOverlay_();
+      this.showOverlay_();
 
       if (page == 'configure' || page == 'passphrase')
         this.showConfigure_(args);
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index dfad491..513e05d 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -63,10 +63,6 @@
 const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200);
 const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20);
 
-// Tracker used for testing purposes only. If this value is non-NULL, it
-// will be returned from GetInstance() instead of the regular singleton.
-RLZTracker* tracker_for_test_ = NULL;
-
 bool IsBrandOrganic(const std::string& brand) {
   return brand.empty() || google_util::IsOrganic(brand);
 }
@@ -135,6 +131,26 @@
   }
 }
 
+bool SendFinancialPing(const std::string& brand,
+                       const string16& lang,
+                       const string16& referral) {
+  rlz_lib::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX,
+                                   RLZTracker::CHROME_HOME_PAGE,
+                                   rlz_lib::NO_ACCESS_POINT};
+  std::string lang_ascii(UTF16ToASCII(lang));
+  std::string referral_ascii(UTF16ToASCII(referral));
+  std::string product_signature;
+#if defined(OS_CHROMEOS)
+  product_signature = "chromeos";
+#else
+  product_signature = "chrome";
+#endif
+  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points,
+                                    product_signature.c_str(),
+                                    brand.c_str(), referral_ascii.c_str(),
+                                    lang_ascii.c_str(), false, true);
+}
+
 }  // namespace
 
 #if defined(OS_WIN)
@@ -144,6 +160,13 @@
 // static
 const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
     rlz_lib::CHROME_HOME_PAGE;
+#elif defined(OS_IOS)
+// static
+const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
+    rlz_lib::CHROME_IOS_OMNIBOX;
+// static
+const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
+    rlz_lib::CHROME_IOS_HOME_PAGE;
 #elif defined(OS_MACOSX)
 // static
 const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
@@ -160,9 +183,11 @@
     rlz_lib::CHROMEOS_HOME_PAGE;
 #endif
 
+RLZTracker* RLZTracker::tracker_ = NULL;
+
 // static
 RLZTracker* RLZTracker::GetInstance() {
-  return tracker_for_test_ ? tracker_for_test_ : Singleton<RLZTracker>::get();
+  return tracker_ ? tracker_ : Singleton<RLZTracker>::get();
 }
 
 RLZTracker::RLZTracker()
@@ -175,21 +200,6 @@
       already_ran_(false),
       omnibox_used_(false),
       homepage_used_(false),
-      delegate_(this),
-      min_init_delay_(kMinInitDelay) {
-}
-
-RLZTracker::RLZTracker(RLZTrackerDelegate* delegate)
-    : first_run_(false),
-      send_ping_immediately_(false),
-      is_google_default_search_(false),
-      is_google_homepage_(false),
-      is_google_in_startpages_(false),
-      worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()),
-      already_ran_(false),
-      omnibox_used_(false),
-      homepage_used_(false),
-      delegate_(delegate),
       min_init_delay_(kMinInitDelay) {
 }
 
@@ -228,6 +238,8 @@
       GURL(pref_service->GetString(prefs::kHomePage)));
 
   bool is_google_in_startpages = false;
+#if !defined(OS_IOS)
+  // iOS does not have a notion of startpages.
   SessionStartupPref session_startup_prefs =
       StartupBrowserCreator::GetSessionStartupPref(
           *CommandLine::ForCurrentProcess(), profile);
@@ -237,6 +249,7 @@
                       session_startup_prefs.urls.end(),
                       google_util::IsGoogleHomePageUrl) > 0;
   }
+#endif
 
   if (!InitRlzDelayed(first_run, send_ping_immediately, delay,
                       is_google_default_search, is_google_homepage,
@@ -252,11 +265,6 @@
   return true;
 }
 
-// static
-void RLZTracker::SetTrackerForTest(RLZTracker* tracker) {
-  tracker_for_test_ = tracker;
-}
-
 bool RLZTracker::Init(bool first_run,
                       bool send_ping_immediately,
                       base::TimeDelta delay,
@@ -312,7 +320,6 @@
 
 void RLZTracker::DelayedInit() {
   bool schedule_ping = false;
-  DCHECK(!already_ran_);
 
   // For organic brandcodes do not use rlz at all. Empty brandcode usually
   // means a chromium install. This is ok.
@@ -336,19 +343,19 @@
   already_ran_ = true;
 
   if (schedule_ping)
-    ScheduleSendFinancialPing();
+    ScheduleFinancialPing();
 }
 
-void RLZTracker::ScheduleSendFinancialPing() {
+void RLZTracker::ScheduleFinancialPing() {
   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
       worker_pool_token_,
       FROM_HERE,
-      base::Bind(&RLZTracker::SendFinancialPingNow, base::Unretained(this)),
+      base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)),
       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
 }
 
-void RLZTracker::SendFinancialPingNow() {
-  TRACE_EVENT0("RLZ", "RLZTracker::SendFinancialPingNow");
+void RLZTracker::PingNowImpl() {
+  TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl");
   string16 lang;
   GoogleUpdateSettings::GetLanguage(&lang);
   if (lang.empty())
@@ -356,8 +363,7 @@
   string16 referral;
   GoogleUpdateSettings::GetReferral(&referral);
 
-  if (!IsBrandOrganic(brand_) &&
-      delegate_->SendFinancialPing(brand_, lang, referral)) {
+  if (!IsBrandOrganic(brand_) && SendFinancialPing(brand_, lang, referral)) {
     GoogleUpdateSettings::ClearReferral();
 
     {
@@ -372,28 +378,14 @@
 
   if (!IsBrandOrganic(reactivation_brand_)) {
     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
-    delegate_->SendFinancialPing(reactivation_brand_, lang, referral);
+    SendFinancialPing(reactivation_brand_, lang, referral);
   }
 }
 
 bool RLZTracker::SendFinancialPing(const std::string& brand,
                                    const string16& lang,
                                    const string16& referral) {
-  rlz_lib::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX,
-                                   RLZTracker::CHROME_HOME_PAGE,
-                                   rlz_lib::NO_ACCESS_POINT};
-  std::string lang_ascii(UTF16ToASCII(lang));
-  std::string referral_ascii(UTF16ToASCII(referral));
-  std::string product_signature;
-#if defined(OS_CHROMEOS)
-  product_signature = "chromeos";
-#else
-  product_signature = "chrome";
-#endif
-  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points,
-                                    product_signature.c_str(),
-                                    brand.c_str(), referral_ascii.c_str(),
-                                    lang_ascii.c_str(), false, true);
+  return ::SendFinancialPing(brand, lang, referral);
 }
 
 void RLZTracker::Observe(int type,
@@ -401,7 +393,7 @@
                          const content::NotificationDetails& details) {
   switch (type) {
     case chrome::NOTIFICATION_OMNIBOX_OPENED_URL:
-      ScheduleRecordFirstSearch(CHROME_OMNIBOX);
+      RecordFirstSearch(CHROME_OMNIBOX);
       registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
                         content::NotificationService::AllSources());
       break;
@@ -411,7 +403,7 @@
       if (entry != NULL &&
           ((entry->GetTransitionType() &
             content::PAGE_TRANSITION_HOME_PAGE) != 0)) {
-        ScheduleRecordFirstSearch(CHROME_HOME_PAGE);
+        RecordFirstSearch(CHROME_HOME_PAGE);
         registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
                           content::NotificationService::AllSources());
       }
@@ -424,15 +416,20 @@
 }
 
 // static
-void RLZTracker::RecordProductEvent(rlz_lib::Product product,
+bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
                                     rlz_lib::AccessPoint point,
                                     rlz_lib::Event event_id) {
-  GetInstance()->ScheduleRecordProductEvent(product, point, event_id);
+  return GetInstance()->RecordProductEventImpl(product, point, event_id);
 }
 
 bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product,
                                         rlz_lib::AccessPoint point,
                                         rlz_lib::Event event_id) {
+  // Make sure we don't access disk outside of the I/O thread.
+  // In such case we repost the task on the right thread and return error.
+  if (ScheduleRecordProductEvent(product, point, event_id))
+    return true;
+
   bool ret = rlz_lib::RecordProductEvent(product, point, event_id);
 
   // If chrome has been reactivated, record the event for this brand as well.
@@ -440,40 +437,53 @@
     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
     ret &= rlz_lib::RecordProductEvent(product, point, event_id);
   }
+
   return ret;
 }
 
-void RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
+bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
                                             rlz_lib::AccessPoint point,
                                             rlz_lib::Event event_id) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+    return false;
+
   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
       worker_pool_token_,
       FROM_HERE,
-      base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEventImpl),
-                 base::Unretained(this),
+      base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
                  product, point, event_id),
       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+  return true;
 }
 
-void RLZTracker::RecordFirstSearchImpl(rlz_lib::AccessPoint point) {
+void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) {
+  // Make sure we don't access disk outside of the I/O thread.
+  // In such case we repost the task on the right thread and return error.
+  if (ScheduleRecordFirstSearch(point))
+    return;
+
   bool* record_used = point == CHROME_OMNIBOX ?
       &omnibox_used_ : &homepage_used_;
 
   // Try to record event now, else set the flag to try later when we
   // attempt the ping.
-  if (!RecordProductEventImpl(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH))
+  if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH))
     *record_used = true;
   else if (send_ping_immediately_ && point == CHROME_OMNIBOX)
     ScheduleDelayedInit(base::TimeDelta());
 }
 
-void RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
+bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+    return false;
   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
       worker_pool_token_,
       FROM_HERE,
-      base::Bind(&RLZTracker::RecordFirstSearchImpl,
+      base::Bind(&RLZTracker::RecordFirstSearch,
                  base::Unretained(this), point),
       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  return true;
 }
 
 // static
@@ -491,88 +501,94 @@
   return extra_headers;
 }
 
-bool RLZTracker::GetCachedAccessPointRlz(rlz_lib::AccessPoint point,
-                                         string16* rlz) {
-  base::AutoLock lock(cache_lock_);
-  if (rlz_cache_.find(point) != rlz_cache_.end()) {
-    if (rlz)
-      *rlz = rlz_cache_[point];
-    return true;
-  }
-  return false;
-}
-
-// static
+// GetAccessPointRlz() caches RLZ strings for all access points. If we had
+// a successful ping, then we update the cached value.
 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
                                    string16* rlz) {
   TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointRlz");
-  RLZTracker* tracker = GetInstance();
-  if (tracker->GetCachedAccessPointRlz(point, rlz))
-    return true;
-
-  // GetAccessPointRlzImpl() caches RLZ strings for all access points. If we had
-  // a successful ping, then we update the cached value.
-  tracker->ScheduleGetAccessPointRlz(point);
-  return false;
+  return GetInstance()->GetAccessPointRlzImpl(point, rlz);
 }
 
-void RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point) {
-  string16* rlz_not_used = NULL;
-  if (GetCachedAccessPointRlz(point, rlz_not_used))
-    return;
+// GetAccessPointRlz() caches RLZ strings for all access points. If we had
+// a successful ping, then we update the cached value.
+bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point,
+                                       string16* rlz) {
+  // If the RLZ string for the specified access point is already cached,
+  // simply return its value.
+  {
+    base::AutoLock lock(cache_lock_);
+    if (rlz_cache_.find(point) != rlz_cache_.end()) {
+      if (rlz)
+        *rlz = rlz_cache_[point];
+      return true;
+    }
+  }
+
+  // Make sure we don't access disk outside of the I/O thread.
+  // In such case we repost the task on the right thread and return error.
+  if (ScheduleGetAccessPointRlz(point))
+    return false;
+
   char str_rlz[rlz_lib::kMaxRlzLength + 1];
   if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength))
-    return;
+    return false;
 
   string16 rlz_local(ASCIIToUTF16(std::string(str_rlz)));
+  if (rlz)
+    *rlz = rlz_local;
+
   base::AutoLock lock(cache_lock_);
   rlz_cache_[point] = rlz_local;
-  return;
+  return true;
 }
 
-void RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
+bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+    return false;
+
+  string16* not_used = NULL;
   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
       worker_pool_token_,
       FROM_HERE,
-      base::Bind(&RLZTracker::GetAccessPointRlzImpl,
-                 base::Unretained(this), point),
+      base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
+                 not_used),
       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  return true;
 }
 
 #if defined(OS_CHROMEOS)
 // static
 void RLZTracker::ClearRlzState() {
-  GetInstance()->ScheduleClearRlzState();
+  GetInstance()->ClearRlzStateImpl();
 }
 
 void RLZTracker::ClearRlzStateImpl() {
+  if (ScheduleClearRlzState())
+    return;
   rlz_lib::ClearAllProductEvents(rlz_lib::CHROME);
 }
 
-void RLZTracker::ScheduleClearRlzState() {
+bool RLZTracker::ScheduleClearRlzState() {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+    return false;
+
   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
       worker_pool_token_,
       FROM_HERE,
       base::Bind(&RLZTracker::ClearRlzStateImpl,
                  base::Unretained(this)),
       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  return true;
 }
 #endif
 
 // static
 void RLZTracker::CleanupRlz() {
-  GetInstance()->Cleanup();
+  GetInstance()->rlz_cache_.clear();
+  GetInstance()->registrar_.RemoveAll();
   rlz_lib::SetURLRequestContext(NULL);
 }
 
-void RLZTracker::Cleanup() {
-  {
-    base::AutoLock lock(cache_lock_);
-    rlz_cache_.clear();
-  }
-  registrar_.RemoveAll();
-}
-
 // static
 void RLZTracker::EnableZeroDelayForTesting() {
   GetInstance()->min_init_delay_ = base::TimeDelta();
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
index 517bb7d..d55e05c 100644
--- a/chrome/browser/rlz/rlz.h
+++ b/chrome/browser/rlz/rlz.h
@@ -13,7 +13,6 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string16.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -27,16 +26,6 @@
 class URLRequestContextGetter;
 }
 
-// An interface to provide financial ping implementation.
-class RLZTrackerDelegate {
- public:
-  // Sends the financial ping to the RLZ servers. This method is virtual to
-  // allow tests to override.
-  virtual bool SendFinancialPing(const std::string& brand,
-                                 const string16& lang,
-                                 const string16& referral) = 0;
-};
-
 // RLZ is a library which is used to measure distribution scenarios.
 // Its job is to record certain lifetime events in the registry and to send
 // them encoded as a compact string at most twice. The sent data does
@@ -46,8 +35,8 @@
 //
 // For partner or bundled installs, the RLZ might send more information
 // according to the terms disclosed in the EULA.
-class RLZTracker : public content::NotificationObserver,
-                   public RLZTrackerDelegate {
+
+class RLZTracker : public content::NotificationObserver {
  public:
   // Initializes the RLZ library services for use in chrome. Schedules a delayed
   // task that performs the ping and registers some events when 'first-run' is
@@ -64,8 +53,9 @@
                                         base::TimeDelta delay);
 
   // Records an RLZ event. Some events can be access point independent.
-  // Requires write access to the HKCU registry hive on windows.
-  static void RecordProductEvent(rlz_lib::Product product,
+  // Returns false it the event could not be recorded. Requires write access
+  // to the HKCU registry hive on windows.
+  static bool RecordProductEvent(rlz_lib::Product product,
                                  rlz_lib::AccessPoint point,
                                  rlz_lib::Event event_id);
 
@@ -100,15 +90,11 @@
   // Enables zero delay for InitRlzFromProfileDelayed. For testing only.
   static void EnableZeroDelayForTesting();
 
- private:
-  friend class RlzLibTest;
-  friend class TestRLZTrackerDelegate;
-  friend class base::RefCountedThreadSafe<RLZTracker>;
-  friend struct DefaultSingletonTraits<RLZTracker>;
-
-  FRIEND_TEST_ALL_PREFIXES(RlzLibTest, GetAccessPointRlzIsCached);
-  FRIEND_TEST_ALL_PREFIXES(RlzLibTest, ObserveHandlesBadArgs);
-  FRIEND_TEST_ALL_PREFIXES(RlzLibTest, PingUpdatesRlzCache);
+  // The following methods are made protected so that they can be used for
+  // testing purposes. Production code should never need to call these.
+ protected:
+  RLZTracker();
+  virtual ~RLZTracker();
 
   // Called by InitRlzFromProfileDelayed with values taken from |profile|.
   static bool InitRlzDelayed(bool first_run,
@@ -118,22 +104,29 @@
                              bool is_google_homepage,
                              bool is_google_in_startpages);
 
-  // Used by test code to override the default RLZTracker instance returned
-  // by GetInstance().
-  static void SetTrackerForTest(RLZTracker* tracker);
-
-  RLZTracker();
-  explicit RLZTracker(RLZTrackerDelegate* delegate);
-  virtual ~RLZTracker();
-
   // Performs initialization of RLZ tracker that is purposefully delayed so
   // that it does not interfere with chrome startup time.
-  void DelayedInit();
+  virtual void DelayedInit();
+
+  // content::NotificationObserver implementation:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Used by test code to override the default RLZTracker instance returned
+  // by GetInstance().
+  void set_tracker(RLZTracker* tracker) {
+    tracker_ = tracker;
+  }
 
   // Sends the financial ping to the RLZ servers and invalidates the RLZ string
   // cache since the response from the RLZ server may have changed then.
   // Protected so that its accessible from tests.
-  void SendFinancialPingNow();
+  void PingNowImpl();
+
+ private:
+  friend struct DefaultSingletonTraits<RLZTracker>;
+  friend class base::RefCountedThreadSafe<RLZTracker>;
 
   // Implementation called from InitRlzDelayed() static method.
   bool Init(bool first_run,
@@ -143,69 +136,59 @@
             bool google_default_homepage,
             bool is_google_in_startpages);
 
-  // Gets the cached accesspoint rlz. Returns false if the cache doesn't exist.
-  bool GetCachedAccessPointRlz(rlz_lib::AccessPoint point, string16* rlz);
+  // Implementation called from RecordProductEvent() static method.
+  bool RecordProductEventImpl(rlz_lib::Product product,
+                              rlz_lib::AccessPoint point,
+                              rlz_lib::Event event_id);
 
-#if defined(OS_CHROMEOS)
-  // Implementation called from ClearRlzState static method.
-  void ClearRlzStateImpl();
-#endif
+  // Records FIRST_SEARCH event. Called from Observe() on blocking task runner.
+  void RecordFirstSearch(rlz_lib::AccessPoint point);
+
+  // Implementation called from GetAccessPointRlz() static method.
+  bool GetAccessPointRlzImpl(rlz_lib::AccessPoint point, string16* rlz);
 
   // Schedules the delayed initialization. This method is virtual to allow
   // tests to override how the scheduling is done.
-  void ScheduleDelayedInit(base::TimeDelta delay);
+  virtual void ScheduleDelayedInit(base::TimeDelta delay);
 
   // Schedules a call to rlz_lib::RecordProductEvent(). This method is virtual
   // to allow tests to override how the scheduling is done.
-  void ScheduleRecordProductEvent(rlz_lib::Product product,
-                                  rlz_lib::AccessPoint point,
-                                  rlz_lib::Event event_id);
+  virtual bool ScheduleRecordProductEvent(rlz_lib::Product product,
+                                          rlz_lib::AccessPoint point,
+                                          rlz_lib::Event event_id);
+
   // Schedules a call to rlz_lib::RecordFirstSearch(). This method is virtual
   // to allow tests to override how the scheduling is done.
-  void ScheduleRecordFirstSearch(rlz_lib::AccessPoint point);
+  virtual bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point);
 
   // Schedules a call to rlz_lib::SendFinancialPing(). This method is virtual
   // to allow tests to override how the scheduling is done.
-  void ScheduleSendFinancialPing();
+  virtual void ScheduleFinancialPing();
 
   // Schedules a call to GetAccessPointRlz() on the I/O thread if the current
   // thread is not already the I/O thread, otherwise does nothing. Returns
   // true if the call was scheduled, and false otherwise. This method is
   // virtual to allow tests to override how the scheduling is done.
-  void ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point);
+  virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point);
 
-
-#if defined(OS_CHROMEOS)
-  // Schedules a call to ClearRlzStateImpl().
-  void ScheduleClearRlzState();
-#endif
-
-  // Implementation called from RecordProductEvent() static method
-  // on SequencedWorkerPool.
-  bool RecordProductEventImpl(rlz_lib::Product product,
-                              rlz_lib::AccessPoint point,
-                              rlz_lib::Event event_id);
-
-  // Records FIRST_SEARCH event. Scheduled on SequencedWorkerPool
-  // in Observe.
-  void RecordFirstSearchImpl(rlz_lib::AccessPoint point);
-
-  // Implementation of GetAccessPointRlz() invoked on SequencedWorkerPool.
-  // This caches RLZ strings for all access points. If we had
-  // a successful ping, then we update the cached value.
-  void GetAccessPointRlzImpl(rlz_lib::AccessPoint point);
-
-  void Cleanup();
-
-  // Overridden from RZLTrackerDelegate:
+  // Sends the financial ping to the RLZ servers. This method is virtual to
+  // allow tests to override.
   virtual bool SendFinancialPing(const std::string& brand,
                                  const string16& lang,
-                                 const string16& referral) OVERRIDE;
+                                 const string16& referral);
 
-  // content::NotificationObserver implementation:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
+#if defined(OS_CHROMEOS)
+  // Implementation called from ClearRlzState static method.
+  void ClearRlzStateImpl();
+
+  // Schedules a call to ClearRlzStateImpl(). This method is virtual
+  // to allow tests to override how the scheduling is done.
+  virtual bool ScheduleClearRlzState();
+#endif
+
+  // Tracker used for testing purposes only. If this value is non-NULL, it
+  // will be returned from GetInstance() instead of the regular singleton.
+  static RLZTracker* tracker_;
 
   // Configuation data for RLZ tracker. Set by call to Init().
   bool first_run_;
@@ -222,10 +205,9 @@
   // initialization.
   bool already_ran_;
 
-  // Keeps a cache of RLZ access point strings, since they rarely
-  // change.  The cache must be protected by a lock since it may be
-  // accessed from the UI thread for reading and the global blocking
-  // pool for reading and/or writing.
+  // Keeps a cache of RLZ access point strings, since they rarely change.
+  // The cache must be protected by a lock since it may be accessed from
+  // the UI thread for reading and the IO thread for reading and/or writing.
   base::Lock cache_lock_;
   std::map<rlz_lib::AccessPoint, string16> rlz_cache_;
 
@@ -239,8 +221,6 @@
 
   content::NotificationRegistrar registrar_;
 
-  RLZTrackerDelegate* delegate_;  // not owned.
-
   // Minimum delay before sending financial ping after initialization.
   base::TimeDelta min_init_delay_;
 
diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc
index 311d11c..0726ce2 100644
--- a/chrome/browser/rlz/rlz_unittest.cc
+++ b/chrome/browser/rlz/rlz_unittest.cc
@@ -18,7 +18,6 @@
 #include "chrome/common/env_vars.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
@@ -91,29 +90,64 @@
 #define EXPECT_STR_NOT_CONTAIN(str, substr) \
     EXPECT_PRED_FORMAT2(CmpHelperSTRNC, str, substr)
 
-void RunPendingTasks() {
-  content::BrowserThread::GetBlockingPool()->FlushForTesting();
-}
-
 }  // namespace
 
-// Test RLZTrackerDelegate that implements test specific
-// SendFinalcialPing and provides a way to verify it works.
-class TestRLZTrackerDelegate : public RLZTrackerDelegate {
+// Test class for RLZ tracker. Makes some member functions public and
+// overrides others to make it easier to test.
+class TestRLZTracker : public RLZTracker {
  public:
-  TestRLZTrackerDelegate() : tracker_(this) {
-    RLZTracker::SetTrackerForTest(&tracker_);
+  using RLZTracker::InitRlzDelayed;
+  using RLZTracker::DelayedInit;
+  using RLZTracker::Observe;
+
+  TestRLZTracker() : assume_not_ui_thread_(true) {
+    set_tracker(this);
   }
 
-  virtual ~TestRLZTrackerDelegate() {
-    RLZTracker::SetTrackerForTest(NULL);
+  virtual ~TestRLZTracker() {
+    set_tracker(NULL);
   }
 
   bool was_ping_sent_for_brand(const std::string& brand) const {
     return pinged_brands_.count(brand) > 0;
   }
 
+  void set_assume_not_ui_thread(bool assume_not_ui_thread) {
+    assume_not_ui_thread_ = assume_not_ui_thread;
+  }
+
  private:
+  virtual void ScheduleDelayedInit(base::TimeDelta delay) OVERRIDE {
+    // If the delay is 0, invoke the delayed init now. Otherwise,
+    // don't schedule anything, it will be manually called during tests.
+    if (delay == base::TimeDelta())
+      DelayedInit();
+  }
+
+  virtual void ScheduleFinancialPing() OVERRIDE {
+    PingNowImpl();
+  }
+
+  virtual bool ScheduleRecordProductEvent(rlz_lib::Product product,
+                                          rlz_lib::AccessPoint point,
+                                          rlz_lib::Event event_id) OVERRIDE {
+    return !assume_not_ui_thread_;
+  }
+
+  virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) OVERRIDE {
+    return !assume_not_ui_thread_;
+  }
+
+  virtual bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) OVERRIDE {
+    return !assume_not_ui_thread_;
+  }
+
+#if defined(OS_CHROMEOS)
+  virtual bool ScheduleClearRlzState() OVERRIDE {
+    return !assume_not_ui_thread_;
+  }
+#endif
+
   virtual bool SendFinancialPing(const std::string& brand,
                                  const string16& lang,
                                  const string16& referral) OVERRIDE {
@@ -131,9 +165,9 @@
   }
 
   std::set<std::string> pinged_brands_;
-  RLZTracker tracker_;
+  bool assume_not_ui_thread_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestRLZTrackerDelegate);
+  DISALLOW_COPY_AND_ASSIGN(TestRLZTracker);
 };
 
 class RlzLibTest : public testing::Test {
@@ -156,24 +190,7 @@
   void ExpectRlzPingSent(bool expected);
   void ExpectReactivationRlzPingSent(bool expected);
 
-  bool InitRlzDelayed(bool first_run,
-                      bool send_ping_immediately,
-                      base::TimeDelta delay,
-                      bool is_google_default_search,
-                      bool is_google_homepage,
-                      bool is_google_in_startpages) {
-    bool ret = RLZTracker::InitRlzDelayed(
-        first_run,
-        send_ping_immediately,
-        delay,
-        is_google_default_search,
-        is_google_homepage,
-        is_google_in_startpages);
-    RunPendingTasks();
-    return ret;
-  }
-
-  TestRLZTrackerDelegate tracker_;
+  TestRLZTracker tracker_;
 #if defined(OS_WIN)
   RegistryOverrideManager override_manager_;
 #elif defined(OS_POSIX)
@@ -272,26 +289,22 @@
 #endif
 
 void RlzLibTest::SimulateOmniboxUsage() {
-  RLZTracker::GetInstance()->Observe(
-      chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
-      content::NotificationService::AllSources(),
-      content::Details<OmniboxLog>(NULL));
-  RunPendingTasks();
+  tracker_.Observe(chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
+                   content::NotificationService::AllSources(),
+                   content::Details<OmniboxLog>(NULL));
 }
 
 void RlzLibTest::SimulateHomepageUsage() {
   scoped_ptr<NavigationEntry> entry(NavigationEntry::Create());
   entry->SetPageID(0);
   entry->SetTransitionType(content::PAGE_TRANSITION_HOME_PAGE);
-  RLZTracker::GetInstance()->Observe(
-      content::NOTIFICATION_NAV_ENTRY_PENDING,
-      content::NotificationService::AllSources(),
-      content::Details<NavigationEntry>(entry.get()));
-  RunPendingTasks();
+  tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+                   content::NotificationService::AllSources(),
+                   content::Details<NavigationEntry>(entry.get()));
 }
 
 void RlzLibTest::InvokeDelayedInit() {
-  RLZTracker::GetInstance()->DelayedInit();
+  tracker_.DelayedInit();
 }
 
 void RlzLibTest::ExpectEventRecorded(const char* event_name, bool expected) {
@@ -380,13 +393,12 @@
 TEST_F(RlzLibTest, RecordProductEvent) {
   RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::CHROME_OMNIBOX,
                                  rlz_lib::FIRST_SEARCH);
-  RunPendingTasks();
 
   ExpectEventRecorded(kOmniboxFirstSearch, true);
 }
 
 TEST_F(RlzLibTest, QuickStopAfterStart) {
-  InitRlzDelayed(true, false, kDelay, true, true, true);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, true);
 
   // Omnibox events.
   ExpectEventRecorded(kOmniboxInstall, false);
@@ -402,7 +414,7 @@
 }
 
 TEST_F(RlzLibTest, DelayedInitOnly) {
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -419,7 +431,7 @@
 }
 
 TEST_F(RlzLibTest, DelayedInitOnlyGoogleAsStartup) {
-  InitRlzDelayed(true, false, kDelay, false, false, true);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, true);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -436,7 +448,7 @@
 }
 
 TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStrings) {
-  InitRlzDelayed(false, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -453,7 +465,7 @@
 }
 
 TEST_F(RlzLibTest, DelayedInitOnlyNoFirstRunNoRlzStringsGoogleAsStartup) {
-  InitRlzDelayed(false, false, kDelay, false, false, true);
+  TestRLZTracker::InitRlzDelayed(false, false, kDelay, false, false, true);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -475,7 +487,7 @@
   rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString);
   rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, kHomepageRlzString);
 
-  InitRlzDelayed(false, false, kDelay, true, true, true);
+  TestRLZTracker::InitRlzDelayed(false, false, kDelay, true, true, true);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -492,7 +504,7 @@
 }
 
 TEST_F(RlzLibTest, DelayedInitOnlyNoGoogleDefaultSearchOrHomepageOrStartup) {
-  InitRlzDelayed(true, false, kDelay, false, false, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, false, false, false);
   InvokeDelayedInit();
 
   // Omnibox events.
@@ -509,7 +521,7 @@
 }
 
 TEST_F(RlzLibTest, OmniboxUsageOnly) {
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   SimulateOmniboxUsage();
 
   // Omnibox events.
@@ -526,7 +538,7 @@
 }
 
 TEST_F(RlzLibTest, HomepageUsageOnly) {
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   SimulateHomepageUsage();
 
   // Omnibox events.
@@ -543,7 +555,7 @@
 }
 
 TEST_F(RlzLibTest, UsageBeforeDelayedInit) {
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   SimulateOmniboxUsage();
   SimulateHomepageUsage();
   InvokeDelayedInit();
@@ -562,7 +574,7 @@
 }
 
 TEST_F(RlzLibTest, OmniboxUsageAfterDelayedInit) {
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
   SimulateOmniboxUsage();
   SimulateHomepageUsage();
@@ -581,7 +593,7 @@
 }
 
 TEST_F(RlzLibTest, OmniboxUsageSendsPingWhenSendPingImmediately) {
-  InitRlzDelayed(true, true, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false);
   SimulateOmniboxUsage();
 
   // Omnibox events.
@@ -598,7 +610,7 @@
 }
 
 TEST_F(RlzLibTest, HomepageUsageDoesNotSendPingWhenSendPingImmediately) {
-  InitRlzDelayed(true, true, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, true, false);
   SimulateHomepageUsage();
 
   // Omnibox events.
@@ -615,7 +627,7 @@
 }
 
 TEST_F(RlzLibTest, StartupUsageDoesNotSendPingWhenSendPingImmediately) {
-  InitRlzDelayed(true, true, kDelay, true, false, true);
+  TestRLZTracker::InitRlzDelayed(true, true, kDelay, true, false, true);
   SimulateHomepageUsage();
 
   // Omnibox events.
@@ -631,18 +643,42 @@
   ExpectRlzPingSent(false);
 }
 
+TEST_F(RlzLibTest, GetAccessPointRlzOnIoThread) {
+  // Set dummy RLZ string.
+  rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString);
+
+  string16 rlz;
+
+  tracker_.set_assume_not_ui_thread(true);
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+  EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
+}
+
+TEST_F(RlzLibTest, GetAccessPointRlzNotOnIoThread) {
+  // Set dummy RLZ string.
+  rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString);
+
+  string16 rlz;
+
+  tracker_.set_assume_not_ui_thread(false);
+  EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+}
+
 TEST_F(RlzLibTest, GetAccessPointRlzIsCached) {
   // Set dummy RLZ string.
   rlz_lib::SetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, kOmniboxRlzString);
 
   string16 rlz;
-  RLZTracker* tracker = RLZTracker::GetInstance();
-  EXPECT_FALSE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+
+  tracker_.set_assume_not_ui_thread(false);
   EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
-  RunPendingTasks();
-  EXPECT_TRUE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+
+  tracker_.set_assume_not_ui_thread(true);
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+  EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
+
+  tracker_.set_assume_not_ui_thread(false);
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
   EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
 }
 
@@ -654,40 +690,36 @@
   string16 rlz;
 
   // Prime the cache.
-  EXPECT_FALSE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
-  RunPendingTasks();
+  tracker_.set_assume_not_ui_thread(true);
+
   EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
-
   EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
-
-  EXPECT_FALSE(
-      RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz));
-  RunPendingTasks();
-  EXPECT_TRUE(
-      RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz));
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(
+        RLZTracker::CHROME_HOME_PAGE, &rlz));
   EXPECT_STREQ(kHomepageRlzString, UTF16ToUTF8(rlz).c_str());
 
   // Make sure cache is valid.
-  RLZTracker* tracker = RLZTracker::GetInstance();
-  EXPECT_TRUE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+  tracker_.set_assume_not_ui_thread(false);
+
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
   EXPECT_STREQ(kOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
-  EXPECT_TRUE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz));
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(
+        RLZTracker::CHROME_HOME_PAGE, &rlz));
   EXPECT_STREQ(kHomepageRlzString, UTF16ToUTF8(rlz).c_str());
 
   // Perform ping.
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  tracker_.set_assume_not_ui_thread(true);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
-  RunPendingTasks();
   ExpectRlzPingSent(true);
 
   // Make sure cache is now updated.
-  EXPECT_TRUE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
+  tracker_.set_assume_not_ui_thread(false);
+
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz));
   EXPECT_STREQ(kNewOmniboxRlzString, UTF16ToUTF8(rlz).c_str());
-  EXPECT_TRUE(
-      tracker->GetCachedAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, &rlz));
+  EXPECT_TRUE(RLZTracker::GetAccessPointRlz(
+        RLZTracker::CHROME_HOME_PAGE, &rlz));
   EXPECT_STREQ(kNewHomepageRlzString, UTF16ToUTF8(rlz).c_str());
 }
 
@@ -695,14 +727,12 @@
   scoped_ptr<NavigationEntry> entry(NavigationEntry::Create());
   entry->SetPageID(0);
   entry->SetTransitionType(content::PAGE_TRANSITION_LINK);
-  RLZTracker::GetInstance()->Observe(
-      content::NOTIFICATION_NAV_ENTRY_PENDING,
-      content::NotificationService::AllSources(),
-      content::Details<NavigationEntry>(NULL));
-  RLZTracker::GetInstance()->Observe(
-      content::NOTIFICATION_NAV_ENTRY_PENDING,
-      content::NotificationService::AllSources(),
-      content::Details<NavigationEntry>(entry.get()));
+  tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+                   content::NotificationService::AllSources(),
+                   content::Details<NavigationEntry>(NULL));
+  tracker_.Observe(content::NOTIFICATION_NAV_ENTRY_PENDING,
+                   content::NotificationService::AllSources(),
+                   content::Details<NavigationEntry>(entry.get()));
 }
 
 // TODO(thakis): Reactivation doesn't exist on Mac yet.
@@ -710,7 +740,7 @@
 TEST_F(RlzLibTest, ReactivationNonOrganicNonOrganic) {
   SetReactivationBrand("REAC");
 
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   ExpectRlzPingSent(true);
@@ -721,7 +751,7 @@
   SetMainBrand("GGLS");
   SetReactivationBrand("REAC");
 
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   ExpectRlzPingSent(false);
@@ -732,7 +762,7 @@
   SetMainBrand("TEST");
   SetReactivationBrand("GGLS");
 
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   ExpectRlzPingSent(true);
@@ -743,7 +773,7 @@
   SetMainBrand("GGLS");
   SetReactivationBrand("GGRS");
 
-  InitRlzDelayed(true, false, kDelay, true, true, false);
+  TestRLZTracker::InitRlzDelayed(true, false, kDelay, true, true, false);
   InvokeDelayedInit();
 
   ExpectRlzPingSent(false);
@@ -755,11 +785,10 @@
 TEST_F(RlzLibTest, ClearRlzState) {
   RLZTracker::RecordProductEvent(rlz_lib::CHROME, RLZTracker::CHROME_OMNIBOX,
                                  rlz_lib::FIRST_SEARCH);
-  RunPendingTasks();
+
   ExpectEventRecorded(kOmniboxFirstSearch, true);
 
   RLZTracker::ClearRlzState();
-  RunPendingTasks();
 
   ExpectEventRecorded(kOmniboxFirstSearch, false);
 }
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index 6f92402..629cbf0 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -339,7 +339,13 @@
   EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneNotPhishing) {
+#else
 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
+#endif
   // Case 1: client thinks the page is phishing.  The server does not agree.
   // No interstitial is shown.
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -371,7 +377,12 @@
   EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest, DISABLED_OnPhishingDetectionDoneDisabled) {
+#else
 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
+#endif
   // Case 2: client thinks the page is phishing and so does the server but
   // showing the interstitial is disabled => no interstitial is shown.
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -403,7 +414,13 @@
   EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneShowInterstitial) {
+#else
 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
+#endif
   // Case 3: client thinks the page is phishing and so does the server.
   // We show an interstitial.
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -453,7 +470,13 @@
                  ui_manager_, resource.callback));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneMultiplePings) {
+#else
 TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
+#endif
   // Case 4 & 5: client thinks a page is phishing then navigates to
   // another page which is also considered phishing by the client
   // before the server responds with a verdict.  After a while the
@@ -540,8 +563,14 @@
                  ui_manager_, resource.callback));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneVerdictNotPhishing) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneVerdictNotPhishing) {
+#endif
   // Case 6: renderer sends a verdict string that isn't phishing.
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
       web_contents(),
@@ -558,8 +587,14 @@
   EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
 }
 
+#if defined(OS_WIN)
+// Fails on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneVerdictNotPhishingButSBMatch) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneVerdictNotPhishingButSBMatch) {
+#endif
   // Case 7: renderer sends a verdict string that isn't phishing but the URL
   // was on the regular phishing or malware lists.
   GURL url("http://not-phishing.com/");
@@ -587,7 +622,12 @@
   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest, DISABLED_UpdateIPUrlMap) {
+#else
 TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
+#endif
   BrowseInfo* browse_info = GetBrowseInfo();
 
   // Empty IP or host are skipped
@@ -640,8 +680,14 @@
   EXPECT_EQ(expected_urls, browse_info->ips["100.100.100.256"]);
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneVerdictNotPhishingNotMalwareIP) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneVerdictNotPhishingNotMalwareIP) {
+#endif
   // Case 7: renderer sends a verdict string that isn't phishing and not matches
   // malware bad IP list
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -667,8 +713,14 @@
   EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneVerdictNotPhishingButMalwareIP) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneVerdictNotPhishingButMalwareIP) {
+#endif
   // Case 8: renderer sends a verdict string that isn't phishing but matches
   // malware bad IP list
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -700,8 +752,14 @@
   EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneVerdictPhishingAndMalwareIP) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneVerdictPhishingAndMalwareIP) {
+#endif
   // Case 9: renderer sends a verdict string that is phishing and matches
   // malware bad IP list
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -743,8 +801,14 @@
   ASSERT_FALSE(cb.is_null());
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_OnPhishingDetectionDoneShowMalwareInterstitial) {
+#else
 TEST_F(ClientSideDetectionHostTest,
        OnPhishingDetectionDoneShowMalwareInterstitial) {
+#endif
   // Case 10: client thinks the page match malware IP and so does the server.
   // We show an sub-resource malware interstitial.
   MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
@@ -802,7 +866,13 @@
                  ui_manager_, resource.callback));
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest,
+       DISABLED_NavigationCancelsShouldClassifyUrl) {
+#else
 TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
+#endif
   // Test that canceling pending should classify requests works as expected.
 
   GURL first_url("http://first.phishy.url.com");
@@ -827,7 +897,12 @@
   WaitAndCheckPreClassificationChecks();
 }
 
+#if defined(OS_WIN)
+// Crashes on Blink canary bots: http://crbug.com/299149
+TEST_F(ClientSideDetectionHostTest, DISABLED_ShouldClassifyUrl) {
+#else
 TEST_F(ClientSideDetectionHostTest, ShouldClassifyUrl) {
+#endif
   // Navigate the tab to a page.  We should see a StartPhishingDetection IPC.
   GURL url("http://host.com/");
   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 37370dc..b727cbd 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -880,9 +880,6 @@
     const content::DownloadItem& item,
     content::PageNavigator* navigator) {
   GURL learn_more_url(chrome::kDownloadScanningLearnMoreURL);
-  if (item.GetDangerType() ==
-      content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED)
-    learn_more_url = GURL(chrome::kDownloadPotentiallyUnwantedLearnMoreURL);
   navigator->OpenURL(
       content::OpenURLParams(learn_more_url,
                              content::Referrer(),
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 1a3a5fb..c790bdc 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -23,6 +23,8 @@
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/startup_task_runner_service.h"
+#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/protocol_manager.h"
@@ -768,6 +770,8 @@
   scoped_ptr<Profile> profile2(Profile::CreateProfile(
       temp_profile_dir_.path(), NULL, Profile::CREATE_MODE_SYNCHRONOUS));
   ASSERT_TRUE(profile2.get() != NULL);
+  StartupTaskRunnerServiceFactory::GetForProfile(profile2.get())->
+              StartDeferredTaskRunners();
   PrefService* pref_service2 = profile2->GetPrefs();
   EXPECT_TRUE(pref_service2->GetBoolean(prefs::kSafeBrowsingEnabled));
   // We don't expect the state to have changed, but if it did, wait for it.
diff --git a/chrome/browser/search/hotword_service_factory.cc b/chrome/browser/search/hotword_service_factory.cc
index c465e08..675d86c 100644
--- a/chrome/browser/search/hotword_service_factory.cc
+++ b/chrome/browser/search/hotword_service_factory.cc
@@ -14,7 +14,9 @@
 
 // static
 HotwordService* HotwordServiceFactory::GetForProfile(Profile* profile) {
-  if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
+  if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled) ||
+      (profile->IsOffTheRecord() &&
+       !profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchIncognitoEnabled)))
     return NULL;
 
   return static_cast<HotwordService*>(
@@ -41,6 +43,9 @@
   prefs->RegisterBooleanPref(prefs::kHotwordSearchEnabled,
                              false,
                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  prefs->RegisterBooleanPref(prefs::kHotwordSearchIncognitoEnabled,
+                             false,
+                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 content::BrowserContext* HotwordServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 5f9fed9..7afd64c 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/browser/user_metrics.h"
 #include "grit/browser_resources.h"
 #include "net/base/url_util.h"
 #include "url/gurl.h"
@@ -67,9 +68,13 @@
     std::string str_position;
     int position;
     if (net::GetValueForKeyInQuery(url, "pos", &str_position) &&
-        base::StringToInt(str_position, &position))
+        base::StringToInt(str_position, &position)) {
       UMA_HISTOGRAM_ENUMERATION(kMostVisitedHistogramName, position,
                                 kNumMostVisited);
+      // Records the action. This will be available as a time-stamped stream
+      // server-side and can be used to compute time-to-long-dwell.
+      content::RecordAction(content::UserMetricsAction("MostVisited_Clicked"));
+    }
     callback.Run(NULL);
   } else {
     callback.Run(NULL);
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index c063cbc..60498e3 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -128,17 +128,20 @@
 
 GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
                           int start_margin,
-                          bool append_extra_query_params) {
+                          bool append_extra_query_params,
+                          bool force_instant_results) {
   TemplateURLRef::SearchTermsArgs search_terms_args =
       TemplateURLRef::SearchTermsArgs(string16());
   search_terms_args.omnibox_start_margin = start_margin;
   search_terms_args.append_extra_query_params = append_extra_query_params;
+  search_terms_args.force_instant_results = force_instant_results;
   return GURL(ref.ReplaceSearchTerms(search_terms_args));
 }
 
 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) {
   GURL search_url =
-      TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false);
+      TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false,
+                           false);
   if (search_url.is_valid() &&
       search::MatchesOriginAndPath(url, search_url))
     return true;
@@ -146,7 +149,7 @@
   // "URLCount() - 1" because we already tested url_ref above.
   for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
     TemplateURLRef ref(template_url, i);
-    search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false);
+    search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false, false);
     if (search_url.is_valid() &&
         search::MatchesOriginAndPath(url, search_url))
       return true;
@@ -223,7 +226,7 @@
 
   const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
   const GURL instant_url =
-      TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false);
+      TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false, false);
   if (!instant_url.is_valid())
     return false;
 
@@ -422,7 +425,8 @@
          profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
 }
 
-GURL GetInstantURL(Profile* profile, int start_margin) {
+GURL GetInstantURL(Profile* profile, int start_margin,
+                   bool force_instant_results) {
   if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
     return GURL();
 
@@ -431,7 +435,8 @@
     return GURL();
 
   GURL instant_url =
-      TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true);
+      TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true,
+                           force_instant_results);
   if (!instant_url.is_valid() ||
       !template_url->HasSearchTermsReplacementKey(instant_url))
     return GURL();
@@ -461,7 +466,8 @@
     return result;
   for (size_t i = 0; i < template_url->URLCount(); ++i) {
     TemplateURLRef ref(template_url, i);
-    result.push_back(TemplateURLRefToGURL(ref, kDisableStartMargin, false));
+    result.push_back(TemplateURLRefToGURL(ref, kDisableStartMargin, false,
+                                          false));
   }
   return result;
 }
@@ -481,7 +487,7 @@
     return GURL(chrome::kChromeSearchLocalNtpUrl);
 
   GURL url(TemplateURLRefToGURL(template_url->new_tab_url_ref(),
-                                kDisableStartMargin, false));
+                                kDisableStartMargin, false, false));
   if (!url.is_valid() || !url.SchemeIsSecure())
     return GURL(chrome::kChromeSearchLocalNtpUrl);
 
@@ -588,7 +594,7 @@
   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
   if (template_url) {
     const GURL instant_url = TemplateURLRefToGURL(
-        template_url->instant_url_ref(), kDisableStartMargin, false);
+        template_url->instant_url_ref(), kDisableStartMargin, false, false);
     if (instant_url.is_valid() &&
         search::MatchesOriginAndPath(url, instant_url)) {
       replacements.SetHost(online_ntp_host.c_str(),
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index 5f2eee5..dd1904f 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -107,11 +107,15 @@
 // because it doesn't satisfy the requirements for extended mode or if Instant
 // is disabled through preferences). Callers must check that the returned URL is
 // valid before using it. The value of |start_margin| is used for the "es_sm"
-// parameter in the URL.
+// parameter in the URL. |force_instant_results| forces a search page to update
+// results incrementally even if that is otherwise disabled by google.com
+// preferences.
 // NOTE: This method expands the default search engine's instant_url template,
 // so it shouldn't be called from SearchTermsData or other such code that would
 // lead to an infinite recursion.
-GURL GetInstantURL(Profile* profile, int start_margin);
+GURL GetInstantURL(Profile* profile,
+                   int start_margin,
+                   bool force_instant_results);
 
 // Returns URLs associated with the default search engine for |profile|.
 std::vector<GURL> GetSearchURLs(Profile* profile);
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index af006e6..3afc595 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -341,7 +341,8 @@
     TemplateURLData data;
     data.SetURL("http://foo.com/url?bar={searchTerms}");
     data.instant_url = "http://foo.com/instant?"
-        "{google:omniboxStartMarginParameter}foo=foo#foo=foo&strk";
+        "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
+        "foo=foo#foo=foo&strk";
     if (set_ntp_url) {
       data.new_tab_url = (insecure_ntp_url ? "http" : "https") +
           std::string("://foo.com/newtab?strk");
@@ -709,7 +710,8 @@
   EXPECT_TRUE(NavEntryIsInstantNTP(contents,
                                    controller.GetLastCommittedEntry()));
   // Instant page is not cacheable NTP.
-  NavigateAndCommitActiveTab(GetInstantURL(profile(), kDisableStartMargin));
+  NavigateAndCommitActiveTab(GetInstantURL(profile(), kDisableStartMargin,
+                                           false));
   EXPECT_FALSE(NavEntryIsInstantNTP(contents,
                                     controller.GetLastCommittedEntry()));
   // Test Cacheable NTP
@@ -762,49 +764,63 @@
 
   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
             chrome::GetNewTabPageURL(profile()));
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
 }
 
 TEST_F(SearchTest, GetInstantURLExtendedEnabled) {
   // Instant is disabled, so no Instant URL.
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
 
   // Enable Instant. Still no Instant URL because "strk" is missing.
   EnableInstantExtendedAPIForTesting();
   SetDefaultInstantTemplateUrl(false);
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
 
   // Set an Instant URL with a valid search terms replacement key.
   SetDefaultInstantTemplateUrl(true);
 
   // Now there should be a valid Instant URL. Note the HTTPS "upgrade".
   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), kDisableStartMargin));
+            GetInstantURL(profile(), kDisableStartMargin, false));
 
   // Enable suggest. No difference.
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), kDisableStartMargin));
+            GetInstantURL(profile(), kDisableStartMargin, false));
 
   // Disable suggest. No Instant URL.
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
 }
 
 TEST_F(SearchTest, StartMarginCGI) {
   // Instant is disabled, so no Instant URL.
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
 
   // Enable Instant. No margin.
   EnableInstantExtendedAPIForTesting();
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
 
   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), kDisableStartMargin));
+            GetInstantURL(profile(), kDisableStartMargin, false));
 
   // With start margin.
   EXPECT_EQ(GURL("https://foo.com/instant?es_sm=10&foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), 10));
+            GetInstantURL(profile(), 10, false));
+}
+
+TEST_F(SearchTest, InstantSearchEnabledCGI) {
+  EnableInstantExtendedAPIForTesting();
+
+  // Disable Instant Search.
+  // Make sure {google:forceInstantResults} is not set in the Instant URL.
+  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
+            GetInstantURL(profile(), kDisableStartMargin, false));
+
+  // Enable Instant Search.
+  // Make sure {google:forceInstantResults} is set in the Instant URL.
+  EXPECT_EQ(GURL("https://foo.com/instant?ion=1&foo=foo#foo=foo&strk"),
+            GetInstantURL(profile(), kDisableStartMargin, true));
 }
 
 TEST_F(SearchTest, CommandLineOverrides) {
@@ -827,7 +843,7 @@
   // By default, Instant Extended forces the instant URL to be HTTPS, so even if
   // we set a Google base URL that is HTTP, we should get an HTTPS URL.
   UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
-  GURL instant_url(GetInstantURL(profile(), kDisableStartMargin));
+  GURL instant_url(GetInstantURL(profile(), kDisableStartMargin, false));
   ASSERT_TRUE(instant_url.is_valid());
   EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
 
@@ -836,7 +852,7 @@
   UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
                                                       "http://www.bar.com/");
-  instant_url = GetInstantURL(profile(), kDisableStartMargin);
+  instant_url = GetInstantURL(profile(), kDisableStartMargin, false);
   ASSERT_TRUE(instant_url.is_valid());
   EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
 
@@ -850,7 +866,7 @@
   // query portion of the instant URL.
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kExtraSearchQueryParams, "a=b");
-  instant_url = GetInstantURL(profile(), kDisableStartMargin);
+  instant_url = GetInstantURL(profile(), kDisableStartMargin, false);
   ASSERT_TRUE(instant_url.is_valid());
   EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
 }
@@ -909,7 +925,7 @@
   // Enable Instant. No margin.
   EnableInstantExtendedAPIForTesting();
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
-  GURL remote_ntp_url(GetInstantURL(profile(), kDisableStartMargin));
+  GURL remote_ntp_url(GetInstantURL(profile(), kDisableStartMargin, false));
   GURL search_url_with_search_terms("https://foo.com/url?strk&bar=abc");
   GURL search_url_without_search_terms("https://foo.com/url?strk&bar");
 
diff --git a/chrome/browser/search_engines/default_search_policy_handler_unittest.cc b/chrome/browser/search_engines/default_search_policy_handler_unittest.cc
index ca88043..04068ff 100644
--- a/chrome/browser/search_engines/default_search_policy_handler_unittest.cc
+++ b/chrome/browser/search_engines/default_search_policy_handler_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/policy/configuration_policy_pref_store.h"
 #include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
 #include "chrome/browser/search_engines/default_search_policy_handler.h"
@@ -20,6 +21,11 @@
         "http://www.google.com/search#q={searchTerms}");
   }
 
+  virtual void SetUp() OVERRIDE {
+    handler_list_.AddHandler(make_scoped_ptr<ConfigurationPolicyHandler>(
+        new DefaultSearchPolicyHandler));
+  }
+
  protected:
   static const char kSearchURL[];
   static const char kSuggestURL[];
diff --git a/chrome/browser/search_engines/prepopulated_engines.json b/chrome/browser/search_engines/prepopulated_engines.json
index d8d741e..e7e4db5 100644
--- a/chrome/browser/search_engines/prepopulated_engines.json
+++ b/chrome/browser/search_engines/prepopulated_engines.json
@@ -488,7 +488,7 @@
       "favicon_url": "http://www.google.com/favicon.ico",
       "search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:bookmarkBarPinned}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}",
       "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&q={searchTerms}&{google:cursorPosition}{google:zeroPrefixUrl}{google:pageClassification}sugkey={google:suggestAPIKeyParameter}",
-      "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:instantEnabledParameter}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}",
+      "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}",
       "image_url": "{google:baseURL}searchbyimage/upload",
       "new_tab_url": "{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}",
       "image_url_post_params": "encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}",
diff --git a/chrome/browser/search_engines/search_provider_install_data.cc b/chrome/browser/search_engines/search_provider_install_data.cc
index a491db7..e650a26 100644
--- a/chrome/browser/search_engines/search_provider_install_data.cc
+++ b/chrome/browser/search_engines/search_provider_install_data.cc
@@ -148,7 +148,7 @@
                          TemplateURL* template_url,
                          const SearchTermsData& search_terms_data) {
   DCHECK(requested_origin == requested_origin.GetOrigin());
-  DCHECK(!template_url->IsExtensionKeyword());
+  DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
   return requested_origin ==
       TemplateURLService::GenerateSearchURLUsingTermsData(template_url,
           search_terms_data).GetOrigin();
@@ -265,7 +265,7 @@
     return;
   }
 
-  DCHECK(!template_url->IsExtensionKeyword());
+  DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
 
   IOThreadSearchTermsData search_terms_data(google_base_url_);
   const GURL url(TemplateURLService::GenerateSearchURLUsingTermsData(
diff --git a/chrome/browser/search_engines/search_terms_data.cc b/chrome/browser/search_engines/search_terms_data.cc
index d4af802..34c3194 100644
--- a/chrome/browser/search_engines/search_terms_data.cc
+++ b/chrome/browser/search_engines/search_terms_data.cc
@@ -73,7 +73,8 @@
   return std::string();
 }
 
-std::string SearchTermsData::InstantEnabledParam() const {
+std::string SearchTermsData::ForceInstantResultsParam(
+    bool for_prerender) const {
   return std::string();
 }
 
@@ -150,10 +151,12 @@
   return chrome::IsInstantExtendedAPIEnabled() ? "chrome-omni" : "chrome";
 }
 
-std::string UIThreadSearchTermsData::InstantEnabledParam() const {
+std::string UIThreadSearchTermsData::ForceInstantResultsParam(
+    bool for_prerender) const {
   DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
          BrowserThread::CurrentlyOn(BrowserThread::UI));
-  return chrome::IsInstantExtendedAPIEnabled() ? std::string() : "ion=1&";
+  return (for_prerender || !chrome::IsInstantExtendedAPIEnabled()) ? "ion=1&" :
+      std::string();
 }
 
 std::string UIThreadSearchTermsData::InstantExtendedEnabledParam() const {
diff --git a/chrome/browser/search_engines/search_terms_data.h b/chrome/browser/search_engines/search_terms_data.h
index cbd1e7d..4980df6 100644
--- a/chrome/browser/search_engines/search_terms_data.h
+++ b/chrome/browser/search_engines/search_terms_data.h
@@ -44,14 +44,15 @@
   // implementation returns the empty string.
   virtual std::string GetSuggestClient() const;
 
-  // Returns a string indicating whether Instant (in the visible-preview mode)
-  // is enabled, suitable for adding as a query string param to the homepage
-  // (instant_url) request. Returns an empty string if Instant is disabled, or
-  // if it's only active in a hidden field trial mode, or if InstantExtended is
-  // enabled (since that supercedes regular Instant). Determining this requires
-  // accessing the Profile, so this can only ever be non-empty for
-  // UIThreadSearchTermsData.
-  virtual std::string InstantEnabledParam() const;
+  // Returns a string that will cause the search results page to update
+  // incrementally. Currently, Instant Extended passes a different param to
+  // search results pages that also has this effect, so by default this function
+  // returns the empty string when Instant Extended is enabled. However, when
+  // doing instant search result prerendering, we still need to pass this param,
+  // as Instant Extended does not cause incremental updates by default for the
+  // prerender page. Callers should set |for_prerender| in this case to force
+  // the returned string to be non-empty.
+  virtual std::string ForceInstantResultsParam(bool for_prerender) const;
 
   // Returns a string indicating whether InstantExtended is enabled, suitable
   // for adding as a query string param to the homepage or search requests.
@@ -74,7 +75,7 @@
 class UIThreadSearchTermsData : public SearchTermsData {
  public:
   // If |profile_| is NULL, the Google base URL accessors will return default
-  // values, and InstantEnabledParam(), InstantExtendedEnabledParam(), and
+  // values, and ForceInstantResultsParam(), InstantExtendedEnabledParam(), and
   // NTPIsThemedParam(), will return the empty string.
   explicit UIThreadSearchTermsData(Profile* profile);
 
@@ -83,7 +84,8 @@
   virtual string16 GetRlzParameterValue() const OVERRIDE;
   virtual std::string GetSearchClient() const OVERRIDE;
   virtual std::string GetSuggestClient() const OVERRIDE;
-  virtual std::string InstantEnabledParam() const OVERRIDE;
+  virtual std::string ForceInstantResultsParam(
+      bool for_prerender) const OVERRIDE;
   virtual std::string InstantExtendedEnabledParam() const OVERRIDE;
   virtual std::string NTPIsThemedParam() const OVERRIDE;
 
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
index 19019fb..abe0a0f 100644
--- a/chrome/browser/search_engines/template_url.cc
+++ b/chrome/browser/search_engines/template_url.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/search_engines/template_url.h"
 
+#include <string>
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/command_line.h"
 #include "base/format_macros.h"
@@ -63,7 +66,7 @@
 const char kGoogleBaseSuggestURLParameterFull[] = "{google:baseSuggestURL}";
 const char kGoogleBookmarkBarPinnedParameter[] = "google:bookmarkBarPinned";
 const char kGoogleCursorPositionParameter[] = "google:cursorPosition";
-const char kGoogleInstantEnabledParameter[] = "google:instantEnabledParameter";
+const char kGoogleForceInstantResultsParameter[] = "google:forceInstantResults";
 const char kGoogleInstantExtendedEnabledParameter[] =
     "google:instantExtendedEnabledParameter";
 const char kGoogleInstantExtendedEnabledKey[] =
@@ -201,7 +204,8 @@
       omnibox_start_margin(-1),
       page_classification(AutocompleteInput::INVALID_SPEC),
       bookmark_bar_pinned(false),
-      append_extra_query_params(false) {
+      append_extra_query_params(false),
+      force_instant_results(false) {
 }
 
 TemplateURLRef::SearchTermsArgs::~SearchTermsArgs() {
@@ -334,23 +338,30 @@
   std::string url(HandleReplacements(search_terms_args, search_terms_data,
                                      post_content));
 
-  // If the user specified additional query params on the command line, add
-  // them.
-  if (search_terms_args.append_extra_query_params) {
-    std::string query_params(CommandLine::ForCurrentProcess()->
-        GetSwitchValueASCII(switches::kExtraSearchQueryParams));
-    GURL gurl(url);
-    if (!query_params.empty() && gurl.is_valid()) {
-      GURL::Replacements replacements;
-      const std::string existing_query_params(gurl.query());
-      if (!existing_query_params.empty())
-        query_params += "&" + existing_query_params;
-      replacements.SetQueryStr(query_params);
-      return gurl.ReplaceComponents(replacements).possibly_invalid_spec();
-    }
-  }
+  GURL gurl(url);
+  if (!gurl.is_valid())
+    return url;
 
-  return url;
+  std::vector<std::string> query_params;
+  if (search_terms_args.append_extra_query_params) {
+    std::string extra_params(
+        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kExtraSearchQueryParams));
+    if (!extra_params.empty())
+      query_params.push_back(extra_params);
+  }
+  if (!search_terms_args.suggest_query_params.empty())
+    query_params.push_back(search_terms_args.suggest_query_params);
+  if (!gurl.query().empty())
+    query_params.push_back(gurl.query());
+
+  if (query_params.empty())
+    return url;
+
+  GURL::Replacements replacements;
+  std::string query_str = JoinString(query_params, "&");
+  replacements.SetQueryStr(query_str);
+  return gurl.ReplaceComponents(replacements).possibly_invalid_spec();
 }
 
 bool TemplateURLRef::IsValid() const {
@@ -564,8 +575,8 @@
   } else if (parameter == kGoogleImageURLParameter) {
     replacements->push_back(Replacement(TemplateURLRef::GOOGLE_IMAGE_URL,
                                         start));
-  } else if (parameter == kGoogleInstantEnabledParameter) {
-    replacements->push_back(Replacement(GOOGLE_INSTANT_ENABLED, start));
+  } else if (parameter == kGoogleForceInstantResultsParameter) {
+    replacements->push_back(Replacement(GOOGLE_FORCE_INSTANT_RESULTS, start));
   } else if (parameter == kGoogleInstantExtendedEnabledParameter) {
     replacements->push_back(Replacement(GOOGLE_INSTANT_EXTENDED_ENABLED,
                                         start));
@@ -861,10 +872,13 @@
               &url);
         break;
 
-      case GOOGLE_INSTANT_ENABLED:
+      case GOOGLE_FORCE_INSTANT_RESULTS:
         DCHECK(!i->is_post_param);
-        HandleReplacement(
-            std::string(), search_terms_data.InstantEnabledParam(), *i, &url);
+        HandleReplacement(std::string(),
+                          search_terms_data.ForceInstantResultsParam(
+                              search_terms_args.force_instant_results),
+                          *i,
+                          &url);
         break;
 
       case GOOGLE_INSTANT_EXTENDED_ENABLED:
@@ -1107,7 +1121,7 @@
 }
 
 bool TemplateURL::IsGoogleSearchURLWithReplaceableKeyword() const {
-  return !IsExtensionKeyword() && url_ref_.HasGoogleBaseURLs() &&
+  return (GetType() == NORMAL) && url_ref_.HasGoogleBaseURLs() &&
       google_util::IsGoogleHostname(UTF16ToUTF8(data_.keyword()),
                                     google_util::DISALLOW_SUBDOMAIN);
 }
@@ -1118,13 +1132,17 @@
        other.IsGoogleSearchURLWithReplaceableKeyword());
 }
 
-std::string TemplateURL::GetExtensionId() const {
-  DCHECK(IsExtensionKeyword());
-  return GURL(data_.url()).host();
+TemplateURL::Type TemplateURL::GetType() const {
+  if (extension_info_)
+    return NORMAL_CONTROLLED_BY_EXTENSION;
+  return GURL(data_.url()).SchemeIs(extensions::kExtensionScheme) ?
+      OMNIBOX_API_EXTENSION : NORMAL;
 }
 
-bool TemplateURL::IsExtensionKeyword() const {
-  return GURL(data_.url()).SchemeIs(extensions::kExtensionScheme);
+std::string TemplateURL::GetExtensionId() const {
+  DCHECK_NE(NORMAL, GetType());
+  return extension_info_ ?
+      extension_info_->extension_id : GURL(data_.url()).host();
 }
 
 size_t TemplateURL::URLCount() const {
@@ -1274,7 +1292,7 @@
 
 void TemplateURL::ResetKeywordIfNecessary(bool force) {
   if (IsGoogleSearchURLWithReplaceableKeyword() || force) {
-    DCHECK(!IsExtensionKeyword());
+    DCHECK(GetType() != OMNIBOX_API_EXTENSION);
     GURL url(TemplateURLService::GenerateSearchURL(this));
     if (url.is_valid())
       data_.SetKeyword(TemplateURLService::GenerateKeyword(url));
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
index ec5d142..ff95397 100644
--- a/chrome/browser/search_engines/template_url.h
+++ b/chrome/browser/search_engines/template_url.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/search_engines/template_url_id.h"
@@ -104,6 +105,9 @@
     // True for searches issued with the bookmark bar pref set to shown.
     bool bookmark_bar_pinned;
 
+    // Additional query params provided by the suggest server.
+    std::string suggest_query_params;
+
     // If set, ReplaceSearchTerms() will automatically append any extra query
     // params specified via the --extra-search-query-params command-line
     // argument.  Generally, this should be set when dealing with the search or
@@ -123,6 +127,12 @@
 
     // When searching for an image, the original size of the image.
     gfx::Size image_original_size;
+
+    // If set, ReplaceSearchTerms() will append a param to the TemplateURLRef to
+    // update the search results page incrementally even if that is otherwise
+    // disabled by google.com preferences. See comments on
+    // SearchTermsData::ForceInstantResultsParam().
+    bool force_instant_results;
   };
 
   TemplateURLRef(TemplateURL* owner, Type type);
@@ -249,7 +259,7 @@
     GOOGLE_IMAGE_SEARCH_SOURCE,
     GOOGLE_IMAGE_THUMBNAIL,
     GOOGLE_IMAGE_URL,
-    GOOGLE_INSTANT_ENABLED,
+    GOOGLE_FORCE_INSTANT_RESULTS,
     GOOGLE_INSTANT_EXTENDED_ENABLED,
     GOOGLE_NTP_IS_THEMED,
     GOOGLE_OMNIBOX_START_MARGIN,
@@ -505,6 +515,22 @@
 };
 
 
+// AssociatedExtensionInfo ----------------------------------------------------
+
+// An AssociatedExtensionInfo represents information about the extension that
+// added the search engine using the Override Settings API.
+struct AssociatedExtensionInfo {
+  std::string extension_id;
+
+  // Whether the search engine is supposed to be default.
+  bool wants_to_be_default_engine;
+
+  // Used to resolve conflicts when there are multiple extensions specifying the
+  // default search engine. The most recently-installed wins.
+  base::Time install_time;
+};
+
+
 // TemplateURL ----------------------------------------------------------------
 
 // A TemplateURL represents a single "search engine", defined primarily as a
@@ -520,6 +546,14 @@
 // is made a friend so that it can be the exception to this pattern.
 class TemplateURL {
  public:
+  enum Type {
+    // Regular search engine.
+    NORMAL,
+    // Installed by extension through Override Settings API.
+    NORMAL_CONTROLLED_BY_EXTENSION,
+    // The keyword associated with an extension that uses the Omnibox API.
+    OMNIBOX_API_EXTENSION,
+  };
   // |profile| may be NULL.  This will affect the results of e.g. calling
   // ReplaceSearchTerms() on the member TemplateURLRefs.
   TemplateURL(Profile* profile, const TemplateURLData& data);
@@ -615,8 +649,12 @@
   // IsGoogleSearchURLWithReplaceableKeyword() is true for both TemplateURLs.
   bool HasSameKeywordAs(const TemplateURL& other) const;
 
+  Type GetType() const;
+
+  // Returns the id of the extension that added this search engine. Only call
+  // this for TemplateURLs of type NORMAL_CONTROLLED_BY_EXTENSION or
+  // OMNIBOX_API_EXTENSION.
   std::string GetExtensionId() const;
-  bool IsExtensionKeyword() const;
 
   // Returns the total number of URLs comprised in this template, including
   // search and alternate URLs.
@@ -721,6 +759,7 @@
   TemplateURLRef instant_url_ref_;
   TemplateURLRef image_url_ref_;
   TemplateURLRef new_tab_url_ref_;
+  scoped_ptr<AssociatedExtensionInfo> extension_info_;
 
   // TODO(sky): Add date last parsed OSD file.
 
diff --git a/chrome/browser/search_engines/template_url_fetcher_unittest.cc b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
index f55aca1..8d50ddf 100644
--- a/chrome/browser/search_engines/template_url_fetcher_unittest.cc
+++ b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
@@ -108,10 +108,7 @@
 }
 
 TemplateURLFetcherTest::TemplateURLFetcherTest()
-    : test_server_(
-        content::BrowserThread::GetMessageLoopProxyForThread(
-            content::BrowserThread::IO)),
-      callbacks_destroyed_(0),
+    : callbacks_destroyed_(0),
       add_provider_called_(0),
       waiting_for_download_(false) {
   base::FilePath src_dir;
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index c560e8f..606cc98 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -113,10 +113,9 @@
     const TemplateURLService::TemplateURLVector& template_urls) {
   for (TemplateURLService::TemplateURLVector::const_iterator i(
        template_urls.begin()); i != template_urls.end(); ++i) {
-    if ((*i)->ShowInDefaultList()) {
-      DCHECK(!(*i)->IsExtensionKeyword());
+    if ((*i)->ShowInDefaultList() &&
+        ((*i)->GetType() == TemplateURL::NORMAL))
       return *i;
-    }
   }
   return NULL;
 }
@@ -538,11 +537,55 @@
   Add(template_url);
 }
 
+void TemplateURLService::AddExtensionControlledTURL(
+    TemplateURL* template_url,
+    scoped_ptr<AssociatedExtensionInfo> info) {
+  DCHECK(loaded_);
+  DCHECK(template_url);
+  DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
+  DCHECK(info);
+  template_url->extension_info_.swap(info);
+  DCHECK(!FindTemplateURLForExtension(
+      template_url->GetExtensionId(),
+      TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION));
+
+  if (AddNoNotify(template_url, true)) {
+    if (template_url->extension_info_->wants_to_be_default_engine &&
+        !is_default_search_managed()) {
+      TemplateURL* default_candidate = FindExtensionDefaultSearchEngine();
+      if (default_candidate == template_url) {
+        base::AutoReset<DefaultSearchChangeOrigin> change_origin(
+            &dsp_change_origin_, DSP_CHANGE_OVERRIDE_SETTINGS_EXTENSION);
+        SetDefaultSearchProviderNoNotify(template_url);
+      }
+    }
+    NotifyObservers();
+  }
+}
+
 void TemplateURLService::Remove(TemplateURL* template_url) {
   RemoveNoNotify(template_url);
   NotifyObservers();
 }
 
+void TemplateURLService::RemoveExtensionControlledTURL(
+    const std::string& extension_id) {
+  DCHECK(loaded_);
+  TemplateURL* url = FindTemplateURLForExtension(
+      extension_id, TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION);
+  if (!url)
+    return;
+  bool restore_dse = (url == GetDefaultSearchProvider());
+  if (restore_dse) {
+    DCHECK(!is_default_search_managed());
+    default_search_provider_ = NULL;
+  }
+  RemoveNoNotify(url);
+  if (restore_dse)
+    SetDefaultSearchProviderAfterRemovingDefaultExtension();
+  NotifyObservers();
+}
+
 void TemplateURLService::RemoveAutoGeneratedSince(base::Time created_after) {
   RemoveAutoGeneratedBetween(created_after, base::Time());
 }
@@ -576,48 +619,42 @@
 }
 
 
-void TemplateURLService::RegisterExtensionKeyword(
+void TemplateURLService::RegisterOmniboxKeyword(
     const std::string& extension_id,
     const std::string& extension_name,
     const std::string& keyword) {
   DCHECK(loaded_);
 
-  if (!GetTemplateURLForExtension(extension_id)) {
+  if (!FindTemplateURLForExtension(extension_id,
+                                   TemplateURL::OMNIBOX_API_EXTENSION)) {
     ExtensionKeyword extension_url(extension_id, extension_name, keyword);
     Add(CreateTemplateURLForExtension(extension_url));
   }
 }
 
-void TemplateURLService::UnregisterExtensionKeyword(
+void TemplateURLService::UnregisterOmniboxKeyword(
     const std::string& extension_id) {
   DCHECK(loaded_);
-  TemplateURL* url = GetTemplateURLForExtension(extension_id);
+  TemplateURL* url = FindTemplateURLForExtension(
+      extension_id, TemplateURL::OMNIBOX_API_EXTENSION);
   if (url)
     Remove(url);
 }
 
-TemplateURL* TemplateURLService::GetTemplateURLForExtension(
-    const std::string& extension_id) {
-  for (TemplateURLVector::const_iterator i = template_urls_.begin();
-       i != template_urls_.end(); ++i) {
-    if ((*i)->IsExtensionKeyword() &&
-        ((*i)->url_ref().GetHost() == extension_id))
-      return *i;
-  }
-
-  return NULL;
-}
-
 TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() {
   return template_urls_;
 }
 
 void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
   DCHECK(url);
+  // Extension-controlled search engines are not persisted.
+  if (url->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
+    return;
   if (std::find(template_urls_.begin(), template_urls_.end(), url) ==
       template_urls_.end())
     return;
   ++url->data_.usage_count;
+
   if (service_.get())
     service_.get()->UpdateKeyword(url->data());
 }
@@ -648,13 +685,16 @@
 
 bool TemplateURLService::CanMakeDefault(const TemplateURL* url) {
   return url != GetDefaultSearchProvider() &&
-      url->url_ref().SupportsReplacement() && !is_default_search_managed();
+      url->url_ref().SupportsReplacement() && !is_default_search_managed() &&
+      (url->GetType() == TemplateURL::NORMAL);
 }
 
 void TemplateURLService::SetDefaultSearchProvider(TemplateURL* url) {
   DCHECK(!is_default_search_managed_);
-  // Extension keywords cannot be made default, as they are inherently async.
-  DCHECK(!url || !url->IsExtensionKeyword());
+  // Omnibox keywords cannot be made default. Extension-controlled search
+  // engines can be made default only by the extension itself because they
+  // aren't persisted.
+  DCHECK(!url || (url->GetType() == TemplateURL::NORMAL));
 
   // Always persist the setting in the database, that way if the backup
   // signature has changed out from under us it gets reset correctly.
@@ -831,17 +871,19 @@
   on_loaded_callbacks_.Notify();
 }
 
-string16 TemplateURLService::GetKeywordShortName(const string16& keyword,
-                                                 bool* is_extension_keyword) {
+string16 TemplateURLService::GetKeywordShortName(
+    const string16& keyword,
+    bool* is_omnibox_api_extension_keyword) {
   const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
 
   // TODO(sky): Once LocationBarView adds a listener to the TemplateURLService
   // to track changes to the model, this should become a DCHECK.
   if (template_url) {
-    *is_extension_keyword = template_url->IsExtensionKeyword();
+    *is_omnibox_api_extension_keyword =
+        template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
     return template_url->AdjustedShortNameForLocaleDirection();
   }
-  *is_extension_keyword = false;
+  *is_omnibox_api_extension_keyword = false;
   return string16();
 }
 
@@ -912,6 +954,9 @@
     // We don't sync keywords managed by policy.
     if ((*iter)->created_by_policy())
       continue;
+    // We don't sync extension-controlled search engines.
+    if ((*iter)->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
+      continue;
     current_data.push_back(CreateSyncDataFromTemplateURL(**iter));
   }
 
@@ -1225,6 +1270,10 @@
   if (turl->created_by_policy())
     return;
 
+  // Avoid syncing extension-controlled search engines.
+  if (turl->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
+    return;
+
   syncer::SyncChangeList changes;
 
   syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
@@ -1348,6 +1397,7 @@
   // possible that sync is trying to modify fields that should not be touched.
   // Revert these fields to the built-in values.
   UpdateTemplateURLIfPrepopulated(turl, profile);
+  DCHECK_NE(TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION, turl->GetType());
   if (reset_keyword || deduped) {
     if (reset_keyword)
       turl->ResetKeywordIfNecessary(true);
@@ -1475,10 +1525,12 @@
          i != template_urls_.end(); ++i) {
       TemplateURL* turl = *i;
       // This next statement relies on the fact that there can only be one
-      // non-extension TemplateURL with a given keyword.
+      // non-Omnibox API TemplateURL with a given keyword.
       if ((turl != template_url) && (turl->keyword() == keyword) &&
-          (!best_fallback || !best_fallback->IsExtensionKeyword() ||
-           (turl->IsExtensionKeyword() && (turl->id() > best_fallback->id()))))
+          (!best_fallback ||
+           (best_fallback->GetType() != TemplateURL::OMNIBOX_API_EXTENSION) ||
+           ((turl->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) &&
+            (turl->id() > best_fallback->id()))))
         best_fallback = turl;
     }
     if (best_fallback)
@@ -1495,22 +1547,9 @@
   }
 }
 
-void TemplateURLService::RemoveFromKeywordMapByPointer(
-    TemplateURL* template_url) {
-  DCHECK(template_url);
-  for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
-       i != keyword_to_template_map_.end(); ++i) {
-    if (i->second == template_url) {
-      keyword_to_template_map_.erase(i);
-      // A given TemplateURL only occurs once in the map. As soon as we find the
-      // entry, stop.
-      break;
-    }
-  }
-}
-
 void TemplateURLService::AddToMaps(TemplateURL* template_url) {
-  bool template_extension = template_url->IsExtensionKeyword();
+  bool template_url_is_omnibox_api =
+      template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
   const string16& keyword = template_url->keyword();
   KeywordToTemplateMap::const_iterator i =
       keyword_to_template_map_.find(keyword);
@@ -1522,9 +1561,10 @@
     // an extension.  In that case, the ranking order is:
     //   Manually-modified keywords > extension keywords > replaceable keywords
     // When there are multiple extensions, the last-added wins.
-    bool existing_extension = existing_url->IsExtensionKeyword();
-    DCHECK(existing_extension || template_extension);
-    if (existing_extension ?
+    bool existing_url_is_omnibox_api =
+        existing_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
+    DCHECK(existing_url_is_omnibox_api || template_url_is_omnibox_api);
+    if (existing_url_is_omnibox_api ?
         !CanReplace(template_url) : CanReplace(existing_url))
       keyword_to_template_map_[keyword] = template_url;
   }
@@ -1603,7 +1643,7 @@
   ListValue alternate_urls;
   std::string search_terms_replacement_key;
   if (t_url) {
-    DCHECK(!t_url->IsExtensionKeyword());
+    DCHECK_EQ(TemplateURL::NORMAL, t_url->GetType());
     enabled = true;
     search_url = t_url->url();
     suggest_url = t_url->suggestions_url();
@@ -1747,7 +1787,7 @@
     data.prepopulate_id = value;
   }
   default_provider->reset(new TemplateURL(profile_, data));
-  DCHECK(!(*default_provider)->IsExtensionKeyword());
+  DCHECK_EQ(TemplateURL::NORMAL, (*default_provider)->GetType());
   if (update_keyword)
     (*default_provider)->ResetKeywordIfNecessary(true);
   return true;
@@ -1788,13 +1828,14 @@
 TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
     const string16& keyword) {
   TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
-  if (!keyword_turl || !keyword_turl->IsExtensionKeyword())
+  if (!keyword_turl || (keyword_turl->GetType() == TemplateURL::NORMAL))
     return keyword_turl;
   // The extension keyword in the model may be hiding a replaceable
   // non-extension keyword.  Look for it.
   for (TemplateURLVector::const_iterator i(template_urls_.begin());
        i != template_urls_.end(); ++i) {
-    if (!(*i)->IsExtensionKeyword() && ((*i)->keyword() == keyword))
+    if (((*i)->GetType() == TemplateURL::NORMAL) &&
+        ((*i)->keyword() == keyword))
       return *i;
   }
   return NULL;
@@ -1837,7 +1878,7 @@
     //     case we delete the existing keyword if it's replaceable, or else undo
     //     the change in keyword for |existing_turl|.
     TemplateURL* existing_keyword_turl = i->second;
-    if (existing_keyword_turl->IsExtensionKeyword()) {
+    if (existing_keyword_turl->GetType() != TemplateURL::NORMAL) {
       if (!CanReplace(existing_turl))
         keyword_to_template_map_[keyword] = existing_turl;
     } else {
@@ -2097,8 +2138,8 @@
     if (std::find(template_urls_.begin(), template_urls_.end(), url) ==
         template_urls_.end())
       return false;
-    // Extension keywords cannot be made default, as they're inherently async.
-    DCHECK(!url->IsExtensionKeyword());
+    // Omnibox keywords cannot be made default.
+    DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, url->GetType());
   }
 
   // Only bother reassigning |url| if it has changed. Notice that we don't just
@@ -2106,16 +2147,25 @@
   // changed, and needs to be persisted below (for example, when this is called
   // from UpdateNoNotify).
   if (default_search_provider_ != url) {
-    UMA_HISTOGRAM_ENUMERATION("Search.DefaultSearchChangeOrigin",
-                              dsp_change_origin_, DSP_CHANGE_MAX);
-    default_search_provider_ = url;
+    // Engines set by policy override extension-controlled engines, which
+    // override other engines.
+    DCHECK(!is_default_search_managed() || !url ||
+           (url->GetType() == TemplateURL::NORMAL));
+    if (is_default_search_managed() || !default_search_provider_ ||
+        (default_search_provider_->GetType() == TemplateURL::NORMAL) ||
+        (url &&
+         (url->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION))){
+      UMA_HISTOGRAM_ENUMERATION("Search.DefaultSearchChangeOrigin",
+                                dsp_change_origin_, DSP_CHANGE_MAX);
+      default_search_provider_ = url;
+    }
   }
 
   if (url) {
     // Don't mark the url as edited, otherwise we won't be able to rev the
     // template urls we ship with.
     url->data_.show_in_default_list = true;
-    if (service_.get())
+    if (service_.get() && (url->GetType() == TemplateURL::NORMAL))
       service_->UpdateKeyword(url->data());
 
     if (url->url_ref().HasGoogleBaseURLs()) {
@@ -2128,6 +2178,10 @@
     }
   }
 
+  // Extension-controlled search engines shouldn't be persisted anywhere.
+  if (url && (url->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION))
+    return true;
+
   if (!is_default_search_managed_) {
     SaveDefaultSearchProviderToPrefs(url);
 
@@ -2177,8 +2231,8 @@
     DCHECK_NE(existing_keyword_turl, template_url);
     // Only replace one of the TemplateURLs if they are either both extensions,
     // or both not extensions.
-    bool are_same_type = existing_keyword_turl->IsExtensionKeyword() ==
-        template_url->IsExtensionKeyword();
+    bool are_same_type = existing_keyword_turl->GetType() ==
+        template_url->GetType();
     if (CanReplace(existing_keyword_turl) && are_same_type) {
       RemoveNoNotify(existing_keyword_turl);
     } else if (CanReplace(template_url) && are_same_type) {
@@ -2194,7 +2248,9 @@
   template_urls_.push_back(template_url);
   AddToMaps(template_url);
 
-  if (newly_adding) {
+  if (newly_adding &&
+      (template_url->GetType() !=
+          TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)) {
     if (service_.get())
       service_->AddKeyword(template_url->data());
 
@@ -2225,15 +2281,18 @@
   // Remove it from the vector containing all TemplateURLs.
   template_urls_.erase(i);
 
-  if (service_.get())
-    service_->RemoveKeyword(template_url->id());
+  if (template_url->GetType() != TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION) {
+    if (service_.get())
+      service_->RemoveKeyword(template_url->id());
 
-  // Inform sync of the deletion.
-  ProcessTemplateURLChange(FROM_HERE,
-                           template_url,
-                           syncer::SyncChange::ACTION_DELETE);
-  UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
-      DELETE_ENGINE_USER_ACTION, DELETE_ENGINE_MAX);
+    // Inform sync of the deletion.
+    ProcessTemplateURLChange(FROM_HERE,
+                             template_url,
+                             syncer::SyncChange::ACTION_DELETE);
+
+    UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
+                              DELETE_ENGINE_USER_ACTION, DELETE_ENGINE_MAX);
+  }
 
   if (profile_) {
     content::Source<Profile> source(profile_);
@@ -2325,7 +2384,8 @@
     // First, try to return the generated keyword for the TemplateURL (except
     // for extensions, as their keywords are not associated with their URLs).
     GURL gurl(turl.url());
-    if (gurl.is_valid() && !turl.IsExtensionKeyword()) {
+    if (gurl.is_valid() &&
+        (turl.GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
       string16 keyword_candidate = GenerateKeyword(gurl);
       if (!GetTemplateURLForKeyword(keyword_candidate))
         return keyword_candidate;
@@ -2361,6 +2421,8 @@
   DCHECK(applied_sync_turl);
   DCHECK(change_list);
   DCHECK_EQ(applied_sync_turl->keyword(), unapplied_sync_turl->keyword());
+  DCHECK_NE(TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION,
+            applied_sync_turl->GetType());
 
   // Both |unapplied_sync_turl| and |applied_sync_turl| are known to Sync, so
   // don't delete either of them. Instead, determine which is "better" and
@@ -2511,7 +2573,9 @@
        i != template_urls->end(); ++i) {
     TemplateURL* template_url = *i;
     DCHECK(template_url);
-    if (template_url->sync_guid().empty()) {
+    if (template_url->sync_guid().empty() &&
+        (template_url->GetType() !=
+            TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)) {
       template_url->data_.sync_guid = base::GenerateGUID();
       if (service_.get())
         service_->UpdateKeyword(template_url->data());
@@ -2560,8 +2624,9 @@
     }
     // Note that this saves the default search provider to prefs.
     if (!default_search_provider ||
-        (!default_search_provider->IsExtensionKeyword() &&
-            default_search_provider->SupportsReplacement())) {
+        ((default_search_provider->GetType() !=
+            TemplateURL::OMNIBOX_API_EXTENSION) &&
+         default_search_provider->SupportsReplacement())) {
       bool success = SetDefaultSearchProviderNoNotify(default_search_provider);
       DCHECK(success);
     }
@@ -2603,7 +2668,7 @@
 }
 
 void TemplateURLService::EnsureDefaultSearchProviderExists() {
-  if (!is_default_search_managed_) {
+  if (!is_default_search_managed()) {
     bool has_default_search_provider = default_search_provider_ &&
         default_search_provider_->SupportsReplacement();
     UMA_HISTOGRAM_BOOLEAN("Search.HasDefaultSearchProvider",
@@ -2640,3 +2705,56 @@
       extension_keyword.extension_id + "/?q={searchTerms}");
   return new TemplateURL(profile_, data);
 }
+
+TemplateURL* TemplateURLService::FindTemplateURLForExtension(
+    const std::string& extension_id,
+    TemplateURL::Type type) const {
+  DCHECK_NE(TemplateURL::NORMAL, type);
+  for (TemplateURLVector::const_iterator i = template_urls_.begin();
+       i != template_urls_.end(); ++i) {
+    if ((*i)->GetType() == type &&
+        (*i)->GetExtensionId() == extension_id)
+      return *i;
+  }
+
+  return NULL;
+}
+
+TemplateURL* TemplateURLService::FindExtensionDefaultSearchEngine() const {
+  TemplateURL* most_recently_intalled_default = NULL;
+  for (TemplateURLVector::const_iterator i = template_urls_.begin();
+       i != template_urls_.end(); ++i) {
+    if (((*i)->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION) &&
+        (*i)->extension_info_->wants_to_be_default_engine &&
+        (*i)->SupportsReplacement() &&
+        (!most_recently_intalled_default ||
+         (most_recently_intalled_default->extension_info_->install_time <
+             (*i)->extension_info_->install_time)))
+      most_recently_intalled_default = *i;
+  }
+
+  return most_recently_intalled_default;
+}
+
+void TemplateURLService::
+    SetDefaultSearchProviderAfterRemovingDefaultExtension() {
+  DCHECK(!is_default_search_managed());
+  TemplateURL* new_dse = FindExtensionDefaultSearchEngine();
+  if (!new_dse) {
+    scoped_ptr<TemplateURL> default_provider;
+    bool is_managed;
+    if (LoadDefaultSearchProviderFromPrefs(&default_provider, &is_managed) &&
+        default_provider) {
+      for (TemplateURLVector::const_iterator i = template_urls_.begin();
+           i != template_urls_.end(); ++i) {
+        if ((*i)->id() == default_provider->id()) {
+          new_dse = *i;
+          break;
+        }
+      }
+    }
+  }
+  if (!new_dse)
+    new_dse = FindNewDefaultSearchProvider();
+  SetDefaultSearchProviderNoNotify(new_dse);
+}
diff --git a/chrome/browser/search_engines/template_url_service.h b/chrome/browser/search_engines/template_url_service.h
index 588c2de..c670d0c 100644
--- a/chrome/browser/search_engines/template_url_service.h
+++ b/chrome/browser/search_engines/template_url_service.h
@@ -166,10 +166,19 @@
                         const string16& keyword,
                         const std::string& url);
 
+  // Add the search engine of type NORMAL_CONTROLLED_BY_EXTENSION.
+  void AddExtensionControlledTURL(TemplateURL* template_url,
+                                  scoped_ptr<AssociatedExtensionInfo> info);
+
   // Removes the keyword from the model. This deletes the supplied TemplateURL.
   // This fails if the supplied template_url is the default search provider.
   void Remove(TemplateURL* template_url);
 
+  // Removes any TemplateURL of type NORMAL_CONTROLLED_BY_EXTENSION associated
+  // with |extension_id|. Unlike with Remove(), this can be called when the
+  // TemplateURL in question is the current default search provider.
+  void RemoveExtensionControlledTURL(const std::string& extension_id);
+
   // Removes all auto-generated keywords that were created on or after the
   // date passed in.
   void RemoveAutoGeneratedSince(base::Time created_after);
@@ -189,17 +198,13 @@
   // Adds a TemplateURL for an extension with an omnibox keyword.
   // Only 1 keyword is allowed for a given extension. If a keyword
   // already exists for this extension, does nothing.
-  void RegisterExtensionKeyword(const std::string& extension_id,
-                                const std::string& extension_name,
-                                const std::string& keyword);
+  void RegisterOmniboxKeyword(const std::string& extension_id,
+                              const std::string& extension_name,
+                              const std::string& keyword);
 
   // Removes the TemplateURL containing the keyword for the extension with the
   // given ID, if any.
-  void UnregisterExtensionKeyword(const std::string& extension_id);
-
-  // Returns the TemplateURL associated with the keyword for this extension.
-  // This will work even if the user changed the keyword.
-  TemplateURL* GetTemplateURLForExtension(const std::string& extension_id);
+  void UnregisterOmniboxKeyword(const std::string& extension_id);
 
   // Returns the set of URLs describing the keywords. The elements are owned
   // by TemplateURLService and should not be deleted.
@@ -287,9 +292,9 @@
 
   // Returns the locale-direction-adjusted short name for the given keyword.
   // Also sets the out param to indicate whether the keyword belongs to an
-  // extension.
+  // Omnibox extension.
   string16 GetKeywordShortName(const string16& keyword,
-                               bool* is_extension_keyword);
+                               bool* is_omnibox_api_extension_keyword);
 
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
@@ -416,6 +421,8 @@
     DSP_CHANGE_OTHER,
     // Changed through "Profile Reset" feature.
     DSP_CHANGE_PROFILE_RESET,
+    // Changed by an extension through the Override Settings API.
+    DSP_CHANGE_OVERRIDE_SETTINGS_EXTENSION,
     // Boundary value.
     DSP_CHANGE_MAX,
   };
@@ -428,11 +435,6 @@
 
   void RemoveFromMaps(TemplateURL* template_url);
 
-  // Removes the supplied template_url from the keyword maps. This searches
-  // through all entries in the keyword map and does not generate the host or
-  // keyword. This is used when the cached content of the TemplateURL changes.
-  void RemoveFromKeywordMapByPointer(TemplateURL* template_url);
-
   void AddToMaps(TemplateURL* template_url);
 
   // Sets the keywords. This is used once the keywords have been loaded.
@@ -520,7 +522,13 @@
 
   // Set the default search provider even if it is managed. |url| may be null.
   // Caller is responsible for notifying observers.  Returns whether |url| was
-  // found in |template_urls_| and thus could be made default.
+  // found in |template_urls_|.
+  // If |url| is an extension-controlled search engine then preferences and the
+  // database are left untouched.
+  // If |url| is a normal search engine and the existing default search engine
+  // is controlled by an extension then |url| is propagated to the database and
+  // prefs but the extension-controlled default engine will continue to hide
+  // this value until the extension is uninstalled.
   bool SetDefaultSearchProviderNoNotify(TemplateURL* url);
 
   // Adds a new TemplateURL to this model. TemplateURLService will own the
@@ -644,6 +652,21 @@
   TemplateURL* CreateTemplateURLForExtension(
       const ExtensionKeyword& extension_keyword) const;
 
+  // Returns the TemplateURL associated with |extension_id|, if any.
+  TemplateURL* FindTemplateURLForExtension(const std::string& extension_id,
+                                           TemplateURL::Type type) const;
+
+  // Finds the most recently-installed NORMAL_CONTROLLED_BY_EXTENSION engine
+  // that supports replacement and wants to be default, if any.
+  TemplateURL* FindExtensionDefaultSearchEngine() const;
+
+  // Sets the default search provider to:
+  // (1) BestDefaultExtensionControlledTURL(), if any; or,
+  // (2) LoadDefaultSearchProviderFromPrefs(), if we have a TURL with that ID;
+  // or,
+  // (3) FindNewDefaultSearchProvider().
+  void SetDefaultSearchProviderAfterRemovingDefaultExtension();
+
   content::NotificationRegistrar notification_registrar_;
   PrefChangeRegistrar pref_change_registrar_;
 
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 252c58e..c40e7e0 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -87,7 +87,7 @@
   history::VisitVector visits;
 };
 
-TemplateURL* AddKeywordWithDate(
+TemplateURL* CreateKeywordWithDate(
     TemplateURLService* model,
     const std::string& short_name,
     const std::string& keyword,
@@ -111,7 +111,24 @@
   base::SplitString(encodings, ';', &data.input_encodings);
   data.date_created = date_created;
   data.last_modified = last_modified;
-  TemplateURL* t_url = new TemplateURL(model->profile(), data);
+  return new TemplateURL(model->profile(), data);
+}
+
+TemplateURL* AddKeywordWithDate(
+    TemplateURLService* model,
+    const std::string& short_name,
+    const std::string& keyword,
+    const std::string& url,
+    const std::string& suggest_url,
+    const std::string& alternate_url,
+    const std::string& favicon_url,
+    bool safe_for_autoreplace,
+    const std::string& encodings,
+    Time date_created,
+    Time last_modified) {
+  TemplateURL* t_url = CreateKeywordWithDate(
+      model, short_name, keyword, url, suggest_url, alternate_url,favicon_url,
+      safe_for_autoreplace, encodings, date_created, last_modified);
   model->Add(t_url);
   EXPECT_NE(0, t_url->id());
   return t_url;
@@ -912,7 +929,7 @@
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
 
   // Register an extension with bing keyword.
-  model()->RegisterExtensionKeyword("abcdefg", "extension_name", "bing.com");
+  model()->RegisterOmniboxKeyword("abcdefg", "extension_name", "bing.com");
   EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
 
   model()->RepairPrepopulatedSearchEngines();
@@ -927,7 +944,7 @@
   // Bing was repaired.
   bing = model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com"));
   ASSERT_TRUE(bing);
-  EXPECT_FALSE(bing->IsExtensionKeyword());
+  EXPECT_EQ(TemplateURL::NORMAL, bing->GetType());
 
   // User search engine is preserved.
   EXPECT_EQ(user_dse, model()->GetTemplateURLForHost("www.goo.com"));
@@ -1557,3 +1574,111 @@
   ASSERT_FALSE(loaded_url == NULL);
   EXPECT_EQ(4U, loaded_url->input_encodings().size());
 }
+
+TEST_F(TemplateURLServiceTest, DefaultExtensionEngine) {
+  test_util_.VerifyLoad();
+  // Add third-party default search engine.
+  TemplateURL* user_dse = AddKeywordWithDate(
+      "user", "user", "http://www.goo.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  model()->SetDefaultSearchProvider(user_dse);
+  EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
+
+  TemplateURL* ext_dse = CreateKeywordWithDate(
+      model(), "ext", "ext", "http://www.search.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  scoped_ptr<AssociatedExtensionInfo> extension_info(
+      new AssociatedExtensionInfo);
+  extension_info->wants_to_be_default_engine = true;
+  extension_info->extension_id = "ext";
+  model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
+  EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
+
+  model()->RemoveExtensionControlledTURL("ext");
+  ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
+}
+
+TEST_F(TemplateURLServiceTest, ExtensionEnginesNotPersist) {
+  test_util_.VerifyLoad();
+  // Add third-party default search engine.
+  TemplateURL* user_dse = AddKeywordWithDate(
+      "user", "user", "http://www.goo.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  model()->SetDefaultSearchProvider(user_dse);
+  EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
+
+  TemplateURL* ext_dse = CreateKeywordWithDate(
+      model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  scoped_ptr<AssociatedExtensionInfo> extension_info(
+      new AssociatedExtensionInfo);
+  extension_info->wants_to_be_default_engine = false;
+  extension_info->extension_id = "ext1";
+  model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
+  EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
+
+  ext_dse = CreateKeywordWithDate(
+      model(), "ext2", "ext2", "http://www.ext2.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  extension_info.reset(new AssociatedExtensionInfo);
+  extension_info->wants_to_be_default_engine = true;
+  extension_info->extension_id = "ext2";
+  model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
+  EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
+
+  test_util_.ResetModel(true);
+  user_dse = model()->GetTemplateURLForKeyword(ASCIIToUTF16("user"));
+  ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext2")));
+}
+
+TEST_F(TemplateURLServiceTest, ExtensionEngineVsPolicy) {
+  // Set a managed preference that establishes a default search provider.
+  const char kName[] = "test";
+  const char kKeyword[] = "test.com";
+  const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
+  const char kIconURL[] = "http://test.com/icon.jpg";
+  const char kEncodings[] = "UTF-16;UTF-32";
+  const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
+  const char kSearchTermsReplacementKey[] = "espv";
+  test_util_.SetManagedDefaultSearchPreferences(
+      true, kName, kKeyword, kSearchURL, std::string(), kIconURL, kEncodings,
+      kAlternateURL, kSearchTermsReplacementKey);
+  test_util_.VerifyLoad();
+  // Verify that the default manager we are getting is the managed one.
+  TemplateURLData data;
+  data.short_name = ASCIIToUTF16(kName);
+  data.SetKeyword(ASCIIToUTF16(kKeyword));
+  data.SetURL(kSearchURL);
+  data.favicon_url = GURL(kIconURL);
+  data.show_in_default_list = true;
+  base::SplitString(kEncodings, ';', &data.input_encodings);
+  data.alternate_urls.push_back(kAlternateURL);
+  data.search_terms_replacement_key = kSearchTermsReplacementKey;
+  scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(
+      test_util_.profile(), data));
+  EXPECT_TRUE(model()->is_default_search_managed());
+  const TemplateURL* actual_managed_default =
+      model()->GetDefaultSearchProvider();
+  ExpectSimilar(expected_managed_default.get(), actual_managed_default);
+
+  TemplateURL* ext_dse = CreateKeywordWithDate(
+      model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  scoped_ptr<AssociatedExtensionInfo> extension_info(
+      new AssociatedExtensionInfo);
+  extension_info->wants_to_be_default_engine = true;
+  extension_info->extension_id = "ext1";
+  model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
+  EXPECT_EQ(ext_dse, model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
+  EXPECT_TRUE(model()->is_default_search_managed());
+  actual_managed_default = model()->GetDefaultSearchProvider();
+  ExpectSimilar(expected_managed_default.get(), actual_managed_default);
+}
diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc
index 99f5b90..feb25f5 100644
--- a/chrome/browser/search_engines/template_url_unittest.cc
+++ b/chrome/browser/search_engines/template_url_unittest.cc
@@ -1142,6 +1142,36 @@
   EXPECT_EQ(GURL("http://google.com/alt/?q=#q=Bob Morane"), result);
 }
 
+// Test the |suggest_query_params| field of SearchTermsArgs.
+TEST_F(TemplateURLTest, SuggestQueryParams) {
+  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.google.com/");
+  TemplateURLData data;
+  // Pick a URL with replacements before, during, and after the query, to ensure
+  // we don't goof up any of them.
+  data.SetURL("{google:baseURL}search?q={searchTerms}"
+      "#{google:originalQueryForSuggestion}x");
+  TemplateURL url(NULL, data);
+
+  // Baseline: no |suggest_query_params| field.
+  TemplateURLRef::SearchTermsArgs search_terms(ASCIIToUTF16("abc"));
+  search_terms.original_query = ASCIIToUTF16("def");
+  search_terms.accepted_suggestion = 0;
+  EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+
+  // Set the suggest_query_params.
+  search_terms.suggest_query_params = "pq=xyz";
+  EXPECT_EQ("http://www.google.com/search?pq=xyz&q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+
+  // Add extra_query_params in the mix, and ensure it works.
+  search_terms.append_extra_query_params = true;
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+  EXPECT_EQ("http://www.google.com/search?a=b&pq=xyz&q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+}
+
 // Test the |append_extra_query_params| field of SearchTermsArgs.
 TEST_F(TemplateURLTest, ExtraQueryParams) {
   UIThreadSearchTermsData::SetGoogleBaseURL("http://www.google.com/");
diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc
index 9106178..cce142e 100644
--- a/chrome/browser/service/service_process_control.cc
+++ b/chrome/browser/service/service_process_control.cc
@@ -8,6 +8,9 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_delta_serialization.h"
+#include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/stl_util.h"
 #include "base/threading/thread.h"
@@ -178,6 +181,7 @@
   IPC_BEGIN_MESSAGE_MAP(ServiceProcessControl, message)
     IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_Info,
                         OnCloudPrintProxyInfo)
+    IPC_MESSAGE_HANDLER(ServiceHostMsg_Histograms, OnHistograms)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -230,13 +234,58 @@
   }
 }
 
+void ServiceProcessControl::OnHistograms(
+    const std::vector<std::string>& pickled_histograms) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  base::HistogramDeltaSerialization::DeserializeAndAddSamples(
+      pickled_histograms);
+  RunHistogramsCallback();
+}
+
+void ServiceProcessControl::RunHistogramsCallback() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!histograms_callback_.is_null()) {
+    histograms_callback_.Run();
+    histograms_callback_.Reset();
+  }
+  histograms_timeout_callback_.Cancel();
+}
+
 bool ServiceProcessControl::GetCloudPrintProxyInfo(
     const CloudPrintProxyInfoHandler& cloud_print_info_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(false, cloud_print_info_callback.is_null());
-
+  DCHECK(!cloud_print_info_callback.is_null());
+  cloud_print_info_callback_.Reset();
+  if (!Send(new ServiceMsg_GetCloudPrintProxyInfo()))
+    return false;
   cloud_print_info_callback_ = cloud_print_info_callback;
-  return Send(new ServiceMsg_GetCloudPrintProxyInfo());
+  return true;
+}
+
+bool ServiceProcessControl::GetHistograms(
+    const base::Closure& histograms_callback,
+    const base::TimeDelta& timeout) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!histograms_callback.is_null());
+  histograms_callback_.Reset();
+
+  // If the service process is already running then connect to it.
+  if (!CheckServiceProcessReady())
+    return false;
+  ConnectInternal();
+  if (!Send(new ServiceMsg_GetHistograms()))
+    return false;
+
+  // Run timeout task to make sure |histograms_callback| is called.
+  histograms_timeout_callback_.Reset(
+      base::Bind(&ServiceProcessControl::RunHistogramsCallback,
+                 base::Unretained(this)));
+  BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+                                 histograms_timeout_callback_.callback(),
+                                 timeout);
+
+  histograms_callback_ = histograms_callback;
+  return true;
 }
 
 bool ServiceProcessControl::Shutdown() {
@@ -256,7 +305,8 @@
     : process_(process),
       cmd_line_(cmd_line),
       launched_(false),
-      retry_count_(0) {
+      retry_count_(0),
+      process_handle_(base::kNullProcessHandle) {
 }
 
 // Execute the command line to start the process asynchronously.
@@ -269,21 +319,36 @@
                           base::Bind(&Launcher::DoRun, this));
 }
 
-ServiceProcessControl::Launcher::~Launcher() {}
+ServiceProcessControl::Launcher::~Launcher() {
+  CloseProcessHandle();
+}
+
 
 void ServiceProcessControl::Launcher::Notify() {
-  DCHECK_EQ(false, notify_task_.is_null());
+  DCHECK(!notify_task_.is_null());
   notify_task_.Run();
   notify_task_.Reset();
 }
 
+void ServiceProcessControl::Launcher::CloseProcessHandle() {
+  if (process_handle_ != base::kNullProcessHandle) {
+    base::CloseProcessHandle(process_handle_);
+    process_handle_ = base::kNullProcessHandle;
+  }
+}
+
 #if !defined(OS_MACOSX)
 void ServiceProcessControl::Launcher::DoDetectLaunched() {
-  DCHECK_EQ(false, notify_task_.is_null());
+  DCHECK(!notify_task_.is_null());
 
   const uint32 kMaxLaunchDetectRetries = 10;
   launched_ = CheckServiceProcessReady();
-  if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries)) {
+
+  int exit_code = 0;
+  if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries) ||
+      base::WaitForExitCodeWithTimeout(process_handle_, &exit_code,
+                                       base::TimeDelta())) {
+    CloseProcessHandle();
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE, base::Bind(&Launcher::Notify, this));
     return;
@@ -298,13 +363,13 @@
 }
 
 void ServiceProcessControl::Launcher::DoRun() {
-  DCHECK_EQ(false, notify_task_.is_null());
+  DCHECK(!notify_task_.is_null());
 
   base::LaunchOptions options;
 #if defined(OS_WIN)
   options.start_hidden = true;
 #endif
-  if (base::LaunchProcess(*cmd_line_, options, NULL)) {
+  if (base::LaunchProcess(*cmd_line_, options, &process_handle_)) {
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::Bind(&Launcher::DoDetectLaunched, this));
diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h
index 901be12..6bbc6d8 100644
--- a/chrome/browser/service/service_process_control.h
+++ b/chrome/browser/service/service_process_control.h
@@ -12,6 +12,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/cancelable_callback.h"
 #include "base/id_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
@@ -85,10 +86,6 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // Message handlers
-  void OnCloudPrintProxyInfo(
-      const cloud_print::CloudPrintProxyInfo& proxy_info);
-
   // Send a shutdown message to the service process. IPC channel will be
   // destroyed after calling this method.
   // Return true if the message was sent.
@@ -97,9 +94,20 @@
 
   // Send request for cloud print proxy info (enabled state, email, proxy id).
   // The callback gets the information when received.
+  // Returns true if request was sent. Callback will be called only in case of
+  // reply from service. The method resets any previous callback.
+  // This call starts service if needed.
   bool GetCloudPrintProxyInfo(
       const CloudPrintProxyInfoHandler& cloud_print_status_callback);
 
+  // Send request for histograms collected in service process.
+  // Returns true if request was sent, and callback will be called in case of
+  // success or timeout. The method resets any previous callback.
+  // Returns false if service is not running or other failure, callback will not
+  // be called in this case.
+  bool GetHistograms(const base::Closure& cloud_print_status_callback,
+                     const base::TimeDelta& timeout);
+
  private:
   // This class is responsible for launching the service process on the
   // PROCESS_LAUNCHER thread.
@@ -124,11 +132,13 @@
 
     void DoRun();
     void Notify();
+    void CloseProcessHandle();
     ServiceProcessControl* process_;
     scoped_ptr<CommandLine> cmd_line_;
     base::Closure notify_task_;
     bool launched_;
     uint32 retry_count_;
+    base::ProcessHandle process_handle_;
   };
 
   friend class MockServiceProcessControl;
@@ -141,6 +151,14 @@
 
   typedef std::vector<base::Closure> TaskList;
 
+  // Message handlers
+  void OnCloudPrintProxyInfo(
+      const cloud_print::CloudPrintProxyInfo& proxy_info);
+  void OnHistograms(const std::vector<std::string>& pickled_histograms);
+
+  // Runs callback provided in |GetHistograms()|.
+  void RunHistogramsCallback();
+
   // Helper method to invoke all the callbacks based on success or failure.
   void RunConnectDoneTasks();
 
@@ -170,7 +188,14 @@
   // the cloud print proxy.
   CloudPrintProxyInfoHandler cloud_print_info_callback_;
 
+  // Callback that gets invoked when a message with histograms is received from
+  // the service process.
+  base::Closure histograms_callback_;
+
   content::NotificationRegistrar registrar_;
+
+  // Callback that gets invoked if service didn't reply in time.
+  base::CancelableClosure histograms_timeout_callback_;
 };
 
 #endif  // CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_H_
diff --git a/chrome/browser/service/service_process_control_browsertest.cc b/chrome/browser/service/service_process_control_browsertest.cc
index 37fc004..7ea8cc5 100644
--- a/chrome/browser/service/service_process_control_browsertest.cc
+++ b/chrome/browser/service/service_process_control_browsertest.cc
@@ -2,18 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/service/service_process_control.h"
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/path_service.h"
 #include "base/process/kill.h"
 #include "base/process/process_handle.h"
 #include "base/process/process_iterator.h"
 #include "base/test/test_timeouts.h"
-#include "chrome/browser/service/service_process_control.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/service_process_util.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 class ServiceProcessControlBrowserTest
     : public InProcessBrowserTest {
@@ -26,12 +33,12 @@
     service_process_handle_ = base::kNullProcessHandle;
   }
 
-#if defined(OS_MACOSX)
-  virtual void TearDown() {
-    // ForceServiceProcessShutdown removes the process from launched on Mac.
-    ForceServiceProcessShutdown("", 0);
+  void HistogramsCallback() {
+    MockHistogramsCallback();
+    QuitMessageLoop();
   }
-#endif  // OS_MACOSX
+
+  MOCK_METHOD0(MockHistogramsCallback, void());
 
  protected:
   void LaunchServiceProcessControl() {
@@ -47,17 +54,13 @@
     content::RunMessageLoop();
   }
 
-  // Send a Cloud Print status request and wait for a reply from the service.
-  void SendRequestAndWait() {
-    ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
-        base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback,
-                   base::Unretained(this)));
-    content::RunMessageLoop();
+  static void QuitMessageLoop() {
+    base::MessageLoop::current()->Quit();
   }
 
-  void CloudPrintInfoCallback(
+  static void CloudPrintInfoCallback(
       const cloud_print::CloudPrintProxyInfo& proxy_info) {
-    base::MessageLoop::current()->Quit();
+    QuitMessageLoop();
   }
 
   void Disconnect() {
@@ -65,10 +68,23 @@
     ServiceProcessControl::GetInstance()->Disconnect();
   }
 
-  void WaitForShutdown() {
-    EXPECT_TRUE(base::WaitForSingleProcess(
-        service_process_handle_,
-        TestTimeouts::action_max_timeout()));
+  virtual void SetUp() OVERRIDE {
+    service_process_handle_ = base::kNullProcessHandle;
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (ServiceProcessControl::GetInstance()->IsConnected())
+      EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
+#if defined(OS_MACOSX)
+    // ForceServiceProcessShutdown removes the process from launched on Mac.
+    ForceServiceProcessShutdown("", 0);
+#endif  // OS_MACOSX
+    if (service_process_handle_ != base::kNullProcessHandle) {
+      EXPECT_TRUE(base::WaitForSingleProcess(
+          service_process_handle_,
+          TestTimeouts::action_max_timeout()));
+      service_process_handle_ = base::kNullProcessHandle;
+    }
   }
 
   void ProcessControlLaunched() {
@@ -99,12 +115,52 @@
   base::ProcessHandle service_process_handle_;
 };
 
+class RealServiceProcessControlBrowserTest
+      : public ServiceProcessControlBrowserTest {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    ServiceProcessControlBrowserTest::SetUpCommandLine(command_line);
+    base::FilePath exe;
+    PathService::Get(base::DIR_EXE, &exe);
+#if defined(OS_MACOSX)
+    exe = exe.DirName().DirName().DirName();
+#endif
+    exe = exe.Append(chrome::kHelperProcessExecutablePath);
+    // Run chrome instead of browser_tests.exe.
+    EXPECT_TRUE(base::PathExists(exe));
+    command_line->AppendSwitchPath(switches::kBrowserSubprocessPath, exe);
+  }
+};
+
+#if defined(OS_MACOSX)
+// Does not work on MACOSX.
+#define MAYBE_LaunchAndIPC DISABLED_LaunchAndIPC
+#else
+#define MAYBE_LaunchAndIPC LaunchAndIPC
+#endif
+
+IN_PROC_BROWSER_TEST_F(RealServiceProcessControlBrowserTest,
+                       MAYBE_LaunchAndIPC) {
+  LaunchServiceProcessControl();
+
+  // Make sure we are connected to the service process.
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
+        base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback));
+  content::RunMessageLoop();
+
+  // And then shutdown the service process.
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
+}
+
 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchAndIPC) {
   LaunchServiceProcessControl();
 
   // Make sure we are connected to the service process.
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  SendRequestAndWait();
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
+        base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback));
+  content::RunMessageLoop();
 
   // And then shutdown the service process.
   EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
@@ -117,16 +173,17 @@
   LaunchServiceProcessControl();
 
   // Make sure we are connected to the service process.
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  SendRequestAndWait();
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
+        base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)));
+  content::RunMessageLoop();
 
   // Launch the service process again.
   LaunchServiceProcessControl();
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  SendRequestAndWait();
-
-  // And then shutdown the service process.
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
+        base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)));
+  content::RunMessageLoop();
 }
 
 static void DecrementUntilZero(int* count) {
@@ -150,8 +207,6 @@
   // Then run the message loop to keep things running.
   content::RunMessageLoop();
   EXPECT_EQ(0, launch_count);
-  // And then shutdown the service process.
-  EXPECT_TRUE(process->Shutdown());
 }
 
 // Make sure using the same task for success and failure tasks works.
@@ -166,34 +221,28 @@
   // Then run the message loop to keep things running.
   content::RunMessageLoop();
   EXPECT_EQ(0, launch_count);
-  // And then shutdown the service process.
-  EXPECT_TRUE(process->Shutdown());
 }
 
 // Tests whether disconnecting from the service IPC causes the service process
 // to die.
-IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
-                       DieOnDisconnect) {
+IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DieOnDisconnect) {
   // Launch the service process.
   LaunchServiceProcessControl();
   // Make sure we are connected to the service process.
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
   Disconnect();
-  WaitForShutdown();
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
-                       ForceShutdown) {
+IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, ForceShutdown) {
   // Launch the service process.
   LaunchServiceProcessControl();
   // Make sure we are connected to the service process.
-  EXPECT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
   base::ProcessId service_pid;
   EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
   EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
   chrome::VersionInfo version_info;
   ForceServiceProcessShutdown(version_info.Version(), service_pid);
-  WaitForShutdown();
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) {
@@ -204,5 +253,42 @@
   EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
   EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
   // Disconnect from service process.
-  ServiceProcessControl::GetInstance()->Disconnect();
+  Disconnect();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsNoService) {
+  ASSERT_FALSE(ServiceProcessControl::GetInstance()->IsConnected());
+  EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
+  EXPECT_FALSE(ServiceProcessControl::GetInstance()->GetHistograms(
+      base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback,
+                 base::Unretained(this)),
+      base::TimeDelta()));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsTimeout) {
+  LaunchServiceProcessControl();
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  // Callback should not be called during GetHistograms call.
+  EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
+      base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback,
+                 base::Unretained(this)),
+      base::TimeDelta::FromMilliseconds(100)));
+  EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
+  content::RunMessageLoop();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, Histograms) {
+  LaunchServiceProcessControl();
+  ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  // Callback should not be called during GetHistograms call.
+  EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
+  // Wait for real callback by providing large timeout value.
+  EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
+      base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback,
+                base::Unretained(this)),
+      base::TimeDelta::FromHours(1)));
+  EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
+  content::RunMessageLoop();
 }
diff --git a/chrome/browser/sessions/OWNERS b/chrome/browser/sessions/OWNERS
index 73674b7..5c85480 100644
--- a/chrome/browser/sessions/OWNERS
+++ b/chrome/browser/sessions/OWNERS
@@ -1,2 +1,5 @@
 marja@chromium.org
 sky@chromium.org
+
+per-file restore_on_startup_policy_handler*=joaodasilva@chromium.org
+per-file restore_on_startup_policy_handler*=dconnelly@chromium.org
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index ad68c95..40c6103 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -303,11 +303,14 @@
     }
   }
 
-  void CloseBrowserSynchronously(Browser* browser) {
+  void CloseBrowserSynchronously(Browser* browser, bool close_all_windows) {
     content::WindowedNotificationObserver observer(
         chrome::NOTIFICATION_BROWSER_CLOSED,
         content::NotificationService::AllSources());
-    browser->window()->Close();
+    if (close_all_windows)
+      chrome::CloseAllBrowsers();
+    else
+      browser->window()->Close();
 #if defined(OS_MACOSX)
     // BrowserWindowController depends on the auto release pool being recycled
     // in the message loop to delete itself, which frees the Browser object
@@ -317,12 +320,19 @@
     observer.Wait();
   }
 
-  virtual Browser* QuitBrowserAndRestore(Browser* browser) {
+  virtual Browser* QuitBrowserAndRestore(Browser* browser,
+                                         bool close_all_windows) {
     Profile* profile = browser->profile();
 
     // Close the browser.
     chrome::StartKeepAlive();
-    CloseBrowserSynchronously(browser);
+    CloseBrowserSynchronously(browser, close_all_windows);
+
+    SessionServiceTestHelper helper;
+    helper.SetService(
+        SessionServiceFactory::GetForProfileForSessionRestore(profile));
+    helper.SetForceBrowserNotAliveWithNoWindows(true);
+    helper.ReleaseService();
 
     // Create a new window, which should trigger session restore.
     ui_test_utils::BrowserAddedObserver window_observer;
@@ -375,12 +385,13 @@
   }
 
  protected:
-  virtual Browser* QuitBrowserAndRestore(Browser* browser) OVERRIDE {
+  virtual Browser* QuitBrowserAndRestore(Browser* browser,
+                                         bool close_all_windows) OVERRIDE {
     content::WindowedNotificationObserver session_restore_observer(
         chrome::NOTIFICATION_SESSION_RESTORE_DONE,
         content::NotificationService::AllSources());
-    Browser* new_browser =
-        BetterSessionRestoreTest::QuitBrowserAndRestore(browser);
+    Browser* new_browser = BetterSessionRestoreTest::QuitBrowserAndRestore(
+        browser, close_all_windows);
     session_restore_observer.Wait();
     return new_browser;
   }
@@ -465,7 +476,7 @@
   // Set the startup preference to "continue where I left off" and visit a page
   // which stores a session cookie.
   StoreDataWithPage("session_cookies.html");
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   // The browsing session will be continued; just wait for the page to reload
   // and check the stored data.
   CheckReloadedPageRestored(new_browser);
@@ -475,18 +486,18 @@
                        CookiesClearedOnBrowserClose) {
   StoreDataWithPage("cookies.html");
   // Normally cookies are restored.
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   CheckReloadedPageRestored(new_browser);
   // ... but not if the content setting is set to clear on exit.
   CookieSettings::Factory::GetForProfile(new_browser->profile())->
       SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
   // ... unless background mode is active.
   EnableBackgroundMode();
-  new_browser = QuitBrowserAndRestore(new_browser);
+  new_browser = QuitBrowserAndRestore(new_browser, false);
   CheckReloadedPageRestored(new_browser);
 
   DisableBackgroundMode();
-  new_browser = QuitBrowserAndRestore(new_browser);
+  new_browser = QuitBrowserAndRestore(new_browser, false);
   if (browser_defaults::kBrowserAliveWithNoWindows)
     CheckReloadedPageRestored(new_browser);
   else
@@ -495,14 +506,64 @@
 
 IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostBrowserClose) {
   PostFormWithPage("post.html", false);
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   CheckFormRestored(new_browser, true, false);
 }
 
 IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
                        PostWithPasswordBrowserClose) {
   PostFormWithPage("post_with_password.html", true);
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
+  CheckReloadedPageRestored(new_browser);
+  // The form data contained passwords, so it's removed completely.
+  CheckFormRestored(new_browser, false, false);
+}
+
+// Check that session cookies are cleared on a wrench menu quit.
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
+                       SessionCookiesCloseAllBrowsers) {
+  // Set the startup preference to "continue where I left off" and visit a page
+  // which stores a session cookie.
+  StoreDataWithPage("session_cookies.html");
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  // The browsing session will be continued; just wait for the page to reload
+  // and check the stored data.
+  CheckReloadedPageRestored(new_browser);
+}
+
+// Check that cookies are cleared on a wrench menu quit only if cookies are set
+// to current session only, regardless of whether background mode is enabled.
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
+                       CookiesClearedOnCloseAllBrowsers) {
+  StoreDataWithPage("cookies.html");
+  // Normally cookies are restored.
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  CheckReloadedPageRestored(new_browser);
+  // ... but not if the content setting is set to clear on exit.
+  CookieSettings::Factory::GetForProfile(new_browser->profile())->
+      SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
+  // ... even if background mode is active.
+  EnableBackgroundMode();
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  CheckReloadedPageNotRestored(new_browser);
+
+  DisableBackgroundMode();
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  CheckReloadedPageNotRestored(new_browser);
+}
+
+// Check that form data is restored after wrench menu quit.
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostCloseAllBrowsers) {
+  PostFormWithPage("post.html", false);
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  CheckFormRestored(new_browser, true, false);
+}
+
+// Check that form data with a password field is cleared after wrench menu quit.
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
+                       PostWithPasswordCloseAllBrowsers) {
+  PostFormWithPage("post_with_password.html", true);
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
   CheckReloadedPageRestored(new_browser);
   // The form data contained passwords, so it's removed completely.
   CheckFormRestored(new_browser, false, false);
@@ -682,10 +743,10 @@
 IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, SessionCookiesBrowserClose) {
   StoreDataWithPage("session_cookies.html");
   EnableBackgroundMode();
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   NavigateAndCheckStoredData(new_browser, "session_cookies.html");
   DisableBackgroundMode();
-  new_browser = QuitBrowserAndRestore(new_browser);
+  new_browser = QuitBrowserAndRestore(new_browser, false);
   if (browser_defaults::kBrowserAliveWithNoWindows)
     NavigateAndCheckStoredData(new_browser, "session_cookies.html");
   else
@@ -696,7 +757,7 @@
   StoreDataWithPage("cookies.html");
 
   // Normally cookies are restored.
-  Browser* new_browser = QuitBrowserAndRestore(browser());
+  Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   NavigateAndCheckStoredData(new_browser, "cookies.html");
 
   // ... but not if the content setting is set to clear on exit.
@@ -704,12 +765,44 @@
       SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
   // ... unless background mode is active.
   EnableBackgroundMode();
-  new_browser = QuitBrowserAndRestore(new_browser);
+  new_browser = QuitBrowserAndRestore(new_browser, false);
   NavigateAndCheckStoredData(new_browser, "cookies.html");
   DisableBackgroundMode();
-  new_browser = QuitBrowserAndRestore(new_browser);
+  new_browser = QuitBrowserAndRestore(new_browser, false);
   if (browser_defaults::kBrowserAliveWithNoWindows)
     NavigateAndCheckStoredData(new_browser, "cookies.html");
   else
     StoreDataWithPage(new_browser, "cookies.html");
 }
+
+// Check that session cookies are cleared on a wrench menu quit.
+IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, SessionCookiesCloseAllBrowsers) {
+  StoreDataWithPage("session_cookies.html");
+  EnableBackgroundMode();
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  StoreDataWithPage(new_browser, "session_cookies.html");
+  DisableBackgroundMode();
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  StoreDataWithPage(new_browser, "session_cookies.html");
+}
+
+// Check that cookies are cleared on a wrench menu quit only if cookies are set
+// to current session only, regardless of whether background mode is enabled.
+IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnCloseAllBrowsers) {
+  StoreDataWithPage("cookies.html");
+
+  // Normally cookies are restored.
+  Browser* new_browser = QuitBrowserAndRestore(browser(), true);
+  NavigateAndCheckStoredData(new_browser, "cookies.html");
+
+  // ... but not if the content setting is set to clear on exit.
+  CookieSettings::Factory::GetForProfile(new_browser->profile())->
+      SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
+  // ... even if background mode is active.
+  EnableBackgroundMode();
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  StoreDataWithPage(new_browser, "cookies.html");
+  DisableBackgroundMode();
+  new_browser = QuitBrowserAndRestore(new_browser, true);
+  StoreDataWithPage(new_browser, "cookies.html");
+}
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler.cc b/chrome/browser/sessions/restore_on_startup_policy_handler.cc
new file mode 100644
index 0000000..6eba1d0
--- /dev/null
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler.cc
@@ -0,0 +1,130 @@
+// Copyright 2013 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/sessions/restore_on_startup_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+RestoreOnStartupPolicyHandler::RestoreOnStartupPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kRestoreOnStartup,
+                                base::Value::TYPE_INTEGER) {}
+
+RestoreOnStartupPolicyHandler::~RestoreOnStartupPolicyHandler() {
+}
+
+void RestoreOnStartupPolicyHandler::ApplyPolicySettings(
+    const PolicyMap& policies,
+    PrefValueMap* prefs) {
+  const base::Value* restore_on_startup_value =
+      policies.GetValue(policy_name());
+  if (restore_on_startup_value) {
+    int restore_on_startup;
+    if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
+      return;
+
+    if (restore_on_startup == SessionStartupPref::kPrefValueHomePage)
+      ApplyPolicySettingsFromHomePage(policies, prefs);
+    else
+      prefs->SetInteger(prefs::kRestoreOnStartup, restore_on_startup);
+  }
+}
+
+void RestoreOnStartupPolicyHandler::ApplyPolicySettingsFromHomePage(
+    const PolicyMap& policies,
+    PrefValueMap* prefs) {
+  const base::Value* homepage_is_new_tab_page_value =
+      policies.GetValue(key::kHomepageIsNewTabPage);
+  if (!homepage_is_new_tab_page_value) {
+    // The policy is enforcing 'open the homepage on startup' but not
+    // enforcing what the homepage should be. Don't set any prefs.
+    return;
+  }
+
+  bool homepage_is_new_tab_page;
+  if (!homepage_is_new_tab_page_value->GetAsBoolean(&homepage_is_new_tab_page))
+    return;
+
+  if (homepage_is_new_tab_page) {
+    prefs->SetInteger(prefs::kRestoreOnStartup,
+                      SessionStartupPref::kPrefValueNewTab);
+  } else {
+    const base::Value* homepage_value =
+        policies.GetValue(key::kHomepageLocation);
+    if (!homepage_value || !homepage_value->IsType(base::Value::TYPE_STRING)) {
+      // The policy is enforcing 'open the homepage on startup' but not
+      // enforcing what the homepage should be. Don't set any prefs.
+      return;
+    }
+    base::ListValue* url_list = new base::ListValue();
+    url_list->Append(homepage_value->DeepCopy());
+    prefs->SetInteger(prefs::kRestoreOnStartup,
+                      SessionStartupPref::kPrefValueURLs);
+    prefs->SetValue(prefs::kURLsToRestoreOnStartup, url_list);
+  }
+}
+
+bool RestoreOnStartupPolicyHandler::CheckPolicySettings(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors) {
+  if (!TypeCheckingPolicyHandler::CheckPolicySettings(policies, errors))
+    return false;
+
+  const base::Value* restore_policy = policies.GetValue(key::kRestoreOnStartup);
+
+  if (restore_policy) {
+    int restore_value;
+    CHECK(restore_policy->GetAsInteger(&restore_value));  // Passed type check.
+    switch (restore_value) {
+      case SessionStartupPref::kPrefValueHomePage:
+        errors->AddError(policy_name(), IDS_POLICY_VALUE_DEPRECATED);
+        break;
+      case SessionStartupPref::kPrefValueLast: {
+        // If the "restore last session" policy is set, session cookies are
+        // treated as permanent cookies and site data needed to restore the
+        // session is not cleared so we have to warn the user in that case.
+        const base::Value* cookies_policy =
+            policies.GetValue(key::kCookiesSessionOnlyForUrls);
+        const base::ListValue* cookies_value;
+        if (cookies_policy && cookies_policy->GetAsList(&cookies_value) &&
+            !cookies_value->empty()) {
+          errors->AddError(key::kCookiesSessionOnlyForUrls,
+                           IDS_POLICY_OVERRIDDEN,
+                           key::kRestoreOnStartup);
+        }
+
+        const base::Value* exit_policy =
+            policies.GetValue(key::kClearSiteDataOnExit);
+        bool exit_value;
+        if (exit_policy && exit_policy->GetAsBoolean(&exit_value) &&
+            exit_value) {
+          errors->AddError(key::kClearSiteDataOnExit,
+                           IDS_POLICY_OVERRIDDEN,
+                           key::kRestoreOnStartup);
+        }
+        break;
+      }
+      case SessionStartupPref::kPrefValueURLs:
+      case SessionStartupPref::kPrefValueNewTab:
+        // No error
+        break;
+      default:
+        errors->AddError(policy_name(),
+                         IDS_POLICY_OUT_OF_RANGE_ERROR,
+                         base::IntToString(restore_value));
+    }
+  }
+  return true;
+}
+
+}  // namespace policy
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler.h b/chrome/browser/sessions/restore_on_startup_policy_handler.h
new file mode 100644
index 0000000..55ebb2c
--- /dev/null
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler.h
@@ -0,0 +1,38 @@
+// Copyright 2013 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_SESSIONS_RESTORE_ON_STARTUP_POLICY_HANDLER_H_
+#define CHROME_BROWSER_SESSIONS_RESTORE_ON_STARTUP_POLICY_HANDLER_H_
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace policy {
+
+class PolicyErrorMap;
+class PolicyMap;
+
+// Handles RestoreOnStartup policy.
+class RestoreOnStartupPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  RestoreOnStartupPolicyHandler();
+  virtual ~RestoreOnStartupPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual bool CheckPolicySettings(const PolicyMap& policies,
+                                   PolicyErrorMap* errors) OVERRIDE;
+  virtual void ApplyPolicySettings(const PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  void ApplyPolicySettingsFromHomePage(const PolicyMap& policies,
+                                       PrefValueMap* prefs);
+
+  DISALLOW_COPY_AND_ASSIGN(RestoreOnStartupPolicyHandler);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_SESSIONS_RESTORE_ON_STARTUP_POLICY_HANDLER_H_
diff --git a/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc b/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc
new file mode 100644
index 0000000..51419c9
--- /dev/null
+++ b/chrome/browser/sessions/restore_on_startup_policy_handler_unittest.cc
@@ -0,0 +1,288 @@
+// Copyright 2013 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 "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/sessions/restore_on_startup_policy_handler.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace policy {
+
+class RestoreOnStartupPolicyHandlerTest : public testing::Test {
+ protected:
+  void SetPolicyValue(const std::string& policy, base::Value* value) {
+    policies_.Set(
+        policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, value, NULL);
+  }
+  bool CheckPolicySettings() {
+    return handler_.CheckPolicySettings(policies_, &errors_);
+  }
+  void ApplyPolicySettings() {
+    handler_.ApplyPolicySettings(policies_, &prefs_);
+  }
+  PolicyErrorMap& errors() { return errors_; }
+  PrefValueMap& prefs() { return prefs_; }
+
+ private:
+  PolicyMap policies_;
+  PolicyErrorMap errors_;
+  PrefValueMap prefs_;
+  RestoreOnStartupPolicyHandler handler_;
+};
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_FailsTypeCheck) {
+  // Handler expects an int; pass it a bool.
+  SetPolicyValue(key::kRestoreOnStartup, new base::FundamentalValue(false));
+  // Checking should fail and add an error to the error map.
+  EXPECT_FALSE(CheckPolicySettings());
+  EXPECT_EQ(1U, errors().size());
+  EXPECT_EQ(l10n_util::GetStringFUTF16(
+                IDS_POLICY_TYPE_ERROR,
+                ASCIIToUTF16(ConfigurationPolicyHandler::ValueTypeToString(
+                    Value::TYPE_INTEGER))),
+            errors().begin()->second);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_Unspecified) {
+  // Don't specify a value for the policy.
+  // Checking should succeed with no errors.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(0U, errors().size());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_UnknownValue) {
+  // Specify an unknown value for the policy.
+  int impossible_value = SessionStartupPref::kPrefValueHomePage +
+                         SessionStartupPref::kPrefValueLast +
+                         SessionStartupPref::kPrefValueURLs +
+                         SessionStartupPref::kPrefValueNewTab;
+  SetPolicyValue(key::kRestoreOnStartup,
+                 new base::FundamentalValue(impossible_value));
+  // Checking should succeed but add an error to the error map.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(1U, errors().size());
+  EXPECT_EQ(l10n_util::GetStringFUTF16(
+                IDS_POLICY_OUT_OF_RANGE_ERROR,
+                ASCIIToUTF16(base::IntToString(impossible_value))),
+            errors().begin()->second);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_HomePage) {
+  // Specify the HomePage value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  // Checking should succeed but add an error to the error map.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(1U, errors().size());
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_POLICY_VALUE_DEPRECATED),
+            errors().begin()->second);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       CheckPolicySettings_RestoreLastSession_SessionCookies) {
+  // Specify the Last value and the Session-Only Cookies value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueLast));
+  scoped_ptr<base::ListValue> urls(new base::ListValue);
+  urls->AppendString("http://foo.com");
+  SetPolicyValue(key::kCookiesSessionOnlyForUrls, urls.release());
+  // Checking should succeed but add an error to the error map.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(1U, errors().size());
+  EXPECT_TRUE(key::kCookiesSessionOnlyForUrls == errors().begin()->first);
+  EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_POLICY_OVERRIDDEN,
+                                       ASCIIToUTF16(key::kRestoreOnStartup)),
+            errors().begin()->second);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       CheckPolicySettings_RestoreLastSession_ClearDataOnExit) {
+  // Specify the Last value and the Clear-Data-On-Exit value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueLast));
+  SetPolicyValue(key::kClearSiteDataOnExit, new base::FundamentalValue(true));
+  // Checking should succeed but add an error to the error map.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(1U, errors().size());
+  EXPECT_TRUE(key::kClearSiteDataOnExit == errors().begin()->first);
+  EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_POLICY_OVERRIDDEN,
+                                       ASCIIToUTF16(key::kRestoreOnStartup)),
+            errors().begin()->second);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       CheckPolicySettings_RestoreLastSession) {
+  // Specify the Last value without the conflicts.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueLast));
+  // Checking should succeed with no errors.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(0U, errors().size());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_URLs) {
+  // Specify the URLs value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueURLs));
+  // Checking should succeed with no errors.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(0U, errors().size());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, CheckPolicySettings_NewTab) {
+  // Specify the NewTab value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueNewTab));
+  // Checking should succeed with no errors.
+  EXPECT_TRUE(CheckPolicySettings());
+  EXPECT_EQ(0U, errors().size());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, ApplyPolicySettings_NoValue) {
+  // Don't specify a value for the policy.
+  ApplyPolicySettings();
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, ApplyPolicySettings_WrongType) {
+  // Handler expects an int; pass it a bool.
+  SetPolicyValue(key::kRestoreOnStartup, new base::FundamentalValue(false));
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest, ApplyPolicySettings_NotHomePage) {
+  // Specify anything except the HomePage value.
+  int not_home_page = SessionStartupPref::kPrefValueHomePage + 1;
+  SetPolicyValue(key::kRestoreOnStartup,
+                 new base::FundamentalValue(not_home_page));
+  ApplyPolicySettings();
+  // The resulting prefs should have the value we specified.
+  int result;
+  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
+  EXPECT_EQ(not_home_page, result);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_NoHomePageValue) {
+  // Specify the HomePage value but no HomePageIsNewTabPage value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  ApplyPolicySettings();
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_HomePageValueIsWrongType) {
+  // Specify the HomePage value and an integer for the home page value.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  SetPolicyValue(
+      key::kHomepageIsNewTabPage,
+      new base::FundamentalValue(314159));
+  ApplyPolicySettings();
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_HomePageIsNewTabPage) {
+  // Specify the HomePage value and the home page as the new tab page.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  SetPolicyValue(
+      key::kHomepageIsNewTabPage,
+      new base::FundamentalValue(true));
+  ApplyPolicySettings();
+  // The resulting prefs should have the restore value as NTP.
+  int result;
+  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
+  int expected = SessionStartupPref::kPrefValueNewTab;
+  EXPECT_EQ(expected, result);
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage_NotDefined) {
+  // Specify the HomePage value but don't specify the home page to use.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  SetPolicyValue(
+      key::kHomepageIsNewTabPage,
+      new base::FundamentalValue(false));
+  ApplyPolicySettings();
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage_WrongType) {
+  // Specify the HomePage value but specify a boolean as the home page.
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  SetPolicyValue(
+      key::kHomepageIsNewTabPage,
+      new base::FundamentalValue(false));
+  SetPolicyValue(
+      key::kHomepageLocation,
+      new base::FundamentalValue(false));
+  ApplyPolicySettings();
+  // The resulting prefs should be empty.
+  EXPECT_TRUE(prefs().begin() == prefs().end());
+}
+
+TEST_F(RestoreOnStartupPolicyHandlerTest,
+       ApplyPolicySettings_HomePage_HomePageIsNotNewTabPage) {
+  SetPolicyValue(
+      key::kRestoreOnStartup,
+      new base::FundamentalValue(SessionStartupPref::kPrefValueHomePage));
+  SetPolicyValue(key::kHomepageIsNewTabPage, new base::FundamentalValue(false));
+  SetPolicyValue(key::kHomepageLocation,
+                 new base::StringValue("http://foo.com"));
+  ApplyPolicySettings();
+
+  // The resulting prefs should have have URLs specified for startup.
+  int result;
+  EXPECT_TRUE(prefs().GetInteger(prefs::kRestoreOnStartup, &result));
+  int expected = SessionStartupPref::kPrefValueURLs;
+  EXPECT_EQ(expected, result);
+
+  // The resulting prefs should have the URL we specified as the home page.
+  base::Value* url_result;
+  EXPECT_TRUE(prefs().GetValue(prefs::kURLsToRestoreOnStartup, &url_result));
+  base::ListValue* url_list_result;
+  EXPECT_TRUE(url_result->GetAsList(&url_list_result));
+  EXPECT_EQ(1U, url_list_result->GetSize());
+  std::string expected_url;
+  EXPECT_TRUE(url_list_result->GetString(0, &expected_url));
+  EXPECT_EQ(std::string("http://foo.com"), expected_url);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/sessions/session_service_factory.cc b/chrome/browser/sessions/session_service_factory.cc
index 7e928f9..7ab2aa6 100644
--- a/chrome/browser/sessions/session_service_factory.cc
+++ b/chrome/browser/sessions/session_service_factory.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/sessions/session_service_factory.h"
 
+#include "base/command_line.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_data_deleter.h"
 #include "chrome/browser/sessions/session_service.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
 // static
@@ -33,6 +35,22 @@
 }
 
 // static
+SessionService* SessionServiceFactory::GetForProfileForSessionRestore(
+    Profile* profile) {
+  SessionService* service = GetForProfile(profile);
+  if (!service && !CommandLine::ForCurrentProcess()->HasSwitch(
+                       switches::kDisableBatchedShutdown)) {
+    SessionServiceFactory* factory = GetInstance();
+    // If the service has been shutdown, remove the reference to NULL for
+    // |profile| so GetServiceForBrowserContext will recreate it.
+    factory->BrowserContextShutdown(profile);
+    factory->BrowserContextDestroyed(profile);
+    service = GetForProfile(profile);
+  }
+  return service;
+}
+
+// static
 void SessionServiceFactory::ShutdownForProfile(Profile* profile) {
   DeleteSessionOnlyData(profile);
 
diff --git a/chrome/browser/sessions/session_service_factory.h b/chrome/browser/sessions/session_service_factory.h
index 719dc8c..5d2b31a 100644
--- a/chrome/browser/sessions/session_service_factory.h
+++ b/chrome/browser/sessions/session_service_factory.h
@@ -18,7 +18,8 @@
   // Returns the session service for |profile|. This may return NULL. If this
   // profile supports a session service (it isn't incognito), and the session
   // service hasn't yet been created, this forces creation of the session
-  // service.
+  // service. This returns NULL if ShutdownForProfile has been called for
+  // |profile|.
   //
   // This returns NULL if the profile is incognito. Callers should always check
   // the return value for NULL.
@@ -30,6 +31,11 @@
   // always check the return value for NULL.
   static SessionService* GetForProfileIfExisting(Profile* profile);
 
+  // Returns the session service for |profile|. This is the same as
+  // GetForProfile, but will force creation of the session service even if
+  // ShutdownForProfile has been called for |profile|.
+  static SessionService* GetForProfileForSessionRestore(Profile* profile);
+
   // If |profile| has a session service, it is shut down. To properly record the
   // current state this forces creation of the session service, then shuts it
   // down.
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index d6de8c5..e6f5a70 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -192,7 +192,9 @@
 
 ShellIntegration::DefaultWebClientSetPermission
     ShellIntegration::CanSetAsDefaultBrowser() {
-  if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
+  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
+  if (distribution->GetDefaultBrowserControlPolicy() !=
+          BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL)
     return SET_DEFAULT_NOT_ALLOWED;
 
   if (ShellUtil::CanMakeChromeDefaultUnattended())
diff --git a/chrome/browser/signin/DEPS b/chrome/browser/signin/DEPS
deleted file mode 100644
index 9ada978..0000000
--- a/chrome/browser/signin/DEPS
+++ /dev/null
@@ -1,64 +0,0 @@
-include_rules = [
-  # Sign-in logic is being componentized (moved to //components, where
-  # it won't depend back on //chrome), so we have restrictive DEPS and
-  # are trying to get the list of temporarily-allowed (!-prefixed
-  # rules) below to zero.
-  "-chrome/common",
-  "-chrome/browser",
-  "+chrome/browser/signin",
-
-  # TODO(joi): Get this list to zero.
-  "!chrome/browser/chrome_notification_types.h",
-  "!chrome/browser/policy/cloud/user_policy_signin_service.h",
-  "!chrome/browser/policy/cloud/user_policy_signin_service_factory.h",
-  "!chrome/browser/profiles/profile.h",
-  "!chrome/browser/profiles/profile_android.h",
-  "!chrome/browser/profiles/profile_info_cache.h",
-  "!chrome/browser/profiles/profile_io_data.h",
-  "!chrome/browser/profiles/profile_manager.h",
-  "!chrome/browser/sync/profile_sync_service.h",
-  "!chrome/browser/sync/profile_sync_service_android.h",
-  "!chrome/browser/sync/profile_sync_service_factory.h",
-  "!chrome/browser/sync/profile_sync_service_observer.h",
-  "!chrome/browser/sync/sync_global_error.h",
-  "!chrome/browser/sync/sync_prefs.h",
-  "!chrome/browser/ui/browser_commands.h",
-  "!chrome/browser/ui/chrome_pages.h",
-  "!chrome/browser/ui/global_error/global_error.h",
-  "!chrome/browser/ui/global_error/global_error_service.h",
-  "!chrome/browser/ui/global_error/global_error_service_factory.h",
-  "!chrome/browser/ui/host_desktop.h",
-  "!chrome/browser/ui/webui/signin/login_ui_service.h",
-  "!chrome/browser/ui/webui/signin/login_ui_service_factory.h",
-  "!chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.h",
-  "!chrome/browser/ui/webui/signin_internals_ui.h",
-  "!chrome/browser/webdata/token_web_data.h",
-  "!chrome/browser/webdata/web_data_service_factory.h",
-  "!chrome/common/chrome_switches.h",
-  "!chrome/common/chrome_version_info.h",
-  "!chrome/common/pref_names.h",
-  "!chrome/common/url_constants.h",
-]
-
-specific_include_rules = {
-  r".*_[a-z]*test\.cc": [
-    # TODO(joi): Get this list to zero.
-    "!chrome/browser/browser_process.h",
-    "!chrome/browser/prefs/browser_prefs.h",
-    "!chrome/browser/sync/profile_sync_service_mock.h",
-    "!chrome/browser/ui/browser.h",
-    "!chrome/browser/ui/singleton_tabs.h",
-    "!chrome/browser/ui/sync/sync_promo_ui.h",
-    "!chrome/browser/ui/tabs/tab_strip_model.h",
-  ],
-
-  # These files are staying in //chrome so no need to limit.
-  r"(chrome_signin_manager_delegate|"
-  r"signin_names_io_thread|"
-  r"signin_manager_factory|"
-  r"signin_promo)"
-  r"\.(h|cc)": [
-    "+chrome/browser",
-    "+chrome/common",
-  ],
-}
diff --git a/chrome/browser/signin/account_reconcilor.cc b/chrome/browser/signin/account_reconcilor.cc
index 7f27ec5..f54e15d 100644
--- a/chrome/browser/signin/account_reconcilor.cc
+++ b/chrome/browser/signin/account_reconcilor.cc
@@ -2,14 +2,145 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/signin/account_reconcilor.h"
-
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/net/chrome_cookie_notification_details.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_reconcilor.h"
+#include "chrome/browser/signin/google_auto_login_helper.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
 
 AccountReconcilor::AccountReconcilor(Profile* profile) : profile_(profile) {
+  RegisterWithSigninManager();
+  RegisterWithCookieMonster();
+
+  // If this profile is not connected, the reconcilor should do nothing but
+  // wait for the connection.
+  SigninManagerBase* signin_manager =
+      SigninManagerFactory::GetForProfile(profile_);
+  if (!signin_manager->GetAuthenticatedUsername().empty()) {
+    RegisterWithTokenService();
+    StartPeriodicReconciliation();
+  }
 }
 
-AccountReconcilor::~AccountReconcilor() {}
+void AccountReconcilor::RegisterWithCookieMonster() {
+  content::Source<Profile> source(profile_);
+  registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
+}
 
-void AccountReconcilor::Shutdown() {}
+void AccountReconcilor::UnregisterWithCookieMonster() {
+  content::Source<Profile> source(profile_);
+  registrar_.Remove(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
+}
 
+void AccountReconcilor::RegisterWithSigninManager() {
+  content::Source<Profile> source(profile_);
+  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, source);
+  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, source);
+}
+
+void AccountReconcilor::UnregisterWithSigninManager() {
+  content::Source<Profile> source(profile_);
+  registrar_.Remove(
+      this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, source);
+  registrar_.Remove(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, source);
+}
+
+void AccountReconcilor::RegisterWithTokenService() {
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+  token_service->AddObserver(this);
+}
+
+void AccountReconcilor::UnregisterWithTokenService() {
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+  token_service->RemoveObserver(this);
+}
+
+void AccountReconcilor::StartPeriodicReconciliation() {
+  // TODO(rogerta): pick appropriate thread and timeout value.
+  reconciliation_timer_.Start(
+      FROM_HERE,
+      base::TimeDelta::FromMinutes(5),
+      this,
+      &AccountReconcilor::PeriodicReconciliation);
+}
+
+void AccountReconcilor::StopPeriodicReconciliation() {
+  reconciliation_timer_.Stop();
+}
+
+void AccountReconcilor::PeriodicReconciliation() {
+  PerformReconcileAction();
+}
+
+void AccountReconcilor::Observe(int type,
+                                const content::NotificationSource& source,
+                                const content::NotificationDetails& details) {
+  switch (type) {
+    case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL:
+      RegisterWithTokenService();
+      StartPeriodicReconciliation();
+      break;
+    case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
+      UnregisterWithTokenService();
+      StopPeriodicReconciliation();
+      break;
+    case chrome::NOTIFICATION_COOKIE_CHANGED:
+      OnCookieChanged(content::Details<ChromeCookieDetails>(details).ptr());
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+void AccountReconcilor::OnCookieChanged(ChromeCookieDetails* details) {
+  // TODO(acleung): Filter out cookies by looking at the domain.
+  // PerformReconcileAction();
+}
+
+void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) {
+  PerformMergeAction(account_id);
+}
+
+void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
+  PerformRemoveAction(account_id);
+}
+
+void AccountReconcilor::OnRefreshTokensLoaded() {}
+
+void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
+  // GoogleAutoLoginHelper deletes itself upon success / failure.
+  GoogleAutoLoginHelper* helper = new GoogleAutoLoginHelper(profile_);
+  helper->LogIn(account_id);
+}
+
+void AccountReconcilor::PerformRemoveAction(const std::string& account_id) {
+  // TODO(acleung): Implement this:
+}
+
+void AccountReconcilor::PerformReconcileAction() {
+  // TODO(acleung): Implement this:
+}
+
+AccountReconcilor::~AccountReconcilor() {
+  // Make sure shutdown was called first.
+  DCHECK(registrar_.IsEmpty());
+}
+
+void AccountReconcilor::Shutdown() {
+  UnregisterWithSigninManager();
+  UnregisterWithTokenService();
+  UnregisterWithCookieMonster();
+  StopPeriodicReconciliation();
+}
diff --git a/chrome/browser/signin/account_reconcilor.h b/chrome/browser/signin/account_reconcilor.h
index b57fa9c..7454f36 100644
--- a/chrome/browser/signin/account_reconcilor.h
+++ b/chrome/browser/signin/account_reconcilor.h
@@ -7,12 +7,18 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "google_apis/gaia/oauth2_token_service.h"
 
 class Profile;
+struct ChromeCookieDetails;
 
-class AccountReconcilor : public BrowserContextKeyedService {
+class AccountReconcilor : public BrowserContextKeyedService,
+                                 content::NotificationObserver,
+                                 OAuth2TokenService::Observer {
  public:
-  AccountReconcilor(Profile* profile);
+  explicit AccountReconcilor(Profile* profile);
   virtual ~AccountReconcilor();
 
   // BrowserContextKeyedService implementation.
@@ -20,9 +26,44 @@
 
   Profile* profile() { return profile_; }
 
+  bool IsPeriodicReconciliationRunning() {
+    return reconciliation_timer_.IsRunning();
+  }
+
  private:
+  // Register and unregister with dependent services.
+  void RegisterWithCookieMonster();
+  void UnregisterWithCookieMonster();
+  void RegisterWithSigninManager();
+  void UnregisterWithSigninManager();
+  void RegisterWithTokenService();
+  void UnregisterWithTokenService();
+
+  // Start and stop the periodic reconciliation.
+  void StartPeriodicReconciliation();
+  void StopPeriodicReconciliation();
+  void PeriodicReconciliation();
+
   // The profile that this reconcilor belongs to.
   Profile* profile_;
+  content::NotificationRegistrar registrar_;
+  base::RepeatingTimer<AccountReconcilor> reconciliation_timer_;
+
+  void PerformMergeAction(const std::string& account_id);
+  void PerformRemoveAction(const std::string& account_id);
+  void PerformReconcileAction();
+
+  // Overriden from content::NotificationObserver
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  void OnCookieChanged(ChromeCookieDetails* details);
+
+  // Overriden from OAuth2TokenService::Observer
+  virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
+  virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE;
+  virtual void OnRefreshTokensLoaded() OVERRIDE;
 
   DISALLOW_COPY_AND_ASSIGN(AccountReconcilor);
 };
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
index c21acc8..52cb18a 100644
--- a/chrome/browser/signin/account_reconcilor_unittest.cc
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -12,29 +12,56 @@
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+#if defined(OS_CHROMEOS)
+typedef FakeSigninManagerBase FakeSigninManagerForTesting;
+#else
+typedef FakeSigninManager FakeSigninManagerForTesting;
+#endif
+
+const char kTestEmail[] = "user@gmail.com";
+
 class AccountReconcilorTest : public testing::Test {
  public:
+  AccountReconcilorTest();
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
   TestingProfile* profile() { return profile_.get(); }
+  FakeSigninManagerForTesting* signin_manager() { return signin_manager_; }
+  FakeProfileOAuth2TokenService* token_service() { return token_service_; }
 
 private:
+  content::TestBrowserThreadBundle bundle_;
   scoped_ptr<TestingProfile> profile_;
+  FakeSigninManagerForTesting* signin_manager_;
+  FakeProfileOAuth2TokenService* token_service_;
 };
 
+AccountReconcilorTest::AccountReconcilorTest()
+    : signin_manager_(NULL), token_service_(NULL) {}
+
 void AccountReconcilorTest::SetUp() {
   TestingProfile::Builder builder;
   builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
                             FakeProfileOAuth2TokenService::Build);
   builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
-                            FakeSigninManagerBase::Build);
+                            FakeSigninManagerForTesting::Build);
   profile_ = builder.Build();
+
+  signin_manager_ =
+      static_cast<FakeSigninManagerForTesting*>(
+          SigninManagerFactory::GetForProfile(profile()));
+  signin_manager_->Initialize(profile(), NULL);
+
+  token_service_ =
+      static_cast<FakeProfileOAuth2TokenService*>(
+          ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
 }
 
 void AccountReconcilorTest::TearDown() {
@@ -50,3 +77,27 @@
   ASSERT_TRUE(NULL != reconcilor);
   ASSERT_EQ(profile(), reconcilor->profile());
 }
+
+#if !defined(OS_CHROMEOS)
+TEST_F(AccountReconcilorTest, SigninManagerRegistration) {
+  AccountReconcilor* reconcilor =
+      AccountReconcilorFactory::GetForProfile(profile());
+  ASSERT_TRUE(NULL != reconcilor);
+  ASSERT_FALSE(reconcilor->IsPeriodicReconciliationRunning());
+
+  signin_manager()->OnExternalSigninCompleted(kTestEmail);
+  ASSERT_TRUE(reconcilor->IsPeriodicReconciliationRunning());
+
+  signin_manager()->SignOut();
+  ASSERT_FALSE(reconcilor->IsPeriodicReconciliationRunning());
+}
+#endif
+
+TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) {
+  signin_manager()->SetAuthenticatedUsername(kTestEmail);
+
+  AccountReconcilor* reconcilor =
+      AccountReconcilorFactory::GetForProfile(profile());
+  ASSERT_TRUE(NULL != reconcilor);
+  ASSERT_TRUE(reconcilor->IsPeriodicReconciliationRunning());
+}
diff --git a/chrome/browser/signin/google_auto_login_helper.cc b/chrome/browser/signin/google_auto_login_helper.cc
new file mode 100644
index 0000000..09cb58a
--- /dev/null
+++ b/chrome/browser/signin/google_auto_login_helper.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 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/signin/google_auto_login_helper.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_constants.h"
+
+GoogleAutoLoginHelper::GoogleAutoLoginHelper(Profile* profile)
+    : profile_(profile) {}
+
+GoogleAutoLoginHelper::~GoogleAutoLoginHelper() {}
+
+void GoogleAutoLoginHelper::LogIn() {
+  uber_token_fetcher_.reset(new UbertokenFetcher(profile_, this));
+  uber_token_fetcher_->StartFetchingToken();
+}
+
+void GoogleAutoLoginHelper::LogIn(const std::string& account_id) {
+  uber_token_fetcher_.reset(new UbertokenFetcher(profile_, this));
+  uber_token_fetcher_->StartFetchingToken(account_id);
+}
+
+void GoogleAutoLoginHelper::OnUbertokenSuccess(const std::string& uber_token) {
+  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(
+      this, GaiaConstants::kChromeSource, profile_->GetRequestContext()));
+  gaia_auth_fetcher_->StartMergeSession(uber_token);
+}
+
+void GoogleAutoLoginHelper::OnUbertokenFailure(
+    const GoogleServiceAuthError& error) {
+  VLOG(1) << "Failed to retrieve ubertoken, error: " << error.ToString();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void GoogleAutoLoginHelper::OnMergeSessionSuccess(const std::string& data) {
+  DVLOG(1) << "MergeSession successful." << data;
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void GoogleAutoLoginHelper::OnMergeSessionFailure(
+    const GoogleServiceAuthError& error) {
+  VLOG(1) << "Failed MergeSession request, error: " << error.ToString();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
diff --git a/chrome/browser/signin/google_auto_login_helper.h b/chrome/browser/signin/google_auto_login_helper.h
new file mode 100644
index 0000000..cb11766
--- /dev/null
+++ b/chrome/browser/signin/google_auto_login_helper.h
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
+#define CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
+
+#include "chrome/browser/signin/ubertoken_fetcher.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+
+class GaiaAuthFetcher;
+class Profile;
+
+// Logs in the current signed in user into Google services. Populates the cookie
+// jar with Google credentials of the signed in user.
+class GoogleAutoLoginHelper : public GaiaAuthConsumer,
+                              public UbertokenConsumer {
+ public:
+  explicit GoogleAutoLoginHelper(Profile* profile);
+  virtual ~GoogleAutoLoginHelper();
+
+  void LogIn();
+  void LogIn(const std::string& account_id);
+
+  // Overridden from GaiaAuthConsumer.
+  virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE;
+  virtual void OnMergeSessionFailure(const GoogleServiceAuthError& error)
+      OVERRIDE;
+
+  // Overridden from UbertokenConsumer.
+  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
+  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
+
+ private:
+  Profile* profile_;
+  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
+  scoped_ptr<UbertokenFetcher> uber_token_fetcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(GoogleAutoLoginHelper);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_SIGNIN_GOOGLE_AUTO_LOGIN_HELPER_H_
diff --git a/chrome/browser/signin/local_auth.cc b/chrome/browser/signin/local_auth.cc
new file mode 100644
index 0000000..6fab25b
--- /dev/null
+++ b/chrome/browser/signin/local_auth.cc
@@ -0,0 +1,179 @@
+// Copyright 2013 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/signin/local_auth.h"
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "components/webdata/encryptor/encryptor.h"
+#include "crypto/random.h"
+#include "crypto/secure_util.h"
+#include "crypto/symmetric_key.h"
+
+namespace {
+
+// WARNING: Changing these values will make it impossible to do off-line
+// authentication until the next successful on-line authentication.  To change
+// these safely, change the "encoding" version below and make verification
+// handle multiple values.
+const char kHash1Encoding = '1';
+const unsigned kHash1Bits = 256;
+const unsigned kHash1Bytes = kHash1Bits / 8;
+const unsigned kHash1IterationCount = 100000;
+
+std::string CreateSecurePasswordHash(const std::string& salt,
+                                     const std::string& password,
+                                     char encoding) {
+  DCHECK_EQ(kHash1Bytes, salt.length());
+  DCHECK_EQ(kHash1Encoding, encoding);  // Currently support only one method.
+
+  base::Time start_time = base::Time::Now();
+
+  // Library call to create secure password hash as SymmetricKey (uses PBKDF2).
+  scoped_ptr<crypto::SymmetricKey> password_key(
+      crypto::SymmetricKey::DeriveKeyFromPassword(
+          crypto::SymmetricKey::AES,
+          password, salt,
+          kHash1IterationCount, kHash1Bits));
+  std::string password_hash;
+  const bool success = password_key->GetRawKey(&password_hash);
+  DCHECK(success);
+  DCHECK_EQ(kHash1Bytes, password_hash.length());
+
+  UMA_HISTOGRAM_TIMES("PasswordHash.CreateTime",
+                      base::Time::Now() - start_time);
+
+  return password_hash;
+}
+
+std::string EncodePasswordHashRecord(const std::string& record,
+                                     char encoding) {
+  DCHECK_EQ(kHash1Encoding, encoding);  // Currently support only one method.
+
+  // Encrypt the hash using the OS account-password protection (if available).
+  std::string encoded;
+  const bool success = Encryptor::EncryptString(record, &encoded);
+  DCHECK(success);
+
+  // Convert binary record to text for preference database.
+  std::string encoded64;
+  base::Base64Encode(encoded, &encoded64);
+
+  // Stuff the "encoding" value into the first byte.
+  encoded64.insert(0, &encoding, sizeof(encoding));
+
+  return encoded64;
+}
+
+bool DecodePasswordHashRecord(const std::string& encoded,
+                              std::string* decoded,
+                              char* encoding) {
+  // Extract the "encoding" value from the first byte and validate.
+  if (encoded.length() < 1)
+    return false;
+  *encoding = encoded[0];
+  if (*encoding != kHash1Encoding)
+    return false;
+
+  // Stored record is base64; convert to binary.
+  std::string unbase64;
+  if (!base::Base64Decode(encoded.substr(1), &unbase64))
+    return false;
+
+  // Decrypt the record using the OS account-password protection (if available).
+  return Encryptor::DecryptString(unbase64, decoded);
+}
+
+}  // namespace
+
+namespace chrome {
+
+void RegisterLocalAuthPrefs(user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterStringPref(
+      prefs::kGoogleServicesPasswordHash,
+      std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+void SetLocalAuthCredentials(Profile* profile,
+                             const std::string& username,
+                             const std::string& password) {
+  DCHECK(profile);
+  DCHECK(username.length());
+  DCHECK(password.length());
+
+  // Salt should be random data, as long as the hash length, and different with
+  // every save.
+  std::string salt_str;
+  crypto::RandBytes(WriteInto(&salt_str, kHash1Bytes + 1), kHash1Bytes);
+  DCHECK_EQ(kHash1Bytes, salt_str.length());
+
+  // Perform secure hash of password for storage.
+  std::string password_hash = CreateSecurePasswordHash(
+      salt_str, password, kHash1Encoding);
+  DCHECK_EQ(kHash1Bytes, password_hash.length());
+
+  // Group all fields into a single record for storage;
+  std::string record;
+  record.append(salt_str);
+  record.append(password_hash);
+  record.append(username);
+
+  // Encode it and store it.
+  std::string encoded = EncodePasswordHashRecord(record, kHash1Encoding);
+  profile->GetPrefs()->SetString(prefs::kGoogleServicesPasswordHash,
+                                 encoded);
+}
+
+bool ValidateLocalAuthCredentials(Profile* profile,
+                                  const std::string& username,
+                                  const std::string& password) {
+  DCHECK(profile);
+  DCHECK(username.length());
+  DCHECK(password.length());
+
+  const size_t name_length = username.length();
+  std::string record;
+  char encoding;
+
+  if (!profile->GetPrefs()->HasPrefPath(prefs::kGoogleServicesPasswordHash))
+    return false;
+  std::string encodedhash = profile->GetPrefs()->GetString(
+      prefs::kGoogleServicesPasswordHash);
+  if (!DecodePasswordHashRecord(encodedhash, &record, &encoding))
+    return false;
+
+  std::string password_hash;
+  const char* password_saved;
+  const char* password_check;
+  size_t password_length;
+
+  if (encoding == '1') {
+    // Validate correct length and username; extract salt and password hash.
+    if (record.length() != 2 * kHash1Bytes + name_length)
+      return false;
+    if (record.compare(2 * kHash1Bytes, name_length, username) != 0)
+      return false;
+    std::string salt_str(record.data(), kHash1Bytes);
+    password_saved = record.data() + kHash1Bytes;
+    password_hash = CreateSecurePasswordHash(salt_str, password, encoding);
+    password_check = password_hash.data();
+    password_length = kHash1Bytes;
+  } else {
+    // unknown encoding
+    return false;
+  }
+
+  return crypto::SecureMemEqual(password_saved, password_check,
+                                password_length);
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/signin/local_auth.h b/chrome/browser/signin/local_auth.h
new file mode 100644
index 0000000..6c2e73e
--- /dev/null
+++ b/chrome/browser/signin/local_auth.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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.
+//
+// The local-auth module allows for user authentication in the case when
+// on-line authentication is not possible (e.g. there is no network
+// connection).
+
+#ifndef CHROME_BROWSER_SIGNIN_LOCAL_AUTH_H_
+#define CHROME_BROWSER_SIGNIN_LOCAL_AUTH_H_
+
+#include <string>
+
+class Profile;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace chrome {
+
+void RegisterLocalAuthPrefs(user_prefs::PrefRegistrySyncable* registry);
+
+void SetLocalAuthCredentials(Profile* profile,
+                             const std::string& username,
+                             const std::string& password);
+
+bool ValidateLocalAuthCredentials(Profile* profile,
+                                  const std::string& username,
+                                  const std::string& password);
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_SIGNIN_LOCAL_AUTH_H_
diff --git a/chrome/browser/signin/local_auth_unittest.cc b/chrome/browser/signin/local_auth_unittest.cc
new file mode 100644
index 0000000..2ce65fd
--- /dev/null
+++ b/chrome/browser/signin/local_auth_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 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/signin/local_auth.h"
+
+#include "base/base64.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/webdata/encryptor/encryptor.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace chrome;
+
+class LocalAuthTest : public testing::Test {
+ public:
+  LocalAuthTest() {
+    TestingProfile::Builder profile_builder;
+    profile_ = profile_builder.Build();
+  }
+
+  scoped_ptr<TestingProfile> profile_;
+};
+
+TEST_F(LocalAuthTest, SetAndCheckCredentials) {
+  Profile* prof = profile_.get();
+  PrefService* prefs = prof->GetPrefs();
+  EXPECT_FALSE(prefs->HasPrefPath(prefs::kGoogleServicesPasswordHash));
+
+#if defined(OS_MACOSX)
+    Encryptor::UseMockKeychain(true);
+#endif
+
+  std::string username("user@gmail.com");
+  std::string password("Some Password");
+  EXPECT_FALSE(ValidateLocalAuthCredentials(prof, username, password));
+
+  SetLocalAuthCredentials(prof, username, password);
+  std::string passhash = prefs->GetString(prefs::kGoogleServicesPasswordHash);
+
+  // We perform basic validation on the written record to ensure bugs don't slip
+  // in that cannot be seen from the API:
+  //  - The encoding exists (we can guarantee future backward compatibility).
+  //  - The plaintext version of the password is not mistakenly stored anywhere.
+  EXPECT_FALSE(passhash.empty());
+  EXPECT_EQ('1', passhash[0]);
+  EXPECT_EQ(passhash.find(password), std::string::npos);
+
+  std::string decodedhash;
+  base::Base64Decode(passhash.substr(1), &decodedhash);
+  EXPECT_FALSE(decodedhash.empty());
+  EXPECT_EQ(decodedhash.find(username), std::string::npos);
+  EXPECT_EQ(decodedhash.find(password), std::string::npos);
+
+  EXPECT_TRUE(ValidateLocalAuthCredentials(prof, username, password));
+  EXPECT_FALSE(ValidateLocalAuthCredentials(prof, username + "1", password));
+  EXPECT_FALSE(ValidateLocalAuthCredentials(prof, username, password + "1"));
+
+  SetLocalAuthCredentials(prof, username, password);  // makes different salt
+  EXPECT_NE(prefs->GetString(prefs::kGoogleServicesPasswordHash), passhash);
+}
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index 4de51aa..2279e46 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/signin/about_signin_internals.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
+#include "chrome/browser/signin/local_auth.h"
 #include "chrome/browser/signin/signin_global_error.h"
 #include "chrome/browser/signin/signin_internals_util.h"
 #include "chrome/browser/signin/signin_manager_cookie_helper.h"
@@ -602,6 +603,12 @@
       content::Source<Profile>(profile_),
       content::Details<const GoogleServiceSigninSuccessDetails>(&details));
 
+  // Don't store password hash except for users of new profile features.
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kNewProfileManagement)) {
+    std::string auth_username = GetAuthenticatedUsername();
+    chrome::SetLocalAuthCredentials(profile_, auth_username, password_);
+  }
   password_.clear();  // Don't need it anymore.
   DisableOneClickSignIn(profile_);  // Don't ever offer again.
 
diff --git a/chrome/browser/signin/signin_manager_base.cc b/chrome/browser/signin/signin_manager_base.cc
index cab9de26..86f1122 100644
--- a/chrome/browser/signin/signin_manager_base.cc
+++ b/chrome/browser/signin/signin_manager_base.cc
@@ -23,6 +23,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 
@@ -81,10 +82,22 @@
 
 void SigninManagerBase::SetAuthenticatedUsername(const std::string& username) {
   if (!authenticated_username_.empty()) {
-    DLOG_IF(ERROR, username != authenticated_username_) <<
+    DLOG_IF(ERROR, !gaia::AreEmailsSame(username, authenticated_username_)) <<
         "Tried to change the authenticated username to something different: " <<
         "Current: " << authenticated_username_ << ", New: " << username;
+
+#if defined(OS_IOS)
+    // Prior to M26, chrome on iOS did not normalize the email before setting
+    // it in SigninManager.  If the emails are the same as given by
+    // gaia::AreEmailsSame() but not the same as given by std::string::op==(),
+    // make sure to set the authenticated name below.
+    if (!gaia::AreEmailsSame(username, authenticated_username_) ||
+        username == authenticated_username_) {
+      return;
+    }
+#else
     return;
+#endif
   }
   authenticated_username_ = username;
   // TODO(tim): We could go further in ensuring kGoogleServicesUsername and
diff --git a/chrome/browser/signin/signin_manager_factory.cc b/chrome/browser/signin/signin_manager_factory.cc
index 8eb4645..cb7ed1d 100644
--- a/chrome/browser/signin/signin_manager_factory.cc
+++ b/chrome/browser/signin/signin_manager_factory.cc
@@ -7,6 +7,7 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/signin/chrome_signin_manager_delegate.h"
+#include "chrome/browser/signin/local_auth.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/pref_names.h"
@@ -77,6 +78,7 @@
   registry->RegisterListPref(prefs::kReverseAutologinRejectedEmailList,
                              new ListValue,
                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  chrome::RegisterLocalAuthPrefs(registry);
 }
 
 // static
diff --git a/chrome/browser/signin/signin_oauth_helper.cc b/chrome/browser/signin/signin_oauth_helper.cc
new file mode 100644
index 0000000..3e99b34
--- /dev/null
+++ b/chrome/browser/signin/signin_oauth_helper.cc
@@ -0,0 +1,69 @@
+// Copyright 2013 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/signin/signin_oauth_helper.h"
+
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_constants.h"
+
+// TODO(guohui): needs to figure out the UI for error cases.
+
+SigninOAuthHelper::SigninOAuthHelper(Profile* profile)
+    : profile_(profile) {}
+
+SigninOAuthHelper::~SigninOAuthHelper() {}
+
+void SigninOAuthHelper::StartAddingAccount(const std::string& oauth_code) {
+  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(
+      this, GaiaConstants::kChromeSource, profile_->GetRequestContext()));
+  gaia_auth_fetcher_->StartAuthCodeForOAuth2TokenExchange(oauth_code);
+}
+
+void SigninOAuthHelper::OnClientOAuthSuccess(const ClientOAuthResult& result) {
+  DVLOG(1) << "SigninOAuthHelper::OnClientOAuthSuccess";
+
+  refresh_token_ = result.refresh_token;
+  gaia_auth_fetcher_->StartOAuthLogin(result.access_token,
+                                      GaiaConstants::kGaiaService);
+}
+
+void SigninOAuthHelper::OnClientOAuthFailure(
+      const GoogleServiceAuthError& error) {
+  VLOG(1) << "SigninOAuthHelper::OnClientOAuthFailure : " << error.ToString();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void SigninOAuthHelper::OnClientLoginSuccess(const ClientLoginResult& result) {
+  DVLOG(1) << "SigninOAuthHelper::OnClientLoginSuccess";
+  gaia_auth_fetcher_->StartGetUserInfo(result.lsid);
+}
+
+void SigninOAuthHelper::OnClientLoginFailure(
+    const GoogleServiceAuthError& error) {
+  VLOG(1) << "SigninOAuthHelper::OnClientLoginFailure : " << error.ToString();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void SigninOAuthHelper::OnGetUserInfoSuccess(const UserInfoMap& data) {
+  DVLOG(1) << "SigninOAuthHelper::OnGetUserInfoSuccess";
+
+  UserInfoMap::const_iterator email_iter = data.find("email");
+  if (email_iter == data.end()) {
+    VLOG(1) << "SigninOAuthHelper::OnGetUserInfoSuccess : no email found ";
+  } else {
+    ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
+        ->UpdateCredentials(email_iter->second, refresh_token_);
+  }
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void SigninOAuthHelper::OnGetUserInfoFailure(
+    const GoogleServiceAuthError& error) {
+  VLOG(1) << "SigninOAuthHelper::OnGetUserInfoFailure : " << error.ToString();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
diff --git a/chrome/browser/signin/signin_oauth_helper.h b/chrome/browser/signin/signin_oauth_helper.h
new file mode 100644
index 0000000..c758235
--- /dev/null
+++ b/chrome/browser/signin/signin_oauth_helper.h
@@ -0,0 +1,46 @@
+// Copyright 2013 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_SIGNIN_SIGNIN_OAUTH_HELPER_H_
+#define CHROME_BROWSER_SIGNIN_SIGNIN_OAUTH_HELPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+
+class GaiaAuthFetcher;
+class Profile;
+
+// Helper class for the sign in process. Currently it provides a single helper
+// method for secondary account authentication by exchanging oauth code for
+// tokens and user info, and upon success adding the user to
+// |ProfileOauth2TokenService|. The class will delete itself upon completion.
+// TODO(guohui): refactor the class to consolidate duplicate code paths in
+// OneClickSigninHelper, SigninManager and this class.
+class SigninOAuthHelper : public GaiaAuthConsumer {
+ public:
+  explicit SigninOAuthHelper(Profile* profile);
+  virtual ~SigninOAuthHelper();
+
+  void StartAddingAccount(const std::string& oauth_code);
+
+  // Overridden from GaiaAuthConsumer.
+  virtual void OnClientOAuthSuccess(const ClientOAuthResult& result) OVERRIDE;
+  virtual void OnClientOAuthFailure(
+      const GoogleServiceAuthError& error) OVERRIDE;
+  virtual void OnClientLoginSuccess(const ClientLoginResult& result) OVERRIDE;
+  virtual void OnClientLoginFailure(
+      const GoogleServiceAuthError& error) OVERRIDE;
+  virtual void OnGetUserInfoSuccess(const UserInfoMap& data) OVERRIDE;
+  virtual void OnGetUserInfoFailure(
+      const GoogleServiceAuthError& error) OVERRIDE;
+
+ private:
+  Profile* profile_;
+  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
+  std::string refresh_token_;
+
+  DISALLOW_COPY_AND_ASSIGN(SigninOAuthHelper);
+};
+
+#endif  // CHROME_BROWSER_SIGNIN_SIGNIN_OAUTH_HELPER_H_
diff --git a/chrome/browser/signin/signin_promo.h b/chrome/browser/signin/signin_promo.h
index 164cbbc..02a415a 100644
--- a/chrome/browser/signin/signin_promo.h
+++ b/chrome/browser/signin/signin_promo.h
@@ -29,6 +29,8 @@
   SOURCE_APP_LAUNCHER,
   SOURCE_APPS_PAGE_LINK,
   SOURCE_BOOKMARK_BUBBLE,
+  SOURCE_AVATAR_BUBBLE_SIGN_IN,
+  SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
   SOURCE_UNKNOWN, // This must be last.
 };
 
diff --git a/chrome/browser/signin/ubertoken_fetcher.cc b/chrome/browser/signin/ubertoken_fetcher.cc
index f8ffd14..aa29321 100644
--- a/chrome/browser/signin/ubertoken_fetcher.cc
+++ b/chrome/browser/signin/ubertoken_fetcher.cc
@@ -26,12 +26,17 @@
 }
 
 void UbertokenFetcher::StartFetchingToken() {
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+  StartFetchingToken(token_service->GetPrimaryAccountId());
+}
+
+void UbertokenFetcher::StartFetchingToken(const std::string& account_id) {
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaUrls::GetInstance()->oauth1_login_scope());
   ProfileOAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-  access_token_request_ = token_service->StartRequest(
-      token_service->GetPrimaryAccountId(), scopes, this);
+  access_token_request_ = token_service->StartRequest(account_id, scopes, this);
 }
 
 void UbertokenFetcher::OnUberAuthTokenSuccess(const std::string& token) {
diff --git a/chrome/browser/signin/ubertoken_fetcher.h b/chrome/browser/signin/ubertoken_fetcher.h
index 649f41c..dc3b6fe 100644
--- a/chrome/browser/signin/ubertoken_fetcher.h
+++ b/chrome/browser/signin/ubertoken_fetcher.h
@@ -40,6 +40,7 @@
 
   // Start fetching the token.
   void StartFetchingToken();
+  void StartFetchingToken(const std::string& account_id);
 
   // Overriden from GaiaAuthConsumer
   virtual void OnUberAuthTokenSuccess(const std::string& token) OVERRIDE;
diff --git a/chrome/browser/speech/OWNERS b/chrome/browser/speech/OWNERS
index 88b7dd9..f49ecc4 100644
--- a/chrome/browser/speech/OWNERS
+++ b/chrome/browser/speech/OWNERS
@@ -1,6 +1,5 @@
 # Speech recognition
 hans@chromium.org
-primiano@chromium.org
 tommi@chromium.org
 xians@chromium.org
 
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
index 8866f04..935c034 100644
--- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
+++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_source.h"
@@ -422,6 +423,15 @@
   }
 
   WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
+
+  // chrome://app-list/ uses speech recognition.
+  if (web_contents->GetCommittedWebUI() &&
+      web_contents->GetLastCommittedURL().spec() ==
+      chrome::kChromeUIAppListStartPageURL) {
+    allowed = true;
+    check_permission = false;
+  }
+
   extensions::ViewType view_type = extensions::GetViewType(web_contents);
 
   // TODO(kalman): Also enable speech bubble for extension popups
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.cc b/chrome/browser/speech/extension_api/tts_extension_api.cc
index 4137421..6523b4e 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_api.cc
@@ -256,7 +256,7 @@
   continuous_params.pitch = pitch;
   continuous_params.volume = volume;
 
-  Utterance* utterance = new Utterance(profile());
+  Utterance* utterance = new Utterance(GetProfile());
   utterance->set_text(text);
   utterance->set_voice_name(voice_name);
   utterance->set_src_extension_id(extension_id());
@@ -300,7 +300,7 @@
 
 bool TtsGetVoicesFunction::RunImpl() {
   std::vector<VoiceData> voices;
-  TtsController::GetInstance()->GetVoices(profile(), &voices);
+  TtsController::GetInstance()->GetVoices(GetProfile(), &voices);
 
   scoped_ptr<ListValue> result_voices(new ListValue());
   for (size_t i = 0; i < voices.size(); ++i) {
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.h b/chrome/browser/speech/extension_api/tts_extension_api.h
index e2ed95c..a8f3c19 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api.h
+++ b/chrome/browser/speech/extension_api/tts_extension_api.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/speech/tts_controller.h"
 
 class Profile;
@@ -18,43 +18,42 @@
 
 namespace extensions {
 
-class TtsSpeakFunction
-    : public AsyncExtensionFunction {
+class TtsSpeakFunction : public ChromeAsyncExtensionFunction {
  private:
   virtual ~TtsSpeakFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tts.speak", TTS_SPEAK)
 };
 
-class TtsStopSpeakingFunction : public SyncExtensionFunction {
+class TtsStopSpeakingFunction : public ChromeSyncExtensionFunction {
  private:
   virtual ~TtsStopSpeakingFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tts.stop", TTS_STOP)
 };
 
-class TtsPauseFunction : public SyncExtensionFunction {
+class TtsPauseFunction : public ChromeSyncExtensionFunction {
  private:
   virtual ~TtsPauseFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tts.pause", TTS_PAUSE)
 };
 
-class TtsResumeFunction : public SyncExtensionFunction {
+class TtsResumeFunction : public ChromeSyncExtensionFunction {
  private:
   virtual ~TtsResumeFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tts.resume", TTS_RESUME)
 };
 
-class TtsIsSpeakingFunction : public SyncExtensionFunction {
+class TtsIsSpeakingFunction : public ChromeSyncExtensionFunction {
  private:
   virtual ~TtsIsSpeakingFunction() {}
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("tts.isSpeaking", TTS_ISSPEAKING)
 };
 
-class TtsGetVoicesFunction : public SyncExtensionFunction {
+class TtsGetVoicesFunction : public ChromeSyncExtensionFunction {
  private:
   virtual ~TtsGetVoicesFunction() {}
   virtual bool RunImpl() OVERRIDE;
diff --git a/chrome/browser/speech/tts_controller.cc b/chrome/browser/speech/tts_controller.cc
index 219c241..a0d376f 100644
--- a/chrome/browser/speech/tts_controller.cc
+++ b/chrome/browser/speech/tts_controller.cc
@@ -181,6 +181,9 @@
     }
 #endif
   } else {
+    // It's possible for certain platforms to send start events immediately
+    // during |speak|.
+    current_utterance_ = utterance;
     GetPlatformImpl()->clear_error();
     bool success = GetPlatformImpl()->Speak(
         utterance->id(),
@@ -188,6 +191,8 @@
         utterance->lang(),
         voice,
         utterance->continuous_parameters());
+    if (!success)
+      current_utterance_ = NULL;
 
     // If the native voice wasn't able to process this speech, see if
     // the browser has built-in TTS that isn't loaded yet.
@@ -203,7 +208,6 @@
       delete utterance;
       return;
     }
-    current_utterance_ = utterance;
   }
 }
 
@@ -259,9 +263,9 @@
   // already finished the utterance (for example because another utterance
   // interrupted or we got a call to Stop). This is normal and we can
   // safely just ignore these events.
-  if (!current_utterance_ || utterance_id != current_utterance_->id())
+  if (!current_utterance_ || utterance_id != current_utterance_->id()) {
     return;
-
+  }
   current_utterance_->OnTtsEvent(event_type, char_index, error_message);
   if (current_utterance_->finished()) {
     FinishCurrentUtterance();
diff --git a/chrome/browser/speech/tts_mac.mm b/chrome/browser/speech/tts_mac.mm
index a5a8aec..b4046ab 100644
--- a/chrome/browser/speech/tts_mac.mm
+++ b/chrome/browser/speech/tts_mac.mm
@@ -89,7 +89,6 @@
   base::scoped_nsobject<ChromeTtsDelegate> delegate_;
   int utterance_id_;
   std::string utterance_;
-  bool sent_start_event_;
   int last_char_index_;
   bool paused_;
 
@@ -133,7 +132,6 @@
   }
 
   utterance_id_ = utterance_id;
-  sent_start_event_ = false;
 
   // TODO: support languages other than the default: crbug.com/88059
 
@@ -164,7 +162,12 @@
         forProperty:NSSpeechVolumeProperty error:nil];
   }
 
-  return [speech_synthesizer_ startSpeakingRetainedUtterance];
+  bool success = [speech_synthesizer_ startSpeakingRetainedUtterance];
+  if (success) {
+    TtsController* controller = TtsController::GetInstance();
+    controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, "");
+  }
+  return success;
 }
 
 bool TtsPlatformImplMac::StopSpeaking() {
@@ -195,7 +198,9 @@
 }
 
 bool TtsPlatformImplMac::IsSpeaking() {
-  return [NSSpeechSynthesizer isAnyApplicationSpeaking];
+  if (speech_synthesizer_)
+    return [speech_synthesizer_ isSpeaking];
+  return false;
 }
 
 void TtsPlatformImplMac::GetVoices(std::vector<VoiceData>* outVoices) {
@@ -268,19 +273,13 @@
   if (event_type == TTS_EVENT_END)
     char_index = utterance_.size();
   TtsController* controller = TtsController::GetInstance();
-  if (event_type == TTS_EVENT_WORD && !sent_start_event_) {
-    controller->OnTtsEvent(
-        utterance_id_, TTS_EVENT_START, 0, "");
-    sent_start_event_ = true;
-  }
-  controller->OnTtsEvent(
+controller->OnTtsEvent(
       utterance_id_, event_type, char_index, error_message);
   last_char_index_ = char_index;
 }
 
 TtsPlatformImplMac::TtsPlatformImplMac() {
   utterance_id_ = -1;
-  sent_start_event_ = true;
   paused_ = false;
 
   delegate_.reset([[ChromeTtsDelegate alloc] initWithPlatformImplMac:this]);
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac_unittest.cc b/chrome/browser/spellchecker/spellcheck_message_filter_mac_unittest.cc
index c06045e..8ae2bcb 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter_mac_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac_unittest.cc
@@ -52,8 +52,7 @@
   content::BrowserThread::ID thread;
   IPC::Message message;
   for (size_t i = 0; i < arraysize(kSpellcheckMessages); ++i) {
-    message.SetHeaderValues(
-        0, kSpellcheckMessages[i], IPC::Message::PRIORITY_NORMAL);
+    message.SetHeaderValues(0, kSpellcheckMessages[i], 0 /* flags */);
     thread = content::BrowserThread::IO;
     filter->OverrideThreadForMessage(message, &thread);
     EXPECT_EQ(content::BrowserThread::UI, thread);
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc b/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
index da560f3..a7f892f 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
@@ -66,8 +66,7 @@
   scoped_refptr<TestingSpellCheckMessageFilter> filter(
       new TestingSpellCheckMessageFilter);
   for (size_t i = 0; i < arraysize(kSpellcheckMessages); ++i) {
-    message.SetHeaderValues(
-        0, kSpellcheckMessages[i], IPC::Message::PRIORITY_NORMAL);
+    message.SetHeaderValues(0, kSpellcheckMessages[i], 0  /* flags */);
     thread = content::BrowserThread::IO;
     filter->OverrideThreadForMessage(message, &thread);
     EXPECT_EQ(content::BrowserThread::UI, thread);
diff --git a/chrome/browser/storage_monitor/image_capture_device_manager.mm b/chrome/browser/storage_monitor/image_capture_device_manager.mm
index a6daed5..bb42984 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager.mm
@@ -104,7 +104,7 @@
           base::SysNSStringToUTF8([cameraDevice UUIDString])),
       base::SysNSStringToUTF16([cameraDevice name]),
       "",
-      string16(),
+      base::SysNSStringToUTF16([cameraDevice name]),
       string16(),
       string16(),
       0);
diff --git a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
index 503cb27..5b2e317 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #import <Foundation/Foundation.h>
 #import <ImageCaptureCore/ImageCaptureCore.h>
 
@@ -11,12 +10,12 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/mac/foundation_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "chrome/browser/storage_monitor/image_capture_device.h"
 #include "chrome/browser/storage_monitor/image_capture_device_manager.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(MAC_OS_X_VERSION_10_7) || \
@@ -256,9 +255,6 @@
 class ImageCaptureDeviceManagerTest : public testing::Test {
  public:
   virtual void SetUp() OVERRIDE {
-    ui_thread_.reset(new content::TestBrowserThread(
-        content::BrowserThread::UI, &message_loop_));
-
     monitor_ = TestStorageMonitor::CreateAndInstall();
   }
 
@@ -282,9 +278,7 @@
   }
 
  protected:
-  base::MessageLoopForUI message_loop_;
-  scoped_ptr<content::TestBrowserThread> ui_thread_;
-
+  content::TestBrowserThreadBundle thread_bundle_;
   TestStorageMonitor* monitor_;
   TestCameraListener listener_;
 };
@@ -354,10 +348,6 @@
 }
 
 TEST_F(ImageCaptureDeviceManagerTest, DownloadFile) {
-  scoped_ptr<content::TestBrowserThread> file_thread(
-      new content::TestBrowserThread(
-          content::BrowserThread::FILE, &message_loop_));
-
   ImageCaptureDeviceManager manager;
   manager.SetNotifications(monitor_->receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
@@ -384,7 +374,7 @@
   // return us a not-found error.
   base::FilePath temp_file = temp_dir.path().Append("tempfile");
   [camera downloadFile:std::string("nonexistent") localPath:temp_file];
-  message_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(1U, listener_.downloads().size());
   EXPECT_EQ("nonexistent", listener_.downloads()[0]);
   EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, listener_.last_error());
@@ -395,7 +385,7 @@
   // library behavior. Our code then renames the file onto the requested
   // destination.
   [camera downloadFile:kTestFileName localPath:temp_file];
-  message_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(2U, listener_.downloads().size());
   EXPECT_EQ(kTestFileName, listener_.downloads()[1]);
@@ -410,10 +400,6 @@
 }
 
 TEST_F(ImageCaptureDeviceManagerTest, TestSubdirectories) {
-  scoped_ptr<content::TestBrowserThread> file_thread(
-      new content::TestBrowserThread(
-          content::BrowserThread::FILE, &message_loop_));
-
   ImageCaptureDeviceManager manager;
   manager.SetNotifications(monitor_->receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
@@ -436,7 +422,7 @@
   base::FilePath temp_file = temp_dir.path().Append("tempfile");
 
   [camera downloadFile:("dir/" + kTestFileName) localPath:temp_file];
-  message_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   char file_contents[5];
   ASSERT_EQ(4, file_util::ReadFile(temp_file, file_contents,
diff --git a/chrome/browser/storage_monitor/media_storage_util_unittest.cc b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
index 03114c3..f1d4621 100644
--- a/chrome/browser/storage_monitor/media_storage_util_unittest.cc
+++ b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/browser/storage_monitor/media_storage_util.h"
@@ -15,7 +15,7 @@
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -29,17 +29,16 @@
 class MediaStorageUtilTest : public testing::Test {
  public:
   MediaStorageUtilTest()
-        : ui_thread_(BrowserThread::UI, &message_loop_),
-          file_thread_(BrowserThread::FILE) {}
-  virtual ~MediaStorageUtilTest() { }
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {}
+  virtual ~MediaStorageUtilTest() {}
 
   // Verify mounted device type.
-  void CheckDeviceType(const base::FilePath& mount_point,
-                       bool expected_val) {
-    if (expected_val)
-      EXPECT_TRUE(MediaStorageUtil::HasDcim(mount_point));
-    else
-      EXPECT_FALSE(MediaStorageUtil::HasDcim(mount_point));
+  void CheckDCIMDeviceType(const base::FilePath& mount_point) {
+    EXPECT_TRUE(MediaStorageUtil::HasDcim(mount_point));
+  }
+
+  void CheckNonDCIMDeviceType(const base::FilePath& mount_point) {
+    EXPECT_FALSE(MediaStorageUtil::HasDcim(mount_point));
   }
 
   void ProcessAttach(const std::string& id,
@@ -63,7 +62,6 @@
   virtual void SetUp() OVERRIDE {
     monitor_ = TestStorageMonitor::CreateAndInstall();
     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
-    file_thread_.Start();
   }
 
   virtual void TearDown() OVERRIDE {
@@ -84,12 +82,9 @@
     base::MessageLoop::current()->Run();
   }
 
-  base::MessageLoop message_loop_;
-
  private:
+  content::TestBrowserThreadBundle thread_bundle_;
   TestStorageMonitor* monitor_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
   base::ScopedTempDir scoped_temp_dir_;
 };
 
@@ -98,11 +93,12 @@
 TEST_F(MediaStorageUtilTest, MediaDeviceAttached) {
   // Create a dummy mount point with DCIM Directory.
   base::FilePath mount_point(CreateMountPoint(true));
+  ASSERT_FALSE(mount_point.empty());
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&MediaStorageUtilTest::CheckDeviceType,
-                 base::Unretained(this), mount_point, true));
-  message_loop_.RunUntilIdle();
+      base::Bind(&MediaStorageUtilTest::CheckDCIMDeviceType,
+                 base::Unretained(this), mount_point));
+  base::RunLoop().RunUntilIdle();
 }
 
 // Test to verify that HasDcim() function returns false for a given non-media
@@ -110,11 +106,12 @@
 TEST_F(MediaStorageUtilTest, NonMediaDeviceAttached) {
   // Create a dummy mount point without DCIM Directory.
   base::FilePath mount_point(CreateMountPoint(false));
+  ASSERT_FALSE(mount_point.empty());
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&MediaStorageUtilTest::CheckDeviceType,
-                 base::Unretained(this), mount_point, false));
-  message_loop_.RunUntilIdle();
+      base::Bind(&MediaStorageUtilTest::CheckNonDCIMDeviceType,
+                 base::Unretained(this), mount_point));
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(MediaStorageUtilTest, CanCreateFileSystemForImageCapture) {
diff --git a/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc b/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
index f0c1136..a861dd9 100644
--- a/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
+++ b/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
@@ -17,8 +16,7 @@
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -88,8 +86,7 @@
 class MediaTransferProtocolDeviceObserverLinuxTest : public testing::Test {
  public:
   MediaTransferProtocolDeviceObserverLinuxTest()
-      : message_loop_(base::MessageLoop::TYPE_IO),
-        file_thread_(content::BrowserThread::FILE, &message_loop_) {}
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
   virtual ~MediaTransferProtocolDeviceObserverLinuxTest() {}
 
@@ -120,8 +117,7 @@
   }
 
  private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   scoped_ptr<TestMediaTransferProtocolDeviceObserverLinux> mtp_device_observer_;
   scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
diff --git a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
index 880b6f9..57e0f46 100644
--- a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.h"
 #include "chrome/browser/storage_monitor/removable_device_constants.h"
@@ -19,7 +19,8 @@
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -131,8 +132,6 @@
     return *mock_storage_observer_;
   }
 
-  base::MessageLoop ui_loop_;
-
   TestStorageMonitorCros* monitor_;
 
   // Owned by DiskMountManager.
@@ -141,8 +140,7 @@
   StorageMonitor::EjectStatus status_;
 
  private:
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   // Temporary directory for created test data.
   base::ScopedTempDir scoped_temp_dir_;
@@ -154,10 +152,10 @@
 };
 
 StorageMonitorCrosTest::StorageMonitorCrosTest()
-    : disk_mount_manager_mock_(NULL),
+    : monitor_(NULL),
+      disk_mount_manager_mock_(NULL),
       status_(StorageMonitor::EJECT_FAILURE),
-      ui_thread_(BrowserThread::UI, &ui_loop_),
-      file_thread_(BrowserThread::FILE) {
+      thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {
 }
 
 StorageMonitorCrosTest::~StorageMonitorCrosTest() {
@@ -166,7 +164,6 @@
 void StorageMonitorCrosTest::SetUp() {
   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
   ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
-  file_thread_.Start();
   disk_mount_manager_mock_ = new disks::MockDiskMountManager();
   DiskMountManager::InitializeForTesting(disk_mount_manager_mock_);
   disk_mount_manager_mock_->SetupDefaultReplies();
@@ -477,7 +474,7 @@
   monitor_->EjectDevice(observer().last_attached().device_id(),
                         base::Bind(&StorageMonitorCrosTest::EjectNotify,
                                    base::Unretained(this)));
-  ui_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(StorageMonitor::EJECT_OK, status_);
 }
diff --git a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
index 8315210..a1c8e0e 100644
--- a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.h"
@@ -25,7 +24,7 @@
 #include "chrome/browser/storage_monitor/test_media_transfer_protocol_manager_linux.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -122,10 +121,8 @@
 
 class TestStorageMonitorLinux : public StorageMonitorLinux {
  public:
-  TestStorageMonitorLinux(const base::FilePath& path,
-                          base::MessageLoop* message_loop)
-      : StorageMonitorLinux(path),
-        message_loop_(message_loop) {
+  explicit TestStorageMonitorLinux(const base::FilePath& path)
+      : StorageMonitorLinux(path) {
     SetMediaTransferProtocolManagerForTest(
         new TestMediaTransferProtocolManagerLinux());
     SetGetDeviceInfoCallbackForTest(base::Bind(&GetDeviceInfo));
@@ -136,11 +133,10 @@
   virtual void UpdateMtab(
       const MtabWatcherLinux::MountPointDeviceMap& new_mtab) OVERRIDE {
     StorageMonitorLinux::UpdateMtab(new_mtab);
-    message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+    base::MessageLoopProxy::current()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   }
 
-  base::MessageLoop* message_loop_;
-
   DISALLOW_COPY_AND_ASSIGN(TestStorageMonitorLinux);
 };
 
@@ -161,10 +157,7 @@
   };
 
   StorageMonitorLinuxTest()
-      : message_loop_(base::MessageLoop::TYPE_IO),
-        ui_thread_(content::BrowserThread::UI, &message_loop_),
-        file_thread_(content::BrowserThread::FILE, &message_loop_) {
-  }
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
   virtual ~StorageMonitorLinuxTest() {}
 
  protected:
@@ -182,7 +175,7 @@
                 true  /* overwrite */);
 
     TestStorageMonitor::RemoveSingleton();
-    monitor_ = new TestStorageMonitorLinux(mtab_file_, &message_loop_);
+    monitor_ = new TestStorageMonitorLinux(mtab_file_);
     scoped_ptr<StorageMonitor> pass_monitor(monitor_);
     TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
     DCHECK(browser_process);
@@ -202,21 +195,20 @@
 
     // Linux storage monitor must be destroyed on the UI thread, so do it here.
     TestStorageMonitor::RemoveSingleton();
-    base::RunLoop().RunUntilIdle();
   }
 
   // Append mtab entries from the |data| array of size |data_size| to the mtab
   // file, and run the message loop.
   void AppendToMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
     WriteToMtab(data, data_size, false  /* do not overwrite */);
-    message_loop_.Run();
+    base::RunLoop().Run();
   }
 
   // Overwrite the mtab file with mtab entries from the |data| array of size
   // |data_size|, and run the message loop.
   void OverwriteMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
     WriteToMtab(data, data_size, true  /* overwrite */);
-    message_loop_.Run();
+    base::RunLoop().Run();
   }
 
   // Simplied version of OverwriteMtabAndRunLoop() that just deletes all the
@@ -312,10 +304,7 @@
     ASSERT_EQ(1, endmntent(file));
   }
 
-  // The message loop and file thread to run tests on.
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
 
diff --git a/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm b/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
index 0aa5a2c..bb483da 100644
--- a/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
+++ b/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
@@ -7,7 +7,6 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/mac/foundation_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -16,7 +15,7 @@
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 uint64 kTestSize = 1000000ULL;
@@ -38,10 +37,7 @@
 
 class StorageMonitorMacTest : public testing::Test {
  public:
-  StorageMonitorMacTest()
-      : ui_thread_(content::BrowserThread::UI, &message_loop_),
-        file_thread_(content::BrowserThread::FILE, &message_loop_) {
-  }
+  StorageMonitorMacTest() {}
 
   virtual void SetUp() OVERRIDE {
     TestStorageMonitor::RemoveSingleton();
@@ -71,10 +67,7 @@
   }
 
  protected:
-  // The message loop and file thread to run tests on.
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
 
@@ -119,7 +112,7 @@
   StorageInfo info2 = CreateStorageInfo(
       device_id_, "", mount_point_, kTestSize * 2);
   UpdateDisk(info2, StorageMonitorMac::UPDATE_DEVICE_CHANGED);
-  message_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1, mock_storage_observer_->detach_calls());
   EXPECT_EQ(device_id_, mock_storage_observer_->last_detached().device_id());
diff --git a/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
index 5ca7138..72e6f75 100644
--- a/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
@@ -10,7 +10,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.h"
@@ -24,7 +24,8 @@
 #include "chrome/browser/storage_monitor/test_volume_mount_watcher_win.h"
 #include "chrome/browser/storage_monitor/volume_mount_watcher_win.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
@@ -70,21 +71,18 @@
   MockRemovableStorageObserver observer_;
 
  private:
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(StorageMonitorWinTest);
 };
 
-StorageMonitorWinTest::StorageMonitorWinTest()
-    : ui_thread_(BrowserThread::UI, &message_loop_),
-      file_thread_(BrowserThread::FILE, &message_loop_) {
+StorageMonitorWinTest::StorageMonitorWinTest() {
 }
 
 StorageMonitorWinTest::~StorageMonitorWinTest() {
 }
 
 void StorageMonitorWinTest::SetUp() {
-  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TestStorageMonitor::RemoveSingleton();
   volume_mount_watcher_ = new TestVolumeMountWatcherWin;
   monitor_ = new TestStorageMonitorWin(volume_mount_watcher_,
@@ -155,7 +153,7 @@
 
 void StorageMonitorWinTest::RunUntilIdle() {
   volume_mount_watcher_->FlushWorkerPoolForTesting();
-  message_loop_.RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 void StorageMonitorWinTest::DoMassStorageDeviceAttachedTest(
diff --git a/chrome/browser/sync/OWNERS b/chrome/browser/sync/OWNERS
index 033e1f6..a7c8a0f 100644
--- a/chrome/browser/sync/OWNERS
+++ b/chrome/browser/sync/OWNERS
@@ -6,3 +6,6 @@
 rsimha@chromium.org
 tim@chromium.org
 zea@chromium.org
+
+per-file sync_policy_handler*=dconnelly@chromium.org
+per-file sync_policy_handler*=joaodasilva@chromium.org
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 9df6acf..0c7c3b3 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -75,6 +75,15 @@
 
 namespace {
 
+// Enums for UMAs.
+enum SyncBackendInitState {
+    SETUP_COMPLETED_FOUND_RESTORED_TYPES = 0,
+    SETUP_COMPLETED_NO_RESTORED_TYPES,
+    FIRST_SETUP_NO_RESTORED_TYPES,
+    FIRST_SETUP_RESTORED_TYPES,
+    SYNC_BACKEND_INIT_STATE_COUNT
+};
+
 // Helper struct to handle currying params to
 // SyncBackendHost::Core::DoConfigureSyncer.
 struct DoConfigureSyncerTypes {
@@ -102,6 +111,7 @@
  public:
   Core(const std::string& name,
        const base::FilePath& sync_data_folder_path,
+       bool has_sync_setup_completed,
        const base::WeakPtr<SyncBackendHost>& backend);
 
   // SyncManager::Observer implementation.  The Core just acts like an air
@@ -118,7 +128,6 @@
   virtual void OnConnectionStatusChange(
       syncer::ConnectionStatus status) OVERRIDE;
   virtual void OnStopSyncingPermanently() OVERRIDE;
-  virtual void OnUpdatedToken(const std::string& token) OVERRIDE;
   virtual void OnActionableError(
       const syncer::SyncProtocolError& sync_error) OVERRIDE;
 
@@ -176,11 +185,6 @@
   // reencrypt everything.
   void DoEnableEncryptEverything();
 
-  // Called at startup to download the control types. Will invoke
-  // DoInitialProcessControlTypes on success, and OnControlTypesDownloadRetry
-  // if an error occurred.
-  void DoDownloadControlTypes(syncer::ConfigureReason reason);
-
   // Ask the syncer to check for updates for the specified types.
   void DoRefreshTypes(syncer::ModelTypeSet types);
 
@@ -291,6 +295,12 @@
   // The top-level syncapi entry point.  Lives on the sync thread.
   scoped_ptr<syncer::SyncManager> sync_manager_;
 
+  // Temporary holder of sync manager's initialization results. Set by
+  // OnInitializeComplete, and consumed when we pass it via OnBackendInitialized
+  // in the final state of HandleInitializationSuccessOnFrontendLoop.
+  syncer::WeakHandle<syncer::JsBackend> js_backend_;
+  syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
+
   // These signals allow us to send requests to shut down the HttpBridgeFactory
   // and ServerConnectionManager without having to wait for those classes to
   // finish initializing first.
@@ -299,6 +309,10 @@
   syncer::CancelationSignal release_request_context_signal_;
   syncer::CancelationSignal stop_syncing_signal_;
 
+  // Matches the value of SyncPref's HasSyncSetupCompleted() flag at init time.
+  // Should not be used for anything except for UMAs and logging.
+  const bool has_sync_setup_completed_;
+
   base::WeakPtrFactory<Core> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Core);
@@ -311,7 +325,7 @@
     : frontend_loop_(base::MessageLoop::current()),
       profile_(profile),
       name_(name),
-      initialization_state_(NOT_ATTEMPTED),
+      initialized_(false),
       sync_prefs_(sync_prefs),
       frontend_(NULL),
       cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
@@ -320,6 +334,7 @@
       invalidation_handler_registered_(false),
       weak_ptr_factory_(this) {
   core_ = new Core(name_, profile_->GetPath().Append(kSyncDataFolderName),
+                   sync_prefs_->HasSyncSetupCompleted(),
                    weak_ptr_factory_.GetWeakPtr());
 }
 
@@ -327,7 +342,7 @@
     : frontend_loop_(base::MessageLoop::current()),
       profile_(profile),
       name_("Unknown"),
-      initialization_state_(NOT_ATTEMPTED),
+      initialized_(false),
       frontend_(NULL),
       cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
       invalidation_handler_registered_(false),
@@ -378,8 +393,6 @@
         InternalComponentsFactoryImpl::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
   }
 
-  initialization_state_ = CREATING_SYNC_MANAGER;
-
   scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
       registrar_->sync_thread()->message_loop(),
       registrar_.get(),
@@ -402,8 +415,7 @@
       scoped_ptr<InternalComponentsFactory>(
           new InternalComponentsFactoryImpl(factory_switches)).Pass(),
       unrecoverable_error_handler.Pass(),
-      report_unrecoverable_error_function,
-      !cl->HasSwitch(switches::kSyncDisableOAuth2Token)));
+      report_unrecoverable_error_function));
   InitCore(init_opts.Pass());
 }
 
@@ -496,7 +508,6 @@
 
 void SyncBackendHost::StopSyncingForShutdown() {
   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  DCHECK_GT(initialization_state_, NOT_ATTEMPTED);
 
   // Immediately stop sending messages to the frontend.
   frontend_ = NULL;
@@ -544,7 +555,6 @@
       base::Bind(&SyncBackendRegistrar::Shutdown,
                  base::Unretained(detached_registrar)));
 
-  js_backend_.Reset();
   if (sync_thread_claimed)
     return detached_registrar->ReleaseSyncThread();
   else
@@ -571,8 +581,6 @@
   // configurations will pass through the DataTypeManager, which is careful to
   // never send a new configure request until the current request succeeds.
 
-  DCHECK_EQ(initialization_state_, INITIALIZED);
-
   // The SyncBackendRegistrar's routing info will be updated by adding the
   // types_to_add to the list then removing types_to_remove.  Any types which
   // are not in either of those sets will remain untouched.
@@ -796,48 +804,6 @@
     ready_task.Run(succeeded_configuration_types, failed_configuration_types);
 }
 
-void SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop(
-    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-        debug_info_listener,
-    syncer::ModelTypeSet restored_types) {
-  DCHECK_EQ(initialization_state_, CREATING_SYNC_MANAGER);
-  DCHECK(!js_backend_.IsInitialized());
-
-  initialization_state_ = INITIALIZATING_CONTROL_TYPES;
-
-  js_backend_ = js_backend;
-  debug_info_listener_ = debug_info_listener;
-
-  invalidator_->RegisterInvalidationHandler(this);
-  invalidation_handler_registered_ = true;
-
-  // Inform the registrar of those types that have been fully downloaded and
-  // applied.
-  registrar_->SetInitialTypes(restored_types);
-
-  // Start forwarding refresh requests to the SyncManager
-  notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
-                              content::Source<Profile>(profile_));
-
-  syncer::ConfigureReason reason =
-      (sync_prefs_->HasSyncSetupCompleted() ?
-       syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE :
-       syncer::CONFIGURE_REASON_NEW_CLIENT);
-
-  // Fake a state change to initialize the SyncManager's cached invalidator
-  // state.
-  OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
-
-  // Kick off the next step in SyncBackendHost initialization by downloading
-  // any necessary control types.
-  registrar_->sync_thread()->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&SyncBackendHost::Core::DoDownloadControlTypes,
-                 core_.get(),
-                 reason));
-}
-
 void SyncBackendHost::Observe(
     int type,
     const content::NotificationSource& source,
@@ -869,8 +835,7 @@
     scoped_ptr<InternalComponentsFactory> internal_components_factory,
     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
     syncer::ReportUnrecoverableErrorFunction
-        report_unrecoverable_error_function,
-    bool use_oauth2_token)
+        report_unrecoverable_error_function)
     : sync_loop(sync_loop),
       registrar(registrar),
       routing_info(routing_info),
@@ -889,20 +854,21 @@
       internal_components_factory(internal_components_factory.Pass()),
       unrecoverable_error_handler(unrecoverable_error_handler.Pass()),
       report_unrecoverable_error_function(
-          report_unrecoverable_error_function),
-      use_oauth2_token(use_oauth2_token) {
+          report_unrecoverable_error_function) {
 }
 
 SyncBackendHost::DoInitializeOptions::~DoInitializeOptions() {}
 
 SyncBackendHost::Core::Core(const std::string& name,
                             const base::FilePath& sync_data_folder_path,
+                            bool has_sync_setup_completed,
                             const base::WeakPtr<SyncBackendHost>& backend)
     : name_(name),
       sync_data_folder_path_(sync_data_folder_path),
       host_(backend),
       sync_loop_(NULL),
       registrar_(NULL),
+      has_sync_setup_completed_(has_sync_setup_completed),
       weak_ptr_factory_(this) {
   DCHECK(backend.get());
 }
@@ -923,33 +889,6 @@
       snapshot);
 }
 
-void SyncBackendHost::Core::DoDownloadControlTypes(
-    syncer::ConfigureReason reason) {
-  syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes(
-      syncer::ControlTypes(), syncer::ModelTypeSet());
-  syncer::ModelSafeRoutingInfo routing_info;
-  registrar_->GetModelSafeRoutingInfo(&routing_info);
-  SDVLOG(1) << "Control Types "
-            << syncer::ModelTypeSetToString(new_control_types)
-            << " added; calling ConfigureSyncer";
-
-  syncer::ModelTypeSet types_to_purge =
-      syncer::Difference(syncer::ModelTypeSet::All(),
-                         GetRoutingInfoTypes(routing_info));
-
-  sync_manager_->ConfigureSyncer(
-      reason,
-      new_control_types,
-      types_to_purge,
-      syncer::ModelTypeSet(),
-      syncer::ModelTypeSet(),
-      routing_info,
-      base::Bind(&SyncBackendHost::Core::DoInitialProcessControlTypes,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(&SyncBackendHost::Core::OnControlTypesDownloadRetry,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
 void SyncBackendHost::Core::DoRefreshTypes(syncer::ModelTypeSet types) {
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
   sync_manager_->RefreshTypes(types);
@@ -971,8 +910,7 @@
   if (!success) {
     DoDestroySyncManager();
     host_.Call(FROM_HERE,
-               &SyncBackendHost::HandleInitializationCompletedOnFrontendLoop,
-               false);
+               &SyncBackendHost::HandleInitializationFailureOnFrontendLoop);
     return;
   }
 
@@ -988,11 +926,63 @@
                        base::Bind(&Core::StartSavingChanges,
                                   weak_ptr_factory_.GetWeakPtr()));
 
-  host_.Call(FROM_HERE,
-             &SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop,
-             js_backend,
-             debug_info_listener,
-             restored_types);
+  // Hang on to these for a while longer.  We're not ready to hand them back to
+  // the UI thread yet.
+  js_backend_ = js_backend;
+  debug_info_listener_ = debug_info_listener;
+
+  // Track whether or not sync DB and preferences were in sync.
+  SyncBackendInitState backend_init_state;
+  if (has_sync_setup_completed_ && !restored_types.Empty()) {
+    backend_init_state = SETUP_COMPLETED_FOUND_RESTORED_TYPES;
+  } else if (has_sync_setup_completed_ && restored_types.Empty()) {
+    backend_init_state = SETUP_COMPLETED_NO_RESTORED_TYPES;
+  } else if (!has_sync_setup_completed_ && restored_types.Empty()) {
+    backend_init_state = FIRST_SETUP_NO_RESTORED_TYPES;
+  } else { // (!has_sync_setup_completed_ && !restored_types.Empty())
+    backend_init_state = FIRST_SETUP_RESTORED_TYPES;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
+                            backend_init_state,
+                            SYNC_BACKEND_INIT_STATE_COUNT);
+
+  // Before proceeding any further, we need to download the control types and
+  // purge any partial data (ie. data downloaded for a type that was on its way
+  // to being initially synced, but didn't quite make it.).  The following
+  // configure cycle will take care of this.  It depends on the registrar state
+  // which we initialize below to ensure that we don't perform any downloads if
+  // all control types have already completed their initial sync.
+  registrar_->SetInitialTypes(restored_types);
+
+  syncer::ConfigureReason reason =
+      restored_types.Empty() ?
+       syncer::CONFIGURE_REASON_NEW_CLIENT :
+       syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
+
+  syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes(
+      syncer::ControlTypes(), syncer::ModelTypeSet());
+  syncer::ModelSafeRoutingInfo routing_info;
+  registrar_->GetModelSafeRoutingInfo(&routing_info);
+  SDVLOG(1) << "Control Types "
+            << syncer::ModelTypeSetToString(new_control_types)
+            << " added; calling ConfigureSyncer";
+
+  syncer::ModelTypeSet types_to_purge =
+      syncer::Difference(syncer::ModelTypeSet::All(),
+                         GetRoutingInfoTypes(routing_info));
+
+  sync_manager_->ConfigureSyncer(
+      reason,
+      new_control_types,
+      types_to_purge,
+      syncer::ModelTypeSet(),
+      syncer::ModelTypeSet(),
+      routing_info,
+      base::Bind(&SyncBackendHost::Core::DoInitialProcessControlTypes,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&SyncBackendHost::Core::OnControlTypesDownloadRetry,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void SyncBackendHost::Core::OnConnectionStatusChange(
@@ -1046,15 +1036,6 @@
       &SyncBackendHost::HandleStopSyncingPermanentlyOnFrontendLoop);
 }
 
-void SyncBackendHost::Core::OnUpdatedToken(const std::string& token) {
-  if (!sync_loop_)
-    return;
-  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
-  host_.Call(
-      FROM_HERE,
-      &SyncBackendHost::NotifyUpdatedToken, token);
-}
-
 void SyncBackendHost::Core::OnEncryptedTypesChanged(
     syncer::ModelTypeSet encrypted_types,
     bool encrypt_everything) {
@@ -1161,7 +1142,6 @@
                       &encryptor_,
                       options->unrecoverable_error_handler.Pass(),
                       options->report_unrecoverable_error_function,
-                      options->use_oauth2_token,
                       &stop_syncing_signal_);
 
   // |sync_manager_| may end up being NULL here in tests (in
@@ -1224,8 +1204,7 @@
     DVLOG(1) << "Skipping initialization of DeviceInfo";
     host_.Call(
         FROM_HERE,
-        &SyncBackendHost::HandleInitializationCompletedOnFrontendLoop,
-        true);
+        &SyncBackendHost::HandleInitializationFailureOnFrontendLoop);
     return;
   }
 
@@ -1233,8 +1212,7 @@
     LOG(ERROR) << "Failed to download control types";
     host_.Call(
         FROM_HERE,
-        &SyncBackendHost::HandleInitializationCompletedOnFrontendLoop,
-        false);
+        &SyncBackendHost::HandleInitializationFailureOnFrontendLoop);
     return;
   }
 
@@ -1256,8 +1234,12 @@
 
   host_.Call(
       FROM_HERE,
-      &SyncBackendHost::HandleInitializationCompletedOnFrontendLoop,
-      true);
+      &SyncBackendHost::HandleInitializationSuccessOnFrontendLoop,
+      js_backend_,
+      debug_info_listener_);
+
+  js_backend_.Reset();
+  debug_info_listener_.Reset();
 }
 
 void SyncBackendHost::Core::DoSetDecryptionPassphrase(
@@ -1417,33 +1399,45 @@
   frontend_->OnSyncConfigureRetry();
 }
 
-void SyncBackendHost::HandleInitializationCompletedOnFrontendLoop(
-    bool success) {
-  DCHECK_NE(initialization_state_, NOT_ATTEMPTED);
+void SyncBackendHost::HandleInitializationSuccessOnFrontendLoop(
+    const syncer::WeakHandle<syncer::JsBackend> js_backend,
+    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
+        debug_info_listener) {
+  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
   if (!frontend_)
     return;
 
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  if (!success) {
-    js_backend_.Reset();
-    initialization_state_ = NOT_INITIALIZED;
-    frontend_->OnBackendInitialized(
-        syncer::WeakHandle<syncer::JsBackend>(),
-        syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
-        false);
-    return;
-  }
+  initialized_ = true;
 
-  initialization_state_ = INITIALIZED;
+  invalidator_->RegisterInvalidationHandler(this);
+  invalidation_handler_registered_ = true;
+
+  // Fake a state change to initialize the SyncManager's cached invalidator
+  // state.
+  OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
+
+  // Start forwarding refresh requests to the SyncManager
+  notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
+                              content::Source<Profile>(profile_));
 
   // Now that we've downloaded the control types, we can see if there are any
   // experimental types to enable. This should be done before we inform
   // the frontend to ensure they're visible in the customize screen.
   AddExperimentalTypes();
-  frontend_->OnBackendInitialized(js_backend_,
-                                  debug_info_listener_,
+  frontend_->OnBackendInitialized(js_backend,
+                                  debug_info_listener,
                                   true);
-  js_backend_.Reset();
+}
+
+void SyncBackendHost::HandleInitializationFailureOnFrontendLoop() {
+  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
+  if (!frontend_)
+    return;
+
+  frontend_->OnBackendInitialized(
+      syncer::WeakHandle<syncer::JsBackend>(),
+      syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
+      false);
 }
 
 void SyncBackendHost::HandleSyncCycleCompletedOnFrontendLoop(
@@ -1559,15 +1553,6 @@
   frontend_->OnPassphraseAccepted();
 }
 
-void SyncBackendHost::NotifyUpdatedToken(const std::string& token) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  TokenAvailableDetails details(GaiaConstants::kSyncService, token);
-
-  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
-  CHECK(token_service);
-  token_service->AddAuthTokenManually(details.service(), details.token());
-}
-
 void SyncBackendHost::NotifyEncryptedTypesChanged(
     syncer::ModelTypeSet encrypted_types,
     bool encrypt_everything) {
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 6a3cb20..0480e96 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -334,8 +334,7 @@
         scoped_ptr<syncer::UnrecoverableErrorHandler>
             unrecoverable_error_handler,
         syncer::ReportUnrecoverableErrorFunction
-            report_unrecoverable_error_function,
-        bool use_oauth2_token);
+            report_unrecoverable_error_function);
     ~DoInitializeOptions();
 
     base::MessageLoop* sync_loop;
@@ -358,7 +357,6 @@
     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler;
     syncer::ReportUnrecoverableErrorFunction
         report_unrecoverable_error_function;
-    bool use_oauth2_token;
   };
 
   // Allows tests to perform alternate core initialization work.
@@ -386,14 +384,16 @@
       const base::Callback<void(syncer::ModelTypeSet,
                                 syncer::ModelTypeSet)>& ready_task);
 
-  // Called when the SyncManager has been constructed and initialized.
-  // Stores |js_backend| and |debug_info_listener| on the UI thread for
-  // consumption when initialization is complete.
-  virtual void HandleSyncManagerInitializationOnFrontendLoop(
-      const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-      const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-          debug_info_listener,
-      syncer::ModelTypeSet restored_types);
+  // Reports backend initialization success.  Includes some objects from sync
+  // manager initialization to be passed back to the UI thread.
+  virtual void HandleInitializationSuccessOnFrontendLoop(
+    const syncer::WeakHandle<syncer::JsBackend> js_backend,
+    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
+        debug_info_listener);
+
+  // Downloading of control types failed and will be retried. Invokes the
+  // frontend's sync configure retry method.
+  void HandleControlTypesDownloadRetry();
 
   SyncFrontend* frontend() { return frontend_; }
 
@@ -419,15 +419,8 @@
   // Note: it is illegal to call this before the backend is initialized.
   void AddExperimentalTypes();
 
-  // Downloading of control types failed and will be retried. Invokes the
-  // frontend's sync configure retry method.
-  void HandleControlTypesDownloadRetry();
-
-  // InitializationComplete passes through the SyncBackendHost to forward
-  // on to |frontend_|, and so that tests can intercept here if they need to
-  // set up initial conditions.
-  void HandleInitializationCompletedOnFrontendLoop(
-      bool success);
+  // Handles backend initialization failure.
+  void HandleInitializationFailureOnFrontendLoop();
 
   // Called from Core::OnSyncCycleCompleted to handle updating frontend
   // thread components.
@@ -448,7 +441,7 @@
       syncer::BootstrapTokenType token_type);
 
   // For convenience, checks if initialization state is INITIALIZED.
-  bool initialized() const { return initialization_state_ == INITIALIZED; }
+  bool initialized() const { return initialized_; }
 
   // Let the front end handle the actionable error event.
   void HandleActionableErrorEventOnFrontendLoop(
@@ -473,9 +466,6 @@
   // Invoked when the passphrase provided by the user has been accepted.
   void NotifyPassphraseAccepted();
 
-  // Invoked when an updated token is available from the sync server.
-  void NotifyUpdatedToken(const std::string& token);
-
   // Invoked when the set of encrypted types or the encrypt
   // everything flag changes.
   void NotifyEncryptedTypesChanged(
@@ -535,7 +525,7 @@
   // sync loop.
   scoped_refptr<Core> core_;
 
-  InitializationState initialization_state_;
+  bool initialized_;
 
   const base::WeakPtr<SyncPrefs> sync_prefs_;
 
@@ -569,13 +559,6 @@
   // UI-thread cache of the last SyncSessionSnapshot received from syncapi.
   syncer::sessions::SyncSessionSnapshot last_snapshot_;
 
-  // Temporary holder of sync manager's initialization results. Set by
-  // HandleSyncManagerInitializationOnFrontendLoop, and consumed when we pass
-  // it via OnBackendInitialized in the final state of
-  // HandleInitializationCompletedOnFrontendLoop.
-  syncer::WeakHandle<syncer::JsBackend> js_backend_;
-  syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
-
   invalidation::InvalidationService* invalidator_;
   bool invalidation_handler_registered_;
 
diff --git a/chrome/browser/sync/glue/sync_backend_host_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
index 8a4ef24..9ce675d 100644
--- a/chrome/browser/sync/glue/sync_backend_host_unittest.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
@@ -679,6 +679,8 @@
 // Test that configuration on restart sends the proper GU source.
 TEST_F(SyncBackendHostTest, DownloadControlTypesRestart) {
   sync_prefs_->SetSyncSetupCompleted();
+  fake_manager_factory_->set_progress_marker_types(enabled_types_);
+  fake_manager_factory_->set_initial_sync_ended_types(enabled_types_);
   InitializeBackend(true);
   EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE,
             fake_manager_->GetAndResetConfigureReason());
diff --git a/chrome/browser/sync/glue/sync_backend_registrar.cc b/chrome/browser/sync/glue/sync_backend_registrar.cc
index 84fcd27..c2c70eb 100644
--- a/chrome/browser/sync/glue/sync_backend_registrar.cc
+++ b/chrome/browser/sync/glue/sync_backend_registrar.cc
@@ -104,10 +104,8 @@
 }
 
 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   base::AutoLock lock(lock_);
 
-
   // This function should be called only once, shortly after construction. The
   // routing info at that point is expected to be empty.
   DCHECK(routing_info_.empty());
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index e734a1e..bb6b5d7 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/storage/settings_frontend.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/history/history_service.h"
@@ -353,7 +354,7 @@
     }
     case syncer::APPS:
     case syncer::EXTENSIONS:
-      return extension_system_->extension_service()->AsWeakPtr();
+      return ExtensionSyncService::Get(profile_)->AsWeakPtr();
     case syncer::SEARCH_ENGINES:
       return TemplateURLServiceFactory::GetForProfile(profile_)->AsWeakPtr();
     case syncer::APP_SETTINGS:
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index bbeed23..ead0cf5 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -174,7 +174,6 @@
       auto_start_enabled_(start_behavior == AUTO_START),
       configure_status_(DataTypeManager::UNKNOWN),
       setup_in_progress_(false),
-      use_oauth2_token_(false),
       oauth2_token_service_(oauth2_token_service),
       request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
       weak_factory_(this) {
@@ -208,22 +207,10 @@
 }
 
 bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
-  // Function name doesn't reflect which token is checked. Function checks
-  // refresh token when use_oauth2_token_ is true (all platforms except android)
-  // and sync token otherwise (for android).
-  // TODO(pavely): Remove "else" part once use_oauth2_token_ is gone.
-  if (use_oauth2_token_) {
-    if (!oauth2_token_service_)
-      return false;
-    return oauth2_token_service_->RefreshTokenIsAvailable(
-        oauth2_token_service_->GetPrimaryAccountId());
-  } else {
-    TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
-    if (!token_service)
-      return false;
-
-    return token_service->HasTokenForService(GaiaConstants::kSyncService);
-  }
+  if (!oauth2_token_service_)
+    return false;
+  return oauth2_token_service_->RefreshTokenIsAvailable(
+      oauth2_token_service_->GetPrimaryAccountId());
 }
 
 void ProfileSyncService::Initialize() {
@@ -306,14 +293,12 @@
     return;
   }
 
-  if (use_oauth2_token_) {
-    // If we got here then tokens are loaded and user logged in and sync is
-    // enabled. If OAuth refresh token is not available then something is wrong.
-    // When PSS requests access token, OAuth2TokenService will return error and
-    // PSS will show error to user asking to reauthenticate.
-    UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable",
-        IsOAuthRefreshTokenAvailable());
-  }
+  // If we got here then tokens are loaded and user logged in and sync is
+  // enabled. If OAuth refresh token is not available then something is wrong.
+  // When PSS requests access token, OAuth2TokenService will return error and
+  // PSS will show error to user asking to reauthenticate.
+  UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable",
+      IsOAuthRefreshTokenAvailable());
 
   // If sync setup has completed we always start the backend. If the user is in
   // the process of setting up now, we should start the backend to download
@@ -481,24 +466,13 @@
       }
     }
   }
-
-  use_oauth2_token_ = !command_line.HasSwitch(
-      switches::kSyncDisableOAuth2Token);
 }
 
 SyncCredentials ProfileSyncService::GetCredentials() {
   SyncCredentials credentials;
   credentials.email = GetEffectiveUsername();
   DCHECK(!credentials.email.empty());
-  if (use_oauth2_token_) {
-    credentials.sync_token = access_token_;
-  } else {
-    TokenService* service = TokenServiceFactory::GetForProfile(profile_);
-    if (service->HasTokenForService(GaiaConstants::kSyncService)) {
-      credentials.sync_token = service->GetTokenForService(
-          GaiaConstants::kSyncService);
-    }
-  }
+  credentials.sync_token = access_token_;
 
   if (credentials.sync_token.empty())
     credentials.sync_token = "credentials_lost";
@@ -1106,12 +1080,6 @@
   is_auth_in_progress_ = false;
   last_auth_error_ = error;
 
-  // Fan the notification out to interested UI-thread components. Notify the
-  // SigninGlobalError first so it reflects the latest auth state before we
-  // notify observers.
-  if (profile_ && !use_oauth2_token_)
-    SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
-
   NotifyObservers();
 }
 
@@ -1139,7 +1107,7 @@
 
 void ProfileSyncService::OnConnectionStatusChange(
     syncer::ConnectionStatus status) {
-  if (use_oauth2_token_ && status == syncer::CONNECTION_AUTH_ERROR) {
+  if (status == syncer::CONNECTION_AUTH_ERROR) {
     // Sync server returned error indicating that access token is invalid. It
     // could be either expired or access is revoked. Let's request another
     // access token and if access is revoked then request for token will fail
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index fe0519d..73da61e 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -955,11 +955,6 @@
   //     * If sync is reenabled, PSS passes ownership to new backend.
   scoped_ptr<base::Thread> sync_thread_;
 
-  // Specifies whenever to use oauth2 access token or ClientLogin token in
-  // communications with sync and xmpp servers.
-  // TODO(pavely): Remove once android is converted to oauth2 tokens.
-  bool use_oauth2_token_;
-
   // ProfileSyncService uses this service to get access tokens.
   ProfileOAuth2TokenService* oauth2_token_service_;
 
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index ec7d507..0ab68f2 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -19,8 +19,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/browser/sync/about_sync_util.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -32,7 +30,6 @@
 #include "google/cacheinvalidation/types.pb.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_token_service.h"
 #include "grit/generated_resources.h"
 #include "jni/ProfileSyncService_jni.h"
 #include "sync/internal_api/public/read_transaction.h"
@@ -135,13 +132,6 @@
       env, weak_java_profile_sync_service_.get(env).obj());
 }
 
-void ProfileSyncServiceAndroid::TokenAvailable(
-    JNIEnv* env, jobject, jstring username, jstring auth_token) {
-  std::string token = ConvertJavaStringToUTF8(env, auth_token);
-  TokenServiceFactory::GetForProfile(profile_)->OnIssueAuthTokenSuccess(
-      GaiaConstants::kSyncService, token);
-}
-
 void ProfileSyncServiceAndroid::EnableSync(JNIEnv* env, jobject) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // Don't need to do anything if we're already enabled.
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h
index 19ec2a3..5af9cd8 100644
--- a/chrome/browser/sync/profile_sync_service_android.h
+++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -47,8 +47,6 @@
   // which types have changed.
   void NudgeSyncerForAllTypes(JNIEnv* env, jobject obj);
 
-  void TokenAvailable(JNIEnv*, jobject, jstring username, jstring auth_token);
-
   // Called from Java when the user manually enables sync
   void EnableSync(JNIEnv* env, jobject obj);
 
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 61b9e7e..56e25fd 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -592,7 +592,6 @@
     // We need tokens to get the tests going
     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
         ->UpdateCredentials("test_user@gmail.com", "oauth2_login_token");
-    token_service_->IssueAuthTokenForTest(GaiaConstants::kSyncService, "token");
 
     sync_service_->RegisterDataTypeController(data_type_controller);
     sync_service_->Initialize();
diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc
index f156fdd..800d1bb 100644
--- a/chrome/browser/sync/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/profile_sync_service_harness.cc
@@ -209,8 +209,6 @@
       content::Details<const GoogleServiceSigninSuccessDetails>(&details));
   TokenServiceFactory::GetForProfile(profile_)->IssueAuthTokenForTest(
       GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth2_login_token");
-  TokenServiceFactory::GetForProfile(profile_)->IssueAuthTokenForTest(
-      GaiaConstants::kSyncService, "sync_token");
 
   // Wait for the OnBackendInitialized() callback.
   if (!AwaitBackendInitialized()) {
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index e10844d..ecf25b9 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -236,8 +236,6 @@
       // We need tokens to get the tests going
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
           ->UpdateCredentials("test_user@gmail.com", "oauth2_login_token");
-      token_service_->IssueAuthTokenForTest(GaiaConstants::kSyncService,
-                                            "token");
 
       sync_service_->RegisterDataTypeController(data_type_controller);
       sync_service_->Initialize();
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index b3683bf..97cc442 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -12,11 +12,11 @@
 #include "base/json/json_string_value_serializer.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/prefs/pref_model_associator.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/token_service_factory.h"
@@ -187,8 +187,6 @@
     sync_service_->RegisterDataTypeController(dtc_);
     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
         ->UpdateCredentials("test", "oauth2_login_token");
-    TokenServiceFactory::GetForProfile(profile_.get())
-        ->IssueAuthTokenForTest(GaiaConstants::kSyncService, "token");
 
     sync_service_->Initialize();
     base::MessageLoop::current()->Run();
@@ -246,6 +244,10 @@
     return pref_sync_service_->registered_preferences().count(pref_name) > 0;
   }
 
+  bool HasSyncData(const std::string& pref_name) {
+    return pref_sync_service_->IsPrefSynced(pref_name);
+  }
+
   std::string ValueString(const Value& value) {
     std::string serialized;
     JSONStringValueSerializer json(&serialized);
@@ -253,6 +255,15 @@
     return serialized;
   }
 
+  // Returns whether a given preference name is a new name of a migrated
+  // preference. Exposed here for testing.
+  static bool IsMigratedPreference(const char* preference_name) {
+    return PrefModelAssociator::IsMigratedPreference(preference_name);
+  }
+  static bool IsOldMigratedPreference(const char* old_preference_name) {
+    return PrefModelAssociator::IsOldMigratedPreference(old_preference_name);
+  }
+
   scoped_ptr<TestingProfile> profile_;
   TestingPrefServiceSyncable* prefs_;
 
@@ -403,12 +414,45 @@
             prefs_->GetString(prefs::kDefaultCharset));
 }
 
+TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationMigrateOldData) {
+  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
+  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
+
+  PreferenceValues cloud_data;
+  STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
+  ListValue* urls_to_restore = new ListValue;
+  urls_to_restore->Append(Value::CreateStringValue(example_url1_));
+  urls_to_restore->Append(Value::CreateStringValue(example_url2_));
+  cloud_data[prefs::kURLsToRestoreOnStartupOld] = urls_to_restore;
+
+  AddPreferenceEntriesHelper helper(this, cloud_data);
+  ASSERT_TRUE(StartSyncService(helper.callback(), false));
+  ASSERT_TRUE(helper.success());
+
+  // Expect that the new preference data contains the old pref's values.
+  scoped_ptr<ListValue> expected_urls(new ListValue);
+  expected_urls->Append(Value::CreateStringValue(example_url1_));
+  expected_urls->Append(Value::CreateStringValue(example_url2_));
+
+  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
+  scoped_ptr<const Value> value(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->Equals(expected_urls.get()));
+  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
+              Equals(expected_urls.get()));
+
+  // The old preference value should be the same.
+  expected_urls.reset(new ListValue);
+  value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartupOld));
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
+              Equals(expected_urls.get()));
+}
+
 TEST_F(ProfileSyncServicePreferenceTest,
        ModelAssociationCloudHasOldMigratedData) {
-  ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
-      prefs::kURLsToRestoreOnStartup));
-  ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
-      prefs::kURLsToRestoreOnStartupOld));
+  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
+  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
   prefs_->SetString(prefs::kHomePage, example_url0_);
   {
     ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartup);
@@ -442,6 +486,7 @@
   expected_urls->Append(Value::CreateStringValue(example_url2_));
   expected_urls->Append(Value::CreateStringValue(example_url0_));
 
+  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
   value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
   ASSERT_TRUE(value.get());
   EXPECT_TRUE(value->Equals(expected_urls.get()));
@@ -458,10 +503,8 @@
 
 TEST_F(ProfileSyncServicePreferenceTest,
        ModelAssociationCloudHasNewMigratedData) {
-  ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
-      prefs::kURLsToRestoreOnStartup));
-  ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
-      prefs::kURLsToRestoreOnStartupOld));
+  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
+  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
   prefs_->SetString(prefs::kHomePage, example_url0_);
   {
     ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartupOld);
@@ -494,6 +537,7 @@
   expected_urls->Append(Value::CreateStringValue(example_url1_));
   expected_urls->Append(Value::CreateStringValue(example_url2_));
 
+  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
   value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
   ASSERT_TRUE(value.get());
   EXPECT_TRUE(value->Equals(expected_urls.get()));
@@ -513,10 +557,8 @@
 
 TEST_F(ProfileSyncServicePreferenceTest,
        ModelAssociationCloudAddsOldAndNewMigratedData) {
-  ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
-      prefs::kURLsToRestoreOnStartup));
-  ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
-      prefs::kURLsToRestoreOnStartupOld));
+  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
+  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
   prefs_->SetString(prefs::kHomePage, example_url0_);
   {
     ListPrefUpdate update_old(prefs_, prefs::kURLsToRestoreOnStartupOld);
@@ -549,6 +591,7 @@
   expected_urls->Append(Value::CreateStringValue(example_url1_));
   expected_urls->Append(Value::CreateStringValue(example_url2_));
 
+  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
   value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
   ASSERT_TRUE(value.get());
   EXPECT_TRUE(value->Equals(expected_urls.get()));
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index 5924cd9..f5829d5 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -222,8 +222,6 @@
 
     ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
         ->UpdateCredentials("test_user", "oauth2_login_token");
-    TokenServiceFactory::GetForProfile(profile())
-        ->IssueAuthTokenForTest(GaiaConstants::kSyncService, "token");
     sync_service_->Initialize();
     base::MessageLoop::current()->Run();
     return true;
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index 8a1b6a1..e61f098 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -141,8 +141,6 @@
   void IssueTestTokens() {
     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
         ->UpdateCredentials("test_user@gmail.com", "oauth2_login_token");
-    TokenServiceFactory::GetForProfile(profile_.get())
-        ->IssueAuthTokenForTest(GaiaConstants::kSyncService, "token");
   }
 
  protected:
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index 9a0abbb..743f249 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -241,8 +241,6 @@
       ProfileOAuth2TokenService* oauth2_token_service =
           ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
       oauth2_token_service->UpdateCredentials("test", "oauth2_login_token");
-      token_service_->IssueAuthTokenForTest(GaiaConstants::kSyncService,
-                                            "token");
 
       sync_service_->RegisterDataTypeController(data_type_controller);
 
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 1899863..18deb39 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -149,8 +149,6 @@
   void IssueTestTokens() {
     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
         ->UpdateCredentials("test", "oauth2_login_token");
-    TokenServiceFactory::GetForProfile(profile_.get())
-        ->IssueAuthTokenForTest(GaiaConstants::kSyncService, "token");
   }
 
   scoped_ptr<TestProfileSyncService> service_;
diff --git a/chrome/browser/sync/sync_policy_handler.cc b/chrome/browser/sync/sync_policy_handler.cc
new file mode 100644
index 0000000..c2d47ae
--- /dev/null
+++ b/chrome/browser/sync/sync_policy_handler.cc
@@ -0,0 +1,30 @@
+// Copyright 2013 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/sync/sync_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+namespace browser_sync {
+
+SyncPolicyHandler::SyncPolicyHandler()
+    : policy::TypeCheckingPolicyHandler(policy::key::kSyncDisabled,
+                                        base::Value::TYPE_BOOLEAN) {}
+
+SyncPolicyHandler::~SyncPolicyHandler() {
+}
+
+void SyncPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies,
+                                            PrefValueMap* prefs) {
+  const base::Value* value = policies.GetValue(policy_name());
+  bool disable_sync;
+  if (value && value->GetAsBoolean(&disable_sync) && disable_sync)
+    prefs->SetValue(prefs::kSyncManaged, value->DeepCopy());
+}
+
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/sync_policy_handler.h b/chrome/browser/sync/sync_policy_handler.h
new file mode 100644
index 0000000..f7080e5
--- /dev/null
+++ b/chrome/browser/sync/sync_policy_handler.h
@@ -0,0 +1,33 @@
+// Copyright 2013 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_SYNC_SYNC_POLICY_HANDLER_H_
+#define CHROME_BROWSER_SYNC_SYNC_POLICY_HANDLER_H_
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace browser_sync {
+
+class PolicyMap;
+
+// ConfigurationPolicyHandler for the SyncDisabled policy.
+class SyncPolicyHandler : public policy::TypeCheckingPolicyHandler {
+ public:
+  SyncPolicyHandler();
+  virtual ~SyncPolicyHandler();
+
+  // ConfigurationPolicyHandler methods:
+  virtual void ApplyPolicySettings(const policy::PolicyMap& policies,
+                                   PrefValueMap* prefs) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncPolicyHandler);
+};
+
+}  // namespace browser_sync
+
+#endif  // CHROME_BROWSER_SYNC_SYNC_POLICY_HANDLER_H_
diff --git a/chrome/browser/sync/sync_policy_handler_unittest.cc b/chrome/browser/sync/sync_policy_handler_unittest.cc
new file mode 100644
index 0000000..8af72cc
--- /dev/null
+++ b/chrome/browser/sync/sync_policy_handler_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 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/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/sync/sync_policy_handler.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+
+// Test cases for the Sync policy setting.
+class SyncPolicyHandlerTest : public testing::Test {};
+
+TEST_F(SyncPolicyHandlerTest, Default) {
+  policy::PolicyMap policy;
+  SyncPolicyHandler handler;
+  PrefValueMap prefs;
+  handler.ApplyPolicySettings(policy, &prefs);
+  EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, NULL));
+}
+
+TEST_F(SyncPolicyHandlerTest, Enabled) {
+  policy::PolicyMap policy;
+  policy.Set(policy::key::kSyncDisabled,
+             policy::POLICY_LEVEL_MANDATORY,
+             policy::POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(false),
+             NULL);
+  SyncPolicyHandler handler;
+  PrefValueMap prefs;
+  handler.ApplyPolicySettings(policy, &prefs);
+
+  // Enabling Sync should not set the pref.
+  EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, NULL));
+}
+
+TEST_F(SyncPolicyHandlerTest, Disabled) {
+  policy::PolicyMap policy;
+  policy.Set(policy::key::kSyncDisabled,
+             policy::POLICY_LEVEL_MANDATORY,
+             policy::POLICY_SCOPE_USER,
+             base::Value::CreateBooleanValue(true),
+             NULL);
+  SyncPolicyHandler handler;
+  PrefValueMap prefs;
+  handler.ApplyPolicySettings(policy, &prefs);
+
+  // Sync should be flagged as managed.
+  const base::Value* value = NULL;
+  EXPECT_TRUE(prefs.GetValue(prefs::kSyncManaged, &value));
+  ASSERT_TRUE(value);
+  bool sync_managed = false;
+  bool result = value->GetAsBoolean(&sync_managed);
+  ASSERT_TRUE(result);
+  EXPECT_TRUE(sync_managed);
+}
+
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index d51ba27..feeb43ee 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -65,16 +65,6 @@
       profile, CreateFakeAppName(index));
 }
 
-void EnableApp(Profile* profile, int index) {
-  return SyncExtensionHelper::GetInstance()->EnableExtension(
-      profile, CreateFakeAppName(index));
-}
-
-void DisableApp(Profile* profile, int index) {
-  return SyncExtensionHelper::GetInstance()->DisableExtension(
-      profile, CreateFakeAppName(index));
-}
-
 void IncognitoEnableApp(Profile* profile, int index) {
   return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension(
       profile, CreateFakeAppName(index));
diff --git a/chrome/browser/sync/test/integration/apps_helper.h b/chrome/browser/sync/test/integration/apps_helper.h
index 70d3ec4..e6a8bb6 100644
--- a/chrome/browser/sync/test/integration/apps_helper.h
+++ b/chrome/browser/sync/test/integration/apps_helper.h
@@ -42,12 +42,6 @@
 // Installs all pending synced apps for |profile|.
 void InstallAppsPendingForSync(Profile* profile);
 
-// Enables the app for the given index on |profile|.
-void EnableApp(Profile* profile, int index);
-
-// Disables the app for the given index on |profile|.
-void DisableApp(Profile* profile, int index);
-
 // Enables the app for the given index in incognito mode on |profile|.
 void IncognitoEnableApp(Profile* profile, int index);
 
diff --git a/chrome/browser/sync/test/integration/extensions_helper.cc b/chrome/browser/sync/test/integration/extensions_helper.cc
index 1727fbb..c244045 100644
--- a/chrome/browser/sync/test/integration/extensions_helper.cc
+++ b/chrome/browser/sync/test/integration/extensions_helper.cc
@@ -81,16 +81,6 @@
   return indices;
 }
 
-void EnableExtension(Profile* profile, int index) {
-  return SyncExtensionHelper::GetInstance()->EnableExtension(
-      profile, CreateFakeExtensionName(index));
-}
-
-void DisableExtension(Profile* profile, int index) {
-  return SyncExtensionHelper::GetInstance()->DisableExtension(
-      profile, CreateFakeExtensionName(index));
-}
-
 bool IsExtensionEnabled(Profile* profile, int index) {
   return SyncExtensionHelper::GetInstance()->IsExtensionEnabled(
       profile, CreateFakeExtensionName(index));
diff --git a/chrome/browser/sync/test/integration/extensions_helper.h b/chrome/browser/sync/test/integration/extensions_helper.h
index 596549d..b016a82 100644
--- a/chrome/browser/sync/test/integration/extensions_helper.h
+++ b/chrome/browser/sync/test/integration/extensions_helper.h
@@ -46,12 +46,6 @@
 // Installs all pending synced extensions for |profile|.
 void InstallExtensionsPendingForSync(Profile* profile);
 
-// Enables the extension for the given index on |profile|.
-void EnableExtension(Profile* profile, int index);
-
-// Disables the extension for the given index on |profile|.
-void DisableExtension(Profile* profile, int index);
-
 // Returns true if the extension with index |index| is enabled on |profile|.
 bool IsExtensionEnabled(Profile* profile, int index);
 
diff --git a/chrome/browser/sync/test/integration/migration_errors_test.cc b/chrome/browser/sync/test/integration/migration_errors_test.cc
index d6e5626..b2fd2db 100644
--- a/chrome/browser/sync/test/integration/migration_errors_test.cc
+++ b/chrome/browser/sync/test/integration/migration_errors_test.cc
@@ -5,7 +5,7 @@
 // TODO(akalin): Rename this file to migration_test.cc.
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
diff --git a/chrome/browser/sync/test/integration/performance/extensions_sync_perf_test.cc b/chrome/browser/sync/test/integration/performance/extensions_sync_perf_test.cc
index b91e65c..4274adc 100644
--- a/chrome/browser/sync/test/integration/performance/extensions_sync_perf_test.cc
+++ b/chrome/browser/sync/test/integration/performance/extensions_sync_perf_test.cc
@@ -10,8 +10,6 @@
 
 using extensions_helper::AllProfilesHaveSameExtensions;
 using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier;
-using extensions_helper::DisableExtension;
-using extensions_helper::EnableExtension;
 using extensions_helper::GetInstalledExtensions;
 using extensions_helper::InstallExtension;
 using extensions_helper::InstallExtensionsPendingForSync;
@@ -31,9 +29,6 @@
   // Adds |num_extensions| new unique extensions to |profile|.
   void AddExtensions(int profile, int num_extensions);
 
-  // Updates the enabled/disabled state for all extensions in |profile|.
-  void UpdateExtensions(int profile);
-
   // Uninstalls all currently installed extensions from |profile|.
   void RemoveExtensions(int profile);
 
@@ -51,18 +46,6 @@
   }
 }
 
-void ExtensionsSyncPerfTest::UpdateExtensions(int profile) {
-  std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile));
-  for (std::vector<int>::iterator it = extensions.begin();
-       it != extensions.end(); ++it) {
-    if (IsExtensionEnabled(GetProfile(profile), *it)) {
-      DisableExtension(GetProfile(profile), *it);
-    } else {
-      EnableExtension(GetProfile(profile), *it);
-    }
-  }
-}
-
 int ExtensionsSyncPerfTest::GetExtensionCount(int profile) {
   return GetInstalledExtensions(GetProfile(profile)).size();
 }
@@ -88,12 +71,6 @@
   ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
   SyncTimingHelper::PrintResult("extensions", "add_extensions", dt);
 
-  // TCM ID - 7655397.
-  UpdateExtensions(0);
-  dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
-  ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
-  SyncTimingHelper::PrintResult("extensions", "update_extensions", dt);
-
   // TCM ID - 7567721.
   RemoveExtensions(0);
   dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
diff --git a/chrome/browser/sync/test/integration/preferences_helper.cc b/chrome/browser/sync/test/integration/preferences_helper.cc
index f649ab1..28ec405 100644
--- a/chrome/browser/sync/test/integration/preferences_helper.cc
+++ b/chrome/browser/sync/test/integration/preferences_helper.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/sync/test/integration/preferences_helper.h"
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index 75a69e6..0bc2a35 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -97,18 +97,6 @@
   return names;
 }
 
-void SyncExtensionHelper::EnableExtension(Profile* profile,
-                                          const std::string& name) {
-  profile->GetExtensionService()->EnableExtension(
-      extensions::id_util::GenerateId(name));
-}
-
-void SyncExtensionHelper::DisableExtension(Profile* profile,
-                                           const std::string& name) {
-  profile->GetExtensionService()->DisableExtension(
-      extensions::id_util::GenerateId(name), Extension::DISABLE_USER_ACTION);
-}
-
 bool SyncExtensionHelper::IsExtensionEnabled(
     Profile* profile, const std::string& name) const {
   return profile->GetExtensionService()->IsExtensionEnabled(
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.h b/chrome/browser/sync/test/integration/sync_extension_helper.h
index 0ed3824..f57bf5a 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.h
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.h
@@ -44,12 +44,6 @@
   // on |profile|.
   std::vector<std::string> GetInstalledExtensionNames(Profile* profile) const;
 
-  // Enables the extension with the given name on |profile|.
-  void EnableExtension(Profile* profile, const std::string& name);
-
-  // Disables the extension with the given name on |profile|.
-  void DisableExtension(Profile* profile, const std::string& name);
-
   // Returns true if the extension with the given name is enabled on |profile|.
   bool IsExtensionEnabled(Profile* profile, const std::string& name) const;
 
diff --git a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
index 2db4c35..abbc8f4 100644
--- a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
@@ -15,8 +15,6 @@
 
 using apps_helper::AllProfilesHaveSameAppsAsVerifier;
 using apps_helper::CopyNTPOrdinals;
-using apps_helper::DisableApp;
-using apps_helper::EnableApp;
 using apps_helper::FixNTPOrdinalCollisions;
 using apps_helper::GetAppLaunchOrdinalForApp;
 using apps_helper::HasSameAppsAsVerifier;
@@ -242,34 +240,6 @@
   ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
 }
 
-// TCM ID - 7723126.
-IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateEnableDisableApp) {
-  ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
-
-  InstallApp(GetProfile(0), 0);
-  InstallApp(GetProfile(1), 0);
-  InstallApp(verifier(), 0);
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
-
-  DisableApp(GetProfile(0), 0);
-  DisableApp(verifier(), 0);
-  ASSERT_TRUE(HasSameAppsAsVerifier(0));
-  ASSERT_FALSE(HasSameAppsAsVerifier(1));
-
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
-
-  EnableApp(GetProfile(1), 0);
-  EnableApp(verifier(), 0);
-  ASSERT_TRUE(HasSameAppsAsVerifier(1));
-  ASSERT_FALSE(HasSameAppsAsVerifier(0));
-
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
-}
-
 // TCM ID - 7706637.
 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateIncognitoEnableDisable) {
   ASSERT_TRUE(SetupSync());
diff --git a/chrome/browser/sync/test/integration/two_client_extensions_sync_test.cc b/chrome/browser/sync/test/integration/two_client_extensions_sync_test.cc
index 0476fa2..ff4147b 100644
--- a/chrome/browser/sync/test/integration/two_client_extensions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_extensions_sync_test.cc
@@ -8,8 +8,6 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 
 using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier;
-using extensions_helper::DisableExtension;
-using extensions_helper::EnableExtension;
 using extensions_helper::HasSameExtensionsAsVerifier;
 using extensions_helper::IncognitoDisableExtension;
 using extensions_helper::IncognitoEnableExtension;
@@ -181,35 +179,6 @@
   ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier());
 }
 
-// TCM ID - 3605300.
-IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest,
-                       UpdateEnableDisableExtension) {
-  ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier());
-
-  InstallExtension(GetProfile(0), 0);
-  InstallExtension(GetProfile(1), 0);
-  InstallExtension(verifier(), 0);
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier());
-
-  DisableExtension(GetProfile(0), 0);
-  DisableExtension(verifier(), 0);
-  ASSERT_TRUE(HasSameExtensionsAsVerifier(0));
-  ASSERT_FALSE(HasSameExtensionsAsVerifier(1));
-
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier());
-
-  EnableExtension(GetProfile(1), 0);
-  EnableExtension(verifier(), 0);
-  ASSERT_TRUE(HasSameExtensionsAsVerifier(1));
-  ASSERT_FALSE(HasSameExtensionsAsVerifier(0));
-
-  ASSERT_TRUE(AwaitQuiescence());
-  ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier());
-}
-
 // TCM ID - 3728322.
 IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest,
                        UpdateIncognitoEnableDisable) {
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 04ec46d..9d8818d 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -7,35 +7,24 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/sync/glue/data_type_controller.h"
 #include "chrome/browser/sync/glue/sync_backend_host.h"
 #include "chrome/browser/sync/profile_sync_components_factory.h"
 #include "chrome/browser/sync/test/test_http_bridge_factory.h"
-#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
-#include "sync/internal_api/public/test/test_user_share.h"
+#include "sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h"
 #include "sync/internal_api/public/user_share.h"
 #include "sync/js/js_reply_handler.h"
 #include "sync/protocol/encryption.pb.h"
-#include "sync/syncable/directory.h"
 
 using syncer::InternalComponentsFactory;
 using syncer::ModelSafeRoutingInfo;
 using syncer::TestInternalComponentsFactory;
-using syncer::sessions::ModelNeutralState;
-using syncer::sessions::SyncSessionSnapshot;
 using syncer::UserShare;
-using syncer::syncable::Directory;
-using syncer::DEVICE_INFO;
-using syncer::EXPERIMENTS;
-using syncer::NIGORI;
-using syncer::PRIORITY_PREFERENCES;
 
 namespace browser_sync {
 
 SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
     Profile* profile,
     const base::WeakPtr<SyncPrefs>& sync_prefs,
-    syncer::TestIdFactory& id_factory,
     base::Closure& callback,
     bool set_initial_sync_ended_on_init,
     bool synchronous_init,
@@ -43,7 +32,6 @@
     syncer::StorageOption storage_option)
     : browser_sync::SyncBackendHost(
         profile->GetDebugName(), profile, sync_prefs),
-      id_factory_(id_factory),
       callback_(callback),
       fail_initial_download_(fail_initial_download),
       set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
@@ -65,6 +53,10 @@
 void SyncBackendHostForProfileSyncTest::InitCore(
     scoped_ptr<DoInitializeOptions> options) {
   options->http_bridge_factory = MakeTestHttpBridgeFactory();
+  options->sync_manager_factory.reset(
+      new syncer::SyncManagerFactoryForProfileSyncTest(
+          callback_,
+          set_initial_sync_ended_on_init_));
   options->credentials.email = "testuser@gmail.com";
   options->credentials.sync_token = "token";
   options->restored_key_for_bootstrapping = "";
@@ -121,72 +113,29 @@
       ready_task);
 }
 
-void SyncBackendHostForProfileSyncTest
-    ::HandleSyncManagerInitializationOnFrontendLoop(
-    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-        debug_info_listener,
-    syncer::ModelTypeSet restored_types) {
-  // Here's our opportunity to pretend to do things that the SyncManager would
-  // normally do during initialization, but can't because this is a test.
-  // Set up any nodes the test wants around before model association.
-  if (!callback_.is_null()) {
-    callback_.Run();
-  }
-
-  // Pretend we downloaded initial updates and set initial sync ended bits
-  // if we were asked to.
-  if (set_initial_sync_ended_on_init_) {
-    UserShare* user_share = GetUserShare();
-    Directory* directory = user_share->directory.get();
-
-    if (!directory->InitialSyncEndedForType(NIGORI)) {
-      syncer::TestUserShare::CreateRoot(NIGORI, user_share);
-
-      // A side effect of adding the NIGORI node (normally done by the
-      // syncer) is a decryption attempt, which will fail the first time.
-    }
-
-    if (!directory->InitialSyncEndedForType(DEVICE_INFO)) {
-      syncer::TestUserShare::CreateRoot(DEVICE_INFO, user_share);
-    }
-
-    if (!directory->InitialSyncEndedForType(EXPERIMENTS)) {
-      syncer::TestUserShare::CreateRoot(EXPERIMENTS, user_share);
-    }
-
-    if (!directory->InitialSyncEndedForType(PRIORITY_PREFERENCES)) {
-      syncer::TestUserShare::CreateRoot(PRIORITY_PREFERENCES, user_share);
-    }
-
-    restored_types = syncer::ModelTypeSet::All();
-  }
-
-  initial_download_closure_ = base::Bind(
-      &SyncBackendHostForProfileSyncTest::ContinueInitialization,
-      weak_ptr_factory_.GetWeakPtr(),
-      js_backend,
-      debug_info_listener,
-      restored_types);
+void
+SyncBackendHostForProfileSyncTest::HandleInitializationSuccessOnFrontendLoop(
+    const syncer::WeakHandle<syncer::JsBackend> js_backend,
+    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
+    debug_info_listener) {
   if (fail_initial_download_) {
-    frontend()->OnSyncConfigureRetry();
+    // We interrupt this successful init to bring you a simulated failure.
+    initial_download_closure_ = base::Bind(
+        &SyncBackendHostForProfileSyncTest::
+            HandleInitializationSuccessOnFrontendLoop,
+        weak_ptr_factory_.GetWeakPtr(),
+        js_backend,
+        debug_info_listener);
+    HandleControlTypesDownloadRetry();
     if (synchronous_init_)
       base::MessageLoop::current()->Quit();
   } else {
-    initial_download_closure_.Run();
-    initial_download_closure_.Reset();
+    SyncBackendHost::HandleInitializationSuccessOnFrontendLoop(
+        js_backend,
+        debug_info_listener);
   }
 }
 
-void SyncBackendHostForProfileSyncTest::ContinueInitialization(
-    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-        debug_info_listener,
-    syncer::ModelTypeSet restored_types) {
-  SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop(
-      js_backend, debug_info_listener, restored_types);
-}
-
 }  // namespace browser_sync
 
 syncer::TestIdFactory* TestProfileSyncService::id_factory() {
@@ -313,7 +262,6 @@
   backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
       profile(),
       sync_prefs_.AsWeakPtr(),
-      id_factory_,
       callback_,
       set_initial_sync_ended_on_init_,
       synchronous_backend_initialization_,
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index f62d8fd..cb8d3e6 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -44,7 +44,6 @@
   SyncBackendHostForProfileSyncTest(
       Profile* profile,
       const base::WeakPtr<SyncPrefs>& sync_prefs,
-      syncer::TestIdFactory& id_factory,
       base::Closure& callback,
       bool set_initial_sync_ended_on_init,
       bool synchronous_init,
@@ -69,25 +68,16 @@
                                 syncer::ModelTypeSet)>& ready_task,
       const base::Closure& retry_callback) OVERRIDE;
 
-  virtual void HandleSyncManagerInitializationOnFrontendLoop(
-      const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-      const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-          debug_info_listener,
-      syncer::ModelTypeSet restored_types) OVERRIDE;
-
-  static void SetHistoryServiceExpectations(ProfileMock* profile);
+  virtual void HandleInitializationSuccessOnFrontendLoop(
+    const syncer::WeakHandle<syncer::JsBackend> js_backend,
+    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
+        debug_info_listener) OVERRIDE;
 
  protected:
   virtual void InitCore(scoped_ptr<DoInitializeOptions> options) OVERRIDE;
 
  private:
-  void ContinueInitialization(
-      const syncer::WeakHandle<syncer::JsBackend>& js_backend,
-      const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
-          debug_info_listener,
-      syncer::ModelTypeSet restored_types);
 
-  syncer::TestIdFactory& id_factory_;
 
   // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop.
   // Allows extra initialization work to be performed before the backend comes
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
index 8b76a0c..841786b 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
@@ -18,6 +18,7 @@
 const char kFileTrackerKeyPrefix[] = "TRACKER: ";
 
 const int kMaxRetry = 5;
+const int64 kListChangesRetryDelaySeconds = 60 * 60;
 
 }  // namespace drive_backend
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
index de9866d..5ca016b 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
@@ -20,6 +20,7 @@
 extern const char kFileTrackerKeyPrefix[];
 
 extern const int kMaxRetry;
+extern const int64 kListChangesRetryDelaySeconds;
 
 }  // namespace drive_backend
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc b/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc
new file mode 100644
index 0000000..d0b3fe0
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task.cc
@@ -0,0 +1,103 @@
+// Copyright 2013 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/sync_file_system/drive_backend/list_changes_task.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "chrome/browser/drive/drive_api_util.h"
+#include "chrome/browser/drive/drive_service_interface.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
+#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
+#include "chrome/browser/sync_file_system/logger.h"
+#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+scoped_ptr<google_apis::ChangeResource> ConvertResourceEntryToChangeResource(
+    const google_apis::ResourceEntry& entry) {
+  scoped_ptr<google_apis::ChangeResource> out(new google_apis::ChangeResource);
+  out->set_file_id(entry.resource_id());
+  if (!entry.deleted())
+    out->set_file(drive::util::ConvertResourceEntryToFileResource(entry));
+  out->set_change_id(entry.changestamp());
+  out->set_deleted(entry.deleted());
+
+  return out.Pass();
+}
+
+}  // namespace
+
+ListChangesTask::ListChangesTask(SyncEngineContext* sync_context)
+    : sync_context_(sync_context),
+      weak_ptr_factory_(this) {
+}
+
+ListChangesTask::~ListChangesTask() {
+}
+
+void ListChangesTask::Run(const SyncStatusCallback& callback) {
+  if (!metadata_database() || !drive_service()) {
+    util::Log(logging::LOG_ERROR, FROM_HERE, "Failed to get required sercive.");
+    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_FAILED));
+    return;
+  }
+
+  drive_service()->GetChangeList(
+      metadata_database()->GetLargestChangeID() + 1,
+      base::Bind(&ListChangesTask::DidListChanges,
+                 weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ListChangesTask::DidListChanges(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceList> resource_list) {
+  if (error != google_apis::HTTP_SUCCESS) {
+    util::Log(logging::LOG_ERROR, FROM_HERE, "Failed to fetch change list.");
+    callback.Run(SYNC_STATUS_NETWORK_ERROR);
+    return;
+  }
+
+  change_list_.reserve(change_list_.size() + resource_list->entries().size());
+  for (size_t i = 0; i < resource_list->entries().size(); ++i) {
+    change_list_.push_back(ConvertResourceEntryToChangeResource(
+        *resource_list->entries()[i]).release());
+  }
+
+  // TODO(tzik): http://crbug.com/310964
+  // This may take long time to run in single task.  Run this as a background
+  // task.
+  GURL next_feed;
+  if (resource_list->GetNextFeedURL(&next_feed)) {
+    drive_service()->GetRemainingChangeList(
+        next_feed,
+        base::Bind(
+            &ListChangesTask::DidListChanges,
+            weak_ptr_factory_.GetWeakPtr(),
+            callback));
+    return;
+  }
+
+  metadata_database()->UpdateByChangeList(
+      resource_list->largest_changestamp(),
+      change_list_.Pass(), callback);
+}
+
+MetadataDatabase* ListChangesTask::metadata_database() {
+  return sync_context_->GetMetadataDatabase();
+}
+
+drive::DriveServiceInterface* ListChangesTask::drive_service() {
+  return sync_context_->GetDriveService();
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task.h b/chrome/browser/sync_file_system/drive_backend/list_changes_task.h
new file mode 100644
index 0000000..beb4cd8
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task.h
@@ -0,0 +1,56 @@
+// Copyright 2013 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_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LIST_CHANGES_TASK_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LIST_CHANGES_TASK_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "chrome/browser/sync_file_system/sync_callbacks.h"
+#include "chrome/browser/sync_file_system/sync_task.h"
+
+namespace drive {
+class DriveServiceInterface;
+}
+
+namespace google_apis {
+class ChangeResource;
+class ResourceList;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class MetadataDatabase;
+class SyncEngineContext;
+
+class ListChangesTask : public SyncTask {
+ public:
+  explicit ListChangesTask(SyncEngineContext* sync_context);
+  virtual ~ListChangesTask();
+
+  virtual void Run(const SyncStatusCallback& callback) OVERRIDE;
+
+ private:
+  void DidListChanges(const SyncStatusCallback& callback,
+                      google_apis::GDataErrorCode error,
+                      scoped_ptr<google_apis::ResourceList> resource_list);
+
+  MetadataDatabase* metadata_database();
+  drive::DriveServiceInterface* drive_service();
+
+  SyncEngineContext* sync_context_;
+  ScopedVector<google_apis::ChangeResource> change_list_;
+
+  base::WeakPtrFactory<ListChangesTask> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListChangesTask);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LIST_CHANGES_TASK_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc
new file mode 100644
index 0000000..fb7b6cc
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc
@@ -0,0 +1,232 @@
+// Copyright 2013 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/sync_file_system/drive_backend/list_changes_task.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
+#include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
+#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
+#include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
+#include "chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h"
+#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+const char kAppID[] = "app_id";
+const char kUnregisteredAppID[] = "app_id unregistered";
+
+}  // namespace
+
+class ListChangesTaskTest : public testing::Test,
+                            public SyncEngineContext {
+ public:
+  ListChangesTaskTest() {}
+  virtual ~ListChangesTaskTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
+
+    fake_drive_service_.reset(new drive::FakeDriveService);
+    ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
+        "sync_file_system/account_metadata.json"));
+    ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
+        "gdata/empty_feed.json"));
+
+    drive_uploader_.reset(new drive::DriveUploader(
+        fake_drive_service_.get(), base::MessageLoopProxy::current()));
+
+    fake_drive_service_helper_.reset(new FakeDriveServiceHelper(
+        fake_drive_service_.get(), drive_uploader_.get()));
+
+    SetUpRemoteFolders();
+    InitializeMetadataDatabase();
+    RegisterApp(kAppID);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    metadata_database_.reset();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
+    return fake_drive_service_.get();
+  }
+
+  virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
+    return metadata_database_.get();
+  }
+
+  int64 GetRemoteLargestChangeID() {
+    scoped_ptr<google_apis::AboutResource> about_resource;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper_->GetAboutResource(&about_resource));
+    return about_resource->largest_change_id();
+  }
+
+ protected:
+  SyncStatusCode RunTask(SyncTask* sync_task) {
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    sync_task->Run(CreateResultReceiver(&status));
+    base::RunLoop().RunUntilIdle();
+    return status;
+  }
+
+  size_t CountDirtyTracker() {
+    return metadata_database_->dirty_trackers_.size();
+  }
+
+  FakeDriveServiceHelper* fake_drive_service_helper() {
+    return fake_drive_service_helper_.get();
+  }
+
+  drive::FakeDriveService* fake_drive_service() {
+    return fake_drive_service_.get();
+  }
+
+  void SetUpChangesInFolder(const std::string& folder_id) {
+    std::string new_file_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->AddFile(
+                  folder_id, "new file", "file contents", &new_file_id));
+    std::string same_name_file_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->AddFile(
+                  folder_id, "new file", "file contents",
+                  &same_name_file_id));
+
+    std::string new_folder_id;
+    ASSERT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_service_helper()->AddFolder(
+                  folder_id, "new folder", &new_folder_id));
+
+    std::string modified_file_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->AddFile(
+                  folder_id, "modified file", "file content",
+                  &modified_file_id));
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->UpdateFile(
+                  modified_file_id, "modified file content"));
+
+
+    std::string trashed_file_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->AddFile(
+                  folder_id, "trashed file", "file content",
+                  &trashed_file_id));
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_service_helper()->RemoveResource(trashed_file_id));
+  }
+
+  std::string root_resource_id() {
+    return fake_drive_service_->GetRootResourceId();
+  }
+
+  std::string sync_root_folder_id() {
+    return sync_root_folder_id_;
+  }
+
+  std::string app_root_folder_id() {
+    return app_root_folder_id_;
+  }
+
+  std::string unregistered_app_root_folder_id() {
+    return unregistered_app_root_folder_id_;
+  }
+
+ private:
+  void SetUpRemoteFolders() {
+    ASSERT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_service_helper_->AddOrphanedFolder(
+                  kSyncRootFolderTitle, &sync_root_folder_id_));
+    ASSERT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_service_helper_->AddFolder(
+                  sync_root_folder_id_, kAppID, &app_root_folder_id_));
+    ASSERT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_service_helper_->AddFolder(
+                  sync_root_folder_id_, kUnregisteredAppID,
+                  &unregistered_app_root_folder_id_));
+  }
+
+  void InitializeMetadataDatabase() {
+    SyncEngineInitializer initializer(base::MessageLoopProxy::current(),
+                                      fake_drive_service_.get(),
+                                      database_dir_.path());
+    EXPECT_EQ(SYNC_STATUS_OK, RunTask(&initializer));
+    metadata_database_ = initializer.PassMetadataDatabase();
+  }
+
+  void RegisterApp(const std::string& app_id) {
+    RegisterAppTask register_app(this, app_id);
+    EXPECT_EQ(SYNC_STATUS_OK, RunTask(&register_app));
+  }
+
+  std::string GenerateFileID() {
+    return base::StringPrintf("file_id_%" PRId64, next_file_id_++);
+  }
+
+  std::string sync_root_folder_id_;
+  std::string app_root_folder_id_;
+  std::string unregistered_app_root_folder_id_;
+
+  int64 next_file_id_;
+  int64 next_tracker_id_;
+
+  content::TestBrowserThreadBundle browser_threads_;
+  base::ScopedTempDir database_dir_;
+
+  scoped_ptr<drive::FakeDriveService> fake_drive_service_;
+  scoped_ptr<drive::DriveUploader> drive_uploader_;
+  scoped_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
+
+  scoped_ptr<MetadataDatabase> metadata_database_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListChangesTaskTest);
+};
+
+TEST_F(ListChangesTaskTest, NoChange) {
+  size_t num_dirty_trackers = CountDirtyTracker();
+
+  ListChangesTask list_changes(this);
+  EXPECT_EQ(SYNC_STATUS_OK, RunTask(&list_changes));
+
+  EXPECT_EQ(num_dirty_trackers, CountDirtyTracker());
+}
+
+TEST_F(ListChangesTaskTest, UnrelatedChange) {
+  size_t num_dirty_trackers = CountDirtyTracker();
+
+  SetUpChangesInFolder(root_resource_id());
+  SetUpChangesInFolder(unregistered_app_root_folder_id());
+
+  ListChangesTask list_changes(this);
+  EXPECT_EQ(SYNC_STATUS_OK, RunTask(&list_changes));
+
+  EXPECT_EQ(num_dirty_trackers, CountDirtyTracker());
+}
+
+TEST_F(ListChangesTaskTest, UnderTrackedFolder) {
+  size_t num_dirty_trackers = CountDirtyTracker();
+
+  SetUpChangesInFolder(app_root_folder_id());
+
+  ListChangesTask list_changes(this);
+  EXPECT_EQ(SYNC_STATUS_OK, RunTask(&list_changes));
+
+  EXPECT_EQ(num_dirty_trackers + 4, CountDirtyTracker());
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index 964b651..737ded8 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -735,8 +735,11 @@
 }
 
 void MetadataDatabase::UpdateByChangeList(
+    int64 largest_change_id,
     ScopedVector<google_apis::ChangeResource> changes,
     const SyncStatusCallback& callback) {
+  DCHECK_LE(service_metadata_->largest_change_id(), largest_change_id);
+
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
 
   for (ScopedVector<google_apis::ChangeResource>::const_iterator itr =
@@ -762,6 +765,8 @@
     }
   }
 
+  service_metadata_->set_largest_change_id(largest_change_id);
+  PutServiceMetadataToBatch(*service_metadata_, batch.get());
   WriteToDatabase(batch.Pass(), callback);
 }
 
@@ -926,6 +931,16 @@
   return status;
 }
 
+SyncStatusCode MetadataDatabase::SetLargestChangeIDForTesting(
+    int64 largest_change_id) {
+  service_metadata_->set_largest_change_id(largest_change_id);
+
+  leveldb::WriteBatch batch;
+  PutServiceMetadataToBatch(*service_metadata_, &batch);
+  return LevelDBStatusToSyncStatusCode(
+      db_->Write(leveldb::WriteOptions(), &batch));
+}
+
 SyncStatusCode MetadataDatabase::InitializeOnTaskRunner(
     const base::FilePath& database_path) {
   base::ThreadRestrictions::AssertIOAllowed();
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
index 82b7e70..dced976 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -201,7 +201,8 @@
   // Updates database by |changes|.
   // Marks each tracker for modified file as dirty and adds new trackers if
   // needed.
-  void UpdateByChangeList(ScopedVector<google_apis::ChangeResource> changes,
+  void UpdateByChangeList(int64 largest_change_id,
+                          ScopedVector<google_apis::ChangeResource> changes,
                           const SyncStatusCallback& callback);
 
   // Updates database by |resource|.
@@ -224,6 +225,8 @@
                      const SyncStatusCallback& callback);
 
  private:
+  friend class ListChangesTaskTest;
+  friend class MetadataDatabaseTest;
   friend class RegisterAppTaskTest;
   friend class SyncEngineInitializerTest;
 
@@ -234,8 +237,6 @@
 
   typedef std::set<FileTracker*, DirtyTrackerComparator> DirtyTrackers;
 
-  friend class MetadataDatabaseTest;
-
   explicit MetadataDatabase(base::SequencedTaskRunner* task_runner);
   static void CreateOnTaskRunner(base::SingleThreadTaskRunner* callback_runner,
                                  base::SequencedTaskRunner* task_runner,
@@ -247,6 +248,8 @@
   SyncStatusCode InitializeOnTaskRunner(const base::FilePath& database_path);
   void BuildIndexes(DatabaseContents* contents);
 
+  SyncStatusCode SetLargestChangeIDForTesting(int64 largest_changestamp);
+
   // Database manipulation methods.
   void RegisterTrackerAsAppRoot(const std::string& app_id,
                                 int64 tracker_id,
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 429ad7c..265f2a0 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -538,6 +538,7 @@
       ScopedVector<google_apis::ChangeResource> changes) {
     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
     metadata_database_->UpdateByChangeList(
+        current_change_id_,
         changes.Pass(), CreateResultReceiver(&status));
     message_loop_.RunUntilIdle();
     return status;
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
index fc19be3..d45dce3 100644
--- a/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
@@ -194,7 +194,7 @@
 void RegisterAppTask::RegisterAppIntoDatabase(
     const FileTracker& tracker,
     const SyncStatusCallback& callback) {
-  sync_context_->GetMetadataDatabase()->RegisterApp(
+  metadata_database()->RegisterApp(
       app_id_, tracker.file_id(), callback);
 }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
index fa7cf92..c857e96 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
@@ -7,13 +7,16 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/drive/drive_api_service.h"
+#include "chrome/browser/drive/drive_notification_manager.h"
 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
+#include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
 #include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h"
+#include "chrome/browser/sync_file_system/logger.h"
 #include "chrome/browser/sync_file_system/sync_task.h"
 
 namespace sync_file_system {
@@ -30,11 +33,19 @@
       drive_service_(drive_service.Pass()),
       notification_manager_(notification_manager),
       extension_service_(extension_service),
+      remote_change_processor_(NULL),
+      service_state_(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE),
+      should_check_remote_change_(true),
+      sync_enabled_(false),
+      conflict_resolution_policy_(CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN),
+      network_available_(false),
       weak_ptr_factory_(this) {
 }
 
 SyncEngine::~SyncEngine() {
-  NOTIMPLEMENTED();
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  drive_service_->RemoveObserver(this);
+  notification_manager_->RemoveObserver(this);
 }
 
 void SyncEngine::Initialize() {
@@ -50,6 +61,15 @@
       scoped_ptr<SyncTask>(initializer),
       base::Bind(&SyncEngine::DidInitialize, weak_ptr_factory_.GetWeakPtr(),
                  initializer));
+
+  notification_manager_->AddObserver(this);
+  drive_service_->AddObserver(this);
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+
+  net::NetworkChangeNotifier::ConnectionType type =
+      net::NetworkChangeNotifier::GetConnectionType();
+  network_available_ =
+      type != net::NetworkChangeNotifier::CONNECTION_NONE;
 }
 
 void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) {
@@ -122,8 +142,7 @@
 }
 
 RemoteServiceState SyncEngine::GetCurrentState() const {
-  NOTIMPLEMENTED();
-  return REMOTE_SERVICE_OK;
+  return service_state_;
 }
 
 void SyncEngine::GetOriginStatusMap(OriginStatusMap* status_map) {
@@ -138,19 +157,29 @@
 }
 
 void SyncEngine::SetSyncEnabled(bool enabled) {
-  NOTIMPLEMENTED();
+  if (sync_enabled_ == enabled)
+    return;
+
+  RemoteServiceState old_state = GetCurrentState();
+  sync_enabled_ = enabled;
+  if (old_state == GetCurrentState())
+    return;
+
+  const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled";
+  FOR_EACH_OBSERVER(
+      Observer, service_observers_,
+      OnRemoteServiceStateUpdated(GetCurrentState(), status_message));
 }
 
 SyncStatusCode SyncEngine::SetConflictResolutionPolicy(
     ConflictResolutionPolicy policy) {
-  NOTIMPLEMENTED();
+  conflict_resolution_policy_ = policy;
   return SYNC_STATUS_OK;
 }
 
 ConflictResolutionPolicy
 SyncEngine::GetConflictResolutionPolicy() const {
-  NOTIMPLEMENTED();
-  return CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
+  return conflict_resolution_policy_;
 }
 
 void SyncEngine::GetRemoteVersions(
@@ -181,7 +210,14 @@
 }
 
 void SyncEngine::MaybeScheduleNextTask() {
-  NOTIMPLEMENTED();
+  if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
+    return;
+
+  // TODO(tzik): Notify observer of OnRemoteChangeQueueUpdated.
+  // TODO(tzik): Add an interface to get the number of dirty trackers to
+  // MetadataDatabase.
+
+  MaybeStartFetchChanges();
 }
 
 void SyncEngine::NotifyLastOperationStatus(SyncStatusCode sync_status) {
@@ -189,11 +225,40 @@
 }
 
 void SyncEngine::OnNotificationReceived() {
-  NOTIMPLEMENTED();
+  should_check_remote_change_ = true;
+  MaybeScheduleNextTask();
 }
 
-void SyncEngine::OnPushNotificationEnabled(bool enabled) {
-  NOTIMPLEMENTED();
+void SyncEngine::OnPushNotificationEnabled(bool enabled) {}
+
+void SyncEngine::OnReadyToSendRequests() {
+  if (service_state_ == REMOTE_SERVICE_OK)
+    return;
+
+  UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated");
+  should_check_remote_change_ = true;
+  MaybeScheduleNextTask();
+}
+
+void SyncEngine::OnRefreshTokenInvalid() {
+  UpdateServiceStateFromSyncStatusCode(
+      SYNC_STATUS_AUTHENTICATION_FAILED,
+      "Found invalid refresh token.");
+}
+
+void SyncEngine::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  bool new_network_availability =
+      type != net::NetworkChangeNotifier::CONNECTION_NONE;
+
+  if (network_available_ && !new_network_availability) {
+    UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, "Disconnected");
+  } else if (!network_available_ && new_network_availability) {
+    UpdateServiceState(REMOTE_SERVICE_OK, "Connected");
+    should_check_remote_change_ = true;
+    MaybeStartFetchChanges();
+  }
+  network_available_ = new_network_availability;
 }
 
 drive::DriveServiceInterface* SyncEngine::GetDriveService() {
@@ -231,5 +296,44 @@
   NOTIMPLEMENTED();
 }
 
+void SyncEngine::MaybeStartFetchChanges() {
+  if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
+    return;
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  if (!should_check_remote_change_ && now < time_to_check_changes_)
+    return;
+
+  if (task_manager_->ScheduleSyncTaskIfIdle(
+          scoped_ptr<SyncTask>(new ListChangesTask(this)))) {
+    should_check_remote_change_ = false;
+    time_to_check_changes_ =
+        now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds);
+  }
+}
+
+void SyncEngine::UpdateServiceStateFromSyncStatusCode(
+    SyncStatusCode status,
+    const std::string& description) {
+  // TODO(tzik): Map |status| to RemoteServiceState and update |service_state_|.
+  NOTIMPLEMENTED();
+}
+
+void SyncEngine::UpdateServiceState(RemoteServiceState state,
+                                    const std::string& description) {
+  RemoteServiceState old_state = GetCurrentState();
+  service_state_ = state;
+
+  if (old_state == GetCurrentState())
+    return;
+
+  util::Log(logging::LOG_INFO, FROM_HERE,
+            "Service state changed: %d->%d: %s",
+            old_state, GetCurrentState(), description.c_str());
+  FOR_EACH_OBSERVER(
+      Observer, service_observers_,
+      OnRemoteServiceStateUpdated(GetCurrentState(), description));
+}
+
 }  // namespace drive_backend
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.h b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
index f65b46a..dfdd67a 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
@@ -9,10 +9,12 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/drive/drive_notification_observer.h"
+#include "chrome/browser/drive/drive_service_interface.h"
 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
 #include "chrome/browser/sync_file_system/local_change_processor.h"
 #include "chrome/browser/sync_file_system/remote_file_sync_service.h"
 #include "chrome/browser/sync_file_system/sync_task_manager.h"
+#include "net/base/network_change_notifier.h"
 
 class ExtensionService;
 
@@ -37,6 +39,8 @@
                    public LocalChangeProcessor,
                    public SyncTaskManager::Client,
                    public drive::DriveNotificationObserver,
+                   public drive::DriveServiceObserver,
+                   public net::NetworkChangeNotifier::NetworkChangeObserver,
                    public SyncEngineContext {
  public:
   typedef Observer SyncServiceObserver;
@@ -102,6 +106,14 @@
   virtual void OnNotificationReceived() OVERRIDE;
   virtual void OnPushNotificationEnabled(bool enabled) OVERRIDE;
 
+  // drive::DriveServiceObserver overrides.
+  virtual void OnReadyToSendRequests() OVERRIDE;
+  virtual void OnRefreshTokenInvalid() OVERRIDE;
+
+  // net::NetworkChangeNotifier::NetworkChangeObserver overrides.
+  virtual void OnNetworkChanged(
+      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
+
   // SyncEngineContext overrides.
   virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE;
   virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE;
@@ -120,6 +132,14 @@
   void DidApplyLocalChange(LocalToRemoteSyncer* syncer,
                            const SyncStatusCallback& callback,
                            SyncStatusCode status);
+  void DidFetchChangeList(SyncStatusCallback& callback);
+
+  void MaybeStartFetchChanges();
+  void UpdateServiceStateFromSyncStatusCode(
+      SyncStatusCode state,
+      const std::string& description);
+  void UpdateServiceState(RemoteServiceState state,
+                          const std::string& description);
 
   base::FilePath base_dir_;
   base::FilePath temporary_file_dir_;
@@ -140,6 +160,15 @@
   ObserverList<FileStatusObserver> file_status_observers_;
   RemoteChangeProcessor* remote_change_processor_;
 
+  RemoteServiceState service_state_;
+
+  bool should_check_remote_change_;
+  base::TimeTicks time_to_check_changes_;
+
+  bool sync_enabled_;
+  ConflictResolutionPolicy conflict_resolution_policy_;
+  bool network_available_;
+
   scoped_ptr<SyncTaskManager> task_manager_;
 
   base::WeakPtrFactory<SyncEngine> weak_ptr_factory_;
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/api_util.cc b/chrome/browser/sync_file_system/drive_backend_v1/api_util.cc
index 7086db9..4c5525e 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/api_util.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/api_util.cc
@@ -742,7 +742,7 @@
     DVLOG(2) << "Error in creating a temp file under "
              << temp_dir_path_.value();
     callback.Run(google_apis::GDATA_FILE_ERROR, std::string(), 0, base::Time(),
-                 local_file.Pass());
+                 local_file->Pass());
     return;
   }
   drive_service_->GetResourceEntry(
@@ -766,8 +766,7 @@
 
   if (error != google_apis::HTTP_SUCCESS) {
     DVLOG(2) << "Error on getting resource entry for download";
-    callback.Run(error, std::string(), 0, base::Time(),
-                 local_file.Pass());
+    callback.Run(error, std::string(), 0, base::Time(), local_file->Pass());
     return;
   }
   DCHECK(entry);
@@ -779,7 +778,7 @@
                  local_file_md5,
                  entry->file_size(),
                  entry->updated_time(),
-                 local_file.Pass());
+                 local_file->Pass());
     return;
   }
 
@@ -810,7 +809,7 @@
 
   callback.Run(
       error, entry->file_md5(), entry->file_size(), entry->updated_time(),
-      local_file.Pass());
+      local_file->Pass());
 }
 
 void APIUtil::DidUploadNewFile(const std::string& parent_resource_id,
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/api_util_interface.h b/chrome/browser/sync_file_system/drive_backend_v1/api_util_interface.h
index fe17529..4b9e96f 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/api_util_interface.h
+++ b/chrome/browser/sync_file_system/drive_backend_v1/api_util_interface.h
@@ -51,7 +51,7 @@
                               const std::string& file_md5,
                               int64 file_size,
                               const base::Time& last_updated,
-                              scoped_ptr<webkit_blob::ScopedFile> downloaded)>
+                              webkit_blob::ScopedFile downloaded)>
       DownloadFileCallback;
   typedef base::Callback<void(google_apis::GDataErrorCode error,
                               const std::string& resource_id,
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/api_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend_v1/api_util_unittest.cc
index 34e2dc3..29f20b1 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/api_util_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/api_util_unittest.cc
@@ -365,9 +365,9 @@
                      const std::string& file_md5,
                      int64 file_size,
                      const base::Time& updated_time,
-                     scoped_ptr<webkit_blob::ScopedFile> file) {
+                     webkit_blob::ScopedFile file) {
   ASSERT_TRUE(output);
-  ASSERT_TRUE(base::PathExists(file->path()));
+  ASSERT_TRUE(base::PathExists(file.path()));
   output->error = error;
   output->file_md5 = file_md5;
 }
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.cc b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.cc
index 28d3b40..4060e9e 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.cc
@@ -64,7 +64,7 @@
     const DriveFileSyncService::DownloadVersionCallback& download_callback,
     const SyncStatusCallback& completion_callback,
     SyncStatusCode status,
-    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+    webkit_blob::ScopedFile downloaded) {
   completion_callback.Run(status);
   download_callback.Run(status, downloaded.Pass());
 }
@@ -707,8 +707,7 @@
   DriveMetadata metadata;
   if (metadata_store_->ReadEntry(url, &metadata) != SYNC_STATUS_OK) {
     // The conflict may have been already resolved.
-    callback.Run(SYNC_FILE_ERROR_NOT_FOUND,
-                 scoped_ptr<webkit_blob::ScopedFile>());
+    callback.Run(SYNC_FILE_ERROR_NOT_FOUND, webkit_blob::ScopedFile());
     return;
   }
 
@@ -724,7 +723,7 @@
     const std::string& file_md5,
     int64 file_size,
     const base::Time& last_updated,
-    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+    webkit_blob::ScopedFile downloaded) {
   SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
   download_callback.Run(status, downloaded.Pass());
 }
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h
index d7c0de6..f561482 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h
+++ b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h
@@ -229,7 +229,7 @@
       const std::string& file_md5,
       int64 file_size,
       const base::Time& last_updated,
-      scoped_ptr<webkit_blob::ScopedFile> downloaded);
+      webkit_blob::ScopedFile downloaded);
 
   void UpdateRegisteredOrigins();
 
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
index 912bbb9..984c193 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
@@ -101,9 +101,9 @@
     SyncStatusCode* status_out,
     webkit_blob::ScopedFile* downloaded_out,
     SyncStatusCode status,
-    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+    webkit_blob::ScopedFile downloaded) {
   *status_out = status;
-  *downloaded_out = downloaded->Pass();
+  *downloaded_out = downloaded.Pass();
 }
 
 void ExpectEqStatus(bool* done,
@@ -297,7 +297,7 @@
     // Call UnloadExtension instead of UninstallExtension since it does
     // unnecessary cleanup (e.g. deleting extension data) and emits warnings.
     extension_service_->UnloadExtension(
-        extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
+        extension_id, extensions::UnloadedExtensionInfo::REASON_UNINSTALL);
   }
 
   void UpdateRegisteredOrigins() {
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util.cc b/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util.cc
index e846961..a7f074f 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util.cc
@@ -163,12 +163,11 @@
     error = google_apis::HTTP_SUCCESS;
   }
 
-  scoped_ptr<webkit_blob::ScopedFile> dummy_local_file(
-      new webkit_blob::ScopedFile);
+  webkit_blob::ScopedFile dummy;
   base::MessageLoopProxy::current()->PostTask(
       FROM_HERE,
       base::Bind(callback, error, file_md5, file_size, updated_time,
-                 base::Passed(&dummy_local_file)));
+                 base::Passed(&dummy)));
 }
 
 void FakeAPIUtil::UploadNewFile(const std::string& directory_resource_id,
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util_unittest.cc
index d110198..af8409f 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/fake_api_util_unittest.cc
@@ -24,7 +24,7 @@
                      const std::string& file_md5,
                      int64 file_size,
                      const base::Time& updated_time,
-                     scoped_ptr<webkit_blob::ScopedFile> downloaded_file) {
+                     webkit_blob::ScopedFile downloaded_file) {
   *error_out = error;
   *file_md5_out = file_md5;
 }
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.cc b/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.cc
index 4fec52c..13f1af2 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.cc
@@ -207,7 +207,7 @@
     const std::string& md5_checksum,
     int64 file_size,
     const base::Time& updated_time,
-    scoped_ptr<webkit_blob::ScopedFile> downloaded_file) {
+    webkit_blob::ScopedFile downloaded_file) {
   if (error == google_apis::HTTP_NOT_MODIFIED) {
     sync_action_ = SYNC_ACTION_NONE;
     DidApplyRemoteChange(callback, SYNC_STATUS_OK);
@@ -228,7 +228,7 @@
     return;
   }
 
-  temporary_file_ = downloaded_file->Pass();
+  temporary_file_ = downloaded_file.Pass();
   drive_metadata_.set_md5_checksum(md5_checksum);
   remote_change_processor()->ApplyRemoteChange(
       remote_file_change(), temporary_file_.path(), url(),
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.h b/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.h
index 24b6297..51f4e3b 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.h
+++ b/chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.h
@@ -61,7 +61,7 @@
                        const std::string& md5_checksum,
                        int64 file_size,
                        const base::Time& updated_time,
-                       scoped_ptr<webkit_blob::ScopedFile> downloaded_file);
+                       webkit_blob::ScopedFile downloaded_file);
   void HandleConflict(const SyncStatusCallback& callback,
                       SyncFileType remote_file_type);
   void HandleLocalWin(const SyncStatusCallback& callback);
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context.cc b/chrome/browser/sync_file_system/local/local_file_sync_context.cc
index 58adc02..6f56f39 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context.cc
@@ -667,13 +667,13 @@
 
   if (shutdown_on_ui_) {
     callback.Run(SYNC_STATUS_ABORT, LocalFileSyncInfo(),
-                 scoped_ptr<webkit_blob::ScopedFile>());
+                 webkit_blob::ScopedFile());
     return;
   }
 
   if (urls->empty()) {
     callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC, LocalFileSyncInfo(),
-                 scoped_ptr<webkit_blob::ScopedFile>());
+                 webkit_blob::ScopedFile());
     return;
   }
 
@@ -695,7 +695,7 @@
     const LocalFileSyncInfoCallback& callback,
     SyncStatusCode status,
     const LocalFileSyncInfo& sync_file_info,
-    scoped_ptr<webkit_blob::ScopedFile> snapshot) {
+    webkit_blob::ScopedFile snapshot) {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   if (status != SYNC_STATUS_FILE_BUSY) {
     callback.Run(status, sync_file_info, snapshot.Pass());
@@ -718,7 +718,7 @@
     DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
     if (shutdown_on_ui_) {
       callback.Run(SYNC_STATUS_ABORT, LocalFileSyncInfo(),
-                   scoped_ptr<webkit_blob::ScopedFile>());
+                   webkit_blob::ScopedFile());
       return;
     }
     file_system_context->default_file_task_runner()->PostTask(
@@ -749,17 +749,17 @@
       &file_info,
       &platform_path);
 
-  scoped_ptr<webkit_blob::ScopedFile> snapshot;
+  webkit_blob::ScopedFile snapshot;
   if (file_error == base::PLATFORM_FILE_OK && sync_mode == SYNC_SNAPSHOT) {
     base::FilePath snapshot_path;
     file_util::CreateTemporaryFileInDir(local_base_path_.Append(kSnapshotDir),
                                         &snapshot_path);
     if (base::CopyFile(platform_path, snapshot_path)) {
       platform_path = snapshot_path;
-      snapshot.reset(new webkit_blob::ScopedFile(
+      snapshot = webkit_blob::ScopedFile(
           snapshot_path,
           webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT,
-          file_system_context->default_file_task_runner()));
+          file_system_context->default_file_task_runner());
     }
   }
 
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context.h b/chrome/browser/sync_file_system/local/local_file_sync_context.h
index 91fc333..da575a3 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context.h
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context.h
@@ -62,7 +62,7 @@
   typedef base::Callback<void(
       SyncStatusCode status,
       const LocalFileSyncInfo& sync_file_info,
-      scoped_ptr<webkit_blob::ScopedFile> snapshot)>
+      webkit_blob::ScopedFile snapshot)>
           LocalFileSyncInfoCallback;
 
   typedef base::Callback<void(SyncStatusCode status,
@@ -256,7 +256,7 @@
       const LocalFileSyncInfoCallback& callback,
       SyncStatusCode status,
       const LocalFileSyncInfo& sync_file_info,
-      scoped_ptr<webkit_blob::ScopedFile> snapshot);
+      webkit_blob::ScopedFile snapshot);
 
   // Callback routine for PrepareForSync and GetFileForLocalSync.
   void DidGetWritingStatusForSync(
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
index c68cb51..8f73d01 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
@@ -122,14 +122,14 @@
                          webkit_blob::ScopedFile* snapshot_out,
                          SyncStatusCode status,
                          const LocalFileSyncInfo& sync_file_info,
-                         scoped_ptr<webkit_blob::ScopedFile> snapshot) {
+                         webkit_blob::ScopedFile snapshot) {
     ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
     has_inflight_prepare_for_sync_ = false;
     status_ = status;
     *metadata_out = sync_file_info.metadata;
     *changes_out = sync_file_info.changes;
-    if (snapshot_out && snapshot)
-      *snapshot_out = snapshot->Pass();
+    if (snapshot_out)
+      *snapshot_out = snapshot.Pass();
     base::MessageLoop::current()->Quit();
   }
 
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service.cc b/chrome/browser/sync_file_system/local/local_file_sync_service.cc
index d282332..775f28b 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_service.cc
@@ -35,7 +35,7 @@
     const RemoteChangeProcessor::PrepareChangeCallback& callback,
     SyncStatusCode status,
     const LocalFileSyncInfo& sync_file_info,
-    scoped_ptr<webkit_blob::ScopedFile> snapshot) {
+    webkit_blob::ScopedFile snapshot) {
   callback.Run(status, sync_file_info.metadata, sync_file_info.changes);
 }
 
@@ -362,7 +362,7 @@
 void LocalFileSyncService::DidGetFileForLocalSync(
     SyncStatusCode status,
     const LocalFileSyncInfo& sync_file_info,
-    scoped_ptr<webkit_blob::ScopedFile> snapshot) {
+    webkit_blob::ScopedFile snapshot) {
   DCHECK(!local_sync_callback_.is_null());
   if (status != SYNC_STATUS_OK) {
     RunLocalSyncCallback(status, sync_file_info.url);
@@ -391,7 +391,7 @@
 }
 
 void LocalFileSyncService::ProcessNextChangeForURL(
-    scoped_ptr<webkit_blob::ScopedFile> snapshot,
+    webkit_blob::ScopedFile snapshot,
     const LocalFileSyncInfo& sync_file_info,
     const FileChange& processed_change,
     const FileChangeList& changes,
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service.h b/chrome/browser/sync_file_system/local/local_file_sync_service.h
index e865e9f..2f2513f 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_service.h
+++ b/chrome/browser/sync_file_system/local/local_file_sync_service.h
@@ -183,9 +183,9 @@
   void DidGetFileForLocalSync(
       SyncStatusCode status,
       const LocalFileSyncInfo& sync_file_info,
-      scoped_ptr<webkit_blob::ScopedFile> snapshot);
+      webkit_blob::ScopedFile snapshot);
   void ProcessNextChangeForURL(
-      scoped_ptr<webkit_blob::ScopedFile> snapshot,
+      webkit_blob::ScopedFile snapshot,
       const LocalFileSyncInfo& sync_file_info,
       const FileChange& last_change,
       const FileChangeList& changes,
diff --git a/chrome/browser/sync_file_system/remote_file_sync_service.h b/chrome/browser/sync_file_system/remote_file_sync_service.h
index 9376c1b..7234d58 100644
--- a/chrome/browser/sync_file_system/remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/remote_file_sync_service.h
@@ -104,7 +104,7 @@
                               const std::vector<Version>& versions)>
       RemoteVersionsCallback;
   typedef base::Callback<void(SyncStatusCode status,
-                              scoped_ptr<webkit_blob::ScopedFile> downloaded)>
+                              webkit_blob::ScopedFile downloaded)>
       DownloadVersionCallback;
 
   RemoteFileSyncService() {}
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.cc b/chrome/browser/sync_file_system/sync_file_system_service.cc
index fef33f5..f4239fd 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service.cc
@@ -659,7 +659,7 @@
     int type,
     const content::NotificationDetails& details) {
   content::Details<const extensions::UnloadedExtensionInfo> info(details);
-  if (info->reason != extension_misc::UNLOAD_REASON_DISABLE)
+  if (info->reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
     return;
 
   std::string extension_id = info->extension->id();
diff --git a/chrome/browser/sync_file_system/sync_task_manager.cc b/chrome/browser/sync_file_system/sync_task_manager.cc
index 954f277..581106b 100644
--- a/chrome/browser/sync_file_system/sync_task_manager.cc
+++ b/chrome/browser/sync_file_system/sync_task_manager.cc
@@ -120,21 +120,23 @@
   task.Run(CreateCompletionCallback(token.Pass(), callback));
 }
 
-void SyncTaskManager::ScheduleTaskIfIdle(const Task& task) {
+bool SyncTaskManager::ScheduleTaskIfIdle(const Task& task) {
   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
   if (!token)
-    return;
+    return false;
   task.Run(CreateCompletionCallback(token.Pass(), SyncStatusCallback()));
+  return true;
 }
 
-void SyncTaskManager::ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task) {
+bool SyncTaskManager::ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task) {
   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
   if (!token)
-    return;
+    return false;
   DCHECK(!running_task_);
   running_task_ = task.Pass();
   running_task_->Run(CreateCompletionCallback(token.Pass(),
                                               SyncStatusCallback()));
+  return true;
 }
 
 void SyncTaskManager::NotifyTaskDone(
diff --git a/chrome/browser/sync_file_system/sync_task_manager.h b/chrome/browser/sync_file_system/sync_task_manager.h
index 3d825d9..b7e8fca 100644
--- a/chrome/browser/sync_file_system/sync_task_manager.h
+++ b/chrome/browser/sync_file_system/sync_task_manager.h
@@ -66,9 +66,10 @@
                               Priority priority,
                               const SyncStatusCallback& callback);
 
-  // Runs the posted task only when we're idle.
-  void ScheduleTaskIfIdle(const Task& task);
-  void ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task);
+  // Runs the posted task only when we're idle.  Returns true if tha task is
+  // scheduled.
+  bool ScheduleTaskIfIdle(const Task& task);
+  bool ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task);
 
   void NotifyTaskDone(scoped_ptr<TaskToken> token,
                       SyncStatusCode status);
diff --git a/chrome/browser/tab_contents/language_state.cc b/chrome/browser/tab_contents/language_state.cc
index eb29895..1567ad2 100644
--- a/chrome/browser/tab_contents/language_state.cc
+++ b/chrome/browser/tab_contents/language_state.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/tab_contents/language_state.h"
 
+#include "chrome/browser/tab_contents/language_state_observer.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
 
 using content::NavigationController;
 
@@ -15,7 +17,9 @@
       page_needs_translation_(false),
       translation_pending_(false),
       translation_declined_(false),
-      in_page_navigation_(false) {
+      in_page_navigation_(false),
+      translate_enabled_(false),
+      observer_(NULL) {
 }
 
 LanguageState::~LanguageState() {
@@ -44,6 +48,8 @@
 
   translation_pending_ = false;
   translation_declined_ = false;
+
+  SetTranslateEnabled(false);
 }
 
 void LanguageState::LanguageDetermined(const std::string& page_language,
@@ -84,3 +90,19 @@
 
   return std::string();
 }
+
+void LanguageState::SetTranslateEnabled(bool value) {
+  if (translate_enabled_ == value)
+    return;
+
+  translate_enabled_ = value;
+  if (observer_) {
+    content::WebContents* web_contents =
+        navigation_controller_->GetWebContents();
+    observer_->OnTranslateEnabledChanged(web_contents);
+  }
+}
+
+bool LanguageState::HasLanguageChanged() const {
+  return original_lang_ != prev_original_lang_;
+}
diff --git a/chrome/browser/tab_contents/language_state.h b/chrome/browser/tab_contents/language_state.h
index b5ac059..2663c4e 100644
--- a/chrome/browser/tab_contents/language_state.h
+++ b/chrome/browser/tab_contents/language_state.h
@@ -9,9 +9,12 @@
 
 #include "base/basictypes.h"
 
+class LanguageStateObserver;
+
 namespace content {
-class NavigationController;
 struct LoadCommittedDetails;
+class NavigationController;
+class WebContents;
 }
 
 // This class holds the language state of the current page.
@@ -71,6 +74,17 @@
   // navigation.
   bool in_page_navigation() const { return in_page_navigation_; }
 
+  // Whether the translate is enabled. This value is supposed to be used for the
+  // Translate icon on the Omnibox.
+  bool translate_enabled() const { return translate_enabled_; }
+  void SetTranslateEnabled(bool value);
+
+  // Whether the current page's language is different from the previous
+  // language.
+  bool HasLanguageChanged() const;
+
+  void set_observer(LanguageStateObserver* observer) { observer_ = observer; }
+
  private:
   // The languages this page is in. Note that current_lang_ is different from
   // original_lang_ when the page has been translated.
@@ -109,6 +123,11 @@
   // Whether the current navigation is a fragment navigation (in page).
   bool in_page_navigation_;
 
+  // Whether the Translate is enabled.
+  bool translate_enabled_;
+
+  LanguageStateObserver* observer_;
+
   DISALLOW_COPY_AND_ASSIGN(LanguageState);
 };
 
diff --git a/chrome/browser/tab_contents/language_state_observer.h b/chrome/browser/tab_contents/language_state_observer.h
new file mode 100644
index 0000000..e93309f
--- /dev/null
+++ b/chrome/browser/tab_contents/language_state_observer.h
@@ -0,0 +1,21 @@
+// Copyright 2013 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_TAB_CONTENTS_LANGUAGE_STATE_OBSERVER_H_
+#define CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_OBSERVER_H_
+
+namespace content {
+class WebContents;
+}
+
+// The observer for the language state.
+class LanguageStateObserver {
+ public:
+  virtual void OnTranslateEnabledChanged(content::WebContents* source) = 0;
+
+ protected:
+  virtual ~LanguageStateObserver() {}
+};
+
+#endif  // CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_OBSERVER_H_
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder.cc b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
index f1475d1..25ad6b3 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder.cc
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
 
 #include "base/metrics/histogram.h"
+#include "components/navigation_metrics/navigation_metrics.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
@@ -17,52 +18,6 @@
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(NavigationMetricsRecorder);
 
-namespace {
-
-enum Scheme {
-  SCHEME_UNKNOWN,
-  SCHEME_HTTP,
-  SCHEME_HTTPS,
-  SCHEME_FILE,
-  SCHEME_FTP,
-  SCHEME_DATA,
-  SCHEME_JAVASCRIPT,
-  SCHEME_ABOUT,
-  SCHEME_CHROME,
-  SCHEME_MAX,
-};
-
-static const char* kSchemeNames[] = {
-  "unknown",
-  "http",
-  "https",
-  "file",
-  "ftp",
-  "data",
-  "javascript",
-  "about",
-  "chrome",
-  "max",
-};
-
-COMPILE_ASSERT(arraysize(kSchemeNames) == SCHEME_MAX + 1,
-               NavigationMetricsRecorder_name_count_mismatch);
-
-void RecordMainFrameNavigation(const content::LoadCommittedDetails& details) {
-  GURL url = details.entry->GetVirtualURL();
-  Scheme scheme = SCHEME_UNKNOWN;
-  for (int i = 1; i < SCHEME_MAX; ++i) {
-    if (url.SchemeIs(kSchemeNames[i])) {
-      scheme = static_cast<Scheme>(i);
-      break;
-    }
-  }
-  UMA_HISTOGRAM_ENUMERATION(
-      "Navigation.MainFrameScheme", scheme, SCHEME_MAX);
-}
-
-}  // namespace
-
 NavigationMetricsRecorder::NavigationMetricsRecorder(
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {
@@ -74,7 +29,7 @@
 void NavigationMetricsRecorder::DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) {
-  RecordMainFrameNavigation(details);
+  navigation_metrics::RecordMainFrameNavigation(details.entry->GetVirtualURL());
 }
 
 void NavigationMetricsRecorder::DidStartLoading(
diff --git a/chrome/browser/task_manager/browser_process_resource_provider.h b/chrome/browser/task_manager/browser_process_resource_provider.h
index 81ae797..d590aeb 100644
--- a/chrome/browser/task_manager/browser_process_resource_provider.h
+++ b/chrome/browser/task_manager/browser_process_resource_provider.h
@@ -12,7 +12,6 @@
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/common/process_type.h"
 
 class TaskManager;
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 238824b..90a3c8c 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -37,6 +37,7 @@
 using content::BrowserThread;
 using content::UserMetricsAction;
 using extensions::Extension;
+using extensions::UnloadedExtensionInfo;
 using ui::ResourceBundle;
 
 typedef ThemeProperties Properties;
@@ -257,9 +258,8 @@
     }
     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
     {
-      Details<const extensions::UnloadedExtensionInfo> unloaded_details(
-          details);
-      if (unloaded_details->reason != extension_misc::UNLOAD_REASON_UPDATE &&
+      Details<const UnloadedExtensionInfo> unloaded_details(details);
+      if (unloaded_details->reason != UnloadedExtensionInfo::REASON_UPDATE &&
           unloaded_details->extension->is_theme() &&
           unloaded_details->extension->id() == GetThemeID()) {
         UseDefaultTheme();
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index 42ae85f..82e721b 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -17,11 +17,11 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "sync/api/sync_error.h"
 #include "sync/api/sync_error_factory_mock.h"
 #include "sync/protocol/sync.pb.h"
diff --git a/chrome/browser/translate/page_translated_details.h b/chrome/browser/translate/page_translated_details.h
index fbf5038..e66dcf6 100644
--- a/chrome/browser/translate/page_translated_details.h
+++ b/chrome/browser/translate/page_translated_details.h
@@ -11,13 +11,6 @@
 
 // Used when sending a notification about a page that has been translated.
 struct PageTranslatedDetails {
-  PageTranslatedDetails(const std::string& in_source_language,
-      const std::string& in_target_language,
-      TranslateErrors::Type in_error_type)
-      : source_language(in_source_language),
-        target_language(in_target_language),
-        error_type(in_error_type) { }
-
   std::string source_language;
   std::string target_language;
   TranslateErrors::Type error_type;
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index 7c841d2..f9b7595 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -32,7 +32,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_factory.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
@@ -61,6 +63,8 @@
 using content::NavigationEntry;
 using content::WebContents;
 
+namespace {
+
 const char kReportLanguageDetectionErrorURL[] =
     "https://translate.google.com/translate_error?client=cr&action=langidc";
 
@@ -75,6 +79,13 @@
 // loading before giving up the translation
 const int kMaxTranslateLoadCheckAttempts = 20;
 
+bool IsEnabledTranslateNewUX() {
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableTranslateNewUX);
+}
+
+}  // namespace
+
 TranslateManager::~TranslateManager() {
 }
 
@@ -302,6 +313,11 @@
 
 void TranslateManager::InitiateTranslation(WebContents* web_contents,
                                            const std::string& page_lang) {
+  TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(web_contents);
+  if (!translate_tab_helper)
+    return;
+
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   Profile* original_profile = profile->GetOriginalProfile();
@@ -395,12 +411,8 @@
     }
   }
 
-  TranslateTabHelper* translate_tab_helper =
-      TranslateTabHelper::FromWebContents(web_contents);
-  if (!translate_tab_helper)
-    return;
-  std::string auto_translate_to =
-      translate_tab_helper->language_state().AutoTranslateTo();
+  LanguageState& language_state = translate_tab_helper->language_state();
+  std::string auto_translate_to = language_state.AutoTranslateTo();
   if (!auto_translate_to.empty()) {
     // This page was navigated through a click from a translated page.
     TranslateBrowserMetrics::ReportInitiationStatus(
@@ -409,13 +421,21 @@
     return;
   }
 
-  // Prompts the user if he/she wants the page translated.
   TranslateBrowserMetrics::ReportInitiationStatus(
       TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR);
-  TranslateInfoBarDelegate::Create(
-      false, InfoBarService::FromWebContents(web_contents),
-      TranslateInfoBarDelegate::BEFORE_TRANSLATE, language_code, target_lang,
-      TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
+
+  if (IsEnabledTranslateNewUX()) {
+    language_state.SetTranslateEnabled(true);
+    if (language_state.HasLanguageChanged())
+      ShowBubble(web_contents,
+                 TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
+  } else {
+    // Prompts the user if he/she wants the page translated.
+    TranslateInfoBarDelegate::Create(
+        false, InfoBarService::FromWebContents(web_contents),
+        TranslateInfoBarDelegate::BEFORE_TRANSLATE, language_code, target_lang,
+        TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
+  }
 }
 
 void TranslateManager::InitiateTranslationPosted(int process_id,
@@ -467,12 +487,16 @@
   if (!IsSupportedLanguage(source_lang))
     source_lang = std::string(translate::kUnknownLanguageCode);
 
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  TranslateInfoBarDelegate::Create(
-      true, InfoBarService::FromWebContents(web_contents),
-      TranslateInfoBarDelegate::TRANSLATING, source_lang, target_lang,
-      TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
+  if (IsEnabledTranslateNewUX()) {
+    ShowBubble(web_contents, TranslateBubbleModel::VIEW_STATE_TRANSLATING);
+  } else {
+    Profile* profile =
+        Profile::FromBrowserContext(web_contents->GetBrowserContext());
+    TranslateInfoBarDelegate::Create(
+        true, InfoBarService::FromWebContents(web_contents),
+        TranslateInfoBarDelegate::TRANSLATING, source_lang, target_lang,
+        TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
+  }
 
   DCHECK(script_.get() != NULL);
 
@@ -584,15 +608,23 @@
     details->error_type = TranslateErrors::UNSUPPORTED_LANGUAGE;
   }
 
-  PrefService* prefs = Profile::FromBrowserContext(
-      web_contents->GetBrowserContext())->GetPrefs();
-  TranslateInfoBarDelegate::Create(
-      true, InfoBarService::FromWebContents(web_contents),
-      (details->error_type == TranslateErrors::NONE) ?
-          TranslateInfoBarDelegate::AFTER_TRANSLATE :
-          TranslateInfoBarDelegate::TRANSLATION_ERROR,
-      details->source_language, details->target_language, details->error_type,
-      prefs, ShortcutConfig());
+  if (IsEnabledTranslateNewUX()) {
+    TranslateBubbleModel::ViewState view_state =
+        (details->error_type == TranslateErrors::NONE) ?
+        TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE :
+        TranslateBubbleModel::VIEW_STATE_ERROR;
+    ShowBubble(web_contents, view_state);
+  } else {
+    PrefService* prefs = Profile::FromBrowserContext(
+        web_contents->GetBrowserContext())->GetPrefs();
+    TranslateInfoBarDelegate::Create(
+        true, InfoBarService::FromWebContents(web_contents),
+        (details->error_type == TranslateErrors::NONE) ?
+        TranslateInfoBarDelegate::AFTER_TRANSLATE :
+        TranslateInfoBarDelegate::TRANSLATION_ERROR,
+        details->source_language, details->target_language, details->error_type,
+        prefs, ShortcutConfig());
+  }
 
   if (details->error_type != TranslateErrors::NONE &&
       !web_contents->GetBrowserContext()->IsOffTheRecord()) {
@@ -650,13 +682,17 @@
       DoTranslatePage(web_contents, translate_script,
                       request.source_lang, request.target_lang);
     } else {
-      Profile* profile =
-          Profile::FromBrowserContext(web_contents->GetBrowserContext());
-      TranslateInfoBarDelegate::Create(
-          true, InfoBarService::FromWebContents(web_contents),
-          TranslateInfoBarDelegate::TRANSLATION_ERROR, request.source_lang,
-          request.target_lang, TranslateErrors::NETWORK, profile->GetPrefs(),
-          ShortcutConfig());
+      if (IsEnabledTranslateNewUX()) {
+        ShowBubble(web_contents, TranslateBubbleModel::VIEW_STATE_ERROR);
+      } else {
+        Profile* profile =
+            Profile::FromBrowserContext(web_contents->GetBrowserContext());
+        TranslateInfoBarDelegate::Create(
+            true, InfoBarService::FromWebContents(web_contents),
+            TranslateInfoBarDelegate::TRANSLATION_ERROR, request.source_lang,
+            request.target_lang, TranslateErrors::NETWORK, profile->GetPrefs(),
+            ShortcutConfig());
+      }
 
       if (!web_contents->GetBrowserContext()->IsOffTheRecord()) {
         TranslateErrorDetails error_details;
@@ -670,6 +706,18 @@
   pending_requests_.clear();
 }
 
+void TranslateManager::ShowBubble(WebContents* web_contents,
+                                  TranslateBubbleModel::ViewState view_state) {
+  // The bubble is implemented only on the desktop platforms.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  BrowserWindow* window = browser ? browser->window() : NULL;
+  TranslateBubbleFactory::Show(window, web_contents, view_state);
+#else
+  NOTREACHED();
+#endif
+}
+
 // static
 std::string TranslateManager::GetTargetLanguage(PrefService* prefs) {
   std::string ui_lang =
diff --git a/chrome/browser/translate/translate_manager.h b/chrome/browser/translate/translate_manager.h
index 8d3a1ab..a49b8a3 100644
--- a/chrome/browser/translate/translate_manager.h
+++ b/chrome/browser/translate/translate_manager.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
 #include "chrome/common/translate/translate_errors.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -191,6 +192,10 @@
   // Notifies to the observers when translate failed.
   void NotifyTranslateError(const TranslateErrorDetails& details);
 
+  // Shows the translate bubble.
+  void ShowBubble(content::WebContents* web_contents,
+                  TranslateBubbleModel::ViewState view_state);
+
   // Returns the different parameters used to decide whether extra shortcuts
   // are needed.
   static ShortcutConfiguration ShortcutConfig();
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index 60e42e6..3fc8761 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -6,6 +6,7 @@
 #include <set>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
@@ -25,6 +26,10 @@
 #include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_factory.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_model_impl.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/translate/language_detection_details.h"
@@ -324,6 +329,42 @@
   DISALLOW_COPY_AND_ASSIGN(TranslateManagerBrowserTest);
 };
 
+class MockTranslateBubbleFactory : public TranslateBubbleFactory {
+ public:
+  MockTranslateBubbleFactory() {
+  }
+
+  virtual void ShowImplementation(
+      BrowserWindow* window,
+      content::WebContents* web_contents,
+      TranslateBubbleModel::ViewState view_state) OVERRIDE {
+    if (model_) {
+      model_->SetViewState(view_state);
+      return;
+    }
+
+    TranslateTabHelper* translate_tab_helper =
+        TranslateTabHelper::FromWebContents(web_contents);
+    std::string source_language =
+        translate_tab_helper->language_state().original_language();
+    std::string target_language = TranslateManager::GetLanguageCode(
+        g_browser_process->GetApplicationLocale());
+    scoped_ptr<TranslateUIDelegate> ui_delegate(
+        new TranslateUIDelegate(web_contents,
+                                source_language,
+                                target_language));
+    model_.reset(
+        new TranslateBubbleModelImpl(view_state, ui_delegate.Pass()));
+  }
+
+  TranslateBubbleModel* model() { return model_.get(); }
+
+ private:
+  scoped_ptr<TranslateBubbleModel> model_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTranslateBubbleFactory);
+};
+
 namespace {
 
 class TestRenderViewContextMenu : public RenderViewContextMenu {
@@ -1410,6 +1451,115 @@
       GURL(chrome::kChromeUIHistoryURL)));
 }
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+
+TEST_F(TranslateManagerBrowserTest, BubbleNormalTranslate) {
+  // Prepare for the bubble
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kEnableTranslateNewUX);
+  MockTranslateBubbleFactory* factory = new MockTranslateBubbleFactory;
+  scoped_ptr<TranslateBubbleFactory> factory_ptr(factory);
+  TranslateBubbleFactory::SetFactory(factory);
+
+  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
+
+  // Check the bubble exists instead of the infobar.
+  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+  ASSERT_TRUE(infobar == NULL);
+  TranslateBubbleModel* bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE,
+            bubble->GetViewState());
+
+  // Simulate clicking translate.
+  process()->sink().ClearMessages();
+  bubble->Translate();
+
+  // Check the bubble shows "Translating...".
+  bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_TRANSLATING,
+            bubble->GetViewState());
+
+  // Simulate the translate script being retrieved (it only needs to be done
+  // once in the test as it is cached).
+  SimulateTranslateScriptURLFetch(true);
+
+  // Simulate the render notifying the translation has been done.
+  SimulateOnPageTranslated("fr", "en");
+
+  // Check the bubble shows "Translated."
+  bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE,
+            bubble->GetViewState());
+}
+
+TEST_F(TranslateManagerBrowserTest, BubbleTranslateScriptNotAvailable) {
+  // Prepare for the bubble
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kEnableTranslateNewUX);
+  MockTranslateBubbleFactory* factory = new MockTranslateBubbleFactory;
+  scoped_ptr<TranslateBubbleFactory> factory_ptr(factory);
+  TranslateBubbleFactory::SetFactory(factory);
+
+  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
+
+  // Check the bubble exists instead of the infobar.
+  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+  ASSERT_TRUE(infobar == NULL);
+  TranslateBubbleModel* bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE,
+            bubble->GetViewState());
+
+  // Simulate clicking translate.
+  process()->sink().ClearMessages();
+  bubble->Translate();
+  SimulateTranslateScriptURLFetch(false);
+
+  // We should not have sent any message to translate to the renderer.
+  EXPECT_FALSE(GetTranslateMessage(NULL, NULL, NULL));
+
+  // And we should have an error infobar showing.
+  bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ERROR,
+            bubble->GetViewState());
+}
+
+TEST_F(TranslateManagerBrowserTest, BubbleUnknownLanguage) {
+  // Prepare for the bubble
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kEnableTranslateNewUX);
+  MockTranslateBubbleFactory* factory = new MockTranslateBubbleFactory;
+  scoped_ptr<TranslateBubbleFactory> factory_ptr(factory);
+  TranslateBubbleFactory::SetFactory(factory);
+
+  // Simulate navigating to a page ("und" is the string returned by the CLD for
+  // languages it does not recognize).
+  SimulateNavigation(GURL("http://www.google.mys"), "und", true);
+
+  // We should not have a bubble as we don't know the language.
+  ASSERT_TRUE(factory->model() == NULL);
+
+  // Translate the page anyway throught the context menu.
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      TestRenderViewContextMenu::CreateContextMenu(web_contents()));
+  menu->Init();
+  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE, 0);
+
+  // Check the bubble exists instead of the infobar.
+  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+  ASSERT_TRUE(infobar == NULL);
+  TranslateBubbleModel* bubble = factory->model();
+  ASSERT_TRUE(bubble != NULL);
+  EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_TRANSLATING,
+            bubble->GetViewState());
+}
+
+#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+
 // Test is flaky on Win http://crbug.com/166334
 #if defined(OS_WIN)
 #define MAYBE_PRE_TranslateSessionRestore DISABLED_PRE_TranslateSessionRestore
diff --git a/chrome/browser/translate/translate_prefs.cc b/chrome/browser/translate/translate_prefs.cc
index db906a0..df9e1b6 100644
--- a/chrome/browser/translate/translate_prefs.cc
+++ b/chrome/browser/translate/translate_prefs.cc
@@ -7,10 +7,10 @@
 #include <set>
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/translate/translate_accept_languages.h"
 #include "chrome/browser/translate/translate_manager.h"
diff --git a/chrome/browser/translate/translate_tab_helper.cc b/chrome/browser/translate/translate_tab_helper.cc
index 4cf6dda..c2dd240 100644
--- a/chrome/browser/translate/translate_tab_helper.cc
+++ b/chrome/browser/translate/translate_tab_helper.cc
@@ -60,7 +60,10 @@
                                           TranslateErrors::Type error_type) {
   language_state_.set_current_language(translated_lang);
   language_state_.set_translation_pending(false);
-  PageTranslatedDetails details(original_lang, translated_lang, error_type);
+  PageTranslatedDetails details;
+  details.source_language = original_lang;
+  details.target_language = translated_lang;
+  details.error_type = error_type;
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_PAGE_TRANSLATED,
       content::Source<WebContents>(web_contents()),
diff --git a/chrome/browser/translate/translate_ui_delegate.cc b/chrome/browser/translate/translate_ui_delegate.cc
index f28941d..ef71178 100644
--- a/chrome/browser/translate/translate_ui_delegate.cc
+++ b/chrome/browser/translate/translate_ui_delegate.cc
@@ -91,7 +91,6 @@
 }
 
 void TranslateUIDelegate::SetOriginalLanguageIndex(size_t language_index) {
-  DCHECK_LT(language_index, GetNumberOfLanguages());
   original_language_index_ = language_index;
 }
 
@@ -167,10 +166,15 @@
 }
 
 void TranslateUIDelegate::SetLanguageBlocked(bool value) {
-  if (value)
+  if (value) {
     prefs_->BlockLanguage(GetOriginalLanguageCode());
-  else
+    TranslateTabHelper* translate_tab_helper =
+        TranslateTabHelper::FromWebContents(web_contents());
+    DCHECK(translate_tab_helper);
+    translate_tab_helper->language_state().SetTranslateEnabled(false);
+  } else {
     prefs_->UnblockLanguage(GetOriginalLanguageCode());
+  }
 
   UMA_HISTOGRAM_BOOLEAN(kNeverTranslateLang, true);
 }
@@ -185,10 +189,15 @@
   if (host.empty())
     return;
 
-  if (value)
+  if (value) {
     prefs_->BlacklistSite(host);
-  else
+    TranslateTabHelper* translate_tab_helper =
+        TranslateTabHelper::FromWebContents(web_contents());
+    DCHECK(translate_tab_helper);
+    translate_tab_helper->language_state().SetTranslateEnabled(false);
+  } else {
     prefs_->RemoveSiteFromBlacklist(host);
+  }
 
   UMA_HISTOGRAM_BOOLEAN(kNeverTranslateSite, true);
 }
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS
index 201afe0..0abd903 100644
--- a/chrome/browser/ui/DEPS
+++ b/chrome/browser/ui/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+components/auto_login_parser",
   "-chrome/browser/ui/views",
 ]
diff --git a/chrome/browser/ui/android/autofill/OWNERS b/chrome/browser/ui/android/autofill/OWNERS
new file mode 100644
index 0000000..44f1849
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/OWNERS
@@ -0,0 +1,2 @@
+aruslan@chromium.org
+aurimas@chromium.org
diff --git a/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
index 7346b24..9db3e43 100644
--- a/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
@@ -11,10 +11,10 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/android/autofill/autofill_dialog_result.h"
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.cc b/chrome/browser/ui/android/infobars/translate_infobar.cc
index a8cd959..3a45bfa 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_infobar.cc
@@ -7,7 +7,9 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_helper.h"
+#include "base/metrics/histogram.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "components/translate/common/translate_metrics.h"
 #include "grit/generated_resources.h"
 #include "jni/TranslateInfoBarDelegate_jni.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -90,8 +92,19 @@
                                              bool always_translate,
                                              bool never_translate_language,
                                              bool never_translate_site) {
-  delegate_->set_original_language_index(source_language_index);
-  delegate_->set_target_language_index(target_language_index);
+  if (delegate_->original_language_index() !=
+      static_cast<size_t>(source_language_index)) {
+    UMA_HISTOGRAM_BOOLEAN(
+        translate::GetMetricsName(translate::UMA_MODIFY_ORIGINAL_LANG), true);
+    delegate_->set_original_language_index(source_language_index);
+  }
+
+  if (delegate_->target_language_index() !=
+      static_cast<size_t>(target_language_index)) {
+    UMA_HISTOGRAM_BOOLEAN(
+        translate::GetMetricsName(translate::UMA_MODIFY_TARGET_LANG), true);
+    delegate_->set_target_language_index(target_language_index);
+  }
 
   if (delegate_->ShouldAlwaysTranslate() != always_translate)
     delegate_->ToggleAlwaysTranslate();
diff --git a/chrome/browser/ui/android/tab_contents/OWNERS b/chrome/browser/ui/android/tab_contents/OWNERS
new file mode 100644
index 0000000..8f9ea72
--- /dev/null
+++ b/chrome/browser/ui/android/tab_contents/OWNERS
@@ -0,0 +1,2 @@
+dfalcantara@chromium.org
+dtrainor@chromium.org
diff --git a/chrome/browser/ui/android/tab_model/OWNERS b/chrome/browser/ui/android/tab_model/OWNERS
new file mode 100644
index 0000000..8f9ea72
--- /dev/null
+++ b/chrome/browser/ui/android/tab_model/OWNERS
@@ -0,0 +1,2 @@
+dfalcantara@chromium.org
+dtrainor@chromium.org
diff --git a/chrome/browser/ui/app_list/app_context_menu.cc b/chrome/browser/ui/app_list/app_context_menu.cc
index ac5ce9e..bd92795 100644
--- a/chrome/browser/ui/app_list/app_context_menu.cc
+++ b/chrome/browser/ui/app_list/app_context_menu.cc
@@ -4,30 +4,24 @@
 
 #include "chrome/browser/ui/app_list/app_context_menu.h"
 
+#include "base/command_line.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/extensions/context_menu_matcher.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_uninstall_dialog.h"
-#include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
-#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "content/public/common/context_menu_params.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
-#include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(USE_ASH)
 #include "ash/shell.h"
 #endif
 
-using extensions::Extension;
-
 namespace app_list {
 
 namespace {
@@ -50,82 +44,6 @@
   LAUNCH_TYPE_LAST,
 };
 
-// ExtensionUninstaller runs the extension uninstall flow. It shows the
-// extension uninstall dialog and wait for user to confirm or cancel the
-// uninstall.
-class ExtensionUninstaller : public ExtensionUninstallDialog::Delegate {
- public:
-  ExtensionUninstaller(Profile* profile,
-                       const std::string& extension_id,
-                       AppListControllerDelegate* controller)
-      : profile_(profile),
-        app_id_(extension_id),
-        controller_(controller) {
-  }
-
-  void Run() {
-    const Extension* extension =
-        extensions::ExtensionSystem::Get(profile_)->extension_service()->
-            GetInstalledExtension(app_id_);
-    if (!extension) {
-      CleanUp();
-      return;
-    }
-    controller_->OnShowExtensionPrompt();
-    dialog_.reset(ExtensionUninstallDialog::Create(profile_, NULL, this));
-    dialog_->ConfirmUninstall(extension);
-  }
-
- private:
-  // Overridden from ExtensionUninstallDialog::Delegate:
-  virtual void ExtensionUninstallAccepted() OVERRIDE {
-    ExtensionService* service =
-        extensions::ExtensionSystem::Get(profile_)->extension_service();
-    const Extension* extension = service->GetInstalledExtension(app_id_);
-    if (extension) {
-      service->UninstallExtension(app_id_,
-                                  false, /* external_uninstall*/
-                                  NULL);
-    }
-    controller_->OnCloseExtensionPrompt();
-    CleanUp();
-  }
-
-  virtual void ExtensionUninstallCanceled() OVERRIDE {
-    controller_->OnCloseExtensionPrompt();
-    CleanUp();
-  }
-
-  void CleanUp() {
-    delete this;
-  }
-
-  Profile* profile_;
-  std::string app_id_;
-  AppListControllerDelegate* controller_;
-  scoped_ptr<ExtensionUninstallDialog> dialog_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstaller);
-};
-
-extensions::ExtensionPrefs::LaunchType GetExtensionLaunchType(
-    Profile* profile,
-    const Extension* extension) {
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  return service->extension_prefs()->
-      GetLaunchType(extension, extensions::ExtensionPrefs::LAUNCH_DEFAULT);
-}
-
-void SetExtensionLaunchType(
-    Profile* profile,
-    const std::string& extension_id,
-    extensions::ExtensionPrefs::LaunchType launch_type) {
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  service->extension_prefs()->SetLaunchType(extension_id, launch_type);
-}
-
 bool MenuItemHasLauncherContext(const extensions::MenuItem* item) {
   return item->contexts().Contains(extensions::MenuItem::LAUNCHER);
 }
@@ -149,8 +67,7 @@
 AppContextMenu::~AppContextMenu() {}
 
 ui::MenuModel* AppContextMenu::GetMenuModel() {
-  const Extension* extension = GetExtension();
-  if (!extension)
+  if (!controller_->IsExtensionInstalled(profile_, app_id_))
     return NULL;
 
   if (menu_model_.get())
@@ -196,27 +113,36 @@
 
     if (!is_platform_app_) {
       menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
-      menu_model_->AddCheckItemWithStringId(
-          LAUNCH_TYPE_REGULAR_TAB,
-          IDS_APP_CONTEXT_MENU_OPEN_REGULAR);
-      menu_model_->AddCheckItemWithStringId(
-          LAUNCH_TYPE_PINNED_TAB,
-          IDS_APP_CONTEXT_MENU_OPEN_PINNED);
+      // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and
+      // LAUNCH_REGULAR.
+      if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableStreamlinedHostedApps)) {
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_REGULAR_TAB,
+            IDS_APP_CONTEXT_MENU_OPEN_TAB);
+      } else {
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_REGULAR_TAB,
+            IDS_APP_CONTEXT_MENU_OPEN_REGULAR);
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_PINNED_TAB,
+            IDS_APP_CONTEXT_MENU_OPEN_PINNED);
 #if defined(OS_MACOSX)
-      // Mac does not support standalone web app browser windows or maximize.
-      menu_model_->AddCheckItemWithStringId(
-          LAUNCH_TYPE_FULLSCREEN,
-          IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN);
+        // Mac does not support standalone web app browser windows or maximize.
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_FULLSCREEN,
+            IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN);
 #else
-      menu_model_->AddCheckItemWithStringId(
-          LAUNCH_TYPE_WINDOW,
-          IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
-      // Even though the launch type is Full Screen it is more accurately
-      // described as Maximized in Ash.
-      menu_model_->AddCheckItemWithStringId(
-          LAUNCH_TYPE_FULLSCREEN,
-          IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_WINDOW,
+            IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
+        // Even though the launch type is Full Screen it is more accurately
+        // described as Maximized in Ash.
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_FULLSCREEN,
+            IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
 #endif
+      }
       menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
       menu_model_->AddItemWithStringId(OPTIONS, IDS_NEW_TAB_APP_OPTIONS);
     }
@@ -231,54 +157,6 @@
   return menu_model_.get();
 }
 
-const Extension* AppContextMenu::GetExtension() const {
-  const ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  const Extension* extension = service->GetInstalledExtension(app_id_);
-  return extension;
-}
-
-void AppContextMenu::ShowExtensionOptions() {
-  const Extension* extension = GetExtension();
-  if (!extension)
-    return;
-
-  chrome::NavigateParams params(
-      profile_,
-      extensions::ManifestURL::GetOptionsPage(extension),
-      content::PAGE_TRANSITION_LINK);
-  chrome::Navigate(&params);
-}
-
-void AppContextMenu::ShowExtensionDetails() {
-  const Extension* extension = GetExtension();
-  if (!extension)
-    return;
-
-  const GURL url = extensions::ManifestURL::GetDetailsURL(extension);
-  DCHECK_NE(url, GURL::EmptyGURL());
-
-  const std::string source = AppListControllerDelegate::AppListSourceToString(
-      is_search_result_ ?
-          AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH :
-          AppListControllerDelegate::LAUNCH_FROM_APP_LIST);
-  chrome::NavigateParams params(
-      profile_,
-      net::AppendQueryParameter(url,
-                                extension_urls::kWebstoreSourceField,
-                                source),
-      content::PAGE_TRANSITION_LINK);
-  chrome::Navigate(&params);
-}
-
-void AppContextMenu::StartExtensionUninstall() {
-  // ExtensionUninstall deletes itself when done or aborted.
-  ExtensionUninstaller* uninstaller = new ExtensionUninstaller(profile_,
-                                                               app_id_,
-                                                               controller_);
-  uninstaller->Run();
-}
-
 bool AppContextMenu::IsItemForCommandIdDynamic(int command_id) const {
   return command_id == TOGGLE_PIN || command_id == LAUNCH_NEW;
 }
@@ -307,8 +185,8 @@
 
 bool AppContextMenu::IsCommandIdChecked(int command_id) const {
   if (command_id >= LAUNCH_TYPE_START && command_id < LAUNCH_TYPE_LAST) {
-    return static_cast<int>(GetExtensionLaunchType(profile_, GetExtension())) +
-        LAUNCH_TYPE_START == command_id;
+    return static_cast<int>(controller_->GetExtensionLaunchType(
+        profile_, app_id_)) + LAUNCH_TYPE_START == command_id;
   } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
              command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
     return extension_menu_items_->IsCommandIdChecked(command_id);
@@ -321,21 +199,11 @@
     return controller_->GetPinnable() ==
         AppListControllerDelegate::PIN_EDITABLE;
   } else if (command_id == OPTIONS) {
-    const ExtensionService* service =
-        extensions::ExtensionSystem::Get(profile_)->extension_service();
-    const Extension* extension = GetExtension();
-    return service->IsExtensionEnabledForLauncher(app_id_) &&
-           extension &&
-           !extensions::ManifestURL::GetOptionsPage(extension).is_empty();
+    return controller_->HasOptionsPage(profile_, app_id_);
   } else if (command_id == UNINSTALL) {
-    const Extension* extension = GetExtension();
-    const extensions::ManagementPolicy* policy =
-        extensions::ExtensionSystem::Get(profile_)->management_policy();
-    return extension &&
-           policy->UserMayModifySettings(extension, NULL);
+    return controller_->UserMayModifySettings(profile_, app_id_);
   } else if (command_id == DETAILS) {
-    const Extension* extension = GetExtension();
-    return extension && extension->from_webstore();
+    return controller_->IsAppFromWebStore(profile_, app_id_);
   } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
              command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
     return extension_menu_items_->IsCommandIdEnabled(command_id);
@@ -370,16 +238,27 @@
     controller_->DoCreateShortcutsFlow(profile_, app_id_);
   } else if (command_id >= LAUNCH_TYPE_START &&
              command_id < LAUNCH_TYPE_LAST) {
-    SetExtensionLaunchType(profile_,
-                           app_id_,
-                           static_cast<extensions::ExtensionPrefs::LaunchType>(
-                               command_id - LAUNCH_TYPE_START));
+    extensions::ExtensionPrefs::LaunchType launch_type =
+        static_cast<extensions::ExtensionPrefs::LaunchType>(
+            command_id - LAUNCH_TYPE_START);
+    // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and
+    // LAUNCH_REGULAR.
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kEnableStreamlinedHostedApps)) {
+      launch_type = controller_->GetExtensionLaunchType(profile_, app_id_) ==
+                            extensions::ExtensionPrefs::LAUNCH_REGULAR
+                        ? extensions::ExtensionPrefs::LAUNCH_WINDOW
+                        : extensions::ExtensionPrefs::LAUNCH_REGULAR;
+    }
+    controller_->SetExtensionLaunchType(profile_,
+                                        app_id_,
+                                        launch_type);
   } else if (command_id == OPTIONS) {
-    ShowExtensionOptions();
+    controller_->ShowOptionsPage(profile_, app_id_);
   } else if (command_id == UNINSTALL) {
-    StartExtensionUninstall();
+    controller_->UninstallApp(profile_, app_id_);
   } else if (command_id == DETAILS) {
-    ShowExtensionDetails();
+    controller_->ShowAppInWebStore(profile_, app_id_, is_search_result_);
   } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
              command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
     extension_menu_items_->ExecuteCommand(command_id, NULL,
diff --git a/chrome/browser/ui/app_list/app_context_menu.h b/chrome/browser/ui/app_list/app_context_menu.h
index 7f6631a..7406c23 100644
--- a/chrome/browser/ui/app_list/app_context_menu.h
+++ b/chrome/browser/ui/app_list/app_context_menu.h
@@ -15,7 +15,6 @@
 class Profile;
 
 namespace extensions {
-class Extension;
 class ContextMenuMatcher;
 }
 
@@ -37,11 +36,6 @@
   ui::MenuModel* GetMenuModel();
 
  private:
-  const extensions::Extension* GetExtension() const;
-  void ShowExtensionOptions();
-  void ShowExtensionDetails();
-  void StartExtensionUninstall();
-
   // ui::SimpleMenuModel::Delegate overrides:
   virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
   virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
index e36192b..6279157 100644
--- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -65,12 +65,17 @@
   DISALLOW_COPY_AND_ASSIGN(AppListControllerBrowserTest);
 };
 
+AppListService* GetAppListService() {
+  // TODO(tapted): Consider testing ash explicitly on the win-ash trybot.
+  return AppListService::Get(chrome::GetActiveDesktop());
+}
+
 // Test the CreateNewWindow function of the controller delegate.
 // TODO(mgiuca): Enable on Linux when supported.
 #if !defined(OS_LINUX)
 IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, CreateNewWindow) {
   const chrome::HostDesktopType desktop = chrome::GetActiveDesktop();
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   scoped_ptr<AppListControllerDelegate> controller(
       service->CreateControllerDelegate());
   ASSERT_TRUE(controller);
@@ -92,7 +97,7 @@
 #if !defined(OS_CHROMEOS) && !defined(OS_LINUX)
 // Show the app list, then dismiss it.
 IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, ShowAndDismiss) {
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   ASSERT_FALSE(service->IsAppListVisible());
   service->ShowForProfile(browser()->profile());
   ASSERT_TRUE(service->IsAppListVisible());
@@ -103,7 +108,7 @@
 IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, SwitchAppListProfiles) {
   InitSecondProfile();
 
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   scoped_ptr<test::AppListServiceTestApi> test_api(
       test::AppListServiceTestApi::Create(chrome::HOST_DESKTOP_TYPE_NATIVE));
   ASSERT_TRUE(service);
@@ -141,7 +146,7 @@
                        SwitchAppListProfilesDuringSearch) {
   InitSecondProfile();
 
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   scoped_ptr<test::AppListServiceTestApi> test_api(
       test::AppListServiceTestApi::Create(chrome::HOST_DESKTOP_TYPE_NATIVE));
   ASSERT_TRUE(service);
@@ -187,7 +192,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ShowAppListBrowserTest, ShowAppListFlag) {
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   // The app list should already be shown because we passed
   // switches::kShowAppList.
   ASSERT_TRUE(service->IsAppListVisible());
@@ -291,7 +296,7 @@
                        1 /* expected_change: new install */);
   ASSERT_TRUE(extension);
 
-  AppListService* service = AppListService::Get();
+  AppListService* service = GetAppListService();
   scoped_ptr<test::AppListServiceTestApi> test_api(
       test::AppListServiceTestApi::Create(chrome::HOST_DESKTOP_TYPE_NATIVE));
   ASSERT_TRUE(service);
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.cc b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
index 9daf2f8..ffba607 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -4,64 +4,35 @@
 
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/extensions/management_policy.h"
+#include "chrome/browser/ui/app_list/extension_uninstaller.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "ui/gfx/image/image_skia.h"
+#include "chrome/common/extensions/manifest_url_handler.h"
+#include "net/base/url_util.h"
+
+namespace {
+
+const extensions::Extension* GetExtension(Profile* profile,
+                              const std::string& extension_id) {
+  const ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  const extensions::Extension* extension =
+      service->GetInstalledExtension(extension_id);
+  return extension;
+}
+
+}  // namespace
 
 AppListControllerDelegate::~AppListControllerDelegate() {}
 
 void AppListControllerDelegate::ViewClosing() {}
 
-gfx::ImageSkia AppListControllerDelegate::GetWindowIcon() {
-  return gfx::ImageSkia();
-}
-
-bool AppListControllerDelegate::IsAppPinned(const std::string& extension_id) {
-  return false;
-}
-
-void AppListControllerDelegate::PinApp(const std::string& extension_id) {}
-
-void AppListControllerDelegate::UnpinApp(const std::string& extension_id) {}
-
-bool AppListControllerDelegate::CanDoCreateShortcutsFlow() {
-  return false;
-}
-
-void AppListControllerDelegate::DoCreateShortcutsFlow(
-    Profile* profile,
-    const std::string& extension_id) {
-  DCHECK(CanDoCreateShortcutsFlow());
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  DCHECK(service);
-  const extensions::Extension* extension = service->GetInstalledExtension(
-      extension_id);
-  DCHECK(extension);
-
-  gfx::NativeWindow parent_window = GetAppListWindow();
-  if (!parent_window)
-    return;
-  OnShowExtensionPrompt();
-  chrome::ShowCreateChromeAppShortcutsDialog(
-      parent_window, profile, extension,
-      base::Bind(&AppListControllerDelegate::OnCloseExtensionPrompt,
-                 base::Unretained(this)));
-}
-
-void AppListControllerDelegate::CreateNewWindow(Profile* profile,
-                                                bool incognito) {
-  NOTREACHED();
-}
-
-bool AppListControllerDelegate::ShouldShowUserIcon() {
-  return g_browser_process->profile_manager()->GetNumberOfProfiles() > 1;
-}
+void AppListControllerDelegate::OnShowExtensionPrompt() {}
+void AppListControllerDelegate::OnCloseExtensionPrompt() {}
 
 std::string AppListControllerDelegate::AppListSourceToString(
     AppListSource source) {
@@ -73,3 +44,102 @@
     default: return std::string();
   }
 }
+
+bool AppListControllerDelegate::UserMayModifySettings(
+    Profile* profile,
+    const std::string& app_id) {
+  const extensions::Extension* extension = GetExtension(profile, app_id);
+  const extensions::ManagementPolicy* policy =
+      extensions::ExtensionSystem::Get(profile)->management_policy();
+  return extension &&
+         policy->UserMayModifySettings(extension, NULL);
+}
+
+void AppListControllerDelegate::UninstallApp(Profile* profile,
+                                             const std::string& app_id) {
+  // ExtensionUninstall deletes itself when done or aborted.
+  ExtensionUninstaller* uninstaller =
+      new ExtensionUninstaller(profile, app_id, this);
+  uninstaller->Run();
+}
+
+bool AppListControllerDelegate::IsAppFromWebStore(
+    Profile* profile,
+    const std::string& app_id) {
+  const extensions::Extension* extension = GetExtension(profile, app_id);
+  return extension && extension->from_webstore();
+}
+
+void AppListControllerDelegate::ShowAppInWebStore(
+    Profile* profile,
+    const std::string& app_id,
+    bool is_search_result) {
+  const extensions::Extension* extension = GetExtension(profile, app_id);
+  if (!extension)
+    return;
+
+  const GURL url = extensions::ManifestURL::GetDetailsURL(extension);
+  DCHECK_NE(url, GURL::EmptyGURL());
+
+  const std::string source = AppListSourceToString(
+      is_search_result ?
+          AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH :
+          AppListControllerDelegate::LAUNCH_FROM_APP_LIST);
+  chrome::NavigateParams params(
+      profile,
+      net::AppendQueryParameter(url,
+                                extension_urls::kWebstoreSourceField,
+                                source),
+      content::PAGE_TRANSITION_LINK);
+  chrome::Navigate(&params);
+}
+
+bool AppListControllerDelegate::HasOptionsPage(
+    Profile* profile,
+    const std::string& app_id) {
+  const ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  const extensions::Extension* extension = GetExtension(profile, app_id);
+  return service->IsExtensionEnabledForLauncher(app_id) &&
+         extension &&
+         !extensions::ManifestURL::GetOptionsPage(extension).is_empty();
+}
+
+void AppListControllerDelegate::ShowOptionsPage(
+    Profile* profile,
+    const std::string& app_id) {
+  const extensions::Extension* extension = GetExtension(profile, app_id);
+  if (!extension)
+    return;
+
+  chrome::NavigateParams params(
+      profile,
+      extensions::ManifestURL::GetOptionsPage(extension),
+      content::PAGE_TRANSITION_LINK);
+  chrome::Navigate(&params);
+}
+
+extensions::ExtensionPrefs::LaunchType
+AppListControllerDelegate::GetExtensionLaunchType(
+    Profile* profile,
+    const std::string& app_id) {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  return service->extension_prefs()->
+      GetLaunchType(GetExtension(profile, app_id),
+                    extensions::ExtensionPrefs::LAUNCH_DEFAULT);
+}
+
+void AppListControllerDelegate::SetExtensionLaunchType(
+    Profile* profile,
+    const std::string& extension_id,
+    extensions::ExtensionPrefs::LaunchType launch_type) {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  service->extension_prefs()->SetLaunchType(extension_id, launch_type);
+}
+
+bool AppListControllerDelegate::IsExtensionInstalled(
+    Profile* profile, const std::string& app_id) {
+  return !!GetExtension(profile, app_id);
+}
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.h b/chrome/browser/ui/app_list/app_list_controller_delegate.h
index 04d04a8..ade1589 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "chrome/browser/extensions/extension_prefs.h"
 #include "ui/gfx/native_widget_types.h"
 
 class Profile;
@@ -54,28 +55,29 @@
   virtual gfx::NativeWindow GetAppListWindow() = 0;
 
   // Get the application icon to be used, if any, for the app list.
-  virtual gfx::ImageSkia GetWindowIcon();
+  virtual gfx::ImageSkia GetWindowIcon() = 0;
 
   // Control of pinning apps.
-  virtual bool IsAppPinned(const std::string& extension_id);
-  virtual void PinApp(const std::string& extension_id);
-  virtual void UnpinApp(const std::string& extension_id);
+  virtual bool IsAppPinned(const std::string& extension_id) = 0;
+  virtual void PinApp(const std::string& extension_id) = 0;
+  virtual void UnpinApp(const std::string& extension_id) = 0;
   virtual Pinnable GetPinnable() = 0;
 
   // Be aware of the extension prompt (either uninstalling flow or enable flow).
-  virtual void OnShowExtensionPrompt() {}
-  virtual void OnCloseExtensionPrompt() {}
+  virtual void OnShowExtensionPrompt();
+  virtual void OnCloseExtensionPrompt();
 
   // Whether the controller supports a Create Shortcuts flow.
-  virtual bool CanDoCreateShortcutsFlow();
+  virtual bool CanDoCreateShortcutsFlow() = 0;
 
   // Show the dialog to create shortcuts. Call only if
   // CanDoCreateShortcutsFlow() returns true.
-  void DoCreateShortcutsFlow(Profile* profile, const std::string& extension_id);
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id) = 0;
 
   // Handle the "create window" context menu items of Chrome App.
   // |incognito| is true to create an incognito window.
-  virtual void CreateNewWindow(Profile* profile, bool incognito);
+  virtual void CreateNewWindow(Profile* profile, bool incognito) = 0;
 
   // Show the app's most recent window, or launch it if it is not running.
   virtual void ActivateApp(Profile* profile,
@@ -94,9 +96,44 @@
 
   // Whether or not the icon indicating which user is logged in should be
   // visible.
-  virtual bool ShouldShowUserIcon();
+  virtual bool ShouldShowUserIcon() = 0;
 
   static std::string AppListSourceToString(AppListSource source);
+
+  // True if the user has permission to modify the given app's settings.
+  bool UserMayModifySettings(Profile* profile, const std::string& app_id);
+
+  // Uninstall the app identified by |app_id| from |profile|.
+  void UninstallApp(Profile* profile, const std::string& app_id);
+
+  // True if the app was installed from the web store.
+  bool IsAppFromWebStore(Profile* profile,
+                         const std::string& app_id);
+
+  // Shows the user the webstore site for the given app.
+  void ShowAppInWebStore(Profile* profile,
+                         const std::string& app_id,
+                         bool is_search_result);
+
+  // True if the given extension has an options page.
+  bool HasOptionsPage(Profile* profile, const std::string& app_id);
+
+  // Shows the user the options page for the app.
+  void ShowOptionsPage(Profile* profile, const std::string& app_id);
+
+  // Gets/sets the launch type for an app.
+  // The launch type specifies whether a hosted app should launch as a separate
+  // window, fullscreened or as a tab.
+  extensions::ExtensionPrefs::LaunchType GetExtensionLaunchType(
+      Profile* profile, const std::string& app_id);
+  virtual void SetExtensionLaunchType(
+      Profile* profile,
+      const std::string& extension_id,
+      extensions::ExtensionPrefs::LaunchType launch_type);
+
+  // Returns true if the given extension is installed.
+  bool IsExtensionInstalled(Profile* profile, const std::string& app_id);
+
 };
 
 #endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_CONTROLLER_DELEGATE_H_
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
new file mode 100644
index 0000000..15b919e
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
@@ -0,0 +1,127 @@
+// Copyright 2013 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/app_list/app_list_controller_delegate_impl.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/app_list/app_list_service_impl.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "net/base/url_util.h"
+#include "ui/gfx/image/image_skia.h"
+
+AppListControllerDelegateImpl::AppListControllerDelegateImpl(
+    AppListService* service)
+    : service_(service) {}
+
+AppListControllerDelegateImpl::~AppListControllerDelegateImpl() {}
+
+void AppListControllerDelegateImpl::DismissView() {
+  service_->DismissAppList();
+}
+
+gfx::NativeWindow AppListControllerDelegateImpl::GetAppListWindow() {
+  return service_->GetAppListWindow();
+}
+
+gfx::ImageSkia AppListControllerDelegateImpl::GetWindowIcon() {
+  return gfx::ImageSkia();
+}
+
+bool AppListControllerDelegateImpl::IsAppPinned(
+    const std::string& extension_id) {
+  return false;
+}
+
+void AppListControllerDelegateImpl::PinApp(const std::string& extension_id) {
+  NOTREACHED();
+}
+
+void AppListControllerDelegateImpl::UnpinApp(const std::string& extension_id) {
+  NOTREACHED();
+}
+
+AppListControllerDelegateImpl::Pinnable
+    AppListControllerDelegateImpl::GetPinnable() {
+  return NO_PIN;
+}
+
+bool AppListControllerDelegateImpl::CanDoCreateShortcutsFlow() {
+  return false;
+}
+
+void AppListControllerDelegateImpl::DoCreateShortcutsFlow(
+    Profile* profile,
+    const std::string& extension_id) {
+  DCHECK(CanDoCreateShortcutsFlow());
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  DCHECK(service);
+  const extensions::Extension* extension = service->GetInstalledExtension(
+      extension_id);
+  DCHECK(extension);
+
+  gfx::NativeWindow parent_window = GetAppListWindow();
+  if (!parent_window)
+    return;
+  OnShowExtensionPrompt();
+  chrome::ShowCreateChromeAppShortcutsDialog(
+      parent_window, profile, extension,
+      base::Bind(&AppListControllerDelegateImpl::OnCloseExtensionPrompt,
+                 base::Unretained(this)));
+}
+
+void AppListControllerDelegateImpl::CreateNewWindow(Profile* profile,
+                                                   bool incognito) {
+  Profile* window_profile = incognito ?
+      profile->GetOffTheRecordProfile() : profile;
+  chrome::NewEmptyWindow(window_profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+}
+
+void AppListControllerDelegateImpl::ActivateApp(
+    Profile* profile,
+    const extensions::Extension* extension,
+    AppListSource source,
+    int event_flags) {
+  LaunchApp(profile, extension, source, event_flags);
+}
+
+void AppListControllerDelegateImpl::LaunchApp(
+    Profile* profile,
+    const extensions::Extension* extension,
+    AppListSource source,
+    int event_flags) {
+  AppListServiceImpl::RecordAppListAppLaunch();
+
+  AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB);
+  params.desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
+
+  if (source != LAUNCH_FROM_UNKNOWN &&
+      extension->id() == extension_misc::kWebStoreAppId) {
+    // Set an override URL to include the source.
+    GURL extension_url = extensions::AppLaunchInfo::GetFullLaunchURL(extension);
+    params.override_url = net::AppendQueryParameter(
+        extension_url,
+        extension_urls::kWebstoreSourceField,
+        AppListSourceToString(source));
+  }
+
+  OpenApplication(params);
+}
+
+void AppListControllerDelegateImpl::ShowForProfileByPath(
+    const base::FilePath& profile_path) {
+  service_->SetProfilePath(profile_path);
+  service_->Show();
+}
+
+bool AppListControllerDelegateImpl::ShouldShowUserIcon() {
+  return g_browser_process->profile_manager()->GetNumberOfProfiles() > 1;
+}
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.h b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.h
new file mode 100644
index 0000000..f0b0042
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.h
@@ -0,0 +1,59 @@
+// Copyright 2013 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_APP_LIST_APP_LIST_CONTROLLER_DELEGATE_IMPL_H_
+#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_CONTROLLER_DELEGATE_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+
+class AppListService;
+class Profile;
+
+namespace base {
+class FilePath;
+}
+
+namespace extensions {
+class Extension;
+}
+
+// Primary implementation of AppListControllerDelegate, used by non-Ash
+// platforms.
+class AppListControllerDelegateImpl : public AppListControllerDelegate {
+ public:
+  explicit AppListControllerDelegateImpl(AppListService* service);
+  virtual ~AppListControllerDelegateImpl();
+
+  // AppListControllerDelegate overrides:
+  virtual void DismissView() OVERRIDE;
+  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
+  virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
+  virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE;
+  virtual void PinApp(const std::string& extension_id) OVERRIDE;
+  virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
+  virtual Pinnable GetPinnable() OVERRIDE;
+  virtual bool CanDoCreateShortcutsFlow() OVERRIDE;
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id) OVERRIDE;
+  virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
+  virtual void ActivateApp(Profile* profile,
+                           const extensions::Extension* extension,
+                           AppListSource source,
+                           int event_flags) OVERRIDE;
+  virtual void LaunchApp(Profile* profile,
+                         const extensions::Extension* extension,
+                         AppListSource source,
+                         int event_flags) OVERRIDE;
+  virtual void ShowForProfileByPath(
+      const base::FilePath& profile_path) OVERRIDE;
+  virtual bool ShouldShowUserIcon() OVERRIDE;
+
+ private:
+  AppListService* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateImpl);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_CONTROLLER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/ui/app_list/app_list_service.cc b/chrome/browser/ui/app_list/app_list_service.cc
index 704becb..7d686ef 100644
--- a/chrome/browser/ui/app_list/app_list_service.cc
+++ b/chrome/browser/ui/app_list/app_list_service.cc
@@ -110,6 +110,6 @@
       break;
   }
 
-  AppListService::Get()->SetAppListNextPaintCallback(
+  Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->SetAppListNextPaintCallback(
       base::Bind(RecordFirstPaintTiming, startup, start_time));
 }
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index ddbd76a..5ba5161 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "ui/gfx/native_widget_types.h"
 
 class AppListControllerDelegate;
@@ -27,8 +28,9 @@
 
 class AppListService {
  public:
-  // Get the AppListService for the current platform and desktop type.
-  static AppListService* Get();
+  // Get the AppListService for the current platform and specified
+  // |desktop_type|.
+  static AppListService* Get(chrome::HostDesktopType desktop_type);
 
   // Call Init for all AppListService instances on this platform.
   static void InitAll(Profile* initial_profile);
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc
index 23671d2..87db7e3 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -55,7 +55,7 @@
 }  // namespace
 
 // static
-AppListService* AppListService::Get() {
+AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) {
   return AppListServiceDisabled::GetInstance();
 }
 
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc
index 90fc03b..ec7d1b3 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -166,8 +166,7 @@
 }
 
 AppListServiceImpl::AppListServiceImpl()
-    : profile_(NULL),
-      profile_store_(new ProfileStoreImpl(
+    : profile_store_(new ProfileStoreImpl(
           g_browser_process->profile_manager())),
       weak_factory_(this),
       command_line_(*CommandLine::ForCurrentProcess()),
@@ -183,8 +182,7 @@
     PrefService* local_state,
     scoped_ptr<ProfileStore> profile_store,
     scoped_ptr<KeepAliveService> keep_alive_service)
-    : profile_(NULL),
-      profile_store_(profile_store.Pass()),
+    : profile_store_(profile_store.Pass()),
       weak_factory_(this),
       command_line_(command_line),
       local_state_(local_state),
@@ -265,14 +263,6 @@
   CreateShortcut();
 }
 
-Profile* AppListServiceImpl::GetCurrentAppListProfile() {
-  return profile();
-}
-
-void AppListServiceImpl::SetProfile(Profile* new_profile) {
-  profile_ = new_profile;
-}
-
 void AppListServiceImpl::InvalidatePendingProfileLoads() {
   profile_loader_->InvalidatePendingProfileLoads();
 }
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.h b/chrome/browser/ui/app_list/app_list_service_impl.h
index cfcff00..2428e1c 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -52,8 +52,6 @@
  protected:
   AppListServiceImpl();
 
-  Profile* profile() const { return profile_; }
-  void SetProfile(Profile* new_profile);
   void InvalidatePendingProfileLoads();
   ProfileLoader& profile_loader() { return *profile_loader_; }
   const ProfileLoader& profile_loader() const { return *profile_loader_; }
@@ -79,18 +77,12 @@
                        Profile* profile,
                        Profile::CreateStatus status);
 
-  virtual Profile* GetCurrentAppListProfile() OVERRIDE;
-
   // ProfileInfoCacheObserver overrides:
   virtual void OnProfileWillBeRemoved(
       const base::FilePath& profile_path) OVERRIDE;
 
-  // The profile the AppList is currently displaying.
-  Profile* profile_;
   scoped_ptr<ProfileStore> profile_store_;
-
   base::WeakPtrFactory<AppListServiceImpl> weak_factory_;
-
   CommandLine command_line_;
   PrefService* local_state_;
   scoped_ptr<ProfileLoader> profile_loader_;
diff --git a/chrome/browser/ui/app_list/app_list_service_linux.cc b/chrome/browser/ui/app_list/app_list_service_linux.cc
index 6261c2d..8487c8e 100644
--- a/chrome/browser/ui/app_list/app_list_service_linux.cc
+++ b/chrome/browser/ui/app_list/app_list_service_linux.cc
@@ -40,6 +40,11 @@
   return gfx::NativeWindow();
 }
 
+Profile* AppListServiceLinux::GetCurrentAppListProfile() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
 AppListControllerDelegate* AppListServiceLinux::CreateControllerDelegate() {
   NOTIMPLEMENTED();
   return NULL;
@@ -52,11 +57,11 @@
 AppListServiceLinux::AppListServiceLinux() {}
 
 // static
-AppListService* AppListService::Get() {
+AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) {
   return AppListServiceLinux::GetInstance();
 }
 
 // static
 void AppListService::InitAll(Profile* initial_profile) {
-  Get()->Init(initial_profile);
+  AppListServiceLinux::GetInstance()->Init(initial_profile);
 }
diff --git a/chrome/browser/ui/app_list/app_list_service_linux.h b/chrome/browser/ui/app_list/app_list_service_linux.h
index a0f4eb8..12c7c34 100644
--- a/chrome/browser/ui/app_list/app_list_service_linux.h
+++ b/chrome/browser/ui/app_list/app_list_service_linux.h
@@ -24,6 +24,7 @@
   virtual void DismissAppList() OVERRIDE;
   virtual bool IsAppListVisible() const OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
+  virtual Profile* GetCurrentAppListProfile() OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
 
   // AppListServiceImpl overrides:
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.h b/chrome/browser/ui/app_list/app_list_service_mac.h
index cbacb64..62ac81c 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.h
+++ b/chrome/browser/ui/app_list/app_list_service_mac.h
@@ -38,6 +38,8 @@
   virtual bool IsAppListVisible() const OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
+  virtual Profile* GetCurrentAppListProfile() OVERRIDE;
+
 
   // AppListServiceImpl overrides:
   virtual void CreateShortcut() OVERRIDE;
@@ -64,6 +66,7 @@
   base::scoped_nsobject<AppListAnimationController> animation_controller_;
   base::scoped_nsobject<NSRunningApplication> previously_active_application_;
   NSPoint last_start_origin_;
+  Profile* profile_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListServiceMac);
 };
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm
index 193a93d..513cd1f 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -14,14 +14,15 @@
 #include "base/lazy_instance.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
@@ -79,31 +80,6 @@
 // Distance towards the screen edge that the app list moves from when showing.
 const CGFloat kDistanceMovedOnShow = 20;
 
-class AppListControllerDelegateCocoa : public AppListControllerDelegate {
- public:
-  AppListControllerDelegateCocoa();
-  virtual ~AppListControllerDelegateCocoa();
-
- private:
-  // AppListControllerDelegate overrides:
-  virtual void DismissView() OVERRIDE;
-  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
-  virtual Pinnable GetPinnable() OVERRIDE;
-  virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
-  virtual void ActivateApp(Profile* profile,
-                           const extensions::Extension* extension,
-                           AppListSource source,
-                           int event_flags) OVERRIDE;
-  virtual void LaunchApp(Profile* profile,
-                         const extensions::Extension* extension,
-                         AppListSource source,
-                         int event_flags) OVERRIDE;
-  virtual void ShowForProfileByPath(
-      const base::FilePath& profile_path) OVERRIDE;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateCocoa);
-};
-
 ShellIntegration::ShortcutInfo GetAppListShortcutInfo(
     const base::FilePath& profile_path) {
   ShellIntegration::ShortcutInfo shortcut_info;
@@ -196,67 +172,6 @@
   return nil;
 }
 
-AppListControllerDelegateCocoa::AppListControllerDelegateCocoa() {}
-
-AppListControllerDelegateCocoa::~AppListControllerDelegateCocoa() {}
-
-void AppListControllerDelegateCocoa::DismissView() {
-  AppListServiceMac::GetInstance()->DismissAppList();
-}
-
-gfx::NativeWindow AppListControllerDelegateCocoa::GetAppListWindow() {
-  return AppListServiceMac::GetInstance()->GetAppListWindow();
-}
-
-AppListControllerDelegate::Pinnable
-    AppListControllerDelegateCocoa::GetPinnable() {
-  return NO_PIN;
-}
-
-void AppListControllerDelegateCocoa::CreateNewWindow(
-    Profile* profile, bool incognito) {
-  Profile* window_profile = incognito ?
-      profile->GetOffTheRecordProfile() : profile;
-  chrome::NewEmptyWindow(window_profile, chrome::GetActiveDesktop());
-}
-
-void AppListControllerDelegateCocoa::ActivateApp(
-    Profile* profile,
-    const extensions::Extension* extension,
-    AppListSource source,
-    int event_flags) {
-  LaunchApp(profile, extension, source, event_flags);
-}
-
-void AppListControllerDelegateCocoa::LaunchApp(
-    Profile* profile,
-    const extensions::Extension* extension,
-    AppListSource source,
-    int event_flags) {
-  AppListServiceImpl::RecordAppListAppLaunch();
-
-  AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB);
-
-  if (source != LAUNCH_FROM_UNKNOWN &&
-      extension->id() == extension_misc::kWebStoreAppId) {
-    // Set an override URL to include the source.
-    GURL extension_url = extensions::AppLaunchInfo::GetFullLaunchURL(extension);
-    params.override_url = net::AppendQueryParameter(
-        extension_url,
-        extension_urls::kWebstoreSourceField,
-        AppListSourceToString(source));
-  }
-
-  OpenApplication(params);
-}
-
-void AppListControllerDelegateCocoa::ShowForProfileByPath(
-    const base::FilePath& profile_path) {
-  AppListService* service = AppListServiceMac::GetInstance();
-  service->SetProfilePath(profile_path);
-  service->Show();
-}
-
 enum DockLocation {
   DockLocationOtherDisplay,
   DockLocationBottom,
@@ -376,7 +291,8 @@
 
 }  // namespace
 
-AppListServiceMac::AppListServiceMac() {
+AppListServiceMac::AppListServiceMac()
+    : profile_(NULL) {
   animation_controller_.reset([[AppListAnimationController alloc] init]);
 }
 
@@ -418,11 +334,15 @@
                                         AppListServiceMac::GetInstance());
 }
 
+Profile* AppListServiceMac::GetCurrentAppListProfile() {
+  return profile_;
+}
+
 void AppListServiceMac::CreateForProfile(Profile* requested_profile) {
-  if (profile() == requested_profile)
+  if (profile_ == requested_profile)
     return;
 
-  SetProfile(requested_profile);
+  profile_ = requested_profile;
 
   if (window_controller_) {
     // Clear the search box.
@@ -435,7 +355,7 @@
   scoped_ptr<app_list::AppListViewDelegate> delegate(
       new AppListViewDelegate(
           scoped_ptr<AppListControllerDelegate>(
-              new AppListControllerDelegateCocoa()), profile()));
+              new AppListControllerDelegateImpl(this)), profile_));
   [[window_controller_ appListViewController] setDelegate:delegate.Pass()];
 }
 
@@ -445,7 +365,7 @@
 
   InvalidatePendingProfileLoads();
 
-  if (requested_profile == profile()) {
+  if (requested_profile == profile_) {
     ShowWindowNearDock();
     return;
   }
@@ -495,7 +415,7 @@
 }
 
 AppListControllerDelegate* AppListServiceMac::CreateControllerDelegate() {
-  return new AppListControllerDelegateCocoa();
+  return new AppListControllerDelegateImpl(this);
 }
 
 void AppListServiceMac::OnShimLaunch(apps::AppShimHandler::Host* host,
@@ -544,13 +464,13 @@
 }
 
 // static
-AppListService* AppListService::Get() {
+AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) {
   return AppListServiceMac::GetInstance();
 }
 
 // static
 void AppListService::InitAll(Profile* initial_profile) {
-  Get()->Init(initial_profile);
+  AppListServiceMac::GetInstance()->Init(initial_profile);
 }
 
 @implementation AppListAnimationController
diff --git a/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm b/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
index 0a8c5df..073f066 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
@@ -63,7 +63,8 @@
   // Check that AppListService has registered as a shim handler for "app_list".
   EXPECT_TRUE(AppShimHandler::GetForAppMode(app_mode::kAppListModeId));
 
-  AppListService* service = AppListService::Get();
+  AppListService* service =
+      AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE);
   EXPECT_FALSE(service->IsAppListVisible());
 
   // With no saved profile, the default profile should be chosen and saved.
diff --git a/chrome/browser/ui/app_list/app_list_service_unittest.cc b/chrome/browser/ui/app_list/app_list_service_unittest.cc
index 9ad7aee..a22fdd2 100644
--- a/chrome/browser/ui/app_list/app_list_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_service_unittest.cc
@@ -42,6 +42,12 @@
     AppListServiceImpl::HandleCommandLineFlags(profile);
   }
 
+  virtual Profile* GetCurrentAppListProfile() OVERRIDE {
+    // We don't return showing_for_profile_ here because that is only defined if
+    // the app list is visible.
+    return NULL;
+  }
+
   virtual void CreateForProfile(Profile* requested_profile) OVERRIDE {
   }
 
diff --git a/chrome/browser/ui/app_list/app_list_shower.h b/chrome/browser/ui/app_list/app_list_shower.h
index bbadd9a..9d3fe1b 100644
--- a/chrome/browser/ui/app_list/app_list_shower.h
+++ b/chrome/browser/ui/app_list/app_list_shower.h
@@ -38,6 +38,8 @@
     return app_list_.get();
   }
 
+  Profile* profile() const { return profile_; }
+
   // Create or recreate, and initialize |app_list_| from |requested_profile|.
   void CreateViewForProfile(Profile* requested_profile);
 
diff --git a/chrome/browser/ui/app_list/app_list_util.cc b/chrome/browser/ui/app_list/app_list_util.cc
new file mode 100644
index 0000000..67e56e7
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_util.cc
@@ -0,0 +1,71 @@
+// Copyright 2013 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/app_list/app_list_util.h"
+
+#include "base/metrics/field_trial.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+#if defined(ENABLE_APP_LIST)
+// The field trial group name that enables showing the promo.
+const char kShowLauncherPromoOnceGroupName[] = "ShowPromoUntilDismissed";
+
+// The field trial group name that resets the pref to show the app launcher
+// promo on every session startup.
+const char kResetShowLauncherPromoPrefGroupName[] = "ResetShowPromoPref";
+
+// The name of the field trial that controls showing the app launcher promo.
+const char kLauncherPromoTrialName[] = "ShowAppLauncherPromo";
+#endif  // defined(ENABLE_APP_LIST)
+
+}  // namespace
+
+void SetupShowAppLauncherPromoFieldTrial(PrefService* local_state) {
+#if defined(ENABLE_APP_LIST)
+  if (base::FieldTrialList::FindFullName(kLauncherPromoTrialName) ==
+      kResetShowLauncherPromoPrefGroupName) {
+    local_state->SetBoolean(prefs::kShowAppLauncherPromo, true);
+  }
+#endif
+}
+
+bool IsAppLauncherEnabled() {
+#if !defined(ENABLE_APP_LIST)
+  return false;
+
+#elif defined(OS_CHROMEOS)
+  return true;
+
+#else  // defined(ENABLE_APP_LIST) && !defined(OS_CHROMEOS)
+  if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
+    return true;
+
+  PrefService* prefs = g_browser_process->local_state();
+  // In some tests, the prefs aren't initialised.
+  return prefs && prefs->GetBoolean(prefs::kAppLauncherHasBeenEnabled);
+#endif
+}
+
+bool ShouldShowAppLauncherPromo() {
+#if !defined(ENABLE_APP_LIST)
+  return false;
+#else
+  PrefService* local_state = g_browser_process->local_state();
+  // In some tests, the prefs aren't initialised.
+  if (!local_state)
+    return false;
+  std::string app_launcher_promo_group_name =
+      base::FieldTrialList::FindFullName(kLauncherPromoTrialName);
+  return !IsAppLauncherEnabled() &&
+      local_state->GetBoolean(prefs::kShowAppLauncherPromo) &&
+      (app_launcher_promo_group_name == kShowLauncherPromoOnceGroupName ||
+       app_launcher_promo_group_name == kResetShowLauncherPromoPrefGroupName);
+#endif
+}  // namespace apps
diff --git a/chrome/browser/ui/app_list/app_list_util.h b/chrome/browser/ui/app_list/app_list_util.h
new file mode 100644
index 0000000..9d6bab7
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_util.h
@@ -0,0 +1,21 @@
+// Copyright 2013 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_APP_LIST_APP_LIST_UTIL_H_
+#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_UTIL_H_
+
+#include "base/callback_forward.h"
+
+class PrefService;
+
+// Does initializiation for the ShowAppLauncherPromo field trial.
+void SetupShowAppLauncherPromoFieldTrial(PrefService* local_state);
+
+// Returns whether the app launcher has been enabled.
+bool IsAppLauncherEnabled();
+
+// Returns whether the app launcher promo should be shown.
+bool ShouldShowAppLauncherPromo();
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_UTIL_H_
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 89d54fe..61cb6a5 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -255,8 +255,7 @@
 void AppListViewDelegate::OpenFeedback() {
   chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow(
       controller_->GetAppListWindow());
-  Browser* browser = chrome::FindOrCreateTabbedBrowser(
-      profile_, desktop);
+  Browser* browser = chrome::FindTabbedBrowser(profile_, false, desktop);
   chrome::ShowFeedbackPage(browser, std::string(),
                            chrome::kAppLauncherCategoryTag);
 }
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 6d1f9aa..dbeaa11 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -85,13 +85,7 @@
   Reload();
   GetExtensionSorting(profile_)->EnsureValidOrdinals(extension_id_,
                                                      syncer::StringOrdinal());
-  // Set |sort_order_|. Use '_' as a separator to ensure a_a preceeds aa_a.
-  // (StringOrdinal uses 'a'-'z').
-  const syncer::StringOrdinal& page =
-      GetExtensionSorting(profile_)->GetPageOrdinal(extension_id_);
-  const syncer::StringOrdinal& launch =
-     GetExtensionSorting(profile_)->GetAppLaunchOrdinal(extension_id_);
-  sort_order_ = page.ToInternalValue() + '_' + launch.ToInternalValue();
+  UpdatePositionFromExtensionOrdering();
 }
 
 ExtensionAppItem::~ExtensionAppItem() {
@@ -130,9 +124,7 @@
 
   const ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
-  // If app waits for permission confirmation, don't show it disabled in UI.
-  const bool enabled = service->IsExtensionEnabledForLauncher(extension_id_) ||
-      service->DoesExtensionRequirePermissionConsent(extension_id_);
+  const bool enabled = service->IsExtensionEnabledForLauncher(extension_id_);
   if (!enabled) {
     const color_utils::HSL shift = {-1, 0, 0.6};
     icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
@@ -171,6 +163,7 @@
   service->extension_prefs()->SetAppDraggedByUser(extension_id_);
   sorting->SetPageOrdinal(extension_id_, page);
   service->OnExtensionMoved(extension_id_, prev_id, next_id);
+  UpdatePositionFromExtensionOrdering();
 }
 
 const Extension* ExtensionAppItem::GetExtension() const {
@@ -242,10 +235,6 @@
   controller_->OnCloseExtensionPrompt();
 }
 
-std::string ExtensionAppItem::GetSortOrder() const {
-  return sort_order_;
-}
-
 void ExtensionAppItem::Activate(int event_flags) {
   // |extension| could be NULL when it is being unloaded for updating.
   const Extension* extension = GetExtension();
@@ -282,3 +271,12 @@
 void ExtensionAppItem::ExecuteLaunchCommand(int event_flags) {
   Launch(event_flags);
 }
+
+void ExtensionAppItem::UpdatePositionFromExtensionOrdering() {
+  const syncer::StringOrdinal& page =
+      GetExtensionSorting(profile_)->GetPageOrdinal(extension_id_);
+  const syncer::StringOrdinal& launch =
+     GetExtensionSorting(profile_)->GetAppLaunchOrdinal(extension_id_);
+  set_position(syncer::StringOrdinal(
+      page.ToInternalValue() + launch.ToInternalValue()));
+}
diff --git a/chrome/browser/ui/app_list/extension_app_item.h b/chrome/browser/ui/app_list/extension_app_item.h
index eb56f42..362a016 100644
--- a/chrome/browser/ui/app_list/extension_app_item.h
+++ b/chrome/browser/ui/app_list/extension_app_item.h
@@ -85,7 +85,6 @@
   virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
 
   // Overridden from AppListItemModel:
-  virtual std::string GetSortOrder() const OVERRIDE;
   virtual void Activate(int event_flags) OVERRIDE;
   virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
   virtual const char* GetAppType() const OVERRIDE;
@@ -93,6 +92,9 @@
   // Overridden from app_list::AppContextMenuDelegate:
   virtual void ExecuteLaunchCommand(int event_flags) OVERRIDE;
 
+  // Set the position from the extension ordering.
+  void UpdatePositionFromExtensionOrdering();
+
   Profile* profile_;
   const std::string extension_id_;
   AppListControllerDelegate* controller_;
@@ -110,11 +112,6 @@
   // Whether or not this app is a platform app.
   bool is_platform_app_;
 
-  // Cache initial sort order. Sort order is not synced with the extensions
-  // app ordering once apps are loaded. This will be ignored (or overridden)
-  // once the app list is synced.
-  std::string sort_order_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionAppItem);
 };
 
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.cc b/chrome/browser/ui/app_list/extension_app_model_builder.cc
index 1f17f6d..63e29a8 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.cc
@@ -48,13 +48,13 @@
       model_(model),
       highlighted_app_pending_(false),
       tracker_(NULL) {
-  model_->apps()->AddObserver(this);
+  model_->item_list()->AddObserver(this);
   SwitchProfile(profile);  // Builds the model.
 }
 
 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
   OnShutdown();
-  model_->apps()->RemoveObserver(this);
+  model_->item_list()->RemoveObserver(this);
 }
 
 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
@@ -123,7 +123,7 @@
 
 void ExtensionAppModelBuilder::OnExtensionUninstalled(
     const Extension* extension) {
-  model_->DeleteItem(extension->id());
+  model_->item_list()->DeleteItem(extension->id());
 }
 
 void ExtensionAppModelBuilder::OnAppsReordered() {
@@ -162,12 +162,7 @@
   profile_ = profile;
 
   // Delete any extension apps.
-  app_list::AppListModel::Apps* app_list = model_->apps();
-  for (int i = static_cast<int>(app_list->item_count()) - 1; i >= 0; --i) {
-    app_list::AppListItemModel* item = app_list->GetItemAt(i);
-    if (item->GetAppType() == ExtensionAppItem::kAppType)
-      app_list->DeleteAt(i);
-  }
+  model_->item_list()->DeleteItemsByType(ExtensionAppItem::kAppType);
 
   if (tracker_)
     tracker_->RemoveObserver(this);
@@ -204,7 +199,7 @@
 }
 
 void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem* app) {
-  model_->AddItem(app);
+  model_->item_list()->AddItem(app);
 }
 
 void ExtensionAppModelBuilder::SetHighlightedApp(
@@ -223,7 +218,8 @@
 
 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
     const std::string& extension_id) {
-  app_list::AppListItemModel* item = model_->FindItem(extension_id);
+  app_list::AppListItemModel* item =
+      model_->item_list()->FindItem(extension_id);
   LOG_IF(ERROR, item &&
          item->GetAppType() != ExtensionAppItem::kAppType)
       << "App Item matching id: " << extension_id
@@ -242,39 +238,33 @@
   highlighted_app_pending_ = false;
 }
 
-void ExtensionAppModelBuilder::ListItemsAdded(size_t start, size_t count) {
-}
-
-void ExtensionAppModelBuilder::ListItemsRemoved(size_t start, size_t count) {
-}
-
-void ExtensionAppModelBuilder::ListItemMoved(size_t index,
-                                             size_t target_index) {
-  app_list::AppListModel::Apps* app_list = model_->apps();
-  app_list::AppListItemModel* item = app_list->GetItemAt(target_index);
+void ExtensionAppModelBuilder::OnListItemMoved(
+    size_t from_index,
+    size_t to_index,
+    app_list::AppListItemModel* item) {
+  // This will get called from AppListItemList::ListItemMoved after
+  // set_position is called for the item.
+  app_list::AppListItemList* item_list = model_->item_list();
   if (item->GetAppType() != ExtensionAppItem::kAppType)
     return;
 
   ExtensionAppItem* prev = NULL;
-  for (size_t idx = target_index; idx > 1; --idx) {
-    app_list::AppListItemModel* item = app_list->GetItemAt(idx - 1);
+  for (size_t idx = to_index; idx > 0; --idx) {
+    app_list::AppListItemModel* item = item_list->item_at(idx - 1);
     if (item->GetAppType() == ExtensionAppItem::kAppType) {
       prev = static_cast<ExtensionAppItem*>(item);
       break;
     }
   }
   ExtensionAppItem* next = NULL;
-  for (size_t idx = target_index; idx < app_list->item_count() - 1; ++idx) {
-    app_list::AppListItemModel* item = app_list->GetItemAt(idx + 1);
+  for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
+    app_list::AppListItemModel* item = item_list->item_at(idx + 1);
     if (item->GetAppType() == ExtensionAppItem::kAppType) {
       next = static_cast<ExtensionAppItem*>(item);
       break;
     }
   }
+  // item->Move will call set_position, overriding the item's position.
   if (prev || next)
     static_cast<ExtensionAppItem*>(item)->Move(prev, next);
 }
-
-void ExtensionAppModelBuilder::ListItemsChanged(size_t start, size_t count) {
-  NOTREACHED();
-}
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.h b/chrome/browser/ui/app_list/extension_app_model_builder.h
index 50cfb9e..48452ee 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.h
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.h
@@ -30,7 +30,7 @@
 // This class populates and maintains the given |model| with information from
 // |profile|.
 class ExtensionAppModelBuilder : public extensions::InstallObserver,
-                                 public ui::ListModelObserver {
+                                 public app_list::AppListItemListObserver {
  public:
   ExtensionAppModelBuilder(Profile* profile,
                            app_list::AppListModel* model,
@@ -65,11 +65,10 @@
       const std::string& extension_id) OVERRIDE;
   virtual void OnShutdown() OVERRIDE;
 
-  // ui::ListModelObserver
-  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
-  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
-  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
-  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+  // AppListItemListObserver
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               app_list::AppListItemModel* item) OVERRIDE;
 
   // Adds apps in |extensions| to |apps|.
   void AddApps(const ExtensionSet* extensions, ExtensionAppList* apps);
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
index bfd3cdd..2354c83 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
@@ -32,10 +32,10 @@
 // Get a string of all apps in |model| joined with ','.
 std::string GetModelContent(app_list::AppListModel* model) {
   std::string content;
-  for (size_t i = 0; i < model->apps()->item_count(); ++i) {
+  for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
     if (i > 0)
       content += ',';
-    content += model->apps()->GetItemAt(i)->title();
+    content += model->item_list()->item_at(i)->title();
   }
   return content;
 }
@@ -285,15 +285,15 @@
 
 TEST_F(ExtensionAppModelBuilderTest, SwitchProfile) {
   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
-  EXPECT_EQ(kDefaultAppCount, model_->apps()->item_count());
+  EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
 
   // Switch to a profile with no apps, ensure all apps are removed.
   TestingProfile::Builder profile_builder;
   scoped_ptr<TestingProfile> profile2(profile_builder.Build());
   builder.SwitchProfile(profile2.get());
-  EXPECT_EQ(0u, model_->apps()->item_count());
+  EXPECT_EQ(0u, model_->item_list()->item_count());
 
   // Switch back to the main profile, ensure apps are restored.
   builder.SwitchProfile(profile_.get());
-  EXPECT_EQ(kDefaultAppCount, model_->apps()->item_count());
+  EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
 }
diff --git a/chrome/browser/ui/app_list/extension_uninstaller.cc b/chrome/browser/ui/app_list/extension_uninstaller.cc
new file mode 100644
index 0000000..ee0c7bd
--- /dev/null
+++ b/chrome/browser/ui/app_list/extension_uninstaller.cc
@@ -0,0 +1,59 @@
+// Copyright 2013 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/app_list/extension_uninstaller.h"
+
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/common/extensions/extension.h"
+
+ExtensionUninstaller::ExtensionUninstaller(
+    Profile* profile,
+    const std::string& extension_id,
+    AppListControllerDelegate* controller)
+    : profile_(profile),
+      app_id_(extension_id),
+      controller_(controller) {
+}
+
+ExtensionUninstaller::~ExtensionUninstaller() {
+}
+
+void ExtensionUninstaller::Run() {
+  const extensions::Extension* extension =
+      extensions::ExtensionSystem::Get(profile_)->extension_service()->
+          GetInstalledExtension(app_id_);
+  if (!extension) {
+    CleanUp();
+    return;
+  }
+  controller_->OnShowExtensionPrompt();
+  dialog_.reset(ExtensionUninstallDialog::Create(profile_, NULL, this));
+  dialog_->ConfirmUninstall(extension);
+}
+
+void ExtensionUninstaller::ExtensionUninstallAccepted() {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  const extensions::Extension* extension =
+      service->GetInstalledExtension(app_id_);
+  if (extension) {
+    service->UninstallExtension(app_id_,
+                                false, /* external_uninstall*/
+                                NULL);
+  }
+  controller_->OnCloseExtensionPrompt();
+  CleanUp();
+}
+
+void ExtensionUninstaller::ExtensionUninstallCanceled() {
+  controller_->OnCloseExtensionPrompt();
+  CleanUp();
+}
+
+void ExtensionUninstaller::CleanUp() {
+  delete this;
+}
diff --git a/chrome/browser/ui/app_list/extension_uninstaller.h b/chrome/browser/ui/app_list/extension_uninstaller.h
new file mode 100644
index 0000000..e4a3f92
--- /dev/null
+++ b/chrome/browser/ui/app_list/extension_uninstaller.h
@@ -0,0 +1,40 @@
+// Copyright 2013 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_APP_LIST_EXTENSION_UNINSTALLER_H_
+#define CHROME_BROWSER_UI_APP_LIST_EXTENSION_UNINSTALLER_H_
+
+#include "chrome/browser/extensions/extension_uninstall_dialog.h"
+
+class AppListControllerDelegate;
+class Profile;
+
+// ExtensionUninstaller runs the extension uninstall flow. It shows the
+// extension uninstall dialog and wait for user to confirm or cancel the
+// uninstall.
+class ExtensionUninstaller : public ExtensionUninstallDialog::Delegate {
+ public:
+  ExtensionUninstaller(Profile* profile,
+                       const std::string& extension_id,
+                       AppListControllerDelegate* controller);
+  virtual ~ExtensionUninstaller();
+
+  void Run();
+
+ private:
+  // Overridden from ExtensionUninstallDialog::Delegate:
+  virtual void ExtensionUninstallAccepted() OVERRIDE;
+  virtual void ExtensionUninstallCanceled() OVERRIDE;
+  void CleanUp();
+
+  Profile* profile_;
+  std::string app_id_;
+  AppListControllerDelegate* controller_;
+  scoped_ptr<ExtensionUninstallDialog> dialog_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstaller);
+};
+
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_EXTENSION_UNINSTALLER_H_
diff --git a/chrome/browser/ui/app_list/fast_show_pickler.cc b/chrome/browser/ui/app_list/fast_show_pickler.cc
index 80b2c0f..0119b03 100644
--- a/chrome/browser/ui/app_list/fast_show_pickler.cc
+++ b/chrome/browser/ui/app_list/fast_show_pickler.cc
@@ -207,23 +207,23 @@
     return scoped_ptr<Pickle>();
   if (!result->WriteBool(model->signed_in()))
     return scoped_ptr<Pickle>();
-  if (!result->WriteInt((int) model->apps()->item_count()))
+  if (!result->WriteInt((int) model->item_list()->item_count()))
     return scoped_ptr<Pickle>();
-  for (size_t i = 0; i < model->apps()->item_count(); ++i) {
-    if (!PickleAppListItemModel(result.get(), model->apps()->GetItemAt(i)))
+  for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
+    if (!PickleAppListItemModel(result.get(), model->item_list()->item_at(i)))
       return scoped_ptr<Pickle>();
   }
   return result.Pass();
 }
 
 void FastShowPickler::CopyOver(AppListModel* src, AppListModel* dest) {
-  dest->apps()->DeleteAll();
+  dest->item_list()->DeleteItemsByType(NULL /* all items */);
   dest->SetSignedIn(src->signed_in());
-  for (size_t i = 0; i < src->apps()->item_count(); i++) {
-    AppListItemModel* src_item = src->apps()->GetItemAt(i);
+  for (size_t i = 0; i < src->item_list()->item_count(); i++) {
+    AppListItemModel* src_item = src->item_list()->item_at(i);
     AppListItemModel* dest_item = new AppListItemModel(src_item->id());
     CopyOverItem(src_item, dest_item);
-    dest->apps()->Add(dest_item);
+    dest->item_list()->AddItem(dest_item);
   }
 }
 
@@ -248,7 +248,7 @@
     scoped_ptr<AppListItemModel> item(UnpickleAppListItemModel(&it).Pass());
     if (!item)
       return scoped_ptr<AppListModel>();
-    model->apps()->Add(item.release());
+    model->item_list()->AddItem(item.release());
   }
 
   return model.Pass();
diff --git a/chrome/browser/ui/app_list/search/common/webservice_cache.cc b/chrome/browser/ui/app_list/search/common/webservice_cache.cc
index 0821312..ff0e15f 100644
--- a/chrome/browser/ui/app_list/search/common/webservice_cache.cc
+++ b/chrome/browser/ui/app_list/search/common/webservice_cache.cc
@@ -4,45 +4,158 @@
 
 #include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
 
+#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
+#include "content/public/browser/browser_context.h"
 
 namespace app_list {
 namespace {
 
-const int kWebserviceCacheMaxSize = 100;
-const int kWebserviceCacheTimeLimitInMinutes = 1;
+const unsigned int kWebserviceCacheMaxSize = 1000;
+const unsigned int kWebserviceCacheTimeLimitInMinutes = 1;
+
+const char kKeyResultTime[] = "time";
+const char kKeyResult[] = "result";
+
+const char kWebstoreQueryPrefix[] = "webstore:";
+const char kPeopleQueryPrefix[] = "people:";
 
 }  // namespace
 
-void WebserviceCache::CacheDeletor::operator()(
-    WebserviceCache::Payload& payload) {
-  delete payload.second;
+void WebserviceCache::CacheDeletor::operator()(Payload& payload) {
+  delete payload.result;
 }
 
-WebserviceCache::WebserviceCache()
-    : cache_(kWebserviceCacheMaxSize) {
+WebserviceCache::WebserviceCache(content::BrowserContext* context)
+    : cache_(Cache::NO_AUTO_EVICT),
+      cache_loaded_(false) {
+  const char kStoreDataFileName[] = "Webservice Search Cache";
+  const base::FilePath data_file =
+      context->GetPath().AppendASCII(kStoreDataFileName);
+  data_store_ = new DictionaryDataStore(data_file);
+  data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr()));
 }
 
 WebserviceCache::~WebserviceCache() {
 }
 
-const base::DictionaryValue* WebserviceCache::Get(const std::string& query) {
-  Cache::iterator iter = cache_.Get(query);
+const CacheResult WebserviceCache::Get(QueryType type,
+                                       const std::string& query) {
+  std::string typed_query = PrependType(type, query);
+  Cache::iterator iter = cache_.Get(typed_query);
   if (iter != cache_.end()) {
-    if (base::Time::Now() - iter->second.first <=
+    if (base::Time::Now() - iter->second.time <=
         base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) {
-      return iter->second.second;
+      return std::make_pair(FRESH, iter->second.result);
     } else {
-      cache_.Erase(iter);
+      return std::make_pair(STALE, iter->second.result);
     }
   }
-  return NULL;
+  return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL));
 }
 
-void WebserviceCache::Put(const std::string& query,
+void WebserviceCache::Put(QueryType type,
+                          const std::string& query,
                           scoped_ptr<base::DictionaryValue> result) {
-  if (result)
-    cache_.Put(query, std::make_pair(base::Time::Now(), result.release()));
+  if (result) {
+    std::string typed_query = PrependType(type, query);
+    Payload payload(base::Time::Now(), result.release());
+
+    cache_.Put(typed_query, payload);
+    // If the cache isn't loaded yet, we're fine with losing queries since
+    // a 1000 entry cache should load really quickly so the chance of a user
+    // already having typed a 3 character search before the cache has loaded is
+    // very unlikely.
+    if (cache_loaded_) {
+      data_store_->cached_dict()->Set(typed_query, DictFromPayload(payload));
+      data_store_->ScheduleWrite();
+      if (cache_.size() > kWebserviceCacheMaxSize)
+        TrimCache();
+    }
+  }
+}
+
+void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) {
+  if (!data_store_->cached_dict())
+    return;
+
+  std::vector<std::string> cleanup_keys;
+  for (DictionaryValue::Iterator it(*data_store_->cached_dict());
+      !it.IsAtEnd();
+      it.Advance()) {
+    const base::DictionaryValue* payload_dict;
+    Payload payload;
+    if (!it.value().GetAsDictionary(&payload_dict) ||
+        !payload_dict ||
+        !PayloadFromDict(payload_dict, &payload)) {
+      // In case we don't have a valid payload associated with a given query,
+      // clean up that query from our data store.
+      cleanup_keys.push_back(it.key());
+      continue;
+    }
+    cache_.Put(it.key(), payload);
+  }
+
+  if (!cleanup_keys.empty()) {
+    for (size_t i = 0; i < cleanup_keys.size(); ++i)
+      data_store_->cached_dict()->Remove(cleanup_keys[i], NULL);
+    data_store_->ScheduleWrite();
+  }
+  cache_loaded_ = true;
+}
+
+bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict,
+                                      Payload* payload) {
+  std::string time_string;
+  if (!dict->GetString(kKeyResultTime, &time_string))
+    return false;
+  const base::DictionaryValue* result;
+  if (!dict->GetDictionary(kKeyResult, &result))
+    return false;
+
+  int64 time_val;
+  base::StringToInt64(time_string, &time_val);
+
+  // The result dictionary will be owned by the cache, hence create a copy
+  // instead of returning the original reference. The new dictionary will be
+  // owned by our MRU cache.
+  *payload = Payload(base::Time::FromInternalValue(time_val),
+                     result->DeepCopy());
+  return true;
+}
+
+base::DictionaryValue* WebserviceCache::DictFromPayload(
+    const Payload& payload) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetString(kKeyResultTime, base::Int64ToString(
+      payload.time.ToInternalValue()));
+  // The payload will still keep ownership of it's result dict, hence put a
+  // a copy of the result dictionary here. This dictionary will be owned by
+  // data_store_->cached_dict().
+  dict->Set(kKeyResult, payload.result->DeepCopy());
+
+  return dict;
+}
+
+void WebserviceCache::TrimCache() {
+  for (Cache::size_type i = cache_.size(); i > kWebserviceCacheMaxSize; i--) {
+    Cache::reverse_iterator rbegin = cache_.rbegin();
+    data_store_->cached_dict()->Remove(rbegin->first, NULL);
+    cache_.Erase(rbegin);
+  }
+  data_store_->ScheduleWrite();
+}
+
+std::string WebserviceCache::PrependType(
+    QueryType type, const std::string& query) {
+  switch (type) {
+    case WEBSTORE:
+      return kWebstoreQueryPrefix + query;
+    case PEOPLE:
+      return kPeopleQueryPrefix + query;
+    default:
+      return query;
+  }
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/common/webservice_cache.h b/chrome/browser/ui/app_list/search/common/webservice_cache.h
index 942e8c5..8bedd16 100644
--- a/chrome/browser/ui/app_list/search/common/webservice_cache.h
+++ b/chrome/browser/ui/app_list/search/common/webservice_cache.h
@@ -9,40 +9,101 @@
 
 #include "base/basictypes.h"
 #include "base/containers/mru_cache.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
+#include "chrome/browser/ui/app_list/search/common/dictionary_data_store.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
 namespace base {
 class DictionaryValue;
 }
 
+namespace content {
+class BrowserContext;
+}
+
 namespace app_list {
 
+enum ResultStatus {
+  FRESH = 0,
+  STALE = 1
+};
+
+// Pair of values, first indicating whether this is a fresh result or stale,
+// the second holding the actual value.
+typedef std::pair<ResultStatus, const base::DictionaryValue*> CacheResult;
+
 // WebserviceCache manages a cache of search results which should be valid
 // during an input session. This will reduce unnecessary queries for typing
 // backspace or so on. This is not meant to hold cache entries across multiple
 // search sessions.
-class WebserviceCache {
+class WebserviceCache : public BrowserContextKeyedService,
+                        public base::SupportsWeakPtr<WebserviceCache> {
  public:
-  WebserviceCache();
-  ~WebserviceCache();
+  enum QueryType {
+    WEBSTORE = 0,
+    PEOPLE = 1
+  };
+
+  explicit WebserviceCache(content::BrowserContext* context);
+  virtual ~WebserviceCache();
 
   // Checks the current cache and returns the value for the |query| if it's
-  // valid. Otherwise returns NULL.
-  const base::DictionaryValue* Get(const std::string& query);
+  // valid. Otherwise an CacheResult object with the result field set to NULL.
+  // A query consists of a query 'type' and the query itself. The two current
+  // types of queries supported are webstore queries and people search queries.
+  // The type silos the query into it's own separate domain, preventing any
+  // mixing of the queries.
+  const CacheResult Get(QueryType type, const std::string& query);
 
   // Puts the new result to the query.
-  void Put(const std::string& query, scoped_ptr<base::DictionaryValue> result);
+  void Put(QueryType type,
+           const std::string& query,
+           scoped_ptr<base::DictionaryValue> result);
 
  private:
-  typedef std::pair<base::Time, base::DictionaryValue*> Payload;
+  struct Payload {
+    Payload(const base::Time& time,
+            const base::DictionaryValue* result)
+        : time(time), result(result) {}
+    Payload() {}
+
+    base::Time time;
+    const base::DictionaryValue* result;
+  };
+
   class CacheDeletor {
    public:
     void operator()(Payload& payload);
   };
   typedef base::MRUCacheBase<std::string, Payload, CacheDeletor> Cache;
 
+  // Callback for when the cache is loaded from the dictionary data store.
+  void OnCacheLoaded(scoped_ptr<base::DictionaryValue>);
+
+  // Populates the payload parameter with the corresponding payload stored
+  // in the given dictionary. If the dictionary is invalid for any reason,
+  // this method will return false.
+  bool PayloadFromDict(const base::DictionaryValue* dict,
+                       Payload* payload);
+
+  // Returns a dictionary value for a given payload. The returned dictionary
+  // will be owned by the data_store_ cached_dict, and freed on the destruction
+  // of our dictionary datastore.
+  base::DictionaryValue* DictFromPayload(const Payload& payload);
+
+  // Trims our MRU cache, making sure that any element that is removed is also
+  // removed from the dictionary data store.
+  void TrimCache();
+
+  // Prepends a type string to the given query and returns a new query string.
+  std::string PrependType(QueryType type, const std::string& query);
+
   Cache cache_;
+  scoped_refptr<DictionaryDataStore> data_store_;
+
+  bool cache_loaded_;
 
   DISALLOW_COPY_AND_ASSIGN(WebserviceCache);
 };
diff --git a/chrome/browser/ui/app_list/search/common/webservice_cache_factory.cc b/chrome/browser/ui/app_list/search/common/webservice_cache_factory.cc
new file mode 100644
index 0000000..b87276c
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/common/webservice_cache_factory.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 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/app_list/search/common/webservice_cache_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+namespace app_list {
+
+// static
+WebserviceCacheFactory* WebserviceCacheFactory::GetInstance() {
+  return Singleton<WebserviceCacheFactory>::get();
+}
+
+// static
+WebserviceCache* WebserviceCacheFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<WebserviceCache*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+WebserviceCacheFactory::WebserviceCacheFactory()
+    : BrowserContextKeyedServiceFactory(
+          "app_list::WebserviceCache",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+WebserviceCacheFactory::~WebserviceCacheFactory() {}
+
+BrowserContextKeyedService* WebserviceCacheFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new WebserviceCache(context);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/common/webservice_cache_factory.h b/chrome/browser/ui/app_list/search/common/webservice_cache_factory.h
new file mode 100644
index 0000000..a7ad11b
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/common/webservice_cache_factory.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_APP_LIST_SEARCH_COMMON_WEBSERVICE_CACHE_FACTORY_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_WEBSERVICE_CACHE_FACTORY_H_
+
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+template<typename T> struct DefaultSingletonTraits;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace app_list {
+
+class WebserviceCache;
+
+// Singleton that owns the WebserviceCaches and associates them with profiles;
+class WebserviceCacheFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns singleton instance of WebserviceCacheFactory.
+  static WebserviceCacheFactory* GetInstance();
+
+  // Returns the Webservice cache associated with |context|.
+  static WebserviceCache* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  friend struct DefaultSingletonTraits<WebserviceCacheFactory>;
+
+  WebserviceCacheFactory();
+  virtual ~WebserviceCacheFactory();
+
+  // BrowserContextKeyedServiceFactory overrides:
+  virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(WebserviceCacheFactory);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_WEBSERVICE_CACHE_FACTORY_H_
diff --git a/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc b/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
index f418495..2b77874 100644
--- a/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
@@ -8,7 +8,10 @@
 
 #include "base/callback.h"
 #include "base/strings/string_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
+#include "chrome/browser/ui/app_list/search/common/webservice_cache_factory.h"
 #include "chrome/common/url_constants.h"
 #include "url/gurl.h"
 
@@ -22,7 +25,9 @@
 }  // namespace
 
 WebserviceSearchProvider::WebserviceSearchProvider(Profile* profile)
-    : profile_(profile), use_throttling_(true) {}
+    : profile_(profile),
+      cache_(WebserviceCacheFactory::GetForBrowserContext(profile)),
+      use_throttling_(true) {}
 
 WebserviceSearchProvider::~WebserviceSearchProvider() {}
 
diff --git a/chrome/browser/ui/app_list/search/common/webservice_search_provider.h b/chrome/browser/ui/app_list/search/common/webservice_search_provider.h
index 74ac94f..5aa45db 100644
--- a/chrome/browser/ui/app_list/search/common/webservice_search_provider.h
+++ b/chrome/browser/ui/app_list/search/common/webservice_search_provider.h
@@ -16,6 +16,8 @@
 
 namespace app_list {
 
+class WebserviceCache;
+
 // Helper class for webservice based searches.
 class WebserviceSearchProvider : public SearchProvider {
  public:
@@ -32,10 +34,7 @@
 
  protected:
   Profile* profile_;
-
-  // The cache of the search result which will be valid only in a single
-  // input session.
-  WebserviceCache cache_;
+  WebserviceCache* cache_;  // BrowserContextKeyedService, not owned.
 
  private:
   bool IsSensitiveInput(const string16& query);
diff --git a/chrome/browser/ui/app_list/search/people/people_provider.cc b/chrome/browser/ui/app_list/search/people/people_provider.cc
index 4a9f668..b999034 100644
--- a/chrome/browser/ui/app_list/search/people/people_provider.cc
+++ b/chrome/browser/ui/app_list/search/people/people_provider.cc
@@ -58,14 +58,17 @@
   }
 
   query_ = UTF16ToUTF8(query);
-  const base::DictionaryValue* cached_result = cache_.Get(query_);
-  if (cached_result) {
-    ProcessPeopleSearchResults(cached_result);
+
+  const CacheResult result = cache_->Get(WebserviceCache::PEOPLE, query_);
+  if (result.second) {
+    ProcessPeopleSearchResults(result.second);
     if (!people_search_fetched_callback_.is_null())
       people_search_fetched_callback_.Run();
-    return;
+    if (result.first == FRESH)
+      return;
   }
 
+
   if (!people_search_) {
     people_search_.reset(new JSONResponseFetcher(
         base::Bind(&PeopleProvider::OnPeopleSearchFetched,
@@ -143,7 +146,7 @@
 void PeopleProvider::OnPeopleSearchFetched(
     scoped_ptr<base::DictionaryValue> json) {
   ProcessPeopleSearchResults(json.get());
-  cache_.Put(query_, json.Pass());
+  cache_->Put(WebserviceCache::PEOPLE, query_, json.Pass());
 
   if (!people_search_fetched_callback_.is_null())
     people_search_fetched_callback_.Run();
diff --git a/chrome/browser/ui/app_list/search/people/people_provider.h b/chrome/browser/ui/app_list/search/people/people_provider.h
index b6e1f94..9e0ade2 100644
--- a/chrome/browser/ui/app_list/search/people/people_provider.h
+++ b/chrome/browser/ui/app_list/search/people/people_provider.h
@@ -64,6 +64,7 @@
   // Start the search request with |query_|.
   void StartQuery();
 
+  // Callback for people search results being fetched.
   void OnPeopleSearchFetched(scoped_ptr<base::DictionaryValue> json);
   void ProcessPeopleSearchResults(const base::DictionaryValue* json);
   scoped_ptr<ChromeSearchResult> CreateResult(
diff --git a/chrome/browser/ui/app_list/search/people/people_provider_browsertest.cc b/chrome/browser/ui/app_list/search/people/people_provider_browsertest.cc
index 6f2387e..022e80c 100644
--- a/chrome/browser/ui/app_list/search/people/people_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/people/people_provider_browsertest.cc
@@ -165,13 +165,8 @@
   virtual ~PeopleProviderTest() {}
 
   // InProcessBrowserTest overrides:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    command_line->AppendSwitch(switches::kEnablePeopleSearch);
-  }
-
   virtual void SetUpOnMainThread() OVERRIDE {
-    test_server_.reset(new EmbeddedTestServer(
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
+    test_server_.reset(new EmbeddedTestServer);
 
     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
     test_server_->RegisterRequestHandler(
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 7d8c008..d10756a 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -66,8 +66,8 @@
       new OmniboxProvider(profile_)).Pass());
   AddProvider(Mixer::WEBSTORE_GROUP, scoped_ptr<SearchProvider>(
       new WebstoreProvider(profile_, list_controller_)).Pass());
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kEnablePeopleSearch)) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisablePeopleSearch)) {
     AddProvider(Mixer::PEOPLE_GROUP, scoped_ptr<SearchProvider>(
         new PeopleProvider(profile_)).Pass());
   }
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
index 973fc2e..b22b397 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
@@ -53,12 +53,13 @@
   }
 
   query_ = UTF16ToUTF8(query);
-  const base::DictionaryValue* cached_result = cache_.Get(query_);
-  if (cached_result) {
-    ProcessWebstoreSearchResults(cached_result);
+  const CacheResult result = cache_->Get(WebserviceCache::WEBSTORE, query_);
+  if (result.second) {
+    ProcessWebstoreSearchResults(result.second);
     if (!webstore_search_fetched_callback_.is_null())
       webstore_search_fetched_callback_.Run();
-    return;
+    if (result.first == FRESH)
+      return;
   }
 
   if (UseWebstoreSearch()) {
@@ -96,7 +97,7 @@
 void WebstoreProvider::OnWebstoreSearchFetched(
     scoped_ptr<base::DictionaryValue> json) {
   ProcessWebstoreSearchResults(json.get());
-  cache_.Put(query_, json.Pass());
+  cache_->Put(WebserviceCache::WEBSTORE, query_, json.Pass());
 
   if (!webstore_search_fetched_callback_.is_null())
     webstore_search_fetched_callback_.Run();
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
index 5b6d9eb..8b4eca6 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
@@ -75,8 +75,7 @@
   }
 
   virtual void SetUpOnMainThread() OVERRIDE {
-    test_server_.reset(new EmbeddedTestServer(
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
+    test_server_.reset(new EmbeddedTestServer);
 
     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
     test_server_->RegisterRequestHandler(
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
index 7148365..4610967 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
@@ -7,18 +7,21 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/install_tracker.h"
 #include "chrome/browser/extensions/install_tracker_factory.h"
+#include "chrome/browser/extensions/webstore_ephemeral_installer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
 #include "chrome/browser/ui/app_list/search/webstore/webstore_installer.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -29,10 +32,12 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/canvas_image_source.h"
 
+using extensions::WebstoreEphemeralInstaller;
 
 namespace {
 
 const int kIconSize = 32;
+const int kLaunchEphemeralAppAction = 1;
 
 // BadgedImageSource adds a webstore badge to a webstore app icon.
 class BadgedIconSource : public gfx::CanvasImageSource {
@@ -111,8 +116,7 @@
 }
 
 void WebstoreResult::InvokeAction(int action_index, int event_flags) {
-  DCHECK_EQ(0, action_index);
-  StartInstall();
+  StartInstall(action_index == kLaunchEphemeralAppAction);
 }
 
 scoped_ptr<ChromeSearchResult> WebstoreResult::Duplicate() {
@@ -128,9 +132,20 @@
       extension_service()->GetInstalledExtension(app_id_);
 
   if (!is_otr && !is_installed && !is_installing()) {
-    actions.push_back(Action(
-        l10n_util::GetStringUTF16(IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE),
-        base::string16()));
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableEphemeralApps)) {
+      actions.push_back(Action(
+          l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_INSTALL),
+          l10n_util::GetStringUTF16(
+              IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE)));
+      actions.push_back(Action(
+          l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_LAUNCH),
+          l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_LAUNCH_APP_TOOLTIP)));
+    } else {
+      actions.push_back(Action(
+          l10n_util::GetStringUTF16(IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE),
+          base::string16()));
+    }
   }
 
   SetActions(actions);
@@ -159,10 +174,22 @@
   SetIcon(icon_);
 }
 
-void WebstoreResult::StartInstall() {
+void WebstoreResult::StartInstall(bool launch_ephemeral_app) {
   SetPercentDownloaded(0);
   SetIsInstalling(true);
 
+  if (launch_ephemeral_app) {
+    scoped_refptr<WebstoreEphemeralInstaller> installer =
+        WebstoreEphemeralInstaller::CreateForLauncher(
+            app_id_,
+            profile_,
+            controller_->GetAppListWindow(),
+            base::Bind(&WebstoreResult::InstallCallback,
+                       weak_factory_.GetWeakPtr()));
+    installer->BeginInstall();
+    return;
+  }
+
   scoped_refptr<WebstoreInstaller> installer =
       new WebstoreInstaller(
           app_id_,
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_result.h b/chrome/browser/ui/app_list/search/webstore/webstore_result.h
index b8d7980..07c02d7 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_result.h
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_result.h
@@ -43,7 +43,7 @@
   void SetDefaultDetails();
   void OnIconLoaded();
 
-  void StartInstall();
+  void StartInstall(bool launch_ephemeral_app);
   void InstallCallback(bool success, const std::string& error);
 
   void StartObservingInstall();
diff --git a/chrome/browser/ui/app_list/test/app_list_shower_unittest.cc b/chrome/browser/ui/app_list/test/app_list_shower_unittest.cc
index ac8c4a4..3f32422 100644
--- a/chrome/browser/ui/app_list/test/app_list_shower_unittest.cc
+++ b/chrome/browser/ui/app_list/test/app_list_shower_unittest.cc
@@ -149,6 +149,14 @@
   EXPECT_FALSE(keep_alive_service_->is_keeping_alive());
 }
 
+TEST_F(AppListShowerUnitTest, CloseAppListClearsProfile) {
+  EXPECT_EQ(NULL, shower_->profile());
+  shower_->ShowForProfile(profile1_.get());
+  EXPECT_EQ(profile1_.get(), shower_->profile());
+  shower_->CloseAppList();
+  EXPECT_EQ(NULL, shower_->profile());
+}
+
 TEST_F(AppListShowerUnitTest, SwitchingProfiles) {
   shower_->ShowForProfile(profile1_.get());
   EXPECT_EQ("p1", GetCurrentAppList()->profile_name());
diff --git a/chrome/browser/ui/app_list/test/fake_profile.cc b/chrome/browser/ui/app_list/test/fake_profile.cc
index d21a2d4..41fcb85 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.cc
+++ b/chrome/browser/ui/app_list/test/fake_profile.cc
@@ -55,10 +55,18 @@
 void FakeProfile::RequestMIDISysExPermission(
     int render_process_id,
     int render_view_id,
+    int bridge_id,
     const GURL& requesting_frame,
     const MIDISysExPermissionCallback& callback) {
 }
 
+void FakeProfile::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+}
+
 content::ResourceContext* FakeProfile::GetResourceContext() {
   return NULL;
 }
diff --git a/chrome/browser/ui/app_list/test/fake_profile.h b/chrome/browser/ui/app_list/test/fake_profile.h
index 4849f6d..04e69a0 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.h
+++ b/chrome/browser/ui/app_list/test/fake_profile.h
@@ -46,8 +46,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+        int render_process_id,
+        int render_view_id,
+        int bridge_id,
+        const GURL& requesting_frame) OVERRIDE;
   virtual content::ResourceContext* GetResourceContext() OVERRIDE;
   virtual content::GeolocationPermissionContext*
       GetGeolocationPermissionContext() OVERRIDE;
diff --git a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
index e87fe89..580c3a5 100644
--- a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
+++ b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
@@ -17,17 +17,17 @@
 class AppListModelPicklerUnitTest : public testing::Test {
  protected:
   void CheckIsSame(AppListModel* m1, AppListModel* m2) {
-    ASSERT_EQ(m1->apps()->item_count(), m2->apps()->item_count());
+    ASSERT_EQ(m1->item_list()->item_count(), m2->item_list()->item_count());
     ASSERT_EQ(m1->signed_in(), m2->signed_in());
-    for (size_t i = 0; i < m1->apps()->item_count(); i++) {
-      ASSERT_EQ(m1->apps()->GetItemAt(i)->id(),
-                m2->apps()->GetItemAt(i)->id());
-      ASSERT_EQ(m1->apps()->GetItemAt(i)->title(),
-                m2->apps()->GetItemAt(i)->title());
-      ASSERT_EQ(m1->apps()->GetItemAt(i)->full_name(),
-                m2->apps()->GetItemAt(i)->full_name());
-      CompareImages(m1->apps()->GetItemAt(i)->icon(),
-                    m2->apps()->GetItemAt(i)->icon());
+    for (size_t i = 0; i < m1->item_list()->item_count(); i++) {
+      ASSERT_EQ(m1->item_list()->item_at(i)->id(),
+                m2->item_list()->item_at(i)->id());
+      ASSERT_EQ(m1->item_list()->item_at(i)->title(),
+                m2->item_list()->item_at(i)->title());
+      ASSERT_EQ(m1->item_list()->item_at(i)->full_name(),
+                m2->item_list()->item_at(i)->full_name());
+      CompareImages(m1->item_list()->item_at(i)->icon(),
+                    m2->item_list()->item_at(i)->icon());
     }
   }
 
@@ -79,7 +79,7 @@
   AppListModel model;
   AppListItemModel* app1 = new AppListItemModel("abc");
   app1->SetTitleAndFullName("ht", "hello, there");
-  model.apps()->Add(app1);
+  model.item_list()->AddItem(app1);
 
   DoConsistencyChecks(&model);
 }
@@ -88,11 +88,11 @@
   AppListModel model;
   AppListItemModel* app1 = new AppListItemModel("abc");
   app1->SetTitleAndFullName("ht", "hello, there");
-  model.apps()->Add(app1);
+  model.item_list()->AddItem(app1);
 
   AppListItemModel* app2 = new AppListItemModel("abc2");
   app2->SetTitleAndFullName("ht2", "hello, there 2");
-  model.apps()->Add(app2);
+  model.item_list()->AddItem(app2);
 
   DoConsistencyChecks(&model);
 }
@@ -102,11 +102,11 @@
   AppListItemModel* app1 = new AppListItemModel("abc");
   app1->SetTitleAndFullName("ht", "hello, there");
   app1->SetIcon(MakeImage(), true);
-  model.apps()->Add(app1);
+  model.item_list()->AddItem(app1);
 
   AppListItemModel* app2 = new AppListItemModel("abc2");
   app2->SetTitleAndFullName("ht2", "hello, there 2");
-  model.apps()->Add(app2);
+  model.item_list()->AddItem(app2);
 
   DoConsistencyChecks(&model);
 }
@@ -116,7 +116,7 @@
   AppListItemModel* app1 = new AppListItemModel("abc");
   app1->SetTitleAndFullName("ht", "hello, there");
   app1->SetIcon(gfx::ImageSkia(), true);
-  model.apps()->Add(app1);
+  model.item_list()->AddItem(app1);
 
   DoConsistencyChecks(&model);
 }
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
new file mode 100644
index 0000000..0e80762
--- /dev/null
+++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -0,0 +1,181 @@
+// Copyright 2013 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 "ash/accelerators/accelerator_commands.h"
+
+#include "apps/shell_window.h"
+#include "apps/ui/native_app_window.h"
+#include "ash/shell.h"
+#include "ash/wm/window_state.h"
+#include "base/command_line.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "ui/aura/client/aura_constants.h"
+
+namespace {
+
+// Returns true if |window| is in immersive fullscreen. Infer whether |window|
+// is in immersive fullscreen based on whether the shelf is hidden when
+// |window| is fullscreen because DEPS does not allow the test to use
+// BrowserView. (This is not quite right because the shelf is hidden if a window
+// is in both immersive fullscreen and tab fullscreen.)
+bool IsInImmersiveFullscreen(BrowserWindow* browser_window) {
+  ash::wm::WindowState* window_state = ash::wm::GetWindowState(
+      browser_window->GetNativeWindow());
+  return window_state->IsFullscreen() &&
+      !window_state->hide_shelf_when_fullscreen();
+}
+
+}  // namespace
+
+typedef InProcessBrowserTest AcceleratorCommandsBrowserTest;
+
+// Confirm that toggling window miximized works properly
+IN_PROC_BROWSER_TEST_F(AcceleratorCommandsBrowserTest, ToggleMaximized) {
+  ASSERT_TRUE(ash::Shell::HasInstance()) << "No Instance";
+  ash::wm::WindowState* window_state = ash::wm::GetActiveWindowState();
+  ASSERT_TRUE(window_state);
+
+  // When not in fullscreen, accelerators::ToggleMaximized toggles Maximized.
+  EXPECT_FALSE(window_state->IsMaximized());
+  ash::accelerators::ToggleMaximized();
+  EXPECT_TRUE(window_state->IsMaximized());
+  ash::accelerators::ToggleMaximized();
+  EXPECT_FALSE(window_state->IsMaximized());
+
+  // When in fullscreen accelerators::ToggleMaximized gets out of fullscreen.
+  EXPECT_FALSE(window_state->IsFullscreen());
+  Browser* browser = chrome::FindBrowserWithWindow(window_state->window());
+  ASSERT_TRUE(browser);
+  chrome::ToggleFullscreenMode(browser);
+  EXPECT_TRUE(window_state->IsFullscreen());
+  ash::accelerators::ToggleMaximized();
+  EXPECT_FALSE(window_state->IsFullscreen());
+  EXPECT_FALSE(window_state->IsMaximized());
+  ash::accelerators::ToggleMaximized();
+  EXPECT_FALSE(window_state->IsFullscreen());
+  EXPECT_TRUE(window_state->IsMaximized());
+}
+
+// Confirm that toggling window fullscren works properly.
+IN_PROC_BROWSER_TEST_F(AcceleratorCommandsBrowserTest, ToggleFullscreen) {
+  ASSERT_TRUE(ash::Shell::HasInstance()) << "No Instance";
+  // 1) ToggleFullscreen() should toggle whether a tabbed browser window is in
+  // immersive fullscreen.
+  ASSERT_TRUE(browser()->is_type_tabbed());
+  BrowserWindow* browser_window = browser()->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_TRUE(IsInImmersiveFullscreen(browser_window));
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 2) ToggleFullscreen() should have no effect on windows which cannot be
+  // maximized.
+  browser_window->GetNativeWindow()->SetProperty(aura::client::kCanMaximizeKey,
+                                                 false);
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 3) ToggleFullscreen() should maximize v1 app browser windows which use
+  // AppNonClientFrameViewAsh.
+  // TODO(pkotwicz): Figure out if we actually want this behavior.
+  Browser::CreateParams browser_create_params(Browser::TYPE_POPUP,
+      browser()->profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
+#if defined(OS_WIN)
+  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
+#endif  // OS_WIN
+  browser_create_params.app_name = "Test";
+  browser_create_params.app_type = Browser::APP_TYPE_HOST;
+
+  Browser* app_host_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(app_host_browser->is_app());
+  AddBlankTabAndShow(app_host_browser);
+  browser_window = app_host_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsMaximized());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 4) ToggleFullscreen() should put child windows of v1 apps into
+  // non-immersive fullscreen.
+  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
+  browser_create_params.app_type = Browser::APP_TYPE_CHILD;
+  Browser* app_child_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(app_child_browser->is_app());
+  AddBlankTabAndShow(app_child_browser);
+  browser_window = app_child_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 5) ToggleFullscreen() should put popup browser windows into non-immersive
+  // fullscreen.
+  browser_create_params.app_name = "";
+  Browser* popup_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(popup_browser->is_type_popup());
+  ASSERT_FALSE(popup_browser->is_app());
+  AddBlankTabAndShow(popup_browser);
+  browser_window = popup_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+}
+
+typedef extensions::PlatformAppBrowserTest
+    AcceleratorCommandsPlatformAppBrowserTest;
+
+// Test that ToggleFullscreen() toggles the platform app's fullscreen state.
+IN_PROC_BROWSER_TEST_F(AcceleratorCommandsPlatformAppBrowserTest,
+                       ToggleFullscreenPlatformApp) {
+  ASSERT_TRUE(ash::Shell::HasInstance()) << "No Instance";
+  const extensions::Extension* extension = LoadAndLaunchPlatformApp("minimal");
+  apps::ShellWindow* shell_window = CreateShellWindow(extension);
+  apps::NativeAppWindow* app_window = shell_window->GetBaseWindow();
+  ASSERT_TRUE(shell_window->GetBaseWindow()->IsActive());
+  EXPECT_FALSE(app_window->IsMaximized());
+  EXPECT_FALSE(app_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_TRUE(app_window->IsFullscreen());
+
+  ash::accelerators::ToggleFullscreen();
+  EXPECT_FALSE(app_window->IsMaximized());
+  EXPECT_FALSE(app_window->IsFullscreen());
+
+  CloseShellWindow(shell_window);
+}
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
index 54b4a51..52499b2 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -22,6 +22,10 @@
   return ash::Shell::GetInstance()->GetAppListWindow();
 }
 
+gfx::ImageSkia AppListControllerDelegateAsh::GetWindowIcon() {
+  return gfx::ImageSkia();
+}
+
 bool AppListControllerDelegateAsh::IsAppPinned(
     const std::string& extension_id) {
   return ChromeLauncherController::instance()->IsAppPinned(extension_id);
@@ -41,6 +45,16 @@
       PIN_FIXED;
 }
 
+bool AppListControllerDelegateAsh::CanDoCreateShortcutsFlow() {
+  return false;
+}
+
+void AppListControllerDelegateAsh::DoCreateShortcutsFlow(
+    Profile* profile,
+    const std::string& extension_id) {
+  NOTREACHED();
+}
+
 void AppListControllerDelegateAsh::CreateNewWindow(Profile* profile,
                                                    bool incognito) {
   if (incognito)
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
index bf4c295..1022de0 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
@@ -19,10 +19,14 @@
   // AppListControllerDelegate overrides:
   virtual void DismissView() OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
+  virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
   virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE;
   virtual void PinApp(const std::string& extension_id) OVERRIDE;
   virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
   virtual Pinnable GetPinnable() OVERRIDE;
+  virtual bool CanDoCreateShortcutsFlow() OVERRIDE;
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id) OVERRIDE;
   virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
   virtual void ActivateApp(Profile* profile,
                            const extensions::Extension* extension,
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
index 232e1b1..97dfbeb 100644
--- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -35,6 +35,7 @@
   virtual void DismissAppList() OVERRIDE;
   virtual void EnableAppList(Profile* initial_profile) OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
+  virtual Profile* GetCurrentAppListProfile() OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
 
   DISALLOW_COPY_AND_ASSIGN(AppListServiceAsh);
@@ -72,6 +73,10 @@
   return NULL;
 }
 
+Profile* AppListServiceAsh::GetCurrentAppListProfile() {
+  return ChromeLauncherController::instance()->profile();
+}
+
 AppListControllerDelegate* AppListServiceAsh::CreateControllerDelegate() {
   return new AppListControllerDelegateAsh();
 }
@@ -90,13 +95,13 @@
 #if !defined(OS_WIN)
 
 // static
-AppListService* AppListService::Get() {
+AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) {
   return chrome::GetAppListServiceAsh();
 }
 
 // static
 void AppListService::InitAll(Profile* initial_profile) {
-  Get()->Init(initial_profile);
+  AppListServiceAsh::GetInstance()->Init(initial_profile);
 }
 
 #endif  // !defined(OS_WIN)
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 8fbecad..8fa62e8 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -83,7 +83,7 @@
     chrome::StartKeepAlive();
   }
 #endif
-  ash::Shell::GetPrimaryRootWindow()->ShowRootWindow();
+  ash::Shell::GetPrimaryRootWindow()->GetDispatcher()->ShowRootWindow();
 }
 
 void CloseAsh() {
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
index 9c986f6..b3ecaeb 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
@@ -148,9 +148,13 @@
     NOTIMPLEMENTED();
 
   KeyboardControllerProxy::ShowKeyboardContainer(container);
-  gfx::Rect showing_area =
-      ash::DisplayController::GetPrimaryDisplay().work_area();
-  GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(showing_area);
+  // GetTextInputClient may return NULL when keyboard-usability-test flag is
+  // set.
+  if (GetInputMethod()->GetTextInputClient()) {
+    gfx::Rect showing_area =
+        ash::DisplayController::GetPrimaryDisplay().work_area();
+    GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(showing_area);
+  }
 }
 
 void AshKeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) {
diff --git a/chrome/browser/ui/ash/chrome_new_window_delegate.cc b/chrome/browser/ui/ash/chrome_new_window_delegate.cc
new file mode 100644
index 0000000..d0e5609
--- /dev/null
+++ b/chrome/browser/ui/ash/chrome_new_window_delegate.cc
@@ -0,0 +1,138 @@
+// Copyright 2013 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/ash/chrome_new_window_delegate.h"
+
+#include "ash/wm/window_util.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.h"
+#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+
+namespace {
+
+void RestoreTabUsingProfile(Profile* profile) {
+  TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
+  service->RestoreMostRecentEntry(NULL, chrome::HOST_DESKTOP_TYPE_ASH);
+}
+
+}  // namespace
+
+ChromeNewWindowDelegate::ChromeNewWindowDelegate() {}
+ChromeNewWindowDelegate::~ChromeNewWindowDelegate() {}
+
+// TabRestoreHelper is used to restore a tab. In particular when the user
+// attempts to a restore a tab if the TabRestoreService hasn't finished loading
+// this waits for it. Once the TabRestoreService finishes loading the tab is
+// restored.
+class ChromeNewWindowDelegate::TabRestoreHelper
+    : public TabRestoreServiceObserver {
+ public:
+  TabRestoreHelper(ChromeNewWindowDelegate* delegate,
+                   Profile* profile,
+                   TabRestoreService* service)
+      : delegate_(delegate),
+        profile_(profile),
+        tab_restore_service_(service) {
+    tab_restore_service_->AddObserver(this);
+  }
+
+  virtual ~TabRestoreHelper() {
+    tab_restore_service_->RemoveObserver(this);
+  }
+
+  TabRestoreService* tab_restore_service() { return tab_restore_service_; }
+
+  virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE {
+  }
+
+  virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE {
+    // This destroys us.
+    delegate_->tab_restore_helper_.reset();
+  }
+
+  virtual void TabRestoreServiceLoaded(TabRestoreService* service) OVERRIDE {
+    RestoreTabUsingProfile(profile_);
+    // This destroys us.
+    delegate_->tab_restore_helper_.reset();
+  }
+
+ private:
+  ChromeNewWindowDelegate* delegate_;
+  Profile* profile_;
+  TabRestoreService* tab_restore_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabRestoreHelper);
+};
+
+void ChromeNewWindowDelegate::NewTab() {
+  Browser* browser = GetTargetBrowser();
+
+  // If the browser was not active, we call BrowserWindow::Show to make it
+  // visible. Otherwise, we let Browser::NewTab handle the active window change.
+  const bool was_active = browser->window()->IsActive();
+  chrome::NewTab(browser);
+  if (!was_active)
+    browser->window()->Show();
+}
+
+void ChromeNewWindowDelegate::NewWindow(bool is_incognito) {
+  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+  chrome::NewEmptyWindow(
+      is_incognito ? profile->GetOffTheRecordProfile() : profile,
+      chrome::HOST_DESKTOP_TYPE_ASH);
+}
+
+void ChromeNewWindowDelegate::RestoreTab() {
+  if (tab_restore_helper_.get()) {
+    DCHECK(!tab_restore_helper_->tab_restore_service()->IsLoaded());
+    return;
+  }
+
+  Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
+  Profile* profile = browser ? browser->profile() : NULL;
+  if (!profile)
+    profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+  if (profile->IsOffTheRecord())
+    return;
+  TabRestoreService* service =
+      TabRestoreServiceFactory::GetForProfile(profile);
+  if (!service)
+    return;
+
+  if (service->IsLoaded()) {
+    RestoreTabUsingProfile(profile);
+  } else {
+    tab_restore_helper_.reset(new TabRestoreHelper(this, profile, service));
+    service->LoadTabsFromLastSession();
+  }
+}
+
+void ChromeNewWindowDelegate::ShowTaskManager() {
+  chrome::OpenTaskManager(NULL);
+}
+
+void ChromeNewWindowDelegate::OpenFeedbackPage() {
+  chrome::OpenFeedbackDialog(GetTargetBrowserIfAvailable());
+}
+
+// static
+Browser* ChromeNewWindowDelegate::GetTargetBrowser() {
+  Browser* browser = GetTargetBrowserIfAvailable();
+  if (browser)
+    return browser;
+  return chrome::FindOrCreateTabbedBrowser(
+      ProfileManager::GetDefaultProfileOrOffTheRecord(),
+      chrome::HOST_DESKTOP_TYPE_ASH);
+}
+
+// static
+Browser* ChromeNewWindowDelegate::GetTargetBrowserIfAvailable() {
+  return chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
+}
diff --git a/chrome/browser/ui/ash/chrome_new_window_delegate.h b/chrome/browser/ui/ash/chrome_new_window_delegate.h
new file mode 100644
index 0000000..47c654c
--- /dev/null
+++ b/chrome/browser/ui/ash/chrome_new_window_delegate.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_ASH_CHROME_NEW_WINDOW_DELEGATE_H_
+#define CHROME_BROWSER_UI_ASH_CHROME_NEW_WINDOW_DELEGATE_H_
+
+#include "ash/new_window_delegate.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+
+class Browser;
+
+class ChromeNewWindowDelegate : public ash::NewWindowDelegate {
+ public:
+  ChromeNewWindowDelegate();
+  virtual ~ChromeNewWindowDelegate();
+
+  // Overridden from ash::NewWindowDelegate:
+  virtual void NewTab() OVERRIDE;
+  virtual void NewWindow(bool incognito) OVERRIDE;
+  virtual void RestoreTab() OVERRIDE;
+  virtual void ShowTaskManager() OVERRIDE;
+  virtual void OpenFeedbackPage() OVERRIDE;
+
+  // Returns the browser for active ash window if any. Otherwise it searches
+  // for a browser or create one for default profile and returns it.
+  static Browser* GetTargetBrowser();
+
+ protected:
+  // This returns the active ash window if any. Unlike the method above, it
+  // does not create a window if one isn't available, instead it returns NULL
+  // in that case.
+  static Browser* GetTargetBrowserIfAvailable();
+
+ private:
+  class TabRestoreHelper;
+
+  scoped_ptr<TabRestoreHelper> tab_restore_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeNewWindowDelegate);
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_CHROME_NEW_WINDOW_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc
new file mode 100644
index 0000000..d64f0b7
--- /dev/null
+++ b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc
@@ -0,0 +1,67 @@
+// Copyright 2013 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/ash/chrome_new_window_delegate_chromeos.h"
+
+#include "apps/shell_window_registry.h"
+#include "apps/ui/native_app_window.h"
+#include "ash/keyboard_overlay/keyboard_overlay_view.h"
+#include "chrome/browser/chromeos/file_manager/app_id.h"
+#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+
+ChromeNewWindowDelegateChromeos::ChromeNewWindowDelegateChromeos() {}
+ChromeNewWindowDelegateChromeos::~ChromeNewWindowDelegateChromeos() {}
+
+void ChromeNewWindowDelegateChromeos::OpenFileManager() {
+  using file_manager::kFileManagerAppId;
+  Profile* const profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+  const ExtensionService* const service = profile->GetExtensionService();
+  if (service == NULL ||
+      !service->IsExtensionEnabledForLauncher(kFileManagerAppId))
+    return;
+  const extensions::Extension* const extension =
+      service->GetInstalledExtension(kFileManagerAppId);
+  // event_flags = 0 means this invokes the same behavior as the launcher
+  // item is clicked without any keyboard modifiers.
+  OpenApplication(AppLaunchParams(profile,
+                                  extension,
+                                  0 /* event_flags */,
+                                  chrome::HOST_DESKTOP_TYPE_ASH));
+}
+
+void ChromeNewWindowDelegateChromeos::OpenCrosh() {
+  GURL crosh_url = extensions::TerminalExtensionHelper::GetCroshExtensionURL(
+      ProfileManager::GetDefaultProfileOrOffTheRecord());
+  if (!crosh_url.is_valid())
+    return;
+  Browser* browser = GetTargetBrowser();
+  content::WebContents* page = browser->OpenURL(
+      content::OpenURLParams(crosh_url,
+                             content::Referrer(),
+                             NEW_FOREGROUND_TAB,
+                             content::PAGE_TRANSITION_GENERATED,
+                             false));
+  browser->window()->Show();
+  browser->window()->Activate();
+  page->GetView()->Focus();
+}
+
+void ChromeNewWindowDelegateChromeos::ShowKeyboardOverlay() {
+  // TODO(mazda): Move the show logic to ash (http://crbug.com/124222).
+  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+  std::string url(chrome::kChromeUIKeyboardOverlayURL);
+  ash::KeyboardOverlayView::ShowDialog(profile,
+                                       new ChromeWebContentsHandler,
+                                       GURL(url));
+}
diff --git a/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h
new file mode 100644
index 0000000..3688e6d
--- /dev/null
+++ b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h
@@ -0,0 +1,24 @@
+// Copyright 2013 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_ASH_CHROME_NEW_WINDOW_DELEGATE_CHROMEOS_H_
+#define CHROME_BROWSER_UI_ASH_CHROME_NEW_WINDOW_DELEGATE_CHROMEOS_H_
+
+#include "chrome/browser/ui/ash/chrome_new_window_delegate.h"
+
+class ChromeNewWindowDelegateChromeos : public ChromeNewWindowDelegate {
+ public:
+  ChromeNewWindowDelegateChromeos();
+  virtual ~ChromeNewWindowDelegateChromeos();
+
+  // Overridden from ash::NewWindowDelegate:
+  virtual void OpenFileManager() OVERRIDE;
+  virtual void OpenCrosh() OVERRIDE;
+  virtual void ShowKeyboardOverlay() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChromeNewWindowDelegateChromeos);
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_CHROME_NEW_WINDOW_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index c94e533..6447983 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -6,37 +6,25 @@
 
 #include "apps/shell_window.h"
 #include "apps/shell_window_registry.h"
-#include "apps/ui/native_app_window.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/magnifier/magnifier_constants.h"
-#include "ash/session_state_delegate.h"
-#include "ash/system/tray/system_tray_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
-#include "base/prefs/pref_service.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/sessions/tab_restore_service_factory.h"
-#include "chrome/browser/sessions/tab_restore_service_observer.h"
 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
 #include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h"
 #include "chrome/browser/ui/ash/ash_keyboard_controller_proxy.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 #include "chrome/browser/ui/ash/user_action_handler.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
-#include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
@@ -47,57 +35,6 @@
 // static
 ChromeShellDelegate* ChromeShellDelegate::instance_ = NULL;
 
-namespace {
-
-void RestoreTabUsingProfile(Profile* profile) {
-  TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
-  service->RestoreMostRecentEntry(NULL, chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-}  // namespace
-
-// TabRestoreHelper is used to restore a tab. In particular when the user
-// attempts to a restore a tab if the TabRestoreService hasn't finished loading
-// this waits for it. Once the TabRestoreService finishes loading the tab is
-// restored.
-class ChromeShellDelegate::TabRestoreHelper : public TabRestoreServiceObserver {
- public:
-  TabRestoreHelper(ChromeShellDelegate* delegate,
-                   Profile* profile,
-                   TabRestoreService* service)
-      : delegate_(delegate),
-        profile_(profile),
-        tab_restore_service_(service) {
-    tab_restore_service_->AddObserver(this);
-  }
-
-  virtual ~TabRestoreHelper() {
-    tab_restore_service_->RemoveObserver(this);
-  }
-
-  TabRestoreService* tab_restore_service() { return tab_restore_service_; }
-
-  virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE {
-  }
-  virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE {
-    // This destroys us.
-    delegate_->tab_restore_helper_.reset();
-  }
-
-  virtual void TabRestoreServiceLoaded(TabRestoreService* service) OVERRIDE {
-    RestoreTabUsingProfile(profile_);
-    // This destroys us.
-    delegate_->tab_restore_helper_.reset();
-  }
-
- private:
-  ChromeShellDelegate* delegate_;
-  Profile* profile_;
-  TabRestoreService* tab_restore_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabRestoreHelper);
-};
-
 ChromeShellDelegate::ChromeShellDelegate()
     : launcher_delegate_(NULL) {
   instance_ = this;
@@ -118,9 +55,24 @@
 #if defined(OS_CHROMEOS)
   // If there is a user manager, we need to see that we can at least have 2
   // simultaneous users to allow this feature.
-  if (chromeos::UserManager::IsInitialized() &&
-      chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile().size() +
-      chromeos::UserManager::Get()->GetLoggedInUsers().size() <= 1)
+  if (!chromeos::UserManager::IsInitialized())
+    return false;
+  size_t admitted_users_to_be_added =
+      chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile().size();
+  size_t logged_in_users =
+      chromeos::UserManager::Get()->GetLoggedInUsers().size();
+  if (!logged_in_users) {
+    // The shelf gets created on the login screen and as such we have to create
+    // all multi profile items of the the system tray menu before the user logs
+    // in. For special cases like Kiosk mode and / or guest mode this isn't a
+    // problem since either the browser gets restarted and / or the flag is not
+    // allowed, but for an "ephermal" user (see crbug.com/312324) it is not
+    // decided yet if he could add other users to his session or not.
+    // TODO(skuhne): As soon as the issue above needs to be resolved, this logic
+    // should change.
+    logged_in_users = 1;
+  }
+  if (admitted_users_to_be_added + logged_in_users <= 1)
     return false;
 #endif
   return true;
@@ -134,101 +86,6 @@
   chrome::AttemptUserExit();
 }
 
-void ChromeShellDelegate::NewTab() {
-  Browser* browser = GetTargetBrowser();
-  // If the browser was not active, we call BrowserWindow::Show to make it
-  // visible. Otherwise, we let Browser::NewTab handle the active window change.
-  const bool was_active = browser->window()->IsActive();
-  chrome::NewTab(browser);
-  if (!was_active)
-    browser->window()->Show();
-}
-
-void ChromeShellDelegate::NewWindow(bool is_incognito) {
-  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-  chrome::NewEmptyWindow(
-      is_incognito ? profile->GetOffTheRecordProfile() : profile,
-      chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-void ChromeShellDelegate::ToggleFullscreen() {
-  // Only toggle if the user has a window open.
-  aura::Window* window = ash::wm::GetActiveWindow();
-  if (!window)
-    return;
-  ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
-
-  bool is_fullscreen = window_state->IsFullscreen();
-
-  // Windows which cannot be maximized should not be fullscreened.
-  if (!is_fullscreen && !window_state->CanMaximize())
-    return;
-
-  Browser* browser = chrome::FindBrowserWithWindow(window);
-  if (browser) {
-    // If a window is fullscreen, exit fullscreen.
-    if (is_fullscreen) {
-      chrome::ToggleFullscreenMode(browser);
-      return;
-    }
-
-    // AppNonClientFrameViewAsh shows only the window controls and no other
-    // window decorations which is pretty close to fullscreen. Put v1 apps
-    // into maximized mode instead of fullscreen to avoid showing the ugly
-    // fullscreen exit bubble.
-#if defined(OS_WIN)
-    if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
-      chrome::ToggleFullscreenMode(browser);
-      return;
-    }
-#endif  // OS_WIN
-    if (browser->is_app() && browser->app_type() != Browser::APP_TYPE_CHILD)
-      window_state->ToggleMaximized();
-    else
-      chrome::ToggleFullscreenMode(browser);
-    return;
-  }
-
-  // |window| may belong to a shell window.
-  apps::ShellWindow* shell_window = apps::ShellWindowRegistry::
-      GetShellWindowForNativeWindowAnyProfile(window);
-  if (shell_window) {
-    if (is_fullscreen)
-      shell_window->Restore();
-    else
-      shell_window->Fullscreen();
-  }
-}
-
-void ChromeShellDelegate::RestoreTab() {
-  if (tab_restore_helper_.get()) {
-    DCHECK(!tab_restore_helper_->tab_restore_service()->IsLoaded());
-    return;
-  }
-
-  Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
-  Profile* profile = browser ? browser->profile() : NULL;
-  if (!profile)
-    profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-  if (profile->IsOffTheRecord())
-    return;
-  TabRestoreService* service =
-      TabRestoreServiceFactory::GetForProfile(profile);
-  if (!service)
-    return;
-
-  if (service->IsLoaded()) {
-    RestoreTabUsingProfile(profile);
-  } else {
-    tab_restore_helper_.reset(new TabRestoreHelper(this, profile, service));
-    service->LoadTabsFromLastSession();
-  }
-}
-
-void ChromeShellDelegate::ShowTaskManager() {
-  chrome::OpenTaskManager(NULL);
-}
-
 content::BrowserContext* ChromeShellDelegate::GetCurrentBrowserContext() {
   return ProfileManager::GetDefaultProfile();
 }
@@ -261,10 +118,6 @@
   return new UserActionHandler;
 }
 
-void ChromeShellDelegate::OpenFeedbackPage() {
-  chrome::OpenFeedbackDialog(GetTargetBrowserIfAvailable());
-}
-
 void ChromeShellDelegate::RecordUserMetricsAction(
     ash::UserMetricsAction action) {
   switch (action) {
@@ -418,7 +271,7 @@
   }
 }
 
-ui::MenuModel* ChromeShellDelegate::CreateContextMenu(aura::RootWindow* root) {
+ui::MenuModel* ChromeShellDelegate::CreateContextMenu(aura::Window* root) {
   DCHECK(launcher_delegate_);
   // Don't show context menu for exclusive app runtime mode.
   if (chrome::IsRunningInAppMode())
@@ -435,19 +288,6 @@
   return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
 }
 
-Browser* ChromeShellDelegate::GetTargetBrowser() {
-  Browser* browser = GetTargetBrowserIfAvailable();
-  if (browser)
-    return browser;
-  return chrome::FindOrCreateTabbedBrowser(
-      ProfileManager::GetDefaultProfileOrOffTheRecord(),
-      chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-Browser* ChromeShellDelegate::GetTargetBrowserIfAvailable() {
-  return chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
-}
-
 keyboard::KeyboardControllerProxy*
     ChromeShellDelegate::CreateKeyboardControllerProxy() {
   return new AshKeyboardControllerProxy();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 804d1c0..b5af8a5 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -26,6 +26,7 @@
 }
 
 class ChromeLauncherController;
+class ChromeNewWindowDelegate;
 
 class ChromeShellDelegate : public ash::ShellDelegate,
                             public content::NotificationObserver {
@@ -42,30 +43,9 @@
   virtual void PreInit() OVERRIDE;
   virtual void Shutdown() OVERRIDE;
   virtual void Exit() OVERRIDE;
-  virtual void NewTab() OVERRIDE;
-  virtual void NewWindow(bool is_incognito) OVERRIDE;
-  virtual void ToggleFullscreen() OVERRIDE;
-  virtual void OpenFileManager() OVERRIDE;
-  virtual void OpenCrosh() OVERRIDE;
-  virtual void RestoreTab() OVERRIDE;
-  virtual void ShowKeyboardOverlay() OVERRIDE;
   virtual keyboard::KeyboardControllerProxy*
       CreateKeyboardControllerProxy() OVERRIDE;
-  virtual void ShowTaskManager() OVERRIDE;
   virtual content::BrowserContext* GetCurrentBrowserContext() OVERRIDE;
-  virtual void ToggleHighContrast() OVERRIDE;
-  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE;
-  virtual void ToggleSpokenFeedback(
-      ash::AccessibilityNotificationVisibility notify) OVERRIDE;
-  virtual bool IsHighContrastEnabled() const OVERRIDE;
-  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE;
-  virtual void SetMagnifierType(ash::MagnifierType type) OVERRIDE;
-  virtual bool IsMagnifierEnabled() const OVERRIDE;
-  virtual ash::MagnifierType GetMagnifierType() const OVERRIDE;
-  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE;
-  virtual bool IsLargeCursorEnabled() const OVERRIDE;
-  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE;
-  virtual void SilenceSpokenFeedback() const OVERRIDE;
   virtual app_list::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
   virtual ash::LauncherDelegate* CreateLauncherDelegate(
       ash::LauncherModel* model) OVERRIDE;
@@ -73,15 +53,14 @@
   virtual ash::UserWallpaperDelegate* CreateUserWallpaperDelegate() OVERRIDE;
   virtual ash::CapsLockDelegate* CreateCapsLockDelegate() OVERRIDE;
   virtual ash::SessionStateDelegate* CreateSessionStateDelegate() OVERRIDE;
+  virtual ash::AccessibilityDelegate* CreateAccessibilityDelegate() OVERRIDE;
+  virtual ash::NewWindowDelegate* CreateNewWindowDelegate() OVERRIDE;
   virtual aura::client::UserActionClient* CreateUserActionClient() OVERRIDE;
-  virtual void OpenFeedbackPage() OVERRIDE;
   virtual void RecordUserMetricsAction(ash::UserMetricsAction action) OVERRIDE;
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
-  virtual double GetSavedScreenMagnifierScale() OVERRIDE;
-  virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root) OVERRIDE;
+  virtual ui::MenuModel* CreateContextMenu(aura::Window* root) OVERRIDE;
   virtual ash::RootWindowHostFactory* CreateRootWindowHostFactory() OVERRIDE;
   virtual string16 GetProductName() const OVERRIDE;
 
@@ -91,27 +70,14 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
  private:
-  class TabRestoreHelper;
-
   void PlatformInit();
 
-  // Returns the browser for active ash window if any. Otherwise it searches
-  // for a browser or create one for default profile and returns it.
-  Browser* GetTargetBrowser();
-
-  // This returns the active ash window if any. Unlike the method above, it
-  // does not create a window if one isn't available, instead it returns NULL
-  // in that case.
-  Browser* GetTargetBrowserIfAvailable();
-
   static ChromeShellDelegate* instance_;
 
   content::NotificationRegistrar registrar_;
 
   ChromeLauncherController* launcher_delegate_;
 
-  scoped_ptr<TabRestoreHelper> tab_restore_helper_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate);
 };
 
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
deleted file mode 100644
index 1caabc8..0000000
--- a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2012 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/ash/chrome_shell_delegate.h"
-
-#include "apps/shell_window.h"
-#include "apps/ui/native_app_window.h"
-#include "ash/accelerators/accelerator_commands.h"
-#include "ash/ash_switches.h"
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#include "ash/wm/window_properties.h"
-#include "ash/wm/window_state.h"
-#include "base/command_line.h"
-#include "chrome/browser/apps/app_browsertest_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "ui/aura/client/aura_constants.h"
-
-namespace {
-
-// Returns true if |window| is in immersive fullscreen. Infer whether |window|
-// is in immersive fullscreen based on whether kFullscreenUsesMinimalChromeKey
-// is set for |window| because DEPS does not allow the test to use BrowserView.
-// (This is not quite right because if a window is in both immersive browser
-// fullscreen and in tab fullscreen, kFullScreenUsesMinimalChromeKey will
-// not be set).
-bool IsInImmersiveFullscreen(BrowserWindow* browser_window) {
-  return browser_window->IsFullscreen() &&
-      browser_window->GetNativeWindow()->GetProperty(
-          ash::internal::kFullscreenUsesMinimalChromeKey);
-}
-
-}  // namespace
-
-typedef InProcessBrowserTest ChromeShellDelegateBrowserTest;
-
-// TODO(oshima): Move these tests to ash once ToggleFullscreen is moved
-// to ash. crbug.com/309837.
-
-// Confirm that toggling window miximized works properly
-IN_PROC_BROWSER_TEST_F(ChromeShellDelegateBrowserTest, ToggleMaximized) {
-  ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
-  ASSERT_TRUE(shell_delegate);
-  ash::wm::WindowState* window_state = ash::wm::GetActiveWindowState();
-  ASSERT_TRUE(window_state);
-
-  // When not in fullscreen, accelerators::ToggleMaximized toggles Maximized.
-  EXPECT_FALSE(window_state->IsMaximized());
-  ash::accelerators::ToggleMaximized();
-  EXPECT_TRUE(window_state->IsMaximized());
-  ash::accelerators::ToggleMaximized();
-  EXPECT_FALSE(window_state->IsMaximized());
-
-  // When in fullscreen accelerators::ToggleMaximized gets out of fullscreen.
-  EXPECT_FALSE(window_state->IsFullscreen());
-  Browser* browser = chrome::FindBrowserWithWindow(window_state->window());
-  ASSERT_TRUE(browser);
-  chrome::ToggleFullscreenMode(browser);
-  EXPECT_TRUE(window_state->IsFullscreen());
-  ash::accelerators::ToggleMaximized();
-  EXPECT_FALSE(window_state->IsFullscreen());
-  EXPECT_FALSE(window_state->IsMaximized());
-  ash::accelerators::ToggleMaximized();
-  EXPECT_FALSE(window_state->IsFullscreen());
-  EXPECT_TRUE(window_state->IsMaximized());
-}
-
-// Confirm that toggling window fullscren works properly.
-IN_PROC_BROWSER_TEST_F(ChromeShellDelegateBrowserTest, ToggleFullscreen) {
-  ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
-  ASSERT_TRUE(shell_delegate);
-
-  // 1) ToggleFullscreen() should toggle whether a tabbed browser window is in
-  // immersive fullscreen.
-  ASSERT_TRUE(browser()->is_type_tabbed());
-  BrowserWindow* browser_window = browser()->window();
-  ASSERT_TRUE(browser_window->IsActive());
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_TRUE(browser_window->IsFullscreen());
-  EXPECT_EQ(IsInImmersiveFullscreen(browser_window),
-      ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  // 2) ToggleFullscreen() should have no effect on windows which cannot be
-  // maximized.
-  browser_window->GetNativeWindow()->SetProperty(aura::client::kCanMaximizeKey,
-                                                 false);
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  // 3) ToggleFullscreen() should maximize v1 app browser windows which use
-  // AppNonClientFrameViewAsh.
-  // TODO(pkotwicz): Figure out if we actually want this behavior.
-  Browser::CreateParams browser_create_params(Browser::TYPE_POPUP,
-      browser()->profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
-#if defined(OS_WIN)
-  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
-#endif  // OS_WIN
-  browser_create_params.app_name = "Test";
-  browser_create_params.app_type = Browser::APP_TYPE_HOST;
-
-  Browser* app_host_browser = new Browser(browser_create_params);
-  ASSERT_TRUE(app_host_browser->is_app());
-  AddBlankTabAndShow(app_host_browser);
-  browser_window = app_host_browser->window();
-  ASSERT_TRUE(browser_window->IsActive());
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_TRUE(browser_window->IsMaximized());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  // 4) ToggleFullscreen() should put child windows of v1 apps into
-  // non-immersive fullscreen.
-  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
-  browser_create_params.app_type = Browser::APP_TYPE_CHILD;
-  Browser* app_child_browser = new Browser(browser_create_params);
-  ASSERT_TRUE(app_child_browser->is_app());
-  AddBlankTabAndShow(app_child_browser);
-  browser_window = app_child_browser->window();
-  ASSERT_TRUE(browser_window->IsActive());
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_TRUE(browser_window->IsFullscreen());
-  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  // 5) ToggleFullscreen() should put popup browser windows into non-immersive
-  // fullscreen.
-  browser_create_params.app_name = "";
-  Browser* popup_browser = new Browser(browser_create_params);
-  ASSERT_TRUE(popup_browser->is_type_popup());
-  ASSERT_FALSE(popup_browser->is_app());
-  AddBlankTabAndShow(popup_browser);
-  browser_window = popup_browser->window();
-  ASSERT_TRUE(browser_window->IsActive());
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_TRUE(browser_window->IsFullscreen());
-  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(browser_window->IsMaximized());
-  EXPECT_FALSE(browser_window->IsFullscreen());
-}
-
-typedef extensions::PlatformAppBrowserTest
-    ChromeShellDelegatePlatformAppBrowserTest;
-
-// Test that ToggleFullscreen() toggles the platform app's fullscreen state.
-IN_PROC_BROWSER_TEST_F(ChromeShellDelegatePlatformAppBrowserTest,
-                       ToggleFullscreenPlatformApp) {
-  ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
-  ASSERT_TRUE(shell_delegate);
-
-  const extensions::Extension* extension = LoadAndLaunchPlatformApp("minimal");
-  apps::ShellWindow* shell_window = CreateShellWindow(extension);
-  apps::NativeAppWindow* app_window = shell_window->GetBaseWindow();
-  ASSERT_TRUE(shell_window->GetBaseWindow()->IsActive());
-  EXPECT_FALSE(app_window->IsMaximized());
-  EXPECT_FALSE(app_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_TRUE(app_window->IsFullscreen());
-
-  shell_delegate->ToggleFullscreen();
-  EXPECT_FALSE(app_window->IsMaximized());
-  EXPECT_FALSE(app_window->IsFullscreen());
-
-  CloseShellWindow(shell_window);
-}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index 2c5be45..e6d31a5 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -4,9 +4,7 @@
 
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 
-#include "apps/shell_window_registry.h"
-#include "apps/ui/native_app_window.h"
-#include "ash/keyboard_overlay/keyboard_overlay_view.h"
+#include "ash/accessibility_delegate.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
@@ -18,29 +16,23 @@
 #include "chrome/browser/chromeos/display/display_preferences.h"
 #include "chrome/browser/chromeos/extensions/media_player_api.h"
 #include "chrome/browser/chromeos/extensions/media_player_event_router.h"
-#include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/system/ash_system_tray_delegate.h"
-#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/speech/tts_controller.h"
 #include "chrome/browser/ui/ash/caps_lock_delegate_chromeos.h"
+#include "chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h"
 #include "chrome/browser/ui/ash/session_state_delegate_chromeos.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/ime/input_method_manager.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
+#include "ui/aura/window.h"
 
 namespace {
 
@@ -55,6 +47,104 @@
     mru_list.front()->Focus();
 }
 
+class AccessibilityDelegateImpl : public ash::AccessibilityDelegate {
+ public:
+  AccessibilityDelegateImpl() {}
+  virtual ~AccessibilityDelegateImpl() {}
+
+  virtual void ToggleHighContrast() OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    chromeos::AccessibilityManager::Get()->EnableHighContrast(
+        !chromeos::AccessibilityManager::Get()->IsHighContrastEnabled());
+  }
+
+  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
+  }
+
+  virtual void ToggleSpokenFeedback(
+      ash::AccessibilityNotificationVisibility notify) OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    chromeos::AccessibilityManager::Get()->ToggleSpokenFeedback(notify);
+  }
+
+  virtual bool IsHighContrastEnabled() const OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->IsHighContrastEnabled();
+  }
+
+  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE {
+    DCHECK(chromeos::MagnificationManager::Get());
+    return chromeos::MagnificationManager::Get()->SetMagnifierEnabled(enabled);
+  }
+
+  virtual void SetMagnifierType(ash::MagnifierType type) OVERRIDE {
+    DCHECK(chromeos::MagnificationManager::Get());
+    return chromeos::MagnificationManager::Get()->SetMagnifierType(type);
+  }
+
+  virtual bool IsMagnifierEnabled() const OVERRIDE {
+    DCHECK(chromeos::MagnificationManager::Get());
+    return chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
+  }
+
+  virtual ash::MagnifierType GetMagnifierType() const OVERRIDE {
+    DCHECK(chromeos::MagnificationManager::Get());
+    return chromeos::MagnificationManager::Get()->GetMagnifierType();
+  }
+
+  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->EnableLargeCursor(enabled);
+  }
+
+  virtual bool IsLargeCursorEnabled() const OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->IsLargeCursorEnabled();
+  }
+
+  virtual void SetAutoclickEnabled(bool enabled) OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->EnableAutoclick(enabled);
+  }
+
+  virtual bool IsAutoclickEnabled() const OVERRIDE {
+    DCHECK(chromeos::AccessibilityManager::Get());
+    return chromeos::AccessibilityManager::Get()->IsAutoclickEnabled();
+  }
+
+  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE {
+    Profile* profile = ProfileManager::GetDefaultProfile();
+    if (!profile)
+      return false;
+
+    PrefService* user_pref_service = profile->GetPrefs();
+    return user_pref_service && user_pref_service->GetBoolean(
+        prefs::kShouldAlwaysShowAccessibilityMenu);
+  }
+
+  virtual void SilenceSpokenFeedback() const OVERRIDE {
+    TtsController::GetInstance()->Stop();
+  }
+
+  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE {
+    if (chromeos::MagnificationManager::Get())
+      chromeos::MagnificationManager::Get()->SaveScreenMagnifierScale(scale);
+  }
+
+  virtual double GetSavedScreenMagnifierScale() OVERRIDE {
+    if (chromeos::MagnificationManager::Get()) {
+      return chromeos::MagnificationManager::Get()->
+          GetSavedScreenMagnifierScale();
+    }
+    return std::numeric_limits<double>::min();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityDelegateImpl);
+};
+
 }  // anonymous namespace
 
 bool ChromeShellDelegate::IsFirstRunAfterBoot() const {
@@ -72,116 +162,6 @@
       RequestShutdown();
 }
 
-void ChromeShellDelegate::OpenFileManager() {
-  using file_manager::kFileManagerAppId;
-  Profile* const profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-  const apps::ShellWindowRegistry* const registry =
-      apps::ShellWindowRegistry::Get(profile);
-  const apps::ShellWindowRegistry::ShellWindowList list =
-      registry->GetShellWindowsForApp(kFileManagerAppId);
-  if (list.empty()) {
-    // Open the new window.
-    const ExtensionService* const service = profile->GetExtensionService();
-    if (service == NULL ||
-        !service->IsExtensionEnabledForLauncher(kFileManagerAppId))
-      return;
-    const extensions::Extension* const extension =
-        service->GetInstalledExtension(kFileManagerAppId);
-    // event_flags = 0 means this invokes the same behavior as the launcher
-    // item is clicked without any keyboard modifiers.
-    OpenApplication(AppLaunchParams(
-        profile,
-        extension,
-        0 /* event_flags */,
-        chrome::HOST_DESKTOP_TYPE_ASH));
-  } else {
-    // Activate the existing window.
-    list.front()->GetBaseWindow()->Activate();
-  }
-}
-
-void ChromeShellDelegate::OpenCrosh() {
-  GURL crosh_url = extensions::TerminalExtensionHelper::GetCroshExtensionURL(
-      ProfileManager::GetDefaultProfileOrOffTheRecord());
-  if (!crosh_url.is_valid())
-    return;
-  Browser* browser = GetTargetBrowser();
-  content::WebContents* page = browser->OpenURL(
-      content::OpenURLParams(crosh_url,
-                             content::Referrer(),
-                             NEW_FOREGROUND_TAB,
-                             content::PAGE_TRANSITION_GENERATED,
-                             false));
-  browser->window()->Show();
-  browser->window()->Activate();
-  page->GetView()->Focus();
-}
-
-void ChromeShellDelegate::ToggleHighContrast() {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  bool enabled = chromeos::AccessibilityManager::Get()->IsHighContrastEnabled();
-  chromeos::AccessibilityManager::Get()->EnableHighContrast(!enabled);
-}
-
-bool ChromeShellDelegate::IsSpokenFeedbackEnabled() const {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  return chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
-}
-
-void ChromeShellDelegate::ToggleSpokenFeedback(
-    ash::AccessibilityNotificationVisibility notify) {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  chromeos::AccessibilityManager::Get()->ToggleSpokenFeedback(notify);
-}
-
-bool ChromeShellDelegate::IsHighContrastEnabled() const {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  return chromeos::AccessibilityManager::Get()->IsHighContrastEnabled();
-}
-
-bool ChromeShellDelegate::IsMagnifierEnabled() const {
-  DCHECK(chromeos::MagnificationManager::Get());
-  return chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
-}
-
-ash::MagnifierType ChromeShellDelegate::GetMagnifierType() const {
-  DCHECK(chromeos::MagnificationManager::Get());
-  return chromeos::MagnificationManager::Get()->GetMagnifierType();
-}
-
-void ChromeShellDelegate::SetMagnifierEnabled(bool enabled) {
-  DCHECK(chromeos::MagnificationManager::Get());
-  return chromeos::MagnificationManager::Get()->SetMagnifierEnabled(enabled);
-}
-
-void ChromeShellDelegate::SetMagnifierType(ash::MagnifierType type) {
-  DCHECK(chromeos::MagnificationManager::Get());
-  return chromeos::MagnificationManager::Get()->SetMagnifierType(type);
-}
-
-void ChromeShellDelegate::SaveScreenMagnifierScale(double scale) {
-  if (chromeos::MagnificationManager::Get())
-    chromeos::MagnificationManager::Get()->SaveScreenMagnifierScale(scale);
-}
-
-double ChromeShellDelegate::GetSavedScreenMagnifierScale() {
-  if (chromeos::MagnificationManager::Get()) {
-    return chromeos::MagnificationManager::Get()->
-        GetSavedScreenMagnifierScale();
-  }
-  return std::numeric_limits<double>::min();
-}
-
-void ChromeShellDelegate::SetLargeCursorEnabled(bool enabled) {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  return chromeos::AccessibilityManager::Get()->EnableLargeCursor(enabled);
-}
-
-bool ChromeShellDelegate::IsLargeCursorEnabled() const {
-  DCHECK(chromeos::AccessibilityManager::Get());
-  return chromeos::AccessibilityManager::Get()->IsLargeCursorEnabled();
-}
-
 ash::CapsLockDelegate* ChromeShellDelegate::CreateCapsLockDelegate() {
   chromeos::input_method::XKeyboard* xkeyboard =
       chromeos::input_method::InputMethodManager::Get()->GetXKeyboard();
@@ -192,27 +172,12 @@
   return new SessionStateDelegateChromeos;
 }
 
-void ChromeShellDelegate::ShowKeyboardOverlay() {
-  // TODO(mazda): Move the show logic to ash (http://crbug.com/124222).
-  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-  std::string url(chrome::kChromeUIKeyboardOverlayURL);
-  ash::KeyboardOverlayView::ShowDialog(profile,
-                                       new ChromeWebContentsHandler,
-                                       GURL(url));
+ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
+  return new AccessibilityDelegateImpl;
 }
 
-bool ChromeShellDelegate::ShouldAlwaysShowAccessibilityMenu() const {
-  Profile* profile = ProfileManager::GetDefaultProfile();
-  if (!profile)
-    return false;
-
-  PrefService* user_pref_service = profile->GetPrefs();
-  return user_pref_service &&
-      user_pref_service->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu);
-}
-
-void ChromeShellDelegate::SilenceSpokenFeedback() const {
-  TtsController::GetInstance()->Stop();
+ash::NewWindowDelegate* ChromeShellDelegate::CreateNewWindowDelegate() {
+  return new ChromeNewWindowDelegateChromeos;
 }
 
 ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
index c6cf777..176fab2 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
@@ -4,13 +4,15 @@
 
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 
-#include "base/command_line.h"
+#include "ash/accessibility_delegate.h"
 #include "ash/magnifier/magnifier_constants.h"
 #include "ash/system/tray/default_system_tray_delegate.h"
+#include "base/command_line.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/caps_lock_delegate_views.h"
+#include "chrome/browser/ui/ash/chrome_new_window_delegate.h"
 #include "chrome/browser/ui/ash/session_state_delegate_views.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -22,9 +24,94 @@
 #include "content/public/browser/notification_service.h"
 
 #if defined(OS_WIN)
+#include "chrome/browser/ui/ash/system_tray_delegate_win.h"
 #include "chrome/browser/ui/ash/user_wallpaper_delegate_win.h"
 #endif
 
+namespace {
+
+class NewWindowDelegateImpl : public ChromeNewWindowDelegate {
+ public:
+  NewWindowDelegateImpl() {}
+  virtual ~NewWindowDelegateImpl() {}
+
+  // Overridden from ash::NewWindowDelegate:
+  virtual void OpenFileManager() OVERRIDE {}
+  virtual void OpenCrosh() OVERRIDE {}
+  virtual void ShowKeyboardOverlay() OVERRIDE {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NewWindowDelegateImpl);
+};
+
+class EmptyAccessibilityDelegate : public ash::AccessibilityDelegate {
+ public:
+  EmptyAccessibilityDelegate() {}
+  virtual ~EmptyAccessibilityDelegate() {}
+
+  virtual void ToggleHighContrast() OVERRIDE {
+  }
+
+  virtual bool IsHighContrastEnabled() const OVERRIDE {
+    return false;
+  }
+
+  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE {
+    return false;
+  }
+
+  virtual void ToggleSpokenFeedback(
+      ash::AccessibilityNotificationVisibility notify) OVERRIDE {
+  }
+
+  virtual void SetLargeCursorEnabled(bool enalbed) OVERRIDE {
+  }
+
+  virtual bool IsLargeCursorEnabled() const OVERRIDE {
+    return false;
+  }
+
+  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE {
+  }
+
+  virtual void SetMagnifierType(ash::MagnifierType type) OVERRIDE {
+  }
+
+  virtual bool IsMagnifierEnabled() const OVERRIDE {
+    return false;
+  }
+
+  virtual void SetAutoclickEnabled(bool enabled) OVERRIDE {
+  }
+
+  virtual bool IsAutoclickEnabled() const OVERRIDE {
+    return false;
+  }
+
+  virtual ash::MagnifierType GetMagnifierType() const OVERRIDE {
+    return ash::kDefaultMagnifierType;
+  }
+
+  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE {
+  }
+
+  virtual double GetSavedScreenMagnifierScale() OVERRIDE {
+    return std::numeric_limits<double>::min();
+  }
+
+  virtual bool ShouldAlwaysShowAccessibilityMenu() const OVERRIDE {
+    return false;
+  }
+
+  virtual void SilenceSpokenFeedback() const OVERRIDE {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EmptyAccessibilityDelegate);
+};
+
+}  // namespace
+
 bool ChromeShellDelegate::IsFirstRunAfterBoot() const {
   return false;
 }
@@ -35,49 +122,8 @@
 void ChromeShellDelegate::Shutdown() {
 }
 
-void ChromeShellDelegate::OpenFileManager() {
-}
-
-void ChromeShellDelegate::OpenCrosh() {
-}
-
-void ChromeShellDelegate::ShowKeyboardOverlay() {
-}
-
-void ChromeShellDelegate::ToggleHighContrast() {
-}
-
-bool ChromeShellDelegate::IsSpokenFeedbackEnabled() const {
-  return false;
-}
-
-void ChromeShellDelegate::ToggleSpokenFeedback(
-    ash::AccessibilityNotificationVisibility notify) {
-}
-
-void ChromeShellDelegate::SetLargeCursorEnabled(bool enalbed) {
-}
-
-bool ChromeShellDelegate::IsLargeCursorEnabled() const {
-  return false;
-}
-
-bool ChromeShellDelegate::IsHighContrastEnabled() const {
-  return false;
-}
-
-void ChromeShellDelegate::SetMagnifierEnabled(bool enabled) {
-}
-
-void ChromeShellDelegate::SetMagnifierType(ash::MagnifierType type) {
-}
-
-bool ChromeShellDelegate::IsMagnifierEnabled() const {
-  return false;
-}
-
-ash::MagnifierType ChromeShellDelegate::GetMagnifierType() const {
-  return ash::kDefaultMagnifierType;
+ash::NewWindowDelegate* ChromeShellDelegate::CreateNewWindowDelegate() {
+  return new NewWindowDelegateImpl;
 }
 
 ash::CapsLockDelegate* ChromeShellDelegate::CreateCapsLockDelegate() {
@@ -88,23 +134,16 @@
   return new SessionStateDelegate;
 }
 
-void ChromeShellDelegate::SaveScreenMagnifierScale(double scale) {
-}
-
-double ChromeShellDelegate::GetSavedScreenMagnifierScale() {
-  return std::numeric_limits<double>::min();
-}
-
-bool ChromeShellDelegate::ShouldAlwaysShowAccessibilityMenu() const {
-  return false;
-}
-
-void ChromeShellDelegate::SilenceSpokenFeedback() const {
-}
-
 ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() {
-  // TODO(sky): need to subclass and override Shutdown() in a meaningful way.
+#if defined(OS_WIN)
+  return CreateWindowsSystemTrayDelegate();
+#else
   return new ash::DefaultSystemTrayDelegate;
+#endif
+}
+
+ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
+  return new EmptyAccessibilityDelegate;
 }
 
 ash::UserWallpaperDelegate* ChromeShellDelegate::CreateUserWallpaperDelegate() {
@@ -156,7 +195,7 @@
                             true,
                             chrome::HOST_DESKTOP_TYPE_ASH);
       } else {
-        Browser* browser = GetTargetBrowser();
+        Browser* browser = ChromeNewWindowDelegate::GetTargetBrowser();
         chrome::AddBlankTabAt(browser, -1, true);
         browser->window()->Show();
       }
diff --git a/chrome/browser/ui/ash/event_rewriter.cc b/chrome/browser/ui/ash/event_rewriter.cc
index 54e808c..f294653 100644
--- a/chrome/browser/ui/ash/event_rewriter.cc
+++ b/chrome/browser/ui/ash/event_rewriter.cc
@@ -136,42 +136,23 @@
       manager->GetCurrentInputMethod().id() == kCaMultixLayoutId;
 }
 
-// Returns true if the target for |event| would prefer to receive raw function
-// keys instead of having them rewritten into back, forward, brightness, volume,
-// etc. Web apps (v2 apps) can request this behavior via a permission so users
-// can use unmodified top-row keypresses to send function keys for things like
-// ssh and remote desktop.
-bool TopRowKeysAreFunctionKeys(ui::KeyEvent* event) {
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  if (!target)
-    return false;
-  aura::Window* top_level = views::corewm::GetToplevelWindow(target);
-  return top_level &&
-      ash::wm::GetWindowState(top_level)->top_row_keys_are_function_keys();
-}
-
 #endif  // defined(OS_CHROMEOS)
 
-const PrefService* GetPrefService() {
-  Profile* profile = ProfileManager::GetDefaultProfile();
-  if (profile)
-    return profile->GetPrefs();
-  return NULL;
-}
-
 }  // namespace
 
 EventRewriter::EventRewriter()
     : last_device_id_(kBadDeviceId),
 #if defined(OS_CHROMEOS)
-      xkeyboard_(NULL),
-      keyboard_driven_event_rewritter_(
+      xkeyboard_for_testing_(NULL),
+      keyboard_driven_event_rewriter_(
           new chromeos::KeyboardDrivenEventRewriter),
 #endif
-      pref_service_(NULL) {
+      pref_service_for_testing_(NULL) {
   // The ash shell isn't instantiated for our unit tests.
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this);
+  if (ash::Shell::HasInstance()) {
+    ash::Shell::GetPrimaryRootWindow()->GetDispatcher()->
+        AddRootWindowObserver(this);
+  }
 #if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS()) {
     chromeos::XInputHierarchyChangedEventListener::GetInstance()
@@ -182,8 +163,10 @@
 }
 
 EventRewriter::~EventRewriter() {
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this);
+  if (ash::Shell::HasInstance()) {
+    ash::Shell::GetPrimaryRootWindow()->GetDispatcher()->
+        RemoveRootWindowObserver(this);
+  }
 #if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS()) {
     chromeos::XInputHierarchyChangedEventListener::GetInstance()
@@ -305,6 +288,21 @@
   return keycode;
 }
 
+bool EventRewriter::TopRowKeysAreFunctionKeys(ui::KeyEvent* event) const {
+  const PrefService* prefs = GetPrefService();
+  if (prefs &&
+      prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
+      prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
+    return true;
+
+  aura::Window* target = static_cast<aura::Window*>(event->target());
+  if (!target)
+    return false;
+  aura::Window* top_level = views::corewm::GetToplevelWindow(target);
+  return top_level &&
+      ash::wm::GetWindowState(top_level)->top_row_keys_are_function_keys();
+}
+
 bool EventRewriter::RewriteWithKeyboardRemappingsByKeySym(
     const KeyboardRemapping* remappings,
     size_t num_remappings,
@@ -365,7 +363,14 @@
 
   return false;
 }
-#endif
+#endif  // defined(OS_CHROMEOS)
+
+const PrefService* EventRewriter::GetPrefService() const {
+  if (pref_service_for_testing_)
+    return pref_service_for_testing_;
+  Profile* profile = ProfileManager::GetDefaultProfile();
+  return profile ? profile->GetPrefs() : NULL;
+}
 
 void EventRewriter::Rewrite(ui::KeyEvent* event) {
 #if defined(OS_CHROMEOS)
@@ -377,7 +382,7 @@
   // Keyboard driven rewriting needs to happen before RewriteExtendedKeys
   // to handle Ctrl+Alt+Shift+(Up | Down) so that they are not translated
   // to Home/End.
-  keyboard_driven_event_rewritter_->RewriteIfKeyboardDrivenOnLoginScreen(event);
+  keyboard_driven_event_rewriter_->RewriteIfKeyboardDrivenOnLoginScreen(event);
 #endif
   RewriteModifiers(event);
   RewriteNumPadKeys(event);
@@ -414,8 +419,7 @@
     return;
   }
 
-  const PrefService* pref_service =
-      pref_service_ ? pref_service_ : GetPrefService();
+  const PrefService* pref_service = GetPrefService();
   if (!pref_service)
     return;
 
@@ -468,6 +472,7 @@
 }
 
 bool EventRewriter::RewriteModifiers(ui::KeyEvent* event) {
+#if defined(OS_CHROMEOS)
   // Do nothing if we have just logged in as guest but have not restarted chrome
   // process yet (so we are still on the login screen). In this situations we
   // have no user profile so can not do anything useful.
@@ -475,17 +480,14 @@
   // restart chrome process. In future this is to be changed.
   // TODO(glotov): remove the following condition when we do not restart chrome
   // when user logs in as guest.
-#if defined(OS_CHROMEOS)
   if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
       chromeos::LoginDisplayHostImpl::default_host())
     return false;
-#endif  // defined(OS_CHROMEOS)
-  const PrefService* pref_service =
-      pref_service_ ? pref_service_ : GetPrefService();
+
+  const PrefService* pref_service = GetPrefService();
   if (!pref_service)
     return false;
 
-#if defined(OS_CHROMEOS)
   DCHECK_EQ(chromeos::input_method::kControlKey,
             kModifierRemappingCtrl->remap_to);
 
@@ -567,8 +569,8 @@
   if ((event->type() == ui::ET_KEY_PRESSED) &&
       (event->key_code() != ui::VKEY_CAPITAL) &&
       (remapped_keycode == ui::VKEY_CAPITAL)) {
-    chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ?
-        xkeyboard_ :
+    chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_for_testing_ ?
+        xkeyboard_for_testing_ :
         chromeos::input_method::InputMethodManager::Get()->GetXKeyboard();
     xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled());
   }
diff --git a/chrome/browser/ui/ash/event_rewriter.h b/chrome/browser/ui/ash/event_rewriter.h
index 431eddf..68ef918 100644
--- a/chrome/browser/ui/ash/event_rewriter.h
+++ b/chrome/browser/ui/ash/event_rewriter.h
@@ -65,11 +65,11 @@
     last_device_id_ = device_id;
   }
   void set_pref_service_for_testing(const PrefService* pref_service) {
-    pref_service_ = pref_service;
+    pref_service_for_testing_ = pref_service;
   }
 #if defined(OS_CHROMEOS)
   void set_xkeyboard_for_testing(chromeos::input_method::XKeyboard* xkeyboard) {
-    xkeyboard_ = xkeyboard;
+    xkeyboard_for_testing_ = xkeyboard;
   }
 #endif
 
@@ -115,6 +115,12 @@
     unsigned int output_native_mods;
   };
 
+  // Returns true if the target for |event| would prefer to receive raw function
+  // keys instead of having them rewritten into back, forward, brightness,
+  // volume, etc. or if the user has specified that they desire top-row keys to
+  // be treated as function keys globally.
+  bool TopRowKeysAreFunctionKeys(ui::KeyEvent* event) const;
+
   // Given a set of KeyboardRemapping structs, it finds a matching struct
   // if possible, and updates the remapped event values. Returns true if a
   // remapping was found and remapped values were updated.
@@ -146,6 +152,9 @@
       unsigned int* remapped_mods);
 #endif
 
+  // Returns the PrefService that should be used.
+  const PrefService* GetPrefService() const;
+
   // Rewrites the |event| by applying all RewriteXXX functions as needed.
   void Rewrite(ui::KeyEvent* event);
 
@@ -214,13 +223,13 @@
   // A mapping from X11 KeySym keys to KeyCode values.
   base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_;
 
-  chromeos::input_method::XKeyboard* xkeyboard_;  // for testing.
+  chromeos::input_method::XKeyboard* xkeyboard_for_testing_;
 
   scoped_ptr<chromeos::KeyboardDrivenEventRewriter>
-      keyboard_driven_event_rewritter_;
+      keyboard_driven_event_rewriter_;
 #endif
 
-  const PrefService* pref_service_;  // for testing.
+  const PrefService* pref_service_for_testing_;
 
   DISALLOW_COPY_AND_ASSIGN(EventRewriter);
 };
diff --git a/chrome/browser/ui/ash/event_rewriter_unittest.cc b/chrome/browser/ui/ash/event_rewriter_unittest.cc
index 4009c93..4bbfb9e 100644
--- a/chrome/browser/ui/ash/event_rewriter_unittest.cc
+++ b/chrome/browser/ui/ash/event_rewriter_unittest.cc
@@ -2332,13 +2332,19 @@
 // Tests of event rewriting that depend on the Ash window manager.
 class EventRewriterAshTest : public ash::test::AshTestBase {
  public:
-  EventRewriterAshTest() {}
+  EventRewriterAshTest() {
+    chromeos::Preferences::RegisterProfilePrefs(prefs_.registry());
+    rewriter_.set_pref_service_for_testing(&prefs_);
+  }
   virtual ~EventRewriterAshTest() {}
 
   bool RewriteFunctionKeys(ui::KeyEvent* event) {
     return rewriter_.RewriteFunctionKeys(event);
   }
 
+ protected:
+  TestingPrefServiceSyncable prefs_;
+
  private:
   EventRewriter rewriter_;
 
@@ -2361,13 +2367,25 @@
   // Simulate an apps v2 window that has requested top row keys as function
   // keys. The event should not be rewritten.
   window_state->set_top_row_keys_are_function_keys(true);
-  EXPECT_FALSE(RewriteFunctionKeys(&press_f1));
-  EXPECT_EQ(ui::VKEY_F1, press_f1.key_code());
+  ASSERT_FALSE(RewriteFunctionKeys(&press_f1));
+  ASSERT_EQ(ui::VKEY_F1, press_f1.key_code());
 
-  // For a regular window, F1 is rewritten to the back key.
+  // The event should also not be rewritten if the send-function-keys pref is
+  // additionally set, for both apps v2 and regular windows.
+  BooleanPrefMember send_function_keys_pref;
+  send_function_keys_pref.Init(prefs::kLanguageSendFunctionKeys, &prefs_);
+  send_function_keys_pref.SetValue(true);
+  ASSERT_FALSE(RewriteFunctionKeys(&press_f1));
+  ASSERT_EQ(ui::VKEY_F1, press_f1.key_code());
   window_state->set_top_row_keys_are_function_keys(false);
-  EXPECT_TRUE(RewriteFunctionKeys(&press_f1));
-  EXPECT_EQ(ui::VKEY_BROWSER_BACK, press_f1.key_code());
+  ASSERT_FALSE(RewriteFunctionKeys(&press_f1));
+  ASSERT_EQ(ui::VKEY_F1, press_f1.key_code());
+
+  // If the pref isn't set when an event is sent to a regular window, F1 is
+  // rewritten to the back key.
+  send_function_keys_pref.SetValue(false);
+  ASSERT_TRUE(RewriteFunctionKeys(&press_f1));
+  ASSERT_EQ(ui::VKEY_BROWSER_BACK, press_f1.key_code());
 }
 
 #endif  // OS_CHROMEOS
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
index e6dcb12..cbb15ec 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -126,7 +126,7 @@
       launcher_controller()->GetV1ApplicationsFromAppId(app_id());
   for (size_t i = 0; i < content.size(); i++) {
     Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
-    if (!browser)
+    if (!browser || !launcher_controller()->IsBrowserFromActiveUser(browser))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     int index = tab_strip->GetIndexOfWebContents(content[i]);
@@ -178,6 +178,8 @@
   for (BrowserList::const_iterator it = ash_browser_list->begin();
        it != ash_browser_list->end(); ++it) {
     Browser* browser = *it;
+    if (!launcher_controller()->IsBrowserFromActiveUser(browser))
+      continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     for (int index = 0; index < tab_strip->count(); index++) {
       content::WebContents* web_contents = tab_strip->GetWebContentsAt(index);
@@ -207,7 +209,7 @@
 }
 
 ui::MenuModel* AppShortcutLauncherItemController::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   ash::LauncherItem item =
       *(launcher_controller()->model()->ItemByID(launcher_id()));
   return new LauncherContextMenu(launcher_controller(), &item, root_window);
@@ -248,6 +250,8 @@
        it = ash_browser_list->begin_last_active();
        it != ash_browser_list->end_last_active(); ++it) {
     Browser* browser = *it;
+    if (!launcher_controller()->IsBrowserFromActiveUser(browser))
+      continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     // We start to enumerate from the active index.
     int active_index = tab_strip->active_index();
@@ -264,6 +268,8 @@
   for (BrowserList::const_iterator it = ash_browser_list->begin();
        it != ash_browser_list->end(); ++it) {
     Browser* browser = *it;
+    if (!launcher_controller()->IsBrowserFromActiveUser(browser))
+      continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     for (int index = 0; index < tab_strip->count(); index++) {
       content::WebContents* web_contents = tab_strip->GetWebContentsAt(index);
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
index 3dc6726..f74725f 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -47,7 +47,7 @@
   virtual void ItemSelected(const ui::Event& event) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 8412877..fb0ab5b 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -8,7 +8,7 @@
 
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_model.h"
-#include "ash/shelf/shelf_util.h"
+#include "ash/launcher/launcher_model_util.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -60,8 +60,9 @@
   ash::LauncherModel* model = launcher_controller()->model();
 
   // Determine the new browser's active state and change if necessary.
-  size_t browser_index = ash::GetBrowserItemIndex(*model);
-  DCHECK_GE(browser_index, 0u);
+  int browser_index =
+      ash::GetLauncherItemIndexForType(ash::TYPE_BROWSER_SHORTCUT, *model);
+  DCHECK_GE(browser_index, 0);
   ash::LauncherItem browser_item = model->items()[browser_index];
   ash::LauncherItemStatus browser_status = ash::STATUS_CLOSED;
 
@@ -116,7 +117,12 @@
 bool BrowserShortcutLauncherItemController::IsOpen() const {
   const BrowserList* ash_browser_list =
       BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
-  return ash_browser_list->empty() ? false : true;
+  for (BrowserList::const_iterator it = ash_browser_list->begin();
+       it != ash_browser_list->end(); ++it) {
+    if (launcher_controller()->IsBrowserFromActiveUser(*it))
+      return true;
+  }
+  return false;
 }
 
 bool BrowserShortcutLauncherItemController::IsVisible() const {
@@ -166,8 +172,10 @@
   for (BrowserList::const_iterator it = ash_browser_list->begin();
        it != ash_browser_list->end(); ++it) {
     Browser* browser = *it;
-    // Make sure that the browser was already shown and it has a proper window.
-    if (std::find(ash_browser_list->begin_last_active(),
+    // Make sure that the browser was already shown, is from the current user
+    // and has a proper window.
+    if (!launcher_controller()->IsBrowserFromActiveUser(browser) ||
+        std::find(ash_browser_list->begin_last_active(),
                   ash_browser_list->end_last_active(),
                   browser) == ash_browser_list->end_last_active() ||
         !browser->window())
@@ -234,7 +242,7 @@
 }
 
 ui::MenuModel* BrowserShortcutLauncherItemController::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   ash::LauncherItem item =
       *(launcher_controller()->model()->ItemByID(launcher_id()));
   return new LauncherContextMenu(launcher_controller(), &item, root_window);
@@ -329,6 +337,7 @@
 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
     Browser* browser) {
   return (browser &&
+          launcher_controller()->IsBrowserFromActiveUser(browser) &&
           browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH &&
           (browser->is_type_tabbed() ||
            !browser->is_app() ||
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
index fbdfd97..d4e64e5 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
@@ -41,7 +41,7 @@
   virtual void ItemSelected(const ui::Event& event) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
index d3268de..2a925bc 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -97,7 +97,9 @@
     content::WebContents* contents,
     ChromeLauncherController::AppState app_state) {
   DCHECK(contents);
-  launcher_controller_->UpdateAppState(contents, app_state);
+  if (launcher_controller_->IsBrowserFromActiveUser(
+          chrome::FindBrowserWithWebContents(contents)))
+    launcher_controller_->UpdateAppState(contents, app_state);
 }
 
 void BrowserStatusMonitor::UpdateBrowserItemState() {
@@ -149,15 +151,13 @@
   if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
     return;
 
-  browser->tab_strip_model()->AddObserver(this);
-
   if (browser->is_type_popup() && browser->is_app()) {
-    std::string app_id =
-        web_app::GetExtensionIdFromApplicationName(browser->app_name());
-    if (!app_id.empty()) {
-      browser_to_app_id_map_[browser] = app_id;
-      launcher_controller_->LockV1AppWithID(app_id);
-    }
+    // Note: A V1 application will set the tab strip observer when the app gets
+    // added to the shelf. This makes sure that in the multi user case we will
+    // only set the observer while the app item exists in the shelf.
+    AddV1AppToShelf(browser);
+  } else {
+    browser->tab_strip_model()->AddObserver(this);
   }
 }
 
@@ -165,12 +165,11 @@
   if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
     return;
 
-  browser->tab_strip_model()->RemoveObserver(this);
+  if (browser->is_type_popup() && browser->is_app())
+    RemoveV1AppFromShelf(browser);
+  else
+    browser->tab_strip_model()->RemoveObserver(this);
 
-  if (browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end()) {
-    launcher_controller_->UnlockV1AppWithID(browser_to_app_id_map_[browser]);
-    browser_to_app_id_map_.erase(browser);
-  }
   UpdateBrowserItemState();
 }
 
@@ -181,7 +180,7 @@
 
 void BrowserStatusMonitor::OnDisplayAdded(const gfx::Display& new_display) {
   // Add a new RootWindow and its ActivationClient to observed list.
-  aura::RootWindow* root_window = ash::Shell::GetInstance()->
+  aura::Window* root_window = ash::Shell::GetInstance()->
       display_controller()->GetRootWindowForDisplayId(new_display.id());
   // When the primary root window's display get removed, the existing root
   // window is taken over by the new display and the observer is already set.
@@ -270,6 +269,34 @@
   RemoveWebContentsObserver(contents);
 }
 
+void BrowserStatusMonitor::AddV1AppToShelf(Browser* browser) {
+  DCHECK(browser->is_type_popup() && browser->is_app());
+
+  browser->tab_strip_model()->AddObserver(this);
+
+  std::string app_id =
+      web_app::GetExtensionIdFromApplicationName(browser->app_name());
+  if (!app_id.empty()) {
+    browser_to_app_id_map_[browser] = app_id;
+    launcher_controller_->LockV1AppWithID(app_id);
+  }
+}
+
+void BrowserStatusMonitor::RemoveV1AppFromShelf(Browser* browser) {
+  DCHECK(browser->is_type_popup() && browser->is_app());
+
+  browser->tab_strip_model()->RemoveObserver(this);
+
+  if (browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end()) {
+    launcher_controller_->UnlockV1AppWithID(browser_to_app_id_map_[browser]);
+    browser_to_app_id_map_.erase(browser);
+  }
+}
+
+bool BrowserStatusMonitor::IsV1AppInShelf(Browser* browser) {
+  return browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end();
+}
+
 void BrowserStatusMonitor::AddWebContentsObserver(
     content::WebContents* contents) {
   if (webcontents_to_observer_map_.find(contents) ==
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.h b/chrome/browser/ui/ash/launcher/browser_status_monitor.h
index 4027160..f7a44d4 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.h
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.h
@@ -42,6 +42,12 @@
   explicit BrowserStatusMonitor(ChromeLauncherController* launcher_controller);
   virtual ~BrowserStatusMonitor();
 
+  // A function which gets called when the current user has changed.
+  // Note that this function is called by the ChromeLauncherController to be
+  // able to do the activation in a proper order - rather then setting an
+  // observer.
+  virtual void ActiveUserChanged(const std::string& user_email) {}
+
   // A shortcut to call the ChromeLauncherController's UpdateAppState().
   void UpdateAppItemState(content::WebContents* contents,
                           ChromeLauncherController::AppState app_state);
@@ -82,6 +88,18 @@
                             content::WebContents* contents,
                             int index) OVERRIDE;
 
+ protected:
+  // Add a V1 application to the shelf. This can get overwritten for multi
+  // profile implementations.
+  virtual void AddV1AppToShelf(Browser* browser);
+
+  // Remove a V1 application from the shelf. This can get overwritten for multi
+  // profile implementations.
+  virtual void RemoveV1AppFromShelf(Browser* browser);
+
+  // Check if V1 application is currently in the shelf.
+  bool IsV1AppInShelf(Browser* browser);
+
  private:
   // This class monitors the WebContent of the all tab and notifies a navigation
   // to the BrowserStatusMonitor.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 780c3b5..52b9114 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -11,13 +11,14 @@
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_item_delegate_manager.h"
 #include "ash/launcher/launcher_model.h"
+#include "ash/launcher/launcher_model_util.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_util.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/app_sync_ui_state.h"
@@ -81,13 +81,17 @@
 #include "ui/views/corewm/window_animations.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
+#include "chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h"
+#include "chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/multi_user_window_manager.h"
 #endif
 
 using extensions::Extension;
+using extensions::UnloadedExtensionInfo;
 using extension_misc::kGmailAppId;
 using content::WebContents;
 
@@ -101,7 +105,7 @@
 // will ignore it.
 const char kAppLauncherIdPlaceholder[] = "AppLauncherIDPlaceholder--------";
 
-std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
+std::string GetPrefKeyForRootWindow(aura::Window* root_window) {
   gfx::Display display = gfx::Screen::GetScreenFor(
       root_window)->GetDisplayNearestWindow(root_window);
   DCHECK(display.is_valid());
@@ -110,7 +114,7 @@
 }
 
 void UpdatePerDisplayPref(PrefService* pref_service,
-                          aura::RootWindow* root_window,
+                          aura::Window* root_window,
                           const char* pref_key,
                           const std::string& value) {
   std::string key = GetPrefKeyForRootWindow(root_window);
@@ -143,7 +147,7 @@
 //  * The default value for |local_path| if the value is not recommended by
 //    policy.
 std::string GetPrefForRootWindow(PrefService* pref_service,
-                                 aura::RootWindow* root_window,
+                                 aura::Window* root_window,
                                  const char* local_path,
                                  const char* path) {
   const PrefService::Preference* local_pref =
@@ -213,16 +217,23 @@
 }  // namespace
 
 #if defined(OS_CHROMEOS)
-// A class to get events from ChromeOS when a user gets changed.
+// A class to get events from ChromeOS when a user gets changed or added.
 class ChromeLauncherControllerUserSwitchObserverChromeOS
     : public ChromeLauncherControllerUserSwitchObserver,
-      public chromeos::UserManager::UserSessionStateObserver {
+      public chromeos::UserManager::UserSessionStateObserver,
+      content::NotificationObserver {
  public:
   ChromeLauncherControllerUserSwitchObserverChromeOS(
       ChromeLauncherController* controller)
       : controller_(controller) {
     DCHECK(chromeos::UserManager::IsInitialized());
     chromeos::UserManager::Get()->AddSessionStateObserver(this);
+    // A UserAddedToSession notification can be sent before a profile is loaded.
+    // Since our observers require that we have already a profile, we might have
+    // to postpone the notification until the ProfileManager lets us know that
+    // the profile for that newly added user was added to the ProfileManager.
+    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
+                   content::NotificationService::AllSources());
   }
   virtual ~ChromeLauncherControllerUserSwitchObserverChromeOS() {
     chromeos::UserManager::Get()->RemoveSessionStateObserver(this);
@@ -230,11 +241,28 @@
 
   // chromeos::UserManager::UserSessionStateObserver overrides:
   virtual void ActiveUserChanged(const chromeos::User* active_user) OVERRIDE;
+  virtual void UserAddedToSession(const chromeos::User* added_user) OVERRIDE;
+
+  // content::NotificationObserver overrides:
+  virtual void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) OVERRIDE;
 
  private:
+  // Add a user to the session.
+  void AddUser(Profile* profile);
+
   // The owning ChromeLauncherController.
   ChromeLauncherController* controller_;
 
+  // The notification registrar to track the Profile creations after a user got
+  // added to the session (if required).
+  content::NotificationRegistrar registrar_;
+
+  // Users which were just added to the system, but which profiles were not yet
+  // (fully) loaded.
+  std::set<std::string> added_user_ids_waiting_for_profiles_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerUserSwitchObserverChromeOS);
 };
 
@@ -248,6 +276,47 @@
   if (chromeos::WallpaperManager::Get())
     chromeos::WallpaperManager::Get()->SetUserWallpaper(user_email);
 }
+
+void ChromeLauncherControllerUserSwitchObserverChromeOS::UserAddedToSession(
+    const chromeos::User* active_user) {
+  Profile* profile = chrome::MultiUserWindowManager::GetProfileFromUserID(
+      active_user->email());
+  // If we do not have a profile yet, we postpone forwarding the notification
+  // until it is loaded.
+  if (!profile)
+    added_user_ids_waiting_for_profiles_.insert(active_user->email());
+  else
+    AddUser(profile);
+}
+
+void ChromeLauncherControllerUserSwitchObserverChromeOS::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  if (type == chrome::NOTIFICATION_PROFILE_ADDED &&
+      !added_user_ids_waiting_for_profiles_.empty()) {
+    // Check if the profile is from a user which was on the waiting list.
+    Profile* profile = content::Source<Profile>(source).ptr();
+    std::string user_id = chrome::MultiUserWindowManager::GetUserIDFromProfile(
+        profile);
+    std::set<std::string>::iterator it = std::find(
+        added_user_ids_waiting_for_profiles_.begin(),
+        added_user_ids_waiting_for_profiles_.end(),
+        user_id);
+    if (it != added_user_ids_waiting_for_profiles_.end()) {
+      added_user_ids_waiting_for_profiles_.erase(it);
+      AddUser(profile->GetOriginalProfile());
+    }
+  }
+}
+
+void ChromeLauncherControllerUserSwitchObserverChromeOS::AddUser(
+    Profile* profile) {
+  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
+          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
+    chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
+  controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile());
+}
 #endif
 
 ChromeLauncherController::ChromeLauncherController(
@@ -270,9 +339,43 @@
 
   // All profile relevant settings get bound to the current profile.
   AttachProfile(profile_);
-
-  browser_status_monitor_.reset(new BrowserStatusMonitor(this));
   model_->AddObserver(this);
+
+#if defined(OS_CHROMEOS)
+  // In multi profile mode we might have a window manager. We try to create it
+  // here. If the instantiation fails, the manager is not needed.
+  chrome::MultiUserWindowManager::CreateInstance();
+
+  // On Chrome OS using multi profile we want to switch the content of the shelf
+  // with a user change. Note that for unit tests the instance can be NULL.
+  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
+          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_OFF) {
+    user_switch_observer_.reset(
+        new ChromeLauncherControllerUserSwitchObserverChromeOS(this));
+  }
+
+  // Create our v1/v2 application / browser monitors which will inform the
+  // launcher of status changes.
+  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
+          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
+    // If running in separated destkop mode, we create the multi profile version
+    // of status monitor.
+    browser_status_monitor_.reset(new MultiProfileBrowserStatusMonitor(this));
+    shell_window_controller_.reset(
+        new MultiProfileShellWindowLauncherController(this));
+  } else {
+    // Create our v1/v2 application / browser monitors which will inform the
+    // launcher of status changes.
+    browser_status_monitor_.reset(new BrowserStatusMonitor(this));
+    shell_window_controller_.reset(new ShellWindowLauncherController(this));
+  }
+#else
+  // Create our v1/v2 application / browser monitors which will inform the
+  // launcher of status changes.
+  browser_status_monitor_.reset(new BrowserStatusMonitor(this));
+  shell_window_controller_.reset(new ShellWindowLauncherController(this));
+#endif
+
   // Right now ash::Shell isn't created for tests.
   // TODO(mukai): Allows it to observe display change and write tests.
   if (ash::Shell::HasInstance()) {
@@ -280,8 +383,6 @@
     item_delegate_manager_ =
         ash::Shell::GetInstance()->launcher_item_delegate_manager();
   }
-  // TODO(stevenjb): Find a better owner for shell_window_controller_?
-  shell_window_controller_.reset(new ShellWindowLauncherController(this));
 
   notification_registrar_.Add(this,
                               chrome::NOTIFICATION_EXTENSION_LOADED,
@@ -289,19 +390,6 @@
   notification_registrar_.Add(this,
                               chrome::NOTIFICATION_EXTENSION_UNLOADED,
                               content::Source<Profile>(profile_));
-
-#if defined(OS_CHROMEOS)
-  // On Chrome OS using multi profile we want to switch the content of the shelf
-  // with a user change. Note that for unit tests the instance can be NULL.
-  if (ChromeShellDelegate::instance() &&
-      ChromeShellDelegate::instance()->IsMultiProfilesEnabled()) {
-    user_switch_observer_.reset(
-        new ChromeLauncherControllerUserSwitchObserverChromeOS(this));
-    // TODO(skuhne): Find a better place where to instantiate this. Note that
-    // once we start using the manager for other operations it will load itself.
-    chrome::MultiUserWindowManager::GetInstance();
-  }
-#endif
 }
 
 ChromeLauncherController::~ChromeLauncherController() {
@@ -338,8 +426,6 @@
     instance_ = NULL;
 #if defined(OS_CHROMEOS)
   // Get rid of the multi user window manager instance.
-  // TODO(skuhne): Find a better place where this can be deleted. Looked at
-  // ash_init.cc, but it could only be deleted there, not created.
   chrome::MultiUserWindowManager::DeleteInstance();
 #endif
 }
@@ -670,7 +756,7 @@
 }
 
 void ChromeLauncherController::OnAutoHideBehaviorChanged(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     ash::ShelfAutoHideBehavior new_behavior) {
   SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
 }
@@ -801,7 +887,7 @@
 }
 
 ash::ShelfAutoHideBehavior ChromeLauncherController::GetShelfAutoHideBehavior(
-    aura::RootWindow* root_window) const {
+    aura::Window* root_window) const {
   // Don't show the shelf in app mode.
   if (chrome::IsRunningInAppMode())
     return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
@@ -823,13 +909,13 @@
 }
 
 bool ChromeLauncherController::CanUserModifyShelfAutoHideBehavior(
-    aura::RootWindow* root_window) const {
+    aura::Window* root_window) const {
   return profile_->GetPrefs()->
       FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
 }
 
 void ChromeLauncherController::ToggleShelfAutoHideBehavior(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
       ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
           ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
@@ -946,6 +1032,21 @@
 void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
     ui::BaseWindow* window,
     bool allow_minimize) {
+#if defined(OS_CHROMEOS)
+  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
+          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
+    chrome::MultiUserWindowManager* manager =
+        chrome::MultiUserWindowManager::GetInstance();
+    aura::Window* native_window = window->GetNativeWindow();
+    const std::string& current_user =
+        manager->GetUserIDFromProfile(profile());
+    if (!manager->IsWindowOnDesktopOfUser(native_window, current_user)) {
+      manager->ShowWindowForUser(native_window, current_user);
+      window->Activate();
+      return;
+    }
+  }
+#endif
   if (window->IsActive() && allow_minimize) {
     if (CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kDisableMinimizeOnSecondLauncherItemClick)) {
@@ -961,7 +1062,8 @@
 }
 
 ash::LauncherID ChromeLauncherController::GetIDByWindow(aura::Window* window) {
-  int browser_index = ash::GetBrowserItemIndex(*model_);
+  int browser_index =
+      ash::GetLauncherItemIndexForType(ash::TYPE_BROWSER_SHORTCUT, *model_);
   DCHECK_GE(browser_index, 0);
   ash::LauncherID browser_id = model_->items()[browser_index].id;
 
@@ -1030,11 +1132,21 @@
   // resources get released and the new profile gets attached instead.
   ReleaseProfile();
   AttachProfile(ProfileManager::GetDefaultProfile());
+  // Update the V1 applications.
+  browser_status_monitor_->ActiveUserChanged(user_email);
+  // Switch the running applications to the new user.
+  shell_window_controller_->ActiveUserChanged(user_email);
   // Update the user specific shell properties from the new user profile.
   UpdateAppLaunchersFromPref();
   SetShelfAlignmentFromPrefs();
   SetShelfAutoHideBehaviorFromPrefs();
   SetShelfBehaviorsFromPrefs();
+  UpdateV1AppStatesAfterUserSwitch();
+}
+
+void ChromeLauncherController::AdditionalUserAddedToSession(Profile* profile) {
+  // Switch the running applications to the new user.
+  shell_window_controller_->AdditionalUserAddedToSession(profile);
 }
 
 void ChromeLauncherController::Observe(
@@ -1055,19 +1167,18 @@
       break;
     }
     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const content::Details<extensions::UnloadedExtensionInfo>& unload_info(
-          details);
+      const content::Details<UnloadedExtensionInfo>& unload_info(details);
       const Extension* extension = unload_info->extension;
       const std::string& id = extension->id();
       // Since we might have windowed apps of this type which might have
       // outstanding locks which needs to be removed.
       if (GetLauncherIDForAppID(id) &&
-          unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
+          unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
         CloseWindowedAppsFromRemovedExtension(id);
       }
 
       if (IsAppPinned(id)) {
-        if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
+        if (unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
           DoUnpinAppWithID(id);
           app_icon_loader_->ClearImage(id);
         } else {
@@ -1082,7 +1193,7 @@
 }
 
 void ChromeLauncherController::OnShelfAlignmentChanged(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   const char* pref_value = NULL;
   switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
     case ash::SHELF_ALIGNMENT_BOTTOM:
@@ -1283,6 +1394,21 @@
   return id_to_item_controller_map_[id];
 }
 
+bool ChromeLauncherController::IsBrowserFromActiveUser(Browser* browser) {
+#if defined(OS_CHROMEOS)
+  // If running multi user mode with separate desktops, we have to check if the
+  // browser is from the active user.
+  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
+          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
+    return true;
+  chromeos::UserManager* manager = chromeos::UserManager::Get();
+  return manager->GetActiveUser() ==
+         manager->GetUserByProfile(browser->profile()->GetOriginalProfile());
+#else
+  return true;
+#endif
+}
+
 Profile* ChromeLauncherController::GetProfileForNewWindows() {
   return ProfileManager::GetDefaultProfileOrOffTheRecord();
 }
@@ -1502,7 +1628,7 @@
 
 void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
     ash::ShelfAutoHideBehavior behavior,
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   const char* value = NULL;
   switch (behavior) {
     case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
@@ -1886,3 +2012,53 @@
 
   pref_change_registrar_.RemoveAll();
 }
+
+void ChromeLauncherController::UpdateV1AppStatesAfterUserSwitch() {
+#if defined(OS_CHROMEOS)
+  if (!ash::switches::UseFullMultiProfileMode() &&
+      ChromeShellDelegate::instance() &&
+      ChromeShellDelegate::instance()->IsMultiProfilesEnabled()) {
+    // First we add the new applications.
+    BrowserList* browser_list =
+        BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+    chromeos::UserManager* user_manager = chromeos::UserManager::Get();
+    chromeos::User* active_user = user_manager->GetActiveUser();
+
+    // Remove old (tabbed V1) applications.
+    for (BrowserList::const_iterator it = browser_list->begin();
+         it != browser_list->end(); ++it) {
+      Browser* browser = *it;
+      if (!browser->is_app() &&
+          browser->is_type_tabbed() &&
+          active_user != user_manager->GetUserByProfile(
+              browser->profile()->GetOriginalProfile())) {
+        for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
+          UpdateAppState(browser->tab_strip_model()->GetWebContentsAt(i),
+                         APP_STATE_REMOVED);
+        }
+      }
+    }
+
+    // Add new (tabbed V1) applications.
+    for (BrowserList::const_iterator it = browser_list->begin();
+         it != browser_list->end(); ++it) {
+      Browser* browser = *it;
+      if (!browser->is_app() &&
+          browser->is_type_tabbed() &&
+          active_user == user_manager->GetUserByProfile(
+              browser->profile()->GetOriginalProfile())) {
+        int active_index = browser->tab_strip_model()->active_index();
+        for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
+          UpdateAppState(browser->tab_strip_model()->GetWebContentsAt(i),
+                         browser->window()->IsActive() && i == active_index ?
+                             APP_STATE_WINDOW_ACTIVE : APP_STATE_INACTIVE);
+        }
+      }
+    }
+  }
+
+  // Finally we update the browser state itself.
+  browser_status_monitor_->UpdateBrowserItemState();
+#endif
+}
+
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 8057626..cec1f87 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -252,15 +252,15 @@
 
   // Gets the shelf auto-hide behavior on |root_window|.
   ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const;
+      aura::Window* root_window) const;
 
   // Returns |true| if the user is allowed to modify the shelf auto-hide
   // behavior on |root_window|.
-  bool CanUserModifyShelfAutoHideBehavior(aura::RootWindow* root_window) const;
+  bool CanUserModifyShelfAutoHideBehavior(aura::Window* root_window) const;
 
   // Toggles the shelf auto-hide behavior on |root_window|. Does nothing if the
   // user is not allowed to modify the auto-hide behavior.
-  void ToggleShelfAutoHideBehavior(aura::RootWindow* root_window);
+  void ToggleShelfAutoHideBehavior(aura::Window* root_window);
 
   // The tab no longer represents its previously identified application.
   void RemoveTabFromRunningApp(content::WebContents* tab,
@@ -308,7 +308,7 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
   // ash::ShellObserver overrides:
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
+  virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE;
 
   // ash::DisplayController::Observer overrides:
   virtual void OnDisplayConfigurationChanging() OVERRIDE;
@@ -330,12 +330,15 @@
 
   // ash::ShelfLayoutManagerObserver overrides:
   virtual void OnAutoHideBehaviorChanged(
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       ash::ShelfAutoHideBehavior new_behavior) OVERRIDE;
 
   // Called when the active user has changed.
   void ActiveUserChanged(const std::string& user_email);
 
+  // Called when a user got added to the session.
+  void AdditionalUserAddedToSession(Profile* profile);
+
   // Get the list of all running incarnations of this item.
   // |event_flags| specifies the flags which were set by the event which
   // triggered this menu generation. It can be used to generate different lists.
@@ -373,6 +376,14 @@
 
   LauncherItemController* GetLauncherItemController(const ash::LauncherID id);
 
+  // Returns true if |browser| is owned by the active user.
+  bool IsBrowserFromActiveUser(Browser* browser);
+
+  // Access to the BrowserStatusMonitor for tests.
+  BrowserStatusMonitor* browser_status_monitor_for_test() {
+    return browser_status_monitor_.get();
+  }
+
  protected:
   // Creates a new app shortcut item and controller on the launcher at |index|.
   // Use kInsertItemAtEnd to add a shortcut as the last item.
@@ -433,7 +444,7 @@
 
   // Persists the shelf auto-hide behavior to prefs.
   void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior,
-                                     aura::RootWindow* root_window);
+                                     aura::Window* root_window);
 
   // Sets the shelf auto-hide behavior from prefs.
   void SetShelfAutoHideBehaviorFromPrefs();
@@ -512,6 +523,9 @@
   // Forget the current profile to allow attaching to a new one.
   void ReleaseProfile();
 
+  // Update the state of all V1 shortcut launcher items after a user switch.
+  void UpdateV1AppStatesAfterUserSwitch();
+
   static ChromeLauncherController* instance_;
 
   ash::LauncherModel* model_;
@@ -559,6 +573,9 @@
   // If true, incoming pinned state changes should be ignored.
   bool ignore_persist_pinned_state_change_;
 
+  // True if each user has an own desktop.
+  bool multi_profile_desktop_separation_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeLauncherController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index c9f37ca..d351190 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -12,9 +12,10 @@
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_button.h"
 #include "ash/launcher/launcher_model.h"
-#include "ash/shelf/shelf_util.h"
+#include "ash/launcher/launcher_model_util.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shell.h"
+#include "ash/test/app_list_controller_test_api.h"
 #include "ash/test/launcher_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/shell_test_api.h"
@@ -268,11 +269,7 @@
 
   // Get the index of an item which has the given type.
   int GetIndexOfLauncherItemType(ash::LauncherItemType type) {
-    for (int i = 0; i < model_->item_count(); i++) {
-      if (model_->items()[i].type == type)
-        return i;
-    }
-    return -1;
+    return ash::GetLauncherItemIndexForType(type, *model_);
   }
 
   // Try to rip off |item_index|.
@@ -1030,7 +1027,7 @@
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, TabDragAndDrop) {
   TabStripModel* tab_strip_model1 = browser()->tab_strip_model();
   EXPECT_EQ(1, tab_strip_model1->count());
-  int browser_index = ash::GetBrowserItemIndex(*model_);
+  int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT);
   EXPECT_TRUE(browser_index >= 0);
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
 
@@ -1173,7 +1170,7 @@
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ActivationStateCheck) {
   TabStripModel* tab_strip = browser()->tab_strip_model();
   // Get the browser item index
-  int browser_index = ash::GetBrowserItemIndex(*controller_->model());
+  int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT);
   EXPECT_TRUE(browser_index >= 0);
 
   // Even though we are just comming up, the browser should be active.
@@ -1547,7 +1544,7 @@
       ash::Shell::GetPrimaryRootWindow(), gfx::Point());
   ash::test::ShelfViewTestAPI test(
       ash::test::LauncherTestAPI(launcher_).shelf_view());
-  AppListService* service = AppListService::Get();
+  AppListService* service = AppListService::Get(chrome::GetActiveDesktop());
 
   // There should be two items in our launcher by this time.
   EXPECT_EQ(2, model_->item_count());
@@ -1563,7 +1560,8 @@
 
   EXPECT_TRUE(service->IsAppListVisible());
   app_list::AppsGridView* grid_view =
-      app_list::AppsGridView::GetLastGridViewForTest();
+      ash::test::AppListControllerTestApi(ash::Shell::GetInstance()).
+          GetRootGridView();
   ASSERT_TRUE(grid_view);
   ASSERT_TRUE(grid_view->has_drag_and_drop_host_for_test());
 
@@ -1764,7 +1762,7 @@
       ash::Shell::GetPrimaryRootWindow(), gfx::Point());
   ash::test::ShelfViewTestAPI test(
       ash::test::LauncherTestAPI(launcher_).shelf_view());
-  AppListService* service = AppListService::Get();
+  AppListService* service = AppListService::Get(chrome::GetActiveDesktop());
   // There should be two items in our launcher by this time.
   EXPECT_EQ(2, model_->item_count());
   EXPECT_FALSE(service->IsAppListVisible());
@@ -1779,7 +1777,8 @@
 
   EXPECT_TRUE(service->IsAppListVisible());
   app_list::AppsGridView* grid_view =
-      app_list::AppsGridView::GetLastGridViewForTest();
+      ash::test::AppListControllerTestApi(ash::Shell::GetInstance()).
+          GetRootGridView();
   ASSERT_TRUE(grid_view);
   const views::ViewModel* vm_grid = grid_view->view_model_for_test();
   EXPECT_EQ(2, vm_grid->view_size());
@@ -1835,7 +1834,7 @@
 
   aura::Window* window = browser()->window()->GetNativeWindow();
 
-  int browser_index = ash::GetBrowserItemIndex(*model_);
+  int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT);
   ash::LauncherID browser_id = model_->items()[browser_index].id;
   EXPECT_EQ(browser_id, controller_->GetIDByWindow(window));
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 45e281a..e1a1738 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -45,12 +45,34 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/menu_model.h"
 
+#if defined(OS_CHROMEOS)
+#include "ash/test/test_session_state_delegate.h"
+#include "ash/test/test_shell_delegate.h"
+#include "base/metrics/field_trial.h"
+#include "chrome/browser/chromeos/login/fake_user_manager.h"
+#include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
+#include "chrome/browser/ui/ash/multi_user_window_manager.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/variations/entropy_provider.h"
+#include "ui/aura/window.h"
+#endif
+
 using extensions::Extension;
 using extensions::Manifest;
+using extensions::UnloadedExtensionInfo;
 
 namespace {
 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
 const char* gmail_url = "https://mail.google.com/mail/u";
+
+// As defined in /chromeos/dbus/cryptohome_client.cc.
+const char kUserIdHashSuffix[] = "-hash";
+
+// An extension prefix.
+const char kCrxAppPrefix[] = "_crx_";
 }
 
 namespace {
@@ -215,7 +237,7 @@
     return items.Pass();
   }
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE { return NULL; }
+      aura::Window* root_window) OVERRIDE { return NULL; }
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE { return NULL; }
   virtual bool IsDraggable() OVERRIDE { return false; }
@@ -595,6 +617,210 @@
   DISALLOW_COPY_AND_ASSIGN(LegacyShelfLayoutChromeLauncherControllerTest);
 };
 
+#if defined(OS_CHROMEOS)
+// A browser window proxy which is able to associate an aura native window with
+// it.
+class TestBrowserWindowAura : public TestBrowserWindow {
+ public:
+  // |native_window| will still be owned by the caller after the constructor
+  // was called.
+  explicit TestBrowserWindowAura(aura::Window* native_window)
+      : native_window_(native_window) {
+  }
+  virtual ~TestBrowserWindowAura() {}
+
+  virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
+    return native_window_.get();
+  }
+
+  Browser* browser() { return browser_.get(); }
+
+  void CreateBrowser(const Browser::CreateParams& params) {
+    Browser::CreateParams create_params = params;
+    create_params.window = this;
+    browser_.reset(new Browser(create_params));
+  }
+
+ private:
+  scoped_ptr<Browser> browser_;
+  scoped_ptr<aura::Window> native_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura);
+};
+
+scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow(
+    const Browser::CreateParams& params) {
+  // Create a window.
+  aura::Window* window = new aura::Window(NULL);
+  window->set_id(0);
+  window->SetType(aura::client::WINDOW_TYPE_NORMAL);
+  window->Init(ui::LAYER_TEXTURED);
+  window->Show();
+
+  scoped_ptr<TestBrowserWindowAura> browser_window(
+      new TestBrowserWindowAura(window));
+  browser_window->CreateBrowser(params);
+  return browser_window.Pass();
+}
+
+// The testing framework to test multi profile scenarios.
+class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest
+    : public ChromeLauncherControllerTest {
+ protected:
+  MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
+  }
+
+  virtual ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
+  }
+
+  // Overwrite the Setup function to enable multi profile and needed objects.
+  virtual void SetUp() OVERRIDE {
+    profile_manager_.reset(
+        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
+
+    ASSERT_TRUE(profile_manager_->SetUp());
+
+    // AvatarMenu and multiple profiles works after user logged in.
+    profile_manager_->SetLoggedIn(true);
+
+    // Enabling multi profile requires several flags to be set.
+    CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMultiProfiles);
+    field_trial_list_.reset(new base::FieldTrialList(
+        new metrics::SHA1EntropyProvider("42")));
+    base::FieldTrialList::CreateTrialsFromString(
+        "ChromeOSUseMultiProfiles/Enable/",
+        base::FieldTrialList::ACTIVATE_TRIALS);
+
+    // Initialize the UserManager singleton to a fresh FakeUserManager instance.
+    user_manager_enabler_.reset(
+        new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
+
+    // Initialize the rest.
+    ChromeLauncherControllerTest::SetUp();
+
+    // Get some base objects.
+    session_delegate_ = static_cast<ash::test::TestSessionStateDelegate*>(
+        ash::Shell::GetInstance()->session_state_delegate());
+    session_delegate_->set_logged_in_users(2);
+    shell_delegate_ = static_cast<ash::test::TestShellDelegate*>(
+        ash::Shell::GetInstance()->delegate());
+    shell_delegate_->set_multi_profiles_enabled(true);
+  }
+
+  virtual void TearDown() {
+    ChromeLauncherControllerTest::TearDown();
+    user_manager_enabler_.reset();
+    field_trial_list_.reset();
+    for (ProfileToNameMap::iterator it = created_profiles_.begin();
+         it != created_profiles_.end(); ++it)
+      profile_manager_->DeleteTestingProfile(it->second);
+
+    // A Task is leaked if we don't destroy everything, then run the message
+    // loop.
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
+    base::MessageLoop::current()->Run();
+  }
+
+  // Creates a profile for a given |user_name|. Note that this class will keep
+  // the ownership of the created object.
+  TestingProfile* CreateMultiUserProfile(const std::string& user_name) {
+    std::string email_string = user_name + "@example.com";
+
+    // Add a user to the fake user manager.
+    GetFakeUserManager()->AddUser(email_string);
+
+    GetFakeUserManager()->UserLoggedIn(
+        email_string,
+        email_string + kUserIdHashSuffix,
+        false);
+
+    std::string profile_name =
+        chrome::kProfileDirPrefix + email_string + kUserIdHashSuffix;
+    TestingProfile* profile = profile_manager()->CreateTestingProfile(
+        profile_name,
+        scoped_ptr<PrefServiceSyncable>(),
+        ASCIIToUTF16(email_string), 0, std::string());
+    profile->set_profile_name(email_string);
+    EXPECT_TRUE(profile);
+    // Remember the profile name so that we can destroy it upon destruction.
+    created_profiles_[profile] = profile_name;
+    return profile;
+  }
+
+  // Switch to another user.
+  void SwitchActiveUser(const std::string& name) {
+    session_delegate()->SwitchActiveUser(name);
+    GetFakeUserManager()->SwitchActiveUser(name);
+    launcher_controller_->browser_status_monitor_for_test()->
+        ActiveUserChanged(name);
+  }
+
+  // Creates a browser with a |profile| and load a tab with a |title| and |url|.
+  Browser* CreateBrowserAndTabWithProfile(Profile* profile,
+                                          const std::string& title,
+                                          const std::string& url) {
+    Browser::CreateParams params(profile, chrome::HOST_DESKTOP_TYPE_ASH);
+    Browser* browser = chrome::CreateBrowserWithTestWindowForParams(&params);
+    chrome::NewTab(browser);
+
+    BrowserList::SetLastActive(browser);
+    NavigateAndCommitActiveTabWithTitle(
+        browser, GURL(url), ASCIIToUTF16(title));
+    return browser;
+  }
+
+  // Creates a browser with a |profile| and load a tab with a |title| and |url|.
+  Browser* CreateV1AppBrowserWithProfile(Profile* profile,
+                                         const std::string& app_name) {
+    Browser::CreateParams params = Browser::CreateParams::CreateForApp(
+        Browser::TYPE_POPUP,
+        kCrxAppPrefix + app_name,
+        gfx::Rect(),
+        profile,
+        chrome::HOST_DESKTOP_TYPE_ASH);
+    Browser* browser = chrome::CreateBrowserWithTestWindowForParams(&params);
+    return browser;
+  }
+
+  ash::test::TestSessionStateDelegate*
+      session_delegate() { return session_delegate_; }
+  ash::test::TestShellDelegate* shell_delegate() { return shell_delegate_; }
+
+  // Override BrowserWithTestWindowTest:
+  virtual TestingProfile* CreateProfile() OVERRIDE {
+    return CreateMultiUserProfile("user1");
+  }
+  virtual void DestroyProfile(TestingProfile* profile) OVERRIDE {
+    // Delete the profile through our profile manager.
+    ProfileToNameMap::iterator it = created_profiles_.find(profile);
+    DCHECK(it != created_profiles_.end());
+    profile_manager_->DeleteTestingProfile(it->second);
+    created_profiles_.erase(it);
+  }
+
+ private:
+  typedef std::map<Profile*, std::string> ProfileToNameMap;
+  TestingProfileManager* profile_manager() { return profile_manager_.get(); }
+
+  chromeos::FakeUserManager* GetFakeUserManager() {
+    return static_cast<chromeos::FakeUserManager*>(
+        chromeos::UserManager::Get());
+  }
+
+  scoped_ptr<TestingProfileManager> profile_manager_;
+  scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
+  scoped_ptr<base::FieldTrialList> field_trial_list_;
+
+  ash::test::TestSessionStateDelegate* session_delegate_;
+  ash::test::TestShellDelegate* shell_delegate_;
+
+  ProfileToNameMap created_profiles_;
+
+  DISALLOW_COPY_AND_ASSIGN(
+      MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest);
+};
+#endif  // defined(OS_CHROMEOS)
 
 TEST_F(LegacyShelfLayoutChromeLauncherControllerTest, DefaultApps) {
   InitLauncherController();
@@ -949,16 +1175,16 @@
 
   // Check that unloading of extensions works as expected.
   extension_service_->UnloadExtension(extension1_->id(),
-                                      extension_misc::UNLOAD_REASON_UNINSTALL);
+                                      UnloadedExtensionInfo::REASON_UNINSTALL);
   EXPECT_EQ("AppList, Chrome, App3, App2, ", GetPinnedAppStatus());
 
   extension_service_->UnloadExtension(extension2_->id(),
-                                      extension_misc::UNLOAD_REASON_UNINSTALL);
+                                      UnloadedExtensionInfo::REASON_UNINSTALL);
   EXPECT_EQ("AppList, Chrome, App3, ", GetPinnedAppStatus());
 
   // Check that an update of an extension does not crash the system.
   extension_service_->UnloadExtension(extension3_->id(),
-                                      extension_misc::UNLOAD_REASON_UPDATE);
+                                      UnloadedExtensionInfo::REASON_UPDATE);
   EXPECT_EQ("AppList, Chrome, App3, ", GetPinnedAppStatus());
 }
 
@@ -1109,6 +1335,105 @@
   EXPECT_EQ(2, model_->item_count());
 }
 
+#if defined(OS_CHROMEOS)
+// Check that with multi profile V1 apps are properly added / removed from the
+// shelf.
+TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
+       V1AppUpdateOnUserSwitch) {
+  // Create a browser item in the LauncherController.
+  InitLauncherController();
+  EXPECT_EQ(2, model_->item_count());
+  {
+    // Create a "windowed gmail app".
+    scoped_ptr<Browser> browser(CreateV1AppBrowserWithProfile(
+        profile(),
+        extension_misc::kGmailAppId));
+    EXPECT_EQ(3, model_->item_count());
+
+    // After switching to a second user the item should be gone.
+    std::string user2 = "user2";
+    TestingProfile* profile2 = CreateMultiUserProfile(user2);
+    SwitchActiveUser(profile2->GetProfileName());
+    EXPECT_EQ(2, model_->item_count());
+
+    // After switching back the item should be back.
+    SwitchActiveUser(profile()->GetProfileName());
+    EXPECT_EQ(3, model_->item_count());
+    // Note we destroy now the gmail app with the closure end.
+  }
+  EXPECT_EQ(2, model_->item_count());
+}
+
+// Check edge cases with multi profile V1 apps in the shelf.
+TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
+       V1AppUpdateOnUserSwitchEdgecases) {
+  // Create a browser item in the LauncherController.
+  InitLauncherController();
+
+  // First test: Create an app when the user is not active.
+  std::string user2 = "user2";
+  TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  {
+    // Create a "windowed gmail app".
+    scoped_ptr<Browser> browser(CreateV1AppBrowserWithProfile(
+        profile2,
+        extension_misc::kGmailAppId));
+    EXPECT_EQ(2, model_->item_count());
+
+    // However - switching to the user should show it.
+    SwitchActiveUser(profile2->GetProfileName());
+    EXPECT_EQ(3, model_->item_count());
+
+    // Second test: Remove the app when the user is not active and see that it
+    // works.
+    SwitchActiveUser(profile()->GetProfileName());
+    EXPECT_EQ(2, model_->item_count());
+    // Note: the closure ends and the browser will go away.
+  }
+  EXPECT_EQ(2, model_->item_count());
+  SwitchActiveUser(profile2->GetProfileName());
+  EXPECT_EQ(2, model_->item_count());
+  SwitchActiveUser(profile()->GetProfileName());
+  EXPECT_EQ(2, model_->item_count());
+}
+
+// Check that activating an item which is on another user's desktop, will bring
+// it back.
+TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
+       TestLauncherActivationPullsBackWindow) {
+  // Create a browser item in the LauncherController.
+  InitLauncherController();
+  chrome::MultiUserWindowManager* manager =
+      chrome::MultiUserWindowManager::GetInstance();
+
+  // Add two users to the window manager.
+  std::string user2 = "user2";
+  manager->UserAddedToSession(manager->GetUserIDFromProfile(profile()));
+  manager->UserAddedToSession(user2);
+  const std::string& current_user = manager->GetUserIDFromProfile(profile());
+
+  // Create a browser window with a native window for the current user.
+  scoped_ptr<BrowserWindow> browser_window(CreateTestBrowserWindow(
+      Browser::CreateParams(profile(), chrome::HOST_DESKTOP_TYPE_ASH)));
+  aura::Window* window = browser_window->GetNativeWindow();
+  manager->SetWindowOwner(window, current_user);
+
+  // Check that an activation of the window on its owner's desktop does not
+  // change the visibility to another user.
+  launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
+                                                         false);
+  EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
+
+  // Transfer the window to another user's desktop and check that activating it
+  // does pull it back to that user.
+  manager->ShowWindowForUser(window, user2);
+  EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user));
+  launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
+                                                         false);
+  EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
+}
+#endif
+
 // Check that lock -> pin -> unlock -> unpin does properly transition.
 TEST_F(ChromeLauncherControllerTest, CheckLockPinUnlockUnpin) {
   InitLauncherController();
@@ -1412,7 +1737,7 @@
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
 
   extension_service_->UnloadExtension(extension3_->id(),
-                                      extension_misc::UNLOAD_REASON_UNINSTALL);
+                                      UnloadedExtensionInfo::REASON_UNINSTALL);
 
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
@@ -1569,7 +1894,7 @@
   BrowserList::SetLastActive(browser());
   string16 title1 = ASCIIToUTF16("Test1");
   NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
-  string16 one_menu_item[] = {title1};
+  string16 one_menu_item[] = { title1 };
 
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_browser, 1, one_menu_item, true));
@@ -1594,6 +1919,59 @@
   chrome::CloseTab(browser2.get());
 }
 
+#if defined(OS_CHROMEOS)
+// Check the multi profile case where only user related browsers should show
+// up.
+TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
+       BrowserMenuGenerationTwoUsers) {
+  // Create a browser item in the LauncherController.
+  InitLauncherController();
+
+  ash::LauncherItem item_browser;
+  item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
+  item_browser.id =
+      launcher_controller_->GetLauncherIDForAppID(extension_misc::kChromeAppId);
+
+  // Check that the menu is empty.
+  chrome::NewTab(browser());
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 0, NULL, true));
+
+  // Show the created |browser()| by adding it to the active browser list.
+  BrowserList::SetLastActive(browser());
+  string16 title1 = ASCIIToUTF16("Test1");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
+  string16 one_menu_item1[] = { title1 };
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
+
+  // Create a browser for another user and check that it is not included in the
+  // users running browser list.
+  std::string user2 = "user2";
+  TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  scoped_ptr<Browser> browser2(
+      CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
+  string16 one_menu_item2[] = { ASCIIToUTF16(user2) };
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
+
+  // Switch to the other user and make sure that only that browser window gets
+  // shown.
+  SwitchActiveUser(profile2->GetProfileName());
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
+
+  // Transferred browsers of other users should not show up in the list.
+  chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
+      browser()->window()->GetNativeWindow(),
+      user2);
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
+
+  chrome::CloseTab(browser2.get());
+}
+#endif  // defined(OS_CHROMEOS)
+
 // Check that V1 apps are correctly reflected in the launcher menu using the
 // refocus logic.
 // Note that the extension matching logic is tested by the extension system
@@ -1633,7 +2011,7 @@
   string16 title1 = ASCIIToUTF16("Test1");
   NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
 
-  string16 one_menu_item[] = {title1};
+  string16 one_menu_item[] = { title1 };
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
 
@@ -1665,11 +2043,71 @@
 
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_gmail, 0, NULL, false));
-  string16 browser_menu_item2[] = {title2};
+  string16 browser_menu_item2[] = { title2 };
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_browser, 1, browser_menu_item2, false));
 }
 
+#if defined(OS_CHROMEOS)
+// Check the multi profile case where only user related apps should show up.
+TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
+       V1AppMenuGenerationTwoUsers) {
+  // Create a browser item in the LauncherController.
+  InitLauncherController();
+  chrome::NewTab(browser());
+
+  // Installing |extension3_| adds it to the launcher.
+  ash::LauncherID gmail_id = model_->next_id();
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ(3, model_->item_count());
+  int gmail_index = model_->ItemIndexByID(gmail_id);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
+  launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
+
+  // Check the menu content.
+  ash::LauncherItem item_browser;
+  item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
+  item_browser.id =
+      launcher_controller_->GetLauncherIDForAppID(extension_misc::kChromeAppId);
+
+  ash::LauncherItem item_gmail;
+  item_gmail.type = ash::TYPE_APP_SHORTCUT;
+  item_gmail.id = gmail_id;
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 0, NULL, false));
+
+  // Set the gmail URL to a new tab.
+  string16 title1 = ASCIIToUTF16("Test1");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
+
+  string16 one_menu_item[] = { title1 };
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
+
+  // Create a second profile and switch to that user.
+  std::string user2 = "user2";
+  TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  SwitchActiveUser(profile2->GetProfileName());
+
+  // No item should have content yet.
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 0, NULL, true));
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 0, NULL, false));
+
+  // Transfer the browser of the first user - it should still not show up.
+  chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
+      browser()->window()->GetNativeWindow(),
+      user2);
+
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 0, NULL, true));
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 0, NULL, false));
+}
+#endif  // defined(OS_CHROMEOS)
+
 // Checks that the generated menu list properly activates items.
 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) {
   InitLauncherControllerWithBrowser();
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 15e1ba0..bc2c6d6 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -37,7 +37,7 @@
 
 LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
                                          const ash::LauncherItem* item,
-                                         aura::RootWindow* root)
+                                         aura::Window* root)
     : ui::SimpleMenuModel(NULL),
       controller_(controller),
       item_(*item),
@@ -49,7 +49,7 @@
 }
 
 LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
-                                         aura::RootWindow* root)
+                                         aura::Window* root)
     : ui::SimpleMenuModel(NULL),
       controller_(controller),
       item_(ash::LauncherItem()),
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.h b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
index 3fc1dd9..5b89dfb 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
@@ -15,7 +15,7 @@
 class ChromeLauncherController;
 
 namespace aura {
-class RootWindow;
+class Window;
 }
 
 namespace extensions {
@@ -30,10 +30,10 @@
   // |clicked on an area with no icons).
   LauncherContextMenu(ChromeLauncherController* controller,
                       const ash::LauncherItem* item,
-                      aura::RootWindow* root_window);
+                      aura::Window* root_window);
   // Creates a menu used as a desktop context menu on |root_window|.
   LauncherContextMenu(ChromeLauncherController* controller,
-                      aura::RootWindow* root_window);
+                      aura::Window* root_window);
   virtual ~LauncherContextMenu();
 
   void Init();
@@ -88,7 +88,7 @@
 
   scoped_ptr<extensions::ContextMenuMatcher> extension_items_;
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(LauncherContextMenu);
 };
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
new file mode 100644
index 0000000..b58e02a
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 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/ash/launcher/multi_profile_browser_status_monitor.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/user_manager.h"
+#endif
+
+MultiProfileBrowserStatusMonitor::MultiProfileBrowserStatusMonitor(
+    ChromeLauncherController* launcher_controller)
+    : BrowserStatusMonitor(launcher_controller) {
+}
+
+MultiProfileBrowserStatusMonitor::~MultiProfileBrowserStatusMonitor() {
+}
+
+void MultiProfileBrowserStatusMonitor::ActiveUserChanged(
+    const std::string& user_email) {
+  for (AppList::iterator it = app_list_.begin(); it != app_list_.end(); ++it) {
+    bool owned = IsV1AppOwnedByCurrentUser(*it);
+    bool shown = IsV1AppInShelf(*it);
+    if (owned && !shown)
+      BrowserStatusMonitor::AddV1AppToShelf(*it);
+    else if (!owned && shown)
+      BrowserStatusMonitor::RemoveV1AppFromShelf(*it);
+  }
+}
+
+void MultiProfileBrowserStatusMonitor::AddV1AppToShelf(Browser* browser) {
+  DCHECK(browser->is_type_popup() && browser->is_app());
+  DCHECK(std::find(app_list_.begin(), app_list_.end(), browser) ==
+             app_list_.end());
+  app_list_.push_back(browser);
+  if (IsV1AppOwnedByCurrentUser(browser)) {
+    BrowserStatusMonitor::AddV1AppToShelf(browser);
+  }
+}
+
+void MultiProfileBrowserStatusMonitor::RemoveV1AppFromShelf(Browser* browser) {
+  DCHECK(browser->is_type_popup() && browser->is_app());
+  AppList::iterator it = std::find(app_list_.begin(), app_list_.end(), browser);
+  DCHECK(it != app_list_.end());
+  app_list_.erase(it);
+  if (IsV1AppInShelf(browser)) {
+    BrowserStatusMonitor::RemoveV1AppFromShelf(browser);
+  }
+}
+
+bool MultiProfileBrowserStatusMonitor::IsV1AppOwnedByCurrentUser(
+    Browser* browser) {
+  Profile* profile = browser->profile()->GetOriginalProfile();
+#if defined(OS_CHROMEOS)
+  return profile->GetProfileName() ==
+         chromeos::UserManager::Get()->GetActiveUser()->email();
+#else
+  return profile == ProfileManager::GetDefaultProfile();
+#endif
+}
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h
new file mode 100644
index 0000000..38f17ac
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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_ASH_LAUNCHER_MULTI_PROFILE_BROWSER_STATUS_MONITOR_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_MULTI_PROFILE_BROWSER_STATUS_MONITOR_H_
+
+#include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
+
+// MultiProfileBrowserStatusMonitor uses mainly the BrowserStatusMonitormonitor
+// with the addition that it creates and destroys launcher items for windowed
+// V1 apps - upon creation as well as upon user switch.
+class MultiProfileBrowserStatusMonitor : public BrowserStatusMonitor {
+ public:
+  explicit MultiProfileBrowserStatusMonitor(
+      ChromeLauncherController* launcher_controller);
+  virtual ~MultiProfileBrowserStatusMonitor();
+
+  // BrowserStatusMonitor overrides.
+  virtual void ActiveUserChanged(const std::string& user_email) OVERRIDE;
+  virtual void AddV1AppToShelf(Browser* browser) OVERRIDE;
+  virtual void RemoveV1AppFromShelf(Browser* browser) OVERRIDE;
+
+ private:
+  // Returns true if app is owned by current user.
+  bool IsV1AppOwnedByCurrentUser(Browser* browser);
+
+  typedef std::vector<Browser*> AppList;
+  AppList app_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultiProfileBrowserStatusMonitor);
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_MULTI_PROFILE_BROWSER_STATUS_MONITOR_H_
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.cc
new file mode 100644
index 0000000..ee27473
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.cc
@@ -0,0 +1,103 @@
+// Copyright 2013 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/ash/launcher/multi_profile_shell_window_launcher_controller.h"
+
+#include "apps/shell_window.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/host_desktop.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/ui/ash/multi_user_window_manager.h"
+#endif
+
+namespace {
+
+bool ControlsWindow(aura::Window* window) {
+  return chrome::GetHostDesktopTypeForNativeWindow(window) ==
+      chrome::HOST_DESKTOP_TYPE_ASH;
+}
+
+}  // namespace
+
+
+MultiProfileShellWindowLauncherController::
+    MultiProfileShellWindowLauncherController(
+    ChromeLauncherController* owner)
+    : ShellWindowLauncherController(owner) {
+}
+
+MultiProfileShellWindowLauncherController::
+    ~MultiProfileShellWindowLauncherController() {
+  // We need to remove all Registry observers for added users.
+  for (ShellWindowRegistryList::iterator it = multi_user_registry_.begin();
+       it != multi_user_registry_.end(); ++it)
+    (*it)->RemoveObserver(this);
+}
+
+void MultiProfileShellWindowLauncherController::ActiveUserChanged(
+    const std::string& user_email) {
+  // The active user has changed and we need to traverse our list of items to
+  // show / hide them one by one. To avoid that a user dependent state
+  // "survives" in a launcher item, we first delete all items making sure that
+  // nothing remains and then re-create them again.
+  for (ShellWindowList::iterator it = shell_window_list_.begin();
+       it != shell_window_list_.end(); ++it) {
+    aura::Window* window = (*it)->GetNativeWindow();
+    if (!IsShellWindowFromActiveUser(*it) && IsRegisteredApp(window))
+      UnregisterApp(window);
+  }
+  for (ShellWindowList::iterator it = shell_window_list_.begin();
+       it != shell_window_list_.end(); ++it) {
+    aura::Window* window = (*it)->GetNativeWindow();
+    if (IsShellWindowFromActiveUser(*it) && !IsRegisteredApp(window))
+      RegisterApp(*it);
+  }
+}
+
+void MultiProfileShellWindowLauncherController::AdditionalUserAddedToSession(
+    Profile* profile) {
+  // Each users ShellRegistry needs to be observed.
+  apps::ShellWindowRegistry* registry = apps::ShellWindowRegistry::Get(profile);
+  multi_user_registry_.push_back(registry);
+  registry->AddObserver(this);
+}
+
+void MultiProfileShellWindowLauncherController::OnShellWindowAdded(
+    apps::ShellWindow* shell_window) {
+  if (!ControlsWindow(shell_window->GetNativeWindow()))
+    return;
+  shell_window_list_.push_back(shell_window);
+  if (IsShellWindowFromActiveUser(shell_window))
+    RegisterApp(shell_window);
+}
+
+void MultiProfileShellWindowLauncherController::OnShellWindowRemoved(
+    apps::ShellWindow* shell_window) {
+  if (!ControlsWindow(shell_window->GetNativeWindow()))
+    return;
+
+  // If the application is registered with ShellWindowLauncher (because the user
+  // is currently active), the OnWindowDestroying observer has already (or will
+  // soon) unregister it independently from the shelf. If it was not registered
+  // we don't need to do anything anyways. As such, all which is left to do here
+  // is to get rid of our own reference.
+  ShellWindowList::iterator it = std::find(shell_window_list_.begin(),
+                                           shell_window_list_.end(),
+                                           shell_window);
+  DCHECK(it != shell_window_list_.end());
+  shell_window_list_.erase(it);
+}
+
+bool MultiProfileShellWindowLauncherController::IsShellWindowFromActiveUser(
+    apps::ShellWindow* shell_window) {
+  Profile* profile = shell_window->profile();
+#if defined(OS_CHROMEOS)
+  return chrome::MultiUserWindowManager::ProfileIsFromActiveUser(profile);
+#else
+  return profile->GetOriginalProfile() == ProfileManager::GetDefaultProfile();
+#endif
+}
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h
new file mode 100644
index 0000000..d26010a
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h
@@ -0,0 +1,43 @@
+// Copyright 2013 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_ASH_LAUNCHER_MULTI_PROFILE_SHELL_WINDOW_LAUNCHER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_MULTI_PROFILE_SHELL_WINDOW_LAUNCHER_CONTROLLER_H_
+
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
+
+// Inherits from ShellWindowLauncherController and overwrites the ShellWindow
+// observing functions to switch between users dynamically.
+class MultiProfileShellWindowLauncherController
+    : public ShellWindowLauncherController {
+ public:
+  explicit MultiProfileShellWindowLauncherController(
+      ChromeLauncherController* owner);
+  virtual ~MultiProfileShellWindowLauncherController();
+
+  // Overridden from ShellWindowLauncherController:
+  virtual void ActiveUserChanged(const std::string& user_email) OVERRIDE;
+  virtual void AdditionalUserAddedToSession(Profile* profile) OVERRIDE;
+
+  // Overridden from ShellWindowRegistry::Observer:
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE;
+
+ private:
+  typedef std::vector<apps::ShellWindow*> ShellWindowList;
+  typedef std::vector<apps::ShellWindowRegistry*> ShellWindowRegistryList;
+
+  // Returns true when the given window is from the active user.
+  bool IsShellWindowFromActiveUser(apps::ShellWindow* shell_window);
+
+  // A list of all shell windows for all users.
+  ShellWindowList shell_window_list_;
+
+  // A list of the shell window registries which we additionally observe.
+  ShellWindowRegistryList multi_user_registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultiProfileShellWindowLauncherController);
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_MULTI_PROFILE_SHELL_WINDOW_LAUNCHER_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
index cf31464..6ebf061 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
@@ -11,7 +11,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "ui/aura/client/activation_client.h"
+#include "ui/aura/root_window.h"
 
 using apps::ShellWindow;
 
@@ -23,6 +25,11 @@
   return shell_window->extension()->id();
 }
 
+bool ControlsWindow(aura::Window* window) {
+  return chrome::GetHostDesktopTypeForNativeWindow(window) ==
+      chrome::HOST_DESKTOP_TYPE_ASH;
+}
+
 }  // namespace
 
 ShellWindowLauncherController::ShellWindowLauncherController(
@@ -54,6 +61,60 @@
 
 void ShellWindowLauncherController::OnShellWindowAdded(
     ShellWindow* shell_window) {
+  if (!ControlsWindow(shell_window->GetNativeWindow()))
+    return;
+  RegisterApp(shell_window);
+}
+
+void ShellWindowLauncherController::OnShellWindowIconChanged(
+    ShellWindow* shell_window) {
+  if (!ControlsWindow(shell_window->GetNativeWindow()))
+    return;
+
+  const std::string app_launcher_id = GetAppLauncherId(shell_window);
+  AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
+  if (iter == app_controller_map_.end())
+    return;
+  ShellWindowLauncherItemController* controller = iter->second;
+  controller->set_image_set_by_controller(true);
+  owner_->SetLauncherItemImage(controller->launcher_id(),
+                               shell_window->app_icon().AsImageSkia());
+}
+
+void ShellWindowLauncherController::OnShellWindowRemoved(
+    ShellWindow* shell_window) {
+  // Do nothing here; shell_window->window() has already been deleted and
+  // OnWindowDestroying() has been called, doing the removal.
+}
+
+// Called from aura::Window::~Window(), before delegate_->OnWindowDestroyed()
+// which destroys ShellWindow, so both |window| and the associated ShellWindow
+// are valid here.
+void ShellWindowLauncherController::OnWindowDestroying(aura::Window* window) {
+  if (!ControlsWindow(window))
+    return;
+  UnregisterApp(window);
+}
+
+void ShellWindowLauncherController::OnWindowActivated(
+    aura::Window* new_active,
+    aura::Window* old_active) {
+  // Make the newly active window the active (first) entry in the controller.
+  ShellWindowLauncherItemController* new_controller =
+      ControllerForWindow(new_active);
+  if (new_controller) {
+    new_controller->SetActiveWindow(new_active);
+    owner_->SetItemStatus(new_controller->launcher_id(), ash::STATUS_ACTIVE);
+  }
+
+  // Mark the old active window's launcher item as running (if different).
+  ShellWindowLauncherItemController* old_controller =
+      ControllerForWindow(old_active);
+  if (old_controller && old_controller != new_controller)
+    owner_->SetItemStatus(old_controller->launcher_id(), ash::STATUS_RUNNING);
+}
+
+void ShellWindowLauncherController::RegisterApp(ShellWindow* shell_window) {
   aura::Window* window = shell_window->GetNativeWindow();
   // Get the app's launcher identifier and add an entry to the map.
   DCHECK(window_to_app_launcher_id_map_.find(window) ==
@@ -95,28 +156,7 @@
   owner_->SetItemStatus(launcher_id, status);
 }
 
-void ShellWindowLauncherController::OnShellWindowIconChanged(
-    ShellWindow* shell_window) {
-  const std::string app_launcher_id = GetAppLauncherId(shell_window);
-  AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
-  if (iter == app_controller_map_.end())
-    return;
-  ShellWindowLauncherItemController* controller = iter->second;
-  controller->set_image_set_by_controller(true);
-  owner_->SetLauncherItemImage(controller->launcher_id(),
-                               shell_window->app_icon().AsImageSkia());
-}
-
-void ShellWindowLauncherController::OnShellWindowRemoved(
-    ShellWindow* shell_window) {
-  // Do nothing here; shell_window->window() has allready been deleted and
-  // OnWindowDestroying() has been called, doing the removal.
-}
-
-// Called from ~aura::Window(), before delegate_->OnWindowDestroyed() which
-// destroys ShellWindow, so both |window| and the associated ShellWindow
-// are valid here.
-void ShellWindowLauncherController::OnWindowDestroying(aura::Window* window) {
+void ShellWindowLauncherController::UnregisterApp(aura::Window* window) {
   WindowToAppLauncherIdMap::iterator iter1 =
       window_to_app_launcher_id_map_.find(window);
   DCHECK(iter1 != window_to_app_launcher_id_map_.end());
@@ -137,22 +177,9 @@
   }
 }
 
-void ShellWindowLauncherController::OnWindowActivated(
-    aura::Window* new_active,
-    aura::Window* old_active) {
-  // Make the newly active window the active (first) entry in the controller.
-  ShellWindowLauncherItemController* new_controller =
-      ControllerForWindow(new_active);
-  if (new_controller) {
-    new_controller->SetActiveWindow(new_active);
-    owner_->SetItemStatus(new_controller->launcher_id(), ash::STATUS_ACTIVE);
-  }
-
-  // Mark the old active window's launcher item as running (if different).
-  ShellWindowLauncherItemController* old_controller =
-      ControllerForWindow(old_active);
-  if (old_controller && old_controller != new_controller)
-    owner_->SetItemStatus(old_controller->launcher_id(), ash::STATUS_RUNNING);
+bool ShellWindowLauncherController::IsRegisteredApp(aura::Window* window) {
+  return window_to_app_launcher_id_map_.find(window) !=
+      window_to_app_launcher_id_map_.end();
 }
 
 // Private Methods
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
index 3669f72..d705acb 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
@@ -28,6 +28,7 @@
 }
 
 class ChromeLauncherController;
+class Profile;
 class ShellWindowLauncherItemController;
 
 // ShellWindowLauncherController observes the Shell Window registry and the
@@ -41,6 +42,14 @@
   explicit ShellWindowLauncherController(ChromeLauncherController* owner);
   virtual ~ShellWindowLauncherController();
 
+  // Called by ChromeLauncherController when the active user changed and the
+  // items need to be updated.
+  virtual void ActiveUserChanged(const std::string& user_email) {}
+
+  // An additional user identified by |Profile|, got added to the existing
+  // session.
+  virtual void AdditionalUserAddedToSession(Profile* profile) {}
+
   // Overridden from ShellWindowRegistry::Observer:
   virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE;
   virtual void OnShellWindowIconChanged(
@@ -54,11 +63,15 @@
   virtual void OnWindowActivated(aura::Window* gained_active,
                                  aura::Window* lost_active) OVERRIDE;
 
-  // Returns the number of running applications.
-  int NumberOfAppsRunning();
+ protected:
+  // Registers a shell window with the shelf and this object.
+  void RegisterApp(apps::ShellWindow* shell_window);
 
-  // Activate the application with the given index.
-  void ActivateAppAt(int index);
+  // Unregisters a shell window with the shelf and this object.
+  void UnregisterApp(aura::Window* window);
+
+  // Check if a given window is known to the launcher controller.
+  bool IsRegisteredApp(aura::Window* window);
 
  private:
   typedef std::map<std::string, ShellWindowLauncherItemController*>
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
index da7cd33..d86b10a 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
@@ -16,15 +16,40 @@
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "content/public/browser/web_contents.h"
+#include "skia/ext/image_operations.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/events/event.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/views/corewm/window_animations.h"
 
 using apps::ShellWindow;
 
 namespace {
 
+// Size of the icon in the shelf launcher in display-independent pixels.
+const int kAppListIconSize = 24;
+
+// This will return a slightly smaller icon than the app icon to be used in
+// the application list menu.
+scoped_ptr<gfx::Image> GetAppListIcon(ShellWindow* shell_window) {
+  // TODO(skuhne): We instead might want to use LoadImages in
+  // ShellWindow::UpdateExtensionAppIcon() to let the extension give us
+  // pre-defined icons in the launcher and the launcher list sizes. Since there
+  // is no mock yet, doing this now seems a bit premature and we scale for the
+  // time being.
+  if (shell_window->app_icon().IsEmpty())
+    return make_scoped_ptr(new gfx::Image());
+
+  SkBitmap bmp =
+      skia::ImageOperations::Resize(*shell_window->app_icon().ToSkBitmap(),
+                                    skia::ImageOperations::RESIZE_BEST,
+                                    kAppListIconSize,
+                                    kAppListIconSize);
+  return make_scoped_ptr(
+      new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)));
+}
+
 // Functor for std::find_if used in AppLauncherItemController.
 class ShellWindowHasWindow {
  public:
@@ -145,7 +170,7 @@
   for (ShellWindowList::iterator iter = shell_windows_.begin();
        iter != shell_windows_.end(); ++iter) {
     ShellWindow* shell_window = *iter;
-    scoped_ptr<gfx::Image> image(shell_window->GetAppListIcon());
+    scoped_ptr<gfx::Image> image(GetAppListIcon(shell_window));
     items.push_back(new ChromeLauncherAppMenuItemV2App(
         shell_window->GetTitle(),
         image.get(),  // Will be copied
@@ -204,7 +229,7 @@
 }
 
 ui::MenuModel* ShellWindowLauncherItemController::CreateContextMenu(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   ash::LauncherItem item =
       *(launcher_controller()->model()->ItemByID(launcher_id()));
   return new LauncherContextMenu(launcher_controller(), &item, root_window);
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
index ea2226c..2ffc77d 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
@@ -66,7 +66,7 @@
   virtual void ItemSelected(const ui::Event& eent) OVERRIDE;
   virtual base::string16 GetTitle() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      aura::RootWindow* root_window) OVERRIDE;
+      aura::Window* root_window) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       int event_flags) OVERRIDE;
   virtual bool IsDraggable() OVERRIDE;
diff --git a/chrome/browser/ui/ash/multi_user_window_manager.cc b/chrome/browser/ui/ash/multi_user_window_manager.cc
index 0a58841..786b8cb 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager.cc
+++ b/chrome/browser/ui/ash/multi_user_window_manager.cc
@@ -10,11 +10,14 @@
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
+#include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/window_positioner.h"
 #include "ash/wm/window_state.h"
 #include "base/auto_reset.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -22,7 +25,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "content/public/browser/notification_service.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_types.h"
 
@@ -32,6 +37,31 @@
 
 namespace chrome {
 
+// Caching the current multi profile mode since the detection which mode is
+// used is quite expensive.
+chrome::MultiUserWindowManager::MultiProfileMode
+    chrome::MultiUserWindowManager::multi_user_mode_ =
+        chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_UNINITIALIZED;
+
+// A class to disable updates to the MRU window list and the auto positioning
+// logic while the user gets switched.
+class UserChangeActionDisabler {
+ public:
+  UserChangeActionDisabler() {
+    ash::WindowPositioner::DisableAutoPositioning(true);
+    ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
+  }
+
+  ~UserChangeActionDisabler() {
+    ash::WindowPositioner::DisableAutoPositioning(false);
+    ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(
+        false);
+  }
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(UserChangeActionDisabler);
+};
+
 // This class keeps track of all applications which were started for a user.
 // When an app gets created, the window will be tagged for that user. Note
 // that the destruction does not need to be tracked here since the universal
@@ -61,26 +91,71 @@
 
 // static
 MultiUserWindowManager* MultiUserWindowManager::GetInstance() {
+  return g_instance;
+}
+
+MultiUserWindowManager* MultiUserWindowManager::CreateInstance() {
   if (!g_instance &&
       ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
       !ash::switches::UseFullMultiProfileMode()) {
     g_instance = CreateInstanceInternal(
-        GetUserIDFromProfile(ProfileManager::GetDefaultProfile()));
+        ash::Shell::GetInstance()->session_state_delegate()->GetUserID(0));
+    multi_user_mode_ = MULTI_PROFILE_MODE_SEPARATED;
+  } else if (ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
+    multi_user_mode_ = MULTI_PROFILE_MODE_MIXED;
+  } else {
+    multi_user_mode_ = MULTI_PROFILE_MODE_OFF;
   }
   return g_instance;
 }
 
 // static
+MultiUserWindowManager::MultiProfileMode
+MultiUserWindowManager::GetMultiProfileMode() {
+  return multi_user_mode_;
+}
+
+// static
 void MultiUserWindowManager::DeleteInstance() {
   if (g_instance)
     delete g_instance;
   g_instance = NULL;
+  multi_user_mode_ = MULTI_PROFILE_MODE_UNINITIALIZED;
 }
 
 // static
 std::string MultiUserWindowManager::GetUserIDFromProfile(Profile* profile) {
-  return gaia::CanonicalizeEmail(gaia::SanitizeEmail(
-      profile->GetOriginalProfile()->GetProfileName()));
+  return GetUserIDFromEmail(profile->GetOriginalProfile()->GetProfileName());
+}
+
+// static
+std::string MultiUserWindowManager::GetUserIDFromEmail(
+    const std::string& email) {
+  return gaia::CanonicalizeEmail(gaia::SanitizeEmail(email));
+}
+
+// static
+Profile* MultiUserWindowManager::GetProfileFromUserID(
+    const std::string& user_id) {
+  // This can only happen for unit tests. If it happens we return NULL.
+  if (!g_browser_process || !g_browser_process->profile_manager())
+    return NULL;
+
+  std::vector<Profile*> profiles =
+      g_browser_process->profile_manager()->GetLoadedProfiles();
+
+  std::vector<Profile*>::const_iterator profile_iterator = profiles.begin();
+  for (; profile_iterator != profiles.end(); ++profile_iterator) {
+    if (GetUserIDFromProfile(*profile_iterator) == user_id)
+      return *profile_iterator;
+  }
+  return NULL;
+}
+
+// static
+bool MultiUserWindowManager::ProfileIsFromActiveUser(Profile* profile) {
+  return MultiUserWindowManager::GetUserIDFromProfile(profile) ==
+         chromeos::UserManager::Get()->GetActiveUser()->email();
 }
 
 void MultiUserWindowManager::SetWindowOwner(aura::Window* window,
@@ -161,9 +236,17 @@
   DCHECK(user_id != current_user_id_);
   std::string old_user = current_user_id_;
   current_user_id_ = user_id;
-  // Hide all windows which are not shown and show which should get shown.
-  WindowToEntryMap::iterator it = window_to_entry_.begin();
-  for (; it != window_to_entry_.end(); ++it) {
+  // When a user has changed, we need to show only the windows which are visible
+  // to that user. Additionally we need to restore the activation state of the
+  // windows. Changing the activation state however triggers the window position
+  // manager to auto position the windows. To avoid that we disable it
+  // temporarily.
+
+  // Disable the window position manager and the MRU window tracker temporarily.
+  scoped_ptr<UserChangeActionDisabler> disabler(new UserChangeActionDisabler);
+
+  for (WindowToEntryMap::iterator it = window_to_entry_.begin();
+       it != window_to_entry_.end(); ++it) {
     aura::Window* window = it->first;
     bool should_be_visible =
         it->second->show_for_user() == user_id && it->second->show();
@@ -171,12 +254,31 @@
     if (should_be_visible != is_visible)
       SetWindowVisibility(window, should_be_visible);
   }
-}
 
-void MultiUserWindowManager::UserAddedToSession(const std::string& user_id) {
-  // Make sure that all newly created applications get properly added to this
-  // user's account.
-  AddUser(user_id);
+  // Retrieve the list of visible windows in their order. Use the list to
+  // traverse the windows and activate them, thus restoring the previous state.
+  // TODO(skuhne): Unfortunately the MruWindowTracker does not let us get the
+  // full list (visible and invisible) and after our visibility changes the
+  // actual order of windows can be changed. A workaround would be to implement
+  // our own aura::client::ActivationChangeObserver and track the activations
+  // from our known windows. But that should be part of another CL.
+  ash::MruWindowTracker* tracker =
+      ash::Shell::GetInstance()->mru_window_tracker();
+  ash::MruWindowTracker::WindowList mru_list = tracker->BuildWindowList(true);
+  for (ash::MruWindowTracker::WindowList::iterator mru_iterator =
+           mru_list.begin();
+       mru_iterator != mru_list.end(); mru_iterator++) {
+    aura::Window* window = *mru_iterator;
+    ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
+    if (IsWindowOnDesktopOfUser(window, user_id) &&
+        !window_state->IsMinimized()) {
+      aura::client::ActivationClient* client =
+          aura::client::GetActivationClient(window->GetRootWindow());
+      // Several unit tests come here without an activation client.
+      if (client)
+        client->ActivateWindow(window);
+    }
+  }
 }
 
 void MultiUserWindowManager::OnWindowDestroyed(aura::Window* window) {
@@ -258,7 +360,9 @@
                  content::NotificationService::AllSources());
 
   // Add an app window observer & all already running apps.
-  AddUser(current_user_id);
+  Profile* profile = GetProfileFromUserID(current_user_id);
+  if (profile)
+    AddUser(profile);
 }
 
 MultiUserWindowManager::~MultiUserWindowManager() {
@@ -287,17 +391,11 @@
         RemoveSessionStateObserver(this);
 }
 
-void MultiUserWindowManager::AddUser(const std::string& user_id) {
+void MultiUserWindowManager::AddUser(Profile* profile) {
+  const std::string& user_id = GetUserIDFromProfile(profile);
   if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
     return;
 
-  // Add an observer for all shell window changes.
-  Profile* profile = GetProfileFromUserID(user_id);
-
-  // In case of unit tests we might have no profile.
-  if (!profile)
-    return;
-
   user_id_to_app_observer_[user_id] = new AppObserver(user_id);
   apps::ShellWindowRegistry::Get(profile)->AddObserver(
       user_id_to_app_observer_[user_id]);
@@ -320,7 +418,9 @@
 }
 
 void MultiUserWindowManager::AddBrowserWindow(Browser* browser) {
-  if (browser->window() && !browser->window()->GetNativeWindow())
+  // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
+  // come here with no valid window.
+  if (!browser->window() || !browser->window()->GetNativeWindow())
     return;
   SetWindowOwner(browser->window()->GetNativeWindow(),
                  GetUserIDFromProfile(browser->profile()));
@@ -341,21 +441,4 @@
     window->Hide();
 }
 
-Profile* MultiUserWindowManager::GetProfileFromUserID(
-    const std::string& user_id) {
-  // This can only happen for unit tests. If it happens we return NULL.
-  if (!g_browser_process || !g_browser_process->profile_manager())
-    return NULL;
-
-  std::vector<Profile*> profiles =
-      g_browser_process->profile_manager()->GetLoadedProfiles();
-
-  std::vector<Profile*>::iterator profile_iterator = profiles.begin();
-  for (; profile_iterator != profiles.end(); ++profile_iterator) {
-    if (GetUserIDFromProfile(*profile_iterator) == user_id)
-      return *profile_iterator;
-  }
-  return NULL;
-}
-
 }  // namespace chrome
diff --git a/chrome/browser/ui/ash/multi_user_window_manager.h b/chrome/browser/ui/ash/multi_user_window_manager.h
index fea8fd0..58b1fee 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager.h
+++ b/chrome/browser/ui/ash/multi_user_window_manager.h
@@ -48,23 +48,52 @@
 //   clean automatically all references of that window upon destruction.
 // - User changes will be tracked via observer. No need to call.
 // - All child windows will be owned by the same owner as its parent.
+// TODO(skuhne): Split this class into a generic (non Chrome OS) utility
+// function list and a pure virtual class. Then create two implementations of
+// it: One for Chrome OS and for all other OS'ses. Then remove the
+// defined(OS_CHROMEOS) in the various locations of the code.
 class MultiUserWindowManager : public ash::SessionStateObserver,
                                public aura::WindowObserver,
                                public content::NotificationObserver,
                                public ash::wm::WindowStateObserver {
  public:
+  // The multi profile mode in use.
+  enum MultiProfileMode {
+    MULTI_PROFILE_MODE_UNINITIALIZED,  // Not initialized yet.
+    MULTI_PROFILE_MODE_OFF,            // Single user mode.
+    MULTI_PROFILE_MODE_SEPARATED,      // Each user has his own desktop.
+    MULTI_PROFILE_MODE_MIXED           // All users mix windows freely.
+  };
+
+  // Creates an instance of the MultiUserWindowManager.
+  // Note: This function might fail if due to the desired mode the
+  // MultiUserWindowManager is not required.
+  static MultiUserWindowManager* CreateInstance();
+
   // Gets the instance of the object. If the multi profile mode is not enabled
-  // this will return NULL. If it wasn't created yet, it will create an instance
-  // using the currently active user as the active user - otherwise it will
-  // return the previously created instance.
+  // this will return NULL.
   static MultiUserWindowManager* GetInstance();
 
+  // Return the current multi profile mode operation. If CreateInstance was not
+  // yet called (or was already destroyed), MULTI_PROFILE_MODE_UNINITIALIZED
+  // will get returned.
+  static MultiProfileMode GetMultiProfileMode();
+
   // Removes the instance.
   static void DeleteInstance();
 
   // Get the user id from a given profile.
   static std::string GetUserIDFromProfile(Profile* profile);
 
+  // Get the user id from an email address.
+  static std::string GetUserIDFromEmail(const std::string& email);
+
+  // Get a profile for a given user id.
+  static Profile* GetProfileFromUserID(const std::string& user_id);
+
+  // Check if the given profile is from the currently active user.
+  static bool ProfileIsFromActiveUser(Profile* profile);
+
   // Assigns an owner to a passed window. Note that this window's parent should
   // be a direct child of the root window.
   // A user switch will automatically change the visibility - and - if the
@@ -96,9 +125,15 @@
   // passed back the window will be presented for every user.
   const std::string& GetUserPresentingWindow(aura::Window* window);
 
+  // Adds user to monitor now and future running V1/V2 application windows.
+  // Returns immediately if the user (identified by a |profile|) is already
+  // known to the manager. Note: This function is not implemented as a
+  // SessionStateObserver to coordinate the timing of the addition with other
+  // modules.
+  void AddUser(Profile* profile);
+
   // SessionStateObserver overrides:
   virtual void ActiveUserChanged(const std::string& user_id) OVERRIDE;
-  virtual void UserAddedToSession(const std::string& user_id) OVERRIDE;
 
   // WindowObserver overrides:
   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
@@ -171,11 +206,6 @@
   explicit MultiUserWindowManager(const std::string& active_user_id);
   virtual ~MultiUserWindowManager();
 
-  // Adds user to monitor for application windows. Returns immediately if the
-  // user is already known to the system. Otherwise it will make sure that
-  // application windows from that user will get properly tracked.
-  void AddUser(const std::string& user_id);
-
   // Add a browser window to the system so that the owner can be remembered.
   void AddBrowserWindow(Browser* browser);
 
@@ -185,9 +215,6 @@
   // performed by the others.
   void SetWindowVisibility(aura::Window* window, bool visible);
 
-  // Get a profile for a given user id.
-  Profile* GetProfileFromUserID(const std::string& user_id);
-
   // A lookup to see to which user the given window belongs to, where and if it
   // should get shown.
   WindowToEntryMap window_to_entry_;
@@ -206,6 +233,10 @@
   // Suppress changes to the visibility flag while we are changing it ourselves.
   bool suppress_visibility_changes_;
 
+  // Caching the current multi profile mode since the detection which mode is
+  // used is quite expensive.
+  static MultiProfileMode multi_user_mode_;
+
   DISALLOW_COPY_AND_ASSIGN(MultiUserWindowManager);
 };
 
diff --git a/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc b/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
index 02c6036..0a6a6d8 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_profile.h"
+#include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/root_window.h"
 #include "ui/base/ui_base_types.h"
@@ -358,5 +359,49 @@
   EXPECT_EQ("H[A]", GetStatus());
 }
 
+// Testing that the activation state changes to the active window.
+TEST_F(MultiUserWindowManagerTest, ActiveWindowTests) {
+  SetUpForThisManyWindows(4);
+
+  aura::client::ActivationClient* activation_client =
+      aura::client::GetActivationClient(window(0)->GetRootWindow());
+
+  // Set some windows to the active owner.
+  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+  multi_user_window_manager()->SetWindowOwner(window(1), "A");
+  multi_user_window_manager()->SetWindowOwner(window(2), "B");
+  multi_user_window_manager()->SetWindowOwner(window(3), "B");
+  EXPECT_EQ("S[A], S[A], H[B], H[B]", GetStatus());
+
+  // Set the active window for user A to be #1
+  activation_client->ActivateWindow(window(1));
+
+  // Change to user B and make sure that one of its windows is active.
+  multi_user_window_manager()->ActiveUserChanged("B");
+  EXPECT_EQ("H[A], H[A], S[B], S[B]", GetStatus());
+  EXPECT_TRUE(window(3) == activation_client->GetActiveWindow() ||
+              window(2) == activation_client->GetActiveWindow());
+  // Set the active window for user B now to be #2
+  activation_client->ActivateWindow(window(2));
+
+  multi_user_window_manager()->ActiveUserChanged("A");
+  EXPECT_EQ(window(1), activation_client->GetActiveWindow());
+
+  multi_user_window_manager()->ActiveUserChanged("B");
+  EXPECT_EQ(window(2), activation_client->GetActiveWindow());
+
+  multi_user_window_manager()->ActiveUserChanged("C");
+  EXPECT_EQ(NULL, activation_client->GetActiveWindow());
+
+  // Now test that a minimized window stays minimized upon switch and back.
+  multi_user_window_manager()->ActiveUserChanged("A");
+  wm::GetWindowState(window(0))->Minimize();
+
+  multi_user_window_manager()->ActiveUserChanged("B");
+  multi_user_window_manager()->ActiveUserChanged("A");
+  EXPECT_TRUE(wm::GetWindowState(window(0))->IsMinimized());
+  EXPECT_EQ(window(1), activation_client->GetActiveWindow());
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/screenshot_taker.cc b/chrome/browser/ui/ash/screenshot_taker.cc
index b7517f2..adaee4e 100644
--- a/chrome/browser/ui/ash/screenshot_taker.cc
+++ b/chrome/browser/ui/ash/screenshot_taker.cc
@@ -343,11 +343,11 @@
 
   ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
   // Reorder root_windows to take the primary root window's snapshot at first.
-  aura::RootWindow* primary_root = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow();
   if (*(root_windows.begin()) != primary_root) {
     root_windows.erase(std::find(
         root_windows.begin(), root_windows.end(), primary_root));
-    root_windows.insert(root_windows.begin(), primary_root);
+    root_windows.insert(root_windows.begin(), primary_root->GetDispatcher());
   }
   for (size_t i = 0; i < root_windows.size(); ++i) {
     aura::RootWindow* root_window = root_windows[i];
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
index e1ff42b..b519eda 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
@@ -169,7 +169,7 @@
 
 bool SessionStateDelegateChromeos::TransferWindowToDesktopOfUser(
     aura::Window* window,
-    ash::MultiProfileIndex index) const {
+    ash::MultiProfileIndex index) {
   chrome::MultiUserWindowManager* window_manager =
       chrome::MultiUserWindowManager::GetInstance();
   if (!window_manager || window_manager->GetWindowOwner(window).empty())
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.h b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
index 24a7964..45a6fe6 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
@@ -49,7 +49,7 @@
       ash::SessionStateObserver* observer) OVERRIDE;
   virtual bool TransferWindowToDesktopOfUser(
       aura::Window* window,
-      ash::MultiProfileIndex index) const OVERRIDE;
+      ash::MultiProfileIndex index) OVERRIDE;
   // UserManager::UserSessionStateObserver:
   virtual void ActiveUserChanged(const chromeos::User* active_user) OVERRIDE;
   virtual void UserAddedToSession(const chromeos::User* added_user) OVERRIDE;
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.cc b/chrome/browser/ui/ash/session_state_delegate_views.cc
index 2998204..4c86889 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_views.cc
@@ -103,7 +103,7 @@
 
 bool SessionStateDelegate::TransferWindowToDesktopOfUser(
     aura::Window* window,
-    ash::MultiProfileIndex index) const {
+    ash::MultiProfileIndex index) {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.h b/chrome/browser/ui/ash/session_state_delegate_views.h
index 238c1b4..aa055ea 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.h
+++ b/chrome/browser/ui/ash/session_state_delegate_views.h
@@ -46,7 +46,7 @@
       ash::SessionStateObserver* observer) OVERRIDE;
   virtual bool TransferWindowToDesktopOfUser(
       aura::Window* window,
-      ash::MultiProfileIndex index) const OVERRIDE;
+      ash::MultiProfileIndex index) OVERRIDE;
  private:
   DISALLOW_COPY_AND_ASSIGN(SessionStateDelegate);
 };
diff --git a/chrome/browser/ui/ash/system_tray_delegate_win.cc b/chrome/browser/ui/ash/system_tray_delegate_win.cc
new file mode 100644
index 0000000..81f5507
--- /dev/null
+++ b/chrome/browser/ui/ash/system_tray_delegate_win.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2012 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/ash/system_tray_delegate_win.h"
+
+#include <string>
+
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_delegate.h"
+#include "ash/system/tray/system_tray_notifier.h"
+#include "ash/volume_control_delegate.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/upgrade_detector.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_service.h"
+
+#include "grit/locale_settings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+class SystemTrayDelegateWin : public ash::SystemTrayDelegate,
+                              public content::NotificationObserver {
+ public:
+  SystemTrayDelegateWin()
+      : clock_type_(base::GetHourClockType()) {
+    // Register notifications on construction so that events such as
+    // PROFILE_CREATED do not get missed if they happen before Initialize().
+    registrar_.reset(new content::NotificationRegistrar);
+    registrar_->Add(this,
+                    chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
+                    content::NotificationService::AllSources());
+  }
+
+  virtual ~SystemTrayDelegateWin() {
+    registrar_.reset();
+  }
+
+  // Overridden from ash::SystemTrayDelegate:
+  virtual void Initialize() OVERRIDE {
+    UpdateClockType();
+  }
+
+  virtual void Shutdown() OVERRIDE {
+  }
+
+  virtual bool GetTrayVisibilityOnStartup() OVERRIDE {
+    return true;
+  }
+
+  virtual ash::user::LoginStatus GetUserLoginStatus() const OVERRIDE {
+    return ash::user::LOGGED_IN_OWNER;
+  }
+
+  virtual bool IsOobeCompleted() const OVERRIDE {
+    return true;
+  }
+
+  virtual void ChangeProfilePicture() OVERRIDE {
+  }
+
+  virtual const std::string GetEnterpriseDomain() const OVERRIDE {
+    return std::string();
+  }
+
+  virtual const string16 GetEnterpriseMessage() const OVERRIDE {
+    return string16();
+  }
+
+  virtual const std::string GetLocallyManagedUserManager() const OVERRIDE {
+    return std::string();
+  }
+
+  virtual const string16 GetLocallyManagedUserManagerName() const OVERRIDE {
+    return string16();
+  }
+
+  virtual const string16 GetLocallyManagedUserMessage() const OVERRIDE {
+    return string16();
+  }
+
+  virtual bool SystemShouldUpgrade() const OVERRIDE {
+    return UpgradeDetector::GetInstance()->notify_upgrade();
+  }
+
+  virtual base::HourClockType GetHourClockType() const OVERRIDE {
+    return clock_type_;
+  }
+
+  virtual void ShowSettings() OVERRIDE {
+  }
+
+  virtual bool ShouldShowSettings() OVERRIDE {
+    return true;
+  }
+
+  virtual void ShowDateSettings() OVERRIDE {
+  }
+
+  virtual void ShowNetworkSettings(const std::string& service_path) OVERRIDE {
+  }
+
+  virtual void ShowBluetoothSettings() OVERRIDE {
+  }
+
+  virtual void ShowDisplaySettings() OVERRIDE {
+  }
+
+  virtual void ShowChromeSlow() OVERRIDE {
+  }
+
+  virtual bool ShouldShowDisplayNotification() OVERRIDE {
+    return false;
+  }
+
+  virtual void ShowDriveSettings() OVERRIDE {
+  }
+
+  virtual void ShowIMESettings() OVERRIDE {
+  }
+
+  virtual void ShowHelp() OVERRIDE {
+    chrome::ShowHelp(GetAppropriateBrowser(), chrome::HELP_SOURCE_MENU);
+  }
+
+  virtual void ShowAccessibilityHelp() OVERRIDE {
+  }
+
+  virtual void ShowAccessibilitySettings() OVERRIDE {
+  }
+
+  virtual void ShowPublicAccountInfo() OVERRIDE {
+  }
+
+  virtual void ShowLocallyManagedUserInfo() OVERRIDE {
+  }
+
+  virtual void ShowEnterpriseInfo() OVERRIDE {
+  }
+
+  virtual void ShowUserLogin() OVERRIDE {
+  }
+
+  virtual void ShutDown() OVERRIDE {
+  }
+
+  virtual void SignOut() OVERRIDE {
+  }
+
+  virtual void RequestLockScreen() OVERRIDE {
+  }
+
+  virtual void RequestRestartForUpdate() OVERRIDE {
+    chrome::AttemptRestart();
+  }
+
+  virtual void GetAvailableBluetoothDevices(
+      ash::BluetoothDeviceList* list) OVERRIDE {
+  }
+
+  virtual void BluetoothStartDiscovering() OVERRIDE {
+  }
+
+  virtual void BluetoothStopDiscovering() OVERRIDE {
+  }
+
+  virtual void ConnectToBluetoothDevice(const std::string& address) OVERRIDE {
+  }
+
+  virtual bool IsBluetoothDiscovering() OVERRIDE {
+    return false;
+  }
+
+  virtual void GetCurrentIME(ash::IMEInfo* info) OVERRIDE {
+  }
+
+  virtual void GetAvailableIMEList(ash::IMEInfoList* list) OVERRIDE {
+  }
+
+  virtual void GetCurrentIMEProperties(
+      ash::IMEPropertyInfoList* list) OVERRIDE {
+  }
+
+  virtual void SwitchIME(const std::string& ime_id) OVERRIDE {
+  }
+
+  virtual void ActivateIMEProperty(const std::string& key) OVERRIDE {
+  }
+
+  virtual void CancelDriveOperation(int32 operation_id) OVERRIDE {
+  }
+
+  virtual void GetDriveOperationStatusList(
+      ash::DriveOperationStatusList* list) OVERRIDE {
+  }
+
+  virtual void ShowNetworkConfigure(const std::string& network_id,
+                                    gfx::NativeWindow parent_window) OVERRIDE {
+  }
+
+  virtual bool EnrollNetwork(const std::string& network_id,
+                             gfx::NativeWindow parent_window) OVERRIDE {
+    return true;
+  }
+
+  virtual void ManageBluetoothDevices() OVERRIDE {
+  }
+
+  virtual void ToggleBluetooth() OVERRIDE {
+  }
+
+  virtual void ShowMobileSimDialog() OVERRIDE {
+  }
+
+  virtual void ShowMobileSetupDialog(const std::string& service_path) OVERRIDE {
+  }
+
+  virtual void ShowOtherNetworkDialog(const std::string& type) OVERRIDE {
+  }
+
+  virtual bool GetBluetoothAvailable() OVERRIDE {
+    return false;
+  }
+
+  virtual bool GetBluetoothEnabled() OVERRIDE {
+    return false;
+  }
+
+  virtual void ChangeProxySettings() OVERRIDE {
+  }
+
+  virtual ash::VolumeControlDelegate*
+  GetVolumeControlDelegate() const OVERRIDE {
+    return NULL;
+  }
+
+  virtual void SetVolumeControlDelegate(
+      scoped_ptr<ash::VolumeControlDelegate> delegate) OVERRIDE {
+  }
+
+  virtual bool GetSessionStartTime(
+      base::TimeTicks* session_start_time) OVERRIDE {
+    return false;
+  }
+
+  virtual bool GetSessionLengthLimit(
+      base::TimeDelta* session_length_limit) OVERRIDE {
+    return false;
+  }
+
+  virtual int GetSystemTrayMenuWidth() OVERRIDE {
+    return l10n_util::GetLocalizedContentsWidthInPixels(
+        IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
+  }
+
+  virtual void MaybeSpeak(const std::string& utterance) const OVERRIDE {
+  }
+
+ private:
+  ash::SystemTrayNotifier* GetSystemTrayNotifier() {
+    return ash::Shell::GetInstance()->system_tray_notifier();
+  }
+
+  // Returns the last active browser. If there is no such browser, creates a new
+  // browser window with an empty tab and returns it.
+  Browser* GetAppropriateBrowser() {
+    return chrome::FindOrCreateTabbedBrowser(
+        ProfileManager::GetDefaultProfileOrOffTheRecord(),
+        chrome::HOST_DESKTOP_TYPE_ASH);
+  }
+
+  void UpdateClockType() {
+    clock_type_ = (base::GetHourClockType() == base::k24HourClock) ?
+        base::k24HourClock : base::k12HourClock;
+    GetSystemTrayNotifier()->NotifyDateFormatChanged();
+  }
+
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    if (type == chrome::NOTIFICATION_UPGRADE_RECOMMENDED) {
+        UpgradeDetector* detector =
+            content::Source<UpgradeDetector>(source).ptr();
+      ash::UpdateObserver::UpdateSeverity severity =
+          ash::UpdateObserver::UPDATE_NORMAL;
+      switch (detector->upgrade_notification_stage()) {
+        case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
+          severity = ash::UpdateObserver::UPDATE_SEVERE_RED;
+          break;
+        case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
+          severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE;
+          break;
+        case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
+          severity = ash::UpdateObserver::UPDATE_LOW_GREEN;
+          break;
+        case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
+          severity = ash::UpdateObserver::UPDATE_NORMAL;
+          break;
+      }
+      GetSystemTrayNotifier()->NotifyUpdateRecommended(severity);
+    } else {
+      NOTREACHED();
+    }
+  }
+
+  scoped_ptr<content::NotificationRegistrar> registrar_;
+  base::HourClockType clock_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemTrayDelegateWin);
+};
+
+}  // namespace
+
+
+ash::SystemTrayDelegate* CreateWindowsSystemTrayDelegate() {
+  return new SystemTrayDelegateWin();
+}
+
diff --git a/chrome/browser/ui/ash/system_tray_delegate_win.h b/chrome/browser/ui/ash/system_tray_delegate_win.h
new file mode 100644
index 0000000..d595a91
--- /dev/null
+++ b/chrome/browser/ui/ash/system_tray_delegate_win.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 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_ASH_SYSTEM_TRAY_DELEGATE_WIN_H_
+#define CHROME_BROWSER_UI_ASH_SYSTEM_TRAY_DELEGATE_WIN_H_
+
+namespace ash {
+class SystemTrayDelegate;
+}
+
+ash::SystemTrayDelegate* CreateWindowsSystemTrayDelegate();
+
+#endif  // CHROME_BROWSER_UI_ASH_SYSTEM_TRAY_DELEGATE_WIN_H_
diff --git a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
index fe60b8a..3fd43ff 100644
--- a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
+++ b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
@@ -48,6 +48,13 @@
 ChromeBrowserMainExtraPartsAura::~ChromeBrowserMainExtraPartsAura() {
 }
 
+void ChromeBrowserMainExtraPartsAura::PreEarlyInitialization() {
+#if !defined(USE_ASH) && defined(OS_LINUX) && defined(USE_X11)
+  // TODO(erg): Refactor this into a dlopen call when we add a GTK3 port.
+  views::LinuxUI::SetInstance(BuildGtk2UI());
+#endif
+}
+
 void ChromeBrowserMainExtraPartsAura::ToolkitInitialized() {
 #if !defined(OS_CHROMEOS)
 #if defined(USE_ASH)
@@ -57,8 +64,7 @@
 #endif
 
 #if !defined(USE_ASH) && defined(OS_LINUX) && defined(USE_X11)
-  // TODO(erg): Refactor this into a dlopen call when we add a GTK3 port.
-  views::LinuxUI::SetInstance(BuildGtk2UI());
+  views::LinuxUI::instance()->Initialize();
 #endif
 }
 
diff --git a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.h b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.h
index a199fe8..8e70ce0 100644
--- a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.h
+++ b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.h
@@ -18,6 +18,7 @@
   virtual ~ChromeBrowserMainExtraPartsAura();
 
   // Overridden from ChromeBrowserMainExtraParts:
+  virtual void PreEarlyInitialization() OVERRIDE;
   virtual void ToolkitInitialized() OVERRIDE;
   virtual void PostMainMessageLoopStart() OVERRIDE;
   virtual void PostMainMessageLoopRun() OVERRIDE;
diff --git a/chrome/browser/ui/aura/tabs/dock_info_auralinux.cc b/chrome/browser/ui/aura/tabs/dock_info_auralinux.cc
new file mode 100644
index 0000000..d43de3b
--- /dev/null
+++ b/chrome/browser/ui/aura/tabs/dock_info_auralinux.cc
@@ -0,0 +1,219 @@
+// Copyright 2013 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/tabs/dock_info.h"
+
+#include "chrome/browser/ui/host_desktop.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#if defined(USE_X11)
+#include "ui/base/x/x11_util.h"
+#endif
+
+#if !defined(OS_CHROMEOS) && defined(USE_X11)
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+// BaseWindowFinder
+//
+// Base class used to locate a window. A subclass need only override
+// ShouldStopIterating to determine when iteration should stop.
+class BaseWindowFinder : public ui::EnumerateWindowsDelegate {
+ public:
+  explicit BaseWindowFinder(const std::set<aura::Window*>& ignore) {
+    std::set<aura::Window*>::iterator iter;
+    for (iter = ignore.begin(); iter != ignore.end(); iter++) {
+      XID xid = (*iter)->GetDispatcher()->GetAcceleratedWidget();
+      ignore_.insert(xid);
+    }
+  }
+
+  virtual ~BaseWindowFinder() {}
+
+ protected:
+  // Returns true if |window| is in the ignore list.
+  bool ShouldIgnoreWindow(XID window) {
+    return (ignore_.find(window) != ignore_.end());
+  }
+
+  // Returns true if iteration should stop, false otherwise.
+  virtual bool ShouldStopIterating(XID window) OVERRIDE {
+    return false;
+  }
+
+ private:
+  std::set<XID> ignore_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// TopMostFinder
+//
+// Helper class to determine if a particular point of a window is not obscured
+// by another window.
+class TopMostFinder : public BaseWindowFinder {
+ public:
+  // Returns true if |window| is not obscured by another window at the
+  // location |screen_loc|, not including the windows in |ignore|.
+  static bool IsTopMostWindowAtPoint(XID window,
+                                     const gfx::Point& screen_loc,
+                                     const std::set<aura::Window*>& ignore) {
+    TopMostFinder finder(window, screen_loc, ignore);
+    return finder.is_top_most_;
+  }
+
+ protected:
+  virtual bool ShouldStopIterating(XID window) OVERRIDE {
+    if (BaseWindowFinder::ShouldIgnoreWindow(window))
+      return false;
+
+    if (window == target_) {
+      // Window is topmost, stop iterating.
+      is_top_most_ = true;
+      return true;
+    }
+
+    if (!ui::IsWindowVisible(window)) {
+      // The window isn't visible, keep iterating.
+      return false;
+    }
+
+    // At this point we haven't found our target window, so this window is
+    // higher in the z-order than the target window.  If this window contains
+    // the point, then we can stop the search now because this window is
+    // obscuring the target window at this point.
+    return ui::WindowContainsPoint(window, screen_loc_);
+  }
+
+ private:
+  TopMostFinder(XID window,
+                const gfx::Point& screen_loc,
+                const std::set<aura::Window*>& ignore)
+    : BaseWindowFinder(ignore),
+      target_(window),
+      screen_loc_(screen_loc),
+      is_top_most_(false) {
+    ui::EnumerateTopLevelWindows(this);
+  }
+
+  // The window we're looking for.
+  XID target_;
+
+  // Location of window to find.
+  gfx::Point screen_loc_;
+
+  // Is target_ the top most window? This is initially false but set to true
+  // in ShouldStopIterating if target_ is passed in.
+  bool is_top_most_;
+
+  DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// LocalProcessWindowFinder
+//
+// Helper class to determine if a particular point of a window from our process
+// is not obscured by another window.
+class LocalProcessWindowFinder : public BaseWindowFinder {
+ public:
+  // Returns the XID from our process at screen_loc that is not obscured by
+  // another window. Returns 0 otherwise.
+  static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
+                                     const std::set<aura::Window*>& ignore) {
+    LocalProcessWindowFinder finder(screen_loc, ignore);
+    if (finder.result_ &&
+        TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
+                                              ignore)) {
+      return finder.result_;
+    }
+    return 0;
+  }
+
+ protected:
+  virtual bool ShouldStopIterating(XID window) OVERRIDE {
+    if (BaseWindowFinder::ShouldIgnoreWindow(window))
+      return false;
+
+    // Check if this window is in our process.
+    if (!aura::RootWindow::GetForAcceleratedWidget(window))
+      return false;
+
+    if (!ui::IsWindowVisible(window))
+      return false;
+
+    if (ui::WindowContainsPoint(window, screen_loc_)) {
+      result_ = window;
+      return true;
+    }
+
+    return false;
+  }
+
+ private:
+  LocalProcessWindowFinder(const gfx::Point& screen_loc,
+                           const std::set<aura::Window*>& ignore)
+    : BaseWindowFinder(ignore),
+      screen_loc_(screen_loc),
+      result_(0) {
+    ui::EnumerateTopLevelWindows(this);
+  }
+
+  // Position of the mouse.
+  gfx::Point screen_loc_;
+
+  // The resulting window. This is initially null but set to true in
+  // ShouldStopIterating if an appropriate window is found.
+  XID result_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
+};
+
+}  // namespace
+
+// static
+gfx::NativeView DockInfo::GetLocalProcessWindowAtPoint(
+    chrome::HostDesktopType host_desktop_type,
+    const gfx::Point& screen_point,
+    const std::set<gfx::NativeView>& ignore) {
+  // The X11 server is the canonical state of what the window stacking order
+  // is.
+  XID xid =
+      LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
+  return views::DesktopRootWindowHostX11::GetContentWindowForXID(xid);
+}
+#else
+// static
+gfx::NativeView DockInfo::GetLocalProcessWindowAtPoint(
+    chrome::HostDesktopType host_desktop_type,
+    const gfx::Point& screen_point,
+    const std::set<gfx::NativeView>& ignore) {
+
+  // TODO(vignatti):
+  NOTIMPLEMENTED();
+  return NULL;
+}
+#endif
+
+// static
+DockInfo DockInfo::GetDockInfoAtPoint(chrome::HostDesktopType host_desktop_type,
+                                      const gfx::Point& screen_point,
+                                      const std::set<gfx::NativeView>& ignore) {
+  // TODO(beng):
+  NOTIMPLEMENTED();
+  return DockInfo();
+}
+
+bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
+  if (!window())
+    return false;
+  *bounds = window_->bounds();
+  return true;
+}
+
+void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
+  window_->SetBounds(bounds);
+}
diff --git a/chrome/browser/ui/aura/tabs/dock_info_aurax11.cc b/chrome/browser/ui/aura/tabs/dock_info_aurax11.cc
deleted file mode 100644
index 274f5c2..0000000
--- a/chrome/browser/ui/aura/tabs/dock_info_aurax11.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2012 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/tabs/dock_info.h"
-
-#include "chrome/browser/ui/host_desktop.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/x/x11_util.h"
-
-#if !defined(OS_CHROMEOS)
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
-#endif
-
-#if !defined(OS_CHROMEOS)
-
-namespace {
-
-////////////////////////////////////////////////////////////////////////////////
-// BaseWindowFinder
-//
-// Base class used to locate a window. A subclass need only override
-// ShouldStopIterating to determine when iteration should stop.
-class BaseWindowFinder : public ui::EnumerateWindowsDelegate {
- public:
-  explicit BaseWindowFinder(const std::set<aura::Window*>& ignore) {
-    std::set<aura::Window*>::iterator iter;
-    for (iter = ignore.begin(); iter != ignore.end(); iter++) {
-      XID xid = (*iter)->GetRootWindow()->GetAcceleratedWidget();
-      ignore_.insert(xid);
-    }
-  }
-
-  virtual ~BaseWindowFinder() {}
-
- protected:
-  // Returns true if |window| is in the ignore list.
-  bool ShouldIgnoreWindow(XID window) {
-    return (ignore_.find(window) != ignore_.end());
-  }
-
-  // Returns true if iteration should stop, false otherwise.
-  virtual bool ShouldStopIterating(XID window) OVERRIDE {
-    return false;
-  }
-
- private:
-  std::set<XID> ignore_;
-
-  DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// TopMostFinder
-//
-// Helper class to determine if a particular point of a window is not obscured
-// by another window.
-class TopMostFinder : public BaseWindowFinder {
- public:
-  // Returns true if |window| is not obscured by another window at the
-  // location |screen_loc|, not including the windows in |ignore|.
-  static bool IsTopMostWindowAtPoint(XID window,
-                                     const gfx::Point& screen_loc,
-                                     const std::set<aura::Window*>& ignore) {
-    TopMostFinder finder(window, screen_loc, ignore);
-    return finder.is_top_most_;
-  }
-
- protected:
-  virtual bool ShouldStopIterating(XID window) OVERRIDE {
-    if (BaseWindowFinder::ShouldIgnoreWindow(window))
-      return false;
-
-    if (window == target_) {
-      // Window is topmost, stop iterating.
-      is_top_most_ = true;
-      return true;
-    }
-
-    if (!ui::IsWindowVisible(window)) {
-      // The window isn't visible, keep iterating.
-      return false;
-    }
-
-    // At this point we haven't found our target window, so this window is
-    // higher in the z-order than the target window.  If this window contains
-    // the point, then we can stop the search now because this window is
-    // obscuring the target window at this point.
-    return ui::WindowContainsPoint(window, screen_loc_);
-  }
-
- private:
-  TopMostFinder(XID window,
-                const gfx::Point& screen_loc,
-                const std::set<aura::Window*>& ignore)
-    : BaseWindowFinder(ignore),
-      target_(window),
-      screen_loc_(screen_loc),
-      is_top_most_(false) {
-    ui::EnumerateTopLevelWindows(this);
-  }
-
-  // The window we're looking for.
-  XID target_;
-
-  // Location of window to find.
-  gfx::Point screen_loc_;
-
-  // Is target_ the top most window? This is initially false but set to true
-  // in ShouldStopIterating if target_ is passed in.
-  bool is_top_most_;
-
-  DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// LocalProcessWindowFinder
-//
-// Helper class to determine if a particular point of a window from our process
-// is not obscured by another window.
-class LocalProcessWindowFinder : public BaseWindowFinder {
- public:
-  // Returns the XID from our process at screen_loc that is not obscured by
-  // another window. Returns 0 otherwise.
-  static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
-                                     const std::set<aura::Window*>& ignore) {
-    LocalProcessWindowFinder finder(screen_loc, ignore);
-    if (finder.result_ &&
-        TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
-                                              ignore)) {
-      return finder.result_;
-    }
-    return 0;
-  }
-
- protected:
-  virtual bool ShouldStopIterating(XID window) OVERRIDE {
-    if (BaseWindowFinder::ShouldIgnoreWindow(window))
-      return false;
-
-    // Check if this window is in our process.
-    if (!aura::RootWindow::GetForAcceleratedWidget(window))
-      return false;
-
-    if (!ui::IsWindowVisible(window))
-      return false;
-
-    if (ui::WindowContainsPoint(window, screen_loc_)) {
-      result_ = window;
-      return true;
-    }
-
-    return false;
-  }
-
- private:
-  LocalProcessWindowFinder(const gfx::Point& screen_loc,
-                           const std::set<aura::Window*>& ignore)
-    : BaseWindowFinder(ignore),
-      screen_loc_(screen_loc),
-      result_(0) {
-    ui::EnumerateTopLevelWindows(this);
-  }
-
-  // Position of the mouse.
-  gfx::Point screen_loc_;
-
-  // The resulting window. This is initially null but set to true in
-  // ShouldStopIterating if an appropriate window is found.
-  XID result_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
-};
-
-}  // namespace
-
-// static
-DockInfo DockInfo::GetDockInfoAtPoint(chrome::HostDesktopType host_desktop_type,
-                                      const gfx::Point& screen_point,
-                                      const std::set<gfx::NativeView>& ignore) {
-  // TODO(beng):
-  NOTIMPLEMENTED();
-  return DockInfo();
-}
-
-// static
-gfx::NativeView DockInfo::GetLocalProcessWindowAtPoint(
-    chrome::HostDesktopType host_desktop_type,
-    const gfx::Point& screen_point,
-    const std::set<gfx::NativeView>& ignore) {
-  // The X11 server is the canonical state of what the window stacking order
-  // is.
-  XID xid =
-      LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
-  return views::DesktopRootWindowHostX11::GetContentWindowForXID(xid);
-}
-
-bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
-  if (!window())
-    return false;
-  *bounds = window_->bounds();
-  return true;
-}
-
-void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
-  window_->SetBounds(bounds);
-}
-
-#endif
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
index 36bfd41..93cda44 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
@@ -7,10 +7,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/autofill/account_chooser_model.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
@@ -19,6 +21,7 @@
 #include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
@@ -32,13 +35,16 @@
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
+#include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "url/gurl.h"
 
 namespace autofill {
 
@@ -97,6 +103,10 @@
 
   virtual ~TestAutofillDialogController() {}
 
+  virtual GURL SignInUrl() const OVERRIDE {
+    return GURL(content::kAboutBlankURL);
+  }
+
   virtual void ViewClosed() OVERRIDE {
     message_loop_runner_->Quit();
     AutofillDialogControllerImpl::ViewClosed();
@@ -152,6 +162,7 @@
   using AutofillDialogControllerImpl::IsManuallyEditingSection;
   using AutofillDialogControllerImpl::IsSubmitPausedOn;
   using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
+  using AutofillDialogControllerImpl::AccountChooserModelForTesting;
 
   void set_use_validation(bool use_validation) {
     use_validation_ = use_validation;
@@ -174,6 +185,10 @@
     return &mock_wallet_client_;
   }
 
+  virtual bool IsSignInContinueUrl(const GURL& url) const OVERRIDE {
+    return true;
+  }
+
  private:
   // To specify our own metric logger.
   virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
@@ -286,6 +301,16 @@
                 "document.forms[0].requestAutocomplete();"
                 "send('clicked');"
               "};"
+              "function getValueForFieldOfType(type) {"
+              "  var fields = document.getElementsByTagName('input');"
+              "  for (var i = 0; i < fields.length; i++) {"
+              "    if (fields[i].autocomplete == type) {"
+              "      send(fields[i].value);"
+              "      return;"
+              "    }"
+              "  }"
+              "  send('');"
+              "};"
             "</script>"
           "</body>"
         "</html>"));
@@ -313,6 +338,19 @@
     EXPECT_EQ("\"" + expected + "\"", message);
   }
 
+  // Returns the value filled into the first field with autocomplete attribute
+  // equal to |autocomplete_type|, or an empty string if there is no such field.
+  std::string GetValueForHTMLFieldOfType(const std::string& autocomplete_type) {
+    content::RenderViewHost* render_view_host =
+        browser()->tab_strip_model()->GetActiveWebContents()->
+        GetRenderViewHost();
+    std::string script = "getValueForFieldOfType('" + autocomplete_type + "');";
+    std::string result;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_view_host, script,
+                                                       &result));
+    return result;
+  }
+
   void AddCreditcardToProfile(Profile* profile, const CreditCard& card) {
     PersonalDataManagerFactory::GetForProfile(profile)->AddCreditCard(card);
     WaitForWebDB();
@@ -806,8 +844,6 @@
 }
 #endif  // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
 
-// TODO(groby): figure out if the CVC challenge code actually works on Mac.
-#if !defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
                        GeneratedCardLastFourAfterVerifyCvv) {
   std::vector<std::string> usernames;
@@ -858,6 +894,52 @@
   EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
   EXPECT_EQ(last_four, test_generated_bubble_controller()->backing_card_name());
 }
-#endif  // !defined(OS_MACOSX)
+
+// Simulates the user successfully signing in to the dialog for the first time.
+// The controller listens for nav entry commits and should not destroy the web
+// contents before its post load code runs (which would cause a crash).
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, SignInNoCrash) {
+  browser()->profile()->GetPrefs()->SetBoolean(
+      ::prefs::kAutofillDialogPayWithoutWallet,
+      true);
+
+  InitializeController();
+
+  ui_test_utils::UrlLoadObserver observer(
+      controller()->SignInUrl(),
+      content::NotificationService::AllSources());
+
+  controller()->SignInLinkClicked();
+
+  TestableAutofillDialogView* view = controller()->GetTestableView();
+  EXPECT_TRUE(view->GetSignInWebContents());
+  EXPECT_TRUE(controller()->ShouldShowSignInWebView());
+
+  const AccountChooserModel& account_chooser_model =
+      controller()->AccountChooserModelForTesting();
+  EXPECT_FALSE(account_chooser_model.WalletIsSelected());
+
+  observer.Wait();
+
+  // Wallet should now be selected and Chrome shouldn't have crashed.
+  EXPECT_TRUE(account_chooser_model.WalletIsSelected());
+}
+
+// Verify that filling a form works correctly, including filling the CVC when
+// that is requested separately.
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, FillFormIncludesCVC) {
+  AutofillDialogControllerImpl* controller =
+      SetUpHtmlAndInvoke("<input autocomplete='cc-csc'>");
+
+  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
+  AddAutofillProfileToProfile(controller->profile(),
+                              test::GetVerifiedProfile());
+
+  TestableAutofillDialogView* view = controller->GetTestableView();
+  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
+  view->SubmitForTesting();
+  ExpectDomMessage("success");
+  EXPECT_EQ("123", GetValueForHTMLFieldOfType("cc-csc"));
+}
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 384a8d7..d924f89 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -17,6 +17,7 @@
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -25,7 +26,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_common.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
@@ -140,16 +140,6 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
 };
 
-// Returns true if |card_type| is supported by Wallet.
-bool IsWalletSupportedCard(const std::string& card_type,
-                           const wallet::WalletItems& wallet_items) {
-  return card_type == autofill::kVisaCard ||
-         card_type == autofill::kMasterCard ||
-         card_type == autofill::kDiscoverCard ||
-         (card_type == autofill::kAmericanExpressCard &&
-             wallet_items.is_amex_allowed());
-}
-
 // Returns true if |input| should be used to fill a site-requested |field| which
 // is notated with a "shipping" tag, for use when the user has decided to use
 // the billing address as the shipping address.
@@ -791,7 +781,6 @@
   if (!IsPayingWithWallet())
     return string16();
 
-  EnsureLegalDocumentsText();
   return legal_documents_text_;
 }
 
@@ -804,6 +793,14 @@
          SignedInState() == REQUIRES_RESPONSE;
 }
 
+bool AutofillDialogControllerImpl::ShouldShowSignInWebView() const {
+  return !signin_registrar_.IsEmpty();
+}
+
+GURL AutofillDialogControllerImpl::SignInUrl() const {
+  return wallet::GetSignInUrl();
+}
+
 bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
   return !IsPayingWithWallet() &&
       !profile_->IsOffTheRecord() &&
@@ -916,7 +913,6 @@
 
 const std::vector<gfx::Range>& AutofillDialogControllerImpl::
     LegalDocumentLinks() {
-  EnsureLegalDocumentsText();
   return legal_document_link_ranges_;
 }
 
@@ -1077,41 +1073,57 @@
   UpdateForErrors();
 }
 
-void AutofillDialogControllerImpl::EnsureLegalDocumentsText() {
+void AutofillDialogControllerImpl::ConstructLegalDocumentsText() {
   if (!wallet_items_ || wallet_items_->legal_documents().empty())
     return;
-
-  // The text has already been constructed, no need to recompute.
-  if (!legal_documents_text_.empty())
-    return;
+  NOTIMPLEMENTED();
 
   const std::vector<wallet::WalletItems::LegalDocument*>& documents =
       wallet_items_->legal_documents();
-  DCHECK_LE(documents.size(), 3U);
+  // There should never be just one document because the privacy policy doc gets
+  // tacked on the end of other documents.
   DCHECK_GE(documents.size(), 2U);
-  const bool new_user = wallet_items_->HasRequiredAction(wallet::SETUP_WALLET);
 
-  const string16 privacy_policy_display_name =
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PRIVACY_POLICY_LINK);
-  string16 text;
-  if (documents.size() == 2U) {
-    text = l10n_util::GetStringFUTF16(
-        new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_2 :
-                   IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_2,
-        documents[0]->display_name(),
-        documents[1]->display_name());
-  } else {
-    text = l10n_util::GetStringFUTF16(
-        new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_3 :
-                   IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_3,
-        documents[0]->display_name(),
-        documents[1]->display_name(),
-        documents[2]->display_name());
+  std::vector<base::string16> link_names;
+  for (size_t i = 0; i < documents.size(); ++i) {
+    link_names.push_back(documents[i]->display_name());
   }
 
+  const bool new_user = wallet_items_->HasRequiredAction(wallet::SETUP_WALLET);
+  int resource_id = 0;
+  switch (documents.size()) {
+    case 2U:
+      resource_id = new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_2 :
+                               IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_2;
+      break;
+    case 3U:
+      resource_id = new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_3 :
+                               IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_3;
+      break;
+    case 4U:
+      resource_id = new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_4 :
+                               IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_4;
+      break;
+    case 5U:
+      resource_id = new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_5 :
+                               IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_5;
+      break;
+    case 6U:
+      resource_id = new_user ? IDS_AUTOFILL_DIALOG_LEGAL_LINKS_NEW_6 :
+                               IDS_AUTOFILL_DIALOG_LEGAL_LINKS_UPDATED_6;
+      break;
+    default:
+      // We can only handle so many documents. For lack of a better way of
+      // handling document overflow, just error out if there are too many.
+      DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
+      return;
+  }
+
+  std::vector<size_t> offsets;
+  string16 text = l10n_util::GetStringFUTF16(resource_id, link_names, &offsets);
   legal_document_link_ranges_.clear();
   for (size_t i = 0; i < documents.size(); ++i) {
-    size_t link_start = text.find(documents[i]->display_name());
+    size_t link_start = offsets[i];
     legal_document_link_ranges_.push_back(gfx::Range(
         link_start, link_start + documents[i]->display_name().size()));
   }
@@ -2170,11 +2182,16 @@
   DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED);
   content::LoadCommittedDetails* load_details =
       content::Details<content::LoadCommittedDetails>(details).ptr();
-  if (wallet::IsSignInContinueUrl(load_details->entry->GetVirtualURL())) {
+  if (IsSignInContinueUrl(load_details->entry->GetVirtualURL())) {
     // TODO(estade): will need to update this when we fix <crbug.com/247755>.
     account_chooser_model_.SelectActiveWalletAccount();
     FetchWalletCookieAndUserName();
-    HideSignIn();
+
+    // NOTE: |HideSignIn()| may delete the WebContents which doesn't expect to
+    // be deleted while committing a nav entry. Just call |HideSignIn()| later.
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+        base::Bind(&AutofillDialogControllerImpl::HideSignIn,
+                   base::Unretained(this)));
   }
 }
 
@@ -2352,6 +2369,7 @@
 
   wallet_items_ = wallet_items.Pass();
   OnWalletOrSigninUpdate();
+  ConstructLegalDocumentsText();
 }
 
 void AutofillDialogControllerImpl::OnDidSaveToWallet(
@@ -2485,6 +2503,15 @@
   last_wallet_items_fetch_timestamp_ = base::TimeTicks();
 }
 
+const AccountChooserModel& AutofillDialogControllerImpl::
+    AccountChooserModelForTesting() const {
+  return account_chooser_model_;
+}
+
+bool AutofillDialogControllerImpl::IsSignInContinueUrl(const GURL& url) const {
+  return wallet::IsSignInContinueUrl(url);
+}
+
 AutofillDialogControllerImpl::AutofillDialogControllerImpl(
     content::WebContents* contents,
     const FormData& form_structure,
@@ -2989,13 +3016,9 @@
         IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER);
   }
 
-  // Wallet only accepts MasterCard, Visa and Discover. No AMEX.
-  if (IsPayingWithWallet() &&
-      !IsWalletSupportedCard(CreditCard::GetCreditCardType(number),
-                             *wallet_items_)) {
-    return l10n_util::GetStringUTF16(
-        IDS_AUTOFILL_DIALOG_VALIDATION_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET);
-  }
+  base::string16 message;
+  if (IsPayingWithWallet() && !wallet_items_->SupportsCard(number, &message))
+    return message;
 
   // Card number is good and supported.
   return base::string16();
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index b320ed4..efbe157 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -113,6 +113,8 @@
   virtual string16 LegalDocumentsText() OVERRIDE;
   virtual bool ShouldDisableSignInLink() const OVERRIDE;
   virtual bool ShouldShowSpinner() const OVERRIDE;
+  virtual bool ShouldShowSignInWebView() const OVERRIDE;
+  virtual GURL SignInUrl() const OVERRIDE;
   virtual bool ShouldOfferToSaveInChrome() const OVERRIDE;
   virtual bool ShouldSaveInChrome() const OVERRIDE;
   virtual ui::MenuModel* MenuModelForAccountChooser() OVERRIDE;
@@ -308,6 +310,12 @@
   // Resets |last_wallet_items_fetch_timestamp_| for testing.
   void ClearLastWalletItemsFetchTimestampForTesting();
 
+  // Allows tests to inspect the state of the account chooser.
+  const AccountChooserModel& AccountChooserModelForTesting() const;
+
+  // Returns whether |url| matches the sign in continue URL.
+  virtual bool IsSignInContinueUrl(const GURL& url) const;
+
  private:
   enum DialogSignedInState {
     REQUIRES_RESPONSE,
@@ -343,9 +351,8 @@
   void OnWalletFormFieldError(
       const std::vector<wallet::FormFieldError>& form_field_errors);
 
-  // Calculates |legal_documents_text_| and |legal_document_link_ranges_| if
-  // they have not already been calculated.
-  void EnsureLegalDocumentsText();
+  // Calculates |legal_documents_text_| and |legal_document_link_ranges_|.
+  void ConstructLegalDocumentsText();
 
   // Clears previously entered manual input and removes |section| from
   // |section_editing_state_|. Does not update the view.
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index f0c2342..3794f90 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -1226,14 +1226,58 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
   EXPECT_CALL(*controller(), LoadRiskFingerprintData());
 
+  EXPECT_TRUE(controller()->LegalDocumentsText().empty());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
+  EXPECT_TRUE(controller()->LegalDocumentsText().empty());
+
   scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
   wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
+  EXPECT_FALSE(controller()->LegalDocumentsText().empty());
+
   controller()->OnAccept();
   controller()->OnDidAcceptLegalDocuments();
   controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
 }
 
+TEST_F(AutofillDialogControllerTest, RejectLegalDocuments) {
+  EXPECT_CALL(*controller()->GetTestingWalletClient(),
+              AcceptLegalDocuments(_, _)).Times(0);
+
+  scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
+  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  EXPECT_FALSE(controller()->LegalDocumentsText().empty());
+
+  controller()->OnCancel();
+}
+
+TEST_F(AutofillDialogControllerTest, LegalDocumentOverflow) {
+  for (size_t number_of_docs = 2; number_of_docs < 11; ++number_of_docs) {
+    scoped_ptr<wallet::WalletItems> wallet_items =
+        CompleteAndValidWalletItems();
+    for (size_t i = 0; i < number_of_docs; ++i)
+      wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+
+    Reset();
+    controller()->OnDidGetWalletItems(wallet_items.Pass());
+
+    // The dialog is only equipped to handle 2-6 legal documents. More than
+    // 6 errors out.
+    if (number_of_docs <= 6U) {
+      EXPECT_FALSE(controller()->LegalDocumentsText().empty());
+    } else {
+      EXPECT_TRUE(controller()->LegalDocumentsText().empty());
+      EXPECT_EQ(1U, NotificationsOfType(
+          DialogNotification::WALLET_ERROR).size());
+    }
+  }
+
+  controller()->OnCancel();
+}
+
 // Makes sure the default object IDs are respected.
 TEST_F(AutofillDialogControllerTest, WalletDefaultItems) {
   scoped_ptr<wallet::WalletItems> wallet_items =
@@ -1926,6 +1970,7 @@
 
   scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
   wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
   controller()->OnAccept();
 }
@@ -1935,6 +1980,7 @@
 
   scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
   wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
+  wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
 
   testing::Mock::VerifyAndClear(controller());
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
index eee85b9..2de200e 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
@@ -16,6 +16,7 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/range/range.h"
 
+class GURL;
 class Profile;
 
 namespace content {
@@ -58,10 +59,16 @@
   // Whether the sign-in link should be disabled.
   virtual bool ShouldDisableSignInLink() const = 0;
 
-  // Whether the dialog is in a not exactly well-defined state
-  // (while attempting to sign-in or retrieving the wallet data etc).
+  // Whether a loading animation should be shown (e.g. while signing in,
+  // retreiving Wallet data, etc.).
   virtual bool ShouldShowSpinner() const = 0;
 
+  // Whether the sign in web view should be displayed.
+  virtual bool ShouldShowSignInWebView() const = 0;
+
+  // The URL to sign in to Google.
+  virtual GURL SignInUrl() const = 0;
+
   // Whether to show the checkbox to save data locally (in Autofill).
   virtual bool ShouldOfferToSaveInChrome() const = 0;
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index c7c1751..a910266 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -336,15 +336,15 @@
 }
 
 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) {
-  int top = 0;
+  int top = AutofillPopupView::kBorderThickness;
   for (size_t i = 0; i < index; ++i) {
     top += GetRowHeightFromId(identifiers()[i]);
   }
 
   return gfx::Rect(
-      0,
+      AutofillPopupView::kBorderThickness,
       top,
-      popup_bounds_.width(),
+      popup_bounds_.width() - 2 * AutofillPopupView::kBorderThickness,
       GetRowHeightFromId(identifiers()[index]));
 }
 
@@ -508,7 +508,7 @@
 }
 
 int AutofillPopupControllerImpl::LineFromY(int y) {
-  int current_height = 0;
+  int current_height = AutofillPopupView::kBorderThickness;
 
   for (size_t i = 0; i < identifiers().size(); ++i) {
     current_height += GetRowHeightFromId(identifiers()[i]);
@@ -586,7 +586,7 @@
 }
 
 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const {
-  int popup_height = 0;
+  int popup_height = 2 * AutofillPopupView::kBorderThickness;
 
   for (size_t i = 0; i < identifiers().size(); ++i) {
     popup_height += GetRowHeightFromId(identifiers()[i]);
@@ -605,9 +605,12 @@
   if (!icons_[row].empty())
     row_size += kAutofillIconWidth + kIconPadding;
 
-  // Add the padding at the end
+  // Add the padding at the end.
   row_size += kEndPadding;
 
+  // Add room for the popup border.
+  row_size += 2 * AutofillPopupView::kBorderThickness;
+
   return row_size;
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
index 45e0e18..b8fbbbc 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
@@ -121,10 +121,18 @@
 }
 #endif // !defined(OS_MACOSX)
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_DeleteDelegateBeforePopupHidden \
+  DISABLED_DeleteDelegateBeforePopupHidden
+#else
+#define MAYBE_DeleteDelegateBeforePopupHidden DeleteDelegateBeforePopupHidden
+#endif
+
 // This test checks that the browser doesn't crash if the delegate is deleted
 // before the popup is hidden.
 IN_PROC_BROWSER_TEST_F(AutofillPopupControllerBrowserTest,
-                       DeleteDelegateBeforePopupHidden){
+                       MAYBE_DeleteDelegateBeforePopupHidden){
   GenerateTestAutofillPopup(autofill_external_delegate_.get());
 
   // Delete the external delegate here so that is gets deleted before popup is
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
index 8cbcdeb..04fea11 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -81,69 +81,34 @@
   }
 
   // Making protected functions public for testing
-  void SetPopupBounds(const gfx::Rect& bounds) {
-    AutofillPopupControllerImpl::SetPopupBounds(bounds);
-  }
-  const std::vector<string16>& names() const {
-    return AutofillPopupControllerImpl::names();
-  }
-  const std::vector<string16>& subtexts() const {
-    return AutofillPopupControllerImpl::subtexts();
-  }
-  const std::vector<int>& identifiers() const {
-    return AutofillPopupControllerImpl::identifiers();
-  }
-  int selected_line() const {
-    return AutofillPopupControllerImpl::selected_line();
-  }
-  void SetSelectedLine(size_t selected_line) {
-    AutofillPopupControllerImpl::SetSelectedLine(selected_line);
-  }
-  void SelectNextLine() {
-    AutofillPopupControllerImpl::SelectNextLine();
-  }
-  void SelectPreviousLine() {
-    AutofillPopupControllerImpl::SelectPreviousLine();
-  }
-  bool RemoveSelectedLine() {
-    return AutofillPopupControllerImpl::RemoveSelectedLine();
-  }
-  void DoHide() {
-    AutofillPopupControllerImpl::Hide();
-  }
-  const gfx::Rect& popup_bounds() const {
-    return AutofillPopupControllerImpl::popup_bounds();
-  }
-  const gfx::RectF& element_bounds() const {
-    return AutofillPopupControllerImpl::element_bounds();
-  }
+  using AutofillPopupControllerImpl::SetPopupBounds;
+  using AutofillPopupControllerImpl::names;
+  using AutofillPopupControllerImpl::subtexts;
+  using AutofillPopupControllerImpl::identifiers;
+  using AutofillPopupControllerImpl::selected_line;
+  using AutofillPopupControllerImpl::SetSelectedLine;
+  using AutofillPopupControllerImpl::SelectNextLine;
+  using AutofillPopupControllerImpl::SelectPreviousLine;
+  using AutofillPopupControllerImpl::RemoveSelectedLine;
+  using AutofillPopupControllerImpl::popup_bounds;
+  using AutofillPopupControllerImpl::element_bounds;
 #if !defined(OS_ANDROID)
-  const gfx::Font& GetNameFontForRow(size_t index) const {
-    return AutofillPopupControllerImpl::GetNameFontForRow(index);
-  }
-  const gfx::Font& subtext_font() const {
-    return AutofillPopupControllerImpl::subtext_font();
-  }
-  int RowWidthWithoutText(int row) const {
-    return AutofillPopupControllerImpl::RowWidthWithoutText(row);
-  }
+  using AutofillPopupControllerImpl::GetNameFontForRow;
+  using AutofillPopupControllerImpl::subtext_font;
+  using AutofillPopupControllerImpl::RowWidthWithoutText;
 #endif
   using AutofillPopupControllerImpl::SetValues;
-  int GetDesiredPopupWidth() const {
-    return AutofillPopupControllerImpl::GetDesiredPopupWidth();
-  }
-  int GetDesiredPopupHeight() const {
-    return AutofillPopupControllerImpl::GetDesiredPopupHeight();
-  }
-
-  WeakPtr<AutofillPopupControllerImpl> GetWeakPtr() {
-    return AutofillPopupControllerImpl::GetWeakPtr();
-  }
-
+  using AutofillPopupControllerImpl::GetDesiredPopupWidth;
+  using AutofillPopupControllerImpl::GetDesiredPopupHeight;
+  using AutofillPopupControllerImpl::GetWeakPtr;
   MOCK_METHOD1(InvalidateRow, void(size_t));
   MOCK_METHOD0(UpdateBoundsAndRedrawPopup, void());
   MOCK_METHOD0(Hide, void());
 
+  void DoHide() {
+    AutofillPopupControllerImpl::Hide();
+  }
+
  private:
   virtual void ShowView() OVERRIDE {}
 
@@ -355,7 +320,9 @@
   icons[3] = ASCIIToUTF16("x");
   autofill_popup_controller_->Show(names, subtexts, icons, ids);
 
-  int base_size = AutofillPopupView::kEndPadding * 2;
+  int base_size =
+      AutofillPopupView::kEndPadding * 2 +
+      AutofillPopupView::kBorderThickness * 2;
   int subtext_increase = AutofillPopupView::kNamePadding;
   int icon_increase = AutofillPopupView::kIconPadding +
       AutofillPopupView::kAutofillIconWidth;
diff --git a/chrome/browser/ui/autofill/data_model_wrapper.cc b/chrome/browser/ui/autofill/data_model_wrapper.cc
index 514d498..2272654 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper.cc
+++ b/chrome/browser/ui/autofill/data_model_wrapper.cc
@@ -13,11 +13,11 @@
 #include "components/autofill/content/browser/wallet/wallet_address.h"
 #include "components/autofill/content/browser/wallet/wallet_items.h"
 #include "components/autofill/core/browser/autofill_data_model.h"
+#include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/form_structure.h"
-#include "components/autofill/core/browser/validation.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 
@@ -60,7 +60,9 @@
     AutofillField* field = form_structure->field(i);
     for (size_t j = 0; j < inputs.size(); ++j) {
       if (compare.Run(inputs[j], *field)) {
-        FillFormField(field);
+        AutofillField::FillFormField(*field, GetInfo(field->Type()),
+                                     g_browser_process->GetApplicationLocale(),
+                                     field);
         filled_something = true;
         break;
       }
@@ -71,10 +73,6 @@
 
 DataModelWrapper::DataModelWrapper() {}
 
-void DataModelWrapper::FillFormField(AutofillField* field) const {
-  field->value = GetInfo(field->Type());
-}
-
 base::string16 DataModelWrapper::GetAddressDisplayText(
     const base::string16& separator) {
   base::string16 address = GetInfoForDisplay(AutofillType(NAME_FULL)) +
@@ -107,8 +105,6 @@
   return base::string16();
 }
 
-void EmptyDataModelWrapper::FillFormField(AutofillField* field) const {}
-
 // AutofillProfileWrapper
 
 AutofillProfileWrapper::AutofillProfileWrapper(const AutofillProfile* profile)
@@ -126,12 +122,17 @@
 
 AutofillProfileWrapper::~AutofillProfileWrapper() {}
 
-base::string16 AutofillProfileWrapper::GetInfo(const AutofillType& type)
-    const {
+base::string16 AutofillProfileWrapper::GetInfo(const AutofillType& type) const {
+  // Requests for the user's credit card are filled from the billing address,
+  // but the AutofillProfile class doesn't know how to fill credit card
+  // fields. So, request for the corresponding profile type instead.
+  AutofillType effective_type = type;
+  if (type.GetStorableType() == CREDIT_CARD_NAME)
+    effective_type = AutofillType(NAME_BILLING_FULL);
+
+  size_t variant = GetVariantForType(effective_type);
   const std::string& app_locale = g_browser_process->GetApplicationLocale();
-  std::vector<base::string16> values;
-  profile_->GetMultiInfo(type, app_locale, &values);
-  return values[GetVariantForType(type)];
+  return profile_->GetInfoForVariant(effective_type, variant, app_locale);
 }
 
 base::string16 AutofillProfileWrapper::GetInfoForDisplay(
@@ -157,29 +158,6 @@
   return DataModelWrapper::GetInfoForDisplay(type);
 }
 
-void AutofillProfileWrapper::FillFormField(AutofillField* field) const {
-  if (field->Type().GetStorableType() == CREDIT_CARD_NAME) {
-    // Cache the field's true type.
-    HtmlFieldType original_type = field->html_type();
-
-    // Requests for the user's credit card are filled from the billing address,
-    // but the AutofillProfile class doesn't know how to fill credit card
-    // fields. So, temporarily set the type to the corresponding profile type.
-    field->SetHtmlType(HTML_TYPE_NAME, field->html_mode());
-
-    profile_->FillFormField(
-        *field, GetVariantForType(field->Type()),
-        g_browser_process->GetApplicationLocale(), field);
-
-    // Restore the field's true type.
-    field->SetHtmlType(original_type, field->html_mode());
-  } else {
-    profile_->FillFormField(
-        *field, GetVariantForType(field->Type()),
-        g_browser_process->GetApplicationLocale(), field);
-  }
-}
-
 size_t AutofillProfileWrapper::GetVariantForType(const AutofillType& type)
     const {
   if (type.group() == variant_group_)
@@ -238,11 +216,6 @@
   return true;
 }
 
-void AutofillCreditCardWrapper::FillFormField(AutofillField* field) const {
-  card_->FillFormField(
-      *field, 0, g_browser_process->GetApplicationLocale(), field);
-}
-
 // WalletAddressWrapper
 
 WalletAddressWrapper::WalletAddressWrapper(
diff --git a/chrome/browser/ui/autofill/data_model_wrapper.h b/chrome/browser/ui/autofill/data_model_wrapper.h
index 37cf117..3cb5661 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper.h
+++ b/chrome/browser/ui/autofill/data_model_wrapper.h
@@ -72,9 +72,6 @@
  protected:
   DataModelWrapper();
 
-  // Fills in |field| with data from the model.
-  virtual void FillFormField(AutofillField* field) const;
-
  private:
   // Formats address data into a single string using |separator| between
   // fields.
@@ -93,8 +90,6 @@
   virtual base::string16 GetInfo(const AutofillType& type) const OVERRIDE;
 
  protected:
-  virtual void FillFormField(AutofillField* field) const OVERRIDE;
-
   DISALLOW_COPY_AND_ASSIGN(EmptyDataModelWrapper);
 };
 
@@ -112,8 +107,6 @@
       OVERRIDE;
 
  protected:
-  virtual void FillFormField(AutofillField* field) const OVERRIDE;
-
   // Returns the variant that should be used when dealing with an element that
   // has the given |type|.
   size_t GetVariantForType(const AutofillType& type) const;
@@ -153,8 +146,6 @@
                               base::string16* horizontally_compact) OVERRIDE;
 
  private:
-  virtual void FillFormField(AutofillField* field) const OVERRIDE;
-
   const CreditCard* card_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardWrapper);
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
index 57e6093..fff3622 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
@@ -21,6 +21,7 @@
   // breaking because of this, use ON_CALL instead.
   DefaultValue<const DetailInputs&>::Set(default_inputs_);
   DefaultValue<string16>::Set(string16());
+  DefaultValue<GURL>::Set(GURL());
   DefaultValue<ValidityMessages>::Set(ValidityMessages());
   DefaultValue<gfx::Image>::Set(gfx::Image());
   DefaultValue<SuggestionState>::Set(SuggestionState(false,
@@ -57,6 +58,10 @@
   testing::DefaultValue<content::WebContents*>::Set(contents);
 }
 
+void MockAutofillDialogViewDelegate::SetProfile(Profile* profile) {
+  testing::DefaultValue<Profile*>::Set(profile);
+}
+
 MockAutofillDialogViewDelegate::~MockAutofillDialogViewDelegate() {
   using testing::DefaultValue;
 
@@ -64,10 +69,12 @@
   DefaultValue<gfx::Image>::Clear();
   DefaultValue<ValidityMessages>::Clear();
   DefaultValue<string16>::Clear();
+  DefaultValue<GURL>::Clear();
   DefaultValue<const DetailInputs&>::Clear();
   DefaultValue<FieldIconMap>::Clear();
   DefaultValue<std::vector<DialogNotification> >::Clear();
   DefaultValue<content::WebContents*>::Clear();
+  DefaultValue<Profile*>::Clear();
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
index 3eb153d..87b9f6e 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
@@ -29,6 +29,8 @@
   MOCK_METHOD0(LegalDocumentsText, string16());
   MOCK_CONST_METHOD0(ShouldDisableSignInLink, bool());
   MOCK_CONST_METHOD0(ShouldShowSpinner, bool());
+  MOCK_CONST_METHOD0(ShouldShowSignInWebView, bool());
+  MOCK_CONST_METHOD0(SignInUrl, GURL());
   MOCK_CONST_METHOD0(ShouldOfferToSaveInChrome, bool());
   MOCK_CONST_METHOD0(ShouldSaveInChrome, bool());
   MOCK_METHOD0(MenuModelForAccountChooser, ui::MenuModel*());
@@ -84,6 +86,9 @@
   // Set which web contents initiated showing the dialog.
   void SetWebContents(content::WebContents* contents);
 
+  // Set which profile to use for mock |profile()| calls.
+  void SetProfile(Profile* profile);
+
  private:
   DetailInputs default_inputs_;
   DetailInputs cc_default_inputs_;  // Default inputs for SECTION_CC.
diff --git a/chrome/browser/ui/autofill/testable_autofill_dialog_view.h b/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
index c8238a7..a9bbbfb 100644
--- a/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
+++ b/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
@@ -35,6 +35,9 @@
 
   // Get the size of the entire view.
   virtual gfx::Size GetSize() const = 0;
+
+  // Get the web contents used to sign in to Google.
+  virtual content::WebContents* GetSignInWebContents() = 0;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.cc b/chrome/browser/ui/bookmarks/bookmark_utils.cc
index b630dd7..9448f5a 100644
--- a/chrome/browser/ui/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_utils.cc
@@ -8,11 +8,11 @@
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e56c71d..f307442 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -85,6 +85,7 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
 #include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
@@ -96,6 +97,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/browser_iterator.h"
+#include "chrome/browser/ui/browser_language_state_observer.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_tab_contents.h"
@@ -119,6 +121,7 @@
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/search/search_delegate.h"
 #include "chrome/browser/ui/search/search_model.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/status_bubble.h"
@@ -142,7 +145,6 @@
 #include "chrome/common/custom_handlers/protocol_handler.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/net/url_fixer_upper.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/profiling.h"
@@ -344,7 +346,8 @@
           this, g_browser_process->profile_manager())),
       window_has_shown_(false),
       chrome_updater_factory_(this),
-      weak_factory_(this) {
+      weak_factory_(this),
+      language_state_observer_(new BrowserLanguageStateObserver(this)) {
   // If this causes a crash then a window is being opened using a profile type
   // that is disallowed by policy. The crash prevents the disabled window type
   // from opening at all, but the path that triggered it should be fixed.
@@ -1024,6 +1027,7 @@
 void Browser::TabDeactivated(WebContents* contents) {
   fullscreen_controller_->OnTabDeactivated(contents);
   search_delegate_->OnTabDeactivated(contents);
+  SearchTabHelper::FromWebContents(contents)->OnTabDeactivated();
 
   // Save what the user's currently typing, so it can be restored when we
   // switch back to this tab.
@@ -1065,8 +1069,8 @@
   // Propagate the profile to the location bar.
   UpdateToolbar((reason & CHANGE_REASON_REPLACED) == 0);
 
-  // Propagate tab state to toolbar, tab-strip, etc.
-  UpdateSearchState(new_contents);
+  if (chrome::IsInstantExtendedAPIEnabled())
+    search_delegate_->OnTabActivated(new_contents);
 
   // Update reload/stop state.
   command_controller_->LoadingStateChanged(new_contents->IsLoading(), true);
@@ -1098,12 +1102,13 @@
                                             tab_strip_model_->active_index());
   }
 
-  // This needs to be called after UpdateSearchState().
+  // This needs to be called after notifying SearchDelegate.
   if (instant_controller_)
     instant_controller_->ActiveTabChanged();
 
   autofill::TabAutofillManagerDelegate::FromWebContents(new_contents)->
       TabActivated(reason);
+  SearchTabHelper::FromWebContents(new_contents)->OnTabActivated();
 }
 
 void Browser::TabMoved(WebContents* contents,
@@ -1802,7 +1807,8 @@
 
       // Close any tabs from the unloaded extension, unless it's terminated,
       // in which case let the sad tabs remain.
-      if (extension_info->reason != extension_misc::UNLOAD_REASON_TERMINATE) {
+      if (extension_info->reason !=
+          extensions::UnloadedExtensionInfo::REASON_TERMINATE) {
         const Extension* extension = extension_info->extension;
         // Iterate backwards as we may remove items while iterating.
         for (int i = tab_strip_model_->count() - 1; i >= 0; --i) {
@@ -1878,11 +1884,6 @@
       tab_strip_model_->GetActiveWebContents() : NULL);
 }
 
-void Browser::UpdateSearchState(WebContents* contents) {
-  if (chrome::IsInstantExtendedAPIEnabled())
-    search_delegate_->OnTabActivated(contents);
-}
-
 void Browser::ScheduleUIUpdate(const WebContents* source,
                                unsigned changed_flags) {
   if (!source)
@@ -2088,6 +2089,10 @@
   CoreTabHelper::FromWebContents(web_contents)->set_delegate(delegate);
   SearchEngineTabHelper::FromWebContents(web_contents)->set_delegate(delegate);
   ZoomController::FromWebContents(web_contents)->set_observer(delegate);
+  TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(web_contents);
+  translate_tab_helper->language_state().set_observer(
+      delegate ? delegate->language_state_observer_.get() : NULL);
 }
 
 void Browser::CloseFrame() {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 0b9c93f..7f85135 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -46,6 +46,7 @@
 
 class BrowserContentSettingBubbleModelDelegate;
 class BrowserInstantController;
+class BrowserLanguageStateObserver;
 class BrowserSyncedWindowDelegate;
 class BrowserToolbarModelDelegate;
 class BrowserTabRestoreServiceDelegate;
@@ -710,9 +711,6 @@
   // well.
   void UpdateToolbar(bool should_restore_state);
 
-  // Updates the browser's search model with the tab's search model.
-  void UpdateSearchState(content::WebContents* contents);
-
   // Does one or both of the following for each bit in |changed_flags|:
   // . If the update should be processed immediately, it is.
   // . If the update should processed asynchronously (to avoid lots of ui
@@ -938,6 +936,8 @@
   // The following factory is used to close the frame at a later time.
   base::WeakPtrFactory<Browser> weak_factory_;
 
+  scoped_ptr<BrowserLanguageStateObserver> language_state_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(Browser);
 };
 
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index c4f0a0e..686816e 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -70,6 +70,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_view.h"
+#include "content/public/common/frame_navigate_params.h"
 #include "content/public/common/page_transition_types.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/url_constants.h"
@@ -471,6 +472,9 @@
   GURL url(test_server()->GetURL("empty.html"));
   ui_test_utils::NavigateToURL(browser(), url);
 
+  // TODO(creis): Test this with a setInterval loop of alert dialogs to ensure
+  // that we can navigate away even if the renderer tries to synchronously
+  // create more.  See http://crbug.com/312490.
   WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
   contents->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
       string16(),
@@ -509,6 +513,28 @@
                                   ASCIIToUTF16("onbeforeunload=null;"));
 }
 
+class RedirectObserver : public content::WebContentsObserver {
+ public:
+  explicit RedirectObserver(content::WebContents* web_contents)
+      : WebContentsObserver(web_contents) {
+  }
+
+  virtual void DidNavigateAnyFrame(
+      const content::LoadCommittedDetails& details,
+      const content::FrameNavigateParams& params) OVERRIDE {
+    params_ = params;
+  }
+
+  const content::FrameNavigateParams& params() const {
+    return params_;
+  }
+
+ private:
+  content::FrameNavigateParams params_;
+
+  DISALLOW_COPY_AND_ASSIGN(RedirectObserver);
+};
+
 // Ensure that a transferred cross-process navigation does not generate
 // DidStopLoading events until the navigation commits.  If it did, then
 // ui_test_utils::NavigateToURL would proceed before the URL had committed.
@@ -531,17 +557,29 @@
   ui_test_utils::NavigateToURL(browser(), init_url);
 
   // Navigate to a same-site page that redirects, causing a transfer.
+  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  RedirectObserver redirect_observer(contents);
   GURL dest_url(https_test_server.GetURL("files/title2.html"));
   GURL redirect_url(test_server()->GetURL("server-redirect?" +
       dest_url.spec()));
   ui_test_utils::NavigateToURL(browser(), redirect_url);
 
   // We should immediately see the new committed entry.
-  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_FALSE(contents->GetController().GetPendingEntry());
   EXPECT_EQ(dest_url,
             contents->GetController().GetLastCommittedEntry()->GetURL());
 
+  // We should keep track of the original request URL, redirect chain, and
+  // page transition type during a transfer, since these are necessary for
+  // history autocomplete to work.
+  EXPECT_EQ(redirect_url, contents->GetController().GetLastCommittedEntry()->
+                GetOriginalRequestURL());
+  EXPECT_EQ(2U, redirect_observer.params().redirects.size());
+  EXPECT_EQ(redirect_url, redirect_observer.params().redirects.at(0));
+  EXPECT_EQ(dest_url, redirect_observer.params().redirects.at(1));
+  EXPECT_TRUE(PageTransitionCoreTypeIs(redirect_observer.params().transition,
+                                       content::PAGE_TRANSITION_TYPED));
+
   // Restore previous browser client.
   SetBrowserClientForTesting(old_client);
 }
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index ff9cdef..b44e8e0 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -536,6 +536,9 @@
     case IDC_PRINT_TO_DESTINATION:
       PrintToDestination(browser_);
       break;
+    case IDC_TRANSLATE_PAGE:
+      Translate(browser_);
+      break;
     case IDC_ENCODING_AUTO_DETECT:
       browser_->ToggleEncodingAutoDetect();
       break;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 0e5b03d..5565f1c 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/sessions/tab_restore_service.h"
 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/ui/bookmarks/bookmark_prompt_controller.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #include "chrome/browser/ui/browser.h"
@@ -49,6 +50,7 @@
 #include "chrome/browser/ui/status_bubble.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -287,7 +289,8 @@
   } else {
     content::RecordAction(UserMetricsAction("NewWindow"));
     SessionService* session_service =
-        SessionServiceFactory::GetForProfile(profile->GetOriginalProfile());
+        SessionServiceFactory::GetForProfileForSessionRestore(
+            profile->GetOriginalProfile());
     if (!session_service ||
         !session_service->RestoreIfNecessary(std::vector<GURL>())) {
       OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type);
@@ -679,6 +682,26 @@
              CanBookmarkCurrentPage(browser);
 }
 
+void Translate(Browser* browser) {
+  if (!browser->window()->IsActive())
+    return;
+
+  WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(web_contents);
+
+  TranslateBubbleModel::ViewState view_state =
+      TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE;
+  if (translate_tab_helper) {
+    if (translate_tab_helper->language_state().translation_pending())
+      view_state = TranslateBubbleModel::VIEW_STATE_TRANSLATING;
+    else if (translate_tab_helper->language_state().IsPageTranslated())
+      view_state = TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE;
+  }
+  browser->window()->ShowTranslateBubble(web_contents, view_state);
+}
+
 void TogglePagePinnedToStartScreen(Browser* browser) {
 #if defined(OS_WIN)
   MetroPinTabHelper::FromWebContents(
diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h
index 7c6863a..9976833 100644
--- a/chrome/browser/ui/browser_commands.h
+++ b/chrome/browser/ui/browser_commands.h
@@ -97,6 +97,7 @@
 bool CanBookmarkCurrentPage(const Browser* browser);
 void BookmarkAllTabs(Browser* browser);
 bool CanBookmarkAllTabs(const Browser* browser);
+void Translate(Browser* browser);
 void TogglePagePinnedToStartScreen(Browser* browser);
 void SavePage(Browser* browser);
 bool CanSavePage(const Browser* browser);
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 4a6f59d..ecf2a35 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -52,6 +52,10 @@
 // TODO(suzhe): http://crbug.com/60973
 #define MAYBE_FocusTraversal DISABLED_FocusTraversal
 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
+#elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): http://crbug.com/163931
+#define MAYBE_FocusTraversal DISABLED_FocusTraversal
+#define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
 #elif defined(OS_WIN) || defined(OS_CHROMEOS)
 // http://crbug.com/109770 and http://crbug.com/62544
 #define MAYBE_FocusTraversal FocusTraversal
@@ -414,8 +418,15 @@
   EXPECT_TRUE(focused_browser->window()->IsActive());
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): http://crbug.com/163931
+#define MAYBE_LocationBarLockFocus DISABLED_LocationBarLockFocus
+#else
+#define MAYBE_LocationBarLockFocus LocationBarLockFocus
+#endif
+
 // Page cannot steal focus when focus is on location bar.
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_LocationBarLockFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
@@ -800,8 +811,15 @@
   EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): http://crbug.com/163931
+#define MAYBE_FocusOnReload DISABLED_FocusOnReload
+#else
+#define MAYBE_FocusOnReload FocusOnReload
+#endif
+
 // Tests that focus goes where expected when using reload.
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusOnReload) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
@@ -920,7 +938,14 @@
   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnNavigate) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): http://crbug.com/163931
+#define MAYBE_FocusOnNavigate DISABLED_FocusOnNavigate
+#else
+#define MAYBE_FocusOnNavigate FocusOnNavigate
+#endif
+
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusOnNavigate) {
   // Needed on Mac.
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
   // Load the NTP.
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index 25bb416..c81a763 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -156,38 +156,6 @@
   instant_.TabDeactivated(contents);
 }
 
-void BrowserInstantController::OpenURL(
-    const GURL& url,
-    content::PageTransition transition,
-    WindowOpenDisposition disposition) {
-  browser_->OpenURL(content::OpenURLParams(url,
-                                           content::Referrer(),
-                                           disposition,
-                                           transition,
-                                           false));
-}
-
-void BrowserInstantController::PasteIntoOmnibox(const string16& text) {
-  OmniboxView* omnibox_view = browser_->window()->GetLocationBar()->
-      GetLocationEntry();
-  // The first case is for right click to paste, where the text is retrieved
-  // from the clipboard already sanitized. The second case is needed to handle
-  // drag-and-drop value and it has to be sanitazed before setting it into the
-  // omnibox.
-  string16 text_to_paste = text.empty() ?
-      omnibox_view->GetClipboardText() :
-      omnibox_view->SanitizeTextForPaste(text);
-
-  if (!text_to_paste.empty()) {
-    if (!omnibox_view->model()->has_focus())
-      omnibox_view->SetFocus();
-    omnibox_view->OnBeforePossibleChange();
-    omnibox_view->model()->on_paste();
-    omnibox_view->SetUserText(text_to_paste);
-    omnibox_view->OnAfterPossibleChange();
-  }
-}
-
 void BrowserInstantController::SetOmniboxBounds(const gfx::Rect& bounds) {
   instant_.SetOmniboxBounds(bounds);
 }
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index 78f08ec..ef858e6 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/search/instant_controller.h"
 #include "chrome/browser/ui/search/instant_unload_handler.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
-#include "ui/base/window_open_disposition.h"
 
 class Browser;
 struct InstantSuggestion;
@@ -65,16 +64,6 @@
   // Invoked by |browser_| when the active tab is about to be deactivated.
   void TabDeactivated(content::WebContents* contents);
 
-  // Invoked by the InstantController when it wants to open a URL.
-  void OpenURL(const GURL& url,
-               content::PageTransition transition,
-               WindowOpenDisposition disposition);
-
-  // Invoked by |instant_| to paste the |text| (or clipboard content if text is
-  // empty) into the omnibox. It will set focus to the omnibox if the omnibox is
-  // not focused.
-  void PasteIntoOmnibox(const string16& text);
-
   // Sets the stored omnibox bounds.
   void SetOmniboxBounds(const gfx::Rect& bounds);
 
diff --git a/chrome/browser/ui/browser_language_state_observer.cc b/chrome/browser/ui/browser_language_state_observer.cc
new file mode 100644
index 0000000..d2fb40b
--- /dev/null
+++ b/chrome/browser/ui/browser_language_state_observer.cc
@@ -0,0 +1,22 @@
+// Copyright 2013 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/browser_language_state_observer.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+
+BrowserLanguageStateObserver::BrowserLanguageStateObserver(Browser* browser)
+    : browser_(browser) {
+}
+
+BrowserLanguageStateObserver::~BrowserLanguageStateObserver() {
+}
+
+void BrowserLanguageStateObserver::OnTranslateEnabledChanged(
+    content::WebContents* source) {
+  if (source == browser_->tab_strip_model()->GetActiveWebContents())
+    browser_->window()->UpdateToolbar(source);
+}
diff --git a/chrome/browser/ui/browser_language_state_observer.h b/chrome/browser/ui/browser_language_state_observer.h
new file mode 100644
index 0000000..83abf69
--- /dev/null
+++ b/chrome/browser/ui/browser_language_state_observer.h
@@ -0,0 +1,33 @@
+// Copyright 2013 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_BROWSER_LANGUAGE_STATE_OBSERVER_H_
+#define CHROME_BROWSER_UI_BROWSER_LANGUAGE_STATE_OBSERVER_H_
+
+#include "chrome/browser/tab_contents/language_state_observer.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+class Browser;
+
+// Implementation of LanguageStateObserver for Browser. This observes the state
+// if Translate is enabled or not, and updates toolbar in response to changes in
+// state of translate.
+class BrowserLanguageStateObserver : public LanguageStateObserver {
+ public:
+  explicit BrowserLanguageStateObserver(Browser* browser);
+
+  virtual ~BrowserLanguageStateObserver();
+
+  // Overridden from LanguageState::Observer
+  virtual void OnTranslateEnabledChanged(content::WebContents* source) OVERRIDE;
+
+ private:
+  Browser* browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserLanguageStateObserver);
+};
+
+#endif  // CHROME_BROWSER_UI_BROWSER_LANGUAGE_STATE_OBSERVER_H_
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 7726b99..1693c91 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -246,6 +246,7 @@
                        chrome::NavigateParams* params) {
   NavigationController::LoadURLParams load_url_params(url);
   load_url_params.referrer = params->referrer;
+  load_url_params.redirect_chain = params->redirect_chain;
   load_url_params.transition_type = params->transition;
   load_url_params.extra_headers = params->extra_headers;
   load_url_params.should_replace_current_entry =
@@ -456,6 +457,7 @@
 void FillNavigateParamsFromOpenURLParams(chrome::NavigateParams* nav_params,
                                          const content::OpenURLParams& params) {
   nav_params->referrer = params.referrer;
+  nav_params->redirect_chain = params.redirect_chain;
   nav_params->extra_headers = params.extra_headers;
   nav_params->disposition = params.disposition;
   nav_params->is_renderer_initiated = params.is_renderer_initiated;
@@ -682,7 +684,17 @@
 #if defined(ENABLE_ENHANCED_BOOKMARKS)
        url.host() == chrome::kChromeUIEnhancedBookmarksHost ||
 #endif
-       url.host() == chrome::kChromeUIUberHost)) {
+       url.host() == chrome::kChromeUIUberHost ||
+       url.host() == chrome::kChromeUIThumbnailHost ||
+       url.host() == chrome::kChromeUIThumbnailHost2 ||
+       url.host() == chrome::kChromeUIThumbnailListHost)) {
+    return false;
+  }
+
+  if (url.scheme() == chrome::kChromeSearchScheme &&
+      (url.host() == chrome::kChromeUIThumbnailHost ||
+       url.host() == chrome::kChromeUIThumbnailHost2 ||
+       url.host() == chrome::kChromeUIThumbnailListHost)) {
     return false;
   }
 
diff --git a/chrome/browser/ui/browser_navigator.h b/chrome/browser/ui/browser_navigator.h
index 93e5597..12f0a54 100644
--- a/chrome/browser/ui/browser_navigator.h
+++ b/chrome/browser/ui/browser_navigator.h
@@ -65,6 +65,10 @@
   GURL url;
   content::Referrer referrer;
 
+  // Any redirect URLs that occurred for this navigation before |url|.
+  // Usually empty.
+  std::vector<GURL> redirect_chain;
+
   // Indicates whether this navigation will be sent using POST.
   // The POST method is limited support for basic POST data by leveraging
   // NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST.
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 7811ace..f9c66db 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
 #include "chrome/common/content_settings_types.h"
 #include "ui/base/base_window.h"
 #include "ui/base/window_open_disposition.h"
@@ -219,6 +220,11 @@
   // TODO(yosin): Make ShowBookmarkPrompt pure virtual.
   virtual void ShowBookmarkPrompt() {}
 
+  // Shows the translate bubble.
+  virtual void ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) = 0;
+
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
   enum OneClickSigninBubbleType {
     ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE,
@@ -239,7 +245,7 @@
       const string16& email,
       const string16& error_message,
       const StartSyncCallback& start_sync_callback) = 0;
-  #endif
+#endif
 
   // Whether or not the shelf view is visible.
   virtual bool IsDownloadShelfVisible() const = 0;
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 1fe3475..1e7412d 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -64,6 +64,45 @@
   ShowSingletonTabOverwritingNTP(browser, params);
 }
 
+// Shows either the help app or the appropriate help page for |source|. If
+// |browser| is NULL and the help page is used (vs the app), the help page is
+// shown in the last active browser. If there is no such browser, a new browser
+// is created.
+void ShowHelpImpl(Browser* browser,
+                  Profile* profile,
+                  HostDesktopType host_desktop_type,
+                  HelpSource source) {
+  content::RecordAction(UserMetricsAction("ShowHelpTab"));
+#if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(chromeos::switches::kDisableGeniusApp)) {
+    Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+    const extensions::Extension* extension = profile->GetExtensionService()->
+        GetInstalledExtension(genius_app::kGeniusAppId);
+    OpenApplication(
+        AppLaunchParams(profile, extension, 0, host_desktop_type));
+    return;
+  }
+#endif
+  GURL url;
+  switch (source) {
+    case HELP_SOURCE_KEYBOARD:
+      url = GURL(kChromeHelpViaKeyboardURL);
+      break;
+    case HELP_SOURCE_MENU:
+      url = GURL(kChromeHelpViaMenuURL);
+      break;
+    case HELP_SOURCE_WEBUI:
+      url = GURL(kChromeHelpViaWebUIURL);
+      break;
+    default:
+      NOTREACHED() << "Unhandled help source " << source;
+  }
+  if (!browser)
+    browser = chrome::FindOrCreateTabbedBrowser(profile, host_desktop_type);
+  ShowSingletonTab(browser, url);
+}
+
 }  // namespace
 
 void ShowBookmarkManager(Browser* browser) {
@@ -134,33 +173,14 @@
 }
 
 void ShowHelp(Browser* browser, HelpSource source) {
-  content::RecordAction(UserMetricsAction("ShowHelpTab"));
-#if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(chromeos::switches::kDisableGeniusApp)) {
-    Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-    const extensions::Extension* extension = profile->GetExtensionService()->
-        GetInstalledExtension(genius_app::kGeniusAppId);
-    OpenApplication(
-        AppLaunchParams(profile, extension, 0, browser->host_desktop_type()));
-    return;
-  }
-#endif
-  GURL url;
-  switch (source) {
-    case HELP_SOURCE_KEYBOARD:
-      url = GURL(kChromeHelpViaKeyboardURL);
-      break;
-    case HELP_SOURCE_MENU:
-      url = GURL(kChromeHelpViaMenuURL);
-      break;
-    case HELP_SOURCE_WEBUI:
-      url = GURL(kChromeHelpViaWebUIURL);
-      break;
-    default:
-      NOTREACHED() << "Unhandled help source " << source;
-  }
-  ShowSingletonTab(browser, url);
+  ShowHelpImpl(browser, browser->profile(), browser->host_desktop_type(),
+      source);
+}
+
+void ShowHelpForProfile(Profile* profile,
+                        HostDesktopType host_desktop_type,
+                        HelpSource source) {
+  ShowHelpImpl(NULL, profile, host_desktop_type, source);
 }
 
 void ShowPolicy(Browser* browser) {
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h
index 792fb6d..9a8c0ab 100644
--- a/chrome/browser/ui/chrome_pages.h
+++ b/chrome/browser/ui/chrome_pages.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "chrome/browser/signin/signin_promo.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/common/content_settings_types.h"
 
 class Browser;
@@ -39,11 +40,17 @@
 void ShowExtensions(Browser* browser,
                     const std::string& extension_to_highlight);
 void ShowConflicts(Browser* browser);
+
+// ShowFeedbackPage() uses |browser| to determine the URL of the current tab.
+// |browser| should be NULL if there are no currently open browser windows.
 void ShowFeedbackPage(Browser* browser,
                       const std::string& description_template,
                       const std::string& category_tag);
 
 void ShowHelp(Browser* browser, HelpSource source);
+void ShowHelpForProfile(Profile* profile,
+                        HostDesktopType host_desktop_type,
+                        HelpSource source);
 void ShowPolicy(Browser* browser);
 void ShowSlow(Browser* browser);
 
diff --git a/chrome/browser/ui/cocoa/DEPS b/chrome/browser/ui/cocoa/DEPS
index c00f313..2fedb51 100644
--- a/chrome/browser/ui/cocoa/DEPS
+++ b/chrome/browser/ui/cocoa/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+third_party/apple_sample_code",  # Apple code ImageAndTextCell.
   "+third_party/molokocacao",  # For NSBezierPath additions.
   "+third_party/ocmock",  # For unit tests.
 ]
diff --git a/chrome/browser/ui/cocoa/animatable_image.mm b/chrome/browser/ui/cocoa/animatable_image.mm
index d2fd2da..9860e24 100644
--- a/chrome/browser/ui/cocoa/animatable_image.mm
+++ b/chrome/browser/ui/cocoa/animatable_image.mm
@@ -5,14 +5,8 @@
 #import "chrome/browser/ui/cocoa/animatable_image.h"
 
 #include "base/logging.h"
-#import "base/mac/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
 
-@interface AnimatableImage (Private)
-- (void)setLayerContents:(CALayer*)layer;
-@end
-
 @implementation AnimatableImage
 
 @synthesize startFrame = startFrame_;
@@ -53,7 +47,7 @@
 
   // Create the layer that will be animated.
   CALayer* layer = [CALayer layer];
-  [self setLayerContents:layer];
+  [layer setContents:image_.get()];
   [layer setAnchorPoint:CGPointMake(0, 1)];
   [layer setFrame:[self startFrame]];
   [layer setNeedsDisplayOnBoundsChange:YES];
@@ -127,15 +121,6 @@
   [CATransaction commit];
 }
 
-// Sets the layer contents by converting the NSImage to a CGImageRef.  This will
-// rasterize PDF resources.
-- (void)setLayerContents:(CALayer*)layer {
-  base::ScopedCFTypeRef<CGImageRef> image(
-      base::mac::CopyNSImageToCGImage(image_.get()));
-  // Create the layer that will be animated.
-  [layer setContents:(id)image.get()];
-}
-
 // CAAnimation delegate method called when the animation is complete.
 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag {
   // Close the window, releasing self.
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
index 78ce04b..0b7edaf 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
@@ -78,6 +78,7 @@
       const base::string16& text) OVERRIDE;
   virtual void ActivateInput(const DetailInput& input) OVERRIDE;
   virtual gfx::Size GetSize() const OVERRIDE;
+  virtual content::WebContents* GetSignInWebContents() OVERRIDE;
 
   // ConstrainedWindowMacDelegate implementation:
   virtual void OnConstrainedWindowClosed(
@@ -146,6 +147,7 @@
            forInput:(const autofill::DetailInput&)input;
 - (void)getInputs:(autofill::DetailOutputMap*)outputs
        forSection:(autofill::DialogSection)section;
+- (NSString*)getCvc;
 - (BOOL)saveDetailsLocally;
 - (content::NavigationController*)showSignIn;
 - (void)hideSignIn;
@@ -164,6 +166,7 @@
 - (void)setTextContents:(NSString*)text
  ofSuggestionForSection:(autofill::DialogSection)section;
 - (void)activateFieldForInput:(const autofill::DetailInput&)input;
+- (content::WebContents*)getSignInWebContents;
 
 @end
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 763f5b3..32076a8 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -33,7 +33,7 @@
 
 // Height of all decorations & paddings on main dialog together.
 const CGFloat kDecorationHeight = kAccountChooserHeight +
-                                  autofill::kDetailTopPadding +
+                                  autofill::kDetailVerticalPadding +
                                   chrome_style::kClientBottomPadding +
                                   chrome_style::kTitleTopPadding;
 
@@ -131,7 +131,7 @@
 }
 
 string16 AutofillDialogCocoa::GetCvc() {
-  return string16();
+  return base::SysNSStringToUTF16([sheet_delegate_ getCvc]);
 }
 
 bool AutofillDialogCocoa::HitTestInput(const DetailInput& input,
@@ -212,6 +212,10 @@
   return gfx::Size(NSSizeToCGSize([[sheet_delegate_ window] frame].size));
 }
 
+content::WebContents* AutofillDialogCocoa::GetSignInWebContents() {
+  return [sheet_delegate_ getSignInWebContents];
+}
+
 void AutofillDialogCocoa::OnConstrainedWindowClosed(
     ConstrainedWindowMac* window) {
   constrained_window_.reset();
@@ -393,7 +397,7 @@
   NSSize contentSize;
 
   // Overall size is determined by either main container or sign in view.
-  if (![[mainContainer_ view] isHidden])
+  if ([[signInContainer_ view] isHidden])
     contentSize = [mainContainer_ preferredSize];
   else
     contentSize = [signInContainer_ preferredSize];
@@ -413,7 +417,8 @@
     // equivalent to the height of the header. Clarify with UX what the final
     // padding will be.
     if (height != 0.0) {
-      size.height = height + headerSize.height + autofill::kDetailTopPadding;
+      size.height =
+          height + headerSize.height + autofill::kDetailVerticalPadding;
     }
   }
 
@@ -436,7 +441,7 @@
   NSDivideRect(clientRect, &headerRect, &mainRect,
                kAccountChooserHeight, NSMinYEdge);
   NSDivideRect(mainRect, &dummyRect, &mainRect,
-               autofill::kDetailTopPadding, NSMinYEdge);
+               autofill::kDetailVerticalPadding, NSMinYEdge);
   headerRect = NSInsetRect(
       headerRect, chrome_style::kHorizontalPadding, 0);
   NSDivideRect(headerRect, &titleRect, &headerRect,
@@ -473,6 +478,7 @@
 
   NSRect frameRect = [[self window] frameRectForContentRect:contentRect];
   [[self window] setFrame:frameRect display:YES];
+  [[self window] recalculateKeyViewLoop];
 }
 
 - (IBAction)accept:(id)sender {
@@ -523,18 +529,15 @@
     NSView* loadingShieldView = [loadingShieldTextField_ superview];
     [loadingShieldTextField_ setStringValue:newLoadingMessage];
     [loadingShieldTextField_ sizeToFit];
-    [loadingShieldView setHidden:[newLoadingMessage length] == 0];
 
-    // For the duration of the loading shield, it becomes first responder.
+    BOOL showShield = ([newLoadingMessage length] != 0);
+
+    // For the duration of the loading shield, hide the main contents.
     // This prevents the currently focused text field "shining through".
-    if (![loadingShieldView isHidden]) {
-      [loadingShieldView setNextResponder:
-          [[loadingShieldView window] firstResponder]];
-      [[loadingShieldView window] makeFirstResponder:loadingShieldView];
-    } else {
-      [[loadingShieldView window] makeFirstResponder:
-          [loadingShieldView nextResponder]];
-    }
+    // No need to remember previous state, because the loading shield
+    // always flows through to the main container.
+    [[mainContainer_ view] setHidden:showShield];
+    [loadingShieldView setHidden:!showShield];
     [self requestRelayout];
   }
 }
@@ -569,6 +572,16 @@
   [[mainContainer_ sectionForId:section] getInputs:output];
 }
 
+- (NSString*)getCvc {
+  autofill::DialogSection section = autofill::SECTION_CC;
+  NSString* value = [[mainContainer_ sectionForId:section] suggestionText];
+  if (!value) {
+    section = autofill::SECTION_CC_BILLING;
+    value = [[mainContainer_ sectionForId:section] suggestionText];
+  }
+  return value;
+}
+
 - (BOOL)saveDetailsLocally {
   return [mainContainer_ saveDetailsLocally];
 }
@@ -618,4 +631,8 @@
   }
 }
 
+- (content::WebContents*)getSignInWebContents {
+  return [signInContainer_ webContents];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
index 546380e..4e54fae 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
@@ -20,16 +20,14 @@
 
 // The space between the edges of a notification bar and the text within (in
 // pixels).
-const int kNotificationPadding = 14;
+const int kNotificationPadding = 17;
 
 // Vertical spacing between legal text and details section.
 const int kVerticalSpacing = 8;
 
-// Padding between top bar and details section.
-const int kDetailTopPadding = 20;
-
-// Padding between the bottom of the details section and the button strip.
-const int kDetailBottomPadding = 30;
+// Padding between top bar and details section, as well as between the bottom of
+// the details section and the button strip.
+const int kDetailVerticalPadding = 10;
 
 }  // autofill
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
index b2e72c7..83accbb 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
@@ -30,6 +30,7 @@
  @private
   base::scoped_nsobject<GTMWidthBasedTweaker> buttonContainer_;
   base::scoped_nsobject<NSButton> saveInChromeCheckbox_;
+  base::scoped_nsobject<NSImageView> saveInChromeTooltip_;
   base::scoped_nsobject<AutofillDetailsContainer> detailsContainer_;
   base::scoped_nsobject<HyperlinkTextView> legalDocumentsView_;
   base::scoped_nsobject<AutofillNotificationContainer> notificationContainer_;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
index 76a3b47..457c053 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
@@ -18,13 +18,14 @@
 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
 #include "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/range/range.h"
 
 @interface AutofillMainContainer (Private)
-- (void)buildWindowButtonsForFrame:(NSRect)frame;
+- (void)buildWindowButtons;
 - (void)layoutButtons;
 - (NSSize)preferredLegalDocumentSizeForWidth:(CGFloat)width;
 @end
@@ -42,7 +43,7 @@
 }
 
 - (void)loadView {
-  [self buildWindowButtonsForFrame:NSZeroRect];
+  [self buildWindowButtons];
 
   base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
   [view setAutoresizesSubviews:YES];
@@ -60,6 +61,15 @@
   [saveInChromeCheckbox_ sizeToFit];
   [[self view] addSubview:saveInChromeCheckbox_];
 
+  saveInChromeTooltip_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
+  [saveInChromeTooltip_ setImage:
+      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+          IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage()];
+  [saveInChromeTooltip_ setToolTip:
+      base::SysUTF16ToNSString(delegate_->SaveLocallyTooltip())];
+  [saveInChromeTooltip_ setFrameSize:[[saveInChromeTooltip_ image] size]];
+  [[self view] addSubview:saveInChromeTooltip_];
+
   detailsContainer_.reset(
       [[AutofillDetailsContainer alloc] initWithDelegate:delegate_]);
   NSSize frameSize = [[detailsContainer_ view] frame].size;
@@ -105,7 +115,7 @@
 
   NSSize size = NSMakeSize(std::max(buttonSize.width, detailsSize.width),
                            buttonSize.height + detailsSize.height);
-  size.height += autofill::kDetailBottomPadding;
+  size.height += 2 * autofill::kDetailVerticalPadding;
 
   if (![legalDocumentsView_ isHidden]) {
     NSSize legalDocumentSize =
@@ -126,19 +136,23 @@
   if (![legalDocumentsView_ isHidden]) {
     [legalDocumentsView_ setFrameSize:
         [self preferredLegalDocumentSizeForWidth:NSWidth(bounds)]];
-    currentY = NSMaxY([legalDocumentsView_ frame]) +
-        autofill::kVerticalSpacing;
+    currentY = NSMaxY([legalDocumentsView_ frame]) + autofill::kVerticalSpacing;
   }
 
   NSRect buttonFrame = [buttonContainer_ frame];
   buttonFrame.origin.y = currentY;
   [buttonContainer_ setFrameOrigin:buttonFrame.origin];
+  currentY = NSMaxY(buttonFrame) + autofill::kDetailVerticalPadding;
 
   NSRect checkboxFrame = [saveInChromeCheckbox_ frame];
   [saveInChromeCheckbox_ setFrameOrigin:
       NSMakePoint(chrome_style::kHorizontalPadding,
                   NSMidY(buttonFrame) - NSHeight(checkboxFrame) / 2.0)];
-  currentY = NSMaxY(buttonFrame) + autofill::kDetailBottomPadding;
+
+  NSRect tooltipFrame = [saveInChromeTooltip_ frame];
+  [saveInChromeTooltip_ setFrameOrigin:
+      NSMakePoint(NSMaxX([saveInChromeCheckbox_ frame]) + autofill::kButtonGap,
+                  NSMidY(buttonFrame) - (NSHeight(tooltipFrame) / 2.0))];
 
   NSRect notificationFrame = NSZeroRect;
   notificationFrame.size = [notificationContainer_ preferredSizeForWidth:
@@ -147,19 +161,20 @@
   // Buttons/checkbox/legal take up lower part of view, notifications the
   // upper part. Adjust the detailsContainer to take up the remainder.
   CGFloat remainingHeight =
-      NSHeight(bounds) - currentY - NSHeight(notificationFrame);
+      NSHeight(bounds) - currentY - NSHeight(notificationFrame) -
+      autofill::kDetailVerticalPadding;
   NSRect containerFrame =
       NSMakeRect(0, currentY, NSWidth(bounds), remainingHeight);
   [[detailsContainer_ view] setFrame:containerFrame];
   [detailsContainer_ performLayout];
 
   notificationFrame.origin =
-      NSMakePoint(0, NSMaxY(containerFrame) + autofill::kDetailTopPadding);
+      NSMakePoint(0, NSMaxY(containerFrame) + autofill::kDetailVerticalPadding);
   [[notificationContainer_ view] setFrame:notificationFrame];
   [notificationContainer_ performLayout];
 }
 
-- (void)buildWindowButtonsForFrame:(NSRect)frame {
+- (void)buildWindowButtons {
   if (buttonContainer_.get())
     return;
 
@@ -188,11 +203,9 @@
   [button sizeToFit];
   [buttonContainer_ addSubview:button];
 
-  frame = NSMakeRect(
-      NSWidth(frame) - NSMaxX([button frame]), 0,
+  NSRect frame = NSMakeRect(
+      -NSMaxX([button frame]) - chrome_style::kHorizontalPadding, 0,
       NSMaxX([button frame]), NSHeight([button frame]));
-  frame = NSOffsetRect(frame, -chrome_style::kHorizontalPadding, 0);
-
   [buttonContainer_ setFrame:frame];
 }
 
@@ -285,6 +298,7 @@
 
 - (void)updateSaveInChrome {
   [saveInChromeCheckbox_ setHidden:!delegate_->ShouldOfferToSaveInChrome()];
+  [saveInChromeTooltip_ setHidden:[saveInChromeCheckbox_ isHidden]];
   [saveInChromeCheckbox_ setState:
       (delegate_->ShouldSaveInChrome() ? NSOnState : NSOffState)];
 }
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
index b24900e0..d49146c 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
@@ -40,10 +40,11 @@
   bool hasTextView = false;
   bool hasDetailsContainer = false;
   bool hasCheckbox = false;
+  bool hasCheckboxTooltip = false;
   int hasNotificationContainer = false;
 
   // Should have account chooser, button strip, and details section.
-  EXPECT_EQ(5U, [[[container_ view] subviews] count]);
+  EXPECT_EQ(6U, [[[container_ view] subviews] count]);
   for (NSView* view in [[container_ view] subviews]) {
     NSArray* subviews = [view subviews];
     if ([view isKindOfClass:[NSScrollView class]]) {
@@ -54,6 +55,8 @@
       EXPECT_TRUE(
           [[subviews objectAtIndex:1] isKindOfClass:[NSButton class]]);
       hasButtons = true;
+    } else if ([view isKindOfClass:[NSImageView class]]) {
+      hasCheckboxTooltip = true;
     } else if ([view isKindOfClass:[NSTextView class]]) {
       hasTextView = true;
     } else if ([view isKindOfClass:[NSButton class]] &&
@@ -71,6 +74,7 @@
   EXPECT_TRUE(hasDetailsContainer);
   EXPECT_TRUE(hasNotificationContainer);
   EXPECT_TRUE(hasCheckbox);
+  EXPECT_TRUE(hasCheckboxTooltip);
 }
 
 // Ensure the default state of the "Save in Chrome" checkbox is controlled by
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h
index deaff2a..171c452 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h
@@ -10,8 +10,6 @@
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
 
-@class AutofillNotificationView;
-
 // Contains a single notification for requestAutocomplete dialog.
 @interface AutofillNotificationController : NSViewController<AutofillLayout> {
  @private
@@ -20,9 +18,6 @@
 
   // Optional checkbox.
   base::scoped_nsobject<NSButton> checkbox_;
-
-  // Size of a checkbox without title.
-  NSSize checkboxSizeWithoutTitle_;
 }
 
 @property(nonatomic, readonly) NSTextField* textfield;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
index 1ec4867..4c74146 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
@@ -81,9 +81,6 @@
 
     checkbox_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
     [checkbox_ setButtonType:NSSwitchButton];
-    [checkbox_ setTitle:@""];
-    [checkbox_ sizeToFit];
-    checkboxSizeWithoutTitle_ = [checkbox_ frame].size;
     [checkbox_ setHidden:YES];
     [view setSubviews:@[textfield_, checkbox_]];
   }
@@ -105,6 +102,7 @@
 
 - (void)setHasCheckbox:(BOOL)hasCheckbox {
   [checkbox_ setHidden:!hasCheckbox];
+  [textfield_ setHidden:hasCheckbox];
 }
 
 - (NSString*)text {
@@ -113,6 +111,7 @@
 
 - (void)setText:(NSString*)string {
   [textfield_ setStringValue:string];
+  [checkbox_ setAttributedTitle:[textfield_ attributedStringValue]];
 }
 
 - (NSTextField*)textfield {
@@ -140,15 +139,9 @@
 }
 
 - (NSSize)preferredSizeForWidth:(CGFloat)width {
-  NSRect textRect = NSMakeRect(0, 0, width, CGFLOAT_MAX);
-  if (![checkbox_ isHidden])
-    textRect.size.width -= checkboxSizeWithoutTitle_.width;
-
-  NSSize preferredSize = [[textfield_ cell] cellSizeForBounds:textRect];
-  if (![checkbox_ isHidden]) {
-    preferredSize.height = std::max(preferredSize.height,
-                                    checkboxSizeWithoutTitle_.height);
-  }
+  NSCell* cell = [checkbox_ isHidden] ? [textfield_ cell] : [checkbox_ cell];
+  NSSize preferredSize =
+      [cell cellSizeForBounds:NSMakeRect(0, 0, width, CGFLOAT_MAX)];
 
   if ([[self notificationView] hasArrow])
       preferredSize.height += autofill::kArrowHeight;
@@ -170,20 +163,9 @@
   NSRect textFrame = NSInsetRect(bounds,
                                  chrome_style::kHorizontalPadding,
                                  autofill::kNotificationPadding);
-  if (![checkbox_ isHidden]) {
-    // Temporarily resize checkbox to just the box, no extra clickable area.
-    textFrame.origin.x += checkboxSizeWithoutTitle_.width;
-    textFrame.size.width -= checkboxSizeWithoutTitle_.width;
-    textFrame.size = [[textfield_ cell] cellSizeForBounds:textFrame];
-
-    NSRect checkboxFrame =
-        NSMakeRect(chrome_style::kHorizontalPadding,
-                   NSMaxY(textFrame) - checkboxSizeWithoutTitle_.height,
-                   NSMaxX(textFrame), NSHeight(textFrame));
-    [checkbox_ setFrame:checkboxFrame];
-  }
-  [textfield_ setFrame:textFrame];
+  NSControl* control =
+      [checkbox_ isHidden] ? textfield_.get() : checkbox_.get();
+  [control setFrame:textFrame];
 }
 
 @end
-
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm
index 17fb50e..a77febf 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm
@@ -29,6 +29,13 @@
   return self;
 }
 
+- (BOOL)becomeFirstResponder {
+  BOOL result = [super becomeFirstResponder];
+  if (result && delegate_)
+    [delegate_ fieldBecameFirstResponder:self];
+  return result;
+}
+
 - (NSString*)fieldValue {
   return [[self cell] fieldValue];
 }
@@ -100,6 +107,22 @@
   }
 }
 
+- (NSRect)drawTitle:(NSAttributedString*)title
+          withFrame:(NSRect)frame
+             inView:(NSView*)controlView {
+  if (invalid_) {
+    // Draw with a color that has high contrast against the custom background.
+    base::scoped_nsobject<NSMutableAttributedString> coloredTitle(
+        [[NSMutableAttributedString alloc] initWithAttributedString:title]);
+    [coloredTitle addAttribute:NSForegroundColorAttributeName
+                         value:[NSColor whiteColor]
+                         range:NSMakeRange(0, [title length])];
+    return [super drawTitle:coloredTitle withFrame:frame inView:controlView];
+  } else {
+    return [super drawTitle:title withFrame:frame inView:controlView];
+  }
+}
+
 - (NSString*)fieldValue {
   if (![self selectedItem])
     return defaultValue_;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
index ee4313f..642b0d8 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
@@ -12,33 +12,6 @@
 #include "ui/base/cocoa/window_size_constants.h"
 #include "ui/gfx/rect.h"
 
-namespace {
-
-// The width of the border around the popup.
-const CGFloat kBorderWidth = 1.0;
-
-// The color of the border around the popup.
-NSColor* BorderColor() {
-  return [NSColor colorForControlTint:[NSColor currentControlTint]];
-}
-
-// Returns a view that contains a border around the content view.
-NSBox* CreateBorderView() {
-  // TODO(isherman): We should consider using asset-based drawing for the
-  // border, creating simple bitmaps for the view's border and background, and
-  // drawing them using NSDrawNinePartImage().
-  NSBox* border_view = [[[NSBox alloc] initWithFrame:NSZeroRect] autorelease];
-  [border_view setBorderColor:BorderColor()];
-  [border_view setBorderType:NSLineBorder];
-  [border_view setBorderWidth:kBorderWidth];
-  [border_view setBoxType:NSBoxCustom];
-  [border_view setContentViewMargins:NSZeroSize];
-  [border_view setTitlePosition:NSNoTitle];
-  return border_view;
-}
-
-}  // namespace
-
 namespace autofill {
 
 AutofillPopupViewBridge::AutofillPopupViewBridge(
@@ -52,13 +25,10 @@
   // Telling Cocoa that the window is opaque enables some drawing optimizations.
   [window_ setOpaque:YES];
 
-  NSBox* border_view = CreateBorderView();
-  [window_ setContentView:border_view];
-
   view_ = [[[AutofillPopupViewCocoa alloc]
              initWithController:controller_
                           frame:NSZeroRect] autorelease];
-  [border_view setContentView:view_];
+  [window_ setContentView:view_];
 }
 
 AutofillPopupViewBridge::~AutofillPopupViewBridge() {
@@ -97,23 +67,6 @@
   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
   frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame);
 
-  // Leave room for the border.
-  frame = NSInsetRect(frame, -kBorderWidth, -kBorderWidth);
-  if (controller_->popup_bounds().y() > controller_->element_bounds().y()) {
-    // Popup is below the element which initiated it.
-    frame.origin.y -= kBorderWidth;
-  } else {
-    // Popup is above the element which initiated it.
-    frame.origin.y += kBorderWidth;
-  }
-  if (controller_->popup_bounds().x() == controller_->element_bounds().x()) {
-    // Popup is anchored to the left of the element which initiated it.
-    frame.origin.x += kBorderWidth;
-  } else {
-    // Popup is anhored to the right of the element which initiated it.
-    frame.origin.x -= kBorderWidth;
-  }
-
   // TODO(isherman): The view should support scrolling if the popup gets too
   // big to fit on the screen.
   [window_ setFrame:frame display:YES];
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
index 9bc71eb..7989d86 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
@@ -23,6 +23,11 @@
   return [NSColor whiteColor];
 }
 
+// The color of the border around the popup.
+NSColor* BorderColor() {
+  return [NSColor colorForControlTint:[NSColor currentControlTint]];
+}
+
 NSColor* SeparatorColor() {
   return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1];
 }
@@ -107,8 +112,19 @@
   if (!controller_)
     return;
 
-  [BackgroundColor() set];
-  [NSBezierPath fillRect:[self bounds]];
+  // Draw the popup's background and border.
+  // The inset is needed since the border is centered on the |path|.
+  // TODO(isherman): We should consider using asset-based drawing for the
+  // border, creating simple bitmaps for the view's border and background, and
+  // drawing them using NSDrawNinePartImage().
+  CGFloat inset = autofill::AutofillPopupView::kBorderThickness / 2.0;
+  NSRect borderRect = NSInsetRect([self bounds], inset, inset);
+  NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect];
+  [BackgroundColor() setFill];
+  [path fill];
+  [path setLineWidth:autofill::AutofillPopupView::kBorderThickness];
+  [BorderColor() setStroke];
+  [path stroke];
 
   for (size_t i = 0; i < controller_->names().size(); ++i) {
     // Skip rows outside of the dirty rect.
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.h b/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
index af19070..6bdbcb5 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
@@ -67,7 +67,7 @@
 // Designated initializer. Queries |delegate| for the list of desired input
 // fields for |section|.
 - (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate
-              forSection:(autofill::DialogSection)section;
+            forSection:(autofill::DialogSection)section;
 
 // Populates |output| with mappings from field identification to input value.
 - (void)getInputs:(autofill::DetailOutputMap*)output;
@@ -85,6 +85,10 @@
 // Validate this section. Validation rules depend on |validationType|.
 - (BOOL)validateFor:(autofill::ValidationType)validationType;
 
+// Returns the value of the |suggestContainer_|'s input field, or nil if no
+// suggestion is currently showing.
+- (NSString*)suggestionText;
+
 @end
 
 @interface AutofillSectionContainer (ForTesting)
@@ -95,7 +99,7 @@
 // Sets the value for the field matching |input|. Does nothing if the field is
 // not part of this section.
 - (void)setFieldValue:(NSString*)text
-              forInput:(const autofill::DetailInput&)input;
+             forInput:(const autofill::DetailInput&)input;
 
 // Sets the value for the suggestion text field.
 - (void)setSuggestionFieldValue:(NSString*)text;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
index 59343e0..2ba0561 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
@@ -366,6 +366,10 @@
   return !messages.HasErrors();
 }
 
+- (NSString*)suggestionText {
+  return showSuggestions_ ? [[suggestContainer_ inputField] stringValue] : nil;
+}
+
 #pragma mark Internal API for AutofillSectionContainer.
 
 - (void)textfieldEditedOrActivated:(NSControl<AutofillInputField>*)field
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
index 0279c20..8487687 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
@@ -37,6 +37,7 @@
 - (void)loadSignInPage;
 - (content::NavigationController*)navigationController;
 - (void)constrainSizeToMinimum:(NSSize)minSize maximum:(NSSize)maximum;
+- (content::WebContents*)webContents;
 
 @end
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
index 02c1b4d..290f155 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
@@ -48,7 +48,7 @@
           gfx::Size(NSSizeToCGSize(minSize_)),
           gfx::Size(NSSizeToCGSize(maxSize_))));
   webContents_->GetController().LoadURL(
-      autofill::wallet::GetSignInUrl(),
+      dialog_->delegate()->SignInUrl(),
       content::Referrer(),
       content::PAGE_TRANSITION_AUTO_TOPLEVEL,
       std::string());
@@ -58,6 +58,10 @@
   return &webContents_->GetController();
 }
 
+- (content::WebContents*)webContents {
+  return webContents_.get();
+}
+
 - (void)constrainSizeToMinimum:(NSSize)minSize maximum:(NSSize)maxSize {
   minSize_ = minSize;
   maxSize_ = maxSize;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
index e50c610..7d3595b 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
@@ -17,14 +17,6 @@
 #include "testing/platform_test.h"
 #import "ui/base/test/ui_cocoa_test_helper.h"
 
-@interface AutofillSignInContainer (ExposedForTesting)
-- (content::WebContents*)webContents;
-@end
-
-@implementation AutofillSignInContainer (ExposedForTesting)
-- (content::WebContents*)webContents { return webContents_.get(); }
-@end
-
 namespace {
 
 class AutofillSignInContainerTest : public ChromeRenderViewHostTestHarness {
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
index 32df150..0d855ca 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
@@ -5,12 +5,15 @@
 #import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h"
 
 #include <algorithm>
+#include <cmath>
 
+#include "base/logging.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
 namespace {
 
 const CGFloat kGap = 6.0;  // gap between icon and text.
+const CGFloat kMinimumHeight = 27.0;  // Enforced minimum height for text cells.
 
 }  // namespace
 
@@ -115,6 +118,16 @@
 }
 
 - (NSRect)textFrameForFrame:(NSRect)frame {
+  // Ensure text height is original cell height, and the text frame is centered
+  // vertically in the cell frame.
+  NSSize originalSize = [super cellSize];
+  if (originalSize.height < NSHeight(frame)) {
+    CGFloat delta = NSHeight(frame) - originalSize.height;
+    frame.origin.y += std::floor(delta / 2.0);
+    frame.size.height -= delta;
+  }
+  DCHECK_EQ(originalSize.height, NSHeight(frame));
+
   if (icon_) {
     NSRect textFrame, iconFrame;
     NSDivideRect(frame, &iconFrame, &textFrame,
@@ -142,7 +155,7 @@
     cellSize.width += kGap + iconSize.width;
     cellSize.height = std::max(cellSize.height, iconSize.height);
   }
-
+  cellSize.height = std::max(cellSize.height, kMinimumHeight);
   return cellSize;
 }
 
@@ -172,6 +185,11 @@
                   length:length];
 }
 
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+  NSRect textFrame = [self textFrameForFrame:cellFrame];
+  [super drawInteriorWithFrame:textFrame inView:controlView];
+}
+
 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
   [super drawWithFrame:cellFrame inView:controlView];
 
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index 0370bc0..49519fa 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -100,6 +100,9 @@
   virtual void ShowUpdateChromeDialog() OVERRIDE;
   virtual void ShowBookmarkBubble(const GURL& url,
                                   bool already_bookmarked) OVERRIDE;
+  virtual void ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) OVERRIDE;
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
   virtual void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 230ba44..1d2ef5d 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -493,6 +493,11 @@
                       alreadyBookmarked:(already_bookmarked ? YES : NO)];
 }
 
+void BrowserWindowCocoa::ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) {
+}
+
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
 void BrowserWindowCocoa::ShowOneClickSigninBubble(
     OneClickSigninBubbleType type,
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index a144dfb..01bb5e6 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -9,9 +9,9 @@
 #include "base/command_line.h"
 #import "base/mac/scoped_nsobject.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/fullscreen.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_util.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
diff --git a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
index ef203ae..17d22f5 100644
--- a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
+++ b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
@@ -13,11 +13,6 @@
 
 #include "base/logging.h"
 #import "chrome/browser/ui/cocoa/animatable_image.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "grit/theme_resources.h"
@@ -29,72 +24,21 @@
 
 class DownloadAnimationWebObserver;
 
-using content::WebContents;
-
 // A class for managing the Core Animation download animation.
 // Should be instantiated using +startAnimationWithWebContents:.
 @interface DownloadStartedAnimationMac : NSObject {
  @private
-  // The observer for the WebContents we are drawing on.
-  scoped_ptr<DownloadAnimationWebObserver> observer_;
   CGFloat imageWidth_;
   AnimatableImage* animation_;
 };
 
-+ (void)startAnimationWithWebContents:(WebContents*)webContents;
-
-// Called by the Observer if the tab is hidden or closed.
-- (void)closeAnimation;
++ (void)startAnimationWithWebContents:(content::WebContents*)webContents;
 
 @end
 
-// A helper class to monitor tab hidden and closed notifications. If we receive
-// such a notification, we stop the animation.
-class DownloadAnimationWebObserver : public content::NotificationObserver {
- public:
-  DownloadAnimationWebObserver(DownloadStartedAnimationMac* owner,
-                               WebContents* web_contents)
-      : owner_(owner),
-        web_contents_(web_contents) {
-    registrar_.Add(this,
-                   content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-                   content::Source<WebContents>(web_contents_));
-    registrar_.Add(this,
-                   content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-                   content::Source<WebContents>(web_contents_));
-  }
-
-  // Runs when a tab is hidden or destroyed. Let our owner know we should end
-  // the animation.
-  virtual void Observe(
-      int type,
-      const content::NotificationSource& source,
-      const content::NotificationDetails& details) OVERRIDE {
-    if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) {
-      bool visible = *content::Details<bool>(details).ptr();
-      if (visible)
-        return;
-    }
-    // This ends up deleting us.
-    [owner_ closeAnimation];
-  }
-
- private:
-  // The object we need to inform when we get a notification. Weak.
-  DownloadStartedAnimationMac* owner_;
-
-  // The tab we are observing. Weak.
-  WebContents* web_contents_;
-
-  // Used for registering to receive notifications and automatic clean up.
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadAnimationWebObserver);
-};
-
 @implementation DownloadStartedAnimationMac
 
-- (id)initWithWebContents:(WebContents*)webContents {
+- (id)initWithWebContents:(content::WebContents*)webContents {
   if ((self = [super init])) {
     // Load the image of the download arrow.
     ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
@@ -144,12 +88,10 @@
     [animation_ setEndOpacity:0.4];
     [animation_ setDuration:0.6];
 
-    observer_.reset(new DownloadAnimationWebObserver(self, webContents));
-
     // Set up to get notified about resize events on the parent window.
     NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
     [center addObserver:self
-               selector:@selector(parentWindowChanged:)
+               selector:@selector(parentWindowDidResize:)
                    name:NSWindowDidResizeNotification
                  object:parentWindow];
     // When the animation window closes, it needs to be removed from the
@@ -157,7 +99,12 @@
     [center addObserver:self
                selector:@selector(windowWillClose:)
                    name:NSWindowWillCloseNotification
-                object:animation_];
+                 object:animation_];
+    // If the parent window closes, shut everything down too.
+    [center addObserver:self
+               selector:@selector(windowWillClose:)
+                   name:NSWindowWillCloseNotification
+                 object:parentWindow];
   }
   return self;
 }
@@ -168,7 +115,7 @@
 }
 
 // Called when the parent window is resized.
-- (void)parentWindowChanged:(NSNotification*)notification {
+- (void)parentWindowDidResize:(NSNotification*)notification {
   NSWindow* parentWindow = [animation_ parentWindow];
   DCHECK([[notification object] isEqual:parentWindow]);
   NSRect parentFrame = [parentWindow frame];
@@ -177,18 +124,13 @@
   [animation_ setFrame:frame display:YES];
 }
 
-- (void)closeAnimation {
-  [animation_ close];
-}
-
 // When the animation closes, release self.
 - (void)windowWillClose:(NSNotification*)notification {
-  DCHECK([[notification object] isEqual:animation_]);
   [[animation_ parentWindow] removeChildWindow:animation_];
   [self release];
 }
 
-+ (void)startAnimationWithWebContents:(WebContents*)contents {
++ (void)startAnimationWithWebContents:(content::WebContents*)contents {
   // Will be deleted when the animation window closes.
   DownloadStartedAnimationMac* controller =
       [[self alloc] initWithWebContents:contents];
@@ -196,13 +138,13 @@
   if (!controller)
     return;
 
-  // The |animation_| releases itself when done.
+  // The |controller| releases itself when done.
   [controller->animation_ startAnimation];
 }
 
 @end
 
-void DownloadStartedAnimation::Show(WebContents* web_contents) {
+void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
   DCHECK(web_contents);
 
   // Will be deleted when the animation is complete.
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
index e3dbf83..252f41b 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
@@ -48,7 +48,8 @@
   EXPECT_FALSE([window isVisible]);
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogControllerTest, Permissions) {
+IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogControllerTest,
+                       DISABLED_Permissions) {
   content::WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(0);
   ExtensionInstallPrompt::ShowParams show_params(tab);
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
index bf9c9e6..d6495df 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/bundle_installer.h"
 #import "chrome/browser/ui/chrome_style.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/page_navigator.h"
 #include "grit/generated_resources.h"
 #include "skia/ext/skia_utils_mac.h"
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 bde8334..439764f 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
@@ -37,9 +37,7 @@
   void OnCheckboxToggled(NSButton* checkbox);
 
   // MediaGalleriesDialog implementation:
-  virtual void UpdateGallery(const MediaGalleryPrefInfo& gallery,
-                             bool permitted) OVERRIDE;
-  virtual void ForgetGallery(MediaGalleryPrefId gallery) OVERRIDE;
+  virtual void UpdateGalleries() OVERRIDE;
 
   // ConstrainedWindowMacDelegate implementation.
   virtual void OnConstrainedWindowClosed(
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 59794fe..edc13a1 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
@@ -255,7 +255,7 @@
   [[[alert_ buttons] objectAtIndex:0] setEnabled:YES];
 
   const MediaGalleriesDialogController::GalleryPermissionsVector&
-  attached_permissions = controller_->AttachedPermissions();
+      attached_permissions = controller_->AttachedPermissions();
   for (MediaGalleriesDialogController::GalleryPermissionsVector::
        const_reverse_iterator iter = attached_permissions.rbegin();
        iter != attached_permissions.rend(); iter++) {
@@ -338,13 +338,7 @@
   [checkbox_container_ addSubview:details];
 }
 
-void MediaGalleriesDialogCocoa::UpdateGallery(
-    const MediaGalleryPrefInfo& gallery,
-    bool permitted) {
-  InitDialogControls();
-}
-
-void MediaGalleriesDialogCocoa::ForgetGallery(MediaGalleryPrefId gallery) {
+void MediaGalleriesDialogCocoa::UpdateGalleries() {
   InitDialogControls();
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
index 6b3da1f..7c95e8e 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
@@ -117,7 +117,7 @@
   EXPECT_EQ([checkbox state], NSOnState);
 }
 
-// Tests that UpdateGallery will add a new checkbox, but only if it refers to
+// Tests that UpdateGalleries will add a new checkbox, but only if it refers to
 // a gallery that the dialog hasn't seen before.
 TEST_F(MediaGalleriesDialogTest, UpdateAdds) {
   NiceMock<MediaGalleriesDialogControllerMock> controller(dummy_extension());
@@ -141,7 +141,7 @@
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(
           MakePrefInfoForTesting(1), true));
-  dialog->UpdateGallery(MakePrefInfoForTesting(1), true);
+  dialog->UpdateGalleries();
   EXPECT_EQ(1U, [dialog->checkboxes_ count]);
 
   // The checkbox container should be taller.
@@ -152,7 +152,7 @@
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(
           MakePrefInfoForTesting(2), true));
-  dialog->UpdateGallery(MakePrefInfoForTesting(2), true);
+  dialog->UpdateGalleries();
   EXPECT_EQ(2U, [dialog->checkboxes_ count]);
 
   // The checkbox container should be taller.
@@ -161,7 +161,7 @@
   old_container_height = new_container_height;
 
   attached_permissions[1].allowed = false;
-  dialog->UpdateGallery(MakePrefInfoForTesting(2), false);
+  dialog->UpdateGalleries();
   EXPECT_EQ(2U, [dialog->checkboxes_ count]);
 
   // The checkbox container height should not have changed.
@@ -189,17 +189,17 @@
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(
           MakePrefInfoForTesting(1), true));
-  dialog->UpdateGallery(MakePrefInfoForTesting(1), true);
+  dialog->UpdateGalleries();
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(
           MakePrefInfoForTesting(2), true));
-  dialog->UpdateGallery(MakePrefInfoForTesting(2), true);
+  dialog->UpdateGalleries();
   EXPECT_EQ(2U, [dialog->checkboxes_ count]);
   CGFloat old_container_height = NSHeight([dialog->checkbox_container_ frame]);
 
   // Remove a gallery.
   attached_permissions.erase(attached_permissions.begin());
-  dialog->ForgetGallery(1);
+  dialog->UpdateGalleries();
   EXPECT_EQ(1U, [dialog->checkboxes_ count]);
 
   // The checkbox container should be shorter.
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm
index 3e4f7b6..2eb13a4 100644
--- a/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm
@@ -14,6 +14,7 @@
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
 #include "chrome/browser/ui/host_desktop.h"
 #import "ui/base/cocoa/cocoa_event_utils.h"
@@ -39,26 +40,25 @@
 
 // Open the URL of the given history item in the current tab.
 - (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node {
-  Browser* browser =
-      chrome::FindOrCreateTabbedBrowser(bridge_->profile(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
-  WindowOpenDisposition disposition =
-      ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
-
   // If this item can be restored using TabRestoreService, do so. Otherwise,
   // just load the URL.
   TabRestoreService* service =
       TabRestoreServiceFactory::GetForProfile(bridge_->profile());
   if (node->session_id && service) {
-    service->RestoreEntryById(
-        browser->tab_restore_service_delegate(), node->session_id,
-        browser->host_desktop_type(), UNKNOWN);
+    Browser* browser = chrome::FindTabbedBrowser(bridge_->profile(), false,
+        chrome::HOST_DESKTOP_TYPE_NATIVE);
+    BrowserTabRestoreServiceDelegate* delegate = browser ?
+        browser->tab_restore_service_delegate() : NULL;
+    service->RestoreEntryById(delegate, node->session_id,
+        chrome::HOST_DESKTOP_TYPE_NATIVE, UNKNOWN);
   } else {
     DCHECK(node->url.is_valid());
-    OpenURLParams params(
-        node->url, Referrer(), disposition,
-        content::PAGE_TRANSITION_AUTO_BOOKMARK, false);
-    browser->OpenURL(params);
+    WindowOpenDisposition disposition =
+        ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+    chrome::NavigateParams params(bridge_->profile(), node->url,
+        content::PAGE_TRANSITION_AUTO_BOOKMARK);
+    params.disposition = disposition;
+    chrome::Navigate(&params);
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm
index c50a25b..e6632fd 100644
--- a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm
+++ b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_infobar_delegate.h"
 #include "chrome/browser/extensions/image_loader.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/animatable_view.h"
 #import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 80e274d..f47847b 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -353,9 +353,9 @@
 
   // Iterate through |content_setting_decorations_| in reverse order so that
   // the order in which the decorations are drawn matches the Views code.
-  for (ScopedVector<ContentSettingDecoration>::reverse_iterator i =
-       content_setting_decorations_.rbegin();
-       i != content_setting_decorations_.rend(); ++i) {
+  for (ScopedVector<ContentSettingDecoration>::iterator i =
+       content_setting_decorations_.begin();
+       i != content_setting_decorations_.end(); ++i) {
     [cell addRightDecoration:*i];
   }
 
@@ -515,7 +515,8 @@
 NSImage* LocationBarViewMac::GetKeywordImage(const string16& keyword) {
   const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile(
       profile_)->GetTemplateURLForKeyword(keyword);
-  if (template_url && template_url->IsExtensionKeyword()) {
+  if (template_url &&
+      (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
     return extensions::OmniboxAPI::Get(profile_)->
         GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage();
   }
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm
index ee7efb5..fe81885 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm
@@ -35,7 +35,8 @@
 typedef SSLClientCertificateSelectorTestBase
     SSLClientCertificateSelectorCocoaTest;
 
-IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorCocoaTest, Basic) {
+// Flaky on 10.7; crbug.com/313243
+IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorCocoaTest, DISABLED_Basic) {
   // TODO(kbr): re-enable: http://crbug.com/222296
   if (base::mac::IsOSMountainLionOrLater())
     return;
diff --git a/chrome/browser/ui/cocoa/tabpose_window.h b/chrome/browser/ui/cocoa/tabpose_window.h
index 7651812..eb6ea9c 100644
--- a/chrome/browser/ui/cocoa/tabpose_window.h
+++ b/chrome/browser/ui/cocoa/tabpose_window.h
@@ -77,7 +77,7 @@
   scoped_ptr<TabStripModelObserverBridge> tabStripModelObserverBridge_;
 
   // The icon used for the closebutton layers.
-  base::ScopedCFTypeRef<CGImageRef> closeIcon_;
+  base::scoped_nsobject<NSImage> closeIcon_;
 
   // True if all close layers should be shown (as opposed to just the close
   // layer of the currently selected thumbnail).
diff --git a/chrome/browser/ui/cocoa/tabpose_window.mm b/chrome/browser/ui/cocoa/tabpose_window.mm
index 1921489..af5b80b 100644
--- a/chrome/browser/ui/cocoa/tabpose_window.mm
+++ b/chrome/browser/ui/cocoa/tabpose_window.mm
@@ -942,10 +942,8 @@
     tileSet_.reset(new tabpose::TileSet);
     tabStripModelObserverBridge_.reset(
         new TabStripModelObserverBridge(tabStripModel_, self));
-    NSImage* nsCloseIcon =
-        ResourceBundle::GetSharedInstance().GetNativeImageNamed(
-            IDR_TABPOSE_CLOSE).ToNSImage();
-    closeIcon_.reset(base::mac::CopyNSImageToCGImage(nsCloseIcon));
+    closeIcon_.reset([ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+            IDR_TABPOSE_CLOSE).ToNSImage() retain]);
     [self setReleasedWhenClosed:YES];
     [self setOpaque:NO];
     [self setBackgroundColor:[NSColor clearColor]];
@@ -1005,10 +1003,9 @@
 
   // Add a close button to the thumb layer.
   CALayer* closeLayer = [CALayer layer];
-  closeLayer.contents = reinterpret_cast<id>(closeIcon_.get());
+  closeLayer.contents = closeIcon_.get();
   CGRect closeBounds = {};
-  closeBounds.size.width = CGImageGetWidth(closeIcon_);
-  closeBounds.size.height = CGImageGetHeight(closeIcon_);
+  closeBounds.size = NSSizeToCGSize([closeIcon_ size]);
   closeLayer.bounds = closeBounds;
   closeLayer.hidden = YES;
 
@@ -1031,9 +1028,6 @@
   NSFont* font = [NSFont systemFontOfSize:tile.title_font_size()];
   tile.set_font_metrics([font ascender], -[font descender]);
 
-  base::ScopedCFTypeRef<CGImageRef> favicon(
-      base::mac::CopyNSImageToCGImage(tile.favicon()));
-
   CALayer* faviconLayer = [CALayer layer];
   if (showZoom) {
     AnimateCALayerFrameFromTo(
@@ -1046,7 +1040,7 @@
   } else {
     faviconLayer.frame = NSRectToCGRect(tile.favicon_rect());
   }
-  faviconLayer.contents = (id)favicon.get();
+  faviconLayer.contents = tile.favicon();
   faviconLayer.zPosition = 1;  // On top of the thumb shadow.
   [bgLayer_ addSublayer:faviconLayer];
   [allFaviconLayers_ addObject:faviconLayer];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller.h b/chrome/browser/ui/cocoa/tabs/tab_controller.h
index ad0a6a1..7e4aa0d 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller.h
@@ -20,6 +20,7 @@
   kTabCrashed,
 };
 
+@class GTMFadeTruncatingTextFieldCell;
 @class MediaIndicatorView;
 @class MenuController;
 namespace TabControllerInternal {
@@ -43,6 +44,7 @@
  @private
   base::scoped_nsobject<NSView> iconView_;
   base::scoped_nsobject<NSTextField> titleView_;
+  GTMFadeTruncatingTextFieldCell* titleViewCell_;  // weak
   base::scoped_nsobject<MediaIndicatorView> mediaIndicatorView_;
   base::scoped_nsobject<HoverCloseButton> closeButton_;
 
@@ -69,6 +71,7 @@
 @property(assign, nonatomic) BOOL app;
 @property(assign, nonatomic) BOOL mini;
 @property(assign, nonatomic) BOOL pinned;
+@property(assign, nonatomic) NSString* toolTip;
 // Note that |-selected| will return YES if the controller is |-active|, too.
 // |-setSelected:| affects the selection, while |-setActive:| affects the key
 // status/focus of the content.
@@ -115,7 +118,6 @@
 @end
 
 @interface TabController(TestingAPI)
-- (NSString*)toolTip;
 - (int)iconCapacity;
 - (BOOL)shouldShowIcon;
 - (BOOL)shouldShowMediaIndicator;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
index ff67592..47f844c 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
@@ -7,8 +7,10 @@
 #include <algorithm>
 #include <cmath>
 
+#include "base/i18n/rtl.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
+#include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/themes/theme_properties.h"
 #import "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/tabs/media_indicator_view.h"
@@ -110,6 +112,7 @@
         [[labelCell font] fontName] size:fontSize];
     [labelCell setFont:font];
     [titleView_ setCell:labelCell];
+    titleViewCell_ = labelCell;
 
     // Close button.
     closeButton_.reset([[HoverCloseButton alloc] initWithFrame:
@@ -192,7 +195,12 @@
 
 - (void)setTitle:(NSString*)title {
   [titleView_ setStringValue:title];
-  [[self view] setToolTip:title];
+  base::string16 title16 = base::SysNSStringToUTF16(title);
+  bool isRTL = base::i18n::GetFirstStrongCharacterDirection(title16) ==
+               base::i18n::RIGHT_TO_LEFT;
+  titleViewCell_.truncateMode = isRTL ? GTMFadeTruncatingHead
+                                      : GTMFadeTruncatingTail;
+
   if ([self mini] && ![self selected]) {
     TabView* tabView = static_cast<TabView*>([self view]);
     DCHECK([tabView isKindOfClass:[TabView class]]);
@@ -201,6 +209,10 @@
   [super setTitle:title];
 }
 
+- (void)setToolTip:(NSString*)toolTip {
+  [[self view] setToolTip:toolTip];
+}
+
 - (void)setActive:(BOOL)active {
   if (active != active_) {
     active_ = active;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
index b530b32..4bb4ba9 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
@@ -122,8 +122,7 @@
         [[controller mediaIndicatorView] mediaState];
     if ([controller mini]) {
       EXPECT_EQ(1, [controller iconCapacity]);
-      if (indicatorState == TAB_MEDIA_STATE_CAPTURING ||
-          indicatorState == TAB_MEDIA_STATE_RECORDING) {
+      if (indicatorState != TAB_MEDIA_STATE_NONE) {
         EXPECT_FALSE([controller shouldShowIcon]);
         EXPECT_TRUE([controller shouldShowMediaIndicator]);
       } else {
@@ -140,8 +139,7 @@
           EXPECT_FALSE([controller shouldShowMediaIndicator]);
           break;
         case 2:
-          if (indicatorState == TAB_MEDIA_STATE_CAPTURING ||
-              indicatorState == TAB_MEDIA_STATE_RECORDING) {
+          if (indicatorState != TAB_MEDIA_STATE_NONE) {
             EXPECT_FALSE([controller shouldShowIcon]);
             EXPECT_TRUE([controller shouldShowMediaIndicator]);
           } else {
@@ -167,8 +165,7 @@
           break;
         case 1:
           EXPECT_FALSE([controller shouldShowCloseButton]);
-          if (indicatorState == TAB_MEDIA_STATE_CAPTURING ||
-              indicatorState == TAB_MEDIA_STATE_RECORDING) {
+          if (indicatorState != TAB_MEDIA_STATE_NONE) {
             EXPECT_FALSE([controller shouldShowIcon]);
             EXPECT_TRUE([controller shouldShowMediaIndicator]);
           } else {
@@ -280,19 +277,6 @@
   [[controller view] removeFromSuperview];
 }
 
-// Tests that setting the title of a tab sets the tooltip as well.
-TEST_F(TabControllerTest, ToolTip) {
-  NSWindow* window = test_window();
-
-  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
-  [[window contentView] addSubview:[controller view]];
-
-  EXPECT_TRUE([[controller toolTip] length] == 0);
-  NSString *tooltip_string = @"Some text to use as a tab title";
-  [controller setTitle:tooltip_string];
-  EXPECT_NSEQ(tooltip_string, [controller toolTip]);
-}
-
 // Tests setting the |loading| property via code.
 TEST_F(TabControllerTest, Loading) {
   NSWindow* window = test_window();
@@ -498,7 +482,8 @@
 // throbber indicators, titile text, audio indicator, and close button) over all
 // relevant combinations of tab state.  This test overlaps with parts of the
 // other tests above.
-TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) {
+// Flaky: https://code.google.com/p/chromium/issues/detail?id=311668
+TEST_F(TabControllerTest, DISABLED_LayoutAndVisibilityOfSubviews) {
   static const TabMediaState kMediaStatesToTest[] = {
     TAB_MEDIA_STATE_NONE, TAB_MEDIA_STATE_CAPTURING,
     TAB_MEDIA_STATE_AUDIO_PLAYING
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
index 203502e..86e01bd 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -237,6 +237,11 @@
 
 @end
 
+@interface TabStripController(TestingAPI)
+- (void)setTabTitle:(TabController*)tab
+       withContents:(content::WebContents*)contents;
+@end
+
 // Returns the parent view to use when showing a sheet for a given web contents.
 NSView* GetSheetParentViewForWebContents(content::WebContents* web_contents);
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index 364a353..b98dc32 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -1222,14 +1222,19 @@
 
 // Handles setting the title of the tab based on the given |contents|. Uses
 // a canned string if |contents| is NULL.
-- (void)setTabTitle:(NSViewController*)tab withContents:(WebContents*)contents {
-  NSString* titleString = nil;
+- (void)setTabTitle:(TabController*)tab withContents:(WebContents*)contents {
+  // TODO(miu): Rectify inconsistent tooltip behavior.  http://crbug.com/310947
+
+  base::string16 title;
   if (contents)
-    titleString = base::SysUTF16ToNSString(contents->GetTitle());
-  if (![titleString length]) {
-    titleString = l10n_util::GetNSString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
-  }
-  [tab setTitle:titleString];
+    title = contents->GetTitle();
+  if (title.empty())
+    title = l10n_util::GetStringUTF16(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
+  [tab setTitle:base::SysUTF16ToNSString(title)];
+
+  const base::string16& toolTip = chrome::AssembleTabTooltipText(
+      title, chrome::GetTabMediaStateForContents(contents));
+  [tab setToolTip:base::SysUTF16ToNSString(toolTip)];
 }
 
 // Called when a notification is received from the model to insert a new tab
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
index 3ffb531..b8277e7 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
@@ -4,7 +4,10 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "base/bind_helpers.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/media_stream_capture_indicator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/new_tab_button.h"
@@ -12,10 +15,13 @@
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
+#include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/media_stream_request.h"
+#import "testing/gtest_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "ui/base/test/cocoa_test_event_utils.h"
@@ -174,7 +180,7 @@
   // TODO(pinkerton): Implement http://crbug.com/10899
 }
 
-TEST_F(TabStripControllerTest, CorrectToolTipText) {
+TEST_F(TabStripControllerTest, CorrectToolTipMouseHoverBehavior) {
   // Set tab 1 tooltip.
   TabView* tab1 = CreateTab();
   [tab1 setToolTip:@"Tab1"];
@@ -228,6 +234,58 @@
                 userData:nil] cStringUsingEncoding:NSASCIIStringEncoding]);
 }
 
+TEST_F(TabStripControllerTest, CorrectTitleAndToolTipTextFromSetTabTitle) {
+  using content::MediaStreamDevice;
+  using content::MediaStreamDevices;
+  using content::MediaStreamUI;
+
+  TabView* const tab = CreateTab();
+  TabController* const tabController = [tab controller];
+  WebContents* const contents = model_->GetActiveWebContents();
+
+  // Initially, tab title and tooltip text are equivalent.
+  EXPECT_EQ(TAB_MEDIA_STATE_NONE,
+            chrome::GetTabMediaStateForContents(contents));
+  [controller_ setTabTitle:tabController withContents:contents];
+  NSString* const baseTitle = [tabController title];
+  EXPECT_NSEQ(baseTitle, [tabController toolTip]);
+
+  // Simulate the start of tab video capture.  Tab title remains the same, but
+  // the tooltip text should include the following appended: 1) a line break;
+  // 2) a non-empty string with a localized description of the media state.
+  scoped_refptr<MediaStreamCaptureIndicator> indicator =
+      MediaCaptureDevicesDispatcher::GetInstance()->
+          GetMediaStreamCaptureIndicator();
+  const MediaStreamDevice dummyVideoCaptureDevice(
+      content::MEDIA_TAB_VIDEO_CAPTURE, "dummy_id", "dummy name");
+  scoped_ptr<MediaStreamUI> streamUi(indicator->RegisterMediaStream(
+      contents, MediaStreamDevices(1, dummyVideoCaptureDevice)));
+  streamUi->OnStarted(base::Bind(&base::DoNothing));
+  EXPECT_EQ(TAB_MEDIA_STATE_CAPTURING,
+            chrome::GetTabMediaStateForContents(contents));
+  [controller_ setTabTitle:tabController withContents:contents];
+  EXPECT_NSEQ(baseTitle, [tabController title]);
+  NSString* const toolTipText = [tabController toolTip];
+  if ([baseTitle length] > 0) {
+    EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, [baseTitle length]),
+                              [toolTipText rangeOfString:baseTitle]));
+    EXPECT_TRUE(NSEqualRanges(NSMakeRange([baseTitle length], 1),
+                              [toolTipText rangeOfString:@"\n"]));
+    EXPECT_LT([baseTitle length] + 1, [toolTipText length]);
+  } else {
+    EXPECT_LT(0u, [toolTipText length]);
+  }
+
+  // Simulate the end of tab video capture.  Tab title and tooltip should become
+  // equivalent again.
+  streamUi.reset();
+  EXPECT_EQ(TAB_MEDIA_STATE_NONE,
+            chrome::GetTabMediaStateForContents(contents));
+  [controller_ setTabTitle:tabController withContents:contents];
+  EXPECT_NSEQ(baseTitle, [tabController title]);
+  EXPECT_NSEQ(baseTitle, [tabController toolTip]);
+}
+
 TEST_F(TabStripControllerTest, TabCloseDuringDrag) {
   TabController* tab;
   // The TabController gets autoreleased when created, but is owned by the
diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
index 15ca1d5..2b5bc5a 100644
--- a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
+++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
@@ -71,7 +71,8 @@
           i == VIEW_ID_CONTENTS_SPLIT ||
           i == VIEW_ID_FEEDBACK_BUTTON ||
           i == VIEW_ID_SCRIPT_BUBBLE ||
-          i == VIEW_ID_MIC_SEARCH_BUTTON) {
+          i == VIEW_ID_MIC_SEARCH_BUTTON ||
+          i == VIEW_ID_TRANSLATE_BUTTON) {
         continue;
       }
 
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver.mm b/chrome/browser/ui/cocoa/window_size_autosaver.mm
index 673320e..63eb986 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver.mm
@@ -7,7 +7,7 @@
 #import "chrome/browser/ui/cocoa/window_size_autosaver.h"
 
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "base/prefs/scoped_user_pref_update.h"
 
 // If the window width stored in the prefs is smaller than this, the size is
 // not restored but instead cleared from the profile -- to protect users from
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
index cde1cb6..9a86034 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
@@ -8,7 +8,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/user_prefs/pref_registry_syncable.h"
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index e0efa58..bcf2158 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -368,6 +368,7 @@
       CookieSettings::Factory::GetForProfile(profile()).get();
   ContentSetting most_restrictive_setting;
   SettingSource most_restrictive_setting_source = SETTING_SOURCE_NONE;
+  bool most_restrictive_setting_is_wildcard = false;
 
   if (resources.empty()) {
     if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) {
@@ -380,28 +381,45 @@
       most_restrictive_setting =
           content_settings::ValueToContentSetting(value.get());
       most_restrictive_setting_source = info.source;
+      most_restrictive_setting_is_wildcard =
+          info.primary_pattern == ContentSettingsPattern::Wildcard() &&
+          info.secondary_pattern == ContentSettingsPattern::Wildcard();
     }
   } else {
     most_restrictive_setting = CONTENT_SETTING_ALLOW;
     for (std::set<std::string>::const_iterator it = resources.begin();
          it != resources.end(); ++it) {
       SettingInfo info;
-      scoped_ptr<Value> value(map->GetWebsiteSetting(
+      scoped_ptr<Value> val(map->GetWebsiteSetting(
           url, url, content_type(), *it, &info));
       ContentSetting setting =
-          content_settings::ValueToContentSetting(value.get());
+          content_settings::ValueToContentSetting(val.get());
       if (setting == CONTENT_SETTING_BLOCK) {
         most_restrictive_setting = CONTENT_SETTING_BLOCK;
         most_restrictive_setting_source = info.source;
+        most_restrictive_setting_is_wildcard =
+            info.primary_pattern == ContentSettingsPattern::Wildcard() &&
+            info.secondary_pattern == ContentSettingsPattern::Wildcard();
         break;
       }
       if (setting == CONTENT_SETTING_ASK) {
         most_restrictive_setting = CONTENT_SETTING_ASK;
         most_restrictive_setting_source = info.source;
+        most_restrictive_setting_is_wildcard =
+            info.primary_pattern == ContentSettingsPattern::Wildcard() &&
+            info.secondary_pattern == ContentSettingsPattern::Wildcard();
       }
     }
   }
-  if (most_restrictive_setting == CONTENT_SETTING_ALLOW) {
+
+  if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS &&
+      most_restrictive_setting == CONTENT_SETTING_ALLOW &&
+      most_restrictive_setting_is_wildcard) {
+    // In the corner case of unrecognized plugins (which are now blocked by
+    // default) we indicate the blocked state in the UI and allow the user to
+    // whitelist.
+    radio_group.default_item = 1;
+  } else if (most_restrictive_setting == CONTENT_SETTING_ALLOW) {
     radio_group.default_item = 0;
     // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
   } else {
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index d68404f..aff09f1 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -64,11 +64,13 @@
 class EnableViaAppListFlow : public ExtensionEnableFlowDelegate {
  public:
   EnableViaAppListFlow(ExtensionService* service,
-                      Profile* profile,
-                      const std::string& extension_id,
-                      const base::Closure& callback)
+                       Profile* profile,
+                       chrome::HostDesktopType desktop_type,
+                       const std::string& extension_id,
+                       const base::Closure& callback)
       : service_(service),
         profile_(profile),
+        desktop_type_(desktop_type),
         extension_id_(extension_id),
         callback_(callback) {
   }
@@ -85,8 +87,9 @@
 
  private:
   gfx::NativeWindow ShowAppList() {
-    AppListService::Get()->Show();
-    return AppListService::Get()->GetAppListWindow();
+    AppListService* app_list_service = AppListService::Get(desktop_type_);
+    app_list_service->Show();
+    return app_list_service->GetAppListWindow();
   }
 
   // ExtensionEnableFlowDelegate overrides.
@@ -105,6 +108,7 @@
 
   ExtensionService* service_;
   Profile* profile_;
+  chrome::HostDesktopType desktop_type_;
   std::string extension_id_;
   base::Closure callback_;
   scoped_ptr<ExtensionEnableFlow> flow_;
@@ -455,7 +459,7 @@
       extensions::ExtensionSystem::Get(profile)->extension_service();
   if (!service->IsExtensionEnabled(extension->id())) {
     (new EnableViaAppListFlow(
-        service, profile, extension->id(),
+        service, profile, params.desktop_type, extension->id(),
         base::Bind(base::IgnoreResult(OpenEnabledApplication), params)))->Run();
     return;
   }
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc
index 3e27e0c..2ec1f98 100644
--- a/chrome/browser/ui/extensions/extension_enable_flow.cc
+++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 
@@ -95,11 +94,7 @@
   }
 
   CreatePrompt();
-  int disable_reasons = extension_prefs->GetDisableReasons(extension->id());
-  if (disable_reasons & Extension::DISABLE_PERMISSIONS_CONSENT)
-    prompt_->ConfirmDefaultInstallFirstRun(this, extension);
-  else
-    prompt_->ConfirmReEnable(this, extension);
+  prompt_->ConfirmReEnable(this, extension);
 }
 
 void ExtensionEnableFlow::CreatePrompt() {
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc
index 31cad6f..b290ee7 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.cc
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
@@ -19,6 +18,7 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -153,7 +153,8 @@
 void ExtensionInstallUI::OpenAppInstalledUI(Profile* profile,
                                             const std::string& app_id) {
 #if defined(OS_CHROMEOS)
-  AppListService::Get()->ShowForProfile(profile);
+  AppListService::Get(chrome::HOST_DESKTOP_TYPE_ASH)->
+      ShowForProfile(profile);
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
@@ -245,7 +246,10 @@
 #endif
 
     if (IsAppLauncherEnabled()) {
-      AppListService::Get()->ShowForProfile(current_profile);
+      // TODO(tapted): ExtensionInstallUI should retain the desktop type from
+      // the browser used to initiate the flow. http://crbug.com/308360.
+      AppListService::Get(chrome::GetActiveDesktop())->
+          ShowForProfile(current_profile);
 
       content::NotificationService::current()->Notify(
           chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller.cc b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
index d66056d..b739e85 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_controller.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
@@ -34,11 +34,6 @@
 #include "chrome/common/pref_names.h"
 #endif
 
-#if defined(USE_ASH)
-#include "ash/shell.h"
-#include "ui/aura/window.h"
-#endif
-
 using content::RenderViewHost;
 using content::UserMetricsAction;
 using content::WebContents;
@@ -496,21 +491,6 @@
 
 void FullscreenController::PostFullscreenChangeNotification(
     bool is_fullscreen) {
-#if defined(USE_ASH)
-  if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
-    // Ash window may not be a browser window and ash can't (and shouldn't)
-    // depend on chrome/ so it needs a separate notification.
-    // In ash send notification to ShellObserver objects specifying the root
-    // window. This allows different handling and layout adjustments in each
-    // screen.
-    aura::Window* window = window_->GetNativeWindow();
-    // GetNativeWindow may return NULL in tests.
-    if (window) {
-      ash::Shell::GetInstance()->NotifyFullscreenStateChange(
-          is_fullscreen, window->GetRootWindow());
-    }
-  }
-#endif
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(&FullscreenController::NotifyFullscreenChange,
diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc
index 6f57404..2f86608 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc
@@ -655,10 +655,18 @@
   ASSERT_TRUE(IsFullscreenForTabOrPending());
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_MouseLockSilentAfterTargetUnlock \
+  DISABLED_MouseLockSilentAfterTargetUnlock
+#else
+#define MAYBE_MouseLockSilentAfterTargetUnlock MouseLockSilentAfterTargetUnlock
+#endif
+
 // Tests mouse lock can be exited and re-entered by an application silently
 // with no UI distraction for users.
 IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
-                       MouseLockSilentAfterTargetUnlock) {
+                       MAYBE_MouseLockSilentAfterTargetUnlock) {
   ASSERT_TRUE(test_server()->Start());
   ui_test_utils::NavigateToURL(browser(),
                                test_server()->GetURL(kFullscreenMouseLockHTML));
@@ -726,9 +734,12 @@
   ASSERT_TRUE(IsMouseLocked());
 }
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || \
+  (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
 // These tests are very flaky on Vista.
 // http://crbug.com/158762
+// These are flaky on linux_aura.
+// http://crbug.com/163931
 #define MAYBE_TestTabExitsMouseLockOnNavigation \
     DISABLED_TestTabExitsMouseLockOnNavigation
 #define MAYBE_TestTabExitsMouseLockOnGoBack \
diff --git a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
index 5f1752e..cb67b4b 100644
--- a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
+++ b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
@@ -23,10 +23,6 @@
 #include "content/public/common/renderer_preferences.h"
 #include "ui/events/gestures/gesture_configuration.h"
 
-#if defined(USE_ASH)
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
-#endif  // USE_ASH
-
 using ui::GestureConfiguration;
 
 namespace {
@@ -66,13 +62,6 @@
   return overscroll_prefs;
 }
 
-#if defined(USE_ASH)
-const char* kImmersiveModePrefs[] = {
-  prefs::kImmersiveModeRevealDelayMs,
-  prefs::kImmersiveModeRevealXThresholdPixels,
-};
-#endif  // USE_ASH
-
 // This class manages gesture configuration preferences.
 class GesturePrefsObserver : public BrowserContextKeyedService {
  public:
@@ -96,8 +85,6 @@
   // content.
   void UpdateOverscrollPrefs();
 
-  void UpdateImmersiveModePrefs();
-
   PrefChangeRegistrar registrar_;
   PrefService* prefs_;
 
@@ -171,11 +158,6 @@
     for (size_t i = 0; i < arraysize(kFlingTouchscreenPrefs); ++i)
       prefs->ClearPref(kFlingTouchscreenPrefs[i]);
 
-#if defined(USE_ASH)
-    for (size_t i = 0; i < arraysize(kImmersiveModePrefs); ++i)
-      prefs->ClearPref(kImmersiveModePrefs[i]);
-#endif  // USE_ASH
-
     prefs->SetBoolean(prefs::kGestureConfigIsTrustworthy, true);
   }
 
@@ -199,10 +181,6 @@
   for (size_t i = 0; i < arraysize(kFlingTouchscreenPrefs); ++i)
     registrar_.Add(kFlingTouchscreenPrefs[i], notify_callback);
 
-#if defined(USE_ASH)
-  for (size_t i = 0; i < arraysize(kImmersiveModePrefs); ++i)
-    registrar_.Add(kImmersiveModePrefs[i], callback);
-#endif  // USE_ASH
   Update();
 }
 
@@ -291,9 +269,10 @@
           prefs::kRailStartProportion));
   GestureConfiguration::set_scroll_prediction_seconds(
       prefs_->GetDouble(prefs::kScrollPredictionSeconds));
+  GestureConfiguration::set_show_press_delay_in_ms(
+      prefs_->GetInteger(prefs::kShowPressDelayInMS));
 
   UpdateOverscrollPrefs();
-  UpdateImmersiveModePrefs();
 }
 
 void GesturePrefsObserver::UpdateOverscrollPrefs() {
@@ -304,16 +283,6 @@
   }
 }
 
-void GesturePrefsObserver::UpdateImmersiveModePrefs() {
-#if defined(USE_ASH)
-  ImmersiveFullscreenConfiguration::set_immersive_mode_reveal_delay_ms(
-      prefs_->GetInteger(prefs::kImmersiveModeRevealDelayMs));
-  ImmersiveFullscreenConfiguration::
-      set_immersive_mode_reveal_x_threshold_pixels(
-          prefs_->GetInteger(prefs::kImmersiveModeRevealXThresholdPixels));
-#endif  // USE_ASH
-}
-
 void GesturePrefsObserver::Notify() {
   // Must do a notify to distribute the changes to all renderers.
   content::NotificationService* service =
@@ -373,21 +342,6 @@
         user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
-void GesturePrefsObserverFactoryAura::RegisterImmersiveModePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-#if defined(USE_ASH)
-  registry->RegisterIntegerPref(
-      prefs::kImmersiveModeRevealDelayMs,
-      ImmersiveFullscreenConfiguration::immersive_mode_reveal_delay_ms(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterIntegerPref(
-      prefs::kImmersiveModeRevealXThresholdPixels,
-      ImmersiveFullscreenConfiguration::
-          immersive_mode_reveal_x_threshold_pixels(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-#endif  // USE_ASH
-}
-
 void GesturePrefsObserverFactoryAura::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterDoublePref(
@@ -506,6 +460,10 @@
       prefs::kScrollPredictionSeconds,
       GestureConfiguration::scroll_prediction_seconds(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kShowPressDelayInMS,
+      GestureConfiguration::show_press_delay_in_ms(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 
   // Register for migration.
   registry->RegisterDoublePref(
@@ -515,7 +473,6 @@
 
   RegisterOverscrollPrefs(registry);
   RegisterFlingCurveParameters(registry);
-  RegisterImmersiveModePrefs(registry);
 
   // Register pref for a one-time wipe of all gesture preferences.
   registry->RegisterBooleanPref(
diff --git a/chrome/browser/ui/gesture_prefs_observer_factory_aura.h b/chrome/browser/ui/gesture_prefs_observer_factory_aura.h
index 070f39e..7145e60 100644
--- a/chrome/browser/ui/gesture_prefs_observer_factory_aura.h
+++ b/chrome/browser/ui/gesture_prefs_observer_factory_aura.h
@@ -26,7 +26,6 @@
 
   void RegisterOverscrollPrefs(user_prefs::PrefRegistrySyncable* registry);
   void RegisterFlingCurveParameters(user_prefs::PrefRegistrySyncable* registry);
-  void RegisterImmersiveModePrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // BrowserContextKeyedServiceFactory:
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
diff --git a/chrome/browser/ui/gtk/DEPS b/chrome/browser/ui/gtk/DEPS
new file mode 100644
index 0000000..33ce4be
--- /dev/null
+++ b/chrome/browser/ui/gtk/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/undoview",
+]
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
index 0600574..df7a764 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
@@ -47,6 +47,7 @@
       state_(GDK_WINDOW_STATE_WITHDRAWN),
       is_active_(false),
       content_thinks_its_fullscreen_(false),
+      maximize_pending_(false),
       frameless_(params.frame == ShellWindow::FRAME_NONE),
       always_on_top_(params.always_on_top),
       frame_cursor_(NULL),
@@ -250,7 +251,18 @@
   // consistency with Windows platform. Otherwise the window will be hidden if
   // it has been minimized.
   gtk_window_present(window_);
-  gtk_window_maximize(window_);
+
+  if (!resizable_) {
+    // When the window is not resizable, we still want to make this call succeed
+    // but gtk will not allow it if the window is not resizable. The actual
+    // maximization will happen with the subsequent OnConfigureDebounced call,
+    // that will be triggered when the window manager's resizable property
+    // changes.
+    maximize_pending_ = true;
+    gtk_window_set_resizable(window_, TRUE);
+  } else {
+    gtk_window_maximize(window_);
+  }
 }
 
 void NativeAppWindowGtk::Minimize() {
@@ -432,6 +444,24 @@
   if (!IsFullscreen() && IsFullscreenOrPending()) {
     gtk_window_fullscreen(window_);
   }
+
+  // maximize_pending_ is the boolean that lets us know that the window is in
+  // the process of being maximized but was set as not resizable.
+  // This function will be called twice during the maximization process:
+  // 1. gtk_window_maximize() is called to maximize the window;
+  // 2. gtk_set_resizable(, FALSE) is called to make the window no longer
+  //    resizable.
+  // gtk_window_maximize() will cause ::OnConfigureDebounced to be called
+  // again, at which time we will run into the second step.
+  if (maximize_pending_) {
+    if (!(state_ & GDK_WINDOW_STATE_MAXIMIZED)) {
+      gtk_window_maximize(window_);
+    } else {
+      maximize_pending_ = false;
+      if (!resizable_)
+        gtk_window_set_resizable(window_, FALSE);
+    }
+  }
 }
 
 gboolean NativeAppWindowGtk::OnWindowState(GtkWidget* sender,
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
index 8ba6317..01c4ccd 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
@@ -145,6 +145,9 @@
   // fullscreen, however: some WMs don't support fullscreen.
   bool content_thinks_its_fullscreen_;
 
+  // Represents whether the window is waiting to be maximized.
+  bool maximize_pending_;
+
   // The region is treated as title bar, can be dragged to move
   // and double clicked to maximize.
   scoped_ptr<SkRegion> draggable_region_;
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index e17c22b..6646434 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -22,6 +22,7 @@
 #include "base/nix/xdg_util.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -32,7 +33,6 @@
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
@@ -1029,6 +1029,11 @@
   toolbar_->GetLocationBarView()->ShowStarBubble(url, !already_bookmarked);
 }
 
+void BrowserWindowGtk::ShowTranslateBubble(
+    content::WebContents* contents,
+    TranslateBubbleModel::ViewState view_state) {
+}
+
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
 void BrowserWindowGtk::ShowOneClickSigninBubble(
     OneClickSigninBubbleType type,
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index 9aeac84..0645e62 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -135,6 +135,9 @@
   virtual void ShowUpdateChromeDialog() OVERRIDE;
   virtual void ShowBookmarkBubble(const GURL& url,
                                   bool already_bookmarked) OVERRIDE;
+  virtual void ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) OVERRIDE;
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
   virtual void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
diff --git a/chrome/browser/ui/gtk/download/download_started_animation_gtk.cc b/chrome/browser/ui/gtk/download/download_started_animation_gtk.cc
index 9cb44a0..10d772e 100644
--- a/chrome/browser/ui/gtk/download/download_started_animation_gtk.cc
+++ b/chrome/browser/ui/gtk/download/download_started_animation_gtk.cc
@@ -9,11 +9,6 @@
 #include <gtk/gtk.h>
 
 #include "base/message_loop/message_loop.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "grit/theme_resources.h"
@@ -22,8 +17,6 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/rect.h"
 
-using content::WebContents;
-
 namespace {
 
 // How long to spend moving downwards and fading out after waiting.
@@ -32,10 +25,9 @@
 // The animation framerate.
 const int kFrameRateHz = 60;
 
-class DownloadStartedAnimationGtk : public gfx::LinearAnimation,
-                                    public content::NotificationObserver {
+class DownloadStartedAnimationGtk : public gfx::LinearAnimation {
  public:
-  explicit DownloadStartedAnimationGtk(WebContents* web_contents);
+  explicit DownloadStartedAnimationGtk(content::WebContents* web_contents);
 
   // DownloadStartedAnimation will delete itself, but this is public so
   // that we can use DeleteSoon().
@@ -51,11 +43,6 @@
   // Animation implementation.
   virtual void AnimateToState(double state) OVERRIDE;
 
-  // NotificationObserver
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
   // The top level window that floats over the browser and displays the
   // image.
   GtkWidget* popup_;
@@ -64,9 +51,6 @@
   int width_;
   int height_;
 
-  // The content area holding us.
-  WebContents* web_contents_;
-
   // The content area at the start of the animation. We store this so that the
   // download shelf's resizing of the content area doesn't cause the animation
   // to move around. This means that once started, the animation won't move
@@ -74,17 +58,13 @@
   // much heartbreak.
   gfx::Rect web_contents_bounds_;
 
-  // A scoped container for notification registries.
-  content::NotificationRegistrar registrar_;
-
   DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationGtk);
 };
 
 DownloadStartedAnimationGtk::DownloadStartedAnimationGtk(
-    WebContents* web_contents)
+    content::WebContents* web_contents)
     : gfx::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
-      popup_(NULL),
-      web_contents_(web_contents) {
+      popup_(NULL) {
   static GdkPixbuf* kDownloadImage = NULL;
   if (!kDownloadImage) {
     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -97,19 +77,10 @@
 
   // If we're too small to show the download image, then don't bother -
   // the shelf will be enough.
-  web_contents_->GetView()->GetContainerBounds(&web_contents_bounds_);
+  web_contents->GetView()->GetContainerBounds(&web_contents_bounds_);
   if (web_contents_bounds_.height() < height_)
     return;
 
-  registrar_.Add(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      content::Source<WebContents>(web_contents_));
-  registrar_.Add(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(web_contents_));
-
   // TODO(estade): don't show up on the wrong virtual desktop.
 
   popup_ = gtk_window_new(GTK_WINDOW_POPUP);
@@ -138,9 +109,6 @@
 }
 
 void DownloadStartedAnimationGtk::Reposition() {
-  if (!web_contents_)
-    return;
-
   DCHECK(popup_);
 
   // Align the image with the bottom left of the web contents (so that it
@@ -152,29 +120,13 @@
 }
 
 void DownloadStartedAnimationGtk::Close() {
-  if (!web_contents_)
-    return;
-
   DCHECK(popup_);
 
-  registrar_.Remove(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      content::Source<WebContents>(web_contents_));
-  registrar_.Remove(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(web_contents_));
-
-  web_contents_ = NULL;
   gtk_widget_destroy(popup_);
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
 
 void DownloadStartedAnimationGtk::AnimateToState(double state) {
-  if (!web_contents_)
-    return;
-
   if (state >= 1.0) {
     Close();
   } else {
@@ -189,22 +141,10 @@
   }
 }
 
-void DownloadStartedAnimationGtk::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) {
-    bool visible = *content::Details<bool>(details).ptr();
-    if (visible)
-      return;
-  }
-  Close();
-}
-
 }  // namespace
 
 // static
-void DownloadStartedAnimation::Show(WebContents* web_contents) {
+void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
   // The animation will delete itself.
   new DownloadStartedAnimationGtk(web_contents);
 }
diff --git a/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
index 73adcd0..f2c2055 100644
--- a/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
diff --git a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
index bac15bf..c5d8de5 100644
--- a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
@@ -60,6 +60,7 @@
 void MediaGalleriesDialogGtk::InitWidgets() {
   gtk_util::RemoveAllChildren(contents_.get());
   checkbox_map_.clear();
+  new_checkbox_map_.clear();
   confirm_ = NULL;
 
   GtkWidget* header = gtk_util::LeftAlignMisc(gtk_label_new(
@@ -161,9 +162,7 @@
   gtk_widget_show_all(contents_.get());
 }
 
-void MediaGalleriesDialogGtk::UpdateGallery(
-    const MediaGalleryPrefInfo& gallery,
-    bool permitted) {
+void MediaGalleriesDialogGtk::UpdateGalleries() {
   InitWidgets();
 }
 
@@ -183,7 +182,10 @@
   gtk_box_pack_start(GTK_BOX(hbox), details_label, FALSE, FALSE, 0);
 
   gtk_widget_show(hbox);
-  checkbox_map_[gallery.pref_id] = widget;
+  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
+    checkbox_map_[gallery.pref_id] = widget;
+  else
+    new_checkbox_map_[widget] = gallery;
 
   std::string tooltip_text = UTF16ToUTF8(gallery.GetGalleryTooltip());
   gtk_widget_set_tooltip_text(widget, tooltip_text.c_str());
@@ -194,18 +196,6 @@
   gtk_button_set_label(GTK_BUTTON(widget), label.c_str());
 }
 
-void MediaGalleriesDialogGtk::ForgetGallery(MediaGalleryPrefId gallery) {
-  for (CheckboxMap::iterator iter = checkbox_map_.begin();
-       iter != checkbox_map_.end(); ++iter) {
-    if (iter->first == gallery) {
-      GtkWidget* checkbox = iter->second;
-      checkbox_map_.erase(iter);
-      gtk_widget_destroy(gtk_widget_get_parent(checkbox));
-      return;
-    }
-  }
-}
-
 void MediaGalleriesDialogGtk::OnToggled(GtkWidget* widget) {
   if (confirm_)
     gtk_widget_set_sensitive(confirm_, TRUE);
@@ -216,6 +206,16 @@
       controller_->DidToggleGalleryId(
           iter->first,
           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
+      return;
+    }
+  }
+  for (NewCheckboxMap::const_iterator iter = new_checkbox_map_.begin();
+       iter != new_checkbox_map_.end(); ++iter) {
+    if (iter->first == widget) {
+      controller_->DidToggleNewGallery(
+          iter->second,
+          gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
+      return;
     }
   }
 }
diff --git a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h
index 7a1b74f..ac494e3 100644
--- a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h
@@ -27,9 +27,7 @@
   virtual ~MediaGalleriesDialogGtk();
 
   // MediaGalleriesDialog implementation:
-  virtual void UpdateGallery(const MediaGalleryPrefInfo& gallery,
-                             bool permitted) OVERRIDE;
-  virtual void ForgetGallery(MediaGalleryPrefId gallery) OVERRIDE;
+  virtual void UpdateGalleries() OVERRIDE;
 
   // Event callbacks.
   CHROMEGTK_CALLBACK_0(MediaGalleriesDialogGtk, void, OnToggled);
@@ -44,6 +42,7 @@
   FRIEND_TEST_ALL_PREFIXES(MediaGalleriesDialogTest, ForgetDeletes);
 
   typedef std::map<MediaGalleryPrefId, GtkWidget*> CheckboxMap;
+  typedef std::map<GtkWidget*, MediaGalleryPrefInfo> NewCheckboxMap;
 
   // Creates the widget hierarchy.
   void InitWidgets();
@@ -66,10 +65,12 @@
   // The confirm button.
   GtkWidget* confirm_;
 
-  // A map from MediaGalleryPrefInfo struct (owned by controller) to the
-  // GtkCheckButton that controls it.
+  // A map from MediaGalleryPrefId to the GtkCheckButton that controls it.
   CheckboxMap checkbox_map_;
 
+  // Map for checkboxes of newly-added galleries to their MediaGalleryPrefInfo.
+  NewCheckboxMap new_checkbox_map_;
+
   // True if the user has pressed accept.
   bool accepted_;
 
diff --git a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
index 503b00f..0001944 100644
--- a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
@@ -135,18 +135,18 @@
   MediaGalleryPrefInfo gallery1 = MakePrefInfoForTesting(1);
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(gallery1, true));
-  dialog.UpdateGallery(gallery1, true);
+  dialog.UpdateGalleries();
   EXPECT_EQ(1U, dialog.checkbox_map_.size());
 
   MediaGalleryPrefInfo gallery2 = MakePrefInfoForTesting(2);
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(gallery2, true));
-  dialog.UpdateGallery(gallery2, true);
+  dialog.UpdateGalleries();
   EXPECT_EQ(2U, dialog.checkbox_map_.size());
 
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(gallery2, false));
-  dialog.UpdateGallery(gallery2, false);
+  dialog.UpdateGalleries();
   EXPECT_EQ(2U, dialog.checkbox_map_.size());
 }
 
@@ -169,16 +169,16 @@
   MediaGalleryPrefInfo gallery1 = MakePrefInfoForTesting(1);
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(gallery1, true));
-  dialog.UpdateGallery(gallery1, true);
+  dialog.UpdateGalleries();
   EXPECT_EQ(1U, dialog.checkbox_map_.size());
 
   MediaGalleryPrefInfo gallery2 = MakePrefInfoForTesting(2);
   attached_permissions.push_back(
       MediaGalleriesDialogController::GalleryPermission(gallery2, true));
-  dialog.UpdateGallery(gallery2, true);
+  dialog.UpdateGalleries();
   EXPECT_EQ(2U, dialog.checkbox_map_.size());
 
-  dialog.ForgetGallery(gallery2.pref_id);
   attached_permissions.pop_back();
+  dialog.UpdateGalleries();
   EXPECT_EQ(1U, dialog.checkbox_map_.size());
 }
diff --git a/chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.cc b/chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.cc
index 98d3f48..79a0a45 100644
--- a/chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.cc
+++ b/chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
+#include "components/translate/common/translate_metrics.h"
 #include "grit/generated_resources.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/gtk/gtk_signal_registrar.h"
@@ -90,11 +92,15 @@
 }
 
 void AfterTranslateInfoBar::SetOriginalLanguage(size_t language_index) {
+  UMA_HISTOGRAM_BOOLEAN(
+      translate::GetMetricsName(translate::UMA_MODIFY_ORIGINAL_LANG), true);
   GetDelegate()->set_original_language_index(language_index);
   GetDelegate()->Translate();
 }
 
 void AfterTranslateInfoBar::SetTargetLanguage(size_t language_index) {
+  UMA_HISTOGRAM_BOOLEAN(
+      translate::GetMetricsName(translate::UMA_MODIFY_TARGET_LANG), true);
   GetDelegate()->set_target_language_index(language_index);
   GetDelegate()->Translate();
 }
diff --git a/chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.cc b/chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.cc
index 7040dbd..a6dd390 100644
--- a/chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.cc
+++ b/chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.h"
 
+#include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
+#include "components/translate/common/translate_metrics.h"
 #include "grit/generated_resources.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/gtk/gtk_signal_registrar.h"
@@ -87,6 +89,8 @@
 }
 
 void BeforeTranslateInfoBar::OnLanguageModified(GtkWidget* sender) {
+  UMA_HISTOGRAM_BOOLEAN(
+      translate::GetMetricsName(translate::UMA_MODIFY_ORIGINAL_LANG), true);
   GetDelegate()->set_original_language_index(
       GetLanguageComboboxActiveId(GTK_COMBO_BOX(sender)));
 }
diff --git a/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
index fc86ca2..ba121db 100644
--- a/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
+++ b/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
@@ -889,17 +889,24 @@
     Browser::FormatTitleForDisplay(&title);
   }
 
+  GtkAllocation allocation;
+  gtk_widget_get_allocation(widget, &allocation);
+  gfx::Rect bounds(allocation);
+
+  // Draw the text directly onto the Cairo context. This is necessary for
+  // getting the draw order correct, and automatically applying transformations
+  // such as scaling when a tab is detached.
+  gfx::CanvasSkiaPaintCairo canvas(cr, bounds.size(), true);
+
   SkColor title_color = IsSelected() ? selected_title_color_
                                      : unselected_title_color_;
 
-  DrawTextOntoCairoSurface(cr,
-                           title,
-                           *title_font_,
-                           title_bounds_,
-                           title_bounds_,
-                           title_color,
-                           base::i18n::IsRTL() ? gfx::Canvas::TEXT_ALIGN_RIGHT :
-                           gfx::Canvas::TEXT_ALIGN_LEFT);
+  // Disable subpixel rendering. This does not work because the canvas has a
+  // transparent background.
+  int flags = gfx::Canvas::NO_ELLIPSIS | gfx::Canvas::NO_SUBPIXEL_RENDERING;
+  canvas.DrawFadeTruncatingStringRectWithFlags(
+      title, gfx::Canvas::TruncateFadeTail, gfx::FontList(*title_font_),
+      title_color, title_bounds_, flags);
 }
 
 void TabRendererGtk::PaintIcon(GtkWidget* widget, cairo_t* cr) {
diff --git a/chrome/browser/ui/gtk/task_manager_gtk.cc b/chrome/browser/ui/gtk/task_manager_gtk.cc
index 32cb85c..43788e0 100644
--- a/chrome/browser/ui/gtk/task_manager_gtk.cc
+++ b/chrome/browser/ui/gtk/task_manager_gtk.cc
@@ -15,11 +15,11 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/memory_purger.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
diff --git a/chrome/browser/ui/gtk/view_id_util_browsertest.cc b/chrome/browser/ui/gtk/view_id_util_browsertest.cc
index 9e71fcd..6695645 100644
--- a/chrome/browser/ui/gtk/view_id_util_browsertest.cc
+++ b/chrome/browser/ui/gtk/view_id_util_browsertest.cc
@@ -45,7 +45,8 @@
         i == VIEW_ID_TAB ||
         i == VIEW_ID_FEEDBACK_BUTTON ||
         i == VIEW_ID_SCRIPT_BUBBLE ||
-        i == VIEW_ID_MIC_SEARCH_BUTTON) {
+        i == VIEW_ID_MIC_SEARCH_BUTTON ||
+        i == VIEW_ID_TRANSLATE_BUTTON) {
       continue;
     }
 
diff --git a/chrome/browser/ui/immersive_fullscreen_configuration.cc b/chrome/browser/ui/immersive_fullscreen_configuration.cc
deleted file mode 100644
index f43ca5b..0000000
--- a/chrome/browser/ui/immersive_fullscreen_configuration.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 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/immersive_fullscreen_configuration.h"
-
-#if defined(OS_CHROMEOS)
-#include "ash/ash_switches.h"
-#include "base/command_line.h"
-#include "chrome/common/chrome_switches.h"
-#endif  // defined(OS_CHROMEOS)
-
-// static
-bool ImmersiveFullscreenConfiguration::UseImmersiveFullscreen() {
-#if defined(OS_CHROMEOS)
-  CommandLine* command = CommandLine::ForCurrentProcess();
-  // Kiosk mode needs the whole screen.
-  if (command->HasSwitch(switches::kKioskMode))
-    return false;
-  // Immersive fullscreen is on by default. If you change the default you must
-  // change the enable function below and BrowserTest FullscreenBookmarkBar
-  // (which cannot depend on this function due to DEPS).
-  return !command->HasSwitch(ash::switches::kAshDisableImmersiveFullscreen);
-#endif
-  return false;
-}
-
-// static
-// Implemented here so all the code dealing with flags lives in one place.
-void ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest() {
-  // Immersive fullscreen is on by default. If we turn it off, this function
-  // will need to add kAshEnableImmersiveFullscreen to the command line.
-}
-
-int ImmersiveFullscreenConfiguration::immersive_mode_reveal_delay_ms_ = 200;
-int
-ImmersiveFullscreenConfiguration::immersive_mode_reveal_x_threshold_pixels_ = 3;
diff --git a/chrome/browser/ui/immersive_fullscreen_configuration.h b/chrome/browser/ui/immersive_fullscreen_configuration.h
deleted file mode 100644
index 2845b6f..0000000
--- a/chrome/browser/ui/immersive_fullscreen_configuration.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 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_IMMERSIVE_FULLSCREEN_CONFIGURATION_H_
-#define CHROME_BROWSER_UI_IMMERSIVE_FULLSCREEN_CONFIGURATION_H_
-
-#include "base/basictypes.h"
-
-class ImmersiveFullscreenConfiguration {
- public:
-  // Returns true if immersive mode should be used for fullscreen based on
-  // command line flags.
-  static bool UseImmersiveFullscreen();
-
-  static void EnableImmersiveFullscreenForTest();
-
-  static int immersive_mode_reveal_delay_ms() {
-    return immersive_mode_reveal_delay_ms_;
-  }
-  static void set_immersive_mode_reveal_delay_ms(int val) {
-    immersive_mode_reveal_delay_ms_ = val;
-  }
-
-  static int immersive_mode_reveal_x_threshold_pixels() {
-    return immersive_mode_reveal_x_threshold_pixels_;
-  }
-  static void set_immersive_mode_reveal_x_threshold_pixels(int val) {
-    immersive_mode_reveal_x_threshold_pixels_ = val;
-  }
-
- private:
-  // The time after which the edge trigger fires and top-chrome is revealed in
-  // immersive fullscreen. This is after the mouse stops moving.
-  static int immersive_mode_reveal_delay_ms_;
-
-  // Threshold for horizontal mouse movement at the top of the screen for the
-  // mouse to be considered "moving" in immersive fullscreen. This allows the
-  // user to trigger a reveal even if their fingers are not completely still on
-  // the trackpad or mouse.
-  static int immersive_mode_reveal_x_threshold_pixels_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ImmersiveFullscreenConfiguration);
-};
-
-#endif  // CHROME_BROWSER_UI_IMMERSIVE_FULLSCREEN_CONFIGURATION_H_
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
index 39115d6..6b75c4a 100644
--- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
@@ -171,7 +171,8 @@
       gtk_menu_(NULL),
       menu_model_(NULL),
       icon_change_count_(0),
-      block_activation_(false) {
+      block_activation_(false),
+      weak_factory_(this) {
   EnsureMethodsLoaded();
   tool_tip_ = UTF16ToUTF8(tool_tip);
   SetImage(image);
@@ -213,7 +214,7 @@
                  icon_change_count_,
                  id_),
       base::Bind(&AppIndicatorIcon::SetImageFromFile,
-                 base::Unretained(this)));
+                 weak_factory_.GetWeakPtr()));
 }
 
 void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.h b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
index 1d70796..8b0f0d9 100644
--- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_H_
 
 #include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
 #include "ui/views/linux_ui/status_icon_linux.h"
 
@@ -71,6 +72,8 @@
   int icon_change_count_;
   bool block_activation_;
 
+  base::WeakPtrFactory<AppIndicatorIcon> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(AppIndicatorIcon);
 };
 
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
index c7d6b83..d28f115 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/libgtk2ui/select_file_dialog_impl.h"
 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
 #include "chrome/browser/ui/libgtk2ui/unity_service.h"
+#include "chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h"
 #include "grit/theme_resources.h"
 #include "grit/ui_resources.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -294,7 +295,9 @@
 
 Gtk2UI::Gtk2UI() {
   GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
+}
 
+void Gtk2UI::Initialize() {
   // Create our fake widgets.
   fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   fake_frame_ = chrome_gtk_frame_new();
@@ -490,6 +493,12 @@
                                                  trailing_buttons_));
 }
 
+scoped_ptr<ui::LinuxInputMethodContext> Gtk2UI::CreateInputMethodContext(
+    ui::LinuxInputMethodContextDelegate* delegate) const {
+  return scoped_ptr<ui::LinuxInputMethodContext>(
+      new X11InputMethodContextImplGtk2(delegate));
+}
+
 ui::SelectFileDialog* Gtk2UI::CreateSelectFileDialog(
     ui::SelectFileDialog::Listener* listener,
     ui::SelectFilePolicy* policy) const {
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.h b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
index da6e908..cb7e08c 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.h
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
@@ -41,12 +41,17 @@
     const std::vector<views::FrameButton>& leading_buttons,
     const std::vector<views::FrameButton>& trailing_buttons);
 
+  // ui::LinuxInputMethodContextFactory:
+  virtual scoped_ptr<ui::LinuxInputMethodContext> CreateInputMethodContext(
+      ui::LinuxInputMethodContextDelegate* delegate) const OVERRIDE;
+
   // ui::LinuxShellDialog:
   virtual ui::SelectFileDialog* CreateSelectFileDialog(
       ui::SelectFileDialog::Listener* listener,
       ui::SelectFilePolicy* policy) const OVERRIDE;
 
   // ui::LinuxUI:
+  virtual void Initialize() OVERRIDE;
   virtual bool UseNativeTheme() const OVERRIDE;
   virtual gfx::Image GetThemeImageNamed(int id) const OVERRIDE;
   virtual bool GetColor(int id, SkColor* color) const OVERRIDE;
diff --git a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
index 6c50d8b..064b64b 100644
--- a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
+++ b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
@@ -59,6 +59,8 @@
         'skia_utils_gtk2.h',
         'unity_service.cc',
         'unity_service.h',
+        'x11_input_method_context_impl_gtk2.cc',
+        'x11_input_method_context_impl_gtk2.h',
       ],
     },
   ],
diff --git a/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc b/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc
index 3626255..77863f1 100644
--- a/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc
+++ b/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc
@@ -42,7 +42,7 @@
   // display server ever happens. Otherwise, this will crash.
   XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window),
                        GDK_WINDOW_XID(gdk_window),
-                       parent->GetRootWindow()->GetAcceleratedWidget());
+                       parent->GetDispatcher()->GetAcceleratedWidget());
 
   // We also set the |parent| as a property of |dialog|, so that we can unlink
   // the two later.
diff --git a/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.cc b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.cc
new file mode 100644
index 0000000..c9dd7d2
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.cc
@@ -0,0 +1,345 @@
+// Copyright 2013 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/libgtk2ui/x11_input_method_context_impl_gtk2.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+#include <gtk/gtk.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include "base/environment.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/composition_text.h"
+#include "ui/base/ime/composition_text_util_pango.h"
+#include "ui/base/ime/text_input_client.h"
+
+namespace {
+
+// Constructs a GdkEventKey from a XKeyEvent and returns it.  Otherwise,
+// returns NULL.  The returned GdkEvent must be freed by gdk_event_free.
+GdkEvent* GdkEventFromXKeyEvent(XKeyEvent& xkey, bool is_modifier) {
+  DCHECK(xkey.type == KeyPress || xkey.type == KeyRelease);
+
+  // Get a GdkDisplay.
+  GdkDisplay* display = gdk_x11_lookup_xdisplay(xkey.display);
+  if (!display) {
+    // Fall back to the default display.
+    display = gdk_display_get_default();
+  }
+  if (!display) {
+    LOG(ERROR) << "Cannot get a GdkDisplay for a key event.";
+    return NULL;
+  }
+  // Get a keysym and group.
+  KeySym keysym = NoSymbol;
+  guint8 keyboard_group = 0;
+  XLookupString(&xkey, NULL, 0, &keysym, NULL);
+  GdkKeymap* keymap = gdk_keymap_get_for_display(display);
+  GdkKeymapKey* keys = NULL;
+  guint* keyvals = NULL;
+  gint n_entries = 0;
+  if (keymap &&
+      gdk_keymap_get_entries_for_keycode(keymap, xkey.keycode,
+                                         &keys, &keyvals, &n_entries)) {
+    for (gint i = 0; i < n_entries; ++i) {
+      if (keyvals[i] == keysym) {
+        keyboard_group = keys[i].group;
+        break;
+      }
+    }
+  }
+  g_free(keys);
+  keys = NULL;
+  g_free(keyvals);
+  keyvals = NULL;
+  // Get a GdkWindow.
+  GdkWindow* window = gdk_x11_window_lookup_for_display(display, xkey.window);
+  if (window)
+    g_object_ref(window);
+  else
+    window = gdk_x11_window_foreign_new_for_display(display, xkey.window);
+  if (!window) {
+    LOG(ERROR) << "Cannot get a GdkWindow for a key event.";
+    return NULL;
+  }
+
+  // Create a GdkEvent.
+  GdkEventType event_type = xkey.type == KeyPress ?
+                            GDK_KEY_PRESS : GDK_KEY_RELEASE;
+  GdkEvent* event = gdk_event_new(event_type);
+  event->key.type = event_type;
+  event->key.window = window;
+  // GdkEventKey and XKeyEvent share the same definition for time and state.
+  event->key.send_event = xkey.send_event;
+  event->key.time = xkey.time;
+  event->key.state = xkey.state;
+  event->key.keyval = keysym;
+  event->key.length = 0;
+  event->key.string = NULL;
+  event->key.hardware_keycode = xkey.keycode;
+  event->key.group = keyboard_group;
+  event->key.is_modifier = is_modifier;
+  return event;
+}
+
+}  // namespace
+
+namespace libgtk2ui {
+
+X11InputMethodContextImplGtk2::X11InputMethodContextImplGtk2(
+    ui::LinuxInputMethodContextDelegate* delegate)
+    : delegate_(delegate),
+      gtk_context_simple_(NULL),
+      gtk_multicontext_(NULL),
+      gtk_context_(NULL) {
+  CHECK(delegate_);
+
+  {
+    // Force a IBus IM context to run in synchronous mode.
+    //
+    // Background: IBus IM context runs by default in asynchronous mode.  In
+    // this mode, gtk_im_context_filter_keypress() consumes all the key events
+    // and returns true while asynchronously sending the event to an underlying
+    // IME implementation.  When the event has not actually been consumed by
+    // the underlying IME implementation, the context pushes the event back to
+    // the GDK event queue marking the event as already handled by the IBus IM
+    // context.
+    //
+    // The problem here is that those pushed-back GDK events are never handled
+    // when base::MessagePumpX11 is used, which only handles X events.  So, we
+    // make a IBus IM context run in synchronous mode by setting an environment
+    // variable.  This is only the interface to change the mode.
+    //
+    // Another possible solution is to use GDK event loop instead of X event
+    // loop.
+    scoped_ptr<base::Environment> env(base::Environment::Create());
+    env->SetVar("IBUS_ENABLE_SYNC_MODE", "1");
+  }
+
+  {
+    XModifierKeymap* keymap = XGetModifierMapping(
+        base::MessagePumpForUI::GetDefaultXDisplay());
+    for (int i = 0; i < 8 * keymap->max_keypermod; ++i) {
+      if (keymap->modifiermap[i])
+        modifier_keycodes_.insert(keymap->modifiermap[i]);
+    }
+    XFreeModifiermap(keymap);
+  }
+
+  gtk_context_simple_ = gtk_im_context_simple_new();
+  gtk_multicontext_ = gtk_im_multicontext_new();
+
+  GtkIMContext* contexts[] = {gtk_context_simple_, gtk_multicontext_};
+  for (size_t i = 0; i < arraysize(contexts); ++i) {
+    g_signal_connect(contexts[i], "commit",
+                     G_CALLBACK(OnCommitThunk), this);
+    g_signal_connect(contexts[i], "preedit-changed",
+                     G_CALLBACK(OnPreeditChangedThunk), this);
+    g_signal_connect(contexts[i], "preedit-end",
+                     G_CALLBACK(OnPreeditEndThunk), this);
+    g_signal_connect(contexts[i], "preedit-start",
+                     G_CALLBACK(OnPreeditStartThunk), this);
+    // TODO(yukishiino): Handle operations on surrounding text.
+    // "delete-surrounding" and "retrieve-surrounding" signals should be
+    // handled.
+  }
+}
+
+X11InputMethodContextImplGtk2::~X11InputMethodContextImplGtk2() {
+  gtk_context_ = NULL;
+  if (gtk_context_simple_) {
+    g_object_unref(gtk_context_simple_);
+    gtk_context_simple_ = NULL;
+  }
+  if (gtk_multicontext_) {
+    g_object_unref(gtk_multicontext_);
+    gtk_multicontext_ = NULL;
+  }
+}
+
+// Overriden from ui::LinuxInputMethodContext
+
+bool X11InputMethodContextImplGtk2::DispatchKeyEvent(
+    const base::NativeEvent& native_key_event) {
+  // The caller must call Focus() first.
+  if (!gtk_context_)
+    return false;
+
+  // Translate a XKeyEvent to a GdkEventKey.
+  GdkEvent* event = GdkEventFromXKeyEvent(
+      native_key_event->xkey,
+      IsKeycodeModifierKey(native_key_event->xkey.keycode));
+  if (!event) {
+    LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent.";
+    return false;
+  }
+
+  // Set the client window and cursor location.
+  gtk_im_context_set_client_window(gtk_context_, event->key.window);
+  // Convert the last known caret bounds relative to the screen coordinates
+  // to a GdkRectangle relative to the client window.
+  gint x = 0;
+  gint y = 0;
+  gdk_window_get_origin(event->key.window, &x, &y);
+  GdkRectangle rect = {last_caret_bounds_.x() - x,
+                       last_caret_bounds_.y() - y,
+                       last_caret_bounds_.width(),
+                       last_caret_bounds_.height()};
+  gtk_im_context_set_cursor_location(gtk_context_, &rect);
+
+  // Let an IME handle the key event.
+  commit_signal_trap_.StartTrap(event->key.keyval);
+  const gboolean handled = gtk_im_context_filter_keypress(gtk_context_,
+                                                          &event->key);
+  commit_signal_trap_.StopTrap();
+  gdk_event_free(event);
+
+  return handled && !commit_signal_trap_.IsSignalCaught();
+}
+
+void X11InputMethodContextImplGtk2::Reset() {
+  // Reset all the states of the context, not only preedit, caret but also
+  // focus.
+  gtk_context_ = NULL;
+  gtk_im_context_reset(gtk_context_simple_);
+  gtk_im_context_reset(gtk_multicontext_);
+  gtk_im_context_focus_out(gtk_context_simple_);
+  gtk_im_context_focus_out(gtk_multicontext_);
+}
+
+base::i18n::TextDirection X11InputMethodContextImplGtk2::GetInputTextDirection()
+    const {
+  switch (gdk_keymap_get_direction(gdk_keymap_get_default())) {
+    case PANGO_DIRECTION_LTR:
+    case PANGO_DIRECTION_TTB_LTR:
+    case PANGO_DIRECTION_WEAK_LTR:
+      return base::i18n::LEFT_TO_RIGHT;
+    case PANGO_DIRECTION_RTL:
+    case PANGO_DIRECTION_TTB_RTL:
+    case PANGO_DIRECTION_WEAK_RTL:
+      return base::i18n::RIGHT_TO_LEFT;
+    case PANGO_DIRECTION_NEUTRAL:
+    default:
+      return base::i18n::UNKNOWN_DIRECTION;
+  }
+}
+
+void X11InputMethodContextImplGtk2::OnTextInputTypeChanged(
+    ui::TextInputType text_input_type) {
+  switch (text_input_type) {
+    case ui::TEXT_INPUT_TYPE_NONE:
+    case ui::TEXT_INPUT_TYPE_PASSWORD:
+      gtk_context_ = gtk_context_simple_;
+      break;
+    default:
+      gtk_context_ = gtk_multicontext_;
+  }
+  gtk_im_context_focus_in(gtk_context_);
+}
+
+void X11InputMethodContextImplGtk2::OnCaretBoundsChanged(
+    const gfx::Rect& caret_bounds) {
+  // Remember the caret bounds so that we can set the cursor location later.
+  // gtk_im_context_set_cursor_location() takes the location relative to the
+  // client window, which is unknown at this point.  So we'll call
+  // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where
+  // (and only where) we know the client window.
+  last_caret_bounds_ = caret_bounds;
+}
+
+// private:
+
+bool X11InputMethodContextImplGtk2::IsKeycodeModifierKey(
+    unsigned int keycode) const {
+  return modifier_keycodes_.find(keycode) != modifier_keycodes_.end();
+}
+
+// GtkIMContext event handlers.
+
+void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context,
+                                             gchar* text) {
+  if (context != gtk_context_)
+    return;
+
+  const base::string16& text_in_utf16 = UTF8ToUTF16(text);
+  // If an underlying IME is emitting the "commit" signal to insert a character
+  // for a direct input key event, ignores the insertion of the character at
+  // this point, because we have to call DispatchKeyEventPostIME() for direct
+  // input key events.  DispatchKeyEvent() takes care of the trapped character
+  // and calls DispatchKeyEventPostIME().
+  if (commit_signal_trap_.Trap(text_in_utf16))
+    return;
+
+  delegate_->OnCommit(text_in_utf16);
+}
+
+void X11InputMethodContextImplGtk2::OnPreeditChanged(GtkIMContext* context) {
+  if (context != gtk_context_)
+    return;
+
+  gchar* str = NULL;
+  PangoAttrList* attrs = NULL;
+  gint cursor_pos = 0;
+  gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos);
+  ui::CompositionText composition_text;
+  ui::ExtractCompositionTextFromGtkPreedit(str, attrs, cursor_pos,
+                                           &composition_text);
+  g_free(str);
+  pango_attr_list_unref(attrs);
+
+  delegate_->OnPreeditChanged(composition_text);
+}
+
+void X11InputMethodContextImplGtk2::OnPreeditEnd(GtkIMContext* context) {
+  if (context != gtk_context_)
+    return;
+
+  delegate_->OnPreeditEnd();
+}
+
+void X11InputMethodContextImplGtk2::OnPreeditStart(GtkIMContext* context) {
+  if (context != gtk_context_)
+    return;
+
+  delegate_->OnPreeditStart();
+}
+
+// GtkCommitSignalTrap
+
+X11InputMethodContextImplGtk2::GtkCommitSignalTrap::GtkCommitSignalTrap()
+    : is_trap_enabled_(false),
+      gdk_event_key_keyval_(GDK_KEY_VoidSymbol),
+      is_signal_caught_(false) {}
+
+void X11InputMethodContextImplGtk2::GtkCommitSignalTrap::StartTrap(
+    guint keyval) {
+  is_signal_caught_ = false;
+  gdk_event_key_keyval_ = keyval;
+  is_trap_enabled_ = true;
+}
+
+void X11InputMethodContextImplGtk2::GtkCommitSignalTrap::StopTrap() {
+  is_trap_enabled_ = false;
+}
+
+bool X11InputMethodContextImplGtk2::GtkCommitSignalTrap::Trap(
+    const base::string16& text) {
+  DCHECK(!is_signal_caught_);
+  if (is_trap_enabled_ &&
+      text.length() == 1 &&
+      text[0] == gdk_keyval_to_unicode(gdk_event_key_keyval_)) {
+    is_signal_caught_ = true;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+}  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h
new file mode 100644
index 0000000..2ea0d4e
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h
@@ -0,0 +1,116 @@
+// Copyright 2013 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_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
+#define CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/strings/string16.h"
+#include "ui/base/glib/glib_integers.h"
+#include "ui/base/glib/glib_signal.h"
+#include "ui/base/ime/linux/linux_input_method_context.h"
+#include "ui/gfx/rect.h"
+
+typedef struct _GtkIMContext GtkIMContext;
+
+namespace libgtk2ui {
+
+// An implementation of LinuxInputMethodContext which is based on X11 event loop
+// and uses GtkIMContext(gtk-immodule) as a bridge from/to underlying IMEs.
+class X11InputMethodContextImplGtk2 : public ui::LinuxInputMethodContext {
+ public:
+  explicit X11InputMethodContextImplGtk2(
+      ui::LinuxInputMethodContextDelegate* delegate);
+  virtual ~X11InputMethodContextImplGtk2();
+
+  // Overriden from ui::LinuxInputMethodContext
+  virtual bool DispatchKeyEvent(const base::NativeEvent& native_key_event)
+      OVERRIDE;
+  virtual void Reset() OVERRIDE;
+  virtual base::i18n::TextDirection GetInputTextDirection() const OVERRIDE;
+  virtual void OnTextInputTypeChanged(ui::TextInputType text_input_type)
+      OVERRIDE;
+  virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) OVERRIDE;
+
+ private:
+  // Returns true if the hardware |keycode| is assigned to a modifier key.
+  bool IsKeycodeModifierKey(unsigned int keycode) const;
+
+  // GtkIMContext event handlers.  They are shared among |gtk_context_simple_|
+  // and |gtk_multicontext_|.
+  CHROMEG_CALLBACK_1(X11InputMethodContextImplGtk2, void, OnCommit,
+                     GtkIMContext*, gchar*);
+  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditChanged,
+                     GtkIMContext*);
+  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditEnd,
+                     GtkIMContext*);
+  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditStart,
+                     GtkIMContext*);
+
+  // A set of callback functions.  Must not be NULL.
+  ui::LinuxInputMethodContextDelegate* delegate_;
+
+  // IME's input context used for TEXT_INPUT_TYPE_NONE and
+  // TEXT_INPUT_TYPE_PASSWORD.
+  GtkIMContext* gtk_context_simple_;
+  // IME's input context used for the other text input types.
+  GtkIMContext* gtk_multicontext_;
+
+  // An alias to |gtk_context_simple_| or |gtk_multicontext_| depending on the
+  // text input type.  Can be NULL when it's not focused.
+  GtkIMContext* gtk_context_;
+
+  // Last known caret bounds relative to the screen coordinates.
+  gfx::Rect last_caret_bounds_;
+
+  // A set of hardware keycodes of modifier keys.
+  base::hash_set<unsigned int> modifier_keycodes_;
+
+  // The helper class to trap GTK+'s "commit" signal for direct input key
+  // events.
+  //
+  // gtk_im_context_filter_keypress() emits "commit" signal in order to insert
+  // a character which is not actually processed by a IME.  This behavior seems,
+  // in Javascript world, that a keydown event with keycode = VKEY_PROCESSKEY
+  // (= 229) is fired.  So we have to trap such "commit" signal for direct input
+  // key events.  This class helps to trap such events.
+  class GtkCommitSignalTrap {
+   public:
+    GtkCommitSignalTrap();
+
+    // Enables the trap which monitors a direct input key event of |keyval|.
+    void StartTrap(guint keyval);
+
+    // Disables the trap.
+    void StopTrap();
+
+    // Checks if the committed |text| has come from a direct input key event,
+    // and returns true in that case.  Once it's trapped, IsSignalCaught()
+    // returns true.
+    // Must be called at most once between StartTrap() and StopTrap().
+    bool Trap(const base::string16& text);
+
+    // Returns true if a direct input key event is detected.
+    bool IsSignalCaught() const { return is_signal_caught_; }
+
+   private:
+    bool is_trap_enabled_;
+    guint gdk_event_key_keyval_;
+    bool is_signal_caught_;
+
+    DISALLOW_COPY_AND_ASSIGN(GtkCommitSignalTrap);
+  };
+
+  GtkCommitSignalTrap commit_signal_trap_;
+
+  FRIEND_TEST_ALL_PREFIXES(X11InputMethodContextImplGtk2FriendTest,
+                           GtkCommitSignalTrap);
+
+  DISALLOW_COPY_AND_ASSIGN(X11InputMethodContextImplGtk2);
+};
+
+}  // namespace libgtk2ui
+
+#endif  // CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
diff --git a/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2_unittest.cc b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2_unittest.cc
new file mode 100644
index 0000000..4c72234
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright 2013 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/libgtk2ui/x11_input_method_context_impl_gtk2.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace libgtk2ui {
+
+class X11InputMethodContextImplGtk2FriendTest : public testing::Test {
+};
+
+TEST_F(X11InputMethodContextImplGtk2FriendTest, GtkCommitSignalTrap) {
+  libgtk2ui::X11InputMethodContextImplGtk2::GtkCommitSignalTrap trap;
+
+  // Test the initial state.
+  EXPECT_FALSE(trap.IsSignalCaught());
+  EXPECT_FALSE(trap.Trap(base::string16()));
+  EXPECT_FALSE(trap.IsSignalCaught());
+
+  // Cases which don't match the target keyval.
+  trap.StartTrap('t');
+  EXPECT_FALSE(trap.Trap(UTF8ToUTF16("T")));
+  EXPECT_FALSE(trap.IsSignalCaught());
+  EXPECT_FALSE(trap.Trap(UTF8ToUTF16("true")));
+  EXPECT_FALSE(trap.IsSignalCaught());
+
+  // Do not catch when the trap is not activated.
+  trap.StopTrap();
+  EXPECT_FALSE(trap.Trap(UTF8ToUTF16("t")));
+  EXPECT_FALSE(trap.IsSignalCaught());
+
+  // Successive calls don't break anything.
+  trap.StopTrap();
+  trap.StopTrap();
+  EXPECT_FALSE(trap.Trap(UTF8ToUTF16("t")));
+  EXPECT_FALSE(trap.IsSignalCaught());
+  trap.StartTrap('f');
+  trap.StartTrap('t');
+  EXPECT_TRUE(trap.Trap(UTF8ToUTF16("t")));
+  EXPECT_TRUE(trap.IsSignalCaught());
+
+  // StartTrap() resets the state.
+  trap.StartTrap('t');
+  EXPECT_FALSE(trap.IsSignalCaught());
+  // Many times calls to Trap() are okay.
+  EXPECT_FALSE(trap.Trap(UTF8ToUTF16("f")));
+  EXPECT_FALSE(trap.IsSignalCaught());
+  EXPECT_TRUE(trap.Trap(UTF8ToUTF16("t")));
+  EXPECT_TRUE(trap.IsSignalCaught());
+}
+
+}  // namespace libgtk2ui
diff --git a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
index 952497c..e63ec10 100644
--- a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
+++ b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
@@ -67,7 +67,7 @@
     TemplateURL* template_url,
     const AutocompleteMatch& match,
     WindowOpenDisposition disposition) {
-  if (!template_url->IsExtensionKeyword())
+  if (template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)
     return false;
 
   // Strip the keyword + leading space off the input.
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
index 589fe2d..2ad74b4 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
@@ -588,7 +588,9 @@
     // Internet Explorer, but not Firefox.
     const AutocompleteInput& old_input = autocomplete_controller()->input();
     AutocompleteInput input(
-      old_input.text(), old_input.cursor_position(), ASCIIToUTF16("com"),
+      has_temporary_text_ ?
+          UserTextFromDisplayText(view_->GetText())  : old_input.text(),
+      old_input.cursor_position(), ASCIIToUTF16("com"),
       GURL(), old_input.current_page_classification(),
       old_input.prevent_inline_autocomplete(), old_input.prefer_keyword(),
       old_input.allow_exact_keyword_match(), old_input.matches_requested());
diff --git a/chrome/browser/ui/omnibox/omnibox_popup_model.cc b/chrome/browser/ui/omnibox/omnibox_popup_model.cc
index 09102d1..2f782cd 100644
--- a/chrome/browser/ui/omnibox/omnibox_popup_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_popup_model.cc
@@ -192,7 +192,8 @@
     const AutocompleteMatch& match) const {
   Profile* profile = edit_model_->profile();
   const TemplateURL* template_url = match.GetTemplateURL(profile, false);
-  if (template_url && template_url->IsExtensionKeyword()) {
+  if (template_url &&
+      (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
     return extensions::OmniboxAPI::Get(profile)->GetOmniboxPopupIcon(
         template_url->GetExtensionId());
   }
diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc
index 341c903..0549d50 100644
--- a/chrome/browser/ui/panels/panel_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_browsertest.cc
@@ -1421,7 +1421,7 @@
 
   // Send unload notification on the first extension.
   extensions::UnloadedExtensionInfo details(
-      extension.get(), extension_misc::UNLOAD_REASON_UNINSTALL);
+      extension.get(), extensions::UnloadedExtensionInfo::REASON_UNINSTALL);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::Source<Profile>(browser()->profile()),
diff --git a/chrome/browser/ui/pdf/pdf_browsertest.cc b/chrome/browser/ui/pdf/pdf_browsertest.cc
index 1228f3c..72a9a59 100644
--- a/chrome/browser/ui/pdf/pdf_browsertest.cc
+++ b/chrome/browser/ui/pdf/pdf_browsertest.cc
@@ -44,10 +44,7 @@
   PDFBrowserTest()
       : snapshot_different_(true),
         next_dummy_search_value_(0),
-        load_stop_notification_count_(0),
-        pdf_test_server_(
-            content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::IO)) {
+        load_stop_notification_count_(0) {
     pdf_test_server_.ServeFilesFromDirectory(
         base::FilePath(FILE_PATH_LITERAL("pdf/test")));
   }
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 7e16914..8b14bc3 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -444,10 +444,6 @@
       1.0,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
-      prefs::kWebKitFontScaleFactorQuirk,
-      true,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterBooleanPref(
       prefs::kWebKitForceEnableZoom,
       pref_defaults.force_enable_zoom,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index 8307c64..526c3b3 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/search/instant_controller.h"
 
-#include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -31,7 +30,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "net/base/escape.h"
@@ -44,32 +42,6 @@
 
 namespace {
 
-// For reporting Instant navigations.
-enum InstantNavigation {
-  INSTANT_NAVIGATION_LOCAL_CLICK = 0,
-  INSTANT_NAVIGATION_LOCAL_SUBMIT = 1,
-  INSTANT_NAVIGATION_ONLINE_CLICK = 2,
-  INSTANT_NAVIGATION_ONLINE_SUBMIT = 3,
-  INSTANT_NAVIGATION_NONEXTENDED = 4,
-  INSTANT_NAVIGATION_MAX = 5
-};
-
-void RecordNavigationHistogram(bool is_local, bool is_click, bool is_extended) {
-  InstantNavigation navigation;
-  if (!is_extended) {
-    navigation = INSTANT_NAVIGATION_NONEXTENDED;
-  } else if (is_local) {
-    navigation = is_click ? INSTANT_NAVIGATION_LOCAL_CLICK :
-                            INSTANT_NAVIGATION_LOCAL_SUBMIT;
-  } else {
-    navigation = is_click ? INSTANT_NAVIGATION_ONLINE_CLICK :
-                            INSTANT_NAVIGATION_ONLINE_SUBMIT;
-  }
-  UMA_HISTOGRAM_ENUMERATION("InstantExtended.InstantNavigation",
-                            navigation,
-                            INSTANT_NAVIGATION_MAX);
-}
-
 bool IsContentsFrom(const InstantPage* page,
                     const content::WebContents* contents) {
   return page && (page->contents() == contents);
@@ -158,7 +130,7 @@
   // we don't want to redirect and nuke their forward history stack.
   const GURL& current_url = contents->GetURL();
   GURL instant_url = chrome::GetInstantURL(profile(),
-                                           chrome::kDisableStartMargin);
+                                           chrome::kDisableStartMargin, false);
   if (instant_tab_->IsLocal() ||
       !search::MatchesOriginAndPath(instant_url, current_url) ||
       !current_url.ref().empty() ||
@@ -289,37 +261,6 @@
   UpdateInfoForInstantTab();
 }
 
-void InstantController::NavigateToURL(const content::WebContents* contents,
-                                      const GURL& url,
-                                      content::PageTransition transition,
-                                      WindowOpenDisposition disposition,
-                                      bool is_search_type) {
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "NavigateToURL: url='%s'", url.spec().c_str()));
-
-  // TODO(samarth): handle case where contents are no longer "active" (e.g. user
-  // has switched tabs).
-  if (transition == content::PAGE_TRANSITION_AUTO_BOOKMARK) {
-    content::RecordAction(
-        content::UserMetricsAction("InstantExtended.MostVisitedClicked"));
-  } else {
-    // Exclude navigation by Most Visited click and searches.
-    if (!is_search_type)
-      RecordNavigationHistogram(UsingLocalPage(), true, true);
-  }
-  browser_->OpenURL(url, transition, disposition);
-}
-
-void InstantController::PasteIntoOmnibox(const content::WebContents* contents,
-      const string16& text) {
-  if (search_mode_.is_origin_default())
-    return;
-
-  DCHECK(IsContentsFrom(instant_tab(), contents));
-
-  browser_->PasteIntoOmnibox(text);
-}
-
 void InstantController::ResetInstantTab() {
   if (!search_mode_.is_origin_default()) {
     content::WebContents* active_tab = browser_->GetActiveWebContents();
@@ -355,10 +296,6 @@
       omnibox_focus_state_ == OMNIBOX_FOCUS_VISIBLE;
 }
 
-bool InstantController::UsingLocalPage() const {
-  return instant_tab_ && instant_tab_->IsLocal();
-}
-
 void InstantController::RedirectToLocalNTP(content::WebContents* contents) {
   contents->GetController().LoadURL(
       GURL(chrome::kChromeSearchLocalNtpUrl),
diff --git a/chrome/browser/ui/search/instant_controller.h b/chrome/browser/ui/search/instant_controller.h
index 845032c..0087935 100644
--- a/chrome/browser/ui/search/instant_controller.h
+++ b/chrome/browser/ui/search/instant_controller.h
@@ -18,8 +18,6 @@
 #include "chrome/common/instant_types.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "chrome/common/search_types.h"
-#include "content/public/common/page_transition_types.h"
-#include "ui/base/window_open_disposition.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/rect.h"
 
@@ -159,14 +157,6 @@
   virtual void InstantPageAboutToNavigateMainFrame(
       const content::WebContents* contents,
       const GURL& url) OVERRIDE;
-  virtual void NavigateToURL(
-      const content::WebContents* contents,
-      const GURL& url,
-      content::PageTransition transition,
-      WindowOpenDisposition disposition,
-      bool is_search_type) OVERRIDE;
-  virtual void PasteIntoOmnibox(const content::WebContents* contents,
-                                const string16& text) OVERRIDE;
   virtual void InstantPageLoadFailed(content::WebContents* contents) OVERRIDE;
 
   // Helper function to navigate the given contents to the local fallback
@@ -187,9 +177,6 @@
   // active tab is in mode SEARCH_SUGGESTIONS.
   bool IsInputInProgress() const;
 
-  // Returns true if the local page is being used.
-  bool UsingLocalPage() const;
-
   // Returns the InstantService for the browser profile.
   InstantService* GetInstantService() const;
 
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer.cc b/chrome/browser/ui/search/instant_ntp_prerenderer.cc
index a4300c0..ed21b92 100644
--- a/chrome/browser/ui/search/instant_ntp_prerenderer.cc
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer.cc
@@ -133,7 +133,8 @@
 
   // TODO(kmadhusu): Remove start margin param from chrome::GetInstantURL().
   const GURL instant_url = chrome::GetInstantURL(profile_,
-                                                 chrome::kDisableStartMargin);
+                                                 chrome::kDisableStartMargin,
+                                                 false);
   if (!instant_url.is_valid())
     return GetLocalInstantURL();
 
@@ -207,21 +208,6 @@
   NOTREACHED();
 }
 
-void InstantNTPPrerenderer::NavigateToURL(
-    const content::WebContents* /* contents */,
-    const GURL& /* url */,
-    content::PageTransition /* transition */,
-    WindowOpenDisposition /* disposition */,
-    bool /* is_search_type */) {
-  NOTREACHED();
-}
-
-void InstantNTPPrerenderer::PasteIntoOmnibox(
-    const content::WebContents* /* contents */,
-    const string16& /* text */) {
-  NOTREACHED();
-}
-
 void InstantNTPPrerenderer::InstantPageLoadFailed(
     content::WebContents* contents) {
   DCHECK(ntp() && ntp()->contents() == contents);
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer.h b/chrome/browser/ui/search/instant_ntp_prerenderer.h
index 0fda843..d52f14c 100644
--- a/chrome/browser/ui/search/instant_ntp_prerenderer.h
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer.h
@@ -125,13 +125,6 @@
   virtual void InstantPageAboutToNavigateMainFrame(
       const content::WebContents* contents,
       const GURL& url) OVERRIDE;
-  virtual void NavigateToURL(const content::WebContents* contents,
-                             const GURL& url,
-                             content::PageTransition transition,
-                             WindowOpenDisposition disposition,
-                             bool is_search_type) OVERRIDE;
-  virtual void PasteIntoOmnibox(const content::WebContents* contents,
-                                const string16& text) OVERRIDE;
   virtual void InstantPageLoadFailed(content::WebContents* contents) OVERRIDE;
 
   // Overridden from InstantServiceObserver:
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc
index c3899b7..31a9888 100644
--- a/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc
@@ -20,7 +20,10 @@
   TestableInstantNTP(InstantNTPPrerenderer* ntp_prerenderer,
                      const std::string& instant_url,
                      Profile* profile)
-      : InstantNTP(ntp_prerenderer, instant_url, profile) {
+      : InstantNTP(ntp_prerenderer, "UNUSED", profile),
+        test_instant_url_(instant_url),
+        test_supports_instant_(true),
+        test_is_local_(false) {
   }
 
   // Overrides from InstantPage
@@ -151,12 +154,8 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
-  instant_ntp_prerenderer()->set_javascript_enabled(true);
   instant_ntp_prerenderer()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(false);
   instant_ntp_prerenderer()->set_in_startup(true);
   EXPECT_EQ(!chrome::ShouldPreferRemoteNTPOnStartup(),
             instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
@@ -166,15 +165,9 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
-                                   profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
-  instant_ntp_prerenderer()->set_javascript_enabled(true);
   instant_ntp_prerenderer()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
   ntp->set_supports_instant(false);
-  instant_ntp_prerenderer()->set_in_startup(false);
   EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
 }
 
@@ -182,15 +175,8 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
-                                   profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
-  instant_ntp_prerenderer()->set_javascript_enabled(true);
   instant_ntp_prerenderer()->set_instant_url("http://bogus_url");
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(true);
-  instant_ntp_prerenderer()->set_in_startup(false);
   EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
 }
 
@@ -198,15 +184,8 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
-                                   profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
-  instant_ntp_prerenderer()->set_javascript_enabled(true);
   instant_ntp_prerenderer()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(true);
-  instant_ntp_prerenderer()->set_in_startup(false);
   EXPECT_FALSE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
 }
 
@@ -214,15 +193,9 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
-                                   profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
-  instant_ntp_prerenderer()->set_javascript_enabled(true);
   instant_ntp_prerenderer()->set_instant_url(instant_url);
   ntp->set_instant_url("http://local_instant_url");
-  ntp->set_supports_instant(true);
-  instant_ntp_prerenderer()->set_in_startup(false);
   EXPECT_FALSE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
 }
 
@@ -230,15 +203,10 @@
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
       instant_ntp_prerenderer(), instant_url, profile()));
-  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
-                                   profile()));
-  ntp->set_is_local(false);
   instant_ntp_prerenderer()->set_ntp(ntp.get());
   instant_ntp_prerenderer()->set_javascript_enabled(false);
   instant_ntp_prerenderer()->set_instant_url(instant_url);
   ntp->set_instant_url("http://local_instant_url");
-  ntp->set_supports_instant(true);
-  instant_ntp_prerenderer()->set_in_startup(false);
   EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
 }
 
diff --git a/chrome/browser/ui/search/instant_page.cc b/chrome/browser/ui/search/instant_page.cc
index 1732a3c..5c68682 100644
--- a/chrome/browser/ui/search/instant_page.cc
+++ b/chrome/browser/ui/search/instant_page.cc
@@ -69,29 +69,6 @@
   return false;
 }
 
-bool InstantPage::ShouldProcessNavigateToURL() {
-  return false;
-}
-
-bool InstantPage::ShouldProcessPasteIntoOmnibox() {
-  return false;
-}
-
-bool InstantPage::OnMessageReceived(const IPC::Message& message) {
-  if (is_incognito_)
-    return false;
-
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(InstantPage, message)
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxNavigate,
-                        OnSearchBoxNavigate);
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PasteAndOpenDropdown,
-                        OnSearchBoxPaste);
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
 void InstantPage::DidCommitProvisionalLoadForFrame(
     int64 /* frame_id */,
     const string16& frame_unique_name,
@@ -139,35 +116,6 @@
     ClearContents();
 }
 
-void InstantPage::OnSearchBoxNavigate(int page_id,
-                                      const GURL& url,
-                                      content::PageTransition transition,
-                                      WindowOpenDisposition disposition,
-                                      bool is_search_type) {
-  if (!contents()->IsActiveEntry(page_id))
-    return;
-
-  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
-  if (!ShouldProcessNavigateToURL())
-    return;
-
-  delegate_->NavigateToURL(
-      contents(), url, transition, disposition, is_search_type);
-}
-
-void InstantPage::OnSearchBoxPaste(int page_id, const string16& text) {
-  if (!contents()->IsActiveEntry(page_id))
-    return;
-
-  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
-  if (!ShouldProcessPasteIntoOmnibox())
-    return;
-
-  delegate_->PasteIntoOmnibox(contents(), text);
-}
-
-
-
 void InstantPage::ClearContents() {
   if (contents())
     SearchTabHelper::FromWebContents(contents())->model()->RemoveObserver(this);
diff --git a/chrome/browser/ui/search/instant_page.h b/chrome/browser/ui/search/instant_page.h
index cb85102..6fd2059 100644
--- a/chrome/browser/ui/search/instant_page.h
+++ b/chrome/browser/ui/search/instant_page.h
@@ -52,21 +52,6 @@
         const content::WebContents* contents,
         const GURL& url) = 0;
 
-    // Called when the page wants to navigate to |url|. Usually used by the
-    // page to navigate to privileged destinations (e.g. chrome:// URLs) or to
-    // navigate to URLs that are hidden from the page using Restricted IDs (rid
-    // in the API).
-    virtual void NavigateToURL(const content::WebContents* contents,
-                               const GURL& url,
-                               content::PageTransition transition,
-                               WindowOpenDisposition disposition,
-                               bool is_search_type) = 0;
-
-    // Called when the page wants to paste the |text| (or the clipboard content
-    // if the |text| is empty) into the omnibox.
-    virtual void PasteIntoOmnibox(const content::WebContents* contents,
-                                  const string16& text) = 0;
-
     // Called when the page fails to load for whatever reason.
     virtual void InstantPageLoadFailed(content::WebContents* contents) = 0;
 
@@ -113,8 +98,6 @@
   // choose to ignore some or all of the received messages by overriding these
   // methods.
   virtual bool ShouldProcessAboutToNavigateMainFrame();
-  virtual bool ShouldProcessNavigateToURL();
-  virtual bool ShouldProcessPasteIntoOmnibox();
 
  private:
   FRIEND_TEST_ALL_PREFIXES(InstantPageTest, IsLocal);
@@ -129,7 +112,6 @@
                            AppropriateMessagesSentToIncognitoPages);
 
   // Overridden from content::WebContentsObserver:
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
   virtual void DidCommitProvisionalLoadForFrame(
       int64 frame_id,
       const string16& frame_unique_name,
@@ -156,13 +138,6 @@
   // Update the status of Instant support.
   void InstantSupportDetermined(bool supports_instant);
 
-  void OnSearchBoxNavigate(int page_id,
-                           const GURL& url,
-                           content::PageTransition transition,
-                           WindowOpenDisposition disposition,
-                           bool is_search_type);
-  void OnSearchBoxPaste(int page_id, const string16& text);
-
   void ClearContents();
 
   // TODO(kmadhusu): Remove |profile_| from here and update InstantNTP to get
diff --git a/chrome/browser/ui/search/instant_page_unittest.cc b/chrome/browser/ui/search/instant_page_unittest.cc
index eed68e8..4e2e4c2 100644
--- a/chrome/browser/ui/search/instant_page_unittest.cc
+++ b/chrome/browser/ui/search/instant_page_unittest.cc
@@ -43,9 +43,6 @@
                     content::PageTransition transition,
                     WindowOpenDisposition disposition,
                     bool is_search_type));
-  MOCK_METHOD2(PasteIntoOmnibox,
-               void(const content::WebContents* contents,
-                    const string16& text));
   MOCK_METHOD1(InstantPageLoadFailed, void(content::WebContents* contents));
 };
 
diff --git a/chrome/browser/ui/search/instant_tab.cc b/chrome/browser/ui/search/instant_tab.cc
index 14a53c7..387214a 100644
--- a/chrome/browser/ui/search/instant_tab.cc
+++ b/chrome/browser/ui/search/instant_tab.cc
@@ -30,11 +30,3 @@
 bool InstantTab::ShouldProcessAboutToNavigateMainFrame() {
   return true;
 }
-
-bool InstantTab::ShouldProcessNavigateToURL() {
-  return true;
-}
-
-bool InstantTab::ShouldProcessPasteIntoOmnibox() {
-  return true;
-}
diff --git a/chrome/browser/ui/search/instant_tab.h b/chrome/browser/ui/search/instant_tab.h
index 3b2430a..1847936 100644
--- a/chrome/browser/ui/search/instant_tab.h
+++ b/chrome/browser/ui/search/instant_tab.h
@@ -28,8 +28,6 @@
  private:
   // Overridden from InstantPage:
   virtual bool ShouldProcessAboutToNavigateMainFrame() OVERRIDE;
-  virtual bool ShouldProcessNavigateToURL() OVERRIDE;
-  virtual bool ShouldProcessPasteIntoOmnibox() OVERRIDE;
 
   DISALLOW_COPY_AND_ASSIGN(InstantTab);
 };
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc
index 064fb27..292efa7 100644
--- a/chrome/browser/ui/search/search_ipc_router.cc
+++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -12,7 +12,8 @@
                                  Delegate* delegate, scoped_ptr<Policy> policy)
     : WebContentsObserver(web_contents),
       delegate_(delegate),
-      policy_(policy.Pass()) {
+      policy_(policy.Pass()),
+      is_active_tab_(false) {
   DCHECK(web_contents);
   DCHECK(delegate);
   DCHECK(policy_.get());
@@ -36,9 +37,10 @@
   if (!policy_->ShouldSendSetDisplayInstantResults())
     return;
 
+  bool is_search_results_page = !chrome::GetSearchTerms(web_contents()).empty();
   Send(new ChromeViewMsg_SearchBoxSetDisplayInstantResults(
        routing_id(),
-       chrome::ShouldPrefetchSearchResultsOnSRP()));
+       is_search_results_page && chrome::ShouldPrefetchSearchResultsOnSRP()));
 }
 
 void SearchIPCRouter::SendThemeBackgroundInfo(
@@ -74,6 +76,14 @@
   Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text));
 }
 
+void SearchIPCRouter::OnTabActivated() {
+  is_active_tab_ = true;
+}
+
+void SearchIPCRouter::OnTabDeactivated() {
+  is_active_tab_ = false;
+}
+
 bool SearchIPCRouter::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(SearchIPCRouter, message)
@@ -82,6 +92,8 @@
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetVoiceSearchSupported,
                         OnVoiceSearchSupportDetermined)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusOmnibox, OnFocusOmnibox);
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxNavigate,
+                        OnSearchBoxNavigate);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem,
                         OnDeleteMostVisitedItem);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion,
@@ -89,6 +101,8 @@
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions,
                         OnUndoAllMostVisitedDeletions);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogEvent, OnLogEvent);
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PasteAndOpenDropdown,
+                        OnPasteAndOpenDropDown);
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -121,12 +135,27 @@
     return;
 
   delegate_->OnInstantSupportDetermined(true);
-  if (!policy_->ShouldProcessFocusOmnibox())
+  if (!policy_->ShouldProcessFocusOmnibox(is_active_tab_))
     return;
 
   delegate_->FocusOmnibox(state);
 }
 
+void SearchIPCRouter::OnSearchBoxNavigate(
+    int page_id,
+    const GURL& url,
+    WindowOpenDisposition disposition,
+    bool is_most_visited_item_url) const {
+  if (!web_contents()->IsActiveEntry(page_id))
+    return;
+
+  delegate_->OnInstantSupportDetermined(true);
+  if (!policy_->ShouldProcessNavigateToURL(is_active_tab_))
+    return;
+
+  delegate_->NavigateToURL(url, disposition, is_most_visited_item_url);
+}
+
 void SearchIPCRouter::OnDeleteMostVisitedItem(int page_id,
                                               const GURL& url) const {
   if (!web_contents()->IsActiveEntry(page_id))
@@ -173,6 +202,18 @@
   delegate_->OnLogEvent(event);
 }
 
+void SearchIPCRouter::OnPasteAndOpenDropDown(int page_id,
+                                             const string16& text) const {
+  if (!web_contents()->IsActiveEntry(page_id))
+    return;
+
+  delegate_->OnInstantSupportDetermined(true);
+  if (!policy_->ShouldProcessPasteIntoOmnibox(is_active_tab_))
+    return;
+
+  delegate_->PasteIntoOmnibox(text);
+}
+
 void SearchIPCRouter::set_delegate(Delegate* delegate) {
   DCHECK(delegate);
   delegate_ = delegate;
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h
index 6d96ecd..13c57ce 100644
--- a/chrome/browser/ui/search/search_ipc_router.h
+++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -13,6 +13,7 @@
 #include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "ui/base/window_open_disposition.h"
 
 class GURL;
 
@@ -41,6 +42,14 @@
     // the omnibox focus state.
     virtual void FocusOmnibox(OmniboxFocusState state) = 0;
 
+    // Called when the page wants to navigate to |url|. Usually used by the
+    // page to navigate to privileged destinations (e.g. chrome:// URLs) or to
+    // navigate to URLs that are hidden from the page using Restricted IDs (rid
+    // in the API).
+    virtual void NavigateToURL(const GURL& url,
+                               WindowOpenDisposition disposition,
+                               bool is_most_visited_item_url) = 0;
+
     // Called when the SearchBox wants to delete a Most Visited item.
     virtual void OnDeleteMostVisitedItem(const GURL& url) = 0;
 
@@ -52,6 +61,10 @@
 
     // Called to signal that an event has occurred on the New Tab Page.
     virtual void OnLogEvent(NTPLoggingEventType event) = 0;
+
+    // Called when the page wants to paste the |text| (or the clipboard contents
+    // if the |text| is empty) into the omnibox.
+    virtual void PasteIntoOmnibox(const string16& text) = 0;
   };
 
   // An interface to be implemented by consumers of SearchIPCRouter objects to
@@ -64,11 +77,13 @@
     // SearchIPCRouter calls these functions before sending/receiving messages
     // to/from the page.
     virtual bool ShouldProcessSetVoiceSearchSupport() = 0;
-    virtual bool ShouldProcessFocusOmnibox() = 0;
+    virtual bool ShouldProcessFocusOmnibox(bool is_active_tab) = 0;
+    virtual bool ShouldProcessNavigateToURL(bool is_active_tab) = 0;
     virtual bool ShouldProcessDeleteMostVisitedItem() = 0;
     virtual bool ShouldProcessUndoMostVisitedDeletion() = 0;
     virtual bool ShouldProcessUndoAllMostVisitedDeletions() = 0;
     virtual bool ShouldProcessLogEvent() = 0;
+    virtual bool ShouldProcessPasteIntoOmnibox(bool is_active_tab) = 0;
     virtual bool ShouldSendSetPromoInformation() = 0;
     virtual bool ShouldSendSetDisplayInstantResults() = 0;
     virtual bool ShouldSendSetSuggestionToPrefetch() = 0;
@@ -104,6 +119,12 @@
   // Tells the page that the user pressed Enter in the omnibox.
   void Submit(const string16& text);
 
+  // Called when the tab corresponding to |this| instance is activated.
+  void OnTabActivated();
+
+  // Called when the tab corresponding to |this| instance is deactivated.
+  void OnTabDeactivated();
+
  private:
   friend class SearchIPCRouterTest;
   FRIEND_TEST_ALL_PREFIXES(SearchTabHelperTest,
@@ -136,6 +157,7 @@
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest, SendSetPromoInformation);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            DoNotSendSetPromoInformation);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest, ProcessNavigateToURL);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            ProcessDeleteMostVisitedItem);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
@@ -143,16 +165,25 @@
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            ProcessUndoAllMostVisitedDeletions);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           ProcessPasteIntoOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           DoNotProcessPasteIntoOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            DoNotProcessMessagesForIncognitoPage);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           DoNotProcessMessagesForInactiveTab);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessVoiceSearchSupportMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreVoiceSearchSupportMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessFocusOmniboxMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreFocusOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, HandleTabChangedEvents);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, SendSetPromoInformationMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            DoNotSendSetPromoInformationMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessLogEventMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreLogEventMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessNavigateToURLMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreNavigateToURLMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            ProcessDeleteMostVisitedItemMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
@@ -167,6 +198,8 @@
                            IgnoreUndoAllMostVisitedDeletionsMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            IgnoreMessageIfThePageIsNotActive);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessPasteAndOpenDropdownMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnorePasteAndOpenDropdownMsg);
 
   // Overridden from contents::WebContentsObserver:
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
@@ -175,10 +208,15 @@
   void OnVoiceSearchSupportDetermined(int page_id,
                                       bool supports_voice_search) const;
   void OnFocusOmnibox(int page_id, OmniboxFocusState state) const;
+  void OnSearchBoxNavigate(int page_id,
+                           const GURL& url,
+                           WindowOpenDisposition disposition,
+                           bool is_most_visited_item_url) const;
   void OnDeleteMostVisitedItem(int page_id, const GURL& url) const;
   void OnUndoMostVisitedDeletion(int page_id, const GURL& url) const;
   void OnUndoAllMostVisitedDeletions(int page_id) const;
   void OnLogEvent(int page_id, NTPLoggingEventType event) const;
+  void OnPasteAndOpenDropDown(int page_id, const string16& text) const;
 
   // Used by unit tests to set a fake delegate.
   void set_delegate(Delegate* delegate);
@@ -192,6 +230,9 @@
   Delegate* delegate_;
   scoped_ptr<Policy> policy_;
 
+  // Set to true, when the tab corresponding to |this| instance is active.
+  bool is_active_tab_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchIPCRouter);
 };
 
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
index 53d9272..2dfb5b3 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
@@ -4,29 +4,10 @@
 
 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
 
-#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/web_contents.h"
 
-namespace {
-
-// Returns true if |web_contents| corresponds to the current active tab.
-bool IsActiveWebContents(const content::WebContents* web_contents) {
-  Browser* browser = NULL;
-
-// iOS and Android doesn't use the Instant framework.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
-  browser = chrome::FindBrowserWithWebContents(web_contents);
-#endif
-  return browser && web_contents &&
-      (browser->tab_strip_model()->GetActiveWebContents() == web_contents);
-}
-
-}  // namespace
-
 SearchIPCRouterPolicyImpl::SearchIPCRouterPolicyImpl(
     const content::WebContents* web_contents)
     : web_contents_(web_contents),
@@ -45,8 +26,12 @@
   return true;
 }
 
-bool SearchIPCRouterPolicyImpl::ShouldProcessFocusOmnibox() {
-  return !is_incognito_ && chrome::IsInstantNTP(web_contents_);
+bool SearchIPCRouterPolicyImpl::ShouldProcessFocusOmnibox(bool is_active_tab) {
+  return is_active_tab && !is_incognito_ && chrome::IsInstantNTP(web_contents_);
+}
+
+bool SearchIPCRouterPolicyImpl::ShouldProcessNavigateToURL(bool is_active_tab) {
+  return is_active_tab && !is_incognito_;
 }
 
 bool SearchIPCRouterPolicyImpl::ShouldProcessDeleteMostVisitedItem() {
@@ -65,6 +50,11 @@
   return !is_incognito_ && chrome::IsInstantNTP(web_contents_);
 }
 
+bool SearchIPCRouterPolicyImpl::ShouldProcessPasteIntoOmnibox(
+    bool is_active_tab) {
+  return is_active_tab && !is_incognito_ && chrome::IsInstantNTP(web_contents_);
+}
+
 bool SearchIPCRouterPolicyImpl::ShouldSendSetPromoInformation() {
   return !is_incognito_ && chrome::IsInstantNTP(web_contents_);
 }
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.h b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
index 0892ac3..1a9eae6 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.h
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
@@ -32,11 +32,13 @@
 
   // Overridden from SearchIPCRouter::Policy:
   virtual bool ShouldProcessSetVoiceSearchSupport() OVERRIDE;
-  virtual bool ShouldProcessFocusOmnibox() OVERRIDE;
+  virtual bool ShouldProcessFocusOmnibox(bool is_active_tab) OVERRIDE;
+  virtual bool ShouldProcessNavigateToURL(bool is_active_tab) OVERRIDE;
   virtual bool ShouldProcessDeleteMostVisitedItem() OVERRIDE;
   virtual bool ShouldProcessUndoMostVisitedDeletion() OVERRIDE;
   virtual bool ShouldProcessUndoAllMostVisitedDeletions() OVERRIDE;
   virtual bool ShouldProcessLogEvent() OVERRIDE;
+  virtual bool ShouldProcessPasteIntoOmnibox(bool is_active_tab) OVERRIDE;
   virtual bool ShouldSendSetPromoInformation() OVERRIDE;
   virtual bool ShouldSendSetDisplayInstantResults() OVERRIDE;
   virtual bool ShouldSendSetSuggestionToPrefetch() OVERRIDE;
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc
index 1804007..877541d 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc
+++ b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc
@@ -4,21 +4,24 @@
 
 #include "chrome/browser/ui/search/search_ipc_router.h"
 
+#include "build/build_config.h"
 #include "base/command_line.h"
 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-class SearchIPCRouterPolicyTest : public ChromeRenderViewHostTestHarness {
+class SearchIPCRouterPolicyTest : public BrowserWithTestWindowTest {
  public:
   virtual void SetUp() {
     CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableInstantExtendedAPI);
-    ChromeRenderViewHostTestHarness::SetUp();
+    BrowserWithTestWindowTest::SetUp();
+    AddTab(browser(), GURL("chrome://blank"));
     SearchTabHelper::CreateForWebContents(web_contents());
   }
 
@@ -29,84 +32,107 @@
     return search_tab_helper;
   }
 
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
 };
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessVoiceSearchSupportMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessSetVoiceSearchSupport());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessFocusOmnibox) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
-  EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
-      ShouldProcessFocusOmnibox());
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper();
+  EXPECT_TRUE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessFocusOmnibox(true));
 }
 
 TEST_F(SearchIPCRouterPolicyTest, DoNotProcessFocusOmnibox) {
   // Process message only if the underlying page is an InstantNTP.
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
-  EXPECT_FALSE(GetSearchTabHelper()->ipc_router().policy()->
-      ShouldProcessFocusOmnibox());
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper();
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessFocusOmnibox(true));
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SendSetPromoInformation) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldSendSetPromoInformation());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, DoNotSendSetPromoInformation) {
   // Send promo information only if the underlying page is an InstantNTP.
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   EXPECT_FALSE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldSendSetPromoInformation());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessDeleteMostVisitedItem) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessDeleteMostVisitedItem());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessUndoMostVisitedDeletion) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessUndoMostVisitedDeletion());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessUndoAllMostVisitedDeletions) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
-  SearchTabHelper* search_tab_helper =
-      SearchTabHelper::FromWebContents(web_contents());
-  ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessUndoAllMostVisitedDeletions());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, ProcessLogEvent) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessLogEvent());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, DoNotProcessLogEvent) {
   // Process message only if the underlying page is an InstantNTP.
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   EXPECT_FALSE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldProcessLogEvent());
 }
 
+TEST_F(SearchIPCRouterPolicyTest, ProcessNavigateToURL) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
+      ShouldProcessNavigateToURL(true));
+}
+
+TEST_F(SearchIPCRouterPolicyTest, ProcessPasteIntoOmniboxMsg) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
+      ShouldProcessPasteIntoOmnibox(true));
+}
+
+TEST_F(SearchIPCRouterPolicyTest, DoNotProcessPasteIntoOmniboxMsg) {
+  // Process message only if the current tab is an Instant NTP.
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  EXPECT_FALSE(GetSearchTabHelper()->ipc_router().policy()->
+      ShouldProcessPasteIntoOmnibox(true));
+}
+
 TEST_F(SearchIPCRouterPolicyTest, DoNotProcessMessagesForIncognitoPage) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   SearchIPCRouterPolicyImpl* policy =
       static_cast<SearchIPCRouterPolicyImpl*>(
           search_tab_helper->ipc_router().policy());
   policy->set_is_incognito(true);
 
-  EXPECT_FALSE(GetSearchTabHelper()->ipc_router().policy()->
-      ShouldProcessFocusOmnibox());
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessFocusOmnibox(true));
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessNavigateToURL(true));
   EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
       ShouldProcessDeleteMostVisitedItem());
   EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
@@ -115,16 +141,31 @@
       ShouldProcessUndoAllMostVisitedDeletions());
   EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
       ShouldProcessLogEvent());
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessPasteIntoOmnibox(true));
+}
+
+TEST_F(SearchIPCRouterPolicyTest, DoNotProcessMessagesForInactiveTab) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+
+  // Assume the NTP is deactivated.
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper();
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessFocusOmnibox(false));
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessNavigateToURL(false));
+  EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
+      ShouldProcessPasteIntoOmnibox(false));
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SendSetDisplayInstantResults) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   EXPECT_TRUE(GetSearchTabHelper()->ipc_router().policy()->
       ShouldSendSetDisplayInstantResults());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SendSetSuggestionToPrefetch) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SearchTabHelper* search_tab_helper =
       SearchTabHelper::FromWebContents(web_contents());
   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
@@ -134,7 +175,7 @@
 
 TEST_F(SearchIPCRouterPolicyTest,
        DoNotSendSetMessagesForIncognitoPage) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   SearchIPCRouterPolicyImpl* policy =
       static_cast<SearchIPCRouterPolicyImpl*>(
@@ -155,7 +196,7 @@
 
 TEST_F(SearchIPCRouterPolicyTest,
        AppropriateMessagesSentToIncognitoPages) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SearchTabHelper* search_tab_helper =
       SearchTabHelper::FromWebContents(web_contents());
   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
@@ -168,7 +209,7 @@
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SendMostVisitedItems) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   EXPECT_TRUE(search_tab_helper->ipc_router().policy()->
       ShouldSendMostVisitedItems());
@@ -176,14 +217,14 @@
 
 TEST_F(SearchIPCRouterPolicyTest, DoNotSendMostVisitedItems) {
   // Send most visited items only if the current tab is an Instant NTP.
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
       ShouldSendMostVisitedItems());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SendThemeBackgroundInfo) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   EXPECT_TRUE(search_tab_helper->ipc_router().policy()->
       ShouldSendThemeBackgroundInfo());
@@ -192,14 +233,14 @@
 TEST_F(SearchIPCRouterPolicyTest, DoNotSendThemeBackgroundInfo) {
   // Send theme background information only if the current tab is an
   // Instant NTP.
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SearchTabHelper* search_tab_helper = GetSearchTabHelper();
   EXPECT_FALSE(search_tab_helper->ipc_router().policy()->
       ShouldSendThemeBackgroundInfo());
 }
 
 TEST_F(SearchIPCRouterPolicyTest, SubmitQuery) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SearchTabHelper* search_tab_helper =
       SearchTabHelper::FromWebContents(web_contents());
   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc
index 1b53a39..39bec6d 100644
--- a/chrome/browser/ui/search/search_ipc_router_unittest.cc
+++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -8,16 +8,24 @@
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
+#include "base/tuple.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/instant_types.h"
 #include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
@@ -26,6 +34,7 @@
 #include "ipc/ipc_test_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
 namespace {
@@ -37,10 +46,12 @@
   MOCK_METHOD1(OnInstantSupportDetermined, void(bool supports_instant));
   MOCK_METHOD1(OnSetVoiceSearchSupport, void(bool supports_voice_search));
   MOCK_METHOD1(FocusOmnibox, void(OmniboxFocusState state));
+  MOCK_METHOD3(NavigateToURL, void(const GURL&, WindowOpenDisposition, bool));
   MOCK_METHOD1(OnDeleteMostVisitedItem, void(const GURL& url));
   MOCK_METHOD1(OnUndoMostVisitedDeletion, void(const GURL& url));
   MOCK_METHOD0(OnUndoAllMostVisitedDeletions, void());
   MOCK_METHOD1(OnLogEvent, void(NTPLoggingEventType event));
+  MOCK_METHOD1(PasteIntoOmnibox, void(const string16&));
 };
 
 class MockSearchIPCRouterPolicy : public SearchIPCRouter::Policy {
@@ -48,11 +59,13 @@
   virtual ~MockSearchIPCRouterPolicy() {}
 
   MOCK_METHOD0(ShouldProcessSetVoiceSearchSupport, bool());
-  MOCK_METHOD0(ShouldProcessFocusOmnibox, bool());
+  MOCK_METHOD1(ShouldProcessFocusOmnibox, bool(bool));
+  MOCK_METHOD1(ShouldProcessNavigateToURL, bool(bool));
   MOCK_METHOD0(ShouldProcessDeleteMostVisitedItem, bool());
   MOCK_METHOD0(ShouldProcessUndoMostVisitedDeletion, bool());
   MOCK_METHOD0(ShouldProcessUndoAllMostVisitedDeletions, bool());
   MOCK_METHOD0(ShouldProcessLogEvent, bool());
+  MOCK_METHOD1(ShouldProcessPasteIntoOmnibox, bool(bool));
   MOCK_METHOD0(ShouldSendSetPromoInformation, bool());
   MOCK_METHOD0(ShouldSendSetDisplayInstantResults, bool());
   MOCK_METHOD0(ShouldSendSetSuggestionToPrefetch, bool());
@@ -63,13 +76,43 @@
 
 }  // namespace
 
-class SearchIPCRouterTest : public ChromeRenderViewHostTestHarness {
+class SearchIPCRouterTest : public BrowserWithTestWindowTest {
  public:
+  SearchIPCRouterTest() : field_trial_list_(NULL) {}
+
   virtual void SetUp() {
-    CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnableInstantExtendedAPI);
-    ChromeRenderViewHostTestHarness::SetUp();
+    BrowserWithTestWindowTest::SetUp();
+    AddTab(browser(), GURL("chrome://blank"));
     SearchTabHelper::CreateForWebContents(web_contents());
+
+    TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+        profile(),
+        &TemplateURLServiceFactory::BuildInstanceFor);
+    TemplateURLService* template_url_service =
+        TemplateURLServiceFactory::GetForProfile(profile());
+    ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
+
+    TemplateURLData data;
+    data.SetURL("http://foo.com/url?bar={searchTerms}");
+    data.instant_url = "http://foo.com/instant?"
+        "{google:omniboxStartMarginParameter}foo=foo#foo=foo&espv";
+    data.new_tab_url = "https://foo.com/newtab?espv";
+    data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
+    data.search_terms_replacement_key = "espv";
+
+    TemplateURL* template_url = new TemplateURL(profile(), data);
+    // Takes ownership of |template_url|.
+    template_url_service->Add(template_url);
+    template_url_service->SetDefaultSearchProvider(template_url);
+  }
+
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  content::MockRenderProcessHost* process() {
+    return static_cast<content::MockRenderProcessHost*>(
+        web_contents()->GetRenderViewHost()->GetProcess());
   }
 
   SearchTabHelper* GetSearchTabHelper(
@@ -93,6 +136,26 @@
     return process()->sink().GetFirstMessageMatching(id) != NULL;
   }
 
+  void VerifyDisplayInstantResultsMsg(bool expected_param_value) {
+    process()->sink().ClearMessages();
+
+    content::WebContents* contents = web_contents();
+    SetupMockDelegateAndPolicy(contents);
+    MockSearchIPCRouterPolicy* policy =
+        GetSearchIPCRouterPolicy(contents);
+    EXPECT_CALL(*policy, ShouldSendSetDisplayInstantResults()).Times(1)
+        .WillOnce(testing::Return(true));
+
+    GetSearchTabHelper(contents)->ipc_router().SetDisplayInstantResults();
+    const IPC::Message* message = process()->sink().GetFirstMessageMatching(
+        ChromeViewMsg_SearchBoxSetDisplayInstantResults::ID);
+    EXPECT_NE(static_cast<const IPC::Message*>(NULL), message);
+    Tuple1<bool> display_instant_results_param;
+    ChromeViewMsg_SearchBoxSetDisplayInstantResults::Read(
+        message, &display_instant_results_param);
+    EXPECT_EQ(expected_param_value, display_instant_results_param.a);
+  }
+
   MockSearchIPCRouterDelegate* mock_delegate() { return &delegate_; }
 
   MockSearchIPCRouterPolicy* GetSearchIPCRouterPolicy(
@@ -107,126 +170,210 @@
 
  private:
   MockSearchIPCRouterDelegate delegate_;
+  base::FieldTrialList field_trial_list_;
 };
 
 TEST_F(SearchIPCRouterTest, ProcessVoiceSearchSupportMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*mock_delegate(), OnSetVoiceSearchSupport(true)).Times(1);
   EXPECT_CALL(*policy, ShouldProcessSetVoiceSearchSupport()).Times(1)
       .WillOnce(testing::Return(true));
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SetVoiceSearchSupported(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           true));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreVoiceSearchSupportMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
-  EXPECT_CALL(*mock_delegate(), OnSetVoiceSearchSupport(true)).Times(0);
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  EXPECT_CALL(*mock_delegate(), OnSetVoiceSearchSupport(true)).Times(0);
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldProcessSetVoiceSearchSupport()).Times(1)
       .WillOnce(testing::Return(false));
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SetVoiceSearchSupported(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           true));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, ProcessFocusOmniboxMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*mock_delegate(), FocusOmnibox(OMNIBOX_FOCUS_VISIBLE)).Times(1);
-  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox()).Times(1)
+
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(1)
       .WillOnce(testing::Return(true));
 
   scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_FocusOmnibox(
-      web_contents()->GetRoutingID(),
-      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
       OMNIBOX_FOCUS_VISIBLE));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreFocusOmniboxMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*mock_delegate(), FocusOmnibox(OMNIBOX_FOCUS_VISIBLE)).Times(0);
-  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox()).Times(1)
+
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(1)
       .WillOnce(testing::Return(false));
 
   scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_FocusOmnibox(
-      web_contents()->GetRoutingID(),
-      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
       OMNIBOX_FOCUS_VISIBLE));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+}
+
+TEST_F(SearchIPCRouterTest, HandleTabChangedEvents) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  content::WebContents* contents = web_contents();
+  EXPECT_EQ(0, browser()->tab_strip_model()->GetIndexOfWebContents(contents));
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  EXPECT_TRUE(search_tab_helper->ipc_router().is_active_tab_);
+
+  // Add a new tab to deactivate the current tab.
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+  EXPECT_EQ(1, browser()->tab_strip_model()->GetIndexOfWebContents(contents));
+  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+  EXPECT_FALSE(search_tab_helper->ipc_router().is_active_tab_);
+
+  // Activate the first tab.
+  browser()->tab_strip_model()->ActivateTabAt(1, false);
+  EXPECT_EQ(browser()->tab_strip_model()->active_index(),
+            browser()->tab_strip_model()->GetIndexOfWebContents(contents));
+  EXPECT_TRUE(search_tab_helper->ipc_router().is_active_tab_);
+}
+
+TEST_F(SearchIPCRouterTest, ProcessNavigateToURLMsg) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  process()->sink().ClearMessages();
+
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(contents);
+
+  GURL destination_url("www.foo.com");
+  EXPECT_CALL(*mock_delegate(), NavigateToURL(destination_url, CURRENT_TAB,
+                                              true)).Times(1);
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*policy, ShouldProcessNavigateToURL(is_active_tab)).Times(1)
+      .WillOnce(testing::Return(true));
+
+  scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_SearchBoxNavigate(
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
+      destination_url, CURRENT_TAB, true));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+}
+
+TEST_F(SearchIPCRouterTest, IgnoreNavigateToURLMsg) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  process()->sink().ClearMessages();
+  GURL destination_url("www.foo.com");
+
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(contents);
+  EXPECT_CALL(*mock_delegate(), NavigateToURL(destination_url, CURRENT_TAB,
+                                              true)).Times(0);
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*policy, ShouldProcessNavigateToURL(is_active_tab)).Times(1)
+      .WillOnce(testing::Return(false));
+
+  scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_SearchBoxNavigate(
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
+      destination_url, CURRENT_TAB, true));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, ProcessLogEventMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
   EXPECT_CALL(*mock_delegate(), OnLogEvent(NTP_MOUSEOVER)).Times(1);
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
 
   EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1)
       .WillOnce(testing::Return(true));
 
   scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_LogEvent(
-      web_contents()->GetRoutingID(),
-      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
       NTP_MOUSEOVER));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreLogEventMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
   EXPECT_CALL(*mock_delegate(), OnLogEvent(NTP_MOUSEOVER)).Times(0);
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1)
       .WillOnce(testing::Return(false));
 
   scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_LogEvent(
-      web_contents()->GetRoutingID(),
-      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(),
       NTP_MOUSEOVER));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, ProcessDeleteMostVisitedItemMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
 
   GURL item_url("www.foo.com");
   EXPECT_CALL(*mock_delegate(), OnDeleteMostVisitedItem(item_url)).Times(1);
@@ -235,19 +382,20 @@
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreDeleteMostVisitedItemMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
 
   GURL item_url("www.foo.com");
   EXPECT_CALL(*mock_delegate(), OnDeleteMostVisitedItem(item_url)).Times(0);
@@ -256,19 +404,20 @@
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, ProcessUndoMostVisitedDeletionMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   GURL item_url("www.foo.com");
   EXPECT_CALL(*mock_delegate(), OnUndoMostVisitedDeletion(item_url)).Times(1);
   EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(1)
@@ -276,19 +425,20 @@
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreUndoMostVisitedDeletionMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   GURL item_url("www.foo.com");
   EXPECT_CALL(*mock_delegate(), OnUndoMostVisitedDeletion(item_url)).Times(0);
   EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(1)
@@ -296,265 +446,360 @@
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID(),
           item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, ProcessUndoAllMostVisitedDeletionsMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*mock_delegate(), OnUndoAllMostVisitedDeletions()).Times(1);
   EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(1)
       .WillOnce(testing::Return(true));
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID()));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID()));
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreUndoAllMostVisitedDeletionsMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*mock_delegate(), OnUndoAllMostVisitedDeletions()).Times(0);
   EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(1)
       .WillOnce(testing::Return(false));
 
   scoped_ptr<IPC::Message> message(
       new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
-          web_contents()->GetRoutingID(),
-          web_contents()->GetController().GetVisibleEntry()->GetPageID()));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+          contents->GetRoutingID(),
+          contents->GetController().GetVisibleEntry()->GetPageID()));
+  GetSearchTabHelper(contents)->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, IgnoreMessageIfThePageIsNotActive) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
 
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
   int invalid_page_id = 1000;
   GURL item_url("www.foo.com");
+  EXPECT_CALL(*mock_delegate(), NavigateToURL(item_url, CURRENT_TAB,
+                                              true)).Times(0);
+  EXPECT_CALL(*policy, ShouldProcessNavigateToURL(
+      search_tab_helper->ipc_router().is_active_tab_)).Times(0);
+  scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_SearchBoxNavigate(
+      contents->GetRoutingID(), invalid_page_id, item_url, CURRENT_TAB,
+      true));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+
   EXPECT_CALL(*mock_delegate(), OnDeleteMostVisitedItem(item_url)).Times(0);
   EXPECT_CALL(*policy, ShouldProcessDeleteMostVisitedItem()).Times(0);
-  scoped_ptr<IPC::Message> message(
-      new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
-          web_contents()->GetRoutingID(), invalid_page_id, item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  message.reset(new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
+      contents->GetRoutingID(), invalid_page_id, item_url));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 
   EXPECT_CALL(*mock_delegate(), OnUndoMostVisitedDeletion(item_url)).Times(0);
   EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(0);
   message.reset(new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(
-      web_contents()->GetRoutingID(), invalid_page_id, item_url));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+      contents->GetRoutingID(), invalid_page_id, item_url));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 
   EXPECT_CALL(*mock_delegate(), OnUndoAllMostVisitedDeletions()).Times(0);
   EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(0);
   message.reset(new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
-      web_contents()->GetRoutingID(), invalid_page_id));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+      contents->GetRoutingID(), invalid_page_id));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 
   EXPECT_CALL(*mock_delegate(), FocusOmnibox(OMNIBOX_FOCUS_VISIBLE)).Times(0);
-  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox()).Times(0);
+  EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(
+      search_tab_helper->ipc_router().is_active_tab_)).Times(0);
   message.reset(new ChromeViewHostMsg_FocusOmnibox(
-      web_contents()->GetRoutingID(), invalid_page_id, OMNIBOX_FOCUS_VISIBLE));
+      contents->GetRoutingID(), invalid_page_id, OMNIBOX_FOCUS_VISIBLE));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 
   EXPECT_CALL(*mock_delegate(), OnLogEvent(NTP_MOUSEOVER)).Times(0);
   EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(0);
-  message.reset(new ChromeViewHostMsg_LogEvent(web_contents()->GetRoutingID(),
+  message.reset(new ChromeViewHostMsg_LogEvent(contents->GetRoutingID(),
                                                invalid_page_id, NTP_MOUSEOVER));
-  GetSearchTabHelper(web_contents())->ipc_router().OnMessageReceived(*message);
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+
+  string16 text;
+  EXPECT_CALL(*mock_delegate(), PasteIntoOmnibox(text)).Times(0);
+  EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(
+      search_tab_helper->ipc_router().is_active_tab_)).Times(0);
+  message.reset(new ChromeViewHostMsg_PasteAndOpenDropdown(
+      contents->GetRoutingID(), invalid_page_id, text));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+}
+
+TEST_F(SearchIPCRouterTest, ProcessPasteAndOpenDropdownMsg) {
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+  process()->sink().ClearMessages();
+
+  content::WebContents* contents = web_contents();
+  string16 text;
+  SetupMockDelegateAndPolicy(contents);
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(contents);
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*mock_delegate(), PasteIntoOmnibox(text)).Times(1);
+  EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(is_active_tab)).Times(1)
+      .WillOnce(testing::Return(true));
+
+  scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_PasteAndOpenDropdown(
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(), text));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
+}
+
+TEST_F(SearchIPCRouterTest, IgnorePasteAndOpenDropdownMsg) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  process()->sink().ClearMessages();
+
+  content::WebContents* contents = web_contents();
+  string16 text;
+  SetupMockDelegateAndPolicy(contents);
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(contents);
+  SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents);
+  bool is_active_tab = search_tab_helper->ipc_router().is_active_tab_;
+  EXPECT_TRUE(is_active_tab);
+  EXPECT_CALL(*mock_delegate(), PasteIntoOmnibox(text)).Times(0);
+  EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(is_active_tab)).Times(1)
+      .WillOnce(testing::Return(false));
+
+  scoped_ptr<IPC::Message> message(new ChromeViewHostMsg_PasteAndOpenDropdown(
+      contents->GetRoutingID(),
+      contents->GetController().GetVisibleEntry()->GetPageID(), text));
+  search_tab_helper->ipc_router().OnMessageReceived(*message);
 }
 
 TEST_F(SearchIPCRouterTest, SendSetPromoInformationMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendSetPromoInformation()).Times(1)
       .WillOnce(testing::Return(true));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SetPromoInformation(true);
+  GetSearchTabHelper(contents)->ipc_router().SetPromoInformation(true);
   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxPromoInformation::ID));
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendSetPromoInformationMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendSetPromoInformation()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SetPromoInformation(false);
+  GetSearchTabHelper(contents)->ipc_router().SetPromoInformation(false);
   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxPromoInformation::ID));
 }
 
-TEST_F(SearchIPCRouterTest, SendSetDisplayInstantResultsMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
-  process()->sink().ClearMessages();
+TEST_F(SearchIPCRouterTest,
+       SendSetDisplayInstantResultsMsg_EnableInstantOnResultsPage) {
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
+      "EmbeddedSearch", "Group1 espv:42 prefetch_results_srp:1"));
+  NavigateAndCommitActiveTab(GURL("https://foo.com/url?espv&bar=abc"));
 
-  SetupMockDelegateAndPolicy(web_contents());
-  MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
-  EXPECT_CALL(*policy, ShouldSendSetDisplayInstantResults()).Times(1)
-      .WillOnce(testing::Return(true));
+  // Make sure ChromeViewMsg_SearchBoxSetDisplayInstantResults message param is
+  // set to true if the underlying page is a results page and
+  // "prefetch_results_srp" flag is enabled via field trials.
+  VerifyDisplayInstantResultsMsg(true);
+}
 
-  GetSearchTabHelper(web_contents())->ipc_router().SetDisplayInstantResults();
-  EXPECT_TRUE(MessageWasSent(
-      ChromeViewMsg_SearchBoxSetDisplayInstantResults::ID));
+TEST_F(SearchIPCRouterTest,
+       SendSetDisplayInstantResultsMsg_DisableInstantOnResultsPage) {
+  // |prefetch_results_srp" flag is disabled via field trials.
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
+      "EmbeddedSearch", "Group1 espv:42 prefetch_results_srp:0"));
+  NavigateAndCommitActiveTab(GURL("https://foo.com/url?espv&bar=abc"));
+
+  // Make sure ChromeViewMsg_SearchBoxSetDisplayInstantResults message param is
+  // set to false.
+  VerifyDisplayInstantResultsMsg(false);
+}
+
+TEST_F(SearchIPCRouterTest,
+       SendSetDisplayInstantResultsMsg_DisableInstantOutsideResultsPage) {
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
+      "EmbeddedSearch", "Group1 espv:42 prefetch_results_srp:1"));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
+
+  // Make sure ChromeViewMsg_SearchBoxSetDisplayInstantResults param is set to
+  // false if the underlying page is not a search results page.
+  VerifyDisplayInstantResultsMsg(false);
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendSetDisplayInstantResultsMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendSetDisplayInstantResults()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SetDisplayInstantResults();
+  GetSearchTabHelper(contents)->ipc_router().SetDisplayInstantResults();
   EXPECT_FALSE(MessageWasSent(
       ChromeViewMsg_SearchBoxSetDisplayInstantResults::ID));
 }
 
 TEST_F(SearchIPCRouterTest, SendSetSuggestionToPrefetch) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendSetSuggestionToPrefetch()).Times(1)
       .WillOnce(testing::Return(true));
 
-  GetSearchTabHelper(web_contents())->SetSuggestionToPrefetch(
+  GetSearchTabHelper(contents)->SetSuggestionToPrefetch(
       InstantSuggestion());
   EXPECT_TRUE(MessageWasSent(
       ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID));
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendSetSuggestionToPrefetch) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendSetSuggestionToPrefetch()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->SetSuggestionToPrefetch(
+  GetSearchTabHelper(contents)->SetSuggestionToPrefetch(
       InstantSuggestion());
   EXPECT_FALSE(MessageWasSent(
       ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID));
 }
 
 TEST_F(SearchIPCRouterTest, SendMostVisitedItemsMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendMostVisitedItems()).Times(1)
       .WillOnce(testing::Return(true));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SendMostVisitedItems(
+  GetSearchTabHelper(contents)->ipc_router().SendMostVisitedItems(
       std::vector<InstantMostVisitedItem>());
   EXPECT_TRUE(MessageWasSent(
       ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID));
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendMostVisitedItemsMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendMostVisitedItems()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SendMostVisitedItems(
+  GetSearchTabHelper(contents)->ipc_router().SendMostVisitedItems(
       std::vector<InstantMostVisitedItem>());
   EXPECT_FALSE(MessageWasSent(
       ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID));
 }
 
 TEST_F(SearchIPCRouterTest, SendThemeBackgroundInfoMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendThemeBackgroundInfo()).Times(1)
       .WillOnce(testing::Return(true));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SendThemeBackgroundInfo(
+  GetSearchTabHelper(contents)->ipc_router().SendThemeBackgroundInfo(
       ThemeBackgroundInfo());
   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID));
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendThemeBackgroundInfoMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSendThemeBackgroundInfo()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->ipc_router().SendThemeBackgroundInfo(
+  GetSearchTabHelper(contents)->ipc_router().SendThemeBackgroundInfo(
       ThemeBackgroundInfo());
   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID));
 }
 
 TEST_F(SearchIPCRouterTest, SendSubmitMsg) {
-  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSubmitQuery()).Times(1)
       .WillOnce(testing::Return(true));
 
-  GetSearchTabHelper(web_contents())->ipc_router().Submit(string16());
+  GetSearchTabHelper(contents)->ipc_router().Submit(string16());
   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID));
 }
 
 TEST_F(SearchIPCRouterTest, DoNotSendSubmitMsg) {
-  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
 
-  SetupMockDelegateAndPolicy(web_contents());
+  content::WebContents* contents = web_contents();
+  SetupMockDelegateAndPolicy(contents);
   MockSearchIPCRouterPolicy* policy =
-      GetSearchIPCRouterPolicy(web_contents());
+      GetSearchIPCRouterPolicy(contents);
   EXPECT_CALL(*policy, ShouldSubmitQuery()).Times(1)
       .WillOnce(testing::Return(false));
 
-  GetSearchTabHelper(web_contents())->ipc_router().Submit(string16());
+  GetSearchTabHelper(contents)->ipc_router().Submit(string16());
   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID));
 }
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 495cb06..47e9aa5 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -8,18 +8,21 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/strings/string16.h"
 #include "build/build_config.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/history/most_visited_tiles_experiment.h"
 #include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
@@ -34,9 +37,11 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/common/page_transition_types.h"
+#include "content/public/common/referrer.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -105,7 +110,7 @@
 
 // Updates the location bar to reflect |contents| Instant support state.
 void UpdateLocationBar(content::WebContents* contents) {
-// iOS and Android doesn't use the Instant framework.
+// iOS and Android don't use the Instant framework.
 #if !defined(OS_IOS) && !defined(OS_ANDROID)
   if (!contents)
     return;
@@ -207,6 +212,14 @@
   ipc_router_.Submit(text);
 }
 
+void SearchTabHelper::OnTabActivated() {
+  ipc_router_.OnTabActivated();
+}
+
+void SearchTabHelper::OnTabDeactivated() {
+  ipc_router_.OnTabDeactivated();
+}
+
 void SearchTabHelper::Observe(
     int type,
     const content::NotificationSource& source,
@@ -371,7 +384,7 @@
 }
 
 void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) {
-// iOS and Android doesn't use the Instant framework.
+// iOS and Android don't use the Instant framework.
 #if !defined(OS_IOS) && !defined(OS_ANDROID)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser)
@@ -412,6 +425,36 @@
 #endif
 }
 
+void SearchTabHelper::NavigateToURL(const GURL& url,
+                                    WindowOpenDisposition disposition,
+                                    bool is_most_visited_item_url) {
+// iOS and Android don't use the Instant framework.
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
+  // TODO(kmadhusu): Remove chrome::FindBrowser...() function call from here.
+  // Create a SearchTabHelperDelegate interface and have the Browser object
+  // implement that interface to provide the necessary functionality.
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
+  if (!browser || !profile)
+    return;
+
+  if (is_most_visited_item_url) {
+    content::RecordAction(
+        content::UserMetricsAction("InstantExtended.MostVisitedClicked"));
+  }
+
+  chrome::NavigateParams params(browser, url,
+                                content::PAGE_TRANSITION_AUTO_BOOKMARK);
+  params.referrer = content::Referrer();
+  params.source_contents = web_contents_;
+  params.disposition = disposition;
+  params.is_renderer_initiated = false;
+  params.initiating_profile = profile;
+  chrome::Navigate(&params);
+#endif
+}
+
 void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) {
   DCHECK(!url.is_empty());
   if (instant_service_)
@@ -435,6 +478,35 @@
     data->LogEvent(event);
 }
 
+void SearchTabHelper::PasteIntoOmnibox(const string16& text) {
+// iOS and Android don't use the Instant framework.
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
+  if (!browser)
+    return;
+
+  OmniboxView* omnibox_view = browser->window()->GetLocationBar()->
+      GetLocationEntry();
+  // The first case is for right click to paste, where the text is retrieved
+  // from the clipboard already sanitized. The second case is needed to handle
+  // drag-and-drop value and it has to be sanitazed before setting it into the
+  // omnibox.
+  string16 text_to_paste = text.empty() ? omnibox_view->GetClipboardText() :
+      omnibox_view->SanitizeTextForPaste(text);
+
+  if (text_to_paste.empty())
+    return;
+
+  if (!omnibox_view->model()->has_focus())
+    omnibox_view->SetFocus();
+
+  omnibox_view->OnBeforePossibleChange();
+  omnibox_view->model()->on_paste();
+  omnibox_view->SetUserText(text_to_paste);
+  omnibox_view->OnAfterPossibleChange();
+#endif
+}
+
 void SearchTabHelper::UpdateMode(bool update_origin, bool is_preloaded_ntp) {
   SearchMode::Type type = SearchMode::MODE_DEFAULT;
   SearchMode::Origin origin = SearchMode::ORIGIN_DEFAULT;
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h
index 64e6921..516266a 100644
--- a/chrome/browser/ui/search/search_tab_helper.h
+++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -19,11 +19,13 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "ui/base/window_open_disposition.h"
 
 namespace content {
 class WebContents;
 }
 
+class GURL;
 class InstantPageTest;
 class InstantService;
 class Profile;
@@ -74,6 +76,12 @@
   // Tells the page that the user pressed Enter in the omnibox.
   void Submit(const string16& text);
 
+  // Called when the tab corresponding to |this| instance is activated.
+  void OnTabActivated();
+
+  // Called when the tab corresponding to |this| instance is deactivated.
+  void OnTabDeactivated();
+
  private:
   friend class content::WebContentsUserData<SearchTabHelper>;
   friend class InstantPageTest;
@@ -108,6 +116,7 @@
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            AppropriateMessagesSentToIncognitoPages);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest, SubmitQuery);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest, ProcessNavigateToURL);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            ProcessDeleteMostVisitedItem);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
@@ -115,16 +124,25 @@
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            ProcessUndoAllMostVisitedDeletions);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           ProcessPasteIntoOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           DoNotProcessPasteIntoOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
                            DoNotProcessMessagesForIncognitoPage);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterPolicyTest,
+                           DoNotProcessMessagesForInactiveTab);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessVoiceSearchSupportMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreVoiceSearchSupportMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessFocusOmniboxMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreFocusOmniboxMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, HandleTabChangedEvents);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, SendSetPromoInformationMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            DoNotSendSetPromoInformationMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessLogEventMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreLogEventMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessNavigateToURLMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnoreNavigateToURLMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            ProcessDeleteMostVisitedItemMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
@@ -140,8 +158,6 @@
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            IgnoreMessageIfThePageIsNotActive);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
-                           SendSetDisplayInstantResultsMsg);
-  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest,
                            DoNotSendSetDisplayInstantResultsMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, SendMostVisitedItemsMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, DoNotSendMostVisitedItemsMsg);
@@ -150,6 +166,8 @@
                            DoNotSendThemeBackgroundInfoMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, SendSubmitMsg);
   FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, DoNotSendSubmitMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, ProcessPasteAndOpenDropdownMsg);
+  FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, IgnorePasteAndOpenDropdownMsg);
   FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
                            DetermineIfPageSupportsInstant_Local);
   FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
@@ -189,10 +207,14 @@
   virtual void OnInstantSupportDetermined(bool supports_instant) OVERRIDE;
   virtual void OnSetVoiceSearchSupport(bool supports_voice_search) OVERRIDE;
   virtual void FocusOmnibox(OmniboxFocusState state) OVERRIDE;
+  virtual void NavigateToURL(const GURL& url,
+                             WindowOpenDisposition disposition,
+                             bool is_most_visited_item_url) OVERRIDE;
   virtual void OnDeleteMostVisitedItem(const GURL& url) OVERRIDE;
   virtual void OnUndoMostVisitedDeletion(const GURL& url) OVERRIDE;
   virtual void OnUndoAllMostVisitedDeletions() OVERRIDE;
   virtual void OnLogEvent(NTPLoggingEventType event) OVERRIDE;
+  virtual void PasteIntoOmnibox(const string16& text) OVERRIDE;
 
   // Overridden from InstantServiceObserver:
   virtual void ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) OVERRIDE;
diff --git a/chrome/browser/ui/search/search_tab_helper_unittest.cc b/chrome/browser/ui/search/search_tab_helper_unittest.cc
index 7e8fc3a..22e4e53 100644
--- a/chrome/browser/ui/search/search_tab_helper_unittest.cc
+++ b/chrome/browser/ui/search/search_tab_helper_unittest.cc
@@ -32,10 +32,12 @@
   MOCK_METHOD1(OnInstantSupportDetermined, void(bool supports_instant));
   MOCK_METHOD1(OnSetVoiceSearchSupport, void(bool supports_voice_search));
   MOCK_METHOD1(FocusOmnibox, void(OmniboxFocusState state));
+  MOCK_METHOD3(NavigateToURL, void(const GURL&, WindowOpenDisposition, bool));
   MOCK_METHOD1(OnDeleteMostVisitedItem, void(const GURL& url));
   MOCK_METHOD1(OnUndoMostVisitedDeletion, void(const GURL& url));
   MOCK_METHOD0(OnUndoAllMostVisitedDeletions, void());
   MOCK_METHOD1(OnLogEvent, void(NTPLoggingEventType event));
+  MOCK_METHOD1(PasteIntoOmnibox, void(const string16&));
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc
index 072885c..dffbc50 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.cc
+++ b/chrome/browser/ui/search_engines/template_url_table_model.cc
@@ -153,7 +153,7 @@
     // the lists while editing.
     if (template_url->show_in_default_list())
       default_entries.push_back(new ModelEntry(this, template_url));
-    else if (template_url->IsExtensionKeyword())
+    else if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)
       extension_entries.push_back(new ModelEntry(this, template_url));
     else
       other_entries.push_back(new ModelEntry(this, template_url));
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index d8d4c14..8a2b513 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -373,8 +373,10 @@
       return true;
     }
   } else if (command_line_.HasSwitch(switches::kShowAppList)) {
+    // This switch is used for shortcuts on the native desktop.
     AppListService::RecordShowTimings(command_line_);
-    AppListService::Get()->ShowForProfile(profile);
+    AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->
+        ShowForProfile(profile);
     return true;
   }
 
@@ -603,7 +605,8 @@
     // Chrome may have been running in the background due to an app with a
     // background page being installed, or running with only an app window
     // displayed.
-    SessionService* service = SessionServiceFactory::GetForProfile(profile_);
+    SessionService* service =
+        SessionServiceFactory::GetForProfileForSessionRestore(profile_);
     if (service && service->ShouldNewWindowStartSession()) {
       // Restore the last session if any.
       if (!HasPendingUncleanExit(profile_) &&
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 7bd2e7d..cac3dd8 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -14,9 +14,11 @@
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -29,7 +31,6 @@
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_io_data.h"
@@ -323,7 +324,7 @@
       break;
     default:
       // This switch statement needs to be updated when the enum Source changes.
-      COMPILE_ASSERT(signin::SOURCE_UNKNOWN == 9,
+      COMPILE_ASSERT(signin::SOURCE_UNKNOWN == 11,
                      kSourceEnumHasChangedButNotThisSwitchStatement);
       NOTREACHED();
       return;
@@ -353,6 +354,17 @@
   contents->OpenURL(params);
 }
 
+void RedirectToNtpOrAppsPageWithIds(int child_id,
+                                    int route_id,
+                                    signin::Source source) {
+  content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id,
+                                                                    route_id);
+  if (!web_contents)
+    return;
+
+  RedirectToNtpOrAppsPage(web_contents, source);
+}
+
 // If the |source| is not settings page/webstore, redirects to
 // the NTP/Apps page.
 void RedirectToNtpOrAppsPageIfNecessary(content::WebContents* contents,
@@ -414,17 +426,21 @@
     // the action is CREATE_NEW_USER because the "Create new user" page might
     // be opened in a different tab that is already showing settings.
     //
-    // Don't redirect when this callback is called while there is a navigation
-    // in progress. Otherwise, there would be 2 nested navigations and a crash
-    // would occur (crbug.com/293261).
-    //
-    // Also, don't redirect when the visible URL is not a blank page: if the
+    // Don't redirect when the visible URL is not a blank page: if the
     // source is SOURCE_WEBSTORE_INSTALL, |contents| might be showing an app
     // page that shouldn't be hidden.
-    if (!contents->IsLoading() &&
-        signin::IsContinueUrlForWebBasedSigninFlow(
+    //
+    // If redirecting, don't do so immediately, otherwise there may be 2 nested
+    // navigations and a crash would occur (crbug.com/293261).  Post the task
+    // to the current thread instead.
+    if (signin::IsContinueUrlForWebBasedSigninFlow(
             contents->GetVisibleURL())) {
-      RedirectToNtpOrAppsPage(contents, args.source);
+      base::MessageLoopProxy::current()->PostNonNestableTask(
+          FROM_HERE,
+          base::Bind(RedirectToNtpOrAppsPageWithIds,
+                     contents->GetRenderProcessHost()->GetID(),
+                     contents->GetRoutingID(),
+                     args.source));
     }
     if (action == ConfirmEmailDialogDelegate::CREATE_NEW_USER) {
       chrome::ShowSettingsSubPage(args.browser,
diff --git a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
index d3e945b..13b20c0 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
@@ -3,12 +3,12 @@
 // found in the LICENSE file.
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_io_data.h"
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 28af3dc..c8ac37f 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -151,15 +151,18 @@
 }
 
 void OneClickSigninSyncStarter::SigninDialogDelegate::OnCancelSignin() {
-  sync_starter_->CancelSigninAndDelete();
+  if (sync_starter_ != NULL)
+    sync_starter_->CancelSigninAndDelete();
 }
 
 void OneClickSigninSyncStarter::SigninDialogDelegate::OnContinueSignin() {
-  sync_starter_->LoadPolicyWithCachedClient();
+  if (sync_starter_ != NULL)
+    sync_starter_->LoadPolicyWithCachedClient();
 }
 
 void OneClickSigninSyncStarter::SigninDialogDelegate::OnSigninWithNewProfile() {
-  sync_starter_->CreateNewSignedInProfile();
+  if (sync_starter_ != NULL)
+    sync_starter_->CreateNewSignedInProfile();
 }
 
 void OneClickSigninSyncStarter::OnRegisteredForPolicy(
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
index f6bfb0c..99056df 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -29,13 +29,13 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
index 746861f..9d36fdd 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
@@ -193,6 +193,8 @@
   testing_pref_service.registry()->RegisterBooleanPref(
       prefs::kRestartLastSessionOnShutdown,
       false);
+  testing_pref_service.registry()->RegisterListPref(
+      prefs::kProfilesLastActive);
 
   TestingBrowserProcess* testing_browser_process =
       TestingBrowserProcess::GetGlobal();
diff --git a/chrome/browser/ui/tabs/pinned_tab_codec.cc b/chrome/browser/ui/tabs/pinned_tab_codec.cc
index 66985b6..e1932d0 100644
--- a/chrome/browser/ui/tabs/pinned_tab_codec.cc
+++ b/chrome/browser/ui/tabs/pinned_tab_codec.cc
@@ -5,9 +5,9 @@
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
 
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_iterator.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 91042c7..980e549 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -21,10 +21,11 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
 #include "chrome/common/url_constants.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_view.h"
 
 using content::UserMetricsAction;
@@ -48,7 +49,7 @@
 // CloseTracker is used when closing a set of WebContents. It listens for
 // deletions of the WebContents and removes from the internal set any time one
 // is deleted.
-class CloseTracker {
+class CloseTracker : public content::NotificationObserver {
  public:
   typedef std::vector<WebContents*> Contents;
 
@@ -62,181 +63,53 @@
   WebContents* Next();
 
  private:
-  class DeletionObserver : public content::WebContentsObserver {
-   public:
-    DeletionObserver(CloseTracker* parent, WebContents* web_contents)
-        : WebContentsObserver(web_contents),
-          parent_(parent) {
-    }
+  // NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
 
-    // Expose web_contents() publicly.
-    using content::WebContentsObserver::web_contents;
+  Contents contents_;
 
-   private:
-    // WebContentsObserver:
-    virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
-      parent_->OnWebContentsDestroyed(this);
-    }
-
-    CloseTracker* parent_;
-
-    DISALLOW_COPY_AND_ASSIGN(DeletionObserver);
-  };
-
-  void OnWebContentsDestroyed(DeletionObserver* observer);
-
-  typedef std::vector<DeletionObserver*> Observers;
-  Observers observers_;
+  content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(CloseTracker);
 };
 
-CloseTracker::CloseTracker(const Contents& contents) {
-  for (size_t i = 0; i < contents.size(); ++i)
-    observers_.push_back(new DeletionObserver(this, contents[i]));
+CloseTracker::CloseTracker(const Contents& contents)
+    : contents_(contents) {
+  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+                 content::NotificationService::AllBrowserContextsAndSources());
 }
 
 CloseTracker::~CloseTracker() {
-  DCHECK(observers_.empty());
 }
 
 bool CloseTracker::HasNext() const {
-  return !observers_.empty();
+  return !contents_.empty();
 }
 
 WebContents* CloseTracker::Next() {
-  if (observers_.empty())
+  if (contents_.empty())
     return NULL;
 
-  DeletionObserver* observer = observers_[0];
-  WebContents* web_contents = observer->web_contents();
-  observers_.erase(observers_.begin());
-  delete observer;
+  WebContents* web_contents = contents_[0];
+  contents_.erase(contents_.begin());
   return web_contents;
 }
 
-void CloseTracker::OnWebContentsDestroyed(DeletionObserver* observer) {
-  Observers::iterator i =
-      std::find(observers_.begin(), observers_.end(), observer);
-  if (i != observers_.end()) {
-    delete *i;
-    observers_.erase(i);
-    return;
-  }
-  NOTREACHED() << "WebContents destroyed that wasn't in the list";
+void CloseTracker::Observe(int type,
+                           const content::NotificationSource& source,
+                           const content::NotificationDetails& details) {
+  WebContents* web_contents = content::Source<WebContents>(source).ptr();
+  Contents::iterator i =
+      std::find(contents_.begin(), contents_.end(), web_contents);
+  if (i != contents_.end())
+    contents_.erase(i);
 }
 
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
-// WebContentsData
-
-// An object to hold a reference to a WebContents that is in a tabstrip, as
-// well as other various properties it has.
-class TabStripModel::WebContentsData : public content::WebContentsObserver {
- public:
-  WebContentsData(TabStripModel* tab_strip_model, WebContents* a_contents);
-
-  // Changes the WebContents that this WebContentsData tracks.
-  void SetWebContents(WebContents* contents);
-  WebContents* web_contents() { return contents_; }
-
-  // Create a relationship between this WebContentsData and other
-  // WebContentses. Used to identify which WebContents to select next after
-  // one is closed.
-  WebContents* group() const { return group_; }
-  void set_group(WebContents* value) { group_ = value; }
-  WebContents* opener() const { return opener_; }
-  void set_opener(WebContents* value) { opener_ = value; }
-
-  // Alters the properties of the WebContents.
-  bool reset_group_on_select() const { return reset_group_on_select_; }
-  void set_reset_group_on_select(bool value) { reset_group_on_select_ = value; }
-  bool pinned() const { return pinned_; }
-  void set_pinned(bool value) { pinned_ = value; }
-  bool blocked() const { return blocked_; }
-  void set_blocked(bool value) { blocked_ = value; }
-  bool discarded() const { return discarded_; }
-  void set_discarded(bool value) { discarded_ = value; }
-
- private:
-  // Make sure that if someone deletes this WebContents out from under us, it
-  // is properly removed from the tab strip.
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
-
-  // The WebContents being tracked by this WebContentsData. The
-  // WebContentsObserver does keep a reference, but when the WebContents is
-  // deleted, the WebContentsObserver reference is NULLed and thus inaccessible.
-  WebContents* contents_;
-
-  // The TabStripModel containing this WebContents.
-  TabStripModel* tab_strip_model_;
-
-  // The group is used to model a set of tabs spawned from a single parent
-  // tab. This value is preserved for a given tab as long as the tab remains
-  // navigated to the link it was initially opened at or some navigation from
-  // that page (i.e. if the user types or visits a bookmark or some other
-  // navigation within that tab, the group relationship is lost). This
-  // property can safely be used to implement features that depend on a
-  // logical group of related tabs.
-  WebContents* group_;
-
-  // The owner models the same relationship as group, except it is more
-  // easily discarded, e.g. when the user switches to a tab not part of the
-  // same group. This property is used to determine what tab to select next
-  // when one is closed.
-  WebContents* opener_;
-
-  // True if our group should be reset the moment selection moves away from
-  // this tab. This is the case for tabs opened in the foreground at the end
-  // of the TabStrip while viewing another Tab. If these tabs are closed
-  // before selection moves elsewhere, their opener is selected. But if
-  // selection shifts to _any_ tab (including their opener), the group
-  // relationship is reset to avoid confusing close sequencing.
-  bool reset_group_on_select_;
-
-  // Is the tab pinned?
-  bool pinned_;
-
-  // Is the tab interaction blocked by a modal dialog?
-  bool blocked_;
-
-  // Has the tab data been discarded to save memory?
-  bool discarded_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebContentsData);
-};
-
-TabStripModel::WebContentsData::WebContentsData(TabStripModel* tab_strip_model,
-                                                WebContents* contents)
-    : content::WebContentsObserver(contents),
-      contents_(contents),
-      tab_strip_model_(tab_strip_model),
-      group_(NULL),
-      opener_(NULL),
-      reset_group_on_select_(false),
-      pinned_(false),
-      blocked_(false),
-      discarded_(false) {
-}
-
-void TabStripModel::WebContentsData::SetWebContents(WebContents* contents) {
-  contents_ = contents;
-  Observe(contents);
-}
-
-void TabStripModel::WebContentsData::WebContentsDestroyed(
-    WebContents* web_contents) {
-  DCHECK_EQ(contents_, web_contents);
-
-  // Note that we only detach the contents here, not close it - it's
-  // already been closed. We just want to undo our bookkeeping.
-  int index = tab_strip_model_->GetIndexOfWebContents(web_contents);
-  DCHECK_NE(TabStripModel::kNoTab, index);
-  tab_strip_model_->DetachWebContentsAt(index);
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // TabStripModel, public:
 
 TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile)
@@ -245,6 +118,8 @@
       closing_all_(false),
       in_notify_(false) {
   DCHECK(delegate_);
+  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+                 content::NotificationService::AllBrowserContextsAndSources());
   order_controller_.reset(new TabStripModelOrderController(this));
 }
 
@@ -295,12 +170,12 @@
   // to clear this bit.
   closing_all_ = false;
 
-  // Have to get the active contents before we monkey with the contents
+  // Have to get the active contents before we monkey with |contents_|
   // otherwise we run into problems when we try to change the active contents
   // since the old contents and the new contents will be the same...
   WebContents* active_contents = GetActiveWebContents();
-  WebContentsData* data = new WebContentsData(this, contents);
-  data->set_pinned(pin);
+  WebContentsData* data = new WebContentsData(contents);
+  data->pinned = pin;
   if ((add_types & ADD_INHERIT_GROUP) && active_contents) {
     if (active) {
       // Forget any existing relationships, we don't want to make things too
@@ -308,21 +183,20 @@
       ForgetAllOpeners();
     }
     // Anything opened by a link we deem to have an opener.
-    data->set_group(active_contents);
-    data->set_opener(active_contents);
+    data->SetGroup(active_contents);
   } else if ((add_types & ADD_INHERIT_OPENER) && active_contents) {
     if (active) {
       // Forget any existing relationships, we don't want to make things too
       // confusing by having multiple groups active at the same time.
       ForgetAllOpeners();
     }
-    data->set_opener(active_contents);
+    data->opener = active_contents;
   }
 
   web_modal::WebContentsModalDialogManager* modal_dialog_manager =
       web_modal::WebContentsModalDialogManager::FromWebContents(contents);
   if (modal_dialog_manager)
-    data->set_blocked(modal_dialog_manager->IsDialogActive());
+    data->blocked = modal_dialog_manager->IsDialogActive();
 
   contents_data_.insert(contents_data_.begin() + index, data);
 
@@ -347,7 +221,7 @@
 
   ForgetOpenersAndGroupsReferencing(old_contents);
 
-  contents_data_[index]->SetWebContents(new_contents);
+  contents_data_[index]->contents = new_contents;
 
   FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
                     TabReplacedAt(this, old_contents, new_contents, index));
@@ -382,7 +256,7 @@
   // Replace the tab we're discarding with the null version.
   ReplaceWebContentsAt(index, null_contents);
   // Mark the tab so it will reload when we click.
-  contents_data_[index]->set_discarded(true);
+  contents_data_[index]->discarded = true;
   // Discard the old tab's renderer.
   // TODO(jamescook): This breaks script connections with other tabs.
   // We need to find a different approach that doesn't do that, perhaps based
@@ -524,7 +398,7 @@
 
 int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
   for (size_t i = 0; i < contents_data_.size(); ++i) {
-    if (contents_data_[i]->web_contents() == contents)
+    if (contents_data_[i]->contents == contents)
       return i;
   }
   return kNoTab;
@@ -559,7 +433,7 @@
 bool TabStripModel::TabsAreLoading() const {
   for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
        iter != contents_data_.end(); ++iter) {
-    if ((*iter)->web_contents()->IsLoading())
+    if ((*iter)->contents->IsLoading())
       return true;
   }
   return false;
@@ -567,14 +441,14 @@
 
 WebContents* TabStripModel::GetOpenerOfWebContentsAt(int index) {
   DCHECK(ContainsIndex(index));
-  return contents_data_[index]->opener();
+  return contents_data_[index]->opener;
 }
 
 void TabStripModel::SetOpenerOfWebContentsAt(int index,
                                              WebContents* opener) {
   DCHECK(ContainsIndex(index));
   DCHECK(opener);
-  contents_data_[index]->set_opener(opener);
+  contents_data_[index]->opener = opener;
 }
 
 int TabStripModel::GetIndexOfNextWebContentsOpenedBy(const WebContents* opener,
@@ -602,7 +476,7 @@
   DCHECK(ContainsIndex(start_index));
 
   for (int i = contents_data_.size() - 1; i > start_index; --i) {
-    if (contents_data_[i]->opener() == opener)
+    if (contents_data_[i]->opener == opener)
       return i;
   }
   return kNoTab;
@@ -635,36 +509,35 @@
   // re-selection ordering.
   for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
        iter != contents_data_.end(); ++iter)
-    (*iter)->set_opener(NULL);
+    (*iter)->ForgetOpener();
 }
 
 void TabStripModel::ForgetGroup(WebContents* contents) {
   int index = GetIndexOfWebContents(contents);
   DCHECK(ContainsIndex(index));
-  contents_data_[index]->set_group(NULL);
-  contents_data_[index]->set_opener(NULL);
+  contents_data_[index]->SetGroup(NULL);
+  contents_data_[index]->ForgetOpener();
 }
 
 bool TabStripModel::ShouldResetGroupOnSelect(WebContents* contents) const {
   int index = GetIndexOfWebContents(contents);
   DCHECK(ContainsIndex(index));
-  return contents_data_[index]->reset_group_on_select();
+  return contents_data_[index]->reset_group_on_select;
 }
 
 void TabStripModel::SetTabBlocked(int index, bool blocked) {
   DCHECK(ContainsIndex(index));
-  if (contents_data_[index]->blocked() == blocked)
+  if (contents_data_[index]->blocked == blocked)
     return;
-  contents_data_[index]->set_blocked(blocked);
-  FOR_EACH_OBSERVER(
-      TabStripModelObserver, observers_,
-      TabBlockedStateChanged(contents_data_[index]->web_contents(),
-                             index));
+  contents_data_[index]->blocked = blocked;
+  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+                    TabBlockedStateChanged(contents_data_[index]->contents,
+                                           index));
 }
 
 void TabStripModel::SetTabPinned(int index, bool pinned) {
   DCHECK(ContainsIndex(index));
-  if (contents_data_[index]->pinned() == pinned)
+  if (contents_data_[index]->pinned == pinned)
     return;
 
   if (IsAppTab(index)) {
@@ -675,12 +548,12 @@
     }
     // Changing the pinned state of an app tab doesn't affect its mini-tab
     // status.
-    contents_data_[index]->set_pinned(pinned);
+    contents_data_[index]->pinned = pinned;
   } else {
     // The tab is not an app tab, its position may have to change as the
     // mini-tab state is changing.
     int non_mini_tab_index = IndexOfFirstNonMiniTab();
-    contents_data_[index]->set_pinned(pinned);
+    contents_data_[index]->pinned = pinned;
     if (pinned && index != non_mini_tab_index) {
       MoveWebContentsAtImpl(index, non_mini_tab_index, false);
       index = non_mini_tab_index;
@@ -690,19 +563,19 @@
     }
 
     FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                      TabMiniStateChanged(contents_data_[index]->web_contents(),
+                      TabMiniStateChanged(contents_data_[index]->contents,
                                           index));
   }
 
   // else: the tab was at the boundary and its position doesn't need to change.
   FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabPinnedStateChanged(contents_data_[index]->web_contents(),
+                    TabPinnedStateChanged(contents_data_[index]->contents,
                                           index));
 }
 
 bool TabStripModel::IsTabPinned(int index) const {
   DCHECK(ContainsIndex(index));
-  return contents_data_[index]->pinned();
+  return contents_data_[index]->pinned;
 }
 
 bool TabStripModel::IsMiniTab(int index) const {
@@ -715,11 +588,11 @@
 }
 
 bool TabStripModel::IsTabBlocked(int index) const {
-  return contents_data_[index]->blocked();
+  return contents_data_[index]->blocked;
 }
 
 bool TabStripModel::IsTabDiscarded(int index) const {
-  return contents_data_[index]->discarded();
+  return contents_data_[index]->discarded;
 }
 
 int TabStripModel::IndexOfFirstNonMiniTab() const {
@@ -826,7 +699,7 @@
   index = GetIndexOfWebContents(contents);
 
   if (inherit_group && transition == content::PAGE_TRANSITION_TYPED)
-    contents_data_[index]->set_reset_group_on_select(true);
+    contents_data_[index]->reset_group_on_select = true;
 
   // TODO(sky): figure out why this is here and not in InsertWebContentsAt. When
   // here we seem to get failures in startup perf tests.
@@ -1096,6 +969,32 @@
   return !all_pinned;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// TabStripModel, content::NotificationObserver implementation:
+
+void TabStripModel::Observe(int type,
+                            const content::NotificationSource& source,
+                            const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
+      // Sometimes, on qemu, it seems like a WebContents object can be destroyed
+      // while we still have a reference to it. We need to break this reference
+      // here so we don't crash later.
+      int index = GetIndexOfWebContents(
+          content::Source<WebContents>(source).ptr());
+      if (index != TabStripModel::kNoTab) {
+        // Note that we only detach the contents here, not close it - it's
+        // already been closed. We just want to undo our bookkeeping.
+        DetachWebContentsAt(index);
+      }
+      break;
+    }
+
+    default:
+      NOTREACHED();
+  }
+}
+
 // static
 bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id,
                                                        int* browser_cmd) {
@@ -1152,7 +1051,7 @@
 
 void TabStripModel::GetIndicesWithSameOpener(int index,
                                              std::vector<int>* indices) {
-  WebContents* opener = contents_data_[index]->group();
+  WebContents* opener = contents_data_[index]->group;
   if (!opener) {
     // If there is no group, find all tabs with the selected tab as the opener.
     opener = GetWebContentsAt(index);
@@ -1162,7 +1061,7 @@
   for (int i = 0; i < count(); ++i) {
     if (i == index)
       continue;
-    if (contents_data_[i]->group() == opener ||
+    if (contents_data_[i]->group == opener ||
         GetWebContentsAtImpl(i) == opener) {
       indices->push_back(i);
     }
@@ -1260,14 +1159,14 @@
     delegate_->CreateHistoricalTab(contents);
 
   // Deleting the WebContents will call back to us via
-  // WebContentsData::WebContentsDestroyed and detach it.
+  // NotificationObserver and detach it.
   delete contents;
 }
 
 WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
   CHECK(ContainsIndex(index)) <<
       "Failed to find: " << index << " in: " << count() << " entries.";
-  return contents_data_[index]->web_contents();
+  return contents_data_[index]->contents;
 }
 
 void TabStripModel::NotifyIfTabDeactivated(WebContents* contents) {
@@ -1293,7 +1192,7 @@
                          reason));
     in_notify_ = false;
     // Activating a discarded tab reloads it, so it is no longer discarded.
-    contents_data_[active_index()]->set_discarded(false);
+    contents_data_[active_index()]->discarded = false;
   }
 }
 
@@ -1346,10 +1245,10 @@
     selection_model_.SetSelectedIndex(to_position);
   }
 
-  ForgetOpenersAndGroupsReferencing(moved_data->web_contents());
+  ForgetOpenersAndGroupsReferencing(moved_data->contents);
 
   FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabMoved(moved_data->web_contents(), index, to_position));
+                    TabMoved(moved_data->contents, index, to_position));
 }
 
 void TabStripModel::MoveSelectedTabsToImpl(int index,
@@ -1392,16 +1291,16 @@
 bool TabStripModel::OpenerMatches(const WebContentsData* data,
                                   const WebContents* opener,
                                   bool use_group) {
-  return data->opener() == opener || (use_group && data->group() == opener);
+  return data->opener == opener || (use_group && data->group == opener);
 }
 
 void TabStripModel::ForgetOpenersAndGroupsReferencing(
     const WebContents* tab) {
   for (WebContentsDataVector::const_iterator i = contents_data_.begin();
        i != contents_data_.end(); ++i) {
-    if ((*i)->group() == tab)
-      (*i)->set_group(NULL);
-    if ((*i)->opener() == tab)
-      (*i)->set_opener(NULL);
+    if ((*i)->group == tab)
+      (*i)->group = NULL;
+    if ((*i)->opener == tab)
+      (*i)->opener = NULL;
   }
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 83a25e5..ab3be89 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -10,6 +10,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "content/public/common/page_transition_types.h"
 #include "ui/base/models/list_selection_model.h"
 
@@ -57,7 +59,7 @@
 //  its bookkeeping when such events happen.
 //
 ////////////////////////////////////////////////////////////////////////////////
-class TabStripModel {
+class TabStripModel : public content::NotificationObserver {
  public:
   // Used to specify what should happen when the tab is closed.
   enum CloseTypes {
@@ -439,13 +441,16 @@
   // supplied to |ExecuteContextMenuCommand|.
   bool WillContextMenuPin(int index);
 
+  // Overridden from content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
   // Convert a ContextMenuCommand into a browser command. Returns true if a
   // corresponding browser command exists, false otherwise.
   static bool ContextMenuCommandToBrowserCommand(int cmd_id, int* browser_cmd);
 
  private:
-  class WebContentsData;
-
   // Used when making selection notifications.
   enum NotifyTypes {
     NOTIFY_DEFAULT,
@@ -543,6 +548,7 @@
   // Returns true if the tab represented by the specified data has an opener
   // that matches the specified one. If |use_group| is true, then this will
   // fall back to check the group relationship as well.
+  struct WebContentsData;
   static bool OpenerMatches(const WebContentsData* data,
                             const content::WebContents* opener,
                             bool use_group);
@@ -553,6 +559,66 @@
   // Our delegate.
   TabStripModelDelegate* delegate_;
 
+  // A hunk of data representing a WebContents and (optionally) the
+  // WebContents that spawned it. This memory only sticks around while
+  // the WebContents is in the current TabStripModel, unless otherwise
+  // specified in code.
+  struct WebContentsData {
+    explicit WebContentsData(content::WebContents* a_contents)
+        : contents(a_contents),
+          reset_group_on_select(false),
+          pinned(false),
+          blocked(false),
+          discarded(false) {
+      SetGroup(NULL);
+    }
+
+    // Create a relationship between this WebContentsData and other
+    // WebContentses. Used to identify which WebContents to select next after
+    // one is closed.
+    void SetGroup(content::WebContents* a_group) {
+      group = a_group;
+      opener = a_group;
+    }
+
+    // Forget the opener relationship so that when this WebContents is
+    // closed unpredictable re-selection does not occur.
+    void ForgetOpener() {
+      opener = NULL;
+    }
+
+    content::WebContents* contents;
+    // The group is used to model a set of tabs spawned from a single parent
+    // tab. This value is preserved for a given tab as long as the tab remains
+    // navigated to the link it was initially opened at or some navigation from
+    // that page (i.e. if the user types or visits a bookmark or some other
+    // navigation within that tab, the group relationship is lost). This
+    // property can safely be used to implement features that depend on a
+    // logical group of related tabs.
+    content::WebContents* group;
+    // The owner models the same relationship as group, except it is more
+    // easily discarded, e.g. when the user switches to a tab not part of the
+    // same group. This property is used to determine what tab to select next
+    // when one is closed.
+    content::WebContents* opener;
+    // True if our group should be reset the moment selection moves away from
+    // this tab. This is the case for tabs opened in the foreground at the end
+    // of the TabStrip while viewing another Tab. If these tabs are closed
+    // before selection moves elsewhere, their opener is selected. But if
+    // selection shifts to _any_ tab (including their opener), the group
+    // relationship is reset to avoid confusing close sequencing.
+    bool reset_group_on_select;
+
+    // Is the tab pinned?
+    bool pinned;
+
+    // Is the tab interaction blocked by a modal dialog?
+    bool blocked;
+
+    // Has the tab data been discarded to save memory?
+    bool discarded;
+  };
+
   // The WebContents data currently hosted within this TabStripModel.
   typedef std::vector<WebContentsData*> WebContentsDataVector;
   WebContentsDataVector contents_data_;
@@ -571,6 +637,9 @@
   typedef ObserverList<TabStripModelObserver> TabStripModelObservers;
   TabStripModelObservers observers_;
 
+  // A scoped container for notification registries.
+  content::NotificationRegistrar registrar_;
+
   ui::ListSelectionModel selection_model_;
 
   // TODO(sky): remove this; used for debugging 291265.
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 0285ce2..546b9eb 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -31,9 +32,11 @@
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::SiteInstance;
@@ -46,19 +49,23 @@
 // Class used to delete a WebContents and TabStripModel when another WebContents
 // is destroyed.
 class DeleteWebContentsOnDestroyedObserver
-    : public content::WebContentsObserver {
+    : public content::NotificationObserver {
  public:
   // When |source| is deleted both |tab_to_delete| and |tab_strip| are deleted.
   // |tab_to_delete| and |tab_strip| may be NULL.
   DeleteWebContentsOnDestroyedObserver(WebContents* source,
                                        WebContents* tab_to_delete,
                                        TabStripModel* tab_strip)
-      : WebContentsObserver(source),
+      : source_(source),
         tab_to_delete_(tab_to_delete),
         tab_strip_(tab_strip) {
+    registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+                   content::Source<WebContents>(source));
   }
 
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
     WebContents* tab_to_delete = tab_to_delete_;
     tab_to_delete_ = NULL;
     TabStripModel* tab_strip_to_delete = tab_strip_;
@@ -68,8 +75,10 @@
   }
 
  private:
+  WebContents* source_;
   WebContents* tab_to_delete_;
   TabStripModel* tab_strip_;
+  content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(DeleteWebContentsOnDestroyedObserver);
 };
diff --git a/chrome/browser/ui/tabs/tab_utils.cc b/chrome/browser/ui/tabs/tab_utils.cc
index a43ce41..9e2ba68 100644
--- a/chrome/browser/ui/tabs/tab_utils.cc
+++ b/chrome/browser/ui/tabs/tab_utils.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ui/tabs/tab_utils.h"
 
+#include "base/strings/string16.h"
 #include "chrome/browser/media/audio_stream_indicator.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/media_stream_capture_indicator.h"
+#include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/animation/multi_animation.h"
 
@@ -97,14 +100,9 @@
                                  TabMediaState media_state) {
   if (media_state == TAB_MEDIA_STATE_NONE)
     return false;
-  const bool audio_playback_active =
-      (media_state == TAB_MEDIA_STATE_AUDIO_PLAYING);
-  int required_capacity = (has_favicon && audio_playback_active) ?
-      2 :  // Must have capacity to also show the favicon.
-      1;  // Only need capacity to show the capturing/recording indicator.
   if (ShouldTabShowCloseButton(capacity, is_pinned_tab, is_active_tab))
-    ++required_capacity;
-  return capacity >= required_capacity;
+    return capacity >= 2;
+  return capacity >= 1;
 }
 
 bool ShouldTabShowCloseButton(int capacity,
@@ -183,4 +181,32 @@
   return animation.PassAs<gfx::Animation>();
 }
 
+base::string16 AssembleTabTooltipText(const base::string16& title,
+                                      TabMediaState media_state) {
+  if (media_state == TAB_MEDIA_STATE_NONE)
+    return title;
+
+  base::string16 result = title;
+  if (!result.empty())
+    result.append(1, '\n');
+  switch (media_state) {
+    case TAB_MEDIA_STATE_AUDIO_PLAYING:
+      result.append(
+          l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_PLAYING));
+      break;
+    case TAB_MEDIA_STATE_RECORDING:
+      result.append(
+          l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_RECORDING));
+      break;
+    case TAB_MEDIA_STATE_CAPTURING:
+      result.append(
+          l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_CAPTURING));
+      break;
+    case TAB_MEDIA_STATE_NONE:
+      NOTREACHED();
+      break;
+  }
+  return result;
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/ui/tabs/tab_utils.h b/chrome/browser/ui/tabs/tab_utils.h
index 114a655..c11000b 100644
--- a/chrome/browser/ui/tabs/tab_utils.h
+++ b/chrome/browser/ui/tabs/tab_utils.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_TABS_TAB_UTILS_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
 
 namespace content {
 class WebContents;
@@ -34,12 +35,11 @@
 // Precedence rules for deciding what to show when capacity is insufficient to
 // show everything:
 //
-//   Active tab: Always show the close button, then the capture/recording
-//               indicator, then favicon, then audio playback indicator.
-//   Inactive tab: Capture/Recording indicator, then favicon, then audio
-//                 playback indicator, then close button.
-//   Pinned tab: Capture/recording indicator, then favicon, then audio
-//               playback indicator.  Never show the close button.
+//   Active tab: Always show the close button, then the media indicator, then
+//               the favicon.
+//   Inactive tab: Media indicator, then the favicon, then the close button.
+//   Pinned tab: Show only the media indicator, or only the favicon
+//               (TAB_MEDIA_STATE_NONE).  Never show the close button.
 bool ShouldTabShowFavicon(int capacity,
                           bool is_pinned_tab,
                           bool is_active_tab,
@@ -74,6 +74,11 @@
 scoped_ptr<gfx::Animation> CreateTabMediaIndicatorFadeAnimation(
     TabMediaState next_media_state);
 
+// Returns the text to show in a tab's tooltip: The contents |title|, followed
+// by a break, followed by a localized string describing the |media_state|.
+base::string16 AssembleTabTooltipText(const base::string16& title,
+                                      TabMediaState media_state);
+
 }  // namespace chrome
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_UTILS_H_
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index 829eb06..6f56a86 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -6,11 +6,11 @@
 
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -579,21 +579,24 @@
 }
 
 void RecentTabsSubMenuModel::AddTabFavicon(int command_id, const GURL& url) {
+  bool is_local_tab = command_id < kFirstOtherDevicesTabCommandId;
   int index_in_menu = GetIndexOfCommandId(command_id);
 
-  // If tab has synced favicon, use it.
-  // Note that currently, other devices' tabs only have favicons if
-  // --sync-tab-favicons switch is on; according to zea@, this flag is now
-  // automatically enabled for iOS and android, and they're looking into
-  // enabling it for other platforms.
-  browser_sync::SessionModelAssociator* associator = GetModelAssociator();
-  scoped_refptr<base::RefCountedMemory> favicon_png;
-  if (associator &&
-      associator->GetSyncedFaviconForPageURL(url.spec(), &favicon_png)) {
-    gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(favicon_png->front(),
-                                                        favicon_png->size());
-    SetIcon(index_in_menu, image);
-    return;
+  if (!is_local_tab) {
+    // If tab has synced favicon, use it.
+    // Note that currently, other devices' tabs only have favicons if
+    // --sync-tab-favicons switch is on; according to zea@, this flag is now
+    // automatically enabled for iOS and android, and they're looking into
+    // enabling it for other platforms.
+    browser_sync::SessionModelAssociator* associator = GetModelAssociator();
+    scoped_refptr<base::RefCountedMemory> favicon_png;
+    if (associator &&
+        associator->GetSyncedFaviconForPageURL(url.spec(), &favicon_png)) {
+      gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(favicon_png->front(),
+                                                          favicon_png->size());
+      SetIcon(index_in_menu, image);
+      return;
+    }
   }
 
   // Otherwise, start to fetch the favicon from local history asynchronously.
@@ -613,9 +616,8 @@
       base::Bind(&RecentTabsSubMenuModel::OnFaviconDataAvailable,
                  weak_ptr_factory_.GetWeakPtr(),
                  command_id),
-      command_id >= kFirstOtherDevicesTabCommandId ?
-          &other_devices_tab_cancelable_task_tracker_ :
-          &local_tab_cancelable_task_tracker_);
+      is_local_tab ? &local_tab_cancelable_task_tracker_ :
+                     &other_devices_tab_cancelable_task_tracker_);
 }
 
 void RecentTabsSubMenuModel::OnFaviconDataAvailable(
diff --git a/chrome/browser/ui/translate/language_combobox_model.cc b/chrome/browser/ui/translate/language_combobox_model.cc
index 031998a..4874fec 100644
--- a/chrome/browser/ui/translate/language_combobox_model.cc
+++ b/chrome/browser/ui/translate/language_combobox_model.cc
@@ -9,8 +9,10 @@
 LanguageComboboxModel::LanguageComboboxModel(
     int default_index,
     TranslateBubbleModel* model)
-    : default_index_(default_index),
+    : default_index_(default_index < 0 ? 0 : default_index),
       model_(model) {
+  // view::Combobox can't treate an negative index, but |default_index| can be
+  // negative when, for example, the page's language can't be detected.
 }
 
 LanguageComboboxModel::~LanguageComboboxModel() {
diff --git a/chrome/browser/ui/translate/translate_bubble_factory.cc b/chrome/browser/ui/translate/translate_bubble_factory.cc
new file mode 100644
index 0000000..8f0bd27
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_factory.cc
@@ -0,0 +1,44 @@
+// Copyright 2013 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/translate/translate_bubble_factory.h"
+
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+
+namespace {
+
+void ShowDefault(BrowserWindow* window,
+                 content::WebContents* web_contents,
+                 TranslateBubbleModel::ViewState view_state) {
+  // |window| might be null when testing.
+  if (!window)
+    return;
+  window->ShowTranslateBubble(web_contents, view_state);
+}
+
+}  // namespace
+
+TranslateBubbleFactory::~TranslateBubbleFactory() {
+}
+
+// static
+void TranslateBubbleFactory::Show(BrowserWindow* window,
+                                  content::WebContents* web_contents,
+                                  TranslateBubbleModel::ViewState view_state) {
+  if (current_factory_) {
+    current_factory_->ShowImplementation(window, web_contents, view_state);
+    return;
+  }
+
+  ShowDefault(window, web_contents, view_state);
+}
+
+// static
+void TranslateBubbleFactory::SetFactory(TranslateBubbleFactory* factory) {
+  current_factory_ = factory;
+}
+
+// static
+TranslateBubbleFactory* TranslateBubbleFactory::current_factory_ = NULL;
diff --git a/chrome/browser/ui/translate/translate_bubble_factory.h b/chrome/browser/ui/translate/translate_bubble_factory.h
new file mode 100644
index 0000000..1c17044
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_factory.h
@@ -0,0 +1,42 @@
+// Copyright 2013 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_TRANSLATE_TRANSLATE_BUBBLE_FACTORY_H_
+#define CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_FACTORY_H_
+
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+
+class BrowserWindow;
+
+namespace content {
+class WebContents;
+}
+
+// Factory to show the Translate bubble.
+class TranslateBubbleFactory {
+ public:
+  virtual ~TranslateBubbleFactory();
+
+  // Shows the translate bubble. The behavior depends on the current factory's
+  // implementation.
+  static void Show(BrowserWindow* window,
+                   content::WebContents* web_contents,
+                   TranslateBubbleModel::ViewState view_state);
+
+  // Sets the factory to change the behavior how to show the bubble.
+  // TranslateBubbleFactory doesn't take the ownership of |factory|.
+  static void SetFactory(TranslateBubbleFactory* factory);
+
+ protected:
+  // Shows the translate bubble.
+  virtual void ShowImplementation(
+      BrowserWindow* window,
+      content::WebContents* web_contents,
+      TranslateBubbleModel::ViewState view_state) = 0;
+
+ private:
+  static TranslateBubbleFactory* current_factory_;
+};
+
+#endif  // CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_FACTORY_H_
diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h
index 81e035e..72a8738 100644
--- a/chrome/browser/ui/view_ids.h
+++ b/chrome/browser/ui/view_ids.h
@@ -56,6 +56,7 @@
   VIEW_ID_FEEDBACK_BUTTON,
   VIEW_ID_OMNIBOX,
   VIEW_ID_SCRIPT_BUBBLE,
+  VIEW_ID_TRANSLATE_BUTTON,
 
   // The Bookmark Bar.
   VIEW_ID_BOOKMARK_BAR,
@@ -100,4 +101,3 @@
 };
 
 #endif  // CHROME_BROWSER_UI_VIEW_IDS_H_
-
diff --git a/chrome/browser/ui/views/accelerator_table_unittest.cc b/chrome/browser/ui/views/accelerator_table_unittest.cc
index f97303d..3984a38 100644
--- a/chrome/browser/ui/views/accelerator_table_unittest.cc
+++ b/chrome/browser/ui/views/accelerator_table_unittest.cc
@@ -56,6 +56,10 @@
     const ash::AcceleratorData& ash_entry = ash::kAcceleratorData[i];
     if (!ash_entry.trigger_on_press)
       continue;  // kAcceleratorMap does not have any release accelerators.
+    // The shortcut to toggle minimized state is defined on both ends
+    // by design. (see crbug.com/309915 and CL)
+    if (ash_entry.action == ash::WINDOW_MINIMIZE)
+      continue;
     AcceleratorMapping entry;
     entry.keycode = ash_entry.keycode;
     entry.modifiers = ash_entry.modifiers;
diff --git a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
index ca4458e..cc2f76d 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
+++ b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
@@ -5,51 +5,26 @@
 #include "chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h"
 
 #include "chrome/browser/ui/app_list/app_list_icon_win.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/views/app_list/win/app_list_service_win.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "net/base/url_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
 AppListControllerDelegateWin::AppListControllerDelegateWin(
     AppListServiceWin* service)
-    : service_(service) {
-}
+    : AppListControllerDelegateImpl(service),
+      service_(service) {}
 
 AppListControllerDelegateWin::~AppListControllerDelegateWin() {}
 
-void AppListControllerDelegateWin::DismissView() {
-  service_->DismissAppList();
-}
-
 void AppListControllerDelegateWin::ViewClosing() {
   service_->OnAppListClosing();
 }
 
-gfx::NativeWindow AppListControllerDelegateWin::GetAppListWindow() {
-  return service_->GetAppListWindow();
-}
-
 gfx::ImageSkia AppListControllerDelegateWin::GetWindowIcon() {
   gfx::ImageSkia* resource = ResourceBundle::GetSharedInstance().
       GetImageSkiaNamed(GetAppListIconResourceId());
   return *resource;
 }
 
-AppListControllerDelegate::Pinnable
-    AppListControllerDelegateWin::GetPinnable() {
-  return NO_PIN;
-}
-
-void AppListControllerDelegateWin::ShowForProfileByPath(
-    const base::FilePath& profile_path) {
-  service_->SetProfilePath(profile_path);
-  service_->Show();
-}
-
 void AppListControllerDelegateWin::OnShowExtensionPrompt() {
   service_->set_can_close(false);
 }
@@ -61,42 +36,3 @@
 bool AppListControllerDelegateWin::CanDoCreateShortcutsFlow() {
   return true;
 }
-
-void AppListControllerDelegateWin::CreateNewWindow(Profile* profile,
-                                                   bool incognito) {
-  Profile* window_profile = incognito ?
-      profile->GetOffTheRecordProfile() : profile;
-  chrome::NewEmptyWindow(window_profile, chrome::GetActiveDesktop());
-}
-
-void AppListControllerDelegateWin::ActivateApp(
-    Profile* profile,
-    const extensions::Extension* extension,
-    AppListSource source,
-    int event_flags) {
-  LaunchApp(profile, extension, source, event_flags);
-}
-
-void AppListControllerDelegateWin::LaunchApp(
-    Profile* profile,
-    const extensions::Extension* extension,
-    AppListSource source,
-    int event_flags) {
-  AppListServiceImpl::RecordAppListAppLaunch();
-
-  AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB);
-  params.desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
-
-  if (source != LAUNCH_FROM_UNKNOWN &&
-      extension->id() == extension_misc::kWebStoreAppId) {
-    // Set an override URL to include the source.
-    GURL extension_url = extensions::AppLaunchInfo::GetFullLaunchURL(extension);
-    params.override_url = net::AppendQueryParameter(
-        extension_url,
-        extension_urls::kWebstoreSourceField,
-        AppListSourceToString(source));
-  }
-
-  OpenApplication(params);
-}
-
diff --git a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
index 9e3ffcc..12faab3 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
+++ b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_APP_LIST_WIN_APP_LIST_CONTROLLER_DELEGATE_WIN_H_
 
 #include "base/files/file_path.h"
-#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -18,31 +18,17 @@
 }
 
 // Windows specific configuration and behaviour for the AppList.
-class AppListControllerDelegateWin : public AppListControllerDelegate {
+class AppListControllerDelegateWin : public AppListControllerDelegateImpl {
  public:
   explicit AppListControllerDelegateWin(AppListServiceWin* service);
   virtual ~AppListControllerDelegateWin();
 
-  // AppListServiceWin overrides:
-  virtual void DismissView() OVERRIDE;
+  // AppListControllerDelegate overrides:
   virtual void ViewClosing() OVERRIDE;
-  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
-  virtual Pinnable GetPinnable() OVERRIDE;
   virtual void OnShowExtensionPrompt() OVERRIDE;
   virtual void OnCloseExtensionPrompt() OVERRIDE;
   virtual bool CanDoCreateShortcutsFlow() OVERRIDE;
-  virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
-  virtual void ActivateApp(Profile* profile,
-                           const extensions::Extension* extension,
-                           AppListSource source,
-                           int event_flags) OVERRIDE;
-  virtual void LaunchApp(Profile* profile,
-                         const extensions::Extension* extension,
-                         AppListSource source,
-                         int event_flags) OVERRIDE;
-  virtual void ShowForProfileByPath(
-      const base::FilePath& profile_path) OVERRIDE;
 
  private:
   AppListServiceWin* service_;
diff --git a/chrome/browser/ui/views/app_list/win/app_list_service_win.cc b/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
index d02c6fa..7f009fd 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
+++ b/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
@@ -81,9 +81,9 @@
 #endif
 
 // static
-AppListService* AppListService::Get() {
+AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) {
 #if defined(USE_ASH)
-  if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
+  if (desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
     return chrome::GetAppListServiceAsh();
 #endif
 
@@ -373,6 +373,10 @@
   return shower_->GetWindow();
 }
 
+Profile* AppListServiceWin::GetCurrentAppListProfile() {
+  return shower_->profile();
+}
+
 AppListControllerDelegate* AppListServiceWin::CreateControllerDelegate() {
   return new AppListControllerDelegateWin(this);
 }
@@ -401,9 +405,7 @@
   }
 
   InvalidatePendingProfileLoads();
-  // TODO(koz): Investigate making SetProfile() call SetProfilePath() itself.
   SetProfilePath(requested_profile->GetPath());
-  SetProfile(requested_profile);
   shower_->ShowForProfile(requested_profile);
   RecordAppListLaunch();
 }
@@ -414,7 +416,6 @@
 
 void AppListServiceWin::OnAppListClosing() {
   shower_->CloseAppList();
-  SetProfile(NULL);
 }
 
 void AppListServiceWin::OnLoadProfileForWarmup(Profile* initial_profile) {
diff --git a/chrome/browser/ui/views/app_list/win/app_list_service_win.h b/chrome/browser/ui/views/app_list/win/app_list_service_win.h
index 23dc5dc..6b9352c 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_service_win.h
+++ b/chrome/browser/ui/views/app_list/win/app_list_service_win.h
@@ -38,6 +38,7 @@
   virtual void DismissAppList() OVERRIDE;
   virtual bool IsAppListVisible() const OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
+  virtual Profile* GetCurrentAppListProfile() OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
 
   // AppListServiceImpl overrides:
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.cc b/chrome/browser/ui/views/apps/native_app_window_views.cc
index ff9bbd2..ecdb65f 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/native_app_window_views.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/apps/native_app_window_views.h"
 
+#include "apps/shell_window.h"
 #include "apps/ui/views/shell_window_frame_view.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
@@ -46,9 +48,14 @@
 #include "ash/wm/custom_frame_view_ash.h"
 #include "ash/wm/panels/panel_frame_view.h"
 #include "ash/wm/window_state.h"
+#include "ash/wm/window_state_delegate.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/window.h"
+#endif
+
+#if defined(USE_AURA)
 #include "ui/aura/window.h"
 #endif
 
@@ -120,6 +127,34 @@
 }
 #endif
 
+#if defined(USE_ASH)
+// This class handles a user's fullscreen request (Shift+F4/F4).
+class NativeAppWindowStateDelegate : public ash::wm::WindowStateDelegate {
+ public:
+  explicit NativeAppWindowStateDelegate(ShellWindow* shell_window)
+      : shell_window_(shell_window) {
+    DCHECK(shell_window_);
+  }
+  virtual ~NativeAppWindowStateDelegate(){}
+
+  // Overridden from ash::wm::WindowStateDelegate.
+  virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
+    // Windows which cannot be maximized should not be fullscreened.
+    DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
+    if (window_state->IsFullscreen())
+      shell_window_->Restore();
+    else if (window_state->CanMaximize())
+      shell_window_->Fullscreen();
+    return true;
+  }
+
+ private:
+  ShellWindow* shell_window_;  // not owned.
+
+  DISALLOW_COPY_AND_ASSIGN(NativeAppWindowStateDelegate);
+};
+#endif  // USE_ASH
+
 }  // namespace
 
 NativeAppWindowViews::NativeAppWindowViews(
@@ -151,6 +186,14 @@
 
   OnViewWasResized();
   window_->AddObserver(this);
+#if defined(USE_ASH)
+  if (chrome::GetHostDesktopTypeForNativeView(GetNativeWindow()) ==
+      chrome::HOST_DESKTOP_TYPE_ASH) {
+    ash::wm::GetWindowState(GetNativeWindow())->SetDelegate(
+        scoped_ptr<ash::wm::WindowStateDelegate>(
+            new NativeAppWindowStateDelegate(shell_window)).Pass());
+  }
+#endif
 }
 
 NativeAppWindowViews::~NativeAppWindowViews() {
@@ -169,6 +212,9 @@
   // TODO(erg): Conceptually, these are toplevel windows, but we theoretically
   // could plumb context through to here in some cases.
   init_params.top_level = true;
+  init_params.opacity = create_params.transparent_background
+                            ? views::Widget::InitParams::TRANSLUCENT_WINDOW
+                            : views::Widget::InitParams::INFER_OPACITY;
   init_params.keep_on_top = create_params.always_on_top;
   gfx::Rect window_bounds = create_params.bounds;
   bool position_specified =
@@ -264,7 +310,7 @@
 #if defined(USE_ASH)
   if (ash::Shell::HasInstance()) {
     // Open a new panel on the target root.
-    aura::RootWindow* target = ash::Shell::GetTargetRootWindow();
+    aura::Window* target = ash::Shell::GetTargetRootWindow();
     params.bounds = ash::ScreenAsh::ConvertRectToScreen(
         target, gfx::Rect(preferred_size_));
   } else {
@@ -287,8 +333,9 @@
                             preferred_size_.height());
     aura::Window* native_window = GetNativeWindow();
     ash::wm::GetWindowState(native_window)->set_panel_attached(false);
-    native_window->SetDefaultParentByRootWindow(
-        native_window->GetRootWindow(), native_window->GetBoundsInScreen());
+    aura::client::ParentWindowWithContext(native_window,
+                                          native_window->GetRootWindow(),
+                                          native_window->GetBoundsInScreen());
     window_->SetBounds(window_bounds);
   }
 #else
@@ -647,7 +694,7 @@
     gfx::NativeView child,
     const gfx::Point& location) {
 #if defined(USE_AURA)
-  if (child == web_view_->web_contents()->GetView()->GetNativeView()) {
+  if (child->Contains(web_view_->web_contents()->GetView()->GetNativeView())) {
     // Shell window should claim mouse events that fall within the draggable
     // region.
     return !draggable_region_.get() ||
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
index a4ad349..d021e0c 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h"
 
+#include "ash/root_window_controller.h"
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
@@ -88,9 +89,15 @@
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostProfileInit() {
+  if (!ash::Shell::HasInstance())
+    return;
+
   // Initialize TabScrubber after the Ash Shell has been initialized.
-  if (ash::Shell::HasInstance())
-    TabScrubber::GetInstance();
+  TabScrubber::GetInstance();
+  // Activate virtual keyboard after profile is initialized. It depends on the
+  // default profile.
+  ash::Shell::GetPrimaryRootWindowController()->ActivateKeyboard(
+      ash::Shell::GetInstance()->keyboard_controller());
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostMainMessageLoopRun() {
diff --git a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
index 32fabba..46862e6 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
+++ b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
@@ -80,7 +80,7 @@
   // fling events.
   void SendScrubEvent(Browser* browser, int index) {
     aura::Window* window = browser->window()->GetNativeWindow();
-    aura::RootWindow* root = window->GetRootWindow();
+    aura::Window* root = window->GetRootWindow();
     aura::test::EventGenerator event_generator(root, window);
     int active_index = browser->tab_strip_model()->active_index();
     TabScrubber::Direction direction = index < active_index ?
@@ -107,7 +107,7 @@
   // active.
   void Scrub(Browser* browser, int index, ScrubType scrub_type) {
     aura::Window* window = browser->window()->GetNativeWindow();
-    aura::RootWindow* root = window->GetRootWindow();
+    aura::Window* root = window->GetRootWindow();
     aura::test::EventGenerator event_generator(root, window);
     event_generator.set_async(true);
     activation_order_.clear();
@@ -150,7 +150,7 @@
   // synchronously (as we don't have anything to wait for).
   void SendScrubSequence(Browser* browser, int x_offset, int index) {
     aura::Window* window = browser->window()->GetNativeWindow();
-    aura::RootWindow* root = window->GetRootWindow();
+    aura::Window* root = window->GetRootWindow();
     aura::test::EventGenerator event_generator(root, window);
     bool wait_for_active = false;
     if (index != browser->tab_strip_model()->active_index()) {
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index b50c295..be6df32 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
 #include "chrome/browser/ui/autofill/loading_animation.h"
 #include "chrome/browser/ui/views/autofill/decorated_textfield.h"
+#include "chrome/browser/ui/views/autofill/tooltip_icon.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
 #include "components/autofill/core/browser/autofill_type.h"
@@ -157,6 +158,12 @@
   }
 }
 
+// Returns whether |view| is an input (e.g. textfield, combobox).
+bool IsInput(views::View* view) {
+  return view->GetClassName() == DecoratedTextfield::kViewClassName ||
+         view->GetClassName() == views::Combobox::kViewClassName;
+}
+
 // This class handles layout for the first row of a SuggestionView.
 // It exists to circumvent shortcomings of GridLayout and BoxLayout (namely that
 // the former doesn't fully respect child visibility, and that the latter won't
@@ -242,28 +249,6 @@
   DISALLOW_COPY_AND_ASSIGN(LayoutPropagationView);
 };
 
-// A tooltip icon (just an ImageView with a tooltip). Looks like (?).
-class TooltipIcon : public views::ImageView {
- public:
-  explicit TooltipIcon(const base::string16& tooltip) : tooltip_(tooltip) {
-    SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-        IDR_AUTOFILL_TOOLTIP_ICON).ToImageSkia());
-  }
-  virtual ~TooltipIcon() {}
-
-  // views::View implementation
-  virtual bool GetTooltipText(const gfx::Point& p,
-                              base::string16* tooltip) const OVERRIDE {
-    *tooltip = tooltip_;
-    return !tooltip_.empty();
-  }
-
- private:
-  base::string16 tooltip_;
-
-  DISALLOW_COPY_AND_ASSIGN(TooltipIcon);
-};
-
 // A View for a single notification banner.
 class NotificationView : public views::View,
                          public views::ButtonListener,
@@ -665,30 +650,6 @@
   }
 }
 
-void AutofillDialogViews::ShowDialogInMode(DialogMode dialog_mode) {
-  std::vector<views::View*> visible;
-
-  if (dialog_mode == LOADING) {
-    visible.push_back(loading_shield_);
-  } else if (dialog_mode == SIGN_IN) {
-    visible.push_back(sign_in_web_view_);
-  } else {
-    DCHECK_EQ(DETAIL_INPUT, dialog_mode);
-    visible.push_back(notification_area_);
-    visible.push_back(scrollable_area_);
-  }
-
-  for (size_t i = 0; i < visible.size(); ++i) {
-    DCHECK_GE(GetIndexOf(visible[i]), 0);
-  }
-
-  for (int i = 0; i < child_count(); ++i) {
-    views::View* child = child_at(i);
-    child->SetVisible(
-        std::find(visible.begin(), visible.end(), child) != visible.end());
-  }
-}
-
 views::View* AutofillDialogViews::GetLoadingShieldForTesting() {
   return loading_shield_;
 }
@@ -1374,14 +1335,10 @@
       delegate_->GetWebContents()->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      window_->GetNativeView(), true);
   focus_manager_ = window_->GetFocusManager();
   focus_manager_->AddFocusChangeListener(this);
 
-  // This line fixes http://crbug.com/271779, which happens only on Views/Win32.
-  // TODO(rouslan): Remove this line after Windows is entirely on Aura.
-  focus_manager_->SetFocusedView(GetInitiallyFocusedView());
+  ShowDialogInMode(DETAIL_INPUT);
 
   // Listen for size changes on the browser.
   views::Widget* browser_widget =
@@ -1418,7 +1375,8 @@
                                         GetContentsBounds().height());
       ShowDialogInMode(LOADING);
     } else {
-      ShowDialogInMode(DETAIL_INPUT);
+      bool show_sign_in = delegate_->ShouldShowSignInWebView();
+      ShowDialogInMode(show_sign_in ? SIGN_IN : DETAIL_INPUT);
     }
 
     InvalidateLayout();
@@ -1550,26 +1508,34 @@
 }
 
 const content::NavigationController* AutofillDialogViews::ShowSignIn() {
-  // TODO(abodenha) We should be able to use the WebContents of the WebView
-  // to navigate instead of LoadInitialURL.  Figure out why it doesn't work.
-
+  // TODO(abodenha): We should be able to use the WebContents of the WebView
+  // to navigate instead of LoadInitialURL. Figure out why it doesn't work.
   sign_in_delegate_.reset(
       new AutofillDialogSignInDelegate(
           this, sign_in_web_view_->GetWebContents(),
           delegate_->GetWebContents()->GetDelegate(),
           GetMinimumSignInViewSize(), GetMaximumSignInViewSize()));
-  sign_in_web_view_->LoadInitialURL(wallet::GetSignInUrl());
+  sign_in_web_view_->LoadInitialURL(delegate_->SignInUrl());
 
   ShowDialogInMode(SIGN_IN);
-  sign_in_web_view_->RequestFocus();
 
   UpdateButtonStrip();
   ContentsPreferredSizeChanged();
+
   return &sign_in_web_view_->web_contents()->GetController();
 }
 
 void AutofillDialogViews::HideSignIn() {
-  ShowDialogInMode(DETAIL_INPUT);
+  sign_in_web_view_->SetWebContents(NULL);
+
+  if (delegate_->ShouldShowSpinner()) {
+    UpdateAccountChooser();
+  } else {
+    ShowDialogInMode(DETAIL_INPUT);
+    InvalidateLayout();
+  }
+  DCHECK(!sign_in_web_view_->visible());
+
   UpdateButtonStrip();
   ContentsPreferredSizeChanged();
 }
@@ -1654,6 +1620,10 @@
   return GetWidget() ? GetWidget()->GetRootView()->size() : gfx::Size();
 }
 
+content::WebContents* AutofillDialogViews::GetSignInWebContents() {
+  return sign_in_web_view_->web_contents();
+}
+
 gfx::Size AutofillDialogViews::GetPreferredSize() {
   if (preferred_size_.IsEmpty())
     preferred_size_ = CalculatePreferredSize(false);
@@ -1746,6 +1716,36 @@
   return delegate_->IsDialogButtonEnabled(button);
 }
 
+views::View* AutofillDialogViews::GetInitiallyFocusedView() {
+  if (!window_ || !focus_manager_)
+    return NULL;
+
+  if (sign_in_web_view_->visible())
+    return sign_in_web_view_;
+
+  if (loading_shield_->visible())
+    return views::DialogDelegateView::GetInitiallyFocusedView();
+
+  DCHECK(scrollable_area_->visible());
+
+  views::FocusManager* manager = focus_manager_;
+  for (views::View* next = scrollable_area_;
+       next;
+       next = manager->GetNextFocusableView(next, window_, false, true)) {
+    if (!IsInput(next))
+      continue;
+
+    // If there are no invalid inputs, return the first input found. Otherwise,
+    // return the first invalid input found.
+    if (validity_map_.empty() ||
+        validity_map_.find(next) != validity_map_.end()) {
+      return next;
+    }
+  }
+
+  return views::DialogDelegateView::GetInitiallyFocusedView();
+}
+
 views::View* AutofillDialogViews::CreateExtraView() {
   return button_strip_extra_view_;
 }
@@ -1789,8 +1789,10 @@
   if (ValidateForm())
     return delegate_->OnAccept();
 
-  if (!validity_map_.empty())
-    validity_map_.begin()->first->RequestFocus();
+  // |ValidateForm()| failed; there should be invalid views in |validity_map_|.
+  DCHECK(!validity_map_.empty());
+  FocusInitialView();
+
   return false;
 }
 
@@ -2010,8 +2012,6 @@
 
   overlay_view_ = new OverlayView(delegate_);
   overlay_view_->SetVisible(false);
-
-  ShowDialogInMode(DETAIL_INPUT);
 }
 
 views::View* AutofillDialogViews::CreateDetailsContainer() {
@@ -2148,6 +2148,14 @@
   return view;
 }
 
+void AutofillDialogViews::ShowDialogInMode(DialogMode dialog_mode) {
+  loading_shield_->SetVisible(dialog_mode == LOADING);
+  sign_in_web_view_->SetVisible(dialog_mode == SIGN_IN);
+  notification_area_->SetVisible(dialog_mode == DETAIL_INPUT);
+  scrollable_area_->SetVisible(dialog_mode == DETAIL_INPUT);
+  FocusInitialView();
+}
+
 void AutofillDialogViews::UpdateSectionImpl(
     DialogSection section,
     bool clobber_inputs) {
@@ -2214,6 +2222,12 @@
   ContentsPreferredSizeChanged();
 }
 
+void AutofillDialogViews::FocusInitialView() {
+  views::View* to_focus = GetInitiallyFocusedView();
+  if (to_focus && !to_focus->HasFocus())
+    to_focus->RequestFocus();
+}
+
 template<class T>
 void AutofillDialogViews::SetValidityForInput(
     T* input,
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index 4f57cf4..195ce66 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -112,6 +112,7 @@
       const base::string16& text) OVERRIDE;
   virtual void ActivateInput(const DetailInput& input) OVERRIDE;
   virtual gfx::Size GetSize() const OVERRIDE;
+  virtual content::WebContents* GetSignInWebContents() OVERRIDE;
 
   // views::View implementation.
   virtual gfx::Size GetPreferredSize() OVERRIDE;
@@ -129,6 +130,7 @@
       OVERRIDE;
   virtual bool ShouldDefaultButtonBeBlue() const OVERRIDE;
   virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
+  virtual views::View* GetInitiallyFocusedView() OVERRIDE;
   virtual views::View* CreateExtraView() OVERRIDE;
   virtual views::View* CreateTitlebarExtraView() OVERRIDE;
   virtual views::View* CreateFootnoteView() OVERRIDE;
@@ -168,6 +170,13 @@
                                    const gfx::Point& point) OVERRIDE;
 
  protected:
+  // Exposed for testing.
+  views::View* GetLoadingShieldForTesting();
+  views::WebView* GetSignInWebViewForTesting();
+  views::View* GetNotificationAreaForTesting();
+  views::View* GetScrollableAreaForTesting();
+
+ private:
   // What the entire dialog should be doing (e.g. gathering info from the user,
   // asking the user to sign in, etc.).
   enum DialogMode {
@@ -176,18 +185,6 @@
     SIGN_IN,
   };
 
-  // Changes the function of the whole dialog. Currently this can show a loading
-  // shield, an embedded sign in web view, or the more typical detail input mode
-  // (suggestions and form inputs).
-  void ShowDialogInMode(DialogMode dialog_mode);
-
-  // Exposed for testing.
-  views::View* GetLoadingShieldForTesting();
-  views::WebView* GetSignInWebViewForTesting();
-  views::View* GetNotificationAreaForTesting();
-  views::View* GetScrollableAreaForTesting();
-
- private:
   // A class that creates and manages a widget for error messages.
   class ErrorBubble : public views::BubbleDelegateView {
    public:
@@ -554,6 +551,11 @@
   // returned.
   views::View* InitInputsView(DialogSection section);
 
+  // Changes the function of the whole dialog. Currently this can show a loading
+  // shield, an embedded sign in web view, or the more typical detail input mode
+  // (suggestions and form inputs).
+  void ShowDialogInMode(DialogMode dialog_mode);
+
   // Updates the given section to match the state provided by |delegate_|. If
   // |clobber_inputs| is true, the current state of the textfields will be
   // ignored, otherwise their contents will be preserved.
@@ -570,6 +572,9 @@
   // Returns NULL if no DetailsGroup was found.
   DetailsGroup* GroupForView(views::View* view);
 
+  // Explicitly focuses the initially focusable view.
+  void FocusInitialView();
+
   // Sets the visual state for an input to be either valid or invalid. This
   // should work on Comboboxes or DecoratedTextfields. If |message| is empty,
   // the input is valid.
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
index 04087d0..e294774 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/autofill/decorated_textfield.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "components/web_modal/test_web_contents_modal_dialog_host.h"
@@ -23,6 +24,7 @@
 
 namespace {
 
+using testing::Return;
 using web_modal::WebContentsModalDialogManager;
 
 // A views implementation of the Autofill dialog with slightly more testability.
@@ -32,10 +34,6 @@
       : AutofillDialogViews(delegate) {}
   virtual ~TestAutofillDialogViews() {}
 
-  void ShowLoadingMode() { ShowDialogInMode(LOADING); }
-  void ShowSignInMode() { ShowDialogInMode(SIGN_IN); }
-  void ShowDetailInputMode() { ShowDialogInMode(DETAIL_INPUT); }
-
   using AutofillDialogViews::GetLoadingShieldForTesting;
   using AutofillDialogViews::GetSignInWebViewForTesting;
   using AutofillDialogViews::GetNotificationAreaForTesting;
@@ -56,6 +54,8 @@
   virtual void SetUp() OVERRIDE {
     TestWithBrowserView::SetUp();
 
+    view_delegate_.SetProfile(profile());
+
     AddTab(browser(), GURL());
     TabStripModel* tab_strip_model = browser()->tab_strip_model();
     content::WebContents* contents = tab_strip_model->GetWebContentsAt(0);
@@ -79,19 +79,20 @@
 
   virtual void TearDown() OVERRIDE {
     dialog_->GetWidget()->CloseNow();
+    dialog_.reset();
 
     TestWithBrowserView::TearDown();
   }
 
+  MockAutofillDialogViewDelegate* delegate() { return &view_delegate_; }
+
   TestAutofillDialogViews* dialog() { return dialog_.get(); }
 
  protected:
-  // Allows each main section (e.g. loading shield, sign in web view,
-  // notification area, and scrollable area) to get focus. Used in focus-related
-  // tests.
   void SetSectionsFocusable() {
     dialog()->GetLoadingShieldForTesting()->set_focusable(true);
-    // The sign in web view has a different implementation of IsFocusable().
+    // The sign in web view is not focusable until a web contents is created.
+    // TODO(dbeam): figure out how to create a web contents on the right thread.
     dialog()->GetNotificationAreaForTesting()->set_focusable(true);
     dialog()->GetScrollableAreaForTesting()->set_focusable(true);
   }
@@ -107,80 +108,80 @@
   scoped_ptr<TestAutofillDialogViews> dialog_;
 };
 
-TEST_F(AutofillDialogViewsTest, ShowLoadingMode) {
-  SetSectionsFocusable();
-
-  dialog()->ShowLoadingMode();
-
-  views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
-  EXPECT_TRUE(loading_shield->visible());
-  EXPECT_TRUE(loading_shield->IsFocusable());
-
-  loading_shield->RequestFocus();
-  EXPECT_TRUE(loading_shield->HasFocus());
-
-  views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
-  EXPECT_FALSE(sign_in_web_view->visible());
-  EXPECT_FALSE(sign_in_web_view->IsFocusable());
-
-  views::View* notification_area = dialog()->GetNotificationAreaForTesting();
-  EXPECT_FALSE(notification_area->visible());
-  EXPECT_FALSE(notification_area->IsFocusable());
-
-  views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
-  EXPECT_FALSE(scrollable_area->visible());
-  EXPECT_FALSE(scrollable_area->IsFocusable());
+TEST_F(AutofillDialogViewsTest, InitialFocus) {
+  views::FocusManager* focus_manager = dialog()->GetWidget()->GetFocusManager();
+  views::View* focused_view = focus_manager->GetFocusedView();
+  EXPECT_STREQ(DecoratedTextfield::kViewClassName,
+               focused_view->GetClassName());
 }
 
-TEST_F(AutofillDialogViewsTest, ShowSignInMode) {
+TEST_F(AutofillDialogViewsTest, SignInFocus) {
   SetSectionsFocusable();
 
-  dialog()->ShowSignInMode();
-
   views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
-  EXPECT_FALSE(loading_shield->visible());
-  EXPECT_FALSE(loading_shield->IsFocusable());
-
   views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
-  EXPECT_TRUE(sign_in_web_view->visible());
-  // NOTE: |sign_in_web_view| is not focusable until a web contents is created.
-  // TODO(dbeam): figure out how to create a web contents on the right thread.
-
   views::View* notification_area = dialog()->GetNotificationAreaForTesting();
-  EXPECT_FALSE(notification_area->visible());
-  EXPECT_FALSE(notification_area->IsFocusable());
-
   views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
-  EXPECT_FALSE(scrollable_area->visible());
-  EXPECT_FALSE(scrollable_area->IsFocusable());
-}
 
-TEST_F(AutofillDialogViewsTest, ShowDetailInputMode) {
-  SetSectionsFocusable();
+  dialog()->ShowSignIn();
 
-  dialog()->ShowDetailInputMode();
-
-  views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
-  EXPECT_FALSE(loading_shield->visible());
+  // The sign in view should be the only showing and focusable view.
+  EXPECT_TRUE(sign_in_web_view->IsFocusable());
   EXPECT_FALSE(loading_shield->IsFocusable());
+  EXPECT_FALSE(notification_area->IsFocusable());
+  EXPECT_FALSE(scrollable_area->IsFocusable());
 
-  views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
-  EXPECT_FALSE(sign_in_web_view->visible());
-  EXPECT_FALSE(sign_in_web_view->IsFocusable());
+  EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(false));
+  dialog()->HideSignIn();
 
-  views::View* notification_area = dialog()->GetNotificationAreaForTesting();
-  EXPECT_TRUE(notification_area->visible());
+  // Hide sign in while not loading Wallet items as if the user clicked "Back".
   EXPECT_TRUE(notification_area->IsFocusable());
-
-  views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
-  EXPECT_TRUE(scrollable_area->visible());
   EXPECT_TRUE(scrollable_area->IsFocusable());
+  EXPECT_FALSE(loading_shield->IsFocusable());
+  EXPECT_FALSE(sign_in_web_view->IsFocusable());
 
-  notification_area->RequestFocus();
-  EXPECT_TRUE(notification_area->HasFocus());
+  dialog()->ShowSignIn();
 
-  scrollable_area->RequestFocus();
-  EXPECT_TRUE(scrollable_area->HasFocus());
+  EXPECT_TRUE(sign_in_web_view->IsFocusable());
+  EXPECT_FALSE(loading_shield->IsFocusable());
+  EXPECT_FALSE(notification_area->IsFocusable());
+  EXPECT_FALSE(scrollable_area->IsFocusable());
+
+  EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(true));
+  dialog()->HideSignIn();
+
+  // Hide sign in while pretending to load Wallet data.
+  EXPECT_TRUE(loading_shield->IsFocusable());
+  EXPECT_FALSE(notification_area->IsFocusable());
+  EXPECT_FALSE(scrollable_area->IsFocusable());
+  EXPECT_FALSE(sign_in_web_view->IsFocusable());
+}
+
+TEST_F(AutofillDialogViewsTest, LoadingFocus) {
+  SetSectionsFocusable();
+
+  views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
+  views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
+  views::View* notification_area = dialog()->GetNotificationAreaForTesting();
+  views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
+
+  // Pretend as if loading Wallet data.
+  EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(true));
+  dialog()->UpdateAccountChooser();
+
+  EXPECT_TRUE(loading_shield->IsFocusable());
+  EXPECT_FALSE(notification_area->IsFocusable());
+  EXPECT_FALSE(scrollable_area->IsFocusable());
+  EXPECT_FALSE(sign_in_web_view->IsFocusable());
+
+  // Pretend as if Wallet data has finished loading.
+  EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(false));
+  dialog()->UpdateAccountChooser();
+
+  EXPECT_TRUE(notification_area->IsFocusable());
+  EXPECT_TRUE(scrollable_area->IsFocusable());
+  EXPECT_FALSE(loading_shield->IsFocusable());
+  EXPECT_FALSE(sign_in_web_view->IsFocusable());
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
index 818112c..1f07bbb 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
@@ -19,6 +19,10 @@
 #include "ui/views/event_utils.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(USE_AURA)
+#include "ui/views/corewm/window_animations.h"
+#endif
+
 using WebKit::WebAutofillClient;
 
 namespace {
@@ -182,6 +186,11 @@
     params.parent = controller_->container_view();
     widget->Init(params);
     widget->SetContentsView(this);
+#if defined(USE_AURA)
+    // No animation for popup appearance (too distracting).
+    views::corewm::SetWindowVisibilityAnimationTransition(
+        widget->GetNativeView(), views::corewm::ANIMATE_HIDE);
+#endif
   }
 
   set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor));
diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.cc b/chrome/browser/ui/views/autofill/decorated_textfield.cc
index d4c0fa3..47d3b30 100644
--- a/chrome/browser/ui/views/autofill/decorated_textfield.cc
+++ b/chrome/browser/ui/views/autofill/decorated_textfield.cc
@@ -120,6 +120,11 @@
   return kViewClassName;
 }
 
+views::View* DecoratedTextfield::GetEventHandlerForPoint(
+    const gfx::Point& point) {
+  return native_wrapper_->GetView();
+}
+
 void DecoratedTextfield::OnFocus() {
   border_->set_has_focus(true);
   views::Textfield::OnFocus();
diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.h b/chrome/browser/ui/views/autofill/decorated_textfield.h
index 9acf971..b14798a 100644
--- a/chrome/browser/ui/views/autofill/decorated_textfield.h
+++ b/chrome/browser/ui/views/autofill/decorated_textfield.h
@@ -52,6 +52,8 @@
   virtual const char* GetClassName() const OVERRIDE;
   virtual gfx::Size GetPreferredSize() OVERRIDE;
   virtual void Layout() OVERRIDE;
+  virtual views::View* GetEventHandlerForPoint(const gfx::Point& point)
+      OVERRIDE;
   virtual void OnFocus() OVERRIDE;
   virtual void OnBlur() OVERRIDE;
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index 5cce190..abb0eae 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -70,7 +70,9 @@
 };
 
 // TODO(jschuh): Fix bookmark DND tests on Win64. crbug.com/244605
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
+// TODO(erg): Fix bookmark DBD tests on linux_aura. crbug.com/163931
+#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || \
+  (defined(OS_LINUX) && defined(USE_AURA))
 #define MAYBE(x) DISABLED_##x
 #else
 #define MAYBE(x) x
@@ -345,7 +347,14 @@
   }
 };
 
-VIEW_TEST(BookmarkBarViewTest2, HideOnDesktopClick)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_HideOnDesktopClick DISABLED_HideOnDesktopClick
+#else
+#define MAYBE_HideOnDesktopClick HideOnDesktopClick
+#endif
+
+VIEW_TEST(BookmarkBarViewTest2, MAYBE_HideOnDesktopClick)
 
 // Brings up menu. Moves over child to make sure submenu appears, moves over
 // another child and make sure next menu appears.
@@ -1074,7 +1083,15 @@
   ContextMenuNotificationObserver observer_;
 };
 
-VIEW_TEST(BookmarkBarViewTest11, CloseMenuAfterClosingContextMenu)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_CloseMenuAfterClosingContextMenu \
+  DISABLED_CloseMenuAfterClosingContextMenu
+#else
+#define MAYBE_CloseMenuAfterClosingContextMenu CloseMenuAfterClosingContextMenu
+#endif
+
+VIEW_TEST(BookmarkBarViewTest11, MAYBE_CloseMenuAfterClosingContextMenu)
 
 // Tests showing a modal dialog from a context menu.
 class BookmarkBarViewTest12 : public BookmarkBarViewEventTestBase {
@@ -1159,7 +1176,14 @@
   }
 };
 
-VIEW_TEST(BookmarkBarViewTest12, CloseWithModalDialog)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_CloseWithModalDialog DISABLED_CloseWithModalDialog
+#else
+#define MAYBE_CloseWithModalDialog CloseWithModalDialog
+#endif
+
+VIEW_TEST(BookmarkBarViewTest12, MAYBE_CloseWithModalDialog)
 
 // Tests clicking on the separator of a context menu (this is for coverage of
 // bug 17862).
@@ -1394,7 +1418,14 @@
   }
 };
 
-VIEW_TEST(BookmarkBarViewTest16, DeleteMenu)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_DeleteMenu DISABLED_DeleteMenu
+#else
+#define MAYBE_DeleteMenu DeleteMenu
+#endif
+
+VIEW_TEST(BookmarkBarViewTest16, MAYBE_DeleteMenu)
 
 // Makes sure right clicking on an item while a context menu is already showing
 // doesn't crash and works.
@@ -1475,7 +1506,14 @@
   ContextMenuNotificationObserver observer_;
 };
 
-VIEW_TEST(BookmarkBarViewTest17, ContextMenus3)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_ContextMenus3 DISABLED_ContextMenus3
+#else
+#define MAYBE_ContextMenus3 ContextMenus3
+#endif
+
+VIEW_TEST(BookmarkBarViewTest17, MAYBE_ContextMenus3)
 
 // Verifies sibling menus works. Clicks on the 'other bookmarks' folder, then
 // moves the mouse over the first item on the bookmark bar and makes sure the
@@ -1524,7 +1562,16 @@
   }
 };
 
-VIEW_TEST(BookmarkBarViewTest18, BookmarkBarViewTest18_SiblingMenu)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_BookmarkBarViewTest18_SiblingMenu \
+  DISABLED_BookmarkBarViewTest18_SiblingMenu
+#else
+#define MAYBE_BookmarkBarViewTest18_SiblingMenu \
+  BookmarkBarViewTest18_SiblingMenu
+#endif
+
+VIEW_TEST(BookmarkBarViewTest18, MAYBE_BookmarkBarViewTest18_SiblingMenu)
 
 // Verifies mousing over an already open sibling menu doesn't prematurely cancel
 // the menu.
@@ -1700,6 +1747,9 @@
 
 #if defined(OS_WIN) && !defined(USE_AURA)
 #define MAYBE_ContextMenuExitTest DISABLED_ContextMenuExitTest
+#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_ContextMenuExitTest DISABLED_ContextMenuExitTest
 #else
 #define MAYBE_ContextMenuExitTest ContextMenuExitTest
 #endif
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
index 6886d1d..92b582c 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
@@ -5,12 +5,12 @@
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
diff --git a/chrome/browser/ui/views/certificate_viewer_win.cc b/chrome/browser/ui/views/certificate_viewer_win.cc
index 21948ae..fa34539 100644
--- a/chrome/browser/ui/views/certificate_viewer_win.cc
+++ b/chrome/browser/ui/views/certificate_viewer_win.cc
@@ -56,7 +56,7 @@
   if (chrome::GetHostDesktopTypeForNativeWindow(parent) !=
       chrome::HOST_DESKTOP_TYPE_ASH) {
     ShowCertificateViewerImpl(
-        web_contents, parent->GetRootWindow()->GetAcceleratedWidget(), cert);
+        web_contents, parent->GetDispatcher()->GetAcceleratedWidget(), cert);
   } else {
     NOTIMPLEMENTED();
   }
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index f658bf2..785a6a0 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -6,11 +6,11 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/views/accessibility/accessibility_event_router_views.h"
 #include "chrome/common/pref_names.h"
@@ -205,27 +205,16 @@
        chrome::GetHostDesktopTypeForNativeView(params->parent) !=
           chrome::HOST_DESKTOP_TYPE_NATIVE);
 
-  if (!ui::win::IsAeroGlassEnabled()) {
-    // If we don't have composition (either because Glass is not enabled or
-    // because it was disabled at the command line), anything that requires
-    // transparency will be broken with a toplevel window, so force the use of
-    // a non toplevel window.
-    if (params->opacity == views::Widget::InitParams::TRANSLUCENT_WINDOW &&
-        params->type != views::Widget::InitParams::TYPE_MENU)
-      use_non_toplevel_window = true;
-  } else {
-    // If we're on Vista+ with composition enabled, then we can use toplevel
-    // windows for most things (they get blended via WS_EX_COMPOSITED, which
-    // allows for animation effects, but also exceeding the bounds of the parent
-    // window).
-    if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
-        params->parent &&
-        params->type != views::Widget::InitParams::TYPE_CONTROL &&
-        params->type != views::Widget::InitParams::TYPE_WINDOW) {
-      // When we set this to false, we get a DesktopNativeWidgetAura from the
-      // default case (not handled in this function).
-      use_non_toplevel_window = false;
-    }
+  // We can use toplevel windows for most things. On Vista+ with DWM, they get
+  // blended via WS_EX_COMPOSITED. Otherwise, they're rendered by the software
+  // compositor and the hwnd is converted to a WS_EX_LAYERED.
+  if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
+      params->parent &&
+      params->type != views::Widget::InitParams::TYPE_CONTROL &&
+      params->type != views::Widget::InitParams::TYPE_WINDOW) {
+    // When we set this to false, we get a DesktopNativeWidgetAura from the
+    // default case (not handled in this function).
+    use_non_toplevel_window = false;
   }
 #endif  // OS_WIN
 #endif  // USE_AURA
@@ -237,13 +226,15 @@
   // but have neither a context nor a parent. Provide a fallback context so
   // users don't crash. Developers will hit the DCHECK and should provide a
   // context.
+  if (params->context)
+    params->context = params->context->GetRootWindow();
   DCHECK(params->parent || params->context || params->top_level)
       << "Please provide a parent or context for this widget.";
   if (!params->parent && !params->context)
     params->context = ash::Shell::GetPrimaryRootWindow();
 #elif defined(USE_AURA)
   // While the majority of the time, context wasn't plumbed through due to the
-  // existence of a global StackingClient, if this window is a toplevel, it's
+  // existence of a global WindowTreeClient, if this window is a toplevel, it's
   // possible that there is no contextual state that we can use.
   if (params->parent == NULL && params->context == NULL && params->top_level) {
     // We need to make a decision about where to place this window based on the
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index 910ee3a..9fceea8 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -219,8 +219,6 @@
       web_contents->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      window_->GetNativeView(), true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/conflicting_module_view_win.cc b/chrome/browser/ui/views/conflicting_module_view_win.cc
index 6c963a2..0611709 100644
--- a/chrome/browser/ui/views/conflicting_module_view_win.cc
+++ b/chrome/browser/ui/views/conflicting_module_view_win.cc
@@ -1,225 +1,232 @@
-// Copyright (c) 2013 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/views/conflicting_module_view_win.h"

-

-#include "base/metrics/histogram.h"

+// Copyright (c) 2013 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/views/conflicting_module_view_win.h"
+
+#include "base/metrics/histogram.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/enumerate_modules_model_win.h"

-#include "chrome/browser/profiles/profile.h"

-#include "chrome/browser/ui/browser.h"

-#include "chrome/common/pref_names.h"

-#include "content/public/browser/notification_service.h"

-#include "content/public/browser/user_metrics.h"

-#include "grit/chromium_strings.h"

-#include "grit/generated_resources.h"

-#include "grit/locale_settings.h"

-#include "grit/theme_resources.h"

-#include "ui/base/accessibility/accessible_view_state.h"

-#include "ui/base/l10n/l10n_util.h"

-#include "ui/base/resource/resource_bundle.h"

-#include "ui/views/controls/button/label_button.h"

-#include "ui/views/controls/image_view.h"

-#include "ui/views/controls/label.h"

-#include "ui/views/layout/grid_layout.h"

-#include "ui/views/layout/layout_constants.h"

-#include "ui/views/widget/widget.h"

-

-using content::UserMetricsAction;

-

-namespace {

-

-// Layout constants.

-const int kInsetBottomRight = 13;

-const int kInsetLeft = 14;

-const int kInsetTop = 9;

-const int kHeadlineMessagePadding = 4;

-const int kMessageBubblePadding = 11;

-

-// How often to show this bubble.

-const int kShowConflictingModuleBubbleMax = 3;

-

-}  // namespace

-

-////////////////////////////////////////////////////////////////////////////////

-// ConflictingModuleView

-

-ConflictingModuleView::ConflictingModuleView(

-    views::View* anchor_view,

-    Browser* browser,

-    const GURL& help_center_url)

-    : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),

-      browser_(browser),

-      explanation_(NULL),

-      learn_more_button_(NULL),

-      not_now_button_(NULL),

-      help_center_url_(help_center_url) {

-  set_close_on_deactivate(false);

-  set_move_with_anchor(true);

-  set_close_on_esc(true);

-

-  // Compensate for built-in vertical padding in the anchor view's image.

-  set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));

-

-  registrar_.Add(this, chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,

-                 content::NotificationService::AllSources());

-}

-

-// static

-void ConflictingModuleView::MaybeShow(Browser* browser,

-                                      views::View* anchor_view) {

-  static bool done_checking = false;

-  if (done_checking)

-    return;  // Only show the bubble once per launch.

-

-  EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();

-  GURL url = model->GetFirstNotableConflict();

-  if (!url.is_valid()) {

-    done_checking = true;

-    return;

-  }

-

-  // A pref that counts how often the Sideload Wipeout bubble has been shown.

-  IntegerPrefMember bubble_shown;

-  bubble_shown.Init(prefs::kModuleConflictBubbleShown,

-                    browser->profile()->GetPrefs());

-  if (bubble_shown.GetValue() >= kShowConflictingModuleBubbleMax) {

-    done_checking = true;

-    return;

-  }

-

-  ConflictingModuleView* bubble_delegate =

-      new ConflictingModuleView(anchor_view, browser, url);

-  views::BubbleDelegateView::CreateBubble(bubble_delegate);

-  bubble_delegate->ShowBubble();

-

-  done_checking = true;

-}

-

-////////////////////////////////////////////////////////////////////////////////

-// ConflictingModuleView - private.

-

-ConflictingModuleView::~ConflictingModuleView() {

-}

-

-void ConflictingModuleView::ShowBubble() {

-  StartFade(true);

-

-  IntegerPrefMember bubble_shown;

-  bubble_shown.Init(

-      prefs::kModuleConflictBubbleShown,

-      browser_->profile()->GetPrefs());

-  bubble_shown.SetValue(bubble_shown.GetValue() + 1);

-}

-

-void ConflictingModuleView::DismissBubble() {

-  GetWidget()->Close();

-

-  content::RecordAction(

-      UserMetricsAction("ConflictingModuleNotificationDismissed"));

-}

-

-void ConflictingModuleView::Init() {

-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

-

-  views::GridLayout* layout = views::GridLayout::CreatePanel(this);

-  layout->SetInsets(kInsetTop, kInsetLeft,

-                    kInsetBottomRight, kInsetBottomRight);

-  SetLayoutManager(layout);

-

-  views::ImageView* icon = new views::ImageView();

-  icon->SetImage(rb.GetNativeImageNamed(IDR_INPUT_ALERT_MENU).ToImageSkia());

-  gfx::Size icon_size = icon->GetPreferredSize();

-

-  const int text_column_set_id = 0;

-  views::ColumnSet* upper_columns = layout->AddColumnSet(text_column_set_id);

-  upper_columns->AddColumn(

-      views::GridLayout::LEADING, views::GridLayout::LEADING,

-      0, views::GridLayout::FIXED, icon_size.width(), icon_size.height());

-  upper_columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);

-  upper_columns->AddColumn(

-      views::GridLayout::LEADING, views::GridLayout::LEADING,

-      0, views::GridLayout::USE_PREF, 0, 0);

-

-  layout->StartRowWithPadding(

-      0, text_column_set_id, 0, kHeadlineMessagePadding);

-  layout->AddView(icon);

-  explanation_ = new views::Label();

-  explanation_->SetMultiLine(true);

-  explanation_->SetHorizontalAlignment(gfx::ALIGN_LEFT);

-  explanation_->SetText(l10n_util::GetStringUTF16(

-      IDS_OPTIONS_CONFLICTING_MODULE));

-  explanation_->SizeToFit(views::Widget::GetLocalizedContentsWidth(

-      IDS_CONFLICTING_MODULE_BUBBLE_WIDTH_CHARS));

-  layout->AddView(explanation_);

-

-  const int action_row_column_set_id = 1;

-  views::ColumnSet* bottom_columns =

-      layout->AddColumnSet(action_row_column_set_id);

-  bottom_columns->AddPaddingColumn(1, 0);

-  bottom_columns->AddColumn(views::GridLayout::TRAILING,

-      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);

-  bottom_columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing);

-  bottom_columns->AddColumn(views::GridLayout::TRAILING,

-      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);

-  layout->AddPaddingRow(0, 7);

-

-  layout->StartRowWithPadding(0, action_row_column_set_id,

-                              0, kMessageBubblePadding);

-  learn_more_button_ = new views::LabelButton(this,

-      l10n_util::GetStringUTF16(IDS_CONFLICTS_LEARN_MORE));

-  learn_more_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);

-  layout->AddView(learn_more_button_);

-  not_now_button_ = new views::LabelButton(this,

-      l10n_util::GetStringUTF16(IDS_CONFLICTS_NOT_NOW));

-  not_now_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);

-  layout->AddView(not_now_button_);

-

-  content::RecordAction(

-      UserMetricsAction("ConflictingModuleNotificationShown"));

-

-  UMA_HISTOGRAM_ENUMERATION("ConflictingModule.UserSelection",

-      EnumerateModulesModel::ACTION_BUBBLE_SHOWN,

-      EnumerateModulesModel::ACTION_BOUNDARY);

-}

-

-void ConflictingModuleView::ButtonPressed(views::Button* sender,

-                                          const ui::Event& event) {

-  if (sender == learn_more_button_) {

-    EnumerateModulesModel::RecordLearnMoreStat(false);

-    browser_->OpenURL(

-        content::OpenURLParams(help_center_url_,

-                               content::Referrer(),

-                               NEW_FOREGROUND_TAB,

-                               content::PAGE_TRANSITION_LINK,

-                               false));

-

-    EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();

-    model->AcknowledgeConflictNotification();

-    DismissBubble();

-  } else if (sender == not_now_button_) {

-    DismissBubble();

-  }

-}

-

-void ConflictingModuleView::GetAccessibleState(

-    ui::AccessibleViewState* state) {

-  state->role = ui::AccessibilityTypes::ROLE_ALERT;

-}

-

-void ConflictingModuleView::ViewHierarchyChanged(

-  const ViewHierarchyChangedDetails& details) {

-  if (details.is_add && details.child == this)

-    NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);

-}

-

-void ConflictingModuleView::Observe(

-    int type,

-    const content::NotificationSource& source,

-    const content::NotificationDetails& details) {

-  DCHECK(type == chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE);

-  EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();

-  if (!model->ShouldShowConflictWarning())

-    GetWidget()->Close();

-}

+#include "chrome/browser/enumerate_modules_model_win.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/user_metrics.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/widget/widget.h"
+
+using content::UserMetricsAction;
+
+namespace {
+
+// Layout constants.
+const int kInsetBottomRight = 13;
+const int kInsetLeft = 14;
+const int kInsetTop = 9;
+const int kHeadlineMessagePadding = 4;
+const int kMessageBubblePadding = 11;
+
+// How often to show this bubble.
+const int kShowConflictingModuleBubbleMax = 3;
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ConflictingModuleView
+
+ConflictingModuleView::ConflictingModuleView(
+    views::View* anchor_view,
+    Browser* browser,
+    const GURL& help_center_url)
+    : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
+      browser_(browser),
+      explanation_(NULL),
+      learn_more_button_(NULL),
+      not_now_button_(NULL),
+      help_center_url_(help_center_url) {
+  set_close_on_deactivate(false);
+  set_move_with_anchor(true);
+  set_close_on_esc(true);
+
+  // Compensate for built-in vertical padding in the anchor view's image.
+  set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
+
+  registrar_.Add(this, chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
+                 content::NotificationService::AllSources());
+}
+
+// static
+void ConflictingModuleView::MaybeShow(Browser* browser,
+                                      views::View* anchor_view) {
+  static bool done_checking = false;
+  if (done_checking)
+    return;  // Only show the bubble once per launch.
+
+  EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
+  GURL url = model->GetFirstNotableConflict();
+  if (!url.is_valid()) {
+    done_checking = true;
+    return;
+  }
+
+  // A pref that counts how often the Sideload Wipeout bubble has been shown.
+  IntegerPrefMember bubble_shown;
+  bubble_shown.Init(prefs::kModuleConflictBubbleShown,
+                    browser->profile()->GetPrefs());
+  if (bubble_shown.GetValue() >= kShowConflictingModuleBubbleMax) {
+    done_checking = true;
+    return;
+  }
+
+  // |anchor_view| must be in a widget (the browser's widget). If not, |browser|
+  // may be destroyed before us, and we'll crash trying to access |browser|
+  // later on. We can't DCHECK |browser|'s widget here as we may be called from
+  // creation of BrowserWindow, which means browser->window() may return NULL.
+  DCHECK(anchor_view);
+  DCHECK(anchor_view->GetWidget());
+
+  ConflictingModuleView* bubble_delegate =
+      new ConflictingModuleView(anchor_view, browser, url);
+  views::BubbleDelegateView::CreateBubble(bubble_delegate);
+  bubble_delegate->ShowBubble();
+
+  done_checking = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConflictingModuleView - private.
+
+ConflictingModuleView::~ConflictingModuleView() {
+}
+
+void ConflictingModuleView::ShowBubble() {
+  StartFade(true);
+
+  IntegerPrefMember bubble_shown;
+  bubble_shown.Init(
+      prefs::kModuleConflictBubbleShown,
+      browser_->profile()->GetPrefs());
+  bubble_shown.SetValue(bubble_shown.GetValue() + 1);
+}
+
+void ConflictingModuleView::DismissBubble() {
+  GetWidget()->Close();
+
+  content::RecordAction(
+      UserMetricsAction("ConflictingModuleNotificationDismissed"));
+}
+
+void ConflictingModuleView::Init() {
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+
+  views::GridLayout* layout = views::GridLayout::CreatePanel(this);
+  layout->SetInsets(kInsetTop, kInsetLeft,
+                    kInsetBottomRight, kInsetBottomRight);
+  SetLayoutManager(layout);
+
+  views::ImageView* icon = new views::ImageView();
+  icon->SetImage(rb.GetNativeImageNamed(IDR_INPUT_ALERT_MENU).ToImageSkia());
+  gfx::Size icon_size = icon->GetPreferredSize();
+
+  const int text_column_set_id = 0;
+  views::ColumnSet* upper_columns = layout->AddColumnSet(text_column_set_id);
+  upper_columns->AddColumn(
+      views::GridLayout::LEADING, views::GridLayout::LEADING,
+      0, views::GridLayout::FIXED, icon_size.width(), icon_size.height());
+  upper_columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+  upper_columns->AddColumn(
+      views::GridLayout::LEADING, views::GridLayout::LEADING,
+      0, views::GridLayout::USE_PREF, 0, 0);
+
+  layout->StartRowWithPadding(
+      0, text_column_set_id, 0, kHeadlineMessagePadding);
+  layout->AddView(icon);
+  explanation_ = new views::Label();
+  explanation_->SetMultiLine(true);
+  explanation_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  explanation_->SetText(l10n_util::GetStringUTF16(
+      IDS_OPTIONS_CONFLICTING_MODULE));
+  explanation_->SizeToFit(views::Widget::GetLocalizedContentsWidth(
+      IDS_CONFLICTING_MODULE_BUBBLE_WIDTH_CHARS));
+  layout->AddView(explanation_);
+
+  const int action_row_column_set_id = 1;
+  views::ColumnSet* bottom_columns =
+      layout->AddColumnSet(action_row_column_set_id);
+  bottom_columns->AddPaddingColumn(1, 0);
+  bottom_columns->AddColumn(views::GridLayout::TRAILING,
+      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
+  bottom_columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+  bottom_columns->AddColumn(views::GridLayout::TRAILING,
+      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
+  layout->AddPaddingRow(0, 7);
+
+  layout->StartRowWithPadding(0, action_row_column_set_id,
+                              0, kMessageBubblePadding);
+  learn_more_button_ = new views::LabelButton(this,
+      l10n_util::GetStringUTF16(IDS_CONFLICTS_LEARN_MORE));
+  learn_more_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+  layout->AddView(learn_more_button_);
+  not_now_button_ = new views::LabelButton(this,
+      l10n_util::GetStringUTF16(IDS_CONFLICTS_NOT_NOW));
+  not_now_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+  layout->AddView(not_now_button_);
+
+  content::RecordAction(
+      UserMetricsAction("ConflictingModuleNotificationShown"));
+
+  UMA_HISTOGRAM_ENUMERATION("ConflictingModule.UserSelection",
+      EnumerateModulesModel::ACTION_BUBBLE_SHOWN,
+      EnumerateModulesModel::ACTION_BOUNDARY);
+}
+
+void ConflictingModuleView::ButtonPressed(views::Button* sender,
+                                          const ui::Event& event) {
+  if (sender == learn_more_button_) {
+    EnumerateModulesModel::RecordLearnMoreStat(false);
+    browser_->OpenURL(
+        content::OpenURLParams(help_center_url_,
+                               content::Referrer(),
+                               NEW_FOREGROUND_TAB,
+                               content::PAGE_TRANSITION_LINK,
+                               false));
+
+    EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
+    model->AcknowledgeConflictNotification();
+    DismissBubble();
+  } else if (sender == not_now_button_) {
+    DismissBubble();
+  }
+}
+
+void ConflictingModuleView::GetAccessibleState(
+    ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_ALERT;
+}
+
+void ConflictingModuleView::ViewHierarchyChanged(
+  const ViewHierarchyChangedDetails& details) {
+  if (details.is_add && details.child == this)
+    NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);
+}
+
+void ConflictingModuleView::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK(type == chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE);
+  EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
+  if (!model->ShouldShowConflictWarning())
+    GetWidget()->Close();
+}
diff --git a/chrome/browser/ui/views/conflicting_module_view_win.h b/chrome/browser/ui/views/conflicting_module_view_win.h
index 118010f..04bd6b1 100644
--- a/chrome/browser/ui/views/conflicting_module_view_win.h
+++ b/chrome/browser/ui/views/conflicting_module_view_win.h
@@ -1,77 +1,77 @@
-// Copyright (c) 2013 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_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_

-#define CHROME_BROWSER_UI_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_

-

-#include "content/public/browser/notification_observer.h"

-#include "content/public/browser/notification_registrar.h"

-#include "ui/views/bubble/bubble_delegate.h"

-#include "ui/views/controls/button/button.h"

-#include "url/gurl.h"

-

-class Browser;

-

-namespace views {

-class Label;

-class LabelButton;

-}

-

-// This is the class that implements the UI for the bubble showing that there

-// is a 3rd party module loaded that conflicts with Chrome.

-class ConflictingModuleView : public views::BubbleDelegateView,

-                              public views::ButtonListener,

-                              public content::NotificationObserver {

- public:

-  ConflictingModuleView(views::View* anchor_view,

-                        Browser* browser,

-                        const GURL& help_center_url);

-

-  // Show the Disabled Extension bubble, if needed.

-  static void MaybeShow(Browser* browser, views::View* anchor_view);

-

- private:

-  virtual ~ConflictingModuleView();

-

-  // Shows the bubble and updates the counter for how often it has been shown.

-  void ShowBubble();

-

-  // Dismiss and make sure the bubble is not shown again. This bubble is a

-  // single-appearance bubble.

-  void DismissBubble();

-

-  // views::BubbleDelegateView implementation:

-  virtual void Init() OVERRIDE;

-

-  // views::ButtonListener implementation.

-  virtual void ButtonPressed(views::Button* sender,

-                             const ui::Event& event) OVERRIDE;

-

-  // views::View implementation.

-  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;

-  virtual void ViewHierarchyChanged(

-      const ViewHierarchyChangedDetails& details) OVERRIDE;

-

-  // content::NotificationObserver implementation.

-  virtual void Observe(

-    int type,

-    const content::NotificationSource& source,

-    const content::NotificationDetails& details) OVERRIDE;

-

-  Browser* browser_;

-

-  content::NotificationRegistrar registrar_;

-

-  // The headline, labels and buttons on the bubble.

-  views::Label* explanation_;

-  views::LabelButton* learn_more_button_;

-  views::LabelButton* not_now_button_;

-

-  // The link to the help center for this conflict.

-  GURL help_center_url_;

-

-  DISALLOW_COPY_AND_ASSIGN(ConflictingModuleView);

-};

-

-#endif  // CHROME_BROWSER_UI_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_

+// Copyright (c) 2013 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_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_
+#define CHROME_BROWSER_UI_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_
+
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "url/gurl.h"
+
+class Browser;
+
+namespace views {
+class Label;
+class LabelButton;
+}
+
+// This is the class that implements the UI for the bubble showing that there
+// is a 3rd party module loaded that conflicts with Chrome.
+class ConflictingModuleView : public views::BubbleDelegateView,
+                              public views::ButtonListener,
+                              public content::NotificationObserver {
+ public:
+  ConflictingModuleView(views::View* anchor_view,
+                        Browser* browser,
+                        const GURL& help_center_url);
+
+  // Show the Disabled Extension bubble, if needed.
+  static void MaybeShow(Browser* browser, views::View* anchor_view);
+
+ private:
+  virtual ~ConflictingModuleView();
+
+  // Shows the bubble and updates the counter for how often it has been shown.
+  void ShowBubble();
+
+  // Dismiss and make sure the bubble is not shown again. This bubble is a
+  // single-appearance bubble.
+  void DismissBubble();
+
+  // views::BubbleDelegateView implementation:
+  virtual void Init() OVERRIDE;
+
+  // views::ButtonListener implementation.
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+  // views::View implementation.
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+  virtual void ViewHierarchyChanged(
+      const ViewHierarchyChangedDetails& details) OVERRIDE;
+
+  // content::NotificationObserver implementation.
+  virtual void Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) OVERRIDE;
+
+  Browser* browser_;
+
+  content::NotificationRegistrar registrar_;
+
+  // The headline, labels and buttons on the bubble.
+  views::Label* explanation_;
+  views::LabelButton* learn_more_button_;
+  views::LabelButton* not_now_button_;
+
+  // The link to the help center for this conflict.
+  GURL help_center_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConflictingModuleView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_CONFLICTING_MODULE_VIEW_WIN_H_
diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
index 3b95bfc..423ebf8 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -235,8 +235,6 @@
       web_contents->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      window->GetNativeView(), true);
   constrained_delegate->SetWindow(window);
   return constrained_delegate;
 }
diff --git a/chrome/browser/ui/views/constrained_window_views_browsertest.cc b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
index eb08335..a430357 100644
--- a/chrome/browser/ui/views/constrained_window_views_browsertest.cc
+++ b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
@@ -130,13 +130,20 @@
   }
 };
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_FocusTest DISABLED_FocusTest
+#else
+#define MAYBE_FocusTest FocusTest
+#endif
+
 // Tests the following:
 //
 // *) Initially focused view in a constrained dialog receives focus reliably.
 //
 // *) Constrained windows that are queued don't register themselves as
 //    accelerator targets until they are displayed.
-IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) {
+IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_FocusTest) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents != NULL);
@@ -218,9 +225,16 @@
   EXPECT_FALSE(web_contents_modal_dialog_manager->IsDialogActive());
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_TabCloseTest DISABLED_TabCloseTest
+#else
+#define MAYBE_TabCloseTest TabCloseTest
+#endif
+
 // Tests that the constrained window is closed properly when its tab is
 // closed.
-IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabCloseTest) {
+IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabCloseTest) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents != NULL);
@@ -248,9 +262,16 @@
   EXPECT_TRUE(test_dialog->done());
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_TabSwitchTest DISABLED_TabSwitchTest
+#else
+#define MAYBE_TabSwitchTest TabSwitchTest
+#endif
+
 // Tests that the constrained window is hidden when an other tab is selected and
 // shown when its tab is selected again.
-IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabSwitchTest) {
+IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, MAYBE_TabSwitchTest) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents != NULL);
@@ -415,7 +436,8 @@
 
 // Fails flakily (once per 10-20 runs) on Win Aura only. http://crbug.com/177482
 // Also fails on CrOS.
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+// Also fails on linux_aura (http://crbug.com/163931)
+#if defined(TOOLKIT_VIEWS)
 #define MAYBE_EscapeCloseConstrainedWindow DISABLED_EscapeCloseConstrainedWindow
 #else
 #define MAYBE_EscapeCloseConstrainedWindow EscapeCloseConstrainedWindow
diff --git a/chrome/browser/ui/views/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_media_picker_views.cc
index 4155e5b..1ed67e3 100644
--- a/chrome/browser/ui/views/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_media_picker_views.cc
@@ -489,7 +489,7 @@
       views::HWNDForWidget(GetWidget()));
 #elif defined(USE_AURA)
   dialog_window_id = static_cast<content::DesktopMediaID::Id>(
-      GetWidget()->GetNativeWindow()->GetRootWindow()->GetAcceleratedWidget());
+      GetWidget()->GetNativeWindow()->GetDispatcher()->GetAcceleratedWidget());
 #else
   dialog_window_id = 0;
   NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/views/download/download_danger_prompt_views.cc b/chrome/browser/ui/views/download/download_danger_prompt_views.cc
new file mode 100644
index 0000000..f875ecd
--- /dev/null
+++ b/chrome/browser/ui/views/download/download_danger_prompt_views.cc
@@ -0,0 +1,377 @@
+// Copyright 2013 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/compiler_specific.h"
+#include "chrome/browser/download/download_danger_prompt.h"
+#include "chrome/browser/ui/views/constrained_window_views.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_danger_type.h"
+#include "content/public/browser/download_item.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
+#include "ui/views/window/dialog_delegate.h"
+
+using content::BrowserThread;
+using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
+
+namespace {
+
+const int kMessageWidth = 320;
+const int kParagraphPadding = 15;
+
+// Views-specific implementation of download danger prompt dialog. We use this
+// class rather than a TabModalConfirmDialog so that we can use custom
+// formatting on the text in the body of the dialog.
+class DownloadDangerPromptViews : public DownloadDangerPrompt,
+                                  public content::DownloadItem::Observer,
+                                  public views::DialogDelegate {
+ public:
+  DownloadDangerPromptViews(content::DownloadItem* item,
+                            content::WebContents* web_contents,
+                            bool show_context,
+                            const OnDone& done);
+
+  // DownloadDangerPrompt methods:
+  virtual void InvokeActionForTesting(Action action) OVERRIDE;
+
+  // views::DialogDelegate methods:
+  virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
+  virtual string16 GetWindowTitle() const OVERRIDE;
+  virtual void DeleteDelegate() OVERRIDE;
+  virtual ui::ModalType GetModalType() const OVERRIDE;
+  virtual bool Cancel() OVERRIDE;
+  virtual bool Accept() OVERRIDE;
+  virtual bool Close() OVERRIDE;
+  // TODO(wittman): Remove this override once we move to the new style frame
+  // view on all dialogs.
+  virtual views::NonClientFrameView* CreateNonClientFrameView(
+      views::Widget* widget) OVERRIDE;
+  virtual views::View* GetInitiallyFocusedView() OVERRIDE;
+  virtual views::View* GetContentsView() OVERRIDE;
+  virtual views::Widget* GetWidget() OVERRIDE;
+  virtual const views::Widget* GetWidget() const OVERRIDE;
+
+  // content::DownloadItem::Observer:
+  virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
+
+ private:
+  string16 GetAcceptButtonTitle() const;
+  string16 GetCancelButtonTitle() const;
+  // The message lead is separated from the main text and is bolded.
+  string16 GetMessageLead() const;
+  string16 GetMessageBody() const;
+  void RunDone(Action action);
+
+  content::DownloadItem* download_;
+  content::WebContents* web_contents_;
+  bool show_context_;
+  OnDone done_;
+
+  views::View* contents_view_;
+};
+
+DownloadDangerPromptViews::DownloadDangerPromptViews(
+    content::DownloadItem* item,
+    content::WebContents* web_contents,
+    bool show_context,
+    const OnDone& done)
+    : download_(item),
+      web_contents_(web_contents),
+      show_context_(show_context),
+      done_(done),
+      contents_view_(NULL) {
+  DCHECK(!done_.is_null());
+  download_->AddObserver(this);
+
+  contents_view_ = new views::View;
+
+  views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_);
+  contents_view_->SetLayoutManager(layout);
+
+  views::ColumnSet* column_set = layout->AddColumnSet(0);
+  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+                        views::GridLayout::FIXED, kMessageWidth, 0);
+
+  const string16 message_lead = GetMessageLead();
+
+  if (!message_lead.empty()) {
+    views::Label* message_lead_label = new views::Label(message_lead);
+    message_lead_label->SetMultiLine(true);
+    message_lead_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    message_lead_label->SetAllowCharacterBreak(true);
+
+    gfx::FontList font_list(gfx::Font().DeriveFont(0, gfx::Font::BOLD));
+    message_lead_label->SetFontList(font_list);
+
+    layout->StartRow(0, 0);
+    layout->AddView(message_lead_label);
+
+    layout->AddPaddingRow(0, kParagraphPadding);
+  }
+
+  views::Label* message_body_label = new views::Label(GetMessageBody());
+  message_body_label->SetMultiLine(true);
+  message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  message_body_label->SetAllowCharacterBreak(true);
+
+  layout->StartRow(0, 0);
+  layout->AddView(message_body_label);
+}
+
+// DownloadDangerPrompt methods:
+void DownloadDangerPromptViews::InvokeActionForTesting(Action action) {
+  switch (action) {
+    case ACCEPT:
+      Accept();
+      break;
+
+    case CANCEL:
+    case DISMISS:
+      Cancel();
+      break;
+
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+// views::DialogDelegate methods:
+string16 DownloadDangerPromptViews::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  switch (button) {
+    case ui::DIALOG_BUTTON_OK:
+      return GetAcceptButtonTitle();
+
+    case ui::DIALOG_BUTTON_CANCEL:
+      return GetCancelButtonTitle();
+
+    default:
+      return DialogDelegate::GetDialogButtonLabel(button);
+  };
+}
+
+string16 DownloadDangerPromptViews::GetWindowTitle() const {
+  if (show_context_)
+    return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+  else
+    return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+}
+
+void DownloadDangerPromptViews::DeleteDelegate() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  delete this;
+}
+
+ui::ModalType DownloadDangerPromptViews::GetModalType() const {
+#if defined(USE_ASH)
+  return ui::MODAL_TYPE_CHILD;
+#else
+  return views::WidgetDelegate::GetModalType();
+#endif
+}
+
+bool DownloadDangerPromptViews::Cancel() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  RunDone(CANCEL);
+  return true;
+}
+
+bool DownloadDangerPromptViews::Accept() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  RunDone(ACCEPT);
+  return true;
+}
+
+bool DownloadDangerPromptViews::Close() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  RunDone(DISMISS);
+  return true;
+}
+
+// TODO(wittman): Remove this override once we move to the new style frame
+// view on all dialogs.
+views::NonClientFrameView* DownloadDangerPromptViews::CreateNonClientFrameView(
+    views::Widget* widget) {
+  return CreateConstrainedStyleNonClientFrameView(
+      widget,
+      web_contents_->GetBrowserContext());
+}
+
+views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() {
+  return GetDialogClientView()->cancel_button();
+}
+
+views::View* DownloadDangerPromptViews::GetContentsView() {
+  return contents_view_;
+}
+
+views::Widget* DownloadDangerPromptViews::GetWidget() {
+  return contents_view_->GetWidget();
+}
+
+const views::Widget* DownloadDangerPromptViews::GetWidget() const {
+  return contents_view_->GetWidget();
+}
+
+// content::DownloadItem::Observer:
+void DownloadDangerPromptViews::OnDownloadUpdated(
+    content::DownloadItem* download) {
+  // If the download is nolonger dangerous (accepted externally) or the download
+  // is in a terminal state, then the download danger prompt is no longer
+  // necessary.
+  if (!download_->IsDangerous() || download_->IsDone()) {
+    RunDone(DISMISS);
+    Cancel();
+  }
+}
+
+string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const {
+  if (show_context_)
+    return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
+  switch (download_->GetDangerType()) {
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+      return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
+    }
+    default:
+      return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
+  }
+}
+
+string16 DownloadDangerPromptViews::GetCancelButtonTitle() const {
+  if (show_context_)
+    return l10n_util::GetStringUTF16(IDS_CANCEL);
+  switch (download_->GetDangerType()) {
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+      return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
+    }
+    default:
+      return l10n_util::GetStringUTF16(IDS_CANCEL);
+  }
+}
+
+string16 DownloadDangerPromptViews::GetMessageLead() const {
+  if (!show_context_) {
+    switch (download_->GetDangerType()) {
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+        return l10n_util::GetStringUTF16(
+            IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD);
+
+      default:
+        break;
+    }
+  }
+
+  return string16();
+}
+
+string16 DownloadDangerPromptViews::GetMessageBody() const {
+  if (show_context_) {
+    switch (download_->GetDangerType()) {
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
+        return l10n_util::GetStringFUTF16(
+            IDS_PROMPT_DANGEROUS_DOWNLOAD,
+            download_->GetFileNameToReportUser().LossyDisplayName());
+      }
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+        return l10n_util::GetStringFUTF16(
+            IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
+            download_->GetFileNameToReportUser().LossyDisplayName());
+      }
+      case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
+        return l10n_util::GetStringFUTF16(
+            IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
+            download_->GetFileNameToReportUser().LossyDisplayName());
+      }
+      case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
+        return l10n_util::GetStringFUTF16(
+            IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
+            download_->GetFileNameToReportUser().LossyDisplayName());
+      }
+      case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
+      case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
+      case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
+      case content::DOWNLOAD_DANGER_TYPE_MAX: {
+        break;
+      }
+    }
+  } else {
+    switch (download_->GetDangerType()) {
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+      case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+        return l10n_util::GetStringUTF16(
+            IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
+      }
+      default: {
+        return l10n_util::GetStringUTF16(
+            IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
+      }
+    }
+  }
+  NOTREACHED();
+  return string16();
+}
+
+void DownloadDangerPromptViews::RunDone(Action action) {
+  // Invoking the callback can cause the download item state to change or cause
+  // the window to close, and |callback| refers to a member variable.
+  OnDone done = done_;
+  done_.Reset();
+  if (download_ != NULL) {
+    download_->RemoveObserver(this);
+    download_ = NULL;
+  }
+  if (!done.is_null())
+    done.Run(action);
+}
+
+}  // namespace
+
+DownloadDangerPrompt* DownloadDangerPrompt::Create(
+    content::DownloadItem* item,
+    content::WebContents* web_contents,
+    bool show_context,
+    const OnDone& done) {
+  DownloadDangerPromptViews* download_danger_prompt =
+      new DownloadDangerPromptViews(item, web_contents, show_context, done);
+
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents);
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  CHECK(modal_delegate);
+  views::Widget* dialog = views::Widget::CreateWindowAsFramelessChild(
+      download_danger_prompt,
+      web_contents->GetView()->GetNativeView(),
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
+  web_contents_modal_dialog_manager->ShowDialog(dialog->GetNativeView());
+
+  return download_danger_prompt;
+}
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 3ff7201..c42d96a 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -104,6 +104,7 @@
     dangerous_download_label_sized_(false),
     disabled_while_opening_(false),
     creation_time_(base::Time::Now()),
+    time_download_warning_shown_(base::Time()),
     weak_ptr_factory_(this) {
   DCHECK(download());
   download()->AddObserver(this);
@@ -524,23 +525,32 @@
   ShowContextMenuImpl(local_point, source_type);
 }
 
-void DownloadItemView::ButtonPressed(
-    views::Button* sender, const ui::Event& event) {
-  if (sender == discard_button_) {
-    if (model_.ShouldAllowDownloadFeedback() && BeginDownloadFeedback())
-      return;
-    UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download",
-                             base::Time::Now() - creation_time_);
-    download()->Remove();
-    // WARNING: we are deleted at this point.  Don't access 'this'.
-  } else if (save_button_ && sender == save_button_) {
+void DownloadItemView::ButtonPressed(views::Button* sender,
+                                     const ui::Event& event) {
+  base::TimeDelta warning_duration;
+  if (!time_download_warning_shown_.is_null())
+    warning_duration = base::Time::Now() - time_download_warning_shown_;
+
+  if (save_button_ && sender == save_button_) {
     // The user has confirmed a dangerous download.  We'd record how quickly the
     // user did this to detect whether we're being clickjacked.
-    UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
-                             base::Time::Now() - creation_time_);
+    UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", warning_duration);
     // This will change the state and notify us.
     download()->ValidateDangerousDownload();
+    return;
   }
+
+  DCHECK_EQ(discard_button_, sender);
+  if (model_.ShouldAllowDownloadFeedback() && BeginDownloadFeedback())
+    return;
+  if (model_.IsMalicious()) {
+    UMA_HISTOGRAM_LONG_TIMES("clickjacking.dismiss_download", warning_duration);
+    shelf_->RemoveDownloadView(this);
+  } else {
+    UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", warning_duration);
+    download()->Remove();
+  }
+  // WARNING: |this| has been deleted!
 }
 
 void DownloadItemView::AnimationProgressed(const gfx::Animation* animation) {
@@ -866,8 +876,11 @@
       sb_service->download_protection_service();
   if (!download_protection_service)
     return false;
+  base::TimeDelta warning_duration = base::TimeDelta();
+  if (!time_download_warning_shown_.is_null())
+    warning_duration = base::Time::Now() - time_download_warning_shown_;
   UMA_HISTOGRAM_LONG_TIMES("clickjacking.report_and_discard_download",
-                           base::Time::Now() - creation_time_);
+                           warning_duration);
   download_protection_service->feedback_service()->BeginFeedbackForDownload(
       download());
   // WARNING: we are deleted at this point.  Don't access 'this'.
@@ -1072,6 +1085,7 @@
 
 void DownloadItemView::ShowWarningDialog() {
   DCHECK(mode_ != DANGEROUS_MODE && mode_ != MALICIOUS_MODE);
+  time_download_warning_shown_ = base::Time::Now();
   mode_ = model_.MightBeMalicious() ? MALICIOUS_MODE : DANGEROUS_MODE;
 
   body_state_ = NORMAL;
@@ -1082,15 +1096,15 @@
     save_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
     AddChildView(save_button_);
   }
+  int discard_button_message = model_.IsMalicious() ?
+      IDS_DISMISS_DOWNLOAD : IDS_DISCARD_DOWNLOAD;
   if (model_.ShouldAllowDownloadFeedback()) {
     safe_browsing::DownloadFeedbackService::RecordFeedbackButtonShown(
         download()->GetDangerType());
-    discard_button_ = new views::LabelButton(
-        this, l10n_util::GetStringUTF16(IDS_REPORT_AND_DISCARD_DOWNLOAD));
-  } else {
-    discard_button_ = new views::LabelButton(
-        this, l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD));
+    discard_button_message = IDS_REPORT_AND_DISCARD_DOWNLOAD;
   }
+  discard_button_ = new views::LabelButton(
+      this, l10n_util::GetStringUTF16(discard_button_message));
   discard_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
   AddChildView(discard_button_);
 
@@ -1100,6 +1114,7 @@
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
     case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
       warning_icon_ = rb.GetImageSkiaNamed(IDR_SAFEBROWSING_WARNING);
       break;
 
@@ -1111,7 +1126,6 @@
       // fallthrough
 
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
-    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
       warning_icon_ = rb.GetImageSkiaNamed(IDR_WARNING);
   }
   string16 dangerous_label = model_.GetWarningText(font_list_, kTextWidth);
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 177d243..a5ce501 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -315,6 +315,9 @@
   // The time at which this view was created.
   base::Time creation_time_;
 
+  // The time at which a dangerous download warning was displayed.
+  base::Time time_download_warning_shown_;
+
   // Method factory used to delay reenabling of the item when opening the
   // downloaded file.
   base::WeakPtrFactory<DownloadItemView> weak_ptr_factory_;
diff --git a/chrome/browser/ui/views/download/download_started_animation_views.cc b/chrome/browser/ui/views/download/download_started_animation_views.cc
index 82f5b58..fcde0a2 100644
--- a/chrome/browser/ui/views/download/download_started_animation_views.cc
+++ b/chrome/browser/ui/views/download/download_started_animation_views.cc
@@ -4,11 +4,6 @@
 
 #include "chrome/browser/download/download_started_animation.h"
 
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "grit/theme_resources.h"
@@ -18,8 +13,6 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/widget/widget.h"
 
-using content::WebContents;
-
 // How long to spend moving downwards and fading out after waiting.
 const int kMoveTimeMs = 600;
 
@@ -33,11 +26,10 @@
 // provided on the constructor, while simultaneously fading it out.  To use,
 // simply call "new DownloadStartAnimation"; the class cleans itself up when it
 // finishes animating.
-class DownloadStartedAnimationWin : public gfx::LinearAnimation,
-                                    public content::NotificationObserver,
-                                    public views::ImageView {
+class DownloadStartedAnimationViews : public gfx::LinearAnimation,
+                                      public views::ImageView {
  public:
-  explicit DownloadStartedAnimationWin(WebContents* web_contents);
+  explicit DownloadStartedAnimationViews(content::WebContents* web_contents);
 
  private:
   // Move the animation to wherever it should currently be.
@@ -49,17 +41,10 @@
   // Animation
   virtual void AnimateToState(double state) OVERRIDE;
 
-  // content::NotificationObserver
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // We use a HWND for the popup so that it may float above any HWNDs in our UI.
+  // We use a TYPE_POPUP for the popup so that it may float above any windows in
+  // our UI.
   views::Widget* popup_;
 
-  // The content area holding us.
-  WebContents* web_contents_;
-
   // The content area at the start of the animation. We store this so that the
   // download shelf's resizing of the content area doesn't cause the animation
   // to move around. This means that once started, the animation won't move
@@ -67,17 +52,13 @@
   // much heartbreak.
   gfx::Rect web_contents_bounds_;
 
-  // A scoped container for notification registries.
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationWin);
+  DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationViews);
 };
 
-DownloadStartedAnimationWin::DownloadStartedAnimationWin(
-    WebContents* web_contents)
+DownloadStartedAnimationViews::DownloadStartedAnimationViews(
+    content::WebContents* web_contents)
     : gfx::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
-      popup_(NULL),
-      web_contents_(web_contents) {
+      popup_(NULL) {
   static gfx::ImageSkia* kDownloadImage = NULL;
   if (!kDownloadImage) {
     kDownloadImage = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
@@ -86,19 +67,10 @@
 
   // If we're too small to show the download image, then don't bother -
   // the shelf will be enough.
-  web_contents_->GetView()->GetContainerBounds(&web_contents_bounds_);
+  web_contents->GetView()->GetContainerBounds(&web_contents_bounds_);
   if (web_contents_bounds_.height() < kDownloadImage->height())
     return;
 
-  registrar_.Add(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      content::Source<WebContents>(web_contents_));
-  registrar_.Add(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(web_contents_));
-
   SetImage(kDownloadImage);
 
   popup_ = new views::Widget;
@@ -106,7 +78,7 @@
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = false;
-  params.parent = web_contents_->GetView()->GetNativeView();
+  params.parent = web_contents->GetView()->GetNativeView();
   popup_->Init(params);
   popup_->SetOpacity(0x00);
   popup_->SetContentsView(this);
@@ -116,10 +88,7 @@
   Start();
 }
 
-void DownloadStartedAnimationWin::Reposition() {
-  if (!web_contents_)
-    return;
-
+void DownloadStartedAnimationViews::Reposition() {
   // Align the image with the bottom left of the web contents (so that it
   // points to the newly created download).
   gfx::Size size = GetPreferredSize();
@@ -133,23 +102,11 @@
       size.height()));
 }
 
-void DownloadStartedAnimationWin::Close() {
-  if (!web_contents_)
-    return;
-
-  registrar_.Remove(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      content::Source<WebContents>(web_contents_));
-  registrar_.Remove(
-      this,
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(web_contents_));
-  web_contents_ = NULL;
+void DownloadStartedAnimationViews::Close() {
   popup_->Close();
 }
 
-void DownloadStartedAnimationWin::AnimateToState(double state) {
+void DownloadStartedAnimationViews::AnimateToState(double state) {
   if (state >= 1.0) {
     Close();
   } else {
@@ -163,23 +120,10 @@
   }
 }
 
-void DownloadStartedAnimationWin::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) {
-    bool visible = *content::Details<bool>(details).ptr();
-    if (visible)
-      return;
-  }
-  Close();
-}
-
 }  // namespace
 
 // static
-void DownloadStartedAnimation::Show(WebContents* web_contents) {
-  // The animation will delete itself when it's finished or when the tab
-  // contents is hidden or destroyed.
-  new DownloadStartedAnimationWin(web_contents);
+void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
+  // The animation will delete itself when it's finished.
+  new DownloadStartedAnimationViews(web_contents);
 }
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index 5575e9f..6968c55 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
@@ -52,8 +53,9 @@
 // Size of extension icon in top left of dialog.
 const int kIconSize = 69;
 
-// The dialog width.
-const int kDialogWidth = 385;
+// We offset the icon a little bit from the right edge of the dialog, to make it
+// align with the button below it.
+const int kIconOffset = 16;
 
 // The dialog will resize based on its content, but this sets a maximum height
 // before overflowing a scrollbar.
@@ -128,10 +130,6 @@
   virtual void Layout() OVERRIDE;
   virtual gfx::Size GetPreferredSize() OVERRIDE;
 
-  // views::WidgetDelegate
-  virtual bool ShouldShowWindowTitle() const OVERRIDE;
-  virtual bool ShouldShowCloseButton() const OVERRIDE;
-
   // views::LinkListener:
   virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
 
@@ -139,11 +137,6 @@
     return prompt_.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT;
   }
 
-  bool is_first_run() const {
-    return prompt_.type() ==
-        ExtensionInstallPrompt::DEFAULT_INSTALL_FIRST_RUN_PROMPT;
-  }
-
   bool is_bundle_install() const {
     return prompt_.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT;
   }
@@ -377,6 +370,8 @@
   if (is_external_install())
     left_column_width = kExternalInstallLeftColumnWidth;
 
+  int dialog_width = left_column_width + 2 * views::kPanelHorizMargin;
+
   column_set->AddColumn(views::GridLayout::LEADING,
                         views::GridLayout::FILL,
                         0,  // no resizing
@@ -385,12 +380,14 @@
                         left_column_width);
   if (!is_bundle_install()) {
     column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
-    column_set->AddColumn(views::GridLayout::LEADING,
+    column_set->AddColumn(views::GridLayout::TRAILING,
                           views::GridLayout::LEADING,
                           0,  // no resizing
                           views::GridLayout::USE_PREF,
                           0,  // no fixed width
                           kIconSize);
+
+    dialog_width += views::kPanelHorizMargin + kIconSize + kIconOffset;
   }
 
   layout->StartRow(0, column_set_id);
@@ -421,15 +418,10 @@
       icon_row_span = 4;
     } else if (prompt.ShouldShowPermissions()) {
       size_t permission_count = prompt.GetPermissionCount();
-      if (permission_count > 0) {
-        // Also span the permission header and each of the permission rows (all
-        // have a padding row above it).
-        icon_row_span = 3 + permission_count * 2;
-      } else {
-        // This is the 'no special permissions' case, so span the line we add
-        // (without a header) saying the extension has no special privileges.
-        icon_row_span = 4;
-      }
+      // Also span the permission header and each of the permission rows (all
+      // have a padding row above it). This also works for the 'no special
+      // permissions' case.
+      icon_row_span = 3 + permission_count * 2;
     } else if (prompt.GetOAuthIssueCount()) {
       // Also span the permission header and each of the permission rows (all
       // have a padding row above it).
@@ -630,7 +622,7 @@
   gfx::Size scrollable_size = scrollable_->GetPreferredSize();
   scrollable_->SetBoundsRect(gfx::Rect(scrollable_size));
   dialog_size_ = gfx::Size(
-      kDialogWidth,
+      dialog_width,
       std::min(scrollable_size.height(), kDialogMaxHeight));
 }
 
@@ -664,10 +656,7 @@
 }
 
 int ExtensionInstallDialogView::GetDefaultDialogButton() const {
-  if (is_first_run())
-    return ui::DIALOG_BUTTON_OK;
-  else
-    return ui::DIALOG_BUTTON_CANCEL;
+  return ui::DIALOG_BUTTON_CANCEL;
 }
 
 bool ExtensionInstallDialogView::Cancel() {
@@ -708,14 +697,6 @@
   return dialog_size_;
 }
 
-bool ExtensionInstallDialogView::ShouldShowWindowTitle() const {
-  return false;
-}
-
-bool ExtensionInstallDialogView::ShouldShowCloseButton() const {
-  return false;
-}
-
 // static
 ExtensionInstallPrompt::ShowDialogCallback
 ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
index e52edaf..c51023a 100644
--- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -130,8 +130,10 @@
 }
 
 void ExtensionUninstallDialogViews::Show() {
+  // TODO(tapted): A true |desktop_type| needs to be passed in at creation time
+  // to remove reliance on GetActiveDesktop(). http://crbug.com/308360
   gfx::NativeWindow parent = show_in_app_list_ ?
-      AppListService::Get()->GetAppListWindow() :
+      AppListService::Get(chrome::GetActiveDesktop())->GetAppListWindow() :
       GetParent(browser_);
   if (browser_ && !parent) {
     delegate_->ExtensionUninstallCanceled();
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
index 6cffb9b..c268981 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -20,6 +20,7 @@
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
@@ -93,8 +94,6 @@
       controller->web_contents()->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      window_->GetNativeView(), true);
 }
 
 MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {}
@@ -150,6 +149,7 @@
 
   // Add attached galleries checkboxes.
   checkbox_map_.clear();
+  new_checkbox_map_.clear();
   GalleryPermissionsVector permissions = controller_->AttachedPermissions();
   for (GalleryPermissionsVector::const_iterator iter = permissions.begin();
        iter != permissions.end(); ++iter) {
@@ -203,14 +203,7 @@
                   dialog_content_width, kScrollAreaHeight);
 }
 
-void MediaGalleriesDialogViews::UpdateGallery(
-    const MediaGalleryPrefInfo& gallery,
-    bool permitted) {
-  InitChildViews();
-  contents_->Layout();
-}
-
-void MediaGalleriesDialogViews::ForgetGallery(MediaGalleryPrefId gallery) {
+void MediaGalleriesDialogViews::UpdateGalleries() {
   InitChildViews();
   contents_->Layout();
 }
@@ -225,7 +218,8 @@
   string16 details = gallery.GetGalleryAdditionalDetails();
 
   CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id);
-  if (iter != checkbox_map_.end()) {
+  if (iter != checkbox_map_.end() &&
+      gallery.pref_id != kInvalidMediaGalleryPrefId) {
     views::Checkbox* checkbox = iter->second;
     checkbox->SetChecked(permitted);
     checkbox->SetText(label);
@@ -237,15 +231,17 @@
     views::Label* secondary_text =
         static_cast<views::Label*>(checkbox_view->child_at(1));
     secondary_text->SetText(details);
-
-    // Why is this returning false? Looks like that will mean it doesn't paint.
     return false;
   }
 
   views::Checkbox* checkbox = new views::Checkbox(label);
   checkbox->set_listener(this);
+  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
+    checkbox->set_context_menu_controller(this);
   checkbox->SetTooltipText(tooltip_text);
   views::Label* secondary_text = new views::Label(details);
+  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
+    secondary_text->set_context_menu_controller(this);
   secondary_text->SetTooltipText(tooltip_text);
   secondary_text->SetEnabledColor(kDeemphasizedTextColor);
   secondary_text->SetTooltipText(tooltip_text);
@@ -256,6 +252,8 @@
       views::kRelatedControlSmallHorizontalSpacing));
 
   views::View* checkbox_view = new views::View();
+  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
+    checkbox_view->set_context_menu_controller(this);
   checkbox_view->set_border(views::Border::CreateEmptyBorder(
       0,
       views::kPanelHorizMargin,
@@ -269,7 +267,10 @@
   container->AddChildView(checkbox_view);
 
   checkbox->SetChecked(permitted);
-  checkbox_map_[gallery.pref_id] = checkbox;
+  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
+    checkbox_map_[gallery.pref_id] = checkbox;
+  else
+    new_checkbox_map_[checkbox] = gallery;
 
   return true;
 }
@@ -363,6 +364,40 @@
       return;
     }
   }
+  for (NewCheckboxMap::const_iterator iter = new_checkbox_map_.begin();
+       iter != new_checkbox_map_.end(); ++iter) {
+    if (sender == iter->first) {
+      controller_->DidToggleNewGallery(iter->second, iter->first->checked());
+    }
+  }
+}
+
+void MediaGalleriesDialogViews::ShowContextMenuForView(
+    views::View* source,
+    const gfx::Point& point,
+    ui::MenuSourceType source_type) {
+  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
+       iter != checkbox_map_.end(); ++iter) {
+    if (iter->second->parent()->Contains(source)) {
+      ShowContextMenu(point, source_type, iter->first);
+      return;
+    }
+  }
+}
+
+void MediaGalleriesDialogViews::ShowContextMenu(const gfx::Point& point,
+                                                ui::MenuSourceType source_type,
+                                                MediaGalleryPrefId id) {
+  context_menu_runner_.reset(new views::MenuRunner(
+      controller_->GetContextMenuModel(id)));
+
+  if (context_menu_runner_->RunMenuAt(
+          GetWidget(), NULL, gfx::Rect(point.x(), point.y(), 0, 0),
+          views::MenuItemView::TOPLEFT, source_type,
+          views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
+      views::MenuRunner::MENU_DELETED) {
+    return;
+  }
 }
 
 // MediaGalleriesDialogViewsController -----------------------------------------
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
index 2710f9b..8b1d95c 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
@@ -9,29 +9,34 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
+#include "ui/views/context_menu_controller.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/window/dialog_delegate.h"
 
+namespace ui {
+class MenuModel;
+}
+
 namespace views {
 class Checkbox;
 class LabelButton;
+class MenuRunner;
 class Widget;
 }
 
 // The media galleries configuration view for Views. It will immediately show
 // upon construction.
 class MediaGalleriesDialogViews : public MediaGalleriesDialog,
-                                  public views::DialogDelegate,
-                                  public views::ButtonListener {
+                                  public views::ButtonListener,
+                                  public views::ContextMenuController,
+                                  public views::DialogDelegate {
  public:
   explicit MediaGalleriesDialogViews(
       MediaGalleriesDialogController* controller);
   virtual ~MediaGalleriesDialogViews();
 
   // MediaGalleriesDialog implementation:
-  virtual void UpdateGallery(const MediaGalleryPrefInfo& gallery,
-                             bool permitted) OVERRIDE;
-  virtual void ForgetGallery(MediaGalleryPrefId gallery) OVERRIDE;
+  virtual void UpdateGalleries() OVERRIDE;
 
   // views::DialogDelegate implementation:
   virtual string16 GetWindowTitle() const OVERRIDE;
@@ -53,8 +58,14 @@
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE;
 
+  // views::ContextMenuController implementation:
+  virtual void ShowContextMenuForView(views::View* source,
+                                      const gfx::Point& point,
+                                      ui::MenuSourceType source_type) OVERRIDE;
+
  private:
   typedef std::map<MediaGalleryPrefId, views::Checkbox*> CheckboxMap;
+  typedef std::map<views::Checkbox*, MediaGalleryPrefInfo> NewCheckboxMap;
 
   void InitChildViews();
 
@@ -65,6 +76,10 @@
                           views::View* container,
                           int trailing_vertical_space);
 
+  void ShowContextMenu(const gfx::Point& point,
+                       ui::MenuSourceType source_type,
+                       MediaGalleryPrefId id);
+
   MediaGalleriesDialogController* controller_;
 
   // The containing window (a weak pointer).
@@ -76,6 +91,8 @@
   // A map from media gallery ID to views::Checkbox view.
   CheckboxMap checkbox_map_;
 
+  NewCheckboxMap new_checkbox_map_;
+
   // Pointer to the button to add a new gallery. Owned by parent in
   // the dialog views tree.
   views::LabelButton* add_gallery_button_;
@@ -88,6 +105,8 @@
   // True if the user has pressed accept.
   bool accepted_;
 
+  scoped_ptr<views::MenuRunner> context_menu_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesDialogViews);
 };
 
diff --git a/chrome/browser/ui/views/external_tab_container_win.cc b/chrome/browser/ui/views/external_tab_container_win.cc
index de2ba67..54fcf1d 100644
--- a/chrome/browser/ui/views/external_tab_container_win.cc
+++ b/chrome/browser/ui/views/external_tab_container_win.cc
@@ -214,7 +214,7 @@
     MSG_WM_SIZE(OnSize)
   END_MSG_MAP()
 
-  ContainerWindow(HWND parent, const gfx::Rect& bounds) : child_(NULL) {
+  ContainerWindow(HWND parent, const gfx::Rect& bounds) : widget_(NULL) {
     RECT rect = bounds.ToRECT();
     Create(parent, rect);
   }
@@ -224,11 +224,12 @@
     return m_hWnd;
   }
 
-  // Sets the child window (the DRWHW). The child is made activateable as part
-  // of the operation.
-  void SetChild(HWND window) {
-    child_ = window;
+  // Sets the Widget. The widget's HWND is made activateable as part of the
+  // operation.
+  void SetWidget(views::Widget* widget) {
+    widget_ = widget;
 
+    HWND window = child();
     ::SetWindowLong(
         window, GWL_STYLE,
         (::GetWindowLong(window, GWL_STYLE) & ~WS_POPUP) | WS_CHILD);
@@ -244,21 +245,35 @@
   }
 
  private:
+  HWND child() {
+    return views::HWNDForWidget(widget_);
+  }
+
   void OnMove(const CPoint& position) {
-    ::SetWindowPos(child_, NULL, position.x, position.y, 0, 0,
+    if (!widget_)
+      return;
+    ::SetWindowPos(child(), NULL, position.x, position.y, 0, 0,
                    SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
   }
 
   void OnShowWindow(BOOL show, UINT status) {
-    ::ShowWindow(child_, SW_SHOWNA);
+    if (!widget_)
+      return;
+    // We need to show |widget_| without changing focus. Contrary to the name,
+    // Widget::ShowInactive() still changes activation.  So, we inline the
+    // implementation minus the focus change.
+    ::ShowWindow(child(), SW_SHOWNA);
+    widget_->GetNativeView()->Show();
   }
 
   void OnSize(UINT type, const CSize& size) {
-    ::SetWindowPos(child_, NULL, 0, 0, size.cx, size.cy,
+    if (!widget_)
+      return;
+    ::SetWindowPos(child(), NULL, 0, 0, size.cx, size.cy,
                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
   }
 
-  HWND child_;
+  views::Widget* widget_;
 
   DISALLOW_COPY_AND_ASSIGN(ContainerWindow);
 };
@@ -271,11 +286,9 @@
  public:
   ExternalTabRootWindowHost(
       views::internal::NativeWidgetDelegate* native_widget_delegate,
-      views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds)
+      views::DesktopNativeWidgetAura* desktop_native_widget_aura)
       : views::DesktopRootWindowHostWin(native_widget_delegate,
-                                        desktop_native_widget_aura,
-                                        initial_bounds) {}
+                                        desktop_native_widget_aura) {}
 
  protected:
   // HWNDMessageHandlerDelegate methods:
@@ -302,9 +315,6 @@
     AutomationResourceMessageFilter* filter)
     : widget_(NULL),
       automation_(automation),
-      rvh_callback_(base::Bind(
-          &ExternalTabContainerWin::RegisterRenderViewHostForAutomation,
-          base::Unretained(this), false)),
       tab_contents_container_(NULL),
       tab_handle_(0),
       ignore_next_load_notification_(false),
@@ -370,14 +380,14 @@
       new views::DesktopNativeWidgetAura(widget_);
   params.native_widget = native_widget;
   params.desktop_root_window_host =
-      new ExternalTabRootWindowHost(widget_, native_widget, params.bounds);
+      new ExternalTabRootWindowHost(widget_, native_widget);
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
   params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
 #endif
   widget_->Init(params);
 
 #if defined(USE_AURA)
-  tab_container_window_->SetChild(views::HWNDForWidget(widget_));
+  tab_container_window_->SetWidget(widget_);
 #endif
 
   // TODO(jcampan): limit focus traversal to contents.
@@ -405,8 +415,6 @@
   registrar_.Add(this,
                  content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
                  content::Source<WebContents>(existing_contents));
-
-  content::RenderViewHost::AddCreatedCallback(rvh_callback_);
   content::WebContentsObserver::Observe(existing_contents);
 
   BrowserTabContents::AttachTabHelpers(existing_contents);
@@ -451,7 +459,6 @@
 
 void ExternalTabContainerWin::Uninitialize() {
   registrar_.RemoveAll();
-  content::RenderViewHost::RemoveCreatedCallback(rvh_callback_);
   if (web_contents_.get()) {
     tab_contents_container_->SetWebContents(NULL);
     UnregisterRenderViewHost(web_contents_->GetRenderViewHost());
diff --git a/chrome/browser/ui/views/external_tab_container_win.h b/chrome/browser/ui/views/external_tab_container_win.h
index 91c3dfe..7163376 100644
--- a/chrome/browser/ui/views/external_tab_container_win.h
+++ b/chrome/browser/ui/views/external_tab_container_win.h
@@ -20,7 +20,6 @@
 #include "content/public/browser/navigation_type.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/base/accelerators/accelerator.h"
@@ -256,8 +255,6 @@
   scoped_ptr<content::WebContents> web_contents_;
   scoped_refptr<AutomationProvider> automation_;
 
-  content::RenderViewHost::CreatedCallback rvh_callback_;
-
   content::NotificationRegistrar registrar_;
 
   // A view to handle focus cycling
diff --git a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
index 464fb88..5a84355 100644
--- a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
@@ -90,8 +90,15 @@
       browser(), ui::VKEY_ESCAPE, false, false, false, false));
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_FocusRestore DISABLED_FocusRestore
+#else
+#define MAYBE_FocusRestore FocusRestore
+#endif
+
 // Flaky because the test server fails to start? See: http://crbug.com/96594.
-IN_PROC_BROWSER_TEST_F(FindInPageTest, FocusRestore) {
+IN_PROC_BROWSER_TEST_F(FindInPageTest, MAYBE_FocusRestore) {
   ASSERT_TRUE(test_server()->Start());
 
   GURL url = test_server()->GetURL("title1.html");
@@ -138,7 +145,11 @@
   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
 }
 
-IN_PROC_BROWSER_TEST_F(FindInPageTest, SelectionRestoreOnTabSwitch) {
+
+// TODO(phajdan.jr): Disabling due to possible timing issues on XP
+// interactive_ui_tests.
+// http://crbug.com/311363
+IN_PROC_BROWSER_TEST_F(FindInPageTest, DISABLED_SelectionRestoreOnTabSwitch) {
   ASSERT_TRUE(test_server()->Start());
 
   // Make sure Chrome is in the foreground, otherwise sending input
@@ -209,8 +220,15 @@
   EXPECT_EQ(ASCIIToUTF16("de"), GetFindBarSelectedText());
 }
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_FocusRestoreOnTabSwitch DISABLED_FocusRestoreOnTabSwitch
+#else
+#define MAYBE_FocusRestoreOnTabSwitch FocusRestoreOnTabSwitch
+#endif
+
 // Flaky because the test server fails to start? See: http://crbug.com/96594.
-IN_PROC_BROWSER_TEST_F(FindInPageTest, FocusRestoreOnTabSwitch) {
+IN_PROC_BROWSER_TEST_F(FindInPageTest, MAYBE_FocusRestoreOnTabSwitch) {
   ASSERT_TRUE(test_server()->Start());
 
   // First we navigate to our test page (tab A).
@@ -322,7 +340,8 @@
 
 // Flaky on Win. http://crbug.com/92467
 // Flaky on ChromeOS. http://crbug.com/118216
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+// Flaky on linux aura. http://crbug.com/163931
+#if defined(TOOLKIT_VIEWS)
 #define MAYBE_PasteWithoutTextChange DISABLED_PasteWithoutTextChange
 #else
 #define MAYBE_PasteWithoutTextChange PasteWithoutTextChange
@@ -393,7 +412,10 @@
 }
 
 #if defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(FindInPageTest, CtrlEnter) {
+// TODO(phajdan.jr): Disabling due to possible timing issues on XP
+// interactive_ui_tests.
+// http://crbug.com/311363
+IN_PROC_BROWSER_TEST_F(FindInPageTest, DISABLED_CtrlEnter) {
   ui_test_utils::NavigateToURL(browser(),
                                GURL("data:text/html,This is some text with a "
                                     "<a href=\"about:blank\">link</a>."));
diff --git a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash_browsertest.cc
index dcf54e8..d9aab04 100644
--- a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash_browsertest.cc
@@ -78,7 +78,7 @@
     return browser_frame->GetFrameView()->GetClassName();
   }
 
-  aura::RootWindow* GetRootWindow() const {
+  aura::Window* GetRootWindow() const {
     BrowserView* browser_view =
         static_cast<BrowserView*>(app_browser_->window());
     views::Widget* widget = browser_view->GetWidget();
@@ -137,7 +137,7 @@
 // Ensure that we can click the close button when the controls are shown.
 // In particular make sure that we can click it on the top pixel of the button.
 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, ClickClose) {
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
   aura::test::EventGenerator eg(root_window, gfx::Point(0, 1));
 
   // Click close button.
@@ -154,7 +154,7 @@
 // Ensure that closing a maximized app with Ctrl-W does not crash the
 // application.  crbug.com/147635
 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, KeyboardClose) {
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
   aura::test::EventGenerator eg(root_window);
 
   // Base browser and app browser.
@@ -176,7 +176,7 @@
 
 // Ensure that snapping left with Alt-[ closes the control window.
 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, SnapLeftClosesControls) {
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
   aura::test::EventGenerator eg(root_window);
   aura::Window* native_window = app_browser()->window()->GetNativeWindow();
 
@@ -196,7 +196,7 @@
 
 // Ensure that the controls are at the proper locations.
 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, ControlsAtRightSide) {
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
   aura::test::EventGenerator eg(root_window);
   aura::Window* native_window = app_browser()->window()->GetNativeWindow();
   const gfx::Rect work_area =
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host.h b/chrome/browser/ui/views/frame/browser_desktop_root_window_host.h
index 8f49a44..70cbcf2 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host.h
@@ -26,7 +26,6 @@
   static BrowserDesktopRootWindowHost* CreateBrowserDesktopRootWindowHost(
       views::internal::NativeWidgetDelegate* native_widget_delegate,
       views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds,
       BrowserView* browser_view,
       BrowserFrame* browser_frame);
 
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
index bbd7f6f..2e67d4c 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/theme_image_mapper.h"
 #include "grit/theme_resources.h"
+#include "ui/aura/root_window.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/win/dpi.h"
 #include "ui/views/controls/menu/native_menu_win.h"
@@ -76,12 +77,10 @@
 BrowserDesktopRootWindowHostWin::BrowserDesktopRootWindowHostWin(
     views::internal::NativeWidgetDelegate* native_widget_delegate,
     views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds,
     BrowserView* browser_view,
     BrowserFrame* browser_frame)
     : DesktopRootWindowHostWin(native_widget_delegate,
-                               desktop_native_widget_aura,
-                               initial_bounds),
+                               desktop_native_widget_aura),
       browser_view_(browser_view),
       browser_frame_(browser_frame),
       did_gdi_clear_(false) {
@@ -94,6 +93,12 @@
 BrowserDesktopRootWindowHostWin::~BrowserDesktopRootWindowHostWin() {
 }
 
+void BrowserDesktopRootWindowHostWin::SetWindowTransparency() {
+  bool transparent = ShouldUseNativeFrame() && !IsFullscreen();
+  GetRootWindow()->compositor()->SetHostHasTransparentBackground(transparent);
+  GetRootWindow()->SetTransparent(transparent);
+}
+
 views::NativeMenuWin* BrowserDesktopRootWindowHostWin::GetSystemMenu() {
   if (!system_menu_.get()) {
     SystemMenuInsertionDelegateWin insertion_delegate;
@@ -124,6 +129,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopRootWindowHostWin, views::DesktopRootWindowHostWin overrides:
 
+void BrowserDesktopRootWindowHostWin::OnRootWindowCreated(
+    aura::RootWindow* root,
+    const views::Widget::InitParams& params) {
+  DesktopRootWindowHostWin::OnRootWindowCreated(root, params);
+  SetWindowTransparency();
+}
+
 int BrowserDesktopRootWindowHostWin::GetInitialShowState() const {
   STARTUPINFO si = {0};
   si.cb = sizeof(si);
@@ -259,6 +271,12 @@
 void BrowserDesktopRootWindowHostWin::FrameTypeChanged() {
   views::DesktopRootWindowHostWin::FrameTypeChanged();
   did_gdi_clear_ = false;
+  SetWindowTransparency();
+}
+
+void BrowserDesktopRootWindowHostWin::SetFullscreen(bool fullscreen) {
+  DesktopRootWindowHostWin::SetFullscreen(fullscreen);
+  SetWindowTransparency();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -309,6 +327,11 @@
   return margins;
 }
 
+void BrowserDesktopRootWindowHostWin::ToggleFullScreen() {
+  DesktopRootWindowHostWin::ToggleFullScreen();
+  SetWindowTransparency();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopRootWindowHost, public:
 
@@ -317,12 +340,10 @@
     BrowserDesktopRootWindowHost::CreateBrowserDesktopRootWindowHost(
         views::internal::NativeWidgetDelegate* native_widget_delegate,
         views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-        const gfx::Rect& initial_bounds,
         BrowserView* browser_view,
         BrowserFrame* browser_frame) {
   return new BrowserDesktopRootWindowHostWin(native_widget_delegate,
                                              desktop_native_widget_aura,
-                                             initial_bounds,
                                              browser_view,
                                              browser_frame);
 }
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h
index 8510d43..91456f6 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h
@@ -26,20 +26,25 @@
   BrowserDesktopRootWindowHostWin(
       views::internal::NativeWidgetDelegate* native_widget_delegate,
       views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds,
       BrowserView* browser_view,
       BrowserFrame* browser_frame);
   virtual ~BrowserDesktopRootWindowHostWin();
 
  private:
+  void SetWindowTransparency();
+
   views::NativeMenuWin* GetSystemMenu();
 
   // Overridden from BrowserDesktopRootWindowHost:
   virtual DesktopRootWindowHost* AsDesktopRootWindowHost() OVERRIDE;
   virtual int GetMinimizeButtonOffset() const OVERRIDE;
   virtual bool UsesNativeSystemMenu() const OVERRIDE;
+  virtual void ToggleFullScreen() OVERRIDE;
 
   // Overridden from DesktopRootWindowHostWin:
+  virtual void OnRootWindowCreated(
+      aura::RootWindow* root,
+      const views::Widget::InitParams& params) OVERRIDE;
   virtual int GetInitialShowState() const OVERRIDE;
   virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
   virtual void HandleFrameChanged() OVERRIDE;
@@ -53,6 +58,7 @@
   virtual bool IsUsingCustomFrame() const OVERRIDE;
   virtual bool ShouldUseNativeFrame() OVERRIDE;
   virtual void FrameTypeChanged() OVERRIDE;
+  virtual void SetFullscreen(bool fullscreen) OVERRIDE;
 
   void UpdateDWMFrame();
 
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
index b7f3fdb..c5e52ce 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
@@ -10,11 +10,9 @@
 BrowserDesktopRootWindowHostX11::BrowserDesktopRootWindowHostX11(
     views::internal::NativeWidgetDelegate* native_widget_delegate,
     views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds,
     BrowserView* browser_view)
     : DesktopRootWindowHostX11(native_widget_delegate,
-                               desktop_native_widget_aura,
-                               initial_bounds),
+                               desktop_native_widget_aura),
       browser_view_(browser_view) {
 }
 
@@ -42,17 +40,16 @@
 // BrowserDesktopRootWindowHostX11,
 //     views::DesktopRootWindowHostX11 implementation:
 
-aura::RootWindow* BrowserDesktopRootWindowHostX11::Init(
+void BrowserDesktopRootWindowHostX11::Init(
     aura::Window* content_window,
-    const views::Widget::InitParams& params) {
-  aura::RootWindow* root_window = views::DesktopRootWindowHostX11::Init(
-      content_window, params);
+    const views::Widget::InitParams& params,
+    aura::RootWindow::CreateParams* rw_create_params) {
+  views::DesktopRootWindowHostX11::Init(content_window, params,
+                                        rw_create_params);
 
   // We have now created our backing X11 window. We now need to (possibly)
   // alert Unity that there's a menu bar attached to it.
   global_menu_bar_x11_.reset(new GlobalMenuBarX11(browser_view_, this));
-
-  return root_window;
 }
 
 void BrowserDesktopRootWindowHostX11::CloseNow() {
@@ -68,11 +65,9 @@
     BrowserDesktopRootWindowHost::CreateBrowserDesktopRootWindowHost(
         views::internal::NativeWidgetDelegate* native_widget_delegate,
         views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-        const gfx::Rect& initial_bounds,
         BrowserView* browser_view,
         BrowserFrame* browser_frame) {
   return new BrowserDesktopRootWindowHostX11(native_widget_delegate,
                                              desktop_native_widget_aura,
-                                             initial_bounds,
                                              browser_view);
 }
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
index 52aa8d7..b7355c8 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
@@ -23,7 +23,6 @@
   BrowserDesktopRootWindowHostX11(
       views::internal::NativeWidgetDelegate* native_widget_delegate,
       views::DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds,
       BrowserView* browser_view);
   virtual ~BrowserDesktopRootWindowHostX11();
 
@@ -34,9 +33,10 @@
   virtual bool UsesNativeSystemMenu() const OVERRIDE;
 
   // Overridden from views::DesktopRootWindowHostX11:
-  virtual aura::RootWindow* Init(
+  virtual void Init(
       aura::Window* content_window,
-      const views::Widget::InitParams& params) OVERRIDE;
+      const views::Widget::InitParams& params,
+      aura::RootWindow::CreateParams* rw_create_params) OVERRIDE;
   virtual void CloseNow() OVERRIDE;
 
   BrowserView* browser_view_;
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc
index 07f4e33..d457dce 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -5,7 +5,10 @@
 #include "chrome/browser/ui/views/frame/browser_frame_ash.h"
 
 #include "ash/wm/window_state.h"
+#include "ash/wm/window_state_delegate.h"
 #include "ash/wm/window_util.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -14,6 +17,64 @@
 
 using aura::Window;
 
+namespace {
+
+// BrowserWindowStateDelegate classe handles a user's fullscreen
+// request (Shift+F4/F4) for browser (tabbed/popup) windows.
+class BrowserWindowStateDelegate : public ash::wm::WindowStateDelegate {
+ public:
+  explicit BrowserWindowStateDelegate(Browser* browser)
+      : browser_(browser) {
+    DCHECK(browser_);
+  }
+  virtual ~BrowserWindowStateDelegate(){}
+
+  // Overridden from ash::wm::WindowStateDelegate.
+  virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
+    DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
+    // Windows which cannot be maximized should not be fullscreened.
+    if (!window_state->IsFullscreen() && !window_state->CanMaximize())
+      return true;
+    chrome::ToggleFullscreenMode(browser_);
+    return true;
+  }
+ private:
+  Browser* browser_;  // not owned.
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserWindowStateDelegate);
+};
+
+// AppNonClientFrameViewAsh shows only the window controls and no
+// other window decorations which is pretty close to fullscreen. Put
+// v1 apps into maximized mode instead of fullscreen to avoid showing
+// the ugly fullscreen exit bubble.  This is used for V1 apps.
+class AppWindowStateDelegate : public ash::wm::WindowStateDelegate {
+ public:
+  explicit AppWindowStateDelegate(Browser* browser)
+      : browser_(browser) {
+    DCHECK(browser_);
+  }
+  virtual ~AppWindowStateDelegate(){}
+
+  // Overridden from ash::wm::WindowStateDelegate.
+  virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
+    DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
+    if (window_state->IsFullscreen())
+      chrome::ToggleFullscreenMode(browser_);
+    else
+      window_state->ToggleMaximized();
+    return true;
+  }
+
+ private:
+  Browser* browser_;  // not owned.
+
+  DISALLOW_COPY_AND_ASSIGN(AppWindowStateDelegate);
+};
+
+
+}  // namespace
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserFrameAsh::WindowPropertyWatcher
 
@@ -86,22 +147,29 @@
       window_property_watcher_(new WindowPropertyWatcher(this, browser_frame)) {
   GetNativeWindow()->SetName(kWindowName);
   GetNativeWindow()->AddObserver(window_property_watcher_.get());
-  if (browser_view->browser()->is_type_tabbed())
-    ash::wm::SetAnimateToFullscreen(GetNativeWindow(), false);
+  Browser* browser = browser_view->browser();
+  ash::wm::WindowState* window_state =
+      ash::wm::GetWindowState(GetNativeWindow());
+  if (browser->is_app() && browser->app_type() != Browser::APP_TYPE_CHILD) {
+    window_state->SetDelegate(
+        scoped_ptr<ash::wm::WindowStateDelegate>(
+            new AppWindowStateDelegate(browser)).Pass());
+  } else {
+    window_state->SetDelegate(
+        scoped_ptr<ash::wm::WindowStateDelegate>(
+            new BrowserWindowStateDelegate(browser)).Pass());
+  }
+  window_state->set_animate_to_fullscreen(!browser->is_type_tabbed());
 
   // Turn on auto window management if we don't need an explicit bounds.
   // This way the requested bounds are honored.
-  if (!browser_view->browser()->bounds_overridden() &&
-      !browser_view->browser()->is_session_restore())
+  if (!browser->bounds_overridden() && !browser->is_session_restore())
     SetWindowAutoManaged();
 #if defined(OS_CHROMEOS)
   // For legacy reasons v1 apps (like Secure Shell) are allowed to consume keys
   // like brightness, volume, etc. Otherwise these keys are handled by the
   // Ash window manager.
-  if (browser_view->browser()->is_app()) {
-    ash::wm::GetWindowState(GetNativeWindow())->
-        set_can_consume_system_keys(true);
-  }
+  window_state->set_can_consume_system_keys(browser->is_app());
 #endif  // defined(OS_CHROMEOS)
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index dd5e2f6..b1a0b3d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -91,7 +91,7 @@
     avatar = rb.GetImageNamed(browser_view_->GetGuestIconResourceID());
   } else if (browser_view_->IsOffTheRecord()) {
     avatar = rb.GetImageNamed(browser_view_->GetOTRIconResourceID());
-  } else if (AvatarMenu::ShouldShowAvatarMenu()) {
+  } else if (avatar_button_ || AvatarMenu::ShouldShowAvatarMenu()) {
     ProfileInfoCache& cache =
         g_browser_process->profile_manager()->GetProfileInfoCache();
     Profile* profile = browser_view_->browser()->profile();
@@ -103,6 +103,9 @@
     AvatarMenu::GetImageForMenuButton(browser_view_->browser()->profile(),
                                       &avatar,
                                       &is_rectangle);
+    // Disable the menu when we should not show the menu.
+    if (avatar_button_ && !AvatarMenu::ShouldShowAvatarMenu())
+      avatar_button_->SetEnabled(false);
   }
   if (avatar_button_) {
     avatar_button_->SetAvatarIcon(avatar, is_rectangle);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index df32b2d..e9ceab0 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -10,7 +10,6 @@
 #include "ash/wm/header_painter.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/avatar_label.h"
 #include "chrome/browser/ui/views/avatar_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index a38408c..477e728 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -12,9 +12,8 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -97,9 +96,7 @@
   EXPECT_TRUE(frame_view->ShouldPaint());
 
   // No painting should occur in non-immersive fullscreen. (We enter into tab
-  // fullscreen here because tab fullscreen is non-immersive even when
-  // ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) returns
-  // true.
+  // fullscreen here because tab fullscreen is non-immersive even on ChromeOS).
   {
     // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously.
     scoped_ptr<FullscreenNotificationObserver> waiter(
@@ -127,22 +124,18 @@
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) {
-  if (!ImmersiveFullscreenConfiguration::UseImmersiveFullscreen())
-    return;
-
   // We know we're using Views, so static cast.
   BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  content::WebContents* web_contents = browser_view->GetActiveWebContents();
   Widget* widget = browser_view->GetWidget();
   // We know we're using Ash, so static cast.
   BrowserNonClientFrameViewAsh* frame_view =
       static_cast<BrowserNonClientFrameViewAsh*>(
           widget->non_client_view()->frame_view());
 
-  ImmersiveModeControllerAsh* immersive_mode_controller =
-      static_cast<ImmersiveModeControllerAsh*>(
-          browser_view->immersive_mode_controller());
-  immersive_mode_controller->DisableAnimationsForTest();
-  immersive_mode_controller->SetForceHideTabIndicatorsForTest(true);
+  ImmersiveModeController* immersive_mode_controller =
+      browser_view->immersive_mode_controller();
+  immersive_mode_controller->SetupForTest();
 
   // Immersive mode starts disabled.
   ASSERT_FALSE(widget->IsFullscreen());
@@ -151,30 +144,53 @@
   // Frame paints by default.
   EXPECT_TRUE(frame_view->ShouldPaint());
 
-  // Going fullscreen enables immersive mode.
-  chrome::ToggleFullscreenMode(browser());
+  // Enter both browser fullscreen and tab fullscreen. Entering browser
+  // fullscreen should enable immersive fullscreen.
+  {
+    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously.
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    chrome::ToggleFullscreenMode(browser());
+    waiter->Wait();
+  }
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
+        web_contents, true);
+    waiter->Wait();
+  }
   EXPECT_TRUE(immersive_mode_controller->IsEnabled());
 
   // An immersive reveal shows the buttons and the top of the frame.
-  immersive_mode_controller->StartRevealForTest(true);
+  scoped_ptr<ImmersiveRevealedLock> revealed_lock(
+      immersive_mode_controller->GetRevealedLock(
+          ImmersiveModeController::ANIMATE_REVEAL_NO));
   EXPECT_TRUE(immersive_mode_controller->IsRevealed());
   EXPECT_TRUE(frame_view->ShouldPaint());
   EXPECT_TRUE(frame_view->caption_button_container_->visible());
   EXPECT_TRUE(frame_view->UseShortHeader());
   EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle());
 
-  // End the reveal. As the header does not paint a light bar when the
-  // top-of-window views are not revealed, nothing should be painted.
-  immersive_mode_controller->SetMouseHoveredForTest(false);
+  // End the reveal. When in both immersive browser fullscreen and tab
+  // fullscreen, the tab lightbars should not be painted.
+  revealed_lock.reset();
   EXPECT_FALSE(immersive_mode_controller->IsRevealed());
   EXPECT_FALSE(frame_view->ShouldPaint());
 
-  // Repeat test but with the tab light bar visible when the top-of-window views
-  // are not revealed.
-  immersive_mode_controller->SetForceHideTabIndicatorsForTest(false);
+  // Repeat test but without tab fullscreen. The tab lightbars should now show
+  // when the top-of-window views are not revealed.
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
+        web_contents, false);
+    waiter->Wait();
+  }
 
   // Immersive reveal should have same behavior as before.
-  immersive_mode_controller->StartRevealForTest(true);
+  revealed_lock.reset(immersive_mode_controller->GetRevealedLock(
+      ImmersiveModeController::ANIMATE_REVEAL_NO));
   EXPECT_TRUE(immersive_mode_controller->IsRevealed());
   EXPECT_TRUE(frame_view->ShouldPaint());
   EXPECT_TRUE(frame_view->caption_button_container_->visible());
@@ -183,17 +199,21 @@
 
   // Ending the reveal should hide the caption buttons and the header should
   // be in the lightbar style.
-  immersive_mode_controller->SetMouseHoveredForTest(false);
+  revealed_lock.reset();
   EXPECT_TRUE(frame_view->ShouldPaint());
   EXPECT_FALSE(frame_view->caption_button_container_->visible());
   EXPECT_TRUE(frame_view->UseShortHeader());
   EXPECT_TRUE(frame_view->UseImmersiveLightbarHeaderStyle());
 
-  // Exiting fullscreen exits immersive mode.
-  browser_view->ExitFullscreen();
+  // Exiting immersive fullscreen should make the caption buttons and the frame
+  // visible again.
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    browser_view->ExitFullscreen();
+    waiter->Wait();
+  }
   EXPECT_FALSE(immersive_mode_controller->IsEnabled());
-
-  // Exiting immersive mode makes controls and frame visible again.
   EXPECT_TRUE(frame_view->ShouldPaint());
   EXPECT_TRUE(frame_view->caption_button_container_->visible());
   EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle());
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index c4fec8a..d79a619 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/speech/tts_controller.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
@@ -46,7 +47,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window_state.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/ntp_background_util.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
@@ -83,6 +83,7 @@
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/toolbar_view.h"
+#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
 #include "chrome/browser/ui/views/update_recommended_message_box.h"
 #include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h"
 #include "chrome/browser/ui/window_sizer/window_sizer.h"
@@ -155,6 +156,10 @@
 #include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/ash/multi_user_window_manager.h"
+#endif
+
 using base::TimeDelta;
 using content::NativeWebKeyboardEvent;
 using content::SSLStatus;
@@ -399,7 +404,7 @@
       devtools_dock_side_(DEVTOOLS_DOCK_SIDE_BOTTOM),
       devtools_window_(NULL),
       initialized_(false),
-      ignore_layout_(true),
+      in_process_fullscreen_(false),
 #if defined(OS_WIN) && !defined(USE_AURA)
       hung_window_detector_(&hung_plugin_action_),
       ticker_(0),
@@ -574,6 +579,28 @@
 #if defined(OS_CHROMEOS)
   if (IsOffTheRecord() && !IsGuestSession())
     return true;
+
+  // Note: In case of the M-31 mode the window manager won't exist.
+  chrome::MultiUserWindowManager* window_manager =
+      chrome::MultiUserWindowManager::GetInstance();
+  if (window_manager) {
+    // This function is called via BrowserNonClientFrameView::UpdateAvatarInfo
+    // during the creation of the BrowserWindow, so browser->window() will not
+    // yet be set. In this case we can safely return false.
+    if (!browser_->window())
+      return false;
+
+    // If the window is shown on a different desktop than the user, it should
+    // have the avatar icon.
+    aura::Window* window = browser_->window()->GetNativeWindow();
+
+    // Note: When the window manager the window is either on it's owners desktop
+    // (and shows no icon) or it is now (in which it will show an icon). So we
+    // can return here.
+    return !window_manager->IsWindowOnDesktopOfUser(
+        window,
+        window_manager->GetWindowOwner(window));
+  }
 #else
   if (IsOffTheRecord())  // Desktop guest is incognito and needs avatar.
     return true;
@@ -1153,6 +1180,18 @@
   GetLocationBarView()->ShowBookmarkPrompt();
 }
 
+void BrowserView::ShowTranslateBubble(
+    content::WebContents* web_contents,
+    TranslateBubbleModel::ViewState view_state) {
+  TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(web_contents);
+  LanguageState& language_state = translate_tab_helper->language_state();
+  language_state.SetTranslateEnabled(true);
+
+  TranslateBubbleView::ShowBubble(GetToolbarView()->GetTranslateBubbleAnchor(),
+                                  web_contents, view_state, browser_.get());
+}
+
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
 void BrowserView::ShowOneClickSigninBubble(
     OneClickSigninBubbleType type,
@@ -1765,7 +1804,7 @@
 }
 
 void BrowserView::Layout() {
-  if (ignore_layout_)
+  if (!initialized_ || in_process_fullscreen_)
     return;
 
   views::View::Layout();
@@ -1841,10 +1880,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserView, ImmersiveModeController::Delegate overrides:
 
-BookmarkBarView* BrowserView::GetBookmarkBar() {
-  return bookmark_bar_view_.get();
-}
-
 FullscreenController* BrowserView::GetFullscreenController() {
   // Cannot be injected into ImmersiveModeController because it is constructed
   // after BrowserView.
@@ -2013,9 +2048,6 @@
 
   GetLocationBar()->GetLocationEntry()->model()->popup_model()->AddObserver(
       this);
-
-  // We're now initialized and ready to process Layout requests.
-  ignore_layout_ = false;
 }
 
 void BrowserView::LoadingAnimationCallback() {
@@ -2250,11 +2282,14 @@
                                     FullscreenType type,
                                     const GURL& url,
                                     FullscreenExitBubbleType bubble_type) {
+  if (in_process_fullscreen_)
+    return;
+  in_process_fullscreen_ = true;
+
   // Reduce jankiness during the following position changes by:
   //   * Hiding the window until it's in the final position
   //   * Ignoring all intervening Layout() calls, which resize the webpage and
-  //     thus are slow and look ugly
-  ignore_layout_ = true;
+  //     thus are slow and look ugly (enforced via |in_process_fullscreen_|).
   LocationBarView* location_bar = GetLocationBarView();
 #if defined(OS_WIN) && !defined(USE_AURA)
   OmniboxViewWin* omnibox_win =
@@ -2325,15 +2360,22 @@
   // recompute the height of the infobar top arrow because toggling in and out
   // of fullscreen changes it. Calling ToolbarSizeChanged() will do both these
   // things since it computes the arrow height directly and forces a layout
-  // indirectly via UpdateUIForContents().
-  ignore_layout_ = false;
+  // indirectly via UpdateUIForContents(). Reset |in_process_fullscreen_| in
+  // order to let the layout occur.
+  in_process_fullscreen_ = false;
   ToolbarSizeChanged(false);
 }
 
 bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
+#if defined(OS_CHROMEOS)
+  // Kiosk mode needs the whole screen.
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
+    return false;
   bool is_browser_fullscreen = url.is_empty();
-  return ImmersiveFullscreenConfiguration::UseImmersiveFullscreen() &&
-      is_browser_fullscreen && IsBrowserTypeNormal();
+  return is_browser_fullscreen && IsBrowserTypeNormal();
+#else
+  return false;
+#endif
 }
 
 void BrowserView::LoadAccelerators() {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 82bc6b3..2d35817 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -325,6 +325,9 @@
   virtual void ShowBookmarkBubble(const GURL& url,
                                   bool already_bookmarked) OVERRIDE;
   virtual void ShowBookmarkPrompt() OVERRIDE;
+  virtual void ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) OVERRIDE;
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
   virtual void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
@@ -424,7 +427,6 @@
   virtual gfx::Size GetMinimumSize() OVERRIDE;
 
   // ImmersiveModeController::Delegate overrides:
-  virtual BookmarkBarView* GetBookmarkBar() OVERRIDE;
   virtual FullscreenController* GetFullscreenController() OVERRIDE;
   virtual void FullscreenStateChanged() OVERRIDE;
   virtual void SetImmersiveStyle(bool immersive) OVERRIDE;
@@ -702,9 +704,10 @@
   // True if we have already been initialized.
   bool initialized_;
 
-  // True if we should ignore requests to layout.  This is set while toggling
-  // fullscreen mode on and off to reduce jankiness.
-  bool ignore_layout_;
+  // True when in ProcessFullscreen(). The flag is used to avoid reentrance and
+  // to ignore requests to layout while in ProcessFullscreen() to reduce
+  // jankiness.
+  bool in_process_fullscreen_;
 
   scoped_ptr<FullscreenExitBubbleViews> fullscreen_bubble_;
 
diff --git a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
index e225c63..5c026fc 100644
--- a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
index 09226ba..90f3cd3 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
@@ -116,6 +116,7 @@
       AnimateReveal animate_reveal) OVERRIDE WARN_UNUSED_RESULT { return NULL; }
   virtual void OnFindBarVisibleBoundsChanged(
       const gfx::Rect& new_visible_bounds) OVERRIDE {}
+  virtual void SetupForTest() OVERRIDE {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockImmersiveModeController);
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc
index 83c184d..7004782 100644
--- a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc
+++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc
@@ -56,7 +56,6 @@
       BrowserDesktopRootWindowHost::CreateBrowserDesktopRootWindowHost(
           browser_frame_,
           this,
-          params.bounds,
           browser_view_,
           browser_frame_);
   views::Widget::InitParams modified_params = params;
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 1d191ad..58f112b 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -114,8 +114,10 @@
 
   // The new avatar button is optionally displayed to the left of the
   // minimize button.
-  if (browser_view()->ShouldShowAvatar() && new_avatar_button())
+  if (new_avatar_button()) {
+    DCHECK(profiles::IsNewProfileManagementEnabled());
     minimize_button_offset -= new_avatar_button()->width();
+  }
 
   int tabstrip_x = browser_view()->ShouldShowAvatar() ?
       (avatar_bounds_.right() + kAvatarRightSpacing) :
@@ -128,6 +130,10 @@
   if (base::i18n::IsRTL()) {
     if (!browser_view()->ShouldShowAvatar() && frame()->IsMaximized())
       tabstrip_x += avatar_bounds_.x();
+    else if (browser_view()->IsRegularOrGuestSession() &&
+        profiles::IsNewProfileManagementEnabled())
+      tabstrip_x = width() - minimize_button_offset;
+
     minimize_button_offset = width();
   }
   int tabstrip_width = minimize_button_offset - tabstrip_x -
@@ -263,13 +269,11 @@
 }
 
 void GlassBrowserFrameView::Layout() {
-  if (browser_view()->ShouldShowAvatar()) {
-    if (browser_view()->IsRegularOrGuestSession() &&
-        profiles::IsNewProfileManagementEnabled())
-      LayoutNewStyleAvatar();
-    else
-      LayoutAvatar();
-  }
+  if (browser_view()->IsRegularOrGuestSession() &&
+      profiles::IsNewProfileManagementEnabled())
+    LayoutNewStyleAvatar();
+  else
+    LayoutAvatar();
 
   LayoutClientView();
 }
@@ -441,6 +445,7 @@
 }
 
 void GlassBrowserFrameView::LayoutNewStyleAvatar() {
+  DCHECK(profiles::IsNewProfileManagementEnabled());
   if (!new_avatar_button())
     return;
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h
index f4a504b..3810a24 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h
@@ -59,9 +59,6 @@
 
   class Delegate {
    public:
-    // Returns the bookmark bar, or NULL if the window does not support one.
-    virtual BookmarkBarView* GetBookmarkBar() = 0;
-
     // Returns the browser's FullscreenController.
     virtual FullscreenController* GetFullscreenController() = 0;
 
@@ -129,6 +126,11 @@
   virtual void OnFindBarVisibleBoundsChanged(
       const gfx::Rect& new_visible_bounds_in_screen) = 0;
 
+  // Disables animations and moves the mouse so that it is not over the
+  // top-of-window views for the sake of testing. Must be called before
+  // enabling immersive fullscreen.
+  virtual void SetupForTest() = 0;
+
   virtual void AddObserver(Observer* observer);
   virtual void RemoveObserver(Observer* observer);
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index ed83008..ea8475b 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -7,13 +7,10 @@
 #include <set>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/shell.h"
-#include "ash/wm/window_properties.h"
-#include "base/command_line.h"
+#include "ash/wm/window_state.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "content/public/browser/notification_service.h"
@@ -48,6 +45,15 @@
 const int kRevealSlowAnimationDurationMs = 400;
 const int kRevealFastAnimationDurationMs = 200;
 
+// The delay in milliseconds between the mouse stopping at the top edge of the
+// screen and the top-of-window views revealing.
+const int kMouseRevealDelayMs = 200;
+
+// The maximum amount of pixels that the cursor can move for the cursor to be
+// considered "stopped". This allows the user to reveal the top-of-window views
+// without holding the cursor completely still.
+const int kMouseRevealXThresholdPixels = 3;
+
 // How many pixels a gesture can start away from |top_container_| when in
 // closed state and still be considered near it. This is needed to overcome
 // issues with poor location values near the edge of the display.
@@ -71,19 +77,6 @@
 // above/below secondary display).
 const int kMouseRevealBoundsHeight = 3;
 
-// If |hovered| is true, moves the mouse above |view|. Moves it outside of
-// |view| otherwise.
-// Should not be called outside of tests.
-void MoveMouse(views::View* view, bool hovered) {
-  gfx::Point cursor_pos;
-  if (!hovered) {
-    int bottom_edge = view->bounds().bottom();
-    cursor_pos = gfx::Point(0, bottom_edge + 100);
-  }
-  views::View::ConvertPointToScreen(view, &cursor_pos);
-  aura::Env::GetInstance()->set_last_mouse_location(cursor_pos);
-}
-
 // Returns the BubbleDelegateView corresponding to |maybe_bubble| if
 // |maybe_bubble| is a bubble.
 views::BubbleDelegateView* AsBubbleDelegate(aura::Window* maybe_bubble) {
@@ -300,11 +293,6 @@
   }
 }
 
-void ImmersiveModeControllerAsh::MaybeExitImmersiveFullscreen() {
-  if (ShouldExitImmersiveFullscreen())
-    delegate_->FullscreenStateChanged();
-}
-
 void ImmersiveModeControllerAsh::Init(
     Delegate* delegate,
     views::Widget* widget,
@@ -315,12 +303,6 @@
   // window pointer so |this| can stop observing during destruction.
   native_window_ = widget_->GetNativeWindow();
   top_container_ = top_container;
-
-  // Optionally allow the tab indicators to be hidden.
-  if (CommandLine::ForCurrentProcess()->
-          HasSwitch(ash::switches::kAshImmersiveHideTabIndicators)) {
-    tab_indicator_visibility_ = TAB_INDICATORS_FORCE_HIDE;
-  }
 }
 
 void ImmersiveModeControllerAsh::SetEnabled(bool enabled) {
@@ -361,7 +343,7 @@
     top_edge_hover_timer_.Stop();
     // Snap immediately to the closed state.
     reveal_state_ = CLOSED;
-    EnablePaintToLayer(false);
+    top_container_->SetPaintToLayer(false);
     delegate_->SetImmersiveStyle(false);
     SetRenderWindowTopInsetsForTouch(0);
 
@@ -406,6 +388,18 @@
   find_bar_visible_bounds_in_screen_ = new_visible_bounds_in_screen;
 }
 
+void ImmersiveModeControllerAsh::SetupForTest() {
+  DCHECK(!enabled_);
+  animations_disabled_for_test_ = true;
+
+  // Move the mouse off of the top-of-window views so that it does not keep
+  // the top-of-window views revealed.
+  gfx::Point cursor_pos(0, top_container_->bounds().bottom() + 100);
+  views::View::ConvertPointToScreen(top_container_, &cursor_pos);
+  aura::Env::GetInstance()->set_last_mouse_location(cursor_pos);
+  UpdateLocatedEventRevealedLock(NULL, ALLOW_REVEAL_WHILE_CLOSING_NO);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Observers:
 
@@ -551,6 +545,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // aura::WindowObserver overrides:
+
 void ImmersiveModeControllerAsh::OnWindowPropertyChanged(aura::Window* window,
                                                          const void* key,
                                                          intptr_t old) {
@@ -561,23 +556,11 @@
     // Disable immersive mode when the user exits fullscreen without going
     // through FullscreenController::ToggleFullscreenMode(). This is the case
     // if the user exits fullscreen via the restore button.
-    if (ShouldExitImmersiveFullscreen()) {
-      // Other "property change" observers may want to animate between the
-      // current visuals and the new window state. Do not alter the current
-      // visuals yet and post a task to exit immersive fullscreen instead.
-      base::MessageLoopForUI::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&ImmersiveModeControllerAsh::MaybeExitImmersiveFullscreen,
-                     weak_ptr_factory_.GetWeakPtr()));
-    }
-
-    ui::WindowShowState show_state = native_window_->GetProperty(
-        aura::client::kShowStateKey);
-    if (show_state == ui::SHOW_STATE_FULLSCREEN &&
-        old == ui::SHOW_STATE_MINIMIZED) {
-      // Relayout in case there was a layout while the window show state was
-      // ui::SHOW_STATE_MINIMIZED.
-      LayoutBrowserRootView();
+    ui::WindowShowState show_state = static_cast<ui::WindowShowState>(
+        native_window_->GetProperty(aura::client::kShowStateKey));
+    if (show_state != ui::SHOW_STATE_FULLSCREEN &&
+        show_state != ui::SHOW_STATE_MINIMIZED) {
+      delegate_->FullscreenStateChanged();
     }
   }
 }
@@ -602,32 +585,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Testing interface:
-
-void ImmersiveModeControllerAsh::SetForceHideTabIndicatorsForTest(bool force) {
-  if (force)
-    tab_indicator_visibility_ = TAB_INDICATORS_FORCE_HIDE;
-  else if (tab_indicator_visibility_ == TAB_INDICATORS_FORCE_HIDE)
-    tab_indicator_visibility_ = TAB_INDICATORS_HIDE;
-  UpdateUseMinimalChrome(LAYOUT_YES);
-}
-
-void ImmersiveModeControllerAsh::StartRevealForTest(bool hovered) {
-  MaybeStartReveal(ANIMATE_NO);
-  MoveMouse(top_container_, hovered);
-  UpdateLocatedEventRevealedLock(NULL, ALLOW_REVEAL_WHILE_CLOSING_NO);
-}
-
-void ImmersiveModeControllerAsh::SetMouseHoveredForTest(bool hovered) {
-  MoveMouse(top_container_, hovered);
-  UpdateLocatedEventRevealedLock(NULL, ALLOW_REVEAL_WHILE_CLOSING_NO);
-}
-
-void ImmersiveModeControllerAsh::DisableAnimationsForTest() {
-  animations_disabled_for_test_ = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // private:
 
 void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) {
@@ -721,8 +678,7 @@
   // |hit_bounds_in_screen| is short.)
   if (top_edge_hover_timer_.IsRunning() &&
       abs(location_in_screen.x() - mouse_x_when_hit_top_in_screen_) <=
-          ImmersiveFullscreenConfiguration::
-              immersive_mode_reveal_x_threshold_pixels())
+          kMouseRevealXThresholdPixels)
     return;
 
   // Start the reveal if the cursor doesn't move for some amount of time.
@@ -731,8 +687,7 @@
   // Timer is stopped when |this| is destroyed, hence Unretained() is safe.
   top_edge_hover_timer_.Start(
       FROM_HERE,
-      base::TimeDelta::FromMilliseconds(
-          ImmersiveFullscreenConfiguration::immersive_mode_reveal_delay_ms()),
+      base::TimeDelta::FromMilliseconds(kMouseRevealDelayMs),
       base::Bind(&ImmersiveModeControllerAsh::AcquireLocatedEventRevealedLock,
                  base::Unretained(this)));
 }
@@ -908,8 +863,12 @@
   bool in_tab_fullscreen = fullscreen_controller ?
       fullscreen_controller->IsFullscreenForTabOrPending() : false;
   bool use_minimal_chrome = !in_tab_fullscreen && enabled_;
-  native_window_->SetProperty(ash::internal::kFullscreenUsesMinimalChromeKey,
-                              use_minimal_chrome);
+
+  // When using minimal chrome, the shelf is auto-hidden. The auto-hidden shelf
+  // displays a 3px 'light bar' when it is closed. Otherwise, the shelf is
+  // hidden completely and cannot be revealed.
+  ash::wm::GetWindowState(native_window_)->set_hide_shelf_when_fullscreen(
+      !use_minimal_chrome);
 
   TabIndicatorVisibility previous_tab_indicator_visibility =
       tab_indicator_visibility_;
@@ -918,12 +877,7 @@
         TAB_INDICATORS_SHOW : TAB_INDICATORS_HIDE;
   }
 
-  // Ash on Windows may not have a shell.
-  if (ash::Shell::HasInstance()) {
-    // When using minimal chrome, the shelf is auto-hidden. The auto-hidden
-    // shelf displays a 3px 'light bar' when it is closed.
-    ash::Shell::GetInstance()->UpdateShelfVisibility();
-  }
+  ash::Shell::GetInstance()->UpdateShelfVisibility();
 
   if (tab_indicator_visibility_ != previous_tab_indicator_visibility) {
     // If the top-of-window views are revealed or animating, the change will
@@ -964,7 +918,7 @@
   reveal_state_ = SLIDING_OPEN;
   if (previous_reveal_state == CLOSED) {
     // Turn on layer painting so that we can overlap the web contents.
-    EnablePaintToLayer(true);
+    top_container_->SetPaintToLayer(true);
 
     // Ensure window caption buttons are updated and the view bounds are
     // computed at normal (non-immersive-style) size. The layout call moves the
@@ -995,25 +949,6 @@
      FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted());
 }
 
-void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) {
-  top_container_->SetPaintToLayer(enable);
-
-  // Views software compositing is not fully layer aware. If the bookmark bar
-  // is detached while the top container layer slides on or off the screen,
-  // the pixels that become exposed are the remnants of the last software
-  // composite of the BrowserView, not the freshly-exposed bookmark bar.
-  // Force the bookmark bar to paint to a layer so the views composite
-  // properly. The infobar container does not need this treatment because
-  // BrowserView::PaintChildren() always draws it last when it is visible.
-  BookmarkBarView* bookmark_bar = delegate_->GetBookmarkBar();
-  if (!bookmark_bar)
-    return;
-  if (enable && bookmark_bar->IsDetached())
-    bookmark_bar->SetPaintToLayer(true);
-  else
-    bookmark_bar->SetPaintToLayer(false);
-}
-
 void ImmersiveModeControllerAsh::LayoutBrowserRootView() {
   // Update the window caption buttons.
   widget_->non_client_view()->frame_view()->ResetWindowControls();
@@ -1050,10 +985,6 @@
   reveal_state_ = SLIDING_CLOSED;
   int duration_ms = GetAnimationDuration(animate);
   if (duration_ms > 0) {
-    // The bookmark bar may have become detached during the reveal so ensure
-    // layers are available. This is a no-op for the top container.
-    EnablePaintToLayer(true);
-
     animation_->SetSlideDuration(duration_ms);
     animation_->Hide();
   } else {
@@ -1066,24 +997,13 @@
   DCHECK_EQ(SLIDING_CLOSED, reveal_state_);
   reveal_state_ = CLOSED;
   // Layers aren't needed after animation completes.
-  EnablePaintToLayer(false);
+  top_container_->SetPaintToLayer(false);
   // Update tabstrip for closed state.
   delegate_->SetImmersiveStyle(true);
   SetRenderWindowTopInsetsForTouch(kNearTopContainerDistance);
   LayoutBrowserRootView();
 }
 
-bool ImmersiveModeControllerAsh::ShouldExitImmersiveFullscreen() const {
-  if (!native_window_)
-    return false;
-
-  ui::WindowShowState show_state = static_cast<ui::WindowShowState>(
-      native_window_->GetProperty(aura::client::kShowStateKey));
-  return IsEnabled() &&
-      show_state != ui::SHOW_STATE_FULLSCREEN &&
-      show_state != ui::SHOW_STATE_MINIMIZED;
-}
-
 ImmersiveModeControllerAsh::SwipeType ImmersiveModeControllerAsh::GetSwipeType(
     ui::GestureEvent* event) const {
   if (event->type() != ui::ET_GESTURE_SCROLL_UPDATE)
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
index a1f90cb..8255e11 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -56,9 +56,6 @@
   void LockRevealedState(AnimateReveal animate_reveal);
   void UnlockRevealedState();
 
-  // Exits immersive fullscreen based on |native_window_|'s show state.
-  void MaybeExitImmersiveFullscreen();
-
   // ImmersiveModeController overrides:
   virtual void Init(Delegate* delegate,
                     views::Widget* widget,
@@ -74,6 +71,7 @@
       AnimateReveal animate_reveal) OVERRIDE WARN_UNUSED_RESULT;
   virtual void OnFindBarVisibleBoundsChanged(
       const gfx::Rect& new_visible_bounds_in_screen) OVERRIDE;
+  virtual void SetupForTest() OVERRIDE;
 
   // content::NotificationObserver override:
   virtual void Observe(int type,
@@ -109,12 +107,6 @@
   virtual void OnRemoveTransientChild(aura::Window* window,
                                       aura::Window* transient) OVERRIDE;
 
-  // Testing interface.
-  void SetForceHideTabIndicatorsForTest(bool force);
-  void StartRevealForTest(bool hovered);
-  void SetMouseHoveredForTest(bool hovered);
-  void DisableAnimationsForTest();
-
  private:
   friend class ImmersiveModeControllerAshTest;
 
@@ -192,9 +184,6 @@
   // is not ANIMATE_NO, slides in the view, otherwise shows it immediately.
   void MaybeStartReveal(Animate animate);
 
-  // Enables or disables layer-based painting to allow smooth animations.
-  void EnablePaintToLayer(bool enable);
-
   // Updates the browser root view's layout including window caption controls.
   void LayoutBrowserRootView();
 
@@ -210,13 +199,6 @@
   // completed.
   void OnSlideClosedAnimationCompleted();
 
-  // Returns whether immersive fullscreen should be exited based on
-  // |native_window_|'s show state. This handles cases where the user has
-  // exited immersive fullscreen without going through
-  // FullscreenController::ToggleFullscreenMode(). This is the case if the
-  // user exits fullscreen via the restore button.
-  bool ShouldExitImmersiveFullscreen() const;
-
   // Returns the type of swipe given |event|.
   SwipeType GetSwipeType(ui::GestureEvent* event) const;
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index 1ab0c85..68ea422 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -2,40 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 
-#include "ash/ash_switches.h"
-#include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_types.h"
-#include "ash/shell.h"
-#include "ash/wm/window_properties.h"
-#include "ash/wm/window_util.h"
-#include "base/command_line.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
-#include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/top_container_view.h"
-#include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
-#include "content/public/test/test_utils.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_animation_duration_scale_mode.h"
-#include "ui/events/event.h"
-#include "ui/gfx/rect.h"
-#include "ui/views/view.h"
-
-using ui::ScopedAnimationDurationScaleMode;
+#include "ui/aura/window.h"
 
 namespace {
 
@@ -56,239 +31,22 @@
   virtual ~ImmersiveModeControllerAshTest() {}
 
   BrowserView* browser_view() { return browser_view_; }
-  ImmersiveModeControllerAsh* controller() { return controller_; }
+  ImmersiveModeController* controller() { return controller_; }
 
   // content::BrowserTestBase overrides:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-  }
-
   virtual void SetUpOnMainThread() OVERRIDE {
-    ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
     browser_view_ = static_cast<BrowserView*>(browser()->window());
-    controller_ = static_cast<ImmersiveModeControllerAsh*>(
-        browser_view_->immersive_mode_controller());
-    controller_->DisableAnimationsForTest();
-    zero_duration_mode_.reset(new ScopedAnimationDurationScaleMode(
-        ScopedAnimationDurationScaleMode::ZERO_DURATION));
-  }
-
-  virtual void CleanUpOnMainThread() OVERRIDE {
-    zero_duration_mode_.reset();
+    controller_ = browser_view_->immersive_mode_controller();
+    controller_->SetupForTest();
   }
 
  private:
   BrowserView* browser_view_;
-  ImmersiveModeControllerAsh* controller_;
-  scoped_ptr<ScopedAnimationDurationScaleMode> zero_duration_mode_;
+  ImmersiveModeController* controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAshTest);
 };
 
-// Test behavior when the mouse becomes hovered without moving.
-IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest,
-                       MouseHoveredWithoutMoving) {
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_TRUE(controller()->IsEnabled());
-
-  scoped_ptr<ImmersiveRevealedLock> lock;
-
-  // 1) Test that if the mouse becomes hovered without the mouse moving due to a
-  // lock causing the top-of-window views to be revealed (and the mouse
-  // happening to be near the top of the screen), the top-of-window views do not
-  // hide till the mouse moves off of the top-of-window views.
-  controller()->SetMouseHoveredForTest(true);
-  EXPECT_FALSE(controller()->IsRevealed());
-  lock.reset(controller()->GetRevealedLock(
-      ImmersiveModeController::ANIMATE_REVEAL_NO));
-  EXPECT_TRUE(controller()->IsRevealed());
-  lock.reset();
-  EXPECT_TRUE(controller()->IsRevealed());
-  controller()->SetMouseHoveredForTest(false);
-  EXPECT_FALSE(controller()->IsRevealed());
-
-  // 2) Test that if the mouse becomes hovered without moving because of a
-  // reveal in ImmersiveModeController::SetEnabled(true) and there are no locks
-  // keeping the top-of-window views revealed, that mouse hover does not prevent
-  // the top-of-window views from closing.
-  chrome::ToggleFullscreenMode(browser());
-  controller()->SetMouseHoveredForTest(true);
-  EXPECT_FALSE(controller()->IsRevealed());
-  chrome::ToggleFullscreenMode(browser());
-  EXPECT_FALSE(controller()->IsRevealed());
-
-  // 3) Test that if the mouse becomes hovered without moving because of a
-  // reveal in ImmersiveModeController::SetEnabled(true) and there is a lock
-  // keeping the top-of-window views revealed, that the top-of-window views do
-  // not hide till the mouse moves off of the top-of-window views.
-  chrome::ToggleFullscreenMode(browser());
-  controller()->SetMouseHoveredForTest(true);
-  lock.reset(controller()->GetRevealedLock(
-      ImmersiveModeController::ANIMATE_REVEAL_NO));
-  EXPECT_FALSE(controller()->IsRevealed());
-  chrome::ToggleFullscreenMode(browser());
-  EXPECT_TRUE(controller()->IsRevealed());
-  lock.reset();
-  EXPECT_TRUE(controller()->IsRevealed());
-  controller()->SetMouseHoveredForTest(false);
-  EXPECT_FALSE(controller()->IsRevealed());
-}
-
-// GetRevealedLock() specific tests.
-IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest, RevealedLock) {
-  scoped_ptr<ImmersiveRevealedLock> lock1;
-  scoped_ptr<ImmersiveRevealedLock> lock2;
-
-  // Immersive mode is not on by default.
-  EXPECT_FALSE(controller()->IsEnabled());
-
-  // Move the mouse out of the way.
-  controller()->SetMouseHoveredForTest(false);
-
-  // 1) Test acquiring and releasing a revealed state lock while immersive mode
-  // is disabled. Acquiring or releasing the lock should have no effect till
-  // immersive mode is enabled.
-  lock1.reset(controller()->GetRevealedLock(
-      ImmersiveModeController::ANIMATE_REVEAL_NO));
-  EXPECT_FALSE(controller()->IsEnabled());
-  EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_FALSE(controller()->ShouldHideTopViews());
-
-  // Immersive mode should start in the revealed state due to the lock.
-  chrome::ToggleFullscreenMode(browser());
-  EXPECT_TRUE(controller()->IsEnabled());
-  EXPECT_TRUE(controller()->IsRevealed());
-  EXPECT_FALSE(controller()->ShouldHideTopViews());
-
-  chrome::ToggleFullscreenMode(browser());
-  EXPECT_FALSE(controller()->IsEnabled());
-  EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_FALSE(controller()->ShouldHideTopViews());
-
-  lock1.reset();
-  EXPECT_FALSE(controller()->IsEnabled());
-  EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_FALSE(controller()->ShouldHideTopViews());
-
-  // Immersive mode should start in the closed state because the lock is no
-  // longer held.
-  chrome::ToggleFullscreenMode(browser());
-  EXPECT_TRUE(controller()->IsEnabled());
-  EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_TRUE(controller()->ShouldHideTopViews());
-
-  // 2) Test that acquiring a revealed state lock reveals the top-of-window
-  // views if they are hidden.
-  EXPECT_FALSE(controller()->IsRevealed());
-  lock1.reset(controller()->GetRevealedLock(
-      ImmersiveModeController::ANIMATE_REVEAL_NO));
-  EXPECT_TRUE(controller()->IsRevealed());
-
-  // 3) Test that the top-of-window views are only hidden when all of the locks
-  // are released.
-  lock2.reset(controller()->GetRevealedLock(
-      ImmersiveModeController::ANIMATE_REVEAL_NO));
-  lock1.reset();
-  EXPECT_TRUE(controller()->IsRevealed());
-
-  lock2.reset();
-  EXPECT_FALSE(controller()->IsRevealed());
-}
-
-// Shelf-specific immersive mode tests.
-IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest, ImmersiveShelf) {
-  // Shelf is visible when the test starts.
-  ash::internal::ShelfLayoutManager* shelf =
-      ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
-  ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
-
-  // Turning immersive mode on sets the shelf to auto-hide.
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_TRUE(browser_view()->IsFullscreen());
-  ASSERT_TRUE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-
-  // Disabling immersive mode puts it back.
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_FALSE(browser_view()->IsFullscreen());
-  ASSERT_FALSE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
-
-  // The user could toggle the launcher behavior.
-  shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-
-  // Enabling immersive mode keeps auto-hide.
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_TRUE(browser_view()->IsFullscreen());
-  ASSERT_TRUE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-
-  // Disabling immersive mode maintains the user's auto-hide selection.
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_FALSE(browser_view()->IsFullscreen());
-  ASSERT_FALSE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-}
-
-// Test how being simultaneously in tab fullscreen and immersive fullscreen
-// affects the shelf visibility and whether the tab indicators are hidden.
-IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest,
-                       TabAndBrowserFullscreen) {
-  ash::internal::ShelfLayoutManager* shelf =
-      ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
-
-  controller()->SetForceHideTabIndicatorsForTest(false);
-
-  // The shelf should start out as visible.
-  ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
-
-  // 1) Test that entering tab fullscreen from immersive mode hides the tab
-  // indicators and the shelf.
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_TRUE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-  EXPECT_FALSE(controller()->ShouldHideTabIndicators());
-
-  // The shelf visibility and the tab indicator visibility are updated as a
-  // result of NOTIFICATION_FULLSCREEN_CHANGED which is asynchronous. Wait for
-  // the notification before testing visibility.
-  scoped_ptr<FullscreenNotificationObserver> waiter(
-      new FullscreenNotificationObserver());
-
-  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
-      browser_view()->GetActiveWebContents(), true);
-  waiter->Wait();
-  ASSERT_TRUE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_HIDDEN, shelf->visibility_state());
-  EXPECT_TRUE(controller()->ShouldHideTabIndicators());
-
-  // 2) Test that exiting tab fullscreen shows the tab indicators and autohides
-  // the shelf.
-  waiter.reset(new FullscreenNotificationObserver());
-  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
-      browser_view()->GetActiveWebContents(), false);
-  waiter->Wait();
-  ASSERT_TRUE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
-  EXPECT_FALSE(controller()->ShouldHideTabIndicators());
-
-  // 3) Test that exiting tab fullscreen and immersive fullscreen
-  // simultaneously correctly updates the shelf visibility and whether the tab
-  // indicators should be hidden.
-  waiter.reset(new FullscreenNotificationObserver());
-  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
-      browser_view()->GetActiveWebContents(), true);
-  waiter->Wait();
-  waiter.reset(new FullscreenNotificationObserver());
-  chrome::ToggleFullscreenMode(browser());
-  waiter->Wait();
-
-  ASSERT_FALSE(controller()->IsEnabled());
-  EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
-  EXPECT_TRUE(controller()->ShouldHideTabIndicators());
-}
-
 // Validate top container touch insets are being updated at the correct time in
 // immersive mode.
 IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest,
@@ -301,17 +59,21 @@
   chrome::ToggleFullscreenMode(browser());
   ASSERT_TRUE(browser_view()->IsFullscreen());
   ASSERT_TRUE(controller()->IsEnabled());
+  ASSERT_FALSE(controller()->IsRevealed());
   EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() > 0);
 
   // Trigger a reveal resets insets as now the touch target for the top
   // container is large enough.
-  controller()->StartRevealForTest(true);
+  scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
+      ImmersiveModeController::ANIMATE_REVEAL_NO));
+  EXPECT_TRUE(controller()->IsRevealed());
   EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() == 0);
 
   // End reveal by moving the mouse off the top-of-window views. We
   // should see the top insets being positive again to allow a bigger touch
   // target.
-  controller()->SetMouseHoveredForTest(false);
+  lock.reset();
+  EXPECT_FALSE(controller()->IsRevealed());
   EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() > 0);
 
   // Disabling immersive mode resets the top touch insets to 0.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index f24f95d..ce91716 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -5,13 +5,15 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 
 #include "ash/display/display_manager.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_types.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
@@ -40,7 +42,6 @@
   bool immersive_style() const { return immersive_style_; }
 
   // ImmersiveModeController::Delegate overrides:
-  virtual BookmarkBarView* GetBookmarkBar() OVERRIDE { return NULL; }
   virtual FullscreenController* GetFullscreenController() OVERRIDE {
     return NULL;
   }
@@ -87,9 +88,6 @@
   virtual void SetUp() OVERRIDE {
     ash::test::AshTestBase::SetUp();
 
-    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-    ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-
     controller_.reset(new ImmersiveModeControllerAsh);
     delegate_.reset(new MockImmersiveModeControllerDelegate);
 
@@ -144,7 +142,7 @@
   // SetHovered(true) moves the mouse over the |top_container_| but does not
   // move it to the top of the screen so will not initiate a reveal.
   void SetHovered(bool is_mouse_hovered) {
-    MoveMouse(0, is_mouse_hovered ? 1 : top_container_->height() + 100);
+    MoveMouse(0, is_mouse_hovered ? 10 : top_container_->height() + 100);
   }
 
   // Move the mouse to the given coordinates. The coordinates should be in
@@ -199,7 +197,6 @@
   scoped_ptr<MockImmersiveModeControllerDelegate> delegate_;
   views::Widget* widget_;  // Owned by the native widget.
   views::View* top_container_;  // Owned by |root_view_|.
-  scoped_ptr<aura::test::EventGenerator> event_generator_;
 
   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAshTest);
 };
@@ -248,6 +245,58 @@
   EXPECT_FALSE(delegate()->immersive_style());
 }
 
+// GetRevealedLock() specific tests.
+TEST_F(ImmersiveModeControllerAshTest, RevealedLock) {
+  scoped_ptr<ImmersiveRevealedLock> lock1;
+  scoped_ptr<ImmersiveRevealedLock> lock2;
+
+  // Immersive fullscreen is not on by default.
+  EXPECT_FALSE(controller()->IsEnabled());
+
+  // 1) Test acquiring and releasing a revealed state lock while immersive
+  // fullscreen is disabled. Acquiring or releasing the lock should have no
+  // effect till immersive fullscreen is enabled.
+  lock1.reset(controller()->GetRevealedLock(
+      ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+  EXPECT_FALSE(controller()->IsEnabled());
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  // Immersive fullscreen should start in the revealed state due to the lock.
+  controller()->SetEnabled(true);
+  EXPECT_TRUE(controller()->IsEnabled());
+  EXPECT_TRUE(controller()->IsRevealed());
+
+  controller()->SetEnabled(false);
+  EXPECT_FALSE(controller()->IsEnabled());
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  lock1.reset();
+  EXPECT_FALSE(controller()->IsEnabled());
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  // Immersive fullscreen should start in the closed state because the lock is
+  // no longer held.
+  controller()->SetEnabled(true);
+  EXPECT_TRUE(controller()->IsEnabled());
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  // 2) Test that acquiring a lock reveals the top-of-window views if they are
+  // hidden.
+  lock1.reset(controller()->GetRevealedLock(
+      ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+  EXPECT_TRUE(controller()->IsRevealed());
+
+  // 3) Test that the top-of-window views are only hidden when all of the locks
+  // are released.
+  lock2.reset(controller()->GetRevealedLock(
+      ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+  lock1.reset();
+  EXPECT_TRUE(controller()->IsRevealed());
+
+  lock2.reset();
+  EXPECT_FALSE(controller()->IsRevealed());
+}
+
 // Test mouse event processing for top-of-screen reveal triggering.
 TEST_F(ImmersiveModeControllerAshTest, OnMouseEvent) {
   // Set up initial state.
@@ -480,6 +529,53 @@
   EXPECT_FALSE(controller()->IsRevealed());
 }
 
+// Test behavior when the mouse becomes hovered without moving.
+TEST_F(ImmersiveModeControllerAshTest, MouseHoveredWithoutMoving) {
+  controller()->SetEnabled(true);
+  scoped_ptr<ImmersiveRevealedLock> lock;
+
+  // 1) Test that if the mouse becomes hovered without the mouse moving due to a
+  // lock causing the top-of-window views to be revealed (and the mouse
+  // happening to be near the top of the screen), the top-of-window views do not
+  // hide till the mouse moves off of the top-of-window views.
+  SetHovered(true);
+  EXPECT_FALSE(controller()->IsRevealed());
+  lock.reset(controller()->GetRevealedLock(
+      ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+  EXPECT_TRUE(controller()->IsRevealed());
+  lock.reset();
+  EXPECT_TRUE(controller()->IsRevealed());
+  SetHovered(false);
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  // 2) Test that if the mouse becomes hovered without moving because of a
+  // reveal in ImmersiveModeControllerAshTest::controller()->SetEnabled(true)
+  // and there are no locks keeping the top-of-window views revealed, that mouse
+  // hover does not prevent the top-of-window views from closing.
+  controller()->SetEnabled(false);
+  SetHovered(true);
+  EXPECT_FALSE(controller()->IsRevealed());
+  controller()->SetEnabled(true);
+  EXPECT_FALSE(controller()->IsRevealed());
+
+  // 3) Test that if the mouse becomes hovered without moving because of a
+  // reveal in ImmersiveModeControllerAshTest::controller()->SetEnabled(true)
+  // and there is a lock keeping the top-of-window views revealed, that the
+  // top-of-window views do not hide till the mouse moves off of the
+  // top-of-window views.
+  controller()->SetEnabled(false);
+  SetHovered(true);
+  lock.reset(controller()->GetRevealedLock(
+      ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+  EXPECT_FALSE(controller()->IsRevealed());
+  controller()->SetEnabled(true);
+  EXPECT_TRUE(controller()->IsRevealed());
+  lock.reset();
+  EXPECT_TRUE(controller()->IsRevealed());
+  SetHovered(false);
+  EXPECT_FALSE(controller()->IsRevealed());
+}
+
 // Test revealing the top-of-window views using one modality and ending
 // the reveal via another. For instance, initiating the reveal via a SWIPE_OPEN
 // edge gesture, switching to using the mouse and ending the reveal by moving
@@ -803,19 +899,8 @@
 
     browser()->window()->Show();
 
-    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-    ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-
-    controller_ = static_cast<ImmersiveModeControllerAsh*>(
-        browser_view()->immersive_mode_controller());
-    controller_->DisableAnimationsForTest();
-
-    // Move the mouse so that it is not over the top-of-window views. The mouse
-    // position matters because entering immersive fullscreen causes synthesized
-    // mouse moves. (If the mouse is at the very top of the screen when entering
-    // immersive fullscreen, the top-of-window views will hide, then reveal as
-    // a result of the synthesized mouse moves).
-    controller()->SetMouseHoveredForTest(false);
+    controller_ = browser_view()->immersive_mode_controller();
+    controller_->SetupForTest();
   }
 
   // Returns the bounds of |view| in widget coordinates.
@@ -823,11 +908,49 @@
     return view->ConvertRectToWidget(view->GetLocalBounds());
   }
 
-  ImmersiveModeControllerAsh* controller() { return controller_; }
+  // Toggle the browser's fullscreen state.
+  void ToggleFullscreen() {
+    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. The notification
+    // is used to trigger changes in whether the shelf is auto hidden and
+    // whether a "light bar" version of the tab strip is used when the
+    // top-of-window views are hidden.
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    chrome::ToggleFullscreenMode(browser());
+    waiter->Wait();
+  }
+
+  // Set whether the browser is in tab fullscreen.
+  void SetTabFullscreen(bool tab_fullscreen) {
+    content::WebContents* web_contents =
+        browser_view()->GetContentsWebViewForTest()->GetWebContents();
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
+        web_contents, tab_fullscreen);
+    waiter->Wait();
+  }
+
+  // Attempt revealing the top-of-window views.
+  void AttemptReveal() {
+    if (!revealed_lock_.get()) {
+      revealed_lock_.reset(controller_->GetRevealedLock(
+          ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
+    }
+  }
+
+  // Attempt unrevealing the top-of-window views.
+  void AttemptUnreveal() {
+    revealed_lock_.reset();
+  }
+
+  ImmersiveModeController* controller() { return controller_; }
 
  private:
   // Not owned.
-  ImmersiveModeControllerAsh* controller_;
+  ImmersiveModeController* controller_;
+
+  scoped_ptr<ImmersiveRevealedLock> revealed_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAshTestWithBrowserView);
 };
@@ -850,14 +973,7 @@
   EXPECT_TRUE(tabstrip->visible());
   EXPECT_TRUE(toolbar->visible());
 
-  // Enter immersive fullscreen.
-  {
-    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously.
-    scoped_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
-    chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
-  }
+  ToggleFullscreen();
   EXPECT_TRUE(browser_view()->GetWidget()->IsFullscreen());
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
@@ -877,7 +993,7 @@
 
   // Revealing the top-of-window views should set the tab strip back to the
   // normal style and show the toolbar.
-  controller()->StartRevealForTest(true);
+  AttemptReveal();
   EXPECT_TRUE(controller()->IsRevealed());
   EXPECT_TRUE(tabstrip->visible());
   EXPECT_FALSE(tabstrip->IsImmersiveStyle());
@@ -894,16 +1010,10 @@
             GetBoundsInWidget(contents_web_view).y());
 
   // Repeat the test for when in both immersive fullscreen and tab fullscreen.
-  {
-    scoped_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
-    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
-        contents_web_view->GetWebContents(), true);
-    waiter->Wait();
-  }
+  SetTabFullscreen(true);
   // Hide and reveal the top-of-window views so that they get relain out.
-  controller()->SetMouseHoveredForTest(false);
-  controller()->StartRevealForTest(true);
+  AttemptUnreveal();
+  AttemptReveal();
 
   // The tab strip and toolbar should still be visible and the TopContainerView
   // should still be flush with the top edge of the widget.
@@ -919,7 +1029,7 @@
 
   // Hide the top-of-window views. Both the tab strip and the toolbar should
   // hide when in both immersive and tab fullscreen.
-  controller()->SetMouseHoveredForTest(false);
+  AttemptUnreveal();
   EXPECT_FALSE(controller()->IsRevealed());
   EXPECT_FALSE(tabstrip->visible());
   EXPECT_FALSE(toolbar->visible());
@@ -929,12 +1039,7 @@
 
   // Exiting both immersive and tab fullscreen should show the tab strip and
   // toolbar.
-  {
-    scoped_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
-    chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
-  }
+  ToggleFullscreen();
   EXPECT_FALSE(browser_view()->GetWidget()->IsFullscreen());
   EXPECT_FALSE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
@@ -951,7 +1056,7 @@
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ABOUT));
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FOCUS_LOCATION));
 
-  chrome::ToggleFullscreenMode(browser());
+  ToggleFullscreen();
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPEN_CURRENT_URL));
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ABOUT));
@@ -961,18 +1066,91 @@
 // Test that restoring a window properly exits immersive fullscreen.
 TEST_F(ImmersiveModeControllerAshTestWithBrowserView, ExitUponRestore) {
   ASSERT_FALSE(controller()->IsEnabled());
-  chrome::ToggleFullscreenMode(browser());
-  controller()->StartRevealForTest(true);
+  ToggleFullscreen();
+  AttemptReveal();
   ASSERT_TRUE(controller()->IsEnabled());
   ASSERT_TRUE(controller()->IsRevealed());
   ASSERT_TRUE(browser_view()->GetWidget()->IsFullscreen());
 
   browser_view()->GetWidget()->Restore();
-  // Exiting immersive fullscreen occurs as a result of a task posted to the
-  // message loop.
-  content::RunAllPendingInMessageLoop();
-
   EXPECT_FALSE(controller()->IsEnabled());
 }
 
+// Test that the shelf is set to auto hide as long as the window is in
+// immersive fullscreen and that the shelf's state before entering immersive
+// fullscreen is restored upon exiting immersive fullscreen.
+TEST_F(ImmersiveModeControllerAshTestWithBrowserView, Shelf) {
+  // Shelf is visible when the test starts.
+  ash::internal::ShelfLayoutManager* shelf =
+      ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
+  ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
+
+  // Entering immersive fullscreen sets the shelf to auto hide.
+  ToggleFullscreen();
+  ASSERT_TRUE(browser_view()->IsFullscreen());
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+
+  // Disabling immersive fullscreen puts it back.
+  ToggleFullscreen();
+  ASSERT_FALSE(browser_view()->IsFullscreen());
+  ASSERT_FALSE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
+
+  // The user could toggle the shelf auto-hide behavior.
+  shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+
+  // Entering immersive fullscreen keeps auto-hide.
+  ToggleFullscreen();
+  ASSERT_TRUE(browser_view()->IsFullscreen());
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+
+  // Disabling immersive fullscreen maintains the user's auto-hide selection.
+  ToggleFullscreen();
+  ASSERT_FALSE(browser_view()->IsFullscreen());
+  ASSERT_FALSE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+}
+
+// Test how being simultaneously in tab fullscreen and immersive fullscreen
+// affects the shelf visibility and whether the tab indicators are hidden.
+TEST_F(ImmersiveModeControllerAshTestWithBrowserView, TabAndBrowserFullscreen) {
+  AddTab(browser(), GURL("about:blank"));
+
+  // The shelf should start out as visible.
+  ash::internal::ShelfLayoutManager* shelf =
+      ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
+  ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
+
+  // 1) Test that entering tab fullscreen from immersive fullscreen hides the
+  // tab indicators and the shelf.
+  ToggleFullscreen();
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+  EXPECT_FALSE(controller()->ShouldHideTabIndicators());
+
+  SetTabFullscreen(true);
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_HIDDEN, shelf->visibility_state());
+  EXPECT_TRUE(controller()->ShouldHideTabIndicators());
+
+  // 2) Test that exiting tab fullscreen shows the tab indicators and autohides
+  // the shelf.
+  SetTabFullscreen(false);
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
+  EXPECT_FALSE(controller()->ShouldHideTabIndicators());
+
+  // 3) Test that exiting tab fullscreen and immersive fullscreen
+  // simultaneously correctly updates the shelf visibility and whether the tab
+  // indicators should be hidden.
+  SetTabFullscreen(true);
+  ToggleFullscreen();
+  ASSERT_FALSE(controller()->IsEnabled());
+  EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
+  EXPECT_TRUE(controller()->ShouldHideTabIndicators());
+}
+
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc
index fdcedd5..3f7bf29 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc
@@ -51,3 +51,6 @@
 void ImmersiveModeControllerStub::OnFindBarVisibleBoundsChanged(
     const gfx::Rect& new_visible_bounds_in_screen) {
 }
+
+void ImmersiveModeControllerStub::SetupForTest() {
+}
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h
index 27bfba0..973cd16 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h
@@ -32,6 +32,7 @@
       AnimateReveal animate_reveal) OVERRIDE WARN_UNUSED_RESULT;
   virtual void OnFindBarVisibleBoundsChanged(
       const gfx::Rect& new_visible_bounds_in_screen) OVERRIDE;
+  virtual void SetupForTest() OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerStub);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 071e392..d38da9d 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -362,6 +362,10 @@
 }
 
 void OpaqueBrowserFrameViewLayout::LayoutNewStyleAvatar(views::View* host) {
+  DCHECK(profiles::IsNewProfileManagementEnabled());
+  if (!new_avatar_button_)
+    return;
+
   gfx::Size label_size = new_avatar_button_->GetPreferredSize();
   int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
 
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc
index 7f86a71..72cfbe6 100644
--- a/chrome/browser/ui/views/hung_renderer_view.cc
+++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -442,8 +442,17 @@
 void ShowHungRendererDialog(WebContents* contents) {
   if (!logging::DialogsAreSuppressed() &&
       !PlatformShowCustomHungRendererDialog(contents)) {
+    gfx::NativeView toplevel_view =
+        platform_util::GetTopLevel(contents->GetView()->GetNativeView());
+#if defined(USE_AURA)
+    // Don't show the dialog if there is no root window for the renderer,
+    // because it's invisible to the user (happens when the renderer is for
+    // prerendering for example).
+    if (!toplevel_view->GetRootWindow())
+      return;
+#endif
     HungRendererDialogView* view = HungRendererDialogView::Create(
-        platform_util::GetTopLevel(contents->GetView()->GetNativeView()));
+        toplevel_view);
     view->ShowForWebContents(contents);
   }
 }
diff --git a/chrome/browser/ui/views/infobars/translate_language_menu_model.cc b/chrome/browser/ui/views/infobars/translate_language_menu_model.cc
index 5a5b189..a93c4b0 100644
--- a/chrome/browser/ui/views/infobars/translate_language_menu_model.cc
+++ b/chrome/browser/ui/views/infobars/translate_language_menu_model.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/views/infobars/translate_infobar_base.h"
+#include "components/translate/common/translate_metrics.h"
 
 TranslateLanguageMenuModel::TranslateLanguageMenuModel(
     LanguageType language_type,
@@ -48,10 +49,12 @@
                                                 int event_flags) {
   size_t command_id_size_t = static_cast<size_t>(command_id);
   if (language_type_ == ORIGINAL) {
-    UMA_HISTOGRAM_BOOLEAN("Translate.ModifyOriginalLang", true);
+    UMA_HISTOGRAM_BOOLEAN(
+        translate::GetMetricsName(translate::UMA_MODIFY_ORIGINAL_LANG), true);
     infobar_delegate_->set_original_language_index(command_id_size_t);
   } else {
-    UMA_HISTOGRAM_BOOLEAN("Translate.ModifyTargetLang", true);
+    UMA_HISTOGRAM_BOOLEAN(
+        translate::GetMetricsName(translate::UMA_MODIFY_TARGET_LANG), true);
     infobar_delegate_->set_target_language_index(command_id_size_t);
   }
   infobar_->UpdateLanguageButtonText(button_,
diff --git a/chrome/browser/ui/views/location_bar/bubble_icon_view.cc b/chrome/browser/ui/views/location_bar/bubble_icon_view.cc
new file mode 100644
index 0000000..2a3d033
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/bubble_icon_view.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/views/location_bar/bubble_icon_view.h"
+
+#include "chrome/browser/command_updater.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/events/event.h"
+
+BubbleIconView::BubbleIconView(CommandUpdater* command_updater, int command_id)
+    : command_updater_(command_updater),
+      command_id_(command_id),
+      suppress_mouse_released_action_(false) {
+  set_accessibility_focusable(true);
+  LocationBarView::InitTouchableLocationBarChildView(this);
+}
+
+BubbleIconView::~BubbleIconView() {
+}
+
+void BubbleIconView::GetAccessibleState(ui::AccessibleViewState* state) {
+  views::ImageView::GetAccessibleState(state);
+  state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
+}
+
+bool BubbleIconView::GetTooltipText(const gfx::Point& p,
+                                    string16* tooltip) const {
+  if (IsBubbleShowing())
+    return false;
+
+  return views::ImageView::GetTooltipText(p, tooltip);
+}
+
+bool BubbleIconView::OnMousePressed(const ui::MouseEvent& event) {
+  // If the bubble is showing then don't reshow it when the mouse is released.
+  suppress_mouse_released_action_ = IsBubbleShowing();
+
+  // We want to show the bubble on mouse release; that is the standard behavior
+  // for buttons.
+  return true;
+}
+
+void BubbleIconView::OnMouseReleased(const ui::MouseEvent& event) {
+  // If this is the second click on this view then the bubble was showing on the
+  // mouse pressed event and is hidden now. Prevent the bubble from reshowing by
+  // doing nothing here.
+  if (suppress_mouse_released_action_) {
+    suppress_mouse_released_action_ = false;
+    return;
+  }
+
+  if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) {
+    OnExecuting(EXECUTE_SOURCE_MOUSE);
+    command_updater_->ExecuteCommand(command_id_);
+  }
+}
+
+bool BubbleIconView::OnKeyPressed(const ui::KeyEvent& event) {
+  if (event.key_code() == ui::VKEY_SPACE ||
+      event.key_code() == ui::VKEY_RETURN) {
+    OnExecuting(EXECUTE_SOURCE_KEYBOARD);
+    command_updater_->ExecuteCommand(command_id_);
+    return true;
+  }
+  return false;
+}
+
+void BubbleIconView::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->type() == ui::ET_GESTURE_TAP) {
+    OnExecuting(EXECUTE_SOURCE_GESTURE);
+    command_updater_->ExecuteCommand(command_id_);
+    event->SetHandled();
+  }
+}
diff --git a/chrome/browser/ui/views/location_bar/bubble_icon_view.h b/chrome/browser/ui/views/location_bar/bubble_icon_view.h
new file mode 100644
index 0000000..37946db
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/bubble_icon_view.h
@@ -0,0 +1,56 @@
+// Copyright 2013 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_VIEWS_LOCATION_BAR_BUBBLE_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_BUBBLE_ICON_VIEW_H_
+
+#include "ui/views/controls/image_view.h"
+
+class CommandUpdater;
+
+// Represents an icon on the omnibox that shows a bubble when clicked.
+class BubbleIconView : public views::ImageView {
+ protected:
+  enum ExecuteSource {
+    EXECUTE_SOURCE_MOUSE,
+    EXECUTE_SOURCE_KEYBOARD,
+    EXECUTE_SOURCE_GESTURE,
+  };
+
+  explicit BubbleIconView(CommandUpdater* command_updater, int command_id);
+  virtual ~BubbleIconView();
+
+  // Returns true if a related bubble is showing.
+  virtual bool IsBubbleShowing() const = 0;
+
+  // Invoked prior to executing the command.
+  virtual void OnExecuting(ExecuteSource execute_source) = 0;
+
+  // views::ImageView:
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+  virtual bool GetTooltipText(const gfx::Point& p, string16* tooltip)
+      const OVERRIDE;
+  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
+  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
+
+  // ui::EventHandler:
+  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ private:
+  // The CommandUpdater for the Browser object that owns the location bar.
+  CommandUpdater* command_updater_;
+
+  // The command ID executed when the user clicks this icon.
+  const int command_id_;
+
+  // This is used to check if the bookmark bubble was showing during the mouse
+  // pressed event. If this is true then the mouse released event is ignored to
+  // prevent the bubble from reshowing.
+  bool suppress_mouse_released_action_;
+
+  DISALLOW_COPY_AND_ASSIGN(BubbleIconView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_BUBBLE_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 244eee7..064d53e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
@@ -49,11 +50,13 @@
 #include "chrome/browser/ui/views/location_bar/script_bubble_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
+#include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/zoom_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_views.h"
 #include "chrome/browser/ui/zoom/zoom_controller.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
@@ -182,6 +185,7 @@
       open_pdf_in_reader_view_(NULL),
       script_bubble_icon_view_(NULL),
       star_view_(NULL),
+      translate_icon_view_(NULL),
       is_popup_mode_(is_popup_mode),
       show_focus_rect_(false),
       template_url_service_(NULL),
@@ -359,6 +363,13 @@
   star_view_->SetVisible(false);
   AddChildView(star_view_);
 
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableTranslateNewUX)) {
+    translate_icon_view_ = new TranslateIconView(command_updater());
+    translate_icon_view_->SetVisible(false);
+    AddChildView(translate_icon_view_);
+  }
+
   registrar_.Add(this,
                  chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
                  content::Source<Profile>(profile_));
@@ -667,7 +678,8 @@
       const TemplateURL* template_url =
           TemplateURLServiceFactory::GetForProfile(profile_)->
           GetTemplateURLForKeyword(keyword);
-      if (template_url && template_url->IsExtensionKeyword()) {
+      if (template_url &&
+          (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
         gfx::Image image = extensions::OmniboxAPI::Get(profile_)->
             GetOmniboxIcon(template_url->GetExtensionId());
         selected_keyword_view_->SetImage(image.AsImageSkia());
@@ -698,6 +710,12 @@
         vertical_edge_thickness(), location_height,
         GetBuiltInHorizontalPaddingForChildViews(), star_view_);
   }
+  if (translate_icon_view_ && translate_icon_view_->visible()) {
+    trailing_decorations.AddDecoration(
+        vertical_edge_thickness(), location_height,
+        GetBuiltInHorizontalPaddingForChildViews(),
+        translate_icon_view_);
+  }
   if (script_bubble_icon_view_ && script_bubble_icon_view_->visible()) {
     trailing_decorations.AddDecoration(
         vertical_edge_thickness(), location_height,
@@ -980,6 +998,7 @@
   RefreshZoomView();
   RefreshPageActionViews();
   RefreshScriptBubble();
+  RefreshTranslateIcon();
   open_pdf_in_reader_view_->Update(
       GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
 
@@ -1442,6 +1461,23 @@
   zoom_view_->Update(zoom_controller);
 }
 
+void LocationBarView::RefreshTranslateIcon() {
+  if (!translate_icon_view_)
+    return;
+
+  WebContents* web_contents = GetWebContents();
+  if (!web_contents)
+    return;
+
+  TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(web_contents);
+  bool enabled =
+      translate_tab_helper->language_state().translate_enabled();
+
+  command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled);
+  translate_icon_view_->SetVisible(enabled);
+}
+
 #if defined(OS_WIN) && !defined(USE_AURA)
 void LocationBarView::OnMouseEvent(const ui::MouseEvent& event, UINT msg) {
   OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 6528681..49874d8 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -51,6 +51,7 @@
 class SelectedKeywordView;
 class StarView;
 class TemplateURLService;
+class TranslateIconView;
 class ZoomView;
 
 namespace views {
@@ -185,6 +186,10 @@
   // Returns the star view. It may not be visible.
   StarView* star_view() { return star_view_; }
 
+  TranslateIconView* translate_icon_view() {
+    return translate_icon_view_;
+  }
+
   // Shows the bookmark prompt.
   void ShowBookmarkPrompt();
 
@@ -379,23 +384,29 @@
   // after UpdateContentSettingViewsPreLayout() and a subsequent Layout().
   void UpdateContentSettingViewsPostLayout();
 
-  // Delete all page action views that we have created.
+  // Deletes all page action views that we have created.
   void DeletePageActionViews();
 
-  // Update the views for the Page Actions, to reflect state changes for
+  // Updates the views for the Page Actions, to reflect state changes for
   // PageActions.
   void RefreshPageActionViews();
 
   // Returns the number of scripts currently running on the page.
   size_t ScriptBubbleScriptsRunning();
 
-  // Update the Script Bubble Icon, to reflect the number of content scripts
+  // Updates the Script Bubble Icon, to reflect the number of content scripts
   // running on the page.
   void RefreshScriptBubble();
 
-  // Update the view for the zoom icon based on the current tab's zoom.
+  // Updates the view for the zoom icon based on the current tab's zoom.
   void RefreshZoomView();
 
+  // Updates the Translate icon based on the current tab's Translate status.
+  void RefreshTranslateIcon();
+
+  // Sets the visibility of view to new_vis.
+  void ToggleVisibility(bool new_vis, views::View* view);
+
 #if !defined(USE_AURA)
   // Helper for the Mouse event handlers that does all the real work.
   void OnMouseEvent(const ui::MouseEvent& event, UINT msg);
@@ -407,7 +418,7 @@
   // Helper to show the first run info bubble.
   void ShowFirstRunBubbleInternal();
 
-  // Draw backgrounds and borders for page actions.  Must be called
+  // Draws backgrounds and borders for page actions.  Must be called
   // after layout, so the |page_action_views_| have their bounds.
   void PaintPageActionBackgrounds(gfx::Canvas* canvas);
 
@@ -492,6 +503,9 @@
   // The star.
   StarView* star_view_;
 
+  // The icon for Translate.
+  TranslateIconView* translate_icon_view_;
+
   // Whether we're in popup mode. This value also controls whether the location
   // bar is read-only.
   const bool is_popup_mode_;
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index 7a3c955..147cce8 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -8,24 +8,17 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/bookmarks/bookmark_stats.h"
-#include "chrome/browser/command_updater.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
-#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/events/event.h"
 
 StarView::StarView(CommandUpdater* command_updater)
-    : command_updater_(command_updater),
-      suppress_mouse_released_action_(false) {
+    : BubbleIconView(command_updater, IDC_BOOKMARK_PAGE_FROM_STAR) {
   set_id(VIEW_ID_STAR_BUTTON);
   SetToggled(false);
-  set_accessibility_focusable(true);
-  LocationBarView::InitTouchableLocationBarChildView(this);
 }
 
 StarView::~StarView() {}
@@ -37,64 +30,25 @@
       on ? IDR_STAR_LIT : IDR_STAR));
 }
 
-void StarView::GetAccessibleState(ui::AccessibleViewState* state) {
-  ImageView::GetAccessibleState(state);
-  state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
+bool StarView::IsBubbleShowing() const {
+  return BookmarkBubbleView::IsShowing();
 }
 
-bool StarView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
-  // Don't show tooltip to distract user if BookmarkBubbleView is showing.
-  if (BookmarkBubbleView::IsShowing())
-    return false;
-
-  return views::ImageView::GetTooltipText(p, tooltip);
-}
-
-bool StarView::OnMousePressed(const ui::MouseEvent& event) {
-  // If the bookmark bubble is showing then don't reshow it when the mouse is
-  // released.
-  suppress_mouse_released_action_ = BookmarkBubbleView::IsShowing();
-
-  // We want to show the bubble on mouse release; that is the standard behavior
-  // for buttons.
-  return true;
-}
-
-void StarView::OnMouseReleased(const ui::MouseEvent& event) {
-  // If this is the second click on this view then the bookmark bubble was
-  // showing on the mouse pressed event and is hidden now. Prevent the bubble
-  // from reshowing by doing nothing here.
-  if (suppress_mouse_released_action_) {
-    suppress_mouse_released_action_ = false;
-    return;
+void StarView::OnExecuting(
+    BubbleIconView::ExecuteSource execute_source) {
+  BookmarkEntryPoint entry_point = BOOKMARK_ENTRY_POINT_STAR_MOUSE;
+  switch (execute_source) {
+    case EXECUTE_SOURCE_MOUSE:
+      entry_point = BOOKMARK_ENTRY_POINT_STAR_MOUSE;
+      break;
+    case EXECUTE_SOURCE_KEYBOARD:
+      entry_point = BOOKMARK_ENTRY_POINT_STAR_KEY;
+      break;
+    case EXECUTE_SOURCE_GESTURE:
+      entry_point = BOOKMARK_ENTRY_POINT_STAR_GESTURE;
+      break;
   }
-
-  if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) {
-    UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
-                              BOOKMARK_ENTRY_POINT_STAR_MOUSE,
-                              BOOKMARK_ENTRY_POINT_LIMIT);
-    command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE_FROM_STAR);
-  }
-}
-
-bool StarView::OnKeyPressed(const ui::KeyEvent& event) {
-  if (event.key_code() == ui::VKEY_SPACE ||
-      event.key_code() == ui::VKEY_RETURN) {
-    UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
-                              BOOKMARK_ENTRY_POINT_STAR_KEY,
-                              BOOKMARK_ENTRY_POINT_LIMIT);
-    command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE_FROM_STAR);
-    return true;
-  }
-  return false;
-}
-
-void StarView::OnGestureEvent(ui::GestureEvent* event) {
-  if (event->type() == ui::ET_GESTURE_TAP) {
-    UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
-                              BOOKMARK_ENTRY_POINT_STAR_GESTURE,
-                              BOOKMARK_ENTRY_POINT_LIMIT);
-    command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE_FROM_STAR);
-    event->SetHandled();
-  }
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
+                            entry_point,
+                            BOOKMARK_ENTRY_POINT_LIMIT);
 }
diff --git a/chrome/browser/ui/views/location_bar/star_view.h b/chrome/browser/ui/views/location_bar/star_view.h
index a2c7b95..3aa91ec 100644
--- a/chrome/browser/ui/views/location_bar/star_view.h
+++ b/chrome/browser/ui/views/location_bar/star_view.h
@@ -5,11 +5,12 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_STAR_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_STAR_VIEW_H_
 
-#include "ui/views/controls/image_view.h"
+#include "chrome/browser/ui/views/location_bar/bubble_icon_view.h"
 
 class CommandUpdater;
 
-class StarView : public views::ImageView {
+// The star icon to show a bookmark bubble.
+class StarView : public BubbleIconView {
  public:
   explicit StarView(CommandUpdater* command_updater);
   virtual ~StarView();
@@ -17,26 +18,13 @@
   // Toggles the star on or off.
   void SetToggled(bool on);
 
+ protected:
+  // BubbleIconView:
+  virtual bool IsBubbleShowing() const OVERRIDE;
+  virtual void OnExecuting(
+      BubbleIconView::ExecuteSource execute_source) OVERRIDE;
+
  private:
-  // views::ImageView:
-  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-  virtual bool GetTooltipText(const gfx::Point& p,
-                              string16* tooltip) const OVERRIDE;
-  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
-  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
-  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
-
-  // ui::EventHandler:
-  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
-  // The CommandUpdater for the Browser object that owns the location bar.
-  CommandUpdater* command_updater_;
-
-  // This is used to check if the bookmark bubble was showing during the mouse
-  // pressed event. If this is true then the mouse released event is ignored to
-  // prevent the bubble from reshowing.
-  bool suppress_mouse_released_action_;
-
   DISALLOW_COPY_AND_ASSIGN(StarView);
 };
 
diff --git a/chrome/browser/ui/views/location_bar/translate_icon_view.cc b/chrome/browser/ui/views/location_bar/translate_icon_view.cc
new file mode 100644
index 0000000..014138e
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/translate_icon_view.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 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/views/location_bar/translate_icon_view.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+TranslateIconView::TranslateIconView(CommandUpdater* command_updater)
+    : BubbleIconView(command_updater, IDC_TRANSLATE_PAGE) {
+  set_id(VIEW_ID_TRANSLATE_BUTTON);
+  SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_TRANSLATE));
+  SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+      IDR_TRANSLATE));
+}
+
+TranslateIconView::~TranslateIconView() {
+}
+
+bool TranslateIconView::IsBubbleShowing() const {
+  return TranslateBubbleView::IsShowing();
+}
+
+void TranslateIconView::OnExecuting(
+    BubbleIconView::ExecuteSource execute_source) {
+}
diff --git a/chrome/browser/ui/views/location_bar/translate_icon_view.h b/chrome/browser/ui/views/location_bar/translate_icon_view.h
new file mode 100644
index 0000000..1e1e287
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/translate_icon_view.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
+
+#include "chrome/browser/ui/views/location_bar/bubble_icon_view.h"
+
+class CommandUpdater;
+
+// The icon to show the Translate bubble where the user can have the page
+// tarnslated.
+class TranslateIconView : public BubbleIconView {
+ public:
+  explicit TranslateIconView(CommandUpdater* command_updater);
+  virtual ~TranslateIconView();
+
+ protected:
+  // BubbleIconView:
+  virtual bool IsBubbleShowing() const OVERRIDE;
+  virtual void OnExecuting(
+      BubbleIconView::ExecuteSource execute_source) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TranslateIconView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_TRANSLATE_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index aabb77a..653c510 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -83,7 +83,10 @@
     if (is_fullscreen)
       zoom_bubble_->AdjustForFullscreen(browser_view->GetBoundsInScreen());
 
-    zoom_bubble_->GetWidget()->Show();
+    if (zoom_bubble_->use_focusless())
+      zoom_bubble_->GetWidget()->ShowInactive();
+    else
+      zoom_bubble_->GetWidget()->Show();
   }
 }
 
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
index ecd103c..dc43622 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -7,28 +7,12 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
-#endif
-
-class ZoomBubbleBrowserTest : public InProcessBrowserTest {
- public:
-  ZoomBubbleBrowserTest() {}
-  virtual ~ZoomBubbleBrowserTest() {}
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ZoomBubbleBrowserTest);
-};
+typedef InProcessBrowserTest ZoomBubbleBrowserTest;
 
 // TODO(linux_aura) http://crbug.com/163931
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
@@ -49,9 +33,7 @@
   EXPECT_TRUE(zoom_bubble->GetAnchorView());
 
   // Entering fullscreen should close the bubble. (We enter into tab fullscreen
-  // here because tab fullscreen is non-immersive even when
-  // ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) returns
-  // true.
+  // here because tab fullscreen is non-immersive even on Chrome OS.)
   {
     // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. Wait for the
     // notification before testing the zoom bubble visibility.
@@ -88,14 +70,9 @@
   BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
   content::WebContents* web_contents = browser_view->GetActiveWebContents();
 
-  ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-  ImmersiveModeControllerAsh* immersive_controller =
-      static_cast<ImmersiveModeControllerAsh*>(
-          browser_view->immersive_mode_controller());
-  immersive_controller->DisableAnimationsForTest();
-
-  // Move the mouse out of the way.
-  immersive_controller->SetMouseHoveredForTest(false);
+  ImmersiveModeController* immersive_controller =
+      browser_view->immersive_mode_controller();
+  immersive_controller->SetupForTest();
 
   // Enter immersive fullscreen.
   {
diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc
index 42b99e4..7daad81 100644
--- a/chrome/browser/ui/views/login_prompt_views.cc
+++ b/chrome/browser/ui/views/login_prompt_views.cc
@@ -163,8 +163,6 @@
         requesting_contents->GetView()->GetNativeView(),
         modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
     web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView());
-    web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-        dialog_->GetNativeView(), true);
     NotifyAuthNeeded();
   }
 
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc b/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc
index ca491ef..ee26ec7 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc
@@ -100,8 +100,16 @@
 
 }  // namespace
 
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_WebNotifications DISABLED_WebNotifications
+#else
+#define MAYBE_WebNotifications WebNotifications
+#endif
+
 // TODO(dewittj): More exhaustive testing.
-IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, WebNotifications) {
+IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, MAYBE_WebNotifications) {
   message_center::MessageCenter* message_center =
       message_center::MessageCenter::Get();
 
diff --git a/chrome/browser/ui/views/new_avatar_button.cc b/chrome/browser/ui/views/new_avatar_button.cc
index 049afb39..f9c272a 100644
--- a/chrome/browser/ui/views/new_avatar_button.cc
+++ b/chrome/browser/ui/views/new_avatar_button.cc
@@ -107,13 +107,13 @@
     rect = gfx::Rect(-kInset, 0, size().width(), size().height());
   else
     rect = gfx::Rect(kInset, 0, size().width(), size().height());
-  // TODO(noms): This should be DrawStringRectWithHalo but that function
-  // has a bug at the moment and incorrectly draws the background.
-  canvas->DrawStringRectWithFlags(
+
+  canvas->DrawStringRectWithHalo(
       text(),
       gfx::FontList(ui::ResourceBundle::GetSharedInstance().GetFont(
           ui::ResourceBundle::BaseFont)),
-      SK_ColorBLACK,
+      SK_ColorWHITE,
+      SK_ColorDKGRAY,
       rect,
       gfx::Canvas::NO_SUBPIXEL_RENDERING);
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index b87a6af..4e9746b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -291,9 +291,13 @@
       return true;
     case ui::VKEY_V:
       if (control && !alt && !read_only()) {
-        OnBeforePossibleChange();
-        OnPaste();
-        OnAfterPossibleChange();
+        ExecuteCommand(IDS_APP_PASTE, 0);
+        return true;
+      }
+      break;
+    case ui::VKEY_INSERT:
+      if (shift && !control && !read_only()) {
+        ExecuteCommand(IDS_APP_PASTE, 0);
         return true;
       }
       break;
@@ -835,8 +839,10 @@
 }
 
 bool OmniboxViewViews::IsCommandIdEnabled(int command_id) const {
+  if (command_id == IDS_APP_PASTE)
+    return !read_only() && !GetClipboardText().empty();
   if (command_id == IDS_PASTE_AND_GO)
-    return model()->CanPasteAndGo(GetClipboardText());
+    return !read_only() && model()->CanPasteAndGo(GetClipboardText());
   if (command_id != IDS_SHOW_URL)
     return command_updater()->IsCommandEnabled(command_id);
   return controller()->GetToolbarModel()->WouldPerformSearchTermReplacement(
diff --git a/chrome/browser/ui/views/profile_chooser_view.cc b/chrome/browser/ui/views/profile_chooser_view.cc
index 3c53784..fd0ea67 100644
--- a/chrome/browser/ui/views/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profile_chooser_view.cc
@@ -5,10 +5,13 @@
 #include "chrome/browser/ui/views/profile_chooser_view.h"
 
 #include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_info_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/singleton_tabs.h"
@@ -24,7 +27,6 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/button/blue_button.h"
-#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -246,6 +248,7 @@
   end_guest_button_ = NULL;
   users_button_ = NULL;
   add_user_button_ = NULL;
+  add_account_button_ = NULL;
   open_other_profile_indexes_map_.clear();
 }
 
@@ -277,12 +280,17 @@
   views::GridLayout* layout = CreateSingleColumnLayout(this);
   layout->set_minimum_size(gfx::Size(kMinMenuWidth, 0));
 
-  if (view_to_display == GAIA_SIGNIN_VIEW) {
-    const int kMinGaiaViewWidth = 280;
-    const int kMinGaiaViewHeight = 300;
+  if (view_to_display == GAIA_SIGNIN_VIEW ||
+      view_to_display == GAIA_ADD_ACCOUNT_VIEW) {
+    // Minimum size for embedded sign in pages as defined in Gaia.
+    const int kMinGaiaViewWidth = 320;
+    const int kMinGaiaViewHeight = 500;
     Profile* profile = browser_->profile();
     views::WebView* web_view = new views::WebView(profile);
-    web_view->LoadInitialURL(GURL(chrome::kChromeUIInlineLoginURL));
+    signin::Source source = (view_to_display == GAIA_SIGNIN_VIEW) ?
+        signin::SOURCE_AVATAR_BUBBLE_SIGN_IN :
+        signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT;
+    web_view->LoadInitialURL(GURL(signin::GetPromoURL(source, false)));
     layout->StartRow(1, 0);
     layout->AddView(web_view);
     layout->set_minimum_size(
@@ -364,6 +372,8 @@
     UserManagerView::Show(browser_);
   } else if (sender == add_user_button_) {
     profiles::CreateAndSwitchToNewProfile(browser_->host_desktop_type());
+  } else if (sender == add_account_button_) {
+    ShowView(GAIA_ADD_ACCOUNT_VIEW, avatar_menu_.get());
   } else {
     // One of the "other profiles" buttons was pressed.
     ButtonIndexes::const_iterator match =
@@ -594,21 +604,30 @@
                     views::kButtonVEdgeMarginNew,
                     views::kButtonHEdgeMarginNew);
 
-  views::Label* email_label = new views::Label(avatar_item.sync_state);
-  email_label->SetElideBehavior(views::Label::ELIDE_AS_EMAIL);
-  email_label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
-      ui::ResourceBundle::SmallFont));
-  email_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  Profile* profile = browser_->profile();
+  std::vector<std::string> accounts(
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->GetAccounts());
+  for (size_t i = 0; i < accounts.size(); ++i) {
+    if (i != 0)
+      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
-  layout->StartRow(1, 0);
-  layout->AddView(email_label);
+    views::Label* email_label = new views::Label(UTF8ToUTF16(accounts[i]));
+    email_label->SetElideBehavior(views::Label::ELIDE_AS_EMAIL);
+    email_label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
+        ui::ResourceBundle::SmallFont));
+    email_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
+    layout->StartRow(1, 0);
+    layout->AddView(email_label);
+  }
+
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
-  views::BlueButton* add_account_button = new views::BlueButton(
-      NULL,
+  add_account_button_ = new views::BlueButton(
+      this,
       l10n_util::GetStringFUTF16(IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON,
                                  avatar_item.name));
   layout->StartRow(1, 0);
-  layout->AddView(add_account_button);
+  layout->AddView(add_account_button_);
   return view;
 }
diff --git a/chrome/browser/ui/views/profile_chooser_view.h b/chrome/browser/ui/views/profile_chooser_view.h
index 8affea1..91a04fb 100644
--- a/chrome/browser/ui/views/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profile_chooser_view.h
@@ -22,6 +22,7 @@
 namespace views {
 class Link;
 class TextButton;
+class LabelButton;
 }
 
 class Browser;
@@ -65,7 +66,8 @@
   enum BubbleViewMode {
     PROFILE_CHOOSER_VIEW,     // Shows a "fast profile switcher" view.
     ACCOUNT_MANAGEMENT_VIEW,  // Shows a list of accounts for the active user.
-    GAIA_SIGNIN_VIEW          // Shows a web view with Gaia signin page.
+    GAIA_SIGNIN_VIEW,         // Shows a web view for primary sign in.
+    GAIA_ADD_ACCOUNT_VIEW     // Shows a web view for adding secondary accounts.
   };
 
   ProfileChooserView(views::View* anchor_view,
@@ -130,6 +132,7 @@
   views::TextButton* end_guest_button_;
   views::TextButton* add_user_button_;
   views::TextButton* users_button_;
+  views::LabelButton* add_account_button_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileChooserView);
 };
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index 214b12d..3257bab 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -49,13 +49,16 @@
 class PendingDialog {
  public:
   static PendingDialog* GetInstance();
-  void Add(int32 tab_id, scoped_refptr<SelectFileDialogExtension> dialog);
-  void Remove(int32 tab_id);
-  scoped_refptr<SelectFileDialogExtension> Find(int32 tab_id);
+  void Add(SelectFileDialogExtension::RoutingID id,
+           scoped_refptr<SelectFileDialogExtension> dialog);
+  void Remove(SelectFileDialogExtension::RoutingID id);
+  scoped_refptr<SelectFileDialogExtension> Find(
+      SelectFileDialogExtension::RoutingID id);
 
  private:
   friend struct DefaultSingletonTraits<PendingDialog>;
-  typedef std::map<int32, scoped_refptr<SelectFileDialogExtension> > Map;
+  typedef std::map<SelectFileDialogExtension::RoutingID,
+                   scoped_refptr<SelectFileDialogExtension> > Map;
   Map map_;
 };
 
@@ -64,21 +67,22 @@
   return Singleton<PendingDialog>::get();
 }
 
-void PendingDialog::Add(int32 tab_id,
-                         scoped_refptr<SelectFileDialogExtension> dialog) {
+void PendingDialog::Add(SelectFileDialogExtension::RoutingID id,
+                        scoped_refptr<SelectFileDialogExtension> dialog) {
   DCHECK(dialog.get());
-  if (map_.find(tab_id) == map_.end())
-    map_.insert(std::make_pair(tab_id, dialog));
+  if (map_.find(id) == map_.end())
+    map_.insert(std::make_pair(id, dialog));
   else
-    DLOG(WARNING) << "Duplicate pending dialog " << tab_id;
+    DLOG(WARNING) << "Duplicate pending dialog " << id;
 }
 
-void PendingDialog::Remove(int32 tab_id) {
-  map_.erase(tab_id);
+void PendingDialog::Remove(SelectFileDialogExtension::RoutingID id) {
+  map_.erase(id);
 }
 
-scoped_refptr<SelectFileDialogExtension> PendingDialog::Find(int32 tab_id) {
-  Map::const_iterator it = map_.find(tab_id);
+scoped_refptr<SelectFileDialogExtension> PendingDialog::Find(
+    SelectFileDialogExtension::RoutingID id) {
+  Map::const_iterator it = map_.find(id);
   if (it == map_.end())
     return NULL;
   return it->second;
@@ -88,6 +92,16 @@
 
 /////////////////////////////////////////////////////////////////////////////
 
+// static
+SelectFileDialogExtension::RoutingID
+SelectFileDialogExtension::GetRoutingIDFromWebContents(
+    const content::WebContents* web_contents) {
+  // Use the raw pointer value as the identifier. Previously we have used the
+  // tab ID for the purpose, but some web_contents, especially those of the
+  // packaged apps, don't have tab IDs assigned.
+  return web_contents;
+}
+
 // TODO(jamescook): Move this into a new file shell_dialogs_chromeos.cc
 // static
 SelectFileDialogExtension* SelectFileDialogExtension::Create(
@@ -101,7 +115,7 @@
     ui::SelectFilePolicy* policy)
     : SelectFileDialog(listener, policy),
       has_multiple_file_type_choices_(false),
-      tab_id_(0),
+      routing_id_(),
       profile_(NULL),
       owner_window_(NULL),
       selection_type_(CANCEL),
@@ -122,7 +136,7 @@
 void SelectFileDialogExtension::ListenerDestroyed() {
   listener_ = NULL;
   params_ = NULL;
-  PendingDialog::GetInstance()->Remove(tab_id_);
+  PendingDialog::GetInstance()->Remove(routing_id_);
 }
 
 void SelectFileDialogExtension::ExtensionDialogClosing(
@@ -131,7 +145,7 @@
   owner_window_ = NULL;
   // Release our reference to the underlying dialog to allow it to close.
   extension_dialog_ = NULL;
-  PendingDialog::GetInstance()->Remove(tab_id_);
+  PendingDialog::GetInstance()->Remove(routing_id_);
   // Actually invoke the appropriate callback on our listener.
   NotifyListener();
 }
@@ -164,11 +178,11 @@
 
 // static
 void SelectFileDialogExtension::OnFileSelected(
-    int32 tab_id,
+    RoutingID routing_id,
     const ui::SelectedFileInfo& file,
     int index) {
   scoped_refptr<SelectFileDialogExtension> dialog =
-      PendingDialog::GetInstance()->Find(tab_id);
+      PendingDialog::GetInstance()->Find(routing_id);
   if (!dialog.get())
     return;
   dialog->selection_type_ = SINGLE_FILE;
@@ -179,10 +193,10 @@
 
 // static
 void SelectFileDialogExtension::OnMultiFilesSelected(
-    int32 tab_id,
+    RoutingID routing_id,
     const std::vector<ui::SelectedFileInfo>& files) {
   scoped_refptr<SelectFileDialogExtension> dialog =
-      PendingDialog::GetInstance()->Find(tab_id);
+      PendingDialog::GetInstance()->Find(routing_id);
   if (!dialog.get())
     return;
   dialog->selection_type_ = MULTIPLE_FILES;
@@ -191,9 +205,9 @@
 }
 
 // static
-void SelectFileDialogExtension::OnFileSelectionCanceled(int32 tab_id) {
+void SelectFileDialogExtension::OnFileSelectionCanceled(RoutingID routing_id) {
   scoped_refptr<SelectFileDialogExtension> dialog =
-      PendingDialog::GetInstance()->Find(tab_id);
+      PendingDialog::GetInstance()->Find(routing_id);
   if (!dialog.get())
     return;
   dialog->selection_type_ = CANCEL;
@@ -228,13 +242,13 @@
   }
 }
 
-void SelectFileDialogExtension::AddPending(int32 tab_id) {
-  PendingDialog::GetInstance()->Add(tab_id, this);
+void SelectFileDialogExtension::AddPending(RoutingID routing_id) {
+  PendingDialog::GetInstance()->Add(routing_id, this);
 }
 
 // static
-bool SelectFileDialogExtension::PendingExists(int32 tab_id) {
-  return PendingDialog::GetInstance()->Find(tab_id).get() != NULL;
+bool SelectFileDialogExtension::PendingExists(RoutingID routing_id) {
+  return PendingDialog::GetInstance()->Find(routing_id).get() != NULL;
 }
 
 bool SelectFileDialogExtension::HasMultipleFileTypeChoicesImpl() {
@@ -306,12 +320,10 @@
   DCHECK(profile_);
 
   // Check if we have another dialog opened for the contents. It's unlikely, but
-  // possible. If there is no web contents use a tab_id of -1. A dialog without
-  // an associated web contents will be shown full-screen; only one at a time
-  // is allowed in this state.
-  int32 tab_id = SessionID::IdForTab(web_contents);
-  if (PendingExists(tab_id)) {
-    DLOG(WARNING) << "Pending dialog exists with id " << tab_id;
+  // possible.
+  RoutingID routing_id = GetRoutingIDFromWebContents(web_contents);
+  if (PendingExists(routing_id)) {
+    DLOG(WARNING) << "Pending dialog exists with id " << routing_id;
     return;
   }
 
@@ -372,10 +384,10 @@
   }
 
   // Connect our listener to FileDialogFunction's per-tab callbacks.
-  AddPending(tab_id);
+  AddPending(routing_id);
 
   extension_dialog_ = dialog;
   params_ = params;
-  tab_id_ = tab_id;
+  routing_id_ = routing_id;
   owner_window_ = owner_window;
 }
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.h b/chrome/browser/ui/views/select_file_dialog_extension.h
index 7503f1b..260fbc9 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.h
+++ b/chrome/browser/ui/views/select_file_dialog_extension.h
@@ -18,6 +18,7 @@
 
 namespace content {
 class RenderViewHost;
+class WebContents;
 }
 
 namespace ui {
@@ -31,6 +32,12 @@
     : public ui::SelectFileDialog,
       public ExtensionDialogObserver {
  public:
+  // Opaque ID type for identifying the tab spawned each dialog, unique for
+  // every WebContents.
+  typedef const void* RoutingID;
+  static RoutingID GetRoutingIDFromWebContents(
+      const content::WebContents* web_contents);
+
   static SelectFileDialogExtension* Create(
       ui::SelectFileDialog::Listener* listener,
       ui::SelectFilePolicy* policy);
@@ -43,15 +50,15 @@
   virtual void ExtensionDialogClosing(ExtensionDialog* dialog) OVERRIDE;
   virtual void ExtensionTerminated(ExtensionDialog* dialog) OVERRIDE;
 
-  // Routes callback to appropriate SelectFileDialog::Listener based on
-  // the owning |tab_id|.
-  static void OnFileSelected(int32 tab_id,
+  // Routes callback to appropriate SelectFileDialog::Listener based on the
+  // owning |web_contents|.
+  static void OnFileSelected(RoutingID routing_id,
                              const ui::SelectedFileInfo& file,
                              int index);
   static void OnMultiFilesSelected(
-      int32 tab_id,
+      RoutingID routing_id,
       const std::vector<ui::SelectedFileInfo>& files);
-  static void OnFileSelectionCanceled(int32 tab_id);
+  static void OnFileSelectionCanceled(RoutingID routing_id);
 
   // For testing, so we can inject JavaScript into the contained view.
   content::RenderViewHost* GetRenderViewHost();
@@ -81,10 +88,10 @@
   void NotifyListener();
 
   // Adds this to the list of pending dialogs, used for testing.
-  void AddPending(int32 tab_id);
+  void AddPending(RoutingID routing_id);
 
-  // Check if the list of pending dialogs contains dialog for |tab_id|.
-  static bool PendingExists(int32 tab_id);
+  // Check if the list of pending dialogs contains dialog for |routing_id|.
+  static bool PendingExists(RoutingID routing_id);
 
   // Returns true if the dialog has multiple file type choices.
   virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
@@ -95,7 +102,7 @@
   scoped_refptr<ExtensionDialog> extension_dialog_;
 
   // ID of the tab that spawned this dialog, used to route callbacks.
-  int32 tab_id_;
+  RoutingID routing_id_;
 
   // Pointer to the profile the dialog is running in.
   Profile* profile_;
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc b/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc
index 1383534..2331a19 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc
@@ -10,7 +10,8 @@
 
 namespace {
 
-const int32 kDefaultTabId = 0;
+const SelectFileDialogExtension::RoutingID kDefaultRoutingID =
+    SelectFileDialogExtension::RoutingID();
 
 }  // namespace
 
@@ -25,9 +26,9 @@
     SelectFileDialogExtension* dialog = new SelectFileDialogExtension(listener,
                                                                       NULL);
     // Simulate the dialog opening.
-    EXPECT_FALSE(SelectFileDialogExtension::PendingExists(kDefaultTabId));
-    dialog->AddPending(kDefaultTabId);
-    EXPECT_TRUE(SelectFileDialogExtension::PendingExists(kDefaultTabId));
+    EXPECT_FALSE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID));
+    dialog->AddPending(kDefaultRoutingID);
+    EXPECT_TRUE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID));
     return dialog;
   }
 
@@ -92,7 +93,8 @@
       CreateDialog(listener.get());
   // Simulate selecting a file.
   ui::SelectedFileInfo info;
-  SelectFileDialogExtension::OnFileSelected(kDefaultTabId, info, kFileIndex);
+  SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, info,
+                                            kFileIndex);
   // Simulate closing the dialog so the listener gets invoked.
   dialog->ExtensionDialogClosing(NULL);
   EXPECT_TRUE(listener->selected());
@@ -104,7 +106,7 @@
   scoped_refptr<SelectFileDialogExtension> dialog =
       CreateDialog(listener.get());
   // Simulate cancelling the dialog.
-  SelectFileDialogExtension::OnFileSelectionCanceled(kDefaultTabId);
+  SelectFileDialogExtension::OnFileSelectionCanceled(kDefaultRoutingID);
   // Simulate closing the dialog so the listener gets invoked.
   dialog->ExtensionDialogClosing(NULL);
   EXPECT_FALSE(listener->selected());
@@ -116,7 +118,7 @@
   // Ensure we don't crash or trip an Address Sanitizer warning about
   // use-after-free.
   ui::SelectedFileInfo file_info;
-  SelectFileDialogExtension::OnFileSelected(kDefaultTabId, file_info, 0);
+  SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, file_info, 0);
   // Simulate closing the dialog so the listener gets invoked.
   client->dialog()->ExtensionDialogClosing(NULL);
 }
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector.cc b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
index d689f91..d6805e5 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
@@ -154,8 +154,6 @@
       web_contents_->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      window_->GetNativeView(), true);
 
   // Select the first row automatically.  This must be done after the dialog has
   // been created.
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
index 7484f40..7866f1b 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
@@ -41,7 +41,7 @@
         selector_(NULL) {
   }
 
-  virtual void SetUpInProcessBrowserTestFixture() {
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     base::FilePath certs_dir = net::GetTestCertsDirectory();
 
     mit_davidben_cert_ = net::ImportCertFromFile(certs_dir, "mit.davidben.der");
@@ -58,7 +58,7 @@
     cert_request_info_->client_certs.push_back(foaf_me_chromium_test_cert_);
   }
 
-  virtual void SetUpOnMainThread() {
+  virtual void SetUpOnMainThread() OVERRIDE {
     url_request_context_getter_ = browser()->profile()->GetRequestContext();
 
     BrowserThread::PostTask(
@@ -92,7 +92,7 @@
 
   // Have to release our reference to the auth handler during the test to allow
   // it to be destroyed while the Browser and its IO thread still exist.
-  virtual void CleanUpOnMainThread() {
+  virtual void CleanUpOnMainThread() OVERRIDE {
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::Bind(&SSLClientCertificateSelectorTest::CleanUpOnIOThread, this));
@@ -133,7 +133,7 @@
 class SSLClientCertificateSelectorMultiTabTest
     : public SSLClientCertificateSelectorTest {
  public:
-  virtual void SetUpInProcessBrowserTestFixture() {
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
 
     cert_request_info_1_ = new net::SSLCertRequestInfo;
@@ -147,7 +147,7 @@
     cert_request_info_2_->client_certs.push_back(foaf_me_chromium_test_cert_);
   }
 
-  virtual void SetUpOnMainThread() {
+  virtual void SetUpOnMainThread() OVERRIDE {
     // Also calls SetUpOnIOThread.
     SSLClientCertificateSelectorTest::SetUpOnMainThread();
 
@@ -179,7 +179,7 @@
     EXPECT_EQ(mit_davidben_cert_.get(), selector_2_->GetSelectedCert());
   }
 
-  virtual void SetUpOnIOThread() {
+  virtual void SetUpOnIOThread() OVERRIDE {
     url_request_1_ = MakeURLRequest(url_request_context_getter_);
     url_request_2_ = MakeURLRequest(url_request_context_getter_);
 
@@ -193,13 +193,13 @@
     SSLClientCertificateSelectorTest::SetUpOnIOThread();
   }
 
-  virtual void CleanUpOnMainThread() {
+  virtual void CleanUpOnMainThread() OVERRIDE {
     auth_requestor_2_ = NULL;
     auth_requestor_1_ = NULL;
     SSLClientCertificateSelectorTest::CleanUpOnMainThread();
   }
 
-  virtual void CleanUpOnIOThread() {
+  virtual void CleanUpOnIOThread() OVERRIDE {
     delete url_request_1_;
     delete url_request_2_;
     SSLClientCertificateSelectorTest::CleanUpOnIOThread();
@@ -219,7 +219,7 @@
 class SSLClientCertificateSelectorMultiProfileTest
     : public SSLClientCertificateSelectorTest {
  public:
-  virtual void SetUpInProcessBrowserTestFixture() {
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     SSLClientCertificateSelectorTest::SetUpInProcessBrowserTestFixture();
 
     cert_request_info_1_ = new net::SSLCertRequestInfo;
@@ -228,7 +228,7 @@
     cert_request_info_1_->client_certs.push_back(foaf_me_chromium_test_cert_);
   }
 
-  virtual void SetUpOnMainThread() {
+  virtual void SetUpOnMainThread() OVERRIDE {
     browser_1_ = CreateIncognitoBrowser();
     url_request_context_getter_1_ = browser_1_->profile()->GetRequestContext();
 
@@ -246,7 +246,7 @@
     EXPECT_EQ(mit_davidben_cert_.get(), selector_1_->GetSelectedCert());
   }
 
-  virtual void SetUpOnIOThread() {
+  virtual void SetUpOnIOThread() OVERRIDE {
     url_request_1_ = MakeURLRequest(url_request_context_getter_1_);
 
     auth_requestor_1_ = new StrictMock<SSLClientAuthRequestorMock>(
@@ -256,12 +256,12 @@
     SSLClientCertificateSelectorTest::SetUpOnIOThread();
   }
 
-  virtual void CleanUpOnMainThread() {
+  virtual void CleanUpOnMainThread() OVERRIDE {
     auth_requestor_1_ = NULL;
     SSLClientCertificateSelectorTest::CleanUpOnMainThread();
   }
 
-  virtual void CleanUpOnIOThread() {
+  virtual void CleanUpOnIOThread() OVERRIDE {
     delete url_request_1_;
     SSLClientCertificateSelectorTest::CleanUpOnIOThread();
   }
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
index 04dc7b8..47a0ebd 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
@@ -24,7 +24,6 @@
 #if defined(USE_AURA)
 #include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #else
 #include "chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h"
@@ -150,7 +149,7 @@
   // Convert from content coordinates to window coordinates.
   aura::Window* web_contents_window =
       web_contents_->GetView()->GetNativeView();
-  aura::RootWindow* root_window = web_contents_window->GetRootWindow();
+  aura::Window* root_window = web_contents_window->GetRootWindow();
   aura::client::ScreenPositionClient* screen_position_client =
       aura::client::GetScreenPositionClient(root_window);
   if (screen_position_client) {
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
index e7b1761..0c99fec 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
@@ -63,8 +63,6 @@
       web_contents->GetView()->GetNativeView(),
       modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView());
-  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
-      dialog_->GetNativeView(), true);
   delegate_->set_close_delegate(this);
 }
 
diff --git a/chrome/browser/ui/views/tabs/dock_info_win.cc b/chrome/browser/ui/views/tabs/dock_info_win.cc
index 07325b7..ad8abc8 100644
--- a/chrome/browser/ui/views/tabs/dock_info_win.cc
+++ b/chrome/browser/ui/views/tabs/dock_info_win.cc
@@ -304,7 +304,7 @@
   std::set<HWND> hwnd_set;
   std::set<gfx::NativeView>::const_iterator it = ignore.begin();
   for (; it != ignore.end(); ++it) {
-    HWND w = (*it)->GetRootWindow()->GetAcceleratedWidget();
+    HWND w = (*it)->GetDispatcher()->GetAcceleratedWidget();
     if (w)
       hwnd_set.insert(w);
   }
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 6990ce3..0e32d9b 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -883,6 +883,13 @@
 }
 
 bool Tab::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+  // TODO(miu): Rectify inconsistent tooltip behavior.  http://crbug.com/310947
+
+  if (data_.media_state != TAB_MEDIA_STATE_NONE) {
+    *tooltip = chrome::AssembleTabTooltipText(data_.title, data_.media_state);
+    return true;
+  }
+
   if (data_.title.empty())
     return false;
 
@@ -1462,9 +1469,7 @@
 
 void Tab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) {
   // Paint the Title.
-  const gfx::Rect& title_bounds = GetTitleBounds();
   string16 title = data().title;
-
   if (title.empty()) {
     title = data().loading ?
         l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
@@ -1473,8 +1478,8 @@
     Browser::FormatTitleForDisplay(&title);
   }
 
-  canvas->DrawFadeTruncatingString(title, gfx::Canvas::TruncateFadeTail, 0,
-                                   *font_, title_color, title_bounds);
+  canvas->DrawFadeTruncatingStringRect(title, gfx::Canvas::TruncateFadeTail,
+      gfx::FontList(*font_), title_color, GetTitleBounds());
 }
 
 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index ba0564b..bb452ef 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -50,8 +50,7 @@
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_ASH)
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
+#include "ash/accelerators/accelerator_commands.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/env.h"
@@ -209,6 +208,16 @@
 #endif
 }
 
+// Returns true if |tab_strip| browser window is docked.
+bool IsDocked(const TabStrip* tab_strip) {
+#if defined(USE_ASH)
+  DCHECK(tab_strip);
+  return ash::wm::GetWindowState(
+      tab_strip->GetWidget()->GetNativeWindow())->IsDocked();
+#endif
+  return false;
+}
+
 // Returns true if |bounds| contains the y-coordinate |y|. The y-coordinate
 // of |bounds| is adjusted by |vertical_adjustment|.
 bool DoesRectContainVerticalPointExpanded(
@@ -484,7 +493,7 @@
 }
 
 // static
-bool TabDragController::IsAttachedTo(TabStrip* tab_strip) {
+bool TabDragController::IsAttachedTo(const TabStrip* tab_strip) {
   return (instance_ && instance_->active() &&
           instance_->attached_tabstrip() == tab_strip);
 }
@@ -1411,10 +1420,26 @@
   gfx::Vector2d drag_offset;
   Browser* browser = CreateBrowserForDrag(
       attached_tabstrip_, point_in_screen, &drag_offset, &drag_bounds);
-  Detach(DONT_RELEASE_CAPTURE);
+#if defined(OS_WIN) && defined(USE_AURA)
+  gfx::NativeView attached_native_view =
+    attached_tabstrip_->GetWidget()->GetNativeView();
+#endif
+  Detach(host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH ?
+         DONT_RELEASE_CAPTURE : RELEASE_CAPTURE);
   BrowserView* dragged_browser_view =
       BrowserView::GetBrowserViewForBrowser(browser);
   views::Widget* dragged_widget = dragged_browser_view->GetWidget();
+#if defined(OS_WIN) && defined(USE_AURA)
+    // The Gesture recognizer does not work well currently when capture changes
+    // while a touch gesture is in progress. So we need to manually transfer
+    // gesture sequence and the GR's touch events queue to the new window. This
+    // should really be done somewhere in capture change code and or inside the
+    // GR. But we currently do not have a consistent way for doing it that would
+    // work in all cases. Hence this hack.
+    ui::GestureRecognizer::Get()->TransferEventsTo(
+        attached_native_view,
+        dragged_widget->GetNativeView());
+#endif
   dragged_widget->SetVisibilityChangedAnimationsEnabled(false);
   Attach(dragged_browser_view->tabstrip(), gfx::Point());
   attached_tabstrip_->InvalidateLayout();
@@ -1872,6 +1897,11 @@
 
   if (attached_tabstrip_) {
     if (is_dragging_new_browser_) {
+      if (IsDocked(attached_tabstrip_)) {
+        DCHECK_EQ(host_desktop_type_, chrome::HOST_DESKTOP_TYPE_ASH);
+        was_source_maximized_ = false;
+        was_source_fullscreen_ = false;
+      }
       // If source window was maximized - maximize the new window as well.
       if (was_source_maximized_)
         attached_tabstrip_->GetWidget()->Maximize();
@@ -1880,9 +1910,17 @@
           host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH) {
         // In fullscreen mode it is only possible to get here if the source
         // was in "immersive fullscreen" mode, so toggle it back on.
-        ash::Shell::GetInstance()->delegate()->ToggleFullscreen();
+        ash::accelerators::ToggleFullscreen();
       }
 #endif
+    } else {
+      // When dragging results in maximized or fullscreen browser window getting
+      // docked, restore it.
+      if ((was_source_fullscreen_ || was_source_maximized_) &&
+          (IsDocked(attached_tabstrip_))) {
+        DCHECK_EQ(host_desktop_type_, chrome::HOST_DESKTOP_TYPE_ASH);
+        attached_tabstrip_->GetWidget()->Restore();
+      }
     }
     attached_tabstrip_->StoppedDraggingTabs(
         GetTabsMatchingDraggedContents(attached_tabstrip_),
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index dd86233..67ad0d9 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -109,7 +109,7 @@
   // |tab_strip|.
   // NOTE: this returns false if the TabDragController is in the process of
   // finishing the drag.
-  static bool IsAttachedTo(TabStrip* tab_strip);
+  static bool IsAttachedTo(const TabStrip* tab_strip);
 
   // Returns true if there is a drag underway.
   static bool IsActive();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 54b91d5..1e1ea17 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
@@ -43,13 +42,15 @@
 #endif
 
 #if defined(USE_ASH)
+#include "ash/ash_switches.h"
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
 #include "ash/test/cursor_manager_test_api.h"
 #include "ash/wm/coordinate_conversion.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
-#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/event_generator.h"
@@ -223,14 +224,14 @@
 #if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
 class ScreenEventGeneratorDelegate : public aura::test::EventGeneratorDelegate {
  public:
-  explicit ScreenEventGeneratorDelegate(aura::RootWindow* root_window)
+  explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
       : root_window_(root_window) {}
   virtual ~ScreenEventGeneratorDelegate() {}
 
   // EventGeneratorDelegate overrides:
   virtual aura::RootWindow* GetRootWindowAt(
       const gfx::Point& point) const OVERRIDE {
-    return root_window_;
+    return root_window_->GetDispatcher();
   }
 
   virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
@@ -239,7 +240,7 @@
   }
 
  private:
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
 };
@@ -339,6 +340,12 @@
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     command_line->AppendSwitch(switches::kTabBrowserDragging);
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
+    if (docked_windows_enabled()) {
+      CommandLine::ForCurrentProcess()->AppendSwitch(
+          ash::switches::kAshEnableDockedWindows);
+    }
+#endif
   }
 
   virtual void SetUpOnMainThread() OVERRIDE {
@@ -349,10 +356,14 @@
   }
 
   InputSource input_source() const {
-    return !strcmp(GetParam(), "mouse") ?
+    return strstr(GetParam(), "mouse") ?
         INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
   }
 
+  bool docked_windows_enabled() const {
+    return (strstr(GetParam(), "docked") != NULL);
+  }
+
   // Set root window from a point in screen coordinates
   void SetEventGeneratorRootWindow(const gfx::Point& point) {
     if (input_source() == INPUT_SOURCE_MOUSE)
@@ -371,7 +382,7 @@
           ui_test_utils::SendMouseEventsSync(
               ui_controls::LEFT, ui_controls::DOWN);
     }
-#if defined(USE_ASH)  && !defined(OS_WIN)  // TODO(win_ash)
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
     event_generator_->set_current_location(location);
     event_generator_->PressTouch();
 #else
@@ -380,6 +391,19 @@
     return true;
   }
 
+  bool PressInput2() {
+    // Second touch input is only used for touch sequence tests.
+    EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
+    event_generator_->set_current_location(
+        event_generator_->current_location());
+    event_generator_->PressTouchId(1);
+#else
+    NOTREACHED();
+#endif
+    return true;
+  }
+
   bool DragInputTo(const gfx::Point& location) {
     if (input_source() == INPUT_SOURCE_MOUSE)
       return ui_test_utils::SendMouseMoveSync(location);
@@ -416,6 +440,35 @@
     return true;
   }
 
+  bool DragInputToDelayedNotifyWhenDone(int x,
+                                        int y,
+                                        const base::Closure& task,
+                                        base::TimeDelta delay) {
+    if (input_source() == INPUT_SOURCE_MOUSE)
+      return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
+    base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
+    event_generator_->MoveTouch(gfx::Point(x, y));
+#else
+    NOTREACHED();
+#endif
+    return true;
+  }
+
+  bool DragInput2ToNotifyWhenDone(int x,
+                                 int y,
+                                 const base::Closure& task) {
+    if (input_source() == INPUT_SOURCE_MOUSE)
+      return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
+    base::MessageLoop::current()->PostTask(FROM_HERE, task);
+    event_generator_->MoveTouchId(gfx::Point(x, y), 1);
+#else
+    NOTREACHED();
+#endif
+    return true;
+  }
+
   bool ReleaseInput() {
     if (input_source() == INPUT_SOURCE_MOUSE) {
       return ui_test_utils::SendMouseEventsSync(
@@ -429,6 +482,19 @@
     return true;
   }
 
+  bool ReleaseInput2() {
+    if (input_source() == INPUT_SOURCE_MOUSE) {
+      return ui_test_utils::SendMouseEventsSync(
+              ui_controls::LEFT, ui_controls::UP);
+    }
+#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
+    event_generator_->ReleaseTouchId(1);
+#else
+    NOTREACHED();
+#endif
+    return true;
+  }
+
   bool ReleaseMouseAsync() {
     return input_source() == INPUT_SOURCE_MOUSE &&
         ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
@@ -502,15 +568,9 @@
 
 }  // namespace
 
-#if defined(OS_WIN) && defined(USE_AURA)
-#define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
-#else
-#define MAYBE_DragToSeparateWindow DragToSeparateWindow
-#endif
-
 // Creates two browsers, drags from first into second.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
-                       MAYBE_DragToSeparateWindow) {
+                       DragToSeparateWindow) {
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
@@ -615,7 +675,7 @@
 
   EXPECT_TRUE(GetTrackedByWorkspace(browser()));
   EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
-  // After this both windows should still be managable.
+  // After this both windows should still be manageable.
   EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
   EXPECT_TRUE(IsWindowPositionManaged(
       new_browser->window()->GetNativeWindow()));
@@ -673,7 +733,7 @@
 
   EXPECT_TRUE(GetTrackedByWorkspace(browser()));
   EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
-  // After this both windows should still be managable.
+  // After this both windows should still be manageable.
   EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
   EXPECT_TRUE(IsWindowPositionManaged(
       new_browser->window()->GetNativeWindow()));
@@ -875,14 +935,8 @@
 
 }  // namespace
 
-// Flaky on Windows Aura. crbug.com/309054
-#if defined(OS_WIN) && defined(USE_AURA)
-#define MAYBE_DragAll DISABLED_DragAll
-#else
-#define MAYBE_DragAll DragAll
-#endif
 // Selects multiple tabs and starts dragging the window.
-IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragAll) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
@@ -1255,12 +1309,13 @@
   EXPECT_TRUE(new_browser->window()->IsMaximized());
 }
 
-// Subclass of DetachToBrowserInSeparateDisplayTabDragControllerTest that
+// Subclass of DetachToBrowserTabDragControllerTest that
 // creates multiple displays.
 class DetachToBrowserInSeparateDisplayTabDragControllerTest
     : public DetachToBrowserTabDragControllerTest {
  public:
   DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
+  virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
@@ -1274,6 +1329,18 @@
       DetachToBrowserInSeparateDisplayTabDragControllerTest);
 };
 
+// Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
+// touch input.
+class DetachToBrowserTabDragControllerTestTouch
+    : public DetachToBrowserTabDragControllerTest {
+ public:
+  DetachToBrowserTabDragControllerTestTouch() {}
+  virtual ~DetachToBrowserTabDragControllerTestTouch() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
+};
+
 namespace {
 
 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
@@ -1549,9 +1616,6 @@
 // second display and releases input.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
                        DragTabToImmersiveBrowserOnSeparateDisplay) {
-  ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-  ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-
   // Add another tab.
   AddTabAndResetBrowser(browser());
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
@@ -1573,10 +1637,9 @@
 
   // Put the second browser into immersive fullscreen.
   BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
-  ImmersiveModeControllerAsh* immersive_controller2 =
-      static_cast<ImmersiveModeControllerAsh*>(
-          browser_view2->immersive_mode_controller());
-  immersive_controller2->DisableAnimationsForTest();
+  ImmersiveModeController* immersive_controller2 =
+      browser_view2->immersive_mode_controller();
+  immersive_controller2->SetupForTest();
   chrome::ToggleFullscreenMode(browser2);
   ASSERT_TRUE(immersive_controller2->IsEnabled());
   ASSERT_FALSE(immersive_controller2->IsRevealed());
@@ -1622,10 +1685,13 @@
 }
 #endif  // OS_CHROMEOS
 
+// Subclass of DetachToBrowserTabDragControllerTest that
+// creates multiple displays with different device scale factors.
 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
     : public DetachToBrowserTabDragControllerTest {
  public:
   DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
+  virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
@@ -1874,6 +1940,204 @@
       ui_controls::LEFT, ui_controls::UP));
 }
 
+namespace {
+
+void DetachToOwnWindowTwoFingersDragStep5(
+    DetachToBrowserTabDragControllerTest* test) {
+  ASSERT_EQ(2u, test->native_browser_list->size());
+  Browser* new_browser = test->native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+
+  ASSERT_TRUE(test->ReleaseInput());
+  ASSERT_TRUE(test->ReleaseInput2());
+  ASSERT_TRUE(new_browser->window()->IsActive());
+}
+
+void DetachToOwnWindowTwoFingersDragStep4(
+    DetachToBrowserTabDragControllerTest* test,
+    const gfx::Point& target_point) {
+  ASSERT_EQ(2u, test->native_browser_list->size());
+  Browser* new_browser = test->native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+
+  ASSERT_TRUE(test->DragInput2ToNotifyWhenDone(
+      target_point.x(), target_point.y(),
+      base::Bind(&DetachToOwnWindowTwoFingersDragStep5, test)));
+}
+
+void DetachToOwnWindowTwoFingersDragStep3(
+    DetachToBrowserTabDragControllerTest* test,
+    const gfx::Point& target_point) {
+  ASSERT_TRUE(test->PressInput2());
+
+  ASSERT_EQ(2u, test->native_browser_list->size());
+  Browser* new_browser = test->native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+
+  ASSERT_TRUE(test->DragInputToDelayedNotifyWhenDone(
+      target_point.x(), target_point.y(),
+      base::Bind(&DetachToOwnWindowTwoFingersDragStep4,
+                 test,
+                 target_point),
+      base::TimeDelta::FromMilliseconds(60)));
+}
+
+void DetachToOwnWindowTwoFingersDragStep2(
+    DetachToBrowserTabDragControllerTest* test,
+    const gfx::Point& target_point) {
+  ASSERT_EQ(2u, test->native_browser_list->size());
+  Browser* new_browser = test->native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+
+  ASSERT_TRUE(test->DragInputToDelayedNotifyWhenDone(
+      target_point.x(), target_point.y(),
+      base::Bind(&DetachToOwnWindowTwoFingersDragStep3,
+                 test,
+                 target_point + gfx::Vector2d(-2, 1)),
+      base::TimeDelta::FromMilliseconds(60)));
+}
+
+}  // namespace
+
+// Drags from browser to separate window starting with one finger and
+// then continuing with two fingers.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
+                       DetachToOwnWindowTwoFingers) {
+  gfx::Rect bounds(browser()->window()->GetBounds());
+  // Add another tab.
+  AddTabAndResetBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+
+  // Move to the first tab and drag it enough so that it detaches.
+  gfx::Point tab_0_center(
+      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
+  ASSERT_TRUE(PressInput(tab_0_center));
+  // Drags in this test are very short to avoid fling.
+  ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
+                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
+                  base::Bind(&DetachToOwnWindowTwoFingersDragStep2,
+                             this, gfx::Point(5 + tab_0_center.x(),
+                                              1 + tab_0_center.y()
+                                              + GetDetachY(tab_strip))),
+                  base::TimeDelta::FromMilliseconds(60)));
+  // Continue dragging, first with one finger, then with two fingers.
+  QuitWhenNotDragging();
+
+  // There should now be another browser.
+  ASSERT_EQ(2u, native_browser_list->size());
+  Browser* new_browser = native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+  // The sequence of drags should successfully move the browser window.
+  bounds += gfx::Vector2d(5 - 2, 1 + 1 + GetDetachY(tab_strip));
+  EXPECT_EQ(bounds.ToString(),
+            new_browser->window()->GetNativeWindow()->bounds().ToString());
+}
+
+// Subclass of DetachToBrowserTabDragControllerTest that runs tests with
+// docked windows enabled and disabled.
+class DetachToDockedTabDragControllerTest
+    : public DetachToBrowserTabDragControllerTest {
+ public:
+  DetachToDockedTabDragControllerTest() {}
+  virtual ~DetachToDockedTabDragControllerTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DetachToDockedTabDragControllerTest);
+};
+
+namespace {
+
+void DetachToDockedWindowNextStep(
+    DetachToDockedTabDragControllerTest* test,
+    const gfx::Point& target_point,
+    int iteration) {
+  ASSERT_EQ(2u, test->native_browser_list->size());
+  Browser* new_browser = test->native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+
+  if (!iteration) {
+    ASSERT_TRUE(test->ReleaseInput());
+    return;
+  }
+  ASSERT_TRUE(test->DragInputToNotifyWhenDone(
+      target_point.x(), target_point.y(),
+      base::Bind(&DetachToDockedWindowNextStep,
+                 test,
+                 gfx::Point(target_point.x(), 1 + target_point.y()),
+                 iteration - 1)));
+}
+
+}  // namespace
+
+// Drags from browser to separate window, docks that window and releases mouse.
+IN_PROC_BROWSER_TEST_P(DetachToDockedTabDragControllerTest,
+                       DetachToDockedWindowFromMaximizedWindow) {
+  if (!TabDragController::ShouldDetachIntoNewBrowser()) {
+    VLOG(1)
+        << "Skipping DetachToDockedWindowFromMaximizedWindow on this platform.";
+    return;
+  }
+
+  // Maximize the initial browser window.
+  browser()->window()->Maximize();
+  ASSERT_TRUE(browser()->window()->IsMaximized());
+
+  // Add another tab.
+  AddTabAndResetBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+
+  // Move to the first tab and drag it enough so that it detaches.
+  gfx::Point tab_0_center(
+      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
+  ASSERT_TRUE(PressInput(tab_0_center));
+
+  // The following matches kMovesBeforeAdjust in snap_sizer.cc
+  const int kNumIterations = 25 * 5 + 10;
+  ASSERT_TRUE(DragInputToNotifyWhenDone(
+      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
+      base::Bind(&DetachToDockedWindowNextStep, this,
+                 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
+                 kNumIterations)));
+  // Continue dragging enough times to go through snapping sequence and dock
+  // the window.
+  QuitWhenNotDragging();
+  // Should no longer be dragging.
+  ASSERT_FALSE(tab_strip->IsDragSessionActive());
+  ASSERT_FALSE(TabDragController::IsActive());
+
+  // There should now be another browser.
+  ASSERT_EQ(2u, native_browser_list->size());
+  Browser* new_browser = native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
+  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
+
+  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
+  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
+
+  // The bounds of the initial window should not have changed.
+  EXPECT_TRUE(browser()->window()->IsMaximized());
+
+  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
+  EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
+  // After this both windows should still be manageable.
+  EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
+  EXPECT_TRUE(IsWindowPositionManaged(
+      new_browser->window()->GetNativeWindow()));
+
+  // The new window should be docked and not maximized if docking is allowed.
+  ash::wm::WindowState* window_state =
+      ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
+  if (docked_windows_enabled()) {
+    EXPECT_FALSE(new_browser->window()->IsMaximized());
+    EXPECT_TRUE(window_state->IsDocked());
+  } else {
+    EXPECT_TRUE(new_browser->window()->IsMaximized());
+    EXPECT_FALSE(window_state->IsDocked());
+  }
+}
+
+
 #endif
 
 #if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
@@ -1886,6 +2150,12 @@
 INSTANTIATE_TEST_CASE_P(TabDragging,
                         DetachToBrowserTabDragControllerTest,
                         ::testing::Values("mouse", "touch"));
+INSTANTIATE_TEST_CASE_P(TabDragging,
+                        DetachToDockedTabDragControllerTest,
+                        ::testing::Values("mouse", "mouse docked"));
+INSTANTIATE_TEST_CASE_P(TabDragging,
+                        DetachToBrowserTabDragControllerTestTouch,
+                        ::testing::Values("touch", "touch docked"));
 #else
 INSTANTIATE_TEST_CASE_P(TabDragging,
                         DetachToBrowserTabDragControllerTest,
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 0e3ac65..1597635 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1557,7 +1557,8 @@
 void TabStrip::OnGestureEvent(ui::GestureEvent* event) {
   SetResetToShrinkOnExit(false);
   switch (event->type()) {
-    case ui::ET_GESTURE_END:
+    case ui::ET_GESTURE_SCROLL_END:
+    case ui::ET_SCROLL_FLING_START:
       EndDrag(END_DRAG_COMPLETE);
       if (adjust_layout_) {
         SetLayoutType(TAB_STRIP_LAYOUT_STACKED, true);
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index c16a508..23d564d 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -83,8 +83,7 @@
     // Tab size and TabRendererData state.
     if (tab.data_.mini) {
       EXPECT_EQ(1, tab.IconCapacity());
-      if (tab.data_.media_state == TAB_MEDIA_STATE_CAPTURING ||
-          tab.data_.media_state == TAB_MEDIA_STATE_RECORDING) {
+      if (tab.data_.media_state != TAB_MEDIA_STATE_NONE) {
         EXPECT_FALSE(tab.ShouldShowIcon());
         EXPECT_TRUE(tab.ShouldShowMediaIndicator());
       } else {
@@ -101,8 +100,7 @@
           EXPECT_FALSE(tab.ShouldShowMediaIndicator());
           break;
         case 2:
-          if (tab.data_.media_state == TAB_MEDIA_STATE_CAPTURING ||
-              tab.data_.media_state == TAB_MEDIA_STATE_RECORDING) {
+          if (tab.data_.media_state != TAB_MEDIA_STATE_NONE) {
             EXPECT_FALSE(tab.ShouldShowIcon());
             EXPECT_TRUE(tab.ShouldShowMediaIndicator());
           } else {
@@ -128,8 +126,7 @@
           break;
         case 1:
           EXPECT_FALSE(tab.ShouldShowCloseBox());
-          if (tab.data_.media_state == TAB_MEDIA_STATE_CAPTURING ||
-              tab.data_.media_state == TAB_MEDIA_STATE_RECORDING) {
+          if (tab.data_.media_state != TAB_MEDIA_STATE_NONE) {
             EXPECT_FALSE(tab.ShouldShowIcon());
             EXPECT_TRUE(tab.ShouldShowMediaIndicator());
           } else {
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 5418e0d..daecc8e 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -8,11 +8,11 @@
 #include "base/compiler_specific.h"
 #include "base/metrics/stats_table.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/memory_purger.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc
index b9f31af..da4dad4 100644
--- a/chrome/browser/ui/views/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar_view.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/ui/views/home_button.h"
 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
+#include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
 #include "chrome/browser/ui/views/wrench_menu.h"
 #include "chrome/browser/ui/views/wrench_toolbar_button.h"
@@ -224,8 +225,6 @@
   app_menu_->SetTooltipText(l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP));
   app_menu_->set_id(VIEW_ID_APP_MENU);
 
-  // Add any necessary badges to the menu item based on the system state.
-  UpdateAppMenuState();
   LoadImages();
 
   // Always add children in order from left to right, for accessibility.
@@ -237,6 +236,11 @@
   AddChildView(browser_actions_);
   AddChildView(app_menu_);
 
+  // Add any necessary badges to the menu item based on the system state.
+  // Do this after |app_menu_| has been added as a bubble may be shown that
+  // needs the widget (widget found by way of app_menu_->GetWidget()).
+  UpdateAppMenuState();
+
   location_bar_->Init();
   show_home_button_.Init(prefs::kShowHomeButton,
                          browser_->profile()->GetPrefs(),
@@ -289,6 +293,13 @@
   return app_menu_;
 }
 
+views::View* ToolbarView::GetTranslateBubbleAnchor() {
+  views::View* translate_icon_view = location_bar()->translate_icon_view();
+  if (translate_icon_view)
+    return translate_icon_view;
+  return app_menu_;
+}
+
 views::MenuButton* ToolbarView::app_menu() const {
   return app_menu_;
 }
@@ -755,6 +766,10 @@
 }
 
 void ToolbarView::UpdateWrenchButtonSeverity() {
+  // Showing the bubble requires |app_menu_| to be in a widget. See comment
+  // in ConflictingModuleView for details.
+  DCHECK(app_menu_->GetWidget());
+
   // Keep track of whether we were showing the badge before, so we don't send
   // multiple UMA events for example when multiple Chrome windows are open.
   static bool incompatibility_badge_showing = false;
diff --git a/chrome/browser/ui/views/toolbar_view.h b/chrome/browser/ui/views/toolbar_view.h
index a146d0f..1ddfc05 100644
--- a/chrome/browser/ui/views/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar_view.h
@@ -76,6 +76,9 @@
   // Returns the view to which the bookmark bubble should be anchored.
   views::View* GetBookmarkBubbleAnchor();
 
+  // Returns the view to which the Translate bubble should be anchored.
+  views::View* GetTranslateBubbleAnchor();
+
   // Accessors...
   Browser* browser() const { return browser_; }
   BrowserActionsContainer* browser_actions() const { return browser_actions_; }
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
index f24b936..10bcd2b 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -160,6 +160,11 @@
   return translate_bubble_view_ != NULL;
 }
 
+// static
+TranslateBubbleView* TranslateBubbleView::GetCurrentBubble() {
+  return translate_bubble_view_;
+}
+
 void TranslateBubbleView::Init() {
   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
                                         0, 0, 0));
@@ -187,8 +192,10 @@
 }
 
 void TranslateBubbleView::WindowClosing() {
-  if (!translate_executed_)
+  if (!translate_executed_ &&
+      (browser_ == NULL || !browser_->IsAttemptingToCloseBrowser())) {
     model_->TranslationDeclined();
+  }
 
   // We have to reset |translate_bubble_view_| here, not in our destructor,
   // because we'll be destroyed asynchronously and the shown state will be
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h
index 937ced2..82e9a4f 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.h
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -48,6 +48,11 @@
   // If true, the Translate bubble is being shown.
   static bool IsShowing();
 
+  // Returns the bubble view currently shown. This may return NULL.
+  static TranslateBubbleView* GetCurrentBubble();
+
+  TranslateBubbleModel* model() { return model_.get(); }
+
   // views::BubbleDelegateView methods.
   virtual void Init() OVERRIDE;
   virtual void ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/uninstall_view.cc b/chrome/browser/ui/views/uninstall_view.cc
index 2bcadbd..cdc8405 100644
--- a/chrome/browser/ui/views/uninstall_view.cc
+++ b/chrome/browser/ui/views/uninstall_view.cc
@@ -82,7 +82,8 @@
   // be set programatically as default, neither can any other browser (for
   // instance because the OS doesn't permit that).
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  if (dist->CanSetAsDefault() &&
+  if (dist->GetDefaultBrowserControlPolicy() !=
+          BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED &&
       ShellIntegration::GetDefaultBrowser() == ShellIntegration::IS_DEFAULT &&
       (ShellIntegration::CanSetAsDefaultBrowser() !=
           ShellIntegration::SET_DEFAULT_INTERACTIVE)) {
diff --git a/chrome/browser/ui/webui/OWNERS b/chrome/browser/ui/webui/OWNERS
index dfafdfb..648c511 100644
--- a/chrome/browser/ui/webui/OWNERS
+++ b/chrome/browser/ui/webui/OWNERS
@@ -8,6 +8,7 @@
 pam@chromium.org
 xiyuan@chromium.org
 
+per-file inspect_ui*=kaznacheev@chromium.org
 per-file inspect_ui*=pfeldman@chromium.org
 per-file sync_setup_handler*=atwilson@chromium.org
 per-file sync_setup_handler*=rogerta@chromium.org
diff --git a/chrome/browser/ui/webui/app_list/start_page_handler.cc b/chrome/browser/ui/webui/app_list/start_page_handler.cc
index 51b6a8d..be7e7ab 100644
--- a/chrome/browser/ui/webui/app_list/start_page_handler.cc
+++ b/chrome/browser/ui/webui/app_list/start_page_handler.cc
@@ -16,9 +16,11 @@
 #include "chrome/browser/ui/app_list/app_list_service.h"
 #include "chrome/browser/ui/app_list/recommended_apps.h"
 #include "chrome/browser/ui/app_list/start_page_service.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_icon_set.h"
+#include "content/public/browser/web_contents_view.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/events/event_constants.h"
 
@@ -105,8 +107,11 @@
     return;
   }
 
+  AppListService* app_list_service = AppListService::Get(
+      chrome::GetHostDesktopTypeForNativeView(
+          web_ui()->GetWebContents()->GetView()->GetNativeView()));
   scoped_ptr<AppListControllerDelegate> controller(
-      AppListService::Get()->CreateControllerDelegate());
+      app_list_service->CreateControllerDelegate());
   controller->ActivateApp(profile,
                           app,
                           AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.cc b/chrome/browser/ui/webui/certificate_viewer_webui.cc
index e5dc6d5..aef05ef 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.cc
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.cc
@@ -21,11 +21,9 @@
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/size.h"
-#include "ui/web_dialogs/web_dialog_observer.h"
 
 using content::WebContents;
 using content::WebUIMessageHandler;
-using ui::WebDialogObserver;
 using web_modal::NativeWebContentsModalDialog;
 
 // Shows a certificate using the WebUI certificate viewer.
@@ -39,16 +37,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 // CertificateViewerDialog
 
-void CertificateViewerDialog::AddObserver(WebDialogObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void CertificateViewerDialog::RemoveObserver(WebDialogObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
 CertificateViewerDialog::CertificateViewerDialog(net::X509Certificate* cert)
-    : cert_(cert), window_(NULL) {
+    : cert_(cert), dialog_(NULL) {
   // Construct the dialog title from the certificate.
   net::X509Certificate::OSCertHandles cert_chain;
   x509_certificate_model::GetCertChainFromCert(cert_->os_cert_handle(),
@@ -64,12 +54,11 @@
                                    gfx::NativeWindow parent) {
   // TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
   // on the title for Aura ConstrainedWebDialogUI.
-  NativeWebContentsModalDialog dialog = CreateConstrainedWebDialog(
+  dialog_ = CreateConstrainedWebDialog(
       web_contents->GetBrowserContext(),
       this,
       NULL,
-      web_contents)->GetNativeDialog();
-  window_ = platform_util::GetTopLevel(dialog);
+      web_contents);
 }
 
 ui::ModalType CertificateViewerDialog::GetDialogModalType() const {
@@ -86,7 +75,8 @@
 
 void CertificateViewerDialog::GetWebUIMessageHandlers(
     std::vector<WebUIMessageHandler*>* handlers) const {
-  handlers->push_back(new CertificateViewerDialogHandler(window_, cert_.get()));
+  handlers->push_back(new CertificateViewerDialogHandler(
+      const_cast<CertificateViewerDialog*>(this), cert_.get()));
 }
 
 void CertificateViewerDialog::GetDialogSize(gfx::Size* size) const {
@@ -195,9 +185,6 @@
 void CertificateViewerDialog::OnDialogShown(
     content::WebUI* webui,
     content::RenderViewHost* render_view_host) {
-  FOR_EACH_OBSERVER(WebDialogObserver,
-                    observers_,
-                    OnDialogShown(webui, render_view_host));
 }
 
 void CertificateViewerDialog::OnDialogClosed(const std::string& json_retval) {
@@ -217,8 +204,8 @@
 // CertificateViewerDialogHandler
 
 CertificateViewerDialogHandler::CertificateViewerDialogHandler(
-    gfx::NativeWindow window,
-    net::X509Certificate* cert) : cert_(cert), window_(window) {
+    CertificateViewerDialog* dialog,
+    net::X509Certificate* cert) : cert_(cert), dialog_(dialog) {
   x509_certificate_model::GetCertChainFromCert(cert_->os_cert_handle(),
       &cert_chain_);
 }
@@ -241,8 +228,10 @@
   if (cert_index < 0)
     return;
 
+  NativeWebContentsModalDialog window =
+      platform_util::GetTopLevel(dialog_->dialog()->GetNativeDialog());
   ShowCertExportDialog(web_ui()->GetWebContents(),
-                       window_,
+                       window,
                        cert_chain_[cert_index]);
 }
 
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.h b/chrome/browser/ui/webui/certificate_viewer_webui.h
index 726cdd7..410300d 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.h
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/observer_list.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/cert/x509_certificate.h"
@@ -20,9 +19,7 @@
 class WebContents;
 }
 
-namespace ui {
-class WebDialogObserver;
-}
+class ConstrainedWebDialogDelegate;
 
 // Dialog for displaying detailed certificate information. This is used in linux
 // and chromeos builds to display detailed information in a floating dialog when
@@ -39,11 +36,7 @@
   // Show the dialog using the given parent window.
   void Show(content::WebContents* web_contents, gfx::NativeWindow parent);
 
-  // Add WebDialogObserver for this dialog.
-  void AddObserver(ui::WebDialogObserver* observer);
-
-  // Remove WebDialogObserver for this dialog.
-  void RemoveObserver(ui::WebDialogObserver* observer);
+  ConstrainedWebDialogDelegate* dialog() { return dialog_; }
 
  private:
   // Overridden from ui::WebDialogDelegate:
@@ -65,14 +58,11 @@
   // The certificate being viewed.
   scoped_refptr<net::X509Certificate> cert_;
 
-  // The window displaying this dialog.
-  gfx::NativeWindow window_;
+  ConstrainedWebDialogDelegate* dialog_;
 
   // The title of the certificate viewer dialog, Certificate Viewer: CN.
   string16 title_;
 
-  ObserverList<ui::WebDialogObserver> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(CertificateViewerDialog);
 };
 
@@ -80,7 +70,7 @@
 // details and export the certificate.
 class CertificateViewerDialogHandler : public content::WebUIMessageHandler {
  public:
-  CertificateViewerDialogHandler(gfx::NativeWindow window,
+  CertificateViewerDialogHandler(CertificateViewerDialog* dialog,
                                  net::X509Certificate* cert);
   virtual ~CertificateViewerDialogHandler();
 
@@ -108,8 +98,8 @@
   // The certificate being viewed.
   scoped_refptr<net::X509Certificate> cert_;
 
-  // The dialog window.
-  gfx::NativeWindow window_;
+  // The dialog.
+  CertificateViewerDialog* dialog_;
 
   // The certificate chain.
   net::X509Certificate::OSCertHandles cert_chain_;
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 998247f..bed7b89 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -179,6 +179,8 @@
   { "keyboardOverlayOpenAddressInNewTab",
     IDS_KEYBOARD_OVERLAY_OPEN_ADDRESS_IN_NEW_TAB },
   { "keyboardOverlayOpenFileManager", IDS_KEYBOARD_OVERLAY_OPEN_FILE_MANAGER },
+  { "keyboardOverlayOpenGoogleCloudPrint",
+    IDS_KEYBOARD_OVERLAY_OPEN_GOOGLE_CLOUD_PRINT },
   { "keyboardOverlayPageDown", IDS_KEYBOARD_OVERLAY_PAGE_DOWN },
   { "keyboardOverlayPageUp", IDS_KEYBOARD_OVERLAY_PAGE_UP },
   { "keyboardOverlayPaste", IDS_KEYBOARD_OVERLAY_PASTE },
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
index d472ad0..388b1e3 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -142,6 +142,8 @@
       return IDS_APP_START_NETWORK_WAIT_MESSAGE;
     case APP_LAUNCH_STATE_INSTALLING_APPLICATION:
       return IDS_APP_START_APP_WAIT_MESSAGE;
+    case APP_LAUNCH_STATE_WAITING_APP_WINDOW:
+      return IDS_APP_START_WAIT_FOR_APP_WINDOW_MESSAGE;
   }
   return IDS_APP_START_NETWORK_WAIT_MESSAGE;
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 3b256e0..1d1b07b 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
@@ -39,20 +40,13 @@
 const char kEnrollmentStepSignin[] = "signin";
 const char kEnrollmentStepSuccess[] = "success";
 
-}  // namespace
-
-namespace chromeos {
-
-// EnrollmentScreenHandler::TokenRevoker ------------------------
-
 // A helper class that takes care of asynchronously revoking a given token.
-class EnrollmentScreenHandler::TokenRevoker
-    : public GaiaAuthConsumer {
+class TokenRevoker : public GaiaAuthConsumer {
  public:
-  explicit TokenRevoker(EnrollmentScreenHandler* owner)
-      : gaia_fetcher_(this, GaiaConstants::kChromeOSSource,
-                      g_browser_process->system_request_context()),
-        owner_(owner) {}
+  TokenRevoker()
+      : gaia_fetcher_(this,
+                      GaiaConstants::kChromeOSSource,
+                      g_browser_process->system_request_context()) {}
   virtual ~TokenRevoker() {}
 
   void Start(const std::string& token) {
@@ -61,16 +55,19 @@
 
   // GaiaAuthConsumer:
   virtual void OnOAuth2RevokeTokenCompleted() OVERRIDE {
-    owner_->OnTokenRevokerDone(this);
+    base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
   }
 
  private:
   GaiaAuthFetcher gaia_fetcher_;
-  EnrollmentScreenHandler* owner_;
 
   DISALLOW_COPY_AND_ASSIGN(TokenRevoker);
 };
 
+}  // namespace
+
+namespace chromeos {
+
 // EnrollmentScreenHandler, public ------------------------------
 
 EnrollmentScreenHandler::EnrollmentScreenHandler()
@@ -82,8 +79,7 @@
       browsing_data_remover_(NULL) {
 }
 
-EnrollmentScreenHandler::
-    ~EnrollmentScreenHandler() {
+EnrollmentScreenHandler::~EnrollmentScreenHandler() {
   if (browsing_data_remover_)
     browsing_data_remover_->RemoveObserver(this);
 }
@@ -102,11 +98,10 @@
 // EnrollmentScreenHandler
 //      EnrollmentScreenActor implementation -----------------------------------
 
-void EnrollmentScreenHandler::SetParameters(
-    Controller* controller,
-    bool is_auto_enrollment,
-    bool can_exit_enrollment,
-    const std::string& user) {
+void EnrollmentScreenHandler::SetParameters(Controller* controller,
+                                            bool is_auto_enrollment,
+                                            bool can_exit_enrollment,
+                                            const std::string& user) {
   controller_ = controller;
   is_auto_enrollment_ = is_auto_enrollment;
   can_exit_enrollment_ = can_exit_enrollment;
@@ -138,22 +133,17 @@
   oauth_fetcher_->Start();
 }
 
-void EnrollmentScreenHandler::ResetAuth(
-    const base::Closure& callback) {
+void EnrollmentScreenHandler::ResetAuth(const base::Closure& callback) {
   auth_reset_callbacks_.push_back(callback);
-  if (browsing_data_remover_ || refresh_token_revoker_ || access_token_revoker_)
+  if (browsing_data_remover_)
     return;
 
   if (oauth_fetcher_) {
-    if (!oauth_fetcher_->oauth2_access_token().empty()) {
-      access_token_revoker_.reset(new TokenRevoker(this));
-      access_token_revoker_->Start(oauth_fetcher_->oauth2_access_token());
-    }
+    if (!oauth_fetcher_->oauth2_access_token().empty())
+      (new TokenRevoker())->Start(oauth_fetcher_->oauth2_access_token());
 
-    if (!oauth_fetcher_->oauth2_refresh_token().empty()) {
-      refresh_token_revoker_.reset(new TokenRevoker(this));
-      refresh_token_revoker_->Start(oauth_fetcher_->oauth2_refresh_token());
-    }
+    if (!oauth_fetcher_->oauth2_refresh_token().empty())
+      (new TokenRevoker())->Start(oauth_fetcher_->oauth2_refresh_token());
   }
 
   Profile* profile = Profile::FromBrowserContext(
@@ -243,6 +233,15 @@
               true);
       }
       return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_AUTH_FETCH_FAILED:
+      ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_AUTH_FETCH_FAILED, true);
+      return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED:
+      ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_FETCH_FAILED, true);
+      return;
+    case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED:
+      ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_STORE_FAILED, true);
+      return;
     case policy::EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE:
       ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_BAD_MODE, false);
       return;
@@ -315,13 +314,17 @@
   browsing_data_remover_->RemoveObserver(this);
   browsing_data_remover_ = NULL;
 
-  CheckAuthResetDone();
+  std::vector<base::Closure> callbacks_to_run;
+  callbacks_to_run.swap(auth_reset_callbacks_);
+  for (std::vector<base::Closure>::iterator callback(callbacks_to_run.begin());
+       callback != callbacks_to_run.end(); ++callback) {
+    callback->Run();
+  }
 }
 
 // EnrollmentScreenHandler, private -----------------------------
 
-void EnrollmentScreenHandler::HandleClose(
-    const std::string& reason) {
+void EnrollmentScreenHandler::HandleClose(const std::string& reason) {
   if (!controller_) {
     NOTREACHED();
     return;
@@ -355,14 +358,12 @@
   CallJS("showStep", std::string(step));
 }
 
-void EnrollmentScreenHandler::ShowError(int message_id,
-                                                       bool retry) {
+void EnrollmentScreenHandler::ShowError(int message_id, bool retry) {
   ShowErrorMessage(l10n_util::GetStringUTF8(message_id), retry);
 }
 
-void EnrollmentScreenHandler::ShowErrorMessage(
-    const std::string& message,
-    bool retry) {
+void EnrollmentScreenHandler::ShowErrorMessage(const std::string& message,
+                                               bool retry) {
   CallJS("showError", message, retry);
 }
 
@@ -382,30 +383,6 @@
     controller_->OnOAuthTokenAvailable(token);
 }
 
-void EnrollmentScreenHandler::OnTokenRevokerDone(
-    TokenRevoker* revoker) {
-  if (access_token_revoker_.get() == revoker)
-    access_token_revoker_.reset();
-  else if (refresh_token_revoker_.get() == revoker)
-    refresh_token_revoker_.reset();
-  else
-    NOTREACHED() << "Bad revoker callback: " << revoker;
-
-  CheckAuthResetDone();
-}
-
-void EnrollmentScreenHandler::CheckAuthResetDone() {
-  if (browsing_data_remover_ || refresh_token_revoker_ || access_token_revoker_)
-    return;
-
-  std::vector<base::Closure> callbacks_to_run;
-  callbacks_to_run.swap(auth_reset_callbacks_);
-  for (std::vector<base::Closure>::iterator callback(callbacks_to_run.begin());
-       callback != callbacks_to_run.end(); ++callback) {
-    callback->Run();
-  }
-}
-
 void EnrollmentScreenHandler::DoShow() {
   DictionaryValue screen_data;
   screen_data.SetString("signin_url", kGaiaExtStartPage);
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
index b3f2384..e1f68aa 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -60,8 +60,6 @@
   virtual void OnBrowsingDataRemoverDone() OVERRIDE;
 
  private:
-  class TokenRevoker;
-
   // Handlers for WebUI messages.
   void HandleClose(const std::string& reason);
   void HandleCompleteLogin(const std::string& user);
@@ -83,12 +81,6 @@
   void OnTokenFetched(const std::string& token,
                       const GoogleServiceAuthError& error);
 
-  // Callback for TokenRevokers that have completed.
-  void OnTokenRevokerDone(TokenRevoker* revoker);
-
-  // Checks whether a pending auth reset is complete. If so, invokes callbacks.
-  void CheckAuthResetDone();
-
   // Shows the screen.
   void DoShow();
 
@@ -115,8 +107,6 @@
 
   // The browsing data remover instance currently active, if any.
   BrowsingDataRemover* browsing_data_remover_;
-  scoped_ptr<TokenRevoker> access_token_revoker_;
-  scoped_ptr<TokenRevoker> refresh_token_revoker_;
 
   // The callbacks to invoke after browsing data has been cleared.
   std::vector<base::Closure> auth_reset_callbacks_;
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
index 5af0b3f..3952383 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
@@ -159,6 +159,9 @@
   AddCallback("importSupervisedUser",
               &LocallyManagedUserCreationScreenHandler::
                   HandleImportSupervisedUser);
+  AddCallback("importSupervisedUserWithPassword",
+              &LocallyManagedUserCreationScreenHandler::
+                  HandleImportSupervisedUserWithPassword);
 
 
   // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
@@ -330,6 +333,19 @@
   delegate_->ImportManagedUser(user_id);
 }
 
+void LocallyManagedUserCreationScreenHandler::
+    HandleImportSupervisedUserWithPassword(
+        const std::string& user_id,
+        const std::string& password) {
+  if (!delegate_)
+    return;
+
+  ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
+      IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_PROGRESS_MESSAGE));
+
+  delegate_->ImportManagedUserWithPassword(user_id, password);
+}
+
 void LocallyManagedUserCreationScreenHandler::HandleAuthenticateManager(
     const std::string& raw_manager_username,
     const std::string& manager_password) {
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
index f39c93e..55673b2 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
@@ -49,6 +49,10 @@
 
     // Starts managed user import flow for user identified with |user_id|.
     virtual void ImportManagedUser(const std::string& user_id) = 0;
+    // Starts managed user import flow for user identified with |user_id| and
+    // additional |password|.
+    virtual void ImportManagedUserWithPassword(const std::string& user_id,
+                                               const std::string& password) = 0;
 
     virtual void AbortFlow() = 0;
     virtual void FinishFlow() = 0;
@@ -115,6 +119,8 @@
   void HandleCreateManagedUser(const string16& new_raw_user_name,
                                const std::string& new_user_password);
   void HandleImportSupervisedUser(const std::string& user_id);
+  void HandleImportSupervisedUserWithPassword(const std::string& user_id,
+                                              const std::string& password);
 
   void HandleGetImages();
   void HandlePhotoTaken(const std::string& image_url);
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 2813556..387139f 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -126,6 +126,10 @@
 
   const std::string& GetScreenName(Screen screen) const;
 
+  SigninScreenHandler* signin_screen_handler_for_test() {
+    return signin_screen_handler_;
+  }
+
  private:
   // Initializes |screen_ids_| and |screen_names_| structures.
   void InitializeScreenMaps();
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 1d65c13..b6ed3ae 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -35,7 +36,6 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
@@ -397,7 +397,8 @@
       is_first_update_state_call_(true),
       offline_login_active_(false),
       last_network_state_(NetworkStateInformer::UNKNOWN),
-      has_pending_auth_ui_(false) {
+      has_pending_auth_ui_(false),
+      wait_for_auto_enrollment_check_(false) {
   DCHECK(network_state_informer_.get());
   DCHECK(error_screen_actor_);
   DCHECK(core_oobe_actor_);
@@ -420,9 +421,12 @@
   registrar_.Add(this,
                  chrome::NOTIFICATION_AUTH_CANCELLED,
                  content::NotificationService::AllSources());
+
+  WallpaperManager::Get()->AddObserver(this);
 }
 
 SigninScreenHandler::~SigninScreenHandler() {
+  WallpaperManager::Get()->RemoveObserver(this);
   weak_factory_.InvalidateWeakPtrs();
   SystemKeyEventListener* key_event_listener =
       SystemKeyEventListener::GetInstance();
@@ -1284,6 +1288,11 @@
     delegate_->LoadWallpaper(email);
 }
 
+void SigninScreenHandler::OnWallpaperAnimationFinished(
+    const std::string& email) {
+  CallJS("login.AccountPickerScreen.onWallpaperLoaded", email);
+}
+
 void SigninScreenHandler::HandleRebootSystem() {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
 }
@@ -1321,8 +1330,13 @@
 
 void SigninScreenHandler::HandleToggleKioskEnableScreen() {
   if (delegate_ &&
+      !wait_for_auto_enrollment_check_ &&
       !g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
-    delegate_->ShowKioskEnableScreen();
+    wait_for_auto_enrollment_check_ = true;
+
+    LoginDisplayHostImpl::default_host()->GetAutoEnrollmentCheckResult(
+        base::Bind(&SigninScreenHandler::ContinueKioskEnableFlow,
+                   weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -1781,4 +1795,22 @@
   // if they are cleared here.
 }
 
+void SigninScreenHandler::ContinueKioskEnableFlow(bool should_auto_enroll) {
+  wait_for_auto_enrollment_check_ = false;
+
+  // Do not proceed with kiosk enable when auto enroll will be enforced.
+  // TODO(xiyuan): Add an error UI feedkback so user knows what happens.
+  if (should_auto_enroll) {
+    LOG(WARNING) << "Kiosk enable flow aborted because auto enrollment is "
+                    "going to be enforced.";
+
+    if (!kiosk_enable_flow_aborted_callback_for_test_.is_null())
+      kiosk_enable_flow_aborted_callback_for_test_.Run();
+    return;
+  }
+
+  if (delegate_)
+    delegate_->ShowKioskEnableScreen();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index 6f977d1..b07e0ce 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/chromeos/login/login_display.h"
 #include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/wallpaper_manager.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system_key_event_listener.h"
@@ -173,7 +174,8 @@
       public LoginDisplayWebUIHandler,
       public SystemKeyEventListener::CapsLockObserver,
       public content::NotificationObserver,
-      public NetworkStateInformer::NetworkStateInformerObserver {
+      public NetworkStateInformer::NetworkStateInformerObserver,
+      public WallpaperManager::Observer {
  public:
   SigninScreenHandler(
       const scoped_refptr<NetworkStateInformer>& network_state_informer,
@@ -201,6 +203,14 @@
   // Required Local State preferences.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
+  // From WallpaperManager::Observer
+  virtual void OnWallpaperAnimationFinished(const std::string& email) OVERRIDE;
+
+  void set_kiosk_enable_flow_aborted_callback_for_test(
+      const base::Closure& callback) {
+    kiosk_enable_flow_aborted_callback_for_test_ = callback;
+  }
+
  private:
   enum UIState {
     UI_STATE_UNKNOWN = 0,
@@ -390,6 +400,11 @@
   // Update current input method (namely keyboard layout) to LRU by this user.
   void SetUserInputMethod(const std::string& username);
 
+  // Invoked when auto enrollment check is finished to decide whether to
+  // continue kiosk enable flow. Kiosk enable flow is resumed when
+  // |should_auto_enroll| is false.
+  void ContinueKioskEnableFlow(bool should_auto_enroll);
+
   // Current UI state of the signin screen.
   UIState ui_state_;
 
@@ -474,6 +489,10 @@
   scoped_ptr<CrosSettings::ObserverSubscription> allow_new_user_subscription_;
   scoped_ptr<CrosSettings::ObserverSubscription> allow_guest_subscription_;
 
+  bool wait_for_auto_enrollment_check_;
+
+  base::Closure kiosk_enable_flow_aborted_callback_for_test_;
+
   DISALLOW_COPY_AND_ASSIGN(SigninScreenHandler);
 };
 
diff --git a/chrome/browser/ui/webui/chromeos/salsa_ui.cc b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
index f7be343..6b622ba 100644
--- a/chrome/browser/ui/webui/chromeos/salsa_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
@@ -58,8 +58,6 @@
   prefs::kOverscrollVerticalThresholdStart,
   prefs::kOverscrollHorizontalResistThreshold,
   prefs::kOverscrollVerticalResistThreshold,
-  prefs::kImmersiveModeRevealDelayMs,
-  prefs::kImmersiveModeRevealXThresholdPixels,
   prefs::kFlingCurveTouchscreenAlpha,
   prefs::kFlingCurveTouchscreenBeta,
   prefs::kFlingCurveTouchscreenGamma,
diff --git a/chrome/browser/ui/webui/components_ui.cc b/chrome/browser/ui/webui/components_ui.cc
index c58b91c..f0c273b 100644
--- a/chrome/browser/ui/webui/components_ui.cc
+++ b/chrome/browser/ui/webui/components_ui.cc
@@ -115,8 +115,7 @@
     return;
   }
 
-  ComponentUpdateService* cus = g_browser_process->component_updater();
-  cus->CheckForUpdateSoon(component_id);
+  ComponentsUI::OnDemandUpdate(component_id);
 }
 
 void ComponentsDOMHandler::LoadComponents() {
@@ -159,6 +158,12 @@
 }
 
 // static
+void ComponentsUI::OnDemandUpdate(const std::string& component_id) {
+  ComponentUpdateService* cus = g_browser_process->component_updater();
+  cus->OnDemandUpdate(component_id);
+}
+
+// static
 base::RefCountedMemory* ComponentsUI::GetFaviconResourceBytes(
       ui::ScaleFactor scale_factor) {
   return ResourceBundle::GetSharedInstance().
diff --git a/chrome/browser/ui/webui/components_ui.h b/chrome/browser/ui/webui/components_ui.h
index afe57cb..2e98f21 100644
--- a/chrome/browser/ui/webui/components_ui.h
+++ b/chrome/browser/ui/webui/components_ui.h
@@ -20,6 +20,8 @@
  public:
   explicit ComponentsUI(content::WebUI* web_ui);
 
+  static void OnDemandUpdate(const std::string& component_id);
+
   static base::RefCountedMemory* GetFaviconResourceBytes(
       ui::ScaleFactor scale_factor);
 
diff --git a/chrome/browser/ui/webui/downloads_ui.cc b/chrome/browser/ui/webui/downloads_ui.cc
index 5a88c51..6e3ddcf 100644
--- a/chrome/browser/ui/webui/downloads_ui.cc
+++ b/chrome/browser/ui/webui/downloads_ui.cc
@@ -60,8 +60,8 @@
                              IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT);
   source->AddLocalizedString("danger_uncommon_desc",
                              IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT);
-  source->AddLocalizedString("danger_potentially_unwanted_desc",
-                             IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS);
+  source->AddLocalizedString("danger_settings_desc",
+                             IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS);
   source->AddLocalizedString("danger_save", IDS_CONFIRM_DOWNLOAD);
   source->AddLocalizedString("danger_restore", IDS_CONFIRM_DOWNLOAD_RESTORE);
   source->AddLocalizedString("danger_discard", IDS_DISCARD_DOWNLOAD);
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
index 3efe894..8eb1838 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "content/public/browser/web_ui.h"
diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc
index 6086dc0..5eddee2 100644
--- a/chrome/browser/ui/webui/extensions/command_handler.cc
+++ b/chrome/browser/ui/webui/extensions/command_handler.cc
@@ -37,12 +37,10 @@
       l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT));
   source->AddString("extensionCommandsDelete",
       l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT));
-  source->AddString("extensionCommandsGlobalTooltip",
+  source->AddString("extensionCommandsGlobal",
       l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL));
-  source->AddString("extensionCommandsNotGlobalTooltip",
+  source->AddString("extensionCommandsRegular",
       l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL));
-  source->AddString("extensionCommandsNotGlobalPermanentTooltip",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL_PERMANENT));
   source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
 }
 
@@ -61,8 +59,8 @@
   web_ui()->RegisterMessageCallback("setExtensionCommandShortcut",
       base::Bind(&CommandHandler::HandleSetExtensionCommandShortcut,
       base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("toggleCommandScope",
-      base::Bind(&CommandHandler::HandleToggleCommandScope,
+  web_ui()->RegisterMessageCallback("setCommandScope",
+      base::Bind(&CommandHandler::HandleSetCommandScope,
       base::Unretained(this)));
 }
 
@@ -105,21 +103,22 @@
   UpdateCommandDataOnPage();
 }
 
-void CommandHandler::HandleToggleCommandScope(
+void CommandHandler::HandleSetCommandScope(
     const base::ListValue* args) {
   std::string extension_id;
   std::string command_name;
+  bool global;
   if (!args->GetString(0, &extension_id) ||
-      !args->GetString(1, &command_name)) {
+      !args->GetString(1, &command_name) ||
+      !args->GetBoolean(2, &global)) {
     NOTREACHED();
     return;
   }
 
   Profile* profile = Profile::FromWebUI(web_ui());
   CommandService* command_service = CommandService::Get(profile);
-  command_service->ToggleScope(extension_id, command_name);
-
-  UpdateCommandDataOnPage();
+  if (command_service->SetScope(extension_id, command_name, global))
+    UpdateCommandDataOnPage();
 }
 
 void CommandHandler::HandleSetShortcutHandlingSuspended(const ListValue* args) {
diff --git a/chrome/browser/ui/webui/extensions/command_handler.h b/chrome/browser/ui/webui/extensions/command_handler.h
index 69f869a..c2f5573 100644
--- a/chrome/browser/ui/webui/extensions/command_handler.h
+++ b/chrome/browser/ui/webui/extensions/command_handler.h
@@ -62,7 +62,7 @@
 
   // Handles requests from javascript to change the scope of a particular
   // keyboard shortcut for a given extension command.
-  void HandleToggleCommandScope(const base::ListValue* args);
+  void HandleSetCommandScope(const base::ListValue* args);
 
   // Handles requests from javascript to temporarily disable general Chrome
   // shortcut handling while the web page is capturing which shortcut to use.
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index 403ee9e..c4f1b7e 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -39,7 +39,6 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/extension_warning_set.h"
-#include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
@@ -77,6 +76,7 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "extensions/browser/extension_error.h"
+#include "extensions/browser/lazy_background_task_queue.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/constants.h"
 #include "grit/browser_resources.h"
@@ -149,16 +149,11 @@
       ignore_notifications_(false),
       deleting_rvh_(NULL),
       registered_for_notifications_(false),
-      rvh_created_callback_(
-          base::Bind(&ExtensionSettingsHandler::RenderViewHostCreated,
-                     base::Unretained(this))),
       warning_service_observer_(this),
       error_console_observer_(this) {
 }
 
 ExtensionSettingsHandler::~ExtensionSettingsHandler() {
-  content::RenderViewHost::RemoveCreatedCallback(rvh_created_callback_);
-
   // 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 (load_extension_dialog_.get())
@@ -429,15 +424,6 @@
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
 }
 
-void ExtensionSettingsHandler::RenderViewHostCreated(
-    content::RenderViewHost* render_view_host) {
-  Profile* source_profile = Profile::FromBrowserContext(
-      render_view_host->GetSiteInstance()->GetBrowserContext());
-  if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
-    return;
-  MaybeUpdateAfterNotification();
-}
-
 void ExtensionSettingsHandler::RenderViewDeleted(
     content::RenderViewHost* render_view_host) {
   deleting_rvh_ = render_view_host;
@@ -1047,8 +1033,6 @@
                  chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
                  content::NotificationService::AllBrowserContextsAndSources());
 
-  content::RenderViewHost::AddCreatedCallback(rvh_created_callback_);
-
   content::WebContentsObserver::Observe(web_ui()->GetWebContents());
 
   warning_service_observer_.Add(
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.h b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
index 3dbe0e0..c2125f0 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
@@ -21,7 +21,6 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -93,8 +92,6 @@
   friend class ExtensionUITest;
   friend class BrokerDelegate;
 
-  void RenderViewHostCreated(content::RenderViewHost* render_view_host);
-
   // content::WebContentsObserver implementation.
   virtual void RenderViewDeleted(
       content::RenderViewHost* render_view_host) OVERRIDE;
@@ -256,8 +253,6 @@
 
   PrefChangeRegistrar pref_registrar_;
 
-  content::RenderViewHost::CreatedCallback rvh_created_callback_;
-
   // This will not be empty when a requirements check is in progress. Doing
   // another Check() before the previous one is complete will cause the first
   // one to abort.
diff --git a/chrome/browser/ui/webui/inline_login_ui.cc b/chrome/browser/ui/webui/inline_login_ui.cc
index 810ee74..5198017 100644
--- a/chrome/browser/ui/webui/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/inline_login_ui.cc
@@ -14,9 +14,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_global_error.h"
 #include "chrome/browser/signin/signin_manager_cookie_helper.h"
 #include "chrome/browser/signin/signin_names_io_thread.h"
+#include "chrome/browser/signin/signin_oauth_helper.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
@@ -143,7 +146,11 @@
 
       const GURL& current_url = web_ui()->GetWebContents()->GetURL();
       signin::Source source = signin::GetSourceForPromoURL(current_url);
-      if (source != signin::SOURCE_UNKNOWN) {
+      // TODO(guohui): switch to the embedded gaia endpoint for avatar flows
+      // when available.
+      DCHECK(source != signin::SOURCE_UNKNOWN);
+      if (source != signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT &&
+          source != signin::SOURCE_AVATAR_BUBBLE_SIGN_IN) {
         params.SetString("service", "chromiumsync");
         base::StringAppendF(
             &encoded_continue_params, "&%s=%d", "source",
@@ -153,6 +160,11 @@
       params.SetString("continueUrl",
           gaiaUrls->client_login_to_oauth2_url().Resolve(
               encoded_continue_params).spec());
+
+      std::string email;
+      net::GetValueForKeyInQuery(current_url, "Email", &email);
+      if (!email.empty())
+        params.SetString("email", email);
     }
 #endif
 
@@ -177,11 +189,11 @@
     string16 email;
     string16 password;
     if (!args->GetDictionary(0, &dict) || !dict ||
-        !dict->GetString("email", &email) ||
-        !dict->GetString("password", &password)) {
+        !dict->GetString("email", &email)) {
       NOTREACHED();
       return;
     }
+    dict->GetString("password", &password);
     dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
 
     content::WebContents* web_contents = web_ui()->GetWebContents();
@@ -204,40 +216,51 @@
       const string16 password,
       const net::CookieList& cookie_list) {
     net::CookieList::const_iterator it;
+    std::string oauth_code;
     for (it = cookie_list.begin(); it != cookie_list.end(); ++it) {
       if (it->Name() == "oauth_code") {
-        content::WebContents* contents = web_ui()->GetWebContents();
-        ProfileSyncService* sync_service =
-            ProfileSyncServiceFactory::GetForProfile(profile_);
-        const GURL& current_url = contents->GetURL();
-        signin::Source source = signin::GetSourceForPromoURL(current_url);
-
-        OneClickSigninSyncStarter::StartSyncMode start_mode =
-            source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
-                (SigninGlobalError::GetForProfile(profile_)->HasMenuItem() &&
-                 sync_service && sync_service->HasSyncSetupCompleted()) ?
-                    OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
-                    OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
-                OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
-        OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
-            source == signin::SOURCE_SETTINGS ||
-            source == signin::SOURCE_WEBSTORE_INSTALL ||
-            choose_what_to_sync_?
-                OneClickSigninSyncStarter::NO_CONFIRMATION :
-                OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
-        // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
-        // OneClickSigninSyncStarter will delete itself once the job is done.
-        new OneClickSigninSyncStarter(
-            profile_, NULL, "0" /* session_index 0 for the default user */,
-            UTF16ToASCII(email), UTF16ToASCII(password), it->Value(),
-            start_mode,
-            contents,
-            confirmation_required,
-            base::Bind(&InlineLoginUIHandler::SyncStarterCallback,
-                       weak_factory_.GetWeakPtr()));
+        oauth_code = it->Value();
         break;
       }
     }
+
+    DCHECK(!oauth_code.empty());
+    content::WebContents* contents = web_ui()->GetWebContents();
+    ProfileSyncService* sync_service =
+        ProfileSyncServiceFactory::GetForProfile(profile_);
+    const GURL& current_url = contents->GetURL();
+    signin::Source source = signin::GetSourceForPromoURL(current_url);
+
+    if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
+      // SigninOAuthHelper will delete itself.
+      SigninOAuthHelper* helper = new SigninOAuthHelper(profile_);
+      helper->StartAddingAccount(oauth_code);
+    } else {
+      OneClickSigninSyncStarter::StartSyncMode start_mode =
+          source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
+              (SigninGlobalError::GetForProfile(profile_)->HasMenuItem() &&
+                sync_service && sync_service->HasSyncSetupCompleted()) ?
+                  OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
+                  OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
+              OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
+      OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
+          source == signin::SOURCE_SETTINGS ||
+          source == signin::SOURCE_WEBSTORE_INSTALL ||
+          choose_what_to_sync_?
+              OneClickSigninSyncStarter::NO_CONFIRMATION :
+              OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
+      // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
+      // OneClickSigninSyncStarter will delete itself once the job is done.
+      new OneClickSigninSyncStarter(
+          profile_, NULL, "" /* session_index, not used */,
+          UTF16ToASCII(email), UTF16ToASCII(password), oauth_code,
+          start_mode,
+          contents,
+          confirmation_required,
+          base::Bind(&InlineLoginUIHandler::SyncStarterCallback,
+                      weak_factory_.GetWeakPtr()));
+    }
+
     web_ui()->CallJavascriptFunction("inline.login.closeDialog");
   }
 
@@ -282,9 +305,11 @@
       }
     }
   }
+
   Profile* profile_;
   base::WeakPtrFactory<InlineLoginUIHandler> weak_factory_;
   bool choose_what_to_sync_;
+
 #if defined(OS_CHROMEOS)
   scoped_ptr<chromeos::OAuth2TokenFetcher> oauth2_token_fetcher_;
   scoped_ptr<InlineLoginUIOAuth2Delegate> oauth2_delegate_;
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index 4a7253d..a70fa45 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -10,21 +10,20 @@
 #include "base/bind_helpers.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/devtools/port_forwarding_controller.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
-#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_child_process_observer.h"
@@ -33,8 +32,6 @@
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_client_host.h"
 #include "content/public/browser/devtools_manager.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
@@ -70,16 +67,13 @@
 
 namespace {
 
-const char kAppTargetType[] = "app";
-const char kExtensionTargetType[]  = "extension";
-const char kPageTargetType[]  = "page";
 const char kWorkerTargetType[]  = "worker";
 const char kAdbTargetType[]  = "adb_page";
 
 const char kInitUICommand[]  = "init-ui";
 const char kInspectCommand[]  = "inspect";
 const char kActivateCommand[]  = "activate";
-const char kTerminateCommand[]  = "terminate";
+const char kCloseCommand[]  = "close";
 const char kReloadCommand[]  = "reload";
 const char kOpenCommand[]  = "open";
 
@@ -92,15 +86,13 @@
 const char kPortForwardingDefaultPort[] = "8080";
 const char kPortForwardingDefaultLocation[] = "localhost:8080";
 
+const char kTargetIdField[]  = "id";
 const char kTargetTypeField[]  = "type";
 const char kAttachedField[]  = "attached";
-const char kProcessIdField[]  = "processId";
-const char kRouteIdField[]  = "routeId";
 const char kUrlField[]  = "url";
 const char kNameField[]  = "name";
 const char kFaviconUrlField[] = "faviconUrl";
 const char kDescription[] = "description";
-const char kPidField[]  = "pid";
 const char kAdbConnectedField[] = "adbConnected";
 const char kAdbModelField[] = "adbModel";
 const char kAdbSerialField[] = "adbSerial";
@@ -117,92 +109,19 @@
 const char kGuestList[] = "guests";
 
 DictionaryValue* BuildTargetDescriptor(
-    const std::string& target_type,
-    bool attached,
-    const GURL& url,
-    const std::string& name,
-    const GURL& favicon_url,
-    const std::string& description,
-    int process_id,
-    int route_id,
-    base::ProcessHandle handle = base::kNullProcessHandle) {
+    const DevToolsTargetImpl& target) {
   DictionaryValue* target_data = new DictionaryValue();
-  target_data->SetString(kTargetTypeField, target_type);
-  target_data->SetBoolean(kAttachedField, attached);
-  target_data->SetInteger(kProcessIdField, process_id);
-  target_data->SetInteger(kRouteIdField, route_id);
-  target_data->SetString(kUrlField, url.spec());
-  target_data->SetString(kNameField, net::EscapeForHTML(name));
-  target_data->SetInteger(kPidField, base::GetProcId(handle));
-  target_data->SetString(kFaviconUrlField, favicon_url.spec());
-  target_data->SetString(kDescription, description);
+  target_data->SetString(kTargetIdField, target.GetId());
+  target_data->SetString(kTargetTypeField, target.GetType());
+  target_data->SetBoolean(kAttachedField, target.IsAttached());
+  target_data->SetString(kUrlField, target.GetUrl().spec());
+  target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
+  target_data->SetString(kFaviconUrlField, target.GetFaviconUrl().spec());
+  target_data->SetString(kDescription, target.GetDescription());
 
   return target_data;
 }
 
-bool HasClientHost(RenderViewHost* rvh) {
-  if (!DevToolsAgentHost::HasFor(rvh))
-    return false;
-
-  scoped_refptr<DevToolsAgentHost> agent(
-      DevToolsAgentHost::GetOrCreateFor(rvh));
-  return agent->IsAttached();
-}
-
-bool HasClientHost(int process_id, int route_id) {
-  if (!DevToolsAgentHost::HasForWorker(process_id, route_id))
-    return false;
-
-  scoped_refptr<DevToolsAgentHost> agent(
-      DevToolsAgentHost::GetForWorker(process_id, route_id));
-  return agent->IsAttached();
-}
-
-DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) {
-  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
-  std::string title;
-  std::string target_type = is_tab ? kPageTargetType : "";
-  GURL url;
-  GURL favicon_url;
-  if (web_contents) {
-    url = web_contents->GetURL();
-    title = UTF16ToUTF8(web_contents->GetTitle());
-    content::NavigationController& controller = web_contents->GetController();
-    content::NavigationEntry* entry = controller.GetActiveEntry();
-    if (entry != NULL && entry->GetURL().is_valid())
-      favicon_url = entry->GetFavicon().url;
-
-    Profile* profile = Profile::FromBrowserContext(
-        web_contents->GetBrowserContext());
-    if (profile) {
-      ExtensionService* extension_service = profile->GetExtensionService();
-      const extensions::Extension* extension = extension_service->
-          extensions()->GetByID(url.host());
-      if (extension) {
-        if (extension->is_hosted_app()
-            || extension->is_legacy_packaged_app()
-            || extension->is_platform_app())
-          target_type = kAppTargetType;
-        else
-          target_type = kExtensionTargetType;
-        title = extension->name();
-        favicon_url = extensions::ExtensionIconSource::GetIconURL(
-            extension, extension_misc::EXTENSION_ICON_SMALLISH,
-            ExtensionIconSet::MATCH_BIGGER, false, NULL);
-      }
-    }
-  }
-
-  return BuildTargetDescriptor(target_type,
-                               HasClientHost(rvh),
-                               url,
-                               title,
-                               favicon_url,
-                               "",
-                               rvh->GetProcess()->GetID(),
-                               rvh->GetRoutingID());
-}
-
 class InspectMessageHandler : public WebUIMessageHandler {
  public:
   explicit InspectMessageHandler(InspectUI* inspect_ui)
@@ -216,18 +135,14 @@
   void HandleInitUICommand(const ListValue* args);
   void HandleInspectCommand(const ListValue* args);
   void HandleActivateCommand(const ListValue* args);
-  void HandleTerminateCommand(const ListValue* args);
+  void HandleCloseCommand(const ListValue* args);
   void HandleReloadCommand(const ListValue* args);
   void HandleOpenCommand(const ListValue* args);
   void HandleBooleanPrefChanged(const char* pref_name,
                                 const ListValue* args);
   void HandlePortForwardingConfigCommand(const ListValue* args);
 
-  static bool GetProcessAndRouteId(const ListValue* args,
-                                   int* process_id,
-                                   int* route_id);
-
-  static bool GetRemotePageId(const ListValue* args, std::string* page_id);
+  DevToolsTargetImpl* FindTarget(const ListValue* args);
 
   InspectUI* inspect_ui_;
 
@@ -244,8 +159,8 @@
   web_ui()->RegisterMessageCallback(kActivateCommand,
       base::Bind(&InspectMessageHandler::HandleActivateCommand,
                  base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(kTerminateCommand,
-      base::Bind(&InspectMessageHandler::HandleTerminateCommand,
+  web_ui()->RegisterMessageCallback(kCloseCommand,
+      base::Bind(&InspectMessageHandler::HandleCloseCommand,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback(kDiscoverUsbDevicesEnabledCommand,
       base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged,
@@ -274,86 +189,61 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   if (!profile)
     return;
-
-  std::string page_id;
-  if (GetRemotePageId(args, &page_id)) {
-    inspect_ui_->InspectRemotePage(page_id);
-    return;
-  }
-
-  int process_id;
-  int route_id;
-  if (!GetProcessAndRouteId(args, &process_id, &route_id) || process_id == 0
-      || route_id == 0) {
-    return;
-  }
-
-  RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
-  if (rvh) {
-    DevToolsWindow::OpenDevToolsWindow(rvh);
-    return;
-  }
-
-  scoped_refptr<DevToolsAgentHost> agent_host(
-      DevToolsAgentHost::GetForWorker(process_id, route_id));
-  if (!agent_host.get())
-    return;
-
-  DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host.get());
+  DevToolsTargetImpl* target = FindTarget(args);
+  if (target)
+    target->Inspect(profile);
 }
 
 void InspectMessageHandler::HandleActivateCommand(const ListValue* args) {
-  std::string page_id;
-  if (GetRemotePageId(args, &page_id))
-    inspect_ui_->ActivateRemotePage(page_id);
+  DevToolsTargetImpl* target = FindTarget(args);
+  if (target)
+    target->Activate();
 }
 
-static void TerminateWorker(int process_id, int route_id) {
-  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
-}
-
-void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) {
-  std::string page_id;
-  if (GetRemotePageId(args, &page_id)) {
-    inspect_ui_->CloseRemotePage(page_id);
-    return;
-  }
-
-  int process_id;
-  int route_id;
-  if (!GetProcessAndRouteId(args, &process_id, &route_id))
-    return;
-
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-      base::Bind(&TerminateWorker, process_id, route_id));
+void InspectMessageHandler::HandleCloseCommand(const ListValue* args) {
+  DevToolsTargetImpl* target = FindTarget(args);
+  if (target)
+    target->Close();
 }
 
 void InspectMessageHandler::HandleReloadCommand(const ListValue* args) {
-  std::string page_id;
-  if (GetRemotePageId(args, &page_id))
-    inspect_ui_->ReloadRemotePage(page_id);
+  DevToolsTargetImpl* target = FindTarget(args);
+  if (target)
+    target->Reload();
 }
 
 void InspectMessageHandler::HandleOpenCommand(const ListValue* args) {
+  if (args->GetSize() != 2)
+    return;
   std::string browser_id;
+  if (!args->GetString(0, &browser_id))
+    return;
+  scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
+      inspect_ui_->FindRemoteBrowser(browser_id);
+  if (!remote_browser)
+    return;
   std::string url;
-  if (args->GetSize() == 2 &&
-      args->GetString(0, &browser_id) &&
-      args->GetString(1, &url)) {
-    inspect_ui_->OpenRemotePage(browser_id, url);
+  if (!args->GetString(1, &url))
+    return;
+  GURL gurl(url);
+  if (!gurl.is_valid()) {
+    gurl = GURL("http://" + url);
+    if (!gurl.is_valid())
+     return;
   }
+  remote_browser->Open(gurl.spec());
 }
 
-bool InspectMessageHandler::GetProcessAndRouteId(const ListValue* args,
-                                                 int* process_id,
-                                                 int* route_id) {
+DevToolsTargetImpl* InspectMessageHandler::FindTarget(const ListValue* args) {
   const DictionaryValue* data;
+  std::string type;
+  std::string id;
   if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
-      data->GetInteger(kProcessIdField, process_id) &&
-      data->GetInteger(kRouteIdField, route_id)) {
-    return true;
+      data->GetString(kTargetTypeField, &type) &&
+      data->GetString(kTargetIdField, &id)) {
+    return inspect_ui_->FindTarget(type, id);
   }
-  return false;
+  return NULL;
 }
 
 void InspectMessageHandler::HandleBooleanPrefChanged(
@@ -379,16 +269,6 @@
     profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src);
 }
 
-bool InspectMessageHandler::GetRemotePageId(const ListValue* args,
-                                            std::string* page_id) {
-  const DictionaryValue* data;
-  if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
-      data->GetString(kAdbGlobalIdField, page_id)) {
-    return true;
-  }
-  return false;
-}
-
 }  // namespace
 
 class InspectUI::WorkerCreationDestructionListener
@@ -457,10 +337,9 @@
 
   void CollectWorkersData() {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&WorkerCreationDestructionListener::PopulateWorkersList,
-                   this, WorkerService::GetInstance()->GetWorkers()));
+    DevToolsTargetImpl::EnumerateWorkerTargets(
+        base::Bind(
+            &WorkerCreationDestructionListener::PopulateWorkersList, this));
   }
 
   void RegisterObserver() {
@@ -471,29 +350,10 @@
     WorkerService::GetInstance()->RemoveObserver(this);
   }
 
-  void PopulateWorkersList(
-      const std::vector<WorkerService::WorkerInfo>& worker_info) {
+  void PopulateWorkersList(const DevToolsTargetImpl::List& targets) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    if (!discovery_ui_)
-      return;
-
-    ListValue target_list;
-    for (size_t i = 0; i < worker_info.size(); ++i) {
-      if (!worker_info[i].handle)
-        continue;  // Process is still being created.
-      target_list.Append(BuildTargetDescriptor(
-          kWorkerTargetType,
-          HasClientHost(worker_info[i].process_id, worker_info[i].route_id),
-          worker_info[i].url,
-          UTF16ToUTF8(worker_info[i].name),
-          GURL(),
-          "",
-          worker_info[i].process_id,
-          worker_info[i].route_id,
-          worker_info[i].handle));
-    }
-    discovery_ui_->web_ui()->CallJavascriptFunction(
-        "populateWorkersList", target_list);
+    if (discovery_ui_)
+       discovery_ui_->PopulateWorkerTargets(targets);
   }
 
   InspectUI* discovery_ui_;
@@ -517,50 +377,31 @@
 void InspectUI::InitUI() {
   SetPortForwardingDefaults();
   StartListeningNotifications();
-  PopulateLists();
+  PopulateWebContentsTargets();
   UpdateDiscoverUsbDevicesEnabled();
   UpdatePortForwardingEnabled();
   UpdatePortForwardingConfig();
   observer_->UpdateUI();
 }
 
-void InspectUI::InspectRemotePage(const std::string& id) {
-  RemotePages::iterator it = remote_pages_.find(id);
-  if (it != remote_pages_.end()) {
-    Profile* profile = Profile::FromWebUI(web_ui());
-    it->second->Inspect(profile);
+DevToolsTargetImpl* InspectUI::FindTarget(const std::string& type,
+                                          const std::string& id) {
+  if (type == kWorkerTargetType) {
+    TargetMap::iterator it = worker_targets_.find(id);
+    return it == worker_targets_.end() ? NULL : it->second;
+  } else if (type == kAdbTargetType) {
+    TargetMap::iterator it = remote_targets_.find(id);
+    return it == remote_targets_.end() ? NULL : it->second;
+  } else {
+    TargetMap::iterator it = render_view_host_targets_.find(id);
+    return it == render_view_host_targets_.end() ? NULL : it->second;
   }
 }
 
-void InspectUI::ActivateRemotePage(const std::string& id) {
-  RemotePages::iterator it = remote_pages_.find(id);
-  if (it != remote_pages_.end())
-    it->second->Activate();
-}
-
-void InspectUI::ReloadRemotePage(const std::string& id) {
-  RemotePages::iterator it = remote_pages_.find(id);
-  if (it != remote_pages_.end())
-    it->second->Reload();
-}
-
-void InspectUI::CloseRemotePage(const std::string& id) {
-  RemotePages::iterator it = remote_pages_.find(id);
-  if (it != remote_pages_.end())
-    it->second->Close();
-}
-
-void InspectUI::OpenRemotePage(const std::string& browser_id,
-                               const std::string& url) {
-  GURL gurl(url);
-  if (!gurl.is_valid()) {
-    gurl = GURL("http://" + url);
-    if (!gurl.is_valid())
-      return;
-  }
-  RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
-  if (it != remote_browsers_.end())
-    it->second->Open(gurl.spec());
+scoped_refptr<DevToolsAdbBridge::RemoteBrowser>
+InspectUI::FindRemoteBrowser(const std::string& id) {
+  RemoteBrowsers::iterator it = remote_browsers_.find(id);
+  return it == remote_browsers_.end() ? NULL : it->second;
 }
 
 void InspectUI::InspectDevices(Browser* browser) {
@@ -571,61 +412,76 @@
   ShowSingletonTabOverwritingNTP(browser, params);
 }
 
-void InspectUI::PopulateLists() {
-  std::set<RenderViewHost*> tab_rvhs;
-  for (TabContentsIterator it; !it.done(); it.Next())
-    tab_rvhs.insert(it->GetRenderViewHost());
+void InspectUI::PopulateWebContentsTargets() {
+  ListValue list_value;
 
-  scoped_ptr<ListValue> target_list(new ListValue());
+  std::map<WebContents*, DictionaryValue*> web_contents_to_descriptor_;
+  std::vector<DevToolsTargetImpl*> guest_targets;
 
-  std::vector<RenderViewHost*> rvh_vector =
-      DevToolsAgentHost::GetValidRenderViewHosts();
+  DevToolsTargetImpl::List targets =
+      DevToolsTargetImpl::EnumerateRenderViewHostTargets();
 
-  std::map<WebContents*, DictionaryValue*> description_map;
-  std::vector<WebContents*> guest_contents;
-
-  for (std::vector<RenderViewHost*>::iterator it(rvh_vector.begin());
-       it != rvh_vector.end(); it++) {
-    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
-    RenderViewHost* rvh = (*it);
+  STLDeleteValues(&render_view_host_targets_);
+  for (DevToolsTargetImpl::List::iterator it = targets.begin();
+      it != targets.end(); ++it) {
+    DevToolsTargetImpl* target = *it;
+    RenderViewHost* rvh = target->GetRenderViewHost();
+    if (!rvh)
+      continue;
     WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+    if (!web_contents)
+      continue;
+
+    render_view_host_targets_[target->GetId()] = target;
     if (rvh->GetProcess()->IsGuest()) {
-      if (web_contents)
-        guest_contents.push_back(web_contents);
+      guest_targets.push_back(target);
     } else {
-      DictionaryValue* dictionary = BuildTargetDescriptor(rvh, is_tab);
-      if (web_contents)
-        description_map[web_contents] = dictionary;
-      target_list->Append(dictionary);
+      DictionaryValue* descriptor = BuildTargetDescriptor(*target);
+      list_value.Append(descriptor);
+      web_contents_to_descriptor_[web_contents] = descriptor;
     }
   }
 
   // Add the list of guest-views to each of its embedders.
-  for (std::vector<WebContents*>::iterator it(guest_contents.begin());
-       it != guest_contents.end(); ++it) {
-    WebContents* guest = (*it);
-    WebContents* embedder = guest->GetEmbedderWebContents();
-    if (embedder && description_map.count(embedder) > 0) {
-      DictionaryValue* description = description_map[embedder];
+  for (std::vector<DevToolsTargetImpl*>::iterator it(guest_targets.begin());
+       it != guest_targets.end(); ++it) {
+    DevToolsTargetImpl* guest = (*it);
+    WebContents* guest_web_contents =
+        WebContents::FromRenderViewHost(guest->GetRenderViewHost());
+    WebContents* embedder = guest_web_contents->GetEmbedderWebContents();
+    if (embedder && web_contents_to_descriptor_.count(embedder) > 0) {
+      DictionaryValue* parent = web_contents_to_descriptor_[embedder];
       ListValue* guests = NULL;
-      if (!description->GetList(kGuestList, &guests)) {
+      if (!parent->GetList(kGuestList, &guests)) {
         guests = new ListValue();
-        description->Set(kGuestList, guests);
+        parent->Set(kGuestList, guests);
       }
-      RenderViewHost* rvh = guest->GetRenderViewHost();
-      if (rvh)
-        guests->Append(BuildTargetDescriptor(rvh, false));
+      guests->Append(BuildTargetDescriptor(*guest));
     }
   }
 
-  web_ui()->CallJavascriptFunction("populateLists", *target_list.get());
+  web_ui()->CallJavascriptFunction("populateWebContentsTargets", list_value);
+}
+
+void InspectUI::PopulateWorkerTargets(const DevToolsTargetImpl::List& targets) {
+  ListValue list_value;
+
+  STLDeleteValues(&worker_targets_);
+  for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
+      it != targets.end(); ++it) {
+    DevToolsTargetImpl* target = *it;
+    list_value.Append(BuildTargetDescriptor(*target));
+    worker_targets_[target->GetId()] = target;
+  }
+
+  web_ui()->CallJavascriptFunction("populateWorkerTargets", list_value);
 }
 
 void InspectUI::Observe(int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   if (source != content::Source<WebContents>(web_ui()->GetWebContents()))
-    PopulateLists();
+    PopulateWebContentsTargets();
   else if (type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED)
     StopListeningNotifications();
 }
@@ -700,7 +556,7 @@
         port_forwarding_controller->UpdateDeviceList(*devices);
 
   remote_browsers_.clear();
-  remote_pages_.clear();
+  STLDeleteValues(&remote_targets_);
   ListValue device_list;
   for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
        dit != devices->end(); ++dit) {
@@ -734,28 +590,22 @@
       ListValue* page_list = new ListValue();
       browser_data->Set(kAdbPagesField, page_list);
 
-      DevToolsAdbBridge::RemotePages& pages = browser->pages();
-      for (DevToolsAdbBridge::RemotePages::iterator it =
+      DevToolsTargetImpl::List pages = browser->CreatePageTargets();
+      for (DevToolsTargetImpl::List::iterator it =
           pages.begin(); it != pages.end(); ++it) {
-        DevToolsAdbBridge::RemotePage* page =  it->get();
-        DictionaryValue* page_data = BuildTargetDescriptor(
-            kAdbTargetType, page->attached(),
-            GURL(page->url()), page->title(), GURL(page->favicon_url()),
-            page->description(), 0, 0);
-        std::string page_id = base::StringPrintf("page:%s:%s:%s",
-            device->GetSerial().c_str(),
-            browser->socket().c_str(),
-            page->id().c_str());
-        page_data->SetString(kAdbGlobalIdField, page_id);
-        page_data->SetBoolean(kAdbAttachedForeignField,
-            page->attached() && !page->HasDevToolsWindow());
+        DevToolsTargetImpl* page =  *it;
+        DictionaryValue* page_data = BuildTargetDescriptor(*page);
+        page_data->SetBoolean(
+            kAdbAttachedForeignField,
+            page->IsAttached() &&
+                !DevToolsAdbBridge::HasDevToolsWindow(page->GetId()));
         // Pass the screen size in the page object to make sure that
         // the caching logic does not prevent the page item from updating
         // when the screen size changes.
         gfx::Size screen_size = device->screen_size();
         page_data->SetInteger(kAdbScreenWidthField, screen_size.width());
         page_data->SetInteger(kAdbScreenHeightField, screen_size.height());
-        remote_pages_[page_id] = page;
+        remote_targets_[page->GetId()] = page;
         page_list->Append(page_data);
       }
       browser_list->Append(browser_data);
@@ -779,7 +629,7 @@
 
     device_list.Append(device_data);
   }
-  web_ui()->CallJavascriptFunction("populateDeviceLists", device_list);
+  web_ui()->CallJavascriptFunction("populateRemoteTargets", device_list);
 }
 
 void InspectUI::UpdateDiscoverUsbDevicesEnabled() {
@@ -793,7 +643,16 @@
   if (adb_bridge) {
     bool enabled = false;
     value->GetAsBoolean(&enabled);
-    adb_bridge->set_discover_usb_devices(enabled);
+
+    DevToolsAdbBridge::DeviceProviders device_providers;
+    device_providers.push_back(AndroidDeviceProvider::GetAdbDeviceProvider());
+
+    if (enabled) {
+      device_providers.push_back(
+          AndroidDeviceProvider::GetUsbDeviceProvider(profile));
+    }
+
+    adb_bridge->set_device_providers(device_providers);
   }
 }
 
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index 6d48b3c..d1d186e 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -21,6 +21,7 @@
 }
 
 class Browser;
+class DevToolsTargetImpl;
 
 class InspectUI : public content::WebUIController,
                   public content::NotificationObserver,
@@ -30,18 +31,18 @@
   virtual ~InspectUI();
 
   void InitUI();
-  void InspectRemotePage(const std::string& page_id);
-  void ActivateRemotePage(const std::string& page_id);
-  void CloseRemotePage(const std::string& page_id);
-  void ReloadRemotePage(const std::string& page_id);
-  void OpenRemotePage(const std::string& browser_id, const std::string& url);
+  DevToolsTargetImpl* FindTarget(const std::string& type,
+                                 const std::string& id);
+  scoped_refptr<DevToolsAdbBridge::RemoteBrowser> FindRemoteBrowser(
+      const std::string& id);
 
   static void InspectDevices(Browser* browser);
 
  private:
   class WorkerCreationDestructionListener;
 
-  void PopulateLists();
+  void PopulateWebContentsTargets();
+  void PopulateWorkerTargets(const std::vector<DevToolsTargetImpl*>&);
 
   // content::NotificationObserver overrides.
   virtual void Observe(int type,
@@ -73,9 +74,10 @@
   // A scoped container for preference change registries.
   PrefChangeRegistrar pref_change_registrar_;
 
-  typedef std::map<std::string, scoped_refptr<DevToolsAdbBridge::RemotePage> >
-      RemotePages;
-  RemotePages remote_pages_;
+  typedef std::map<std::string, DevToolsTargetImpl*> TargetMap;
+  TargetMap render_view_host_targets_;
+  TargetMap worker_targets_;
+  TargetMap remote_targets_;
 
   typedef std::map<std::string,
       scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 01f6c18..7de4af0 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -187,6 +187,11 @@
     "     \"x-privet-token\" : \"MyPrivetToken\""
     "}";
 
+const char kResponseInfoWithID[] = "{"
+    "     \"x-privet-token\" : \"MyPrivetToken\","
+    "     \"id\" : \"my_id\""
+    "}";
+
 const char kResponseRegisterStart[] = "{"
     "     \"action\": \"start\","
     "     \"user\": \"user@host.com\""
@@ -223,17 +228,17 @@
 const char kURLInfo[] = "http://1.2.3.4:8888/privet/info";
 
 const char kURLRegisterStart[] =
-    "http://1.2.3.4:8888/privet/register?action=start&user=user@host.com";
+    "http://1.2.3.4:8888/privet/register?action=start&user=user%40host.com";
 
 const char kURLRegisterClaimToken[] =
     "http://1.2.3.4:8888/privet/register?action=getClaimToken&"
-    "user=user@host.com";
+    "user=user%40host.com";
 
 const char kURLCloudPrintConfirm[] =
     "https://www.google.com/cloudprint/confirm?token=MySampleToken";
 
 const char kURLRegisterComplete[] =
-    "http://1.2.3.4:8888/privet/register?action=complete&user=user@host.com";
+    "http://1.2.3.4:8888/privet/register?action=complete&user=user%40host.com";
 
 const char kURLGaiaToken[] =
     "https://accounts.google.com/o/oauth2/token";
@@ -365,8 +370,7 @@
     ProfileOAuth2TokenService* token_service =
         ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile());
 
-    token_service->UpdateCredentials("user@host.com",
-                                     "MyFakeToken");
+    token_service->UpdateCredentials("user@host.com", "MyFakeToken");
 
     AddLibrary(base::FilePath(FILE_PATH_LITERAL("local_discovery_ui_test.js")));
   }
@@ -479,6 +483,11 @@
       kResponseRegisterClaimTokenConfirm,
       true);
 
+  fake_fetcher_factory().SetFakeResponse(
+      GURL(kURLInfo),
+      kResponseInfoWithID,
+      true);
+
   {
     InSequence s;
     EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
@@ -486,7 +495,8 @@
     EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
         kURLCloudPrintConfirm));
     EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
-        kURLRegisterComplete))
+        kURLRegisterComplete));
+    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo))
         .WillOnce(InvokeWithoutArgs(&condition_token_claimed,
                                     &TestMessageLoopCondition::Signal));
   }
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
index d1fafa6..a9b2436 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -55,7 +55,6 @@
 
 namespace {
 const char kPrivetAutomatedClaimURLFormat[] = "%s/confirm?token=%s";
-const int kRegistrationAnnouncementTimeoutSeconds = 5;
 
 const int kInitialRequeryTimeSeconds = 1;
 const int kMaxRequeryTimeSeconds = 2; // Time for last requery
@@ -321,30 +320,20 @@
   current_register_operation_.reset();
   current_http_client_.reset();
 
+  // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
+  // block the printer's announcement.
+  privet_lister_->DiscoverNewDevices(false);
+
   DeviceDescriptionMap::iterator found = device_descriptions_.find(name);
 
-  if (found == device_descriptions_.end() || found->second.id.empty()) {
-    // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
-    // block the printer's announcement.
-    privet_lister_->DiscoverNewDevices(false);
-
-    new_register_device_ = name;
-    registration_announce_timeout_.Reset(base::Bind(
-        &LocalDiscoveryUIHandler::OnAnnouncementTimeoutReached,
-        base::Unretained(this)));
-
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        registration_announce_timeout_.callback(),
-        base::TimeDelta::FromSeconds(kRegistrationAnnouncementTimeoutSeconds));
+  if (found == device_descriptions_.end()) {
+    // TODO(noamsml): Handle the case where a printer's record is not present at
+    // the end of registration.
+    SendRegisterError();
+    return;
   }
-}
 
-void LocalDiscoveryUIHandler::OnAnnouncementTimeoutReached() {
-  new_register_device_.clear();
-  registration_announce_timeout_.Cancel();
-
-  SendRegisterError();
+  SendRegisterDone(found->second);
 }
 
 void LocalDiscoveryUIHandler::OnConfirmDone(
@@ -380,11 +369,6 @@
     web_ui()->CallJavascriptFunction(
         "local_discovery.onUnregisteredDeviceUpdate",
         service_name, *null_value);
-
-    if (name == new_register_device_) {
-      new_register_device_.clear();
-      SendRegisterDone(description);
-    }
   }
 }
 
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
index ebe4c35..78d6008 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
@@ -66,10 +66,9 @@
       const std::string& device_id) OVERRIDE;
 
   // PrivetDeviceLister::Delegate implementation.
-  virtual void DeviceChanged(
-      bool added,
-      const std::string& name,
-      const DeviceDescription& description) OVERRIDE;
+  virtual void DeviceChanged(bool added,
+                             const std::string& name,
+                             const DeviceDescription& description) OVERRIDE;
 
   virtual void DeviceRemoved(const std::string& name) OVERRIDE;
 
@@ -188,16 +187,9 @@
   // Whether or not the page is marked as visible.
   bool is_visible_;
 
-  // Device whose state must be updated to "registered" to complete
-  // registration.
-  std::string new_register_device_;
-
   // List of printers from cloud print.
   scoped_ptr<CloudPrintPrinterList> cloud_print_printer_list_;
 
-  // Announcement timeout for registration.
-  base::CancelableCallback<void()> registration_announce_timeout_;
-
   // Callback for requery.
   base::CancelableCallback<void()> requery_callback_;
 
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 9be9f30..7f8e49a 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -14,9 +14,9 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/crx_installer.h"
@@ -25,8 +25,8 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -60,6 +60,7 @@
 using extensions::CrxInstaller;
 using extensions::Extension;
 using extensions::ExtensionPrefs;
+using extensions::UnloadedExtensionInfo;
 
 namespace {
 
@@ -283,8 +284,8 @@
         extension = content::Details<const Extension>(details).ptr();
         uninstalled = true;
       } else {  // NOTIFICATION_EXTENSION_UNLOADED
-        if (content::Details<extensions::UnloadedExtensionInfo>(
-                details)->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
+        if (content::Details<UnloadedExtensionInfo>(details)->reason ==
+            UnloadedExtensionInfo::REASON_UNINSTALL) {
           // Uninstalls are tracked by NOTIFICATION_EXTENSION_UNINSTALLED.
           return;
         }
diff --git a/chrome/browser/ui/webui/ntp/foreign_session_handler.cc b/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
index 0602d2b..2167292 100644
--- a/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
+++ b/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
@@ -13,11 +13,11 @@
 #include "base/i18n/time_formatting.h"
 #include "base/memory/scoped_vector.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "chrome/browser/sync/profile_sync_service.h"
diff --git a/chrome/browser/ui/webui/ntp/most_visited_handler.cc b/chrome/browser/ui/webui/ntp/most_visited_handler.cc
index 5416aa3..ba6e7e0 100644
--- a/chrome/browser/ui/webui/ntp/most_visited_handler.cc
+++ b/chrome/browser/ui/webui/ntp/most_visited_handler.cc
@@ -14,6 +14,7 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -23,7 +24,6 @@
 #include "chrome/browser/history/most_visited_tiles_experiment.h"
 #include "chrome/browser/history/page_usage_data.h"
 #include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index fe38435..c472797 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -15,7 +15,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/apps/app_launcher_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/first_run/first_run.h"
@@ -28,6 +27,7 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
 #include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
@@ -478,6 +478,17 @@
   load_time_data.SetBoolean("showWebStoreIcon",
                             !prefs->GetBoolean(prefs::kHideWebStoreIcon));
 
+  bool streamlined_hosted_apps = CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableStreamlinedHostedApps);
+  load_time_data.SetBoolean("enableStreamlinedHostedApps",
+                            streamlined_hosted_apps);
+  // Use a different string for launching as a regular tab for streamlined
+  // hosted apps.
+  if (streamlined_hosted_apps) {
+    load_time_data.SetString("applaunchtypetab",
+        l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_TAB));
+  }
+
 #if defined(OS_MACOSX)
   load_time_data.SetBoolean(
       "disableCreateAppShortcut",
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils_linux.cc b/chrome/browser/ui/webui/options/advanced_options_utils_linux.cc
new file mode 100644
index 0000000..f1c3790
--- /dev/null
+++ b/chrome/browser/ui/webui/options/advanced_options_utils_linux.cc
@@ -0,0 +1,159 @@
+// Copyright 2013 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.
+
+#if !defined(OS_CHROMEOS)
+
+#include "chrome/browser/ui/webui/options/advanced_options_utils.h"
+
+#include "base/bind.h"
+#include "base/environment.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/nix/xdg_util.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+
+using content::BrowserThread;
+using content::OpenURLParams;
+using content::Referrer;
+using content::WebContents;
+
+namespace options {
+
+// Command used to configure GNOME 2 proxy settings.
+const char* kGNOME2ProxyConfigCommand[] = {"gnome-network-properties", NULL};
+// In GNOME 3, we might need to run gnome-control-center instead. We try this
+// only after gnome-network-properties is not found, because older GNOME also
+// has this but it doesn't do the same thing. See below where we use it.
+const char* kGNOME3ProxyConfigCommand[] = {"gnome-control-center", "network",
+                                           NULL};
+// KDE3 and KDE4 are only slightly different, but incompatible. Go figure.
+const char* kKDE3ProxyConfigCommand[] = {"kcmshell", "proxy", NULL};
+const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL};
+
+// The URL for Linux proxy configuration help when not running under a
+// supported desktop environment.
+const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config";
+
+namespace {
+
+// Show the proxy config URL in the given tab.
+void ShowLinuxProxyConfigUrl(int render_process_id, int render_view_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  const char* name = base::nix::GetDesktopEnvironmentName(env.get());
+  if (name)
+    LOG(ERROR) << "Could not find " << name << " network settings in $PATH";
+  OpenURLParams params(
+      GURL(kLinuxProxyConfigUrl), Referrer(), NEW_FOREGROUND_TAB,
+      content::PAGE_TRANSITION_LINK, false);
+
+  WebContents* web_contents =
+      tab_util::GetWebContentsByID(render_process_id, render_view_id);
+  if (web_contents)
+    web_contents->OpenURL(params);
+}
+
+// Start the given proxy configuration utility.
+bool StartProxyConfigUtil(const char* command[]) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  // base::LaunchProcess() returns true ("success") if the fork()
+  // succeeds, but not necessarily the exec(). We'd like to be able to
+  // use StartProxyConfigUtil() to search possible options and stop on
+  // success, so we search $PATH first to predict whether the exec is
+  // expected to succeed.
+  // TODO(mdm): this is a useful check, and is very similar to some
+  // code in proxy_config_service_linux.cc. It should probably be in
+  // base:: somewhere.
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  std::string path;
+  if (!env->GetVar("PATH", &path)) {
+    LOG(ERROR) << "No $PATH variable. Assuming no " << command[0] << ".";
+    return false;
+  }
+  std::vector<std::string> paths;
+  Tokenize(path, ":", &paths);
+  bool found = false;
+  for (size_t i = 0; i < paths.size(); ++i) {
+    base::FilePath file(paths[i]);
+    if (base::PathExists(file.Append(command[0]))) {
+      found = true;
+      break;
+    }
+  }
+  if (!found)
+    return false;
+  std::vector<std::string> argv;
+  for (size_t i = 0; command[i]; ++i)
+    argv.push_back(command[i]);
+  base::ProcessHandle handle;
+  if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
+    LOG(ERROR) << "StartProxyConfigUtil failed to start " << command[0];
+    return false;
+  }
+  base::EnsureProcessGetsReaped(handle);
+  return true;
+}
+
+// Detect, and if possible, start the appropriate proxy config utility. On
+// failure to do so, show the Linux proxy config URL in a new tab instead.
+void DetectAndStartProxyConfigUtil(int render_process_id,
+                                   int render_view_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+
+  bool launched = false;
+  switch (base::nix::GetDesktopEnvironment(env.get())) {
+    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
+    case base::nix::DESKTOP_ENVIRONMENT_UNITY: {
+      launched = StartProxyConfigUtil(kGNOME2ProxyConfigCommand);
+      if (!launched) {
+        // We try this second, even though it's the newer way, because this
+        // command existed in older versions of GNOME, but it didn't do the
+        // same thing. The older command is gone though, so this should do
+        // the right thing. (Also some distributions have blurred the lines
+        // between GNOME 2 and 3, so we can't necessarily detect what the
+        // right thing is based on indications of which version we have.)
+        launched = StartProxyConfigUtil(kGNOME3ProxyConfigCommand);
+      }
+      break;
+    }
+
+    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
+      launched = StartProxyConfigUtil(kKDE3ProxyConfigCommand);
+      break;
+
+    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
+      launched = StartProxyConfigUtil(kKDE4ProxyConfigCommand);
+      break;
+
+    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
+    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
+      break;
+  }
+
+  if (launched)
+    return;
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShowLinuxProxyConfigUrl, render_process_id, render_view_id));
+}
+
+}  // anonymous namespace
+
+void AdvancedOptionsUtilities::ShowNetworkProxySettings(
+    WebContents* web_contents) {
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+      base::Bind(&DetectAndStartProxyConfigUtil,
+                 web_contents->GetRenderProcessHost()->GetID(),
+                 web_contents->GetRenderViewHost()->GetRoutingID()));
+}
+
+}  // namespace options
+
+#endif  // !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils_x11.cc b/chrome/browser/ui/webui/options/advanced_options_utils_x11.cc
deleted file mode 100644
index 211f5b9..0000000
--- a/chrome/browser/ui/webui/options/advanced_options_utils_x11.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2012 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.
-
-#if !defined(OS_CHROMEOS)
-
-#include "chrome/browser/ui/webui/options/advanced_options_utils.h"
-
-#include "base/bind.h"
-#include "base/environment.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/nix/xdg_util.h"
-#include "base/process/launch.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-
-using content::BrowserThread;
-using content::OpenURLParams;
-using content::Referrer;
-using content::WebContents;
-
-namespace options {
-
-// Command used to configure GNOME 2 proxy settings.
-const char* kGNOME2ProxyConfigCommand[] = {"gnome-network-properties", NULL};
-// In GNOME 3, we might need to run gnome-control-center instead. We try this
-// only after gnome-network-properties is not found, because older GNOME also
-// has this but it doesn't do the same thing. See below where we use it.
-const char* kGNOME3ProxyConfigCommand[] = {"gnome-control-center", "network",
-                                           NULL};
-// KDE3 and KDE4 are only slightly different, but incompatible. Go figure.
-const char* kKDE3ProxyConfigCommand[] = {"kcmshell", "proxy", NULL};
-const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL};
-
-// The URL for Linux proxy configuration help when not running under a
-// supported desktop environment.
-const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config";
-
-namespace {
-
-// Show the proxy config URL in the given tab.
-void ShowLinuxProxyConfigUrl(int render_process_id, int render_view_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  scoped_ptr<base::Environment> env(base::Environment::Create());
-  const char* name = base::nix::GetDesktopEnvironmentName(env.get());
-  if (name)
-    LOG(ERROR) << "Could not find " << name << " network settings in $PATH";
-  OpenURLParams params(
-      GURL(kLinuxProxyConfigUrl), Referrer(), NEW_FOREGROUND_TAB,
-      content::PAGE_TRANSITION_LINK, false);
-
-  WebContents* web_contents =
-      tab_util::GetWebContentsByID(render_process_id, render_view_id);
-  if (web_contents)
-    web_contents->OpenURL(params);
-}
-
-// Start the given proxy configuration utility.
-bool StartProxyConfigUtil(const char* command[]) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  // base::LaunchProcess() returns true ("success") if the fork()
-  // succeeds, but not necessarily the exec(). We'd like to be able to
-  // use StartProxyConfigUtil() to search possible options and stop on
-  // success, so we search $PATH first to predict whether the exec is
-  // expected to succeed.
-  // TODO(mdm): this is a useful check, and is very similar to some
-  // code in proxy_config_service_linux.cc. It should probably be in
-  // base:: somewhere.
-  scoped_ptr<base::Environment> env(base::Environment::Create());
-  std::string path;
-  if (!env->GetVar("PATH", &path)) {
-    LOG(ERROR) << "No $PATH variable. Assuming no " << command[0] << ".";
-    return false;
-  }
-  std::vector<std::string> paths;
-  Tokenize(path, ":", &paths);
-  bool found = false;
-  for (size_t i = 0; i < paths.size(); ++i) {
-    base::FilePath file(paths[i]);
-    if (base::PathExists(file.Append(command[0]))) {
-      found = true;
-      break;
-    }
-  }
-  if (!found)
-    return false;
-  std::vector<std::string> argv;
-  for (size_t i = 0; command[i]; ++i)
-    argv.push_back(command[i]);
-  base::ProcessHandle handle;
-  if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
-    LOG(ERROR) << "StartProxyConfigUtil failed to start " << command[0];
-    return false;
-  }
-  base::EnsureProcessGetsReaped(handle);
-  return true;
-}
-
-// Detect, and if possible, start the appropriate proxy config utility. On
-// failure to do so, show the Linux proxy config URL in a new tab instead.
-void DetectAndStartProxyConfigUtil(int render_process_id,
-                                   int render_view_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  scoped_ptr<base::Environment> env(base::Environment::Create());
-
-  bool launched = false;
-  switch (base::nix::GetDesktopEnvironment(env.get())) {
-    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
-    case base::nix::DESKTOP_ENVIRONMENT_UNITY: {
-      launched = StartProxyConfigUtil(kGNOME2ProxyConfigCommand);
-      if (!launched) {
-        // We try this second, even though it's the newer way, because this
-        // command existed in older versions of GNOME, but it didn't do the
-        // same thing. The older command is gone though, so this should do
-        // the right thing. (Also some distributions have blurred the lines
-        // between GNOME 2 and 3, so we can't necessarily detect what the
-        // right thing is based on indications of which version we have.)
-        launched = StartProxyConfigUtil(kGNOME3ProxyConfigCommand);
-      }
-      break;
-    }
-
-    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
-      launched = StartProxyConfigUtil(kKDE3ProxyConfigCommand);
-      break;
-
-    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
-      launched = StartProxyConfigUtil(kKDE4ProxyConfigCommand);
-      break;
-
-    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
-    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
-      break;
-  }
-
-  if (launched)
-    return;
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-      base::Bind(&ShowLinuxProxyConfigUrl, render_process_id, render_view_id));
-}
-
-}  // anonymous namespace
-
-void AdvancedOptionsUtilities::ShowNetworkProxySettings(
-    WebContents* web_contents) {
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-      base::Bind(&DetectAndStartProxyConfigUtil,
-                 web_contents->GetRenderProcessHost()->GetID(),
-                 web_contents->GetRenderViewHost()->GetRoutingID()));
-}
-
-}  // namespace options
-
-#endif  // !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 03d3d1f..1cc6ecf 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -17,6 +17,7 @@
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/gpu/gpu_mode_manager.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
@@ -507,9 +507,6 @@
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   values->SetBoolean("enableStickyKeys",
                      command_line.HasSwitch(switches::kEnableStickyKeys));
-  values->SetBoolean("enableAutoclick",
-                     command_line.HasSwitch(
-                        ash::switches::kAshEnableAutoclick));
 #endif
 
 #if defined(OS_MACOSX)
@@ -850,13 +847,6 @@
 }
 
 void BrowserOptionsHandler::UpdateDefaultBrowserState() {
-  // Check for side-by-side first.
-  if (ShellIntegration::CanSetAsDefaultBrowser() ==
-          ShellIntegration::SET_DEFAULT_NOT_ALLOWED) {
-    SetDefaultBrowserUIString(IDS_OPTIONS_DEFAULTBROWSER_SXS);
-    return;
-  }
-
 #if defined(OS_MACOSX)
   ShellIntegration::DefaultWebClientState state =
       ShellIntegration::GetDefaultBrowser();
@@ -907,14 +897,21 @@
 void BrowserOptionsHandler::SetDefaultWebClientUIState(
     ShellIntegration::DefaultWebClientUIState state) {
   int status_string_id;
-  if (state == ShellIntegration::STATE_IS_DEFAULT)
+
+  if (state == ShellIntegration::STATE_IS_DEFAULT) {
     status_string_id = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
-  else if (state == ShellIntegration::STATE_NOT_DEFAULT)
-    status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
-  else if (state == ShellIntegration::STATE_UNKNOWN)
+  } else if (state == ShellIntegration::STATE_NOT_DEFAULT) {
+    if (ShellIntegration::CanSetAsDefaultBrowser() ==
+            ShellIntegration::SET_DEFAULT_NOT_ALLOWED) {
+      status_string_id = IDS_OPTIONS_DEFAULTBROWSER_SXS;
+    } else {
+      status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
+    }
+  } else if (state == ShellIntegration::STATE_UNKNOWN) {
     status_string_id = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
-  else
+  } else {
     return;  // Still processing.
+  }
 
   SetDefaultBrowserUIString(status_string_id);
 }
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
index 5fc6abc..0f4c64e 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -1457,8 +1457,9 @@
         shill::kStaticIPAddressProperty,
         address, shill_properties, &properties_to_set);
     int prefixlen = network_util::NetmaskToPrefixLength(netmask);
-    if (prefixlen > 0) {
-      LOG(ERROR) << "Invalid prefix length for: " << service_path;
+    if (prefixlen < 0) {
+      LOG(ERROR) << "Invalid prefix length for: " << service_path
+                 << " with netmask " << netmask;
       prefixlen = 0;
     }
     request_reconnect |= AddIntegerPropertyIfChanged(
diff --git a/chrome/browser/ui/webui/options/chromeos/keyboard_handler.cc b/chrome/browser/ui/webui/options/chromeos/keyboard_handler.cc
index 9c95cc2..6aa795c 100644
--- a/chrome/browser/ui/webui/options/chromeos/keyboard_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/keyboard_handler.cc
@@ -69,6 +69,12 @@
   localized_strings->SetString("remapDiamondKeyToContent",
       l10n_util::GetStringUTF16(
           IDS_OPTIONS_SETTINGS_LANGUAGES_KEY_DIAMOND_KEY_LABEL));
+  localized_strings->SetString("sendFunctionKeys",
+      l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_LANGUAGES_SEND_FUNCTION_KEYS));
+  localized_strings->SetString("sendFunctionKeysDescription",
+      l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_LANGUAGES_SEND_FUNCTION_KEYS_DESCRIPTION));
   localized_strings->SetString("changeLanguageAndInputSettings",
       l10n_util::GetStringUTF16(
           IDS_OPTIONS_SETTINGS_CHANGE_LANGUAGE_AND_INPUT_SETTINGS));
diff --git a/chrome/browser/ui/webui/options/font_settings_browsertest.js b/chrome/browser/ui/webui/options/font_settings_browsertest.js
index f3da8dc..6899858 100644
--- a/chrome/browser/ui/webui/options/font_settings_browsertest.js
+++ b/chrome/browser/ui/webui/options/font_settings_browsertest.js
@@ -16,9 +16,33 @@
    * Browse to the font settings page.
    **/
   browsePreload: 'chrome://settings-frame/fonts',
+
+  /** @inheritDoc */
+  preLoad: function() {
+    this.makeAndRegisterMockHandler(['openAdvancedFontSettingsOptions']);
+  }
 };
 
 // Test opening font settings has correct location.
 TEST_F('FontSettingsWebUITest', 'testOpenFontSettings', function() {
   assertEquals(this.browsePreload, document.location.href);
 });
+
+// Test setup of the Advanced Font Settings links.
+TEST_F('FontSettingsWebUITest', 'testAdvancedFontSettingsLink', function() {
+  var installElement = $('advanced-font-settings-install');
+  var optionsElement = $('advanced-font-settings-options');
+  var expectedUrl = 'https://chrome.google.com/webstore/detail/' +
+      'caclkomlalccbpcdllchkeecicepbmbm';
+
+  FontSettings.notifyAdvancedFontSettingsAvailability(false);
+  assertFalse(installElement.hidden);
+  assertEquals(expectedUrl, installElement.querySelector('a').href);
+  assertTrue(optionsElement.hidden);
+
+  FontSettings.notifyAdvancedFontSettingsAvailability(true);
+  assertTrue(installElement.hidden);
+  assertFalse(optionsElement.hidden);
+  this.mockHandler.expects(once()).openAdvancedFontSettingsOptions();
+  optionsElement.click();
+});
diff --git a/chrome/browser/ui/webui/options/font_settings_handler.cc b/chrome/browser/ui/webui/options/font_settings_handler.cc
index 23f7d6a..fec97fa 100644
--- a/chrome/browser/ui/webui/options/font_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/font_settings_handler.cc
@@ -13,19 +13,27 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/character_encoding.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/webui/options/font_settings_utils.h"
+#include "chrome/common/extensions/extension.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/font_list_async.h"
 #include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_ui.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 #if defined(OS_WIN)
 #include "ui/gfx/font.h"
@@ -47,6 +55,9 @@
 #endif
 }
 
+const char kAdvancedFontSettingsExtensionId[] =
+    "caclkomlalccbpcdllchkeecicepbmbm";
+
 }  // namespace
 
 
@@ -81,6 +92,8 @@
       IDS_FONT_LANGUAGE_SETTING_FONT_SIZE_HUGE },
     { "fontSettingsLoremIpsum",
       IDS_FONT_LANGUAGE_SETTING_LOREM_IPSUM },
+    { "advancedFontSettingsOptions",
+      IDS_FONT_LANGUAGE_SETTING_ADVANCED_FONT_SETTINGS_OPTIONS }
   };
 
   RegisterStrings(localized_strings, resources, arraysize(resources));
@@ -89,6 +102,20 @@
   localized_strings->SetString("fontSettingsPlaceholder",
       l10n_util::GetStringUTF16(
           IDS_FONT_LANGUAGE_SETTING_PLACEHOLDER));
+
+  GURL install_url(extension_urls::GetWebstoreItemDetailURLPrefix());
+  localized_strings->SetString("advancedFontSettingsInstall",
+      l10n_util::GetStringFUTF16(
+          IDS_FONT_LANGUAGE_SETTING_ADVANCED_FONT_SETTINGS_INSTALL,
+          UTF8ToUTF16(
+              install_url.Resolve(kAdvancedFontSettingsExtensionId).spec())));
+}
+
+void FontSettingsHandler::InitializeHandler() {
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                 content::NotificationService::AllSources());
 }
 
 void FontSettingsHandler::InitializePage() {
@@ -98,6 +125,7 @@
   SetUpSansSerifFontSample();
   SetUpFixedFontSample();
   SetUpMinimumFontSample();
+  NotifyAdvancedFontSettingsAvailability();
 }
 
 void FontSettingsHandler::RegisterMessages() {
@@ -142,6 +170,17 @@
   web_ui()->RegisterMessageCallback("fetchFontsData",
       base::Bind(&FontSettingsHandler::HandleFetchFontsData,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("openAdvancedFontSettingsOptions",
+      base::Bind(&FontSettingsHandler::HandleOpenAdvancedFontSettingsOptions,
+                 base::Unretained(this)));
+}
+
+void FontSettingsHandler::Observe(int type,
+                                  const content::NotificationSource& source,
+                                  const content::NotificationDetails& details) {
+  DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
+         type == chrome::NOTIFICATION_EXTENSION_UNLOADED);
+  NotifyAdvancedFontSettingsAvailability();
 }
 
 void FontSettingsHandler::HandleFetchFontsData(const ListValue* args) {
@@ -244,6 +283,31 @@
                                    size_value);
 }
 
+const extensions::Extension*
+FontSettingsHandler::GetAdvancedFontSettingsExtension() {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  if (!service->IsExtensionEnabled(kAdvancedFontSettingsExtensionId))
+    return NULL;
+  return service->GetInstalledExtension(kAdvancedFontSettingsExtensionId);
+}
+
+void FontSettingsHandler::NotifyAdvancedFontSettingsAvailability() {
+  web_ui()->CallJavascriptFunction(
+      "FontSettings.notifyAdvancedFontSettingsAvailability",
+      base::FundamentalValue(GetAdvancedFontSettingsExtension() != NULL));
+}
+
+void FontSettingsHandler::HandleOpenAdvancedFontSettingsOptions(
+    const base::ListValue* args) {
+  const extensions::Extension* extension = GetAdvancedFontSettingsExtension();
+  if (!extension)
+    return;
+  ExtensionTabUtil::OpenOptionsPage(extension,
+      chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
+}
+
 void FontSettingsHandler::OnWebKitDefaultFontSizeChanged() {
   SetUpStandardFontSample();
   SetUpSerifFontSample();
diff --git a/chrome/browser/ui/webui/options/font_settings_handler.h b/chrome/browser/ui/webui/options/font_settings_handler.h
index 32ca8c4..5a533aa 100644
--- a/chrome/browser/ui/webui/options/font_settings_handler.h
+++ b/chrome/browser/ui/webui/options/font_settings_handler.h
@@ -8,11 +8,16 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
+#include "content/public/browser/notification_registrar.h"
 
 namespace base {
 class ListValue;
 }
 
+namespace extensions {
+class Extension;
+}
+
 namespace options {
 
 // Font settings overlay page UI handler.
@@ -23,12 +28,18 @@
 
   // OptionsPageUIHandler implementation.
   virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE;
+  virtual void InitializeHandler() OVERRIDE;
   virtual void InitializePage() OVERRIDE;
 
   // WebUIMessageHandler implementation.
   virtual void RegisterMessages() OVERRIDE;
 
  private:
+  // OptionsPageUIHandler implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
   void HandleFetchFontsData(const ListValue* args);
 
   void FontsListHasLoaded(scoped_ptr<base::ListValue> list);
@@ -38,6 +49,16 @@
   void SetUpSansSerifFontSample();
   void SetUpFixedFontSample();
   void SetUpMinimumFontSample();
+
+  // Returns the Advanced Font Settings Extension if it's installed and enabled,
+  // or NULL otherwise.
+  const extensions::Extension* GetAdvancedFontSettingsExtension();
+  // Notifies the web UI about whether the Advanced Font Settings Extension is
+  // installed and enabled.
+  void NotifyAdvancedFontSettingsAvailability();
+  // Opens the options page of the Advanced Font Settings Extension.
+  void HandleOpenAdvancedFontSettingsOptions(const base::ListValue* args);
+
   void OnWebKitDefaultFontSizeChanged();
 
   StringPrefMember standard_font_;
@@ -49,6 +70,8 @@
   IntegerPrefMember default_fixed_font_size_;
   IntegerPrefMember minimum_font_size_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(FontSettingsHandler);
 };
 
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc
index ada4acd..ec8acfc 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -8,6 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/value_conversions.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/managed_mode/managed_user_service.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/gaia_info_update_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -30,6 +30,7 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/webui/options/options_handlers_helper.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
@@ -363,7 +364,8 @@
       !base::GetValueAsFilePath(*file_path_value, &profile_file_path))
     return;
 
-  AppListService* app_list_service = AppListService::Get();
+  AppListService* app_list_service = AppListService::Get(
+      options::helper::GetDesktopType(web_ui()));
   app_list_service->SetProfilePath(profile_file_path);
   app_list_service->Show();
 
diff --git a/chrome/browser/ui/webui/options/media_galleries_handler.cc b/chrome/browser/ui/webui/options/media_galleries_handler.cc
index a4d76b0..cef51fe 100644
--- a/chrome/browser/ui/webui/options/media_galleries_handler.cc
+++ b/chrome/browser/ui/webui/options/media_galleries_handler.cc
@@ -32,7 +32,8 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   MediaGalleriesPreferences* preferences =
       g_browser_process->media_file_system_registry()->GetPreferences(profile);
-  preferences->RemoveGalleryChangeObserver(this);
+  if (preferences->IsInitialized())
+    preferences->RemoveGalleryChangeObserver(this);
 }
 
 void MediaGalleriesHandler::GetLocalizedValues(DictionaryValue* values) {
@@ -49,39 +50,16 @@
                 IDS_MEDIA_GALLERY_MANAGE_TITLE);
 }
 
-void MediaGalleriesHandler::InitializeHandler() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile);
-  preferences->EnsureInitialized(base::Bind(
-      &MediaGalleriesHandler::InitializeHandlerOnMediaGalleriesPreferencesInit,
-      weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MediaGalleriesHandler::InitializePage() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile);
-  preferences->EnsureInitialized(base::Bind(
-      &MediaGalleriesHandler::InitializePageOnMediaGalleriesPreferencesInit,
-      weak_ptr_factory_.GetWeakPtr()));
-}
-
 void MediaGalleriesHandler::RegisterMessages() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile);
-  preferences->EnsureInitialized(base::Bind(
-      &MediaGalleriesHandler::RegisterOnPreferencesInit,
-      weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MediaGalleriesHandler::RegisterOnPreferencesInit() {
   web_ui()->RegisterMessageCallback(
       "addNewGallery",
       base::Bind(&MediaGalleriesHandler::HandleAddNewGallery,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "initializeMediaGalleries",
+      base::Bind(&MediaGalleriesHandler::HandleInitializeMediaGalleries,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "forgetGallery",
       base::Bind(&MediaGalleriesHandler::HandleForgetGallery,
                  base::Unretained(this)));
@@ -125,26 +103,6 @@
       "options.MediaGalleriesManager.setAvailableMediaGalleries", list);
 }
 
-void MediaGalleriesHandler::InitializeHandlerOnMediaGalleriesPreferencesInit() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  if (!MediaGalleriesPreferences::APIHasBeenUsed(profile))
-    return;
-  MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile);
-
-  preferences->AddGalleryChangeObserver(this);
-}
-
-void MediaGalleriesHandler::InitializePageOnMediaGalleriesPreferencesInit() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  if (!MediaGalleriesPreferences::APIHasBeenUsed(profile))
-    return;
-  MediaGalleriesPreferences* preferences =
-      g_browser_process->media_file_system_registry()->GetPreferences(profile);
-
-  OnGalleriesChanged(preferences);
-}
-
 void MediaGalleriesHandler::HandleAddNewGallery(const base::ListValue* args) {
   select_file_dialog_ = ui::SelectFileDialog::Create(
       this,
@@ -160,6 +118,16 @@
       NULL);
 }
 
+void MediaGalleriesHandler::HandleInitializeMediaGalleries(
+    const base::ListValue* args) {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(profile);
+  preferences->EnsureInitialized(base::Bind(
+      &MediaGalleriesHandler::PreferencesInitialized,
+      weak_ptr_factory_.GetWeakPtr()));
+}
+
 void MediaGalleriesHandler::HandleForgetGallery(const base::ListValue* args) {
   std::string string_id;
   uint64 id = 0;
@@ -188,4 +156,14 @@
   preferences->AddGalleryByPath(path);
 }
 
+void MediaGalleriesHandler::PreferencesInitialized() {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(profile);
+  DCHECK(preferences->IsInitialized());
+  preferences->RemoveGalleryChangeObserver(this);
+  preferences->AddGalleryChangeObserver(this);
+  OnGalleriesChanged(preferences);
+}
+
 }  // namespace options
diff --git a/chrome/browser/ui/webui/options/media_galleries_handler.h b/chrome/browser/ui/webui/options/media_galleries_handler.h
index 267de34..3566344 100644
--- a/chrome/browser/ui/webui/options/media_galleries_handler.h
+++ b/chrome/browser/ui/webui/options/media_galleries_handler.h
@@ -26,8 +26,6 @@
 
   // OptionsPageUIHandler implementation.
   virtual void GetLocalizedValues(base::DictionaryValue* values) OVERRIDE;
-  virtual void InitializeHandler() OVERRIDE;
-  virtual void InitializePage() OVERRIDE;
   virtual void RegisterMessages() OVERRIDE;
 
   // SelectFileDialog::Listener implementation.
@@ -46,6 +44,10 @@
  private:
   // Handles the "addNewGallery" message (no arguments).
   void HandleAddNewGallery(const base::ListValue* args);
+
+  // Handles the "initializeMediaGalleries" message (no arguments).
+  void HandleInitializeMediaGalleries(const base::ListValue* args);
+
   // Handles "forgetGallery" message. The first and only argument is the id of
   // the gallery.
   void HandleForgetGallery(const base::ListValue* args);
@@ -53,14 +55,8 @@
   // Called when the list of known galleries has changed; updates the page.
   void OnGalleriesChanged(MediaGalleriesPreferences* pref);
 
-  // Bottom half of |InitializeHandler()| and |InitializePage()|, respectively,
-  // after async call to initialize MediaGalleriesPreferences.
-  void InitializeHandlerOnMediaGalleriesPreferencesInit();
-  void InitializePageOnMediaGalleriesPreferencesInit();
-
-  // Bottom half of |RegisterMessages()| after async call to initialize
-  // MediaGalleriesPreferences.
-  void RegisterOnPreferencesInit();
+  // Called when MediaGalleriesPreferences have been initialized.
+  void PreferencesInitialized();
 
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
 
diff --git a/chrome/browser/ui/webui/options/options_browsertest.js b/chrome/browser/ui/webui/options/options_browsertest.js
index 2acef84..0a7115e 100644
--- a/chrome/browser/ui/webui/options/options_browsertest.js
+++ b/chrome/browser/ui/webui/options/options_browsertest.js
@@ -668,3 +668,23 @@
     });
   });
 });
+
+// An overlay's position should remain the same as it shows.
+TEST_F('OptionsWebUINavigationTest', 'OverlayShowDoesntShift', function() {
+  var searchEngineOverlay = $('search-engine-manager-page');
+  var frozenPages = document.getElementsByClassName('frozen');  // Gets updated.
+  expectEquals(0, frozenPages.length);
+
+  document.addEventListener('webkitTransitionEnd', function(e) {
+    if (e.target != searchEngineOverlay)
+      return;
+
+    assertFalse(searchEngineOverlay.classList.contains('transparent'));
+    expectEquals(numFrozenPages, frozenPages.length);
+    testDone();
+  });
+
+  OptionsPage.navigateToPage('searchEngines');
+  var numFrozenPages = frozenPages.length;
+  expectGT(numFrozenPages, 0);
+});
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
index d1ef29a..a420edb 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -5,13 +5,17 @@
 #include "chrome/browser/ui/webui/options/password_manager_handler.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/password_manager/password_manager_util.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/core/common/password_form.h"
@@ -28,8 +32,9 @@
 
 PasswordManagerHandler::PasswordManagerHandler()
     : populater_(this),
-      exception_populater_(this),
-      is_user_authenticated_(false) {
+      exception_populater_(this) {
+  require_reauthentication_ = CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnablePasswordManagerReauthentication);
 }
 
 PasswordManagerHandler::~PasswordManagerHandler() {
@@ -157,9 +162,11 @@
     return;
   }
 
-  if (!is_user_authenticated_) {
-    // TODO(dubroy): Insert actual authentication code here.
-    is_user_authenticated_ = true;
+  if (IsAuthenticationRequired()) {
+    if (password_manager_util::AuthenticateUser())
+      last_authentication_time_ = base::TimeTicks::Now();
+    else
+      return;
   }
 
   // Call back the front end to reveal the password.
@@ -178,7 +185,7 @@
     InitializeHandler();
 
   ListValue entries;
-  bool show_passwords = *show_passwords_ && is_user_authenticated_;
+  bool show_passwords = *show_passwords_ && !require_reauthentication_;
   string16 placeholder(ASCIIToUTF16("        "));
   for (size_t i = 0; i < password_list_.size(); ++i) {
     ListValue* entry = new ListValue();
@@ -210,6 +217,12 @@
                                    entries);
 }
 
+bool PasswordManagerHandler::IsAuthenticationRequired() {
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(60);
+  return require_reauthentication_ &&
+      (base::TimeTicks::Now() - last_authentication_time_) > delta;
+}
+
 PasswordManagerHandler::ListPopulater::ListPopulater(
     PasswordManagerHandler* page)
     : page_(page),
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.h b/chrome/browser/ui/webui/options/password_manager_handler.h
index 8dc188e..ee39245 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.h
+++ b/chrome/browser/ui/webui/options/password_manager_handler.h
@@ -64,6 +64,10 @@
   void SetPasswordList();
   void SetPasswordExceptionList();
 
+  // Returns true if the user needs to be authenticated before a plaintext
+  // password is revealed.
+  bool IsAuthenticationRequired();
+
   // A short class to mediate requests to the password store.
   class ListPopulater : public PasswordStoreConsumer {
    public:
@@ -123,9 +127,13 @@
   // Whether to show stored passwords or not.
   BooleanPrefMember show_passwords_;
 
-  // Indicates whether or not the user has recently been authenticated.
-  // Used to determine whether or not to reveal plain text passwords.
-  bool is_user_authenticated_;
+  // Indicates whether or not the password manager should require the user to
+  // reauthenticate before revealing plaintext passwords.
+  bool require_reauthentication_;
+
+  // The last time the user was successfully authenticated.
+  // Used to determine whether or not to reveal plaintext passwords.
+  base::TimeTicks last_authentication_time_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordManagerHandler);
 };
diff --git a/chrome/browser/ui/webui/options/startup_page_list_browsertest.js b/chrome/browser/ui/webui/options/startup_page_list_browsertest.js
new file mode 100644
index 0000000..0cf7b7c
--- /dev/null
+++ b/chrome/browser/ui/webui/options/startup_page_list_browsertest.js
@@ -0,0 +1,148 @@
+// Copyright 2013 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.
+
+/**
+ * Fixture for startup pages WebUI tests.
+ * @extends {testing.Test}
+ * @constructor
+ */
+function StartupPageListWebUITest() {}
+
+StartupPageListWebUITest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /**
+   * Browse to the options page & call our preLoad().
+   * @override
+   */
+  browsePreload: 'chrome://settings-frame/startup',
+
+  /** @override */
+  setUp: function() {
+    StartupOverlay.updateStartupPages(this.fakeStartupList);
+    // 1 item for entering data, 1+ from |this.fakeStartupList|.
+    assertGE(this.getList().items.length, 2);
+  },
+
+  /**
+   * Returns the list to be tested.
+   * @return {Element}
+   * @protected
+   */
+  getList: function() {
+    return $('startupPagesList');
+  },
+
+  /**
+   * Register a mock handler to ensure expectations are met and options pages
+   * behave correctly.
+   * @override
+   */
+  preLoad: function() {
+    this.makeAndRegisterMockHandler(['addStartupPage',
+                                     'dragDropStartupPage']);
+  },
+
+  /**
+   * A fake list of startup pages to send to the overlay.
+   * @protected
+   */
+  fakeStartupList: [
+    {
+      title: 'Yahoo!',
+      url: 'http://yahoo.com',
+      tooltip: 'Yahoo! homepage',
+      modelIndex: 0
+    },
+    {
+      title: 'Facebook',
+      url: 'http://facebook.com',
+      tooltip: 'Facebook :: Sign In',
+      modelIndex: 1
+    }
+  ],
+};
+
+(function() {
+
+/**
+ * A mock data transfer object for drag/drop events.
+ * @constructor
+ */
+function MockDataTransfer() {
+  /**
+   * The data this dataTransfer object knows about.
+   * @type {!Object.<string, string>}
+   * @private
+   */
+  this.data_ = {};
+}
+
+/**
+ * Installs a lazily created MockDataTransfer on event#dataTransfer.
+ * @param {!Event} event An event to modify.
+ */
+MockDataTransfer.install = function(event) {
+  event.__defineGetter__('dataTransfer', function() {
+    event.dataTransfer_ = event.dataTransfer_ || new MockDataTransfer;
+    return event.dataTransfer_;
+  });
+};
+
+MockDataTransfer.prototype = {
+  /**
+   * The URL data in this mock drop event.
+   * @param {string} type The text of data being set.
+   * @param {*} val The data to set. Will be stringified.
+   */
+  setData: function(type, val) {
+    this.data_[type] = String(val);
+  },
+
+  /**
+   * Gets data associated with this fake data transfer.
+   * @param {string} type The type of data to get.
+   * @returns {string} The requested type of data or '' if not set.
+   */
+  getData: function(type) {
+    return this.data_[type] || '';
+  },
+};
+
+/**
+ * Creates a fake bubbling, cancelable mouse event with a mock data transfer
+ * installed.
+ * @param {string} type A type of mouse event (e.g. 'drop').
+ * @return {!Event} A fake mouse event.
+ */
+function createMouseEvent(type) {
+  var event = new MouseEvent(type, {bubbles: true, cancelable: true});
+  MockDataTransfer.install(event);
+  return event;
+}
+
+TEST_F('StartupPageListWebUITest', 'testDropFromOutsideSource', function() {
+  /** @const */ var NEW_PAGE = 'http://google.com';
+
+  var mockDropEvent = createMouseEvent('drop');
+  mockDropEvent.dataTransfer.setData('url', NEW_PAGE);
+
+  this.mockHandler.expects(once()).addStartupPage([NEW_PAGE, 0]);
+
+  this.getList().items[0].dispatchEvent(mockDropEvent);
+
+  expectTrue(mockDropEvent.defaultPrevented);
+});
+
+TEST_F('StartupPageListWebUITest', 'testDropToReorder', function() {
+  // TODO(dbeam): mock4js doesn't handle complex arguments well. Fix this.
+  this.mockHandler.expects(once()).dragDropStartupPage([0, [1].join()]);
+
+  this.getList().selectionModel.selectedIndex = 1;
+  expectEquals(1, this.getList().selectionModel.selectedIndexes.length);
+
+  this.getList().items[0].dispatchEvent(createMouseEvent('drop'));
+});
+
+}());
diff --git a/chrome/browser/ui/webui/options/startup_pages_handler.cc b/chrome/browser/ui/webui/options/startup_pages_handler.cc
index f58b6bc..343b2a6 100644
--- a/chrome/browser/ui/webui/options/startup_pages_handler.cc
+++ b/chrome/browser/ui/webui/options/startup_pages_handler.cc
@@ -151,13 +151,17 @@
 
 void StartupPagesHandler::AddStartupPage(const ListValue* args) {
   std::string url_string;
-  CHECK_EQ(args->GetSize(), 1U);
   CHECK(args->GetString(0, &url_string));
 
   GURL url = URLFixerUpper::FixupURL(url_string, std::string());
   if (!url.is_valid())
     return;
-  int index = startup_custom_pages_table_model_->RowCount();
+
+  int row_count = startup_custom_pages_table_model_->RowCount();
+  int index;
+  if (!args->GetInteger(1, &index) || index > row_count)
+    index = row_count;
+
   startup_custom_pages_table_model_->Add(index, url);
 }
 
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc
index da4d8a5..6e1a798 100644
--- a/chrome/browser/ui/webui/plugins_ui.cc
+++ b/chrome/browser/ui/webui/plugins_ui.cc
@@ -18,6 +18,7 @@
 #include "base/path_service.h"
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/plugins/plugin_finder.h"
 #include "chrome/browser/plugins/plugin_metadata.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 962e93b..0897977 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -60,8 +60,6 @@
 #include "printing/backend/print_backend.h"
 #include "printing/metafile.h"
 #include "printing/metafile_impl.h"
-#include "printing/page_range.h"
-#include "printing/page_size_margins.h"
 #include "printing/print_settings.h"
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
@@ -71,12 +69,8 @@
 #endif
 
 using content::BrowserThread;
-using content::NavigationEntry;
-using content::OpenURLParams;
 using content::RenderViewHost;
-using content::Referrer;
 using content::WebContents;
-using printing::Metafile;
 
 namespace {
 
@@ -247,12 +241,12 @@
 }
 
 // Callback that stores a PDF file on disk.
-void PrintToPdfCallback(Metafile* metafile, const base::FilePath& path) {
+void PrintToPdfCallback(printing::Metafile* metafile,
+                        const base::FilePath& path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   metafile->SaveTo(path);
   // |metafile| must be deleted on the UI thread.
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&base::DeletePointer<Metafile>, metafile));
+  BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, metafile);
 }
 
 std::string GetDefaultPrinterOnFileThread(
@@ -373,7 +367,8 @@
     : public OAuth2TokenService::Consumer {
  public:
   explicit AccessTokenService(PrintPreviewHandler* handler)
-      : handler_(handler) {
+      : handler_(handler),
+        weak_factory_(this) {
   }
 
   void RequestToken(const std::string& type) {
@@ -392,13 +387,35 @@
       }
     } else if (type == "device") {
 #if defined(OS_CHROMEOS)
-      chromeos::DeviceOAuth2TokenService* token_service =
-          chromeos::DeviceOAuth2TokenServiceFactory::Get();
-      account_id = token_service->GetRobotAccountId();
-      service = token_service;
+      chromeos::DeviceOAuth2TokenServiceFactory::Get(
+          base::Bind(
+              &AccessTokenService::DidGetTokenService,
+              weak_factory_.GetWeakPtr(),
+              type));
+      return;
 #endif
     }
 
+    ContinueRequestToken(type, service, account_id);
+  }
+
+#if defined(OS_CHROMEOS)
+  // Continuation of RequestToken().
+  void DidGetTokenService(const std::string& type,
+                          chromeos::DeviceOAuth2TokenService* token_service) {
+    std::string account_id;
+    if (token_service)
+      account_id = token_service->GetRobotAccountId();
+    ContinueRequestToken(type,
+                         token_service,
+                         account_id);
+  }
+#endif
+
+  // Continuation of RequestToken().
+  void ContinueRequestToken(const std::string& type,
+                            OAuth2TokenService* service,
+                            const std::string& account_id) {
     if (service) {
       OAuth2TokenService::ScopeSet oauth_scopes;
       oauth_scopes.insert(cloud_print::kCloudPrintAuth);
@@ -438,6 +455,7 @@
                    linked_ptr<OAuth2TokenService::Request> > Requests;
   Requests requests_;
   PrintPreviewHandler* handler_;
+  base::WeakPtrFactory<AccessTokenService> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
 };
@@ -566,7 +584,8 @@
     settings->SetString(printing::kSettingHeaderFooterTitle,
                         initiator->GetTitle());
     std::string url;
-    NavigationEntry* entry = initiator->GetController().GetActiveEntry();
+    content::NavigationEntry* entry =
+        initiator->GetController().GetActiveEntry();
     if (entry)
       url = entry->GetVirtualURL().spec();
     settings->SetString(printing::kSettingHeaderFooterURL, url);
@@ -672,8 +691,8 @@
     // The PDF being printed contains only the pages that the user selected,
     // so ignore the page range and print all pages.
     settings->Remove(printing::kSettingPageRange, NULL);
-    // Remove selection only flag for the same reason.
-    settings->Remove(printing::kSettingShouldPrintSelectionOnly, NULL);
+    // Reset selection only flag for the same reason.
+    settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
 
 #if defined(USE_CUPS)
     ConvertColorSettingToCUPSColorModel(settings.get());
@@ -699,7 +718,7 @@
 }
 
 void PrintPreviewHandler::PrintToPdf() {
-  if (print_to_pdf_path_.get()) {
+  if (!print_to_pdf_path_.empty()) {
     // User has already selected a path, no need to show the dialog again.
     PostPrintToPdfTask();
   } else if (!select_file_dialog_.get() ||
@@ -830,9 +849,9 @@
   Profile* profile = Profile::FromBrowserContext(
       preview_web_contents()->GetBrowserContext());
   preview_web_contents()->OpenURL(
-      OpenURLParams(
+      content::OpenURLParams(
           CloudPrintURL(profile).GetCloudPrintServiceManageURL(),
-          Referrer(),
+          content::Referrer(),
           NEW_FOREGROUND_TAB,
           content::PAGE_TRANSITION_LINK,
           false));
@@ -1137,7 +1156,7 @@
   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
       preview_web_contents()->GetBrowserContext())->GetPrefs());
   web_ui()->CallJavascriptFunction("fileSelectionCompleted");
-  print_to_pdf_path_.reset(new base::FilePath(path));
+  print_to_pdf_path_ = path;
   PostPrintToPdfTask();
 }
 
@@ -1148,13 +1167,12 @@
     NOTREACHED() << "Preview data was checked before file dialog.";
     return;
   }
-  printing::PreviewMetafile* metafile = new printing::PreviewMetafile;
+  scoped_ptr<printing::PreviewMetafile> metafile(new printing::PreviewMetafile);
   metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
-  // PrintToPdfCallback takes ownership of |metafile|.
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&PrintToPdfCallback, metafile,
-                                     *print_to_pdf_path_));
-  print_to_pdf_path_.reset();
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&PrintToPdfCallback, metafile.release(), print_to_pdf_path_));
+  print_to_pdf_path_ = base::FilePath();
   ClosePreviewDialog();
 }
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 5500c32..23ad9b7 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -18,7 +19,6 @@
 
 namespace base {
 class DictionaryValue;
-class FilePath;
 class RefCountedBytes;
 }
 
@@ -223,7 +223,7 @@
 
   // Holds the path to the print to pdf request. It is empty if no such request
   // exists.
-  scoped_ptr<base::FilePath> print_to_pdf_path_;
+  base::FilePath print_to_pdf_path_;
 
   // Holds token service to get OAuth2 access tokens.
   scoped_ptr<AccessTokenService> token_service_;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index d01fffa..e927c4d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -238,6 +238,9 @@
       l10n_util::GetStringFUTF16(
         IDS_PRINT_PREVIEW_PRINT_WITH_CLOUD_PRINT_WAIT,
         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT)));
+  source->AddString(
+      "noDestsPromoLearnMoreUrl",
+      chrome::kCloudPrintNoDestinationsLearnMoreURL);
   source->AddLocalizedString("pageRangeInstruction",
                              IDS_PRINT_PREVIEW_PAGE_RANGE_INSTRUCTION);
   source->AddLocalizedString("copiesInstruction",
@@ -309,6 +312,8 @@
                              IDS_PRINT_PREVIEW_NO_DESTS_PROMO_BODY);
   source->AddLocalizedString("noDestsPromoGcpDesc",
                              IDS_PRINT_PREVIEW_NO_DESTS_GCP_DESC);
+  source->AddLocalizedString("learnMore",
+                             IDS_LEARN_MORE);
   source->AddLocalizedString(
       "noDestsPromoAddPrinterButtonLabel",
       IDS_PRINT_PREVIEW_NO_DESTS_PROMO_ADD_PRINTER_BUTTON_LABEL);
@@ -338,7 +343,7 @@
   return source;
 }
 
-PrintPreviewUI::TestingDelegate *g_testing_delegate_ = NULL;
+PrintPreviewUI::TestingDelegate* g_testing_delegate = NULL;
 
 }  // namespace
 
@@ -454,8 +459,8 @@
 void PrintPreviewUI::OnDidGetPreviewPageCount(
     const PrintHostMsg_DidGetPreviewPageCount_Params& params) {
   DCHECK_GT(params.page_count, 0);
-  if (g_testing_delegate_)
-    g_testing_delegate_->DidGetPreviewPageCount(params.page_count);
+  if (g_testing_delegate)
+    g_testing_delegate->DidGetPreviewPageCount(params.page_count);
   base::FundamentalValue count(params.page_count);
   base::FundamentalValue request_id(params.preview_request_id);
   web_ui()->CallJavascriptFunction("onDidGetPreviewPageCount",
@@ -499,11 +504,11 @@
   base::FundamentalValue number(page_number);
   base::FundamentalValue ui_identifier(id_);
   base::FundamentalValue request_id(preview_request_id);
-  if (g_testing_delegate_)
-    g_testing_delegate_->DidRenderPreviewPage(*web_ui()->GetWebContents());
+  if (g_testing_delegate)
+    g_testing_delegate->DidRenderPreviewPage(*web_ui()->GetWebContents());
   web_ui()->CallJavascriptFunction(
       "onDidPreviewPage", number, ui_identifier, request_id);
-  if (g_testing_delegate_ && g_testing_delegate_->IsAutoCancelEnabled())
+  if (g_testing_delegate && g_testing_delegate->IsAutoCancelEnabled())
     web_ui()->CallJavascriptFunction("autoCancelForTesting");
 }
 
@@ -593,5 +598,5 @@
 
 // static
 void PrintPreviewUI::SetDelegateForTesting(TestingDelegate* delegate) {
-  g_testing_delegate_ = delegate;
+  g_testing_delegate = delegate;
 }
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_types.cc b/chrome/browser/ui/webui/quota_internals/quota_internals_types.cc
index fea8950..097ccaa 100644
--- a/chrome/browser/ui/webui/quota_internals/quota_internals_types.cc
+++ b/chrome/browser/ui/webui/quota_internals/quota_internals_types.cc
@@ -19,6 +19,8 @@
       return "persistent";
     case quota::kStorageTypeSyncable:
       return "syncable";
+    case quota::kStorageTypeQuotaNotManaged:
+      return "quota not managed";
     case quota::kStorageTypeUnknown:
       return "unknown";
   }
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index 7602d1e..80e4c9c 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -44,6 +44,7 @@
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
+#include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
@@ -504,11 +505,7 @@
     UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
                               signin::HISTOGRAM_SHOWN,
                               signin::HISTOGRAM_MAX);
-    std::string fragment("Email=");
-    fragment += email;
-    GURL::Replacements replacements;
-    replacements.SetRefStr(fragment);
-    url = url.ReplaceComponents(replacements);
+    url = net::AppendQueryParameter(url, "Email", email);
   }
 
   browser->OpenURL(
diff --git a/chrome/browser/ui/webui/task_manager/task_manager_dialog.cc b/chrome/browser/ui/webui/task_manager/task_manager_dialog.cc
index 3ca217b..221df31 100644
--- a/chrome/browser/ui/webui/task_manager/task_manager_dialog.cc
+++ b/chrome/browser/ui/webui/task_manager/task_manager_dialog.cc
@@ -12,11 +12,11 @@
 #include "base/command_line.h"
 #include "base/memory/singleton.h"
 #include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/platform_util.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_dialogs.h"
diff --git a/chrome/browser/ui/webui/welcome_handler_android.cc b/chrome/browser/ui/webui/welcome_handler_android.cc
index aca9068..a585bb3 100644
--- a/chrome/browser/ui/webui/welcome_handler_android.cc
+++ b/chrome/browser/ui/webui/welcome_handler_android.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/values.h"
-#include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/android/chromium_application.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "content/public/browser/web_ui.h"
@@ -46,11 +46,11 @@
 }
 
 void WelcomeHandler::HandleShowSyncSettings(const ListValue* args) {
-  TabAndroid::FromWebContents(web_ui()->GetWebContents())->ShowSyncSettings();
+  chrome::android::ChromiumApplication::ShowSyncSettings();
 }
 
 void WelcomeHandler::HandleShowTermsOfService(const ListValue* args) {
-  TabAndroid::FromWebContents(web_ui()->GetWebContents())->ShowTermsOfService();
+  chrome::android::ChromiumApplication::ShowTermsOfServiceDialog();
 }
 
 void WelcomeHandler::OnStateChanged() {
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index 7a37701..ebad0cb 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -46,7 +46,7 @@
     native_window_->Hide();
   }
   virtual void Activate() OVERRIDE {
-    GetActivationClient(
+    aura::client::GetActivationClient(
         native_window_->GetRootWindow())->ActivateWindow(native_window_.get());
   }
   virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
diff --git a/chrome/browser/upload_list.cc b/chrome/browser/upload_list.cc
index 6b6f93b..2f96005 100644
--- a/chrome/browser/upload_list.cc
+++ b/chrome/browser/upload_list.cc
@@ -54,7 +54,7 @@
     base::ReadFileToString(upload_log_path_, &contents);
     std::vector<std::string> log_entries;
     base::SplitStringAlongWhitespace(contents, &log_entries);
-    uploads_.clear();
+    ClearUploads();
     ParseLogEntries(log_entries);
   }
 }
@@ -63,6 +63,10 @@
   uploads_.push_back(info);
 }
 
+void UploadList::ClearUploads() {
+  uploads_.clear();
+}
+
 void UploadList::ParseLogEntries(
     const std::vector<std::string>& log_entries) {
   std::vector<std::string>::const_reverse_iterator i;
diff --git a/chrome/browser/upload_list.h b/chrome/browser/upload_list.h
index 23c4ff5..e62288d 100644
--- a/chrome/browser/upload_list.h
+++ b/chrome/browser/upload_list.h
@@ -65,6 +65,9 @@
   // Adds |info| to |uploads_|.
   void AppendUploadInfo(const UploadInfo& info);
 
+  // Clear |uploads_|.
+  void ClearUploads();
+
  private:
   friend class base::RefCountedThreadSafe<UploadList>;
   FRIEND_TEST_ALL_PREFIXES(UploadListTest, ParseLogEntries);
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index e5b5c2c..40ebc27 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -495,8 +495,18 @@
   if (success_count != paths.size())
     return false;
 
-  if (creation_locations.in_quick_launch_bar && path_to_add_to_dock)
-    dock::AddIcon(path_to_add_to_dock, nil);
+  if (creation_locations.in_quick_launch_bar && path_to_add_to_dock) {
+    switch (dock::AddIcon(path_to_add_to_dock, nil)) {
+      case dock::IconAddFailure:
+        // If adding the icon failed, instead reveal the Finder window.
+        RevealAppShimInFinder();
+        break;
+      case dock::IconAddSuccess:
+      case dock::IconAlreadyPresent:
+        break;
+    }
+    return true;
+  }
 
   if (creation_reason == SHORTCUT_CREATION_BY_USER)
     RevealAppShimInFinder();
diff --git a/chrome/browser/webdata/keyword_table.cc b/chrome/browser/webdata/keyword_table.cc
index ec02c29..f7b75a5 100644
--- a/chrome/browser/webdata/keyword_table.cc
+++ b/chrome/browser/webdata/keyword_table.cc
@@ -642,7 +642,7 @@
     TemplateURL turl(NULL, data);
     // Don't persist extension keywords to disk.  These will get added to the
     // TemplateURLService as the extensions are loaded.
-    bool delete_entry = turl.IsExtensionKeyword();
+    bool delete_entry = turl.GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
     if (!delete_entry && generate_keyword) {
       // Explicitly generate keywords for all rows with the autogenerate bit set
       // or where the keyword is empty.
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate
index 40c98f6..150f018 100644
--- a/chrome/browser_tests.isolate
+++ b/chrome/browser_tests.isolate
@@ -8,13 +8,10 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
-          '--use-less-jobs',
           '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_tracked': [
           '../testing/xvfb.py',
-          '<(PRODUCT_DIR)/chrome<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/libclearkeycdm.so',
           '<(PRODUCT_DIR)/libclearkeycdmadapter.so',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
@@ -87,6 +84,7 @@
     ['OS=="linux" or OS=="win"', {
       'variables': {
         'isolate_dependency_tracked': [
+          '<(PRODUCT_DIR)/chrome<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/chrome_100_percent.pak',
           '<(PRODUCT_DIR)/locales/en-US.pak',
           '<(PRODUCT_DIR)/locales/fr.pak',
@@ -117,6 +115,7 @@
         ],
         'isolate_dependency_untracked': [
           '<(PRODUCT_DIR)/Chromium Framework.framework/',
+          '<(PRODUCT_DIR)/Chromium Helper.app/',
           '<(PRODUCT_DIR)/Chromium.app/',
           '<(PRODUCT_DIR)/lib32/',
           '<(PRODUCT_DIR)/plugins/TestNetscapePlugIn.plugin/',
@@ -128,8 +127,6 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
-          '--use-less-jobs',
           '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
         ],
       },
@@ -143,6 +140,7 @@
           '<(PRODUCT_DIR)/D3DCompiler_43.dll',
           '<(PRODUCT_DIR)/clearkeycdm.dll',
           '<(PRODUCT_DIR)/clearkeycdmadapter.dll',
+          '<(PRODUCT_DIR)/chrome.dll',
           '<(PRODUCT_DIR)/d3dcompiler_46.dll',
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/icudt.dll',
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 546f220..f7f7d59 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -173,6 +173,8 @@
             'browser/devtools/adb_client_socket.h',
             'browser/devtools/adb_web_socket.cc',
             'browser/devtools/adb_web_socket.h',
+            'browser/devtools/android_device.cc',
+            'browser/devtools/android_device.h',
             'browser/devtools/browser_list_tabcontents_provider.cc',
             'browser/devtools/browser_list_tabcontents_provider.h',
             'browser/devtools/devtools_adb_bridge.cc',
@@ -185,11 +187,15 @@
             'browser/devtools/devtools_file_system_indexer.h',
             'browser/devtools/devtools_protocol.cc',
             'browser/devtools/devtools_protocol.h',
+            'browser/devtools/devtools_target_impl.cc',
+            'browser/devtools/devtools_target_impl.h',
             'browser/devtools/devtools_toggle_action.h',
             'browser/devtools/devtools_window.cc',
             'browser/devtools/devtools_window.h',
             'browser/devtools/port_forwarding_controller.cc',
             'browser/devtools/port_forwarding_controller.h',
+            'browser/devtools/refcounted_adb_thread.cc',
+            'browser/devtools/refcounted_adb_thread.h',
             'browser/devtools/remote_debugging_server.cc',
             'browser/devtools/remote_debugging_server.h',
           ],
@@ -207,6 +213,7 @@
                 'browser/devtools/adb/android_rsa.cc',
                 'browser/devtools/browser_list_tabcontents_provider.cc',
                 'browser/devtools/devtools_file_system_indexer.cc',
+                'browser/devtools/devtools_target_impl.cc',
                 'browser/devtools/devtools_window.cc',
                 'browser/devtools/remote_debugging_server.cc',
               ],
@@ -354,22 +361,6 @@
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
           'msvs_disabled_warnings': [ 4267, ],
         },
-        {
-          'target_name': 'ipclist',
-          'type': 'executable',
-          'variables': { 'enable_wexit_time_destructors': 1, },
-          'dependencies': [
-            'test_support_common',
-            '../skia/skia.gyp:skia',
-            '../sync/sync.gyp:sync',
-          ],
-          'include_dirs': [
-             '..',
-          ],
-          'sources': [
-            'tools/ipclist/ipclist.cc',
-          ],
-        },
       ],
     }],  # OS!="ios"
     ['OS=="mac"',
@@ -827,7 +818,7 @@
             '../content/content_shell_and_tests.gyp:content_shell',
             '../content/content_shell_and_tests.gyp:content_unittests',
             '../net/net.gyp:net_unittests',
-            '../ui/ui.gyp:ui_unittests',
+            '../ui/ui_unittests.gyp:ui_unittests',
           ],
           'conditions': [
             ['use_aura==1 or target_arch=="x64"', {
diff --git a/chrome/chrome_android.gypi b/chrome/chrome_android.gypi
index 9b8cbb7..7cdac10 100644
--- a/chrome/chrome_android.gypi
+++ b/chrome/chrome_android.gypi
@@ -16,7 +16,6 @@
       'dependencies': [
         '../base/base.gyp:base',
         'chrome_android_core',
-        'chrome_android_auxiliary',
         'chromium_testshell_jni_headers',
         'chrome.gyp:browser_ui',
         '../content/content.gyp:content_app_browser',
@@ -117,8 +116,6 @@
       'sources': [
         'app/android/chrome_android_initializer.cc',
         'app/android/chrome_android_initializer.h',
-        'app/android/chrome_data_reduction_proxy_android.cc',
-        'app/android/chrome_data_reduction_proxy_android.h',
         'app/android/chrome_main_delegate_android.cc',
         'app/android/chrome_main_delegate_android.h',
         'app/chrome_main_delegate.cc',
@@ -132,19 +129,6 @@
       },
     },
     {
-       'target_name': 'chrome_android_auxiliary',
-       'type': 'static_library',
-       'include_dirs': [
-         '<(SHARED_INTERMEDIATE_DIR)/chromium_testshell',
-       ],
-       'sources': [
-         'android/testshell/chrome_data_reduction_proxy_testshell_android.cc',
-       ],
-       'dependencies': [
-         '../base/base.gyp:base',
-       ],
-    },
-    {
       'target_name': 'chromium_testshell_paks',
       'type': 'none',
       'dependencies': [
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index fddebc7..d55f7a0 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -28,6 +28,7 @@
         'safe_browsing_report_proto',
         '../components/components.gyp:browser_context_keyed_service',
         '../components/components.gyp:encryptor',
+        '../components/components.gyp:navigation_metrics',
         '../components/components.gyp:sessions',
         '../components/components.gyp:startup_metric_utils',
         '../components/components.gyp:translate_common',
@@ -62,7 +63,7 @@
         '../ui/events/events.gyp:events',
         '../ui/gfx/gfx.gyp:gfx',
         '../ui/message_center/message_center.gyp:message_center',
-        '../ui/ui.gyp:shell_dialogs',
+        '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
         '../ui/ui.gyp:ui',
         '../ui/ui.gyp:ui_resources',
         '../webkit/common/user_agent/webkit_user_agent.gyp:user_agent',
@@ -127,13 +128,13 @@
         'browser/android/provider/chrome_browser_provider.cc',
         'browser/android/provider/chrome_browser_provider.h',
         'browser/android/provider/run_on_ui_thread_blocking.h',
+        'browser/android/recently_closed_tabs_bridge.cc',
+        'browser/android/recently_closed_tabs_bridge.h',
         'browser/android/resource_mapper.cc',
         'browser/android/resource_mapper.h',
         'browser/android/resource_id.h',
         'browser/android/shortcut_helper.cc',
         'browser/android/shortcut_helper.h',
-        'browser/android/signin/google_auto_login_helper.cc',
-        'browser/android/signin/google_auto_login_helper.h',
         'browser/android/signin/signin_manager_android.cc',
         'browser/android/signin/signin_manager_android.h',
         'browser/android/tab_android.cc',
@@ -701,8 +702,6 @@
         'browser/google_apis/task_util.h',
         'browser/google_apis/time_util.cc',
         'browser/google_apis/time_util.h',
-        'browser/gpu/chrome_gpu_util.cc',
-        'browser/gpu/chrome_gpu_util.h',
         'browser/gpu/gl_string_manager.cc',
         'browser/gpu/gl_string_manager.h',
         'browser/gpu/gpu_feature_checker.cc',
@@ -1079,6 +1078,7 @@
         'browser/media_galleries/fileapi/native_media_file_util.h',
         'browser/media_galleries/fileapi/picasa_finder.cc',
         'browser/media_galleries/fileapi/picasa_finder.h',
+        'browser/media_galleries/fileapi/picasa_finder_mac.mm',
         'browser/media_galleries/fileapi/safe_audio_video_checker.cc',
         'browser/media_galleries/fileapi/safe_audio_video_checker.h',
         'browser/media_galleries/fileapi/supported_audio_video_checker.cc',
@@ -1111,7 +1111,6 @@
         'browser/media_galleries/media_galleries_preferences.h',
         'browser/media_galleries/media_galleries_preferences_factory.cc',
         'browser/media_galleries/media_galleries_preferences_factory.h',
-        'browser/media_galleries/mtp_device_delegate_impl.h',
         'browser/media_galleries/win/mtp_device_delegate_impl_win.cc',
         'browser/media_galleries/win/mtp_device_delegate_impl_win.h',
         'browser/media_galleries/win/mtp_device_object_entry.cc',
@@ -1368,6 +1367,9 @@
         'browser/password_manager/password_manager_delegate_impl.h',
         'browser/password_manager/password_manager_metrics_util.cc',
         'browser/password_manager/password_manager_metrics_util.h',
+        'browser/password_manager/password_manager_util.h',
+        'browser/password_manager/password_manager_util_mac.mm',
+        'browser/password_manager/password_manager_util_stub.cc',
         'browser/password_manager/password_store.cc',
         'browser/password_manager/password_store.h',
         'browser/password_manager/password_store_consumer.cc',
@@ -1445,6 +1447,8 @@
         'browser/policy/async_policy_loader.h',
         'browser/policy/async_policy_provider.cc',
         'browser/policy/async_policy_provider.h',
+        'browser/policy/autofill_policy_handler.cc',
+        'browser/policy/autofill_policy_handler.h',
         'browser/policy/browser_policy_connector.cc',
         'browser/policy/browser_policy_connector.h',
         'browser/policy/cloud/cloud_external_data_manager.cc',
@@ -1526,6 +1530,10 @@
         'browser/policy/external_data_fetcher.cc',
         'browser/policy/external_data_fetcher.h',
         'browser/policy/external_data_manager.h',
+        'browser/policy/file_selection_dialogs_policy_handler.cc',
+        'browser/policy/file_selection_dialogs_policy_handler.h',
+        'browser/policy/javascript_policy_handler.cc',
+        'browser/policy/javascript_policy_handler.h',
         'browser/policy/policy_bundle.cc',
         'browser/policy/policy_bundle.h',
         'browser/policy/policy_domain_descriptor.cc',
@@ -1562,6 +1570,8 @@
         'browser/policy/registry_dict_win.h',
         'browser/policy/url_blacklist_manager.cc',
         'browser/policy/url_blacklist_manager.h',
+        'browser/policy/url_blacklist_policy_handler.cc',
+        'browser/policy/url_blacklist_policy_handler.h',
         'browser/predictors/autocomplete_action_predictor.cc',
         'browser/predictors/autocomplete_action_predictor.h',
         'browser/predictors/autocomplete_action_predictor_factory.cc',
@@ -1613,8 +1623,6 @@
         'browser/prefs/proxy_config_dictionary.h',
         'browser/prefs/proxy_prefs.cc',
         'browser/prefs/proxy_prefs.h',
-        'browser/prefs/scoped_user_pref_update.cc',
-        'browser/prefs/scoped_user_pref_update.h',
         'browser/prefs/session_startup_pref.cc',
         'browser/prefs/session_startup_pref.h',
         'browser/prefs/synced_pref_change_registrar.cc',
@@ -1715,6 +1723,8 @@
         'browser/process_singleton_win.cc',
         'browser/profile_resetter/automatic_profile_resetter.h',
         'browser/profile_resetter/automatic_profile_resetter.cc',
+        'browser/profile_resetter/automatic_profile_resetter_delegate.h',
+        'browser/profile_resetter/automatic_profile_resetter_delegate.cc',
         'browser/profile_resetter/automatic_profile_resetter_factory.h',
         'browser/profile_resetter/automatic_profile_resetter_factory.cc',
         'browser/profile_resetter/automatic_profile_resetter_mementos.h',
@@ -1756,6 +1766,8 @@
         'browser/profiles/gaia_info_update_service_factory.h',
         'browser/profiles/incognito_helpers.cc',
         'browser/profiles/incognito_helpers.h',
+        'browser/profiles/incognito_mode_policy_handler.cc',
+        'browser/profiles/incognito_mode_policy_handler.h',
         'browser/profiles/off_the_record_profile_impl.cc',
         'browser/profiles/off_the_record_profile_impl.h',
         'browser/profiles/off_the_record_profile_io_data.cc',
@@ -1973,6 +1985,8 @@
         'browser/sessions/base_session_service.h',
         'browser/sessions/persistent_tab_restore_service.cc',
         'browser/sessions/persistent_tab_restore_service.h',
+        'browser/sessions/restore_on_startup_policy_handler.cc',
+        'browser/sessions/restore_on_startup_policy_handler.h',
         'browser/sessions/session_backend.cc',
         'browser/sessions/session_backend.h',
         'browser/sessions/session_command.cc',
@@ -2016,6 +2030,10 @@
         'browser/signin/account_reconcilor_factory.h',
         'browser/signin/chrome_signin_manager_delegate.cc',
         'browser/signin/chrome_signin_manager_delegate.h',
+        'browser/signin/google_auto_login_helper.cc',
+        'browser/signin/google_auto_login_helper.h',
+        'browser/signin/local_auth.cc',
+        'browser/signin/local_auth.h',
         'browser/signin/profile_oauth2_token_service.cc',
         'browser/signin/profile_oauth2_token_service.h',
         'browser/signin/profile_oauth2_token_service_factory.cc',
@@ -2037,6 +2055,8 @@
         'browser/signin/signin_manager_factory.h',
         'browser/signin/signin_names_io_thread.cc',
         'browser/signin/signin_names_io_thread.h',
+        'browser/signin/signin_oauth_helper.cc',
+        'browser/signin/signin_oauth_helper.h',
         'browser/signin/signin_tracker.cc',
         'browser/signin/signin_tracker.h',
         'browser/signin/signin_promo.cc',
@@ -2301,6 +2321,8 @@
         'browser/sync/sessions2/tab_node_pool2.h',
         'browser/sync/sync_global_error.cc',
         'browser/sync/sync_global_error.h',
+        'browser/sync/sync_policy_handler.cc',
+        'browser/sync/sync_policy_handler.h',
         'browser/sync/sync_prefs.cc',
         'browser/sync/sync_prefs.h',
         'browser/sync/sync_startup_tracker.cc',
@@ -2315,6 +2337,8 @@
         'browser/sync_file_system/drive_backend/drive_backend_constants.h',
         'browser/sync_file_system/drive_backend/drive_backend_util.cc',
         'browser/sync_file_system/drive_backend/drive_backend_util.h',
+        'browser/sync_file_system/drive_backend/list_changes_task.cc',
+        'browser/sync_file_system/drive_backend/list_changes_task.h',
         'browser/sync_file_system/drive_backend/local_to_remote_syncer.cc',
         'browser/sync_file_system/drive_backend/local_to_remote_syncer.h',
         'browser/sync_file_system/drive_backend/metadata_database.cc',
@@ -2404,6 +2428,7 @@
         'browser/tab_contents/background_contents.h',
         'browser/tab_contents/language_state.cc',
         'browser/tab_contents/language_state.h',
+        'browser/tab_contents/language_state_observer.h',
         'browser/tab_contents/navigation_metrics_recorder.cc',
         'browser/tab_contents/navigation_metrics_recorder.h',
         'browser/tab_contents/render_view_context_menu.cc',
@@ -3170,7 +3195,6 @@
         ['OS=="android"', {
           'dependencies': [
             '../components/components.gyp:web_contents_delegate_android',
-            '../sync/sync.gyp:sync_jni_headers',
             'chrome_browser_jni_headers',
           ],
           'dependencies!': [
@@ -3637,6 +3661,7 @@
             'android/java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java',
             'android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java',
             'android/java/src/org/chromium/chrome/browser/profiles/Profile.java',
+            'android/java/src/org/chromium/chrome/browser/RecentlyClosedBridge.java',
             'android/java/src/org/chromium/chrome/browser/ShortcutHelper.java',
             'android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java',
             'android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java',
@@ -3654,6 +3679,7 @@
             'android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java',
             'android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java',
             'android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBarDelegate.java',
+            'android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java'
           ],
           'variables': {
             'jni_gen_package': 'chrome',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 7027970..fc3190c 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -61,8 +61,6 @@
         # tests and mocks.
         'browser/apps/app_launch_for_metro_restart_win.cc',
         'browser/apps/app_launch_for_metro_restart_win.h',
-        'browser/apps/app_launcher_util.cc',
-        'browser/apps/app_launcher_util.h',
         'browser/apps/app_url_redirector.cc',
         'browser/apps/app_url_redirector.h',
         'browser/apps/chrome_apps_client.cc',
@@ -149,8 +147,13 @@
         'browser/extensions/api/braille_display_private/braille_display_private_api.cc',
         'browser/extensions/api/braille_display_private/brlapi_connection.cc',
         'browser/extensions/api/braille_display_private/brlapi_connection.h',
+        'browser/extensions/api/braille_display_private/stub_braille_controller.cc',
+        'browser/extensions/api/braille_display_private/stub_braille_controller.h',
         'browser/extensions/api/browsing_data/browsing_data_api.cc',
         'browser/extensions/api/browsing_data/browsing_data_api.h',
+        'browser/extensions/api/cast_channel/cast_auth_util.h',
+        'browser/extensions/api/cast_channel/cast_auth_util_nss.cc',
+        'browser/extensions/api/cast_channel/cast_auth_util_openssl.cc',
         'browser/extensions/api/cast_channel/cast_channel_api.cc',
         'browser/extensions/api/cast_channel/cast_channel_api.h',
         'browser/extensions/api/cast_channel/cast_message_util.cc',
@@ -286,8 +289,6 @@
         'browser/extensions/api/identity/gaia_web_auth_flow.h',
         'browser/extensions/api/identity/identity_api.cc',
         'browser/extensions/api/identity/identity_api.h',
-        'browser/extensions/api/identity/identity_event_router.cc',
-        'browser/extensions/api/identity/identity_event_router.h',
         'browser/extensions/api/identity/identity_mint_queue.cc',
         'browser/extensions/api/identity/identity_mint_queue.h',
         'browser/extensions/api/identity/identity_signin_flow.cc',
@@ -456,6 +457,8 @@
         'browser/extensions/api/sessions/sessions_api.h',
         'browser/extensions/api/sessions/session_id.cc',
         'browser/extensions/api/sessions/session_id.h',
+        'browser/extensions/api/settings_overrides/settings_overrides_api.cc',
+        'browser/extensions/api/settings_overrides/settings_overrides_api.h',
         'browser/extensions/api/signed_in_devices/id_mapping_helper.cc',
         'browser/extensions/api/signed_in_devices/id_mapping_helper.h',
         'browser/extensions/api/signed_in_devices/signed_in_devices_api.cc',
@@ -604,6 +607,8 @@
         'browser/extensions/api/web_request/web_request_permissions.h',
         'browser/extensions/api/web_request/web_request_time_tracker.cc',
         'browser/extensions/api/web_request/web_request_time_tracker.h',
+        'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc',
+        'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h',
         'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc',
         'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h',
         'browser/extensions/api/webstore_private/webstore_private_api.cc',
@@ -626,6 +631,10 @@
         'browser/extensions/browser_permissions_policy_delegate.h',
         'browser/extensions/bundle_installer.cc',
         'browser/extensions/bundle_installer.h',
+        'browser/extensions/chrome_extension_function.cc',
+        'browser/extensions/chrome_extension_function.h',
+        'browser/extensions/chrome_extensions_browser_client.cc',
+        'browser/extensions/chrome_extensions_browser_client.h',
         'browser/extensions/component_loader.cc',
         'browser/extensions/component_loader.h',
         'browser/extensions/context_menu_matcher.cc',
@@ -730,6 +739,10 @@
         'browser/extensions/extension_sorting.h',
         'browser/extensions/extension_special_storage_policy.cc',
         'browser/extensions/extension_special_storage_policy.h',
+        'browser/extensions/extension_sync_service.cc',
+        'browser/extensions/extension_sync_service.h',
+        'browser/extensions/extension_sync_service_factory.cc',
+        'browser/extensions/extension_sync_service_factory.h',
         'browser/extensions/extension_system.cc',
         'browser/extensions/extension_system.h',
         'browser/extensions/extension_sync_bundle.cc',
@@ -800,8 +813,6 @@
         'browser/extensions/install_tracker.h',
         'browser/extensions/install_tracker_factory.cc',
         'browser/extensions/install_tracker_factory.h',
-        'browser/extensions/lazy_background_task_queue.cc',
-        'browser/extensions/lazy_background_task_queue.h',
         'browser/extensions/location_bar_controller.h',
         'browser/extensions/management_policy.cc',
         'browser/extensions/management_policy.h',
@@ -870,6 +881,8 @@
         'browser/extensions/webstore_data_fetcher.cc',
         'browser/extensions/webstore_data_fetcher.h',
         'browser/extensions/webstore_data_fetcher_delegate.h',
+        'browser/extensions/webstore_ephemeral_installer.cc',
+        'browser/extensions/webstore_ephemeral_installer.h',
         'browser/extensions/webstore_inline_installer.cc',
         'browser/extensions/webstore_inline_installer.h',
         'browser/extensions/webstore_inline_installer_factory.cc',
@@ -1080,6 +1093,13 @@
           'sources!': [
             # networking_private_crypto.cc uses NSS functions.
             'browser/extensions/api/networking_private/networking_private_crypto.cc',
+            # cast_auth_util_nss.cc uses NSS functions.
+            'browser/extensions/api/cast_channel/cast_auth_util_nss.cc',
+          ],
+        }, {
+          # If not using OpenSSL then exclude the OpenSSL specific code.
+          'sources!': [
+            'browser/extensions/api/cast_channel/cast_auth_util_openssl.cc',
           ],
         }],
         ['OS=="android"', {
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 9dc1477..5bcd99d 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -127,6 +127,8 @@
         'browser/ui/app_list/app_list.h',
         'browser/ui/app_list/app_list_controller_delegate.cc',
         'browser/ui/app_list/app_list_controller_delegate.h',
+        'browser/ui/app_list/app_list_controller_delegate_impl.cc',
+        'browser/ui/app_list/app_list_controller_delegate_impl.h',
         'browser/ui/app_list/app_list_factory.h',
         'browser/ui/app_list/app_list_service.cc',
         'browser/ui/app_list/app_list_service.h',
@@ -142,6 +144,8 @@
         'browser/ui/app_list/app_list_shower.h',
         'browser/ui/app_list/app_list_icon_win.cc',
         'browser/ui/app_list/app_list_icon_win.h',
+        'browser/ui/app_list/app_list_util.cc',
+        'browser/ui/app_list/app_list_util.h',
         'browser/ui/app_list/app_list_view_delegate.cc',
         'browser/ui/app_list/app_list_view_delegate.h',
         'browser/ui/app_list/chrome_signin_delegate.cc',
@@ -150,6 +154,8 @@
         'browser/ui/app_list/extension_app_item.h',
         'browser/ui/app_list/extension_app_model_builder.cc',
         'browser/ui/app_list/extension_app_model_builder.h',
+        'browser/ui/app_list/extension_uninstaller.cc',
+        'browser/ui/app_list/extension_uninstaller.h',
         'browser/ui/app_list/keep_alive_service.h',
         'browser/ui/app_list/keep_alive_service_impl.cc',
         'browser/ui/app_list/keep_alive_service_impl.h',
@@ -169,6 +175,8 @@
         'browser/ui/app_list/search/common/url_icon_source.h',
         'browser/ui/app_list/search/common/webservice_cache.cc',
         'browser/ui/app_list/search/common/webservice_cache.h',
+        'browser/ui/app_list/search/common/webservice_cache_factory.cc',
+        'browser/ui/app_list/search/common/webservice_cache_factory.h',
         'browser/ui/app_list/search/common/webservice_search_provider.cc',
         'browser/ui/app_list/search/common/webservice_search_provider.h',
         'browser/ui/app_list/search/history.cc',
@@ -254,6 +262,10 @@
         'browser/ui/ash/caps_lock_delegate_views.h',
         'browser/ui/ash/chrome_launcher_prefs.cc',
         'browser/ui/ash/chrome_launcher_prefs.h',
+        'browser/ui/ash/chrome_new_window_delegate.cc',
+        'browser/ui/ash/chrome_new_window_delegate.h',
+        'browser/ui/ash/chrome_new_window_delegate_chromeos.cc',
+        'browser/ui/ash/chrome_new_window_delegate_chromeos.h',
         'browser/ui/ash/chrome_shell_delegate.cc',
         'browser/ui/ash/chrome_shell_delegate.h',
         'browser/ui/ash/chrome_shell_delegate_chromeos.cc',
@@ -288,17 +300,23 @@
         'browser/ui/ash/launcher/launcher_item_controller.h',
         'browser/ui/ash/launcher/launcher_application_menu_item_model.cc',
         'browser/ui/ash/launcher/launcher_application_menu_item_model.h',
+        'browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc',
+        'browser/ui/ash/launcher/multi_profile_browser_status_monitor.h',
+        'browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.cc',
+        'browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h',        
         'browser/ui/ash/launcher/shell_window_launcher_item_controller.cc',
         'browser/ui/ash/launcher/shell_window_launcher_item_controller.h',
         'browser/ui/ash/launcher/shell_window_launcher_controller.cc',
         'browser/ui/ash/launcher/shell_window_launcher_controller.h',
-        'browser/ui/ash/multi_user_window_manager.h',        
+        'browser/ui/ash/multi_user_window_manager.h',
         'browser/ui/ash/screenshot_taker.cc',
         'browser/ui/ash/screenshot_taker.h',
         'browser/ui/ash/session_state_delegate_chromeos.cc',
         'browser/ui/ash/session_state_delegate_chromeos.h',
         'browser/ui/ash/session_state_delegate_views.cc',
         'browser/ui/ash/session_state_delegate_views.h',
+        'browser/ui/ash/system_tray_delegate_win.cc',
+        'browser/ui/ash/system_tray_delegate_win.h',
         'browser/ui/ash/tabs/dock_info_ash.cc',
         'browser/ui/ash/tabs/dock_info_ash.h',
         'browser/ui/ash/tabs/dock_info_chromeos.cc',
@@ -314,7 +332,7 @@
         'browser/ui/aura/chrome_browser_main_extra_parts_aura.h',
         'browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.cc',
         'browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h',
-        'browser/ui/aura/tabs/dock_info_aurax11.cc',
+        'browser/ui/aura/tabs/dock_info_auralinux.cc',
         'browser/ui/autofill/account_chooser_model.cc',
         'browser/ui/autofill/account_chooser_model.h',
         'browser/ui/autofill/autofill_dialog_common.cc',
@@ -399,6 +417,8 @@
         'browser/ui/browser_instant_controller.h',
         'browser/ui/browser_iterator.cc',
         'browser/ui/browser_iterator.h',
+        'browser/ui/browser_language_state_observer.cc',
+        'browser/ui/browser_language_state_observer.h',
         'browser/ui/browser_list.cc',
         'browser/ui/browser_list.h',
         'browser/ui/browser_mac.cc',
@@ -1333,8 +1353,6 @@
         'browser/ui/host_desktop.h',
         'browser/ui/hung_plugin_tab_helper.cc',
         'browser/ui/hung_plugin_tab_helper.h',
-        'browser/ui/immersive_fullscreen_configuration.cc',
-        'browser/ui/immersive_fullscreen_configuration.h',
         'browser/ui/login/login_model.h',
         'browser/ui/login/login_prompt.cc',
         'browser/ui/login/login_prompt.h',
@@ -1572,6 +1590,8 @@
         'browser/ui/top_level_widget.h',
         'browser/ui/translate/language_combobox_model.cc',
         'browser/ui/translate/language_combobox_model.h',
+        'browser/ui/translate/translate_bubble_factory.cc',
+        'browser/ui/translate/translate_bubble_factory.h',
         'browser/ui/translate/translate_bubble_model.h',
         'browser/ui/translate/translate_bubble_model_impl.cc',
         'browser/ui/translate/translate_bubble_model_impl.h',
@@ -1689,6 +1709,7 @@
         'browser/ui/views/desktop_media_picker_views.cc',
         'browser/ui/views/detachable_toolbar_view.cc',
         'browser/ui/views/detachable_toolbar_view.h',
+        'browser/ui/views/download/download_danger_prompt_views.cc',
         'browser/ui/views/download/download_in_progress_dialog_view.cc',
         'browser/ui/views/download/download_in_progress_dialog_view.h',
         'browser/ui/views/download/download_item_view.cc',
@@ -1866,6 +1887,8 @@
         'browser/ui/views/javascript_app_modal_dialog_views.h',
         'browser/ui/views/load_complete_listener.cc',
         'browser/ui/views/load_complete_listener.h',
+        'browser/ui/views/location_bar/bubble_icon_view.cc',
+        'browser/ui/views/location_bar/bubble_icon_view.h',
         'browser/ui/views/location_bar/generated_credit_card_view.cc',
         'browser/ui/views/location_bar/generated_credit_card_view.h',
         'browser/ui/views/location_bar/content_setting_image_view.cc',
@@ -1898,6 +1921,8 @@
         'browser/ui/views/location_bar/selected_keyword_view.h',
         'browser/ui/views/location_bar/star_view.cc',
         'browser/ui/views/location_bar/star_view.h',
+        'browser/ui/views/location_bar/translate_icon_view.cc',
+        'browser/ui/views/location_bar/translate_icon_view.h',
         'browser/ui/views/location_bar/zoom_bubble_view.cc',
         'browser/ui/views/location_bar/zoom_bubble_view.h',
         'browser/ui/views/location_bar/zoom_view.cc',
@@ -2302,9 +2327,9 @@
         'browser/ui/webui/omnibox/omnibox_ui_handler.cc',
         'browser/ui/webui/omnibox/omnibox_ui_handler.h',
         'browser/ui/webui/options/advanced_options_utils.h',
+        'browser/ui/webui/options/advanced_options_utils_linux.cc',
         'browser/ui/webui/options/advanced_options_utils_mac.mm',
         'browser/ui/webui/options/advanced_options_utils_win.cc',
-        'browser/ui/webui/options/advanced_options_utils_x11.cc',
         'browser/ui/webui/options/autofill_options_handler.cc',
         'browser/ui/webui/options/autofill_options_handler.h',
         'browser/ui/webui/options/browser_options_handler.cc',
@@ -2672,7 +2697,7 @@
           ],
           'sources': [
             'browser/ui/ash/multi_user_window_manager.cc',
-          ],      
+          ],
           'sources!': [
             'browser/first_run/upgrade_util.cc',
             'browser/first_run/upgrade_util.h',
@@ -3017,7 +3042,6 @@
             'browser/ui/find_bar/find_bar_controller.cc',
             'browser/ui/fullscreen/fullscreen_controller.cc',
             'browser/ui/fullscreen/fullscreen_exit_bubble_type.cc',
-            'browser/ui/immersive_fullscreen_configuration.cc',
             'browser/ui/options/options_util.cc',
             'browser/ui/sad_tab.cc',
             'browser/ui/search_engines/search_engine_tab_helper_delegate.cc',
@@ -3245,6 +3269,8 @@
           'sources/': [
             ['exclude', '^browser/ui/views/app_list/'],
             ['exclude', '^browser/ui/app_list/'],
+            ['include', '^browser/ui/app_list/app_list_util.h'],
+            ['include', '^browser/ui/app_list/app_list_util.cc'],
             ['include', '^browser/ui/app_list/app_list_service.h'],
             ['include', '^browser/ui/app_list/app_list_service_disabled.cc'],
           ],
diff --git a/chrome/chrome_browser_ui_views.gyp b/chrome/chrome_browser_ui_views.gyp
index 8efd591..cdbce19 100644
--- a/chrome/chrome_browser_ui_views.gyp
+++ b/chrome/chrome_browser_ui_views.gyp
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'chromium_code': 1,
+  },
   'targets': [
     {
       'target_name': 'browser_ui_views',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 2367b4f..4a9ecb1 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -144,6 +144,7 @@
         'common/extensions/api/managed_mode_private/managed_mode_handler.h',
         'common/extensions/api/media_galleries_private/media_galleries_handler.h',
         'common/extensions/api/media_galleries_private/media_galleries_handler.cc',
+        'common/extensions/api/messaging/message.h',
         'common/extensions/api/omnibox/omnibox_handler.cc',
         'common/extensions/api/omnibox/omnibox_handler.h',
         'common/extensions/api/plugins/plugins_handler.cc',
@@ -233,6 +234,8 @@
         'common/extensions/manifest_handlers/requirements_handler.h',
         'common/extensions/manifest_handlers/sandboxed_page_info.cc',
         'common/extensions/manifest_handlers/sandboxed_page_info.h',
+        'common/extensions/manifest_handlers/settings_overrides_handler.cc',
+        'common/extensions/manifest_handlers/settings_overrides_handler.h',
         'common/extensions/manifest_handlers/shared_module_info.cc',
         'common/extensions/manifest_handlers/shared_module_info.h',
         'common/extensions/manifest_handlers/theme_handler.cc',
@@ -249,8 +252,6 @@
         'common/extensions/permissions/bluetooth_permission_data.h',
         'common/extensions/permissions/chrome_api_permissions.cc',
         'common/extensions/permissions/chrome_api_permissions.h',
-        'common/extensions/permissions/chrome_scheme_hosts.cc',
-        'common/extensions/permissions/chrome_scheme_hosts.h',
         'common/extensions/permissions/chrome_permission_message_provider.cc',
         'common/extensions/permissions/chrome_permission_message_provider.h',
         'common/extensions/permissions/media_galleries_permission.cc',
@@ -259,8 +260,6 @@
         'common/extensions/permissions/media_galleries_permission_data.h',
         'common/extensions/permissions/permission_message_util.cc',
         'common/extensions/permissions/permission_message_util.h',
-        'common/extensions/permissions/permission_set.cc',
-        'common/extensions/permissions/permission_set.h',
         'common/extensions/permissions/permissions_data.cc',
         'common/extensions/permissions/permissions_data.h',
         'common/extensions/permissions/set_disjunction_permission.h',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index dd16c6a..04a471a 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -158,10 +158,10 @@
         'renderer/extensions/user_script_slave.h',
         'renderer/extensions/v8_schema_registry.cc',
         'renderer/extensions/v8_schema_registry.h',
+        'renderer/extensions/webrtc_native_handler.cc',
+        'renderer/extensions/webrtc_native_handler.h',
         'renderer/extensions/webstore_bindings.cc',
         'renderer/extensions/webstore_bindings.h',
-        'renderer/frame_sniffer.cc',
-        'renderer/frame_sniffer.h',
         'renderer/isolated_world_ids.h',
         'renderer/loadtimes_extension_bindings.cc',
         'renderer/loadtimes_extension_bindings.h',
@@ -169,6 +169,8 @@
         'renderer/media/cast_send_transport.h',
         'renderer/media/cast_session.cc',
         'renderer/media/cast_session.h',
+        'renderer/media/cast_session_delegate.cc',
+        'renderer/media/cast_session_delegate.h',
         'renderer/media/cast_udp_transport.cc',
         'renderer/media/cast_udp_transport.h',
         'renderer/media/chrome_key_systems.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 8a4b2dc..e9ad7c1 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -74,6 +74,24 @@
   ],
   'targets': [
     {
+      'target_name': 'test_support_chrome',
+      'type': 'static_library',
+      'dependencies': [
+        'test_support_common',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'export_dependent_settings': [
+        'test_support_common',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'test/base/chrome_test_launcher.cc',
+        'test/base/chrome_test_launcher.h',
+      ],
+    },
+    {
       'target_name': 'test_support_ui_runner',
       'type': 'static_library',
       'dependencies': [
@@ -151,6 +169,7 @@
         'common/extensions/api/api.gyp:api',
         'debugger',
         'renderer',
+        'test_support_chrome',
         'test_support_common',
         # NOTE: don't add test_support_ui, no more UITests. See
         # http://crbug.com/137365
@@ -178,7 +197,6 @@
       ],
       'defines': [
         'HAS_OUT_OF_PROC_TEST_RUNNER',
-        'INTERACTIVE_TESTS',
       ],
       'variables': {
         'win_use_external_manifest': 1,
@@ -266,7 +284,6 @@
         'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc',
         'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h',
         'browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc',
-        'test/base/chrome_test_launcher.cc',
         'test/base/interactive_test_utils.cc',
         'test/base/interactive_test_utils.h',
         'test/base/interactive_test_utils_aura.cc',
@@ -275,6 +292,7 @@
         'test/base/interactive_test_utils_mac.mm',
         'test/base/interactive_test_utils_views.cc',
         'test/base/interactive_test_utils_win.cc',
+        'test/base/interactive_ui_tests_main.cc',
         'test/base/view_event_test_base.cc',
         'test/base/view_event_test_base.h',
         'test/ppapi/ppapi_interactive_browsertest.cc',
@@ -313,6 +331,43 @@
             'test/base/view_event_test_base.h',
           ],
         }],
+        ['OS=="linux" and use_aura==1 and chromeos==0', {
+          'sources!': [
+            # TODO(port): Disable all the interactive panel tests. All of this
+            # is currently very flaky.
+            'browser/ui/panels/base_panel_browser_test.cc',
+            'browser/ui/panels/base_panel_browser_test.h',
+            'browser/ui/panels/detached_panel_browsertest.cc',
+            'browser/ui/panels/docked_panel_browsertest.cc',
+            'browser/ui/panels/panel_browsertest.cc',
+            'browser/ui/panels/panel_drag_browsertest.cc',
+            'browser/ui/panels/panel_resize_browsertest.cc',
+            'browser/ui/panels/stacked_panel_browsertest.cc',
+            'browser/ui/views/panels/panel_view_browsertest.cc',
+            # TODO(port): These tests fail because they don't have a Screen,
+            # but expect one.
+            'browser/notifications/desktop_notifications_unittest.cc',
+            'browser/notifications/desktop_notifications_unittest.h',
+            'browser/notifications/notification_browsertest.cc',
+            # TODO(port): I have no idea about the crashes in here; there's
+            # nothing obviously wrong. It doesn't run on gtk today, either.
+            'browser/ui/views/button_dropdown_test.cc',
+            'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc',
+            # TODO(port): Everything here times out. Attempts have been made to
+            # fix the individual failures, but each time I disable a test from
+            # these suites, it seems like one or another starts timing out too.
+            'browser/apps/web_view_interactive_browsertest.cc',
+            'browser/autofill/autofill_interactive_uitest.cc',
+            'browser/extensions/api/extension_action/browser_action_interactive_test.cc',
+            'browser/extensions/api/omnibox/omnibox_api_interactive_test.cc',
+            'browser/ui/omnibox/omnibox_view_browsertest.cc',
+            'browser/extensions/api/tabs/tabs_interactive_test.cc',
+            'browser/ui/search/instant_extended_interactive_uitest.cc',
+            'browser/ui/startup/startup_browser_creator_interactive_uitest.cc',
+            'browser/ui/views/keyboard_access_browsertest.cc',
+            'browser/ui/views/omnibox/omnibox_view_views_browsertest.cc',
+          ],
+        }],
         ['use_ash==1', {
           'sources': [
             '../ash/drag_drop/drag_drop_interactive_uitest.cc',
@@ -479,7 +534,6 @@
           'msvs_disabled_warnings': [ 4267, ],
         }, { # else: OS != "win"
           'sources!': [
-            'browser/ui/views/ssl_client_certificate_selector_browsertest.cc',
             'browser/ui/views/native_widget_win_interactive_uitest.cc',
           ],
         }],  # OS != "win"
@@ -886,6 +940,7 @@
         'common/extensions/api/api.gyp:api',
         'renderer',
         'test/perf/perf_test.gyp:*',
+        'test_support_chrome',
         'test_support_common',
         'test_support_unit',
         '../base/base.gyp:base',
@@ -970,6 +1025,7 @@
         'browser/chromeos/accessibility/magnification_manager_browsertest.cc',
         'browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc',
         'browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc',
+        'browser/chromeos/attestation/attestation_policy_browsertest.cc',
         'browser/chromeos/drive/drive_integration_service_browsertest.cc',
         'browser/chromeos/drive/test_util.cc',
         'browser/chromeos/drive/test_util.h',
@@ -1041,10 +1097,12 @@
         'browser/content_settings/content_settings_browsertest.cc',
         'browser/crash_recovery_browsertest.cc',
         'browser/custom_handlers/protocol_handler_registry_browsertest.cc',
+        'browser/devtools/devtools_adb_bridge_browsertest.cc',
         'browser/devtools/devtools_sanity_browsertest.cc',
         'browser/do_not_track_browsertest.cc',
         'browser/download/download_browsertest.cc',
         'browser/download/download_danger_prompt_browsertest.cc',
+        'browser/download/download_started_animation_browsertest.cc',
         'browser/download/save_page_browsertest.cc',
         'browser/drive/fake_drive_service.cc',
         'browser/drive/fake_drive_service.h',
@@ -1120,6 +1178,7 @@
         'browser/extensions/api/runtime/runtime_apitest.cc',
         'browser/extensions/api/serial/serial_apitest.cc',
         'browser/extensions/api/sessions/sessions_apitest.cc',
+        'browser/extensions/api/settings_overrides/settings_overrides_browsertest.cc',
         'browser/extensions/api/socket/socket_apitest.cc',
         'browser/extensions/api/sockets_tcp/sockets_tcp_apitest.cc',
         'browser/extensions/api/sockets_tcp_server/sockets_tcp_server_apitest.cc',
@@ -1145,6 +1204,8 @@
         'browser/extensions/api/usb/usb_manual_apitest.cc',
         'browser/extensions/api/web_navigation/web_navigation_apitest.cc',
         'browser/extensions/api/web_request/web_request_apitest.cc',
+        'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc',
+        'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc',
         'browser/extensions/api/webstore_private/webstore_private_apitest.cc',
         'browser/extensions/app_background_page_apitest.cc',
         'browser/extensions/app_process_apitest.cc',
@@ -1215,6 +1276,7 @@
         'browser/extensions/test_extension_dir.cc',
         'browser/extensions/test_extension_dir.h',
         'browser/extensions/web_contents_browsertest.cc',
+        'browser/extensions/webrtc_cast_apitest.cc',
         'browser/extensions/webstore_inline_installer_browsertest.cc',
         'browser/extensions/webstore_installer_test.cc',
         'browser/extensions/webstore_installer_test.h',
@@ -1347,8 +1409,8 @@
         'browser/ui/app_list/test/app_list_service_test_api_ash.h',
         'browser/ui/app_list/test/app_list_service_test_api_linux.cc',
         'browser/ui/app_list/test/app_list_service_test_api_mac.mm',
+        'browser/ui/ash/accelerator_commands_browsertest.cc',
         'browser/ui/ash/caps_lock_delegate_chromeos_browsertest.cc',
-        'browser/ui/ash/chrome_shell_delegate_browsertest.cc',
         'browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc',
         'browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc',
         'browser/ui/ash/shelf_browsertest.cc',
@@ -1471,6 +1533,7 @@
         'browser/ui/webui/options/search_engine_manager_browsertest.js',
         'browser/ui/webui/options/settings_app_browsertest.js',
         'browser/ui/webui/options/settings_format_browsertest.js',
+        'browser/ui/webui/options/startup_page_list_browsertest.js',
         'browser/ui/webui/policy_ui_browsertest.cc',
         'browser/ui/webui/print_preview/print_preview_ui_browsertest.cc',
         'browser/ui/webui/signin/user_manager_ui_browsertest.cc',
@@ -1490,6 +1553,7 @@
         'renderer/autofill/password_autofill_agent_browsertest.cc',
         'renderer/autofill/password_generation_agent_browsertest.cc',
         'renderer/content_settings_observer_browsertest.cc',
+        'renderer/media/cast_session_browsertest.cc',
         'renderer/printing/print_web_view_helper_browsertest.cc',
         'renderer/safe_browsing/malware_dom_details_browsertest.cc',
         'renderer/safe_browsing/phishing_classifier_browsertest.cc',
@@ -1497,9 +1561,9 @@
         'renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc',
         'renderer/translate/translate_helper_browsertest.cc',
         'renderer/translate/translate_script_browsertest.cc',
+        'test/base/browser_tests_main.cc',
         'test/base/chrome_render_view_test.cc',
         'test/base/chrome_render_view_test.h',
-        'test/base/chrome_test_launcher.cc',
         'test/base/web_ui_browsertest.cc',
         'test/base/web_ui_browsertest.h',
         'test/base/in_process_browser_test_browsertest.cc',
@@ -1676,6 +1740,9 @@
             'test/data/webui/certificate_viewer_dialog_test.js',
             'test/data/webui/certificate_viewer_ui_test-inl.h',
           ],
+          'dependencies': [
+            'chrome',  # for service_process_control_browsertest.cc
+          ],
         }, { # chromeos==1
           'sources!': [
             '../apps/load_and_launch_browsertest.cc',
@@ -1752,6 +1819,7 @@
         }],
         ['enable_webrtc==0', {
           'sources!': [
+            'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc',
             'browser/media/chrome_webrtc_browsertest.cc',
           ],
         }],
@@ -1787,8 +1855,8 @@
             # for win aura builds.
             # TODO: enable these for win_ash browser tests.
             'browser/chromeos/system/tray_accessibility_browsertest.cc',
+            'browser/ui/ash/accelerator_commands_browsertest.cc',
             'browser/ui/ash/caps_lock_delegate_chromeos_browsertest.cc',
-            'browser/ui/ash/chrome_shell_delegate_browsertest.cc',
             'browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc',
             'browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc',
             'browser/ui/ash/shelf_browsertest.cc',
@@ -1952,6 +2020,7 @@
         'chrome_resources.gyp:packed_resources',
         'renderer',
         'test/perf/perf_test.gyp:*',
+        'test_support_chrome',
         'test_support_common',
         '../base/base.gyp:base',
         '../base/base.gyp:base_i18n',
@@ -1988,9 +2057,9 @@
         'browser/extensions/extension_apitest.cc',
         'browser/extensions/extension_browsertest.cc',
         'browser/extensions/extension_test_notification_observer.cc',
+        'test/base/browser_perf_tests_main.cc',
         'test/base/chrome_render_view_test.cc',
         'test/base/chrome_render_view_test.h',
-        'test/base/chrome_test_launcher.cc',
         'test/perf/browser_perf_test.cc',
         'test/perf/browser_perf_test.h',
         'test/perf/rendering/throughput_tests.cc',
@@ -2219,6 +2288,7 @@
         'common',
         'common/extensions/api/api.gyp:api',
         'renderer',
+        'test_support_chrome',
         'test_support_common',
         '../net/net.gyp:net',
         '../printing/printing.gyp:printing',
@@ -2247,7 +2317,7 @@
         'app/chrome_dll.rc',
         'app/chrome_dll_resource.h',
         'app/chrome_version.rc.version',
-        'test/base/chrome_test_launcher.cc',
+        'test/base/browser_tests_main.cc',
         'test/data/resource.rc',
         'browser/sync/test/integration/apps_helper.cc',
         'browser/sync/test/integration/apps_helper.h',
@@ -2399,6 +2469,7 @@
         'chrome',
         'common/extensions/api/api.gyp:api',
         'test/perf/perf_test.gyp:*',
+        'test_support_chrome',
         'test_support_common',
         '../skia/skia.gyp:skia',
         '../sync/sync.gyp:sync',
@@ -2450,7 +2521,7 @@
         'browser/sync/test/integration/sync_test.h',
         'browser/sync/test/integration/typed_urls_helper.cc',
         'browser/sync/test/integration/typed_urls_helper.h',
-        'test/base/chrome_test_launcher.cc',
+        'test/base/browser_perf_tests_main.cc',
         'test/data/resource.rc',
       ],
       'conditions': [
@@ -2568,6 +2639,10 @@
             'OTHER_LDFLAGS': [
               '/usr/lib/libpython2.6.dylib'
             ],
+            'WARNING_CFLAGS': [
+              # swig creates code with self assignments.
+              '-Wno-self-assign',
+            ],
           },
           'msvs_disabled_warnings': [4211],
           'conditions': [
@@ -2617,17 +2692,6 @@
                 },
               }
             }],
-            ['clang == 1', {
-              'xcode_settings': {
-                'WARNING_CFLAGS': [
-                  # swig creates code with self assignments.
-                  '-Wno-self-assign',
-                ],
-              },
-              'cflags': [
-                '-Wno-self-assign',
-              ],
-            }],
             ['asan==1', {
               'cflags!': [ '-fsanitize=address' ],
               'xcode_settings': { 'OTHER_CFLAGS!': [ '-fsanitize=address' ] },
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 4825c55..6ff5af7 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -92,6 +92,8 @@
         'browser/chromeos/login/mock_user_image_manager.h',
         'browser/chromeos/login/mock_user_manager.cc',
         'browser/chromeos/login/mock_user_manager.h',
+        'browser/chromeos/login/test/oobe_screen_waiter.cc',
+        'browser/chromeos/login/test/oobe_screen_waiter.h',
         'browser/chromeos/policy/device_policy_builder.cc',
         'browser/chromeos/policy/device_policy_builder.h',
         'browser/chromeos/policy/stub_enterprise_install_attributes.cc',
@@ -250,8 +252,6 @@
         'test/base/test_launcher_utils.h',
         'test/base/test_switches.cc',
         'test/base/test_switches.h',
-        'test/base/test_tab_strip_model_observer.cc',
-        'test/base/test_tab_strip_model_observer.h',
         'test/base/testing_browser_process.cc',
         'test/base/testing_browser_process.h',
         'test/base/testing_browser_process_platform_part.h',
@@ -431,6 +431,8 @@
         '..',
       ],
       'sources': [
+        'browser/sync/glue/session_sync_test_helper.cc',
+        'browser/sync/glue/session_sync_test_helper.h',
         'browser/sync/profile_sync_service_mock.cc',
         'browser/sync/profile_sync_service_mock.h',
         'test/base/run_all_unittests.cc',
@@ -479,7 +481,7 @@
         '../third_party/icu/icu.gyp:icuuc',
         '../third_party/libxml/libxml.gyp:libxml',
         '../ui/ui.gyp:ui_resources',
-        '../ui/ui.gyp:ui_test_support',
+        '../ui/ui_unittests.gyp:ui_test_support',
         'chrome_resources.gyp:chrome_resources',
         'chrome_resources.gyp:chrome_strings',
       ],
@@ -504,6 +506,7 @@
         'win_use_external_manifest': 1,
       },
       'sources': [
+        '../apps/app_keep_alive_service_unittest.cc',
         '../apps/app_shim/app_shim_host_mac_unittest.cc',
         '../apps/saved_files_service_unittest.cc',
         '../apps/app_shim/extension_app_shim_handler_mac_unittest.cc',
@@ -512,6 +515,7 @@
         '../components/autofill/content/renderer/test_password_autofill_agent.h',
         '../extensions/browser/file_highlighter_unittest.cc',
         '../extensions/browser/file_reader_unittest.cc',
+        '../extensions/browser/lazy_background_task_queue_unittest.cc',
         '../extensions/common/event_filter_unittest.cc',
         '../extensions/common/extension_resource_unittest.cc',
         '../extensions/common/id_util_unittest.cc',
@@ -717,6 +721,7 @@
         'browser/chromeos/session_length_limiter_unittest.cc',
         'browser/chromeos/proxy_config_service_impl_unittest.cc',
         'browser/chromeos/settings/cros_settings_unittest.cc',
+        'browser/chromeos/settings/device_oauth2_token_service_factory_unittest.cc',
         'browser/chromeos/settings/device_oauth2_token_service_unittest.cc',
         'browser/chromeos/settings/device_settings_provider_unittest.cc',
         'browser/chromeos/settings/device_settings_service_unittest.cc',
@@ -812,7 +817,6 @@
         'browser/extensions/api/identity/account_tracker_unittest.cc',
         'browser/extensions/api/identity/experimental_web_auth_flow_unittest.cc',
         'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc',
-        'browser/extensions/api/identity/identity_event_router_unittest.cc',
         'browser/extensions/api/identity/identity_mint_queue_unittest.cc',
         'browser/extensions/api/idle/idle_api_unittest.cc',
         'browser/extensions/api/log_private/syslog_parser_unittest.cc',
@@ -1042,6 +1046,7 @@
         'browser/network_time/navigation_time_helper_unittest.cc',
         'browser/network_time/network_time_tracker_unittest.cc',
         'browser/notifications/desktop_notification_service_unittest.cc',
+        'browser/notifications/login_state_notification_blocker_chromeos_unittest.cc',
         'browser/notifications/message_center_notifications_unittest_win.cc',
         'browser/notifications/message_center_settings_controller_unittest.cc',
         'browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc',
@@ -1068,6 +1073,7 @@
         'browser/plugins/plugin_metadata_unittest.cc',
         'browser/plugins/plugin_prefs_unittest.cc',
         'browser/policy/async_policy_provider_unittest.cc',
+        'browser/policy/autofill_policy_handler_unittest.cc',
         'browser/policy/browser_policy_connector_unittest.cc',
         'browser/policy/cloud/cloud_policy_client_unittest.cc',
         'browser/policy/cloud/cloud_policy_core_unittest.cc',
@@ -1096,6 +1102,8 @@
         'browser/policy/configuration_policy_pref_store_unittest.h',
         'browser/policy/configuration_policy_provider_test.cc',
         'browser/policy/configuration_policy_provider_test.h',
+        'browser/policy/file_selection_dialogs_policy_handler_unittest.cc',
+        'browser/policy/javascript_policy_handler_unittest.cc',
         'browser/policy/mock_policy_service.cc',
         'browser/policy/mock_policy_service.h',
         'browser/policy/policy_bundle_unittest.cc',
@@ -1109,6 +1117,7 @@
         'browser/policy/preg_parser_win_unittest.cc',
         'browser/policy/registry_dict_win_unittest.cc',
         'browser/policy/url_blacklist_manager_unittest.cc',
+        'browser/policy/url_blacklist_policy_handler_unittest.cc',
         'browser/predictors/autocomplete_action_predictor_table_unittest.cc',
         'browser/predictors/autocomplete_action_predictor_unittest.cc',
         'browser/predictors/resource_prefetch_predictor_unittest.cc',
@@ -1122,7 +1131,6 @@
         'browser/prefs/proxy_config_dictionary_unittest.cc',
         'browser/prefs/proxy_policy_unittest.cc',
         'browser/prefs/proxy_prefs_unittest.cc',
-        'browser/prefs/scoped_user_pref_update_unittest.cc',
         'browser/prefs/session_startup_pref_unittest.cc',
         'browser/prerender/prerender_history_unittest.cc',
         'browser/prerender/prerender_manager_unittest.cc',
@@ -1138,11 +1146,13 @@
         'browser/process_info_snapshot_mac_unittest.cc',
         'browser/process_singleton_linux_unittest.cc',
         'browser/process_singleton_mac_unittest.cc',
+        'browser/profile_resetter/automatic_profile_resetter_delegate_unittest.cc',
         'browser/profile_resetter/automatic_profile_resetter_unittest.cc',
         'browser/profile_resetter/jtl_interpreter_unittest.cc',
         'browser/profile_resetter/profile_resetter_unittest.cc',
         'browser/profiles/file_path_verifier_win_unittest.cc',
         'browser/profiles/gaia_info_update_service_unittest.cc',
+        'browser/profiles/incognito_mode_policy_handler_unittest.cc',
         'browser/profiles/off_the_record_profile_impl_unittest.cc',
         'browser/profiles/profile_downloader_unittest.cc',
         'browser/profiles/profile_info_cache_unittest.cc',
@@ -1207,6 +1217,7 @@
         'browser/search_engines/template_url_prepopulate_data_unittest.cc',
         'browser/search_engines/template_url_scraper_unittest.cc',
         'browser/search_engines/template_url_unittest.cc',
+        'browser/sessions/restore_on_startup_policy_handler_unittest.cc',
         'browser/sessions/session_backend_unittest.cc',
         'browser/sessions/session_service_unittest.cc',
         'browser/sessions/session_types_unittest.cc',
@@ -1215,6 +1226,7 @@
         'browser/signin/account_reconcilor_unittest.cc',
         'browser/signin/fake_auth_status_provider.cc',
         'browser/signin/fake_auth_status_provider.h',
+        'browser/signin/local_auth_unittest.cc',
         'browser/signin/profile_oauth2_token_service_request_unittest.cc',
         'browser/signin/profile_oauth2_token_service_unittest.cc',
         'browser/signin/signin_global_error_unittest.cc',
@@ -1297,8 +1309,6 @@
         'browser/sync/glue/non_ui_data_type_controller_unittest.cc',
         'browser/sync/glue/search_engine_data_type_controller_unittest.cc',
         'browser/sync/glue/session_model_associator_unittest.cc',
-        'browser/sync/glue/session_sync_test_helper.cc',
-        'browser/sync/glue/session_sync_test_helper.h',
         'browser/sync/glue/shared_change_processor_mock.cc',
         'browser/sync/glue/shared_change_processor_mock.h',
         'browser/sync/glue/shared_change_processor_unittest.cc',
@@ -1326,6 +1336,7 @@
         'browser/sync/sessions2/sessions_sync_manager_unittest.cc',
         'browser/sync/sessions2/tab_node_pool2_unittest.cc',
         'browser/sync/sync_global_error_unittest.cc',
+        'browser/sync/sync_policy_handler_unittest.cc',
         'browser/sync/sync_prefs_unittest.cc',
         'browser/sync/sync_startup_tracker_unittest.cc',
         'browser/sync/sync_ui_util_unittest.cc',
@@ -1334,6 +1345,7 @@
         'browser/sync/test_profile_sync_service.cc',
         'browser/sync/test_profile_sync_service.h',
         'browser/sync_file_system/drive_backend/register_app_task_unittest.cc',
+        'browser/sync_file_system/drive_backend/list_changes_task_unittest.cc',
         'browser/sync_file_system/drive_backend/metadata_database_unittest.cc',
         'browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc',
         'browser/sync_file_system/drive_backend_v1/api_util_unittest.cc',
@@ -1627,6 +1639,7 @@
         'browser/ui/gtk/reload_button_gtk_unittest.cc',
         'browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc',
         'browser/ui/gtk/tabs/tab_renderer_gtk_unittest.cc',
+        'browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2_unittest.cc',
         'browser/ui/login/login_prompt_unittest.cc',
         'browser/ui/omnibox/omnibox_controller_unittest.cc',
         'browser/ui/omnibox/omnibox_edit_unittest.cc',
@@ -1774,6 +1787,7 @@
         'common/extensions/manifest_handlers/content_scripts_manifest_unittest.cc',
         'common/extensions/manifest_handlers/exclude_matches_manifest_unittest.cc',
         'common/extensions/manifest_handlers/externally_connectable_unittest.cc',
+        'common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc',
         'common/extensions/manifest_handlers/shared_module_manifest_unittest.cc',
         'common/extensions/manifest_tests/extension_manifest_test.cc',
         'common/extensions/manifest_tests/extension_manifests_background_unittest.cc',
@@ -1950,7 +1964,6 @@
         '../components/autofill/core/browser/webdata/autofill_entry_unittest.cc',
         '../components/autofill/core/browser/webdata/autofill_table_unittest.cc',
         '../components/autofill/core/browser/webdata/web_data_service_unittest.cc',
-        '../components/autofill/core/common/password_form_fill_data_unittest.cc',
 
         # TODO(yael): Move to //components/components_tests.gypi once
         # nacl_defines is moved out of chrome.gyp into a common place.
@@ -2167,6 +2180,26 @@
             ['exclude', '^browser/bookmarks/bookmark_node_data_unittest.cc'],
           ],
         }],
+        ['use_aura==1 and use_ash==0 and use_ozone==0 and OS=="linux"', {
+          'dependencies': [
+            'browser/ui/libgtk2ui/libgtk2ui.gyp:gtk2ui',
+            '../build/linux/system.gyp:gio',
+          ],
+        }, {
+          'sources/': [
+            ['exclude', '^browser/ui/libgtk2ui/'],
+          ],
+        }],
+        ['use_aura==1 and component=="shared_library"', {
+          'sources!': [
+            # TODO(erg): This file does not compile in shared library mode
+            # because it is reaching into the internals of libgtk2ui, which
+            # shouldn't be linked with the rest of chrome. This should either
+            # be fixed by creating a separate unit test target, or by deleting
+            # the test.
+            'browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2_unittest.cc'
+          ],
+        }],
         ['enable_task_manager==0', {
           'sources/': [
             ['exclude', '^browser/task_manager/'],
@@ -2295,6 +2328,7 @@
           'sources!': [
             'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc',
             'browser/net/gaia/gaia_oauth_fetcher_unittest.cc',
+            'browser/notifications/login_state_notification_blocker_chromeos_unittest.cc',
             'browser/extensions/api/log_private/syslog_parser_unittest.cc',
           ],
         }],
@@ -2642,7 +2676,6 @@
             ['gtest_target_type == "shared_library"', {
               'dependencies': [
                 '../testing/android/native_test.gyp:native_test_native_code',
-                'chrome.gyp:chrome_android_auxiliary',
               ],
             }],
           ],
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index afa41dc..7f6120d 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -5,35 +5,12 @@
   "+components/autofill/core/common",
   "+components/nacl/common",
   "+components/policy/core/common",
-  "+device/bluetooth",  # For BluetoothPermission
-  "+device/media_transfer_protocol",  # For MediaTransferProtocolManager
-  "+device/usb",  # For UsbDevicePermission
   "+extensions/common",
   "+grit",  # For generated headers
-  "+libxml",
-  "+ppapi/c",  # For various types.
-  "+ppapi/proxy",
   "+ppapi/shared_impl",
   "+remoting/client/plugin",
-  "+sandbox/win/src",
-  "+skia",
   "+webkit/common/user_agent",
   "+webkit/glue",
-  "+webkit/plugins",
-
-  # Other libraries.
-  "+chrome/third_party/xdg_user_dirs",
-  "+third_party/bzip2",
-  "+third_party/mt19937ar",
-  "+third_party/npapi",
-  "+third_party/re2",
-  "+third_party/sqlite",
-  "+third_party/zlib",
-
-  # This is required by all_messages.h to allow logging of all messages. It
-  # can't be moved to chrome/common/ because it has so many dependencies in
-  # chrome/browser/.
-  "+chrome/browser/importer/profile_import_process_messages.h",
 
   # FIXME - refactor code and remove these dependencies
   "+chrome/installer",
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 2b3a8ef..a054b8d 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -9,6 +9,7 @@
 #include "base/debug/crash_logging.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -32,7 +33,6 @@
 #include "gpu/config/gpu_info.h"
 #include "grit/common_resources.h"
 #include "ppapi/shared_impl/ppapi_permissions.h"
-#include "remoting/client/plugin/pepper_entrypoints.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/layout.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -44,11 +44,14 @@
 #if defined(OS_WIN)
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
-#include "sandbox/win/src/sandbox.h"
 #elif defined(OS_MACOSX)
 #include "components/nacl/common/nacl_sandbox_type_mac.h"
 #endif
 
+#if defined(ENABLE_REMOTING)
+#include "remoting/client/plugin/pepper_entrypoints.h"
+#endif
+
 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \
     !defined(WIDEVINE_CDM_IS_COMPONENT)
 #include "chrome/common/widevine_cdm_constants.h"
@@ -287,6 +290,28 @@
           kWidevineCdmPluginMimeType,
           kWidevineCdmPluginExtension,
           kWidevineCdmPluginMimeTypeDescription);
+
+      // Add the supported codecs as if they came from the component manifest.
+      std::vector<std::string> codecs;
+      codecs.push_back(kCdmSupportedCodecVorbis);
+      codecs.push_back(kCdmSupportedCodecVp8);
+#if defined(USE_PROPRIETARY_CODECS)
+// TODO(ddorwin): Rename these macros to reflect their real meaning: whether the
+// CDM Chrome was built [and shipped] with support these types.
+#if defined(WIDEVINE_CDM_AAC_SUPPORT_AVAILABLE)
+      codecs.push_back(kCdmSupportedCodecAac);
+#endif
+#if defined(WIDEVINE_CDM_AVC1_SUPPORT_AVAILABLE)
+      codecs.push_back(kCdmSupportedCodecAvc1);
+#endif
+#endif  // defined(USE_PROPRIETARY_CODECS)
+      std::string codec_string =
+          JoinString(codecs, kCdmSupportedCodecsValueDelimiter);
+      widevine_cdm_mime_type.additional_param_names.push_back(
+          base::ASCIIToUTF16(kCdmSupportedCodecsParamName));
+      widevine_cdm_mime_type.additional_param_values.push_back(
+          base::ASCIIToUTF16(codec_string));
+
       widevine_cdm.mime_types.push_back(widevine_cdm_mime_type);
       widevine_cdm.permissions = kWidevineCdmPluginPermissions;
       plugins->push_back(widevine_cdm);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 52f85cc..095e3e2 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -111,9 +111,6 @@
 // Whether to always use the new app install bubble when installing an app.
 const char kAppsNewInstallBubble[]          = "apps-new-install-bubble";
 
-// Disable throbber for extension apps.
-const char kAppsNoThrob[]                   = "apps-no-throb";
-
 // Experimental native frame support for packaged apps.
 const char kAppsUseNativeFrame[]            = "apps-use-native-frame";
 
@@ -554,6 +551,11 @@
 const char kEnablePasswordAutofillPublicSuffixDomainMatching[] =
     "enable-password-autofill-public-suffix-domain-matching";
 
+// Enable the setting to prompt the user for their OS account password before
+// revealing plaintext passwords in the password manager.
+const char kEnablePasswordManagerReauthentication[] =
+    "enable-password-manager-reauthentication";
+
 // Enables the pre- and auto-login features. When a user signs in to sync, the
 // browser's cookie jar is pre-filled with GAIA cookies. When the user visits a
 // GAIA login page, an info bar can help the user login.
@@ -608,9 +610,6 @@
 const char kEnableExtensionActivityLogTesting[] =
     "enable-extension-activity-log-testing";
 
-// Enables or disables showing extensions in the action box.
-const char kExtensionsInActionBox[]         = "extensions-in-action-box";
-
 // Enable the fast unload controller, which speeds up tab/window close by
 // running a tab's onunload js handler independently of the GUI -
 // crbug.com/142458 .
@@ -685,7 +684,7 @@
 const char kEnablePanels[]                  = "enable-panels";
 
 // Enables searching for people from the apps list search box.
-const char kEnablePeopleSearch[]            = "enable-people-search";
+const char kDisablePeopleSearch[]           = "disable-people-search";
 
 // Disables the usage of Portable Native Client.
 const char kDisablePnacl[]                  = "disable-pnacl";
@@ -700,6 +699,9 @@
 // are likely to be needed in future page fetches.
 const char kEnablePrecache[]                = "enable-precache";
 
+// Enable Privet local printing.
+const char kEnablePrivetLocalPrinting[]     = "enable-privet-local-printing";
+
 // Enables tracking of tasks in profiler for viewing via about:profiler.
 // To predominantly disable tracking (profiling), use the command line switch:
 // --enable-profiling=0
@@ -747,9 +749,6 @@
 // Enable SPDY/4 alpha 2. This is a temporary testing flag.
 const char kEnableSpdy4a2[]                 = "enable-spdy4a2";
 
-// Enable SPDY CREDENTIAL frame support.  This is a temporary testing flag.
-const char kEnableSpdyCredentialFrames[]    = "enable-spdy-credential-frames";
-
 // Enables auto correction for misspelled words.
 const char kEnableSpellingAutoCorrect[]     = "enable-spelling-auto-correct";
 
@@ -871,15 +870,15 @@
 // testing the cloud policy framework.
 const char kForceLoadCloudPolicy[]          = "force-load-cloud-policy";
 
-// Enables using GAIA information to populate profile name and icon.
-const char kGaiaProfileInfo[]               = "gaia-profile-info";
-
 // Enables setting global commands through the Extensions Commands API.
 const char kGlobalCommands[]                = "global-commands";
 
 // Specifies an alternate URL to use for speaking to Google. Useful for testing.
 const char kGoogleBaseURL[]                 = "google-base-url";
 
+// Enables using GAIA information to populate profile name and icon.
+const char kGoogleProfileInfo[]             = "google-profile-info";
+
 // Specifies an alternate URL to use for retrieving the search domain for
 // Google. Useful for testing.
 const char kGoogleSearchDomainCheckURL[]    = "google-search-domain-check-url";
@@ -1227,10 +1226,6 @@
 // NOTE: This is only implemented for Views.
 const char kPurgeMemoryButton[]             = "purge-memory-button";
 
-// Capture resource consumption information through page cycling and output the
-// data to the specified file.
-const char kRecordStats[]                   = "record-stats";
-
 // Chrome supports a playback and record mode.  Record mode saves *everything*
 // to the cache.  Playback mode reads data exclusively from the cache.  This
 // allows us to record a session into the cache and then replay it at will.
@@ -1346,6 +1341,9 @@
 // Replaces the buffered data source for <audio> and <video> with a simplified
 // resource loader that downloads the entire resource into memory.
 
+// Second origin that can be used for the spdy proxy.
+const char kSpdyProxyAuthFallback[]         = "spdy-proxy-auth-fallback";
+
 // Origin for which SpdyProxy authentication is supported.
 const char kSpdyProxyAuthOrigin[]           = "spdy-proxy-auth-origin";
 
@@ -1433,10 +1431,6 @@
 // occur.
 const char kSyncEnableDeferredStartup[]     = "sync-enable-deferred-startup";
 
-// Disables use of OAuth2 token in sync components and reverts behavior to
-// ClientLogin token.
-const char kSyncDisableOAuth2Token[]         = "sync-disable-oauth2-token";
-
 // Enables feature to avoid unnecessary GetUpdate requests.
 const char kSyncEnableGetUpdateAvoidance[]   =
     "sync-enable-get-update-avoidance";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f72c0a8..01460ab 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -48,7 +48,6 @@
 extern const char kAppModeAuthCode[];
 extern const char kAppModeOAuth2Token[];
 extern const char kAppsNewInstallBubble[];
-extern const char kAppsNoThrob[];
 extern const char kAppsUseNativeFrame[];
 extern const char kAuthExtensionPath[];
 extern const char kAuthNegotiateDelegateWhitelist[];
@@ -199,8 +198,10 @@
 extern const char kEnableOmniboxAutoCompletionForIme[];
 extern const char kEnablePanels[];
 extern const char kEnablePasswordAutofillPublicSuffixDomainMatching[];
-extern const char kEnablePeopleSearch[];
+extern const char kEnablePasswordManagerReauthentication[];
+extern const char kDisablePeopleSearch[];
 extern const char kEnablePrecache[];
+extern const char kEnablePrivetLocalPrinting[];
 extern const char kEnableProfiling[];
 extern const char kEnableQuic[];
 extern const char kEnableQuicHttps[];
@@ -213,7 +214,6 @@
 extern const char kEnableSpdy2[];
 extern const char kDisableSpdy31[];
 extern const char kEnableSpdy4a2[];
-extern const char kEnableSpdyCredentialFrames[];
 extern const char kEnableSpellingAutoCorrect[];
 extern const char kEnableSpellingServiceFeedback[];
 extern const char kEnableStackedTabStrip[];
@@ -228,7 +228,6 @@
 extern const char kEnableUserAlternateProtocolPorts[];
 extern const char kEnableWatchdog[];
 extern const char kEnableWebSocketOverSpdy[];
-extern const char kExtensionsInActionBox[];
 extern const char kEventPageIdleTime[];
 extern const char kEventPageSuspendingTime[];
 extern const char kExplicitlyAllowedPorts[];
@@ -245,9 +244,9 @@
 extern const char kForceFirstRun[];
 extern const char kForceVariationIds[];
 extern const char kForceLoadCloudPolicy[];
-extern const char kGaiaProfileInfo[];
 extern const char kGlobalCommands[];
 extern const char kGoogleBaseURL[];
+extern const char kGoogleProfileInfo[];
 extern const char kGoogleSearchDomainCheckURL[];
 extern const char kGSSAPILibraryName[];
 extern const char kHelp[];
@@ -332,7 +331,6 @@
 extern const char kProxyPacUrl[];
 extern const char kProxyServer[];
 extern const char kPurgeMemoryButton[];
-extern const char kRecordStats[];
 extern const char kRecordMode[];
 extern const char kRemoteDebuggingFrontend[];
 extern const char kRendererPrintPreview[];
@@ -364,6 +362,7 @@
 extern const char kSpeculativeResourcePrefetching[];
 extern const char kSpeculativeResourcePrefetchingDisabled[];
 extern const char kSpeculativeResourcePrefetchingLearning[];
+extern const char kSpdyProxyAuthFallback[];
 extern const char kSpdyProxyAuthOrigin[];
 extern const char kSpdyProxyAuthValue[];
 extern const char kSpeculativeResourcePrefetchingEnabled[];
@@ -383,7 +382,6 @@
 extern const char kSyncThrowUnrecoverableError[];
 extern const char kSyncTrySsltcpFirstForXmpp[];
 extern const char kSyncEnableDeferredStartup[];
-extern const char kSyncDisableOAuth2Token[];
 extern const char kSyncEnableGetUpdateAvoidance[];
 extern const char kSyncfsEnableDirectoryOperation[];
 extern const char kTabBrowserDragging[];
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 56885ce..f3926c4 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -238,7 +238,7 @@
          StartsWithASCII(flag, "--plugin-path=", true) ||
 
          // This is too big so we end up truncating it anyway.
-         StartsWithASCII(flag, "--force-fieldtest=", true) ||
+         StartsWithASCII(flag, "--force-fieldtrials=", true) ||
 
          // These surround the flags that were added by about:flags, it lets
          // you distinguish which flags were added manually via the command
diff --git a/chrome/common/extensions/DEPS b/chrome/common/extensions/DEPS
new file mode 100644
index 0000000..cce9b4d
--- /dev/null
+++ b/chrome/common/extensions/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+  "+components/policy/core/common",
+  "+device/bluetooth",  # For BluetoothPermission
+  "+device/usb",  # For UsbDevicePermission
+  "+libxml",
+  "+ppapi/c",  # For various types.
+  "+skia",
+]
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index e9317da..27d3798 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -44,10 +44,6 @@
     "channel": "stable",
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
   },
-  "app.currentWindowInternal.setAlwaysOnTop": {
-    "channel": "dev",
-    "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
-  },
   "app.getDetails": {
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
     "matches": []
@@ -678,6 +674,10 @@
     "channel": "stable",
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
   },
+  "webrtcAudioPrivate": {
+    "dependencies": ["permission:webrtcAudioPrivate"],
+    "contexts": ["blessed_extension"]
+  },
   "webrtcLoggingPrivate": {
     "dependencies": ["permission:webrtcLoggingPrivate"],
     "contexts": ["blessed_extension"]
@@ -698,7 +698,7 @@
     "dependencies": ["permission:webrtc"],
     "contexts": ["blessed_extension"]
   },
-  "webrtc.udpTransport": {
+  "webrtc.castUdpTransport": {
     "dependencies": ["permission:webrtc"],
     "contexts": ["blessed_extension"]
   },
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json
index 145db29..1004562 100644
--- a/chrome/common/extensions/api/_manifest_features.json
+++ b/chrome/common/extensions/api/_manifest_features.json
@@ -71,6 +71,10 @@
     "channel": "stable",
     "extension_types": ["extension"]
   },
+  "chrome_settings_overrides": {
+    "channel": "dev",
+    "extension_types": ["extension"]
+  },
   "chrome_url_overrides": {
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"]
@@ -270,7 +274,13 @@
       "F7FA7ABC1ECB89BA8EE6656847EFABBF43BB9BCA",
       "1A26E32DE447A17CBE5E9750CDBA78F58539B39C",  // TODO(rockot): Kill these.
       "E61F841D8210B6A9891E5384CB665FBED31FCD7B",  // http://crbug.com/281715
-      "0F42756099D914A026DADFA182871C015735DD95"   // http://crbug.com/300087
+                                                   // -------------------------
+      "0F42756099D914A026DADFA182871C015735DD95",  // These 6 IDs are for
+      "E7E2461CE072DF036CF9592740196159E2D7C089",  // http://crbug.com/300087
+      "A74A4D44C7CFCD8844830E6140C8D763E12DD8F3",
+      "312745D9BF916161191143F6490085EEA0434997",
+      "53041A2FA309EECED01FFC751E7399186E860B2C",
+      "2D22CDB6583FD0A13758AEBE8B15E45208B4E9A7"
     ]
   },
   "offline_enabled": {
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 2035508..d14021e 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -239,7 +239,11 @@
     {
       "channel": "stable",
       "extension_types": ["extension", "platform_app"],
-      "whitelist": ["80B9DC58E5210749F052F5B4DB239C50CF72AEB6"]
+      "whitelist": [
+        "80B9DC58E5210749F052F5B4DB239C50CF72AEB6",
+        // Hangout Services component extension.
+        "nkeimhogjdpnpccoofpliimaahmaaome"
+      ]
     }
   ],
   "dns": [
@@ -360,10 +364,6 @@
     "channel": "stable",
     "extension_types": ["extension", "platform_app"]
   },
-  "identity.email": {
-    "channel": "dev",
-    "extension_types": ["extension", "platform_app"]
-  },
   "identityPrivate": {
     "channel": "stable",
     "extension_types": [
@@ -529,6 +529,10 @@
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
     "whitelist": [
+      "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/293683
+      "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/293683
+      "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578",  // http://crbug.com/234235
+      "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/234235
       "pkedcjkdefgpdelpbcmbmeomcjbeemfm",  // Trusted Tester
       "fmfcbgogabcbclcofgocippekhfcmgfj",  // Staging
       "hfaagokkkhdbgiakmmlclaapfelnkoah",  // Canary
@@ -686,11 +690,11 @@
     "min_manifest_version": 2
   },
   "system.cpu": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"]
   },
   "system.memory": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"]
   },
   "system.storage": {
@@ -784,13 +788,28 @@
     "extension_types": ["extension", "legacy_packaged_app"]
   },
   "webrtc": {
-    "channel": "trunk",
+    "channel": "dev",
     "extension_types": ["extension"]
   },
+  "webrtcAudioPrivate": {
+    "channel": "stable",
+    "extension_types": ["extension"],
+    "whitelist": [
+      "80B9DC58E5210749F052F5B4DB239C50CF72AEB6",
+      // Hangout Services component extension.
+      "nkeimhogjdpnpccoofpliimaahmaaome",
+      // Extension used for API test.
+      "knldjmfmopnpolahpmmgbagdohdnhkik"
+    ]
+  },
   "webrtcLoggingPrivate": {
     "channel": "stable",
     "extension_types": ["extension"],
-    "whitelist": ["80B9DC58E5210749F052F5B4DB239C50CF72AEB6"]
+    "whitelist": [
+      "80B9DC58E5210749F052F5B4DB239C50CF72AEB6",
+      // Hangout Services component extension.
+      "nkeimhogjdpnpccoofpliimaahmaaome"
+    ]
   },
   "webstorePrivate": {
     "channel": "stable",
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index 3c90b0d..2fbab8f 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -18,11 +18,25 @@
       ],
       'variables': {
         'chromium_code': 1,
+        # Disable schema compiler to generate model extension API code.
+        # Only register the extension functions in extension system.
+        'non_compiled_schema_files': [
+          'adview.json',
+          'browsing_data.json',
+          'chromeos_info_private.json',
+          'extension.json',
+          'idltest.idl',
+          'infobars.json',
+          'media_player_private.json',
+          'music_manager_private.idl',
+          'preferences_private.json',
+          'principals_private.idl',
+          'top_sites.json',
+        ],
         'conditions': [
           ['OS!="android"', {
             'schema_files': [
               'activity_log_private.json',
-              'adview.json',
               'alarms.idl',
               'app_current_window_internal.idl',
               'app_runtime.idl',
@@ -33,9 +47,7 @@
               'bookmark_manager_private.json',
               'bookmarks.json',
               'braille_display_private.idl',
-              'browsing_data.json',
               'cast_channel.idl',
-              'chromeos_info_private.json',
               'cloud_print_private.json',
               'command_line_private.json',
               'content_settings.json',
@@ -55,7 +67,6 @@
               'experimental_discovery.idl',
               'experimental_history.json',
               'experimental_identity.idl',
-              'extension.json',
               'feedback_private.idl',
               'file_browser_private.json',
               'file_system.idl',
@@ -66,9 +77,7 @@
               'identity.idl',
               'identity_private.idl',
               'idle.json',
-              'idltest.idl',
               'image_writer_private.idl',
-              'infobars.json',
               'input_ime.json',
               'location.idl',
               'management.json',
@@ -76,17 +85,13 @@
               'mdns.idl',
               'media_galleries.idl',
               'media_galleries_private.idl',
-              'media_player_private.json',
               'metrics_private.json',
-              'music_manager_private.idl',
               'networking_private.json',
               'notifications.idl',
               'omnibox.json',
               'page_capture.json',
               'permissions.json',
               'power.idl',
-              'preferences_private.json',
-              'principals_private.idl',
               'push_messaging.idl',
               'runtime.json',
               'serial.idl',
@@ -108,11 +113,14 @@
               'tabs.json',
               'terminal_private.json',
               'test.json',
-              'top_sites.json',
               'usb.idl',
               'virtual_keyboard_private.json',
               'web_navigation.json',
               'web_request.json',
+              # Despite the name, this API does not rely on any
+              # WebRTC-specific bits and as such does not belong in
+              # the enable_webrtc=0 section below.
+              'webrtc_audio_private.idl',
               'webstore_private.json',
               'webview.json',
               'windows.json',
@@ -154,8 +162,8 @@
           ['enable_webrtc==1', {
             'schema_files': [
               'webrtc_cast_send_transport.idl',
+              'webrtc_cast_udp_transport.idl',
               'webrtc_logging_private.idl',
-              'webrtc_udp_transport.idl',
             ],
           }],
         ],
diff --git a/chrome/common/extensions/api/app_current_window_internal.idl b/chrome/common/extensions/api/app_current_window_internal.idl
index 6999636..0c42aa8 100644
--- a/chrome/common/extensions/api/app_current_window_internal.idl
+++ b/chrome/common/extensions/api/app_current_window_internal.idl
@@ -38,6 +38,10 @@
     static void show();
     static void hide();
     static void setBounds(Bounds bounds);
+    static void setMinWidth(optional long minWidth);
+    static void setMinHeight(optional long minHeight);
+    static void setMaxWidth(optional long maxWidth);
+    static void setMaxHeight(optional long maxHeight);
     static void setIcon(DOMString icon_url);
     static void setInputRegion(Region region);
     static void setAlwaysOnTop(boolean always_on_top);
diff --git a/chrome/common/extensions/api/app_window.idl b/chrome/common/extensions/api/app_window.idl
index 65f34f8..6c0b5f0 100644
--- a/chrome/common/extensions/api/app_window.idl
+++ b/chrome/common/extensions/api/app_window.idl
@@ -54,16 +54,16 @@
     // Y coordinate of the window. (Deprecated; use 'bounds'.)
     [nodoc] long? top;
 
-    // Minimum width for the lifetime of the window.
+    // Minimum width of the window.
     long? minWidth;
 
-    // Minimum height for the lifetime of the window.
+    // Minimum height of the window.
     long? minHeight;
 
-    // Maximum width for the lifetime of the window.
+    // Maximum width of the window.
     long? maxWidth;
 
-    // Maximum height for the lifetime of the window.
+    // Maximum height of the window.
     long? maxHeight;
 
     // Type of window to create.
@@ -108,19 +108,18 @@
     // multiple windows of this kind, the currently focused window will be in
     // the foreground. Defaults to false. Call <code>setAlwaysOnTop()</code> on
     // the window to change this property after creation.
-    // Currently available in the Dev channel only.
     boolean? alwaysOnTop;
   };
 
   // Called in the creating window (parent) before the load event is called in
   // the created window (child). The parent can set fields or functions on the
   // child usable from onload. E.g. background.js:<br>
-  // <code>function(created_window) { created_window.contentWindow.foo =
+  // <code>function(createdWindow) { createdWindow.contentWindow.foo =
   // function () { }; };</code>
   // <br>window.js:<br>
   // <code>window.onload = function () { foo(); }</code>
   callback CreateWindowCallback =
-      void ([instanceOf=AppWindow] object created_window);
+      void ([instanceOf=AppWindow] object createdWindow);
 
   [noinline_doc] dictionary AppWindow {
     // Focus the window.
@@ -174,18 +173,48 @@
     // Set the window's bounds.
     static void setBounds(Bounds bounds);
 
+    // Get the current minimum width of the window. Returns |undefined| if there
+    // is no minimum.
+    [nocompile] static long getMinWidth();
+
+    // Get the current minimum height of the window. Returns |undefined| if
+    // there is no minimum.
+    [nocompile] static long getMinHeight();
+
+    // Get the current maximum width of the window. Returns |undefined| if there
+    // is no maximum.
+    [nocompile] static long getMaxWidth();
+
+    // Get the current maximum height of the window. Returns |undefined| if
+    // there is no maximum.
+    [nocompile] static long getMaxHeight();
+
+    // Set the current minimum width of the window. Set to |null| to remove the
+    // constraint.
+    static void setMinWidth(optional long minWidth);
+
+    // Set the current minimum height of the window. Set to |null| to remove the
+    // constraint.
+    static void setMinHeight(optional long minHeight);
+
+    // Set the current maximum width of the window. Set to |null| to remove the
+    // constraint.
+    static void setMaxWidth(optional long maxWidth);
+
+    // Set the current maximum height of the window. Set to |null| to remove the
+    // constraint.
+    static void setMaxHeight(optional long maxHeight);
+
     // Set the app icon for the window (experimental).
     // Currently this is only being implemented on Ash.
     // TODO(stevenjb): Investigate implementing this on Windows and OSX.
-    [nodoc] static void setIcon(DOMString icon_url);
+    [nodoc] static void setIcon(DOMString iconUrl);
 
     // Is the window always on top?
-    // Currently available in the Dev channel only.
     static boolean isAlwaysOnTop();
 
     // Set whether the window should stay above most other windows.
-    // Currently available in the Dev channel only.
-    static void setAlwaysOnTop(boolean always_on_top);
+    static void setAlwaysOnTop(boolean alwaysOnTop);
 
     // The JavaScript 'window' object for the created child.
     [instanceOf=Window] object contentWindow;
diff --git a/chrome/common/extensions/api/browser_action.json b/chrome/common/extensions/api/browser_action.json
index 698cf17..e08851b 100644
--- a/chrome/common/extensions/api/browser_action.json
+++ b/chrome/common/extensions/api/browser_action.json
@@ -324,6 +324,8 @@
               {
                 "name": "popupView",
                 "type": "object",
+                "optional": true,
+                "description": "JavaScript 'window' object for the popup window if it was succesfully opened.",
                 "additionalProperties": { "type": "any" }
               }
             ]
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc
index b6fa5ec..423e33f 100644
--- a/chrome/common/extensions/api/extension_action/action_info.cc
+++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -8,6 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_handler_helpers.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest_constants.h"
diff --git a/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc b/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
index c73cfed..993e1d0 100644
--- a/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
+++ b/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest_constants.h"
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index f28ab3c..2490d5d 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -18,10 +18,10 @@
 #include "base/values.h"
 #include "chrome/common/extensions/api/generated_schemas.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "grit/common_resources.h"
 #include "grit/extensions_api_resources.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
index 1ce1ac7..797a11f 100644
--- a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
+++ b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
 #include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "chrome/common/extensions/value_builder.h"
 #include "extensions/common/error_utils.h"
diff --git a/chrome/common/extensions/api/identity.idl b/chrome/common/extensions/api/identity.idl
index cefd50c..0cd6514 100644
--- a/chrome/common/extensions/api/identity.idl
+++ b/chrome/common/extensions/api/identity.idl
@@ -40,8 +40,9 @@
   };
 
   dictionary AccountInfo {
+    // A unique identifier for the account. This ID will not change
+    // for the lifetime of the account.
     DOMString id;
-    DOMString? email;
   };
 
   callback GetAuthTokenCallback = void (optional DOMString token);
diff --git a/chrome/common/extensions/api/manifest_types.json b/chrome/common/extensions/api/manifest_types.json
index 4a798a7..fc8592e 100644
--- a/chrome/common/extensions/api/manifest_types.json
+++ b/chrome/common/extensions/api/manifest_types.json
@@ -39,6 +39,96 @@
         }
       },
       {
+        "id": "ChromeSettingsOverrides",
+        "type": "object",
+        "description": "Chrome settings which can be overriden by an extension.",
+        "properties": {
+          "homepage": {
+            "description": "New value for the homepage.",
+            "optional": true,
+            "type": "string"
+          },
+          "search_provider": {
+            "type": "object",
+            "description": "A search engine",
+            "optional": true,
+            "properties": {
+              "name": {
+                "type": "string",
+                "description": "Name of the search engine displayed to user."
+              },
+              "keyword": {
+                "type": "string",
+                "description": "Omnibox keyword for the search engine."
+              },
+              "favicon_url": {
+                "type": "string",
+                "description": "An icon URL for the search engine."
+              },
+              "search_url": {
+                "type": "string",
+                "description": "An search URL used by the search engine."
+              },
+              "encoding": {
+                "type": "string",
+                "description": "Encoding of the search term."
+              },
+              "suggest_url": {
+                "type": "string",
+                "optional": true,
+                "description": "If omitted, this engine does not support suggestions."
+              },
+              "instant_url": {
+                "type": "string",
+                "optional": true,
+                "description": "If omitted, this engine does not support instant."
+              },
+              "image_url": {
+                "type": "string",
+                "optional": true,
+                "description": "If omitted, this engine does not support image search."
+              },
+              "search_url_post_params": {
+                "type": "string",
+                "optional": true,
+                "description": "The string of post parameters to search_url"
+              },
+              "suggest_url_post_params": {
+                "type": "string",
+                "optional": true,
+                "description": "The string of post parameters to suggest_url"
+              },
+              "instant_url_post_params": {
+                "type": "string",
+                "optional": true,
+                "description": "The string of post parameters to instant_url"
+              },
+              "image_url_post_params": {
+                "type": "string",
+                "optional": true,
+                "description": "The string of post parameters to image_url"
+              },
+              "alternate_urls": {
+                "type": "array",
+                "items": { "type": "string" },
+                "optional": true,
+                "description": "A list of URL patterns that can be used, in addition to |search_url|."
+              },
+              "is_default": {
+                "type": "boolean",
+                "description": "Specifies if the search provider should be default."
+              }
+            }
+          },
+          "startup_pages": {
+            "description": "A new startup page to be added to the list.",
+            "optional": true,
+            "type": "array",
+            "items": {"type": "string"}
+          }
+        }
+      },
+      {
         "id": "sockets",
         "type": "object",
         "description": "The <code>sockets</code> manifest property declares which sockets operations an app can issue.",
diff --git a/chrome/common/extensions/api/mdns.idl b/chrome/common/extensions/api/mdns.idl
index b792327..434d4b8 100644
--- a/chrome/common/extensions/api/mdns.idl
+++ b/chrome/common/extensions/api/mdns.idl
@@ -26,9 +26,10 @@
   interface Events {
     // Event fired to inform clients of the current complete set of known
     // available services. Clients should only need to store the list from the
-    // most recent event. The service types that the extension is interested in
-    // discovering should be declared as an array in the extensions manifest
-    // file with the 'mdns_service_types' key.
+    // most recent event. The service type that the extension is interested in
+    // discovering should be specified as the event filter with the
+    // 'serviceType' key. Not specifying an event filter will not start any
+    // discovery listeners.
     [supportsFilters=true] static void onServiceList(MDnsService[] services);
   };
 };
diff --git a/chrome/common/extensions/api/messaging/message.h b/chrome/common/extensions/api/messaging/message.h
new file mode 100644
index 0000000..5a03224
--- /dev/null
+++ b/chrome/common/extensions/api/messaging/message.h
@@ -0,0 +1,22 @@
+// Copyright 2013 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_COMMON_EXTENSIONS_API_MESSAGING_MESSAGE_H_
+#define CHROME_COMMON_EXTENSIONS_API_MESSAGING_MESSAGE_H_
+
+namespace extensions {
+
+// A message consists of both the data itself as well as a user  gestur e state.
+struct Message {
+  std::string data;
+  bool user_gesture;
+
+  Message() : data(), user_gesture(false) {}
+  Message(const std::string& data, bool user_gesture)
+      : data(data), user_gesture(user_gesture) {}
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_API_MESSAGING_MESSAGE_H_
diff --git a/chrome/common/extensions/api/notifications.idl b/chrome/common/extensions/api/notifications.idl
index 85ae00a..f916f01 100644
--- a/chrome/common/extensions/api/notifications.idl
+++ b/chrome/common/extensions/api/notifications.idl
@@ -19,6 +19,15 @@
     progress
   };
 
+  enum PermissionLevel {
+    // User has elected to show notifications from the app or extension.
+    // This is the default at install time.
+    granted,
+
+    // User has elected not to show notifications from the app or extension.
+    denied
+  };
+
   dictionary NotificationItem {
     // Title of one item of a list notification.
     DOMString title;
@@ -41,16 +50,20 @@
 
   dictionary NotificationOptions {
     // Which type of notification to display.
+    // <em>Required for $ref:notifications.create</em> method.
     TemplateType? type;
 
     // Sender's avatar, app icon, or a thumbnail for image notifications.
+    // <em>Required for $ref:notifications.create</em> method.
     DOMString? iconUrl;
     [nodoc] NotificationBitmap? iconBitmap;
 
     // Title of the notification (e.g. sender name for email).
+    // <em>Required for $ref:notifications.create</em> method.
     DOMString? title;
 
     // Main notification content.
+    // <em>Required for $ref:notifications.create</em> method.
     DOMString? message;
 
     // Alternate notification content with a lower-weight font.
@@ -93,32 +106,44 @@
 
   callback GetAllCallback = void (object notifications);
 
+  callback PermissionLevelCallback = void (PermissionLevel level);
+
   interface Functions {
-    // Creates and displays a notification having the contents in |options|,
-    // identified by the id |notificationId|. If |notificationId| is empty,
-    // |create| generates an id. If |notificationId| matches an existing
-    // notification, |create| first clears that notification before proceeding
-    // with the create operation. |callback| returns the notification id
-    // (either supplied or generated) that represents the created notification.
+    // Creates and displays a notification.
+    // |notificationId|: Identifier of the notification. If it is empty, this
+    // method generates an id. If it matches an existing notification, this
+    // method first clears that notification before proceeding with the create
+    // operation.
+    // |options|: Contents of the notification.
+    // |callback|: Returns the notification id (either supplied or generated)
+    // that represents the created notification.
     static void create(DOMString notificationId,
                        NotificationOptions options,
                        CreateCallback callback);
 
-    // Updates an existing notification having the id |notificationId| and the
-    // options |options|. |callback| indicates whether a matching notification
-    // existed.
+    // Updates an existing notification.
+    // |notificationId|: The id of the notification to be updated. This is
+    // returned by $ref:notifications.create method.
+    // |options|: Contents of the notification to update to.
+    // |callback|: Called to indicate whether a matching notification existed.
     static void update(DOMString notificationId,
                        NotificationOptions options,
                        UpdateCallback callback);
 
-    // Given a |notificationId| returned by the |create| method, clears the
-    // corresponding notification. |callback| indicates whether a matching
-    // notification existed.
+    // Clears the specified notification.
+    // |notificationId|: The id of the notification to be cleared. This is
+    // returned by $ref:notifications.create method.
+    // |callback|: Called to indicate whether a matching notification existed.
     static void clear(DOMString notificationId, ClearCallback callback);
 
-    // |callback| is executed with the set of notification_ids currently in
-    // the system.
+    // Retrieves all the notifications.
+    // |callback|: Returns the set of notification_ids currently in the system.
     static void getAll(GetAllCallback callback);
+
+    // Retrieves whether the user has enabled notifications from this app
+    // or extension.
+    // |callback|: Returns the current permission level.
+    static void getPermissionLevel(PermissionLevelCallback callback);
   };
 
   interface Events {
@@ -130,6 +155,9 @@
 
     // The user pressed a button in the notification.
     static void onButtonClicked(DOMString notificationId, long buttonIndex);
+
+    // The user changes the permission level.
+    static void onPermissionLevelChanged(PermissionLevel level);
   };
 
 };
diff --git a/chrome/common/extensions/api/sockets_tcp.idl b/chrome/common/extensions/api/sockets_tcp.idl
index d54f3d4..f6cbc51 100644
--- a/chrome/common/extensions/api/sockets_tcp.idl
+++ b/chrome/common/extensions/api/sockets_tcp.idl
@@ -54,7 +54,7 @@
     long resultCode;
 
     // The number of bytes sent (if result == 0)
-    long? bytesWritten;
+    long? bytesSent;
   };
 
   // Callback from the <code>send</code> method.
@@ -170,7 +170,7 @@
     // Enables or disables the keep-alive functionality for a TCP connection.
     // |socketId| : The socket identifier.
     // |enable| : If true, enable keep-alive functionality.
-    // |delay| : Set the delay seconds between the last data packet read
+    // |delay| : Set the delay seconds between the last data packet received
     // and the first keepalive probe. Default is 0.
     // |callback| : Called when the setKeepAlive attempt is complete.
     static void setKeepAlive(long socketId,
@@ -211,7 +211,7 @@
 
     // Sends data on the given TCP socket.
     // |socketId| : The socket identifier.
-    // |data| : The data to write.
+    // |data| : The data to send.
     // |callback| : Called when the <code>send</code> operation completes.
     static void send(long socketId,
                      ArrayBuffer data,
diff --git a/chrome/common/extensions/api/sockets_tcp_server.idl b/chrome/common/extensions/api/sockets_tcp_server.idl
index 60c9b61..5bf0e78 100644
--- a/chrome/common/extensions/api/sockets_tcp_server.idl
+++ b/chrome/common/extensions/api/sockets_tcp_server.idl
@@ -103,7 +103,7 @@
     // The server socket identifier.
     long socketId;
 
-     // The result code returned from the underlying network call.
+    // The result code returned from the underlying network call.
     long resultCode;
   };
 
diff --git a/chrome/common/extensions/api/sockets_udp.idl b/chrome/common/extensions/api/sockets_udp.idl
index bfc432e..3d984df 100644
--- a/chrome/common/extensions/api/sockets_udp.idl
+++ b/chrome/common/extensions/api/sockets_udp.idl
@@ -48,10 +48,10 @@
   dictionary SendInfo {
     // The result code returned from the underlying network call.
     // A negative value indicates an error.
-    long result;
+    long resultCode;
 
     // The number of bytes sent (if result == 0)
-    long? bytesWritten;
+    long? bytesSent;
   };
 
   // Callback from the <code>send</code> method.
@@ -141,7 +141,7 @@
     long socketId;
 
      // The result code returned from the underlying recvfrom() call.
-    long result;
+    long resultCode;
   };
 
   interface Functions {
@@ -178,7 +178,7 @@
 
     // Sends data on the given UDP socket to the given address and port.
     // |socketId| : The socket ID.
-    // |data| : The data to write.
+    // |data| : The data to send.
     // |address| : The address of the remote machine.
     // |port| : The port of the remote machine.
     // |callback| : Called when the <code>send</code> operation completes.
diff --git a/chrome/common/extensions/api/tab_capture.idl b/chrome/common/extensions/api/tab_capture.idl
index cfa2887..7e3e2a2 100644
--- a/chrome/common/extensions/api/tab_capture.idl
+++ b/chrome/common/extensions/api/tab_capture.idl
@@ -29,6 +29,7 @@
   // http://dev.w3.org/2011/webrtc/editor/getusermedia.html
   dictionary MediaStreamConstraint {
     object mandatory;
+    object? _optional;
   };
 
   // Whether we are requesting tab video and/or audio and the
diff --git a/chrome/common/extensions/api/test.json b/chrome/common/extensions/api/test.json
index 134a3ed..285c497 100644
--- a/chrome/common/extensions/api/test.json
+++ b/chrome/common/extensions/api/test.json
@@ -36,6 +36,19 @@
                       }
                     }
                   },
+                  "spawnedTestServer": {
+                    "type": "object",
+                    "optional": true,
+                    "description": "Details on the spawned test server used to mock network responses.  Will be set only if test calls ExtensionApiTest::StartSpawnedTestServer().",
+                    "properties": {
+                      "port": {
+                        "type": "integer",
+                        "description": "The port on which the test server is listening.",
+                        "minimum": 1024,
+                        "maximum": 65535
+                      }
+                    }
+                  },
                   "testDataDirectory": {
                     "type": "string",
                     "description": "file:/// URL for the API test data directory."
@@ -309,6 +322,37 @@
             "items": {"type": "string"}
           }
         ]
+      },
+      {
+        "name": "isProcessingUserGesture",
+        "type": "function",
+        "nocompile": true,
+        "parameters": []
+      },
+      {
+        "name": "runWithUserGesture",
+        "type": "function",
+        "description": "Runs the callback in the context of a user gesture.",
+        "nocompile": true,
+        "parameters": [
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "runWithoutUserGesture",
+        "type": "function",
+        "nocompile": true,
+        "parameters": [
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": []
+          }
+        ]
       }
     ],
     "events": [
diff --git a/chrome/common/extensions/api/virtual_keyboard_private.json b/chrome/common/extensions/api/virtual_keyboard_private.json
index 9094008..d58bb33 100644
--- a/chrome/common/extensions/api/virtual_keyboard_private.json
+++ b/chrome/common/extensions/api/virtual_keyboard_private.json
@@ -18,7 +18,7 @@
           "type": {"type": "string", "description": "One of keyup or keydown.", "enum": ["keyup", "keydown"]},
           "charValue": {"type": "integer", "description": "Unicode value of the key."},
           "keyCode": {"type": "integer", "description": "Virtual key code, which is independent of the keyboard layout or modifier state."},
-          "shiftKey": {"type": "boolean", "optional": true, "description": "Whether or not the SHIFT key is pressed."}
+          "modifiers": {"type": "integer", "optional": true, "description": "Flag for modifiers that are active. None = 0, Shift = 2, Control = 4, Alt = 8."}
         }
       }
     ],
@@ -90,6 +90,19 @@
             "parameters": []
           }
         ]
+      },
+      {
+        "name": "keyboardLoaded",
+        "type": "function",
+        "description": "Inform the system that the keyboard has loaded.",
+        "parameters": [
+          { "type": "function",
+            "name": "callback",
+            "optional": true,
+            "description": "Called when load acknowledgement is complete.",
+            "parameters": []
+          }
+        ]
       }
     ],
     "events": [
diff --git a/chrome/common/extensions/api/wallpaper_private.json b/chrome/common/extensions/api/wallpaper_private.json
index 0780ef7..49f5955 100644
--- a/chrome/common/extensions/api/wallpaper_private.json
+++ b/chrome/common/extensions/api/wallpaper_private.json
@@ -176,7 +176,7 @@
           {
             "name": "source",
             "type": "string",
-            "enum": [ "ONLINE", "CUSTOM" ]
+            "enum": [ "ONLINE", "OEM" ]
           },
           {
             "type": "function",
diff --git a/chrome/common/extensions/api/webrtc_audio_private.idl b/chrome/common/extensions/api/webrtc_audio_private.idl
new file mode 100644
index 0000000..efbe0d0
--- /dev/null
+++ b/chrome/common/extensions/api/webrtc_audio_private.idl
@@ -0,0 +1,74 @@
+// Copyright 2013 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.
+
+// The <code>chrome.webrtcAudioPrivate</code> API allows enumeration
+// of audio output (sink) devices as well as getting and setting the
+// active device for a given tab.
+//
+// Note that device IDs as used in this API are opaque (i.e. they are
+// not the hardware identifier of the device) and while they are
+// unique and persistent across sessions, they are valid only to the
+// extension calling this API (i.e. they cannot be shared between
+// extensions).
+//
+// See http://goo.gl/8rOmgk for further documentation of this API.
+
+[nodoc] namespace webrtcAudioPrivate {
+
+  dictionary SinkInfo {
+    // The opaque identifier of the audio sink device, which is unique
+    // and static for the extension calling the API but invalid for
+    // others.
+    DOMString sinkId;
+    // The user-friendly name (e.g. "Bose Amplifier").
+    DOMString sinkLabel;
+    // Current sample rate of the device, in Hz. Useful e.g. to know
+    // if the remote side should be asked to send a lower sampling
+    // rate.
+    long sampleRate;
+    // True if the device is ready to play out audio. E.g. if it is a
+    // device that takes an audio jack, whether a jack is plugged in.
+    //
+    // TODO(joi): Do unplugged devices even get included in enumeration?
+    boolean isReady;
+    // True if this device is the default audio sink device on the
+    // machine.
+    boolean isDefault;
+  };
+
+  callback GetSinksCallback = void(SinkInfo[] sinkInfo);
+  callback SinkIdCallback = void(DOMString sinkId);
+  callback CompletionCallback = void();
+
+  interface Functions {
+    // Retrieves a list of available audio sink devices.
+    static void getSinks(GetSinksCallback callback);
+
+    // Retrieves the currently active audio sink for the given tab.
+    static void getActiveSink(long tabId,
+                              SinkIdCallback callback);
+
+    // Sets the active audio sink device for the specified tab.
+    static void setActiveSink(long tabId,
+                              DOMString sinkId,
+                              optional CompletionCallback callback);
+
+    // Given a security origin and an input device ID valid for that
+    // security origin, retrieve an audio sink ID valid for the
+    // extension, or the empty string if there is no associated audio
+    // sink.
+    //
+    // The associated sink ID can be used as a sink ID for
+    // setActiveSink. It is valid irrespective of which tab you are
+    // setting the active sink for.
+    static void getAssociatedSink(DOMString securityOrigin,
+                                  DOMString sourceIdInOrigin,
+                                  SinkIdCallback cb);
+  };
+
+  interface Events {
+    // Fired when audio sink devices are added or removed.
+    static void onSinksChanged();
+  };
+};
diff --git a/chrome/common/extensions/api/webrtc_cast_send_transport.idl b/chrome/common/extensions/api/webrtc_cast_send_transport.idl
index 1a851fd..3070bde 100644
--- a/chrome/common/extensions/api/webrtc_cast_send_transport.idl
+++ b/chrome/common/extensions/api/webrtc_cast_send_transport.idl
@@ -63,56 +63,60 @@
   // Result of <code>create</code> call.
   dictionary CreateInfo {
     // The ID of the newly created transport.
-    long id;
+    long transportId;
   };
 
   // Callback from the <code>create</code> method.
   // |id| : The transport id.
-  // A null value indicates an error.
-  callback CreateCallback = void (CreateInfo id);
+  callback CreateCallback = void (CreateInfo info);
 
   // Callback from the <code>createParams</code> method.
   // |params| : The cast transport params.
-  // A null value indicates an error.
   callback CreateParamsCallback = void (CastTransportParams params);
 
+  // Callback from the <code>getCaps</code> method.
+  // |caps| : Capabilities of the cast transport.
+  callback GetCapsCallback = void (CastTransportCaps caps);
+
   interface Functions {
     // Creates a cast send transport.
+    // |track| : the media track encoded by this transport.
     // |innerTransportId| : the ID of the inner transport. The transport to be
     //   created will send data on the inner transport.
     // |callback| : Called when the transport has been created.
-    [nocompile] static void create(long innerTransportId,
+    [nocompile] static void create(
+        [instanceOf=MediaStreamTrack] object track,
+        long innerTransportId,
         CreateCallback callback);
 
+    // Destroys a cast send transport.
+    // |transportId| : The transport ID.
+    [nocompile] static void destroy(long transportId);
+
     // Creates suitable params given the capabilities.
     // |caps| : the capabilities.
-    // |callback| : Called when the params has been created.
-    [nocompile] static void createParams(CastTransportCaps caps,
-        CreateParamsCallback callback);
+    // |callback| : Called when the params have been created.
+    [nocompile] static void getCaps(long transportId,
+        GetCapsCallback callback);
 
-    // Set the source of media.
-    // |transportId| : the transport ID.
-    // |track| : A media stream track.
-    [nocompile] static void setTrack(long transportId,
-        [instanceOf=MediaStreamTrack] object track);
+    // Creates suitable params given the capabilities.
+    // |transportId| : The transport ID.
+    // |remoteCaps| : Capabilities of remote peer.
+    // |callback| : Called when the params has been created.
+    [nocompile] static void createParams(
+        long transportId,
+        CastTransportCaps remoteCaps,
+        CreateParamsCallback callback);
 
     // Starts to use the transport by providing remote params info.
     // |transportId| : The transport ID.
-    // |remoteParams| : The remote params.
+    // |params| : Parameters set for this transport.
     [nocompile] static void start(long transportId,
-        CastTransportParams remoteParams);
+        CastTransportParams params);
 
     // Stops using the transport.
     // |transportId| : The transport ID.
     [nocompile] static void stop(long transportId);
-
-    // Mutes the media track.
-    // |transportId| : The transport ID.
-    [nocompile] static void mute(long transportId);
-
-    // Unmute the media track.
-    // |transportId| : The transport ID.
-    [nocompile] static void unmute(long transportId);
   };
 
   interface Events {
diff --git a/chrome/common/extensions/api/webrtc_cast_udp_transport.idl b/chrome/common/extensions/api/webrtc_cast_udp_transport.idl
new file mode 100644
index 0000000..0370a38
--- /dev/null
+++ b/chrome/common/extensions/api/webrtc_cast_udp_transport.idl
@@ -0,0 +1,49 @@
+// Copyright 2013 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.
+
+// The <code>chrome.webrtc.castUdpTransport</code> API creates a UDP
+// transport for outer transport to send and receive data. This API is not
+// useful when standalone since it does not have send and receive methods.
+// It should be used as an inner transport for other transports such as
+// castSendTransport.
+namespace webrtc.castUdpTransport {
+  // The UDP socket address and port.
+  dictionary UdpParams {
+    DOMString address;
+    long port;
+  };
+
+  // Result of <code>create</code> call.
+  dictionary CreateInfo {
+    // The ID of the newly created UDP transport.
+    long tranportId;
+
+    // The transport params.
+    UdpParams params;
+  };
+
+  // Callback from the <code>create</code> method.
+  // |createInfo| : The transport info.
+  // A null value indicates an error.
+  callback CreateCallback = void (CreateInfo createInfo);
+
+  interface Functions {
+    // Creates a UDP transport.
+    // |callback| : Called when the transport has been created.
+    [nocompile] static void create(CreateCallback callback);
+
+    // Destroys a UDP transport.
+    // |transportId| : The transport ID.
+    [nocompile] static void destroy(long transportId);
+
+    // Starts to use the transport by providing remote UDP info.
+    // |transportId| : The transport ID.
+    // |remoteParams| : The address and port to send packets to.
+    [nocompile] static void start(long transportId, UdpParams remoteParams);
+
+    // Stops using the transport.
+    // |transportId| : The transport ID.
+    [nocompile] static void stop(long transportId);
+  };
+};
diff --git a/chrome/common/extensions/api/webrtc_udp_transport.idl b/chrome/common/extensions/api/webrtc_udp_transport.idl
deleted file mode 100644
index f118671..0000000
--- a/chrome/common/extensions/api/webrtc_udp_transport.idl
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 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.
-
-// The <code>chrome.webrtc.udpTransport</code> API creates a UDP transport
-// for outer transport to send and receive data. This API is not useful when
-// standalone since it does not have send and receive methods. It should be
-// used as an inner transport for other transports such as castSendTransport.
-namespace webrtc.udpTransport {
-  // The UDP socket address and port.
-  dictionary UdpParams {
-    DOMString address;
-    long port;
-  };
-
-  // Result of <code>create</code> call.
-  dictionary CreateInfo {
-    // The ID of the newly created UDP transport.
-    long id;
-
-    // The transport params.
-    UdpParams params;
-  };
-
-  // Callback from the <code>create</code> method.
-  // |createInfo| : The transport info.
-  // A null value indicates an error.
-  callback CreateCallback = void (CreateInfo createInfo);
-
-  interface Functions {
-    // Creates a UDP transport.
-    // |callback| : Called when the transport has been created.
-    [nocompile] static void create(CreateCallback callback);
-
-    // Starts to use the transport by providing remote UDP info.
-    // |transportId| : The transport ID.
-    // |remoteParams| : The address and port to send packets to.
-    [nocompile] static void start(long transportId, UdpParams remoteParams);
-
-    // Stops using the transport.
-    // |transportId| : The transport ID.
-    [nocompile] static void stop(long transportId);
-  };
-};
diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc
index dcc4d5f..4e2c379 100644
--- a/chrome/common/extensions/chrome_extensions_client.cc
+++ b/chrome/common/extensions/chrome_extensions_client.cc
@@ -5,15 +5,23 @@
 #include "chrome/common/extensions/chrome_extensions_client.h"
 
 #include "chrome/common/extensions/chrome_manifest_handlers.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/features/base_feature_provider.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/common/url_constants.h"
+#include "extensions/common/permissions/api_permission_set.h"
 #include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
+namespace {
+const char kThumbsWhiteListedExtension[] = "khopmbdjffemhegeeobelklnbglcdgfh";
+}  // namespace
+
 namespace extensions {
 
 static base::LazyInstance<ChromeExtensionsClient> g_client =
@@ -28,6 +36,20 @@
 
 void ChromeExtensionsClient::Initialize() {
   RegisterChromeManifestHandlers();
+
+  // Set up the scripting whitelist.
+  // Whitelist ChromeVox, an accessibility extension from Google that needs
+  // the ability to script webui pages. This is temporary and is not
+  // meant to be a general solution.
+  // TODO(dmazzoni): remove this once we have an extension API that
+  // allows any extension to request read-only access to webui pages.
+  scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
+
+  // Whitelist "Discover DevTools Companion" extension from Google that
+  // needs the ability to script DevTools pages. Companion will assist
+  // online courses and will be needed while the online educational programs
+  // are in place.
+  scripting_whitelist_.push_back("angkfkebojeancgemegoedelbnjgcgme");
 }
 
 const PermissionsProvider&
@@ -67,6 +89,40 @@
   }
 }
 
+void ChromeExtensionsClient::SetScriptingWhitelist(
+    const ExtensionsClient::ScriptingWhitelist& whitelist) {
+  scripting_whitelist_ = whitelist;
+}
+
+const ExtensionsClient::ScriptingWhitelist&
+ChromeExtensionsClient::GetScriptingWhitelist() const {
+  return scripting_whitelist_;
+}
+
+URLPatternSet ChromeExtensionsClient::GetPermittedChromeSchemeHosts(
+      const Extension* extension,
+      const APIPermissionSet& api_permissions) const {
+  URLPatternSet hosts;
+  // Regular extensions are only allowed access to chrome://favicon.
+  hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
+                              chrome::kChromeUIFaviconURL));
+
+  // Experimental extensions are also allowed chrome://thumb.
+  //
+  // TODO: A public API should be created for retrieving thumbnails.
+  // See http://crbug.com/222856. A temporary hack is implemented here to
+  // make chrome://thumbs available to NTP Russia extension as
+  // non-experimental.
+  if ((api_permissions.find(APIPermission::kExperimental) !=
+       api_permissions.end()) ||
+      (extension->id() == kThumbsWhiteListedExtension &&
+       extension->from_webstore())) {
+    hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
+                                chrome::kChromeUIThumbnailURL));
+  }
+  return hosts;
+}
+
 // static
 ChromeExtensionsClient* ChromeExtensionsClient::GetInstance() {
   return g_client.Pointer();
diff --git a/chrome/common/extensions/chrome_extensions_client.h b/chrome/common/extensions/chrome_extensions_client.h
index f832172..2c3aedd 100644
--- a/chrome/common/extensions/chrome_extensions_client.h
+++ b/chrome/common/extensions/chrome_extensions_client.h
@@ -32,6 +32,12 @@
       const URLPatternSet& hosts,
       URLPatternSet* new_hosts,
       std::set<PermissionMessage>* messages) const OVERRIDE;
+  virtual void SetScriptingWhitelist(const ScriptingWhitelist& whitelist)
+      OVERRIDE;
+  virtual const ScriptingWhitelist& GetScriptingWhitelist() const OVERRIDE;
+  virtual URLPatternSet GetPermittedChromeSchemeHosts(
+      const Extension* extension,
+      const APIPermissionSet& api_permissions) const OVERRIDE;
 
   // Get the LazyInstance for ChromeExtensionsClient.
   static ChromeExtensionsClient* GetInstance();
@@ -40,6 +46,12 @@
   const ChromeAPIPermissions chrome_api_permissions_;
   const ChromePermissionMessageProvider permission_message_provider_;
 
+  // A whitelist of extensions that can script anywhere. Do not add to this
+  // list (except in tests) without consulting the Extensions team first.
+  // Note: Component extensions have this right implicitly and do not need to be
+  // added to this list.
+  ScriptingWhitelist scripting_whitelist_;
+
   friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsClient>;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsClient);
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index e0a636a..f733313 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -39,6 +39,7 @@
 #include "chrome/common/extensions/manifest_handlers/offline_enabled_info.h"
 #include "chrome/common/extensions/manifest_handlers/requirements_handler.h"
 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h"
+#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
@@ -86,6 +87,7 @@
   (new PluginsHandler)->Register();
   (new RequirementsHandler)->Register();
   (new SandboxedPageHandler)->Register();
+  (new SettingsOverridesHandler)->Register();
   (new ScriptBadgeHandler)->Register();
   (new SharedModuleHandler)->Register();
   (new SocketsHandler)->Register();
diff --git a/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json b/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json
index 10c6401..3274c34 100644
--- a/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json
@@ -1,11 +1,8 @@
 {
   "name": "A browser action which changes its icon when clicked",
   "description": "Change browser action color when its icon is clicked",
-  "version": "1.1",
+  "version": "1.2",
   "background": { "scripts": ["background.js"] },
-  "permissions": [
-    "tabs", "http://*/*"
-  ],
   "browser_action": {
       "name": "Click to change the icon's color"
   },
diff --git a/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json b/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json
index ece0a73..adf1dae 100644
--- a/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json
@@ -1,11 +1,11 @@
-{

-  "name" : "Content settings",

-  "version" : "0.2",

-  "description" : "Shows the content settings for the current site.",

-  "permissions": [ "contentSettings", "tabs" ],

-  "browser_action": {

-     "default_icon": "contentSettings.png",

-     "default_popup": "popup.html"

-  },

-  "manifest_version": 2

-}

+{
+  "name" : "Content settings",
+  "version" : "0.2",
+  "description" : "Shows the content settings for the current site.",
+  "permissions": [ "contentSettings", "tabs" ],
+  "browser_action": {
+     "default_icon": "contentSettings.png",
+     "default_popup": "popup.html"
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json b/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json
index 78173fe..c59cec1 100644
--- a/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json
@@ -1,10 +1,10 @@
-{

-  "name": "Context Menus Sample",

-  "description": "Shows some of the features of the Context Menus API",

-  "version": "0.6",

-  "permissions": ["contextMenus"],

-  "background": {

-    "scripts": ["sample.js"]

-  },

-  "manifest_version": 2

-}

+{
+  "name": "Context Menus Sample",
+  "description": "Shows some of the features of the Context Menus API",
+  "version": "0.6",
+  "permissions": ["contextMenus"],
+  "background": {
+    "scripts": ["sample.js"]
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/contextMenus/basic/sample.js b/chrome/common/extensions/docs/examples/api/contextMenus/basic/sample.js
index a58be3a..be77af0 100644
--- a/chrome/common/extensions/docs/examples/api/contextMenus/basic/sample.js
+++ b/chrome/common/extensions/docs/examples/api/contextMenus/basic/sample.js
@@ -1,69 +1,69 @@
-// Copyright (c) 2010 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.

-

-// A generic onclick callback function.

-function genericOnClick(info, tab) {

-  console.log("item " + info.menuItemId + " was clicked");

-  console.log("info: " + JSON.stringify(info));

-  console.log("tab: " + JSON.stringify(tab));

-}

-

-// Create one test item for each context type.

-var contexts = ["page","selection","link","editable","image","video",

-                "audio"];

-for (var i = 0; i < contexts.length; i++) {

-  var context = contexts[i];

-  var title = "Test '" + context + "' menu item";

-  var id = chrome.contextMenus.create({"title": title, "contexts":[context],

-                                       "onclick": genericOnClick});

-  console.log("'" + context + "' item:" + id);

-}

-

-

-// Create a parent item and two children.

-var parent = chrome.contextMenus.create({"title": "Test parent item"});

-var child1 = chrome.contextMenus.create(

-  {"title": "Child 1", "parentId": parent, "onclick": genericOnClick});

-var child2 = chrome.contextMenus.create(

-  {"title": "Child 2", "parentId": parent, "onclick": genericOnClick});

-console.log("parent:" + parent + " child1:" + child1 + " child2:" + child2);

-

-

-// Create some radio items.

-function radioOnClick(info, tab) {

-  console.log("radio item " + info.menuItemId +

-              " was clicked (previous checked state was "  +

-              info.wasChecked + ")");

-}

-var radio1 = chrome.contextMenus.create({"title": "Radio 1", "type": "radio",

-                                         "onclick":radioOnClick});

-var radio2 = chrome.contextMenus.create({"title": "Radio 2", "type": "radio",

-                                         "onclick":radioOnClick});

-console.log("radio1:" + radio1 + " radio2:" + radio2);

-

-

-// Create some checkbox items.

-function checkboxOnClick(info, tab) {

-  console.log(JSON.stringify(info));

-  console.log("checkbox item " + info.menuItemId +

-              " was clicked, state is now: " + info.checked +

-              "(previous state was " + info.wasChecked + ")");

-

-}

-var checkbox1 = chrome.contextMenus.create(

-  {"title": "Checkbox1", "type": "checkbox", "onclick":checkboxOnClick});

-var checkbox2 = chrome.contextMenus.create(

-  {"title": "Checkbox2", "type": "checkbox", "onclick":checkboxOnClick});

-console.log("checkbox1:" + checkbox1 + " checkbox2:" + checkbox2);

-

-

-// Intentionally create an invalid item, to show off error checking in the

-// create callback.

-console.log("About to try creating an invalid item - an error about " +

-            "item 999 should show up");

-chrome.contextMenus.create({"title": "Oops", "parentId":999}, function() {

-  if (chrome.extension.lastError) {

-    console.log("Got expected error: " + chrome.extension.lastError.message);

-  }

-});

+// Copyright (c) 2010 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.
+
+// A generic onclick callback function.
+function genericOnClick(info, tab) {
+  console.log("item " + info.menuItemId + " was clicked");
+  console.log("info: " + JSON.stringify(info));
+  console.log("tab: " + JSON.stringify(tab));
+}
+
+// Create one test item for each context type.
+var contexts = ["page","selection","link","editable","image","video",
+                "audio"];
+for (var i = 0; i < contexts.length; i++) {
+  var context = contexts[i];
+  var title = "Test '" + context + "' menu item";
+  var id = chrome.contextMenus.create({"title": title, "contexts":[context],
+                                       "onclick": genericOnClick});
+  console.log("'" + context + "' item:" + id);
+}
+
+
+// Create a parent item and two children.
+var parent = chrome.contextMenus.create({"title": "Test parent item"});
+var child1 = chrome.contextMenus.create(
+  {"title": "Child 1", "parentId": parent, "onclick": genericOnClick});
+var child2 = chrome.contextMenus.create(
+  {"title": "Child 2", "parentId": parent, "onclick": genericOnClick});
+console.log("parent:" + parent + " child1:" + child1 + " child2:" + child2);
+
+
+// Create some radio items.
+function radioOnClick(info, tab) {
+  console.log("radio item " + info.menuItemId +
+              " was clicked (previous checked state was "  +
+              info.wasChecked + ")");
+}
+var radio1 = chrome.contextMenus.create({"title": "Radio 1", "type": "radio",
+                                         "onclick":radioOnClick});
+var radio2 = chrome.contextMenus.create({"title": "Radio 2", "type": "radio",
+                                         "onclick":radioOnClick});
+console.log("radio1:" + radio1 + " radio2:" + radio2);
+
+
+// Create some checkbox items.
+function checkboxOnClick(info, tab) {
+  console.log(JSON.stringify(info));
+  console.log("checkbox item " + info.menuItemId +
+              " was clicked, state is now: " + info.checked +
+              "(previous state was " + info.wasChecked + ")");
+
+}
+var checkbox1 = chrome.contextMenus.create(
+  {"title": "Checkbox1", "type": "checkbox", "onclick":checkboxOnClick});
+var checkbox2 = chrome.contextMenus.create(
+  {"title": "Checkbox2", "type": "checkbox", "onclick":checkboxOnClick});
+console.log("checkbox1:" + checkbox1 + " checkbox2:" + checkbox2);
+
+
+// Intentionally create an invalid item, to show off error checking in the
+// create callback.
+console.log("About to try creating an invalid item - an error about " +
+            "item 999 should show up");
+chrome.contextMenus.create({"title": "Oops", "parentId":999}, function() {
+  if (chrome.extension.lastError) {
+    console.log("Got expected error: " + chrome.extension.lastError.message);
+  }
+});
diff --git a/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json b/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json
index 7c9ff52..8279823 100644
--- a/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json
@@ -1,11 +1,11 @@
-{

-  "name": "Context Menus Sample (with Event Page)",

-  "description": "Shows some of the features of the Context Menus API using an event page",

-  "version": "0.7",

-  "permissions": ["contextMenus"],

-  "background": {

-    "persistent": false,

-    "scripts": ["sample.js"]

-  },

-  "manifest_version": 2

-}

+{
+  "name": "Context Menus Sample (with Event Page)",
+  "description": "Shows some of the features of the Context Menus API using an event page",
+  "version": "0.7",
+  "permissions": ["contextMenus"],
+  "background": {
+    "persistent": false,
+    "scripts": ["sample.js"]
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/contextMenus/event_page/sample.js b/chrome/common/extensions/docs/examples/api/contextMenus/event_page/sample.js
index 860b95b..227dd0c 100644
--- a/chrome/common/extensions/docs/examples/api/contextMenus/event_page/sample.js
+++ b/chrome/common/extensions/docs/examples/api/contextMenus/event_page/sample.js
@@ -1,70 +1,70 @@
-// Copyright (c) 2012 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.

-

-// The onClicked callback function.

-function onClickHandler(info, tab) {

-  if (info.menuItemId == "radio1" || info.menuItemId == "radio2") {

-    console.log("radio item " + info.menuItemId +

-                " was clicked (previous checked state was "  +

-                info.wasChecked + ")");

-  } else if (info.menuItemId == "checkbox1" || info.menuItemId == "checkbox2") {

-    console.log(JSON.stringify(info));

-    console.log("checkbox item " + info.menuItemId +

-                " was clicked, state is now: " + info.checked +

-                " (previous state was " + info.wasChecked + ")");

-

-  } else {

-    console.log("item " + info.menuItemId + " was clicked");

-    console.log("info: " + JSON.stringify(info));

-    console.log("tab: " + JSON.stringify(tab));

-  }

-};

-

-chrome.contextMenus.onClicked.addListener(onClickHandler);

-

-// Set up context menu tree at install time.

-chrome.runtime.onInstalled.addListener(function() {

-  // Create one test item for each context type.

-  var contexts = ["page","selection","link","editable","image","video",

-                  "audio"];

-  for (var i = 0; i < contexts.length; i++) {

-    var context = contexts[i];

-    var title = "Test '" + context + "' menu item";

-    var id = chrome.contextMenus.create({"title": title, "contexts":[context],

-                                         "id": "context" + context});

-    console.log("'" + context + "' item:" + id);

-  }

-

-  // Create a parent item and two children.

-  chrome.contextMenus.create({"title": "Test parent item", "id": "parent"});

-  chrome.contextMenus.create(

-      {"title": "Child 1", "parentId": "parent", "id": "child1"});

-  chrome.contextMenus.create(

-      {"title": "Child 2", "parentId": "parent", "id": "child2"});

-  console.log("parent child1 child2");

-

-  // Create some radio items.

-  chrome.contextMenus.create({"title": "Radio 1", "type": "radio",

-                              "id": "radio1"});

-  chrome.contextMenus.create({"title": "Radio 2", "type": "radio",

-                              "id": "radio2"});

-  console.log("radio1 radio2");

-

-  // Create some checkbox items.

-  chrome.contextMenus.create(

-      {"title": "Checkbox1", "type": "checkbox", "id": "checkbox1"});

-  chrome.contextMenus.create(

-      {"title": "Checkbox2", "type": "checkbox", "id": "checkbox2"});

-  console.log("checkbox1 checkbox2");

-

-  // Intentionally create an invalid item, to show off error checking in the

-  // create callback.

-  console.log("About to try creating an invalid item - an error about " +

-      "duplicate item child1 should show up");

-  chrome.contextMenus.create({"title": "Oops", "id": "child1"}, function() {

-    if (chrome.extension.lastError) {

-      console.log("Got expected error: " + chrome.extension.lastError.message);

-    }

-  });

-});

+// Copyright (c) 2012 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.
+
+// The onClicked callback function.
+function onClickHandler(info, tab) {
+  if (info.menuItemId == "radio1" || info.menuItemId == "radio2") {
+    console.log("radio item " + info.menuItemId +
+                " was clicked (previous checked state was "  +
+                info.wasChecked + ")");
+  } else if (info.menuItemId == "checkbox1" || info.menuItemId == "checkbox2") {
+    console.log(JSON.stringify(info));
+    console.log("checkbox item " + info.menuItemId +
+                " was clicked, state is now: " + info.checked +
+                " (previous state was " + info.wasChecked + ")");
+
+  } else {
+    console.log("item " + info.menuItemId + " was clicked");
+    console.log("info: " + JSON.stringify(info));
+    console.log("tab: " + JSON.stringify(tab));
+  }
+};
+
+chrome.contextMenus.onClicked.addListener(onClickHandler);
+
+// Set up context menu tree at install time.
+chrome.runtime.onInstalled.addListener(function() {
+  // Create one test item for each context type.
+  var contexts = ["page","selection","link","editable","image","video",
+                  "audio"];
+  for (var i = 0; i < contexts.length; i++) {
+    var context = contexts[i];
+    var title = "Test '" + context + "' menu item";
+    var id = chrome.contextMenus.create({"title": title, "contexts":[context],
+                                         "id": "context" + context});
+    console.log("'" + context + "' item:" + id);
+  }
+
+  // Create a parent item and two children.
+  chrome.contextMenus.create({"title": "Test parent item", "id": "parent"});
+  chrome.contextMenus.create(
+      {"title": "Child 1", "parentId": "parent", "id": "child1"});
+  chrome.contextMenus.create(
+      {"title": "Child 2", "parentId": "parent", "id": "child2"});
+  console.log("parent child1 child2");
+
+  // Create some radio items.
+  chrome.contextMenus.create({"title": "Radio 1", "type": "radio",
+                              "id": "radio1"});
+  chrome.contextMenus.create({"title": "Radio 2", "type": "radio",
+                              "id": "radio2"});
+  console.log("radio1 radio2");
+
+  // Create some checkbox items.
+  chrome.contextMenus.create(
+      {"title": "Checkbox1", "type": "checkbox", "id": "checkbox1"});
+  chrome.contextMenus.create(
+      {"title": "Checkbox2", "type": "checkbox", "id": "checkbox2"});
+  console.log("checkbox1 checkbox2");
+
+  // Intentionally create an invalid item, to show off error checking in the
+  // create callback.
+  console.log("About to try creating an invalid item - an error about " +
+      "duplicate item child1 should show up");
+  chrome.contextMenus.create({"title": "Oops", "id": "child1"}, function() {
+    if (chrome.extension.lastError) {
+      console.log("Got expected error: " + chrome.extension.lastError.message);
+    }
+  });
+});
diff --git a/chrome/common/extensions/docs/examples/api/cookies/manager.html b/chrome/common/extensions/docs/examples/api/cookies/manager.html
index 527a25c..b1d93b5 100644
--- a/chrome/common/extensions/docs/examples/api/cookies/manager.html
+++ b/chrome/common/extensions/docs/examples/api/cookies/manager.html
@@ -1,43 +1,43 @@
-<html>

-<head>

-<style>

-table {

-  border-collapse:collapse;

-}

-

-td {

-  border: 1px solid black;

-  padding-left: 5px;

-}

-

-td.button {

-  border: none;

-}

-

-td.cookie_count {

-  text-align: right;

-}

-

-</style>

-<script src="manager.js"></script>

-</head>

-<body>

-  <h2>Cookies! ... Nom Nom Nom...</h2>

-  <button id="remove_button">DELETE ALL!</button>

-  <div id="filter_div">

-    Filter: <input id="filter" type="text">

-    <button>x</button>

-  </div>

-  <br />

-  <div id="summary_div">

-    Showing <span id="filter_count"></span> of <span id="total_count"></span> cookie domains.

-    <span id="delete_all_button"></span>

-  </div>

-  <br />

-  <table id="cookies">

-    <tr class="header">

-      <th>Name</th>

-      <th>#Cookies</th>

-    </tr>

-  </body>

-</html>

+<html>
+<head>
+<style>
+table {
+  border-collapse:collapse;
+}
+
+td {
+  border: 1px solid black;
+  padding-left: 5px;
+}
+
+td.button {
+  border: none;
+}
+
+td.cookie_count {
+  text-align: right;
+}
+
+</style>
+<script src="manager.js"></script>
+</head>
+<body>
+  <h2>Cookies! ... Nom Nom Nom...</h2>
+  <button id="remove_button">DELETE ALL!</button>
+  <div id="filter_div">
+    Filter: <input id="filter" type="text">
+    <button>x</button>
+  </div>
+  <br />
+  <div id="summary_div">
+    Showing <span id="filter_count"></span> of <span id="total_count"></span> cookie domains.
+    <span id="delete_all_button"></span>
+  </div>
+  <br />
+  <table id="cookies">
+    <tr class="header">
+      <th>Name</th>
+      <th>#Cookies</th>
+    </tr>
+  </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/cookies/manifest.json b/chrome/common/extensions/docs/examples/api/cookies/manifest.json
index 09dbbdc..eb7da26 100644
--- a/chrome/common/extensions/docs/examples/api/cookies/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/cookies/manifest.json
@@ -1,14 +1,14 @@
-{

-  "name" : "Cookie API Test Extension",

-  "version" : "0.8",

-  "description" : "Testing Cookie API",

-  "permissions": [ "cookies", "tabs", "http://*/*", "https://*/*" ],

-  "icons": { "16": "cookie.png", "48": "cookie.png", "128": "cookie.png" },

-  "browser_action": {

-    "default_icon": "cookie.png"

-  },

-  "background": {

-    "scripts": ["background.js"]

-  },

-  "manifest_version": 2

-}

+{
+  "name" : "Cookie API Test Extension",
+  "version" : "0.8",
+  "description" : "Testing Cookie API",
+  "permissions": [ "cookies", "tabs", "http://*/*", "https://*/*" ],
+  "icons": { "16": "cookie.png", "48": "cookie.png", "128": "cookie.png" },
+  "browser_action": {
+    "default_icon": "cookie.png"
+  },
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json b/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json
index e770f59..275dced 100644
--- a/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json
@@ -1,14 +1,13 @@
-{

-  "name": "FirePHP for Chrome",

-  "version": "1.0",

-  "minimum_chrome_version": "10.0",

-  "description": "Extends the Developer Tools, adding support for parsing FirePHP messages from server",

-  "devtools_page": "devtools.html",

-  "background": { "scripts": ["background.js"] },

-  "permissions": [

-    "tabs",

-    "http://*/*",

-    "https://*/*"

-  ],

-  "manifest_version": 2

-}

+{
+  "name": "FirePHP for Chrome",
+  "version": "1.1",
+  "minimum_chrome_version": "10.0",
+  "description": "Extends the Developer Tools, adding support for parsing FirePHP messages from server",
+  "devtools_page": "devtools.html",
+  "background": { "scripts": ["background.js"] },
+  "permissions": [
+    "http://*/*",
+    "https://*/*"
+  ],
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json b/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json
index 9b0acc1..2511406 100644
--- a/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json
@@ -1,11 +1,11 @@
-{

-  "name" : "Block/allow third-party cookies API example extension",

-  "version" : "0.1",

-  "description" : "Sample extension which demonstrates how to access a preference.",

-  "permissions": [ "privacy" ],

-  "browser_action": {

-     "default_icon": "advicedog.jpg",

-     "default_popup": "popup.html"

-  },

-  "manifest_version": 2

-}

+{
+  "name" : "Block/allow third-party cookies API example extension",
+  "version" : "0.1",
+  "description" : "Sample extension which demonstrates how to access a preference.",
+  "permissions": [ "privacy" ],
+  "browser_action": {
+     "default_icon": "advicedog.jpg",
+     "default_popup": "popup.html"
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
index 57013fd..c72e895 100644
--- a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
@@ -1,11 +1,11 @@
-{

-  "name" : "Block/allow referrer API example extension",

-  "version" : "0.1",

-  "description" : "Sample extension which demonstrates how to access a preference.",

-  "permissions": [ "privacy" ],

-  "browser_action": {

-     "default_icon": "advicedog.jpg",

-     "default_popup": "popup.html"

-  },

-  "manifest_version": 2

-}

+{
+  "name" : "Block/allow referrer API example extension",
+  "version" : "0.1",
+  "description" : "Sample extension which demonstrates how to access a preference.",
+  "permissions": [ "privacy" ],
+  "browser_action": {
+     "default_icon": "advicedog.jpg",
+     "default_popup": "popup.html"
+  },
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json b/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json
index fb9ba8f..0861384 100644
--- a/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json
+++ b/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json
@@ -1,12 +1,12 @@
-{

-  "name": "Simple Background App",

-  "version": "0.2",

-  "app": {

-    "urls": [ "http://SOME_SITE_WITHOUT_PORT_NUMBERS/SOME_PATH/" ],

-    "launch": {

-      "web_url": "http://SOME_SITE/SOME_PATH/index.html"

-    }

-  },

-  "permissions": ["background", "notifications"],

-  "manifest_version": 2

-}

+{
+  "name": "Simple Background App",
+  "version": "0.2",
+  "app": {
+    "urls": [ "http://SOME_SITE_WITHOUT_PORT_NUMBERS/SOME_PATH/" ],
+    "launch": {
+      "web_url": "http://SOME_SITE/SOME_PATH/index.html"
+    }
+  },
+  "permissions": ["background", "notifications"],
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/jquery/jquery-1.8.2.min.js b/chrome/common/extensions/docs/examples/extensions/benchmark/jquery/jquery-1.8.2.min.js
index f65cf1d..bc3fbc8 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/jquery/jquery-1.8.2.min.js
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/jquery/jquery-1.8.2.min.js
@@ -1,2 +1,2 @@
-/*! jQuery v1.8.2 jquery.com | jquery.org/license */

+/*! jQuery v1.8.2 jquery.com | jquery.org/license */
 (function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
\ No newline at end of file
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jsevalcontext.js b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jsevalcontext.js
index 4f2a5ee..0fc00ff 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jsevalcontext.js
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jsevalcontext.js
@@ -1,409 +1,409 @@
-// Copyright 2006 Google Inc.

-//

-// 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.

-/**

- * Author: Steffen Meschkat <mesch@google.com>

- *

- * @fileoverview This class is used to evaluate expressions in a local

- * context. Used by JstProcessor.

- */

-

-

-/**

- * Names of special variables defined by the jstemplate evaluation

- * context. These can be used in js expression in jstemplate

- * attributes.

- */

-var VAR_index = '$index';

-var VAR_count = '$count';

-var VAR_this = '$this';

-var VAR_context = '$context';

-var VAR_top = '$top';

-

-

-/**

- * The name of the global variable which holds the value to be returned if

- * context evaluation results in an error. 

- * Use JsEvalContext.setGlobal(GLOB_default, value) to set this.

- */

-var GLOB_default = '$default';

-

-

-/**

- * Un-inlined literals, to avoid object creation in IE6. TODO(mesch):

- * So far, these are only used here, but we could use them thoughout

- * the code and thus move them to constants.js.

- */

-var CHAR_colon = ':';

-var REGEXP_semicolon = /\s*;\s*/;

-

-

-/**

- * See constructor_()

- * @param {Object|null} opt_data

- * @param {Object} opt_parent

- * @constructor

- */

-function JsEvalContext(opt_data, opt_parent) {

-  this.constructor_.apply(this, arguments);

-}

-

-/**

- * Context for processing a jstemplate. The context contains a context

- * object, whose properties can be referred to in jstemplate

- * expressions, and it holds the locally defined variables.

- *

- * @param {Object|null} opt_data The context object. Null if no context.

- *

- * @param {Object} opt_parent The parent context, from which local

- * variables are inherited. Normally the context object of the parent

- * context is the object whose property the parent object is. Null for the

- * context of the root object.

- */

-JsEvalContext.prototype.constructor_ = function(opt_data, opt_parent) {

-  var me = this;

-

-  /**

-   * The context for variable definitions in which the jstemplate

-   * expressions are evaluated. Other than for the local context,

-   * which replaces the parent context, variable definitions of the

-   * parent are inherited. The special variable $this points to data_.

-   *

-   * If this instance is recycled from the cache, then the property is

-   * already initialized.

-   *

-   * @type {Object}

-   */

-  if (!me.vars_) {

-    me.vars_ = {};

-  }

-  if (opt_parent) {

-    // If there is a parent node, inherit local variables from the

-    // parent.

-    copyProperties(me.vars_, opt_parent.vars_);

-  } else {

-    // If a root node, inherit global symbols. Since every parent

-    // chain has a root with no parent, global variables will be

-    // present in the case above too. This means that globals can be

-    // overridden by locals, as it should be.

-    copyProperties(me.vars_, JsEvalContext.globals_);

-  }

-

-  /**

-   * The current context object is assigned to the special variable

-   * $this so it is possible to use it in expressions.

-   * @type Object

-   */

-  me.vars_[VAR_this] = opt_data;

-

-  /**

-   * The entire context structure is exposed as a variable so it can be

-   * passed to javascript invocations through jseval.

-   */

-  me.vars_[VAR_context] = me;

-

-  /**

-   * The local context of the input data in which the jstemplate

-   * expressions are evaluated. Notice that this is usually an Object,

-   * but it can also be a scalar value (and then still the expression

-   * $this can be used to refer to it). Notice this can even be value,

-   * undefined or null. Hence, we have to protect jsexec() from using

-   * undefined or null, yet we want $this to reflect the true value of

-   * the current context. Thus we assign the original value to $this,

-   * above, but for the expression context we replace null and

-   * undefined by the empty string.

-   *

-   * @type {Object|null}

-   */

-  me.data_ = getDefaultObject(opt_data, STRING_empty);

-

-  if (!opt_parent) {

-    // If this is a top-level context, create a variable reference to the data

-    // to allow for  accessing top-level properties of the original context

-    // data from child contexts.

-    me.vars_[VAR_top] = me.data_;

-  }

-};

-

-

-/**

- * A map of globally defined symbols. Every instance of JsExprContext

- * inherits them in its vars_.

- * @type Object

- */

-JsEvalContext.globals_ = {}

-

-

-/**

- * Sets a global symbol. It will be available like a variable in every

- * JsEvalContext instance. This is intended mainly to register

- * immutable global objects, such as functions, at load time, and not

- * to add global data at runtime. I.e. the same objections as to

- * global variables in general apply also here. (Hence the name

- * "global", and not "global var".)

- * @param {string} name

- * @param {Object|null} value

- */

-JsEvalContext.setGlobal = function(name, value) {

-  JsEvalContext.globals_[name] = value;

-};

-

-

-/**

- * Set the default value to be returned if context evaluation results in an 

- * error. (This can occur if a non-existent value was requested). 

- */

-JsEvalContext.setGlobal(GLOB_default, null);

-

-

-/**

- * A cache to reuse JsEvalContext instances. (IE6 perf)

- *

- * @type Array.<JsEvalContext>

- */

-JsEvalContext.recycledInstances_ = [];

-

-

-/**

- * A factory to create a JsEvalContext instance, possibly reusing

- * one from recycledInstances_. (IE6 perf)

- *

- * @param {Object} opt_data

- * @param {JsEvalContext} opt_parent

- * @return {JsEvalContext}

- */

-JsEvalContext.create = function(opt_data, opt_parent) {

-  if (jsLength(JsEvalContext.recycledInstances_) > 0) {

-    var instance = JsEvalContext.recycledInstances_.pop();

-    JsEvalContext.call(instance, opt_data, opt_parent);

-    return instance;

-  } else {

-    return new JsEvalContext(opt_data, opt_parent);

-  }

-};

-

-

-/**

- * Recycle a used JsEvalContext instance, so we can avoid creating one

- * the next time we need one. (IE6 perf)

- *

- * @param {JsEvalContext} instance

- */

-JsEvalContext.recycle = function(instance) {

-  for (var i in instance.vars_) {

-    // NOTE(mesch): We avoid object creation here. (IE6 perf)

-    delete instance.vars_[i];

-  }

-  instance.data_ = null;

-  JsEvalContext.recycledInstances_.push(instance);

-};

-

-

-/**

- * Executes a function created using jsEvalToFunction() in the context

- * of vars, data, and template.

- *

- * @param {Function} exprFunction A javascript function created from

- * a jstemplate attribute value.

- *

- * @param {Element} template DOM node of the template.

- *

- * @return {Object|null} The value of the expression from which

- * exprFunction was created in the current js expression context and

- * the context of template.

- */

-JsEvalContext.prototype.jsexec = function(exprFunction, template) {

-  try {

-    return exprFunction.call(template, this.vars_, this.data_);

-  } catch (e) {

-    log('jsexec EXCEPTION: ' + e + ' at ' + template +

-        ' with ' + exprFunction);

-    return JsEvalContext.globals_[GLOB_default];

-  }

-};

-

-

-/**

- * Clones the current context for a new context object. The cloned

- * context has the data object as its context object and the current

- * context as its parent context. It also sets the $index variable to

- * the given value. This value usually is the position of the data

- * object in a list for which a template is instantiated multiply.

- *

- * @param {Object} data The new context object.

- *

- * @param {number} index Position of the new context when multiply

- * instantiated. (See implementation of jstSelect().)

- * 

- * @param {number} count The total number of contexts that were multiply

- * instantiated. (See implementation of jstSelect().)

- *

- * @return {JsEvalContext}

- */

-JsEvalContext.prototype.clone = function(data, index, count) {

-  var ret = JsEvalContext.create(data, this);

-  ret.setVariable(VAR_index, index);

-  ret.setVariable(VAR_count, count);

-  return ret;

-};

-

-

-/**

- * Binds a local variable to the given value. If set from jstemplate

- * jsvalue expressions, variable names must start with $, but in the

- * API they only have to be valid javascript identifier.

- *

- * @param {string} name

- *

- * @param {Object?} value

- */

-JsEvalContext.prototype.setVariable = function(name, value) {

-  this.vars_[name] = value;

-};

-

-

-/**

- * Returns the value bound to the local variable of the given name, or

- * undefined if it wasn't set. There is no way to distinguish a

- * variable that wasn't set from a variable that was set to

- * undefined. Used mostly for testing.

- *

- * @param {string} name

- *

- * @return {Object?} value

- */

-JsEvalContext.prototype.getVariable = function(name) {

-  return this.vars_[name];

-};

-

-

-/**

- * Evaluates a string expression within the scope of this context

- * and returns the result.

- *

- * @param {string} expr A javascript expression

- * @param {Element} opt_template An optional node to serve as "this"

- *

- * @return {Object?} value

- */

-JsEvalContext.prototype.evalExpression = function(expr, opt_template) {

-  var exprFunction = jsEvalToFunction(expr);

-  return this.jsexec(exprFunction, opt_template);

-};

-

-

-/**

- * Uninlined string literals for jsEvalToFunction() (IE6 perf).

- */

-var STRING_a = 'a_';

-var STRING_b = 'b_';

-var STRING_with = 'with (a_) with (b_) return ';

-

-

-/**

- * Cache for jsEvalToFunction results.

- * @type Object

- */

-JsEvalContext.evalToFunctionCache_ = {};

-

-

-/**

- * Evaluates the given expression as the body of a function that takes

- * vars and data as arguments. Since the resulting function depends

- * only on expr, we cache the result so we save some Function

- * invocations, and some object creations in IE6.

- *

- * @param {string} expr A javascript expression.

- *

- * @return {Function} A function that returns the value of expr in the

- * context of vars and data.

- */

-function jsEvalToFunction(expr) {

-  if (!JsEvalContext.evalToFunctionCache_[expr]) {

-    try {

-      // NOTE(mesch): The Function constructor is faster than eval().

-      JsEvalContext.evalToFunctionCache_[expr] =

-        new Function(STRING_a, STRING_b, STRING_with + expr);

-    } catch (e) {

-      log('jsEvalToFunction (' + expr + ') EXCEPTION ' + e);

-    }

-  }

-  return JsEvalContext.evalToFunctionCache_[expr];

-}

-

-

-/**

- * Evaluates the given expression to itself. This is meant to pass

- * through string attribute values.

- *

- * @param {string} expr

- *

- * @return {string}

- */

-function jsEvalToSelf(expr) {

-  return expr;

-}

-

-

-/**

- * Parses the value of the jsvalues attribute in jstemplates: splits

- * it up into a map of labels and expressions, and creates functions

- * from the expressions that are suitable for execution by

- * JsEvalContext.jsexec(). All that is returned as a flattened array

- * of pairs of a String and a Function.

- *

- * @param {string} expr

- *

- * @return {Array}

- */

-function jsEvalToValues(expr) {

-  // TODO(mesch): It is insufficient to split the values by simply

-  // finding semi-colons, as the semi-colon may be part of a string

-  // constant or escaped.

-  var ret = [];

-  var values = expr.split(REGEXP_semicolon);

-  for (var i = 0, I = jsLength(values); i < I; ++i) {

-    var colon = values[i].indexOf(CHAR_colon);

-    if (colon < 0) {

-      continue;

-    }

-    var label = stringTrim(values[i].substr(0, colon));

-    var value = jsEvalToFunction(values[i].substr(colon + 1));

-    ret.push(label, value);

-  }

-  return ret;

-}

-

-

-/**

- * Parses the value of the jseval attribute of jstemplates: splits it

- * up into a list of expressions, and creates functions from the

- * expressions that are suitable for execution by

- * JsEvalContext.jsexec(). All that is returned as an Array of

- * Function.

- *

- * @param {string} expr

- *

- * @return {Array.<Function>}

- */

-function jsEvalToExpressions(expr) {

-  var ret = [];

-  var values = expr.split(REGEXP_semicolon);

-  for (var i = 0, I = jsLength(values); i < I; ++i) {

-    if (values[i]) {

-      var value = jsEvalToFunction(values[i]);

-      ret.push(value);

-    }

-  }

-  return ret;

-}

+// Copyright 2006 Google Inc.
+//
+// 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.
+/**
+ * Author: Steffen Meschkat <mesch@google.com>
+ *
+ * @fileoverview This class is used to evaluate expressions in a local
+ * context. Used by JstProcessor.
+ */
+
+
+/**
+ * Names of special variables defined by the jstemplate evaluation
+ * context. These can be used in js expression in jstemplate
+ * attributes.
+ */
+var VAR_index = '$index';
+var VAR_count = '$count';
+var VAR_this = '$this';
+var VAR_context = '$context';
+var VAR_top = '$top';
+
+
+/**
+ * The name of the global variable which holds the value to be returned if
+ * context evaluation results in an error. 
+ * Use JsEvalContext.setGlobal(GLOB_default, value) to set this.
+ */
+var GLOB_default = '$default';
+
+
+/**
+ * Un-inlined literals, to avoid object creation in IE6. TODO(mesch):
+ * So far, these are only used here, but we could use them thoughout
+ * the code and thus move them to constants.js.
+ */
+var CHAR_colon = ':';
+var REGEXP_semicolon = /\s*;\s*/;
+
+
+/**
+ * See constructor_()
+ * @param {Object|null} opt_data
+ * @param {Object} opt_parent
+ * @constructor
+ */
+function JsEvalContext(opt_data, opt_parent) {
+  this.constructor_.apply(this, arguments);
+}
+
+/**
+ * Context for processing a jstemplate. The context contains a context
+ * object, whose properties can be referred to in jstemplate
+ * expressions, and it holds the locally defined variables.
+ *
+ * @param {Object|null} opt_data The context object. Null if no context.
+ *
+ * @param {Object} opt_parent The parent context, from which local
+ * variables are inherited. Normally the context object of the parent
+ * context is the object whose property the parent object is. Null for the
+ * context of the root object.
+ */
+JsEvalContext.prototype.constructor_ = function(opt_data, opt_parent) {
+  var me = this;
+
+  /**
+   * The context for variable definitions in which the jstemplate
+   * expressions are evaluated. Other than for the local context,
+   * which replaces the parent context, variable definitions of the
+   * parent are inherited. The special variable $this points to data_.
+   *
+   * If this instance is recycled from the cache, then the property is
+   * already initialized.
+   *
+   * @type {Object}
+   */
+  if (!me.vars_) {
+    me.vars_ = {};
+  }
+  if (opt_parent) {
+    // If there is a parent node, inherit local variables from the
+    // parent.
+    copyProperties(me.vars_, opt_parent.vars_);
+  } else {
+    // If a root node, inherit global symbols. Since every parent
+    // chain has a root with no parent, global variables will be
+    // present in the case above too. This means that globals can be
+    // overridden by locals, as it should be.
+    copyProperties(me.vars_, JsEvalContext.globals_);
+  }
+
+  /**
+   * The current context object is assigned to the special variable
+   * $this so it is possible to use it in expressions.
+   * @type Object
+   */
+  me.vars_[VAR_this] = opt_data;
+
+  /**
+   * The entire context structure is exposed as a variable so it can be
+   * passed to javascript invocations through jseval.
+   */
+  me.vars_[VAR_context] = me;
+
+  /**
+   * The local context of the input data in which the jstemplate
+   * expressions are evaluated. Notice that this is usually an Object,
+   * but it can also be a scalar value (and then still the expression
+   * $this can be used to refer to it). Notice this can even be value,
+   * undefined or null. Hence, we have to protect jsexec() from using
+   * undefined or null, yet we want $this to reflect the true value of
+   * the current context. Thus we assign the original value to $this,
+   * above, but for the expression context we replace null and
+   * undefined by the empty string.
+   *
+   * @type {Object|null}
+   */
+  me.data_ = getDefaultObject(opt_data, STRING_empty);
+
+  if (!opt_parent) {
+    // If this is a top-level context, create a variable reference to the data
+    // to allow for  accessing top-level properties of the original context
+    // data from child contexts.
+    me.vars_[VAR_top] = me.data_;
+  }
+};
+
+
+/**
+ * A map of globally defined symbols. Every instance of JsExprContext
+ * inherits them in its vars_.
+ * @type Object
+ */
+JsEvalContext.globals_ = {}
+
+
+/**
+ * Sets a global symbol. It will be available like a variable in every
+ * JsEvalContext instance. This is intended mainly to register
+ * immutable global objects, such as functions, at load time, and not
+ * to add global data at runtime. I.e. the same objections as to
+ * global variables in general apply also here. (Hence the name
+ * "global", and not "global var".)
+ * @param {string} name
+ * @param {Object|null} value
+ */
+JsEvalContext.setGlobal = function(name, value) {
+  JsEvalContext.globals_[name] = value;
+};
+
+
+/**
+ * Set the default value to be returned if context evaluation results in an 
+ * error. (This can occur if a non-existent value was requested). 
+ */
+JsEvalContext.setGlobal(GLOB_default, null);
+
+
+/**
+ * A cache to reuse JsEvalContext instances. (IE6 perf)
+ *
+ * @type Array.<JsEvalContext>
+ */
+JsEvalContext.recycledInstances_ = [];
+
+
+/**
+ * A factory to create a JsEvalContext instance, possibly reusing
+ * one from recycledInstances_. (IE6 perf)
+ *
+ * @param {Object} opt_data
+ * @param {JsEvalContext} opt_parent
+ * @return {JsEvalContext}
+ */
+JsEvalContext.create = function(opt_data, opt_parent) {
+  if (jsLength(JsEvalContext.recycledInstances_) > 0) {
+    var instance = JsEvalContext.recycledInstances_.pop();
+    JsEvalContext.call(instance, opt_data, opt_parent);
+    return instance;
+  } else {
+    return new JsEvalContext(opt_data, opt_parent);
+  }
+};
+
+
+/**
+ * Recycle a used JsEvalContext instance, so we can avoid creating one
+ * the next time we need one. (IE6 perf)
+ *
+ * @param {JsEvalContext} instance
+ */
+JsEvalContext.recycle = function(instance) {
+  for (var i in instance.vars_) {
+    // NOTE(mesch): We avoid object creation here. (IE6 perf)
+    delete instance.vars_[i];
+  }
+  instance.data_ = null;
+  JsEvalContext.recycledInstances_.push(instance);
+};
+
+
+/**
+ * Executes a function created using jsEvalToFunction() in the context
+ * of vars, data, and template.
+ *
+ * @param {Function} exprFunction A javascript function created from
+ * a jstemplate attribute value.
+ *
+ * @param {Element} template DOM node of the template.
+ *
+ * @return {Object|null} The value of the expression from which
+ * exprFunction was created in the current js expression context and
+ * the context of template.
+ */
+JsEvalContext.prototype.jsexec = function(exprFunction, template) {
+  try {
+    return exprFunction.call(template, this.vars_, this.data_);
+  } catch (e) {
+    log('jsexec EXCEPTION: ' + e + ' at ' + template +
+        ' with ' + exprFunction);
+    return JsEvalContext.globals_[GLOB_default];
+  }
+};
+
+
+/**
+ * Clones the current context for a new context object. The cloned
+ * context has the data object as its context object and the current
+ * context as its parent context. It also sets the $index variable to
+ * the given value. This value usually is the position of the data
+ * object in a list for which a template is instantiated multiply.
+ *
+ * @param {Object} data The new context object.
+ *
+ * @param {number} index Position of the new context when multiply
+ * instantiated. (See implementation of jstSelect().)
+ * 
+ * @param {number} count The total number of contexts that were multiply
+ * instantiated. (See implementation of jstSelect().)
+ *
+ * @return {JsEvalContext}
+ */
+JsEvalContext.prototype.clone = function(data, index, count) {
+  var ret = JsEvalContext.create(data, this);
+  ret.setVariable(VAR_index, index);
+  ret.setVariable(VAR_count, count);
+  return ret;
+};
+
+
+/**
+ * Binds a local variable to the given value. If set from jstemplate
+ * jsvalue expressions, variable names must start with $, but in the
+ * API they only have to be valid javascript identifier.
+ *
+ * @param {string} name
+ *
+ * @param {Object?} value
+ */
+JsEvalContext.prototype.setVariable = function(name, value) {
+  this.vars_[name] = value;
+};
+
+
+/**
+ * Returns the value bound to the local variable of the given name, or
+ * undefined if it wasn't set. There is no way to distinguish a
+ * variable that wasn't set from a variable that was set to
+ * undefined. Used mostly for testing.
+ *
+ * @param {string} name
+ *
+ * @return {Object?} value
+ */
+JsEvalContext.prototype.getVariable = function(name) {
+  return this.vars_[name];
+};
+
+
+/**
+ * Evaluates a string expression within the scope of this context
+ * and returns the result.
+ *
+ * @param {string} expr A javascript expression
+ * @param {Element} opt_template An optional node to serve as "this"
+ *
+ * @return {Object?} value
+ */
+JsEvalContext.prototype.evalExpression = function(expr, opt_template) {
+  var exprFunction = jsEvalToFunction(expr);
+  return this.jsexec(exprFunction, opt_template);
+};
+
+
+/**
+ * Uninlined string literals for jsEvalToFunction() (IE6 perf).
+ */
+var STRING_a = 'a_';
+var STRING_b = 'b_';
+var STRING_with = 'with (a_) with (b_) return ';
+
+
+/**
+ * Cache for jsEvalToFunction results.
+ * @type Object
+ */
+JsEvalContext.evalToFunctionCache_ = {};
+
+
+/**
+ * Evaluates the given expression as the body of a function that takes
+ * vars and data as arguments. Since the resulting function depends
+ * only on expr, we cache the result so we save some Function
+ * invocations, and some object creations in IE6.
+ *
+ * @param {string} expr A javascript expression.
+ *
+ * @return {Function} A function that returns the value of expr in the
+ * context of vars and data.
+ */
+function jsEvalToFunction(expr) {
+  if (!JsEvalContext.evalToFunctionCache_[expr]) {
+    try {
+      // NOTE(mesch): The Function constructor is faster than eval().
+      JsEvalContext.evalToFunctionCache_[expr] =
+        new Function(STRING_a, STRING_b, STRING_with + expr);
+    } catch (e) {
+      log('jsEvalToFunction (' + expr + ') EXCEPTION ' + e);
+    }
+  }
+  return JsEvalContext.evalToFunctionCache_[expr];
+}
+
+
+/**
+ * Evaluates the given expression to itself. This is meant to pass
+ * through string attribute values.
+ *
+ * @param {string} expr
+ *
+ * @return {string}
+ */
+function jsEvalToSelf(expr) {
+  return expr;
+}
+
+
+/**
+ * Parses the value of the jsvalues attribute in jstemplates: splits
+ * it up into a map of labels and expressions, and creates functions
+ * from the expressions that are suitable for execution by
+ * JsEvalContext.jsexec(). All that is returned as a flattened array
+ * of pairs of a String and a Function.
+ *
+ * @param {string} expr
+ *
+ * @return {Array}
+ */
+function jsEvalToValues(expr) {
+  // TODO(mesch): It is insufficient to split the values by simply
+  // finding semi-colons, as the semi-colon may be part of a string
+  // constant or escaped.
+  var ret = [];
+  var values = expr.split(REGEXP_semicolon);
+  for (var i = 0, I = jsLength(values); i < I; ++i) {
+    var colon = values[i].indexOf(CHAR_colon);
+    if (colon < 0) {
+      continue;
+    }
+    var label = stringTrim(values[i].substr(0, colon));
+    var value = jsEvalToFunction(values[i].substr(colon + 1));
+    ret.push(label, value);
+  }
+  return ret;
+}
+
+
+/**
+ * Parses the value of the jseval attribute of jstemplates: splits it
+ * up into a list of expressions, and creates functions from the
+ * expressions that are suitable for execution by
+ * JsEvalContext.jsexec(). All that is returned as an Array of
+ * Function.
+ *
+ * @param {string} expr
+ *
+ * @return {Array.<Function>}
+ */
+function jsEvalToExpressions(expr) {
+  var ret = [];
+  var values = expr.split(REGEXP_semicolon);
+  for (var i = 0, I = jsLength(values); i < I; ++i) {
+    if (values[i]) {
+      var value = jsEvalToFunction(values[i]);
+      ret.push(value);
+    }
+  }
+  return ret;
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate.js b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate.js
index d2cc386..7634ff6 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate.js
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate.js
@@ -1,1018 +1,1018 @@
-// Copyright 2006 Google Inc.

-//

-// 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.

-/**

- * Author: Steffen Meschkat <mesch@google.com>

- *

- * @fileoverview A simple formatter to project JavaScript data into

- * HTML templates. The template is edited in place. I.e. in order to

- * instantiate a template, clone it from the DOM first, and then

- * process the cloned template. This allows for updating of templates:

- * If the templates is processed again, changed values are merely

- * updated.

- *

- * NOTE(mesch): IE DOM doesn't have importNode().

- *

- * NOTE(mesch): The property name "length" must not be used in input

- * data, see comment in jstSelect_().

- */

-

-

-/**

- * Names of jstemplate attributes. These attributes are attached to

- * normal HTML elements and bind expression context data to the HTML

- * fragment that is used as template.

- */

-var ATT_select = 'jsselect';

-var ATT_instance = 'jsinstance';

-var ATT_display = 'jsdisplay';

-var ATT_values = 'jsvalues';

-var ATT_vars = 'jsvars';

-var ATT_eval = 'jseval';

-var ATT_transclude = 'transclude';

-var ATT_content = 'jscontent';

-var ATT_skip = 'jsskip';

-

-

-/**

- * Name of the attribute that caches a reference to the parsed

- * template processing attribute values on a template node.

- */

-var ATT_jstcache = 'jstcache';

-

-

-/**

- * Name of the property that caches the parsed template processing

- * attribute values on a template node.

- */

-var PROP_jstcache = '__jstcache';

-

-

-/**

- * ID of the element that contains dynamically loaded jstemplates.

- */

-var STRING_jsts = 'jsts';

-

-

-/**

- * Un-inlined string literals, to avoid object creation in

- * IE6.

- */

-var CHAR_asterisk = '*';

-var CHAR_dollar = '$';

-var CHAR_period = '.';

-var CHAR_ampersand = '&';

-var STRING_div = 'div';

-var STRING_id = 'id';

-var STRING_asteriskzero = '*0';

-var STRING_zero = '0';

-

-

-/**

- * HTML template processor. Data values are bound to HTML templates

- * using the attributes transclude, jsselect, jsdisplay, jscontent,

- * jsvalues. The template is modifed in place. The values of those

- * attributes are JavaScript expressions that are evaluated in the

- * context of the data object fragment.

- *

- * @param {JsEvalContext} context Context created from the input data

- * object.

- *

- * @param {Element} template DOM node of the template. This will be

- * processed in place. After processing, it will still be a valid

- * template that, if processed again with the same data, will remain

- * unchanged.

- *

- * @param {boolean} opt_debugging Optional flag to collect debugging

- *     information while processing the template.  Only takes effect

- *     in MAPS_DEBUG.

- */

-function jstProcess(context, template, opt_debugging) {

-  var processor = new JstProcessor;

-  if (MAPS_DEBUG && opt_debugging) {

-    processor.setDebugging(opt_debugging);

-  }

-  JstProcessor.prepareTemplate_(template);

-

-  /**

-   * Caches the document of the template node, so we don't have to

-   * access it through ownerDocument.

-   * @type Document

-   */

-  processor.document_ = ownerDocument(template);

-

-  processor.run_(bindFully(processor, processor.jstProcessOuter_,

-                           context, template));

-  if (MAPS_DEBUG && opt_debugging) {

-    log('jstProcess:' + '\n' + processor.getLogs().join('\n'));

-  }

-}

-

-

-/**

- * Internal class used by jstemplates to maintain context.  This is

- * necessary to process deep templates in Safari which has a

- * relatively shallow maximum recursion depth of 100.

- * @class

- * @constructor

- */

-function JstProcessor() {

-  if (MAPS_DEBUG) {

-    /**

-     * An array of logging messages.  These are collected during processing

-     * and dumped to the console at the end.

-     * @type Array.<string>

-     */

-    this.logs_ = [];

-  }

-}

-

-

-/**

- * Counter to generate node ids. These ids will be stored in

- * ATT_jstcache and be used to lookup the preprocessed js attributes

- * from the jstcache_. The id is stored in an attribute so it

- * suvives cloneNode() and thus cloned template nodes can share the

- * same cache entry.

- * @type number

- */

-JstProcessor.jstid_ = 0;

-

-

-/**

- * Map from jstid to processed js attributes.

- * @type Object

- */

-JstProcessor.jstcache_ = {};

-

-/**

- * The neutral cache entry. Used for all nodes that don't have any

- * jst attributes. We still set the jsid attribute on those nodes so

- * we can avoid to look again for all the other jst attributes that

- * aren't there. Remember: not only the processing of the js

- * attribute values is expensive and we thus want to cache it. The

- * access to the attributes on the Node in the first place is

- * expensive too.

- */

-JstProcessor.jstcache_[0] = {};

-

-

-/**

- * Map from concatenated attribute string to jstid.

- * The key is the concatenation of all jst atributes found on a node

- * formatted as "name1=value1&name2=value2&...", in the order defined by

- * JST_ATTRIBUTES. The value is the id of the jstcache_ entry that can

- * be used for this node. This allows the reuse of cache entries in cases

- * when a cached entry already exists for a given combination of attribute

- * values. (For example when two different nodes in a template share the same

- * JST attributes.)

- * @type Object

- */

-JstProcessor.jstcacheattributes_ = {};

-

-

-/**

- * Map for storing temporary attribute values in prepareNode_() so they don't

- * have to be retrieved twice. (IE6 perf)

- * @type Object

- */

-JstProcessor.attributeValues_ = {};

-

-

-/**

- * A list for storing non-empty attributes found on a node in prepareNode_().

- * The array is global since it can be reused - this way there is no need to

- * construct a new array object for each invocation. (IE6 perf)

- * @type Array

- */

-JstProcessor.attributeList_ = [];

-

-

-/**

- * Prepares the template: preprocesses all jstemplate attributes.

- *

- * @param {Element} template

- */

-JstProcessor.prepareTemplate_ = function(template) {

-  if (!template[PROP_jstcache]) {

-    domTraverseElements(template, function(node) {

-      JstProcessor.prepareNode_(node);

-    });

-  }

-};

-

-

-/**

- * A list of attributes we use to specify jst processing instructions,

- * and the functions used to parse their values.

- *

- * @type Array.<Array>

- */

-var JST_ATTRIBUTES = [

-    [ ATT_select, jsEvalToFunction ],

-    [ ATT_display, jsEvalToFunction ],

-    [ ATT_values, jsEvalToValues ],

-    [ ATT_vars, jsEvalToValues ],

-    [ ATT_eval, jsEvalToExpressions ],

-    [ ATT_transclude, jsEvalToSelf ],

-    [ ATT_content, jsEvalToFunction ],

-    [ ATT_skip, jsEvalToFunction ]

-];

-

-

-/**

- * Prepares a single node: preprocesses all template attributes of the

- * node, and if there are any, assigns a jsid attribute and stores the

- * preprocessed attributes under the jsid in the jstcache.

- *

- * @param {Element} node

- *

- * @return {Object} The jstcache entry. The processed jst attributes

- * are properties of this object. If the node has no jst attributes,

- * returns an object with no properties (the jscache_[0] entry).

- */

-JstProcessor.prepareNode_ = function(node) {

-  // If the node already has a cache property, return it.

-  if (node[PROP_jstcache]) {

-    return node[PROP_jstcache];

-  }

-

-  // If it is not found, we always set the PROP_jstcache property on the node.

-  // Accessing the property is faster than executing getAttribute(). If we

-  // don't find the property on a node that was cloned in jstSelect_(), we

-  // will fall back to check for the attribute and set the property

-  // from cache.

-

-  // If the node has an attribute indexing a cache object, set it as a property

-  // and return it.

-  var jstid = domGetAttribute(node, ATT_jstcache);

-  if (jstid != null) {

-    return node[PROP_jstcache] = JstProcessor.jstcache_[jstid];

-  }

-

-  var attributeValues = JstProcessor.attributeValues_;

-  var attributeList = JstProcessor.attributeList_;

-  attributeList.length = 0;

-

-  // Look for interesting attributes.

-  for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) {

-    var name = JST_ATTRIBUTES[i][0];

-    var value = domGetAttribute(node, name);

-    attributeValues[name] = value;

-    if (value != null) {

-      attributeList.push(name + "=" + value);

-    }

-  }

-

-  // If none found, mark this node to prevent further inspection, and return

-  // an empty cache object.

-  if (attributeList.length == 0) {

-    domSetAttribute(node, ATT_jstcache, STRING_zero);

-    return node[PROP_jstcache] = JstProcessor.jstcache_[0];

-  }

-

-  // If we already have a cache object corresponding to these attributes,

-  // annotate the node with it, and return it.

-  var attstring = attributeList.join(CHAR_ampersand);

-  if (jstid = JstProcessor.jstcacheattributes_[attstring]) {

-    domSetAttribute(node, ATT_jstcache, jstid);

-    return node[PROP_jstcache] = JstProcessor.jstcache_[jstid];

-  }

-

-  // Otherwise, build a new cache object.

-  var jstcache = {};

-  for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) {

-    var att = JST_ATTRIBUTES[i];

-    var name = att[0];

-    var parse = att[1];

-    var value = attributeValues[name];

-    if (value != null) {

-      jstcache[name] = parse(value);

-      if (MAPS_DEBUG) {

-        jstcache.jstAttributeValues = jstcache.jstAttributeValues || {};

-        jstcache.jstAttributeValues[name] = value;

-      }

-    }

-  }

-

-  jstid = STRING_empty + ++JstProcessor.jstid_;

-  domSetAttribute(node, ATT_jstcache, jstid);

-  JstProcessor.jstcache_[jstid] = jstcache;

-  JstProcessor.jstcacheattributes_[attstring] = jstid;

-

-  return node[PROP_jstcache] = jstcache;

-};

-

-

-/**

- * Runs the given function in our state machine.

- *

- * It's informative to view the set of all function calls as a tree:

- * - nodes are states

- * - edges are state transitions, implemented as calls to the pending

- *   functions in the stack.

- *   - pre-order function calls are downward edges (recursion into call).

- *   - post-order function calls are upward edges (return from call).

- * - leaves are nodes which do not recurse.

- * We represent the call tree as an array of array of calls, indexed as

- * stack[depth][index].  Here [depth] indexes into the call stack, and

- * [index] indexes into the call queue at that depth.  We require a call

- * queue so that a node may branch to more than one child

- * (which will be called serially), typically due to a loop structure.

- *

- * @param {Function} f The first function to run.

- */

-JstProcessor.prototype.run_ = function(f) {

-  var me = this;

-

-  /**

-   * A stack of queues of pre-order calls.

-   * The inner arrays (constituent queues) are structured as

-   * [ arg2, arg1, method, arg2, arg1, method, ...]

-   * ie. a flattened array of methods with 2 arguments, in reverse order

-   * for efficient push/pop.

-   *

-   * The outer array is a stack of such queues.

-   *

-   * @type Array.<Array>

-   */

-  var calls = me.calls_ = [];

-

-  /**

-   * The index into the queue for each depth. NOTE: Alternative would

-   * be to maintain the queues in reverse order (popping off of the

-   * end) but the repeated calls to .pop() consumed 90% of this

-   * function's execution time.

-   * @type Array.<number>

-   */

-  var queueIndices = me.queueIndices_ = [];

-

-  /**

-   * A pool of empty arrays.  Minimizes object allocation for IE6's benefit.

-   * @type Array.<Array>

-   */

-  var arrayPool = me.arrayPool_ = [];

-

-  f();

-  var queue, queueIndex;

-  var method, arg1, arg2;

-  var temp;

-  while (calls.length) {

-    queue = calls[calls.length - 1];

-    queueIndex = queueIndices[queueIndices.length - 1];

-    if (queueIndex >= queue.length) {

-      me.recycleArray_(calls.pop());

-      queueIndices.pop();

-      continue;

-    }

-

-    // Run the first function in the queue.

-    method = queue[queueIndex++];

-    arg1 = queue[queueIndex++];

-    arg2 = queue[queueIndex++];

-    queueIndices[queueIndices.length - 1] = queueIndex;

-    method.call(me, arg1, arg2);

-  }

-};

-

-

-/**

- * Pushes one or more functions onto the stack.  These will be run in sequence,

- * interspersed with any recursive calls that they make.

- *

- * This method takes ownership of the given array!

- *

- * @param {Array} args Array of method calls structured as

- *     [ method, arg1, arg2, method, arg1, arg2, ... ]

- */

-JstProcessor.prototype.push_ = function(args) {

-  this.calls_.push(args);

-  this.queueIndices_.push(0);

-};

-

-

-/**

- * Enable/disable debugging.

- * @param {boolean} debugging New state

- */

-JstProcessor.prototype.setDebugging = function(debugging) {

-  if (MAPS_DEBUG) {

-    this.debugging_ = debugging;

-  }

-};

-

-

-JstProcessor.prototype.createArray_ = function() {

-  if (this.arrayPool_.length) {

-    return this.arrayPool_.pop();

-  } else {

-    return [];

-  }

-};

-

-

-JstProcessor.prototype.recycleArray_ = function(array) {

-  arrayClear(array);

-  this.arrayPool_.push(array);

-};

-

-/**

- * Implements internals of jstProcess. This processes the two

- * attributes transclude and jsselect, which replace or multiply

- * elements, hence the name "outer". The remainder of the attributes

- * is processed in jstProcessInner_(), below. That function

- * jsProcessInner_() only processes attributes that affect an existing

- * node, but doesn't create or destroy nodes, hence the name

- * "inner". jstProcessInner_() is called through jstSelect_() if there

- * is a jsselect attribute (possibly for newly created clones of the

- * current template node), or directly from here if there is none.

- *

- * @param {JsEvalContext} context

- *

- * @param {Element} template

- */

-JstProcessor.prototype.jstProcessOuter_ = function(context, template) {

-  var me = this;

-

-  var jstAttributes = me.jstAttributes_(template);

-  if (MAPS_DEBUG && me.debugging_) {

-    me.logState_('Outer', template, jstAttributes.jstAttributeValues);

-  }

-

-  var transclude = jstAttributes[ATT_transclude];

-  if (transclude) {

-    var tr = jstGetTemplate(transclude);

-    if (tr) {

-      domReplaceChild(tr, template);

-      var call = me.createArray_();

-      call.push(me.jstProcessOuter_, context, tr);

-      me.push_(call);

-    } else {

-      domRemoveNode(template);

-    }

-    return;

-  }

-

-  var select = jstAttributes[ATT_select];

-  if (select) {

-    me.jstSelect_(context, template, select);

-  } else {

-    me.jstProcessInner_(context, template);

-  }

-};

-

-

-/**

- * Implements internals of jstProcess. This processes all attributes

- * except transclude and jsselect. It is called either from

- * jstSelect_() for nodes that have a jsselect attribute so that the

- * jsselect attribute will not be processed again, or else directly

- * from jstProcessOuter_(). See the comment on jstProcessOuter_() for

- * an explanation of the name.

- *

- * @param {JsEvalContext} context

- *

- * @param {Element} template

- */

-JstProcessor.prototype.jstProcessInner_ = function(context, template) {

-  var me = this;

-

-  var jstAttributes = me.jstAttributes_(template);

-  if (MAPS_DEBUG && me.debugging_) {

-    me.logState_('Inner', template, jstAttributes.jstAttributeValues);

-  }

-

-  // NOTE(mesch): See NOTE on ATT_content why this is a separate

-  // attribute, and not a special value in ATT_values.

-  var display = jstAttributes[ATT_display];

-  if (display) {

-    var shouldDisplay = context.jsexec(display, template);

-    if (MAPS_DEBUG && me.debugging_) {

-      me.logs_.push(ATT_display + ': ' + shouldDisplay + '<br/>');

-    }

-    if (!shouldDisplay) {

-      displayNone(template);

-      return;

-    }

-    displayDefault(template);

-  }

-

-  // NOTE(mesch): jsvars is evaluated before jsvalues, because it's

-  // more useful to be able to use var values in attribute value

-  // expressions than vice versa.

-  var values = jstAttributes[ATT_vars];

-  if (values) {

-    me.jstVars_(context, template, values);

-  }

-

-  values = jstAttributes[ATT_values];

-  if (values) {

-    me.jstValues_(context, template, values);

-  }

-

-  // Evaluate expressions immediately. Useful for hooking callbacks

-  // into jstemplates.

-  //

-  // NOTE(mesch): Evaluation order is sometimes significant, e.g. when

-  // the expression evaluated in jseval relies on the values set in

-  // jsvalues, so it needs to be evaluated *after*

-  // jsvalues. TODO(mesch): This is quite arbitrary, it would be

-  // better if this would have more necessity to it.

-  var expressions = jstAttributes[ATT_eval];

-  if (expressions) {

-    for (var i = 0, I = jsLength(expressions); i < I; ++i) {

-      context.jsexec(expressions[i], template);

-    }

-  }

-

-  var skip = jstAttributes[ATT_skip];

-  if (skip) {

-    var shouldSkip = context.jsexec(skip, template);

-    if (MAPS_DEBUG && me.debugging_) {

-      me.logs_.push(ATT_skip + ': ' + shouldSkip + '<br/>');

-    }

-    if (shouldSkip) return;

-  }

-

-  // NOTE(mesch): content is a separate attribute, instead of just a

-  // special value mentioned in values, for two reasons: (1) it is

-  // fairly common to have only mapped content, and writing

-  // content="expr" is shorter than writing values="content:expr", and

-  // (2) the presence of content actually terminates traversal, and we

-  // need to check for that. Display is a separate attribute for a

-  // reason similar to the second, in that its presence *may*

-  // terminate traversal.

-  var content = jstAttributes[ATT_content];

-  if (content) {

-    me.jstContent_(context, template, content);

-

-  } else {

-    // Newly generated children should be ignored, so we explicitly

-    // store the children to be processed.

-    var queue = me.createArray_();

-    for (var c = template.firstChild; c; c = c.nextSibling) {

-      if (c.nodeType == DOM_ELEMENT_NODE) {

-        queue.push(me.jstProcessOuter_, context, c);

-      }

-    }

-    if (queue.length) me.push_(queue);

-  }

-};

-

-

-/**

- * Implements the jsselect attribute: evalutes the value of the

- * jsselect attribute in the current context, with the current

- * variable bindings (see JsEvalContext.jseval()). If the value is an

- * array, the current template node is multiplied once for every

- * element in the array, with the array element being the context

- * object. If the array is empty, or the value is undefined, then the

- * current template node is dropped. If the value is not an array,

- * then it is just made the context object.

- *

- * @param {JsEvalContext} context The current evaluation context.

- *

- * @param {Element} template The currently processed node of the template.

- *

- * @param {Function} select The javascript expression to evaluate.

- *

- * @notypecheck FIXME(hmitchell): See OCL6434950. instance and value need

- * type checks.

- */

-JstProcessor.prototype.jstSelect_ = function(context, template, select) {

-  var me = this;

-

-  var value = context.jsexec(select, template);

-

-  // Enable reprocessing: if this template is reprocessed, then only

-  // fill the section instance here. Otherwise do the cardinal

-  // processing of a new template.

-  var instance = domGetAttribute(template, ATT_instance);

-

-  var instanceLast = false;

-  if (instance) {

-    if (instance.charAt(0) == CHAR_asterisk) {

-      instance = parseInt10(instance.substr(1));

-      instanceLast = true;

-    } else {

-      instance = parseInt10(/** @type string */(instance));

-    }

-  }

-

-  // The expression value instanceof Array is occasionally false for

-  // arrays, seen in Firefox. Thus we recognize an array as an object

-  // which is not null that has a length property. Notice that this

-  // also matches input data with a length property, so this property

-  // name should be avoided in input data.

-  var multiple = isArray(value);

-  var count = multiple ? jsLength(value) : 1;

-  var multipleEmpty = (multiple && count == 0);

-

-  if (multiple) {

-    if (multipleEmpty) {

-      // For an empty array, keep the first template instance and mark

-      // it last. Remove all other template instances.

-      if (!instance) {

-        domSetAttribute(template, ATT_instance, STRING_asteriskzero);

-        displayNone(template);

-      } else {

-        domRemoveNode(template);

-      }

-

-    } else {

-      displayDefault(template);

-      // For a non empty array, create as many template instances as

-      // are needed. If the template is first processed, as many

-      // template instances are needed as there are values in the

-      // array. If the template is reprocessed, new template instances

-      // are only needed if there are more array values than template

-      // instances. Those additional instances are created by

-      // replicating the last template instance.

-      //

-      // When the template is first processed, there is no jsinstance

-      // attribute. This is indicated by instance === null, except in

-      // opera it is instance === "". Notice also that the === is

-      // essential, because 0 == "", presumably via type coercion to

-      // boolean.

-      if (instance === null || instance === STRING_empty ||

-          (instanceLast && instance < count - 1)) {

-        // A queue of calls to push.

-        var queue = me.createArray_();

-

-        var instancesStart = instance || 0;

-        var i, I, clone;

-        for (i = instancesStart, I = count - 1; i < I; ++i) {

-          var node = domCloneNode(template);

-          domInsertBefore(node, template);

-

-          jstSetInstance(/** @type Element */(node), value, i);

-          clone = context.clone(value[i], i, count);

-

-          queue.push(me.jstProcessInner_, clone, node,

-                     JsEvalContext.recycle, clone, null);

-                     

-        }

-        // Push the originally present template instance last to keep

-        // the order aligned with the DOM order, because the newly

-        // created template instances are inserted *before* the

-        // original instance.

-        jstSetInstance(template, value, i);

-        clone = context.clone(value[i], i, count);

-        queue.push(me.jstProcessInner_, clone, template,

-                   JsEvalContext.recycle, clone, null);

-        me.push_(queue);

-      } else if (instance < count) {

-        var v = value[instance];

-

-        jstSetInstance(template, value, instance);

-        var clone = context.clone(v, instance, count);

-        var queue = me.createArray_();

-        queue.push(me.jstProcessInner_, clone, template,

-                   JsEvalContext.recycle, clone, null);

-        me.push_(queue);

-      } else {

-        domRemoveNode(template);

-      }

-    }

-  } else {

-    if (value == null) {

-      displayNone(template);

-    } else {

-      displayDefault(template);

-      var clone = context.clone(value, 0, 1);

-      var queue = me.createArray_();

-      queue.push(me.jstProcessInner_, clone, template,

-                 JsEvalContext.recycle, clone, null);

-      me.push_(queue);

-    }

-  }

-};

-

-

-/**

- * Implements the jsvars attribute: evaluates each of the values and

- * assigns them to variables in the current context. Similar to

- * jsvalues, except that all values are treated as vars, independent

- * of their names.

- *

- * @param {JsEvalContext} context Current evaluation context.

- *

- * @param {Element} template Currently processed template node.

- *

- * @param {Array} values Processed value of the jsvalues attribute: a

- * flattened array of pairs. The second element in the pair is a

- * function that can be passed to jsexec() for evaluation in the

- * current jscontext, and the first element is the variable name that

- * the value returned by jsexec is assigned to.

- */

-JstProcessor.prototype.jstVars_ = function(context, template, values) {

-  for (var i = 0, I = jsLength(values); i < I; i += 2) {

-    var label = values[i];

-    var value = context.jsexec(values[i+1], template);

-    context.setVariable(label, value);

-  }

-};

-

-

-/**

- * Implements the jsvalues attribute: evaluates each of the values and

- * assigns them to variables in the current context (if the name

- * starts with '$', javascript properties of the current template node

- * (if the name starts with '.'), or DOM attributes of the current

- * template node (otherwise). Since DOM attribute values are always

- * strings, the value is coerced to string in the latter case,

- * otherwise it's the uncoerced javascript value.

- *

- * @param {JsEvalContext} context Current evaluation context.

- *

- * @param {Element} template Currently processed template node.

- *

- * @param {Array} values Processed value of the jsvalues attribute: a

- * flattened array of pairs. The second element in the pair is a

- * function that can be passed to jsexec() for evaluation in the

- * current jscontext, and the first element is the label that

- * determines where the value returned by jsexec is assigned to.

- */

-JstProcessor.prototype.jstValues_ = function(context, template, values) {

-  for (var i = 0, I = jsLength(values); i < I; i += 2) {

-    var label = values[i];

-    var value = context.jsexec(values[i+1], template);

-

-    if (label.charAt(0) == CHAR_dollar) {

-      // A jsvalues entry whose name starts with $ sets a local

-      // variable.

-      context.setVariable(label, value);

-

-    } else if (label.charAt(0) == CHAR_period) {

-      // A jsvalues entry whose name starts with . sets a property of

-      // the current template node. The name may have further dot

-      // separated components, which are translated into namespace

-      // objects. This specifically allows to set properties on .style

-      // using jsvalues. NOTE(mesch): Setting the style attribute has

-      // no effect in IE and hence should not be done anyway.

-      var nameSpaceLabel = label.substr(1).split(CHAR_period);

-      var nameSpaceObject = template;

-      var nameSpaceDepth = jsLength(nameSpaceLabel);

-      for (var j = 0, J = nameSpaceDepth - 1; j < J; ++j) {

-        var jLabel = nameSpaceLabel[j];

-        if (!nameSpaceObject[jLabel]) {

-          nameSpaceObject[jLabel] = {};

-        }

-        nameSpaceObject = nameSpaceObject[jLabel];

-      }

-      nameSpaceObject[nameSpaceLabel[nameSpaceDepth - 1]] = value;

-

-    } else if (label) {

-      // Any other jsvalues entry sets an attribute of the current

-      // template node.

-      if (typeof value == TYPE_boolean) {

-        // Handle boolean values that are set as attributes specially,

-        // according to the XML/HTML convention.

-        if (value) {

-          domSetAttribute(template, label, label);

-        } else {

-          domRemoveAttribute(template, label);

-        }

-      } else {

-        domSetAttribute(template, label, STRING_empty + value);

-      }

-    }

-  }

-};

-

-

-/**

- * Implements the jscontent attribute. Evalutes the expression in

- * jscontent in the current context and with the current variables,

- * and assigns its string value to the content of the current template

- * node.

- *

- * @param {JsEvalContext} context Current evaluation context.

- *

- * @param {Element} template Currently processed template node.

- *

- * @param {Function} content Processed value of the jscontent

- * attribute.

- */

-JstProcessor.prototype.jstContent_ = function(context, template, content) {

-  // NOTE(mesch): Profiling shows that this method costs significant

-  // time. In jstemplate_perf.html, it's about 50%. I tried to replace

-  // by HTML escaping and assignment to innerHTML, but that was even

-  // slower.

-  var value = STRING_empty + context.jsexec(content, template);

-  // Prevent flicker when refreshing a template and the value doesn't

-  // change.

-  if (template.innerHTML == value) {

-    return;

-  }

-  while (template.firstChild) {

-    domRemoveNode(template.firstChild);

-  }

-  var t = domCreateTextNode(this.document_, value);

-  domAppendChild(template, t);

-};

-

-

-/**

- * Caches access to and parsing of template processing attributes. If

- * domGetAttribute() is called every time a template attribute value

- * is used, it takes more than 10% of the time.

- *

- * @param {Element} template A DOM element node of the template.

- *

- * @return {Object} A javascript object that has all js template

- * processing attribute values of the node as properties.

- */

-JstProcessor.prototype.jstAttributes_ = function(template) {

-  if (template[PROP_jstcache]) {

-    return template[PROP_jstcache];

-  }

-

-  var jstid = domGetAttribute(template, ATT_jstcache);

-  if (jstid) {

-    return template[PROP_jstcache] = JstProcessor.jstcache_[jstid];

-  }

-

-  return JstProcessor.prepareNode_(template);

-};

-

-

-/**

- * Helps to implement the transclude attribute, and is the initial

- * call to get hold of a template from its ID.

- *

- * If the ID is not present in the DOM, and opt_loadHtmlFn is specified, this

- * function will call that function and add the result to the DOM, before

- * returning the template.

- *

- * @param {string} name The ID of the HTML element used as template.

- * @param {Function} opt_loadHtmlFn A function which, when called, will return

- *   HTML that contains an element whose ID is 'name'.

- *

- * @return {Element|null} The DOM node of the template. (Only element nodes

- * can be found by ID, hence it's a Element.)

- */

-function jstGetTemplate(name, opt_loadHtmlFn) {

-  var doc = document;

-  var section;

-  if (opt_loadHtmlFn) {

-    section = jstLoadTemplateIfNotPresent(doc, name, opt_loadHtmlFn);

-  } else {

-    section = domGetElementById(doc, name);

-  }

-  if (section) {

-    JstProcessor.prepareTemplate_(section);

-    var ret = domCloneElement(section);

-    domRemoveAttribute(ret, STRING_id);

-    return ret;

-  } else {

-    return null;

-  }

-}

-

-/**

- * This function is the same as 'jstGetTemplate' but, if the template

- * does not exist, throw an exception.

- *

- * @param {string} name The ID of the HTML element used as template.

- * @param {Function} opt_loadHtmlFn A function which, when called, will return

- *   HTML that contains an element whose ID is 'name'.

- *

- * @return {Element} The DOM node of the template. (Only element nodes

- * can be found by ID, hence it's a Element.)

- */

-function jstGetTemplateOrDie(name, opt_loadHtmlFn) {

-  var x = jstGetTemplate(name, opt_loadHtmlFn);

-  check(x !== null);

-  return /** @type Element */(x);

-}

-

-

-/**

- * If an element with id 'name' is not present in the document, call loadHtmlFn

- * and insert the result into the DOM.

- *

- * @param {Document} doc

- * @param {string} name

- * @param {Function} loadHtmlFn A function that returns HTML to be inserted

- * into the DOM.

- * @param {string} opt_target The id of a DOM object under which to attach the

- *   HTML once it's inserted.  An object with this id is created if it does not

- *   exist.

- * @return {Element} The node whose id is 'name'

- */

-function jstLoadTemplateIfNotPresent(doc, name, loadHtmlFn, opt_target) {

-  var section = domGetElementById(doc, name);

-  if (section) {

-    return section;

-  }

-  // Load any necessary HTML and try again.

-  jstLoadTemplate_(doc, loadHtmlFn(), opt_target || STRING_jsts);

-  var section = domGetElementById(doc, name);

-  if (!section) {

-    log("Error: jstGetTemplate was provided with opt_loadHtmlFn, " +

-	"but that function did not provide the id '" + name + "'.");

-  }

-  return /** @type Element */(section);

-}

-

-

-/**

- * Loads the given HTML text into the given document, so that

- * jstGetTemplate can find it.

- *

- * We append it to the element identified by targetId, which is hidden.

- * If it doesn't exist, it is created.

- *

- * @param {Document} doc The document to create the template in.

- *

- * @param {string} html HTML text to be inserted into the document.

- *

- * @param {string} targetId The id of a DOM object under which to attach the

- *   HTML once it's inserted.  An object with this id is created if it does not

- *   exist.

- */

-function jstLoadTemplate_(doc, html, targetId) {

-  var existing_target = domGetElementById(doc, targetId);

-  var target;

-  if (!existing_target) {

-    target = domCreateElement(doc, STRING_div);

-    target.id = targetId;

-    displayNone(target);

-    positionAbsolute(target);

-    domAppendChild(doc.body, target);

-  } else {

-    target = existing_target;

-  }

-  var div = domCreateElement(doc, STRING_div);

-  target.appendChild(div);

-  div.innerHTML = html;

-}

-

-

-/**

- * Sets the jsinstance attribute on a node according to its context.

- *

- * @param {Element} template The template DOM node to set the instance

- * attribute on.

- *

- * @param {Array} values The current input context, the array of

- * values of which the template node will render one instance.

- *

- * @param {number} index The index of this template node in values.

- */

-function jstSetInstance(template, values, index) {

-  if (index == jsLength(values) - 1) {

-    domSetAttribute(template, ATT_instance, CHAR_asterisk + index);

-  } else {

-    domSetAttribute(template, ATT_instance, STRING_empty + index);

-  }

-}

-

-

-/**

- * Log the current state.

- * @param {string} caller An identifier for the caller of .log_.

- * @param {Element} template The template node being processed.

- * @param {Object} jstAttributeValues The jst attributes of the template node.

- */

-JstProcessor.prototype.logState_ = function(

-    caller, template, jstAttributeValues) {

-  if (MAPS_DEBUG) {

-    var msg = '<table>';

-    msg += '<caption>' + caller + '</caption>';

-    msg += '<tbody>';

-    if (template.id) {

-      msg += '<tr><td>' + 'id:' + '</td><td>' + template.id + '</td></tr>';

-    }

-    if (template.name) {

-      msg += '<tr><td>' + 'name:' + '</td><td>' + template.name + '</td></tr>';

-    }

-    if (jstAttributeValues) {

-      msg += '<tr><td>' + 'attr:' +

-      '</td><td>' + jsToSource(jstAttributeValues) + '</td></tr>';

-    }

-    msg += '</tbody></table><br/>';

-    this.logs_.push(msg);

-  }

-};

-

-

-/**

- * Retrieve the processing logs.

- * @return {Array.<string>} The processing logs.

- */

-JstProcessor.prototype.getLogs = function() {

-  return this.logs_;

-};

-

+// Copyright 2006 Google Inc.
+//
+// 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.
+/**
+ * Author: Steffen Meschkat <mesch@google.com>
+ *
+ * @fileoverview A simple formatter to project JavaScript data into
+ * HTML templates. The template is edited in place. I.e. in order to
+ * instantiate a template, clone it from the DOM first, and then
+ * process the cloned template. This allows for updating of templates:
+ * If the templates is processed again, changed values are merely
+ * updated.
+ *
+ * NOTE(mesch): IE DOM doesn't have importNode().
+ *
+ * NOTE(mesch): The property name "length" must not be used in input
+ * data, see comment in jstSelect_().
+ */
+
+
+/**
+ * Names of jstemplate attributes. These attributes are attached to
+ * normal HTML elements and bind expression context data to the HTML
+ * fragment that is used as template.
+ */
+var ATT_select = 'jsselect';
+var ATT_instance = 'jsinstance';
+var ATT_display = 'jsdisplay';
+var ATT_values = 'jsvalues';
+var ATT_vars = 'jsvars';
+var ATT_eval = 'jseval';
+var ATT_transclude = 'transclude';
+var ATT_content = 'jscontent';
+var ATT_skip = 'jsskip';
+
+
+/**
+ * Name of the attribute that caches a reference to the parsed
+ * template processing attribute values on a template node.
+ */
+var ATT_jstcache = 'jstcache';
+
+
+/**
+ * Name of the property that caches the parsed template processing
+ * attribute values on a template node.
+ */
+var PROP_jstcache = '__jstcache';
+
+
+/**
+ * ID of the element that contains dynamically loaded jstemplates.
+ */
+var STRING_jsts = 'jsts';
+
+
+/**
+ * Un-inlined string literals, to avoid object creation in
+ * IE6.
+ */
+var CHAR_asterisk = '*';
+var CHAR_dollar = '$';
+var CHAR_period = '.';
+var CHAR_ampersand = '&';
+var STRING_div = 'div';
+var STRING_id = 'id';
+var STRING_asteriskzero = '*0';
+var STRING_zero = '0';
+
+
+/**
+ * HTML template processor. Data values are bound to HTML templates
+ * using the attributes transclude, jsselect, jsdisplay, jscontent,
+ * jsvalues. The template is modifed in place. The values of those
+ * attributes are JavaScript expressions that are evaluated in the
+ * context of the data object fragment.
+ *
+ * @param {JsEvalContext} context Context created from the input data
+ * object.
+ *
+ * @param {Element} template DOM node of the template. This will be
+ * processed in place. After processing, it will still be a valid
+ * template that, if processed again with the same data, will remain
+ * unchanged.
+ *
+ * @param {boolean} opt_debugging Optional flag to collect debugging
+ *     information while processing the template.  Only takes effect
+ *     in MAPS_DEBUG.
+ */
+function jstProcess(context, template, opt_debugging) {
+  var processor = new JstProcessor;
+  if (MAPS_DEBUG && opt_debugging) {
+    processor.setDebugging(opt_debugging);
+  }
+  JstProcessor.prepareTemplate_(template);
+
+  /**
+   * Caches the document of the template node, so we don't have to
+   * access it through ownerDocument.
+   * @type Document
+   */
+  processor.document_ = ownerDocument(template);
+
+  processor.run_(bindFully(processor, processor.jstProcessOuter_,
+                           context, template));
+  if (MAPS_DEBUG && opt_debugging) {
+    log('jstProcess:' + '\n' + processor.getLogs().join('\n'));
+  }
+}
+
+
+/**
+ * Internal class used by jstemplates to maintain context.  This is
+ * necessary to process deep templates in Safari which has a
+ * relatively shallow maximum recursion depth of 100.
+ * @class
+ * @constructor
+ */
+function JstProcessor() {
+  if (MAPS_DEBUG) {
+    /**
+     * An array of logging messages.  These are collected during processing
+     * and dumped to the console at the end.
+     * @type Array.<string>
+     */
+    this.logs_ = [];
+  }
+}
+
+
+/**
+ * Counter to generate node ids. These ids will be stored in
+ * ATT_jstcache and be used to lookup the preprocessed js attributes
+ * from the jstcache_. The id is stored in an attribute so it
+ * suvives cloneNode() and thus cloned template nodes can share the
+ * same cache entry.
+ * @type number
+ */
+JstProcessor.jstid_ = 0;
+
+
+/**
+ * Map from jstid to processed js attributes.
+ * @type Object
+ */
+JstProcessor.jstcache_ = {};
+
+/**
+ * The neutral cache entry. Used for all nodes that don't have any
+ * jst attributes. We still set the jsid attribute on those nodes so
+ * we can avoid to look again for all the other jst attributes that
+ * aren't there. Remember: not only the processing of the js
+ * attribute values is expensive and we thus want to cache it. The
+ * access to the attributes on the Node in the first place is
+ * expensive too.
+ */
+JstProcessor.jstcache_[0] = {};
+
+
+/**
+ * Map from concatenated attribute string to jstid.
+ * The key is the concatenation of all jst atributes found on a node
+ * formatted as "name1=value1&name2=value2&...", in the order defined by
+ * JST_ATTRIBUTES. The value is the id of the jstcache_ entry that can
+ * be used for this node. This allows the reuse of cache entries in cases
+ * when a cached entry already exists for a given combination of attribute
+ * values. (For example when two different nodes in a template share the same
+ * JST attributes.)
+ * @type Object
+ */
+JstProcessor.jstcacheattributes_ = {};
+
+
+/**
+ * Map for storing temporary attribute values in prepareNode_() so they don't
+ * have to be retrieved twice. (IE6 perf)
+ * @type Object
+ */
+JstProcessor.attributeValues_ = {};
+
+
+/**
+ * A list for storing non-empty attributes found on a node in prepareNode_().
+ * The array is global since it can be reused - this way there is no need to
+ * construct a new array object for each invocation. (IE6 perf)
+ * @type Array
+ */
+JstProcessor.attributeList_ = [];
+
+
+/**
+ * Prepares the template: preprocesses all jstemplate attributes.
+ *
+ * @param {Element} template
+ */
+JstProcessor.prepareTemplate_ = function(template) {
+  if (!template[PROP_jstcache]) {
+    domTraverseElements(template, function(node) {
+      JstProcessor.prepareNode_(node);
+    });
+  }
+};
+
+
+/**
+ * A list of attributes we use to specify jst processing instructions,
+ * and the functions used to parse their values.
+ *
+ * @type Array.<Array>
+ */
+var JST_ATTRIBUTES = [
+    [ ATT_select, jsEvalToFunction ],
+    [ ATT_display, jsEvalToFunction ],
+    [ ATT_values, jsEvalToValues ],
+    [ ATT_vars, jsEvalToValues ],
+    [ ATT_eval, jsEvalToExpressions ],
+    [ ATT_transclude, jsEvalToSelf ],
+    [ ATT_content, jsEvalToFunction ],
+    [ ATT_skip, jsEvalToFunction ]
+];
+
+
+/**
+ * Prepares a single node: preprocesses all template attributes of the
+ * node, and if there are any, assigns a jsid attribute and stores the
+ * preprocessed attributes under the jsid in the jstcache.
+ *
+ * @param {Element} node
+ *
+ * @return {Object} The jstcache entry. The processed jst attributes
+ * are properties of this object. If the node has no jst attributes,
+ * returns an object with no properties (the jscache_[0] entry).
+ */
+JstProcessor.prepareNode_ = function(node) {
+  // If the node already has a cache property, return it.
+  if (node[PROP_jstcache]) {
+    return node[PROP_jstcache];
+  }
+
+  // If it is not found, we always set the PROP_jstcache property on the node.
+  // Accessing the property is faster than executing getAttribute(). If we
+  // don't find the property on a node that was cloned in jstSelect_(), we
+  // will fall back to check for the attribute and set the property
+  // from cache.
+
+  // If the node has an attribute indexing a cache object, set it as a property
+  // and return it.
+  var jstid = domGetAttribute(node, ATT_jstcache);
+  if (jstid != null) {
+    return node[PROP_jstcache] = JstProcessor.jstcache_[jstid];
+  }
+
+  var attributeValues = JstProcessor.attributeValues_;
+  var attributeList = JstProcessor.attributeList_;
+  attributeList.length = 0;
+
+  // Look for interesting attributes.
+  for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) {
+    var name = JST_ATTRIBUTES[i][0];
+    var value = domGetAttribute(node, name);
+    attributeValues[name] = value;
+    if (value != null) {
+      attributeList.push(name + "=" + value);
+    }
+  }
+
+  // If none found, mark this node to prevent further inspection, and return
+  // an empty cache object.
+  if (attributeList.length == 0) {
+    domSetAttribute(node, ATT_jstcache, STRING_zero);
+    return node[PROP_jstcache] = JstProcessor.jstcache_[0];
+  }
+
+  // If we already have a cache object corresponding to these attributes,
+  // annotate the node with it, and return it.
+  var attstring = attributeList.join(CHAR_ampersand);
+  if (jstid = JstProcessor.jstcacheattributes_[attstring]) {
+    domSetAttribute(node, ATT_jstcache, jstid);
+    return node[PROP_jstcache] = JstProcessor.jstcache_[jstid];
+  }
+
+  // Otherwise, build a new cache object.
+  var jstcache = {};
+  for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) {
+    var att = JST_ATTRIBUTES[i];
+    var name = att[0];
+    var parse = att[1];
+    var value = attributeValues[name];
+    if (value != null) {
+      jstcache[name] = parse(value);
+      if (MAPS_DEBUG) {
+        jstcache.jstAttributeValues = jstcache.jstAttributeValues || {};
+        jstcache.jstAttributeValues[name] = value;
+      }
+    }
+  }
+
+  jstid = STRING_empty + ++JstProcessor.jstid_;
+  domSetAttribute(node, ATT_jstcache, jstid);
+  JstProcessor.jstcache_[jstid] = jstcache;
+  JstProcessor.jstcacheattributes_[attstring] = jstid;
+
+  return node[PROP_jstcache] = jstcache;
+};
+
+
+/**
+ * Runs the given function in our state machine.
+ *
+ * It's informative to view the set of all function calls as a tree:
+ * - nodes are states
+ * - edges are state transitions, implemented as calls to the pending
+ *   functions in the stack.
+ *   - pre-order function calls are downward edges (recursion into call).
+ *   - post-order function calls are upward edges (return from call).
+ * - leaves are nodes which do not recurse.
+ * We represent the call tree as an array of array of calls, indexed as
+ * stack[depth][index].  Here [depth] indexes into the call stack, and
+ * [index] indexes into the call queue at that depth.  We require a call
+ * queue so that a node may branch to more than one child
+ * (which will be called serially), typically due to a loop structure.
+ *
+ * @param {Function} f The first function to run.
+ */
+JstProcessor.prototype.run_ = function(f) {
+  var me = this;
+
+  /**
+   * A stack of queues of pre-order calls.
+   * The inner arrays (constituent queues) are structured as
+   * [ arg2, arg1, method, arg2, arg1, method, ...]
+   * ie. a flattened array of methods with 2 arguments, in reverse order
+   * for efficient push/pop.
+   *
+   * The outer array is a stack of such queues.
+   *
+   * @type Array.<Array>
+   */
+  var calls = me.calls_ = [];
+
+  /**
+   * The index into the queue for each depth. NOTE: Alternative would
+   * be to maintain the queues in reverse order (popping off of the
+   * end) but the repeated calls to .pop() consumed 90% of this
+   * function's execution time.
+   * @type Array.<number>
+   */
+  var queueIndices = me.queueIndices_ = [];
+
+  /**
+   * A pool of empty arrays.  Minimizes object allocation for IE6's benefit.
+   * @type Array.<Array>
+   */
+  var arrayPool = me.arrayPool_ = [];
+
+  f();
+  var queue, queueIndex;
+  var method, arg1, arg2;
+  var temp;
+  while (calls.length) {
+    queue = calls[calls.length - 1];
+    queueIndex = queueIndices[queueIndices.length - 1];
+    if (queueIndex >= queue.length) {
+      me.recycleArray_(calls.pop());
+      queueIndices.pop();
+      continue;
+    }
+
+    // Run the first function in the queue.
+    method = queue[queueIndex++];
+    arg1 = queue[queueIndex++];
+    arg2 = queue[queueIndex++];
+    queueIndices[queueIndices.length - 1] = queueIndex;
+    method.call(me, arg1, arg2);
+  }
+};
+
+
+/**
+ * Pushes one or more functions onto the stack.  These will be run in sequence,
+ * interspersed with any recursive calls that they make.
+ *
+ * This method takes ownership of the given array!
+ *
+ * @param {Array} args Array of method calls structured as
+ *     [ method, arg1, arg2, method, arg1, arg2, ... ]
+ */
+JstProcessor.prototype.push_ = function(args) {
+  this.calls_.push(args);
+  this.queueIndices_.push(0);
+};
+
+
+/**
+ * Enable/disable debugging.
+ * @param {boolean} debugging New state
+ */
+JstProcessor.prototype.setDebugging = function(debugging) {
+  if (MAPS_DEBUG) {
+    this.debugging_ = debugging;
+  }
+};
+
+
+JstProcessor.prototype.createArray_ = function() {
+  if (this.arrayPool_.length) {
+    return this.arrayPool_.pop();
+  } else {
+    return [];
+  }
+};
+
+
+JstProcessor.prototype.recycleArray_ = function(array) {
+  arrayClear(array);
+  this.arrayPool_.push(array);
+};
+
+/**
+ * Implements internals of jstProcess. This processes the two
+ * attributes transclude and jsselect, which replace or multiply
+ * elements, hence the name "outer". The remainder of the attributes
+ * is processed in jstProcessInner_(), below. That function
+ * jsProcessInner_() only processes attributes that affect an existing
+ * node, but doesn't create or destroy nodes, hence the name
+ * "inner". jstProcessInner_() is called through jstSelect_() if there
+ * is a jsselect attribute (possibly for newly created clones of the
+ * current template node), or directly from here if there is none.
+ *
+ * @param {JsEvalContext} context
+ *
+ * @param {Element} template
+ */
+JstProcessor.prototype.jstProcessOuter_ = function(context, template) {
+  var me = this;
+
+  var jstAttributes = me.jstAttributes_(template);
+  if (MAPS_DEBUG && me.debugging_) {
+    me.logState_('Outer', template, jstAttributes.jstAttributeValues);
+  }
+
+  var transclude = jstAttributes[ATT_transclude];
+  if (transclude) {
+    var tr = jstGetTemplate(transclude);
+    if (tr) {
+      domReplaceChild(tr, template);
+      var call = me.createArray_();
+      call.push(me.jstProcessOuter_, context, tr);
+      me.push_(call);
+    } else {
+      domRemoveNode(template);
+    }
+    return;
+  }
+
+  var select = jstAttributes[ATT_select];
+  if (select) {
+    me.jstSelect_(context, template, select);
+  } else {
+    me.jstProcessInner_(context, template);
+  }
+};
+
+
+/**
+ * Implements internals of jstProcess. This processes all attributes
+ * except transclude and jsselect. It is called either from
+ * jstSelect_() for nodes that have a jsselect attribute so that the
+ * jsselect attribute will not be processed again, or else directly
+ * from jstProcessOuter_(). See the comment on jstProcessOuter_() for
+ * an explanation of the name.
+ *
+ * @param {JsEvalContext} context
+ *
+ * @param {Element} template
+ */
+JstProcessor.prototype.jstProcessInner_ = function(context, template) {
+  var me = this;
+
+  var jstAttributes = me.jstAttributes_(template);
+  if (MAPS_DEBUG && me.debugging_) {
+    me.logState_('Inner', template, jstAttributes.jstAttributeValues);
+  }
+
+  // NOTE(mesch): See NOTE on ATT_content why this is a separate
+  // attribute, and not a special value in ATT_values.
+  var display = jstAttributes[ATT_display];
+  if (display) {
+    var shouldDisplay = context.jsexec(display, template);
+    if (MAPS_DEBUG && me.debugging_) {
+      me.logs_.push(ATT_display + ': ' + shouldDisplay + '<br/>');
+    }
+    if (!shouldDisplay) {
+      displayNone(template);
+      return;
+    }
+    displayDefault(template);
+  }
+
+  // NOTE(mesch): jsvars is evaluated before jsvalues, because it's
+  // more useful to be able to use var values in attribute value
+  // expressions than vice versa.
+  var values = jstAttributes[ATT_vars];
+  if (values) {
+    me.jstVars_(context, template, values);
+  }
+
+  values = jstAttributes[ATT_values];
+  if (values) {
+    me.jstValues_(context, template, values);
+  }
+
+  // Evaluate expressions immediately. Useful for hooking callbacks
+  // into jstemplates.
+  //
+  // NOTE(mesch): Evaluation order is sometimes significant, e.g. when
+  // the expression evaluated in jseval relies on the values set in
+  // jsvalues, so it needs to be evaluated *after*
+  // jsvalues. TODO(mesch): This is quite arbitrary, it would be
+  // better if this would have more necessity to it.
+  var expressions = jstAttributes[ATT_eval];
+  if (expressions) {
+    for (var i = 0, I = jsLength(expressions); i < I; ++i) {
+      context.jsexec(expressions[i], template);
+    }
+  }
+
+  var skip = jstAttributes[ATT_skip];
+  if (skip) {
+    var shouldSkip = context.jsexec(skip, template);
+    if (MAPS_DEBUG && me.debugging_) {
+      me.logs_.push(ATT_skip + ': ' + shouldSkip + '<br/>');
+    }
+    if (shouldSkip) return;
+  }
+
+  // NOTE(mesch): content is a separate attribute, instead of just a
+  // special value mentioned in values, for two reasons: (1) it is
+  // fairly common to have only mapped content, and writing
+  // content="expr" is shorter than writing values="content:expr", and
+  // (2) the presence of content actually terminates traversal, and we
+  // need to check for that. Display is a separate attribute for a
+  // reason similar to the second, in that its presence *may*
+  // terminate traversal.
+  var content = jstAttributes[ATT_content];
+  if (content) {
+    me.jstContent_(context, template, content);
+
+  } else {
+    // Newly generated children should be ignored, so we explicitly
+    // store the children to be processed.
+    var queue = me.createArray_();
+    for (var c = template.firstChild; c; c = c.nextSibling) {
+      if (c.nodeType == DOM_ELEMENT_NODE) {
+        queue.push(me.jstProcessOuter_, context, c);
+      }
+    }
+    if (queue.length) me.push_(queue);
+  }
+};
+
+
+/**
+ * Implements the jsselect attribute: evalutes the value of the
+ * jsselect attribute in the current context, with the current
+ * variable bindings (see JsEvalContext.jseval()). If the value is an
+ * array, the current template node is multiplied once for every
+ * element in the array, with the array element being the context
+ * object. If the array is empty, or the value is undefined, then the
+ * current template node is dropped. If the value is not an array,
+ * then it is just made the context object.
+ *
+ * @param {JsEvalContext} context The current evaluation context.
+ *
+ * @param {Element} template The currently processed node of the template.
+ *
+ * @param {Function} select The javascript expression to evaluate.
+ *
+ * @notypecheck FIXME(hmitchell): See OCL6434950. instance and value need
+ * type checks.
+ */
+JstProcessor.prototype.jstSelect_ = function(context, template, select) {
+  var me = this;
+
+  var value = context.jsexec(select, template);
+
+  // Enable reprocessing: if this template is reprocessed, then only
+  // fill the section instance here. Otherwise do the cardinal
+  // processing of a new template.
+  var instance = domGetAttribute(template, ATT_instance);
+
+  var instanceLast = false;
+  if (instance) {
+    if (instance.charAt(0) == CHAR_asterisk) {
+      instance = parseInt10(instance.substr(1));
+      instanceLast = true;
+    } else {
+      instance = parseInt10(/** @type string */(instance));
+    }
+  }
+
+  // The expression value instanceof Array is occasionally false for
+  // arrays, seen in Firefox. Thus we recognize an array as an object
+  // which is not null that has a length property. Notice that this
+  // also matches input data with a length property, so this property
+  // name should be avoided in input data.
+  var multiple = isArray(value);
+  var count = multiple ? jsLength(value) : 1;
+  var multipleEmpty = (multiple && count == 0);
+
+  if (multiple) {
+    if (multipleEmpty) {
+      // For an empty array, keep the first template instance and mark
+      // it last. Remove all other template instances.
+      if (!instance) {
+        domSetAttribute(template, ATT_instance, STRING_asteriskzero);
+        displayNone(template);
+      } else {
+        domRemoveNode(template);
+      }
+
+    } else {
+      displayDefault(template);
+      // For a non empty array, create as many template instances as
+      // are needed. If the template is first processed, as many
+      // template instances are needed as there are values in the
+      // array. If the template is reprocessed, new template instances
+      // are only needed if there are more array values than template
+      // instances. Those additional instances are created by
+      // replicating the last template instance.
+      //
+      // When the template is first processed, there is no jsinstance
+      // attribute. This is indicated by instance === null, except in
+      // opera it is instance === "". Notice also that the === is
+      // essential, because 0 == "", presumably via type coercion to
+      // boolean.
+      if (instance === null || instance === STRING_empty ||
+          (instanceLast && instance < count - 1)) {
+        // A queue of calls to push.
+        var queue = me.createArray_();
+
+        var instancesStart = instance || 0;
+        var i, I, clone;
+        for (i = instancesStart, I = count - 1; i < I; ++i) {
+          var node = domCloneNode(template);
+          domInsertBefore(node, template);
+
+          jstSetInstance(/** @type Element */(node), value, i);
+          clone = context.clone(value[i], i, count);
+
+          queue.push(me.jstProcessInner_, clone, node,
+                     JsEvalContext.recycle, clone, null);
+                     
+        }
+        // Push the originally present template instance last to keep
+        // the order aligned with the DOM order, because the newly
+        // created template instances are inserted *before* the
+        // original instance.
+        jstSetInstance(template, value, i);
+        clone = context.clone(value[i], i, count);
+        queue.push(me.jstProcessInner_, clone, template,
+                   JsEvalContext.recycle, clone, null);
+        me.push_(queue);
+      } else if (instance < count) {
+        var v = value[instance];
+
+        jstSetInstance(template, value, instance);
+        var clone = context.clone(v, instance, count);
+        var queue = me.createArray_();
+        queue.push(me.jstProcessInner_, clone, template,
+                   JsEvalContext.recycle, clone, null);
+        me.push_(queue);
+      } else {
+        domRemoveNode(template);
+      }
+    }
+  } else {
+    if (value == null) {
+      displayNone(template);
+    } else {
+      displayDefault(template);
+      var clone = context.clone(value, 0, 1);
+      var queue = me.createArray_();
+      queue.push(me.jstProcessInner_, clone, template,
+                 JsEvalContext.recycle, clone, null);
+      me.push_(queue);
+    }
+  }
+};
+
+
+/**
+ * Implements the jsvars attribute: evaluates each of the values and
+ * assigns them to variables in the current context. Similar to
+ * jsvalues, except that all values are treated as vars, independent
+ * of their names.
+ *
+ * @param {JsEvalContext} context Current evaluation context.
+ *
+ * @param {Element} template Currently processed template node.
+ *
+ * @param {Array} values Processed value of the jsvalues attribute: a
+ * flattened array of pairs. The second element in the pair is a
+ * function that can be passed to jsexec() for evaluation in the
+ * current jscontext, and the first element is the variable name that
+ * the value returned by jsexec is assigned to.
+ */
+JstProcessor.prototype.jstVars_ = function(context, template, values) {
+  for (var i = 0, I = jsLength(values); i < I; i += 2) {
+    var label = values[i];
+    var value = context.jsexec(values[i+1], template);
+    context.setVariable(label, value);
+  }
+};
+
+
+/**
+ * Implements the jsvalues attribute: evaluates each of the values and
+ * assigns them to variables in the current context (if the name
+ * starts with '$', javascript properties of the current template node
+ * (if the name starts with '.'), or DOM attributes of the current
+ * template node (otherwise). Since DOM attribute values are always
+ * strings, the value is coerced to string in the latter case,
+ * otherwise it's the uncoerced javascript value.
+ *
+ * @param {JsEvalContext} context Current evaluation context.
+ *
+ * @param {Element} template Currently processed template node.
+ *
+ * @param {Array} values Processed value of the jsvalues attribute: a
+ * flattened array of pairs. The second element in the pair is a
+ * function that can be passed to jsexec() for evaluation in the
+ * current jscontext, and the first element is the label that
+ * determines where the value returned by jsexec is assigned to.
+ */
+JstProcessor.prototype.jstValues_ = function(context, template, values) {
+  for (var i = 0, I = jsLength(values); i < I; i += 2) {
+    var label = values[i];
+    var value = context.jsexec(values[i+1], template);
+
+    if (label.charAt(0) == CHAR_dollar) {
+      // A jsvalues entry whose name starts with $ sets a local
+      // variable.
+      context.setVariable(label, value);
+
+    } else if (label.charAt(0) == CHAR_period) {
+      // A jsvalues entry whose name starts with . sets a property of
+      // the current template node. The name may have further dot
+      // separated components, which are translated into namespace
+      // objects. This specifically allows to set properties on .style
+      // using jsvalues. NOTE(mesch): Setting the style attribute has
+      // no effect in IE and hence should not be done anyway.
+      var nameSpaceLabel = label.substr(1).split(CHAR_period);
+      var nameSpaceObject = template;
+      var nameSpaceDepth = jsLength(nameSpaceLabel);
+      for (var j = 0, J = nameSpaceDepth - 1; j < J; ++j) {
+        var jLabel = nameSpaceLabel[j];
+        if (!nameSpaceObject[jLabel]) {
+          nameSpaceObject[jLabel] = {};
+        }
+        nameSpaceObject = nameSpaceObject[jLabel];
+      }
+      nameSpaceObject[nameSpaceLabel[nameSpaceDepth - 1]] = value;
+
+    } else if (label) {
+      // Any other jsvalues entry sets an attribute of the current
+      // template node.
+      if (typeof value == TYPE_boolean) {
+        // Handle boolean values that are set as attributes specially,
+        // according to the XML/HTML convention.
+        if (value) {
+          domSetAttribute(template, label, label);
+        } else {
+          domRemoveAttribute(template, label);
+        }
+      } else {
+        domSetAttribute(template, label, STRING_empty + value);
+      }
+    }
+  }
+};
+
+
+/**
+ * Implements the jscontent attribute. Evalutes the expression in
+ * jscontent in the current context and with the current variables,
+ * and assigns its string value to the content of the current template
+ * node.
+ *
+ * @param {JsEvalContext} context Current evaluation context.
+ *
+ * @param {Element} template Currently processed template node.
+ *
+ * @param {Function} content Processed value of the jscontent
+ * attribute.
+ */
+JstProcessor.prototype.jstContent_ = function(context, template, content) {
+  // NOTE(mesch): Profiling shows that this method costs significant
+  // time. In jstemplate_perf.html, it's about 50%. I tried to replace
+  // by HTML escaping and assignment to innerHTML, but that was even
+  // slower.
+  var value = STRING_empty + context.jsexec(content, template);
+  // Prevent flicker when refreshing a template and the value doesn't
+  // change.
+  if (template.innerHTML == value) {
+    return;
+  }
+  while (template.firstChild) {
+    domRemoveNode(template.firstChild);
+  }
+  var t = domCreateTextNode(this.document_, value);
+  domAppendChild(template, t);
+};
+
+
+/**
+ * Caches access to and parsing of template processing attributes. If
+ * domGetAttribute() is called every time a template attribute value
+ * is used, it takes more than 10% of the time.
+ *
+ * @param {Element} template A DOM element node of the template.
+ *
+ * @return {Object} A javascript object that has all js template
+ * processing attribute values of the node as properties.
+ */
+JstProcessor.prototype.jstAttributes_ = function(template) {
+  if (template[PROP_jstcache]) {
+    return template[PROP_jstcache];
+  }
+
+  var jstid = domGetAttribute(template, ATT_jstcache);
+  if (jstid) {
+    return template[PROP_jstcache] = JstProcessor.jstcache_[jstid];
+  }
+
+  return JstProcessor.prepareNode_(template);
+};
+
+
+/**
+ * Helps to implement the transclude attribute, and is the initial
+ * call to get hold of a template from its ID.
+ *
+ * If the ID is not present in the DOM, and opt_loadHtmlFn is specified, this
+ * function will call that function and add the result to the DOM, before
+ * returning the template.
+ *
+ * @param {string} name The ID of the HTML element used as template.
+ * @param {Function} opt_loadHtmlFn A function which, when called, will return
+ *   HTML that contains an element whose ID is 'name'.
+ *
+ * @return {Element|null} The DOM node of the template. (Only element nodes
+ * can be found by ID, hence it's a Element.)
+ */
+function jstGetTemplate(name, opt_loadHtmlFn) {
+  var doc = document;
+  var section;
+  if (opt_loadHtmlFn) {
+    section = jstLoadTemplateIfNotPresent(doc, name, opt_loadHtmlFn);
+  } else {
+    section = domGetElementById(doc, name);
+  }
+  if (section) {
+    JstProcessor.prepareTemplate_(section);
+    var ret = domCloneElement(section);
+    domRemoveAttribute(ret, STRING_id);
+    return ret;
+  } else {
+    return null;
+  }
+}
+
+/**
+ * This function is the same as 'jstGetTemplate' but, if the template
+ * does not exist, throw an exception.
+ *
+ * @param {string} name The ID of the HTML element used as template.
+ * @param {Function} opt_loadHtmlFn A function which, when called, will return
+ *   HTML that contains an element whose ID is 'name'.
+ *
+ * @return {Element} The DOM node of the template. (Only element nodes
+ * can be found by ID, hence it's a Element.)
+ */
+function jstGetTemplateOrDie(name, opt_loadHtmlFn) {
+  var x = jstGetTemplate(name, opt_loadHtmlFn);
+  check(x !== null);
+  return /** @type Element */(x);
+}
+
+
+/**
+ * If an element with id 'name' is not present in the document, call loadHtmlFn
+ * and insert the result into the DOM.
+ *
+ * @param {Document} doc
+ * @param {string} name
+ * @param {Function} loadHtmlFn A function that returns HTML to be inserted
+ * into the DOM.
+ * @param {string} opt_target The id of a DOM object under which to attach the
+ *   HTML once it's inserted.  An object with this id is created if it does not
+ *   exist.
+ * @return {Element} The node whose id is 'name'
+ */
+function jstLoadTemplateIfNotPresent(doc, name, loadHtmlFn, opt_target) {
+  var section = domGetElementById(doc, name);
+  if (section) {
+    return section;
+  }
+  // Load any necessary HTML and try again.
+  jstLoadTemplate_(doc, loadHtmlFn(), opt_target || STRING_jsts);
+  var section = domGetElementById(doc, name);
+  if (!section) {
+    log("Error: jstGetTemplate was provided with opt_loadHtmlFn, " +
+	"but that function did not provide the id '" + name + "'.");
+  }
+  return /** @type Element */(section);
+}
+
+
+/**
+ * Loads the given HTML text into the given document, so that
+ * jstGetTemplate can find it.
+ *
+ * We append it to the element identified by targetId, which is hidden.
+ * If it doesn't exist, it is created.
+ *
+ * @param {Document} doc The document to create the template in.
+ *
+ * @param {string} html HTML text to be inserted into the document.
+ *
+ * @param {string} targetId The id of a DOM object under which to attach the
+ *   HTML once it's inserted.  An object with this id is created if it does not
+ *   exist.
+ */
+function jstLoadTemplate_(doc, html, targetId) {
+  var existing_target = domGetElementById(doc, targetId);
+  var target;
+  if (!existing_target) {
+    target = domCreateElement(doc, STRING_div);
+    target.id = targetId;
+    displayNone(target);
+    positionAbsolute(target);
+    domAppendChild(doc.body, target);
+  } else {
+    target = existing_target;
+  }
+  var div = domCreateElement(doc, STRING_div);
+  target.appendChild(div);
+  div.innerHTML = html;
+}
+
+
+/**
+ * Sets the jsinstance attribute on a node according to its context.
+ *
+ * @param {Element} template The template DOM node to set the instance
+ * attribute on.
+ *
+ * @param {Array} values The current input context, the array of
+ * values of which the template node will render one instance.
+ *
+ * @param {number} index The index of this template node in values.
+ */
+function jstSetInstance(template, values, index) {
+  if (index == jsLength(values) - 1) {
+    domSetAttribute(template, ATT_instance, CHAR_asterisk + index);
+  } else {
+    domSetAttribute(template, ATT_instance, STRING_empty + index);
+  }
+}
+
+
+/**
+ * Log the current state.
+ * @param {string} caller An identifier for the caller of .log_.
+ * @param {Element} template The template node being processed.
+ * @param {Object} jstAttributeValues The jst attributes of the template node.
+ */
+JstProcessor.prototype.logState_ = function(
+    caller, template, jstAttributeValues) {
+  if (MAPS_DEBUG) {
+    var msg = '<table>';
+    msg += '<caption>' + caller + '</caption>';
+    msg += '<tbody>';
+    if (template.id) {
+      msg += '<tr><td>' + 'id:' + '</td><td>' + template.id + '</td></tr>';
+    }
+    if (template.name) {
+      msg += '<tr><td>' + 'name:' + '</td><td>' + template.name + '</td></tr>';
+    }
+    if (jstAttributeValues) {
+      msg += '<tr><td>' + 'attr:' +
+      '</td><td>' + jsToSource(jstAttributeValues) + '</td></tr>';
+    }
+    msg += '</tbody></table><br/>';
+    this.logs_.push(msg);
+  }
+};
+
+
+/**
+ * Retrieve the processing logs.
+ * @return {Array.<string>} The processing logs.
+ */
+JstProcessor.prototype.getLogs = function() {
+  return this.logs_;
+};
+
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate_test.js b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate_test.js
index b9653e1..c6aadb3 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate_test.js
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/jstemplate_test.js
@@ -1,357 +1,357 @@
-// Copyright 2006 Google Inc.

-//

-// 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.

-/**

- * @author Steffen Meschkat (mesch@google.com)

- * @fileoverview Unittest and examples for jstemplates.

- */

-

-function jstWrap(data, template) {

-  return jstProcess(new JsEvalContext(data), template);

-}

-

-function testJstSelect() {

-  // Template cardinality from jsselect.

-  var t = document.getElementById('t1');

-  var d = {

-    items: [ 'A', 'B', 'C', '' ]

-  }

-  jstWrap(d, t);

-

-  var h = t.innerHTML;

-  var clone = domCloneNode(t);

-  assertTrue(/>A<\/div>/.test(h));

-  assertTrue(/>B<\/div>/.test(h));

-  assertTrue(/>C<\/div>/.test(h));

-  assertTrue(/><\/div>/.test(h));

-

-  // Reprocessing with identical data.

-  jstWrap(d, t);

-  assertAttributesMatch(t, clone);

-

-  // Reprocessing with changed data.

-  d.items[1] = 'BB';

-  jstWrap(d, t);

-

-  h = t.innerHTML;

-  assertTrue(/>A<\/div>/.test(h));

-  assertFalse(/>B<\/div>/.test(h));

-  assertTrue(/>BB<\/div>/.test(h));

-  assertTrue(/>C<\/div>/.test(h));

-

-  // Reprocessing with dropped data.

-  d.items.pop();

-  d.items.pop();

-  jstWrap(d, t);

-  h = t.innerHTML;

-  assertTrue(/>A<\/div>/.test(h));

-  assertTrue(/>BB<\/div>/.test(h));

-  assertFalse(/>C<\/div>/.test(h));

-  assertFalse(/><\/div>/.test(h));

-

-  // Reprocessing with dropped data, once more.

-  d.items.pop();

-  jstWrap(d, t);

-  h = t.innerHTML;

-  assertTrue(/>A<\/div>/.test(h));

-  assertFalse(/>BB<\/div>/.test(h));

-  assertFalse(/>C<\/div>/.test(h));

-

-  // Reprocessing with empty data -- the last template instance is

-  // preserved, and only hidden.

-  d.items.pop();

-  jstWrap(d, t);

-

-  assertTrue(/>A<\/div>/.test(h));

-  assertFalse(/>BB<\/div>/.test(h));

-  assertFalse(/>C<\/div>/.test(h));

-

-  // Reprocessing with added data.

-  d.items.push('D');

-  jstWrap(d, t);

-  h = t.innerHTML;

-  assertFalse(/>A<\/div>/.test(h));

-  assertTrue(/>D<\/div>/.test(h));

-}

-

-function testJstDisplay() {

-  var t = document.getElementById('t2');

-  var d = {

-    display: true

-  }

-  jstWrap(d, t);

-

-  var h = t.innerHTML;

-  assertFalse(/display:\s*none/.test(h));

-

-  d.display = false;

-  jstWrap(d, t);

-

-  h = t.innerHTML;

-  assertTrue(/display:\s*none/.test(h));

-

-  // Check that 'this' within js expressions is the template node

-  t = document.getElementById('t2a');

-  d = {

-    showId: 'x'

-  };

-  jstWrap(d, t);

-

-  h = t.innerHTML;

-  assertFalse(/display:\s*none/.test(h));

-

-  d.showId = 'y';

-  jstWrap(d, t);

-

-  h = t.innerHTML;

-  assertTrue(/display:\s*none/.test(h));

-}

-

-function stringContains(str, sub) {

-  return str.indexOf(sub) != -1;

-}

-

-function testJseval() {

-  var data = {};

-

-  var counter = 0;

-  var ctx = new JsEvalContext(data);

-  ctx.setVariable("callback1", function() {

-    ++counter;

-  });

-  ctx.setVariable("callback2", function() {

-    counter *= 2;

-  });

-

-  jstProcess(ctx, document.getElementById('testJseval1'));

-  assertEquals("testJseval1", 1, counter);

-

-  jstProcess(ctx, document.getElementById('testJseval2'));

-  assertEquals("testJseval2", 4, counter);

-}

-

-function testJstValues() {

-  var t = document.getElementById('t3');

-  var d = {};

-  jstWrap(d, t);

-  var h = t.innerHTML;

-  assertTrue(stringContains(h, 'http://maps.google.com/'));

-  var t3a = document.getElementById('t3a');

-  assertEquals('http://maps.google.com/', t3a.foo.bar.baz);

-  assertEquals('http://maps.google.com/', t3a.bar);

-  assertEquals('red', t3a.style.backgroundColor);

-}

-

-function testJstTransclude() {

-  var t = document.getElementById('t4');

-  var p = document.getElementById('parent');

-  var d = {};

-  jstWrap(d, t);

-  var h = p.innerHTML;

-  assertTrue(h, stringContains(h, 'http://maps.google.com/'));

-}

-

-function assertAttributesMatch(first, second) {

-  assertEquals('assertAttributesMatch: number of child nodes',

-               jsLength(first.childNodes), jsLength(second.childNodes));

-  var b = second.firstChild;

-  for (var a = first.firstChild; a; a = a.nextSibling) {

-    var att = a.attributes;

-    if (att) {

-      assertTrue(b.attributes != null);

-      assertEquals('assertAttributesMatch: number of attribute nodes',

-                   att.length, b.attributes.length);

-      for (var i = 0; i < jsLength(att); i++) {

-        var a = att[i];

-        assertEquals('assertAttributesMatch: value of attribute ' + a.name,

-                     a.value, b.getAttribute(a.name));

-      }

-    } else {

-      assertNull(b.attributes);

-    }

-    b = b.nextSibling;

-  }

-}

-

-function testJsskip() {

-  var div = domCreateElement(document, "DIV");

-  div.innerHTML = [

-      '<div jseval="outercallback()" jsskip="1">',

-      '<div jseval="innercallback()">',

-      '</div>',

-      '</div>'

-  ].join('');

-

-  var data = {};

-  var ctx = new JsEvalContext(data);

-  var outerCalled = false;

-  ctx.setVariable("outercallback", function() {

-    outerCalled = true;

-  });

-  var innerCalled = false;

-  ctx.setVariable("innercallback", function() {

-    innerCalled = true;

-  });

-  jstProcess(ctx, div);

-

-  assertTrue(outerCalled);

-  assertFalse(innerCalled);

-}

-

-function testScalarContext() {

-  var t = document.getElementById('testScalarContext');

-

-  jstWrap(true, t);

-  assertTrue(/>true</.test(t.innerHTML));

-

-  jstWrap(false, t);

-  assertTrue(/>false</.test(t.innerHTML));

-

-  jstWrap(0, t);

-  assertTrue(/>0</.test(t.innerHTML));

-

-  jstWrap("foo", t);

-  assertTrue(/>foo</.test(t.innerHTML));

-

-  jstWrap(undefined, t);

-  assertTrue(/>undefined</.test(t.innerHTML));

-

-  jstWrap(null, t);

-  assertTrue(/>null</.test(t.innerHTML));

-}

-

-function testJstLoadTemplate() {

-  var wrapperId = 'testJstLoadTemplateWrapper';

-  var id = 'testJstLoadTemplate';

-  jstLoadTemplate_(document, '<div id="' + id + '">content</div>', wrapperId);

-  var wrapperElem = document.getElementById(wrapperId);

-  assertTrue('Expected wrapper element to be in document',

-             !!wrapperElem);

-  var newTemplate = document.getElementById(id);

-  assertTrue('Expected newly loaded template to be in document',

-             !!newTemplate);

-  assertTrue('Expected wrapper to be grandparent of template',

-             newTemplate.parentNode.parentNode == wrapperElem);

-

-  // Make sure the next template loaded with the same wrapper id re-uses the

-  // wrapper element.

-  var id2 = 'testJstLoadTemplate2';

-  jstLoadTemplate_(document, '<div id="' + id2 + '">content</div>', wrapperId);

-  var newTemplate2 = document.getElementById(id2);

-  assertTrue('Expected newly loaded template to be in document',

-             !!newTemplate2);

-  assertTrue('Expected wrapper to be grandparent of template',

-             newTemplate2.parentNode.parentNode == wrapperElem);

-}

-

-function testJstGetTemplateFromDom() {

-  var element;

-  // Get by id a template in the document

-  // Success

-  element = jstGetTemplate('t1');

-  assertTrue("Asserted jstGetTemplate('t1') to return a dom element",

-             !!element);

-  // Failure

-  element = jstGetTemplate('asdf');

-  assertFalse("Asserted jstGetTemplate('asdf') to return null",

-              !!element);

-}

-

-function testJstGetTemplateFromFunction() {

-  var element;

-  // Fetch a jstemplate by id from within a html string, passed via a function.

-  function returnHtmlWithId(id) {

-    var html =

-        '<div>' +

-        '<div id="' + id + '">Here is the template</div>' +

-        '</div>';

-    return html;

-  }

-  // Success

-  element = jstGetTemplate('template',

-                           partial(returnHtmlWithId, 'template'));

-  assertTrue("Expected jstGetTemplate('template') to return a dom element",

-             !!element);

-

-  // Failure

-  element = jstGetTemplate('asdf',

-                           partial(returnHtmlWithId, 'zxcv'));

-  assertFalse("Expected jstGetTemplate('zxcv') to return null",

-              !!element);

-}

-

-function testPrepareNode() {

-  var id, node;

-  // Reset the cache so we're testing from a known state.

-  JstProcessor.jstCache_ = {};

-  JstProcessor.jstCache_[0] = {};

-

-  // Skip pre-processed nodes.  Preprocessed nodes are those with a

-  // PROP_jstcache property.

-  var t = document.getElementById('t1');

-  var caches = [];

-  caches.push(JstProcessor.prepareNode_(t));

-  caches.push(JstProcessor.prepareNode_(t));

-  assertEquals('The same cache should be returned on each call to prepareNode',

-               caches[0], caches[1]);

-

-  // Preprocessing a node with a jst attribute should return a valid struct

-  id = 'testPrepareNodeWithAttributes';

-  jstLoadTemplate_(document, '<div id="' + id + '" jsskip="1"></div>');

-  node = document.getElementById(id);

-  var cache = JstProcessor.prepareNode_(node);

-  try {

-    var jsskip = cache['jsskip']({}, {});

-  } catch (e) {

-    fail('Exception when evaluating jsskip from cache');

-  }

-  assertEquals(1, jsskip);

-}

-

-

-function testPrepareNodeWithNoAttributes() {

-  // Preprocessing a node with no jst attributes should return null

-  var id = 'testPrepareNodeNoAttributes';

-  jstLoadTemplate_(document, '<div id="' + id + '"></div>');

-  var node = document.getElementById(id);

-  assertEquals('prepareNode with no jst attributes should return default',

-               JstProcessor.jstcache_[0], JstProcessor.prepareNode_(node));

-}

-

-

-function testJsVars() {

-  var template = document.createElement('div');

-  document.body.appendChild(template);

-  template.innerHTML = '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>';

-

-  var context = new JsEvalContext;

-  jstProcess(context, template);

-

-  assertEquals('foo', context.getVariable('foo'));

-  assertEquals(1, context.getVariable('$baz'));

-  assertTrue(context.getVariable('bar'));

-  assertUndefined(context.getVariable('foobar'));

-}

-

-

-function testCacheReuse() {

-  var template = document.createElement('div');

-  document.body.appendChild(template);

-  template.innerHTML = 

-    '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>' +

-    '<span jsvars="foo:\'foo\';bar:true;$baz:1"></span>';

-  JstProcessor.prepareTemplate_(template);

-  assertEquals(template.firstChild.getAttribute(ATT_jstcache),

-               template.lastChild.getAttribute(ATT_jstcache));

-}

-

+// Copyright 2006 Google Inc.
+//
+// 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.
+/**
+ * @author Steffen Meschkat (mesch@google.com)
+ * @fileoverview Unittest and examples for jstemplates.
+ */
+
+function jstWrap(data, template) {
+  return jstProcess(new JsEvalContext(data), template);
+}
+
+function testJstSelect() {
+  // Template cardinality from jsselect.
+  var t = document.getElementById('t1');
+  var d = {
+    items: [ 'A', 'B', 'C', '' ]
+  }
+  jstWrap(d, t);
+
+  var h = t.innerHTML;
+  var clone = domCloneNode(t);
+  assertTrue(/>A<\/div>/.test(h));
+  assertTrue(/>B<\/div>/.test(h));
+  assertTrue(/>C<\/div>/.test(h));
+  assertTrue(/><\/div>/.test(h));
+
+  // Reprocessing with identical data.
+  jstWrap(d, t);
+  assertAttributesMatch(t, clone);
+
+  // Reprocessing with changed data.
+  d.items[1] = 'BB';
+  jstWrap(d, t);
+
+  h = t.innerHTML;
+  assertTrue(/>A<\/div>/.test(h));
+  assertFalse(/>B<\/div>/.test(h));
+  assertTrue(/>BB<\/div>/.test(h));
+  assertTrue(/>C<\/div>/.test(h));
+
+  // Reprocessing with dropped data.
+  d.items.pop();
+  d.items.pop();
+  jstWrap(d, t);
+  h = t.innerHTML;
+  assertTrue(/>A<\/div>/.test(h));
+  assertTrue(/>BB<\/div>/.test(h));
+  assertFalse(/>C<\/div>/.test(h));
+  assertFalse(/><\/div>/.test(h));
+
+  // Reprocessing with dropped data, once more.
+  d.items.pop();
+  jstWrap(d, t);
+  h = t.innerHTML;
+  assertTrue(/>A<\/div>/.test(h));
+  assertFalse(/>BB<\/div>/.test(h));
+  assertFalse(/>C<\/div>/.test(h));
+
+  // Reprocessing with empty data -- the last template instance is
+  // preserved, and only hidden.
+  d.items.pop();
+  jstWrap(d, t);
+
+  assertTrue(/>A<\/div>/.test(h));
+  assertFalse(/>BB<\/div>/.test(h));
+  assertFalse(/>C<\/div>/.test(h));
+
+  // Reprocessing with added data.
+  d.items.push('D');
+  jstWrap(d, t);
+  h = t.innerHTML;
+  assertFalse(/>A<\/div>/.test(h));
+  assertTrue(/>D<\/div>/.test(h));
+}
+
+function testJstDisplay() {
+  var t = document.getElementById('t2');
+  var d = {
+    display: true
+  }
+  jstWrap(d, t);
+
+  var h = t.innerHTML;
+  assertFalse(/display:\s*none/.test(h));
+
+  d.display = false;
+  jstWrap(d, t);
+
+  h = t.innerHTML;
+  assertTrue(/display:\s*none/.test(h));
+
+  // Check that 'this' within js expressions is the template node
+  t = document.getElementById('t2a');
+  d = {
+    showId: 'x'
+  };
+  jstWrap(d, t);
+
+  h = t.innerHTML;
+  assertFalse(/display:\s*none/.test(h));
+
+  d.showId = 'y';
+  jstWrap(d, t);
+
+  h = t.innerHTML;
+  assertTrue(/display:\s*none/.test(h));
+}
+
+function stringContains(str, sub) {
+  return str.indexOf(sub) != -1;
+}
+
+function testJseval() {
+  var data = {};
+
+  var counter = 0;
+  var ctx = new JsEvalContext(data);
+  ctx.setVariable("callback1", function() {
+    ++counter;
+  });
+  ctx.setVariable("callback2", function() {
+    counter *= 2;
+  });
+
+  jstProcess(ctx, document.getElementById('testJseval1'));
+  assertEquals("testJseval1", 1, counter);
+
+  jstProcess(ctx, document.getElementById('testJseval2'));
+  assertEquals("testJseval2", 4, counter);
+}
+
+function testJstValues() {
+  var t = document.getElementById('t3');
+  var d = {};
+  jstWrap(d, t);
+  var h = t.innerHTML;
+  assertTrue(stringContains(h, 'http://maps.google.com/'));
+  var t3a = document.getElementById('t3a');
+  assertEquals('http://maps.google.com/', t3a.foo.bar.baz);
+  assertEquals('http://maps.google.com/', t3a.bar);
+  assertEquals('red', t3a.style.backgroundColor);
+}
+
+function testJstTransclude() {
+  var t = document.getElementById('t4');
+  var p = document.getElementById('parent');
+  var d = {};
+  jstWrap(d, t);
+  var h = p.innerHTML;
+  assertTrue(h, stringContains(h, 'http://maps.google.com/'));
+}
+
+function assertAttributesMatch(first, second) {
+  assertEquals('assertAttributesMatch: number of child nodes',
+               jsLength(first.childNodes), jsLength(second.childNodes));
+  var b = second.firstChild;
+  for (var a = first.firstChild; a; a = a.nextSibling) {
+    var att = a.attributes;
+    if (att) {
+      assertTrue(b.attributes != null);
+      assertEquals('assertAttributesMatch: number of attribute nodes',
+                   att.length, b.attributes.length);
+      for (var i = 0; i < jsLength(att); i++) {
+        var a = att[i];
+        assertEquals('assertAttributesMatch: value of attribute ' + a.name,
+                     a.value, b.getAttribute(a.name));
+      }
+    } else {
+      assertNull(b.attributes);
+    }
+    b = b.nextSibling;
+  }
+}
+
+function testJsskip() {
+  var div = domCreateElement(document, "DIV");
+  div.innerHTML = [
+      '<div jseval="outercallback()" jsskip="1">',
+      '<div jseval="innercallback()">',
+      '</div>',
+      '</div>'
+  ].join('');
+
+  var data = {};
+  var ctx = new JsEvalContext(data);
+  var outerCalled = false;
+  ctx.setVariable("outercallback", function() {
+    outerCalled = true;
+  });
+  var innerCalled = false;
+  ctx.setVariable("innercallback", function() {
+    innerCalled = true;
+  });
+  jstProcess(ctx, div);
+
+  assertTrue(outerCalled);
+  assertFalse(innerCalled);
+}
+
+function testScalarContext() {
+  var t = document.getElementById('testScalarContext');
+
+  jstWrap(true, t);
+  assertTrue(/>true</.test(t.innerHTML));
+
+  jstWrap(false, t);
+  assertTrue(/>false</.test(t.innerHTML));
+
+  jstWrap(0, t);
+  assertTrue(/>0</.test(t.innerHTML));
+
+  jstWrap("foo", t);
+  assertTrue(/>foo</.test(t.innerHTML));
+
+  jstWrap(undefined, t);
+  assertTrue(/>undefined</.test(t.innerHTML));
+
+  jstWrap(null, t);
+  assertTrue(/>null</.test(t.innerHTML));
+}
+
+function testJstLoadTemplate() {
+  var wrapperId = 'testJstLoadTemplateWrapper';
+  var id = 'testJstLoadTemplate';
+  jstLoadTemplate_(document, '<div id="' + id + '">content</div>', wrapperId);
+  var wrapperElem = document.getElementById(wrapperId);
+  assertTrue('Expected wrapper element to be in document',
+             !!wrapperElem);
+  var newTemplate = document.getElementById(id);
+  assertTrue('Expected newly loaded template to be in document',
+             !!newTemplate);
+  assertTrue('Expected wrapper to be grandparent of template',
+             newTemplate.parentNode.parentNode == wrapperElem);
+
+  // Make sure the next template loaded with the same wrapper id re-uses the
+  // wrapper element.
+  var id2 = 'testJstLoadTemplate2';
+  jstLoadTemplate_(document, '<div id="' + id2 + '">content</div>', wrapperId);
+  var newTemplate2 = document.getElementById(id2);
+  assertTrue('Expected newly loaded template to be in document',
+             !!newTemplate2);
+  assertTrue('Expected wrapper to be grandparent of template',
+             newTemplate2.parentNode.parentNode == wrapperElem);
+}
+
+function testJstGetTemplateFromDom() {
+  var element;
+  // Get by id a template in the document
+  // Success
+  element = jstGetTemplate('t1');
+  assertTrue("Asserted jstGetTemplate('t1') to return a dom element",
+             !!element);
+  // Failure
+  element = jstGetTemplate('asdf');
+  assertFalse("Asserted jstGetTemplate('asdf') to return null",
+              !!element);
+}
+
+function testJstGetTemplateFromFunction() {
+  var element;
+  // Fetch a jstemplate by id from within a html string, passed via a function.
+  function returnHtmlWithId(id) {
+    var html =
+        '<div>' +
+        '<div id="' + id + '">Here is the template</div>' +
+        '</div>';
+    return html;
+  }
+  // Success
+  element = jstGetTemplate('template',
+                           partial(returnHtmlWithId, 'template'));
+  assertTrue("Expected jstGetTemplate('template') to return a dom element",
+             !!element);
+
+  // Failure
+  element = jstGetTemplate('asdf',
+                           partial(returnHtmlWithId, 'zxcv'));
+  assertFalse("Expected jstGetTemplate('zxcv') to return null",
+              !!element);
+}
+
+function testPrepareNode() {
+  var id, node;
+  // Reset the cache so we're testing from a known state.
+  JstProcessor.jstCache_ = {};
+  JstProcessor.jstCache_[0] = {};
+
+  // Skip pre-processed nodes.  Preprocessed nodes are those with a
+  // PROP_jstcache property.
+  var t = document.getElementById('t1');
+  var caches = [];
+  caches.push(JstProcessor.prepareNode_(t));
+  caches.push(JstProcessor.prepareNode_(t));
+  assertEquals('The same cache should be returned on each call to prepareNode',
+               caches[0], caches[1]);
+
+  // Preprocessing a node with a jst attribute should return a valid struct
+  id = 'testPrepareNodeWithAttributes';
+  jstLoadTemplate_(document, '<div id="' + id + '" jsskip="1"></div>');
+  node = document.getElementById(id);
+  var cache = JstProcessor.prepareNode_(node);
+  try {
+    var jsskip = cache['jsskip']({}, {});
+  } catch (e) {
+    fail('Exception when evaluating jsskip from cache');
+  }
+  assertEquals(1, jsskip);
+}
+
+
+function testPrepareNodeWithNoAttributes() {
+  // Preprocessing a node with no jst attributes should return null
+  var id = 'testPrepareNodeNoAttributes';
+  jstLoadTemplate_(document, '<div id="' + id + '"></div>');
+  var node = document.getElementById(id);
+  assertEquals('prepareNode with no jst attributes should return default',
+               JstProcessor.jstcache_[0], JstProcessor.prepareNode_(node));
+}
+
+
+function testJsVars() {
+  var template = document.createElement('div');
+  document.body.appendChild(template);
+  template.innerHTML = '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>';
+
+  var context = new JsEvalContext;
+  jstProcess(context, template);
+
+  assertEquals('foo', context.getVariable('foo'));
+  assertEquals(1, context.getVariable('$baz'));
+  assertTrue(context.getVariable('bar'));
+  assertUndefined(context.getVariable('foobar'));
+}
+
+
+function testCacheReuse() {
+  var template = document.createElement('div');
+  document.body.appendChild(template);
+  template.innerHTML = 
+    '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>' +
+    '<span jsvars="foo:\'foo\';bar:true;$baz:1"></span>';
+  JstProcessor.prepareTemplate_(template);
+  assertEquals(template.firstChild.getAttribute(ATT_jstcache),
+               template.lastChild.getAttribute(ATT_jstcache));
+}
+
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/util.js b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/util.js
index 570c71f..9b45411 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/jst/util.js
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/jst/util.js
@@ -1,471 +1,471 @@
-// Copyright 2006 Google Inc.

-//

-// 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.

-/**

- * @fileoverview Miscellaneous constants and functions referenced in

- * the main source files.

- *

- * @author Steffen Meschkat (mesch@google.com)

- */

-

-var MAPS_DEBUG = false;

-

-function log(msg) {}

-

-// String literals defined globally and not to be inlined. (IE6 perf)

-/** @const */ var STRING_empty = '';

-

-/** @const */ var CSS_display = 'display';

-/** @const */ var CSS_position = 'position';

-

-// Constants for possible values of the typeof operator.

-var TYPE_boolean = 'boolean';

-var TYPE_number = 'number';

-var TYPE_object = 'object';

-var TYPE_string = 'string';

-var TYPE_function = 'function';

-var TYPE_undefined = 'undefined';

-

-

-/**

- * Wrapper for the eval() builtin function to evaluate expressions and

- * obtain their value. It wraps the expression in parentheses such

- * that object literals are really evaluated to objects. Without the

- * wrapping, they are evaluated as block, and create syntax

- * errors. Also protects against other syntax errors in the eval()ed

- * code and returns null if the eval throws an exception.

- *

- * @param {string} expr

- * @return {Object|null}

- */

-function jsEval(expr) {

-  try {

-    // NOTE(mesch): An alternative idiom would be:

-    //

-    //   eval('(' + expr + ')');

-    //

-    // Note that using the square brackets as below, "" evals to undefined.

-    // The alternative of using parentheses does not work when evaluating

-    // function literals in IE.

-    // e.g. eval("(function() {})") returns undefined, and not a function

-    // object, in IE.

-    return eval('[' + expr + '][0]');

-  } catch (e) {

-    log('EVAL FAILED ' + expr + ': ' + e);

-    return null;

-  }

-}

-

-function jsLength(obj) {

-  return obj.length;

-}

-

-function assert(obj) {}

-

-/**

- * Copies all properties from second object to the first.  Modifies to.

- *

- * @param {Object} to  The target object.

- * @param {Object} from  The source object.

- */

-function copyProperties(to, from) {

-  for (var p in from) {

-    to[p] = from[p];

-  }

-}

-

-

-/**

- * @param {Object|null|undefined} value The possible value to use.

- * @param {Object} defaultValue The default if the value is not set.

- * @return {Object} The value, if it is

- * defined and not null; otherwise the default

- */

-function getDefaultObject(value, defaultValue) {

-  if (typeof value != TYPE_undefined && value != null) {

-    return /** @type Object */(value);

-  } else {

-    return defaultValue;

-  }

-}

-

-/**

- * Detect if an object looks like an Array.

- * Note that instanceof Array is not robust; for example an Array

- * created in another iframe fails instanceof Array.

- * @param {Object|null} value Object to interrogate

- * @return {boolean} Is the object an array?

- */

-function isArray(value) {

-  return value != null &&

-      typeof value == TYPE_object &&

-      typeof value.length == TYPE_number;

-}

-

-

-/**

- * Finds a slice of an array.

- *

- * @param {Array} array  Array to be sliced.

- * @param {number} start  The start of the slice.

- * @param {number} opt_end  The end of the slice (optional).

- * @return {Array} array  The slice of the array from start to end.

- */

-function arraySlice(array, start, opt_end) {

-  // Use

-  //   return Function.prototype.call.apply(Array.prototype.slice, arguments);

-  // instead of the simpler

-  //   return Array.prototype.slice.call(array, start, opt_end);

-  // here because of a bug in the FF and IE implementations of

-  // Array.prototype.slice which causes this function to return an empty list

-  // if opt_end is not provided.

-  return Function.prototype.call.apply(Array.prototype.slice, arguments);

-}

-

-

-/**

- * Jscompiler wrapper for parseInt() with base 10.

- *

- * @param {string} s string repersentation of a number.

- *

- * @return {number} The integer contained in s, converted on base 10.

- */

-function parseInt10(s) {

-  return parseInt(s, 10);

-}

-

-

-/**

- * Clears the array by setting the length property to 0. This usually

- * works, and if it should turn out not to work everywhere, here would

- * be the place to implement the browser specific workaround.

- *

- * @param {Array} array  Array to be cleared.

- */

-function arrayClear(array) {

-  array.length = 0;

-}

-

-

-/**

- * Prebinds "this" within the given method to an object, but ignores all 

- * arguments passed to the resulting function.

- * I.e. var_args are all the arguments that method is invoked with when

- * invoking the bound function.

- *

- * @param {Object|null} object  The object that the method call targets.

- * @param {Function} method  The target method.

- * @return {Function}  Method with the target object bound to it and curried by

- *                     the provided arguments.

- */

-function bindFully(object, method, var_args) {

-  var args = arraySlice(arguments, 2);

-  return function() {

-    return method.apply(object, args);

-  }

-}

-

-// Based on <http://www.w3.org/TR/2000/ REC-DOM-Level-2-Core-20001113/

-// core.html#ID-1950641247>.

-var DOM_ELEMENT_NODE = 1;

-var DOM_ATTRIBUTE_NODE = 2;

-var DOM_TEXT_NODE = 3;

-var DOM_CDATA_SECTION_NODE = 4;

-var DOM_ENTITY_REFERENCE_NODE = 5;

-var DOM_ENTITY_NODE = 6;

-var DOM_PROCESSING_INSTRUCTION_NODE = 7;

-var DOM_COMMENT_NODE = 8;

-var DOM_DOCUMENT_NODE = 9;

-var DOM_DOCUMENT_TYPE_NODE = 10;

-var DOM_DOCUMENT_FRAGMENT_NODE = 11;

-var DOM_NOTATION_NODE = 12;

-

-

-

-function domGetElementById(document, id) {

-  return document.getElementById(id);

-}

-

-/**

- * Creates a new node in the given document

- *

- * @param {Document} doc  Target document.

- * @param {string} name  Name of new element (i.e. the tag name)..

- * @return {Element}  Newly constructed element.

- */

-function domCreateElement(doc, name) {

-  return doc.createElement(name);

-}

-

-/**

- * Traverses the element nodes in the DOM section underneath the given

- * node and invokes the given callback as a method on every element

- * node encountered.

- *

- * @param {Element} node  Parent element of the subtree to traverse.

- * @param {Function} callback  Called on each node in the traversal.

- */

-function domTraverseElements(node, callback) {

-  var traverser = new DomTraverser(callback);

-  traverser.run(node);

-}

-

-/**

- * A class to hold state for a dom traversal.

- * @param {Function} callback  Called on each node in the traversal.

- * @constructor

- * @class

- */

-function DomTraverser(callback) {

-  this.callback_ = callback;

-}

-

-/**

- * Processes the dom tree in breadth-first order.

- * @param {Element} root  The root node of the traversal.

- */

-DomTraverser.prototype.run = function(root) {

-  var me = this;

-  me.queue_ = [ root ];

-  while (jsLength(me.queue_)) {

-    me.process_(me.queue_.shift());

-  }

-}

-

-/**

- * Processes a single node.

- * @param {Element} node  The current node of the traversal.

- */

-DomTraverser.prototype.process_ = function(node) {

-  var me = this;

-

-  me.callback_(node);

-

-  for (var c = node.firstChild; c; c = c.nextSibling) {

-    if (c.nodeType == DOM_ELEMENT_NODE) {

-      me.queue_.push(c);

-    }

-  }

-}

-

-/**

- * Get an attribute from the DOM.  Simple redirect, exists to compress code.

- *

- * @param {Element} node  Element to interrogate.

- * @param {string} name  Name of parameter to extract.

- * @return {string|null}  Resulting attribute.

- */

-function domGetAttribute(node, name) {

-  return node.getAttribute(name);

-  // NOTE(mesch): Neither in IE nor in Firefox, HTML DOM attributes

-  // implement namespaces. All items in the attribute collection have

-  // null localName and namespaceURI attribute values. In IE, we even

-  // encounter DIV elements that don't implement the method

-  // getAttributeNS().

-}

-

-

-/**

- * Set an attribute in the DOM.  Simple redirect to compress code.

- *

- * @param {Element} node  Element to interrogate.

- * @param {string} name  Name of parameter to set.

- * @param {string|number} value  Set attribute to this value.

- */

-function domSetAttribute(node, name, value) {

-  node.setAttribute(name, value);

-}

-

-/**

- * Remove an attribute from the DOM.  Simple redirect to compress code.

- *

- * @param {Element} node  Element to interrogate.

- * @param {string} name  Name of parameter to remove.

- */

-function domRemoveAttribute(node, name) {

-  node.removeAttribute(name);

-}

-

-/**

- * Clone a node in the DOM.

- *

- * @param {Node} node  Node to clone.

- * @return {Node}  Cloned node.

- */

-function domCloneNode(node) {

-  return node.cloneNode(true);

-  // NOTE(mesch): we never so far wanted to use cloneNode(false),

-  // hence the default.

-}

-

-/**

- * Clone a element in the DOM.

- *

- * @param {Element} element  Element to clone.

- * @return {Element}  Cloned element.

- */

-function domCloneElement(element) {

-  return /** @type {Element} */(domCloneNode(element));

-}

-

-/**

- * Returns the document owner of the given element. In particular,

- * returns window.document if node is null or the browser does not

- * support ownerDocument.  If the node is a document itself, returns

- * itself.

- *

- * @param {Node|null|undefined} node  The node whose ownerDocument is required.

- * @returns {Document}  The owner document or window.document if unsupported.

- */

-function ownerDocument(node) {

-  if (!node) {

-    return document;

-  } else if (node.nodeType == DOM_DOCUMENT_NODE) {

-    return /** @type Document */(node);

-  } else {

-    return node.ownerDocument || document;

-  }

-}

-

-/**

- * Creates a new text node in the given document.

- *

- * @param {Document} doc  Target document.

- * @param {string} text  Text composing new text node.

- * @return {Text}  Newly constructed text node.

- */

-function domCreateTextNode(doc, text) {

-  return doc.createTextNode(text);

-}

-

-/**

- * Appends a new child to the specified (parent) node.

- *

- * @param {Element} node  Parent element.

- * @param {Node} child  Child node to append.

- * @return {Node}  Newly appended node.

- */

-function domAppendChild(node, child) {

-  return node.appendChild(child);

-}

-

-/**

- * Sets display to default.

- *

- * @param {Element} node  The dom element to manipulate.

- */

-function displayDefault(node) {

-  node.style[CSS_display] = '';

-}

-

-/**

- * Sets display to none. Doing this as a function saves a few bytes for

- * the 'style.display' property and the 'none' literal.

- *

- * @param {Element} node  The dom element to manipulate.

- */

-function displayNone(node) {

-  node.style[CSS_display] = 'none';

-}

-

-

-/**

- * Sets position style attribute to absolute.

- *

- * @param {Element} node  The dom element to manipulate.

- */

-function positionAbsolute(node) {

-  node.style[CSS_position] = 'absolute';

-}

-

-

-/**

- * Inserts a new child before a given sibling.

- *

- * @param {Node} newChild  Node to insert.

- * @param {Node} oldChild  Sibling node.

- * @return {Node}  Reference to new child.

- */

-function domInsertBefore(newChild, oldChild) {

-  return oldChild.parentNode.insertBefore(newChild, oldChild);

-}

-

-/**

- * Replaces an old child node with a new child node.

- *

- * @param {Node} newChild  New child to append.

- * @param {Node} oldChild  Old child to remove.

- * @return {Node}  Replaced node.

- */

-function domReplaceChild(newChild, oldChild) {

-  return oldChild.parentNode.replaceChild(newChild, oldChild);

-}

-

-/**

- * Removes a node from the DOM.

- *

- * @param {Node} node  The node to remove.

- * @return {Node}  The removed node.

- */

-function domRemoveNode(node) {

-  return domRemoveChild(node.parentNode, node);

-}

-

-/**

- * Remove a child from the specified (parent) node.

- *

- * @param {Element} node  Parent element.

- * @param {Node} child  Child node to remove.

- * @return {Node}  Removed node.

- */

-function domRemoveChild(node, child) {

-  return node.removeChild(child);

-}

-

-

-/**

- * Trim whitespace from begin and end of string.

- *

- * @see testStringTrim();

- *

- * @param {string} str  Input string.

- * @return {string}  Trimmed string.

- */

-function stringTrim(str) {

-  return stringTrimRight(stringTrimLeft(str));

-}

-

-/**

- * Trim whitespace from beginning of string.

- *

- * @see testStringTrimLeft();

- *

- * @param {string} str  Input string.

- * @return {string}  Trimmed string.

- */

-function stringTrimLeft(str) {

-  return str.replace(/^\s+/, "");

-}

-

-/**

- * Trim whitespace from end of string.

- *

- * @see testStringTrimRight();

- *

- * @param {string} str  Input string.

- * @return {string}  Trimmed string.

-  */

-function stringTrimRight(str) {

-  return str.replace(/\s+$/, "");

-}

-

+// Copyright 2006 Google Inc.
+//
+// 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.
+/**
+ * @fileoverview Miscellaneous constants and functions referenced in
+ * the main source files.
+ *
+ * @author Steffen Meschkat (mesch@google.com)
+ */
+
+var MAPS_DEBUG = false;
+
+function log(msg) {}
+
+// String literals defined globally and not to be inlined. (IE6 perf)
+/** @const */ var STRING_empty = '';
+
+/** @const */ var CSS_display = 'display';
+/** @const */ var CSS_position = 'position';
+
+// Constants for possible values of the typeof operator.
+var TYPE_boolean = 'boolean';
+var TYPE_number = 'number';
+var TYPE_object = 'object';
+var TYPE_string = 'string';
+var TYPE_function = 'function';
+var TYPE_undefined = 'undefined';
+
+
+/**
+ * Wrapper for the eval() builtin function to evaluate expressions and
+ * obtain their value. It wraps the expression in parentheses such
+ * that object literals are really evaluated to objects. Without the
+ * wrapping, they are evaluated as block, and create syntax
+ * errors. Also protects against other syntax errors in the eval()ed
+ * code and returns null if the eval throws an exception.
+ *
+ * @param {string} expr
+ * @return {Object|null}
+ */
+function jsEval(expr) {
+  try {
+    // NOTE(mesch): An alternative idiom would be:
+    //
+    //   eval('(' + expr + ')');
+    //
+    // Note that using the square brackets as below, "" evals to undefined.
+    // The alternative of using parentheses does not work when evaluating
+    // function literals in IE.
+    // e.g. eval("(function() {})") returns undefined, and not a function
+    // object, in IE.
+    return eval('[' + expr + '][0]');
+  } catch (e) {
+    log('EVAL FAILED ' + expr + ': ' + e);
+    return null;
+  }
+}
+
+function jsLength(obj) {
+  return obj.length;
+}
+
+function assert(obj) {}
+
+/**
+ * Copies all properties from second object to the first.  Modifies to.
+ *
+ * @param {Object} to  The target object.
+ * @param {Object} from  The source object.
+ */
+function copyProperties(to, from) {
+  for (var p in from) {
+    to[p] = from[p];
+  }
+}
+
+
+/**
+ * @param {Object|null|undefined} value The possible value to use.
+ * @param {Object} defaultValue The default if the value is not set.
+ * @return {Object} The value, if it is
+ * defined and not null; otherwise the default
+ */
+function getDefaultObject(value, defaultValue) {
+  if (typeof value != TYPE_undefined && value != null) {
+    return /** @type Object */(value);
+  } else {
+    return defaultValue;
+  }
+}
+
+/**
+ * Detect if an object looks like an Array.
+ * Note that instanceof Array is not robust; for example an Array
+ * created in another iframe fails instanceof Array.
+ * @param {Object|null} value Object to interrogate
+ * @return {boolean} Is the object an array?
+ */
+function isArray(value) {
+  return value != null &&
+      typeof value == TYPE_object &&
+      typeof value.length == TYPE_number;
+}
+
+
+/**
+ * Finds a slice of an array.
+ *
+ * @param {Array} array  Array to be sliced.
+ * @param {number} start  The start of the slice.
+ * @param {number} opt_end  The end of the slice (optional).
+ * @return {Array} array  The slice of the array from start to end.
+ */
+function arraySlice(array, start, opt_end) {
+  // Use
+  //   return Function.prototype.call.apply(Array.prototype.slice, arguments);
+  // instead of the simpler
+  //   return Array.prototype.slice.call(array, start, opt_end);
+  // here because of a bug in the FF and IE implementations of
+  // Array.prototype.slice which causes this function to return an empty list
+  // if opt_end is not provided.
+  return Function.prototype.call.apply(Array.prototype.slice, arguments);
+}
+
+
+/**
+ * Jscompiler wrapper for parseInt() with base 10.
+ *
+ * @param {string} s string repersentation of a number.
+ *
+ * @return {number} The integer contained in s, converted on base 10.
+ */
+function parseInt10(s) {
+  return parseInt(s, 10);
+}
+
+
+/**
+ * Clears the array by setting the length property to 0. This usually
+ * works, and if it should turn out not to work everywhere, here would
+ * be the place to implement the browser specific workaround.
+ *
+ * @param {Array} array  Array to be cleared.
+ */
+function arrayClear(array) {
+  array.length = 0;
+}
+
+
+/**
+ * Prebinds "this" within the given method to an object, but ignores all 
+ * arguments passed to the resulting function.
+ * I.e. var_args are all the arguments that method is invoked with when
+ * invoking the bound function.
+ *
+ * @param {Object|null} object  The object that the method call targets.
+ * @param {Function} method  The target method.
+ * @return {Function}  Method with the target object bound to it and curried by
+ *                     the provided arguments.
+ */
+function bindFully(object, method, var_args) {
+  var args = arraySlice(arguments, 2);
+  return function() {
+    return method.apply(object, args);
+  }
+}
+
+// Based on <http://www.w3.org/TR/2000/ REC-DOM-Level-2-Core-20001113/
+// core.html#ID-1950641247>.
+var DOM_ELEMENT_NODE = 1;
+var DOM_ATTRIBUTE_NODE = 2;
+var DOM_TEXT_NODE = 3;
+var DOM_CDATA_SECTION_NODE = 4;
+var DOM_ENTITY_REFERENCE_NODE = 5;
+var DOM_ENTITY_NODE = 6;
+var DOM_PROCESSING_INSTRUCTION_NODE = 7;
+var DOM_COMMENT_NODE = 8;
+var DOM_DOCUMENT_NODE = 9;
+var DOM_DOCUMENT_TYPE_NODE = 10;
+var DOM_DOCUMENT_FRAGMENT_NODE = 11;
+var DOM_NOTATION_NODE = 12;
+
+
+
+function domGetElementById(document, id) {
+  return document.getElementById(id);
+}
+
+/**
+ * Creates a new node in the given document
+ *
+ * @param {Document} doc  Target document.
+ * @param {string} name  Name of new element (i.e. the tag name)..
+ * @return {Element}  Newly constructed element.
+ */
+function domCreateElement(doc, name) {
+  return doc.createElement(name);
+}
+
+/**
+ * Traverses the element nodes in the DOM section underneath the given
+ * node and invokes the given callback as a method on every element
+ * node encountered.
+ *
+ * @param {Element} node  Parent element of the subtree to traverse.
+ * @param {Function} callback  Called on each node in the traversal.
+ */
+function domTraverseElements(node, callback) {
+  var traverser = new DomTraverser(callback);
+  traverser.run(node);
+}
+
+/**
+ * A class to hold state for a dom traversal.
+ * @param {Function} callback  Called on each node in the traversal.
+ * @constructor
+ * @class
+ */
+function DomTraverser(callback) {
+  this.callback_ = callback;
+}
+
+/**
+ * Processes the dom tree in breadth-first order.
+ * @param {Element} root  The root node of the traversal.
+ */
+DomTraverser.prototype.run = function(root) {
+  var me = this;
+  me.queue_ = [ root ];
+  while (jsLength(me.queue_)) {
+    me.process_(me.queue_.shift());
+  }
+}
+
+/**
+ * Processes a single node.
+ * @param {Element} node  The current node of the traversal.
+ */
+DomTraverser.prototype.process_ = function(node) {
+  var me = this;
+
+  me.callback_(node);
+
+  for (var c = node.firstChild; c; c = c.nextSibling) {
+    if (c.nodeType == DOM_ELEMENT_NODE) {
+      me.queue_.push(c);
+    }
+  }
+}
+
+/**
+ * Get an attribute from the DOM.  Simple redirect, exists to compress code.
+ *
+ * @param {Element} node  Element to interrogate.
+ * @param {string} name  Name of parameter to extract.
+ * @return {string|null}  Resulting attribute.
+ */
+function domGetAttribute(node, name) {
+  return node.getAttribute(name);
+  // NOTE(mesch): Neither in IE nor in Firefox, HTML DOM attributes
+  // implement namespaces. All items in the attribute collection have
+  // null localName and namespaceURI attribute values. In IE, we even
+  // encounter DIV elements that don't implement the method
+  // getAttributeNS().
+}
+
+
+/**
+ * Set an attribute in the DOM.  Simple redirect to compress code.
+ *
+ * @param {Element} node  Element to interrogate.
+ * @param {string} name  Name of parameter to set.
+ * @param {string|number} value  Set attribute to this value.
+ */
+function domSetAttribute(node, name, value) {
+  node.setAttribute(name, value);
+}
+
+/**
+ * Remove an attribute from the DOM.  Simple redirect to compress code.
+ *
+ * @param {Element} node  Element to interrogate.
+ * @param {string} name  Name of parameter to remove.
+ */
+function domRemoveAttribute(node, name) {
+  node.removeAttribute(name);
+}
+
+/**
+ * Clone a node in the DOM.
+ *
+ * @param {Node} node  Node to clone.
+ * @return {Node}  Cloned node.
+ */
+function domCloneNode(node) {
+  return node.cloneNode(true);
+  // NOTE(mesch): we never so far wanted to use cloneNode(false),
+  // hence the default.
+}
+
+/**
+ * Clone a element in the DOM.
+ *
+ * @param {Element} element  Element to clone.
+ * @return {Element}  Cloned element.
+ */
+function domCloneElement(element) {
+  return /** @type {Element} */(domCloneNode(element));
+}
+
+/**
+ * Returns the document owner of the given element. In particular,
+ * returns window.document if node is null or the browser does not
+ * support ownerDocument.  If the node is a document itself, returns
+ * itself.
+ *
+ * @param {Node|null|undefined} node  The node whose ownerDocument is required.
+ * @returns {Document}  The owner document or window.document if unsupported.
+ */
+function ownerDocument(node) {
+  if (!node) {
+    return document;
+  } else if (node.nodeType == DOM_DOCUMENT_NODE) {
+    return /** @type Document */(node);
+  } else {
+    return node.ownerDocument || document;
+  }
+}
+
+/**
+ * Creates a new text node in the given document.
+ *
+ * @param {Document} doc  Target document.
+ * @param {string} text  Text composing new text node.
+ * @return {Text}  Newly constructed text node.
+ */
+function domCreateTextNode(doc, text) {
+  return doc.createTextNode(text);
+}
+
+/**
+ * Appends a new child to the specified (parent) node.
+ *
+ * @param {Element} node  Parent element.
+ * @param {Node} child  Child node to append.
+ * @return {Node}  Newly appended node.
+ */
+function domAppendChild(node, child) {
+  return node.appendChild(child);
+}
+
+/**
+ * Sets display to default.
+ *
+ * @param {Element} node  The dom element to manipulate.
+ */
+function displayDefault(node) {
+  node.style[CSS_display] = '';
+}
+
+/**
+ * Sets display to none. Doing this as a function saves a few bytes for
+ * the 'style.display' property and the 'none' literal.
+ *
+ * @param {Element} node  The dom element to manipulate.
+ */
+function displayNone(node) {
+  node.style[CSS_display] = 'none';
+}
+
+
+/**
+ * Sets position style attribute to absolute.
+ *
+ * @param {Element} node  The dom element to manipulate.
+ */
+function positionAbsolute(node) {
+  node.style[CSS_position] = 'absolute';
+}
+
+
+/**
+ * Inserts a new child before a given sibling.
+ *
+ * @param {Node} newChild  Node to insert.
+ * @param {Node} oldChild  Sibling node.
+ * @return {Node}  Reference to new child.
+ */
+function domInsertBefore(newChild, oldChild) {
+  return oldChild.parentNode.insertBefore(newChild, oldChild);
+}
+
+/**
+ * Replaces an old child node with a new child node.
+ *
+ * @param {Node} newChild  New child to append.
+ * @param {Node} oldChild  Old child to remove.
+ * @return {Node}  Replaced node.
+ */
+function domReplaceChild(newChild, oldChild) {
+  return oldChild.parentNode.replaceChild(newChild, oldChild);
+}
+
+/**
+ * Removes a node from the DOM.
+ *
+ * @param {Node} node  The node to remove.
+ * @return {Node}  The removed node.
+ */
+function domRemoveNode(node) {
+  return domRemoveChild(node.parentNode, node);
+}
+
+/**
+ * Remove a child from the specified (parent) node.
+ *
+ * @param {Element} node  Parent element.
+ * @param {Node} child  Child node to remove.
+ * @return {Node}  Removed node.
+ */
+function domRemoveChild(node, child) {
+  return node.removeChild(child);
+}
+
+
+/**
+ * Trim whitespace from begin and end of string.
+ *
+ * @see testStringTrim();
+ *
+ * @param {string} str  Input string.
+ * @return {string}  Trimmed string.
+ */
+function stringTrim(str) {
+  return stringTrimRight(stringTrimLeft(str));
+}
+
+/**
+ * Trim whitespace from beginning of string.
+ *
+ * @see testStringTrimLeft();
+ *
+ * @param {string} str  Input string.
+ * @return {string}  Trimmed string.
+ */
+function stringTrimLeft(str) {
+  return str.replace(/^\s+/, "");
+}
+
+/**
+ * Trim whitespace from end of string.
+ *
+ * @see testStringTrimRight();
+ *
+ * @param {string} str  Input string.
+ * @return {string}  Trimmed string.
+  */
+function stringTrimRight(str) {
+  return str.replace(/\s+$/, "");
+}
+
diff --git a/chrome/common/extensions/docs/examples/extensions/fx/options.html b/chrome/common/extensions/docs/examples/extensions/fx/options.html
index 2442482..12d86c3 100644
--- a/chrome/common/extensions/docs/examples/extensions/fx/options.html
+++ b/chrome/common/extensions/docs/examples/extensions/fx/options.html
@@ -1,31 +1,31 @@
-<!doctype html>

-<html>

-<head>

-<style>

-body {

-  font-family: sans-serif;

-}

-#attributions {

-  margin-top: 20px;

-  color: #666666;

-  Xfont-size: 10px;

-}

-.sound {

-  cursor: pointer;

-}

-</style>

-<script src="options.js"></script>

-</head>

-<body>

-<div id="sounds"></div>

-<div id="attributions">

-Sounds from:

-<ul>

-<li><a href="http://www.freesound.org">www.freesound.org</a></li>

-<li><a href="http://www.free-samples-n-loops.com/loops.html">www.free-samples-n-loops.com/loops.html</a></li>

-<li>Googlers with microphones.*</li>

-</ul>

-<span style="font-size:10px">* Canadian sound made by actual Canadian.</span>

-</div>

-</body>

-</html>

+<!doctype html>
+<html>
+<head>
+<style>
+body {
+  font-family: sans-serif;
+}
+#attributions {
+  margin-top: 20px;
+  color: #666666;
+  Xfont-size: 10px;
+}
+.sound {
+  cursor: pointer;
+}
+</style>
+<script src="options.js"></script>
+</head>
+<body>
+<div id="sounds"></div>
+<div id="attributions">
+Sounds from:
+<ul>
+<li><a href="http://www.freesound.org">www.freesound.org</a></li>
+<li><a href="http://www.free-samples-n-loops.com/loops.html">www.free-samples-n-loops.com/loops.html</a></li>
+<li>Googlers with microphones.*</li>
+</ul>
+<span style="font-size:10px">* Canadian sound made by actual Canadian.</span>
+</div>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/binaryajax.js b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/binaryajax.js
index 1f800ad..f4e0426 100644
--- a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/binaryajax.js
+++ b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/binaryajax.js
@@ -1,235 +1,235 @@
-

-/*

- * Binary Ajax 0.1.5

- * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/

- * MIT License [http://www.opensource.org/licenses/mit-license.php]

- */

-

-

-var BinaryFile = function(strData, iDataOffset, iDataLength) {

-  var data = strData;

-  var dataOffset = iDataOffset || 0;

-  var dataLength = 0;

-

-  this.getRawData = function() {

-    return data;

-  }

-

-  if (typeof strData == "string") {

-    dataLength = iDataLength || data.length;

-

-    this.getByteAt = function(iOffset) {

-      return data.charCodeAt(iOffset + dataOffset) & 0xFF;

-    }

-  } else if (typeof strData == "unknown") {

-    dataLength = iDataLength || IEBinary_getLength(data);

-

-    this.getByteAt = function(iOffset) {

-      return IEBinary_getByteAt(data, iOffset + dataOffset);

-    }

-  }

-

-  this.getLength = function() {

-    return dataLength;

-  }

-

-  this.getSByteAt = function(iOffset) {

-    var iByte = this.getByteAt(iOffset);

-    if (iByte > 127)

-      return iByte - 256;

-    else

-      return iByte;

-  }

-

-  this.getShortAt = function(iOffset, bBigEndian) {

-    var iShort = bBigEndian ?

-      (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)

-      : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)

-    if (iShort < 0) iShort += 65536;

-    return iShort;

-  }

-  this.getSShortAt = function(iOffset, bBigEndian) {

-    var iUShort = this.getShortAt(iOffset, bBigEndian);

-    if (iUShort > 32767)

-      return iUShort - 65536;

-    else

-      return iUShort;

-  }

-  this.getLongAt = function(iOffset, bBigEndian) {

-    var iByte1 = this.getByteAt(iOffset),

-      iByte2 = this.getByteAt(iOffset + 1),

-      iByte3 = this.getByteAt(iOffset + 2),

-      iByte4 = this.getByteAt(iOffset + 3);

-

-    var iLong = bBigEndian ?

-      (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4

-      : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;

-    if (iLong < 0) iLong += 4294967296;

-    return iLong;

-  }

-  this.getSLongAt = function(iOffset, bBigEndian) {

-    var iULong = this.getLongAt(iOffset, bBigEndian);

-    if (iULong > 2147483647)

-      return iULong - 4294967296;

-    else

-      return iULong;

-  }

-  this.getStringAt = function(iOffset, iLength) {

-    var aStr = [];

-    for (var i=iOffset,j=0;i<iOffset+iLength;i++,j++) {

-      aStr[j] = String.fromCharCode(this.getByteAt(i));

-    }

-    return aStr.join("");

-  }

-

-  this.getCharAt = function(iOffset) {

-    return String.fromCharCode(this.getByteAt(iOffset));

-  }

-  this.toBase64 = function() {

-    return window.btoa(data);

-  }

-  this.fromBase64 = function(strBase64) {

-    data = window.atob(strBase64);

-  }

-}

-

-

-var BinaryAjax = (function() {

-

-  function createRequest() {

-    var oHTTP = null;

-    if (window.XMLHttpRequest) {

-      oHTTP = new XMLHttpRequest();

-    } else if (window.ActiveXObject) {

-      oHTTP = new ActiveXObject("Microsoft.XMLHTTP");

-    }

-    return oHTTP;

-  }

-

-  function getHead(strURL, fncCallback, fncError) {

-    var oHTTP = createRequest();

-    if (oHTTP) {

-      if (fncCallback) {

-        if (typeof(oHTTP.onload) != "undefined") {

-          oHTTP.onload = function() {

-            if (oHTTP.status == "200") {

-              fncCallback(this);

-            } else {

-              if (fncError) fncError();

-            }

-            oHTTP = null;

-          };

-        } else {

-          oHTTP.onreadystatechange = function() {

-            if (oHTTP.readyState == 4) {

-              if (oHTTP.status == "200") {

-                fncCallback(this);

-              } else {

-                if (fncError) fncError();

-              }

-              oHTTP = null;

-            }

-          };

-        }

-      }

-      oHTTP.open("HEAD", strURL, true);

-      oHTTP.send(null);

-    } else {

-      if (fncError) fncError();

-    }

-  }

-

-  function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {

-    var oHTTP = createRequest();

-    if (oHTTP) {

-

-      var iDataOffset = 0;

-      if (aRange && !bAcceptRanges) {

-        iDataOffset = aRange[0];

-      }

-      var iDataLen = 0;

-      if (aRange) {

-        iDataLen = aRange[1]-aRange[0]+1;

-      }

-

-      if (fncCallback) {

-        if (typeof(oHTTP.onload) != "undefined") {

-          oHTTP.onload = function() {

-

-            if (oHTTP.status == "200" || oHTTP.status == "206") {

-              this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);

-              this.fileSize = iFileSize || this.getResponseHeader("Content-Length");

-              fncCallback(this);

-            } else {

-              if (fncError) fncError();

-            }

-            oHTTP = null;

-          };

-        } else {

-          oHTTP.onreadystatechange = function() {

-            if (oHTTP.readyState == 4) {

-              if (oHTTP.status == "200" || oHTTP.status == "206") {

-                this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);

-                this.fileSize = iFileSize || this.getResponseHeader("Content-Length");

-                fncCallback(this);

-              } else {

-                if (fncError) fncError();

-              }

-              oHTTP = null;

-            }

-          };

-        }

-      }

-      oHTTP.open("GET", strURL, true);

-

-      if (oHTTP.overrideMimeType) oHTTP.overrideMimeType('text/plain; charset=x-user-defined');

-

-      if (aRange && bAcceptRanges) {

-        oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);

-      }

-

-      oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");

-

-      oHTTP.send(null);

-    } else {

-      if (fncError) fncError();

-    }

-  }

-

-  return function(strURL, fncCallback, fncError, aRange) {

-

-    if (aRange) {

-      getHead(

-        strURL,

-        function(oHTTP) {

-          var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"),10);

-          var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");

-

-          var iStart, iEnd;

-          iStart = aRange[0];

-          if (aRange[0] < 0)

-            iStart += iLength;

-          iEnd = iStart + aRange[1] - 1;

-

-          sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);

-        }

-      );

-

-    } else {

-      sendRequest(strURL, fncCallback, fncError);

-    }

-  }

-

-}());

-

-

-document.write(

-  "<script type='text/vbscript'>\r\n"

-  + "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"

-  + "	IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"

-  + "End Function\r\n"

-  + "Function IEBinary_getLength(strBinary)\r\n"

-  + "	IEBinary_getLength = LenB(strBinary)\r\n"

-  + "End Function\r\n"

-  + "</script>\r\n"

-);

+
+/*
+ * Binary Ajax 0.1.5
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+
+var BinaryFile = function(strData, iDataOffset, iDataLength) {
+  var data = strData;
+  var dataOffset = iDataOffset || 0;
+  var dataLength = 0;
+
+  this.getRawData = function() {
+    return data;
+  }
+
+  if (typeof strData == "string") {
+    dataLength = iDataLength || data.length;
+
+    this.getByteAt = function(iOffset) {
+      return data.charCodeAt(iOffset + dataOffset) & 0xFF;
+    }
+  } else if (typeof strData == "unknown") {
+    dataLength = iDataLength || IEBinary_getLength(data);
+
+    this.getByteAt = function(iOffset) {
+      return IEBinary_getByteAt(data, iOffset + dataOffset);
+    }
+  }
+
+  this.getLength = function() {
+    return dataLength;
+  }
+
+  this.getSByteAt = function(iOffset) {
+    var iByte = this.getByteAt(iOffset);
+    if (iByte > 127)
+      return iByte - 256;
+    else
+      return iByte;
+  }
+
+  this.getShortAt = function(iOffset, bBigEndian) {
+    var iShort = bBigEndian ?
+      (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)
+      : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)
+    if (iShort < 0) iShort += 65536;
+    return iShort;
+  }
+  this.getSShortAt = function(iOffset, bBigEndian) {
+    var iUShort = this.getShortAt(iOffset, bBigEndian);
+    if (iUShort > 32767)
+      return iUShort - 65536;
+    else
+      return iUShort;
+  }
+  this.getLongAt = function(iOffset, bBigEndian) {
+    var iByte1 = this.getByteAt(iOffset),
+      iByte2 = this.getByteAt(iOffset + 1),
+      iByte3 = this.getByteAt(iOffset + 2),
+      iByte4 = this.getByteAt(iOffset + 3);
+
+    var iLong = bBigEndian ?
+      (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
+      : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
+    if (iLong < 0) iLong += 4294967296;
+    return iLong;
+  }
+  this.getSLongAt = function(iOffset, bBigEndian) {
+    var iULong = this.getLongAt(iOffset, bBigEndian);
+    if (iULong > 2147483647)
+      return iULong - 4294967296;
+    else
+      return iULong;
+  }
+  this.getStringAt = function(iOffset, iLength) {
+    var aStr = [];
+    for (var i=iOffset,j=0;i<iOffset+iLength;i++,j++) {
+      aStr[j] = String.fromCharCode(this.getByteAt(i));
+    }
+    return aStr.join("");
+  }
+
+  this.getCharAt = function(iOffset) {
+    return String.fromCharCode(this.getByteAt(iOffset));
+  }
+  this.toBase64 = function() {
+    return window.btoa(data);
+  }
+  this.fromBase64 = function(strBase64) {
+    data = window.atob(strBase64);
+  }
+}
+
+
+var BinaryAjax = (function() {
+
+  function createRequest() {
+    var oHTTP = null;
+    if (window.XMLHttpRequest) {
+      oHTTP = new XMLHttpRequest();
+    } else if (window.ActiveXObject) {
+      oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
+    }
+    return oHTTP;
+  }
+
+  function getHead(strURL, fncCallback, fncError) {
+    var oHTTP = createRequest();
+    if (oHTTP) {
+      if (fncCallback) {
+        if (typeof(oHTTP.onload) != "undefined") {
+          oHTTP.onload = function() {
+            if (oHTTP.status == "200") {
+              fncCallback(this);
+            } else {
+              if (fncError) fncError();
+            }
+            oHTTP = null;
+          };
+        } else {
+          oHTTP.onreadystatechange = function() {
+            if (oHTTP.readyState == 4) {
+              if (oHTTP.status == "200") {
+                fncCallback(this);
+              } else {
+                if (fncError) fncError();
+              }
+              oHTTP = null;
+            }
+          };
+        }
+      }
+      oHTTP.open("HEAD", strURL, true);
+      oHTTP.send(null);
+    } else {
+      if (fncError) fncError();
+    }
+  }
+
+  function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {
+    var oHTTP = createRequest();
+    if (oHTTP) {
+
+      var iDataOffset = 0;
+      if (aRange && !bAcceptRanges) {
+        iDataOffset = aRange[0];
+      }
+      var iDataLen = 0;
+      if (aRange) {
+        iDataLen = aRange[1]-aRange[0]+1;
+      }
+
+      if (fncCallback) {
+        if (typeof(oHTTP.onload) != "undefined") {
+          oHTTP.onload = function() {
+
+            if (oHTTP.status == "200" || oHTTP.status == "206") {
+              this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);
+              this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
+              fncCallback(this);
+            } else {
+              if (fncError) fncError();
+            }
+            oHTTP = null;
+          };
+        } else {
+          oHTTP.onreadystatechange = function() {
+            if (oHTTP.readyState == 4) {
+              if (oHTTP.status == "200" || oHTTP.status == "206") {
+                this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);
+                this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
+                fncCallback(this);
+              } else {
+                if (fncError) fncError();
+              }
+              oHTTP = null;
+            }
+          };
+        }
+      }
+      oHTTP.open("GET", strURL, true);
+
+      if (oHTTP.overrideMimeType) oHTTP.overrideMimeType('text/plain; charset=x-user-defined');
+
+      if (aRange && bAcceptRanges) {
+        oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);
+      }
+
+      oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");
+
+      oHTTP.send(null);
+    } else {
+      if (fncError) fncError();
+    }
+  }
+
+  return function(strURL, fncCallback, fncError, aRange) {
+
+    if (aRange) {
+      getHead(
+        strURL,
+        function(oHTTP) {
+          var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"),10);
+          var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");
+
+          var iStart, iEnd;
+          iStart = aRange[0];
+          if (aRange[0] < 0)
+            iStart += iLength;
+          iEnd = iStart + aRange[1] - 1;
+
+          sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);
+        }
+      );
+
+    } else {
+      sendRequest(strURL, fncCallback, fncError);
+    }
+  }
+
+}());
+
+
+document.write(
+  "<script type='text/vbscript'>\r\n"
+  + "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"
+  + "	IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"
+  + "End Function\r\n"
+  + "Function IEBinary_getLength(strBinary)\r\n"
+  + "	IEBinary_getLength = LenB(strBinary)\r\n"
+  + "End Function\r\n"
+  + "</script>\r\n"
+);
diff --git a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/exif.js b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/exif.js
index 76a6810..29a2782 100644
--- a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/exif.js
+++ b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/exif.js
@@ -1,615 +1,615 @@
-/*

- * Javascript EXIF Reader 0.1.2

- * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/

- * MIT License [http://www.opensource.org/licenses/mit-license.php]

- */

-

-

-var EXIF = {};

-

-(function() {

-

-var bDebug = false;

-

-EXIF.Tags = {

-

-  // version tags

-  0x9000 : "ExifVersion",			// EXIF version

-  0xA000 : "FlashpixVersion",		// Flashpix format version

-

-  // colorspace tags

-  0xA001 : "ColorSpace",			// Color space information tag

-

-  // image configuration

-  0xA002 : "PixelXDimension",		// Valid width of meaningful image

-  0xA003 : "PixelYDimension",		// Valid height of meaningful image

-  0x9101 : "ComponentsConfiguration",	// Information about channels

-  0x9102 : "CompressedBitsPerPixel",	// Compressed bits per pixel

-

-  // user information

-  0x927C : "MakerNote",			// Any desired information written by the manufacturer

-  0x9286 : "UserComment",			// Comments by user

-

-  // related file

-  0xA004 : "RelatedSoundFile",		// Name of related sound file

-

-  // date and time

-  0x9003 : "DateTimeOriginal",		// Date and time when the original image was generated

-  0x9004 : "DateTimeDigitized",		// Date and time when the image was stored digitally

-  0x9290 : "SubsecTime",			// Fractions of seconds for DateTime

-  0x9291 : "SubsecTimeOriginal",		// Fractions of seconds for DateTimeOriginal

-  0x9292 : "SubsecTimeDigitized",		// Fractions of seconds for DateTimeDigitized

-

-  // picture-taking conditions

-  0x829A : "ExposureTime",		// Exposure time (in seconds)

-  0x829D : "FNumber",			// F number

-  0x8822 : "ExposureProgram",		// Exposure program

-  0x8824 : "SpectralSensitivity",		// Spectral sensitivity

-  0x8827 : "ISOSpeedRatings",		// ISO speed rating

-  0x8828 : "OECF",			// Optoelectric conversion factor

-  0x9201 : "ShutterSpeedValue",		// Shutter speed

-  0x9202 : "ApertureValue",		// Lens aperture

-  0x9203 : "BrightnessValue",		// Value of brightness

-  0x9204 : "ExposureBias",		// Exposure bias

-  0x9205 : "MaxApertureValue",		// Smallest F number of lens

-  0x9206 : "SubjectDistance",		// Distance to subject in meters

-  0x9207 : "MeteringMode", 		// Metering mode

-  0x9208 : "LightSource",			// Kind of light source

-  0x9209 : "Flash",			// Flash status

-  0x9214 : "SubjectArea",			// Location and area of main subject

-  0x920A : "FocalLength",			// Focal length of the lens in mm

-  0xA20B : "FlashEnergy",			// Strobe energy in BCPS

-  0xA20C : "SpatialFrequencyResponse",	//

-  0xA20E : "FocalPlaneXResolution", 	// Number of pixels in width direction per FocalPlaneResolutionUnit

-  0xA20F : "FocalPlaneYResolution", 	// Number of pixels in height direction per FocalPlaneResolutionUnit

-  0xA210 : "FocalPlaneResolutionUnit", 	// Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution

-  0xA214 : "SubjectLocation",		// Location of subject in image

-  0xA215 : "ExposureIndex",		// Exposure index selected on camera

-  0xA217 : "SensingMethod", 		// Image sensor type

-  0xA300 : "FileSource", 			// Image source (3 == DSC)

-  0xA301 : "SceneType", 			// Scene type (1 == directly photographed)

-  0xA302 : "CFAPattern",			// Color filter array geometric pattern

-  0xA401 : "CustomRendered",		// Special processing

-  0xA402 : "ExposureMode",		// Exposure mode

-  0xA403 : "WhiteBalance",		// 1 = auto white balance, 2 = manual

-  0xA404 : "DigitalZoomRation",		// Digital zoom ratio

-  0xA405 : "FocalLengthIn35mmFilm",	// Equivalent foacl length assuming 35mm film camera (in mm)

-  0xA406 : "SceneCaptureType",		// Type of scene

-  0xA407 : "GainControl",			// Degree of overall image gain adjustment

-  0xA408 : "Contrast",			// Direction of contrast processing applied by camera

-  0xA409 : "Saturation", 			// Direction of saturation processing applied by camera

-  0xA40A : "Sharpness",			// Direction of sharpness processing applied by camera

-  0xA40B : "DeviceSettingDescription",	//

-  0xA40C : "SubjectDistanceRange",	// Distance to subject

-

-  // other tags

-  0xA005 : "InteroperabilityIFDPointer",

-  0xA420 : "ImageUniqueID"		// Identifier assigned uniquely to each image

-};

-

-EXIF.TiffTags = {

-  0x0100 : "ImageWidth",

-  0x0101 : "ImageHeight",

-  0x8769 : "ExifIFDPointer",

-  0x8825 : "GPSInfoIFDPointer",

-  0xA005 : "InteroperabilityIFDPointer",

-  0x0102 : "BitsPerSample",

-  0x0103 : "Compression",

-  0x0106 : "PhotometricInterpretation",

-  0x0112 : "Orientation",

-  0x0115 : "SamplesPerPixel",

-  0x011C : "PlanarConfiguration",

-  0x0212 : "YCbCrSubSampling",

-  0x0213 : "YCbCrPositioning",

-  0x011A : "XResolution",

-  0x011B : "YResolution",

-  0x0128 : "ResolutionUnit",

-  0x0111 : "StripOffsets",

-  0x0116 : "RowsPerStrip",

-  0x0117 : "StripByteCounts",

-  0x0201 : "JPEGInterchangeFormat",

-  0x0202 : "JPEGInterchangeFormatLength",

-  0x012D : "TransferFunction",

-  0x013E : "WhitePoint",

-  0x013F : "PrimaryChromaticities",

-  0x0211 : "YCbCrCoefficients",

-  0x0214 : "ReferenceBlackWhite",

-  0x0132 : "DateTime",

-  0x010E : "ImageDescription",

-  0x010F : "Make",

-  0x0110 : "Model",

-  0x0131 : "Software",

-  0x013B : "Artist",

-  0x8298 : "Copyright"

-}

-

-EXIF.GPSTags = {

-  0x0000 : "GPSVersionID",

-  0x0001 : "GPSLatitudeRef",

-  0x0002 : "GPSLatitude",

-  0x0003 : "GPSLongitudeRef",

-  0x0004 : "GPSLongitude",

-  0x0005 : "GPSAltitudeRef",

-  0x0006 : "GPSAltitude",

-  0x0007 : "GPSTimeStamp",

-  0x0008 : "GPSSatellites",

-  0x0009 : "GPSStatus",

-  0x000A : "GPSMeasureMode",

-  0x000B : "GPSDOP",

-  0x000C : "GPSSpeedRef",

-  0x000D : "GPSSpeed",

-  0x000E : "GPSTrackRef",

-  0x000F : "GPSTrack",

-  0x0010 : "GPSImgDirectionRef",

-  0x0011 : "GPSImgDirection",

-  0x0012 : "GPSMapDatum",

-  0x0013 : "GPSDestLatitudeRef",

-  0x0014 : "GPSDestLatitude",

-  0x0015 : "GPSDestLongitudeRef",

-  0x0016 : "GPSDestLongitude",

-  0x0017 : "GPSDestBearingRef",

-  0x0018 : "GPSDestBearing",

-  0x0019 : "GPSDestDistanceRef",

-  0x001A : "GPSDestDistance",

-  0x001B : "GPSProcessingMethod",

-  0x001C : "GPSAreaInformation",

-  0x001D : "GPSDateStamp",

-  0x001E : "GPSDifferential"

-}

-

-EXIF.StringValues = {

-  ExposureProgram : {

-    0 : "Not defined",

-    1 : "Manual",

-    2 : "Normal program",

-    3 : "Aperture priority",

-    4 : "Shutter priority",

-    5 : "Creative program",

-    6 : "Action program",

-    7 : "Portrait mode",

-    8 : "Landscape mode"

-  },

-  MeteringMode : {

-    0 : "Unknown",

-    1 : "Average",

-    2 : "CenterWeightedAverage",

-    3 : "Spot",

-    4 : "MultiSpot",

-    5 : "Pattern",

-    6 : "Partial",

-    255 : "Other"

-  },

-  LightSource : {

-    0 : "Unknown",

-    1 : "Daylight",

-    2 : "Fluorescent",

-    3 : "Tungsten (incandescent light)",

-    4 : "Flash",

-    9 : "Fine weather",

-    10 : "Cloudy weather",

-    11 : "Shade",

-    12 : "Daylight fluorescent (D 5700 - 7100K)",

-    13 : "Day white fluorescent (N 4600 - 5400K)",

-    14 : "Cool white fluorescent (W 3900 - 4500K)",

-    15 : "White fluorescent (WW 3200 - 3700K)",

-    17 : "Standard light A",

-    18 : "Standard light B",

-    19 : "Standard light C",

-    20 : "D55",

-    21 : "D65",

-    22 : "D75",

-    23 : "D50",

-    24 : "ISO studio tungsten",

-    255 : "Other"

-  },

-  Flash : {

-    0x0000 : "Flash did not fire",

-    0x0001 : "Flash fired",

-    0x0005 : "Strobe return light not detected",

-    0x0007 : "Strobe return light detected",

-    0x0009 : "Flash fired, compulsory flash mode",

-    0x000D : "Flash fired, compulsory flash mode, return light not detected",

-    0x000F : "Flash fired, compulsory flash mode, return light detected",

-    0x0010 : "Flash did not fire, compulsory flash mode",

-    0x0018 : "Flash did not fire, auto mode",

-    0x0019 : "Flash fired, auto mode",

-    0x001D : "Flash fired, auto mode, return light not detected",

-    0x001F : "Flash fired, auto mode, return light detected",

-    0x0020 : "No flash function",

-    0x0041 : "Flash fired, red-eye reduction mode",

-    0x0045 : "Flash fired, red-eye reduction mode, return light not detected",

-    0x0047 : "Flash fired, red-eye reduction mode, return light detected",

-    0x0049 : "Flash fired, compulsory flash mode, red-eye reduction mode",

-    0x004D : "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",

-    0x004F : "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",

-    0x0059 : "Flash fired, auto mode, red-eye reduction mode",

-    0x005D : "Flash fired, auto mode, return light not detected, red-eye reduction mode",

-    0x005F : "Flash fired, auto mode, return light detected, red-eye reduction mode"

-  },

-  SensingMethod : {

-    1 : "Not defined",

-    2 : "One-chip color area sensor",

-    3 : "Two-chip color area sensor",

-    4 : "Three-chip color area sensor",

-    5 : "Color sequential area sensor",

-    7 : "Trilinear sensor",

-    8 : "Color sequential linear sensor"

-  },

-  SceneCaptureType : {

-    0 : "Standard",

-    1 : "Landscape",

-    2 : "Portrait",

-    3 : "Night scene"

-  },

-  SceneType : {

-    1 : "Directly photographed"

-  },

-  CustomRendered : {

-    0 : "Normal process",

-    1 : "Custom process"

-  },

-  WhiteBalance : {

-    0 : "Auto white balance",

-    1 : "Manual white balance"

-  },

-  GainControl : {

-    0 : "None",

-    1 : "Low gain up",

-    2 : "High gain up",

-    3 : "Low gain down",

-    4 : "High gain down"

-  },

-  Contrast : {

-    0 : "Normal",

-    1 : "Soft",

-    2 : "Hard"

-  },

-  Saturation : {

-    0 : "Normal",

-    1 : "Low saturation",

-    2 : "High saturation"

-  },

-  Sharpness : {

-    0 : "Normal",

-    1 : "Soft",

-    2 : "Hard"

-  },

-  SubjectDistanceRange : {

-    0 : "Unknown",

-    1 : "Macro",

-    2 : "Close view",

-    3 : "Distant view"

-  },

-  FileSource : {

-    3 : "DSC"

-  },

-

-  Components : {

-    0 : "",

-    1 : "Y",

-    2 : "Cb",

-    3 : "Cr",

-    4 : "R",

-    5 : "G",

-    6 : "B"

-  }

-}

-

-function addEvent(oElement, strEvent, fncHandler)

-{

-  if (oElement.addEventListener) {

-    oElement.addEventListener(strEvent, fncHandler, false);

-  } else if (oElement.attachEvent) {

-    oElement.attachEvent("on" + strEvent, fncHandler);

-  }

-}

-

-

-function imageHasData(oImg)

-{

-  return !!(oImg.exifdata);

-}

-

-function getImageData(oImg, fncCallback)

-{

-  BinaryAjax(

-    oImg.src,

-    function(oHTTP) {

-      var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);

-      oImg.exifdata = oEXIF || {};

-      if (fncCallback) fncCallback();

-    }

-  )

-}

-

-function findEXIFinJPEG(oFile) {

-  var aMarkers = [];

-

-  if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {

-    return false; // not a valid jpeg

-  }

-

-  var iOffset = 2;

-  var iLength = oFile.getLength();

-  while (iOffset < iLength) {

-    if (oFile.getByteAt(iOffset) != 0xFF) {

-      if (bDebug) console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));

-      return false; // not a valid marker, something is wrong

-    }

-

-    var iMarker = oFile.getByteAt(iOffset+1);

-

-    // we could implement handling for other markers here,

-    // but we're only looking for 0xFFE1 for EXIF data

-

-    if (iMarker == 22400) {

-      if (bDebug) console.log("Found 0xFFE1 marker");

-      return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);

-      iOffset += 2 + oFile.getShortAt(iOffset+2, true);

-

-    } else if (iMarker == 225) {

-      // 0xE1 = Application-specific 1 (for EXIF)

-      if (bDebug) console.log("Found 0xFFE1 marker");

-      return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);

-

-    } else {

-      iOffset += 2 + oFile.getShortAt(iOffset+2, true);

-    }

-

-  }

-

-}

-

-

-function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd)

-{

-  var iEntries = oFile.getShortAt(iDirStart, bBigEnd);

-  var oTags = {};

-  for (var i=0;i<iEntries;i++) {

-    var iEntryOffset = iDirStart + i*12 + 2;

-    var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];

-    if (!strTag && bDebug) console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));

-    oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);

-  }

-  return oTags;

-}

-

-

-function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)

-{

-  var iType = oFile.getShortAt(iEntryOffset+2, bBigEnd);

-  var iNumValues = oFile.getLongAt(iEntryOffset+4, bBigEnd);

-  var iValueOffset = oFile.getLongAt(iEntryOffset+8, bBigEnd) + iTIFFStart;

-

-  switch (iType) {

-    case 1: // byte, 8-bit unsigned int

-    case 7: // undefined, 8-bit byte, value depending on field

-      if (iNumValues == 1) {

-        return oFile.getByteAt(iEntryOffset + 8, bBigEnd);

-      } else {

-        var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getByteAt(iValOffset + n);

-        }

-        return aVals;

-      }

-      break;

-

-    case 2: // ascii, 8-bit byte

-      var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);

-      return oFile.getStringAt(iStringOffset, iNumValues-1);

-      break;

-

-    case 3: // short, 16 bit int

-      if (iNumValues == 1) {

-        return oFile.getShortAt(iEntryOffset + 8, bBigEnd);

-      } else {

-        var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getShortAt(iValOffset + 2*n, bBigEnd);

-        }

-        return aVals;

-      }

-      break;

-

-    case 4: // long, 32 bit int

-      if (iNumValues == 1) {

-        return oFile.getLongAt(iEntryOffset + 8, bBigEnd);

-      } else {

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getLongAt(iValueOffset + 4*n, bBigEnd);

-        }

-        return aVals;

-      }

-      break;

-    case 5:	// rational = two long values, first is numerator, second is denominator

-      if (iNumValues == 1) {

-        return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset+4, bBigEnd);

-      } else {

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getLongAt(iValueOffset+4 + 8*n, bBigEnd);

-        }

-        return aVals;

-      }

-      break;

-    case 9: // slong, 32 bit signed int

-      if (iNumValues == 1) {

-        return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);

-      } else {

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getSLongAt(iValueOffset + 4*n, bBigEnd);

-        }

-        return aVals;

-      }

-      break;

-    case 10: // signed rational, two slongs, first is numerator, second is denominator

-      if (iNumValues == 1) {

-        return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset+4, bBigEnd);

-      } else {

-        var aVals = [];

-        for (var n=0;n<iNumValues;n++) {

-          aVals[n] = oFile.getSLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getSLongAt(iValueOffset+4 + 8*n, bBigEnd);

-        }

-        return aVals;

-      }

-      break;

-  }

-}

-

-

-function readEXIFData(oFile, iStart, iLength)

-{

-  if (oFile.getStringAt(iStart, 4) != "Exif") {

-    if (bDebug) console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));

-    return false;

-  }

-

-  var bBigEnd;

-

-  var iTIFFOffset = iStart + 6;

-

-  // test for TIFF validity and endianness

-  if (oFile.getShortAt(iTIFFOffset) == 0x4949) {

-    bBigEnd = false;

-  } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {

-    bBigEnd = true;

-  } else {

-    if (bDebug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");

-    return false;

-  }

-

-  if (oFile.getShortAt(iTIFFOffset+2, bBigEnd) != 0x002A) {

-    if (bDebug) console.log("Not valid TIFF data! (no 0x002A)");

-    return false;

-  }

-

-  if (oFile.getLongAt(iTIFFOffset+4, bBigEnd) != 0x00000008) {

-    if (bDebug) console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset+4, bBigEnd));

-    return false;

-  }

-

-  var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset+8, EXIF.TiffTags, bBigEnd);

-

-  if (oTags.ExifIFDPointer) {

-    var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);

-    for (var strTag in oEXIFTags) {

-      switch (strTag) {

-        case "LightSource" :

-        case "Flash" :

-        case "MeteringMode" :

-        case "ExposureProgram" :

-        case "SensingMethod" :

-        case "SceneCaptureType" :

-        case "SceneType" :

-        case "CustomRendered" :

-        case "WhiteBalance" :

-        case "GainControl" :

-        case "Contrast" :

-        case "Saturation" :

-        case "Sharpness" :

-        case "SubjectDistanceRange" :

-        case "FileSource" :

-          oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];

-          break;

-

-        case "ExifVersion" :

-        case "FlashpixVersion" :

-          oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);

-          break;

-

-        case "ComponentsConfiguration" :

-          oEXIFTags[strTag] =

-            EXIF.StringValues.Components[oEXIFTags[strTag][0]]

-            + EXIF.StringValues.Components[oEXIFTags[strTag][1]]

-            + EXIF.StringValues.Components[oEXIFTags[strTag][2]]

-            + EXIF.StringValues.Components[oEXIFTags[strTag][3]];

-          break;

-      }

-      oTags[strTag] = oEXIFTags[strTag];

-    }

-  }

-

-  if (oTags.GPSInfoIFDPointer) {

-    var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);

-    for (var strTag in oGPSTags) {

-      switch (strTag) {

-        case "GPSVersionID" :

-          oGPSTags[strTag] = oGPSTags[strTag][0]

-            + "." + oGPSTags[strTag][1]

-            + "." + oGPSTags[strTag][2]

-            + "." + oGPSTags[strTag][3];

-          break;

-      }

-      oTags[strTag] = oGPSTags[strTag];

-    }

-  }

-

-  return oTags;

-}

-

-

-EXIF.getData = function(oImg, fncCallback)

-{

-  if (!oImg.complete) return false;

-  if (!imageHasData(oImg)) {

-    getImageData(oImg, fncCallback);

-  } else {

-    if (fncCallback) fncCallback();

-  }

-  return true;

-}

-

-EXIF.getTag = function(oImg, strTag)

-{

-  if (!imageHasData(oImg)) return;

-  return oImg.exifdata[strTag];

-}

-

-EXIF.pretty = function(oImg)

-{

-  if (!imageHasData(oImg)) return "";

-  var oData = oImg.exifdata;

-  var strPretty = "";

-  for (var a in oData) {

-    if (oData.hasOwnProperty(a)) {

-      if (typeof oData[a] == "object") {

-        strPretty += a + " : [" + oData[a].length + " values]\r\n";

-      } else {

-        strPretty += a + " : " + oData[a] + "\r\n";

-      }

-    }

-  }

-  return strPretty;

-}

-

-EXIF.readFromBinaryFile = function(oFile) {

-  return findEXIFinJPEG(oFile);

-}

-

-function loadAllImages()

-{

-  var aImages = document.getElementsByTagName("img");

-  for (var i=0;i<aImages.length;i++) {

-    if (aImages[i].getAttribute("exif") == "true") {

-      if (!aImages[i].complete) {

-        addEvent(aImages[i], "load",

-          function() {

-            EXIF.getData(this);

-          }

-        );

-      } else {

-        EXIF.getData(aImages[i]);

-      }

-    }

-  }

-}

-

-addEvent(window, "load", loadAllImages);

-

-})();

-

+/*
+ * Javascript EXIF Reader 0.1.2
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+
+var EXIF = {};
+
+(function() {
+
+var bDebug = false;
+
+EXIF.Tags = {
+
+  // version tags
+  0x9000 : "ExifVersion",			// EXIF version
+  0xA000 : "FlashpixVersion",		// Flashpix format version
+
+  // colorspace tags
+  0xA001 : "ColorSpace",			// Color space information tag
+
+  // image configuration
+  0xA002 : "PixelXDimension",		// Valid width of meaningful image
+  0xA003 : "PixelYDimension",		// Valid height of meaningful image
+  0x9101 : "ComponentsConfiguration",	// Information about channels
+  0x9102 : "CompressedBitsPerPixel",	// Compressed bits per pixel
+
+  // user information
+  0x927C : "MakerNote",			// Any desired information written by the manufacturer
+  0x9286 : "UserComment",			// Comments by user
+
+  // related file
+  0xA004 : "RelatedSoundFile",		// Name of related sound file
+
+  // date and time
+  0x9003 : "DateTimeOriginal",		// Date and time when the original image was generated
+  0x9004 : "DateTimeDigitized",		// Date and time when the image was stored digitally
+  0x9290 : "SubsecTime",			// Fractions of seconds for DateTime
+  0x9291 : "SubsecTimeOriginal",		// Fractions of seconds for DateTimeOriginal
+  0x9292 : "SubsecTimeDigitized",		// Fractions of seconds for DateTimeDigitized
+
+  // picture-taking conditions
+  0x829A : "ExposureTime",		// Exposure time (in seconds)
+  0x829D : "FNumber",			// F number
+  0x8822 : "ExposureProgram",		// Exposure program
+  0x8824 : "SpectralSensitivity",		// Spectral sensitivity
+  0x8827 : "ISOSpeedRatings",		// ISO speed rating
+  0x8828 : "OECF",			// Optoelectric conversion factor
+  0x9201 : "ShutterSpeedValue",		// Shutter speed
+  0x9202 : "ApertureValue",		// Lens aperture
+  0x9203 : "BrightnessValue",		// Value of brightness
+  0x9204 : "ExposureBias",		// Exposure bias
+  0x9205 : "MaxApertureValue",		// Smallest F number of lens
+  0x9206 : "SubjectDistance",		// Distance to subject in meters
+  0x9207 : "MeteringMode", 		// Metering mode
+  0x9208 : "LightSource",			// Kind of light source
+  0x9209 : "Flash",			// Flash status
+  0x9214 : "SubjectArea",			// Location and area of main subject
+  0x920A : "FocalLength",			// Focal length of the lens in mm
+  0xA20B : "FlashEnergy",			// Strobe energy in BCPS
+  0xA20C : "SpatialFrequencyResponse",	//
+  0xA20E : "FocalPlaneXResolution", 	// Number of pixels in width direction per FocalPlaneResolutionUnit
+  0xA20F : "FocalPlaneYResolution", 	// Number of pixels in height direction per FocalPlaneResolutionUnit
+  0xA210 : "FocalPlaneResolutionUnit", 	// Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
+  0xA214 : "SubjectLocation",		// Location of subject in image
+  0xA215 : "ExposureIndex",		// Exposure index selected on camera
+  0xA217 : "SensingMethod", 		// Image sensor type
+  0xA300 : "FileSource", 			// Image source (3 == DSC)
+  0xA301 : "SceneType", 			// Scene type (1 == directly photographed)
+  0xA302 : "CFAPattern",			// Color filter array geometric pattern
+  0xA401 : "CustomRendered",		// Special processing
+  0xA402 : "ExposureMode",		// Exposure mode
+  0xA403 : "WhiteBalance",		// 1 = auto white balance, 2 = manual
+  0xA404 : "DigitalZoomRation",		// Digital zoom ratio
+  0xA405 : "FocalLengthIn35mmFilm",	// Equivalent foacl length assuming 35mm film camera (in mm)
+  0xA406 : "SceneCaptureType",		// Type of scene
+  0xA407 : "GainControl",			// Degree of overall image gain adjustment
+  0xA408 : "Contrast",			// Direction of contrast processing applied by camera
+  0xA409 : "Saturation", 			// Direction of saturation processing applied by camera
+  0xA40A : "Sharpness",			// Direction of sharpness processing applied by camera
+  0xA40B : "DeviceSettingDescription",	//
+  0xA40C : "SubjectDistanceRange",	// Distance to subject
+
+  // other tags
+  0xA005 : "InteroperabilityIFDPointer",
+  0xA420 : "ImageUniqueID"		// Identifier assigned uniquely to each image
+};
+
+EXIF.TiffTags = {
+  0x0100 : "ImageWidth",
+  0x0101 : "ImageHeight",
+  0x8769 : "ExifIFDPointer",
+  0x8825 : "GPSInfoIFDPointer",
+  0xA005 : "InteroperabilityIFDPointer",
+  0x0102 : "BitsPerSample",
+  0x0103 : "Compression",
+  0x0106 : "PhotometricInterpretation",
+  0x0112 : "Orientation",
+  0x0115 : "SamplesPerPixel",
+  0x011C : "PlanarConfiguration",
+  0x0212 : "YCbCrSubSampling",
+  0x0213 : "YCbCrPositioning",
+  0x011A : "XResolution",
+  0x011B : "YResolution",
+  0x0128 : "ResolutionUnit",
+  0x0111 : "StripOffsets",
+  0x0116 : "RowsPerStrip",
+  0x0117 : "StripByteCounts",
+  0x0201 : "JPEGInterchangeFormat",
+  0x0202 : "JPEGInterchangeFormatLength",
+  0x012D : "TransferFunction",
+  0x013E : "WhitePoint",
+  0x013F : "PrimaryChromaticities",
+  0x0211 : "YCbCrCoefficients",
+  0x0214 : "ReferenceBlackWhite",
+  0x0132 : "DateTime",
+  0x010E : "ImageDescription",
+  0x010F : "Make",
+  0x0110 : "Model",
+  0x0131 : "Software",
+  0x013B : "Artist",
+  0x8298 : "Copyright"
+}
+
+EXIF.GPSTags = {
+  0x0000 : "GPSVersionID",
+  0x0001 : "GPSLatitudeRef",
+  0x0002 : "GPSLatitude",
+  0x0003 : "GPSLongitudeRef",
+  0x0004 : "GPSLongitude",
+  0x0005 : "GPSAltitudeRef",
+  0x0006 : "GPSAltitude",
+  0x0007 : "GPSTimeStamp",
+  0x0008 : "GPSSatellites",
+  0x0009 : "GPSStatus",
+  0x000A : "GPSMeasureMode",
+  0x000B : "GPSDOP",
+  0x000C : "GPSSpeedRef",
+  0x000D : "GPSSpeed",
+  0x000E : "GPSTrackRef",
+  0x000F : "GPSTrack",
+  0x0010 : "GPSImgDirectionRef",
+  0x0011 : "GPSImgDirection",
+  0x0012 : "GPSMapDatum",
+  0x0013 : "GPSDestLatitudeRef",
+  0x0014 : "GPSDestLatitude",
+  0x0015 : "GPSDestLongitudeRef",
+  0x0016 : "GPSDestLongitude",
+  0x0017 : "GPSDestBearingRef",
+  0x0018 : "GPSDestBearing",
+  0x0019 : "GPSDestDistanceRef",
+  0x001A : "GPSDestDistance",
+  0x001B : "GPSProcessingMethod",
+  0x001C : "GPSAreaInformation",
+  0x001D : "GPSDateStamp",
+  0x001E : "GPSDifferential"
+}
+
+EXIF.StringValues = {
+  ExposureProgram : {
+    0 : "Not defined",
+    1 : "Manual",
+    2 : "Normal program",
+    3 : "Aperture priority",
+    4 : "Shutter priority",
+    5 : "Creative program",
+    6 : "Action program",
+    7 : "Portrait mode",
+    8 : "Landscape mode"
+  },
+  MeteringMode : {
+    0 : "Unknown",
+    1 : "Average",
+    2 : "CenterWeightedAverage",
+    3 : "Spot",
+    4 : "MultiSpot",
+    5 : "Pattern",
+    6 : "Partial",
+    255 : "Other"
+  },
+  LightSource : {
+    0 : "Unknown",
+    1 : "Daylight",
+    2 : "Fluorescent",
+    3 : "Tungsten (incandescent light)",
+    4 : "Flash",
+    9 : "Fine weather",
+    10 : "Cloudy weather",
+    11 : "Shade",
+    12 : "Daylight fluorescent (D 5700 - 7100K)",
+    13 : "Day white fluorescent (N 4600 - 5400K)",
+    14 : "Cool white fluorescent (W 3900 - 4500K)",
+    15 : "White fluorescent (WW 3200 - 3700K)",
+    17 : "Standard light A",
+    18 : "Standard light B",
+    19 : "Standard light C",
+    20 : "D55",
+    21 : "D65",
+    22 : "D75",
+    23 : "D50",
+    24 : "ISO studio tungsten",
+    255 : "Other"
+  },
+  Flash : {
+    0x0000 : "Flash did not fire",
+    0x0001 : "Flash fired",
+    0x0005 : "Strobe return light not detected",
+    0x0007 : "Strobe return light detected",
+    0x0009 : "Flash fired, compulsory flash mode",
+    0x000D : "Flash fired, compulsory flash mode, return light not detected",
+    0x000F : "Flash fired, compulsory flash mode, return light detected",
+    0x0010 : "Flash did not fire, compulsory flash mode",
+    0x0018 : "Flash did not fire, auto mode",
+    0x0019 : "Flash fired, auto mode",
+    0x001D : "Flash fired, auto mode, return light not detected",
+    0x001F : "Flash fired, auto mode, return light detected",
+    0x0020 : "No flash function",
+    0x0041 : "Flash fired, red-eye reduction mode",
+    0x0045 : "Flash fired, red-eye reduction mode, return light not detected",
+    0x0047 : "Flash fired, red-eye reduction mode, return light detected",
+    0x0049 : "Flash fired, compulsory flash mode, red-eye reduction mode",
+    0x004D : "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
+    0x004F : "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
+    0x0059 : "Flash fired, auto mode, red-eye reduction mode",
+    0x005D : "Flash fired, auto mode, return light not detected, red-eye reduction mode",
+    0x005F : "Flash fired, auto mode, return light detected, red-eye reduction mode"
+  },
+  SensingMethod : {
+    1 : "Not defined",
+    2 : "One-chip color area sensor",
+    3 : "Two-chip color area sensor",
+    4 : "Three-chip color area sensor",
+    5 : "Color sequential area sensor",
+    7 : "Trilinear sensor",
+    8 : "Color sequential linear sensor"
+  },
+  SceneCaptureType : {
+    0 : "Standard",
+    1 : "Landscape",
+    2 : "Portrait",
+    3 : "Night scene"
+  },
+  SceneType : {
+    1 : "Directly photographed"
+  },
+  CustomRendered : {
+    0 : "Normal process",
+    1 : "Custom process"
+  },
+  WhiteBalance : {
+    0 : "Auto white balance",
+    1 : "Manual white balance"
+  },
+  GainControl : {
+    0 : "None",
+    1 : "Low gain up",
+    2 : "High gain up",
+    3 : "Low gain down",
+    4 : "High gain down"
+  },
+  Contrast : {
+    0 : "Normal",
+    1 : "Soft",
+    2 : "Hard"
+  },
+  Saturation : {
+    0 : "Normal",
+    1 : "Low saturation",
+    2 : "High saturation"
+  },
+  Sharpness : {
+    0 : "Normal",
+    1 : "Soft",
+    2 : "Hard"
+  },
+  SubjectDistanceRange : {
+    0 : "Unknown",
+    1 : "Macro",
+    2 : "Close view",
+    3 : "Distant view"
+  },
+  FileSource : {
+    3 : "DSC"
+  },
+
+  Components : {
+    0 : "",
+    1 : "Y",
+    2 : "Cb",
+    3 : "Cr",
+    4 : "R",
+    5 : "G",
+    6 : "B"
+  }
+}
+
+function addEvent(oElement, strEvent, fncHandler)
+{
+  if (oElement.addEventListener) {
+    oElement.addEventListener(strEvent, fncHandler, false);
+  } else if (oElement.attachEvent) {
+    oElement.attachEvent("on" + strEvent, fncHandler);
+  }
+}
+
+
+function imageHasData(oImg)
+{
+  return !!(oImg.exifdata);
+}
+
+function getImageData(oImg, fncCallback)
+{
+  BinaryAjax(
+    oImg.src,
+    function(oHTTP) {
+      var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);
+      oImg.exifdata = oEXIF || {};
+      if (fncCallback) fncCallback();
+    }
+  )
+}
+
+function findEXIFinJPEG(oFile) {
+  var aMarkers = [];
+
+  if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {
+    return false; // not a valid jpeg
+  }
+
+  var iOffset = 2;
+  var iLength = oFile.getLength();
+  while (iOffset < iLength) {
+    if (oFile.getByteAt(iOffset) != 0xFF) {
+      if (bDebug) console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));
+      return false; // not a valid marker, something is wrong
+    }
+
+    var iMarker = oFile.getByteAt(iOffset+1);
+
+    // we could implement handling for other markers here,
+    // but we're only looking for 0xFFE1 for EXIF data
+
+    if (iMarker == 22400) {
+      if (bDebug) console.log("Found 0xFFE1 marker");
+      return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);
+      iOffset += 2 + oFile.getShortAt(iOffset+2, true);
+
+    } else if (iMarker == 225) {
+      // 0xE1 = Application-specific 1 (for EXIF)
+      if (bDebug) console.log("Found 0xFFE1 marker");
+      return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);
+
+    } else {
+      iOffset += 2 + oFile.getShortAt(iOffset+2, true);
+    }
+
+  }
+
+}
+
+
+function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd)
+{
+  var iEntries = oFile.getShortAt(iDirStart, bBigEnd);
+  var oTags = {};
+  for (var i=0;i<iEntries;i++) {
+    var iEntryOffset = iDirStart + i*12 + 2;
+    var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];
+    if (!strTag && bDebug) console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));
+    oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);
+  }
+  return oTags;
+}
+
+
+function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)
+{
+  var iType = oFile.getShortAt(iEntryOffset+2, bBigEnd);
+  var iNumValues = oFile.getLongAt(iEntryOffset+4, bBigEnd);
+  var iValueOffset = oFile.getLongAt(iEntryOffset+8, bBigEnd) + iTIFFStart;
+
+  switch (iType) {
+    case 1: // byte, 8-bit unsigned int
+    case 7: // undefined, 8-bit byte, value depending on field
+      if (iNumValues == 1) {
+        return oFile.getByteAt(iEntryOffset + 8, bBigEnd);
+      } else {
+        var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getByteAt(iValOffset + n);
+        }
+        return aVals;
+      }
+      break;
+
+    case 2: // ascii, 8-bit byte
+      var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
+      return oFile.getStringAt(iStringOffset, iNumValues-1);
+      break;
+
+    case 3: // short, 16 bit int
+      if (iNumValues == 1) {
+        return oFile.getShortAt(iEntryOffset + 8, bBigEnd);
+      } else {
+        var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getShortAt(iValOffset + 2*n, bBigEnd);
+        }
+        return aVals;
+      }
+      break;
+
+    case 4: // long, 32 bit int
+      if (iNumValues == 1) {
+        return oFile.getLongAt(iEntryOffset + 8, bBigEnd);
+      } else {
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getLongAt(iValueOffset + 4*n, bBigEnd);
+        }
+        return aVals;
+      }
+      break;
+    case 5:	// rational = two long values, first is numerator, second is denominator
+      if (iNumValues == 1) {
+        return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset+4, bBigEnd);
+      } else {
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getLongAt(iValueOffset+4 + 8*n, bBigEnd);
+        }
+        return aVals;
+      }
+      break;
+    case 9: // slong, 32 bit signed int
+      if (iNumValues == 1) {
+        return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);
+      } else {
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getSLongAt(iValueOffset + 4*n, bBigEnd);
+        }
+        return aVals;
+      }
+      break;
+    case 10: // signed rational, two slongs, first is numerator, second is denominator
+      if (iNumValues == 1) {
+        return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset+4, bBigEnd);
+      } else {
+        var aVals = [];
+        for (var n=0;n<iNumValues;n++) {
+          aVals[n] = oFile.getSLongAt(iValueOffset + 8*n, bBigEnd) / oFile.getSLongAt(iValueOffset+4 + 8*n, bBigEnd);
+        }
+        return aVals;
+      }
+      break;
+  }
+}
+
+
+function readEXIFData(oFile, iStart, iLength)
+{
+  if (oFile.getStringAt(iStart, 4) != "Exif") {
+    if (bDebug) console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));
+    return false;
+  }
+
+  var bBigEnd;
+
+  var iTIFFOffset = iStart + 6;
+
+  // test for TIFF validity and endianness
+  if (oFile.getShortAt(iTIFFOffset) == 0x4949) {
+    bBigEnd = false;
+  } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {
+    bBigEnd = true;
+  } else {
+    if (bDebug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
+    return false;
+  }
+
+  if (oFile.getShortAt(iTIFFOffset+2, bBigEnd) != 0x002A) {
+    if (bDebug) console.log("Not valid TIFF data! (no 0x002A)");
+    return false;
+  }
+
+  if (oFile.getLongAt(iTIFFOffset+4, bBigEnd) != 0x00000008) {
+    if (bDebug) console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset+4, bBigEnd));
+    return false;
+  }
+
+  var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset+8, EXIF.TiffTags, bBigEnd);
+
+  if (oTags.ExifIFDPointer) {
+    var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);
+    for (var strTag in oEXIFTags) {
+      switch (strTag) {
+        case "LightSource" :
+        case "Flash" :
+        case "MeteringMode" :
+        case "ExposureProgram" :
+        case "SensingMethod" :
+        case "SceneCaptureType" :
+        case "SceneType" :
+        case "CustomRendered" :
+        case "WhiteBalance" :
+        case "GainControl" :
+        case "Contrast" :
+        case "Saturation" :
+        case "Sharpness" :
+        case "SubjectDistanceRange" :
+        case "FileSource" :
+          oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];
+          break;
+
+        case "ExifVersion" :
+        case "FlashpixVersion" :
+          oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);
+          break;
+
+        case "ComponentsConfiguration" :
+          oEXIFTags[strTag] =
+            EXIF.StringValues.Components[oEXIFTags[strTag][0]]
+            + EXIF.StringValues.Components[oEXIFTags[strTag][1]]
+            + EXIF.StringValues.Components[oEXIFTags[strTag][2]]
+            + EXIF.StringValues.Components[oEXIFTags[strTag][3]];
+          break;
+      }
+      oTags[strTag] = oEXIFTags[strTag];
+    }
+  }
+
+  if (oTags.GPSInfoIFDPointer) {
+    var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);
+    for (var strTag in oGPSTags) {
+      switch (strTag) {
+        case "GPSVersionID" :
+          oGPSTags[strTag] = oGPSTags[strTag][0]
+            + "." + oGPSTags[strTag][1]
+            + "." + oGPSTags[strTag][2]
+            + "." + oGPSTags[strTag][3];
+          break;
+      }
+      oTags[strTag] = oGPSTags[strTag];
+    }
+  }
+
+  return oTags;
+}
+
+
+EXIF.getData = function(oImg, fncCallback)
+{
+  if (!oImg.complete) return false;
+  if (!imageHasData(oImg)) {
+    getImageData(oImg, fncCallback);
+  } else {
+    if (fncCallback) fncCallback();
+  }
+  return true;
+}
+
+EXIF.getTag = function(oImg, strTag)
+{
+  if (!imageHasData(oImg)) return;
+  return oImg.exifdata[strTag];
+}
+
+EXIF.pretty = function(oImg)
+{
+  if (!imageHasData(oImg)) return "";
+  var oData = oImg.exifdata;
+  var strPretty = "";
+  for (var a in oData) {
+    if (oData.hasOwnProperty(a)) {
+      if (typeof oData[a] == "object") {
+        strPretty += a + " : [" + oData[a].length + " values]\r\n";
+      } else {
+        strPretty += a + " : " + oData[a] + "\r\n";
+      }
+    }
+  }
+  return strPretty;
+}
+
+EXIF.readFromBinaryFile = function(oFile) {
+  return findEXIFinJPEG(oFile);
+}
+
+function loadAllImages()
+{
+  var aImages = document.getElementsByTagName("img");
+  for (var i=0;i<aImages.length;i++) {
+    if (aImages[i].getAttribute("exif") == "true") {
+      if (!aImages[i].complete) {
+        addEvent(aImages[i], "load",
+          function() {
+            EXIF.getData(this);
+          }
+        );
+      } else {
+        EXIF.getData(aImages[i]);
+      }
+    }
+  }
+}
+
+addEvent(window, "load", loadAllImages);
+
+})();
+
diff --git a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/imageinfo.js b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/imageinfo.js
index 79eb0d2..5a35c76 100644
--- a/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/imageinfo.js
+++ b/chrome/common/extensions/docs/examples/extensions/imageinfo/imageinfo/imageinfo.js
@@ -1,182 +1,182 @@
-/*

- * ImageInfo 0.1.2 - A JavaScript library for reading image metadata.

- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/

- * MIT License [http://www.nihilogic.dk/licenses/mit-license.txt]

- */

-

-

-var ImageInfo = {};

-

-ImageInfo.useRange = false;

-ImageInfo.range = 10240;

-

-(function() {

-

-  var files = [];

-

-  function readFileData(url, callback) {

-    BinaryAjax(

-      url,

-      function(http) {

-        var tags = readInfoFromData(http.binaryResponse);

-        var mime = http.getResponseHeader("Content-Type");

-

-        tags["mimeType"] = mime;

-        tags["byteSize"] = http.fileSize;

-

-        files[url] = tags;

-        if (callback) callback();

-      },

-      null,

-      ImageInfo.useRange ? [0, ImageInfo.range] : null

-    )

-  }

-

-  function readInfoFromData(data) {

-

-    var offset = 0;

-

-    if (data.getByteAt(0) == 0xFF && data.getByteAt(1) == 0xD8) {

-      return readJPEGInfo(data);

-    }

-    if (data.getByteAt(0) == 0x89 && data.getStringAt(1, 3) == "PNG") {

-      return readPNGInfo(data);

-    }

-    if (data.getStringAt(0,3) == "GIF") {

-      return readGIFInfo(data);

-    }

-    if (data.getByteAt(0) == 0x42 && data.getByteAt(1) == 0x4D) {

-      return readBMPInfo(data);

-    }

-    if (data.getByteAt(0) == 0x00 && data.getByteAt(1) == 0x00) {

-      return readICOInfo(data);

-    }

-

-    return {

-      format : "UNKNOWN"

-    };

-  }

-

-

-  function readPNGInfo(data) {

-    var w = data.getLongAt(16,true);

-    var h = data.getLongAt(20,true);

-

-    var bpc = data.getByteAt(24);

-    var ct = data.getByteAt(25);

-

-    var bpp = bpc;

-    if (ct == 4) bpp *= 2;

-    if (ct == 2) bpp *= 3;

-    if (ct == 6) bpp *= 4;

-

-    var alpha = data.getByteAt(25) >= 4;

-

-    return {

-      format : "PNG",

-      version : "",

-      width : w,

-      height : h,

-      bpp : bpp,

-      alpha : alpha,

-      exif : {}

-    }

-  }

-

-  function readGIFInfo(data) {

-    var version = data.getStringAt(3,3);

-    var w = data.getShortAt(6);

-    var h = data.getShortAt(8);

-

-    var bpp = ((data.getByteAt(10) >> 4) & 7) + 1;

-

-    return {

-      format : "GIF",

-      version : version,

-      width : w,

-      height : h,

-      bpp : bpp,

-      alpha : false,

-      exif : {}

-    }

-  }

-

-  function readJPEGInfo(data) {

-

-    var w = 0;

-    var h = 0;

-    var comps = 0;

-    var len = data.getLength();

-    var offset = 2;

-    while (offset < len) {

-      var marker = data.getShortAt(offset, true);

-      offset += 2;

-      if (marker == 0xFFC0) {

-        h = data.getShortAt(offset + 3, true);

-        w = data.getShortAt(offset + 5, true);

-        comps = data.getByteAt(offset + 7, true)

-        break;

-      } else {

-        offset += data.getShortAt(offset, true)

-      }

-    }

-

-    var exif = {};

-

-    if (typeof EXIF != "undefined" && EXIF.readFromBinaryFile) {

-      exif = EXIF.readFromBinaryFile(data);

-    }

-

-    return {

-      format : "JPEG",

-      version : "",

-      width : w,

-      height : h,

-      bpp : comps * 8,

-      alpha : false,

-      exif : exif

-    }

-  }

-

-  function readBMPInfo(data) {

-    var w = data.getLongAt(18);

-    var h = data.getLongAt(22);

-    var bpp = data.getShortAt(28);

-    return {

-      format : "BMP",

-      version : "",

-      width : w,

-      height : h,

-      bpp : bpp,

-      alpha : false,

-      exif : {}

-    }

-  }

-

-  ImageInfo.loadInfo = function(url, cb) {

-    if (!files[url]) {

-      readFileData(url, cb);

-    } else {

-      if (cb) cb();

-    }

-  }

-

-  ImageInfo.getAllFields = function(url) {

-    if (!files[url]) return null;

-

-    var tags = {};

-    for (var a in files[url]) {

-      if (files[url].hasOwnProperty(a))

-        tags[a] = files[url][a];

-    }

-    return tags;

-  }

-

-  ImageInfo.getField = function(url, field) {

-    if (!files[url]) return null;

-    return files[url][field];

-  }

-

-

-})();

-

+/*
+ * ImageInfo 0.1.2 - A JavaScript library for reading image metadata.
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * MIT License [http://www.nihilogic.dk/licenses/mit-license.txt]
+ */
+
+
+var ImageInfo = {};
+
+ImageInfo.useRange = false;
+ImageInfo.range = 10240;
+
+(function() {
+
+  var files = [];
+
+  function readFileData(url, callback) {
+    BinaryAjax(
+      url,
+      function(http) {
+        var tags = readInfoFromData(http.binaryResponse);
+        var mime = http.getResponseHeader("Content-Type");
+
+        tags["mimeType"] = mime;
+        tags["byteSize"] = http.fileSize;
+
+        files[url] = tags;
+        if (callback) callback();
+      },
+      null,
+      ImageInfo.useRange ? [0, ImageInfo.range] : null
+    )
+  }
+
+  function readInfoFromData(data) {
+
+    var offset = 0;
+
+    if (data.getByteAt(0) == 0xFF && data.getByteAt(1) == 0xD8) {
+      return readJPEGInfo(data);
+    }
+    if (data.getByteAt(0) == 0x89 && data.getStringAt(1, 3) == "PNG") {
+      return readPNGInfo(data);
+    }
+    if (data.getStringAt(0,3) == "GIF") {
+      return readGIFInfo(data);
+    }
+    if (data.getByteAt(0) == 0x42 && data.getByteAt(1) == 0x4D) {
+      return readBMPInfo(data);
+    }
+    if (data.getByteAt(0) == 0x00 && data.getByteAt(1) == 0x00) {
+      return readICOInfo(data);
+    }
+
+    return {
+      format : "UNKNOWN"
+    };
+  }
+
+
+  function readPNGInfo(data) {
+    var w = data.getLongAt(16,true);
+    var h = data.getLongAt(20,true);
+
+    var bpc = data.getByteAt(24);
+    var ct = data.getByteAt(25);
+
+    var bpp = bpc;
+    if (ct == 4) bpp *= 2;
+    if (ct == 2) bpp *= 3;
+    if (ct == 6) bpp *= 4;
+
+    var alpha = data.getByteAt(25) >= 4;
+
+    return {
+      format : "PNG",
+      version : "",
+      width : w,
+      height : h,
+      bpp : bpp,
+      alpha : alpha,
+      exif : {}
+    }
+  }
+
+  function readGIFInfo(data) {
+    var version = data.getStringAt(3,3);
+    var w = data.getShortAt(6);
+    var h = data.getShortAt(8);
+
+    var bpp = ((data.getByteAt(10) >> 4) & 7) + 1;
+
+    return {
+      format : "GIF",
+      version : version,
+      width : w,
+      height : h,
+      bpp : bpp,
+      alpha : false,
+      exif : {}
+    }
+  }
+
+  function readJPEGInfo(data) {
+
+    var w = 0;
+    var h = 0;
+    var comps = 0;
+    var len = data.getLength();
+    var offset = 2;
+    while (offset < len) {
+      var marker = data.getShortAt(offset, true);
+      offset += 2;
+      if (marker == 0xFFC0) {
+        h = data.getShortAt(offset + 3, true);
+        w = data.getShortAt(offset + 5, true);
+        comps = data.getByteAt(offset + 7, true)
+        break;
+      } else {
+        offset += data.getShortAt(offset, true)
+      }
+    }
+
+    var exif = {};
+
+    if (typeof EXIF != "undefined" && EXIF.readFromBinaryFile) {
+      exif = EXIF.readFromBinaryFile(data);
+    }
+
+    return {
+      format : "JPEG",
+      version : "",
+      width : w,
+      height : h,
+      bpp : comps * 8,
+      alpha : false,
+      exif : exif
+    }
+  }
+
+  function readBMPInfo(data) {
+    var w = data.getLongAt(18);
+    var h = data.getLongAt(22);
+    var bpp = data.getShortAt(28);
+    return {
+      format : "BMP",
+      version : "",
+      width : w,
+      height : h,
+      bpp : bpp,
+      alpha : false,
+      exif : {}
+    }
+  }
+
+  ImageInfo.loadInfo = function(url, cb) {
+    if (!files[url]) {
+      readFileData(url, cb);
+    } else {
+      if (cb) cb();
+    }
+  }
+
+  ImageInfo.getAllFields = function(url) {
+    if (!files[url]) return null;
+
+    var tags = {};
+    for (var a in files[url]) {
+      if (files[url].hasOwnProperty(a))
+        tags[a] = files[url][a];
+    }
+    return tags;
+  }
+
+  ImageInfo.getField = function(url, field) {
+    if (!files[url]) return null;
+    return files[url][field];
+  }
+
+
+})();
+
diff --git a/chrome/common/extensions/docs/examples/extensions/irc/servlet/irc.js b/chrome/common/extensions/docs/examples/extensions/irc/servlet/irc.js
index b169952..05cae96 100644
--- a/chrome/common/extensions/docs/examples/extensions/irc/servlet/irc.js
+++ b/chrome/common/extensions/docs/examples/extensions/irc/servlet/irc.js
@@ -1,188 +1,188 @@
-/*

- * IRCConnection is a simple implementation of the IRC protocol. A small

- * subset of the IRC commands are implemented. To be functional, IRCConnection

- * needs some mechanism of transport to be hooked up by:

- * -Passing in |sendFunc| and |closeFunc| which an IRCConnection to use to send

- *  an IRC message command and to close the connection respectively.

- * -Connecting the in-bound functions |onOpened|, |onMessage|, and |onClosed|,

- *  to the transport so that the IRCConnection can respond to the connection

- *  being opened, a message being received and the connection being closed.

- */

-

-function NoOp() {};

-function log(message) { console.log(message); };

-

-function IRCConnection(server, port, nick, sendFunc, closeFunc) {

-  this.server = server;

-  this.port = port;

-  this.nick = nick;

-  this.connected = false;

-  

-  var that = this;

-

-  /**

-   * Client API

-   */

-  this.onConnect = NoOp;

-  this.onDisconnect = NoOp;

-  this.onText = NoOp;

-  this.onNotice = NoOp;

-  this.onNickReferenced = NoOp;

-

-  this.joinChannel = function(channel) {

-    sendCommand(commands.JOIN, [channel], "");

-  };

-

-  this.sendMessage = function(recipient, message) {

-    sendCommand(commands.PRIVMSG, [recipient], message);

-  };

-

-  this.quitChannel = function(channel) {

-    sendCommand(commands.PART, [channel], "");

-  }

-

-  this.disconnect = function(message) {

-    sendCommand(commands.QUIT, [], message);

-    closeFunc();

-  }

-

-  /**

-   * Transport Interface

-   * Whatever transport is used must provide and connect to the following

-   * in-bound events.

-   */

-  this.onOpened = function() {

-    sendFunc(that.server + ":" + that.port);

-    sendCommand(commands.NICK, [this.nick], "");

-    sendCommand(commands.USER,

-                ["chromium-irc-lib", "chromium-ircproxy", "*"],

-                "indigo");

-  };

-

-  this.onMessage = function(message) {

-    log("<< " + message);

-    if (!message || !message.length) {

-      return;

-    }

-

-    var parsed = parseMessage(message);

-

-    // Respond to PING command.

-    if (parsed.command == commands.PING) {

-      sendCommand(commands.PONG, [], parsed.body);

-      return;

-    }

-

-    // Process PRIVMSG.

-    if (parsed.command == commands.PRIVMSG) {

-      if (parsed.body.charCodeAt(0) == 1) {

-        // Ignore CTCP.

-        return;

-      }

-      that.onText(parsed.parameters[0],

-                  parsed.prefix.split("!")[0],

-                  parsed.body);

-      return;

-    }

-

-    // TODO: Other IRC commands.

-    var commandCode = parseInt(parsed.command);

-    if (commandCode == NaN) {

-      return;

-    }

-

-    switch(commandCode) {

-      case 001:  // Server welcome message.

-        that.connected = true;

-        that.onConnect(parsed.body);

-        break;

-      case 002:

-      case 003:

-      case 004:

-      case 005:

-        if (!that.connected) {

-          that.connected = true;

-          that.onConnect();

-        }

-        break;

-      case 433:  // TODO(rafaelw): Nickname in use. 

-        throw "NOT IMPLEMENTED";

-        break;

-      default:

-        break;

-    }

-  }

-

-  this.onClosed = function() {

-    that.connected = false;

-    that.onDisconnect();

-  };

-

-  /**

-   * IRC Implementation

-   * What follows in a minimal implementation of the IRC protocol.

-   * Only |commands| are currently implemented.

-   */

-  var commands = {

-    JOIN: "JOIN",

-    NICK: "NICK",

-    NOTICE: "NOTICE",

-    PART: "PART",

-    PING: "PING",

-    PONG: "PONG",

-    PRIVMSG: "PRIVMSG",

-    QUIT: "QUIT",

-    USER: "USER"

-  };

-

-  function parseMessage(message) {

-    var parsed = {};

-    parsed.prefix = "";

-    parsed.command = "";

-    parsed.parameters = [];

-    parsed.body = "";

-

-    // Trim trailing CRLF.

-    var crlfIndex = message.indexOf("\r\n");

-    if(crlfIndex >= 0) {

-      message = message.substring(0, crlfIndex);

-    }

-

-    // If leading character is ':', the message starts with a prefix.

-    if (message.indexOf(':') == 0) {

-      parsed.prefix = message.substring(1, message.indexOf(" "));

-      message = message.substring(parsed.prefix.length + 2);

-

-      // Forward past extra whitespace.

-      while(message.indexOf(" ") == 0) {

-        message = message.substring(1);

-      }

-    }

-

-    // If there is still a ':', then the message has trailing body.

-    var bodyMarker = message.indexOf(':');

-    if (bodyMarker >= 0) {

-      parsed.body = message.substring(bodyMarker + 1);

-      message = message.substring(0, bodyMarker);

-    }

-

-    parsed.parameters = message.split(" ");

-    parsed.command = parsed.parameters.shift();  // First param is the command.

-

-    return parsed;

-  }

-

-  function sendCommand(command, params, message) {

-    var line = command;

-    if (params && params.length > 0) {

-      line += " " + params.join(" ");

-    }

-    if (message && message.length > 0) {

-      line += " :"  + message;

-    }

-

-    log(">> " + line);

-    line += "\r\n";

-    sendFunc(line);

-  };

-};

+/*
+ * IRCConnection is a simple implementation of the IRC protocol. A small
+ * subset of the IRC commands are implemented. To be functional, IRCConnection
+ * needs some mechanism of transport to be hooked up by:
+ * -Passing in |sendFunc| and |closeFunc| which an IRCConnection to use to send
+ *  an IRC message command and to close the connection respectively.
+ * -Connecting the in-bound functions |onOpened|, |onMessage|, and |onClosed|,
+ *  to the transport so that the IRCConnection can respond to the connection
+ *  being opened, a message being received and the connection being closed.
+ */
+
+function NoOp() {};
+function log(message) { console.log(message); };
+
+function IRCConnection(server, port, nick, sendFunc, closeFunc) {
+  this.server = server;
+  this.port = port;
+  this.nick = nick;
+  this.connected = false;
+  
+  var that = this;
+
+  /**
+   * Client API
+   */
+  this.onConnect = NoOp;
+  this.onDisconnect = NoOp;
+  this.onText = NoOp;
+  this.onNotice = NoOp;
+  this.onNickReferenced = NoOp;
+
+  this.joinChannel = function(channel) {
+    sendCommand(commands.JOIN, [channel], "");
+  };
+
+  this.sendMessage = function(recipient, message) {
+    sendCommand(commands.PRIVMSG, [recipient], message);
+  };
+
+  this.quitChannel = function(channel) {
+    sendCommand(commands.PART, [channel], "");
+  }
+
+  this.disconnect = function(message) {
+    sendCommand(commands.QUIT, [], message);
+    closeFunc();
+  }
+
+  /**
+   * Transport Interface
+   * Whatever transport is used must provide and connect to the following
+   * in-bound events.
+   */
+  this.onOpened = function() {
+    sendFunc(that.server + ":" + that.port);
+    sendCommand(commands.NICK, [this.nick], "");
+    sendCommand(commands.USER,
+                ["chromium-irc-lib", "chromium-ircproxy", "*"],
+                "indigo");
+  };
+
+  this.onMessage = function(message) {
+    log("<< " + message);
+    if (!message || !message.length) {
+      return;
+    }
+
+    var parsed = parseMessage(message);
+
+    // Respond to PING command.
+    if (parsed.command == commands.PING) {
+      sendCommand(commands.PONG, [], parsed.body);
+      return;
+    }
+
+    // Process PRIVMSG.
+    if (parsed.command == commands.PRIVMSG) {
+      if (parsed.body.charCodeAt(0) == 1) {
+        // Ignore CTCP.
+        return;
+      }
+      that.onText(parsed.parameters[0],
+                  parsed.prefix.split("!")[0],
+                  parsed.body);
+      return;
+    }
+
+    // TODO: Other IRC commands.
+    var commandCode = parseInt(parsed.command);
+    if (commandCode == NaN) {
+      return;
+    }
+
+    switch(commandCode) {
+      case 001:  // Server welcome message.
+        that.connected = true;
+        that.onConnect(parsed.body);
+        break;
+      case 002:
+      case 003:
+      case 004:
+      case 005:
+        if (!that.connected) {
+          that.connected = true;
+          that.onConnect();
+        }
+        break;
+      case 433:  // TODO(rafaelw): Nickname in use. 
+        throw "NOT IMPLEMENTED";
+        break;
+      default:
+        break;
+    }
+  }
+
+  this.onClosed = function() {
+    that.connected = false;
+    that.onDisconnect();
+  };
+
+  /**
+   * IRC Implementation
+   * What follows in a minimal implementation of the IRC protocol.
+   * Only |commands| are currently implemented.
+   */
+  var commands = {
+    JOIN: "JOIN",
+    NICK: "NICK",
+    NOTICE: "NOTICE",
+    PART: "PART",
+    PING: "PING",
+    PONG: "PONG",
+    PRIVMSG: "PRIVMSG",
+    QUIT: "QUIT",
+    USER: "USER"
+  };
+
+  function parseMessage(message) {
+    var parsed = {};
+    parsed.prefix = "";
+    parsed.command = "";
+    parsed.parameters = [];
+    parsed.body = "";
+
+    // Trim trailing CRLF.
+    var crlfIndex = message.indexOf("\r\n");
+    if(crlfIndex >= 0) {
+      message = message.substring(0, crlfIndex);
+    }
+
+    // If leading character is ':', the message starts with a prefix.
+    if (message.indexOf(':') == 0) {
+      parsed.prefix = message.substring(1, message.indexOf(" "));
+      message = message.substring(parsed.prefix.length + 2);
+
+      // Forward past extra whitespace.
+      while(message.indexOf(" ") == 0) {
+        message = message.substring(1);
+      }
+    }
+
+    // If there is still a ':', then the message has trailing body.
+    var bodyMarker = message.indexOf(':');
+    if (bodyMarker >= 0) {
+      parsed.body = message.substring(bodyMarker + 1);
+      message = message.substring(0, bodyMarker);
+    }
+
+    parsed.parameters = message.split(" ");
+    parsed.command = parsed.parameters.shift();  // First param is the command.
+
+    return parsed;
+  }
+
+  function sendCommand(command, params, message) {
+    var line = command;
+    if (params && params.length > 0) {
+      line += " " + params.join(" ");
+    }
+    if (message && message.length > 0) {
+      line += " :"  + message;
+    }
+
+    log(">> " + line);
+    line += "\r\n";
+    sendFunc(line);
+  };
+};
diff --git a/chrome/common/extensions/docs/examples/extensions/irc/servlet/styles.css b/chrome/common/extensions/docs/examples/extensions/irc/servlet/styles.css
index 3773dfa..a1efa37 100644
--- a/chrome/common/extensions/docs/examples/extensions/irc/servlet/styles.css
+++ b/chrome/common/extensions/docs/examples/extensions/irc/servlet/styles.css
@@ -1,159 +1,159 @@
-body {

-  margin: 0;

-  padding: 0;

-}

-

-#pageContainer {

-  display: -webkit-box;

-  position: fixed;

-  -webkit-box-orient: vertical;

-  -webkit-box-align: stretch;

-  height: 100%;

-  width: 100%;

- }

-

- #headerContainer {

-  display: -webkit-box;

-  height: 32px;

-  -webkit-box-orient: horizontal;

-  -webkit-box-align: stretch;

- }

-

-#pageControls {

-  position: absolute;

-  right: 0px;

-  font-family: Verdana, sans-serif;

-  font-size: 16px;

-  color: #aaaaaa;

-  padding: 8px;

-}

-

-#pageControls *, .removeButton, .channel, .messageLine * {

-  display: inline-block;

-}

-

-.addControlLabel {

-  margin-left: 20px;

-}

-

-.addButton {

-  background-color: #aaaaaa;

-  color: white;

-}

-

-#slideContainer {

-  display: -webkit-box;

-  -webkit-box-flex: 1;

-  position: relative;

-}

-

-#channelSlides {

-  position: absolute;

-  width: 100%;

-  height: 100%;

-}

-

-.channelSlide {

-  position: absolute;

-  width: 80%;

-  height: 100%;

-  background: -webkit-linear-gradient(#aaa, white);

-  -webkit-transition: margin 0.25s ease-in-out;

-}

-

-.channelSlide.far-left {

-  margin-left: -160%;

-}

-

-.channelSlide.left {

-  margin-left: -75%;

-}

-

-.channelSlide.center {

-  margin-left: 10%;

-}

-

-.channelSlide.right {

-  margin-left: 95%;

-}

-

-.channelSlide.far-right {

-  margin-left: 180%;

-}

-

-.channelControls {

-  position: absolute;

-  z-index: 1;

-  right: 0px;

-  top:0px;

-  color: white;

-  text-align: right;

-  padding: 8px;

-  font-family: "Verdana", sans-serif;

-  font-size: 20px;

-}

-

-.channelControls .removeButton {

-  background-color: white;

-  color: #999999;

-  padding: 0px 6px 4px 6px;

-  height:

-}

-

-.channelSlideContainer {

-  position: relative;

-  display: -webkit-box;

-  -webkit-box-orient: vertical;

-  -webkit-box-align: stretch;

-  height: 100%;

-  width: 100%;

-}

-

-.messageListContainer {

-  overflow: hidden;

-  position: relative;

-  display: -webkit-box;

-  -webkit-box-flex: 1;

-}

-

-.messageListSpacer {

-  display: -webkit-box;

-  -webkit-box-flex: 0;

-  height: 40px;

-  width: 100%;

-}

-

-.messageLine {

-  margin: 6px;

-  color: #999999;

-  font-family: "Lucida Console", Monospace;

-  font-size: 14px;

-}

-

-.messageList {

-  position: absolute;

-  bottom: 0;

-}

-

-#typingDiv {

-  position: fixed;

-  z-index: 4;

-  width: 80%;

-  height: 30px;

-  margin: 10px;

-  margin-left: 10%;

-  bottom: 0px;

-  -webkit-box-shadow: 3px 3px 5px #888;

-}

-

-#entryText {

-  width: 100%;

-  border: 0px;

-  height: 100%;

-  padding-left: 8px;

-  padding-right: 8px;

-  font-family: "Lucida Console", Monospace;

-  color: white;

-  border: 0px;

-  background: #777777;

-}

+body {
+  margin: 0;
+  padding: 0;
+}
+
+#pageContainer {
+  display: -webkit-box;
+  position: fixed;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  height: 100%;
+  width: 100%;
+ }
+
+ #headerContainer {
+  display: -webkit-box;
+  height: 32px;
+  -webkit-box-orient: horizontal;
+  -webkit-box-align: stretch;
+ }
+
+#pageControls {
+  position: absolute;
+  right: 0px;
+  font-family: Verdana, sans-serif;
+  font-size: 16px;
+  color: #aaaaaa;
+  padding: 8px;
+}
+
+#pageControls *, .removeButton, .channel, .messageLine * {
+  display: inline-block;
+}
+
+.addControlLabel {
+  margin-left: 20px;
+}
+
+.addButton {
+  background-color: #aaaaaa;
+  color: white;
+}
+
+#slideContainer {
+  display: -webkit-box;
+  -webkit-box-flex: 1;
+  position: relative;
+}
+
+#channelSlides {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+}
+
+.channelSlide {
+  position: absolute;
+  width: 80%;
+  height: 100%;
+  background: -webkit-linear-gradient(#aaa, white);
+  -webkit-transition: margin 0.25s ease-in-out;
+}
+
+.channelSlide.far-left {
+  margin-left: -160%;
+}
+
+.channelSlide.left {
+  margin-left: -75%;
+}
+
+.channelSlide.center {
+  margin-left: 10%;
+}
+
+.channelSlide.right {
+  margin-left: 95%;
+}
+
+.channelSlide.far-right {
+  margin-left: 180%;
+}
+
+.channelControls {
+  position: absolute;
+  z-index: 1;
+  right: 0px;
+  top:0px;
+  color: white;
+  text-align: right;
+  padding: 8px;
+  font-family: "Verdana", sans-serif;
+  font-size: 20px;
+}
+
+.channelControls .removeButton {
+  background-color: white;
+  color: #999999;
+  padding: 0px 6px 4px 6px;
+  height:
+}
+
+.channelSlideContainer {
+  position: relative;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-box-align: stretch;
+  height: 100%;
+  width: 100%;
+}
+
+.messageListContainer {
+  overflow: hidden;
+  position: relative;
+  display: -webkit-box;
+  -webkit-box-flex: 1;
+}
+
+.messageListSpacer {
+  display: -webkit-box;
+  -webkit-box-flex: 0;
+  height: 40px;
+  width: 100%;
+}
+
+.messageLine {
+  margin: 6px;
+  color: #999999;
+  font-family: "Lucida Console", Monospace;
+  font-size: 14px;
+}
+
+.messageList {
+  position: absolute;
+  bottom: 0;
+}
+
+#typingDiv {
+  position: fixed;
+  z-index: 4;
+  width: 80%;
+  height: 30px;
+  margin: 10px;
+  margin-left: 10%;
+  bottom: 0px;
+  -webkit-box-shadow: 3px 3px 5px #888;
+}
+
+#entryText {
+  width: 100%;
+  border: 0px;
+  height: 100%;
+  padding-left: 8px;
+  padding-right: 8px;
+  font-family: "Lucida Console", Monospace;
+  color: white;
+  border: 0px;
+  background: #777777;
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/irc/servlet/util.js b/chrome/common/extensions/docs/examples/extensions/irc/servlet/util.js
index ee1d332..f654d2c 100644
--- a/chrome/common/extensions/docs/examples/extensions/irc/servlet/util.js
+++ b/chrome/common/extensions/docs/examples/extensions/irc/servlet/util.js
@@ -1,19 +1,19 @@
-function $(el) {

-  return document.getElementById(el);

-}

-

-function $F(el) {

-  return $(el).value;

-}

-

-function bind(obj, func) {

-  return function() {

-    return func.apply(obj, arguments);

-  };

-}

-

-function childNodeWithClass(node, className) {

-  var expression = ".//*[@class='" + className + "']";

-  return document.evaluate(expression, node,

-      null, XPathResult.ANY_TYPE, null).iterateNext();  

+function $(el) {
+  return document.getElementById(el);
+}
+
+function $F(el) {
+  return $(el).value;
+}
+
+function bind(obj, func) {
+  return function() {
+    return func.apply(obj, arguments);
+  };
+}
+
+function childNodeWithClass(node, className) {
+  var expression = ".//*[@class='" + className + "']";
+  return document.evaluate(expression, node,
+      null, XPathResult.ANY_TYPE, null).iterateNext();  
 }
\ No newline at end of file
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json b/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json
index e5914f1..a6181e2 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json
@@ -1,16 +1,16 @@
-{

-  "name" : "__MSG_extName__",

-  "version" : "0.6",

-  "description" : "__MSG_extDescription__",

-  "options_page": "options.html",

-  "permissions": [

-    "contentSettings"

-  ],

-  "icons": {

-    "128": "bunny128.png",

-    "48": "bunny48.png"

-  },

-  "minimum_chrome_version": "16.0.912",

-  "default_locale": "en",

-  "manifest_version": 2

-}

+{
+  "name" : "__MSG_extName__",
+  "version" : "0.6",
+  "description" : "__MSG_extDescription__",
+  "options_page": "options.html",
+  "permissions": [
+    "contentSettings"
+  ],
+  "icons": {
+    "128": "bunny128.png",
+    "48": "bunny48.png"
+  },
+  "minimum_chrome_version": "16.0.912",
+  "default_locale": "en",
+  "manifest_version": 2
+}
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
index d3d095d..e1655d1 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -13,88 +13,10 @@
 import third_party.json_schema_compiler.model as model
 import third_party.json_schema_compiler.idl_schema as idl_schema
 import third_party.json_schema_compiler.idl_parser as idl_parser
+from schema_util import RemoveNoDocs, DetectInlineableTypes, InlineDocs
 from third_party.handlebar import Handlebar
 
 
-def _RemoveNoDocs(item):
-  if json_parse.IsDict(item):
-    if item.get('nodoc', False):
-      return True
-    for key, value in item.items():
-      if _RemoveNoDocs(value):
-        del item[key]
-  elif type(item) == list:
-    to_remove = []
-    for i in item:
-      if _RemoveNoDocs(i):
-        to_remove.append(i)
-    for i in to_remove:
-      item.remove(i)
-  return False
-
-
-def _DetectInlineableTypes(schema):
-  '''Look for documents that are only referenced once and mark them as inline.
-  Actual inlining is done by _InlineDocs.
-  '''
-  if not schema.get('types'):
-    return
-
-  ignore = frozenset(('value', 'choices'))
-  refcounts = defaultdict(int)
-  # Use an explicit stack instead of recursion.
-  stack = [schema]
-
-  while stack:
-    node = stack.pop()
-    if isinstance(node, list):
-      stack.extend(node)
-    elif isinstance(node, Mapping):
-      if '$ref' in node:
-        refcounts[node['$ref']] += 1
-      stack.extend(v for k, v in node.iteritems() if k not in ignore)
-
-  for type_ in schema['types']:
-    if not 'noinline_doc' in type_:
-      if refcounts[type_['id']] == 1:
-        type_['inline_doc'] = True
-
-
-def _InlineDocs(schema):
-  '''Replace '$ref's that refer to inline_docs with the json for those docs.
-  '''
-  types = schema.get('types')
-  if types is None:
-    return
-
-  inline_docs = {}
-  types_without_inline_doc = []
-
-  # Gather the types with inline_doc.
-  for type_ in types:
-    if type_.get('inline_doc'):
-      inline_docs[type_['id']] = type_
-      for k in ('description', 'id', 'inline_doc'):
-        type_.pop(k, None)
-    else:
-      types_without_inline_doc.append(type_)
-  schema['types'] = types_without_inline_doc
-
-  def apply_inline(node):
-    if isinstance(node, list):
-      for i in node:
-        apply_inline(i)
-    elif isinstance(node, Mapping):
-      ref = node.get('$ref')
-      if ref and ref in inline_docs:
-        node.update(inline_docs[ref])
-        del node['$ref']
-      for k, v in node.iteritems():
-        apply_inline(v)
-
-  apply_inline(schema)
-
-
 def _CreateId(node, prefix):
   if node.parent is not None and not isinstance(node.parent, model.Namespace):
     return '-'.join([prefix, node.parent.simple_name, node.simple_name])
@@ -154,12 +76,12 @@
     self._template_data_source = template_data_source
     self._add_rules_schema_function = add_rules_schema_function
     clean_json = copy.deepcopy(json)
-    if _RemoveNoDocs(clean_json):
+    if RemoveNoDocs(clean_json):
       self._namespace = None
     else:
       if idl:
-        _DetectInlineableTypes(clean_json)
-      _InlineDocs(clean_json)
+        DetectInlineableTypes(clean_json)
+      InlineDocs(clean_json)
       self._namespace = model.Namespace(clean_json, clean_json['namespace'])
 
   def _FormatDescription(self, description):
@@ -404,9 +326,9 @@
     elif type_.property_type == model.PropertyType.ARRAY:
       dst_dict['array'] = self._GenerateType(type_.item_type)
     elif type_.property_type == model.PropertyType.ENUM:
-      dst_dict['enum_values'] = []
-      for enum_value in type_.enum_values:
-        dst_dict['enum_values'].append({'name': enum_value})
+      dst_dict['enum_values'] = [
+          {'name': value.name, 'description': value.description}
+          for value in type_.enum_values]
       if len(dst_dict['enum_values']) > 0:
         dst_dict['enum_values'][-1]['last'] = True
     elif type_.instance_of is not None:
diff --git a/chrome/common/extensions/docs/server2/api_data_source_test.py b/chrome/common/extensions/docs/server2/api_data_source_test.py
index 96ff388..90c8656 100755
--- a/chrome/common/extensions/docs/server2/api_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/api_data_source_test.py
@@ -11,9 +11,6 @@
 
 from api_data_source import (_JSCModel,
                              _FormatValue,
-                             _RemoveNoDocs,
-                             _DetectInlineableTypes,
-                             _InlineDocs,
                              _GetAddRulesDefinitionFromEvents)
 from branch_utility import ChannelInfo
 from collections import namedtuple
@@ -156,10 +153,6 @@
                       _MakeLink('ref_test.html#type-type2', 'type2')),
         _GetType(dict_, 'type3')['description'])
 
-  def testRemoveNoDocs(self):
-    d = self._LoadJSON('nodoc_test.json')
-    _RemoveNoDocs(d)
-    self.assertEquals(self._LoadJSON('expected_nodoc.json'), d)
 
   def testGetApiAvailability(self):
     model = _JSCModel(self._LoadJSON('test_file.json')[0],
@@ -241,101 +234,6 @@
     self.assertEquals(json.dumps(model._GetIntroTableList()),
                       json.dumps(expected_list))
 
-  def testInlineDocs(self):
-    schema = {
-      "namespace": "storage",
-      "properties": {
-        "key2": {
-          "description": "second key",
-          "$ref": "Key"
-        },
-        "key1": {
-          "description": "first key",
-          "$ref": "Key"
-        }
-      },
-      "types": [
-        {
-          "inline_doc": True,
-          "type": "string",
-          "id": "Key",  # Should be inlined into both properties and be removed
-                        # from types.
-          "description": "This is a key.",  # This description should disappear.
-          "marker": True  # This should appear three times in the output.
-        },
-        {
-          "items": {
-            "$ref": "Key"
-          },
-          "type": "array",
-          "id": "KeyList",
-          "description": "A list of keys"
-        }
-      ]
-    }
-
-    expected_schema = {
-      "namespace": "storage",
-      "properties": {
-        "key2": {
-          "marker": True,
-          "type": "string",
-          "description": "second key"
-        },
-        "key1": {
-          "marker": True,
-          "type": "string",
-          "description": "first key"
-        }
-      },
-      "types": [
-        {
-          "items": {
-            "marker": True,
-            "type": "string"
-          },
-          "type": "array",
-          "id": "KeyList",
-          "description": "A list of keys"
-        }
-      ]
-    }
-
-    inlined_schema = deepcopy(schema)
-    _InlineDocs(inlined_schema)
-    self.assertEqual(expected_schema, inlined_schema)
-
-  def testDetectInline(self):
-    schema = {
-      "types": [
-        {
-          "id": "Key",
-          "items": {
-            "$ref": "Value"
-          }
-        },
-        {
-          "id": "Value",
-          "marker": True
-        }
-      ]
-    }
-
-    expected_schema = {
-      "types": [
-        {
-          "id": "Key",
-          "items": {
-            "marker": True,
-          }
-        }
-      ]
-    }
-
-    _DetectInlineableTypes(schema)
-    _InlineDocs(schema)
-    self.assertEqual(expected_schema, schema)
-
   def testGetAddRulesDefinitionFromEvents(self):
     events = {}
     # Missing 'types' completely.
diff --git a/chrome/common/extensions/docs/server2/api_models.py b/chrome/common/extensions/docs/server2/api_models.py
new file mode 100644
index 0000000..3928c03
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/api_models.py
@@ -0,0 +1,65 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import posixpath
+
+from file_system import FileNotFoundError
+from future import Gettable, Future
+from schema_util import ProcessSchema
+from svn_constants import API_PATH
+from third_party.json_schema_compiler.model import Namespace, UnixName
+
+
+def _CreateAPIModel(path, data):
+  schema = ProcessSchema(path, data)
+  if os.path.splitext(path)[1] == '.json':
+    schema = schema[0]
+  return Namespace(schema, schema['namespace'])
+
+
+class APIModels(object):
+  '''Tracks APIs and their Models.
+  '''
+
+  def __init__(self, features_bundle, compiled_fs_factory, file_system):
+    self._features_bundle = features_bundle
+    self._model_cache = compiled_fs_factory.Create(
+        file_system, _CreateAPIModel, APIModels)
+
+  def GetNames(self):
+    return self._features_bundle.GetAPIFeatures().keys()
+
+  def GetModel(self, api_name):
+    # Callers sometimes specify a filename which includes .json or .idl - if
+    # so, believe them. They may even include the 'api/' prefix.
+    if os.path.splitext(api_name)[1] in ('.json', '.idl'):
+      if not api_name.startswith(API_PATH + '/'):
+        api_name = posixpath.join(API_PATH, api_name)
+      return self._model_cache.GetFromFile(api_name)
+
+    assert not api_name.startswith(API_PATH)
+
+    # API names are given as declarativeContent and app.window but file names
+    # will be declarative_content and app_window.
+    file_name = UnixName(api_name).replace('.', '_')
+    # Devtools APIs are in API_PATH/devtools/ not API_PATH/, and have their
+    # "devtools" names removed from the file names.
+    basename = posixpath.basename(file_name)
+    if basename.startswith('devtools_'):
+      file_name = posixpath.join(
+          'devtools', file_name.replace(basename, basename[len('devtools_'):]))
+
+    futures = [self._model_cache.GetFromFile('%s/%s.%s' %
+                                             (API_PATH, file_name, ext))
+               for ext in ('json', 'idl')]
+    def resolve():
+      for future in futures:
+        try:
+          return future.Get()
+        except FileNotFoundError: pass
+      # Propagate the first FileNotFoundError if neither were found.
+      futures[0].Get()
+    return Future(delegate=Gettable(resolve))
diff --git a/chrome/common/extensions/docs/server2/api_models_test.py b/chrome/common/extensions/docs/server2/api_models_test.py
new file mode 100755
index 0000000..ff191d0
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/api_models_test.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import json
+import unittest
+
+from api_models import APIModels
+from compiled_file_system import CompiledFileSystem
+from features_bundle import FeaturesBundle
+from file_system import FileNotFoundError
+from object_store_creator import ObjectStoreCreator
+from test_file_system import TestFileSystem
+from test_util import ReadFile
+
+
+_TEST_DATA = {
+  'api': {
+    'devtools': {
+      'inspected_window.json': ReadFile(os.path.join(
+          'api', 'devtools', 'inspected_window.json')),
+    },
+    '_api_features.json': json.dumps({
+      'alarms': {},
+      'declarativeWebRequest': {},
+      'devtools.inspectedWindow': {},
+      'experimental.accessibility': {},
+      'storage': {},
+    }),
+    '_manifest_features.json': '{}',
+    '_permission_features.json': '{}',
+    'alarms.idl': ReadFile(os.path.join('api', 'alarms.idl')),
+    'declarative_web_request.json': ReadFile(os.path.join(
+        'api', 'declarative_web_request.json')),
+    'experimental_accessibility.json': ReadFile(os.path.join(
+        'api', 'experimental_accessibility.json')),
+    'page_action.json': ReadFile(os.path.join('api', 'page_action.json')),
+  },
+  'docs': {
+    'templates': {
+      'json': {
+        'manifest.json': '{}',
+        'permissions.json': '{}',
+      }
+    }
+  },
+}
+
+
+class APIModelsTest(unittest.TestCase):
+  def setUp(self):
+    object_store_creator = ObjectStoreCreator.ForTest()
+    compiled_fs_factory = CompiledFileSystem.Factory(object_store_creator)
+    file_system = TestFileSystem(_TEST_DATA)
+    features_bundle = FeaturesBundle(
+        file_system, compiled_fs_factory, object_store_creator)
+    self._api_models = APIModels(
+        features_bundle, compiled_fs_factory, file_system)
+
+  def testGetNames(self):
+    self.assertEqual(
+        ['alarms', 'declarativeWebRequest', 'devtools.inspectedWindow',
+         'experimental.accessibility', 'storage'],
+        sorted(self._api_models.GetNames()))
+
+  def testGetModel(self):
+    def get_model_name(api_name):
+      return self._api_models.GetModel(api_name).Get().name
+    self.assertEqual('devtools.inspectedWindow',
+                     get_model_name('devtools.inspectedWindow'))
+    self.assertEqual('devtools.inspectedWindow',
+                     get_model_name('devtools/inspected_window.json'))
+    self.assertEqual('devtools.inspectedWindow',
+                     get_model_name('api/devtools/inspected_window.json'))
+    self.assertEqual('alarms', get_model_name('alarms'))
+    self.assertEqual('alarms', get_model_name('alarms.idl'))
+    self.assertEqual('alarms', get_model_name('api/alarms.idl'))
+    self.assertEqual('declarativeWebRequest',
+                     get_model_name('declarativeWebRequest'))
+    self.assertEqual('declarativeWebRequest',
+                     get_model_name('declarative_web_request.json'))
+    self.assertEqual('declarativeWebRequest',
+                     get_model_name('api/declarative_web_request.json'))
+    self.assertEqual('experimental.accessibility',
+                     get_model_name('experimental.accessibility'))
+    self.assertEqual('experimental.accessibility',
+                     get_model_name('experimental_accessibility.json'))
+    self.assertEqual('experimental.accessibility',
+                     get_model_name('api/experimental_accessibility.json'))
+    self.assertEqual('pageAction', get_model_name('pageAction'))
+    self.assertEqual('pageAction', get_model_name('page_action.json'))
+    self.assertEqual('pageAction', get_model_name('api/page_action.json'))
+
+  def testGetNonexistentModel(self):
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('notfound').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('notfound.json').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('api/notfound.json').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('api/alarms.json').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('storage').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('api/storage.json').Get)
+    self.assertRaises(FileNotFoundError,
+                      self._api_models.GetModel('api/storage.idl').Get)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 80e3402..c31cc06 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 2-32-5
+version: 2-33-0
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
index 6b30214..10ae7ed 100644
--- a/chrome/common/extensions/docs/server2/availability_finder.py
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -2,27 +2,26 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from collections import Mapping
 import os
+from collections import Mapping
 
 from api_schema_graph import APISchemaGraph
 from branch_utility import BranchUtility
-from compiled_file_system import CompiledFileSystem
+from file_system import FileNotFoundError
 from svn_constants import API_PATH
-from third_party.json_schema_compiler import idl_schema, idl_parser, json_parse
-from third_party.json_schema_compiler.json_parse import OrderedDict
+from third_party.json_schema_compiler import idl_schema, idl_parser
 from third_party.json_schema_compiler.model import UnixName
 
 
 _EXTENSION_API = 'extension_api.json'
 
 
-def _GetChannelFromFeatures(api_name, file_system, path):
+def _GetChannelFromFeatures(api_name, json_fs, path):
   '''Finds API channel information within _features.json files at the given
-  |path| for the given |file_system|. Returns None if channel information for
-  the API cannot be located.
+  |path| for the given |json_fs|. Returns None if channel information for the
+  API cannot be located.
   '''
-  feature = file_system.GetFromFile(path).Get().get(api_name)
+  feature = json_fs.GetFromFile(path).Get().get(api_name)
 
   if feature is None:
     return None
@@ -34,78 +33,77 @@
   return BranchUtility.NewestChannel(entry.get('channel') for entry in feature)
 
 
-def _GetChannelFromApiFeatures(api_name, file_system):
-  return _GetChannelFromFeatures(
-      api_name,
-      file_system,
-      '%s/_api_features.json' % API_PATH)
+def _GetChannelFromApiFeatures(api_name, json_fs):
+  return _GetChannelFromFeatures(api_name,
+                                 json_fs,
+                                 '%s/_api_features.json' % API_PATH)
 
 
-def _GetChannelFromManifestFeatures(api_name, file_system):
-  return _GetChannelFromFeatures(
-      UnixName(api_name), #_manifest_features uses unix_style API names
-      file_system,
-      '%s/_manifest_features.json' % API_PATH)
+def _GetChannelFromManifestFeatures(api_name, json_fs):
+  return _GetChannelFromFeatures(#_manifest_features uses unix_style API names
+                                 UnixName(api_name),
+                                 json_fs,
+                                 '%s/_manifest_features.json' % API_PATH)
 
 
-def _GetChannelFromPermissionFeatures(api_name, file_system):
-  return _GetChannelFromFeatures(
-      api_name,
-      file_system,
-      '%s/_permission_features.json' % API_PATH)
+def _GetChannelFromPermissionFeatures(api_name, json_fs):
+  return _GetChannelFromFeatures(api_name,
+                                 json_fs,
+                                 '%s/_permission_features.json' % API_PATH)
 
 
-def _GetApiSchemaFilename(api_name, file_system):
+def _GetApiSchemaFilename(api_name, schema_fs):
   '''Gets the name of the file which contains the schema for |api_name| in
-  |file_system|, or None if the API is not found. Note that this may be the
+  |schema_fs|, or None if the API is not found. Note that this may be the
   single _EXTENSION_API file which all APIs share in older versions of Chrome.
   '''
   def under_api_path(path):
     return '%s/%s' % (API_PATH, path)
 
-  file_names = file_system.ReadSingle(under_api_path('')).Get()
-
-  if _EXTENSION_API in file_names:
-    # Prior to Chrome version 18, extension_api.json contained all API schema
+  try:
+    # Prior to Chrome version 18, _EXTENSION_API contained all API schema
     # data, which replaced the current implementation of individual API files.
     # We're forced to parse this (very large) file to determine if the API
     # exists in it.
-    #
-    # TODO(epeterson) Avoid doing unnecessary work by re-parsing.
-    # See http://crbug.com/295812.
-    extension_api_json = json_parse.Parse(
-        file_system.ReadSingle('%s/%s'% (API_PATH, _EXTENSION_API)).Get())
+    extension_api_path = under_api_path(_EXTENSION_API)
+    extension_api_json = schema_fs.GetFromFile(extension_api_path).Get()
     if any(api['namespace'] == api_name for api in extension_api_json):
-      return under_api_path(_EXTENSION_API)
+      return extension_api_path
     return None
+  except FileNotFoundError:
+    pass
 
-  api_file_names = [
-      file_name for file_name in file_names
-      if os.path.splitext(file_name)[0] in (api_name, UnixName(api_name))]
-  assert len(api_file_names) < 2
-  return under_api_path(api_file_names[0]) if api_file_names else None
+  for file_name in (api_name, UnixName(api_name)):
+    # From Chrome version 19 and onwards, each API schema is contained within
+    # an individual file.
+    for ext in ('json', 'idl'):
+      try:
+        api_file_name = under_api_path('%s.%s' % (file_name, ext))
+        schema_fs.GetFromFile(api_file_name).Get()
+        return api_file_name
+      except FileNotFoundError:
+        # The current format of the API filename does not exist in this
+        # filesystem.
+        pass
+  # API schema data could not be found in _EXTENSION_API or in a standalone
+  # schema file.
+  return None
 
 
-def _HasApiSchema(api_name, file_system):
-  return _GetApiSchemaFilename(api_name, file_system) is not None
+def _HasApiSchema(api_name, schema_fs):
+  return _GetApiSchemaFilename(api_name, schema_fs) is not None
 
 
-def _GetApiSchema(api_name, file_system):
-  '''Searches |file_system| for |api_name|'s API schema data, and parses and
-  returns it if found.
+def _GetApiSchema(api_name, schema_fs):
+  '''Searches |schema_fs| for |api_name|'s API schema data, and processes
+  and returns it if found.
   '''
-  api_file_name = _GetApiSchemaFilename(api_name, file_system)
-  if api_file_name is None:
+  file_name = _GetApiSchemaFilename(api_name, schema_fs)
+  if file_name is None:
     return None
 
-  api_file_text = file_system.ReadSingle(api_file_name).Get()
-  if api_file_name == _EXTENSION_API:
-    matching_schemas = [api for api in json_parse.Parse(api_file_text)
-                        if api['namespace'] == api_name]
-  elif api_file_name.endswith('.idl'):
-    matching_schemas = idl_parser.IDLParser().ParseData(api_file_text)
-  else:
-    matching_schemas = json_parse.Parse(api_file_text)
+  matching_schemas = [api for api in schema_fs.GetFromFile(file_name).Get()
+                      if api['namespace'] == api_name]
   # There should only be a single matching schema per file.
   assert len(matching_schemas) == 1
   return matching_schemas
@@ -117,18 +115,20 @@
   '''
 
   def __init__(self,
-               file_system_iterator,
-               object_store_creator,
                branch_utility,
-               host_file_system):
+               compiled_fs_factory,
+               file_system_iterator,
+               host_file_system,
+               object_store_creator):
+    self._branch_utility = branch_utility
+    self._compiled_fs_factory = compiled_fs_factory
     self._file_system_iterator = file_system_iterator
+    self._host_file_system = host_file_system
     self._object_store_creator = object_store_creator
     def create_object_store(category):
       return object_store_creator.Create(AvailabilityFinder, category=category)
     self._top_level_object_store = create_object_store('top_level')
     self._node_level_object_store = create_object_store('node_level')
-    self._branch_utility = branch_utility
-    self._host_file_system = host_file_system
 
   def _CheckStableAvailability(self, api_name, file_system, version):
     '''Checks for availability of an API, |api_name|, on the stable channel.
@@ -139,44 +139,38 @@
       # SVN data isn't available below version 5.
       return False
     available_channel = None
-    fs_factory = CompiledFileSystem.Factory(self._object_store_creator)
-    features_fs = fs_factory.Create(file_system,
-                                    lambda _, json: json_parse.Parse(json),
-                                    AvailabilityFinder,
-                                    category='features')
+    json_fs = self._compiled_fs_factory.ForJson(file_system)
     if version >= 28:
       # The _api_features.json file first appears in version 28 and should be
       # the most reliable for finding API availability.
-      available_channel = _GetChannelFromApiFeatures(api_name, features_fs)
+      available_channel = _GetChannelFromApiFeatures(api_name, json_fs)
     if version >= 20:
       # The _permission_features.json and _manifest_features.json files are
       # present in Chrome 20 and onwards. Use these if no information could be
       # found using _api_features.json.
       available_channel = available_channel or (
-          _GetChannelFromPermissionFeatures(api_name, features_fs)
-          or _GetChannelFromManifestFeatures(api_name, features_fs))
+          _GetChannelFromPermissionFeatures(api_name, json_fs)
+          or _GetChannelFromManifestFeatures(api_name, json_fs))
       if available_channel is not None:
         return available_channel == 'stable'
     if version >= 5:
       # Fall back to a check for file system existence if the API is not
       # stable in any of the _features.json files, or if the _features files
       # do not exist (version 19 and earlier).
-      return _HasApiSchema(api_name, file_system)
+      return _HasApiSchema(api_name,
+                           self._compiled_fs_factory.ForApiSchema(file_system))
 
   def _CheckChannelAvailability(self, api_name, file_system, channel_name):
-    '''Searches through the _features files in a given |file_system| and
-    determines whether or not an API is available on the given channel,
-    |channel_name|.
+    '''Searches through the _features files in a given |file_system|, falling
+    back to checking the file system for API schema existence, to determine
+    whether or not an API is available on the given channel, |channel_name|.
     '''
-    fs_factory = CompiledFileSystem.Factory(self._object_store_creator)
-    features_fs = fs_factory.Create(file_system,
-                                    lambda _, json: json_parse.Parse(json),
-                                    AvailabilityFinder,
-                                    category='features')
-    available_channel = (_GetChannelFromApiFeatures(api_name, features_fs)
-        or _GetChannelFromPermissionFeatures(api_name, features_fs)
-        or _GetChannelFromManifestFeatures(api_name, features_fs))
-    if available_channel is None and _HasApiSchema(api_name, file_system):
+    json_fs = self._compiled_fs_factory.ForJson(file_system)
+    schema_fs = self._compiled_fs_factory.ForApiSchema(file_system)
+    available_channel = (_GetChannelFromApiFeatures(api_name, json_fs)
+        or _GetChannelFromPermissionFeatures(api_name, json_fs)
+        or _GetChannelFromManifestFeatures(api_name, json_fs))
+    if available_channel is None and _HasApiSchema(api_name, schema_fs):
       # If an API is not represented in any of the _features files, but exists
       # in the filesystem, then assume it is available in this version.
       # The windows API is an example of this.
@@ -210,7 +204,10 @@
       return availability
 
     def check_api_availability(file_system, channel_info):
-      return self._CheckApiAvailability(api_name, file_system, channel_info)
+      return self._CheckApiAvailability(
+          api_name,
+          file_system,
+          channel_info)
 
     availability = self._file_system_iterator.Descending(
         self._branch_utility.GetChannelInfo('dev'),
@@ -229,12 +226,14 @@
     if availability_graph is not None:
       return availability_graph
 
+    def get_schema(api_name, file_system):
+      return _GetApiSchema(api_name,
+                           self._compiled_fs_factory.ForApiSchema(file_system))
 
     availability_graph = APISchemaGraph()
-    trunk_graph = APISchemaGraph(_GetApiSchema(api_name,
-                                               self._host_file_system))
+    trunk_graph = APISchemaGraph(get_schema(api_name, self._host_file_system))
     def update_availability_graph(file_system, channel_info):
-      version_graph = APISchemaGraph(_GetApiSchema(api_name, file_system))
+      version_graph = APISchemaGraph(get_schema(api_name, file_system))
       # Keep track of any new schema elements from this version by adding
       # them to |availability_graph|.
       #
diff --git a/chrome/common/extensions/docs/server2/availability_finder_test.py b/chrome/common/extensions/docs/server2/availability_finder_test.py
index 1540f36..0831a77 100755
--- a/chrome/common/extensions/docs/server2/availability_finder_test.py
+++ b/chrome/common/extensions/docs/server2/availability_finder_test.py
@@ -2,15 +2,13 @@
 # Copyright 2013 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-import json
-
 import os
 import sys
 import unittest
 
 from availability_finder import AvailabilityFinder
 from api_schema_graph import LookupResult
-from branch_utility import BranchUtility
+from branch_utility import BranchUtility, ChannelInfo
 from compiled_file_system import CompiledFileSystem
 from fake_url_fetcher import FakeUrlFetcher
 from host_file_system_iterator import HostFileSystemIterator
@@ -43,11 +41,13 @@
 
     def create_availability_finder(file_system_data):
       fake_host_fs_creator = FakeHostFileSystemProvider(file_system_data)
-      return AvailabilityFinder(HostFileSystemIterator(fake_host_fs_creator,
+      test_object_store = ObjectStoreCreator.ForTest()
+      return AvailabilityFinder(self._branch_utility,
+                                CompiledFileSystem.Factory(test_object_store),
+                                HostFileSystemIterator(fake_host_fs_creator,
                                                        self._branch_utility),
-                                ObjectStoreCreator.ForTest(),
-                                self._branch_utility,
-                                fake_host_fs_creator.GetTrunk())
+                                fake_host_fs_creator.GetTrunk(),
+                                test_object_store)
 
     self._avail_finder = create_availability_finder(CANNED_API_FILE_SYSTEM_DATA)
     self._node_avail_finder = create_availability_finder(TABS_SCHEMA_BRANCHES)
@@ -59,132 +59,108 @@
     # availability is being checked.
 
     # Testing a whitelisted API.
-    self.assertEquals('beta',
-        self._avail_finder.GetApiAvailability('declarativeWebRequest').channel)
-    self.assertEquals(27,
-        self._avail_finder.GetApiAvailability('declarativeWebRequest').version)
+    self.assertEquals(
+        ChannelInfo('beta', CANNED_BRANCHES[27], 27),
+        self._avail_finder.GetApiAvailability('declarativeWebRequest'))
 
     # Testing APIs found only by checking file system existence.
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('windows').channel)
-    self.assertEquals(23,
-        self._avail_finder.GetApiAvailability('windows').version)
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('tabs').channel)
-    self.assertEquals(18,
-        self._avail_finder.GetApiAvailability('tabs').version)
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('input.ime').channel)
-    self.assertEquals(18,
-        self._avail_finder.GetApiAvailability('input.ime').version)
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[23], 23),
+        self._avail_finder.GetApiAvailability('windows'))
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[18], 18),
+        self._avail_finder.GetApiAvailability('tabs'))
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[18], 18),
+        self._avail_finder.GetApiAvailability('input.ime'))
 
     # Testing API channel existence for _api_features.json.
     # Listed as 'dev' on |beta|, 'dev' on |dev|.
-    self.assertEquals('dev',
-        self._avail_finder.GetApiAvailability('systemInfo.stuff').channel)
-    self.assertEquals(28,
-        self._avail_finder.GetApiAvailability('systemInfo.stuff').version)
+    self.assertEquals(
+        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
+        self._avail_finder.GetApiAvailability('systemInfo.stuff'))
     # Listed as 'stable' on |beta|.
-    self.assertEquals('beta',
-        self._avail_finder.GetApiAvailability('systemInfo.cpu').channel)
-    self.assertEquals(27,
-        self._avail_finder.GetApiAvailability('systemInfo.cpu').version)
+    self.assertEquals(
+        ChannelInfo('beta', CANNED_BRANCHES[27], 27),
+        self._avail_finder.GetApiAvailability('systemInfo.cpu'))
 
     # Testing API channel existence for _manifest_features.json.
     # Listed as 'trunk' on all channels.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('sync').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('sync').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('sync'))
     # No records of API until |trunk|.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('history').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('history').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('history'))
     # Listed as 'dev' on |dev|.
-    self.assertEquals('dev',
-        self._avail_finder.GetApiAvailability('storage').channel)
-    self.assertEquals(28,
-        self._avail_finder.GetApiAvailability('storage').version)
+    self.assertEquals(
+        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
+        self._avail_finder.GetApiAvailability('storage'))
     # Stable in _manifest_features and into pre-18 versions.
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('pageAction').channel)
-    self.assertEquals(8,
-        self._avail_finder.GetApiAvailability('pageAction').version)
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[8], 8),
+        self._avail_finder.GetApiAvailability('pageAction'))
 
     # Testing API channel existence for _permission_features.json.
     # Listed as 'beta' on |trunk|.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('falseBetaAPI').version)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('falseBetaAPI').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('falseBetaAPI'))
     # Listed as 'trunk' on |trunk|.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('trunkAPI').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('trunkAPI').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('trunkAPI'))
     # Listed as 'trunk' on all development channels.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('declarativeContent').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('declarativeContent').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('declarativeContent'))
     # Listed as 'dev' on all development channels.
-    self.assertEquals('dev',
-        self._avail_finder.GetApiAvailability('bluetooth').channel)
-    self.assertEquals(28,
-        self._avail_finder.GetApiAvailability('bluetooth').version)
+    self.assertEquals(
+        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
+        self._avail_finder.GetApiAvailability('bluetooth'))
     # Listed as 'dev' on |dev|.
-    self.assertEquals('dev',
-        self._avail_finder.GetApiAvailability('cookies').channel)
-    self.assertEquals(28,
-        self._avail_finder.GetApiAvailability('cookies').version)
+    self.assertEquals(
+        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
+        self._avail_finder.GetApiAvailability('cookies'))
     # Treated as 'stable' APIs.
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('alarms').channel)
-    self.assertEquals(24,
-        self._avail_finder.GetApiAvailability('alarms').version)
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('bookmarks').channel)
-    self.assertEquals(21,
-        self._avail_finder.GetApiAvailability('bookmarks').version)
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[24], 24),
+        self._avail_finder.GetApiAvailability('alarms'))
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[21], 21),
+        self._avail_finder.GetApiAvailability('bookmarks'))
 
     # Testing older API existence using extension_api.json.
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('menus').channel)
-    self.assertEquals(6,
-        self._avail_finder.GetApiAvailability('menus').version)
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('idle').channel)
-    self.assertEquals(5,
-        self._avail_finder.GetApiAvailability('idle').version)
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[6], 6),
+        self._avail_finder.GetApiAvailability('menus'))
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[5], 5),
+        self._avail_finder.GetApiAvailability('idle'))
 
     # Switches between _features.json files across branches.
     # Listed as 'trunk' on all channels, in _api, _permission, or _manifest.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('contextMenus').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('contextMenus').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('contextMenus'))
     # Moves between _permission and _manifest as file system is traversed.
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('systemInfo.display').channel)
-    self.assertEquals(23,
-        self._avail_finder.GetApiAvailability('systemInfo.display').version)
-    self.assertEquals('stable',
-        self._avail_finder.GetApiAvailability('webRequest').channel)
-    self.assertEquals(17,
-        self._avail_finder.GetApiAvailability('webRequest').version)
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[23], 23),
+        self._avail_finder.GetApiAvailability('systemInfo.display'))
+    self.assertEquals(
+        ChannelInfo('stable', CANNED_BRANCHES[17], 17),
+        self._avail_finder.GetApiAvailability('webRequest'))
 
     # Mid-upgrade cases:
     # Listed as 'dev' on |beta| and 'beta' on |dev|.
-    self.assertEquals('dev',
-        self._avail_finder.GetApiAvailability('notifications').channel)
-    self.assertEquals(28,
-        self._avail_finder.GetApiAvailability('notifications').version)
+    self.assertEquals(
+        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
+        self._avail_finder.GetApiAvailability('notifications'))
     # Listed as 'beta' on |stable|, 'dev' on |beta| ... until |stable| on trunk.
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('events').channel)
-    self.assertEquals('trunk',
-        self._avail_finder.GetApiAvailability('events').version)
+    self.assertEquals(
+        ChannelInfo('trunk', 'trunk', 'trunk'),
+        self._avail_finder.GetApiAvailability('events'))
 
   def testGetApiNodeAvailability(self):
     availability_graph = self._node_avail_finder.GetApiNodeAvailability('tabs')
diff --git a/chrome/common/extensions/docs/server2/caching_file_system.py b/chrome/common/extensions/docs/server2/caching_file_system.py
index a203150..b4d1966 100644
--- a/chrome/common/extensions/docs/server2/caching_file_system.py
+++ b/chrome/common/extensions/docs/server2/caching_file_system.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import posixpath
 import sys
 
 from file_system import FileSystem, StatInfo, FileNotFoundError
@@ -62,10 +63,8 @@
     '''
     # Always stat the parent directory, since it will have the stat of the child
     # anyway, and this gives us an entire directory's stat info at once.
-    if path.endswith('/'):
-      dir_path = path
-    else:
-      dir_path, file_path = path.rsplit('/', 1)
+    dir_path, file_path = posixpath.split(path)
+    if dir_path and not dir_path.endswith('/'):
       dir_path += '/'
 
     # ... and we only ever need to cache the dir stat, too.
diff --git a/chrome/common/extensions/docs/server2/chroot_file_system.py b/chrome/common/extensions/docs/server2/chroot_file_system.py
new file mode 100644
index 0000000..3bf1028
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/chroot_file_system.py
@@ -0,0 +1,47 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import posixpath
+
+from docs_server_utils import StringIdentity
+from file_system import FileSystem
+from future import Gettable, Future
+
+
+class ChrootFileSystem(FileSystem):
+  '''ChrootFileSystem(fs, path) exposes a FileSystem whose root is |path| inside
+  |fs|, so ChrootFileSystem(fs, '/hello').Read(['/world']) is equivalent to
+  fs.Read(['/hello/world']) with the '/hello' prefix stripped from the result.
+  '''
+
+  def __init__(self, file_system, root):
+    '''Parameters:
+    |file_system| The FileSystem instance to transpose paths of.
+    |root|        The path to transpose all Read/Stat calls by.
+    '''
+    self._file_system = file_system
+    self._root = root.strip('/')
+
+  def Read(self, paths, binary=False):
+    # Maintain reverse mapping so the result can be mapped to the original
+    # paths given (the result from |file_system| will include |root| in the
+    # result, which would be wrong).
+    prefixed_paths = {}
+    def prefix(path):
+      prefixed = posixpath.join(self._root, path)
+      prefixed_paths[prefixed] = path
+      return prefixed
+    future_result = self._file_system.Read(
+        tuple(prefix(path) for path in paths), binary=binary)
+    def resolve():
+      return dict((prefixed_paths[path], content)
+                  for path, content in future_result.Get().iteritems())
+    return Future(delegate=Gettable(resolve))
+
+  def Stat(self, path):
+    return self._file_system.Stat(posixpath.join(self._root, path))
+
+  def GetIdentity(self):
+    return StringIdentity(
+        '%s/%s' % (self._file_system.GetIdentity(), self._root))
diff --git a/chrome/common/extensions/docs/server2/chroot_file_system_test.py b/chrome/common/extensions/docs/server2/chroot_file_system_test.py
new file mode 100755
index 0000000..b0fe033
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/chroot_file_system_test.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from chroot_file_system import ChrootFileSystem
+from file_system import FileNotFoundError, StatInfo
+from test_file_system import TestFileSystem
+
+
+def _SortListValues(dict_):
+  for value in dict_.itervalues():
+    if isinstance(value, list):
+      value.sort()
+  return dict_
+
+
+class ChrootFileSystemTest(unittest.TestCase):
+
+  def setUp(self):
+    self._test_fs = TestFileSystem({
+      '404.html': '404.html contents',
+      'apps': {
+        'a11y.html': 'a11y.html contents',
+        'about_apps.html': 'about_apps.html contents',
+        'fakedir': {
+          'file.html': 'file.html contents',
+        },
+      },
+      'extensions': {
+        'activeTab.html': 'activeTab.html contents',
+        'alarms.html': 'alarms.html contents',
+        'manifest': {
+          'moremanifest': {
+            'csp.html': 'csp.html contents',
+            'usb.html': 'usb.html contents',
+          },
+          'sockets.html': 'sockets.html contents',
+        },
+      },
+    })
+
+  def testRead(self):
+    for prefix in ('', '/'):
+      for suffix in ('', '/'):
+        chroot_fs = ChrootFileSystem(self._test_fs,
+                                     prefix + 'extensions/manifest' + suffix)
+        self.assertEqual({
+          'moremanifest/usb.html': 'usb.html contents',
+          '': ['moremanifest/', 'sockets.html', ],
+          'moremanifest/': ['csp.html', 'usb.html'],
+          'sockets.html': 'sockets.html contents',
+        }, _SortListValues(chroot_fs.Read(
+          ('moremanifest/usb.html', '', 'moremanifest/', 'sockets.html')
+        ).Get()))
+
+  def testEmptyRoot(self):
+    chroot_fs = ChrootFileSystem(self._test_fs, '')
+    self.assertEqual('404.html contents',
+                     chroot_fs.ReadSingle('404.html').Get())
+
+  def testStat(self):
+    self._test_fs.IncrementStat('extensions/manifest/', by=2)
+    self._test_fs.IncrementStat('extensions/manifest/moremanifest/csp.html')
+    for prefix in ('', '/'):
+      for suffix in ('', '/'):
+        chroot_fs = ChrootFileSystem(self._test_fs,
+                                     prefix + 'extensions' + suffix)
+        self.assertEqual(StatInfo('0', child_versions={
+          'activeTab.html': '0',
+          'alarms.html': '0',
+          'manifest/': '2',
+        }), chroot_fs.Stat(''))
+        self.assertEqual(StatInfo('0'), chroot_fs.Stat('activeTab.html'))
+        self.assertEqual(StatInfo('2', child_versions={
+          'moremanifest/': '0',
+          'sockets.html': '0',
+        }), chroot_fs.Stat('manifest/'))
+        self.assertEqual(StatInfo('0'), chroot_fs.Stat('manifest/sockets.html'))
+        self.assertEqual(StatInfo('0', child_versions={
+          'csp.html': '1',
+          'usb.html': '0',
+        }), chroot_fs.Stat('manifest/moremanifest/'))
+        self.assertEqual(StatInfo('1'),
+                         chroot_fs.Stat('manifest/moremanifest/csp.html'))
+        self.assertEqual(StatInfo('0'),
+                         chroot_fs.Stat('manifest/moremanifest/usb.html'))
+
+  def testIdentity(self):
+    chroot_fs1 = ChrootFileSystem(self._test_fs, '1')
+    chroot_fs1b = ChrootFileSystem(self._test_fs, '1')
+    chroot_fs2 = ChrootFileSystem(self._test_fs, '2')
+    self.assertNotEqual(self._test_fs.GetIdentity(), chroot_fs1.GetIdentity())
+    self.assertNotEqual(self._test_fs.GetIdentity(), chroot_fs2.GetIdentity())
+    self.assertNotEqual(chroot_fs1.GetIdentity(), chroot_fs2.GetIdentity())
+    self.assertEqual(chroot_fs1.GetIdentity(), chroot_fs1b.GetIdentity())
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/compiled_file_system.py b/chrome/common/extensions/docs/server2/compiled_file_system.py
index 51b9382..a51a732 100644
--- a/chrome/common/extensions/docs/server2/compiled_file_system.py
+++ b/chrome/common/extensions/docs/server2/compiled_file_system.py
@@ -4,32 +4,39 @@
 
 import sys
 
+import schema_util
 from file_system import FileNotFoundError
 from future import Gettable, Future
+from third_party.json_schema_compiler import json_parse
+from third_party.json_schema_compiler.memoize import memoize
 
 
 class _CacheEntry(object):
   def __init__(self, cache_data, version):
+
     self._cache_data = cache_data
     self.version = version
 
+
 class CompiledFileSystem(object):
-  """This class caches FileSystem data that has been processed.
-  """
+  '''This class caches FileSystem data that has been processed.
+  '''
+
   class Factory(object):
-    """A class to build a CompiledFileSystem backed by |file_system|.
-    """
+    '''A class to build a CompiledFileSystem backed by |file_system|.
+    '''
+
     def __init__(self, object_store_creator):
       self._object_store_creator = object_store_creator
 
     def Create(self, file_system, populate_function, cls, category=None):
-      """Creates a CompiledFileSystem view over |file_system| that populates
+      '''Creates a CompiledFileSystem view over |file_system| that populates
       its cache by calling |populate_function| with (path, data), where |data|
       is the data that was fetched from |path| in |file_system|.
 
       The namespace for the compiled file system is derived similar to
       ObjectStoreCreator: from |cls| along with an optional |category|.
-      """
+      '''
       assert isinstance(cls, type)
       assert not cls.__name__[0].islower()  # guard against non-class types
       full_name = [cls.__name__, file_system.GetIdentity()]
@@ -43,6 +50,27 @@
                                 create_object_store('file'),
                                 create_object_store('list'))
 
+    @memoize
+    def ForJson(self, file_system):
+      '''A CompiledFileSystem specifically for parsing JSON configuration data.
+      These are memoized over file systems tied to different branches.
+      '''
+      return self.Create(file_system,
+                         lambda _, data: json_parse.Parse(data),
+                         CompiledFileSystem,
+                         category='json')
+
+    @memoize
+    def ForApiSchema(self, file_system):
+      '''Creates a CompiledFileSystem for parsing raw JSON or IDL API schema
+      data and formatting it so that it can be used by other classes, such
+      as Model and APISchemaGraph.
+      '''
+      return self.Create(file_system,
+                         schema_util.ProcessSchema,
+                         CompiledFileSystem,
+                         category='api-schema')
+
   def __init__(self,
                file_system,
                populate_function,
@@ -109,11 +137,11 @@
     return Future(delegate=Gettable(resolve))
 
   def GetFromFile(self, path, binary=False):
-    """Calls |populate_function| on the contents of the file at |path|.  If
+    '''Calls |populate_function| on the contents of the file at |path|.  If
     |binary| is True then the file will be read as binary - but this will only
     apply for the first time the file is fetched; if already cached, |binary|
     will be ignored.
-    """
+    '''
     try:
       version = self._file_system.Stat(path).version
     except FileNotFoundError:
@@ -131,9 +159,9 @@
     return Future(delegate=Gettable(resolve))
 
   def GetFromFileListing(self, path):
-    """Calls |populate_function| on the listing of the files at |path|.
+    '''Calls |populate_function| on the listing of the files at |path|.
     Assumes that the path given is to a directory.
-    """
+    '''
     if not path.endswith('/'):
       path += '/'
 
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 9e75306..c77e536 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,4 +2,4 @@
 - description: Repopulates all cached data.
   url: /_cron
   schedule: every 5 minutes
-  target: 2-32-5
+  target: 2-33-0
diff --git a/chrome/common/extensions/docs/server2/cron_servlet.py b/chrome/common/extensions/docs/server2/cron_servlet.py
index cd62060..ea4b9b4 100644
--- a/chrome/common/extensions/docs/server2/cron_servlet.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet.py
@@ -14,7 +14,7 @@
 from data_source_registry import CreateDataSources
 from empty_dir_file_system import EmptyDirFileSystem
 from file_system_util import CreateURLsFromPaths
-from github_file_system import GithubFileSystem
+from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from object_store_creator import ObjectStoreCreator
 from render_servlet import RenderServlet
@@ -96,11 +96,8 @@
       return HostFileSystemProvider(object_store_creator,
                                     max_trunk_revision=max_trunk_revision)
 
-    def CreateAppSamplesFileSystem(self, object_store_creator):
-      # TODO(kalman): CachingFileSystem wrapper for GithubFileSystem, but it's
-      # not supported yet (see comment there).
-      return (EmptyDirFileSystem() if IsDevServer() else
-              GithubFileSystem.Create(object_store_creator))
+    def CreateGithubFileSystemProvider(self, object_store_creator):
+      return GithubFileSystemProvider(object_store_creator)
 
     def GetAppVersion(self):
       return GetAppVersion()
@@ -263,10 +260,10 @@
     branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
     host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
         object_store_creator, max_trunk_revision=revision)
-    app_samples_file_system = self._delegate.CreateAppSamplesFileSystem(
+    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
         object_store_creator)
     return ServerInstance(object_store_creator,
-                          app_samples_file_system,
                           CompiledFileSystem.Factory(object_store_creator),
                           branch_utility,
-                          host_file_system_provider)
+                          host_file_system_provider,
+                          github_file_system_provider)
diff --git a/chrome/common/extensions/docs/server2/cron_servlet_test.py b/chrome/common/extensions/docs/server2/cron_servlet_test.py
index 9f5e672..671a0d8 100755
--- a/chrome/common/extensions/docs/server2/cron_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet_test.py
@@ -9,6 +9,7 @@
 from app_yaml_helper import AppYamlHelper
 from cron_servlet import CronServlet
 from empty_dir_file_system import EmptyDirFileSystem
+from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from local_file_system import LocalFileSystem
 from mock_file_system import MockFileSystem
@@ -38,11 +39,11 @@
       self.file_systems.append(file_system)
       return file_system
     return HostFileSystemProvider(object_store_creator,
-                                 max_trunk_revision=max_trunk_revision,
-                                 constructor_for_test=constructor)
+                                  max_trunk_revision=max_trunk_revision,
+                                  constructor_for_test=constructor)
 
-  def CreateAppSamplesFileSystem(self, object_store_creator):
-    return EmptyDirFileSystem()
+  def CreateGithubFileSystemProvider(self, object_store_creator):
+    return GithubFileSystemProvider.ForEmpty()
 
   def GetAppVersion(self):
     return self._app_version
diff --git a/chrome/common/extensions/docs/server2/directory_zipper.py b/chrome/common/extensions/docs/server2/directory_zipper.py
new file mode 100644
index 0000000..daa96e7
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/directory_zipper.py
@@ -0,0 +1,49 @@
+# Copyright 2013 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.
+
+from io import BytesIO
+import posixpath
+from zipfile import ZipFile
+
+
+class DirectoryZipper(object):
+  '''Creates zip files of whole directories.
+  '''
+
+  def __init__(self, compiled_fs_factory, file_system):
+    self._file_system = file_system
+    self._zip_cache = compiled_fs_factory.Create(file_system,
+                                                 self._MakeZipFile,
+                                                 DirectoryZipper)
+
+  def _MakeZipFile(self, base_dir, files):
+    base_dir = base_dir.strip('/')
+    zip_bytes = BytesIO()
+    with ZipFile(zip_bytes, mode='w') as zip_file:
+      futures_with_name = [
+          (file_name,
+           self._file_system.ReadSingle(posixpath.join(base_dir, file_name),
+                                        binary=True))
+          for file_name in files]
+      for file_name, future in futures_with_name:
+        file_contents = future.Get()
+        if isinstance(file_contents, unicode):
+          # Data is sometimes already cached as unicode.
+          file_contents = file_contents.encode('utf8')
+        # We want e.g. basic.zip to expand to basic/manifest.json etc, not
+        # chrome/common/extensions/.../basic/manifest.json, so only use the
+        # end of the path component when writing into the zip file.
+        dir_name = posixpath.basename(base_dir)
+        zip_file.writestr(posixpath.join(dir_name, file_name), file_contents)
+    return zip_bytes.getvalue()
+
+  def Zip(self, path):
+    '''Creates a new zip file from the recursive contents of |path| as returned
+    by |_zip_cache|.
+
+    Paths within the zip file will be relative to and include the last
+    component of |path|, such that when zipping foo/bar containing baf.txt and
+    qux.txt will return a zip file which unzips to bar/baz.txt and bar/qux.txt.
+    '''
+    return self._zip_cache.GetFromFileListing(path)
diff --git a/chrome/common/extensions/docs/server2/directory_zipper_test.py b/chrome/common/extensions/docs/server2/directory_zipper_test.py
new file mode 100755
index 0000000..aa85f68
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/directory_zipper_test.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+from cStringIO import StringIO
+from zipfile import ZipFile
+
+from compiled_file_system import CompiledFileSystem
+from directory_zipper import DirectoryZipper
+from file_system import FileNotFoundError
+from test_file_system import TestFileSystem
+from object_store_creator import ObjectStoreCreator
+
+
+_TEST_DATA = {
+  'top': {
+    'one.txt': 'one.txt contents',
+    'two': {
+      'three.txt': 'three.txt contents',
+      'four.txt': 'four.txt contents',
+    },
+  }
+}
+
+
+class DirectoryZipperTest(unittest.TestCase):
+  def setUp(self):
+    self._directory_zipper = DirectoryZipper(
+        CompiledFileSystem.Factory(ObjectStoreCreator.ForTest()),
+        TestFileSystem(_TEST_DATA))
+
+  def testTopZip(self):
+    top_zip = ZipFile(StringIO(self._directory_zipper.Zip('top').Get()))
+    self.assertEqual(['top/one.txt', 'top/two/four.txt', 'top/two/three.txt'],
+                     sorted(top_zip.namelist()))
+    self.assertEqual('one.txt contents', top_zip.read('top/one.txt'))
+    self.assertEqual('three.txt contents', top_zip.read('top/two/three.txt'))
+    self.assertEqual('four.txt contents', top_zip.read('top/two/four.txt'))
+
+  def testTwoZip(self):
+    two_zip = ZipFile(StringIO(self._directory_zipper.Zip('top/two').Get()))
+    self.assertEqual(['two/four.txt', 'two/three.txt'],
+                     sorted(two_zip.namelist()))
+    self.assertEqual('three.txt contents', two_zip.read('two/three.txt'))
+    self.assertEqual('four.txt contents', two_zip.read('two/four.txt'))
+
+  def testNotFound(self):
+    self.assertRaises(FileNotFoundError,
+                      self._directory_zipper.Zip('notfound').Get)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/example_zipper.py b/chrome/common/extensions/docs/server2/example_zipper.py
deleted file mode 100644
index 578c99d..0000000
--- a/chrome/common/extensions/docs/server2/example_zipper.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2012 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.
-
-from io import BytesIO
-from zipfile import ZipFile
-
-class ExampleZipper(object):
-  '''This class creates a zip file given a samples directory.
-  '''
-  def __init__(self, compiled_fs_factory, file_system, base_path):
-    self._base_path = base_path.rstrip('/')
-    self._file_system = file_system
-    self._zip_cache = compiled_fs_factory.Create(file_system,
-                                                 self._MakeZipFile,
-                                                 ExampleZipper)
-
-  def _MakeZipFile(self, base_dir, files):
-    if 'manifest.json' not in files:
-      return None
-    zip_bytes = BytesIO()
-    zip_file = ZipFile(zip_bytes, mode='w')
-    try:
-      for file_name in files:
-        file_path = '%s%s' % (base_dir, file_name)
-        file_contents = self._file_system.ReadSingle(
-            file_path, binary=True).Get()
-        if isinstance(file_contents, unicode):
-          # Data is sometimes already cached as unicode.
-          file_contents = file_contents.encode('utf8')
-        # We want e.g. basic.zip to expand to basic/manifest.json etc, not
-        # chrome/common/extensions/.../basic/manifest.json, so only use the
-        # end of the path component when writing into the zip file.
-        redundant_prefix = '%s/' % base_dir.rstrip('/').rsplit('/', 1)[0]
-        zip_file.writestr(file_path[len(redundant_prefix):], file_contents)
-    finally:
-      zip_file.close()
-    return zip_bytes.getvalue()
-
-  def Create(self, path):
-    ''' Creates a new zip file from the recursive contents of |path|
-    as returned by |_zip_cache|.
-    Paths within the zip file are given relative to and including |path|.
-    '''
-    return self._zip_cache.GetFromFileListing(
-        '%s/%s' % (self._base_path, path.strip('/'))).Get()
diff --git a/chrome/common/extensions/docs/server2/example_zipper_test.py b/chrome/common/extensions/docs/server2/example_zipper_test.py
deleted file mode 100755
index e41fa67..0000000
--- a/chrome/common/extensions/docs/server2/example_zipper_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import sys
-import unittest
-
-from caching_file_system import CachingFileSystem
-from compiled_file_system import CompiledFileSystem
-from example_zipper import ExampleZipper
-from local_file_system import LocalFileSystem
-from object_store_creator import ObjectStoreCreator
-
-class ExampleZipperTest(unittest.TestCase):
-  def setUp(self):
-    object_store_creator = ObjectStoreCreator.ForTest()
-    self._file_system = CachingFileSystem(
-        LocalFileSystem(os.path.join(sys.path[0], 'test_data')),
-        object_store_creator)
-    self._example_zipper = ExampleZipper(
-        CompiledFileSystem.Factory(object_store_creator),
-        self._file_system,
-        'example_zipper')
-
-  def testCreateZip(self):
-    # Cache manifest.json as unicode and make sure ExampleZipper doesn't error.
-    self._file_system.ReadSingle('example_zipper/basic/manifest.json').Get()
-    self.assertTrue(len(self._example_zipper.Create('basic')) > 0)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/fake_fetchers.py b/chrome/common/extensions/docs/server2/fake_fetchers.py
index 1967bfb..8734d10 100644
--- a/chrome/common/extensions/docs/server2/fake_fetchers.py
+++ b/chrome/common/extensions/docs/server2/fake_fetchers.py
@@ -13,6 +13,7 @@
 import appengine_wrappers
 import url_constants
 
+
 class _FakeFetcher(object):
   def __init__(self, base_path):
     self._base_path = base_path
@@ -30,6 +31,7 @@
   def _Stat(self, path):
     return int(os.stat(os.path.join(self._base_path, path)).st_mtime)
 
+
 class FakeOmahaProxy(_FakeFetcher):
   def fetch(self, url):
     return self._ReadFile(os.path.join('server2',
@@ -37,6 +39,7 @@
                                        'branch_utility',
                                        'first.json'))
 
+
 class FakeOmahaHistory(_FakeFetcher):
   def fetch(self, url):
     return self._ReadFile(os.path.join('server2',
@@ -44,6 +47,7 @@
                                        'branch_utility',
                                        'second.json'))
 
+
 class FakeSubversionServer(_FakeFetcher):
   def __init__(self, base_path):
     _FakeFetcher.__init__(self, base_path)
@@ -71,6 +75,7 @@
     except IOError as e:
       return None
 
+
 class FakeViewvcServer(_FakeFetcher):
   def __init__(self, base_path):
     _FakeFetcher.__init__(self, base_path)
@@ -105,10 +110,12 @@
     except IOError as e:
       return None
 
+
 class FakeGithubStat(_FakeFetcher):
   def fetch(self, url):
     return '{ "commit": { "tree": { "sha": 0} } }'
 
+
 class FakeGithubZip(_FakeFetcher):
   def fetch(self, url):
     try:
@@ -120,6 +127,7 @@
     except IOError:
       return None
 
+
 class FakeRietveldAPI(_FakeFetcher):
   def __init__(self, base_path):
     _FakeFetcher.__init__(self, base_path)
@@ -136,6 +144,7 @@
     except IOError:
       return None
 
+
 class FakeRietveldTarball(_FakeFetcher):
   def __init__(self, base_path):
     _FakeFetcher.__init__(self, base_path)
@@ -151,6 +160,7 @@
     except IOError:
       return None
 
+
 def ConfigureFakeFetchers():
   '''Configure the fake fetcher paths relative to the docs directory.
   '''
@@ -160,8 +170,8 @@
     re.escape(url_constants.OMAHA_DEV_HISTORY): FakeOmahaHistory(docs),
     '%s/.*' % url_constants.SVN_URL: FakeSubversionServer(docs),
     '%s/.*' % url_constants.VIEWVC_URL: FakeViewvcServer(docs),
-    '%s/commits/.*' % url_constants.GITHUB_URL: FakeGithubStat(docs),
-    '%s/zipball' % url_constants.GITHUB_URL: FakeGithubZip(docs),
+    '%s/.*/commits/.*' % url_constants.GITHUB_REPOS: FakeGithubStat(docs),
+    '%s/.*/zipball' % url_constants.GITHUB_REPOS: FakeGithubZip(docs),
     '%s/api/.*' % url_constants.CODEREVIEW_SERVER: FakeRietveldAPI(docs),
     '%s/tarball/.*' % url_constants.CODEREVIEW_SERVER:
         FakeRietveldTarball(docs),
diff --git a/chrome/common/extensions/docs/server2/features_utility.py b/chrome/common/extensions/docs/server2/features_utility.py
index d8ca3e7..c7f9f62 100644
--- a/chrome/common/extensions/docs/server2/features_utility.py
+++ b/chrome/common/extensions/docs/server2/features_utility.py
@@ -29,17 +29,25 @@
   '''
   features = {}
 
-  for name, value in deepcopy(features_json).iteritems():
-    # Some feature names correspond to a list; force a list down to a single
-    # feature by removing entries that have a 'whitelist'.
-    if isinstance(value, list):
-      values = [subvalue for subvalue in value if not 'whitelist' in subvalue]
-      if values:
-        value = values[0]
-      else:
-        continue
+  def ignore_feature(name, value):
+    '''Returns true if this feature should be ignored. This is defined by the
+    presence of a 'whitelist' property for non-private APIs. Private APIs
+    shouldn't have whitelisted features ignored since they're inherently
+    private. Logic elsewhere makes sure not to list private APIs.
+    '''
+    return 'whitelist' in value and not name.endswith('Private')
 
-    if 'whitelist' in value:
+  for name, value in deepcopy(features_json).iteritems():
+    # Some feature names correspond to a list, typically because they're
+    # whitelisted in stable for certain extensions and available in dev for
+    # everybody else. Force a list down to a single feature by attempting to
+    # remove the entries that don't affect the typical usage of an API.
+    if isinstance(value, list):
+      available_values = [subvalue for subvalue in value
+                          if not ignore_feature(name, subvalue)]
+      value = available_values[0] if available_values else value[0]
+
+    if ignore_feature(name, value):
       continue
 
     features[name] = { 'platforms': [] }
diff --git a/chrome/common/extensions/docs/server2/github_file_system.py b/chrome/common/extensions/docs/server2/github_file_system.py
index 263397a..e2ca6f5 100644
--- a/chrome/common/extensions/docs/server2/github_file_system.py
+++ b/chrome/common/extensions/docs/server2/github_file_system.py
@@ -69,9 +69,9 @@
 
 class GithubFileSystem(FileSystem):
   @staticmethod
-  def Create(object_store_creator):
+  def CreateChromeAppsSamples(object_store_creator):
     return GithubFileSystem(
-        url_constants.GITHUB_URL,
+        '%s/GoogleChrome/chrome-app-samples' % url_constants.GITHUB_REPOS,
         blobstore.AppEngineBlobstore(),
         object_store_creator)
 
diff --git a/chrome/common/extensions/docs/server2/github_file_system_provider.py b/chrome/common/extensions/docs/server2/github_file_system_provider.py
new file mode 100644
index 0000000..b5e5c22
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/github_file_system_provider.py
@@ -0,0 +1,40 @@
+# Copyright 2013 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.
+
+from caching_file_system import CachingFileSystem
+from empty_dir_file_system import EmptyDirFileSystem
+from github_file_system import GithubFileSystem as OldGithubFileSystem
+from new_github_file_system import GithubFileSystem as NewGithubFileSystem
+
+
+class GithubFileSystemProvider(object):
+  '''Provides GithubFileSystems bound to an owner/repo pair.
+  '''
+
+  def __init__(self, object_store_creator):
+    self._object_store_creator = object_store_creator
+
+  def Create(self, owner, repo):
+    '''Creates a GithubFileSystem. For legacy reasons this is hacked
+    such that the apps samples returns the old GithubFileSystem.
+
+    |owner| is the owner of the GitHub account, e.g. 'GoogleChrome'.
+    |repo| is the repository name, e.g. 'devtools-docs'.
+    '''
+    if owner == 'GoogleChrome' and repo == 'chrome-app-samples':
+      # NOTE: The old GitHub file system implementation doesn't support being
+      # wrapped by a CachingFileSystem. It's also too slow to run on the dev
+      # server, since every app API page would need to read from it.
+      return OldGithubFileSystem.CreateChromeAppsSamples(
+          self._object_store_creator)
+    return CachingFileSystem(
+        NewGithubFileSystem.Create(owner, repo, self._object_store_creator),
+        self._object_store_creator)
+
+  @staticmethod
+  def ForEmpty():
+    class EmptyImpl(object):
+      def Create(self, owner, repo):
+        return EmptyDirFileSystem()
+    return EmptyImpl()
diff --git a/chrome/common/extensions/docs/server2/github_file_system_test.py b/chrome/common/extensions/docs/server2/github_file_system_test.py
index ea71069..655a7f2 100755
--- a/chrome/common/extensions/docs/server2/github_file_system_test.py
+++ b/chrome/common/extensions/docs/server2/github_file_system_test.py
@@ -22,7 +22,8 @@
     self._base_path = os.path.join(sys.path[0],
                                    'test_data',
                                    'github_file_system')
-    self._file_system = GithubFileSystem.Create(ObjectStoreCreator.ForTest())
+    self._file_system = GithubFileSystem.CreateChromeAppsSamples(
+        ObjectStoreCreator.ForTest())
 
   def _ReadLocalFile(self, filename):
     with open(os.path.join(self._base_path, filename), 'r') as f:
diff --git a/chrome/common/extensions/docs/server2/instance_servlet.py b/chrome/common/extensions/docs/server2/instance_servlet.py
index 974d70a..7447d14 100644
--- a/chrome/common/extensions/docs/server2/instance_servlet.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet.py
@@ -6,7 +6,7 @@
 from branch_utility import BranchUtility
 from compiled_file_system import CompiledFileSystem
 from empty_dir_file_system import EmptyDirFileSystem
-from github_file_system import GithubFileSystem
+from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from third_party.json_schema_compiler.memoize import memoize
 from render_servlet import RenderServlet
@@ -38,13 +38,13 @@
     host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
         object_store_creator,
         offline=True)
-    app_samples_file_system = self._delegate.CreateAppSamplesFileSystem(
+    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
         object_store_creator)
     return ServerInstance(object_store_creator,
-                          app_samples_file_system,
                           CompiledFileSystem.Factory(object_store_creator),
                           branch_utility,
-                          host_file_system_provider)
+                          host_file_system_provider,
+                          github_file_system_provider)
 
 class InstanceServlet(object):
   '''Servlet for running on normal AppEngine instances.
@@ -60,11 +60,8 @@
     def CreateHostFileSystemProvider(self, object_store_creator, **optargs):
       return HostFileSystemProvider(object_store_creator, **optargs)
 
-    def CreateAppSamplesFileSystem(self, object_store_creator):
-      # TODO(kalman): OfflineServerInstance wrapper for GithubFileSystem, but
-      # the cron job doesn't crawl the samples yet.
-      return (EmptyDirFileSystem() if IsDevServer() else
-              GithubFileSystem.Create(object_store_creator))
+    def CreateGithubFileSystemProvider(self, object_store_creator):
+      return GithubFileSystemProvider(object_store_creator)
 
   @staticmethod
   def GetConstructor(delegate_for_test=None):
diff --git a/chrome/common/extensions/docs/server2/instance_servlet_test.py b/chrome/common/extensions/docs/server2/instance_servlet_test.py
index 3a2b999..8643f57 100755
--- a/chrome/common/extensions/docs/server2/instance_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet_test.py
@@ -6,15 +6,13 @@
 import unittest
 
 from empty_dir_file_system import EmptyDirFileSystem
+from github_file_system_provider import GithubFileSystemProvider
 from instance_servlet import InstanceServlet
 from servlet import Request
 from fail_on_access_file_system import FailOnAccessFileSystem
 from test_branch_utility import TestBranchUtility
 from test_util import DisableLogging
 
-# XXX(kalman): what is this test supposed to be?
-# Create a test host file system creator which failz?
-
 # NOTE(kalman): The ObjectStore created by the InstanceServlet is backed onto
 # our fake AppEngine memcache/datastore, so the tests aren't isolated.
 class _TestDelegate(InstanceServlet.Delegate):
@@ -24,10 +22,15 @@
   def CreateBranchUtility(self, object_store_creator):
     return TestBranchUtility.CreateWithCannedData()
 
-  def CreateAppSamplesFileSystem(self, object_store_creator):
-    return EmptyDirFileSystem()
+  def CreateGithubFileSystemProvider(self, object_store_creator):
+    return GithubFileSystemProvider.ForEmpty()
 
 class InstanceServletTest(unittest.TestCase):
+  '''Tests that if the file systems underlying the docserver's data fail,
+  the instance servlet still returns 404s or 301s with a best-effort.
+  It should never return a 500 (i.e. crash).
+  '''
+
   @DisableLogging('warning')
   def testHostFileSystemNotAccessed(self):
     delegate = _TestDelegate(FailOnAccessFileSystem)
diff --git a/chrome/common/extensions/docs/server2/new_github_file_system.py b/chrome/common/extensions/docs/server2/new_github_file_system.py
index 27c4be3..40fa8ae 100644
--- a/chrome/common/extensions/docs/server2/new_github_file_system.py
+++ b/chrome/common/extensions/docs/server2/new_github_file_system.py
@@ -5,6 +5,7 @@
 import json
 import logging
 from cStringIO import StringIO
+import posixpath
 import sys
 from zipfile import BadZipfile, ZipFile
 
@@ -42,7 +43,7 @@
     specified by |owner| and |repo|.
     '''
     return GithubFileSystem(
-        url_constants.NEW_GITHUB_URL,
+        url_constants.GITHUB_REPOS,
         owner,
         repo,
         object_store_creator,
@@ -159,8 +160,8 @@
 
     reads = {}
     for path in paths:
-      full_path = prefix + path
-      if path.endswith('/'):  # If path is a directory...
+      full_path = posixpath.join(prefix, path)
+      if path == '' or path.endswith('/'):  # If path is a directory...
         trimmed_paths = []
         for f in filter(lambda s: s.startswith(full_path), names):
           if not '/' in f[len(full_path):-1] and not f == full_path:
@@ -188,14 +189,15 @@
     stat versions are always 0.
     '''
     # Trim off the zip file's name.
-    trimmed = ['/' + f.split('/', 1)[1] for f in self._GetNamelist()]
+    path = path.lstrip('/')
+    trimmed = [f.split('/', 1)[1] for f in self._GetNamelist()]
 
     if path not in trimmed:
-      raise FileNotFoundError("No stat found for '%s'" % path)
+      raise FileNotFoundError("No stat found for '%s' in %s" % (path, trimmed))
 
     version = self._GetVersion()
     child_paths = {}
-    if path.endswith('/'):
+    if path == '' or path.endswith('/'):
       # Deal with a directory
       for f in filter(lambda s: s.startswith(path), trimmed):
         filename = f[len(path):]
diff --git a/chrome/common/extensions/docs/server2/new_github_file_system_test.py b/chrome/common/extensions/docs/server2/new_github_file_system_test.py
index 02c21d8..513a024 100755
--- a/chrome/common/extensions/docs/server2/new_github_file_system_test.py
+++ b/chrome/common/extensions/docs/server2/new_github_file_system_test.py
@@ -41,10 +41,10 @@
     self._gfs.Refresh().Get()
     self.assertEqual(
         sorted(['requirements.txt', '.gitignore', 'README.md', 'src/']),
-        sorted(self._gfs.ReadSingle('/').Get()))
+        sorted(self._gfs.ReadSingle('').Get()))
     self.assertEqual(
         sorted(['__init__.notpy', 'hello.notpy']),
-        sorted(self._gfs.ReadSingle('/src/').Get()))
+        sorted(self._gfs.ReadSingle('src/').Get()))
 
   def testReadFile(self):
     self._gfs.Refresh().Get()
@@ -52,24 +52,24 @@
       '# Compiled Python files\n'
       '*.pyc\n'
     )
-    self.assertEqual(expected, self._gfs.ReadSingle('/.gitignore').Get())
+    self.assertEqual(expected, self._gfs.ReadSingle('.gitignore').Get())
 
   def testMultipleReads(self):
     self._gfs.Refresh().Get()
     self.assertEqual(
-        self._gfs.ReadSingle('/requirements.txt').Get(),
-        self._gfs.ReadSingle('/requirements.txt').Get())
+        self._gfs.ReadSingle('requirements.txt').Get(),
+        self._gfs.ReadSingle('requirements.txt').Get())
 
   def testReads(self):
     self._gfs.Refresh().Get()
     expected = {
-        '/src/': sorted(['hello.notpy', '__init__.notpy']),
-        '/': sorted(['requirements.txt', '.gitignore', 'README.md', 'src/'])
+        'src/': sorted(['hello.notpy', '__init__.notpy']),
+        '': sorted(['requirements.txt', '.gitignore', 'README.md', 'src/'])
     }
 
-    read = self._gfs.Read(['/', '/src/']).Get()
-    self.assertEqual(expected['/src/'], sorted(read['/src/']))
-    self.assertEqual(expected['/'], sorted(read['/']))
+    read = self._gfs.Read(['', 'src/']).Get()
+    self.assertEqual(expected['src/'], sorted(read['src/']))
+    self.assertEqual(expected[''], sorted(read['']))
 
   def testStat(self):
     self._gfs.Refresh().Get()
@@ -78,37 +78,37 @@
       '__init__.notpy': StatInfo(FAKE_HASH)
     })
 
-    self.assertEqual(StatInfo(FAKE_HASH), self._gfs.Stat('/README.md'))
-    self.assertEqual(StatInfo(FAKE_HASH), self._gfs.Stat('/src/hello.notpy'))
-    self.assertEqual(dir_stat, self._gfs.Stat('/src/'))
+    self.assertEqual(StatInfo(FAKE_HASH), self._gfs.Stat('README.md'))
+    self.assertEqual(StatInfo(FAKE_HASH), self._gfs.Stat('src/hello.notpy'))
+    self.assertEqual(dir_stat, self._gfs.Stat('src/'))
 
   def testBadReads(self):
     self._gfs.Refresh().Get()
-    self.assertRaises(FileNotFoundError, self._gfs.Stat, '/DONT_README.md')
+    self.assertRaises(FileNotFoundError, self._gfs.Stat, 'DONT_README.md')
     self.assertRaises(FileNotFoundError,
-                      self._gfs.ReadSingle('/DONT_README.md').Get)
+                      self._gfs.ReadSingle('DONT_README.md').Get)
 
   def testCachingFileSystem(self):
     self._cgfs.Refresh().Get()
-    initial_cgfs_read_one = self._cgfs.ReadSingle('/src/hello.notpy').Get()
+    initial_cgfs_read_one = self._cgfs.ReadSingle('src/hello.notpy').Get()
 
     self.assertEqual(initial_cgfs_read_one,
-                     self._gfs.ReadSingle('/src/hello.notpy').Get())
+                     self._gfs.ReadSingle('src/hello.notpy').Get())
     self.assertEqual(initial_cgfs_read_one,
-                     self._cgfs.ReadSingle('/src/hello.notpy').Get())
+                     self._cgfs.ReadSingle('src/hello.notpy').Get())
 
     initial_cgfs_read_two = self._cgfs.Read(
-        ['/README.md', '/requirements.txt']).Get()
+        ['README.md', 'requirements.txt']).Get()
 
     self.assertEqual(
         initial_cgfs_read_two,
-        self._gfs.Read(['/README.md', '/requirements.txt']).Get())
+        self._gfs.Read(['README.md', 'requirements.txt']).Get())
     self.assertEqual(
         initial_cgfs_read_two,
-        self._cgfs.Read(['/README.md', '/requirements.txt']).Get())
+        self._cgfs.Read(['README.md', 'requirements.txt']).Get())
 
   def testWithoutRefresh(self):
-    self.assertRaises(FileNotFoundError, self._gfs.ReadSingle('/src/').Get)
+    self.assertRaises(FileNotFoundError, self._gfs.ReadSingle('src/').Get)
 
   def testRefresh(self):
     def make_sha_json(hash_value):
@@ -146,8 +146,8 @@
         'changing-repo', FakeURLFSFetcher.Create(test_file_system), path='')
 
     gfs.Refresh().Get()
-    initial_dir_read = sorted(gfs.ReadSingle('/').Get())
-    initial_file_read = gfs.ReadSingle('/dir/file1').Get()
+    initial_dir_read = sorted(gfs.ReadSingle('').Get())
+    initial_file_read = gfs.ReadSingle('dir/file1').Get()
 
     # Change the underlying data.
     files['zipfile/hello.txt'] = 'hello world again'
@@ -158,15 +158,15 @@
         make_sha_json(FAKE_HASH + 'hash'))
 
     # Check that changes have not effected the file system yet.
-    self.assertEqual(initial_dir_read, sorted(gfs.ReadSingle('/').Get()))
-    self.assertEqual(initial_file_read, gfs.ReadSingle('/dir/file1').Get())
+    self.assertEqual(initial_dir_read, sorted(gfs.ReadSingle('').Get()))
+    self.assertEqual(initial_file_read, gfs.ReadSingle('dir/file1').Get())
 
     gfs.Refresh().Get()
 
     # Check that the changes have effected the file system.
-    self.assertTrue('new-file' in gfs.ReadSingle('/').Get())
+    self.assertTrue('new-file' in gfs.ReadSingle('').Get())
     self.assertEqual(files['zipfile/dir/file1'],
-                     gfs.ReadSingle('/dir/file1').Get())
+                     gfs.ReadSingle('dir/file1').Get())
 
 
 if __name__ == '__main__':
diff --git a/chrome/common/extensions/docs/server2/patch_servlet.py b/chrome/common/extensions/docs/server2/patch_servlet.py
index 2fd673d..fba20b4 100644
--- a/chrome/common/extensions/docs/server2/patch_servlet.py
+++ b/chrome/common/extensions/docs/server2/patch_servlet.py
@@ -61,11 +61,11 @@
     branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
 
     return ServerInstance(object_store_creator,
-                          self._delegate.CreateAppSamplesFileSystem(
-                              object_store_creator),
                           combined_compiled_fs_factory,
                           branch_utility,
                           patched_host_file_system_provider,
+                          self._delegate.CreateGithubFileSystemProvider(
+                              object_store_creator),
                           base_path='/_patch/%s/' % self._issue)
 
 class PatchServlet(Servlet):
diff --git a/chrome/common/extensions/docs/server2/patch_servlet_test.py b/chrome/common/extensions/docs/server2/patch_servlet_test.py
index e61da4e..182f87d 100755
--- a/chrome/common/extensions/docs/server2/patch_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/patch_servlet_test.py
@@ -7,6 +7,7 @@
 
 from empty_dir_file_system import EmptyDirFileSystem
 from fake_fetchers import ConfigureFakeFetchers
+from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from patch_servlet import PatchServlet
 from render_servlet import RenderServlet
@@ -22,15 +23,15 @@
     return ServerInstance.ForLocal()
 
 class _PatchServletDelegate(RenderServlet.Delegate):
-  def CreateAppSamplesFileSystem(self, object_store_creator):
-    return EmptyDirFileSystem()
-
   def CreateBranchUtility(self, object_store_creator):
     return TestBranchUtility.CreateWithCannedData()
 
   def CreateHostFileSystemProvider(self, object_store_creator, **optargs):
     return HostFileSystemProvider.ForLocal(object_store_creator, **optargs)
 
+  def CreateGithubFileSystemProvider(self, object_store_creator):
+    return GithubFileSystemProvider.ForEmpty()
+
 class PatchServletTest(unittest.TestCase):
   def setUp(self):
     ConfigureFakeFetchers()
diff --git a/chrome/common/extensions/docs/server2/render_servlet.py b/chrome/common/extensions/docs/server2/render_servlet.py
index 10a9b52..6547c67 100644
--- a/chrome/common/extensions/docs/server2/render_servlet.py
+++ b/chrome/common/extensions/docs/server2/render_servlet.py
@@ -63,8 +63,9 @@
       if path.endswith('/'):
         pass
       elif fnmatch(path, 'extensions/examples/*.zip'):
-        content = server_instance.example_zipper.Create(
-            path[len('extensions/'):-len('.zip')])
+        zip_path = (
+            svn_constants.DOCS_PATH + path[len('extensions'):-len('.zip')])
+        content = server_instance.directory_zipper.Zip(zip_path).Get()
         content_type = 'application/zip'
       elif path.startswith('extensions/examples/'):
         mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
diff --git a/chrome/common/extensions/docs/server2/samples_data_source.py b/chrome/common/extensions/docs/server2/samples_data_source.py
index 449914b..9a57fba 100644
--- a/chrome/common/extensions/docs/server2/samples_data_source.py
+++ b/chrome/common/extensions/docs/server2/samples_data_source.py
@@ -191,21 +191,9 @@
     only the samples that use the API |api_name|. |key| is either 'apps' or
     'extensions'.
     '''
-    api_search = api_name.replace('.', '_') + '_'
-    samples_list = []
-    try:
-      for sample in self.get(key):
-        api_calls_unix = [model.UnixName(call['name'])
-                          for call in sample['api_calls']]
-        for call in api_calls_unix:
-          if call.startswith(api_search):
-            samples_list.append(sample)
-            break
-    except NotImplementedError:
-      # If we're testing, the GithubFileSystem can't fetch samples.
-      # Bug: http://crbug.com/141910
-      return []
-    return samples_list
+    return [sample for sample in self.get(key) if any(
+        call['name'].startswith(api_name + '.')
+        for call in sample['api_calls'])]
 
   def _CreateSamplesDict(self, key):
     if key == 'apps':
diff --git a/chrome/common/extensions/docs/server2/schema_util.py b/chrome/common/extensions/docs/server2/schema_util.py
new file mode 100644
index 0000000..60c9f31
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/schema_util.py
@@ -0,0 +1,118 @@
+# Copyright 2013 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.
+
+from collections import defaultdict, Mapping
+
+from third_party.json_schema_compiler import json_parse, idl_schema, idl_parser
+
+
+def RemoveNoDocs(item):
+  '''Removes nodes that should not be rendered from an API schema.
+  '''
+  if json_parse.IsDict(item):
+    if item.get('nodoc', False):
+      return True
+    for key, value in item.items():
+      if RemoveNoDocs(value):
+        del item[key]
+  elif type(item) == list:
+    to_remove = []
+    for i in item:
+      if RemoveNoDocs(i):
+        to_remove.append(i)
+    for i in to_remove:
+      item.remove(i)
+  return False
+
+
+def DetectInlineableTypes(schema):
+  '''Look for documents that are only referenced once and mark them as inline.
+  Actual inlining is done by _InlineDocs.
+  '''
+  if not schema.get('types'):
+    return
+
+  ignore = frozenset(('value', 'choices'))
+  refcounts = defaultdict(int)
+  # Use an explicit stack instead of recursion.
+  stack = [schema]
+
+  while stack:
+    node = stack.pop()
+    if isinstance(node, list):
+      stack.extend(node)
+    elif isinstance(node, Mapping):
+      if '$ref' in node:
+        refcounts[node['$ref']] += 1
+      stack.extend(v for k, v in node.iteritems() if k not in ignore)
+
+  for type_ in schema['types']:
+    if not 'noinline_doc' in type_:
+      if refcounts[type_['id']] == 1:
+        type_['inline_doc'] = True
+
+
+def InlineDocs(schema):
+  '''Replace '$ref's that refer to inline_docs with the json for those docs.
+  '''
+  types = schema.get('types')
+  if types is None:
+    return
+
+  inline_docs = {}
+  types_without_inline_doc = []
+
+  # Gather the types with inline_doc.
+  for type_ in types:
+    if type_.get('inline_doc'):
+      inline_docs[type_['id']] = type_
+      for k in ('description', 'id', 'inline_doc'):
+        type_.pop(k, None)
+    else:
+      types_without_inline_doc.append(type_)
+  schema['types'] = types_without_inline_doc
+
+  def apply_inline(node):
+    if isinstance(node, list):
+      for i in node:
+        apply_inline(i)
+    elif isinstance(node, Mapping):
+      ref = node.get('$ref')
+      if ref and ref in inline_docs:
+        node.update(inline_docs[ref])
+        del node['$ref']
+      for k, v in node.iteritems():
+        apply_inline(v)
+
+  apply_inline(schema)
+
+
+def ProcessSchema(path, file_data):
+  '''Parses |file_data| using a method determined by checking the
+  extension of the file at the given |path|. Then, trims 'nodoc' and handles
+  inlineable types from the parsed schema data.
+  '''
+  def trim_and_inline(schema, is_idl=False):
+    '''Modifies an API schema in place by removing nodes that shouldn't be
+    documented and inlining schema types that are only referenced once.
+    '''
+    if RemoveNoDocs(schema):
+      # A return of True signifies that the entire schema should not be
+      # documented. Otherwise, only nodes that request 'nodoc' are removed.
+      return None
+    if is_idl:
+      DetectInlineableTypes(schema)
+    InlineDocs(schema)
+    return schema
+
+  if path.endswith('.idl'):
+    idl = idl_schema.IDLSchema(idl_parser.IDLParser().ParseData(file_data))
+    return trim_and_inline(idl.process()[0], is_idl=True)
+
+  schemas = json_parse.Parse(file_data)
+  for schema in schemas:
+    # Schemas could consist of one API schema (data for a specific API file)
+    # or multiple (data from extension_api.json).
+    trim_and_inline(schema)
+  return schemas
diff --git a/chrome/common/extensions/docs/server2/schema_util_test.py b/chrome/common/extensions/docs/server2/schema_util_test.py
new file mode 100755
index 0000000..8116f22
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/schema_util_test.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+from copy import deepcopy
+
+from schema_util import RemoveNoDocs, DetectInlineableTypes, InlineDocs
+
+
+class SchemaUtilTest(unittest.TestCase):
+
+  def testRemoveNoDocs(self):
+    expected_nodoc = [
+      {
+        'name': 'B',
+        'list': [
+          {
+            'name': 'B2'
+          }
+        ]
+      },
+      {
+        'name': 'D',
+        'nodoc': False
+      },
+      {
+        'name': 'E',
+        'items1': [
+          {
+            'name': 'E1',
+            'items': [
+              {
+                'name': 'E1.3'
+              }
+            ]
+          },
+          {
+            'name': 'E2'
+          }
+        ]
+      }
+    ]
+
+    nodoc_data = [
+      {
+        'name': 'A',
+        'nodoc': True
+      },
+      {
+        'name': 'B',
+        'list': [
+          {
+            'name': 'B1',
+            'nodoc': True
+          },
+          {
+            'name': 'B2'
+          },
+          {
+            'name': 'B3',
+            'nodoc': True
+          }
+        ]
+      },
+      {
+        'name': 'C',
+        'nodoc': True
+      },
+      {
+        'name': 'D',
+        'nodoc': False
+      },
+      {
+        'name': 'E',
+        'dict': {
+          'name': 'Ed',
+          'nodoc': True
+        },
+        'items1': [
+          {
+            'name': 'E1',
+            'items': [
+              {
+                'name': 'E1.1',
+                'nodoc': True
+              },
+              {
+                'name': 'E1.2',
+                'nodoc': True
+              },
+              {
+                'name': 'E1.3'
+              }
+            ]
+          },
+          {
+            'name': 'E2'
+          },
+          {
+            'name': 'E3',
+            'nodoc': True
+          }
+        ]
+      }
+    ]
+
+    RemoveNoDocs(nodoc_data)
+    self.assertEquals(expected_nodoc, nodoc_data)
+
+  def testInlineDocs(self):
+    schema = {
+      'namespace': 'storage',
+      'properties': {
+        'key2': {
+          'description': 'second key',
+          '$ref': 'Key'
+        },
+        'key1': {
+          'description': 'first key',
+          '$ref': 'Key'
+        }
+      },
+      'types': [
+        {
+          'inline_doc': True,
+          'type': 'string',
+          'id': 'Key',  # Should be inlined into both properties and be removed
+                        # from types.
+          'description': 'This is a key.',  # This description should disappear.
+          'marker': True  # This should appear three times in the output.
+        },
+        {
+          'items': {
+            '$ref': 'Key'
+          },
+          'type': 'array',
+          'id': 'KeyList',
+          'description': 'A list of keys'
+        }
+      ]
+    }
+
+    expected_schema = {
+      'namespace': 'storage',
+      'properties': {
+        'key2': {
+          'marker': True,
+          'type': 'string',
+          'description': 'second key'
+        },
+        'key1': {
+          'marker': True,
+          'type': 'string',
+          'description': 'first key'
+        }
+      },
+      'types': [
+        {
+          'items': {
+            'marker': True,
+            'type': 'string'
+          },
+          'type': 'array',
+          'id': 'KeyList',
+          'description': 'A list of keys'
+        }
+      ]
+    }
+
+    inlined_schema = deepcopy(schema)
+    InlineDocs(inlined_schema)
+    self.assertEqual(expected_schema, inlined_schema)
+
+  def testDetectInline(self):
+    schema = {
+      'types': [
+        {
+          'id': 'Key',
+          'items': {
+            '$ref': 'Value'
+          }
+        },
+        {
+          'id': 'Value',
+          'marker': True
+        }
+      ]
+    }
+
+    expected_schema = {
+      'types': [
+        {
+          'id': 'Key',
+          'items': {
+            'marker': True,
+          }
+        }
+      ]
+    }
+
+    DetectInlineableTypes(schema)
+    InlineDocs(schema)
+    self.assertEqual(expected_schema, schema)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
index 225ed61..483f0d4 100644
--- a/chrome/common/extensions/docs/server2/server_instance.py
+++ b/chrome/common/extensions/docs/server2/server_instance.py
@@ -4,12 +4,14 @@
 
 from api_data_source import APIDataSource
 from api_list_data_source import APIListDataSource
+from api_models import APIModels
 from appengine_wrappers import IsDevServer
 from availability_finder import AvailabilityFinder
 from compiled_file_system import CompiledFileSystem
+from directory_zipper import DirectoryZipper
 from empty_dir_file_system import EmptyDirFileSystem
-from example_zipper import ExampleZipper
 from features_bundle import FeaturesBundle
+from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from host_file_system_iterator import HostFileSystemIterator
 from intro_data_source import IntroDataSource
@@ -27,16 +29,14 @@
 
   def __init__(self,
                object_store_creator,
-               app_samples_file_system,
                compiled_fs_factory,
                branch_utility,
                host_file_system_provider,
+               github_file_system_provider,
                base_path='/'):
     '''
     |object_store_creator|
         The ObjectStoreCreator used to create almost all caches.
-    |app_samples_file_system|
-        The FileSystem instance which hosts the App samples.
     |compiled_fs_factory|
         Factory used to create CompiledFileSystems, a higher-level cache type
         than ObjectStores. This can usually be derived from just
@@ -47,19 +47,21 @@
     |host_file_system_provider|
         Creates FileSystem instances which host the server at alternative
         revisions.
+    |github_file_system_provider|
+        Creates FileSystem instances backed by GitHub.
     |base_path|
         The path which all HTML is generated relative to. Usually this is /
         but some servlets need to override this.
     '''
     self.object_store_creator = object_store_creator
 
-    self.app_samples_file_system = app_samples_file_system
-
     self.compiled_fs_factory = compiled_fs_factory
 
     self.host_file_system_provider = host_file_system_provider
     host_fs_at_trunk = host_file_system_provider.GetTrunk()
 
+    self.github_file_system_provider = github_file_system_provider
+
     assert base_path.startswith('/') and base_path.endswith('/')
     self.base_path = base_path
 
@@ -72,12 +74,18 @@
         self.compiled_fs_factory,
         self.object_store_creator)
 
-    self.availability_finder = AvailabilityFinder(
-        self.host_file_system_iterator,
-        object_store_creator,
-        branch_utility,
+    self.api_models = APIModels(
+        self.features_bundle,
+        self.compiled_fs_factory,
         host_fs_at_trunk)
 
+    self.availability_finder = AvailabilityFinder(
+        branch_utility,
+        compiled_fs_factory,
+        self.host_file_system_iterator,
+        host_fs_at_trunk,
+        object_store_creator)
+
     self.api_list_data_source_factory = APIListDataSource.Factory(
         self.compiled_fs_factory,
         host_fs_at_trunk,
@@ -104,11 +112,14 @@
     # async fetch, so disable them.
     if IsDevServer():
       extension_samples_fs = EmptyDirFileSystem()
+      app_samples_fs = EmptyDirFileSystem()
     else:
       extension_samples_fs = host_fs_at_trunk
+      app_samples_fs = github_file_system_provider.Create(
+          'GoogleChrome', 'chrome-app-samples')
     self.samples_data_source_factory = SamplesDataSource.Factory(
         extension_samples_fs,
-        self.app_samples_file_system,
+        app_samples_fs,
         CompiledFileSystem.Factory(object_store_creator),
         self.ref_resolver_factory,
         svn_constants.EXAMPLES_PATH,
@@ -123,10 +134,9 @@
         self.ref_resolver_factory,
         [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH])
 
-    self.example_zipper = ExampleZipper(
+    self.directory_zipper = DirectoryZipper(
         self.compiled_fs_factory,
-        host_fs_at_trunk,
-        svn_constants.DOCS_PATH)
+        host_fs_at_trunk)
 
     self.path_canonicalizer = PathCanonicalizer(
         self.compiled_fs_factory,
@@ -160,11 +170,11 @@
   def ForTest(file_system, base_path='/'):
     object_store_creator = ObjectStoreCreator.ForTest()
     return ServerInstance(object_store_creator,
-                          EmptyDirFileSystem(),
                           CompiledFileSystem.Factory(object_store_creator),
                           TestBranchUtility.CreateWithCannedData(),
                           HostFileSystemProvider.ForTest(file_system,
                                                          object_store_creator),
+                          GithubFileSystemProvider.ForEmpty(),
                           base_path=base_path)
 
   @staticmethod
@@ -175,7 +185,7 @@
         object_store_creator)
     return ServerInstance(
         object_store_creator,
-        EmptyDirFileSystem(),
         CompiledFileSystem.Factory(object_store_creator),
         TestBranchUtility.CreateWithCannedData(),
-        host_file_system_provider)
+        host_file_system_provider,
+        GithubFileSystemProvider.ForEmpty())
diff --git a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/icon.png b/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/icon.png
deleted file mode 100644
index 84c4be3..0000000
--- a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/manifest.json b/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/manifest.json
deleted file mode 100644
index a42819b..0000000
--- a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "My Bookmarks",
-  "version": "1.0",
-  "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.",
-  "permissions": [
-    "bookmarks", "tabs"
-  ],
-  "browser_action": {
-      "default_title": "My Bookmarks.",
-      "default_icon": "icon.png",
-      "default_popup": "popup.html"
-  },
-  "manifest_version": 2,
-  "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
-}
diff --git a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.html b/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.html
deleted file mode 100644
index 9baa86e..0000000
--- a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
-<head>
-<link type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css" rel="stylesheet">
-<style>
-div, td, th { color: black; }
-</style>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
-<script src="popup.js"></script>
-<script>
-</script>
-</head>
-<body style="width: 400px">
-<div>Search Bookmarks: <input id="search"></div>
-<div id="bookmarks"></div>
-<div id="editdialog"></div>
-<div id="deletedialog"></div>
-<div id="adddialog"></div>
-</body>
-</html>
diff --git a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.js b/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.js
deleted file mode 100644
index ca72daa..0000000
--- a/chrome/common/extensions/docs/server2/test_data/example_zipper/basic/popup.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2012 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.
-
-// Search the bookmarks when entering the search keyword.
-$(function() {
-  $('#search').change(function() {
-     $('#bookmarks').empty();
-     dumpBookmarks($('#search').val());
-  });
-});
-// Traverse the bookmark tree, and print the folder and nodes.
-function dumpBookmarks(query) {
-  var bookmarkTreeNodes = chrome.bookmarks.getTree(
-    function(bookmarkTreeNodes) {
-      $('#bookmarks').append(dumpTreeNodes(bookmarkTreeNodes, query));
-    });
-}
-function dumpTreeNodes(bookmarkNodes, query) {
-  var list = $('<ul>');
-  var i;
-  for (i = 0; i < bookmarkNodes.length; i++) {
-    list.append(dumpNode(bookmarkNodes[i], query));
-  }
-  return list;
-}
-function dumpNode(bookmarkNode, query) {
-  if (bookmarkNode.title) {
-    if (query && !bookmarkNode.children) {
-      if (String(bookmarkNode.title).indexOf(query) == -1) {
-        return $('<span></span>');
-      }
-    }
-    var anchor = $('<a>');
-    anchor.attr('href', bookmarkNode.url);
-    anchor.text(bookmarkNode.title);
-    /*
-     * When clicking on a bookmark in the extension, a new tab is fired with
-     * the bookmark url.
-     */
-    anchor.click(function() {
-      chrome.tabs.create({url: bookmarkNode.url});
-    });
-    var span = $('<span>');
-    var options = bookmarkNode.children ?
-      $('<span>[<a href="#" id="addlink">Add</a>]</span>') :
-      $('<span>[<a id="editlink" href="#">Edit</a> <a id="deletelink" ' +
-        'href="#">Delete</a>]</span>');
-    var edit = bookmarkNode.children ? $('<table><tr><td>Name</td><td>' +
-      '<input id="title"></td></tr><tr><td>URL</td><td><input id="url">' +
-      '</td></tr></table>') : $('<input>');
-    // Show add and edit links when hover over.
-        span.hover(function() {
-        span.append(options);
-        $('#deletelink').click(function() {
-          $('#deletedialog').empty().dialog({
-                 autoOpen: false,
-                 title: 'Confirm Deletion',
-                 resizable: false,
-                 height: 140,
-                 modal: true,
-                 overlay: {
-                   backgroundColor: '#000',
-                   opacity: 0.5
-                 },
-                 buttons: {
-                   'Yes, Delete It!': function() {
-                      chrome.bookmarks.remove(String(bookmarkNode.id));
-                      span.parent().remove();
-                      $(this).dialog('destroy');
-                    },
-                    Cancel: function() {
-                      $(this).dialog('destroy');
-                    }
-                 }
-               }).dialog('open');
-         });
-        $('#addlink').click(function() {
-          $('#adddialog').empty().append(edit).dialog({autoOpen: false,
-            closeOnEscape: true, title: 'Add New Bookmark', modal: true,
-            buttons: {
-            'Add' : function() {
-               chrome.bookmarks.create({parentId: bookmarkNode.id,
-                 title: $('#title').val(), url: $('#url').val()});
-               $('#bookmarks').empty();
-               $(this).dialog('destroy');
-               window.dumpBookmarks();
-             },
-            'Cancel': function() {
-               $(this).dialog('destroy');
-            }
-          }}).dialog('open');
-        });
-        $('#editlink').click(function() {
-         edit.val(anchor.text());
-         $('#editdialog').empty().append(edit).dialog({autoOpen: false,
-           closeOnEscape: true, title: 'Edit Title', modal: true,
-           show: 'slide', buttons: {
-              'Save': function() {
-                 chrome.bookmarks.update(String(bookmarkNode.id), {
-                   title: edit.val()
-                 });
-                 anchor.text(edit.val());
-                 options.show();
-                 $(this).dialog('destroy');
-              },
-             'Cancel': function() {
-                 $(this).dialog('destroy');
-             }
-         }}).dialog('open');
-        });
-        options.fadeIn();
-      },
-      // unhover
-      function() {
-        options.remove();
-      }).append(anchor);
-  }
-  var li = $(bookmarkNode.title ? '<li>' : '<div>').append(span);
-  if (bookmarkNode.children && bookmarkNode.children.length > 0) {
-    li.append(dumpTreeNodes(bookmarkNode.children, query));
-  }
-  return li;
-}
-
-document.addEventListener('DOMContentLoaded', function () {
-  dumpBookmarks();
-});
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/expected_nodoc.json b/chrome/common/extensions/docs/server2/test_data/test_json/expected_nodoc.json
deleted file mode 100644
index 1e3d6cd..0000000
--- a/chrome/common/extensions/docs/server2/test_data/test_json/expected_nodoc.json
+++ /dev/null
@@ -1,30 +0,0 @@
-[
-  {
-    "name": "B",
-    "list": [
-      {
-        "name": "B2"
-      }
-    ]
-  },
-  {
-    "name": "D",
-    "nodoc": false
-  },
-  {
-    "name": "E",
-    "items1": [
-      {
-        "name": "E1",
-        "items": [
-          {
-            "name": "E1.3"
-          }
-        ]
-      },
-      {
-        "name": "E2"
-      }
-    ]
-  }
-]
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/nodoc_test.json b/chrome/common/extensions/docs/server2/test_data/test_json/nodoc_test.json
deleted file mode 100644
index 53b9059..0000000
--- a/chrome/common/extensions/docs/server2/test_data/test_json/nodoc_test.json
+++ /dev/null
@@ -1,62 +0,0 @@
-[
-  {
-    "name": "A",
-    "nodoc": true
-  },
-  {
-    "name": "B",
-    "list": [
-      {
-        "name": "B1",
-        "nodoc": true
-      },
-      {
-        "name": "B2"
-      },
-      {
-        "name": "B3",
-        "nodoc": true
-      }
-    ]
-  },
-  {
-    "name": "C",
-    "nodoc": true
-  },
-  {
-    "name": "D",
-    "nodoc": false
-  },
-  {
-    "name": "E",
-    "dict": {
-      "name": "Ed",
-      "nodoc": true
-    },
-    "items1": [
-      {
-        "name": "E1",
-        "items": [
-          {
-            "name": "E1.1",
-            "nodoc": true
-          },
-          {
-            "name": "E1.2",
-            "nodoc": true
-          },
-          {
-            "name": "E1.3"
-          }
-        ]
-      },
-      {
-        "name": "E2"
-      },
-      {
-        "name": "E3",
-        "nodoc": true
-      }
-    ]
-  }
-]
diff --git a/chrome/common/extensions/docs/server2/test_file_system.py b/chrome/common/extensions/docs/server2/test_file_system.py
index 2a8d06d..6dad23f 100644
--- a/chrome/common/extensions/docs/server2/test_file_system.py
+++ b/chrome/common/extensions/docs/server2/test_file_system.py
@@ -107,11 +107,11 @@
   # Testing methods.
   #
 
-  def IncrementStat(self, path=None):
+  def IncrementStat(self, path=None, by=1):
     if path is not None:
-      self._path_stats[path] = self._path_stats.get(path, 0) + 1
+      self._path_stats[path] = self._path_stats.get(path, 0) + by
     else:
-      self._global_stat += 1
+      self._global_stat += by
 
   def GetIdentity(self):
     return self._identity
diff --git a/chrome/common/extensions/docs/server2/url_constants.py b/chrome/common/extensions/docs/server2/url_constants.py
index 49a8835..d9db0c7 100644
--- a/chrome/common/extensions/docs/server2/url_constants.py
+++ b/chrome/common/extensions/docs/server2/url_constants.py
@@ -2,8 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-GITHUB_URL = 'https://api.github.com/repos/GoogleChrome/chrome-app-samples'
-NEW_GITHUB_URL = 'https://api.github.com/repos'
+GITHUB_REPOS = 'https://api.github.com/repos'
 GITHUB_BASE = 'https://github.com/GoogleChrome/chrome-app-samples/tree/master'
 RAW_GITHUB_BASE = ('https://github.com/GoogleChrome/chrome-app-samples/raw/'
                    'master')
diff --git a/chrome/common/extensions/docs/static/images/in-app-payments-confirmation.png b/chrome/common/extensions/docs/static/images/in-app-payments-confirmation.png
deleted file mode 100644
index f2ad8dd..0000000
--- a/chrome/common/extensions/docs/static/images/in-app-payments-confirmation.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/in-app-payments-review.png b/chrome/common/extensions/docs/static/images/in-app-payments-review.png
deleted file mode 100644
index 8706fd3..0000000
--- a/chrome/common/extensions/docs/static/images/in-app-payments-review.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/in-app-payments-set-up.png b/chrome/common/extensions/docs/static/images/in-app-payments-set-up.png
deleted file mode 100644
index 646c91c..0000000
--- a/chrome/common/extensions/docs/static/images/in-app-payments-set-up.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/wallet-confirmation.png b/chrome/common/extensions/docs/static/images/wallet-confirmation.png
new file mode 100644
index 0000000..b04f520
--- /dev/null
+++ b/chrome/common/extensions/docs/static/images/wallet-confirmation.png
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/wallet-review.png b/chrome/common/extensions/docs/static/images/wallet-review.png
new file mode 100644
index 0000000..f4428f2
--- /dev/null
+++ b/chrome/common/extensions/docs/static/images/wallet-review.png
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/wallet-set-up.png b/chrome/common/extensions/docs/static/images/wallet-set-up.png
new file mode 100644
index 0000000..ac6c8e9
--- /dev/null
+++ b/chrome/common/extensions/docs/static/images/wallet-set-up.png
Binary files differ
diff --git a/chrome/common/extensions/docs/templates/articles/app_hardware.html b/chrome/common/extensions/docs/templates/articles/app_usb.html
similarity index 100%
rename from chrome/common/extensions/docs/templates/articles/app_hardware.html
rename to chrome/common/extensions/docs/templates/articles/app_usb.html
diff --git a/chrome/common/extensions/docs/templates/articles/google_wallet.html b/chrome/common/extensions/docs/templates/articles/google_wallet.html
new file mode 100644
index 0000000..714f9db
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/articles/google_wallet.html
@@ -0,0 +1,207 @@
+<h1>Google Wallet for Digital Goods</h1>
+
+<table class="intro">
+  <tr>
+    <td><strong>Description:</strong></td>
+    <td>Use Google Wallet for digital goods to sell digital and virtual goods within a Chrome app.</td>
+  </tr>
+  <tr>
+    <td><strong>Availability:</strong></td>
+    <td>Chrome 29</td>
+  </tr>
+  <tr>
+    <td><strong>Sample:</strong></td>
+    <td><a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/in-app-payments">in-app-payments</a></td>
+  </tr>
+  <tr>
+    <td><strong>Learn more:</strong></td>
+    <td>
+    <a href="https://support.google.com/chrome_webstore/answer/1053354">Google Wallet</a><br>
+    <a href="https://developers.google.com/commerce/wallet/digital/docs/">Google Wallet for Digital Goods</a><br>
+    <a href="http://www.youtube.com/watch?v=Z3jryGggMCs">How-to Video</a></td>
+  </tr>
+</table>
+
+<h2 id="overview">Overview</h2>
+
+<p>
+You can use Google Wallet for digital goods to sell digital and virtual goods within your app.
+The Google Wallet for digital goods client app, which is embedded in Chrome, communicates with the
+<a href="https://support.google.com/chrome_webstore/answer/1053354">Google Wallet</a>
+servers and handles all the required checkout details, so your app does not have to process any financial transactions.
+Google Wallet for digital goods requires you to package a JavaScript file, 
+<a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>,
+with your app to trigger the purchase flow.
+</p>
+
+<h2 id="flow">Purchase flow</h2>
+
+<p>
+When a customer clicks a "Buy" button in your app to make a purchase, Google Wallet for digital goods displays a payment processing window
+on top of your application window:
+</p>
+
+<img src="{{static}}/images/wallet-review.png"
+     width="694"
+     alt="screenshot: Google Wallet review dialog">
+
+<p>
+When the user clicks the "Buy" button in the payment processing window, the Google Wallet server processes the payment
+and displays a purchase confirmation dialog to the user, as shown below.
+The success or failure callback in your app is invoked appropriately.
+</p>
+
+<img src="{{static}}/images/wallet-confirmation.png"
+     width="694"
+     alt="screenshot: Google Wallet confirmation dialog">
+
+<p>
+If the user is not signed up for Google Wallet, Google Wallet for digital goods takes the user through the sign-up flow:
+</p>
+
+<img src="{{static}}/images/wallet-set-up.png"
+     width="694"
+     alt="screenshot: Google Wallet set up dialog">
+
+<h2 id="sample-code">Sample code</h2>
+
+<p>
+The following code snippet illustrates how to initiate the purchase flow in an app.
+The parameters for the <code>buy()</code> method are described below.
+</p>
+
+<pre>
+google.payments.inapp.buy({
+  parameters: {},
+  jwt: 'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxNDIwNDk' +
+       '1MzA5NDM1MjE2ODU3MSIsImF1ZCI6Ikdvb2dsZSI' +
+       'sInR5cCI6Imdvb2dsZS9wYXltZW50cy9pbmFwcC9' +
+       'zdWJzY3JpcHRpb24vdjEiLCJpYXQiOjEzNTg0NTc' +
+       'yNjksImV4cCI6MjM1ODQxMjMzNDMsInJlcXVlc3Q' +
+       'iOnsiaW5pdGlhbFBheW1lbnQiOnsicHJpY2UiOiI' +
+       'xMC41MCIsImN1cnJlbmN5Q29kZSI6IlVTRCIsInB' +
+       'heW1lbnRUeXBlIjoicHJvcmF0ZWQifSwicmVjdXJ' +
+       'yZW5jZSI6eyJwcmljZSI6IjQuOTkiLCJjdXJyZW5' +
+       'jeUNvZGUiOiJVU0QiLCJzdGFydERhdGUiOiIxMzU' +
+       '4NDYzMjY5IiwiZnJlcXVlbmN5IjoibW9udGhseSI' +
+       'sIm51bVJlY3VycmVuY2VzIjoiMTIifSwibmFtZSI' +
+       '6IlBpZWNlIG9mIENha2UiLCJkZXNjcmlwdGlvbiI' +
+       '6IkEgZGVsaWNpb3VzIHBpZWNlIG9mIHZpcnR1YWw' +
+       'gY2FrZSIsInNlbGxlckRhdGEiOiJZb3VyIERhdGE' +
+       'gSGVyZSJ9fQ.sXd39R7MNNfDFa-jnlTNu2C2te-_' +
+       'x9--87Phfdr5GrE',
+  success: logSuccess,
+  failure: logFailure
+});
+</pre>
+
+<h2 id="how-to">How to use Google Wallet for digital goods</h2>
+
+<p>Using Google Wallet for digital goods in a Chrome App is similar to using the
+<a href="https://developers.google.com/commerce/wallet/digital/docs/">Google Wallet for digital goods API</a> in a web site.
+The integration steps below are based on the
+<a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial">Google Wallet for digital goods tutorial</a>,
+but there are a few key differences for apps. These differences are summarized below and described in detail in the
+integration steps.
+</p>
+
+<ul>
+  <li>You can use pre-generated JSON Web Tokens (JWTs) in your app, rather than using a server to generate the tokens.</li>
+
+  <li>You must package the <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
+  library with your app, and load the library from its location in your package.</li>
+
+  <li>You must call the <code>buy()</code> method with an extra parameter called <code>parameters</code>.</li>
+
+  <li>The UI to process payments is displayed in a separate window on top of your application window, rather than in an iframe.</li>
+</ul>
+
+<p>Follow these steps to use Google Wallet for digital goods in your app:</p>
+
+<ol>
+  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#1">Generate a JSON Web Token (JWT) for each item to be purchased.</a>
+    <div class="indent-small">
+      You can generate JWTs using a server, or you can pre-generate JWTs for use in your app.
+      <p class="warning">
+      Note: If you use pre-generated JWTs, you should generate the JWTs outside of your app, and include
+      the generated tokens in your app.
+      <strong>NEVER</strong> include the Seller secret you use to generate tokens in your app.
+      If you need to generate JWTs dynamically, you should use a server.
+      </p>
+    </div>
+  </li>
+
+  <li>Include <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a> in your app.
+    <div class="indent-small">
+      Due to the security restrictions in the
+      <a href="contentSecurityPolicy.html">Content Security Policy</a> for Chrome Apps,
+      you cannot include the <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
+      library from an external location. Instead, you must package the library with your app, and load it from the packaged location.
+    </div>
+  </li>
+
+  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#3">Create success and failure callback handlers.</a>
+    <div class="indent-small">
+      Success and failure callback handlers let your app react to the purchase flow's completion.
+    </div>
+  </li>
+
+  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#4">Call buy().</a>
+    <div class="indent-small">
+      When a customer clicks a "Buy" button in your app, call <code>buy()</code> to initiate the purchase flow.
+      <p>
+      For Apps, you must call <code>buy()</code> with an extra parameter called <code>parameters</code>.
+      This parameter currently has one field, <code>env</code>, which specifies the environment in which to process a payment.
+      You can set this field to either <code>prod</code> (production server that accepts real credit cards), or
+      <code>sandbox</code> (test server that accepts test credit cards to simulate transactions).
+      The default setting is <code>sandbox</code>.
+      </p>
+    </div>
+  </li>
+
+  <li>(Optional) <a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#5">Acknowledge purchase notification.</a>
+    <div class="indent-small">
+      You can specify a postback URL to make sure that the customer has paid for an item.
+    </div>
+  </li>
+
+  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#6">Get set up as a seller on Google Wallet.</a>
+    <div class="indent-small">
+      You must sign up for Google Wallet in order to use Google Wallet for digital goods.
+    </div>
+  </li>
+
+  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#7">Switch to the production server.</a>
+    <div class="indent-small">
+      Switch from the sandbox server to the production server and test your app using real credit cards.
+    </div>
+  </li>
+</ol>
+
+<h2 id="recurring">Recurring billing</h2>
+
+<p>Google Wallet for digital goods supports automated recurring billing. To set up recurring billing, follow the
+instructions for setting up
+<a href="https://developers.google.com/commerce/wallet/digital/docs/subscriptions">subscriptions</a>
+for the Google Wallet for digital goods API,
+but note again the differences described above (you can use pre-generated JWT tokens;
+you must package <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
+with your app; and you must specify an additional parameter in the call to <code>buy()</code>).
+
+<h2 id="sample-app">Sample app</h2>
+
+<p>
+For a simple app that demonstrates how to use Google Wallet for digital goods, see:
+</p>
+
+</ul>
+  <li><a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/in-app-payments">source code</a></li>
+  <li><a href="https://chrome.google.com/webstore/detail/moldiohggmfllblgmikpeoagipenlcae">published app</a> (requires Chrome 29 or higher)</li>
+</ul>
+
+<p>
+You can install and run the published app from the Chrome Web Store to try out the in-app payment purchase flow.
+The app has options to use either the production server or the sandbox server. When testing with the sandbox server,
+use these <a href="https://developers.google.com/commerce/wallet/digital/docs/testing">test credit card numbers</a>,
+which pass basic checks by the Google Wallet for digital goods system.
+</p>
diff --git a/chrome/common/extensions/docs/templates/articles/in_app_payments.html b/chrome/common/extensions/docs/templates/articles/in_app_payments.html
deleted file mode 100644
index a245cdd..0000000
--- a/chrome/common/extensions/docs/templates/articles/in_app_payments.html
+++ /dev/null
@@ -1,206 +0,0 @@
-<h1>In-App Payments Service</h1>
-
-<table class="intro">
-  <tr>
-    <td><strong>Description:</strong></td>
-    <td>Use the In-App Payments Service to sell digital and virtual goods within a Chrome app.</td>
-  </tr>
-  <tr>
-    <td><strong>Availability:</strong></td>
-    <td>Chrome 29</td>
-  </tr>
-  <tr>
-    <td><strong>Sample:</strong></td>
-    <td><a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/in-app-payments">in-app-payments</a></td>
-  </tr>
-  <tr>
-    <td><strong>Learn more:</strong></td>
-    <td>
-    <a href="https://support.google.com/chrome_webstore/answer/1053354">Google Wallet</a>; <br>
-    <a href="https://developers.google.com/commerce/wallet/digital/docs/">Google Wallet for Digital Goods</a></td>
-  </tr>
-</table>
-
-<h2 id="overview">Overview</h2>
-
-<p>
-You can use the In-App Payments Service to sell digital and virtual goods within your app.
-The In-App Payments Service, which is embedded in Chrome, communicates with the
-<a href="https://support.google.com/chrome_webstore/answer/1053354">Google Wallet</a>
-servers and handles all the required checkout details, so your app does not have to process any financial transactions.
-The In-App Payments Service requires you to package a JavaScript file, 
-<a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>,
-with your app to trigger the purchase flow.
-</p>
-
-<h2 id="flow">Purchase flow</h2>
-
-<p>
-When a customer clicks a "Buy" button in your app to make a purchase, the In-App Payments Service displays a payment processing window
-on top of your application window:
-</p>
-
-<img src="{{static}}/images/in-app-payments-review.png"
-     width="569"
-     alt="screenshot: in-app-payments review dialog">
-
-<p>
-When the user clicks the "Buy" button in the payment processing window, the Google Wallet server processes the payment
-and displays a purchase confirmation dialog to the user, as shown below.
-The success or failure callback in your app is invoked appropriately.
-</p>
-
-<img src="{{static}}/images/in-app-payments-confirmation.png"
-     width="563"
-     alt="screenshot: in-app-payments confirmation dialog">
-
-<p>
-If the user is not signed up for Google Wallet, the In-App Payments Service takes the user through the sign-up flow:
-</p>
-
-<img src="{{static}}/images/in-app-payments-set-up.png"
-     width="565"
-     alt="screenshot: Google wallet set up dialog">
-
-<h2 id="sample-code">Sample code</h2>
-
-<p>
-The following code snippet illustrates how to initiate the purchase flow in an app.
-The parameters for the <code>buy()</code> method are described below.
-</p>
-
-<pre>
-google.payments.inapp.buy({
-  parameters: {},
-  jwt: 'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxNDIwNDk' +
-       '1MzA5NDM1MjE2ODU3MSIsImF1ZCI6Ikdvb2dsZSI' +
-       'sInR5cCI6Imdvb2dsZS9wYXltZW50cy9pbmFwcC9' +
-       'zdWJzY3JpcHRpb24vdjEiLCJpYXQiOjEzNTg0NTc' +
-       'yNjksImV4cCI6MjM1ODQxMjMzNDMsInJlcXVlc3Q' +
-       'iOnsiaW5pdGlhbFBheW1lbnQiOnsicHJpY2UiOiI' +
-       'xMC41MCIsImN1cnJlbmN5Q29kZSI6IlVTRCIsInB' +
-       'heW1lbnRUeXBlIjoicHJvcmF0ZWQifSwicmVjdXJ' +
-       'yZW5jZSI6eyJwcmljZSI6IjQuOTkiLCJjdXJyZW5' +
-       'jeUNvZGUiOiJVU0QiLCJzdGFydERhdGUiOiIxMzU' +
-       '4NDYzMjY5IiwiZnJlcXVlbmN5IjoibW9udGhseSI' +
-       'sIm51bVJlY3VycmVuY2VzIjoiMTIifSwibmFtZSI' +
-       '6IlBpZWNlIG9mIENha2UiLCJkZXNjcmlwdGlvbiI' +
-       '6IkEgZGVsaWNpb3VzIHBpZWNlIG9mIHZpcnR1YWw' +
-       'gY2FrZSIsInNlbGxlckRhdGEiOiJZb3VyIERhdGE' +
-       'gSGVyZSJ9fQ.sXd39R7MNNfDFa-jnlTNu2C2te-_' +
-       'x9--87Phfdr5GrE',
-  success: logSuccess,
-  failure: logFailure
-});
-</pre>
-
-<h2 id="how-to">How to use the Service</h2>
-
-<p>Using the In-App Payments Service in an app is similar to using the
-<a href="https://developers.google.com/commerce/wallet/digital/docs/">Google Wallet for Digital Goods API</a> in a web site.
-The integration steps below are based on the
-<a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial">Google Wallet for Digital Goods Tutorial</a>,
-but there are a few key differences for Apps. These differences are summarized below and described in detail in the
-integration steps.
-</p>
-
-<ul>
-  <li>You can use pre-generated JSON Web Tokens (JWTs) in your app, rather than using a server to generate the tokens.</li>
-
-  <li>You must package the <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
-  library with your app, and load the library from its location in your package.</li>
-
-  <li>You must call the <code>buy()</code> method with an extra parameter called <code>parameters</code>.</li>
-
-  <li>The UI to process payments is displayed in a separate window on top of your application window, rather than in an iframe.</li>
-</ul>
-
-<p>Follow these steps to use the In-App Payments Service in your app:</p>
-
-<ol>
-  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#1">Generate a JSON Web Token (JWT) for each item to be purchased.</a>
-    <div class="indent-small">
-      You can generate JWTs using a server, or you can pre-generate JWTs for use in your app.
-      <p class="warning">
-      Note: If you use pre-generated JWTs, you should generate the JWTs outside of your app, and include
-      the generated tokens in your app.
-      <strong>NEVER</strong> include the Seller secret you use to generate tokens in your app.
-      If you need to generate JWTs dynamically, you should use a server.
-      </p>
-    </div>
-  </li>
-
-  <li>Include <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a> in your app.
-    <div class="indent-small">
-      Due to the security restrictions in the
-      <a href="contentSecurityPolicy.html">Content Security Policy</a> for Chrome apps,
-      you cannot include the <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
-      library from an external location. Instead, you must package the library with your app, and load it from the packaged location.
-    </div>
-  </li>
-
-  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#3">Create success and failure callback handlers.</a>
-    <div class="indent-small">
-      Success and failure callback handlers let your app react to the purchase flow's completion.
-    </div>
-  </li>
-
-  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#4">Call buy().</a>
-    <div class="indent-small">
-      When a customer clicks a "Buy" button in your app, call <code>buy()</code> to initiate the purchase flow.
-      <p>
-      For Apps, you must call <code>buy()</code> with an extra parameter called <code>parameters</code>.
-      This parameter currently has one field, <code>env</code>, which specifies the environment in which to process a payment.
-      You can set this field to either <code>prod</code> (production server that accepts real credit cards), or
-      <code>sandbox</code> (test server that accepts test credit cards to simulate transactions).
-      The default setting is <code>sandbox</code>.
-      </p>
-    </div>
-  </li>
-
-  <li>(Optional) <a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#5">Acknowledge purchase notification.</a>
-    <div class="indent-small">
-      You can specify a postback URL to make sure that the customer has paid for an item.
-    </div>
-  </li>
-
-  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#6">Get set up as a seller on Google Wallet.</a>
-    <div class="indent-small">
-      You must sign up for Google Wallet for digital goods in order to use the In-App Payments Service.
-    </div>
-  </li>
-
-  <li><a href="https://developers.google.com/commerce/wallet/digital/docs/tutorial#7">Switch to the production server.</a>
-    <div class="indent-small">
-      Switch from the sandbox server to the production server and test your app using real credit cards.
-    </div>
-  </li>
-</ol>
-
-<h2 id="recurring">Recurring billing</h2>
-
-<p>The In-App Payments Service supports automated recurring billing. To set up recurring billing, follow the
-instructions for setting up
-<a href="https://developers.google.com/commerce/wallet/digital/docs/subscriptions">subscriptions</a>
-for the Google Wallet for Digital Goods API,
-but note again the differences described above (you can use pre-generated JWT tokens;
-you must package <a href="https://raw.github.com/GoogleChrome/chrome-app-samples/master/in-app-payments/buy.js">buy.js</a>
-with your app; and you must specify an additional parameter in the call to <code>buy()</code>).
-
-<h2 id="sample-app">Sample app</h2>
-
-<p>
-For a simple app that demonstrates how to use the In-App Payments Service, see:
-</p>
-
-</ul>
-  <li><a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/in-app-payments">source code</a></li>
-  <li><a href="https://chrome.google.com/webstore/detail/moldiohggmfllblgmikpeoagipenlcae">published app</a> (requires Chrome 29 or higher)</li>
-</ul>
-
-<p>
-You can install and run the published app from the Chrome Web Store to try out the in-app payment purchase flow.
-The app has options to use either the production server or the sandbox server. When testing with the sandbox server,
-use these <a href="https://developers.google.com/commerce/wallet/digital/docs/testing">test credit card numbers</a>,
-which pass basic checks by the Google Wallet for Digital Goods system.
-</p>
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/incognito.html b/chrome/common/extensions/docs/templates/articles/manifest/incognito.html
index 7079bfd..77ef631 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest/incognito.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest/incognito.html
@@ -1,32 +1,51 @@
 <h1 id="incognito">Manifest - Incognito</h1>
 
 <p>
-Either "spanning" or "split", to specify how this extension will
-behave if allowed to run in incognito mode.
+Use the <code>"incognito"</code> manifest key with either
+<code>"spanning"</code> or <code>"split"</code> to specify how this
+{{platform}} will behave if allowed to run in incognito mode.
 </p>
 
 <p>
-The default for extensions is "spanning", which means that the extension
-will run in a single shared process. Any events or messages from an incognito
-tab will be sent to the shared process, with an <em>incognito</em> flag
-indicating where it came from. Because incognito tabs cannot use this shared
-process, an extension using the "spanning" incognito mode will not be able to
-load pages from its extension package into the main frame of an incognito tab.
+Only extensions can choose. Apps will always use the default value for the app
+type; <code>"spanning"</code> for Chrome apps and <code>"split"</code> for
+installable web and legacy packaged apps.
+</p>
+
+<h2 id="spanning">Spanning mode</h2>
+<p>
+The default for extensions and Chrome apps is <code>"spanning"</code>, which
+means that it will run in a single shared process. Any events or messages from
+an incognito tab will be sent to the shared process, with an <em>incognito</em>
+flag indicating where it came from. Because incognito tabs cannot use this
+shared process, an extension using the <code>"spanning"</code> incognito mode
+will not be able to load pages from its extension package into the main frame
+of an incognito tab.
+</p>
+
+<h2 id="split">Split mode</h2>
+<p>
+The default for installable web apps and legacy packaged apps is
+<code>"split"</code>, which means that all app pages in an incognito window
+will run in their own incognito process.  If the app or extension contains a
+background page, that will also run in the incognito process.  This incognito
+process runs along side the regular process, but has a separate memory-only
+cookie store. Each process sees events and messages only from its own context
+(for example, the incognito process will see only incognito tab updates).  The
+processes are unable to communicate with each other.
+</p>
+
+<h2 id="how-to-choose">How to choose</h2>
+<p>
+As a rule of thumb, if your extension or app needs to load a tab in an
+incognito browser, use <em>split</em> incognito behavior. If your extension or
+app needs to be logged into a remote server use <em>spanning</em> incognito
+behavior.
 </p>
 
 <p>
-The default for installable web apps is "split",
-which means that all app pages in
-an incognito window will run in their own incognito process. If the app or extension contains a background page, that will also run in the incognito process.
-This incognito process runs along side the regular process, but has a separate
-memory-only cookie store. Each process sees events and messages only from its
-own context (for example, the incognito process will see only incognito tab updates).
-The processes are unable to communicate with each other.
-</p>
-
-<p>
-As a rule of thumb, if your extension or app needs to load a tab in an incognito browser, use
-<em>split</em> incognito behavior. If your extension or app needs to be logged
-into a remote server or persist settings locally, use <em>spanning</em>
-incognito behavior.
+<a href="/{{platform}}s/storage.html#property-sync">chrome.storage.sync</a> and
+<a href="/{{platform}}s/storage.html#property-local">chrome.storage.local</a>
+are <em>always</em> shared between regular and incognito processes. It is
+recommended to use them for persisting your {{platform}}'s settings.
 </p>
diff --git a/chrome/common/extensions/docs/templates/json/apps_sidenav.json b/chrome/common/extensions/docs/templates/json/apps_sidenav.json
index 2decf7b..0066be0 100644
--- a/chrome/common/extensions/docs/templates/json/apps_sidenav.json
+++ b/chrome/common/extensions/docs/templates/json/apps_sidenav.json
@@ -175,7 +175,7 @@
             "items": [
               {
                 "title": "USB",
-                "href": "/apps/app_hardware.html"
+                "href": "/apps/app_usb.html"
               },
               {
                 "title": "Network Communications",
@@ -209,8 +209,8 @@
         "toggleable": true,
         "items": [
           {
-            "title": "In-App Payments",
-            "href": "/apps/in_app_payments.html"
+            "title": "Google Wallet for Digital Goods",
+            "href": "/apps/google_wallet.html"
           }
         ]
       },
diff --git a/chrome/common/extensions/docs/templates/private/enum_descriptions.html b/chrome/common/extensions/docs/templates/private/enum_descriptions.html
new file mode 100644
index 0000000..f67e23e
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/enum_descriptions.html
@@ -0,0 +1,16 @@
+{{?values}}
+<dl>
+  {{#values}}
+  {{?description}}
+    <dd>
+      <dl>
+        <dt>{{name}}</dt>
+        <dd>
+          {{description}}
+        </dd>
+      </dl>
+    </dd>
+  {{/description}}
+  {{/values}}
+</dl>
+{{/values}}
diff --git a/chrome/common/extensions/docs/templates/private/property.html b/chrome/common/extensions/docs/templates/private/property.html
index 782a402..d7eef71 100644
--- a/chrome/common/extensions/docs/templates/private/property.html
+++ b/chrome/common/extensions/docs/templates/private/property.html
@@ -10,6 +10,7 @@
 {{?description}}<dd>
   {{{description}}}
 </dd>{{/description}}
+{{+partials.enum_descriptions values:enum_values}}
 {{?array.is_object}}
   <h4>Properties of each item</h4>
   {{+partials.type @:array}}
diff --git a/chrome/common/extensions/docs/templates/private/type.html b/chrome/common/extensions/docs/templates/private/type.html
index 250a22c..f99dad8 100644
--- a/chrome/common/extensions/docs/templates/private/type.html
+++ b/chrome/common/extensions/docs/templates/private/type.html
@@ -19,6 +19,7 @@
     {{?description}}
     <dd>{{{description}}}</dd>
     {{/description}}
+    {{+partials.enum_descriptions values:enum_values}}
     {{?properties}}
       {{+partials.type_item title:strings.properties
                             display_name:display_name
diff --git a/chrome/common/extensions/docs/templates/public/apps/app_hardware.html b/chrome/common/extensions/docs/templates/public/apps/app_hardware.html
deleted file mode 100644
index 98db693..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/app_hardware.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_article article:intros.app_hardware}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/app_usb.html b/chrome/common/extensions/docs/templates/public/apps/app_usb.html
new file mode 100644
index 0000000..7518e18
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/app_usb.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_article article:intros.app_usb}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/google_wallet.html b/chrome/common/extensions/docs/templates/public/apps/google_wallet.html
new file mode 100644
index 0000000..484746c
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/google_wallet.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_article article:intros.google_wallet}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/in_app_payments.html b/chrome/common/extensions/docs/templates/public/apps/in_app_payments.html
deleted file mode 100644
index d41dd30..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/in_app_payments.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_article article:intros.in_app_payments}}
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 1855691..86f20ff 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -20,8 +20,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/version.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_handler.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
@@ -30,6 +30,7 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
@@ -61,41 +62,6 @@
 const char kPublic[] = "PUBLIC";
 const char kPrivate[] = "PRIVATE";
 
-// A singleton object containing global data needed by the extension objects.
-class ExtensionConfig {
- public:
-  static ExtensionConfig* GetInstance() {
-    return Singleton<ExtensionConfig>::get();
-  }
-
-  Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; }
-
- private:
-  friend struct DefaultSingletonTraits<ExtensionConfig>;
-
-  ExtensionConfig() {
-    // Whitelist ChromeVox, an accessibility extension from Google that needs
-    // the ability to script webui pages. This is temporary and is not
-    // meant to be a general solution.
-    // TODO(dmazzoni): remove this once we have an extension API that
-    // allows any extension to request read-only access to webui pages.
-    scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
-
-    // Whitelist "Discover DevTools Companion" extension from Google that
-    // needs the ability to script DevTools pages. Companion will assist
-    // online courses and will be needed while the online educational programs
-    // are in place.
-    scripting_whitelist_.push_back("angkfkebojeancgemegoedelbnjgcgme");
-  }
-  ~ExtensionConfig() { }
-
-  // A whitelist of extensions that can script anywhere. Do not add to this
-  // list (except in tests) without consulting the Extensions team first.
-  // Note: Component extensions have this right implicitly and do not need to be
-  // added to this list.
-  Extension::ScriptingWhitelist scripting_whitelist_;
-};
-
 bool ContainsReservedCharacters(const base::FilePath& path) {
   // We should disallow backslash '\\' as file path separator even on Windows,
   // because the backslash is not regarded as file path separator on Linux/Mac.
@@ -109,11 +75,6 @@
 
 }  // namespace
 
-#if defined(OS_WIN)
-const char Extension::kExtensionRegistryPath[] =
-    "Software\\Google\\Chrome\\Extensions";
-#endif
-
 const char Extension::kMimeType[] = "application/x-chrome-extension";
 
 const int Extension::kValidWebExtentSchemes =
@@ -328,23 +289,6 @@
               content::kStandardSchemeSeparator + extension_id + "/");
 }
 
-// static
-void Extension::SetScriptingWhitelist(
-    const Extension::ScriptingWhitelist& whitelist) {
-  ScriptingWhitelist* current_whitelist =
-      ExtensionConfig::GetInstance()->whitelist();
-  current_whitelist->clear();
-  for (ScriptingWhitelist::const_iterator it = whitelist.begin();
-       it != whitelist.end(); ++it) {
-    current_whitelist->push_back(*it);
-  }
-}
-
-// static
-const Extension::ScriptingWhitelist* Extension::GetScriptingWhitelist() {
-  return ExtensionConfig::GetInstance()->whitelist();
-}
-
 bool Extension::HasAPIPermission(APIPermission::ID permission) const {
   return PermissionsData::HasAPIPermission(this, permission);
 }
@@ -834,7 +778,7 @@
 
 UnloadedExtensionInfo::UnloadedExtensionInfo(
     const Extension* extension,
-    extension_misc::UnloadedExtensionReason reason)
+    UnloadedExtensionInfo::Reason reason)
     : reason(reason),
       extension(extension) {}
 
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 81a2c8b..c99a80d 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -20,7 +20,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest.h"
@@ -56,7 +55,6 @@
  public:
   struct ManifestData;
 
-  typedef std::vector<std::string> ScriptingWhitelist;
   typedef std::map<const std::string, linked_ptr<ManifestData> >
       ManifestDataMap;
 
@@ -89,9 +87,7 @@
     DISABLE_UNSUPPORTED_REQUIREMENT = 1 << 3,
     DISABLE_SIDELOAD_WIPEOUT = 1 << 4,
     DISABLE_UNKNOWN_FROM_SYNC = 1 << 5,
-    // Disabled because the user has not yet consented to the permissions,
-    // for instance for a default installed item.
-    DISABLE_PERMISSIONS_CONSENT = 1 << 6,
+    DISABLE_PERMISSIONS_CONSENT = 1 << 6,  // Unused - abandoned experiment.
     DISABLE_KNOWN_DISABLED = 1 << 7,
   };
 
@@ -150,9 +146,7 @@
     // created.
     WAS_INSTALLED_BY_DEFAULT = 1 << 7,
 
-    // |REQUIRE_PERMISSIONS_CONSENT| means that user needs to accept permissions
-    // before running the app even if it is marked as |WAS_INSTALLED_BY_DEFAULT|
-    // and |FROM_WEBSTORE|.
+    // Unused - was part of an abandoned experiment.
     REQUIRE_PERMISSIONS_CONSENT = 1 << 8,
   };
 
@@ -177,10 +171,6 @@
   // Valid schemes for host permission URLPatterns.
   static const int kValidHostPermissionSchemes;
 
-#if defined(OS_WIN)
-  static const char kExtensionRegistryPath[];
-#endif
-
   // The mimetype used for extensions.
   static const char kMimeType[];
 
@@ -230,10 +220,6 @@
   // Returns the base extension url for a given |extension_id|.
   static GURL GetBaseURLFromExtensionId(const std::string& extension_id);
 
-  // Adds an extension to the scripting whitelist. Used for testing only.
-  static void SetScriptingWhitelist(const ScriptingWhitelist& whitelist);
-  static const ScriptingWhitelist* GetScriptingWhitelist();
-
   // DEPRECATED: These methods have been moved to PermissionsData.
   // TODO(rdevlin.cronin): remove these once all calls have been updated.
   bool HasAPIPermission(APIPermission::ID permission) const;
@@ -321,9 +307,6 @@
   bool was_installed_by_default() const {
     return (creation_flags_ & WAS_INSTALLED_BY_DEFAULT) != 0;
   }
-  bool requires_permissions_consent() const {
-    return (creation_flags_ & REQUIRE_PERMISSIONS_CONSENT) != 0;
-  }
 
   // App-related.
   bool is_app() const;
@@ -504,14 +487,20 @@
 };
 
 struct UnloadedExtensionInfo {
-  extension_misc::UnloadedExtensionReason reason;
+  enum Reason {
+    REASON_DISABLE,    // Extension is being disabled.
+    REASON_UPDATE,     // Extension is being updated to a newer version.
+    REASON_UNINSTALL,  // Extension is being uninstalled.
+    REASON_TERMINATE,  // Extension has terminated.
+    REASON_BLACKLIST,  // Extension has been blacklisted.
+  };
+
+  Reason reason;
 
   // The extension being unloaded - this should always be non-NULL.
   const Extension* extension;
 
-  UnloadedExtensionInfo(
-      const Extension* extension,
-      extension_misc::UnloadedExtensionReason reason);
+  UnloadedExtensionInfo(const Extension* extension, Reason reason);
 };
 
 // The details sent for EXTENSION_PERMISSIONS_UPDATED notifications.
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 7938d4f..b1cf82d 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -285,14 +285,6 @@
     NUM_INSTALL_CAUSES
   };
 
-  enum UnloadedExtensionReason {
-    UNLOAD_REASON_DISABLE,    // Extension is being disabled.
-    UNLOAD_REASON_UPDATE,     // Extension is being updated to a newer version.
-    UNLOAD_REASON_UNINSTALL,  // Extension is being uninstalled.
-    UNLOAD_REASON_TERMINATE,  // Extension has terminated.
-    UNLOAD_REASON_BLACKLIST,  // Extension has been blacklisted.
-  };
-
   // The states that an app can be in, as reported by chrome.app.installState
   // and chrome.app.runningState.
   extern const char kAppStateNotInstalled[];
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index e3d335e..1fd4c32 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -215,6 +215,18 @@
     }
   }
 
+  // Initialize search_provider fields.
+  base::DictionaryValue* search_provider = NULL;
+  if (manifest->GetDictionary(keys::kSearchProvider, &search_provider)) {
+    for (DictionaryValue::Iterator iter(*search_provider); !iter.IsAtEnd();
+        iter.Advance()) {
+      key.assign(base::StringPrintf("%s.%s", keys::kSearchProvider,
+                                    iter.key().c_str()));
+      if (!LocalizeManifestValue(key, messages, manifest, error))
+        return false;
+    }
+  }
+
   // Add current locale key to the manifest, so we can overwrite prefs
   // with new manifest when chrome locale changes.
   manifest->SetString(keys::kCurrentLocale, CurrentLocaleOrDefault());
diff --git a/chrome/common/extensions/extension_l10n_util_unittest.cc b/chrome/common/extensions/extension_l10n_util_unittest.cc
index c7a6d08..8ba14de 100644
--- a/chrome/common/extensions/extension_l10n_util_unittest.cc
+++ b/chrome/common/extensions/extension_l10n_util_unittest.cc
@@ -292,6 +292,10 @@
   second_command_description_tree->SetString("message", "second command");
   catalog->Set("second_command_description", second_command_description_tree);
 
+  base::DictionaryValue* url_country_tree = new base::DictionaryValue();
+  url_country_tree->SetString("message", "de");
+  catalog->Set("country", url_country_tree);
+
   std::vector<linked_ptr<base::DictionaryValue> > catalogs;
   catalogs.push_back(catalog);
 
@@ -562,6 +566,52 @@
   EXPECT_EQ("__MSG_short_name_bad__", result);
 }
 
+TEST(ExtensionL10nUtil, LocalizeManifestWithSearchProviderMsgs) {
+  base::DictionaryValue manifest;
+  manifest.SetString(keys::kName, "__MSG_name__");
+  manifest.SetString(keys::kDescription, "__MSG_description__");
+
+  base::DictionaryValue* search_provider = new base::DictionaryValue;
+  search_provider->SetString("name", "__MSG_country__");
+  search_provider->SetString("keyword", "__MSG_omnibox_keyword__");
+  search_provider->SetString("search_url", "http://www.foo.__MSG_country__");
+  search_provider->SetString("favicon_url", "http://www.foo.__MSG_country__");
+  search_provider->SetString("suggest_url", "http://www.foo.__MSG_country__");
+  manifest.Set(keys::kSearchProvider, search_provider);
+
+  std::string error;
+  scoped_ptr<MessageBundle> messages(CreateManifestBundle());
+
+  EXPECT_TRUE(
+      extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
+
+  std::string result;
+  ASSERT_TRUE(manifest.GetString(keys::kName, &result));
+  EXPECT_EQ("name", result);
+
+  ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
+  EXPECT_EQ("description", result);
+
+  std::string key_prefix(keys::kSearchProvider);
+  key_prefix += '.';
+  ASSERT_TRUE(manifest.GetString(key_prefix + "name", &result));
+  EXPECT_EQ("de", result);
+
+  ASSERT_TRUE(manifest.GetString(key_prefix + "keyword", &result));
+  EXPECT_EQ("omnibox keyword", result);
+
+  ASSERT_TRUE(manifest.GetString(key_prefix + "search_url", &result));
+  EXPECT_EQ("http://www.foo.de", result);
+
+  ASSERT_TRUE(manifest.GetString(key_prefix + "favicon_url", &result));
+  EXPECT_EQ("http://www.foo.de", result);
+
+  ASSERT_TRUE(manifest.GetString(key_prefix + "suggest_url", &result));
+  EXPECT_EQ("http://www.foo.de", result);
+
+  EXPECT_TRUE(error.empty());
+}
+
 // Try with NULL manifest.
 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithNullManifest) {
   EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(NULL));
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index e947497..8e0d843 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -10,16 +10,18 @@
 
 #include "base/memory/shared_memory.h"
 #include "base/values.h"
+#include "chrome/common/extensions/api/messaging/message.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/permissions/bluetooth_permission_data.h"
 #include "chrome/common/extensions/permissions/media_galleries_permission_data.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/socket_permission_data.h"
 #include "chrome/common/extensions/permissions/usb_device_permission_data.h"
 #include "chrome/common/web_application_info.h"
 #include "content/public/common/common_param_traits.h"
 #include "content/public/common/socket_permission_request.h"
 #include "extensions/common/draggable_region.h"
+#include "extensions/common/extensions_client.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
 #include "extensions/common/view_type.h"
@@ -193,6 +195,11 @@
   IPC_STRUCT_TRAITS_MEMBER(uuid())
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(extensions::Message)
+  IPC_STRUCT_TRAITS_MEMBER(data)
+  IPC_STRUCT_TRAITS_MEMBER(user_gesture)
+IPC_STRUCT_TRAITS_END()
+
 // Singly-included section for custom IPC traits.
 #ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
 #define CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
@@ -341,7 +348,7 @@
 // only used for testing.
 IPC_MESSAGE_CONTROL1(ExtensionMsg_SetScriptingWhitelist,
                      // extension ids
-                     extensions::Extension::ScriptingWhitelist)
+                     extensions::ExtensionsClient::ScriptingWhitelist)
 
 // Notification that renderer should run some JavaScript code.
 IPC_MESSAGE_ROUTED1(ExtensionMsg_ExecuteCode,
@@ -436,7 +443,7 @@
 // Deliver a message sent with ExtensionHostMsg_PostMessage.
 IPC_MESSAGE_ROUTED2(ExtensionMsg_DeliverMessage,
                     int /* target_port_id */,
-                    std::string /* message */)
+                    extensions::Message)
 
 // Dispatch the Port.onDisconnect event for message channels.
 IPC_MESSAGE_ROUTED2(ExtensionMsg_DispatchOnDisconnect,
@@ -547,7 +554,7 @@
 // by ViewHostMsg_OpenChannelTo*.
 IPC_MESSAGE_ROUTED2(ExtensionHostMsg_PostMessage,
                     int /* port_id */,
-                    std::string /* message */)
+                    extensions::Message)
 
 // Send a message to an extension process.  The handle is the value returned
 // by ViewHostMsg_OpenChannelTo*.
diff --git a/chrome/common/extensions/extension_process_policy.cc b/chrome/common/extensions/extension_process_policy.cc
index cb938ee..1008711 100644
--- a/chrome/common/extensions/extension_process_policy.cc
+++ b/chrome/common/extensions/extension_process_policy.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/extensions/extension_process_policy.h"
 
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_set.h"
 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
 
diff --git a/chrome/common/extensions/extension_set.cc b/chrome/common/extensions/extension_set.cc
index 5c6861c..33d9abc 100644
--- a/chrome/common/extensions/extension_set.cc
+++ b/chrome/common/extensions/extension_set.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/common/extensions/extension_set.h"
 
+#include "base/callback.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "chrome/common/extensions/extension.h"
@@ -44,6 +45,8 @@
 bool ExtensionSet::Insert(const scoped_refptr<const Extension>& extension) {
   bool was_present = ContainsKey(extensions_, extension->id());
   extensions_[extension->id()] = extension;
+  if (!was_present && !modification_callback_.is_null())
+    modification_callback_.Run(GetIDs());
   return !was_present;
 }
 
@@ -57,7 +60,10 @@
 }
 
 bool ExtensionSet::Remove(const std::string& id) {
-  return extensions_.erase(id) > 0;
+  bool was_present = extensions_.erase(id) > 0;
+  if (was_present && !modification_callback_.is_null())
+    modification_callback_.Run(GetIDs());
+  return was_present;
 }
 
 void ExtensionSet::Clear() {
@@ -117,8 +123,8 @@
     return NULL;
 }
 
-std::set<std::string> ExtensionSet::GetIDs() const {
-  std::set<std::string> ids;
+extensions::ExtensionIdSet ExtensionSet::GetIDs() const {
+  extensions::ExtensionIdSet ids;
   for (ExtensionMap::const_iterator it = extensions_.begin();
        it != extensions_.end(); ++it) {
     ids.insert(it->first);
diff --git a/chrome/common/extensions/extension_set.h b/chrome/common/extensions/extension_set.h
index 95b9cd2..7dc3ea0 100644
--- a/chrome/common/extensions/extension_set.h
+++ b/chrome/common/extensions/extension_set.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <string>
 
+#include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/common/extensions/extension.h"
@@ -21,6 +22,8 @@
   typedef std::pair<base::FilePath, std::string> ExtensionPathAndDefaultLocale;
   typedef std::map<std::string, scoped_refptr<const extensions::Extension> >
       ExtensionMap;
+  typedef base::Callback<void(const extensions::ExtensionIdSet&)>
+      ModificationCallback;
 
   // Iteration over the values of the map (given that it's an ExtensionSet,
   // it should iterate like a set iterator).
@@ -113,18 +116,29 @@
   const extensions::Extension* GetByID(const std::string& id) const;
 
   // Gets the IDs of all extensions in the set.
-  std::set<std::string> GetIDs() const;
+  extensions::ExtensionIdSet GetIDs() const;
 
   // Returns true if |info| should get extension api bindings and be permitted
   // to make api calls. Note that this is independent of what extension
   // permissions the given extension has been granted.
   bool ExtensionBindingsAllowed(const GURL& url) const;
 
+  void set_modification_callback(
+      const ModificationCallback& modification_callback) {
+    modification_callback_ = modification_callback;
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ExtensionSetTest, ExtensionSet);
 
   ExtensionMap extensions_;
 
+  // If non-null, called with the extension ids in this set after a modification
+  // occurred. This is not called on Clear() which is typically used when
+  // discarding the set (e.g., on shutdown) and we do not want to track that as
+  // a real modification.
+  ModificationCallback modification_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionSet);
 };
 
diff --git a/chrome/common/extensions/features/permission_feature.cc b/chrome/common/extensions/features/permission_feature.cc
index 5beb26f..cc91c41 100644
--- a/chrome/common/extensions/features/permission_feature.cc
+++ b/chrome/common/extensions/features/permission_feature.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/common/extensions/features/permission_feature.h"
 
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
+#include "extensions/common/permissions/permission_set.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/incognito_handler.cc b/chrome/common/extensions/incognito_handler.cc
index 24b9dd6..ca31480 100644
--- a/chrome/common/extensions/incognito_handler.cc
+++ b/chrome/common/extensions/incognito_handler.cc
@@ -36,9 +36,12 @@
 
 bool IncognitoHandler::Parse(Extension* extension, string16* error) {
   if (!extension->manifest()->HasKey(keys::kIncognito)) {
-    // Apps default to split mode, extensions default to spanning.
-    extension->SetManifestData(keys::kIncognito,
-                               new IncognitoInfo(extension->is_app()));
+    // Extensions and Chrome apps default to spanning mode.
+    // Hosted and legacy packaged apps default to split mode.
+    extension->SetManifestData(
+        keys::kIncognito,
+        new IncognitoInfo(extension->is_hosted_app() ||
+                          extension->is_legacy_packaged_app()));
     return true;
   }
 
diff --git a/chrome/common/extensions/manifest_handlers/icons_handler.cc b/chrome/common/extensions/manifest_handlers/icons_handler.cc
index 70b66ad..35de4f8 100644
--- a/chrome/common/extensions/manifest_handlers/icons_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/icons_handler.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/manifest_handler_helpers.h"
 #include "extensions/common/manifest_constants.h"
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
new file mode 100644
index 0000000..391643e
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 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/common/extensions/manifest_handlers/settings_overrides_handler.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+
+using extensions::api::manifest_types::ChromeSettingsOverrides;
+
+namespace extensions {
+namespace {
+
+scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
+  scoped_ptr<GURL> manifest_url(new GURL(url));
+  if (!manifest_url->is_valid() ||
+      !manifest_url->SchemeIsHTTPOrHTTPS())
+    return scoped_ptr<GURL>();
+  return manifest_url.Pass();
+}
+
+scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
+                               string16* error) {
+  if (!overrides.homepage)
+    return scoped_ptr<GURL>();
+  scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
+  if (!manifest_url) {
+    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+        manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
+  }
+  return manifest_url.Pass();
+}
+
+std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
+                                   string16* error) {
+  std::vector<GURL> urls;
+  if (!overrides.startup_pages)
+    return urls;
+
+  for (std::vector<std::string>::const_iterator i =
+       overrides.startup_pages->begin(); i != overrides.startup_pages->end();
+       ++i) {
+    scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
+    if (!manifest_url) {
+      *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+          manifest_errors::kInvalidStartupOverrideURL, *i);
+    } else {
+      urls.push_back(GURL());
+      urls.back().Swap(manifest_url.get());
+    }
+  }
+  return urls;
+}
+
+}  // namespace
+
+SettingsOverrides::SettingsOverrides() {}
+
+SettingsOverrides::~SettingsOverrides() {}
+
+const SettingsOverrides* SettingsOverrides::Get(
+    const Extension* extension) {
+  return static_cast<SettingsOverrides*>(
+      extension->GetManifestData(manifest_keys::kSettingsOverride));
+}
+
+SettingsOverridesHandler::SettingsOverridesHandler() {}
+
+SettingsOverridesHandler::~SettingsOverridesHandler() {}
+
+bool SettingsOverridesHandler::Parse(Extension* extension, string16* error) {
+  const base::Value* dict = NULL;
+  CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
+  scoped_ptr<ChromeSettingsOverrides> settings(
+      ChromeSettingsOverrides::FromValue(*dict, error));
+  if (!settings)
+    return false;
+
+  scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
+  info->homepage = ParseHomepage(*settings, error);
+  info->search_engine = settings->search_provider.Pass();
+  info->startup_pages = ParseStartupPage(*settings, error);
+  if (!info->homepage && !info->search_engine && info->startup_pages.empty()) {
+    *error = ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides);
+    return false;
+  }
+  extension->SetManifestData(manifest_keys::kSettingsOverride,
+                             info.release());
+  return true;
+}
+
+const std::vector<std::string> SettingsOverridesHandler::Keys() const {
+  return SingleKey(manifest_keys::kSettingsOverride);
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h
new file mode 100644
index 0000000..cf0bed4
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h
@@ -0,0 +1,46 @@
+// Copyright 2013 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_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
+
+#include "chrome/common/extensions/api/manifest_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handler.h"
+
+namespace extensions {
+
+// SettingsOverride is associated with "chrome_settings_overrides" manifest key.
+// An extension can add a search engine as default or non-default, overwrite the
+// homepage and append a startup page to the list.
+struct SettingsOverrides : public Extension::ManifestData {
+  SettingsOverrides();
+  virtual ~SettingsOverrides();
+
+  static const SettingsOverrides* Get(const Extension* extension);
+
+  scoped_ptr<api::manifest_types::ChromeSettingsOverrides::Search_provider>
+      search_engine;
+  scoped_ptr<GURL> homepage;
+  std::vector<GURL> startup_pages;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SettingsOverrides);
+};
+
+class SettingsOverridesHandler : public ManifestHandler {
+ public:
+  SettingsOverridesHandler();
+  virtual ~SettingsOverridesHandler();
+
+  virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
+
+ private:
+  virtual const std::vector<std::string> Keys() const OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(SettingsOverridesHandler);
+};
+
+}  // namespace extensions
+#endif  // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
new file mode 100644
index 0000000..6b9a332
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright 2013 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/common/extensions/manifest_handlers/settings_overrides_handler.h"
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/features/feature_channel.h"
+#include "chrome/common/extensions/manifest_url_handler.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kManifest[] = "{"
+    " \"version\" : \"1.0.0.0\","
+    " \"name\" : \"Test\","
+    " \"chrome_settings_overrides\" : {"
+    "   \"homepage\" : \"http://www.homepage.com\","
+    "   \"search_provider\" : {"
+    "        \"name\" : \"first\","
+    "        \"keyword\" : \"firstkey\","
+    "        \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\","
+    "        \"favicon_url\" : \"http://www.foo.com/favicon.ico\","
+    "        \"suggest_url\" : \"http://www.foo.com/s?q={searchTerms}\","
+    "        \"encoding\" : \"UTF-8\","
+    "        \"is_default\" : true"
+    "    },"
+    "   \"startup_pages\" : [\"http://www.startup.com\"]"
+    "  }"
+    "}";
+
+using extensions::api::manifest_types::ChromeSettingsOverrides;
+using extensions::Extension;
+using extensions::Manifest;
+using extensions::SettingsOverrides;
+namespace manifest_keys = extensions::manifest_keys;
+
+class DeclarativeSettingsTest : public testing::Test {
+};
+
+
+TEST_F(DeclarativeSettingsTest, ParseManifest) {
+  extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_DEV);
+  std::string manifest(kManifest);
+  JSONStringValueSerializer json(&manifest);
+  std::string error;
+  scoped_ptr<base::Value> root(json.Deserialize(NULL, &error));
+  ASSERT_TRUE(root);
+  ASSERT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY));
+  scoped_refptr<Extension> extension = Extension::Create(
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      Manifest::INVALID_LOCATION,
+      *static_cast<base::DictionaryValue*>(root.get()),
+      Extension::NO_FLAGS,
+      &error);
+  ASSERT_TRUE(extension);
+  ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+
+  SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
+        extension->GetManifestData(manifest_keys::kSettingsOverride));
+  ASSERT_TRUE(settings_override);
+  ASSERT_TRUE(settings_override->search_engine);
+  EXPECT_TRUE(settings_override->search_engine->is_default);
+  const ChromeSettingsOverrides::Search_provider* search_engine =
+      settings_override->search_engine.get();
+  EXPECT_EQ("first", search_engine->name);
+  EXPECT_EQ("firstkey", search_engine->keyword);
+  EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", search_engine->search_url);
+  EXPECT_EQ("http://www.foo.com/favicon.ico", search_engine->favicon_url);
+  EXPECT_EQ("http://www.foo.com/s?q={searchTerms}",
+            *search_engine->suggest_url);
+  EXPECT_EQ("UTF-8", search_engine->encoding);
+
+  EXPECT_EQ(std::vector<GURL>(1, GURL("http://www.startup.com")),
+            settings_override->startup_pages);
+
+  ASSERT_TRUE(settings_override->homepage);
+  EXPECT_EQ(GURL("http://www.homepage.com"), *settings_override->homepage);
+}
+
+}  // namespace
diff --git a/chrome/common/extensions/manifest_handlers/shared_module_info.cc b/chrome/common/extensions/manifest_handlers/shared_module_info.cc
index 1bf8839..a7c8164 100644
--- a/chrome/common/extensions/manifest_handlers/shared_module_info.cc
+++ b/chrome/common/extensions/manifest_handlers/shared_module_info.cc
@@ -10,10 +10,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
index 8af8e89..3c760a2 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -26,14 +26,14 @@
   scoped_refptr<Extension> extension =
       LoadAndExpectSuccess("init_valid_platform_app.json");
   EXPECT_TRUE(AppIsolationInfo::HasIsolatedStorage(extension.get()));
-  EXPECT_TRUE(IncognitoInfo::IsSplitMode(extension.get()));
+  EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
 
   extension =
       LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json");
   EXPECT_EQ(2, extension->manifest_version());
 
   extension = LoadAndExpectSuccess("incognito_valid_platform_app.json");
-  EXPECT_TRUE(IncognitoInfo::IsSplitMode(extension.get()));
+  EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
 
   Testcase error_testcases[] = {
     Testcase("init_invalid_platform_app_2.json",
diff --git a/chrome/common/extensions/manifest_url_handler.cc b/chrome/common/extensions/manifest_url_handler.cc
index 24fbafa..538f1a9 100644
--- a/chrome/common/extensions/manifest_url_handler.cc
+++ b/chrome/common/extensions/manifest_url_handler.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 1950a99..0fe74ed 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -64,10 +64,6 @@
       PermissionMessage::kDownloadsOpen },
     { APIPermission::kDownloadsShelf, "downloads.shelf" },
     { APIPermission::kIdentity, "identity" },
-    { APIPermission::kIdentityEmail, "identity.email",
-      APIPermissionInfo::kFlagNone,
-      IDS_EXTENSION_PROMPT_WARNING_IDENTITY_EMAIL,
-      PermissionMessage::kIdentityEmail },
     { APIPermission::kExperimental, "experimental",
       APIPermissionInfo::kFlagCannotBeOptional },
       // NOTE(kalman): this is provided by a manifest property but needs to
@@ -239,6 +235,8 @@
     { APIPermission::kEnterprisePlatformKeysPrivate,
       "enterprise.platformKeysPrivate",
       APIPermissionInfo::kFlagCannotBeOptional },
+    { APIPermission::kWebrtcAudioPrivate, "webrtcAudioPrivate",
+      APIPermissionInfo::kFlagCannotBeOptional },
     { APIPermission::kWebrtcLoggingPrivate, "webrtcLoggingPrivate",
       APIPermissionInfo::kFlagCannotBeOptional },
     { APIPermission::kPrincipalsPrivate, "principalsPrivate",
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
index 1bea93b..433c18d 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
@@ -6,9 +6,9 @@
 
 #include "base/stl_util.h"
 #include "chrome/common/extensions/permissions/permission_message_util.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern_set.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/common/extensions/permissions/chrome_scheme_hosts.cc b/chrome/common/extensions/permissions/chrome_scheme_hosts.cc
deleted file mode 100644
index 722d20c..0000000
--- a/chrome/common/extensions/permissions/chrome_scheme_hosts.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 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/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/chrome_scheme_hosts.h"
-#include "chrome/common/url_constants.h"
-#include "extensions/common/permissions/api_permission_set.h"
-#include "extensions/common/url_pattern.h"
-#include "extensions/common/url_pattern_set.h"
-
-namespace {
-const char kThumbsWhiteListedExtension[] = "khopmbdjffemhegeeobelklnbglcdgfh";
-}  // namespace
-
-namespace extensions {
-
-URLPatternSet GetPermittedChromeSchemeHosts(
-    const Extension* extension,
-    const APIPermissionSet& api_permissions) {
-  URLPatternSet hosts;
-  // Regular extensions are only allowed access to chrome://favicon.
-  hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
-                              chrome::kChromeUIFaviconURL));
-
-  // Experimental extensions are also allowed chrome://thumb.
-  //
-  // TODO: A public API should be created for retrieving thumbnails.
-  // See http://crbug.com/222856. A temporary hack is implemented here to
-  // make chrome://thumbs available to NTP Russia extension as
-  // non-experimental.
-  if ((api_permissions.find(APIPermission::kExperimental) !=
-       api_permissions.end()) ||
-      (extension->id() == kThumbsWhiteListedExtension &&
-       extension->from_webstore())) {
-    hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
-                                chrome::kChromeUIThumbnailURL));
-  }
-  return hosts;
-}
-
-}  // namespace extensions
diff --git a/chrome/common/extensions/permissions/chrome_scheme_hosts.h b/chrome/common/extensions/permissions/chrome_scheme_hosts.h
deleted file mode 100644
index 4ac8162..0000000
--- a/chrome/common/extensions/permissions/chrome_scheme_hosts.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2013 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_COMMON_EXTENSIONS_PERMISSIONS_CHROME_SCHEME_HOSTS_H_
-#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_SCHEME_HOSTS_H_
-
-// Chrome-specific special case handling for permissions on hosts in
-// the chrome:// scheme.
-namespace extensions {
-
-class APIPermissionSet;
-class Extension;
-class URLPatternSet;
-
-URLPatternSet GetPermittedChromeSchemeHosts(
-    const Extension* extension,
-    const APIPermissionSet& permissions);
-
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_SCHEME_HOSTS_H_
diff --git a/chrome/common/extensions/permissions/permission_message_util.cc b/chrome/common/extensions/permissions/permission_message_util.cc
index bb43236..1a99542 100644
--- a/chrome/common/extensions/permissions/permission_message_util.cc
+++ b/chrome/common/extensions/permissions/permission_message_util.cc
@@ -6,9 +6,9 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern_set.h"
 #include "grit/generated_resources.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc
deleted file mode 100644
index 9c97014..0000000
--- a/chrome/common/extensions/permissions/permission_set.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2013 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/common/extensions/permissions/permission_set.h"
-
-#include <algorithm>
-#include <iterator>
-#include <string>
-
-#include "extensions/common/permissions/permissions_info.h"
-#include "extensions/common/url_pattern.h"
-#include "extensions/common/url_pattern_set.h"
-#include "url/gurl.h"
-
-using extensions::URLPatternSet;
-
-namespace {
-
-void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
-  DCHECK(out);
-  for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
-    URLPattern p = *i;
-    p.SetPath("/*");
-    out->AddPattern(p);
-  }
-}
-
-}  // namespace
-
-namespace extensions {
-
-//
-// PermissionSet
-//
-
-PermissionSet::PermissionSet() {}
-
-PermissionSet::PermissionSet(
-    const APIPermissionSet& apis,
-    const URLPatternSet& explicit_hosts,
-    const URLPatternSet& scriptable_hosts)
-    : apis_(apis),
-      scriptable_hosts_(scriptable_hosts) {
-  AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
-  InitImplicitPermissions();
-  InitEffectiveHosts();
-}
-
-// static
-PermissionSet* PermissionSet::CreateDifference(
-    const PermissionSet* set1,
-    const PermissionSet* set2) {
-  scoped_refptr<PermissionSet> empty = new PermissionSet();
-  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
-  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
-
-  APIPermissionSet apis;
-  APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
-
-  URLPatternSet explicit_hosts;
-  URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
-                                  set2_safe->explicit_hosts(),
-                                  &explicit_hosts);
-
-  URLPatternSet scriptable_hosts;
-  URLPatternSet::CreateDifference(set1_safe->scriptable_hosts(),
-                                  set2_safe->scriptable_hosts(),
-                                  &scriptable_hosts);
-
-  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
-}
-
-// static
-PermissionSet* PermissionSet::CreateIntersection(
-    const PermissionSet* set1,
-    const PermissionSet* set2) {
-  scoped_refptr<PermissionSet> empty = new PermissionSet();
-  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
-  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
-
-  APIPermissionSet apis;
-  APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
-
-  URLPatternSet explicit_hosts;
-  URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
-                                    set2_safe->explicit_hosts(),
-                                    &explicit_hosts);
-
-  URLPatternSet scriptable_hosts;
-  URLPatternSet::CreateIntersection(set1_safe->scriptable_hosts(),
-                                    set2_safe->scriptable_hosts(),
-                                    &scriptable_hosts);
-
-  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
-}
-
-// static
-PermissionSet* PermissionSet::CreateUnion(
-    const PermissionSet* set1,
-    const PermissionSet* set2) {
-  scoped_refptr<PermissionSet> empty = new PermissionSet();
-  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
-  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
-
-  APIPermissionSet apis;
-  APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
-
-  URLPatternSet explicit_hosts;
-  URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
-                             set2_safe->explicit_hosts(),
-                             &explicit_hosts);
-
-  URLPatternSet scriptable_hosts;
-  URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
-                             set2_safe->scriptable_hosts(),
-                             &scriptable_hosts);
-
-  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
-}
-
-bool PermissionSet::operator==(
-    const PermissionSet& rhs) const {
-  return apis_ == rhs.apis_ &&
-      scriptable_hosts_ == rhs.scriptable_hosts_ &&
-      explicit_hosts_ == rhs.explicit_hosts_;
-}
-
-bool PermissionSet::Contains(const PermissionSet& set) const {
-  return apis_.Contains(set.apis()) &&
-         explicit_hosts().Contains(set.explicit_hosts()) &&
-         scriptable_hosts().Contains(set.scriptable_hosts());
-}
-
-std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
-  std::set<std::string> apis_str;
-  for (APIPermissionSet::const_iterator i = apis_.begin();
-       i != apis_.end(); ++i) {
-    apis_str.insert(i->name());
-  }
-  return apis_str;
-}
-
-bool PermissionSet::IsEmpty() const {
-  // Not default if any host permissions are present.
-  if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
-    return false;
-
-  // Or if it has no api permissions.
-  return apis().empty();
-}
-
-bool PermissionSet::HasAPIPermission(
-    APIPermission::ID id) const {
-  return apis().find(id) != apis().end();
-}
-
-bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
-  const APIPermissionInfo* permission =
-      PermissionsInfo::GetInstance()->GetByName(permission_name);
-  CHECK(permission) << permission_name;
-  return (permission && apis_.count(permission->id()));
-}
-
-bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
-  return CheckAPIPermissionWithParam(permission, NULL);
-}
-
-bool PermissionSet::CheckAPIPermissionWithParam(
-    APIPermission::ID permission,
-    const APIPermission::CheckParam* param) const {
-  APIPermissionSet::const_iterator iter = apis().find(permission);
-  if (iter == apis().end())
-    return false;
-  return iter->Check(param);
-}
-
-bool PermissionSet::HasExplicitAccessToOrigin(
-    const GURL& origin) const {
-  return explicit_hosts().MatchesURL(origin);
-}
-
-bool PermissionSet::HasScriptableAccessToURL(
-    const GURL& origin) const {
-  // We only need to check our host list to verify access. The host list should
-  // already reflect any special rules (such as chrome://favicon, all hosts
-  // access, etc.).
-  return scriptable_hosts().MatchesURL(origin);
-}
-
-bool PermissionSet::HasEffectiveAccessToAllHosts() const {
-  // There are two ways this set can have effective access to all hosts:
-  //  1) it has an <all_urls> URL pattern.
-  //  2) it has a named permission with implied full URL access.
-  for (URLPatternSet::const_iterator host = effective_hosts().begin();
-       host != effective_hosts().end(); ++host) {
-    if (host->match_all_urls() ||
-        (host->match_subdomains() && host->host().empty()))
-      return true;
-  }
-
-  for (APIPermissionSet::const_iterator i = apis().begin();
-       i != apis().end(); ++i) {
-    if (i->info()->implies_full_url_access())
-      return true;
-  }
-  return false;
-}
-
-bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
-  return effective_hosts().MatchesURL(url);
-}
-
-bool PermissionSet::HasEffectiveFullAccess() const {
-  for (APIPermissionSet::const_iterator i = apis().begin();
-       i != apis().end(); ++i) {
-    if (i->info()->implies_full_access())
-      return true;
-  }
-  return false;
-}
-
-PermissionSet::~PermissionSet() {}
-
-void PermissionSet::InitImplicitPermissions() {
-  // The downloads permission implies the internal version as well.
-  if (apis_.find(APIPermission::kDownloads) != apis_.end())
-    apis_.insert(APIPermission::kDownloadsInternal);
-
-  // TODO(fsamuel): Is there a better way to request access to the WebRequest
-  // API without exposing it to the Chrome App?
-  if (apis_.find(APIPermission::kWebView) != apis_.end())
-    apis_.insert(APIPermission::kWebRequestInternal);
-
-  // The webRequest permission implies the internal version as well.
-  if (apis_.find(APIPermission::kWebRequest) != apis_.end())
-    apis_.insert(APIPermission::kWebRequestInternal);
-
-  // The fileBrowserHandler permission implies the internal version as well.
-  if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
-    apis_.insert(APIPermission::kFileBrowserHandlerInternal);
-}
-
-void PermissionSet::InitEffectiveHosts() {
-  effective_hosts_.ClearPatterns();
-
-  URLPatternSet::CreateUnion(
-      explicit_hosts(), scriptable_hosts(), &effective_hosts_);
-}
-
-}  // namespace extensions
diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h
deleted file mode 100644
index e4cbd43..0000000
--- a/chrome/common/extensions/permissions/permission_set.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2012 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_COMMON_EXTENSIONS_PERMISSIONS_PERMISSION_SET_H_
-#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_PERMISSION_SET_H_
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/strings/string16.h"
-#include "extensions/common/manifest.h"
-#include "extensions/common/permissions/api_permission.h"
-#include "extensions/common/permissions/api_permission_set.h"
-#include "extensions/common/url_pattern_set.h"
-
-namespace extensions {
-class Extension;
-
-// The PermissionSet is an immutable class that encapsulates an
-// extension's permissions. The class exposes set operations for combining and
-// manipulating the permissions.
-class PermissionSet
-    : public base::RefCountedThreadSafe<PermissionSet> {
- public:
-  // Creates an empty permission set (e.g. default permissions).
-  PermissionSet();
-
-  // Creates a new permission set based on the specified data: the API
-  // permissions, host permissions, and scriptable hosts. The effective hosts
-  // of the newly created permission set will be inferred from the given
-  // host permissions.
-  PermissionSet(const APIPermissionSet& apis,
-                const URLPatternSet& explicit_hosts,
-                const URLPatternSet& scriptable_hosts);
-
-  // Creates a new permission set equal to |set1| - |set2|, passing ownership of
-  // the new set to the caller.
-  static PermissionSet* CreateDifference(
-      const PermissionSet* set1, const PermissionSet* set2);
-
-  // Creates a new permission set equal to the intersection of |set1| and
-  // |set2|, passing ownership of the new set to the caller.
-  static PermissionSet* CreateIntersection(
-      const PermissionSet* set1, const PermissionSet* set2);
-
-  // Creates a new permission set equal to the union of |set1| and |set2|.
-  // Passes ownership of the new set to the caller.
-  static PermissionSet* CreateUnion(
-      const PermissionSet* set1, const PermissionSet* set2);
-
-  bool operator==(const PermissionSet& rhs) const;
-
-  // Returns true if every API or host permission available to |set| is also
-  // available to this. In other words, if the API permissions of |set| are a
-  // subset of this, and the host permissions in this encompass those in |set|.
-  bool Contains(const PermissionSet& set) const;
-
-  // Gets the API permissions in this set as a set of strings.
-  std::set<std::string> GetAPIsAsStrings() const;
-
-  // Returns true if this is an empty set (e.g., the default permission set).
-  bool IsEmpty() const;
-
-  // Returns true if the set has the specified API permission.
-  bool HasAPIPermission(APIPermission::ID permission) const;
-
-  // Returns true if the |extension| explicitly requests access to the given
-  // |permission_name|. Note this does not include APIs without no corresponding
-  // permission, like "runtime" or "browserAction".
-  bool HasAPIPermission(const std::string& permission_name) const;
-
-  // Returns true if the set allows the given permission with the default
-  // permission detal.
-  bool CheckAPIPermission(APIPermission::ID permission) const;
-
-  // Returns true if the set allows the given permission and permission param.
-  bool CheckAPIPermissionWithParam(APIPermission::ID permission,
-      const APIPermission::CheckParam* param) const;
-
-  // Returns true if this includes permission to access |origin|.
-  bool HasExplicitAccessToOrigin(const GURL& origin) const;
-
-  // Returns true if this permission set includes access to script |url|.
-  bool HasScriptableAccessToURL(const GURL& url) const;
-
-  // Returns true if this permission set includes effective access to all
-  // origins.
-  bool HasEffectiveAccessToAllHosts() const;
-
-  // Returns true if this permission set includes effective access to |url|.
-  bool HasEffectiveAccessToURL(const GURL& url) const;
-
-  // Returns ture if this permission set effectively represents full access
-  // (e.g. native code).
-  bool HasEffectiveFullAccess() const;
-
-  const APIPermissionSet& apis() const { return apis_; }
-
-  const URLPatternSet& effective_hosts() const { return effective_hosts_; }
-
-  const URLPatternSet& explicit_hosts() const { return explicit_hosts_; }
-
-  const URLPatternSet& scriptable_hosts() const { return scriptable_hosts_; }
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetWarningMessages_AudioVideo);
-  friend class base::RefCountedThreadSafe<PermissionSet>;
-
-  ~PermissionSet();
-
-  void AddAPIPermission(APIPermission::ID id);
-
-  // Adds permissions implied independently of other context.
-  void InitImplicitPermissions();
-
-  // Initializes the effective host permission based on the data in this set.
-  void InitEffectiveHosts();
-
-  // The api list is used when deciding if an extension can access certain
-  // extension APIs and features.
-  APIPermissionSet apis_;
-
-  // The list of hosts that can be accessed directly from the extension.
-  // TODO(jstritar): Rename to "hosts_"?
-  URLPatternSet explicit_hosts_;
-
-  // The list of hosts that can be scripted by content scripts.
-  // TODO(jstritar): Rename to "user_script_hosts_"?
-  URLPatternSet scriptable_hosts_;
-
-  // The list of hosts this effectively grants access to.
-  URLPatternSet effective_hosts_;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_PERMISSIONS_PERMISSION_SET_H_
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 175b0f7..ca33510 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -14,11 +14,11 @@
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
 #include "chrome/common/extensions/permissions/permission_message_util.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/permissions/socket_permission.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -735,6 +735,7 @@
   skip.insert(APIPermission::kVirtualKeyboardPrivate);
   skip.insert(APIPermission::kWallpaperPrivate);
   skip.insert(APIPermission::kWebRequestInternal);
+  skip.insert(APIPermission::kWebrtcAudioPrivate);
   skip.insert(APIPermission::kWebrtcLoggingPrivate);
   skip.insert(APIPermission::kWebstorePrivate);
 
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index f252bd1..9c0891a 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -12,11 +12,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/chrome_scheme_hosts.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/manifest.h"
@@ -24,6 +24,7 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission_set.h"
 #include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
@@ -66,7 +67,7 @@
                               const APIPermissionSet& permissions) {
   if (!pattern.match_all_urls() &&
       pattern.MatchesScheme(chrome::kChromeUIScheme)) {
-    URLPatternSet chrome_scheme_hosts =
+    URLPatternSet chrome_scheme_hosts = ExtensionsClient::Get()->
         GetPermittedChromeSchemeHosts(extension, permissions);
     if (chrome_scheme_hosts.ContainsPattern(pattern))
       return true;
@@ -214,9 +215,11 @@
       host_permissions->AddPattern(pattern);
       // We need to make sure all_urls matches chrome://favicon and (maybe)
       // chrome://thumbnail, so add them back in to host_permissions separately.
-      if (pattern.match_all_urls())
-        host_permissions->AddPatterns(GetPermittedChromeSchemeHosts(
-            extension, *api_permissions));
+      if (pattern.match_all_urls()) {
+        host_permissions->AddPatterns(
+            ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
+                extension, *api_permissions));
+      }
       continue;
     }
 
@@ -392,9 +395,6 @@
 // static
 bool PermissionsData::CanSilentlyIncreasePermissions(
     const Extension* extension) {
-  if (extension->requires_permissions_consent())
-    return false;
-
   return extension->location() != Manifest::INTERNAL;
 }
 
@@ -537,16 +537,11 @@
   if (extension->location() == Manifest::COMPONENT)
     return true;
 
-  const Extension::ScriptingWhitelist* whitelist =
-      Extension::GetScriptingWhitelist();
+  const ExtensionsClient::ScriptingWhitelist& whitelist =
+      ExtensionsClient::Get()->GetScriptingWhitelist();
 
-  for (Extension::ScriptingWhitelist::const_iterator iter = whitelist->begin();
-       iter != whitelist->end(); ++iter) {
-    if (extension->id() == *iter)
-      return true;
-  }
-
-  return false;
+  return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
+      whitelist.end();
 }
 
 // static
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index 92ec84c..c2bdb07 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -12,7 +12,6 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_test_util.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/permissions/socket_permission.h"
 #include "content/public/common/socket_permission_request.h"
@@ -20,6 +19,7 @@
 #include "extensions/common/id_util.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index d85c2d2..3bbb690 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -256,8 +256,6 @@
     "webkit.webprefs.allow_running_insecure_content";
 #if defined(OS_ANDROID)
 const char kWebKitFontScaleFactor[] = "webkit.webprefs.font_scale_factor";
-const char kWebKitFontScaleFactorQuirk[] =
-    "webkit.webprefs.font_scale_factor_quirk";
 const char kWebKitForceEnableZoom[] = "webkit.webprefs.force_enable_zoom";
 const char kWebKitPasswordEchoEnabled[] =
     "webkit.webprefs.password_echo_enabled";
@@ -637,7 +635,7 @@
 const char kLanguageEnabledExtensionImes[] =
     "settings.language.enabled_extension_imes";
 
-// A integer prefs which determine how we remap modifier keys (e.g. swap Alt and
+// Integer prefs which determine how we remap modifier keys (e.g. swap Alt and
 // Control.) Possible values for these prefs are 0-4. See ModifierKey enum in
 // src/chrome/browser/chromeos/input_method/xkeyboard.h
 const char kLanguageRemapSearchKeyTo[] =
@@ -653,6 +651,11 @@
 const char kLanguageRemapDiamondKeyTo[] =
     "settings.language.remap_diamond_key_to";
 
+// A boolean pref that causes top-row keys to be interpreted as function keys
+// instead of as media keys.
+const char kLanguageSendFunctionKeys[] =
+    "settings.language.send_function_keys";
+
 // A boolean pref which determines whether key repeat is enabled.
 const char kLanguageXkbAutoRepeatEnabled[] =
     "settings.language.xkb_auto_repeat_enabled_r2";
@@ -729,10 +732,17 @@
 // layout/offset information.
 const char kSecondaryDisplays[] = "settings.display.secondary_displays";
 
-// A preference to keep track of the session start time. The value is set
-// after login. When the browser restarts after a crash, the pref value is not
-// changed unless it appears corrupted (value unset, value lying in the future,
-// zero value).
+// A boolean pref indicating whether user activity has been observed in the
+// current session already. The pref is used to restore information about user
+// activity after browser crashes.
+const char kSessionUserActivitySeen[] = "session.user_activity_seen";
+
+// A preference to keep track of the session start time. If the session length
+// limit is configured to start running after initial user activity has been
+// observed, the pref is set after the first user activity in a session.
+// Otherwise, it is set immediately after session start. The pref is used to
+// restore the session start time after browser crashes. The time is expressed
+// as the serialization obtained from base::TimeTicks::ToInternalValue().
 const char kSessionStartTime[] = "session.start_time";
 
 // Holds the maximum session time in milliseconds. If this pref is set, the
@@ -741,6 +751,11 @@
 // system tray.
 const char kSessionLengthLimit[] = "session.length_limit";
 
+// Whether the session length limit should start running only after the first
+// user activity has been observed in a session.
+const char kSessionWaitForInitialUserActivity[] =
+    "session.wait_for_initial_user_activity";
+
 // Inactivity time in milliseconds while the system is on AC power before
 // the screen should be dimmed, turned off, or locked, before an
 // IdleActionImminent D-Bus signal should be sent, or before
@@ -793,6 +808,11 @@
 const char kPowerUserActivityScreenDimDelayFactor[] =
     "power.user_activity_screen_dim_delay_factor";
 
+// Whether the power management delays should start running only after the first
+// user activity has been observed in a session.
+const char kPowerWaitForInitialUserActivity[] =
+    "power.wait_for_initial_user_activity";
+
 // The URL from which the Terms of Service can be downloaded. The value is only
 // honored for public accounts.
 const char kTermsOfServiceURL[] = "terms_of_service.url";
@@ -1208,10 +1228,6 @@
 extern const char kMessageCenterEnabledSyncNotifierIds[] =
     "message_center.enabled_sync_notifier_ids";
 
-// Boolean pref indicating the welcome notification was dismissed by the user.
-extern const char kWelcomeNotificationDismissed[] =
-    "message_center.welcome_notification_dismissed";
-
 // List pref containing synced notification sending services that are currently
 // enabled.
 extern const char kEnabledSyncedNotificationSendingServices[] =
@@ -1227,6 +1243,14 @@
 extern const char kSyncedNotificationFirstRun[] =
     "synced_notification.first_run";
 
+// Boolean pref indicating the welcome notification was dismissed by the user.
+extern const char kWelcomeNotificationDismissed[] =
+    "message_center.welcome_notification_dismissed";
+
+// Boolean pref indicating the welcome notification was previously popped up.
+extern const char kWelcomeNotificationPreviouslyPoppedUp[] =
+    "message_center.welcome_notification_previously_popped_up";
+
 // Dictionary pref that keeps track of per-extension settings. The keys are
 // extension ids.
 const char kExtensionsPref[] = "extensions.settings";
@@ -1356,6 +1380,10 @@
 // SHA-1 hash of the serialized variations seed data.
 const char kVariationsSeedHash[] = "variations_seed_hash";
 
+// An enum value to indicate the execution phase the browser was in.
+const char kStabilityExecutionPhase[] =
+    "user_experience_metrics.stability.execution_phase";
+
 // True if the previous run of the program exited cleanly.
 const char kStabilityExitedCleanly[] =
     "user_experience_metrics.stability.exited_cleanly";
@@ -1863,6 +1891,10 @@
 const char kGoogleServicesUsernamePattern[] =
     "google.services.username_pattern";
 
+// Local hash of authentication password, used for off-line authentication
+// when on-line authentication is not available.
+const char kGoogleServicesPasswordHash[] = "google.services.password_hash";
+
 #if !defined(OS_ANDROID)
 // Tracks the number of times that we have shown the sign in promo at startup.
 const char kSignInPromoStartupCount[] = "sync_promo.startup_count";
@@ -2058,6 +2090,11 @@
 // trigger.
 const char kHotwordSearchEnabled[] = "hotword.search_enabled";
 
+// A boolean pref that controls the enabled-state of hotword search voice
+// trigger when using incognito mode.
+const char kHotwordSearchIncognitoEnabled[] =
+    "hotword.incognito_search_enabled";
+
 #if defined(OS_ANDROID)
 // Boolean that controls the global enabled-state of protected media identifier.
 const char kProtectedMediaIdentifierEnabled[] =
@@ -2373,12 +2410,6 @@
 // its value is a dictionary whose keys are kShelfAlignment and
 // kShelfAutoHideBehavior.
 const char kShelfPreferences[] = "shelf_preferences";
-
-// Tuning for immersive fullscreen.
-const char kImmersiveModeRevealDelayMs[] =
-    "immersive_mode.reveal_delay_ms";
-const char kImmersiveModeRevealXThresholdPixels[] =
-    "immersive_mode.reveal_x_threshold_pixels";
 #endif
 
 #if defined(USE_AURA)
@@ -2426,6 +2457,8 @@
     "gesture.scroll_prediction_seconds";
 const char kSemiLongPressTimeInSeconds[] =
     "gesture.semi_long_press_time_in_seconds";
+const char kShowPressDelayInMS[] =
+    "gesture.show_press_delay_in_ms";
 const char kTabScrubActivationDelayInMS[] =
     "gesture.tab_scrub_activation_delay_in_ms";
 const char kFlingAccelerationCurveCoefficient0[] =
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index fea41cb..e766126 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -126,7 +126,6 @@
 extern const char kWebKitAllowRunningInsecureContent[];
 #if defined(OS_ANDROID)
 extern const char kWebKitFontScaleFactor[];
-extern const char kWebKitFontScaleFactorQuirk[];
 extern const char kWebKitForceEnableZoom[];
 extern const char kWebKitPasswordEchoEnabled[];
 #endif
@@ -218,6 +217,7 @@
 extern const char kLanguageRemapControlKeyTo[];
 extern const char kLanguageRemapAltKeyTo[];
 extern const char kLanguageRemapDiamondKeyTo[];
+extern const char kLanguageSendFunctionKeys[];
 extern const char kLanguageXkbAutoRepeatEnabled[];
 extern const char kLanguageXkbAutoRepeatDelay[];
 extern const char kLanguageXkbAutoRepeatInterval[];
@@ -242,8 +242,10 @@
 extern const char kDisplayPowerState[];
 extern const char kDisplayProperties[];
 extern const char kSecondaryDisplays[];
+extern const char kSessionUserActivitySeen[];
 extern const char kSessionStartTime[];
 extern const char kSessionLengthLimit[];
+extern const char kSessionWaitForInitialUserActivity[];
 extern const char kPowerAcScreenDimDelayMs[];
 extern const char kPowerAcScreenOffDelayMs[];
 extern const char kPowerAcScreenLockDelayMs[];
@@ -262,6 +264,7 @@
 extern const char kPowerAllowScreenWakeLocks[];
 extern const char kPowerPresentationScreenDimDelayFactor[];
 extern const char kPowerUserActivityScreenDimDelayFactor[];
+extern const char kPowerWaitForInitialUserActivity[];
 extern const char kTermsOfServiceURL[];
 extern const char kUsedPolicyCertificatesOnce[];
 extern const char kAttestationEnabled[];
@@ -389,10 +392,11 @@
 extern const char kMessageCenterDisabledExtensionIds[];
 extern const char kMessageCenterDisabledSystemComponentIds[];
 extern const char kMessageCenterEnabledSyncNotifierIds[];
-extern const char kWelcomeNotificationDismissed[];
 extern const char kEnabledSyncedNotificationSendingServices[];
 extern const char kInitializedSyncedNotificationSendingServices[];
 extern const char kSyncedNotificationFirstRun[];
+extern const char kWelcomeNotificationDismissed[];
+extern const char kWelcomeNotificationPreviouslyPoppedUp[];
 
 extern const char kExtensionsPref[];
 extern const char kExtensionsLastChromeVersion[];
@@ -452,6 +456,7 @@
 extern const char kProfileInfoCache[];
 extern const char kProfileCreatedByVersion[];
 
+extern const char kStabilityExecutionPhase[];
 extern const char kStabilityExitedCleanly[];
 extern const char kStabilityStatsVersion[];
 extern const char kStabilityStatsBuildTime[];
@@ -629,6 +634,7 @@
 extern const char kGoogleServicesLastUsername[];
 extern const char kGoogleServicesUsername[];
 extern const char kGoogleServicesUsernamePattern[];
+extern const char kGoogleServicesPasswordHash[];
 extern const char kSyncUsingSecondaryPassphrase[];
 extern const char kSyncEncryptionBootstrapToken[];
 extern const char kSyncKeystoreEncryptionBootstrapToken[];
@@ -729,6 +735,7 @@
 extern const char kVideoCaptureAllowedUrls[];
 
 extern const char kHotwordSearchEnabled[];
+extern const char kHotwordSearchIncognitoEnabled[];
 
 #if defined(OS_ANDROID)
 extern const char kProtectedMediaIdentifierEnabled[];
@@ -833,9 +840,6 @@
 extern const char kPinnedLauncherApps[];
 extern const char kShowLogoutButtonInTray[];
 extern const char kShelfPreferences[];
-
-extern const char kImmersiveModeRevealDelayMs[];
-extern const char kImmersiveModeRevealXThresholdPixels[];
 #endif
 
 #if defined(USE_AURA)
@@ -861,6 +865,7 @@
 extern const char kRailStartProportion[];
 extern const char kScrollPredictionSeconds[];
 extern const char kSemiLongPressTimeInSeconds[];
+extern const char kShowPressDelayInMS[];
 extern const char kTabScrubActivationDelayInMS[];
 extern const char kFlingAccelerationCurveCoefficient0[];
 extern const char kFlingAccelerationCurveCoefficient1[];
diff --git a/chrome/common/print_messages.cc b/chrome/common/print_messages.cc
index a7ff157..74fa280 100644
--- a/chrome/common/print_messages.cc
+++ b/chrome/common/print_messages.cc
@@ -27,7 +27,6 @@
     print_scaling_option(WebKit::WebPrintScalingOptionSourceSize),
     print_to_pdf(false),
     display_header_footer(false),
-    date(),
     title(),
     url(),
     should_print_backgrounds(false) {
@@ -54,7 +53,6 @@
   print_scaling_option = WebKit::WebPrintScalingOptionSourceSize;
   print_to_pdf = false;
   display_header_footer = false;
-  date = string16();
   title = string16();
   url = string16();
   should_print_backgrounds = false;
diff --git a/chrome/common/print_messages.h b/chrome/common/print_messages.h
index bfc0026..fe519fd 100644
--- a/chrome/common/print_messages.h
+++ b/chrome/common/print_messages.h
@@ -45,7 +45,6 @@
   WebKit::WebPrintScalingOption print_scaling_option;
   bool print_to_pdf;
   bool display_header_footer;
-  string16 date;
   string16 title;
   string16 url;
   bool should_print_backgrounds;
@@ -137,9 +136,6 @@
   // Specifies if the header and footer should be rendered.
   IPC_STRUCT_TRAITS_MEMBER(display_header_footer)
 
-  // Date string to be printed as header if requested by the user.
-  IPC_STRUCT_TRAITS_MEMBER(date)
-
   // Title string to be printed as header if requested by the user.
   IPC_STRUCT_TRAITS_MEMBER(title)
 
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index a601a75..2913e86 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -376,10 +376,6 @@
 IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetClientSidePhishingDetection,
                     bool /* enable_phishing_detection */)
 
-// This message asks frame sniffer start.
-IPC_MESSAGE_ROUTED1(ChromeViewMsg_StartFrameSniffer,
-                    string16 /* frame-name */)
-
 // Asks the renderer for a thumbnail of the image selected by the most
 // recently opened context menu, if there is one. If the image's area
 // is greater than thumbnail_min_area it will be downscaled to
@@ -507,10 +503,15 @@
 // Returns whether any internal plugin supporting |mime_type| is registered
 // Does not determine whether the plugin can actually be instantiated
 // (e.g. whether it is allowed or has all its dependencies).
-IPC_SYNC_MESSAGE_CONTROL1_1(
+// When the returned *|is_registered| is true, |additional_param_names| and
+// |additional_param_values| contain the name-value pairs, if any, specified
+// for the *first* plugin found that is registered for |mime_type|.
+IPC_SYNC_MESSAGE_CONTROL1_3(
     ChromeViewHostMsg_IsInternalPluginRegisteredForMimeType,
     std::string /* mime_type */,
-    bool /* registered */)
+    bool /* registered */,
+    std::vector<base::string16> /* additional_param_names */,
+    std::vector<base::string16> /* additional_param_values */)
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
 // Tells the browser to search for a plug-in that can handle the given MIME
@@ -734,14 +735,13 @@
                     int /* page_id */,
                     GURL /* url */)
 
-// Tells InstantExtended to navigate the active tab to a possibly priveleged
+// Tells InstantExtended to navigate the active tab to a possibly privileged
 // URL.
-IPC_MESSAGE_ROUTED5(ChromeViewHostMsg_SearchBoxNavigate,
+IPC_MESSAGE_ROUTED4(ChromeViewHostMsg_SearchBoxNavigate,
                     int /* page_id */,
                     GURL /* destination */,
-                    content::PageTransition /* transition */,
                     WindowOpenDisposition /* disposition */,
-                    bool /* is_search_type */)
+                    bool /*is_most_visited_item_url*/)
 
 // Tells InstantExtended to undo all most visited item deletions.
 IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions,
diff --git a/chrome/common/safe_browsing/DEPS b/chrome/common/safe_browsing/DEPS
new file mode 100644
index 0000000..c6e9550
--- /dev/null
+++ b/chrome/common/safe_browsing/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/zlib",
+]
diff --git a/chrome/common/service_messages.h b/chrome/common/service_messages.h
index e868b63..1f05e63 100644
--- a/chrome/common/service_messages.h
+++ b/chrome/common/service_messages.h
@@ -34,6 +34,9 @@
 // (whether it is enabled, the email address and the proxy id).
 IPC_MESSAGE_CONTROL0(ServiceMsg_GetCloudPrintProxyInfo)
 
+// Requests a message back with serialized UMA histograms.
+IPC_MESSAGE_CONTROL0(ServiceMsg_GetHistograms)
+
 // Tell the service process to shutdown.
 IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown)
 
@@ -43,9 +46,10 @@
 //-----------------------------------------------------------------------------
 // Service process host messages:
 // These are messages from the service process to the browser.
-// Sent when the cloud print proxy has an authentication error.
-IPC_MESSAGE_CONTROL0(ServiceHostMsg_CloudPrintProxy_AuthError)
-
 // Sent as a response to a request for cloud print proxy info
 IPC_MESSAGE_CONTROL1(ServiceHostMsg_CloudPrintProxy_Info,
                      cloud_print::CloudPrintProxyInfo /* proxy info */)
+
+// Sent as a response to ServiceMsg_GetHistograms.
+IPC_MESSAGE_CONTROL1(ServiceHostMsg_Histograms,
+                     std::vector<std::string> /* pickled_histograms */)
diff --git a/chrome/common/translate/translate_errors.h b/chrome/common/translate/translate_errors.h
index af011aa..f41a921 100644
--- a/chrome/common/translate/translate_errors.h
+++ b/chrome/common/translate/translate_errors.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_COMMON_TRANSLATE_TRANSLATE_ERRORS_H_
 #define CHROME_COMMON_TRANSLATE_TRANSLATE_ERRORS_H_
 
+#include "base/basictypes.h"
+
 // This file consolidates all the error types for translation of a page.
 // Note: TranslateErrors is used for UMA and translate_internals.js.
 // Assigned numbers should be changed because the number is binded to UMA value.
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index fc4c094..bb7684e 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -472,10 +472,7 @@
     "https://support.google.com/chrome/?p=settings_sign_in";
 
 const char kDownloadScanningLearnMoreURL[] =
-    "https://support.google.com/chrome/?p=ib_download_scan";
-
-const char kDownloadPotentiallyUnwantedLearnMoreURL[] =
-    "https://support.google.com/chrome/?p=ui_protect_settings";
+    "https://support.google.com/chrome/?p=ib_download_blocked";
 
 const char kDownloadInterruptedLearnMoreURL[] =
     "https://support.google.com/chrome/?p=ui_download_errors";
@@ -490,6 +487,9 @@
     "https://support.google.com/chrome/?p=settings_cloud_print";
 #endif
 
+const char kCloudPrintNoDestinationsLearnMoreURL[] =
+    "https://www.google.com/cloudprint/learn/";
+
 const char kAppLauncherHelpURL[] =
     "https://support.google.com/chrome_webstore/?p=cws_app_launcher";
 
@@ -519,6 +519,9 @@
 const char kNotificationsHelpURL[] =
     "https://support.google.com/chrome/?p=ui_notifications";
 
+const char kNotificationWelcomeLearnMoreURL[] =
+    "https://support.google.com/chrome/?p=ib_google_now_welcome";
+
 // Add hosts here to be included in chrome://chrome-urls (about:about).
 // These hosts will also be suggested by BuiltinProvider.
 const char* const kChromeHostURLs[] = {
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 172d09b..78e5b6c 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -404,10 +404,6 @@
 // The URL for the "Learn more" page for download scanning.
 extern const char kDownloadScanningLearnMoreURL[];
 
-// The URL for the "Learn more" page for downloads flagged as potentially
-// unwanted by the SafeBrowsing service.
-extern const char kDownloadPotentiallyUnwantedLearnMoreURL[];
-
 // The URL for the "Learn more" page for interrupted downloads.
 extern const char kDownloadInterruptedLearnMoreURL[];
 
@@ -437,6 +433,9 @@
 
 extern const char kNotificationsHelpURL[];
 
+// The Welcome Notification More Info URL.
+extern const char kNotificationWelcomeLearnMoreURL[];
+
 // Gets the hosts/domains that are shown in chrome://chrome-urls.
 extern const char* const kChromeHostURLs[];
 extern const size_t kNumberOfChromeHostURLs;
@@ -487,6 +486,9 @@
 // "Learn more" URL for the Cloud Print section under Options.
 extern const char kCloudPrintLearnMoreURL[];
 
+// "Learn more" URL for the Cloud Print Preview No Destinations Promotion.
+extern const char kCloudPrintNoDestinationsLearnMoreURL[];
+
 // Parameters that get appended to force SafeSearch.
 extern const char kSafeSearchSafeParameter[];
 extern const char kSafeSearchSsuiParameter[];
diff --git a/chrome/installer/linux/rpm/expected_deps_i386 b/chrome/installer/linux/rpm/expected_deps_i386
index 8401dcf..40d1741 100644
--- a/chrome/installer/linux/rpm/expected_deps_i386
+++ b/chrome/installer/linux/rpm/expected_deps_i386
@@ -27,7 +27,6 @@
 libfontconfig.so.1
 libfreetype.so.6
 libgcc_s.so.1
-libgcc_s.so.1(GCC_3.0)
 libgcc_s.so.1(GCC_3.4)
 libgcc_s.so.1(GCC_4.0.0)
 libgcc_s.so.1(GLIBC_2.0)
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index bfd60cd..07453a4 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -21,7 +21,6 @@
 libfontconfig.so.1()(64bit)
 libfreetype.so.6()(64bit)
 libgcc_s.so.1()(64bit)
-libgcc_s.so.1(GCC_3.0)(64bit)
 libgcc_s.so.1(GCC_3.4)(64bit)
 libgcc_s.so.1(GCC_4.0.0)(64bit)
 libgconf-2.so.4()(64bit)
diff --git a/chrome/installer/mac/dirdiffer.sh b/chrome/installer/mac/dirdiffer.sh
index 2e81928..cd8f673 100755
--- a/chrome/installer/mac/dirdiffer.sh
+++ b/chrome/installer/mac/dirdiffer.sh
@@ -106,7 +106,7 @@
 # find_tool looks for an executable file named |tool_name|:
 #  - in the same directory as this script,
 #  - if this script is located in a Chromium source tree, at the expected
-#    Release output location in the Mac xcodebuild directory,
+#    Release output location in the Mac out directory,
 #  - as above, but in the Debug output location
 # If found in any of the above locations, the script's path is output.
 # Otherwise, this function outputs |tool_name| as a fallback, allowing it to
@@ -126,13 +126,13 @@
   local script_dir_phys
   script_dir_phys="$(cd "${script_dir}" && pwd -P)"
   if [[ "${script_dir_phys}" =~ ^(.*)/src/chrome/installer/mac$ ]]; then
-    tool="${BASH_REMATCH[1]}/src/xcodebuild/Release/${tool_name}"
+    tool="${BASH_REMATCH[1]}/src/out/Release/${tool_name}"
     if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then
       echo "${tool}"
       return
     fi
 
-    tool="${BASH_REMATCH[1]}/src/xcodebuild/Debug/${tool_name}"
+    tool="${BASH_REMATCH[1]}/src/out/Debug/${tool_name}"
     if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then
       echo "${tool}"
       return
diff --git a/chrome/installer/mac/dirpatcher.sh b/chrome/installer/mac/dirpatcher.sh
index 7b68fca..b4d0620 100755
--- a/chrome/installer/mac/dirpatcher.sh
+++ b/chrome/installer/mac/dirpatcher.sh
@@ -49,7 +49,7 @@
 # find_tool looks for an executable file named |tool_name|:
 #  - in the same directory as this script,
 #  - if this script is located in a Chromium source tree, at the expected
-#    Release output location in the Mac xcodebuild directory,
+#    Release output location in the Mac out directory,
 #  - as above, but in the Debug output location
 # If found in any of the above locations, the script's path is output.
 # Otherwise, this function outputs |tool_name| as a fallback, allowing it to
@@ -69,13 +69,13 @@
   local script_dir_phys
   script_dir_phys="$(cd "${script_dir}" && pwd -P)"
   if [[ "${script_dir_phys}" =~ ^(.*)/src/chrome/installer/mac$ ]]; then
-    tool="${BASH_REMATCH[1]}/src/xcodebuild/Release/${tool_name}"
+    tool="${BASH_REMATCH[1]}/src/out/Release/${tool_name}"
     if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then
       echo "${tool}"
       return
     fi
 
-    tool="${BASH_REMATCH[1]}/src/xcodebuild/Debug/${tool_name}"
+    tool="${BASH_REMATCH[1]}/src/out/Debug/${tool_name}"
     if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then
       echo "${tool}"
       return
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 473c3bb..460c4905 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -800,7 +800,8 @@
                                   const string16& browser_entry_suffix,
                                   InstallStatus* exit_code) {
   DCHECK(exit_code);
-  if (!dist->CanSetAsDefault()) {
+  if (dist->GetDefaultBrowserControlPolicy() ==
+      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
     // We should have never set those keys.
     return true;
   }
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index b311d59..2456cbd 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -265,8 +265,9 @@
   return L"Software\\Chromium";
 }
 
-bool BrowserDistribution::CanSetAsDefault() {
-  return true;
+BrowserDistribution::DefaultBrowserControlPolicy
+    BrowserDistribution::GetDefaultBrowserControlPolicy() {
+  return DEFAULT_BROWSER_FULL_CONTROL;
 }
 
 bool BrowserDistribution::CanCreateDesktopShortcuts() {
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 1d11a87..a1ac824 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -40,6 +40,12 @@
     // TODO(calamity): add SUBFOLDER_APPS when refactoring chrome app dir code.
   };
 
+  enum DefaultBrowserControlPolicy {
+    DEFAULT_BROWSER_UNSUPPORTED,
+    DEFAULT_BROWSER_OS_CONTROL_ONLY,
+    DEFAULT_BROWSER_FULL_CONTROL
+  };
+
   virtual ~BrowserDistribution() {}
 
   static BrowserDistribution* GetDistribution();
@@ -129,8 +135,9 @@
 
   virtual string16 GetVersionKey();
 
-  // Returns true if this distribution can be set as the default browser.
-  virtual bool CanSetAsDefault();
+  // Returns an enum specifying the different ways in which this distribution
+  // is allowed to be set as default.
+  virtual DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy();
 
   virtual bool CanCreateDesktopShortcuts();
 
diff --git a/chrome/installer/util/chrome_app_host_distribution.cc b/chrome/installer/util/chrome_app_host_distribution.cc
index be0fdf5..9ecf2ab 100644
--- a/chrome/installer/util/chrome_app_host_distribution.cc
+++ b/chrome/installer/util/chrome_app_host_distribution.cc
@@ -130,8 +130,9 @@
   return key;
 }
 
-bool ChromeAppHostDistribution::CanSetAsDefault() {
-  return false;
+BrowserDistribution::DefaultBrowserControlPolicy
+    ChromeAppHostDistribution::GetDefaultBrowserControlPolicy() {
+  return DEFAULT_BROWSER_UNSUPPORTED;
 }
 
 bool ChromeAppHostDistribution::CanCreateDesktopShortcuts() {
diff --git a/chrome/installer/util/chrome_app_host_distribution.h b/chrome/installer/util/chrome_app_host_distribution.h
index c0d2abb..567ede7 100644
--- a/chrome/installer/util/chrome_app_host_distribution.h
+++ b/chrome/installer/util/chrome_app_host_distribution.h
@@ -54,7 +54,7 @@
 
   virtual string16 GetVersionKey() OVERRIDE;
 
-  virtual bool CanSetAsDefault() OVERRIDE;
+  virtual DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy() OVERRIDE;
 
   virtual bool CanCreateDesktopShortcuts() OVERRIDE;
 
diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc
index 0b12cc1..58f475b 100644
--- a/chrome/installer/util/chrome_frame_distribution.cc
+++ b/chrome/installer/util/chrome_frame_distribution.cc
@@ -131,8 +131,9 @@
   }
 }
 
-bool ChromeFrameDistribution::CanSetAsDefault() {
-  return false;
+BrowserDistribution::DefaultBrowserControlPolicy
+    ChromeFrameDistribution::GetDefaultBrowserControlPolicy() {
+  return DEFAULT_BROWSER_UNSUPPORTED;
 }
 
 bool ChromeFrameDistribution::CanCreateDesktopShortcuts() {
diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h
index 45db56a..0a69bd1 100644
--- a/chrome/installer/util/chrome_frame_distribution.h
+++ b/chrome/installer/util/chrome_frame_distribution.h
@@ -51,7 +51,7 @@
 
   virtual string16 GetIconFilename() OVERRIDE;
 
-  virtual bool CanSetAsDefault() OVERRIDE;
+  virtual DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy() OVERRIDE;
 
   virtual bool CanCreateDesktopShortcuts() OVERRIDE;
 
diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc
index 62c645b..7e8bdcf 100644
--- a/chrome/installer/util/chromium_binaries_distribution.cc
+++ b/chrome/installer/util/chromium_binaries_distribution.cc
@@ -100,8 +100,9 @@
   return string16(L"Software\\").append(kChromiumBinariesName);
 }
 
-bool ChromiumBinariesDistribution::CanSetAsDefault() {
-  return false;
+BrowserDistribution::DefaultBrowserControlPolicy
+    ChromiumBinariesDistribution::GetDefaultBrowserControlPolicy() {
+  return DEFAULT_BROWSER_UNSUPPORTED;
 }
 
 int ChromiumBinariesDistribution::GetIconIndex(ShortcutType shortcut_type) {
diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h
index 68de283..6c00669 100644
--- a/chrome/installer/util/chromium_binaries_distribution.h
+++ b/chrome/installer/util/chromium_binaries_distribution.h
@@ -49,7 +49,7 @@
 
   virtual string16 GetVersionKey() OVERRIDE;
 
-  virtual bool CanSetAsDefault() OVERRIDE;
+  virtual DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy() OVERRIDE;
 
   virtual bool GetChromeChannel(string16* channel) OVERRIDE;
 
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 1925f30..f86e8ff 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -75,8 +75,9 @@
       installer::kSxSSuffix);
 }
 
-bool GoogleChromeSxSDistribution::CanSetAsDefault() {
-  return false;
+BrowserDistribution::DefaultBrowserControlPolicy
+    GoogleChromeSxSDistribution::GetDefaultBrowserControlPolicy() {
+  return DEFAULT_BROWSER_OS_CONTROL_ONLY;
 }
 
 int GoogleChromeSxSDistribution::GetIconIndex(ShortcutType shortcut_type) {
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.h b/chrome/installer/util/google_chrome_sxs_distribution.h
index d089196..e069c68 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.h
+++ b/chrome/installer/util/google_chrome_sxs_distribution.h
@@ -27,7 +27,7 @@
   virtual string16 GetBrowserProgIdDesc() OVERRIDE;
   virtual string16 GetInstallSubDir() OVERRIDE;
   virtual string16 GetUninstallRegPath() OVERRIDE;
-  virtual bool CanSetAsDefault() OVERRIDE;
+  virtual DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy() OVERRIDE;
   virtual bool GetChromeChannel(string16* channel) OVERRIDE;
   virtual bool GetCommandExecuteImplClsid(
       string16* handler_class_uuid) OVERRIDE;
diff --git a/chrome/installer/util/helper.cc b/chrome/installer/util/helper.cc
index bb0f22e..10a2156 100644
--- a/chrome/installer/util/helper.cc
+++ b/chrome/installer/util/helper.cc
@@ -45,8 +45,11 @@
 
 void GetChromeUserDataPaths(BrowserDistribution* dist,
                             std::vector<base::FilePath>* paths) {
-  const bool has_metro_data = dist->CanSetAsDefault() &&
-      base::win::GetVersion() >= base::win::VERSION_WIN8;
+  const bool has_metro_data =
+      base::win::GetVersion() >= base::win::VERSION_WIN8 &&
+      dist->GetDefaultBrowserControlPolicy() !=
+          BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED;
+
   base::FilePath data_dir(GetChromeInstallBasePath(false, dist,
                                                    kInstallUserDataDir));
   if (data_dir.empty()) {
diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py
index 03c17a0..85fde1c 100755
--- a/chrome/installer/util/prebuild/create_string_rc.py
+++ b/chrome/installer/util/prebuild/create_string_rc.py
@@ -35,9 +35,9 @@
 from google import path_utils
 
 # Quick hack to fix the path.
-sys.path.append(os.path.abspath('../../tools/grit/grit/extern'))
-sys.path.append(os.path.abspath('../tools/grit/grit/extern'))
-import FP
+sys.path.append(os.path.abspath('../../tools/grit'))
+sys.path.append(os.path.abspath('../tools/grit'))
+from grit.extern import tclib
 
 # The IDs of strings we want to import from generated_resources.grd and include
 # in setup.exe's resources.
@@ -127,9 +127,9 @@
                           x.getAttribute('name') == string_id][0])
   message_texts = [node.firstChild.nodeValue.strip() for node in message_nodes]
 
-  # The fingerprint of the string is the message ID in the translation files
-  # (xtb files).
-  translation_ids = [str(FP.FingerPrint(text)) for text in message_texts]
+  # Generate the message ID of the string to correlate it with its translations
+  # in the xtb files.
+  translation_ids = [tclib.GenerateMessageId(text) for text in message_texts]
 
   # Manually put _EN_US in the list of translated strings because it doesn't
   # have a .xtb file.
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 19a5feb..f5b8544 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1695,8 +1695,11 @@
 }
 
 ShellUtil::DefaultState ShellUtil::GetChromeDefaultState() {
-  if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
+  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
+  if (distribution->GetDefaultBrowserControlPolicy() ==
+      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
     return NOT_DEFAULT;
+  }
   // When we check for default browser we don't necessarily want to count file
   // type handlers and icons as having changed the default browser status,
   // since the user may have changed their shell settings to cause HTML files
@@ -1712,8 +1715,12 @@
 
 ShellUtil::DefaultState ShellUtil::GetChromeDefaultProtocolClientState(
     const string16& protocol) {
-  if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
+  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
+  if (distribution->GetDefaultBrowserControlPolicy() ==
+      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
     return NOT_DEFAULT;
+  }
+
   if (protocol.empty())
     return UNKNOWN_DEFAULT;
 
@@ -1732,8 +1739,11 @@
                                   bool elevate_if_not_admin) {
   DCHECK(!(shell_change & ShellUtil::SYSTEM_LEVEL) || IsUserAnAdmin());
 
-  if (!dist->CanSetAsDefault())
+  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
+  if (distribution->GetDefaultBrowserControlPolicy() !=
+      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
     return false;
+  }
 
   // Windows 8 does not permit making a browser default just like that.
   // This process needs to be routed through the system's UI. Use
@@ -1796,8 +1806,10 @@
 bool ShellUtil::ShowMakeChromeDefaultSystemUI(BrowserDistribution* dist,
                                               const string16& chrome_exe) {
   DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
-  if (!dist->CanSetAsDefault())
+  if (dist->GetDefaultBrowserControlPolicy() !=
+      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
     return false;
+  }
 
   if (!RegisterChromeBrowser(dist, chrome_exe, string16(), true))
       return false;
@@ -1822,8 +1834,10 @@
 bool ShellUtil::MakeChromeDefaultProtocolClient(BrowserDistribution* dist,
                                                 const string16& chrome_exe,
                                                 const string16& protocol) {
-  if (!dist->CanSetAsDefault())
+  if (dist->GetDefaultBrowserControlPolicy() !=
+      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
     return false;
+  }
 
   if (!RegisterChromeForProtocol(dist, chrome_exe, string16(), protocol, true))
     return false;
@@ -1869,8 +1883,10 @@
     const string16& chrome_exe,
     const string16& protocol) {
   DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
-  if (!dist->CanSetAsDefault())
+  if (dist->GetDefaultBrowserControlPolicy() !=
+      BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) {
     return false;
+  }
 
   if (!RegisterChromeForProtocol(dist, chrome_exe, string16(), protocol, true))
     return false;
@@ -1898,8 +1914,10 @@
                                       const string16& chrome_exe,
                                       const string16& unique_suffix,
                                       bool elevate_if_not_admin) {
-  if (!dist->CanSetAsDefault())
+  if (dist->GetDefaultBrowserControlPolicy() ==
+      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
     return false;
+  }
 
   CommandLine& command_line = *CommandLine::ForCurrentProcess();
 
@@ -1988,8 +2006,10 @@
                                           const string16& unique_suffix,
                                           const string16& protocol,
                                           bool elevate_if_not_admin) {
-  if (!dist->CanSetAsDefault())
+  if (dist->GetDefaultBrowserControlPolicy() ==
+      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
     return false;
+  }
 
   string16 suffix;
   if (!unique_suffix.empty()) {
diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate
index 057e0b9..7f9fc0e 100644
--- a/chrome/interactive_ui_tests.isolate
+++ b/chrome/interactive_ui_tests.isolate
@@ -8,8 +8,6 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
-          '-j1',
           '<(PRODUCT_DIR)/interactive_ui_tests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_tracked': [
@@ -67,8 +65,6 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
-          '-j1',
           '<(PRODUCT_DIR)/interactive_ui_tests<(EXECUTABLE_SUFFIX)',
         ],
       },
diff --git a/chrome/nacl/nacl_helper_linux.cc b/chrome/nacl/nacl_helper_linux.cc
index 88d44b1..78b01bf 100644
--- a/chrome/nacl/nacl_helper_linux.cc
+++ b/chrome/nacl/nacl_helper_linux.cc
@@ -335,7 +335,7 @@
 // __asan_default_options should not be instrumented, because it is called
 // before ASan is initialized.
 extern "C"
-__attribute__((no_address_safety_analysis))
+__attribute__((no_sanitize_address))
 const char* __asan_default_options() {
   return kAsanDefaultOptionsNaCl;
 }
diff --git a/chrome/plugin/chrome_content_plugin_client.cc b/chrome/plugin/chrome_content_plugin_client.cc
index f9f8f0c..4e1dee7 100644
--- a/chrome/plugin/chrome_content_plugin_client.cc
+++ b/chrome/plugin/chrome_content_plugin_client.cc
@@ -17,14 +17,6 @@
 #endif
 #endif
 
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/strings/sys_string_conversions.h"
-#include "grit/chromium_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#endif
-
 namespace chrome {
 
 void ChromeContentPluginClient::PreSandboxInitialization() {
@@ -52,21 +44,4 @@
 #endif // defined(ENABLE_REMOTING)
 }
 
-void ChromeContentPluginClient::PluginProcessStarted(
-    const string16& plugin_name) {
-#if defined(OS_MACOSX)
-  base::ScopedCFTypeRef<CFStringRef> cf_plugin_name(
-      base::SysUTF16ToCFStringRef(plugin_name));
-  base::ScopedCFTypeRef<CFStringRef> app_name(base::SysUTF16ToCFStringRef(
-      l10n_util::GetStringUTF16(IDS_SHORT_PLUGIN_APP_NAME)));
-  base::ScopedCFTypeRef<CFStringRef> process_name(
-      CFStringCreateWithFormat(kCFAllocatorDefault,
-                               NULL,
-                               CFSTR("%@ (%@)"),
-                               cf_plugin_name.get(),
-                               app_name.get()));
-  base::mac::SetProcessName(process_name);
-#endif
-}
-
 }  // namespace chrome
diff --git a/chrome/plugin/chrome_content_plugin_client.h b/chrome/plugin/chrome_content_plugin_client.h
index 0392102..0d224f6 100644
--- a/chrome/plugin/chrome_content_plugin_client.h
+++ b/chrome/plugin/chrome_content_plugin_client.h
@@ -13,7 +13,6 @@
 class ChromeContentPluginClient : public content::ContentPluginClient {
  public:
   virtual void PreSandboxInitialization() OVERRIDE;
-  virtual void PluginProcessStarted(const string16& plugin_name) OVERRIDE;
 };
 
 }  // namespace chrome
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index cc3dfff..5d98d35 100644
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -9,12 +9,8 @@
   "+content/public/renderer",
   "+extensions/common",
   "+grit",  # For generated headers
-  "+media/base",  # For initializing media library and media switches.
-  "+ppapi/native_client/src/trusted/plugin/nacl_entry_points.h",  # For NaCl registration.
   "+ppapi/c",
-  "+ppapi/proxy",
   "+ppapi/shared_impl",
-  "+sandbox/win/src",
   "+skia",
 
   "+webkit/child",
@@ -22,9 +18,5 @@
   "+webkit/glue",
   "+webkit/renderer",
 
-  "+third_party/npapi/bindings",
-  "+third_party/re2",
-  "+third_party/smhasher",
   "+third_party/sqlite",
-  "+third_party/widevine",
 ]
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index 5d4e476..ee73e13 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -66,6 +66,8 @@
     "  <INPUT type=\"text\" style=\"visibility: hidden\""
     "         id=\"invisible\"/>"
     "  <INPUT type=\"text\" style=\"display: none\" id=\"displaynone\"/>"
+    "  <INPUT type=\"month\" id=\"month\"/>"
+    "  <INPUT type=\"month\" id=\"month-nonempty\" value=\"2011-12\"/>"
     "  <SELECT id=\"select\">"
     "    <OPTION></OPTION>"
     "    <OPTION value=\"CA\">California</OPTION>"
@@ -234,7 +236,8 @@
     } else if (element.formControlType() == "textarea") {
       value = element.to<WebTextAreaElement>().value();
     } else {
-      ASSERT_EQ("text", element.formControlType());
+      ASSERT_TRUE(element.formControlType() == "text" ||
+                  element.formControlType() == "month");
       WebInputElement input_element = GetMainFrame()->document().getElementById(
           ASCIIToUTF16(field_case.name)).to<WebInputElement>();
       value = (input_element.*get_value_function)();
@@ -462,7 +465,6 @@
   expected.form_control_type = "textarea";
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, result_sans_value);
 
-
   FormFieldData result_with_value;
   WebFormControlElementToFormField(element, autofill::EXTRACT_VALUE,
                                    &result_with_value);
@@ -471,6 +473,32 @@
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, result_with_value);
 }
 
+// We should be able to extract an <input type="month"> field.
+TEST_F(FormAutofillTest, WebFormControlElementToFormFieldMonthInput) {
+  LoadHTML("<INPUT type=\"month\" id=\"element\" value=\"2011-12\">");
+
+  WebFrame* frame = GetMainFrame();
+  ASSERT_NE(static_cast<WebFrame*>(NULL), frame);
+
+  WebElement web_element = frame->document().getElementById("element");
+  WebFormControlElement element = web_element.to<WebFormControlElement>();
+  FormFieldData result_sans_value;
+  WebFormControlElementToFormField(element, autofill::EXTRACT_NONE,
+                                   &result_sans_value);
+
+  FormFieldData expected;
+  expected.name = ASCIIToUTF16("element");
+  expected.max_length = 0;
+  expected.form_control_type = "month";
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, result_sans_value);
+
+  FormFieldData result_with_value;
+  WebFormControlElementToFormField(element, autofill::EXTRACT_VALUE,
+                                   &result_with_value);
+  expected.value = ASCIIToUTF16("2011-12");
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, result_with_value);
+}
+
 // We should not extract the value for non-text and non-select fields.
 TEST_F(FormAutofillTest, WebFormControlElementToFormFieldInvalidType) {
   LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
@@ -533,6 +561,7 @@
       "<INPUT type=\"text\" id=\"multi-valued\" "
       "       autocomplete=\"billing email\"/>"
       "<INPUT type=\"text\" id=\"experimental\" x-autocompletetype=\"email\"/>"
+      "<INPUT type=\"month\" id=\"month\" autocomplete=\"cc-exp\"/>"
       "<SELECT id=\"select\" autocomplete=\"state\"/>"
       "  <OPTION value=\"CA\">California</OPTION>"
       "  <OPTION value=\"TX\">Texas</OPTION>"
@@ -566,6 +595,8 @@
     { "regular", "text", "email" },
     // Verify that we correctly extract multiple tokens as well.
     { "multi-valued", "text", "billing email" },
+    // Verify that <input type="month"> fields are supported.
+    { "month", "month", "cc-exp" },
     // We previously extracted this data from the experimental
     // 'x-autocompletetype' attribute.  Now that the field type hints are part
     // of the spec under the autocomplete attribute, we no longer support the
@@ -619,6 +650,8 @@
            "  </SELECT>"
            " <LABEL for=\"password\">Password:</LABEL>"
            "  <INPUT type=\"password\" id=\"password\" value=\"secret\"/>"
+           " <LABEL for=\"month\">Card expiration:</LABEL>"
+           "  <INPUT type=\"month\" id=\"month\" value=\"2011-12\"/>"
            "  <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
            // The below inputs should be ignored
            " <LABEL for=\"notvisible\">Hidden:</LABEL>"
@@ -648,7 +681,7 @@
   EXPECT_EQ(GURL("http://cnn.com"), form.action);
 
   const std::vector<FormFieldData>& fields = form.fields;
-  ASSERT_EQ(5U, fields.size());
+  ASSERT_EQ(6U, fields.size());
 
   FormFieldData expected;
   expected.name = ASCIIToUTF16("firstname");
@@ -685,6 +718,13 @@
   expected.form_control_type = "password";
   expected.max_length = WebInputElement::defaultMaxLength();
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[4]);
+
+  expected.name = ASCIIToUTF16("month");
+  expected.value = ASCIIToUTF16("2011-12");
+  expected.label = ASCIIToUTF16("Card expiration:");
+  expected.form_control_type = "month";
+  expected.max_length = 0;
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[5]);
 }
 
 // We should not be able to serialize a form with too many fillable fields.
@@ -1057,6 +1097,10 @@
       {"text", "invisible", "", "", false, "filled invisible", ""},
       // Fields with "display:none" should not be autofilled.
       {"text", "displaynone", "", "", false, "filled displaynone", ""},
+      // Regular <input type="month"> should be autofilled.
+      {"month", "month", "", "", true, "2017-11", "2017-11"},
+      // Non-empty <input type="month"> should not be autofilled.
+      {"month", "month-nonempty", "2011-12", "", false, "2017-11", "2011-12"},
       // Regular select fields should be autofilled.
       {"select-one", "select", "", "", true, "TX", "TX"},
       // Select fields should be autofilled even if they already have a
@@ -1102,6 +1146,10 @@
       // Fields with "display:none" should also be autofilled.
       {"text", "displaynone", "", "", true, "filled displaynone",
        "filled displaynone"},
+      // Regular <input type="month"> should be autofilled.
+      {"month", "month", "", "", true, "2017-11", "2017-11"},
+      // Non-empty <input type="month"> should be overridden.
+      {"month", "month-nonempty", "2011-12", "", true, "2017-11", "2017-11"},
       // Regular select fields should be autofilled.
       {"select-one", "select", "", "", true, "TX", "TX"},
       // Select fields should be autofilled even if they already have a
@@ -2589,6 +2637,9 @@
       "  <INPUT type=\"text\" id=\"lastname\" value=\"Earp\"/>"
       "  <INPUT type=\"text\" autocomplete=\"off\" id=\"noAC\" value=\"one\"/>"
       "  <INPUT type=\"text\" id=\"notenabled\" disabled=\"disabled\">"
+      "  <INPUT type=\"month\" id=\"month\" value=\"2012-11\">"
+      "  <INPUT type=\"month\" id=\"month-disabled\" value=\"2012-11\""
+      "         disabled=\"disabled\">"
       "  <TEXTAREA id=\"textarea\">Apple.</TEXTAREA>"
       "  <TEXTAREA id=\"textarea-disabled\" disabled=\"disabled\">"
       "    Banana!"
@@ -2631,7 +2682,7 @@
   EXPECT_EQ(GURL("http://buh.com"), form2.action);
 
   const std::vector<FormFieldData>& fields2 = form2.fields;
-  ASSERT_EQ(7U, fields2.size());
+  ASSERT_EQ(9U, fields2.size());
 
   FormFieldData expected;
   expected.form_control_type = "text";
@@ -2655,20 +2706,29 @@
   expected.value = ASCIIToUTF16("no clear");
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[3]);
 
-  expected.form_control_type = "textarea";
+  expected.form_control_type = "month";
   expected.max_length = 0;
-  expected.name = ASCIIToUTF16("textarea");
+  expected.name = ASCIIToUTF16("month");
   expected.value = string16();
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[4]);
 
+  expected.name = ASCIIToUTF16("month-disabled");
+  expected.value = ASCIIToUTF16("2012-11");
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[5]);
+
+  expected.form_control_type = "textarea";
+  expected.name = ASCIIToUTF16("textarea");
+  expected.value = string16();
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[6]);
+
   expected.name = ASCIIToUTF16("textarea-disabled");
   expected.value = ASCIIToUTF16("    Banana!  ");
-  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[5]);
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[7]);
 
   expected.name = ASCIIToUTF16("textarea-noAC");
   expected.value = string16();
   expected.autocomplete_attribute = "off";
-  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[6]);
+  EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[8]);
   expected.autocomplete_attribute = std::string();  // reset
 
   // Verify that the cursor position has been updated.
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 912a374..8c366d3 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -819,9 +819,11 @@
     bool is_nacl_unrestricted,
     const Extension* extension,
     WebPluginParams* params) {
-  // Temporarily allow these whitelisted apps to use NaCl.
+  // Temporarily allow these whitelisted apps and WebUIs to use NaCl.
   std::string app_url_host = app_url.host();
   std::string manifest_url_path = manifest_url.path();
+  bool is_whitelisted_web_ui =
+      app_url.spec() == chrome::kChromeUIAppListStartPageURL;
   bool is_whitelisted_app =
       // Whitelisted apps must be served over https.
       app_url.SchemeIs("https") &&
@@ -863,6 +865,7 @@
   // scheme. Also allow invocations if they are from whitelisted URLs or
   // if --enable-nacl is set.
   bool is_nacl_allowed = is_nacl_unrestricted ||
+                         is_whitelisted_web_ui ||
                          is_whitelisted_app ||
                          is_nacl_pdf_viewer ||
                          is_invoked_by_hosted_app ||
diff --git a/chrome/renderer/chrome_mock_render_thread.cc b/chrome/renderer/chrome_mock_render_thread.cc
index 94e2c10..ec8a2ad 100644
--- a/chrome/renderer/chrome_mock_render_thread.cc
+++ b/chrome/renderer/chrome_mock_render_thread.cc
@@ -37,6 +37,16 @@
 ChromeMockRenderThread::~ChromeMockRenderThread() {
 }
 
+scoped_refptr<base::MessageLoopProxy>
+ChromeMockRenderThread::GetIOMessageLoopProxy() {
+  return io_message_loop_proxy_;
+}
+
+void ChromeMockRenderThread::set_io_message_loop_proxy(
+    const scoped_refptr<base::MessageLoopProxy>& proxy) {
+  io_message_loop_proxy_ = proxy;
+}
+
 bool ChromeMockRenderThread::OnMessageReceived(const IPC::Message& msg) {
   if (content::MockRenderThread::OnMessageReceived(msg))
     return true;
diff --git a/chrome/renderer/chrome_mock_render_thread.h b/chrome/renderer/chrome_mock_render_thread.h
index 212d435..f9e88f8 100644
--- a/chrome/renderer/chrome_mock_render_thread.h
+++ b/chrome/renderer/chrome_mock_render_thread.h
@@ -30,9 +30,17 @@
   ChromeMockRenderThread();
   virtual ~ChromeMockRenderThread();
 
+  // content::RenderThread overrides.
+  virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy()
+      OVERRIDE;
+
   //////////////////////////////////////////////////////////////////////////
   // The following functions are called by the test itself.
 
+  // Set IO message loop proxy.
+  void set_io_message_loop_proxy(
+      const scoped_refptr<base::MessageLoopProxy>& proxy);
+
 #if defined(ENABLE_PRINTING)
   // Returns the pseudo-printer instance.
   MockPrinter* printer();
@@ -104,6 +112,8 @@
   int print_preview_pages_remaining_;
 #endif
 
+  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeMockRenderThread);
 };
 
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 2876f42..aedfa4f 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -36,7 +36,6 @@
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/render_view_visitor.h"
 #include "crypto/nss_util.h"
-#include "media/base/media_switches.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_module.h"
 #include "third_party/WebKit/public/web/WebCache.h"
@@ -352,9 +351,6 @@
   WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme);
   WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
       native_scheme);
-
-  if (base::FieldTrialList::FindFullName("DateExtensionEnabled") == "Disabled")
-    WebRuntimeFeatures::enableDateExtension(false);
 }
 
 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index ab3676d..6fcdf2a 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -22,7 +22,6 @@
 #include "chrome/renderer/content_settings_observer.h"
 #include "chrome/renderer/extensions/dispatcher.h"
 #include "chrome/renderer/external_host_bindings.h"
-#include "chrome/renderer/frame_sniffer.h"
 #include "chrome/renderer/prerender/prerender_helper.h"
 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
 #include "chrome/renderer/translate/translate_helper.h"
@@ -312,9 +311,6 @@
                         OnSetVisuallyDeemphasized)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestThumbnailForContextNode,
                         OnRequestThumbnailForContextNode)
-#if defined(OS_CHROMEOS)
-    IPC_MESSAGE_HANDLER(ChromeViewMsg_StartFrameSniffer, OnStartFrameSniffer)
-#endif
     IPC_MESSAGE_HANDLER(ChromeViewMsg_GetFPS, OnGetFPS)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_AddStrictSecurityHost,
                         OnAddStrictSecurityHost)
@@ -515,10 +511,6 @@
       routing_id(), thumbnail, original_size));
 }
 
-void ChromeRenderViewObserver::OnStartFrameSniffer(const string16& frame_name) {
-  new FrameSniffer(render_view(), frame_name);
-}
-
 void ChromeRenderViewObserver::OnGetFPS() {
   float fps = (render_view()->GetFilteredTimePerFrame() > 0.0f)?
       1.0f / render_view()->GetFilteredTimePerFrame() : 0.0f;
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h
index b661eaa..fdb2350 100644
--- a/chrome/renderer/chrome_render_view_observer.h
+++ b/chrome/renderer/chrome_render_view_observer.h
@@ -139,7 +139,6 @@
   void OnSetVisuallyDeemphasized(bool deemphasized);
   void OnRequestThumbnailForContextNode(int thumbnail_min_area_pixels,
                                         gfx::Size thumbnail_max_size_pixels);
-  void OnStartFrameSniffer(const string16& frame_name);
   void OnGetFPS();
   void OnAddStrictSecurityHost(const std::string& host);
   void OnNPAPINotSupported();
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index db3888b..112ee8c 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/extension_set.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index 6a3c090..21e55cd 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -18,6 +18,7 @@
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/extensions/api/extension_api.h"
+#include "chrome/common/extensions/api/messaging/message.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
@@ -25,7 +26,6 @@
 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h"
 #include "chrome/common/extensions/message_bundle.h"
-#include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/renderer/chrome_render_process_observer.h"
@@ -69,6 +69,7 @@
 #include "chrome/renderer/extensions/tab_finder.h"
 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
 #include "chrome/renderer/extensions/user_script_slave.h"
+#include "chrome/renderer/extensions/webrtc_native_handler.h"
 #include "chrome/renderer/extensions/webstore_bindings.h"
 #include "chrome/renderer/resource_bundle_source_map.h"
 #include "content/public/renderer/render_thread.h"
@@ -80,6 +81,7 @@
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/view_type.h"
 #include "grit/common_resources.h"
 #include "grit/renderer_resources.h"
@@ -92,6 +94,7 @@
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/layout.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -160,6 +163,49 @@
   }
 };
 
+class UserGesturesNativeHandler : public ObjectBackedNativeHandler {
+ public:
+  explicit UserGesturesNativeHandler(ChromeV8Context* context)
+      : ObjectBackedNativeHandler(context) {
+    RouteFunction("IsProcessingUserGesture",
+        base::Bind(&UserGesturesNativeHandler::IsProcessingUserGesture,
+                   base::Unretained(this)));
+    RouteFunction("RunWithUserGesture",
+        base::Bind(&UserGesturesNativeHandler::RunWithUserGesture,
+                   base::Unretained(this)));
+    RouteFunction("RunWithoutUserGesture",
+        base::Bind(&UserGesturesNativeHandler::RunWithoutUserGesture,
+                   base::Unretained(this)));
+  }
+
+ private:
+  void IsProcessingUserGesture(
+      const v8::FunctionCallbackInfo<v8::Value>& args) {
+    args.GetReturnValue().Set(v8::Boolean::New(
+        WebKit::WebUserGestureIndicator::isProcessingUserGesture()));
+  }
+
+  void RunWithUserGesture(
+      const v8::FunctionCallbackInfo<v8::Value>& args) {
+    WebKit::WebScopedUserGesture user_gesture;
+    CHECK_EQ(args.Length(), 1);
+    CHECK(args[0]->IsFunction());
+    v8::Handle<v8::Value> no_args;
+    context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
+                            0, &no_args);
+  }
+
+  void RunWithoutUserGesture(
+      const v8::FunctionCallbackInfo<v8::Value>& args) {
+    WebKit::WebUserGestureIndicator::consumeUserGesture();
+    CHECK_EQ(args.Length(), 1);
+    CHECK(args[0]->IsFunction());
+    v8::Handle<v8::Value> no_args;
+    context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
+                            0, &no_args);
+  }
+};
+
 class V8ContextNativeHandler : public ObjectBackedNativeHandler {
  public:
   V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher)
@@ -539,7 +585,7 @@
 }
 
 void Dispatcher::OnDeliverMessage(int target_port_id,
-                                  const std::string& message) {
+                                  const Message& message) {
   MessagingBindings::DeliverMessage(
       v8_context_set_.GetAll(),
       target_port_id,
@@ -610,8 +656,8 @@
 }
 
 void Dispatcher::OnSetScriptingWhitelist(
-    const Extension::ScriptingWhitelist& extension_ids) {
-  Extension::SetScriptingWhitelist(extension_ids);
+    const ExtensionsClient::ScriptingWhitelist& extension_ids) {
+  ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids);
 }
 
 bool Dispatcher::IsExtensionActive(
@@ -892,6 +938,8 @@
       scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context)));
   module_system->RegisterNativeHandler("webstore",
       scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
+  module_system->RegisterNativeHandler("webrtc_natives",
+      scoped_ptr<NativeHandler>(new WebRtcNativeHandler(context)));
 }
 
 void Dispatcher::PopulateSourceMap() {
@@ -965,8 +1013,8 @@
                              IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
   source_map_.RegisterSource("webrtc.castSendTransport",
                              IDR_WEBRTC_CAST_SEND_TRANSPORT_CUSTOM_BINDINGS_JS);
-  source_map_.RegisterSource("webrtc.udpTransport",
-                             IDR_WEBRTC_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
+  source_map_.RegisterSource("webrtc.castUdpTransport",
+                             IDR_WEBRTC_CAST_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
   source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
   source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS);
   source_map_.RegisterSource("binding", IDR_BINDING_JS);
@@ -1076,6 +1124,8 @@
       scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
   module_system->RegisterNativeHandler("test_features",
       scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
+  module_system->RegisterNativeHandler("user_gestures",
+      scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context)));
 
   int manifest_version = extension ? extension->manifest_version() : 1;
   bool send_request_disabled =
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index 7238c4d..a42a604 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -19,6 +19,7 @@
 #include "chrome/renderer/resource_bundle_source_map.h"
 #include "content/public/renderer/render_process_observer.h"
 #include "extensions/common/event_filter.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/features/feature.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
@@ -51,6 +52,7 @@
 class FilteredEventRouter;
 class RequestSender;
 class UserScriptSlave;
+struct Message;
 
 // Dispatches extension control messages sent to the renderer and stores
 // renderer extension related state.
@@ -163,7 +165,7 @@
                            const base::DictionaryValue& source_tab,
                            const ExtensionMsg_ExternalConnectionInfo& info,
                            const std::string& tls_channel_id);
-  void OnDeliverMessage(int target_port_id, const std::string& message);
+  void OnDeliverMessage(int target_port_id, const Message& message);
   void OnDispatchOnDisconnect(int port_id, const std::string& error_message);
   void OnSetFunctionNames(const std::vector<std::string>& names);
   void OnSetSystemFont(const std::string& font_family,
@@ -173,7 +175,7 @@
   void OnLoadedInternal(scoped_refptr<const Extension> extension);
   void OnUnloaded(const std::string& id);
   void OnSetScriptingWhitelist(
-      const Extension::ScriptingWhitelist& extension_ids);
+      const ExtensionsClient::ScriptingWhitelist& extension_ids);
   void OnPageActionsUpdated(const std::string& extension_id,
       const std::vector<std::string>& page_actions);
   void OnActivateExtension(const std::string& extension_id);
diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc
index 4eaf7a8..b2de397 100644
--- a/chrome/renderer/extensions/extension_helper.cc
+++ b/chrome/renderer/extensions/extension_helper.cc
@@ -12,6 +12,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/messaging/message.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
@@ -281,7 +283,7 @@
 }
 
 void ExtensionHelper::OnExtensionDeliverMessage(int target_id,
-                                                const std::string& message) {
+                                                const Message& message) {
   MessagingBindings::DeliverMessage(dispatcher_->v8_context_set().GetAll(),
                                         target_id,
                                         message,
diff --git a/chrome/renderer/extensions/extension_helper.h b/chrome/renderer/extensions/extension_helper.h
index 68ac896..a5f48ab 100644
--- a/chrome/renderer/extensions/extension_helper.h
+++ b/chrome/renderer/extensions/extension_helper.h
@@ -29,6 +29,7 @@
 
 namespace extensions {
 class Dispatcher;
+struct Message;
 
 // RenderView-level plumbing for extension features.
 class ExtensionHelper
@@ -87,7 +88,7 @@
       const ExtensionMsg_ExternalConnectionInfo& info,
       const std::string& tls_channel_id);
   void OnExtensionDeliverMessage(int target_port_id,
-                                 const std::string& message);
+                                 const Message& message);
   void OnExtensionDispatchOnDisconnect(int port_id,
                                        const std::string& error_message);
   void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params);
diff --git a/chrome/renderer/extensions/feedback_private_custom_bindings.cc b/chrome/renderer/extensions/feedback_private_custom_bindings.cc
index 64e8373..ad0c99d 100644
--- a/chrome/renderer/extensions/feedback_private_custom_bindings.cc
+++ b/chrome/renderer/extensions/feedback_private_custom_bindings.cc
@@ -14,11 +14,7 @@
 void GetBlobUuid(const v8::FunctionCallbackInfo<v8::Value> &args) {
   DCHECK(args.Length() == 1);
   WebKit::WebBlob blob = WebKit::WebBlob::fromV8Value(args[0]);
-#ifdef USE_BLOB_UUIDS
   args.GetReturnValue().Set(v8::String::New(blob.uuid().utf8().data()));
-#else
-  args.GetReturnValue().Set(v8::String::New(blob.url().spec().data()));
-#endif
 }
 
 }  // namespace
diff --git a/chrome/renderer/extensions/messaging_bindings.cc b/chrome/renderer/extensions/messaging_bindings.cc
index 94275e7..c06422f 100644
--- a/chrome/renderer/extensions/messaging_bindings.cc
+++ b/chrome/renderer/extensions/messaging_bindings.cc
@@ -13,6 +13,7 @@
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
 #include "base/values.h"
+#include "chrome/common/extensions/api/messaging/message.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
 #include "chrome/common/extensions/message_bundle.h"
@@ -28,6 +29,8 @@
 #include "content/public/renderer/v8_value_converter.h"
 #include "grit/renderer_resources.h"
 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "v8/include/v8.h"
 
 // Message passing API example (in a content script):
@@ -112,7 +115,10 @@
     }
 
     renderview->Send(new ExtensionHostMsg_PostMessage(
-        renderview->GetRoutingID(), port_id, *v8::String::AsciiValue(args[1])));
+        renderview->GetRoutingID(), port_id,
+        extensions::Message(
+            *v8::String::AsciiValue(args[1]),
+            WebKit::WebUserGestureIndicator::isProcessingUserGesture())));
   }
 
   // Forcefully disconnects a port.
@@ -314,8 +320,12 @@
 void MessagingBindings::DeliverMessage(
     const ChromeV8ContextSet::ContextSet& contexts,
     int target_port_id,
-    const std::string& message,
+    const Message& message,
     content::RenderView* restrict_to_render_view) {
+  scoped_ptr<WebKit::WebScopedUserGesture> web_user_gesture;
+  if (message.user_gesture)
+    web_user_gesture.reset(new WebKit::WebScopedUserGesture);
+
   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
 
   // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach.
@@ -343,7 +353,8 @@
       continue;
 
     std::vector<v8::Handle<v8::Value> > arguments;
-    arguments.push_back(v8::String::New(message.c_str(), message.size()));
+    arguments.push_back(v8::String::New(message.data.c_str(),
+                                        message.data.size()));
     arguments.push_back(port_id_handle);
     (*it)->module_system()->CallModuleMethod("messaging",
                                              "dispatchOnMessage",
diff --git a/chrome/renderer/extensions/messaging_bindings.h b/chrome/renderer/extensions/messaging_bindings.h
index 12e2096..c9ebd83 100644
--- a/chrome/renderer/extensions/messaging_bindings.h
+++ b/chrome/renderer/extensions/messaging_bindings.h
@@ -24,6 +24,7 @@
 namespace extensions {
 class ChromeV8Extension;
 class Dispatcher;
+struct Message;
 
 // Manually implements JavaScript bindings for extension messaging.
 //
@@ -56,7 +57,7 @@
   static void DeliverMessage(
       const ChromeV8ContextSet::ContextSet& context_set,
       int target_port_id,
-      const std::string& message,
+      const Message& message,
       content::RenderView* restrict_to_render_view);
 
   // Dispatches the onDisconnect event in response to the channel being closed.
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
index d9a75cb..0f751b2 100644
--- a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
+++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
@@ -8,6 +8,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/renderer/extensions/dispatcher.h"
+#include "extensions/common/extensions_client.h"
 #include "extensions/common/manifest_constants.h"
 
 namespace extensions {
@@ -30,10 +31,10 @@
     const UserScript* script,
     int process_id,
     std::string* error) {
-  const Extension::ScriptingWhitelist* whitelist =
-      Extension::GetScriptingWhitelist();
-  if (std::find(whitelist->begin(), whitelist->end(), extension->id()) !=
-      whitelist->end()) {
+  const ExtensionsClient::ScriptingWhitelist& whitelist =
+      ExtensionsClient::Get()->GetScriptingWhitelist();
+  if (std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
+      whitelist.end()) {
     return true;
   }
 
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
index 4d5d003..80825af 100644
--- a/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
+++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate_unittest.cc
@@ -6,6 +6,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/renderer/extensions/dispatcher.h"
diff --git a/chrome/renderer/extensions/webrtc_native_handler.cc b/chrome/renderer/extensions/webrtc_native_handler.cc
new file mode 100644
index 0000000..8ea32ee
--- /dev/null
+++ b/chrome/renderer/extensions/webrtc_native_handler.cc
@@ -0,0 +1,90 @@
+// Copyright 2013 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/renderer/extensions/webrtc_native_handler.h"
+
+#include "base/logging.h"
+
+namespace extensions {
+
+WebRtcNativeHandler::WebRtcNativeHandler(ChromeV8Context* context)
+    : ObjectBackedNativeHandler(context) {
+  RouteFunction("CreateCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::CreateCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("DestroyCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::DestroyCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("CreateParamsCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::CreateParamsCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("GetCapsCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::GetCapsCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("StartCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::StartCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("StopCastSendTransport",
+      base::Bind(&WebRtcNativeHandler::StopCastSendTransport,
+                 base::Unretained(this)));
+  RouteFunction("CreateCastUdpTransport",
+      base::Bind(&WebRtcNativeHandler::CreateCastUdpTransport,
+                 base::Unretained(this)));
+  RouteFunction("StartCastUdpTransport",
+      base::Bind(&WebRtcNativeHandler::StartCastUdpTransport,
+                 base::Unretained(this)));
+  RouteFunction("StopCastUdpTransport",
+      base::Bind(&WebRtcNativeHandler::StopCastUdpTransport,
+                 base::Unretained(this)));
+}
+
+WebRtcNativeHandler::~WebRtcNativeHandler() {
+}
+
+void WebRtcNativeHandler::CreateCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::DestroyCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::CreateParamsCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::GetCapsCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::StartCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::StopCastSendTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::CreateCastUdpTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::StartCastUdpTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+void WebRtcNativeHandler::StopCastUdpTransport(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace extensions
diff --git a/chrome/renderer/extensions/webrtc_native_handler.h b/chrome/renderer/extensions/webrtc_native_handler.h
new file mode 100644
index 0000000..fb3ecdc
--- /dev/null
+++ b/chrome/renderer/extensions/webrtc_native_handler.h
@@ -0,0 +1,49 @@
+// Copyright 2013 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_RENDERER_EXTENSIONS_WEBRTC_NATIVE_HANDLER_H_
+#define CHROME_RENDERER_EXTENSIONS_WEBRTC_NATIVE_HANDLER_H_
+
+#include "chrome/renderer/extensions/object_backed_native_handler.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+
+class ChromeV8Context;
+
+// Native code that handle chrome.webrtc custom bindings.
+class WebRtcNativeHandler : public ObjectBackedNativeHandler {
+ public:
+  explicit WebRtcNativeHandler(ChromeV8Context* context);
+  virtual ~WebRtcNativeHandler();
+
+ private:
+  void CreateCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void DestroyCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void CreateParamsCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void GetCapsCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void StartCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void StopCastSendTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+
+  void CreateCastUdpTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void DestroyCastUdpTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void StartCastUdpTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+  void StopCastUdpTransport(
+      const v8::FunctionCallbackInfo<v8::Value>& args);
+
+  DISALLOW_COPY_AND_ASSIGN(WebRtcNativeHandler);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_RENDERER_EXTENSIONS_WEBRTC_NATIVE_HANDLER_H_
diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc
index 9d11cb0..ad50c42 100644
--- a/chrome/renderer/extensions/webstore_bindings.cc
+++ b/chrome/renderer/extensions/webstore_bindings.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string_util.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
 #include "content/public/renderer/render_view.h"
diff --git a/chrome/renderer/frame_sniffer.cc b/chrome/renderer/frame_sniffer.cc
deleted file mode 100644
index 21dad2f..0000000
--- a/chrome/renderer/frame_sniffer.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2011 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/renderer/frame_sniffer.h"
-
-#include "base/logging.h"
-#include "chrome/common/render_messages.h"
-#include "third_party/WebKit/public/platform/WebURLError.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-
-FrameSniffer::FrameSniffer(content::RenderView* render_view,
-                           const string16 &unique_frame_name)
-    : content::RenderViewObserver(render_view),
-      unique_frame_name_(unique_frame_name) {
-}
-
-FrameSniffer::~FrameSniffer() {
-}
-
-void FrameSniffer::DidFailProvisionalLoad(WebKit::WebFrame* frame,
-                                          const WebKit::WebURLError& error) {
-  if (!ShouldSniffFrame(frame))
-    return;
-  Send(new ChromeViewHostMsg_FrameLoadingError(routing_id(), -error.reason));
-}
-
-void FrameSniffer::DidCommitProvisionalLoad(WebKit::WebFrame* frame,
-                                            bool is_new_navigation) {
-  if (!ShouldSniffFrame(frame))
-    return;
-  Send(new ChromeViewHostMsg_FrameLoadingCompleted(routing_id()));
-}
-
-bool FrameSniffer::ShouldSniffFrame(WebKit::WebFrame* frame) {
-  return frame->uniqueName() == unique_frame_name_;
-}
diff --git a/chrome/renderer/frame_sniffer.h b/chrome/renderer/frame_sniffer.h
deleted file mode 100644
index c5c2316..0000000
--- a/chrome/renderer/frame_sniffer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2011 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_RENDERER_FRAME_SNIFFER_H_
-#define CHROME_RENDERER_FRAME_SNIFFER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/renderer/render_view_observer.h"
-
-// Class which observes events from the frame with specific name and sends IPC
-// messages to be handled by RenderViewHostObserver.
-class FrameSniffer : public content::RenderViewObserver {
- public:
-  FrameSniffer(content::RenderView* render_view,
-               const string16 &unique_frame_name);
-  virtual ~FrameSniffer();
-
-  // Implements RenderViewObserver.
-  virtual void DidFailProvisionalLoad(
-      WebKit::WebFrame* frame, const WebKit::WebURLError& error) OVERRIDE;
-  virtual void DidCommitProvisionalLoad(WebKit::WebFrame* frame,
-                                        bool is_new_navigation) OVERRIDE;
-
- private:
-  bool ShouldSniffFrame(WebKit::WebFrame* frame);
-
-  // Name of the frame to be monitored.
-  string16 unique_frame_name_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameSniffer);
-};
-
-#endif  // CHROME_RENDERER_FRAME_SNIFFER_H_
diff --git a/chrome/renderer/media/DEPS b/chrome/renderer/media/DEPS
new file mode 100644
index 0000000..e3c962b
--- /dev/null
+++ b/chrome/renderer/media/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+media/cast",  # For cast mirroring library.
+]
diff --git a/chrome/renderer/media/cast_send_transport.cc b/chrome/renderer/media/cast_send_transport.cc
index f2889df..119a051 100644
--- a/chrome/renderer/media/cast_send_transport.cc
+++ b/chrome/renderer/media/cast_send_transport.cc
@@ -5,6 +5,8 @@
 #include "chrome/renderer/media/cast_send_transport.h"
 
 #include "base/logging.h"
+#include "chrome/renderer/media/cast_session.h"
+#include "chrome/renderer/media/cast_udp_transport.h"
 
 CastCodecSpecificParam::CastCodecSpecificParam() {
 }
@@ -32,8 +34,8 @@
 }
 
 CastSendTransport::CastSendTransport(
-    CastUdpTransport* udp_transport) {
-  NOTIMPLEMENTED();
+    CastUdpTransport* udp_transport)
+    : cast_session_(udp_transport->cast_session()) {
 }
 
 CastSendTransport::~CastSendTransport() {
diff --git a/chrome/renderer/media/cast_send_transport.h b/chrome/renderer/media/cast_send_transport.h
index 235d7ab..b5c670a 100644
--- a/chrome/renderer/media/cast_send_transport.h
+++ b/chrome/renderer/media/cast_send_transport.h
@@ -9,11 +9,13 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 
 namespace WebKit {
 class WebMediaStreamTrack;
 }  // namespace WebKit
 
+class CastSession;
 class CastUdpTransport;
 
 // A key value pair structure for codec specific parameters.
@@ -103,6 +105,8 @@
   void Stop();
 
  private:
+  const scoped_refptr<CastSession> cast_session_;
+
   DISALLOW_COPY_AND_ASSIGN(CastSendTransport);
 };
 
diff --git a/chrome/renderer/media/cast_session.cc b/chrome/renderer/media/cast_session.cc
index 530f6a0..28ba851 100644
--- a/chrome/renderer/media/cast_session.cc
+++ b/chrome/renderer/media/cast_session.cc
@@ -4,8 +4,17 @@
 
 #include "chrome/renderer/media/cast_session.h"
 
-CastSession::CastSession() {
+#include "base/message_loop/message_loop_proxy.h"
+#include "chrome/renderer/media/cast_session_delegate.h"
+#include "content/public/renderer/render_thread.h"
+
+CastSession::CastSession()
+    : delegate_(new CastSessionDelegate()),
+      io_message_loop_proxy_(
+          content::RenderThread::Get()->GetIOMessageLoopProxy()) {
 }
 
 CastSession::~CastSession() {
+  // We should always be able to delete the object on the IO thread.
+  CHECK(io_message_loop_proxy_->DeleteSoon(FROM_HERE, delegate_.release()));
 }
diff --git a/chrome/renderer/media/cast_session.h b/chrome/renderer/media/cast_session.h
index 5e39c83..dcf7945 100644
--- a/chrome/renderer/media/cast_session.h
+++ b/chrome/renderer/media/cast_session.h
@@ -6,21 +6,35 @@
 #define CHROME_RENDERER_MEDIA_CAST_SESSION_H_
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 
-// This class represents a Cast session which consists of the
-// following three major components:
-// 1. Video and audio input.
-// 2. Cast RTP transport.
-// 3. Network connection.
-//
-// This class connects the above three components to provide a Cast
-// service.
-class CastSession {
+namespace base {
+class MessageLoopProxy;
+}  // namespace base
+
+class CastSessionDelegate;
+
+// This class represents a Cast session and allows the session to be
+// configured on the main thread. Actual work is forwarded to
+// CastSessionDelegate on the IO thread.
+class CastSession : public base::RefCounted<CastSession> {
  public:
   CastSession();
-  ~CastSession();
 
  private:
+  friend class base::RefCounted<CastSession>;
+  virtual ~CastSession();
+
+  // This member should never be dereferenced on the main thread.
+  // CastSessionDelegate lives only on the IO thread. It is always
+  // safe to post task on the IO thread to access CastSessionDelegate
+  // because it is owned by this object.
+  scoped_ptr<CastSessionDelegate> delegate_;
+
+  // Proxy to the IO message loop.
+  const scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+
   DISALLOW_COPY_AND_ASSIGN(CastSession);
 };
 
diff --git a/chrome/renderer/media/cast_session_browsertest.cc b/chrome/renderer/media/cast_session_browsertest.cc
new file mode 100644
index 0000000..3fe21e8
--- /dev/null
+++ b/chrome/renderer/media/cast_session_browsertest.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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/renderer/media/cast_session.h"
+
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
+#include "chrome/test/base/chrome_render_view_test.h"
+
+namespace chrome {
+
+typedef ChromeRenderViewTest CastSessionBrowserTest;
+
+// Tests that CastSession is created and destroyed properly inside
+// chrome renderer.
+TEST_F(CastSessionBrowserTest, CreateAndDestroy) {
+  chrome_content_renderer_client_.RenderThreadStarted();
+  chrome_render_thread_->set_io_message_loop_proxy(
+      base::MessageLoopProxy::current());
+
+  scoped_refptr<CastSession> session(new CastSession());
+
+  // Causes CastSession to destruct.
+  session = NULL;
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace chrome
diff --git a/chrome/renderer/media/cast_session_delegate.cc b/chrome/renderer/media/cast_session_delegate.cc
new file mode 100644
index 0000000..8f0fc07
--- /dev/null
+++ b/chrome/renderer/media/cast_session_delegate.cc
@@ -0,0 +1,60 @@
+// Copyright 2013 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/renderer/media/cast_session_delegate.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/public/renderer/render_thread.h"
+#include "media/cast/cast_config.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/cast_sender.h"
+
+using media::cast::AudioSenderConfig;
+using media::cast::CastEnvironment;
+using media::cast::CastSender;
+using media::cast::VideoSenderConfig;
+
+CastSessionDelegate::CastSessionDelegate()
+    : audio_encode_thread_("CastAudioEncodeThread"),
+      video_encode_thread_("CastVideoEncodeThread"),
+      io_message_loop_proxy_(
+          content::RenderThread::Get()->GetIOMessageLoopProxy()) {
+}
+
+CastSessionDelegate::~CastSessionDelegate() {
+  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
+}
+
+void CastSessionDelegate::PrepareForSending() {
+  DCHECK(base::MessageLoopProxy::current() == io_message_loop_proxy_);
+
+  if (cast_environment_)
+    return;
+
+  audio_encode_thread_.Start();
+  video_encode_thread_.Start();
+
+  // CastSender uses the renderer's IO thread as the main thread. This reduces
+  // thread hopping for incoming video frames and outgoing network packets.
+  // There's no need to decode so no thread assigned for decoding.
+  cast_environment_ = new CastEnvironment(
+      &clock_,
+      base::MessageLoopProxy::current(),
+      audio_encode_thread_.message_loop_proxy(),
+      NULL,
+      video_encode_thread_.message_loop_proxy(),
+      NULL);
+
+  // TODO(hclam): A couple things need to be done here:
+  // 1. Pass audio and video configuration to CastSender.
+  // 2. Connect media::cast::PacketSender to net::Socket interface.
+  // 3. Implement VideoEncoderController to configure hardware encoder.
+  cast_sender_.reset(CastSender::CreateCastSender(
+      cast_environment_,
+      AudioSenderConfig(),
+      VideoSenderConfig(),
+      NULL,
+      NULL));
+}
diff --git a/chrome/renderer/media/cast_session_delegate.h b/chrome/renderer/media/cast_session_delegate.h
new file mode 100644
index 0000000..9c51b7f
--- /dev/null
+++ b/chrome/renderer/media/cast_session_delegate.h
@@ -0,0 +1,57 @@
+// Copyright 2013 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_RENDERER_MEDIA_CAST_SESSION_DELEGATE_H_
+#define CHROME_RENDERER_MEDIA_CAST_SESSION_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/default_tick_clock.h"
+
+namespace base {
+class MessageLoopProxy;
+}  // namespace base
+
+namespace media {
+namespace cast {
+class CastEnvironment;
+class CastSender;
+}  // namespace cast
+}  // namespace media
+
+// This class hosts CastSender and connects it to audio/video frame input
+// and network socket.
+// This class is created on the render thread and destroyed on the IO
+// thread. All methods are accessible only on the IO thread.
+class CastSessionDelegate {
+ public:
+  CastSessionDelegate();
+  ~CastSessionDelegate();
+
+  // Start encoding threads and configure CastSender. It is ready to accept
+  // audio/video frames after this call.
+  void PrepareForSending();
+
+ private:
+  base::ThreadChecker thread_checker_;
+  scoped_refptr<media::cast::CastEnvironment> cast_environment_;
+  scoped_ptr<media::cast::CastSender> cast_sender_;
+
+  // Utilities threads owned by this class. They are used by CastSender for
+  // encoding.
+  base::Thread audio_encode_thread_;
+  base::Thread video_encode_thread_;
+
+  // Clock used by CastSender.
+  base::DefaultTickClock clock_;
+
+  // Proxy to the IO message loop.
+  const scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastSessionDelegate);
+};
+
+#endif  // CHROME_RENDERER_MEDIA_CAST_SESSION_DELEGATE_H_
diff --git a/chrome/renderer/media/cast_udp_transport.cc b/chrome/renderer/media/cast_udp_transport.cc
index 3c864c9..03b65bc 100644
--- a/chrome/renderer/media/cast_udp_transport.cc
+++ b/chrome/renderer/media/cast_udp_transport.cc
@@ -5,8 +5,10 @@
 #include "chrome/renderer/media/cast_udp_transport.h"
 
 #include "base/logging.h"
+#include "chrome/renderer/media/cast_session.h"
 
-CastUdpTransport::CastUdpTransport() {
+CastUdpTransport::CastUdpTransport()
+    : cast_session_(new CastSession()) {
 }
 
 CastUdpTransport::~CastUdpTransport() {
diff --git a/chrome/renderer/media/cast_udp_transport.h b/chrome/renderer/media/cast_udp_transport.h
index e2e5c28..5860888 100644
--- a/chrome/renderer/media/cast_udp_transport.h
+++ b/chrome/renderer/media/cast_udp_transport.h
@@ -6,11 +6,18 @@
 #define CHROME_RENDERER_MEDIA_CAST_UDP_TRANSPORT_H_
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 #include "net/base/ip_endpoint.h"
 
+class CastSession;
+
 // This class represents an end point to which communication is done by
 // UDP. The interface does not allow direct access to a UDP socket but
 // represents a transport mechanism.
+//
+// CastUdpTransport creates a CastSession and then shares it with
+// multiple CastSendTransports. This is because CastSession corresponds
+// to only one remote peer.
 class CastUdpTransport {
  public:
   CastUdpTransport();
@@ -23,7 +30,13 @@
   // Terminate the communication with the end point.
   void Stop();
 
+  scoped_refptr<CastSession> cast_session() const {
+    return cast_session_;
+  }
+
  private:
+  const scoped_refptr<CastSession> cast_session_;
+
   DISALLOW_COPY_AND_ASSIGN(CastUdpTransport);
 };
 
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 4e15775..0372a80 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -6,11 +6,12 @@
 
 #include <string>
 
-#include "base/command_line.h"
 #include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/common/render_messages.h"
 #include "content/public/renderer/render_thread.h"
-#include "media/base/media_switches.h"
 
 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
 
@@ -43,11 +44,17 @@
 #endif  // defined(USE_PROPRIETARY_CODECS)
 
 #if defined(ENABLE_PEPPER_CDMS)
-static bool IsPepperCdmRegistered(const std::string& pepper_type) {
+static bool IsPepperCdmRegistered(
+    const std::string& pepper_type,
+    std::vector<base::string16>* additional_param_names,
+    std::vector<base::string16>* additional_param_values) {
   bool is_registered = false;
   content::RenderThread::Get()->Send(
       new ChromeViewHostMsg_IsInternalPluginRegisteredForMimeType(
-          pepper_type, &is_registered));
+          pepper_type,
+          &is_registered,
+          additional_param_names,
+          additional_param_values));
 
   return is_registered;
 }
@@ -60,8 +67,13 @@
   static const char kExternalClearKeyPepperType[] =
       "application/x-ppapi-clearkey-cdm";
 
-  if (!IsPepperCdmRegistered(kExternalClearKeyPepperType))
+  std::vector<base::string16> additional_param_names;
+  std::vector<base::string16> additional_param_values;
+  if (!IsPepperCdmRegistered(kExternalClearKeyPepperType,
+                             &additional_param_names,
+                             &additional_param_values)) {
     return;
+  }
 
   KeySystemInfo info(kExternalClearKeyKeySystem);
 
@@ -95,7 +107,10 @@
 
 // Defines bitmask values used to specify supported codecs.
 // Each value represents a codec within a specific container.
-enum SupportedCodecs {
+// The mask values are stored in a SupportedCodecs.
+typedef uint32 SupportedCodecs;
+enum SupportedCodecMasks {
+  NO_CODECS = 0,
   WEBM_VP8_AND_VORBIS = 1 << 0,
 #if defined(USE_PROPRIETARY_CODECS)
   MP4_AAC = 1 << 1,
@@ -181,7 +196,37 @@
 }
 
 #if defined(ENABLE_PEPPER_CDMS)
-// Supported types are determined at compile time.
+// When the adapter is registered, a name-value pair is inserted in
+// additional_param_* that lists the supported codecs. The name is "codecs" and
+// the value is a comma-delimited list of codecs.
+// This function finds "codecs" and parses the value into the vector |codecs|.
+// Converts the codec strings to UTF-8 since we only expect ASCII strings and
+// this simplifies the rest of the code in this file.
+void GetSupportedCodecs(
+    const std::vector<base::string16>& additional_param_names,
+    const std::vector<base::string16>& additional_param_values,
+    std::vector<std::string>* codecs) {
+  DCHECK(codecs->empty());
+  DCHECK_EQ(additional_param_names.size(), additional_param_values.size());
+  for (size_t i = 0; i < additional_param_names.size(); ++i) {
+    if (additional_param_names[i] ==
+        base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) {
+      const base::string16& codecs_string16 = additional_param_values[i];
+      std::string codecs_string;
+      if (!base::UTF16ToUTF8(codecs_string16.c_str(),
+                             codecs_string16.length(),
+                             &codecs_string)) {
+        DLOG(WARNING) << "Non-UTF-8 codecs string.";
+        // Continue using the best effort conversion.
+      }
+      base::SplitString(codecs_string,
+                        kCdmSupportedCodecsValueDelimiter,
+                        codecs);
+      break;
+    }
+  }
+}
+
 static void AddPepperBasedWidevine(
     std::vector<KeySystemInfo>* concrete_key_systems) {
 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
@@ -191,21 +236,30 @@
     return;
 #endif  // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
 
-  if (!IsPepperCdmRegistered(kWidevineCdmPluginMimeType)) {
+  std::vector<base::string16> additional_param_names;
+  std::vector<base::string16> additional_param_values;
+  if (!IsPepperCdmRegistered(kWidevineCdmPluginMimeType,
+                             &additional_param_names,
+                             &additional_param_values)) {
     DVLOG(1) << "Widevine CDM is not currently available.";
     return;
   }
 
-  SupportedCodecs supported_codecs = WEBM_VP8_AND_VORBIS;
+  std::vector<std::string> codecs;
+  GetSupportedCodecs(additional_param_names, additional_param_values, &codecs);
 
+  SupportedCodecs supported_codecs = NO_CODECS;
+  for (size_t i = 0; i < codecs.size(); ++i) {
+    // TODO(ddorwin): Break up VP8 and Vorbis. For now, "vp8" implies both.
+    if (codecs[i] == kCdmSupportedCodecVp8)
+      supported_codecs |= WEBM_VP8_AND_VORBIS;
 #if defined(USE_PROPRIETARY_CODECS)
-#if defined(WIDEVINE_CDM_AAC_SUPPORT_AVAILABLE)
-  supported_codecs = static_cast<SupportedCodecs>(supported_codecs | MP4_AAC);
-#endif
-#if defined(WIDEVINE_CDM_AVC1_SUPPORT_AVAILABLE)
-  supported_codecs = static_cast<SupportedCodecs>(supported_codecs | MP4_AVC1);
-#endif
+    if (codecs[i] == kCdmSupportedCodecAac)
+      supported_codecs |= MP4_AAC;
+    if (codecs[i] == kCdmSupportedCodecAvc1)
+      supported_codecs |= MP4_AVC1;
 #endif  // defined(USE_PROPRIETARY_CODECS)
+  }
 
   AddWidevineWithCodecs(WIDEVINE, supported_codecs, concrete_key_systems);
 
@@ -254,8 +308,7 @@
 #if defined(ENABLE_PEPPER_CDMS)
   AddPepperBasedWidevine(key_systems_info);
 #elif defined(OS_ANDROID)
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableMediaDrm))
-    AddAndroidWidevine(key_systems_info);
+  AddAndroidWidevine(key_systems_info);
 #endif
 #endif
 }
diff --git a/chrome/renderer/mock_printer.cc b/chrome/renderer/mock_printer.cc
index fdcbd0e..d7a5c3f 100644
--- a/chrome/renderer/mock_printer.cc
+++ b/chrome/renderer/mock_printer.cc
@@ -72,7 +72,6 @@
     preview_request_id_(0),
     print_scaling_option_(WebKit::WebPrintScalingOptionSourceSize),
     display_header_footer_(false),
-    date_(ASCIIToUTF16("date")),
     title_(ASCIIToUTF16("title")),
     url_(ASCIIToUTF16("url")),
     use_invalid_settings_(false) {
@@ -119,7 +118,6 @@
   margin_left_ = params.margin_left;
   margin_top_ = params.margin_top;
   display_header_footer_ = params.display_header_footer;
-  date_ = params.date;
   title_ = params.title;
   url_ = params.url;
 }
@@ -162,7 +160,6 @@
   settings->params.print_to_pdf = print_to_pdf_;
   settings->params.preview_request_id = preview_request_id_;
   settings->params.display_header_footer = display_header_footer_;
-  settings->params.date = date_;
   settings->params.title = title_;
   settings->params.url = url_;
   printer_status_ = PRINTER_PRINTING;
@@ -312,7 +309,6 @@
   params->print_to_pdf = print_to_pdf_;
   params->preview_request_id = preview_request_id_;
   params->display_header_footer = display_header_footer_;
-  params->date = date_;
   params->title = title_;
   params->url = url_;
 }
diff --git a/chrome/renderer/mock_printer.h b/chrome/renderer/mock_printer.h
index 838717f..9386edf 100644
--- a/chrome/renderer/mock_printer.h
+++ b/chrome/renderer/mock_printer.h
@@ -152,7 +152,6 @@
 
   // Used for displaying headers and footers.
   bool display_header_footer_;
-  string16 date_;
   string16 title_;
   string16 url_;
 
diff --git a/chrome/renderer/pepper/DEPS b/chrome/renderer/pepper/DEPS
index ea5f65b..40e81e2 100644
--- a/chrome/renderer/pepper/DEPS
+++ b/chrome/renderer/pepper/DEPS
@@ -1,6 +1,8 @@
 include_rules = [
   "+components/nacl/common",
   "+ppapi/host",
+  "+ppapi/native_client/src/trusted/plugin/nacl_entry_points.h",  # For NaCl registration.
+  "+ppapi/proxy",
   
   # TODO(raymes): Once all of the resources are refactored to the new pepper
   # resource model, these includes shouldn't be needed.
diff --git a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc
index b7ca8b5..6873b7a 100644
--- a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc
+++ b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc
@@ -21,8 +21,6 @@
 
 using ppapi::host::ResourceHost;
 
-namespace chrome {
-
 ChromeRendererPepperHostFactory::ChromeRendererPepperHostFactory(
     content::RendererPpapiHost* host)
     : host_(host) {
@@ -113,5 +111,3 @@
 
   return scoped_ptr<ResourceHost>();
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
index 0dfba86..03adf48 100644
--- a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
+++ b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
@@ -13,8 +13,6 @@
 class RendererPpapiHost;
 }
 
-namespace chrome {
-
 class ChromeRendererPepperHostFactory : public ppapi::host::HostFactory {
  public:
   explicit ChromeRendererPepperHostFactory(content::RendererPpapiHost* host);
@@ -34,6 +32,4 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeRendererPepperHostFactory);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_
diff --git a/chrome/renderer/pepper/pepper_extensions_common_host.cc b/chrome/renderer/pepper/pepper_extensions_common_host.cc
index b768a20..5b76cab 100644
--- a/chrome/renderer/pepper/pepper_extensions_common_host.cc
+++ b/chrome/renderer/pepper/pepper_extensions_common_host.cc
@@ -22,8 +22,6 @@
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebPluginContainer.h"
 
-namespace chrome {
-
 PepperExtensionsCommonHost::PepperExtensionsCommonHost(
     content::RendererPpapiHost* host,
     PP_Instance instance,
@@ -130,5 +128,3 @@
                                               true, false, &args);
   return PP_OK_COMPLETIONPENDING;
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_extensions_common_host.h b/chrome/renderer/pepper/pepper_extensions_common_host.h
index 054709d..2dfb376 100644
--- a/chrome/renderer/pepper/pepper_extensions_common_host.h
+++ b/chrome/renderer/pepper/pepper_extensions_common_host.h
@@ -32,8 +32,6 @@
 class Dispatcher;
 }
 
-namespace chrome {
-
 class PepperExtensionsCommonHost : public ppapi::host::ResourceHost,
                                    public extensions::RequestSender::Source {
  public:
@@ -82,6 +80,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperExtensionsCommonHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_EXTENSIONS_COMMON_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_flash_drm_renderer_host.cc b/chrome/renderer/pepper/pepper_flash_drm_renderer_host.cc
index 4d9a24c..9f4006c 100644
--- a/chrome/renderer/pepper/pepper_flash_drm_renderer_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_drm_renderer_host.cc
@@ -13,8 +13,6 @@
 #include "ppapi/host/ppapi_host.h"
 #include "ppapi/proxy/ppapi_messages.h"
 
-namespace chrome {
-
 // TODO(raymes): This is duplicated from pepper_flash_drm_host.cc but once
 // FileRef is refactored to the browser, it won't need to be.
 namespace {
@@ -94,6 +92,3 @@
   host()->SendReply(reply_context,
                     PpapiPluginMsg_FlashDRM_GetVoucherFileReply(create_info));
 }
-
-}  // namespace chrome
-
diff --git a/chrome/renderer/pepper/pepper_flash_drm_renderer_host.h b/chrome/renderer/pepper/pepper_flash_drm_renderer_host.h
index 73f67dc..bdb17c1 100644
--- a/chrome/renderer/pepper/pepper_flash_drm_renderer_host.h
+++ b/chrome/renderer/pepper/pepper_flash_drm_renderer_host.h
@@ -18,8 +18,6 @@
 class RendererPpapiHost;
 }
 
-namespace chrome {
-
 // TODO(raymes): This is only needed until we move FileRef resources to the
 // browser. After that, get rid of this class altogether.
 class PepperFlashDRMRendererHost : public ppapi::host::ResourceHost {
@@ -50,6 +48,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperFlashDRMRendererHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_FLASH_DRM_RENDERER_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_flash_font_file_host.cc b/chrome/renderer/pepper/pepper_flash_font_file_host.cc
index 524c227..01b434d 100644
--- a/chrome/renderer/pepper/pepper_flash_font_file_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_font_file_host.cc
@@ -17,8 +17,6 @@
 #include "content/public/common/child_process_sandbox_support_linux.h"
 #endif
 
-namespace chrome {
-
 PepperFlashFontFileHost::PepperFlashFontFileHost(
     content::RendererPpapiHost* host,
     PP_Instance instance,
@@ -74,6 +72,3 @@
   context->reply_msg = PpapiPluginMsg_FlashFontFile_GetFontTableReply(contents);
   return result;
 }
-
-}  // namespace chrome
-
diff --git a/chrome/renderer/pepper/pepper_flash_font_file_host.h b/chrome/renderer/pepper/pepper_flash_font_file_host.h
index ad60c6f..272ed6c 100644
--- a/chrome/renderer/pepper/pepper_flash_font_file_host.h
+++ b/chrome/renderer/pepper/pepper_flash_font_file_host.h
@@ -20,8 +20,6 @@
 }
 }
 
-namespace chrome {
-
 class PepperFlashFontFileHost : public ppapi::host::ResourceHost {
  public:
   PepperFlashFontFileHost(
@@ -48,6 +46,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperFlashFontFileHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc b/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
index 4ebcbd9..35e25ca 100644
--- a/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
@@ -12,8 +12,6 @@
 #include "ppapi/host/ppapi_host.h"
 #include "ppapi/proxy/ppapi_messages.h"
 
-namespace chrome {
-
 PepperFlashFullscreenHost::PepperFlashFullscreenHost(
     content::RendererPpapiHost* host,
     PP_Instance instance,
@@ -45,6 +43,3 @@
     return PP_OK;
   return PP_ERROR_FAILED;
 }
-
-}  // namespace chrome
-
diff --git a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
index a98432e..8d3f0d4 100644
--- a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
+++ b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
@@ -13,8 +13,6 @@
 class RendererPpapiHost;
 }
 
-namespace chrome {
-
 class PepperFlashFullscreenHost : public ppapi::host::ResourceHost {
  public:
   PepperFlashFullscreenHost(content::RendererPpapiHost* host,
@@ -36,6 +34,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperFlashFullscreenHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_flash_menu_host.cc b/chrome/renderer/pepper/pepper_flash_menu_host.cc
index a948ce5..5f258a8 100644
--- a/chrome/renderer/pepper/pepper_flash_menu_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_menu_host.cc
@@ -16,8 +16,6 @@
 #include "ppapi/proxy/serialized_flash_menu.h"
 #include "ui/gfx/point.h"
 
-namespace chrome {
-
 namespace {
 
 // Maximum depth of submenus allowed (e.g., 1 indicates that submenus are
@@ -203,5 +201,3 @@
                     PpapiPluginMsg_FlashMenu_ShowReply(action));
 
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_flash_menu_host.h b/chrome/renderer/pepper/pepper_flash_menu_host.h
index 51cc42c..9376146 100644
--- a/chrome/renderer/pepper/pepper_flash_menu_host.h
+++ b/chrome/renderer/pepper/pepper_flash_menu_host.h
@@ -24,8 +24,6 @@
 }
 }
 
-namespace chrome {
-
 class PepperFlashMenuHost : public ppapi::host::ResourceHost,
                             public content::ContextMenuClient {
  public:
@@ -68,6 +66,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperFlashMenuHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chrome/renderer/pepper/pepper_flash_renderer_host.cc
index 91652b1..e978b6a 100644
--- a/chrome/renderer/pepper/pepper_flash_renderer_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_renderer_host.cc
@@ -33,8 +33,6 @@
 using ppapi::thunk::EnterResourceNoLock;
 using ppapi::thunk::PPB_ImageData_API;
 
-namespace chrome {
-
 PepperFlashRendererHost::PepperFlashRendererHost(
     content::RendererPpapiHost* host,
     PP_Instance instance,
@@ -255,5 +253,3 @@
   PPB_PDF_Impl::InvokePrintingForInstance(pp_instance());
   return PP_OK;
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_flash_renderer_host.h b/chrome/renderer/pepper/pepper_flash_renderer_host.h
index 7908880..0e30dec 100644
--- a/chrome/renderer/pepper/pepper_flash_renderer_host.h
+++ b/chrome/renderer/pepper/pepper_flash_renderer_host.h
@@ -29,8 +29,6 @@
 class RendererPpapiHost;
 }
 
-namespace chrome {
-
 class PepperFlashRendererHost : public ppapi::host::ResourceHost {
  public:
   PepperFlashRendererHost(content::RendererPpapiHost* host,
@@ -69,6 +67,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperFlashRendererHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_helper.cc b/chrome/renderer/pepper/pepper_helper.cc
index c36bac0..8874004 100644
--- a/chrome/renderer/pepper/pepper_helper.cc
+++ b/chrome/renderer/pepper/pepper_helper.cc
@@ -9,8 +9,6 @@
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "ppapi/host/ppapi_host.h"
 
-namespace chrome {
-
 PepperHelper::PepperHelper(content::RenderView* render_view)
     : RenderViewObserver(render_view) {
 }
@@ -28,5 +26,3 @@
       scoped_ptr<ppapi::host::InstanceMessageFilter>(
           new PepperSharedMemoryMessageFilter(host)));
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_helper.h b/chrome/renderer/pepper/pepper_helper.h
index 5f810b8..ae40c2e 100644
--- a/chrome/renderer/pepper/pepper_helper.h
+++ b/chrome/renderer/pepper/pepper_helper.h
@@ -8,8 +8,6 @@
 #include "base/compiler_specific.h"
 #include "content/public/renderer/render_view_observer.h"
 
-namespace chrome {
-
 // This class listens for Pepper creation events from the RenderView and
 // attaches the parts required for Chrome-specific plugin support.
 class PepperHelper : public content::RenderViewObserver {
@@ -24,6 +22,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperHelper);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_
diff --git a/chrome/renderer/pepper/pepper_pdf_host.cc b/chrome/renderer/pepper/pepper_pdf_host.cc
index e187c52..3edffe0 100644
--- a/chrome/renderer/pepper/pepper_pdf_host.cc
+++ b/chrome/renderer/pepper/pepper_pdf_host.cc
@@ -38,8 +38,6 @@
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/gfx/point.h"
 
-namespace chrome {
-
 namespace {
 
 struct ResourceImageInfo {
@@ -139,15 +137,15 @@
     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStartLoading,
                                         OnHostMsgDidStartLoading)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStopLoading,
-                                      OnHostMsgDidStopLoading)
+                                        OnHostMsgDidStopLoading)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_UserMetricsRecordAction,
                                       OnHostMsgUserMetricsRecordAction)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_HasUnsupportedFeature,
                                         OnHostMsgHasUnsupportedFeature)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_Print,
-                                      OnHostMsgPrint)
+                                        OnHostMsgPrint)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs,
-                                      OnHostMsgSaveAs)
+                                        OnHostMsgSaveAs)
     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetResourceImage,
                                       OnHostMsgGetResourceImage)
   IPC_END_MESSAGE_MAP()
@@ -396,5 +394,3 @@
 
   return true;
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_pdf_host.h b/chrome/renderer/pepper/pepper_pdf_host.h
index cf8adeb..b066fb8 100644
--- a/chrome/renderer/pepper/pepper_pdf_host.h
+++ b/chrome/renderer/pepper/pepper_pdf_host.h
@@ -33,8 +33,6 @@
 }
 }
 
-namespace chrome {
-
 class PepperPDFHost : public ppapi::host::ResourceHost {
  public:
   PepperPDFHost(content::RendererPpapiHost* host,
@@ -79,6 +77,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperPDFHost);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_PDF_HOST_H_
diff --git a/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc b/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc
index 8aafd70..c1af72d 100644
--- a/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc
+++ b/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc
@@ -15,8 +15,6 @@
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/shared_impl/var_tracker.h"
 
-namespace chrome {
-
 PepperSharedMemoryMessageFilter::PepperSharedMemoryMessageFilter(
     content::RendererPpapiHost* host)
     : InstanceMessageFilter(host->GetPpapiHost()),
@@ -72,5 +70,3 @@
   plugin_handle->set_shmem(
       host_->ShareHandleWithRemote(host_handle, false), size);
 }
-
-}  // namespace chrome
diff --git a/chrome/renderer/pepper/pepper_shared_memory_message_filter.h b/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
index 5ffcf0b..9186f24 100644
--- a/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
+++ b/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
@@ -21,8 +21,6 @@
 }
 }
 
-namespace chrome {
-
 // Implements the backend for shared memory messages from a plugin process.
 class PepperSharedMemoryMessageFilter
     : public ppapi::host::InstanceMessageFilter {
@@ -48,6 +46,4 @@
   DISALLOW_COPY_AND_ASSIGN(PepperSharedMemoryMessageFilter);
 };
 
-}  // namespace chrome
-
 #endif  // CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_
diff --git a/chrome/renderer/pepper/ppb_nacl_private_impl.cc b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
index 967ea6d..6717bba 100644
--- a/chrome/renderer/pepper/ppb_nacl_private_impl.cc
+++ b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
@@ -306,11 +306,6 @@
   return PP_FromBool(ChromeRenderProcessObserver::is_incognito_process());
 }
 
-PP_Bool IsPnaclEnabled() {
-  return PP_FromBool(
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisablePnacl));
-}
-
 PP_ExternalPluginResult ReportNaClError(PP_Instance instance,
                               PP_NaClError error_id) {
   IPC::Sender* sender = content::RenderThread::Get();
@@ -366,7 +361,6 @@
   &GetNexeFd,
   &ReportTranslationFinished,
   &IsOffTheRecord,
-  &IsPnaclEnabled,
   &ReportNaClError,
   &OpenNaClExecutable
 };
diff --git a/chrome/renderer/plugins/DEPS b/chrome/renderer/plugins/DEPS
new file mode 100644
index 0000000..9883c71
--- /dev/null
+++ b/chrome/renderer/plugins/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/widevine",
+]
diff --git a/chrome/renderer/printing/print_web_view_helper.cc b/chrome/renderer/printing/print_web_view_helper.cc
index 668c5b1..f36d40c 100644
--- a/chrome/renderer/printing/print_web_view_helper.cc
+++ b/chrome/renderer/printing/print_web_view_helper.cc
@@ -1483,8 +1483,8 @@
     // Header/Footer: Set |header_footer_info_|.
     if (settings.params.display_header_footer) {
       header_footer_info_.reset(new base::DictionaryValue());
-      header_footer_info_->SetString(kSettingHeaderFooterDate,
-                                     settings.params.date);
+      header_footer_info_->SetDouble(kSettingHeaderFooterDate,
+                                     base::Time::Now().ToJsTime());
       header_footer_info_->SetString(kSettingHeaderFooterURL,
                                      settings.params.url);
       header_footer_info_->SetString(kSettingHeaderFooterTitle,
diff --git a/chrome/renderer/resources/extensions/app_window_custom_bindings.js b/chrome/renderer/resources/extensions/app_window_custom_bindings.js
index e32bd12..a060f11 100644
--- a/chrome/renderer/resources/extensions/app_window_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/app_window_custom_bindings.js
@@ -103,6 +103,18 @@
       return { left: bounds.left, top: bounds.top,
                width: bounds.width, height: bounds.height };
     };
+    AppWindow.prototype.getMinWidth = function() {
+      return appWindowData.minWidth;
+    };
+    AppWindow.prototype.getMinHeight = function() {
+      return appWindowData.minHeight;
+    };
+    AppWindow.prototype.getMaxWidth = function() {
+      return appWindowData.maxWidth;
+    };
+    AppWindow.prototype.getMaxHeight = function() {
+      return appWindowData.maxHeight;
+    };
     AppWindow.prototype.isFullscreen = function() {
       return appWindowData.fullscreen;
     };
@@ -124,6 +136,10 @@
       id: params.id || '',
       bounds: { left: params.bounds.left, top: params.bounds.top,
                 width: params.bounds.width, height: params.bounds.height },
+      minWidth: params.minWidth,
+      minHeight: params.minHeight,
+      maxWidth: params.maxWidth,
+      maxHeight: params.maxHeight,
       fullscreen: params.fullscreen,
       minimized: params.minimized,
       maximized: params.maximized,
diff --git a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
index 9a9fae0..9bec48b 100644
--- a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
@@ -19,14 +19,15 @@
 
   apiFunctions.setCustomCallback('openPopup',
                                  function(name, request, response) {
-    if (chrome.runtime.lastError)
-      throw new Error(chrome.runtime.lastError.message);
-
     if (!request.callback)
       return;
 
-    var views = getExtensionViews(-1, 'POPUP');
-    request.callback(views.length > 0 ? views[0] : null);
+    if (chrome.runtime.lastError) {
+      request.callback();
+    } else {
+      var views = getExtensionViews(-1, 'POPUP');
+      request.callback(views.length > 0 ? views[0] : null);
+    }
     request.callback = null;
   });
 });
diff --git a/chrome/renderer/resources/extensions/json_schema.js b/chrome/renderer/resources/extensions/json_schema.js
index 4b8996a..3c6f394 100644
--- a/chrome/renderer/resources/extensions/json_schema.js
+++ b/chrome/renderer/resources/extensions/json_schema.js
@@ -53,6 +53,10 @@
   return typeof(value) === 'undefined' || value === null;
 }
 
+function enumToString(enumValue) {
+  return enumValue.name || enumValue;
+}
+
 /**
  * Validates an instance against a schema and accumulates errors. Usage:
  *
@@ -317,11 +321,12 @@
  */
 JSONSchemaValidator.prototype.validateEnum = function(instance, schema, path) {
   for (var i = 0; i < schema.enum.length; i++) {
-    if (instance === schema.enum[i])
+    if (instance === enumToString(schema.enum[i]))
       return true;
   }
 
-  this.addError(path, "invalidEnum", [schema.enum.join(", ")]);
+  this.addError(path, "invalidEnum",
+                [schema.enum.map(enumToString).join(", ")]);
   return false;
 };
 
diff --git a/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js b/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
index a75d36d..0e285d2 100644
--- a/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
@@ -9,26 +9,24 @@
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
   var apiFunctions = bindingsAPI.apiFunctions;
 
-  apiFunctions.setCustomCallback('capture',
-                                 function(name, request, response) {
+  apiFunctions.setCustomCallback('capture', function(name, request, response) {
     if (response && request.callback) {
       var callback = request.callback;
-      var successFunc = function(stream) {
-        callback(stream);
-      };
-      var errorFunc = function() {
-        callback(null);
-      };
-
       var options = {};
       if (response.audioConstraints)
         options.audio = response.audioConstraints;
       if (response.videoConstraints)
         options.video = response.videoConstraints;
 
-      navigator.webkitGetUserMedia(options, successFunc, errorFunc);
+      try {
+        navigator.webkitGetUserMedia(options,
+                                     function(stream) { callback(stream); },
+                                     function() { callback(null); });
+      } catch (e) {
+        callback(null);
+      }
     } else {
-      request.callback();
+      request.callback(null);
     }
     request.callback = null;
   });
diff --git a/chrome/renderer/resources/extensions/test_custom_bindings.js b/chrome/renderer/resources/extensions/test_custom_bindings.js
index 7df6f5d..fe60eb2 100644
--- a/chrome/renderer/resources/extensions/test_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/test_custom_bindings.js
@@ -12,6 +12,7 @@
     requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest;
 var GetAvailability = requireNative('v8_context').GetAvailability;
 var GetAPIFeatures = requireNative('test_features').GetAPIFeatures;
+var userGestures = requireNative('user_gestures');
 
 binding.registerCustomHook(function(api) {
   var chromeTest = api.compiledApi;
@@ -326,6 +327,20 @@
   apiFunctions.setHandleRequest('getApiFeatures', function() {
     return GetAPIFeatures();
   });
+
+  apiFunctions.setHandleRequest('isProcessingUserGesture', function() {
+    return userGestures.IsProcessingUserGesture();
+  });
+
+  apiFunctions.setHandleRequest('runWithUserGesture', function(callback) {
+    chromeTest.assertEq(typeof(callback), 'function');
+    return userGestures.RunWithUserGesture(callback);
+  });
+
+  apiFunctions.setHandleRequest('runWithoutUserGesture', function(callback) {
+    chromeTest.assertEq(typeof(callback), 'function');
+    return userGestures.RunWithoutUserGesture(callback);
+  });
 });
 
 exports.binding = binding.generate();
diff --git a/chrome/renderer/resources/extensions/webrtc_cast_send_transport_custom_bindings.js b/chrome/renderer/resources/extensions/webrtc_cast_send_transport_custom_bindings.js
index 6ba4c6f..f295a0a 100644
--- a/chrome/renderer/resources/extensions/webrtc_cast_send_transport_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/webrtc_cast_send_transport_custom_bindings.js
@@ -5,13 +5,35 @@
 // Custom binding for the webrtc custom transport API.
 
 var binding = require('binding').Binding.create('webrtc.castSendTransport');
+var webrtc = requireNative('webrtc_natives');
 
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
   var apiFunctions = bindingsAPI.apiFunctions;
 
   apiFunctions.setHandleRequest('create',
-                                function(innerTransportId, callback) {
-    // invoke impl here.
+      function(track, innerTransportId, callback) {
+        webrtc.CreateCastSendTransport(track, innerTransportId, callback);
+  });
+  apiFunctions.setHandleRequest('destroy',
+      function(transportId) {
+        webrtc.DestroyCastSendTransport(transportId);
+  });
+  apiFunctions.setHandleRequest('getCaps',
+      function(transportId, callback) {
+        webrtc.GetCapsCastSendTransport(transportId, callback);
+  });
+  apiFunctions.setHandleRequest('createParams',
+      function(transportId, remoteCaps, callback) {
+        webrtc.CreateParamsCastSendTransport(transportId, remoteCaps,
+                                             callback);
+  });
+  apiFunctions.setHandleRequest('start',
+      function(transportId, params) {
+        webrtc.StartCastSendTransport(transportId, params);
+  });
+  apiFunctions.setHandleRequest('stop',
+      function(transportId) {
+        webrtc.StopCastSendTransport(transportId);
   });
 });
 
diff --git a/chrome/renderer/resources/extensions/webrtc_cast_udp_transport_custom_bindings.js b/chrome/renderer/resources/extensions/webrtc_cast_udp_transport_custom_bindings.js
new file mode 100644
index 0000000..52f86e9
--- /dev/null
+++ b/chrome/renderer/resources/extensions/webrtc_cast_udp_transport_custom_bindings.js
@@ -0,0 +1,28 @@
+// Copyright 2013 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.
+
+// Custom binding for the webrtc custom transport API.
+
+var binding = require('binding').Binding.create('webrtc.castUdpTransport');
+var webrtc = requireNative('webrtc_natives');
+
+binding.registerCustomHook(function(bindingsAPI, extensionId) {
+  var apiFunctions = bindingsAPI.apiFunctions;
+
+  apiFunctions.setHandleRequest('create', function(callback) {
+    webrtc.CreateCastUdpTransport(callback);
+  });
+  apiFunctions.setHandleRequest('destroy', function(transportId) {
+    webrtc.DestroyCastUdpTransport(transportId);
+  });
+  apiFunctions.setHandleRequest('start',
+      function(transportId, remoteParams) {
+        webrtc.StartCastUdpTransport(transportId, remoteParams);
+  });
+  apiFunctions.setHandleRequest('stop', function(transportId) {
+    webrtc.StopCastUdpTransport(transportId);
+  });
+});
+
+exports.binding = binding.generate();
diff --git a/chrome/renderer/resources/extensions/webrtc_udp_transport_custom_bindings.js b/chrome/renderer/resources/extensions/webrtc_udp_transport_custom_bindings.js
deleted file mode 100644
index 3b0b42f..0000000
--- a/chrome/renderer/resources/extensions/webrtc_udp_transport_custom_bindings.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2013 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.
-
-// Custom binding for the webrtc custom transport API.
-
-var binding = require('binding').Binding.create('webrtc.udpTransport');
-
-binding.registerCustomHook(function(bindingsAPI, extensionId) {
-  var apiFunctions = bindingsAPI.apiFunctions;
-
-  apiFunctions.setHandleRequest('create',
-                                function(callback) {
-    // invoke impl here.
-  });
-});
-
-exports.binding = binding.generate();
diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd
index 60ef63f..d199fd0 100644
--- a/chrome/renderer/resources/renderer_resources.grd
+++ b/chrome/renderer/resources/renderer_resources.grd
@@ -91,7 +91,7 @@
         <include name="IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS" file="extensions\web_request_custom_bindings.js" type="BINDATA" />
         <include name="IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS" file="extensions\web_request_internal_custom_bindings.js" type="BINDATA" />
         <include name="IDR_WEBRTC_CAST_SEND_TRANSPORT_CUSTOM_BINDINGS_JS" file="extensions\webrtc_cast_send_transport_custom_bindings.js" type="BINDATA" />
-        <include name="IDR_WEBRTC_UDP_TRANSPORT_CUSTOM_BINDINGS_JS" file="extensions\webrtc_udp_transport_custom_bindings.js" type="BINDATA" />
+        <include name="IDR_WEBRTC_CAST_UDP_TRANSPORT_CUSTOM_BINDINGS_JS" file="extensions\webrtc_cast_udp_transport_custom_bindings.js" type="BINDATA" />
         <include name="IDR_WEBSTORE_CUSTOM_BINDINGS_JS" file="extensions\webstore_custom_bindings.js" type="BINDATA" />
         <include name="IDR_WEB_VIEW_DENY_JS" file="extensions\web_view_deny.js" type="BINDATA" />
         <include name="IDR_WEB_VIEW_EXPERIMENTAL_JS" file="extensions\web_view_experimental.js" type="BINDATA" />
diff --git a/chrome/renderer/safe_browsing/DEPS b/chrome/renderer/safe_browsing/DEPS
new file mode 100644
index 0000000..aa579c4
--- /dev/null
+++ b/chrome/renderer/safe_browsing/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/smhasher",
+]
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc
index f7948d8..b6f3cab 100644
--- a/chrome/renderer/searchbox/searchbox.cc
+++ b/chrome/renderer/searchbox/searchbox.cc
@@ -228,12 +228,11 @@
 }
 
 void SearchBox::NavigateToURL(const GURL& url,
-                              content::PageTransition transition,
                               WindowOpenDisposition disposition,
-                              bool is_search_type) {
+                              bool is_most_visited_item_url) {
   render_view()->Send(new ChromeViewHostMsg_SearchBoxNavigate(
-      render_view()->GetRoutingID(), render_view()->GetPageId(),
-      url, transition, disposition, is_search_type));
+      render_view()->GetRoutingID(), render_view()->GetPageId(), url,
+      disposition, is_most_visited_item_url));
 }
 
 void SearchBox::Paste(const string16& text) {
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h
index 51db602..51247db 100644
--- a/chrome/renderer/searchbox/searchbox.h
+++ b/chrome/renderer/searchbox/searchbox.h
@@ -13,7 +13,6 @@
 #include "chrome/common/instant_types.h"
 #include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/omnibox_focus_state.h"
-#include "content/public/common/page_transition_types.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/renderer/render_view_observer_tracker.h"
 #include "ui/base/window_open_disposition.h"
@@ -71,9 +70,8 @@
 
   // Sends ChromeViewHostMsg_SearchBoxNavigate to the browser.
   void NavigateToURL(const GURL& url,
-                     content::PageTransition transition,
                      WindowOpenDisposition disposition,
-                     bool is_search_type);
+                     bool is_most_visited_item_url);
 
   // Sends ChromeViewHostMsg_SearchBoxPaste to the browser.
   void Paste(const string16& text);
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index f9488ee..9dc6ca1 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -855,14 +855,14 @@
   if (!render_view || !args.Length()) return;
 
   GURL destination_url;
-  content::PageTransition transition = content::PAGE_TRANSITION_AUTO_BOOKMARK;
-
+  bool is_most_visited_item_url = false;
   // Check if the url is a rid
   if (args[0]->IsNumber()) {
     InstantMostVisitedItem item;
     if (SearchBox::Get(render_view)->GetMostVisitedItemWithID(
-        args[0]->IntegerValue(), &item)) {
+            args[0]->IntegerValue(), &item)) {
       destination_url = item.url;
+      is_most_visited_item_url = true;
     }
   } else {
     // Resolve the URL
@@ -878,8 +878,8 @@
     WindowOpenDisposition disposition = CURRENT_TAB;
     if (args[1]->Uint32Value() == 2)
       disposition = NEW_BACKGROUND_TAB;
-    SearchBox::Get(render_view)->NavigateToURL(
-        destination_url, transition, disposition, false);
+    SearchBox::Get(render_view)->NavigateToURL(destination_url, disposition,
+                                               is_most_visited_item_url);
   }
 }
 
diff --git a/chrome/renderer/web_apps.cc b/chrome/renderer/web_apps.cc
index b5c3395..5e7a30f 100644
--- a/chrome/renderer/web_apps.cc
+++ b/chrome/renderer/web_apps.cc
@@ -80,19 +80,16 @@
   if (!url.is_valid())
     return;
 
-  if (!link.hasAttribute("sizes"))
-    return;
-
+  WebApplicationInfo::IconInfo icon_info;
   bool is_any = false;
   std::vector<gfx::Size> icon_sizes;
-  if (!ParseIconSizes(link.getAttribute("sizes"), &icon_sizes, &is_any) ||
-      is_any ||
-      icon_sizes.size() != 1) {
-    return;
+  if (link.hasAttribute("sizes") &&
+      ParseIconSizes(link.getAttribute("sizes"), &icon_sizes, &is_any) &&
+      !is_any &&
+      icon_sizes.size() == 1) {
+    icon_info.width = icon_sizes[0].width();
+    icon_info.height = icon_sizes[0].height();
   }
-  WebApplicationInfo::IconInfo icon_info;
-  icon_info.width = icon_sizes[0].width();
-  icon_info.height = icon_sizes[0].height();
   icon_info.url = url;
   icons->push_back(icon_info);
 }
diff --git a/chrome/service/service_ipc_server.cc b/chrome/service/service_ipc_server.cc
index f05bf4b..b700c57 100644
--- a/chrome/service/service_ipc_server.cc
+++ b/chrome/service/service_ipc_server.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/service/service_ipc_server.h"
 
+#include "base/metrics/histogram_delta_serialization.h"
 #include "chrome/common/service_messages.h"
 #include "chrome/service/cloud_print/cloud_print_proxy.h"
 #include "chrome/service/service_process.h"
@@ -98,6 +99,7 @@
                         OnDisableCloudPrintProxy)
     IPC_MESSAGE_HANDLER(ServiceMsg_GetCloudPrintProxyInfo,
                         OnGetCloudPrintProxyInfo)
+    IPC_MESSAGE_HANDLER(ServiceMsg_GetHistograms, OnGetHistograms)
     IPC_MESSAGE_HANDLER(ServiceMsg_Shutdown, OnShutdown);
     IPC_MESSAGE_HANDLER(ServiceMsg_UpdateAvailable, OnUpdateAvailable);
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -120,6 +122,16 @@
   channel_->Send(new ServiceHostMsg_CloudPrintProxy_Info(info));
 }
 
+void ServiceIPCServer::OnGetHistograms() {
+  if (!histogram_delta_serializer_) {
+    histogram_delta_serializer_.reset(
+        new base::HistogramDeltaSerialization("ServiceProcess"));
+  }
+  std::vector<std::string> deltas;
+  histogram_delta_serializer_->PrepareAndSerializeDeltas(&deltas);
+  channel_->Send(new ServiceHostMsg_Histograms(deltas));
+}
+
 void ServiceIPCServer::OnDisableCloudPrintProxy() {
   // User disabled CloudPrint proxy explicitly. Delete printers
   // registered from this proxy and disable proxy.
diff --git a/chrome/service/service_ipc_server.h b/chrome/service/service_ipc_server.h
index 28fe4b4..c265a98 100644
--- a/chrome/service/service_ipc_server.h
+++ b/chrome/service/service_ipc_server.h
@@ -18,6 +18,7 @@
 namespace base {
 
 class DictionaryValue;
+class HistogramDeltaSerialization;
 
 }  // namespace base
 
@@ -58,6 +59,7 @@
       const std::string& user_email,
       const base::DictionaryValue& user_settings);
   void OnGetCloudPrintProxyInfo();
+  void OnGetHistograms();
   void OnDisableCloudPrintProxy();
 
   void OnShutdown();
@@ -74,6 +76,8 @@
   // Allows threads other than the main thread to send sync messages.
   scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
 
+  // Calculates histograms deltas.
+  scoped_ptr<base::HistogramDeltaSerialization> histogram_delta_serializer_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceIPCServer);
 };
diff --git a/chrome/service/service_main.cc b/chrome/service/service_main.cc
index 99e680b..e6d0142 100644
--- a/chrome/service/service_main.cc
+++ b/chrome/service/service_main.cc
@@ -4,6 +4,7 @@
 
 #include "base/debug/debugger.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/statistics_recorder.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/service_process_util.h"
 #include "chrome/service/service_process.h"
@@ -37,6 +38,7 @@
           << parameters.command_line.GetCommandLineString();
 
   base::PlatformThread::SetName("CrServiceMain");
+  base::StatisticsRecorder::Initialize();
 
   // If there is already a service process running, quit now.
   scoped_ptr<ServiceProcessState> state(new ServiceProcessState);
diff --git a/chrome/sync_integration_tests.isolate b/chrome/sync_integration_tests.isolate
index 5aa2463..3861306 100644
--- a/chrome/sync_integration_tests.isolate
+++ b/chrome/sync_integration_tests.isolate
@@ -8,7 +8,6 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/sync_integration_tests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_tracked': [
@@ -52,7 +51,6 @@
     ['OS=="mac"', {
       'variables': {
         'command': [
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/sync_integration_tests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_tracked': [
diff --git a/chrome/test/DEPS b/chrome/test/DEPS
index 5a9fdbd..595b0db 100644
--- a/chrome/test/DEPS
+++ b/chrome/test/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   # The test directory can do whatever it wants in chrome, and may
   # rely on components.
+  "+ash",
   "+chrome",
   "+chromeos",
   "+components",
diff --git a/chrome/test/android/OWNERS b/chrome/test/android/OWNERS
index df798f4..b8e17f3 100644
--- a/chrome/test/android/OWNERS
+++ b/chrome/test/android/OWNERS
@@ -2,7 +2,7 @@
 bulach@chromium.org
 dfalcantara@chromium.org
 dtrainor@chromium.org
-miguelg@chromium.org
 nyquist@chromium.org
+skyostil@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/test/base/browser_perf_tests_main.cc b/chrome/test/base/browser_perf_tests_main.cc
new file mode 100644
index 0000000..e9aafbf
--- /dev/null
+++ b/chrome/test/base/browser_perf_tests_main.cc
@@ -0,0 +1,11 @@
+// Copyright 2013 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/test/base/chrome_test_launcher.h"
+
+int main(int argc, char** argv) {
+  // Always run browser perf tests serially - parallel running would be less
+  // deterministic and distort perf measurements.
+  return LaunchChromeTests(1, argc, argv);
+}
diff --git a/chrome/test/base/browser_tests_main.cc b/chrome/test/base/browser_tests_main.cc
new file mode 100644
index 0000000..cb2acce
--- /dev/null
+++ b/chrome/test/base/browser_tests_main.cc
@@ -0,0 +1,11 @@
+// Copyright 2013 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 "chrome/test/base/chrome_test_launcher.h"
+
+int main(int argc, char** argv) {
+  int default_jobs = std::max(1, base::SysInfo::NumberOfProcessors() / 2);
+  return LaunchChromeTests(default_jobs, argc, argv);
+}
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index 73efa62..16f22df 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -59,7 +59,7 @@
 #endif  // USE_AURA
 
   // Subclasses can provide their own Profile.
-  profile_.reset(CreateProfile());
+  profile_ = CreateProfile();
   // Subclasses can provide their own test BrowserWindow. If they return NULL
   // then Browser will create the a production BrowserWindow and the subclass
   // is responsible for cleaning it up (usually by NativeWidget destruction).
@@ -179,13 +179,19 @@
   // destructor, and a test subclass owns a resource that the profile depends
   // on (such as g_browser_process()->local_state()) there's no way for the
   // subclass to free it after the profile.
-  profile_.reset(NULL);
+  if (profile_)
+    DestroyProfile(profile_);
+  profile_ = NULL;
 }
 
 TestingProfile* BrowserWithTestWindowTest::CreateProfile() {
   return new TestingProfile();
 }
 
+void BrowserWithTestWindowTest::DestroyProfile(TestingProfile* profile) {
+  delete profile;
+}
+
 BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() {
   return new TestBrowserWindow();
 }
diff --git a/chrome/test/base/browser_with_test_window_test.h b/chrome/test/base/browser_with_test_window_test.h
index f4e6e51..91bb325 100644
--- a/chrome/test/base/browser_with_test_window_test.h
+++ b/chrome/test/base/browser_with_test_window_test.h
@@ -95,9 +95,9 @@
     return browser_.release();
   }
 
-  TestingProfile* profile() const { return profile_.get(); }
+  TestingProfile* profile() const { return profile_; }
 
-  TestingProfile* GetProfile() { return profile_.get(); }
+  TestingProfile* GetProfile() { return profile_; }
 
   BrowserWindow* release_browser_window() WARN_UNUSED_RESULT {
     return window_.release();
@@ -134,6 +134,9 @@
   // Creates the profile used by this test. The caller owns the return value.
   virtual TestingProfile* CreateProfile();
 
+  // Destroys the profile which was created through |CreateProfile|.
+  virtual void DestroyProfile(TestingProfile* profile);
+
   // Creates the BrowserWindow used by this test. The caller owns the return
   // value. Can return NULL to use the default window created by Browser.
   virtual BrowserWindow* CreateBrowserWindow();
@@ -149,7 +152,10 @@
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
-  scoped_ptr<TestingProfile> profile_;
+  // The profile will automatically be destroyed by TearDown using the
+  // |DestroyProfile()| function - which can be overwritten by derived testing
+  // frameworks.
+  TestingProfile* profile_;
   scoped_ptr<BrowserWindow> window_;  // Usually a TestBrowserWindow.
   scoped_ptr<Browser> browser_;
 
diff --git a/chrome/test/base/chrome_test_launcher.cc b/chrome/test/base/chrome_test_launcher.cc
index 442e344..f14ace3 100644
--- a/chrome/test/base/chrome_test_launcher.cc
+++ b/chrome/test/base/chrome_test_launcher.cc
@@ -42,6 +42,9 @@
 #if defined(USE_AURA)
 #include "ui/aura/test/ui_controls_factory_aura.h"
 #include "ui/base/test/ui_controls_aura.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/test/ui_controls_factory_desktop_aurax11.h"
+#endif
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -52,6 +55,8 @@
 #include "chrome/app/chrome_breakpad_client.h"
 #endif
 
+namespace {
+
 class ChromeTestLauncherDelegate : public content::TestLauncherDelegate {
  public:
   ChromeTestLauncherDelegate() {}
@@ -123,39 +128,13 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeTestLauncherDelegate);
 };
 
-int main(int argc, char** argv) {
-// http://crbug.com/163931 Disabled until interactive_ui_tests ready on Linux
-// Aura.
-#if defined(OS_LINUX) && defined(USE_AURA) && !defined(OS_CHROMEOS)
-  base::FilePath bin_dir;
-  CHECK(file_util::ReadSymbolicLink(
-      base::FilePath(base::kProcSelfExe), &bin_dir));
-  std::string filename = bin_dir.value();
-  // http://crbug.com/154081: early exit until interactive_ui_tests are green.
-  if (EndsWith(filename, "interactive_ui_tests", false)) {
-    LOG(INFO) << "interactive_ui_tests on Linux Aura are not ready yet.";
-    return 0;
-  }
-#endif
+}  // namespace
 
+int LaunchChromeTests(int default_jobs, int argc, char** argv) {
 #if defined(OS_MACOSX)
   chrome_browser_application_mac::RegisterBrowserCrApp();
 #endif
 
-// Only allow ui_controls to be used in interactive_ui_tests, since they depend
-// on focus and can't be sharded.
-#if defined(INTERACTIVE_TESTS)
-  ui_controls::EnableUIControls();
-
-#if defined(OS_CHROMEOS)
-  ui_controls::InstallUIControlsAura(ash::test::CreateAshUIControls());
-#elif defined(USE_AURA)
-  // TODO(win_ash): when running interactive_ui_tests for Win Ash, use above.
-  ui_controls::InstallUIControlsAura(aura::test::CreateUIControlsAura(NULL));
-#endif
-
-#endif
-
 #if defined(OS_LINUX) || defined(OS_ANDROID)
   // We leak this pointer intentionally. The breakpad client needs to outlive
   // all other code.
@@ -166,5 +145,5 @@
 #endif
 
   ChromeTestLauncherDelegate launcher_delegate;
-  return content::LaunchTests(&launcher_delegate, argc, argv);
+  return content::LaunchTests(&launcher_delegate, default_jobs, argc, argv);
 }
diff --git a/chrome/test/base/chrome_test_launcher.h b/chrome/test/base/chrome_test_launcher.h
new file mode 100644
index 0000000..b9254d3
--- /dev/null
+++ b/chrome/test/base/chrome_test_launcher.h
@@ -0,0 +1,13 @@
+// Copyright 2013 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_TEST_BASE_CHROME_TEST_LAUNCHER_H_
+#define CHROME_TEST_BASE_CHROME_TEST_LAUNCHER_H_
+
+// Launches Chrome tests using |launcher_delegate|. |default_jobs| is number
+// of test jobs to be run in parallel, unless overridden from the command line.
+// Returns exit code.
+int LaunchChromeTests(int default_jobs, int argc, char** argv);
+
+#endif  // CHROME_TEST_BASE_CHROME_TEST_LAUNCHER_H_
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc
index ad2967e..e010054 100644
--- a/chrome/test/base/chrome_test_suite.cc
+++ b/chrome/test/base/chrome_test_suite.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
+#include "chrome/browser/extensions/chrome_extensions_browser_client.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_content_client.h"
@@ -171,6 +172,8 @@
 
   extensions::ExtensionsClient::Set(
       extensions::ChromeExtensionsClient::GetInstance());
+  extensions::ExtensionsBrowserClient::Set(
+      extensions::ChromeExtensionsBrowserClient::GetInstance());
 
   // Only want to do this for unit tests.
   if (!content::GetCurrentTestLauncherDelegate()) {
diff --git a/chrome/test/base/interactive_test_utils_win.cc b/chrome/test/base/interactive_test_utils_win.cc
index ec7e285..7a4f747 100644
--- a/chrome/test/base/interactive_test_utils_win.cc
+++ b/chrome/test/base/interactive_test_utils_win.cc
@@ -29,7 +29,7 @@
     HideNativeWindowAura(window);
     return;
   }
-  HWND hwnd = window->GetRootWindow()->GetAcceleratedWidget();
+  HWND hwnd = window->GetDispatcher()->GetAcceleratedWidget();
 #else
   HWND hwnd = window;
 #endif
@@ -41,8 +41,9 @@
   if (chrome::GetHostDesktopTypeForNativeWindow(window) ==
       chrome::HOST_DESKTOP_TYPE_ASH)
     ShowAndFocusNativeWindowAura(window);
+  window->Show();
   // Always make sure the window hosting ash is visible and focused.
-  HWND hwnd = window->GetRootWindow()->GetAcceleratedWidget();
+  HWND hwnd = window->GetDispatcher()->GetAcceleratedWidget();
 #else
   HWND hwnd = window;
 #endif
diff --git a/chrome/test/base/interactive_ui_tests_main.cc b/chrome/test/base/interactive_ui_tests_main.cc
new file mode 100644
index 0000000..8de925a
--- /dev/null
+++ b/chrome/test/base/interactive_ui_tests_main.cc
@@ -0,0 +1,41 @@
+// Copyright 2013 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/test/base/chrome_test_launcher.h"
+
+#include "ui/base/test/ui_controls.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/test/ui_controls_factory_aura.h"
+#include "ui/base/test/ui_controls_aura.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/test/ui_controls_factory_desktop_aurax11.h"
+#endif
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "ash/test/ui_controls_factory_ash.h"
+#endif
+
+int main(int argc, char** argv) {
+  // Only allow ui_controls to be used in interactive_ui_tests, since they
+  // depend on focus and can't be sharded.
+  ui_controls::EnableUIControls();
+
+#if defined(OS_CHROMEOS)
+  ui_controls::InstallUIControlsAura(ash::test::CreateAshUIControls());
+#elif defined(USE_AURA)
+
+#if defined(OS_LINUX)
+  ui_controls::InstallUIControlsAura(
+      views::test::CreateUIControlsDesktopAura());
+#else
+  // TODO(win_ash): when running interactive_ui_tests for Win Ash, use above.
+  ui_controls::InstallUIControlsAura(aura::test::CreateUIControlsAura(NULL));
+#endif
+#endif
+
+  // Run interactive_ui_tests serially, they do not support running in parallel.
+  return LaunchChromeTests(1, argc, argv);
+}
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 1f28044..a6d9682 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -101,6 +101,9 @@
   virtual void ShowUpdateChromeDialog() OVERRIDE {}
   virtual void ShowBookmarkBubble(const GURL& url,
                                   bool already_bookmarked) OVERRIDE {}
+  virtual void ShowTranslateBubble(
+      content::WebContents* contents,
+      TranslateBubbleModel::ViewState view_state) OVERRIDE {}
 #if defined(ENABLE_ONE_CLICK_SIGNIN)
   virtual void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
diff --git a/chrome/test/base/test_tab_strip_model_observer.cc b/chrome/test/base/test_tab_strip_model_observer.cc
deleted file mode 100644
index f25a599..0000000
--- a/chrome/test/base/test_tab_strip_model_observer.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 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/test/base/test_tab_strip_model_observer.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "chrome/browser/printing/print_preview_dialog_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host_observer.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/js_injection_ready_observer.h"
-
-class TestTabStripModelObserver::RenderViewHostInitializedObserver
-    : public content::RenderViewHostObserver {
- public:
-  RenderViewHostInitializedObserver(content::RenderViewHost* render_view_host,
-                                    content::JsInjectionReadyObserver* observer)
-      : content::RenderViewHostObserver(render_view_host),
-        injection_observer_(observer) {
-  }
-
-  // content::RenderViewHostObserver:
-  virtual void RenderViewHostInitialized() OVERRIDE {
-    injection_observer_->OnJsInjectionReady(render_view_host());
-  }
-
- private:
-  content::JsInjectionReadyObserver* injection_observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostInitializedObserver);
-};
-
-TestTabStripModelObserver::TestTabStripModelObserver(
-    TabStripModel* tab_strip_model,
-    content::JsInjectionReadyObserver* js_injection_ready_observer)
-    : TestNavigationObserver(NULL, 1),
-      tab_strip_model_(tab_strip_model),
-      rvh_created_callback_(
-          base::Bind(&TestTabStripModelObserver::RenderViewHostCreated,
-                     base::Unretained(this))),
-      injection_observer_(js_injection_ready_observer) {
-  content::RenderViewHost::AddCreatedCallback(rvh_created_callback_);
-  tab_strip_model_->AddObserver(this);
-}
-
-TestTabStripModelObserver::~TestTabStripModelObserver() {
-  content::RenderViewHost::RemoveCreatedCallback(rvh_created_callback_);
-  tab_strip_model_->RemoveObserver(this);
-}
-
-void TestTabStripModelObserver::RenderViewHostCreated(
-    content::RenderViewHost* rvh) {
-  rvh_observer_.reset(
-      new RenderViewHostInitializedObserver(rvh, injection_observer_));
-}
-
-void TestTabStripModelObserver::TabBlockedStateChanged(
-    content::WebContents* contents, int index) {
-  // Need to do this later - the print preview dialog has not been created yet.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&TestTabStripModelObserver::ObservePrintPreviewDialog,
-                 base::Unretained(this),
-                 contents));
-}
-
-void TestTabStripModelObserver::ObservePrintPreviewDialog(
-    content::WebContents* contents) {
-  printing::PrintPreviewDialogController* dialog_controller =
-      printing::PrintPreviewDialogController::GetInstance();
-  if (!dialog_controller)
-    return;
-  content::WebContents* preview_dialog =
-      dialog_controller->GetPrintPreviewForContents(contents);
-  if (!preview_dialog)
-    return;
-  RegisterAsObserver(preview_dialog);
-}
diff --git a/chrome/test/base/test_tab_strip_model_observer.h b/chrome/test/base/test_tab_strip_model_observer.h
deleted file mode 100644
index 13e18ea..0000000
--- a/chrome/test/base/test_tab_strip_model_observer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2012 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_TEST_BASE_TEST_TAB_STRIP_MODEL_OBSERVER_H_
-#define CHROME_TEST_BASE_TEST_TAB_STRIP_MODEL_OBSERVER_H_
-
-#include "base/compiler_specific.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/test/test_navigation_observer.h"
-
-class TabStripModel;
-
-namespace content {
-class JsInjectionReadyObserver;
-}
-
-// In order to support testing of print preview, we need to wait for the
-// constrained window to block the current tab, and then observe notifications
-// on the newly added tab's controller to wait for it to be loaded.
-// To support tests registering javascript WebUI handlers, we need to inject
-// the framework & registration javascript before the webui page loads by
-// calling back through the TestTabStripModelObserver::LoadStartObserver when
-// the new page starts loading.
-class TestTabStripModelObserver : public content::TestNavigationObserver,
-                                  public TabStripModelObserver {
- public:
-  // Observe the |tab_strip_model|, which may not be NULL. If
-  // |load_start_observer| is non-NULL, notify when the page load starts.
-  TestTabStripModelObserver(
-      TabStripModel* tab_strip_model,
-      content::JsInjectionReadyObserver* js_injection_ready_observer);
-  virtual ~TestTabStripModelObserver();
-
- private:
-  class RenderViewHostInitializedObserver;
-
-  void RenderViewHostCreated(content::RenderViewHost* rvh);
-
-  // Callback to observer the print preview dialog associated with |contents|.
-  void ObservePrintPreviewDialog(content::WebContents* contents);
-
-  // TabStripModelObserver:
-  virtual void TabBlockedStateChanged(content::WebContents* contents,
-                                      int index) OVERRIDE;
-
-  // |tab_strip_model_| is the object this observes. The constructor will
-  // register this as an observer, and the destructor will remove the observer.
-  TabStripModel* tab_strip_model_;
-
-  content::RenderViewHost::CreatedCallback rvh_created_callback_;
-
-  // RenderViewHost watched for JS injection.
-  scoped_ptr<RenderViewHostInitializedObserver> rvh_observer_;
-
-  content::JsInjectionReadyObserver* injection_observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestTabStripModelObserver);
-};
-
-#endif  // CHROME_TEST_BASE_TEST_TAB_STRIP_MODEL_OBSERVER_H_
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index bc655aa..83de4b4 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -700,12 +700,20 @@
 void TestingProfile::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   // Always reject requests for testing.
   callback.Run(false);
 }
 
+void TestingProfile::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+}
+
 net::URLRequestContextGetter* TestingProfile::GetRequestContextForExtensions() {
   if (!extensions_request_context_.get())
     extensions_request_context_ = new TestExtensionURLRequestContextGetter();
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 297cb95..6f2f3eb 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -263,8 +263,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+        int render_process_id,
+        int render_view_id,
+        int bridge_id,
+        const GURL& requesting_frame) OVERRIDE;
   virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
       const base::FilePath& partition_path,
       bool in_memory,
diff --git a/chrome/test/base/view_event_test_base.cc b/chrome/test/base/view_event_test_base.cc
index eb9fb3d..ac4d8ac 100644
--- a/chrome/test/base/view_event_test_base.cc
+++ b/chrome/test/base/view_event_test_base.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/test/ui_controls.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
@@ -22,9 +23,6 @@
 #include "ash/shell.h"
 #include "ash/test/test_session_state_delegate.h"
 #include "ash/test/test_shell_delegate.h"
-#if defined(OS_WIN)
-#include "ui/compositor/compositor.h"
-#endif
 #endif
 
 #if defined(USE_AURA)
@@ -102,17 +100,15 @@
   gfx::NativeView context = NULL;
 
 #if defined(USE_ASH)
+  // The ContextFactory must exist before any Compositors are created.
+  bool allow_test_contexts = true;
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
 #if defined(OS_WIN)
   // http://crbug.com/154081 use ash::Shell code path below on win_ash bots when
   // interactive_ui_tests is brought up on that platform.
   gfx::Screen::SetScreenInstance(
       gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
 
-  // The ContextFactory must exist before any Compositors are created. The
-  // ash::Shell code path below handles this, but since we skip it we must
-  // do this here.
-  bool allow_test_contexts = true;
-  ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
 #else  // !OS_WIN
   // Ash Shell can't just live on its own without a browser process, we need to
   // also create the message center.
@@ -164,6 +160,7 @@
   message_center::MessageCenter::Shutdown();
 #endif  // !OS_WIN
   aura::Env::DeleteInstance();
+  ui::TerminateContextFactoryForTests();
 #elif defined(USE_AURA)
   aura_test_helper_->TearDown();
 #endif  // !USE_ASH && USE_AURA
diff --git a/chrome/test/base/web_ui_browsertest.cc b/chrome/test/base/web_ui_browsertest.cc
index bfa5f95..4b6d6b2 100644
--- a/chrome/test/base/web_ui_browsertest.cc
+++ b/chrome/test/base/web_ui_browsertest.cc
@@ -14,27 +14,30 @@
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/webui/web_ui_test_handler.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/test_chrome_web_ui_controller_factory.h"
-#include "chrome/test/base/test_tab_strip_model_observer.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "net/base/net_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest-spi.h"
@@ -78,54 +81,26 @@
   return false;
 }
 
-class RenderViewHostInitializedObserver
-    : public content::RenderViewHostObserver {
+class WebUIJsInjectionReadyObserver : public content::WebContentsObserver {
  public:
-  RenderViewHostInitializedObserver(content::RenderViewHost* render_view_host,
-                                    content::JsInjectionReadyObserver* observer)
-      : content::RenderViewHostObserver(render_view_host),
-        injection_observer_(observer) {
-  }
+  WebUIJsInjectionReadyObserver(content::WebContents* web_contents,
+                                WebUIBrowserTest* browser_test,
+                                const std::string& preload_test_fixture,
+                                const std::string& preload_test_name)
+      : content::WebContentsObserver(web_contents),
+        browser_test_(browser_test),
+        preload_test_fixture_(preload_test_fixture),
+        preload_test_name_(preload_test_name) {}
 
-  // content::RenderViewHostObserver:
-  virtual void RenderViewHostInitialized() OVERRIDE {
-    injection_observer_->OnJsInjectionReady(render_view_host());
+  virtual void RenderViewCreated(content::RenderViewHost* rvh) OVERRIDE {
+    browser_test_->PreLoadJavascriptLibraries(
+        preload_test_fixture_, preload_test_name_, rvh);
   }
 
  private:
-  content::JsInjectionReadyObserver* injection_observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostInitializedObserver);
-};
-
-class WebUIJsInjectionReadyObserver {
- public:
-  explicit WebUIJsInjectionReadyObserver(
-      content::JsInjectionReadyObserver* observer)
-      : injection_observer_(observer),
-        rvh_callback_(
-            base::Bind(&WebUIJsInjectionReadyObserver::RenderViewHostCreated,
-                       base::Unretained(this))) {
-    content::RenderViewHost::AddCreatedCallback(rvh_callback_);
-  }
-
-  ~WebUIJsInjectionReadyObserver() {
-    content::RenderViewHost::RemoveCreatedCallback(rvh_callback_);
-  }
-
- private:
-  void RenderViewHostCreated(content::RenderViewHost* rvh) {
-    rvh_observer_.reset(
-        new RenderViewHostInitializedObserver(rvh, injection_observer_));
-  }
-
-  content::JsInjectionReadyObserver* injection_observer_;
-
-  scoped_ptr<RenderViewHostInitializedObserver> rvh_observer_;
-
-  content::RenderViewHost::CreatedCallback rvh_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebUIJsInjectionReadyObserver);
+  WebUIBrowserTest* browser_test_;
+  std::string preload_test_fixture_;
+  std::string preload_test_name_;
 };
 
 }  // namespace
@@ -268,9 +243,11 @@
 }
 
 void WebUIBrowserTest::BrowsePreload(const GURL& browse_to) {
-  WebUIJsInjectionReadyObserver injection_observer(this);
-  content::TestNavigationObserver navigation_observer(
-      browser()->tab_strip_model()->GetActiveWebContents());
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  WebUIJsInjectionReadyObserver injection_observer(
+      web_contents, this, preload_test_fixture_, preload_test_name_);
+  content::TestNavigationObserver navigation_observer(web_contents);
   chrome::NavigateParams params(browser(), GURL(browse_to),
                                 content::PAGE_TRANSITION_TYPED);
   params.disposition = CURRENT_TAB;
@@ -278,14 +255,61 @@
   navigation_observer.Wait();
 }
 
+#if defined(ENABLE_FULL_PRINTING)
+
+// This custom ContentBrowserClient is used to get notified when a WebContents
+// for the print preview dialog gets created.
+class PrintContentBrowserClient : public chrome::ChromeContentBrowserClient {
+ public:
+  PrintContentBrowserClient(WebUIBrowserTest* browser_test,
+                            const std::string& preload_test_fixture,
+                            const std::string& preload_test_name)
+      : browser_test_(browser_test),
+        preload_test_fixture_(preload_test_fixture),
+        preload_test_name_(preload_test_name),
+        preview_dialog_(NULL),
+        message_loop_runner_(new content::MessageLoopRunner) {}
+
+  void Wait() {
+    message_loop_runner_->Run();
+    content::WaitForLoadStop(preview_dialog_);
+  }
+
+ private:
+  // ChromeContentBrowserClient implementation:
+  virtual content::WebContentsViewPort* OverrideCreateWebContentsView(
+      content::WebContents* web_contents,
+      content::RenderViewHostDelegateView** view) OVERRIDE {
+    preview_dialog_ = web_contents;
+    observer_.reset(new WebUIJsInjectionReadyObserver(
+        preview_dialog_, browser_test_, preload_test_fixture_,
+        preload_test_name_));
+    message_loop_runner_->Quit();
+    return NULL;
+  }
+
+  WebUIBrowserTest* browser_test_;
+  scoped_ptr<WebUIJsInjectionReadyObserver> observer_;
+  std::string preload_test_fixture_;
+  std::string preload_test_name_;
+  content::WebContents* preview_dialog_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+};
+#endif
+
 void WebUIBrowserTest::BrowsePrintPreload(const GURL& browse_to) {
 #if defined(ENABLE_FULL_PRINTING)
   ui_test_utils::NavigateToURL(browser(), browse_to);
 
-  TestTabStripModelObserver tabstrip_observer(
-      browser()->tab_strip_model(), this);
+  PrintContentBrowserClient new_client(
+      this, preload_test_fixture_, preload_test_name_);
+  content::ContentBrowserClient* old_client =
+      SetBrowserClientForTesting(&new_client);
+
   chrome::Print(browser());
-  tabstrip_observer.Wait();
+  new_client.Wait();
+
+  SetBrowserClientForTesting(old_client);
 
   printing::PrintPreviewDialogController* tab_controller =
       printing::PrintPreviewDialogController::GetInstance();
@@ -437,11 +461,6 @@
   return net::FilePathToFileURL(test_path);
 }
 
-void WebUIBrowserTest::OnJsInjectionReady(RenderViewHost* render_view_host) {
-  PreLoadJavascriptLibraries(preload_test_fixture_, preload_test_name_,
-                             render_view_host);
-}
-
 void WebUIBrowserTest::BuildJavascriptLibraries(string16* content) {
   ASSERT_TRUE(content != NULL);
   std::string utf8_content;
diff --git a/chrome/test/base/web_ui_browsertest.h b/chrome/test/base/web_ui_browsertest.h
index 4dec52e..dfda661 100644
--- a/chrome/test/base/web_ui_browsertest.h
+++ b/chrome/test/base/web_ui_browsertest.h
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "content/public/test/js_injection_ready_observer.h"
 
 namespace base {
 class Value;
@@ -41,9 +40,7 @@
 // These tests should follow the form given in:
 // chrome/test/data/webui/sample_downloads.js.
 // and the lone test within this class.
-class WebUIBrowserTest
-    : public InProcessBrowserTest,
-      public content::JsInjectionReadyObserver {
+class WebUIBrowserTest : public InProcessBrowserTest {
  public:
   typedef ScopedVector<const base::Value> ConstValueVector;
   virtual ~WebUIBrowserTest();
@@ -140,10 +137,6 @@
   static GURL WebUITestDataPathToURL(const base::FilePath::StringType& path);
 
  private:
-  // content::JsInjectionReadyObserver implementation.
-  virtual void OnJsInjectionReady(
-      content::RenderViewHost* render_view_host) OVERRIDE;
-
   // Builds a string containing all added javascript libraries.
   void BuildJavascriptLibraries(string16* content);
 
diff --git a/chrome/test/chromedriver/VERSION b/chrome/test/chromedriver/VERSION
index 6b4950e..95e3ba8 100644
--- a/chrome/test/chromedriver/VERSION
+++ b/chrome/test/chromedriver/VERSION
@@ -1 +1 @@
-2.4
+2.5
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index b8e6e45..6e884c9 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -277,6 +277,8 @@
     parser_map["localState"] =
         base::Bind(&ParseDict, &capabilities->local_state);
     parser_map["logPath"] = base::Bind(&ParseLogPath);
+    parser_map["minidumpPath"] =
+        base::Bind(&ParseString, &capabilities->minidump_path);
     parser_map["prefs"] = base::Bind(&ParseDict, &capabilities->prefs);
   }
 
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h
index d23740e..c5f52cd 100644
--- a/chrome/test/chromedriver/capabilities.h
+++ b/chrome/test/chromedriver/capabilities.h
@@ -105,6 +105,9 @@
 
   LoggingPrefs logging_prefs;
 
+  // If set, enable minidump for chrome crashes and save to this directory.
+  std::string minidump_path;
+
   scoped_ptr<base::DictionaryValue> prefs;
 
   Switches switches;
diff --git a/chrome/test/chromedriver/chrome/chrome.h b/chrome/test/chromedriver/chrome/chrome.h
index 2433fad..4c8feac 100644
--- a/chrome/test/chromedriver/chrome/chrome.h
+++ b/chrome/test/chromedriver/chrome/chrome.h
@@ -8,7 +8,7 @@
 #include <list>
 #include <string>
 
-class AutomationExtension;
+class ChromeDesktopImpl;
 class Status;
 class WebView;
 
@@ -16,13 +16,7 @@
  public:
   virtual ~Chrome() {}
 
-  enum Type {
-    DESKTOP,
-    ANDROID,
-    EXISTING
-  };
-
-  virtual Type GetType() = 0;
+  virtual ChromeDesktopImpl* GetAsDesktop() = 0;
 
   virtual std::string GetVersion() = 0;
 
@@ -42,9 +36,6 @@
   // Activates the specified WebView.
   virtual Status ActivateWebView(const std::string& id) = 0;
 
-  // Gets the automation extension.
-  virtual Status GetAutomationExtension(AutomationExtension** extension) = 0;
-
   // Get the operation system where Chrome is running.
   virtual std::string GetOperatingSystemName() = 0;
 
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.cc b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
index 0bddb4a..41da0a0 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
@@ -21,10 +21,6 @@
 
 ChromeAndroidImpl::~ChromeAndroidImpl() {}
 
-Chrome::Type ChromeAndroidImpl::GetType() {
-  return ANDROID;
-}
-
 std::string ChromeAndroidImpl::GetOperatingSystemName() {
   return "ANDROID";
 }
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.h b/chrome/test/chromedriver/chrome/chrome_android_impl.h
index 43ed71a..39da9da 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.h
@@ -24,7 +24,6 @@
   virtual ~ChromeAndroidImpl();
 
   // Overridden from Chrome:
-  virtual Type GetType() OVERRIDE;
   virtual std::string GetOperatingSystemName() OVERRIDE;
 
   // Overridden from ChromeImpl:
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
index 717e43f..3982f9c 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -66,12 +66,14 @@
     ScopedVector<DevToolsEventListener>& devtools_event_listeners,
     scoped_ptr<PortReservation> port_reservation,
     base::ProcessHandle process,
+    const CommandLine& command,
     base::ScopedTempDir* user_data_dir,
     base::ScopedTempDir* extension_dir)
     : ChromeImpl(client.Pass(),
                  devtools_event_listeners,
                  port_reservation.Pass()),
-      process_(process) {
+      process_(process),
+      command_(command) {
   if (user_data_dir->IsValid())
     CHECK(user_data_dir_.Set(user_data_dir->Take()));
   if (extension_dir->IsValid())
@@ -125,10 +127,6 @@
   return status;
 }
 
-Chrome::Type ChromeDesktopImpl::GetType() {
-  return DESKTOP;
-}
-
 Status ChromeDesktopImpl::GetAutomationExtension(
     AutomationExtension** extension) {
   if (!automation_extension_) {
@@ -147,6 +145,10 @@
   return Status(kOk);
 }
 
+ChromeDesktopImpl* ChromeDesktopImpl::GetAsDesktop() {
+  return this;
+}
+
 std::string ChromeDesktopImpl::GetOperatingSystemName() {
   return base::SysInfo::OperatingSystemName();
 }
@@ -156,3 +158,7 @@
     return Status(kUnknownError, "cannot kill Chrome");
   return Status(kOk);
 }
+
+const CommandLine& ChromeDesktopImpl::command() const {
+  return command_;
+}
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
index ab4e393..f9c2ab6 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
@@ -29,6 +30,7 @@
       ScopedVector<DevToolsEventListener>& devtools_event_listeners,
       scoped_ptr<PortReservation> port_reservation,
       base::ProcessHandle process,
+      const CommandLine& command,
       base::ScopedTempDir* user_data_dir,
       base::ScopedTempDir* extension_dir);
   virtual ~ChromeDesktopImpl();
@@ -39,17 +41,21 @@
                            const base::TimeDelta& timeout,
                            scoped_ptr<WebView>* web_view);
 
+  // Gets the installed automation extension.
+  Status GetAutomationExtension(AutomationExtension** extension);
+
   // Overridden from Chrome:
-  virtual Type GetType() OVERRIDE;
-  virtual Status GetAutomationExtension(
-      AutomationExtension** extension) OVERRIDE;
+  virtual ChromeDesktopImpl* GetAsDesktop() OVERRIDE;
   virtual std::string GetOperatingSystemName() OVERRIDE;
 
   // Overridden from ChromeImpl:
   virtual Status QuitImpl() OVERRIDE;
 
+  const CommandLine& command() const;
+
  private:
   base::ProcessHandle process_;
+  CommandLine command_;
   base::ScopedTempDir user_data_dir_;
   base::ScopedTempDir extension_dir_;
 
diff --git a/chrome/test/chromedriver/chrome/chrome_existing_impl.cc b/chrome/test/chromedriver/chrome/chrome_existing_impl.cc
index af23106..b4a3387 100644
--- a/chrome/test/chromedriver/chrome/chrome_existing_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_existing_impl.cc
@@ -16,10 +16,6 @@
 
 ChromeExistingImpl::~ChromeExistingImpl() {}
 
-Chrome::Type ChromeExistingImpl::GetType() {
-  return EXISTING;
-}
-
 std::string ChromeExistingImpl::GetOperatingSystemName() {
  return std::string();
 }
diff --git a/chrome/test/chromedriver/chrome/chrome_existing_impl.h b/chrome/test/chromedriver/chrome/chrome_existing_impl.h
index 2a04e50..284f6b7 100644
--- a/chrome/test/chromedriver/chrome/chrome_existing_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_existing_impl.h
@@ -21,7 +21,6 @@
   virtual ~ChromeExistingImpl();
 
   // Overridden from Chrome.
-  virtual Type GetType() OVERRIDE;
   virtual std::string GetOperatingSystemName() OVERRIDE;
 
   // Overridden from ChromeImpl.
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index 772e1e3..f293899 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -16,6 +16,10 @@
     port_reservation_->Leak();
 }
 
+ChromeDesktopImpl* ChromeImpl::GetAsDesktop() {
+  return NULL;
+}
+
 std::string ChromeImpl::GetVersion() {
   return devtools_http_client_->version();
 }
@@ -115,10 +119,6 @@
   return devtools_http_client_->ActivateWebView(id);
 }
 
-Status ChromeImpl::GetAutomationExtension(AutomationExtension** extension) {
-  return Status(kUnknownError, "automation extension not supported");
-}
-
 Status ChromeImpl::Quit() {
   Status status = QuitImpl();
   if (status.IsOk())
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h
index ce23ed2..792d48f 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -29,6 +29,7 @@
 
   // Overridden from Chrome:
   virtual std::string GetVersion() OVERRIDE;
+  virtual ChromeDesktopImpl* GetAsDesktop() OVERRIDE;
   virtual int GetBuildNo() OVERRIDE;
   virtual bool HasCrashedWebView() OVERRIDE;
   virtual Status GetWebViewIds(std::list<std::string>* web_view_ids) OVERRIDE;
@@ -36,8 +37,6 @@
                                 WebView** web_view) OVERRIDE;
   virtual Status CloseWebView(const std::string& id) OVERRIDE;
   virtual Status ActivateWebView(const std::string& id) OVERRIDE;
-  virtual Status GetAutomationExtension(
-      AutomationExtension** extension) OVERRIDE;
   virtual Status Quit() OVERRIDE;
 
  protected:
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.cc b/chrome/test/chromedriver/chrome/devtools_http_client.cc
index f2b2d1c..7afafce 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.cc
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.cc
@@ -302,22 +302,29 @@
     std::string id;
     if (!info->GetString("id", &id))
       return Status(kUnknownError, "DevTools did not include id");
-    std::string type;
-    if (!info->GetString("type", &type))
+    std::string type_as_string;
+    if (!info->GetString("type", &type_as_string))
       return Status(kUnknownError, "DevTools did not include type");
     std::string url;
     if (!info->GetString("url", &url))
       return Status(kUnknownError, "DevTools did not include url");
     std::string debugger_url;
     info->GetString("webSocketDebuggerUrl", &debugger_url);
-    if (type == "page")
-      temp_views_info.push_back(
-          WebViewInfo(id, debugger_url, url, WebViewInfo::kPage));
-    else if (type == "other")
-      temp_views_info.push_back(
-          WebViewInfo(id, debugger_url, url, WebViewInfo::kOther));
+    WebViewInfo::Type type;
+    if (type_as_string == "app")
+      type = WebViewInfo::kApp;
+    else if (type_as_string == "background_page")
+      type = WebViewInfo::kBackgroundPage;
+    else if (type_as_string == "page")
+      type = WebViewInfo::kPage;
+    else if (type_as_string == "worker")
+      type = WebViewInfo::kWorker;
+    else if (type_as_string == "other")
+      type = WebViewInfo::kOther;
     else
-      return Status(kUnknownError, "DevTools returned unknown type:" + type);
+      return Status(kUnknownError,
+                    "DevTools returned unknown type:" + type_as_string);
+    temp_views_info.push_back(WebViewInfo(id, debugger_url, url, type));
   }
   *views_info = WebViewsInfo(temp_views_info);
   return Status(kOk);
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.h b/chrome/test/chromedriver/chrome/devtools_http_client.h
index 7dbb537..282adcc 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.h
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.h
@@ -23,7 +23,10 @@
 
 struct WebViewInfo {
   enum Type {
+    kApp,
+    kBackgroundPage,
     kPage,
+    kWorker,
     kOther
   };
 
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client_unittest.cc b/chrome/test/chromedriver/chrome/devtools_http_client_unittest.cc
index c92abb8..673a817 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_http_client_unittest.cc
@@ -70,6 +70,17 @@
 
 namespace {
 
+void AssertTypeIsOk(const std::string& type_as_string, WebViewInfo::Type type) {
+  WebViewsInfo views_info;
+  std::string data = "[{\"type\": \"" + type_as_string
+      + "\", \"id\": \"1\", \"url\": \"http://page1\"}]";
+  Status status = internal::ParseWebViewsInfo(data, &views_info);
+  ASSERT_TRUE(status.IsOk());
+  ASSERT_EQ(1u, views_info.GetSize());
+  ExpectEqual(WebViewInfo("1", std::string(), "http://page1", type),
+              views_info.Get(0));
+}
+
 void AssertFails(const std::string& data) {
   WebViewsInfo views_info;
   Status status = internal::ParseWebViewsInfo(data, &views_info);
@@ -79,6 +90,15 @@
 
 }  // namespace
 
+TEST(ParseWebViewsInfo, Types) {
+  AssertTypeIsOk("app", WebViewInfo::kApp);
+  AssertTypeIsOk("background_page", WebViewInfo::kBackgroundPage);
+  AssertTypeIsOk("page", WebViewInfo::kPage);
+  AssertTypeIsOk("worker", WebViewInfo::kWorker);
+  AssertTypeIsOk("other", WebViewInfo::kOther);
+  AssertFails("[{\"type\": \"\", \"id\": \"1\", \"url\": \"http://page1\"}]");
+}
+
 TEST(ParseWebViewsInfo, NonList) {
   AssertFails("{\"id\": \"1\"}");
 }
diff --git a/chrome/test/chromedriver/chrome/stub_chrome.cc b/chrome/test/chromedriver/chrome/stub_chrome.cc
index 7e5888b..97de39e 100644
--- a/chrome/test/chromedriver/chrome/stub_chrome.cc
+++ b/chrome/test/chromedriver/chrome/stub_chrome.cc
@@ -10,8 +10,8 @@
 
 StubChrome::~StubChrome() {}
 
-Chrome::Type StubChrome::GetType() {
-  return DESKTOP;
+ChromeDesktopImpl* StubChrome::GetAsDesktop() {
+  return NULL;
 }
 
 std::string StubChrome::GetVersion() {
@@ -42,10 +42,6 @@
   return Status(kOk);
 }
 
-Status StubChrome::GetAutomationExtension(AutomationExtension** extension) {
-  return Status(kOk);
-}
-
 std::string StubChrome::GetOperatingSystemName() {
   return std::string();
 }
diff --git a/chrome/test/chromedriver/chrome/stub_chrome.h b/chrome/test/chromedriver/chrome/stub_chrome.h
index af0bd06..ddd38be 100644
--- a/chrome/test/chromedriver/chrome/stub_chrome.h
+++ b/chrome/test/chromedriver/chrome/stub_chrome.h
@@ -19,7 +19,7 @@
   virtual ~StubChrome();
 
   // Overridden from Chrome:
-  virtual Type GetType() OVERRIDE;
+  virtual ChromeDesktopImpl* GetAsDesktop() OVERRIDE;
   virtual std::string GetVersion() OVERRIDE;
   virtual int GetBuildNo() OVERRIDE;
   virtual bool HasCrashedWebView() OVERRIDE;
@@ -28,8 +28,6 @@
                                 WebView** web_view) OVERRIDE;
   virtual Status CloseWebView(const std::string& id) OVERRIDE;
   virtual Status ActivateWebView(const std::string& id) OVERRIDE;
-  virtual Status GetAutomationExtension(
-      AutomationExtension** extension) OVERRIDE;
   virtual std::string GetOperatingSystemName() OVERRIDE;
   virtual Status Quit() OVERRIDE;
 };
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 09cef68..5db4d31 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -46,6 +46,10 @@
 const char* kCommonSwitches[] = {
     "ignore-certificate-errors", "metrics-recording-only"};
 
+#if defined(OS_LINUX)
+const char* kEnableCrashReport = "enable-crash-reporter-for-testing";
+#endif
+
 Status UnpackAutomationExtension(const base::FilePath& temp_dir,
                                  base::FilePath* automation_extension) {
   std::string decoded_extension;
@@ -217,6 +221,20 @@
 
   base::LaunchOptions options;
 
+#if defined(OS_LINUX)
+  // If minidump path is set in the capability, enable minidump for crashes.
+  if (!capabilities.minidump_path.empty()) {
+    VLOG(0) << "Minidump generation specified. Will save dumps to: "
+            << capabilities.minidump_path;
+
+    options.environ["CHROME_HEADLESS"] = 1;
+    options.environ["BREAKPAD_DUMP_LOCATION"] = capabilities.minidump_path;
+
+    if (!command.HasSwitch(kEnableCrashReport))
+      command.AppendSwitch(kEnableCrashReport);
+  }
+#endif
+
 #if !defined(OS_WIN)
   if (!capabilities.log_path.empty())
     options.environ["CHROME_LOG_FILE"] = capabilities.log_path;
@@ -277,6 +295,7 @@
                             devtools_event_listeners,
                             port_reservation.Pass(),
                             process,
+                            command,
                             &user_data_dir,
                             &extension_dir));
   for (size_t i = 0; i < extension_bg_pages.size(); ++i) {
diff --git a/chrome/test/chromedriver/run_buildbot_steps.py b/chrome/test/chromedriver/run_buildbot_steps.py
index 7bfdeca..4447fdf 100755
--- a/chrome/test/chromedriver/run_buildbot_steps.py
+++ b/chrome/test/chromedriver/run_buildbot_steps.py
@@ -8,6 +8,7 @@
 import bisect
 import csv
 import datetime
+import glob
 import json
 import optparse
 import os
@@ -30,6 +31,7 @@
 GS_CHROMEDRIVER_DATA_BUCKET = 'gs://chromedriver-data'
 GS_CONTINUOUS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/continuous'
 GS_PREBUILTS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/prebuilts'
+GS_SERVER_LOGS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/server_logs'
 TEST_LOG_FORMAT = '%s_log.json'
 
 SCRIPT_DIR = os.path.join(_THIS_DIR, os.pardir, os.pardir, os.pardir, os.pardir,
@@ -54,6 +56,16 @@
     util.MarkBuildStepError()
 
 
+def _ArchiveServerLogs():
+  """Uploads chromedriver server logs to google storage."""
+  util.MarkBuildStepStart('archive chromedriver server logs')
+  for server_log in glob.glob(os.path.join(tempfile.gettempdir(),
+                                           'chromedriver_*')):
+    slave_utils.GSUtilCopy(
+        server_log, '%s/%s' % (GS_SERVER_LOGS_URL,
+                               os.path.basename(server_log)))
+
+
 def _DownloadPrebuilts():
   """Downloads the most recent prebuilts from google storage."""
   util.MarkBuildStepStart('Download latest chromedriver')
@@ -354,6 +366,8 @@
 
   passed = (util.RunCommand(cmd) == 0)
 
+  _ArchiveServerLogs()
+
   if platform == 'android':
     if options.update_log:
       util.MarkBuildStepStart('update test result log')
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 0ea5cef..4a21932 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -179,6 +179,10 @@
           kGet,
           "session/:sessionId/screenshot",
           WrapToCommand("Screenshot", base::Bind(&ExecuteScreenshot))),
+      CommandMapping(
+          kGet,
+          "session/:sessionId/chromium/heap_snapshot",
+          WrapToCommand("HeapSnapshot", base::Bind(&ExecuteTakeHeapSnapshot))),
       CommandMapping(kPost,
                      "session/:sessionId/visible",
                      base::Bind(&UnimplementedCommand)),
diff --git a/chrome/test/chromedriver/server/server.py b/chrome/test/chromedriver/server/server.py
index 655aac3..5a1a440 100644
--- a/chrome/test/chromedriver/server/server.py
+++ b/chrome/test/chromedriver/server/server.py
@@ -13,11 +13,12 @@
 class Server(object):
   """A running ChromeDriver server."""
 
-  def __init__(self, exe_path):
+  def __init__(self, exe_path, log_path=None):
     """Starts the ChromeDriver server and waits for it to be ready.
 
     Args:
       exe_path: path to the ChromeDriver executable
+      log_path: path to the log file
     Raises:
       RuntimeError if ChromeDriver fails to start
     """
@@ -26,6 +27,8 @@
 
     port = self._FindOpenPort()
     chromedriver_args = [exe_path, '--port=%d' % port]
+    if log_path:
+      chromedriver_args.append('--log-path=%s' % log_path)
     self._process = subprocess.Popen(chromedriver_args)
     self._url = 'http://127.0.0.1:%d' % port
     if self._process is None:
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index e5c1d46..85809f6 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -76,6 +76,7 @@
   caps->SetString("platform", chrome->GetOperatingSystemName());
   caps->SetBoolean("javascriptEnabled", true);
   caps->SetBoolean("takesScreenshot", true);
+  caps->SetBoolean("takesHeapSnapshot", true);
   caps->SetBoolean("handlesAlerts", true);
   caps->SetBoolean("databaseEnabled", false);
   caps->SetBoolean("locationContextEnabled", true);
@@ -86,6 +87,14 @@
   caps->SetBoolean("rotatable", false);
   caps->SetBoolean("acceptSslCerts", true);
   caps->SetBoolean("nativeEvents", true);
+  scoped_ptr<base::DictionaryValue> chrome_caps(new base::DictionaryValue());
+  if (chrome->GetAsDesktop()) {
+    chrome_caps->SetString(
+        "userDataDir",
+        chrome->GetAsDesktop()->command().GetSwitchValueNative(
+            "user-data-dir"));
+  }
+  caps->Set("chrome", chrome_caps.release());
   return caps.Pass();
 }
 
@@ -413,8 +422,15 @@
     Session* session,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
+  ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
+  if (!desktop) {
+    return Status(
+        kUnknownError,
+        "command only supported for desktop Chrome without debuggerAddress");
+  }
+
   AutomationExtension* extension = NULL;
-  Status status = session->chrome->GetAutomationExtension(&extension);
+  Status status = desktop->GetAutomationExtension(&extension);
   if (status.IsError())
     return status;
 
@@ -437,8 +453,16 @@
   double x, y;
   if (!params.GetDouble("x", &x) || !params.GetDouble("y", &y))
     return Status(kUnknownError, "missing or invalid 'x' or 'y'");
+
+  ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
+  if (!desktop) {
+    return Status(
+        kUnknownError,
+        "command only supported for desktop Chrome without debuggerAddress");
+  }
+
   AutomationExtension* extension = NULL;
-  Status status = session->chrome->GetAutomationExtension(&extension);
+  Status status = desktop->GetAutomationExtension(&extension);
   if (status.IsError())
     return status;
 
@@ -449,8 +473,15 @@
     Session* session,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
+  ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
+  if (!desktop) {
+    return Status(
+        kUnknownError,
+        "command only supported for desktop Chrome without debuggerAddress");
+  }
+
   AutomationExtension* extension = NULL;
-  Status status = session->chrome->GetAutomationExtension(&extension);
+  Status status = desktop->GetAutomationExtension(&extension);
   if (status.IsError())
     return status;
 
@@ -474,8 +505,16 @@
   if (!params.GetDouble("width", &width) ||
       !params.GetDouble("height", &height))
     return Status(kUnknownError, "missing or invalid 'width' or 'height'");
+
+  ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
+  if (!desktop) {
+    return Status(
+        kUnknownError,
+        "command only supported for desktop Chrome without debuggerAddress");
+  }
+
   AutomationExtension* extension = NULL;
-  Status status = session->chrome->GetAutomationExtension(&extension);
+  Status status = desktop->GetAutomationExtension(&extension);
   if (status.IsError())
     return status;
 
@@ -487,8 +526,15 @@
     Session* session,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
+  ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
+  if (!desktop) {
+    return Status(
+        kUnknownError,
+        "command only supported for desktop Chrome without debuggerAddress");
+  }
+
   AutomationExtension* extension = NULL;
-  Status status = session->chrome->GetAutomationExtension(&extension);
+  Status status = desktop->GetAutomationExtension(&extension);
   if (status.IsError())
     return status;
 
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index 7da52fa..ee8e1c7 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -9,6 +9,7 @@
 import os
 import platform
 import sys
+import tempfile
 
 _THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, os.path.join(_THIS_DIR, os.pardir))
@@ -46,15 +47,20 @@
                          chrome_version=None,
                          android_package=None,
                          verbose=False):
+  _, log_path = tempfile.mkstemp(prefix='chromedriver_')
+  print 'chromedriver server log: %s' % log_path
   cmd = [
       sys.executable,
       os.path.join(_THIS_DIR, script),
-      '--chromedriver=' + chromedriver,
+      '--chromedriver=%s' % chromedriver,
+      '--log-path=%s' % log_path,
   ]
   if ref_chromedriver:
     cmd.append('--reference-chromedriver=' + ref_chromedriver)
+
   if chrome:
     cmd.append('--chrome=' + chrome)
+
   if chrome_version:
     cmd.append('--chrome-version=' + chrome_version)
 
@@ -62,7 +68,7 @@
     cmd.append('--verbose')
 
   if android_package:
-    cmd.insert(0, 'xvfb-run')
+    cmd = ['xvfb-run', '-a'] + cmd
     cmd.append('--android-package=' + android_package)
   return cmd
 
diff --git a/chrome/test/chromedriver/test/run_java_tests.py b/chrome/test/chromedriver/test/run_java_tests.py
index 5b7b3be..7ed8524 100755
--- a/chrome/test/chromedriver/test/run_java_tests.py
+++ b/chrome/test/chromedriver/test/run_java_tests.py
@@ -58,7 +58,7 @@
 
 
 def _Run(java_tests_src_dir, test_filter,
-         chromedriver_path, chrome_path, android_package,
+         chromedriver_path, chrome_path, log_path, android_package,
          verbose, debug):
   """Run the WebDriver Java tests and return the test results.
 
@@ -68,6 +68,7 @@
         as Google C++ Test format.
     chromedriver_path: path to ChromeDriver exe.
     chrome_path: path to Chrome exe.
+    log_path: path to server log.
     android_package: name of Chrome's Android package.
     verbose: whether the output should be verbose.
     debug: whether the tests should wait until attached by a debugger.
@@ -94,9 +95,11 @@
 
   sys_props = ['selenium.browser=chrome',
                'webdriver.chrome.driver=' + os.path.abspath(chromedriver_path)]
-  if chrome_path is not None:
+  if chrome_path:
     sys_props += ['webdriver.chrome.binary=' + os.path.abspath(chrome_path)]
-  if android_package is not None:
+  if log_path:
+    sys_props += ['webdriver.chrome.logfile=' + log_path]
+  if android_package:
     sys_props += ['webdriver.chrome.android_package=' + android_package]
   if test_filter:
     # Test jar actually takes a regex. Convert from glob.
@@ -233,6 +236,9 @@
       '', '--chrome', type='string', default=None,
       help='Path to a build of the chrome binary')
   parser.add_option(
+      '', '--log-path',
+      help='Output verbose server logs to this file')
+  parser.add_option(
       '', '--chrome-version', default='HEAD',
       help='Version of chrome. Default is \'HEAD\'')
   parser.add_option(
@@ -302,6 +308,7 @@
           test_filter=filter,
           chromedriver_path=options.chromedriver,
           chrome_path=options.chrome,
+          log_path=options.log_path,
           android_package=options.android_package,
           verbose=options.verbose,
           debug=options.debug)
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index dd38b4b..97a10a7 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -814,6 +814,9 @@
       '', '--chromedriver',
       help='Path to chromedriver server (REQUIRED!)')
   parser.add_option(
+      '', '--log-path',
+      help='Output verbose server logs to this file')
+  parser.add_option(
       '', '--reference-chromedriver',
       help='Path to the reference chromedriver server')
   parser.add_option(
@@ -833,7 +836,8 @@
     parser.error('chromedriver is required or the given path is invalid.' +
                  'Please run "%s --help" for help' % __file__)
 
-  chromedriver_server = server.Server(os.path.abspath(options.chromedriver))
+  chromedriver_server = server.Server(os.path.abspath(options.chromedriver),
+                                      options.log_path)
   global _CHROMEDRIVER_SERVER_URL
   _CHROMEDRIVER_SERVER_URL = chromedriver_server.GetUrl()
 
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 28ed9fc..9610e60 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -48,8 +48,6 @@
     'ExecutingJavascriptTest.testShouldThrowAnExceptionWithMessageAndStacktraceWhenTheJavascriptIsBad',
     'FormHandlingTest.testShouldNotBeAbleToSubmitAFormThatDoesNotExist',
     'FrameSwitchingTest.testShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs',
-    # Disabled until https://code.google.com/p/chromedriver/issues/detail?id=345 is fixed.
-    'I18nTest.*',
     'I18nTest.testShouldBeAbleToActivateIMEEngine',
     # Broken because AddWebStorage.java is broken.
     'LocalStorageTest.*',
@@ -86,21 +84,12 @@
     'VisibilityTest.testElementHiddenByOverflowYIsNotVisible',
     'VisibilityTest.tooSmallAWindowWithOverflowHiddenIsNotAProblem',
     'WindowTest.*',
-    # https://code.google.com/p/chromedriver/issues/detail?id=412
-    'ClickTest.testCanClickOnAnElementWithTopSetToANegativeNumber',
-    'ClickTest.testShouldBeAbleToClickOnAnElementInTheViewport',
-    'ExecutingAsyncJavascriptTest.shouldBeAbleToExecuteAsynchronousScripts',
-    'FormHandlingTest.testShouldClickOnSubmitInputElements',
-    'FrameSwitchingTest.testShouldBeAbleToClickInAFrame',
-    'FrameSwitchingTest.testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUs',
-    'FrameSwitchingTest.testShouldAllowTheUserToSwitchToAnIFrameAndRemainFocusedOnIt',
-    'FrameSwitchingTest.testShouldBeAbleToClickInASubFrame',
-    'FrameSwitchingTest.testShouldNotSwitchMagicallyToTheTopWindow',
-    'ImplicitWaitTest.testShouldImplicitlyWaitUntilAtLeastOneElementIsFoundWhenSearchingForMany',
-    'ImplicitWaitTest.testShouldImplicitlyWaitForAnElementToBeVisibleBeforeInteracting',
-    'ImplicitWaitTest.testShouldReturnAfterFirstAttemptToFindManyAfterDisablingImplicitWaits',
-    'ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement',
-    'XPathElementFindingTest.testShouldBeAbleToSearchForMultipleAttributes',
+]
+_REVISION_NEGATIVE_FILTER['31'] = _REVISION_NEGATIVE_FILTER['HEAD'] + [
+    'I18nTest.*',  # This was fixed in a later version of 31 than we use.
+]
+_REVISION_NEGATIVE_FILTER['30'] = _REVISION_NEGATIVE_FILTER['HEAD'] + [
+    'I18nTest.*',
 ]
 
 
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index d7195f6..266361b 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -16,6 +16,7 @@
 #include "chrome/test/chromedriver/basic_types.h"
 #include "chrome/test/chromedriver/chrome/automation_extension.h"
 #include "chrome/test/chromedriver/chrome/chrome.h"
+#include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 #include "chrome/test/chromedriver/chrome/geoposition.h"
 #include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
@@ -739,10 +740,10 @@
     return status;
 
   std::string screenshot;
-  if (session->chrome->GetType() == Chrome::DESKTOP &&
-      !session->force_devtools_screenshot) {
+  if (session->chrome->GetAsDesktop() && !session->force_devtools_screenshot) {
     AutomationExtension* extension = NULL;
-    status = session->chrome->GetAutomationExtension(&extension);
+    status =
+        session->chrome->GetAsDesktop()->GetAutomationExtension(&extension);
     if (status.IsError())
       return status;
     status = extension->CaptureScreenshot(&screenshot);
@@ -862,3 +863,11 @@
     session->overridden_geoposition.reset(new Geoposition(geoposition));
   return status;
 }
+
+Status ExecuteTakeHeapSnapshot(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value) {
+  return web_view->TakeHeapSnapshot(value);
+}
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index 0178136..4e97ac9 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -283,4 +283,10 @@
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value);
 
+Status ExecuteTakeHeapSnapshot(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value);
+
 #endif  // CHROME_TEST_CHROMEDRIVER_WINDOW_COMMANDS_H_
diff --git a/chrome/test/functional/ispy/client/boto_bucket.py b/chrome/test/functional/ispy/client/boto_bucket.py
index 4b7d15e..df0cd1c 100644
--- a/chrome/test/functional/ispy/client/boto_bucket.py
+++ b/chrome/test/functional/ispy/client/boto_bucket.py
@@ -1,5 +1,8 @@
 # Copyright 2013 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.  """Implementation of CloudBucket using Google Cloud Storage as the backend."""
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Implementation of CloudBucket using Google Cloud Storage as the backend."""
 import os
 import sys
 
@@ -9,7 +12,7 @@
                              'depot_tools', 'third_party'))
 import boto
 
-from common import cloud_bucket
+from ..common import cloud_bucket
 
 
 class BotoCloudBucket(cloud_bucket.BaseCloudBucket):
diff --git a/chrome/test/functional/ispy/server/debug_view_handler.py b/chrome/test/functional/ispy/server/debug_view_handler.py
index 96bfe3c..4d5f740 100644
--- a/chrome/test/functional/ispy/server/debug_view_handler.py
+++ b/chrome/test/functional/ispy/server/debug_view_handler.py
@@ -9,7 +9,7 @@
 import sys
 import webapp2
 
-from common import ispy_utils
+from ..common import ispy_utils
 
 import views
 
diff --git a/chrome/test/functional/ispy/server/gs_bucket.py b/chrome/test/functional/ispy/server/gs_bucket.py
index a132f05..e73dcef 100644
--- a/chrome/test/functional/ispy/server/gs_bucket.py
+++ b/chrome/test/functional/ispy/server/gs_bucket.py
@@ -8,7 +8,7 @@
 
 import cloudstorage
 
-from common import cloud_bucket
+from ..common import cloud_bucket
 
 
 class GoogleCloudStorageBucket(cloud_bucket.BaseCloudBucket):
diff --git a/chrome/test/functional/ispy/server/image_handler.py b/chrome/test/functional/ispy/server/image_handler.py
index d1f11f2..f23f41f 100644
--- a/chrome/test/functional/ispy/server/image_handler.py
+++ b/chrome/test/functional/ispy/server/image_handler.py
@@ -9,8 +9,8 @@
 import sys
 import webapp2
 
-from common import cloud_bucket
-from common import constants
+from ..common import cloud_bucket
+from ..common import constants
 
 import gs_bucket
 
diff --git a/chrome/test/functional/ispy/server/main_view_handler.py b/chrome/test/functional/ispy/server/main_view_handler.py
index 4b3ec10..f6c2c72 100644
--- a/chrome/test/functional/ispy/server/main_view_handler.py
+++ b/chrome/test/functional/ispy/server/main_view_handler.py
@@ -11,8 +11,8 @@
 import sys
 import webapp2
 
-from common import constants
-from common import ispy_utils
+from ..common import constants
+from ..common import ispy_utils
 
 import gs_bucket
 import views
diff --git a/chrome/test/functional/ispy/server/update_mask_handler.py b/chrome/test/functional/ispy/server/update_mask_handler.py
index 4a2a2da..bf66e77 100644
--- a/chrome/test/functional/ispy/server/update_mask_handler.py
+++ b/chrome/test/functional/ispy/server/update_mask_handler.py
@@ -9,9 +9,9 @@
 import sys
 import os
 
-from common import constants
-from common import image_tools
-from common import ispy_utils
+from ..common import constants
+from ..common import image_tools
+from ..common import ispy_utils
 
 import gs_bucket
 
diff --git a/chrome/test/functional/prefs.py b/chrome/test/functional/prefs.py
index 9a82de9..7dc95ae 100755
--- a/chrome/test/functional/prefs.py
+++ b/chrome/test/functional/prefs.py
@@ -85,24 +85,6 @@
     self.ActivateTab(1)
     self.assertEqual(url2, self.GetActiveTabURL().spec())
 
-  def testHomepagePrefs(self):
-    """Verify homepage prefs."""
-    # "Use the New Tab page"
-    self.SetPrefs(pyauto.kHomePageIsNewTabPage, True)
-    logging.debug('Setting %s to 1' % pyauto.kHomePageIsNewTabPage)
-    self.RestartBrowser(clear_profile=False)
-    self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kHomePageIsNewTabPage),
-                     True)
-    # "Open this page"
-    url = self.GetFileURLForPath(os.path.join(self.DataDir(), 'title1.html'))
-    self.SetPrefs(pyauto.kHomePage, url)
-    self.SetPrefs(pyauto.kHomePageIsNewTabPage, False)
-    self.RestartBrowser(clear_profile=False)
-    self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kHomePage), url)
-    self.assertFalse(self.GetPrefsInfo().Prefs(pyauto.kHomePageIsNewTabPage))
-    # TODO(nirnimesh): Actually verify that homepage loads.
-    # This requires telling pyauto *not* to set about:blank as homepage.
-
   def testGeolocationPref(self):
     """Verify geolocation pref.
 
@@ -132,24 +114,6 @@
         behavior, Behaviors.BLOCK,
         msg='Behavior is "%s" when it should be BLOCKED.'  % behavior)
 
-  def testUnderTheHoodPref(self):
-    """Verify the security preferences for Under the Hood.
-    The setting is enabled by default."""
-    pref_list = [pyauto.kNetworkPredictionEnabled, pyauto.kSafeBrowsingEnabled,
-                 pyauto.kAlternateErrorPagesEnabled,
-                 pyauto.kSearchSuggestEnabled]
-    for pref in pref_list:
-      # Verify the default value
-      self.assertEqual(self.GetPrefsInfo().Prefs(pref), True)
-      self.SetPrefs(pref, False)
-    self.RestartBrowser(clear_profile=False)
-    for pref in pref_list:
-      self.assertEqual(self.GetPrefsInfo().Prefs(pref), False)
-
-  def testHaveLocalStatePrefs(self):
-    """Verify that we have some Local State prefs."""
-    self.assertTrue(self.GetLocalStatePrefsInfo())
-
   def testAllowSelectedGeoTracking(self):
     """Verify hostname pattern and behavior for allowed tracking."""
     # Default location tracking option "Ask me".
@@ -227,14 +191,6 @@
     """
     return self.ExecuteJavascript(script, windex=windex, tab_index=tab_index)
 
-  def testImagesNotBlockedInIncognito(self):
-    """Verify images are not blocked in Incognito mode."""
-    url = self.GetHttpURLForDataPath('settings', 'image_page.html')
-    self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
-    self.NavigateToURL(url, 1, 0)
-    self.assertTrue(self._CheckForVisibleImage(windex=1),
-                    msg='No visible images found in Incognito mode.')
-
   def testBlockImagesForHostname(self):
     """Verify images blocked for defined hostname pattern."""
     url = 'http://www.google.com'
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 66524df..f465305 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -849,7 +849,13 @@
       LIST_TEST(FileIO_Mmap)
   );
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, FileIO) {
+// Flaky on XP; times out, http://crbug.com/313205
+#if defined(OS_WIN)
+#define MAYBE_FileIO DISABLED_FileIO
+#else
+#define MAYBE_FileIO FileIO
+#endif
+IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_FileIO) {
   RunTestViaHTTP(
       LIST_TEST(FileIO_Open)
       LIST_TEST(FileIO_AbortCalls)
diff --git a/chrome/test/remoting/me2me_browsertest.cc b/chrome/test/remoting/me2me_browsertest.cc
index 7cfdda7..1cdeb58 100644
--- a/chrome/test/remoting/me2me_browsertest.cc
+++ b/chrome/test/remoting/me2me_browsertest.cc
@@ -13,52 +13,66 @@
  protected:
   void TestKeyboardInput();
   void TestMouseInput();
+
+  void ConnectPinlessAndCleanupPairings(bool cleanup_all);
+  bool IsPairingSpinnerHidden();
 };
 
 IN_PROC_BROWSER_TEST_F(Me2MeBrowserTest,
                        MANUAL_Me2Me_Connect_Local_Host) {
   VerifyInternetAccess();
-
   Install();
-
   LaunchChromotingApp();
 
   // Authorize, Authenticate, and Approve.
   Auth();
+  ExpandMe2Me();
 
-  StartMe2Me();
-
-  ConnectToLocalHost();
+  ConnectToLocalHost(false);
 
   TestKeyboardInput();
-
   TestMouseInput();
 
   DisconnectMe2Me();
-
   Cleanup();
 }
 
 IN_PROC_BROWSER_TEST_F(Me2MeBrowserTest,
                        MANUAL_Me2Me_Connect_Remote_Host) {
   VerifyInternetAccess();
-
   Install();
-
   LaunchChromotingApp();
 
   // Authorize, Authenticate, and Approve.
   Auth();
+  ExpandMe2Me();
 
-  StartMe2Me();
-
-  ConnectToRemoteHost(remote_host_name());
+  ConnectToRemoteHost(remote_host_name(), false);
 
   // TODO(weitaosu): Find a way to verify keyboard input injection.
   // We cannot use TestKeyboardInput because it assumes
   // that the client and the host are on the same machine.
 
   DisconnectMe2Me();
+  Cleanup();
+}
+
+IN_PROC_BROWSER_TEST_F(Me2MeBrowserTest,
+                       MANUAL_Me2Me_Connect_Pinless) {
+  VerifyInternetAccess();
+  Install();
+  LaunchChromotingApp();
+
+  // Authorize, Authenticate, and Approve.
+  Auth();
+  ExpandMe2Me();
+
+  ASSERT_FALSE(HtmlElementVisible("paired-client-manager-message"))
+      << "The host must have no pairings before running the pinless test.";
+
+  // Test that cleanup works with either the Delete or Delete all buttons.
+  ConnectPinlessAndCleanupPairings(false);
+  ConnectPinlessAndCleanupPairings(true);
 
   Cleanup();
 }
@@ -66,7 +80,7 @@
 // Typing a command which writes to a temp file and then verify the contents of
 // the file.
 void Me2MeBrowserTest::TestKeyboardInput() {
-  // Start a terminal windows with ctrl+alt+T
+  // Start a terminal window with ctrl+alt+T
   SimulateKeyPressWithCode(ui::VKEY_T, "KeyT", true, false, true, false);
 
   // Wait for the keyboard events to be sent to and processed by the host.
@@ -105,4 +119,52 @@
   ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(5)).Wait());
 }
 
+void Me2MeBrowserTest::ConnectPinlessAndCleanupPairings(bool cleanup_all) {
+  // First connection: verify that a PIN is requested, and request pairing.
+  ConnectToLocalHost(true);
+  DisconnectMe2Me();
+
+  // TODO(jamiewalch): This reload is only needed because there's a bug in the
+  // web-app whereby it doesn't refresh its pairing state correctly.
+  // http://crbug.com/311290
+  LaunchChromotingApp();
+  ASSERT_TRUE(HtmlElementVisible("paired-client-manager-message"));
+
+  // Second connection: verify that no PIN is requested.
+  ClickOnControl("this-host-connect");
+  WaitForConnection();
+  DisconnectMe2Me();
+
+  // Clean up pairings.
+  ClickOnControl("open-paired-client-manager-dialog");
+  ASSERT_TRUE(HtmlElementVisible("paired-client-manager-dialog"));
+
+  if (cleanup_all) {
+    ClickOnControl("delete-all-paired-clients");
+  } else {
+    std::string host_id = ExecuteScriptAndExtractString(
+        "remoting.pairedClientManager.getFirstClientIdForTesting_()");
+    std::string node_id = "delete-client-" + host_id;
+    ClickOnControl(node_id);
+  }
+
+  // Wait for the "working" spinner to disappear. The spinner is shown by both
+  // methods of deleting a host and is removed when the operation completes.
+  ConditionalTimeoutWaiter waiter(
+      base::TimeDelta::FromSeconds(5),
+      base::TimeDelta::FromMilliseconds(200),
+      base::Bind(&Me2MeBrowserTest::IsPairingSpinnerHidden, this));
+  EXPECT_TRUE(waiter.Wait());
+  EXPECT_TRUE(ExecuteScriptAndExtractBool(
+      "document.getElementById('delete-all-paired-clients').disabled"));
+
+  ClickOnControl("close-paired-client-manager-dialog");
+  ASSERT_FALSE(HtmlElementVisible("paired-client-manager-dialog"));
+  ASSERT_FALSE(HtmlElementVisible("paired-client-manager-message"));
+}
+
+bool Me2MeBrowserTest::IsPairingSpinnerHidden() {
+  return !HtmlElementVisible("paired-client-manager-dialog-working");
+}
+
 }  // namespace remoting
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index 156d532..c9ed3d7 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -305,7 +305,7 @@
   EXPECT_TRUE(IsAuthenticated());
 }
 
-void RemoteDesktopBrowserTest::StartMe2Me() {
+void RemoteDesktopBrowserTest::ExpandMe2Me() {
   // The chromoting extension should be installed.
   ASSERT_TRUE(extension_);
 
@@ -459,7 +459,7 @@
   Approve();
 }
 
-void RemoteDesktopBrowserTest::ConnectToLocalHost() {
+void RemoteDesktopBrowserTest::ConnectToLocalHost(bool remember_pin) {
   // Verify that the local host is online.
   ASSERT_TRUE(ExecuteScriptAndExtractBool(
       "remoting.hostList.localHost_.hostName && "
@@ -471,13 +471,13 @@
   ClickOnControl("this-host-connect");
 
   // Enter the pin # passed in from the command line.
-  EnterPin(me2me_pin());
+  EnterPin(me2me_pin(), remember_pin);
 
   WaitForConnection();
 }
 
 void RemoteDesktopBrowserTest::ConnectToRemoteHost(
-    const std::string& host_name) {
+    const std::string& host_name, bool remember_pin) {
   std::string host_id = ExecuteScriptAndExtractString(
       "remoting.hostList.getHostIdForName('" + host_name + "')");
 
@@ -492,7 +492,7 @@
   ClickOnControl(element_id);
 
   // Enter the pin # passed in from the command line.
-  EnterPin(me2me_pin());
+  EnterPin(me2me_pin(), remember_pin);
 
   WaitForConnection();
 }
@@ -613,7 +613,8 @@
   ExecuteScript("document.getElementById(\"" + name + "\").click();");
 }
 
-void RemoteDesktopBrowserTest::EnterPin(const std::string& pin) {
+void RemoteDesktopBrowserTest::EnterPin(const std::string& pin,
+                                        bool remember_pin) {
   // Wait for the pin-form to be displayed. This can take a while.
   // We also need to dismiss the host-needs-update dialog if it comes up.
   // TODO(weitaosu) 1: Instead of polling, can we register a callback to be
@@ -630,6 +631,15 @@
   ExecuteScript(
       "document.getElementById(\"pin-entry\").value = \"" + pin + "\";");
 
+  if (remember_pin) {
+    EXPECT_TRUE(HtmlElementVisible("remember-pin"));
+    EXPECT_FALSE(ExecuteScriptAndExtractBool(
+        "document.getElementById('remember-pin-checkbox').checked"));
+    ClickOnControl("remember-pin");
+    EXPECT_TRUE(ExecuteScriptAndExtractBool(
+        "document.getElementById('remember-pin-checkbox').checked"));
+  }
+
   ClickOnControl("pin-connect-button");
 }
 
@@ -657,6 +667,10 @@
 }
 
 bool RemoteDesktopBrowserTest::IsSessionConnected() {
+  // If some form of PINless authentication is enabled, the host version
+  // warning may appear while waiting for the session to connect.
+  DismissHostVersionWarningIfVisible();
+
   return ExecuteScriptAndExtractBool(
       "remoting.clientSession != null && "
       "remoting.clientSession.getState() == "
@@ -664,10 +678,13 @@
 }
 
 bool RemoteDesktopBrowserTest::IsPinFormVisible() {
+  DismissHostVersionWarningIfVisible();
+  return HtmlElementVisible("pin-form");
+}
+
+void RemoteDesktopBrowserTest::DismissHostVersionWarningIfVisible() {
   if (HtmlElementVisible("host-needs-update-connect-button"))
     ClickOnControl("host-needs-update-connect-button");
-
-  return HtmlElementVisible("pin-form");
 }
 
 // static
diff --git a/chrome/test/remoting/remote_desktop_browsertest.h b/chrome/test/remoting/remote_desktop_browsertest.h
index faa3a89..36abbfd 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.h
+++ b/chrome/test/remoting/remote_desktop_browsertest.h
@@ -84,7 +84,7 @@
   void Approve();
 
   // Click on "Get Started" in the Me2Me section and show the host list.
-  void StartMe2Me();
+  void ExpandMe2Me();
 
   // Disconnect the active Me2Me session.
   void DisconnectMe2Me();
@@ -126,13 +126,13 @@
   void Auth();
 
   // Connect to the local host through Me2Me.
-  void ConnectToLocalHost();
+  void ConnectToLocalHost(bool remember_pin);
 
   // Connect to a remote host through Me2Me.
-  void ConnectToRemoteHost(const std::string& host_name);
+  void ConnectToRemoteHost(const std::string& host_name, bool remember_pin);
 
   // Enter the pin number and connect.
-  void EnterPin(const std::string& name);
+  void EnterPin(const std::string& name, bool remember_pin);
 
   // Helper to get the pin number used for me2me authentication.
   std::string me2me_pin() { return me2me_pin_; }
@@ -140,7 +140,6 @@
   // Helper to get the name of the remote host to connect to.
   std::string remote_host_name() { return remote_host_name_; }
 
- private:
   // Change behavior of the default host resolver to allow DNS lookup
   // to proceed instead of being blocked by the test infrastructure.
   void EnableDNSLookupForThisTest(
@@ -266,10 +265,14 @@
       return IsAuthenticatedInWindow(active_web_contents());
   }
 
+  // If the "Host version out-of-date" form is visible, dismiss it.
+  void DismissHostVersionWarningIfVisible();
+
   // Callback used by Approve to check whether the chromoting app has
   // successfully authenticated with the Google services.
   static bool IsAuthenticatedInWindow(content::WebContents* web_contents);
 
+ private:
   // Fields
 
   // This test needs to make live DNS requests for access to
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 3fe110a..19cc015 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -305,6 +305,7 @@
   },
   {
     'filename': 'wow_helper.exe',
+    'arch': ['32bit'],
     'buildtype': ['dev', 'official'],
   },
   # PNaCl translator (only for dev builds, components use for shipping).
diff --git a/chrome/tools/ipclist/ipclist.gyp b/chrome/tools/ipclist/ipclist.gyp
new file mode 100644
index 0000000..79ceb17
--- /dev/null
+++ b/chrome/tools/ipclist/ipclist.gyp
@@ -0,0 +1,22 @@
+# Copyright 2013 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.
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'ipclist',
+      'type': 'executable',
+      'dependencies': [
+        '../../../base/base.gyp:base',
+        '../../../skia/skia.gyp:skia',
+        '../../../third_party/khronos/khronos.gyp:khronos_headers',
+      ],
+      'sources': [
+        'ipclist.cc',
+      ]
+    }
+  ]
+}
diff --git a/chrome/tools/profile_reset/jtl_compiler.cc b/chrome/tools/profile_reset/jtl_compiler.cc
index 21104e9..f98d3d5 100644
--- a/chrome/tools/profile_reset/jtl_compiler.cc
+++ b/chrome/tools/profile_reset/jtl_compiler.cc
@@ -23,7 +23,7 @@
   void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); }
   void WriteOpCode(uint8 op_code) { WriteUint8(op_code); }
   void WriteHash(const std::string& hash) {
-    CHECK_EQ(hash.size(), jtl::kHashSizeInBytes);
+    CHECK(jtl::Hasher::IsHash(hash));
     *output_ += hash;
   }
   void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); }
@@ -40,19 +40,40 @@
  public:
   InstructionSet() {
     // Define each instruction in this list.
-    Add(Instruction("node", jtl::NAVIGATE, Arguments(Hash)));
+    // Note:
+    //  - Instructions ending in "hash" will write their 'HashString' arguments
+    //    directly into the byte-code.
+    //  - Instructions ending in "hashed" will first hash their 'String'
+    //    arguments, and will write this hash to the byte-code.
+    Add(Instruction("go", jtl::NAVIGATE, Arguments(String)));
     Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments()));
     Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments()));
-    Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(Hash, Bool)));
+    Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(String, Bool)));
+    Add(Instruction("store_hash",
+                    jtl::STORE_HASH, Arguments(String, HashString)));
+    Add(Instruction("store_hashed",
+                    jtl::STORE_HASH, Arguments(String, String)));
+    Add(Instruction("store_node_bool",
+                    jtl::STORE_NODE_BOOL, Arguments(String)));
+    Add(Instruction("store_node_hash",
+                    jtl::STORE_NODE_HASH, Arguments(String)));
+    Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
+    Add(Instruction("compare_hashed",
+                    jtl::COMPARE_NODE_HASH, Arguments(String)));
+    Add(Instruction("compare_hashed_not",
+                    jtl::COMPARE_NODE_HASH_NOT, Arguments(String)));
     Add(Instruction("compare_stored_bool",
                     jtl::COMPARE_STORED_BOOL,
-                    Arguments(Hash, Bool, Bool)));
-    Add(Instruction("store_hash", jtl::STORE_HASH, Arguments(Hash, Hash)));
-    Add(Instruction("compare_stored_hash",
+                    Arguments(String, Bool, Bool)));
+    Add(Instruction("compare_stored_hashed",
                     jtl::COMPARE_STORED_HASH,
-                    Arguments(Hash, Hash, Hash)));
-    Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
-    Add(Instruction("compare_hash", jtl::COMPARE_NODE_HASH, Arguments(Hash)));
+                    Arguments(String, String, String)));
+    Add(Instruction("compare_to_stored_bool",
+                    jtl::COMPARE_NODE_TO_STORED_BOOL,
+                    Arguments(String)));
+    Add(Instruction("compare_to_stored_hash",
+                    jtl::COMPARE_NODE_TO_STORED_HASH,
+                    Arguments(String)));
     Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments()));
   }
 
@@ -77,13 +98,21 @@
           target->WriteBool(value);
           break;
         }
-        case Hash: {
+        case String: {
           std::string value;
           if (!arguments.GetString(i, &value))
             return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
           target->WriteHash(hasher.GetHash(value));
           break;
         }
+        case HashString: {
+          std::string hash_value;
+          if (!arguments.GetString(i, &hash_value) ||
+              !jtl::Hasher::IsHash(hash_value))
+            return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
+          target->WriteHash(hash_value);
+          break;
+        }
         default:
           NOTREACHED();
           return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
@@ -99,7 +128,8 @@
   enum ArgumentType {
     None,
     Bool,
-    Hash
+    String,
+    HashString
   };
 
   // Encapsulates meta-data about one instruction.
diff --git a/chrome/tools/profile_reset/jtl_compiler.h b/chrome/tools/profile_reset/jtl_compiler.h
index fe3a68d..e563036 100644
--- a/chrome/tools/profile_reset/jtl_compiler.h
+++ b/chrome/tools/profile_reset/jtl_compiler.h
@@ -16,7 +16,7 @@
 //
 // The text-based JTL syntax itself much resembles C/C++. A program consists of
 // zero or more sentences. Each sentence is terminated by a semi-colon (;), and
-// is composed of *one* or more operations, separated by forward slashes (/).
+// is composed of *one* or more operations, separated by periods (.).
 //
 // Each operation resembles a C/C++ function call and consists of an instruction
 // name, and an optional argument list, which takes Boolean values and/or string
@@ -28,10 +28,10 @@
 // Example source code:
 //
 //   // Store "x"=true if path "foo.bar" is found.
-//   node("foo")/node("bar")/store_bool("x", true);
+//   go("foo").go("bar").store_bool("x", true);
 //
 //   // Store "y"="1" if the above value is set.
-//   compare_stored_bool("x", true, false)/store_hash("y", "1");
+//   compare_stored_bool("x", true, false).store_hash("y", "1");
 //
 class JtlCompiler {
  public:
diff --git a/chrome/tools/profile_reset/jtl_compiler_unittest.cc b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
index 2eb1d61..6b83774 100644
--- a/chrome/tools/profile_reset/jtl_compiler_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
@@ -33,25 +33,36 @@
     std::string source_code;
     std::string expected_bytecode;
   } cases[] = {
-        {"node(\"foo\")/", OP_NAVIGATE(GetHash("foo"))},
-        {"node(\"has whitespace\t\")/",
+        {"go(\"foo\").", OP_NAVIGATE(GetHash("foo"))},
+        {"go(\"has whitespace\t\").",
          OP_NAVIGATE(GetHash("has whitespace\t"))},
-        {"any/", OP_NAVIGATE_ANY},
-        {"back/", OP_NAVIGATE_BACK},
-        {"store_bool(\"name\", true)/",
+        {"any.", OP_NAVIGATE_ANY},
+        {"back.", OP_NAVIGATE_BACK},
+        {"store_bool(\"name\", true).",
          OP_STORE_BOOL(GetHash("name"), VALUE_TRUE)},
-        {"compare_stored_bool(\"name\", true, false)/",
+        {"compare_stored_bool(\"name\", true, false).",
          OP_COMPARE_STORED_BOOL(GetHash("name"), VALUE_TRUE, VALUE_FALSE)},
-        {"store_hash(\"name\", \"value\")/",
+        {"store_hash(\"name\", \"" + GetHash("value") + "\").",
          OP_STORE_HASH(GetHash("name"), GetHash("value"))},
-        {"compare_stored_hash(\"name\", \"value\", \"default\")/",
+        {"store_hashed(\"name\", \"value\").",
+         OP_STORE_HASH(GetHash("name"), GetHash("value"))},
+        {"store_node_bool(\"name\").",
+         OP_STORE_NODE_BOOL(GetHash("name"))},
+        {"store_node_hash(\"name\").",
+         OP_STORE_NODE_HASH(GetHash("name"))},
+        {"compare_stored_hashed(\"name\", \"value\", \"default\").",
          OP_COMPARE_STORED_HASH(
              GetHash("name"), GetHash("value"), GetHash("default"))},
-        {"compare_bool(false)/", OP_COMPARE_NODE_BOOL(VALUE_FALSE)},
-        {"compare_bool(true)/", OP_COMPARE_NODE_BOOL(VALUE_TRUE)},
-        {"compare_hash(\"foo\")/", OP_COMPARE_NODE_HASH(GetHash("foo"))},
-        {"compare_hash(\"bar\")/", OP_COMPARE_NODE_HASH(GetHash("bar"))},
-        {"break/", OP_STOP_EXECUTING_SENTENCE},
+        {"compare_bool(false).", OP_COMPARE_NODE_BOOL(VALUE_FALSE)},
+        {"compare_bool(true).", OP_COMPARE_NODE_BOOL(VALUE_TRUE)},
+        {"compare_hashed(\"foo\").", OP_COMPARE_NODE_HASH(GetHash("foo"))},
+        {"compare_hashed_not(\"foo\").",
+         OP_COMPARE_NODE_HASH_NOT(GetHash("foo"))},
+        {"compare_to_stored_bool(\"name\").",
+         OP_COMPARE_NODE_TO_STORED_BOOL(GetHash("name"))},
+        {"compare_to_stored_hash(\"name\").",
+         OP_COMPARE_NODE_TO_STORED_HASH(GetHash("name"))},
+        {"break.", OP_STOP_EXECUTING_SENTENCE},
         {"break;", OP_STOP_EXECUTING_SENTENCE + OP_END_OF_SENTENCE}};
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -66,10 +77,10 @@
 TEST(JtlCompiler, CompileEntireProgram) {
   const char kSourceCode[] =
       "// Store \"x\"=true if path is found.\n"
-      "node(\"foo\")/node(\"bar\")/store_bool(\"x\", true);\n"
+      "go(\"foo\").go(\"bar\").store_bool(\"x\", true);\n"
       "// ...\n"
       "// Store \"y\"=\"1\" if above value is set.\n"
-      "compare_stored_bool(\"x\", true, false)/store_hash(\"y\", \"1\");\n";
+      "compare_stored_bool(\"x\", true, false).store_hashed(\"y\", \"1\");\n";
 
   std::string expected_bytecode =
       OP_NAVIGATE(GetHash("foo")) +
@@ -85,7 +96,7 @@
 }
 
 TEST(JtlCompiler, InvalidOperationName) {
-  const char kSourceCode[] = "any()\n/\nnon_existent_instruction\n(\n)\n;\n";
+  const char kSourceCode[] = "any()\n.\nnon_existent_instruction\n(\n)\n;\n";
 
   std::string bytecode;
   JtlCompiler::CompileError error;
@@ -99,8 +110,8 @@
 
 TEST(JtlCompiler, InvalidArgumentsCount) {
   const char* kSourceCodes[] = {
-      "any()/\nstore_bool(\"name\", true, \"superfluous argument\");\n",
-      "any()/\nstore_bool(\"name\");"};  // missing argument
+      "any().\nstore_bool(\"name\", true, \"superfluous argument\");\n",
+      "any().\nstore_bool(\"name\");"};  // missing argument
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSourceCodes); ++i) {
     SCOPED_TRACE(kSourceCodes[i]);
@@ -116,19 +127,29 @@
 }
 
 TEST(JtlCompiler, InvalidArgumentType) {
-  const char* kSourceCodes[] = {
-      "any()\n/\ncompare_stored_bool(true, false, false);",  // Arg#1 should be
-                                                             // a hash.
-      "any()\n/\ncompare_stored_bool(\"name\", \"should be a bool\", false);",
-      "any()\n/\ncompare_stored_bool(\"name\", false, \"should be a bool\");"};
+  struct TestCase {
+    std::string expected_context_prefix;
+    std::string source_code;
+  } cases[] = {
+        {"compare_bool", "any()\n.\ncompare_bool(\"foo\");"},
+        {"compare_bool",
+         "any()\n.\ncompare_bool(\"01234567890123456789012345678901\");"},
+        {"compare_hashed", "any()\n.\ncompare_hashed(false);"},
+        {"store_hash", "any()\n.\nstore_hash(\"name\", false);"},
+        {"store_hash", "any()\n.\nstore_hash(\"name\", \"foo\");"},
+        {"compare_stored_bool",
+         "any()\n.\ncompare_stored_bool(\"name\", \"need a bool\", false);"},
+        {"compare_stored_bool",
+         "any()\n.\ncompare_stored_bool(\"name\", false, \"need a bool\");"}};
 
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSourceCodes); ++i) {
-    SCOPED_TRACE(kSourceCodes[i]);
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    SCOPED_TRACE(cases[i].source_code);
     std::string bytecode;
     JtlCompiler::CompileError error;
     EXPECT_FALSE(JtlCompiler::Compile(
-        kSourceCodes[i], kTestHashSeed, &bytecode, &error));
-    EXPECT_THAT(error.context, testing::StartsWith("compare_stored_bool"));
+        cases[i].source_code, kTestHashSeed, &bytecode, &error));
+    EXPECT_THAT(error.context,
+                testing::StartsWith(cases[i].expected_context_prefix));
     EXPECT_EQ(2u, error.line_number);
     EXPECT_EQ(JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE,
               error.error_code);
@@ -136,7 +157,7 @@
 }
 
 TEST(JtlCompiler, MistmatchedDoubleQuotes) {
-  const char kSourceCode[] = "any()/\nnode(\"ok\", \"stray quote)/break();";
+  const char kSourceCode[] = "any().\ngo(\"ok\", \"stray quote).break();";
 
   std::string bytecode;
   JtlCompiler::CompileError error;
@@ -148,13 +169,13 @@
 }
 
 TEST(JtlCompiler, ParsingError) {
-  const char kSourceCode[] = "any()/\nnode()missing_separator();";
+  const char kSourceCode[] = "any().\ngo()missing_separator();";
 
   std::string bytecode;
   JtlCompiler::CompileError error;
   EXPECT_FALSE(
       JtlCompiler::Compile(kSourceCode, kTestHashSeed, &bytecode, &error));
-  EXPECT_THAT(error.context, testing::StartsWith("node"));
+  EXPECT_THAT(error.context, testing::StartsWith("go"));
   EXPECT_EQ(1u, error.line_number);
   EXPECT_EQ(JtlCompiler::CompileError::PARSING_ERROR, error.error_code);
 }
diff --git a/chrome/tools/profile_reset/jtl_parser.cc b/chrome/tools/profile_reset/jtl_parser.cc
index 9a4e1d2..9c9bdbb 100644
--- a/chrome/tools/profile_reset/jtl_parser.cc
+++ b/chrome/tools/profile_reset/jtl_parser.cc
@@ -50,7 +50,7 @@
     "(?:\\("                    // Opening parenthesis.
     "((?:\"[^\"]*\"|[^\")])*)"  // Capture: anything inside, quote-aware.
     "\\))?";                    // Closing parenthesis + everything optional.
-const char kOperationSeparatorRE[] = "(;|/)";
+const char kOperationSeparatorRE[] = "(;|\\.)";
 
 }  // namespace
 
diff --git a/chrome/tools/profile_reset/jtl_parser_unittest.cc b/chrome/tools/profile_reset/jtl_parser_unittest.cc
index 58ee3d6..1868df8 100644
--- a/chrome/tools/profile_reset/jtl_parser_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_parser_unittest.cc
@@ -215,12 +215,12 @@
     const bool expected_ends_sentence;
   } cases[] = {
       {"foo1;", "foo1", "[]", true},
-      {"foo2()/", "foo2", "[]", false},
+      {"foo2().", "foo2", "[]", false},
       {"foo3(true);", "foo3", "[true]", true},
-      {"foo4(false)/", "foo4", "[false]", false},
-      {"foo5(\"bar\")/", "foo5", "[\"bar\"]", false},
-      {"foo6(\" b a r \")/", "foo6", "[\" b a r \"]", false},
-      {"foo7(true, \"bar\")/", "foo7", "[true,\"bar\"]", false},
+      {"foo4(false).", "foo4", "[false]", false},
+      {"foo5(\"bar\").", "foo5", "[\"bar\"]", false},
+      {"foo6(\" b a r \").", "foo6", "[\" b a r \"]", false},
+      {"foo7(true, \"bar\").", "foo7", "[true,\"bar\"]", false},
       {"foo8(\"bar\", false, true);", "foo8", "[\"bar\",false,true]", true},
       {"foo9(\"bar\", \" b a r \");", "foo9", "[\"bar\",\" b a r \"]", true}
   };
@@ -239,7 +239,7 @@
 
 TEST(JtlParser, ParsingMultipleWellFormedOperations) {
   const char kSourceCode[] =
-      "foo1(true)/foo2/foo3(\"bar\");"
+      "foo1(true).foo2.foo3(\"bar\");"
       "foo4(\"bar\", false);";
 
   scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode));
@@ -257,13 +257,14 @@
     const char* expected_args;
     const bool expected_ends_sentence;
   } cases[] = {
-      {"prev()/foo1(\"\");next(true);", "foo1", "[\"\"]", true},
-      {"prev()/foo2(\" \");next(true);", "foo2", "[\" \"]", true},
-      {"prev()/foo3(\",\",true);next(true);", "foo3", "[\",\",true]", true},
-      {"prev()/foo4(\")\",true);next(true);", "foo4", "[\")\",true]", true},
-      {"prev()/foo5(\";\",true);next(true);", "foo5", "[\";\",true]", true},
-      {"prev()/foo6(\"/\",true)/next(true);", "foo6", "[\"/\",true]", false},
-      {"prev()/foo7(\"//\",true)/next(true);", "foo7", "[\"//\",true]", false},
+      {"prev().foo1(\"\");next(true);", "foo1", "[\"\"]", true},
+      {"prev().foo2(\" \");next(true);", "foo2", "[\" \"]", true},
+      {"prev().foo3(\",\",true);next(true);", "foo3", "[\",\",true]", true},
+      {"prev().foo4(\")\",true);next(true);", "foo4", "[\")\",true]", true},
+      {"prev().foo5(\";\",true);next(true);", "foo5", "[\";\",true]", true},
+      {"prev().foo6(\"/\",true).next(true);", "foo6", "[\"/\",true]", false},
+      {"prev().foo7(\"//\",true).next(true);", "foo7", "[\"//\",true]", false},
+      {"prev().foo8(\".\",true).next(true);", "foo8", "[\".\",true]", false},
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -294,14 +295,14 @@
       {"bad_args6([\"bar\"]);", "bad_args6"},
       {"bad_args7(False);", "bad_args7"},
       {"bad_args8(True);", "bad_args8"},
-      {"bad_quotes1(missing both, true)/good();", "bad_quotes1"},
-      {"bad_quotes2(true, \"missing one)/good(); //\"", "bad_quotes2"},
-      {"bad_quotes3(\"too\" \"much\", true)/good();", "bad_quotes3"},
+      {"bad_quotes1(missing both, true).good();", "bad_quotes1"},
+      {"bad_quotes2(true, \"missing one).good(); //\"", "bad_quotes2"},
+      {"bad_quotes3(\"too\" \"much\", true).good();", "bad_quotes3"},
       {"bad_missing_separator1", "bad_missing_separator1"},
       {"bad_missing_separator2()good();", "bad_missing_separator2"},
-      {"bad_parenthesis1(true/good();", "bad_parenthesis1"},
-      {"bad_parenthesis2(true/good());", "bad_parenthesis2"},
-      {"bad_parenthesis3)/good();", "bad_parenthesis3"}
+      {"bad_parenthesis1(true.good();", "bad_parenthesis1"},
+      {"bad_parenthesis2(true.good());", "bad_parenthesis2"},
+      {"bad_parenthesis3).good();", "bad_parenthesis3"}
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -317,18 +318,20 @@
     const char* source_code;
     const char* bad_operation_name;
   } cases[] = {
-      {"\ngood(true,false)\n/bad_args(,);", "bad_args"},
-      {"\ngood(true,false)\n/bad_quotes1(missing both, true)/good();",
+      {"\ngood(true,false)\n.bad_args(,);", "bad_args"},
+      {"\ngood(true,false)\n.bad_quotes1(missing both, true).good();",
        "bad_quotes1"},
-      {"\ngood(true,false)\n/bad_quotes2(\"missing one, true)/good(); //\"",
+      {"\ngood(true,false)\n.bad_quotes2(\"missing one, true).good(); //\"",
        "bad_quotes2"},
-      {"\ngood(true,false)\n/bad_quotes3(\"too\" \"many\", true)/good();",
+      {"\ngood(true,false)\n.bad_quotes3(\"too\" \"many\", true).good();",
        "bad_quotes3"},
-      {"\ngood(true,false)\n/missing_separator1", "missing_separator1"},
-      {"\ngood(true,false)\n/missing_separator2()good()", "missing_separator2"},
-      {"\ngood(true,false)\n/bad_parens1(true/good();", "bad_parens1"},
-      {"\ngood(true,false)\n/bad_parens2(true/good());", "bad_parens2"},
-      {"\ngood(true,false)\n/bad_parens3)/good();", "bad_parens3"}
+      {"\ngood(true,false)\n.bad_separator1()/good();", "bad_separator1"},
+      {"\ngood(true,false)\n.missing_separator1", "missing_separator1"},
+      {"\ngood(true,false)\n.missing_separator2()good();",
+       "missing_separator2"},
+      {"\ngood(true,false)\n.bad_parens1(true.good();", "bad_parens1"},
+      {"\ngood(true,false)\n.bad_parens2(true.good());", "bad_parens2"},
+      {"\ngood(true,false)\n.bad_parens3).good();", "bad_parens3"}
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate
index 71bab21..3f077d6 100644
--- a/chrome/unit_tests.isolate
+++ b/chrome/unit_tests.isolate
@@ -41,8 +41,8 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/unit_tests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
         'isolate_dependency_tracked': [
           '../testing/xvfb.py',
@@ -86,8 +86,8 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/unit_tests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
         'isolate_dependency_untracked': [
           '<(PRODUCT_DIR)/test_data/chrome/browser/resources/google_now/',
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.cc b/chrome/utility/local_discovery/service_discovery_message_handler.cc
index a8d876e..e03853f 100644
--- a/chrome/utility/local_discovery/service_discovery_message_handler.cc
+++ b/chrome/utility/local_discovery/service_discovery_message_handler.cc
@@ -410,8 +410,10 @@
     const net::IPAddressNumber& address_ipv4,
     const net::IPAddressNumber& address_ipv6) {
   VLOG(1) << "OnLocalDomainResolved, id=" << id
-          << ", IPv4=" << net::IPAddressToString(address_ipv4)
-          << ", IPv6=" << net::IPAddressToString(address_ipv6);
+          << ", IPv4=" << (address_ipv4.empty() ? "" :
+                           net::IPAddressToString(address_ipv4))
+          << ", IPv6=" << (address_ipv6.empty() ? "" :
+                           net::IPAddressToString(address_ipv6));
 
   DCHECK(service_discovery_client_);
   Send(new LocalDiscoveryHostMsg_LocalDomainResolverCallback(
diff --git a/chrome/utility/media_galleries/picasa_album_table_reader.cc b/chrome/utility/media_galleries/picasa_album_table_reader.cc
index d6e2cc3..ccd6112 100644
--- a/chrome/utility/media_galleries/picasa_album_table_reader.cc
+++ b/chrome/utility/media_galleries/picasa_album_table_reader.cc
@@ -33,7 +33,9 @@
       initialized_(false) {
 }
 
-PicasaAlbumTableReader::~PicasaAlbumTableReader() {}
+PicasaAlbumTableReader::~PicasaAlbumTableReader() {
+  CloseAlbumTableFiles(&table_files_);
+}
 
 const std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const {
   DCHECK(initialized_);
diff --git a/chrome/utility/media_galleries/picasa_album_table_reader.h b/chrome/utility/media_galleries/picasa_album_table_reader.h
index 32f28af..6a9253b 100644
--- a/chrome/utility/media_galleries/picasa_album_table_reader.h
+++ b/chrome/utility/media_galleries/picasa_album_table_reader.h
@@ -14,6 +14,7 @@
 
 class PicasaAlbumTableReader {
  public:
+  // This class takes ownership of |table_files| and will close them.
   explicit PicasaAlbumTableReader(const AlbumTableFiles& table_files);
   ~PicasaAlbumTableReader();
 
@@ -23,7 +24,7 @@
   const std::vector<AlbumInfo>& folders() const;
 
  private:
-  const AlbumTableFiles table_files_;
+  AlbumTableFiles table_files_;
 
   bool initialized_;
 
diff --git a/chrome/utility/media_galleries/picasa_album_table_reader_unittest.cc b/chrome/utility/media_galleries/picasa_album_table_reader_unittest.cc
index d3473c7..8b7729a 100644
--- a/chrome/utility/media_galleries/picasa_album_table_reader_unittest.cc
+++ b/chrome/utility/media_galleries/picasa_album_table_reader_unittest.cc
@@ -60,7 +60,6 @@
   PicasaAlbumTableReader reader(album_table_files);
 
   ASSERT_TRUE(reader.Init());
-  CloseAlbumTableFiles(&album_table_files);
 
   const std::vector<AlbumInfo>& albums = reader.albums();
   const std::vector<AlbumInfo>& folders = reader.folders();
diff --git a/chrome_frame/navigation_constraints.cc b/chrome_frame/navigation_constraints.cc
index 59efb0e..18d8d9d 100644
--- a/chrome_frame/navigation_constraints.cc
+++ b/chrome_frame/navigation_constraints.cc
@@ -32,7 +32,7 @@
   // Additional checking for view-source. Allow only http and https
   // URLs in view source.
   if (url.SchemeIs(content::kViewSourceScheme)) {
-    GURL sub_url(url.path());
+    GURL sub_url(url.GetContent());
     if (sub_url.SchemeIs(content::kHttpScheme) ||
         sub_url.SchemeIs(content::kHttpsScheme))
       return true;
diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc
index 935b02c..dcfaa4c 100644
--- a/chrome_frame/test/net/fake_external_tab.cc
+++ b/chrome_frame/test/net/fake_external_tab.cc
@@ -335,7 +335,13 @@
     "URLRequestTest*.*_GetFullRequestHeaders",
 
     // IE redirects to data: URLs differently.
-    "URLRequestTestHTTP.RestrictDataRedirects"
+    "URLRequestTestHTTP.RestrictDataRedirects",
+
+    // Chrome frame doesn't use URLRequestHttpJob, so doesn't call into
+    // NetworkDelegates in OnStartCompleted, unlike Chrome.
+    "URLRequestTestHTTP.NetworkDelegateInfo",
+    "URLRequestTestHTTP.NetworkDelegateInfoAuth",
+    "URLRequestTestHTTP.NetworkDelegateInfoRedirect",
   };
 
   const char* ie9_disabled_tests[] = {
diff --git a/chrome_frame/test/reliability/page_load_test.cc b/chrome_frame/test/reliability/page_load_test.cc
index 389a3ab..666b967 100644
--- a/chrome_frame/test/reliability/page_load_test.cc
+++ b/chrome_frame/test/reliability/page_load_test.cc
@@ -136,6 +136,7 @@
     int crash_dump_count;
     // These are stability metrics recorded by Chrome itself
     bool browser_clean_exit;
+    int browser_execution_phase;
     int browser_launch_count;
     int page_load_count;
     int browser_crash_count;
@@ -446,6 +447,7 @@
       return;
     scoped_refptr<PrefRegistrySimple> registry = new PrefRegistrySimple();
     registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, false);
+    registry->RegisterIntegerPref(prefs::kStabilityExecutionPhase, 0);
     registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, -1);
     registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, -1);
     registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
@@ -457,6 +459,8 @@
 
     metrics->browser_clean_exit =
         local_state->GetBoolean(prefs::kStabilityExitedCleanly);
+    metrics->browser_execution_phase =
+        local_state->GetInteger(prefs::kStabilityExecutionPhase);
     metrics->browser_launch_count =
         local_state->GetInteger(prefs::kStabilityLaunchCount);
     metrics->page_load_count =
diff --git a/chrome_frame/turndown_prompt/turndown_prompt.cc b/chrome_frame/turndown_prompt/turndown_prompt.cc
index 513852a..f3e9af7 100644
--- a/chrome_frame/turndown_prompt/turndown_prompt.cc
+++ b/chrome_frame/turndown_prompt/turndown_prompt.cc
@@ -35,7 +35,7 @@
 namespace {
 
 // Time between showings of the turndown prompt.
-const int kTurndownPromptReshowDeltaMinutes = 60 * 24 * 7;
+const int kTurndownPromptReshowDeltaMinutes = 60 * 24 * 1;
 
 void OnUninstallClicked(UrlLauncher* url_launcher);
 
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 7c8b713..a00f503 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -1009,7 +1009,7 @@
   // Additional checking for view-source. Allow only http and https
   // URLs in view source.
   if (url.SchemeIs(content::kViewSourceScheme)) {
-    GURL sub_url(url.path());
+    GURL sub_url(url.GetContent());
     if (sub_url.SchemeIs(content::kHttpScheme) ||
         sub_url.SchemeIs(content::kHttpsScheme))
       return true;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 785daf3..4d9ecd7 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-4855.0.0
\ No newline at end of file
+4883.0.0
\ No newline at end of file
diff --git a/chromeos/cert_loader.cc b/chromeos/cert_loader.cc
index 5674117..5752ada 100644
--- a/chromeos/cert_loader.cc
+++ b/chromeos/cert_loader.cc
@@ -94,6 +94,7 @@
       tpm_token_state_(TPM_STATE_UNKNOWN),
       tpm_request_delay_(
           base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)),
+      tpm_token_slot_id_(-1),
       initialize_token_factory_(this),
       update_certificates_factory_(this) {
   if (LoginState::IsInitialized())
@@ -211,8 +212,10 @@
       base::PostTaskAndReplyWithResult(
           crypto_task_runner_.get(),
           FROM_HERE,
-          base::Bind(
-              &crypto::InitializeTPMToken, tpm_token_name_, tpm_user_pin_),
+          base::Bind(&crypto::InitializeTPMToken,
+                     tpm_token_name_,
+                     tpm_token_slot_id_,
+                     tpm_user_pin_),
           base::Bind(&CertLoader::OnTPMTokenInitialized,
                      initialize_token_factory_.GetWeakPtr()));
       return;
@@ -298,7 +301,7 @@
 void CertLoader::OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status,
                                          const std::string& token_name,
                                          const std::string& user_pin,
-                                         int token_slot) {
+                                         int token_slot_id) {
   VLOG(1) << "OnPkcs11GetTpmTokenInfo: " << token_name;
 
   if (call_status == DBUS_METHOD_CALL_FAILURE) {
@@ -307,7 +310,7 @@
   }
 
   tpm_token_name_ = token_name;
-  tpm_token_slot_ = base::IntToString(token_slot);
+  tpm_token_slot_id_ = token_slot_id;
   tpm_user_pin_ = user_pin;
   tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED;
 
@@ -376,10 +379,14 @@
                     OnCertificatesLoaded(cert_list_, initial_load));
 }
 
-void CertLoader::OnCertTrustChanged(const net::X509Certificate* cert) {
+void CertLoader::OnCACertChanged(const net::X509Certificate* cert) {
+  // This is triggered when a CA certificate is modified.
+  VLOG(1) << "OnCACertChanged";
+  LoadCertificates();
 }
 
 void CertLoader::OnCertAdded(const net::X509Certificate* cert) {
+  // This is triggered when a client certificate is added.
   VLOG(1) << "OnCertAdded";
   LoadCertificates();
 }
diff --git a/chromeos/cert_loader.h b/chromeos/cert_loader.h
index f9c2de0..e8534be 100644
--- a/chromeos/cert_loader.h
+++ b/chromeos/cert_loader.h
@@ -100,7 +100,7 @@
   // TPM info is only valid once the TPM is available (IsHardwareBacked is
   // true). Otherwise empty strings will be returned.
   const std::string& tpm_token_name() const { return tpm_token_name_; }
-  const std::string& tpm_token_slot() const { return tpm_token_slot_; }
+  int tpm_token_slot_id() const { return tpm_token_slot_id_; }
   const std::string& tpm_user_pin() const { return tpm_user_pin_; }
 
   // This will be empty until certificates_loaded() is true.
@@ -124,7 +124,7 @@
   void OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status,
                                const std::string& token_name,
                                const std::string& user_pin,
-                               int token_slot);
+                               int token_slot_id);
   void OnTPMTokenInitialized(bool success);
 
   // These calls handle the updating of the certificate list after the TPM token
@@ -143,7 +143,7 @@
   void NotifyCertificatesLoaded(bool initial_load);
 
   // net::CertDatabase::Observer
-  virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE;
+  virtual void OnCACertChanged(const net::X509Certificate* cert) OVERRIDE;
   virtual void OnCertAdded(const net::X509Certificate* cert) OVERRIDE;
   virtual void OnCertRemoved(const net::X509Certificate* cert) OVERRIDE;
 
@@ -178,7 +178,7 @@
 
   // Cached TPM token info.
   std::string tpm_token_name_;
-  std::string tpm_token_slot_;
+  int tpm_token_slot_id_;
   std::string tpm_user_pin_;
 
   // Cached Certificates.
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 2415173..debcaa6 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -113,6 +113,10 @@
         'dbus/fake_cryptohome_client.h',
         'dbus/fake_gsm_sms_client.cc',
         'dbus/fake_gsm_sms_client.h',
+        'dbus/fake_nfc_adapter_client.cc',
+        'dbus/fake_nfc_adapter_client.h',
+        'dbus/fake_nfc_manager_client.cc',
+        'dbus/fake_nfc_manager_client.h',
         'dbus/fake_image_burner_client.cc',
         'dbus/fake_image_burner_client.h',
         'dbus/fake_shill_device_client.cc',
@@ -129,6 +133,14 @@
         'dbus/fake_system_clock_client.h',
         'dbus/gsm_sms_client.cc',
         'dbus/gsm_sms_client.h',
+        'dbus/nfc_adapter_client.cc',
+        'dbus/nfc_adapter_client.h',
+        'dbus/nfc_client_helpers.cc',
+        'dbus/nfc_client_helpers.h',
+        'dbus/nfc_manager_client.cc',
+        'dbus/nfc_manager_client.h',
+        'dbus/nfc_property_set.cc',
+        'dbus/nfc_property_set.h',
         'dbus/shill_client_helper.cc',
         'dbus/shill_client_helper.h',
         'dbus/shill_device_client.cc',
@@ -476,6 +488,7 @@
         'dbus/ibus/ibus_text_unittest.cc',
         'dbus/introspectable_client_unittest.cc',
         'dbus/modem_messaging_client_unittest.cc',
+        'dbus/nfc_client_unittest.cc',
         'dbus/power_policy_controller_unittest.cc',
         'dbus/shill_client_unittest_base.cc',
         'dbus/shill_client_unittest_base.h',
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index e324073..42ffe24 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -18,9 +18,6 @@
 // Enables overriding the path for the default authentication extension.
 const char kAuthExtensionPath[]             = "auth-ext-path";
 
-// Enables overriding the Chrome OS board type when running on Linux.
-const char kChromeOSReleaseBoard[] = "chromeos-release-board";
-
 // Forces the stub implementation of dbus clients.
 const char kDbusStub[] = "dbus-stub";
 
@@ -80,9 +77,6 @@
 // Enables switching between different cellular carriers from the UI.
 const char kEnableCarrierSwitching[]        = "enable-carrier-switching";
 
-// Enable switching between audio devices in Chrome instead of cras.
-const char kEnableChromeAudioSwitching[] = "enable-chrome-audio-switching";
-
 // Enables Chrome Captive Portal detector, which initiates Captive
 // Portal detection for new active networks.
 const char kEnableChromeCaptivePortalDetector[] =
@@ -166,11 +160,6 @@
 // Enables natural scroll by default.
 const char kNaturalScrollDefault[]          = "enable-natural-scroll-default";
 
-// Disables tab discard in low memory conditions, a feature which silently
-// closes inactive tabs to free memory and to attempt to avoid the kernel's
-// out-of-memory process killer.
-const char kNoDiscardTabs[]                 = "no-discard-tabs";
-
 // Skips all other OOBE pages after user login.
 const char kOobeSkipPostLogin[]             = "oobe-skip-postlogin";
 
@@ -195,5 +184,8 @@
 // Enables new first-run overlay UI.
 const char kEnableFirstRunUI[] = "enable-first-run-ui";
 
+// Enables testing for auto update UI.
+const char kTestAutoUpdateUI[] = "test-auto-update-ui";
+
 }  // namespace switches
 }  // namespace chromeos
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 24fcce8..7218df3 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -23,7 +23,6 @@
 CHROMEOS_EXPORT extern const char kAppOemManifestFile[];
 CHROMEOS_EXPORT extern const char kAshWebUIInit[];
 CHROMEOS_EXPORT extern const char kAuthExtensionPath[];
-CHROMEOS_EXPORT extern const char kChromeOSReleaseBoard[];
 CHROMEOS_EXPORT extern const char kDbusStub[];
 CHROMEOS_EXPORT extern const char kDefaultStubNetworkStateIdle[];
 CHROMEOS_EXPORT extern const char kDisableBootAnimation[];
@@ -41,7 +40,6 @@
 CHROMEOS_EXPORT extern const char kEchoExtensionPath[];
 CHROMEOS_EXPORT extern const char kEnableBackgroundLoader[];
 CHROMEOS_EXPORT extern const char kEnableCarrierSwitching[];
-CHROMEOS_EXPORT extern const char kEnableChromeAudioSwitching[];
 CHROMEOS_EXPORT extern const char kEnableChromeCaptivePortalDetector[];
 CHROMEOS_EXPORT extern const char kEnableIMEModeIndicator[];
 CHROMEOS_EXPORT extern const char kEnableKioskMode[];
@@ -65,7 +63,6 @@
 CHROMEOS_EXPORT extern const char kLoginProfile[];
 CHROMEOS_EXPORT extern const char kLoginUser[];
 CHROMEOS_EXPORT extern const char kNaturalScrollDefault[];
-CHROMEOS_EXPORT extern const char kNoDiscardTabs[];
 CHROMEOS_EXPORT extern const char kOobeSkipPostLogin[];
 CHROMEOS_EXPORT extern const char kSkipHWIDCheck[];
 CHROMEOS_EXPORT extern const char kSmsTestMessages[];
@@ -73,6 +70,7 @@
 CHROMEOS_EXPORT extern const char kDisableUserImageSync[];
 CHROMEOS_EXPORT extern const char kEnableFirstRunUI[];
 CHROMEOS_EXPORT extern const char kEnableSamlSignin[];
+CHROMEOS_EXPORT extern const char kTestAutoUpdateUI[];
 
 }  // namespace switches
 }  // namespace chromeos
diff --git a/chromeos/cryptohome/system_salt_getter.cc b/chromeos/cryptohome/system_salt_getter.cc
index f299f0f..2a26db7 100644
--- a/chromeos/cryptohome/system_salt_getter.cc
+++ b/chromeos/cryptohome/system_salt_getter.cc
@@ -27,39 +27,43 @@
 
 void SystemSaltGetter::GetSystemSalt(
     const GetSystemSaltCallback& callback) {
+  if (!system_salt_.empty()) {
+    base::MessageLoopProxy::current()->PostTask(
+        FROM_HERE, base::Bind(callback, system_salt_));
+    return;
+  }
+
   DBusThreadManager::Get()->GetCryptohomeClient()->WaitForServiceToBeAvailable(
-      base::Bind(&SystemSaltGetter::GetSystemSaltInternal,
+      base::Bind(&SystemSaltGetter::DidWaitForServiceToBeAvailable,
                  weak_ptr_factory_.GetWeakPtr(),
                  callback));
 }
 
-std::string SystemSaltGetter::GetSystemSaltSync() {
-  LoadSystemSalt();  // no-op if it's already loaded.
-  return system_salt_;
-}
-
-std::string SystemSaltGetter::GetCachedSystemSalt() {
-  return system_salt_;
-}
-
-void SystemSaltGetter::GetSystemSaltInternal(
+void SystemSaltGetter::DidWaitForServiceToBeAvailable(
     const GetSystemSaltCallback& callback,
     bool service_is_available) {
-  LOG_IF(ERROR, !service_is_available) << "WaitForServiceToBeAvailable failed.";
-  // TODO(hashimoto): Stop using GetSystemSaltSync(). crbug.com/141009
-  callback.Run(GetSystemSaltSync());
-}
-
-void SystemSaltGetter::LoadSystemSalt() {
-  if (!system_salt_.empty())
-    return;
-  std::vector<uint8> salt;
-  DBusThreadManager::Get()->GetCryptohomeClient()->GetSystemSalt(&salt);
-  if (salt.empty() || salt.size() % 2 != 0U) {
-    LOG(WARNING) << "System salt not available";
+  if (!service_is_available) {
+    LOG(ERROR) << "WaitForServiceToBeAvailable failed.";
+    callback.Run(std::string());
     return;
   }
-  system_salt_ = ConvertRawSaltToHexString(salt);
+  DBusThreadManager::Get()->GetCryptohomeClient()->GetSystemSalt(
+      base::Bind(&SystemSaltGetter::DidGetSystemSalt,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 callback));
+}
+
+void SystemSaltGetter::DidGetSystemSalt(const GetSystemSaltCallback& callback,
+                                        DBusMethodCallStatus call_status,
+                                        const std::vector<uint8>& system_salt) {
+  if (call_status == DBUS_METHOD_CALL_SUCCESS &&
+      !system_salt.empty() &&
+      system_salt.size() % 2 == 0U)
+    system_salt_ = ConvertRawSaltToHexString(system_salt);
+  else
+    LOG(WARNING) << "System salt not available";
+
+  callback.Run(system_salt_);
 }
 
 // static
diff --git a/chromeos/cryptohome/system_salt_getter.h b/chromeos/cryptohome/system_salt_getter.h
index a47b617..ee33133 100644
--- a/chromeos/cryptohome/system_salt_getter.h
+++ b/chromeos/cryptohome/system_salt_getter.h
@@ -12,6 +12,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
 
 namespace chromeos {
 
@@ -31,31 +32,20 @@
   static std::string ConvertRawSaltToHexString(const std::vector<uint8>& salt);
 
   // Returns system hash in hex encoded ascii format. Note: this may return
-  // an empty string (e.g. if cryptohome is not running). It is up to the
-  // calling function to try again after a delay if desired.
+  // an empty string (e.g. errors in D-Bus layer)
   void GetSystemSalt(const GetSystemSaltCallback& callback);
 
-  // Synchronous version of GetSystemSalt().
-  // Blocks the UI thread until the Cryptohome service returns the result.
-  // DEPRECATED: DO NOT USE.
-  std::string GetSystemSaltSync();
-
-  // Returns system hash in hex encoded ascii format, cached by a prior call
-  // to GetSystemSalt(). Note: this may return an empty string (e.g. if
-  // GetSystemSalt() is not yet called).
-  std::string GetCachedSystemSalt();
-
  protected:
   SystemSaltGetter();
   ~SystemSaltGetter();
 
  private:
   // Used to implement GetSystemSalt().
-  void GetSystemSaltInternal(const GetSystemSaltCallback& callback,
-                             bool service_is_available);
-
-  // Loads the system salt from cryptohome and caches it.
-  void LoadSystemSalt();
+  void DidWaitForServiceToBeAvailable(const GetSystemSaltCallback& callback,
+                                      bool service_is_available);
+  void DidGetSystemSalt(const GetSystemSaltCallback& callback,
+                        DBusMethodCallStatus call_status,
+                        const std::vector<uint8>& system_salt);
 
   std::string system_salt_;
 
diff --git a/chromeos/cryptohome/system_salt_getter_unittest.cc b/chromeos/cryptohome/system_salt_getter_unittest.cc
index 84403e4..07883a0 100644
--- a/chromeos/cryptohome/system_salt_getter_unittest.cc
+++ b/chromeos/cryptohome/system_salt_getter_unittest.cc
@@ -55,6 +55,7 @@
 
   // Service becomes available.
   fake_cryptohome_client_->SetServiceIsAvailable(true);
+  base::RunLoop().RunUntilIdle();
   const std::string expected_system_salt =
       SystemSaltGetter::ConvertRawSaltToHexString(
           FakeCryptohomeClient::GetStubSystemSalt());
diff --git a/chromeos/dbus/cryptohome_client.cc b/chromeos/dbus/cryptohome_client.cc
index ca2d48a..77848d3 100644
--- a/chromeos/dbus/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome_client.cc
@@ -110,20 +110,13 @@
   }
 
   // CryptohomeClient override.
-  virtual bool GetSystemSalt(std::vector<uint8>* salt) OVERRIDE {
+  virtual void GetSystemSalt(const GetSystemSaltCallback& callback) OVERRIDE {
     dbus::MethodCall method_call(cryptohome::kCryptohomeInterface,
                                  cryptohome::kCryptohomeGetSystemSalt);
-    scoped_ptr<dbus::Response> response(
-        blocking_method_caller_->CallMethodAndBlock(&method_call));
-    if (!response.get())
-      return false;
-    dbus::MessageReader reader(response.get());
-    uint8* bytes = NULL;
-    size_t length = 0;
-    if (!reader.PopArrayOfBytes(&bytes, &length))
-      return false;
-    salt->assign(bytes, bytes + length);
-    return true;
+    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                       base::Bind(&CryptohomeClientImpl::OnGetSystemSalt,
+                                  weak_ptr_factory_.GetWeakPtr(),
+                                  callback));
   }
 
   // CryptohomeClient override,
@@ -720,6 +713,24 @@
     callback.Run(async_id);
   }
 
+  // Handles the result of GetSystemSalt().
+  void OnGetSystemSalt(const GetSystemSaltCallback& callback,
+                       dbus::Response* response) {
+    if (!response) {
+      callback.Run(DBUS_METHOD_CALL_FAILURE, std::vector<uint8>());
+      return;
+    }
+    dbus::MessageReader reader(response);
+    uint8* bytes = NULL;
+    size_t length = 0;
+    if (!reader.PopArrayOfBytes(&bytes, &length)) {
+      callback.Run(DBUS_METHOD_CALL_FAILURE, std::vector<uint8>());
+      return;
+    }
+    callback.Run(DBUS_METHOD_CALL_SUCCESS,
+                 std::vector<uint8>(bytes, bytes + length));
+  }
+
   // Calls a method without result values.
   void CallVoidMethod(dbus::MethodCall* method_call,
                       const VoidDBusMethodCallback& callback) {
diff --git a/chromeos/dbus/cryptohome_client.h b/chromeos/dbus/cryptohome_client.h
index 036cf64..87457a7 100644
--- a/chromeos/dbus/cryptohome_client.h
+++ b/chromeos/dbus/cryptohome_client.h
@@ -35,6 +35,10 @@
       AsyncCallStatusWithDataHandler;
   // A callback to handle responses of AsyncXXX methods.
   typedef base::Callback<void(int async_id)> AsyncMethodCallback;
+  // A callback for GetSystemSalt().
+  typedef base::Callback<void(
+      DBusMethodCallStatus call_status,
+      const std::vector<uint8>& system_salt)> GetSystemSaltCallback;
   // A callback for WaitForServiceToBeAvailable().
   typedef base::Callback<void(bool service_is_ready)>
       WaitForServiceToBeAvailableCallback;
@@ -105,9 +109,9 @@
   virtual void AsyncRemove(const std::string& username,
                            const AsyncMethodCallback& callback) = 0;
 
-  // Calls GetSystemSalt method.  This method blocks until the call returns.
-  // The original content of |salt| is lost.
-  virtual bool GetSystemSalt(std::vector<uint8>* salt) = 0;
+  // Calls GetSystemSalt method.  |callback| is called after the method call
+  // succeeds.
+  virtual void GetSystemSalt(const GetSystemSaltCallback& callback) = 0;
 
   // Calls GetSanitizedUsername method.  |callback| is called after the method
   // call succeeds.
diff --git a/chromeos/dbus/dbus_client.h b/chromeos/dbus/dbus_client.h
index 902d533..c9ac671 100644
--- a/chromeos/dbus/dbus_client.h
+++ b/chromeos/dbus/dbus_client.h
@@ -5,6 +5,8 @@
 #ifndef CHROMEOS_DBUS_DBUS_CLIENT_H_
 #define CHROMEOS_DBUS_DBUS_CLIENT_H_
 
+#include "base/basictypes.h"
+
 namespace dbus {
 class Bus;
 };
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 46753c1..b98e07c 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -29,6 +29,8 @@
 #include "chromeos/dbus/image_burner_client.h"
 #include "chromeos/dbus/introspectable_client.h"
 #include "chromeos/dbus/modem_messaging_client.h"
+#include "chromeos/dbus/nfc_adapter_client.h"
+#include "chromeos/dbus/nfc_manager_client.h"
 #include "chromeos/dbus/permission_broker_client.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/dbus/power_policy_controller.h"
@@ -101,6 +103,8 @@
     InitClient(image_burner_client_.get());
     InitClient(introspectable_client_.get());
     InitClient(modem_messaging_client_.get());
+    InitClient(nfc_manager_client_.get());
+    InitClient(nfc_adapter_client_.get());
     InitClient(permission_broker_client_.get());
     InitClient(power_manager_client_.get());
     InitClient(session_manager_client_.get());
@@ -261,6 +265,14 @@
     return modem_messaging_client_.get();
   }
 
+  virtual NfcAdapterClient* GetNfcAdapterClient() OVERRIDE {
+    return nfc_adapter_client_.get();
+  }
+
+  virtual NfcManagerClient* GetNfcManagerClient() OVERRIDE {
+    return nfc_manager_client_.get();
+  }
+
   virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE {
     return permission_broker_client_.get();
   }
@@ -354,6 +366,9 @@
     image_burner_client_.reset(ImageBurnerClient::Create(client_type));
     introspectable_client_.reset(IntrospectableClient::Create(client_type));
     modem_messaging_client_.reset(ModemMessagingClient::Create(client_type));
+    nfc_manager_client_.reset(NfcManagerClient::Create(client_type));
+    nfc_adapter_client_.reset(
+        NfcAdapterClient::Create(client_type, nfc_manager_client_.get()));
     permission_broker_client_.reset(
         PermissionBrokerClient::Create(client_type));
     power_manager_client_.reset(
@@ -389,6 +404,11 @@
   scoped_ptr<ImageBurnerClient> image_burner_client_;
   scoped_ptr<IntrospectableClient> introspectable_client_;
   scoped_ptr<ModemMessagingClient> modem_messaging_client_;
+  // NfcAdapterClient depends on NfcManagerClient. We declare NfcManagerClient
+  // first, so that it won't be deallocated before NfcAdapterClient is done
+  // cleaning up.
+  scoped_ptr<NfcManagerClient> nfc_manager_client_;
+  scoped_ptr<NfcAdapterClient> nfc_adapter_client_;
   scoped_ptr<PermissionBrokerClient> permission_broker_client_;
   scoped_ptr<SystemClockClient> system_clock_client_;
   scoped_ptr<PowerManagerClient> power_manager_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 65f0333..d0d6c3c 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -42,6 +42,8 @@
 class ImageBurnerClient;
 class IntrospectableClient;
 class ModemMessagingClient;
+class NfcAdapterClient;
+class NfcManagerClient;
 class PermissionBrokerClient;
 class PowerManagerClient;
 class PowerPolicyController;
@@ -134,6 +136,8 @@
   virtual ImageBurnerClient* GetImageBurnerClient() = 0;
   virtual IntrospectableClient* GetIntrospectableClient() = 0;
   virtual ModemMessagingClient* GetModemMessagingClient() = 0;
+  virtual NfcAdapterClient* GetNfcAdapterClient() = 0;
+  virtual NfcManagerClient* GetNfcManagerClient() = 0;
   virtual PermissionBrokerClient* GetPermissionBrokerClient() = 0;
   virtual PowerManagerClient* GetPowerManagerClient() = 0;
   virtual PowerPolicyController* GetPowerPolicyController() = 0;
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index d23be71..50ae793 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -17,6 +17,7 @@
       async_call_id_(1),
       tpm_is_ready_counter_(0),
       unmount_result_(true),
+      system_salt_(GetStubSystemSalt()),
       locked_(false),
       weak_ptr_factory_(this) {}
 
@@ -79,9 +80,11 @@
   ReturnAsyncMethodResult(callback, false);
 }
 
-bool FakeCryptohomeClient::GetSystemSalt(std::vector<uint8>* salt) {
-  *salt = GetStubSystemSalt();
-  return true;
+void FakeCryptohomeClient::GetSystemSalt(
+    const GetSystemSaltCallback& callback) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, system_salt_));
 }
 
 void FakeCryptohomeClient::GetSanitizedUsername(
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h
index 3c960e8..fd482b9 100644
--- a/chromeos/dbus/fake_cryptohome_client.h
+++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -36,7 +36,7 @@
                                const AsyncMethodCallback& callback) OVERRIDE;
   virtual void AsyncRemove(const std::string& username,
                            const AsyncMethodCallback& callback) OVERRIDE;
-  virtual bool GetSystemSalt(std::vector<uint8>* salt) OVERRIDE;
+  virtual void GetSystemSalt(const GetSystemSaltCallback& callback) OVERRIDE;
   virtual void GetSanitizedUsername(
       const std::string& username,
       const StringDBusMethodCallback& callback) OVERRIDE;
@@ -162,6 +162,13 @@
     unmount_result_= result;
   }
 
+  // Sets the system salt which will be returned from GetSystemSalt(). By
+  // default, GetSystemSalt() returns the value generated by
+  // GetStubSystemSalt().
+  void set_system_salt(const std::vector<uint8>& system_salt) {
+    system_salt_ = system_salt;
+  }
+
   // Returns the stub system salt as raw bytes. (not as a string encoded in the
   // format used by SystemSaltGetter::ConvertRawSaltToHexString()).
   static std::vector<uint8> GetStubSystemSalt();
@@ -181,6 +188,7 @@
   AsyncCallStatusWithDataHandler async_call_status_data_handler_;
   int tpm_is_ready_counter_;
   bool unmount_result_;
+  std::vector<uint8> system_salt_;
 
   std::vector<WaitForServiceToBeAvailableCallback>
       pending_wait_for_service_to_be_available_callbacks_;
diff --git a/chromeos/dbus/fake_dbus_thread_manager.cc b/chromeos/dbus/fake_dbus_thread_manager.cc
index 4378d1c..e8f7bbb 100644
--- a/chromeos/dbus/fake_dbus_thread_manager.cc
+++ b/chromeos/dbus/fake_dbus_thread_manager.cc
@@ -14,6 +14,8 @@
 #include "chromeos/dbus/fake_cryptohome_client.h"
 #include "chromeos/dbus/fake_gsm_sms_client.h"
 #include "chromeos/dbus/fake_image_burner_client.h"
+#include "chromeos/dbus/fake_nfc_adapter_client.h"
+#include "chromeos/dbus/fake_nfc_manager_client.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/fake_shill_device_client.h"
@@ -38,6 +40,8 @@
     fake_cryptohome_client_(new FakeCryptohomeClient),
     fake_gsm_sms_client_(new FakeGsmSMSClient),
     fake_image_burner_client_(new FakeImageBurnerClient),
+    fake_nfc_adapter_client_(new FakeNfcAdapterClient()),
+    fake_nfc_manager_client_(new FakeNfcManagerClient()),
     fake_session_manager_client_(new FakeSessionManagerClient),
     fake_shill_device_client_(new FakeShillDeviceClient),
     fake_shill_manager_client_(new FakeShillManagerClient),
@@ -174,6 +178,14 @@
   return NULL;
 }
 
+NfcAdapterClient* FakeDBusThreadManager::GetNfcAdapterClient() {
+  return fake_nfc_adapter_client_.get();
+}
+
+NfcManagerClient* FakeDBusThreadManager::GetNfcManagerClient() {
+  return fake_nfc_manager_client_.get();
+}
+
 PermissionBrokerClient*
     FakeDBusThreadManager::GetPermissionBrokerClient() {
   NOTIMPLEMENTED();
diff --git a/chromeos/dbus/fake_dbus_thread_manager.h b/chromeos/dbus/fake_dbus_thread_manager.h
index 13addee..495d2d1 100644
--- a/chromeos/dbus/fake_dbus_thread_manager.h
+++ b/chromeos/dbus/fake_dbus_thread_manager.h
@@ -27,6 +27,8 @@
 class FakeCrosDisksClient;
 class FakeCryptohomeClient;
 class FakeGsmSMSClient;
+class FakeNfcAdapterClient;
+class FakeNfcManagerClient;
 class FakePowerManagerClient;
 class FakeImageBurnerClient;
 class FakeSessionManagerClient;
@@ -72,6 +74,8 @@
   virtual ImageBurnerClient* GetImageBurnerClient() OVERRIDE;
   virtual IntrospectableClient* GetIntrospectableClient() OVERRIDE;
   virtual ModemMessagingClient* GetModemMessagingClient() OVERRIDE;
+  virtual NfcAdapterClient* GetNfcAdapterClient() OVERRIDE;
+  virtual NfcManagerClient* GetNfcManagerClient() OVERRIDE;
   virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE;
   virtual PowerManagerClient* GetPowerManagerClient() OVERRIDE;
   virtual PowerPolicyController* GetPowerPolicyController() OVERRIDE;
@@ -122,6 +126,14 @@
     return fake_image_burner_client_.get();
   }
 
+  FakeNfcAdapterClient* fake_nfc_adapter_client() {
+    return fake_nfc_adapter_client_.get();
+  }
+
+  FakeNfcManagerClient* fake_nfc_manager_client() {
+    return fake_nfc_manager_client_.get();
+  }
+
   FakeSessionManagerClient* fake_session_manager_client() {
     return fake_session_manager_client_.get();
   }
@@ -179,6 +191,8 @@
   scoped_ptr<FakeCryptohomeClient> fake_cryptohome_client_;
   scoped_ptr<FakeGsmSMSClient> fake_gsm_sms_client_;
   scoped_ptr<FakeImageBurnerClient> fake_image_burner_client_;
+  scoped_ptr<FakeNfcAdapterClient> fake_nfc_adapter_client_;
+  scoped_ptr<FakeNfcManagerClient> fake_nfc_manager_client_;
   scoped_ptr<FakeSessionManagerClient> fake_session_manager_client_;
   scoped_ptr<FakeShillDeviceClient> fake_shill_device_client_;
   scoped_ptr<FakeShillManagerClient> fake_shill_manager_client_;
diff --git a/chromeos/dbus/fake_nfc_adapter_client.cc b/chromeos/dbus/fake_nfc_adapter_client.cc
new file mode 100644
index 0000000..6ace808
--- /dev/null
+++ b/chromeos/dbus/fake_nfc_adapter_client.cc
@@ -0,0 +1,83 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/fake_nfc_adapter_client.h"
+
+#include "base/logging.h"
+#include "dbus/object_path.h"
+
+// TODO(armansito): For now, this class doesn't do anything. Implement fake
+// behavior in conjunction with unit tests while implementing the src/device
+// layer.
+
+namespace chromeos {
+
+FakeNfcAdapterClient::Properties::Properties(
+    const PropertyChangedCallback& callback)
+    : NfcAdapterClient::Properties(NULL, callback) {
+}
+
+FakeNfcAdapterClient::Properties::~Properties() {
+}
+
+void FakeNfcAdapterClient::Properties::Get(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::GetCallback callback) {
+  VLOG(1) << "Get " << property->name();
+  callback.Run(false);
+}
+
+void FakeNfcAdapterClient::Properties::GetAll() {
+  VLOG(1) << "GetAll";
+}
+
+void FakeNfcAdapterClient::Properties::Set(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::SetCallback callback) {
+  VLOG(1) << "Set " << property->name();
+  callback.Run(false);
+}
+
+FakeNfcAdapterClient::FakeNfcAdapterClient() {
+  VLOG(1) << "Creating FakeNfcAdapterClient";
+}
+
+FakeNfcAdapterClient::~FakeNfcAdapterClient() {
+}
+
+void FakeNfcAdapterClient::Init(dbus::Bus* bus) {
+}
+
+void FakeNfcAdapterClient::AddObserver(Observer* observer) {
+}
+
+void FakeNfcAdapterClient::RemoveObserver(Observer* observer) {
+}
+
+FakeNfcAdapterClient::Properties*
+FakeNfcAdapterClient::GetProperties(const dbus::ObjectPath& object_path) {
+  return NULL;
+}
+
+void FakeNfcAdapterClient::StartPollLoop(
+    const dbus::ObjectPath& object_path,
+    const std::string& mode,
+    const base::Closure& callback,
+    const nfc_client_helpers::ErrorCallback& error_callback) {
+  VLOG(1) << "Starting fake NFC Adapter poll loop.";
+  VLOG(1) << "Nothing happened.";
+}
+
+void FakeNfcAdapterClient::StopPollLoop(
+    const dbus::ObjectPath& object_path,
+    const base::Closure& callback,
+    const nfc_client_helpers::ErrorCallback& error_callback) {
+  VLOG(1) << "Stopping fake NFC Adapter poll loop.";
+}
+
+void FakeNfcAdapterClient::OnPropertyChanged(const std::string& property_name) {
+  VLOG(1) << "Fake NFC property changed:  " << property_name;
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_nfc_adapter_client.h b/chromeos/dbus/fake_nfc_adapter_client.h
new file mode 100644
index 0000000..97cab97
--- /dev/null
+++ b/chromeos/dbus/fake_nfc_adapter_client.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_FAKE_NFC_ADAPTER_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_NFC_ADAPTER_CLIENT_H_
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/nfc_adapter_client.h"
+#include "chromeos/dbus/nfc_client_helpers.h"
+
+namespace chromeos {
+
+// FakeNfcAdapterClient simulates the behavior of the NFC adapter objects
+// and is used both in test cases in place of a mock and on the Linux desktop.
+// TODO(armansito): For now, this doesn't do anything. Implement fake
+// behavior in conjunction with unit tests while implementing the src/device
+// layer.
+class CHROMEOS_EXPORT FakeNfcAdapterClient : public NfcAdapterClient {
+ public:
+  struct Properties : public NfcAdapterClient::Properties {
+    explicit Properties(const PropertyChangedCallback& callback);
+    virtual ~Properties();
+
+    // dbus::PropertySet overrides.
+    virtual void Get(dbus::PropertyBase* property,
+                     dbus::PropertySet::GetCallback callback) OVERRIDE;
+    virtual void GetAll() OVERRIDE;
+    virtual void Set(dbus::PropertyBase* property,
+                     dbus::PropertySet::SetCallback callback) OVERRIDE;
+  };
+
+  FakeNfcAdapterClient();
+  virtual ~FakeNfcAdapterClient();
+
+  // NfcAdapterClient overrides.
+  virtual void Init(dbus::Bus* bus) OVERRIDE;
+  virtual void AddObserver(Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(Observer* observer) OVERRIDE;
+  virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
+      OVERRIDE;
+  virtual void StartPollLoop(
+      const dbus::ObjectPath& object_path,
+      const std::string& mode,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE;
+  virtual void StopPollLoop(
+      const dbus::ObjectPath& object_path,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE;
+
+ private:
+  // Property callback passed when we create Properties* structures.
+  void OnPropertyChanged(const std::string& property_name);
+
+  DISALLOW_COPY_AND_ASSIGN(FakeNfcAdapterClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_NFC_ADAPTER_CLIENT_H_
diff --git a/chromeos/dbus/fake_nfc_manager_client.cc b/chromeos/dbus/fake_nfc_manager_client.cc
new file mode 100644
index 0000000..3c8564a
--- /dev/null
+++ b/chromeos/dbus/fake_nfc_manager_client.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/fake_nfc_manager_client.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "dbus/object_path.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+const char FakeNfcManagerClient::kDefaultAdapterPath[] = "/fake/nfc0";
+
+FakeNfcManagerClient::Properties::Properties(
+    const PropertyChangedCallback& callback)
+    : NfcManagerClient::Properties(NULL, callback) {
+}
+
+FakeNfcManagerClient::Properties::~Properties() {
+}
+
+void FakeNfcManagerClient::Properties::Get(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::GetCallback callback) {
+  VLOG(1) << "Get " << property->name();
+  callback.Run(false);
+}
+
+void FakeNfcManagerClient::Properties::GetAll() {
+  VLOG(1) << "GetAll";
+}
+
+void FakeNfcManagerClient::Properties::Set(
+    dbus::PropertyBase* property,
+    dbus::PropertySet::SetCallback callback) {
+  VLOG(1) << "Set " << property->name();
+  callback.Run(false);
+}
+
+FakeNfcManagerClient::FakeNfcManagerClient() {
+  properties_.reset(new Properties(base::Bind(
+      &FakeNfcManagerClient::OnPropertyChanged, base::Unretained(this))));
+  AddAdapter(kDefaultAdapterPath);
+}
+
+FakeNfcManagerClient::~FakeNfcManagerClient() {
+}
+
+void FakeNfcManagerClient::Init(dbus::Bus* bus) {
+}
+
+void FakeNfcManagerClient::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void FakeNfcManagerClient::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+FakeNfcManagerClient::Properties* FakeNfcManagerClient::GetProperties() {
+  return properties_.get();
+}
+
+void FakeNfcManagerClient::AddAdapter(const std::string& adapter_path) {
+  VLOG(1) << "Adding NFC adapter: " << adapter_path;
+  dbus::ObjectPath new_adapter(adapter_path);
+  std::pair<std::set<dbus::ObjectPath>::iterator, bool> result =
+      adapters_.insert(new_adapter);
+  if (!result.second) {
+    VLOG(1) << "Adapter \"" << adapter_path << "\" already exists.";
+    return;
+  }
+  // Create a vector containing all object paths in the set |adapters_|. This
+  // will copy all members of |adapters_| to |adapters|.
+  std::vector<dbus::ObjectPath> adapters(adapters_.begin(), adapters_.end());
+  properties_->adapters.ReplaceValue(adapters);
+  FOR_EACH_OBSERVER(Observer, observers_, AdapterAdded(new_adapter));
+}
+
+void FakeNfcManagerClient::RemoveAdapter(const std::string& adapter_path) {
+  VLOG(1) << "Removing NFC adapter: " << adapter_path;
+  dbus::ObjectPath to_remove(adapter_path);
+  if (adapters_.erase(to_remove) == 0) {
+    VLOG(1) << "No such adapter: \"" << adapter_path << "\"";
+    return;
+  }
+  std::vector<dbus::ObjectPath> adapters(adapters_.begin(), adapters_.end());
+  properties_->adapters.ReplaceValue(adapters);
+  FOR_EACH_OBSERVER(Observer, observers_, AdapterRemoved(to_remove));
+}
+
+void FakeNfcManagerClient::OnPropertyChanged(
+    const std::string& property_name) {
+  FOR_EACH_OBSERVER(Observer, observers_,
+                    ManagerPropertyChanged(property_name));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_nfc_manager_client.h b/chromeos/dbus/fake_nfc_manager_client.h
new file mode 100644
index 0000000..2393fa2
--- /dev/null
+++ b/chromeos/dbus/fake_nfc_manager_client.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_FAKE_NFC_MANAGER_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_NFC_MANAGER_CLIENT_H_
+
+#include <set>
+#include <string>
+
+#include "base/observer_list.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/nfc_manager_client.h"
+#include "dbus/property.h"
+
+namespace chromeos {
+
+// FakeNfcManagerClient simulates the behavior of the NFC Daemon manager object
+// and is used both in test cases in place of a mock and on the Linux desktop.
+class CHROMEOS_EXPORT FakeNfcManagerClient : public NfcManagerClient {
+ public:
+  struct Properties : public NfcManagerClient::Properties {
+    explicit Properties(const PropertyChangedCallback& callback);
+    virtual ~Properties();
+
+    // dbus::PropertySet overrides.
+    virtual void Get(dbus::PropertyBase* property,
+                     dbus::PropertySet::GetCallback callback) OVERRIDE;
+    virtual void GetAll() OVERRIDE;
+    virtual void Set(dbus::PropertyBase* property,
+                     dbus::PropertySet::SetCallback callback) OVERRIDE;
+  };
+
+  FakeNfcManagerClient();
+  virtual ~FakeNfcManagerClient();
+
+  // NfcManagerClient overrides.
+  virtual void Init(dbus::Bus* bus) OVERRIDE;
+  virtual void AddObserver(Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(Observer* observer) OVERRIDE;
+  virtual Properties* GetProperties() OVERRIDE;
+
+  // Methods to simulate adapters getting added and removed.
+  void AddAdapter(const std::string& adapter_path);
+  void RemoveAdapter(const std::string& adapter_path);
+
+  // Default path of an adapter that is simulated for testing.
+  static const char kDefaultAdapterPath[];
+
+ private:
+  // Property callback passed when we create Properties* structures.
+  void OnPropertyChanged(const std::string& property_name);
+
+  // List of observers interested in event notifications.
+  ObserverList<Observer> observers_;
+
+  // Set containing the currently simulated adapters.
+  std::set<dbus::ObjectPath> adapters_;
+
+  // Fake properties object. This gets updated whenever AddAdapter or
+  // RemoveAdapter gets called.
+  scoped_ptr<Properties> properties_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeNfcManagerClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_NFC_MANAGER_CLIENT_H_
diff --git a/chromeos/dbus/fake_power_manager_client.cc b/chromeos/dbus/fake_power_manager_client.cc
index 3c70a6f..81ca360 100644
--- a/chromeos/dbus/fake_power_manager_client.cc
+++ b/chromeos/dbus/fake_power_manager_client.cc
@@ -51,6 +51,10 @@
   return base::Closure();
 }
 
+int FakePowerManagerClient::GetNumPendingSuspendReadinessCallbacks() {
+  return 0;
+}
+
 bool FakePowerManagerClient::HasObserver(Observer* observer) {
   return false;
 }
diff --git a/chromeos/dbus/fake_power_manager_client.h b/chromeos/dbus/fake_power_manager_client.h
index d89bb51..ae1adc5 100644
--- a/chromeos/dbus/fake_power_manager_client.h
+++ b/chromeos/dbus/fake_power_manager_client.h
@@ -47,6 +47,7 @@
       const power_manager::PowerManagementPolicy& policy) OVERRIDE;
   virtual void SetIsProjecting(bool is_projecting) OVERRIDE;
   virtual base::Closure GetSuspendReadinessCallback() OVERRIDE;
+  virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE;
 
   power_manager::PowerManagementPolicy& get_policy() { return policy_; }
 
diff --git a/chromeos/dbus/mock_cryptohome_client.h b/chromeos/dbus/mock_cryptohome_client.h
index cdb1ad8..c8232da 100644
--- a/chromeos/dbus/mock_cryptohome_client.h
+++ b/chromeos/dbus/mock_cryptohome_client.h
@@ -37,7 +37,7 @@
                     const AsyncMethodCallback& callback));
   MOCK_METHOD2(AsyncRemove, void(const std::string& username,
                                  const AsyncMethodCallback& callback));
-  MOCK_METHOD1(GetSystemSalt, bool(std::vector<uint8>* salt));
+  MOCK_METHOD1(GetSystemSalt, void(const GetSystemSaltCallback& callback));
   MOCK_METHOD2(GetSanitizedUsername,
                void(const std::string& username,
                     const StringDBusMethodCallback& callback));
diff --git a/chromeos/dbus/mock_dbus_thread_manager.cc b/chromeos/dbus/mock_dbus_thread_manager.cc
index a6eb16b..95901b1 100644
--- a/chromeos/dbus/mock_dbus_thread_manager.cc
+++ b/chromeos/dbus/mock_dbus_thread_manager.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/dbus/mock_dbus_thread_manager.h"
 
+#include "base/message_loop/message_loop.h"
 #include "chromeos/dbus/dbus_thread_manager_observer.h"
 #include "chromeos/dbus/fake_bluetooth_adapter_client.h"
 #include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
@@ -11,6 +12,8 @@
 #include "chromeos/dbus/fake_bluetooth_input_client.h"
 #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
 #include "chromeos/dbus/fake_gsm_sms_client.h"
+#include "chromeos/dbus/fake_nfc_adapter_client.h"
+#include "chromeos/dbus/fake_nfc_manager_client.h"
 #include "chromeos/dbus/fake_shill_device_client.h"
 #include "chromeos/dbus/fake_shill_ipconfig_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_client.h"
@@ -24,24 +27,25 @@
 #include "chromeos/dbus/power_policy_controller.h"
 
 using ::testing::AnyNumber;
+using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::ReturnNull;
-using ::testing::SetArgumentPointee;
 using ::testing::_;
 
 namespace chromeos {
 
 namespace {
 
-std::vector<uint8>* GetMockSystemSalt() {
-  static std::vector<uint8>* s_system_salt = NULL;
-  if (!s_system_salt) {
-    const char kStubSystemSalt[] = "stub_system_salt";
-    s_system_salt = new std::vector<uint8>();
-    s_system_salt->assign(kStubSystemSalt,
-                          kStubSystemSalt + arraysize(kStubSystemSalt) - 1);
-  }
-  return s_system_salt;
+void GetMockSystemSalt(
+    const CryptohomeClient::GetSystemSaltCallback& callback) {
+  const char kStubSystemSalt[] = "stub_system_salt";
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 DBUS_METHOD_CALL_SUCCESS,
+                 std::vector<uint8>(
+                     kStubSystemSalt,
+                     kStubSystemSalt + arraysize(kStubSystemSalt) - 1)));
 }
 
 }  // namespace
@@ -55,6 +59,8 @@
       fake_bluetooth_profile_manager_client_(
           new FakeBluetoothProfileManagerClient),
       fake_gsm_sms_client_(new FakeGsmSMSClient),
+      fake_nfc_adapter_client_(new FakeNfcAdapterClient()),
+      fake_nfc_manager_client_(new FakeNfcManagerClient()),
       fake_shill_device_client_(new FakeShillDeviceClient),
       fake_shill_ipconfig_client_(new FakeShillIPConfigClient),
       mock_cryptohome_client_(new MockCryptohomeClient),
@@ -74,6 +80,10 @@
       .WillRepeatedly(Return(fake_bluetooth_input_client_.get()));
   EXPECT_CALL(*this, GetBluetoothProfileManagerClient())
       .WillRepeatedly(Return(fake_bluetooth_profile_manager_client()));
+  EXPECT_CALL(*this, GetNfcAdapterClient())
+      .WillRepeatedly(Return(fake_nfc_adapter_client()));
+  EXPECT_CALL(*this, GetNfcManagerClient())
+      .WillRepeatedly(Return(fake_nfc_manager_client()));
   EXPECT_CALL(*this, GetShillDeviceClient())
       .WillRepeatedly(Return(fake_shill_device_client()));
   EXPECT_CALL(*this, GetShillIPConfigClient())
@@ -109,8 +119,7 @@
       .Times(AnyNumber());
   // Called from various locations.
   EXPECT_CALL(*mock_cryptohome_client_.get(), GetSystemSalt(_))
-      .WillRepeatedly(DoAll(SetArgumentPointee<0>(*GetMockSystemSalt()),
-                            Return(true)));
+      .WillRepeatedly(Invoke(&GetMockSystemSalt));
   EXPECT_CALL(*mock_cryptohome_client_.get(), TpmIsEnabled(_))
       .Times(AnyNumber());
 
diff --git a/chromeos/dbus/mock_dbus_thread_manager.h b/chromeos/dbus/mock_dbus_thread_manager.h
index 80ea9cf..5fe6675 100644
--- a/chromeos/dbus/mock_dbus_thread_manager.h
+++ b/chromeos/dbus/mock_dbus_thread_manager.h
@@ -26,6 +26,8 @@
 class FakeBluetoothInputClient;
 class FakeBluetoothProfileManagerClient;
 class FakeGsmSMSClient;
+class FakeNfcAdapterClient;
+class FakeNfcManagerClient;
 class FakeShillDeviceClient;
 class FakeShillIPConfigClient;
 class MockCryptohomeClient;
@@ -71,6 +73,8 @@
   MOCK_METHOD0(GetImageBurnerClient, ImageBurnerClient*(void));
   MOCK_METHOD0(GetIntrospectableClient, IntrospectableClient*(void));
   MOCK_METHOD0(GetModemMessagingClient, ModemMessagingClient*(void));
+  MOCK_METHOD0(GetNfcAdapterClient, NfcAdapterClient*(void));
+  MOCK_METHOD0(GetNfcManagerClient, NfcManagerClient*(void));
   MOCK_METHOD0(GetPermissionBrokerClient, PermissionBrokerClient*(void));
   MOCK_METHOD0(GetPowerManagerClient, PowerManagerClient*(void));
   MOCK_METHOD0(GetPowerPolicyController, PowerPolicyController*(void));
@@ -103,6 +107,12 @@
   FakeGsmSMSClient* fake_gsm_sms_client() {
     return fake_gsm_sms_client_.get();
   }
+  FakeNfcAdapterClient* fake_nfc_adapter_client() {
+    return fake_nfc_adapter_client_.get();
+  }
+  FakeNfcManagerClient* fake_nfc_manager_client() {
+    return fake_nfc_manager_client_.get();
+  }
   FakeShillDeviceClient* fake_shill_device_client() {
     return fake_shill_device_client_.get();
   }
@@ -138,6 +148,8 @@
   scoped_ptr<FakeBluetoothProfileManagerClient>
       fake_bluetooth_profile_manager_client_;
   scoped_ptr<FakeGsmSMSClient> fake_gsm_sms_client_;
+  scoped_ptr<FakeNfcAdapterClient> fake_nfc_adapter_client_;
+  scoped_ptr<FakeNfcManagerClient> fake_nfc_manager_client_;
   scoped_ptr<FakeShillDeviceClient> fake_shill_device_client_;
   scoped_ptr<FakeShillIPConfigClient> fake_shill_ipconfig_client_;
   scoped_ptr<MockCryptohomeClient> mock_cryptohome_client_;
diff --git a/chromeos/dbus/nfc_adapter_client.cc b/chromeos/dbus/nfc_adapter_client.cc
new file mode 100644
index 0000000..0557dd8
--- /dev/null
+++ b/chromeos/dbus/nfc_adapter_client.cc
@@ -0,0 +1,250 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/nfc_adapter_client.h"
+
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/strings/stringprintf.h"
+#include "chromeos/dbus/fake_nfc_adapter_client.h"
+#include "chromeos/dbus/nfc_manager_client.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+NfcAdapterClient::Properties::Properties(
+    dbus::ObjectProxy* object_proxy,
+    const PropertyChangedCallback& callback)
+    : NfcPropertySet(object_proxy,
+                     nfc_adapter::kNfcAdapterInterface,
+                     callback) {
+  RegisterProperty(nfc_adapter::kModeProperty, &mode);
+  RegisterProperty(nfc_adapter::kPoweredProperty, &powered);
+  RegisterProperty(nfc_adapter::kPollingProperty, &polling);
+  RegisterProperty(nfc_adapter::kProtocolsProperty, &protocols);
+  RegisterProperty(nfc_adapter::kTagsProperty, &tags);
+  RegisterProperty(nfc_adapter::kDevicesProperty, &devices);
+}
+
+NfcAdapterClient::Properties::~Properties() {
+}
+
+// The NfcAdapterClient implementation used in production.
+class NfcAdapterClientImpl
+    : public NfcAdapterClient,
+      public NfcManagerClient::Observer,
+      public nfc_client_helpers::DBusObjectMap::Delegate {
+ public:
+  explicit NfcAdapterClientImpl(NfcManagerClient* manager_client)
+      : initial_adapters_received_(false),
+        bus_(NULL),
+        manager_client_(manager_client),
+        weak_ptr_factory_(this) {
+    DCHECK(manager_client);
+  }
+
+  virtual ~NfcAdapterClientImpl() {
+    manager_client_->RemoveObserver(this);
+  }
+
+  // NfcAdapterClient override.
+  virtual void AddObserver(NfcAdapterClient::Observer* observer) OVERRIDE {
+    DCHECK(observer);
+    observers_.AddObserver(observer);
+  }
+
+  // NfcAdapterClient override.
+  virtual void RemoveObserver(NfcAdapterClient::Observer* observer) OVERRIDE {
+    DCHECK(observer);
+    observers_.RemoveObserver(observer);
+  }
+
+  // NfcAdapterClient override.
+  virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
+      OVERRIDE {
+    return static_cast<Properties*>(
+        object_map_->GetObjectProperties(object_path));
+  }
+
+  // NfcAdapterClient override.
+  virtual void StartPollLoop(
+      const dbus::ObjectPath& object_path,
+      const std::string& mode,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE {
+    dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path);
+    if (!object_proxy) {
+      std::string error_message =
+          base::StringPrintf("NFC adapter with object path \"%s\" does not "
+                             "exist.", object_path.value().c_str());
+      LOG(ERROR) << error_message;
+      error_callback.Run(nfc_client_helpers::kUnknownObjectError,
+                         error_message);
+      return;
+    }
+    dbus::MethodCall method_call(nfc_adapter::kNfcAdapterInterface,
+                                 nfc_adapter::kStartPollLoop);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(mode);
+    object_proxy->CallMethodWithErrorCallback(
+        &method_call,
+        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::Bind(&nfc_client_helpers::OnSuccess, callback),
+        base::Bind(&nfc_client_helpers::OnError, error_callback));
+  }
+
+  // NfcAdapterClient override.
+  virtual void StopPollLoop(
+      const dbus::ObjectPath& object_path,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE {
+    dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path);
+    if (!object_proxy) {
+      std::string error_message =
+          base::StringPrintf("NFC adapter with object path \"%s\" does not "
+                             "exist.", object_path.value().c_str());
+      LOG(ERROR) << error_message;
+      error_callback.Run(nfc_client_helpers::kUnknownObjectError,
+                         error_message);
+      return;
+    }
+    dbus::MethodCall method_call(nfc_adapter::kNfcAdapterInterface,
+                                 nfc_adapter::kStopPollLoop);
+    object_proxy->CallMethodWithErrorCallback(
+        &method_call,
+        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::Bind(&nfc_client_helpers::OnSuccess, callback),
+        base::Bind(&nfc_client_helpers::OnError, error_callback));
+  }
+
+ protected:
+  // DBusClient override.
+  virtual void Init(dbus::Bus* bus) OVERRIDE {
+    VLOG(1) << "Creating NfcAdapterClientImpl";
+    DCHECK(bus);
+    bus_ = bus;
+    object_map_.reset(new nfc_client_helpers::DBusObjectMap(
+        nfc_adapter::kNfcAdapterServiceName, this, bus));
+    DCHECK(manager_client_);
+    manager_client_->AddObserver(this);
+  }
+
+ private:
+  // NfcManagerClient::Observer override.
+  virtual void AdapterAdded(const dbus::ObjectPath& object_path) OVERRIDE {
+    VLOG(1) << "AdapterAdded: " << object_path.value();
+    // Initialize the object proxy here, so that observers can start receiving
+    // notifications for it and it is cached for reuse. Note that, even if we
+    // miss this signal, a proxy will be created on demand for any object paths
+    // that are passed to the public methods later.
+    object_map_->AddObject(object_path);
+    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
+                      AdapterAdded(object_path));
+  }
+
+  // NfcManagerClient::Observer override.
+  virtual void AdapterRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
+    VLOG(1) << "AdapterRemoved: " << object_path.value();
+    // Remove the object proxy, as we know that the adapter no longer exists.
+    // Note that this doesn't prevent a client from recreating a proxy for an
+    // object path that is no longer valid, as proxies are created on demand as
+    // necessary by the public methods.
+    object_map_->RemoveObject(object_path);
+    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
+                      AdapterRemoved(object_path));
+  }
+
+  // NfcManagerClient::Observer override.
+  virtual void ManagerPropertyChanged(const std::string& property_name)
+        OVERRIDE {
+    NfcManagerClient::Properties* manager_properties =
+        manager_client_->GetProperties();
+    if (!initial_adapters_received_ &&
+        property_name == manager_properties->adapters.name()) {
+      initial_adapters_received_ = true;
+      VLOG(1) << "Initial set of adapters received.";
+      // Create proxies for all adapters that are known to the manager, so that
+      // observers can start getting notified for any signals emitted by
+      // adapters. We use the PropertyChanged signal from manager only to
+      // create proxies for the initial fetch. We rely on the AdapterAdded and
+      // AdapterRemoved signals after that.
+      std::vector<dbus::ObjectPath> adapters =
+          manager_properties->adapters.value();
+      for (std::vector<dbus::ObjectPath>::iterator iter = adapters.begin();
+           iter != adapters.end(); ++iter) {
+        VLOG(1) << "Creating proxy for: " << iter->value();
+        object_map_->AddObject(*iter);
+      }
+    }
+  }
+
+  // nfc_client_helpers::DBusObjectMap::Delegate override.
+  virtual NfcPropertySet* CreateProperties(
+      dbus::ObjectProxy* object_proxy) OVERRIDE {
+    return new Properties(
+        object_proxy,
+        base::Bind(&NfcAdapterClientImpl::OnPropertyChanged,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   object_proxy->object_path()));
+  }
+
+  // Called by NfcPropertySet when a property value is changed, either by
+  // result of a signal or response to a GetAll() or Get() call.
+  void OnPropertyChanged(const dbus::ObjectPath& object_path,
+                         const std::string& property_name) {
+    VLOG(1) << "Adapter property changed; Path: " << object_path.value()
+            << " Property: " << property_name;
+    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
+                      AdapterPropertyChanged(object_path, property_name));
+  }
+
+  // This variable stores whether or not we have ever been notified of
+  // ManagerPropertiesChanged. This is used to bootstrap adapter proxies
+  // after receiving the initial set of properties from the NFC manager.
+  bool initial_adapters_received_;
+
+  // We maintain a pointer to the bus to be able to request proxies for
+  // new NFC adapters that appear.
+  dbus::Bus* bus_;
+
+  // Mapping from object paths to object proxies and properties structures that
+  // were already created by us.
+  scoped_ptr<nfc_client_helpers::DBusObjectMap> object_map_;
+
+  // The manager client that we listen to events notifications from.
+  NfcManagerClient* manager_client_;
+
+  // List of observers interested in event notifications.
+  ObserverList<NfcAdapterClient::Observer> observers_;
+
+  // Weak pointer factory for generating 'this' pointers that might live longer
+  // than we do.
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<NfcAdapterClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(NfcAdapterClientImpl);
+};
+
+NfcAdapterClient::NfcAdapterClient() {
+}
+
+NfcAdapterClient::~NfcAdapterClient() {
+}
+
+NfcAdapterClient* NfcAdapterClient::Create(DBusClientImplementationType type,
+                                           NfcManagerClient* manager_client) {
+  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
+    return new NfcAdapterClientImpl(manager_client);
+  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
+  return new FakeNfcAdapterClient();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/nfc_adapter_client.h b/chromeos/dbus/nfc_adapter_client.h
new file mode 100644
index 0000000..b55c93a
--- /dev/null
+++ b/chromeos/dbus/nfc_adapter_client.h
@@ -0,0 +1,127 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_NFC_ADAPTER_CLIENT_H_
+#define CHROMEOS_DBUS_NFC_ADAPTER_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_client_implementation_type.h"
+#include "chromeos/dbus/nfc_client_helpers.h"
+#include "chromeos/dbus/nfc_property_set.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "dbus/property.h"
+
+namespace chromeos {
+
+class NfcManagerClient;
+
+// NfcAdapterClient is used to communicate with objects representing local NFC
+// adapters.
+class CHROMEOS_EXPORT NfcAdapterClient : public DBusClient {
+ public:
+  // Structure of properties associated with an NFC adapter.
+  struct Properties : public NfcPropertySet {
+    // The adapter NFC radio mode. One of "Initiator", "Target", and "Idle".
+    // The NFC adapter will usually be in the "Idle" mode. The mode will change
+    // to "Initiator" or "Target" based on how a pairing is established with a
+    // remote tag or device.
+    dbus::Property<std::string> mode;
+
+    // The adapter's current power state.
+    dbus::Property<bool> powered;
+
+    // Indicates whether or not the adapter is currently polling for targets.
+    // This property is only valid when |mode| is "Initiator".
+    dbus::Property<bool> polling;
+
+    // The NFC protocols that are supported by the adapter. Possible values
+    // are: "Felica", "MIFARE", "Jewel", "ISO-DEP", and "NFC-DEP".
+    dbus::Property<std::vector<std::string> > protocols;
+
+    // The object paths of the NFC tags that are known to the local adapter.
+    // These are tags that have been "tapped" on the local adapter.
+    dbus::Property<std::vector<dbus::ObjectPath> > tags;
+
+    // The object paths of the remote NFC devices that have been found by the
+    // local adapter. These are NFC adapters that were "tapped" on the local
+    // adapter.
+    dbus::Property<std::vector<dbus::ObjectPath> > devices;
+
+    Properties(dbus::ObjectProxy* object_proxy,
+               const PropertyChangedCallback& callback);
+    virtual ~Properties();
+  };
+
+  // Interface for observing changes from a local NFC adapter.
+  class Observer {
+   public:
+    virtual ~Observer() {}
+
+    // Called when a new adapter with object path |object_path| is added to the
+    // system.
+    virtual void AdapterAdded(const dbus::ObjectPath& object_path) {}
+
+    // Called when an adapter with object path |object_path| is removed from the
+    // system.
+    virtual void AdapterRemoved(const dbus::ObjectPath& object_path) {}
+
+    // Called when the adapter property with the name |property_name| on adapter
+    // with object path |object_path| has acquired a new value.
+    virtual void AdapterPropertyChanged(const dbus::ObjectPath& object_path,
+                                        const std::string& property_name) {}
+  };
+
+  virtual ~NfcAdapterClient();
+
+  // Adds and removes observers for events on all local bluetooth adapters.
+  // Check the |object_path| parameter of the observer methods to determine
+  // which adapter is issuing the event.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Obtains the properties for the adapter with object path |object_path|, any
+  // values should be copied if needed. A NULL pointer will be returned, if no
+  // adapter with the given object path is known to exist.
+  virtual Properties* GetProperties(const dbus::ObjectPath& object_path) = 0;
+
+  // Starts the polling loop for the adapter with object path |object_path|.
+  // Depending on the mode, the adapter will start polling for targets,
+  // listening to NFC devices, or both. The |mode| parameter should be one of
+  // "Initiator", "Target", or "Dual". The "Dual" mode will have the adapter
+  // alternate between "Initiator" and "Target" modes during the polling loop.
+  // For any other value, the adapter will default to "Initiator" mode.
+  virtual void StartPollLoop(
+      const dbus::ObjectPath& object_path,
+      const std::string& mode,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) = 0;
+
+  // Stops the polling loop for the adapter with object_path |object_path|.
+  virtual void StopPollLoop(
+      const dbus::ObjectPath& object_path,
+      const base::Closure& callback,
+      const nfc_client_helpers::ErrorCallback& error_callback) = 0;
+
+  // Creates the instance.
+  static NfcAdapterClient* Create(DBusClientImplementationType type,
+                                  NfcManagerClient* manager_client);
+
+ protected:
+  friend class NfcClientTest;
+
+  NfcAdapterClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NfcAdapterClient);
+};
+
+}  // namespace chromeos
+
+#endif   // CHROMEOS_DBUS_NFC_ADAPTER_CLIENT_H_
diff --git a/chromeos/dbus/nfc_client_helpers.cc b/chromeos/dbus/nfc_client_helpers.cc
new file mode 100644
index 0000000..12ae6c0
--- /dev/null
+++ b/chromeos/dbus/nfc_client_helpers.cc
@@ -0,0 +1,114 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/nfc_client_helpers.h"
+
+namespace chromeos {
+namespace nfc_client_helpers {
+
+const char kNoResponseError[] = "org.chromium.Error.NoResponse";
+const char kUnknownObjectError[] = "org.chromium.Error.UnknownObject";
+
+void OnSuccess(const base::Closure& callback, dbus::Response* response) {
+  DCHECK(response);
+  callback.Run();
+}
+
+void OnError(const ErrorCallback& error_callback,
+             dbus::ErrorResponse* response) {
+  // Error response has optional error message argument.
+  std::string error_name;
+  std::string error_message;
+  if (response) {
+    dbus::MessageReader reader(response);
+    error_name = response->GetErrorName();
+    reader.PopString(&error_message);
+  } else {
+    error_name = kNoResponseError;
+    error_message = "";
+  }
+  error_callback.Run(error_name, error_message);
+}
+
+DBusObjectMap::DBusObjectMap(const std::string& service_name,
+                             Delegate* delegate,
+                             dbus::Bus* bus)
+    : bus_(bus),
+      service_name_(service_name),
+      delegate_(delegate) {
+  DCHECK(bus_);
+  DCHECK(delegate_);
+}
+
+DBusObjectMap::~DBusObjectMap() {
+  // Clean up the Properties structures. We don't explicitly delete the object
+  // proxies, as they are owned by dbus::Bus.
+  for (ObjectMap::iterator iter = object_map_.begin();
+       iter != object_map_.end(); ++iter) {
+    ObjectPropertyPair pair = iter->second;
+    CleanUpObjectPropertyPair(pair);
+  }
+}
+
+dbus::ObjectProxy* DBusObjectMap::GetObjectProxy(
+    const dbus::ObjectPath& object_path) {
+  return GetObjectPropertyPair(object_path).first;
+}
+
+NfcPropertySet* DBusObjectMap::GetObjectProperties(
+    const dbus::ObjectPath& object_path) {
+  return GetObjectPropertyPair(object_path).second;
+}
+
+bool DBusObjectMap::AddObject(const dbus::ObjectPath& object_path) {
+  ObjectMap::iterator iter = object_map_.find(object_path);
+  if (iter != object_map_.end())
+    return false;
+
+  DCHECK(bus_);
+  dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name_,
+                                                         object_path);
+
+  // Create the properties structure.
+  NfcPropertySet* properties = delegate_->CreateProperties(object_proxy);
+  properties->ConnectSignals();
+  properties->GetAll();
+  VLOG(1) << "Created proxy for object with Path: " << object_path.value()
+          << " Service: " << service_name_;
+  ObjectPropertyPair object = std::make_pair(object_proxy, properties);
+  object_map_[object_path] = object;
+  return true;
+}
+
+void DBusObjectMap::RemoveObject(const dbus::ObjectPath& object_path) {
+  DCHECK(bus_);
+  ObjectMap::iterator iter = object_map_.find(object_path);
+  if (iter == object_map_.end())
+    return;
+  // Clean up the object proxy and the properties structure.
+  ObjectPropertyPair pair = iter->second;
+  CleanUpObjectPropertyPair(pair);
+  object_map_.erase(iter);
+}
+
+DBusObjectMap::ObjectPropertyPair DBusObjectMap::GetObjectPropertyPair(
+    const dbus::ObjectPath& object_path) {
+  ObjectMap::iterator iter = object_map_.find(object_path);
+  if (iter != object_map_.end())
+    return iter->second;
+  return std::make_pair(static_cast<dbus::ObjectProxy*>(NULL),
+                        static_cast<NfcPropertySet*>(NULL));
+}
+
+void DBusObjectMap::CleanUpObjectPropertyPair(const ObjectPropertyPair& pair) {
+  dbus::ObjectProxy* object_proxy = pair.first;
+  NfcPropertySet* properties = pair.second;
+  bus_->RemoveObjectProxy(service_name_,
+                          object_proxy->object_path(),
+                          base::Bind(&base::DoNothing));
+  delete properties;
+}
+
+}  // namespace nfc_client_helpers
+}  // namespace chromeos
diff --git a/chromeos/dbus/nfc_client_helpers.h b/chromeos/dbus/nfc_client_helpers.h
new file mode 100644
index 0000000..d910369
--- /dev/null
+++ b/chromeos/dbus/nfc_client_helpers.h
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_NFC_CLIENT_HELPERS_H_
+#define CHROMEOS_DBUS_NFC_CLIENT_HELPERS_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/nfc_property_set.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+namespace nfc_client_helpers {
+
+  // Constants used to indicate exceptional error conditions.
+CHROMEOS_EXPORT extern const char kNoResponseError[];
+CHROMEOS_EXPORT extern const char kUnknownObjectError[];
+
+// The ErrorCallback is used by D-Bus methods to indicate failure.
+// It receives two arguments: the name of the error in |error_name| and
+// an optional message in |error_message|.
+typedef base::Callback<void(const std::string& error_name,
+                            const std::string& error_message)> ErrorCallback;
+
+
+// Called when a response for a successful method call is received.
+CHROMEOS_EXPORT void OnSuccess(const base::Closure& callback,
+                               dbus::Response* response);
+
+// Extracts the error data from |response| and invokes |error_callback| with
+// the resulting error name and error message.
+CHROMEOS_EXPORT void OnError(const ErrorCallback& error_callback,
+                             dbus::ErrorResponse* response);
+
+// DBusObjectMap is a simple data structure that facilitates keeping track of
+// D-Bus object proxies and properties. It maintains a mapping from object
+// paths to object proxy - property structure pairs.
+// TODO(armansito): This is only needed until neard implements the D-Bus
+// org.freedesktop.DBus.ObjectManager interface. Remove this once we upgrade
+// to neard-0.14.
+class CHROMEOS_EXPORT DBusObjectMap {
+ public:
+  // DBusObjectMap::Delegate must be implemented by classes that use an
+  // instance of DBusObjectMap to manage object proxies.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Called by DBusObjectMap to create a Properties structure for the remote
+    // D-Bus object accessible through |object_proxy|. The implementation class
+    // should create and return an instance of its own subclass of
+    // ::chromeos::NfcPropertySet. DBusObjectMap will handle connecting the
+    // signals and update the properties.
+    virtual NfcPropertySet* CreateProperties(
+        dbus::ObjectProxy* object_proxy) = 0;
+  };
+
+  // Constructor takes in the D-Bus service name the proxies belong to and
+  // the delegate which will be used to construct properties structures.
+  // |service_name| must be a valid D-Bus service name, and |delegate| cannot
+  // be NULL.
+  DBusObjectMap(const std::string& service_name,
+                Delegate* delegate,
+                dbus::Bus* bus);
+  virtual ~DBusObjectMap();
+
+  // Returns the object proxy for object path |object_path|. If no object proxy
+  // exists for |object_path|, returns NULL.
+  dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path);
+
+  // Returns the properties structure for remote object with object path
+  // |object_path|. If no properties structure exists for |object_path|,
+  // returns NULL.
+  NfcPropertySet* GetObjectProperties(const dbus::ObjectPath& object_path);
+
+  // Creates and stores an object proxy and properties structure for a remote
+  // object with object path |object_path|. If an object proxy was already
+  // created, this operation returns false; returns true otherwise.
+  bool AddObject(const dbus::ObjectPath& object_path);
+
+  // Removes the D-Bus object proxy and the properties structure for the
+  // remote object with object path |object_path|.
+  void RemoveObject(const dbus::ObjectPath& object_path);
+
+ private:
+  typedef std::pair<dbus::ObjectProxy*, NfcPropertySet*> ObjectPropertyPair;
+  typedef std::map<dbus::ObjectPath, ObjectPropertyPair> ObjectMap;
+
+  // Returns an instance of ObjectPropertyPair by looking up |object_path| in
+  // |object_map_|. If no entry is found, returns an instance that contains
+  // NULL pointers.
+  ObjectPropertyPair GetObjectPropertyPair(const dbus::ObjectPath& object_path);
+
+  // Cleans up the object proxy and properties structure in |pair|. This method
+  // will remove the object proxy by calling |dbus::Bus::RemoveObjectProxy| and
+  // explicitly deallocate the properties structure. Once this method exits,
+  // both pointers stored by |pair| will become invalid and should not be used.
+  // If |pair| contains invalid pointers at the time when this method is called
+  // memory errors are likely to happen, so only valid pointers should be
+  // passed.
+  void CleanUpObjectPropertyPair(const ObjectPropertyPair& pair);
+
+  dbus::Bus* bus_;
+  ObjectMap object_map_;
+  std::string service_name_;
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusObjectMap);
+};
+
+}  // namespace nfc_client_helpers
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_NFC_CLIENT_HELPERS_H_
diff --git a/chromeos/dbus/nfc_client_unittest.cc b/chromeos/dbus/nfc_client_unittest.cc
new file mode 100644
index 0000000..f62fc42
--- /dev/null
+++ b/chromeos/dbus/nfc_client_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2013 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/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "chromeos/dbus/nfc_adapter_client.h"
+#include "chromeos/dbus/nfc_client_helpers.h"
+#include "chromeos/dbus/nfc_manager_client.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Return;
+
+namespace chromeos {
+
+namespace {
+
+// D-Bus service name used by the test.
+const char kTestServiceName[] = "test.service.name";
+
+// Object paths that are used for testing.
+const char kTestManagerPath[] = "/test/nfc/manager";
+const char kTestAdapterPath0[] = "/test/nfc/adapter0";
+const char kTestAdapterPath1[] = "/test/nfc/adapter1";
+
+class MockNfcManagerObserver : public NfcManagerClient::Observer {
+ public:
+  MOCK_METHOD1(AdapterAdded, void(const dbus::ObjectPath&));
+  MOCK_METHOD1(AdapterRemoved, void(const dbus::ObjectPath&));
+  MOCK_METHOD1(ManagerPropertyChanged, void(const std::string&));
+};
+
+class MockNfcAdapterObserver : public NfcAdapterClient::Observer {
+ public:
+  MOCK_METHOD1(AdapterAdded, void(const dbus::ObjectPath&));
+  MOCK_METHOD1(AdapterRemoved, void(const dbus::ObjectPath&));
+  MOCK_METHOD2(AdapterPropertyChanged, void(const dbus::ObjectPath&,
+                                            const std::string&));
+};
+
+}  // namespace
+
+class NfcClientTest : public testing::Test {
+ public:
+  NfcClientTest() : response_(NULL) {}
+  virtual ~NfcClientTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    // Create the mock bus.
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    mock_bus_ = new dbus::MockBus(options);
+
+    // Create the mock proxies.
+    mock_manager_proxy_ = new dbus::MockObjectProxy(
+        mock_bus_.get(),
+        kTestServiceName,
+        dbus::ObjectPath(kTestManagerPath));
+    mock_adapter0_proxy_ = new dbus::MockObjectProxy(
+        mock_bus_.get(),
+        kTestServiceName,
+        dbus::ObjectPath(kTestAdapterPath0));
+    mock_adapter1_proxy_ = new dbus::MockObjectProxy(
+        mock_bus_.get(),
+        kTestServiceName,
+        dbus::ObjectPath(kTestAdapterPath1));
+
+    // Set expectations that use NfcClientTest::OnConnectToSignal when the
+    // client connect signals on the mock proxies.
+    EXPECT_CALL(*mock_manager_proxy_.get(), ConnectToSignal(_, _, _, _))
+        .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal));
+    EXPECT_CALL(*mock_adapter0_proxy_.get(), ConnectToSignal(_, _, _, _))
+        .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal));
+    EXPECT_CALL(*mock_adapter1_proxy_.get(), ConnectToSignal(_, _, _, _))
+        .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal));
+
+    // Set expectations that return our mock proxies on demand.
+    EXPECT_CALL(
+        *mock_bus_.get(),
+        GetObjectProxy(nfc_manager::kNfcManagerServiceName,
+                       dbus::ObjectPath(nfc_manager::kNfcManagerServicePath)))
+        .WillRepeatedly(Return(mock_manager_proxy_.get()));
+    EXPECT_CALL(*mock_bus_.get(),
+                GetObjectProxy(nfc_adapter::kNfcAdapterServiceName,
+                               dbus::ObjectPath(kTestAdapterPath0)))
+        .WillRepeatedly(Return(mock_adapter0_proxy_.get()));
+    EXPECT_CALL(*mock_bus_.get(),
+                GetObjectProxy(nfc_adapter::kNfcAdapterServiceName,
+                               dbus::ObjectPath(kTestAdapterPath1)))
+        .WillRepeatedly(Return(mock_adapter1_proxy_.get()));
+
+    // ShutdownAndBlock will be called in TearDown.
+    EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
+
+    // Create the clients.
+    manager_client_.reset(
+        NfcManagerClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION));
+    adapter_client_.reset(
+        NfcAdapterClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION,
+                                 manager_client_.get()));
+    manager_client_->Init(mock_bus_.get());
+    adapter_client_->Init(mock_bus_.get());
+    manager_client_->AddObserver(&mock_manager_observer_);
+    adapter_client_->AddObserver(&mock_adapter_observer_);
+
+    message_loop_.RunUntilIdle();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    adapter_client_->RemoveObserver(&mock_adapter_observer_);
+    manager_client_->RemoveObserver(&mock_manager_observer_);
+    mock_bus_->ShutdownAndBlock();
+  }
+
+  void SendManagerAdapterAddedSignal(const dbus::ObjectPath& object_path) {
+    dbus::Signal signal(nfc_manager::kNfcManagerInterface,
+                        nfc_manager::kAdapterAddedSignal);
+    dbus::MessageWriter writer(&signal);
+    writer.AppendObjectPath(object_path);
+    ASSERT_FALSE(manager_adapter_added_signal_callback_.is_null());
+    manager_adapter_added_signal_callback_.Run(&signal);
+  }
+
+  void SendManagerAdapterRemovedSignal(const dbus::ObjectPath& object_path) {
+    dbus::Signal signal(nfc_manager::kNfcManagerInterface,
+                        nfc_manager::kAdapterRemovedSignal);
+    dbus::MessageWriter writer(&signal);
+    writer.AppendObjectPath(object_path);
+    ASSERT_FALSE(manager_adapter_removed_signal_callback_.is_null());
+    manager_adapter_removed_signal_callback_.Run(&signal);
+  }
+
+  MOCK_METHOD0(SuccessCallback, void(void));
+  MOCK_METHOD2(ErrorCallback, void(const std::string& error_name,
+                                   const std::string& error_message));
+
+ protected:
+  // The mock bus.
+  scoped_refptr<dbus::MockBus> mock_bus_;
+  // A message loop to emulate asynchronous behavior.
+  base::MessageLoop message_loop_;
+  // Response returned by mock methods.
+  dbus::Response* response_;
+  // The D-Bus client objects under test.
+  scoped_ptr<NfcManagerClient> manager_client_;
+  scoped_ptr<NfcAdapterClient> adapter_client_;
+  // Mock observers.
+  MockNfcManagerObserver mock_manager_observer_;
+  MockNfcAdapterObserver mock_adapter_observer_;
+  // The mock object proxies.
+  scoped_refptr<dbus::MockObjectProxy> mock_manager_proxy_;
+  scoped_refptr<dbus::MockObjectProxy> mock_adapter0_proxy_;
+  scoped_refptr<dbus::MockObjectProxy> mock_adapter1_proxy_;
+  // The signal callbacks used to simulate asychronous signals.
+  dbus::ObjectProxy::SignalCallback manager_adapter_added_signal_callback_;
+  dbus::ObjectProxy::SignalCallback manager_adapter_removed_signal_callback_;
+
+ private:
+  // Used to implement the mock proxy.
+  void OnConnectToSignal(
+      const std::string& interface_name,
+      const std::string& signal_name,
+      const dbus::ObjectProxy::SignalCallback& signal_callback,
+      const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
+    if (interface_name == nfc_manager::kNfcManagerInterface) {
+      if (signal_name == nfc_manager::kAdapterAddedSignal)
+        manager_adapter_added_signal_callback_ = signal_callback;
+      else if (signal_name == nfc_manager::kAdapterRemovedSignal)
+        manager_adapter_removed_signal_callback_ = signal_callback;
+    }
+    message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback,
+                                                 interface_name,
+                                                 signal_name,
+                                                 true));
+  }
+};
+
+// Tests that when adapters are added and removed through the manager, all
+// observers are notified and the proxies are created and removed
+// accordingly.
+TEST_F(NfcClientTest, AdaptersAddedAndRemoved) {
+  // Invoking methods on adapters that haven't been added should fail.
+  EXPECT_CALL(*this,
+              ErrorCallback(nfc_client_helpers::kUnknownObjectError, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath0),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Add adapter 0.
+  EXPECT_CALL(mock_manager_observer_,
+              AdapterAdded(dbus::ObjectPath(kTestAdapterPath0)));
+  EXPECT_CALL(mock_adapter_observer_,
+              AdapterAdded(dbus::ObjectPath(kTestAdapterPath0)));
+  SendManagerAdapterAddedSignal(dbus::ObjectPath(kTestAdapterPath0));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Invoking methods should succeed on adapter 0 but fail on adapter 1.
+  EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath0),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*this,
+              ErrorCallback(nfc_client_helpers::kUnknownObjectError, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath1),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Add adapter 1.
+  EXPECT_CALL(mock_manager_observer_,
+              AdapterAdded(dbus::ObjectPath(kTestAdapterPath1)));
+  EXPECT_CALL(mock_adapter_observer_,
+              AdapterAdded(dbus::ObjectPath(kTestAdapterPath1)));
+  SendManagerAdapterAddedSignal(dbus::ObjectPath(kTestAdapterPath1));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Invoking methods should succeed on both adapters.
+  EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _));
+  EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath0),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath1),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Remove adapter 0.
+  EXPECT_CALL(mock_manager_observer_,
+              AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0)));
+  EXPECT_CALL(mock_adapter_observer_,
+              AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0)));
+  SendManagerAdapterRemovedSignal(dbus::ObjectPath(kTestAdapterPath0));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Invoking methods should succeed on adapter 1 but fail on adapter 0.
+  EXPECT_CALL(*this,
+              ErrorCallback(nfc_client_helpers::kUnknownObjectError, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath0),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath1),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Remove adapter 1.
+  EXPECT_CALL(mock_manager_observer_,
+              AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1)));
+  EXPECT_CALL(mock_adapter_observer_,
+              AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1)));
+  SendManagerAdapterRemovedSignal(dbus::ObjectPath(kTestAdapterPath1));
+  Mock::VerifyAndClearExpectations(this);
+
+  // Invoking methods should fail on both adapters.
+  EXPECT_CALL(*this,
+              ErrorCallback(nfc_client_helpers::kUnknownObjectError, _))
+      .Times(2);
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath0),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+  adapter_client_->StartPollLoop(
+      dbus::ObjectPath(kTestAdapterPath1),
+      nfc_adapter::kModeInitiator,
+      base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)),
+      base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this)));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/nfc_manager_client.cc b/chromeos/dbus/nfc_manager_client.cc
new file mode 100644
index 0000000..6ee43a8
--- /dev/null
+++ b/chromeos/dbus/nfc_manager_client.cc
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/nfc_manager_client.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "chromeos/dbus/fake_nfc_manager_client.h"
+#include "dbus/bus.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+NfcManagerClient::Properties::Properties(
+    dbus::ObjectProxy* object_proxy,
+    const PropertyChangedCallback& callback)
+    : NfcPropertySet(object_proxy,
+                     nfc_manager::kNfcManagerInterface,
+                     callback) {
+  RegisterProperty(nfc_manager::kAdaptersProperty, &adapters);
+}
+
+NfcManagerClient::Properties::~Properties() {
+}
+
+
+// The NfcManagerClient implementation used in production.
+class NfcManagerClientImpl : public NfcManagerClient {
+ public:
+  NfcManagerClientImpl()
+      : object_proxy_(NULL),
+        weak_ptr_factory_(this) {
+  }
+
+  virtual ~NfcManagerClientImpl() {
+  }
+
+  // NfcManagerClient override.
+  virtual void AddObserver(Observer* observer) OVERRIDE {
+    DCHECK(observer);
+    observers_.AddObserver(observer);
+  }
+
+  // NfcManagerClient override.
+  virtual void RemoveObserver(Observer* observer) OVERRIDE {
+    DCHECK(observer);
+    observers_.RemoveObserver(observer);
+  }
+
+  // NfcManagerClient override.
+  virtual Properties* GetProperties() OVERRIDE {
+    return properties_.get();
+  }
+
+ protected:
+  // DBusClient override.
+  virtual void Init(dbus::Bus* bus) OVERRIDE {
+    VLOG(1) << "Creating NfcManagerClientImpl";
+
+    // Create the object proxy.
+    object_proxy_ = bus->GetObjectProxy(
+        nfc_manager::kNfcManagerServiceName,
+        dbus::ObjectPath(nfc_manager::kNfcManagerServicePath));
+
+    // Set up the signal handlers.
+    object_proxy_->ConnectToSignal(
+        nfc_manager::kNfcManagerInterface,
+        nfc_manager::kAdapterAddedSignal,
+        base::Bind(&NfcManagerClientImpl::AdapterAddedReceived,
+                   weak_ptr_factory_.GetWeakPtr()),
+        base::Bind(&NfcManagerClientImpl::AdapterAddedConnected,
+                   weak_ptr_factory_.GetWeakPtr()));
+
+    object_proxy_->ConnectToSignal(
+        nfc_manager::kNfcManagerInterface,
+        nfc_manager::kAdapterRemovedSignal,
+        base::Bind(&NfcManagerClientImpl::AdapterRemovedReceived,
+                   weak_ptr_factory_.GetWeakPtr()),
+        base::Bind(&NfcManagerClientImpl::AdapterRemovedConnected,
+                   weak_ptr_factory_.GetWeakPtr()));
+
+    // Create the properties structure.
+    properties_.reset(new Properties(
+        object_proxy_,
+        base::Bind(&NfcManagerClientImpl::OnPropertyChanged,
+                   weak_ptr_factory_.GetWeakPtr())));
+
+    properties_->ConnectSignals();
+    properties_->GetAll();
+  }
+
+ private:
+  // NFC manager signal handlers.
+  void OnPropertyChanged(const std::string& property_name) {
+    VLOG(1) << "NFC Manager property changed: " << property_name;
+    FOR_EACH_OBSERVER(Observer, observers_,
+                      ManagerPropertyChanged(property_name));
+  }
+
+  // Called by dbus:: when an "AdapterAdded" signal is received..
+  void AdapterAddedReceived(dbus::Signal* signal) {
+    DCHECK(signal);
+    dbus::MessageReader reader(signal);
+    dbus::ObjectPath object_path;
+    if (!reader.PopObjectPath(&object_path)) {
+      LOG(WARNING) << "AdapterAdded signal has incorrect parameters: "
+                   << signal->ToString();
+      return;
+    }
+    VLOG(1) << "Adapter added: " << object_path.value();
+    FOR_EACH_OBSERVER(Observer, observers_, AdapterAdded(object_path));
+  }
+
+  // Called by dbus:: when the "AdapterAdded" signal is initially connected.
+  void AdapterAddedConnected(const std::string& interface_name,
+                             const std::string& signal_name,
+                             bool success) {
+    LOG_IF(WARNING, !success) << "Failed to connect to AdapterAdded signal.";
+  }
+
+  // Called by dbus:: when an "AdapterRemoved" signal is received..
+  void AdapterRemovedReceived(dbus::Signal* signal) {
+    DCHECK(signal);
+    dbus::MessageReader reader(signal);
+    dbus::ObjectPath object_path;
+    if (!reader.PopObjectPath(&object_path)) {
+      LOG(WARNING) << "AdapterRemoved signal has incorrect parameters: "
+                   << signal->ToString();
+      return;
+    }
+    VLOG(1) << "Adapter removed: " << object_path.value();
+    FOR_EACH_OBSERVER(Observer, observers_, AdapterRemoved(object_path));
+  }
+
+  // Called by dbus:: when the "AdapterAdded" signal is initially connected.
+  void AdapterRemovedConnected(const std::string& interface_name,
+                               const std::string& signal_name,
+                               bool success) {
+    LOG_IF(WARNING, !success) << "Failed to connect to AdapterRemoved signal.";
+  }
+
+  // D-Bus proxy for neard Manager interface.
+  dbus::ObjectProxy* object_proxy_;
+
+  // Properties for neard Manager interface.
+  scoped_ptr<Properties> properties_;
+
+  // List of observers interested in event notifications.
+  ObserverList<NfcManagerClient::Observer> observers_;
+
+  // Weak pointer factory for generating 'this' pointers that might live longer
+  // than we do.
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<NfcManagerClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(NfcManagerClientImpl);
+};
+
+NfcManagerClient::NfcManagerClient() {
+}
+
+NfcManagerClient::~NfcManagerClient() {
+}
+
+// static
+NfcManagerClient* NfcManagerClient::Create(DBusClientImplementationType type) {
+  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
+    return new NfcManagerClientImpl();
+  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
+  return new FakeNfcManagerClient();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/nfc_manager_client.h b/chromeos/dbus/nfc_manager_client.h
new file mode 100644
index 0000000..200144c
--- /dev/null
+++ b/chromeos/dbus/nfc_manager_client.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_NFC_MANAGER_CLIENT_H_
+#define CHROMEOS_DBUS_NFC_MANAGER_CLIENT_H_
+
+#include <vector>
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_client_implementation_type.h"
+#include "chromeos/dbus/nfc_property_set.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "dbus/property.h"
+
+namespace chromeos {
+
+// NfcManagerClient is used to communicate with the neard Manager service.
+class CHROMEOS_EXPORT NfcManagerClient : public DBusClient {
+ public:
+  // Structure of properties associated with the NFC manager.
+  struct Properties : public NfcPropertySet {
+    // List of Adapter object paths.
+    dbus::Property<std::vector<dbus::ObjectPath> > adapters;
+
+    Properties(dbus::ObjectProxy* object_proxy,
+               const PropertyChangedCallback& callback);
+    virtual ~Properties();
+  };
+
+  // Interface for observing changes to the NFC manager. Use this interface
+  // to be notified when NFC adapters get added or removed.
+  // NOTE: Users of the NFC D-Bus client code shouldn't need to observe changes
+  // from NfcManagerClient::Observer; to get notified of changes to the list of
+  // NFC adapters, use NfcAdapterClient::Observer instead.
+  class Observer {
+   public:
+    virtual ~Observer() {}
+
+    // Called when a new adapter with object path |object_path| is added to the
+    // system.
+    virtual void AdapterAdded(const dbus::ObjectPath& object_path) {}
+
+    // Called when an adapter with object path |object_path| is removed from the
+    // system.
+    virtual void AdapterRemoved(const dbus::ObjectPath& object_path) {}
+
+    // Called when the manager property with name |property_name| has acquired
+    // a new value.
+    virtual void ManagerPropertyChanged(const std::string& property_name) {}
+  };
+
+  virtual ~NfcManagerClient();
+
+  // Adds and removes observers for events on the NFC manager.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Obtains the properties of the NFC manager service.
+  virtual Properties* GetProperties() = 0;
+
+  // Creates the instance.
+  static NfcManagerClient* Create(DBusClientImplementationType type);
+
+ protected:
+  friend class NfcClientTest;
+
+  NfcManagerClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NfcManagerClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_NFC_MANAGER_CLIENT_H_
diff --git a/chromeos/dbus/nfc_property_set.cc b/chromeos/dbus/nfc_property_set.cc
new file mode 100644
index 0000000..2814bcf
--- /dev/null
+++ b/chromeos/dbus/nfc_property_set.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/nfc_property_set.h"
+
+#include "base/bind.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+NfcPropertySet::NfcPropertySet(dbus::ObjectProxy* object_proxy,
+                               const std::string& interface,
+                               const PropertyChangedCallback& callback)
+    : dbus::PropertySet(object_proxy, interface, callback) {
+}
+
+void NfcPropertySet::ConnectSignals() {
+  object_proxy()->ConnectToSignal(
+      interface(),
+      nfc_common::kPropertyChangedSignal,
+      base::Bind(&dbus::PropertySet::ChangedReceived, GetWeakPtr()),
+      base::Bind(&dbus::PropertySet::ChangedConnected, GetWeakPtr()));
+}
+
+void NfcPropertySet::Get(dbus::PropertyBase* property,
+                         GetCallback callback) {
+  NOTREACHED() << "neard does not implement Get for properties.";
+}
+
+void NfcPropertySet::GetAll() {
+  dbus::MethodCall method_call(
+      interface(), nfc_common::kGetProperties);
+  object_proxy()->CallMethod(&method_call,
+                           dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                           base::Bind(&dbus::PropertySet::OnGetAll,
+                                      GetWeakPtr()));
+}
+
+void NfcPropertySet::Set(dbus::PropertyBase* property,
+                         SetCallback callback) {
+  dbus::MethodCall method_call(
+      interface(), nfc_common::kSetProperty);
+  object_proxy()->CallMethod(&method_call,
+                           dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                           base::Bind(&dbus::PropertySet::OnSet,
+                                      GetWeakPtr(),
+                                      property,
+                                      callback));
+}
+
+void NfcPropertySet::ChangedReceived(dbus::Signal* signal) {
+  DCHECK(signal);
+  dbus::MessageReader reader(signal);
+  UpdatePropertyFromReader(&reader);
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/nfc_property_set.h b/chromeos/dbus/nfc_property_set.h
new file mode 100644
index 0000000..6560d4d
--- /dev/null
+++ b/chromeos/dbus/nfc_property_set.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_NFC_PROPERTY_SET_H_
+#define CHROMEOS_DBUS_NFC_PROPERTY_SET_H_
+
+#include <string>
+
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "dbus/property.h"
+
+namespace chromeos {
+
+// neard doesn't use the standard D-Bus interfaces for property access and
+// instead defines property accessor methods in each D-Bus interface. This
+// class customizes dbus::PropertySet to generate the correct method call to
+// get all properties, connect to the correct signal and parse it correctly.
+class NfcPropertySet : public dbus::PropertySet {
+ public:
+  NfcPropertySet(dbus::ObjectProxy* object_proxy,
+                 const std::string& interface,
+                 const PropertyChangedCallback& callback);
+
+  // dbus::PropertySet overrides
+  virtual void ConnectSignals() OVERRIDE;
+  virtual void Get(dbus::PropertyBase* property,
+                   GetCallback callback) OVERRIDE;
+  virtual void GetAll() OVERRIDE;
+  virtual void Set(dbus::PropertyBase* property,
+                   SetCallback callback) OVERRIDE;
+  virtual void ChangedReceived(dbus::Signal* signal) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NfcPropertySet);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_NFC_PROPERTY_SET_H_
diff --git a/chromeos/dbus/power_manager_client.cc b/chromeos/dbus/power_manager_client.cc
index 82b934a..c065c09 100644
--- a/chromeos/dbus/power_manager_client.cc
+++ b/chromeos/dbus/power_manager_client.cc
@@ -211,6 +211,10 @@
                       weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_);
   }
 
+  virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
+    return num_pending_suspend_readiness_callbacks_;
+  }
+
  protected:
   virtual void Init(dbus::Bus* bus) OVERRIDE {
     power_manager_proxy_ = bus->GetObjectProxy(
@@ -641,11 +645,16 @@
         brightness_(50.0),
         pause_count_(2),
         cycle_count_(0),
+        num_pending_suspend_readiness_callbacks_(0),
         weak_ptr_factory_(this) {}
 
   virtual ~PowerManagerClientStubImpl() {}
 
-  // PowerManagerClient overrides
+  int num_pending_suspend_readiness_callbacks() const {
+    return num_pending_suspend_readiness_callbacks_;
+  }
+
+  // PowerManagerClient overrides:
   virtual void Init(dbus::Bus* bus) OVERRIDE {
     if (CommandLine::ForCurrentProcess()->HasSwitch(
         chromeos::switches::kEnableStubInteractive)) {
@@ -714,10 +723,19 @@
       const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
   virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
   virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
-    return base::Closure();
+    num_pending_suspend_readiness_callbacks_++;
+    return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness,
+                      weak_ptr_factory_.GetWeakPtr());
+  }
+  virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
+    return num_pending_suspend_readiness_callbacks_;
   }
 
  private:
+  void HandleSuspendReadiness() {
+    num_pending_suspend_readiness_callbacks_--;
+  }
+
   void UpdateStatus() {
     if (pause_count_ > 0) {
       pause_count_--;
@@ -802,6 +820,10 @@
   base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
   power_manager::PowerSupplyProperties props_;
 
+  // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
+  // invoked.
+  int num_pending_suspend_readiness_callbacks_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
diff --git a/chromeos/dbus/power_manager_client.h b/chromeos/dbus/power_manager_client.h
index a24312b..5c957f4 100644
--- a/chromeos/dbus/power_manager_client.h
+++ b/chromeos/dbus/power_manager_client.h
@@ -143,6 +143,10 @@
   // readiness for suspend.  See Observer::SuspendImminent().
   virtual base::Closure GetSuspendReadinessCallback() = 0;
 
+  // Returns the number of callbacks returned by GetSuspendReadinessCallback()
+  // for the current suspend attempt but not yet called. Used by tests.
+  virtual int GetNumPendingSuspendReadinessCallbacks() = 0;
+
   // Creates the instance.
   static PowerManagerClient* Create(DBusClientImplementationType type);
 
diff --git a/chromeos/dbus/power_policy_controller.cc b/chromeos/dbus/power_policy_controller.cc
index 5d1c8ae..6eed965 100644
--- a/chromeos/dbus/power_policy_controller.cc
+++ b/chromeos/dbus/power_policy_controller.cc
@@ -84,7 +84,8 @@
       allow_screen_wake_locks(true),
       enable_screen_lock(false),
       presentation_screen_dim_delay_factor(1.0),
-      user_activity_screen_dim_delay_factor(1.0) {}
+      user_activity_screen_dim_delay_factor(1.0),
+      wait_for_initial_user_activity(false) {}
 
 // static
 std::string PowerPolicyController::GetPolicyDebugString(
@@ -112,6 +113,10 @@
     str += base::StringPrintf("user_activity_screen_dim_delay_factor=%f ",
         policy.user_activity_screen_dim_delay_factor());
   }
+  if (policy.has_wait_for_initial_user_activity()) {
+    str += base::StringPrintf("wait_for_initial_user_activity=%d ",
+        policy.wait_for_initial_user_activity());
+  }
   if (policy.has_reason())
     str += base::StringPrintf("reason=\"%s\" ", policy.reason().c_str());
   TrimWhitespace(str, TRIM_TRAILING, &str);
@@ -185,6 +190,8 @@
       values.presentation_screen_dim_delay_factor);
   prefs_policy_.set_user_activity_screen_dim_delay_factor(
       values.user_activity_screen_dim_delay_factor);
+  prefs_policy_.set_wait_for_initial_user_activity(
+      values.wait_for_initial_user_activity);
 
   honor_screen_wake_locks_ = values.allow_screen_wake_locks;
 
diff --git a/chromeos/dbus/power_policy_controller.h b/chromeos/dbus/power_policy_controller.h
index 4cf68df..9e133aa 100644
--- a/chromeos/dbus/power_policy_controller.h
+++ b/chromeos/dbus/power_policy_controller.h
@@ -56,6 +56,7 @@
     bool enable_screen_lock;
     double presentation_screen_dim_delay_factor;
     double user_activity_screen_dim_delay_factor;
+    bool wait_for_initial_user_activity;
   };
 
   // Returns a string describing |policy|.  Useful for tests.
diff --git a/chromeos/dbus/power_policy_controller_unittest.cc b/chromeos/dbus/power_policy_controller_unittest.cc
index 44dd59f..ea7630c 100644
--- a/chromeos/dbus/power_policy_controller_unittest.cc
+++ b/chromeos/dbus/power_policy_controller_unittest.cc
@@ -56,6 +56,7 @@
   prefs.enable_screen_lock = false;
   prefs.presentation_screen_dim_delay_factor = 3.0;
   prefs.user_activity_screen_dim_delay_factor = 2.0;
+  prefs.wait_for_initial_user_activity = true;
   policy_controller_->ApplyPrefs(prefs);
 
   power_manager::PowerManagementPolicy expected_policy;
@@ -79,6 +80,7 @@
   expected_policy.set_use_video_activity(true);
   expected_policy.set_presentation_screen_dim_delay_factor(3.0);
   expected_policy.set_user_activity_screen_dim_delay_factor(2.0);
+  expected_policy.set_wait_for_initial_user_activity(true);
   expected_policy.set_reason("Prefs");
   EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
             PowerPolicyController::GetPolicyDebugString(
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc
index a0c58e3..8b9c8f0 100644
--- a/chromeos/dbus/update_engine_client.cc
+++ b/chromeos/dbus/update_engine_client.cc
@@ -6,7 +6,10 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
+#include "chromeos/chromeos_switches.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
@@ -21,6 +24,17 @@
 const char kReleaseChannelBeta[] = "beta-channel";
 const char kReleaseChannelStable[] = "stable-channel";
 
+// Delay between successive state transitions during AU.
+const int kStateTransitionDefaultDelayMs = 3000;
+
+// Delay between successive notificatioins about downloading progress
+// during fake AU.
+const int kStateTransitionDownloadingDelayMs = 250;
+
+// Size of parts of a "new" image which are downloaded each
+// |kStateTransitionDownloadingDelayMs| during fake AU.
+const int64_t kDownloadSizeDelta = 1 << 19;
+
 // Returns UPDATE_STATUS_ERROR on error.
 UpdateEngineClient::UpdateStatusOperation UpdateStatusFromString(
     const std::string& str) {
@@ -342,10 +356,107 @@
                           const GetChannelCallback& callback) OVERRIDE {
     LOG(INFO) << "Requesting to get channel, get_current_channel="
               << get_current_channel;
-    callback.Run("beta-channel");
+    callback.Run(kReleaseChannelBeta);
   }
 };
 
+// The UpdateEngineClient implementation used on Linux desktop, which
+// tries to emulate real update engine client.
+class UpdateEngineClientFakeImpl : public UpdateEngineClientStubImpl {
+ public:
+  UpdateEngineClientFakeImpl() : weak_factory_(this) {
+  }
+
+  virtual ~UpdateEngineClientFakeImpl() {
+  }
+
+  // UpdateEngineClient implementation:
+  virtual void AddObserver(Observer* observer) OVERRIDE {
+    if (observer)
+      observers_.AddObserver(observer);
+  }
+
+  virtual void RemoveObserver(Observer* observer) OVERRIDE {
+    if (observer)
+      observers_.RemoveObserver(observer);
+  }
+
+  virtual bool HasObserver(Observer* observer) OVERRIDE {
+    return observers_.HasObserver(observer);
+  }
+
+  virtual void RequestUpdateCheck(
+      const UpdateCheckCallback& callback) OVERRIDE {
+    if (last_status_.status != UPDATE_STATUS_IDLE) {
+      callback.Run(UPDATE_RESULT_FAILED);
+      return;
+    }
+    callback.Run(UPDATE_RESULT_SUCCESS);
+    last_status_.status = UPDATE_STATUS_CHECKING_FOR_UPDATE;
+    last_status_.download_progress = 0.0;
+    last_status_.last_checked_time = 0;
+    last_status_.new_size = 0;
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
+                   weak_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs));
+  }
+
+  virtual Status GetLastStatus() OVERRIDE { return last_status_; }
+
+ private:
+  void StateTransition() {
+    UpdateStatusOperation next_status = UPDATE_STATUS_ERROR;
+    int delay_ms = kStateTransitionDefaultDelayMs;
+    switch (last_status_.status) {
+      case UPDATE_STATUS_ERROR:
+      case UPDATE_STATUS_IDLE:
+      case UPDATE_STATUS_UPDATED_NEED_REBOOT:
+      case UPDATE_STATUS_REPORTING_ERROR_EVENT:
+        return;
+      case UPDATE_STATUS_CHECKING_FOR_UPDATE:
+        next_status = UPDATE_STATUS_UPDATE_AVAILABLE;
+        break;
+      case UPDATE_STATUS_UPDATE_AVAILABLE:
+        next_status = UPDATE_STATUS_DOWNLOADING;
+        break;
+      case UPDATE_STATUS_DOWNLOADING:
+        if (last_status_.download_progress >= 1.0) {
+          next_status = UPDATE_STATUS_VERIFYING;
+        } else {
+          next_status = UPDATE_STATUS_DOWNLOADING;
+          last_status_.download_progress += 0.01;
+          last_status_.new_size = kDownloadSizeDelta;
+          delay_ms = kStateTransitionDownloadingDelayMs;
+        }
+        break;
+      case UPDATE_STATUS_VERIFYING:
+        next_status = UPDATE_STATUS_FINALIZING;
+        break;
+      case UPDATE_STATUS_FINALIZING:
+        next_status = UPDATE_STATUS_IDLE;
+        break;
+    }
+    last_status_.status = next_status;
+    FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(last_status_));
+    if (last_status_.status != UPDATE_STATUS_IDLE) {
+      base::MessageLoop::current()->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
+                     weak_factory_.GetWeakPtr()),
+          base::TimeDelta::FromMilliseconds(delay_ms));
+    }
+  }
+
+  ObserverList<Observer> observers_;
+  Status last_status_;
+
+  base::WeakPtrFactory<UpdateEngineClientFakeImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl);
+};
+
 UpdateEngineClient::UpdateEngineClient() {
 }
 
@@ -364,7 +475,10 @@
   if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
     return new UpdateEngineClientImpl();
   DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
-  return new UpdateEngineClientStubImpl();
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestAutoUpdateUI))
+    return new UpdateEngineClientFakeImpl();
+  else
+    return new UpdateEngineClientStubImpl();
 }
 
 }  // namespace chromeos
diff --git a/chromeos/ime/ibus_bridge.h b/chromeos/ime/ibus_bridge.h
index a537e94..57799ec 100644
--- a/chromeos/ime/ibus_bridge.h
+++ b/chromeos/ime/ibus_bridge.h
@@ -60,7 +60,7 @@
   virtual ~IBusEngineHandlerInterface() {}
 
   // Called when the Chrome input field get the focus.
-  virtual void FocusIn() = 0;
+  virtual void FocusIn(ibus::TextInputType text_input_type) = 0;
 
   // Called when the Chrome input field lose the focus.
   virtual void FocusOut() = 0;
diff --git a/chromeos/ime/ime_constants.h b/chromeos/ime/ime_constants.h
index 8dcfffa..5f32601 100644
--- a/chromeos/ime/ime_constants.h
+++ b/chromeos/ime/ime_constants.h
@@ -39,6 +39,29 @@
  int height;
 };
 
+// We can't use ui/base/ime/text_input_type.h in chromeos/, so we should
+// redefine that.
+enum TextInputType {
+  TEXT_INPUT_TYPE_NONE,
+  TEXT_INPUT_TYPE_TEXT,
+  TEXT_INPUT_TYPE_PASSWORD,
+  TEXT_INPUT_TYPE_SEARCH,
+  TEXT_INPUT_TYPE_EMAIL,
+  TEXT_INPUT_TYPE_NUMBER,
+  TEXT_INPUT_TYPE_TELEPHONE,
+  TEXT_INPUT_TYPE_URL,
+  TEXT_INPUT_TYPE_DATE,
+  TEXT_INPUT_TYPE_DATE_TIME,
+  TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
+  TEXT_INPUT_TYPE_MONTH,
+  TEXT_INPUT_TYPE_TIME,
+  TEXT_INPUT_TYPE_WEEK,
+  TEXT_INPUT_TYPE_TEXT_AREA,
+  TEXT_INPUT_TYPE_CONTENT_EDITABLE,
+  TEXT_INPUT_TYPE_DATE_TIME_FIELD,
+  TEXT_INPUT_TYPE_MAX = TEXT_INPUT_TYPE_DATE_TIME_FIELD,
+};
+
 }  // namespace ibus
 }  // namespace chromeos
 
diff --git a/chromeos/ime/mock_ime_engine_handler.cc b/chromeos/ime/mock_ime_engine_handler.cc
index bedd18e..d708971 100644
--- a/chromeos/ime/mock_ime_engine_handler.cc
+++ b/chromeos/ime/mock_ime_engine_handler.cc
@@ -12,6 +12,7 @@
       set_surrounding_text_call_count_(0),
       process_key_event_call_count_(0),
       reset_call_count_(0),
+      last_text_input_type_(ibus::TEXT_INPUT_TYPE_NONE),
       last_set_surrounding_cursor_pos_(0),
       last_set_surrounding_anchor_pos_(0),
       last_processed_keysym_(0),
@@ -22,8 +23,9 @@
 MockIMEEngineHandler::~MockIMEEngineHandler() {
 }
 
-void MockIMEEngineHandler::FocusIn() {
+void MockIMEEngineHandler::FocusIn(ibus::TextInputType text_input_type) {
   ++focus_in_call_count_;
+  last_text_input_type_ = text_input_type;
 }
 
 void MockIMEEngineHandler::FocusOut() {
diff --git a/chromeos/ime/mock_ime_engine_handler.h b/chromeos/ime/mock_ime_engine_handler.h
index d8f39d9..2f9e3ee 100644
--- a/chromeos/ime/mock_ime_engine_handler.h
+++ b/chromeos/ime/mock_ime_engine_handler.h
@@ -14,7 +14,7 @@
   MockIMEEngineHandler();
   virtual ~MockIMEEngineHandler();
 
-  virtual void FocusIn() OVERRIDE;
+  virtual void FocusIn(ibus::TextInputType text_input_type) OVERRIDE;
   virtual void FocusOut() OVERRIDE;
   virtual void Enable() OVERRIDE;
   virtual void Disable() OVERRIDE;
@@ -40,6 +40,10 @@
     return process_key_event_call_count_;
   }
 
+  ibus::TextInputType last_text_input_type() const {
+    return last_text_input_type_;
+  }
+
   std::string last_set_surrounding_text() const {
     return last_set_surrounding_text_;
   }
@@ -74,6 +78,7 @@
   int set_surrounding_text_call_count_;
   int process_key_event_call_count_;
   int reset_call_count_;
+  ibus::TextInputType last_text_input_type_;
   std::string last_set_surrounding_text_;
   uint32 last_set_surrounding_cursor_pos_;
   uint32 last_set_surrounding_anchor_pos_;
diff --git a/chromeos/login/login_state.cc b/chromeos/login/login_state.cc
index a1f1fbb..db26d15 100644
--- a/chromeos/login/login_state.cc
+++ b/chromeos/login/login_state.cc
@@ -16,7 +16,7 @@
 // When running a Chrome OS build outside of a device (i.e. on a developer's
 // workstation) and not running as login-manager, pretend like we're always
 // logged in.
-bool AlwaysLoggedIn() {
+bool AlwaysLoggedInByDefault() {
   return !base::SysInfo::IsRunningOnChromeOS() &&
       !CommandLine::ForCurrentProcess()->HasSwitch(switches::kLoginManager);
 }
@@ -72,13 +72,13 @@
 }
 
 bool LoginState::IsUserLoggedIn() const {
-  if (AlwaysLoggedIn())
+  if (always_logged_in_)
     return true;
   return logged_in_state_ == LOGGED_IN_ACTIVE;
 }
 
 bool LoginState::IsInSafeMode() const {
-  DCHECK(!AlwaysLoggedIn() || logged_in_state_ != LOGGED_IN_SAFE_MODE);
+  DCHECK(!always_logged_in_ || logged_in_state_ != LOGGED_IN_SAFE_MODE);
   return logged_in_state_ == LOGGED_IN_SAFE_MODE;
 }
 
@@ -117,7 +117,8 @@
 // Private methods
 
 LoginState::LoginState() : logged_in_state_(LOGGED_IN_OOBE),
-                           logged_in_user_type_(LOGGED_IN_USER_NONE) {
+                           logged_in_user_type_(LOGGED_IN_USER_NONE),
+                           always_logged_in_(AlwaysLoggedInByDefault()) {
 }
 
 LoginState::~LoginState() {
diff --git a/chromeos/login/login_state.h b/chromeos/login/login_state.h
index 0ef18a7..9fd03d7 100644
--- a/chromeos/login/login_state.h
+++ b/chromeos/login/login_state.h
@@ -74,6 +74,10 @@
   // (i.e., non public nor locally managed account).
   bool IsUserGaiaAuthenticated() const;
 
+  void set_always_logged_in(bool always_logged_in) {
+    always_logged_in_ = always_logged_in;
+  }
+
  private:
   LoginState();
   virtual ~LoginState();
@@ -84,6 +88,11 @@
   LoggedInUserType logged_in_user_type_;
   ObserverList<Observer> observer_list_;
 
+  // If true, it always thinks the current status as logged in. Set to true by
+  // default running on a Linux desktop without flags and test cases. To test
+  // behaviors with a specific login state, call set_always_logged_in(false).
+  bool always_logged_in_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginState);
 };
 
diff --git a/chromeos/login/login_state_unittest.cc b/chromeos/login/login_state_unittest.cc
index 4054007..431b419 100644
--- a/chromeos/login/login_state_unittest.cc
+++ b/chromeos/login/login_state_unittest.cc
@@ -22,8 +22,8 @@
 
   // testing::Test
   virtual void SetUp() OVERRIDE {
-    CommandLine::ForCurrentProcess()->AppendSwitch(switches::kLoginManager);
     LoginState::Initialize();
+    LoginState::Get()->set_always_logged_in(false);
     LoginState::Get()->AddObserver(this);
   }
 
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
index 72c97c5..9a48ec4 100644
--- a/chromeos/network/client_cert_resolver.cc
+++ b/chromeos/network/client_cert_resolver.cc
@@ -12,6 +12,7 @@
 #include <string>
 
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task_runner.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
@@ -431,11 +432,12 @@
     VLOG(1) << "Configuring certificate of network " << it->service_path;
     CertLoader* cert_loader = CertLoader::Get();
     base::DictionaryValue shill_properties;
-    client_cert::SetShillProperties(it->cert_config_type,
-                                    cert_loader->tpm_token_slot(),
-                                    cert_loader->tpm_user_pin(),
-                                    &it->pkcs11_id,
-                                    &shill_properties);
+    client_cert::SetShillProperties(
+        it->cert_config_type,
+        base::IntToString(cert_loader->tpm_token_slot_id()),
+        cert_loader->tpm_user_pin(),
+        &it->pkcs11_id,
+        &shill_properties);
     DBusThreadManager::Get()->GetShillServiceClient()->
         SetProperties(dbus::ObjectPath(it->service_path),
                         shill_properties,
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc
index 73e5e07..9a7af0f 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.cc
+++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -43,22 +43,13 @@
 
 // These are error strings used for error callbacks. None of these error
 // messages are user-facing: they should only appear in logs.
-const char kInvalidUserSettingsMessage[] = "User settings are invalid.";
-const char kInvalidUserSettings[] = "Error.InvalidUserSettings";
-const char kNetworkAlreadyConfiguredMessage[] =
-    "Network is already configured.";
-const char kNetworkAlreadyConfigured[] = "Error.NetworkAlreadyConfigured";
-const char kPoliciesNotInitializedMessage[] = "Policies not initialized.";
-const char kPoliciesNotInitialized[] = "Error.PoliciesNotInitialized";
-const char kProfileNotInitializedMessage[] = "Profile not initialized.";
-const char kProfileNotInitialized[] = "Error.ProflieNotInitialized";
-const char kSetOnUnconfiguredNetworkMessage[] =
-    "Unable to modify properties of an unconfigured network.";
-const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork";
-const char kUnknownProfilePathMessage[] = "Profile path is unknown.";
-const char kUnknownProfilePath[] = "Error.UnknownProfilePath";
-const char kUnknownServicePathMessage[] = "Service path is unknown.";
-const char kUnknownServicePath[] = "Error.UnknownServicePath";
+const char kInvalidUserSettings[] = "InvalidUserSettings";
+const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
+const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
+const char kProfileNotInitialized[] = "ProflieNotInitialized";
+const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
+const char kUnknownProfilePath[] = "UnknownProfilePath";
+const char kUnknownServicePath[] = "UnknownServicePath";
 
 std::string ToDebugString(::onc::ONCSource source,
                           const std::string& userhash) {
@@ -66,17 +57,13 @@
       ("user policy of " + userhash) : "device policy";
 }
 
-void RunErrorCallback(const std::string& service_path,
-                      const std::string& error_name,
-                      const std::string& error_message,
-                      const network_handler::ErrorCallback& error_callback) {
-  NET_LOG_ERROR(error_name, error_message);
-  error_callback.Run(
-      error_name,
-      make_scoped_ptr(
-          network_handler::CreateErrorData(service_path,
-                                           error_name,
-                                           error_message)));
+void InvokeErrorCallback(const std::string& service_path,
+                         const network_handler::ErrorCallback& error_callback,
+                         const std::string& error_name) {
+  std::string error_msg = "ManagedConfig Error: " + error_name;
+  NET_LOG_ERROR(error_msg, service_path);
+  network_handler::RunErrorCallback(
+      error_callback, service_path, error_name, error_msg);
 }
 
 void LogErrorWithDict(const tracked_objects::Location& from_where,
@@ -133,10 +120,7 @@
     const network_handler::DictionaryResultCallback& callback,
     const network_handler::ErrorCallback& error_callback) {
   if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
-    RunErrorCallback(service_path,
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
+    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
     return;
   }
   network_configuration_handler_->GetProperties(
@@ -199,10 +183,8 @@
   if (!guid.empty() && profile) {
     const Policies* policies = GetPoliciesForProfile(*profile);
     if (!policies) {
-      RunErrorCallback(service_path,
-                       kPoliciesNotInitialized,
-                       kPoliciesNotInitializedMessage,
-                       error_callback);
+      InvokeErrorCallback(
+          service_path, error_callback, kPoliciesNotInitialized);
       return;
     }
     const base::DictionaryValue* policy =
@@ -246,10 +228,7 @@
       network_state_handler_->GetNetworkState(service_path);
 
   if (!state) {
-    RunErrorCallback(service_path,
-                     kUnknownServicePath,
-                     kUnknownServicePathMessage,
-                     error_callback);
+    InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
     return;
   }
 
@@ -258,10 +237,8 @@
     // TODO(pneubeck): create an initial configuration in this case. As for
     // CreateConfiguration, user settings from older ChromeOS versions have to
     // determined here.
-    RunErrorCallback(service_path,
-                     kSetOnUnconfiguredNetwork,
-                     kSetOnUnconfiguredNetworkMessage,
-                     error_callback);
+    InvokeErrorCallback(
+        service_path, error_callback, kSetOnUnconfiguredNetwork);
     return;
   }
 
@@ -269,10 +246,7 @@
   const NetworkProfile *profile =
       network_profile_handler_->GetProfileForPath(profile_path);
   if (!profile) {
-    RunErrorCallback(service_path,
-                     kUnknownProfilePath,
-                     kUnknownProfilePathMessage,
-                     error_callback);
+    InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
     return;
   }
 
@@ -281,10 +255,7 @@
 
   const Policies* policies = GetPoliciesForProfile(*profile);
   if (!policies) {
-    RunErrorCallback(service_path,
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
+    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
     return;
   }
 
@@ -303,10 +274,7 @@
           &validation_result);
 
   if (validation_result == onc::Validator::INVALID) {
-    RunErrorCallback(service_path,
-                     kInvalidUserSettings,
-                     kInvalidUserSettingsMessage,
-                     error_callback);
+    InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
     return;
   }
   if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
@@ -331,28 +299,21 @@
     const network_handler::ErrorCallback& error_callback) const {
   const Policies* policies = GetPoliciesForUser(userhash);
   if (!policies) {
-    RunErrorCallback("",
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
+    InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
     return;
   }
 
   if (policy_util::FindMatchingPolicy(policies->per_network_config,
                                       properties)) {
-    RunErrorCallback("",
-                     kNetworkAlreadyConfigured,
-                     kNetworkAlreadyConfiguredMessage,
-                     error_callback);
+    InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
+    return;
   }
 
   const NetworkProfile* profile =
       network_profile_handler_->GetProfileForUserhash(userhash);
   if (!profile) {
-    RunErrorCallback("",
-                     kProfileNotInitialized,
-                     kProfileNotInitializedMessage,
-                     error_callback);
+    InvokeErrorCallback("", error_callback, kProfileNotInitialized);
+    return;
   }
 
   // TODO(pneubeck): In case of WiFi, check that no other configuration for the
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index f464dee..ff81dee 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -38,15 +38,13 @@
   return in_str;
 }
 
-void InvokeErrorCallback(const std::string& error,
-                         const std::string& path,
-                         const network_handler::ErrorCallback& error_callback) {
-  NET_LOG_ERROR(error, path);
-  if (error_callback.is_null())
-    return;
-  scoped_ptr<base::DictionaryValue> error_data(
-      network_handler::CreateErrorData(path, error, ""));
-  error_callback.Run(error, error_data.Pass());
+void InvokeErrorCallback(const std::string& service_path,
+                         const network_handler::ErrorCallback& error_callback,
+                         const std::string& error_name) {
+  std::string error_msg = "Config Error: " + error_name;
+  NET_LOG_ERROR(error_msg, service_path);
+  network_handler::RunErrorCallback(
+      error_callback, service_path, error_name, error_msg);
 }
 
 void GetPropertiesCallback(
@@ -65,14 +63,10 @@
   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
     // Because network services are added and removed frequently, we will see
     // failures regularly, so don't log these.
-    if (!error_callback.is_null()) {
-      scoped_ptr<base::DictionaryValue> error_data(
-          network_handler::CreateErrorData(
-              service_path,
-              network_handler::kDBusFailedError,
-              network_handler::kDBusFailedErrorMessage));
-      error_callback.Run(network_handler::kDBusFailedError, error_data.Pass());
-    }
+    network_handler::RunErrorCallback(error_callback,
+                                      service_path,
+                                      network_handler::kDBusFailedError,
+                                      network_handler::kDBusFailedErrorMessage);
   } else if (!callback.is_null()) {
     callback.Run(service_path, *properties_copy.get());
   }
@@ -147,7 +141,7 @@
       const base::DictionaryValue& profile_entries) {
     if (call_status != DBUS_METHOD_CALL_SUCCESS) {
       InvokeErrorCallback(
-          "GetLoadableProfileEntries Failed", service_path_, error_callback_);
+          service_path_, error_callback_, "GetLoadableProfileEntriesFailed");
       owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
       return;
     }
@@ -285,6 +279,13 @@
       DBusThreadManager::Get()->GetShillManagerClient();
   std::string type;
   properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
+  if (NetworkTypePattern::Ethernet().MatchesType(type)) {
+    InvokeErrorCallback(
+        "" /* no service path */,
+        error_callback,
+        "ConfigureServiceForProfile is not implemented for Ethernet");
+    return;
+  }
 
   NET_LOG_USER("CreateConfiguration", type);
   LogConfigProperties("Configure", type, properties);
@@ -311,9 +312,9 @@
     const network_handler::ErrorCallback& error_callback) {
   // Service.Remove is not reliable. Instead, request the profile entries
   // for the service and remove each entry.
-  if (profile_entry_deleters_.count(service_path)) {
+  if (ContainsKey(profile_entry_deleters_,service_path)) {
     InvokeErrorCallback(
-        "RemoveConfiguration In-Progress", service_path, error_callback);
+        service_path, error_callback, "RemoveConfigurationInProgress");
     return;
   }
   NET_LOG_USER("Remove Configuration", service_path);
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc
index 1f127c6..9649f51 100644
--- a/chromeos/network/network_connection_handler.cc
+++ b/chromeos/network/network_connection_handler.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/json/json_reader.h"
+#include "base/strings/string_number_conversions.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_manager_client.h"
@@ -33,11 +34,8 @@
                          const std::string& error_name) {
   std::string error_msg = "Connect Error: " + error_name;
   NET_LOG_ERROR(error_msg, service_path);
-  if (error_callback.is_null())
-    return;
-  scoped_ptr<base::DictionaryValue> error_data(
-      network_handler::CreateErrorData(service_path, error_name, error_msg));
-  error_callback.Run(error_name, error_data.Pass());
+  network_handler::RunErrorCallback(
+      error_callback, service_path, error_name, error_msg);
 }
 
 bool IsAuthenticationError(const std::string& error) {
@@ -444,11 +442,12 @@
     if (cert_loader_ && cert_loader_->IsHardwareBacked()) {
       // Pass NULL if pkcs11_id is empty, so that it doesn't clear any
       // previously configured client cert.
-      client_cert::SetShillProperties(client_cert_type,
-                                      cert_loader_->tpm_token_slot(),
-                                      cert_loader_->tpm_user_pin(),
-                                      pkcs11_id.empty() ? NULL : &pkcs11_id,
-                                      &config_properties);
+      client_cert::SetShillProperties(
+          client_cert_type,
+          base::IntToString(cert_loader_->tpm_token_slot_id()),
+          cert_loader_->tpm_user_pin(),
+          pkcs11_id.empty() ? NULL : &pkcs11_id,
+          &config_properties);
     }
   }
 
@@ -609,9 +608,8 @@
   pending_requests_.erase(service_path);
   if (error_callback.is_null())
     return;
-  scoped_ptr<base::DictionaryValue> error_data(
-      network_handler::CreateErrorData(service_path, error_name, shill_error));
-  error_callback.Run(error_name, error_data.Pass());
+  network_handler::RunErrorCallback(
+      error_callback, service_path, error_name, shill_error);
 }
 
 void NetworkConnectionHandler::CheckAllPendingRequests() {
diff --git a/chromeos/network/network_handler_callbacks.cc b/chromeos/network/network_handler_callbacks.cc
index e34d549..6b54074 100644
--- a/chromeos/network/network_handler_callbacks.cc
+++ b/chromeos/network/network_handler_callbacks.cc
@@ -22,10 +22,21 @@
 const char kDbusErrorMessage[] = "dbusErrorMessage";
 const char kPath[] = "path";
 
-base::DictionaryValue* CreateErrorData(const std::string& service_path,
+base::DictionaryValue* CreateErrorData(const std::string& path,
                                        const std::string& error_name,
                                        const std::string& error_detail) {
-  return CreateDBusErrorData(service_path, error_name, error_detail, "", "");
+  return CreateDBusErrorData(path, error_name, error_detail, "", "");
+}
+
+void RunErrorCallback(const ErrorCallback& error_callback,
+                      const std::string& path,
+                      const std::string& error_name,
+                      const std::string& error_detail) {
+  if (error_callback.is_null())
+    return;
+  error_callback.Run(
+      error_name,
+      make_scoped_ptr(CreateErrorData(path, error_name, error_detail)));
 }
 
 base::DictionaryValue* CreateDBusErrorData(
@@ -65,22 +76,17 @@
   error_callback.Run(error_name, error_data.Pass());
 }
 
-void GetPropertiesCallback(
-    const network_handler::DictionaryResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback,
-    const std::string& path,
-    DBusMethodCallStatus call_status,
-    const base::DictionaryValue& value) {
+void GetPropertiesCallback(const DictionaryResultCallback& callback,
+                           const ErrorCallback& error_callback,
+                           const std::string& path,
+                           DBusMethodCallStatus call_status,
+                           const base::DictionaryValue& value) {
   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
-    scoped_ptr<base::DictionaryValue> error_data(
-        network_handler::CreateErrorData(path,
-                                         kDBusFailedError,
-                                         kDBusFailedErrorMessage));
     NET_LOG_ERROR(
         base::StringPrintf("GetProperties failed. Status: %d", call_status),
         path);
-    if (!error_callback.is_null())
-      error_callback.Run(kDBusFailedError, error_data.Pass());
+    RunErrorCallback(
+        error_callback, path, kDBusFailedError, kDBusFailedErrorMessage);
   } else if (!callback.is_null()) {
     callback.Run(path, value);
   }
diff --git a/chromeos/network/network_handler_callbacks.h b/chromeos/network/network_handler_callbacks.h
index f939ef3..4bdd687 100644
--- a/chromeos/network/network_handler_callbacks.h
+++ b/chromeos/network/network_handler_callbacks.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 
@@ -45,6 +46,13 @@
     const std::string& error_name,
     const std::string& error_detail);
 
+// If not NULL, runs |error_callback| with an ErrorData dictionary created from
+// the other arguments.
+CHROMEOS_EXPORT void RunErrorCallback(const ErrorCallback& error_callback,
+                                      const std::string& path,
+                                      const std::string& error_name,
+                                      const std::string& error_detail);
+
 CHROMEOS_EXPORT base::DictionaryValue* CreateDBusErrorData(
     const std::string& path,
     const std::string& error_name,
@@ -69,8 +77,8 @@
 // the DBus Dictionary callback into one that calls the error callback
 // if |call_status| != DBUS_METHOD_CALL_SUCCESS.
 CHROMEOS_EXPORT void GetPropertiesCallback(
-    const network_handler::DictionaryResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback,
+    const DictionaryResultCallback& callback,
+    const ErrorCallback& error_callback,
     const std::string& path,
     DBusMethodCallStatus call_status,
     const base::DictionaryValue& value);
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc
index a82a254..fbc30a3 100644
--- a/chromeos/settings/cros_settings_names.cc
+++ b/chromeos/settings/cros_settings_names.cc
@@ -85,6 +85,10 @@
 const char kReportDeviceNetworkInterfaces[] =
     "cros.device_status.report_network_interfaces";
 
+// Determines whether the device reports recently logged in users in device
+// status reports to the device management server.
+const char kReportDeviceUsers[] = "cros.device_status.report_users";
+
 // A list of dictionaries, each detailing one extension to install as part of
 // the AppPack and including the following fields:
 // "extension-id": ID of the extension to install
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index b0971dd..ffaf6f4 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -50,6 +50,7 @@
 CHROMEOS_EXPORT extern const char kReportDeviceBootMode[];
 CHROMEOS_EXPORT extern const char kReportDeviceLocation[];
 CHROMEOS_EXPORT extern const char kReportDeviceNetworkInterfaces[];
+CHROMEOS_EXPORT extern const char kReportDeviceUsers[];
 
 CHROMEOS_EXPORT extern const char kAppPack[];
 CHROMEOS_EXPORT extern const char kAppPackKeyExtensionId[];
diff --git a/cloud_print/service/win/service_listener.cc b/cloud_print/service/win/service_listener.cc
index 96c6bbf..f092188 100644
--- a/cloud_print/service/win/service_listener.cc
+++ b/cloud_print/service/win/service_listener.cc
@@ -75,7 +75,7 @@
 }
 
 void ServiceListener::OnChannelConnected(int32 peer_pid) {
-  IPC::Message* message = new IPC::Message(0, 0, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, 0);
   message->WriteString(GetEnvironment(user_data_dir_));
   channel_->Send(message);
 }
diff --git a/components/auto_login_parser.target.darwin-arm.mk b/components/auto_login_parser.target.darwin-arm.mk
index 244b351..34eaabd 100644
--- a/components/auto_login_parser.target.darwin-arm.mk
+++ b/components/auto_login_parser.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/auto_login_parser.target.darwin-mips.mk b/components/auto_login_parser.target.darwin-mips.mk
index 0613312..34361ea 100644
--- a/components/auto_login_parser.target.darwin-mips.mk
+++ b/components/auto_login_parser.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/auto_login_parser.target.darwin-x86.mk b/components/auto_login_parser.target.darwin-x86.mk
index 2275614..5fd3925 100644
--- a/components/auto_login_parser.target.darwin-x86.mk
+++ b/components/auto_login_parser.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/auto_login_parser.target.linux-arm.mk b/components/auto_login_parser.target.linux-arm.mk
index 244b351..34eaabd 100644
--- a/components/auto_login_parser.target.linux-arm.mk
+++ b/components/auto_login_parser.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/auto_login_parser.target.linux-mips.mk b/components/auto_login_parser.target.linux-mips.mk
index 0613312..34361ea 100644
--- a/components/auto_login_parser.target.linux-mips.mk
+++ b/components/auto_login_parser.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/auto_login_parser.target.linux-x86.mk b/components/auto_login_parser.target.linux-x86.mk
index 2275614..5fd3925 100644
--- a/components/auto_login_parser.target.linux-x86.mk
+++ b/components/auto_login_parser.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill/content/browser/wallet/wallet_items.cc b/components/autofill/content/browser/wallet/wallet_items.cc
index 0ef44d2..fbc49ef 100644
--- a/components/autofill/content/browser/wallet/wallet_items.cc
+++ b/components/autofill/content/browser/wallet/wallet_items.cc
@@ -257,6 +257,30 @@
                    action) != required_actions_.end();
 }
 
+bool WalletItems::SupportsCard(const base::string16& card_number,
+                               base::string16* message) const {
+  std::string card_type = CreditCard::GetCreditCardType(card_number);
+
+  if (card_type == kVisaCard ||
+      card_type == kMasterCard ||
+      card_type == kDiscoverCard) {
+    return true;
+  }
+
+  if (card_type == kAmericanExpressCard) {
+    if (amex_permission_ == AMEX_ALLOWED)
+      return true;
+
+    *message = l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET_FOR_MERCHANT);
+    return false;
+  }
+
+  *message = l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET);
+   return false;
+}
+
 base::string16 WalletItems::MaskedInstrument::DisplayName() const {
 #if defined(OS_ANDROID)
   // TODO(aruslan): improve this stub implementation.
diff --git a/components/autofill/content/browser/wallet/wallet_items.h b/components/autofill/content/browser/wallet/wallet_items.h
index 9838ec83d..6d57213 100644
--- a/components/autofill/content/browser/wallet/wallet_items.h
+++ b/components/autofill/content/browser/wallet/wallet_items.h
@@ -239,6 +239,11 @@
   // Whether or not |action| is in |required_actions_|.
   bool HasRequiredAction(RequiredAction action) const;
 
+  // Checks whether |card_number| is supported by Wallet for this merchant and
+  // if not, fills in |message| with a user-visible explanation.
+  bool SupportsCard(const base::string16& card_number,
+                    base::string16* message) const;
+
   const std::vector<RequiredAction>& required_actions() const {
     return required_actions_;
   }
@@ -257,7 +262,6 @@
   const std::vector<LegalDocument*>& legal_documents() const {
     return legal_documents_.get();
   }
-  bool is_amex_allowed() const { return amex_permission_ == AMEX_ALLOWED; }
 
  private:
   friend class WalletItemsTest;
diff --git a/components/autofill/content/browser/wallet/wallet_items_unittest.cc b/components/autofill/content/browser/wallet/wallet_items_unittest.cc
index 0766fea..a1b32f6 100644
--- a/components/autofill/content/browser/wallet/wallet_items_unittest.cc
+++ b/components/autofill/content/browser/wallet/wallet_items_unittest.cc
@@ -515,7 +515,11 @@
 TEST_F(WalletItemsTest, CreateWalletItemsMissingAmexDisallowed) {
   SetUpDictionary(std::string(kWalletItems) + std::string(kCloseJson));
   EXPECT_TRUE(dict->Remove("amex_disallowed", NULL));
-  EXPECT_FALSE(WalletItems::CreateWalletItems(*dict)->is_amex_allowed());
+  base::string16 amex_number = ASCIIToUTF16("378282246310005");
+  base::string16 message;
+  EXPECT_FALSE(WalletItems::CreateWalletItems(*dict)->SupportsCard(amex_number,
+                                                                   &message));
+  EXPECT_FALSE(message.empty());
 }
 
 TEST_F(WalletItemsTest, CreateWalletItems) {
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index dcf6dc2..f875435 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -507,7 +507,8 @@
     // i.e. the field the user is currently editing and interacting with.
     const WebInputElement* input_element = toWebInputElement(element);
     if (!force_override && !is_initiating_element &&
-        ((IsTextInput(input_element) && !input_element->value().isEmpty()) ||
+        ((IsAutofillableInputElement(input_element) &&
+          !input_element->value().isEmpty()) ||
          (IsTextAreaElement(*element) &&
           !element->toConst<WebTextAreaElement>().value().isEmpty())))
       continue;
@@ -533,7 +534,7 @@
   field->setAutofilled(true);
 
   WebInputElement* input_element = toWebInputElement(field);
-  if (IsTextInput(input_element)) {
+  if (IsTextInput(input_element) || IsMonthInput(input_element)) {
     // If the maxlength attribute contains a negative value, maxLength()
     // returns the default maxlength value.
     input_element->setValue(
@@ -628,6 +629,11 @@
 
 const size_t kMaxParseableFields = 200;
 
+bool IsMonthInput(const WebInputElement* element) {
+  CR_DEFINE_STATIC_LOCAL(WebString, kMonth, ("month"));
+  return element && element->formControlType() == kMonth;
+}
+
 // All text fields, including password fields, should be extracted.
 bool IsTextInput(const WebInputElement* element) {
   return element && element->isTextField();
@@ -653,7 +659,9 @@
 }
 
 bool IsAutofillableInputElement(const WebInputElement* element) {
-  return IsTextInput(element) || IsCheckableElement(element);
+  return IsTextInput(element) ||
+         IsMonthInput(element) ||
+         IsCheckableElement(element);
 }
 
 const base::string16 GetFormIdentifier(const WebFormElement& form) {
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index abff7bf..ae4470a 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -51,6 +51,9 @@
 // Google code project settings.
 extern const size_t kMaxParseableFields;
 
+// Returns true if |element| is a month input element.
+bool IsMonthInput(const WebKit::WebInputElement* element);
+
 // Returns true if |element| is a text input element.
 bool IsTextInput(const WebKit::WebInputElement* element);
 
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index 46df3ef..b959009 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -196,7 +196,7 @@
     control_element.setAutofilled(false);
 
     WebInputElement* input_element = toWebInputElement(&control_element);
-    if (IsTextInput(input_element)) {
+    if (IsTextInput(input_element) || IsMonthInput(input_element)) {
       input_element->setValue(base::string16(), true);
 
       // Clearing the value in the focused node (above) can cause selection
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 682f33a..5e1bff7 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -74,17 +74,20 @@
 }
 
 // Returns true if the |form1| is essentially equal to |form2|.
-bool FormEquals(const autofill::FormData& form1,
-                const PasswordForm& form2) {
+bool FormsAreEqual(const autofill::FormData& form1,
+                   const PasswordForm& form2) {
   // TODO(zysxqn): use more signals than just origin to compare.
-  return form1.origin == form2.origin;
+  // Note that FormData strips the fragement from the url while PasswordForm
+  // strips both the fragement and the path, so we can't just compare these
+  // two directly.
+  return form1.origin.GetOrigin() == form2.origin.GetOrigin();
 }
 
 bool ContainsForm(const std::vector<autofill::FormData>& forms,
                   const PasswordForm& form) {
   for (std::vector<autofill::FormData>::const_iterator it =
            forms.begin(); it != forms.end(); ++it) {
-    if (FormEquals(*it, form))
+    if (FormsAreEqual(*it, form))
       return true;
   }
   return false;
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc
index 2d1edcf..48b818d 100644
--- a/components/autofill/core/browser/autofill_data_model.cc
+++ b/components/autofill/core/browser/autofill_data_model.cc
@@ -4,119 +4,10 @@
 
 #include "components/autofill/core/browser/autofill_data_model.h"
 
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_country.h"
-#include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_type.h"
-#include "components/autofill/core/browser/state_names.h"
-#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/form_field_data.h"
-#include "grit/component_strings.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
 namespace autofill {
-namespace {
-
-const char* const kMonthsAbbreviated[] = {
-  NULL,  // Padding so index 1 = month 1 = January.
-  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-};
-
-const char* const kMonthsFull[] = {
-  NULL,  // Padding so index 1 = month 1 = January.
-  "January", "February", "March", "April", "May", "June",
-  "July", "August", "September", "October", "November", "December",
-};
-
-const char* const kMonthsNumeric[] = {
-  NULL,  // Padding so index 1 = month 1 = January.
-  "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
-};
-
-// Returns true if the value was successfully set, meaning |value| was found in
-// the list of select options in |field|.
-bool SetSelectControlValue(const base::string16& value,
-                           FormFieldData* field) {
-  base::string16 value_lowercase = StringToLowerASCII(value);
-
-  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
-  for (size_t i = 0; i < field->option_values.size(); ++i) {
-    if (value_lowercase == StringToLowerASCII(field->option_values[i]) ||
-        value_lowercase == StringToLowerASCII(field->option_contents[i])) {
-      field->value = field->option_values[i];
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool FillStateSelectControl(const base::string16& value,
-                            FormFieldData* field) {
-  base::string16 full, abbreviation;
-  state_names::GetNameAndAbbreviation(value, &full, &abbreviation);
-
-  // Try the abbreviation first.
-  if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field))
-    return true;
-
-  return !full.empty() && SetSelectControlValue(full, field);
-}
-
-bool FillExpirationMonthSelectControl(const base::string16& value,
-                                      FormFieldData* field) {
-  int index = 0;
-  if (!base::StringToInt(value, &index) ||
-      index <= 0 ||
-      static_cast<size_t>(index) >= arraysize(kMonthsFull))
-    return false;
-
-  bool filled =
-      SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
-      SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
-      SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field);
-  return filled;
-}
-
-// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the
-// given |field|.
-bool FillCreditCardTypeSelectControl(const base::string16& value,
-                                     FormFieldData* field) {
-  // Try stripping off spaces.
-  base::string16 value_stripped;
-  RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped);
-
-  for (size_t i = 0; i < field->option_values.size(); ++i) {
-    base::string16 option_value_lowercase;
-    RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16,
-                &option_value_lowercase);
-    base::string16 option_contents_lowercase;
-    RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16,
-                &option_contents_lowercase);
-
-    // Perform a case-insensitive comparison; but fill the form with the
-    // original text, not the lowercased version.
-    if (value_stripped == option_value_lowercase ||
-        value_stripped == option_contents_lowercase) {
-      field->value = field->option_values[i];
-      return true;
-    }
-  }
-
-  // For American Express, also try filling as "AmEx".
-  if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
-    return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field);
-
-  return false;
-}
-
-}  // namespace
 
 AutofillDataModel::AutofillDataModel(const std::string& guid,
                                      const std::string& origin)
@@ -124,62 +15,11 @@
       origin_(origin) {}
 AutofillDataModel::~AutofillDataModel() {}
 
-void AutofillDataModel::FillSelectControl(const AutofillType& type,
-                                          const std::string& app_locale,
-                                          FormFieldData* field) const {
-  DCHECK(field);
-  DCHECK_EQ("select-one", field->form_control_type);
-  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
-
-  base::string16 field_text = GetInfo(type, app_locale);
-  base::string16 field_text_lower = StringToLowerASCII(field_text);
-  if (field_text.empty())
-    return;
-
-  base::string16 value;
-  for (size_t i = 0; i < field->option_values.size(); ++i) {
-    if (field_text == field->option_values[i] ||
-        field_text == field->option_contents[i]) {
-      // An exact match, use it.
-      value = field->option_values[i];
-      break;
-    }
-
-    if (field_text_lower == StringToLowerASCII(field->option_values[i]) ||
-        field_text_lower == StringToLowerASCII(field->option_contents[i])) {
-      // A match, but not in the same case. Save it in case an exact match is
-      // not found.
-      value = field->option_values[i];
-    }
-  }
-
-  if (!value.empty()) {
-    field->value = value;
-    return;
-  }
-
-  ServerFieldType storable_type = type.GetStorableType();
-  if (storable_type == ADDRESS_HOME_STATE) {
-    FillStateSelectControl(field_text, field);
-  } else if (storable_type == ADDRESS_HOME_COUNTRY) {
-    FillCountrySelectControl(app_locale, field);
-  } else if (storable_type == CREDIT_CARD_EXP_MONTH) {
-    FillExpirationMonthSelectControl(field_text, field);
-  } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
-    // Attempt to fill the year as a 2-digit year.  This compensates for the
-    // fact that our heuristics do not always correctly detect when a website
-    // requests a 2-digit rather than a 4-digit year.
-    FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale,
-                      field);
-  } else if (storable_type == CREDIT_CARD_TYPE) {
-    FillCreditCardTypeSelectControl(field_text, field);
-  }
-}
-
-bool AutofillDataModel::FillCountrySelectControl(
-    const std::string& app_locale,
-    FormFieldData* field_data) const {
-  return false;
+base::string16 AutofillDataModel::GetInfoForVariant(
+    const AutofillType& type,
+    size_t variant,
+    const std::string& app_locale) const {
+  return GetInfo(type, app_locale);
 }
 
 bool AutofillDataModel::IsVerified() const {
diff --git a/components/autofill/core/browser/autofill_data_model.h b/components/autofill/core/browser/autofill_data_model.h
index 0f2cd33..04499f3 100644
--- a/components/autofill/core/browser/autofill_data_model.h
+++ b/components/autofill/core/browser/autofill_data_model.h
@@ -7,13 +7,12 @@
 
 #include <string>
 
-#include "components/autofill/core/browser/field_types.h"
+#include "base/strings/string16.h"
 #include "components/autofill/core/browser/form_group.h"
 
 namespace autofill {
 
-class AutofillField;
-struct FormFieldData;
+class AutofillType;
 
 // This class is an interface for the primary data models that back Autofill.
 // The information in objects of this class is managed by the
@@ -23,18 +22,13 @@
   AutofillDataModel(const std::string& guid, const std::string& origin);
   virtual ~AutofillDataModel();
 
-  // Set |field_data|'s value based on |field| and contents of |this| (using
-  // data variant |variant|).
-  virtual void FillFormField(const AutofillField& field,
-                             size_t variant,
-                             const std::string& app_locale,
-                             FormFieldData* field_data) const = 0;
-
-  // Fills in select control with data matching |type| from |this|.
-  // Public for testing purposes.
-  void FillSelectControl(const AutofillType& type,
-                         const std::string& app_locale,
-                         FormFieldData* field_data) const;
+  // Returns the string that should be auto-filled into a text field given the
+  // |type| of that field, localized to the given |app_locale| if appropriate.
+  // If the data model supports multiple values for the given |type|, returns
+  // the |variant|th value for the |type|.
+  virtual base::string16 GetInfoForVariant(const AutofillType& type,
+                                           size_t variant,
+                                           const std::string& app_locale) const;
 
   // Returns true if the data in this model was entered directly by the user,
   // rather than automatically aggregated.
@@ -46,12 +40,6 @@
   std::string origin() const { return origin_; }
   void set_origin(const std::string& origin) { origin_ = origin; }
 
- protected:
-  // Fills in a select control for a country from data in |this|. Returns true
-  // for success.
-  virtual bool FillCountrySelectControl(const std::string& app_locale,
-                                        FormFieldData* field_data) const;
-
  private:
   // A globally unique ID for this object.
   std::string guid_;
diff --git a/components/autofill/core/browser/autofill_data_model_unittest.cc b/components/autofill/core/browser/autofill_data_model_unittest.cc
index 8004df4..8540ecf 100644
--- a/components/autofill/core/browser/autofill_data_model_unittest.cc
+++ b/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -26,10 +26,6 @@
                           const base::string16& value) OVERRIDE {}
   virtual void GetSupportedTypes(
       ServerFieldTypeSet* supported_types) const OVERRIDE {}
-  virtual void FillFormField(const AutofillField& field,
-                             size_t variant,
-                             const std::string& app_locale,
-                             FormFieldData* field_data) const OVERRIDE {}
 
   DISALLOW_COPY_AND_ASSIGN(TestAutofillDataModel);
 };
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 4bcb118..56f7204 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -7,12 +7,278 @@
 #include "base/logging.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/phone_number.h"
+#include "components/autofill/core/browser/state_names.h"
+#include "grit/component_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 
+using base::StringToInt;
+
+namespace autofill {
 namespace {
 
-static std::string Hash32Bit(const std::string& str) {
+const char* const kMonthsAbbreviated[] = {
+  NULL,  // Padding so index 1 = month 1 = January.
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+};
+
+const char* const kMonthsFull[] = {
+  NULL,  // Padding so index 1 = month 1 = January.
+  "January", "February", "March", "April", "May", "June",
+  "July", "August", "September", "October", "November", "December",
+};
+
+// Returns true if the value was successfully set, meaning |value| was found in
+// the list of select options in |field|.
+bool SetSelectControlValue(const base::string16& value,
+                           FormFieldData* field) {
+  base::string16 value_lowercase = StringToLowerASCII(value);
+
+  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
+  base::string16 best_match;
+  for (size_t i = 0; i < field->option_values.size(); ++i) {
+    if (value == field->option_values[i] ||
+        value == field->option_contents[i]) {
+      // An exact match, use it.
+      best_match = field->option_values[i];
+      break;
+    }
+
+    if (value_lowercase == StringToLowerASCII(field->option_values[i]) ||
+        value_lowercase == StringToLowerASCII(field->option_contents[i])) {
+      // A match, but not in the same case. Save it in case an exact match is
+      // not found.
+      best_match = field->option_values[i];
+    }
+  }
+
+  if (best_match.empty())
+    return false;
+
+  field->value = best_match;
+  return true;
+}
+
+
+// Try to fill a numeric |value| into the given |field|.
+bool FillNumericSelectControl(int value,
+                              FormFieldData* field) {
+  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
+  for (size_t i = 0; i < field->option_values.size(); ++i) {
+    int option;
+    if ((StringToInt(field->option_values[i], &option) && option == value) ||
+        (StringToInt(field->option_contents[i], &option) && option == value)) {
+      field->value = field->option_values[i];
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FillStateSelectControl(const base::string16& value,
+                            FormFieldData* field) {
+  base::string16 full, abbreviation;
+  state_names::GetNameAndAbbreviation(value, &full, &abbreviation);
+
+  // Try the abbreviation first.
+  if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field))
+    return true;
+
+  return !full.empty() && SetSelectControlValue(full, field);
+}
+
+bool FillCountrySelectControl(const base::string16& value,
+                              const std::string& app_locale,
+                              FormFieldData* field_data) {
+  std::string country_code = AutofillCountry::GetCountryCode(value, app_locale);
+  if (country_code.empty())
+    return false;
+
+  DCHECK_EQ(field_data->option_values.size(),
+            field_data->option_contents.size());
+  for (size_t i = 0; i < field_data->option_values.size(); ++i) {
+    // Canonicalize each <option> value to a country code, and compare to the
+    // target country code.
+    base::string16 value = field_data->option_values[i];
+    base::string16 contents = field_data->option_contents[i];
+    if (country_code == AutofillCountry::GetCountryCode(value, app_locale) ||
+        country_code == AutofillCountry::GetCountryCode(contents, app_locale)) {
+      field_data->value = value;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FillExpirationMonthSelectControl(const base::string16& value,
+                                      FormFieldData* field) {
+  int index = 0;
+  if (!StringToInt(value, &index) ||
+      index <= 0 ||
+      static_cast<size_t>(index) >= arraysize(kMonthsFull))
+    return false;
+
+  bool filled =
+      SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
+      SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
+      FillNumericSelectControl(index, field);
+  return filled;
+}
+
+// Returns true if the last two digits in |year| match those in |str|.
+bool LastTwoDigitsMatch(const base::string16& year,
+                        const base::string16& str) {
+  int year_int;
+  int str_int;
+  if (!StringToInt(year, &year_int) || !StringToInt(str, &str_int))
+    return false;
+
+  return (year_int % 100) == (str_int % 100);
+}
+
+// Try to fill a year |value| into the given |field| by comparing the last two
+// digits of the year to the field's options.
+bool FillYearSelectControl(const base::string16& value,
+                           FormFieldData* field) {
+  if (value.size() != 2U && value.size() != 4U)
+    return false;
+
+  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
+  for (size_t i = 0; i < field->option_values.size(); ++i) {
+    if (LastTwoDigitsMatch(value, field->option_values[i]) ||
+        LastTwoDigitsMatch(value, field->option_contents[i])) {
+      field->value = field->option_values[i];
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the
+// given |field|.
+bool FillCreditCardTypeSelectControl(const base::string16& value,
+                                     FormFieldData* field) {
+  // Try stripping off spaces.
+  base::string16 value_stripped;
+  RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped);
+
+  for (size_t i = 0; i < field->option_values.size(); ++i) {
+    base::string16 option_value_lowercase;
+    RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16,
+                &option_value_lowercase);
+    base::string16 option_contents_lowercase;
+    RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16,
+                &option_contents_lowercase);
+
+    // Perform a case-insensitive comparison; but fill the form with the
+    // original text, not the lowercased version.
+    if (value_stripped == option_value_lowercase ||
+        value_stripped == option_contents_lowercase) {
+      field->value = field->option_values[i];
+      return true;
+    }
+  }
+
+  // For American Express, also try filling as "AmEx".
+  if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
+    return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field);
+
+  return false;
+}
+
+// Set |field_data|'s value to |number|, or possibly an appropriate substring of
+// |number|.  The |field| specifies the type of the phone and whether this is a
+// phone prefix or suffix.
+void FillPhoneNumberField(const AutofillField& field,
+                          const base::string16& number,
+                          FormFieldData* field_data) {
+  // Check to see if the size field matches the "prefix" or "suffix" sizes and
+  // fill accordingly.
+  base::string16 value = number;
+  if (number.length() ==
+          PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) {
+    if (field.phone_part() == AutofillField::PHONE_PREFIX ||
+        field_data->max_length == PhoneNumber::kPrefixLength) {
+      value = number.substr(PhoneNumber::kPrefixOffset,
+                            PhoneNumber::kPrefixLength);
+    } else if (field.phone_part() == AutofillField::PHONE_SUFFIX ||
+               field_data->max_length == PhoneNumber::kSuffixLength) {
+      value = number.substr(PhoneNumber::kSuffixOffset,
+                            PhoneNumber::kSuffixLength);
+    }
+  }
+
+  field_data->value = value;
+}
+
+// Fills in the select control |field| with |value|.  If an exact match is not
+// found, falls back to alternate filling strategies based on the |type|.
+void FillSelectControl(const AutofillType& type,
+                       const base::string16& value,
+                       const std::string& app_locale,
+                       FormFieldData* field) {
+  DCHECK_EQ("select-one", field->form_control_type);
+
+  // Guard against corrupted values passed over IPC.
+  if (field->option_values.size() != field->option_contents.size())
+    return;
+
+  if (value.empty())
+    return;
+
+  // First, search for exact matches.
+  if (SetSelectControlValue(value, field))
+    return;
+
+  // If that fails, try specific fallbacks based on the field type.
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == ADDRESS_HOME_STATE) {
+    FillStateSelectControl(value, field);
+  } else if (storable_type == ADDRESS_HOME_COUNTRY) {
+    FillCountrySelectControl(value, app_locale, field);
+  } else if (storable_type == CREDIT_CARD_EXP_MONTH) {
+    FillExpirationMonthSelectControl(value, field);
+  } else if (storable_type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
+             storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
+    FillYearSelectControl(value, field);
+  } else if (storable_type == CREDIT_CARD_TYPE) {
+    FillCreditCardTypeSelectControl(value, field);
+  }
+}
+
+// Fills in the month control |field| with |value|.  |value| should be a date
+// formatted as MM/YYYY.  If it isn't, filling will fail.
+bool FillMonthControl(const base::string16& value, FormFieldData* field) {
+  // Autofill formats a combined date as month/year.
+  std::vector<base::string16> pieces;
+  base::SplitString(value, char16('/'), &pieces);
+  if (pieces.size() != 2)
+    return false;
+
+  // HTML5 input="month" is formatted as year-month.
+  base::string16 month = pieces[0];
+  base::string16 year = pieces[1];
+  if ((month.size() != 1 && month.size() != 2) || year.size() != 4)
+    return false;
+
+  // HTML5 input="month" expects zero-padded months.
+  if (month.size() == 1)
+    month = ASCIIToUTF16("0") + month;
+
+  field->value = year + ASCIIToUTF16("-") + month;
+  return true;
+}
+
+std::string Hash32Bit(const std::string& str) {
   std::string hash_bin = base::SHA1HashString(str);
   DCHECK_EQ(20U, hash_bin.length());
 
@@ -26,8 +292,6 @@
 
 }  // namespace
 
-namespace autofill {
-
 AutofillField::AutofillField()
     : server_type_(NO_SERVER_DATA),
       heuristic_type_(UNKNOWN_TYPE),
@@ -74,9 +338,11 @@
   html_mode_ = mode;
 
   if (type == HTML_TYPE_TEL_LOCAL_PREFIX)
-    phone_part_ = AutofillField::PHONE_PREFIX;
+    phone_part_ = PHONE_PREFIX;
   else if (type == HTML_TYPE_TEL_LOCAL_SUFFIX)
-    phone_part_ = AutofillField::PHONE_SUFFIX;
+    phone_part_ = PHONE_SUFFIX;
+  else
+    phone_part_ = IGNORED;
 }
 
 AutofillType AutofillField::Type() const {
@@ -103,4 +369,21 @@
   return !Type().IsUnknown();
 }
 
+// static
+void AutofillField::FillFormField(const AutofillField& field,
+                                  const base::string16& value,
+                                  const std::string& app_locale,
+                                  FormFieldData* field_data) {
+  AutofillType type = field.Type();
+
+  if (type.GetStorableType() == PHONE_HOME_NUMBER)
+    FillPhoneNumberField(field, value, field_data);
+  else if (field_data->form_control_type == "select-one")
+    FillSelectControl(type, value, app_locale, field_data);
+  else if (field_data->form_control_type == "month")
+    FillMonthControl(value, field_data);
+  else
+    field_data->value = value;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h
index 6f57484..38aeaea 100644
--- a/components/autofill/core/browser/autofill_field.h
+++ b/components/autofill/core/browser/autofill_field.h
@@ -65,6 +65,14 @@
   void set_default_value(const std::string& value) { default_value_ = value; }
   const std::string& default_value() const { return default_value_; }
 
+  // Set |field_data|'s value to |value|.  Uses |field| and |app_locale| as
+  // hints when filling exceptional cases like phone number values and <select>
+  // fields.
+  static void FillFormField(const AutofillField& field,
+                            const base::string16& value,
+                            const std::string& app_locale,
+                            FormFieldData* field_data);
+
  private:
   // The unique name of this field, generated by Autofill.
   base::string16 unique_name_;
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index 3c26302..b7daeda 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/format_macros.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_type.h"
@@ -12,6 +14,22 @@
 namespace autofill {
 namespace {
 
+// Returns a FormFieldData object corresponding to a <select> field populated
+// with the given |options|.
+FormFieldData GenerateSelectFieldWithOptions(const char* const* options,
+                                             size_t options_size) {
+  std::vector<base::string16> options16(options_size);
+  for (size_t i = 0; i < options_size; ++i) {
+    options16[i] = ASCIIToUTF16(options[i]);
+  }
+
+  FormFieldData form_field;
+  form_field.form_control_type = "select-one";
+  form_field.option_values = options16;
+  form_field.option_contents = options16;
+  return form_field;
+}
+
 TEST(AutofillFieldTest, Type) {
   AutofillField field;
   ASSERT_EQ(NO_SERVER_DATA, field.server_type());
@@ -95,5 +113,241 @@
   EXPECT_TRUE(field.IsFieldFillable());
 }
 
+TEST(AutofillFieldTest, FillPhoneNumber) {
+  AutofillField field;
+  field.SetHtmlType(HTML_TYPE_TEL_LOCAL_PREFIX, HtmlFieldMode());
+
+  // Fill with a non-phone number; should fill normally.
+  AutofillField::FillFormField(field, ASCIIToUTF16("Oh hai"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("Oh hai"), field.value);
+
+  // Fill with a phone number; should fill just the prefix.
+  AutofillField::FillFormField(field, ASCIIToUTF16("5551234"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("555"), field.value);
+
+  // Now reset the type, and set a max-length instead.
+  field.SetHtmlType(HTML_TYPE_UNKNOWN, HtmlFieldMode());
+  field.set_heuristic_type(PHONE_HOME_NUMBER);
+  field.max_length = 4;
+
+  // Fill with a phone-number; should fill just the suffix.
+  AutofillField::FillFormField(field, ASCIIToUTF16("5551234"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("1234"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlByValue) {
+  const char* const kOptions[] = {
+    "Eenie", "Meenie", "Miney", "Mo",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kOptions, arraysize(kOptions)),
+      base::string16());
+
+  // Set semantically empty contents for each option, so that only the values
+  // can be used for matching.
+  for (size_t i = 0; i < field.option_contents.size(); ++i) {
+    field.option_contents[i] = ASCIIToUTF16(base::StringPrintf("%" PRIuS, i));
+  }
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("Meenie"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("Meenie"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlByContents) {
+  const char* const kOptions[] = {
+    "Eenie", "Meenie", "Miney", "Mo",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kOptions, arraysize(kOptions)),
+      base::string16());
+
+  // Set semantically empty values for each option, so that only the contents
+  // can be used for matching.
+  for (size_t i = 0; i < field.option_values.size(); ++i) {
+    field.option_values[i] = ASCIIToUTF16(base::StringPrintf("%" PRIuS, i));
+  }
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("Miney"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("2"), field.value);  // Corresponds to "Miney".
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithFullCountryNames) {
+  const char* const kCountries[] = {
+    "Albania", "Canada"
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kCountries, arraysize(kCountries)),
+      base::string16());
+  field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("CA"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("Canada"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedCountryNames) {
+  const char* const kCountries[] = {
+    "AL", "CA"
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kCountries, arraysize(kCountries)),
+      base::string16());
+  field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("Canada"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithFullStateNames) {
+  const char* const kStates[] = {
+    "Alabama", "California"
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kStates, arraysize(kStates)),
+      base::string16());
+  field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("CA"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("California"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithWithAbbreviateStateNames) {
+  const char* const kStates[] = {
+    "AL", "CA"
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kStates, arraysize(kStates)),
+      base::string16());
+  field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("California"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithNumericMonth) {
+  const char* const kMonthsNumeric[] = {
+    "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kMonthsNumeric, arraysize(kMonthsNumeric)),
+      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_EXP_MONTH);
+
+  // Try with a leading zero.
+  AutofillField::FillFormField(field, ASCIIToUTF16("03"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("03"), field.value);
+
+  // Try without a leading zero.
+  AutofillField::FillFormField(field, ASCIIToUTF16("4"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("04"), field.value);
+
+  // Try a two-digit month.
+  AutofillField::FillFormField(field, ASCIIToUTF16("11"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("11"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
+  const char* const kMonthsAbbreviated[] = {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(
+          kMonthsAbbreviated, arraysize(kMonthsAbbreviated)),
+      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_EXP_MONTH);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("Apr"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithFullMonthName) {
+  const char* const kMonthsFull[] = {
+    "January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kMonthsFull, arraysize(kMonthsFull)),
+      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_EXP_MONTH);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("April"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithNumericMonthSansLeadingZero) {
+  const char* const kMonthsNumeric[] = {
+    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(kMonthsNumeric, arraysize(kMonthsNumeric)),
+      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_EXP_MONTH);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("4"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithTwoDigitCreditCardYear) {
+  const char* const kYears[] = {
+    "12", "13", "14", "15", "16", "17", "18", "19"
+  };
+  AutofillField field(GenerateSelectFieldWithOptions(kYears, arraysize(kYears)),
+                      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_EXP_2_DIGIT_YEAR);
+
+  AutofillField::FillFormField(field, ASCIIToUTF16("2017"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("17"), field.value);
+}
+
+TEST(AutofillFieldTest, FillSelectControlWithCreditCardType) {
+  const char* const kCreditCardTypes[] = {
+    "Visa", "Master Card", "AmEx", "discover"
+  };
+  AutofillField field(
+      GenerateSelectFieldWithOptions(
+          kCreditCardTypes, arraysize(kCreditCardTypes)),
+      base::string16());
+  field.set_heuristic_type(CREDIT_CARD_TYPE);
+
+  // Normal case:
+  AutofillField::FillFormField(field, ASCIIToUTF16("Visa"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("Visa"), field.value);
+
+  // Filling should be able to handle intervening whitespace:
+  AutofillField::FillFormField(field, ASCIIToUTF16("MasterCard"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value);
+
+  // American Express is sometimes abbreviated as AmEx:
+  AutofillField::FillFormField(field, ASCIIToUTF16("American Express"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value);
+
+  // Case insensitivity:
+  AutofillField::FillFormField(field, ASCIIToUTF16("Discover"), "en-US",
+                               &field);
+  EXPECT_EQ(ASCIIToUTF16("discover"), field.value);
+}
+
+TEST(AutofillFieldTest, FillMonthControl) {
+  AutofillField field;
+  field.form_control_type = "month";
+
+  // Try a month with two digits.
+  AutofillField::FillFormField(field, ASCIIToUTF16("12/2017"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("2017-12"), field.value);
+
+  // Try a month with a leading zero.
+  AutofillField::FillFormField(field, ASCIIToUTF16("03/2019"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("2019-03"), field.value);
+
+  // Try a month without a leading zero.
+  AutofillField::FillFormField(field, ASCIIToUTF16("4/2018"), "en-US", &field);
+  EXPECT_EQ(ASCIIToUTF16("2018-04"), field.value);
+}
+
 }  // namespace
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index d6d55df..4c76295 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -483,8 +483,10 @@
     for (std::vector<FormFieldData>::iterator iter = result.fields.begin();
          iter != result.fields.end(); ++iter) {
       if ((*iter) == field) {
-        data_model->FillFormField(
-            *autofill_field, variant, app_locale_, &(*iter));
+        base::string16 value = data_model->GetInfoForVariant(
+            autofill_field->Type(), variant, app_locale_);
+        AutofillField::FillFormField(*autofill_field, value, app_locale_,
+                                     &(*iter));
         // Mark the cached field as autofilled, so that we can detect when a
         // user edits an autofilled field (for metrics).
         autofill_field->is_autofilled = true;
@@ -518,10 +520,10 @@
           field_group_type == initiating_group_type) {
         use_variant = variant;
       }
-      data_model->FillFormField(*cached_field,
-                                use_variant,
-                                app_locale_,
-                                &result.fields[i]);
+      base::string16 value = data_model->GetInfoForVariant(
+          cached_field->Type(), use_variant, app_locale_);
+      AutofillField::FillFormField(*cached_field, value, app_locale_,
+                                   &result.fields[i]);
       // Mark the cached field as autofilled, so that we can detect when a user
       // edits an autofilled field (for metrics).
       form_structure->field(i)->is_autofilled = true;
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index 735549f..53a056f 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -309,6 +309,22 @@
       form_group->SetInfo(type, CollapseWhitespace(value, false), app_locale);
 }
 
+base::string16 AutofillProfile::GetInfoForVariant(
+    const AutofillType& type,
+    size_t variant,
+    const std::string& app_locale) const {
+  std::vector<base::string16> values;
+  GetMultiInfo(type, app_locale, &values);
+
+  if (variant >= values.size()) {
+    // If the variant is unavailable, bail. This case is reachable, for
+    // example if Sync updates a profile during the filling process.
+    return base::string16();
+  }
+
+  return values[variant];
+}
+
 void AutofillProfile::SetRawMultiInfo(
     ServerFieldType type,
     const std::vector<base::string16>& values) {
@@ -352,58 +368,6 @@
   GetMultiInfoImpl(type, app_locale, values);
 }
 
-void AutofillProfile::FillFormField(const AutofillField& field,
-                                    size_t variant,
-                                    const std::string& app_locale,
-                                    FormFieldData* field_data) const {
-  AutofillType type = field.Type();
-  DCHECK_NE(CREDIT_CARD, type.group());
-  DCHECK(field_data);
-
-  if (type.GetStorableType() == PHONE_HOME_NUMBER) {
-    FillPhoneNumberField(field, variant, app_locale, field_data);
-  } else if (field_data->form_control_type == "select-one") {
-    FillSelectControl(type, app_locale, field_data);
-  } else {
-    std::vector<base::string16> values;
-    GetMultiInfo(type, app_locale, &values);
-    if (variant >= values.size()) {
-      // If the variant is unavailable, bail.  This case is reachable, for
-      // example if Sync updates a profile during the filling process.
-      return;
-    }
-
-    field_data->value = values[variant];
-  }
-}
-
-void AutofillProfile::FillPhoneNumberField(const AutofillField& field,
-                                           size_t variant,
-                                           const std::string& app_locale,
-                                           FormFieldData* field_data) const {
-  std::vector<base::string16> values;
-  GetMultiInfo(field.Type(), app_locale, &values);
-  DCHECK(variant < values.size());
-
-  // If we are filling a phone number, check to see if the size field
-  // matches the "prefix" or "suffix" sizes and fill accordingly.
-  base::string16 number = values[variant];
-  if (number.length() ==
-          PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) {
-    if (field.phone_part() == AutofillField::PHONE_PREFIX ||
-        field_data->max_length == PhoneNumber::kPrefixLength) {
-      number = number.substr(PhoneNumber::kPrefixOffset,
-                             PhoneNumber::kPrefixLength);
-    } else if (field.phone_part() == AutofillField::PHONE_SUFFIX ||
-               field_data->max_length == PhoneNumber::kSuffixLength) {
-      number = number.substr(PhoneNumber::kSuffixOffset,
-                             PhoneNumber::kSuffixLength);
-    }
-  }
-
-  field_data->value = number;
-}
-
 const base::string16 AutofillProfile::Label() const {
   return label_;
 }
@@ -661,28 +625,6 @@
     (*it)->GetSupportedTypes(supported_types);
 }
 
-bool AutofillProfile::FillCountrySelectControl(
-    const std::string& app_locale,
-    FormFieldData* field_data) const {
-  std::string country_code = UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
-
-  DCHECK_EQ(field_data->option_values.size(),
-            field_data->option_contents.size());
-  for (size_t i = 0; i < field_data->option_values.size(); ++i) {
-    // Canonicalize each <option> value to a country code, and compare to the
-    // target country code.
-    base::string16 value = field_data->option_values[i];
-    base::string16 contents = field_data->option_contents[i];
-    if (country_code == AutofillCountry::GetCountryCode(value, app_locale) ||
-        country_code == AutofillCountry::GetCountryCode(contents, app_locale)) {
-      field_data->value = value;
-      return true;
-    }
-  }
-
-  return false;
-}
-
 void AutofillProfile::GetMultiInfoImpl(
     const AutofillType& type,
     const std::string& app_locale,
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index 5a3f65c..0611fd3 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -54,10 +54,10 @@
                        const std::string& app_locale) OVERRIDE;
 
   // AutofillDataModel:
-  virtual void FillFormField(const AutofillField& field,
-                             size_t variant,
-                             const std::string& app_locale,
-                             FormFieldData* field_data) const OVERRIDE;
+  virtual base::string16 GetInfoForVariant(
+      const AutofillType& type,
+      size_t variant,
+      const std::string& app_locale) const OVERRIDE;
 
   // Multi-value equivalents to |GetInfo| and |SetInfo|.
   void SetRawMultiInfo(ServerFieldType type,
@@ -68,15 +68,6 @@
                     const std::string& app_locale,
                     std::vector<base::string16>* values) const;
 
-  // Set |field_data|'s value for phone number based on contents of |this|.
-  // The |field| specifies the type of the phone and whether this is a
-  // phone prefix or suffix.  The |variant| parameter specifies which value in a
-  // multi-valued profile.
-  void FillPhoneNumberField(const AutofillField& field,
-                            size_t variant,
-                            const std::string& app_locale,
-                            FormFieldData* field_data) const;
-
   // The user-visible label of the profile, generated in relation to other
   // profiles. Shows at least 2 fields that differentiate profile from other
   // profiles. See AdjustInferredLabels() further down for more description.
@@ -153,8 +144,6 @@
   typedef std::vector<const FormGroup*> FormGroupList;
 
   // FormGroup:
-  virtual bool FillCountrySelectControl(const std::string& app_locale,
-                                        FormFieldData* field) const OVERRIDE;
   virtual void GetSupportedTypes(
       ServerFieldTypeSet* supported_types) const OVERRIDE;
 
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index f67c536..e652fdf 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_common_test.h"
 #include "components/autofill/core/browser/autofill_profile.h"
@@ -772,132 +771,6 @@
   EXPECT_EQ(base::string16(), p.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
 }
 
-TEST(AutofillProfileTest, AddressCountryFull) {
-  const char* const kCountries[] = {
-    "Albania", "Canada"
-  };
-  std::vector<base::string16> options(arraysize(kCountries));
-  for (size_t i = 0; i < arraysize(kCountries); ++i) {
-    options[i] = ASCIIToUTF16(kCountries[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA"));
-  profile.FillSelectControl(
-      AutofillType(ADDRESS_HOME_COUNTRY), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("Canada"), field.value);
-}
-
-TEST(AutofillProfileTest, AddressCountryAbbrev) {
-  const char* const kCountries[] = {
-    "AL", "CA"
-  };
-  std::vector<base::string16> options(arraysize(kCountries));
-  for (size_t i = 0; i < arraysize(kCountries); ++i) {
-    options[i] = ASCIIToUTF16(kCountries[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA"));
-  profile.FillSelectControl(
-      AutofillType(ADDRESS_HOME_COUNTRY), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
-}
-
-TEST(AutofillProfileTest, AddressStateFull) {
-  const char* const kStates[] = {
-    "Alabama", "California"
-  };
-  std::vector<base::string16> options(arraysize(kStates));
-  for (size_t i = 0; i < arraysize(kStates); ++i) {
-    options[i] = ASCIIToUTF16(kStates[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
-  profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("California"), field.value);
-}
-
-TEST(AutofillProfileTest, AddressStateAbbrev) {
-  const char* const kStates[] = {
-    "AL", "CA"
-  };
-  std::vector<base::string16> options(arraysize(kStates));
-  for (size_t i = 0; i < arraysize(kStates); ++i) {
-    options[i] = ASCIIToUTF16(kStates[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California"));
-  profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
-}
-
-TEST(AutofillProfileTest, FillByValue) {
-  const char* const kStates[] = {
-    "Alabama", "California"
-  };
-  std::vector<base::string16> values(arraysize(kStates));
-  std::vector<base::string16> contents(arraysize(kStates));
-  for (unsigned int i = 0; i < arraysize(kStates); ++i) {
-    values[i] = ASCIIToUTF16(kStates[i]);
-    contents[i] = ASCIIToUTF16(base::StringPrintf("%u", i));
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = values;
-  field.option_contents = contents;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California"));
-  profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("California"), field.value);
-}
-
-TEST(AutofillProfileTest, FillByContents) {
-  const char* const kStates[] = {
-    "Alabama", "California"
-  };
-  std::vector<base::string16> values(arraysize(kStates));
-  std::vector<base::string16> contents(arraysize(kStates));
-  for (unsigned int i = 0; i < arraysize(kStates); ++i) {
-    values[i] = ASCIIToUTF16(base::StringPrintf("%u", i + 1));
-    contents[i] = ASCIIToUTF16(kStates[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = values;
-  field.option_contents = contents;
-
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
-  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California"));
-  profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("2"), field.value);
-}
-
 TEST(AutofillProfileTest, IsPresentButInvalid) {
   AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
   EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_STATE));
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc.utf8 b/components/autofill/core/browser/autofill_regex_constants.cc.utf8
index 960f432..a39a9cf 100644
--- a/components/autofill/core/browser/autofill_regex_constants.cc.utf8
+++ b/components/autofill/core/browser/autofill_regex_constants.cc.utf8
@@ -77,6 +77,7 @@
     "|국가|나라";  // ko-KR
 const char kZipCodeRe[] =
     "zip|postal|post.*code|pcode|^1z$"
+    "|pin.?code"  // en-IN
     "|postleitzahl"  // de-DE
     "|\\bcp\\b"  // es
     "|\\bcdp\\b"  // fr-FR
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index a3e3044..9617798 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -534,31 +534,6 @@
   return true;
 }
 
-void CreditCard::FillFormField(const AutofillField& field,
-                               size_t /*variant*/,
-                               const std::string& app_locale,
-                               FormFieldData* field_data) const {
-  DCHECK_EQ(CREDIT_CARD, field.Type().group());
-  DCHECK(field_data);
-
-  if (field_data->form_control_type == "select-one") {
-    FillSelectControl(field.Type(), app_locale, field_data);
-  } else if (field_data->form_control_type == "month") {
-    // HTML5 input="month" consists of year-month.
-    base::string16 year =
-        GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale);
-    base::string16 month =
-        GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale);
-    if (!year.empty() && !month.empty()) {
-      // Fill the value only if |this| includes both year and month
-      // information.
-      field_data->value = year + ASCIIToUTF16("-") + month;
-    }
-  } else {
-    field_data->value = GetInfo(field.Type(), app_locale);
-  }
-}
-
 int CreditCard::Compare(const CreditCard& credit_card) const {
   // The following CreditCard field types are the only types we store in the
   // WebDB so far, so we're only concerned with matching these types in the
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index d5bf1a0..4c92e62 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -59,12 +59,6 @@
                        const base::string16& value,
                        const std::string& app_locale) OVERRIDE;
 
-  // AutofillDataModel:
-  virtual void FillFormField(const AutofillField& field,
-                             size_t variant,
-                             const std::string& app_locale,
-                             FormFieldData* field_data) const OVERRIDE;
-
   // Credit card preview summary, for example: ******1234, Exp: 01/2020
   const base::string16 Label() const;
 
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index bba804c..f9012ca 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -95,7 +95,7 @@
     }
 
     if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) {
-      credit_card_field->expiration_month_ = scanner->Cursor();
+      credit_card_field->expiration_date_ = scanner->Cursor();
       scanner->Advance();
     } else {
       // First try to parse split month/year expiration fields.
@@ -170,10 +170,7 @@
   if ((credit_card_field->number_ || credit_card_field->verification_) &&
       (credit_card_field->expiration_date_ ||
        (credit_card_field->expiration_month_ &&
-        (credit_card_field->expiration_year_ ||
-         (LowerCaseEqualsASCII(
-             credit_card_field->expiration_month_->form_control_type,
-             "month")))))) {
+        credit_card_field->expiration_year_))) {
     return credit_card_field.release();
   }
 
diff --git a/components/autofill/core/browser/credit_card_field.h b/components/autofill/core/browser/credit_card_field.h
index 119e1ab..bf45e7e 100644
--- a/components/autofill/core/browser/credit_card_field.h
+++ b/components/autofill/core/browser/credit_card_field.h
@@ -27,15 +27,7 @@
   virtual bool ClassifyField(ServerFieldTypeMap* map) const OVERRIDE;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseMiniumCreditCard);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseFullCreditCard);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseCreditCardType);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpMonthYear);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpMonthYear2);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpField);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpField2DigitYear);
-  FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest,
-                           ParseCreditCardHolderNameWithCCFullName);
+  friend class CreditCardFieldTest;
 
   CreditCardField();
 
diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc
index 9f60a1d..073e5d7 100644
--- a/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -16,15 +16,25 @@
 class CreditCardFieldTest : public testing::Test {
  public:
   CreditCardFieldTest() {}
+  virtual ~CreditCardFieldTest() {}
 
  protected:
   ScopedVector<const AutofillField> list_;
-  scoped_ptr<CreditCardField> field_;
+  scoped_ptr<const CreditCardField> field_;
   ServerFieldTypeMap field_type_map_;
 
-  // Downcast for tests.
-  static CreditCardField* Parse(AutofillScanner* scanner) {
-    return static_cast<CreditCardField*>(CreditCardField::Parse(scanner));
+  // Parses the contents of |list_| as a form, and stores the result into
+  // |field_|.
+  void Parse() {
+    AutofillScanner scanner(list_.get());
+    field_.reset(
+        static_cast<const CreditCardField*>(CreditCardField::Parse(&scanner)));
+  }
+
+  // Associates fields with their corresponding types, based on the previous
+  // call to Parse().
+  bool ClassifyField() {
+    return field_->ClassifyField(&field_type_map_);
   }
 
  private:
@@ -32,15 +42,13 @@
 };
 
 TEST_F(CreditCardFieldTest, Empty) {
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
 }
 
 TEST_F(CreditCardFieldTest, NonParse) {
   list_.push_back(new AutofillField);
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
 }
 
@@ -56,8 +64,7 @@
   field.name = ASCIIToUTF16("ccyear");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("year2")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
 }
 
@@ -69,8 +76,7 @@
   field.name = ASCIIToUTF16("card_number");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("number1")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
 }
 
@@ -90,10 +96,9 @@
   field.name = ASCIIToUTF16("ccyear");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("year3")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number1")]);
@@ -134,10 +139,9 @@
   field.name = ASCIIToUTF16("verification");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("cvc")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("type")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_TYPE, field_type_map_[ASCIIToUTF16("type")]);
@@ -180,10 +184,9 @@
   field.name = ASCIIToUTF16("ExpDate");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("year4")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
@@ -219,10 +222,9 @@
   field.name = ASCIIToUTF16("ExpDate");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("year4")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
@@ -254,10 +256,9 @@
   field.name = ASCIIToUTF16("cc_exp");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
@@ -286,10 +287,9 @@
   field.name = ASCIIToUTF16("cc_exp");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
@@ -310,13 +310,39 @@
   field.name = ASCIIToUTF16("ccfullname");
   list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
 
-  AutofillScanner scanner(list_.get());
-  field_.reset(Parse(&scanner));
+  Parse();
   ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+  EXPECT_TRUE(ClassifyField());
   ASSERT_TRUE(
       field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
   EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
 }
 
+// Verifies that <input type="month"> controls are able to be parsed correctly.
+TEST_F(CreditCardFieldTest, ParseMonthControl) {
+  FormFieldData field;
+
+  field.form_control_type = "text";
+  field.label = ASCIIToUTF16("Card number:");
+  field.name = ASCIIToUTF16("ccnumber");
+  list_.push_back(new AutofillField(field, ASCIIToUTF16("number1")));
+
+  field.form_control_type = "month";
+  field.label = ASCIIToUTF16("Expiration date:");
+  field.name = ASCIIToUTF16("ccexp");
+  list_.push_back(new AutofillField(field, ASCIIToUTF16("date2")));
+
+  Parse();
+  ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
+  EXPECT_TRUE(ClassifyField());
+  ASSERT_TRUE(
+      field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_type_map_[ASCIIToUTF16("number1")]);
+  ASSERT_TRUE(
+      field_type_map_.find(ASCIIToUTF16("date2")) != field_type_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+            field_type_map_[ASCIIToUTF16("date2")]);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index 837d729..ee3b7d9 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -360,172 +360,6 @@
 }
 
 
-TEST(CreditCardTest, CreditCardMonthExact) {
-  const char* const kMonthsNumeric[] = {
-    "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
-  };
-  std::vector<base::string16> options(arraysize(kMonthsNumeric));
-  for (size_t i = 0; i < arraysize(kMonthsNumeric); ++i) {
-    options[i] = ASCIIToUTF16(kMonthsNumeric[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-  credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
-  credit_card.FillSelectControl(
-      AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("01"), field.value);
-}
-
-TEST(CreditCardTest, CreditCardMonthAbbreviated) {
-  const char* const kMonthsAbbreviated[] = {
-    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-  };
-  std::vector<base::string16> options(arraysize(kMonthsAbbreviated));
-  for (size_t i = 0; i < arraysize(kMonthsAbbreviated); ++i) {
-    options[i] = ASCIIToUTF16(kMonthsAbbreviated[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-  credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
-  credit_card.FillSelectControl(
-      AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("Jan"), field.value);
-}
-
-TEST(CreditCardTest, CreditCardMonthFull) {
-  const char* const kMonthsFull[] = {
-    "January", "February", "March", "April", "May", "June",
-    "July", "August", "September", "October", "November", "December",
-  };
-  std::vector<base::string16> options(arraysize(kMonthsFull));
-  for (size_t i = 0; i < arraysize(kMonthsFull); ++i) {
-    options[i] = ASCIIToUTF16(kMonthsFull[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-  credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
-  credit_card.FillSelectControl(
-      AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("January"), field.value);
-}
-
-TEST(CreditCardTest, CreditCardMonthNumeric) {
-  const char* const kMonthsNumeric[] = {
-    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
-  };
-  std::vector<base::string16> options(arraysize(kMonthsNumeric));
-  for (size_t i = 0; i < arraysize(kMonthsNumeric); ++i) {
-    options[i] = ASCIIToUTF16(kMonthsNumeric[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-  credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
-  credit_card.FillSelectControl(
-      AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("1"), field.value);
-}
-
-TEST(CreditCardTest, CreditCardTwoDigitYear) {
-  const char* const kYears[] = {
-    "12", "13", "14", "15", "16", "17", "18", "19"
-  };
-  std::vector<base::string16> options(arraysize(kYears));
-  for (size_t i = 0; i < arraysize(kYears); ++i) {
-    options[i] = ASCIIToUTF16(kYears[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-  credit_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2017"));
-  credit_card.FillSelectControl(
-      AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), "en-US", &field);
-  EXPECT_EQ(ASCIIToUTF16("17"), field.value);
-  EXPECT_EQ(2017, credit_card.expiration_year());
-}
-
-TEST(CreditCardTest, CreditCardTypeSelectControl) {
-  const char* const kCreditCardTypes[] = {
-    "Visa", "Master Card", "AmEx", "discover"
-  };
-  std::vector<base::string16> options(arraysize(kCreditCardTypes));
-  for (size_t i = 0; i < arraysize(kCreditCardTypes); ++i) {
-    options[i] = ASCIIToUTF16(kCreditCardTypes[i]);
-  }
-
-  FormFieldData field;
-  field.form_control_type = "select-one";
-  field.option_values = options;
-  field.option_contents = options;
-
-  // Credit card types are inferred from the numbers, so we use test numbers for
-  // each card type. Test card numbers are drawn from
-  // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
-
-  {
-    // Normal case:
-    CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-    credit_card.SetRawInfo(CREDIT_CARD_NUMBER,
-                           ASCIIToUTF16("4111111111111111"));
-    credit_card.FillSelectControl(
-        AutofillType(CREDIT_CARD_TYPE), "en-US", &field);
-    EXPECT_EQ(ASCIIToUTF16("Visa"), field.value);
-  }
-
-  {
-    // Filling should be able to handle intervening whitespace:
-    CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-    credit_card.SetRawInfo(CREDIT_CARD_NUMBER,
-                           ASCIIToUTF16("5105105105105100"));
-    credit_card.FillSelectControl(
-        AutofillType(CREDIT_CARD_TYPE), "en-US", &field);
-    EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value);
-  }
-
-  {
-    // American Express is sometimes abbreviated as AmEx:
-    CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-    credit_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("371449635398431"));
-    credit_card.FillSelectControl(
-        AutofillType(CREDIT_CARD_TYPE), "en-US", &field);
-    EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value);
-  }
-
-  {
-    // Case insensitivity:
-    CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
-    credit_card.SetRawInfo(CREDIT_CARD_NUMBER,
-                           ASCIIToUTF16("6011111111111117"));
-    credit_card.FillSelectControl(
-        AutofillType(CREDIT_CARD_TYPE), "en-US", &field);
-    EXPECT_EQ(ASCIIToUTF16("discover"), field.value);
-  }
-}
-
 TEST(CreditCardTest, GetCreditCardType) {
   struct {
     std::string card_number;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 1ea9913..37e0bc9 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -334,8 +334,7 @@
   std::map<base::string16, size_t> unique_names;
   for (std::vector<FormFieldData>::const_iterator field =
            form.fields.begin();
-       field != form.fields.end(); field++) {
-
+       field != form.fields.end(); ++field) {
     if (!ShouldSkipField(*field)) {
       // Add all supported form fields (including with empty names) to the
       // signature.  This is a requirement for Autofill servers.
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 5c9c80c..9298047 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -291,7 +291,7 @@
 
     if (group == CREDIT_CARD) {
       if (LowerCaseEqualsASCII(field->form_control_type, "month")) {
-        DCHECK_EQ(CREDIT_CARD_EXP_MONTH, server_field_type);
+        DCHECK_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, server_field_type);
         local_imported_credit_card->SetInfoForMonthInputType(value);
       } else {
         local_imported_credit_card->SetInfo(field_type, value, app_locale_);
diff --git a/components/autofill_content_browser.target.darwin-arm.mk b/components/autofill_content_browser.target.darwin-arm.mk
index 9110cde..5dd32d7 100644
--- a/components/autofill_content_browser.target.darwin-arm.mk
+++ b/components/autofill_content_browser.target.darwin-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -217,13 +217,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_browser.target.darwin-mips.mk b/components/autofill_content_browser.target.darwin-mips.mk
index 5e25b7f..cef4130 100644
--- a/components/autofill_content_browser.target.darwin-mips.mk
+++ b/components/autofill_content_browser.target.darwin-mips.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -215,13 +215,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_browser.target.darwin-x86.mk b/components/autofill_content_browser.target.darwin-x86.mk
index 5ce7783..0f2e381 100644
--- a/components/autofill_content_browser.target.darwin-x86.mk
+++ b/components/autofill_content_browser.target.darwin-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -221,13 +221,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_browser.target.linux-arm.mk b/components/autofill_content_browser.target.linux-arm.mk
index 9110cde..5dd32d7 100644
--- a/components/autofill_content_browser.target.linux-arm.mk
+++ b/components/autofill_content_browser.target.linux-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -217,13 +217,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_browser.target.linux-mips.mk b/components/autofill_content_browser.target.linux-mips.mk
index 5e25b7f..cef4130 100644
--- a/components/autofill_content_browser.target.linux-mips.mk
+++ b/components/autofill_content_browser.target.linux-mips.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -215,13 +215,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_browser.target.linux-x86.mk b/components/autofill_content_browser.target.linux-x86.mk
index 5ce7783..0f2e381 100644
--- a/components/autofill_content_browser.target.linux-x86.mk
+++ b/components/autofill_content_browser.target.linux-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -221,13 +221,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.darwin-arm.mk b/components/autofill_content_renderer.target.darwin-arm.mk
index 283cedf..5f8096e 100644
--- a/components/autofill_content_renderer.target.darwin-arm.mk
+++ b/components/autofill_content_renderer.target.darwin-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.darwin-mips.mk b/components/autofill_content_renderer.target.darwin-mips.mk
index 665d6c0..b8bbb16 100644
--- a/components/autofill_content_renderer.target.darwin-mips.mk
+++ b/components/autofill_content_renderer.target.darwin-mips.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -174,13 +174,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.darwin-x86.mk b/components/autofill_content_renderer.target.darwin-x86.mk
index b6cfcda..14b01f6 100644
--- a/components/autofill_content_renderer.target.darwin-x86.mk
+++ b/components/autofill_content_renderer.target.darwin-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.linux-arm.mk b/components/autofill_content_renderer.target.linux-arm.mk
index 283cedf..5f8096e 100644
--- a/components/autofill_content_renderer.target.linux-arm.mk
+++ b/components/autofill_content_renderer.target.linux-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.linux-mips.mk b/components/autofill_content_renderer.target.linux-mips.mk
index 665d6c0..b8bbb16 100644
--- a/components/autofill_content_renderer.target.linux-mips.mk
+++ b/components/autofill_content_renderer.target.linux-mips.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -174,13 +174,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_renderer.target.linux-x86.mk b/components/autofill_content_renderer.target.linux-x86.mk
index b6cfcda..14b01f6 100644
--- a/components/autofill_content_renderer.target.linux-x86.mk
+++ b/components/autofill_content_renderer.target.linux-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.darwin-arm.mk b/components/autofill_content_risk_proto.target.darwin-arm.mk
index c57822f..ed089b9 100644
--- a/components/autofill_content_risk_proto.target.darwin-arm.mk
+++ b/components/autofill_content_risk_proto.target.darwin-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.darwin-mips.mk b/components/autofill_content_risk_proto.target.darwin-mips.mk
index d604224..68e3671 100644
--- a/components/autofill_content_risk_proto.target.darwin-mips.mk
+++ b/components/autofill_content_risk_proto.target.darwin-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.darwin-x86.mk b/components/autofill_content_risk_proto.target.darwin-x86.mk
index 044be20..35d402c 100644
--- a/components/autofill_content_risk_proto.target.darwin-x86.mk
+++ b/components/autofill_content_risk_proto.target.darwin-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.linux-arm.mk b/components/autofill_content_risk_proto.target.linux-arm.mk
index c57822f..ed089b9 100644
--- a/components/autofill_content_risk_proto.target.linux-arm.mk
+++ b/components/autofill_content_risk_proto.target.linux-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.linux-mips.mk b/components/autofill_content_risk_proto.target.linux-mips.mk
index d604224..68e3671 100644
--- a/components/autofill_content_risk_proto.target.linux-mips.mk
+++ b/components/autofill_content_risk_proto.target.linux-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_content_risk_proto.target.linux-x86.mk b/components/autofill_content_risk_proto.target.linux-x86.mk
index 044be20..35d402c 100644
--- a/components/autofill_content_risk_proto.target.linux-x86.mk
+++ b/components/autofill_content_risk_proto.target.linux-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.darwin-arm.mk b/components/autofill_core_browser.target.darwin-arm.mk
index 0afd61f..4f50e40 100644
--- a/components/autofill_core_browser.target.darwin-arm.mk
+++ b/components/autofill_core_browser.target.darwin-arm.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -246,13 +246,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.darwin-mips.mk b/components/autofill_core_browser.target.darwin-mips.mk
index f8023a1..db34df6 100644
--- a/components/autofill_core_browser.target.darwin-mips.mk
+++ b/components/autofill_core_browser.target.darwin-mips.mk
@@ -111,13 +111,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -244,13 +244,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.darwin-x86.mk b/components/autofill_core_browser.target.darwin-x86.mk
index a5910c5..193d262 100644
--- a/components/autofill_core_browser.target.darwin-x86.mk
+++ b/components/autofill_core_browser.target.darwin-x86.mk
@@ -114,13 +114,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -250,13 +250,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.linux-arm.mk b/components/autofill_core_browser.target.linux-arm.mk
index 0afd61f..4f50e40 100644
--- a/components/autofill_core_browser.target.linux-arm.mk
+++ b/components/autofill_core_browser.target.linux-arm.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -246,13 +246,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.linux-mips.mk b/components/autofill_core_browser.target.linux-mips.mk
index f8023a1..db34df6 100644
--- a/components/autofill_core_browser.target.linux-mips.mk
+++ b/components/autofill_core_browser.target.linux-mips.mk
@@ -111,13 +111,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -244,13 +244,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_browser.target.linux-x86.mk b/components/autofill_core_browser.target.linux-x86.mk
index a5910c5..193d262 100644
--- a/components/autofill_core_browser.target.linux-x86.mk
+++ b/components/autofill_core_browser.target.linux-x86.mk
@@ -114,13 +114,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -250,13 +250,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.darwin-arm.mk b/components/autofill_core_common.target.darwin-arm.mk
index afcde49..de4f762 100644
--- a/components/autofill_core_common.target.darwin-arm.mk
+++ b/components/autofill_core_common.target.darwin-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.darwin-mips.mk b/components/autofill_core_common.target.darwin-mips.mk
index 8095eab..82cd02b 100644
--- a/components/autofill_core_common.target.darwin-mips.mk
+++ b/components/autofill_core_common.target.darwin-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.darwin-x86.mk b/components/autofill_core_common.target.darwin-x86.mk
index 0a1b061..3082f8d 100644
--- a/components/autofill_core_common.target.darwin-x86.mk
+++ b/components/autofill_core_common.target.darwin-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -195,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.linux-arm.mk b/components/autofill_core_common.target.linux-arm.mk
index afcde49..de4f762 100644
--- a/components/autofill_core_common.target.linux-arm.mk
+++ b/components/autofill_core_common.target.linux-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.linux-mips.mk b/components/autofill_core_common.target.linux-mips.mk
index 8095eab..82cd02b 100644
--- a/components/autofill_core_common.target.linux-mips.mk
+++ b/components/autofill_core_common.target.linux-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_core_common.target.linux-x86.mk b/components/autofill_core_common.target.linux-x86.mk
index 0a1b061..3082f8d 100644
--- a/components/autofill_core_common.target.linux-x86.mk
+++ b/components/autofill_core_common.target.linux-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -195,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.darwin-arm.mk b/components/autofill_jni_headers.target.darwin-arm.mk
index b87ef2f..40660f4 100644
--- a/components/autofill_jni_headers.target.darwin-arm.mk
+++ b/components/autofill_jni_headers.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.darwin-mips.mk b/components/autofill_jni_headers.target.darwin-mips.mk
index 342292e..20b8092 100644
--- a/components/autofill_jni_headers.target.darwin-mips.mk
+++ b/components/autofill_jni_headers.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.darwin-x86.mk b/components/autofill_jni_headers.target.darwin-x86.mk
index f4ade00..ce3d1b3 100644
--- a/components/autofill_jni_headers.target.darwin-x86.mk
+++ b/components/autofill_jni_headers.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.linux-arm.mk b/components/autofill_jni_headers.target.linux-arm.mk
index b87ef2f..40660f4 100644
--- a/components/autofill_jni_headers.target.linux-arm.mk
+++ b/components/autofill_jni_headers.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.linux-mips.mk b/components/autofill_jni_headers.target.linux-mips.mk
index 342292e..20b8092 100644
--- a/components/autofill_jni_headers.target.linux-mips.mk
+++ b/components/autofill_jni_headers.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_jni_headers.target.linux-x86.mk b/components/autofill_jni_headers.target.linux-x86.mk
index f4ade00..ce3d1b3 100644
--- a/components/autofill_jni_headers.target.linux-x86.mk
+++ b/components/autofill_jni_headers.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 16fe939..8f0621c 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -103,4 +103,11 @@
     Chrome Autofill settings
   </message>
 
+  <message name="IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET" desc="Message displayed to user when user entered a credit card number that is not supported by Google Wallet.">
+    This type of card is not supported by Google Wallet. Please select a different card.
+  </message>
+  <message name="IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET_FOR_MERCHANT" desc="Message displayed to user when user entered a credit card number that is not supported by Google Wallet for the particular merchant site the user is on.">
+    This type of card is not supported by Google Wallet for this merchant. Please select a different card.
+  </message>
+
 </grit-part>
diff --git a/components/breakpad.gypi b/components/breakpad.gypi
index b125713..f613bfb 100644
--- a/components/breakpad.gypi
+++ b/components/breakpad.gypi
@@ -101,6 +101,9 @@
           'variables': {
             'breakpad_component_target': 1,
           },
+          'defines': [
+            'COMPILE_CONTENT_STATICALLY',
+          ],
           'dependencies': [
             '../base/base.gyp:base_nacl_win64',
             '../breakpad/breakpad.gyp:breakpad_handler_win64',
diff --git a/components/breakpad/app/breakpad_client.cc b/components/breakpad/app/breakpad_client.cc
index 0c488da..16f7dc7 100644
--- a/components/breakpad/app/breakpad_client.cc
+++ b/components/breakpad/app/breakpad_client.cc
@@ -50,7 +50,7 @@
 }
 
 bool BreakpadClient::AboutToRestart() {
-  return true;
+  return false;
 }
 
 bool BreakpadClient::GetDeferredUploadsSupported(bool is_per_usr_install) {
@@ -58,7 +58,7 @@
 }
 
 bool BreakpadClient::GetIsPerUserInstall(const base::FilePath& exe_path) {
-  return false;
+  return true;
 }
 
 bool BreakpadClient::GetShouldDumpLargerDumps(bool is_per_user_install) {
@@ -100,7 +100,7 @@
 }
 
 bool BreakpadClient::IsRunningUnattended() {
-  return false;
+  return true;
 }
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
diff --git a/components/breakpad/app/breakpad_win.cc b/components/breakpad/app/breakpad_win.cc
index 84ee9bb..e2fca70 100644
--- a/components/breakpad/app/breakpad_win.cc
+++ b/components/breakpad/app/breakpad_win.cc
@@ -421,6 +421,9 @@
 // before doing so!
 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
     const wchar_t* key, const wchar_t* value) {
+  if (!g_dynamic_entries)
+    return;
+
   // CustomInfoEntry limits the length of key and value. If they exceed
   // their maximum length the underlying string handling functions raise
   // an exception and prematurely trigger a crash. Truncate here.
@@ -448,6 +451,9 @@
 
 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
     const wchar_t* key) {
+  if (!g_dynamic_entries)
+    return;
+
   std::wstring key_string(key);
   DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string);
   if (it == g_dynamic_entries->end())
diff --git a/components/breakpad/tools/dmp2minidump.py b/components/breakpad/tools/dmp2minidump.py
new file mode 100755
index 0000000..7823d48
--- /dev/null
+++ b/components/breakpad/tools/dmp2minidump.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""A tool to extract minidumps from dmp crash dumps."""
+
+import os
+import sys
+from cgi import parse_multipart
+
+
+def ProcessDump(dump_file, minidump_file):
+  """Extracts the part of the dump file that minidump_stackwalk can read.
+
+  The dump files generated by the breakpad integration multi-part form data
+  that include the minidump as file attachment.
+
+  Args:
+    dump_file: the dump file that needs to be processed.
+    minidump_file: the file to write the minidump to.
+  """
+  try:
+    dump = open(dump_file, 'rb')
+    boundary = dump.readline().strip()[2:]
+    data = parse_multipart(dump, {'boundary': boundary})
+  except:
+    print 'Failed to read dmp file %s' % dump_file
+    return
+
+  if not 'upload_file_minidump' in data:
+    print 'Could not find minidump file in dump.'
+    return
+
+  f = open(minidump_file, 'w')
+  f.write("\r\n".join(data['upload_file_minidump']))
+  f.close()
+
+
+def main():
+  if len(sys.argv) != 3:
+    print 'Usage: %s [dmp file] [minidump]' % sys.argv[0]
+    print ''
+    print 'Extracts the minidump stored in the crash dump file'
+    return 1
+
+  ProcessDump(sys.argv[1], sys.argv[2])
+
+
+if '__main__' == __name__:
+  sys.exit(main())
diff --git a/components/breakpad/tools/generate_breakpad_symbols.py b/components/breakpad/tools/generate_breakpad_symbols.py
new file mode 100755
index 0000000..e7ec3a9
--- /dev/null
+++ b/components/breakpad/tools/generate_breakpad_symbols.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""A tool to generate symbols for a binary suitable for breakpad.
+
+Currently, the tool only supports Linux, Android, and Mac. Support for other
+platforms is planned.
+"""
+
+import errno
+import optparse
+import os
+import Queue
+import re
+import shutil
+import subprocess
+import sys
+import threading
+
+
+CONCURRENT_TASKS=4
+
+
+def GetCommandOutput(command):
+  """Runs the command list, returning its output.
+
+  Prints the given command (which should be a list of one or more strings),
+  then runs it and returns its output (stdout) as a string.
+
+  From chromium_utils.
+  """
+  devnull = open(os.devnull, 'w')
+  proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull,
+                          bufsize=1)
+  output = proc.communicate()[0]
+  return output
+
+
+def GetDumpSymsBinary(build_dir=None):
+  """Returns the path to the dump_syms binary."""
+  DUMP_SYMS = 'dump_syms'
+  dump_syms_bin = os.path.join(os.path.expanduser(build_dir), DUMP_SYMS)
+  if not os.access(dump_syms_bin, os.X_OK):
+    print 'Cannot find %s.' % DUMP_SYMS
+    sys.exit(1)
+
+  return dump_syms_bin
+
+
+def Resolve(path, exe_path, loader_path, rpaths):
+  """Resolve a dyld path.
+
+  @executable_path is replaced with |exe_path|
+  @loader_path is replaced with |loader_path|
+  @rpath is replaced with the first path in |rpaths| where the referenced file
+      is found
+  """
+  path = path.replace('@loader_path', loader_path)
+  path = path.replace('@executable_path', exe_path)
+  if path.find('@rpath') != -1:
+    for rpath in rpaths:
+      new_path = Resolve(path.replace('@rpath', rpath), exe_path, loader_path,
+                         [])
+      if os.access(new_path, os.X_OK):
+        return new_path
+    return ''
+  return path
+
+
+def GetSharedLibraryDependenciesLinux(binary):
+  """Return absolute paths to all shared library dependecies of the binary.
+
+  This implementation assumes that we're running on a Linux system."""
+  ldd = GetCommandOutput(['ldd', binary])
+  lib_re = re.compile('\t.* => (.+) \(.*\)$')
+  result = []
+  for line in ldd.splitlines():
+    m = lib_re.match(line)
+    if m:
+      result.append(m.group(1))
+  return result
+
+
+def GetSharedLibraryDependenciesMac(binary, exe_path):
+  """Return absolute paths to all shared library dependecies of the binary.
+
+  This implementation assumes that we're running on a Mac system."""
+  loader_path = os.path.dirname(binary)
+  otool = GetCommandOutput(['otool', '-l', binary]).splitlines()
+  rpaths = []
+  for idx, line in enumerate(otool):
+    if line.find('cmd LC_RPATH') != -1:
+      m = re.match(' *path (.*) \(offset .*\)$', otool[idx+2])
+      rpaths.append(m.group(1))
+
+  otool = GetCommandOutput(['otool', '-L', binary]).splitlines()
+  lib_re = re.compile('\t(.*) \(compatibility .*\)$')
+  deps = []
+  for line in otool:
+    m = lib_re.match(line)
+    if m:
+      dep = Resolve(m.group(1), exe_path, loader_path, rpaths)
+      if dep:
+        deps.append(os.path.normpath(dep))
+  return deps
+
+
+def GetSharedLibraryDependencies(options, binary, exe_path):
+  """Return absolute paths to all shared library dependecies of the binary."""
+  deps = []
+  if sys.platform.startswith('linux'):
+    deps = GetSharedLibraryDependenciesLinux(binary)
+  elif sys.platform == 'darwin':
+    deps = GetSharedLibraryDependenciesMac(binary, exe_path)
+  else:
+    print "Platform not supported."
+    sys.exit(1)
+
+  result = []
+  build_dir = os.path.abspath(options.build_dir)
+  for dep in deps:
+    if (os.access(dep, os.X_OK) and
+        os.path.abspath(os.path.dirname(dep)).startswith(build_dir)):
+      result.append(dep)
+  return result
+
+
+def mkdir_p(path):
+  """Simulates mkdir -p."""
+  try:
+    os.makedirs(path)
+  except OSError as e:
+    if e.errno == errno.EEXIST and os.path.isdir(path):
+      pass
+    else: raise
+
+
+def GenerateSymbols(options, binaries):
+  """Dumps the symbols of binary and places them in the given directory."""
+
+  queue = Queue.Queue()
+
+  def _Worker():
+    while True:
+      binary = queue.get()
+
+      syms = GetCommandOutput([GetDumpSymsBinary(options.build_dir),
+                               binary])
+      module_line = re.match("MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n", syms)
+      output_path = os.path.join(options.symbols_dir, module_line.group(2),
+                                 module_line.group(1))
+      mkdir_p(output_path)
+      symbol_file = "%s.sym" % module_line.group(2)
+      f = open(os.path.join(output_path, symbol_file), 'w')
+      f.write(syms)
+      f.close()
+
+      queue.task_done()
+
+  for binary in binaries:
+    queue.put(binary)
+
+  for _ in range(options.jobs):
+    t = threading.Thread(target=_Worker)
+    t.daemon = True
+    t.start()
+
+  queue.join()
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('', '--build-dir', default='',
+                    help='The build output directory.')
+  parser.add_option('', '--symbols-dir', default='',
+                    help='The directory where to write the symbols file.')
+  parser.add_option('', '--binary', default='',
+                    help='The path of the binary to generate symbols for.')
+  parser.add_option('', '--clear', default=False, action='store_true',
+                    help='Clear the symbols directory before writing new '
+                         'symbols.')
+  parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store',
+                    type='int', help='Number of parallel tasks to run.')
+
+  (options, _) = parser.parse_args()
+
+  if not options.symbols_dir:
+    print "Required option --symbols-dir missing."
+    return 1
+
+  if not options.build_dir:
+    print "Required option --build-dir missing."
+    return 1
+
+  if not options.binary:
+    print "Required option --binary missing."
+    return 1
+
+  if not os.access(options.binary, os.X_OK):
+    print "Cannot find %s." % options.binary
+    return 1
+
+  if options.clear:
+    try:
+      shutil.rmtree(options.symbols_dir)
+    except:
+      pass
+
+  # Build the transitive closure of all dependencies.
+  binaries = set([options.binary])
+  queue = [options.binary]
+  exe_path = os.path.dirname(options.binary)
+  while queue:
+    deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path)
+    new_deps = set(deps) - binaries
+    binaries |= new_deps
+    queue.extend(list(new_deps))
+
+  GenerateSymbols(options, binaries)
+
+  return 0
+
+
+if '__main__' == __name__:
+  sys.exit(main())
diff --git a/components/breakpad/tools/process_dumps_linux.py b/components/breakpad/tools/process_dumps_linux.py
deleted file mode 100755
index 1f0ba9d..0000000
--- a/components/breakpad/tools/process_dumps_linux.py
+++ /dev/null
@@ -1,300 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-"""A tool to collect crash signatures for Chrome builds on Linux."""
-
-import fnmatch
-import optparse
-import os
-import shutil
-import subprocess
-import struct
-import sys
-import tempfile
-
-
-def VerifySymbolAndCopyToTempDir(symbol_file, temp_dir, sym_module_name):
-  """Verify the symbol file looks correct and copy it to the right place
-  in temp_dir.
-
-  Args:
-    symbol_file: the path to the symbol file.
-    temp_dir: the base of the temp directory where the symbol file will reside.
-  Returns:
-    True on success.
-  """
-  symbol = open(symbol_file)
-  signature_line = symbol.readline().strip().split()
-  symbol.close()
-  # signature_line should look like:
-  # MODULE Linux x86 28D8A79A426807B5462CBA24F56746750 chrome
-  if (len(signature_line) == 5 and signature_line[0] == 'MODULE' and
-      signature_line[1] == 'Linux' and signature_line[4] == sym_module_name and
-      len(signature_line[3]) == 33):
-    dest = os.path.join(temp_dir, signature_line[4], signature_line[3])
-    os.makedirs(dest)
-    dest_file = os.path.join(dest, '%s.sym' % signature_line[4])
-    shutil.copyfile(symbol_file, dest_file)
-    return True
-  return False
-
-
-def GetCommandOutput(command):
-  """Runs the command list, returning its output.
-
-  Prints the given command (which should be a list of one or more strings),
-  then runs it and returns its output (stdout and stderr) as a string.
-
-  If the command exits with an error, raises OSError.
-
-  From chromium_utils.
-  """
-  proc = subprocess.Popen(command, stdout=subprocess.PIPE,
-                          stderr=subprocess.STDOUT, bufsize=1)
-  output = proc.communicate()[0]
-  if proc.returncode:
-    raise OSError('%s: %s' % (subprocess.list2cmdline(command), output))
-  return output
-
-
-def GetCrashDumpDir():
-  """Returns the default crash dump directory used by Chromium."""
-  config_home = os.environ.get('XDG_CONFIG_HOME')
-  if not config_home:
-    home = os.path.expanduser('~')
-    if not home:
-      return ''
-    config_home = os.path.join(home, '.config')
-  return os.path.join(config_home, 'chromium', 'Crash Reports')
-
-
-def GetStackTrace(processor_bin, symbol_path, dump_file):
-  """Gets and prints the stack trace from a crash dump file.
-
-  Args:
-    processor_bin: the path to the processor.
-    symbol_path: root dir for the symbols.
-    dump_file: the path to the dump file.
-  Returns:
-    A string representing the stack trace.
-  """
-  # Run processor to analyze crash dump.
-  cmd = [processor_bin, '-m', dump_file, symbol_path]
-
-  try:
-    output = GetCommandOutput(cmd)
-  except OSError:
-    return 'Cannot get stack trace.'
-
-  # Retrieve stack trace from processor output. Processor output looks like:
-  # ----------------
-  # Debug output
-  # ...
-  # Debug output
-  # Module ...
-  # ...
-  # Module ...
-  #
-  # N|...     <--+
-  # ...          |--- crashed thread stack trace
-  # N|...     <--+
-  # M|...
-  # ...
-  # ----------------
-  # where each line of the stack trace looks like:
-  # ThreadNumber|FrameNumber|ExeName|Function|SourceFile|LineNo|Offset
-
-  stack_trace_frames = []
-  idx = output.find('\nModule')
-  if idx >= 0:
-    output = output[idx+1:]
-    idx = output.find('\n\n')
-    if idx >= 0:
-      output = output[idx+2:].splitlines()
-      if output:
-        first_line = output[0].split('|')
-        if first_line:
-          crashed_thread = first_line[0]
-          for line in output:
-            line_split = line.split('|')
-            if not line_split:
-              break
-            if line_split[0] != crashed_thread:
-              break
-            stack_trace_frames.append(line_split)
-  if not stack_trace_frames:
-    return 'Cannot get stack trace.'
-  stack_trace = []
-  for frame in stack_trace_frames:
-    if len(frame) != 7:
-      continue
-    (exe, func, source, line, offset) = frame[2:]
-    if not exe or not source or not line or not offset:
-      continue
-    idx = func.find('(')
-    if idx >= 0:
-      func = func[:idx]
-    if not func:
-      continue
-    frame_output = '%s!%s+%s [%s @ %s]' % (exe, func, offset, source, line)
-    stack_trace.append(frame_output)
-  return '\n'.join(stack_trace)
-
-
-def LocateFiles(pattern, root=os.curdir):
-  """Yields files matching pattern found in root and its subdirectories.
-
-  An exception is thrown if root doesn't exist.
-
-  From chromium_utils."""
-  root = os.path.expanduser(root)
-  for path, dirs, files in os.walk(os.path.abspath(root)):
-    for filename in fnmatch.filter(files, pattern):
-      yield os.path.join(path, filename)
-
-
-def ProcessDump(dump_file, temp_dir):
-  """Extracts the part of the dump file that minidump_stackwalk can read.
-
-  Args:
-    dump_file: the dump file that needs to be processed.
-    temp_dir: the temp directory to put the dump file in.
-  Returns:
-    path of the processed dump file.
-  """
-  dump = open(dump_file, 'rb')
-  dump_data = dump.read()
-  dump.close()
-  idx = dump_data.find('MDMP')
-  if idx < 0:
-    return ''
-
-  dump_data = dump_data[idx:]
-  if not dump_data:
-    return ''
-  (dump_fd, dump_name) = tempfile.mkstemp(suffix='chromedump', dir=temp_dir)
-  os.write(dump_fd, dump_data)
-  os.close(dump_fd)
-  return dump_name
-
-
-def main_linux(options, args):
-  # minidump_stackwalk is part of Google Breakpad. You may need to checkout
-  # the code and build your own copy. http://google-breakpad.googlecode.com/
-  LINUX_PROCESSOR = 'minidump_stackwalk'
-  processor_bin = None
-  if options.processor_dir:
-    bin = os.path.join(os.path.expanduser(options.processor_dir),
-                       LINUX_PROCESSOR)
-    if os.access(bin, os.X_OK):
-      processor_bin = bin
-  else:
-    for path in os.environ['PATH'].split(':'):
-      bin = os.path.join(path, LINUX_PROCESSOR)
-      if os.access(bin, os.X_OK):
-        processor_bin = bin
-        break
-  if not processor_bin:
-    print 'Cannot find minidump_stackwalk.'
-    return 1
-
-  if options.symbol_filename:
-    symbol_file = options.symbol_filename
-  else:
-    if options.architecture:
-      bits = options.architecture
-    else:
-      bits = struct.calcsize('P') * 8
-    if bits == 32:
-      symbol_file = 'chrome.breakpad.ia32'
-    elif bits == 64:
-      symbol_file = 'chrome.breakpad.x64'
-    else:
-      print 'Unknown architecture'
-      return 1
-
-  symbol_dir = options.symbol_dir
-  if not options.symbol_dir:
-    symbol_dir = os.curdir
-  symbol_dir = os.path.abspath(os.path.expanduser(symbol_dir))
-  symbol_file = os.path.join(symbol_dir, symbol_file)
-  if not os.path.exists(symbol_file):
-    print 'Cannot find symbols.'
-    return 1
-  symbol_time = os.path.getmtime(symbol_file)
-
-  dump_files = []
-  if options.dump_file:
-    dump_files.append(options.dump_file)
-  else:
-    dump_dir = options.dump_dir
-    if not dump_dir:
-      dump_dir = GetCrashDumpDir()
-    if not dump_dir:
-      print 'Cannot find dump files.'
-      return 1
-    for dump_file in LocateFiles(pattern='*.dmp', root=dump_dir):
-      file_time = os.path.getmtime(dump_file)
-      if file_time < symbol_time:
-        # Ignore dumps older than symbol file.
-        continue
-      dump_files.append(dump_file)
-
-  temp_dir = tempfile.mkdtemp(suffix='chromedump')
-  if not VerifySymbolAndCopyToTempDir(symbol_file, temp_dir,
-                                      options.sym_module_name):
-    print 'Cannot parse symbols.'
-    shutil.rmtree(temp_dir)
-    return 1
-
-  dump_count = 0
-  for dump_file in dump_files:
-    processed_dump_file = ProcessDump(dump_file, temp_dir)
-    if not processed_dump_file:
-      continue
-    print '-------------------------'
-    print GetStackTrace(processor_bin, temp_dir, processed_dump_file)
-    print
-    os.remove(processed_dump_file)
-    dump_count += 1
-
-  shutil.rmtree(temp_dir)
-  print '%s dumps found' % dump_count
-  return 0
-
-
-def main():
-  if not sys.platform.startswith('linux'):
-    return 1
-  parser = optparse.OptionParser()
-  parser.add_option('', '--processor-dir', type='string', default='',
-                    help='The directory where the processor is installed. '
-                         'The processor is used to get stack trace from dumps. '
-                          'Searches $PATH by default')
-  parser.add_option('', '--dump-file', type='string', default='',
-                    help='The path of the dump file to be processed. '
-                         'Overwrites dump-path.')
-  parser.add_option('', '--dump-dir', type='string', default='',
-                    help='The directory where dump files are stored. '
-                         'Searches this directory if dump-file is not '
-                         'specified. Default is the Chromium crash directory.')
-  parser.add_option('', '--symbol-dir', default='',
-                    help='The directory with the symbols file. [Required]')
-  parser.add_option('', '--symbol-filename', default='',
-                    help='The name of the symbols file to use.  '
-                         'This argument overrides --architecture.')
-  parser.add_option('', '--architecture', type='int', default=None,
-                    help='Override automatic x86/x86-64 detection. '
-                         'Valid values are 32 and 64')
-  parser.add_option('', '--sym-module-name', type='string', default='chrome',
-                    help='The module name for the symbol file.  '
-                         'Default: chrome')
-
-  (options, args) = parser.parse_args()
-  return main_linux(options, args)
-
-
-if '__main__' == __name__:
-  sys.exit(main())
diff --git a/components/components.gyp b/components/components.gyp
index 1c2a774..d9b31c4 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -14,10 +14,10 @@
     'auto_login_parser.gypi',
     'breakpad.gypi',
     'browser_context_keyed_service.gypi',
-    'components_tests.gypi',
     'dom_distiller.gypi',
     'json_schema.gypi',
     'navigation_interception.gypi',
+    'navigation_metrics.gypi',
     'onc.gypi',
     'plugins.gypi',
     'policy.gypi',
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
new file mode 100644
index 0000000..02e5df6
--- /dev/null
+++ b/components/components_tests.gyp
@@ -0,0 +1,215 @@
+# Copyright (c) 2012 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.
+
+{
+  'variables': {
+    # This turns on e.g. the filename-based detection of which
+    # platforms to include source files on (e.g. files ending in
+    # _mac.h or _mac.cc are only compiled on MacOSX).
+    'chromium_code': 1,
+   },
+  'conditions': [
+    ['android_webview_build == 0', {
+      'targets': [
+        {
+          'target_name': 'components_unittests',
+          'type': '<(gtest_target_type)',
+          'sources': [
+            'auto_login_parser/auto_login_parser_unittest.cc',
+            'autofill/core/common/form_data_unittest.cc',
+            'autofill/core/common/form_field_data_unittest.cc',
+            'autofill/core/common/password_form_fill_data_unittest.cc',
+            'browser_context_keyed_service/browser_context_dependency_manager_unittest.cc',
+            'browser_context_keyed_service/dependency_graph_unittest.cc',
+            'dom_distiller/core/distiller_url_fetcher_unittest.cc',
+            'dom_distiller/core/dom_distiller_database_unittest.cc',
+            'dom_distiller/core/dom_distiller_model_unittest.cc',
+            'dom_distiller/core/dom_distiller_store_unittest.cc',
+            'dom_distiller/core/article_entry_unittest.cc',
+            'json_schema/json_schema_validator_unittest.cc',
+            'json_schema/json_schema_validator_unittest_base.cc',
+            'json_schema/json_schema_validator_unittest_base.h',
+            'navigation_interception/intercept_navigation_resource_throttle_unittest.cc',
+            'precache/core/precache_fetcher_unittest.cc',
+            'sessions/serialized_navigation_entry_unittest.cc',
+            'test/run_all_unittests.cc',
+            'translate/common/translate_metrics_unittest.cc',
+            'translate/common/translate_util_unittest.cc',
+            'translate/language_detection/language_detection_util_unittest.cc',
+            # TODO(asvitkine): These should be tested on iOS too.
+            'variations/entropy_provider_unittest.cc',
+            'variations/metrics_util_unittest.cc',
+            'variations/variations_associated_data_unittest.cc',
+            'variations/variations_seed_processor_unittest.cc',
+            'visitedlink/test/visitedlink_unittest.cc',
+            'webdata/encryptor/encryptor_password_mac_unittest.cc',
+            'webdata/encryptor/encryptor_unittest.cc',
+            'web_modal/web_contents_modal_dialog_manager_unittest.cc',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'dependencies': [
+            '../base/base.gyp:test_support_base',
+            '../sync/sync.gyp:sync',
+            '../testing/gmock.gyp:gmock',
+            '../testing/gtest.gyp:gtest',
+
+            # Dependencies of autofill
+            'components.gyp:autofill_core_common',
+
+            # Dependencies of auto_login_parser
+            'components.gyp:auto_login_parser',
+
+            # Dependencies of browser_context_keyed_service
+            'components.gyp:browser_context_keyed_service',
+
+            # Dependencies of dom_distiller
+            'components.gyp:distilled_page_proto',
+            'components.gyp:dom_distiller_core',
+
+            # Dependencies of encryptor
+            'components.gyp:encryptor',
+
+            # Dependencies of json_schema
+            'components.gyp:json_schema',
+
+            # Dependencies of intercept_navigation_resource_throttle_unittest.cc
+            '../content/content_shell_and_tests.gyp:test_support_content',
+            '../skia/skia.gyp:skia',
+            'components.gyp:navigation_interception',
+
+            # Dependencies of policy
+            'components.gyp:policy_component',
+
+            # Dependencies of precache
+            'components.gyp:precache_core',
+            'components.gyp:precache_core_proto',
+
+            # Dependencies of sessions
+            '../third_party/protobuf/protobuf.gyp:protobuf_lite',
+            'components.gyp:sessions',
+            'components.gyp:sessions_test_support',
+
+            # Dependencies of translate.
+            'components.gyp:translate_common',
+            'components.gyp:translate_language_detection',
+
+            # Dependencies of variations
+            'components.gyp:variations',
+
+            # Dependencies of visitedlink
+            'components.gyp:visitedlink_browser',
+            'components.gyp:visitedlink_renderer',
+            '../content/content_resources.gyp:content_resources',
+
+            'components.gyp:web_modal',
+            'components.gyp:web_modal_test_support',
+          ],
+          'conditions': [
+            ['OS == "ios"', {
+              'sources/': [
+                ['exclude', '\\.cc$'],
+                ['include', '^test/run_all_unittests\\.cc$'],
+                # TODO(ios): Include files here as they are made to work, see
+                # http://crbug.com/303011.
+                # TODO(asvitkine): Bring up varations/ unittests on iOS.
+                ['include', '^dom_distiller'],
+                ['include', '^translate'],
+              ],
+              'dependencies!': [
+                'autofill_core_common',
+                'navigation_interception',
+                'visitedlink_renderer',
+              ],
+            }],
+            ['OS == "android"', {
+              'sources!': [
+                'web_modal/web_contents_modal_dialog_manager_unittest.cc',
+              ],
+              'dependencies!': [
+                'components.gyp:web_modal',
+                'components.gyp:web_modal_test_support',
+              ],
+            }],
+            ['OS == "android" and gtest_target_type == "shared_library"', {
+              'dependencies': [
+                '../testing/android/native_test.gyp:native_test_native_code',
+              ]
+            }],
+            ['OS=="win" and win_use_allocator_shim==1', {
+              'dependencies': [
+                '../base/allocator/allocator.gyp:allocator',
+              ],
+            }],
+            ['OS=="linux" and component=="shared_library" and linux_use_tcmalloc==1', {
+            'dependencies': [
+                '<(DEPTH)/base/allocator/allocator.gyp:allocator',
+            ],
+            'link_settings': {
+                'ldflags': ['-rdynamic'],
+            },
+            }],
+            ['configuration_policy==1', {
+              'sources': [
+                'policy/core/common/schema_unittest.cc',
+              ],
+            }],
+          ],
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [4267, ],
+        },
+      ],
+    }],
+    ['OS != "ios" and android_webview_build == 0', {
+      'targets': [
+        {
+          'target_name': 'components_perftests',
+          'type': '<(gtest_target_type)',
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../base/base.gyp:test_support_perf',
+            '../content/content_shell_and_tests.gyp:test_support_content',
+            '../testing/gtest.gyp:gtest',
+            '../ui/compositor/compositor.gyp:compositor',
+            'components.gyp:visitedlink_browser',
+          ],
+         'include_dirs': [
+           '..',
+         ],
+         'sources': [
+           'visitedlink/test/visitedlink_perftest.cc',
+         ],
+         'conditions': [
+           ['OS == "android" and gtest_target_type == "shared_library"', {
+             'dependencies': [
+               '../testing/android/native_test.gyp:native_test_native_code',
+             ],
+           }],
+         ],
+         # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+         'msvs_disabled_warnings': [ 4267, ],
+        },
+      ],
+      'conditions': [
+        ['OS == "android" and gtest_target_type == "shared_library"', {
+          'targets': [
+            {
+              'target_name': 'components_unittests_apk',
+              'type': 'none',
+              'dependencies': [
+                'components_unittests',
+              ],
+              'variables': {
+                'test_suite_name': 'components_unittests',
+                'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)components_unittests<(SHARED_LIB_SUFFIX)',
+              },
+              'includes': [ '../build/apk_test.gypi' ],
+            },
+          ],
+        }],
+      ],
+    }],
+  ],
+}
diff --git a/components/components_tests.gypi b/components/components_tests.gypi
deleted file mode 100644
index 12a79dc..0000000
--- a/components/components_tests.gypi
+++ /dev/null
@@ -1,207 +0,0 @@
-# Copyright (c) 2012 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.
-
-{
-  'conditions': [
-    ['android_webview_build == 0', {
-      'targets': [
-        {
-          'target_name': 'components_unittests',
-          'type': '<(gtest_target_type)',
-          'sources': [
-            'autofill/core/common/form_data_unittest.cc',
-            'autofill/core/common/form_field_data_unittest.cc',
-            'auto_login_parser/auto_login_parser_unittest.cc',
-            'browser_context_keyed_service/browser_context_dependency_manager_unittest.cc',
-            'browser_context_keyed_service/dependency_graph_unittest.cc',
-            'dom_distiller/core/distiller_url_fetcher_unittest.cc',
-            'dom_distiller/core/dom_distiller_database_unittest.cc',
-            'dom_distiller/core/dom_distiller_store_unittest.cc',
-            'dom_distiller/core/article_entry_unittest.cc',
-            'json_schema/json_schema_validator_unittest.cc',
-            'json_schema/json_schema_validator_unittest_base.cc',
-            'json_schema/json_schema_validator_unittest_base.h',
-            'navigation_interception/intercept_navigation_resource_throttle_unittest.cc',
-            'precache/core/precache_fetcher_unittest.cc',
-            'sessions/serialized_navigation_entry_unittest.cc',
-            'test/run_all_unittests.cc',
-            'translate/common/translate_metrics_unittest.cc',
-            'translate/common/translate_util_unittest.cc',
-            'translate/language_detection/language_detection_util_unittest.cc',
-            # TODO(asvitkine): These should be tested on iOS too.
-            'variations/entropy_provider_unittest.cc',
-            'variations/metrics_util_unittest.cc',
-            'variations/variations_associated_data_unittest.cc',
-            'variations/variations_seed_processor_unittest.cc',
-            'visitedlink/test/visitedlink_unittest.cc',
-            'webdata/encryptor/encryptor_password_mac_unittest.cc',
-            'webdata/encryptor/encryptor_unittest.cc',
-            'web_modal/web_contents_modal_dialog_manager_unittest.cc',
-          ],
-          'include_dirs': [
-            '..',
-          ],
-          'dependencies': [
-            '../base/base.gyp:test_support_base',
-            '../sync/sync.gyp:sync',
-            '../testing/gmock.gyp:gmock',
-            '../testing/gtest.gyp:gtest',
-
-            # Dependencies of autofill
-            'autofill_core_common',
-
-            # Dependencies of auto_login_parser
-            'auto_login_parser',
-
-            # Dependencies of browser_context_keyed_service
-            'browser_context_keyed_service',
-
-            # Dependencies of dom_distiller
-            'distilled_page_proto',
-            'dom_distiller_core',
-
-            # Dependencies of encryptor
-            'encryptor',
-
-            # Dependencies of json_schema
-            'json_schema',
-
-            # Dependencies of intercept_navigation_resource_throttle_unittest.cc
-            '../content/content_shell_and_tests.gyp:test_support_content',
-            '../skia/skia.gyp:skia',
-            'navigation_interception',
-
-            # Dependencies of policy
-            'policy_component',
-
-            # Dependencies of precache
-            'precache_core',
-            'precache_core_proto',
-
-            # Dependencies of sessions
-            '../third_party/protobuf/protobuf.gyp:protobuf_lite',
-            'sessions',
-            'sessions_test_support',
-
-            # Dependencies of translate.
-            'translate_common',
-            'translate_language_detection',
-
-            # Dependencies of variations
-            'variations',
-
-            # Dependencies of visitedlink
-            'visitedlink_browser',
-            'visitedlink_renderer',
-            '../content/content_resources.gyp:content_resources',
-
-            'web_modal',
-            'web_modal_test_support',
-          ],
-          'conditions': [
-            ['OS == "ios"', {
-              'sources/': [
-                ['exclude', '\\.cc$'],
-                ['include', '^test/run_all_unittests\\.cc$'],
-                # TODO(ios): Include files here as they are made to work, see
-                # http://crbug.com/303011.
-                # TODO(asvitkine): Bring up varations/ unittests on iOS.
-                ['include', '^dom_distiller'],
-                ['include', '^translate'],
-              ],
-              'dependencies!': [
-                'autofill_core_common',
-                'navigation_interception',
-                'visitedlink_renderer',
-              ],
-            }],
-            ['OS == "android"', {
-              'sources!': [
-                'web_modal/web_contents_modal_dialog_manager_unittest.cc',
-              ],
-              'dependencies!': [
-                'web_modal',
-                'web_modal_test_support',
-              ],
-            }],
-            ['OS == "android" and gtest_target_type == "shared_library"', {
-              'dependencies': [
-                '../testing/android/native_test.gyp:native_test_native_code',
-              ]
-            }],
-            ['OS=="win" and win_use_allocator_shim==1', {
-              'dependencies': [
-                '../base/allocator/allocator.gyp:allocator',
-              ],
-            }],
-            ['OS=="linux" and component=="shared_library" and linux_use_tcmalloc==1', {
-            'dependencies': [
-                '<(DEPTH)/base/allocator/allocator.gyp:allocator',
-            ],
-            'link_settings': {
-                'ldflags': ['-rdynamic'],
-            },
-            }],
-            ['configuration_policy==1', {
-              'sources': [
-                'policy/core/common/schema_unittest.cc',
-              ],
-            }],
-          ],
-          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-          'msvs_disabled_warnings': [4267, ],
-        },
-      ],
-    }],
-    ['OS != "ios" and android_webview_build == 0', {
-      'targets': [
-        {
-          'target_name': 'components_perftests',
-          'type': '<(gtest_target_type)',
-          'dependencies': [
-            '../base/base.gyp:base',
-            '../base/base.gyp:test_support_perf',
-            '../content/content_shell_and_tests.gyp:test_support_content',
-            '../testing/gtest.gyp:gtest',
-            '../ui/compositor/compositor.gyp:compositor',
-            'visitedlink_browser',
-          ],
-         'include_dirs': [
-           '..',
-         ],
-         'sources': [
-           'visitedlink/test/visitedlink_perftest.cc',
-         ],
-         'conditions': [
-           ['OS == "android" and gtest_target_type == "shared_library"', {
-             'dependencies': [
-               '../testing/android/native_test.gyp:native_test_native_code',
-             ],
-           }],
-         ],
-         # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-         'msvs_disabled_warnings': [ 4267, ],
-        },
-      ],
-      'conditions': [
-        ['OS == "android" and gtest_target_type == "shared_library"', {
-          'targets': [
-            {
-              'target_name': 'components_unittests_apk',
-              'type': 'none',
-              'dependencies': [
-                'components_unittests',
-              ],
-              'variables': {
-                'test_suite_name': 'components_unittests',
-                'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)components_unittests<(SHARED_LIB_SUFFIX)',
-              },
-              'includes': [ '../build/apk_test.gypi' ],
-            },
-          ],
-        }],
-      ],
-    }],
-  ],
-}
diff --git a/components/dom_distiller.gypi b/components/dom_distiller.gypi
index 4efe807..abece3f 100644
--- a/components/dom_distiller.gypi
+++ b/components/dom_distiller.gypi
@@ -82,6 +82,8 @@
             'dom_distiller/core/dom_distiller_constants.h',
             'dom_distiller/core/dom_distiller_database.cc',
             'dom_distiller/core/dom_distiller_database.h',
+            'dom_distiller/core/dom_distiller_model.cc',
+            'dom_distiller/core/dom_distiller_model.h',
             'dom_distiller/core/dom_distiller_service.cc',
             'dom_distiller/core/dom_distiller_service.h',
             'dom_distiller/core/dom_distiller_store.cc',
diff --git a/components/dom_distiller/core/article_entry.cc b/components/dom_distiller/core/article_entry.cc
index 2e370a4..1550caf 100644
--- a/components/dom_distiller/core/article_entry.cc
+++ b/components/dom_distiller/core/article_entry.cc
@@ -5,6 +5,7 @@
 #include "components/dom_distiller/core/article_entry.h"
 
 #include "base/logging.h"
+#include "sync/api/sync_change.h"
 
 using sync_pb::EntitySpecifics;
 using sync_pb::ArticlePage;
@@ -45,4 +46,24 @@
   return specifics;
 }
 
+ArticleEntry GetEntryFromChange(const syncer::SyncChange& change) {
+  DCHECK(change.IsValid());
+  DCHECK(change.sync_data().IsValid());
+  return EntryFromSpecifics(change.sync_data().GetSpecifics());
+}
+
+std::string GetEntryIdFromSyncData(const syncer::SyncData& data) {
+  const EntitySpecifics& entity = data.GetSpecifics();
+  DCHECK(entity.has_article());
+  const ArticleSpecifics& specifics = entity.article();
+  DCHECK(specifics.has_entry_id());
+  return specifics.entry_id();
+}
+
+syncer::SyncData CreateLocalData(const ArticleEntry& entry) {
+  EntitySpecifics specifics = SpecificsFromEntry(entry);
+  const std::string& entry_id = entry.entry_id();
+  return syncer::SyncData::CreateLocalData(entry_id, entry_id, specifics);
+}
+
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/article_entry.h b/components/dom_distiller/core/article_entry.h
index 3811612..388dc51 100644
--- a/components/dom_distiller/core/article_entry.h
+++ b/components/dom_distiller/core/article_entry.h
@@ -5,9 +5,14 @@
 #ifndef COMPONENTS_DOM_DISTILLER_CORE_ARTICLE_ENTRY_H_
 #define COMPONENTS_DOM_DISTILLER_CORE_ARTICLE_ENTRY_H_
 
+#include "sync/api/sync_data.h"
 #include "sync/protocol/article_specifics.pb.h"
 #include "sync/protocol/sync.pb.h"
 
+namespace syncer {
+class SyncChange;
+}
+
 namespace dom_distiller {
 
 typedef sync_pb::ArticleSpecifics ArticleEntry;
@@ -20,6 +25,11 @@
 sync_pb::EntitySpecifics SpecificsFromEntry(const ArticleEntry& entry);
 ArticleEntry EntryFromSpecifics(const sync_pb::EntitySpecifics& specifics);
 
+ArticleEntry GetEntryFromChange(const syncer::SyncChange& change);
+std::string GetEntryIdFromSyncData(const syncer::SyncData& data);
+syncer::SyncData CreateLocalData(const ArticleEntry& entry);
+
+
 }  // namespace dom_distiller
 
 #endif
diff --git a/components/dom_distiller/core/dom_distiller_model.cc b/components/dom_distiller/core/dom_distiller_model.cc
new file mode 100644
index 0000000..79a95ab
--- /dev/null
+++ b/components/dom_distiller/core/dom_distiller_model.cc
@@ -0,0 +1,208 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dom_distiller/core/dom_distiller_model.h"
+
+using syncer::SyncChange;
+using syncer::SyncChangeList;
+using syncer::SyncData;
+using syncer::SyncDataList;
+
+namespace dom_distiller {
+
+DomDistillerModel::DomDistillerModel()
+    : next_key_(1) {}
+
+DomDistillerModel::DomDistillerModel(
+    const std::vector<ArticleEntry>& initial_data)
+    : next_key_(1) {
+  for (size_t i = 0; i < initial_data.size(); ++i) {
+    AddEntry(initial_data[i]);
+  }
+}
+
+DomDistillerModel::~DomDistillerModel() {}
+
+bool DomDistillerModel::GetEntryById(const std::string& entry_id,
+                                     ArticleEntry* entry) const {
+  KeyType key = 0;
+  if (!GetKeyById(entry_id, &key)) {
+    return false;
+  }
+  GetEntryByKey(key, entry);
+  return true;
+}
+
+bool DomDistillerModel::GetEntryByUrl(const GURL& url,
+                                     ArticleEntry* entry) const {
+  KeyType key = 0;
+  if (!GetKeyByUrl(url, &key)) {
+    return false;
+  }
+  GetEntryByKey(key, entry);
+  return true;
+}
+
+bool DomDistillerModel::GetKeyById(const std::string& entry_id,
+                                   KeyType* key) const {
+  StringToKeyMap::const_iterator it = entry_id_to_key_map_.find(entry_id);
+  if (it == entry_id_to_key_map_.end()) {
+    return false;
+  }
+  if (key != NULL) {
+    *key = it->second;
+  }
+  return true;
+}
+
+bool DomDistillerModel::GetKeyByUrl(const GURL& url, KeyType* key) const {
+  StringToKeyMap::const_iterator it = url_to_key_map_.find(url.spec());
+  if (it == url_to_key_map_.end()) {
+    return false;
+  }
+  if (key != NULL) {
+    *key = it->second;
+  }
+  return true;
+}
+
+void DomDistillerModel::GetEntryByKey(KeyType key, ArticleEntry* entry) const {
+  if (entry != NULL) {
+    EntryMap::const_iterator it = entries_.find(key);
+    DCHECK(it != entries_.end());
+    *entry = it->second;
+  }
+}
+
+size_t DomDistillerModel::GetNumEntries() const {
+  return entries_.size();
+}
+
+std::vector<ArticleEntry> DomDistillerModel::GetEntries() const {
+  std::vector<ArticleEntry> entries_list;
+  for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end();
+       ++it) {
+    entries_list.push_back(it->second);
+  }
+  return entries_list;
+}
+
+SyncDataList DomDistillerModel::GetAllSyncData() const {
+  SyncDataList data;
+  for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end();
+       ++it) {
+    data.push_back(CreateLocalData(it->second));
+  }
+  return data;
+}
+
+void DomDistillerModel::CalculateChangesForMerge(
+    const SyncDataList& data,
+    SyncChangeList* changes_to_apply,
+    SyncChangeList* changes_missing) {
+  typedef base::hash_set<std::string> StringSet;
+  StringSet entries_to_change;
+  for (SyncDataList::const_iterator it = data.begin(); it != data.end(); ++it) {
+    std::string entry_id = GetEntryIdFromSyncData(*it);
+    std::pair<StringSet::iterator, bool> insert_result =
+        entries_to_change.insert(entry_id);
+
+    DCHECK(insert_result.second);
+
+    SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD;
+    if (GetEntryById(entry_id, NULL)) {
+      change_type = SyncChange::ACTION_UPDATE;
+    }
+    changes_to_apply->push_back(SyncChange(FROM_HERE, change_type, *it));
+  }
+
+  for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end();
+       ++it) {
+    if (entries_to_change.find(it->second.entry_id()) ==
+        entries_to_change.end()) {
+      changes_missing->push_back(SyncChange(
+          FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(it->second)));
+    }
+  }
+}
+
+DomDistillerModel::ChangeResult DomDistillerModel::ApplyChangesToModel(
+    const SyncChangeList& changes,
+    SyncChangeList* changes_applied,
+    SyncChangeList* changes_missing) {
+  DCHECK(changes_applied);
+  DCHECK(changes_missing);
+
+  ChangeResult result = SUCCESS;
+
+  for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end();
+       ++it) {
+    result = ApplyChangeToModel(*it, changes_applied, changes_missing);
+    if (result != SUCCESS) {
+      break;
+    }
+  }
+  return result;
+}
+
+void DomDistillerModel::AddEntry(const ArticleEntry& entry) {
+  const std::string& entry_id = entry.entry_id();
+  KeyType key = next_key_++;
+  DCHECK(!GetKeyById(entry_id, NULL));
+  entries_.insert(std::make_pair(key, entry));
+  entry_id_to_key_map_.insert(std::make_pair(entry_id, key));
+  for (int i = 0; i < entry.pages_size(); ++i) {
+    url_to_key_map_.insert(std::make_pair(entry.pages(i).url(), key));
+  }
+}
+
+void DomDistillerModel::RemoveEntry(const ArticleEntry& entry) {
+  const std::string& entry_id = entry.entry_id();
+  KeyType key = 0;
+  bool success = GetKeyById(entry_id, &key);
+  DCHECK(success);
+
+  entries_.erase(key);
+  entry_id_to_key_map_.erase(entry_id);
+  for (int i = 0; i < entry.pages_size(); ++i) {
+    url_to_key_map_.erase(entry.pages(i).url());
+  }
+}
+
+DomDistillerModel::ChangeResult DomDistillerModel::ApplyChangeToModel(
+    const SyncChange& change,
+    SyncChangeList* changes_applied,
+    SyncChangeList* changes_missing) {
+  DCHECK(change.IsValid());
+  DCHECK(changes_applied);
+  DCHECK(changes_missing);
+
+  const std::string& entry_id = GetEntryIdFromSyncData(change.sync_data());
+
+  if (change.change_type() == SyncChange::ACTION_DELETE) {
+    // TODO(cjhopman): Support delete.
+    NOTIMPLEMENTED();
+    return DELETE_NOT_SUPPORTED;
+  }
+
+  ArticleEntry entry = GetEntryFromChange(change);
+  ArticleEntry current_entry;
+  if (!GetEntryById(entry_id, &current_entry)) {
+    AddEntry(entry);
+    changes_applied->push_back(SyncChange(
+        change.location(), SyncChange::ACTION_ADD, change.sync_data()));
+  } else {
+    if (!AreEntriesEqual(current_entry, entry)) {
+      // Currently, conflicts are simply resolved by accepting the last one to
+      // arrive.
+      RemoveEntry(current_entry);
+      AddEntry(entry);
+      changes_applied->push_back(SyncChange(
+          change.location(), SyncChange::ACTION_UPDATE, change.sync_data()));
+    }
+  }
+  return SUCCESS;
+}
+
+}  // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_model.h b/components/dom_distiller/core/dom_distiller_model.h
new file mode 100644
index 0000000..1bc2ec2
--- /dev/null
+++ b/components/dom_distiller/core/dom_distiller_model.h
@@ -0,0 +1,94 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_
+#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_
+
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/id_map.h"
+#include "components/dom_distiller/core/article_entry.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_change_processor.h" // syncer::SyncChangeList
+#include "sync/api/sync_data.h"
+#include "url/gurl.h"
+
+namespace dom_distiller {
+
+// This stores the in-memory model of the DOM distiller list. Entries can be
+// looked up by URL or by entry_id.
+// The model assumes that an URL corresponds to at most a single entry. If this
+// assumption is broken, lookup by URL may return unexpected results.
+class DomDistillerModel {
+ public:
+  enum ChangeResult {
+    SUCCESS = 0,
+    DELETE_NOT_SUPPORTED,
+  };
+
+  DomDistillerModel();
+  explicit DomDistillerModel(const std::vector<ArticleEntry>& initial_data);
+
+  ~DomDistillerModel();
+
+  // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry
+  // was found. On success, if |entry| is not null, it will contain the entry.
+  bool GetEntryById(const std::string& entry_id, ArticleEntry* entry) const;
+  bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) const;
+
+  std::vector<ArticleEntry> GetEntries() const;
+  size_t GetNumEntries() const;
+
+  syncer::SyncDataList GetAllSyncData() const;
+
+  // Convert a SyncDataList to a SyncChangeList of add or update changes based
+  // on the state of the model. Also calculate the entries missing from the
+  // SyncDataList.
+  void CalculateChangesForMerge(const syncer::SyncDataList& data,
+                                syncer::SyncChangeList* changes_to_apply,
+                                syncer::SyncChangeList* changes_missing);
+
+  // Applies the change list to the model, appending the actual changes made to
+  // the model to |changes_applied|. If conflict resolution does not apply the
+  // requested change, then adds the "diff" between what was requested and what
+  // was actually applied to |changes_missing|.
+  // Note: Currently conflicts are resolved by just applying the requested
+  // change. This means nothing will be added to |changes_missing|.
+  ChangeResult ApplyChangesToModel(const syncer::SyncChangeList& change_list,
+                                   syncer::SyncChangeList* changes_applied,
+                                   syncer::SyncChangeList* changes_missing);
+
+ private:
+  typedef int32 KeyType;
+  typedef base::hash_map<KeyType, ArticleEntry> EntryMap;
+  typedef base::hash_map<std::string, KeyType> StringToKeyMap;
+
+  void AddEntry(const ArticleEntry& entry);
+  void RemoveEntry(const ArticleEntry& entry);
+
+  // Lookup an entry's key by ID or URL. Returns whether a corresponding key was
+  // found. On success, if |key| is not null, it will contain the entry.
+  bool GetKeyById(const std::string& entry_id, KeyType* key) const;
+  bool GetKeyByUrl(const GURL& url, KeyType* key) const;
+
+  // If |entry| is not null, assigns the entry for |key| to it. |key| must map
+  // to an entry in |entries_|.
+  void GetEntryByKey(KeyType key, ArticleEntry* entry) const;
+
+  ChangeResult ApplyChangeToModel(const syncer::SyncChange& change,
+                                  syncer::SyncChangeList* changes_applied,
+                                  syncer::SyncChangeList* changes_missing);
+
+  KeyType next_key_;
+  EntryMap entries_;
+  StringToKeyMap url_to_key_map_;
+  StringToKeyMap entry_id_to_key_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(DomDistillerModel);
+};
+
+}  // namespace dom_distiller
+
+#endif
diff --git a/components/dom_distiller/core/dom_distiller_model_unittest.cc b/components/dom_distiller/core/dom_distiller_model_unittest.cc
new file mode 100644
index 0000000..0220439
--- /dev/null
+++ b/components/dom_distiller/core/dom_distiller_model_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dom_distiller/core/dom_distiller_model.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace dom_distiller {
+
+TEST(DomDistillerModelTest, TestGetByEntryId) {
+  ArticleEntry entry1;
+  entry1.set_entry_id("id1");
+  entry1.set_title("title1");
+  ArticleEntry entry2;
+  entry2.set_entry_id("id2");
+  entry2.set_title("title1");
+
+  std::vector<ArticleEntry> initial_model;
+  initial_model.push_back(entry1);
+  initial_model.push_back(entry2);
+
+  DomDistillerModel model(initial_model);
+
+  ArticleEntry found_entry;
+  EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry1, found_entry));
+
+  EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry2, found_entry));
+
+  EXPECT_FALSE(model.GetEntryById("some_other_id", NULL));
+}
+
+TEST(DomDistillerModelTest, TestGetByUrl) {
+  ArticleEntry entry1;
+  entry1.set_entry_id("id1");
+  entry1.set_title("title1");
+  ArticleEntryPage* page1 = entry1.add_pages();
+  page1->set_url("http://example.com/1");
+  ArticleEntryPage* page2 = entry1.add_pages();
+  page2->set_url("http://example.com/2");
+
+  ArticleEntry entry2;
+  entry2.set_entry_id("id2");
+  entry2.set_title("title1");
+  ArticleEntryPage* page3 = entry2.add_pages();
+  page3->set_url("http://example.com/a1");
+
+  std::vector<ArticleEntry> initial_model;
+  initial_model.push_back(entry1);
+  initial_model.push_back(entry2);
+
+  DomDistillerModel model(initial_model);
+
+  ArticleEntry found_entry;
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page1->url()), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry1, found_entry));
+
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page2->url()), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry1, found_entry));
+
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page3->url()), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry2, found_entry));
+
+  EXPECT_FALSE(model.GetEntryByUrl(GURL("http://example.com/foo"), NULL));
+}
+
+// This test ensures that the model handles the case where an URL maps to
+// multiple entries. In that case, the model is allowed to have an inconsistent
+// url-to-entry mapping, but it should not fail in other ways (i.e. id-to-entry
+// should be correct, shouldn't crash).
+TEST(DomDistillerModelTest, TestUrlToMultipleEntries) {
+  ArticleEntry entry1;
+  entry1.set_entry_id("id1");
+  entry1.set_title("title1");
+  ArticleEntryPage* page1 = entry1.add_pages();
+  page1->set_url("http://example.com/1");
+  ArticleEntryPage* page2 = entry1.add_pages();
+  page2->set_url("http://example.com/2");
+
+  ArticleEntry entry2;
+  entry2.set_entry_id("id2");
+  entry2.set_title("title1");
+  ArticleEntryPage* page3 = entry2.add_pages();
+  page3->set_url("http://example.com/1");
+
+  std::vector<ArticleEntry> initial_model;
+  initial_model.push_back(entry1);
+  initial_model.push_back(entry2);
+
+  DomDistillerModel model(initial_model);
+
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page1->url()), NULL));
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page2->url()), NULL));
+  EXPECT_TRUE(model.GetEntryByUrl(GURL(page3->url()), NULL));
+
+  ArticleEntry found_entry;
+  EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry1, found_entry));
+
+  EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry2, found_entry));
+
+  syncer::SyncChangeList changes_to_apply;
+  syncer::SyncChangeList changes_applied;
+  syncer::SyncChangeList changes_missing;
+
+  entry2.mutable_pages(0)->set_url("http://example.com/foo1");
+  changes_to_apply.push_back(syncer::SyncChange(
+      FROM_HERE, syncer::SyncChange::ACTION_UPDATE, CreateLocalData(entry2)));
+  model.ApplyChangesToModel(
+      changes_to_apply, &changes_applied, &changes_missing);
+
+  EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry1, found_entry));
+
+  EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry));
+  ASSERT_TRUE(IsEntryValid(found_entry));
+  EXPECT_TRUE(AreEntriesEqual(entry2, found_entry));
+}
+
+}  // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc
index f5a7a70..8be2cb6 100644
--- a/components/dom_distiller/core/dom_distiller_store.cc
+++ b/components/dom_distiller/core/dom_distiller_store.cc
@@ -23,24 +23,6 @@
 
 namespace dom_distiller {
 
-namespace {
-
-std::string GetEntryIdFromSyncData(const SyncData& data) {
-  const EntitySpecifics& entity = data.GetSpecifics();
-  DCHECK(entity.has_article());
-  const ArticleSpecifics& specifics = entity.article();
-  DCHECK(specifics.has_entry_id());
-  return specifics.entry_id();
-}
-
-SyncData CreateLocalData(const ArticleEntry& entry) {
-  EntitySpecifics specifics = SpecificsFromEntry(entry);
-  const std::string& entry_id = entry.entry_id();
-  return SyncData::CreateLocalData(entry_id, entry_id, specifics);
-}
-
-}  // namespace
-
 DomDistillerStore::DomDistillerStore(
     scoped_ptr<DomDistillerDatabaseInterface> database,
     const base::FilePath& database_dir)
@@ -54,11 +36,11 @@
 
 DomDistillerStore::DomDistillerStore(
     scoped_ptr<DomDistillerDatabaseInterface> database,
-    const EntryMap& initial_model,
+    const std::vector<ArticleEntry>& initial_data,
     const base::FilePath& database_dir)
     : database_(database.Pass()),
       database_loaded_(false),
-      model_(initial_model),
+      model_(initial_data),
       weak_ptr_factory_(this) {
   database_->Init(database_dir,
                   base::Bind(&DomDistillerStore::OnDatabaseInit,
@@ -72,11 +54,23 @@
   return this;
 }
 
+bool DomDistillerStore::GetEntryById(const std::string& entry_id,
+                                     ArticleEntry* entry) {
+  return model_.GetEntryById(entry_id, entry);
+}
+
+bool DomDistillerStore::GetEntryByUrl(const GURL& url,
+                                     ArticleEntry* entry) {
+  return model_.GetEntryByUrl(url, entry);
+}
+
+
 bool DomDistillerStore::AddEntry(const ArticleEntry& entry) {
   if (!database_loaded_) {
     return false;
   }
-  if (model_.find(entry.entry_id()) != model_.end()) {
+
+  if (model_.GetEntryById(entry.entry_id(), NULL)) {
     return false;
   }
 
@@ -86,7 +80,11 @@
 
   SyncChangeList changes_applied;
   SyncChangeList changes_missing;
-  ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing);
+
+  if (!ApplyChangesToModel(
+           changes_to_apply, &changes_applied, &changes_missing)) {
+    return false;
+  }
 
   DCHECK_EQ(size_t(0), changes_missing.size());
   DCHECK_EQ(size_t(1), changes_applied.size());
@@ -98,11 +96,7 @@
 }
 
 std::vector<ArticleEntry> DomDistillerStore::GetEntries() const {
-  std::vector<ArticleEntry> entries;
-  for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) {
-    entries.push_back(it->second);
-  }
-  return entries;
+  return model_.GetEntries();
 }
 
 // syncer::SyncableService implementation.
@@ -133,11 +127,7 @@
 }
 
 SyncDataList DomDistillerStore::GetAllSyncData(ModelType type) const {
-  SyncDataList data;
-  for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) {
-    data.push_back(CreateLocalData(it->second));
-  }
-  return data;
+  return model_.GetAllSyncData();
 }
 
 SyncError DomDistillerStore::ProcessSyncChanges(
@@ -146,17 +136,34 @@
   DCHECK(database_loaded_);
   SyncChangeList database_changes;
   SyncChangeList sync_changes;
-  SyncError error =
-      ApplyChangesToModel(change_list, &database_changes, &sync_changes);
+  if (!ApplyChangesToModel(change_list, &database_changes, &sync_changes)) {
+    return SyncError(FROM_HERE,
+                     SyncError::DATATYPE_ERROR,
+                     "Applying changes to the DOM distiller model failed",
+                     syncer::ARTICLES);
+  }
   ApplyChangesToDatabase(database_changes);
   DCHECK_EQ(size_t(0), sync_changes.size());
-  return error;
+  return SyncError();
 }
 
-ArticleEntry DomDistillerStore::GetEntryFromChange(const SyncChange& change) {
-  DCHECK(change.IsValid());
-  DCHECK(change.sync_data().IsValid());
-  return EntryFromSpecifics(change.sync_data().GetSpecifics());
+bool DomDistillerStore::ApplyChangesToModel(
+    const SyncChangeList& changes,
+    SyncChangeList* changes_applied,
+    SyncChangeList* changes_missing) {
+  DomDistillerModel::ChangeResult change_result =
+      model_.ApplyChangesToModel(changes, changes_applied, changes_missing);
+  if (change_result == DomDistillerModel::SUCCESS) {
+    return true;
+  }
+
+  LOG(WARNING) << "Applying changes to DOM distiller model failed with error "
+               << change_result;
+
+  database_.reset();
+  database_loaded_ = false;
+  StopSyncing(syncer::ARTICLES);
+  return false;
 }
 
 void DomDistillerStore::OnDatabaseInit(bool success) {
@@ -238,35 +245,6 @@
   return true;
 }
 
-void DomDistillerStore::CalculateChangesForMerge(
-    const SyncDataList& data,
-    SyncChangeList* changes_to_apply,
-    SyncChangeList* changes_missing) {
-  typedef base::hash_set<std::string> StringSet;
-  StringSet entries_to_change;
-  for (SyncDataList::const_iterator it = data.begin(); it != data.end(); ++it) {
-    std::string entry_id = GetEntryIdFromSyncData(*it);
-    std::pair<StringSet::iterator, bool> insert_result =
-        entries_to_change.insert(entry_id);
-
-    DCHECK(insert_result.second);
-
-    SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD;
-    EntryMap::const_iterator current = model_.find(entry_id);
-    if (current != model_.end()) {
-      change_type = SyncChange::ACTION_UPDATE;
-    }
-    changes_to_apply->push_back(SyncChange(FROM_HERE, change_type, *it));
-  }
-
-  for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) {
-    if (entries_to_change.find(it->first) == entries_to_change.end()) {
-      changes_missing->push_back(SyncChange(
-          FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(it->second)));
-    }
-  }
-}
-
 SyncMergeResult DomDistillerStore::MergeDataWithModel(
     const SyncDataList& data,
     SyncChangeList* changes_applied,
@@ -275,12 +253,18 @@
   DCHECK(changes_missing);
 
   SyncMergeResult result(syncer::ARTICLES);
-  result.set_num_items_before_association(model_.size());
+  result.set_num_items_before_association(model_.GetNumEntries());
 
   SyncChangeList changes_to_apply;
-  CalculateChangesForMerge(data, &changes_to_apply, changes_missing);
-  SyncError error =
-      ApplyChangesToModel(changes_to_apply, changes_applied, changes_missing);
+  model_.CalculateChangesForMerge(data, &changes_to_apply, changes_missing);
+  SyncError error;
+  if (!ApplyChangesToModel(
+           changes_to_apply, changes_applied, changes_missing)) {
+    error = SyncError(FROM_HERE,
+                      SyncError::DATATYPE_ERROR,
+                      "Applying changes to the DOM distiller model failed",
+                      syncer::ARTICLES);
+  }
 
   int num_added = 0;
   int num_modified = 0;
@@ -304,57 +288,10 @@
   result.set_num_items_deleted(0);
 
   result.set_pre_association_version(0);
-  result.set_num_items_after_association(model_.size());
+  result.set_num_items_after_association(model_.GetNumEntries());
   result.set_error(error);
 
   return result;
 }
 
-SyncError DomDistillerStore::ApplyChangesToModel(
-    const SyncChangeList& changes,
-    SyncChangeList* changes_applied,
-    SyncChangeList* changes_missing) {
-  DCHECK(changes_applied);
-  DCHECK(changes_missing);
-
-  for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end();
-       ++it) {
-    ApplyChangeToModel(*it, changes_applied, changes_missing);
-  }
-  return SyncError();
-}
-
-void DomDistillerStore::ApplyChangeToModel(const SyncChange& change,
-                                           SyncChangeList* changes_applied,
-                                           SyncChangeList* changes_missing) {
-  DCHECK(changes_applied);
-  DCHECK(changes_missing);
-  DCHECK(change.IsValid());
-
-  const std::string& entry_id = GetEntryIdFromSyncData(change.sync_data());
-  EntryMap::iterator entry_it = model_.find(entry_id);
-
-  if (change.change_type() == SyncChange::ACTION_DELETE) {
-    // TODO(cjhopman): Support delete.
-    NOTIMPLEMENTED();
-    StopSyncing(syncer::ARTICLES);
-    return;
-  }
-
-  ArticleEntry entry = GetEntryFromChange(change);
-  if (entry_it == model_.end()) {
-    model_.insert(std::make_pair(entry.entry_id(), entry));
-    changes_applied->push_back(SyncChange(
-        change.location(), SyncChange::ACTION_ADD, change.sync_data()));
-  } else {
-    if (!AreEntriesEqual(entry_it->second, entry)) {
-      // Currently, conflicts are simply resolved by accepting the last one to
-      // arrive.
-      entry_it->second = entry;
-      changes_applied->push_back(SyncChange(
-          change.location(), SyncChange::ACTION_UPDATE, change.sync_data()));
-    }
-  }
-}
-
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h
index fdc1851..18641b7 100644
--- a/components/dom_distiller/core/dom_distiller_store.h
+++ b/components/dom_distiller/core/dom_distiller_store.h
@@ -11,12 +11,14 @@
 #include "base/memory/weak_ptr.h"
 #include "components/dom_distiller/core/article_entry.h"
 #include "components/dom_distiller/core/dom_distiller_database.h"
+#include "components/dom_distiller/core/dom_distiller_model.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_data.h"
 #include "sync/api/sync_error.h"
 #include "sync/api/sync_error_factory.h"
 #include "sync/api/sync_merge_result.h"
 #include "sync/api/syncable_service.h"
+#include "url/gurl.h"
 
 namespace base {
 class FilePath;
@@ -34,6 +36,12 @@
 
   virtual bool AddEntry(const ArticleEntry& entry) = 0;
 
+  // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry
+  // was found. On success, if |entry| is not null, it will contain the entry.
+  virtual bool GetEntryById(const std::string& entry_id,
+                            ArticleEntry* entry) = 0;
+  virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) = 0;
+
   // Gets a copy of all the current entries.
   virtual std::vector<ArticleEntry> GetEntries() const = 0;
 
@@ -59,8 +67,6 @@
 class DomDistillerStore : public syncer::SyncableService,
                           DomDistillerStoreInterface {
  public:
-  typedef base::hash_map<std::string, ArticleEntry> EntryMap;
-
   // Creates storage using the given database for local storage. Initializes the
   // database with |database_dir|.
   DomDistillerStore(scoped_ptr<DomDistillerDatabaseInterface> database,
@@ -70,7 +76,7 @@
   // database with |database_dir|.  Also initializes the internal model to
   // |initial_model|.
   DomDistillerStore(scoped_ptr<DomDistillerDatabaseInterface> database,
-                    const EntryMap& initial_model,
+                    const std::vector<ArticleEntry>& initial_data,
                     const base::FilePath& database_dir);
 
   virtual ~DomDistillerStore();
@@ -78,6 +84,9 @@
   // DomDistillerStoreInterface implementation.
   virtual syncer::SyncableService* GetSyncableService() OVERRIDE;
   virtual bool AddEntry(const ArticleEntry& entry) OVERRIDE;
+  virtual bool GetEntryById(const std::string& entry_id,
+                            ArticleEntry* entry) OVERRIDE;
+  virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) OVERRIDE;
   virtual std::vector<ArticleEntry> GetEntries() const OVERRIDE;
 
   // syncer::SyncableService implementation.
@@ -92,9 +101,6 @@
   virtual syncer::SyncError ProcessSyncChanges(
       const tracked_objects::Location& from_here,
       const syncer::SyncChangeList& change_list) OVERRIDE;
-
-  static ArticleEntry GetEntryFromChange(const syncer::SyncChange& change);
-
  private:
   void OnDatabaseInit(bool success);
   void OnDatabaseLoad(bool success, scoped_ptr<EntryVector> entries);
@@ -116,24 +122,18 @@
                           const syncer::SyncChangeList& change_list);
   bool ApplyChangesToDatabase(const syncer::SyncChangeList& change_list);
 
-  // Applies the change list to the in-memory model, appending the actual
-  // changes made to the model to changes_applied. If conflict resolution does
-  // not apply the requested change, then adds the "diff" to changes_missing.
-  syncer::SyncError ApplyChangesToModel(
-      const syncer::SyncChangeList& change_list,
-      syncer::SyncChangeList* changes_applied,
-      syncer::SyncChangeList* changes_missing);
-
-  void ApplyChangeToModel(const syncer::SyncChange& change,
-                          syncer::SyncChangeList* changes_applied,
-                          syncer::SyncChangeList* changes_missing);
+  // Applies the changes to |model_|. If the model returns an error, disables
+  // syncing and database changes and returns false.
+  bool ApplyChangesToModel(const syncer::SyncChangeList& change_list,
+                           syncer::SyncChangeList* changes_applied,
+                           syncer::SyncChangeList* changes_missing);
 
   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
   scoped_ptr<syncer::SyncErrorFactory> error_factory_;
   scoped_ptr<DomDistillerDatabaseInterface> database_;
   bool database_loaded_;
 
-  EntryMap model_;
+  DomDistillerModel model_;
 
   base::WeakPtrFactory<DomDistillerStore> weak_ptr_factory_;
 
diff --git a/components/dom_distiller/core/dom_distiller_store_unittest.cc b/components/dom_distiller/core/dom_distiller_store_unittest.cc
index 333d72d..9e4cf35 100644
--- a/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -34,12 +34,21 @@
 
 const ModelType kDomDistillerModelType = syncer::ARTICLES;
 
-typedef DomDistillerStore::EntryMap EntryMap;
+typedef base::hash_map<std::string, ArticleEntry> EntryMap;
 
 void AddEntry(const ArticleEntry& e, EntryMap* map) {
   (*map)[e.entry_id()] = e;
 }
 
+std::vector<ArticleEntry> EntryMapToList(const EntryMap& entries) {
+  std::vector<ArticleEntry> entry_list;
+  for (EntryMap::const_iterator it = entries.begin(); it != entries.end();
+       ++it) {
+    entry_list.push_back(it->second);
+  }
+  return entry_list;
+}
+
 class FakeDB : public DomDistillerDatabaseInterface {
   typedef base::Callback<void(bool)> Callback;
 
@@ -134,7 +143,7 @@
     for (SyncChangeList::const_iterator it = changes.begin();
          it != changes.end();
          ++it) {
-      AddEntry(DomDistillerStore::GetEntryFromChange(*it), model_);
+      AddEntry(GetEntryFromChange(*it), model_);
     }
     return SyncError();
   }
@@ -203,7 +212,7 @@
     fake_db_ = new FakeDB(&db_model_);
     store_.reset(new DomDistillerStore(
         scoped_ptr<DomDistillerDatabaseInterface>(fake_db_),
-        store_model_,
+        EntryMapToList(store_model_),
         db_dir_));
   }
 
@@ -448,7 +457,7 @@
   FakeDB* other_fake_db = new FakeDB(&other_db_model);
   scoped_ptr<DomDistillerStore> owned_other_store(new DomDistillerStore(
       scoped_ptr<DomDistillerDatabaseInterface>(other_fake_db),
-      EntryMap(),
+      std::vector<ArticleEntry>(),
       base::FilePath(FILE_PATH_LITERAL("/fake/other/path"))));
   DomDistillerStore* other_store = owned_other_store.get();
   other_fake_db->InitCallback(true);
diff --git a/components/encryptor.target.darwin-arm.mk b/components/encryptor.target.darwin-arm.mk
index 4d69953..1aa2b16 100644
--- a/components/encryptor.target.darwin-arm.mk
+++ b/components/encryptor.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/encryptor.target.darwin-mips.mk b/components/encryptor.target.darwin-mips.mk
index 41ffc22..50e47fa 100644
--- a/components/encryptor.target.darwin-mips.mk
+++ b/components/encryptor.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/encryptor.target.darwin-x86.mk b/components/encryptor.target.darwin-x86.mk
index 487157b..97f436b 100644
--- a/components/encryptor.target.darwin-x86.mk
+++ b/components/encryptor.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/encryptor.target.linux-arm.mk b/components/encryptor.target.linux-arm.mk
index 4d69953..1aa2b16 100644
--- a/components/encryptor.target.linux-arm.mk
+++ b/components/encryptor.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/encryptor.target.linux-mips.mk b/components/encryptor.target.linux-mips.mk
index 41ffc22..50e47fa 100644
--- a/components/encryptor.target.linux-mips.mk
+++ b/components/encryptor.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/encryptor.target.linux-x86.mk b/components/encryptor.target.linux-x86.mk
index 487157b..97f436b 100644
--- a/components/encryptor.target.linux-x86.mk
+++ b/components/encryptor.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/json_schema/json_schema_validator.cc b/components/json_schema/json_schema_validator.cc
index 3816a76..3cc9e2b 100644
--- a/components/json_schema/json_schema_validator.cc
+++ b/components/json_schema/json_schema_validator.cc
@@ -53,6 +53,18 @@
   return entry.key < key;
 }
 
+// If |value| is a dictionary, returns the "name" attribute of |value| or NULL
+// if |value| does not contain a "name" attribute. Otherwise, returns |value|.
+const base::Value* ExtractNameFromDictionary(const base::Value* value) {
+  const base::DictionaryValue* value_dict = NULL;
+  const base::Value* name_value = NULL;
+  if (value->GetAsDictionary(&value_dict)) {
+    value_dict->Get("name", &name_value);
+    return name_value;
+  }
+  return value;
+}
+
 bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) {
   // This array must be sorted, so that std::lower_bound can perform a
   // binary search.
@@ -195,6 +207,13 @@
       for (size_t i = 0; i < list_value->GetSize(); ++i) {
         const base::Value* value = NULL;
         list_value->Get(i, &value);
+        // Sometimes the enum declaration is a dictionary with the enum value
+        // under "name".
+        value = ExtractNameFromDictionary(value);
+        if (!value) {
+          *error = "Invalid value in enum attribute";
+          return false;
+        }
         switch (value->GetType()) {
           case base::Value::TYPE_NULL:
           case base::Value::TYPE_BOOLEAN:
@@ -479,6 +498,12 @@
   for (size_t i = 0; i < choices->GetSize(); ++i) {
     const base::Value* choice = NULL;
     CHECK(choices->Get(i, &choice));
+    // Sometimes the enum declaration is a dictionary with the enum value under
+    // "name".
+    choice = ExtractNameFromDictionary(choice);
+    if (!choice) {
+      NOTREACHED();
+    }
     switch (choice->GetType()) {
       case base::Value::TYPE_NULL:
       case base::Value::TYPE_BOOLEAN:
diff --git a/components/json_schema/json_schema_validator_unittest.cc b/components/json_schema/json_schema_validator_unittest.cc
index 4844ed1..6372032 100644
--- a/components/json_schema/json_schema_validator_unittest.cc
+++ b/components/json_schema/json_schema_validator_unittest.cc
@@ -77,10 +77,16 @@
   EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
       "{"
       "  \"type\": \"string\","
-      "  \"enum\": [ {} ],"  // "enum" must contain simple values.
+      "  \"enum\": [ {} ]"  // "enum" dict values must contain "name".
       "}", &error));
   EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
       "{"
+      "  \"type\": \"string\","
+      "  \"enum\": [ { \"name\": {} } ]"  // "enum" name must be a simple value.
+      "}",
+      &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{"
       "  \"type\": \"array\","
       "  \"items\": [ 123 ],"  // "items" must contain a schema or schemas.
       "}", &error));
@@ -106,7 +112,7 @@
       "    },"
       "    \"enum-property\": {"
       "      \"type\": \"integer\","
-      "      \"enum\": [0, 1, 10, 100]"
+      "      \"enum\": [0, 1, {\"name\": 10}, 100]"
       "    },"
       "    \"items-property\": {"
       "      \"type\": \"array\","
diff --git a/components/nacl/common/nacl_browser_delegate.h b/components/nacl/common/nacl_browser_delegate.h
index dc0d8c7..ba577de 100644
--- a/components/nacl/common/nacl_browser_delegate.h
+++ b/components/nacl/common/nacl_browser_delegate.h
@@ -74,6 +74,12 @@
   // TODO(jvoung): Add the progress callback as well.
   virtual void TryInstallPnacl(
       const base::Callback<void(bool)>& installed) = 0;
+
+  // Set match patterns which will be checked before enabling debug stub.
+  virtual void SetDebugPatterns(std::string debug_patterns) = 0;
+
+  // Returns whether NaCl application with this manifest URL should be debugged.
+  virtual bool URLMatchesDebugPatterns(const GURL& manifest_url) = 0;
 };
 
 #endif  // COMPONENTS_NACL_COMMON_NACL_BROWSER_DELEGATE_H_
diff --git a/components/nacl/loader/nacl_ipc_adapter.cc b/components/nacl/loader/nacl_ipc_adapter.cc
index 3399bbb..8134d3c 100644
--- a/components/nacl/loader/nacl_ipc_adapter.cc
+++ b/components/nacl/loader/nacl_ipc_adapter.cc
@@ -515,8 +515,7 @@
   // We actually discard the flags and only copy the ones we care about. This
   // is just because message doesn't have a constructor that takes raw flags.
   scoped_ptr<IPC::Message> msg(
-      new IPC::Message(header->routing, header->type,
-                       IPC::Message::PRIORITY_NORMAL));
+      new IPC::Message(header->routing, header->type));
   if (header->flags & IPC::Message::SYNC_BIT)
     msg->set_sync();
   if (header->flags & IPC::Message::REPLY_BIT)
diff --git a/components/nacl/loader/nacl_ipc_adapter_unittest.cc b/components/nacl/loader/nacl_ipc_adapter_unittest.cc
index 80fd408..21e5f7f 100644
--- a/components/nacl/loader/nacl_ipc_adapter_unittest.cc
+++ b/components/nacl/loader/nacl_ipc_adapter_unittest.cc
@@ -75,7 +75,7 @@
 TEST_F(NaClIPCAdapterTest, SimpleReceiveRewriting) {
   int routing_id = 0x89898989;
   uint32 type = 0x55555555;
-  IPC::Message input(routing_id, type, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message input(routing_id, type);
   uint32 flags = input.flags();
 
   int value = 0x12345678;
@@ -175,14 +175,14 @@
 TEST_F(NaClIPCAdapterTest, PartialReceive) {
   int routing_id_1 = 0x89898989;
   uint32 type_1 = 0x55555555;
-  IPC::Message input_1(routing_id_1, type_1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message input_1(routing_id_1, type_1);
   int value_1 = 0x12121212;
   input_1.WriteInt(value_1);
   adapter_->OnMessageReceived(input_1);
 
   int routing_id_2 = 0x90909090;
   uint32 type_2 = 0x66666666;
-  IPC::Message input_2(routing_id_2, type_2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message input_2(routing_id_2, type_2);
   int value_2 = 0x23232323;
   input_2.WriteInt(value_2);
   adapter_->OnMessageReceived(input_2);
diff --git a/components/nacl/zygote/nacl_fork_delegate_linux.cc b/components/nacl/zygote/nacl_fork_delegate_linux.cc
index 7bd2e9f..3dbe6e6 100644
--- a/components/nacl/zygote/nacl_fork_delegate_linux.cc
+++ b/components/nacl/zygote/nacl_fork_delegate_linux.cc
@@ -257,7 +257,7 @@
   *uma_name = "NaCl.Client.Helper.StateOnFork";
   *uma_sample = status_;
   *uma_boundary_value = kNaClHelperStatusBoundary;
-  return status_ == kNaClHelperSuccess;
+  return true;
 }
 
 pid_t NaClForkDelegate::Fork(const std::vector<int>& fds) {
@@ -265,6 +265,11 @@
 
   DCHECK(fds.size() == kNumPassedFDs);
 
+  if (status_ != kNaClHelperSuccess) {
+    LOG(ERROR) << "Cannot launch NaCl process: nacl_helper failed to start";
+    return -1;
+  }
+
   // First, send a remote fork request.
   Pickle write_pickle;
   write_pickle.WriteInt(kNaClForkRequest);
diff --git a/components/nacl_common.gyp b/components/nacl_common.gyp
index 1364ef2..cedf675 100644
--- a/components/nacl_common.gyp
+++ b/components/nacl_common.gyp
@@ -53,6 +53,9 @@
         {
           'target_name': 'nacl_common_win64',
           'type': 'static_library',
+          'defines': [
+            'COMPILE_CONTENT_STATICALLY',
+          ],
           'sources': [
             'nacl/common/nacl_cmd_line.cc',
             'nacl/common/nacl_cmd_line.h',
diff --git a/components/navigation_interception.target.darwin-arm.mk b/components/navigation_interception.target.darwin-arm.mk
index c65d841..176bdcd 100644
--- a/components/navigation_interception.target.darwin-arm.mk
+++ b/components/navigation_interception.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception.target.darwin-mips.mk b/components/navigation_interception.target.darwin-mips.mk
index fc331f1..cc20f6f 100644
--- a/components/navigation_interception.target.darwin-mips.mk
+++ b/components/navigation_interception.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception.target.darwin-x86.mk b/components/navigation_interception.target.darwin-x86.mk
index f8e6ff3..d7def75 100644
--- a/components/navigation_interception.target.darwin-x86.mk
+++ b/components/navigation_interception.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception.target.linux-arm.mk b/components/navigation_interception.target.linux-arm.mk
index c65d841..176bdcd 100644
--- a/components/navigation_interception.target.linux-arm.mk
+++ b/components/navigation_interception.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception.target.linux-mips.mk b/components/navigation_interception.target.linux-mips.mk
index fc331f1..cc20f6f 100644
--- a/components/navigation_interception.target.linux-mips.mk
+++ b/components/navigation_interception.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception.target.linux-x86.mk b/components/navigation_interception.target.linux-x86.mk
index f8e6ff3..d7def75 100644
--- a/components/navigation_interception.target.linux-x86.mk
+++ b/components/navigation_interception.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.darwin-arm.mk b/components/navigation_interception_jni_headers.target.darwin-arm.mk
index 1a4672e..c82c002 100644
--- a/components/navigation_interception_jni_headers.target.darwin-arm.mk
+++ b/components/navigation_interception_jni_headers.target.darwin-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.darwin-mips.mk b/components/navigation_interception_jni_headers.target.darwin-mips.mk
index 6723897..3aa11a4 100644
--- a/components/navigation_interception_jni_headers.target.darwin-mips.mk
+++ b/components/navigation_interception_jni_headers.target.darwin-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.darwin-x86.mk b/components/navigation_interception_jni_headers.target.darwin-x86.mk
index f70d289..56f182e 100644
--- a/components/navigation_interception_jni_headers.target.darwin-x86.mk
+++ b/components/navigation_interception_jni_headers.target.darwin-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.linux-arm.mk b/components/navigation_interception_jni_headers.target.linux-arm.mk
index 1a4672e..c82c002 100644
--- a/components/navigation_interception_jni_headers.target.linux-arm.mk
+++ b/components/navigation_interception_jni_headers.target.linux-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.linux-mips.mk b/components/navigation_interception_jni_headers.target.linux-mips.mk
index 6723897..3aa11a4 100644
--- a/components/navigation_interception_jni_headers.target.linux-mips.mk
+++ b/components/navigation_interception_jni_headers.target.linux-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_interception_jni_headers.target.linux-x86.mk b/components/navigation_interception_jni_headers.target.linux-x86.mk
index f70d289..56f182e 100644
--- a/components/navigation_interception_jni_headers.target.linux-x86.mk
+++ b/components/navigation_interception_jni_headers.target.linux-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/navigation_metrics.gypi b/components/navigation_metrics.gypi
new file mode 100644
index 0000000..a8f2233
--- /dev/null
+++ b/components/navigation_metrics.gypi
@@ -0,0 +1,23 @@
+# Copyright 2013 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': 'navigation_metrics',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../url/url.gyp:url_lib',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'navigation_metrics/navigation_metrics.cc',
+        'navigation_metrics/navigation_metrics.h',
+      ],
+    },
+  ],
+}
diff --git a/components/navigation_metrics/navigation_metrics.cc b/components/navigation_metrics/navigation_metrics.cc
new file mode 100644
index 0000000..acbe25a
--- /dev/null
+++ b/components/navigation_metrics/navigation_metrics.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/navigation_metrics/navigation_metrics.h"
+
+#include "base/metrics/histogram.h"
+#include "url/gurl.h"
+
+namespace {
+
+enum Scheme {
+  SCHEME_UNKNOWN,
+  SCHEME_HTTP,
+  SCHEME_HTTPS,
+  SCHEME_FILE,
+  SCHEME_FTP,
+  SCHEME_DATA,
+  SCHEME_JAVASCRIPT,
+  SCHEME_ABOUT,
+  SCHEME_CHROME,
+  SCHEME_MAX,
+};
+
+static const char* kSchemeNames[] = {
+  "unknown",
+  "http",
+  "https",
+  "file",
+  "ftp",
+  "data",
+  "javascript",
+  "about",
+  "chrome",
+  "max",
+};
+
+COMPILE_ASSERT(arraysize(kSchemeNames) == SCHEME_MAX + 1,
+               NavigationMetricsRecorder_name_count_mismatch);
+
+}  // namespace
+
+namespace navigation_metrics {
+
+void RecordMainFrameNavigation(const GURL& url) {
+  Scheme scheme = SCHEME_UNKNOWN;
+  for (int i = 1; i < SCHEME_MAX; ++i) {
+    if (url.SchemeIs(kSchemeNames[i])) {
+      scheme = static_cast<Scheme>(i);
+      break;
+    }
+  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "Navigation.MainFrameScheme", scheme, SCHEME_MAX);
+}
+
+}  // namespace navigation_metrics
diff --git a/components/navigation_metrics/navigation_metrics.h b/components/navigation_metrics/navigation_metrics.h
new file mode 100644
index 0000000..db5eb7f
--- /dev/null
+++ b/components/navigation_metrics/navigation_metrics.h
@@ -0,0 +1,16 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NAVIGATION_METRICS_NAVIGATION_METRICS_H_
+#define COMPONENTS_NAVIGATION_METRICS_NAVIGATION_METRICS_H_
+
+class GURL;
+
+namespace navigation_metrics {
+
+void RecordMainFrameNavigation(const GURL& url);
+
+}  // namespace navigation_metrics
+
+#endif  // COMPONENTS_NAVIGATION_METRICS_NAVIGATION_METRICS_H_
diff --git a/components/policy.gypi b/components/policy.gypi
index 77fe110..32aed7e 100644
--- a/components/policy.gypi
+++ b/components/policy.gypi
@@ -20,6 +20,8 @@
       'conditions': [
         ['configuration_policy==1', {
           'sources': [
+            'policy/core/common/policy_namespace.cc',
+            'policy/core/common/policy_namespace.h',
             'policy/core/common/policy_pref_names.cc',
             'policy/core/common/policy_pref_names.h',
             'policy/core/common/policy_switches.cc',
@@ -30,14 +32,12 @@
             'policy/policy_export.h',
           ],
         }, {  # configuration_policy==0
-          # The target 'policy_component' always exists. Later it will include
-          # some stubs when configuration_policy==0. For now this stub file is
-          # compiled so that an output is produced, otherwise the shared build
-          # breaks on iOS.
-          # TODO(joaodasilva): remove this comment and the temporary stub after
-          # moving one of the real stubs. http://crbug.com/271392
+          # Some of the policy code is always enabled, so that other parts of
+          # Chrome can always interface with the PolicyService without having
+          # to #ifdef on ENABLE_CONFIGURATION_POLICY.
           'sources': [
-            'policy/stub_to_remove.cc',
+            'policy/core/common/policy_namespace.cc',
+            'policy/core/common/policy_namespace.h',
           ],
         }],
       ],
diff --git a/components/policy/core/common/policy_namespace.cc b/components/policy/core/common/policy_namespace.cc
new file mode 100644
index 0000000..0fac9ca
--- /dev/null
+++ b/components/policy/core/common/policy_namespace.cc
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_namespace.h"
+
+namespace policy {
+
+PolicyNamespace::PolicyNamespace() {}
+
+PolicyNamespace::PolicyNamespace(PolicyDomain domain,
+                                 const std::string& component_id)
+    : domain(domain),
+      component_id(component_id) {}
+
+PolicyNamespace::PolicyNamespace(const PolicyNamespace& other)
+    : domain(other.domain),
+      component_id(other.component_id) {}
+
+PolicyNamespace::~PolicyNamespace() {}
+
+PolicyNamespace& PolicyNamespace::operator=(const PolicyNamespace& other) {
+  domain = other.domain;
+  component_id = other.component_id;
+  return *this;
+}
+
+bool PolicyNamespace::operator<(const PolicyNamespace& other) const {
+  return domain < other.domain ||
+         (domain == other.domain && component_id < other.component_id);
+}
+
+bool PolicyNamespace::operator==(const PolicyNamespace& other) const {
+  return domain == other.domain && component_id == other.component_id;
+}
+
+bool PolicyNamespace::operator!=(const PolicyNamespace& other) const {
+  return !(*this == other);
+}
+
+}  // namespace policy
diff --git a/components/policy/core/common/policy_namespace.h b/components/policy/core/common/policy_namespace.h
new file mode 100644
index 0000000..4d8cf1c
--- /dev/null
+++ b/components/policy/core/common/policy_namespace.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_
+#define COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_
+
+#include <string>
+
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+// Policies are namespaced by a (PolicyDomain, ID) pair. The meaning of the ID
+// string depends on the domain; for example, if the PolicyDomain is
+// "extensions" then the ID identifies the extension that the policies control.
+enum POLICY_EXPORT PolicyDomain {
+  // The component ID for chrome policies is always the empty string.
+  POLICY_DOMAIN_CHROME,
+
+  // The extensions policy domain is a work in progress. Included here for
+  // tests.
+  POLICY_DOMAIN_EXTENSIONS,
+
+  // Must be the last entry.
+  POLICY_DOMAIN_SIZE,
+};
+
+// Groups a policy domain and a component ID in a single object representing
+// a policy namespace. Objects of this class can be used as keys in std::maps.
+struct POLICY_EXPORT PolicyNamespace {
+ public:
+  PolicyNamespace();
+  PolicyNamespace(PolicyDomain domain, const std::string& component_id);
+  PolicyNamespace(const PolicyNamespace& other);
+  ~PolicyNamespace();
+
+  PolicyNamespace& operator=(const PolicyNamespace& other);
+  bool operator<(const PolicyNamespace& other) const;
+  bool operator==(const PolicyNamespace& other) const;
+  bool operator!=(const PolicyNamespace& other) const;
+
+  PolicyDomain domain;
+  std::string component_id;
+};
+
+}  // namespace policy
+
+#endif  // COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_
diff --git a/components/policy/stub_to_remove.cc b/components/policy/stub_to_remove.cc
deleted file mode 100644
index 6e352ac..0000000
--- a/components/policy/stub_to_remove.cc
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2013 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.
-
-// TODO(joaodasilva): remove this file and update the comment on policy.gypi.
-// http://crbug.com/271392
diff --git a/components/test/data/json_schema/enum_schema.json b/components/test/data/json_schema/enum_schema.json
index ae0c12a..efb68de 100644
--- a/components/test/data/json_schema/enum_schema.json
+++ b/components/test/data/json_schema/enum_schema.json
@@ -1,3 +1,3 @@
 {
-  "enum": ["foo", 42, false]
+  "enum": ["foo", 42, {"name": false, "description": "a false value"}]
 }
diff --git a/components/tracing.target.darwin-arm.mk b/components/tracing.target.darwin-arm.mk
index 1912f50..22c1cb9 100644
--- a/components/tracing.target.darwin-arm.mk
+++ b/components/tracing.target.darwin-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing.target.darwin-mips.mk b/components/tracing.target.darwin-mips.mk
index d6bd8cc..10da891 100644
--- a/components/tracing.target.darwin-mips.mk
+++ b/components/tracing.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing.target.darwin-x86.mk b/components/tracing.target.darwin-x86.mk
index d0249e0..1d41d4b 100644
--- a/components/tracing.target.darwin-x86.mk
+++ b/components/tracing.target.darwin-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing.target.linux-arm.mk b/components/tracing.target.linux-arm.mk
index 1912f50..22c1cb9 100644
--- a/components/tracing.target.linux-arm.mk
+++ b/components/tracing.target.linux-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing.target.linux-mips.mk b/components/tracing.target.linux-mips.mk
index d6bd8cc..10da891 100644
--- a/components/tracing.target.linux-mips.mk
+++ b/components/tracing.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing.target.linux-x86.mk b/components/tracing.target.linux-x86.mk
index d0249e0..1d41d4b 100644
--- a/components/tracing.target.linux-x86.mk
+++ b/components/tracing.target.linux-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/tracing/child_trace_message_filter.cc b/components/tracing/child_trace_message_filter.cc
index 9925f3f..721c676 100644
--- a/components/tracing/child_trace_message_filter.cc
+++ b/components/tracing/child_trace_message_filter.cc
@@ -52,7 +52,8 @@
 void ChildTraceMessageFilter::OnBeginTracing(
     const std::string& category_filter_str,
     base::TimeTicks browser_time,
-    int options) {
+    int options,
+    bool tracing_startup) {
 #if defined(__native_client__)
   // NaCl and system times are offset by a bit, so subtract some time from
   // the captured timestamps. The value might be off by a bit due to messaging
@@ -61,9 +62,15 @@
       browser_time;
   TraceLog::GetInstance()->SetTimeOffset(time_offset);
 #endif
-  TraceLog::GetInstance()->SetEnabled(
-      base::debug::CategoryFilter(category_filter_str),
-      static_cast<base::debug::TraceLog::Options>(options));
+
+  // Some subprocesses handle --trace-startup by themselves to begin
+  // trace as early as possible. Don't start twice, otherwise the trace
+  // buffer can't be correctly flushed on the end of startup tracing.
+  if (!tracing_startup || !TraceLog::GetInstance()->IsEnabled()) {
+    TraceLog::GetInstance()->SetEnabled(
+        base::debug::CategoryFilter(category_filter_str),
+        static_cast<base::debug::TraceLog::Options>(options));
+  }
 }
 
 void ChildTraceMessageFilter::OnEndTracing() {
diff --git a/components/tracing/child_trace_message_filter.h b/components/tracing/child_trace_message_filter.h
index cbd300f..8fe301a 100644
--- a/components/tracing/child_trace_message_filter.h
+++ b/components/tracing/child_trace_message_filter.h
@@ -32,7 +32,8 @@
   // Message handlers.
   void OnBeginTracing(const std::string& category_filter_str,
                       base::TimeTicks browser_time,
-                      int options);
+                      int options,
+                      bool tracing_startup);
   void OnEndTracing();
   void OnEnableMonitoring(const std::string& category_filter_str,
                           base::TimeTicks browser_time,
diff --git a/components/tracing/tracing_messages.h b/components/tracing/tracing_messages.h
index 25b45bd..2b491ba 100644
--- a/components/tracing/tracing_messages.h
+++ b/components/tracing/tracing_messages.h
@@ -16,10 +16,11 @@
 #define IPC_MESSAGE_START TracingMsgStart
 
 // Sent to all child processes to enable trace event recording.
-IPC_MESSAGE_CONTROL3(TracingMsg_BeginTracing,
+IPC_MESSAGE_CONTROL4(TracingMsg_BeginTracing,
                      std::string /*  category_filter_str */,
                      base::TimeTicks /* browser_time */,
-                     int /* base::debug::TraceLog::Options */)
+                     int /* base::debug::TraceLog::Options */,
+                     bool /* tracing_startup */)
 
 // Sent to all child processes to disable trace event recording.
 IPC_MESSAGE_CONTROL0(TracingMsg_EndTracing)
diff --git a/components/translate/common/translate_metrics.cc b/components/translate/common/translate_metrics.cc
index b095084..5402491 100644
--- a/components/translate/common/translate_metrics.cc
+++ b/components/translate/common/translate_metrics.cc
@@ -23,6 +23,9 @@
 const char kTranslateUserActionDuration[] = "Translate.UserActionDuration";
 const char kTranslatePageScheme[] = "Translate.PageScheme";
 const char kTranslateSimilarLanguageMatch[] = "Translate.SimilarLanguageMatch";
+const char kTranslateModifyOriginalLang[] = "Translate.ModifyOriginalLang";
+const char kTranslateModifyTargetLang[] = "Translate.ModifyTargetlLang";
+
 
 const char kSchemeHttp[] = "http";
 const char kSchemeHttps[] = "https";
@@ -33,6 +36,8 @@
 };
 
 // This entry table should be updated when new UMA items are added.
+// TODO(miguelg) Move kTranslateModifyOriginalLang and
+// kTranslateModifyTargetLang to the UX delegate  once crbug/312720 is fixed.
 const MetricsEntry kMetricsEntries[] = {
     {UMA_LANGUAGE_DETECTION, kRenderer4LanguageDetection},
     {UMA_CONTENT_LANGUAGE, kTranslateContentLanguage},
@@ -43,7 +48,9 @@
     {UMA_TIME_TO_TRANSLATE, kTranslateTimeToTranslate},
     {UMA_USER_ACTION_DURATION, kTranslateUserActionDuration},
     {UMA_PAGE_SCHEME, kTranslatePageScheme},
-    {UMA_SIMILAR_LANGUAGE_MATCH, kTranslateSimilarLanguageMatch}, };
+    {UMA_SIMILAR_LANGUAGE_MATCH, kTranslateSimilarLanguageMatch},
+    {UMA_MODIFY_ORIGINAL_LANG, kTranslateModifyOriginalLang},
+    {UMA_MODIFY_TARGET_LANG, kTranslateModifyTargetLang}, };
 
 COMPILE_ASSERT(arraysize(kMetricsEntries) == UMA_MAX,
                arraysize_of_kMetricsEntries_should_be_UMA_MAX);
diff --git a/components/translate/common/translate_metrics.h b/components/translate/common/translate_metrics.h
index 9baa268..a38db44 100644
--- a/components/translate/common/translate_metrics.h
+++ b/components/translate/common/translate_metrics.h
@@ -24,6 +24,8 @@
   UMA_USER_ACTION_DURATION,
   UMA_PAGE_SCHEME,
   UMA_SIMILAR_LANGUAGE_MATCH,
+  UMA_MODIFY_ORIGINAL_LANG,
+  UMA_MODIFY_TARGET_LANG,
   UMA_MAX,
 };
 
diff --git a/components/user_prefs.target.darwin-arm.mk b/components/user_prefs.target.darwin-arm.mk
index 50c1fbd..70a2561 100644
--- a/components/user_prefs.target.darwin-arm.mk
+++ b/components/user_prefs.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/user_prefs.target.darwin-mips.mk b/components/user_prefs.target.darwin-mips.mk
index 079e437..b4473ee 100644
--- a/components/user_prefs.target.darwin-mips.mk
+++ b/components/user_prefs.target.darwin-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/user_prefs.target.darwin-x86.mk b/components/user_prefs.target.darwin-x86.mk
index 604dd44..1ef3916 100644
--- a/components/user_prefs.target.darwin-x86.mk
+++ b/components/user_prefs.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/user_prefs.target.linux-arm.mk b/components/user_prefs.target.linux-arm.mk
index 50c1fbd..70a2561 100644
--- a/components/user_prefs.target.linux-arm.mk
+++ b/components/user_prefs.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/user_prefs.target.linux-mips.mk b/components/user_prefs.target.linux-mips.mk
index 079e437..b4473ee 100644
--- a/components/user_prefs.target.linux-mips.mk
+++ b/components/user_prefs.target.linux-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/user_prefs.target.linux-x86.mk b/components/user_prefs.target.linux-x86.mk
index 604dd44..1ef3916 100644
--- a/components/user_prefs.target.linux-x86.mk
+++ b/components/user_prefs.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.darwin-arm.mk b/components/visitedlink_browser.target.darwin-arm.mk
index 65f6040..dcfe8c6 100644
--- a/components/visitedlink_browser.target.darwin-arm.mk
+++ b/components/visitedlink_browser.target.darwin-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.darwin-mips.mk b/components/visitedlink_browser.target.darwin-mips.mk
index bf5c886..9c9efa4 100644
--- a/components/visitedlink_browser.target.darwin-mips.mk
+++ b/components/visitedlink_browser.target.darwin-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.darwin-x86.mk b/components/visitedlink_browser.target.darwin-x86.mk
index 37a34c7..f6b390a 100644
--- a/components/visitedlink_browser.target.darwin-x86.mk
+++ b/components/visitedlink_browser.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.linux-arm.mk b/components/visitedlink_browser.target.linux-arm.mk
index 65f6040..dcfe8c6 100644
--- a/components/visitedlink_browser.target.linux-arm.mk
+++ b/components/visitedlink_browser.target.linux-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.linux-mips.mk b/components/visitedlink_browser.target.linux-mips.mk
index bf5c886..9c9efa4 100644
--- a/components/visitedlink_browser.target.linux-mips.mk
+++ b/components/visitedlink_browser.target.linux-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_browser.target.linux-x86.mk b/components/visitedlink_browser.target.linux-x86.mk
index 37a34c7..f6b390a 100644
--- a/components/visitedlink_browser.target.linux-x86.mk
+++ b/components/visitedlink_browser.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.darwin-arm.mk b/components/visitedlink_common.target.darwin-arm.mk
index a8cd30e..a486d13 100644
--- a/components/visitedlink_common.target.darwin-arm.mk
+++ b/components/visitedlink_common.target.darwin-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.darwin-mips.mk b/components/visitedlink_common.target.darwin-mips.mk
index 9c19cac..361eeef 100644
--- a/components/visitedlink_common.target.darwin-mips.mk
+++ b/components/visitedlink_common.target.darwin-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.darwin-x86.mk b/components/visitedlink_common.target.darwin-x86.mk
index 5c03d40..1ffd577 100644
--- a/components/visitedlink_common.target.darwin-x86.mk
+++ b/components/visitedlink_common.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.linux-arm.mk b/components/visitedlink_common.target.linux-arm.mk
index a8cd30e..a486d13 100644
--- a/components/visitedlink_common.target.linux-arm.mk
+++ b/components/visitedlink_common.target.linux-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.linux-mips.mk b/components/visitedlink_common.target.linux-mips.mk
index 9c19cac..361eeef 100644
--- a/components/visitedlink_common.target.linux-mips.mk
+++ b/components/visitedlink_common.target.linux-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_common.target.linux-x86.mk b/components/visitedlink_common.target.linux-x86.mk
index 5c03d40..1ffd577 100644
--- a/components/visitedlink_common.target.linux-x86.mk
+++ b/components/visitedlink_common.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.darwin-arm.mk b/components/visitedlink_renderer.target.darwin-arm.mk
index 8de84f4..3d69fb9 100644
--- a/components/visitedlink_renderer.target.darwin-arm.mk
+++ b/components/visitedlink_renderer.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.darwin-mips.mk b/components/visitedlink_renderer.target.darwin-mips.mk
index 34ae362..70f1e08 100644
--- a/components/visitedlink_renderer.target.darwin-mips.mk
+++ b/components/visitedlink_renderer.target.darwin-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.darwin-x86.mk b/components/visitedlink_renderer.target.darwin-x86.mk
index 35bf3cd..735758f 100644
--- a/components/visitedlink_renderer.target.darwin-x86.mk
+++ b/components/visitedlink_renderer.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.linux-arm.mk b/components/visitedlink_renderer.target.linux-arm.mk
index 8de84f4..3d69fb9 100644
--- a/components/visitedlink_renderer.target.linux-arm.mk
+++ b/components/visitedlink_renderer.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.linux-mips.mk b/components/visitedlink_renderer.target.linux-mips.mk
index 34ae362..70f1e08 100644
--- a/components/visitedlink_renderer.target.linux-mips.mk
+++ b/components/visitedlink_renderer.target.linux-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/visitedlink_renderer.target.linux-x86.mk b/components/visitedlink_renderer.target.linux-x86.mk
index 35bf3cd..735758f 100644
--- a/components/visitedlink_renderer.target.linux-x86.mk
+++ b/components/visitedlink_renderer.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.darwin-arm.mk b/components/web_contents_delegate_android.target.darwin-arm.mk
index 8095c54..0f73802 100644
--- a/components/web_contents_delegate_android.target.darwin-arm.mk
+++ b/components/web_contents_delegate_android.target.darwin-arm.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.darwin-mips.mk b/components/web_contents_delegate_android.target.darwin-mips.mk
index d752183..52e14f4 100644
--- a/components/web_contents_delegate_android.target.darwin-mips.mk
+++ b/components/web_contents_delegate_android.target.darwin-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.darwin-x86.mk b/components/web_contents_delegate_android.target.darwin-x86.mk
index d23ab53..af33556 100644
--- a/components/web_contents_delegate_android.target.darwin-x86.mk
+++ b/components/web_contents_delegate_android.target.darwin-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.linux-arm.mk b/components/web_contents_delegate_android.target.linux-arm.mk
index 8095c54..0f73802 100644
--- a/components/web_contents_delegate_android.target.linux-arm.mk
+++ b/components/web_contents_delegate_android.target.linux-arm.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.linux-mips.mk b/components/web_contents_delegate_android.target.linux-mips.mk
index d752183..52e14f4 100644
--- a/components/web_contents_delegate_android.target.linux-mips.mk
+++ b/components/web_contents_delegate_android.target.linux-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android.target.linux-x86.mk b/components/web_contents_delegate_android.target.linux-x86.mk
index d23ab53..af33556 100644
--- a/components/web_contents_delegate_android.target.linux-x86.mk
+++ b/components/web_contents_delegate_android.target.linux-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.darwin-arm.mk b/components/web_contents_delegate_android_jni_headers.target.darwin-arm.mk
index eea1368..12654b9 100644
--- a/components/web_contents_delegate_android_jni_headers.target.darwin-arm.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.darwin-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.darwin-mips.mk b/components/web_contents_delegate_android_jni_headers.target.darwin-mips.mk
index feff9d6..c2e42aa 100644
--- a/components/web_contents_delegate_android_jni_headers.target.darwin-mips.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.darwin-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.darwin-x86.mk b/components/web_contents_delegate_android_jni_headers.target.darwin-x86.mk
index 39ac216..5db42f6 100644
--- a/components/web_contents_delegate_android_jni_headers.target.darwin-x86.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.darwin-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.linux-arm.mk b/components/web_contents_delegate_android_jni_headers.target.linux-arm.mk
index eea1368..12654b9 100644
--- a/components/web_contents_delegate_android_jni_headers.target.linux-arm.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.linux-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.linux-mips.mk b/components/web_contents_delegate_android_jni_headers.target.linux-mips.mk
index feff9d6..c2e42aa 100644
--- a/components/web_contents_delegate_android_jni_headers.target.linux-mips.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.linux-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_contents_delegate_android_jni_headers.target.linux-x86.mk b/components/web_contents_delegate_android_jni_headers.target.linux-x86.mk
index 39ac216..5db42f6 100644
--- a/components/web_contents_delegate_android_jni_headers.target.linux-x86.mk
+++ b/components/web_contents_delegate_android_jni_headers.target.linux-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc
index f454445..85b0448 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -51,7 +51,7 @@
   native_manager_->FocusDialog(child_dialogs_.front().dialog);
 }
 
-void WebContentsModalDialogManager::SetCloseOnInterstitialWebUI(
+void WebContentsModalDialogManager::SetCloseOnInterstitialPage(
     NativeWebContentsModalDialog dialog,
     bool close) {
   WebContentsModalDialogList::iterator loc = FindDialogState(dialog);
@@ -93,7 +93,14 @@
 WebContentsModalDialogManager::DialogState::DialogState(
     NativeWebContentsModalDialog dialog)
     : dialog(dialog),
-      close_on_interstitial_webui(false) {
+#if defined(OS_WIN) || defined(USE_AURA)
+      close_on_interstitial_webui(true)
+#else
+      // TODO(wittman): Test that closing on interstitial webui works properly
+      // on Mac and use the true default for all platforms.
+      close_on_interstitial_webui(false)
+#endif
+                                         {
 }
 
 WebContentsModalDialogManager::WebContentsModalDialogList::iterator
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index 253de18..dc32674 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -43,8 +43,8 @@
   void FocusTopmostDialog();
 
   // Set to true to close the window when a page load starts on the WebContents.
-  void SetCloseOnInterstitialWebUI(NativeWebContentsModalDialog dialog,
-                                   bool close);
+  void SetCloseOnInterstitialPage(NativeWebContentsModalDialog dialog,
+                                  bool close);
 
   // Overriden from NativeWebContentsModalDialogManagerDelegate:
   virtual content::WebContents* GetWebContents() const OVERRIDE;
diff --git a/components/web_modal/web_contents_modal_dialog_manager_unittest.cc b/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
index 7095498..1353f10 100644
--- a/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
@@ -198,9 +198,8 @@
             native_manager->GetDialogState(dialog1));
 }
 
-// Test that attaching an interstitial WebUI page closes dialogs configured to
-// close on interstitial WebUI.
-TEST_F(WebContentsModalDialogManagerTest, InterstitialWebUI) {
+// Test that attaching an interstitial page closes dialogs configured to close.
+TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) {
   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
   const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
@@ -209,8 +208,14 @@
   manager->ShowDialog(dialog2);
   manager->ShowDialog(dialog3);
 
-  manager->SetCloseOnInterstitialWebUI(dialog1, true);
-  manager->SetCloseOnInterstitialWebUI(dialog3, true);
+#if defined(OS_WIN) || defined(USE_AURA)
+  manager->SetCloseOnInterstitialPage(dialog2, false);
+#else
+  // TODO(wittman): Remove this section once Mac is changed to close on
+  // interstitial pages by default.
+  manager->SetCloseOnInterstitialPage(dialog1, true);
+  manager->SetCloseOnInterstitialPage(dialog3, true);
+#endif
 
   test_api->DidAttachInterstitialPage();
   EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
diff --git a/components/webdata_common.target.darwin-arm.mk b/components/webdata_common.target.darwin-arm.mk
index bf03623..9e5cd4a 100644
--- a/components/webdata_common.target.darwin-arm.mk
+++ b/components/webdata_common.target.darwin-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/webdata_common.target.darwin-mips.mk b/components/webdata_common.target.darwin-mips.mk
index 5f410a6..5d8adfc 100644
--- a/components/webdata_common.target.darwin-mips.mk
+++ b/components/webdata_common.target.darwin-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/webdata_common.target.darwin-x86.mk b/components/webdata_common.target.darwin-x86.mk
index ac4636a..9b8c1ab 100644
--- a/components/webdata_common.target.darwin-x86.mk
+++ b/components/webdata_common.target.darwin-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/webdata_common.target.linux-arm.mk b/components/webdata_common.target.linux-arm.mk
index bf03623..9e5cd4a 100644
--- a/components/webdata_common.target.linux-arm.mk
+++ b/components/webdata_common.target.linux-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/webdata_common.target.linux-mips.mk b/components/webdata_common.target.linux-mips.mk
index 5f410a6..5d8adfc 100644
--- a/components/webdata_common.target.linux-mips.mk
+++ b/components/webdata_common.target.linux-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/components/webdata_common.target.linux-x86.mk b/components/webdata_common.target.linux-x86.mk
index ac4636a..9b8c1ab 100644
--- a/components/webdata_common.target.linux-x86.mk
+++ b/components/webdata_common.target.linux-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/DEPS b/content/browser/DEPS
index be3040d..f011c7b 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -5,6 +5,7 @@
   "+media/audio",  # For audio input for speech input feature.
   "+media/base",  # For Android JNI registration.
   "+media/midi",  # For Web MIDI API
+  "+media/video",  # For Video Device monitoring in Mac.
   "+sql",
   "+ui/webui",
   "+win8/util",
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index c11ceea..5fc094a 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -39,7 +39,7 @@
  public:
   // Unfortunately, some screen readers look for this exact window class
   // to enable certain features. It'd be great to remove this.
-  DECLARE_WND_CLASS_EX(L"Chrome_RenderWidgetHostHWND1", CS_DBLCLKS, 0);
+  DECLARE_WND_CLASS_EX(L"Chrome_RenderWidgetHostHWND", CS_DBLCLKS, 0);
 
   BEGIN_MSG_MAP_EX(AccessibleHWND)
     MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
diff --git a/content/browser/android/OWNERS b/content/browser/android/OWNERS
index a5cf4a9..a05938f 100644
--- a/content/browser/android/OWNERS
+++ b/content/browser/android/OWNERS
@@ -1,5 +1,6 @@
 bulach@chromium.org
 joth@chromium.org
+sievers@chromium.org
+skyostil@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
-sievers@chromium.org
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc
index 8c622c2..875f91e 100644
--- a/content/browser/android/content_startup_flags.cc
+++ b/content/browser/android/content_startup_flags.cc
@@ -71,8 +71,6 @@
   parsed_command_line->AppendSwitch(switches::kInProcessGPU);
   parsed_command_line->AppendSwitch(switches::kDisableGpuShaderDiskCache);
 
-  // Always use fixed layout and viewport tag.
-  parsed_command_line->AppendSwitch(switches::kEnableFixedLayout);
   parsed_command_line->AppendSwitch(switches::kEnableViewport);
 
   // Disable anti-aliasing.
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 4ecebb7..1e296f1 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -18,6 +18,9 @@
 #include "content/browser/android/interstitial_page_delegate_android.h"
 #include "content/browser/android/load_url_params.h"
 #include "content/browser/android/touch_point.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/renderer_host/compositor_impl_android.h"
 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
@@ -27,9 +30,6 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/browser/ssl/ssl_host_state.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_view_android.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
@@ -1044,7 +1044,7 @@
                                          jlong time_ms,
                                          jfloat x, jfloat y) {
   WebGestureEvent event = MakeGestureEvent(
-      WebInputEvent::GestureTapDown, time_ms, x, y);
+      WebInputEvent::GestureShowPress, time_ms, x, y);
   SendGestureEvent(event);
 }
 
@@ -1058,6 +1058,14 @@
   SendGestureEvent(event);
 }
 
+void ContentViewCoreImpl::TapDown(JNIEnv* env, jobject obj,
+                                  jlong time_ms,
+                                  jfloat x, jfloat y) {
+  WebGestureEvent event = MakeGestureEvent(
+      WebInputEvent::GestureTapDown, time_ms, x, y);
+  SendGestureEvent(event);
+}
+
 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
                                     jfloat x, jfloat y) {
   WebGestureEvent event = MakeGestureEvent(
@@ -1353,6 +1361,8 @@
 
 void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) {
   RenderViewHost* host = web_contents_->GetRenderViewHost();
+  if (!host)
+    return;
   host->ExitFullscreen();
 }
 
@@ -1362,6 +1372,8 @@
                                                  bool enable_showing,
                                                  bool animate) {
   RenderViewHost* host = web_contents_->GetRenderViewHost();
+  if (!host)
+    return;
   host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
                                                 enable_hiding,
                                                 enable_showing,
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index b9da583..116174c 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -123,6 +123,8 @@
                       jfloat x, jfloat y);
   void ShowPressCancel(JNIEnv* env, jobject obj, jlong time_ms,
                        jfloat x, jfloat y);
+  void TapDown(JNIEnv* env, jobject obj, jlong time_ms,
+               jfloat x, jfloat y);
   void DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
                  jfloat x, jfloat y) ;
   void LongPress(JNIEnv* env, jobject obj, jlong time_ms,
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc
index 7c91ff0..be87a93 100644
--- a/content/browser/android/date_time_chooser_android.cc
+++ b/content/browser/android/date_time_chooser_android.cc
@@ -7,7 +7,7 @@
 #include "base/android/jni_string.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/android/content_view_core.h"
-#include "content/public/browser/render_view_host_observer.h"
+#include "content/public/browser/render_view_host.h"
 #include "jni/DateTimeChooserAndroid_jni.h"
 
 using base::android::AttachCurrentThread;
@@ -17,61 +17,9 @@
 
 namespace content {
 
-// Updates date/time via IPC to the RenderView
-class DateTimeChooserAndroid::DateTimeIPCSender :
-    public RenderViewHostObserver {
- public:
-  explicit DateTimeIPCSender(RenderViewHost* sender);
-  virtual ~DateTimeIPCSender() {}
-  void ReplaceDateTime(int dialog_type,
-                       int year,
-                       int month,
-                       int day,
-                       int hour,
-                       int minute,
-                       int second,
-                       int milli,
-                       int week);
-  void CancelDialog();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DateTimeIPCSender);
-};
-
-DateTimeChooserAndroid::DateTimeIPCSender::DateTimeIPCSender(
-    RenderViewHost* sender)
-  : RenderViewHostObserver(sender) {
-}
-
-void DateTimeChooserAndroid::DateTimeIPCSender::ReplaceDateTime(int dialog_type,
-                                                                int year,
-                                                                int month,
-                                                                int day,
-                                                                int hour,
-                                                                int minute,
-                                                                int second,
-                                                                int milli,
-                                                                int week) {
-  ViewHostMsg_DateTimeDialogValue_Params value;
-  value.year = year;
-  value.month = month;
-  value.day = day;
-  value.hour = hour;
-  value.minute = minute;
-  value.second = second;
-  value.milli = milli;
-  value.week = week;
-  value.dialog_type = dialog_type;
-  Send(new ViewMsg_ReplaceDateTime(routing_id(), value));
-}
-
-void DateTimeChooserAndroid::DateTimeIPCSender::CancelDialog() {
-  Send(new ViewMsg_CancelDateTimeDialog(routing_id()));
-}
-
 // DateTimeChooserAndroid implementation
 DateTimeChooserAndroid::DateTimeChooserAndroid()
-  : sender_(NULL) {
+  : host_(NULL) {
 }
 
 DateTimeChooserAndroid::~DateTimeChooserAndroid() {
@@ -101,16 +49,25 @@
                                              int second,
                                              int milli,
                                              int week) {
-  sender_->ReplaceDateTime(
-      dialog_type, year, month, day, hour, minute, second, milli, week);
+  ViewHostMsg_DateTimeDialogValue_Params value;
+  value.year = year;
+  value.month = month;
+  value.day = day;
+  value.hour = hour;
+  value.minute = minute;
+  value.second = second;
+  value.milli = milli;
+  value.week = week;
+  value.dialog_type = dialog_type;
+  host_->Send(new ViewMsg_ReplaceDateTime(host_->GetRoutingID(), value));
 }
 
 void DateTimeChooserAndroid::CancelDialog(JNIEnv* env, jobject) {
-  sender_->CancelDialog();
+  host_->Send(new ViewMsg_CancelDateTimeDialog(host_->GetRoutingID()));
 }
 
 void DateTimeChooserAndroid::ShowDialog(ContentViewCore* content,
-                                        RenderViewHost* sender,
+                                        RenderViewHost* host,
                                         int type,
                                         int year,
                                         int month,
@@ -123,9 +80,7 @@
                                         double min,
                                         double max,
                                         double step) {
-  if (sender_)
-    delete sender_;
-  sender_ = new DateTimeIPCSender(sender);
+  host_ = host;
 
   JNIEnv* env = AttachCurrentThread();
   j_date_time_chooser_.Reset(Java_DateTimeChooserAndroid_createDateTimeChooser(
diff --git a/content/browser/android/date_time_chooser_android.h b/content/browser/android/date_time_chooser_android.h
index 68cb456..a5578e0 100644
--- a/content/browser/android/date_time_chooser_android.h
+++ b/content/browser/android/date_time_chooser_android.h
@@ -23,7 +23,7 @@
 
   // DateTimeChooser implementation:
   void ShowDialog(ContentViewCore* content,
-                  RenderViewHost* sender,
+                  RenderViewHost* host,
                   int type,
                   int year,
                   int month,
@@ -61,11 +61,7 @@
        int text_input_type_time, int text_input_type_week);
 
  private:
-  class DateTimeIPCSender;
-
-  // The DateTimeIPCSender class is a render view observer, so it will take care
-  // of its own deletion.
-  DateTimeIPCSender* sender_;
+  RenderViewHost* host_;
 
   base::android::ScopedJavaGlobalRef<jobject> j_date_time_chooser_;
 
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
index a966cb3..54ea181 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -14,6 +14,7 @@
 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "third_party/skia/include/core/SkBitmapDevice.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "ui/gfx/rect_conversions.h"
@@ -104,7 +105,7 @@
     : cc::OutputSurface(
           scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
       routing_id_(routing_id),
-      needs_begin_frame_(false),
+      needs_begin_impl_frame_(false),
       invoking_composite_(false),
       did_swap_buffer_(false),
       current_sw_canvas_(NULL),
@@ -117,7 +118,7 @@
   // constructed on the correct thread.
 
   memory_policy_.priority_cutoff_when_visible =
-      cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
+      gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
 }
 
 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
@@ -158,14 +159,14 @@
   // Intentional no-op: surface size is controlled by the embedder.
 }
 
-void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(
+void SynchronousCompositorOutputSurface::SetNeedsBeginImplFrame(
     bool enable) {
   DCHECK(CalledOnValidThread());
-  cc::OutputSurface::SetNeedsBeginFrame(enable);
-  needs_begin_frame_ = enable;
+  cc::OutputSurface::SetNeedsBeginImplFrame(enable);
+  needs_begin_impl_frame_ = enable;
   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
   if (delegate)
-    delegate->SetContinuousInvalidate(needs_begin_frame_);
+    delegate->SetContinuousInvalidate(needs_begin_impl_frame_);
 }
 
 void SynchronousCompositorOutputSurface::SwapBuffers(
@@ -264,8 +265,8 @@
       adjusted_transform, viewport, clip, valid_for_tile_management);
   SetNeedsRedrawRect(gfx::Rect(viewport.size()));
 
-  if (needs_begin_frame_)
-    BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
+  if (needs_begin_impl_frame_)
+    BeginImplFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
 
   // After software draws (which might move the viewport arbitrarily), restore
   // the previous hardware viewport to allow CC's tile manager to prioritize
@@ -283,8 +284,9 @@
     OnSwapBuffersComplete();
 }
 
-void SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginFrame() {
-  // Synchronous compositor cannot perform retroactive begin frames, so
+void
+SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginImplFrame() {
+  // Synchronous compositor cannot perform retroactive BeginImplFrames, so
   // intentionally no-op here.
 }
 
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h
index b9b4d67..2879de0 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.h
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h
@@ -59,7 +59,7 @@
   virtual bool ForcedDrawToSoftwareDevice() const OVERRIDE;
   virtual bool BindToClient(cc::OutputSurfaceClient* surface_client) OVERRIDE;
   virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE;
-  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
+  virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE;
   virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
 
   // Partial SynchronousCompositor API implementation.
@@ -80,7 +80,7 @@
   friend class SoftwareDevice;
 
   // Private OutputSurface overrides.
-  virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE;
+  virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE;
 
   void InvokeComposite(const gfx::Transform& transform,
                        gfx::Rect viewport,
@@ -90,7 +90,7 @@
   SynchronousCompositorOutputSurfaceDelegate* GetDelegate();
 
   int routing_id_;
-  bool needs_begin_frame_;
+  bool needs_begin_impl_frame_;
   bool invoking_composite_;
   bool did_swap_buffer_;
 
diff --git a/content/browser/android/vibration_message_filter.cc b/content/browser/android/vibration_message_filter.cc
index 578fbfd..6792db1 100644
--- a/content/browser/android/vibration_message_filter.cc
+++ b/content/browser/android/vibration_message_filter.cc
@@ -57,13 +57,17 @@
             base::android::GetApplicationContext()));
   }
   Java_VibrationMessageFilter_vibrate(AttachCurrentThread(),
-                                j_vibration_message_filter_.obj(),
-                                milliseconds);
+                                      j_vibration_message_filter_.obj(),
+                                      milliseconds);
 }
 
 void VibrationMessageFilter::OnCancelVibration() {
+  // If somehow a cancel message is received before this object was
+  // instantiated, it means there is no current vibration anyway. Just return.
+  if (j_vibration_message_filter_.is_null())
+    return;
   Java_VibrationMessageFilter_cancelVibration(AttachCurrentThread(),
-                                        j_vibration_message_filter_.obj());
+      j_vibration_message_filter_.obj());
 }
 
 }  // namespace content
diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc
index 649dd28..302f9ef 100644
--- a/content/browser/aura/gpu_process_transport_factory.cc
+++ b/content/browser/aura/gpu_process_transport_factory.cc
@@ -36,6 +36,8 @@
 #if defined(OS_WIN)
 #include "content/browser/aura/software_output_device_win.h"
 #include "ui/surface/accelerated_surface_win.h"
+#elif defined(USE_OZONE)
+#include "content/browser/aura/software_output_device_ozone.h"
 #elif defined(USE_X11)
 #include "content/browser/aura/software_output_device_x11.h"
 #endif
@@ -205,6 +207,9 @@
 #if defined(OS_WIN)
   return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin(
       compositor));
+#elif defined(USE_OZONE)
+  return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone(
+      compositor));
 #elif defined(USE_X11)
   return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11(
       compositor));
@@ -221,12 +226,17 @@
     data = CreatePerCompositorData(compositor);
 
   scoped_refptr<ContextProviderCommandBuffer> context_provider;
+  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client_weak_ptr;
+  if (data->swap_client)
+    swap_client_weak_ptr = data->swap_client->AsWeakPtr();
 
   CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
+  if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing) &&
+      (!compositor->use_software_renderer() ||
+       ui::Compositor::WasInitializedWithThread())) {
     context_provider = ContextProviderCommandBuffer::Create(
         GpuProcessTransportFactory::CreateContextCommon(
-            data->swap_client->AsWeakPtr(),
+            swap_client_weak_ptr,
             data->surface_id),
             "Compositor");
   }
@@ -451,7 +461,8 @@
 
   // Prevent callbacks from other contexts in the same share group from
   // calling us again.
-  data->swap_client.reset(new CompositorSwapClient(compositor, this));
+  if (data->swap_client.get())
+    data->swap_client.reset(new CompositorSwapClient(compositor, this));
   compositor->OnSwapBuffersAborted();
 }
 
@@ -465,7 +476,8 @@
 
   PerCompositorData* data = new PerCompositorData;
   data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
-  data->swap_client.reset(new CompositorSwapClient(compositor, this));
+  if (!ui::Compositor::WasInitializedWithThread())
+    data->swap_client.reset(new CompositorSwapClient(compositor, this));
 #if defined(OS_WIN)
   if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
     data->accelerated_surface.reset(new AcceleratedSurface(widget));
@@ -491,19 +503,21 @@
   attrs.stencil = false;
   attrs.antialias = false;
   attrs.noAutomaticFlushes = true;
-  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
+  scoped_refptr<GpuChannelHost> gpu_channel_host(
+      BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(
+          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
+  if (!gpu_channel_host)
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
   GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
       new WebGraphicsContext3DCommandBufferImpl(
           surface_id,
           url,
-          factory,
-          swap_client));
-  if (!context->InitializeWithDefaultBufferSizes(
-        attrs,
-        false,
-        CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
-    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+          gpu_channel_host.get(),
+          swap_client,
+          attrs,
+          false,
+          WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits()));
   return context.Pass();
 }
 
diff --git a/content/browser/aura/image_transport_factory.cc b/content/browser/aura/image_transport_factory.cc
index ca83149..4a20e7d 100644
--- a/content/browser/aura/image_transport_factory.cc
+++ b/content/browser/aura/image_transport_factory.cc
@@ -4,56 +4,32 @@
 
 #include "content/browser/aura/image_transport_factory.h"
 
-#include "base/command_line.h"
-#include "base/sys_info.h"
 #include "content/browser/aura/gpu_process_transport_factory.h"
 #include "content/browser/aura/no_transport_image_transport_factory.h"
-#include "content/public/common/content_switches.h"
 #include "ui/compositor/compositor.h"
-#include "ui/compositor/compositor_switches.h"
 
 namespace content {
 
 namespace {
-ImageTransportFactory* g_factory;
-}
-
-
-static bool UseTestContextAndTransportFactory() {
-#if defined(OS_CHROMEOS)
-  // If the test is running on the chromeos envrionment (such as
-  // device or vm bots), always use real contexts.
-  if (base::SysInfo::IsRunningOnChromeOS())
-    return false;
-#endif
-
-  // Only used if the enable command line flag is used.
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(switches::kTestCompositor))
-    return false;
-
-  // The disable command line flag preempts the enable flag.
-  if (!command_line->HasSwitch(switches::kDisableTestCompositor))
-    return true;
-
-  return false;
+ImageTransportFactory* g_factory = NULL;
+bool g_initialized_for_unit_tests = false;
 }
 
 // static
 void ImageTransportFactory::Initialize() {
-  DCHECK(!g_factory);
-  if (UseTestContextAndTransportFactory()) {
-    g_factory =
-        new NoTransportImageTransportFactory(new ui::TestContextFactory);
-  } else {
-    g_factory = new GpuProcessTransportFactory;
-  }
+  DCHECK(!g_factory || g_initialized_for_unit_tests);
+  if (g_initialized_for_unit_tests)
+    return;
+  g_factory = new GpuProcessTransportFactory;
   ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
 }
 
-void ImageTransportFactory::InitializeForUnitTests() {
+void ImageTransportFactory::InitializeForUnitTests(
+    scoped_ptr<ui::ContextFactory> test_factory) {
   DCHECK(!g_factory);
-  g_factory = new NoTransportImageTransportFactory(new ui::TestContextFactory);
+  DCHECK(!g_initialized_for_unit_tests);
+  g_initialized_for_unit_tests = true;
+  g_factory = new NoTransportImageTransportFactory(test_factory.Pass());
   ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
 }
 
@@ -62,6 +38,7 @@
   ui::ContextFactory::SetInstance(NULL);
   delete g_factory;
   g_factory = NULL;
+  g_initialized_for_unit_tests = false;
 }
 
 // static
diff --git a/content/browser/aura/image_transport_factory.h b/content/browser/aura/image_transport_factory.h
index 7cd2523..bfe7057c 100644
--- a/content/browser/aura/image_transport_factory.h
+++ b/content/browser/aura/image_transport_factory.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -52,9 +53,10 @@
   // Initializes the global transport factory.
   static void Initialize();
 
-  // Initializes the global transport factory for unit tests, using a test
-  // context.
-  static void InitializeForUnitTests();
+  // Initializes the global transport factory for unit tests using the provided
+  // context factory.
+  static void InitializeForUnitTests(
+      scoped_ptr<ui::ContextFactory> test_factory);
 
   // Terminates the global transport factory.
   static void Terminate();
diff --git a/content/browser/aura/no_transport_image_transport_factory.cc b/content/browser/aura/no_transport_image_transport_factory.cc
index 496362a..5764805 100644
--- a/content/browser/aura/no_transport_image_transport_factory.cc
+++ b/content/browser/aura/no_transport_image_transport_factory.cc
@@ -44,8 +44,8 @@
 }  // anonymous namespace
 
 NoTransportImageTransportFactory::NoTransportImageTransportFactory(
-    ui::ContextFactory* context_factory)
-    : context_factory_(context_factory) {}
+    scoped_ptr<ui::ContextFactory> context_factory)
+    : context_factory_(context_factory.Pass()) {}
 
 NoTransportImageTransportFactory::~NoTransportImageTransportFactory() {}
 
diff --git a/content/browser/aura/no_transport_image_transport_factory.h b/content/browser/aura/no_transport_image_transport_factory.h
index 0d57164..dd551d9 100644
--- a/content/browser/aura/no_transport_image_transport_factory.h
+++ b/content/browser/aura/no_transport_image_transport_factory.h
@@ -18,7 +18,7 @@
 class NoTransportImageTransportFactory : public ImageTransportFactory {
  public:
   explicit NoTransportImageTransportFactory(
-      ui::ContextFactory* context_factory);
+      scoped_ptr<ui::ContextFactory> context_factory);
   virtual ~NoTransportImageTransportFactory();
 
   // ImageTransportFactory implementation.
diff --git a/content/browser/aura/software_output_device_ozone.cc b/content/browser/aura/software_output_device_ozone.cc
new file mode 100644
index 0000000..c704fed
--- /dev/null
+++ b/content/browser/aura/software_output_device_ozone.cc
@@ -0,0 +1,69 @@
+// Copyright 2013 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/aura/software_output_device_ozone.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "ui/compositor/compositor.h"
+#include "ui/gfx/ozone/surface_factory_ozone.h"
+#include "ui/gfx/skia_util.h"
+
+namespace content {
+
+SoftwareOutputDeviceOzone::SoftwareOutputDeviceOzone(
+    ui::Compositor* compositor) : compositor_(compositor) {
+  if (gfx::SurfaceFactoryOzone::GetInstance()->InitializeHardware() !=
+      gfx::SurfaceFactoryOzone::INITIALIZED)
+    LOG(FATAL) << "Failed to initialize hardware in OZONE";
+}
+
+SoftwareOutputDeviceOzone::~SoftwareOutputDeviceOzone() {
+}
+
+void SoftwareOutputDeviceOzone::Resize(gfx::Size viewport_size) {
+  if (viewport_size_ == viewport_size)
+    return;
+
+  viewport_size_ = viewport_size;
+  gfx::Rect bounds(viewport_size_);
+
+  gfx::SurfaceFactoryOzone* factory = gfx::SurfaceFactoryOzone::GetInstance();
+  factory->AttemptToResizeAcceleratedWidget(compositor_->widget(),
+                                            bounds);
+  gfx::AcceleratedWidget realized_widget = factory->RealizeAcceleratedWidget(
+      compositor_->widget());
+
+  if (realized_widget == gfx::kNullAcceleratedWidget)
+    LOG(FATAL) << "Failed to get a realized AcceleratedWidget";
+
+  canvas_ = skia::SharePtr(factory->GetCanvasForWidget(realized_widget));
+  device_ = skia::SharePtr(canvas_->getDevice());
+}
+
+SkCanvas* SoftwareOutputDeviceOzone::BeginPaint(gfx::Rect damage_rect) {
+  DCHECK(gfx::Rect(viewport_size_).Contains(damage_rect));
+
+  canvas_->clipRect(gfx::RectToSkRect(damage_rect), SkRegion::kReplace_Op);
+  // Save the current state so we can restore once we're done drawing. This is
+  // saved after the clip since we want to keep the clip information after we're
+  // done drawing such that OZONE knows what was updated.
+  canvas_->save();
+
+  return SoftwareOutputDevice::BeginPaint(damage_rect);
+}
+
+void SoftwareOutputDeviceOzone::EndPaint(cc::SoftwareFrameData* frame_data) {
+  SoftwareOutputDevice::EndPaint(frame_data);
+
+  canvas_->restore();
+
+  if (damage_rect_.IsEmpty())
+    return;
+
+  bool scheduled = gfx::SurfaceFactoryOzone::GetInstance()->SchedulePageFlip(
+      compositor_->widget());
+  DCHECK(scheduled) << "Failed to schedule pageflip";
+}
+
+}  // namespace content
diff --git a/content/browser/aura/software_output_device_ozone.h b/content/browser/aura/software_output_device_ozone.h
new file mode 100644
index 0000000..cee91f8
--- /dev/null
+++ b/content/browser/aura/software_output_device_ozone.h
@@ -0,0 +1,36 @@
+// Copyright 2013 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_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_
+#define CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_
+
+#include "cc/output/software_output_device.h"
+
+namespace ui {
+class Compositor;
+}
+
+namespace content {
+
+// Ozone implementation which relies on software rendering. Ozone will present
+// an accelerated widget as a SkCanvas. SoftwareOutputDevice will then use the
+// Ozone provided canvas to draw.
+class SoftwareOutputDeviceOzone : public cc::SoftwareOutputDevice {
+ public:
+  explicit SoftwareOutputDeviceOzone(ui::Compositor* compositor);
+  virtual ~SoftwareOutputDeviceOzone();
+
+  virtual void Resize(gfx::Size viewport_size) OVERRIDE;
+  virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE;
+  virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+
+ private:
+  ui::Compositor* compositor_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzone);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_
diff --git a/content/browser/aura/software_output_device_ozone_unittest.cc b/content/browser/aura/software_output_device_ozone_unittest.cc
new file mode 100644
index 0000000..30c696c
--- /dev/null
+++ b/content/browser/aura/software_output_device_ozone_unittest.cc
@@ -0,0 +1,191 @@
+// Copyright 2013 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/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "cc/output/software_frame_data.h"
+#include "content/browser/aura/software_output_device_ozone.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/gfx/ozone/surface_factory_ozone.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace {
+
+class MockSurfaceFactoryOzone : public gfx::SurfaceFactoryOzone {
+ public:
+  MockSurfaceFactoryOzone() {}
+  virtual ~MockSurfaceFactoryOzone() {}
+
+  virtual HardwareState InitializeHardware() OVERRIDE {
+    return SurfaceFactoryOzone::INITIALIZED;
+  }
+
+  virtual void ShutdownHardware() OVERRIDE {}
+  virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 1; }
+  virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
+      gfx::AcceleratedWidget w) OVERRIDE { return w; }
+  virtual bool LoadEGLGLES2Bindings() OVERRIDE { return false; }
+  virtual bool AttemptToResizeAcceleratedWidget(
+      gfx::AcceleratedWidget w, const gfx::Rect& bounds) OVERRIDE {
+    device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
+                                                bounds.width(),
+                                                bounds.height(),
+                                                true));
+    canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
+    return true;
+  }
+  virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w) OVERRIDE {
+    return canvas_.get();
+  }
+  virtual gfx::VSyncProvider* GetVSyncProvider(
+      gfx::AcceleratedWidget w) OVERRIDE {
+    return NULL;
+  }
+ private:
+  skia::RefPtr<SkBitmapDevice> device_;
+  skia::RefPtr<SkCanvas> canvas_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockSurfaceFactoryOzone);
+};
+
+}  // namespace
+
+class SoftwareOutputDeviceOzoneTest : public testing::Test {
+ public:
+  SoftwareOutputDeviceOzoneTest();
+  virtual ~SoftwareOutputDeviceOzoneTest();
+
+  virtual void SetUp() OVERRIDE;
+  virtual void TearDown() OVERRIDE;
+
+ protected:
+  scoped_ptr<content::SoftwareOutputDeviceOzone> output_device_;
+
+ private:
+  scoped_ptr<ui::Compositor> compositor_;
+  scoped_ptr<base::MessageLoop> message_loop_;
+  scoped_ptr<gfx::SurfaceFactoryOzone> surface_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzoneTest);
+};
+
+SoftwareOutputDeviceOzoneTest::SoftwareOutputDeviceOzoneTest() {
+  CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
+  message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
+}
+
+SoftwareOutputDeviceOzoneTest::~SoftwareOutputDeviceOzoneTest() {
+}
+
+void SoftwareOutputDeviceOzoneTest::SetUp() {
+  ui::InitializeContextFactoryForTests(false);
+  ui::Compositor::Initialize();
+
+  surface_factory_.reset(new MockSurfaceFactoryOzone());
+  gfx::SurfaceFactoryOzone::SetInstance(surface_factory_.get());
+
+  const gfx::Size size(500, 400);
+  compositor_.reset(new ui::Compositor(gfx::SurfaceFactoryOzone::GetInstance()
+                                           ->GetAcceleratedWidget()));
+  compositor_->SetScaleAndSize(1.0f, size);
+
+  output_device_.reset(new content::SoftwareOutputDeviceOzone(
+      compositor_.get()));
+  output_device_->Resize(size);
+}
+
+void SoftwareOutputDeviceOzoneTest::TearDown() {
+  output_device_.reset();
+  compositor_.reset();
+  surface_factory_.reset();
+  ui::TerminateContextFactoryForTests();
+  ui::Compositor::Terminate();
+}
+
+TEST_F(SoftwareOutputDeviceOzoneTest, CheckClipAfterBeginPaint) {
+  gfx::Rect damage(10, 10, 100, 100);
+  SkCanvas* canvas = output_device_->BeginPaint(damage);
+
+  SkIRect sk_bounds;
+  canvas->getClipDeviceBounds(&sk_bounds);
+
+  EXPECT_EQ(damage.ToString(), gfx::SkIRectToRect(sk_bounds).ToString());
+}
+
+TEST_F(SoftwareOutputDeviceOzoneTest, CheckClipAfterSecondBeginPaint) {
+  gfx::Rect damage(10, 10, 100, 100);
+  SkCanvas* canvas = output_device_->BeginPaint(damage);
+
+  cc::SoftwareFrameData frame;
+  output_device_->EndPaint(&frame);
+
+  damage = gfx::Rect(100, 100, 100, 100);
+  canvas = output_device_->BeginPaint(damage);
+  SkIRect sk_bounds;
+  canvas->getClipDeviceBounds(&sk_bounds);
+
+  EXPECT_EQ(damage.ToString(), gfx::SkIRectToRect(sk_bounds).ToString());
+}
+
+TEST_F(SoftwareOutputDeviceOzoneTest, CheckCorrectResizeBehavior) {
+  gfx::Rect damage(0, 0, 100, 100);
+  gfx::Size size(200, 100);
+  // Reduce size.
+  output_device_->Resize(size);
+
+  SkCanvas* canvas = output_device_->BeginPaint(damage);
+  gfx::Size canvas_size(canvas->getDeviceSize().width(),
+                        canvas->getDeviceSize().height());
+  EXPECT_EQ(size.ToString(), canvas_size.ToString());
+
+  size.SetSize(1000, 500);
+  // Increase size.
+  output_device_->Resize(size);
+
+  canvas = output_device_->BeginPaint(damage);
+  canvas_size.SetSize(canvas->getDeviceSize().width(),
+                      canvas->getDeviceSize().height());
+  EXPECT_EQ(size.ToString(), canvas_size.ToString());
+
+}
+
+TEST_F(SoftwareOutputDeviceOzoneTest, CheckCopyToBitmap) {
+  const gfx::Rect area(6, 4);
+  output_device_->Resize(area.size());
+  SkCanvas* canvas = output_device_->BeginPaint(area);
+
+  // Clear the background to black.
+  canvas->drawColor(SK_ColorBLACK);
+
+  cc::SoftwareFrameData frame;
+  output_device_->EndPaint(&frame);
+
+  // Draw a white rectangle.
+  gfx::Rect damage(area.width() / 2, area.height() / 2);
+  canvas = output_device_->BeginPaint(damage);
+
+  canvas->drawColor(SK_ColorWHITE);
+
+  output_device_->EndPaint(&frame);
+
+  SkBitmap bitmap;
+  output_device_->CopyToBitmap(area, &bitmap);
+
+  SkAutoLockPixels pixel_lock(bitmap);
+  // Check that the copied bitmap contains the same pixel values as what we
+  // painted.
+  for (int i = 0; i < area.height(); ++i) {
+    for (int j = 0; j < area.width(); ++j) {
+      if (j < damage.width() && i < damage.height())
+        EXPECT_EQ(SK_ColorWHITE, bitmap.getColor(j, i));
+      else
+        EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(j, i));
+    }
+  }
+}
diff --git a/content/browser/aura/software_output_device_win.cc b/content/browser/aura/software_output_device_win.cc
index f8d6d9b..20672c9 100644
--- a/content/browser/aura/software_output_device_win.cc
+++ b/content/browser/aura/software_output_device_win.cc
@@ -22,7 +22,8 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   LONG style = GetWindowLong(hwnd_, GWL_EXSTYLE);
-  is_hwnd_composited_ = !!(style & WS_EX_COMPOSITED);
+  is_hwnd_composited_ =
+      !!(style & WS_EX_COMPOSITED) || !!(style & WS_EX_LAYERED);
 }
 
 SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index f8c8a1c..2019ce6 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -345,6 +345,29 @@
   }
 #endif
 
+  // Due to bugs in GLib we need to initialize GLib/GTK before we start threads;
+  // see crbug.com/309093. Sandbox setup spawns sub-processes and a thread
+  // running waitpid().
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  // g_type_init will be deprecated in 2.36. 2.35 is the development
+  // version for 2.36, hence do not call g_type_init starting 2.35.
+  // http://developer.gnome.org/gobject/unstable/gobject-Type-Information.html#g-type-init
+#if !GLIB_CHECK_VERSION(2, 35, 0)
+  // GLib type system initialization. Needed at least for gconf,
+  // used in net/proxy/proxy_config_service_linux.cc. Most likely
+  // this is superfluous as gtk_init() ought to do this. It's
+  // definitely harmless, so retained as a reminder of this
+  // requirement for gconf.
+  g_type_init();
+#endif
+
+#if !defined(USE_AURA)
+  gfx::GtkInitFromCommandLine(parsed_command_line_);
+#endif
+
+  SetUpGLibLogHandler();
+#endif
+
   if (parts_)
     parts_->PreEarlyInitialization();
 
@@ -853,7 +876,8 @@
   // it.
   {
     TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:GPUChannelFactory");
-    BrowserGpuChannelHostFactory::Terminate();
+    if (BrowserGpuChannelHostFactory::instance())
+      BrowserGpuChannelHostFactory::Terminate();
   }
 
   // Must happen after the I/O thread is shutdown since this class lives on the
@@ -910,9 +934,26 @@
 #if !defined(OS_IOS)
   HistogramSynchronizer::GetInstance();
 
-  BrowserGpuChannelHostFactory::Initialize();
+  // Initialize the GpuDataManager before we set up the MessageLoops because
+  // otherwise we'll trigger the assertion about doing IO on the UI thread.
+  GpuDataManagerImpl::GetInstance()->Initialize();
+
+  bool always_uses_gpu = IsForceCompositingModeEnabled();
+  bool established_gpu_channel = false;
+#if defined(USE_AURA) || defined(OS_ANDROID)
+  established_gpu_channel =
+      !parsed_command_line_.HasSwitch(switches::kDisableGpuProcessPrelaunch) ||
+      parsed_command_line_.HasSwitch(switches::kSingleProcess) ||
+      parsed_command_line_.HasSwitch(switches::kInProcessGPU);
 #if defined(USE_AURA)
+  if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
+    established_gpu_channel = always_uses_gpu = false;
+  }
+  BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
   ImageTransportFactory::Initialize();
+#elif defined(OS_ANDROID)
+  BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
+#endif
 #endif
 
 #if defined(OS_LINUX)
@@ -935,10 +976,6 @@
     media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
   }
 
-  // Initialize the GpuDataManager before we set up the MessageLoops because
-  // otherwise we'll trigger the assertion about doing IO on the UI thread.
-  GpuDataManagerImpl::GetInstance()->Initialize();
-
   {
     TRACE_EVENT0("startup",
       "BrowserMainLoop::BrowserThreadsStarted:InitSpeechRecognition");
@@ -969,12 +1006,8 @@
   // When running the GPU thread in-process, avoid optimistically starting it
   // since creating the GPU thread races against creation of the one-and-only
   // ChildProcess instance which is created by the renderer thread.
-  bool always_uses_gpu = IsForceCompositingModeEnabled();
-#if defined(USE_AURA)
-  if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
-    always_uses_gpu = false;
-#endif
   if (GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL) &&
+      !established_gpu_channel &&
       always_uses_gpu &&
       !parsed_command_line_.HasSwitch(switches::kDisableGpuProcessPrelaunch) &&
       !parsed_command_line_.HasSwitch(switches::kSingleProcess) &&
@@ -998,25 +1031,7 @@
   // are no #else branches on any #ifs.
   // TODO(stevenjb): Move platform specific code into platform specific Parts
   // (Need to add InitializeToolkit stage to BrowserParts).
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
-  // g_type_init will be deprecated in 2.36. 2.35 is the development
-  // version for 2.36, hence do not call g_type_init starting 2.35.
-  // http://developer.gnome.org/gobject/unstable/gobject-Type-Information.html#g-type-init
-#if !GLIB_CHECK_VERSION(2, 35, 0)
-  // Glib type system initialization. Needed at least for gconf,
-  // used in net/proxy/proxy_config_service_linux.cc. Most likely
-  // this is superfluous as gtk_init() ought to do this. It's
-  // definitely harmless, so retained as a reminder of this
-  // requirement for gconf.
-  g_type_init();
-#endif
-
-#if !defined(USE_AURA)
-  gfx::GtkInitFromCommandLine(parsed_command_line_);
-#endif
-
-  SetUpGLibLogHandler();
-#endif
+  // See also GTK setup in EarlyInitialization, above, and associated comments.
 
 #if defined(TOOLKIT_GTK)
   // It is important for this to happen before the first run dialog, as it
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 1aab2e0..b8f7e24 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -10,7 +10,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
-#include "content/browser/browser_plugin/browser_plugin_guest_helper.h"
 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
 #include "content/browser/browser_thread_impl.h"
@@ -557,9 +556,6 @@
       static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
   new_view->OnGuestInitialized(embedder_web_contents->GetView());
 
-  // |render_view_host| manages the ownership of this BrowserPluginGuestHelper.
-  new BrowserPluginGuestHelper(this, GetWebContents()->GetRenderViewHost());
-
   RendererPreferences* renderer_prefs =
       GetWebContents()->GetMutableRendererPrefs();
   std::string guest_user_agent_override = renderer_prefs->user_agent_override;
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index 552874e..710a735 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -6,12 +6,9 @@
 // renderer channel. A BrowserPlugin (a WebPlugin) is on the embedder
 // renderer side of browser <--> embedder renderer communication.
 //
-// BrowserPluginGuest lives on the UI thread of the browser process. It has a
-// helper, BrowserPluginGuestHelper, which is a RenderViewHostObserver. The
-// helper object intercepts messages (ViewHostMsg_*) directed at the browser
-// process and redirects them to this class. Any messages about the guest render
-// process that the embedder might be interested in receiving should be listened
-// for here.
+// BrowserPluginGuest lives on the UI thread of the browser process. Any
+// messages about the guest render process that the embedder might be interested
+// in receiving should be listened for here.
 //
 // BrowserPluginGuest is a WebContentsDelegate and WebContentsObserver for the
 // guest WebContents. BrowserPluginGuest operates under the assumption that the
@@ -33,7 +30,6 @@
 #include "content/port/common/input_event_ack_state.h"
 #include "content/public/browser/browser_plugin_guest_delegate.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/browser_plugin_permission_type.h"
diff --git a/content/browser/browser_plugin/browser_plugin_guest_helper.cc b/content/browser/browser_plugin/browser_plugin_guest_helper.cc
deleted file mode 100644
index ee18b6e..0000000
--- a/content/browser/browser_plugin/browser_plugin_guest_helper.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 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/browser_plugin/browser_plugin_guest_helper.h"
-
-#include "content/browser/browser_plugin/browser_plugin_guest.h"
-#include "content/common/drag_messages.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/render_view_host.h"
-
-namespace content {
-
-BrowserPluginGuestHelper::BrowserPluginGuestHelper(
-    BrowserPluginGuest* guest,
-    RenderViewHost* render_view_host)
-    : RenderViewHostObserver(render_view_host),
-      guest_(guest) {
-}
-
-BrowserPluginGuestHelper::~BrowserPluginGuestHelper() {
-}
-
-bool BrowserPluginGuestHelper::OnMessageReceived(
-    const IPC::Message& message) {
-  if (ShouldForwardToBrowserPluginGuest(message))
-    return guest_->OnMessageReceived(message);
-  return false;
-}
-
-// static
-bool BrowserPluginGuestHelper::ShouldForwardToBrowserPluginGuest(
-    const IPC::Message& message) {
-  switch (message.type()) {
-    case DragHostMsg_StartDragging::ID:
-    case DragHostMsg_TargetDrop_ACK::ID:
-    case ViewHostMsg_HasTouchEventHandlers::ID:
-    case ViewHostMsg_SetCursor::ID:
- #if defined(OS_MACOSX)
-    case ViewHostMsg_ShowPopup::ID:
- #endif
-    case ViewHostMsg_ShowWidget::ID:
-    case ViewHostMsg_TakeFocus::ID:
-    case ViewHostMsg_UpdateFrameName::ID:
-    case ViewHostMsg_UpdateRect::ID:
-    case ViewHostMsg_LockMouse::ID:
-    case ViewHostMsg_UnlockMouse::ID:
-      return true;
-    default:
-      break;
-  }
-  return false;
-}
-
-}  // namespace content
diff --git a/content/browser/browser_plugin/browser_plugin_guest_helper.h b/content/browser/browser_plugin/browser_plugin_guest_helper.h
deleted file mode 100644
index dfe2e32..0000000
--- a/content/browser/browser_plugin/browser_plugin_guest_helper.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_HELPER_H_
-#define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_HELPER_H_
-
-#include "content/port/common/input_event_ack_state.h"
-#include "content/public/browser/render_view_host_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "third_party/WebKit/public/web/WebDragOperation.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-
-class WebCursor;
-#if defined(OS_MACOSX)
-struct ViewHostMsg_ShowPopup_Params;
-#endif
-struct ViewHostMsg_UpdateRect_Params;
-
-namespace gfx {
-class Size;
-}
-
-namespace content {
-class BrowserPluginGuest;
-class RenderViewHost;
-
-// Helper for BrowserPluginGuest.
-//
-// The purpose of this class is to intercept messages from the guest RenderView
-// before they are handled by the standard message handlers in the browser
-// process. This permits overriding standard behavior with BrowserPlugin-
-// specific behavior.
-//
-// The lifetime of this class is managed by the associated RenderViewHost. A
-// BrowserPluginGuestHelper is created whenever a BrowserPluginGuest is created.
-class BrowserPluginGuestHelper : public RenderViewHostObserver {
- public:
-  BrowserPluginGuestHelper(BrowserPluginGuest* guest,
-                           RenderViewHost* render_view_host);
-  virtual ~BrowserPluginGuestHelper();
-
- protected:
-  // RenderViewHostObserver implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
-  // Returns whether a message should be forward to the helper's associated
-  // BrowserPluginGuest.
-  static bool ShouldForwardToBrowserPluginGuest(const IPC::Message& message);
-
-  BrowserPluginGuest* guest_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserPluginGuestHelper);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_HELPER_H_
diff --git a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
index ee3c519..4906415 100644
--- a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
+++ b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
@@ -21,8 +21,8 @@
 #include "content/common/view_messages.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/drop_data.h"
 #include "content/public/common/url_constants.h"
@@ -179,16 +179,15 @@
 
 // A transparent observer that can be used to verify that a RenderViewHost
 // received a specific message.
-class RenderViewHostMessageObserver : public RenderViewHostObserver {
+class MessageObserver : public WebContentsObserver {
  public:
-  RenderViewHostMessageObserver(RenderViewHost* host,
-                                uint32 message_id)
-      : RenderViewHostObserver(host),
+  MessageObserver(WebContents* web_contents, uint32 message_id)
+      : WebContentsObserver(web_contents),
         message_id_(message_id),
         message_received_(false) {
   }
 
-  virtual ~RenderViewHostMessageObserver() {}
+  virtual ~MessageObserver() {}
 
   void WaitUntilMessageReceived() {
     if (message_received_)
@@ -216,7 +215,7 @@
   uint32 message_id_;
   bool message_received_;
 
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostMessageObserver);
+  DISALLOW_COPY_AND_ASSIGN(MessageObserver);
 };
 
 class BrowserPluginHostTest : public ContentBrowserTest {
@@ -519,8 +518,8 @@
 
   // Install the touch handler in the guest. This should cause the embedder to
   // start listening for touch events too.
-  RenderViewHostMessageObserver observer(rvh,
-      ViewHostMsg_HasTouchEventHandlers::ID);
+  MessageObserver observer(test_embedder()->web_contents(),
+                           ViewHostMsg_HasTouchEventHandlers::ID);
   ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(),
                         "InstallTouchHandler();");
   observer.WaitUntilMessageReceived();
diff --git a/content/browser/browser_url_handler_impl.cc b/content/browser/browser_url_handler_impl.cc
index e642e1f..9a73afa 100644
--- a/content/browser/browser_url_handler_impl.cc
+++ b/content/browser/browser_url_handler_impl.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/string_util.h"
-#include "content/browser/web_contents/debug_urls.h"
+#include "content/browser/frame_host/debug_urls.h"
 #include "content/browser/webui/web_ui_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_switches.h"
@@ -19,7 +19,7 @@
 static bool HandleViewSource(GURL* url, BrowserContext* browser_context) {
   if (url->SchemeIs(kViewSourceScheme)) {
     // Load the inner URL instead.
-    *url = GURL(url->path());
+    *url = GURL(url->GetContent());
 
     // Bug 26129: limit view-source to view the content and not any
     // other kind of 'active' url scheme like 'javascript' or 'data'.
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 5e069c4..3fc6e0a 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -121,19 +121,18 @@
   // Grant certain permissions to a file.
   void GrantPermissionsForFileSystem(const std::string& filesystem_id,
                                      int permissions) {
-    if (filesystem_permissions_.find(filesystem_id) ==
-        filesystem_permissions_.end())
+    if (!ContainsKey(filesystem_permissions_, filesystem_id))
       fileapi::IsolatedContext::GetInstance()->AddReference(filesystem_id);
     filesystem_permissions_[filesystem_id] |= permissions;
   }
 
   bool HasPermissionsForFileSystem(const std::string& filesystem_id,
                                    int permissions) {
-    if (filesystem_permissions_.find(filesystem_id) ==
-        filesystem_permissions_.end())
+    FileSystemMap::const_iterator it =
+        filesystem_permissions_.find(filesystem_id);
+    if (it == filesystem_permissions_.end())
       return false;
-    return (filesystem_permissions_[filesystem_id] & permissions) ==
-        permissions;
+    return (it->second & permissions) == permissions;
   }
 
   void GrantBindings(int bindings) {
@@ -164,7 +163,7 @@
     if (url.SchemeIs(chrome::kFileScheme)) {
       base::FilePath path;
       if (net::FileURLToFilePath(url, &path))
-        return request_file_set_.find(path) != request_file_set_.end();
+        return ContainsKey(request_file_set_, path);
     }
 
     return false;  // Unmentioned schemes are disallowed.
@@ -178,15 +177,16 @@
     base::FilePath last_path;
     int skip = 0;
     while (current_path != last_path) {
-      base::FilePath base_name =  current_path.BaseName();
+      base::FilePath base_name = current_path.BaseName();
       if (base_name.value() == base::FilePath::kParentDirectory) {
         ++skip;
       } else if (skip > 0) {
         if (base_name.value() != base::FilePath::kCurrentDirectory)
           --skip;
       } else {
-        if (file_permissions_.find(current_path) != file_permissions_.end())
-          return (file_permissions_[current_path] & permissions) == permissions;
+        FileMap::const_iterator it = file_permissions_.find(current_path);
+        if (it != file_permissions_.end())
+          return (it->second & permissions) == permissions;
       }
       last_path = current_path;
       current_path = current_path.DirName();
@@ -333,19 +333,21 @@
 
 void ChildProcessSecurityPolicyImpl::Remove(int child_id) {
   base::AutoLock lock(lock_);
-  if (!security_state_.count(child_id))
+  SecurityStateMap::iterator it = security_state_.find(child_id);
+  if (it == security_state_.end())
     return;  // May be called multiple times.
 
-  delete security_state_[child_id];
-  security_state_.erase(child_id);
+  delete it->second;
+  security_state_.erase(it);
   worker_map_.erase(child_id);
 }
 
 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme(
     const std::string& scheme) {
   base::AutoLock lock(lock_);
-  DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once.";
-  DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not pseudo.";
+  DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) << "Add schemes at most once.";
+  DCHECK_EQ(0U, pseudo_schemes_.count(scheme))
+      << "Web-safe implies not pseudo.";
 
   web_safe_schemes_.insert(scheme);
 }
@@ -354,15 +356,15 @@
     const std::string& scheme) {
   base::AutoLock lock(lock_);
 
-  return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end());
+  return ContainsKey(web_safe_schemes_, scheme);
 }
 
 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme(
     const std::string& scheme) {
   base::AutoLock lock(lock_);
-  DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once.";
-  DCHECK(web_safe_schemes_.count(scheme) == 0) <<
-      "Pseudo implies not web-safe.";
+  DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once.";
+  DCHECK_EQ(0U, web_safe_schemes_.count(scheme))
+      << "Pseudo implies not web-safe.";
 
   pseudo_schemes_.insert(scheme);
 }
@@ -371,7 +373,7 @@
     const std::string& scheme) {
   base::AutoLock lock(lock_);
 
-  return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end());
+  return ContainsKey(pseudo_schemes_, scheme);
 }
 
 void ChildProcessSecurityPolicyImpl::GrantRequestURL(
@@ -391,7 +393,7 @@
       //   view-source:http://www.google.com/a
       // In order to request these URLs, the child_id needs to be able to
       // request the embedded URL.
-      GrantRequestURL(child_id, GURL(url.path()));
+      GrantRequestURL(child_id, GURL(url.GetContent()));
     }
 
     return;  // Can't grant the capability to request pseudo schemes.
@@ -572,7 +574,7 @@
     if (url.SchemeIs(kViewSourceScheme)) {
       // A view-source URL is allowed if the child process is permitted to
       // request the embedded URL. Careful to avoid pointless recursion.
-      GURL child_url(url.path());
+      GURL child_url(url.GetContent());
       if (child_url.SchemeIs(kViewSourceScheme) &&
           url.SchemeIs(kViewSourceScheme))
           return false;
@@ -641,6 +643,12 @@
                                      DELETE_FILE_GRANT);
 }
 
+void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFileSystem(
+    int child_id, const std::string& filesystem_id) {
+  GrantPermissionsForFileSystem(
+      child_id, filesystem_id, CREATE_READ_WRITE_FILE_GRANT);
+}
+
 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile(
     int child_id, const base::FilePath& file, int permissions) {
   base::AutoLock lock(lock_);
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index 646b3e6..7f0ee78 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -75,6 +75,10 @@
       int child_id,
       const std::string& filesystem_id) OVERRIDE;
 
+  void GrantCreateReadWriteFileSystem(
+      int child_id,
+      const std::string& filesystem_id);
+
   // Pseudo schemes are treated differently than other schemes because they
   // cannot be requested like normal URLs.  There is no mechanism for revoking
   // pseudo schemes.
diff --git a/content/browser/device_monitor_mac.h b/content/browser/device_monitor_mac.h
index bab522f..6def493 100644
--- a/content/browser/device_monitor_mac.h
+++ b/content/browser/device_monitor_mac.h
@@ -8,19 +8,29 @@
 #include "base/basictypes.h"
 #include "base/system_monitor/system_monitor.h"
 
+namespace {
+class DeviceMonitorMacImpl;
+}
+
 namespace content {
 
+// Class to track audio/video devices removal or addition via callback to
+// base::SystemMonitor ProcessDevicesChanged(). A single object of this class
+// is created from the browser main process and lives as long as this one.
 class DeviceMonitorMac {
  public:
   DeviceMonitorMac();
   ~DeviceMonitorMac();
 
- private:
-  // Forward the notifications to system monitor.
+  // Method called by the internal DeviceMonitorMacImpl object
+  // |device_monitor_impl_| when a device of type |type| has been added to or
+  // removed from the system. This code executes in the notification thread
+  // (QTKit or AVFoundation).
   void NotifyDeviceChanged(base::SystemMonitor::DeviceType type);
 
-  class QTMonitorImpl;
-  scoped_ptr<DeviceMonitorMac::QTMonitorImpl> qt_monitor_;
+ private:
+  scoped_ptr<DeviceMonitorMacImpl> device_monitor_impl_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMac);
 };
 
diff --git a/content/browser/device_monitor_mac.mm b/content/browser/device_monitor_mac.mm
index 7b12e91..abda079 100644
--- a/content/browser/device_monitor_mac.mm
+++ b/content/browser/device_monitor_mac.mm
@@ -7,97 +7,248 @@
 #import <QTKit/QTKit.h>
 
 #include "base/logging.h"
+#import "media/video/capture/mac/avfoundation_glue.h"
 
-namespace content {
+namespace {
 
-class DeviceMonitorMac::QTMonitorImpl {
+// This class is used to keep track of system devices names and their types.
+class DeviceInfo {
  public:
-  explicit QTMonitorImpl(DeviceMonitorMac* monitor);
-  virtual ~QTMonitorImpl() {}
+  enum DeviceType {
+    kAudio,
+    kVideo,
+    kMuxed,
+    kUnknown
+  };
 
-  void Start();
-  void Stop();
+  DeviceInfo(std::string unique_id, DeviceType type)
+      : unique_id_(unique_id), type_(type) {}
+
+  // Operator== is needed here to use this class in a std::find. A given
+  // |unique_id_| always has the same |type_| so for comparison purposes the
+  // latter can be safely ignored.
+  bool operator==(const DeviceInfo& device) const {
+    return unique_id_ == device.unique_id_;
+  }
+
+  const std::string& unique_id() const { return unique_id_; }
+  DeviceType type() const { return type_; }
 
  private:
-  void OnDeviceChanged();
+  std::string unique_id_;
+  DeviceType type_;
+  // Allow generated copy constructor and assignment.
+};
 
-  DeviceMonitorMac* monitor_;
-  int number_audio_devices_;
-  int number_video_devices_;
+// Base abstract class used by DeviceMonitorMac to interact with either a QTKit
+// or an AVFoundation implementation of events and notifications.
+class DeviceMonitorMacImpl {
+ public:
+  explicit DeviceMonitorMacImpl(content::DeviceMonitorMac* monitor)
+      : monitor_(monitor),
+        cached_devices_(),
+        device_arrival_(nil),
+        device_removal_(nil) {
+    DCHECK(monitor);
+  }
+  virtual ~DeviceMonitorMacImpl() {}
+
+  virtual void OnDeviceChanged() = 0;
+
+  // Method called by the default notification center when a device is removed
+  // or added to the system. It will compare the |cached_devices_| with the
+  // current situation, update it, and, if there's an update, signal to
+  // |monitor_| with the appropriate device type.
+  void ConsolidateDevicesListAndNotify(
+      const std::vector<DeviceInfo>& snapshot_devices);
+
+ protected:
+  content::DeviceMonitorMac* monitor_;
+  std::vector<DeviceInfo> cached_devices_;
+
+  // Handles to NSNotificationCenter block observers.
   id device_arrival_;
   id device_removal_;
 
-  DISALLOW_COPY_AND_ASSIGN(QTMonitorImpl);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl);
 };
 
-DeviceMonitorMac::QTMonitorImpl::QTMonitorImpl(DeviceMonitorMac* monitor)
-    : monitor_(monitor),
-      number_audio_devices_(0),
-      number_video_devices_(0),
-      device_arrival_(nil),
-      device_removal_(nil) {
-  DCHECK(monitor);
+void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
+    const std::vector<DeviceInfo>& snapshot_devices) {
+  bool video_device_added = false;
+  bool audio_device_added = false;
+  bool video_device_removed = false;
+  bool audio_device_removed = false;
+
+  // Compare the current system devices snapshot with the ones cached to detect
+  // additions, present in the former but not in the latter. If we find a device
+  // in snapshot_devices entry also present in cached_devices, we remove it from
+  // the latter vector.
+  std::vector<DeviceInfo>::const_iterator it;
+  for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
+    std::vector<DeviceInfo>::iterator cached_devices_iterator =
+        std::find(cached_devices_.begin(), cached_devices_.end(), *it);
+    if (cached_devices_iterator == cached_devices_.end()) {
+      video_device_added |= ((it->type() == DeviceInfo::kVideo) ||
+                             (it->type() == DeviceInfo::kMuxed));
+      audio_device_added |= ((it->type() == DeviceInfo::kAudio) ||
+                             (it->type() == DeviceInfo::kMuxed));
+      DVLOG(1) << "Device has been added, id: " << it->unique_id();
+    } else {
+      cached_devices_.erase(cached_devices_iterator);
+    }
+  }
+  // All the remaining entries in cached_devices are removed devices.
+  for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
+    video_device_removed |= ((it->type() == DeviceInfo::kVideo) ||
+                             (it->type() == DeviceInfo::kMuxed));
+    audio_device_removed |= ((it->type() == DeviceInfo::kAudio) ||
+                             (it->type() == DeviceInfo::kMuxed));
+    DVLOG(1) << "Device has been removed, id: " << it->unique_id();
+  }
+  // Update the cached devices with the current system snapshot.
+  cached_devices_ = snapshot_devices;
+
+  if (video_device_added || video_device_removed)
+    monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
+  if (audio_device_added || audio_device_removed)
+    monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
 }
 
-void DeviceMonitorMac::QTMonitorImpl::Start() {
+class QTKitMonitorImpl : public DeviceMonitorMacImpl {
+ public:
+  explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
+  virtual ~QTKitMonitorImpl();
+
+  virtual void OnDeviceChanged() OVERRIDE;
+};
+
+QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
+    : DeviceMonitorMacImpl(monitor) {
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   device_arrival_ =
-    [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
-                    object:nil
-                     queue:nil
-                usingBlock:^(NSNotification* notification) {
-                    OnDeviceChanged();}];
+      [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      OnDeviceChanged();
+                  }];
 
   device_removal_ =
       [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnDeviceChanged();}];
+                      OnDeviceChanged();
+                  }];
 }
 
-void DeviceMonitorMac::QTMonitorImpl::Stop() {
-  if (!monitor_)
-    return;
-
+QTKitMonitorImpl::~QTKitMonitorImpl() {
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:device_arrival_];
   [nc removeObserver:device_removal_];
 }
 
-void DeviceMonitorMac::QTMonitorImpl::OnDeviceChanged() {
+void QTKitMonitorImpl::OnDeviceChanged() {
+  std::vector<DeviceInfo> snapshot_devices;
+
   NSArray* devices = [QTCaptureDevice inputDevices];
-  int number_video_devices = 0;
-  int number_audio_devices = 0;
   for (QTCaptureDevice* device in devices) {
-    if ([device hasMediaType:QTMediaTypeVideo] ||
-        [device hasMediaType:QTMediaTypeMuxed])
-      ++number_video_devices;
+    DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
+    if ([device hasMediaType:QTMediaTypeVideo])
+      device_type = DeviceInfo::kVideo;
+    else if ([device hasMediaType:QTMediaTypeMuxed])
+      device_type = DeviceInfo::kMuxed;
+    else if ([device hasMediaType:QTMediaTypeSound])
+      device_type = DeviceInfo::kAudio;
 
-    if ([device hasMediaType:QTMediaTypeSound] ||
-        [device hasMediaType:QTMediaTypeMuxed])
-      ++number_audio_devices;
+    snapshot_devices.push_back(
+        DeviceInfo([[device uniqueID] UTF8String], device_type));
   }
 
-  if (number_video_devices_ != number_video_devices) {
-    number_video_devices_ = number_video_devices;
-    monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
-  }
-
-  if (number_audio_devices_ != number_audio_devices) {
-    number_audio_devices_ = number_audio_devices;
-    monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
-  }
+  ConsolidateDevicesListAndNotify(snapshot_devices);
 }
 
+class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
+ public:
+  explicit AVFoundationMonitorImpl(content::DeviceMonitorMac* monitor);
+  virtual ~AVFoundationMonitorImpl();
+
+  virtual void OnDeviceChanged() OVERRIDE;
+};
+
+AVFoundationMonitorImpl::AVFoundationMonitorImpl(
+    content::DeviceMonitorMac* monitor)
+    : DeviceMonitorMacImpl(monitor) {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+
+  device_arrival_ =
+      [nc addObserverForName:AVFoundationGlue::
+          AVCaptureDeviceWasConnectedNotification()
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      OnDeviceChanged();
+                  }];
+  device_removal_ =
+      [nc addObserverForName:AVFoundationGlue::
+          AVCaptureDeviceWasDisconnectedNotification()
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      OnDeviceChanged();
+                  }];
+}
+
+AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  [nc removeObserver:device_arrival_];
+  [nc removeObserver:device_removal_];
+}
+
+void AVFoundationMonitorImpl::OnDeviceChanged() {
+  std::vector<DeviceInfo> snapshot_devices;
+
+  NSArray* devices = [AVCaptureDeviceGlue devices];
+  for (CrAVCaptureDevice* device in devices) {
+    DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
+    if ([AVCaptureDeviceGlue hasMediaType:AVFoundationGlue::AVMediaTypeVideo()
+                         forCaptureDevice:device]) {
+      device_type = DeviceInfo::kVideo;
+    } else if ([AVCaptureDeviceGlue
+                   hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()
+               forCaptureDevice:device]) {
+      device_type = DeviceInfo::kMuxed;
+    } else if ([AVCaptureDeviceGlue
+                   hasMediaType:AVFoundationGlue::AVMediaTypeAudio()
+               forCaptureDevice:device]) {
+      device_type = DeviceInfo::kAudio;
+    }
+    snapshot_devices.push_back(DeviceInfo(
+        [[AVCaptureDeviceGlue uniqueID:device] UTF8String], device_type));
+  }
+
+  ConsolidateDevicesListAndNotify(snapshot_devices);
+}
+
+}  // namespace
+
+namespace content {
+
 DeviceMonitorMac::DeviceMonitorMac() {
-  qt_monitor_.reset(new QTMonitorImpl(this));
-  qt_monitor_->Start();
+  if (AVFoundationGlue::IsAVFoundationSupported()) {
+    DVLOG(1) << "Monitoring via AVFoundation";
+    device_monitor_impl_.reset(new AVFoundationMonitorImpl(this));
+  } else {
+    DVLOG(1) << "Monitoring via QTKit";
+    device_monitor_impl_.reset(new QTKitMonitorImpl(this));
+  }
+  // Force device enumeration to correctly list those already in the system.
+  device_monitor_impl_->OnDeviceChanged();
 }
 
-DeviceMonitorMac::~DeviceMonitorMac() {
-  qt_monitor_->Stop();
-}
+DeviceMonitorMac::~DeviceMonitorMac() {}
 
 void DeviceMonitorMac::NotifyDeviceChanged(
     base::SystemMonitor::DeviceType type) {
diff --git a/content/browser/device_orientation/data_fetcher_impl_android.cc b/content/browser/device_orientation/data_fetcher_impl_android.cc
index aa9a238..135dab1 100644
--- a/content/browser/device_orientation/data_fetcher_impl_android.cc
+++ b/content/browser/device_orientation/data_fetcher_impl_android.cc
@@ -185,6 +185,8 @@
 
 void DataFetcherImplAndroid::SetOrientationBufferReadyStatus(bool ready) {
   device_orientation_buffer_->seqlock.WriteBegin();
+  device_orientation_buffer_->data.absolute = ready;
+  device_orientation_buffer_->data.hasAbsolute = ready;
   device_orientation_buffer_->data.allAvailableSensorsAreActive = ready;
   device_orientation_buffer_->seqlock.WriteEnd();
   is_orientation_buffer_ready_ = ready;
diff --git a/content/browser/device_orientation/data_fetcher_impl_android.h b/content/browser/device_orientation/data_fetcher_impl_android.h
index 1dbc4c9..50a55be 100644
--- a/content/browser/device_orientation/data_fetcher_impl_android.h
+++ b/content/browser/device_orientation/data_fetcher_impl_android.h
@@ -17,13 +17,12 @@
 
 namespace content {
 
-// Android implementation of DeviceOrientation API.
-
-// Android's SensorManager has a push API, whereas Chrome wants to pull data.
-// To fit them together, we store incoming sensor events in a 1-element buffer.
-// SensorManager calls SetOrientation() which pushes a new value (discarding the
-// previous value if any). Chrome calls GetDeviceData() which reads the most
-// recent value. Repeated calls to GetDeviceData() will return the same value.
+// Android implementation of Device Orientation API.
+//
+// Android's SensorManager has a push API, so when Got*() methods are called
+// by the system the browser process puts the received data into a shared
+// memory buffer, which is read by the renderer processes.
+//
 
 // TODO(timvolodine): rename this class to SensorManagerAndroid.
 class CONTENT_EXPORT DataFetcherImplAndroid {
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc
index f56ea6b..cd6cf8f 100644
--- a/content/browser/devtools/devtools_http_handler_impl.cc
+++ b/content/browser/devtools/devtools_http_handler_impl.cc
@@ -32,6 +32,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
 #include "grit/devtools_resources_map.h"
+#include "net/base/escape.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/server/http_server_request_info.h"
@@ -424,9 +425,12 @@
   std::string path = info.path.substr(5);
 
   // Trim fragment and query
+  std::string query;
   size_t query_pos = path.find("?");
-  if (query_pos != std::string::npos)
+  if (query_pos != std::string::npos) {
+    query = path.substr(query_pos + 1);
     path = path.substr(0, query_pos);
+  }
 
   size_t fragment_pos = path.find("#");
   if (fragment_pos != std::string::npos)
@@ -463,7 +467,11 @@
   }
 
   if (command == "new") {
-    scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget());
+    GURL url(net::UnescapeURLComponent(
+        query, net::UnescapeRule::URL_SPECIAL_CHARS));
+    if (!url.is_valid())
+      url = GURL(kAboutBlankURL);
+    scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget(url));
     if (!target) {
       SendJson(connection_id,
                net::HTTP_INTERNAL_SERVER_ERROR,
@@ -738,7 +746,8 @@
   std::string id = target.GetId();
   dictionary->SetString(kTargetIdField, id);
   dictionary->SetString(kTargetTypeField, target.GetType());
-  dictionary->SetString(kTargetTitleField, target.GetTitle());
+  dictionary->SetString(kTargetTitleField,
+                        net::EscapeForHTML(target.GetTitle()));
   dictionary->SetString(kTargetDescriptionField, target.GetDescription());
 
   GURL url = target.GetUrl();
diff --git a/content/browser/devtools/devtools_http_handler_unittest.cc b/content/browser/devtools/devtools_http_handler_unittest.cc
index cc751f0..f3179f0 100644
--- a/content/browser/devtools/devtools_http_handler_unittest.cc
+++ b/content/browser/devtools/devtools_http_handler_unittest.cc
@@ -65,7 +65,7 @@
   virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE {
     return std::string();
   }
-  virtual scoped_ptr<DevToolsTarget> CreateNewTarget() OVERRIDE {
+  virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) OVERRIDE {
     return scoped_ptr<DevToolsTarget>();
   }
   virtual void EnumerateTargets(TargetCallback callback) OVERRIDE {
diff --git a/content/browser/devtools/render_view_devtools_agent_host.cc b/content/browser/devtools/render_view_devtools_agent_host.cc
index 9d0918e..7bee941 100644
--- a/content/browser/devtools/render_view_devtools_agent_host.cc
+++ b/content/browser/devtools/render_view_devtools_agent_host.cc
@@ -12,7 +12,6 @@
 #include "content/browser/devtools/devtools_protocol_constants.h"
 #include "content/browser/devtools/devtools_tracing_handler.h"
 #include "content/browser/devtools/renderer_overrides_handler.h"
-#include "content/browser/power_save_blocker_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
@@ -25,6 +24,7 @@
 #include "content/public/browser/render_widget_host_iterator.h"
 
 #if defined(OS_ANDROID)
+#include "content/browser/power_save_blocker_impl.h"
 #include "content/public/browser/render_widget_host_view.h"
 #endif
 
@@ -48,28 +48,6 @@
 
 }  // namespace
 
-class RenderViewDevToolsAgentHost::DevToolsAgentHostRvhObserver
-    : public RenderViewHostObserver {
- public:
-  DevToolsAgentHostRvhObserver(RenderViewHost* rvh,
-                               RenderViewDevToolsAgentHost* agent_host)
-      : RenderViewHostObserver(rvh),
-        agent_host_(agent_host) {
-  }
-  virtual ~DevToolsAgentHostRvhObserver() {}
-
-  // RenderViewHostObserver overrides.
-  virtual void RenderViewHostDestroyed(RenderViewHost* rvh) OVERRIDE {
-    agent_host_->RenderViewHostDestroyed(rvh);
-  }
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
-    return agent_host_->OnRvhMessageReceived(message);
-  }
- private:
-  RenderViewDevToolsAgentHost* agent_host_;
-  DISALLOW_COPY_AND_ASSIGN(DevToolsAgentHostRvhObserver);
-};
-
 // static
 scoped_refptr<DevToolsAgentHost>
 DevToolsAgentHost::GetOrCreateFor(RenderViewHost* rvh) {
@@ -152,9 +130,6 @@
   overrides_handler_->SetNotifier(notifier);
   tracing_handler_->SetNotifier(notifier);
   g_instances.Get().push_back(this);
-  RenderViewHostDelegate* delegate = render_view_host_->GetDelegate();
-  if (delegate && delegate->GetAsWebContents())
-    WebContentsObserver::Observe(delegate->GetAsWebContents());
   AddRef();  // Balanced in RenderViewHostDestroyed.
 }
 
@@ -201,12 +176,12 @@
   // ExtensionProcessManager no longer relies on this notification.
   DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true);
 
+#if defined(OS_ANDROID)
   power_save_blocker_.reset(
       static_cast<PowerSaveBlockerImpl*>(
           PowerSaveBlocker::Create(
               PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
               "DevTools").release()));
-#if defined(OS_ANDROID)
   if (render_view_host_->GetView()) {
     power_save_blocker_.get()->
         InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
@@ -215,7 +190,9 @@
 }
 
 void RenderViewDevToolsAgentHost::OnClientDetached() {
+#if defined(OS_ANDROID)
   power_save_blocker_.reset();
+#endif
   overrides_handler_->OnClientDetached();
   ClientDetachedFromRenderer();
 }
@@ -267,6 +244,17 @@
   ConnectRenderViewHost(dest_rvh);
 }
 
+void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
+  if (rvh != render_view_host_)
+    return;
+
+  DCHECK(render_view_host_);
+  scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
+  NotifyCloseListener();
+  ClearRenderViewHost();
+  Release();
+}
+
 void RenderViewDevToolsAgentHost::RenderProcessGone(
     base::TerminationStatus status) {
   switch(status) {
@@ -305,7 +293,9 @@
 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
   DCHECK(!render_view_host_);
   render_view_host_ = rvh;
-  rvh_observer_.reset(new DevToolsAgentHostRvhObserver(rvh, this));
+
+  WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
+
   registrar_.Add(
       this,
       content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
@@ -318,7 +308,6 @@
       this,
       content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
       content::Source<RenderWidgetHost>(render_view_host_));
-  rvh_observer_.reset(NULL);
   render_view_host_ = NULL;
 }
 
@@ -333,15 +322,6 @@
   ClearRenderViewHost();
 }
 
-void RenderViewDevToolsAgentHost::RenderViewHostDestroyed(
-    RenderViewHost* rvh) {
-  DCHECK(render_view_host_);
-  scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
-  NotifyCloseListener();
-  ClearRenderViewHost();
-  Release();
-}
-
 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
   scoped_refptr<DevToolsProtocol::Notification> notification =
       DevToolsProtocol::CreateNotification(
@@ -350,8 +330,11 @@
       DispatchOnInspectorFrontend(this, notification->Serialize());
 }
 
-bool RenderViewDevToolsAgentHost::OnRvhMessageReceived(
+bool RenderViewDevToolsAgentHost::OnMessageReceived(
     const IPC::Message& msg) {
+  if (!render_view_host_)
+    return false;
+
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
     IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
diff --git a/content/browser/devtools/render_view_devtools_agent_host.h b/content/browser/devtools/render_view_devtools_agent_host.h
index c775182..4313e2a 100644
--- a/content/browser/devtools/render_view_devtools_agent_host.h
+++ b/content/browser/devtools/render_view_devtools_agent_host.h
@@ -14,16 +14,18 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
 
 class DevToolsTracingHandler;
-class PowerSaveBlockerImpl;
 class RendererOverridesHandler;
 class RenderViewHost;
 
+#if defined(OS_ANDROID)
+class PowerSaveBlockerImpl;
+#endif
+
 class CONTENT_EXPORT RenderViewDevToolsAgentHost
     : public IPCDevToolsAgentHost,
       private WebContentsObserver,
@@ -38,7 +40,6 @@
 
  private:
   friend class DevToolsAgentHost;
-  class DevToolsAgentHostRvhObserver;
 
   virtual ~RenderViewDevToolsAgentHost();
 
@@ -55,8 +56,10 @@
 
   // WebContentsObserver overrides.
   virtual void AboutToNavigateRenderView(RenderViewHost* dest_rvh) OVERRIDE;
+  virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE;
   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
   virtual void DidAttachInterstitialPage() OVERRIDE;
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // NotificationObserver overrides:
   virtual void Observe(int type,
@@ -66,9 +69,7 @@
   void SetRenderViewHost(RenderViewHost* rvh);
   void ClearRenderViewHost();
 
-  void RenderViewHostDestroyed(RenderViewHost* rvh);
   void RenderViewCrashed();
-  bool OnRvhMessageReceived(const IPC::Message& message);
   void OnSwapCompositorFrame(const IPC::Message& message);
 
   void OnDispatchOnInspectorFrontend(const std::string& message);
@@ -79,10 +80,11 @@
   void ClientDetachedFromRenderer();
 
   RenderViewHost* render_view_host_;
-  scoped_ptr<DevToolsAgentHostRvhObserver> rvh_observer_;
   scoped_ptr<RendererOverridesHandler> overrides_handler_;
   scoped_ptr<DevToolsTracingHandler> tracing_handler_;
+#if defined(OS_ANDROID)
   scoped_ptr<PowerSaveBlockerImpl> power_save_blocker_;
+#endif
   std::string state_;
   NotificationRegistrar registrar_;
 
diff --git a/content/browser/devtools/renderer_overrides_handler.cc b/content/browser/devtools/renderer_overrides_handler.cc
index a48570d..8d0177b 100644
--- a/content/browser/devtools/renderer_overrides_handler.cc
+++ b/content/browser/devtools/renderer_overrides_handler.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/devtools/renderer_overrides_handler.h"
 
+#include <map>
 #include <string>
 
 #include "base/barrier_closure.h"
@@ -183,13 +184,16 @@
     return;
   }
 
+  RenderViewHost* host = agent_->GetRenderViewHost();
+  if (!host->GetView())
+    return;
+
   last_frame_time_ = base::TimeTicks::Now();
   std::string format;
   int quality = kDefaultScreenshotQuality;
   double scale = 1;
   ParseCaptureParameters(screencast_command_.get(), &format, &quality, &scale);
 
-  RenderViewHost* host = agent_->GetRenderViewHost();
   RenderWidgetHostViewPort* view_port =
       RenderWidgetHostViewPort::FromRWHV(host->GetView());
 
@@ -227,14 +231,13 @@
   }
 
   RenderViewHost* host = agent_->GetRenderViewHost();
-  if (host->GetView()) {
-    gfx::Rect view_bounds = host->GetView()->GetViewBounds();
-    float device_sf = last_compositor_frame_metadata_.device_scale_factor;
-    if (max_width > 0)
-      *scale = std::min(*scale, max_width / view_bounds.width() / device_sf);
-    if (max_height > 0)
-      *scale = std::min(*scale, max_height / view_bounds.height() / device_sf);
-  }
+  CHECK(host->GetView());
+  gfx::Rect view_bounds = host->GetView()->GetViewBounds();
+  float device_sf = last_compositor_frame_metadata_.device_scale_factor;
+  if (max_width > 0)
+    *scale = std::min(*scale, max_width / view_bounds.width() / device_sf);
+  if (max_height > 0)
+    *scale = std::min(*scale, max_height / view_bounds.height() / device_sf);
 
   if (format->empty())
     *format = kPng;
@@ -422,12 +425,15 @@
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageCaptureScreenshot(
     scoped_refptr<DevToolsProtocol::Command> command) {
+  RenderViewHost* host = agent_->GetRenderViewHost();
+  if (!host->GetView())
+    return command->InternalErrorResponse("Unable to access the view");
+
   std::string format;
   int quality = kDefaultScreenshotQuality;
   double scale = 1;
   ParseCaptureParameters(command.get(), &format, &quality, &scale);
 
-  RenderViewHost* host = agent_->GetRenderViewHost();
   gfx::Rect view_bounds = host->GetView()->GetViewBounds();
   gfx::Size snapshot_size = gfx::ToFlooredSize(
       gfx::ScaleSize(view_bounds.size(), scale));
@@ -661,10 +667,11 @@
       return devtools::Page::Usage::kItemPersistent;
     case quota::kStorageTypeSyncable:
       return devtools::Page::Usage::kItemSyncable;
-    default:
+    case quota::kStorageTypeQuotaNotManaged:
+    case quota::kStorageTypeUnknown:
       NOTREACHED();
-      return "";
   }
+  return "";
 }
 
 std::string GetQuotaClientName(quota::QuotaClient::ID id) {
@@ -698,23 +705,21 @@
   };
 
   static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
-
-  base::ListValue* storage_type_lists[kStorageTypeCount];
+  std::map<quota::StorageType, base::ListValue*> storage_type_lists;
 
   for (size_t i = 0; i != kStorageTypeCount; i++) {
     const quota::StorageType type = static_cast<quota::StorageType>(i);
-    storage_type_lists[i] = new base::ListValue;
-    usage->Set(GetStorageTypeName(type), storage_type_lists[i]);
+    if (type == quota::kStorageTypeQuotaNotManaged)
+      continue;
+    storage_type_lists[type] = new base::ListValue;
+    usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
   }
 
-  COMPILE_ASSERT(kStorageTypeCount == arraysize(storage_type_lists),
-      inconsistent_storage_type_list);
-
-  int kExpectedResults = 2 + arraysize(kQuotaClients) * kStorageTypeCount;
-
+  const int kExpectedResults =
+      2 + arraysize(kQuotaClients) * storage_type_lists.size();
   base::DictionaryValue* quota_raw_ptr = quota.get();
 
-  // Takes owneship on usage and quota.
+  // Takes ownership on usage and quota.
   base::Closure barrier = BarrierClosure(
       kExpectedResults,
       base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
@@ -736,16 +741,17 @@
                  barrier));
 
   for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
-    for (size_t j = 0; j != kStorageTypeCount; j++) {
-      const quota::StorageType type = static_cast<quota::StorageType>(j);
-      if (!quota_manager->IsTrackingHostUsage(type,
-                                              kQuotaClients[i])) {
+    std::map<quota::StorageType, base::ListValue*>::const_iterator iter;
+    for (iter = storage_type_lists.begin();
+         iter != storage_type_lists.end(); ++iter) {
+      const quota::StorageType type = (*iter).first;
+      if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
         barrier.Run();
         continue;
       }
-      quota_manager->GetHostUsage(host, type,
-          kQuotaClients[i],
-          base::Bind(&DidGetHostUsage, storage_type_lists[j],
+      quota_manager->GetHostUsage(
+          host, type, kQuotaClients[i],
+          base::Bind(&DidGetHostUsage, (*iter).second,
                      GetQuotaClientName(kQuotaClients[i]),
                      barrier));
     }
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index c5c3b36..36967c5 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -71,7 +71,7 @@
     // to do a re-POST without user consent, and currently don't have a good
     // plan on how to display the UI for that.
     DCHECK(params->prefer_cache());
-    DCHECK(params->method() == "POST");
+    DCHECK_EQ("POST", params->method());
     ScopedVector<net::UploadElementReader> element_readers;
     request->set_upload(make_scoped_ptr(
         new net::UploadDataStream(element_readers.Pass(), params->post_id())));
@@ -108,7 +108,7 @@
        iter != params->request_headers_end();
        ++iter) {
     request->SetExtraRequestHeaderByName(
-        iter->first, iter->second, false/*overwrite*/);
+        iter->first, iter->second, false /*overwrite*/);
   }
 
   scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
@@ -561,11 +561,9 @@
     return;
 
   uint32 download_id = download->GetId();
-  if (downloads_.find(download_id) == downloads_.end())
+  if (downloads_.erase(download_id) == 0)
     return;
-
   delete download;
-  downloads_.erase(download_id);
 }
 
 int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
@@ -605,7 +603,7 @@
   if (params->post_id() >= 0) {
     // Check this here so that the traceback is more useful.
     DCHECK(params->prefer_cache());
-    DCHECK(params->method() == "POST");
+    DCHECK_EQ("POST", params->method());
   }
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
       &BeginDownload, base::Passed(&params),
@@ -636,9 +634,10 @@
     DownloadDangerType danger_type,
     DownloadInterruptReason interrupt_reason,
     bool opened) {
-  DCHECK(!ContainsKey(downloads_, id));
-  if (ContainsKey(downloads_, id))
+  if (ContainsKey(downloads_, id)) {
+    NOTREACHED();
     return NULL;
+  }
   DownloadItemImpl* item = item_factory_->CreatePersistedItem(
       this,
       id,
@@ -680,7 +679,9 @@
     if (it->second->GetState() == DownloadItem::IN_PROGRESS &&
         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_URL &&
         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT &&
-        it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST) {
+        it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST &&
+        it->second->GetDangerType() !=
+            DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED) {
       ++count;
     }
   }
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 0865c04..aecded1 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -404,11 +404,17 @@
   MOCK_METHOD2(GetMediaRequestContextForStoragePartition,
                net::URLRequestContextGetter*(
                    const base::FilePath& partition_path, bool in_memory));
-  MOCK_METHOD4(RequestMIDISysExPermission,
+  MOCK_METHOD5(RequestMIDISysExPermission,
                void(int render_process_id,
                     int render_view_id,
+                    int bridge_id,
                     const GURL& requesting_frame,
                     const MIDISysExPermissionCallback& callback));
+  MOCK_METHOD4(CancelMIDISysExPermissionRequest,
+               void(int render_process_id,
+                    int render_view_id,
+                    int bridge_id,
+                    const GURL& requesting_frame));
   MOCK_METHOD0(GetResourceContext, ResourceContext*());
   MOCK_METHOD0(GetDownloadManagerDelegate, DownloadManagerDelegate*());
   MOCK_METHOD0(GetGeolocationPermissionContext,
diff --git a/content/browser/fileapi/file_system_context_unittest.cc b/content/browser/fileapi/file_system_context_unittest.cc
index 18c6122..63365dc 100644
--- a/content/browser/fileapi/file_system_context_unittest.cc
+++ b/content/browser/fileapi/file_system_context_unittest.cc
@@ -324,6 +324,44 @@
       kIsolatedFileSystemID);
 }
 
+TEST_F(FileSystemContextTest, CanServeURLRequest) {
+  scoped_refptr<ExternalMountPoints> external_mount_points(
+      ExternalMountPoints::CreateRefCounted());
+  scoped_refptr<FileSystemContext> context(
+      CreateFileSystemContextForTest(external_mount_points.get()));
+
+  // A request for a sandbox mount point should be served.
+  FileSystemURL cracked_url =
+      context->CrackURL(CreateRawFileSystemURL("persistent", "pers_mount"));
+  EXPECT_EQ(kFileSystemTypePersistent, cracked_url.mount_type());
+  EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
+
+  // A request for an isolated mount point should NOT be served.
+  std::string isolated_fs_name = "root";
+  std::string isolated_fs_id =
+      IsolatedContext::GetInstance()->RegisterFileSystemForPath(
+          kFileSystemTypeNativeLocal,
+          base::FilePath(DRIVE FPL("/test/isolated/root")),
+          &isolated_fs_name);
+  cracked_url = context->CrackURL(
+      CreateRawFileSystemURL("isolated", isolated_fs_id));
+  EXPECT_EQ(kFileSystemTypeIsolated, cracked_url.mount_type());
+  EXPECT_FALSE(context->CanServeURLRequest(cracked_url));
+
+  // A request for an external mount point should be served.
+  const std::string kExternalMountName = "ext_mount";
+  ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+      kExternalMountName, kFileSystemTypeDrive, base::FilePath()));
+  cracked_url = context->CrackURL(
+      CreateRawFileSystemURL("external", kExternalMountName));
+  EXPECT_EQ(kFileSystemTypeExternal, cracked_url.mount_type());
+  EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
+
+  ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+      kExternalMountName);
+  IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id);
+}
+
 }  // namespace
 
 }  // namespace fileapi
diff --git a/content/browser/fileapi/fileapi_message_filter.cc b/content/browser/fileapi/fileapi_message_filter.cc
index 5c1282c..99439b7 100644
--- a/content/browser/fileapi/fileapi_message_filter.cc
+++ b/content/browser/fileapi/fileapi_message_filter.cc
@@ -177,7 +177,6 @@
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
-    IPC_MESSAGE_HANDLER(FileSystemHostMsg_WriteDeprecated, OnWriteDeprecated)
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
     IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
@@ -206,12 +205,6 @@
     IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL,
                         OnRegisterPublicBlobURL)
     IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
-    IPC_MESSAGE_HANDLER(BlobHostMsg_DeprecatedRegisterBlobURL,
-                        OnDeprecatedRegisterBlobURL)
-    IPC_MESSAGE_HANDLER(BlobHostMsg_DeprecatedRevokeBlobURL,
-                        OnDeprecatedRevokeBlobURL)
-    IPC_MESSAGE_HANDLER(BlobHostMsg_DeprecatedCloneBlobURL,
-                        OnDeprecatedCloneBlobURL)
     IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
     IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
                         OnAppendBlobDataItemToStream)
@@ -417,16 +410,6 @@
                       this, request_id));
 }
 
-void FileAPIMessageFilter::OnWriteDeprecated(
-    int request_id,
-    const GURL& path,
-    const GURL& blob_url,
-    int64 offset) {
-  std::string uuid =
-      blob_storage_context_->context()->LookupUuidFromDeprecatedURL(blob_url);
-  OnWrite(request_id, path, uuid, offset);
-}
-
 void FileAPIMessageFilter::OnWrite(
     int request_id,
     const GURL& path,
@@ -704,23 +687,6 @@
   ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
 }
 
-void FileAPIMessageFilter::OnDeprecatedRegisterBlobURL(
-    const GURL& url, const std::string& uuid) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  blob_storage_host_->DeprecatedRegisterBlobURL(url, uuid);
-}
-
-void FileAPIMessageFilter::OnDeprecatedCloneBlobURL(
-    const GURL& url, const GURL& src_url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  blob_storage_host_->DeprecatedCloneBlobURL(url, src_url);
-}
-
-void FileAPIMessageFilter::OnDeprecatedRevokeBlobURL(const GURL& url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  blob_storage_host_->DeprecatedRevokeBlobURL(url);
-}
-
 void FileAPIMessageFilter::OnStartBuildingStream(
     const GURL& url, const std::string& content_type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/content/browser/fileapi/fileapi_message_filter.h b/content/browser/fileapi/fileapi_message_filter.h
index 91899b5..85e2ad2 100644
--- a/content/browser/fileapi/fileapi_message_filter.h
+++ b/content/browser/fileapi/fileapi_message_filter.h
@@ -116,11 +116,6 @@
                const GURL& path,
                const std::string& blob_uuid,
                int64 offset);
-  void OnWriteDeprecated(
-               int request_id,
-               const GURL& path,
-               const GURL& blob_url,
-               int64 offset);
   void OnTruncate(int request_id, const GURL& path, int64 length);
   void OnTouchFile(int request_id,
                    const GURL& path,
@@ -155,13 +150,6 @@
   void OnRegisterPublicBlobURL(const GURL& public_url, const std::string& uuid);
   void OnRevokePublicBlobURL(const GURL& public_url);
 
-  // Extra methods to establish a mapping from old-style blobURLs to uuids,
-  // and to clone them. These won't be here for long, just during a
-  // transition period. See crbug/174200
-  void OnDeprecatedRegisterBlobURL(const GURL& url, const std::string& uuid);
-  void OnDeprecatedCloneBlobURL(const GURL& url, const GURL& existing_url);
-  void OnDeprecatedRevokeBlobURL(const GURL& url);
-
   // Handlers for StreamHostMsg_ family messages.
   //
   // TODO(tyoshino): Consider renaming BlobData to more generic one as it's now
diff --git a/content/browser/fileapi/obfuscated_file_util_unittest.cc b/content/browser/fileapi/obfuscated_file_util_unittest.cc
index de4bce9..a32be5f 100644
--- a/content/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -2316,7 +2316,7 @@
       ObfuscatedFileUtil::CreateForTesting(
           NULL, data_dir_path(),
           base::MessageLoopProxy::current().get()));
-  file_util->InitOriginDatabase(true /*create*/);
+  file_util->InitOriginDatabase(GURL(), true /*create*/);
   ASSERT_TRUE(file_util->origin_database_ != NULL);
 
   // Callback to Drop DB is called while ObfuscatedFileUtilTest is still alive.
@@ -2335,7 +2335,7 @@
         ObfuscatedFileUtil::CreateForTesting(
             NULL, data_dir_path(),
             base::MessageLoopProxy::current().get()));
-    file_util->InitOriginDatabase(true /*create*/);
+    file_util->InitOriginDatabase(GURL(), true /*create*/);
     file_util->db_flush_delay_seconds_ = 0;
     file_util->MarkUsed();
   }
@@ -2397,7 +2397,10 @@
   {
     std::string origin_string =
         webkit_database::GetIdentifierFromOrigin(origin_);
-    SandboxIsolatedOriginDatabase database_old(origin_string, data_dir_path());
+    SandboxIsolatedOriginDatabase database_old(
+        origin_string, data_dir_path(),
+        base::FilePath(
+            SandboxIsolatedOriginDatabase::kObsoleteOriginDirectory));
     base::FilePath path;
     EXPECT_TRUE(database_old.GetPathForOrigin(origin_string, &path));
     EXPECT_FALSE(path.empty());
diff --git a/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc b/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
index 9aee406..a724688 100644
--- a/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
+++ b/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
@@ -28,13 +27,13 @@
 const FileSystemType kType = kFileSystemTypePluginPrivate;
 
 void DidOpenFileSystem(GURL* root_url_out,
-                       std::string* name_out,
+                       std::string* filesystem_id_out,
                        base::PlatformFileError* error_out,
                        const GURL& root_url,
-                       const std::string& name,
+                       const std::string& filesystem_id,
                        base::PlatformFileError error) {
   *root_url_out = root_url;
-  *name_out = name;
+  *filesystem_id_out = filesystem_id;
   *error_out = error;
 }
 
@@ -44,16 +43,8 @@
  protected:
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
-    backend_ = new PluginPrivateFileSystemBackend(
-        base::MessageLoopProxy::current().get(),
-        data_dir_.path(),
-        NULL /* special_storage_policy */,
-        CreateAllowFileAccessOptions());
-    ScopedVector<FileSystemBackend> additional_providers;
-    additional_providers.push_back(backend_);
-    context_ = CreateFileSystemContextWithAdditionalProvidersForTesting(
+    context_ = CreateFileSystemContextForTesting(
         NULL /* quota_manager_proxy */,
-        additional_providers.Pass(),
         data_dir_.path());
   }
 
@@ -65,30 +56,33 @@
         root.virtual_path().AppendASCII(relative));
   }
 
-  const base::FilePath& base_path() const { return backend_->base_path(); }
+  PluginPrivateFileSystemBackend* backend() const {
+    return context_->plugin_private_backend();
+  }
+
+  const base::FilePath& base_path() const { return backend()->base_path(); }
 
   base::ScopedTempDir data_dir_;
   base::MessageLoop message_loop_;
   scoped_refptr<FileSystemContext> context_;
-  PluginPrivateFileSystemBackend* backend_;  // Owned by context_.
 };
 
 TEST_F(PluginPrivateFileSystemBackendTest, OpenFileSystemBasic) {
   GURL root_url;
-  std::string name;
+  std::string filesystem_id;
   base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
 
-  backend_->OpenPrivateFileSystem(
+  backend()->OpenPrivateFileSystem(
       kOrigin, kType, kPlugin1, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-      base::Bind(&DidOpenFileSystem, &root_url, &name, &error));
+      base::Bind(&DidOpenFileSystem, &root_url, &filesystem_id, &error));
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
 
   // Run this again with FAIL_IF_NONEXISTENT to see if it succeeds.
   error = base::PLATFORM_FILE_ERROR_FAILED;
-  backend_->OpenPrivateFileSystem(
+  backend()->OpenPrivateFileSystem(
       kOrigin, kType, kPlugin1, OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
-      base::Bind(&DidOpenFileSystem, &root_url, &name, &error));
+      base::Bind(&DidOpenFileSystem, &root_url, &filesystem_id, &error));
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
 
@@ -105,20 +99,20 @@
 
 TEST_F(PluginPrivateFileSystemBackendTest, PluginIsolation) {
   GURL root_url1, root_url2;
-  std::string name1, name2;
+  std::string filesystem_id1, filesystem_id2;
 
   // Open filesystem for kPlugin1 and kPlugin2.
   base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
-  backend_->OpenPrivateFileSystem(
+  backend()->OpenPrivateFileSystem(
       kOrigin, kType, kPlugin1, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-      base::Bind(&DidOpenFileSystem, &root_url1, &name1, &error));
+      base::Bind(&DidOpenFileSystem, &root_url1, &filesystem_id1, &error));
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
 
   error = base::PLATFORM_FILE_ERROR_FAILED;
-  backend_->OpenPrivateFileSystem(
+  backend()->OpenPrivateFileSystem(
       kOrigin, kType, kPlugin2, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-      base::Bind(&DidOpenFileSystem, &root_url2, &name2, &error));
+      base::Bind(&DidOpenFileSystem, &root_url2, &filesystem_id2, &error));
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
 
diff --git a/content/browser/frame_host/DEPS b/content/browser/frame_host/DEPS
new file mode 100644
index 0000000..85fb015
--- /dev/null
+++ b/content/browser/frame_host/DEPS
@@ -0,0 +1,22 @@
+include_rules = [
+  # The frame_host files should only call upwards in the layering via the
+  # delegate interfaces.
+  "-content/browser/web_contents",
+  "-content/public/browser/web_contents.h",
+  "-content/public/browser/web_contents_delegate.h",
+  "-content/public/browser/web_contents_view.h",
+]
+
+specific_include_rules = {
+  ".*_(unit|browser)test\.cc": [
+    "+content/browser/web_contents",
+    "+content/public/browser/web_contents_delegate.h",
+  ],
+  ".*interstitial_page_impl\.cc": [
+    # TODO(nasko): This should be removed once we remove
+    # WebContentsObserver as the method of telling interstitial pages to
+    # clean themselves up.
+    "+content/browser/web_contents",
+    "+content/public/browser/web_contents_delegate.h",
+  ],
+}
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc
new file mode 100644
index 0000000..7cb11e8
--- /dev/null
+++ b/content/browser/frame_host/debug_urls.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 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/debug_urls.h"
+
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/ppapi_plugin_process_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/url_constants.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+void HandlePpapiFlashDebugURL(const GURL& url) {
+#if defined(ENABLE_PLUGINS)
+  bool crash = url == GURL(kChromeUIPpapiFlashCrashURL);
+
+  std::vector<PpapiPluginProcessHost*> hosts;
+  PpapiPluginProcessHost::FindByName(UTF8ToUTF16(kFlashPluginName), &hosts);
+  for (std::vector<PpapiPluginProcessHost*>::iterator iter = hosts.begin();
+       iter != hosts.end(); ++iter) {
+    if (crash)
+      (*iter)->Send(new PpapiMsg_Crash());
+    else
+      (*iter)->Send(new PpapiMsg_Hang());
+  }
+#endif
+}
+
+}  // namespace
+
+bool HandleDebugURL(const GURL& url, PageTransition transition) {
+  // Ensure that the user explicitly navigated to this URL.
+  if (!(transition & PAGE_TRANSITION_FROM_ADDRESS_BAR))
+    return false;
+
+  if (url.host() == kChromeUIBrowserCrashHost) {
+    // Induce an intentional crash in the browser process.
+    CHECK(false);
+    return true;
+  }
+
+  if (url == GURL(kChromeUIGpuCleanURL)) {
+    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
+    if (shim)
+      shim->SimulateRemoveAllContext();
+    return true;
+  }
+
+  if (url == GURL(kChromeUIGpuCrashURL)) {
+    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
+    if (shim)
+      shim->SimulateCrash();
+    return true;
+  }
+
+  if (url == GURL(kChromeUIGpuHangURL)) {
+    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
+    if (shim)
+      shim->SimulateHang();
+    return true;
+  }
+
+  if (url == GURL(kChromeUIPpapiFlashCrashURL) ||
+      url == GURL(kChromeUIPpapiFlashHangURL)) {
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                            base::Bind(&HandlePpapiFlashDebugURL, url));
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/debug_urls.h b/content/browser/frame_host/debug_urls.h
new file mode 100644
index 0000000..1985253
--- /dev/null
+++ b/content/browser/frame_host/debug_urls.h
@@ -0,0 +1,20 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_DEBUG_URLS_H_
+#define CONTENT_BROWSER_FRAME_HOST_DEBUG_URLS_H_
+
+#include "content/public/common/page_transition_types.h"
+
+class GURL;
+
+namespace content {
+
+// Checks if the given url is a url used for debugging purposes, and if so
+// handles it and returns true.
+bool HandleDebugURL(const GURL& url, PageTransition transition);
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_DEBUG_URLS_H_
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
new file mode 100644
index 0000000..0cb9d5e
--- /dev/null
+++ b/content/browser/frame_host/frame_tree.cc
@@ -0,0 +1,138 @@
+// Copyright 2013 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/frame_tree.h"
+
+#include <queue>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+
+namespace content {
+
+namespace {
+// Used with FrameTree::ForEach() to search for the FrameTreeNode
+// corresponding to |frame_id|.
+bool FrameTreeNodeForId(int64 frame_id, FrameTreeNode** out_node,
+                        FrameTreeNode* node) {
+  if (node->frame_id() == frame_id) {
+    *out_node = node;
+    // Terminate iteration once the node has been found.
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+FrameTree::FrameTree()
+    : root_(new FrameTreeNode(FrameTreeNode::kInvalidFrameId, std::string(),
+                              scoped_ptr<RenderFrameHostImpl>())) {
+}
+
+FrameTree::~FrameTree() {
+}
+
+FrameTreeNode* FrameTree::FindByID(int64 frame_id) {
+  FrameTreeNode* node = NULL;
+  ForEach(base::Bind(&FrameTreeNodeForId, frame_id, &node));
+  return node;
+}
+
+void FrameTree::ForEach(
+    const base::Callback<bool(FrameTreeNode*)>& on_node) const {
+  std::queue<FrameTreeNode*> queue;
+  queue.push(root_.get());
+
+  while (!queue.empty()) {
+    FrameTreeNode* node = queue.front();
+    queue.pop();
+    if (!on_node.Run(node))
+      break;
+
+    for (size_t i = 0; i < node->child_count(); ++i)
+      queue.push(node->child_at(i));
+  }
+}
+
+bool FrameTree::IsFirstNavigationAfterSwap() const {
+  return root_->frame_id() == FrameTreeNode::kInvalidFrameId;
+}
+
+void FrameTree::OnFirstNavigationAfterSwap(int main_frame_id) {
+  root_->set_frame_id(main_frame_id);
+}
+
+void FrameTree::AddFrame(int render_frame_host_id, int64 parent_frame_id,
+                         int64 frame_id, const std::string& frame_name) {
+  FrameTreeNode* parent = FindByID(parent_frame_id);
+  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
+  // shutdown that might make this case possible?
+  if (!parent)
+    return;
+
+  parent->AddChild(CreateNode(frame_id, frame_name, render_frame_host_id,
+                              parent->render_frame_host()->GetProcess()));
+}
+
+void FrameTree::RemoveFrame(int64 parent_frame_id, int64 frame_id) {
+  // If switches::kSitePerProcess is not specified, then the FrameTree only
+  // contains a node for the root element. However, even in this case
+  // frame detachments need to be broadcast outwards.
+  //
+  // TODO(ajwong): Move this below the |parent| check after the FrameTree is
+  // guaranteed to be correctly populated even without the
+  // switches::kSitePerProcess flag.
+  FrameTreeNode* parent = FindByID(parent_frame_id);
+  if (!on_frame_removed_.is_null()) {
+    on_frame_removed_.Run(
+        root_->render_frame_host()->render_view_host(), frame_id);
+  }
+
+  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
+  // shutdown that might make this case possible?
+  if (!parent)
+    return;
+
+  parent->RemoveChild(frame_id);
+}
+
+void FrameTree::SetFrameUrl(int64 frame_id, const GURL& url) {
+  FrameTreeNode* node = FindByID(frame_id);
+  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
+  // shutdown that might make this case possible?
+  if (!node)
+    return;
+
+  if (node)
+    node->set_current_url(url);
+}
+
+void FrameTree::SwapMainFrame(RenderFrameHostImpl* render_frame_host) {
+  return root_->ResetForMainFrame(render_frame_host);
+}
+
+RenderFrameHostImpl* FrameTree::GetMainFrame() const {
+  return root_->render_frame_host();
+}
+
+void FrameTree::SetFrameRemoveListener(
+    const base::Callback<void(RenderViewHostImpl*, int64)>& on_frame_removed) {
+  on_frame_removed_ = on_frame_removed;
+}
+
+scoped_ptr<FrameTreeNode> FrameTree::CreateNode(
+    int64 frame_id, const std::string& frame_name, int render_frame_host_id,
+    RenderProcessHost* render_process_host) {
+  scoped_ptr<RenderFrameHostImpl> render_frame_host(
+      new RenderFrameHostImpl(root_->render_frame_host()->render_view_host(),
+                              this, render_frame_host_id, false));
+
+  return make_scoped_ptr(new FrameTreeNode(frame_id, frame_name,
+                                           render_frame_host.Pass()));
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
new file mode 100644
index 0000000..f9bf809
--- /dev/null
+++ b/content/browser/frame_host/frame_tree.h
@@ -0,0 +1,103 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_FRAME_TREE_H_
+#define CONTENT_BROWSER_FRAME_HOST_FRAME_TREE_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class FrameTreeNode;
+class RenderProcessHost;
+class RenderViewHostImpl;
+
+// Represents the frame tree for a page. With the exception of the main frame,
+// all FrameTreeNodes will be created/deleted in response to frame attach and
+// detach events in the DOM.
+//
+// The main frame's FrameTreeNode is special in that it is reused. This allows
+// it to serve as an anchor for state that needs to persist across top-level
+// page navigations.
+//
+// TODO(ajwong): Move NavigationController ownership to the main frame
+// FrameTreeNode. Possibly expose access to it from here.
+//
+// TODO(ajwong): Currently this class only contains FrameTreeNodes for
+// subframes if the --site-per-process flag is enabled.
+//
+// This object is only used on the UI thread.
+class CONTENT_EXPORT FrameTree {
+ public:
+  FrameTree();
+  ~FrameTree();
+
+  // Returns the FrameTreeNode with the given |frame_id|.
+  FrameTreeNode* FindByID(int64 frame_id);
+
+  // Executes |on_node| on each node in the frame tree.  If |on_node| returns
+  // false, terminates the iteration immediately. Returning false is useful
+  // if |on_node| is just doing a search over the tree.
+  void ForEach(const base::Callback<bool(FrameTreeNode*)>& on_node) const;
+
+  // After the FrameTree is created, or after SwapMainFrame() has been called,
+  // the root node does not yet have a frame id. This is allocated by the
+  // renderer and is published to the browser process on the first navigation
+  // after a swap. These two functions are used to set the root node's frame
+  // id.
+  //
+  // TODO(ajwong): Remove these once RenderFrameHost's routing id replaces
+  // frame_id.
+  bool IsFirstNavigationAfterSwap() const;
+  void OnFirstNavigationAfterSwap(int main_frame_id);
+
+  // Frame tree manipulation routines.
+  void AddFrame(int render_frame_host_id, int64 parent_frame_id,
+                int64 frame_id, const std::string& frame_name);
+  void RemoveFrame(int64 parent_frame_id, int64 frame_id);
+  void SetFrameUrl(int64 frame_id, const GURL& url);
+
+  // Resets the FrameTree and changes RenderFrameHost for the main frame.
+  // This destroys most of the frame tree but retains the root node so that
+  // navigation state may be kept on it between process swaps. Used to
+  // support bookkeeping for top-level navigations.
+  //
+  // If |main_frame| is NULL, reset tree to initially constructed state.
+  //
+  // TODO(ajwong): This function should not be given a |main_frame|. This is
+  // required currently because the RenderViewHost owns its main frame. When
+  // that relation is fixed, the FrameTree should be responsible for
+  // created/destroying the main frame on the swap.
+  void SwapMainFrame(RenderFrameHostImpl* main_frame);
+
+  // Convenience accessor for the main frame's RenderFrameHostImpl.
+  RenderFrameHostImpl* GetMainFrame() const;
+
+  // Allows a client to listen for frame removal.
+  void SetFrameRemoveListener(
+      const base::Callback<void(RenderViewHostImpl*, int64)>& on_frame_removed);
+
+  FrameTreeNode* GetRootForTesting() { return root_.get(); }
+
+ private:
+  scoped_ptr<FrameTreeNode> CreateNode(int64 frame_id,
+                                       const std::string& frame_name,
+                                       int render_frame_host_id,
+                                       RenderProcessHost* render_process_host);
+
+  scoped_ptr<FrameTreeNode> root_;
+
+  base::Callback<void(RenderViewHostImpl*, int64)> on_frame_removed_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameTree);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_FRAME_TREE_H_
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
new file mode 100644
index 0000000..9bed9f6
--- /dev/null
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 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/frame_tree_node.h"
+
+#include <queue>
+
+#include "base/stl_util.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+
+namespace content {
+
+const int64 FrameTreeNode::kInvalidFrameId = -1;
+
+FrameTreeNode::FrameTreeNode(int64 frame_id, const std::string& name,
+                             scoped_ptr<RenderFrameHostImpl> render_frame_host)
+  : frame_id_(frame_id),
+    frame_name_(name),
+    owns_render_frame_host_(true),
+    render_frame_host_(render_frame_host.release()) {
+}
+
+FrameTreeNode::~FrameTreeNode() {
+  if (owns_render_frame_host_)
+    delete render_frame_host_;
+}
+
+void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child) {
+  children_.push_back(child.release());
+}
+
+void FrameTreeNode::RemoveChild(int64 child_id) {
+  std::vector<FrameTreeNode*>::iterator iter;
+
+  for (iter = children_.begin(); iter != children_.end(); ++iter) {
+    if ((*iter)->frame_id() == child_id)
+      break;
+  }
+
+  if (iter != children_.end())
+    children_.erase(iter);
+}
+
+void FrameTreeNode::ResetForMainFrame(
+    RenderFrameHostImpl* new_render_frame_host) {
+  DCHECK_EQ(0UL, children_.size());
+
+  owns_render_frame_host_ = false;
+  frame_id_ = kInvalidFrameId;
+  current_url_ = GURL();
+  children_.clear();
+
+  render_frame_host_ = new_render_frame_host;
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
new file mode 100644
index 0000000..63030a6
--- /dev/null
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -0,0 +1,116 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_FRAME_TREE_NODE_H_
+#define CONTENT_BROWSER_FRAME_HOST_FRAME_TREE_NODE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+
+// When a page contains iframes, its renderer process maintains a tree structure
+// 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:
+  static const int64 kInvalidFrameId;
+
+  FrameTreeNode(int64 frame_id, const std::string& name,
+                scoped_ptr<RenderFrameHostImpl> render_frame_host);
+  ~FrameTreeNode();
+
+  void AddChild(scoped_ptr<FrameTreeNode> child);
+  void RemoveChild(int64 child_id);
+
+  // Transitional API allowing the RenderFrameHost of a FrameTreeNode
+  // representing the main frame to be provided by someone else. After
+  // this is called, the FrameTreeNode no longer owns its RenderFrameHost.
+  //
+  // This should only be used for the main frame (aka root) in a frame tree.
+  //
+  // TODO(ajwong): Remove this method once the main frame RenderFrameHostImpl is
+  // no longer owned by the RenderViewHostImpl.
+  void ResetForMainFrame(RenderFrameHostImpl* new_render_frame_host);
+
+  void set_frame_id(int64 frame_id) {
+    DCHECK_EQ(frame_id_, kInvalidFrameId);
+    frame_id_ = frame_id;
+  }
+
+  int64 frame_id() const {
+    return frame_id_;
+  }
+
+  const std::string& frame_name() const {
+    return frame_name_;
+  }
+
+  size_t child_count() const {
+    return children_.size();
+  }
+
+  FrameTreeNode* child_at(size_t index) const {
+    return children_[index];
+  }
+
+  const GURL& current_url() const {
+    return current_url_;
+  }
+
+  void set_current_url(const GURL& url) {
+    current_url_ = url;
+  }
+
+  RenderFrameHostImpl* render_frame_host() const {
+    return render_frame_host_;
+  }
+
+ private:
+  // The unique identifier for the frame in the page.
+  int64 frame_id_;
+
+  // The assigned name of the frame. This name can be empty, unlike the unique
+  // name generated internally in the DOM tree.
+  std::string frame_name_;
+
+  // The immediate children of this specific frame.
+  ScopedVector<FrameTreeNode> children_;
+
+  // When ResetForMainFrame() is called, this is set to false and the
+  // |render_frame_host_| below is not deleted on destruction.
+  //
+  // For the mainframe, the FrameTree does not own the |render_frame_host_|.
+  // This is a transitional wart because RenderViewHostManager does not yet
+  // have the bookkeeping logic to handle creating a pending RenderFrameHost
+  // along with a pending RenderViewHost. Thus, for the main frame, the
+  // RenderViewHost currently retains ownership and the FrameTreeNode should
+  // not delete it on destruction.
+  bool owns_render_frame_host_;
+
+  // The active RenderFrameHost for this frame. The FrameTreeNode does not
+  // always own this pointer.  See comments above |owns_render_frame_host_|.
+  // TODO(ajwong): Replace with RenderFrameHostManager.
+  RenderFrameHostImpl* render_frame_host_;
+
+  // Track the current frame's last committed URL, so we can estimate the
+  // process impact of out-of-process iframes.
+  // TODO(creis): Remove this when we can store subframe URLs in the
+  // NavigationController.
+  GURL current_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameTreeNode);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_FRAME_TREE_NODE_H_
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
new file mode 100644
index 0000000..20295dc
--- /dev/null
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright 2013 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/frame_tree.h"
+
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class FrameTreeTest : public RenderViewHostTestHarness {
+ protected:
+  // Prints a FrameTree, for easy assertions of the tree hierarchy.
+  std::string GetTreeState(FrameTree* frame_tree) {
+    std::string result;
+    AppendTreeNodeState(frame_tree->GetRootForTesting(), &result);
+    return result;
+  }
+
+ private:
+  void AppendTreeNodeState(FrameTreeNode* node, std::string* result) {
+    result->append(base::Int64ToString(node->frame_id()));
+    if (!node->frame_name().empty()) {
+      result->append(" '");
+      result->append(node->frame_name());
+      result->append("'");
+    }
+    result->append(": [");
+    const char* separator = "";
+    for (size_t i = 0; i < node->child_count(); i++) {
+      result->append(separator);
+      AppendTreeNodeState(node->child_at(i), result);
+      separator = ", ";
+    }
+    result->append("]");
+  }
+};
+
+// The root node never changes during navigation even though its
+// RenderFrameHost does.
+//  - Swapping main frame doesn't change root node.
+//  - Swapping back to NULL doesn't crash (easier tear-down for interstitials).
+//  - Main frame does not own RenderFrameHost.
+TEST_F(FrameTreeTest, RootNode) {
+  FrameTree frame_tree;
+
+  // Initial state has empty node.
+  FrameTreeNode* root = frame_tree.GetRootForTesting();
+  ASSERT_TRUE(root);
+  EXPECT_FALSE(frame_tree.GetMainFrame());
+
+  // Swap in main frame.
+  RenderFrameHostImpl* dummy = reinterpret_cast<RenderFrameHostImpl*>(0x1);
+  frame_tree.SwapMainFrame(dummy);
+  EXPECT_EQ(root, frame_tree.GetRootForTesting());
+  EXPECT_EQ(dummy, frame_tree.GetMainFrame());
+
+  // Move back to NULL.
+  frame_tree.SwapMainFrame(NULL);
+  EXPECT_EQ(root, frame_tree.GetRootForTesting());
+  EXPECT_FALSE(frame_tree.GetMainFrame());
+
+  // Move back to an invalid pointer, let the FrameTree go out of scope. Test
+  // should not crash because the main frame isn't owned.
+  frame_tree.SwapMainFrame(dummy);
+}
+
+// Test that swapping the main frame resets the renderer-assigned frame id.
+//  - On creation, frame id is unassigned.
+//  - After a swap, frame id is unassigned.
+TEST_F(FrameTreeTest, FirstNavigationAfterSwap) {
+  FrameTree frame_tree;
+
+  EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
+  EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
+            frame_tree.GetRootForTesting()->frame_id());
+  frame_tree.OnFirstNavigationAfterSwap(1);
+  EXPECT_FALSE(frame_tree.IsFirstNavigationAfterSwap());
+  EXPECT_EQ(1, frame_tree.GetRootForTesting()->frame_id());
+
+  frame_tree.SwapMainFrame(NULL);
+  EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
+  EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
+            frame_tree.GetRootForTesting()->frame_id());
+}
+
+// Exercise tree manipulation routines.
+//  - Add a series of nodes and verify tree structure.
+//  - Remove a series of nodes and verify tree structure.
+TEST_F(FrameTreeTest, Shape) {
+  FrameTree frame_tree;
+  std::string no_children_node("no children node");
+  std::string deep_subtree("node with deep subtree");
+
+  // Ensure the top-level node of the FrameTree is initialized by simulating a
+  // main frame swap here.
+  RenderFrameHostImpl render_frame_host(static_cast<RenderViewHostImpl*>(rvh()),
+                                        &frame_tree,
+                                        process()->GetNextRoutingID(), false);
+  frame_tree.SwapMainFrame(&render_frame_host);
+  frame_tree.OnFirstNavigationAfterSwap(5);
+
+  ASSERT_EQ("5: []", GetTreeState(&frame_tree));
+
+  // Simulate attaching a series of frames to build the frame tree.
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 14, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 15, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 16, std::string());
+
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 244, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 15, 255, no_children_node);
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 245, std::string());
+
+  ASSERT_EQ("5: [14: [244: [], 245: []], "
+                "15: [255 'no children node': []], "
+                "16: []]",
+            GetTreeState(&frame_tree));
+
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 264, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 265, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 266, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 267, deep_subtree);
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 268, std::string());
+
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 267, 365, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 365, 455, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 455, 555, std::string());
+  frame_tree.AddFrame(process()->GetNextRoutingID(), 555, 655, std::string());
+
+  // Now that's it's fully built, verify the tree structure is as expected.
+  ASSERT_EQ("5: [14: [244: [], 245: []], "
+                "15: [255 'no children node': []], "
+                "16: [264: [], 265: [], 266: [], "
+                     "267 'node with deep subtree': "
+                         "[365: [455: [555: [655: []]]]], 268: []]]",
+            GetTreeState(&frame_tree));
+
+  // Test removing of nodes.
+  frame_tree.RemoveFrame(555, 655);
+  ASSERT_EQ("5: [14: [244: [], 245: []], "
+                "15: [255 'no children node': []], "
+                "16: [264: [], 265: [], 266: [], "
+                     "267 'node with deep subtree': "
+                         "[365: [455: [555: []]]], 268: []]]",
+            GetTreeState(&frame_tree));
+
+  frame_tree.RemoveFrame(16, 265);
+  ASSERT_EQ("5: [14: [244: [], 245: []], "
+                "15: [255 'no children node': []], "
+                "16: [264: [], 266: [], "
+                     "267 'node with deep subtree': "
+                         "[365: [455: [555: []]]], 268: []]]",
+            GetTreeState(&frame_tree));
+
+  frame_tree.RemoveFrame(5, 15);
+  ASSERT_EQ("5: [14: [244: [], 245: []], "
+                "16: [264: [], 266: [], "
+                     "267 'node with deep subtree': "
+                         "[365: [455: [555: []]]], 268: []]]",
+            GetTreeState(&frame_tree));
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
new file mode 100644
index 0000000..4bcee69
--- /dev/null
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -0,0 +1,843 @@
+// Copyright 2013 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/interstitial_page_impl.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_factory.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/view_messages.h"
+#include "content/port/browser/render_view_host_delegate_view.h"
+#include "content/port/browser/render_widget_host_view_port.h"
+#include "content/port/browser/web_contents_view_port.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/dom_operation_notification_details.h"
+#include "content/public/browser/interstitial_page_delegate.h"
+#include "content/public/browser/invalidate_type.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/common/bindings_policy.h"
+#include "content/public/common/page_transition_types.h"
+#include "net/base/escape.h"
+#include "net/url_request/url_request_context_getter.h"
+
+using WebKit::WebDragOperation;
+using WebKit::WebDragOperationsMask;
+
+namespace content {
+namespace {
+
+void ResourceRequestHelper(ResourceDispatcherHostImpl* rdh,
+                           int process_id,
+                           int render_view_host_id,
+                           ResourceRequestAction action) {
+  switch (action) {
+    case BLOCK:
+      rdh->BlockRequestsForRoute(process_id, render_view_host_id);
+      break;
+    case RESUME:
+      rdh->ResumeBlockedRequestsForRoute(process_id, render_view_host_id);
+      break;
+    case CANCEL:
+      rdh->CancelBlockedRequestsForRoute(process_id, render_view_host_id);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace
+
+class InterstitialPageImpl::InterstitialPageRVHDelegateView
+  : public RenderViewHostDelegateView {
+ public:
+  explicit InterstitialPageRVHDelegateView(InterstitialPageImpl* page);
+
+  // RenderViewHostDelegateView implementation:
+  virtual void ShowPopupMenu(const gfx::Rect& bounds,
+                             int item_height,
+                             double item_font_size,
+                             int selected_item,
+                             const std::vector<MenuItem>& items,
+                             bool right_aligned,
+                             bool allow_multiple_selection) OVERRIDE;
+  virtual void StartDragging(const DropData& drop_data,
+                             WebDragOperationsMask operations_allowed,
+                             const gfx::ImageSkia& image,
+                             const gfx::Vector2d& image_offset,
+                             const DragEventSourceInfo& event_info) OVERRIDE;
+  virtual void UpdateDragCursor(WebDragOperation operation) OVERRIDE;
+  virtual void GotFocus() OVERRIDE;
+  virtual void TakeFocus(bool reverse) OVERRIDE;
+  virtual void OnFindReply(int request_id,
+                           int number_of_matches,
+                           const gfx::Rect& selection_rect,
+                           int active_match_ordinal,
+                           bool final_update);
+
+ private:
+  InterstitialPageImpl* interstitial_page_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterstitialPageRVHDelegateView);
+};
+
+
+// We keep a map of the various blocking pages shown as the UI tests need to
+// be able to retrieve them.
+typedef std::map<WebContents*, InterstitialPageImpl*> InterstitialPageMap;
+static InterstitialPageMap* g_web_contents_to_interstitial_page;
+
+// Initializes g_web_contents_to_interstitial_page in a thread-safe manner.
+// Should be called before accessing g_web_contents_to_interstitial_page.
+static void InitInterstitialPageMap() {
+  if (!g_web_contents_to_interstitial_page)
+    g_web_contents_to_interstitial_page = new InterstitialPageMap;
+}
+
+InterstitialPage* InterstitialPage::Create(WebContents* web_contents,
+                                           bool new_navigation,
+                                           const GURL& url,
+                                           InterstitialPageDelegate* delegate) {
+  return new InterstitialPageImpl(
+      web_contents,
+      static_cast<RenderWidgetHostDelegate*>(
+          static_cast<WebContentsImpl*>(web_contents)),
+      new_navigation, url, delegate);
+}
+
+InterstitialPage* InterstitialPage::GetInterstitialPage(
+    WebContents* web_contents) {
+  InitInterstitialPageMap();
+  InterstitialPageMap::const_iterator iter =
+      g_web_contents_to_interstitial_page->find(web_contents);
+  if (iter == g_web_contents_to_interstitial_page->end())
+    return NULL;
+
+  return iter->second;
+}
+
+InterstitialPageImpl::InterstitialPageImpl(
+    WebContents* web_contents,
+    RenderWidgetHostDelegate* render_widget_host_delegate,
+    bool new_navigation,
+    const GURL& url,
+    InterstitialPageDelegate* delegate)
+    : WebContentsObserver(web_contents),
+      web_contents_(web_contents),
+      controller_(static_cast<NavigationControllerImpl*>(
+          &web_contents->GetController())),
+      render_widget_host_delegate_(render_widget_host_delegate),
+      url_(url),
+      new_navigation_(new_navigation),
+      should_discard_pending_nav_entry_(new_navigation),
+      reload_on_dont_proceed_(false),
+      enabled_(true),
+      action_taken_(NO_ACTION),
+      render_view_host_(NULL),
+      original_child_id_(web_contents->GetRenderProcessHost()->GetID()),
+      original_rvh_id_(web_contents->GetRenderViewHost()->GetRoutingID()),
+      should_revert_web_contents_title_(false),
+      web_contents_was_loading_(false),
+      resource_dispatcher_host_notified_(false),
+      rvh_delegate_view_(new InterstitialPageRVHDelegateView(this)),
+      create_view_(true),
+      delegate_(delegate),
+      weak_ptr_factory_(this) {
+  InitInterstitialPageMap();
+  // It would be inconsistent to create an interstitial with no new navigation
+  // (which is the case when the interstitial was triggered by a sub-resource on
+  // a page) when we have a pending entry (in the process of loading a new top
+  // frame).
+  DCHECK(new_navigation || !web_contents->GetController().GetPendingEntry());
+}
+
+InterstitialPageImpl::~InterstitialPageImpl() {
+}
+
+void InterstitialPageImpl::Show() {
+  if (!enabled())
+    return;
+
+  // If an interstitial is already showing or about to be shown, close it before
+  // showing the new one.
+  // Be careful not to take an action on the old interstitial more than once.
+  InterstitialPageMap::const_iterator iter =
+      g_web_contents_to_interstitial_page->find(web_contents_);
+  if (iter != g_web_contents_to_interstitial_page->end()) {
+    InterstitialPageImpl* interstitial = iter->second;
+    if (interstitial->action_taken_ != NO_ACTION) {
+      interstitial->Hide();
+    } else {
+      // If we are currently showing an interstitial page for which we created
+      // a transient entry and a new interstitial is shown as the result of a
+      // new browser initiated navigation, then that transient entry has already
+      // been discarded and a new pending navigation entry created.
+      // So we should not discard that new pending navigation entry.
+      // See http://crbug.com/9791
+      if (new_navigation_ && interstitial->new_navigation_)
+        interstitial->should_discard_pending_nav_entry_= false;
+      interstitial->DontProceed();
+    }
+  }
+
+  // Block the resource requests for the render view host while it is hidden.
+  TakeActionOnResourceDispatcher(BLOCK);
+  // We need to be notified when the RenderViewHost is destroyed so we can
+  // cancel the blocked requests.  We cannot do that on
+  // NOTIFY_WEB_CONTENTS_DESTROYED as at that point the RenderViewHost has
+  // already been destroyed.
+  notification_registrar_.Add(
+      this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
+      Source<RenderWidgetHost>(controller_->delegate()->GetRenderViewHost()));
+
+  // Update the g_web_contents_to_interstitial_page map.
+  iter = g_web_contents_to_interstitial_page->find(web_contents_);
+  DCHECK(iter == g_web_contents_to_interstitial_page->end());
+  (*g_web_contents_to_interstitial_page)[web_contents_] = this;
+
+  if (new_navigation_) {
+    NavigationEntryImpl* entry = new NavigationEntryImpl;
+    entry->SetURL(url_);
+    entry->SetVirtualURL(url_);
+    entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
+
+    // Give delegates a chance to set some states on the navigation entry.
+    delegate_->OverrideEntry(entry);
+
+    controller_->SetTransientEntry(entry);
+  }
+
+  DCHECK(!render_view_host_);
+  render_view_host_ = static_cast<RenderViewHostImpl*>(CreateRenderViewHost());
+  render_view_host_->AttachToFrameTree();
+  CreateWebContentsView();
+
+  std::string data_url = "data:text/html;charset=utf-8," +
+                         net::EscapePath(delegate_->GetHTMLContents());
+  render_view_host_->NavigateToURL(GURL(data_url));
+
+  notification_registrar_.Add(this, NOTIFICATION_NAV_ENTRY_PENDING,
+      Source<NavigationController>(controller_));
+  notification_registrar_.Add(
+      this, NOTIFICATION_DOM_OPERATION_RESPONSE,
+      Source<RenderViewHost>(render_view_host_));
+}
+
+void InterstitialPageImpl::Hide() {
+  // We may have already been hidden, and are just waiting to be deleted.
+  // We can't check for enabled() here, because some callers have already
+  // called Disable.
+  if (!render_view_host_)
+    return;
+
+  Disable();
+
+  RenderWidgetHostView* old_view =
+      controller_->delegate()->GetRenderViewHost()->GetView();
+  if (controller_->delegate()->GetInterstitialPage() == this &&
+      old_view &&
+      !old_view->IsShowing() &&
+      !controller_->delegate()->IsHidden()) {
+    // Show the original RVH since we're going away.  Note it might not exist if
+    // the renderer crashed while the interstitial was showing.
+    // Note that it is important that we don't call Show() if the view is
+    // already showing. That would result in bad things (unparented HWND on
+    // Windows for example) happening.
+    old_view->Show();
+  }
+
+  // If the focus was on the interstitial, let's keep it to the page.
+  // (Note that in unit-tests the RVH may not have a view).
+  if (render_view_host_->GetView() &&
+      render_view_host_->GetView()->HasFocus() &&
+      controller_->delegate()->GetRenderViewHost()->GetView()) {
+    RenderWidgetHostViewPort::FromRWHV(
+        controller_->delegate()->GetRenderViewHost()->GetView())->Focus();
+  }
+
+  // Shutdown the RVH asynchronously, as we may have been called from a RVH
+  // delegate method, and we can't delete the RVH out from under itself.
+  base::MessageLoop::current()->PostNonNestableTask(
+      FROM_HERE,
+      base::Bind(&InterstitialPageImpl::Shutdown,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 render_view_host_));
+  render_view_host_ = NULL;
+  frame_tree_.SwapMainFrame(NULL);
+  controller_->delegate()->DetachInterstitialPage();
+  // Let's revert to the original title if necessary.
+  NavigationEntry* entry = controller_->GetVisibleEntry();
+  if (!new_navigation_ && should_revert_web_contents_title_) {
+    entry->SetTitle(original_web_contents_title_);
+    controller_->delegate()->NotifyNavigationStateChanged(
+        INVALIDATE_TYPE_TITLE);
+  }
+
+  InterstitialPageMap::iterator iter =
+      g_web_contents_to_interstitial_page->find(web_contents_);
+  DCHECK(iter != g_web_contents_to_interstitial_page->end());
+  if (iter != g_web_contents_to_interstitial_page->end())
+    g_web_contents_to_interstitial_page->erase(iter);
+
+  // Clear the WebContents pointer, because it may now be deleted.
+  // This signifies that we are in the process of shutting down.
+  web_contents_ = NULL;
+}
+
+void InterstitialPageImpl::Observe(
+    int type,
+    const NotificationSource& source,
+    const NotificationDetails& details) {
+  switch (type) {
+    case NOTIFICATION_NAV_ENTRY_PENDING:
+      // We are navigating away from the interstitial (the user has typed a URL
+      // in the location bar or clicked a bookmark).  Make sure clicking on the
+      // interstitial will have no effect.  Also cancel any blocked requests
+      // on the ResourceDispatcherHost.  Note that when we get this notification
+      // the RenderViewHost has not yet navigated so we'll unblock the
+      // RenderViewHost before the resource request for the new page we are
+      // navigating arrives in the ResourceDispatcherHost.  This ensures that
+      // request won't be blocked if the same RenderViewHost was used for the
+      // new navigation.
+      Disable();
+      TakeActionOnResourceDispatcher(CANCEL);
+      break;
+    case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED:
+      if (action_taken_ == NO_ACTION) {
+        // The RenderViewHost is being destroyed (as part of the tab being
+        // closed); make sure we clear the blocked requests.
+        RenderViewHost* rvh = static_cast<RenderViewHost*>(
+            static_cast<RenderViewHostImpl*>(
+                RenderWidgetHostImpl::From(
+                    Source<RenderWidgetHost>(source).ptr())));
+        DCHECK(rvh->GetProcess()->GetID() == original_child_id_ &&
+               rvh->GetRoutingID() == original_rvh_id_);
+        TakeActionOnResourceDispatcher(CANCEL);
+      }
+      break;
+    case NOTIFICATION_DOM_OPERATION_RESPONSE:
+      if (enabled()) {
+        Details<DomOperationNotificationDetails> dom_op_details(
+            details);
+        delegate_->CommandReceived(dom_op_details->json);
+      }
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void InterstitialPageImpl::NavigationEntryCommitted(
+    const LoadCommittedDetails& load_details) {
+  OnNavigatingAwayOrTabClosing();
+}
+
+void InterstitialPageImpl::WebContentsDestroyed(WebContents* web_contents) {
+  OnNavigatingAwayOrTabClosing();
+}
+
+RenderViewHostDelegateView* InterstitialPageImpl::GetDelegateView() {
+  return rvh_delegate_view_.get();
+}
+
+const GURL& InterstitialPageImpl::GetURL() const {
+  return url_;
+}
+
+void InterstitialPageImpl::RenderViewTerminated(
+    RenderViewHost* render_view_host,
+    base::TerminationStatus status,
+    int error_code) {
+  // Our renderer died. This should not happen in normal cases.
+  // If we haven't already started shutdown, just dismiss the interstitial.
+  // We cannot check for enabled() here, because we may have called Disable
+  // without calling Hide.
+  if (render_view_host_)
+    DontProceed();
+}
+
+void InterstitialPageImpl::DidNavigate(
+    RenderViewHost* render_view_host,
+    const ViewHostMsg_FrameNavigate_Params& params) {
+  // A fast user could have navigated away from the page that triggered the
+  // interstitial while the interstitial was loading, that would have disabled
+  // us. In that case we can dismiss ourselves.
+  if (!enabled()) {
+    DontProceed();
+    return;
+  }
+  if (PageTransitionCoreTypeIs(params.transition,
+                               PAGE_TRANSITION_AUTO_SUBFRAME)) {
+    // No need to handle navigate message from iframe in the interstitial page.
+    return;
+  }
+
+  // The RenderViewHost has loaded its contents, we can show it now.
+  if (!controller_->delegate()->IsHidden())
+    render_view_host_->GetView()->Show();
+  controller_->delegate()->AttachInterstitialPage(this);
+
+  RenderWidgetHostView* rwh_view =
+      controller_->delegate()->GetRenderViewHost()->GetView();
+
+  // The RenderViewHost may already have crashed before we even get here.
+  if (rwh_view) {
+    // If the page has focus, focus the interstitial.
+    if (rwh_view->HasFocus())
+      Focus();
+
+    // Hide the original RVH since we're showing the interstitial instead.
+    rwh_view->Hide();
+  }
+
+  // Notify the tab we are not loading so the throbber is stopped. It also
+  // causes a WebContentsObserver::DidStopLoading callback that the
+  // AutomationProvider (used by the UI tests) expects to consider a navigation
+  // as complete. Without this, navigating in a UI test to a URL that triggers
+  // an interstitial would hang.
+  web_contents_was_loading_ = controller_->delegate()->IsLoading();
+  controller_->delegate()->SetIsLoading(
+      controller_->delegate()->GetRenderViewHost(), false, NULL);
+}
+
+void InterstitialPageImpl::UpdateTitle(
+    RenderViewHost* render_view_host,
+    int32 page_id,
+    const string16& title,
+    base::i18n::TextDirection title_direction) {
+  if (!enabled())
+    return;
+
+  DCHECK(render_view_host == render_view_host_);
+  NavigationEntry* entry = controller_->GetVisibleEntry();
+  if (!entry) {
+    // Crash reports from the field indicate this can be NULL.
+    // This is unexpected as InterstitialPages constructed with the
+    // new_navigation flag set to true create a transient navigation entry
+    // (that is returned as the active entry). And the only case so far of
+    // interstitial created with that flag set to false is with the
+    // SafeBrowsingBlockingPage, when the resource triggering the interstitial
+    // is a sub-resource, meaning the main page has already been loaded and a
+    // navigation entry should have been created.
+    NOTREACHED();
+    return;
+  }
+
+  // If this interstitial is shown on an existing navigation entry, we'll need
+  // to remember its title so we can revert to it when hidden.
+  if (!new_navigation_ && !should_revert_web_contents_title_) {
+    original_web_contents_title_ = entry->GetTitle();
+    should_revert_web_contents_title_ = true;
+  }
+  // TODO(evan): make use of title_direction.
+  // http://code.google.com/p/chromium/issues/detail?id=27094
+  entry->SetTitle(title);
+  controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
+}
+
+RendererPreferences InterstitialPageImpl::GetRendererPrefs(
+    BrowserContext* browser_context) const {
+  delegate_->OverrideRendererPrefs(&renderer_preferences_);
+  return renderer_preferences_;
+}
+
+WebPreferences InterstitialPageImpl::GetWebkitPrefs() {
+  if (!enabled())
+    return WebPreferences();
+
+  return render_view_host_->GetWebkitPrefs(url_);
+}
+
+void InterstitialPageImpl::RenderWidgetDeleted(
+    RenderWidgetHostImpl* render_widget_host) {
+  delete this;
+}
+
+bool InterstitialPageImpl::PreHandleKeyboardEvent(
+    const NativeWebKeyboardEvent& event,
+    bool* is_keyboard_shortcut) {
+  if (!enabled())
+    return false;
+  return render_widget_host_delegate_->PreHandleKeyboardEvent(
+      event, is_keyboard_shortcut);
+}
+
+void InterstitialPageImpl::HandleKeyboardEvent(
+      const NativeWebKeyboardEvent& event) {
+  if (enabled())
+    render_widget_host_delegate_->HandleKeyboardEvent(event);
+}
+
+#if defined(OS_WIN) && defined(USE_AURA)
+gfx::NativeViewAccessible
+InterstitialPageImpl::GetParentNativeViewAccessible() {
+  return render_widget_host_delegate_->GetParentNativeViewAccessible();
+}
+#endif
+
+WebContents* InterstitialPageImpl::web_contents() const {
+  return web_contents_;
+}
+
+RenderViewHost* InterstitialPageImpl::CreateRenderViewHost() {
+  if (!enabled())
+    return NULL;
+
+  // Interstitial pages don't want to share the session storage so we mint a
+  // new one.
+  BrowserContext* browser_context = web_contents()->GetBrowserContext();
+  scoped_refptr<SiteInstance> site_instance =
+      SiteInstance::Create(browser_context);
+  DOMStorageContextWrapper* dom_storage_context =
+      static_cast<DOMStorageContextWrapper*>(
+          BrowserContext::GetStoragePartition(
+              browser_context, site_instance.get())->GetDOMStorageContext());
+  session_storage_namespace_ =
+      new SessionStorageNamespaceImpl(dom_storage_context);
+
+  return RenderViewHostFactory::Create(site_instance.get(),
+                                       this,
+                                       this,
+                                       MSG_ROUTING_NONE,
+                                       MSG_ROUTING_NONE,
+                                       false,
+                                       false);
+}
+
+WebContentsView* InterstitialPageImpl::CreateWebContentsView() {
+  if (!enabled() || !create_view_)
+    return NULL;
+  WebContentsView* web_contents_view = web_contents()->GetView();
+  WebContentsViewPort* web_contents_view_port =
+      static_cast<WebContentsViewPort*>(web_contents_view);
+  RenderWidgetHostView* view =
+      web_contents_view_port->CreateViewForWidget(render_view_host_);
+  render_view_host_->SetView(view);
+  render_view_host_->AllowBindings(BINDINGS_POLICY_DOM_AUTOMATION);
+
+  int32 max_page_id = web_contents()->
+      GetMaxPageIDForSiteInstance(render_view_host_->GetSiteInstance());
+  render_view_host_->CreateRenderView(string16(),
+                                      MSG_ROUTING_NONE,
+                                      max_page_id);
+  controller_->delegate()->RenderViewForInterstitialPageCreated(
+      render_view_host_);
+  view->SetSize(web_contents_view->GetContainerSize());
+  // Don't show the interstitial until we have navigated to it.
+  view->Hide();
+  return web_contents_view;
+}
+
+void InterstitialPageImpl::Proceed() {
+  // Don't repeat this if we are already shutting down.  We cannot check for
+  // enabled() here, because we may have called Disable without calling Hide.
+  if (!render_view_host_)
+    return;
+
+  if (action_taken_ != NO_ACTION) {
+    NOTREACHED();
+    return;
+  }
+  Disable();
+  action_taken_ = PROCEED_ACTION;
+
+  // Resumes the throbber, if applicable.
+  if (web_contents_was_loading_)
+    controller_->delegate()->SetIsLoading(
+        controller_->delegate()->GetRenderViewHost(), true, NULL);
+
+  // If this is a new navigation, the old page is going away, so we cancel any
+  // blocked requests for it.  If it is not a new navigation, then it means the
+  // interstitial was shown as a result of a resource loading in the page.
+  // Since the user wants to proceed, we'll let any blocked request go through.
+  if (new_navigation_)
+    TakeActionOnResourceDispatcher(CANCEL);
+  else
+    TakeActionOnResourceDispatcher(RESUME);
+
+  // No need to hide if we are a new navigation, we'll get hidden when the
+  // navigation is committed.
+  if (!new_navigation_) {
+    Hide();
+    delegate_->OnProceed();
+    return;
+  }
+
+  delegate_->OnProceed();
+}
+
+void InterstitialPageImpl::DontProceed() {
+  // Don't repeat this if we are already shutting down.  We cannot check for
+  // enabled() here, because we may have called Disable without calling Hide.
+  if (!render_view_host_)
+    return;
+  DCHECK(action_taken_ != DONT_PROCEED_ACTION);
+
+  Disable();
+  action_taken_ = DONT_PROCEED_ACTION;
+
+  // If this is a new navigation, we are returning to the original page, so we
+  // resume blocked requests for it.  If it is not a new navigation, then it
+  // means the interstitial was shown as a result of a resource loading in the
+  // page and we won't return to the original page, so we cancel blocked
+  // requests in that case.
+  if (new_navigation_)
+    TakeActionOnResourceDispatcher(RESUME);
+  else
+    TakeActionOnResourceDispatcher(CANCEL);
+
+  if (should_discard_pending_nav_entry_) {
+    // Since no navigation happens we have to discard the transient entry
+    // explicitely.  Note that by calling DiscardNonCommittedEntries() we also
+    // discard the pending entry, which is what we want, since the navigation is
+    // cancelled.
+    controller_->DiscardNonCommittedEntries();
+  }
+
+  if (reload_on_dont_proceed_)
+    controller_->Reload(true);
+
+  Hide();
+  delegate_->OnDontProceed();
+}
+
+void InterstitialPageImpl::CancelForNavigation() {
+  // The user is trying to navigate away.  We should unblock the renderer and
+  // disable the interstitial, but keep it visible until the navigation
+  // completes.
+  Disable();
+  // If this interstitial was shown for a new navigation, allow any navigations
+  // on the original page to resume (e.g., subresource requests, XHRs, etc).
+  // Otherwise, cancel the pending, possibly dangerous navigations.
+  if (new_navigation_)
+    TakeActionOnResourceDispatcher(RESUME);
+  else
+    TakeActionOnResourceDispatcher(CANCEL);
+}
+
+void InterstitialPageImpl::SetSize(const gfx::Size& size) {
+  if (!enabled())
+    return;
+#if !defined(OS_MACOSX)
+  // When a tab is closed, we might be resized after our view was NULLed
+  // (typically if there was an info-bar).
+  if (render_view_host_->GetView())
+    render_view_host_->GetView()->SetSize(size);
+#else
+  // TODO(port): Does Mac need to SetSize?
+  NOTIMPLEMENTED();
+#endif
+}
+
+void InterstitialPageImpl::Focus() {
+  // Focus the native window.
+  if (!enabled())
+    return;
+  RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus();
+}
+
+void InterstitialPageImpl::FocusThroughTabTraversal(bool reverse) {
+  if (!enabled())
+    return;
+  render_view_host_->SetInitialFocus(reverse);
+}
+
+RenderWidgetHostView* InterstitialPageImpl::GetView() {
+  return render_view_host_->GetView();
+}
+
+RenderViewHost* InterstitialPageImpl::GetRenderViewHostForTesting() const {
+  return render_view_host_;
+}
+
+#if defined(OS_ANDROID)
+RenderViewHost* InterstitialPageImpl::GetRenderViewHost() const {
+  return render_view_host_;
+}
+#endif
+
+InterstitialPageDelegate* InterstitialPageImpl::GetDelegateForTesting() {
+  return delegate_.get();
+}
+
+void InterstitialPageImpl::DontCreateViewForTesting() {
+  create_view_ = false;
+}
+
+gfx::Rect InterstitialPageImpl::GetRootWindowResizerRect() const {
+  return gfx::Rect();
+}
+
+void InterstitialPageImpl::CreateNewWindow(
+    int route_id,
+    int main_frame_route_id,
+    const ViewHostMsg_CreateWindow_Params& params,
+    SessionStorageNamespace* session_storage_namespace) {
+  NOTREACHED() << "InterstitialPage does not support showing popups yet.";
+}
+
+void InterstitialPageImpl::CreateNewWidget(int route_id,
+                                           WebKit::WebPopupType popup_type) {
+  NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
+}
+
+void InterstitialPageImpl::CreateNewFullscreenWidget(int route_id) {
+  NOTREACHED()
+      << "InterstitialPage does not support showing full screen popups.";
+}
+
+void InterstitialPageImpl::ShowCreatedWindow(int route_id,
+                                             WindowOpenDisposition disposition,
+                                             const gfx::Rect& initial_pos,
+                                             bool user_gesture) {
+  NOTREACHED() << "InterstitialPage does not support showing popups yet.";
+}
+
+void InterstitialPageImpl::ShowCreatedWidget(int route_id,
+                                             const gfx::Rect& initial_pos) {
+  NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
+}
+
+void InterstitialPageImpl::ShowCreatedFullscreenWidget(int route_id) {
+  NOTREACHED()
+      << "InterstitialPage does not support showing full screen popups.";
+}
+
+SessionStorageNamespace* InterstitialPageImpl::GetSessionStorageNamespace(
+    SiteInstance* instance) {
+  return session_storage_namespace_.get();
+}
+
+FrameTree* InterstitialPageImpl::GetFrameTree() {
+  return &frame_tree_;
+}
+
+void InterstitialPageImpl::Disable() {
+  enabled_ = false;
+}
+
+void InterstitialPageImpl::Shutdown(RenderViewHostImpl* render_view_host) {
+  render_view_host->Shutdown();
+  // We are deleted now.
+}
+
+void InterstitialPageImpl::OnNavigatingAwayOrTabClosing() {
+  if (action_taken_ == NO_ACTION) {
+    // We are navigating away from the interstitial or closing a tab with an
+    // interstitial.  Default to DontProceed(). We don't just call Hide as
+    // subclasses will almost certainly override DontProceed to do some work
+    // (ex: close pending connections).
+    DontProceed();
+  } else {
+    // User decided to proceed and either the navigation was committed or
+    // the tab was closed before that.
+    Hide();
+  }
+}
+
+void InterstitialPageImpl::TakeActionOnResourceDispatcher(
+    ResourceRequestAction action) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) <<
+      "TakeActionOnResourceDispatcher should be called on the main thread.";
+
+  if (action == CANCEL || action == RESUME) {
+    if (resource_dispatcher_host_notified_)
+      return;
+    resource_dispatcher_host_notified_ = true;
+  }
+
+  // The tab might not have a render_view_host if it was closed (in which case,
+  // we have taken care of the blocked requests when processing
+  // NOTIFY_RENDER_WIDGET_HOST_DESTROYED.
+  // Also we need to test there is a ResourceDispatcherHostImpl, as when unit-
+  // tests we don't have one.
+  RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(original_child_id_,
+                                                       original_rvh_id_);
+  if (!rvh || !ResourceDispatcherHostImpl::Get())
+    return;
+
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(
+          &ResourceRequestHelper,
+          ResourceDispatcherHostImpl::Get(),
+          original_child_id_,
+          original_rvh_id_,
+          action));
+}
+
+InterstitialPageImpl::InterstitialPageRVHDelegateView::
+    InterstitialPageRVHDelegateView(InterstitialPageImpl* page)
+    : interstitial_page_(page) {
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::ShowPopupMenu(
+    const gfx::Rect& bounds,
+    int item_height,
+    double item_font_size,
+    int selected_item,
+    const std::vector<MenuItem>& items,
+    bool right_aligned,
+    bool allow_multiple_selection) {
+  NOTREACHED() << "InterstitialPage does not support showing popup menus.";
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::StartDragging(
+    const DropData& drop_data,
+    WebDragOperationsMask allowed_operations,
+    const gfx::ImageSkia& image,
+    const gfx::Vector2d& image_offset,
+    const DragEventSourceInfo& event_info) {
+  NOTREACHED() << "InterstitialPage does not support dragging yet.";
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::UpdateDragCursor(
+    WebDragOperation) {
+  NOTREACHED() << "InterstitialPage does not support dragging yet.";
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::GotFocus() {
+  WebContents* web_contents = interstitial_page_->web_contents();
+  if (web_contents && web_contents->GetDelegate())
+    web_contents->GetDelegate()->WebContentsFocused(web_contents);
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::TakeFocus(
+    bool reverse) {
+  if (!interstitial_page_->web_contents())
+    return;
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(interstitial_page_->web_contents());
+  if (!web_contents->GetDelegateView())
+    return;
+
+  web_contents->GetDelegateView()->TakeFocus(reverse);
+}
+
+void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply(
+    int request_id, int number_of_matches, const gfx::Rect& selection_rect,
+    int active_match_ordinal, bool final_update) {
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
new file mode 100644
index 0000000..66c0ca9
--- /dev/null
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -0,0 +1,267 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_INTERSTITIAL_PAGE_IMPL_H_
+#define CONTENT_BROWSER_FRAME_HOST_INTERSTITIAL_PAGE_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/public/browser/interstitial_page.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/renderer_preferences.h"
+#include "url/gurl.h"
+
+namespace content {
+class NavigationEntry;
+class NavigationControllerImpl;
+class RenderViewHostImpl;
+class RenderWidgetHostView;
+class WebContentsView;
+class WebContentsImpl;
+
+enum ResourceRequestAction {
+  BLOCK,
+  RESUME,
+  CANCEL
+};
+
+class CONTENT_EXPORT InterstitialPageImpl
+    : public NON_EXPORTED_BASE(InterstitialPage),
+      public NotificationObserver,
+      public WebContentsObserver,
+      public RenderViewHostDelegate,
+      public RenderWidgetHostDelegate {
+ public:
+  // The different state of actions the user can take in an interstitial.
+  enum ActionState {
+    NO_ACTION,           // No action has been taken yet.
+    PROCEED_ACTION,      // "Proceed" was selected.
+    DONT_PROCEED_ACTION  // "Don't proceed" was selected.
+  };
+
+  InterstitialPageImpl(WebContents* web_contents,
+                       RenderWidgetHostDelegate* render_widget_host_delegate,
+                       bool new_navigation,
+                       const GURL& url,
+                       InterstitialPageDelegate* delegate);
+  virtual ~InterstitialPageImpl();
+
+  // InterstitialPage implementation:
+  virtual void Show() OVERRIDE;
+  virtual void Hide() OVERRIDE;
+  virtual void DontProceed() OVERRIDE;
+  virtual void Proceed() OVERRIDE;
+  virtual RenderViewHost* GetRenderViewHostForTesting() const OVERRIDE;
+  virtual InterstitialPageDelegate* GetDelegateForTesting() OVERRIDE;
+  virtual void DontCreateViewForTesting() OVERRIDE;
+  virtual void SetSize(const gfx::Size& size) OVERRIDE;
+  virtual void Focus() OVERRIDE;
+
+  // Allows the user to navigate away by disabling the interstitial, canceling
+  // the pending request, and unblocking the hidden renderer.  The interstitial
+  // will stay visible until the navigation completes.
+  void CancelForNavigation();
+
+  // Focus the first (last if reverse is true) element in the interstitial page.
+  // Called when tab traversing.
+  void FocusThroughTabTraversal(bool reverse);
+
+  RenderWidgetHostView* GetView();
+
+  // See description above field.
+  void set_reload_on_dont_proceed(bool value) {
+    reload_on_dont_proceed_ = value;
+  }
+  bool reload_on_dont_proceed() const { return reload_on_dont_proceed_; }
+
+#if defined(OS_ANDROID)
+  // Android shares a single platform window for all tabs, so we need to expose
+  // the RenderViewHost to properly route gestures to the interstitial.
+  RenderViewHost* GetRenderViewHost() const;
+#endif
+
+ protected:
+  // NotificationObserver method:
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  // WebContentsObserver implementation:
+  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+  virtual void NavigationEntryCommitted(
+      const LoadCommittedDetails& load_details) OVERRIDE;
+
+  // RenderViewHostDelegate implementation:
+  virtual RenderViewHostDelegateView* GetDelegateView() OVERRIDE;
+  virtual const GURL& GetURL() const OVERRIDE;
+  virtual void RenderViewTerminated(RenderViewHost* render_view_host,
+                                    base::TerminationStatus status,
+                                    int error_code) OVERRIDE;
+  virtual void DidNavigate(
+      RenderViewHost* render_view_host,
+      const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE;
+  virtual void UpdateTitle(RenderViewHost* render_view_host,
+                           int32 page_id,
+                           const string16& title,
+                           base::i18n::TextDirection title_direction) OVERRIDE;
+  virtual RendererPreferences GetRendererPrefs(
+      BrowserContext* browser_context) const OVERRIDE;
+  virtual WebPreferences GetWebkitPrefs() OVERRIDE;
+  virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE;
+  virtual void CreateNewWindow(
+      int route_id,
+      int main_frame_route_id,
+      const ViewHostMsg_CreateWindow_Params& params,
+      SessionStorageNamespace* session_storage_namespace) OVERRIDE;
+  virtual void CreateNewWidget(int route_id,
+                               WebKit::WebPopupType popup_type) OVERRIDE;
+  virtual void CreateNewFullscreenWidget(int route_id) OVERRIDE;
+  virtual void ShowCreatedWindow(int route_id,
+                                 WindowOpenDisposition disposition,
+                                 const gfx::Rect& initial_pos,
+                                 bool user_gesture) OVERRIDE;
+  virtual void ShowCreatedWidget(int route_id,
+                                 const gfx::Rect& initial_pos) OVERRIDE;
+  virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
+
+  virtual SessionStorageNamespace* GetSessionStorageNamespace(
+      SiteInstance* instance) OVERRIDE;
+
+  virtual FrameTree* GetFrameTree() OVERRIDE;
+
+  // RenderWidgetHostDelegate implementation:
+  virtual void RenderWidgetDeleted(
+      RenderWidgetHostImpl* render_widget_host) OVERRIDE;
+  virtual bool PreHandleKeyboardEvent(
+      const NativeWebKeyboardEvent& event,
+      bool* is_keyboard_shortcut) OVERRIDE;
+  virtual void HandleKeyboardEvent(
+      const NativeWebKeyboardEvent& event) OVERRIDE;
+#if defined(OS_WIN) && defined(USE_AURA)
+  virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() OVERRIDE;
+#endif
+
+  bool enabled() const { return enabled_; }
+  WebContents* web_contents() const;
+  const GURL& url() const { return url_; }
+
+  // Creates the RenderViewHost containing the interstitial content.
+  // Overriden in unit tests.
+  virtual RenderViewHost* CreateRenderViewHost();
+
+  // Creates the WebContentsView that shows the interstitial RVH.
+  // Overriden in unit tests.
+  virtual WebContentsView* CreateWebContentsView();
+
+  // Notification magic.
+  NotificationRegistrar notification_registrar_;
+
+ private:
+  class InterstitialPageRVHDelegateView;
+
+  // Disable the interstitial:
+  // - if it is not yet showing, then it won't be shown.
+  // - any command sent by the RenderViewHost will be ignored.
+  void Disable();
+
+  // Shutdown the RVH.  We will be deleted by the time this method returns.
+  void Shutdown(RenderViewHostImpl* render_view_host);
+
+  void OnNavigatingAwayOrTabClosing();
+
+  // Executes the passed action on the ResourceDispatcher (on the IO thread).
+  // Used to block/resume/cancel requests for the RenderViewHost hidden by this
+  // interstitial.
+  void TakeActionOnResourceDispatcher(ResourceRequestAction action);
+
+  // The contents in which we are displayed.  This is valid until Hide is
+  // called, at which point it will be set to NULL because the WebContents
+  // itself may be deleted.
+  WebContents* web_contents_;
+
+  // The NavigationController for the content this page is being displayed over.
+  NavigationControllerImpl* controller_;
+
+  // Delegate for dispatching keyboard events and accessing the native view.
+  RenderWidgetHostDelegate* render_widget_host_delegate_;
+
+  // The URL that is shown when the interstitial is showing.
+  GURL url_;
+
+  // Whether this interstitial is shown as a result of a new navigation (in
+  // which case a transient navigation entry is created).
+  bool new_navigation_;
+
+  // Whether we should discard the pending navigation entry when not proceeding.
+  // This is to deal with cases where |new_navigation_| is true but a new
+  // pending entry was created since this interstitial was shown and we should
+  // not discard it.
+  bool should_discard_pending_nav_entry_;
+
+  // If true and the user chooses not to proceed the target NavigationController
+  // is reloaded. This is used when two NavigationControllers are merged
+  // (CopyStateFromAndPrune).
+  // The default is false.
+  bool reload_on_dont_proceed_;
+
+  // Whether this interstitial is enabled.  See Disable() for more info.
+  bool enabled_;
+
+  // Whether the Proceed or DontProceed methods have been called yet.
+  ActionState action_taken_;
+
+  // The RenderViewHost displaying the interstitial contents.  This is valid
+  // until Hide is called, at which point it will be set to NULL, signifying
+  // that shutdown has started.
+  RenderViewHostImpl* render_view_host_;
+
+  // The frame tree structure of the current page.
+  FrameTree frame_tree_;
+
+  // The IDs for the Render[View|Process]Host hidden by this interstitial.
+  int original_child_id_;
+  int original_rvh_id_;
+
+  // Whether or not we should change the title of the contents when hidden (to
+  // revert it to its original value).
+  bool should_revert_web_contents_title_;
+
+  // Whether or not the contents was loading resources when the interstitial was
+  // shown.  We restore this state if the user proceeds from the interstitial.
+  bool web_contents_was_loading_;
+
+  // Whether the ResourceDispatcherHost has been notified to cancel/resume the
+  // resource requests blocked for the RenderViewHost.
+  bool resource_dispatcher_host_notified_;
+
+  // The original title of the contents that should be reverted to when the
+  // interstitial is hidden.
+  string16 original_web_contents_title_;
+
+  // Our RenderViewHostViewDelegate, necessary for accelerators to work.
+  scoped_ptr<InterstitialPageRVHDelegateView> rvh_delegate_view_;
+
+  // Settings passed to the renderer.
+  mutable RendererPreferences renderer_preferences_;
+
+  bool create_view_;
+
+  scoped_ptr<InterstitialPageDelegate> delegate_;
+
+  base::WeakPtrFactory<InterstitialPageImpl> weak_ptr_factory_;
+
+  scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterstitialPageImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_INTERSTITIAL_PAGE_IMPL_H_
diff --git a/content/browser/frame_host/navigation_controller_delegate.h b/content/browser/frame_host/navigation_controller_delegate.h
new file mode 100644
index 0000000..cb3204c
--- /dev/null
+++ b/content/browser/frame_host/navigation_controller_delegate.h
@@ -0,0 +1,79 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_DELEGATE_H_
+#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_DELEGATE_H_
+
+#include <string>
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_details.h"
+
+namespace content {
+
+struct LoadCommittedDetails;
+struct LoadNotificationDetails;
+struct NativeWebKeyboardEvent;
+class InterstitialPage;
+class InterstitialPageImpl;
+class RenderViewHost;
+class SiteInstance;
+class WebContents;
+class WebContentsDelegate;
+
+// Interface for objects embedding a NavigationController to provide the
+// functionality NavigationController needs.
+// TODO(nasko): This interface should exist for short amount of time, while
+// we transition navigation code from WebContents to Navigator.
+class NavigationControllerDelegate {
+ public:
+  virtual ~NavigationControllerDelegate() {}
+
+  // Duplicates of WebContents methods.
+  virtual RenderViewHost* GetRenderViewHost() const = 0;
+  virtual InterstitialPage* GetInterstitialPage() const = 0;
+  virtual const std::string& GetContentsMimeType() const = 0;
+  virtual void NotifyNavigationStateChanged(unsigned changed_flags) = 0;
+  virtual void Stop() = 0;
+  virtual SiteInstance* GetSiteInstance() const = 0;
+  virtual SiteInstance* GetPendingSiteInstance() const = 0;
+  virtual int32 GetMaxPageID() = 0;
+  virtual int32 GetMaxPageIDForSiteInstance(SiteInstance* site_instance) = 0;
+  virtual bool IsLoading() const = 0;
+
+  // Methods from WebContentsImpl that NavigationControllerImpl needs to
+  // call.
+  virtual void NotifyBeforeFormRepostWarningShow() = 0;
+  virtual void NotifyNavigationEntryCommitted(
+      const LoadCommittedDetails& load_details) = 0;
+  virtual bool NavigateToPendingEntry(
+      NavigationController::ReloadType reload_type) = 0;
+  virtual void SetHistoryLengthAndPrune(
+      const SiteInstance* site_instance,
+      int merge_history_length,
+      int32 minimum_page_id) = 0;
+  virtual void CopyMaxPageIDsFrom(WebContents* web_contents) = 0;
+  virtual void UpdateMaxPageID(int32 page_id) = 0;
+  virtual void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
+                                              int32 page_id) = 0;
+  virtual void ActivateAndShowRepostFormWarningDialog() = 0;
+
+  // This method is needed, since we are no longer guaranteed that the
+  // embedder for NavigationController will be a WebContents object.
+  virtual WebContents* GetWebContents() = 0;
+
+  // Methods needed by InterstitialPageImpl.
+  virtual bool IsHidden() = 0;
+  virtual void RenderViewForInterstitialPageCreated(
+      RenderViewHost* render_view_host) = 0;
+  virtual void AttachInterstitialPage(
+      InterstitialPageImpl* interstitial_page) = 0;
+  virtual void DetachInterstitialPage() = 0;
+  virtual void SetIsLoading(RenderViewHost* render_view_host,
+                            bool is_loading,
+                            LoadNotificationDetails* details) = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_DELEGATE_H_
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
new file mode 100644
index 0000000..04c229a
--- /dev/null
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -0,0 +1,1700 @@
+// Copyright 2013 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/navigation_controller_impl.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"  // Temporary
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "content/browser/browser_url_handler_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/frame_host/debug_urls.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/web_contents_screenshot_manager.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"  // Temporary
+#include "content/browser/site_instance_impl.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/invalidate_type.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/user_metrics.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/url_constants.h"
+#include "net/base/escape.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace content {
+namespace {
+
+const int kInvalidateAll = 0xFFFFFFFF;
+
+// Invoked when entries have been pruned, or removed. For example, if the
+// current entries are [google, digg, yahoo], with the current entry google,
+// and the user types in cnet, then digg and yahoo are pruned.
+void NotifyPrunedEntries(NavigationControllerImpl* nav_controller,
+                         bool from_front,
+                         int count) {
+  PrunedDetails details;
+  details.from_front = from_front;
+  details.count = count;
+  NotificationService::current()->Notify(
+      NOTIFICATION_NAV_LIST_PRUNED,
+      Source<NavigationController>(nav_controller),
+      Details<PrunedDetails>(&details));
+}
+
+// Ensure the given NavigationEntry has a valid state, so that WebKit does not
+// get confused if we navigate back to it.
+//
+// An empty state is treated as a new navigation by WebKit, which would mean
+// losing the navigation entries and generating a new navigation entry after
+// this one. We don't want that. To avoid this we create a valid state which
+// WebKit will not treat as a new navigation.
+void SetPageStateIfEmpty(NavigationEntryImpl* entry) {
+  if (!entry->GetPageState().IsValid())
+    entry->SetPageState(PageState::CreateFromURL(entry->GetURL()));
+}
+
+NavigationEntryImpl::RestoreType ControllerRestoreTypeToEntryType(
+    NavigationController::RestoreType type) {
+  switch (type) {
+    case NavigationController::RESTORE_CURRENT_SESSION:
+      return NavigationEntryImpl::RESTORE_CURRENT_SESSION;
+    case NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY:
+      return NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY;
+    case NavigationController::RESTORE_LAST_SESSION_CRASHED:
+      return NavigationEntryImpl::RESTORE_LAST_SESSION_CRASHED;
+  }
+  NOTREACHED();
+  return NavigationEntryImpl::RESTORE_CURRENT_SESSION;
+}
+
+// Configure all the NavigationEntries in entries for restore. This resets
+// the transition type to reload and makes sure the content state isn't empty.
+void ConfigureEntriesForRestore(
+    std::vector<linked_ptr<NavigationEntryImpl> >* entries,
+    NavigationController::RestoreType type) {
+  for (size_t i = 0; i < entries->size(); ++i) {
+    // Use a transition type of reload so that we don't incorrectly increase
+    // the typed count.
+    (*entries)[i]->SetTransitionType(PAGE_TRANSITION_RELOAD);
+    (*entries)[i]->set_restore_type(ControllerRestoreTypeToEntryType(type));
+    // NOTE(darin): This code is only needed for backwards compat.
+    SetPageStateIfEmpty((*entries)[i].get());
+  }
+}
+
+// See NavigationController::IsURLInPageNavigation for how this works and why.
+bool AreURLsInPageNavigation(const GURL& existing_url,
+                             const GURL& new_url,
+                             bool renderer_says_in_page,
+                             NavigationType navigation_type) {
+  if (existing_url == new_url)
+    return renderer_says_in_page;
+
+  if (!new_url.has_ref()) {
+    // When going back from the ref URL to the non ref one the navigation type
+    // is IN_PAGE.
+    return navigation_type == NAVIGATION_TYPE_IN_PAGE;
+  }
+
+  url_canon::Replacements<char> replacements;
+  replacements.ClearRef();
+  return existing_url.ReplaceComponents(replacements) ==
+      new_url.ReplaceComponents(replacements);
+}
+
+// Determines whether or not we should be carrying over a user agent override
+// between two NavigationEntries.
+bool ShouldKeepOverride(const NavigationEntry* last_entry) {
+  return last_entry && last_entry->GetIsOverridingUserAgent();
+}
+
+}  // namespace
+
+// NavigationControllerImpl ----------------------------------------------------
+
+const size_t kMaxEntryCountForTestingNotSet = -1;
+
+// static
+size_t NavigationControllerImpl::max_entry_count_for_testing_ =
+    kMaxEntryCountForTestingNotSet;
+
+// Should Reload check for post data? The default is true, but is set to false
+// when testing.
+static bool g_check_for_repost = true;
+
+// static
+NavigationEntry* NavigationController::CreateNavigationEntry(
+      const GURL& url,
+      const Referrer& referrer,
+      PageTransition transition,
+      bool is_renderer_initiated,
+      const std::string& extra_headers,
+      BrowserContext* browser_context) {
+  // Allow the browser URL handler to rewrite the URL. This will, for example,
+  // remove "view-source:" from the beginning of the URL to get the URL that
+  // will actually be loaded. This real URL won't be shown to the user, just
+  // used internally.
+  GURL loaded_url(url);
+  bool reverse_on_redirect = false;
+  BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
+      &loaded_url, browser_context, &reverse_on_redirect);
+
+  NavigationEntryImpl* entry = new NavigationEntryImpl(
+      NULL,  // The site instance for tabs is sent on navigation
+             // (WebContents::GetSiteInstance).
+      -1,
+      loaded_url,
+      referrer,
+      string16(),
+      transition,
+      is_renderer_initiated);
+  entry->SetVirtualURL(url);
+  entry->set_user_typed_url(url);
+  entry->set_update_virtual_url_with_url(reverse_on_redirect);
+  entry->set_extra_headers(extra_headers);
+  return entry;
+}
+
+// static
+void NavigationController::DisablePromptOnRepost() {
+  g_check_for_repost = false;
+}
+
+base::Time NavigationControllerImpl::TimeSmoother::GetSmoothedTime(
+    base::Time t) {
+  // If |t| is between the water marks, we're in a run of duplicates
+  // or just getting out of it, so increase the high-water mark to get
+  // a time that probably hasn't been used before and return it.
+  if (low_water_mark_ <= t && t <= high_water_mark_) {
+    high_water_mark_ += base::TimeDelta::FromMicroseconds(1);
+    return high_water_mark_;
+  }
+
+  // Otherwise, we're clear of the last duplicate run, so reset the
+  // water marks.
+  low_water_mark_ = high_water_mark_ = t;
+  return t;
+}
+
+NavigationControllerImpl::NavigationControllerImpl(
+    NavigationControllerDelegate* delegate,
+    BrowserContext* browser_context)
+    : browser_context_(browser_context),
+      pending_entry_(NULL),
+      last_committed_entry_index_(-1),
+      pending_entry_index_(-1),
+      transient_entry_index_(-1),
+      delegate_(delegate),
+      max_restored_page_id_(-1),
+      ssl_manager_(this),
+      needs_reload_(false),
+      is_initial_navigation_(true),
+      pending_reload_(NO_RELOAD),
+      get_timestamp_callback_(base::Bind(&base::Time::Now)),
+      screenshot_manager_(new WebContentsScreenshotManager(this)) {
+  DCHECK(browser_context_);
+}
+
+NavigationControllerImpl::~NavigationControllerImpl() {
+  DiscardNonCommittedEntriesInternal();
+}
+
+WebContents* NavigationControllerImpl::GetWebContents() const {
+  return delegate_->GetWebContents();
+}
+
+BrowserContext* NavigationControllerImpl::GetBrowserContext() const {
+  return browser_context_;
+}
+
+void NavigationControllerImpl::SetBrowserContext(
+    BrowserContext* browser_context) {
+  browser_context_ = browser_context;
+}
+
+void NavigationControllerImpl::Restore(
+    int selected_navigation,
+    RestoreType type,
+    std::vector<NavigationEntry*>* entries) {
+  // Verify that this controller is unused and that the input is valid.
+  DCHECK(GetEntryCount() == 0 && !GetPendingEntry());
+  DCHECK(selected_navigation >= 0 &&
+         selected_navigation < static_cast<int>(entries->size()));
+
+  needs_reload_ = true;
+  for (size_t i = 0; i < entries->size(); ++i) {
+    NavigationEntryImpl* entry =
+        NavigationEntryImpl::FromNavigationEntry((*entries)[i]);
+    entries_.push_back(linked_ptr<NavigationEntryImpl>(entry));
+  }
+  entries->clear();
+
+  // And finish the restore.
+  FinishRestore(selected_navigation, type);
+}
+
+void NavigationControllerImpl::Reload(bool check_for_repost) {
+  ReloadInternal(check_for_repost, RELOAD);
+}
+void NavigationControllerImpl::ReloadIgnoringCache(bool check_for_repost) {
+  ReloadInternal(check_for_repost, RELOAD_IGNORING_CACHE);
+}
+void NavigationControllerImpl::ReloadOriginalRequestURL(bool check_for_repost) {
+  ReloadInternal(check_for_repost, RELOAD_ORIGINAL_REQUEST_URL);
+}
+
+void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
+                                              ReloadType reload_type) {
+  if (transient_entry_index_ != -1) {
+    // If an interstitial is showing, treat a reload as a navigation to the
+    // transient entry's URL.
+    NavigationEntryImpl* transient_entry =
+        NavigationEntryImpl::FromNavigationEntry(GetTransientEntry());
+    if (!transient_entry)
+      return;
+    LoadURL(transient_entry->GetURL(),
+            Referrer(),
+            PAGE_TRANSITION_RELOAD,
+            transient_entry->extra_headers());
+    return;
+  }
+
+  NavigationEntryImpl* entry = NULL;
+  int current_index = -1;
+
+  // If we are reloading the initial navigation, just use the current
+  // pending entry.  Otherwise look up the current entry.
+  if (IsInitialNavigation() && pending_entry_) {
+    entry = pending_entry_;
+    // The pending entry might be in entries_ (e.g., after a Clone), so we
+    // should also update the current_index.
+    current_index = pending_entry_index_;
+  } else {
+    DiscardNonCommittedEntriesInternal();
+    current_index = GetCurrentEntryIndex();
+    if (current_index != -1) {
+      entry = NavigationEntryImpl::FromNavigationEntry(
+          GetEntryAtIndex(current_index));
+    }
+  }
+
+  // If we are no where, then we can't reload.  TODO(darin): We should add a
+  // CanReload method.
+  if (!entry)
+    return;
+
+  if (reload_type == NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL &&
+      entry->GetOriginalRequestURL().is_valid() && !entry->GetHasPostData()) {
+    // We may have been redirected when navigating to the current URL.
+    // Use the URL the user originally intended to visit, if it's valid and if a
+    // POST wasn't involved; the latter case avoids issues with sending data to
+    // the wrong page.
+    entry->SetURL(entry->GetOriginalRequestURL());
+  }
+
+  if (g_check_for_repost && check_for_repost &&
+      entry->GetHasPostData()) {
+    // The user is asking to reload a page with POST data. Prompt to make sure
+    // they really want to do this. If they do, the dialog will call us back
+    // with check_for_repost = false.
+    delegate_->NotifyBeforeFormRepostWarningShow();
+
+    pending_reload_ = reload_type;
+    delegate_->ActivateAndShowRepostFormWarningDialog();
+  } else {
+    if (!IsInitialNavigation())
+      DiscardNonCommittedEntriesInternal();
+
+    // If we are reloading an entry that no longer belongs to the current
+    // site instance (for example, refreshing a page for just installed app),
+    // the reload must happen in a new process.
+    // The new entry must have a new page_id and site instance, so it behaves
+    // as new navigation (which happens to clear forward history).
+    // Tabs that are discarded due to low memory conditions may not have a site
+    // instance, and should not be treated as a cross-site reload.
+    SiteInstanceImpl* site_instance = entry->site_instance();
+    if (site_instance &&
+        site_instance->HasWrongProcessForURL(entry->GetURL())) {
+      // Create a navigation entry that resembles the current one, but do not
+      // copy page id, site instance, content state, or timestamp.
+      NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry(
+          CreateNavigationEntry(
+              entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(),
+              false, entry->extra_headers(), browser_context_));
+
+      // Mark the reload type as NO_RELOAD, so navigation will not be considered
+      // a reload in the renderer.
+      reload_type = NavigationController::NO_RELOAD;
+
+      nav_entry->set_should_replace_entry(true);
+      pending_entry_ = nav_entry;
+    } else {
+      pending_entry_ = entry;
+      pending_entry_index_ = current_index;
+
+      // The title of the page being reloaded might have been removed in the
+      // meanwhile, so we need to revert to the default title upon reload and
+      // invalidate the previously cached title (SetTitle will do both).
+      // See Chromium issue 96041.
+      pending_entry_->SetTitle(string16());
+
+      pending_entry_->SetTransitionType(PAGE_TRANSITION_RELOAD);
+    }
+
+    NavigateToPendingEntry(reload_type);
+  }
+}
+
+void NavigationControllerImpl::CancelPendingReload() {
+  DCHECK(pending_reload_ != NO_RELOAD);
+  pending_reload_ = NO_RELOAD;
+}
+
+void NavigationControllerImpl::ContinuePendingReload() {
+  if (pending_reload_ == NO_RELOAD) {
+    NOTREACHED();
+  } else {
+    ReloadInternal(false, pending_reload_);
+    pending_reload_ = NO_RELOAD;
+  }
+}
+
+bool NavigationControllerImpl::IsInitialNavigation() const {
+  return is_initial_navigation_;
+}
+
+NavigationEntryImpl* NavigationControllerImpl::GetEntryWithPageID(
+  SiteInstance* instance, int32 page_id) const {
+  int index = GetEntryIndexWithPageID(instance, page_id);
+  return (index != -1) ? entries_[index].get() : NULL;
+}
+
+void NavigationControllerImpl::LoadEntry(NavigationEntryImpl* entry) {
+  // When navigating to a new page, we don't know for sure if we will actually
+  // end up leaving the current page.  The new page load could for example
+  // result in a download or a 'no content' response (e.g., a mailto: URL).
+  SetPendingEntry(entry);
+  NavigateToPendingEntry(NO_RELOAD);
+}
+
+void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) {
+  DiscardNonCommittedEntriesInternal();
+  pending_entry_ = entry;
+  NotificationService::current()->Notify(
+      NOTIFICATION_NAV_ENTRY_PENDING,
+      Source<NavigationController>(this),
+      Details<NavigationEntry>(entry));
+}
+
+NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
+  if (transient_entry_index_ != -1)
+    return entries_[transient_entry_index_].get();
+  if (pending_entry_)
+    return pending_entry_;
+  return GetLastCommittedEntry();
+}
+
+NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
+  if (transient_entry_index_ != -1)
+    return entries_[transient_entry_index_].get();
+  // The pending entry is safe to return for new (non-history), browser-
+  // initiated navigations.  Most renderer-initiated navigations should not
+  // show the pending entry, to prevent URL spoof attacks.
+  //
+  // We make an exception for renderer-initiated navigations in new tabs, as
+  // long as no other page has tried to access the initial empty document in
+  // the new tab.  If another page modifies this blank page, a URL spoof is
+  // possible, so we must stop showing the pending entry.
+  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
+      delegate_->GetRenderViewHost());
+  bool safe_to_show_pending =
+      pending_entry_ &&
+      // Require a new navigation.
+      pending_entry_->GetPageID() == -1 &&
+      // Require either browser-initiated or an unmodified new tab.
+      (!pending_entry_->is_renderer_initiated() ||
+       (IsInitialNavigation() &&
+        !GetLastCommittedEntry() &&
+        !rvh->has_accessed_initial_document()));
+
+  // Also allow showing the pending entry for history navigations in a new tab,
+  // such as Ctrl+Back.  In this case, no existing page is visible and no one
+  // can script the new tab before it commits.
+  if (!safe_to_show_pending &&
+      pending_entry_ &&
+      pending_entry_->GetPageID() != -1 &&
+      IsInitialNavigation() &&
+      !pending_entry_->is_renderer_initiated())
+    safe_to_show_pending = true;
+
+  if (safe_to_show_pending)
+    return pending_entry_;
+  return GetLastCommittedEntry();
+}
+
+int NavigationControllerImpl::GetCurrentEntryIndex() const {
+  if (transient_entry_index_ != -1)
+    return transient_entry_index_;
+  if (pending_entry_index_ != -1)
+    return pending_entry_index_;
+  return last_committed_entry_index_;
+}
+
+NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
+  if (last_committed_entry_index_ == -1)
+    return NULL;
+  return entries_[last_committed_entry_index_].get();
+}
+
+bool NavigationControllerImpl::CanViewSource() const {
+  const std::string& mime_type = delegate_->GetContentsMimeType();
+  bool is_viewable_mime_type = net::IsSupportedNonImageMimeType(mime_type) &&
+      !net::IsSupportedMediaMimeType(mime_type);
+  NavigationEntry* visible_entry = GetVisibleEntry();
+  return visible_entry && !visible_entry->IsViewSourceMode() &&
+      is_viewable_mime_type && !delegate_->GetInterstitialPage();
+}
+
+int NavigationControllerImpl::GetLastCommittedEntryIndex() const {
+  return last_committed_entry_index_;
+}
+
+int NavigationControllerImpl::GetEntryCount() const {
+  DCHECK(entries_.size() <= max_entry_count());
+  return static_cast<int>(entries_.size());
+}
+
+NavigationEntry* NavigationControllerImpl::GetEntryAtIndex(
+    int index) const {
+  return entries_.at(index).get();
+}
+
+NavigationEntry* NavigationControllerImpl::GetEntryAtOffset(
+    int offset) const {
+  int index = GetIndexForOffset(offset);
+  if (index < 0 || index >= GetEntryCount())
+    return NULL;
+
+  return entries_[index].get();
+}
+
+int NavigationControllerImpl::GetIndexForOffset(int offset) const {
+  return GetCurrentEntryIndex() + offset;
+}
+
+void NavigationControllerImpl::TakeScreenshot() {
+  screenshot_manager_->TakeScreenshot();
+}
+
+void NavigationControllerImpl::SetScreenshotManager(
+    WebContentsScreenshotManager* manager) {
+  screenshot_manager_.reset(manager ? manager :
+                            new WebContentsScreenshotManager(this));
+}
+
+bool NavigationControllerImpl::CanGoBack() const {
+  return entries_.size() > 1 && GetCurrentEntryIndex() > 0;
+}
+
+bool NavigationControllerImpl::CanGoForward() const {
+  int index = GetCurrentEntryIndex();
+  return index >= 0 && index < (static_cast<int>(entries_.size()) - 1);
+}
+
+bool NavigationControllerImpl::CanGoToOffset(int offset) const {
+  int index = GetIndexForOffset(offset);
+  return index >= 0 && index < GetEntryCount();
+}
+
+void NavigationControllerImpl::GoBack() {
+  if (!CanGoBack()) {
+    NOTREACHED();
+    return;
+  }
+
+  // Base the navigation on where we are now...
+  int current_index = GetCurrentEntryIndex();
+
+  DiscardNonCommittedEntries();
+
+  pending_entry_index_ = current_index - 1;
+  entries_[pending_entry_index_]->SetTransitionType(
+      PageTransitionFromInt(
+          entries_[pending_entry_index_]->GetTransitionType() |
+          PAGE_TRANSITION_FORWARD_BACK));
+  NavigateToPendingEntry(NO_RELOAD);
+}
+
+void NavigationControllerImpl::GoForward() {
+  if (!CanGoForward()) {
+    NOTREACHED();
+    return;
+  }
+
+  bool transient = (transient_entry_index_ != -1);
+
+  // Base the navigation on where we are now...
+  int current_index = GetCurrentEntryIndex();
+
+  DiscardNonCommittedEntries();
+
+  pending_entry_index_ = current_index;
+  // If there was a transient entry, we removed it making the current index
+  // the next page.
+  if (!transient)
+    pending_entry_index_++;
+
+  entries_[pending_entry_index_]->SetTransitionType(
+      PageTransitionFromInt(
+          entries_[pending_entry_index_]->GetTransitionType() |
+          PAGE_TRANSITION_FORWARD_BACK));
+  NavigateToPendingEntry(NO_RELOAD);
+}
+
+void NavigationControllerImpl::GoToIndex(int index) {
+  if (index < 0 || index >= static_cast<int>(entries_.size())) {
+    NOTREACHED();
+    return;
+  }
+
+  if (transient_entry_index_ != -1) {
+    if (index == transient_entry_index_) {
+      // Nothing to do when navigating to the transient.
+      return;
+    }
+    if (index > transient_entry_index_) {
+      // Removing the transient is goint to shift all entries by 1.
+      index--;
+    }
+  }
+
+  DiscardNonCommittedEntries();
+
+  pending_entry_index_ = index;
+  entries_[pending_entry_index_]->SetTransitionType(
+      PageTransitionFromInt(
+          entries_[pending_entry_index_]->GetTransitionType() |
+          PAGE_TRANSITION_FORWARD_BACK));
+  NavigateToPendingEntry(NO_RELOAD);
+}
+
+void NavigationControllerImpl::GoToOffset(int offset) {
+  if (!CanGoToOffset(offset))
+    return;
+
+  GoToIndex(GetIndexForOffset(offset));
+}
+
+bool NavigationControllerImpl::RemoveEntryAtIndex(int index) {
+  if (index == last_committed_entry_index_ ||
+      index == pending_entry_index_)
+    return false;
+
+  RemoveEntryAtIndexInternal(index);
+  return true;
+}
+
+void NavigationControllerImpl::UpdateVirtualURLToURL(
+    NavigationEntryImpl* entry, const GURL& new_url) {
+  GURL new_virtual_url(new_url);
+  if (BrowserURLHandlerImpl::GetInstance()->ReverseURLRewrite(
+          &new_virtual_url, entry->GetVirtualURL(), browser_context_)) {
+    entry->SetVirtualURL(new_virtual_url);
+  }
+}
+
+void NavigationControllerImpl::LoadURL(
+    const GURL& url,
+    const Referrer& referrer,
+    PageTransition transition,
+    const std::string& extra_headers) {
+  LoadURLParams params(url);
+  params.referrer = referrer;
+  params.transition_type = transition;
+  params.extra_headers = extra_headers;
+  LoadURLWithParams(params);
+}
+
+void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
+  TRACE_EVENT0("browser", "NavigationControllerImpl::LoadURLWithParams");
+  if (HandleDebugURL(params.url, params.transition_type))
+    return;
+
+  // Checks based on params.load_type.
+  switch (params.load_type) {
+    case LOAD_TYPE_DEFAULT:
+      break;
+    case LOAD_TYPE_BROWSER_INITIATED_HTTP_POST:
+      if (!params.url.SchemeIs(kHttpScheme) &&
+          !params.url.SchemeIs(kHttpsScheme)) {
+        NOTREACHED() << "Http post load must use http(s) scheme.";
+        return;
+      }
+      break;
+    case LOAD_TYPE_DATA:
+      if (!params.url.SchemeIs(chrome::kDataScheme)) {
+        NOTREACHED() << "Data load must use data scheme.";
+        return;
+      }
+      break;
+    default:
+      NOTREACHED();
+      break;
+  };
+
+  // The user initiated a load, we don't need to reload anymore.
+  needs_reload_ = false;
+
+  bool override = false;
+  switch (params.override_user_agent) {
+    case UA_OVERRIDE_INHERIT:
+      override = ShouldKeepOverride(GetLastCommittedEntry());
+      break;
+    case UA_OVERRIDE_TRUE:
+      override = true;
+      break;
+    case UA_OVERRIDE_FALSE:
+      override = false;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+      CreateNavigationEntry(
+          params.url,
+          params.referrer,
+          params.transition_type,
+          params.is_renderer_initiated,
+          params.extra_headers,
+          browser_context_));
+  if (params.redirect_chain.size() > 0)
+    entry->set_redirect_chain(params.redirect_chain);
+  if (params.should_replace_current_entry)
+    entry->set_should_replace_entry(true);
+  entry->set_should_clear_history_list(params.should_clear_history_list);
+  entry->SetIsOverridingUserAgent(override);
+  entry->set_transferred_global_request_id(
+      params.transferred_global_request_id);
+  entry->SetFrameToNavigate(params.frame_name);
+
+  switch (params.load_type) {
+    case LOAD_TYPE_DEFAULT:
+      break;
+    case LOAD_TYPE_BROWSER_INITIATED_HTTP_POST:
+      entry->SetHasPostData(true);
+      entry->SetBrowserInitiatedPostData(
+          params.browser_initiated_post_data.get());
+      break;
+    case LOAD_TYPE_DATA:
+      entry->SetBaseURLForDataURL(params.base_url_for_data_url);
+      entry->SetVirtualURL(params.virtual_url_for_data_url);
+      entry->SetCanLoadLocalResources(params.can_load_local_resources);
+      break;
+    default:
+      NOTREACHED();
+      break;
+  };
+
+  LoadEntry(entry);
+}
+
+bool NavigationControllerImpl::RendererDidNavigate(
+    const ViewHostMsg_FrameNavigate_Params& params,
+    LoadCommittedDetails* details) {
+  is_initial_navigation_ = false;
+
+  // Save the previous state before we clobber it.
+  if (GetLastCommittedEntry()) {
+    details->previous_url = GetLastCommittedEntry()->GetURL();
+    details->previous_entry_index = GetLastCommittedEntryIndex();
+  } else {
+    details->previous_url = GURL();
+    details->previous_entry_index = -1;
+  }
+
+  // If we have a pending entry at this point, it should have a SiteInstance.
+  // Restored entries start out with a null SiteInstance, but we should have
+  // assigned one in NavigateToPendingEntry.
+  DCHECK(pending_entry_index_ == -1 || pending_entry_->site_instance());
+
+  // If we are doing a cross-site reload, we need to replace the existing
+  // navigation entry, not add another entry to the history. This has the side
+  // effect of removing forward browsing history, if such existed.
+  // Or if we are doing a cross-site redirect navigation,
+  // we will do a similar thing.
+  details->did_replace_entry =
+      pending_entry_ && pending_entry_->should_replace_entry();
+
+  // Do navigation-type specific actions. These will make and commit an entry.
+  details->type = ClassifyNavigation(params);
+
+  // is_in_page must be computed before the entry gets committed.
+  details->is_in_page = IsURLInPageNavigation(
+      params.url, params.was_within_same_page, details->type);
+
+  switch (details->type) {
+    case NAVIGATION_TYPE_NEW_PAGE:
+      RendererDidNavigateToNewPage(params, details->did_replace_entry);
+      break;
+    case NAVIGATION_TYPE_EXISTING_PAGE:
+      RendererDidNavigateToExistingPage(params);
+      break;
+    case NAVIGATION_TYPE_SAME_PAGE:
+      RendererDidNavigateToSamePage(params);
+      break;
+    case NAVIGATION_TYPE_IN_PAGE:
+      RendererDidNavigateInPage(params, &details->did_replace_entry);
+      break;
+    case NAVIGATION_TYPE_NEW_SUBFRAME:
+      RendererDidNavigateNewSubframe(params);
+      break;
+    case NAVIGATION_TYPE_AUTO_SUBFRAME:
+      if (!RendererDidNavigateAutoSubframe(params))
+        return false;
+      break;
+    case NAVIGATION_TYPE_NAV_IGNORE:
+      // If a pending navigation was in progress, this canceled it.  We should
+      // discard it and make sure it is removed from the URL bar.  After that,
+      // there is nothing we can do with this navigation, so we just return to
+      // the caller that nothing has happened.
+      if (pending_entry_) {
+        DiscardNonCommittedEntries();
+        delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
+      }
+      return false;
+    default:
+      NOTREACHED();
+  }
+
+  // At this point, we know that the navigation has just completed, so
+  // record the time.
+  //
+  // TODO(akalin): Use "sane time" as described in
+  // http://www.chromium.org/developers/design-documents/sane-time .
+  base::Time timestamp =
+      time_smoother_.GetSmoothedTime(get_timestamp_callback_.Run());
+  DVLOG(1) << "Navigation finished at (smoothed) timestamp "
+           << timestamp.ToInternalValue();
+
+  // We should not have a pending entry anymore.  Clear it again in case any
+  // error cases above forgot to do so.
+  DiscardNonCommittedEntriesInternal();
+
+  // All committed entries should have nonempty content state so WebKit doesn't
+  // get confused when we go back to them (see the function for details).
+  DCHECK(params.page_state.IsValid());
+  NavigationEntryImpl* active_entry =
+      NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
+  active_entry->SetTimestamp(timestamp);
+  active_entry->SetHttpStatusCode(params.http_status_code);
+  active_entry->SetPageState(params.page_state);
+
+  // Once it is committed, we no longer need to track several pieces of state on
+  // the entry.
+  active_entry->ResetForCommit();
+
+  // The active entry's SiteInstance should match our SiteInstance.
+  CHECK(active_entry->site_instance() == delegate_->GetSiteInstance());
+
+  // Remember the bindings the renderer process has at this point, so that
+  // we do not grant this entry additional bindings if we come back to it.
+  active_entry->SetBindings(
+      delegate_->GetRenderViewHost()->GetEnabledBindings());
+
+  // Now prep the rest of the details for the notification and broadcast.
+  details->entry = active_entry;
+  details->is_main_frame =
+      PageTransitionIsMainFrame(params.transition);
+  details->serialized_security_info = params.security_info;
+  details->http_status_code = params.http_status_code;
+  NotifyNavigationEntryCommitted(details);
+
+  return true;
+}
+
+NavigationType NavigationControllerImpl::ClassifyNavigation(
+    const ViewHostMsg_FrameNavigate_Params& params) const {
+  if (params.page_id == -1) {
+    // The renderer generates the page IDs, and so if it gives us the invalid
+    // page ID (-1) we know it didn't actually navigate. This happens in a few
+    // cases:
+    //
+    // - If a page makes a popup navigated to about blank, and then writes
+    //   stuff like a subframe navigated to a real page. We'll get the commit
+    //   for the subframe, but there won't be any commit for the outer page.
+    //
+    // - We were also getting these for failed loads (for example, bug 21849).
+    //   The guess is that we get a "load commit" for the alternate error page,
+    //   but that doesn't affect the page ID, so we get the "old" one, which
+    //   could be invalid. This can also happen for a cross-site transition
+    //   that causes us to swap processes. Then the error page load will be in
+    //   a new process with no page IDs ever assigned (and hence a -1 value),
+    //   yet the navigation controller still might have previous pages in its
+    //   list.
+    //
+    // In these cases, there's nothing we can do with them, so ignore.
+    return NAVIGATION_TYPE_NAV_IGNORE;
+  }
+
+  if (params.page_id > delegate_->GetMaxPageID()) {
+    // Greater page IDs than we've ever seen before are new pages. We may or may
+    // not have a pending entry for the page, and this may or may not be the
+    // main frame.
+    if (PageTransitionIsMainFrame(params.transition))
+      return NAVIGATION_TYPE_NEW_PAGE;
+
+    // When this is a new subframe navigation, we should have a committed page
+    // for which it's a suframe in. This may not be the case when an iframe is
+    // navigated on a popup navigated to about:blank (the iframe would be
+    // written into the popup by script on the main page). For these cases,
+    // there isn't any navigation stuff we can do, so just ignore it.
+    if (!GetLastCommittedEntry())
+      return NAVIGATION_TYPE_NAV_IGNORE;
+
+    // Valid subframe navigation.
+    return NAVIGATION_TYPE_NEW_SUBFRAME;
+  }
+
+  // We only clear the session history when navigating to a new page.
+  DCHECK(!params.history_list_was_cleared);
+
+  // Now we know that the notification is for an existing page. Find that entry.
+  int existing_entry_index = GetEntryIndexWithPageID(
+      delegate_->GetSiteInstance(),
+      params.page_id);
+  if (existing_entry_index == -1) {
+    // The page was not found. It could have been pruned because of the limit on
+    // back/forward entries (not likely since we'll usually tell it to navigate
+    // to such entries). It could also mean that the renderer is smoking crack.
+    NOTREACHED();
+
+    // Because the unknown entry has committed, we risk showing the wrong URL in
+    // release builds. Instead, we'll kill the renderer process to be safe.
+    LOG(ERROR) << "terminating renderer for bad navigation: " << params.url;
+    RecordAction(UserMetricsAction("BadMessageTerminate_NC"));
+
+    // Temporary code so we can get more information.  Format:
+    //  http://url/foo.html#page1#max3#frame1#ids:2_Nx,1_1x,3_2
+    std::string temp = params.url.spec();
+    temp.append("#page");
+    temp.append(base::IntToString(params.page_id));
+    temp.append("#max");
+    temp.append(base::IntToString(delegate_->GetMaxPageID()));
+    temp.append("#frame");
+    temp.append(base::IntToString(params.frame_id));
+    temp.append("#ids");
+    for (int i = 0; i < static_cast<int>(entries_.size()); ++i) {
+      // Append entry metadata (e.g., 3_7x):
+      //  3: page_id
+      //  7: SiteInstance ID, or N for null
+      //  x: appended if not from the current SiteInstance
+      temp.append(base::IntToString(entries_[i]->GetPageID()));
+      temp.append("_");
+      if (entries_[i]->site_instance())
+        temp.append(base::IntToString(entries_[i]->site_instance()->GetId()));
+      else
+        temp.append("N");
+      if (entries_[i]->site_instance() != delegate_->GetSiteInstance())
+        temp.append("x");
+      temp.append(",");
+    }
+    GURL url(temp);
+    static_cast<RenderViewHostImpl*>(
+        delegate_->GetRenderViewHost())->Send(
+            new ViewMsg_TempCrashWithData(url));
+    return NAVIGATION_TYPE_NAV_IGNORE;
+  }
+  NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
+
+  if (!PageTransitionIsMainFrame(params.transition)) {
+    // All manual subframes would get new IDs and were handled above, so we
+    // know this is auto. Since the current page was found in the navigation
+    // entry list, we're guaranteed to have a last committed entry.
+    DCHECK(GetLastCommittedEntry());
+    return NAVIGATION_TYPE_AUTO_SUBFRAME;
+  }
+
+  // Anything below here we know is a main frame navigation.
+  if (pending_entry_ &&
+      !pending_entry_->is_renderer_initiated() &&
+      existing_entry != pending_entry_ &&
+      pending_entry_->GetPageID() == -1 &&
+      existing_entry == GetLastCommittedEntry()) {
+    // In this case, we have a pending entry for a URL but WebCore didn't do a
+    // new navigation. This happens when you press enter in the URL bar to
+    // reload. We will create a pending entry, but WebKit will convert it to
+    // a reload since it's the same page and not create a new entry for it
+    // (the user doesn't want to have a new back/forward entry when they do
+    // this). If this matches the last committed entry, we want to just ignore
+    // the pending entry and go back to where we were (the "existing entry").
+    return NAVIGATION_TYPE_SAME_PAGE;
+  }
+
+  // Any toplevel navigations with the same base (minus the reference fragment)
+  // are in-page navigations. We weeded out subframe navigations above. Most of
+  // the time this doesn't matter since WebKit doesn't tell us about subframe
+  // navigations that don't actually navigate, but it can happen when there is
+  // an encoding override (it always sends a navigation request).
+  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
+                              params.was_within_same_page,
+                              NAVIGATION_TYPE_UNKNOWN)) {
+    return NAVIGATION_TYPE_IN_PAGE;
+  }
+
+  // Since we weeded out "new" navigations above, we know this is an existing
+  // (back/forward) navigation.
+  return NAVIGATION_TYPE_EXISTING_PAGE;
+}
+
+bool NavigationControllerImpl::IsRedirect(
+  const ViewHostMsg_FrameNavigate_Params& params) {
+  // For main frame transition, we judge by params.transition.
+  // Otherwise, by params.redirects.
+  if (PageTransitionIsMainFrame(params.transition)) {
+    return PageTransitionIsRedirect(params.transition);
+  }
+  return params.redirects.size() > 1;
+}
+
+void NavigationControllerImpl::RendererDidNavigateToNewPage(
+    const ViewHostMsg_FrameNavigate_Params& params, bool replace_entry) {
+  NavigationEntryImpl* new_entry;
+  bool update_virtual_url;
+  // Only make a copy of the pending entry if it is appropriate for the new page
+  // that was just loaded.  We verify this at a coarse grain by checking that
+  // the SiteInstance hasn't been assigned to something else.
+  if (pending_entry_ &&
+      (!pending_entry_->site_instance() ||
+       pending_entry_->site_instance() == delegate_->GetSiteInstance())) {
+    new_entry = new NavigationEntryImpl(*pending_entry_);
+
+    // Don't use the page type from the pending entry. Some interstitial page
+    // may have set the type to interstitial. Once we commit, however, the page
+    // type must always be normal.
+    new_entry->set_page_type(PAGE_TYPE_NORMAL);
+    update_virtual_url = new_entry->update_virtual_url_with_url();
+  } else {
+    new_entry = new NavigationEntryImpl;
+
+    // Find out whether the new entry needs to update its virtual URL on URL
+    // change and set up the entry accordingly. This is needed to correctly
+    // update the virtual URL when replaceState is called after a pushState.
+    GURL url = params.url;
+    bool needs_update = false;
+    BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
+        &url, browser_context_, &needs_update);
+    new_entry->set_update_virtual_url_with_url(needs_update);
+
+    // When navigating to a new page, give the browser URL handler a chance to
+    // update the virtual URL based on the new URL. For example, this is needed
+    // to show chrome://bookmarks/#1 when the bookmarks webui extension changes
+    // the URL.
+    update_virtual_url = needs_update;
+  }
+
+  new_entry->SetURL(params.url);
+  if (update_virtual_url)
+    UpdateVirtualURLToURL(new_entry, params.url);
+  new_entry->SetReferrer(params.referrer);
+  new_entry->SetPageID(params.page_id);
+  new_entry->SetTransitionType(params.transition);
+  new_entry->set_site_instance(
+      static_cast<SiteInstanceImpl*>(delegate_->GetSiteInstance()));
+  new_entry->SetHasPostData(params.is_post);
+  new_entry->SetPostID(params.post_id);
+  new_entry->SetOriginalRequestURL(params.original_request_url);
+  new_entry->SetIsOverridingUserAgent(params.is_overriding_user_agent);
+
+  DCHECK(!params.history_list_was_cleared || !replace_entry);
+  // The browser requested to clear the session history when it initiated the
+  // navigation. Now we know that the renderer has updated its state accordingly
+  // and it is safe to also clear the browser side history.
+  if (params.history_list_was_cleared) {
+    DiscardNonCommittedEntriesInternal();
+    entries_.clear();
+    last_committed_entry_index_ = -1;
+  }
+
+  InsertOrReplaceEntry(new_entry, replace_entry);
+}
+
+void NavigationControllerImpl::RendererDidNavigateToExistingPage(
+    const ViewHostMsg_FrameNavigate_Params& params) {
+  // We should only get here for main frame navigations.
+  DCHECK(PageTransitionIsMainFrame(params.transition));
+
+  // This is a back/forward navigation. The existing page for the ID is
+  // guaranteed to exist by ClassifyNavigation, and we just need to update it
+  // with new information from the renderer.
+  int entry_index = GetEntryIndexWithPageID(delegate_->GetSiteInstance(),
+                                            params.page_id);
+  DCHECK(entry_index >= 0 &&
+         entry_index < static_cast<int>(entries_.size()));
+  NavigationEntryImpl* entry = entries_[entry_index].get();
+
+  // The URL may have changed due to redirects.
+  entry->SetURL(params.url);
+  if (entry->update_virtual_url_with_url())
+    UpdateVirtualURLToURL(entry, params.url);
+
+  // The redirected to page should not inherit the favicon from the previous
+  // page.
+  if (PageTransitionIsRedirect(params.transition))
+    entry->GetFavicon() = FaviconStatus();
+
+  // The site instance will normally be the same except during session restore,
+  // when no site instance will be assigned.
+  DCHECK(entry->site_instance() == NULL ||
+         entry->site_instance() == delegate_->GetSiteInstance());
+  entry->set_site_instance(
+      static_cast<SiteInstanceImpl*>(delegate_->GetSiteInstance()));
+
+  entry->SetHasPostData(params.is_post);
+  entry->SetPostID(params.post_id);
+
+  // The entry we found in the list might be pending if the user hit
+  // back/forward/reload. This load should commit it (since it's already in the
+  // list, we can just discard the pending pointer).  We should also discard the
+  // pending entry if it corresponds to a different navigation, since that one
+  // is now likely canceled.  If it is not canceled, we will treat it as a new
+  // navigation when it arrives, which is also ok.
+  //
+  // Note that we need to use the "internal" version since we don't want to
+  // actually change any other state, just kill the pointer.
+  DiscardNonCommittedEntriesInternal();
+
+  // If a transient entry was removed, the indices might have changed, so we
+  // have to query the entry index again.
+  last_committed_entry_index_ =
+      GetEntryIndexWithPageID(delegate_->GetSiteInstance(), params.page_id);
+}
+
+void NavigationControllerImpl::RendererDidNavigateToSamePage(
+    const ViewHostMsg_FrameNavigate_Params& params) {
+  // This mode implies we have a pending entry that's the same as an existing
+  // entry for this page ID. This entry is guaranteed to exist by
+  // ClassifyNavigation. All we need to do is update the existing entry.
+  NavigationEntryImpl* existing_entry = GetEntryWithPageID(
+      delegate_->GetSiteInstance(), params.page_id);
+
+  // We assign the entry's unique ID to be that of the new one. Since this is
+  // always the result of a user action, we want to dismiss infobars, etc. like
+  // a regular user-initiated navigation.
+  existing_entry->set_unique_id(pending_entry_->GetUniqueID());
+
+  // The URL may have changed due to redirects.
+  if (existing_entry->update_virtual_url_with_url())
+    UpdateVirtualURLToURL(existing_entry, params.url);
+  existing_entry->SetURL(params.url);
+
+  DiscardNonCommittedEntries();
+}
+
+void NavigationControllerImpl::RendererDidNavigateInPage(
+    const ViewHostMsg_FrameNavigate_Params& params, bool* did_replace_entry) {
+  DCHECK(PageTransitionIsMainFrame(params.transition)) <<
+      "WebKit should only tell us about in-page navs for the main frame.";
+  // We're guaranteed to have an entry for this one.
+  NavigationEntryImpl* existing_entry = GetEntryWithPageID(
+      delegate_->GetSiteInstance(), params.page_id);
+
+  // Reference fragment navigation. We're guaranteed to have the last_committed
+  // entry and it will be the same page as the new navigation (minus the
+  // reference fragments, of course).  We'll update the URL of the existing
+  // entry without pruning the forward history.
+  existing_entry->SetURL(params.url);
+  if (existing_entry->update_virtual_url_with_url())
+    UpdateVirtualURLToURL(existing_entry, params.url);
+
+  // This replaces the existing entry since the page ID didn't change.
+  *did_replace_entry = true;
+
+  DiscardNonCommittedEntriesInternal();
+
+  // If a transient entry was removed, the indices might have changed, so we
+  // have to query the entry index again.
+  last_committed_entry_index_ =
+      GetEntryIndexWithPageID(delegate_->GetSiteInstance(), params.page_id);
+}
+
+void NavigationControllerImpl::RendererDidNavigateNewSubframe(
+    const ViewHostMsg_FrameNavigate_Params& params) {
+  if (PageTransitionCoreTypeIs(params.transition,
+                               PAGE_TRANSITION_AUTO_SUBFRAME)) {
+    // This is not user-initiated. Ignore.
+    DiscardNonCommittedEntriesInternal();
+    return;
+  }
+
+  // Manual subframe navigations just get the current entry cloned so the user
+  // can go back or forward to it. The actual subframe information will be
+  // stored in the page state for each of those entries. This happens out of
+  // band with the actual navigations.
+  DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee "
+                                  << "that a last committed entry exists.";
+  NavigationEntryImpl* new_entry = new NavigationEntryImpl(
+      *NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()));
+  new_entry->SetPageID(params.page_id);
+  InsertOrReplaceEntry(new_entry, false);
+}
+
+bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
+    const ViewHostMsg_FrameNavigate_Params& params) {
+  // We're guaranteed to have a previously committed entry, and we now need to
+  // handle navigation inside of a subframe in it without creating a new entry.
+  DCHECK(GetLastCommittedEntry());
+
+  // Handle the case where we're navigating back/forward to a previous subframe
+  // navigation entry. This is case "2." in NAV_AUTO_SUBFRAME comment in the
+  // header file. In case "1." this will be a NOP.
+  int entry_index = GetEntryIndexWithPageID(
+      delegate_->GetSiteInstance(),
+      params.page_id);
+  if (entry_index < 0 ||
+      entry_index >= static_cast<int>(entries_.size())) {
+    NOTREACHED();
+    return false;
+  }
+
+  // Update the current navigation entry in case we're going back/forward.
+  if (entry_index != last_committed_entry_index_) {
+    last_committed_entry_index_ = entry_index;
+    DiscardNonCommittedEntriesInternal();
+    return true;
+  }
+
+  // We do not need to discard the pending entry in this case, since we will
+  // not generate commit notifications for this auto-subframe navigation.
+  return false;
+}
+
+int NavigationControllerImpl::GetIndexOfEntry(
+    const NavigationEntryImpl* entry) const {
+  const NavigationEntries::const_iterator i(std::find(
+      entries_.begin(),
+      entries_.end(),
+      entry));
+  return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin());
+}
+
+bool NavigationControllerImpl::IsURLInPageNavigation(
+    const GURL& url,
+    bool renderer_says_in_page,
+    NavigationType navigation_type) const {
+  NavigationEntry* last_committed = GetLastCommittedEntry();
+  return last_committed && AreURLsInPageNavigation(
+      last_committed->GetURL(), url, renderer_says_in_page, navigation_type);
+}
+
+void NavigationControllerImpl::CopyStateFrom(
+    const NavigationController& temp) {
+  const NavigationControllerImpl& source =
+      static_cast<const NavigationControllerImpl&>(temp);
+  // Verify that we look new.
+  DCHECK(GetEntryCount() == 0 && !GetPendingEntry());
+
+  if (source.GetEntryCount() == 0)
+    return;  // Nothing new to do.
+
+  needs_reload_ = true;
+  InsertEntriesFrom(source, source.GetEntryCount());
+
+  for (SessionStorageNamespaceMap::const_iterator it =
+           source.session_storage_namespace_map_.begin();
+       it != source.session_storage_namespace_map_.end();
+       ++it) {
+    SessionStorageNamespaceImpl* source_namespace =
+        static_cast<SessionStorageNamespaceImpl*>(it->second.get());
+    session_storage_namespace_map_[it->first] = source_namespace->Clone();
+  }
+
+  FinishRestore(source.last_committed_entry_index_, RESTORE_CURRENT_SESSION);
+
+  // Copy the max page id map from the old tab to the new tab.  This ensures
+  // that new and existing navigations in the tab's current SiteInstances
+  // are identified properly.
+  delegate_->CopyMaxPageIDsFrom(source.delegate()->GetWebContents());
+}
+
+void NavigationControllerImpl::CopyStateFromAndPrune(
+    NavigationController* temp) {
+  // It is up to callers to check the invariants before calling this.
+  CHECK(CanPruneAllButVisible());
+
+  NavigationControllerImpl* source =
+      static_cast<NavigationControllerImpl*>(temp);
+  // The SiteInstance and page_id of the last committed entry needs to be
+  // remembered at this point, in case there is only one committed entry
+  // and it is pruned.  We use a scoped_refptr to ensure the SiteInstance
+  // can't be freed during this time period.
+  NavigationEntryImpl* last_committed =
+      NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
+  scoped_refptr<SiteInstance> site_instance(
+      last_committed->site_instance());
+  int32 minimum_page_id = last_committed->GetPageID();
+  int32 max_page_id =
+      delegate_->GetMaxPageIDForSiteInstance(site_instance.get());
+
+  // Remove all the entries leaving the active entry.
+  PruneAllButVisibleInternal();
+
+  // We now have one entry, possibly with a new pending entry.  Ensure that
+  // adding the entries from source won't put us over the limit.
+  DCHECK_EQ(1, GetEntryCount());
+  source->PruneOldestEntryIfFull();
+
+  // Insert the entries from source. Don't use source->GetCurrentEntryIndex as
+  // we don't want to copy over the transient entry.  Ignore any pending entry,
+  // since it has not committed in source.
+  int max_source_index = source->last_committed_entry_index_;
+  if (max_source_index == -1)
+    max_source_index = source->GetEntryCount();
+  else
+    max_source_index++;
+  InsertEntriesFrom(*source, max_source_index);
+
+  // Adjust indices such that the last entry and pending are at the end now.
+  last_committed_entry_index_ = GetEntryCount() - 1;
+
+  delegate_->SetHistoryLengthAndPrune(site_instance.get(),
+                                      max_source_index,
+                                      minimum_page_id);
+
+  // Copy the max page id map from the old tab to the new tab.  This ensures
+  // that new and existing navigations in the tab's current SiteInstances
+  // are identified properly.
+  delegate_->CopyMaxPageIDsFrom(source->delegate()->GetWebContents());
+
+  // If there is a last committed entry, be sure to include it in the new
+  // max page ID map.
+  if (max_page_id > -1) {
+    delegate_->UpdateMaxPageIDForSiteInstance(site_instance.get(),
+                                              max_page_id);
+  }
+}
+
+bool NavigationControllerImpl::CanPruneAllButVisible() {
+  // If there is no last committed entry, we cannot prune.  Even if there is a
+  // pending entry, it may not commit, leaving this WebContents blank, despite
+  // possibly giving it new entries via CopyStateFromAndPrune.
+  if (last_committed_entry_index_ == -1)
+    return false;
+
+  // We cannot prune if there is a pending entry at an existing entry index.
+  // It may not commit, so we have to keep the last committed entry, and thus
+  // there is no sensible place to keep the pending entry.  It is ok to have
+  // a new pending entry, which can optionally commit as a new navigation.
+  if (pending_entry_index_ != -1)
+    return false;
+
+  // We should not prune if we are currently showing a transient entry.
+  if (transient_entry_index_ != -1)
+    return false;
+
+  return true;
+}
+
+void NavigationControllerImpl::PruneAllButVisible() {
+  PruneAllButVisibleInternal();
+
+  // We should still have a last committed entry.
+  DCHECK_NE(-1, last_committed_entry_index_);
+
+  // We pass 0 instead of GetEntryCount() for the history_length parameter of
+  // SetHistoryLengthAndPrune, because it will create history_length additional
+  // history entries.
+  // TODO(jochen): This API is confusing and we should clean it up.
+  // http://crbug.com/178491
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(GetVisibleEntry());
+  delegate_->SetHistoryLengthAndPrune(
+      entry->site_instance(), 0, entry->GetPageID());
+}
+
+void NavigationControllerImpl::PruneAllButVisibleInternal() {
+  // It is up to callers to check the invariants before calling this.
+  CHECK(CanPruneAllButVisible());
+
+  // Erase all entries but the last committed entry.  There may still be a
+  // new pending entry after this.
+  entries_.erase(entries_.begin(),
+                 entries_.begin() + last_committed_entry_index_);
+  entries_.erase(entries_.begin() + 1, entries_.end());
+  last_committed_entry_index_ = 0;
+}
+
+void NavigationControllerImpl::ClearAllScreenshots() {
+  screenshot_manager_->ClearAllScreenshots();
+}
+
+void NavigationControllerImpl::SetSessionStorageNamespace(
+    const std::string& partition_id,
+    SessionStorageNamespace* session_storage_namespace) {
+  if (!session_storage_namespace)
+    return;
+
+  // We can't overwrite an existing SessionStorage without violating spec.
+  // Attempts to do so may give a tab access to another tab's session storage
+  // so die hard on an error.
+  bool successful_insert = session_storage_namespace_map_.insert(
+      make_pair(partition_id,
+                static_cast<SessionStorageNamespaceImpl*>(
+                    session_storage_namespace)))
+          .second;
+  CHECK(successful_insert) << "Cannot replace existing SessionStorageNamespace";
+}
+
+void NavigationControllerImpl::SetMaxRestoredPageID(int32 max_id) {
+  max_restored_page_id_ = max_id;
+}
+
+int32 NavigationControllerImpl::GetMaxRestoredPageID() const {
+  return max_restored_page_id_;
+}
+
+SessionStorageNamespace*
+NavigationControllerImpl::GetSessionStorageNamespace(SiteInstance* instance) {
+  std::string partition_id;
+  if (instance) {
+    // TODO(ajwong): When GetDefaultSessionStorageNamespace() goes away, remove
+    // this if statement so |instance| must not be NULL.
+    partition_id =
+        GetContentClient()->browser()->GetStoragePartitionIdForSite(
+            browser_context_, instance->GetSiteURL());
+  }
+
+  SessionStorageNamespaceMap::const_iterator it =
+      session_storage_namespace_map_.find(partition_id);
+  if (it != session_storage_namespace_map_.end())
+    return it->second.get();
+
+  // Create one if no one has accessed session storage for this partition yet.
+  //
+  // TODO(ajwong): Should this use the |partition_id| directly rather than
+  // re-lookup via |instance|?  http://crbug.com/142685
+  StoragePartition* partition =
+              BrowserContext::GetStoragePartition(browser_context_, instance);
+  SessionStorageNamespaceImpl* session_storage_namespace =
+      new SessionStorageNamespaceImpl(
+          static_cast<DOMStorageContextWrapper*>(
+              partition->GetDOMStorageContext()));
+  session_storage_namespace_map_[partition_id] = session_storage_namespace;
+
+  return session_storage_namespace;
+}
+
+SessionStorageNamespace*
+NavigationControllerImpl::GetDefaultSessionStorageNamespace() {
+  // TODO(ajwong): Remove if statement in GetSessionStorageNamespace().
+  return GetSessionStorageNamespace(NULL);
+}
+
+const SessionStorageNamespaceMap&
+NavigationControllerImpl::GetSessionStorageNamespaceMap() const {
+  return session_storage_namespace_map_;
+}
+
+bool NavigationControllerImpl::NeedsReload() const {
+  return needs_reload_;
+}
+
+void NavigationControllerImpl::SetNeedsReload() {
+  needs_reload_ = true;
+}
+
+void NavigationControllerImpl::RemoveEntryAtIndexInternal(int index) {
+  DCHECK(index < GetEntryCount());
+  DCHECK(index != last_committed_entry_index_);
+
+  DiscardNonCommittedEntries();
+
+  entries_.erase(entries_.begin() + index);
+  if (last_committed_entry_index_ > index)
+    last_committed_entry_index_--;
+}
+
+void NavigationControllerImpl::DiscardNonCommittedEntries() {
+  bool transient = transient_entry_index_ != -1;
+  DiscardNonCommittedEntriesInternal();
+
+  // If there was a transient entry, invalidate everything so the new active
+  // entry state is shown.
+  if (transient) {
+    delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+  }
+}
+
+NavigationEntry* NavigationControllerImpl::GetPendingEntry() const {
+  return pending_entry_;
+}
+
+int NavigationControllerImpl::GetPendingEntryIndex() const {
+  return pending_entry_index_;
+}
+
+void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry,
+                                                    bool replace) {
+  DCHECK(entry->GetTransitionType() != PAGE_TRANSITION_AUTO_SUBFRAME);
+
+  // Copy the pending entry's unique ID to the committed entry.
+  // I don't know if pending_entry_index_ can be other than -1 here.
+  const NavigationEntryImpl* const pending_entry =
+      (pending_entry_index_ == -1) ?
+          pending_entry_ : entries_[pending_entry_index_].get();
+  if (pending_entry)
+    entry->set_unique_id(pending_entry->GetUniqueID());
+
+  DiscardNonCommittedEntriesInternal();
+
+  int current_size = static_cast<int>(entries_.size());
+
+  if (current_size > 0) {
+    // Prune any entries which are in front of the current entry.
+    // Also prune the current entry if we are to replace the current entry.
+    // last_committed_entry_index_ must be updated here since calls to
+    // NotifyPrunedEntries() below may re-enter and we must make sure
+    // last_committed_entry_index_ is not left in an invalid state.
+    if (replace)
+      --last_committed_entry_index_;
+
+    int num_pruned = 0;
+    while (last_committed_entry_index_ < (current_size - 1)) {
+      num_pruned++;
+      entries_.pop_back();
+      current_size--;
+    }
+    if (num_pruned > 0)  // Only notify if we did prune something.
+      NotifyPrunedEntries(this, false, num_pruned);
+  }
+
+  PruneOldestEntryIfFull();
+
+  entries_.push_back(linked_ptr<NavigationEntryImpl>(entry));
+  last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1;
+
+  // This is a new page ID, so we need everybody to know about it.
+  delegate_->UpdateMaxPageID(entry->GetPageID());
+}
+
+void NavigationControllerImpl::PruneOldestEntryIfFull() {
+  if (entries_.size() >= max_entry_count()) {
+    DCHECK_EQ(max_entry_count(), entries_.size());
+    DCHECK_GT(last_committed_entry_index_, 0);
+    RemoveEntryAtIndex(0);
+    NotifyPrunedEntries(this, true, 1);
+  }
+}
+
+void NavigationControllerImpl::NavigateToPendingEntry(ReloadType reload_type) {
+  needs_reload_ = false;
+
+  // If we were navigating to a slow-to-commit page, and the user performs
+  // a session history navigation to the last committed page, RenderViewHost
+  // will force the throbber to start, but WebKit will essentially ignore the
+  // navigation, and won't send a message to stop the throbber. To prevent this
+  // from happening, we drop the navigation here and stop the slow-to-commit
+  // page from loading (which would normally happen during the navigation).
+  if (pending_entry_index_ != -1 &&
+      pending_entry_index_ == last_committed_entry_index_ &&
+      (entries_[pending_entry_index_]->restore_type() ==
+          NavigationEntryImpl::RESTORE_NONE) &&
+      (entries_[pending_entry_index_]->GetTransitionType() &
+          PAGE_TRANSITION_FORWARD_BACK)) {
+    delegate_->Stop();
+
+    // If an interstitial page is showing, we want to close it to get back
+    // to what was showing before.
+    if (delegate_->GetInterstitialPage())
+      delegate_->GetInterstitialPage()->DontProceed();
+
+    DiscardNonCommittedEntries();
+    return;
+  }
+
+  // If an interstitial page is showing, the previous renderer is blocked and
+  // cannot make new requests.  Unblock (and disable) it to allow this
+  // navigation to succeed.  The interstitial will stay visible until the
+  // resulting DidNavigate.
+  if (delegate_->GetInterstitialPage()) {
+    static_cast<InterstitialPageImpl*>(delegate_->GetInterstitialPage())->
+        CancelForNavigation();
+  }
+
+  // For session history navigations only the pending_entry_index_ is set.
+  if (!pending_entry_) {
+    DCHECK_NE(pending_entry_index_, -1);
+    pending_entry_ = entries_[pending_entry_index_].get();
+  }
+
+  if (!delegate_->NavigateToPendingEntry(reload_type))
+    DiscardNonCommittedEntries();
+
+  // If the entry is being restored and doesn't have a SiteInstance yet, fill
+  // it in now that we know. This allows us to find the entry when it commits.
+  // This works for browser-initiated navigations. We handle renderer-initiated
+  // navigations to restored entries in WebContentsImpl::OnGoToEntryAtOffset.
+  if (pending_entry_ && !pending_entry_->site_instance() &&
+      pending_entry_->restore_type() != NavigationEntryImpl::RESTORE_NONE) {
+    pending_entry_->set_site_instance(static_cast<SiteInstanceImpl*>(
+        delegate_->GetPendingSiteInstance()));
+    pending_entry_->set_restore_type(NavigationEntryImpl::RESTORE_NONE);
+  }
+}
+
+void NavigationControllerImpl::NotifyNavigationEntryCommitted(
+    LoadCommittedDetails* details) {
+  details->entry = GetLastCommittedEntry();
+
+  // We need to notify the ssl_manager_ before the web_contents_ so the
+  // location bar will have up-to-date information about the security style
+  // when it wants to draw.  See http://crbug.com/11157
+  ssl_manager_.DidCommitProvisionalLoad(*details);
+
+  delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+  delegate_->NotifyNavigationEntryCommitted(*details);
+
+  // TODO(avi): Remove. http://crbug.com/170921
+  NotificationDetails notification_details =
+      Details<LoadCommittedDetails>(details);
+  NotificationService::current()->Notify(
+      NOTIFICATION_NAV_ENTRY_COMMITTED,
+      Source<NavigationController>(this),
+      notification_details);
+}
+
+// static
+size_t NavigationControllerImpl::max_entry_count() {
+  if (max_entry_count_for_testing_ != kMaxEntryCountForTestingNotSet)
+     return max_entry_count_for_testing_;
+  return kMaxSessionHistoryEntries;
+}
+
+void NavigationControllerImpl::SetActive(bool is_active) {
+  if (is_active && needs_reload_)
+    LoadIfNecessary();
+}
+
+void NavigationControllerImpl::LoadIfNecessary() {
+  if (!needs_reload_)
+    return;
+
+  // Calling Reload() results in ignoring state, and not loading.
+  // Explicitly use NavigateToPendingEntry so that the renderer uses the
+  // cached state.
+  pending_entry_index_ = last_committed_entry_index_;
+  NavigateToPendingEntry(NO_RELOAD);
+}
+
+void NavigationControllerImpl::NotifyEntryChanged(const NavigationEntry* entry,
+                                                  int index) {
+  EntryChangedDetails det;
+  det.changed_entry = entry;
+  det.index = index;
+  NotificationService::current()->Notify(
+      NOTIFICATION_NAV_ENTRY_CHANGED,
+      Source<NavigationController>(this),
+      Details<EntryChangedDetails>(&det));
+}
+
+void NavigationControllerImpl::FinishRestore(int selected_index,
+                                             RestoreType type) {
+  DCHECK(selected_index >= 0 && selected_index < GetEntryCount());
+  ConfigureEntriesForRestore(&entries_, type);
+
+  SetMaxRestoredPageID(static_cast<int32>(GetEntryCount()));
+
+  last_committed_entry_index_ = selected_index;
+}
+
+void NavigationControllerImpl::DiscardNonCommittedEntriesInternal() {
+  DiscardPendingEntry();
+  DiscardTransientEntry();
+}
+
+void NavigationControllerImpl::DiscardPendingEntry() {
+  if (pending_entry_index_ == -1)
+    delete pending_entry_;
+  pending_entry_ = NULL;
+  pending_entry_index_ = -1;
+}
+
+void NavigationControllerImpl::DiscardTransientEntry() {
+  if (transient_entry_index_ == -1)
+    return;
+  entries_.erase(entries_.begin() + transient_entry_index_);
+  if (last_committed_entry_index_ > transient_entry_index_)
+    last_committed_entry_index_--;
+  transient_entry_index_ = -1;
+}
+
+int NavigationControllerImpl::GetEntryIndexWithPageID(
+    SiteInstance* instance, int32 page_id) const {
+  for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
+    if ((entries_[i]->site_instance() == instance) &&
+        (entries_[i]->GetPageID() == page_id))
+      return i;
+  }
+  return -1;
+}
+
+NavigationEntry* NavigationControllerImpl::GetTransientEntry() const {
+  if (transient_entry_index_ == -1)
+    return NULL;
+  return entries_[transient_entry_index_].get();
+}
+
+void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) {
+  // Discard any current transient entry, we can only have one at a time.
+  int index = 0;
+  if (last_committed_entry_index_ != -1)
+    index = last_committed_entry_index_ + 1;
+  DiscardTransientEntry();
+  entries_.insert(
+      entries_.begin() + index, linked_ptr<NavigationEntryImpl>(
+          NavigationEntryImpl::FromNavigationEntry(entry)));
+  transient_entry_index_ = index;
+  delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+}
+
+void NavigationControllerImpl::InsertEntriesFrom(
+    const NavigationControllerImpl& source,
+    int max_index) {
+  DCHECK_LE(max_index, source.GetEntryCount());
+  size_t insert_index = 0;
+  for (int i = 0; i < max_index; i++) {
+    // When cloning a tab, copy all entries except interstitial pages
+    if (source.entries_[i].get()->GetPageType() !=
+        PAGE_TYPE_INTERSTITIAL) {
+      entries_.insert(entries_.begin() + insert_index++,
+                      linked_ptr<NavigationEntryImpl>(
+                          new NavigationEntryImpl(*source.entries_[i])));
+    }
+  }
+}
+
+void NavigationControllerImpl::SetGetTimestampCallbackForTest(
+    const base::Callback<base::Time()>& get_timestamp_callback) {
+  get_timestamp_callback_ = get_timestamp_callback;
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
new file mode 100644
index 0000000..9177914
--- /dev/null
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -0,0 +1,410 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_IMPL_H_
+#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_IMPL_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/linked_ptr.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "content/browser/frame_host/navigation_controller_delegate.h"
+#include "content/browser/ssl/ssl_manager.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_type.h"
+
+struct ViewHostMsg_FrameNavigate_Params;
+
+namespace content {
+class NavigationEntryImpl;
+class RenderViewHost;
+class WebContentsScreenshotManager;
+class SiteInstance;
+struct LoadCommittedDetails;
+
+class CONTENT_EXPORT NavigationControllerImpl
+    : public NON_EXPORTED_BASE(NavigationController) {
+ public:
+  NavigationControllerImpl(
+      NavigationControllerDelegate* delegate,
+      BrowserContext* browser_context);
+  virtual ~NavigationControllerImpl();
+
+  // NavigationController implementation:
+  virtual WebContents* GetWebContents() const OVERRIDE;
+  virtual BrowserContext* GetBrowserContext() const OVERRIDE;
+  virtual void SetBrowserContext(
+      BrowserContext* browser_context) OVERRIDE;
+  virtual void Restore(
+      int selected_navigation,
+      RestoreType type,
+      std::vector<NavigationEntry*>* entries) OVERRIDE;
+  virtual NavigationEntry* GetActiveEntry() const OVERRIDE;
+  virtual NavigationEntry* GetVisibleEntry() const OVERRIDE;
+  virtual int GetCurrentEntryIndex() const OVERRIDE;
+  virtual NavigationEntry* GetLastCommittedEntry() const OVERRIDE;
+  virtual int GetLastCommittedEntryIndex() const OVERRIDE;
+  virtual bool CanViewSource() const OVERRIDE;
+  virtual int GetEntryCount() const OVERRIDE;
+  virtual NavigationEntry* GetEntryAtIndex(int index) const OVERRIDE;
+  virtual NavigationEntry* GetEntryAtOffset(int offset) const OVERRIDE;
+  virtual void DiscardNonCommittedEntries() OVERRIDE;
+  virtual NavigationEntry* GetPendingEntry() const OVERRIDE;
+  virtual int GetPendingEntryIndex() const OVERRIDE;
+  virtual NavigationEntry* GetTransientEntry() const OVERRIDE;
+  virtual void SetTransientEntry(NavigationEntry* entry) OVERRIDE;
+  virtual void LoadURL(const GURL& url,
+                       const Referrer& referrer,
+                       PageTransition type,
+                       const std::string& extra_headers) OVERRIDE;
+  virtual void LoadURLWithParams(const LoadURLParams& params) OVERRIDE;
+  virtual void LoadIfNecessary() OVERRIDE;
+  virtual bool CanGoBack() const OVERRIDE;
+  virtual bool CanGoForward() const OVERRIDE;
+  virtual bool CanGoToOffset(int offset) const OVERRIDE;
+  virtual void GoBack() OVERRIDE;
+  virtual void GoForward() OVERRIDE;
+  virtual void GoToIndex(int index) OVERRIDE;
+  virtual void GoToOffset(int offset) OVERRIDE;
+  virtual bool RemoveEntryAtIndex(int index) OVERRIDE;
+  virtual const SessionStorageNamespaceMap&
+      GetSessionStorageNamespaceMap() const OVERRIDE;
+  virtual SessionStorageNamespace*
+      GetDefaultSessionStorageNamespace() OVERRIDE;
+  virtual void SetMaxRestoredPageID(int32 max_id) OVERRIDE;
+  virtual int32 GetMaxRestoredPageID() const OVERRIDE;
+  virtual bool NeedsReload() const OVERRIDE;
+  virtual void SetNeedsReload() OVERRIDE;
+  virtual void CancelPendingReload() OVERRIDE;
+  virtual void ContinuePendingReload() OVERRIDE;
+  virtual bool IsInitialNavigation() const OVERRIDE;
+  virtual void Reload(bool check_for_repost) OVERRIDE;
+  virtual void ReloadIgnoringCache(bool check_for_repost) OVERRIDE;
+  virtual void ReloadOriginalRequestURL(bool check_for_repost) OVERRIDE;
+  virtual void NotifyEntryChanged(const NavigationEntry* entry,
+                                 int index) OVERRIDE;
+  virtual void CopyStateFrom(
+      const NavigationController& source) OVERRIDE;
+  virtual void CopyStateFromAndPrune(
+      NavigationController* source) OVERRIDE;
+  virtual bool CanPruneAllButVisible() OVERRIDE;
+  virtual void PruneAllButVisible() OVERRIDE;
+  virtual void ClearAllScreenshots() OVERRIDE;
+
+  // The session storage namespace that all child RenderViews belonging to
+  // |instance| should use.
+  SessionStorageNamespace* GetSessionStorageNamespace(
+      SiteInstance* instance);
+
+  // Returns the index of the specified entry, or -1 if entry is not contained
+  // in this NavigationController.
+  int GetIndexOfEntry(const NavigationEntryImpl* entry) const;
+
+  // Return the index of the entry with the corresponding instance and page_id,
+  // or -1 if not found.
+  int GetEntryIndexWithPageID(SiteInstance* instance,
+                              int32 page_id) const;
+
+  // Return the entry with the corresponding instance and page_id, or NULL if
+  // not found.
+  NavigationEntryImpl* GetEntryWithPageID(
+      SiteInstance* instance,
+      int32 page_id) const;
+
+  NavigationControllerDelegate* delegate() const {
+    return delegate_;
+  }
+
+  // For use by WebContentsImpl ------------------------------------------------
+
+  // Allow renderer-initiated navigations to create a pending entry when the
+  // provisional load starts.
+  void SetPendingEntry(content::NavigationEntryImpl* entry);
+
+  // Handles updating the navigation state after the renderer has navigated.
+  // This is used by the WebContentsImpl.
+  //
+  // If a new entry is created, it will return true and will have filled the
+  // given details structure and broadcast the NOTIFY_NAV_ENTRY_COMMITTED
+  // notification. The caller can then use the details without worrying about
+  // listening for the notification.
+  //
+  // In the case that nothing has changed, the details structure is undefined
+  // and it will return false.
+  bool RendererDidNavigate(const ViewHostMsg_FrameNavigate_Params& params,
+                           LoadCommittedDetails* details);
+
+  // Notifies us that we just became active. This is used by the WebContentsImpl
+  // so that we know to load URLs that were pending as "lazy" loads.
+  void SetActive(bool is_active);
+
+  // Returns true if the given URL would be an in-page navigation (i.e. only
+  // the reference fragment is different) from the "last committed entry". We do
+  // not compare it against the "active entry" since the active entry can be
+  // pending and in page navigations only happen on committed pages. If there
+  // is no last committed entry, then nothing will be in-page.
+  //
+  // Special note: if the URLs are the same, it does NOT automatically count as
+  // an in-page navigation. Neither does an input URL that has no ref, even if
+  // the rest is the same. This may seem weird, but when we're considering
+  // whether a navigation happened without loading anything, the same URL could
+  // be a reload, while only a different ref would be in-page (pages can't clear
+  // refs without reload, only change to "#" which we don't count as empty).
+  bool IsURLInPageNavigation(const GURL& url) const {
+    return IsURLInPageNavigation(url, false, NAVIGATION_TYPE_UNKNOWN);
+  }
+
+  // The situation is made murkier by history.replaceState(), which could
+  // provide the same URL as part of an in-page navigation, not a reload. So
+  // we need this form which lets the (untrustworthy) renderer resolve the
+  // ambiguity, but only when the URLs are equal. This should be safe since the
+  // origin isn't changing.
+  bool IsURLInPageNavigation(
+      const GURL& url,
+      bool renderer_says_in_page,
+      NavigationType navigation_type) const;
+
+  // Sets the SessionStorageNamespace for the given |partition_id|. This is
+  // used during initialization of a new NavigationController to allow
+  // pre-population of the SessionStorageNamespace objects. Session restore,
+  // prerendering, and the implementaion of window.open() are the primary users
+  // of this API.
+  //
+  // Calling this function when a SessionStorageNamespace has already been
+  // associated with a |partition_id| will CHECK() fail.
+  void SetSessionStorageNamespace(
+      const std::string& partition_id,
+      SessionStorageNamespace* session_storage_namespace);
+
+  // Random data ---------------------------------------------------------------
+
+  SSLManager* ssl_manager() { return &ssl_manager_; }
+
+  // Maximum number of entries before we start removing entries from the front.
+  static void set_max_entry_count_for_testing(size_t max_entry_count) {
+    max_entry_count_for_testing_ = max_entry_count;
+  }
+  static size_t max_entry_count();
+
+  void SetGetTimestampCallbackForTest(
+      const base::Callback<base::Time()>& get_timestamp_callback);
+
+  // Takes a screenshot of the page at the current state.
+  void TakeScreenshot();
+
+  // Sets the screenshot manager for this NavigationControllerImpl. The
+  // controller takes ownership of the screenshot manager and destroys it when
+  // a new screenshot-manager is set, or when the controller is destroyed.
+  // Setting a NULL manager recreates the default screenshot manager and uses
+  // that.
+  void SetScreenshotManager(WebContentsScreenshotManager* manager);
+
+  // Discards only the pending entry.
+  void DiscardPendingEntry();
+
+ private:
+  friend class RestoreHelper;
+
+  FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest,
+                           PurgeScreenshot);
+  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, Basic);
+  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, SingleDuplicate);
+  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ManyDuplicates);
+  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ClockBackwardsJump);
+
+  // Helper class to smooth out runs of duplicate timestamps while still
+  // allowing time to jump backwards.
+  class CONTENT_EXPORT TimeSmoother {
+   public:
+    // Returns |t| with possibly some time added on.
+    base::Time GetSmoothedTime(base::Time t);
+
+   private:
+    // |low_water_mark_| is the first time in a sequence of adjusted
+    // times and |high_water_mark_| is the last.
+    base::Time low_water_mark_;
+    base::Time high_water_mark_;
+  };
+
+  // Classifies the given renderer navigation (see the NavigationType enum).
+  NavigationType ClassifyNavigation(
+      const ViewHostMsg_FrameNavigate_Params& params) const;
+
+  // Causes the controller to load the specified entry. The function assumes
+  // ownership of the pointer since it is put in the navigation list.
+  // NOTE: Do not pass an entry that the controller already owns!
+  void LoadEntry(NavigationEntryImpl* entry);
+
+  // Handlers for the different types of navigation types. They will actually
+  // handle the navigations corresponding to the different NavClasses above.
+  // They will NOT broadcast the commit notification, that should be handled by
+  // the caller.
+  //
+  // RendererDidNavigateAutoSubframe is special, it may not actually change
+  // anything if some random subframe is loaded. It will return true if anything
+  // changed, or false if not.
+  //
+  // The functions taking |did_replace_entry| will fill into the given variable
+  // whether the last entry has been replaced or not.
+  // See LoadCommittedDetails.did_replace_entry.
+  void RendererDidNavigateToNewPage(
+      const ViewHostMsg_FrameNavigate_Params& params, bool replace_entry);
+  void RendererDidNavigateToExistingPage(
+      const ViewHostMsg_FrameNavigate_Params& params);
+  void RendererDidNavigateToSamePage(
+      const ViewHostMsg_FrameNavigate_Params& params);
+  void RendererDidNavigateInPage(
+      const ViewHostMsg_FrameNavigate_Params& params, bool* did_replace_entry);
+  void RendererDidNavigateNewSubframe(
+      const ViewHostMsg_FrameNavigate_Params& params);
+  bool RendererDidNavigateAutoSubframe(
+      const ViewHostMsg_FrameNavigate_Params& params);
+
+  // Helper function for code shared between Reload() and ReloadIgnoringCache().
+  void ReloadInternal(bool check_for_repost, ReloadType reload_type);
+
+  // Actually issues the navigation held in pending_entry.
+  void NavigateToPendingEntry(ReloadType reload_type);
+
+  // Allows the derived class to issue notifications that a load has been
+  // committed. This will fill in the active entry to the details structure.
+  void NotifyNavigationEntryCommitted(LoadCommittedDetails* details);
+
+  // Updates the virtual URL of an entry to match a new URL, for cases where
+  // the real renderer URL is derived from the virtual URL, like view-source:
+  void UpdateVirtualURLToURL(NavigationEntryImpl* entry,
+                             const GURL& new_url);
+
+  // Invoked after session/tab restore or cloning a tab. Resets the transition
+  // type of the entries, updates the max page id and creates the active
+  // contents.
+  void FinishRestore(int selected_index, RestoreType type);
+
+  // Inserts a new entry or replaces the current entry with a new one, removing
+  // all entries after it. The new entry will become the active one.
+  void InsertOrReplaceEntry(NavigationEntryImpl* entry, bool replace);
+
+  // Removes the entry at |index|, as long as it is not the current entry.
+  void RemoveEntryAtIndexInternal(int index);
+
+  // Discards both the pending and transient entries.
+  void DiscardNonCommittedEntriesInternal();
+
+  // Discards only the transient entry.
+  void DiscardTransientEntry();
+
+  // If we have the maximum number of entries, remove the oldest one in
+  // preparation to add another.
+  void PruneOldestEntryIfFull();
+
+  // Removes all entries except the last committed entry.  If there is a new
+  // pending navigation it is preserved. In contrast to PruneAllButVisible()
+  // this does not update the session history of the RenderView.  Callers
+  // must ensure that |CanPruneAllButVisible| returns true before calling this.
+  void PruneAllButVisibleInternal();
+
+  // Returns true if the navigation is redirect.
+  bool IsRedirect(const ViewHostMsg_FrameNavigate_Params& params);
+
+  // Returns true if the navigation is likley to be automatic rather than
+  // user-initiated.
+  bool IsLikelyAutoNavigation(base::TimeTicks now);
+
+  // Inserts up to |max_index| entries from |source| into this. This does NOT
+  // adjust any of the members that reference entries_
+  // (last_committed_entry_index_, pending_entry_index_ or
+  // transient_entry_index_).
+  void InsertEntriesFrom(const NavigationControllerImpl& source, int max_index);
+
+  // Returns the navigation index that differs from the current entry by the
+  // specified |offset|.  The index returned is not guaranteed to be valid.
+  int GetIndexForOffset(int offset) const;
+
+  // ---------------------------------------------------------------------------
+
+  // The user browser context associated with this controller.
+  BrowserContext* browser_context_;
+
+  // List of NavigationEntry for this tab
+  typedef std::vector<linked_ptr<NavigationEntryImpl> > NavigationEntries;
+  NavigationEntries entries_;
+
+  // An entry we haven't gotten a response for yet.  This will be discarded
+  // when we navigate again.  It's used only so we know what the currently
+  // displayed tab is.
+  //
+  // This may refer to an item in the entries_ list if the pending_entry_index_
+  // == -1, or it may be its own entry that should be deleted. Be careful with
+  // the memory management.
+  NavigationEntryImpl* pending_entry_;
+
+  // currently visible entry
+  int last_committed_entry_index_;
+
+  // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
+  // new entry (created by LoadURL).
+  int pending_entry_index_;
+
+  // The index for the entry that is shown until a navigation occurs.  This is
+  // used for interstitial pages. -1 if there are no such entry.
+  // Note that this entry really appears in the list of entries, but only
+  // temporarily (until the next navigation).  Any index pointing to an entry
+  // after the transient entry will become invalid if you navigate forward.
+  int transient_entry_index_;
+
+  // The delegate associated with the controller. Possibly NULL during
+  // setup.
+  NavigationControllerDelegate* delegate_;
+
+  // The max restored page ID in this controller, if it was restored.  We must
+  // store this so that WebContentsImpl can tell any renderer in charge of one
+  // of the restored entries to update its max page ID.
+  int32 max_restored_page_id_;
+
+  // Manages the SSL security UI.
+  SSLManager ssl_manager_;
+
+  // Whether we need to be reloaded when made active.
+  bool needs_reload_;
+
+  // Whether this is the initial navigation.
+  // Becomes false when initial navigation commits.
+  bool is_initial_navigation_;
+
+  // Used to find the appropriate SessionStorageNamespace for the storage
+  // partition of a NavigationEntry.
+  //
+  // A NavigationController may contain NavigationEntries that correspond to
+  // different StoragePartitions. Even though they are part of the same
+  // NavigationController, only entries in the same StoragePartition may
+  // share session storage state with one another.
+  SessionStorageNamespaceMap session_storage_namespace_map_;
+
+  // The maximum number of entries that a navigation controller can store.
+  static size_t max_entry_count_for_testing_;
+
+  // If a repost is pending, its type (RELOAD or RELOAD_IGNORING_CACHE),
+  // NO_RELOAD otherwise.
+  ReloadType pending_reload_;
+
+  // Used to get timestamps for newly-created navigation entries.
+  base::Callback<base::Time()> get_timestamp_callback_;
+
+  // Used to smooth out timestamps from |get_timestamp_callback_|.
+  // Without this, whenever there is a run of redirects or
+  // code-generated navigations, those navigations may occur within
+  // the timer resolution, leading to things sometimes showing up in
+  // the wrong order in the history view.
+  TimeSmoother time_smoother_;
+
+  scoped_ptr<WebContentsScreenshotManager> screenshot_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_IMPL_H_
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
new file mode 100644
index 0000000..9056f85
--- /dev/null
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -0,0 +1,3844 @@
+// Copyright 2013 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/basictypes.h"
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/web_contents_screenshot_manager.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/page_state.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_notification_tracker.h"
+#include "content/public/test/test_utils.h"
+#include "content/test/test_web_contents.h"
+#include "net/base/net_util.h"
+#include "skia/ext/platform_canvas.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+namespace {
+
+// Creates an image with a 1x1 SkBitmap of the specified |color|.
+gfx::Image CreateImage(SkColor color) {
+  SkBitmap bitmap;
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+  bitmap.allocPixels();
+  bitmap.eraseColor(color);
+  return gfx::Image::CreateFrom1xBitmap(bitmap);
+}
+
+// Returns true if images |a| and |b| have the same pixel data.
+bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
+  // Assume that if the 1x bitmaps match, the images match.
+  SkBitmap a_bitmap = a.AsBitmap();
+  SkBitmap b_bitmap = b.AsBitmap();
+
+  if (a_bitmap.width() != b_bitmap.width() ||
+      a_bitmap.height() != b_bitmap.height()) {
+    return false;
+  }
+  SkAutoLockPixels a_bitmap_lock(a_bitmap);
+  SkAutoLockPixels b_bitmap_lock(b_bitmap);
+  return memcmp(a_bitmap.getPixels(),
+                b_bitmap.getPixels(),
+                a_bitmap.getSize()) == 0;
+}
+
+class MockScreenshotManager : public content::WebContentsScreenshotManager {
+ public:
+  explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
+      : content::WebContentsScreenshotManager(owner),
+        encoding_screenshot_in_progress_(false) {
+  }
+
+  virtual ~MockScreenshotManager() {
+  }
+
+  void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
+    SkBitmap bitmap;
+    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+    bitmap.allocPixels();
+    bitmap.eraseRGB(0, 0, 0);
+    encoding_screenshot_in_progress_ = true;
+    OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+    WaitUntilScreenshotIsReady();
+  }
+
+  int GetScreenshotCount() {
+    return content::WebContentsScreenshotManager::GetScreenshotCount();
+  }
+
+  void WaitUntilScreenshotIsReady() {
+    if (!encoding_screenshot_in_progress_)
+      return;
+    message_loop_runner_ = new content::MessageLoopRunner;
+    message_loop_runner_->Run();
+  }
+
+ private:
+  // Overridden from content::WebContentsScreenshotManager:
+  virtual void TakeScreenshotImpl(
+      content::RenderViewHost* host,
+      content::NavigationEntryImpl* entry) OVERRIDE {
+  }
+
+  virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
+    encoding_screenshot_in_progress_ = false;
+    WebContentsScreenshotManager::OnScreenshotSet(entry);
+    if (message_loop_runner_.get())
+      message_loop_runner_->Quit();
+  }
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  bool encoding_screenshot_in_progress_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
+};
+
+}  // namespace
+
+namespace content {
+
+// TimeSmoother tests ----------------------------------------------------------
+
+// With no duplicates, GetSmoothedTime should be the identity
+// function.
+TEST(TimeSmoother, Basic) {
+  NavigationControllerImpl::TimeSmoother smoother;
+  for (int64 i = 1; i < 1000; ++i) {
+    base::Time t = base::Time::FromInternalValue(i);
+    EXPECT_EQ(t, smoother.GetSmoothedTime(t));
+  }
+}
+
+// With a single duplicate and timestamps thereafter increasing by one
+// microsecond, the smoothed time should always be one behind.
+TEST(TimeSmoother, SingleDuplicate) {
+  NavigationControllerImpl::TimeSmoother smoother;
+  base::Time t = base::Time::FromInternalValue(1);
+  EXPECT_EQ(t, smoother.GetSmoothedTime(t));
+  for (int64 i = 1; i < 1000; ++i) {
+    base::Time expected_t = base::Time::FromInternalValue(i + 1);
+    t = base::Time::FromInternalValue(i);
+    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
+  }
+}
+
+// With k duplicates and timestamps thereafter increasing by one
+// microsecond, the smoothed time should always be k behind.
+TEST(TimeSmoother, ManyDuplicates) {
+  const int64 kNumDuplicates = 100;
+  NavigationControllerImpl::TimeSmoother smoother;
+  base::Time t = base::Time::FromInternalValue(1);
+  for (int64 i = 0; i < kNumDuplicates; ++i) {
+    base::Time expected_t = base::Time::FromInternalValue(i + 1);
+    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
+  }
+  for (int64 i = 1; i < 1000; ++i) {
+    base::Time expected_t =
+        base::Time::FromInternalValue(i + kNumDuplicates);
+    t = base::Time::FromInternalValue(i);
+    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
+  }
+}
+
+// If the clock jumps far back enough after a run of duplicates, it
+// should immediately jump to that value.
+TEST(TimeSmoother, ClockBackwardsJump) {
+  const int64 kNumDuplicates = 100;
+  NavigationControllerImpl::TimeSmoother smoother;
+  base::Time t = base::Time::FromInternalValue(1000);
+  for (int64 i = 0; i < kNumDuplicates; ++i) {
+    base::Time expected_t = base::Time::FromInternalValue(i + 1000);
+    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
+  }
+  t = base::Time::FromInternalValue(500);
+  EXPECT_EQ(t, smoother.GetSmoothedTime(t));
+}
+
+// NavigationControllerTest ----------------------------------------------------
+
+class NavigationControllerTest
+    : public RenderViewHostImplTestHarness,
+      public WebContentsObserver {
+ public:
+  NavigationControllerTest() : navigation_entry_committed_counter_(0) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    RenderViewHostImplTestHarness::SetUp();
+    WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
+    ASSERT_TRUE(web_contents);  // The WebContents should be created by now.
+    WebContentsObserver::Observe(web_contents);
+  }
+
+  // WebContentsObserver:
+  virtual void NavigateToPendingEntry(
+      const GURL& url,
+      NavigationController::ReloadType reload_type) OVERRIDE {
+    navigated_url_ = url;
+  }
+
+  virtual void NavigationEntryCommitted(
+      const LoadCommittedDetails& load_details) OVERRIDE {
+    navigation_entry_committed_counter_++;
+  }
+
+  const GURL& navigated_url() const {
+    return navigated_url_;
+  }
+
+  NavigationControllerImpl& controller_impl() {
+    return static_cast<NavigationControllerImpl&>(controller());
+  }
+
+ protected:
+  GURL navigated_url_;
+  size_t navigation_entry_committed_counter_;
+};
+
+void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
+                                    NavigationController* controller) {
+  tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED,
+                     Source<NavigationController>(controller));
+  tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED,
+                     Source<NavigationController>(controller));
+}
+
+SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
+  return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
+}
+
+class TestWebContentsDelegate : public WebContentsDelegate {
+ public:
+  explicit TestWebContentsDelegate() :
+      navigation_state_change_count_(0) {}
+
+  int navigation_state_change_count() {
+    return navigation_state_change_count_;
+  }
+
+  // Keep track of whether the tab has notified us of a navigation state change.
+  virtual void NavigationStateChanged(const WebContents* source,
+                                      unsigned changed_flags) OVERRIDE {
+    navigation_state_change_count_++;
+  }
+
+ private:
+  // The number of times NavigationStateChanged has been called.
+  int navigation_state_change_count_;
+};
+
+// -----------------------------------------------------------------------------
+
+TEST_F(NavigationControllerTest, Defaults) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
+  EXPECT_EQ(controller.GetEntryCount(), 0);
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+TEST_F(NavigationControllerTest, GoToOffset) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const int kNumUrls = 5;
+  std::vector<GURL> urls(kNumUrls);
+  for (int i = 0; i < kNumUrls; ++i) {
+    urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
+  }
+
+  test_rvh()->SendNavigate(0, urls[0]);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_FALSE(controller.CanGoToOffset(1));
+
+  for (int i = 1; i <= 4; ++i) {
+    test_rvh()->SendNavigate(i, urls[i]);
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+    EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL());
+    EXPECT_TRUE(controller.CanGoToOffset(-i));
+    EXPECT_FALSE(controller.CanGoToOffset(-(i + 1)));
+    EXPECT_FALSE(controller.CanGoToOffset(1));
+  }
+
+  // We have loaded 5 pages, and are currently at the last-loaded page.
+  int url_index = 4;
+
+  enum Tests {
+    GO_TO_MIDDLE_PAGE = -2,
+    GO_FORWARDS = 1,
+    GO_BACKWARDS = -1,
+    GO_TO_BEGINNING = -2,
+    GO_TO_END = 4,
+    NUM_TESTS = 5,
+  };
+
+  const int test_offsets[NUM_TESTS] = {
+    GO_TO_MIDDLE_PAGE,
+    GO_FORWARDS,
+    GO_BACKWARDS,
+    GO_TO_BEGINNING,
+    GO_TO_END
+  };
+
+  for (int test = 0; test < NUM_TESTS; ++test) {
+    int offset = test_offsets[test];
+    controller.GoToOffset(offset);
+    url_index += offset;
+    // Check that the GoToOffset will land on the expected page.
+    EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
+    test_rvh()->SendNavigate(url_index, urls[url_index]);
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+    // Check that we can go to any valid offset into the history.
+    for (size_t j = 0; j < urls.size(); ++j)
+      EXPECT_TRUE(controller.CanGoToOffset(j - url_index));
+    // Check that we can't go beyond the beginning or end of the history.
+    EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1)));
+    EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index));
+  }
+}
+
+TEST_F(NavigationControllerTest, LoadURL) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  // Creating a pending notification should not have issued any of the
+  // notifications we're listening for.
+  EXPECT_EQ(0U, notifications.size());
+
+  // The load should now be pending.
+  EXPECT_EQ(controller.GetEntryCount(), 0);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  ASSERT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(contents()->GetMaxPageID(), -1);
+
+  // Neither the timestamp nor the status code should have been set yet.
+  EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
+  EXPECT_EQ(0, controller.GetPendingEntry()->GetHttpStatusCode());
+
+  // We should have gotten no notifications from the preceeding checks.
+  EXPECT_EQ(0U, notifications.size());
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The load should now be committed.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(contents()->GetMaxPageID(), 0);
+  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
+      controller.GetLastCommittedEntry())->bindings());
+
+  // The timestamp should have been set.
+  EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
+
+  // Load another...
+  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  // The load should now be pending.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  ASSERT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
+  // TODO(darin): maybe this should really be true?
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(contents()->GetMaxPageID(), 0);
+
+  EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
+
+  // Simulate the beforeunload ack for the cross-site transition, and then the
+  // commit.
+  test_rvh()->SendShouldCloseACK(true);
+  static_cast<TestRenderViewHost*>(
+      contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The load should now be committed.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(contents()->GetMaxPageID(), 1);
+
+  EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
+}
+
+namespace {
+
+base::Time GetFixedTime(base::Time time) {
+  return time;
+}
+
+}  // namespace
+
+TEST_F(NavigationControllerTest, LoadURLSameTime) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Set the clock to always return a timestamp of 1.
+  controller.SetGetTimestampCallbackForTest(
+      base::Bind(&GetFixedTime, base::Time::FromInternalValue(1)));
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Load another...
+  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  // Simulate the beforeunload ack for the cross-site transition, and then the
+  // commit.
+  test_rvh()->SendShouldCloseACK(true);
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The two loads should now be committed.
+  ASSERT_EQ(controller.GetEntryCount(), 2);
+
+  // Timestamps should be distinct despite the clock returning the
+  // same value.
+  EXPECT_EQ(1u,
+            controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
+  EXPECT_EQ(2u,
+            controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
+}
+
+void CheckNavigationEntryMatchLoadParams(
+    NavigationController::LoadURLParams& load_params,
+    NavigationEntryImpl* entry) {
+  EXPECT_EQ(load_params.url, entry->GetURL());
+  EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
+  EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy);
+  EXPECT_EQ(load_params.transition_type, entry->GetTransitionType());
+  EXPECT_EQ(load_params.extra_headers, entry->extra_headers());
+
+  EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated());
+  EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL());
+  if (!load_params.virtual_url_for_data_url.is_empty()) {
+    EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL());
+  }
+  if (NavigationController::UA_OVERRIDE_INHERIT !=
+      load_params.override_user_agent) {
+    bool should_override = (NavigationController::UA_OVERRIDE_TRUE ==
+        load_params.override_user_agent);
+    EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
+  }
+  EXPECT_EQ(load_params.browser_initiated_post_data,
+      entry->GetBrowserInitiatedPostData());
+  EXPECT_EQ(load_params.transferred_global_request_id,
+      entry->transferred_global_request_id());
+}
+
+TEST_F(NavigationControllerTest, LoadURLWithParams) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  NavigationController::LoadURLParams load_params(GURL("http://foo"));
+  load_params.referrer =
+      Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault);
+  load_params.transition_type = PAGE_TRANSITION_GENERATED;
+  load_params.extra_headers = "content-type: text/plain";
+  load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
+  load_params.is_renderer_initiated = true;
+  load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
+  load_params.transferred_global_request_id = GlobalRequestID(2, 3);
+
+  controller.LoadURLWithParams(load_params);
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetPendingEntry());
+
+  // The timestamp should not have been set yet.
+  ASSERT_TRUE(entry);
+  EXPECT_TRUE(entry->GetTimestamp().is_null());
+
+  CheckNavigationEntryMatchLoadParams(load_params, entry);
+}
+
+TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  NavigationController::LoadURLParams load_params(
+      GURL("data:text/html,dataurl"));
+  load_params.load_type = NavigationController::LOAD_TYPE_DATA;
+  load_params.base_url_for_data_url = GURL("http://foo");
+  load_params.virtual_url_for_data_url = GURL(kAboutBlankURL);
+  load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
+
+  controller.LoadURLWithParams(load_params);
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetPendingEntry());
+
+  CheckNavigationEntryMatchLoadParams(load_params, entry);
+}
+
+TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  NavigationController::LoadURLParams load_params(GURL("https://posturl"));
+  load_params.transition_type = PAGE_TRANSITION_TYPED;
+  load_params.load_type =
+      NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
+  load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
+
+
+  const unsigned char* raw_data =
+      reinterpret_cast<const unsigned char*>("d\n\0a2");
+  const int length = 5;
+  std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
+  scoped_refptr<base::RefCountedBytes> data =
+      base::RefCountedBytes::TakeVector(&post_data_vector);
+  load_params.browser_initiated_post_data = data.get();
+
+  controller.LoadURLWithParams(load_params);
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetPendingEntry());
+
+  CheckNavigationEntryMatchLoadParams(load_params, entry);
+}
+
+// Tests what happens when the same page is loaded again.  Should not create a
+// new session history entry. This is what happens when you press enter in the
+// URL bar to reload: a pending entry is created and then it is discarded when
+// the load commits (because WebCore didn't actually make a new entry).
+TEST_F(NavigationControllerTest, LoadURL_SamePage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
+  EXPECT_FALSE(timestamp.is_null());
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // We should not have produced a new session history entry.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  // The timestamp should have been updated.
+  //
+  // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
+  // EXPECT_GT once we guarantee that timestamps are unique.
+  EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
+}
+
+// Tests loading a URL but discarding it before the load commits.
+TEST_F(NavigationControllerTest, LoadURL_Discarded) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
+  EXPECT_FALSE(timestamp.is_null());
+
+  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  controller.DiscardNonCommittedEntries();
+  EXPECT_EQ(0U, notifications.size());
+
+  // Should not have produced a new session history entry.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  // Timestamp should not have changed.
+  EXPECT_EQ(timestamp, controller.GetVisibleEntry()->GetTimestamp());
+}
+
+// Tests navigations that come in unrequested. This happens when the user
+// navigates from the web page, and here we test that there is no pending entry.
+TEST_F(NavigationControllerTest, LoadURL_NoPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make an existing committed entry.
+  const GURL kExistingURL1("http://eh");
+  controller.LoadURL(
+      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, kExistingURL1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Do a new navigation without making a pending one.
+  const GURL kNewURL("http://see");
+  test_rvh()->SendNavigate(99, kNewURL);
+
+  // There should no longer be any pending entry, and the third navigation we
+  // just made should be committed.
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
+}
+
+// Tests navigating to a new URL when there is a new pending navigation that is
+// not the one that just loaded. This will happen if the user types in a URL to
+// somewhere slow, and then navigates the current page before the typed URL
+// commits.
+TEST_F(NavigationControllerTest, LoadURL_NewPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make an existing committed entry.
+  const GURL kExistingURL1("http://eh");
+  controller.LoadURL(
+      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, kExistingURL1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Make a pending entry to somewhere new.
+  const GURL kExistingURL2("http://bee");
+  controller.LoadURL(
+      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+
+  // After the beforeunload but before it commits, do a new navigation.
+  test_rvh()->SendShouldCloseACK(true);
+  const GURL kNewURL("http://see");
+  static_cast<TestRenderViewHost*>(
+      contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
+
+  // There should no longer be any pending entry, and the third navigation we
+  // just made should be committed.
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
+}
+
+// Tests navigating to a new URL when there is a pending back/forward
+// navigation. This will happen if the user hits back, but before that commits,
+// they navigate somewhere new.
+TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make some history.
+  const GURL kExistingURL1("http://foo/eh");
+  controller.LoadURL(
+      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, kExistingURL1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  const GURL kExistingURL2("http://foo/bee");
+  controller.LoadURL(
+      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(1, kExistingURL2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now make a pending back/forward navigation. The zeroth entry should be
+  // pending.
+  controller.GoBack();
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(0, controller.GetPendingEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+  // Before that commits, do a new navigation.
+  const GURL kNewURL("http://foo/see");
+  LoadCommittedDetails details;
+  test_rvh()->SendNavigate(3, kNewURL);
+
+  // There should no longer be any pending entry, and the third navigation we
+  // just made should be committed.
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
+}
+
+// Tests navigating to a new URL when there is a pending back/forward
+// navigation to a cross-process, privileged URL. This will happen if the user
+// hits back, but before that commits, they navigate somewhere new.
+TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make some history, starting with a privileged URL.
+  const GURL kExistingURL1("http://privileged");
+  controller.LoadURL(
+      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  // Pretend it has bindings so we can tell if we incorrectly copy it.
+  test_rvh()->AllowBindings(2);
+  test_rvh()->SendNavigate(0, kExistingURL1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Navigate cross-process to a second URL.
+  const GURL kExistingURL2("http://foo/eh");
+  controller.LoadURL(
+      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendShouldCloseACK(true);
+  TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>(
+      contents()->GetPendingRenderViewHost());
+  foo_rvh->SendNavigate(1, kExistingURL2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now make a pending back/forward navigation to a privileged entry.
+  // The zeroth entry should be pending.
+  controller.GoBack();
+  foo_rvh->SendShouldCloseACK(true);
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(0, controller.GetPendingEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
+                controller.GetPendingEntry())->bindings());
+
+  // Before that commits, do a new navigation.
+  const GURL kNewURL("http://foo/bee");
+  LoadCommittedDetails details;
+  foo_rvh->SendNavigate(3, kNewURL);
+
+  // There should no longer be any pending entry, and the third navigation we
+  // just made should be committed.
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
+                controller.GetLastCommittedEntry())->bindings());
+}
+
+// Tests navigating to an existing URL when there is a pending new navigation.
+// This will happen if the user enters a URL, but before that commits, the
+// current page fires history.back().
+TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make some history.
+  const GURL kExistingURL1("http://foo/eh");
+  controller.LoadURL(
+      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, kExistingURL1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  const GURL kExistingURL2("http://foo/bee");
+  controller.LoadURL(
+      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(1, kExistingURL2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now make a pending new navigation.
+  const GURL kNewURL("http://foo/see");
+  controller.LoadURL(
+      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+  // Before that commits, a back navigation from the renderer commits.
+  test_rvh()->SendNavigate(0, kExistingURL1);
+
+  // There should no longer be any pending entry, and the back navigation we
+  // just made should be committed.
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kExistingURL1, controller.GetVisibleEntry()->GetURL());
+}
+
+// Tests an ignored navigation when there is a pending new navigation.
+// This will happen if the user enters a URL, but before that commits, the
+// current blank page reloads.  See http://crbug.com/77507.
+TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Set a WebContentsDelegate to listen for state changes.
+  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
+  EXPECT_FALSE(contents()->GetDelegate());
+  contents()->SetDelegate(delegate.get());
+
+  // Without any navigations, the renderer starts at about:blank.
+  const GURL kExistingURL(kAboutBlankURL);
+
+  // Now make a pending new navigation.
+  const GURL kNewURL("http://eh");
+  controller.LoadURL(
+      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(1, delegate->navigation_state_change_count());
+
+  // Before that commits, a document.write and location.reload can cause the
+  // renderer to send a FrameNavigate with page_id -1.
+  test_rvh()->SendNavigate(-1, kExistingURL);
+
+  // This should clear the pending entry and notify of a navigation state
+  // change, so that we do not keep displaying kNewURL.
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(2, delegate->navigation_state_change_count());
+
+  contents()->SetDelegate(NULL);
+}
+
+// Tests that the pending entry state is correct after an abort.
+// We do not want to clear the pending entry, so that the user doesn't
+// lose a typed URL.  (See http://crbug.com/9682.)
+TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Set a WebContentsDelegate to listen for state changes.
+  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
+  EXPECT_FALSE(contents()->GetDelegate());
+  contents()->SetDelegate(delegate.get());
+
+  // Start with a pending new navigation.
+  const GURL kNewURL("http://eh");
+  controller.LoadURL(
+      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(1, delegate->navigation_state_change_count());
+
+  // It may abort before committing, if it's a download or due to a stop or
+  // a new navigation from the user.
+  ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
+  params.frame_id = 1;
+  params.is_main_frame = true;
+  params.error_code = net::ERR_ABORTED;
+  params.error_description = string16();
+  params.url = kNewURL;
+  params.showing_repost_interstitial = false;
+  test_rvh()->OnMessageReceived(
+          ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
+                                                      params));
+
+  // This should not clear the pending entry or notify of a navigation state
+  // change, so that we keep displaying kNewURL (until the user clears it).
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(1, delegate->navigation_state_change_count());
+  NavigationEntry* pending_entry = controller.GetPendingEntry();
+
+  // Ensure that a reload keeps the same pending entry.
+  controller.Reload(true);
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(pending_entry, controller.GetPendingEntry());
+  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+
+  contents()->SetDelegate(NULL);
+}
+
+// Tests that the pending URL is not visible during a renderer-initiated
+// redirect and abort.  See http://crbug.com/83031.
+TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // First make an existing committed entry.
+  const GURL kExistingURL("http://foo/eh");
+  controller.LoadURL(kExistingURL, content::Referrer(),
+                     content::PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, kExistingURL);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Set a WebContentsDelegate to listen for state changes.
+  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
+  EXPECT_FALSE(contents()->GetDelegate());
+  contents()->SetDelegate(delegate.get());
+
+  // Now make a pending new navigation, initiated by the renderer.
+  const GURL kNewURL("http://foo/bee");
+  NavigationController::LoadURLParams load_url_params(kNewURL);
+  load_url_params.transition_type = PAGE_TRANSITION_TYPED;
+  load_url_params.is_renderer_initiated = true;
+  controller.LoadURLWithParams(load_url_params);
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, delegate->navigation_state_change_count());
+
+  // The visible entry should be the last committed URL, not the pending one.
+  EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
+
+  // Now the navigation redirects.
+  const GURL kRedirectURL("http://foo/see");
+  test_rvh()->OnMessageReceived(
+      ViewHostMsg_DidRedirectProvisionalLoad(0,  // routing_id
+                                             -1,  // pending page_id
+                                             kNewURL,  // old url
+                                             kRedirectURL));  // new url
+
+  // We don't want to change the NavigationEntry's url, in case it cancels.
+  // Prevents regression of http://crbug.com/77786.
+  EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
+
+  // It may abort before committing, if it's a download or due to a stop or
+  // a new navigation from the user.
+  ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
+  params.frame_id = 1;
+  params.is_main_frame = true;
+  params.error_code = net::ERR_ABORTED;
+  params.error_description = string16();
+  params.url = kRedirectURL;
+  params.showing_repost_interstitial = false;
+  test_rvh()->OnMessageReceived(
+          ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
+                                                      params));
+
+  // Because the pending entry is renderer initiated and not visible, we
+  // clear it when it fails.
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, delegate->navigation_state_change_count());
+
+  // The visible entry should be the last committed URL, not the pending one,
+  // so that no spoof is possible.
+  EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
+
+  contents()->SetDelegate(NULL);
+}
+
+// Ensure that NavigationEntries track which bindings their RenderViewHost had
+// at the time they committed.  http://crbug.com/173672.
+TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  // Navigate to a first, unprivileged URL.
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
+            NavigationEntryImpl::FromNavigationEntry(
+                controller.GetPendingEntry())->bindings());
+
+  // Commit.
+  TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh());
+  orig_rvh->SendNavigate(0, url1);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
+      controller.GetLastCommittedEntry())->bindings());
+
+  // Manually increase the number of active views in the SiteInstance
+  // that orig_rvh belongs to, to prevent it from being destroyed when
+  // it gets swapped out, so that we can reuse orig_rvh when the
+  // controller goes back.
+  static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
+      increment_active_view_count();
+
+  // Navigate to a second URL, simulate the beforeunload ack for the cross-site
+  // transition, and set bindings on the pending RenderViewHost to simulate a
+  // privileged url.
+  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  orig_rvh->SendShouldCloseACK(true);
+  contents()->GetPendingRenderViewHost()->AllowBindings(1);
+  static_cast<TestRenderViewHost*>(
+      contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
+
+  // The second load should be committed, and bindings should be remembered.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
+      controller.GetLastCommittedEntry())->bindings());
+
+  // Going back, the first entry should still appear unprivileged.
+  controller.GoBack();
+  orig_rvh->SendNavigate(0, url1);
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
+      controller.GetLastCommittedEntry())->bindings());
+}
+
+TEST_F(NavigationControllerTest, Reload) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title"));
+  controller.Reload(true);
+  EXPECT_EQ(0U, notifications.size());
+
+  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
+  EXPECT_FALSE(timestamp.is_null());
+
+  // The reload is pending.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  // Make sure the title has been cleared (will be redrawn just after reload).
+  // Avoids a stale cached title when the new page being reloaded has no title.
+  // See http://crbug.com/96041.
+  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now the reload is committed.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  // The timestamp should have been updated.
+  ASSERT_TRUE(controller.GetVisibleEntry());
+  EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
+}
+
+// Tests what happens when a reload navigation produces a new page.
+TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.Reload(true);
+  EXPECT_EQ(0U, notifications.size());
+
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now the reload is committed.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+#if !defined(OS_ANDROID)  // http://crbug.com/157428
+TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL original_url("http://foo1");
+  const GURL final_url("http://foo2");
+
+  // Load up the original URL, but get redirected.
+  controller.LoadURL(
+      original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url, original_url);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The NavigationEntry should save both the original URL and the final
+  // redirected URL.
+  EXPECT_EQ(
+      original_url, controller.GetVisibleEntry()->GetOriginalRequestURL());
+  EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL());
+
+  // Reload using the original URL.
+  controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title"));
+  controller.ReloadOriginalRequestURL(false);
+  EXPECT_EQ(0U, notifications.size());
+
+  // The reload is pending.  The request should point to the original URL.
+  EXPECT_EQ(original_url, navigated_url());
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  // Make sure the title has been cleared (will be redrawn just after reload).
+  // Avoids a stale cached title when the new page being reloaded has no title.
+  // See http://crbug.com/96041.
+  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
+
+  // Send that the navigation has proceeded; say it got redirected again.
+  test_rvh()->SendNavigate(0, final_url);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now the reload is committed.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+#endif  // !defined(OS_ANDROID)
+
+// Test that certain non-persisted NavigationEntryImpl values get reset after
+// commit.
+TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  // Set up some sample values.
+  const unsigned char* raw_data =
+      reinterpret_cast<const unsigned char*>("post\n\n\0data");
+  const int length = 11;
+  std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
+  scoped_refptr<base::RefCountedBytes> post_data =
+      base::RefCountedBytes::TakeVector(&post_data_vector);
+  GlobalRequestID transfer_id(3, 4);
+  std::vector<GURL> redirects;
+  redirects.push_back(GURL("http://foo2"));
+
+  // Set non-persisted values on the pending entry.
+  NavigationEntryImpl* pending_entry =
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
+  pending_entry->SetBrowserInitiatedPostData(post_data.get());
+  pending_entry->set_is_renderer_initiated(true);
+  pending_entry->set_transferred_global_request_id(transfer_id);
+  pending_entry->set_should_replace_entry(true);
+  pending_entry->set_redirect_chain(redirects);
+  pending_entry->set_should_clear_history_list(true);
+  EXPECT_EQ(post_data.get(), pending_entry->GetBrowserInitiatedPostData());
+  EXPECT_TRUE(pending_entry->is_renderer_initiated());
+  EXPECT_EQ(transfer_id, pending_entry->transferred_global_request_id());
+  EXPECT_TRUE(pending_entry->should_replace_entry());
+  EXPECT_EQ(1U, pending_entry->redirect_chain().size());
+  EXPECT_TRUE(pending_entry->should_clear_history_list());
+
+  test_rvh()->SendNavigate(0, url1);
+
+  // Certain values that are only used for pending entries get reset after
+  // commit.
+  NavigationEntryImpl* committed_entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetLastCommittedEntry());
+  EXPECT_FALSE(committed_entry->GetBrowserInitiatedPostData());
+  EXPECT_FALSE(committed_entry->is_renderer_initiated());
+  EXPECT_EQ(GlobalRequestID(-1, -1),
+            committed_entry->transferred_global_request_id());
+  EXPECT_FALSE(committed_entry->should_replace_entry());
+  EXPECT_EQ(0U, committed_entry->redirect_chain().size());
+  EXPECT_FALSE(committed_entry->should_clear_history_list());
+}
+
+// Tests what happens when we navigate back successfully
+TEST_F(NavigationControllerTest, Back) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  const GURL url2("http://foo2");
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoBack();
+  EXPECT_EQ(0U, notifications.size());
+
+  // We should now have a pending navigation to go back.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoToOffset(-1));
+  EXPECT_TRUE(controller.CanGoForward());
+  EXPECT_TRUE(controller.CanGoToOffset(1));
+  EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
+
+  // Timestamp for entry 1 should be on or after that of entry 0.
+  EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
+  EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
+            controller.GetEntryAtIndex(0)->GetTimestamp());
+
+  test_rvh()->SendNavigate(0, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The back navigation completed successfully.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoToOffset(-1));
+  EXPECT_TRUE(controller.CanGoForward());
+  EXPECT_TRUE(controller.CanGoToOffset(1));
+  EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
+
+  // Timestamp for entry 0 should be on or after that of entry 1
+  // (since we went back to it).
+  EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
+            controller.GetEntryAtIndex(1)->GetTimestamp());
+}
+
+// Tests what happens when a back navigation produces a new page.
+TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoBack();
+  EXPECT_EQ(0U, notifications.size());
+
+  // We should now have a pending navigation to go back.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_TRUE(controller.CanGoForward());
+
+  test_rvh()->SendNavigate(2, url3);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The back navigation resulted in a completely new navigation.
+  // TODO(darin): perhaps this behavior will be confusing to users?
+  EXPECT_EQ(controller.GetEntryCount(), 3);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+// Receives a back message when there is a new pending navigation entry.
+TEST_F(NavigationControllerTest, Back_NewPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL kUrl1("http://foo1");
+  const GURL kUrl2("http://foo2");
+  const GURL kUrl3("http://foo3");
+
+  // First navigate two places so we have some back history.
+  test_rvh()->SendNavigate(0, kUrl1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
+  test_rvh()->SendNavigate(1, kUrl2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Now start a new pending navigation and go back before it commits.
+  controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
+  controller.GoBack();
+
+  // The pending navigation should now be the "back" item and the new one
+  // should be gone.
+  EXPECT_EQ(0, controller.GetPendingEntryIndex());
+  EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
+}
+
+// Receives a back message when there is a different renavigation already
+// pending.
+TEST_F(NavigationControllerTest, Back_OtherBackPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL kUrl1("http://foo/1");
+  const GURL kUrl2("http://foo/2");
+  const GURL kUrl3("http://foo/3");
+
+  // First navigate three places so we have some back history.
+  test_rvh()->SendNavigate(0, kUrl1);
+  test_rvh()->SendNavigate(1, kUrl2);
+  test_rvh()->SendNavigate(2, kUrl3);
+
+  // With nothing pending, say we get a navigation to the second entry.
+  test_rvh()->SendNavigate(1, kUrl2);
+
+  // We know all the entries have the same site instance, so we can just grab
+  // a random one for looking up other entries.
+  SiteInstance* site_instance =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetLastCommittedEntry())->site_instance();
+
+  // That second URL should be the last committed and it should have gotten the
+  // new title.
+  EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+
+  // Now go forward to the last item again and say it was committed.
+  controller.GoForward();
+  test_rvh()->SendNavigate(2, kUrl3);
+
+  // Now start going back one to the second page. It will be pending.
+  controller.GoBack();
+  EXPECT_EQ(1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+
+  // Not synthesize a totally new back event to the first page. This will not
+  // match the pending one.
+  test_rvh()->SendNavigate(0, kUrl1);
+
+  // The committed navigation should clear the pending entry.
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+
+  // But the navigated entry should be the last committed.
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
+}
+
+// Tests what happens when we navigate forward successfully.
+TEST_F(NavigationControllerTest, Forward) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoBack();
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoForward();
+
+  // We should now have a pending navigation to go forward.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_TRUE(controller.CanGoToOffset(-1));
+  EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_FALSE(controller.CanGoToOffset(1));
+
+  // Timestamp for entry 0 should be on or after that of entry 1
+  // (since we went back to it).
+  EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
+  EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
+            controller.GetEntryAtIndex(1)->GetTimestamp());
+
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // The forward navigation completed successfully.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_TRUE(controller.CanGoToOffset(-1));
+  EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_FALSE(controller.CanGoToOffset(1));
+
+  // Timestamp for entry 1 should be on or after that of entry 0
+  // (since we went forward to it).
+  EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
+            controller.GetEntryAtIndex(0)->GetTimestamp());
+}
+
+// Tests what happens when a forward navigation produces a new page.
+TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoBack();
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  controller.GoForward();
+  EXPECT_EQ(0U, notifications.size());
+
+  // Should now have a pending navigation to go forward.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  test_rvh()->SendNavigate(2, url3);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
+
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+// Two consequent navigation for the same URL entered in should be considered
+// as SAME_PAGE navigation even when we are redirected to some other page.
+TEST_F(NavigationControllerTest, Redirect) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");  // Redirection target
+
+  // First request
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Second request
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+  params.redirects.push_back(GURL("http://foo1"));
+  params.redirects.push_back(GURL("http://foo2"));
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  LoadCommittedDetails details;
+
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+// Similar to Redirect above, but the first URL is requested by POST,
+// the second URL is requested by GET. NavigationEntry::has_post_data_
+// must be cleared. http://crbug.com/21245
+TEST_F(NavigationControllerTest, PostThenRedirect) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");  // Redirection target
+
+  // First request as POST
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  controller.GetVisibleEntry()->SetHasPostData(true);
+
+  EXPECT_EQ(0U, notifications.size());
+  test_rvh()->SendNavigate(0, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Second request
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+  params.redirects.push_back(GURL("http://foo1"));
+  params.redirects.push_back(GURL("http://foo2"));
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  LoadCommittedDetails details;
+
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+  EXPECT_FALSE(controller.GetVisibleEntry()->GetHasPostData());
+
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+// A redirect right off the bat should be a NEW_PAGE.
+TEST_F(NavigationControllerTest, ImmediateRedirect) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");  // Redirection target
+
+  // First request
+  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+  params.redirects.push_back(GURL("http://foo1"));
+  params.redirects.push_back(GURL("http://foo2"));
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  LoadCommittedDetails details;
+
+  EXPECT_EQ(0U, notifications.size());
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+// Tests navigation via link click within a subframe. A new navigation entry
+// should be created.
+TEST_F(NavigationControllerTest, NewSubframe) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  const GURL url2("http://foo2");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 1;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  LoadCommittedDetails details;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(url1, details.previous_url);
+  EXPECT_FALSE(details.is_in_page);
+  EXPECT_FALSE(details.is_main_frame);
+
+  // The new entry should be appended.
+  EXPECT_EQ(2, controller.GetEntryCount());
+
+  // New entry should refer to the new page, but the old URL (entries only
+  // reflect the toplevel URL).
+  EXPECT_EQ(url1, details.entry->GetURL());
+  EXPECT_EQ(params.page_id, details.entry->GetPageID());
+}
+
+// Some pages create a popup, then write an iframe into it. This causes a
+// subframe navigation without having any committed entry. Such navigations
+// just get thrown on the ground, but we shouldn't crash.
+TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Navigation controller currently has no entries.
+  const GURL url("http://foo2");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 1;
+  params.url = url;
+  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url);
+
+  LoadCommittedDetails details;
+  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(0U, notifications.size());
+}
+
+// Auto subframes are ones the page loads automatically like ads. They should
+// not create new navigation entries.
+TEST_F(NavigationControllerTest, AutoSubframe) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  const GURL url2("http://foo2");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  // Navigating should do nothing.
+  LoadCommittedDetails details;
+  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(0U, notifications.size());
+
+  // There should still be only one entry.
+  EXPECT_EQ(1, controller.GetEntryCount());
+}
+
+// Tests navigation and then going back to a subframe navigation.
+TEST_F(NavigationControllerTest, BackSubframe) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Main page.
+  const GURL url1("http://foo1");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // First manual subframe navigation.
+  const GURL url2("http://foo2");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 1;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  // This should generate a new entry.
+  LoadCommittedDetails details;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(2, controller.GetEntryCount());
+
+  // Second manual subframe navigation should also make a new entry.
+  const GURL url3("http://foo3");
+  params.page_id = 2;
+  params.url = url3;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+
+  // Go back one.
+  controller.GoBack();
+  params.url = url2;
+  params.page_id = 1;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+
+  // Go back one more.
+  controller.GoBack();
+  params.url = url1;
+  params.page_id = 0;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+}
+
+TEST_F(NavigationControllerTest, LinkClick) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  test_rvh()->SendNavigate(1, url2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Should not have produced a new session history entry.
+  EXPECT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+}
+
+TEST_F(NavigationControllerTest, InPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Main page.
+  const GURL url1("http://foo");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Ensure main page navigation to same url respects the was_within_same_page
+  // hint provided in the params.
+  ViewHostMsg_FrameNavigate_Params self_params;
+  self_params.page_id = 0;
+  self_params.url = url1;
+  self_params.transition = PAGE_TRANSITION_LINK;
+  self_params.should_update_history = false;
+  self_params.gesture = NavigationGestureUser;
+  self_params.is_post = false;
+  self_params.page_state = PageState::CreateFromURL(url1);
+  self_params.was_within_same_page = true;
+
+  LoadCommittedDetails details;
+  EXPECT_TRUE(controller.RendererDidNavigate(self_params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(details.is_in_page);
+  EXPECT_TRUE(details.did_replace_entry);
+  EXPECT_EQ(1, controller.GetEntryCount());
+
+  // Fragment navigation to a new page_id.
+  const GURL url2("http://foo#a");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 1;
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_LINK;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+  params.was_within_same_page = true;
+
+  // This should generate a new entry.
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(details.is_in_page);
+  EXPECT_FALSE(details.did_replace_entry);
+  EXPECT_EQ(2, controller.GetEntryCount());
+
+  // Go back one.
+  ViewHostMsg_FrameNavigate_Params back_params(params);
+  controller.GoBack();
+  back_params.url = url1;
+  back_params.page_id = 0;
+  EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(details.is_in_page);
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
+
+  // Go forward
+  ViewHostMsg_FrameNavigate_Params forward_params(params);
+  controller.GoForward();
+  forward_params.url = url2;
+  forward_params.page_id = 1;
+  EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(details.is_in_page);
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(forward_params.url,
+            controller.GetVisibleEntry()->GetURL());
+
+  // Now go back and forward again. This is to work around a bug where we would
+  // compare the incoming URL with the last committed entry rather than the
+  // one identified by an existing page ID. This would result in the second URL
+  // losing the reference fragment when you navigate away from it and then back.
+  controller.GoBack();
+  EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
+  controller.GoForward();
+  EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
+  EXPECT_EQ(forward_params.url,
+            controller.GetVisibleEntry()->GetURL());
+
+  // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
+  const GURL url3("http://bar");
+  params.page_id = 2;
+  params.url = url3;
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_FALSE(details.is_in_page);
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+}
+
+TEST_F(NavigationControllerTest, InPage_Replace) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Main page.
+  const GURL url1("http://foo");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // First navigation.
+  const GURL url2("http://foo#a");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;  // Same page_id
+  params.url = url2;
+  params.transition = PAGE_TRANSITION_LINK;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url2);
+
+  // This should NOT generate a new entry, nor prune the list.
+  LoadCommittedDetails details;
+  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_TRUE(details.is_in_page);
+  EXPECT_TRUE(details.did_replace_entry);
+  EXPECT_EQ(1, controller.GetEntryCount());
+}
+
+// Tests for http://crbug.com/40395
+// Simulates this:
+//   <script>
+//     window.location.replace("#a");
+//     window.location='http://foo3/';
+//   </script>
+TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Load an initial page.
+  {
+    const GURL url("http://foo/");
+    test_rvh()->SendNavigate(0, url);
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+  }
+
+  // Navigate to a new page.
+  {
+    const GURL url("http://foo2/");
+    test_rvh()->SendNavigate(1, url);
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+  }
+
+  // Navigate within the page.
+  {
+    const GURL url("http://foo2/#a");
+    ViewHostMsg_FrameNavigate_Params params;
+    params.page_id = 1;  // Same page_id
+    params.url = url;
+    params.transition = PAGE_TRANSITION_LINK;
+    params.redirects.push_back(url);
+    params.should_update_history = true;
+    params.gesture = NavigationGestureUnknown;
+    params.is_post = false;
+    params.page_state = PageState::CreateFromURL(url);
+
+    // This should NOT generate a new entry, nor prune the list.
+    LoadCommittedDetails details;
+    EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+    EXPECT_TRUE(details.is_in_page);
+    EXPECT_TRUE(details.did_replace_entry);
+    EXPECT_EQ(2, controller.GetEntryCount());
+  }
+
+  // Perform a client redirect to a new page.
+  {
+    const GURL url("http://foo3/");
+    ViewHostMsg_FrameNavigate_Params params;
+    params.page_id = 2;  // New page_id
+    params.url = url;
+    params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
+    params.redirects.push_back(GURL("http://foo2/#a"));
+    params.redirects.push_back(url);
+    params.should_update_history = true;
+    params.gesture = NavigationGestureUnknown;
+    params.is_post = false;
+    params.page_state = PageState::CreateFromURL(url);
+
+    // This SHOULD generate a new entry.
+    LoadCommittedDetails details;
+    EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+    EXPECT_FALSE(details.is_in_page);
+    EXPECT_EQ(3, controller.GetEntryCount());
+  }
+
+  // Verify that BACK brings us back to http://foo2/.
+  {
+    const GURL url("http://foo2/");
+    controller.GoBack();
+    test_rvh()->SendNavigate(1, url);
+    EXPECT_EQ(1U, navigation_entry_committed_counter_);
+    navigation_entry_committed_counter_ = 0;
+    EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
+  }
+}
+
+// NotificationObserver implementation used in verifying we've received the
+// NOTIFICATION_NAV_LIST_PRUNED method.
+class PrunedListener : public NotificationObserver {
+ public:
+  explicit PrunedListener(NavigationControllerImpl* controller)
+      : notification_count_(0) {
+    registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED,
+                   Source<NavigationController>(controller));
+  }
+
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE {
+    if (type == NOTIFICATION_NAV_LIST_PRUNED) {
+      notification_count_++;
+      details_ = *(Details<PrunedDetails>(details).ptr());
+    }
+  }
+
+  // Number of times NAV_LIST_PRUNED has been observed.
+  int notification_count_;
+
+  // Details from the last NAV_LIST_PRUNED.
+  PrunedDetails details_;
+
+ private:
+  NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrunedListener);
+};
+
+// Tests that we limit the number of navigation entries created correctly.
+TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
+  NavigationControllerImpl& controller = controller_impl();
+  size_t original_count = NavigationControllerImpl::max_entry_count();
+  const int kMaxEntryCount = 5;
+
+  NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
+
+  int url_index;
+  // Load up to the max count, all entries should be there.
+  for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
+    GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
+    controller.LoadURL(
+        url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+    test_rvh()->SendNavigate(url_index, url);
+  }
+
+  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
+
+  // Created a PrunedListener to observe prune notifications.
+  PrunedListener listener(&controller);
+
+  // Navigate some more.
+  GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
+  controller.LoadURL(
+      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(url_index, url);
+  url_index++;
+
+  // We should have got a pruned navigation.
+  EXPECT_EQ(1, listener.notification_count_);
+  EXPECT_TRUE(listener.details_.from_front);
+  EXPECT_EQ(1, listener.details_.count);
+
+  // We expect http://www.a.com/0 to be gone.
+  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
+            GURL("http:////www.a.com/1"));
+
+  // More navigations.
+  for (int i = 0; i < 3; i++) {
+    url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
+    controller.LoadURL(
+        url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+    test_rvh()->SendNavigate(url_index, url);
+    url_index++;
+  }
+  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
+            GURL("http:////www.a.com/4"));
+
+  NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
+}
+
+// Tests that we can do a restore and navigate to the restored entries and
+// everything is updated properly. This can be tricky since there is no
+// SiteInstance for the entries created initially.
+TEST_F(NavigationControllerTest, RestoreNavigate) {
+  // Create a NavigationController with a restored set of tabs.
+  GURL url("http://foo");
+  std::vector<NavigationEntry*> entries;
+  NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
+      url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
+      browser_context());
+  entry->SetPageID(0);
+  entry->SetTitle(ASCIIToUTF16("Title"));
+  entry->SetPageState(PageState::CreateFromEncodedData("state"));
+  const base::Time timestamp = base::Time::Now();
+  entry->SetTimestamp(timestamp);
+  entries.push_back(entry);
+  scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
+      WebContents::Create(WebContents::CreateParams(browser_context()))));
+  NavigationControllerImpl& our_controller = our_contents->GetController();
+  our_controller.Restore(
+      0,
+      NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+      &entries);
+  ASSERT_EQ(0u, entries.size());
+
+  // Before navigating to the restored entry, it should have a restore_type
+  // and no SiteInstance.
+  ASSERT_EQ(1, our_controller.GetEntryCount());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetEntryAtIndex(0))->restore_type());
+  EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
+      our_controller.GetEntryAtIndex(0))->site_instance());
+
+  // After navigating, we should have one entry, and it should be "pending".
+  // It should now have a SiteInstance and no restore_type.
+  our_controller.GoToIndex(0);
+  EXPECT_EQ(1, our_controller.GetEntryCount());
+  EXPECT_EQ(our_controller.GetEntryAtIndex(0),
+            our_controller.GetPendingEntry());
+  EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
+            NavigationEntryImpl::FromNavigationEntry
+                (our_controller.GetEntryAtIndex(0))->restore_type());
+  EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
+      our_controller.GetEntryAtIndex(0))->site_instance());
+
+  // Timestamp should remain the same before the navigation finishes.
+  EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
+
+  // Say we navigated to that entry.
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url;
+  params.transition = PAGE_TRANSITION_LINK;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url);
+  LoadCommittedDetails details;
+  our_controller.RendererDidNavigate(params, &details);
+
+  // There should be no longer any pending entry and one committed one. This
+  // means that we were able to locate the entry, assign its site instance, and
+  // commit it properly.
+  EXPECT_EQ(1, our_controller.GetEntryCount());
+  EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
+  EXPECT_FALSE(our_controller.GetPendingEntry());
+  EXPECT_EQ(url,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetLastCommittedEntry())->site_instance()->
+                    GetSiteURL());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetEntryAtIndex(0))->restore_type());
+
+  // Timestamp should have been updated.
+  EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
+}
+
+// Tests that we can still navigate to a restored entry after a different
+// navigation fails and clears the pending entry.  http://crbug.com/90085
+TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
+  // Create a NavigationController with a restored set of tabs.
+  GURL url("http://foo");
+  std::vector<NavigationEntry*> entries;
+  NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
+      url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
+      browser_context());
+  entry->SetPageID(0);
+  entry->SetTitle(ASCIIToUTF16("Title"));
+  entry->SetPageState(PageState::CreateFromEncodedData("state"));
+  entries.push_back(entry);
+  scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
+      WebContents::Create(WebContents::CreateParams(browser_context()))));
+  NavigationControllerImpl& our_controller = our_contents->GetController();
+  our_controller.Restore(
+      0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
+  ASSERT_EQ(0u, entries.size());
+
+  // Before navigating to the restored entry, it should have a restore_type
+  // and no SiteInstance.
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetEntryAtIndex(0))->restore_type());
+  EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
+      our_controller.GetEntryAtIndex(0))->site_instance());
+
+  // After navigating, we should have one entry, and it should be "pending".
+  // It should now have a SiteInstance and no restore_type.
+  our_controller.GoToIndex(0);
+  EXPECT_EQ(1, our_controller.GetEntryCount());
+  EXPECT_EQ(our_controller.GetEntryAtIndex(0),
+            our_controller.GetPendingEntry());
+  EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetEntryAtIndex(0))->restore_type());
+  EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
+      our_controller.GetEntryAtIndex(0))->site_instance());
+
+  // This pending navigation may have caused a different navigation to fail,
+  // which causes the pending entry to be cleared.
+  TestRenderViewHost* rvh =
+      static_cast<TestRenderViewHost*>(our_contents->GetRenderViewHost());
+  ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
+  fail_load_params.frame_id = 1;
+  fail_load_params.is_main_frame = true;
+  fail_load_params.error_code = net::ERR_ABORTED;
+  fail_load_params.error_description = string16();
+  fail_load_params.url = url;
+  fail_load_params.showing_repost_interstitial = false;
+  rvh->OnMessageReceived(
+      ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
+                                                  fail_load_params));
+
+  // Now the pending restored entry commits.
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = url;
+  params.transition = PAGE_TRANSITION_LINK;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureUser;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url);
+  LoadCommittedDetails details;
+  our_controller.RendererDidNavigate(params, &details);
+
+  // There should be no pending entry and one committed one.
+  EXPECT_EQ(1, our_controller.GetEntryCount());
+  EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
+  EXPECT_FALSE(our_controller.GetPendingEntry());
+  EXPECT_EQ(url,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetLastCommittedEntry())->site_instance()->
+                    GetSiteURL());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
+            NavigationEntryImpl::FromNavigationEntry(
+                our_controller.GetEntryAtIndex(0))->restore_type());
+}
+
+// Make sure that the page type and stuff is correct after an interstitial.
+TEST_F(NavigationControllerTest, Interstitial) {
+  NavigationControllerImpl& controller = controller_impl();
+  // First navigate somewhere normal.
+  const GURL url1("http://foo");
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url1);
+
+  // Now navigate somewhere with an interstitial.
+  const GURL url2("http://bar");
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+      set_page_type(PAGE_TYPE_INTERSTITIAL);
+
+  // At this point the interstitial will be displayed and the load will still
+  // be pending. If the user continues, the load will commit.
+  test_rvh()->SendNavigate(1, url2);
+
+  // The page should be a normal page again.
+  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
+  EXPECT_EQ(PAGE_TYPE_NORMAL,
+            controller.GetLastCommittedEntry()->GetPageType());
+}
+
+TEST_F(NavigationControllerTest, RemoveEntry) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+  const GURL url4("http://foo/4");
+  const GURL url5("http://foo/5");
+  const GURL pending_url("http://foo/pending");
+  const GURL default_url("http://foo/default");
+
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url1);
+  controller.LoadURL(
+      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(1, url2);
+  controller.LoadURL(
+      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(2, url3);
+  controller.LoadURL(
+      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(3, url4);
+  controller.LoadURL(
+      url5, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(4, url5);
+
+  // Try to remove the last entry.  Will fail because it is the current entry.
+  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
+  EXPECT_EQ(5, controller.GetEntryCount());
+  EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
+
+  // Go back, but don't commit yet. Check that we can't delete the current
+  // and pending entries.
+  controller.GoBack();
+  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
+  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
+
+  // Now commit and delete the last entry.
+  test_rvh()->SendNavigate(3, url4);
+  EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
+  EXPECT_EQ(4, controller.GetEntryCount());
+  EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+
+  // Remove an entry which is not the last committed one.
+  EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+
+  // Remove the 2 remaining entries.
+  controller.RemoveEntryAtIndex(1);
+  controller.RemoveEntryAtIndex(0);
+
+  // This should leave us with only the last committed entry.
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+}
+
+// Tests the transient entry, making sure it goes away with all navigations.
+TEST_F(NavigationControllerTest, TransientEntry) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url0("http://foo/0");
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+  const GURL url3_ref("http://foo/3#bar");
+  const GURL url4("http://foo/4");
+  const GURL transient_url("http://foo/transient");
+
+  controller.LoadURL(
+      url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url0);
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(1, url1);
+
+  notifications.Reset();
+
+  // Adding a transient with no pending entry.
+  NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+
+  // We should not have received any notifications.
+  EXPECT_EQ(0U, notifications.size());
+
+  // Check our state.
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(controller.GetEntryCount(), 3);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(contents()->GetMaxPageID(), 1);
+
+  // Navigate.
+  controller.LoadURL(
+      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(2, url2);
+
+  // We should have navigated, transient entry should be gone.
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(controller.GetEntryCount(), 3);
+
+  // Add a transient again, then navigate with no pending entry this time.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(3, url3);
+  // Transient entry should be gone.
+  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(controller.GetEntryCount(), 4);
+
+  // Initiate a navigation, add a transient then commit navigation.
+  controller.LoadURL(
+      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(4, url4);
+  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(controller.GetEntryCount(), 5);
+
+  // Add a transient and go back.  This should simply remove the transient.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  controller.GoBack();
+  // Transient entry should be gone.
+  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(controller.GetEntryCount(), 5);
+  test_rvh()->SendNavigate(3, url3);
+
+  // Add a transient and go to an entry before the current one.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  controller.GoToIndex(1);
+  // The navigation should have been initiated, transient entry should be gone.
+  EXPECT_FALSE(controller.GetTransientEntry());
+  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
+  // Visible entry does not update for history navigations until commit.
+  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(1, url1);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+  // Add a transient and go to an entry after the current one.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  controller.GoToIndex(3);
+  // The navigation should have been initiated, transient entry should be gone.
+  // Because of the transient entry that is removed, going to index 3 makes us
+  // land on url2 (which is visible after the commit).
+  EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(2, url2);
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+
+  // Add a transient and go forward.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  EXPECT_TRUE(controller.CanGoForward());
+  controller.GoForward();
+  // We should have navigated, transient entry should be gone.
+  EXPECT_FALSE(controller.GetTransientEntry());
+  EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL());
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(3, url3);
+  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
+
+  // Add a transient and do an in-page navigation, replacing the current entry.
+  transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(3, url3_ref);
+  // Transient entry should be gone.
+  EXPECT_FALSE(controller.GetTransientEntry());
+  EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL());
+
+  // Ensure the URLs are correct.
+  EXPECT_EQ(controller.GetEntryCount(), 5);
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
+  EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
+  EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
+  EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref);
+  EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
+}
+
+// Test that Reload initiates a new navigation to a transient entry's URL.
+TEST_F(NavigationControllerTest, ReloadTransient) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url0("http://foo/0");
+  const GURL url1("http://foo/1");
+  const GURL transient_url("http://foo/transient");
+
+  // Load |url0|, and start a pending navigation to |url1|.
+  controller.LoadURL(
+      url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  test_rvh()->SendNavigate(0, url0);
+  controller.LoadURL(
+      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  // A transient entry is added, interrupting the navigation.
+  NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
+  transient_entry->SetURL(transient_url);
+  controller.SetTransientEntry(transient_entry);
+  EXPECT_TRUE(controller.GetTransientEntry());
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+
+  // The page is reloaded, which should remove the pending entry for |url1| and
+  // the transient entry for |transient_url|, and start a navigation to
+  // |transient_url|.
+  controller.Reload(true);
+  EXPECT_FALSE(controller.GetTransientEntry());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
+  ASSERT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
+
+  // Load of |transient_url| completes.
+  test_rvh()->SendNavigate(1, transient_url);
+  ASSERT_EQ(controller.GetEntryCount(), 2);
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
+  EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
+}
+
+// Ensure that renderer initiated pending entries get replaced, so that we
+// don't show a stale virtual URL when a navigation commits.
+// See http://crbug.com/266922.
+TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  const GURL url1("nonexistent:12121");
+  const GURL url1_fixed("http://nonexistent:12121/");
+  const GURL url2("http://foo");
+
+  // We create pending entries for renderer-initiated navigations so that we
+  // can show them in new tabs when it is safe.
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, url1);
+
+  // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
+  // the virtual URL to differ from the URL.
+  controller.GetPendingEntry()->SetURL(url1_fixed);
+  controller.GetPendingEntry()->SetVirtualURL(url1);
+
+  EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL());
+  EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL());
+  EXPECT_TRUE(
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+          is_renderer_initiated());
+
+  // If the user clicks another link, we should replace the pending entry.
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, url2);
+  EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
+  EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
+
+  // Once it commits, the URL and virtual URL should reflect the actual page.
+  test_rvh()->SendNavigate(0, url2);
+  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
+  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
+
+  // We should not replace the pending entry for an error URL.
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, url1);
+  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, GURL(kUnreachableWebDataURL));
+  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
+
+  // We should remember if the pending entry will replace the current one.
+  // http://crbug.com/308444.
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, url1);
+  NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+      set_should_replace_entry(true);
+  contents()->DidStartProvisionalLoadForFrame(
+      test_rvh(), 1, -1, true, url2);
+  EXPECT_TRUE(
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+          should_replace_entry());
+  test_rvh()->SendNavigate(0, url2);
+  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
+}
+
+// Tests that the URLs for renderer-initiated navigations are not displayed to
+// the user until the navigation commits, to prevent URL spoof attacks.
+// See http://crbug.com/99016.
+TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url0("http://foo/0");
+  const GURL url1("http://foo/1");
+
+  // For typed navigations (browser-initiated), both pending and visible entries
+  // should update before commit.
+  controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
+  EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
+  test_rvh()->SendNavigate(0, url0);
+
+  // For link clicks (renderer-initiated navigations), the pending entry should
+  // update before commit but the visible should not.
+  NavigationController::LoadURLParams load_url_params(url1);
+  load_url_params.is_renderer_initiated = true;
+  controller.LoadURLWithParams(load_url_params);
+  EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
+  EXPECT_TRUE(
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+          is_renderer_initiated());
+
+  // After commit, both visible should be updated, there should be no pending
+  // entry, and we should no longer treat the entry as renderer-initiated.
+  test_rvh()->SendNavigate(1, url1);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_FALSE(
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetLastCommittedEntry())->is_renderer_initiated());
+
+  notifications.Reset();
+}
+
+// Tests that the URLs for renderer-initiated navigations in new tabs are
+// displayed to the user before commit, as long as the initial about:blank
+// page has not been modified.  If so, we must revert to showing about:blank.
+// See http://crbug.com/9682.
+TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url("http://foo");
+
+  // For renderer-initiated navigations in new tabs (with no committed entries),
+  // we show the pending entry's URL as long as the about:blank page is not
+  // modified.
+  NavigationController::LoadURLParams load_url_params(url);
+  load_url_params.transition_type = PAGE_TRANSITION_LINK;
+  load_url_params.is_renderer_initiated = true;
+  controller.LoadURLWithParams(load_url_params);
+  EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
+  EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
+  EXPECT_TRUE(
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+          is_renderer_initiated());
+  EXPECT_TRUE(controller.IsInitialNavigation());
+  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
+
+  // There should be no title yet.
+  EXPECT_TRUE(contents()->GetTitle().empty());
+
+  // If something else modifies the contents of the about:blank page, then
+  // we must revert to showing about:blank to avoid a URL spoof.
+  test_rvh()->OnMessageReceived(
+        ViewHostMsg_DidAccessInitialDocument(0));
+  EXPECT_TRUE(test_rvh()->has_accessed_initial_document());
+  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
+
+  notifications.Reset();
+}
+
+TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  const GURL url1("http://foo/eh");
+  const GURL url2("http://foo/bee");
+
+  // For renderer-initiated navigations in new tabs (with no committed entries),
+  // we show the pending entry's URL as long as the about:blank page is not
+  // modified.
+  NavigationController::LoadURLParams load_url_params(url1);
+  load_url_params.transition_type = PAGE_TRANSITION_LINK;
+  load_url_params.is_renderer_initiated = true;
+  controller.LoadURLWithParams(load_url_params);
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+  EXPECT_TRUE(
+      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
+          is_renderer_initiated());
+  EXPECT_TRUE(controller.IsInitialNavigation());
+  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
+
+  // Simulate a commit and then starting a new pending navigation.
+  test_rvh()->SendNavigate(0, url1);
+  NavigationController::LoadURLParams load_url2_params(url2);
+  load_url2_params.transition_type = PAGE_TRANSITION_LINK;
+  load_url2_params.is_renderer_initiated = true;
+  controller.LoadURLWithParams(load_url2_params);
+
+  // We should not consider this an initial navigation, and thus should
+  // not show the pending URL.
+  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
+  EXPECT_FALSE(controller.IsInitialNavigation());
+  EXPECT_TRUE(controller.GetVisibleEntry());
+  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
+
+  notifications.Reset();
+}
+
+// Tests that IsInPageNavigation returns appropriate results.  Prevents
+// regression for bug 1126349.
+TEST_F(NavigationControllerTest, IsInPageNavigation) {
+  NavigationControllerImpl& controller = controller_impl();
+  // Navigate to URL with no refs.
+  const GURL url("http://www.google.com/home.html");
+  test_rvh()->SendNavigate(0, url);
+
+  // Reloading the page is not an in-page navigation.
+  EXPECT_FALSE(controller.IsURLInPageNavigation(url));
+  const GURL other_url("http://www.google.com/add.html");
+  EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
+  const GURL url_with_ref("http://www.google.com/home.html#my_ref");
+  EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref));
+
+  // Navigate to URL with refs.
+  test_rvh()->SendNavigate(1, url_with_ref);
+
+  // Reloading the page is not an in-page navigation.
+  EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref));
+  EXPECT_FALSE(controller.IsURLInPageNavigation(url));
+  EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
+  const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
+  EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref));
+
+  // Going to the same url again will be considered in-page
+  // if the renderer says it is even if the navigation type isn't IN_PAGE.
+  EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
+      NAVIGATION_TYPE_UNKNOWN));
+
+  // Going back to the non ref url will be considered in-page if the navigation
+  // type is IN_PAGE.
+  EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
+      NAVIGATION_TYPE_IN_PAGE));
+}
+
+// Some pages can have subframes with the same base URL (minus the reference) as
+// the main page. Even though this is hard, it can happen, and we don't want
+// these subframe navigations to affect the toplevel document. They should
+// instead be ignored.  http://crbug.com/5585
+TEST_F(NavigationControllerTest, SameSubframe) {
+  NavigationControllerImpl& controller = controller_impl();
+  // Navigate the main frame.
+  const GURL url("http://www.google.com/");
+  test_rvh()->SendNavigate(0, url);
+
+  // We should be at the first navigation entry.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+
+  // Navigate a subframe that would normally count as in-page.
+  const GURL subframe("http://www.google.com/#");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 0;
+  params.url = subframe;
+  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(subframe);
+  LoadCommittedDetails details;
+  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
+
+  // Nothing should have changed.
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+}
+
+// Make sure that on cloning a WebContentsImpl and going back needs_reload is
+// false.
+TEST_F(NavigationControllerTest, CloneAndGoBack) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const string16 title(ASCIIToUTF16("Title"));
+
+  NavigateAndCommit(url1);
+  controller.GetVisibleEntry()->SetTitle(title);
+  NavigateAndCommit(url2);
+
+  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
+
+  ASSERT_EQ(2, clone->GetController().GetEntryCount());
+  EXPECT_TRUE(clone->GetController().NeedsReload());
+  clone->GetController().GoBack();
+  // Navigating back should have triggered needs_reload_ to go false.
+  EXPECT_FALSE(clone->GetController().NeedsReload());
+
+  // Ensure that the pending URL and its title are visible.
+  EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL());
+  EXPECT_EQ(title, clone->GetTitle());
+}
+
+// Make sure that reloading a cloned tab doesn't change its pending entry index.
+// See http://crbug.com/234491.
+TEST_F(NavigationControllerTest, CloneAndReload) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const string16 title(ASCIIToUTF16("Title"));
+
+  NavigateAndCommit(url1);
+  controller.GetVisibleEntry()->SetTitle(title);
+  NavigateAndCommit(url2);
+
+  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
+  clone->GetController().LoadIfNecessary();
+
+  ASSERT_EQ(2, clone->GetController().GetEntryCount());
+  EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
+
+  clone->GetController().Reload(true);
+  EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
+}
+
+// Make sure that cloning a WebContentsImpl doesn't copy interstitials.
+TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  // Add an interstitial entry.  Should be deleted with controller.
+  NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
+  interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
+  controller.SetTransientEntry(interstitial_entry);
+
+  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
+
+  ASSERT_EQ(2, clone->GetController().GetEntryCount());
+}
+
+// Test requesting and triggering a lazy reload.
+TEST_F(NavigationControllerTest, LazyReload) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url("http://foo");
+  NavigateAndCommit(url);
+  ASSERT_FALSE(controller.NeedsReload());
+
+  // Request a reload to happen when the controller becomes active (e.g. after
+  // the renderer gets killed in background on Android).
+  controller.SetNeedsReload();
+  ASSERT_TRUE(controller.NeedsReload());
+
+  // Set the controller as active, triggering the requested reload.
+  controller.SetActive(true);
+  ASSERT_FALSE(controller.NeedsReload());
+}
+
+// Tests a subframe navigation while a toplevel navigation is pending.
+// http://crbug.com/43967
+TEST_F(NavigationControllerTest, SubframeWhilePending) {
+  NavigationControllerImpl& controller = controller_impl();
+  // Load the first page.
+  const GURL url1("http://foo/");
+  NavigateAndCommit(url1);
+
+  // Now start a pending load to a totally different page, but don't commit it.
+  const GURL url2("http://bar/");
+  controller.LoadURL(
+      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+
+  // Send a subframe update from the first page, as if one had just
+  // automatically loaded. Auto subframes don't increment the page ID.
+  const GURL url1_sub("http://foo/subframe");
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = controller.GetLastCommittedEntry()->GetPageID();
+  params.url = url1_sub;
+  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(url1_sub);
+  LoadCommittedDetails details;
+
+  // This should return false meaning that nothing was actually updated.
+  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
+
+  // The notification should have updated the last committed one, and not
+  // the pending load.
+  EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
+
+  // The active entry should be unchanged by the subframe load.
+  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
+}
+
+// Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
+TEST_F(NavigationControllerTest, CopyStateFrom) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_controller.CopyStateFrom(controller);
+
+  // other_controller should now contain 2 urls.
+  ASSERT_EQ(2, other_controller.GetEntryCount());
+  // We should be looking at the first one.
+  ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
+  // This is a different site than url1, so the IDs start again at 0.
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+
+  // Ensure the SessionStorageNamespaceMaps are the same size and have
+  // the same partitons loaded.
+  //
+  // TODO(ajwong): We should load a url from a different partition earlier
+  // to make sure this map has more than one entry.
+  const SessionStorageNamespaceMap& session_storage_namespace_map =
+      controller.GetSessionStorageNamespaceMap();
+  const SessionStorageNamespaceMap& other_session_storage_namespace_map =
+      other_controller.GetSessionStorageNamespaceMap();
+  EXPECT_EQ(session_storage_namespace_map.size(),
+            other_session_storage_namespace_map.size());
+  for (SessionStorageNamespaceMap::const_iterator it =
+           session_storage_namespace_map.begin();
+       it != session_storage_namespace_map.end();
+       ++it) {
+    SessionStorageNamespaceMap::const_iterator other =
+        other_session_storage_namespace_map.find(it->first);
+    EXPECT_TRUE(other != other_session_storage_namespace_map.end());
+  }
+}
+
+// Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  // First two entries should have the same SiteInstance.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
+  SiteInstance* instance2 =
+      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
+  EXPECT_EQ(instance1, instance2);
+  EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
+  EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain the 3 urls: url1, url2 and url3.
+
+  ASSERT_EQ(3, other_controller.GetEntryCount());
+
+  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
+
+  // A new SiteInstance should be used for the new tab.
+  SiteInstance* instance3 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+  EXPECT_NE(instance3, instance1);
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
+}
+
+// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
+// the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain: url1, url3
+
+  ASSERT_EQ(2, other_controller.GetEntryCount());
+  ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
+// the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+  const GURL url4("http://foo4");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_contents->NavigateAndCommit(url4);
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain: url1, url2, url4
+
+  ASSERT_EQ(3, other_controller.GetEntryCount());
+  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
+// not the last entry selected in the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+  const GURL url4("http://foo4");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_contents->NavigateAndCommit(url4);
+  other_controller.GoBack();
+  other_contents->CommitPendingNavigation();
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain: url1, url2, url3
+
+  ASSERT_EQ(3, other_controller.GetEntryCount());
+  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
+// a pending entry in the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+  const GURL url4("http://foo4");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_controller.LoadURL(
+      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain url1, url3, and a pending entry
+  // for url4.
+
+  ASSERT_EQ(2, other_controller.GetEntryCount());
+  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
+
+  // And there should be a pending entry for url4.
+  ASSERT_TRUE(other_controller.GetPendingEntry());
+  EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
+// client redirect entry (with the same page ID) in the target.  This used to
+// crash because the last committed entry would be pruned but max_page_id
+// remembered the page ID (http://crbug.com/234809).
+TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2a("http://foo2/a");
+  const GURL url2b("http://foo2/b");
+
+  NavigateAndCommit(url1);
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url2a);
+  // Simulate a client redirect, which has the same page ID as entry 2a.
+  other_controller.LoadURL(
+      url2b, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  other_controller.GetPendingEntry()->SetPageID(
+      other_controller.GetLastCommittedEntry()->GetPageID());
+
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain url1, url2a, and a pending entry
+  // for url2b.
+
+  ASSERT_EQ(2, other_controller.GetEntryCount());
+  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL());
+
+  // And there should be a pending entry for url4.
+  ASSERT_TRUE(other_controller.GetPendingEntry());
+  EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
+
+  // Let the pending entry commit.
+  other_contents->CommitPendingNavigation();
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
+// source, and 1 entry in the target. The back pending entry should be ignored.
+TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  controller.GoBack();
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url3);
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // other_controller should now contain: url1, url2, url3
+
+  ASSERT_EQ(3, other_controller.GetEntryCount());
+  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
+
+  // The max page ID map should be copied over and updated with the max page ID
+  // from the current tab.
+  SiteInstance* instance1 =
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
+  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
+}
+
+// Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
+// when the max entry count is 3.  We should prune one entry.
+TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
+  NavigationControllerImpl& controller = controller_impl();
+  size_t original_count = NavigationControllerImpl::max_entry_count();
+  const int kMaxEntryCount = 3;
+
+  NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
+
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+  const GURL url4("http://foo/4");
+
+  // Create a PrunedListener to observe prune notifications.
+  PrunedListener listener(&controller);
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  NavigateAndCommit(url3);
+
+  scoped_ptr<TestWebContents> other_contents(
+      static_cast<TestWebContents*>(CreateTestWebContents()));
+  NavigationControllerImpl& other_controller = other_contents->GetController();
+  other_contents->NavigateAndCommit(url4);
+  other_contents->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
+      other_controller.GetEntryAtIndex(0)->GetPageID());
+  other_controller.CopyStateFromAndPrune(&controller);
+
+  // We should have received a pruned notification.
+  EXPECT_EQ(1, listener.notification_count_);
+  EXPECT_TRUE(listener.details_.from_front);
+  EXPECT_EQ(1, listener.details_.count);
+
+  // other_controller should now contain only 3 urls: url2, url3 and url4.
+
+  ASSERT_EQ(3, other_controller.GetEntryCount());
+
+  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
+  EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
+  EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
+  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
+
+  NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
+}
+
+// Tests that navigations initiated from the page (with the history object)
+// work as expected without navigation entries.
+TEST_F(NavigationControllerTest, HistoryNavigate) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  NavigateAndCommit(url3);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  // Simulate the page calling history.back(), it should not create a pending
+  // entry.
+  contents()->OnGoToEntryAtOffset(-1);
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  // The actual cross-navigation is suspended until the current RVH tells us
+  // it unloaded, simulate that.
+  contents()->ProceedWithCrossSiteNavigation();
+  // Also make sure we told the page to navigate.
+  const IPC::Message* message =
+      process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+  ASSERT_TRUE(message != NULL);
+  Tuple1<ViewMsg_Navigate_Params> nav_params;
+  ViewMsg_Navigate::Read(message, &nav_params);
+  EXPECT_EQ(url1, nav_params.a.url);
+  process()->sink().ClearMessages();
+
+  // Now test history.forward()
+  contents()->OnGoToEntryAtOffset(1);
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  // The actual cross-navigation is suspended until the current RVH tells us
+  // it unloaded, simulate that.
+  contents()->ProceedWithCrossSiteNavigation();
+  message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+  ASSERT_TRUE(message != NULL);
+  ViewMsg_Navigate::Read(message, &nav_params);
+  EXPECT_EQ(url3, nav_params.a.url);
+  process()->sink().ClearMessages();
+
+  // Make sure an extravagant history.go() doesn't break.
+  contents()->OnGoToEntryAtOffset(120);  // Out of bounds.
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+  EXPECT_TRUE(message == NULL);
+}
+
+// Test call to PruneAllButVisible for the only entry.
+TEST_F(NavigationControllerTest, PruneAllButVisibleForSingle) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo1");
+  NavigateAndCommit(url1);
+
+  contents()->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
+      controller.GetEntryAtIndex(0)->GetPageID());
+
+  controller.PruneAllButVisible();
+
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
+}
+
+// Test call to PruneAllButVisible for first entry.
+TEST_F(NavigationControllerTest, PruneAllButVisibleForFirst) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  NavigateAndCommit(url3);
+  controller.GoBack();
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  contents()->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
+      controller.GetEntryAtIndex(0)->GetPageID());
+
+  controller.PruneAllButVisible();
+
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
+}
+
+// Test call to PruneAllButVisible for intermediate entry.
+TEST_F(NavigationControllerTest, PruneAllButVisibleForIntermediate) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  NavigateAndCommit(url3);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  contents()->ExpectSetHistoryLengthAndPrune(
+      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
+      controller.GetEntryAtIndex(1)->GetPageID());
+
+  controller.PruneAllButVisible();
+
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
+}
+
+// Test call to PruneAllButVisible for a pending entry that is not yet in the
+// list of entries.
+TEST_F(NavigationControllerTest, PruneAllButVisibleForPendingNotInList) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url1("http://foo/1");
+  const GURL url2("http://foo/2");
+  const GURL url3("http://foo/3");
+
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  // Create a pending entry that is not in the entry list.
+  controller.LoadURL(
+      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(2, controller.GetEntryCount());
+
+  contents()->ExpectSetHistoryLengthAndPrune(
+      NULL, 0, controller.GetPendingEntry()->GetPageID());
+  controller.PruneAllButVisible();
+
+  // We should only have the last committed and pending entries at this point,
+  // and the pending entry should still not be in the entry list.
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_TRUE(controller.GetPendingEntry());
+  EXPECT_EQ(1, controller.GetEntryCount());
+
+  // Try to commit the pending entry.
+  test_rvh()->SendNavigate(2, url3);
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.GetPendingEntry());
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL());
+}
+
+// Test to ensure that when we do a history navigation back to the current
+// committed page (e.g., going forward to a slow-loading page, then pressing
+// the back button), we just stop the navigation to prevent the throbber from
+// running continuously. Otherwise, the RenderViewHost forces the throbber to
+// start, but WebKit essentially ignores the navigation and never sends a
+// message to stop the throbber.
+TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
+  NavigationControllerImpl& controller = controller_impl();
+  const GURL url0("http://foo/0");
+  const GURL url1("http://foo/1");
+
+  NavigateAndCommit(url0);
+  NavigateAndCommit(url1);
+
+  // Go back to the original page, then forward to the slow page, then back
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+
+  controller.GoForward();
+  EXPECT_EQ(1, controller.GetPendingEntryIndex());
+
+  controller.GoBack();
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+}
+
+TEST_F(NavigationControllerTest, IsInitialNavigation) {
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  // Initial state.
+  EXPECT_TRUE(controller.IsInitialNavigation());
+
+  // After commit, it stays false.
+  const GURL url1("http://foo1");
+  test_rvh()->SendNavigate(0, url1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  EXPECT_FALSE(controller.IsInitialNavigation());
+
+  // After starting a new navigation, it stays false.
+  const GURL url2("http://foo2");
+  controller.LoadURL(
+      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+}
+
+// Check that the favicon is not reused across a client redirect.
+// (crbug.com/28515)
+TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
+  const GURL kPageWithFavicon("http://withfavicon.html");
+  const GURL kPageWithoutFavicon("http://withoutfavicon.html");
+  const GURL kIconURL("http://withfavicon.ico");
+  const gfx::Image kDefaultFavicon = FaviconStatus().image;
+
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  test_rvh()->SendNavigate(0, kPageWithFavicon);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  NavigationEntry* entry = controller.GetLastCommittedEntry();
+  EXPECT_TRUE(entry);
+  EXPECT_EQ(kPageWithFavicon, entry->GetURL());
+
+  // Simulate Chromium having set the favicon for |kPageWithFavicon|.
+  content::FaviconStatus& favicon_status = entry->GetFavicon();
+  favicon_status.image = CreateImage(SK_ColorWHITE);
+  favicon_status.url = kIconURL;
+  favicon_status.valid = true;
+  EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
+
+  test_rvh()->SendNavigateWithTransition(
+      0,  // same page ID.
+      kPageWithoutFavicon,
+      PAGE_TRANSITION_CLIENT_REDIRECT);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_TRUE(entry);
+  EXPECT_EQ(kPageWithoutFavicon, entry->GetURL());
+
+  EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
+}
+
+// Check that the favicon is not cleared for NavigationEntries which were
+// previously navigated to.
+TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
+  const GURL kUrl1("http://www.a.com/1");
+  const GURL kUrl2("http://www.a.com/2");
+  const GURL kIconURL("http://www.a.com/1/favicon.ico");
+
+  NavigationControllerImpl& controller = controller_impl();
+  TestNotificationTracker notifications;
+  RegisterForAllNavNotifications(&notifications, &controller);
+
+  test_rvh()->SendNavigate(0, kUrl1);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Simulate Chromium having set the favicon for |kUrl1|.
+  gfx::Image favicon_image = CreateImage(SK_ColorWHITE);
+  content::NavigationEntry* entry = controller.GetLastCommittedEntry();
+  EXPECT_TRUE(entry);
+  content::FaviconStatus& favicon_status = entry->GetFavicon();
+  favicon_status.image = favicon_image;
+  favicon_status.url = kIconURL;
+  favicon_status.valid = true;
+
+  // Navigate to another page and go back to the original page.
+  test_rvh()->SendNavigate(1, kUrl2);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+  test_rvh()->SendNavigateWithTransition(
+      0,
+      kUrl1,
+      PAGE_TRANSITION_FORWARD_BACK);
+  EXPECT_EQ(1U, navigation_entry_committed_counter_);
+  navigation_entry_committed_counter_ = 0;
+
+  // Verify that the favicon for the page at |kUrl1| was not cleared.
+  entry = controller.GetEntryAtIndex(0);
+  EXPECT_TRUE(entry);
+  EXPECT_EQ(kUrl1, entry->GetURL());
+  EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
+}
+
+// The test crashes on android: http://crbug.com/170449
+#if defined(OS_ANDROID)
+#define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
+#else
+#define MAYBE_PurgeScreenshot PurgeScreenshot
+#endif
+// Tests that screenshot are purged correctly.
+TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
+  NavigationControllerImpl& controller = controller_impl();
+
+  NavigationEntryImpl* entry;
+
+  // Navigate enough times to make sure that some screenshots are purged.
+  for (int i = 0; i < 12; ++i) {
+    const GURL url(base::StringPrintf("http://foo%d/", i));
+    NavigateAndCommit(url);
+    EXPECT_EQ(i, controller.GetCurrentEntryIndex());
+  }
+
+  MockScreenshotManager* screenshot_manager =
+      new MockScreenshotManager(&controller);
+  controller.SetScreenshotManager(screenshot_manager);
+  for (int i = 0; i < controller.GetEntryCount(); ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    screenshot_manager->TakeScreenshotFor(entry);
+    EXPECT_TRUE(entry->screenshot().get());
+  }
+
+  NavigateAndCommit(GURL("https://foo/"));
+  EXPECT_EQ(13, controller.GetEntryCount());
+  entry = NavigationEntryImpl::FromNavigationEntry(
+      controller.GetEntryAtIndex(11));
+  screenshot_manager->TakeScreenshotFor(entry);
+
+  for (int i = 0; i < 2; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
+                                            << " not purged";
+  }
+
+  for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
+  }
+
+  // Navigate to index 5 and then try to assign screenshot to all entries.
+  controller.GoToIndex(5);
+  contents()->CommitPendingNavigation();
+  EXPECT_EQ(5, controller.GetCurrentEntryIndex());
+  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    screenshot_manager->TakeScreenshotFor(entry);
+  }
+
+  for (int i = 10; i <= 12; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
+                                            << " not purged";
+    screenshot_manager->TakeScreenshotFor(entry);
+  }
+
+  // Navigate to index 7 and assign screenshot to all entries.
+  controller.GoToIndex(7);
+  contents()->CommitPendingNavigation();
+  EXPECT_EQ(7, controller.GetCurrentEntryIndex());
+  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    screenshot_manager->TakeScreenshotFor(entry);
+  }
+
+  for (int i = 0; i < 2; ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
+                                            << " not purged";
+  }
+
+  // Clear all screenshots.
+  EXPECT_EQ(13, controller.GetEntryCount());
+  EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
+  controller.ClearAllScreenshots();
+  EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
+  for (int i = 0; i < controller.GetEntryCount(); ++i) {
+    entry = NavigationEntryImpl::FromNavigationEntry(
+        controller.GetEntryAtIndex(i));
+    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
+                                            << " not cleared";
+  }
+}
+
+// Test that the navigation controller clears its session history when a
+// navigation commits with the clear history list flag set.
+TEST_F(NavigationControllerTest, ClearHistoryList) {
+  const GURL url1("http://foo1");
+  const GURL url2("http://foo2");
+  const GURL url3("http://foo3");
+  const GURL url4("http://foo4");
+
+  NavigationControllerImpl& controller = controller_impl();
+
+  // Create a session history with three entries, second entry is active.
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+  NavigateAndCommit(url3);
+  controller.GoBack();
+  contents()->CommitPendingNavigation();
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+
+  // Create a new pending navigation, and indicate that the session history
+  // should be cleared.
+  NavigationController::LoadURLParams params(url4);
+  params.should_clear_history_list = true;
+  controller.LoadURLWithParams(params);
+
+  // Verify that the pending entry correctly indicates that the session history
+  // should be cleared.
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(
+          controller.GetPendingEntry());
+  ASSERT_TRUE(entry);
+  EXPECT_TRUE(entry->should_clear_history_list());
+
+  // Assume that the RV correctly cleared its history and commit the navigation.
+  static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())->
+      set_simulate_history_list_was_cleared(true);
+  contents()->CommitPendingNavigation();
+
+  // Verify that the NavigationController's session history was correctly
+  // cleared.
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
new file mode 100644
index 0000000..58dbaf4
--- /dev/null
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -0,0 +1,342 @@
+// Copyright 2013 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/navigation_entry_impl.h"
+
+#include "base/metrics/histogram.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/url_constants.h"
+#include "net/base/net_util.h"
+#include "ui/gfx/text_elider.h"
+
+// Use this to get a new unique ID for a NavigationEntry during construction.
+// The returned ID is guaranteed to be nonzero (which is the "no ID" indicator).
+static int GetUniqueIDInConstructor() {
+  static int unique_id_counter = 0;
+  return ++unique_id_counter;
+}
+
+namespace content {
+
+int NavigationEntryImpl::kInvalidBindings = -1;
+
+NavigationEntry* NavigationEntry::Create() {
+  return new NavigationEntryImpl();
+}
+
+NavigationEntry* NavigationEntry::Create(const NavigationEntry& copy) {
+  return new NavigationEntryImpl(static_cast<const NavigationEntryImpl&>(copy));
+}
+
+NavigationEntryImpl* NavigationEntryImpl::FromNavigationEntry(
+    NavigationEntry* entry) {
+  return static_cast<NavigationEntryImpl*>(entry);
+}
+
+NavigationEntryImpl::NavigationEntryImpl()
+    : unique_id_(GetUniqueIDInConstructor()),
+      site_instance_(NULL),
+      bindings_(kInvalidBindings),
+      page_type_(PAGE_TYPE_NORMAL),
+      update_virtual_url_with_url_(false),
+      page_id_(-1),
+      transition_type_(PAGE_TRANSITION_LINK),
+      has_post_data_(false),
+      post_id_(-1),
+      restore_type_(RESTORE_NONE),
+      is_overriding_user_agent_(false),
+      http_status_code_(0),
+      is_renderer_initiated_(false),
+      should_replace_entry_(false),
+      should_clear_history_list_(false),
+      can_load_local_resources_(false) {
+}
+
+NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
+                                         int page_id,
+                                         const GURL& url,
+                                         const Referrer& referrer,
+                                         const string16& title,
+                                         PageTransition transition_type,
+                                         bool is_renderer_initiated)
+    : unique_id_(GetUniqueIDInConstructor()),
+      site_instance_(instance),
+      bindings_(kInvalidBindings),
+      page_type_(PAGE_TYPE_NORMAL),
+      url_(url),
+      referrer_(referrer),
+      update_virtual_url_with_url_(false),
+      title_(title),
+      page_id_(page_id),
+      transition_type_(transition_type),
+      has_post_data_(false),
+      post_id_(-1),
+      restore_type_(RESTORE_NONE),
+      is_overriding_user_agent_(false),
+      http_status_code_(0),
+      is_renderer_initiated_(is_renderer_initiated),
+      should_replace_entry_(false),
+      should_clear_history_list_(false),
+      can_load_local_resources_(false) {
+}
+
+NavigationEntryImpl::~NavigationEntryImpl() {
+}
+
+int NavigationEntryImpl::GetUniqueID() const {
+  return unique_id_;
+}
+
+PageType NavigationEntryImpl::GetPageType() const {
+  return page_type_;
+}
+
+void NavigationEntryImpl::SetURL(const GURL& url) {
+  url_ = url;
+  cached_display_title_.clear();
+}
+
+const GURL& NavigationEntryImpl::GetURL() const {
+  return url_;
+}
+
+void NavigationEntryImpl::SetBaseURLForDataURL(const GURL& url) {
+  base_url_for_data_url_ = url;
+}
+
+const GURL& NavigationEntryImpl::GetBaseURLForDataURL() const {
+  return base_url_for_data_url_;
+}
+
+void NavigationEntryImpl::SetReferrer(const Referrer& referrer) {
+  referrer_ = referrer;
+}
+
+const Referrer& NavigationEntryImpl::GetReferrer() const {
+  return referrer_;
+}
+
+void NavigationEntryImpl::SetVirtualURL(const GURL& url) {
+  virtual_url_ = (url == url_) ? GURL() : url;
+  cached_display_title_.clear();
+}
+
+const GURL& NavigationEntryImpl::GetVirtualURL() const {
+  return virtual_url_.is_empty() ? url_ : virtual_url_;
+}
+
+void NavigationEntryImpl::SetTitle(const string16& title) {
+  title_ = title;
+  cached_display_title_.clear();
+}
+
+const string16& NavigationEntryImpl::GetTitle() const {
+  return title_;
+}
+
+void NavigationEntryImpl::SetPageState(const PageState& state) {
+  page_state_ = state;
+}
+
+const PageState& NavigationEntryImpl::GetPageState() const {
+  return page_state_;
+}
+
+void NavigationEntryImpl::SetPageID(int page_id) {
+  page_id_ = page_id;
+}
+
+int32 NavigationEntryImpl::GetPageID() const {
+  return page_id_;
+}
+
+void NavigationEntryImpl::set_site_instance(SiteInstanceImpl* site_instance) {
+  site_instance_ = site_instance;
+}
+
+void NavigationEntryImpl::SetBindings(int bindings) {
+  // Ensure this is set to a valid value, and that it stays the same once set.
+  CHECK_NE(bindings, kInvalidBindings);
+  CHECK(bindings_ == kInvalidBindings || bindings_ == bindings);
+  bindings_ = bindings;
+}
+
+const string16& NavigationEntryImpl::GetTitleForDisplay(
+    const std::string& languages) const {
+  // Most pages have real titles. Don't even bother caching anything if this is
+  // the case.
+  if (!title_.empty())
+    return title_;
+
+  // More complicated cases will use the URLs as the title. This result we will
+  // cache since it's more complicated to compute.
+  if (!cached_display_title_.empty())
+    return cached_display_title_;
+
+  // Use the virtual URL first if any, and fall back on using the real URL.
+  string16 title;
+  if (!virtual_url_.is_empty()) {
+    title = net::FormatUrl(virtual_url_, languages);
+  } else if (!url_.is_empty()) {
+    title = net::FormatUrl(url_, languages);
+  }
+
+  // For file:// URLs use the filename as the title, not the full path.
+  if (url_.SchemeIsFile()) {
+    string16::size_type slashpos = title.rfind('/');
+    if (slashpos != string16::npos)
+      title = title.substr(slashpos + 1);
+  }
+
+  gfx::ElideString(title, kMaxTitleChars, &cached_display_title_);
+  return cached_display_title_;
+}
+
+bool NavigationEntryImpl::IsViewSourceMode() const {
+  return virtual_url_.SchemeIs(kViewSourceScheme);
+}
+
+void NavigationEntryImpl::SetTransitionType(
+    PageTransition transition_type) {
+  transition_type_ = transition_type;
+}
+
+PageTransition NavigationEntryImpl::GetTransitionType() const {
+  return transition_type_;
+}
+
+const GURL& NavigationEntryImpl::GetUserTypedURL() const {
+  return user_typed_url_;
+}
+
+void NavigationEntryImpl::SetHasPostData(bool has_post_data) {
+  has_post_data_ = has_post_data;
+}
+
+bool NavigationEntryImpl::GetHasPostData() const {
+  return has_post_data_;
+}
+
+void NavigationEntryImpl::SetPostID(int64 post_id) {
+  post_id_ = post_id;
+}
+
+int64 NavigationEntryImpl::GetPostID() const {
+  return post_id_;
+}
+
+void NavigationEntryImpl::SetBrowserInitiatedPostData(
+    const base::RefCountedMemory* data) {
+  browser_initiated_post_data_ = data;
+}
+
+const base::RefCountedMemory*
+NavigationEntryImpl::GetBrowserInitiatedPostData() const {
+  return browser_initiated_post_data_.get();
+}
+
+
+const FaviconStatus& NavigationEntryImpl::GetFavicon() const {
+  return favicon_;
+}
+
+FaviconStatus& NavigationEntryImpl::GetFavicon() {
+  return favicon_;
+}
+
+const SSLStatus& NavigationEntryImpl::GetSSL() const {
+  return ssl_;
+}
+
+SSLStatus& NavigationEntryImpl::GetSSL() {
+  return ssl_;
+}
+
+void NavigationEntryImpl::SetOriginalRequestURL(const GURL& original_url) {
+  original_request_url_ = original_url;
+}
+
+const GURL& NavigationEntryImpl::GetOriginalRequestURL() const {
+  return original_request_url_;
+}
+
+void NavigationEntryImpl::SetIsOverridingUserAgent(bool override) {
+  is_overriding_user_agent_ = override;
+}
+
+bool NavigationEntryImpl::GetIsOverridingUserAgent() const {
+  return is_overriding_user_agent_;
+}
+
+void NavigationEntryImpl::SetTimestamp(base::Time timestamp) {
+  timestamp_ = timestamp;
+}
+
+base::Time NavigationEntryImpl::GetTimestamp() const {
+  return timestamp_;
+}
+
+void NavigationEntryImpl::SetHttpStatusCode(int http_status_code) {
+  http_status_code_ = http_status_code;
+}
+
+int NavigationEntryImpl::GetHttpStatusCode() const {
+  return http_status_code_;
+}
+
+void NavigationEntryImpl::SetCanLoadLocalResources(bool allow) {
+  can_load_local_resources_ = allow;
+}
+
+bool NavigationEntryImpl::GetCanLoadLocalResources() const {
+  return can_load_local_resources_;
+}
+
+void NavigationEntryImpl::SetFrameToNavigate(const std::string& frame_name) {
+  frame_to_navigate_ = frame_name;
+}
+
+const std::string& NavigationEntryImpl::GetFrameToNavigate() const {
+  return frame_to_navigate_;
+}
+
+void NavigationEntryImpl::SetExtraData(const std::string& key,
+                                       const string16& data) {
+  extra_data_[key] = data;
+}
+
+bool NavigationEntryImpl::GetExtraData(const std::string& key,
+                                       string16* data) const {
+  std::map<std::string, string16>::const_iterator iter = extra_data_.find(key);
+  if (iter == extra_data_.end())
+    return false;
+  *data = iter->second;
+  return true;
+}
+
+void NavigationEntryImpl::ClearExtraData(const std::string& key) {
+  extra_data_.erase(key);
+}
+
+void NavigationEntryImpl::ResetForCommit() {
+  // Any state that only matters when a navigation entry is pending should be
+  // cleared here.
+  SetBrowserInitiatedPostData(NULL);
+  set_is_renderer_initiated(false);
+  set_transferred_global_request_id(GlobalRequestID());
+  set_should_replace_entry(false);
+  redirect_chain_.clear();
+  set_should_clear_history_list(false);
+}
+
+void NavigationEntryImpl::SetScreenshotPNGData(
+    scoped_refptr<base::RefCountedBytes> png_data) {
+  screenshot_ = png_data;
+  if (screenshot_.get())
+    UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size());
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
new file mode 100644
index 0000000..1149ae6
--- /dev/null
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -0,0 +1,336 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_IMPL_H_
+#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/common/page_state.h"
+#include "content/public/common/ssl_status.h"
+
+namespace content {
+
+class CONTENT_EXPORT NavigationEntryImpl
+    : public NON_EXPORTED_BASE(NavigationEntry) {
+ public:
+  static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry);
+
+  // The value of bindings() before it is set during commit.
+  static int kInvalidBindings;
+
+  NavigationEntryImpl();
+  NavigationEntryImpl(SiteInstanceImpl* instance,
+                      int page_id,
+                      const GURL& url,
+                      const Referrer& referrer,
+                      const string16& title,
+                      PageTransition transition_type,
+                      bool is_renderer_initiated);
+  virtual ~NavigationEntryImpl();
+
+  // NavigationEntry implementation:
+  virtual int GetUniqueID() const OVERRIDE;
+  virtual PageType GetPageType() const OVERRIDE;
+  virtual void SetURL(const GURL& url) OVERRIDE;
+  virtual const GURL& GetURL() const OVERRIDE;
+  virtual void SetBaseURLForDataURL(const GURL& url) OVERRIDE;
+  virtual const GURL& GetBaseURLForDataURL() const OVERRIDE;
+  virtual void SetReferrer(const Referrer& referrer) OVERRIDE;
+  virtual const Referrer& GetReferrer() const OVERRIDE;
+  virtual void SetVirtualURL(const GURL& url) OVERRIDE;
+  virtual const GURL& GetVirtualURL() const OVERRIDE;
+  virtual void SetTitle(const string16& title) OVERRIDE;
+  virtual const string16& GetTitle() const OVERRIDE;
+  virtual void SetPageState(const PageState& state) OVERRIDE;
+  virtual const PageState& GetPageState() const OVERRIDE;
+  virtual void SetPageID(int page_id) OVERRIDE;
+  virtual int32 GetPageID() const OVERRIDE;
+  virtual const string16& GetTitleForDisplay(
+      const std::string& languages) const OVERRIDE;
+  virtual bool IsViewSourceMode() const OVERRIDE;
+  virtual void SetTransitionType(PageTransition transition_type) OVERRIDE;
+  virtual PageTransition GetTransitionType() const OVERRIDE;
+  virtual const GURL& GetUserTypedURL() const OVERRIDE;
+  virtual void SetHasPostData(bool has_post_data) OVERRIDE;
+  virtual bool GetHasPostData() const OVERRIDE;
+  virtual void SetPostID(int64 post_id) OVERRIDE;
+  virtual int64 GetPostID() const OVERRIDE;
+  virtual void SetBrowserInitiatedPostData(
+      const base::RefCountedMemory* data) OVERRIDE;
+  virtual const base::RefCountedMemory*
+      GetBrowserInitiatedPostData() const OVERRIDE;
+  virtual const FaviconStatus& GetFavicon() const OVERRIDE;
+  virtual FaviconStatus& GetFavicon() OVERRIDE;
+  virtual const SSLStatus& GetSSL() const OVERRIDE;
+  virtual SSLStatus& GetSSL() OVERRIDE;
+  virtual void SetOriginalRequestURL(const GURL& original_url) OVERRIDE;
+  virtual const GURL& GetOriginalRequestURL() const OVERRIDE;
+  virtual void SetIsOverridingUserAgent(bool override) OVERRIDE;
+  virtual bool GetIsOverridingUserAgent() const OVERRIDE;
+  virtual void SetTimestamp(base::Time timestamp) OVERRIDE;
+  virtual base::Time GetTimestamp() const OVERRIDE;
+  virtual void SetCanLoadLocalResources(bool allow) OVERRIDE;
+  virtual bool GetCanLoadLocalResources() const OVERRIDE;
+  virtual void SetFrameToNavigate(const std::string& frame_name) OVERRIDE;
+  virtual const std::string& GetFrameToNavigate() const OVERRIDE;
+  virtual void SetExtraData(const std::string& key,
+                            const string16& data) OVERRIDE;
+  virtual bool GetExtraData(const std::string& key,
+                            string16* data) const OVERRIDE;
+  virtual void ClearExtraData(const std::string& key) OVERRIDE;
+  virtual void SetHttpStatusCode(int http_status_code) OVERRIDE;
+  virtual int GetHttpStatusCode() const OVERRIDE;
+
+  // Once a navigation entry is committed, we should no longer track several
+  // pieces of non-persisted state, as documented on the members below.
+  void ResetForCommit();
+
+  void set_unique_id(int unique_id) {
+    unique_id_ = unique_id;
+  }
+
+  // The SiteInstance tells us how to share sub-processes. This is a reference
+  // counted pointer to a shared site instance.
+  //
+  // Note that the SiteInstance should usually not be changed after it is set,
+  // but this may happen if the NavigationEntry was cloned and needs to use a
+  // different SiteInstance.
+  void set_site_instance(SiteInstanceImpl* site_instance);
+  SiteInstanceImpl* site_instance() const {
+    return site_instance_.get();
+  }
+
+  // Remember the set of bindings granted to this NavigationEntry at the time
+  // of commit, to ensure that we do not grant it additional bindings if we
+  // navigate back to it in the future.  This can only be changed once.
+  void SetBindings(int bindings);
+  int bindings() const {
+    return bindings_;
+  }
+
+  void set_page_type(PageType page_type) {
+    page_type_ = page_type;
+  }
+
+  bool has_virtual_url() const {
+    return !virtual_url_.is_empty();
+  }
+
+  bool update_virtual_url_with_url() const {
+    return update_virtual_url_with_url_;
+  }
+  void set_update_virtual_url_with_url(bool update) {
+    update_virtual_url_with_url_ = update;
+  }
+
+  // Extra headers (separated by \n) to send during the request.
+  void set_extra_headers(const std::string& extra_headers) {
+    extra_headers_ = extra_headers;
+  }
+  const std::string& extra_headers() const {
+    return extra_headers_;
+  }
+
+  // Whether this (pending) navigation is renderer-initiated.  Resets to false
+  // for all types of navigations after commit.
+  void set_is_renderer_initiated(bool is_renderer_initiated) {
+    is_renderer_initiated_ = is_renderer_initiated;
+  }
+  bool is_renderer_initiated() const {
+    return is_renderer_initiated_;
+  }
+
+  void set_user_typed_url(const GURL& user_typed_url) {
+    user_typed_url_ = user_typed_url;
+  }
+
+  // Enumerations of the possible restore types.
+  enum RestoreType {
+    // Restore from the previous session.
+    RESTORE_LAST_SESSION_EXITED_CLEANLY,
+    RESTORE_LAST_SESSION_CRASHED,
+
+    // The entry has been restored from the current session. This is used when
+    // the user issues 'reopen closed tab'.
+    RESTORE_CURRENT_SESSION,
+
+    // The entry was not restored.
+    RESTORE_NONE
+  };
+
+  // The RestoreType for this entry. This is set if the entry was retored. This
+  // is set to RESTORE_NONE once the entry is loaded.
+  void set_restore_type(RestoreType type) {
+    restore_type_ = type;
+  }
+  RestoreType restore_type() const {
+    return restore_type_;
+  }
+
+  void set_transferred_global_request_id(
+      const GlobalRequestID& transferred_global_request_id) {
+    transferred_global_request_id_ = transferred_global_request_id;
+  }
+
+  GlobalRequestID transferred_global_request_id() const {
+    return transferred_global_request_id_;
+  }
+
+  // Whether this (pending) navigation needs to replace current entry.
+  // Resets to false after commit.
+  bool should_replace_entry() const {
+    return should_replace_entry_;
+  }
+
+  void set_should_replace_entry(bool should_replace_entry) {
+    should_replace_entry_ = should_replace_entry;
+  }
+
+  // Any redirects present in a pending entry when it is transferred from one
+  // process to another.  Not valid after commit.
+  const std::vector<GURL>& redirect_chain() const {
+    return redirect_chain_;
+  }
+
+  void set_redirect_chain(const std::vector<GURL>& redirect_chain) {
+    redirect_chain_ = redirect_chain;
+  }
+
+  void SetScreenshotPNGData(scoped_refptr<base::RefCountedBytes> png_data);
+  const scoped_refptr<base::RefCountedBytes> screenshot() const {
+    return screenshot_;
+  }
+
+  // Whether this (pending) navigation should clear the session history. Resets
+  // to false after commit.
+  bool should_clear_history_list() const {
+    return should_clear_history_list_;
+  }
+  void set_should_clear_history_list(bool should_clear_history_list) {
+    should_clear_history_list_ = should_clear_history_list;
+  }
+
+ private:
+  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+  // Session/Tab restore save portions of this class so that it can be recreated
+  // later. If you add a new field that needs to be persisted you'll have to
+  // update SessionService/TabRestoreService and Android WebView
+  // state_serializer.cc appropriately.
+  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+
+  // See the accessors above for descriptions.
+  int unique_id_;
+  scoped_refptr<SiteInstanceImpl> site_instance_;
+  // TODO(creis): Persist bindings_. http://crbug.com/173672.
+  int bindings_;
+  PageType page_type_;
+  GURL url_;
+  Referrer referrer_;
+  GURL virtual_url_;
+  bool update_virtual_url_with_url_;
+  string16 title_;
+  FaviconStatus favicon_;
+  PageState page_state_;
+  int32 page_id_;
+  SSLStatus ssl_;
+  PageTransition transition_type_;
+  GURL user_typed_url_;
+  bool has_post_data_;
+  int64 post_id_;
+  RestoreType restore_type_;
+  GURL original_request_url_;
+  bool is_overriding_user_agent_;
+  base::Time timestamp_;
+  int http_status_code_;
+
+  // This member is not persisted with session restore because it is transient.
+  // If the post request succeeds, this field is cleared since the same
+  // information is stored in |content_state_| above. It is also only shallow
+  // copied with compiler provided copy constructor.
+  // Cleared in |ResetForCommit|.
+  scoped_refptr<const base::RefCountedMemory> browser_initiated_post_data_;
+
+  // This is also a transient member (i.e. is not persisted with session
+  // restore). The screenshot of a page is taken when navigating away from the
+  // page. This screenshot is displayed during an overscroll-navigation
+  // gesture. |screenshot_| will be NULL when the screenshot is not available
+  // (e.g. after a session restore, or if taking the screenshot of a page
+  // failed). The UI is responsible for dealing with missing screenshots
+  // appropriately (e.g. display a placeholder image instead).
+  scoped_refptr<base::RefCountedBytes> screenshot_;
+
+  // This member is not persisted with session restore.
+  std::string extra_headers_;
+
+  // Used for specifying base URL for pages loaded via data URLs. Only used and
+  // persisted by Android WebView.
+  GURL base_url_for_data_url_;
+
+  // Whether the entry, while loading, was created for a renderer-initiated
+  // navigation.  This dictates whether the URL should be displayed before the
+  // navigation commits.  It is cleared in |ResetForCommit| and not persisted.
+  bool is_renderer_initiated_;
+
+  // This is a cached version of the result of GetTitleForDisplay. It prevents
+  // us from having to do URL formatting on the URL every time the title is
+  // displayed. When the URL, virtual URL, or title is set, this should be
+  // cleared to force a refresh.
+  mutable string16 cached_display_title_;
+
+  // In case a navigation is transferred to a new RVH but the request has
+  // been generated in the renderer already, this identifies the old request so
+  // that it can be resumed. The old request is stored until the
+  // ResourceDispatcher receives the navigation from the renderer which
+  // carries this |transferred_global_request_id_| annotation. Once the request
+  // is transferred to the new process, this is cleared and the request
+  // continues as normal.
+  // Cleared in |ResetForCommit|.
+  GlobalRequestID transferred_global_request_id_;
+
+  // This is set to true when this entry is being reloaded and due to changes in
+  // the state of the URL, it has to be reloaded in a different site instance.
+  // In such case, we must treat it as an existing navigation in the new site
+  // instance, instead of a new navigation. This value should not be persisted
+  // and is cleared in |ResetForCommit|.
+  //
+  // We also use this flag for cross-process redirect navigations, so that the
+  // browser will replace the current navigation entry (which is the page
+  // doing the redirect).
+  bool should_replace_entry_;
+
+  // This is used when transferring a pending entry from one process to another.
+  // It is cleared in |ResetForCommit| and should not be persisted.
+  std::vector<GURL> redirect_chain_;
+
+  // This is set to true when this entry's navigation should clear the session
+  // history both on the renderer and browser side. The browser side history
+  // won't be cleared until the renderer has committed this navigation. This
+  // entry is not persisted by the session restore system, as it is always
+  // cleared in |ResetForCommit|.
+  bool should_clear_history_list_;
+
+  // Set when this entry should be able to access local file:// resources. This
+  // value is not needed after the entry commits and is not persisted.
+  bool can_load_local_resources_;
+
+  // If not empty, the name of the frame to navigate. This field is not
+  // persisted, because it is currently only used in tests.
+  std::string frame_to_navigate_;
+
+  // Used to store extra data to support browser features. This member is not
+  // persisted, unless specific data is taken out/put back in at save/restore
+  // time (see TabNavigation for an example of this).
+  std::map<std::string, string16> extra_data_;
+
+  // Copy and assignment is explicitly allowed for this class.
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_ENTRY_IMPL_H_
diff --git a/content/browser/frame_host/navigation_entry_impl_unittest.cc b/content/browser/frame_host/navigation_entry_impl_unittest.cc
new file mode 100644
index 0000000..6486fde
--- /dev/null
+++ b/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/public/common/ssl_status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class NavigationEntryTest : public testing::Test {
+ public:
+  NavigationEntryTest() : instance_(NULL) {
+  }
+
+  virtual void SetUp() {
+    entry1_.reset(new NavigationEntryImpl);
+
+#if !defined(OS_IOS)
+    instance_ = static_cast<SiteInstanceImpl*>(SiteInstance::Create(NULL));
+#endif
+    entry2_.reset(new NavigationEntryImpl(
+          instance_, 3,
+          GURL("test:url"),
+          Referrer(GURL("from"), WebKit::WebReferrerPolicyDefault),
+          ASCIIToUTF16("title"),
+          PAGE_TRANSITION_TYPED,
+          false));
+  }
+
+  virtual void TearDown() {
+  }
+
+ protected:
+  scoped_ptr<NavigationEntryImpl> entry1_;
+  scoped_ptr<NavigationEntryImpl> entry2_;
+  // SiteInstances are deleted when their NavigationEntries are gone.
+  SiteInstanceImpl* instance_;
+};
+
+// Test unique ID accessors
+TEST_F(NavigationEntryTest, NavigationEntryUniqueIDs) {
+  // Two entries should have different IDs by default
+  EXPECT_NE(entry1_->GetUniqueID(), entry2_->GetUniqueID());
+
+  // Can set an entry to have the same ID as another
+  entry2_->set_unique_id(entry1_->GetUniqueID());
+  EXPECT_EQ(entry1_->GetUniqueID(), entry2_->GetUniqueID());
+}
+
+// Test URL accessors
+TEST_F(NavigationEntryTest, NavigationEntryURLs) {
+  // Start with no virtual_url (even if a url is set)
+  EXPECT_FALSE(entry1_->has_virtual_url());
+  EXPECT_FALSE(entry2_->has_virtual_url());
+
+  EXPECT_EQ(GURL(), entry1_->GetURL());
+  EXPECT_EQ(GURL(), entry1_->GetVirtualURL());
+  EXPECT_TRUE(entry1_->GetTitleForDisplay(std::string()).empty());
+
+  // Setting URL affects virtual_url and GetTitleForDisplay
+  entry1_->SetURL(GURL("http://www.google.com"));
+  EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetURL());
+  EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetVirtualURL());
+  EXPECT_EQ(ASCIIToUTF16("www.google.com"),
+            entry1_->GetTitleForDisplay(std::string()));
+
+  // file:/// URLs should only show the filename.
+  entry1_->SetURL(GURL("file:///foo/bar baz.txt"));
+  EXPECT_EQ(ASCIIToUTF16("bar baz.txt"),
+            entry1_->GetTitleForDisplay(std::string()));
+
+  // Title affects GetTitleForDisplay
+  entry1_->SetTitle(ASCIIToUTF16("Google"));
+  EXPECT_EQ(ASCIIToUTF16("Google"), entry1_->GetTitleForDisplay(std::string()));
+
+  // Setting virtual_url doesn't affect URL
+  entry2_->SetVirtualURL(GURL("display:url"));
+  EXPECT_TRUE(entry2_->has_virtual_url());
+  EXPECT_EQ(GURL("test:url"), entry2_->GetURL());
+  EXPECT_EQ(GURL("display:url"), entry2_->GetVirtualURL());
+
+  // Having a title set in constructor overrides virtual URL
+  EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitleForDisplay(std::string()));
+
+  // User typed URL is independent of the others
+  EXPECT_EQ(GURL(), entry1_->GetUserTypedURL());
+  EXPECT_EQ(GURL(), entry2_->GetUserTypedURL());
+  entry2_->set_user_typed_url(GURL("typedurl"));
+  EXPECT_EQ(GURL("typedurl"), entry2_->GetUserTypedURL());
+}
+
+// Test Favicon inner class construction.
+TEST_F(NavigationEntryTest, NavigationEntryFavicons) {
+  EXPECT_EQ(GURL(), entry1_->GetFavicon().url);
+  EXPECT_FALSE(entry1_->GetFavicon().valid);
+}
+
+// Test SSLStatus inner class
+TEST_F(NavigationEntryTest, NavigationEntrySSLStatus) {
+  // Default (unknown)
+  EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry1_->GetSSL().security_style);
+  EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry2_->GetSSL().security_style);
+  EXPECT_EQ(0, entry1_->GetSSL().cert_id);
+  EXPECT_EQ(0U, entry1_->GetSSL().cert_status);
+  EXPECT_EQ(-1, entry1_->GetSSL().security_bits);
+  int content_status = entry1_->GetSSL().content_status;
+  EXPECT_FALSE(!!(content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT));
+  EXPECT_FALSE(!!(content_status & SSLStatus::RAN_INSECURE_CONTENT));
+}
+
+// Test other basic accessors
+TEST_F(NavigationEntryTest, NavigationEntryAccessors) {
+  // SiteInstance
+  EXPECT_TRUE(entry1_->site_instance() == NULL);
+  EXPECT_EQ(instance_, entry2_->site_instance());
+  entry1_->set_site_instance(instance_);
+  EXPECT_EQ(instance_, entry1_->site_instance());
+
+  // Page type
+  EXPECT_EQ(PAGE_TYPE_NORMAL, entry1_->GetPageType());
+  EXPECT_EQ(PAGE_TYPE_NORMAL, entry2_->GetPageType());
+  entry2_->set_page_type(PAGE_TYPE_INTERSTITIAL);
+  EXPECT_EQ(PAGE_TYPE_INTERSTITIAL, entry2_->GetPageType());
+
+  // Referrer
+  EXPECT_EQ(GURL(), entry1_->GetReferrer().url);
+  EXPECT_EQ(GURL("from"), entry2_->GetReferrer().url);
+  entry2_->SetReferrer(
+      Referrer(GURL("from2"), WebKit::WebReferrerPolicyDefault));
+  EXPECT_EQ(GURL("from2"), entry2_->GetReferrer().url);
+
+  // Title
+  EXPECT_EQ(string16(), entry1_->GetTitle());
+  EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitle());
+  entry2_->SetTitle(ASCIIToUTF16("title2"));
+  EXPECT_EQ(ASCIIToUTF16("title2"), entry2_->GetTitle());
+
+  // State
+  EXPECT_FALSE(entry1_->GetPageState().IsValid());
+  EXPECT_FALSE(entry2_->GetPageState().IsValid());
+  entry2_->SetPageState(PageState::CreateFromEncodedData("state"));
+  EXPECT_EQ("state", entry2_->GetPageState().ToEncodedData());
+
+  // Page ID
+  EXPECT_EQ(-1, entry1_->GetPageID());
+  EXPECT_EQ(3, entry2_->GetPageID());
+  entry2_->SetPageID(2);
+  EXPECT_EQ(2, entry2_->GetPageID());
+
+  // Transition type
+  EXPECT_EQ(PAGE_TRANSITION_LINK, entry1_->GetTransitionType());
+  EXPECT_EQ(PAGE_TRANSITION_TYPED, entry2_->GetTransitionType());
+  entry2_->SetTransitionType(PAGE_TRANSITION_RELOAD);
+  EXPECT_EQ(PAGE_TRANSITION_RELOAD, entry2_->GetTransitionType());
+
+  // Is renderer initiated
+  EXPECT_FALSE(entry1_->is_renderer_initiated());
+  EXPECT_FALSE(entry2_->is_renderer_initiated());
+  entry2_->set_is_renderer_initiated(true);
+  EXPECT_TRUE(entry2_->is_renderer_initiated());
+
+  // Post Data
+  EXPECT_FALSE(entry1_->GetHasPostData());
+  EXPECT_FALSE(entry2_->GetHasPostData());
+  entry2_->SetHasPostData(true);
+  EXPECT_TRUE(entry2_->GetHasPostData());
+
+  // Restored
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, entry1_->restore_type());
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, entry2_->restore_type());
+  entry2_->set_restore_type(
+      NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY);
+  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+            entry2_->restore_type());
+
+  // Original URL
+  EXPECT_EQ(GURL(), entry1_->GetOriginalRequestURL());
+  EXPECT_EQ(GURL(), entry2_->GetOriginalRequestURL());
+  entry2_->SetOriginalRequestURL(GURL("original_url"));
+  EXPECT_EQ(GURL("original_url"), entry2_->GetOriginalRequestURL());
+
+  // User agent override
+  EXPECT_FALSE(entry1_->GetIsOverridingUserAgent());
+  EXPECT_FALSE(entry2_->GetIsOverridingUserAgent());
+  entry2_->SetIsOverridingUserAgent(true);
+  EXPECT_TRUE(entry2_->GetIsOverridingUserAgent());
+
+  // Browser initiated post data
+  EXPECT_EQ(NULL, entry1_->GetBrowserInitiatedPostData());
+  EXPECT_EQ(NULL, entry2_->GetBrowserInitiatedPostData());
+  const int length = 11;
+  const unsigned char* raw_data =
+      reinterpret_cast<const unsigned char*>("post\n\n\0data");
+  std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
+  scoped_refptr<base::RefCountedBytes> post_data =
+      base::RefCountedBytes::TakeVector(&post_data_vector);
+  entry2_->SetBrowserInitiatedPostData(post_data.get());
+  EXPECT_EQ(post_data->front(),
+      entry2_->GetBrowserInitiatedPostData()->front());
+
+ // Frame to navigate.
+  EXPECT_TRUE(entry1_->GetFrameToNavigate().empty());
+  EXPECT_TRUE(entry2_->GetFrameToNavigate().empty());
+}
+
+// Test timestamps.
+TEST_F(NavigationEntryTest, NavigationEntryTimestamps) {
+  EXPECT_EQ(base::Time(), entry1_->GetTimestamp());
+  const base::Time now = base::Time::Now();
+  entry1_->SetTimestamp(now);
+  EXPECT_EQ(now, entry1_->GetTimestamp());
+}
+
+// Test extra data stored in the navigation entry.
+TEST_F(NavigationEntryTest, NavigationEntryExtraData) {
+  string16 test_data = ASCIIToUTF16("my search terms");
+  string16 output;
+  entry1_->SetExtraData("search_terms", test_data);
+
+  EXPECT_FALSE(entry1_->GetExtraData("non_existent_key", &output));
+  EXPECT_EQ(ASCIIToUTF16(""), output);
+  EXPECT_TRUE(entry1_->GetExtraData("search_terms", &output));
+  EXPECT_EQ(test_data, output);
+  // Data is cleared.
+  entry1_->ClearExtraData("search_terms");
+  // Content in |output| is not modified if data is not present at the key.
+  EXPECT_FALSE(entry1_->GetExtraData("search_terms", &output));
+  EXPECT_EQ(test_data, output);
+  // Using an empty string shows that the data is not present in the map.
+  string16 output2;
+  EXPECT_FALSE(entry1_->GetExtraData("search_terms", &output2));
+  EXPECT_EQ(ASCIIToUTF16(""), output2);
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
new file mode 100644
index 0000000..c1fbc30
--- /dev/null
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -0,0 +1,103 @@
+// Copyright 2013 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/render_frame_host_impl.h"
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// The (process id, routing id) pair that identifies one RenderFrame.
+typedef std::pair<int32, int32> RenderFrameHostID;
+typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
+    RoutingIDFrameMap;
+static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
+    LAZY_INSTANCE_INITIALIZER;
+
+// static
+RenderFrameHostImpl* RenderFrameHostImpl::FromID(
+    int process_id, int routing_id) {
+  RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer();
+  RoutingIDFrameMap::iterator it = frames->find(
+      RenderFrameHostID(process_id, routing_id));
+  return it == frames->end() ? NULL : it->second;
+}
+
+RenderFrameHostImpl::RenderFrameHostImpl(
+    RenderViewHostImpl* render_view_host,
+    FrameTree* frame_tree,
+    int routing_id,
+    bool is_swapped_out)
+    : render_view_host_(render_view_host),
+      frame_tree_(frame_tree),
+      routing_id_(routing_id),
+      is_swapped_out_(is_swapped_out) {
+  GetProcess()->AddRoute(routing_id_, this);
+  g_routing_id_frame_map.Get().insert(std::make_pair(
+      RenderFrameHostID(GetProcess()->GetID(), routing_id_),
+      this));
+}
+
+RenderFrameHostImpl::~RenderFrameHostImpl() {
+  GetProcess()->RemoveRoute(routing_id_);
+  g_routing_id_frame_map.Get().erase(
+      RenderFrameHostID(GetProcess()->GetID(), routing_id_));
+
+}
+
+bool RenderFrameHostImpl::Send(IPC::Message* message) {
+  return GetProcess()->Send(message);
+}
+
+bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
+  bool handled = true;
+  bool msg_is_ok = true;
+  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameHostImpl, msg, msg_is_ok)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame,
+                        OnDidStartProvisionalLoadForFrame)
+  IPC_END_MESSAGE_MAP_EX()
+
+  return handled;
+}
+
+void RenderFrameHostImpl::Init() {
+  GetProcess()->ResumeRequestsForView(routing_id());
+}
+
+RenderProcessHost* RenderFrameHostImpl::GetProcess() const {
+  // TODO(nasko): This should return its own process, once we have working
+  // cross-process navigation for subframes.
+  return render_view_host_->GetProcess();
+}
+
+void RenderFrameHostImpl::OnCreateChildFrame(int new_frame_routing_id,
+                                             int64 parent_frame_id,
+                                             int64 frame_id,
+                                             const std::string& frame_name) {
+  frame_tree_->AddFrame(new_frame_routing_id, parent_frame_id, frame_id,
+                        frame_name);
+}
+
+void RenderFrameHostImpl::OnDetach(int64 parent_frame_id, int64 frame_id) {
+  frame_tree_->RemoveFrame(parent_frame_id, frame_id);
+}
+
+void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame(
+    int64 frame_id,
+    int64 parent_frame_id,
+    bool is_main_frame,
+    const GURL& url) {
+  render_view_host_->OnDidStartProvisionalLoadForFrame(
+      frame_id, parent_frame_id, is_main_frame, url);
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
new file mode 100644
index 0000000..dbe8972
--- /dev/null
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -0,0 +1,77 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_IMPL_H_
+#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_IMPL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/render_frame_host.h"
+
+class GURL;
+
+namespace content {
+
+class FrameTree;
+class RenderProcessHost;
+class RenderViewHostImpl;
+
+class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
+ public:
+  static RenderFrameHostImpl* FromID(int process_id, int routing_id);
+
+  // TODO(nasko): Remove dependency on RenderViewHost here. RenderProcessHost
+  // should be the abstraction needed here, but we need RenderViewHost to pass
+  // into WebContentsObserver::FrameDetached for now.
+  RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
+                      FrameTree* frame_tree,
+                      int routing_id,
+                      bool is_swapped_out);
+  virtual ~RenderFrameHostImpl();
+
+  // IPC::Sender
+  virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+  // IPC::Listener
+  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+
+  void Init();
+  RenderProcessHost* GetProcess() const;
+  int routing_id() const { return routing_id_; }
+  void OnCreateChildFrame(int new_frame_routing_id,
+                          int64 parent_frame_id,
+                          int64 frame_id,
+                          const std::string& frame_name);
+
+  RenderViewHostImpl* render_view_host() {
+    return render_view_host_;
+  }
+
+ private:
+  // IPC Message handlers.
+  void OnDetach(int64 parent_frame_id, int64 frame_id);
+  void OnDidStartProvisionalLoadForFrame(int64 frame_id,
+                                         int64 parent_frame_id,
+                                         bool main_frame,
+                                         const GURL& url);
+
+  bool is_swapped_out() { return is_swapped_out_; }
+
+  // TODO(nasko): This should be removed and replaced by RenderProcessHost.
+  RenderViewHostImpl* render_view_host_;  // Not owned.
+
+  // Reference to the whole frame tree that this RenderFrameHost belongs too.
+  // Allows this RenderFrameHost to add and remove nodes in response to
+  // messages from the renderer requesting DOM manipulation.
+  FrameTree* frame_tree_;
+  int routing_id_;
+  bool is_swapped_out_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameHostImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_IMPL_H_
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
new file mode 100644
index 0000000..c187680
--- /dev/null
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -0,0 +1,71 @@
+// Copyright 2013 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/render_frame_message_filter.h"
+
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_widget_helper.h"
+#include "content/common/frame_messages.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+namespace {
+
+void CreateChildFrameOnUI(int process_id,
+                          int parent_render_frame_id,
+                          int64 parent_frame_id,
+                          int64 frame_id,
+                          const std::string& frame_name,
+                          int new_render_frame_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  RenderFrameHostImpl* render_frame_host =
+      RenderFrameHostImpl::FromID(process_id, parent_render_frame_id);
+  // Handles the RenderFrameHost being deleted on the UI thread while
+  // processing a subframe creation message.
+  if (render_frame_host) {
+    render_frame_host->OnCreateChildFrame(new_render_frame_id,
+                                          parent_frame_id, frame_id,
+                                          frame_name);
+  }
+}
+
+}  // namespace
+
+RenderFrameMessageFilter::RenderFrameMessageFilter(
+    int render_process_id,
+    RenderWidgetHelper* render_widget_helper)
+    : render_process_id_(render_process_id),
+      render_widget_helper_(render_widget_helper) {
+}
+
+RenderFrameMessageFilter::~RenderFrameMessageFilter() {
+}
+
+bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message,
+                                                 bool* message_was_ok) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameMessageFilter, message, *message_was_ok)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_CreateChildFrame, OnCreateChildFrame)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP_EX()
+
+  return handled;
+}
+
+void RenderFrameMessageFilter::OnCreateChildFrame(
+    int parent_render_frame_id,
+    int64 parent_frame_id,
+    int64 frame_id,
+    const std::string& frame_name,
+    int* new_render_frame_id) {
+  *new_render_frame_id = render_widget_helper_->GetNextRoutingID();
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&CreateChildFrameOnUI, render_process_id_,
+                 parent_render_frame_id, parent_frame_id, frame_id, frame_name,
+                 *new_render_frame_id));
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/render_frame_message_filter.h b/content/browser/frame_host/render_frame_message_filter.h
new file mode 100644
index 0000000..82a1b94
--- /dev/null
+++ b/content/browser/frame_host/render_frame_message_filter.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
+
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+class RenderWidgetHelper;
+
+// RenderFrameMessageFilter intercepts FrameHost messages on the IO thread
+// that require low-latency processing. The canonical example of this is
+// child-frame creation which is a sync IPC that provides the renderer
+// with the routing id for a newly created RenderFrame.
+//
+// This object is created on the UI thread and used on the IO thread.
+class RenderFrameMessageFilter : public BrowserMessageFilter {
+ public:
+  RenderFrameMessageFilter(int render_process_id,
+                           RenderWidgetHelper* render_widget_helper);
+
+  virtual bool OnMessageReceived(const IPC::Message& message,
+                                 bool* message_was_ok) OVERRIDE;
+
+ private:
+  virtual ~RenderFrameMessageFilter();
+
+  void OnCreateChildFrame(int parent_render_frame_id,
+                          int64 parent_frame_id,
+                          int64 frame_id,
+                          const std::string& frame_name,
+                          int* new_render_frame_id);
+
+  const int render_process_id_;
+
+  // Needed for issuing routing ids and surface ids.
+  scoped_refptr<RenderWidgetHelper> render_widget_helper_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
diff --git a/content/browser/frame_host/render_view_host_manager.cc b/content/browser/frame_host/render_view_host_manager.cc
new file mode 100644
index 0000000..34e2a00
--- /dev/null
+++ b/content/browser/frame_host/render_view_host_manager.cc
@@ -0,0 +1,1119 @@
+// Copyright 2013 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/render_view_host_manager.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "content/browser/devtools/render_view_devtools_agent_host.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_factory.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/webui/web_ui_controller_factory_registry.h"
+#include "content/browser/webui/web_ui_impl.h"
+#include "content/common/view_messages.h"
+#include "content/port/browser/render_widget_host_view_port.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/browser/user_metrics.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+
+namespace content {
+
+RenderViewHostManager::PendingNavigationParams::PendingNavigationParams()
+    : is_transfer(false), frame_id(-1) {
+}
+
+RenderViewHostManager::PendingNavigationParams::PendingNavigationParams(
+    const GlobalRequestID& global_request_id,
+    bool is_transfer,
+    const std::vector<GURL>& transfer_url_chain,
+    Referrer referrer,
+    PageTransition page_transition,
+    int64 frame_id)
+    : global_request_id(global_request_id),
+      is_transfer(is_transfer),
+      transfer_url_chain(transfer_url_chain),
+      referrer(referrer),
+      page_transition(page_transition),
+      frame_id(frame_id) {
+}
+
+RenderViewHostManager::PendingNavigationParams::~PendingNavigationParams() {}
+
+RenderViewHostManager::RenderViewHostManager(
+    RenderViewHostDelegate* render_view_delegate,
+    RenderWidgetHostDelegate* render_widget_delegate,
+    Delegate* delegate)
+    : delegate_(delegate),
+      cross_navigation_pending_(false),
+      render_view_delegate_(render_view_delegate),
+      render_widget_delegate_(render_widget_delegate),
+      render_view_host_(NULL),
+      pending_render_view_host_(NULL),
+      interstitial_page_(NULL) {
+}
+
+RenderViewHostManager::~RenderViewHostManager() {
+  if (pending_render_view_host_)
+    CancelPending();
+
+  // We should always have a main RenderViewHost except in some tests.
+  RenderViewHostImpl* render_view_host = render_view_host_;
+  render_view_host_ = NULL;
+  if (render_view_host)
+    render_view_host->Shutdown();
+
+  // Shut down any swapped out RenderViewHosts.
+  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+       iter != swapped_out_hosts_.end();
+       ++iter) {
+    iter->second->Shutdown();
+  }
+}
+
+void RenderViewHostManager::Init(BrowserContext* browser_context,
+                                 SiteInstance* site_instance,
+                                 int routing_id,
+                                 int main_frame_routing_id) {
+  // Create a RenderViewHost, once we have an instance.  It is important to
+  // immediately give this SiteInstance to a RenderViewHost so that it is
+  // ref counted.
+  if (!site_instance)
+    site_instance = SiteInstance::Create(browser_context);
+  render_view_host_ = static_cast<RenderViewHostImpl*>(
+      RenderViewHostFactory::Create(
+          site_instance, render_view_delegate_, render_widget_delegate_,
+          routing_id, main_frame_routing_id, false,
+          delegate_->IsHidden()));
+  render_view_host_->AttachToFrameTree();
+
+  // Keep track of renderer processes as they start to shut down or are
+  // crashed/killed.
+  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
+                 NotificationService::AllSources());
+  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
+                 NotificationService::AllSources());
+}
+
+RenderViewHostImpl* RenderViewHostManager::current_host() const {
+  return render_view_host_;
+}
+
+RenderViewHostImpl* RenderViewHostManager::pending_render_view_host() const {
+  return pending_render_view_host_;
+}
+
+RenderWidgetHostView* RenderViewHostManager::GetRenderWidgetHostView() const {
+  if (interstitial_page_)
+    return interstitial_page_->GetView();
+  if (!render_view_host_)
+    return NULL;
+  return render_view_host_->GetView();
+}
+
+void RenderViewHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
+  pending_web_ui_.reset(
+      delegate_->CreateWebUIForRenderManager(entry.GetURL()));
+  pending_and_current_web_ui_.reset();
+
+  // If we have assigned (zero or more) bindings to this NavigationEntry in the
+  // past, make sure we're not granting it different bindings than it had
+  // before.  If so, note it and don't give it any bindings, to avoid a
+  // potential privilege escalation.
+  if (pending_web_ui_.get() &&
+      entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
+      pending_web_ui_->GetBindings() != entry.bindings()) {
+    RecordAction(UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
+    pending_web_ui_.reset();
+  }
+}
+
+RenderViewHostImpl* RenderViewHostManager::Navigate(
+    const NavigationEntryImpl& entry) {
+  TRACE_EVENT0("browser", "RenderViewHostManager:Navigate");
+  // Create a pending RenderViewHost. It will give us the one we should use
+  RenderViewHostImpl* dest_render_view_host =
+      static_cast<RenderViewHostImpl*>(UpdateRendererStateForNavigate(entry));
+  if (!dest_render_view_host)
+    return NULL;  // We weren't able to create a pending render view host.
+
+  // If the current render_view_host_ isn't live, we should create it so
+  // that we don't show a sad tab while the dest_render_view_host fetches
+  // its first page.  (Bug 1145340)
+  if (dest_render_view_host != render_view_host_ &&
+      !render_view_host_->IsRenderViewLive()) {
+    // Note: we don't call InitRenderView here because we are navigating away
+    // soon anyway, and we don't have the NavigationEntry for this host.
+    delegate_->CreateRenderViewForRenderManager(render_view_host_,
+                                                MSG_ROUTING_NONE);
+  }
+
+  // If the renderer crashed, then try to create a new one to satisfy this
+  // navigation request.
+  if (!dest_render_view_host->IsRenderViewLive()) {
+    // Recreate the opener chain.
+    int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
+        dest_render_view_host->GetSiteInstance());
+    if (!InitRenderView(dest_render_view_host, opener_route_id))
+      return NULL;
+
+    // Now that we've created a new renderer, be sure to hide it if it isn't
+    // our primary one.  Otherwise, we might crash if we try to call Show()
+    // on it later.
+    if (dest_render_view_host != render_view_host_ &&
+        dest_render_view_host->GetView()) {
+      dest_render_view_host->GetView()->Hide();
+    } else {
+      // This is our primary renderer, notify here as we won't be calling
+      // CommitPending (which does the notify).
+      delegate_->NotifySwappedFromRenderManager(NULL, render_view_host_);
+    }
+  }
+
+  return dest_render_view_host;
+}
+
+void RenderViewHostManager::Stop() {
+  render_view_host_->Stop();
+
+  // If we are cross-navigating, we should stop the pending renderers.  This
+  // will lead to a DidFailProvisionalLoad, which will properly destroy them.
+  if (cross_navigation_pending_) {
+    pending_render_view_host_->Send(
+        new ViewMsg_Stop(pending_render_view_host_->GetRoutingID()));
+  }
+}
+
+void RenderViewHostManager::SetIsLoading(bool is_loading) {
+  render_view_host_->SetIsLoading(is_loading);
+  if (pending_render_view_host_)
+    pending_render_view_host_->SetIsLoading(is_loading);
+}
+
+bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
+  if (!cross_navigation_pending_)
+    return true;
+
+  // We should always have a pending RVH when there's a cross-process navigation
+  // in progress.  Sanity check this for http://crbug.com/276333.
+  CHECK(pending_render_view_host_);
+
+  // If the tab becomes unresponsive during {before}unload while doing a
+  // cross-site navigation, proceed with the navigation.  (This assumes that
+  // the pending RenderViewHost is still responsive.)
+  if (render_view_host_->is_waiting_for_unload_ack()) {
+    // The request has been started and paused while we're waiting for the
+    // unload handler to finish.  We'll pretend that it did.  The pending
+    // renderer will then be swapped in as part of the usual DidNavigate logic.
+    // (If the unload handler later finishes, this call will be ignored because
+    // the pending_nav_params_ state will already be cleaned up.)
+    current_host()->OnSwappedOut(true);
+  } else if (render_view_host_->is_waiting_for_beforeunload_ack()) {
+    // Haven't gotten around to starting the request, because we're still
+    // waiting for the beforeunload handler to finish.  We'll pretend that it
+    // did finish, to let the navigation proceed.  Note that there's a danger
+    // that the beforeunload handler will later finish and possibly return
+    // false (meaning the navigation should not proceed), but we'll ignore it
+    // in this case because it took too long.
+    if (pending_render_view_host_->are_navigations_suspended())
+      pending_render_view_host_->SetNavigationsSuspended(
+          false, base::TimeTicks::Now());
+  }
+  return false;
+}
+
+void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) {
+  // Make sure this is from our current RVH, and that we have a pending
+  // navigation from OnCrossSiteResponse.  (There may be no pending navigation
+  // for data URLs that don't make network requests, for example.)   If not,
+  // just return early and ignore.
+  if (render_view_host != render_view_host_ || !pending_nav_params_.get()) {
+    pending_nav_params_.reset();
+    return;
+  }
+
+  // Now that the unload handler has run, we need to either initiate the
+  // pending transfer (if there is one) or resume the paused response (if not).
+  // TODO(creis): The blank swapped out page is visible during this time, but
+  // we can shorten this by delivering the response directly, rather than
+  // forcing an identical request to be made.
+  if (pending_nav_params_->is_transfer) {
+    // Treat the last URL in the chain as the destination and the remainder as
+    // the redirect chain.
+    CHECK(pending_nav_params_->transfer_url_chain.size());
+    GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
+    pending_nav_params_->transfer_url_chain.pop_back();
+
+    // We don't know whether the original request had |user_action| set to true.
+    // However, since we force the navigation to be in the current tab, it
+    // doesn't matter.
+    render_view_host->GetDelegate()->RequestTransferURL(
+        transfer_url,
+        pending_nav_params_->transfer_url_chain,
+        pending_nav_params_->referrer,
+        pending_nav_params_->page_transition,
+        CURRENT_TAB,
+        pending_nav_params_->frame_id,
+        pending_nav_params_->global_request_id,
+        false,
+        true);
+  } else if (pending_render_view_host_) {
+    RenderProcessHostImpl* pending_process =
+        static_cast<RenderProcessHostImpl*>(
+            pending_render_view_host_->GetProcess());
+    pending_process->ResumeDeferredNavigation(
+        pending_nav_params_->global_request_id);
+  }
+  pending_nav_params_.reset();
+}
+
+void RenderViewHostManager::DidNavigateMainFrame(
+    RenderViewHost* render_view_host) {
+  if (!cross_navigation_pending_) {
+    DCHECK(!pending_render_view_host_);
+
+    // We should only hear this from our current renderer.
+    DCHECK(render_view_host == render_view_host_);
+
+    // Even when there is no pending RVH, there may be a pending Web UI.
+    if (pending_web_ui())
+      CommitPending();
+    return;
+  }
+
+  if (render_view_host == pending_render_view_host_) {
+    // The pending cross-site navigation completed, so show the renderer.
+    // If it committed without sending network requests (e.g., data URLs),
+    // then we still need to swap out the old RVH first and run its unload
+    // handler.  OK for that to happen in the background.
+    if (pending_render_view_host_->HasPendingCrossSiteRequest())
+      SwapOutOldPage();
+
+    CommitPending();
+    cross_navigation_pending_ = false;
+  } else if (render_view_host == render_view_host_) {
+    // A navigation in the original page has taken place.  Cancel the pending
+    // one.
+    CancelPending();
+    cross_navigation_pending_ = false;
+  } else {
+    // No one else should be sending us DidNavigate in this state.
+    DCHECK(false);
+  }
+}
+
+void RenderViewHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
+  // Notify all swapped out hosts, including the pending RVH.
+  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+       iter != swapped_out_hosts_.end();
+       ++iter) {
+    DCHECK_NE(iter->second->GetSiteInstance(),
+              current_host()->GetSiteInstance());
+    iter->second->DisownOpener();
+  }
+}
+
+void RenderViewHostManager::RendererAbortedProvisionalLoad(
+    RenderViewHost* render_view_host) {
+  // We used to cancel the pending renderer here for cross-site downloads.
+  // However, it's not safe to do that because the download logic repeatedly
+  // looks for this WebContents based on a render view ID.  Instead, we just
+  // leave the pending renderer around until the next navigation event
+  // (Navigate, DidNavigate, etc), which will clean it up properly.
+  // TODO(creis): All of this will go away when we move the cross-site logic
+  // to ResourceDispatcherHost, so that we intercept responses rather than
+  // navigation events.  (That's necessary to support onunload anyway.)  Once
+  // we've made that change, we won't create a pending renderer until we know
+  // the response is not a download.
+}
+
+void RenderViewHostManager::RendererProcessClosing(
+    RenderProcessHost* render_process_host) {
+  // Remove any swapped out RVHs from this process, so that we don't try to
+  // swap them back in while the process is exiting.  Start by finding them,
+  // since there could be more than one.
+  std::list<int> ids_to_remove;
+  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+       iter != swapped_out_hosts_.end();
+       ++iter) {
+    if (iter->second->GetProcess() == render_process_host)
+      ids_to_remove.push_back(iter->first);
+  }
+
+  // Now delete them.
+  while (!ids_to_remove.empty()) {
+    swapped_out_hosts_[ids_to_remove.back()]->Shutdown();
+    swapped_out_hosts_.erase(ids_to_remove.back());
+    ids_to_remove.pop_back();
+  }
+}
+
+void RenderViewHostManager::ShouldClosePage(
+    bool for_cross_site_transition,
+    bool proceed,
+    const base::TimeTicks& proceed_time) {
+  if (for_cross_site_transition) {
+    // Ignore if we're not in a cross-site navigation.
+    if (!cross_navigation_pending_)
+      return;
+
+    if (proceed) {
+      // Ok to unload the current page, so proceed with the cross-site
+      // navigation.  Note that if navigations are not currently suspended, it
+      // might be because the renderer was deemed unresponsive and this call was
+      // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
+      // is ok to do nothing here.
+      if (pending_render_view_host_ &&
+          pending_render_view_host_->are_navigations_suspended()) {
+        pending_render_view_host_->SetNavigationsSuspended(false, proceed_time);
+      }
+    } else {
+      // Current page says to cancel.
+      CancelPending();
+      cross_navigation_pending_ = false;
+    }
+  } else {
+    // Non-cross site transition means closing the entire tab.
+    bool proceed_to_fire_unload;
+    delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
+                                                  &proceed_to_fire_unload);
+
+    if (proceed_to_fire_unload) {
+      // If we're about to close the tab and there's a pending RVH, cancel it.
+      // Otherwise, if the navigation in the pending RVH completes before the
+      // close in the current RVH, we'll lose the tab close.
+      if (pending_render_view_host_) {
+        CancelPending();
+        cross_navigation_pending_ = false;
+      }
+
+      // This is not a cross-site navigation, the tab is being closed.
+      render_view_host_->ClosePage();
+    }
+  }
+}
+
+void RenderViewHostManager::OnCrossSiteResponse(
+    RenderViewHost* pending_render_view_host,
+    const GlobalRequestID& global_request_id,
+    bool is_transfer,
+    const std::vector<GURL>& transfer_url_chain,
+    const Referrer& referrer,
+    PageTransition page_transition,
+    int64 frame_id) {
+  // This should be called either when the pending RVH is ready to commit or
+  // when we realize that the current RVH's request requires a transfer.
+  DCHECK(
+      pending_render_view_host == pending_render_view_host_ ||
+      pending_render_view_host == render_view_host_);
+
+  // TODO(creis): Eventually we will want to check all navigation responses
+  // here, but currently we pass information for a transfer if
+  // ShouldSwapProcessesForRedirect returned true in the network stack.
+  // In that case, we should set up a transfer after the unload handler runs.
+  // If is_transfer is false, we will just run the unload handler and resume.
+  pending_nav_params_.reset(new PendingNavigationParams(
+      global_request_id, is_transfer, transfer_url_chain, referrer,
+      page_transition, frame_id));
+
+  // Run the unload handler of the current page.
+  SwapOutOldPage();
+}
+
+void RenderViewHostManager::SwapOutOldPage() {
+  // Should only see this while we have a pending renderer or transfer.
+  CHECK(cross_navigation_pending_ || pending_nav_params_.get());
+
+  // First close any modal dialogs that would prevent us from swapping out.
+  // TODO(creis): This is not a guarantee.  The renderer could immediately
+  // create another dialog in a loop, potentially causing a renderer crash when
+  // we tell it to swap out with a nested message loop and PageGroupLoadDeferrer
+  // on the stack.  We should prevent the renderer from showing more dialogs
+  // until the SwapOut.  See http://crbug.com/312490.
+  delegate_->CancelModalDialogsForRenderManager();
+
+  // Tell the old renderer it is being swapped out.  This will fire the unload
+  // handler (without firing the beforeunload handler a second time).  When the
+  // unload handler finishes and the navigation completes, we will send a
+  // message to the ResourceDispatcherHost, allowing the pending RVH's response
+  // to resume.
+  render_view_host_->SwapOut();
+
+  // ResourceDispatcherHost has told us to run the onunload handler, which
+  // means it is not a download or unsafe page, and we are going to perform the
+  // navigation.  Thus, we no longer need to remember that the RenderViewHost
+  // is part of a pending cross-site request.
+  if (pending_render_view_host_)
+    pending_render_view_host_->SetHasPendingCrossSiteRequest(false);
+}
+
+void RenderViewHostManager::Observe(
+    int type,
+    const NotificationSource& source,
+    const NotificationDetails& details) {
+  switch (type) {
+    case NOTIFICATION_RENDERER_PROCESS_CLOSED:
+    case NOTIFICATION_RENDERER_PROCESS_CLOSING:
+      RendererProcessClosing(
+          Source<RenderProcessHost>(source).ptr());
+      break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+bool RenderViewHostManager::ShouldTransitionCrossSite() {
+  // False in the single-process mode, as it makes RVHs to accumulate
+  // in swapped_out_hosts_.
+  // True if we are using process-per-site-instance (default) or
+  // process-per-site (kProcessPerSite).
+  return
+      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
+}
+
+bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
+    const NavigationEntry* curr_entry,
+    const NavigationEntryImpl* new_entry) const {
+  DCHECK(new_entry);
+
+  // Check for reasons to swap processes even if we are in a process model that
+  // doesn't usually swap (e.g., process-per-tab).
+
+  // For security, we should transition between processes when one is a Web UI
+  // page and one isn't.  If there's no curr_entry, check the current RVH's
+  // site, which might already be committed to a Web UI URL (such as the NTP).
+  const GURL& current_url = (curr_entry) ? curr_entry->GetURL() :
+      render_view_host_->GetSiteInstance()->GetSiteURL();
+  BrowserContext* browser_context =
+      delegate_->GetControllerForRenderManager().GetBrowserContext();
+  if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
+          browser_context, current_url)) {
+    // Force swap if it's not an acceptable URL for Web UI.
+    // Here, data URLs are never allowed.
+    if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
+            browser_context, new_entry->GetURL(), false)) {
+      return true;
+    }
+  } else {
+    // Force swap if it's a Web UI URL.
+    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
+            browser_context, new_entry->GetURL())) {
+      return true;
+    }
+  }
+
+  if (GetContentClient()->browser()->ShouldSwapProcessesForNavigation(
+          render_view_host_->GetSiteInstance(),
+          curr_entry ? curr_entry->GetURL() : GURL(),
+          new_entry->GetURL())) {
+    return true;
+  }
+
+  if (!curr_entry)
+    return false;
+
+  // We can't switch a RenderView between view source and non-view source mode
+  // without screwing up the session history sometimes (when navigating between
+  // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat
+  // it as a new navigation). So require a view switch.
+  if (curr_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
+    return true;
+
+  return false;
+}
+
+bool RenderViewHostManager::ShouldReuseWebUI(
+    const NavigationEntry* curr_entry,
+    const NavigationEntryImpl* new_entry) const {
+  NavigationControllerImpl& controller =
+      delegate_->GetControllerForRenderManager();
+  return curr_entry && web_ui_.get() &&
+      (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
+          controller.GetBrowserContext(), curr_entry->GetURL()) ==
+       WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
+          controller.GetBrowserContext(), new_entry->GetURL()));
+}
+
+SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
+    const NavigationEntryImpl& entry,
+    SiteInstance* curr_instance) {
+  // NOTE: This is only called when ShouldTransitionCrossSite is true.
+
+  const GURL& dest_url = entry.GetURL();
+  NavigationControllerImpl& controller =
+      delegate_->GetControllerForRenderManager();
+  BrowserContext* browser_context = controller.GetBrowserContext();
+
+  // If the entry has an instance already we should use it.
+  if (entry.site_instance())
+    return entry.site_instance();
+
+  // (UGLY) HEURISTIC, process-per-site only:
+  //
+  // If this navigation is generated, then it probably corresponds to a search
+  // query.  Given that search results typically lead to users navigating to
+  // other sites, we don't really want to use the search engine hostname to
+  // determine the site instance for this navigation.
+  //
+  // NOTE: This can be removed once we have a way to transition between
+  //       RenderViews in response to a link click.
+  //
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
+      PageTransitionCoreTypeIs(entry.GetTransitionType(),
+                               PAGE_TRANSITION_GENERATED)) {
+    return curr_instance;
+  }
+
+  SiteInstanceImpl* curr_site_instance =
+      static_cast<SiteInstanceImpl*>(curr_instance);
+
+  // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
+  // for this entry.  We won't commit the SiteInstance to this site until the
+  // navigation commits (in DidNavigate), unless the navigation entry was
+  // restored or it's a Web UI as described below.
+  if (!curr_site_instance->HasSite()) {
+    // If we've already created a SiteInstance for our destination, we don't
+    // want to use this unused SiteInstance; use the existing one.  (We don't
+    // do this check if the curr_instance has a site, because for now, we want
+    // to compare against the current URL and not the SiteInstance's site.  In
+    // this case, there is no current URL, so comparing against the site is ok.
+    // See additional comments below.)
+    //
+    // Also, if the URL should use process-per-site mode and there is an
+    // existing process for the site, we should use it.  We can call
+    // GetRelatedSiteInstance() for this, which will eagerly set the site and
+    // thus use the correct process.
+    bool use_process_per_site =
+        RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
+        RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
+    if (curr_site_instance->HasRelatedSiteInstance(dest_url) ||
+        use_process_per_site) {
+      return curr_site_instance->GetRelatedSiteInstance(dest_url);
+    }
+
+    // For extensions, Web UI URLs (such as the new tab page), and apps we do
+    // not want to use the curr_instance if it has no site, since it will have a
+    // RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for this
+    // URL instead (with the correct process type).
+    if (curr_site_instance->HasWrongProcessForURL(dest_url))
+      return curr_site_instance->GetRelatedSiteInstance(dest_url);
+
+    // View-source URLs must use a new SiteInstance and BrowsingInstance.
+    // TODO(nasko): This is the same condition as later in the function. This
+    // should be taken into account when refactoring this method as part of
+    // http://crbug.com/123007.
+    if (entry.IsViewSourceMode())
+      return SiteInstance::CreateForURL(browser_context, dest_url);
+
+    // If we are navigating from a blank SiteInstance to a WebUI, make sure we
+    // create a new SiteInstance.
+    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
+            browser_context, dest_url)) {
+        return SiteInstance::CreateForURL(browser_context, dest_url);
+    }
+
+    // Normally the "site" on the SiteInstance is set lazily when the load
+    // actually commits. This is to support better process sharing in case
+    // the site redirects to some other site: we want to use the destination
+    // site in the site instance.
+    //
+    // In the case of session restore, as it loads all the pages immediately
+    // we need to set the site first, otherwise after a restore none of the
+    // pages would share renderers in process-per-site.
+    if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
+      curr_site_instance->SetSite(dest_url);
+
+    return curr_site_instance;
+  }
+
+  // Otherwise, only create a new SiteInstance for cross-site navigation.
+
+  // TODO(creis): Once we intercept links and script-based navigations, we
+  // will be able to enforce that all entries in a SiteInstance actually have
+  // the same site, and it will be safe to compare the URL against the
+  // SiteInstance's site, as follows:
+  // const GURL& current_url = curr_instance->site();
+  // For now, though, we're in a hybrid model where you only switch
+  // SiteInstances if you type in a cross-site URL.  This means we have to
+  // compare the entry's URL to the last committed entry's URL.
+  NavigationEntry* curr_entry = controller.GetLastCommittedEntry();
+  if (interstitial_page_) {
+    // The interstitial is currently the last committed entry, but we want to
+    // compare against the last non-interstitial entry.
+    curr_entry = controller.GetEntryAtOffset(-1);
+  }
+  // If there is no last non-interstitial entry (and curr_instance already
+  // has a site), then we must have been opened from another tab.  We want
+  // to compare against the URL of the page that opened us, but we can't
+  // get to it directly.  The best we can do is check against the site of
+  // the SiteInstance.  This will be correct when we intercept links and
+  // script-based navigations, but for now, it could place some pages in a
+  // new process unnecessarily.  We should only hit this case if a page tries
+  // to open a new tab to an interstitial-inducing URL, and then navigates
+  // the page to a different same-site URL.  (This seems very unlikely in
+  // practice.)
+  const GURL& current_url = (curr_entry) ? curr_entry->GetURL() :
+      curr_instance->GetSiteURL();
+
+  // View-source URLs must use a new SiteInstance and BrowsingInstance.
+  // TODO(creis): Refactor this method so this duplicated code isn't needed.
+  // See http://crbug.com/123007.
+  if (curr_entry &&
+      curr_entry->IsViewSourceMode() != entry.IsViewSourceMode()) {
+    return SiteInstance::CreateForURL(browser_context, dest_url);
+  }
+
+  // Use the current SiteInstance for same site navigations, as long as the
+  // process type is correct.  (The URL may have been installed as an app since
+  // the last time we visited it.)
+  if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
+      !static_cast<SiteInstanceImpl*>(curr_instance)->HasWrongProcessForURL(
+          dest_url)) {
+    return curr_instance;
+  } else if (ShouldSwapProcessesForNavigation(curr_entry, &entry)) {
+    // When we're swapping, we need to force the site instance AND browsing
+    // instance to be different ones. This addresses special cases where we use
+    // a single BrowsingInstance for all pages of a certain type (e.g., New Tab
+    // Pages), keeping them in the same process. When you navigate away from
+    // that page, we want to explicity ignore that BrowsingInstance and group
+    // this page into the appropriate SiteInstance for its URL.
+    return SiteInstance::CreateForURL(browser_context, dest_url);
+  } else {
+    // Start the new renderer in a new SiteInstance, but in the current
+    // BrowsingInstance.  It is important to immediately give this new
+    // SiteInstance to a RenderViewHost (if it is different than our current
+    // SiteInstance), so that it is ref counted.  This will happen in
+    // CreateRenderView.
+    return curr_instance->GetRelatedSiteInstance(dest_url);
+  }
+}
+
+int RenderViewHostManager::CreateRenderView(
+    SiteInstance* instance,
+    int opener_route_id,
+    bool swapped_out,
+    bool hidden) {
+  CHECK(instance);
+  DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
+
+  // Check if we've already created an RVH for this SiteInstance.  If so, try
+  // to re-use the existing one, which has already been initialized.  We'll
+  // remove it from the list of swapped out hosts if it commits.
+  RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>(
+      GetSwappedOutRenderViewHost(instance));
+  if (new_render_view_host) {
+    // Prevent the process from exiting while we're trying to use it.
+    if (!swapped_out)
+      new_render_view_host->GetProcess()->AddPendingView();
+  } else {
+    // Create a new RenderViewHost if we don't find an existing one.
+    new_render_view_host = static_cast<RenderViewHostImpl*>(
+        RenderViewHostFactory::Create(instance,
+                                      render_view_delegate_,
+                                      render_widget_delegate_,
+                                      MSG_ROUTING_NONE,
+                                      MSG_ROUTING_NONE,
+                                      swapped_out,
+                                      hidden));
+
+    // If the new RVH is swapped out already, store it.  Otherwise prevent the
+    // process from exiting while we're trying to navigate in it.
+    if (swapped_out) {
+      swapped_out_hosts_[instance->GetId()] = new_render_view_host;
+    } else {
+      new_render_view_host->GetProcess()->AddPendingView();
+    }
+
+    bool success = InitRenderView(new_render_view_host, opener_route_id);
+    if (success) {
+      // Don't show the view until we get a DidNavigate from it.
+      new_render_view_host->GetView()->Hide();
+    } else if (!swapped_out) {
+      CancelPending();
+    }
+  }
+
+  // Use this as our new pending RVH if it isn't swapped out.
+  if (!swapped_out)
+    pending_render_view_host_ = new_render_view_host;
+
+  return new_render_view_host->GetRoutingID();
+}
+
+bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
+                                           int opener_route_id) {
+  // If the pending navigation is to a WebUI and the RenderView is not in a
+  // guest process, tell the RenderView about any bindings it will need enabled.
+  if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest())
+    render_view_host->AllowBindings(pending_web_ui()->GetBindings());
+
+  return delegate_->CreateRenderViewForRenderManager(render_view_host,
+                                                     opener_route_id);
+}
+
+void RenderViewHostManager::CommitPending() {
+  // First check whether we're going to want to focus the location bar after
+  // this commit.  We do this now because the navigation hasn't formally
+  // committed yet, so if we've already cleared |pending_web_ui_| the call chain
+  // this triggers won't be able to figure out what's going on.
+  bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
+
+  // We currently can't guarantee that the renderer isn't showing a new modal
+  // dialog, even though we canceled them in SwapOutOldPage.  (It may have
+  // created another in the meantime.)  Make sure we run and reset the callback
+  // now before we delete its RVH below.
+  // TODO(creis): Remove this if we can guarantee that no new dialogs will be
+  // shown after SwapOutOldPage.  See http://crbug.com/312490.
+  delegate_->CancelModalDialogsForRenderManager();
+
+  // Next commit the Web UI, if any. Either replace |web_ui_| with
+  // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
+  // leave |web_ui_| as is if reusing it.
+  DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
+  if (pending_web_ui_)
+    web_ui_.reset(pending_web_ui_.release());
+  else if (!pending_and_current_web_ui_.get())
+    web_ui_.reset();
+
+  // It's possible for the pending_render_view_host_ to be NULL when we aren't
+  // crossing process boundaries. If so, we just needed to handle the Web UI
+  // committing above and we're done.
+  if (!pending_render_view_host_) {
+    if (will_focus_location_bar)
+      delegate_->SetFocusToLocationBar(false);
+    return;
+  }
+
+  // Remember if the page was focused so we can focus the new renderer in
+  // that case.
+  bool focus_render_view = !will_focus_location_bar &&
+      render_view_host_->GetView() && render_view_host_->GetView()->HasFocus();
+
+  // Swap in the pending view and make it active. Also ensure the FrameTree
+  // stays in sync.
+  RenderViewHostImpl* old_render_view_host = render_view_host_;
+  render_view_host_ = pending_render_view_host_;
+  pending_render_view_host_ = NULL;
+  render_view_host_->AttachToFrameTree();
+
+  // The process will no longer try to exit, so we can decrement the count.
+  render_view_host_->GetProcess()->RemovePendingView();
+
+  // If the view is gone, then this RenderViewHost died while it was hidden.
+  // We ignored the RenderProcessGone call at the time, so we should send it now
+  // to make sure the sad tab shows up, etc.
+  if (!render_view_host_->GetView())
+    delegate_->RenderProcessGoneFromRenderManager(render_view_host_);
+  else if (!delegate_->IsHidden())
+    render_view_host_->GetView()->Show();
+
+  // Hide the old view now that the new one is visible.
+  if (old_render_view_host->GetView()) {
+    old_render_view_host->GetView()->Hide();
+    old_render_view_host->WasSwappedOut();
+  }
+
+  // Make sure the size is up to date.  (Fix for bug 1079768.)
+  delegate_->UpdateRenderViewSizeForRenderManager();
+
+  if (will_focus_location_bar)
+    delegate_->SetFocusToLocationBar(false);
+  else if (focus_render_view && render_view_host_->GetView())
+    RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus();
+
+  // Notify that we've swapped RenderViewHosts. We do this
+  // before shutting down the RVH so that we can clean up
+  // RendererResources related to the RVH first.
+  delegate_->NotifySwappedFromRenderManager(old_render_view_host,
+                                            render_view_host_);
+
+  // If the pending view was on the swapped out list, we can remove it.
+  swapped_out_hosts_.erase(render_view_host_->GetSiteInstance()->GetId());
+
+  // If there are no active RVHs in this SiteInstance, it means that
+  // this RVH was the last active one in the SiteInstance. Now that we
+  // know that all RVHs are swapped out, we can delete all the RVHs in
+  // this SiteInstance.
+  if (!static_cast<SiteInstanceImpl*>(old_render_view_host->GetSiteInstance())->
+          active_view_count()) {
+    ShutdownRenderViewHostsInSiteInstance(
+        old_render_view_host->GetSiteInstance()->GetId());
+    // This is deleted while cleaning up the SitaInstance's views.
+    old_render_view_host = NULL;
+  } else if (old_render_view_host->IsRenderViewLive()) {
+    // If the old RVH is live, we are swapping it out and should keep track of
+    // it in case we navigate back to it.
+    DCHECK(old_render_view_host->is_swapped_out());
+    // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
+    // sure we don't get different rvh instances for the same site instance
+    // in the same rvhmgr.
+    // TODO(creis): Clean this up.
+    int32 old_site_instance_id =
+        old_render_view_host->GetSiteInstance()->GetId();
+    RenderViewHostMap::iterator iter =
+        swapped_out_hosts_.find(old_site_instance_id);
+    if (iter != swapped_out_hosts_.end() &&
+        iter->second != old_render_view_host) {
+      // Shutdown the RVH that will be replaced in the map to avoid a leak.
+      iter->second->Shutdown();
+    }
+    swapped_out_hosts_[old_site_instance_id] = old_render_view_host;
+  } else {
+    old_render_view_host->Shutdown();
+    old_render_view_host = NULL;  // Shutdown() deletes it.
+  }
+}
+
+void RenderViewHostManager::ShutdownRenderViewHostsInSiteInstance(
+    int32 site_instance_id) {
+  // First remove any swapped out RVH for this SiteInstance from our
+  // list.
+  swapped_out_hosts_.erase(site_instance_id);
+
+  scoped_ptr<RenderWidgetHostIterator> widgets(
+      RenderWidgetHostImpl::GetAllRenderWidgetHosts());
+  while (RenderWidgetHost* widget = widgets->GetNextHost()) {
+    if (!widget->IsRenderView())
+      continue;
+    RenderViewHostImpl* rvh =
+        static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
+    if (site_instance_id == rvh->GetSiteInstance()->GetId())
+      rvh->Shutdown();
+  }
+}
+
+RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
+    const NavigationEntryImpl& entry) {
+  // If we are cross-navigating, then we want to get back to normal and navigate
+  // as usual.
+  if (cross_navigation_pending_) {
+    if (pending_render_view_host_)
+      CancelPending();
+    cross_navigation_pending_ = false;
+  }
+
+  // render_view_host_ will not be deleted before the end of this method, so we
+  // don't have to worry about this SiteInstance's ref count dropping to zero.
+  SiteInstance* curr_instance = render_view_host_->GetSiteInstance();
+
+  // Determine if we need a new SiteInstance for this entry.
+  // Again, new_instance won't be deleted before the end of this method, so it
+  // is safe to use a normal pointer here.
+  SiteInstance* new_instance = curr_instance;
+  const NavigationEntry* curr_entry =
+      delegate_->GetLastCommittedNavigationEntryForRenderManager();
+  bool is_guest_scheme = curr_instance->GetSiteURL().SchemeIs(kGuestScheme);
+  bool force_swap = ShouldSwapProcessesForNavigation(curr_entry, &entry);
+  if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
+    new_instance = GetSiteInstanceForEntry(entry, curr_instance);
+
+  if (!is_guest_scheme && (new_instance != curr_instance || force_swap)) {
+    // New SiteInstance.
+    DCHECK(!cross_navigation_pending_);
+
+    // This will possibly create (set to NULL) a Web UI object for the pending
+    // page. We'll use this later to give the page special access. This must
+    // happen before the new renderer is created below so it will get bindings.
+    // It must also happen after the above conditional call to CancelPending(),
+    // otherwise CancelPending may clear the pending_web_ui_ and the page will
+    // not have its bindings set appropriately.
+    SetPendingWebUI(entry);
+
+    // Ensure that we have created RVHs for the new RVH's opener chain if
+    // we are staying in the same BrowsingInstance. This allows the pending RVH
+    // to send cross-process script calls to its opener(s).
+    int opener_route_id = MSG_ROUTING_NONE;
+    if (new_instance->IsRelatedSiteInstance(curr_instance)) {
+      opener_route_id =
+          delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
+    }
+
+    // Create a non-swapped-out pending RVH with the given opener and navigate
+    // it.
+    int route_id = CreateRenderView(new_instance, opener_route_id, false,
+                                    delegate_->IsHidden());
+    if (route_id == MSG_ROUTING_NONE)
+      return NULL;
+
+    // Check if our current RVH is live before we set up a transition.
+    if (!render_view_host_->IsRenderViewLive()) {
+      if (!cross_navigation_pending_) {
+        // The current RVH is not live.  There's no reason to sit around with a
+        // sad tab or a newly created RVH while we wait for the pending RVH to
+        // navigate.  Just switch to the pending RVH now and go back to non
+        // cross-navigating (Note that we don't care about on{before}unload
+        // handlers if the current RVH isn't live.)
+        CommitPending();
+        return render_view_host_;
+      } else {
+        NOTREACHED();
+        return render_view_host_;
+      }
+    }
+    // Otherwise, it's safe to treat this as a pending cross-site transition.
+
+    // We need to wait until the beforeunload handler has run, unless we are
+    // transferring an existing request (in which case it has already run).
+    // Suspend the new render view (i.e., don't let it send the cross-site
+    // Navigate message) until we hear back from the old renderer's
+    // beforeunload handler.  If the handler returns false, we'll have to
+    // cancel the request.
+    DCHECK(!pending_render_view_host_->are_navigations_suspended());
+    bool is_transfer =
+        entry.transferred_global_request_id() != GlobalRequestID();
+    if (is_transfer) {
+      // We don't need to stop the old renderer or run beforeunload/unload
+      // handlers, because those have already been done.
+      DCHECK(pending_nav_params_->global_request_id ==
+                entry.transferred_global_request_id());
+    } else {
+      // Also make sure the old render view stops, in case a load is in
+      // progress.  (We don't want to do this for transfers, since it will
+      // interrupt the transfer with an unexpected DidStopLoading.)
+      render_view_host_->Send(
+          new ViewMsg_Stop(render_view_host_->GetRoutingID()));
+
+      pending_render_view_host_->SetNavigationsSuspended(true,
+                                                         base::TimeTicks());
+
+      // Tell the CrossSiteRequestManager that this RVH has a pending cross-site
+      // request, so that ResourceDispatcherHost will know to tell us to run the
+      // old page's unload handler before it sends the response.
+      pending_render_view_host_->SetHasPendingCrossSiteRequest(true);
+    }
+
+    // We now have a pending RVH.
+    DCHECK(!cross_navigation_pending_);
+    cross_navigation_pending_ = true;
+
+    // Unless we are transferring an existing request, we should now
+    // tell the old render view to run its beforeunload handler, since it
+    // doesn't otherwise know that the cross-site request is happening.  This
+    // will trigger a call to ShouldClosePage with the reply.
+    if (!is_transfer)
+      render_view_host_->FirePageBeforeUnload(true);
+
+    return pending_render_view_host_;
+  } else {
+    if (ShouldReuseWebUI(curr_entry, &entry)) {
+      pending_web_ui_.reset();
+      pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
+    } else {
+      SetPendingWebUI(entry);
+
+      // Make sure the new RenderViewHost has the right bindings.
+      if (pending_web_ui() && !render_view_host_->GetProcess()->IsGuest())
+        render_view_host_->AllowBindings(pending_web_ui()->GetBindings());
+    }
+
+    if (pending_web_ui() && render_view_host_->IsRenderViewLive())
+      pending_web_ui()->GetController()->RenderViewReused(render_view_host_);
+
+    // The renderer can exit view source mode when any error or cancellation
+    // happen. We must overwrite to recover the mode.
+    if (entry.IsViewSourceMode()) {
+      render_view_host_->Send(
+          new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID()));
+    }
+  }
+
+  // Same SiteInstance can be used.  Navigate render_view_host_ if we are not
+  // cross navigating.
+  DCHECK(!cross_navigation_pending_);
+  return render_view_host_;
+}
+
+void RenderViewHostManager::CancelPending() {
+  RenderViewHostImpl* pending_render_view_host = pending_render_view_host_;
+  pending_render_view_host_ = NULL;
+
+  RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
+      pending_render_view_host,
+      render_view_host_);
+
+  // We no longer need to prevent the process from exiting.
+  pending_render_view_host->GetProcess()->RemovePendingView();
+
+  // The pending RVH may already be on the swapped out list if we started to
+  // swap it back in and then canceled.  If so, make sure it gets swapped out
+  // again.  If it's not on the swapped out list (e.g., aborting a pending
+  // load), then it's safe to shut down.
+  if (IsOnSwappedOutList(pending_render_view_host)) {
+    // Any currently suspended navigations are no longer needed.
+    pending_render_view_host->CancelSuspendedNavigations();
+
+    pending_render_view_host->SwapOut();
+  } else {
+    // We won't be coming back, so shut this one down.
+    pending_render_view_host->Shutdown();
+  }
+
+  pending_web_ui_.reset();
+  pending_and_current_web_ui_.reset();
+}
+
+void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) {
+  // We are doing this in order to work around and to track a crasher
+  // (http://crbug.com/23411) where it seems that pending_render_view_host_ is
+  // deleted (not sure from where) but not NULLed.
+  if (rvh == pending_render_view_host_) {
+    // If you hit this NOTREACHED, please report it in the following bug
+    // http://crbug.com/23411 Make sure to include what you were doing when it
+    // happened  (navigating to a new page, closing a tab...) and if you can
+    // reproduce.
+    NOTREACHED();
+    pending_render_view_host_ = NULL;
+  }
+
+  // Make sure deleted RVHs are not kept in the swapped out list while we are
+  // still alive.  (If render_view_host_ is null, we're already being deleted.)
+  if (!render_view_host_)
+    return;
+  // We can't look it up by SiteInstance ID, which may no longer be valid.
+  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+       iter != swapped_out_hosts_.end();
+       ++iter) {
+    if (iter->second == rvh) {
+      swapped_out_hosts_.erase(iter);
+      break;
+    }
+  }
+}
+
+bool RenderViewHostManager::IsOnSwappedOutList(RenderViewHost* rvh) const {
+  if (!rvh->GetSiteInstance())
+    return false;
+
+  RenderViewHostMap::const_iterator iter = swapped_out_hosts_.find(
+      rvh->GetSiteInstance()->GetId());
+  if (iter == swapped_out_hosts_.end())
+    return false;
+
+  return iter->second == rvh;
+}
+
+RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost(
+    SiteInstance* instance) {
+  RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId());
+  if (iter != swapped_out_hosts_.end())
+    return iter->second;
+
+  return NULL;
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/render_view_host_manager.h b/content/browser/frame_host/render_view_host_manager.h
new file mode 100644
index 0000000..377758f
--- /dev/null
+++ b/content/browser/frame_host/render_view_host_manager.h
@@ -0,0 +1,397 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_RENDER_VIEW_HOST_MANAGER_H_
+#define CONTENT_BROWSER_FRAME_HOST_RENDER_VIEW_HOST_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/common/referrer.h"
+
+
+namespace content {
+class BrowserContext;
+class InterstitialPageImpl;
+class NavigationControllerImpl;
+class NavigationEntry;
+class NavigationEntryImpl;
+class RenderViewHost;
+class RenderViewHostImpl;
+class RenderViewHostManagerTest;
+class RenderWidgetHostDelegate;
+class RenderWidgetHostView;
+class TestWebContents;
+class WebUIImpl;
+
+// Manages RenderViewHosts for a WebContentsImpl. Normally there is only one and
+// it is easy to do. But we can also have transitions of processes (and hence
+// RenderViewHosts) that can get complex.
+class CONTENT_EXPORT RenderViewHostManager
+    : public RenderViewHostDelegate::RendererManagement,
+      public NotificationObserver {
+ public:
+  // Functions implemented by our owner that we need.
+  //
+  // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl
+  // that are required to run this class. The design should probably be better
+  // such that these are more clear.
+  //
+  // There is additional complexity that some of the functions we need in
+  // WebContentsImpl are inherited and non-virtual. These are named with
+  // "RenderManager" so that the duplicate implementation of them will be clear.
+  class CONTENT_EXPORT Delegate {
+   public:
+    // Initializes the given renderer if necessary and creates the view ID
+    // corresponding to this view host. If this method is not called and the
+    // process is not shared, then the WebContentsImpl will act as though the
+    // renderer is not running (i.e., it will render "sad tab"). This method is
+    // automatically called from LoadURL.
+    //
+    // If you are attaching to an already-existing RenderView, you should call
+    // InitWithExistingID.
+    virtual bool CreateRenderViewForRenderManager(
+        RenderViewHost* render_view_host, int opener_route_id) = 0;
+    virtual void BeforeUnloadFiredFromRenderManager(
+        bool proceed, const base::TimeTicks& proceed_time,
+        bool* proceed_to_fire_unload) = 0;
+    virtual void RenderProcessGoneFromRenderManager(
+        RenderViewHost* render_view_host) = 0;
+    virtual void UpdateRenderViewSizeForRenderManager() = 0;
+    virtual void CancelModalDialogsForRenderManager() = 0;
+    virtual void NotifySwappedFromRenderManager(
+        RenderViewHost* old_host, RenderViewHost* new_host) = 0;
+    virtual NavigationControllerImpl&
+        GetControllerForRenderManager() = 0;
+
+    // Create swapped out RenderViews in the given SiteInstance for each tab in
+    // the opener chain of this tab, if any.  This allows the current tab to
+    // make cross-process script calls to its opener(s).  Returns the route ID
+    // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE).
+    virtual int CreateOpenerRenderViewsForRenderManager(
+        SiteInstance* instance) = 0;
+
+    // Creates a WebUI object for the given URL if one applies. Ownership of the
+    // returned pointer will be passed to the caller. If no WebUI applies,
+    // returns NULL.
+    virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
+
+    // Returns the navigation entry of the current navigation, or NULL if there
+    // is none.
+    virtual NavigationEntry*
+        GetLastCommittedNavigationEntryForRenderManager() = 0;
+
+    // Returns true if the location bar should be focused by default rather than
+    // the page contents. The view calls this function when the tab is focused
+    // to see what it should do.
+    virtual bool FocusLocationBarByDefault() = 0;
+
+    // Focuses the location bar.
+    virtual void SetFocusToLocationBar(bool select_all) = 0;
+
+    // Creates a view and sets the size for the specified RVH.
+    virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
+
+    // Returns true if views created for this delegate should be created in a
+    // hidden state.
+    virtual bool IsHidden() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  // All three delegate pointers must be non-NULL and are not owned by this
+  // class.  They must outlive this class. The RenderViewHostDelegate and
+  // RenderWidgetHostDelegate are what will be installed into all
+  // RenderViewHosts that are created.
+  //
+  // You must call Init() before using this class.
+  RenderViewHostManager(
+      RenderViewHostDelegate* render_view_delegate,
+      RenderWidgetHostDelegate* render_widget_delegate,
+      Delegate* delegate);
+  virtual ~RenderViewHostManager();
+
+  // For arguments, see WebContentsImpl constructor.
+  void Init(BrowserContext* browser_context,
+            SiteInstance* site_instance,
+            int routing_id,
+            int main_frame_routing_id);
+
+  // Returns the currently active RenderViewHost.
+  //
+  // This will be non-NULL between Init() and Shutdown(). You may want to NULL
+  // check it in many cases, however. Windows can send us messages during the
+  // destruction process after it has been shut down.
+  RenderViewHostImpl* current_host() const;
+
+  // Returns the view associated with the current RenderViewHost, or NULL if
+  // there is no current one.
+  RenderWidgetHostView* GetRenderWidgetHostView() const;
+
+  // Returns the pending render view host, or NULL if there is no pending one.
+  RenderViewHostImpl* pending_render_view_host() const;
+
+  // Returns the current committed Web UI or NULL if none applies.
+  WebUIImpl* web_ui() const { return web_ui_.get(); }
+
+  // Returns the Web UI for the pending navigation, or NULL of none applies.
+  WebUIImpl* pending_web_ui() const {
+    return pending_web_ui_.get() ? pending_web_ui_.get() :
+                                   pending_and_current_web_ui_.get();
+  }
+
+  // Sets the pending Web UI for the pending navigation, ensuring that the
+  // bindings are appropriate for the given NavigationEntry.
+  void SetPendingWebUI(const NavigationEntryImpl& entry);
+
+  // Called when we want to instruct the renderer to navigate to the given
+  // navigation entry. It may create a new RenderViewHost or re-use an existing
+  // one. The RenderViewHost to navigate will be returned. Returns NULL if one
+  // could not be created.
+  RenderViewHostImpl* Navigate(const NavigationEntryImpl& entry);
+
+  // Instructs the various live views to stop. Called when the user directed the
+  // page to stop loading.
+  void Stop();
+
+  // Notifies the regular and pending RenderViewHosts that a load is or is not
+  // happening. Even though the message is only for one of them, we don't know
+  // which one so we tell both.
+  void SetIsLoading(bool is_loading);
+
+  // Whether to close the tab or not when there is a hang during an unload
+  // handler. If we are mid-crosssite navigation, then we should proceed
+  // with the navigation instead of closing the tab.
+  bool ShouldCloseTabOnUnresponsiveRenderer();
+
+  // The RenderViewHost has been swapped out, so we should resume the pending
+  // network response and allow the pending RenderViewHost to commit.
+  void SwappedOut(RenderViewHost* render_view_host);
+
+  // Called when a renderer's main frame navigates.
+  void DidNavigateMainFrame(RenderViewHost* render_view_host);
+
+  // Called when a renderer sets its opener to null.
+  void DidDisownOpener(RenderViewHost* render_view_host);
+
+  // Helper method to create a RenderViewHost.  If |swapped_out| is true, it
+  // will be initially placed on the swapped out hosts list.  Otherwise, it
+  // will be used for a pending cross-site navigation.
+  int CreateRenderView(SiteInstance* instance,
+                       int opener_route_id,
+                       bool swapped_out,
+                       bool hidden);
+
+  // Called when a provisional load on the given renderer is aborted.
+  void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host);
+
+  // Sets the passed passed interstitial as the currently showing interstitial.
+  // |interstitial_page| should be non NULL (use the remove_interstitial_page
+  // method to unset the interstitial) and no interstitial page should be set
+  // when there is already a non NULL interstitial page set.
+  void set_interstitial_page(InterstitialPageImpl* interstitial_page) {
+    DCHECK(!interstitial_page_ && interstitial_page);
+    interstitial_page_ = interstitial_page;
+  }
+
+  // Unsets the currently showing interstitial.
+  void remove_interstitial_page() {
+    DCHECK(interstitial_page_);
+    interstitial_page_ = NULL;
+  }
+
+  // Returns the currently showing interstitial, NULL if no interstitial is
+  // showing.
+  InterstitialPageImpl* interstitial_page() const { return interstitial_page_; }
+
+  // RenderViewHostDelegate::RendererManagement implementation.
+  virtual void ShouldClosePage(
+      bool for_cross_site_transition,
+      bool proceed,
+      const base::TimeTicks& proceed_time) OVERRIDE;
+  virtual void OnCrossSiteResponse(
+      RenderViewHost* pending_render_view_host,
+      const GlobalRequestID& global_request_id,
+      bool is_transfer,
+      const std::vector<GURL>& transfer_url_chain,
+      const Referrer& referrer,
+      PageTransition page_transition,
+      int64 frame_id) OVERRIDE;
+
+  // NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  // Called when a RenderViewHost is about to be deleted.
+  void RenderViewDeleted(RenderViewHost* rvh);
+
+  // Returns whether the given RenderViewHost is on the list of swapped out
+  // RenderViewHosts.
+  bool IsOnSwappedOutList(RenderViewHost* rvh) const;
+
+  // Returns the swapped out RenderViewHost for the given SiteInstance, if any.
+  RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance);
+
+  // Runs the unload handler in the current page, when we know that a pending
+  // cross-process navigation is going to commit.  We may initiate a transfer
+  // to a new process after this completes or times out.
+  void SwapOutOldPage();
+
+ private:
+  friend class RenderViewHostManagerTest;
+  friend class TestWebContents;
+
+  // Tracks information about a navigation while a cross-process transition is
+  // in progress, in case we need to transfer it to a new RenderViewHost.
+  struct PendingNavigationParams {
+    PendingNavigationParams();
+    PendingNavigationParams(const GlobalRequestID& global_request_id,
+                            bool is_transfer,
+                            const std::vector<GURL>& transfer_url,
+                            Referrer referrer,
+                            PageTransition page_transition,
+                            int64 frame_id);
+    ~PendingNavigationParams();
+
+    // The child ID and request ID for the pending navigation.  Present whether
+    // |is_transfer| is true or false.
+    GlobalRequestID global_request_id;
+
+    // Whether this pending navigation needs to be transferred to another
+    // process than the one it was going to commit in.  If so, the
+    // |transfer_url|, |referrer|, and |frame_id| parameters will be set.
+    bool is_transfer;
+
+    // If |is_transfer|, this is the URL chain of the request.  The first entry
+    // is the original request URL, and the last entry is the destination URL to
+    // request in the new process.
+    std::vector<GURL> transfer_url_chain;
+
+    // If |is_transfer|, this is the referrer to use for the request in the new
+    // process.
+    Referrer referrer;
+
+    // If |is_transfer|, this is the transition type for the original
+    // navigation.
+    PageTransition page_transition;
+
+    // If |is_transfer|, this is the frame ID to use in RequestTransferURL.
+    int64 frame_id;
+  };
+
+  // Returns whether this tab should transition to a new renderer for
+  // cross-site URLs.  Enabled unless we see the --process-per-tab command line
+  // switch.  Can be overridden in unit tests.
+  bool ShouldTransitionCrossSite();
+
+  // Returns true if the two navigation entries are incompatible in some way
+  // other than site instances. Cases where this can happen include Web UI
+  // to regular web pages. It will cause us to swap RenderViewHosts (and hence
+  // RenderProcessHosts) even if the site instance would otherwise be the same.
+  // As part of this, we'll also force new SiteInstances and BrowsingInstances.
+  // Either of the entries may be NULL.
+  bool ShouldSwapProcessesForNavigation(
+      const NavigationEntry* curr_entry,
+      const NavigationEntryImpl* new_entry) const;
+
+  bool ShouldReuseWebUI(
+      const NavigationEntry* curr_entry,
+      const NavigationEntryImpl* new_entry) const;
+
+  // Returns an appropriate SiteInstance object for the given NavigationEntry,
+  // possibly reusing the current SiteInstance.
+  // Never called if --process-per-tab is used.
+  SiteInstance* GetSiteInstanceForEntry(
+      const NavigationEntryImpl& entry,
+      SiteInstance* curr_instance);
+
+  // Sets up the necessary state for a new RenderViewHost with the given opener.
+  bool InitRenderView(RenderViewHost* render_view_host, int opener_route_id);
+
+  // Sets the pending RenderViewHost/WebUI to be the active one. Note that this
+  // doesn't require the pending render_view_host_ pointer to be non-NULL, since
+  // there could be Web UI switching as well. Call this for every commit.
+  void CommitPending();
+
+  // Shutdown all RenderViewHosts in a SiteInstance. This is called
+  // to shutdown views when all the views in a SiteInstance are
+  // confirmed to be swapped out.
+  void ShutdownRenderViewHostsInSiteInstance(int32 site_instance_id);
+
+  // Helper method to terminate the pending RenderViewHost.
+  void CancelPending();
+
+  RenderViewHostImpl* UpdateRendererStateForNavigate(
+      const NavigationEntryImpl& entry);
+
+  // Called when a renderer process is starting to close.  We should not
+  // schedule new navigations in its swapped out RenderViewHosts after this.
+  void RendererProcessClosing(RenderProcessHost* render_process_host);
+
+  // Our delegate, not owned by us. Guaranteed non-NULL.
+  Delegate* delegate_;
+
+  // Whether a navigation requiring different RenderView's is pending. This is
+  // either cross-site request is (in the new process model), or when required
+  // for the view type (like view source versus not).
+  bool cross_navigation_pending_;
+
+  // Implemented by the owner of this class, these delegates are installed into
+  // all the RenderViewHosts that we create.
+  RenderViewHostDelegate* render_view_delegate_;
+  RenderWidgetHostDelegate* render_widget_delegate_;
+
+  // Our RenderView host and its associated Web UI (if any, will be NULL for
+  // non-DOM-UI pages). This object is responsible for all communication with
+  // a child RenderView instance.
+  RenderViewHostImpl* render_view_host_;
+  scoped_ptr<WebUIImpl> web_ui_;
+
+  // A RenderViewHost used to load a cross-site page. This remains hidden
+  // while a cross-site request is pending until it calls DidNavigate. It may
+  // have an associated Web UI, in which case the Web UI pointer will be non-
+  // NULL.
+  //
+  // The |pending_web_ui_| may be non-NULL even when the
+  // |pending_render_view_host_| is NULL. This will happen when we're
+  // transitioning between two Web UI pages: the RVH won't be swapped, so the
+  // pending pointer will be unused, but there will be a pending Web UI
+  // associated with the navigation.
+  RenderViewHostImpl* pending_render_view_host_;
+
+  // Tracks information about any current pending cross-process navigation.
+  scoped_ptr<PendingNavigationParams> pending_nav_params_;
+
+  // If either of these is non-NULL, the pending navigation is to a chrome:
+  // page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
+  // used for when they reference the same object. If either is non-NULL, the
+  // other should be NULL.
+  scoped_ptr<WebUIImpl> pending_web_ui_;
+  base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
+
+  // A map of site instance ID to swapped out RenderViewHosts.  This may include
+  // pending_render_view_host_ for navigations to existing entries.
+  typedef base::hash_map<int32, RenderViewHostImpl*> RenderViewHostMap;
+  RenderViewHostMap swapped_out_hosts_;
+
+  // The intersitial page currently shown if any, not own by this class
+  // (the InterstitialPage is self-owned, it deletes itself when hidden).
+  InterstitialPageImpl* interstitial_page_;
+
+  NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderViewHostManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_RENDER_VIEW_HOST_MANAGER_H_
diff --git a/content/browser/frame_host/render_view_host_manager_unittest.cc b/content/browser/frame_host/render_view_host_manager_unittest.cc
new file mode 100644
index 0000000..f55de8a
--- /dev/null
+++ b/content/browser/frame_host/render_view_host_manager_unittest.cc
@@ -0,0 +1,1312 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/render_view_host_manager.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/webui/web_ui_controller_factory_registry.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/common/bindings_policy.h"
+#include "content/public/common/javascript_message_type.h"
+#include "content/public/common/page_transition_types.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_notification_tracker.h"
+#include "content/test/test_content_browser_client.h"
+#include "content/test/test_content_client.h"
+#include "content/test/test_web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class RenderViewHostManagerTestWebUIControllerFactory
+    : public WebUIControllerFactory {
+ public:
+  RenderViewHostManagerTestWebUIControllerFactory()
+    : should_create_webui_(false) {
+  }
+  virtual ~RenderViewHostManagerTestWebUIControllerFactory() {}
+
+  void set_should_create_webui(bool should_create_webui) {
+    should_create_webui_ = should_create_webui;
+  }
+
+  // WebUIFactory implementation.
+  virtual WebUIController* CreateWebUIControllerForURL(
+      WebUI* web_ui, const GURL& url) const OVERRIDE {
+    if (!(should_create_webui_ && HasWebUIScheme(url)))
+      return NULL;
+    return new WebUIController(web_ui);
+  }
+
+   virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+      const GURL& url) const OVERRIDE {
+    return WebUI::kNoWebUI;
+  }
+
+  virtual bool UseWebUIForURL(BrowserContext* browser_context,
+                              const GURL& url) const OVERRIDE {
+    return HasWebUIScheme(url);
+  }
+
+  virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+                                      const GURL& url) const OVERRIDE {
+    return HasWebUIScheme(url);
+  }
+
+ private:
+  bool should_create_webui_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderViewHostManagerTestWebUIControllerFactory);
+};
+
+class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
+ public:
+  BeforeUnloadFiredWebContentsDelegate() {}
+  virtual ~BeforeUnloadFiredWebContentsDelegate() {}
+
+  virtual void BeforeUnloadFired(WebContents* web_contents,
+                                 bool proceed,
+                                 bool* proceed_to_fire_unload) OVERRIDE {
+    *proceed_to_fire_unload = proceed;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate);
+};
+
+}  // namespace
+
+class RenderViewHostManagerTest
+    : public RenderViewHostImplTestHarness {
+ public:
+  virtual void SetUp() OVERRIDE {
+    RenderViewHostImplTestHarness::SetUp();
+    WebUIControllerFactory::RegisterFactory(&factory_);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    RenderViewHostImplTestHarness::TearDown();
+    WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
+  }
+
+  void set_should_create_webui(bool should_create_webui) {
+    factory_.set_should_create_webui(should_create_webui);
+  }
+
+  void NavigateActiveAndCommit(const GURL& url) {
+    // Note: we navigate the active RenderViewHost because previous navigations
+    // won't have committed yet, so NavigateAndCommit does the wrong thing
+    // for us.
+    controller().LoadURL(url, Referrer(), PAGE_TRANSITION_LINK, std::string());
+    TestRenderViewHost* old_rvh = test_rvh();
+
+    // Simulate the ShouldClose_ACK that is received from the current renderer
+    // for a cross-site navigation.
+    if (old_rvh != active_rvh())
+      old_rvh->SendShouldCloseACK(true);
+
+    // Commit the navigation with a new page ID.
+    int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
+        active_rvh()->GetSiteInstance());
+
+    // Simulate the SwapOut_ACK that fires if you commit a cross-site
+    // navigation.
+    if (old_rvh != active_rvh())
+      old_rvh->OnSwappedOut(false);
+
+    active_test_rvh()->SendNavigate(max_page_id + 1, url);
+  }
+
+  bool ShouldSwapProcesses(RenderViewHostManager* manager,
+                           const NavigationEntryImpl* cur_entry,
+                           const NavigationEntryImpl* new_entry) const {
+    return manager->ShouldSwapProcessesForNavigation(cur_entry, new_entry);
+  }
+
+  // Creates a test RenderViewHost that's swapped out.
+  TestRenderViewHost* CreateSwappedOutRenderViewHost() {
+    const GURL kChromeURL("chrome://foo");
+    const GURL kDestUrl("http://www.google.com/");
+
+    // Navigate our first tab to a chrome url and then to the destination.
+    NavigateActiveAndCommit(kChromeURL);
+    TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
+        contents()->GetRenderManagerForTesting()->current_host());
+
+    // Navigate to a cross-site URL.
+    contents()->GetController().LoadURL(
+        kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+    EXPECT_TRUE(contents()->cross_navigation_pending());
+
+    // Manually increase the number of active views in the
+    // SiteInstance that ntp_rvh belongs to, to prevent it from being
+    // destroyed when it gets swapped out.
+    static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
+        increment_active_view_count();
+
+    TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
+        contents()->GetRenderManagerForTesting()->pending_render_view_host());
+    CHECK(dest_rvh);
+    EXPECT_NE(ntp_rvh, dest_rvh);
+
+    // BeforeUnload finishes.
+    ntp_rvh->SendShouldCloseACK(true);
+
+    // Assume SwapOutACK times out, so the dest_rvh proceeds and commits.
+    dest_rvh->SendNavigate(101, kDestUrl);
+
+    EXPECT_TRUE(ntp_rvh->is_swapped_out());
+    return ntp_rvh;
+  }
+
+ private:
+  RenderViewHostManagerTestWebUIControllerFactory factory_;
+};
+
+// Tests that when you navigate from a chrome:// url to another page, and
+// then do that same thing in another tab, that the two resulting pages have
+// different SiteInstances, BrowsingInstances, and RenderProcessHosts. This is
+// a regression test for bug 9364.
+TEST_F(RenderViewHostManagerTest, NewTabPageProcesses) {
+  set_should_create_webui(true);
+  const GURL kChromeUrl("chrome://foo");
+  const GURL kDestUrl("http://www.google.com/");
+
+  // Navigate our first tab to the chrome url and then to the destination,
+  // ensuring we grant bindings to the chrome URL.
+  NavigateActiveAndCommit(kChromeUrl);
+  EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+  NavigateActiveAndCommit(kDestUrl);
+
+  // Make a second tab.
+  scoped_ptr<TestWebContents> contents2(
+      TestWebContents::Create(browser_context(), NULL));
+
+  // Load the two URLs in the second tab. Note that the first navigation creates
+  // a RVH that's not pending (since there is no cross-site transition), so
+  // we use the committed one.
+  contents2->GetController().LoadURL(
+      kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  TestRenderViewHost* ntp_rvh2 = static_cast<TestRenderViewHost*>(
+      contents2->GetRenderManagerForTesting()->current_host());
+  EXPECT_FALSE(contents2->cross_navigation_pending());
+  ntp_rvh2->SendNavigate(100, kChromeUrl);
+
+  // The second one is the opposite, creating a cross-site transition and
+  // requiring a beforeunload ack.
+  contents2->GetController().LoadURL(
+      kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  EXPECT_TRUE(contents2->cross_navigation_pending());
+  TestRenderViewHost* dest_rvh2 = static_cast<TestRenderViewHost*>(
+      contents2->GetRenderManagerForTesting()->pending_render_view_host());
+  ASSERT_TRUE(dest_rvh2);
+
+  ntp_rvh2->SendShouldCloseACK(true);
+  ntp_rvh2->OnSwappedOut(false);
+  dest_rvh2->SendNavigate(101, kDestUrl);
+
+  // The two RVH's should be different in every way.
+  EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
+  EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
+  EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
+                   dest_rvh2->GetSiteInstance()));
+
+  // Navigate both to the new tab page, and verify that they share a
+  // RenderProcessHost (not a SiteInstance).
+  NavigateActiveAndCommit(kChromeUrl);
+
+  contents2->GetController().LoadURL(
+      kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  dest_rvh2->SendShouldCloseACK(true);
+  dest_rvh2->OnSwappedOut(false);
+  static_cast<TestRenderViewHost*>(contents2->GetRenderManagerForTesting()->
+     pending_render_view_host())->SendNavigate(102, kChromeUrl);
+
+  EXPECT_NE(active_rvh()->GetSiteInstance(),
+            contents2->GetRenderViewHost()->GetSiteInstance());
+  EXPECT_EQ(active_rvh()->GetSiteInstance()->GetProcess(),
+            contents2->GetRenderViewHost()->GetSiteInstance()->GetProcess());
+}
+
+// Ensure that the browser ignores most IPC messages that arrive from a
+// RenderViewHost that has been swapped out.  We do not want to take
+// action on requests from a non-active renderer.  The main exception is
+// for synchronous messages, which cannot be ignored without leaving the
+// renderer in a stuck state.  See http://crbug.com/93427.
+TEST_F(RenderViewHostManagerTest, FilterMessagesWhileSwappedOut) {
+  const GURL kChromeURL("chrome://foo");
+  const GURL kDestUrl("http://www.google.com/");
+
+  // Navigate our first tab to a chrome url and then to the destination.
+  NavigateActiveAndCommit(kChromeURL);
+  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
+      contents()->GetRenderManagerForTesting()->current_host());
+
+  // Send an update title message and make sure it works.
+  const string16 ntp_title = ASCIIToUTF16("NTP Title");
+  WebKit::WebTextDirection direction = WebKit::WebTextDirectionLeftToRight;
+  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
+      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
+  EXPECT_EQ(ntp_title, contents()->GetTitle());
+
+  // Navigate to a cross-site URL.
+  contents()->GetController().LoadURL(
+      kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  EXPECT_TRUE(contents()->cross_navigation_pending());
+  TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
+      contents()->GetRenderManagerForTesting()->pending_render_view_host());
+  ASSERT_TRUE(dest_rvh);
+  EXPECT_NE(ntp_rvh, dest_rvh);
+
+  // Create one more view in the same SiteInstance where dest_rvh2
+  // exists so that it doesn't get deleted on navigation to another
+  // site.
+  static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
+      increment_active_view_count();
+
+  // BeforeUnload finishes.
+  ntp_rvh->SendShouldCloseACK(true);
+
+  // Assume SwapOutACK times out, so the dest_rvh proceeds and commits.
+  dest_rvh->SendNavigate(101, kDestUrl);
+
+  // The new RVH should be able to update its title.
+  const string16 dest_title = ASCIIToUTF16("Google");
+  EXPECT_TRUE(dest_rvh->OnMessageReceived(
+      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 101, dest_title,
+                              direction)));
+  EXPECT_EQ(dest_title, contents()->GetTitle());
+
+  // The old renderer, being slow, now updates the title. It should be filtered
+  // out and not take effect.
+  EXPECT_TRUE(ntp_rvh->is_swapped_out());
+  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
+      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
+  EXPECT_EQ(dest_title, contents()->GetTitle());
+
+  // We cannot filter out synchronous IPC messages, because the renderer would
+  // be left waiting for a reply.  We pick RunBeforeUnloadConfirm as an example
+  // that can run easily within a unit test, and that needs to receive a reply
+  // without showing an actual dialog.
+  MockRenderProcessHost* ntp_process_host =
+      static_cast<MockRenderProcessHost*>(ntp_rvh->GetProcess());
+  ntp_process_host->sink().ClearMessages();
+  const string16 msg = ASCIIToUTF16("Message");
+  bool result = false;
+  string16 unused;
+  ViewHostMsg_RunBeforeUnloadConfirm before_unload_msg(
+      rvh()->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
+  // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
+  before_unload_msg.EnableMessagePumping();
+  EXPECT_TRUE(ntp_rvh->OnMessageReceived(before_unload_msg));
+  EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
+
+  // Also test RunJavaScriptMessage.
+  ntp_process_host->sink().ClearMessages();
+  ViewHostMsg_RunJavaScriptMessage js_msg(
+      rvh()->GetRoutingID(), msg, msg, kChromeURL,
+      JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
+  js_msg.EnableMessagePumping();
+  EXPECT_TRUE(ntp_rvh->OnMessageReceived(js_msg));
+  EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
+}
+
+TEST_F(RenderViewHostManagerTest, WhiteListSwapCompositorFrame) {
+  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
+  TestRenderWidgetHostView* swapped_out_rwhv =
+      static_cast<TestRenderWidgetHostView*>(swapped_out_rvh->GetView());
+  EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
+
+  MockRenderProcessHost* process_host =
+      static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
+  process_host->sink().ClearMessages();
+
+  cc::CompositorFrame frame;
+  ViewHostMsg_SwapCompositorFrame msg(rvh()->GetRoutingID(), 0, frame);
+
+  EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
+  EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
+}
+
+TEST_F(RenderViewHostManagerTest, WhiteListDidActivateAcceleratedCompositing) {
+  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
+
+  MockRenderProcessHost* process_host =
+      static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
+  process_host->sink().ClearMessages();
+  ViewHostMsg_DidActivateAcceleratedCompositing msg(
+      rvh()->GetRoutingID(), true);
+  EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
+  EXPECT_TRUE(swapped_out_rvh->is_accelerated_compositing_active());
+}
+
+// Test if RenderViewHost::GetRenderWidgetHosts() only returns active
+// widgets.
+TEST_F(RenderViewHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
+  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
+  EXPECT_TRUE(swapped_out_rvh->is_swapped_out());
+
+  scoped_ptr<RenderWidgetHostIterator> widgets(
+      RenderWidgetHost::GetRenderWidgetHosts());
+  // We know that there is the only one active widget. Another view is
+  // now swapped out, so the swapped out view is not included in the
+  // list.
+  RenderWidgetHost* widget = widgets->GetNextHost();
+  EXPECT_FALSE(widgets->GetNextHost());
+  RenderViewHost* rvh = RenderViewHost::From(widget);
+  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(rvh)->is_swapped_out());
+}
+
+// Test if RenderViewHost::GetRenderWidgetHosts() returns a subset of
+// RenderViewHostImpl::GetAllRenderWidgetHosts().
+// RenderViewHost::GetRenderWidgetHosts() returns only active widgets, but
+// RenderViewHostImpl::GetAllRenderWidgetHosts() returns everything
+// including swapped out ones.
+TEST_F(RenderViewHostManagerTest,
+       GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
+  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
+  EXPECT_TRUE(swapped_out_rvh->is_swapped_out());
+
+  scoped_ptr<RenderWidgetHostIterator> widgets(
+      RenderWidgetHost::GetRenderWidgetHosts());
+
+  while (RenderWidgetHost* w = widgets->GetNextHost()) {
+    bool found = false;
+    scoped_ptr<RenderWidgetHostIterator> all_widgets(
+        RenderWidgetHostImpl::GetAllRenderWidgetHosts());
+    while (RenderWidgetHost* widget = all_widgets->GetNextHost()) {
+      if (w == widget) {
+        found = true;
+        break;
+      }
+    }
+    EXPECT_TRUE(found);
+  }
+}
+
+// Test if SiteInstanceImpl::active_view_count() is correctly updated
+// as views in a SiteInstance get swapped out and in.
+TEST_F(RenderViewHostManagerTest, ActiveViewCountWhileSwappingInandOut) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+
+  // Navigate to an initial URL.
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderViewHost* rvh1 = test_rvh();
+
+  SiteInstanceImpl* instance1 =
+      static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance());
+  EXPECT_EQ(instance1->active_view_count(), 1U);
+
+  // Create 2 new tabs and simulate them being the opener chain for the main
+  // tab.  They should be in the same SiteInstance.
+  scoped_ptr<TestWebContents> opener1(
+      TestWebContents::Create(browser_context(), instance1));
+  contents()->SetOpener(opener1.get());
+
+  scoped_ptr<TestWebContents> opener2(
+      TestWebContents::Create(browser_context(), instance1));
+  opener1->SetOpener(opener2.get());
+
+  EXPECT_EQ(instance1->active_view_count(), 3U);
+
+  // Navigate to a cross-site URL (different SiteInstance but same
+  // BrowsingInstance).
+  contents()->NavigateAndCommit(kUrl2);
+  TestRenderViewHost* rvh2 = test_rvh();
+  SiteInstanceImpl* instance2 =
+      static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance());
+
+  // rvh2 is on chromium.org which is different from google.com on
+  // which other tabs are.
+  EXPECT_EQ(instance2->active_view_count(), 1U);
+
+  // There are two active views on google.com now.
+  EXPECT_EQ(instance1->active_view_count(), 2U);
+
+  // Navigate to the original origin (google.com).
+  contents()->NavigateAndCommit(kUrl1);
+
+  EXPECT_EQ(instance1->active_view_count(), 3U);
+}
+
+// This deletes a WebContents when the given RVH is deleted. This is
+// only for testing whether deleting an RVH does not cause any UaF in
+// other parts of the system. For now, this class is only used for the
+// next test cases to detect the bug mentioned at
+// http://crbug.com/259859.
+class RenderViewHostDestroyer : public WebContentsObserver {
+ public:
+  RenderViewHostDestroyer(RenderViewHost* render_view_host,
+                          WebContents* web_contents)
+      : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
+        render_view_host_(render_view_host),
+        web_contents_(web_contents) {}
+
+  virtual void RenderViewDeleted(
+      RenderViewHost* render_view_host) OVERRIDE {
+    if (render_view_host == render_view_host_)
+      delete web_contents_;
+  }
+
+ private:
+  RenderViewHost* render_view_host_;
+  WebContents* web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestroyer);
+};
+
+// Test if ShutdownRenderViewHostsInSiteInstance() does not touch any
+// RenderWidget that has been freed while deleting a RenderViewHost in
+// a previous iteration. This is a regression test for
+// http://crbug.com/259859.
+TEST_F(RenderViewHostManagerTest,
+       DetectUseAfterFreeInShutdownRenderViewHostsInSiteInstance) {
+  const GURL kChromeURL("chrome://newtab");
+  const GURL kUrl1("http://www.google.com");
+  const GURL kUrl2("http://www.chromium.org");
+
+  // Navigate our first tab to a chrome url and then to the destination.
+  NavigateActiveAndCommit(kChromeURL);
+  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
+      contents()->GetRenderManagerForTesting()->current_host());
+
+  // Create one more tab and navigate to kUrl1.  web_contents is not
+  // wrapped as scoped_ptr since it intentionally deleted by destroyer
+  // below as part of this test.
+  TestWebContents* web_contents =
+      TestWebContents::Create(browser_context(), ntp_rvh->GetSiteInstance());
+  web_contents->NavigateAndCommit(kUrl1);
+  RenderViewHostDestroyer destroyer(ntp_rvh, web_contents);
+
+  // This causes the first tab to navigate to kUrl2, which destroys
+  // the ntp_rvh in ShutdownRenderViewHostsInSiteInstance(). When
+  // ntp_rvh is destroyed, it also destroys the RVHs in web_contents
+  // too. This can test whether
+  // SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
+  // touch any object freed in this way or not while iterating through
+  // all widgets.
+  contents()->NavigateAndCommit(kUrl2);
+}
+
+// When there is an error with the specified page, renderer exits view-source
+// mode. See WebFrameImpl::DidFail(). We check by this test that
+// EnableViewSourceMode message is sent on every navigation regardless
+// RenderView is being newly created or reused.
+TEST_F(RenderViewHostManagerTest, AlwaysSendEnableViewSourceMode) {
+  const GURL kChromeUrl("chrome://foo");
+  const GURL kUrl("view-source:http://foo");
+
+  // We have to navigate to some page at first since without this, the first
+  // navigation will reuse the SiteInstance created by Init(), and the second
+  // one will create a new SiteInstance. Because current_instance and
+  // new_instance will be different, a new RenderViewHost will be created for
+  // the second navigation. We have to avoid this in order to exercise the
+  // target code patch.
+  NavigateActiveAndCommit(kChromeUrl);
+
+  // Navigate.
+  controller().LoadURL(
+      kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  // Simulate response from RenderView for FirePageBeforeUnload.
+  base::TimeTicks now = base::TimeTicks::Now();
+  test_rvh()->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(
+      rvh()->GetRoutingID(), true, now, now));
+  ASSERT_TRUE(pending_rvh());  // New pending RenderViewHost will be created.
+  RenderViewHost* last_rvh = pending_rvh();
+  int32 new_id = contents()->GetMaxPageIDForSiteInstance(
+      active_rvh()->GetSiteInstance()) + 1;
+  pending_test_rvh()->SendNavigate(new_id, kUrl);
+  EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
+  ASSERT_TRUE(controller().GetLastCommittedEntry());
+  EXPECT_TRUE(kUrl == controller().GetLastCommittedEntry()->GetURL());
+  EXPECT_FALSE(controller().GetPendingEntry());
+  // Because we're using TestWebContents and TestRenderViewHost in this
+  // unittest, no one calls WebContentsImpl::RenderViewCreated(). So, we see no
+  // EnableViewSourceMode message, here.
+
+  // Clear queued messages before load.
+  process()->sink().ClearMessages();
+  // Navigate, again.
+  controller().LoadURL(
+      kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+  // The same RenderViewHost should be reused.
+  EXPECT_FALSE(pending_rvh());
+  EXPECT_TRUE(last_rvh == rvh());
+  test_rvh()->SendNavigate(new_id, kUrl);  // The same page_id returned.
+  EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
+  EXPECT_FALSE(controller().GetPendingEntry());
+  // New message should be sent out to make sure to enter view-source mode.
+  EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
+      ViewMsg_EnableViewSourceMode::ID));
+}
+
+// Tests the Init function by checking the initial RenderViewHost.
+TEST_F(RenderViewHostManagerTest, Init) {
+  // Using TestBrowserContext.
+  SiteInstanceImpl* instance =
+      static_cast<SiteInstanceImpl*>(SiteInstance::Create(browser_context()));
+  EXPECT_FALSE(instance->HasSite());
+
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+
+  RenderViewHost* host = manager.current_host();
+  ASSERT_TRUE(host);
+  EXPECT_EQ(instance, host->GetSiteInstance());
+  EXPECT_EQ(web_contents.get(), host->GetDelegate());
+  EXPECT_TRUE(manager.GetRenderWidgetHostView());
+  EXPECT_FALSE(manager.pending_render_view_host());
+}
+
+// Tests the Navigate function. We navigate three sites consecutively and check
+// how the pending/committed RenderViewHost are modified.
+TEST_F(RenderViewHostManagerTest, Navigate) {
+  TestNotificationTracker notifications;
+
+  SiteInstance* instance = SiteInstance::Create(browser_context());
+
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+                          Source<WebContents>(web_contents.get()));
+
+  // Create.
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+
+  RenderViewHost* host;
+
+  // 1) The first navigation. --------------------------
+  const GURL kUrl1("http://www.google.com/");
+  NavigationEntryImpl entry1(
+      NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
+      string16() /* title */, PAGE_TRANSITION_TYPED,
+      false /* is_renderer_init */);
+  host = manager.Navigate(entry1);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_TRUE(host == manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+  // Commit to SiteInstance should be delayed until RenderView commit.
+  EXPECT_TRUE(host == manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
+
+  // 2) Navigate to next site. -------------------------
+  const GURL kUrl2("http://www.google.com/foo");
+  NavigationEntryImpl entry2(
+      NULL /* instance */, -1 /* page_id */, kUrl2,
+      Referrer(kUrl1, WebKit::WebReferrerPolicyDefault),
+      string16() /* title */, PAGE_TRANSITION_LINK,
+      true /* is_renderer_init */);
+  host = manager.Navigate(entry2);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_TRUE(host == manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+  EXPECT_TRUE(host == manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+
+  // 3) Cross-site navigate to next site. --------------
+  const GURL kUrl3("http://webkit.org/");
+  NavigationEntryImpl entry3(
+      NULL /* instance */, -1 /* page_id */, kUrl3,
+      Referrer(kUrl2, WebKit::WebReferrerPolicyDefault),
+      string16() /* title */, PAGE_TRANSITION_LINK,
+      false /* is_renderer_init */);
+  host = manager.Navigate(entry3);
+
+  // A new RenderViewHost should be created.
+  EXPECT_TRUE(manager.pending_render_view_host());
+  ASSERT_EQ(host, manager.pending_render_view_host());
+
+  notifications.Reset();
+
+  // Commit.
+  manager.DidNavigateMainFrame(manager.pending_render_view_host());
+  EXPECT_TRUE(host == manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+  // Check the pending RenderViewHost has been committed.
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // We should observe a notification.
+  EXPECT_TRUE(
+      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+}
+
+// Tests the Navigate function. In this unit test we verify that the Navigate
+// function can handle a new navigation event before the previous navigation
+// has been committed. This is also a regression test for
+// http://crbug.com/104600.
+TEST_F(RenderViewHostManagerTest, NavigateWithEarlyReNavigation) {
+  TestNotificationTracker notifications;
+
+  SiteInstance* instance = SiteInstance::Create(browser_context());
+
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+                          Source<WebContents>(web_contents.get()));
+
+  // Create.
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+
+  // 1) The first navigation. --------------------------
+  const GURL kUrl1("http://www.google.com/");
+  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
+                             Referrer(), string16() /* title */,
+                             PAGE_TRANSITION_TYPED,
+                             false /* is_renderer_init */);
+  RenderViewHost* host = manager.Navigate(entry1);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_TRUE(host == manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // We should observe a notification.
+  EXPECT_TRUE(
+      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+  notifications.Reset();
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+
+  // Commit to SiteInstance should be delayed until RenderView commit.
+  EXPECT_TRUE(host == manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
+
+  // 2) Cross-site navigate to next site. -------------------------
+  const GURL kUrl2("http://www.example.com");
+  NavigationEntryImpl entry2(
+      NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
+      string16() /* title */, PAGE_TRANSITION_TYPED,
+      false /* is_renderer_init */);
+  RenderViewHostImpl* host2 = static_cast<RenderViewHostImpl*>(
+      manager.Navigate(entry2));
+  int host2_process_id = host2->GetProcess()->GetID();
+
+  // A new RenderViewHost should be created.
+  EXPECT_TRUE(manager.pending_render_view_host());
+  ASSERT_EQ(host2, manager.pending_render_view_host());
+  EXPECT_NE(host2, host);
+
+  // Check that the navigation is still suspended because the old RVH
+  // is not swapped out, yet.
+  EXPECT_TRUE(host2->are_navigations_suspended());
+  MockRenderProcessHost* test_process_host2 =
+      static_cast<MockRenderProcessHost*>(host2->GetProcess());
+  test_process_host2->sink().ClearMessages();
+  host2->NavigateToURL(kUrl2);
+  EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
+      ViewMsg_Navigate::ID));
+
+  // Allow closing the current Render View (precondition for swapping out
+  // the RVH): Simulate response from RenderView for ViewMsg_ShouldClose sent by
+  // FirePageBeforeUnload.
+  TestRenderViewHost* test_host = static_cast<TestRenderViewHost*>(host);
+  MockRenderProcessHost* test_process_host =
+      static_cast<MockRenderProcessHost*>(test_host->GetProcess());
+  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+      ViewMsg_ShouldClose::ID));
+  test_host->SendShouldCloseACK(true);
+
+  // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
+  // call of RenderViewHostManager::SwapOutOldPage before
+  // RenderViewHostManager::DidNavigateMainFrame is called.
+  // The RVH is not swapped out until the commit.
+  manager.SwapOutOldPage();
+  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+      ViewMsg_SwapOut::ID));
+  test_host->OnSwappedOut(false);
+
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
+      manager.current_host())->is_swapped_out());
+  EXPECT_EQ(host2, manager.pending_render_view_host());
+  // There should be still no navigation messages being sent.
+  EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
+      ViewMsg_Navigate::ID));
+
+  // 3) Cross-site navigate to next site before 2) has committed. --------------
+  const GURL kUrl3("http://webkit.org/");
+  NavigationEntryImpl entry3(NULL /* instance */, -1 /* page_id */, kUrl3,
+                             Referrer(), string16() /* title */,
+                             PAGE_TRANSITION_TYPED,
+                             false /* is_renderer_init */);
+  test_process_host->sink().ClearMessages();
+  RenderViewHost* host3 = manager.Navigate(entry3);
+
+  // A new RenderViewHost should be created. host2 is now deleted.
+  EXPECT_TRUE(manager.pending_render_view_host());
+  ASSERT_EQ(host3, manager.pending_render_view_host());
+  EXPECT_NE(host3, host);
+  EXPECT_NE(host3->GetProcess()->GetID(), host2_process_id);
+
+  // Navigations in the new RVH should be suspended, which is ok because the
+  // old RVH is not yet swapped out and can respond to a second beforeunload
+  // request.
+  EXPECT_TRUE(static_cast<RenderViewHostImpl*>(
+      host3)->are_navigations_suspended());
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
+      manager.current_host())->is_swapped_out());
+
+  // Simulate a response to the second beforeunload request.
+  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+      ViewMsg_ShouldClose::ID));
+  test_host->SendShouldCloseACK(true);
+
+  // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
+  // call of RenderViewHostManager::SwapOutOldPage before
+  // RenderViewHostManager::DidNavigateMainFrame is called.
+  // The RVH is not swapped out until the commit.
+  manager.SwapOutOldPage();
+  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
+      ViewMsg_SwapOut::ID));
+  test_host->OnSwappedOut(false);
+
+  // Commit.
+  manager.DidNavigateMainFrame(host3);
+  EXPECT_TRUE(host3 == manager.current_host());
+  ASSERT_TRUE(host3);
+  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host3->GetSiteInstance())->
+      HasSite());
+  // Check the pending RenderViewHost has been committed.
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // We should observe a notification.
+  EXPECT_TRUE(
+      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+}
+
+// Tests WebUI creation.
+TEST_F(RenderViewHostManagerTest, WebUI) {
+  set_should_create_webui(true);
+  SiteInstance* instance = SiteInstance::Create(browser_context());
+
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+  EXPECT_FALSE(manager.current_host()->IsRenderViewLive());
+
+  const GURL kUrl("chrome://foo");
+  NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
+                            Referrer(), string16() /* title */,
+                            PAGE_TRANSITION_TYPED,
+                            false /* is_renderer_init */);
+  RenderViewHost* host = manager.Navigate(entry);
+
+  // We commit the pending RenderViewHost immediately because the previous
+  // RenderViewHost was not live.  We test a case where it is live in
+  // WebUIInNewTab.
+  EXPECT_TRUE(host);
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // It's important that the site instance get set on the Web UI page as soon
+  // as the navigation starts, rather than lazily after it commits, so we don't
+  // try to re-use the SiteInstance/process for non Web UI things that may
+  // get loaded in between.
+  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+  EXPECT_EQ(kUrl, host->GetSiteInstance()->GetSiteURL());
+
+  // The Web UI is committed immediately because the RenderViewHost has not been
+  // used yet. UpdateRendererStateForNavigate() took the short cut path.
+  EXPECT_FALSE(manager.pending_web_ui());
+  EXPECT_TRUE(manager.web_ui());
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+  EXPECT_TRUE(host->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+}
+
+// Tests that we can open a WebUI link in a new tab from a WebUI page and still
+// grant the correct bindings.  http://crbug.com/189101.
+TEST_F(RenderViewHostManagerTest, WebUIInNewTab) {
+  set_should_create_webui(true);
+  SiteInstance* blank_instance = SiteInstance::Create(browser_context());
+
+  // Create a blank tab.
+  scoped_ptr<TestWebContents> web_contents1(
+      TestWebContents::Create(browser_context(), blank_instance));
+  RenderViewHostManager manager1(web_contents1.get(), web_contents1.get(),
+                                 web_contents1.get());
+  manager1.Init(
+      browser_context(), blank_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+  // Test the case that new RVH is considered live.
+  manager1.current_host()->CreateRenderView(string16(), -1, -1);
+
+  // Navigate to a WebUI page.
+  const GURL kUrl1("chrome://foo");
+  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
+                             Referrer(), string16() /* title */,
+                             PAGE_TRANSITION_TYPED,
+                             false /* is_renderer_init */);
+  RenderViewHost* host1 = manager1.Navigate(entry1);
+
+  // We should have a pending navigation to the WebUI RenderViewHost.
+  // It should already have bindings.
+  EXPECT_EQ(host1, manager1.pending_render_view_host());
+  EXPECT_NE(host1, manager1.current_host());
+  EXPECT_TRUE(host1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+
+  // Commit and ensure we still have bindings.
+  manager1.DidNavigateMainFrame(host1);
+  SiteInstance* webui_instance = host1->GetSiteInstance();
+  EXPECT_EQ(host1, manager1.current_host());
+  EXPECT_TRUE(host1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+
+  // Now simulate clicking a link that opens in a new tab.
+  scoped_ptr<TestWebContents> web_contents2(
+      TestWebContents::Create(browser_context(), webui_instance));
+  RenderViewHostManager manager2(web_contents2.get(), web_contents2.get(),
+                                 web_contents2.get());
+  manager2.Init(
+      browser_context(), webui_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+  // Make sure the new RVH is considered live.  This is usually done in
+  // RenderWidgetHost::Init when opening a new tab from a link.
+  manager2.current_host()->CreateRenderView(string16(), -1, -1);
+
+  const GURL kUrl2("chrome://foo/bar");
+  NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
+                             Referrer(), string16() /* title */,
+                             PAGE_TRANSITION_LINK,
+                             true /* is_renderer_init */);
+  RenderViewHost* host2 = manager2.Navigate(entry2);
+
+  // No cross-process transition happens because we are already in the right
+  // SiteInstance.  We should grant bindings immediately.
+  EXPECT_EQ(host2, manager2.current_host());
+  EXPECT_TRUE(host2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+
+  manager2.DidNavigateMainFrame(host2);
+}
+
+// Tests that we don't end up in an inconsistent state if a page does a back and
+// then reload. http://crbug.com/51680
+TEST_F(RenderViewHostManagerTest, PageDoesBackAndReload) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.evil-site.com/");
+
+  // Navigate to a safe site, then an evil site.
+  // This will switch RenderViewHosts.  We cannot assert that the first and
+  // second RVHs are different, though, because the first one may be promptly
+  // deleted.
+  contents()->NavigateAndCommit(kUrl1);
+  contents()->NavigateAndCommit(kUrl2);
+  RenderViewHost* evil_rvh = contents()->GetRenderViewHost();
+
+  // Now let's simulate the evil page calling history.back().
+  contents()->OnGoToEntryAtOffset(-1);
+  // We should have a new pending RVH.
+  // Note that in this case, the navigation has not committed, so evil_rvh will
+  // not be deleted yet.
+  EXPECT_NE(evil_rvh, contents()->GetRenderManagerForTesting()->
+      pending_render_view_host());
+
+  // Before that RVH has committed, the evil page reloads itself.
+  ViewHostMsg_FrameNavigate_Params params;
+  params.page_id = 1;
+  params.url = kUrl2;
+  params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
+  params.should_update_history = false;
+  params.gesture = NavigationGestureAuto;
+  params.was_within_same_page = false;
+  params.is_post = false;
+  params.page_state = PageState::CreateFromURL(kUrl2);
+  contents()->DidNavigate(evil_rvh, params);
+
+  // That should have cancelled the pending RVH, and the evil RVH should be the
+  // current one.
+  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
+      pending_render_view_host() == NULL);
+  EXPECT_EQ(evil_rvh, contents()->GetRenderManagerForTesting()->current_host());
+
+  // Also we should not have a pending navigation entry.
+  EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
+  NavigationEntry* entry = contents()->GetController().GetVisibleEntry();
+  ASSERT_TRUE(entry != NULL);
+  EXPECT_EQ(kUrl2, entry->GetURL());
+}
+
+// Ensure that we can go back and forward even if a SwapOut ACK isn't received.
+// See http://crbug.com/93427.
+TEST_F(RenderViewHostManagerTest, NavigateAfterMissingSwapOutACK) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+
+  // Navigate to two pages.
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderViewHost* rvh1 = test_rvh();
+
+  // Keep active_view_count nonzero so that no swapped out views in
+  // this SiteInstance get forcefully deleted.
+  static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
+      increment_active_view_count();
+
+  contents()->NavigateAndCommit(kUrl2);
+  TestRenderViewHost* rvh2 = test_rvh();
+  static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
+      increment_active_view_count();
+
+  // Now go back, but suppose the SwapOut_ACK isn't received.  This shouldn't
+  // happen, but we have seen it when going back quickly across many entries
+  // (http://crbug.com/93427).
+  contents()->GetController().GoBack();
+  EXPECT_TRUE(rvh2->is_waiting_for_beforeunload_ack());
+  contents()->ProceedWithCrossSiteNavigation();
+  EXPECT_FALSE(rvh2->is_waiting_for_beforeunload_ack());
+  rvh2->SwapOut();
+  EXPECT_TRUE(rvh2->is_waiting_for_unload_ack());
+
+  // The back navigation commits.  We should proactively clear the
+  // is_waiting_for_unload_ack state to be safe.
+  const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
+  rvh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+  EXPECT_TRUE(rvh2->is_swapped_out());
+  EXPECT_FALSE(rvh2->is_waiting_for_unload_ack());
+
+  // We should be able to navigate forward.
+  contents()->GetController().GoForward();
+  contents()->ProceedWithCrossSiteNavigation();
+  const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
+  rvh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
+  EXPECT_EQ(rvh2, rvh());
+  EXPECT_FALSE(rvh2->is_swapped_out());
+  EXPECT_TRUE(rvh1->is_swapped_out());
+}
+
+// Test that we create swapped out RVHs for the opener chain when navigating an
+// opened tab cross-process.  This allows us to support certain cross-process
+// JavaScript calls (http://crbug.com/99202).
+TEST_F(RenderViewHostManagerTest, CreateSwappedOutOpenerRVHs) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kChromeUrl("chrome://foo");
+
+  // Navigate to an initial URL.
+  contents()->NavigateAndCommit(kUrl1);
+  RenderViewHostManager* manager = contents()->GetRenderManagerForTesting();
+  TestRenderViewHost* rvh1 = test_rvh();
+
+  // Create 2 new tabs and simulate them being the opener chain for the main
+  // tab.  They should be in the same SiteInstance.
+  scoped_ptr<TestWebContents> opener1(
+      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+  RenderViewHostManager* opener1_manager =
+      opener1->GetRenderManagerForTesting();
+  contents()->SetOpener(opener1.get());
+
+  scoped_ptr<TestWebContents> opener2(
+      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+  RenderViewHostManager* opener2_manager =
+      opener2->GetRenderManagerForTesting();
+  opener1->SetOpener(opener2.get());
+
+  // Navigate to a cross-site URL (different SiteInstance but same
+  // BrowsingInstance).
+  contents()->NavigateAndCommit(kUrl2);
+  TestRenderViewHost* rvh2 = test_rvh();
+  EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
+  EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
+                  rvh2->GetSiteInstance()));
+
+  // Ensure rvh1 is placed on swapped out list of the current tab.
+  EXPECT_TRUE(manager->IsOnSwappedOutList(rvh1));
+  EXPECT_EQ(rvh1,
+            manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
+
+  // Ensure a swapped out RVH is created in the first opener tab.
+  TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
+      opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rvh));
+  EXPECT_TRUE(opener1_rvh->is_swapped_out());
+
+  // Ensure a swapped out RVH is created in the second opener tab.
+  TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
+      opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+  EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rvh));
+  EXPECT_TRUE(opener2_rvh->is_swapped_out());
+
+  // Navigate to a cross-BrowsingInstance URL.
+  contents()->NavigateAndCommit(kChromeUrl);
+  TestRenderViewHost* rvh3 = test_rvh();
+  EXPECT_NE(rvh1->GetSiteInstance(), rvh3->GetSiteInstance());
+  EXPECT_FALSE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
+                   rvh3->GetSiteInstance()));
+
+  // No scripting is allowed across BrowsingInstances, so we should not create
+  // swapped out RVHs for the opener chain in this case.
+  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
+                   rvh3->GetSiteInstance()));
+  EXPECT_FALSE(opener2_manager->GetSwappedOutRenderViewHost(
+                   rvh3->GetSiteInstance()));
+}
+
+// Test that we clean up swapped out RenderViewHosts when a process hosting
+// those associated RenderViews crashes. http://crbug.com/258993
+TEST_F(RenderViewHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
+  const GURL kUrl1("http://www.google.com/");
+
+  // Navigate to an initial URL.
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderViewHost* rvh1 = test_rvh();
+
+  // Create a new tab as an opener for the main tab.
+  scoped_ptr<TestWebContents> opener1(
+      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+  RenderViewHostManager* opener1_manager =
+      opener1->GetRenderManagerForTesting();
+  contents()->SetOpener(opener1.get());
+
+  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
+      rvh1->GetSiteInstance()));
+  opener1->CreateSwappedOutRenderView(rvh1->GetSiteInstance());
+  EXPECT_TRUE(opener1_manager->GetSwappedOutRenderViewHost(
+      rvh1->GetSiteInstance()));
+
+  // Fake a process crash.
+  RenderProcessHost::RendererClosedDetails details(
+      rvh1->GetProcess()->GetHandle(),
+      base::TERMINATION_STATUS_PROCESS_CRASHED,
+      0);
+  NotificationService::current()->Notify(
+      NOTIFICATION_RENDERER_PROCESS_CLOSED,
+      Source<RenderProcessHost>(rvh1->GetProcess()),
+      Details<RenderProcessHost::RendererClosedDetails>(&details));
+  rvh1->set_render_view_created(false);
+
+  // Ensure that the swapped out RenderViewHost has been deleted.
+  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
+      rvh1->GetSiteInstance()));
+
+  // Reload the initial tab. This should recreate the opener.
+  contents()->GetController().Reload(true);
+
+  EXPECT_EQ(opener1_manager->current_host()->GetRoutingID(),
+            test_rvh()->opener_route_id());
+}
+
+// Test that RenderViewHosts created for WebUI navigations are properly
+// granted WebUI bindings even if an unprivileged swapped out RenderViewHost
+// is in the same process (http://crbug.com/79918).
+TEST_F(RenderViewHostManagerTest, EnableWebUIWithSwappedOutOpener) {
+  set_should_create_webui(true);
+  const GURL kSettingsUrl("chrome://chrome/settings");
+  const GURL kPluginUrl("chrome://plugins");
+
+  // Navigate to an initial WebUI URL.
+  contents()->NavigateAndCommit(kSettingsUrl);
+
+  // Ensure the RVH has WebUI bindings.
+  TestRenderViewHost* rvh1 = test_rvh();
+  EXPECT_TRUE(rvh1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+
+  // Create a new tab and simulate it being the opener for the main
+  // tab.  It should be in the same SiteInstance.
+  scoped_ptr<TestWebContents> opener1(
+      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+  RenderViewHostManager* opener1_manager =
+      opener1->GetRenderManagerForTesting();
+  contents()->SetOpener(opener1.get());
+
+  // Navigate to a different WebUI URL (different SiteInstance, same
+  // BrowsingInstance).
+  contents()->NavigateAndCommit(kPluginUrl);
+  TestRenderViewHost* rvh2 = test_rvh();
+  EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
+  EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
+                  rvh2->GetSiteInstance()));
+
+  // Ensure a swapped out RVH is created in the first opener tab.
+  TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
+      opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rvh));
+  EXPECT_TRUE(opener1_rvh->is_swapped_out());
+
+  // Ensure the new RVH has WebUI bindings.
+  EXPECT_TRUE(rvh2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+}
+
+// Test that we reuse the same guest SiteInstance if we navigate across sites.
+TEST_F(RenderViewHostManagerTest, NoSwapOnGuestNavigations) {
+  TestNotificationTracker notifications;
+
+  GURL guest_url(std::string(kGuestScheme).append("://abc123"));
+  SiteInstance* instance =
+      SiteInstance::CreateForURL(browser_context(), guest_url);
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+
+  // Create.
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+
+  RenderViewHost* host;
+
+  // 1) The first navigation. --------------------------
+  const GURL kUrl1("http://www.google.com/");
+  NavigationEntryImpl entry1(
+      NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
+      string16() /* title */, PAGE_TRANSITION_TYPED,
+      false /* is_renderer_init */);
+  host = manager.Navigate(entry1);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_TRUE(host == manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+  EXPECT_EQ(manager.current_host()->GetSiteInstance(), instance);
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+  // Commit to SiteInstance should be delayed until RenderView commit.
+  EXPECT_EQ(host, manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+
+  // 2) Navigate to a different domain. -------------------------
+  // Guests stay in the same process on navigation.
+  const GURL kUrl2("http://www.chromium.org");
+  NavigationEntryImpl entry2(
+      NULL /* instance */, -1 /* page_id */, kUrl2,
+      Referrer(kUrl1, WebKit::WebReferrerPolicyDefault),
+      string16() /* title */, PAGE_TRANSITION_LINK,
+      true /* is_renderer_init */);
+  host = manager.Navigate(entry2);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+  EXPECT_EQ(host, manager.current_host());
+  ASSERT_TRUE(host);
+  EXPECT_EQ(static_cast<SiteInstanceImpl*>(host->GetSiteInstance()),
+      instance);
+}
+
+// Test that we cancel a pending RVH if we close the tab while it's pending.
+// http://crbug.com/294697.
+TEST_F(RenderViewHostManagerTest, NavigateWithEarlyClose) {
+  TestNotificationTracker notifications;
+
+  SiteInstance* instance = SiteInstance::Create(browser_context());
+
+  BeforeUnloadFiredWebContentsDelegate delegate;
+  scoped_ptr<TestWebContents> web_contents(
+      TestWebContents::Create(browser_context(), instance));
+  web_contents->SetDelegate(&delegate);
+  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+                          Source<WebContents>(web_contents.get()));
+
+  // Create.
+  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
+                                web_contents.get());
+
+  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+
+  // 1) The first navigation. --------------------------
+  const GURL kUrl1("http://www.google.com/");
+  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
+                             Referrer(), string16() /* title */,
+                             PAGE_TRANSITION_TYPED,
+                             false /* is_renderer_init */);
+  RenderViewHost* host = manager.Navigate(entry1);
+
+  // The RenderViewHost created in Init will be reused.
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(manager.pending_render_view_host());
+
+  // We should observe a notification.
+  EXPECT_TRUE(
+      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
+  notifications.Reset();
+
+  // Commit.
+  manager.DidNavigateMainFrame(host);
+
+  // Commit to SiteInstance should be delayed until RenderView commit.
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
+      HasSite());
+  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
+
+  // 2) Cross-site navigate to next site. -------------------------
+  const GURL kUrl2("http://www.example.com");
+  NavigationEntryImpl entry2(
+      NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
+      string16() /* title */, PAGE_TRANSITION_TYPED,
+      false /* is_renderer_init */);
+  RenderViewHostImpl* host2 = static_cast<RenderViewHostImpl*>(
+      manager.Navigate(entry2));
+
+  // A new RenderViewHost should be created.
+  ASSERT_EQ(host2, manager.pending_render_view_host());
+  EXPECT_NE(host2, host);
+
+  EXPECT_EQ(host, manager.current_host());
+  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
+      manager.current_host())->is_swapped_out());
+  EXPECT_EQ(host2, manager.pending_render_view_host());
+
+  // 3) Close the tab. -------------------------
+  notifications.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
+                          Source<RenderWidgetHost>(host2));
+  manager.ShouldClosePage(false, true, base::TimeTicks());
+
+  EXPECT_TRUE(
+      notifications.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED));
+  EXPECT_FALSE(manager.pending_render_view_host());
+  EXPECT_EQ(host, manager.current_host());
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/web_contents_screenshot_manager.cc b/content/browser/frame_host/web_contents_screenshot_manager.cc
new file mode 100644
index 0000000..97ac533
--- /dev/null
+++ b/content/browser/frame_host/web_contents_screenshot_manager.cc
@@ -0,0 +1,273 @@
+// Copyright 2013 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/web_contents_screenshot_manager.h"
+
+#include "base/command_line.h"
+#include "base/threading/worker_pool.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/common/content_switches.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+// Minimum delay between taking screenshots.
+const int kMinScreenshotIntervalMS = 1000;
+
+}
+
+namespace content {
+
+// Encodes an SkBitmap to PNG data in a worker thread.
+class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
+ public:
+  ScreenshotData() {
+  }
+
+  void EncodeScreenshot(const SkBitmap& bitmap, base::Closure callback) {
+    if (!base::WorkerPool::PostTaskAndReply(FROM_HERE,
+            base::Bind(&ScreenshotData::EncodeOnWorker,
+                       this,
+                       bitmap),
+            callback,
+            true)) {
+      callback.Run();
+    }
+  }
+
+  scoped_refptr<base::RefCountedBytes> data() const { return data_; }
+
+ private:
+  friend class base::RefCountedThreadSafe<ScreenshotData>;
+  virtual ~ScreenshotData() {
+  }
+
+  void EncodeOnWorker(const SkBitmap& bitmap) {
+    std::vector<unsigned char> data;
+    if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data))
+      data_ = new base::RefCountedBytes(data);
+  }
+
+  scoped_refptr<base::RefCountedBytes> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenshotData);
+};
+
+WebContentsScreenshotManager::WebContentsScreenshotManager(
+    NavigationControllerImpl* owner)
+    : owner_(owner),
+      screenshot_factory_(this),
+      min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
+}
+
+WebContentsScreenshotManager::~WebContentsScreenshotManager() {
+}
+
+void WebContentsScreenshotManager::TakeScreenshot() {
+  static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
+      GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
+  if (!overscroll_enabled)
+    return;
+
+  NavigationEntryImpl* entry =
+      NavigationEntryImpl::FromNavigationEntry(owner_->GetLastCommittedEntry());
+  if (!entry)
+    return;
+
+  RenderViewHost* render_view_host =
+      owner_->delegate()->GetRenderViewHost();
+  if (!static_cast<RenderViewHostImpl*>
+      (render_view_host)->overscroll_controller()) {
+    return;
+  }
+  content::RenderWidgetHostView* view = render_view_host->GetView();
+  if (!view)
+    return;
+
+  // Make sure screenshots aren't taken too frequently.
+  base::Time now = base::Time::Now();
+  if (now - last_screenshot_time_ <
+          base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
+    return;
+  }
+
+  last_screenshot_time_ = now;
+
+  TakeScreenshotImpl(render_view_host, entry);
+}
+
+// Implemented here and not in NavigationEntry because this manager keeps track
+// of the total number of screen shots across all entries.
+void WebContentsScreenshotManager::ClearAllScreenshots() {
+  int count = owner_->GetEntryCount();
+  for (int i = 0; i < count; ++i) {
+    ClearScreenshot(NavigationEntryImpl::FromNavigationEntry(
+        owner_->GetEntryAtIndex(i)));
+  }
+  DCHECK_EQ(GetScreenshotCount(), 0);
+}
+
+void WebContentsScreenshotManager::TakeScreenshotImpl(
+    RenderViewHost* host,
+    NavigationEntryImpl* entry) {
+  DCHECK(host && host->GetView());
+  DCHECK(entry);
+  host->CopyFromBackingStore(gfx::Rect(),
+      host->GetView()->GetViewBounds().size(),
+      base::Bind(&WebContentsScreenshotManager::OnScreenshotTaken,
+                 screenshot_factory_.GetWeakPtr(),
+                 entry->GetUniqueID()));
+}
+
+void WebContentsScreenshotManager::SetMinScreenshotIntervalMS(int interval_ms) {
+  DCHECK_GE(interval_ms, 0);
+  min_screenshot_interval_ms_ = interval_ms;
+}
+
+void WebContentsScreenshotManager::OnScreenshotTaken(int unique_id,
+                                                     bool success,
+                                                     const SkBitmap& bitmap) {
+  NavigationEntryImpl* entry = NULL;
+  int entry_count = owner_->GetEntryCount();
+  for (int i = 0; i < entry_count; ++i) {
+    NavigationEntry* iter = owner_->GetEntryAtIndex(i);
+    if (iter->GetUniqueID() == unique_id) {
+      entry = NavigationEntryImpl::FromNavigationEntry(iter);
+      break;
+    }
+  }
+
+  if (!entry) {
+    LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
+    return;
+  }
+
+  if (!success || bitmap.empty() || bitmap.isNull()) {
+    if (!ClearScreenshot(entry))
+      OnScreenshotSet(entry);
+    return;
+  }
+
+  scoped_refptr<ScreenshotData> screenshot = new ScreenshotData();
+  screenshot->EncodeScreenshot(
+      bitmap,
+      base::Bind(&WebContentsScreenshotManager::OnScreenshotEncodeComplete,
+                 screenshot_factory_.GetWeakPtr(),
+                 unique_id,
+                 screenshot));
+}
+
+int WebContentsScreenshotManager::GetScreenshotCount() const {
+  int screenshot_count = 0;
+  int entry_count = owner_->GetEntryCount();
+  for (int i = 0; i < entry_count; ++i) {
+    NavigationEntryImpl* entry =
+        NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(i));
+    if (entry->screenshot().get())
+      screenshot_count++;
+  }
+  return screenshot_count;
+}
+
+void WebContentsScreenshotManager::OnScreenshotEncodeComplete(
+    int unique_id,
+    scoped_refptr<ScreenshotData> screenshot) {
+  NavigationEntryImpl* entry = NULL;
+  int entry_count = owner_->GetEntryCount();
+  for (int i = 0; i < entry_count; ++i) {
+    NavigationEntry* iter = owner_->GetEntryAtIndex(i);
+    if (iter->GetUniqueID() == unique_id) {
+      entry = NavigationEntryImpl::FromNavigationEntry(iter);
+      break;
+    }
+  }
+  if (!entry)
+    return;
+  entry->SetScreenshotPNGData(screenshot->data());
+  OnScreenshotSet(entry);
+}
+
+void WebContentsScreenshotManager::OnScreenshotSet(NavigationEntryImpl* entry) {
+  if (entry->screenshot().get())
+    PurgeScreenshotsIfNecessary();
+}
+
+bool WebContentsScreenshotManager::ClearScreenshot(NavigationEntryImpl* entry) {
+  if (!entry->screenshot().get())
+    return false;
+
+  entry->SetScreenshotPNGData(NULL);
+  return true;
+}
+
+void WebContentsScreenshotManager::PurgeScreenshotsIfNecessary() {
+  // Allow only a certain number of entries to keep screenshots.
+  const int kMaxScreenshots = 10;
+  int screenshot_count = GetScreenshotCount();
+  if (screenshot_count < kMaxScreenshots)
+    return;
+
+  const int current = owner_->GetCurrentEntryIndex();
+  const int num_entries = owner_->GetEntryCount();
+  int available_slots = kMaxScreenshots;
+  if (NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(current))
+          ->screenshot().get()) {
+    --available_slots;
+  }
+
+  // Keep screenshots closer to the current navigation entry, and purge the ones
+  // that are farther away from it. So in each step, look at the entries at
+  // each offset on both the back and forward history, and start counting them
+  // to make sure that the correct number of screenshots are kept in memory.
+  // Note that it is possible for some entries to be missing screenshots (e.g.
+  // when taking the screenshot failed for some reason). So there may be a state
+  // where there are a lot of entries in the back history, but none of them has
+  // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
+  // entries in the forward history list.
+  int back = current - 1;
+  int forward = current + 1;
+  while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
+    if (back >= 0) {
+      NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+          owner_->GetEntryAtIndex(back));
+      if (entry->screenshot().get())
+        --available_slots;
+      --back;
+    }
+
+    if (available_slots > 0 && forward < num_entries) {
+      NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+          owner_->GetEntryAtIndex(forward));
+      if (entry->screenshot().get())
+        --available_slots;
+      ++forward;
+    }
+  }
+
+  // Purge any screenshot at |back| or lower indices, and |forward| or higher
+  // indices.
+  while (screenshot_count > kMaxScreenshots && back >= 0) {
+    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+        owner_->GetEntryAtIndex(back));
+    if (ClearScreenshot(entry))
+      --screenshot_count;
+    --back;
+  }
+
+  while (screenshot_count > kMaxScreenshots && forward < num_entries) {
+    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+        owner_->GetEntryAtIndex(forward));
+    if (ClearScreenshot(entry))
+      --screenshot_count;
+    ++forward;
+  }
+  CHECK_GE(screenshot_count, 0);
+  CHECK_LE(screenshot_count, kMaxScreenshots);
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/web_contents_screenshot_manager.h b/content/browser/frame_host/web_contents_screenshot_manager.h
new file mode 100644
index 0000000..10339a2
--- /dev/null
+++ b/content/browser/frame_host/web_contents_screenshot_manager.h
@@ -0,0 +1,91 @@
+// Copyright 2013 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_BROWSER_FRAME_HOST_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
+#define CONTENT_BROWSER_FRAME_HOST_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+class SkBitmap;
+
+namespace content {
+
+class NavigationControllerImpl;
+class NavigationEntryImpl;
+class RenderViewHost;
+class ScreenshotData;
+
+// WebContentsScreenshotManager takes care of taking image-captures for the
+// current navigation entry of a NavigationControllerImpl, and managing these
+// captured images. These image-captures are used for history navigation using
+// overscroll gestures.
+// TODO(nasko): Rename this to better reflect that it is used for
+// navigation entries and not WebContents.
+class CONTENT_EXPORT WebContentsScreenshotManager {
+ public:
+  explicit WebContentsScreenshotManager(NavigationControllerImpl* controller);
+  virtual ~WebContentsScreenshotManager();
+
+  // Takes a screenshot of the last-committed entry of the controller.
+  void TakeScreenshot();
+
+  // Clears screenshots of all navigation entries.
+  void ClearAllScreenshots();
+
+ protected:
+  virtual void TakeScreenshotImpl(RenderViewHost* host,
+                                  NavigationEntryImpl* entry);
+
+  // Called after a screenshot has been set on an NavigationEntryImpl.
+  // Overridden in tests to get notified of when a screenshot is set.
+  virtual void OnScreenshotSet(NavigationEntryImpl* entry);
+
+  NavigationControllerImpl* owner() { return owner_; }
+
+  void SetMinScreenshotIntervalMS(int interval_ms);
+
+  // The callback invoked when taking the screenshot of the page is complete.
+  // This sets the screenshot on the navigation entry.
+  void OnScreenshotTaken(int unique_id,
+                         bool success,
+                         const SkBitmap& bitmap);
+
+  // Returns the number of entries with screenshots.
+  int GetScreenshotCount() const;
+
+ private:
+  // This is called when the screenshot data has beene encoded to PNG in a
+  // worker thread.
+  void OnScreenshotEncodeComplete(int unique_id,
+                                  scoped_refptr<ScreenshotData> data);
+
+  // Removes the screenshot for the entry, returning true if the entry had a
+  // screenshot.
+  bool ClearScreenshot(NavigationEntryImpl* entry);
+
+  // The screenshots in the NavigationEntryImpls can accumulate and consume a
+  // large amount of memory. This function makes sure that the memory
+  // consumption is within a certain limit.
+  void PurgeScreenshotsIfNecessary();
+
+  // The navigation controller that owns this screenshot-manager.
+  NavigationControllerImpl* owner_;
+
+  // Taking a screenshot and encoding them can be async. So use a weakptr for
+  // the callback to make sure that the screenshot/encoding completion callback
+  // does not trigger on a destroyed WebContentsScreenshotManager.
+  base::WeakPtrFactory<WebContentsScreenshotManager> screenshot_factory_;
+
+  base::Time last_screenshot_time_;
+  int min_screenshot_interval_ms_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsScreenshotManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc
index 41f3cea..2e269b3 100644
--- a/content/browser/geolocation/network_location_request.cc
+++ b/content/browser/geolocation/network_location_request.cc
@@ -60,8 +60,8 @@
 
 void RecordUmaAccessPoints(int count) {
   const int min = 0;
-  const int max = 10;
-  const int buckets = 11;
+  const int max = 20;
+  const int buckets = 21;
   UMA_HISTOGRAM_CUSTOM_COUNTS("Geolocation.NetworkLocationRequest.AccessPoints",
       count, min, max, buckets);
 }
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 7bc6fca..9474999 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -5,12 +5,14 @@
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
 
 #include "base/bind.h"
+#include "base/debug/trace_event.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/gpu/gpu_surface_tracker.h"
-#include "content/common/gpu/gpu_messages.h"
 #include "content/common/child_process_host_impl.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/common/gpu/gpu_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_client.h"
 #include "ipc/ipc_forwarding_message_filter.h"
@@ -20,7 +22,7 @@
 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
 
 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
-    : event(false, false),
+    : event(true, false),
       gpu_host_id(0),
       route_id(MSG_ROUTING_NONE) {
 }
@@ -29,32 +31,137 @@
 }
 
 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
-    CauseForGpuLaunch cause)
-    : event(false, false),
-      cause_for_gpu_launch(cause),
-      gpu_host_id(0),
-      reused_gpu_process(true) {
+    CauseForGpuLaunch cause,
+    int gpu_client_id,
+    int gpu_host_id)
+    : event_(false, false),
+      cause_for_gpu_launch_(cause),
+      gpu_client_id_(gpu_client_id),
+      gpu_host_id_(gpu_host_id),
+      reused_gpu_process_(false),
+      finished_(false),
+      main_loop_(base::MessageLoopProxy::current()) {
+  scoped_refptr<base::MessageLoopProxy> loop =
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+  loop->PostTask(
+      FROM_HERE,
+      base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
+                 this));
 }
 
 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
 }
 
-void BrowserGpuChannelHostFactory::Initialize() {
-  instance_ = new BrowserGpuChannelHostFactory();
+void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
+  GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+  if (!host) {
+    host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+                               cause_for_gpu_launch_);
+    if (!host) {
+      FinishOnIO();
+      return;
+    }
+    gpu_host_id_ = host->host_id();
+    reused_gpu_process_ = false;
+  } else {
+    if (reused_gpu_process_) {
+      // We come here if we retried to establish the channel because of a
+      // failure in ChannelEstablishedOnIO, but we ended up with the same
+      // process ID, meaning the failure was not because of a channel error,
+      // but another reason. So fail now.
+      FinishOnIO();
+      return;
+    }
+    reused_gpu_process_ = true;
+  }
+
+  host->EstablishGpuChannel(
+      gpu_client_id_,
+      true,
+      base::Bind(
+          &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
+          this));
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
+    const IPC::ChannelHandle& channel_handle,
+    const gpu::GPUInfo& gpu_info) {
+  if (channel_handle.name.empty() && reused_gpu_process_) {
+    // We failed after re-using the GPU process, but it may have died in the
+    // mean time. Retry to have a chance to create a fresh GPU process.
+    EstablishOnIO();
+  } else {
+    channel_handle_ = channel_handle;
+    gpu_info_ = gpu_info;
+    FinishOnIO();
+  }
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
+  event_.Signal();
+  main_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
+                 this));
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
+  if (!finished_) {
+    BrowserGpuChannelHostFactory* factory =
+        BrowserGpuChannelHostFactory::instance();
+    factory->GpuChannelEstablished();
+    finished_ = true;
+  }
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
+  DCHECK(main_loop_->BelongsToCurrentThread());
+  {
+    // We're blocking the UI thread, which is generally undesirable.
+    // In this case we need to wait for this before we can show any UI
+    // /anyway/, so it won't cause additional jank.
+    // TODO(piman): Make this asynchronous (http://crbug.com/125248).
+    TRACE_EVENT0("browser",
+                 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
+    base::ThreadRestrictions::ScopedAllowWait allow_wait;
+    event_.Wait();
+  }
+  FinishOnMain();
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
+  DCHECK(main_loop_->BelongsToCurrentThread());
+  finished_ = true;
+}
+
+void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
+  DCHECK(!instance_);
+  instance_ = new BrowserGpuChannelHostFactory(establish_gpu_channel);
 }
 
 void BrowserGpuChannelHostFactory::Terminate() {
+  DCHECK(instance_);
   delete instance_;
   instance_ = NULL;
 }
 
-BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
+BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory(
+    bool establish_gpu_channel)
     : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
       shutdown_event_(new base::WaitableEvent(true, false)),
       gpu_host_id_(0) {
+  if (establish_gpu_channel) {
+    pending_request_ = new EstablishRequest(
+        CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP, gpu_client_id_, gpu_host_id_);
+  }
 }
 
 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
+  DCHECK(IsMainThread());
+  if (pending_request_)
+    pending_request_->Cancel();
+  for (size_t n = 0; n < established_callbacks_.size(); n++)
+    established_callbacks_[n].Run();
   shutdown_event_->Signal();
 }
 
@@ -126,6 +233,8 @@
   // In this case we need to wait for this before we can show any UI /anyway/,
   // so it won't cause additional jank.
   // TODO(piman): Make this asynchronous (http://crbug.com/125248).
+  TRACE_EVENT0("browser",
+               "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
   base::ThreadRestrictions::ScopedAllowWait allow_wait;
   request.event.Wait();
   return request.route_id;
@@ -197,93 +306,88 @@
         sync_point));
 }
 
-void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
-    EstablishRequest* request) {
-  GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
-  if (!host) {
-    host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
-                               request->cause_for_gpu_launch);
-    if (!host) {
-      request->event.Signal();
-      return;
-    }
-    gpu_host_id_ = host->host_id();
-    request->reused_gpu_process = false;
-  } else {
-    if (host->host_id() == request->gpu_host_id) {
-      // We come here if we retried to establish the channel because of a
-      // failure in GpuChannelEstablishedOnIO, but we ended up with the same
-      // process ID, meaning the failure was not because of a channel error, but
-      // another reason. So fail now.
-      request->event.Signal();
-      return;
-    }
-    request->reused_gpu_process = true;
-  }
-  request->gpu_host_id = gpu_host_id_;
-
-  host->EstablishGpuChannel(
-      gpu_client_id_,
-      true,
-      base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO,
-                 base::Unretained(this),
-                 request));
-}
-
-void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO(
-    EstablishRequest* request,
-    const IPC::ChannelHandle& channel_handle,
-    const gpu::GPUInfo& gpu_info) {
-  if (channel_handle.name.empty() && request->reused_gpu_process) {
-    // We failed after re-using the GPU process, but it may have died in the
-    // mean time. Retry to have a chance to create a fresh GPU process.
-    EstablishGpuChannelOnIO(request);
-  } else {
-    request->channel_handle = channel_handle;
-    request->gpu_info = gpu_info;
-    request->event.Signal();
-  }
-}
-
 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
     CauseForGpuLaunch cause_for_gpu_launch) {
-  if (gpu_channel_.get()) {
-    // Recreate the channel if it has been lost.
-    if (gpu_channel_->IsLost())
-      gpu_channel_ = NULL;
-    else
-      return gpu_channel_.get();
-  }
-  // Ensure initialization on the main thread.
-  GpuDataManagerImpl::GetInstance();
+  EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
 
-  EstablishRequest request(cause_for_gpu_launch);
-  GetIOLoopProxy()->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO,
-          base::Unretained(this),
-          &request));
+  if (pending_request_)
+    pending_request_->Wait();
 
-  {
-    // We're blocking the UI thread, which is generally undesirable.
-    // In this case we need to wait for this before we can show any UI /anyway/,
-    // so it won't cause additional jank.
-    // TODO(piman): Make this asynchronous (http://crbug.com/125248).
-    base::ThreadRestrictions::ScopedAllowWait allow_wait;
-    request.event.Wait();
-  }
-
-  if (request.channel_handle.name.empty())
-    return NULL;
-
-  GetContentClient()->SetGpuInfo(request.gpu_info);
-  gpu_channel_ = GpuChannelHost::Create(
-      this, request.gpu_host_id, gpu_client_id_,
-      request.gpu_info, request.channel_handle);
   return gpu_channel_.get();
 }
 
+void BrowserGpuChannelHostFactory::EstablishGpuChannel(
+    CauseForGpuLaunch cause_for_gpu_launch,
+    const base::Closure& callback) {
+  if (gpu_channel_.get() && gpu_channel_->IsLost()) {
+    DCHECK(!pending_request_);
+    // Recreate the channel if it has been lost.
+    gpu_channel_ = NULL;
+  }
+
+  if (!gpu_channel_ && !pending_request_) {
+    // We should only get here if the context was lost.
+    pending_request_ = new EstablishRequest(
+        cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
+  }
+
+  if (!callback.is_null()) {
+    if (gpu_channel_)
+      callback.Run();
+    else
+      established_callbacks_.push_back(callback);
+  }
+}
+
+GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
+  if (gpu_channel_ && !gpu_channel_->IsLost())
+    return gpu_channel_;
+
+  return NULL;
+}
+
+void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
+  DCHECK(IsMainThread());
+  DCHECK(pending_request_);
+  if (pending_request_->channel_handle().name.empty())
+    return;
+
+  GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
+  gpu_channel_ = GpuChannelHost::Create(this,
+                                        pending_request_->gpu_host_id(),
+                                        gpu_client_id_,
+                                        pending_request_->gpu_info(),
+                                        pending_request_->channel_handle());
+  gpu_host_id_ = pending_request_->gpu_host_id();
+  pending_request_ = NULL;
+
+  for (size_t n = 0; n < established_callbacks_.size(); n++)
+    established_callbacks_[n].Run();
+
+  established_callbacks_.clear();
+}
+
+scoped_ptr<gfx::GpuMemoryBuffer>
+    BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(
+        size_t width,
+        size_t height,
+        unsigned internalformat) {
+  if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  size_t size = width * height *
+      GpuMemoryBufferImpl::BytesPerPixel(internalformat);
+  scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
+  if (!shm->CreateAnonymous(size))
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+      new GpuMemoryBufferImpl(shm.Pass(),
+                              width,
+                              height,
+                              internalformat));
+}
+
 // static
 void BrowserGpuChannelHostFactory::AddFilterOnIO(
     int host_id,
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.h b/content/browser/gpu/browser_gpu_channel_host_factory.h
index ca31183..6f09e14 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
 #define CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
 
+#include <vector>
+
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/process/process.h"
@@ -17,7 +19,7 @@
 class CONTENT_EXPORT BrowserGpuChannelHostFactory
     : public GpuChannelHostFactory {
  public:
-  static void Initialize();
+  static void Initialize(bool establish_gpu_channel);
   static void Terminate();
   static BrowserGpuChannelHostFactory* instance() { return instance_; }
 
@@ -36,8 +38,10 @@
       int32 image_id,
       const CreateImageCallback& callback) OVERRIDE;
   virtual void DeleteImage(int32 image_idu, int32 sync_point) OVERRIDE;
-  virtual GpuChannelHost* EstablishGpuChannelSync(
-      CauseForGpuLaunch cause_for_gpu_launch) OVERRIDE;
+  virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat) OVERRIDE;
 
   // Specify a task runner and callback to be used for a set of messages. The
   // callback will be set up on the current GpuProcessHost, identified by
@@ -48,6 +52,11 @@
       const base::Callback<void(const IPC::Message&)>& handler,
       base::TaskRunner* target_task_runner);
   int GpuProcessHostId() { return gpu_host_id_; }
+  GpuChannelHost* EstablishGpuChannelSync(
+      CauseForGpuLaunch cause_for_gpu_launch);
+  void EstablishGpuChannel(CauseForGpuLaunch cause_for_gpu_launch,
+                           const base::Closure& callback);
+  GpuChannelHost* GetGpuChannel();
 
  private:
   struct CreateRequest {
@@ -58,20 +67,42 @@
     int32 route_id;
   };
 
-  struct EstablishRequest {
-    explicit EstablishRequest(CauseForGpuLaunch);
+  class EstablishRequest : public base::RefCountedThreadSafe<EstablishRequest> {
+   public:
+    explicit EstablishRequest(CauseForGpuLaunch cause,
+                              int gpu_client_id,
+                              int gpu_host_id);
+    void Wait();
+    void Cancel();
+
+    int gpu_host_id() { return gpu_host_id_; }
+    IPC::ChannelHandle& channel_handle() { return channel_handle_; }
+    gpu::GPUInfo gpu_info() { return gpu_info_; }
+
+   private:
+    friend class base::RefCountedThreadSafe<EstablishRequest>;
     ~EstablishRequest();
-    base::WaitableEvent event;
-    CauseForGpuLaunch cause_for_gpu_launch;
-    int gpu_host_id;
-    bool reused_gpu_process;
-    IPC::ChannelHandle channel_handle;
-    gpu::GPUInfo gpu_info;
+    void EstablishOnIO();
+    void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
+                           const gpu::GPUInfo& gpu_info);
+    void FinishOnIO();
+    void FinishOnMain();
+
+    base::WaitableEvent event_;
+    CauseForGpuLaunch cause_for_gpu_launch_;
+    int gpu_client_id_;
+    int gpu_host_id_;
+    bool reused_gpu_process_;
+    IPC::ChannelHandle channel_handle_;
+    gpu::GPUInfo gpu_info_;
+    bool finished_;
+    scoped_refptr<base::MessageLoopProxy> main_loop_;
   };
 
-  BrowserGpuChannelHostFactory();
+  explicit BrowserGpuChannelHostFactory(bool establish_gpu_channel);
   virtual ~BrowserGpuChannelHostFactory();
 
+  void GpuChannelEstablished();
   void CreateViewCommandBufferOnIO(
       CreateRequest* request,
       int32 surface_id,
@@ -86,11 +117,6 @@
   static void OnImageCreated(
       const CreateImageCallback& callback, const gfx::Size size);
   void DeleteImageOnIO(int32 image_id, int32 sync_point);
-  void EstablishGpuChannelOnIO(EstablishRequest* request);
-  void GpuChannelEstablishedOnIO(
-      EstablishRequest* request,
-      const IPC::ChannelHandle& channel_handle,
-      const gpu::GPUInfo& gpu_info);
   static void AddFilterOnIO(
       int gpu_host_id,
       scoped_refptr<IPC::ChannelProxy::MessageFilter> filter);
@@ -99,6 +125,8 @@
   scoped_ptr<base::WaitableEvent> shutdown_event_;
   scoped_refptr<GpuChannelHost> gpu_channel_;
   int gpu_host_id_;
+  scoped_refptr<EstablishRequest> pending_request_;
+  std::vector<base::Closure> established_callbacks_;
 
   static BrowserGpuChannelHostFactory* instance_;
 
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 263d9b5..d440cb9 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -5,20 +5,13 @@
 #include "content/browser/gpu/compositor_util.h"
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial.h"
+#include "base/logging.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/config/gpu_feature_type.h"
 
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#elif defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 namespace content {
 
 namespace {
@@ -186,7 +179,7 @@
 bool CanDoAcceleratedCompositing() {
   const GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
 
-  // Don't run the field trial if gpu access has been blocked or
+  // Don't use force compositing mode if gpu access has been blocked or
   // accelerated compositing is blacklisted.
   if (!manager->GpuAccessAllowed(NULL) ||
       manager->IsFeatureBlacklisted(
@@ -219,7 +212,7 @@
 
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
 
-  // Command line switches take precedence over blacklist and field trials.
+  // Command line switches take precedence over blacklist.
   if (command_line.HasSwitch(switches::kDisableForceCompositingMode) ||
       command_line.HasSwitch(switches::kDisableThreadedCompositing)) {
     return false;
@@ -230,10 +223,14 @@
   if (!CanDoAcceleratedCompositing() || IsForceCompositingModeBlacklisted())
     return false;
 
-  base::FieldTrial* trial =
-      base::FieldTrialList::Find(kGpuCompositingFieldTrialName);
-  return trial &&
-         trial->group_name() == kGpuCompositingFieldTrialThreadEnabledName;
+#if defined(OS_MACOSX) || defined(OS_WIN)
+  // Windows Vista+ has been shipping with TCM enabled at 100% since M24 and
+  // Mac OSX 10.8+ since M28. The blacklist check above takes care of returning
+  // false before this hits on unsupported Win/Mac versions.
+  return true;
+#endif
+
+  return false;
 }
 
 bool IsForceCompositingModeEnabled() {
@@ -243,7 +240,7 @@
 
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
 
-  // Command line switches take precedence over blacklisting and field trials.
+  // Command line switches take precedence over blacklisting.
   if (command_line.HasSwitch(switches::kDisableForceCompositingMode))
     return false;
   else if (command_line.HasSwitch(switches::kForceCompositingMode))
@@ -252,9 +249,8 @@
   if (!CanDoAcceleratedCompositing() || IsForceCompositingModeBlacklisted())
     return false;
 
-// TODO(gab): Do the same thing for TCM above once this is stable.
 #if defined(OS_MACOSX) || defined(OS_WIN)
-  // Windows Vista+ has been shipping with FCM enabled at 100% since M24 and
+  // Windows Vista+ has been shipping with TCM enabled at 100% since M24 and
   // Mac OSX 10.8+ since M28. The blacklist check above takes care of returning
   // false before this hits on unsupported Win/Mac versions.
   return true;
@@ -267,9 +263,8 @@
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   bool enabled = false;
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
-  // Enable on non-ChromeOS Aura. Chrome OS has driver issues on some platforms:
-  // https://code.google.com/p/chrome-os-partner/issues/detail?id=22688
+#if defined(USE_AURA)
+  // Enable on Aura.
   enabled = true;
 #endif
 
diff --git a/content/browser/gpu/compositor_util_browsertest.cc b/content/browser/gpu/compositor_util_browsertest.cc
index 2921bae..3bb8eea 100644
--- a/content/browser/gpu/compositor_util_browsertest.cc
+++ b/content/browser/gpu/compositor_util_browsertest.cc
@@ -25,19 +25,15 @@
     DELEGATED,  // Implies threaded
   } expected_mode = DISABLED;
 #if defined(USE_AURA)
-#if defined(OS_CHROMEOS)
-  expected_mode = THREADED;
-#else
   expected_mode = DELEGATED;
-#endif
 #elif defined(OS_ANDROID)
   expected_mode = THREADED;
 #elif defined(OS_MACOSX)
   if (base::mac::IsOSMountainLionOrLater())
-    expected_mode = ENABLED;
+    expected_mode = THREADED;
 #elif defined(OS_WIN)
   if (base::win::GetVersion() >= base::win::VERSION_VISTA)
-    expected_mode = ENABLED;
+    expected_mode = THREADED;
 #endif
 
   EXPECT_EQ(expected_mode == ENABLED ||
diff --git a/content/browser/gpu/gpu_crash_browsertest.cc b/content/browser/gpu/gpu_crash_browsertest.cc
deleted file mode 100644
index 98650d3..0000000
--- a/content/browser/gpu/gpu_crash_browsertest.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2012 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/path_service.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/browser/gpu/gpu_process_host_ui_shim.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/common/content_paths.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "content/shell/browser/shell.h"
-#include "content/test/content_browser_test.h"
-#include "content/test/content_browser_test_utils.h"
-
-namespace content {
-class GpuCrashTest : public ContentBrowserTest {
- protected:
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    base::FilePath test_dir;
-    ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir));
-    gpu_test_dir_ = test_dir.AppendASCII("gpu");
-  }
-  base::FilePath gpu_test_dir_;
-};
-
-#if defined(OS_LINUX) && !defined(NDEBUG)
-// http://crbug.com/254724
-#define IF_NOT_DEBUG_LINUX(x) DISABLED_ ## x
-#else
-#define IF_NOT_DEBUG_LINUX(x) x
-#endif
-
-IN_PROC_BROWSER_TEST_F(GpuCrashTest, IF_NOT_DEBUG_LINUX(MANUAL_Kill)) {
-  DOMMessageQueue message_queue;
-
-  content::GpuDataManagerImpl::GetInstance()->
-      DisableDomainBlockingFor3DAPIsForTesting();
-
-  // Load page and wait for it to load.
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::NotificationService::AllSources());
-  NavigateToURL(
-      shell(),
-      GetFileUrlWithQuery(
-          gpu_test_dir_.AppendASCII("webgl.html"), "query=kill"));
-  observer.Wait();
-
-  GpuProcessHostUIShim* host =
-      GpuProcessHostUIShim::GetOneInstance();
-  ASSERT_TRUE(host);
-  host->SimulateCrash();
-
-  std::string m;
-  ASSERT_TRUE(message_queue.WaitForMessage(&m));
-  EXPECT_EQ("\"SUCCESS\"", m);
-}
-
-IN_PROC_BROWSER_TEST_F(GpuCrashTest,
-                       IF_NOT_DEBUG_LINUX(MANUAL_WebkitLoseContext)) {
-  DOMMessageQueue message_queue;
-
-  NavigateToURL(
-      shell(),
-      GetFileUrlWithQuery(
-          gpu_test_dir_.AppendASCII("webgl.html"),
-          "query=WEBGL_lose_context"));
-
-  std::string m;
-  ASSERT_TRUE(message_queue.WaitForMessage(&m));
-  EXPECT_EQ("\"SUCCESS\"", m);
-}
-
-} // namespace content
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index ceef233..f59dae1 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -685,7 +685,6 @@
   }
   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING)) {
     command_line->AppendSwitch(switches::kDisableImageTransportSurface);
-    reduce_sandbox = true;
   }
   if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
     command_line->AppendSwitch(switches::kDisableD3D11);
@@ -1006,7 +1005,7 @@
   if (command_line->HasSwitch(switches::kEnableSoftwareCompositing))
     use_software_compositor_ = true;
   //TODO(jbauman): enable for Chrome OS and Linux
-#if defined(USE_AURA) && defined(OS_WIN)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
   use_software_compositor_ = true;
 #endif
   if (command_line->HasSwitch(switches::kGpuSwitching)) {
diff --git a/content/browser/gpu/gpu_info_browsertest.cc b/content/browser/gpu/gpu_info_browsertest.cc
deleted file mode 100644
index d555d1d..0000000
--- a/content/browser/gpu/gpu_info_browsertest.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2013 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/command_line.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/public/browser/gpu_data_manager_observer.h"
-#include "content/public/common/content_switches.h"
-#include "content/test/content_browser_test.h"
-
-namespace content {
-
-namespace {
-
-class TestObserver : public GpuDataManagerObserver {
- public:
-  explicit TestObserver(base::MessageLoop* message_loop)
-      : message_loop_(message_loop) {
-  }
-
-  virtual ~TestObserver() { }
-
-  virtual void OnGpuInfoUpdate() OVERRIDE {
-    // Display GPU/Driver information.
-    gpu::GPUInfo gpu_info =
-        GpuDataManagerImpl::GetInstance()->GetGPUInfo();
-    std::string vendor_id = base::StringPrintf(
-        "0x%04x", gpu_info.gpu.vendor_id);
-    std::string device_id = base::StringPrintf(
-        "0x%04x", gpu_info.gpu.device_id);
-    LOG(INFO) << "GPU[0]: vendor_id = " << vendor_id
-              << ", device_id = " << device_id;
-    for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
-      gpu::GPUInfo::GPUDevice gpu = gpu_info.secondary_gpus[i];
-      vendor_id = base::StringPrintf("0x%04x", gpu.vendor_id);
-      device_id = base::StringPrintf("0x%04x", gpu.device_id);
-      LOG(INFO) << "GPU[" << (i + 1)
-                << "]: vendor_id = " << vendor_id
-                << ", device_od = " << device_id;
-    }
-    LOG(INFO) << "GPU Driver: vendor = " << gpu_info.driver_vendor
-              << ", version = " << gpu_info.driver_version
-              << ", date = " << gpu_info.driver_date;
-
-    // Display GL information.
-    LOG(INFO) << "GL: vendor = " << gpu_info.gl_vendor
-              << ", renderer = " << gpu_info.gl_renderer;
-
-    // Display GL window system binding information.
-    LOG(INFO) << "GL Window System: vendor = " << gpu_info.gl_ws_vendor
-              << ", version = " << gpu_info.gl_ws_version;
-
-    // Display OS information.
-    LOG(INFO) << "OS = " << base::SysInfo::OperatingSystemName()
-              << " " << base::SysInfo::OperatingSystemVersion();
-
-    message_loop_->Quit();
-  }
-
- private:
-  base::MessageLoop* message_loop_;
-};
-
-}  // namespace anonymous
-
-class GpuInfoBrowserTest : public ContentBrowserTest {
- public:
-  GpuInfoBrowserTest()
-      : message_loop_(base::MessageLoop::TYPE_UI) {
-  }
-
-  virtual void SetUp() {
-    // We expect real pixel output for these tests.
-    UseRealGLContexts();
-
-    ContentBrowserTest::SetUp();
-  }
-
-  base::MessageLoop* GetMessageLoop() { return &message_loop_; }
-
- private:
-  base::MessageLoop message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuInfoBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(GpuInfoBrowserTest, MANUAL_DisplayGpuInfo) {
-  // crbug.com/262287
-#if defined(OS_MACOSX)
-  // TODO(zmo): crashing on Mac, and also we don't have the full info
-  // collected.
-  return;
-#endif
-#if defined(OS_LINUX) && !defined(NDEBUG)
-  // TODO(zmo): crashing on Linux Debug.
-  return;
-#endif
-  TestObserver observer(GetMessageLoop());
-  GpuDataManagerImpl::GetInstance()->AddObserver(&observer);
-  GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
-
-  GetMessageLoop()->Run();
-}
-
-}  // namespace content
-
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 0f838cd..f066fe6 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -3,8 +3,13 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/run_loop.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "content/test/content_browser_test.h"
 #include "ui/gl/gl_switches.h"
@@ -17,10 +22,19 @@
 class ContextTestBase : public content::ContentBrowserTest {
  public:
   virtual void SetUpOnMainThread() OVERRIDE {
-    CHECK(content::BrowserGpuChannelHostFactory::instance());
+    if (!content::BrowserGpuChannelHostFactory::instance())
+      content::BrowserGpuChannelHostFactory::Initialize(true);
+
+    content::BrowserGpuChannelHostFactory* factory =
+        content::BrowserGpuChannelHostFactory::instance();
+    CHECK(factory);
+    scoped_refptr<content::GpuChannelHost> gpu_channel_host(
+        factory->EstablishGpuChannelSync(
+            content::
+                CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
     context_.reset(
         WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-            content::BrowserGpuChannelHostFactory::instance(),
+            gpu_channel_host.get(),
             WebKit::WebGraphicsContext3D::Attributes(),
             GURL()));
     CHECK(context_.get());
@@ -42,6 +56,133 @@
 
 }  // namespace
 
-// Include the actual tests.
+// Include the shared tests.
 #define CONTEXT_TEST_F IN_PROC_BROWSER_TEST_F
 #include "content/common/gpu/client/gpu_context_tests.h"
+
+namespace content {
+
+class BrowserGpuChannelHostFactoryTest : public ContextTestBase {
+ public:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    // Start all tests without a gpu channel so that the tests exercise a
+    // consistent codepath.
+    if (!content::BrowserGpuChannelHostFactory::instance())
+      content::BrowserGpuChannelHostFactory::Initialize(false);
+
+    CHECK(GetFactory());
+
+    ContentBrowserTest::SetUpOnMainThread();
+  }
+
+  virtual void TearDownOnMainThread() OVERRIDE {
+    ContextTestBase::TearDownOnMainThread();
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    // Start all tests without a gpu channel so that the tests exercise a
+    // consistent codepath.
+    command_line->AppendSwitch(switches::kDisableGpuProcessPrelaunch);
+  }
+
+  void OnContextLost(const base::Closure callback, int* counter) {
+    (*counter)++;
+    callback.Run();
+  }
+
+ protected:
+  BrowserGpuChannelHostFactory* GetFactory() {
+    return BrowserGpuChannelHostFactory::instance();
+  }
+
+  bool IsChannelEstablished() {
+    return GetFactory()->GetGpuChannel() != NULL;
+  }
+
+  void EstablishAndWait() {
+    base::RunLoop run_loop;
+    GetFactory()->EstablishGpuChannel(
+        CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  GpuChannelHost* GetGpuChannel() {
+    return GetFactory()->GetGpuChannel();
+  }
+
+  static void Signal(bool *event) {
+    CHECK_EQ(*event, false);
+    *event = true;
+  }
+
+  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext() {
+    return make_scoped_ptr(
+        WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
+            GetGpuChannel(),
+            WebKit::WebGraphicsContext3D::Attributes(),
+            GURL()));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, Basic) {
+  DCHECK(!IsChannelEstablished());
+  EstablishAndWait();
+  EXPECT_TRUE(GetGpuChannel() != NULL);
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
+                       EstablishAndTerminate) {
+  DCHECK(!IsChannelEstablished());
+  base::RunLoop run_loop;
+  GetFactory()->EstablishGpuChannel(
+      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+      run_loop.QuitClosure());
+  GetFactory()->Terminate();
+
+  // The callback should still trigger.
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, AlreadyEstablished) {
+  DCHECK(!IsChannelEstablished());
+  scoped_refptr<GpuChannelHost> gpu_channel =
+      GetFactory()->EstablishGpuChannelSync(
+          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
+
+  // Expect established callback immediately.
+  bool event = false;
+  GetFactory()->EstablishGpuChannel(
+      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+      base::Bind(&BrowserGpuChannelHostFactoryTest::Signal, &event));
+  EXPECT_TRUE(event);
+  EXPECT_EQ(gpu_channel, GetGpuChannel());
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, CrashAndRecover) {
+  DCHECK(!IsChannelEstablished());
+  EstablishAndWait();
+  scoped_refptr<GpuChannelHost> host = GetGpuChannel();
+
+  scoped_refptr<ContextProviderCommandBuffer> provider =
+      ContextProviderCommandBuffer::Create(CreateContext(),
+                                           "BrowserGpuChannelHostFactoryTest");
+  base::RunLoop run_loop;
+  int counter = 0;
+  provider->SetLostContextCallback(
+      base::Bind(&BrowserGpuChannelHostFactoryTest::OnContextLost,
+                 base::Unretained(this), run_loop.QuitClosure(), &counter));
+  EXPECT_TRUE(provider->BindToCurrentThread());
+  GpuProcessHostUIShim* shim =
+      GpuProcessHostUIShim::FromID(GetFactory()->GpuProcessHostId());
+  EXPECT_TRUE(shim != NULL);
+  shim->SimulateCrash();
+  run_loop.Run();
+
+  EXPECT_EQ(1, counter);
+  EXPECT_FALSE(IsChannelEstablished());
+  EstablishAndWait();
+  EXPECT_TRUE(IsChannelEstablished());
+}
+
+}  // namespace content
diff --git a/content/browser/gpu/gpu_memory_test.cc b/content/browser/gpu/gpu_memory_test.cc
deleted file mode 100644
index 7f9a3fe..0000000
--- a/content/browser/gpu/gpu_memory_test.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2012 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/callback.h"
-#include "base/command_line.h"
-#include "base/path_service.h"
-#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/browser/gpu_data_manager_observer.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_paths.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "content/shell/browser/shell.h"
-#include "content/test/content_browser_test.h"
-#include "content/test/content_browser_test_utils.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
-#include "gpu/config/gpu_test_config.h"
-#include "net/base/net_util.h"
-
-namespace content {
-
-// Run the tests with a memory limit of 256MB, and give
-// and extra 4MB of wiggle-room for over-allocation.
-const char* kMemoryLimitMBSwitch = "256";
-const size_t kMemoryLimitMB = 256;
-const size_t kSingleTabLimitMB = 128;
-const size_t kWiggleRoomMB = 4;
-
-// Observer to report GPU memory usage when requested.
-class GpuMemoryBytesAllocatedObserver : public GpuDataManagerObserver {
- public:
-  GpuMemoryBytesAllocatedObserver()
-      : bytes_allocated_(0) {
-  }
-
-  virtual ~GpuMemoryBytesAllocatedObserver() {
-  }
-
-  virtual void OnVideoMemoryUsageStatsUpdate(
-      const GPUVideoMemoryUsageStats& video_memory_usage_stats) OVERRIDE {
-    bytes_allocated_ = video_memory_usage_stats.bytes_allocated;
-    message_loop_runner_->Quit();
-  }
-
-  size_t GetBytesAllocated() {
-    message_loop_runner_ = new MessageLoopRunner;
-    GpuDataManager::GetInstance()->AddObserver(this);
-    GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
-    message_loop_runner_->Run();
-    GpuDataManager::GetInstance()->RemoveObserver(this);
-    message_loop_runner_ = NULL;
-    return bytes_allocated_;
-  }
-
- private:
-  size_t bytes_allocated_;
-  scoped_refptr<MessageLoopRunner> message_loop_runner_;
-};
-
-class GpuMemoryTest : public ContentBrowserTest {
- public:
-  GpuMemoryTest()
-      : allow_tests_to_run_(false),
-        has_used_first_shell_(false) {
-  }
-  virtual ~GpuMemoryTest() {
-  }
-
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    base::FilePath test_dir;
-    ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir));
-    gpu_test_dir_ = test_dir.AppendASCII("gpu");
-  }
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    command_line->AppendSwitch(switches::kEnableLogging);
-    command_line->AppendSwitchASCII(switches::kForceGpuMemAvailableMb,
-                                    kMemoryLimitMBSwitch);
-    // Only run this on GPU bots for now. These tests should work with
-    // any GPU process, but may be slow.
-    if (command_line->HasSwitch(switches::kUseGpuInTests)) {
-      allow_tests_to_run_ = true;
-    }
-    // Don't enable these tests on Android just yet (they use lots of memory and
-    // may not be stable).
-#if defined(OS_ANDROID)
-    allow_tests_to_run_ = false;
-#endif
-  }
-
-  enum PageType {
-    PAGE_CSS3D,
-    PAGE_WEBGL,
-  };
-
-  // Load a page and consume a specified amount of GPU memory.
-  void LoadPage(Shell* tab_to_load,
-                PageType page_type,
-                size_t mb_to_use) {
-    base::FilePath url;
-    switch (page_type) {
-      case PAGE_CSS3D:
-        url = gpu_test_dir_.AppendASCII("mem_css3d.html");
-        break;
-      case PAGE_WEBGL:
-        url = gpu_test_dir_.AppendASCII("mem_webgl.html");
-        break;
-    }
-
-    NavigateToURL(tab_to_load, net::FilePathToFileURL(url));
-    std::ostringstream js_call;
-    js_call << "useGpuMemory(";
-    js_call << mb_to_use;
-    js_call << ");";
-    std::string message;
-    ASSERT_TRUE(ExecuteScriptInFrameAndExtractString(
-        tab_to_load->web_contents(), std::string(), js_call.str(), &message));
-    EXPECT_EQ("DONE_USE_GPU_MEMORY", message);
-  }
-
-  // Create a new tab.
-  Shell* CreateNewTab() {
-    // The ContentBrowserTest will create one shell by default, use that one
-    // first so that we don't confuse the memory manager into thinking there
-    // are more windows than there are.
-    Shell* new_tab = has_used_first_shell_ ? CreateBrowser() : shell();
-    has_used_first_shell_ = true;
-    tabs_.insert(new_tab);
-    visible_tabs_.insert(new_tab);
-    return new_tab;
-  }
-
-  void SetTabBackgrounded(Shell* tab_to_background) {
-    ASSERT_TRUE(
-        visible_tabs_.find(tab_to_background) != visible_tabs_.end());
-    visible_tabs_.erase(tab_to_background);
-    tab_to_background->web_contents()->WasHidden();
-  }
-
-  bool MemoryUsageInRange(size_t low, size_t high) {
-    FinishGpuMemoryChanges();
-    size_t memory_usage_bytes = GetMemoryUsageMbytes();
-
-    // If it's not immediately the case that low <= usage <= high, then
-    // allow
-    // Because we haven't implemented the full delay in FinishGpuMemoryChanges,
-    // keep re-reading the GPU memory usage for 2 seconds before declaring
-    // failure.
-    base::Time start_time = base::Time::Now();
-    while (low > memory_usage_bytes || memory_usage_bytes > high) {
-      memory_usage_bytes = GetMemoryUsageMbytes();
-      base::TimeDelta delta = base::Time::Now() - start_time;
-      if (delta.InMilliseconds() >= 2000)
-        break;
-    }
-
-    return (low <= memory_usage_bytes && memory_usage_bytes <= high);
-  }
-
-  bool AllowTestsToRun() const {
-    return allow_tests_to_run_;
-  }
-
- private:
-  void FinishGpuMemoryChanges() {
-    // This should wait until all effects of memory management complete.
-    // We will need to wait until all
-    // 1. pending commits from the main thread to the impl thread in the
-    //    compositor complete (for visible compositors).
-    // 2. allocations that the renderer's impl thread will make due to the
-    //    compositor and WebGL are completed.
-    // 3. pending GpuMemoryManager::Manage() calls to manage are made.
-    // 4. renderers' OnMemoryAllocationChanged callbacks in response to
-    //    manager are made.
-    // Each step in this sequence can cause trigger the next (as a 1-2-3-4-1
-    // cycle), so we will need to pump this cycle until it stabilizes.
-
-    // Pump the cycle 8 times (in principle it could take an infinite number
-    // of iterations to settle).
-    for (size_t pump_it = 0; pump_it < 8; ++pump_it) {
-      // Wait for a RequestAnimationFrame to complete from all visible tabs
-      // for stage 1 of the cycle.
-      for (std::set<Shell*>::iterator it = visible_tabs_.begin();
-           it != visible_tabs_.end();
-           ++it) {
-        std::string js_call(
-            "window.webkitRequestAnimationFrame(function() {"
-            "  domAutomationController.setAutomationId(1);"
-            "  domAutomationController.send(\"DONE_RAF\");"
-            "})");
-        std::string message;
-        ASSERT_TRUE(ExecuteScriptInFrameAndExtractString(
-            (*it)->web_contents(), std::string(), js_call, &message));
-        EXPECT_EQ("DONE_RAF", message);
-      }
-      // TODO(ccameron): send an IPC from Browser -> Renderer (delay it until
-      // painting finishes) -> GPU process (delay it until any pending manages
-      // happen) -> All Renderers -> Browser to flush parts 2, 3, and 4.
-    }
-  }
-
-  size_t GetMemoryUsageMbytes() {
-    GpuMemoryBytesAllocatedObserver observer;
-    observer.GetBytesAllocated();
-    return observer.GetBytesAllocated() / 1048576;
-  }
-
-  bool allow_tests_to_run_;
-  std::set<Shell*> tabs_;
-  std::set<Shell*> visible_tabs_;
-  bool has_used_first_shell_;
-  base::FilePath gpu_test_dir_;
-};
-
-#if defined(OS_LINUX) && !defined(NDEBUG)
-// http://crbug.com/254724
-#define MAYBE(x) DISABLED_ ## x
-#elif defined(OS_WIN) && defined(USE_AURA)
-// http://crbug.com/292882
-#define MAYBE(x) DISABLED_ ## x
-#else
-#define MAYBE(x) x
-#endif
-
-// When trying to load something that doesn't fit into our total GPU memory
-// limit, we shouldn't exceed that limit.
-IN_PROC_BROWSER_TEST_F(GpuMemoryTest,
-                       MAYBE(SingleWindowDoesNotExceedLimit)) {
-  if (!AllowTestsToRun())
-    return;
-
-  Shell* tab = CreateNewTab();
-  LoadPage(tab, PAGE_CSS3D, kMemoryLimitMB);
-  // Make sure that the CSS3D page maxes out a single tab's budget (otherwise
-  // the test doesn't test anything) but still stays under the limit.
-  EXPECT_TRUE(MemoryUsageInRange(
-     kSingleTabLimitMB - kWiggleRoomMB,
-     kMemoryLimitMB + kWiggleRoomMB));
-}
-
-}  // namespace content
diff --git a/content/browser/histogram_synchronizer.cc b/content/browser/histogram_synchronizer.cc
index 5a1e6f9..1661723 100644
--- a/content/browser/histogram_synchronizer.cc
+++ b/content/browser/histogram_synchronizer.cc
@@ -8,6 +8,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/histogram_delta_serialization.h"
 #include "base/pickle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
@@ -268,16 +269,10 @@
     const std::vector<std::string>& pickled_histograms) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
+  base::HistogramDeltaSerialization::DeserializeAndAddSamples(
+      pickled_histograms);
+
   RequestContext* request = RequestContext::GetRequestContext(sequence_number);
-
-  for (std::vector<std::string>::const_iterator it = pickled_histograms.begin();
-       it < pickled_histograms.end();
-       ++it) {
-    Pickle pickle(it->data(), it->size());
-    PickleIterator iter(pickle);
-    base::DeserializeHistogramAndAddSamples(&iter);
-  }
-
   if (!request)
     return;
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index 479ab34..b499801 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -23,11 +23,26 @@
 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
 #include "third_party/leveldatabase/env_chromium.h"
+#include "webkit/common/database/database_identifier.h"
 
 using base::StringPiece;
 
 namespace content {
 
+namespace {
+
+static std::string ComputeOriginIdentifier(const GURL& origin_url) {
+  return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1";
+}
+
+static base::FilePath ComputeFileName(const GURL& origin_url) {
+  return base::FilePath()
+      .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
+      .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
+}
+
+}  // namespace
+
 static const int64 kKeyGeneratorInitialNumber =
     1;  // From the IndexedDB specification.
 
@@ -360,10 +375,13 @@
 };
 
 IndexedDBBackingStore::IndexedDBBackingStore(
-    const std::string& identifier,
+    const GURL& origin_url,
     scoped_ptr<LevelDBDatabase> db,
     scoped_ptr<LevelDBComparator> comparator)
-    : identifier_(identifier), db_(db.Pass()), comparator_(comparator.Pass()) {}
+    : origin_url_(origin_url),
+      origin_identifier_(ComputeOriginIdentifier(origin_url)),
+      db_(db.Pass()),
+      comparator_(comparator.Pass()) {}
 
 IndexedDBBackingStore::~IndexedDBBackingStore() {
   // db_'s destructor uses comparator_. The order of destruction is important.
@@ -402,20 +420,16 @@
   INDEXED_DB_BACKING_STORE_OPEN_MAX,
 };
 
+// static
 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& path_base,
-    const std::string& file_identifier,
     WebKit::WebIDBCallbacks::DataLoss* data_loss,
     bool* disk_full) {
   *data_loss = WebKit::WebIDBCallbacks::DataLossNone;
   DefaultLevelDBFactory leveldb_factory;
-  return IndexedDBBackingStore::Open(origin_identifier,
-                                     path_base,
-                                     file_identifier,
-                                     data_loss,
-                                     disk_full,
-                                     &leveldb_factory);
+  return IndexedDBBackingStore::Open(
+      origin_url, path_base, data_loss, disk_full, &leveldb_factory);
 }
 
 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result) {
@@ -454,10 +468,10 @@
   return false;
 }
 
+// static
 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& path_base,
-    const std::string& file_identifier,
     WebKit::WebIDBCallbacks::DataLoss* data_loss,
     bool* is_disk_full,
     LevelDBFactory* leveldb_factory) {
@@ -478,9 +492,8 @@
     return scoped_refptr<IndexedDBBackingStore>();
   }
 
-  base::FilePath file_path =
-      path_base.AppendASCII(origin_identifier)
-          .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
+  const base::FilePath file_path =
+      path_base.Append(ComputeFileName(origin_url));
 
   if (IsPathTooLong(file_path)) {
     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG);
@@ -546,17 +559,19 @@
     return scoped_refptr<IndexedDBBackingStore>();
   }
 
-  return Create(file_identifier, db.Pass(), comparator.Pass());
+  return Create(origin_url, db.Pass(), comparator.Pass());
 }
 
+// static
 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
-    const std::string& file_identifier) {
+    const GURL& origin_url) {
   DefaultLevelDBFactory leveldb_factory;
-  return IndexedDBBackingStore::OpenInMemory(file_identifier, &leveldb_factory);
+  return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory);
 }
 
+// static
 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
-    const std::string& file_identifier,
+    const GURL& origin_url,
     LevelDBFactory* leveldb_factory) {
   IDB_TRACE("IndexedDBBackingStore::OpenInMemory");
 
@@ -570,18 +585,20 @@
   }
   HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS);
 
-  return Create(file_identifier, db.Pass(), comparator.Pass());
+  return Create(origin_url, db.Pass(), comparator.Pass());
 }
 
+// static
 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
-    const std::string& identifier,
+    const GURL& origin_url,
     scoped_ptr<LevelDBDatabase> db,
     scoped_ptr<LevelDBComparator> comparator) {
   // TODO(jsbell): Handle comparator name changes.
-  scoped_refptr<IndexedDBBackingStore> backing_store(
-      new IndexedDBBackingStore(identifier, db.Pass(), comparator.Pass()));
 
-  if (!SetUpMetadata(backing_store->db_.get(), identifier))
+  scoped_refptr<IndexedDBBackingStore> backing_store(
+      new IndexedDBBackingStore(origin_url, db.Pass(), comparator.Pass()));
+  if (!SetUpMetadata(backing_store->db_.get(),
+                     backing_store->origin_identifier_))
     return scoped_refptr<IndexedDBBackingStore>();
 
   return backing_store;
@@ -590,9 +607,9 @@
 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() {
   std::vector<string16> found_names;
   const std::string start_key =
-      DatabaseNameKey::EncodeMinKeyForOrigin(identifier_);
+      DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
   const std::string stop_key =
-      DatabaseNameKey::EncodeStopKeyForOrigin(identifier_);
+      DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
 
   DCHECK(found_names.empty());
 
@@ -615,7 +632,7 @@
     const string16& name,
     IndexedDBDatabaseMetadata* metadata,
     bool* found) {
-  const std::string key = DatabaseNameKey::Encode(identifier_, name);
+  const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
   *found = false;
 
   bool ok = GetInt(db_.get(), key, &metadata->id, found);
@@ -672,8 +689,8 @@
   *new_id = -1;
   int64 max_database_id = -1;
   bool found = false;
-  bool ok = GetInt(
-      transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found);
+  bool ok =
+      GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found);
   if (!ok) {
     INTERNAL_READ_ERROR(GET_NEW_DATABASE_ID);
     return false;
@@ -704,8 +721,9 @@
   if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
     int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
 
-  PutInt(
-      transaction.get(), DatabaseNameKey::Encode(identifier_, name), *row_id);
+  PutInt(transaction.get(),
+         DatabaseNameKey::Encode(origin_identifier_, name),
+         *row_id);
   PutString(
       transaction.get(),
       DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION),
@@ -778,7 +796,7 @@
        it->Next())
     transaction->Remove(it->Key());
 
-  const std::string key = DatabaseNameKey::Encode(identifier_, name);
+  const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
   transaction->Remove(key);
 
   if (!transaction->Commit()) {
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index c0394d6..14f7d72 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -23,6 +23,7 @@
 #include "content/common/indexed_db/indexed_db_key_range.h"
 #include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -32,11 +33,10 @@
 class LevelDBFactory {
  public:
   virtual ~LevelDBFactory() {}
-  virtual leveldb::Status OpenLevelDB(
-      const base::FilePath& file_name,
-      const LevelDBComparator* comparator,
-      scoped_ptr<LevelDBDatabase>* db,
-      bool* is_disk_full) = 0;
+  virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
+                                      const LevelDBComparator* comparator,
+                                      scoped_ptr<LevelDBDatabase>* db,
+                                      bool* is_disk_full) = 0;
   virtual bool DestroyLevelDB(const base::FilePath& file_name) = 0;
 };
 
@@ -45,29 +45,27 @@
  public:
   class CONTENT_EXPORT Transaction;
 
-  const std::string& identifier() { return identifier_; }
+  const GURL& origin_url() const { return origin_url_; }
   base::OneShotTimer<IndexedDBBackingStore>* close_timer() {
     return &close_timer_;
   }
 
   static scoped_refptr<IndexedDBBackingStore> Open(
-      const std::string& origin_identifier,
+      const GURL& origin_url,
       const base::FilePath& path_base,
-      const std::string& file_identifier,
       WebKit::WebIDBCallbacks::DataLoss* data_loss,
       bool* disk_full);
 
   static scoped_refptr<IndexedDBBackingStore> Open(
-      const std::string& origin_identifier,
+      const GURL& origin_url,
       const base::FilePath& path_base,
-      const std::string& file_identifier,
       WebKit::WebIDBCallbacks::DataLoss* data_loss,
       bool* disk_full,
       LevelDBFactory* factory);
   static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
-      const std::string& file_identifier);
+      const GURL& origin_url);
   static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
-      const std::string& file_identifier,
+      const GURL& origin_url,
       LevelDBFactory* factory);
 
   virtual std::vector<string16> GetDatabaseNames();
@@ -294,7 +292,7 @@
   };
 
  protected:
-  IndexedDBBackingStore(const std::string& identifier,
+  IndexedDBBackingStore(const GURL& origin_url,
                         scoped_ptr<LevelDBDatabase> db,
                         scoped_ptr<LevelDBComparator> comparator);
   virtual ~IndexedDBBackingStore();
@@ -302,7 +300,7 @@
 
  private:
   static scoped_refptr<IndexedDBBackingStore> Create(
-      const std::string& identifier,
+      const GURL& origin_url,
       scoped_ptr<LevelDBDatabase> db,
       scoped_ptr<LevelDBComparator> comparator);
 
@@ -318,7 +316,15 @@
                   IndexedDBObjectStoreMetadata::IndexMap* map)
       WARN_UNUSED_RESULT;
 
-  std::string identifier_;
+  const GURL origin_url_;
+
+  // The origin identifier is a key prefix unique to the origin used in the
+  // leveldb backing store to partition data by origin. It is a normalized
+  // version of the origin URL with a versioning suffix appended, e.g.
+  // "http_localhost_81@1" Since only one origin is stored per backing store
+  // this is redundant but necessary for backwards compatibility; the suffix
+  // provides for future flexibility.
+  const std::string origin_identifier_;
 
   scoped_ptr<LevelDBDatabase> db_;
   scoped_ptr<LevelDBComparator> comparator_;
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 4e25f93..7b5fc62 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -19,8 +19,8 @@
  public:
   IndexedDBBackingStoreTest() {}
   virtual void SetUp() {
-    std::string file_identifier;
-    backing_store_ = IndexedDBBackingStore::OpenInMemory(file_identifier);
+    const GURL origin("http://localhost:81");
+    backing_store_ = IndexedDBBackingStore::OpenInMemory(origin);
 
     // useful keys and values during tests
     m_value1 = "value1";
diff --git a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
index a848090..c845c2d 100644
--- a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
@@ -61,22 +61,17 @@
 };
 
 TEST(IndexedDBIOErrorTest, CleanUpTest) {
-  std::string origin_identifier("http_localhost_81");
+  const GURL origin("http://localhost:81");
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   const base::FilePath path = temp_directory.path();
-  std::string dummy_file_identifier;
   MockLevelDBFactory mock_leveldb_factory;
   WebKit::WebIDBCallbacks::DataLoss data_loss =
       WebKit::WebIDBCallbacks::DataLossNone;
   bool disk_full = false;
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      IndexedDBBackingStore::Open(origin_identifier,
-                                  path,
-                                  dummy_file_identifier,
-                                  &data_loss,
-                                  &disk_full,
-                                  &mock_leveldb_factory);
+      IndexedDBBackingStore::Open(
+          origin, path, &data_loss, &disk_full, &mock_leveldb_factory);
 }
 
 // TODO(dgrogan): Remove expect_destroy if we end up not using it again. It is
@@ -112,52 +107,35 @@
 };
 
 TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
-  std::string origin_identifier("http_localhost_81");
+  const GURL origin("http://localhost:81");
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   const base::FilePath path = temp_directory.path();
-  std::string dummy_file_identifier;
   WebKit::WebIDBCallbacks::DataLoss data_loss =
       WebKit::WebIDBCallbacks::DataLossNone;
   bool disk_full = false;
 
   MockErrorLevelDBFactory<int> mock_leveldb_factory(ENOSPC, false);
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      IndexedDBBackingStore::Open(origin_identifier,
-                                  path,
-                                  dummy_file_identifier,
-                                  &data_loss,
-                                  &disk_full,
-                                  &mock_leveldb_factory);
+      IndexedDBBackingStore::Open(
+          origin, path, &data_loss, &disk_full, &mock_leveldb_factory);
 
   MockErrorLevelDBFactory<base::PlatformFileError> mock_leveldb_factory2(
       base::PLATFORM_FILE_ERROR_NO_MEMORY, false);
   scoped_refptr<IndexedDBBackingStore> backing_store2 =
-      IndexedDBBackingStore::Open(origin_identifier,
-                                  path,
-                                  dummy_file_identifier,
-                                  &data_loss,
-                                  &disk_full,
-                                  &mock_leveldb_factory2);
+      IndexedDBBackingStore::Open(
+          origin, path, &data_loss, &disk_full, &mock_leveldb_factory2);
 
   MockErrorLevelDBFactory<int> mock_leveldb_factory3(EIO, false);
   scoped_refptr<IndexedDBBackingStore> backing_store3 =
-      IndexedDBBackingStore::Open(origin_identifier,
-                                  path,
-                                  dummy_file_identifier,
-                                  &data_loss,
-                                  &disk_full,
-                                  &mock_leveldb_factory3);
+      IndexedDBBackingStore::Open(
+          origin, path, &data_loss, &disk_full, &mock_leveldb_factory3);
 
   MockErrorLevelDBFactory<base::PlatformFileError> mock_leveldb_factory4(
       base::PLATFORM_FILE_ERROR_FAILED, false);
   scoped_refptr<IndexedDBBackingStore> backing_store4 =
-      IndexedDBBackingStore::Open(origin_identifier,
-                                  path,
-                                  dummy_file_identifier,
-                                  &data_loss,
-                                  &disk_full,
-                                  &mock_leveldb_factory4);
+      IndexedDBBackingStore::Open(
+          origin, path, &data_loss, &disk_full, &mock_leveldb_factory4);
 }
 
 }  // namespace
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index 3b6f570..dbf7aca 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -119,7 +119,7 @@
     // Prime our cache of origins with existing databases so we can
     // detect when dbs are newly created.
     GetOriginSet();
-    factory_ = new IndexedDBFactory();
+    factory_ = new IndexedDBFactory(this);
   }
   return factory_;
 }
@@ -186,8 +186,7 @@
 
     if (factory_) {
       std::vector<IndexedDBDatabase*> databases =
-          factory_->GetOpenDatabasesForOrigin(
-              webkit_database::GetIdentifierFromOrigin(origin_url));
+          factory_->GetOpenDatabasesForOrigin(origin_url);
       // TODO(jsbell): Sort by name?
       scoped_ptr<ListValue> database_list(new ListValue());
 
@@ -329,7 +328,7 @@
   }
 }
 
-void IndexedDBContextImpl::ForceClose(const GURL& origin_url) {
+void IndexedDBContextImpl::ForceClose(const GURL origin_url) {
   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
   if (data_path_.empty() || !IsInOriginSet(origin_url))
     return;
@@ -360,7 +359,7 @@
   return connections_[origin_url].size();
 }
 
-base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) {
+base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) const {
   std::string origin_id = webkit_database::GetIdentifierFromOrigin(origin_url);
   return GetIndexedDBFilePath(origin_id);
 }
@@ -444,12 +443,9 @@
 
 IndexedDBContextImpl::~IndexedDBContextImpl() {
   if (factory_) {
-    IndexedDBFactory* factory = factory_;
-    factory->AddRef();
+    TaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&IndexedDBFactory::ContextDestroyed, factory_));
     factory_ = NULL;
-    if (!task_runner_->ReleaseSoon(FROM_HERE, factory)) {
-      factory->Release();
-    }
   }
 
   if (data_path_.empty())
@@ -482,8 +478,7 @@
 int64 IndexedDBContextImpl::ReadUsageFromDisk(const GURL& origin_url) const {
   if (data_path_.empty())
     return 0;
-  std::string origin_id = webkit_database::GetIdentifierFromOrigin(origin_url);
-  base::FilePath file_path = GetIndexedDBFilePath(origin_id);
+  base::FilePath file_path = GetFilePath(origin_url);
   return base::ComputeDirectorySize(file_path);
 }
 
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h
index 3c76465..a16a622 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -75,8 +75,10 @@
   quota::QuotaManagerProxy* quota_manager_proxy();
 
   base::ListValue* GetAllOriginsDetails();
-  void ForceClose(const GURL& origin_url);
-  base::FilePath GetFilePath(const GURL& origin_url);
+  // ForceClose takes a value rather than a reference since it may release the
+  // owning object.
+  void ForceClose(const GURL origin_url);
+  base::FilePath GetFilePath(const GURL& origin_url) const;
   base::FilePath data_path() const { return data_path_; }
   bool IsInOriginSet(const GURL& origin_url) {
     std::set<GURL>* set = GetOriginSet();
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index ec0746e..27053b6 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -218,10 +218,6 @@
   DCHECK(pending_delete_calls_.empty());
 }
 
-scoped_refptr<IndexedDBBackingStore> IndexedDBDatabase::BackingStore() const {
-  return backing_store_;
-}
-
 IndexedDBTransaction* IndexedDBDatabase::GetTransaction(
     int64 transaction_id) const {
   TransactionMap::const_iterator trans_iterator =
@@ -882,18 +878,17 @@
     return;
   DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
 
-  scoped_refptr<IndexedDBBackingStore> store = BackingStore();
   // TODO(alecflett): This method could be asynchronous, but we need to
   // evaluate if it's worth the extra complexity.
   IndexedDBBackingStore::RecordIdentifier record_identifier;
   bool found = false;
-  bool ok =
-      store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(),
-                                    metadata_.id,
-                                    object_store_id,
-                                    *primary_key,
-                                    &record_identifier,
-                                    &found);
+  bool ok = backing_store_->KeyExistsInObjectStore(
+      transaction->BackingStoreTransaction(),
+      metadata_.id,
+      object_store_id,
+      *primary_key,
+      &record_identifier,
+      &found);
   if (!ok) {
     transaction->Abort(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
@@ -915,7 +910,7 @@
   const IndexedDBObjectStoreMetadata& object_store_metadata =
       metadata_.object_stores[object_store_id];
   bool backing_store_success = MakeIndexWriters(transaction,
-                                                store,
+                                                backing_store_,
                                                 id(),
                                                 object_store_metadata,
                                                 *primary_key,
@@ -940,7 +935,7 @@
   for (size_t i = 0; i < index_writers.size(); ++i) {
     IndexWriter* index_writer = index_writers[i];
     index_writer->WriteIndexKeys(record_identifier,
-                                 store,
+                                 backing_store_,
                                  transaction->BackingStoreTransaction(),
                                  id(),
                                  object_store_id);
@@ -1320,6 +1315,10 @@
   }
 }
 
+void IndexedDBDatabase::TransactionCommitFailed() {
+  factory_->HandleBackingStoreFailure(backing_store_->origin_url());
+}
+
 size_t IndexedDBDatabase::ConnectionCount() const {
   // This does not include pending open calls, as those should not block version
   // changes and deletes.
@@ -1680,17 +1679,15 @@
       !pending_delete_calls_.size()) {
     DCHECK(transactions_.empty());
 
+    const GURL origin_url = backing_store_->origin_url();
+    backing_store_ = NULL;
+
     // factory_ should only be null in unit tests.
     // TODO(jsbell): DCHECK(factory_ || !in_unit_tests) - somehow.
     if (factory_) {
-      DCHECK(backing_store_.get());
-      factory_->ReleaseDatabase(identifier_, forced);
+      factory_->ReleaseDatabase(identifier_, origin_url, forced);
       factory_ = NULL;
     }
-
-    // Drop reference to backing store after informing factory, so
-    // that factory can do accounting on it.
-    backing_store_ = NULL;
   }
 }
 
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h
index d5bf678..d50d9bd 100644
--- a/content/browser/indexed_db/indexed_db_database.h
+++ b/content/browser/indexed_db/indexed_db_database.h
@@ -18,6 +18,7 @@
 #include "content/browser/indexed_db/indexed_db_metadata.h"
 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
 #include "content/browser/indexed_db/list_set.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -44,8 +45,8 @@
   };
 
   typedef std::vector<IndexedDBKey> IndexKeys;
-  // Identifier is pair of (origin identifier, database name).
-  typedef std::pair<std::string, base::string16> Identifier;
+  // Identifier is pair of (origin url, database name).
+  typedef std::pair<GURL, base::string16> Identifier;
 
   static const int64 kInvalidId = 0;
   static const int64 kMinimumIndexId = 30;
@@ -55,12 +56,9 @@
       IndexedDBBackingStore* backing_store,
       IndexedDBFactory* factory,
       const Identifier& unique_identifier);
-  scoped_refptr<IndexedDBBackingStore> BackingStore() const;
 
-  const Identifier& identifier() { return identifier_; }
-  scoped_refptr<IndexedDBBackingStore> backing_store() {
-    return backing_store_;
-  }
+  const Identifier& identifier() const { return identifier_; }
+  IndexedDBBackingStore* backing_store() { return backing_store_.get(); }
 
   int64 id() const { return metadata_.id; }
   const base::string16& name() const { return metadata_.name; }
@@ -124,6 +122,9 @@
   void TransactionFinishedAndCompleteFired(IndexedDBTransaction* transaction);
   void TransactionFinishedAndAbortFired(IndexedDBTransaction* transaction);
 
+  // Called by transactions to report failure committing to the backing store.
+  void TransactionCommitFailed();
+
   void Get(int64 transaction_id,
            int64 object_store_id,
            int64 index_id,
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index 80609e9..73a7ec2 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -14,10 +14,11 @@
 #include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_cursor.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
-#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
 #include "content/browser/indexed_db/indexed_db_factory.h"
 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
 #include "content/browser/indexed_db/indexed_db_transaction.h"
+#include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
+#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -38,36 +39,6 @@
   EXPECT_TRUE(backing_store->HasOneRef());  // local
 }
 
-class MockOpenCallbacks : public IndexedDBCallbacks {
- public:
-  MockOpenCallbacks() : IndexedDBCallbacks(NULL, 0, 0) {}
-
-  virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
-                         const IndexedDBDatabaseMetadata& metadata) OVERRIDE {
-    connection_ = connection.Pass();
-  }
-
-  IndexedDBConnection* connection() { return connection_.get(); }
-
- private:
-  virtual ~MockOpenCallbacks() { EXPECT_TRUE(connection_); }
-  scoped_ptr<IndexedDBConnection> connection_;
-};
-
-class FakeDatabaseCallbacks : public IndexedDBDatabaseCallbacks {
- public:
-  FakeDatabaseCallbacks() : IndexedDBDatabaseCallbacks(NULL, 0, 0) {}
-
-  virtual void OnVersionChange(int64 old_version, int64 new_version) OVERRIDE {}
-  virtual void OnForcedClose() OVERRIDE {}
-  virtual void OnAbort(int64 transaction_id,
-                       const IndexedDBDatabaseError& error) OVERRIDE {}
-  virtual void OnComplete(int64 transaction_id) OVERRIDE {}
-
- private:
-  virtual ~FakeDatabaseCallbacks() {}
-};
-
 TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
       new IndexedDBFakeBackingStore();
@@ -82,8 +53,9 @@
 
   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
 
-  scoped_refptr<MockOpenCallbacks> request1(new MockOpenCallbacks());
-  scoped_refptr<FakeDatabaseCallbacks> callbacks1(new FakeDatabaseCallbacks());
+  scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
+      new MockIndexedDBDatabaseCallbacks());
   const int64 transaction_id1 = 1;
   db->OpenConnection(request1,
                      callbacks1,
@@ -92,8 +64,9 @@
 
   EXPECT_FALSE(backing_store->HasOneRef());  // db, connection count > 0
 
-  scoped_refptr<MockOpenCallbacks> request2(new MockOpenCallbacks());
-  scoped_refptr<FakeDatabaseCallbacks> callbacks2(new FakeDatabaseCallbacks());
+  scoped_refptr<MockIndexedDBCallbacks> request2(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2(
+      new MockIndexedDBDatabaseCallbacks());
   const int64 transaction_id2 = 2;
   db->OpenConnection(request2,
                      callbacks2,
@@ -111,26 +84,11 @@
   EXPECT_FALSE(request2->connection()->IsConnected());
 
   EXPECT_TRUE(backing_store->HasOneRef());
-  EXPECT_FALSE(db->BackingStore());
+  EXPECT_FALSE(db->backing_store());
 
   db = NULL;
 }
 
-class MockAbortCallbacks : public IndexedDBDatabaseCallbacks {
- public:
-  MockAbortCallbacks()
-      : IndexedDBDatabaseCallbacks(NULL, 0, 0), abort_called_(false) {}
-
-  virtual void OnAbort(int64 transaction_id,
-                       const IndexedDBDatabaseError& error) OVERRIDE {
-    abort_called_ = true;
-  }
-
- private:
-  virtual ~MockAbortCallbacks() { EXPECT_TRUE(abort_called_); }
-  bool abort_called_;
-};
-
 TEST(IndexedDBDatabaseTest, ForcedClose) {
   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
       new IndexedDBFakeBackingStore();
@@ -145,8 +103,9 @@
 
   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
 
-  scoped_refptr<MockAbortCallbacks> callbacks(new MockAbortCallbacks());
-  scoped_refptr<MockOpenCallbacks> request(new MockOpenCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks(
+      new MockIndexedDBDatabaseCallbacks());
+  scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks());
   const int64 upgrade_transaction_id = 3;
   database->OpenConnection(request,
                            callbacks,
@@ -164,6 +123,7 @@
   request->connection()->ForceClose();
 
   EXPECT_TRUE(backing_store->HasOneRef());  // local
+  EXPECT_TRUE(callbacks->abort_called());
 }
 
 class MockDeleteCallbacks : public IndexedDBCallbacks {
@@ -183,7 +143,6 @@
  private:
   virtual ~MockDeleteCallbacks() { EXPECT_TRUE(success_void_called_); }
 
-  scoped_ptr<IndexedDBConnection> connection_;
   bool blocked_called_;
   bool success_void_called_;
 };
@@ -202,8 +161,9 @@
 
   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
 
-  scoped_refptr<MockOpenCallbacks> request1(new MockOpenCallbacks());
-  scoped_refptr<FakeDatabaseCallbacks> callbacks1(new FakeDatabaseCallbacks());
+  scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
+      new MockIndexedDBDatabaseCallbacks());
   const int64 transaction_id1 = 1;
   db->OpenConnection(request1,
                      callbacks1,
@@ -220,7 +180,7 @@
 
   db->Close(request1->connection(), true /* forced */);
 
-  EXPECT_FALSE(db->BackingStore());
+  EXPECT_FALSE(db->backing_store());
   EXPECT_TRUE(backing_store->HasOneRef());  // local
 }
 
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index ffbecf6..1f8f895 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -221,10 +221,13 @@
   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
 
+  GURL origin_url =
+      webkit_database::GetOriginFromIdentifier(params.database_identifier);
+
   Context()->GetIDBFactory()->GetDatabaseNames(
       new IndexedDBCallbacks(
           this, params.ipc_thread_id, params.ipc_callbacks_id),
-      params.database_identifier,
+      origin_url,
       indexed_db_path);
 }
 
@@ -255,19 +258,21 @@
                                    host_transaction_id,
                                    callbacks,
                                    database_callbacks,
-                                   params.database_identifier,
+                                   origin_url,
                                    indexed_db_path);
 }
 
 void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
     const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+  GURL origin_url =
+      webkit_database::GetOriginFromIdentifier(params.database_identifier);
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
   Context()->GetIDBFactory()->DeleteDatabase(
       params.name,
       new IndexedDBCallbacks(
           this, params.ipc_thread_id, params.ipc_callbacks_id),
-      params.database_identifier,
+      origin_url,
       indexed_db_path);
 }
 
diff --git a/content/browser/indexed_db/indexed_db_factory.cc b/content/browser/indexed_db/indexed_db_factory.cc
index 4e41111..9089920 100644
--- a/content/browser/indexed_db/indexed_db_factory.cc
+++ b/content/browser/indexed_db/indexed_db_factory.cc
@@ -8,88 +8,111 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
+#include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_tracing.h"
 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
+#include "webkit/common/database/database_identifier.h"
 
 namespace content {
 
 const int64 kBackingStoreGracePeriodMs = 2000;
 
-static std::string ComputeFileIdentifier(const std::string& origin_identifier) {
-  return origin_identifier + "@1";
-}
-
-IndexedDBFactory::IndexedDBFactory() {}
+IndexedDBFactory::IndexedDBFactory(IndexedDBContextImpl* context)
+    : context_(context) {}
 
 IndexedDBFactory::~IndexedDBFactory() {}
 
 void IndexedDBFactory::ReleaseDatabase(
     const IndexedDBDatabase::Identifier& identifier,
+    const GURL& origin_url,
     bool forcedClose) {
-  DCHECK(database_map_.find(identifier) != database_map_.end());
-  std::string backing_store_identifier =
-      database_map_[identifier]->backing_store()->identifier();
-  database_map_.erase(identifier);
+  IndexedDBDatabaseMap::iterator it = database_map_.find(identifier);
+  DCHECK(it != database_map_.end());
+  DCHECK(!it->second->backing_store());
+  database_map_.erase(it);
 
   // No grace period on a forced-close, as the initiator is
   // assuming the backing store will be released once all
   // connections are closed.
-  ReleaseBackingStore(backing_store_identifier, forcedClose);
+  ReleaseBackingStore(origin_url, forcedClose);
 }
 
-void IndexedDBFactory::ReleaseBackingStore(const std::string& identifier,
+void IndexedDBFactory::ReleaseBackingStore(const GURL& origin_url,
                                            bool immediate) {
   // Only close if this is the last reference.
-  if (!HasLastBackingStoreReference(identifier))
+  if (!HasLastBackingStoreReference(origin_url))
     return;
 
+  // If this factory does hold the last reference to the backing store, it can
+  // be closed - but unless requested to close it immediately, keep it around
+  // for a short period so that a re-open is fast.
   if (immediate) {
-    CloseBackingStore(identifier);
+    CloseBackingStore(origin_url);
     return;
   }
 
-  DCHECK(!backing_store_map_[identifier]->close_timer()->IsRunning());
-  backing_store_map_[identifier]->close_timer()->Start(
+  // Start a timer to close the backing store, unless something else opens it
+  // in the mean time.
+  DCHECK(!backing_store_map_[origin_url]->close_timer()->IsRunning());
+  backing_store_map_[origin_url]->close_timer()->Start(
       FROM_HERE,
       base::TimeDelta::FromMilliseconds(kBackingStoreGracePeriodMs),
-      base::Bind(&IndexedDBFactory::MaybeCloseBackingStore, this, identifier));
+      base::Bind(&IndexedDBFactory::MaybeCloseBackingStore, this, origin_url));
 }
 
-void IndexedDBFactory::MaybeCloseBackingStore(const std::string& identifier) {
-  // Another reference may have opened since the maybe-close was posted,
-  // so it is necessary to check again.
-  if (HasLastBackingStoreReference(identifier))
-    CloseBackingStore(identifier);
+void IndexedDBFactory::MaybeCloseBackingStore(const GURL& origin_url) {
+  // Another reference may have opened since the maybe-close was posted, so it
+  // is necessary to check again.
+  if (HasLastBackingStoreReference(origin_url))
+    CloseBackingStore(origin_url);
 }
 
-void IndexedDBFactory::CloseBackingStore(const std::string& identifier) {
-  backing_store_map_.erase(identifier);
+void IndexedDBFactory::CloseBackingStore(const GURL& origin_url) {
+  IndexedDBBackingStoreMap::iterator it = backing_store_map_.find(origin_url);
+  DCHECK(it != backing_store_map_.end());
+  // Stop the timer (if it's running) - this may happen if the timer was started
+  // and then a forced close occurs.
+  it->second->close_timer()->Stop();
+  backing_store_map_.erase(it);
 }
 
-bool IndexedDBFactory::HasLastBackingStoreReference(
-    const std::string& identifier) const {
+bool IndexedDBFactory::HasLastBackingStoreReference(const GURL& origin_url)
+    const {
   IndexedDBBackingStore* ptr;
   {
     // Scope so that the implicit scoped_refptr<> is freed.
     IndexedDBBackingStoreMap::const_iterator it =
-        backing_store_map_.find(identifier);
+        backing_store_map_.find(origin_url);
     DCHECK(it != backing_store_map_.end());
     ptr = it->second.get();
   }
   return ptr->HasOneRef();
 }
 
+void IndexedDBFactory::ContextDestroyed() {
+  // Timers on backing stores hold a reference to this factory. When the
+  // context (which nominally owns this factory) is destroyed during thread
+  // termination the timers must be stopped so that this factory and the
+  // stores can be disposed of.
+  for (IndexedDBBackingStoreMap::iterator it = backing_store_map_.begin();
+       it != backing_store_map_.end();
+       ++it)
+    it->second->close_timer()->Stop();
+  backing_store_map_.clear();
+  context_ = NULL;
+}
+
 void IndexedDBFactory::GetDatabaseNames(
     scoped_refptr<IndexedDBCallbacks> callbacks,
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& data_directory) {
   IDB_TRACE("IndexedDBFactory::GetDatabaseNames");
   // TODO(dgrogan): Plumb data_loss back to script eventually?
   WebKit::WebIDBCallbacks::DataLoss data_loss;
   bool disk_full;
-  scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
-      origin_identifier, data_directory, &data_loss, &disk_full);
+  scoped_refptr<IndexedDBBackingStore> backing_store =
+      OpenBackingStore(origin_url, data_directory, &data_loss, &disk_full);
   if (!backing_store) {
     callbacks->OnError(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
@@ -104,10 +127,10 @@
 void IndexedDBFactory::DeleteDatabase(
     const string16& name,
     scoped_refptr<IndexedDBCallbacks> callbacks,
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& data_directory) {
   IDB_TRACE("IndexedDBFactory::DeleteDatabase");
-  IndexedDBDatabase::Identifier unique_identifier(origin_identifier, name);
+  IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
   IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
   if (it != database_map_.end()) {
     // If there are any connections to the database, directly delete the
@@ -119,8 +142,8 @@
   // TODO(dgrogan): Plumb data_loss back to script eventually?
   WebKit::WebIDBCallbacks::DataLoss data_loss;
   bool disk_full = false;
-  scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
-      origin_identifier, data_directory, &data_loss, &disk_full);
+  scoped_refptr<IndexedDBBackingStore> backing_store =
+      OpenBackingStore(origin_url, data_directory, &data_loss, &disk_full);
   if (!backing_store) {
     callbacks->OnError(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
@@ -146,16 +169,26 @@
   database_map_.erase(unique_identifier);
 }
 
+void IndexedDBFactory::HandleBackingStoreFailure(const GURL& origin_url) {
+  // NULL after ContextDestroyed() called, and in some unit tests.
+  if (!context_)
+    return;
+  context_->ForceClose(origin_url);
+}
+
+bool IndexedDBFactory::IsBackingStoreOpenForTesting(const GURL& origin_url)
+    const {
+  return backing_store_map_.find(origin_url) != backing_store_map_.end();
+}
+
 scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& data_directory,
     WebKit::WebIDBCallbacks::DataLoss* data_loss,
     bool* disk_full) {
-  const std::string file_identifier = ComputeFileIdentifier(origin_identifier);
   const bool open_in_memory = data_directory.empty();
 
-  IndexedDBBackingStoreMap::iterator it2 =
-      backing_store_map_.find(file_identifier);
+  IndexedDBBackingStoreMap::iterator it2 = backing_store_map_.find(origin_url);
   if (it2 != backing_store_map_.end()) {
     it2->second->close_timer()->Stop();
     return it2->second;
@@ -163,17 +196,14 @@
 
   scoped_refptr<IndexedDBBackingStore> backing_store;
   if (open_in_memory) {
-    backing_store = IndexedDBBackingStore::OpenInMemory(file_identifier);
+    backing_store = IndexedDBBackingStore::OpenInMemory(origin_url);
   } else {
-    backing_store = IndexedDBBackingStore::Open(origin_identifier,
-                                                data_directory,
-                                                file_identifier,
-                                                data_loss,
-                                                disk_full);
+    backing_store = IndexedDBBackingStore::Open(
+        origin_url, data_directory, data_loss, disk_full);
   }
 
   if (backing_store.get()) {
-    backing_store_map_[file_identifier] = backing_store;
+    backing_store_map_[origin_url] = backing_store;
     // If an in-memory database, bind lifetime to this factory instance.
     if (open_in_memory)
       session_only_backing_stores_.insert(backing_store);
@@ -194,18 +224,18 @@
     int64 transaction_id,
     scoped_refptr<IndexedDBCallbacks> callbacks,
     scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
-    const std::string& origin_identifier,
+    const GURL& origin_url,
     const base::FilePath& data_directory) {
   IDB_TRACE("IndexedDBFactory::Open");
   scoped_refptr<IndexedDBDatabase> database;
-  IndexedDBDatabase::Identifier unique_identifier(origin_identifier, name);
+  IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
   IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
   WebKit::WebIDBCallbacks::DataLoss data_loss =
       WebKit::WebIDBCallbacks::DataLossNone;
   bool disk_full = false;
   if (it == database_map_.end()) {
-    scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
-        origin_identifier, data_directory, &data_loss, &disk_full);
+    scoped_refptr<IndexedDBBackingStore> backing_store =
+        OpenBackingStore(origin_url, data_directory, &data_loss, &disk_full);
     if (!backing_store) {
       if (disk_full) {
         callbacks->OnError(
@@ -242,12 +272,12 @@
 }
 
 std::vector<IndexedDBDatabase*> IndexedDBFactory::GetOpenDatabasesForOrigin(
-    const std::string& origin_identifier) const {
+    const GURL& origin_url) const {
   std::vector<IndexedDBDatabase*> result;
   for (IndexedDBDatabaseMap::const_iterator it = database_map_.begin();
        it != database_map_.end();
        ++it) {
-    if (it->first.first == origin_identifier)
+    if (it->first.first == origin_url)
       result.push_back(it->second.get());
   }
   return result;
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h
index 97f5d80..ab550b5 100644
--- a/content/browser/indexed_db/indexed_db_factory.h
+++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -16,39 +16,49 @@
 #include "content/browser/indexed_db/indexed_db_database.h"
 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
 #include "content/common/content_export.h"
+#include "url/gurl.h"
 
 namespace content {
 
 class IndexedDBBackingStore;
+class IndexedDBContextImpl;
 
 class CONTENT_EXPORT IndexedDBFactory
     : NON_EXPORTED_BASE(public base::RefCounted<IndexedDBFactory>) {
  public:
-  IndexedDBFactory();
+  explicit IndexedDBFactory(IndexedDBContextImpl* context);
 
   // Notifications from weak pointers.
   void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
+                       const GURL& origin_url,
                        bool forcedClose);
 
   void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
-                        const std::string& origin_identifier,
+                        const GURL& origin_url,
                         const base::FilePath& data_directory);
   void Open(const string16& name,
             int64 version,
             int64 transaction_id,
             scoped_refptr<IndexedDBCallbacks> callbacks,
             scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
-            const std::string& origin_identifier,
+            const GURL& origin_url,
             const base::FilePath& data_directory);
 
   void DeleteDatabase(const string16& name,
                       scoped_refptr<IndexedDBCallbacks> callbacks,
-                      const std::string& origin_identifier,
+                      const GURL& origin_url,
                       const base::FilePath& data_directory);
 
+  void HandleBackingStoreFailure(const GURL& origin_url);
+
   // Iterates over all databases; for diagnostics only.
   std::vector<IndexedDBDatabase*> GetOpenDatabasesForOrigin(
-      const std::string& origin_identifier) const;
+      const GURL& origin_url) const;
+
+  bool IsBackingStoreOpenForTesting(const GURL& origin_url) const;
+
+  // Called by the IndexedDBContext destructor so the factory can do cleanup.
+  void ContextDestroyed();
 
  protected:
   friend class base::RefCounted<IndexedDBFactory>;
@@ -56,25 +66,27 @@
   virtual ~IndexedDBFactory();
 
   virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
-      const std::string& origin_identifier,
+      const GURL& origin_url,
       const base::FilePath& data_directory,
       WebKit::WebIDBCallbacks::DataLoss* data_loss,
       bool* disk_full);
 
-  void ReleaseBackingStore(const std::string& identifier, bool immediate);
-  void CloseBackingStore(const std::string& identifier);
+  void ReleaseBackingStore(const GURL& origin_url, bool immediate);
+  void CloseBackingStore(const GURL& origin_url);
 
  private:
   // Called internally after a database is closed, with some delay. If this
   // factory has the last reference, it will be released.
-  void MaybeCloseBackingStore(const std::string& identifier);
-  bool HasLastBackingStoreReference(const std::string& identifier) const;
+  void MaybeCloseBackingStore(const GURL& origin_url);
+  bool HasLastBackingStoreReference(const GURL& origin_url) const;
+
+  IndexedDBContextImpl* context_;
 
   typedef std::map<IndexedDBDatabase::Identifier,
                    scoped_refptr<IndexedDBDatabase> > IndexedDBDatabaseMap;
   IndexedDBDatabaseMap database_map_;
 
-  typedef std::map<std::string, scoped_refptr<IndexedDBBackingStore> >
+  typedef std::map<GURL, scoped_refptr<IndexedDBBackingStore> >
       IndexedDBBackingStoreMap;
   IndexedDBBackingStoreMap backing_store_map_;
 
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 4e1402c..136a26c 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -10,6 +10,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/indexed_db/indexed_db_connection.h"
+#include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
+#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
@@ -34,6 +36,7 @@
 
 class MockIDBFactory : public IndexedDBFactory {
  public:
+  MockIDBFactory() : IndexedDBFactory(NULL) {}
   scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore(
       const GURL& origin,
       const base::FilePath& data_directory) {
@@ -41,21 +44,18 @@
         WebKit::WebIDBCallbacks::DataLossNone;
     bool disk_full;
     scoped_refptr<IndexedDBBackingStore> backing_store =
-        OpenBackingStore(webkit_database::GetIdentifierFromOrigin(origin),
-                         data_directory,
-                         &data_loss,
-                         &disk_full);
+        OpenBackingStore(origin, data_directory, &data_loss, &disk_full);
     EXPECT_EQ(WebKit::WebIDBCallbacks::DataLossNone, data_loss);
     return backing_store;
   }
 
   void TestCloseBackingStore(IndexedDBBackingStore* backing_store) {
-    CloseBackingStore(backing_store->identifier());
+    CloseBackingStore(backing_store->origin_url());
   }
 
   void TestReleaseBackingStore(IndexedDBBackingStore* backing_store,
                                bool immediate) {
-    ReleaseBackingStore(backing_store->identifier(), immediate);
+    ReleaseBackingStore(backing_store->origin_url(), immediate);
   }
 
  private:
@@ -81,7 +81,6 @@
       factory->TestOpenBackingStore(origin2, temp_directory.path());
 
   factory->TestCloseBackingStore(disk_store1);
-  factory->TestCloseBackingStore(disk_store2);
   factory->TestCloseBackingStore(disk_store3);
 
   EXPECT_FALSE(disk_store1->HasOneRef());
@@ -99,13 +98,13 @@
 
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-  scoped_refptr<IndexedDBBackingStore> store1 =
+  scoped_refptr<IndexedDBBackingStore> store =
       factory->TestOpenBackingStore(origin, temp_directory.path());
 
   // Give up the local refptr so that the factory has the only
   // outstanding reference.
-  IndexedDBBackingStore* store_ptr = store1.get();
-  store1 = NULL;
+  IndexedDBBackingStore* store_ptr = store.get();
+  store = NULL;
   EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
   factory->TestReleaseBackingStore(store_ptr, false);
   EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
@@ -115,7 +114,11 @@
   factory->TestReleaseBackingStore(store_ptr, false);
   EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
 
-  store_ptr->close_timer()->Stop();
+  // Take back a ref ptr and ensure that the actual close
+  // stops a running timer.
+  store = store_ptr;
+  factory->TestCloseBackingStore(store_ptr);
+  EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
 }
 
 TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
@@ -134,7 +137,6 @@
       factory->TestOpenBackingStore(origin2, base::FilePath());
 
   factory->TestCloseBackingStore(mem_store1);
-  factory->TestCloseBackingStore(mem_store2);
   factory->TestCloseBackingStore(mem_store3);
 
   EXPECT_FALSE(mem_store1->HasOneRef());
@@ -172,10 +174,13 @@
 }
 
 class DiskFullFactory : public IndexedDBFactory {
+ public:
+  DiskFullFactory() : IndexedDBFactory(NULL) {}
+
  private:
   virtual ~DiskFullFactory() {}
   virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
-      const std::string& origin_identifier,
+      const GURL& origin_url,
       const base::FilePath& data_directory,
       WebKit::WebIDBCallbacks::DataLoss* data_loss,
       bool* disk_full) OVERRIDE {
@@ -199,6 +204,8 @@
 };
 
 TEST_F(IndexedDBFactoryTest, QuotaErrorOnDiskFull) {
+  const GURL origin("http://localhost:81");
+
   scoped_refptr<DiskFullFactory> factory = new DiskFullFactory;
   scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks =
       new LookingForQuotaErrorMockCallbacks;
@@ -210,10 +217,77 @@
                 2, /* transaction_id */
                 callbacks,
                 dummy_database_callbacks,
-                "origin",
+                origin,
                 base::FilePath(FILE_PATH_LITERAL("/dummy")));
 }
 
+TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) {
+  GURL origin("http://localhost:81");
+
+  base::ScopedTempDir temp_directory;
+  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+
+  scoped_refptr<IndexedDBFactory> factory = new IndexedDBFactory(NULL);
+
+  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
+      new MockIndexedDBDatabaseCallbacks());
+  const int64 transaction_id = 1;
+  factory->Open(ASCIIToUTF16("db"),
+                IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION,
+                transaction_id,
+                callbacks,
+                db_callbacks,
+                origin,
+                temp_directory.path());
+
+  EXPECT_TRUE(callbacks->connection());
+
+  EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(origin));
+  callbacks->connection()->ForceClose();
+  EXPECT_FALSE(factory->IsBackingStoreOpenForTesting(origin));
+}
+
+TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) {
+  GURL origin("http://localhost:81");
+
+  base::ScopedTempDir temp_directory;
+  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+
+  scoped_refptr<IndexedDBFactory> factory = new IndexedDBFactory(NULL);
+
+  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
+      new MockIndexedDBDatabaseCallbacks());
+  const int64 transaction_id = 1;
+  factory->Open(ASCIIToUTF16("db"),
+                IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION,
+                transaction_id,
+                callbacks,
+                db_callbacks,
+                origin,
+                temp_directory.path());
+
+  EXPECT_TRUE(callbacks->connection());
+  IndexedDBBackingStore* store =
+      callbacks->connection()->database()->backing_store();
+  EXPECT_FALSE(store->HasOneRef());  // Factory and database.
+
+  EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(origin));
+  callbacks->connection()->Close();
+  EXPECT_TRUE(store->HasOneRef());  // Factory.
+  EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(origin));
+  EXPECT_TRUE(store->close_timer()->IsRunning());
+
+  // Take a ref so it won't be destroyed out from under the test.
+  scoped_refptr<IndexedDBBackingStore> store_ref = store;
+  // Now simulate shutdown, which should stop the timer.
+  factory->ContextDestroyed();
+  EXPECT_TRUE(store->HasOneRef());  // Local.
+  EXPECT_FALSE(store->close_timer()->IsRunning());
+  EXPECT_FALSE(factory->IsBackingStoreOpenForTesting(origin));
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.h b/content/browser/indexed_db/indexed_db_fake_backing_store.h
index 20ebf46..1d40713 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.h
@@ -14,7 +14,7 @@
 class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
  public:
   IndexedDBFakeBackingStore()
-      : IndexedDBBackingStore(std::string(),
+      : IndexedDBBackingStore(GURL("http://localhost:81"),
                               scoped_ptr<LevelDBDatabase>(),
                               scoped_ptr<LevelDBComparator>()) {}
   virtual std::vector<string16> GetDatabaseNames() OVERRIDE;
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc
index 3916726..276b1a9 100644
--- a/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -61,7 +61,7 @@
       commit_pending_(false),
       callbacks_(callbacks),
       database_(database),
-      transaction_(database->BackingStore().get()),
+      transaction_(database->backing_store()),
       should_process_queue_(false),
       pending_preemptive_events_(0),
       queue_status_(CREATED),
@@ -256,6 +256,7 @@
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                "Internal error committing transaction."));
     database_->TransactionFinishedAndAbortFired(this);
+    database_->TransactionCommitFailed();
   }
 
   database_ = NULL;
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc
index 6180c86..43613af 100644
--- a/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -9,6 +9,8 @@
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
+#include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
+#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/test_browser_context.h"
@@ -221,4 +223,41 @@
   EXPECT_TRUE(base::DirectoryExists(test_path));
 }
 
+TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
+  const GURL kTestOrigin("http://test/");
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
+      temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+
+  scoped_refptr<IndexedDBFactory> factory = context->GetIDBFactory();
+
+  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
+  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
+      new MockIndexedDBDatabaseCallbacks());
+  const int64 transaction_id = 1;
+  factory->Open(ASCIIToUTF16("db"),
+                IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION,
+                transaction_id,
+                callbacks,
+                db_callbacks,
+                kTestOrigin,
+                temp_dir.path());
+
+  EXPECT_TRUE(callbacks->connection());
+
+  // ConnectionOpened() is usually called by the dispatcher.
+  context->ConnectionOpened(kTestOrigin, callbacks->connection());
+
+  EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
+
+  // Simulate the write failure.
+  callbacks->connection()->database()->TransactionCommitFailed();
+
+  EXPECT_TRUE(db_callbacks->forced_close_called());
+  EXPECT_FALSE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
+}
+
 }  // namespace content
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc
index 829b2fd..882d6b2 100644
--- a/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -213,60 +213,16 @@
 static void ParseAndHistogramCorruptionDetails(
     const std::string& histogram_name,
     const leveldb::Status& status) {
-  DCHECK(!status.IsIOError());
-  DCHECK(!status.ok());
-  const int kOtherError = 0;
-  int error = kOtherError;
-  const std::string& str_error = status.ToString();
-  // Keep in sync with LevelDBCorruptionTypes in histograms.xml.
-  const char* patterns[] = {
-    "missing files",
-    "log record too small",
-    "corrupted internal key",
-    "partial record",
-    "missing start of fragmented record",
-    "error in middle of record",
-    "unknown record type",
-    "truncated record at end",
-    "bad record length",
-    "VersionEdit",
-    "FileReader invoked with unexpected value",
-    "corrupted key",
-    "CURRENT file does not end with newline",
-    "no meta-nextfile entry",
-    "no meta-lognumber entry",
-    "no last-sequence-number entry",
-    "malformed WriteBatch",
-    "bad WriteBatch Put",
-    "bad WriteBatch Delete",
-    "unknown WriteBatch tag",
-    "WriteBatch has wrong count",
-    "bad entry in block",
-    "bad block contents",
-    "bad block handle",
-    "truncated block read",
-    "block checksum mismatch",
-    "checksum mismatch",
-    "corrupted compressed block contents",
-    "bad block type",
-    "bad magic number",
-    "file is too short",
-  };
-  const size_t kNumPatterns = arraysize(patterns);
-  for (size_t i = 0; i < kNumPatterns; ++i) {
-    if (str_error.find(patterns[i]) != std::string::npos) {
-      error = i + 1;
-      break;
-    }
-  }
+  int error = leveldb_env::ParseCorruptionMessage(status);
   DCHECK(error >= 0);
   std::string corruption_histogram_name(histogram_name);
   corruption_histogram_name.append(".Corruption");
+  const int kNumPatterns = leveldb_env::GetNumCorruptionPatterns();
   base::LinearHistogram::FactoryGet(
       corruption_histogram_name,
       1,
+      kNumPatterns,
       kNumPatterns + 1,
-      kNumPatterns + 2,
       base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error);
 }
 
diff --git a/content/browser/indexed_db/mock_indexed_db_callbacks.cc b/content/browser/indexed_db/mock_indexed_db_callbacks.cc
new file mode 100644
index 0000000..c5f93e0
--- /dev/null
+++ b/content/browser/indexed_db/mock_indexed_db_callbacks.cc
@@ -0,0 +1,22 @@
+// Copyright 2013 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/indexed_db/mock_indexed_db_callbacks.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+MockIndexedDBCallbacks::MockIndexedDBCallbacks()
+    : IndexedDBCallbacks(NULL, 0, 0) {}
+
+MockIndexedDBCallbacks::~MockIndexedDBCallbacks() { EXPECT_TRUE(connection_); }
+
+void MockIndexedDBCallbacks::OnSuccess(
+    scoped_ptr<IndexedDBConnection> connection,
+    const IndexedDBDatabaseMetadata& metadata) {
+  connection_ = connection.Pass();
+}
+
+}  // namespace content
diff --git a/content/browser/indexed_db/mock_indexed_db_callbacks.h b/content/browser/indexed_db/mock_indexed_db_callbacks.h
new file mode 100644
index 0000000..3d6b949
--- /dev/null
+++ b/content/browser/indexed_db/mock_indexed_db_callbacks.h
@@ -0,0 +1,31 @@
+// Copyright 2013 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_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_CALLBACKS_H_
+#define CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_CALLBACKS_H_
+
+#include "content/browser/indexed_db/indexed_db_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_connection.h"
+
+namespace content {
+
+class MockIndexedDBCallbacks : public IndexedDBCallbacks {
+ public:
+  MockIndexedDBCallbacks();
+
+  virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
+                         const IndexedDBDatabaseMetadata& metadata) OVERRIDE;
+
+  IndexedDBConnection* connection() { return connection_.get(); }
+
+ private:
+  virtual ~MockIndexedDBCallbacks();
+  scoped_ptr<IndexedDBConnection> connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockIndexedDBCallbacks);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_CALLBACKS_H_
diff --git a/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc b/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc
new file mode 100644
index 0000000..479bb3a
--- /dev/null
+++ b/content/browser/indexed_db/mock_indexed_db_database_callbacks.cc
@@ -0,0 +1,26 @@
+// Copyright 2013 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/indexed_db/mock_indexed_db_database_callbacks.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+MockIndexedDBDatabaseCallbacks::MockIndexedDBDatabaseCallbacks()
+    : IndexedDBDatabaseCallbacks(NULL, 0, 0),
+      abort_called_(false),
+      forced_close_called_(false) {}
+
+void MockIndexedDBDatabaseCallbacks::OnForcedClose() {
+  forced_close_called_ = true;
+}
+
+void MockIndexedDBDatabaseCallbacks::OnAbort(
+    int64 transaction_id,
+    const IndexedDBDatabaseError& error) {
+  abort_called_ = true;
+}
+
+}  // namespace content
diff --git a/content/browser/indexed_db/mock_indexed_db_database_callbacks.h b/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
new file mode 100644
index 0000000..7252a9f
--- /dev/null
+++ b/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
@@ -0,0 +1,37 @@
+// Copyright 2013 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_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_DATABASE_CALLBACKS_H_
+#define CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_DATABASE_CALLBACKS_H_
+
+#include "content/browser/indexed_db/indexed_db_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_connection.h"
+
+namespace content {
+
+class MockIndexedDBDatabaseCallbacks : public IndexedDBDatabaseCallbacks {
+ public:
+  MockIndexedDBDatabaseCallbacks();
+
+  virtual void OnVersionChange(int64 old_version, int64 new_version) OVERRIDE {}
+  virtual void OnForcedClose() OVERRIDE;
+  virtual void OnAbort(int64 transaction_id,
+                       const IndexedDBDatabaseError& error) OVERRIDE;
+  virtual void OnComplete(int64 transaction_id) OVERRIDE {}
+
+  bool abort_called() const { return abort_called_; }
+  bool forced_close_called() const { return forced_close_called_; }
+
+ private:
+  virtual ~MockIndexedDBDatabaseCallbacks() {}
+
+  bool abort_called_;
+  bool forced_close_called_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockIndexedDBDatabaseCallbacks);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_DATABASE_CALLBACKS_H_
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
index b9729f3..2e7cca5 100644
--- a/content/browser/loader/async_resource_handler.cc
+++ b/content/browser/loader/async_resource_handler.cc
@@ -135,10 +135,11 @@
 bool AsyncResourceHandler::OnUploadProgress(int request_id,
                                             uint64 position,
                                             uint64 size) {
-  ResourceMessageFilter* filter = GetFilter();
-  if (!filter)
-    return false;
-  return filter->Send(
+  const ResourceRequestInfoImpl* info = GetRequestInfo();
+  // Cancel the request if the renderer is gone unless it's detachable.
+  if (!info->filter())
+    return info->is_detached();
+  return info->filter()->Send(
       new ResourceMsg_UploadProgress(request_id, position, size));
 }
 
@@ -147,8 +148,9 @@
                                                ResourceResponse* response,
                                                bool* defer) {
   const ResourceRequestInfoImpl* info = GetRequestInfo();
+  // Cancel the request if the renderer is gone unless it's detached.
   if (!info->filter())
-    return false;
+    return info->is_detached();
 
   *defer = did_defer_ = true;
 
@@ -172,10 +174,11 @@
   // renderer will be able to set these precisely at the time the
   // request commits, avoiding the possibility of e.g. zooming the old content
   // or of having to layout the new content twice.
-
   const ResourceRequestInfoImpl* info = GetRequestInfo();
+
+  // Cancel the request if the renderer is gone unless it's detachable.
   if (!info->filter())
-    return false;
+    return info->is_detached();
 
   if (rdh_->delegate()) {
     rdh_->delegate()->OnResponseStarted(
@@ -248,9 +251,19 @@
   if (!bytes_read)
     return true;
 
+  const ResourceRequestInfoImpl* info = GetRequestInfo();
+  // Don't send any data if the resource is detached from the renderer.
+  if (info->is_detached()) {
+    buffer_->RecycleLeastRecentlyAllocated();
+    return true;
+  }
+
   ResourceMessageFilter* filter = GetFilter();
-  if (!filter)
+  // Cancel the request if the renderer is gone.
+  if (!filter) {
+    DCHECK(!info->is_detachable());
     return false;
+  }
 
   buffer_->ShrinkLastAllocation(bytes_read);
 
@@ -309,8 +322,10 @@
     const net::URLRequestStatus& status,
     const std::string& security_info) {
   const ResourceRequestInfoImpl* info = GetRequestInfo();
+
+  // Cancel the request if the renderer is gone unless it's detachable.
   if (!info->filter())
-    return false;
+    return info->is_detachable();
 
   // If we crash here, figure out what URL the renderer was requesting.
   // http://crbug.com/107692
diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc
index 657791f..1267137 100644
--- a/content/browser/loader/cross_site_resource_handler.cc
+++ b/content/browser/loader/cross_site_resource_handler.cc
@@ -25,15 +25,15 @@
 
 namespace {
 
-void OnCrossSiteResponseHelper(int render_process_id,
-                               int render_view_id,
+void OnCrossSiteResponseHelper(int render_view_id,
                                const GlobalRequestID& global_request_id,
                                bool is_transfer,
-                               const GURL& transfer_url,
+                               const std::vector<GURL>& transfer_url_chain,
                                const Referrer& referrer,
+                               PageTransition page_transition,
                                int64 frame_id) {
-  RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id,
-                                                       render_view_id);
+  RenderViewHostImpl* rvh =
+      RenderViewHostImpl::FromID(global_request_id.child_id, render_view_id);
   if (!rvh)
     return;
   RenderViewHostDelegate* delegate = rvh->GetDelegate();
@@ -41,7 +41,8 @@
     return;
 
   delegate->GetRendererManagementDelegate()->OnCrossSiteResponse(
-      rvh, global_request_id, is_transfer, transfer_url, referrer, frame_id);
+      rvh, global_request_id, is_transfer, transfer_url_chain, referrer,
+      page_transition, frame_id);
 }
 
 }  // namespace
@@ -225,28 +226,30 @@
   // is starting, so that it can tell its old renderer to run its onunload
   // handler now.  We will wait until the unload is finished and (if a transfer
   // is needed) for the new renderer's request to arrive.
-  GURL transfer_url;
+  // The |transfer_url_chain| contains any redirect URLs that have already
+  // occurred, plus the destination URL at the end.
+  std::vector<GURL> transfer_url_chain;
   Referrer referrer;
   int frame_id = -1;
   if (should_transfer) {
-    transfer_url = request()->url();
+    transfer_url_chain = request()->url_chain();
     referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
     frame_id = info->GetFrameID();
 
     ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(
-        global_id, transfer_url);
+        global_id, transfer_url_chain.front());
   }
   BrowserThread::PostTask(
       BrowserThread::UI,
       FROM_HERE,
       base::Bind(
           &OnCrossSiteResponseHelper,
-          info->GetChildID(),
           info->GetRouteID(),
           global_id,
           should_transfer,
-          transfer_url,
+          transfer_url_chain,
           referrer,
+          info->GetPageTransition(),
           frame_id));
 }
 
diff --git a/content/browser/loader/render_view_host_tracker.cc b/content/browser/loader/render_view_host_tracker.cc
deleted file mode 100644
index 2f006e8..0000000
--- a/content/browser/loader/render_view_host_tracker.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2013 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/loader/render_view_host_tracker.h"
-
-#include "base/bind_helpers.h"
-#include "base/stl_util.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/loader/resource_scheduler.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-
-namespace content {
-
-RenderViewHostTracker::RenderViewHostTracker()
-    : rvh_created_callback_(
-          base::Bind(&RenderViewHostTracker::RenderViewHostCreated,
-                     base::Unretained(this))) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  RenderViewHost::AddCreatedCallback(rvh_created_callback_);
-}
-
-RenderViewHostTracker::~RenderViewHostTracker() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(observers_.empty());
-  RenderViewHost::RemoveCreatedCallback(rvh_created_callback_);
-}
-
-void RenderViewHostTracker::RenderViewHostCreated(RenderViewHost* rvh) {
-  Observer* observer = new Observer(rvh, this);
-  observers_.insert(observer);
-
-  int child_id = rvh->GetProcess()->GetID();
-  int route_id = rvh->GetRoutingID();
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostCreated,
-                 base::Unretained(ResourceDispatcherHostImpl::Get()),
-                 child_id, route_id));
-}
-
-void RenderViewHostTracker::RemoveObserver(Observer* observer) {
-  DCHECK(ContainsKey(observers_, observer));
-  observers_.erase(observer);
-  delete observer;
-}
-
-RenderViewHostTracker::Observer::Observer(RenderViewHost* rvh,
-                                          RenderViewHostTracker* tracker)
-    : RenderViewHostObserver(rvh),
-      tracker_(tracker) {
-}
-
-RenderViewHostTracker::Observer::~Observer() {
-}
-
-void RenderViewHostTracker::Observer::RenderViewHostDestroyed(
-    RenderViewHost* rvh) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  int child_id = rvh->GetProcess()->GetID();
-  int route_id = rvh->GetRoutingID();
-
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostDeleted,
-                 base::Unretained(ResourceDispatcherHostImpl::Get()),
-                 child_id, route_id));
-
-  tracker_->RemoveObserver(this);
-}
-
-}  // namespace content
diff --git a/content/browser/loader/render_view_host_tracker.h b/content/browser/loader/render_view_host_tracker.h
deleted file mode 100644
index 7fc5fa0..0000000
--- a/content/browser/loader/render_view_host_tracker.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2013 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_BROWSER_LOADER_RENDER_VIEW_HOST_TRACKER_H_
-#define CONTENT_BROWSER_LOADER_RENDER_VIEW_HOST_TRACKER_H_
-
-#include <set>
-
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
-
-namespace content {
-
-// The ResourceDispatcherHost needs to know when renderers are created and
-// destroyed. That happens on the UI thread, but the ResourceDispatcherHost
-// operates on the IO thread. RenderViewHostTracker listens for renderer
-// notifications on the UI thread, then bounces them over to the IO thread so
-// the ResourceDispatcherHost can be notified.
-class CONTENT_EXPORT RenderViewHostTracker {
- public:
-  RenderViewHostTracker();
-  virtual ~RenderViewHostTracker();
-
- private:
-  // TODO(phajdan.jr): Move this declaration of inner class to the .cc file.
-  class Observer : public RenderViewHostObserver {
-   public:
-    Observer(RenderViewHost* rvh,
-             RenderViewHostTracker* tracker);
-    virtual ~Observer();
-
-   private:
-    // RenderViewHostObserver interface:
-    virtual void RenderViewHostDestroyed(RenderViewHost* rvh) OVERRIDE;
-
-    RenderViewHostTracker* tracker_;
-  };
-
-  friend class Observer;
-  typedef std::set<Observer*> ObserverSet;
-
-  void RenderViewHostCreated(RenderViewHost* rvh);
-
-  void RemoveObserver(Observer* observer);
-
-  RenderViewHost::CreatedCallback rvh_created_callback_;
-  ObserverSet observers_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_LOADER_RENDER_VIEW_HOST_TRACKER_H_
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index a6859df..657b385 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -127,6 +127,15 @@
 // use. Arbitrarily chosen.
 const double kMaxRequestsPerProcessRatio = 0.45;
 
+bool IsDetachableResourceType(ResourceType::Type type) {
+  switch (type) {
+    case ResourceType::PREFETCH:
+      return true;
+    default:
+      return false;
+  }
+}
+
 // Aborts a request before an URLRequest has actually been created.
 void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
                                 IPC::Message* sync_result,
@@ -406,13 +415,16 @@
   for (LoaderList::iterator i = loaders_to_cancel.begin();
        i != loaders_to_cancel.end(); ++i) {
     // There is no strict requirement that this be the case, but currently
-    // downloads, streams  and transferred requests are the only requests that
-    // aren't cancelled when the associated processes go away. It may be OK for
-    // this invariant to change in the future, but if this assertion fires
-    // without the invariant changing, then it's indicative of a leak.
-    DCHECK((*i)->GetRequestInfo()->is_download() ||
-           (*i)->GetRequestInfo()->is_stream() ||
-           (*i)->is_transferring());
+    // downloads, streams, detachable requests, and transferred requests are the
+    // only requests that aren't cancelled when the associated processes go
+    // away. It may be OK for this invariant to change in the future, but if
+    // this assertion fires without the invariant changing, then it's indicative
+    // of a leak.
+    DCHECK(
+        (*i)->GetRequestInfo()->is_download() ||
+        (*i)->GetRequestInfo()->is_stream() ||
+        (*i)->GetRequestInfo()->is_detached() ||
+        (*i)->is_transferring());
   }
 #endif
 
@@ -694,18 +706,19 @@
 
 void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
   ResourceRequestInfoImpl* info = loader->GetRequestInfo();
+
   // There should be an entry in the map created when we dispatched the
-  // request.
+  // request unless it's been detached and the renderer has died.
   OfflineMap::iterator policy_it(
       offline_policy_map_.find(info->GetGlobalRoutingID()));
   if (offline_policy_map_.end() != policy_it) {
     policy_it->second->UpdateStateForSuccessfullyStartedRequest(
         loader->request()->response_info());
   } else {
-    // We should always have an entry in offline_policy_map_ from when
-    // this request traversed Begin{Download,SaveFile,Request}.
+    // Unless detached, we should have an entry in offline_policy_map_ from
+    // when this request traversed Begin{Download,SaveFile,Request}.
     // TODO(rdsmith): This isn't currently true; see http://crbug.com/241176.
-    NOTREACHED();
+    DCHECK(info->is_detached());
   }
 
   int render_process_id, render_view_id;
@@ -1073,6 +1086,7 @@
           request_data.transition_type,
           false,  // is download
           false,  // is stream
+          false,  // is detachable
           allow_download,
           request_data.has_user_gesture,
           request_data.referrer_policy,
@@ -1101,6 +1115,8 @@
     handler.reset(new SyncResourceHandler(request, sync_result, this));
   } else {
     handler.reset(new AsyncResourceHandler(request, this));
+    if (IsDetachableResourceType(request_data.resource_type))
+      extra_info->set_is_detachable(true);
   }
 
   // The RedirectToFileResourceHandler depends on being next in the chain.
@@ -1219,7 +1235,8 @@
       ResourceType::SUB_RESOURCE,
       PAGE_TRANSITION_LINK,
       download,  // is_download
-      false,  // is_stream
+      false,     // is_stream
+      false,     // is_detachable
       download,  // allow_download
       false,     // has_user_gesture
       WebKit::WebReferrerPolicyDefault,
@@ -1315,8 +1332,8 @@
 }
 
 // The object died, so cancel and detach all requests associated with it except
-// for downloads, which belong to the browser process even if initiated via a
-// renderer.
+// for downloads and detachable resources, which belong to the browser process
+// even if initiated via a renderer.
 void ResourceDispatcherHostImpl::CancelRequestsForProcess(int child_id) {
   CancelRequestsForRoute(child_id, -1 /* cancel all */);
   registered_temp_files_.erase(child_id);
@@ -1341,14 +1358,15 @@
 
     GlobalRequestID id(child_id, i->first.request_id);
     DCHECK(id == i->first);
-
-    // Don't cancel navigations that are transferring to another process,
-    // since they belong to another process now.
+    // Don't cancel navigations that are expected to live beyond this process.
     if (IsTransferredNavigation(id))
       any_requests_transferring = true;
-    if (!info->is_download() && !info->is_stream() &&
-        !IsTransferredNavigation(id) &&
-        (route_id == -1 || route_id == info->GetRouteID())) {
+
+    if (info->is_detachable()) {
+      i->second->Detach();
+    } else if (!info->is_download() && !info->is_stream() &&
+               !IsTransferredNavigation(id) &&
+               (route_id == -1 || route_id == info->GetRouteID())) {
       matching_requests.push_back(id);
     }
   }
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index f10b3f7..ef0e4cf 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -27,7 +27,6 @@
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/loader/global_routing_id.h"
 #include "content/browser/loader/offline_policy.h"
-#include "content/browser/loader/render_view_host_tracker.h"
 #include "content/browser/loader/resource_loader.h"
 #include "content/browser/loader/resource_loader_delegate.h"
 #include "content/browser/loader/resource_scheduler.h"
@@ -239,6 +238,10 @@
                            TestBlockedRequestsProcessDies);
   FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
                            CalculateApproximateMemoryCost);
+  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
+                           DetachableResourceTimesOut);
+  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
+                           TestProcessCancelDetachableTimesOut);
 
   class ShutdownTask;
 
@@ -503,8 +506,6 @@
 
   scoped_ptr<ResourceScheduler> scheduler_;
 
-  RenderViewHostTracker tracker_;  // Lives on UI thread.
-
   typedef std::map<GlobalRoutingID, OfflinePolicy*> OfflineMap;
 
   OfflineMap offline_policy_map_;
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index 4a9e275..4939b80 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_loader.h"
 #include "content/browser/loader/resource_message_filter.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/worker_host/worker_service_impl.h"
@@ -523,7 +524,6 @@
         cache_thread_(BrowserThread::CACHE, &message_loop_),
         io_thread_(BrowserThread::IO, &message_loop_),
         old_factory_(NULL),
-        resource_type_(ResourceType::SUB_RESOURCE),
         send_data_received_acks_(false) {
     browser_context_.reset(new TestBrowserContext());
     BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
@@ -594,17 +594,17 @@
     message_loop_.RunUntilIdle();
   }
 
-  // Creates a request using the current test object as the filter.
+  // Creates a request using the current test object as the filter and
+  // SubResource as the resource type.
   void MakeTestRequest(int render_view_id,
                        int request_id,
                        const GURL& url);
 
-  // Generates a request using the given filter. This will probably be a
-  // ForwardingFilter.
-  void MakeTestRequest(ResourceMessageFilter* filter,
-                       int render_view_id,
-                       int request_id,
-                       const GURL& url);
+  // Generates a request using the given filter and resource type.
+  void MakeTestRequestWithResourceType(ResourceMessageFilter* filter,
+                                       int render_view_id, int request_id,
+                                       const GURL& url,
+                                       ResourceType::Type type);
 
   void CancelRequest(int request_id);
 
@@ -634,11 +634,6 @@
     SetResponse(headers, std::string());
   }
 
-  // Sets a particular resource type for any request from now on.
-  void SetResourceType(ResourceType::Type type) {
-    resource_type_ = type;
-  }
-
   void SendDataReceivedACKs(bool send_acks) {
     send_data_received_acks_ = send_acks;
   }
@@ -724,7 +719,6 @@
   std::string response_data_;
   std::string scheme_;
   net::URLRequest::ProtocolFactory* old_factory_;
-  ResourceType::Type resource_type_;
   bool send_data_received_acks_;
   std::set<int> child_ids_;
   static ResourceDispatcherHostTest* test_fixture_;
@@ -741,19 +735,21 @@
 void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
                                                  int request_id,
                                                  const GURL& url) {
-  MakeTestRequest(filter_.get(), render_view_id, request_id, url);
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  url, ResourceType::SUB_RESOURCE);
 }
 
-void ResourceDispatcherHostTest::MakeTestRequest(
+void ResourceDispatcherHostTest::MakeTestRequestWithResourceType(
     ResourceMessageFilter* filter,
     int render_view_id,
     int request_id,
-    const GURL& url) {
+    const GURL& url,
+    ResourceType::Type type) {
   // If it's already there, this'll be dropped on the floor, which is fine.
   child_ids_.insert(filter->child_id());
 
   ResourceHostMsg_Request request =
-      CreateResourceRequest("GET", resource_type_, url);
+      CreateResourceRequest("GET", type, url);
   ResourceHostMsg_RequestResource msg(render_view_id, request_id, request);
   bool msg_was_ok;
   host_.OnMessageReceived(msg, filter, &msg_was_ok);
@@ -778,6 +774,29 @@
     URLRequestTestDelayedStartJob::CompleteStart(req);
 }
 
+void CheckRequestCompleteErrorCode(const IPC::Message& message,
+                                   int expected_error_code) {
+  // Verify that there was no error.
+  int request_id;
+  int error_code;
+
+  ASSERT_EQ(ResourceMsg_RequestComplete::ID, message.type());
+
+  PickleIterator iter(message);
+  ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id));
+  ASSERT_TRUE(IPC::ReadParam(&message, &iter, &error_code));
+  ASSERT_EQ(error_code, expected_error_code);
+}
+
+void ExtractDataOffsetAndLength(const IPC::Message& message, int* data_offset,
+                                int* data_length) {
+  PickleIterator iter(message);
+  int request_id;
+  ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id));
+  ASSERT_TRUE(IPC::ReadParam(&message, &iter, data_offset));
+  ASSERT_TRUE(IPC::ReadParam(&message, &iter, data_length));
+}
+
 void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages,
                             const std::string& reference_data) {
   // A successful request will have received 4 messages:
@@ -807,12 +826,9 @@
   // should probably test multiple chunks later
   ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[2].type());
 
-  PickleIterator iter2(messages[2]);
-  ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &request_id));
   int data_offset;
-  ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_offset));
   int data_length;
-  ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_length));
+  ExtractDataOffsetAndLength(messages[2], &data_offset, &data_length);
 
   ASSERT_EQ(reference_data.size(), static_cast<size_t>(data_length));
   ASSERT_GE(shm_size, data_length);
@@ -823,7 +839,34 @@
   ASSERT_EQ(0, memcmp(reference_data.c_str(), data, data_length));
 
   // The last message should be all data received.
-  ASSERT_EQ(ResourceMsg_RequestComplete::ID, messages[3].type());
+  CheckRequestCompleteErrorCode(messages[3], net::OK);
+}
+
+void CheckSuccessfulRedirect(const std::vector<IPC::Message>& messages,
+                             const std::string& reference_data) {
+  ASSERT_EQ(5U, messages.size());
+  ASSERT_EQ(ResourceMsg_ReceivedRedirect::ID, messages[0].type());
+
+  const std::vector<IPC::Message> second_req_msgs =
+      std::vector<IPC::Message>(messages.begin() + 1, messages.end());
+  CheckSuccessfulRequest(second_req_msgs, reference_data);
+}
+
+void CheckSuccessfulDetachedRequest(
+    const std::vector<IPC::Message>& messages) {
+  // A successful request will have received 2 messages:
+  //     ReceivedResponse    (indicates headers received)
+  //     RequestComplete     (request is done)
+  //
+  // This function verifies that we received 2 messages and that they
+  // are appropriate.
+  ASSERT_EQ(2U, messages.size());
+
+  // The first messages should be received response
+  ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type());
+
+  // The last message should be all data received.
+  CheckRequestCompleteErrorCode(messages[1], net::OK);
 }
 
 void CheckFailedRequest(const std::vector<IPC::Message>& messages,
@@ -836,15 +879,8 @@
   if (messages.size() == 2) {
     EXPECT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type());
   }
-  EXPECT_EQ(ResourceMsg_RequestComplete::ID, messages[failure_index].type());
 
-  int request_id;
-  int error_code;
-
-  PickleIterator iter(messages[failure_index]);
-  EXPECT_TRUE(IPC::ReadParam(&messages[failure_index], &iter, &request_id));
-  EXPECT_TRUE(IPC::ReadParam(&messages[failure_index], &iter, &error_code));
-  EXPECT_EQ(expected_error, error_code);
+  CheckRequestCompleteErrorCode(messages[failure_index], expected_error);
 }
 
 // Tests whether many messages get dispatched properly.
@@ -852,6 +888,14 @@
   MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
   MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
   MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
+  MakeTestRequest(0, 4, net::URLRequestTestJob::test_url_4());
+  MakeTestRequest(0, 5, net::URLRequestTestJob::test_url_redirect_to_url_2());
+
+  // Finish the redirection
+  ResourceHostMsg_FollowRedirect redirect_msg(5, false, GURL());
+  bool msg_was_ok;
+  host_.OnMessageReceived(redirect_msg, filter_.get(), &msg_was_ok);
+  base::MessageLoop::current()->RunUntilIdle();
 
   // flush all the pending requests
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -860,35 +904,32 @@
   ResourceIPCAccumulator::ClassifiedMessages msgs;
   accum_.GetClassifiedMessages(&msgs);
 
-  // there are three requests, so we should have gotten them classified as such
-  ASSERT_EQ(3U, msgs.size());
+  // there are five requests, so we should have gotten them classified as such
+  ASSERT_EQ(5U, msgs.size());
 
   CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
   CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_2());
   CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3());
+  CheckSuccessfulRequest(msgs[3], net::URLRequestTestJob::test_data_4());
+  CheckSuccessfulRedirect(msgs[4], net::URLRequestTestJob::test_data_2());
 }
 
-void CheckCancelledRequestCompleteMessage(const IPC::Message& message) {
-  ASSERT_EQ(ResourceMsg_RequestComplete::ID, message.type());
-
-  int request_id;
-  int error_code;
-
-  PickleIterator iter(message);
-  ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id));
-  ASSERT_TRUE(IPC::ReadParam(&message, &iter, &error_code));
-
-  EXPECT_EQ(net::ERR_ABORTED, error_code);
-}
-
-// Tests whether messages get canceled properly. We issue three requests,
-// cancel one of them, and make sure that each sent the proper notifications.
+// Tests whether messages get canceled properly. We issue four requests,
+// cancel two of them, and make sure that each sent the proper notifications.
 TEST_F(ResourceDispatcherHostTest, Cancel) {
   MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
   MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
   MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
+  MakeTestRequestWithResourceType(filter_.get(), 0, 4,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
+
   CancelRequest(2);
 
+  // Cancel request must come from the renderer for a detachable resource to
+  // delay.
+  host_.CancelRequest(filter_->child_id(), 4, true);
+
   // flush all the pending requests
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
   base::MessageLoop::current()->RunUntilIdle();
@@ -896,16 +937,140 @@
   ResourceIPCAccumulator::ClassifiedMessages msgs;
   accum_.GetClassifiedMessages(&msgs);
 
-  // there are three requests, so we should have gotten them classified as such
-  ASSERT_EQ(3U, msgs.size());
+  // there are four requests, so we should have gotten them classified as such
+  ASSERT_EQ(4U, msgs.size());
 
   CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
   CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3());
+  // The detachable resource should have delayed its cancellation and completed.
+  CheckSuccessfulDetachedRequest(msgs[3]);
 
   // Check that request 2 got canceled.
   ASSERT_EQ(2U, msgs[1].size());
   ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type());
-  CheckCancelledRequestCompleteMessage(msgs[1][1]);
+  CheckRequestCompleteErrorCode(msgs[1][1], net::ERR_ABORTED);
+}
+
+// Shows that detachable requests will timeout if the request takes too long to
+// complete.
+TEST_F(ResourceDispatcherHostTest, DetachableResourceTimesOut) {
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::PREFETCH);  // detachable type
+  ResourceLoader* loader = host_.GetLoader(filter_->child_id(), 1);
+  ASSERT_TRUE(loader);
+  loader->set_detachable_delay_ms(200);
+  base::MessageLoop::current()->RunUntilIdle();
+  host_.CancelRequest(filter_->child_id(), 1, true);
+
+  EXPECT_EQ(1, host_.pending_requests());
+
+  // Wait until after the delay timer times out before we start processing any
+  // messages.
+  base::OneShotTimer<base::MessageLoop> timer;
+  timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210),
+              base::MessageLoop::current(), &base::MessageLoop::QuitWhenIdle);
+  base::MessageLoop::current()->Run();
+
+  // We should have cancelled the prefetch by now.
+  EXPECT_EQ(0, host_.pending_requests());
+
+  // In case any messages are still to be processed.
+  while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+  base::MessageLoop::current()->RunUntilIdle();
+
+  ResourceIPCAccumulator::ClassifiedMessages msgs;
+  accum_.GetClassifiedMessages(&msgs);
+
+  ASSERT_EQ(1U, msgs.size());
+
+  // The request should have cancelled.
+  ASSERT_EQ(2U, msgs[0].size());
+  ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type());
+  CheckRequestCompleteErrorCode(msgs[0][1], net::ERR_ABORTED);
+}
+
+// If the filter has disappeared then detachable resources should continue to
+// load.
+TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachable) {
+  ResourceHostMsg_Request request = CreateResourceRequest(
+      "GET", ResourceType::PREFETCH, net::URLRequestTestJob::test_url_4());
+
+  ResourceHostMsg_RequestResource msg(0, 1, request);
+  bool msg_was_ok;
+  host_.OnMessageReceived(msg, filter_, &msg_was_ok);
+
+  // Remove the filter before processing the request by simulating channel
+  // closure.
+  GlobalRequestID global_request_id(filter_->child_id(), 1);
+  ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(
+      host_.GetURLRequest(global_request_id));
+  info->filter_->OnChannelClosing();
+  info->filter_.reset();
+
+  EXPECT_EQ(1, host_.pending_requests());
+
+  KickOffRequest();
+
+  // Make sure the request wasn't canceled early.
+  EXPECT_EQ(1, host_.pending_requests());
+
+  while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_EQ(0, host_.pending_requests());
+
+  // Because the filter was gone, no messages should have been sent.
+  // TODO(jkarlin): It would be nice to verify that we successfully completed
+  // the request, but we have no messages to verify with.
+  ResourceIPCAccumulator::ClassifiedMessages msgs;
+  accum_.GetClassifiedMessages(&msgs);
+  ASSERT_EQ(0U, msgs.size());
+}
+
+// If the filter has disappeared (original process dies) then detachable
+// resources should continue to load, even when redirected.
+TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachableRedirect) {
+  ResourceHostMsg_Request request = CreateResourceRequest(
+      "GET", ResourceType::PREFETCH,
+      net::URLRequestTestJob::test_url_redirect_to_url_2());
+
+  ResourceHostMsg_RequestResource msg(0, 1, request);
+  bool msg_was_ok;
+  host_.OnMessageReceived(msg, filter_, &msg_was_ok);
+
+  // Remove the filter before processing the request by simulating channel
+  // closure.
+  GlobalRequestID global_request_id(filter_->child_id(), 1);
+  ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(
+      host_.GetURLRequest(global_request_id));
+  info->filter_->OnChannelClosing();
+  info->filter_.reset();
+
+  EXPECT_EQ(1, host_.pending_requests());
+  // Verify no redirects before resetting the filter.
+  net::URLRequest* url_request = host_.GetURLRequest(global_request_id);
+  EXPECT_EQ(1u, url_request->url_chain().size());
+  KickOffRequest();
+
+  // Verify that a redirect was followed.
+  EXPECT_EQ(2u, url_request->url_chain().size());
+
+  // Make sure the request wasn't canceled early.
+  EXPECT_EQ(1, host_.pending_requests());
+
+  // Finish up the request.
+  while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_EQ(0, host_.pending_requests());
+
+  // Because the filter was deleted, no messages should have been sent.
+  // TODO(jkarlin): It would be nice to verify that we successfully completed
+  // the request, but we have no messages to verify with.
+  ResourceIPCAccumulator::ClassifiedMessages msgs;
+  accum_.GetClassifiedMessages(&msgs);
+  ASSERT_EQ(0U, msgs.size());
 }
 
 TEST_F(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) {
@@ -950,7 +1115,7 @@
 
   // Check that request got canceled.
   ASSERT_EQ(1U, msgs[0].size());
-  CheckCancelledRequestCompleteMessage(msgs[0][0]);
+  CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ABORTED);
 
   // Make sure URLRequest is never started.
   EXPECT_EQ(0, url_request_jobs_created_count_);
@@ -1030,16 +1195,8 @@
   // Check the cancellation
   ASSERT_EQ(1U, msgs.size());
   ASSERT_EQ(1U, msgs[0].size());
-  ASSERT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][0].type());
 
-  int request_id;
-  int error_code;
-
-  PickleIterator iter(msgs[0][0]);
-  ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id));
-  ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code));
-
-  EXPECT_EQ(net::ERR_ACCESS_DENIED, error_code);
+  CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ACCESS_DENIED);
 }
 
 // The host delegate acts as a second one so we can have some requests
@@ -1077,15 +1234,23 @@
   ResourceHostMsg_Request request = CreateResourceRequest(
       "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
 
-  MakeTestRequest(test_filter.get(), 0, 1,
-                  net::URLRequestTestJob::test_url_1());
+  MakeTestRequestWithResourceType(test_filter.get(), 0, 1,
+                                  net::URLRequestTestJob::test_url_1(),
+                                  ResourceType::SUB_RESOURCE);
 
   // request 2 goes to us
   MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
 
   // request 3 goes to the test delegate
-  MakeTestRequest(test_filter.get(), 0, 3,
-                  net::URLRequestTestJob::test_url_3());
+  MakeTestRequestWithResourceType(test_filter.get(), 0, 3,
+                                  net::URLRequestTestJob::test_url_3(),
+                                  ResourceType::SUB_RESOURCE);
+
+  // request 4 goes to us
+  MakeTestRequestWithResourceType(filter_.get(), 0, 4,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
+
 
   // Make sure all requests have finished stage one. test_url_1 will have
   // finished.
@@ -1097,7 +1262,9 @@
   // breaks the whole test.
   //EXPECT_EQ(3, host_.pending_requests());
 
-  // Process each request for one level so one callback is called.
+  // Process test_url_2 and test_url_3 for one level so one callback is called.
+  // We'll cancel test_url_4 (detachable) before processing it to verify that it
+  // delays the cancel.
   for (int i = 0; i < 2; i++)
     EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
 
@@ -1113,11 +1280,52 @@
   // The test delegate should not have gotten any messages after being canceled.
   ASSERT_EQ(0, test_filter->received_after_canceled_);
 
-  // We should have gotten exactly one result.
+  // We should have gotten two results.
   ResourceIPCAccumulator::ClassifiedMessages msgs;
   accum_.GetClassifiedMessages(&msgs);
-  ASSERT_EQ(1U, msgs.size());
+  ASSERT_EQ(2U, msgs.size());
   CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2());
+  // We cancelled the detachable request before it finished, and it should have
+  // delayed and completed regardless.
+  CheckSuccessfulDetachedRequest(msgs[1]);
+}
+
+TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachableTimesOut) {
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
+  ResourceLoader* loader = host_.GetLoader(filter_->child_id(), 1);
+  EXPECT_TRUE(loader);
+  loader->set_detachable_delay_ms(200);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Cancel the requests to the test process.
+  host_.CancelRequestsForProcess(filter_->child_id());
+  EXPECT_EQ(1, host_.pending_requests());
+
+  // Wait until after the delay timer times out before we start processing any
+  // messages.
+  base::OneShotTimer<base::MessageLoop> timer;
+  timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210),
+              base::MessageLoop::current(), &base::MessageLoop::QuitWhenIdle);
+  base::MessageLoop::current()->Run();
+
+  // We should have cancelled the prefetch by now.
+  EXPECT_EQ(0, host_.pending_requests());
+
+  // In case any messages are still to be processed.
+  while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+  base::MessageLoop::current()->RunUntilIdle();
+
+  ResourceIPCAccumulator::ClassifiedMessages msgs;
+  accum_.GetClassifiedMessages(&msgs);
+
+  ASSERT_EQ(1U, msgs.size());
+
+  // The request should have cancelled.
+  ASSERT_EQ(2U, msgs[0].size());
+  ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type());
+  CheckRequestCompleteErrorCode(msgs[0][1], net::ERR_ABORTED);
 }
 
 // Tests blocking and resuming requests.
@@ -1186,6 +1394,10 @@
   MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2());
   MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
   MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1());
+  // Blocked detachable resources should not delay cancellation.
+  MakeTestRequestWithResourceType(filter_.get(), 1, 5,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
 
   // Flush all the pending requests.
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1218,12 +1430,21 @@
 
   host_.BlockRequestsForRoute(second_filter->child_id(), 0);
 
-  MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1());
-  MakeTestRequest(second_filter.get(), 0, 2,
-                  net::URLRequestTestJob::test_url_2());
-  MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3());
-  MakeTestRequest(second_filter.get(), 0, 4,
-                  net::URLRequestTestJob::test_url_1());
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1,
+                                  net::URLRequestTestJob::test_url_1(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(second_filter.get(), 0, 2,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 0, 3,
+                                  net::URLRequestTestJob::test_url_3(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(second_filter.get(), 0, 4,
+                                  net::URLRequestTestJob::test_url_1(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(second_filter.get(), 0, 5,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
 
   // Simulate process death.
   host_.CancelRequestsForProcess(second_filter->child_id());
@@ -1235,7 +1456,8 @@
   ResourceIPCAccumulator::ClassifiedMessages msgs;
   accum_.GetClassifiedMessages(&msgs);
 
-  // The 2 requests for the RVH 0 should have been processed.
+  // The 2 requests for the RVH 0 should have been processed.  Note that
+  // blocked detachable requests are canceled without delay.
   ASSERT_EQ(2U, msgs.size());
 
   CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
@@ -1257,13 +1479,30 @@
   host_.BlockRequestsForRoute(filter_->child_id(), 2);
   host_.BlockRequestsForRoute(second_filter->child_id(), 1);
 
-  MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1());
-  MakeTestRequest(filter_.get(), 1, 2, net::URLRequestTestJob::test_url_2());
-  MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3());
-  MakeTestRequest(second_filter.get(), 1, 4,
-                  net::URLRequestTestJob::test_url_1());
-  MakeTestRequest(filter_.get(), 2, 5, net::URLRequestTestJob::test_url_2());
-  MakeTestRequest(filter_.get(), 2, 6, net::URLRequestTestJob::test_url_3());
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1,
+                                  net::URLRequestTestJob::test_url_1(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 1, 2,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 0, 3,
+                                  net::URLRequestTestJob::test_url_3(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(second_filter.get(), 1, 4,
+                                  net::URLRequestTestJob::test_url_1(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 2, 5,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 2, 6,
+                                  net::URLRequestTestJob::test_url_3(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 0, 7,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
+  MakeTestRequestWithResourceType(second_filter.get(), 1, 8,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
 
   host_.CancelRequestsForProcess(filter_->child_id());
   host_.CancelRequestsForProcess(second_filter->child_id());
@@ -1322,22 +1561,27 @@
 
   // Saturate the number of outstanding requests for our process.
   for (size_t i = 0; i < kMaxRequests; ++i) {
-    MakeTestRequest(filter_.get(), 0, i + 1,
-                    net::URLRequestTestJob::test_url_2());
+    MakeTestRequestWithResourceType(filter_.get(), 0, i + 1,
+                                    net::URLRequestTestJob::test_url_2(),
+                                    ResourceType::SUB_RESOURCE);
   }
 
   // Issue two more requests for our process -- these should fail immediately.
-  MakeTestRequest(filter_.get(), 0, kMaxRequests + 1,
-                  net::URLRequestTestJob::test_url_2());
-  MakeTestRequest(filter_.get(), 0, kMaxRequests + 2,
-                  net::URLRequestTestJob::test_url_2());
+  MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 1,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 2,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
 
   // Issue two requests for the second process -- these should succeed since
   // it is just process 0 that is saturated.
-  MakeTestRequest(second_filter.get(), 0, kMaxRequests + 3,
-                  net::URLRequestTestJob::test_url_2());
-  MakeTestRequest(second_filter.get(), 0, kMaxRequests + 4,
-                  net::URLRequestTestJob::test_url_2());
+  MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 3,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
+  MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 4,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
 
   // Flush all the pending requests.
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1388,23 +1632,27 @@
 
   // Saturate the number of outstanding requests for our process.
   for (size_t i = 0; i < kMaxRequestsPerProcess; ++i) {
-    MakeTestRequest(filter_.get(), 0, i + 1,
-                    net::URLRequestTestJob::test_url_2());
+    MakeTestRequestWithResourceType(filter_.get(), 0, i + 1,
+                                    net::URLRequestTestJob::test_url_2(),
+                                    ResourceType::SUB_RESOURCE);
   }
 
   // Issue another request for our process -- this should fail immediately.
-  MakeTestRequest(filter_.get(), 0, kMaxRequestsPerProcess + 1,
-                  net::URLRequestTestJob::test_url_2());
+  MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequestsPerProcess + 1,
+                                  net::URLRequestTestJob::test_url_2(),
+                                  ResourceType::SUB_RESOURCE);
 
   // Issue a request for the second process -- this should succeed, because it
   // is just process 0 that is saturated.
-  MakeTestRequest(second_filter.get(), 0, kMaxRequestsPerProcess + 2,
-                  net::URLRequestTestJob::test_url_2());
+  MakeTestRequestWithResourceType(
+      second_filter.get(), 0, kMaxRequestsPerProcess + 2,
+      net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE);
 
   // Issue a request for the third process -- this should fail, because the
   // global limit has been reached.
-  MakeTestRequest(third_filter.get(), 0, kMaxRequestsPerProcess + 3,
-                  net::URLRequestTestJob::test_url_2());
+  MakeTestRequestWithResourceType(
+      third_filter.get(), 0, kMaxRequestsPerProcess + 3,
+      net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE);
 
   // Flush all the pending requests.
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1544,11 +1792,11 @@
   std::string response_data("<html><title>Test One</title></html>");
   SetResponse(raw_headers, response_data);
 
-  // Only MAIN_FRAMEs can trigger a download.
-  SetResourceType(ResourceType::MAIN_FRAME);
-
   HandleScheme("http");
-  MakeTestRequest(0, 1, GURL("http:bla"));
+
+  // Only MAIN_FRAMEs can trigger a download.
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("http:bla"),
+                                  ResourceType::MAIN_FRAME);
 
   // Flush all pending requests.
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1563,15 +1811,7 @@
 
   // The RequestComplete message should have had the error code of
   // ERR_FILE_NOT_FOUND.
-  int request_id;
-  int error_code;
-
-  PickleIterator iter(msgs[0][0]);
-  EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id));
-  EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code));
-
-  EXPECT_EQ(1, request_id);
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, error_code);
+  CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_FILE_NOT_FOUND);
 }
 
 // Test for http://crbug.com/76202 .  We don't want to destroy a
@@ -1595,11 +1835,12 @@
   response_data.resize(1025, ' ');
 
   SetResponse(raw_headers, response_data);
-  SetResourceType(ResourceType::MAIN_FRAME);
   SetDelayedCompleteJobGeneration(true);
   HandleScheme("http");
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  GURL("http://example.com/blah"),
+                                  ResourceType::MAIN_FRAME);
   // Return some data so that the request is identified as a download
   // and the proper resource handlers are created.
   EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
@@ -1630,11 +1871,12 @@
   response_data.resize(1025, ' ');
 
   SetResponse(raw_headers, response_data);
-  SetResourceType(ResourceType::MAIN_FRAME);
   SetDelayedCompleteJobGeneration(true);
   HandleScheme("http");
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  GURL("http://example.com/blah"),
+                                  ResourceType::MAIN_FRAME);
   // Return some data so that the request is identified as a download
   // and the proper resource handlers are created.
   EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
@@ -1658,6 +1900,33 @@
   EXPECT_EQ(0, host_.pending_requests());
 }
 
+TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextDetachable) {
+  EXPECT_EQ(0, host_.pending_requests());
+
+  int render_view_id = 0;
+  int request_id = 1;
+
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  net::URLRequestTestJob::test_url_4(),
+                                  ResourceType::PREFETCH);  // detachable type
+
+  // Simulate a cancel coming from the renderer.
+  host_.CancelRequest(filter_->child_id(), request_id, true);
+
+  // Since the request had already started processing as detachable,
+  // the cancellation above should have been ignored and the request
+  // should still be alive.
+  EXPECT_EQ(1, host_.pending_requests());
+
+  // Cancelling by other methods should also be delayed.
+  host_.CancelRequestsForProcess(render_view_id);
+  EXPECT_EQ(1, host_.pending_requests());
+
+  // Cancelling by context should work.
+  host_.CancelRequestsForContext(filter_->resource_context());
+  EXPECT_EQ(0, host_.pending_requests());
+}
+
 // Test the cancelling of requests that are being transferred to a new renderer
 // due to a redirection.
 TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
@@ -1671,10 +1940,12 @@
   std::string response_data("<html>foobar</html>");
 
   SetResponse(raw_headers, response_data);
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                               GURL("http://example.com/blah"),
+                               ResourceType::MAIN_FRAME);
+
 
   GlobalRequestID global_request_id(filter_->child_id(), request_id);
   host_.MarkAsTransferredNavigation(global_request_id,
@@ -1711,7 +1982,6 @@
   SetResponse("HTTP/1.1 302 Found\n"
               "Location: http://other.com/blech\n\n");
 
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
   // Temporarily replace ContentBrowserClient with one that will trigger the
@@ -1719,7 +1989,8 @@
   TransfersAllNavigationsContentBrowserClient new_client;
   ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                  GURL("http://example.com/blah"), ResourceType::MAIN_FRAME);
 
   // Now that we're blocked on the redirect, update the response and unblock by
   // telling the AsyncResourceHandler to follow the redirect.
@@ -1782,7 +2053,6 @@
   SetResponse("HTTP/1.1 302 Found\n"
               "Location: http://other.com/blech\n\n");
 
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
   // Temporarily replace ContentBrowserClient with one that will trigger the
@@ -1790,7 +2060,9 @@
   TransfersAllNavigationsContentBrowserClient new_client;
   ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  GURL("http://example.com/blah"),
+                                  ResourceType::MAIN_FRAME);
 
   // Now that we're blocked on the redirect, update the response and unblock by
   // telling the AsyncResourceHandler to follow the redirect.  Use a text/plain
@@ -1854,7 +2126,6 @@
               "Location: http://other.com/blech\n\n");
   const std::string kResponseBody = "hello world";
 
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
   // Temporarily replace ContentBrowserClient with one that will trigger the
@@ -1943,7 +2214,6 @@
   SetResponse("HTTP/1.1 302 Found\n"
               "Location: http://other.com/blech\n\n");
 
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
   // Temporarily replace ContentBrowserClient with one that will trigger the
@@ -1951,7 +2221,9 @@
   TransfersAllNavigationsContentBrowserClient new_client;
   ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
 
-  MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  GURL("http://example.com/blah"),
+                                  ResourceType::MAIN_FRAME);
 
   // Now that we're blocked on the redirect, simulate hitting another redirect.
   SetResponse("HTTP/1.1 302 Found\n"
@@ -2024,10 +2296,10 @@
 TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) {
   EXPECT_EQ(0, host_.pending_requests());
 
-  SetResourceType(ResourceType::MAIN_FRAME);
   HandleScheme("http");
 
-  MakeTestRequest(0, 1, GURL("foo://bar"));
+  MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("foo://bar"),
+                                  ResourceType::MAIN_FRAME);
 
   // Flush all pending requests.
   while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -2042,15 +2314,7 @@
 
   // The RequestComplete message should have the error code of
   // ERR_UNKNOWN_URL_SCHEME.
-  int request_id;
-  int error_code;
-
-  PickleIterator iter(msgs[0][0]);
-  EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id));
-  EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code));
-
-  EXPECT_EQ(1, request_id);
-  EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, error_code);
+  CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_UNKNOWN_URL_SCHEME);
 }
 
 TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) {
@@ -2074,6 +2338,63 @@
   EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][size - 1].type());
 }
 
+// Request a very large detachable resource and cancel part way. Some of the
+// data should have been sent to the renderer, but not all.
+TEST_F(ResourceDispatcherHostTest, DataSentBeforeDetach) {
+  EXPECT_EQ(0, host_.pending_requests());
+
+  int render_view_id = 0;
+  int request_id = 1;
+
+  std::string raw_headers("HTTP\n"
+                          "Content-type: image/jpeg\n\n");
+  std::string response_data("01234567890123456789\x01foobar");
+
+  // Create a response larger than kMaxAllocationSize (currently 32K). Note
+  // that if this increase beyond 512K we'll need to make the response longer.
+  const int kAllocSize = 1024*512;
+  response_data.resize(kAllocSize, ' ');
+
+  SetResponse(raw_headers, response_data);
+  SetDelayedCompleteJobGeneration(true);
+  HandleScheme("http");
+
+  MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+                                  GURL("http://example.com/blah"),
+                                  ResourceType::PREFETCH);
+
+  // Get a bit of data before cancelling.
+  EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
+
+  // Simulate a cancellation coming from the renderer.
+  ResourceHostMsg_CancelRequest msg(request_id);
+  bool msg_was_ok;
+  host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok);
+
+  EXPECT_EQ(1, host_.pending_requests());
+
+  while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+
+  // Sort all the messages we saw by request.
+  ResourceIPCAccumulator::ClassifiedMessages msgs;
+  accum_.GetClassifiedMessages(&msgs);
+
+  EXPECT_EQ(4U, msgs[0].size());
+
+  // Figure out how many bytes were received by the renderer.
+  int data_offset;
+  int data_length;
+  ExtractDataOffsetAndLength(msgs[0][2], &data_offset, &data_length);
+  EXPECT_LT(0, data_length);
+  EXPECT_GT(kAllocSize, data_length);
+
+  // Verify the data that was received before cancellation. Also verify that the
+  // response completed.
+  CheckSuccessfulRequest(
+      msgs[0],
+      std::string(response_data.begin(), response_data.begin() + data_length));
+}
+
 TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) {
   EXPECT_EQ(0, host_.pending_requests());
 
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 55add72..a995259 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -7,7 +7,9 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/cross_site_resource_handler.h"
 #include "content/browser/loader/resource_loader_delegate.h"
@@ -16,6 +18,7 @@
 #include "content/browser/ssl/ssl_manager.h"
 #include "content/common/ssl_status_serialization.h"
 #include "content/public/browser/cert_store.h"
+#include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/common/content_client.h"
@@ -27,7 +30,6 @@
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/ssl/client_cert_store.h"
-#include "net/ssl/client_cert_store_impl.h"
 #include "webkit/browser/appcache/appcache_interceptor.h"
 
 using base::TimeDelta;
@@ -36,6 +38,13 @@
 namespace content {
 namespace {
 
+// TODO(jkarlin): The value is high to reduce the chance of the detachable
+// request timing out, forcing a blocked second request to open a new connection
+// and start over. Reduce this value once we have a better idea of what it
+// should be and once we stop blocking multiple simultaneous requests for the
+// same resource (see bugs 46104 and 31014).
+const int kDefaultDetachableDelayOnCancelMs = 30000;
+
 void PopulateResourceResponse(net::URLRequest* request,
                               ResourceResponse* response) {
   response->head.error_code = request->status().error();
@@ -67,12 +76,17 @@
 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
                                scoped_ptr<ResourceHandler> handler,
                                ResourceLoaderDelegate* delegate)
-    : weak_ptr_factory_(this) {
-  scoped_ptr<net::ClientCertStore> client_cert_store;
-#if !defined(USE_OPENSSL)
-  client_cert_store.reset(new net::ClientCertStoreImpl());
-#endif
-  Init(request.Pass(), handler.Pass(), delegate, client_cert_store.Pass());
+    : deferred_stage_(DEFERRED_NONE),
+      request_(request.Pass()),
+      handler_(handler.Pass()),
+      delegate_(delegate),
+      last_upload_position_(0),
+      waiting_for_upload_progress_ack_(false),
+      is_transferring_(false),
+      detachable_delay_on_cancel_ms_(kDefaultDetachableDelayOnCancelMs),
+      weak_ptr_factory_(this) {
+  request_->set_delegate(this);
+  handler_->SetController(this);
 }
 
 ResourceLoader::~ResourceLoader() {
@@ -189,32 +203,6 @@
   waiting_for_upload_progress_ack_ = false;
 }
 
-ResourceLoader::ResourceLoader(
-    scoped_ptr<net::URLRequest> request,
-    scoped_ptr<ResourceHandler> handler,
-    ResourceLoaderDelegate* delegate,
-    scoped_ptr<net::ClientCertStore> client_cert_store)
-    : weak_ptr_factory_(this) {
-  Init(request.Pass(), handler.Pass(), delegate, client_cert_store.Pass());
-}
-
-void ResourceLoader::Init(scoped_ptr<net::URLRequest> request,
-                          scoped_ptr<ResourceHandler> handler,
-                          ResourceLoaderDelegate* delegate,
-                          scoped_ptr<net::ClientCertStore> client_cert_store) {
-  deferred_stage_ = DEFERRED_NONE;
-  request_ = request.Pass();
-  handler_ = handler.Pass();
-  delegate_ = delegate;
-  last_upload_position_ = 0;
-  waiting_for_upload_progress_ack_ = false;
-  is_transferring_ = false;
-  client_cert_store_ = client_cert_store.Pass();
-
-  request_->set_delegate(this);
-  handler_->SetController(this);
-}
-
 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
                                         const GURL& new_url,
                                         bool* defer) {
@@ -289,19 +277,12 @@
     return;
   }
 
-#if !defined(USE_OPENSSL)
-  client_cert_store_->GetClientCerts(*cert_info, &cert_info->client_certs);
-  if (cert_info->client_certs.empty()) {
-    // No need to query the user if there are no certs to choose from.
-    request_->ContinueWithCertificate(NULL);
-    return;
-  }
-#endif
-
   DCHECK(!ssl_client_auth_handler_.get())
       << "OnCertificateRequested called with ssl_client_auth_handler pending";
-  ssl_client_auth_handler_ = new SSLClientAuthHandler(request_.get(),
-                                                      cert_info);
+  ssl_client_auth_handler_ = new SSLClientAuthHandler(
+      GetRequestInfo()->GetContext()->CreateClientCertStore(),
+      request_.get(),
+      cert_info);
   ssl_client_auth_handler_->SelectCertificate();
 }
 
@@ -458,6 +439,18 @@
   delegate_->DidStartRequest(this);
 }
 
+void ResourceLoader::Detach() {
+  ResourceRequestInfoImpl* info = GetRequestInfo();
+
+  if (info->is_detached())
+    return;
+  info->set_detached();
+  detached_timer_.reset(new base::OneShotTimer<ResourceLoader>());
+  detached_timer_->Start(
+      FROM_HERE, TimeDelta::FromMilliseconds(detachable_delay_on_cancel_ms_),
+      this, &ResourceLoader::Cancel);
+}
+
 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
   VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
 
@@ -469,6 +462,11 @@
   if (from_renderer && (info->is_download() || info->is_stream()))
     return;
 
+  if (from_renderer && info->is_detachable()) {
+    Detach();
+    return;
+  }
+
   // TODO(darin): Perhaps we should really be looking to see if the status is
   // IO_PENDING?
   bool was_pending = request_->is_pending();
diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h
index 6a611a7..8662cca 100644
--- a/content/browser/loader/resource_loader.h
+++ b/content/browser/loader/resource_loader.h
@@ -8,16 +8,13 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "content/browser/loader/resource_handler.h"
 #include "content/browser/ssl/ssl_error_handler.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/resource_controller.h"
 #include "net/url_request/url_request.h"
 
-namespace net {
-class ClientCertStore;
-}
-
 namespace content {
 class ResourceDispatcherHostLoginDelegate;
 class ResourceLoaderDelegate;
@@ -39,6 +36,10 @@
   void StartRequest();
   void CancelRequest(bool from_renderer);
 
+  // Sets the resource as detached and starts a timer to cancel the request in
+  // the future.
+  void Detach();
+
   void ReportUploadProgress();
 
   bool is_transferring() const { return is_transferring_; }
@@ -54,19 +55,13 @@
   // IPC message handlers:
   void OnUploadProgressACK();
 
+  void set_detachable_delay_ms(int delay) {
+    detachable_delay_on_cancel_ms_ = delay;
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ResourceLoaderTest, ClientCertStoreLookup);
-
-  ResourceLoader(scoped_ptr<net::URLRequest> request,
-                 scoped_ptr<ResourceHandler> handler,
-                 ResourceLoaderDelegate* delegate,
-                 scoped_ptr<net::ClientCertStore> client_cert_store);
-
-  // Initialization logic shared between the public and private constructor.
-  void Init(scoped_ptr<net::URLRequest> request,
-            scoped_ptr<ResourceHandler> handler,
-            ResourceLoaderDelegate* delegate,
-            scoped_ptr<net::ClientCertStore> client_cert_store);
+  FRIEND_TEST_ALL_PREFIXES(ResourceLoaderTest, ClientCertStoreNull);
 
   // net::URLRequest::Delegate implementation:
   virtual void OnReceivedRedirect(net::URLRequest* request,
@@ -133,7 +128,8 @@
   // which point we'll receive a new ResourceHandler.
   bool is_transferring_;
 
-  scoped_ptr<net::ClientCertStore> client_cert_store_;
+  int detachable_delay_on_cancel_ms_;
+  scoped_ptr<base::OneShotTimer<ResourceLoader> > detached_timer_;
 
   base::WeakPtrFactory<ResourceLoader> weak_ptr_factory_;
 
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index bf4f52f..d228300 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -48,12 +48,13 @@
   }
 
   // net::ClientCertStore:
-  virtual bool GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                              net::CertificateList* selected_certs) OVERRIDE {
+  virtual void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+                              net::CertificateList* selected_certs,
+                              const base::Closure& callback) OVERRIDE {
     ++request_count_;
     requested_authorities_ = cert_request_info.cert_authorities;
     *selected_certs = response_;
-    return true;
+    callback.Run();
   }
 
  private:
@@ -143,6 +144,23 @@
   int call_count_;
 };
 
+class ResourceContextStub : public MockResourceContext {
+ public:
+  explicit ResourceContextStub(net::URLRequestContext* test_request_context)
+      : MockResourceContext(test_request_context) {}
+
+  virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore() OVERRIDE {
+    return dummy_cert_store_.Pass();
+  }
+
+  void SetClientCertStore(scoped_ptr<net::ClientCertStore> store) {
+    dummy_cert_store_ = store.Pass();
+  }
+
+ private:
+  scoped_ptr<net::ClientCertStore> dummy_cert_store_;
+};
+
 }  // namespace
 
 class ResourceLoaderTest : public testing::Test,
@@ -182,12 +200,9 @@
   content::TestBrowserThreadBundle thread_bundle_;
 
   net::TestURLRequestContext test_url_request_context_;
-  content::MockResourceContext resource_context_;
+  ResourceContextStub resource_context_;
 };
 
-// When OpenSSL is used, client cert store is not being queried in
-// ResourceLoader.
-#if !defined(USE_OPENSSL)
 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested()
 // causes client cert store to be queried for certificates and if the returned
 // certificates are correctly passed to the content browser client for
@@ -218,10 +233,11 @@
   // later.
   net::URLRequest* raw_ptr_to_request = request.get();
   ClientCertStoreStub* raw_ptr_to_store = test_store.get();
+  resource_context_.SetClientCertStore(
+      test_store.PassAs<net::ClientCertStore>());
 
   scoped_ptr<ResourceHandler> resource_handler(new ResourceHandlerStub());
-  ResourceLoader loader(request.Pass(), resource_handler.Pass(), this,
-                        test_store.PassAs<net::ClientCertStore>());
+  ResourceLoader loader(request.Pass(), resource_handler.Pass(), this);
 
   // Prepare a dummy certificate request.
   scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
@@ -250,6 +266,52 @@
   EXPECT_EQ(1, test_client.call_count());
   EXPECT_EQ(dummy_certs, test_client.passed_certs());
 }
-#endif  // !defined(OPENSSL)
+
+// Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested()
+// on a platform with a NULL client cert store still calls the content browser
+// client for selection.
+TEST_F(ResourceLoaderTest, ClientCertStoreNull) {
+  const int kRenderProcessId = 1;
+  const int kRenderViewId = 2;
+
+  scoped_ptr<net::URLRequest> request(new net::URLRequest(
+      GURL("dummy"), NULL, resource_context_.GetRequestContext()));
+  ResourceRequestInfo::AllocateForTesting(request.get(),
+                                          ResourceType::MAIN_FRAME,
+                                          &resource_context_,
+                                          kRenderProcessId,
+                                          kRenderViewId,
+                                          false);
+
+  // Ownership of the |request| is about to be turned over to ResourceLoader. We
+  // need to keep a raw pointer copy to access this object later.
+  net::URLRequest* raw_ptr_to_request = request.get();
+
+  scoped_ptr<ResourceHandler> resource_handler(new ResourceHandlerStub());
+  ResourceLoader loader(request.Pass(), resource_handler.Pass(), this);
+
+  // Prepare a dummy certificate request.
+  scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
+      new net::SSLCertRequestInfo());
+  std::vector<std::string> dummy_authority(1, "dummy");
+  cert_request_info->cert_authorities = dummy_authority;
+
+  // Plug in test content browser client.
+  SelectCertificateBrowserClient test_client;
+  ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
+
+  // Everything is set up. Trigger the resource loader certificate request event
+  // and run the message loop.
+  loader.OnCertificateRequested(raw_ptr_to_request, cert_request_info.get());
+  base::RunLoop().RunUntilIdle();
+
+  // Restore the original content browser client.
+  SetBrowserClientForTesting(old_client);
+
+  // Check if the SelectClientCertificate was called on the content browser
+  // client.
+  EXPECT_EQ(1, test_client.call_count());
+  EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
+}
 
 }  // namespace content
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 5af13db..3ff3f19 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -45,6 +45,7 @@
           PAGE_TRANSITION_LINK,              // transition_type
           false,                             // is_download
           false,                             // is_stream
+          false,                             // is_detachable
           true,                              // allow_download
           false,                             // has_user_gesture
           WebKit::WebReferrerPolicyDefault,  // referrer_policy
@@ -97,6 +98,7 @@
     PageTransition transition_type,
     bool is_download,
     bool is_stream,
+    bool is_detachable,
     bool allow_download,
     bool has_user_gesture,
     WebKit::WebReferrerPolicy referrer_policy,
@@ -115,6 +117,8 @@
       parent_frame_id_(parent_frame_id),
       is_download_(is_download),
       is_stream_(is_stream),
+      is_detachable_(is_detachable),
+      is_detached_(false),
       allow_download_(allow_download),
       has_user_gesture_(has_user_gesture),
       was_ignored_by_handler_(false),
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 6947315..1ab85e3 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -51,6 +52,7 @@
       PageTransition transition_type,
       bool is_download,
       bool is_stream,
+      bool is_detachable,
       bool allow_download,
       bool has_user_gesture,
       WebKit::WebReferrerPolicy referrer_policy,
@@ -123,6 +125,17 @@
   bool is_stream() const { return is_stream_; }
   void set_is_stream(bool stream) { is_stream_ = stream; }
 
+  // Whether this is a detachable resource. Detachable resource requests can
+  // live beyond the life of the renderer.
+  bool is_detachable() const { return is_detachable_; }
+  void set_is_detachable(bool is_detachable) { is_detachable_ = is_detachable; }
+
+  // Detached resources are detachable resources that have ignored a request by
+  // the renderer to cancel and will continue to fetch but stops sending
+  // messages to the renderer. Detached resources eventually timeout.
+  bool is_detached() const { return is_detached_; }
+  void set_detached() { is_detached_ = true; }
+
   void set_was_ignored_by_handler(bool value) {
     was_ignored_by_handler_ = value;
   }
@@ -133,6 +146,10 @@
   void set_memory_cost(int cost) { memory_cost_ = cost; }
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
+                           DeletedFilterDetachable);
+  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
+                           DeletedFilterDetachableRedirect);
   // Non-owning, may be NULL.
   CrossSiteResourceHandler* cross_site_handler_;
 
@@ -147,6 +164,8 @@
   int64 parent_frame_id_;
   bool is_download_;
   bool is_stream_;
+  bool is_detachable_;
+  bool is_detached_;
   bool allow_download_;
   bool has_user_gesture_;
   bool was_ignored_by_handler_;
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 0277783..d458936 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -90,7 +90,7 @@
   }
 
   void Start() {
-    TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request_, "Queued");
+    TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued");
     ready_ = true;
     if (deferred_ && request_->status().is_success()) {
       deferred_ = false;
@@ -336,6 +336,7 @@
 //   * Higher priority requests (>= net::LOW).
 //   * Synchronous requests.
 //   * Requests to SPDY-capable origin servers.
+//   * Non-HTTP[S] requests.
 //
 // 2. The remainder are delayable requests, which follow these rules:
 //
@@ -347,6 +348,13 @@
 bool ResourceScheduler::ShouldStartRequest(ScheduledResourceRequest* request,
                                            Client* client) const {
   const net::URLRequest& url_request = *request->url_request();
+
+  // TODO(simonjam): This may end up causing disk contention. We should
+  // experiment with throttling if that happens.
+  if (!url_request.url().SchemeIsHTTPOrHTTPS()) {
+    return true;
+  }
+
   const net::HttpServerProperties& http_server_properties =
       *url_request.context()->http_server_properties();
 
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index 6a0bd28..adcb74e 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -155,6 +155,7 @@
         PAGE_TRANSITION_LINK,              // transition_type
         false,                             // is_download
         false,                             // is_stream
+        false,                             // is_detachable
         true,                              // allow_download
         false,                             // has_user_gesture
         WebKit::WebReferrerPolicyDefault,  // referrer_policy
@@ -430,6 +431,16 @@
   EXPECT_FALSE(idle->started());
 }
 
+TEST_F(ResourceSchedulerTest, NonHTTPSchedulesImmediately) {
+  // Dummies to enforce scheduling.
+  scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
+  scoped_ptr<TestRequest> low(NewRequest("http://host/high", net::LOWEST));
+
+  scoped_ptr<TestRequest> request(
+      NewRequest("chrome-extension://req", net::LOWEST));
+  EXPECT_TRUE(request->started());
+}
+
 }  // unnamed namespace
 
 }  // namespace content
diff --git a/content/browser/loader/upload_data_stream_builder.cc b/content/browser/loader/upload_data_stream_builder.cc
index 3ac99a6..ba7cca7 100644
--- a/content/browser/loader/upload_data_stream_builder.cc
+++ b/content/browser/loader/upload_data_stream_builder.cc
@@ -70,11 +70,8 @@
     const ResourceRequestBody::Element& element,
     std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
   DCHECK(blob_context);
-  std::string uuid = element.blob_uuid();
-  if (uuid.empty())
-    uuid = blob_context->LookupUuidFromDeprecatedURL(element.blob_url());
   scoped_ptr<webkit_blob::BlobDataHandle> handle =
-      blob_context->GetBlobDataFromUUID(uuid);
+      blob_context->GetBlobDataFromUUID(element.blob_uuid());
   DCHECK(handle);
   if (!handle)
     return;
diff --git a/content/browser/media/android/browser_demuxer_android.cc b/content/browser/media/android/browser_demuxer_android.cc
index 8ddc711..8480b14 100644
--- a/content/browser/media/android/browser_demuxer_android.cc
+++ b/content/browser/media/android/browser_demuxer_android.cc
@@ -38,10 +38,11 @@
   }
 
   virtual void RequestDemuxerSeek(
-      const base::TimeDelta& time_to_seek) OVERRIDE {
+      const base::TimeDelta& time_to_seek,
+      bool is_browser_seek) OVERRIDE {
     DCHECK(ClientIDExists()) << demuxer_client_id_;
     demuxer_->Send(new MediaPlayerMsg_DemuxerSeekRequest(
-        demuxer_client_id_, time_to_seek));
+        demuxer_client_id_, time_to_seek, is_browser_seek));
   }
 
  private:
@@ -127,11 +128,13 @@
     client->OnDemuxerDataAvailable(data);
 }
 
-void BrowserDemuxerAndroid::OnDemuxerSeekDone(int demuxer_client_id) {
+void BrowserDemuxerAndroid::OnDemuxerSeekDone(
+    int demuxer_client_id,
+    const base::TimeDelta& actual_browser_seek_time) {
   media::DemuxerAndroidClient* client =
       demuxer_clients_.Lookup(demuxer_client_id);
   if (client)
-    client->OnDemuxerSeekDone();
+    client->OnDemuxerSeekDone(actual_browser_seek_time);
 }
 
 void BrowserDemuxerAndroid::OnDurationChanged(int demuxer_client_id,
diff --git a/content/browser/media/android/browser_demuxer_android.h b/content/browser/media/android/browser_demuxer_android.h
index 58cbbd7..7601831 100644
--- a/content/browser/media/android/browser_demuxer_android.h
+++ b/content/browser/media/android/browser_demuxer_android.h
@@ -49,7 +49,8 @@
                       const media::DemuxerConfigs& configs);
   void OnReadFromDemuxerAck(int demuxer_client_id,
                             const media::DemuxerData& data);
-  void OnDemuxerSeekDone(int demuxer_client_id);
+  void OnDemuxerSeekDone(int demuxer_client_id,
+                         const base::TimeDelta& actual_browser_seek_time);
   void OnDurationChanged(int demuxer_client_id,
                          const base::TimeDelta& duration);
 
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index 02e90b4..e9e36fc 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -81,7 +81,7 @@
 
 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
     RenderViewHost* render_view_host)
-    : RenderViewHostObserver(render_view_host),
+    : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
       fullscreen_player_id_(-1),
       pending_fullscreen_player_id_(-1),
       web_contents_(WebContents::FromRenderViewHost(render_view_host)),
@@ -266,7 +266,7 @@
 media::MediaResourceGetter*
 BrowserMediaPlayerManager::GetMediaResourceGetter() {
   if (!media_resource_getter_.get()) {
-    RenderProcessHost* host = render_view_host()->GetProcess();
+    RenderProcessHost* host = web_contents()->GetRenderProcessHost();
     BrowserContext* context = host->GetBrowserContext();
     StoragePartition* partition = host->GetStoragePartition();
     fileapi::FileSystemContext* file_system_context =
@@ -403,10 +403,8 @@
     // In Android WebView, two ContentViewCores could both try to enter
     // fullscreen video, we just ignore the second one.
     fullscreen_player_id_ = player_id;
-    WebContents* web_contents =
-        WebContents::FromRenderViewHost(render_view_host());
     ContentViewCoreImpl* content_view_core_impl =
-        ContentViewCoreImpl::FromWebContents(web_contents);
+        ContentViewCoreImpl::FromWebContents(web_contents());
     video_view_.reset(new ContentVideoView(content_view_core_impl->GetContext(),
         content_view_core_impl->GetContentVideoViewClient(), this));
   }
@@ -433,8 +431,8 @@
 
   RemovePlayer(player_id);
 
-  RenderProcessHostImpl* host =
-      static_cast<RenderProcessHostImpl*>(render_view_host()->GetProcess());
+  RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
+      web_contents()->GetRenderProcessHost());
   AddPlayer(CreateMediaPlayer(
       type, player_id, url, first_party_for_cookies, demuxer_client_id,
       host->GetBrowserContext()->IsOffTheRecord(), this,
@@ -522,10 +520,8 @@
       media_keys_ids_approved_.end()) {
     media_keys_ids_pending_approval_.insert(media_keys_id);
   }
-  WebContents* web_contents =
-      WebContents::FromRenderViewHost(render_view_host());
-  web_contents->GetDelegate()->RequestProtectedMediaIdentifierPermission(
-      web_contents,
+  web_contents()->GetDelegate()->RequestProtectedMediaIdentifierPermission(
+      web_contents(),
       drm_bridge->frame_url(),
       base::Bind(&BrowserMediaPlayerManager::GenerateKeyIfAllowed,
                  weak_ptr_factory_.GetWeakPtr(),
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h
index a6cad8f..93b7592 100644
--- a/content/browser/media/android/browser_media_player_manager.h
+++ b/content/browser/media/android/browser_media_player_manager.h
@@ -17,7 +17,7 @@
 #include "base/time/time.h"
 #include "content/browser/android/content_video_view.h"
 #include "content/common/media/media_player_messages_enums_android.h"
-#include "content/public/browser/render_view_host_observer.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "media/base/android/media_player_android.h"
 #include "media/base/android/media_player_manager.h"
 #include "ui/gfx/rect_f.h"
@@ -38,7 +38,7 @@
 // MediaPlayerAndroid objects are converted to IPCs and then sent to the
 // render process.
 class CONTENT_EXPORT BrowserMediaPlayerManager
-    : public RenderViewHostObserver,
+    : public WebContentsObserver,
       public media::MediaPlayerManager {
  public:
   // Permits embedders to provide an extended version of the class.
@@ -50,7 +50,7 @@
 
   virtual ~BrowserMediaPlayerManager();
 
-  // RenderViewHostObserver overrides.
+  // WebContentsObserver overrides.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // Fullscreen video playback controls.
diff --git a/content/browser/media/webrtc_identity_store_backend.cc b/content/browser/media/webrtc_identity_store_backend.cc
index 1e21be1..5aed520 100644
--- a/content/browser/media/webrtc_identity_store_backend.cc
+++ b/content/browser/media/webrtc_identity_store_backend.cc
@@ -567,7 +567,7 @@
       case DELETE_IDENTITY:
         del_stmt.Reset(true);
         del_stmt.BindString(0, po->origin.spec());
-        add_stmt.BindString(1, po->identity_name);
+        del_stmt.BindString(1, po->identity_name);
         CHECK(del_stmt.Run());
         break;
 
diff --git a/content/browser/plugin_browsertest.cc b/content/browser/plugin_browsertest.cc
index 74289b6..11c3fae 100644
--- a/content/browser/plugin_browsertest.cc
+++ b/content/browser/plugin_browsertest.cc
@@ -273,10 +273,10 @@
   LoadAndWait(GetURL("self_delete_plugin_stream.html"));
 }
 
-// This test asserts on Mac in plugin_host in the NPNVWindowNPObject case.
-#if !(defined(OS_MACOSX) && !defined(NDEBUG))
-// If this test flakes use http://crbug.com/95558.
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(DeletePluginInDeallocate)) {
+// On Mac this test asserts in plugin_host: http://crbug.com/95558
+// On all platforms it flakes in ~URLRequestContext: http://crbug.com/310336
+#if !defined(NDEBUG)
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_DeletePluginInDeallocate) {
   LoadAndWait(GetURL("plugin_delete_in_deallocate.html"));
 }
 #endif
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index e42d549..fbf512a 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -215,7 +215,8 @@
 
   host_impl_.reset(new BrowserPpapiHostImpl(this, permissions_, info.name,
                                             info.path, profile_data_directory,
-                                            false));
+                                            false /* in_process */,
+                                            false /* external_plugin */));
 
   filter_ = new PepperMessageFilter();
   process_->AddFilter(filter_.get());
@@ -239,7 +240,8 @@
   host_impl_.reset(new BrowserPpapiHostImpl(this, permissions,
                                             std::string(), base::FilePath(),
                                             base::FilePath(),
-                                            false));
+                                            false /* in_process */,
+                                            false /* external_plugin */));
 }
 
 bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) {
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index a0f0ecf..7fce152 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -7,6 +7,7 @@
 
   # The renderer_host files should only call upwards in the layering via the
   # delegate interfaces.
+  "-content/browser/frame_host",
   "-content/browser/web_contents",
   "-content/public/browser/web_contents.h",
   "-content/public/browser/web_contents_delegate.h",
@@ -15,6 +16,7 @@
 
 specific_include_rules = {
   ".*_(unit|browser)test\.cc": [
+    "+content/browser/frame_host",
     "+content/browser/web_contents",
     "+content/public/browser/web_contents.h",
     "+content/public/browser/web_contents_view.h",
@@ -24,4 +26,13 @@
     "+third_party/WebKit/public/web/WebKit.h",
     "+third_party/WebKit/public/web/linux/WebFontInfo.h",
   ],
+  "render_process_host_impl\.cc": [
+    "+content/browser/frame_host/render_frame_message_filter.h",
+  ],
+  # TODO(nasko): Remove these exceptions once we've untangled the dependency
+  # of RenderViewHost on the FrameTree.
+  "render_view_host_impl\.(cc|h)": [
+    "+content/browser/frame_host/frame_tree.h",
+    "+content/browser/frame_host/render_frame_host_impl.h",
+  ],
 }
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index da0c00f..8550172 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -40,6 +40,7 @@
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "ui/gfx/android/device_display_info.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/frame_time.h"
 #include "webkit/common/gpu/context_provider_in_process.h"
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
@@ -153,7 +154,7 @@
 
 void CompositorImpl::Composite() {
   if (host_)
-    host_->Composite(base::TimeTicks::Now());
+    host_->Composite(gfx::FrameTime::Now());
 }
 
 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
@@ -229,7 +230,8 @@
         g_impl_thread ? g_impl_thread->message_loop()->message_loop_proxy()
                       : NULL;
 
-    host_ = cc::LayerTreeHost::Create(this, settings, impl_thread_task_runner);
+    host_ = cc::LayerTreeHost::Create(
+        this, NULL, settings, impl_thread_task_runner);
     host_->SetRootLayer(root_layer_);
 
     host_->SetVisible(true);
@@ -358,34 +360,35 @@
     const WebKit::WebGraphicsContext3D::Attributes attributes,
     int surface_id,
     base::WeakPtr<CompositorImpl> compositor_impl) {
-  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
+  BrowserGpuChannelHostFactory* factory =
+      BrowserGpuChannelHostFactory::instance();
+  scoped_refptr<GpuChannelHost> gpu_channel_host(factory->EstablishGpuChannelSync(
+      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
+  if (!gpu_channel_host)
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+
   GURL url("chrome://gpu/Compositor::createContext3D");
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
-      new WebGraphicsContext3DCommandBufferImpl(surface_id,
-                                                url,
-                                                factory,
-                                                compositor_impl));
   static const size_t kBytesPerPixel = 4;
   gfx::DeviceDisplayInfo display_info;
   size_t full_screen_texture_size_in_bytes =
       display_info.GetDisplayHeight() *
       display_info.GetDisplayWidth() *
       kBytesPerPixel;
-  if (!context->Initialize(
-          attributes,
-          false,
-          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
-          64 * 1024,  // command buffer size
-          64 * 1024,  // start transfer buffer size
-          64 * 1024,  // min transfer buffer size
-          std::min(3 * full_screen_texture_size_in_bytes,
-                   kDefaultMaxTransferBufferSize),
-          2 * 1024 * 1024  // mapped memory limit
-  )) {
-    LOG(ERROR) << "Failed to create 3D context for compositor.";
-    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
-  }
-  return context.Pass();
+  WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
+  limits.command_buffer_size = 64 * 1024;
+  limits.start_transfer_buffer_size = 64 * 1024;
+  limits.min_transfer_buffer_size = 64 * 1024;
+  limits.max_transfer_buffer_size = std::min(
+      3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
+  limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
+  return make_scoped_ptr(
+      new WebGraphicsContext3DCommandBufferImpl(surface_id,
+                                                url,
+                                                gpu_channel_host.get(),
+                                                compositor_impl,
+                                                attributes,
+                                                false,
+                                                limits));
 }
 
 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 66eb07d..7ef04f7 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -72,8 +72,8 @@
                                    gfx::JavaBitmap& bitmap) OVERRIDE;
 
   // LayerTreeHostClient implementation.
-  virtual void WillBeginFrame() OVERRIDE {}
-  virtual void DidBeginFrame() OVERRIDE {}
+  virtual void WillBeginMainFrame() OVERRIDE {}
+  virtual void DidBeginMainFrame() OVERRIDE {}
   virtual void Animate(double frame_begin_time) OVERRIDE {}
   virtual void Layout() OVERRIDE {}
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
diff --git a/content/browser/renderer_host/delegated_frame_evictor.cc b/content/browser/renderer_host/delegated_frame_evictor.cc
new file mode 100644
index 0000000..8993d11
--- /dev/null
+++ b/content/browser/renderer_host/delegated_frame_evictor.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 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/renderer_host/delegated_frame_evictor.h"
+
+namespace content {
+
+DelegatedFrameEvictor::DelegatedFrameEvictor(
+    DelegatedFrameEvictorClient* client)
+    : client_(client), has_frame_(false) {}
+
+DelegatedFrameEvictor::~DelegatedFrameEvictor() { DiscardedFrame(); }
+
+void DelegatedFrameEvictor::SwappedFrame(bool visible) {
+  has_frame_ = true;
+  RendererFrameManager::GetInstance()->AddFrame(this, visible);
+}
+
+void DelegatedFrameEvictor::DiscardedFrame() {
+  RendererFrameManager::GetInstance()->RemoveFrame(this);
+  has_frame_ = false;
+}
+
+void DelegatedFrameEvictor::SetVisible(bool visible) {
+  if (has_frame_)
+    RendererFrameManager::GetInstance()->SetFrameVisibility(this, visible);
+}
+
+void DelegatedFrameEvictor::EvictCurrentFrame() {
+  client_->EvictDelegatedFrame();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/delegated_frame_evictor.h b/content/browser/renderer_host/delegated_frame_evictor.h
new file mode 100644
index 0000000..c54f2c4
--- /dev/null
+++ b/content/browser/renderer_host/delegated_frame_evictor.h
@@ -0,0 +1,41 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_DELEGATED_FRAME_EVICTOR_H_
+#define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_EVICTOR_H_
+
+#include "content/browser/renderer_host/renderer_frame_manager.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT DelegatedFrameEvictorClient {
+ public:
+  virtual ~DelegatedFrameEvictorClient() {}
+  virtual void EvictDelegatedFrame() = 0;
+};
+
+class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient {
+ public:
+  // |client| must outlive |this|.
+  explicit DelegatedFrameEvictor(DelegatedFrameEvictorClient* client);
+  virtual ~DelegatedFrameEvictor();
+
+  void SwappedFrame(bool visible);
+  void DiscardedFrame();
+  void SetVisible(bool visible);
+
+ private:
+  // RendererFrameManagerClient implementation.
+  virtual void EvictCurrentFrame() OVERRIDE;
+
+  DelegatedFrameEvictorClient* client_;
+  bool has_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(DelegatedFrameEvictor);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_EVICTOR_H_
diff --git a/content/browser/renderer_host/frame_memory_manager.cc b/content/browser/renderer_host/frame_memory_manager.cc
deleted file mode 100644
index 708bddf..0000000
--- a/content/browser/renderer_host/frame_memory_manager.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2013 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/renderer_host/frame_memory_manager.h"
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/sys_info.h"
-
-namespace content {
-
-namespace {
-
-size_t MaxNumberOfSavedFrames() {
-  return std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
-}
-
-}  // namespace
-
-FrameMemoryManager* FrameMemoryManager::GetInstance() {
-  return Singleton<FrameMemoryManager>::get();
-}
-
-void FrameMemoryManager::AddFrame(FrameContainer* frame, bool visible) {
-  RemoveFrame(frame);
-  if (visible)
-    visible_frames_.insert(frame);
-  else
-    hidden_frames_.push_front(frame);
-  CullHiddenFrames();
-}
-
-void FrameMemoryManager::RemoveFrame(FrameContainer* frame) {
-  visible_frames_.erase(frame);
-  hidden_frames_.remove(frame);
-}
-
-void FrameMemoryManager::SetFrameVisibility(FrameContainer* frame,
-                                            bool visible) {
-  if (visible) {
-    hidden_frames_.remove(frame);
-    visible_frames_.insert(frame);
-  } else {
-    visible_frames_.erase(frame);
-    hidden_frames_.push_front(frame);
-    CullHiddenFrames();
-  }
-}
-
-FrameMemoryManager::FrameMemoryManager() {}
-
-FrameMemoryManager::~FrameMemoryManager() {}
-
-void FrameMemoryManager::CullHiddenFrames() {
-  while (!hidden_frames_.empty() &&
-         hidden_frames_.size() + visible_frames_.size() >
-             MaxNumberOfSavedFrames()) {
-    size_t old_size = hidden_frames_.size();
-    // Should remove self from list.
-    hidden_frames_.back()->ReleaseCurrentFrame();
-    DCHECK_EQ(hidden_frames_.size() + 1, old_size);
-  }
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/frame_memory_manager.h b/content/browser/renderer_host/frame_memory_manager.h
deleted file mode 100644
index ce3fc25..0000000
--- a/content/browser/renderer_host/frame_memory_manager.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 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_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
-
-#include <list>
-#include <set>
-
-#include "base/basictypes.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace content {
-
-class FrameContainer {
- public:
-  virtual void ReleaseCurrentFrame() = 0;
-};
-
-class FrameMemoryManager {
- public:
-  static FrameMemoryManager* GetInstance();
-
-  void AddFrame(FrameContainer*, bool visible);
-  void RemoveFrame(FrameContainer*);
-  void SetFrameVisibility(FrameContainer*, bool visible);
-
- private:
-  FrameMemoryManager();
-  ~FrameMemoryManager();
-  void CullHiddenFrames();
-  friend struct DefaultSingletonTraits<FrameMemoryManager>;
-
-  std::set<FrameContainer*> visible_frames_;
-  std::list<FrameContainer*> hidden_frames_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameMemoryManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
deleted file mode 100644
index 620da91..0000000
--- a/content/browser/renderer_host/frame_tree.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2013 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/renderer_host/frame_tree.h"
-
-#include <queue>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "content/browser/renderer_host/frame_tree_node.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
-
-namespace content {
-
-namespace {
-// Used with FrameTree::ForEach() to search for the FrameTreeNode
-// corresponding to |frame_id|.
-bool FrameTreeNodeForId(int64 frame_id, FrameTreeNode** out_node,
-                        FrameTreeNode* node) {
-  if (node->frame_id() == frame_id) {
-    *out_node = node;
-    // Terminate iteration once the node has been found.
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
-FrameTree::FrameTree()
-    : root_(new FrameTreeNode(FrameTreeNode::kInvalidFrameId, std::string(),
-                              scoped_ptr<RenderFrameHostImpl>())) {
-}
-
-FrameTree::~FrameTree() {
-}
-
-FrameTreeNode* FrameTree::FindByID(int64 frame_id) {
-  FrameTreeNode* node = NULL;
-  ForEach(base::Bind(&FrameTreeNodeForId, frame_id, &node));
-  return node;
-}
-
-void FrameTree::ForEach(
-    const base::Callback<bool(FrameTreeNode*)>& on_node) const {
-  std::queue<FrameTreeNode*> queue;
-  queue.push(root_.get());
-
-  while (!queue.empty()) {
-    FrameTreeNode* node = queue.front();
-    queue.pop();
-    if (!on_node.Run(node))
-      break;
-
-    for (size_t i = 0; i < node->child_count(); ++i)
-      queue.push(node->child_at(i));
-  }
-}
-
-bool FrameTree::IsFirstNavigationAfterSwap() const {
-  return root_->frame_id() == FrameTreeNode::kInvalidFrameId;
-}
-
-void FrameTree::OnFirstNavigationAfterSwap(int main_frame_id) {
-  root_->set_frame_id(main_frame_id);
-}
-
-void FrameTree::AddFrame(int render_frame_host_id, int64 parent_frame_id,
-                         int64 frame_id, const std::string& frame_name) {
-  FrameTreeNode* parent = FindByID(parent_frame_id);
-  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
-  // shutdown that might make this case possible?
-  if (!parent)
-    return;
-
-  parent->AddChild(CreateNode(frame_id, frame_name, render_frame_host_id,
-                              parent->render_frame_host()->GetProcess()));
-}
-
-void FrameTree::RemoveFrame(int64 parent_frame_id, int64 frame_id) {
-  // If switches::kSitePerProcess is not specified, then the FrameTree only
-  // contains a node for the root element. However, even in this case
-  // frame detachments need to be broadcast outwards.
-  //
-  // TODO(ajwong): Move this below the |parent| check after the FrameTree is
-  // guaranteed to be correctly populated even without the
-  // switches::kSitePerProcess flag.
-  FrameTreeNode* parent = FindByID(parent_frame_id);
-  if (!on_frame_removed_.is_null()) {
-    on_frame_removed_.Run(
-        root_->render_frame_host()->render_view_host(), frame_id);
-  }
-
-  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
-  // shutdown that might make this case possible?
-  if (!parent)
-    return;
-
-  parent->RemoveChild(frame_id);
-}
-
-void FrameTree::SetFrameUrl(int64 frame_id, const GURL& url) {
-  FrameTreeNode* node = FindByID(frame_id);
-  // TODO(ajwong): Should the renderer be killed here? Would there be a race on
-  // shutdown that might make this case possible?
-  if (!node)
-    return;
-
-  if (node)
-    node->set_current_url(url);
-}
-
-void FrameTree::SwapMainFrame(RenderFrameHostImpl* render_frame_host) {
-  return root_->ResetForMainFrame(render_frame_host);
-}
-
-RenderFrameHostImpl* FrameTree::GetMainFrame() const {
-  return root_->render_frame_host();
-}
-
-void FrameTree::SetFrameRemoveListener(
-    const base::Callback<void(RenderViewHostImpl*, int64)>& on_frame_removed) {
-  on_frame_removed_ = on_frame_removed;
-}
-
-scoped_ptr<FrameTreeNode> FrameTree::CreateNode(
-    int64 frame_id, const std::string& frame_name, int render_frame_host_id,
-    RenderProcessHost* render_process_host) {
-  scoped_ptr<RenderFrameHostImpl> render_frame_host(
-      new RenderFrameHostImpl(root_->render_frame_host()->render_view_host(),
-                              this, render_frame_host_id, false));
-
-  return make_scoped_ptr(new FrameTreeNode(frame_id, frame_name,
-                                           render_frame_host.Pass()));
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h
deleted file mode 100644
index 8c452e9..0000000
--- a/content/browser/renderer_host/frame_tree.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2013 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_BROWSER_RENDERER_HOST_FRAME_TREE_H_
-#define CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/renderer_host/frame_tree_node.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class FrameTreeNode;
-class RenderProcessHost;
-class RenderViewHostImpl;
-
-// Represents the frame tree for a page. With the exception of the main frame,
-// all FrameTreeNodes will be created/deleted in response to frame attach and
-// detach events in the DOM.
-//
-// The main frame's FrameTreeNode is special in that it is reused. This allows
-// it to serve as an anchor for state that needs to persist across top-level
-// page navigations.
-//
-// TODO(ajwong): Move NavigationController ownership to the main frame
-// FrameTreeNode. Possibly expose access to it from here.
-//
-// TODO(ajwong): Currently this class only contains FrameTreeNodes for
-// subframes if the --site-per-process flag is enabled.
-//
-// This object is only used on the UI thread.
-class CONTENT_EXPORT FrameTree {
- public:
-  FrameTree();
-  ~FrameTree();
-
-  // Returns the FrameTreeNode with the given |frame_id|.
-  FrameTreeNode* FindByID(int64 frame_id);
-
-  // Executes |on_node| on each node in the frame tree.  If |on_node| returns
-  // false, terminates the iteration immediately. Returning false is useful
-  // if |on_node| is just doing a search over the tree.
-  void ForEach(const base::Callback<bool(FrameTreeNode*)>& on_node) const;
-
-  // After the FrameTree is created, or after SwapMainFrame() has been called,
-  // the root node does not yet have a frame id. This is allocated by the
-  // renderer and is published to the browser process on the first navigation
-  // after a swap. These two functions are used to set the root node's frame
-  // id.
-  //
-  // TODO(ajwong): Remove these once RenderFrameHost's routing id replaces
-  // frame_id.
-  bool IsFirstNavigationAfterSwap() const;
-  void OnFirstNavigationAfterSwap(int main_frame_id);
-
-  // Frame tree manipulation routines.
-  void AddFrame(int render_frame_host_id, int64 parent_frame_id,
-                int64 frame_id, const std::string& frame_name);
-  void RemoveFrame(int64 parent_frame_id, int64 frame_id);
-  void SetFrameUrl(int64 frame_id, const GURL& url);
-
-  // Resets the FrameTree and changes RenderFrameHost for the main frame.
-  // This destroys most of the frame tree but retains the root node so that
-  // navigation state may be kept on it between process swaps. Used to
-  // support bookkeeping for top-level navigations.
-  //
-  // If |main_frame| is NULL, reset tree to initially constructed state.
-  //
-  // TODO(ajwong): This function should not be given a |main_frame|. This is
-  // required currently because the RenderViewHost owns its main frame. When
-  // that relation is fixed, the FrameTree should be responsible for
-  // created/destroying the main frame on the swap.
-  void SwapMainFrame(RenderFrameHostImpl* main_frame);
-
-  // Convenience accessor for the main frame's RenderFrameHostImpl.
-  RenderFrameHostImpl* GetMainFrame() const;
-
-  // Allows a client to listen for frame removal.
-  void SetFrameRemoveListener(
-      const base::Callback<void(RenderViewHostImpl*, int64)>& on_frame_removed);
-
-  FrameTreeNode* GetRootForTesting() { return root_.get(); }
-
- private:
-  scoped_ptr<FrameTreeNode> CreateNode(int64 frame_id,
-                                       const std::string& frame_name,
-                                       int render_frame_host_id,
-                                       RenderProcessHost* render_process_host);
-
-  scoped_ptr<FrameTreeNode> root_;
-
-  base::Callback<void(RenderViewHostImpl*, int64)> on_frame_removed_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameTree);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_H_
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc
deleted file mode 100644
index 81ea361..0000000
--- a/content/browser/renderer_host/frame_tree_node.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 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/renderer_host/frame_tree_node.h"
-
-#include <queue>
-
-#include "base/stl_util.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
-
-namespace content {
-
-const int64 FrameTreeNode::kInvalidFrameId = -1;
-
-FrameTreeNode::FrameTreeNode(int64 frame_id, const std::string& name,
-                             scoped_ptr<RenderFrameHostImpl> render_frame_host)
-  : frame_id_(frame_id),
-    frame_name_(name),
-    owns_render_frame_host_(true),
-    render_frame_host_(render_frame_host.release()) {
-}
-
-FrameTreeNode::~FrameTreeNode() {
-  if (owns_render_frame_host_)
-    delete render_frame_host_;
-}
-
-void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child) {
-  children_.push_back(child.release());
-}
-
-void FrameTreeNode::RemoveChild(int64 child_id) {
-  std::vector<FrameTreeNode*>::iterator iter;
-
-  for (iter = children_.begin(); iter != children_.end(); ++iter) {
-    if ((*iter)->frame_id() == child_id)
-      break;
-  }
-
-  if (iter != children_.end())
-    children_.erase(iter);
-}
-
-void FrameTreeNode::ResetForMainFrame(
-    RenderFrameHostImpl* new_render_frame_host) {
-  DCHECK_EQ(0UL, children_.size());
-
-  owns_render_frame_host_ = false;
-  frame_id_ = kInvalidFrameId;
-  current_url_ = GURL();
-  children_.clear();
-
-  render_frame_host_ = new_render_frame_host;
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h
deleted file mode 100644
index bfede18..0000000
--- a/content/browser/renderer_host/frame_tree_node.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2013 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_BROWSER_WEB_CONTENTS_FRAME_TREE_NODE_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_FRAME_TREE_NODE_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "content/common/content_export.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class RenderFrameHostImpl;
-
-// When a page contains iframes, its renderer process maintains a tree structure
-// 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:
-  static const int64 kInvalidFrameId;
-
-  FrameTreeNode(int64 frame_id, const std::string& name,
-                scoped_ptr<RenderFrameHostImpl> render_frame_host);
-  ~FrameTreeNode();
-
-  void AddChild(scoped_ptr<FrameTreeNode> child);
-  void RemoveChild(int64 child_id);
-
-  // Transitional API allowing the RenderFrameHost of a FrameTreeNode
-  // representing the main frame to be provided by someone else. After
-  // this is called, the FrameTreeNode no longer owns its RenderFrameHost.
-  //
-  // This should only be used for the main frame (aka root) in a frame tree.
-  //
-  // TODO(ajwong): Remove this method once the main frame RenderFrameHostImpl is
-  // no longer owned by the RenderViewHostImpl.
-  void ResetForMainFrame(RenderFrameHostImpl* new_render_frame_host);
-
-  void set_frame_id(int64 frame_id) {
-    DCHECK_EQ(frame_id_, kInvalidFrameId);
-    frame_id_ = frame_id;
-  }
-
-  int64 frame_id() const {
-    return frame_id_;
-  }
-
-  const std::string& frame_name() const {
-    return frame_name_;
-  }
-
-  size_t child_count() const {
-    return children_.size();
-  }
-
-  FrameTreeNode* child_at(size_t index) const {
-    return children_[index];
-  }
-
-  const GURL& current_url() const {
-    return current_url_;
-  }
-
-  void set_current_url(const GURL& url) {
-    current_url_ = url;
-  }
-
-  RenderFrameHostImpl* render_frame_host() const {
-    return render_frame_host_;
-  }
-
- private:
-  // The unique identifier for the frame in the page.
-  int64 frame_id_;
-
-  // The assigned name of the frame. This name can be empty, unlike the unique
-  // name generated internally in the DOM tree.
-  std::string frame_name_;
-
-  // The immediate children of this specific frame.
-  ScopedVector<FrameTreeNode> children_;
-
-  // When ResetForMainFrame() is called, this is set to false and the
-  // |render_frame_host_| below is not deleted on destruction.
-  //
-  // For the mainframe, the FrameTree does not own the |render_frame_host_|.
-  // This is a transitional wart because RenderViewHostManager does not yet
-  // have the bookkeeping logic to handle creating a pending RenderFrameHost
-  // along with a pending RenderViewHost. Thus, for the main frame, the
-  // RenderViewHost currently retains ownership and the FrameTreeNode should
-  // not delete it on destruction.
-  bool owns_render_frame_host_;
-
-  // The active RenderFrameHost for this frame. The FrameTreeNode does not
-  // always own this pointer.  See comments above |owns_render_frame_host_|.
-  // TODO(ajwong): Replace with RenderFrameHostManager.
-  RenderFrameHostImpl* render_frame_host_;
-
-  // Track the current frame's last committed URL, so we can estimate the
-  // process impact of out-of-process iframes.
-  // TODO(creis): Remove this when we can store subframe URLs in the
-  // NavigationController.
-  GURL current_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameTreeNode);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_FRAME_TREE_NODE_H_
diff --git a/content/browser/renderer_host/frame_tree_unittest.cc b/content/browser/renderer_host/frame_tree_unittest.cc
deleted file mode 100644
index cc23741..0000000
--- a/content/browser/renderer_host/frame_tree_unittest.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2013 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/renderer_host/frame_tree.h"
-
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_renderer_host.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-class FrameTreeTest : public RenderViewHostTestHarness {
- protected:
-  // Prints a FrameTree, for easy assertions of the tree hierarchy.
-  std::string GetTreeState(FrameTree* frame_tree) {
-    std::string result;
-    AppendTreeNodeState(frame_tree->GetRootForTesting(), &result);
-    return result;
-  }
-
- private:
-  void AppendTreeNodeState(FrameTreeNode* node, std::string* result) {
-    result->append(base::Int64ToString(node->frame_id()));
-    if (!node->frame_name().empty()) {
-      result->append(" '");
-      result->append(node->frame_name());
-      result->append("'");
-    }
-    result->append(": [");
-    const char* separator = "";
-    for (size_t i = 0; i < node->child_count(); i++) {
-      result->append(separator);
-      AppendTreeNodeState(node->child_at(i), result);
-      separator = ", ";
-    }
-    result->append("]");
-  }
-};
-
-// The root node never changes during navigation even though its
-// RenderFrameHost does.
-//  - Swapping main frame doesn't change root node.
-//  - Swapping back to NULL doesn't crash (easier tear-down for interstitials).
-//  - Main frame does not own RenderFrameHost.
-TEST_F(FrameTreeTest, RootNode) {
-  FrameTree frame_tree;
-
-  // Initial state has empty node.
-  FrameTreeNode* root = frame_tree.GetRootForTesting();
-  ASSERT_TRUE(root);
-  EXPECT_FALSE(frame_tree.GetMainFrame());
-
-  // Swap in main frame.
-  RenderFrameHostImpl* dummy = reinterpret_cast<RenderFrameHostImpl*>(0x1);
-  frame_tree.SwapMainFrame(dummy);
-  EXPECT_EQ(root, frame_tree.GetRootForTesting());
-  EXPECT_EQ(dummy, frame_tree.GetMainFrame());
-
-  // Move back to NULL.
-  frame_tree.SwapMainFrame(NULL);
-  EXPECT_EQ(root, frame_tree.GetRootForTesting());
-  EXPECT_FALSE(frame_tree.GetMainFrame());
-
-  // Move back to an invalid pointer, let the FrameTree go out of scope. Test
-  // should not crash because the main frame isn't owned.
-  frame_tree.SwapMainFrame(dummy);
-}
-
-// Test that swapping the main frame resets the renderer-assigned frame id.
-//  - On creation, frame id is unassigned.
-//  - After a swap, frame id is unassigned.
-TEST_F(FrameTreeTest, FirstNavigationAfterSwap) {
-  FrameTree frame_tree;
-
-  EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
-  EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
-            frame_tree.GetRootForTesting()->frame_id());
-  frame_tree.OnFirstNavigationAfterSwap(1);
-  EXPECT_FALSE(frame_tree.IsFirstNavigationAfterSwap());
-  EXPECT_EQ(1, frame_tree.GetRootForTesting()->frame_id());
-
-  frame_tree.SwapMainFrame(NULL);
-  EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
-  EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
-            frame_tree.GetRootForTesting()->frame_id());
-}
-
-// Exercise tree manipulation routines.
-//  - Add a series of nodes and verify tree structure.
-//  - Remove a series of nodes and verify tree structure.
-TEST_F(FrameTreeTest, Shape) {
-  FrameTree frame_tree;
-  std::string no_children_node("no children node");
-  std::string deep_subtree("node with deep subtree");
-
-  // Ensure the top-level node of the FrameTree is initialized by simulating a
-  // main frame swap here.
-  RenderFrameHostImpl render_frame_host(static_cast<RenderViewHostImpl*>(rvh()),
-                                        &frame_tree,
-                                        process()->GetNextRoutingID(), false);
-  frame_tree.SwapMainFrame(&render_frame_host);
-  frame_tree.OnFirstNavigationAfterSwap(5);
-
-  ASSERT_EQ("5: []", GetTreeState(&frame_tree));
-
-  // Simulate attaching a series of frames to build the frame tree.
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 14, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 15, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 16, std::string());
-
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 244, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 15, 255, no_children_node);
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 245, std::string());
-
-  ASSERT_EQ("5: [14: [244: [], 245: []], "
-                "15: [255 'no children node': []], "
-                "16: []]",
-            GetTreeState(&frame_tree));
-
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 264, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 265, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 266, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 267, deep_subtree);
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 268, std::string());
-
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 267, 365, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 365, 455, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 455, 555, std::string());
-  frame_tree.AddFrame(process()->GetNextRoutingID(), 555, 655, std::string());
-
-  // Now that's it's fully built, verify the tree structure is as expected.
-  ASSERT_EQ("5: [14: [244: [], 245: []], "
-                "15: [255 'no children node': []], "
-                "16: [264: [], 265: [], 266: [], "
-                     "267 'node with deep subtree': "
-                         "[365: [455: [555: [655: []]]]], 268: []]]",
-            GetTreeState(&frame_tree));
-
-  // Test removing of nodes.
-  frame_tree.RemoveFrame(555, 655);
-  ASSERT_EQ("5: [14: [244: [], 245: []], "
-                "15: [255 'no children node': []], "
-                "16: [264: [], 265: [], 266: [], "
-                     "267 'node with deep subtree': "
-                         "[365: [455: [555: []]]], 268: []]]",
-            GetTreeState(&frame_tree));
-
-  frame_tree.RemoveFrame(16, 265);
-  ASSERT_EQ("5: [14: [244: [], 245: []], "
-                "15: [255 'no children node': []], "
-                "16: [264: [], 266: [], "
-                     "267 'node with deep subtree': "
-                         "[365: [455: [555: []]]], 268: []]]",
-            GetTreeState(&frame_tree));
-
-  frame_tree.RemoveFrame(5, 15);
-  ASSERT_EQ("5: [14: [244: [], 245: []], "
-                "16: [264: [], 266: [], "
-                     "267 'node with deep subtree': "
-                         "[365: [455: [555: []]]], 268: []]]",
-            GetTreeState(&frame_tree));
-}
-
-}  // namespace
-}  // namespace content
diff --git a/content/browser/renderer_host/gtk_im_context_wrapper.cc b/content/browser/renderer_host/gtk_im_context_wrapper.cc
index 65dc545..e79faba 100644
--- a/content/browser/renderer_host/gtk_im_context_wrapper.cc
+++ b/content/browser/renderer_host/gtk_im_context_wrapper.cc
@@ -17,7 +17,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_gtk.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
-#include "ui/base/gtk/gtk_im_context_util.h"
+#include "ui/base/ime/composition_text_util_pango.h"
 #include "ui/gfx/gtk_util.h"
 #include "ui/gfx/rect.h"
 
diff --git a/content/browser/renderer_host/image_transport_factory_android.cc b/content/browser/renderer_host/image_transport_factory_android.cc
index a32947d..9b3de30 100644
--- a/content/browser/renderer_host/image_transport_factory_android.cc
+++ b/content/browser/renderer_host/image_transport_factory_android.cc
@@ -56,34 +56,38 @@
 };
 
 CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
+  BrowserGpuChannelHostFactory* factory =
+      BrowserGpuChannelHostFactory::instance();
+  scoped_refptr<GpuChannelHost> gpu_channel_host(factory->EstablishGpuChannelSync(
+      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
+  DCHECK(gpu_channel_host);
+
   WebKit::WebGraphicsContext3D::Attributes attrs;
   attrs.shareResources = true;
-  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
   GURL url("chrome://gpu/ImageTransportFactoryAndroid");
   base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
-  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
-                                                           url,
-                                                           factory,
-                                                           swap_client));
   static const size_t kBytesPerPixel = 4;
   gfx::DeviceDisplayInfo display_info;
-  size_t full_screen_texture_size_in_bytes =
-      display_info.GetDisplayHeight() *
-      display_info.GetDisplayWidth() *
-      kBytesPerPixel;
+  size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() *
+                                             display_info.GetDisplayWidth() *
+                                             kBytesPerPixel;
+  WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
+  limits.command_buffer_size = 64 * 1024;
+  limits.start_transfer_buffer_size = 64 * 1024;
+  limits.min_transfer_buffer_size = 64 * 1024;
+  limits.max_transfer_buffer_size = std::min(
+      3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
+  limits.mapped_memory_reclaim_limit =
+      WebGraphicsContext3DCommandBufferImpl::kNoLimit;
+  context_.reset(
+      new WebGraphicsContext3DCommandBufferImpl(0,  // offscreen
+                                                url,
+                                                gpu_channel_host.get(),
+                                                swap_client,
+                                                attrs,
+                                                false,
+                                                limits));
   context_->setContextLostCallback(context_lost_listener_.get());
-  context_->Initialize(
-      attrs,
-      false,
-      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
-      64 * 1024,  // command buffer size
-      64 * 1024,  // starting buffer size
-      64 * 1024,  // min buffer size
-      std::min(3 * full_screen_texture_size_in_bytes,
-               kDefaultMaxTransferBufferSize),
-      WebGraphicsContext3DCommandBufferImpl::kNoLimit
-  );
-
   if (context_->makeContextCurrent())
     context_->pushGroupMarkerEXT(
         base::StringPrintf("CmdBufferImageTransportFactory-%p",
diff --git a/content/browser/renderer_host/input/gesture_event_filter.cc b/content/browser/renderer_host/input/gesture_event_filter.cc
index b6c766b..e0e830c 100644
--- a/content/browser/renderer_host/input/gesture_event_filter.cc
+++ b/content/browser/renderer_host/input/gesture_event_filter.cc
@@ -17,45 +17,11 @@
 namespace content {
 namespace {
 
-// Default maximum time between the GestureRecognizer generating a
-// GestureTapDown and when it is forwarded to the renderer.
-#if !defined(OS_ANDROID)
-static const int kTapDownDeferralTimeMs = 150;
-#else
-// Android OS sends this gesture with a delay already.
-static const int kTapDownDeferralTimeMs = 0;
-#endif
-
 // Default debouncing interval duration: if a scroll is in progress, non-scroll
 // events during this interval are deferred to either its end or discarded on
 // receipt of another GestureScrollUpdate.
 static const int kDebouncingIntervalTimeMs = 30;
 
-// Sets |*value| to |switchKey| if it exists or sets it to |defaultValue|.
-static void GetParamHelper(int* value,
-                           int defaultValue,
-                           const char switchKey[]) {
-  if (*value < 0) {
-    *value = defaultValue;
-    CommandLine* command_line = CommandLine::ForCurrentProcess();
-    std::string command_line_param =
-        command_line->GetSwitchValueASCII(switchKey);
-    if (!command_line_param.empty()) {
-      int v;
-      if (base::StringToInt(command_line_param, &v))
-        *value = v;
-    }
-    DCHECK_GE(*value, 0);
-  }
-}
-
-static int GetTapDownDeferralTimeMs() {
-  static int tap_down_deferral_time_window = -1;
-  GetParamHelper(&tap_down_deferral_time_window,
-                 kTapDownDeferralTimeMs,
-                 switches::kTapDownDeferralTimeMs);
-  return tap_down_deferral_time_window;
-}
 }  // namespace
 
 GestureEventFilter::GestureEventFilter(
@@ -70,7 +36,6 @@
            new TouchpadTapSuppressionController(touchpad_client)),
        touchscreen_tap_suppression_controller_(
            new TouchscreenTapSuppressionController(this)),
-       maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()),
        debounce_interval_time_ms_(kDebouncingIntervalTimeMs) {
   DCHECK(client);
   DCHECK(touchpad_tap_suppression_controller_);
@@ -137,7 +102,6 @@
       ShouldForwardForBounceReduction(gesture_event) &&
       ShouldForwardForGFCFiltering(gesture_event) &&
       ShouldForwardForTapSuppression(gesture_event) &&
-      ShouldForwardForTapDeferral(gesture_event) &&
       ShouldForwardForCoalescing(gesture_event);
 }
 
@@ -181,51 +145,6 @@
   return false;
 }
 
-bool GestureEventFilter::ShouldForwardForTapDeferral(
-    const GestureEventWithLatencyInfo& gesture_event) {
-  switch (gesture_event.event.type) {
-    case WebInputEvent::GestureTapDown:
-      // GestureTapDown is always paired with either a Tap, or TapCancel, so it
-      // should be impossible to have more than one outstanding at a time.
-      DCHECK_EQ(deferred_tap_down_event_.event.type, WebInputEvent::Undefined);
-      deferred_tap_down_event_ = gesture_event;
-      send_gtd_timer_.Start(
-          FROM_HERE,
-          base::TimeDelta::FromMilliseconds(maximum_tap_gap_time_ms_),
-          this,
-          &GestureEventFilter::SendGestureTapDownNow);
-      return false;
-    case WebInputEvent::GestureTapCancel:
-      if (deferred_tap_down_event_.event.type == WebInputEvent::Undefined) {
-        // The TapDown has already been put in the queue, must send the
-        // corresponding TapCancel as well.
-        return true;
-      }
-      // Cancelling a deferred TapDown, just drop them on the floor.
-      send_gtd_timer_.Stop();
-      deferred_tap_down_event_.event.type = WebInputEvent::Undefined;
-      return false;
-    case WebInputEvent::GestureTap:
-      send_gtd_timer_.Stop();
-      if (deferred_tap_down_event_.event.type != WebInputEvent::Undefined) {
-        ForwardGestureEventSkipDeferral(deferred_tap_down_event_);
-        deferred_tap_down_event_.event.type = WebInputEvent::Undefined;
-      }
-      return true;
-    case WebInputEvent::GestureFlingStart:
-    case WebInputEvent::GestureScrollBegin:
-    case WebInputEvent::GesturePinchBegin:
-      send_gtd_timer_.Stop();
-      deferred_tap_down_event_.event.type = WebInputEvent::Undefined;
-      return true;
-    default:
-      return true;
-  }
-
-  NOTREACHED();
-  return true;
-}
-
 bool GestureEventFilter::ShouldForwardForCoalescing(
     const GestureEventWithLatencyInfo& gesture_event) {
   switch (gesture_event.event.type) {
@@ -242,66 +161,74 @@
     default:
       break;
   }
-  coalesced_gesture_events_.push_back(gesture_event);
+  EnqueueEvent(gesture_event);
 
-  // Ensure that if the added event is asynchonous, it is fired and
+  // Ensure that if the added event ignores its ack, it is fired and
   // removed from |coalesced_gesture_events_|.
-  SendAsyncEvents();
+  SendEventsIgnoringAck();
   return ShouldHandleEventNow();
 }
 
 void GestureEventFilter::ProcessGestureAck(InputEventAckState ack_result,
                                            WebInputEvent::Type type,
                                            const ui::LatencyInfo& latency) {
-  if (IsGestureEventTypeAsync(type))
+  if (ShouldIgnoreAckForGestureType(type))
     return;
 
   if (coalesced_gesture_events_.empty()) {
     DLOG(ERROR) << "Received unexpected ACK for event type " << type;
     return;
   }
-  DCHECK_EQ(coalesced_gesture_events_.front().event.type, type);
 
   // Ack'ing an event may enqueue additional gesture events.  By ack'ing the
   // event before the forwarding of queued events below, such additional events
   // can be coalesced with existing queued events prior to dispatch.
-  GestureEventWithLatencyInfo event_with_latency = GetGestureEventAwaitingAck();
+  GestureEventWithLatencyInfo event_with_latency =
+      coalesced_gesture_events_.front();
+  DCHECK_EQ(event_with_latency.event.type, type);
   event_with_latency.latency.AddNewLatencyFrom(latency);
   client_->OnGestureEventAck(event_with_latency, ack_result);
 
   const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result);
   if (type == WebInputEvent::GestureFlingCancel) {
-    if (coalesced_gesture_events_.front().event.sourceDevice ==
-        WebGestureEvent::Touchscreen)
+    if (event_with_latency.event.sourceDevice == WebGestureEvent::Touchscreen)
       touchscreen_tap_suppression_controller_->GestureFlingCancelAck(processed);
     else
       touchpad_tap_suppression_controller_->GestureFlingCancelAck(processed);
   }
   coalesced_gesture_events_.pop_front();
-  // If the event which was just ACKed was blocking asynchronous
-  // events, fire those asynchronous events now.
-  SendAsyncEvents();
+
+  // If the event which was just ACKed was blocking events ignoring ack, fire
+  // those events now.
+  SendEventsIgnoringAck();
+
   if (ignore_next_ack_) {
     ignore_next_ack_ = false;
-  } else if (!coalesced_gesture_events_.empty()) {
-    const GestureEventWithLatencyInfo& next_gesture_event =
-        coalesced_gesture_events_.front();
-    client_->SendGestureEventImmediately(next_gesture_event);
-    // TODO(yusufo): Introduce GesturePanScroll so that these can be combined
-    // into one gesture and kept inside the queue that way.
-    if (coalesced_gesture_events_.size() > 1) {
-      const GestureEventWithLatencyInfo& second_gesture_event =
-          coalesced_gesture_events_[1];
-      if (next_gesture_event.event.type ==
-              WebInputEvent::GestureScrollUpdate &&
-          second_gesture_event.event.type ==
-              WebInputEvent::GesturePinchUpdate) {
-        client_->SendGestureEventImmediately(second_gesture_event);
-        ignore_next_ack_ = true;
-        combined_scroll_pinch_ = gfx::Transform();
-      }
-    }
+    return;
   }
+
+  if (coalesced_gesture_events_.empty())
+    return;
+
+  const GestureEventWithLatencyInfo& first_gesture_event =
+      coalesced_gesture_events_.front();
+
+  // TODO(yusufo): Introduce GesturePanScroll so that these can be combined
+  // into one gesture and kept inside the queue that way.
+  // Check for the coupled GesturePinchUpdate before sending either event,
+  // handling the case where the first GestureScrollUpdate ack is synchronous.
+  GestureEventWithLatencyInfo second_gesture_event;
+  if (first_gesture_event.event.type == WebInputEvent::GestureScrollUpdate &&
+      coalesced_gesture_events_.size() > 1 &&
+      coalesced_gesture_events_[1].event.type ==
+          WebInputEvent::GesturePinchUpdate) {
+    second_gesture_event = coalesced_gesture_events_[1];
+    ignore_next_ack_ = true;
+  }
+
+  client_->SendGestureEventImmediately(first_gesture_event);
+  if (second_gesture_event.event.type != WebInputEvent::Undefined)
+    client_->SendGestureEventImmediately(second_gesture_event);
 }
 
 TouchpadTapSuppressionController*
@@ -313,15 +240,6 @@
   return !coalesced_gesture_events_.empty();
 }
 
-const GestureEventWithLatencyInfo&
-GestureEventFilter::GetGestureEventAwaitingAck() const {
-  DCHECK(!coalesced_gesture_events_.empty());
-  if (!ignore_next_ack_)
-    return coalesced_gesture_events_.front();
-  else
-    return coalesced_gesture_events_.at(1);
-}
-
 void GestureEventFilter::FlingHasBeenHalted() {
   fling_in_progress_ = false;
 }
@@ -330,57 +248,45 @@
   return coalesced_gesture_events_.size() == 1;
 }
 
-void GestureEventFilter::ForwardGestureEventForDeferral(
-    const GestureEventWithLatencyInfo& gesture_event) {
-  if (ShouldForwardForTapDeferral(gesture_event))
-    ForwardGestureEventSkipDeferral(gesture_event);
-}
-
-void GestureEventFilter::ForwardGestureEventSkipDeferral(
+void GestureEventFilter::ForwardGestureEvent(
     const GestureEventWithLatencyInfo& gesture_event) {
   if (ShouldForwardForCoalescing(gesture_event))
-      client_->SendGestureEventImmediately(gesture_event);
-}
-
-void GestureEventFilter::SendGestureTapDownNow() {
-  // We must not have already sent the deferred TapDown (if we did, we would
-  // have stopped the timer, which prevents this task from running - even if
-  // it's time had already elapsed).
-  DCHECK_EQ(deferred_tap_down_event_.event.type, WebInputEvent::GestureTapDown);
-  ForwardGestureEventSkipDeferral(deferred_tap_down_event_);
-  deferred_tap_down_event_.event.type = WebInputEvent::Undefined;
+    client_->SendGestureEventImmediately(gesture_event);
 }
 
 void GestureEventFilter::SendScrollEndingEventsNow() {
   scrolling_in_progress_ = false;
-  for (GestureEventQueue::const_iterator it =
-      debouncing_deferral_queue_.begin();
-      it != debouncing_deferral_queue_.end(); it++) {
+  GestureEventQueue debouncing_deferral_queue;
+  debouncing_deferral_queue.swap(debouncing_deferral_queue_);
+  for (GestureEventQueue::const_iterator it = debouncing_deferral_queue.begin();
+       it != debouncing_deferral_queue.end(); it++) {
     if (ShouldForwardForGFCFiltering(*it) &&
         ShouldForwardForTapSuppression(*it) &&
-        ShouldForwardForTapDeferral(*it) &&
         ShouldForwardForCoalescing(*it)) {
       client_->SendGestureEventImmediately(*it);
     }
   }
-  debouncing_deferral_queue_.clear();
 }
 
 void GestureEventFilter::MergeOrInsertScrollAndPinchEvent(
     const GestureEventWithLatencyInfo& gesture_event) {
   if (coalesced_gesture_events_.size() <= 1) {
-    coalesced_gesture_events_.push_back(gesture_event);
+    EnqueueEvent(gesture_event);
     return;
   }
   GestureEventWithLatencyInfo* last_event = &coalesced_gesture_events_.back();
   if (last_event->CanCoalesceWith(gesture_event)) {
     last_event->CoalesceWith(gesture_event);
+    if (!combined_scroll_pinch_.IsIdentity()) {
+      combined_scroll_pinch_.ConcatTransform(
+          GetTransformForEvent(gesture_event));
+    }
     return;
   }
   if (coalesced_gesture_events_.size() == 2 ||
       (coalesced_gesture_events_.size() == 3 && ignore_next_ack_) ||
       !ShouldTryMerging(gesture_event, *last_event)) {
-    coalesced_gesture_events_.push_back(gesture_event);
+    EnqueueEvent(gesture_event);
     return;
   }
   GestureEventWithLatencyInfo scroll_event;
@@ -456,19 +362,31 @@
   return gesture_transform;
 }
 
-void GestureEventFilter::SendAsyncEvents() {
+void GestureEventFilter::SendEventsIgnoringAck() {
   GestureEventWithLatencyInfo gesture_event;
   while (!coalesced_gesture_events_.empty()) {
     gesture_event = coalesced_gesture_events_.front();
-    if (!GestureEventFilter::IsGestureEventTypeAsync(gesture_event.event.type))
+    if (!GestureEventFilter::ShouldIgnoreAckForGestureType(
+            gesture_event.event.type)) {
       return;
+    }
     coalesced_gesture_events_.pop_front();
     client_->SendGestureEventImmediately(gesture_event);
   }
 }
 
-bool GestureEventFilter::IsGestureEventTypeAsync(WebInputEvent::Type type) {
-  return type == WebInputEvent::GestureTapDown;
+bool GestureEventFilter::ShouldIgnoreAckForGestureType(
+    WebInputEvent::Type type) {
+  return type == WebInputEvent::GestureTapDown ||
+      type == WebInputEvent::GestureShowPress;
+}
+
+void GestureEventFilter::EnqueueEvent(
+    const GestureEventWithLatencyInfo& gesture_event) {
+  coalesced_gesture_events_.push_back(gesture_event);
+  // Scroll and pinch events contributing to |combined_scroll_pinch_| will be
+  // manually added to the queue in |MergeOrInsertScrollAndPinchEvent()|.
+  combined_scroll_pinch_ = gfx::Transform();
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/gesture_event_filter.h b/content/browser/renderer_host/input/gesture_event_filter.h
index 832dba0..61cb7f7 100644
--- a/content/browser/renderer_host/input/gesture_event_filter.h
+++ b/content/browser/renderer_host/input/gesture_event_filter.h
@@ -87,31 +87,18 @@
   // Returns whether there are any gesture event in the queue.
   bool HasQueuedGestureEvents() const;
 
-  // Tries forwarding the event to the tap deferral sub-filter.
-  void ForwardGestureEventForDeferral(
-      const GestureEventWithLatencyInfo& gesture_event);
-
-  // Tries forwarding the event, skipping the tap deferral sub-filter.
-  void ForwardGestureEventSkipDeferral(
-      const GestureEventWithLatencyInfo& gesture_event);
+  void ForwardGestureEvent(const GestureEventWithLatencyInfo& gesture_event);
 
  private:
   friend class MockRenderWidgetHost;
   friend class GestureEventFilterTest;
 
-  static bool IsGestureEventTypeAsync(WebKit::WebInputEvent::Type type);
-
-  // Returns the last gesture event that was sent to the renderer.
-  const GestureEventWithLatencyInfo& GetGestureEventAwaitingAck() const;
+  static bool ShouldIgnoreAckForGestureType(WebKit::WebInputEvent::Type type);
 
   // TODO(mohsen): There are a bunch of ShouldForward.../ShouldDiscard...
   // methods that are getting confusing. This should be somehow fixed. Maybe
   // while refactoring GEF: http://crbug.com/148443.
 
-  // Invoked on the expiration of the timer to release a deferred
-  // GestureTapDown to the renderer.
-  void SendGestureTapDownNow();
-
   // Inovked on the expiration of the debounce interval to release
   // deferred events.
   void SendScrollEndingEventsNow();
@@ -146,10 +133,6 @@
   bool ShouldForwardForTapSuppression(
       const GestureEventWithLatencyInfo& gesture_event);
 
-  // Sub-filter for deferring GestureTapDowns.
-  bool ShouldForwardForTapDeferral(
-      const GestureEventWithLatencyInfo& gesture_event);
-
   // Puts the events in a queue to forward them one by one; i.e., forward them
   // whenever ACK for previous event is received. This queue also tries to
   // coalesce events as much as possible.
@@ -169,9 +152,14 @@
   gfx::Transform GetTransformForEvent(
       const GestureEventWithLatencyInfo& gesture_event) const;
 
-  // Pops and sends async events from the head of |coalesced_gesture_events_|
-  // until the queue is empty or the event at the head is synchronous.
-  void SendAsyncEvents();
+  // Pops and sends events ignoring ack from the head of
+  // |coalesced_gesture_events_| until the queue is empty or the event at the
+  // head requires an ack.
+  void SendEventsIgnoringAck();
+
+  // Adds |gesture_event| to the |coalesced_gesture_events_|, resetting the
+  // accumulation of |combined_scroll_pinch_|.
+  void EnqueueEvent(const GestureEventWithLatencyInfo& gesture_event);
 
   // The receiver of all forwarded gesture events.
   GestureEventFilterClient* client_;
@@ -191,9 +179,6 @@
   // scroll-pinch sequence at the end of the queue.
   gfx::Transform combined_scroll_pinch_;
 
-  // Timer to release a previously deferred GestureTapDown event.
-  base::OneShotTimer<GestureEventFilter> send_gtd_timer_;
-
   // An object tracking the state of touchpad on the delivery of mouse events to
   // the renderer to filter mouse immediately after a touchpad fling canceling
   // tap.
@@ -218,18 +203,12 @@
   // have yet to be sent.
   GestureEventQueue coalesced_gesture_events_;
 
-  // Tap gesture event currently subject to deferral.
-  GestureEventWithLatencyInfo deferred_tap_down_event_;
-
-  // Timer to release a previously deferred GestureTapDown event.
+  // Timer to release a previously deferred gesture event.
   base::OneShotTimer<GestureEventFilter> debounce_deferring_timer_;
 
   // Queue of events that have been deferred for debounce.
   GestureEventQueue debouncing_deferral_queue_;
 
-  // Time window in which to defer a GestureTapDown.
-  int maximum_tap_gap_time_ms_;
-
   // Time window in which to debounce scroll/fling ends.
   // TODO(rjkroege): Make this dynamically configurable.
   int debounce_interval_time_ms_;
diff --git a/content/browser/renderer_host/input/gesture_event_filter_unittest.cc b/content/browser/renderer_host/input/gesture_event_filter_unittest.cc
index 8038a04..4d9ee48 100644
--- a/content/browser/renderer_host/input/gesture_event_filter_unittest.cc
+++ b/content/browser/renderer_host/input/gesture_event_filter_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
 #include "content/browser/renderer_host/input/gesture_event_filter.h"
-#include "content/browser/renderer_host/input/mock_web_input_event_builders.h"
+#include "content/browser/renderer_host/input/synthetic_web_input_event_builders.h"
 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
 #include "content/port/common/input_event_ack_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -47,13 +47,17 @@
   virtual void SendGestureEventImmediately(
       const GestureEventWithLatencyInfo& event) OVERRIDE {
     ++sent_gesture_event_count_;
-    last_immediately_sent_gesture_event_ = event.event;
+    if (sync_ack_result_) {
+      scoped_ptr<InputEventAckState> ack_result = sync_ack_result_.Pass();
+      SendInputEventACK(event.event.type, *ack_result);
+    }
   }
 
   virtual void OnGestureEventAck(
       const GestureEventWithLatencyInfo& event,
       InputEventAckState ack_result) OVERRIDE {
     ++acked_gesture_event_count_;
+    last_acked_event_ = event.event;
   }
 
   // TouchpadTapSuppressionControllerClient
@@ -76,12 +80,13 @@
 
   void SimulateGestureEvent(WebInputEvent::Type type,
                             WebGestureEvent::SourceDevice sourceDevice) {
-    SimulateGestureEvent(MockWebGestureEventBuilder::Build(type, sourceDevice));
+    SimulateGestureEvent(
+        SyntheticWebGestureEventBuilder::Build(type, sourceDevice));
   }
 
   void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
     SimulateGestureEvent(
-        MockWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+        SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
   }
 
   void SimulateGesturePinchUpdateEvent(float scale,
@@ -89,10 +94,10 @@
                                        float anchorY,
                                        int modifiers) {
     SimulateGestureEvent(
-        MockWebGestureEventBuilder::BuildPinchUpdate(scale,
-                                                     anchorX,
-                                                     anchorY,
-                                                     modifiers));
+        SyntheticWebGestureEventBuilder::BuildPinchUpdate(scale,
+                                                          anchorX,
+                                                          anchorY,
+                                                          modifiers));
   }
 
   void SimulateGestureFlingStartEvent(
@@ -100,9 +105,9 @@
       float velocityY,
       WebGestureEvent::SourceDevice sourceDevice) {
     SimulateGestureEvent(
-        MockWebGestureEventBuilder::BuildFling(velocityX,
-                                               velocityY,
-                                               sourceDevice));
+        SyntheticWebGestureEventBuilder::BuildFling(velocityX,
+                                                    velocityY,
+                                                    sourceDevice));
   }
 
   void SendInputEventACK(WebInputEvent::Type type,
@@ -126,16 +131,16 @@
     return count;
   }
 
-  const WebGestureEvent& last_immediately_sent_gesture_event() const {
-    return last_immediately_sent_gesture_event_;
+  const WebGestureEvent& last_acked_event() const {
+    return last_acked_event_;
   }
 
   void set_debounce_interval_time_ms(int ms) {
     filter()->debounce_interval_time_ms_ = ms;
   }
 
-  void set_maximum_tap_gap_time_ms(int delay_ms) {
-    filter()->maximum_tap_gap_time_ms_ = delay_ms;
+  void set_synchronous_ack(InputEventAckState ack_result) {
+    sync_ack_result_.reset(new InputEventAckState(ack_result));
   }
 
   unsigned GestureEventLastQueueEventSize() {
@@ -159,10 +164,6 @@
     return filter()->coalesced_gesture_events_.at(i).event;
   }
 
-  bool ShouldDeferTapDownEvents() {
-    return filter()->maximum_tap_gap_time_ms_ != 0;
-  }
-
   bool ScrollingInProgress() {
     return filter()->scrolling_in_progress_;
   }
@@ -183,7 +184,8 @@
   scoped_ptr<GestureEventFilter> filter_;
   size_t acked_gesture_event_count_;
   size_t sent_gesture_event_count_;
-  WebGestureEvent last_immediately_sent_gesture_event_;
+  WebGestureEvent last_acked_event_;
+  scoped_ptr<InputEventAckState> sync_ack_result_;
   base::MessageLoopForUI message_loop_;
 };
 
@@ -293,7 +295,7 @@
   EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
 
   // Coalesced without changing event order. Note anchor at (60, 60). Anchoring
-  // from a poinht that is not the origin should still give us the wight scroll.
+  // from a point that is not the origin should still give us the right scroll.
   SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
   EXPECT_EQ(4U, GestureEventLastQueueEventSize());
   merged_event = GestureEventLastQueueEvent();
@@ -435,6 +437,7 @@
   // Check that the ACK gets ignored.
   SendInputEventACK(WebInputEvent::GestureScrollUpdate,
                     INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, last_acked_event().type);
   RunUntilIdle();
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
   // The flag should have been flipped back to false.
@@ -458,29 +461,173 @@
   // Check that the ACK sends the next scroll pinch pair.
   SendInputEventACK(WebInputEvent::GesturePinchUpdate,
                     INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, last_acked_event().type);
   RunUntilIdle();
   EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
 
   // Check that the ACK sends the second message.
   SendInputEventACK(WebInputEvent::GestureScrollUpdate,
                     INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, last_acked_event().type);
   RunUntilIdle();
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
 
   // Check that the ACK sends the second event.
   SendInputEventACK(WebInputEvent::GesturePinchUpdate,
                     INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, last_acked_event().type);
   RunUntilIdle();
   EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
 
   // Check that the queue is empty after ACK and no events get sent.
   SendInputEventACK(WebInputEvent::GestureScrollUpdate,
                     INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, last_acked_event().type);
   RunUntilIdle();
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
   EXPECT_EQ(0U, GestureEventLastQueueEventSize());
 }
 
+TEST_F(GestureEventFilterTest, CoalescesMultiplePinchEventSequences) {
+  // Turn off debounce handling for test isolation.
+  set_debounce_interval_time_ms(0);
+
+  // Simulate a pinch sequence.
+  SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+                       WebGestureEvent::Touchscreen);
+  SimulateGestureEvent(WebInputEvent::GesturePinchBegin,
+                       WebGestureEvent::Touchscreen);
+
+  SimulateGestureScrollUpdateEvent(8, -4, 1);
+  // Make sure that the queue contains what we think it should.
+  WebGestureEvent merged_event = GestureEventLastQueueEvent();
+  size_t expected_events_in_queue = 3;
+  EXPECT_EQ(expected_events_in_queue, GestureEventLastQueueEventSize());
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+
+  // Coalesced without changing event order. Note anchor at (60, 60). Anchoring
+  // from a point that is not the origin should still give us the right scroll.
+  SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
+  EXPECT_EQ(++expected_events_in_queue, GestureEventLastQueueEventSize());
+  merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, merged_event.type);
+  EXPECT_EQ(1.5, merged_event.data.pinchUpdate.scale);
+  EXPECT_EQ(1, merged_event.modifiers);
+  merged_event = GestureEventSecondFromLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+  EXPECT_EQ(8, merged_event.data.scrollUpdate.deltaX);
+  EXPECT_EQ(-4, merged_event.data.scrollUpdate.deltaY);
+  EXPECT_EQ(1, merged_event.modifiers);
+
+  // Enqueued.
+  SimulateGestureScrollUpdateEvent(6, -3, 1);
+
+  // Check whether coalesced correctly.
+  EXPECT_EQ(expected_events_in_queue, GestureEventLastQueueEventSize());
+  merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, merged_event.type);
+  EXPECT_EQ(1.5, merged_event.data.pinchUpdate.scale);
+  EXPECT_EQ(1, merged_event.modifiers);
+  merged_event = GestureEventSecondFromLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+  EXPECT_EQ(12, merged_event.data.scrollUpdate.deltaX);
+  EXPECT_EQ(-6, merged_event.data.scrollUpdate.deltaY);
+  EXPECT_EQ(1, merged_event.modifiers);
+
+  // Now start another sequence before the previous sequence has been ack'ed.
+  SimulateGestureEvent(WebInputEvent::GesturePinchEnd,
+                       WebGestureEvent::Touchscreen);
+  SimulateGestureEvent(WebInputEvent::GestureScrollEnd,
+                       WebGestureEvent::Touchscreen);
+  SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+                       WebGestureEvent::Touchscreen);
+  SimulateGestureEvent(WebInputEvent::GesturePinchBegin,
+                       WebGestureEvent::Touchscreen);
+
+  SimulateGestureScrollUpdateEvent(8, -4, 1);
+  // Make sure that the queue contains what we think it should.
+  expected_events_in_queue += 5;
+  merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(expected_events_in_queue, GestureEventLastQueueEventSize());
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+
+  // Coalesced without changing event order. Note anchor at (60, 60). Anchoring
+  // from a point that is not the origin should still give us the right scroll.
+  SimulateGesturePinchUpdateEvent(1.5, 30, 30, 1);
+  EXPECT_EQ(++expected_events_in_queue, GestureEventLastQueueEventSize());
+  merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, merged_event.type);
+  EXPECT_EQ(1.5, merged_event.data.pinchUpdate.scale);
+  EXPECT_EQ(1, merged_event.modifiers);
+  merged_event = GestureEventSecondFromLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+  EXPECT_EQ(8, merged_event.data.scrollUpdate.deltaX);
+  EXPECT_EQ(-4, merged_event.data.scrollUpdate.deltaY);
+  EXPECT_EQ(1, merged_event.modifiers);
+
+  // Enqueued.
+  SimulateGestureScrollUpdateEvent(6, -3, 1);
+
+  // Check whether coalesced correctly.
+  EXPECT_EQ(expected_events_in_queue, GestureEventLastQueueEventSize());
+  merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, merged_event.type);
+  EXPECT_EQ(1.5, merged_event.data.pinchUpdate.scale);
+  EXPECT_EQ(1, merged_event.modifiers);
+  merged_event = GestureEventSecondFromLastQueueEvent();
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+  EXPECT_EQ(12, merged_event.data.scrollUpdate.deltaX);
+  EXPECT_EQ(-6, merged_event.data.scrollUpdate.deltaY);
+  EXPECT_EQ(1, merged_event.modifiers);
+}
+
+
+TEST_F(GestureEventFilterTest, CoalescesScrollAndPinchEventWithSyncAck) {
+  // Turn off debounce handling for test isolation.
+  set_debounce_interval_time_ms(0);
+
+  // Simulate a pinch sequence.
+  SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+                       WebGestureEvent::Touchscreen);
+  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+  SimulateGestureEvent(WebInputEvent::GesturePinchBegin,
+                       WebGestureEvent::Touchscreen);
+  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+
+  SimulateGestureScrollUpdateEvent(8, -4, 1);
+  // Make sure that the queue contains what we think it should.
+  WebGestureEvent merged_event = GestureEventLastQueueEvent();
+  EXPECT_EQ(3U, GestureEventLastQueueEventSize());
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, merged_event.type);
+
+  // Coalesced without changing event order. Note anchor at (60, 60). Anchoring
+  // from a point that is not the origin should still give us the right scroll.
+  SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
+  EXPECT_EQ(4U, GestureEventLastQueueEventSize());
+
+  SendInputEventACK(WebInputEvent::GestureScrollBegin,
+                    INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(3U, GestureEventLastQueueEventSize());
+
+  // Ack the PinchBegin, and schedule a synchronous ack for GestureScrollUpdate.
+  set_synchronous_ack(INPUT_EVENT_ACK_STATE_CONSUMED);
+  SendInputEventACK(WebInputEvent::GesturePinchBegin,
+                    INPUT_EVENT_ACK_STATE_CONSUMED);
+
+  // Both GestureScrollUpdate and GesturePinchUpdate should have been sent.
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, last_acked_event().type);
+  EXPECT_EQ(1U, GestureEventLastQueueEventSize());
+  EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
+
+  // Ack the final GesturePinchUpdate.
+  SendInputEventACK(WebInputEvent::GesturePinchUpdate,
+                    INPUT_EVENT_ACK_STATE_CONSUMED);
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, last_acked_event().type);
+  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
+  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+}
+
 #if GTEST_HAS_PARAM_TEST
 TEST_P(GestureEventFilterWithSourceTest, GestureFlingCancelsFiltered) {
   WebGestureEvent::SourceDevice source_device = GetParam();
@@ -578,271 +725,68 @@
                                         WebGestureEvent::Touchpad));
 #endif  // GTEST_HAS_PARAM_TEST
 
-// Test that GestureTapDown events are deferred.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDown) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
+// Test that GestureShowPress and GestureTapDown events don't wait for ACKs.
+TEST_F(GestureEventFilterTest, GestureShowPressAndTapDownIgnoreAck) {
+  SimulateGestureEvent(WebInputEvent::GestureShowPress,
+                       WebGestureEvent::Touchscreen);
+
+  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
+
+  SimulateGestureEvent(WebInputEvent::GestureShowPress,
+                       WebGestureEvent::Touchscreen);
+
+  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
+
+  SimulateGestureEvent(WebInputEvent::GestureShowPress,
+                       WebGestureEvent::Touchscreen);
+
+  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
 
   SimulateGestureEvent(WebInputEvent::GestureTapDown,
                        WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
 
   EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  // The tap down event will have escaped the queue, since they're async.
+  // The show press and tap down events will have escaped the queue, since they
+  // ignore acks.
   EXPECT_EQ(0U, GestureEventLastQueueEventSize());
 }
 
-// Test that GestureTapDown events are sent immediately on GestureTap.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDownSentOnTap) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
+// Test that GestureShowPress events don't get out of order due to
+// ignoring their acks.
+TEST_F(GestureEventFilterTest, GestureShowPressIsInOrder) {
   SimulateGestureEvent(WebInputEvent::GestureTap,
                        WebGestureEvent::Touchscreen);
 
-  EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(1U, GestureEventLastQueueEventSize());
-  EXPECT_EQ(WebInputEvent::GestureTap,
-            GestureEventLastQueueEvent().type);
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(WebInputEvent::GestureTapDown,
-            last_immediately_sent_gesture_event().type);
-
-  // If the deferral timer incorrectly fired, it sent an extra event.
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-}
-
-// Test that only a single GestureTapDown event is sent when tap occurs after
-// the timeout.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDownOnlyOnce) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Wait long enough for the timeout and verify it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  // The tap down events will have escaped the queue, since they're async.
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Now send the tap gesture and verify we didn't get an extra TapDown.
-  SimulateGestureEvent(WebInputEvent::GestureTap,
-                       WebGestureEvent::Touchscreen);
   EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
   EXPECT_EQ(1U, GestureEventLastQueueEventSize());
-  EXPECT_EQ(WebInputEvent::GestureTap,
-            GestureEventLastQueueEvent().type);
-}
 
-// Test that GestureTapDown events don't wait for ACKs.
-TEST_F(GestureEventFilterTest, GestureTapDownIsAsync) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Wait for tap deferral to end.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
+  SimulateGestureEvent(WebInputEvent::GestureShowPress,
                        WebGestureEvent::Touchscreen);
 
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Wait for tap deferral to end.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  // Wait for tap deferral to end.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  // The tap down events will have escaped the queue, since they're async.
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-}
-
-// Test that GestureTapDown events don't get out of order due to asynchronicity.
-TEST_F(GestureEventFilterTest, GestureTapDownIsInOrder) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTap,
-                       WebGestureEvent::Touchscreen);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  // TapDown is deferred, hasn't entered the queue yet.
-  EXPECT_EQ(1U, GestureEventLastQueueEventSize());
-
-  // Wait long enough for the first timeout and verify it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  // The TapDown, though asynchronous, is still stuck in the queue
-  // behind the synchronous Tap.
+  // The ShowPress, though it ignores ack, is still stuck in the queue
+  // behind the Tap which requires an ack.
   EXPECT_EQ(2U, GestureEventLastQueueEventSize());
 
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
+  SimulateGestureEvent(WebInputEvent::GestureShowPress,
                        WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  // TapDown is deferred, hasn't entered the queue yet.
-  EXPECT_EQ(2U, GestureEventLastQueueEventSize());
-
-  // Wait long enough for the second timeout and verify it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
 
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  // TapDown has entered the queue.
+  // ShowPress has entered the queue.
   EXPECT_EQ(3U, GestureEventLastQueueEventSize());
 
   SendInputEventACK(WebInputEvent::GestureTap,
                     INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
 
-  // Now that the Tap has been ACKed, the TapDowns should fire immediately.
+  // Now that the Tap has been ACKed, the ShowPress events should fire
+  // immediately.
   EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
   EXPECT_EQ(0U, GestureEventLastQueueEventSize());
 }
 
-// Test that scroll events during the deferral interval drop the GestureTapDown.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDownAnulledOnScroll) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(1U, GestureEventLastQueueEventSize());
-  EXPECT_EQ(WebInputEvent::GestureScrollBegin,
-            GestureEventLastQueueEvent().type);
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  // If the deferral timer incorrectly fired, it will send an extra event.
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-}
-
-// Test that a tap cancel event during the deferral interval drops the
-// GestureTapDown.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDownAnulledOnTapCancel) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  SimulateGestureEvent(WebInputEvent::GestureTapCancel,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  // If the deferral timer incorrectly fired, it will send an extra event.
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-}
-
-// Test that if a GestureTapDown gets sent, any corresponding GestureTapCancel
-// is also sent.
-TEST_F(GestureEventFilterTest, DeferredGestureTapDownTapCancel) {
-  // Set some sort of short deferral timeout
-  set_maximum_tap_gap_time_ms(5);
-
-  SimulateGestureEvent(WebInputEvent::GestureTapDown,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      TimeDelta::FromMilliseconds(10));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventLastQueueEventSize());
-
-  SimulateGestureEvent(WebInputEvent::GestureTapCancel,
-                       WebGestureEvent::Touchscreen);
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(1U, GestureEventLastQueueEventSize());
-}
-
 // Test that a GestureScrollEnd | GestureFlingStart are deferred during the
 // debounce interval, that Scrolls are not and that the deferred events are
 // sent after that timer fires.
@@ -888,11 +832,7 @@
 
   // The deferred events are correctly queued in coalescing queue.
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  if (ShouldDeferTapDownEvents())
-    // NOTE: The  TapDown is still deferred hence not queued.
-    EXPECT_EQ(4U, GestureEventLastQueueEventSize());
-  else
-    EXPECT_EQ(5U, GestureEventLastQueueEventSize());
+  EXPECT_EQ(5U, GestureEventLastQueueEventSize());
   EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
   EXPECT_FALSE(ScrollingInProgress());
 
diff --git a/content/browser/renderer_host/input/immediate_input_router.cc b/content/browser/renderer_host/input/immediate_input_router.cc
index ce64dfa..444678f 100644
--- a/content/browser/renderer_host/input/immediate_input_router.cc
+++ b/content/browser/renderer_host/input/immediate_input_router.cc
@@ -303,17 +303,6 @@
   return sender_->Send(message);
 }
 
-void ImmediateInputRouter::SendWebInputEvent(
-    const WebInputEvent& input_event,
-    const ui::LatencyInfo& latency_info,
-    bool is_keyboard_shortcut) {
-  input_event_start_time_ = TimeTicks::Now();
-  if (Send(new InputMsg_HandleInputEvent(
-          routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
-    client_->IncrementInFlightEventCount();
-  }
-}
-
 void ImmediateInputRouter::FilterAndSendWebInputEvent(
     const WebInputEvent& input_event,
     const ui::LatencyInfo& latency_info,
@@ -321,28 +310,35 @@
   TRACE_EVENT1("input", "ImmediateInputRouter::FilterAndSendWebInputEvent",
                "type", WebInputEventTraits::GetName(input_event.type));
 
+  // Transmit any pending wheel events on a non-wheel event. This ensures that
+  // final PhaseEnded wheel event is received, which is necessary to terminate
+  // rubber-banding, for example.
+   if (input_event.type != WebInputEvent::MouseWheel) {
+    WheelEventQueue mouse_wheel_events;
+    mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
+    for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
+      OfferToHandlers(mouse_wheel_events[i].event,
+                      mouse_wheel_events[i].latency,
+                      false);
+     }
+  }
+
+  // Any input event cancels a pending mouse move event.
+  next_mouse_move_.reset();
+
+  OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
+}
+
+void ImmediateInputRouter::OfferToHandlers(const WebInputEvent& input_event,
+                                           const ui::LatencyInfo& latency_info,
+                                           bool is_keyboard_shortcut) {
   if (OfferToOverscrollController(input_event, latency_info))
     return;
 
   if (OfferToClient(input_event, latency_info))
     return;
 
-  // Transmit any pending wheel events on a non-wheel event. This ensures that
-  // the renderer receives the final PhaseEnded wheel event, which is necessary
-  // to terminate rubber-banding, for example.
-  if (input_event.type != WebInputEvent::MouseWheel) {
-    for (size_t i = 0; i < coalesced_mouse_wheel_events_.size(); ++i) {
-      SendWebInputEvent(coalesced_mouse_wheel_events_[i].event,
-                        coalesced_mouse_wheel_events_[i].latency,
-                        false);
-    }
-    coalesced_mouse_wheel_events_.clear();
-  }
-
-  SendWebInputEvent(input_event, latency_info, is_keyboard_shortcut);
-
-  // Any input event cancels a pending mouse move event.
-  next_mouse_move_.reset();
+  OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
 }
 
 bool ImmediateInputRouter::OfferToOverscrollController(
@@ -406,6 +402,18 @@
   return consumed;
 }
 
+bool ImmediateInputRouter::OfferToRenderer(const WebInputEvent& input_event,
+                                           const ui::LatencyInfo& latency_info,
+                                           bool is_keyboard_shortcut) {
+  input_event_start_time_ = TimeTicks::Now();
+  if (Send(new InputMsg_HandleInputEvent(
+          routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
+    client_->IncrementInFlightEventCount();
+    return true;
+  }
+  return false;
+}
+
 void ImmediateInputRouter::OnInputEventAck(
     WebInputEvent::Type event_type,
     InputEventAckState ack_result,
@@ -623,6 +631,9 @@
         startX = x;
         startY = y;
         SendGestureEvent(MakeGestureEvent(
+            WebInputEvent::GestureShowPress, mouse_event.timeStampSeconds,
+            x, y, 0, event.latency));
+        SendGestureEvent(MakeGestureEvent(
             WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
             x, y, 0, event.latency));
       }
diff --git a/content/browser/renderer_host/input/immediate_input_router.h b/content/browser/renderer_host/input/immediate_input_router.h
index 6210bf7..cc760bd 100644
--- a/content/browser/renderer_host/input/immediate_input_router.h
+++ b/content/browser/renderer_host/input/immediate_input_router.h
@@ -90,26 +90,32 @@
   bool SendSelectRange(scoped_ptr<IPC::Message> message);
   bool Send(IPC::Message* message);
 
-  // Transmits the given input event an as an IPC::Message. This is an internal
-  // helper for |FilterAndSendInputEvent()| and should not be used otherwise.
-  void SendWebInputEvent(const WebKit::WebInputEvent& input_event,
-                         const ui::LatencyInfo& latency_info,
-                         bool is_keyboard_shortcut);
-
-  // Filters and forwards the given WebInputEvent to |SendWebInputEvent()|. This
-  // is an internal helper for |Send*Event()| and should not be used otherwise.
+  // Filters and forwards |input_event| to the appropriate handler.
   void FilterAndSendWebInputEvent(const WebKit::WebInputEvent& input_event,
                                   const ui::LatencyInfo& latency_info,
                                   bool is_keyboard_shortcut);
-  // Returns true if the event was consumed by the OverscrollController, called
-  // immediately prior to sending |input_event| to the renderer.
+
+  // Utility routine for filtering and forwarding |input_event| to the
+  // appropriate handler. |input_event| will be offered to the overscroll
+  // controller, client and renderer, in that order.
+  void OfferToHandlers(const WebKit::WebInputEvent& input_event,
+                       const ui::LatencyInfo& latency_info,
+                       bool is_keyboard_shortcut);
+
+  // Returns true if |input_event| was consumed by the overscroll controller.
   bool OfferToOverscrollController(const WebKit::WebInputEvent& input_event,
                                    const ui::LatencyInfo& latency_info);
-  // Returns true if the event was consumed by the client, called immediately
-  // prior to sending |input_event| to the renderer.
+
+  // Returns true if |input_event| was consumed by the client.
   bool OfferToClient(const WebKit::WebInputEvent& input_event,
                      const ui::LatencyInfo& latency_info);
 
+  // Returns true if |input_event| was successfully sent to the renderer
+  // as an async IPC Message.
+  bool OfferToRenderer(const WebKit::WebInputEvent& input_event,
+                       const ui::LatencyInfo& latency_info,
+                       bool is_keyboard_shortcut);
+
   // IPC message handlers
   void OnInputEventAck(WebKit::WebInputEvent::Type event_type,
                        InputEventAckState ack_result,
diff --git a/content/browser/renderer_host/input/input_router_unittest.cc b/content/browser/renderer_host/input/input_router_unittest.cc
index 3981d73..48ec3bf 100644
--- a/content/browser/renderer_host/input/input_router_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_unittest.cc
@@ -44,9 +44,10 @@
 
 void InputRouterTest::SimulateKeyboardEvent(WebInputEvent::Type type,
                                             bool is_shortcut) {
-  input_router_->SendKeyboardEvent(MockWebKeyboardEventBuilder::Build(type),
-                                   ui::LatencyInfo(),
-                                   is_shortcut);
+  input_router_->SendKeyboardEvent(
+      SyntheticWebKeyboardEventBuilder::Build(type),
+      ui::LatencyInfo(),
+      is_shortcut);
 }
 
 void InputRouterTest::SimulateWheelEvent(float dX,
@@ -55,13 +56,13 @@
                                          bool precise) {
   input_router_->SendWheelEvent(
       MouseWheelEventWithLatencyInfo(
-          MockWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise),
+          SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise),
           ui::LatencyInfo()));
 }
 
 void InputRouterTest::SimulateMouseMove(int x, int y, int modifiers) {
   input_router_->SendMouseEvent(
-      MouseEventWithLatencyInfo(MockWebMouseEventBuilder::Build(
+      MouseEventWithLatencyInfo(SyntheticWebMouseEventBuilder::Build(
                                     WebInputEvent::MouseMove, x, y, modifiers),
                                 ui::LatencyInfo()));
 }
@@ -70,7 +71,7 @@
     WebMouseWheelEvent::Phase phase) {
   input_router_->SendWheelEvent(
       MouseWheelEventWithLatencyInfo(
-          MockWebMouseWheelEventBuilder::Build(phase), ui::LatencyInfo()));
+          SyntheticWebMouseWheelEventBuilder::Build(phase), ui::LatencyInfo()));
 }
 
 // Inject provided synthetic WebGestureEvent instance.
@@ -84,14 +85,15 @@
 void InputRouterTest::SimulateGestureEvent(
     WebInputEvent::Type type,
     WebGestureEvent::SourceDevice sourceDevice) {
-  SimulateGestureEvent(MockWebGestureEventBuilder::Build(type, sourceDevice));
+  SimulateGestureEvent(
+      SyntheticWebGestureEventBuilder::Build(type, sourceDevice));
 }
 
 void InputRouterTest::SimulateGestureScrollUpdateEvent(float dX,
                                                        float dY,
                                                        int modifiers) {
   SimulateGestureEvent(
-      MockWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+      SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
 }
 
 void InputRouterTest::SimulateGesturePinchUpdateEvent(float scale,
@@ -99,10 +101,10 @@
                                                       float anchorY,
                                                       int modifiers) {
   SimulateGestureEvent(
-      MockWebGestureEventBuilder::BuildPinchUpdate(scale,
-                                                   anchorX,
-                                                   anchorY,
-                                                   modifiers));
+      SyntheticWebGestureEventBuilder::BuildPinchUpdate(scale,
+                                                        anchorX,
+                                                        anchorY,
+                                                        modifiers));
 }
 
 // Inject synthetic GestureFlingStart events.
@@ -111,9 +113,9 @@
     float velocityY,
     WebGestureEvent::SourceDevice sourceDevice) {
   SimulateGestureEvent(
-      MockWebGestureEventBuilder::BuildFling(velocityX,
-                                             velocityY,
-                                             sourceDevice));
+      SyntheticWebGestureEventBuilder::BuildFling(velocityX,
+                                                  velocityY,
+                                                  sourceDevice));
 }
 
 void InputRouterTest::SimulateTouchEvent(int x, int y) {
diff --git a/content/browser/renderer_host/input/input_router_unittest.h b/content/browser/renderer_host/input/input_router_unittest.h
index 8901301..bd1e6f4 100644
--- a/content/browser/renderer_host/input/input_router_unittest.h
+++ b/content/browser/renderer_host/input/input_router_unittest.h
@@ -9,7 +9,7 @@
 #include "content/browser/renderer_host/input/input_router_client.h"
 #include "content/browser/renderer_host/input/mock_input_ack_handler.h"
 #include "content/browser/renderer_host/input/mock_input_router_client.h"
-#include "content/browser/renderer_host/input/mock_web_input_event_builders.h"
+#include "content/browser/renderer_host/input/synthetic_web_input_event_builders.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,7 +73,7 @@
 
  private:
   base::MessageLoopForUI message_loop_;
-  MockWebTouchEvent touch_event_;
+  SyntheticWebTouchEvent touch_event_;
 
   scoped_ptr<TestBrowserContext> browser_context_;
 };
diff --git a/content/browser/renderer_host/input/mock_web_input_event_builders.cc b/content/browser/renderer_host/input/mock_web_input_event_builders.cc
deleted file mode 100644
index 3e80b6e..0000000
--- a/content/browser/renderer_host/input/mock_web_input_event_builders.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2013 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/renderer_host/input/mock_web_input_event_builders.h"
-
-#include "base/logging.h"
-#include "content/browser/renderer_host/input/web_input_event_util.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-namespace content {
-
-using WebKit::WebInputEvent;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebGestureEvent;
-using WebKit::WebMouseEvent;
-using WebKit::WebMouseWheelEvent;
-using WebKit::WebTouchEvent;
-using WebKit::WebTouchPoint;
-
-WebMouseEvent MockWebMouseEventBuilder::Build(
-    WebKit::WebInputEvent::Type type) {
-  WebMouseEvent result;
-  result.type = type;
-  return result;
-}
-
-WebMouseEvent MockWebMouseEventBuilder::Build(WebKit::WebInputEvent::Type type,
-                                              int window_x,
-                                              int window_y,
-                                              int modifiers) {
-  DCHECK(WebInputEvent::isMouseEventType(type));
-  WebMouseEvent result = Build(type);
-  result.x = window_x;
-  result.y = window_y;
-  result.windowX = window_x;
-  result.windowY = window_y;
-  result.modifiers = modifiers;
-
-  if (type == WebInputEvent::MouseDown || type == WebInputEvent::MouseUp)
-    result.button = WebMouseEvent::ButtonLeft;
-  else
-    result.button = WebMouseEvent::ButtonNone;
-
-  return result;
-}
-
-WebMouseWheelEvent MockWebMouseWheelEventBuilder::Build(
-    WebMouseWheelEvent::Phase phase) {
-  WebMouseWheelEvent result;
-  result.type = WebInputEvent::MouseWheel;
-  result.phase = phase;
-  return result;
-}
-
-WebMouseWheelEvent MockWebMouseWheelEventBuilder::Build(float dx,
-                                                        float dy,
-                                                        int modifiers,
-                                                        bool precise) {
-  WebMouseWheelEvent result;
-  result.type = WebInputEvent::MouseWheel;
-  result.deltaX = dx;
-  result.deltaY = dy;
-  result.modifiers = modifiers;
-  result.hasPreciseScrollingDeltas = precise;
-  return result;
-}
-
-NativeWebKeyboardEvent MockWebKeyboardEventBuilder::Build(
-    WebInputEvent::Type type) {
-  DCHECK(WebInputEvent::isKeyboardEventType(type));
-  NativeWebKeyboardEvent result;
-  result.type = type;
-  result.windowsKeyCode = ui::VKEY_L;  // non-null made up value.
-  return result;
-}
-
-WebGestureEvent MockWebGestureEventBuilder::Build(
-    WebInputEvent::Type type,
-    WebGestureEvent::SourceDevice source_device) {
-  DCHECK(WebInputEvent::isGestureEventType(type));
-  WebGestureEvent result;
-  result.type = type;
-  result.sourceDevice = source_device;
-  return result;
-}
-
-WebGestureEvent MockWebGestureEventBuilder::BuildScrollUpdate(
-    float dx,
-    float dy,
-    int modifiers) {
-  WebGestureEvent result = Build(WebInputEvent::GestureScrollUpdate,
-                                 WebGestureEvent::Touchscreen);
-  result.data.scrollUpdate.deltaX = dx;
-  result.data.scrollUpdate.deltaY = dy;
-  result.modifiers = modifiers;
-  return result;
-}
-
-WebGestureEvent MockWebGestureEventBuilder::BuildPinchUpdate(
-    float scale,
-    float anchor_x,
-    float anchor_y,
-    int modifiers) {
-  WebGestureEvent result = Build(WebInputEvent::GesturePinchUpdate,
-                                 WebGestureEvent::Touchscreen);
-  result.data.pinchUpdate.scale = scale;
-  result.x = anchor_x;
-  result.y = anchor_y;
-  result.modifiers = modifiers;
-  return result;
-}
-
-WebGestureEvent MockWebGestureEventBuilder::BuildFling(
-    float velocity_x,
-    float velocity_y,
-    WebGestureEvent::SourceDevice source_device) {
-  WebGestureEvent result = Build(WebInputEvent::GestureFlingStart,
-                                 source_device);
-  result.data.flingStart.velocityX = velocity_x;
-  result.data.flingStart.velocityY = velocity_y;
-  return result;
-}
-
-MockWebTouchEvent::MockWebTouchEvent() : WebTouchEvent() {}
-
-void MockWebTouchEvent::ResetPoints() {
-  int point = 0;
-  for (unsigned int i = 0; i < touchesLength; ++i) {
-    if (touches[i].state == WebTouchPoint::StateReleased)
-      continue;
-
-    touches[point] = touches[i];
-    touches[point].state = WebTouchPoint::StateStationary;
-    ++point;
-  }
-  touchesLength = point;
-  type = WebInputEvent::Undefined;
-}
-
-int MockWebTouchEvent::PressPoint(int x, int y) {
-  if (touchesLength == touchesLengthCap)
-    return -1;
-  WebTouchPoint& point = touches[touchesLength];
-  point.id = touchesLength;
-  point.position.x = point.screenPosition.x = x;
-  point.position.y = point.screenPosition.y = y;
-  point.state = WebTouchPoint::StatePressed;
-  point.radiusX = point.radiusY = 1.f;
-  ++touchesLength;
-  type = WebInputEvent::TouchStart;
-  return point.id;
-}
-
-void MockWebTouchEvent::MovePoint(int index, int x, int y) {
-  CHECK(index >= 0 && index < touchesLengthCap);
-  WebTouchPoint& point = touches[index];
-  point.position.x = point.screenPosition.x = x;
-  point.position.y = point.screenPosition.y = y;
-  touches[index].state = WebTouchPoint::StateMoved;
-  type = WebInputEvent::TouchMove;
-}
-
-void MockWebTouchEvent::ReleasePoint(int index) {
-  CHECK(index >= 0 && index < touchesLengthCap);
-  touches[index].state = WebTouchPoint::StateReleased;
-  type = WebInputEvent::TouchEnd;
-}
-
-void MockWebTouchEvent::SetTimestamp(base::TimeDelta timestamp) {
-  timeStampSeconds = timestamp.InSecondsF();
-}
-
-MockWebTouchEvent MockWebTouchEventBuilder::Build(WebInputEvent::Type type) {
-  DCHECK(WebInputEvent::isTouchEventType(type));
-  MockWebTouchEvent result;
-  result.type = type;
-  return result;
-};
-
-}  // namespace content
diff --git a/content/browser/renderer_host/input/mock_web_input_event_builders.h b/content/browser/renderer_host/input/mock_web_input_event_builders.h
deleted file mode 100644
index 0cc8d08..0000000
--- a/content/browser/renderer_host/input/mock_web_input_event_builders.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_MOCK_WEB_INPUT_EVENT_BUILDERS_H_
-#define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_WEB_INPUT_EVENT_BUILDERS_H_
-
-#include "base/time/time.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-
-// Provides sensible creation of default WebInputEvents for testing purposes.
-
-namespace content {
-
-class MockWebMouseEventBuilder {
- public:
-  static WebKit::WebMouseEvent Build(WebKit::WebInputEvent::Type type);
-  static WebKit::WebMouseEvent Build(WebKit::WebInputEvent::Type type,
-                                     int window_x,
-                                     int window_y,
-                                     int modifiers);
-};
-
-class MockWebMouseWheelEventBuilder {
- public:
-  static WebKit::WebMouseWheelEvent Build(
-      WebKit::WebMouseWheelEvent::Phase phase);
-  static WebKit::WebMouseWheelEvent Build(float dx,
-                                          float dy,
-                                          int modifiers,
-                                          bool precise);
-};
-
-class MockWebKeyboardEventBuilder {
- public:
-  static NativeWebKeyboardEvent Build(WebKit::WebInputEvent::Type type);
-};
-
-class MockWebGestureEventBuilder {
- public:
-  static WebKit::WebGestureEvent Build(
-      WebKit::WebInputEvent::Type type,
-      WebKit::WebGestureEvent::SourceDevice sourceDevice);
-  static WebKit::WebGestureEvent BuildScrollUpdate(float dx,
-                                                   float dY,
-                                                   int modifiers);
-  static WebKit::WebGestureEvent BuildPinchUpdate(float scale,
-                                                  float anchor_x,
-                                                  float anchor_y,
-                                                  int modifiers);
-  static WebKit::WebGestureEvent BuildFling(
-      float velocity_x,
-      float velocity_y,
-      WebKit::WebGestureEvent::SourceDevice source_device);
-};
-
-struct MockWebTouchEvent : public WebKit::WebTouchEvent {
- public:
-  MockWebTouchEvent();
-
-  // Mark all the points as stationary, and remove any released points.
-  void ResetPoints();
-
-  // Adds an additional point to the touch list, returning the point's index.
-  int PressPoint(int x, int y);
-  void MovePoint(int index, int x, int y);
-  void ReleasePoint(int index);
-
-  void SetTimestamp(base::TimeDelta timestamp);
-};
-
-class MockWebTouchEventBuilder {
- public:
-  static MockWebTouchEvent Build(WebKit::WebInputEvent::Type type);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOCK_WEB_INPUT_EVENT_BUILDERS_H_
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller_new.cc b/content/browser/renderer_host/input/synthetic_gesture_controller_new.cc
new file mode 100644
index 0000000..2c277dc
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller_new.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/renderer_host/input/synthetic_gesture_controller_new.h"
+
+#include "base/debug/trace_event.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/common/input_messages.h"
+#include "content/public/browser/render_widget_host.h"
+
+namespace content {
+
+SyntheticGestureControllerNew::SyntheticGestureControllerNew(
+    SyntheticGestureTarget* gesture_target)
+    : gesture_target_(gesture_target) {}
+
+SyntheticGestureControllerNew::~SyntheticGestureControllerNew() {}
+
+void SyntheticGestureControllerNew::QueueSyntheticGesture(
+    scoped_ptr<SyntheticGestureNew> synthetic_gesture) {
+  DCHECK(synthetic_gesture);
+
+  pending_gesture_queue_.push_back(synthetic_gesture.release());
+
+  // Start forwarding input events if the queue was previously empty.
+  if (pending_gesture_queue_.size() == 1) {
+    StartGesture(*pending_gesture_queue_.front());
+    last_tick_time_ = base::TimeTicks::Now();
+    timer_.Start(FROM_HERE,
+                 gesture_target_->GetSyntheticGestureUpdateRate(),
+                 this,
+                 &SyntheticGestureControllerNew::ForwardInputEvents);
+  }
+}
+
+void SyntheticGestureControllerNew::ForwardInputEvents() {
+  DCHECK(!pending_gesture_queue_.empty());
+  DCHECK(!last_tick_time_.is_null());
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeDelta interval = last_tick_time_ - now;
+  last_tick_time_ = now;
+  SyntheticGestureNew::Result result =
+      pending_gesture_queue_.front()->ForwardInputEvents(interval,
+                                                         gesture_target_);
+
+  if (result != SyntheticGestureNew::GESTURE_RUNNING) {
+
+    StopGesture(*pending_gesture_queue_.front(), result);
+    pending_gesture_queue_.erase(pending_gesture_queue_.begin());
+
+    if (!pending_gesture_queue_.empty())
+      StartGesture(*pending_gesture_queue_.front());
+    else
+      timer_.Stop();
+  }
+}
+
+void SyntheticGestureControllerNew::StartGesture(
+    const SyntheticGestureNew& gesture) {
+  TRACE_EVENT_ASYNC_BEGIN0("benchmark", "SyntheticGestureController::running",
+                           &gesture);
+}
+
+void SyntheticGestureControllerNew::StopGesture(
+    const SyntheticGestureNew& gesture, SyntheticGestureNew::Result result) {
+  DCHECK_NE(result, SyntheticGestureNew::GESTURE_RUNNING);
+  TRACE_EVENT_ASYNC_END0("benchmark", "SyntheticGestureController::running",
+                         &gesture);
+
+  gesture_target_->OnSyntheticGestureCompleted(result);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller_new.h b/content/browser/renderer_host/input/synthetic_gesture_controller_new.h
new file mode 100644
index 0000000..d3acf46
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller_new.h
@@ -0,0 +1,49 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_CONTROLLER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_CONTROLLER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_new.h"
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_gesture_params.h"
+
+namespace content {
+
+class SyntheticGestureTarget;
+
+// Controls a synthetic gesture.
+// Repeatedly invokes the gesture object's ForwardInputEvent method to send
+// input events to the platform until the gesture has finished.
+class CONTENT_EXPORT SyntheticGestureControllerNew {
+ public:
+  explicit SyntheticGestureControllerNew(
+      SyntheticGestureTarget* gesture_target);
+  virtual ~SyntheticGestureControllerNew();
+
+  void QueueSyntheticGesture(
+      scoped_ptr<SyntheticGestureNew> synthetic_gesture);
+
+ private:
+  void ForwardInputEvents();
+
+  void StartGesture(const SyntheticGestureNew& gesture);
+  void StopGesture(const SyntheticGestureNew& gesture,
+                   SyntheticGestureNew::Result result);
+
+  SyntheticGestureTarget* gesture_target_;
+  ScopedVector<SyntheticGestureNew> pending_gesture_queue_;
+
+  base::RepeatingTimer<SyntheticGestureControllerNew> timer_;
+  base::TimeTicks last_tick_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyntheticGestureControllerNew);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_CONTROLLER_H_
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller_new_unittest.cc b/content/browser/renderer_host/input/synthetic_gesture_controller_new_unittest.cc
new file mode 100644
index 0000000..744ebee
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller_new_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright 2013 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/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_controller_new.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_new.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+class MockSyntheticGesture : public SyntheticGestureNew {
+ public:
+  MockSyntheticGesture(bool *finished, int num_steps)
+      : finished_(finished),
+        num_steps_(num_steps),
+        step_count_(0) {
+    *finished_ = false;
+  }
+  virtual ~MockSyntheticGesture() {}
+
+  virtual Result ForwardInputEvents(const base::TimeDelta& interval,
+                                    SyntheticGestureTarget* target) OVERRIDE {
+    step_count_++;
+    if (step_count_ == num_steps_) {
+      *finished_ = true;
+      return SyntheticGestureNew::GESTURE_FINISHED;
+    }
+    else if (step_count_ > num_steps_) {
+      *finished_ = true;
+      // Return arbitrary failure.
+      return SyntheticGestureNew::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
+    }
+    else
+      return SyntheticGestureNew::GESTURE_RUNNING;
+  }
+
+ protected:
+  bool* finished_;
+  int num_steps_;
+  int step_count_;
+};
+
+class MockSyntheticGestureTarget : public SyntheticGestureTarget {
+ public:
+  MockSyntheticGestureTarget() : num_success_(0), num_failure_(0) {}
+  virtual ~MockSyntheticGestureTarget() {}
+
+  virtual void QueueInputEventToPlatform(const InputEvent& event) OVERRIDE {}
+
+  virtual void OnSyntheticGestureCompleted(
+      SyntheticGestureNew::Result result) OVERRIDE {
+    DCHECK_NE(result, SyntheticGestureNew::GESTURE_RUNNING);
+    if (result == SyntheticGestureNew::GESTURE_FINISHED)
+      num_success_++;
+    else
+      num_failure_++;
+  }
+
+  virtual base::TimeDelta GetSyntheticGestureUpdateRate() const OVERRIDE {
+    return base::TimeDelta::FromMilliseconds(16);
+  }
+
+  virtual SyntheticGestureParams::GestureSourceType
+      GetDefaultSyntheticGestureSourceType() const OVERRIDE {
+    return SyntheticGestureParams::TOUCH_INPUT;
+  }
+  virtual bool SupportsSyntheticGestureSourceType(
+      SyntheticGestureParams::GestureSourceType gesture_source_type)
+      const OVERRIDE {
+    return true;
+  }
+
+  int num_success() { return num_success_; }
+  int num_failure() { return num_failure_; }
+
+ private:
+  int num_success_;
+  int num_failure_;
+};
+
+class SyntheticGestureControllerNewTest : public testing::Test {
+ public:
+  SyntheticGestureControllerNewTest() {}
+  virtual ~SyntheticGestureControllerNewTest() {}
+
+ protected:
+  virtual void SetUp() OVERRIDE {
+    target_.reset(new MockSyntheticGestureTarget());
+    controller_.reset(new SyntheticGestureControllerNew(target_.get()));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    controller_.reset();
+    target_.reset();
+
+    // Process all pending tasks to avoid leaks.
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void PostQuitMessageAndRun(int num_steps) {
+    // Allow the message loop to process pending synthetic scrolls, then quit.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE, base::MessageLoop::QuitClosure(),
+        base::TimeDelta::FromMilliseconds(
+            target_->GetSyntheticGestureUpdateRate().InMilliseconds() *
+            num_steps));
+    base::MessageLoop::current()->Run();
+  }
+
+  base::MessageLoopForUI message_loop_;
+
+  scoped_ptr<SyntheticGestureControllerNew> controller_;
+  scoped_ptr<MockSyntheticGestureTarget> target_;
+};
+
+TEST_F(SyntheticGestureControllerNewTest, SingleGesture) {
+  bool finished;
+  scoped_ptr<MockSyntheticGesture> gesture(
+      new MockSyntheticGesture(&finished, 3));
+  controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(5);
+
+  EXPECT_TRUE(finished);
+  EXPECT_EQ(1, target_->num_success());
+  EXPECT_EQ(0, target_->num_failure());
+}
+
+TEST_F(SyntheticGestureControllerNewTest, GestureFailed) {
+  bool finished;
+  scoped_ptr<MockSyntheticGesture> gesture(
+      new MockSyntheticGesture(&finished, 0));
+  controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(5);
+
+  EXPECT_TRUE(finished);
+  EXPECT_EQ(1, target_->num_failure());
+  EXPECT_EQ(0, target_->num_success());
+}
+
+TEST_F(SyntheticGestureControllerNewTest, SuccessiveGestures) {
+  bool finished_1, finished_2;
+  scoped_ptr<MockSyntheticGesture> gesture_1(
+      new MockSyntheticGesture(&finished_1, 2));
+  scoped_ptr<MockSyntheticGesture> gesture_2(
+      new MockSyntheticGesture(&finished_2, 4));
+
+  // Queue first gesture and wait for it to finish
+  controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(4);
+
+  EXPECT_TRUE(finished_1);
+  EXPECT_EQ(1, target_->num_success());
+  EXPECT_EQ(0, target_->num_failure());
+
+  // Queue second gesture.
+  controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(6);
+
+  EXPECT_TRUE(finished_2);
+  EXPECT_EQ(2, target_->num_success());
+  EXPECT_EQ(0, target_->num_failure());
+}
+
+TEST_F(SyntheticGestureControllerNewTest, TwoGesturesInFlight) {
+  bool finished_1, finished_2;
+  scoped_ptr<MockSyntheticGesture> gesture_1(
+      new MockSyntheticGesture(&finished_1, 2));
+  scoped_ptr<MockSyntheticGesture> gesture_2(
+      new MockSyntheticGesture(&finished_2, 4));
+
+  controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGestureNew>());
+  controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(10);
+
+  EXPECT_TRUE(finished_1);
+  EXPECT_TRUE(finished_2);
+
+  EXPECT_EQ(2, target_->num_success());
+  EXPECT_EQ(0, target_->num_failure());
+}
+
+TEST_F(SyntheticGestureControllerNewTest, SmoothScrollGesture) {
+  SyntheticSmoothScrollGestureParams params;
+  params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+  params.distance = 100;
+
+  scoped_ptr<SyntheticSmoothScrollGestureNew> gesture(
+      new SyntheticSmoothScrollGestureNew(params));
+  controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGestureNew>());
+  PostQuitMessageAndRun(20);
+
+  EXPECT_EQ(1, target_->num_success());
+  EXPECT_EQ(0, target_->num_failure());
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_new.cc b/content/browser/renderer_host/input/synthetic_gesture_new.cc
new file mode 100644
index 0000000..0c7f8b2
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_new.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 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/renderer_host/input/synthetic_gesture_new.h"
+
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h"
+
+namespace content {
+namespace {
+
+template <typename GestureType, typename GestureParamsType>
+static scoped_ptr<SyntheticGestureNew> CreateGesture(
+    const SyntheticGestureParams& gesture_params) {
+  return scoped_ptr<SyntheticGestureNew>(
+      new GestureType(*GestureParamsType::Cast(&gesture_params)));
+}
+
+}  // namespace
+
+SyntheticGestureNew::SyntheticGestureNew() {}
+
+SyntheticGestureNew::~SyntheticGestureNew() {}
+
+scoped_ptr<SyntheticGestureNew> SyntheticGestureNew::Create(
+    const SyntheticGestureParams& gesture_params) {
+  switch (gesture_params.GetGestureType()) {
+    case SyntheticGestureParams::SMOOTH_SCROLL_GESTURE:
+      return CreateGesture<SyntheticSmoothScrollGestureNew,
+                           SyntheticSmoothScrollGestureParams>(gesture_params);
+  }
+  NOTREACHED() << "Invalid synthetic gesture type";
+  return scoped_ptr<SyntheticGestureNew>();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_new.h b/content/browser/renderer_host/input/synthetic_gesture_new.h
new file mode 100644
index 0000000..203651b
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_new.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_gesture_params.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+
+class SyntheticGestureTarget;
+
+class CONTENT_EXPORT SyntheticGestureNew {
+ public:
+  SyntheticGestureNew();
+  virtual ~SyntheticGestureNew();
+
+  static scoped_ptr<SyntheticGestureNew> Create(
+      const SyntheticGestureParams& gesture_params);
+
+  enum Result {
+    GESTURE_RUNNING,
+    GESTURE_FINISHED,
+    GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED,
+    GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM,
+    GESTURE_RESULT_MAX = GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM
+  };
+  // Update the state of the gesture and forward the appropriate events to the
+  // platform. This function is called repeatedly by the synthetic gesture
+  // controller until it stops returning GESTURE_RUNNING.
+  virtual Result ForwardInputEvents(
+      const base::TimeDelta& interval, SyntheticGestureTarget* target) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyntheticGestureNew);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_H_
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target.h b/content/browser/renderer_host/input/synthetic_gesture_target.h
new file mode 100644
index 0000000..59ca6c1
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_gesture_target.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_H_
+
+#include "base/time/time.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_new.h"
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_gesture_params.h"
+
+namespace content {
+
+class InputEvent;
+
+// Interface between the synthetic gesture controller and the RWHV.
+class CONTENT_EXPORT SyntheticGestureTarget {
+ public:
+  virtual void QueueInputEventToPlatform(const InputEvent& event) = 0;
+
+  virtual void OnSyntheticGestureCompleted(
+      SyntheticGestureNew::Result result) = 0;
+
+  virtual base::TimeDelta GetSyntheticGestureUpdateRate() const = 0;
+
+  virtual SyntheticGestureParams::GestureSourceType
+      GetDefaultSyntheticGestureSourceType() const = 0;
+  virtual bool SupportsSyntheticGestureSourceType(
+      SyntheticGestureParams::GestureSourceType gesture_source_type) const = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_H_
diff --git a/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc b/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc
new file mode 100644
index 0000000..e56fcd7
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc
@@ -0,0 +1,116 @@
+// Copyright 2013 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/renderer_host/input/synthetic_smooth_scroll_gesture_new.h"
+
+#include <cmath>
+
+#include "content/common/input/input_event.h"
+#include "ui/events/latency_info.h"
+
+namespace content {
+namespace {
+
+// TODO(dominikg): Calibrate or add as another parameter.
+const float kDeltaInPixelsPerMs = 0.5f;
+
+}
+
+SyntheticSmoothScrollGestureNew::SyntheticSmoothScrollGestureNew(
+    const SyntheticSmoothScrollGestureParams& params)
+    : params_(params),
+      current_y_(params_.anchor_y) {}
+
+SyntheticSmoothScrollGestureNew::~SyntheticSmoothScrollGestureNew() {}
+
+SyntheticGestureNew::Result SyntheticSmoothScrollGestureNew::ForwardInputEvents(
+    const base::TimeDelta& interval, SyntheticGestureTarget* target) {
+
+  SyntheticGestureParams::GestureSourceType source =
+      params_.gesture_source_type;
+  if (source == SyntheticGestureParams::DEFAULT_INPUT)
+    source = target->GetDefaultSyntheticGestureSourceType();
+
+  if (!target->SupportsSyntheticGestureSourceType(source)) {
+    return SyntheticGestureNew::GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM;
+  }
+
+  if (source == SyntheticGestureParams::TOUCH_INPUT) {
+    return ForwardTouchInputEvents(interval, target);
+  }
+  else if (source == SyntheticGestureParams::MOUSE_INPUT) {
+    return ForwardMouseInputEvents(interval, target);
+  }
+  else {
+    return SyntheticGestureNew::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
+  }
+}
+
+SyntheticGestureNew::Result
+SyntheticSmoothScrollGestureNew::ForwardTouchInputEvents(
+    const base::TimeDelta& interval, SyntheticGestureTarget* target) {
+  if (HasFinished())
+    return SyntheticGestureNew::GESTURE_FINISHED;
+
+  if (current_y_ == params_.anchor_y) {
+    touch_event_.PressPoint(params_.anchor_x, current_y_);
+    ForwardTouchEvent(target);
+  }
+
+  current_y_ += GetPositionDelta(interval);
+  touch_event_.MovePoint(0, params_.anchor_x, current_y_);
+  ForwardTouchEvent(target);
+
+  if (HasFinished()) {
+    touch_event_.ReleasePoint(0);
+    ForwardTouchEvent(target);
+    return SyntheticGestureNew::GESTURE_FINISHED;
+  }
+  else {
+    return SyntheticGestureNew::GESTURE_RUNNING;
+  }
+}
+
+SyntheticGestureNew::Result
+SyntheticSmoothScrollGestureNew::ForwardMouseInputEvents(
+    const base::TimeDelta& interval, SyntheticGestureTarget* target) {
+  if (HasFinished())
+    return SyntheticGestureNew::GESTURE_FINISHED;
+
+  float delta = GetPositionDelta(interval);
+  current_y_ += delta;
+  ForwardMouseWheelEvent(target, delta);
+
+  if (HasFinished())
+    return SyntheticGestureNew::GESTURE_FINISHED;
+  else
+    return SyntheticGestureNew::GESTURE_RUNNING;
+}
+
+void SyntheticSmoothScrollGestureNew::ForwardTouchEvent(
+    SyntheticGestureTarget* target) {
+  target->QueueInputEventToPlatform(
+      InputEvent(touch_event_, ui::LatencyInfo(), false));
+}
+
+void SyntheticSmoothScrollGestureNew::ForwardMouseWheelEvent(
+    SyntheticGestureTarget* target,
+    float delta) {
+  WebKit::WebMouseWheelEvent mouse_wheel_event =
+      SyntheticWebMouseWheelEventBuilder::Build(0, delta, 0, false);
+
+  target->QueueInputEventToPlatform(
+      InputEvent(mouse_wheel_event, ui::LatencyInfo(), false));
+}
+
+float SyntheticSmoothScrollGestureNew::GetPositionDelta(
+    const base::TimeDelta& interval) {
+  return kDeltaInPixelsPerMs * interval.InMillisecondsF();
+}
+
+bool SyntheticSmoothScrollGestureNew::HasFinished() {
+  return abs(current_y_ - params_.anchor_y) >= abs(params_.distance);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h b/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h
new file mode 100644
index 0000000..a23aaea
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_SCROLL_GESTURE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_SMOOTH_SCROLL_GESTURE_H_
+
+#include "content/browser/renderer_host/input/synthetic_gesture_new.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/browser/renderer_host/input/synthetic_web_input_event_builders.h"
+#include "content/common/content_export.h"
+#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+
+class CONTENT_EXPORT SyntheticSmoothScrollGestureNew :
+    public SyntheticGestureNew {
+ public:
+  explicit SyntheticSmoothScrollGestureNew(
+      const SyntheticSmoothScrollGestureParams& params);
+  virtual ~SyntheticSmoothScrollGestureNew();
+
+  virtual Result ForwardInputEvents(const base::TimeDelta& interval,
+                                    SyntheticGestureTarget* target) OVERRIDE;
+
+ private:
+  SyntheticSmoothScrollGestureParams params_;
+  float current_y_;
+  SyntheticWebTouchEvent touch_event_;
+
+  SyntheticGestureNew::Result ForwardTouchInputEvents(
+      const base::TimeDelta& interval, SyntheticGestureTarget* target);
+  SyntheticGestureNew::Result ForwardMouseInputEvents(
+      const base::TimeDelta& interval, SyntheticGestureTarget* target);
+
+  void ForwardTouchEvent(SyntheticGestureTarget* target);
+  void ForwardMouseWheelEvent(SyntheticGestureTarget* target,
+                              float delta);
+
+  float GetPositionDelta(const base::TimeDelta& interval);
+
+  bool HasFinished();
+
+  DISALLOW_COPY_AND_ASSIGN(SyntheticSmoothScrollGestureNew);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_H_
diff --git a/content/browser/renderer_host/input/synthetic_web_input_event_builders.cc b/content/browser/renderer_host/input/synthetic_web_input_event_builders.cc
new file mode 100644
index 0000000..634299d
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_web_input_event_builders.cc
@@ -0,0 +1,183 @@
+// Copyright 2013 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/renderer_host/input/synthetic_web_input_event_builders.h"
+
+#include "base/logging.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace content {
+
+using WebKit::WebInputEvent;
+using WebKit::WebKeyboardEvent;
+using WebKit::WebGestureEvent;
+using WebKit::WebMouseEvent;
+using WebKit::WebMouseWheelEvent;
+using WebKit::WebTouchEvent;
+using WebKit::WebTouchPoint;
+
+WebMouseEvent SyntheticWebMouseEventBuilder::Build(
+    WebKit::WebInputEvent::Type type) {
+  WebMouseEvent result;
+  result.type = type;
+  return result;
+}
+
+WebMouseEvent SyntheticWebMouseEventBuilder::Build(
+    WebKit::WebInputEvent::Type type,
+    int window_x,
+    int window_y,
+    int modifiers) {
+  DCHECK(WebInputEvent::isMouseEventType(type));
+  WebMouseEvent result = Build(type);
+  result.x = window_x;
+  result.y = window_y;
+  result.windowX = window_x;
+  result.windowY = window_y;
+  result.modifiers = modifiers;
+
+  if (type == WebInputEvent::MouseDown || type == WebInputEvent::MouseUp)
+    result.button = WebMouseEvent::ButtonLeft;
+  else
+    result.button = WebMouseEvent::ButtonNone;
+
+  return result;
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
+    WebMouseWheelEvent::Phase phase) {
+  WebMouseWheelEvent result;
+  result.type = WebInputEvent::MouseWheel;
+  result.phase = phase;
+  return result;
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(float dx,
+                                                             float dy,
+                                                             int modifiers,
+                                                             bool precise) {
+  WebMouseWheelEvent result;
+  result.type = WebInputEvent::MouseWheel;
+  result.deltaX = dx;
+  result.deltaY = dy;
+  result.modifiers = modifiers;
+  result.hasPreciseScrollingDeltas = precise;
+  return result;
+}
+
+NativeWebKeyboardEvent SyntheticWebKeyboardEventBuilder::Build(
+    WebInputEvent::Type type) {
+  DCHECK(WebInputEvent::isKeyboardEventType(type));
+  NativeWebKeyboardEvent result;
+  result.type = type;
+  result.windowsKeyCode = ui::VKEY_L;  // non-null made up value.
+  return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::Build(
+    WebInputEvent::Type type,
+    WebGestureEvent::SourceDevice source_device) {
+  DCHECK(WebInputEvent::isGestureEventType(type));
+  WebGestureEvent result;
+  result.type = type;
+  result.sourceDevice = source_device;
+  return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+    float dx,
+    float dy,
+    int modifiers) {
+  WebGestureEvent result = Build(WebInputEvent::GestureScrollUpdate,
+                                 WebGestureEvent::Touchscreen);
+  result.data.scrollUpdate.deltaX = dx;
+  result.data.scrollUpdate.deltaY = dy;
+  result.modifiers = modifiers;
+  return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildPinchUpdate(
+    float scale,
+    float anchor_x,
+    float anchor_y,
+    int modifiers) {
+  WebGestureEvent result = Build(WebInputEvent::GesturePinchUpdate,
+                                 WebGestureEvent::Touchscreen);
+  result.data.pinchUpdate.scale = scale;
+  result.x = anchor_x;
+  result.y = anchor_y;
+  result.modifiers = modifiers;
+  return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildFling(
+    float velocity_x,
+    float velocity_y,
+    WebGestureEvent::SourceDevice source_device) {
+  WebGestureEvent result = Build(WebInputEvent::GestureFlingStart,
+                                 source_device);
+  result.data.flingStart.velocityX = velocity_x;
+  result.data.flingStart.velocityY = velocity_y;
+  return result;
+}
+
+SyntheticWebTouchEvent::SyntheticWebTouchEvent() : WebTouchEvent() {}
+
+void SyntheticWebTouchEvent::ResetPoints() {
+  int point = 0;
+  for (unsigned int i = 0; i < touchesLength; ++i) {
+    if (touches[i].state == WebTouchPoint::StateReleased)
+      continue;
+
+    touches[point] = touches[i];
+    touches[point].state = WebTouchPoint::StateStationary;
+    ++point;
+  }
+  touchesLength = point;
+  type = WebInputEvent::Undefined;
+}
+
+int SyntheticWebTouchEvent::PressPoint(int x, int y) {
+  if (touchesLength == touchesLengthCap)
+    return -1;
+  WebTouchPoint& point = touches[touchesLength];
+  point.id = touchesLength;
+  point.position.x = point.screenPosition.x = x;
+  point.position.y = point.screenPosition.y = y;
+  point.state = WebTouchPoint::StatePressed;
+  point.radiusX = point.radiusY = 1.f;
+  ++touchesLength;
+  type = WebInputEvent::TouchStart;
+  return point.id;
+}
+
+void SyntheticWebTouchEvent::MovePoint(int index, int x, int y) {
+  CHECK(index >= 0 && index < touchesLengthCap);
+  WebTouchPoint& point = touches[index];
+  point.position.x = point.screenPosition.x = x;
+  point.position.y = point.screenPosition.y = y;
+  touches[index].state = WebTouchPoint::StateMoved;
+  type = WebInputEvent::TouchMove;
+}
+
+void SyntheticWebTouchEvent::ReleasePoint(int index) {
+  CHECK(index >= 0 && index < touchesLengthCap);
+  touches[index].state = WebTouchPoint::StateReleased;
+  type = WebInputEvent::TouchEnd;
+}
+
+void SyntheticWebTouchEvent::SetTimestamp(base::TimeDelta timestamp) {
+  timeStampSeconds = timestamp.InSecondsF();
+}
+
+SyntheticWebTouchEvent SyntheticWebTouchEventBuilder::Build(
+    WebInputEvent::Type type) {
+  DCHECK(WebInputEvent::isTouchEventType(type));
+  SyntheticWebTouchEvent result;
+  result.type = type;
+  return result;
+};
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_web_input_event_builders.h b/content/browser/renderer_host/input/synthetic_web_input_event_builders.h
new file mode 100644
index 0000000..3b0d7a3
--- /dev/null
+++ b/content/browser/renderer_host/input/synthetic_web_input_event_builders.h
@@ -0,0 +1,82 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_WEB_INPUT_EVENT_BUILDERS_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_WEB_INPUT_EVENT_BUILDERS_H_
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+// Provides sensible creation of default WebInputEvents for testing purposes.
+
+namespace content {
+
+class CONTENT_EXPORT SyntheticWebMouseEventBuilder {
+ public:
+  static WebKit::WebMouseEvent Build(WebKit::WebInputEvent::Type type);
+  static WebKit::WebMouseEvent Build(WebKit::WebInputEvent::Type type,
+                                     int window_x,
+                                     int window_y,
+                                     int modifiers);
+};
+
+class CONTENT_EXPORT SyntheticWebMouseWheelEventBuilder {
+ public:
+  static WebKit::WebMouseWheelEvent Build(
+      WebKit::WebMouseWheelEvent::Phase phase);
+  static WebKit::WebMouseWheelEvent Build(float dx,
+                                          float dy,
+                                          int modifiers,
+                                          bool precise);
+};
+
+class CONTENT_EXPORT SyntheticWebKeyboardEventBuilder {
+ public:
+  static NativeWebKeyboardEvent Build(WebKit::WebInputEvent::Type type);
+};
+
+class CONTENT_EXPORT SyntheticWebGestureEventBuilder {
+ public:
+  static WebKit::WebGestureEvent Build(
+      WebKit::WebInputEvent::Type type,
+      WebKit::WebGestureEvent::SourceDevice sourceDevice);
+  static WebKit::WebGestureEvent BuildScrollUpdate(float dx,
+                                                   float dY,
+                                                   int modifiers);
+  static WebKit::WebGestureEvent BuildPinchUpdate(float scale,
+                                                  float anchor_x,
+                                                  float anchor_y,
+                                                  int modifiers);
+  static WebKit::WebGestureEvent BuildFling(
+      float velocity_x,
+      float velocity_y,
+      WebKit::WebGestureEvent::SourceDevice source_device);
+};
+
+class CONTENT_EXPORT SyntheticWebTouchEvent
+    : public NON_EXPORTED_BASE(WebKit::WebTouchEvent) {
+ public:
+  SyntheticWebTouchEvent();
+
+  // Mark all the points as stationary, and remove any released points.
+  void ResetPoints();
+
+  // Adds an additional point to the touch list, returning the point's index.
+  int PressPoint(int x, int y);
+  void MovePoint(int index, int x, int y);
+  void ReleasePoint(int index);
+
+  void SetTimestamp(base::TimeDelta timestamp);
+};
+
+class CONTENT_EXPORT SyntheticWebTouchEventBuilder {
+ public:
+  static SyntheticWebTouchEvent Build(WebKit::WebInputEvent::Type type);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_WEB_INPUT_EVENT_BUILDERS_H_
diff --git a/content/browser/renderer_host/input/tap_suppression_controller.cc b/content/browser/renderer_host/input/tap_suppression_controller.cc
index 387576c..dd9ddb7 100644
--- a/content/browser/renderer_host/input/tap_suppression_controller.cc
+++ b/content/browser/renderer_host/input/tap_suppression_controller.cc
@@ -45,7 +45,7 @@
         TRACE_EVENT0("browser",
                      "TapSuppressionController::GestureFlingCancelAck");
         StopTapDownTimer();
-        client_->ForwardStashedTapDownForDeferral();
+        client_->ForwardStashedTapDown();
         state_ = NOTHING;
       }  // Else waiting for the timer to release the stashed tap down.
       break;
@@ -140,7 +140,7 @@
     case TAP_DOWN_STASHED:
       TRACE_EVENT0("browser",
                    "TapSuppressionController::TapDownTimerExpired");
-      client_->ForwardStashedTapDownSkipDeferral();
+      client_->ForwardStashedTapDown();
       state_ = NOTHING;
       break;
   }
diff --git a/content/browser/renderer_host/input/tap_suppression_controller_client.h b/content/browser/renderer_host/input/tap_suppression_controller_client.h
index 821f546..fcea0e1 100644
--- a/content/browser/renderer_host/input/tap_suppression_controller_client.h
+++ b/content/browser/renderer_host/input/tap_suppression_controller_client.h
@@ -25,14 +25,9 @@
   virtual void DropStashedTapDown() = 0;
 
   // Called whenever the deferred tap down (if saved) should be forwarded to the
-  // renderer. In this case, the tap down should go back to normal path it was
+  // renderer. The tap down should go back to normal path it was
   // on before being deferred.
-  virtual void ForwardStashedTapDownForDeferral() = 0;
-
-  // Called whenever the deferred tap down (if saved) should be forwarded to the
-  // renderer. In this case, the tap down should skip deferral filter, because
-  // it is handled here, and there is no need to delay it more.
-  virtual void ForwardStashedTapDownSkipDeferral() = 0;
+  virtual void ForwardStashedTapDown() = 0;
 
  protected:
   TapSuppressionControllerClient() {}
diff --git a/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc b/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
index 552e8cf..9073ee0 100644
--- a/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
+++ b/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
@@ -29,8 +29,7 @@
     TAP_UP_FORWARDED                     = 1 << 4,
     TAP_CANCEL_SUPPRESSED                = 1 << 5,
     TAP_CANCEL_FORWARDED                 = 1 << 6,
-    TAP_DOWN_FORWARDED_FOR_DEFERRAL      = 1 << 7,
-    TAP_DOWN_FORWARDED_SKIPPING_DEFERRAL = 1 << 8,
+    STASHED_TAP_DOWN_FORWARDED           = 1 << 7,
   };
 
   MockTapSuppressionController()
@@ -127,12 +126,8 @@
     last_actions_ |= TAP_DOWN_DROPPED;
   }
 
-  virtual void ForwardStashedTapDownForDeferral() OVERRIDE {
-    last_actions_ |= TAP_DOWN_FORWARDED_FOR_DEFERRAL;
-  }
-
-  virtual void ForwardStashedTapDownSkipDeferral() OVERRIDE {
-    last_actions_ |= TAP_DOWN_FORWARDED_SKIPPING_DEFERRAL;
+  virtual void ForwardStashedTapDown() OVERRIDE {
+    last_actions_ |= STASHED_TAP_DOWN_FORWARDED;
   }
 
   // Hiding some derived public methods
@@ -284,7 +279,7 @@
   // Wait more than allowed delay between TapDown and TapUp, so they are not
   // considered a tap. This should release the previously suppressed TapDown.
   tap_suppression_controller_->AdvanceTime(TimeDelta::FromMilliseconds(13));
-  EXPECT_EQ(MockTapSuppressionController::TAP_DOWN_FORWARDED_SKIPPING_DEFERRAL,
+  EXPECT_EQ(MockTapSuppressionController::STASHED_TAP_DOWN_FORWARDED,
             tap_suppression_controller_->last_actions());
   EXPECT_EQ(MockTapSuppressionController::NOTHING,
             tap_suppression_controller_->state());
@@ -407,7 +402,7 @@
   // Send unprocessed GestureFlingCancel Ack. This should release the
   // previously suppressed TapDown.
   tap_suppression_controller_->SendGestureFlingCancelAck(false);
-  EXPECT_EQ(MockTapSuppressionController::TAP_DOWN_FORWARDED_FOR_DEFERRAL,
+  EXPECT_EQ(MockTapSuppressionController::STASHED_TAP_DOWN_FORWARDED,
             tap_suppression_controller_->last_actions());
   EXPECT_EQ(MockTapSuppressionController::NOTHING,
             tap_suppression_controller_->state());
@@ -530,7 +525,7 @@
   // Wait more than allowed delay between TapDown and TapUp, so they are not
   // considered as a tap. This should release the previously suppressed TapDown.
   tap_suppression_controller_->AdvanceTime(TimeDelta::FromMilliseconds(13));
-  EXPECT_EQ(MockTapSuppressionController::TAP_DOWN_FORWARDED_SKIPPING_DEFERRAL,
+  EXPECT_EQ(MockTapSuppressionController::STASHED_TAP_DOWN_FORWARDED,
             tap_suppression_controller_->last_actions());
   EXPECT_EQ(MockTapSuppressionController::NOTHING,
             tap_suppression_controller_->state());
diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
index 3470aa3..61f51fe 100644
--- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "content/browser/renderer_host/input/mock_web_input_event_builders.h"
+#include "content/browser/renderer_host/input/synthetic_web_input_event_builders.h"
 #include "content/browser/renderer_host/input/touch_event_queue.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -156,7 +156,7 @@
   WebTouchEvent last_sent_event_;
   WebTouchEvent last_acked_event_;
   InputEventAckState last_acked_event_state_;
-  MockWebTouchEvent touch_event_;
+  SyntheticWebTouchEvent touch_event_;
   scoped_ptr<WebTouchEvent> followup_touch_event_;
   scoped_ptr<WebGestureEvent> followup_gesture_event_;
 };
diff --git a/content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc b/content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc
index 92a9a99..d920779 100644
--- a/content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc
+++ b/content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc
@@ -42,10 +42,7 @@
 void TouchpadTapSuppressionController::DropStashedTapDown() {
 }
 
-void TouchpadTapSuppressionController::ForwardStashedTapDownForDeferral() {
-}
-
-void TouchpadTapSuppressionController::ForwardStashedTapDownSkipDeferral() {
+void TouchpadTapSuppressionController::ForwardStashedTapDown() {
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h b/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
index 179e61d..64b2ed4 100644
--- a/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
+++ b/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
@@ -54,8 +54,7 @@
   virtual int MaxCancelToDownTimeInMs() OVERRIDE;
   virtual int MaxTapGapTimeInMs() OVERRIDE;
   virtual void DropStashedTapDown() OVERRIDE;
-  virtual void ForwardStashedTapDownForDeferral() OVERRIDE;
-  virtual void ForwardStashedTapDownSkipDeferral() OVERRIDE;
+  virtual void ForwardStashedTapDown() OVERRIDE;
 
   TouchpadTapSuppressionControllerClient* client_;
   MouseEventWithLatencyInfo stashed_mouse_down_;
diff --git a/content/browser/renderer_host/input/touchpad_tap_suppression_controller_aura.cc b/content/browser/renderer_host/input/touchpad_tap_suppression_controller_aura.cc
index 39bda63..bbfa353 100644
--- a/content/browser/renderer_host/input/touchpad_tap_suppression_controller_aura.cc
+++ b/content/browser/renderer_host/input/touchpad_tap_suppression_controller_aura.cc
@@ -49,13 +49,7 @@
 void TouchpadTapSuppressionController::DropStashedTapDown() {
 }
 
-void TouchpadTapSuppressionController::ForwardStashedTapDownForDeferral() {
-  // Mouse downs are not handled by gesture event filter; so, they are
-  // immediately forwarded to the renderer.
-  client_->SendMouseEventImmediately(stashed_mouse_down_);
-}
-
-void TouchpadTapSuppressionController::ForwardStashedTapDownSkipDeferral() {
+void TouchpadTapSuppressionController::ForwardStashedTapDown() {
   // Mouse downs are not handled by gesture event filter; so, they are
   // immediately forwarded to the renderer.
   client_->SendMouseEventImmediately(stashed_mouse_down_);
diff --git a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
index 10ad6a3..e777012 100644
--- a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
+++ b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
@@ -55,12 +55,8 @@
 void TouchscreenTapSuppressionController::DropStashedTapDown() {
 }
 
-void TouchscreenTapSuppressionController::ForwardStashedTapDownForDeferral() {
-  gesture_event_filter_->ForwardGestureEventForDeferral(stashed_tap_down_);
-}
-
-void TouchscreenTapSuppressionController::ForwardStashedTapDownSkipDeferral() {
-  gesture_event_filter_->ForwardGestureEventSkipDeferral(stashed_tap_down_);
+void TouchscreenTapSuppressionController::ForwardStashedTapDown() {
+  gesture_event_filter_->ForwardGestureEvent(stashed_tap_down_);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
index b974d9c..9ad6f5b 100644
--- a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
+++ b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
@@ -47,8 +47,7 @@
   virtual int MaxCancelToDownTimeInMs() OVERRIDE;
   virtual int MaxTapGapTimeInMs() OVERRIDE;
   virtual void DropStashedTapDown() OVERRIDE;
-  virtual void ForwardStashedTapDownForDeferral() OVERRIDE;
-  virtual void ForwardStashedTapDownSkipDeferral() OVERRIDE;
+  virtual void ForwardStashedTapDown() OVERRIDE;
 
   GestureEventFilter* gesture_event_filter_;
   GestureEventWithLatencyInfo stashed_tap_down_;
diff --git a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc
index d6cf6c8..1bcfdb6 100644
--- a/content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc
+++ b/content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc
@@ -46,8 +46,6 @@
 
 void TouchscreenTapSuppressionController::DropStashedTapDown() {}
 
-void TouchscreenTapSuppressionController::ForwardStashedTapDownForDeferral() {}
-
-void TouchscreenTapSuppressionController::ForwardStashedTapDownSkipDeferral() {}
+void TouchscreenTapSuppressionController::ForwardStashedTapDown() {}
 
 }  // namespace content
diff --git a/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc b/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
index 95a1c6a..ece3056 100644
--- a/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
+++ b/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
@@ -18,7 +18,7 @@
 #include "third_party/WebKit/public/web/WebBindings.h"
 
 #if !defined(OS_ANDROID)
-#error "JavaBridge currently only supports OS_ANDROID"
+#error "JavaBridge only supports OS_ANDROID"
 #endif
 
 namespace content {
@@ -50,8 +50,7 @@
 
 JavaBridgeDispatcherHost::JavaBridgeDispatcherHost(
     RenderViewHost* render_view_host)
-    : RenderViewHostObserver(render_view_host),
-      is_renderer_initialized_(false) {
+    : render_view_host_(render_view_host) {
 }
 
 JavaBridgeDispatcherHost::~JavaBridgeDispatcherHost() {
@@ -65,11 +64,8 @@
   NPVariant_Param variant_param;
   CreateNPVariantParam(object, &variant_param);
 
-  if (!is_renderer_initialized_) {
-    is_renderer_initialized_ = true;
-    Send(new JavaBridgeMsg_Init(routing_id()));
-  }
-  Send(new JavaBridgeMsg_AddNamedObject(routing_id(), name, variant_param));
+  Send(new JavaBridgeMsg_AddNamedObject(
+      render_view_host_->GetRoutingID(), name, variant_param));
 }
 
 void JavaBridgeDispatcherHost::RemoveNamedObject(const string16& name) {
@@ -78,28 +74,12 @@
   // removed, the proxy object will delete its NPObjectProxy, which will cause
   // the NPObjectStub to be deleted, which will drop its reference to the
   // original NPObject.
-  Send(new JavaBridgeMsg_RemoveNamedObject(routing_id(), name));
+  Send(new JavaBridgeMsg_RemoveNamedObject(
+      render_view_host_->GetRoutingID(), name));
 }
 
-bool JavaBridgeDispatcherHost::Send(IPC::Message* msg) {
-  return RenderViewHostObserver::Send(msg);
-}
-
-void JavaBridgeDispatcherHost::RenderViewHostDestroyed(
-    RenderViewHost* render_view_host) {
-  // Base implementation deletes the object. This class is ref counted, with
-  // refs held by the JavaBridgeDispatcherHostManager and base::Bind, so that
-  // behavior is unwanted.
-}
-
-bool JavaBridgeDispatcherHost::OnMessageReceived(const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(JavaBridgeDispatcherHost, msg)
-    IPC_MESSAGE_HANDLER_DELAY_REPLY(JavaBridgeHostMsg_GetChannelHandle,
-                                    OnGetChannelHandle)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
+void JavaBridgeDispatcherHost::RenderViewDeleted() {
+  render_view_host_ = NULL;
 }
 
 void JavaBridgeDispatcherHost::OnGetChannelHandle(IPC::Message* reply_msg) {
@@ -108,6 +88,15 @@
       base::Bind(&JavaBridgeDispatcherHost::GetChannelHandle, this, reply_msg));
 }
 
+void JavaBridgeDispatcherHost::Send(IPC::Message* msg) {
+  if (render_view_host_) {
+    render_view_host_->Send(msg);
+    return;
+  }
+
+  delete msg;
+}
+
 void JavaBridgeDispatcherHost::GetChannelHandle(IPC::Message* reply_msg) {
   // The channel creates the channel handle based on the renderer ID we passed
   // to GetJavaBridgeChannelHost() and, on POSIX, the file descriptor used by
@@ -115,7 +104,11 @@
   JavaBridgeHostMsg_GetChannelHandle::WriteReplyParams(
       reply_msg,
       channel_->channel_handle());
-  Send(reply_msg);
+
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&JavaBridgeDispatcherHost::Send, this, reply_msg));
 }
 
 void JavaBridgeDispatcherHost::CreateNPVariantParam(NPObject* object,
@@ -139,16 +132,17 @@
   g_background_thread.Get().message_loop()->PostTask(
       FROM_HERE,
       base::Bind(&JavaBridgeDispatcherHost::CreateObjectStub, this, object,
-                 route_id));
+                 render_view_host_->GetProcess()->GetID(), route_id));
 }
 
 void JavaBridgeDispatcherHost::CreateObjectStub(NPObject* object,
+                                                int render_process_id,
                                                 int route_id) {
   DCHECK_EQ(g_background_thread.Get().message_loop(),
             base::MessageLoop::current());
   if (!channel_.get()) {
     channel_ = JavaBridgeChannelHost::GetJavaBridgeChannelHost(
-        render_view_host()->GetProcess()->GetID(),
+        render_process_id,
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
   }
 
diff --git a/content/browser/renderer_host/java/java_bridge_dispatcher_host.h b/content/browser/renderer_host/java/java_bridge_dispatcher_host.h
index 6d44c39..94ee632 100644
--- a/content/browser/renderer_host/java/java_bridge_dispatcher_host.h
+++ b/content/browser/renderer_host/java/java_bridge_dispatcher_host.h
@@ -10,11 +10,14 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "content/child/npapi/npobject_stub.h"
-#include "content/public/browser/render_view_host_observer.h"
 
 class RouteIDGenerator;
 struct NPObject;
 
+namespace IPC {
+class Message;
+}
+
 namespace content {
 class NPChannelBase;
 class RenderViewHost;
@@ -25,11 +28,10 @@
 // proxy object is created in the renderer. An instance of this class exists
 // for each RenderViewHost.
 class JavaBridgeDispatcherHost
-    : public base::RefCountedThreadSafe<JavaBridgeDispatcherHost>,
-      public RenderViewHostObserver {
+    : public base::RefCountedThreadSafe<JavaBridgeDispatcherHost> {
  public:
   // We hold a weak pointer to the RenderViewhost. It must outlive this object.
-  JavaBridgeDispatcherHost(RenderViewHost* render_view_host);
+  explicit JavaBridgeDispatcherHost(RenderViewHost* render_view_host);
 
   // Injects |object| into the main frame of the corresponding RenderView. A
   // proxy object is created in the renderer and when the main frame's window
@@ -43,28 +45,23 @@
   void AddNamedObject(const string16& name, NPObject* object);
   void RemoveNamedObject(const string16& name);
 
-  // RenderViewHostObserver overrides:
-  // The IPC macros require this to be public.
-  virtual bool Send(IPC::Message* msg) OVERRIDE;
-  virtual void RenderViewHostDestroyed(
-      RenderViewHost* render_view_host) OVERRIDE;
+  // Since this object is ref-counted, it might outlive render_view_host_.
+  void RenderViewDeleted();
+
+  void OnGetChannelHandle(IPC::Message* reply_msg);
 
  private:
   friend class base::RefCountedThreadSafe<JavaBridgeDispatcherHost>;
   virtual ~JavaBridgeDispatcherHost();
 
-  // RenderViewHostObserver override:
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
-  // Message handlers
-  void OnGetChannelHandle(IPC::Message* reply_msg);
+  void Send(IPC::Message* msg);
 
   void GetChannelHandle(IPC::Message* reply_msg);
   void CreateNPVariantParam(NPObject* object, NPVariant_Param* param);
-  void CreateObjectStub(NPObject* object, int route_id);
+  void CreateObjectStub(NPObject* object, int render_process_id, int route_id);
 
   scoped_refptr<NPChannelBase> channel_;
-  bool is_renderer_initialized_;
+  RenderViewHost* render_view_host_;
   std::vector<base::WeakPtr<NPObjectStub> > stubs_;
 
   DISALLOW_COPY_AND_ASSIGN(JavaBridgeDispatcherHost);
diff --git a/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc b/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc
index 5625d05..a3822a0 100644
--- a/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc
+++ b/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc
@@ -82,6 +82,11 @@
   }
 }
 
+void JavaBridgeDispatcherHostManager::OnGetChannelHandle(
+    RenderViewHost* render_view_host, IPC::Message* reply_msg) {
+  instances_[render_view_host]->OnGetChannelHandle(reply_msg);
+}
+
 void JavaBridgeDispatcherHostManager::RenderViewCreated(
     RenderViewHost* render_view_host) {
   // Creates a JavaBridgeDispatcherHost for the specified RenderViewHost and
@@ -99,6 +104,9 @@
 
 void JavaBridgeDispatcherHostManager::RenderViewDeleted(
     RenderViewHost* render_view_host) {
+  if (!instances_.count(render_view_host))  // Needed for tests.
+    return;
+  instances_[render_view_host]->RenderViewDeleted();
   instances_.erase(render_view_host);
 }
 
diff --git a/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h b/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h
index e2bb7dc..e3d629a 100644
--- a/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h
+++ b/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h
@@ -37,6 +37,9 @@
   void AddNamedObject(const string16& name, NPObject* object);
   void RemoveNamedObject(const string16& name);
 
+  void OnGetChannelHandle(RenderViewHost* render_view_host,
+                          IPC::Message* reply_msg);
+
   // Every time a JavaBoundObject backed by a real Java object is
   // created/destroyed, we insert/remove a strong ref to that Java object into
   // this set so that it doesn't get garbage collected while it's still
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index a897534..7e6ab82 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/memory/shared_memory.h"
 #include "base/metrics/histogram.h"
 #include "base/process/process.h"
@@ -21,11 +20,11 @@
 #include "content/public/browser/media_observer.h"
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_manager_base.h"
-#include "media/audio/shared_memory_util.h"
 #include "media/base/audio_bus.h"
 #include "media/base/limits.h"
 
 using media::AudioBus;
+using media::AudioManager;
 
 namespace content {
 
@@ -108,6 +107,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 // AudioRendererHost implementations.
+
 AudioRendererHost::AudioRendererHost(
     int render_process_id,
     media::AudioManager* audio_manager,
@@ -127,6 +127,17 @@
   DCHECK(audio_entries_.empty());
 }
 
+void AudioRendererHost::GetOutputControllers(
+    int render_view_id,
+    const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
+                 render_view_id),
+      callback);
+}
+
 void AudioRendererHost::OnChannelClosing() {
   // Since the IPC channel is gone, close all requested audio streams.
   while (!audio_entries_.empty()) {
@@ -238,7 +249,22 @@
       entry->stream_id(),
       foreign_memory_handle,
       foreign_socket_handle,
-      media::PacketSizeInBytes(entry->shared_memory()->requested_size())));
+      entry->shared_memory()->requested_size()));
+}
+
+RenderViewHost::AudioOutputControllerList
+AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  RenderViewHost::AudioOutputControllerList controllers;
+  AudioEntryMap::const_iterator it = audio_entries_.begin();
+  for (; it != audio_entries_.end(); ++it) {
+    AudioEntry* entry = it->second;
+    if (entry->render_view_id() == render_view_id)
+      controllers.push_back(entry->controller());
+  }
+
+  return controllers;
 }
 
 void AudioRendererHost::DoNotifyAudioPowerLevel(int stream_id,
@@ -249,14 +275,11 @@
   MediaObserver* const media_observer =
       GetContentClient()->browser()->GetMediaObserver();
   if (media_observer) {
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kEnableAudibleNotifications)) {
-      AudioEntry* const entry = LookupById(stream_id);
-      if (entry) {
-        media_observer->OnAudioStreamPlayingChanged(
-            render_process_id_, entry->render_view_id(), entry->stream_id(),
-            true, power_dbfs, clipped);
-      }
+    AudioEntry* const entry = LookupById(stream_id);
+    if (entry) {
+      media_observer->OnAudioStreamPlayingChanged(
+          render_process_id_, entry->render_view_id(), entry->stream_id(),
+          true, power_dbfs, clipped);
     }
   }
 }
@@ -323,15 +346,12 @@
   // Calculate output and input memory size.
   int output_memory_size = AudioBus::CalculateMemorySize(params);
   int frames = params.frames_per_buffer();
-  int input_memory_size =
-      AudioBus::CalculateMemorySize(input_channels, frames);
+  int input_memory_size = AudioBus::CalculateMemorySize(input_channels, frames);
 
   // Create the shared memory and share with the renderer process.
   // For synchronized I/O (if input_channels > 0) then we allocate
   // extra memory after the output data for the input data.
-  uint32 io_buffer_size = output_memory_size + input_memory_size;
-  uint32 shared_memory_size =
-      media::TotalSharedMemorySizeInBytes(io_buffer_size);
+  uint32 shared_memory_size = output_memory_size + input_memory_size;
   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
   if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
     SendErrorMessage(stream_id);
diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h
index 486d55f..cd8b136 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.h
+++ b/content/browser/renderer_host/media/audio_renderer_host.h
@@ -47,6 +47,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_view_host.h"
 #include "media/audio/audio_io.h"
 #include "media/audio/audio_output_controller.h"
 #include "media/audio/simple_sources.h"
@@ -72,6 +73,11 @@
                     MediaInternals* media_internals,
                     MediaStreamManager* media_stream_manager);
 
+  // Calls |callback| with the list of AudioOutputControllers for this object.
+  void GetOutputControllers(
+      int render_view_id,
+      const RenderViewHost::GetAudioOutputControllersCallback& callback) const;
+
   // BrowserMessageFilter implementation.
   virtual void OnChannelClosing() OVERRIDE;
   virtual void OnDestruct() const OVERRIDE;
@@ -125,6 +131,9 @@
   // NotifyStreamCreated message to the peer.
   void DoCompleteCreation(int stream_id);
 
+  RenderViewHost::AudioOutputControllerList DoGetOutputControllers(
+      int render_view_id) const;
+
   // Propagate measured power level of the audio signal to MediaObserver.
   void DoNotifyAudioPowerLevel(int stream_id, float power_dbfs, bool clipped);
 
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc
index dea8ae2..45ea41e 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -12,7 +12,6 @@
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_buffers_state.h"
 #include "media/audio/audio_parameters.h"
-#include "media/audio/shared_memory_util.h"
 
 using media::AudioBus;
 
@@ -25,9 +24,16 @@
       input_channels_(input_channels),
       mute_audio_(CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kMuteAudio)),
+      packet_size_(shared_memory_->requested_size()),
       renderer_callback_count_(0),
-      renderer_missed_callback_count_(0) {
-  packet_size_ = media::PacketSizeInBytes(shared_memory_->requested_size());
+      renderer_missed_callback_count_(0),
+#if defined(OS_MACOSX)
+      maximum_wait_time_(params.GetBufferDuration() / 2),
+#else
+      // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
+      maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
+#endif
+      buffer_index_(0) {
   int input_memory_size = 0;
   int output_memory_size = AudioBus::CalculateMemorySize(params);
   if (input_channels_ > 0) {
@@ -37,9 +43,11 @@
     char* input_data =
         static_cast<char*>(shared_memory_->memory()) + output_memory_size;
     input_bus_ = AudioBus::WrapMemory(input_channels_, frames, input_data);
+    input_bus_->Zero();
   }
   DCHECK_EQ(packet_size_, output_memory_size + input_memory_size);
   output_bus_ = AudioBus::WrapMemory(params, shared_memory->memory());
+  output_bus_->Zero();
 }
 
 AudioSyncReader::~AudioSyncReader() {
@@ -54,93 +62,47 @@
       "Media.AudioRendererMissedDeadline", percentage_missed);
 }
 
-bool AudioSyncReader::DataReady() {
-  return !media::IsUnknownDataSize(shared_memory_, packet_size_);
-}
-
 // media::AudioOutputController::SyncReader implementations.
 void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
-  if (bytes != static_cast<uint32>(media::kPauseMark)) {
-    // Store unknown length of data into buffer, so we later
-    // can find out if data became available.
-    media::SetUnknownDataSize(shared_memory_, packet_size_);
-  }
-
-  if (socket_) {
-    socket_->Send(&bytes, sizeof(bytes));
-  }
+  // Zero out the entire output buffer to avoid stuttering/repeating-buffers
+  // in the anomalous case if the renderer is unable to keep up with real-time.
+  output_bus_->Zero();
+  socket_->Send(&bytes, sizeof(bytes));
+  ++buffer_index_;
 }
 
-int AudioSyncReader::Read(bool block, const AudioBus* source, AudioBus* dest) {
+void AudioSyncReader::Read(const AudioBus* source, AudioBus* dest) {
   ++renderer_callback_count_;
-  if (!DataReady()) {
+  if (!WaitUntilDataIsReady()) {
     ++renderer_missed_callback_count_;
-
-    if (block)
-      WaitTillDataReady();
+    dest->Zero();
+    return;
   }
 
   // Copy optional synchronized live audio input for consumption by renderer
   // process.
   if (source && input_bus_) {
-    DCHECK_EQ(source->channels(), input_bus_->channels());
-    // TODO(crogers): In some cases with device and sample-rate changes
-    // it's possible for an AOR to insert a resampler in the path.
-    // Because this is used with the Web Audio API, it'd be better
-    // to bypass the device change handling in AOR and instead let
-    // the renderer-side Web Audio code deal with this.
+    // TODO(rtoy): In some cases with device and sample-rate changes it's
+    // possible for an AOR to insert a resampler in the path. Because this is
+    // used with the Web Audio API, it'd be better to bypass the device change
+    // handling in AOR and instead let the renderer-side Web Audio code deal
+    // with this.
     if (source->frames() == input_bus_->frames() &&
-        source->channels() == input_bus_->channels())
+        source->channels() == input_bus_->channels()) {
       source->CopyTo(input_bus_.get());
-    else
+    } else {
       input_bus_->Zero();
+    }
   }
 
-  // Retrieve the actual number of bytes available from the shared memory.  If
-  // the renderer has not completed rendering this value will be invalid (still
-  // the marker stored in UpdatePendingBytes() above) and must be sanitized.
-  // TODO(dalecurtis): Technically this is not the exact size.  Due to channel
-  // padding for alignment, there may be more data available than this; AudioBus
-  // will automatically do the right thing during CopyTo().  Rename this method
-  // to GetActualFrameCount().
-  uint32 size = media::GetActualDataSizeInBytes(shared_memory_, packet_size_);
-
-  // Compute the actual number of frames read.  It's important to sanitize this
-  // value for a couple reasons.  One, it might still be the unknown data size
-  // marker.  Two, shared memory comes from a potentially untrusted source.
-  int frames =
-      size / (sizeof(*output_bus_->channel(0)) * output_bus_->channels());
-  if (frames < 0)
-    frames = 0;
-  else if (frames > output_bus_->frames())
-    frames = output_bus_->frames();
-
-  if (mute_audio_) {
+  if (mute_audio_)
     dest->Zero();
-  } else {
-    // Copy data from the shared memory into the caller's AudioBus.
+  else
     output_bus_->CopyTo(dest);
-
-    // Zero out any unfilled frames in the destination bus.
-    dest->ZeroFramesPartial(frames, dest->frames() - frames);
-  }
-
-  // Zero out the entire output buffer to avoid stuttering/repeating-buffers
-  // in the anomalous case if the renderer is unable to keep up with real-time.
-  output_bus_->Zero();
-
-  // Store unknown length of data into buffer, in case renderer does not store
-  // the length itself. It also helps in decision if we need to yield.
-  media::SetUnknownDataSize(shared_memory_, packet_size_);
-
-  // Return the actual number of frames read.
-  return frames;
 }
 
 void AudioSyncReader::Close() {
-  if (socket_) {
-    socket_->Close();
-  }
+  socket_->Close();
 }
 
 bool AudioSyncReader::Init() {
@@ -157,9 +119,7 @@
   ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
                     process_handle, foreign_handle,
                     0, FALSE, DUPLICATE_SAME_ACCESS);
-  if (*foreign_handle != 0)
-    return true;
-  return false;
+  return (*foreign_handle != 0);
 }
 #else
 bool AudioSyncReader::PrepareForeignSocketHandle(
@@ -167,34 +127,59 @@
     base::FileDescriptor* foreign_handle) {
   foreign_handle->fd = foreign_socket_->handle();
   foreign_handle->auto_close = false;
-  if (foreign_handle->fd != -1)
-    return true;
-  return false;
+  return (foreign_handle->fd != -1);
 }
 #endif
 
-void AudioSyncReader::WaitTillDataReady() {
-  base::TimeTicks start = base::TimeTicks::Now();
-  const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20);
-#if defined(OS_WIN)
-  // Sleep(0) on Windows lets the other threads run.
-  const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0);
-#else
-  // We want to sleep for a bit here, as otherwise a backgrounded renderer won't
-  // get enough cpu to send the data and the high priority thread in the browser
-  // will use up a core causing even more skips.
-  const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2);
-#endif
-  base::TimeDelta time_since_start;
-  do {
-    base::PlatformThread::Sleep(kSleep);
-    time_since_start = base::TimeTicks::Now() - start;
-  } while (!DataReady() && time_since_start < kMaxWait);
-  UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
-                             time_since_start,
-                             base::TimeDelta::FromMilliseconds(1),
-                             base::TimeDelta::FromMilliseconds(1000),
-                             50);
+bool AudioSyncReader::WaitUntilDataIsReady() {
+  base::TimeDelta timeout = maximum_wait_time_;
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  const base::TimeTicks finish_time = start_time + timeout;
+
+  // Check if data is ready and if not, wait a reasonable amount of time for it.
+  //
+  // Data readiness is achieved via parallel counters, one on the renderer side
+  // and one here.  Every time a buffer is requested via UpdatePendingBytes(),
+  // |buffer_index_| is incremented.  Subsequently every time the renderer has a
+  // buffer ready it increments its counter and sends the counter value over the
+  // SyncSocket.  Data is ready when |buffer_index_| matches the counter value
+  // received from the renderer.
+  //
+  // The counter values may temporarily become out of sync if the renderer is
+  // unable to deliver audio fast enough.  It's assumed that the renderer will
+  // catch up at some point, which means discarding counter values read from the
+  // SyncSocket which don't match our current buffer index.
+  size_t bytes_received = 0;
+  uint32 renderer_buffer_index = 0;
+  while (timeout.InMicroseconds() > 0) {
+    bytes_received = socket_->ReceiveWithTimeout(
+        &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
+    if (!bytes_received)
+      break;
+
+    DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index));
+    if (renderer_buffer_index == buffer_index_)
+      break;
+
+    // Reduce the timeout value as receives succeed, but aren't the right index.
+    timeout = finish_time - base::TimeTicks::Now();
+  }
+
+  // Receive timed out or another error occurred.  Receive can timeout if the
+  // renderer is unable to deliver audio data within the allotted time.
+  if (!bytes_received || renderer_buffer_index != buffer_index_) {
+    DVLOG(2) << "AudioSyncReader::WaitUntilDataIsReady() timed out.";
+
+    base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
+    UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
+                               time_since_start,
+                               base::TimeDelta::FromMilliseconds(1),
+                               base::TimeDelta::FromMilliseconds(1000),
+                               50);
+    return false;
+  }
+
+  return true;
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h
index fdfbf81..e9f57a0 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -33,9 +33,8 @@
 
   // media::AudioOutputController::SyncReader implementations.
   virtual void UpdatePendingBytes(uint32 bytes) OVERRIDE;
-  virtual int Read(bool block,
-                   const media::AudioBus* source,
-                   media::AudioBus* dest) OVERRIDE;
+  virtual void Read(const media::AudioBus* source,
+                    media::AudioBus* dest) OVERRIDE;
   virtual void Close() OVERRIDE;
 
   bool Init();
@@ -47,11 +46,9 @@
 #endif
 
  private:
-  // Indicates whether the renderer has data available for reading.
-  bool DataReady();
-
-  // Blocks until DataReady() is true or a timeout expires.
-  void WaitTillDataReady();
+  // Blocks until data is ready for reading or a timeout expires.  Returns false
+  // if an error or timeout occurs.
+  bool WaitUntilDataIsReady();
 
   base::SharedMemory* shared_memory_;
 
@@ -83,6 +80,14 @@
   size_t renderer_callback_count_;
   size_t renderer_missed_callback_count_;
 
+  // The maximum amount of time to wait for data from the renderer.  Calculated
+  // from the parameters given at construction.
+  const base::TimeDelta maximum_wait_time_;
+
+  // The index of the audio buffer we're expecting to be sent from the renderer;
+  // used to block with timeout for audio data.
+  uint32 buffer_index_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioSyncReader);
 };
 
diff --git a/content/browser/renderer_host/media/desktop_capture_device.cc b/content/browser/renderer_host/media/desktop_capture_device.cc
index c9d77ec..6303f21 100644
--- a/content/browser/renderer_host/media/desktop_capture_device.cc
+++ b/content/browser/renderer_host/media/desktop_capture_device.cc
@@ -227,10 +227,7 @@
   client_ = client.Pass();
   requested_format_ = capture_format;
 
-  // Store requested frame rate and calculate expected delay.
   capture_format_.frame_rate = requested_format_.frame_rate;
-  capture_format_.expected_capture_delay =
-      base::Time::kMillisecondsPerSecond / requested_format_.frame_rate;
 
   // Support dynamic changes in resolution only if requester also does.
   if (requested_format_.frame_size_type ==
@@ -241,7 +238,6 @@
 
   // This capturer always outputs ARGB, non-interlaced.
   capture_format_.color = media::PIXEL_FORMAT_ARGB;
-  capture_format_.interlaced = false;
 
   desktop_capturer_->Start(this);
 
diff --git a/content/browser/renderer_host/media/desktop_capture_device_unittest.cc b/content/browser/renderer_host/media/desktop_capture_device_unittest.cc
index 363c3f8..5a8a145 100644
--- a/content/browser/renderer_host/media/desktop_capture_device_unittest.cc
+++ b/content/browser/renderer_host/media/desktop_capture_device_unittest.cc
@@ -40,7 +40,8 @@
 
 class MockDeviceClient : public media::VideoCaptureDevice::Client {
  public:
-  MOCK_METHOD0(ReserveOutputBuffer, scoped_refptr<media::VideoFrame>());
+  MOCK_METHOD1(ReserveOutputBuffer,
+               scoped_refptr<media::VideoFrame>(const gfx::Size& size));
   MOCK_METHOD0(OnError, void());
   MOCK_METHOD1(OnFrameInfo, void(const media::VideoCaptureCapability& info));
   MOCK_METHOD1(OnFrameInfoChanged,
@@ -129,7 +130,7 @@
                  InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
 
   media::VideoCaptureCapability capture_format(
-      640, 480, kFrameRate, media::PIXEL_FORMAT_I420, 0, false,
+      640, 480, kFrameRate, media::PIXEL_FORMAT_I420,
       media::ConstantResolutionVideoCaptureDevice);
   capture_device.AllocateAndStart(
       capture_format, client.PassAs<media::VideoCaptureDevice::Client>());
@@ -140,7 +141,6 @@
   EXPECT_GT(caps.height, 0);
   EXPECT_EQ(kFrameRate, caps.frame_rate);
   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, caps.color);
-  EXPECT_FALSE(caps.interlaced);
 
   EXPECT_EQ(caps.width * caps.height * 4, frame_size);
   worker_pool_->FlushForTesting();
@@ -175,8 +175,6 @@
       kTestFrameHeight1,
       kFrameRate,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
 
   capture_device.AllocateAndStart(
@@ -194,7 +192,6 @@
   EXPECT_EQ(kTestFrameHeight1, caps.height);
   EXPECT_EQ(kFrameRate, caps.frame_rate);
   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, caps.color);
-  EXPECT_FALSE(caps.interlaced);
 
   EXPECT_EQ(caps.width * caps.height * 4, frame_size);
   worker_pool_->FlushForTesting();
@@ -236,8 +233,6 @@
       kTestFrameHeight2,
       kFrameRate,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::VariableResolutionVideoCaptureDevice);
 
   capture_device.AllocateAndStart(
@@ -257,7 +252,6 @@
   EXPECT_EQ(kTestFrameHeight1, caps.height);
   EXPECT_EQ(kFrameRate, caps.frame_rate);
   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, caps.color);
-  EXPECT_FALSE(caps.interlaced);
   worker_pool_->FlushForTesting();
 }
 
diff --git a/content/browser/renderer_host/media/device_request_message_filter.cc b/content/browser/renderer_host/media/device_request_message_filter.cc
index fd26c6b..7baa6f3 100644
--- a/content/browser/renderer_host/media/device_request_message_filter.cc
+++ b/content/browser/renderer_host/media/device_request_message_filter.cc
@@ -4,13 +4,11 @@
 
 #include "content/browser/renderer_host/media/device_request_message_filter.h"
 
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/common/media/media_stream_messages.h"
+#include "content/public/browser/media_device_id.h"
 #include "content/public/browser/resource_context.h"
-#include "crypto/hmac.h"
 
 // Clears the MediaStreamDevice.name from all devices in |device_list|.
 static void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) {
@@ -162,36 +160,13 @@
   for (StreamDeviceInfoArray::const_iterator device_itr = raw_devices.begin();
        device_itr != raw_devices.end();
        ++device_itr) {
-    crypto::HMAC hmac(crypto::HMAC::SHA256);
-    const size_t digest_length = hmac.DigestLength();
-    std::vector<uint8> digest(digest_length);
-    bool result = hmac.Init(origin.spec()) &&
-                  hmac.Sign(device_itr->device.id, &digest[0], digest.size());
-    DCHECK(result);
-    if (result) {
-      StreamDeviceInfo current_device_info = *device_itr;
-      current_device_info.device.id =
-          StringToLowerASCII(base::HexEncode(&digest[0], digest.size()));
-      devices_with_guids->push_back(current_device_info);
-    }
+    StreamDeviceInfo current_device_info = *device_itr;
+    current_device_info.device.id =
+        content::GetHMACForMediaDeviceID(origin, device_itr->device.id);
+    devices_with_guids->push_back(current_device_info);
   }
 }
 
-bool DeviceRequestMessageFilter::DoesRawIdMatchGuid(
-    const GURL& security_origin,
-    const std::string& device_guid,
-    const std::string& raw_device_id) {
-  crypto::HMAC hmac(crypto::HMAC::SHA256);
-  bool result = hmac.Init(security_origin.spec());
-  DCHECK(result);
-  std::vector<uint8> converted_guid;
-  base::HexStringToBytes(device_guid, &converted_guid);
-  return hmac.Verify(
-      raw_device_id,
-      base::StringPiece(reinterpret_cast<const char*>(&converted_guid[0]),
-                        converted_guid.size()));
-}
-
 void DeviceRequestMessageFilter::OnGetSources(int request_id,
                                               const GURL& security_origin) {
   // Make request to get audio devices.
diff --git a/content/browser/renderer_host/media/device_request_message_filter.h b/content/browser/renderer_host/media/device_request_message_filter.h
index 0f0505d..2f31f08 100644
--- a/content/browser/renderer_host/media/device_request_message_filter.h
+++ b/content/browser/renderer_host/media/device_request_message_filter.h
@@ -47,12 +47,6 @@
                                  bool* message_was_ok) OVERRIDE;
   virtual void OnChannelClosing() OVERRIDE;
 
-  // Helper method that checks whether the GUID generated by
-  // DeviceRequestMessageFilter matches the given |raw_device_id|.
-  static bool DoesRawIdMatchGuid(const GURL& security_origin,
-                                 const std::string& device_guid,
-                                 const std::string& raw_device_id);
-
  protected:
   virtual ~DeviceRequestMessageFilter();
 
diff --git a/content/browser/renderer_host/media/device_request_message_filter_unittest.cc b/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
index ea42808..c3ffe95 100644
--- a/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
+++ b/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
@@ -6,6 +6,7 @@
 #include "content/browser/renderer_host/media/device_request_message_filter.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/common/media/media_stream_messages.h"
+#include "content/public/browser/media_device_id.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -217,7 +218,7 @@
     for (size_t i = 0; i < devices.size(); i++) {
       bool found_match = false;
       for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
-        if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+        if (content::DoesMediaDeviceIDMatchHMAC(
                 origin,
                 devices[i].device.id,
                 physical_audio_devices_[j].device.id)) {
@@ -226,7 +227,7 @@
         }
       }
       for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
-        if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+        if (content::DoesMediaDeviceIDMatchHMAC(
                 origin,
                 devices[i].device.id,
                 physical_video_devices_[j].device.id)) {
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 2fe5e6f..ff0cdd9 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -21,6 +21,7 @@
 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/media_device_id.h"
 #include "content/public/browser/media_observer.h"
 #include "content/public/browser/media_request_state.h"
 #include "content/public/common/content_switches.h"
@@ -66,9 +67,13 @@
 class MediaStreamManager::DeviceRequest {
  public:
   DeviceRequest(MediaStreamRequester* requester,
-                const MediaStreamRequest& request)
+                const MediaStreamRequest& request,
+                int requesting_process_id,
+                int requesting_view_id)
       : requester(requester),
         request(request),
+        requesting_process_id(requesting_process_id),
+        requesting_view_id(requesting_view_id),
         state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) {
   }
 
@@ -116,6 +121,18 @@
   MediaStreamRequester* const requester;  // Can be NULL.
   MediaStreamRequest request;
 
+  // The render process id that requested this stream to be generated and that
+  // will receive a handle to the MediaStream. This may be different from
+  // MediaStreamRequest::render_process_id which in the tab capture case
+  // specifies the target renderer from which audio and video is captured.
+  const int requesting_process_id;
+
+  // The render view id that requested this stream to be generated and that
+  // will receive a handle to the MediaStream. This may be different from
+  // MediaStreamRequest::render_view_id which in the tab capture case
+  // specifies the target renderer from which audio and video is captured.
+  const int requesting_view_id;
+
   StreamDeviceInfoArray devices;
 
   // Callback to the requester which audio/video devices have been selected.
@@ -193,7 +210,8 @@
       render_process_id, render_view_id, page_request_id, std::string(),
       security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(),
       options.audio_type, options.video_type);
-  DeviceRequest* request = new DeviceRequest(NULL, stream_request);
+  DeviceRequest* request = new DeviceRequest(NULL, stream_request,
+                                             render_process_id, render_view_id);
   const std::string& label = AddRequest(request);
 
   request->callback = callback;
@@ -285,7 +303,9 @@
       tab_capture_device_id, security_origin, MEDIA_GENERATE_STREAM,
       translated_audio_device_id, translated_video_device_id,
       options.audio_type, options.video_type);
-  DeviceRequest* request = new DeviceRequest(requester, stream_request);
+  DeviceRequest* request = new DeviceRequest(requester, stream_request,
+                                             render_process_id,
+                                             render_view_id);
   const std::string& label = AddRequest(request);
   HandleRequest(label);
   return label;
@@ -326,7 +346,7 @@
 void MediaStreamManager::CancelAllRequests(int render_process_id) {
   DeviceRequests::iterator request_it = requests_.begin();
   while (request_it != requests_.end()) {
-    if (request_it->second->request.render_process_id != render_process_id) {
+    if (request_it->second->requesting_process_id != render_process_id) {
       ++request_it;
       continue;
     }
@@ -348,15 +368,15 @@
   // MEDIA_GENERATE_STREAM that has requested to use |device_id|.
   DeviceRequests::iterator request_it = requests_.begin();
   while (request_it  != requests_.end()) {
-    const MediaStreamRequest& ms_request = request_it->second->request;
-    if (ms_request.render_process_id != render_process_id ||
-        ms_request.render_view_id != render_view_id ||
+    DeviceRequest* request = request_it->second;
+    const MediaStreamRequest& ms_request = request->request;
+    if (request->requesting_process_id != render_process_id ||
+        request->requesting_view_id != render_view_id ||
         ms_request.request_type != MEDIA_GENERATE_STREAM) {
       ++request_it;
       continue;
     }
 
-    DeviceRequest* request = request_it->second;
     StreamDeviceInfoArray* devices = &request->devices;
     StreamDeviceInfoArray::iterator device_it = devices->begin();
     while (device_it != devices->end()) {
@@ -443,7 +463,9 @@
       render_process_id, render_view_id, page_request_id, std::string(),
       security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(),
       options.audio_type, options.video_type);
-  DeviceRequest* request = new DeviceRequest(requester, stream_request);
+  DeviceRequest* request = new DeviceRequest(requester, stream_request,
+                                             render_process_id,
+                                             render_view_id);
   const std::string& label = AddRequest(request);
 
   if (cache->valid) {
@@ -492,7 +514,9 @@
       render_process_id, render_view_id, page_request_id, std::string(),
       security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id,
       options.video_device_id, options.audio_type, options.video_type);
-  DeviceRequest* request = new DeviceRequest(requester, stream_request);
+  DeviceRequest* request = new DeviceRequest(requester, stream_request,
+                                             render_process_id,
+                                             render_view_id);
   const std::string& label = AddRequest(request);
   StartEnumeration(request);
 
@@ -559,8 +583,8 @@
   for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
        it != cache->devices.end();
        ++it) {
-    if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
-        security_origin, device_guid, it->device.id)) {
+    if (content::DoesMediaDeviceIDMatchHMAC(
+            security_origin, device_guid, it->device.id)) {
       *raw_device_id = it->device.id;
       return true;
     }
@@ -695,8 +719,8 @@
   for (DeviceRequests::const_iterator it = requests_.begin();
        it != requests_.end() ; ++it) {
     const DeviceRequest* request = it->second;
-    if (request->request.render_process_id ==render_process_id &&
-        request->request.render_view_id == render_view_id &&
+    if (request->requesting_process_id ==render_process_id &&
+        request->requesting_view_id == render_view_id &&
         request->request.request_type == type) {
       for (StreamDeviceInfoArray::const_iterator device_it =
                request->devices.begin();
@@ -1035,8 +1059,8 @@
 
     if (request->request.request_type == MEDIA_GENERATE_STREAM) {
       MediaRequestState state;
-      if (FindExistingRequestedDeviceInfo(request->request.render_process_id,
-                                          request->request.render_view_id,
+      if (FindExistingRequestedDeviceInfo(request->requesting_process_id,
+                                          request->requesting_view_id,
                                           request->request.request_type,
                                           device_it->id,
                                           &device_info,
diff --git a/content/browser/renderer_host/media/midi_dispatcher_host.cc b/content/browser/renderer_host/media/midi_dispatcher_host.cc
index 53f5a76..2181dcc 100644
--- a/content/browser/renderer_host/media/midi_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/midi_dispatcher_host.cc
@@ -29,6 +29,8 @@
   IPC_BEGIN_MESSAGE_MAP_EX(MIDIDispatcherHost, message, *message_was_ok)
     IPC_MESSAGE_HANDLER(MIDIHostMsg_RequestSysExPermission,
                         OnRequestSysExPermission)
+    IPC_MESSAGE_HANDLER(MIDIHostMsg_CancelSysExPermissionRequest,
+                        OnCancelSysExPermissionRequest)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP_EX()
   return handled;
@@ -36,31 +38,42 @@
 
 void MIDIDispatcherHost::OverrideThreadForMessage(
     const IPC::Message& message, BrowserThread::ID* thread) {
-  if (message.type() == MIDIHostMsg_RequestSysExPermission::ID)
+  if (IPC_MESSAGE_CLASS(message) == MIDIMsgStart)
     *thread = BrowserThread::UI;
 }
 
 void MIDIDispatcherHost::OnRequestSysExPermission(int render_view_id,
-                                                  int client_id,
+                                                  int bridge_id,
                                                   const GURL& origin) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   browser_context_->RequestMIDISysExPermission(
       render_process_id_,
       render_view_id,
+      bridge_id,
       origin,
       base::Bind(&MIDIDispatcherHost::WasSysExPermissionGranted,
                  base::Unretained(this),
                  render_view_id,
-                 client_id));
+                 bridge_id));
 }
 
+void MIDIDispatcherHost::OnCancelSysExPermissionRequest(
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" << render_view_id
+           << ":" << bridge_id;
+  browser_context_->CancelMIDISysExPermissionRequest(
+      render_process_id_, render_view_id, bridge_id, requesting_frame);
+}
 void MIDIDispatcherHost::WasSysExPermissionGranted(int render_view_id,
-                                                   int client_id,
+                                                   int bridge_id,
                                                    bool success) {
   ChildProcessSecurityPolicyImpl::GetInstance()->GrantSendMIDISysExMessage(
       render_process_id_);
-  Send(new MIDIMsg_SysExPermissionApproved(render_view_id, client_id, success));
+  Send(new MIDIMsg_SysExPermissionApproved(render_view_id, bridge_id, success));
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/midi_dispatcher_host.h b/content/browser/renderer_host/media/midi_dispatcher_host.h
index ee86155..068f719 100644
--- a/content/browser/renderer_host/media/midi_dispatcher_host.h
+++ b/content/browser/renderer_host/media/midi_dispatcher_host.h
@@ -31,10 +31,13 @@
 
  private:
   void OnRequestSysExPermission(int render_view_id,
-                                int client_id,
+                                int bridge_id,
                                 const GURL& origin);
+  void OnCancelSysExPermissionRequest(int render_view_id,
+                                      int bridge_id,
+                                      const GURL& requesting_frame);
   void WasSysExPermissionGranted(int render_view_id,
-                                 int client_id,
+                                 int bridge_id,
                                  bool success);
 
   int render_process_id_;
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.cc b/content/browser/renderer_host/media/video_capture_buffer_pool.cc
index 3e30834..f6486a5 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool.cc
@@ -7,71 +7,54 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 
 namespace content {
 
-VideoCaptureBufferPool::VideoCaptureBufferPool(size_t size, int count)
-    : size_(size),
-      count_(count) {
+const int VideoCaptureBufferPool::kInvalidId = -1;
+
+VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
+    : count_(count),
+      next_buffer_id_(0) {
 }
 
 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
-}
-
-bool VideoCaptureBufferPool::Allocate() {
-  base::AutoLock lock(lock_);
-  DCHECK(!IsAllocated());
-  buffers_.resize(count_);
-  for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
-    Buffer* buffer = new Buffer();
-    buffers_[buffer_id] = buffer;
-    if (!buffer->shared_memory.CreateAndMapAnonymous(GetMemorySize()))
-      return false;
-  }
-  return true;
+  STLDeleteValues(&buffers_);
 }
 
 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
     int buffer_id,
-    base::ProcessHandle process_handle) {
+    base::ProcessHandle process_handle,
+    size_t* memory_size) {
   base::AutoLock lock(lock_);
-  DCHECK(IsAllocated());
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count_);
-  Buffer* buffer = buffers_[buffer_id];
+
+  Buffer* buffer = GetBuffer(buffer_id);
+  if (!buffer) {
+    NOTREACHED() << "Invalid buffer_id.";
+    return base::SharedMemory::NULLHandle();
+  }
   base::SharedMemoryHandle remote_handle;
   buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
+  *memory_size = buffer->shared_memory.requested_size();
   return remote_handle;
 }
 
-base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) {
+int VideoCaptureBufferPool::ReserveForProducer(size_t size,
+                                               int* buffer_id_to_drop) {
   base::AutoLock lock(lock_);
-  DCHECK(IsAllocated());
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count_);
-  return buffers_[buffer_id]->shared_memory.handle();
-}
-
-void* VideoCaptureBufferPool::GetMemory(int buffer_id) {
-  base::AutoLock lock(lock_);
-  DCHECK(IsAllocated());
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count_);
-  return buffers_[buffer_id]->shared_memory.memory();
-}
-
-int VideoCaptureBufferPool::ReserveForProducer() {
-  base::AutoLock lock(lock_);
-  return ReserveForProducerInternal();
+  return ReserveForProducerInternal(size, buffer_id_to_drop);
 }
 
 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
   base::AutoLock lock(lock_);
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count());
-  Buffer* buffer = buffers_[buffer_id];
+  Buffer* buffer = GetBuffer(buffer_id);
+  if (!buffer) {
+    NOTREACHED() << "Invalid buffer_id.";
+    return;
+  }
   DCHECK(buffer->held_by_producer);
   buffer->held_by_producer = false;
 }
@@ -80,65 +63,56 @@
     int buffer_id,
     int num_clients) {
   base::AutoLock lock(lock_);
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count());
-  DCHECK(IsAllocated());
-  Buffer* buffer = buffers_[buffer_id];
+  Buffer* buffer = GetBuffer(buffer_id);
+  if (!buffer) {
+    NOTREACHED() << "Invalid buffer_id.";
+    return;
+  }
   DCHECK(buffer->held_by_producer);
   DCHECK(!buffer->consumer_hold_count);
 
   buffer->consumer_hold_count = num_clients;
   // Note: |held_by_producer| will stay true until
   // RelinquishProducerReservation() (usually called by destructor of the object
-  // wrapping this buffer, e.g. a media::VideoFrame
+  // wrapping this buffer, e.g. a media::VideoFrame).
 }
 
 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
                                                     int num_clients) {
   base::AutoLock lock(lock_);
-  DCHECK(buffer_id >= 0);
-  DCHECK(buffer_id < count());
-  DCHECK_GT(num_clients, 0);
-  DCHECK(IsAllocated());
-  Buffer* buffer = buffers_[buffer_id];
+  Buffer* buffer = GetBuffer(buffer_id);
+  if (!buffer) {
+    NOTREACHED() << "Invalid buffer_id.";
+    return;
+  }
   DCHECK_GE(buffer->consumer_hold_count, num_clients);
 
   buffer->consumer_hold_count -= num_clients;
 }
 
-// State query functions.
-size_t VideoCaptureBufferPool::GetMemorySize() const {
-  // No need to take |lock_| currently.
-  return size_;
-}
-
 int VideoCaptureBufferPool::RecognizeReservedBuffer(
     base::SharedMemoryHandle maybe_belongs_to_pool) {
   base::AutoLock lock(lock_);
-  for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
-    Buffer* buffer = buffers_[buffer_id];
-    if (buffer->shared_memory.handle() == maybe_belongs_to_pool) {
-      DCHECK(buffer->held_by_producer);
-      return buffer_id;
+  for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
+    if (it->second->shared_memory.handle() == maybe_belongs_to_pool) {
+      DCHECK(it->second->held_by_producer);
+      return it->first;
     }
   }
-  return -1;  // Buffer is not from our pool.
+  return kInvalidId;  // Buffer is not from our pool.
 }
 
 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame(
     const gfx::Size& size,
-    int rotation) {
-  if (GetMemorySize() !=
-      media::VideoFrame::AllocationSize(media::VideoFrame::I420, size)) {
-    DCHECK_EQ(GetMemorySize(),
-              media::VideoFrame::AllocationSize(media::VideoFrame::I420, size));
-    return NULL;
-  }
-
+    int rotation,
+    int* buffer_id_to_drop) {
   base::AutoLock lock(lock_);
 
-  int buffer_id = ReserveForProducerInternal();
-  if (buffer_id < 0)
+  size_t frame_bytes =
+      media::VideoFrame::AllocationSize(media::VideoFrame::I420, size);
+
+  int buffer_id = ReserveForProducerInternal(frame_bytes, buffer_id_to_drop);
+  if (buffer_id == kInvalidId)
     return NULL;
 
   base::Closure disposal_handler = base::Bind(
@@ -146,7 +120,7 @@
       this,
       buffer_id);
 
-  Buffer* buffer = buffers_[buffer_id];
+  Buffer* buffer = GetBuffer(buffer_id);
   // Wrap the buffer in a VideoFrame container.
   scoped_refptr<media::VideoFrame> frame =
       media::VideoFrame::WrapExternalSharedMemory(
@@ -155,13 +129,13 @@
           gfx::Rect(size),
           size,
           static_cast<uint8*>(buffer->shared_memory.memory()),
-          GetMemorySize(),
+          frame_bytes,
           buffer->shared_memory.handle(),
           base::TimeDelta(),
           disposal_handler);
 
   if (buffer->rotation != rotation) {
-    // TODO(nick): Generalize the |rotation| mechanism.
+    // TODO(jiayl): Generalize the |rotation| mechanism.
     media::FillYUV(frame.get(), 0, 128, 128);
     buffer->rotation = rotation;
   }
@@ -169,45 +143,62 @@
   return frame;
 }
 
-bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() {
-  base::AutoLock lock(lock_);
-  for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
-    Buffer* buffer = buffers_[buffer_id];
-    if (buffer->consumer_hold_count > 0)
-      return true;
-  }
-  return false;
-}
-
 VideoCaptureBufferPool::Buffer::Buffer()
     : rotation(0),
       held_by_producer(false),
       consumer_hold_count(0) {}
 
-int VideoCaptureBufferPool::ReserveForProducerInternal() {
+int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
+                                                       int* buffer_id_to_drop) {
   lock_.AssertAcquired();
-  DCHECK(IsAllocated());
 
-  int buffer_id = -1;
-  for (int candidate_id = 0; candidate_id < count(); ++candidate_id) {
-    Buffer* candidate = buffers_[candidate_id];
-    if (!candidate->consumer_hold_count && !candidate->held_by_producer) {
-      buffer_id = candidate_id;
+  // Look for a buffer that's allocated, big enough, and not in use.
+  *buffer_id_to_drop = kInvalidId;
+  for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
+    Buffer* buffer = it->second;
+    if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
+      if (buffer->shared_memory.requested_size() >= size) {
+        // Existing buffer is big enough. Reuse it.
+        buffer->held_by_producer = true;
+        return it->first;
+      }
+    }
+  }
+
+  // Look for a buffer that's not in use, that we can reallocate.
+  for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
+    Buffer* buffer = it->second;
+    if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
+      // Existing buffer is too small. Free it so we can allocate a new one
+      // after the loop.
+      *buffer_id_to_drop = it->first;
+      buffers_.erase(it);
+      delete buffer;
       break;
     }
   }
-  if (buffer_id == -1)
-    return -1;
 
-  Buffer* buffer = buffers_[buffer_id];
-  CHECK_GE(buffer->shared_memory.requested_size(), size_);
-  buffer->held_by_producer = true;
-  return buffer_id;
+  // If possible, grow the pool by creating a new buffer.
+  if (static_cast<int>(buffers_.size()) < count_) {
+    int buffer_id = next_buffer_id_++;
+    scoped_ptr<Buffer> buffer(new Buffer());
+    if (!buffer->shared_memory.CreateAndMapAnonymous(size))
+      return kInvalidId;
+    buffer->held_by_producer = true;
+    buffers_[buffer_id] = buffer.release();
+    return buffer_id;
+  }
+
+  // The pool is at its size limit, and all buffers are in use.
+  return kInvalidId;
 }
 
-bool VideoCaptureBufferPool::IsAllocated() const {
-  lock_.AssertAcquired();
-  return !buffers_.empty();
+VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
+    int buffer_id) {
+  BufferMap::iterator it = buffers_.find(buffer_id);
+  if (it == buffers_.end())
+    return NULL;
+  return it->second;
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.h b/content/browser/renderer_host/media/video_capture_buffer_pool.h
index 6d96077..70677c1 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.h
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
 
+#include <map>
+
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
@@ -25,43 +27,49 @@
 // A thread-safe class that does the bookkeeping and lifetime management for a
 // pool of shared-memory pixel buffers cycled between an in-process producer
 // (e.g. a VideoCaptureDevice) and a set of out-of-process consumers. The pool
-// is intended to be allocated and orchestrated by a VideoCaptureController, but
-// is designed to outlive the controller if necessary.
+// is intended to be orchestrated by a VideoCaptureController, but is designed
+// to outlive the controller if necessary.
 //
-// Buffers are identified by an int value called |buffer_id|. Callers may depend
-// on the buffer IDs being dense in the range [0, count()), so long as the
-// Allocate() step succeeded. -1 is never a valid ID, and is returned by some
-// methods to indicate failure. Producers get a buffer by calling
-// ReserveForProducer(), and may pass on their ownership to the consumer by
-// calling HoldForConsumers(), or drop the buffer (without further processing)
-// by calling ReserveForProducer(). Consumers signal that they are done with the
-// buffer by calling RelinquishConsumerHold().
+// Producers get a buffer by calling ReserveForProducer(), and may pass on their
+// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
+// (without further processing) by calling RelinquishProducerReservation().
+// Consumers signal that they are done with the buffer by calling
+// RelinquishConsumerHold().
+//
+// Buffers are allocated on demand, but there will never be more than |count|
+// buffers in existence at any time. Buffers are identified by an int value
+// called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by
+// some methods to indicate failure. The active set of buffer ids may change
+// over the lifetime of the buffer pool, as existing buffers are freed and
+// reallocated at larger size. When reallocation occurs, new buffer IDs will
+// circulate.
 class CONTENT_EXPORT VideoCaptureBufferPool
     : public base::RefCountedThreadSafe<VideoCaptureBufferPool> {
  public:
-  VideoCaptureBufferPool(size_t size, int count);
-
-  // One-time initialization to allocate the shared memory buffers. Returns true
-  // on success.
-  bool Allocate();
+  static const int kInvalidId;
+  explicit VideoCaptureBufferPool(int count);
 
   // One-time (per client/per-buffer) initialization to share a particular
-  // buffer to a process.
+  // buffer to a process. The size of the allocation is returned as
+  // |memory_size|.
   base::SharedMemoryHandle ShareToProcess(int buffer_id,
-                                          base::ProcessHandle process_handle);
+                                          base::ProcessHandle process_handle,
+                                          size_t* memory_size);
 
-  // Get the shared memory handle for a particular buffer index.
-  base::SharedMemoryHandle GetHandle(int buffer_id);
-
-  // Get the mapped buffer memory for a particular buffer index.
-  void* GetMemory(int buffer_id);
-
-  // Locate the index of a buffer (if any) that's not in use by the producer or
-  // consumers, and reserve it. The buffer remains reserved (and writable by the
+  // Reserve or allocate a buffer of at least |size| bytes and return its id.
+  // This will fail (returning kInvalidId) if the pool already is at its |count|
+  // limit of the number of allocations, and all allocated buffers are in use by
+  // the producer and/or consumers.
+  //
+  // If successful, the reserved buffer remains reserved (and writable by the
   // producer) until ownership is transferred either to the consumer via
   // HoldForConsumers(), or back to the pool with
   // RelinquishProducerReservation().
-  int ReserveForProducer();
+  //
+  // On occasion, this call will decide to free an old buffer to make room for a
+  // new allocation at a larger size. If so, the ID of the destroyed buffer is
+  // returned via |buffer_id_to_drop|.
+  int ReserveForProducer(size_t size, int* buffer_id_to_drop);
 
   // Indicate that a buffer held for the producer should be returned back to the
   // pool without passing on to the consumer. This effectively is the opposite
@@ -79,19 +87,20 @@
   void RelinquishConsumerHold(int buffer_id, int num_clients);
 
   // Detect whether a particular SharedMemoryHandle is exported by a buffer that
-  // belongs to this pool -- that is, whether it was allocated by an earlier
-  // call to ReserveForProducer(). If so, return its buffer_id (a value on the
-  // range [0, count())). If not, return -1, indicating the buffer is not
-  // recognized (it may be a valid frame, but we didn't allocate it).
+  // belongs to this pool -- that is, whether it was reserved by an earlier call
+  // to ReserveForProducer(). If so, return its buffer_id. If not, return
+  // kInvalidId, indicating the buffer is not recognized (it may be a valid
+  // frame, but we didn't allocate it).
   int RecognizeReservedBuffer(base::SharedMemoryHandle maybe_belongs_to_pool);
 
-  // Utility functions to return a buffer wrapped in a useful type.
-  scoped_refptr<media::VideoFrame> ReserveI420VideoFrame(const gfx::Size& size,
-                                                         int rotation);
+  // Return a buffer wrapped in a useful type. If a reallocation occurred, the
+  // ID of the destroyed buffer is returned via |buffer_id_to_drop|.
+  scoped_refptr<media::VideoFrame> ReserveI420VideoFrame(
+      const gfx::Size& size,
+      int rotation,
+      int* buffer_id_to_drop);
 
   int count() const { return count_; }
-  size_t GetMemorySize() const;
-  bool IsAnyBufferHeldForConsumers();
 
  private:
   friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
@@ -104,6 +113,9 @@
     base::SharedMemory shared_memory;
 
     // Rotation in degrees of the buffer.
+    //
+    // TODO(jiayl): Move this out of this class. Clients can track rotation
+    // state themselves by means of a map keyed by buffer_id.
     int rotation;
 
     // Tracks whether this buffer is currently referenced by the producer.
@@ -113,20 +125,25 @@
     int consumer_hold_count;
   };
 
+  typedef std::map<int, Buffer*> BufferMap;
+
   virtual ~VideoCaptureBufferPool();
 
-  int ReserveForProducerInternal();
+  int ReserveForProducerInternal(size_t size, int* buffer_id_to_drop);
 
-  bool IsAllocated() const;
+  Buffer* GetBuffer(int buffer_id);
 
-  // Protects |buffers_| and contents thereof.
+  // The max number of buffers that the pool is allowed to have at any moment.
+  const int count_;
+
+  // Protects everything below it.
   base::Lock lock_;
 
-  // The buffers, indexed by |buffer_id|. Element 0 is always NULL.
-  ScopedVector<Buffer> buffers_;
+  // The ID of the next buffer.
+  int next_buffer_id_;
 
-  const size_t size_;
-  const int count_;
+  // The buffers, indexed by |buffer_id|.
+  BufferMap buffers_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPool);
 };
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
index 30509a3..bc6e965 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
@@ -16,27 +16,53 @@
 
 namespace content {
 
-TEST(VideoCaptureBufferPoolTest, BufferPool) {
-  const gfx::Size size = gfx::Size(640, 480);
+class VideoCaptureBufferPoolTest : public testing::Test {
+ protected:
+  VideoCaptureBufferPoolTest()
+      : expected_dropped_id_(0),
+        pool_(new VideoCaptureBufferPool(3)) {}
+
+  void ExpectDroppedId(int expected_dropped_id) {
+    expected_dropped_id_ = expected_dropped_id;
+  }
+
+  scoped_refptr<media::VideoFrame> ReserveI420VideoFrame(
+      const gfx::Size& size) {
+    // To verify that ReserveI420VideoFrame always sets |buffer_id_to_drop|,
+    // initialize it to something different than the expected value.
+    int buffer_id_to_drop = ~expected_dropped_id_;
+    scoped_refptr<media::VideoFrame> frame =
+        pool_->ReserveI420VideoFrame(size, 0, &buffer_id_to_drop);
+    EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop)
+        << "Unexpected buffer reallocation result.";
+    return frame;
+  }
+
+  int expected_dropped_id_;
+  scoped_refptr<VideoCaptureBufferPool> pool_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
+};
+
+TEST_F(VideoCaptureBufferPoolTest, BufferPool) {
+  const gfx::Size size_lo = gfx::Size(640, 480);
+  const gfx::Size size_hi = gfx::Size(1024, 768);
   scoped_refptr<media::VideoFrame> non_pool_frame =
-      media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size,
-                                     gfx::Rect(size), size, base::TimeDelta());
-  scoped_refptr<VideoCaptureBufferPool> pool = new VideoCaptureBufferPool(
-      media::VideoFrame::AllocationSize(media::VideoFrame::I420, size), 3);
+      media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_lo,
+                                     gfx::Rect(size_lo), size_lo,
+                                     base::TimeDelta());
 
-  ASSERT_EQ(460800u, pool->GetMemorySize());
-  ASSERT_TRUE(pool->Allocate());
+  // Reallocation won't happen for the first part of the test.
+  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
 
-  scoped_refptr<media::VideoFrame> frame1 =
-      pool->ReserveI420VideoFrame(size, 0);
+  scoped_refptr<media::VideoFrame> frame1 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame1.get());
-  ASSERT_EQ(size, frame1->coded_size());
-  scoped_refptr<media::VideoFrame> frame2 =
-      pool->ReserveI420VideoFrame(size, 0);
+  ASSERT_EQ(size_lo, frame1->coded_size());
+  scoped_refptr<media::VideoFrame> frame2 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame2.get());
-  ASSERT_EQ(size, frame2->coded_size());
-  scoped_refptr<media::VideoFrame> frame3 =
-      pool->ReserveI420VideoFrame(size, 0);
+  ASSERT_EQ(size_lo, frame2->coded_size());
+  scoped_refptr<media::VideoFrame> frame3 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame3.get());
 
   // Touch the memory.
@@ -45,112 +71,110 @@
   media::FillYUV(frame3.get(), 0x77, 0x88, 0x99);
 
   // Fourth frame should fail.
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
   // Release 1st frame and retry; this should succeed.
   frame1 = NULL;
-  scoped_refptr<media::VideoFrame> frame4 =
-      pool->ReserveI420VideoFrame(size, 0);
+  scoped_refptr<media::VideoFrame> frame4 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame4.get());
 
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_hi)) << "Pool should be empty";
 
   // Validate the IDs
   int buffer_id2 =
-      pool->RecognizeReservedBuffer(frame2->shared_memory_handle());
-  ASSERT_LE(0, buffer_id2);
+      pool_->RecognizeReservedBuffer(frame2->shared_memory_handle());
+  ASSERT_EQ(1, buffer_id2);
   int buffer_id3 =
-      pool->RecognizeReservedBuffer(frame3->shared_memory_handle());
-  ASSERT_LE(0, buffer_id3);
+      pool_->RecognizeReservedBuffer(frame3->shared_memory_handle());
+  base::SharedMemoryHandle memory_handle3 = frame3->shared_memory_handle();
+  ASSERT_EQ(2, buffer_id3);
   int buffer_id4 =
-      pool->RecognizeReservedBuffer(frame4->shared_memory_handle());
-  ASSERT_LE(0, buffer_id4);
+      pool_->RecognizeReservedBuffer(frame4->shared_memory_handle());
+  ASSERT_EQ(0, buffer_id4);
   int buffer_id_non_pool =
-      pool->RecognizeReservedBuffer(non_pool_frame->shared_memory_handle());
-  ASSERT_GT(0, buffer_id_non_pool);
-
-  ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers());
+      pool_->RecognizeReservedBuffer(non_pool_frame->shared_memory_handle());
+  ASSERT_EQ(VideoCaptureBufferPool::kInvalidId, buffer_id_non_pool);
 
   // Deliver a frame.
-  pool->HoldForConsumers(buffer_id3, 2);
+  pool_->HoldForConsumers(buffer_id3, 2);
 
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
+
   frame3 = NULL;   // Old producer releases frame. Should be a noop.
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
-  frame2 = NULL;  // Active producer releases frame. Should free a frame.
-  buffer_id2 = 0;
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_hi)) << "Pool should be empty";
 
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
-  frame1 = pool->ReserveI420VideoFrame(size, 0);
+  frame2 = NULL;  // Active producer releases frame. Should free a frame.
+
+  frame1 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame1.get());
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
   // First consumer finishes.
-  pool->RelinquishConsumerHold(buffer_id3, 1);
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
+  pool_->RelinquishConsumerHold(buffer_id3, 1);
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
   // Second consumer finishes. This should free that frame.
-  pool->RelinquishConsumerHold(buffer_id3, 1);
-  ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers());
-  frame3 = pool->ReserveI420VideoFrame(size, 0);
+  pool_->RelinquishConsumerHold(buffer_id3, 1);
+  frame3 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame3.get());
-  ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers());
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ASSERT_EQ(buffer_id3,
+            pool_->RecognizeReservedBuffer(frame3->shared_memory_handle()))
+      << "Buffer ID should be reused.";
+  ASSERT_EQ(memory_handle3, frame3->shared_memory_handle());
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
   // Now deliver & consume frame1, but don't release the VideoFrame.
   int buffer_id1 =
-      pool->RecognizeReservedBuffer(frame1->shared_memory_handle());
-  ASSERT_LE(0, buffer_id1);
-  pool->HoldForConsumers(buffer_id1, 5);
-  ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers());
-  pool->RelinquishConsumerHold(buffer_id1, 5);
-  ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers());
+      pool_->RecognizeReservedBuffer(frame1->shared_memory_handle());
+  ASSERT_EQ(1, buffer_id1);
+  pool_->HoldForConsumers(buffer_id1, 5);
+  pool_->RelinquishConsumerHold(buffer_id1, 5);
 
   // Even though the consumer is done with the buffer at |buffer_id1|, it cannot
   // be re-allocated to the producer, because |frame1| still references it. But
   // when |frame1| goes away, we should be able to re-reserve the buffer (and
   // the ID ought to be the same).
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
   frame1 = NULL;  // Should free the frame.
-  frame2 = pool->ReserveI420VideoFrame(size, 0);
+  frame2 = ReserveI420VideoFrame(size_lo);
   ASSERT_TRUE(NULL != frame2.get());
   ASSERT_EQ(buffer_id1,
-            pool->RecognizeReservedBuffer(frame2->shared_memory_handle()));
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+            pool_->RecognizeReservedBuffer(frame2->shared_memory_handle()));
+  buffer_id2 = buffer_id1;
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
-  // For good measure, do one more cycle of free/realloc without delivery, now
-  // that this buffer has been through the consumer-hold cycle.
+  // Now try reallocation with different resolutions. We expect reallocation
+  // to occur only when the old buffer is too small.
   frame2 = NULL;
-  frame1 = pool->ReserveI420VideoFrame(size, 0);
-  ASSERT_TRUE(NULL != frame1.get());
-  ASSERT_EQ(buffer_id1,
-            pool->RecognizeReservedBuffer(frame1->shared_memory_handle()));
-  ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get())
-      << "Pool should be empty";
+  ExpectDroppedId(buffer_id2);
+  frame2 = ReserveI420VideoFrame(size_hi);
+  ASSERT_TRUE(NULL != frame2.get());
+  ASSERT_TRUE(frame2->coded_size() == size_hi);
+  ASSERT_EQ(3, pool_->RecognizeReservedBuffer(frame2->shared_memory_handle()));
+  base::SharedMemoryHandle memory_handle_hi = frame2->shared_memory_handle();
+  frame2 = NULL;  // Frees it.
+  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  frame2 = ReserveI420VideoFrame(size_lo);
+  base::SharedMemoryHandle memory_handle_lo = frame2->shared_memory_handle();
+  ASSERT_EQ(memory_handle_hi, memory_handle_lo)
+      << "Decrease in resolution should not reallocate buffer";
+  ASSERT_TRUE(NULL != frame2.get());
+  ASSERT_TRUE(frame2->coded_size() == size_lo);
+  ASSERT_EQ(3, pool_->RecognizeReservedBuffer(frame2->shared_memory_handle()));
+  ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty";
 
-  // Tear down the pool, writing into the frames. The VideoFrame should
+  // Tear down the pool_, writing into the frames. The VideoFrame should
   // preserve the lifetime of the underlying memory.
   frame3 = NULL;
-  pool = NULL;
+  pool_ = NULL;
 
   // Touch the memory.
-  media::FillYUV(frame1.get(), 0x11, 0x22, 0x33);
+  media::FillYUV(frame2.get(), 0x11, 0x22, 0x33);
   media::FillYUV(frame4.get(), 0x44, 0x55, 0x66);
 
-  frame1 = NULL;
+  frame2 = NULL;
 
   media::FillYUV(frame4.get(), 0x44, 0x55, 0x66);
   frame4 = NULL;
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index c01c949..40e94bd 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -49,8 +49,11 @@
   base::ProcessHandle render_process_handle;
   media::VideoCaptureParams parameters;
 
-  // Buffers used by this client.
-  std::set<int> buffers;
+  // Buffers that are currently known to this client.
+  std::set<int> known_buffers;
+
+  // Buffers currently held by this client.
+  std::set<int> active_buffers;
 
   // State of capture session, controlled by VideoCaptureManager directly. This
   // transitions to true as soon as StopSession() occurs, at which point the
@@ -77,11 +80,13 @@
     : public media::VideoCaptureDevice::Client {
  public:
   explicit VideoCaptureDeviceClient(
-      const base::WeakPtr<VideoCaptureController>& controller);
+      const base::WeakPtr<VideoCaptureController>& controller,
+      const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
   virtual ~VideoCaptureDeviceClient();
 
   // VideoCaptureDevice::Client implementation.
-  virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() OVERRIDE;
+  virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer(
+      const gfx::Size& size) OVERRIDE;
   virtual void OnIncomingCapturedFrame(const uint8* data,
                                        int length,
                                        base::Time timestamp,
@@ -98,11 +103,15 @@
       const media::VideoCaptureCapability& info) OVERRIDE;
 
  private:
+  scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame(
+      const gfx::Size& size,
+      int rotation);
+
   // The controller to which we post events.
   const base::WeakPtr<VideoCaptureController> controller_;
 
   // The pool of shared-memory buffers used for capturing.
-  scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
 
   // Chopped pixels in width/height in case video capture device has odd
   // numbers for width/height.
@@ -114,14 +123,16 @@
 };
 
 VideoCaptureController::VideoCaptureController()
-    : state_(VIDEO_CAPTURE_STATE_STARTED),
+    : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)),
+      state_(VIDEO_CAPTURE_STATE_STARTED),
       weak_ptr_factory_(this) {
-  memset(&current_params_, 0, sizeof(current_params_));
 }
 
 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
-    const base::WeakPtr<VideoCaptureController>& controller)
+    const base::WeakPtr<VideoCaptureController>& controller,
+    const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
     : controller_(controller),
+      buffer_pool_(buffer_pool),
       chopped_width_(0),
       chopped_height_(0) {}
 
@@ -134,7 +145,7 @@
 scoped_ptr<media::VideoCaptureDevice::Client>
 VideoCaptureController::NewDeviceClient() {
   scoped_ptr<media::VideoCaptureDevice::Client> result(
-      new VideoCaptureDeviceClient(this->GetWeakPtr()));
+      new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_));
   return result.Pass();
 }
 
@@ -145,9 +156,9 @@
     const media::VideoCaptureParams& params) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id
-           << ", (" << params.width
-           << ", " << params.height
-           << ", " << params.frame_rate
+           << ", (" << params.requested_format.width
+           << ", " << params.requested_format.height
+           << ", " << params.requested_format.frame_rate
            << ", " << params.session_id
            << ")";
 
@@ -166,9 +177,6 @@
   // If we already have gotten frame_info from the device, repeat it to the new
   // client.
   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
-    if (frame_info_.IsValid()) {
-      SendFrameInfoAndBuffers(client);
-    }
     controller_clients_.push_back(client);
     return;
   }
@@ -185,15 +193,13 @@
     return kInvalidMediaCaptureSessionId;
 
   // Take back all buffers held by the |client|.
-  if (buffer_pool_.get()) {
-    for (std::set<int>::iterator buffer_it = client->buffers.begin();
-         buffer_it != client->buffers.end();
-         ++buffer_it) {
-      int buffer_id = *buffer_it;
-      buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
-    }
+  for (std::set<int>::iterator buffer_it = client->active_buffers.begin();
+       buffer_it != client->active_buffers.end();
+       ++buffer_it) {
+    int buffer_id = *buffer_it;
+    buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
   }
-  client->buffers.clear();
+  client->active_buffers.clear();
 
   int session_id = client->parameters.session_id;
   controller_clients_.remove(client);
@@ -224,21 +230,18 @@
 
   // If this buffer is not held by this client, or this client doesn't exist
   // in controller, do nothing.
-  if (!client ||
-      client->buffers.find(buffer_id) == client->buffers.end()) {
+  if (!client || !client->active_buffers.erase(buffer_id)) {
     NOTREACHED();
     return;
   }
 
-  client->buffers.erase(buffer_id);
   buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
 }
 
 scoped_refptr<media::VideoFrame>
-VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() {
-  return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
-                                                       frame_info_.height),
-                                             0);
+VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer(
+    const gfx::Size& size) {
+  return DoReserveI420VideoFrame(size, 0);
 }
 
 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame(
@@ -250,9 +253,10 @@
     bool flip_horiz) {
   TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame");
 
-  if (!buffer_pool_.get())
+  if (!frame_info_.IsValid())
     return;
-  scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame(
+
+  scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame(
       gfx::Size(frame_info_.width, frame_info_.height), rotation);
 
   if (!dst.get())
@@ -387,6 +391,7 @@
       base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
                  controller_,
                  dst,
+                 frame_info_.frame_rate,
                  timestamp));
 }
 
@@ -394,8 +399,6 @@
 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
     const scoped_refptr<media::VideoFrame>& frame,
     base::Time timestamp) {
-  if (!buffer_pool_)
-    return;
 
   // If this is a frame that belongs to the buffer pool, we can forward it
   // directly to the IO thread and be done.
@@ -404,104 +407,11 @@
     BrowserThread::PostTask(BrowserThread::IO,
         FROM_HERE,
         base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
-                   controller_, frame, timestamp));
+                   controller_, frame, frame_info_.frame_rate, timestamp));
     return;
   }
 
-  // Otherwise, this is a frame that belongs to the caller, and we must copy
-  // it to a frame from the buffer pool.
-  scoped_refptr<media::VideoFrame> target =
-      buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
-                                                    frame_info_.height),
-                                          0);
-
-  if (!target.get())
-    return;
-
-  // Validate the inputs.
-  if (frame->coded_size() != target->coded_size())
-    return;  // Only exact copies are supported.
-  if (!(frame->format() == media::VideoFrame::I420 ||
-        frame->format() == media::VideoFrame::YV12 ||
-        frame->format() == media::VideoFrame::RGB32)) {
-    NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame";
-    return;
-  }
-
-  const int kYPlane = media::VideoFrame::kYPlane;
-  const int kUPlane = media::VideoFrame::kUPlane;
-  const int kVPlane = media::VideoFrame::kVPlane;
-  const int kAPlane = media::VideoFrame::kAPlane;
-  const int kRGBPlane = media::VideoFrame::kRGBPlane;
-
-  // Do color conversion from the camera format to I420.
-  switch (frame->format()) {
-#if defined(GOOGLE_TV)
-    case media::VideoFrame::HOLE:
-      // Fall-through to NOTREACHED() block.
-#endif
-    case media::VideoFrame::INVALID:
-    case media::VideoFrame::YV16:
-    case media::VideoFrame::EMPTY:
-    case media::VideoFrame::NATIVE_TEXTURE: {
-      NOTREACHED();
-      break;
-    }
-    case media::VideoFrame::I420:
-    case media::VideoFrame::YV12: {
-      DCHECK(!chopped_width_ && !chopped_height_);
-      media::CopyYPlane(frame->data(kYPlane),
-                        frame->stride(kYPlane),
-                        frame->rows(kYPlane),
-                        target.get());
-      media::CopyUPlane(frame->data(kUPlane),
-                        frame->stride(kUPlane),
-                        frame->rows(kUPlane),
-                        target.get());
-      media::CopyVPlane(frame->data(kVPlane),
-                        frame->stride(kVPlane),
-                        frame->rows(kVPlane),
-                        target.get());
-      break;
-    }
-    case media::VideoFrame::YV12A: {
-      DCHECK(!chopped_width_ && !chopped_height_);
-      media::CopyYPlane(frame->data(kYPlane),
-                        frame->stride(kYPlane),
-                        frame->rows(kYPlane),
-                        target.get());
-      media::CopyUPlane(frame->data(kUPlane),
-                        frame->stride(kUPlane),
-                        frame->rows(kUPlane),
-                        target.get());
-      media::CopyVPlane(frame->data(kVPlane),
-                        frame->stride(kVPlane),
-                        frame->rows(kVPlane),
-                        target.get());
-      media::CopyAPlane(frame->data(kAPlane),
-                        frame->stride(kAPlane),
-                        frame->rows(kAPlane),
-                        target.get());
-      break;
-    }
-    case media::VideoFrame::RGB32: {
-      media::ConvertRGB32ToYUV(frame->data(kRGBPlane),
-                               target->data(kYPlane),
-                               target->data(kUPlane),
-                               target->data(kVPlane),
-                               target->coded_size().width(),
-                               target->coded_size().height(),
-                               frame->stride(kRGBPlane),
-                               target->stride(kYPlane),
-                               target->stride(kUPlane));
-      break;
-    }
-  }
-
-  BrowserThread::PostTask(BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
-                 controller_, target, timestamp));
+  NOTREACHED() << "Frames should always belong to the buffer pool.";
 }
 
 void VideoCaptureController::VideoCaptureDeviceClient::OnError() {
@@ -526,54 +436,40 @@
   } else {
     chopped_height_ = 0;
   }
-
-  DCHECK(!buffer_pool_.get());
-
-  // TODO(nick): Give BufferPool the same lifetime as the controller, have it
-  // support frame size changes, and stop checking it for NULL everywhere.
-  // http://crbug.com/266082
-  buffer_pool_ = new VideoCaptureBufferPool(
-      media::VideoFrame::AllocationSize(
-            media::VideoFrame::I420,
-            gfx::Size(frame_info_.width, frame_info_.height)),
-      kNoOfBuffers);
-
-  // Check whether all buffers were created successfully.
-  if (!buffer_pool_->Allocate()) {
-    // Transition to the error state.
-    buffer_pool_ = NULL;
-    OnError();
-    return;
-  }
-
-  BrowserThread::PostTask(BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, controller_,
-                 frame_info_, buffer_pool_));
 }
 
 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged(
     const media::VideoCaptureCapability& info) {
-  BrowserThread::PostTask(BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&VideoCaptureController::DoFrameInfoChangedOnIOThread,
-                 controller_, info));
+  OnFrameInfo(info);
+}
+
+scoped_refptr<media::VideoFrame>
+VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame(
+    const gfx::Size& size,
+    int rotation) {
+  int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
+  scoped_refptr<media::VideoFrame> frame =
+      buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop);
+  if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
+    BrowserThread::PostTask(BrowserThread::IO,
+        FROM_HERE,
+        base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
+                   controller_, buffer_id_to_drop));
+  }
+  return frame;
 }
 
 VideoCaptureController::~VideoCaptureController() {
-  buffer_pool_ = NULL;  // Release all buffers.
   STLDeleteContainerPointers(controller_clients_.begin(),
                              controller_clients_.end());
 }
 
 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread(
     const scoped_refptr<media::VideoFrame>& reserved_frame,
+    int frame_rate,
     base::Time timestamp) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
-  if (!buffer_pool_.get())
-    return;
-
   int buffer_id = buffer_pool_->RecognizeReservedBuffer(
       reserved_frame->shared_memory_handle());
   if (buffer_id < 0) {
@@ -581,16 +477,37 @@
     return;
   }
 
+  media::VideoCaptureFormat frame_format(
+      reserved_frame->coded_size().width(),
+      reserved_frame->coded_size().height(),
+      frame_rate,
+      media::VariableResolutionVideoCaptureDevice);
+
   int count = 0;
   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
     for (ControllerClients::iterator client_it = controller_clients_.begin();
          client_it != controller_clients_.end(); ++client_it) {
-      if ((*client_it)->session_closed)
+      ControllerClient* client = *client_it;
+      if (client->session_closed)
         continue;
 
-      (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id,
-                                                 buffer_id, timestamp);
-      (*client_it)->buffers.insert(buffer_id);
+      bool is_new_buffer = client->known_buffers.insert(buffer_id).second;
+      if (is_new_buffer) {
+        // On the first use of a buffer on a client, share the memory handle.
+        size_t memory_size = 0;
+        base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess(
+            buffer_id, client->render_process_handle, &memory_size);
+        client->event_handler->OnBufferCreated(client->controller_id,
+                                               remote_handle,
+                                               memory_size,
+                                               buffer_id);
+      }
+
+      client->event_handler->OnBufferReady(client->controller_id,
+                                           buffer_id, timestamp,
+                                           frame_format);
+      bool inserted = client->active_buffers.insert(buffer_id).second;
+      DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id;
       count++;
     }
   }
@@ -598,72 +515,34 @@
   buffer_pool_->HoldForConsumers(buffer_id, count);
 }
 
-void VideoCaptureController::DoFrameInfoOnIOThread(
-    const media::VideoCaptureCapability& frame_info,
-    const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  DCHECK(!buffer_pool_.get()) << "Frame info should happen only once.";
-
-  // Allocate memory only when device has been started.
-  if (state_ != VIDEO_CAPTURE_STATE_STARTED)
-    return;
-
-  frame_info_ = frame_info;
-  buffer_pool_ = buffer_pool;
-
-  for (ControllerClients::iterator client_it = controller_clients_.begin();
-       client_it != controller_clients_.end(); ++client_it) {
-    if ((*client_it)->session_closed)
-        continue;
-
-    SendFrameInfoAndBuffers(*client_it);
-  }
-}
-
-void VideoCaptureController::DoFrameInfoChangedOnIOThread(
-    const media::VideoCaptureCapability& info) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if
-  // needed, to support the new video capture format. See crbug.com/266082.
-  for (ControllerClients::iterator client_it = controller_clients_.begin();
-       client_it != controller_clients_.end(); ++client_it) {
-    if ((*client_it)->session_closed)
-        continue;
-
-    (*client_it)->event_handler->OnFrameInfoChanged(
-        (*client_it)->controller_id,
-        info.width,
-        info.height,
-        info.frame_rate);
-  }
-}
-
 void VideoCaptureController::DoErrorOnIOThread() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   state_ = VIDEO_CAPTURE_STATE_ERROR;
-  ControllerClients::iterator client_it;
-  for (client_it = controller_clients_.begin();
-       client_it != controller_clients_.end(); ++client_it) {
-     if ((*client_it)->session_closed)
-        continue;
 
-    (*client_it)->event_handler->OnError((*client_it)->controller_id);
+  for (ControllerClients::iterator client_it = controller_clients_.begin();
+       client_it != controller_clients_.end(); ++client_it) {
+    ControllerClient* client = *client_it;
+    if (client->session_closed)
+       continue;
+
+    client->event_handler->OnError(client->controller_id);
   }
 }
 
-void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) {
+void VideoCaptureController::DoBufferDestroyedOnIOThread(
+    int buffer_id_to_drop) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  DCHECK(frame_info_.IsValid());
-  client->event_handler->OnFrameInfo(client->controller_id,
-                                     frame_info_);
-  for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) {
-    base::SharedMemoryHandle remote_handle =
-        buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle);
 
-    client->event_handler->OnBufferCreated(client->controller_id,
-                                           remote_handle,
-                                           buffer_pool_->GetMemorySize(),
-                                           buffer_id);
+  for (ControllerClients::iterator client_it = controller_clients_.begin();
+       client_it != controller_clients_.end(); ++client_it) {
+    ControllerClient* client = *client_it;
+    if (client->session_closed)
+      continue;
+
+    if (client->known_buffers.erase(buffer_id_to_drop)) {
+      client->event_handler->OnBufferDestroyed(client->controller_id,
+                                               buffer_id_to_drop);
+    }
   }
 }
 
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h
index 5a2dec0..0e9fd78 100644
--- a/content/browser/renderer_host/media/video_capture_controller.h
+++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -55,7 +55,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
-#include "base/synchronization/lock.h"
 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
 #include "content/common/content_export.h"
@@ -78,10 +77,9 @@
   // instance.
   scoped_ptr<media::VideoCaptureDevice::Client> NewDeviceClient();
 
-  // Start video capturing and try to use the resolution specified in
-  // |params|.
-  // When capturing starts, the |event_handler| will receive an OnFrameInfo()
-  // call informing it of the resolution that was actually picked by the device.
+  // Start video capturing and try to use the resolution specified in |params|.
+  // Buffers will be shared to the client as necessary. The client will continue
+  // to receive frames from the device until RemoveClient() is called.
   void AddClient(const VideoCaptureControllerID& id,
                  VideoCaptureControllerEventHandler* event_handler,
                  base::ProcessHandle render_process,
@@ -115,16 +113,11 @@
   // Worker functions on IO thread. Called by the VideoCaptureDeviceClient.
   void DoIncomingCapturedFrameOnIOThread(
       const scoped_refptr<media::VideoFrame>& captured_frame,
+      int frame_rate,
       base::Time timestamp);
-  void DoFrameInfoOnIOThread(
-      const media::VideoCaptureCapability& frame_info,
-      const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
-  void DoFrameInfoChangedOnIOThread(const media::VideoCaptureCapability& info);
   void DoErrorOnIOThread();
   void DoDeviceStoppedOnIOThread();
-
-  // Send frame info and init buffers to |client|.
-  void SendFrameInfoAndBuffers(ControllerClient* client);
+  void DoBufferDestroyedOnIOThread(int buffer_id_to_drop);
 
   // Find a client of |id| and |handler| in |clients|.
   ControllerClient* FindClient(
@@ -138,17 +131,11 @@
       const ControllerClients& clients);
 
   // The pool of shared-memory buffers used for capturing.
-  scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
 
   // All clients served by this controller.
   ControllerClients controller_clients_;
 
-  // The parameter that currently used for the capturing.
-  media::VideoCaptureParams current_params_;
-
-  // Tracks the current frame format.
-  media::VideoCaptureCapability frame_info_;
-
   // Takes on only the states 'STARTED' and 'ERROR'. 'ERROR' is an absorbing
   // state which stops the flow of data to clients.
   VideoCaptureState state_;
diff --git a/content/browser/renderer_host/media/video_capture_controller_event_handler.h b/content/browser/renderer_host/media/video_capture_controller_event_handler.h
index 4a2c294..6559a53 100644
--- a/content/browser/renderer_host/media/video_capture_controller_event_handler.h
+++ b/content/browser/renderer_host/media/video_capture_controller_event_handler.h
@@ -8,10 +8,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-
-namespace media {
-class VideoCaptureCapability;
-}
+#include "media/video/capture/video_capture_types.h"
 
 namespace content {
 
@@ -36,22 +33,19 @@
   // A buffer has been newly created.
   virtual void OnBufferCreated(const VideoCaptureControllerID& id,
                                base::SharedMemoryHandle handle,
-                               int length, int buffer_id) = 0;
+                               int length,
+                               int buffer_id) = 0;
+
+  // A previously created buffer has been freed and will no longer be used.
+  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
+                                 int buffer_id) = 0;
 
   // A buffer has been filled with I420 video.
-  virtual void OnBufferReady(const VideoCaptureControllerID& id,
-                             int buffer_id,
-                             base::Time timestamp) = 0;
-
-  // The frame resolution the VideoCaptureDevice capture video in.
-  virtual void OnFrameInfo(const VideoCaptureControllerID& id,
-                           const media::VideoCaptureCapability& format) = 0;
-
-  // The frame resolution the VideoCaptureDevice capture video in.
-  virtual void OnFrameInfoChanged(const VideoCaptureControllerID& id,
-                                  int width,
-                                  int height,
-                                  int frame_rate) {};
+  virtual void OnBufferReady(
+      const VideoCaptureControllerID& id,
+      int buffer_id,
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format) = 0;
 
   // The capture session has ended and no more frames will be sent.
   virtual void OnEnded(const VideoCaptureControllerID& id) = 0;
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 1bb4c20..89ac62c 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -40,8 +40,8 @@
   // These mock methods are delegated to by our fake implementation of
   // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
   MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&));
+  MOCK_METHOD1(DoBufferDestroyed, void(const VideoCaptureControllerID&));
   MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&));
-  MOCK_METHOD1(DoFrameInfo, void(const VideoCaptureControllerID&));
   MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
   MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&));
 
@@ -53,19 +53,19 @@
                                int length, int buffer_id) OVERRIDE {
     DoBufferCreated(id);
   }
+  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
+                                 int buffer_id) OVERRIDE {
+    DoBufferDestroyed(id);
+  }
   virtual void OnBufferReady(const VideoCaptureControllerID& id,
                              int buffer_id,
-                             base::Time timestamp) OVERRIDE {
+                             base::Time timestamp,
+                             const media::VideoCaptureFormat& format) OVERRIDE {
     DoBufferReady(id);
     base::MessageLoop::current()->PostTask(FROM_HERE,
         base::Bind(&VideoCaptureController::ReturnBuffer,
                    base::Unretained(controller_), id, this, buffer_id));
   }
-  virtual void OnFrameInfo(
-      const VideoCaptureControllerID& id,
-      const media::VideoCaptureCapability& format) OVERRIDE {
-    DoFrameInfo(id);
-  }
   virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {
     DoEnded(id);
     // OnEnded() must respond by (eventually) unregistering the client.
@@ -114,9 +114,8 @@
 TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
   media::VideoCaptureParams session_100;
   session_100.session_id = 100;
-  session_100.width = 320;
-  session_100.height = 240;
-  session_100.frame_rate = 30;
+  session_100.requested_format = media::VideoCaptureFormat(
+      320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
 
   media::VideoCaptureParams session_200 = session_100;
   session_200.session_id = 200;
@@ -209,9 +208,8 @@
 TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
   media::VideoCaptureParams session_100;
   session_100.session_id = 100;
-  session_100.width = 320;
-  session_100.height = 240;
-  session_100.frame_rate = 30;
+  session_100.requested_format = media::VideoCaptureFormat(
+      320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
 
   media::VideoCaptureParams session_200 = session_100;
   session_200.session_id = 200;
@@ -222,10 +220,12 @@
   media::VideoCaptureParams session_1 = session_100;
   session_1.session_id = 1;
 
+  gfx::Size capture_resolution(444, 200);
+
   // The device format needn't match the VideoCaptureParams (the camera can do
   // what it wants). Pick something random to use for OnFrameInfo.
   media::VideoCaptureCapability device_format(
-      10, 10, 25, media::PIXEL_FORMAT_RGB24, 10, false,
+      10, 10, 25, media::PIXEL_FORMAT_RGB24,
       media::ConstantResolutionVideoCaptureDevice);
 
   const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1);
@@ -238,83 +238,64 @@
                          base::kNullProcessHandle, session_100);
   controller_->AddClient(client_b_route_1, client_b_.get(),
                          base::kNullProcessHandle, session_300);
-  ASSERT_EQ(2, controller_->GetClientCount());
-
-  // The OnFrameInfo() event from the device, when processed by the controller,
-  // should generate client OnFrameInfo() and OnBufferCreated() events.
-  {
-    InSequence s;
-    EXPECT_CALL(*client_a_, DoFrameInfo(client_a_route_1)).Times(1);
-    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(kPoolSize);
-  }
-  {
-    InSequence s;
-    EXPECT_CALL(*client_b_, DoFrameInfo(client_b_route_1)).Times(1);
-    EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(kPoolSize);
-  }
-  device_->OnFrameInfo(device_format);
-  base::RunLoop().RunUntilIdle();
-  Mock::VerifyAndClearExpectations(client_a_.get());
-  Mock::VerifyAndClearExpectations(client_b_.get());
-
-  // When a third clients is subsequently added, the frame info and buffers
-  // should immediately be shared to the new clients.
-  {
-    InSequence s;
-    EXPECT_CALL(*client_a_, DoFrameInfo(client_a_route_2)).Times(1);
-    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(kPoolSize);
-  }
   controller_->AddClient(client_a_route_2, client_a_.get(),
                          base::kNullProcessHandle, session_200);
-  Mock::VerifyAndClearExpectations(client_a_.get());
+  ASSERT_EQ(3, controller_->GetClientCount());
 
-  // Now, simulate an incoming captured frame from the capture device.
+  // Now, simulate an incoming captured frame from the capture device. As a side
+  // effect this will cause the first buffer to be shared with clients.
   uint8 frame_no = 1;
   scoped_refptr<media::VideoFrame> frame;
-  frame = device_->ReserveOutputBuffer();
+  frame = device_->ReserveOutputBuffer(capture_resolution);
   ASSERT_TRUE(frame);
   media::FillYUV(frame, frame_no++, 0x22, 0x44);
-  device_->OnIncomingCapturedVideoFrame(frame, base::Time());
-  frame = NULL;
-
-  // The buffer should be delivered to the clients in any order.
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
-  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
-  base::RunLoop().RunUntilIdle();
-  Mock::VerifyAndClearExpectations(client_a_.get());
-  Mock::VerifyAndClearExpectations(client_b_.get());
-
-  // Second frame. In this case pretend that the VideoFrame pointer is held
-  // by the device for a long delay. This shouldn't affect anything.
-  frame = device_->ReserveOutputBuffer();
-  ASSERT_TRUE(frame);
-  media::FillYUV(frame, frame_no++, 0x22, 0x44);
-  device_->OnIncomingCapturedVideoFrame(frame, base::Time());
-
-  // The buffer should be delivered to the clients in any order.
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
-  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
-  base::RunLoop().RunUntilIdle();
-  Mock::VerifyAndClearExpectations(client_a_.get());
-  Mock::VerifyAndClearExpectations(client_b_.get());
-  frame = NULL;
-
-  // Add a fourth client now that some frames have come through. It should get
-  // the buffer info, but it won't get any frames until new ones are captured.
   {
     InSequence s;
-    EXPECT_CALL(*client_b_, DoFrameInfo(client_b_route_2)).Times(1);
-    EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
+    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
+    EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
   }
+  {
+    InSequence s;
+    EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
+    EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
+  }
+  {
+    InSequence s;
+    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
+    EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
+  }
+  device_->OnIncomingCapturedVideoFrame(frame, base::Time());
+  frame = NULL;
+
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(client_a_.get());
+  Mock::VerifyAndClearExpectations(client_b_.get());
+
+  // Second frame which ought to use the same shared memory buffer. In this case
+  // pretend that the VideoFrame pointer is held by the device for a long delay.
+  // This shouldn't affect anything.
+  frame = device_->ReserveOutputBuffer(capture_resolution);
+  ASSERT_TRUE(frame);
+  media::FillYUV(frame, frame_no++, 0x22, 0x44);
+  device_->OnIncomingCapturedVideoFrame(frame, base::Time());
+
+  // The buffer should be delivered to the clients in any order.
+  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
+  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
+  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(client_a_.get());
+  Mock::VerifyAndClearExpectations(client_b_.get());
+  frame = NULL;
+
+  // Add a fourth client now that some frames have come through.
   controller_->AddClient(client_b_route_2, client_b_.get(),
                          base::kNullProcessHandle, session_1);
   Mock::VerifyAndClearExpectations(client_b_.get());
 
   // Third, fourth, and fifth frames. Pretend they all arrive at the same time.
   for (int i = 0; i < kPoolSize; i++) {
-    frame = device_->ReserveOutputBuffer();
+    frame = device_->ReserveOutputBuffer(capture_resolution);
     ASSERT_TRUE(frame);
     ASSERT_EQ(media::VideoFrame::I420, frame->format());
     media::FillYUV(frame, frame_no++, 0x22, 0x44);
@@ -322,11 +303,20 @@
 
   }
   // ReserveOutputBuffer ought to fail now, because the pool is depleted.
-  ASSERT_FALSE(device_->ReserveOutputBuffer());
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize);
-  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize);
-  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize);
+  ASSERT_FALSE(device_->ReserveOutputBuffer(capture_resolution));
+
+  // The new client needs to be told of 3 buffers; the old clients only 2.
+  EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
   EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(kPoolSize);
+  EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
+      .Times(kPoolSize - 1);
+  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize);
+  EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
+      .Times(kPoolSize - 1);
+  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize);
+  EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
+      .Times(kPoolSize - 1);
+  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize);
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClearExpectations(client_a_.get());
   Mock::VerifyAndClearExpectations(client_b_.get());
@@ -338,11 +328,11 @@
   EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
   controller_->StopSession(300);
   // Queue up another frame.
-  frame = device_->ReserveOutputBuffer();
+  frame = device_->ReserveOutputBuffer(capture_resolution);
   ASSERT_TRUE(frame);
   media::FillYUV(frame, frame_no++, 0x22, 0x44);
   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
-  frame = device_->ReserveOutputBuffer();
+  frame = device_->ReserveOutputBuffer(capture_resolution);
   {
     // Kill A2 via session close (posts a task to disconnect, but A2 must not
     // be sent either of these two frames)..
@@ -365,9 +355,8 @@
 TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
   media::VideoCaptureParams session_100;
   session_100.session_id = 100;
-  session_100.width = 320;
-  session_100.height = 240;
-  session_100.frame_rate = 30;
+  session_100.requested_format = media::VideoCaptureFormat(
+    320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
 
   media::VideoCaptureParams session_200 = session_100;
   session_200.session_id = 200;
@@ -392,7 +381,7 @@
 
   // OnFrameInfo from the VCD should become a no-op after the error occurs.
   media::VideoCaptureCapability device_format(
-      10, 10, 25, media::PIXEL_FORMAT_ARGB, 10, false,
+      10, 10, 25, media::PIXEL_FORMAT_ARGB,
       media::ConstantResolutionVideoCaptureDevice);
 
   device_->OnFrameInfo(device_format);
@@ -404,9 +393,8 @@
 TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
   media::VideoCaptureParams session_100;
   session_100.session_id = 100;
-  session_100.width = 320;
-  session_100.height = 240;
-  session_100.frame_rate = 30;
+  session_100.requested_format = media::VideoCaptureFormat(
+      320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
 
   media::VideoCaptureParams session_200 = session_100;
   session_200.session_id = 200;
@@ -418,19 +406,17 @@
                          base::kNullProcessHandle, session_100);
   // OnFrameInfo from the VCD should become a no-op after the error occurs.
   media::VideoCaptureCapability device_format(
-      10, 10, 25, media::PIXEL_FORMAT_ARGB, 10, false,
+      10, 10, 25, media::PIXEL_FORMAT_ARGB,
       media::ConstantResolutionVideoCaptureDevice);
 
-  // Start the device and get as far as exchanging buffers with the subprocess.
-  // Then, signal an error and deliver the frame. The error should be propagated
-  // to clients; the frame should not be.
-  device_->OnFrameInfo(device_format);
-  EXPECT_CALL(*client_a_, DoFrameInfo(route_id)).Times(1);
-  EXPECT_CALL(*client_a_, DoBufferCreated(route_id)).Times(kPoolSize);
+  // Start the device. Then, before the first frame, signal an error and deliver
+  // the frame. The error should be propagated to clients; the frame should not
+  // be.
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClearExpectations(client_a_.get());
 
-  scoped_refptr<media::VideoFrame> frame = device_->ReserveOutputBuffer();
+  scoped_refptr<media::VideoFrame> frame =
+      device_->ReserveOutputBuffer(gfx::Size(320, 240));
   ASSERT_TRUE(frame);
 
   device_->OnError();
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc
index 1c22199..eb51246 100644
--- a/content/browser/renderer_host/media/video_capture_host.cc
+++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -57,35 +57,25 @@
                  this, controller_id, handle, length, buffer_id));
 }
 
+void VideoCaptureHost::OnBufferDestroyed(
+    const VideoCaptureControllerID& controller_id,
+    int buffer_id) {
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&VideoCaptureHost::DoSendFreeBufferOnIOThread,
+                 this, controller_id, buffer_id));
+}
+
 void VideoCaptureHost::OnBufferReady(
     const VideoCaptureControllerID& controller_id,
     int buffer_id,
-    base::Time timestamp) {
+    base::Time timestamp,
+    const media::VideoCaptureFormat& frame_format) {
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
-                 this, controller_id, buffer_id, timestamp));
-}
-
-void VideoCaptureHost::OnFrameInfo(
-    const VideoCaptureControllerID& controller_id,
-    const media::VideoCaptureCapability& format) {
-  BrowserThread::PostTask(
-      BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&VideoCaptureHost::DoSendFrameInfoOnIOThread,
-                 this, controller_id, format));
-}
-
-void VideoCaptureHost::OnFrameInfoChanged(
-    const VideoCaptureControllerID& controller_id,
-    int width,
-    int height,
-    int frame_rate) {
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&VideoCaptureHost::DoSendFrameInfoChangedOnIOThread,
-                 this, controller_id, width, height, frame_rate));
+                 this, controller_id, buffer_id, timestamp,
+                 frame_format));
 }
 
 void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
@@ -109,16 +99,28 @@
                                      length, buffer_id));
 }
 
+void VideoCaptureHost::DoSendFreeBufferOnIOThread(
+    const VideoCaptureControllerID& controller_id,
+    int buffer_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  if (entries_.find(controller_id) == entries_.end())
+    return;
+
+  Send(new VideoCaptureMsg_FreeBuffer(controller_id.device_id, buffer_id));
+}
+
 void VideoCaptureHost::DoSendFilledBufferOnIOThread(
     const VideoCaptureControllerID& controller_id,
-    int buffer_id, base::Time timestamp) {
+    int buffer_id, base::Time timestamp,
+    const media::VideoCaptureFormat& format) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   if (entries_.find(controller_id) == entries_.end())
     return;
 
   Send(new VideoCaptureMsg_BufferReady(controller_id.device_id, buffer_id,
-                                       timestamp));
+                                       timestamp, format));
 }
 
 void VideoCaptureHost::DoHandleErrorOnIOThread(
@@ -145,41 +147,6 @@
   DeleteVideoCaptureControllerOnIOThread(controller_id);
 }
 
-void VideoCaptureHost::DoSendFrameInfoOnIOThread(
-    const VideoCaptureControllerID& controller_id,
-    const media::VideoCaptureCapability& format) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (entries_.find(controller_id) == entries_.end())
-    return;
-
-  media::VideoCaptureParams params;
-  params.width = format.width;
-  params.height = format.height;
-  params.frame_rate = format.frame_rate;
-  params.frame_size_type = format.frame_size_type;
-  Send(new VideoCaptureMsg_DeviceInfo(controller_id.device_id, params));
-  Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
-                                        VIDEO_CAPTURE_STATE_STARTED));
-}
-
-void VideoCaptureHost::DoSendFrameInfoChangedOnIOThread(
-    const VideoCaptureControllerID& controller_id,
-    int width,
-    int height,
-    int frame_rate) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (entries_.find(controller_id) == entries_.end())
-    return;
-
-  media::VideoCaptureParams params;
-  params.width = width;
-  params.height = height;
-  params.frame_rate = frame_rate;
-  Send(new VideoCaptureMsg_DeviceInfoChanged(controller_id.device_id, params));
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // IPC Messages handler.
 bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message,
@@ -200,12 +167,13 @@
                                       const media::VideoCaptureParams& params) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DVLOG(1) << "VideoCaptureHost::OnStartCapture, device_id " << device_id
-           << ", (" << params.width << ", " << params.height << ", "
-           << params.frame_rate << ", " << params.session_id
-           << ", variable resolution device:"
-           << ((params.frame_size_type ==
+           << ", (" << params.requested_format.width
+           << ", " << params.requested_format.height
+           << ", " << params.requested_format.frame_rate
+           << ", " << params.session_id << ", variable resolution device:"
+           << ((params.requested_format.frame_size_type ==
                media::VariableResolutionVideoCaptureDevice) ? "yes" : "no")
-            << ")";
+           << ")";
   VideoCaptureControllerID controller_id(device_id);
   DCHECK(entries_.find(controller_id) == entries_.end());
 
@@ -225,7 +193,7 @@
 }
 
 void VideoCaptureHost::DoControllerAddedOnIOThread(
-    int device_id, const media::VideoCaptureParams params,
+    int device_id, const media::VideoCaptureParams& params,
     const base::WeakPtr<VideoCaptureController>& controller) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   VideoCaptureControllerID controller_id(device_id);
diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h
index 6ce3956..4648466 100644
--- a/content/browser/renderer_host/media/video_capture_host.h
+++ b/content/browser/renderer_host/media/video_capture_host.h
@@ -5,33 +5,48 @@
 // VideoCaptureHost serves video capture related messages from
 // VideoCaptureMessageFilter which lives inside the render process.
 //
-// This class is owned by BrowserRenderProcessHost, and instantiated on UI
+// This class is owned by RenderProcessHostImpl, and instantiated on UI
 // thread, but all other operations and method calls happen on IO thread.
 //
 // Here's an example of a typical IPC dialog for video capture:
 //
-//   Renderer                          VideoCaptureHost
-//      |                                     |
-//      |  VideoCaptureHostMsg_Start >        |
-//      |  < VideoCaptureMsg_DeviceInfo       |
-//      |                                     |
-//      | < VideoCaptureMsg_StateChanged      |
-//      |        (kStarted)                   |
-//      | < VideoCaptureMsg_BufferReady       |
-//      |             ...                     |
-//      | < VideoCaptureMsg_BufferReady       |
-//      |             ...                     |
-//      | VideoCaptureHostMsg_BufferReady >   |
-//      | VideoCaptureHostMsg_BufferReady >   |
-//      |                                     |
-//      |             ...                     |
-//      |                                     |
-//      | < VideoCaptureMsg_BufferReady       |
-//      |  VideoCaptureHostMsg_Stop >         |
-//      | VideoCaptureHostMsg_BufferReady >   |
-//      | < VideoCaptureMsg_StateChanged      |
-//      |         (kStopped)                  |
-//      v                                     v
+//   Renderer                             VideoCaptureHost
+//      |                                        |
+//      |  VideoCaptureHostMsg_Start >           |
+//      | < VideoCaptureMsg_StateChanged         |
+//      |        (VIDEO_CAPTURE_STATE_STARTED)   |
+//      | < VideoCaptureMsg_NewBuffer(1)         |
+//      | < VideoCaptureMsg_NewBuffer(2)         |
+//      | < VideoCaptureMsg_NewBuffer(3)         |
+//      |                                        |
+//      | < VideoCaptureMsg_BufferReady(1)       |
+//      | < VideoCaptureMsg_BufferReady(2)       |
+//      | VideoCaptureHostMsg_BufferReady(1) >   |
+//      | < VideoCaptureMsg_BufferReady(3)       |
+//      | VideoCaptureHostMsg_BufferReady(2) >   |
+//      | < VideoCaptureMsg_BufferReady(1)       |
+//      | VideoCaptureHostMsg_BufferReady(3) >   |
+//      | < VideoCaptureMsg_BufferReady(2)       |
+//      | VideoCaptureHostMsg_BufferReady(1) >   |
+//      |             ...                        |
+//      | < VideoCaptureMsg_BufferReady(3)       |
+//      |                                        |
+//      |             ... (resolution change)    |
+//      | < VideoCaptureMsg_FreeBuffer(1)        |  Buffers are re-allocated
+//      | < VideoCaptureMsg_NewBuffer(4)         |  at a larger size, as
+//      | < VideoCaptureMsg_BufferReady(4)       |  needed.
+//      | VideoCaptureHostMsg_BufferReady(2) >   |
+//      | < VideoCaptureMsg_FreeBuffer(2)        |
+//      | < VideoCaptureMsg_NewBuffer(5)         |
+//      | < VideoCaptureMsg_BufferReady(5)       |
+//      |             ...                        |
+//      |                                        |
+//      | < VideoCaptureMsg_BufferReady          |
+//      | VideoCaptureHostMsg_Stop >             |
+//      | VideoCaptureHostMsg_BufferReady >      |
+//      | < VideoCaptureMsg_StateChanged         |
+//      |         (VIDEO_CAPTURE_STATE_STOPPED)  |
+//      v                                        v
 
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_HOST_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_HOST_H_
@@ -69,17 +84,15 @@
   virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE;
   virtual void OnBufferCreated(const VideoCaptureControllerID& id,
                                base::SharedMemoryHandle handle,
-                               int length, int buffer_id) OVERRIDE;
-  virtual void OnBufferReady(const VideoCaptureControllerID& id,
-                             int buffer_id,
-                             base::Time timestamp) OVERRIDE;
-  virtual void OnFrameInfo(
+                               int length,
+                               int buffer_id) OVERRIDE;
+  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
+                                 int buffer_id) OVERRIDE;
+  virtual void OnBufferReady(
       const VideoCaptureControllerID& id,
-      const media::VideoCaptureCapability& format) OVERRIDE;
-  virtual void OnFrameInfoChanged(const VideoCaptureControllerID& id,
-                                  int width,
-                                  int height,
-                                  int frame_per_second) OVERRIDE;
+      int buffer_id,
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format) OVERRIDE;
   virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE;
 
  private:
@@ -100,7 +113,7 @@
       int device_id, const media::VideoCaptureParams& params,
       const base::WeakPtr<VideoCaptureController>& controller);
   void DoControllerAddedOnIOThread(
-      int device_id, const media::VideoCaptureParams params,
+      int device_id, const media::VideoCaptureParams& params,
       const base::WeakPtr<VideoCaptureController>& controller);
 
   // IPC message: Stop capture on device referenced by |device_id|.
@@ -120,24 +133,16 @@
       int length,
       int buffer_id);
 
+  void DoSendFreeBufferOnIOThread(
+      const VideoCaptureControllerID& controller_id,
+      int buffer_id);
+
   // Send a filled buffer to the VideoCaptureMessageFilter.
   void DoSendFilledBufferOnIOThread(
       const VideoCaptureControllerID& controller_id,
       int buffer_id,
-      base::Time timestamp);
-
-  // Send information about the capture parameters (resolution, frame rate etc)
-  // to the VideoCaptureMessageFilter.
-  void DoSendFrameInfoOnIOThread(const VideoCaptureControllerID& controller_id,
-                                 const media::VideoCaptureCapability& format);
-
-  // Send newly changed information about frame resolution and frame rate
-  // to the VideoCaptureMessageFilter.
-  void DoSendFrameInfoChangedOnIOThread(
-      const VideoCaptureControllerID& controller_id,
-      int width,
-      int height,
-      int frame_per_second);
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format);
 
   // Handle error coming from VideoCaptureDevice.
   void DoHandleErrorOnIOThread(const VideoCaptureControllerID& controller_id);
diff --git a/content/browser/renderer_host/media/video_capture_host_unittest.cc b/content/browser/renderer_host/media/video_capture_host_unittest.cc
index 0623333..f57cfdb 100644
--- a/content/browser/renderer_host/media/video_capture_host_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_host_unittest.cc
@@ -106,17 +106,19 @@
   MOCK_METHOD4(OnNewBufferCreated,
                void(int device_id, base::SharedMemoryHandle handle,
                     int length, int buffer_id));
-  MOCK_METHOD3(OnBufferFilled,
-               void(int device_id, int buffer_id, base::Time timestamp));
+  MOCK_METHOD2(OnBufferFreed,
+               void(int device_id, int buffer_id));
+  MOCK_METHOD4(OnBufferFilled,
+               void(int device_id, int buffer_id, base::Time timestamp,
+                    const media::VideoCaptureFormat& format));
   MOCK_METHOD2(OnStateChanged, void(int device_id, VideoCaptureState state));
-  MOCK_METHOD1(OnDeviceInfo, void(int device_id));
 
   // Use class DumpVideo to write I420 video to file.
   void SetDumpVideo(bool enable) {
     dump_video_ = enable;
   }
 
-  void SetReturnReceviedDibs(bool enable) {
+  void SetReturnReceivedDibs(bool enable) {
     return_buffers_ = enable;
   }
 
@@ -157,9 +159,9 @@
     bool handled = true;
     IPC_BEGIN_MESSAGE_MAP(MockVideoCaptureHost, *message)
       IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnNewBufferCreatedDispatch)
+      IPC_MESSAGE_HANDLER(VideoCaptureMsg_FreeBuffer, OnBufferFreedDispatch)
       IPC_MESSAGE_HANDLER(VideoCaptureMsg_BufferReady, OnBufferFilledDispatch)
       IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnStateChangedDispatch)
-      IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfoDispatch)
       IPC_MESSAGE_UNHANDLED(handled = false)
     IPC_END_MESSAGE_MAP()
     EXPECT_TRUE(handled);
@@ -179,15 +181,35 @@
     filled_dib_[buffer_id] = dib;
   }
 
-  void OnBufferFilledDispatch(int device_id, int buffer_id,
-                              base::Time timestamp) {
+  void OnBufferFreedDispatch(int device_id, int buffer_id) {
+    OnBufferFreed(device_id, buffer_id);
+
+    std::map<int, base::SharedMemory*>::iterator it =
+        filled_dib_.find(buffer_id);
+    ASSERT_TRUE(it != filled_dib_.end());
+    delete it->second;
+    filled_dib_.erase(it);
+  }
+
+  void OnBufferFilledDispatch(int device_id,
+                              int buffer_id,
+                              base::Time timestamp,
+                              const media::VideoCaptureFormat& frame_format) {
+    base::SharedMemory* dib = filled_dib_[buffer_id];
+    ASSERT_TRUE(dib != NULL);
     if (dump_video_) {
-      base::SharedMemory* dib = filled_dib_[buffer_id];
-      ASSERT_TRUE(dib != NULL);
+      if (!format_.IsValid()) {
+        dumper_.StartDump(frame_format.width, frame_format.height);
+        format_ = frame_format;
+      }
+      ASSERT_EQ(format_.width, frame_format.width)
+          << "Dump format does not handle variable resolution.";
+      ASSERT_EQ(format_.height, frame_format.height)
+          << "Dump format does not handle variable resolution.";;
       dumper_.NewVideoFrame(dib->memory());
     }
 
-    OnBufferFilled(device_id, buffer_id, timestamp);
+    OnBufferFilled(device_id, buffer_id, timestamp, frame_format);
     if (return_buffers_) {
       VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id);
     }
@@ -197,17 +219,10 @@
     OnStateChanged(device_id, state);
   }
 
-  void OnDeviceInfoDispatch(int device_id,
-                            media::VideoCaptureParams params) {
-    if (dump_video_) {
-      dumper_.StartDump(params.width, params.height);
-    }
-    OnDeviceInfo(device_id);
-  }
-
   std::map<int, base::SharedMemory*> filled_dib_;
   bool return_buffers_;
   bool dump_video_;
+  media::VideoCaptureFormat format_;
   DumpVideo dumper_;
 };
 
@@ -322,27 +337,17 @@
 
  protected:
   void StartCapture() {
-    InSequence s;
-    // 1. First - get info about the new resolution
-    EXPECT_CALL(*host_, OnDeviceInfo(kDeviceId));
-
-    // 2. Change state to started
-    EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STARTED));
-
-    // 3. Newly created buffers will arrive.
     EXPECT_CALL(*host_, OnNewBufferCreated(kDeviceId, _, _, _))
         .Times(AnyNumber()).WillRepeatedly(Return());
 
-    // 4. First filled buffer will arrive.
     base::RunLoop run_loop;
-    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _))
+    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
         .Times(AnyNumber()).WillOnce(ExitMessageLoop(
             message_loop_, run_loop.QuitClosure()));
 
     media::VideoCaptureParams params;
-    params.width = 352;
-    params.height = 288;
-    params.frame_rate = 30;
+    params.requested_format = media::VideoCaptureFormat(
+        352, 288, 30, media::ConstantResolutionVideoCaptureDevice);
     params.session_id = opened_session_id_;
     host_->OnStartCapture(kDeviceId, params);
     run_loop.Run();
@@ -355,9 +360,8 @@
     base::RunLoop run_loop;
     EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED));
     media::VideoCaptureParams params;
-    params.width = 352;
-    params.height = 288;
-    params.frame_rate = 30;
+    params.requested_format = media::VideoCaptureFormat(
+        352, 288, 30, media::ConstantResolutionVideoCaptureDevice);
     params.session_id = opened_session_id_;
     host_->OnStartCapture(kDeviceId, params);
     host_->OnStopCapture(kDeviceId);
@@ -367,22 +371,17 @@
 #ifdef DUMP_VIDEO
   void CaptureAndDumpVideo(int width, int height, int frame_rate) {
     InSequence s;
-    // 1. First - get info about the new resolution
-    EXPECT_CALL(*host_, OnDeviceInfo(kDeviceId));
+    EXPECT_CALL(*host_.get(), OnNewBufferCreated(kDeviceId, _, _, _))
+        .Times(AnyNumber()).WillRepeatedly(Return());
 
-    // 2. Change state to started
-    EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STARTED));
-
-    // 3. First filled buffer will arrive.
     base::RunLoop run_loop;
-    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _))
+    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
         .Times(AnyNumber())
         .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
 
     media::VideoCaptureParams params;
-    params.width = width;
-    params.height = height;
-    params.frame_rate = frame_rate;
+    params.requested_format = media::VideoCaptureFormat(
+        width, height, frame_rate, media::ConstantResolutionVideoCaptureDevice);
     params.session_id = opened_session_id_;
     host_->SetDumpVideo(true);
     host_->OnStartCapture(kDeviceId, params);
@@ -396,19 +395,19 @@
         .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
 
     host_->OnStopCapture(kDeviceId);
-    host_->SetReturnReceviedDibs(true);
+    host_->SetReturnReceivedDibs(true);
     host_->ReturnReceivedDibs(kDeviceId);
 
     run_loop.Run();
 
-    host_->SetReturnReceviedDibs(false);
+    host_->SetReturnReceivedDibs(false);
     // Expect the VideoCaptureDevice has been stopped
     EXPECT_EQ(0u, host_->entries_.size());
   }
 
   void NotifyPacketReady() {
     base::RunLoop run_loop;
-    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _))
+    EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
         .Times(AnyNumber()).WillOnce(ExitMessageLoop(
             message_loop_, run_loop.QuitClosure()))
         .RetiresOnSaturation();
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 9d4d3d5..a1fcad7 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -183,20 +183,20 @@
 }
 
 void VideoCaptureManager::StartCaptureForClient(
-    const media::VideoCaptureParams& capture_params,
+    const media::VideoCaptureParams& params,
     base::ProcessHandle client_render_process,
     VideoCaptureControllerID client_id,
     VideoCaptureControllerEventHandler* client_handler,
     const DoneCB& done_cb) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, ("
-         << capture_params.width
-         << ", " << capture_params.height
-         << ", " << capture_params.frame_rate
-         << ", #" << capture_params.session_id
+         << params.requested_format.width
+         << ", " << params.requested_format.height
+         << ", " << params.requested_format.frame_rate
+         << ", #" << params.session_id
          << ")";
 
-  DeviceEntry* entry = GetOrCreateDeviceEntry(capture_params.session_id);
+  DeviceEntry* entry = GetOrCreateDeviceEntry(params.session_id);
   if (!entry) {
     done_cb.Run(base::WeakPtr<VideoCaptureController>());
     return;
@@ -210,11 +210,11 @@
              << entry->stream_type << ", id = " << entry->id << ")";
 
     media::VideoCaptureCapability params_as_capability;
-    params_as_capability.width = capture_params.width;
-    params_as_capability.height = capture_params.height;
-    params_as_capability.frame_rate = capture_params.frame_rate;
-    params_as_capability.session_id = capture_params.session_id;
-    params_as_capability.frame_size_type = capture_params.frame_size_type;
+    params_as_capability.width = params.requested_format.width;
+    params_as_capability.height = params.requested_format.height;
+    params_as_capability.frame_rate = params.requested_format.frame_rate;
+    params_as_capability.frame_size_type =
+        params.requested_format.frame_size_type;
 
     device_loop_->PostTask(FROM_HERE, base::Bind(
         &VideoCaptureManager::DoStartDeviceOnDeviceThread, this,
@@ -226,7 +226,7 @@
   entry->video_capture_controller->AddClient(client_id,
                                              client_handler,
                                              client_render_process,
-                                             capture_params);
+                                             params);
 }
 
 void VideoCaptureManager::StopCaptureForClient(
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index a8980b5..a986e0b 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -49,18 +49,15 @@
 
   virtual void OnBufferCreated(const VideoCaptureControllerID& id,
                                base::SharedMemoryHandle handle,
-                               int length, int buffer_id) OVERRIDE {};
-  virtual void OnBufferReady(const VideoCaptureControllerID& id,
-                             int buffer_id,
-                             base::Time timestamp) OVERRIDE {};
-  virtual void OnFrameInfo(
+                               int length, int buffer_id) OVERRIDE {}
+  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
+                               int buffer_id) OVERRIDE {}
+  virtual void OnBufferReady(
       const VideoCaptureControllerID& id,
-      const media::VideoCaptureCapability& format) OVERRIDE {};
-  virtual void OnFrameInfoChanged(const VideoCaptureControllerID& id,
-                                  int width,
-                                  int height,
-                                  int frame_rate) OVERRIDE {};
-  virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {};
+      int buffer_id,
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format) OVERRIDE {}
+  virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {}
 
   void OnGotControllerCallback(VideoCaptureControllerID) {}
 };
@@ -103,9 +100,8 @@
   VideoCaptureControllerID StartClient(int session_id, bool expect_success) {
     media::VideoCaptureParams params;
     params.session_id = session_id;
-    params.width = 320;
-    params.height = 240;
-    params.frame_rate = 30;
+    params.requested_format = media::VideoCaptureFormat(
+        320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
 
     VideoCaptureControllerID client_id(next_client_id_++);
     base::RunLoop run_loop;
diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device.cc b/content/browser/renderer_host/media/web_contents_video_capture_device.cc
index 7aca8df..d8a7ac7 100644
--- a/content/browser/renderer_host/media/web_contents_video_capture_device.cc
+++ b/content/browser/renderer_host/media/web_contents_video_capture_device.cc
@@ -139,7 +139,8 @@
     : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> {
  public:
   ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client,
-                          scoped_ptr<VideoCaptureOracle> oracle);
+                          scoped_ptr<VideoCaptureOracle> oracle,
+                          const gfx::Size& capture_size);
 
   bool ObserveEventAndDecideCapture(
       VideoCaptureOracle::Event event,
@@ -174,6 +175,9 @@
 
   // Makes the decision to capture a frame.
   const scoped_ptr<VideoCaptureOracle> oracle_;
+
+  // The resolution at which we're capturing.
+  const gfx::Size capture_size_;
 };
 
 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
@@ -396,8 +400,12 @@
 
 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
     scoped_ptr<media::VideoCaptureDevice::Client> client,
-    scoped_ptr<VideoCaptureOracle> oracle)
-    : client_(client.Pass()), oracle_(oracle.Pass()) {}
+    scoped_ptr<VideoCaptureOracle> oracle,
+    const gfx::Size& capture_size)
+    : client_(client.Pass()),
+      oracle_(oracle.Pass()),
+      capture_size_(capture_size) {
+}
 
 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
     VideoCaptureOracle::Event event,
@@ -410,7 +418,7 @@
     return false;  // Capture is stopped.
 
   scoped_refptr<media::VideoFrame> output_buffer =
-      client_->ReserveOutputBuffer();
+      client_->ReserveOutputBuffer(capture_size_);
   const bool should_capture =
       oracle_->ObserveEventAndDecideCapture(event, event_time);
   const bool content_is_dirty =
@@ -642,7 +650,7 @@
       method = skia::ImageOperations::RESIZE_BOX;
     }
 
-    TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", output.get(), "Scale");
+    TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "Scale");
     scaled_bitmap = skia::ImageOperations::Resize(input, method,
                                                   region_in_frame.width(),
                                                   region_in_frame.height());
@@ -650,7 +658,7 @@
     scaled_bitmap = input;
   }
 
-  TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", output.get(), "YUV");
+  TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "YUV");
   {
     SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
 
@@ -864,7 +872,8 @@
   base::Time now = base::Time::Now();
   if (success) {
     UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
-    TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", target.get(), "Render");
+    TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
+                                 "Render");
     render_task_runner_->PostTask(FROM_HERE, base::Bind(
         &RenderVideoFrame, bitmap, target,
         base::Bind(deliver_frame_cb, start_time)));
@@ -1028,27 +1037,21 @@
     return;
   }
 
-  // Initialize capture settings which will be consistent for the
-  // duration of the capture.
+  // Need to call OnFrameInfo just to set the frame rate.
+  // TODO(nick): http://crbug.com/309907 The other parameters of this struct are
+  // ignored. Come up with a better way to communicate the frame rate.
   media::VideoCaptureCapability settings;
-
-  settings.width = width;
-  settings.height = height;
   settings.frame_rate = frame_rate;
-  // Note: the value of |settings.color| doesn't matter if we use only the
-  // VideoFrame based methods on |client|.
-  settings.color = media::PIXEL_FORMAT_I420;
-  settings.expected_capture_delay = 0;
-  settings.interlaced = false;
+  client->OnFrameInfo(settings);
 
   base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds(
-      1000000.0 / settings.frame_rate + 0.5);
+      1000000.0 / frame_rate + 0.5);
 
-  client->OnFrameInfo(settings);
   scoped_ptr<VideoCaptureOracle> oracle(
       new VideoCaptureOracle(capture_period,
                              kAcceleratedSubscriberIsSupported));
-  oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), oracle.Pass());
+  oracle_proxy_ = new ThreadSafeCaptureOracle(
+      client.Pass(), oracle.Pass(), gfx::Size(width, height));
 
   // Allocates the CaptureMachine. The CaptureMachine will be tracking render
   // view swapping over its lifetime, and we don't want to lose our reference to
diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
index d56fb3c..accac84 100644
--- a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
@@ -311,18 +311,14 @@
              const base::Closure& error_callback)
       : color_callback_(color_callback),
         error_callback_(error_callback) {
-    buffer_pool_ = new VideoCaptureBufferPool(
-        media::VideoFrame::AllocationSize(media::VideoFrame::I420,
-                                          gfx::Size(kTestWidth, kTestHeight)),
-        2);
-    EXPECT_TRUE(buffer_pool_->Allocate());
+    buffer_pool_ = new VideoCaptureBufferPool(2);
   }
   virtual ~StubClient() {}
 
-  virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() OVERRIDE {
-    return buffer_pool_->ReserveI420VideoFrame(gfx::Size(kTestWidth,
-                                                         kTestHeight),
-                                               0);
+  virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer(
+      const gfx::Size& size) OVERRIDE {
+    int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;  // Ignored.
+    return buffer_pool_->ReserveI420VideoFrame(size, 0, &buffer_id_to_drop);
   }
 
   virtual void OnIncomingCapturedFrame(
@@ -358,10 +354,7 @@
   }
 
   virtual void OnFrameInfo(const media::VideoCaptureCapability& info) OVERRIDE {
-    EXPECT_EQ(kTestWidth, info.width);
-    EXPECT_EQ(kTestHeight, info.height);
     EXPECT_EQ(kTestFramesPerSecond, info.frame_rate);
-    EXPECT_EQ(media::PIXEL_FORMAT_I420, info.color);
   }
 
  private:
@@ -583,8 +576,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -600,8 +591,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -628,8 +617,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -654,8 +641,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -678,8 +663,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -721,8 +704,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   device()->AllocateAndStart(
       capture_format, client_observer()->PassClient());
@@ -776,8 +757,6 @@
       720,
       -2,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   BrowserThread::PostTask(
       BrowserThread::UI,
@@ -801,8 +780,6 @@
       kTestHeight,
       kTestFramesPerSecond,
       media::PIXEL_FORMAT_I420,
-      0,
-      false,
       media::ConstantResolutionVideoCaptureDevice);
   // 1x1 is too small to process; we intend for this to result in an error.
   source()->SetCopyResultSize(1, 1);
diff --git a/content/browser/renderer_host/overscroll_controller.cc b/content/browser/renderer_host/overscroll_controller.cc
index e65cfcf..069c4f1 100644
--- a/content/browser/renderer_host/overscroll_controller.cc
+++ b/content/browser/renderer_host/overscroll_controller.cc
@@ -4,19 +4,16 @@
 
 #include "content/browser/renderer_host/overscroll_controller.h"
 
+#include "base/logging.h"
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/public/browser/overscroll_configuration.h"
-#include "content/public/browser/render_widget_host_view.h"
 
 using WebKit::WebInputEvent;
 
 namespace content {
 
-OverscrollController::OverscrollController(
-    RenderWidgetHostImpl* render_widget_host)
-    : render_widget_host_(render_widget_host),
-      overscroll_mode_(OVERSCROLL_NONE),
+OverscrollController::OverscrollController()
+    : overscroll_mode_(OVERSCROLL_NONE),
       scroll_state_(STATE_UNKNOWN),
       overscroll_delta_x_(0.f),
       overscroll_delta_y_(0.f),
@@ -145,11 +142,10 @@
       event.type != WebKit::WebInputEvent::GestureFlingStart)
     return false;
 
-  RenderWidgetHostView* view = render_widget_host_->GetView();
-  if (!view->IsShowing())
+  if (!delegate_)
     return false;
 
-  const gfx::Rect& bounds = view->GetViewBounds();
+  gfx::Rect bounds = delegate_->GetVisibleBounds();
   if (bounds.IsEmpty())
     return false;
 
diff --git a/content/browser/renderer_host/overscroll_controller.h b/content/browser/renderer_host/overscroll_controller.h
index a0ebba6..8586c8a 100644
--- a/content/browser/renderer_host/overscroll_controller.h
+++ b/content/browser/renderer_host/overscroll_controller.h
@@ -17,7 +17,6 @@
 
 class MockRenderWidgetHost;
 class OverscrollControllerDelegate;
-class RenderWidgetHostImpl;
 
 // Indicates the direction that the scroll is heading in relative to the screen,
 // with the top being NORTH.
@@ -36,10 +35,7 @@
 // status accordingly.
 class OverscrollController {
  public:
-  // Creates an overscroll controller for the specified RenderWidgetHost.
-  // The RenderWidgetHost owns this overscroll controller.
-  // TODO(jdduke): crbug.com/306194 - Take an OverscrollControllerClient.
-  explicit OverscrollController(RenderWidgetHostImpl* widget_host);
+  OverscrollController();
   virtual ~OverscrollController();
 
   // The result of |DispatchEvent()|, indicating either how the event was
@@ -114,9 +110,6 @@
   // appropriate).
   void SetOverscrollMode(OverscrollMode new_mode);
 
-  // The RenderWidgetHost that owns this overscroll controller.
-  RenderWidgetHostImpl* render_widget_host_;
-
   // The current state of overscroll gesture.
   OverscrollMode overscroll_mode_;
 
diff --git a/content/browser/renderer_host/overscroll_controller_delegate.h b/content/browser/renderer_host/overscroll_controller_delegate.h
index 6d40ed1..59295ce 100644
--- a/content/browser/renderer_host/overscroll_controller_delegate.h
+++ b/content/browser/renderer_host/overscroll_controller_delegate.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
+#include "ui/gfx/rect.h"
 
 namespace content {
 
@@ -18,6 +19,10 @@
   OverscrollControllerDelegate() {}
   virtual ~OverscrollControllerDelegate() {}
 
+  // Get the bounds of the view corresponding to the delegate. Overscroll-ending
+  // events will only be processed if the visible bounds are non-empty.
+  virtual gfx::Rect GetVisibleBounds() const = 0;
+
   // This is called for each update in the overscroll amount.
   virtual void OnOverscrollUpdate(float delta_x, float delta_y) = 0;
 
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc
index 3fa8cb6..e199d94 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -175,7 +175,7 @@
   }
 
   if (!ContainsKey(connected_peers_, to)) {
-    P2PSocketHost::StunMessageType type;
+    P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType();
     bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
     if (!stun || type == STUN_DATA_INDICATION) {
       LOG(ERROR) << "Page tried to send a data packet to " << to.ToString()
@@ -200,9 +200,14 @@
 }
 
 void P2PSocketHostUdp::DoSend(const PendingPacket& packet) {
-  TRACE_EVENT_ASYNC_STEP1("p2p", "Send", packet.id, "UdpAsyncSendTo",
-                          "size", packet.size);
-  if (last_dscp_ != packet.dscp && last_dscp_ != net::DSCP_NO_CHANGE) {
+  TRACE_EVENT_ASYNC_STEP_INTO1("p2p", "Send", packet.id, "UdpAsyncSendTo",
+                               "size", packet.size);
+  // Don't try to set DSCP in following conditions,
+  // 1. If the outgoing packet is set to DSCP_NO_CHANGE
+  // 2. If no change in DSCP value from last packet
+  // 3. If there is any error in setting DSCP on socket.
+  if (packet.dscp != net::DSCP_NO_CHANGE &&
+      last_dscp_ != packet.dscp && last_dscp_ != net::DSCP_NO_CHANGE) {
     int result = socket_->SetDiffServCodePoint(packet.dscp);
     if (result == net::OK) {
       last_dscp_ = packet.dscp;
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
index 8fca534..c3c2c6f 100644
--- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
@@ -25,7 +25,9 @@
   // The plugin name and path shouldn't be needed for external plugins.
   BrowserPpapiHostImpl* browser_ppapi_host =
       new BrowserPpapiHostImpl(sender, permissions, std::string(),
-                               base::FilePath(), profile_directory, true);
+                               base::FilePath(), profile_directory,
+                               false /* in_process */,
+                               true /* external_plugin */);
   browser_ppapi_host->set_plugin_process_handle(plugin_child_process);
 
   scoped_refptr<PepperMessageFilter> pepper_message_filter(
@@ -43,12 +45,14 @@
     const std::string& plugin_name,
     const base::FilePath& plugin_path,
     const base::FilePath& profile_data_directory,
+    bool in_process,
     bool external_plugin)
     : ppapi_host_(new ppapi::host::PpapiHost(sender, permissions)),
       plugin_process_handle_(base::kNullProcessHandle),
       plugin_name_(plugin_name),
       plugin_path_(plugin_path),
       profile_data_directory_(profile_data_directory),
+      in_process_(in_process),
       external_plugin_(external_plugin),
       ssl_context_helper_(new SSLContextHelper()) {
   message_filter_ = new HostMessageFilter(ppapi_host_.get());
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
index 7479e40..5d95342 100644
--- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
@@ -36,6 +36,7 @@
       const std::string& plugin_name,
       const base::FilePath& plugin_path,
       const base::FilePath& profile_data_directory,
+      bool in_process,
       bool external_plugin);
   virtual ~BrowserPpapiHostImpl();
 
@@ -56,6 +57,7 @@
     plugin_process_handle_ = handle;
   }
 
+  bool in_process() const { return in_process_; }
   bool external_plugin() const { return external_plugin_; }
 
   // These two functions are notifications that an instance has been created
@@ -100,6 +102,9 @@
   base::FilePath plugin_path_;
   base::FilePath profile_data_directory_;
 
+  // If true, this refers to a plugin running in the renderer process.
+  bool in_process_;
+
   // If true, this is an external plugin, i.e. created by the embedder using
   // BrowserPpapiHost::CreateExternalPluginProcess.
   bool external_plugin_;
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
index c338a99..ecbcd0e 100644
--- a/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
@@ -16,7 +16,8 @@
                         std::string(),
                         base::FilePath(),
                         base::FilePath(),
-                        false));
+                        false /* in_process */,
+                        false /* external_plugin */));
   ppapi_host_->set_plugin_process_handle(base::GetCurrentProcessHandle());
 }
 
diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
index af3ec67..923ee684 100644
--- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
@@ -23,19 +23,6 @@
 
 namespace {
 
-// TODO(teravest): Move this function to be shared and public in fileapi.
-bool LooksLikeAGuid(const std::string& fsid) {
-  const size_t kExpectedFsIdSize = 32;
-  if (fsid.size() != kExpectedFsIdSize)
-    return false;
-  for (std::string::const_iterator it = fsid.begin(); it != fsid.end(); ++it) {
-    if (('A' <= *it && *it <= 'F') || ('0' <= *it && *it <= '9'))
-      continue;
-    return false;
-  }
-  return true;
-}
-
 scoped_refptr<fileapi::FileSystemContext>
 GetFileSystemContextFromRenderId(int render_process_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -201,7 +188,7 @@
     return PP_ERROR_INPROGRESS;
   called_open_ = true;
   // Do a sanity check.
-  if (!LooksLikeAGuid(fsid))
+  if (!fileapi::ValidateIsolatedFileSystemId(fsid))
     return PP_ERROR_BADARGUMENT;
   const GURL& url =
       browser_ppapi_host_->GetDocumentURLForInstance(pp_instance());
diff --git a/content/browser/renderer_host/pepper/pepper_message_filter.cc b/content/browser/renderer_host/pepper/pepper_message_filter.cc
index 6434729..1394d95 100644
--- a/content/browser/renderer_host/pepper/pepper_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_message_filter.cc
@@ -31,10 +31,8 @@
     const std::vector<char>& der,
     bool* succeeded,
     ppapi::PPB_X509Certificate_Fields* result) {
-  if (der.size() == 0)
-    *succeeded = false;
-  *succeeded =
-      pepper_socket_utils::GetCertificateFields(&der[0], der.size(), result);
+  *succeeded = (der.size() != 0 && pepper_socket_utils::GetCertificateFields(
+      &der[0], der.size(), result));
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
index e4c8aa7..73d9d9c 100644
--- a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
+++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
@@ -29,7 +29,8 @@
                                                   "",
                                                   base::FilePath(),
                                                   base::FilePath(),
-                                                  false));
+                                                  true /* in_process */,
+                                                  false /* external_plugin */));
 }
 
 PepperRendererConnection::~PepperRendererConnection() {
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 039a0bc..f943f39 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -63,6 +63,7 @@
       state_(TCPSocketState::INITIAL),
       end_of_file_reached_(false),
       bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+      address_index_(0),
       socket_(new net::TCPSocket(NULL, net::NetLog::Source())),
       ssl_context_helper_(host->ssl_context_helper()),
       pending_accept_(false) {
@@ -90,6 +91,7 @@
       state_(TCPSocketState::CONNECTED),
       end_of_file_reached_(false),
       bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+      address_index_(0),
       socket_(socket.Pass()),
       ssl_context_helper_(host->ssl_context_helper()),
       pending_accept_(false) {
@@ -549,6 +551,8 @@
   }
 
   state_.SetPendingTransition(TCPSocketState::CONNECT);
+  address_index_ = 0;
+  address_list_.clear();
   net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
   resolver_.reset(new net::SingleRequestHostResolver(
       resource_context->GetHostResolver()));
@@ -585,6 +589,7 @@
   }
 
   // Copy the single IPEndPoint to address_list_.
+  address_index_ = 0;
   address_list_.clear();
   address_list_.push_back(net::IPEndPoint(address, port));
   StartConnect(context);
@@ -661,14 +666,15 @@
     const ppapi::host::ReplyMessageContext& context) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DCHECK(state_.IsPending(TCPSocketState::CONNECT));
+  DCHECK_LT(address_index_, address_list_.size());
 
   int net_result = net::OK;
   if (!socket_->IsValid())
-    net_result = socket_->Open(address_list_[0].GetFamily());
+    net_result = socket_->Open(address_list_[address_index_].GetFamily());
 
   if (net_result == net::OK) {
     net_result = socket_->Connect(
-        address_list_[0],
+        address_list_[address_index_],
         base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
                    base::Unretained(this), context));
   }
@@ -725,17 +731,27 @@
     return;
   } while (false);
 
-  SendConnectError(context, pp_result);
   if (version_ == ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
+    DCHECK_EQ(1u, address_list_.size());
+
+    SendConnectError(context, pp_result);
     state_.CompletePendingTransition(false);
   } else {
-    // In order to maintain backward compatibility, allow further attempts to
-    // connect the socket.
-    state_ = TCPSocketState(TCPSocketState::INITIAL);
     // We have to recreate |socket_| because it doesn't allow a second connect
     // attempt. We won't lose any state such as bound address or set options,
     // because in the private or v1.0 API, connect must be the first operation.
     socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
+
+    if (address_index_ + 1 < address_list_.size()) {
+      DCHECK_EQ(version_, ppapi::TCP_SOCKET_VERSION_PRIVATE);
+      address_index_++;
+      StartConnect(context);
+    } else {
+      SendConnectError(context, pp_result);
+      // In order to maintain backward compatibility, allow further attempts to
+      // connect the socket.
+      state_ = TCPSocketState(TCPSocketState::INITIAL);
+    }
   }
 }
 
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index 7b4c577..fb34b98 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -187,7 +187,14 @@
   PP_NetAddress_Private bind_input_addr_;
 
   scoped_ptr<net::SingleRequestHostResolver> resolver_;
+
+  // |address_list_| may store multiple addresses when
+  // PPB_TCPSocket_Private.Connect() is used, which involves name resolution.
+  // In that case, we will try each address in the list until a connection is
+  // successfully established.
   net::AddressList address_list_;
+  // Where we are in the above list.
+  size_t address_index_;
 
   // Non-null unless an SSL connection is requested.
   scoped_ptr<net::TCPSocket> socket_;
diff --git a/content/browser/renderer_host/pepper/pepper_truetype_font_list_linux.cc b/content/browser/renderer_host/pepper/pepper_truetype_font_list_linux.cc
index 24c3f5d..cd1a5e5 100644
--- a/content/browser/renderer_host/pepper/pepper_truetype_font_list_linux.cc
+++ b/content/browser/renderer_host/pepper/pepper_truetype_font_list_linux.cc
@@ -54,6 +54,7 @@
         desc.charset = PP_TRUETYPEFONTCHARSET_DEFAULT;
 
         fonts_in_family->push_back(desc);
+        ::pango_font_description_free(font_desc);
       }
       g_free(font_faces);
     }
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
deleted file mode 100644
index 0ec640c..0000000
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2013 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/renderer_host/render_frame_host_impl.h"
-
-#include "base/containers/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "content/browser/renderer_host/frame_tree.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/common/frame_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "url/gurl.h"
-
-namespace content {
-
-// The (process id, routing id) pair that identifies one RenderFrame.
-typedef std::pair<int32, int32> RenderFrameHostID;
-typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
-    RoutingIDFrameMap;
-static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map =
-    LAZY_INSTANCE_INITIALIZER;
-
-// static
-RenderFrameHostImpl* RenderFrameHostImpl::FromID(
-    int process_id, int routing_id) {
-  RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer();
-  RoutingIDFrameMap::iterator it = frames->find(
-      RenderFrameHostID(process_id, routing_id));
-  return it == frames->end() ? NULL : it->second;
-}
-
-RenderFrameHostImpl::RenderFrameHostImpl(
-    RenderViewHostImpl* render_view_host,
-    FrameTree* frame_tree,
-    int routing_id,
-    bool is_swapped_out)
-    : render_view_host_(render_view_host),
-      frame_tree_(frame_tree),
-      routing_id_(routing_id),
-      is_swapped_out_(is_swapped_out) {
-  GetProcess()->AddRoute(routing_id_, this);
-  g_routing_id_frame_map.Get().insert(std::make_pair(
-      RenderFrameHostID(GetProcess()->GetID(), routing_id_),
-      this));
-}
-
-RenderFrameHostImpl::~RenderFrameHostImpl() {
-  GetProcess()->RemoveRoute(routing_id_);
-  g_routing_id_frame_map.Get().erase(
-      RenderFrameHostID(GetProcess()->GetID(), routing_id_));
-
-}
-
-bool RenderFrameHostImpl::Send(IPC::Message* message) {
-  return GetProcess()->Send(message);
-}
-
-bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
-  bool handled = true;
-  bool msg_is_ok = true;
-  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameHostImpl, msg, msg_is_ok)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame,
-                        OnDidStartProvisionalLoadForFrame)
-  IPC_END_MESSAGE_MAP_EX()
-
-  return handled;
-}
-
-void RenderFrameHostImpl::Init() {
-  GetProcess()->ResumeRequestsForView(routing_id());
-}
-
-RenderProcessHost* RenderFrameHostImpl::GetProcess() const {
-  // TODO(nasko): This should return its own process, once we have working
-  // cross-process navigation for subframes.
-  return render_view_host_->GetProcess();
-}
-
-void RenderFrameHostImpl::OnCreateChildFrame(int new_frame_routing_id,
-                                             int64 parent_frame_id,
-                                             int64 frame_id,
-                                             const std::string& frame_name) {
-  frame_tree_->AddFrame(new_frame_routing_id, parent_frame_id, frame_id,
-                        frame_name);
-}
-
-void RenderFrameHostImpl::OnDetach(int64 parent_frame_id, int64 frame_id) {
-  frame_tree_->RemoveFrame(parent_frame_id, frame_id);
-}
-
-void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame(
-    int64 frame_id,
-    int64 parent_frame_id,
-    bool is_main_frame,
-    const GURL& url) {
-  render_view_host_->OnDidStartProvisionalLoadForFrame(
-      frame_id, parent_frame_id, is_main_frame, url);
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
deleted file mode 100644
index b4ba136..0000000
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2013 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_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_IMPL_H_
-#define CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_IMPL_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "content/public/browser/render_frame_host.h"
-
-class GURL;
-
-namespace content {
-
-class FrameTree;
-class RenderProcessHost;
-class RenderViewHostImpl;
-
-class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
- public:
-  static RenderFrameHostImpl* FromID(int process_id, int routing_id);
-
-  // TODO(nasko): Remove dependency on RenderViewHost here. RenderProcessHost
-  // should be the abstraction needed here, but we need RenderViewHost to pass
-  // into WebContentsObserver::FrameDetached for now.
-  RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
-                      FrameTree* frame_tree,
-                      int routing_id,
-                      bool is_swapped_out);
-  virtual ~RenderFrameHostImpl();
-
-  // IPC::Sender
-  virtual bool Send(IPC::Message* msg) OVERRIDE;
-
-  // IPC::Listener
-  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
-
-  void Init();
-  RenderProcessHost* GetProcess() const;
-  int routing_id() const { return routing_id_; }
-  void OnCreateChildFrame(int new_frame_routing_id,
-                          int64 parent_frame_id,
-                          int64 frame_id,
-                          const std::string& frame_name);
-
-  RenderViewHostImpl* render_view_host() {
-    return render_view_host_;
-  }
-
- private:
-  // IPC Message handlers.
-  void OnDetach(int64 parent_frame_id, int64 frame_id);
-  void OnDidStartProvisionalLoadForFrame(int64 frame_id,
-                                         int64 parent_frame_id,
-                                         bool main_frame,
-                                         const GURL& url);
-
-  bool is_swapped_out() { return is_swapped_out_; }
-
-  // TODO(nasko): This should be removed and replaced by RenderProcessHost.
-  RenderViewHostImpl* render_view_host_;  // Not owned.
-
-  // Reference to the whole frame tree that this RenderFrameHost belongs too.
-  // Allows this RenderFrameHost to add and remove nodes in response to
-  // messages from the renderer requesting DOM manipulation.
-  FrameTree* frame_tree_;
-  int routing_id_;
-  bool is_swapped_out_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderFrameHostImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_IMPL_H_
diff --git a/content/browser/renderer_host/render_frame_message_filter.cc b/content/browser/renderer_host/render_frame_message_filter.cc
deleted file mode 100644
index ecea8de..0000000
--- a/content/browser/renderer_host/render_frame_message_filter.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 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/renderer_host/render_frame_message_filter.h"
-
-#include "content/browser/renderer_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/render_widget_helper.h"
-#include "content/common/frame_messages.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-namespace {
-
-void CreateChildFrameOnUI(int process_id,
-                          int parent_render_frame_id,
-                          int64 parent_frame_id,
-                          int64 frame_id,
-                          const std::string& frame_name,
-                          int new_render_frame_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  RenderFrameHostImpl* render_frame_host =
-      RenderFrameHostImpl::FromID(process_id, parent_render_frame_id);
-  // Handles the RenderFrameHost being deleted on the UI thread while
-  // processing a subframe creation message.
-  if (render_frame_host) {
-    render_frame_host->OnCreateChildFrame(new_render_frame_id,
-                                          parent_frame_id, frame_id,
-                                          frame_name);
-  }
-}
-
-}  // namespace
-
-RenderFrameMessageFilter::RenderFrameMessageFilter(
-    int render_process_id,
-    RenderWidgetHelper* render_widget_helper)
-    : render_process_id_(render_process_id),
-      render_widget_helper_(render_widget_helper) {
-}
-
-RenderFrameMessageFilter::~RenderFrameMessageFilter() {
-}
-
-bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message,
-                                                 bool* message_was_ok) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameMessageFilter, message, *message_was_ok)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_CreateChildFrame, OnCreateChildFrame)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP_EX()
-
-  return handled;
-}
-
-void RenderFrameMessageFilter::OnCreateChildFrame(
-    int parent_render_frame_id,
-    int64 parent_frame_id,
-    int64 frame_id,
-    const std::string& frame_name,
-    int* new_render_frame_id) {
-  *new_render_frame_id = render_widget_helper_->GetNextRoutingID();
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&CreateChildFrameOnUI, render_process_id_,
-                 parent_render_frame_id, parent_frame_id, frame_id, frame_name,
-                 *new_render_frame_id));
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/render_frame_message_filter.h b/content/browser/renderer_host/render_frame_message_filter.h
deleted file mode 100644
index a2faac7..0000000
--- a/content/browser/renderer_host/render_frame_message_filter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 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_BROWSER_RENDERER_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
-
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-class RenderWidgetHelper;
-
-// RenderFrameMessageFilter intercepts FrameHost messages on the IO thread
-// that require low-latency processing. The canonical example of this is
-// child-frame creation which is a sync IPC that provides the renderer
-// with the routing id for a newly created RenderFrame.
-//
-// This object is created on the UI thread and used on the IO thread.
-class RenderFrameMessageFilter : public BrowserMessageFilter {
- public:
-  RenderFrameMessageFilter(int render_process_id,
-                           RenderWidgetHelper* render_widget_helper);
-
-  virtual bool OnMessageReceived(const IPC::Message& message,
-                                 bool* message_was_ok) OVERRIDE;
-
- private:
-  virtual ~RenderFrameMessageFilter();
-
-  void OnCreateChildFrame(int parent_render_frame_id,
-                          int64 parent_frame_id,
-                          int64 frame_id,
-                          const std::string& frame_name,
-                          int* new_render_frame_id);
-
-  const int render_process_id_;
-
-  // Needed for issuing routing ids and surface ids.
-  scoped_refptr<RenderWidgetHelper> render_widget_helper_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_MESSAGE_FILTER_H_
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index d7e32d0..7fd1870 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -398,6 +398,8 @@
                         OnCheckNotificationPermission)
     IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
                         OnAllocateSharedMemory)
+    IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+                        OnAllocateGpuMemoryBuffer)
 #if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB)
     IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB)
@@ -1165,4 +1167,23 @@
       true);
 }
 #endif
+
+void RenderMessageFilter::OnAllocateGpuMemoryBuffer(
+    uint32 buffer_size,
+    gfx::GpuMemoryBufferHandle* handle) {
+  // TODO(reveman): Implement allocation of real GpuMemoryBuffer.
+  // Currently this function creates a fake GpuMemoryBuffer that is
+  // backed by shared memory and requires an upload before it can
+  // be used as a texture. The plan is to instead have this function
+  // allocate a real GpuMemoryBuffer in whatever form is supported
+  // by platform and drivers.
+  //
+  // Note: |buffer_size| likely needs to be replaced by a more
+  // specific buffer description but is enough for the shared memory
+  // backed GpuMemoryBuffer currently returned.
+  handle->type = gfx::SHARED_MEMORY_BUFFER;
+  ChildProcessHostImpl::AllocateSharedMemory(
+      buffer_size, PeerHandle(), &handle->handle);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 446a531..d0a4386 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -52,6 +52,7 @@
 
 namespace gfx {
 class Rect;
+struct GpuMemoryBufferHandle;
 }
 
 namespace media {
@@ -261,6 +262,9 @@
                             uint32_t data_size);
 #endif
 
+  void OnAllocateGpuMemoryBuffer(uint32 buffer_size,
+                                 gfx::GpuMemoryBufferHandle* handle);
+
   // Cached resource request dispatcher host and plugin service, guaranteed to
   // be non-null if Init succeeds. We do not own the objects, they are managed
   // by the BrowserProcess, which has a wider scope than we do.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 814ab9e..50d752d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -50,6 +50,7 @@
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
 #include "content/browser/fileapi/fileapi_message_filter.h"
+#include "content/browser/frame_host/render_frame_message_filter.h"
 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -85,7 +86,6 @@
 #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
 #include "content/browser/renderer_host/pepper/pepper_message_filter.h"
 #include "content/browser/renderer_host/pepper/pepper_renderer_connection.h"
-#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "content/browser/renderer_host/render_message_filter.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -93,6 +93,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
 #include "content/browser/renderer_host/text_input_client_message_filter.h"
+#include "content/browser/renderer_host/websocket_dispatcher_host.h"
 #include "content/browser/resolve_proxy_msg_helper.h"
 #include "content/browser/service_worker/service_worker_context.h"
 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
@@ -100,6 +101,7 @@
 #include "content/browser/speech/speech_recognition_dispatcher_host.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/streams/stream_context.h"
+#include "content/browser/tracing/trace_controller_impl.h"
 #include "content/browser/tracing/trace_message_filter.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/browser/worker_host/worker_message_filter.h"
@@ -588,12 +590,15 @@
       media_stream_manager,
       BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
       BrowserMainLoop::GetInstance()->user_input_monitor()));
-  AddFilter(new AudioRendererHost(
+  // The AudioRendererHost needs to be available for lookup, so it's
+  // stashed in a member variable.
+  audio_renderer_host_ = new AudioRendererHost(
       GetID(),
       audio_manager,
       BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
       media_internals,
-      media_stream_manager));
+      media_stream_manager);
+  AddFilter(audio_renderer_host_);
   AddFilter(
       new MIDIHost(GetID(), BrowserMainLoop::GetInstance()->midi_manager()));
   AddFilter(new MIDIDispatcherHost(GetID(), browser_context));
@@ -609,7 +614,7 @@
       GetID(),
       storage_partition_impl_->GetIndexedDBContext()));
   AddFilter(new ServiceWorkerDispatcherHost(
-      storage_partition_impl_->GetServiceWorkerContext()));
+      GetID(), storage_partition_impl_->GetServiceWorkerContext()));
   if (IsGuest()) {
     if (!g_browser_plugin_geolocation_context.Get().get()) {
       g_browser_plugin_geolocation_context.Get() =
@@ -671,6 +676,13 @@
           GetID(), request_context_callback, resource_context);
   AddFilter(socket_stream_dispatcher_host);
 
+  WebSocketDispatcherHost::GetRequestContextCallback
+      websocket_request_context_callback(
+          base::Bind(&GetRequestContext, request_context,
+                     media_request_context, ResourceType::SUB_RESOURCE));
+
+  AddFilter(new WebSocketDispatcherHost(websocket_request_context_callback));
+
   message_port_message_filter_ = new MessagePortMessageFilter(
       base::Bind(&RenderWidgetHelper::GetNextRoutingID,
                  base::Unretained(widget_helper_.get())));
@@ -931,7 +943,6 @@
     switches::kEnableExperimentalWebPlatformFeatures,
     switches::kEnableExperimentalWebSocket,
     switches::kEnableFastTextAutosizing,
-    switches::kEnableFixedLayout,
     switches::kEnableGpuBenchmarking,
     switches::kEnableGPUClientLogging,
     switches::kEnableGpuClientTracing,
@@ -975,7 +986,6 @@
     switches::kMemoryMetrics,
     switches::kNoReferrers,
     switches::kNoSandbox,
-    switches::kOverrideEncryptedMediaCanPlayType,
     switches::kPpapiInProcess,
     switches::kRegisterPepperPlugins,
     switches::kRendererAssertTest,
@@ -985,7 +995,6 @@
     switches::kStatsCollectionController,
     switches::kTestSandbox,
     switches::kTouchEvents,
-    switches::kTraceStartup,
     switches::kTraceToConsole,
     // This flag needs to be propagated to the renderer process for
     // --in-process-webgl.
@@ -1058,7 +1067,6 @@
     switches::kDisableWebRTC,
     switches::kEnableSpeechRecognition,
     switches::kHideScrollbars,
-    switches::kEnableMediaDrm,
     switches::kMediaDrmEnableNonCompositing,
     switches::kNetworkCountryIso,
 #endif
@@ -1076,6 +1084,13 @@
   renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
                                  arraysize(kSwitchNames));
 
+  if (browser_cmd.HasSwitch(switches::kTraceStartup) &&
+      TraceControllerImpl::GetInstance()->is_tracing_startup()) {
+    // Pass kTraceStartup switch to renderer only if startup tracing has not
+    // finished.
+    renderer_cmd->AppendSwitch(switches::kTraceStartup);
+  }
+
   // Disable databases in incognito mode.
   if (GetBrowserContext()->IsOffTheRecord() &&
       !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
@@ -1782,6 +1797,11 @@
   }
 }
 
+scoped_refptr<AudioRendererHost>
+RenderProcessHostImpl::audio_renderer_host() const {
+  return audio_renderer_host_;
+}
+
 void RenderProcessHostImpl::OnUserMetricsRecordAction(
     const std::string& action) {
   RecordComputedAction(action);
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index a056191..681d329 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -33,6 +33,7 @@
 }
 
 namespace content {
+class AudioRendererHost;
 class BrowserDemuxerAndroid;
 class GpuMessageFilter;
 class MessagePortMessageFilter;
@@ -126,6 +127,8 @@
   // ChildProcessLauncher::Client implementation.
   virtual void OnProcessLaunched() OVERRIDE;
 
+  scoped_refptr<AudioRendererHost> audio_renderer_host() const;
+
   // Tells the ResourceDispatcherHost to resume a deferred navigation without
   // transferring it to a new renderer process.
   void ResumeDeferredNavigation(const GlobalRequestID& request_id);
@@ -338,6 +341,8 @@
   // Forwards power state messages to the renderer process.
   PowerMonitorMessageBroadcaster power_monitor_broadcaster_;
 
+  scoped_refptr<AudioRendererHost> audio_renderer_host_;
+
 #if defined(OS_ANDROID)
   scoped_refptr<BrowserDemuxerAndroid> browser_demuxer_android_;
 #endif
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 3176e37..f3f31e4 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -15,6 +15,7 @@
 #include "content/common/content_export.h"
 #include "content/public/common/javascript_message_type.h"
 #include "content/public/common/media_stream_request.h"
+#include "content/public/common/page_transition_types.h"
 #include "net/base/load_states.h"
 #include "third_party/WebKit/public/web/WebPopupType.h"
 #include "ui/base/window_open_disposition.h"
@@ -100,8 +101,9 @@
         RenderViewHost* pending_render_view_host,
         const GlobalRequestID& global_request_id,
         bool is_transfer,
-        const GURL& transfer_url,
+        const std::vector<GURL>& transfer_url_chain,
         const Referrer& referrer,
+        PageTransition page_transition,
         int64 frame_id) = 0;
 
    protected:
@@ -255,9 +257,13 @@
                               bool user_gesture) {}
 
   // The page wants to transfer the request to a new renderer.
+  // |redirect_chain| contains any redirect URLs (excluding |url|) that happened
+  // before the transfer.
   virtual void RequestTransferURL(
       const GURL& url,
+      const std::vector<GURL>& redirect_chain,
       const Referrer& referrer,
+      PageTransition page_transition,
       WindowOpenDisposition disposition,
       int64 source_frame_id,
       const GlobalRequestID& old_request_id,
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index c63d487..0b1f7c6 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -14,21 +14,27 @@
 #include "base/debug/trace_event.h"
 #include "base/i18n/rtl.h"
 #include "base/json/json_reader.h"
-#include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "cc/base/switches.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/cross_site_request_manager.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/gpu/compositor_util.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/gpu/gpu_surface_tracker.h"
 #include "content/browser/host_zoom_map_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/renderer_host/dip_util.h"
-#include "content/browser/renderer_host/frame_tree.h"
+#include "content/browser/renderer_host/media/audio_renderer_host.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/common/accessibility_messages.h"
@@ -51,7 +57,6 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/common/bindings_policy.h"
@@ -63,8 +68,12 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "net/base/net_util.h"
+#include "net/base/network_change_notifier.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/touch/touch_device.h"
+#include "ui/base/touch/touch_enabled.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/shell_dialogs/selected_file_info.h"
@@ -106,9 +115,6 @@
   }
 }
 
-base::LazyInstance<std::vector<RenderViewHost::CreatedCallback> >
-g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
-
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -189,22 +195,32 @@
 
   GetProcess()->EnableSendQueue();
 
-  for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
-    g_created_callbacks.Get().at(i).Run(this);
-
   if (!swapped_out)
     instance_->increment_active_view_count();
 
+  if (ResourceDispatcherHostImpl::Get()) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostCreated,
+                   base::Unretained(ResourceDispatcherHostImpl::Get()),
+                   GetProcess()->GetID(), GetRoutingID()));
+  }
+
 #if defined(OS_ANDROID)
-  media_player_manager_ = BrowserMediaPlayerManager::Create(this);
+  media_player_manager_.reset(BrowserMediaPlayerManager::Create(this));
 #endif
 }
 
 RenderViewHostImpl::~RenderViewHostImpl() {
-  FOR_EACH_OBSERVER(
-      RenderViewHostObserver, observers_, RenderViewHostDestruction());
+  if (ResourceDispatcherHostImpl::Get()) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostDeleted,
+                   base::Unretained(ResourceDispatcherHostImpl::Get()),
+                   GetProcess()->GetID(), GetRoutingID()));
+  }
 
-  GetDelegate()->RenderViewDeleted(this);
+  delegate_->RenderViewDeleted(this);
 
   // Be sure to clean up any leftover state from cross-site requests.
   CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest(
@@ -280,9 +296,6 @@
   // Let our delegate know that we created a RenderView.
   delegate_->RenderViewCreated(this);
 
-  FOR_EACH_OBSERVER(
-      RenderViewHostObserver, observers_, RenderViewHostInitialized());
-
   return true;
 }
 
@@ -300,6 +313,224 @@
                                         GetProcess()->GetBrowserContext())));
 }
 
+WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
+  TRACE_EVENT0("browser", "RenderViewHostImpl::GetWebkitPrefs");
+  WebPreferences prefs;
+
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+  prefs.javascript_enabled =
+      !command_line.HasSwitch(switches::kDisableJavaScript);
+  prefs.web_security_enabled =
+      !command_line.HasSwitch(switches::kDisableWebSecurity);
+  prefs.plugins_enabled =
+      !command_line.HasSwitch(switches::kDisablePlugins);
+  prefs.java_enabled =
+      !command_line.HasSwitch(switches::kDisableJava);
+
+  prefs.remote_fonts_enabled =
+      !command_line.HasSwitch(switches::kDisableRemoteFonts);
+  prefs.xslt_enabled =
+      !command_line.HasSwitch(switches::kDisableXSLT);
+  prefs.xss_auditor_enabled =
+      !command_line.HasSwitch(switches::kDisableXSSAuditor);
+  prefs.application_cache_enabled =
+      !command_line.HasSwitch(switches::kDisableApplicationCache);
+
+  prefs.local_storage_enabled =
+      !command_line.HasSwitch(switches::kDisableLocalStorage);
+  prefs.databases_enabled =
+      !command_line.HasSwitch(switches::kDisableDatabases);
+  prefs.webaudio_enabled =
+      !command_line.HasSwitch(switches::kDisableWebAudio);
+
+  prefs.experimental_webgl_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisable3DAPIs) &&
+      !command_line.HasSwitch(switches::kDisableExperimentalWebGL);
+
+  prefs.flash_3d_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisableFlash3d);
+  prefs.flash_stage3d_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisableFlashStage3d);
+  prefs.flash_stage3d_baseline_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisableFlashStage3d);
+
+  prefs.gl_multisampling_enabled =
+      !command_line.HasSwitch(switches::kDisableGLMultisampling);
+  prefs.privileged_webgl_extensions_enabled =
+      command_line.HasSwitch(switches::kEnablePrivilegedWebGLExtensions);
+  prefs.site_specific_quirks_enabled =
+      !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks);
+  prefs.allow_file_access_from_file_urls =
+      command_line.HasSwitch(switches::kAllowFileAccessFromFiles);
+
+  prefs.accelerated_compositing_for_overflow_scroll_enabled = false;
+  if (command_line.HasSwitch(switches::kEnableAcceleratedOverflowScroll))
+    prefs.accelerated_compositing_for_overflow_scroll_enabled = true;
+  if (command_line.HasSwitch(switches::kDisableAcceleratedOverflowScroll))
+    prefs.accelerated_compositing_for_overflow_scroll_enabled = false;
+
+  prefs.accelerated_compositing_for_scrollable_frames_enabled = false;
+  if (command_line.HasSwitch(switches::kEnableAcceleratedScrollableFrames))
+    prefs.accelerated_compositing_for_scrollable_frames_enabled = true;
+  if (command_line.HasSwitch(switches::kDisableAcceleratedScrollableFrames))
+    prefs.accelerated_compositing_for_scrollable_frames_enabled = false;
+
+  prefs.composited_scrolling_for_frames_enabled = false;
+  if (command_line.HasSwitch(switches::kEnableCompositedScrollingForFrames))
+    prefs.composited_scrolling_for_frames_enabled = true;
+  if (command_line.HasSwitch(switches::kDisableCompositedScrollingForFrames))
+    prefs.composited_scrolling_for_frames_enabled = false;
+
+  prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = false;
+  if (command_line.HasSwitch(
+          switches::kEnableUniversalAcceleratedOverflowScroll))
+    prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = true;
+  if (command_line.HasSwitch(
+          switches::kDisableUniversalAcceleratedOverflowScroll))
+    prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = false;
+
+  prefs.show_paint_rects =
+      command_line.HasSwitch(switches::kShowPaintRects);
+  prefs.accelerated_compositing_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisableAcceleratedCompositing);
+  prefs.force_compositing_mode =
+      content::IsForceCompositingModeEnabled() &&
+      !command_line.HasSwitch(switches::kDisableForceCompositingMode);
+  prefs.accelerated_2d_canvas_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      !command_line.HasSwitch(switches::kDisableAccelerated2dCanvas);
+  prefs.antialiased_2d_canvas_disabled =
+      command_line.HasSwitch(switches::kDisable2dCanvasAntialiasing);
+  prefs.accelerated_2d_canvas_msaa_sample_count =
+      atoi(command_line.GetSwitchValueASCII(
+      switches::kAcceleratedCanvas2dMSAASampleCount).c_str());
+  prefs.accelerated_filters_enabled =
+      GpuProcessHost::gpu_enabled() &&
+      command_line.HasSwitch(switches::kEnableAcceleratedFilters);
+  prefs.accelerated_compositing_for_3d_transforms_enabled =
+      prefs.accelerated_compositing_for_animation_enabled =
+          !command_line.HasSwitch(switches::kDisableAcceleratedLayers);
+  prefs.accelerated_compositing_for_plugins_enabled =
+      !command_line.HasSwitch(switches::kDisableAcceleratedPlugins);
+  prefs.accelerated_compositing_for_video_enabled =
+      !command_line.HasSwitch(switches::kDisableAcceleratedVideo);
+  prefs.fullscreen_enabled =
+      !command_line.HasSwitch(switches::kDisableFullScreen);
+  prefs.lazy_layout_enabled =
+      command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+  prefs.region_based_columns_enabled =
+      command_line.HasSwitch(switches::kEnableRegionBasedColumns);
+  prefs.threaded_html_parser =
+      !command_line.HasSwitch(switches::kDisableThreadedHTMLParser);
+  prefs.experimental_websocket_enabled =
+      command_line.HasSwitch(switches::kEnableExperimentalWebSocket);
+  if (command_line.HasSwitch(cc::switches::kEnablePinchVirtualViewport)) {
+    prefs.pinch_virtual_viewport_enabled = true;
+    prefs.pinch_overlay_scrollbar_thickness = 10;
+  }
+  prefs.use_solid_color_scrollbars = command_line.HasSwitch(
+      switches::kEnableOverlayScrollbars);
+
+#if defined(OS_ANDROID)
+  prefs.user_gesture_required_for_media_playback = !command_line.HasSwitch(
+      switches::kDisableGestureRequirementForMediaPlayback);
+  prefs.user_gesture_required_for_media_fullscreen = !command_line.HasSwitch(
+      switches::kDisableGestureRequirementForMediaFullscreen);
+#endif
+
+  prefs.touch_enabled = ui::AreTouchEventsEnabled();
+  prefs.device_supports_touch = prefs.touch_enabled &&
+      ui::IsTouchDevicePresent();
+#if defined(OS_ANDROID)
+  prefs.device_supports_mouse = false;
+#endif
+
+  prefs.pointer_events_max_touch_points = ui::MaxTouchPoints();
+
+  prefs.touch_adjustment_enabled =
+      !command_line.HasSwitch(switches::kDisableTouchAdjustment);
+  prefs.compositor_touch_hit_testing =
+      !command_line.HasSwitch(cc::switches::kDisableCompositorTouchHitTesting);
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+  bool default_enable_scroll_animator = true;
+#else
+  bool default_enable_scroll_animator = false;
+#endif
+  prefs.enable_scroll_animator = default_enable_scroll_animator;
+  if (command_line.HasSwitch(switches::kEnableSmoothScrolling))
+    prefs.enable_scroll_animator = true;
+  if (command_line.HasSwitch(switches::kDisableSmoothScrolling))
+    prefs.enable_scroll_animator = false;
+
+  prefs.visual_word_movement_enabled =
+      command_line.HasSwitch(switches::kEnableVisualWordMovement);
+
+  // Certain GPU features might have been blacklisted.
+  GpuDataManagerImpl::GetInstance()->UpdateRendererWebPrefs(&prefs);
+
+  if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+          GetProcess()->GetID())) {
+    prefs.loads_images_automatically = true;
+    prefs.javascript_enabled = true;
+  }
+
+  prefs.is_online = !net::NetworkChangeNotifier::IsOffline();
+
+#if !defined(USE_AURA)
+  // Force accelerated compositing and 2d canvas off for chrome: and about:
+  // pages (unless it's specifically allowed).
+  if ((url.SchemeIs(chrome::kChromeUIScheme) ||
+      (url.SchemeIs(chrome::kAboutScheme) &&
+       url.spec() != kAboutBlankURL)) &&
+      !command_line.HasSwitch(switches::kAllowWebUICompositing)) {
+    prefs.accelerated_compositing_enabled = false;
+    prefs.accelerated_2d_canvas_enabled = false;
+  }
+#endif
+
+  prefs.fixed_position_creates_stacking_context = !command_line.HasSwitch(
+      switches::kDisableFixedPositionCreatesStackingContext);
+
+#if defined(OS_CHROMEOS)
+  prefs.gesture_tap_highlight_enabled = !command_line.HasSwitch(
+      switches::kDisableGestureTapHighlight);
+#else
+  prefs.gesture_tap_highlight_enabled = command_line.HasSwitch(
+      switches::kEnableGestureTapHighlight);
+#endif
+
+  prefs.number_of_cpu_cores = base::SysInfo::NumberOfProcessors();
+
+  prefs.viewport_enabled = command_line.HasSwitch(switches::kEnableViewport);
+
+  prefs.deferred_image_decoding_enabled =
+      command_line.HasSwitch(switches::kEnableDeferredImageDecoding) ||
+      cc::switches::IsImplSidePaintingEnabled();
+
+  prefs.spatial_navigation_enabled = command_line.HasSwitch(
+      switches::kEnableSpatialNavigation);
+
+  GetContentClient()->browser()->OverrideWebkitPrefs(this, url, &prefs);
+
+  // Disable compositing in guests until we have compositing path implemented
+  // for guests.
+  bool guest_compositing_enabled = !command_line.HasSwitch(
+      switches::kDisableBrowserPluginCompositing);
+  if (GetProcess()->IsGuest() && !guest_compositing_enabled) {
+    prefs.force_compositing_mode = false;
+    prefs.accelerated_compositing_enabled = false;
+  }
+
+  return prefs;
+}
+
 void RenderViewHostImpl::Navigate(const ViewMsg_Navigate_Params& params) {
   TRACE_EVENT0("renderer_host", "RenderViewHostImpl::Navigate");
   // Browser plugin guests are not allowed to navigate outside web-safe schemes,
@@ -908,13 +1139,6 @@
     }
   }
 
-  ObserverListBase<RenderViewHostObserver>::Iterator it(observers_);
-  RenderViewHostObserver* observer;
-  while ((observer = it.GetNext()) != NULL) {
-    if (observer->OnMessageReceived(msg))
-      return true;
-  }
-
   if (delegate_->OnMessageReceived(this, msg))
     return true;
 
@@ -1539,14 +1763,6 @@
   }
 }
 
-void RenderViewHostImpl::AddObserver(RenderViewHostObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void RenderViewHostImpl::RemoveObserver(RenderViewHostObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
 void RenderViewHostImpl::OnUserGesture() {
   delegate_->OnUserGesture();
 }
@@ -1761,19 +1977,6 @@
   }
 }
 
-void RenderViewHost::AddCreatedCallback(const CreatedCallback& callback) {
-  g_created_callbacks.Get().push_back(callback);
-}
-
-void RenderViewHost::RemoveCreatedCallback(const CreatedCallback& callback) {
-  for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) {
-    if (g_created_callbacks.Get().at(i).Equals(callback)) {
-      g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i);
-      return;
-    }
-  }
-}
-
 void RenderViewHostImpl::SetAltErrorPageURL(const GURL& url) {
   Send(new ViewMsg_SetAltErrorPageURL(GetRoutingID(), url));
 }
@@ -1808,6 +2011,13 @@
   Send(new ViewMsg_TimezoneChange(GetRoutingID()));
 }
 
+void RenderViewHostImpl::GetAudioOutputControllers(
+    const GetAudioOutputControllersCallback& callback) const {
+  AudioRendererHost* audio_host =
+      static_cast<RenderProcessHostImpl*>(GetProcess())->audio_renderer_host();
+  audio_host->GetOutputControllers(GetRoutingID(), callback);
+}
+
 void RenderViewHostImpl::ClearFocusedNode() {
   Send(new ViewMsg_ClearFocusedNode(GetRoutingID()));
 }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index dc714fa..a3401c3 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -12,9 +12,8 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
 #include "base/process/kill.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/accessibility_node_data.h"
@@ -62,7 +61,6 @@
 class ChildProcessSecurityPolicyImpl;
 class PageState;
 class RenderFrameHostImpl;
-class RenderViewHostObserver;
 class RenderWidgetHostDelegate;
 class SessionStorageNamespace;
 class SessionStorageNamespaceImpl;
@@ -212,6 +210,8 @@
   virtual void UpdateWebkitPreferences(
       const WebPreferences& prefs) OVERRIDE;
   virtual void NotifyTimezoneChange() OVERRIDE;
+  virtual void GetAudioOutputControllers(
+      const GetAudioOutputControllersCallback& callback) const OVERRIDE;
 
 #if defined(OS_ANDROID)
   virtual void ActivateNearestFindResult(int request_id,
@@ -240,6 +240,9 @@
     return render_view_termination_status_;
   }
 
+  // Returns the content specific prefs for this RenderViewHost.
+  WebPreferences GetWebkitPrefs(const GURL& url);
+
   // Sends the given navigation message. Use this rather than sending it
   // yourself since this does the internal bookkeeping described below. This
   // function takes ownership of the provided message pointer.
@@ -390,7 +393,7 @@
 
 #if defined(OS_ANDROID)
   BrowserMediaPlayerManager* media_player_manager() {
-    return media_player_manager_;
+    return media_player_manager_.get();
   }
 
   void DidSelectPopupMenuItems(const std::vector<int>& selected_indices);
@@ -480,13 +483,6 @@
   // to keep them consistent).
 
  protected:
-  friend class RenderViewHostObserver;
-
-  // Add and remove observers for filtering IPC messages.  Clients must be sure
-  // to remove the observer before they go away.
-  void AddObserver(RenderViewHostObserver* observer);
-  void RemoveObserver(RenderViewHostObserver* observer);
-
   // RenderWidgetHost protected overrides.
   virtual void OnUserGesture() OVERRIDE;
   virtual void NotifyRendererUnresponsive() OVERRIDE;
@@ -713,16 +709,12 @@
   // The termination status of the last render view that terminated.
   base::TerminationStatus render_view_termination_status_;
 
-  // A list of observers that filter messages.  Weak references.
-  ObserverList<RenderViewHostObserver> observers_;
-
   // When the last ShouldClose message was sent.
   base::TimeTicks send_should_close_start_time_;
 
 #if defined(OS_ANDROID)
   // Manages all the android mediaplayer objects and handling IPCs for video.
-  // This class inherits from RenderViewHostObserver.
-  BrowserMediaPlayerManager* media_player_manager_;
+  scoped_ptr<BrowserMediaPlayerManager> media_player_manager_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(RenderViewHostImpl);
diff --git a/content/browser/renderer_host/render_view_host_manager_browsertest.cc b/content/browser/renderer_host/render_view_host_manager_browsertest.cc
index 342e98a..7fce2bc 100644
--- a/content/browser/renderer_host/render_view_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_view_host_manager_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <set>
+
 #include "base/json/json_reader.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
@@ -18,7 +20,6 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/url_constants.h"
@@ -1202,50 +1203,27 @@
   EXPECT_TRUE(success);
 }
 
-// This class holds onto RenderViewHostObservers for as long as their observed
-// RenderViewHosts are alive. This allows us to confirm that all hosts have
-// properly been shutdown.
-class RenderViewHostObserverArray {
+// This class ensures that all the given RenderViewHosts have properly been
+// shutdown.
+class RenderViewHostDestructionObserver : public WebContentsObserver {
  public:
-  ~RenderViewHostObserverArray() {
-    // In case some would be left in there with a dead pointer to us.
-    for (std::list<RVHObserver*>::iterator iter = observers_.begin();
-         iter != observers_.end(); ++iter) {
-      (*iter)->ClearParent();
-    }
+  explicit RenderViewHostDestructionObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents) {}
+  virtual ~RenderViewHostDestructionObserver() {}
+  void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
+    watched_render_view_hosts_.insert(rvh);
   }
-  void AddObserverToRVH(RenderViewHost* rvh) {
-    observers_.push_back(new RVHObserver(this, rvh));
-  }
-  size_t GetNumObservers() const {
-    return observers_.size();
+  size_t GetNumberOfWatchedRenderViewHosts() const {
+    return watched_render_view_hosts_.size();
   }
 
  private:
-  friend class RVHObserver;
-  class RVHObserver : public RenderViewHostObserver {
-   public:
-    RVHObserver(RenderViewHostObserverArray* parent, RenderViewHost* rvh)
-        : RenderViewHostObserver(rvh),
-          parent_(parent) {
-    }
-    virtual void RenderViewHostDestroyed(RenderViewHost* rvh) OVERRIDE {
-      if (parent_)
-        parent_->RemoveObserver(this);
-      RenderViewHostObserver::RenderViewHostDestroyed(rvh);
-    };
-    void ClearParent() {
-      parent_ = NULL;
-    }
-   private:
-    RenderViewHostObserverArray* parent_;
-  };
-
-  void RemoveObserver(RVHObserver* observer) {
-    observers_.remove(observer);
+  // WebContentsObserver implementation:
+  virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
+    watched_render_view_hosts_.erase(rvh);
   }
 
-  std::list<RVHObserver*> observers_;
+  std::set<RenderViewHost*> watched_render_view_hosts_;
 };
 
 // Test for crbug.com/90867. Make sure we don't leak render view hosts since
@@ -1263,7 +1241,7 @@
   ASSERT_TRUE(https_server.Start());
 
   // Observe the created render_view_host's to make sure they will not leak.
-  RenderViewHostObserverArray rvh_observers;
+  RenderViewHostDestructionObserver rvh_observers(shell()->web_contents());
 
   GURL navigated_url(test_server()->GetURL("files/title2.html"));
   GURL view_source_url(kViewSourceScheme + std::string(":") +
@@ -1275,7 +1253,7 @@
   SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
-  rvh_observers.AddObserverToRVH(blank_rvh);
+  rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
 
   // Now navigate to the view-source URL and ensure we got a different
   // SiteInstance and RenderViewHost.
@@ -1283,7 +1261,8 @@
   EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost());
   EXPECT_NE(blank_site_instance, shell()->web_contents()->
       GetRenderViewHost()->GetSiteInstance());
-  rvh_observers.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
+  rvh_observers.EnsureRVHGetsDestructed(
+      shell()->web_contents()->GetRenderViewHost());
 
   // Load a random page and then navigate to view-source: of it.
   // This used to cause two RVH instances for the same SiteInstance, which
@@ -1291,10 +1270,12 @@
   NavigateToURL(shell(), navigated_url);
   SiteInstance* site_instance1 = shell()->web_contents()->
       GetRenderViewHost()->GetSiteInstance();
-  rvh_observers.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
+  rvh_observers.EnsureRVHGetsDestructed(
+      shell()->web_contents()->GetRenderViewHost());
 
   NavigateToURL(shell(), view_source_url);
-  rvh_observers.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
+  rvh_observers.EnsureRVHGetsDestructed(
+      shell()->web_contents()->GetRenderViewHost());
   SiteInstance* site_instance2 = shell()->web_contents()->
       GetRenderViewHost()->GetSiteInstance();
 
@@ -1303,14 +1284,15 @@
 
   // Now navigate to a different instance so that we swap out again.
   NavigateToURL(shell(), https_server.GetURL("files/title2.html"));
-  rvh_observers.AddObserverToRVH(shell()->web_contents()->GetRenderViewHost());
+  rvh_observers.EnsureRVHGetsDestructed(
+      shell()->web_contents()->GetRenderViewHost());
 
   // This used to leak a render view host.
   shell()->Close();
 
   RunAllPendingInMessageLoop();  // Needed on ChromeOS.
 
-  EXPECT_EQ(0U, rvh_observers.GetNumObservers());
+  EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts());
 }
 
 // Test for crbug.com/143155.  Frame tree updates during unload should not
diff --git a/content/browser/renderer_host/render_view_host_unittest.cc b/content/browser/renderer_host/render_view_host_unittest.cc
index 6e702d5..87c2404 100644
--- a/content/browser/renderer_host/render_view_host_unittest.cc
+++ b/content/browser/renderer_host/render_view_host_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/test_render_view_host.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/port/browser/render_view_host_delegate_view.h"
@@ -226,8 +225,7 @@
   EXPECT_EQ(0, process()->bad_msg_count());
   // craft an incorrect ViewHostMsg_UpdateTargetURL message. The real one has
   // two payload items but the one we construct has none.
-  IPC::Message message(0, ViewHostMsg_UpdateTargetURL::ID,
-                       IPC::Message::PRIORITY_NORMAL);
+  IPC::Message message(0, ViewHostMsg_UpdateTargetURL::ID);
   test_rvh()->OnMessageReceived(message);
   EXPECT_EQ(1, process()->bad_msg_count());
 }
@@ -238,8 +236,7 @@
   EXPECT_EQ(0, process()->bad_msg_count());
   // craft an incorrect ViewHostMsg_UpdateRect message. The real one has
   // one payload item but the one we construct has none.
-  IPC::Message message(0, ViewHostMsg_UpdateRect::ID,
-                       IPC::Message::PRIORITY_NORMAL);
+  IPC::Message message(0, ViewHostMsg_UpdateRect::ID);
   test_rvh()->OnMessageReceived(message);
   EXPECT_EQ(1, process()->bad_msg_count());
 }
@@ -251,8 +248,7 @@
   // the code actually expects it to have at least one int para, this this
   // bogus message will not fail at de-serialization but should fail in
   // OnInputEventAck() processing.
-  IPC::Message message(0, InputHostMsg_HandleInputEvent_ACK::ID,
-                       IPC::Message::PRIORITY_NORMAL);
+  IPC::Message message(0, InputHostMsg_HandleInputEvent_ACK::ID);
   test_rvh()->OnMessageReceived(message);
   EXPECT_EQ(1, process()->bad_msg_count());
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index d70381f..3435ec5 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -414,7 +414,7 @@
   if (!enabled)
     overscroll_controller_.reset();
   else if (!overscroll_controller_)
-    overscroll_controller_.reset(new OverscrollController(this));
+    overscroll_controller_.reset(new OverscrollController());
 }
 
 void RenderWidgetHostImpl::SuppressNextCharEvents() {
@@ -1222,6 +1222,11 @@
     const gfx::Rect& src_subrect,
     const base::Callback<void(bool, const SkBitmap&)>& callback) {
   TRACE_EVENT0("browser", "RenderWidgetHostImpl::GetSnapshotFromRenderer");
+  if (!view_) {
+    callback.Run(false, SkBitmap());
+    return;
+  }
+
   pending_snapshots_.push(callback);
 
   gfx::Rect copy_rect = src_subrect.IsEmpty() ?
@@ -1484,7 +1489,6 @@
 }
 
 void RenderWidgetHostImpl::OnRequestMove(const gfx::Rect& pos) {
-  // Note that we ignore the position.
   if (view_) {
     view_->SetBounds(pos);
     Send(new ViewMsg_Move_ACK(routing_id_));
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 489539a..ab259fd 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -11,7 +11,7 @@
 #include "content/browser/renderer_host/backing_store.h"
 #include "content/browser/renderer_host/input/gesture_event_filter.h"
 #include "content/browser/renderer_host/input/immediate_input_router.h"
-#include "content/browser/renderer_host/input/mock_web_input_event_builders.h"
+#include "content/browser/renderer_host/input/synthetic_web_input_event_builders.h"
 #include "content/browser/renderer_host/input/tap_suppression_controller.h"
 #include "content/browser/renderer_host/input/tap_suppression_controller_client.h"
 #include "content/browser/renderer_host/input/touch_event_queue.h"
@@ -58,8 +58,9 @@
 
 class TestOverscrollDelegate : public OverscrollControllerDelegate {
  public:
-  TestOverscrollDelegate()
-      : current_mode_(OVERSCROLL_NONE),
+  explicit TestOverscrollDelegate(RenderWidgetHostView* view)
+      : view_(view),
+        current_mode_(OVERSCROLL_NONE),
         completed_mode_(OVERSCROLL_NONE),
         delta_x_(0.f),
         delta_y_(0.f) {
@@ -80,6 +81,10 @@
 
  private:
   // Overridden from OverscrollControllerDelegate:
+  virtual gfx::Rect GetVisibleBounds() const OVERRIDE {
+    return view_->IsShowing() ? view_->GetViewBounds() : gfx::Rect();
+  }
+
   virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE {
     delta_x_ = delta_x;
     delta_y_ = delta_y;
@@ -98,6 +103,7 @@
     delta_x_ = delta_y_ = 0.f;
   }
 
+  RenderWidgetHostView* view_;
   OverscrollMode current_mode_;
   OverscrollMode completed_mode_;
   float delta_x_;
@@ -233,10 +239,6 @@
     return gesture_event_filter()->coalesced_gesture_events_.at(i).event;
   }
 
-  bool shouldDeferTapDownEvents() const {
-    return gesture_event_filter()->maximum_tap_gap_time_ms_ != 0;
-  }
-
   bool ScrollingInProgress() const {
     return gesture_event_filter()->scrolling_in_progress_;
   }
@@ -251,14 +253,10 @@
 
   void SetupForOverscrollControllerTest() {
     SetOverscrollControllerEnabled(true);
-    overscroll_delegate_.reset(new TestOverscrollDelegate);
+    overscroll_delegate_.reset(new TestOverscrollDelegate(GetView()));
     overscroll_controller_->set_delegate(overscroll_delegate_.get());
   }
 
-  void set_maximum_tap_gap_time_ms(int delay_ms) {
-    gesture_event_filter()->maximum_tap_gap_time_ms_ = delay_ms;
-  }
-
   void set_debounce_interval_time_ms(int delay_ms) {
     gesture_event_filter()->debounce_interval_time_ms_ = delay_ms;
   }
@@ -649,28 +647,28 @@
   }
 
   void SimulateKeyboardEvent(WebInputEvent::Type type) {
-    host_->ForwardKeyboardEvent(MockWebKeyboardEventBuilder::Build(type));
+    host_->ForwardKeyboardEvent(SyntheticWebKeyboardEventBuilder::Build(type));
   }
 
   void SimulateMouseEvent(WebInputEvent::Type type) {
-    host_->ForwardMouseEvent(MockWebMouseEventBuilder::Build(type));
+    host_->ForwardMouseEvent(SyntheticWebMouseEventBuilder::Build(type));
   }
 
   void SimulateWheelEvent(float dX, float dY, int modifiers, bool precise) {
     host_->ForwardWheelEvent(
-        MockWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise));
+        SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise));
   }
 
   void SimulateMouseMove(int x, int y, int modifiers) {
     host_->ForwardMouseEvent(
-        MockWebMouseEventBuilder::Build(WebInputEvent::MouseMove,
-                                        x,
-                                        y,
-                                        modifiers));
+        SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseMove,
+                                             x,
+                                             y,
+                                             modifiers));
   }
 
   void SimulateWheelEventWithPhase(WebMouseWheelEvent::Phase phase) {
-    host_->ForwardWheelEvent(MockWebMouseWheelEventBuilder::Build(phase));
+    host_->ForwardWheelEvent(SyntheticWebMouseWheelEventBuilder::Build(phase));
   }
 
   // Inject provided synthetic WebGestureEvent instance.
@@ -682,12 +680,12 @@
   void SimulateGestureEvent(WebInputEvent::Type type,
                             WebGestureEvent::SourceDevice sourceDevice) {
     SimulateGestureEventCore(
-        MockWebGestureEventBuilder::Build(type, sourceDevice));
+        SyntheticWebGestureEventBuilder::Build(type, sourceDevice));
   }
 
   void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
     SimulateGestureEventCore(
-        MockWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
+        SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers));
   }
 
   void SimulateGesturePinchUpdateEvent(float scale,
@@ -695,10 +693,10 @@
                                        float anchorY,
                                        int modifiers) {
     SimulateGestureEventCore(
-        MockWebGestureEventBuilder::BuildPinchUpdate(scale,
-                                                     anchorX,
-                                                     anchorY,
-                                                     modifiers));
+        SyntheticWebGestureEventBuilder::BuildPinchUpdate(scale,
+                                                          anchorX,
+                                                          anchorY,
+                                                          modifiers));
   }
 
   // Inject synthetic GestureFlingStart events.
@@ -707,9 +705,9 @@
       float velocityY,
       WebGestureEvent::SourceDevice sourceDevice) {
     SimulateGestureEventCore(
-        MockWebGestureEventBuilder::BuildFling(velocityX,
-                                               velocityY,
-                                               sourceDevice));
+        SyntheticWebGestureEventBuilder::BuildFling(velocityX,
+                                                    velocityY,
+                                                    sourceDevice));
   }
 
   // Set the timestamp for the touch-event.
@@ -758,7 +756,7 @@
   bool handle_mouse_event_;
 
  private:
-  MockWebTouchEvent touch_event_;
+  SyntheticWebTouchEvent touch_event_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostTest);
 };
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index a1b4e26..4c89830 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -152,6 +152,9 @@
 
   if (texture_layer_.get())
     texture_layer_->ClearClient();
+
+  if (resource_collection_.get())
+    resource_collection_->SetClient(NULL);
 }
 
 
@@ -681,14 +684,17 @@
 
     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
     // any resources from the old output surface with the new output surface id.
-    resource_collection_ = NULL;
+    if (resource_collection_.get()) {
+      resource_collection_->SetClient(NULL);
+      resource_collection_ = NULL;
+    }
     DestroyDelegatedContent();
   }
 
   if (!has_content) {
     DestroyDelegatedContent();
   } else {
-    if (!resource_collection_) {
+    if (!resource_collection_.get()) {
       resource_collection_ = new cc::DelegatedFrameResourceCollection;
       resource_collection_->SetClient(this);
     }
@@ -1302,10 +1308,10 @@
 
   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
-                    dst_size_in_pixel.width(), dst_size_in_pixel.height());
+                    dst_size_in_pixel.width(), dst_size_in_pixel.height(),
+                    0, kOpaque_SkAlphaType);
   if (!bitmap->allocPixels())
     return;
-  bitmap->setIsOpaque(true);
 
   ImageTransportFactoryAndroid* factory =
       ImageTransportFactoryAndroid::GetInstance();
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 55517eb..2d56a3f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -53,8 +53,8 @@
 #include "ui/aura/client/cursor_client_observer.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/client/tooltip_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/client/window_types.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
@@ -93,35 +93,6 @@
 
 namespace content {
 
-void ReleaseMailbox(scoped_refptr<MemoryHolder> holder,
-                    unsigned sync_point,
-                    bool lost_resource) {}
-
-class MemoryHolder : public base::RefCounted<MemoryHolder> {
- public:
-  MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory,
-               gfx::Size frame_size,
-               base::Callback<void()> callback)
-      : shared_memory_(shared_memory.Pass()),
-        frame_size_(frame_size),
-        callback_(callback) {}
-
-  void GetMailbox(cc::TextureMailbox* mailbox,
-                  scoped_ptr<cc::SingleReleaseCallback>* release_callback) {
-    *mailbox = cc::TextureMailbox(shared_memory_.get(), frame_size_);
-    *release_callback = cc::SingleReleaseCallback::Create(
-        base::Bind(ReleaseMailbox, make_scoped_refptr(this)));
-  }
-
- private:
-  friend class base::RefCounted<MemoryHolder>;
-  ~MemoryHolder() { callback_.Run(); }
-
-  scoped_ptr<base::SharedMemory> shared_memory_;
-  gfx::Size frame_size_;
-  base::Callback<void()> callback_;
-};
-
 namespace {
 
 void MailboxReleaseCallback(scoped_ptr<base::SharedMemory> shared_memory,
@@ -173,7 +144,7 @@
 
   if (GetProp(window, kWidgetOwnerProperty) == widget) {
     HWND parent =
-        widget->GetNativeView()->GetRootWindow()->GetAcceleratedWidget();
+        widget->GetNativeView()->GetDispatcher()->GetAcceleratedWidget();
     SetParent(window, parent);
   }
   return TRUE;
@@ -195,7 +166,7 @@
   if (GetProp(window, kWidgetOwnerProperty) == params->widget) {
     // First calculate the offset of this plugin from the root window, since
     // the cutouts are relative to the root window.
-    HWND parent = params->widget->GetNativeView()->GetRootWindow()->
+    HWND parent = params->widget->GetNativeView()->GetDispatcher()->
         GetAcceleratedWidget();
     POINT offset;
     offset.x = offset.y = 0;
@@ -398,13 +369,13 @@
   explicit EventFilterForPopupExit(RenderWidgetHostViewAura* rwhva)
       : rwhva_(rwhva) {
     DCHECK(rwhva_);
-    aura::RootWindow* root_window = rwhva_->window_->GetRootWindow();
+    aura::Window* root_window = rwhva_->window_->GetRootWindow();
     DCHECK(root_window);
     root_window->AddPreTargetHandler(this);
   }
 
   virtual ~EventFilterForPopupExit() {
-    aura::RootWindow* root_window = rwhva_->window_->GetRootWindow();
+    aura::Window* root_window = rwhva_->window_->GetRootWindow();
     DCHECK(root_window);
     root_window->RemovePreTargetHandler(this);
   }
@@ -533,7 +504,7 @@
   }
 
   aura::Window* GetToplevelWindow() {
-    aura::RootWindow* root = view_->window_->GetRootWindow();
+    aura::Window* root = view_->window_->GetRootWindow();
     if (!root)
       return NULL;
     aura::client::ActivationClient* activation_client =
@@ -603,7 +574,9 @@
       can_lock_compositor_(YES),
       cursor_visibility_state_in_renderer_(UNKNOWN),
       paint_observer_(NULL),
-      touch_editing_client_(NULL) {
+      touch_editing_client_(NULL),
+      delegated_frame_evictor_(new DelegatedFrameEvictor(this)),
+      weak_ptr_factory_(this) {
   host_->SetView(this);
   window_observer_.reset(new WindowObserver(this));
   aura::client::SetTooltipText(window_, &tooltip_);
@@ -614,6 +587,8 @@
 #if defined(OS_WIN)
   transient_observer_.reset(new TransientWindowObserver(this));
 #endif
+  software_frame_manager_.reset(new SoftwareFrameManager(
+      weak_ptr_factory_.GetWeakPtr()));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -645,20 +620,10 @@
   window_->Init(ui::LAYER_TEXTURED);
   window_->SetName("RenderWidgetHostViewAura");
 
-  aura::RootWindow* root = popup_parent_host_view_->window_->GetRootWindow();
-  window_->SetDefaultParentByRootWindow(root, bounds_in_screen);
+  aura::Window* root = popup_parent_host_view_->window_->GetRootWindow();
+  aura::client::ParentWindowWithContext(window_, root, bounds_in_screen);
 
-  // TODO(erg): While I could make sure details of the StackingClient are
-  // hidden behind aura, hiding the details of the ScreenPositionClient will
-  // take another effort.
-  aura::client::ScreenPositionClient* screen_position_client =
-      aura::client::GetScreenPositionClient(root);
-  gfx::Point origin_in_parent(bounds_in_screen.origin());
-  if (screen_position_client) {
-    screen_position_client->ConvertPointFromScreen(
-        window_->parent(), &origin_in_parent);
-  }
-  SetBounds(gfx::Rect(origin_in_parent, bounds_in_screen.size()));
+  SetBounds(bounds_in_screen);
   Show();
 }
 
@@ -670,7 +635,7 @@
   window_->SetName("RenderWidgetHostViewAura");
   window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
 
-  aura::RootWindow* parent = NULL;
+  aura::Window* parent = NULL;
   gfx::Rect bounds;
   if (reference_host_view) {
     aura::Window* reference_window =
@@ -684,7 +649,7 @@
     parent = reference_window->GetRootWindow();
     bounds = display.bounds();
   }
-  window_->SetDefaultParentByRootWindow(parent, bounds);
+  aura::client::ParentWindowWithContext(window_, parent, bounds);
   Show();
   Focus();
 }
@@ -698,10 +663,10 @@
   if (!host_->is_hidden())
     return;
   host_->WasShown();
-  if (framebuffer_holder_)
-    FrameMemoryManager::GetInstance()->SetFrameVisibility(this, true);
+  software_frame_manager_->SetVisibility(true);
+  delegated_frame_evictor_->SetVisible(true);
 
-  aura::RootWindow* root = window_->GetRootWindow();
+  aura::Window* root = window_->GetRootWindow();
   if (root) {
     aura::client::CursorClient* cursor_client =
         aura::client::GetCursorClient(root);
@@ -727,15 +692,14 @@
   if (!host_ || host_->is_hidden())
     return;
   host_->WasHidden();
-  if (framebuffer_holder_)
-    FrameMemoryManager::GetInstance()->SetFrameVisibility(this, false);
-
+  software_frame_manager_->SetVisibility(false);
+  delegated_frame_evictor_->SetVisible(false);
   released_front_lock_ = NULL;
 
 #if defined(OS_WIN)
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (root_window) {
-    HWND parent = root_window->GetAcceleratedWidget();
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (dispatcher) {
+    HWND parent = dispatcher->GetAcceleratedWidget();
     LPARAM lparam = reinterpret_cast<LPARAM>(this);
 
     EnumChildWindows(parent, HideWindowsCallback, lparam);
@@ -744,30 +708,38 @@
 }
 
 void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) {
-  SetBounds(gfx::Rect(window_->bounds().origin(), size));
+  // For a SetSize operation, we don't care what coordinate system the origin
+  // of the window is in, it's only important to make sure that the origin
+  // remains constant after the operation.
+  InternalSetBounds(gfx::Rect(window_->bounds().origin(), size));
 }
 
 void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) {
-  if (HasDisplayPropertyChanged(window_))
-    host_->InvalidateScreenInfo();
+  gfx::Point relative_origin(rect.origin());
 
-  window_->SetBounds(rect);
-  host_->WasResized();
-  MaybeCreateResizeLock();
-  if (touch_editing_client_) {
-    touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
-        selection_focus_rect_);
+  // RenderWidgetHostViewAura::SetBounds() takes screen coordinates, but
+  // Window::SetBounds() takes parent coordinates, so do the conversion here.
+  aura::Window* root = window_->GetRootWindow();
+  if (root) {
+    aura::client::ScreenPositionClient* screen_position_client =
+        aura::client::GetScreenPositionClient(root);
+    if (screen_position_client) {
+      screen_position_client->ConvertPointFromScreen(
+          window_->parent(), &relative_origin);
+    }
   }
+
+  InternalSetBounds(gfx::Rect(relative_origin, rect.size()));
 }
 
 void RenderWidgetHostViewAura::MaybeCreateResizeLock() {
   if (!ShouldCreateResizeLock())
     return;
-  DCHECK(window_->GetRootWindow());
-  DCHECK(window_->GetRootWindow()->compositor());
+  DCHECK(window_->GetDispatcher());
+  DCHECK(window_->GetDispatcher()->compositor());
 
   // Listen to changes in the compositor lock state.
-  ui::Compositor* compositor = window_->GetRootWindow()->compositor();
+  ui::Compositor* compositor = window_->GetDispatcher()->compositor();
   if (!compositor->HasObserver(this))
     compositor->AddObserver(this);
 
@@ -805,11 +777,11 @@
   if (desired_size == current_frame_size_)
     return false;
 
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (!root_window)
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (!dispatcher)
     return false;
 
-  ui::Compositor* compositor = root_window->compositor();
+  ui::Compositor* compositor = dispatcher->compositor();
   if (!compositor)
     return false;
 
@@ -820,7 +792,7 @@
     bool defer_compositor_lock) {
   gfx::Size desired_size = window_->bounds().size();
   return scoped_ptr<ResizeLock>(new CompositorResizeLock(
-      window_->GetRootWindow(),
+      window_->GetDispatcher(),
       desired_size,
       defer_compositor_lock,
       base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs)));
@@ -832,9 +804,9 @@
 
 gfx::NativeViewId RenderWidgetHostViewAura::GetNativeViewId() const {
 #if defined(OS_WIN)
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (root_window) {
-    HWND window = root_window->GetAcceleratedWidget();
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (dispatcher) {
+    HWND window = dispatcher->GetAcceleratedWidget();
     return reinterpret_cast<gfx::NativeViewId>(window);
   }
 #endif
@@ -843,10 +815,10 @@
 
 gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() {
 #if defined(OS_WIN)
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (!root_window)
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (!dispatcher)
     return static_cast<gfx::NativeViewAccessible>(NULL);
-  HWND hwnd = root_window->GetAcceleratedWidget();
+  HWND hwnd = dispatcher->GetAcceleratedWidget();
 
   BrowserAccessibilityManager* manager =
       GetOrCreateBrowserAccessibilityManager();
@@ -865,10 +837,10 @@
     return manager;
 
 #if defined(OS_WIN)
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (!root_window)
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (!dispatcher)
     return NULL;
-  HWND hwnd = root_window->GetAcceleratedWidget();
+  HWND hwnd = dispatcher->GetAcceleratedWidget();
 
   // The accessible_parent may be NULL at this point. The WebContents will pass
   // it down to this instance (by way of the RenderViewHost and
@@ -899,7 +871,7 @@
     DCHECK(plugin_window_moves.empty());
     return;
   }
-  HWND parent = window_->GetRootWindow()->GetAcceleratedWidget();
+  HWND parent = window_->GetDispatcher()->GetAcceleratedWidget();
   gfx::Rect view_bounds = window_->GetBoundsInRootWindow();
   std::vector<WebPluginGeometry> moves = plugin_window_moves;
 
@@ -1074,7 +1046,7 @@
     SchedulePaintIfNotInClip(scroll_rect, clip_rect);
 
 #if defined(OS_WIN)
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
 #endif
   for (size_t i = 0; i < copy_rects.size(); ++i) {
     gfx::Rect rect = gfx::SubtractRects(copy_rects[i], scroll_rect);
@@ -1084,12 +1056,12 @@
     SchedulePaintIfNotInClip(rect, clip_rect);
 
 #if defined(OS_WIN)
-    if (root_window) {
+    if (dispatcher) {
       // Send the invalid rect in screen coordinates.
       gfx::Rect screen_rect = GetViewBounds();
       gfx::Rect invalid_screen_rect(rect);
       invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
-      HWND hwnd = root_window->GetAcceleratedWidget();
+      HWND hwnd = dispatcher->GetAcceleratedWidget();
       PaintPluginWindowsHelper(hwnd, invalid_screen_rect);
     }
 #endif  // defined(OS_WIN)
@@ -1112,7 +1084,7 @@
 
 void RenderWidgetHostViewAura::SetTooltipText(const string16& tooltip_text) {
   tooltip_ = tooltip_text;
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   aura::client::TooltipClient* tooltip_client =
       aura::client::GetTooltipClient(root_window);
   if (tooltip_client) {
@@ -1158,7 +1130,7 @@
 }
 
 void RenderWidgetHostViewAura::ScrollOffsetChanged() {
-  aura::RootWindow* root = window_->GetRootWindow();
+  aura::Window* root = window_->GetRootWindow();
   if (!root)
     return;
   aura::client::CursorClient* cursor_client =
@@ -1260,6 +1232,19 @@
   return size_in_dip != resize_lock_->expected_size();
 }
 
+void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
+  if (HasDisplayPropertyChanged(window_))
+    host_->InvalidateScreenInfo();
+
+  window_->SetBounds(rect);
+  host_->WasResized();
+  MaybeCreateResizeLock();
+  if (touch_editing_client_) {
+    touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
+      selection_focus_rect_);
+  }
+}
+
 void RenderWidgetHostViewAura::CheckResizeLock() {
   if (!resize_lock_ || resize_lock_->expected_size() != current_frame_size_)
     return;
@@ -1288,12 +1273,12 @@
     current_frame_size_ = ConvertSizeToDIP(
         current_surface_->device_scale_factor(), current_surface_->size());
     CheckResizeLock();
-    framebuffer_holder_ = NULL;
-    FrameMemoryManager::GetInstance()->RemoveFrame(this);
-  } else if (is_compositing_active && framebuffer_holder_) {
+    software_frame_manager_->DiscardCurrentFrame();
+  } else if (is_compositing_active &&
+             software_frame_manager_->HasCurrentFrame()) {
     cc::TextureMailbox mailbox;
     scoped_ptr<cc::SingleReleaseCallback> callback;
-    framebuffer_holder_->GetMailbox(&mailbox, &callback);
+    software_frame_manager_->GetCurrentFrameMailbox(&mailbox, &callback);
     window_->layer()->SetTextureMailbox(mailbox,
                                         callback.Pass(),
                                         last_swapped_surface_scale_factor_);
@@ -1304,8 +1289,7 @@
     window_->layer()->SetShowPaintedContent();
     resize_lock_.reset();
     host_->WasResized();
-    framebuffer_holder_ = NULL;
-    FrameMemoryManager::GetInstance()->RemoveFrame(this);
+    software_frame_manager_->DiscardCurrentFrame();
   }
 }
 
@@ -1393,7 +1377,7 @@
 void RenderWidgetHostViewAura::UpdateCutoutRects() {
   if (!window_->GetRootWindow())
     return;
-  HWND parent = window_->GetRootWindow()->GetAcceleratedWidget();
+  HWND parent = window_->GetDispatcher()->GetAcceleratedWidget();
   CutoutRectsParams params;
   params.widget = this;
   params.cutout_rects.assign(transient_rects_.begin(), transient_rects_.end());
@@ -1440,8 +1424,7 @@
   gfx::Rect damage_rect_in_dip =
       ConvertRectToDIP(frame_device_scale_factor, damage_rect);
 
-  framebuffer_holder_ = NULL;
-  FrameMemoryManager::GetInstance()->RemoveFrame(this);
+  software_frame_manager_->DiscardCurrentFrame();
 
   if (ShouldSkipFrame(frame_size_in_dip)) {
     cc::CompositorFrameAck ack;
@@ -1472,8 +1455,7 @@
     // resources from the old one with resources from the new one which would
     // have the same id. Changing the layer to showing painted content destroys
     // the DelegatedRendererLayer.
-    window_->layer()->SetShowPaintedContent();
-    frame_provider_ = NULL;
+    EvictDelegatedFrame();
 
     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
     // any resources from the old output surface with the new output surface id.
@@ -1489,8 +1471,7 @@
   }
   if (frame_size.IsEmpty()) {
     DCHECK_EQ(0u, frame_data->resource_list.size());
-    window_->layer()->SetShowPaintedContent();
-    frame_provider_ = NULL;
+    EvictDelegatedFrame();
   } else {
     if (!resource_collection_) {
       resource_collection_ = new cc::DelegatedFrameResourceCollection;
@@ -1526,6 +1507,9 @@
                    output_surface_id));
   }
   DidReceiveFrameFromRenderer();
+  if (frame_provider_.get())
+    delegated_frame_evictor_->SwappedFrame(!host_->is_hidden());
+  // Note: the frame may have been evicted immediately.
 }
 
 void RenderWidgetHostViewAura::SendDelegatedFrameAck(uint32 output_surface_id) {
@@ -1560,6 +1544,12 @@
       ack);
 }
 
+void RenderWidgetHostViewAura::EvictDelegatedFrame() {
+  window_->layer()->SetShowPaintedContent();
+  frame_provider_ = NULL;
+  delegated_frame_evictor_->DiscardedFrame();
+}
+
 void RenderWidgetHostViewAura::SwapSoftwareFrame(
     uint32 output_surface_id,
     scoped_ptr<cc::SoftwareFrameData> frame_data,
@@ -1575,18 +1565,13 @@
     return;
   }
 
-  const size_t size_in_bytes = 4 * frame_size.GetArea();
-#ifdef OS_WIN
-  scoped_ptr<base::SharedMemory> shared_memory(
-      new base::SharedMemory(frame_data->handle, true,
-                             host_->GetProcess()->GetHandle()));
-#else
-  scoped_ptr<base::SharedMemory> shared_memory(
-      new base::SharedMemory(frame_data->handle, true));
-#endif
-
-  if (!shared_memory->Map(size_in_bytes)) {
-    host_->GetProcess()->ReceivedBadMessage();
+  if (!software_frame_manager_->SwapToNewFrame(
+          output_surface_id,
+          frame_data.get(),
+          frame_device_scale_factor,
+          host_->GetProcess()->GetHandle())) {
+    ReleaseSoftwareFrame(output_surface_id, frame_data->id);
+    SendSoftwareFrameAck(output_surface_id);
     return;
   }
 
@@ -1597,17 +1582,9 @@
   last_swapped_surface_size_ = frame_size;
   last_swapped_surface_scale_factor_ = frame_device_scale_factor;
 
-  scoped_refptr<MemoryHolder> holder(new MemoryHolder(
-      shared_memory.Pass(),
-      frame_size,
-      base::Bind(&RenderWidgetHostViewAura::ReleaseSoftwareFrame,
-                 AsWeakPtr(),
-                 output_surface_id,
-                 frame_data->id)));
-  framebuffer_holder_.swap(holder);
   cc::TextureMailbox mailbox;
   scoped_ptr<cc::SingleReleaseCallback> callback;
-  framebuffer_holder_->GetMailbox(&mailbox, &callback);
+  software_frame_manager_->GetCurrentFrameMailbox(&mailbox, &callback);
   DCHECK(mailbox.IsSharedMemory());
   current_frame_size_ = frame_size_in_dip;
 
@@ -1630,7 +1607,8 @@
   if (paint_observer_)
     paint_observer_->OnUpdateCompositorContent();
   DidReceiveFrameFromRenderer();
-  FrameMemoryManager::GetInstance()->AddFrame(this, !host_->is_hidden());
+
+  software_frame_manager_->SwapToNewFrameComplete(!host_->is_hidden());
 }
 
 void RenderWidgetHostViewAura::SendSoftwareFrameAck(uint32 output_surface_id) {
@@ -1738,8 +1716,7 @@
     const BufferPresentedCallback& ack_callback) {
   scoped_refptr<ui::Texture> previous_texture(current_surface_);
   const gfx::Rect surface_rect = gfx::Rect(surface_size);
-  framebuffer_holder_ = NULL;
-  FrameMemoryManager::GetInstance()->RemoveFrame(this);
+  software_frame_manager_->DiscardCurrentFrame();
 
   if (!SwapBuffersPrepare(surface_rect,
                           surface_scale_factor,
@@ -1832,8 +1809,7 @@
       // We need to wait for a commit to clear to guarantee that all we
       // will not issue any more GL referencing the previous surface.
       AddOnCommitCallbackAndDisableLocks(
-          base::Bind(&RenderWidgetHostViewAura::
-                     SetSurfaceNotInUseByCompositor,
+          base::Bind(&RenderWidgetHostViewAura::SetSurfaceNotInUseByCompositor,
                      AsWeakPtr(),
                      current_surface_));  // Hold a ref so the texture will not
                                           // get deleted until after commit.
@@ -1899,10 +1875,10 @@
 
   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
-                    dst_size_in_pixel.width(), dst_size_in_pixel.height());
+                    dst_size_in_pixel.width(), dst_size_in_pixel.height(),
+                    0, kOpaque_SkAlphaType);
   if (!bitmap->allocPixels())
     return;
-  bitmap->setIsOpaque(true);
 
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
   GLHelper* gl_helper = factory->GetGLHelper();
@@ -2078,7 +2054,7 @@
                                              video_frame->coded_size(),
                                              region_in_frame,
                                              true,
-                                             false));
+                                             true));
     yuv_readback_pipeline = rwhva->yuv_readback_pipeline_.get();
   }
 
@@ -2105,10 +2081,10 @@
   RECT window_rect = {0};
 
   aura::Window* top_level = window_->GetToplevelWindow();
-  aura::RootWindow* root_window = top_level->GetRootWindow();
-  if (!root_window)
+  aura::WindowEventDispatcher* dispatcher = top_level->GetDispatcher();
+  if (!dispatcher)
     return top_level->GetBoundsInScreen();
-  HWND hwnd = root_window->GetAcceleratedWidget();
+  HWND hwnd = dispatcher->GetAcceleratedWidget();
   ::GetWindowRect(hwnd, &window_rect);
   gfx::Rect rect(window_rect);
 
@@ -2140,16 +2116,16 @@
                                            SCREEN_COORDINATES))
     return;
 
-  aura::RootWindow* root = window_->GetRootWindow();
-  // |root| is NULL during tests.
-  if (!root)
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  // |dispatcher| is NULL during tests.
+  if (!dispatcher)
     return;
 
   ui::EventResult result = (ack_result ==
       INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
   for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
       end = events.end(); iter != end; ++iter) {
-    root->ProcessedTouchEvent((*iter), window_, result);
+    dispatcher->ProcessedTouchEvent((*iter), window_, result);
   }
 }
 
@@ -2194,7 +2170,7 @@
 }
 
 bool RenderWidgetHostViewAura::LockMouse() {
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (!root_window)
     return false;
 
@@ -2222,7 +2198,7 @@
 }
 
 void RenderWidgetHostViewAura::UnlockMouse() {
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (!mouse_locked_ || !root_window)
     return;
 
@@ -2331,7 +2307,7 @@
   gfx::Point origin = rect.origin();
   gfx::Point end = gfx::Point(rect.right(), rect.bottom());
 
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (!root_window)
     return rect;
   aura::client::ScreenPositionClient* screen_position_client =
@@ -2351,7 +2327,7 @@
   gfx::Point origin = rect.origin();
   gfx::Point end = gfx::Point(rect.right(), rect.bottom());
 
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (root_window) {
     aura::client::ScreenPositionClient* screen_position_client =
         aura::client::GetScreenPositionClient(root_window);
@@ -2597,7 +2573,7 @@
   if (!window_->GetRootWindow() || host_->is_hidden()) {
     parent = ui::GetHiddenWindow();
   } else {
-    parent = window_->GetRootWindow()->GetAcceleratedWidget();
+    parent = window_->GetDispatcher()->GetAcceleratedWidget();
   }
   LPARAM lparam = reinterpret_cast<LPARAM>(this);
   EnumChildWindows(parent, WindowDestroyingCallback, lparam);
@@ -2801,9 +2777,9 @@
     // We get mouse wheel/scroll messages even if we are not in the foreground.
     // So here we check if we have any owned popup windows in the foreground and
     // dismiss them.
-    aura::RootWindow* root_window = window_->GetRootWindow();
-    if (root_window) {
-      HWND parent = root_window->GetAcceleratedWidget();
+    aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+    if (dispatcher) {
+      HWND parent = dispatcher->GetAcceleratedWidget();
       HWND toplevel_hwnd = ::GetAncestor(parent, GA_ROOT);
       EnumThreadWindows(GetCurrentThreadId(),
                         DismissOwnedPopups,
@@ -2958,10 +2934,10 @@
 // RenderWidgetHostViewAura, aura::client::ActivationDelegate implementation:
 
 bool RenderWidgetHostViewAura::ShouldActivate() const {
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  if (!root_window)
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  if (!dispatcher)
     return true;
-  const ui::Event* event = root_window->current_event();
+  const ui::Event* event = dispatcher->current_event();
   if (!event)
     return true;
   return is_fullscreen_;
@@ -2975,7 +2951,7 @@
                                                  aura::Window* lost_active) {
   DCHECK(window_ == gained_active || window_ == lost_active);
   if (window_ == gained_active) {
-    const ui::Event* event = window_->GetRootWindow()->current_event();
+    const ui::Event* event = window_->GetDispatcher()->current_event();
     if (event && PointerEventActivates(*event))
       host_->OnPointerEventActivate();
   }
@@ -3052,16 +3028,21 @@
   UpdateScreenInfo(window_);
 }
 
-void RenderWidgetHostViewAura::ReleaseCurrentFrame() {
-  if (framebuffer_holder_.get() && !current_surface_.get()) {
-    framebuffer_holder_ = NULL;
-    ui::Compositor* compositor = GetCompositor();
-    if (compositor) {
-      AddOnCommitCallbackAndDisableLocks(base::Bind(
-          &RenderWidgetHostViewAura::SendReclaimSoftwareFrames, AsWeakPtr()));
-    }
-    UpdateExternalTexture();
+////////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewAura, SoftwareFrameManagerClient implementation:
+
+void RenderWidgetHostViewAura::SoftwareFrameWasFreed(
+    uint32 output_surface_id, unsigned frame_id) {
+  ReleaseSoftwareFrame(output_surface_id, frame_id);
+}
+
+void RenderWidgetHostViewAura::ReleaseReferencesToSoftwareFrame() {
+  ui::Compositor* compositor = GetCompositor();
+  if (compositor) {
+    AddOnCommitCallbackAndDisableLocks(base::Bind(
+        &RenderWidgetHostViewAura::SendReclaimSoftwareFrames, AsWeakPtr()));
   }
+  UpdateExternalTexture();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -3215,10 +3196,10 @@
 #if defined(OS_WIN)
   transient_observer_.reset();
 #endif
-  if (window_->GetRootWindow())
-    window_->GetRootWindow()->RemoveRootWindowObserver(this);
+  if (window_->GetDispatcher())
+    window_->GetDispatcher()->RemoveRootWindowObserver(this);
   UnlockMouse();
-  if (popup_type_ != WebKit::WebPopupTypeNone && popup_parent_host_view_) {
+  if (popup_parent_host_view_) {
     DCHECK(popup_parent_host_view_->popup_child_host_view_ == NULL ||
            popup_parent_host_view_->popup_child_host_view_ == this);
     popup_parent_host_view_->popup_child_host_view_ = NULL;
@@ -3235,10 +3216,6 @@
   // Aura root window and we don't have a way to get an input method object
   // associated with the window, but just in case.
   DetachFromInputMethod();
-  FrameMemoryManager::GetInstance()->RemoveFrame(this);
-  // The destruction of the holder may call back into the RWHVA, so do it
-  // early.
-  framebuffer_holder_ = NULL;
 
   if (resource_collection_.get())
     resource_collection_->SetClient(NULL);
@@ -3247,7 +3224,7 @@
 void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
   const gfx::Point screen_point =
       gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (!root_window)
     return;
 
@@ -3259,7 +3236,8 @@
   // If there's another toplevel window above us at this point (for example a
   // menu), we don't want to update the cursor.
   POINT windows_point = { screen_point.x(), screen_point.y() };
-  if (root_window->GetAcceleratedWidget() != ::WindowFromPoint(windows_point))
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  if (dispatcher->GetAcceleratedWidget() != ::WindowFromPoint(windows_point))
     return;
 #endif
   if (root_window->GetEventHandlerForPoint(local_point) != window_)
@@ -3278,7 +3256,7 @@
 }
 
 ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const {
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   if (!root_window)
     return NULL;
   return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
@@ -3387,7 +3365,7 @@
 }
 
 void RenderWidgetHostViewAura::AddedToRootWindow() {
-  window_->GetRootWindow()->AddRootWindowObserver(this);
+  window_->GetDispatcher()->AddRootWindowObserver(this);
   host_->ParentChanged(GetNativeViewId());
   UpdateScreenInfo(window_);
   if (popup_type_ != WebKit::WebPopupTypeNone)
@@ -3410,7 +3388,7 @@
     cursor_client->RemoveObserver(this);
 
   event_filter_for_popup_exit_.reset();
-  window_->GetRootWindow()->RemoveRootWindowObserver(this);
+  window_->GetDispatcher()->RemoveRootWindowObserver(this);
   host_->ParentChanged(0);
   ui::Compositor* compositor = GetCompositor();
   if (current_surface_.get()) {
@@ -3429,8 +3407,8 @@
 }
 
 ui::Compositor* RenderWidgetHostViewAura::GetCompositor() const {
-  aura::RootWindow* root_window = window_->GetRootWindow();
-  return root_window ? root_window->compositor() : NULL;
+  aura::WindowEventDispatcher* dispatcher = window_->GetDispatcher();
+  return dispatcher ? dispatcher->compositor() : NULL;
 }
 
 void RenderWidgetHostViewAura::DetachFromInputMethod() {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 77b5db4..2a5c4f2 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -20,8 +20,9 @@
 #include "cc/resources/texture_mailbox.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/aura/image_transport_factory.h"
-#include "content/browser/renderer_host/frame_memory_manager.h"
+#include "content/browser/renderer_host/delegated_frame_evictor.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/renderer_host/software_frame_manager.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "third_party/skia/include/core/SkRegion.h"
@@ -59,7 +60,6 @@
 }
 
 namespace content {
-class MemoryHolder;
 class RenderWidgetHostImpl;
 class RenderWidgetHostView;
 class ResizeLock;
@@ -78,7 +78,8 @@
       public aura::client::CursorClientObserver,
       public ImageTransportFactoryObserver,
       public BrowserAccessibilityDelegate,
-      public FrameContainer,
+      public SoftwareFrameManagerClient,
+      public DelegatedFrameEvictorClient,
       public base::SupportsWeakPtr<RenderWidgetHostViewAura>,
       public cc::DelegatedFrameResourceCollectionClient {
  public:
@@ -332,8 +333,10 @@
   virtual void OnRootWindowHostMoved(const aura::RootWindow* root,
                                      const gfx::Point& new_origin) OVERRIDE;
 
-  // FrameContainer implementation:
-  virtual void ReleaseCurrentFrame() OVERRIDE;
+  // SoftwareFrameManagerClient implementation:
+  virtual void SoftwareFrameWasFreed(
+      uint32 output_surface_id, unsigned frame_id) OVERRIDE;
+  virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE;
 
   bool CanCopyToBitmap() const;
 
@@ -387,6 +390,8 @@
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
                            SkippedDelegatedFrames);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange);
+  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
+                           DiscardDelegatedFrames);
 
   class WindowObserver;
   friend class WindowObserver;
@@ -413,6 +418,11 @@
   void UpdateCursorIfOverSelf();
   bool ShouldSkipFrame(gfx::Size size_in_dip) const;
 
+  // Set the bounds of the window and handle size changes.  Assumes the caller
+  // has already adjusted the origin of |rect| to conform to whatever coordinate
+  // space is required by the aura::Window.
+  void InternalSetBounds(const gfx::Rect& rect);
+
   // Lazily grab a resize lock if the aura window size doesn't match the current
   // frame size, to give time to the renderer.
   void MaybeCreateResizeLock();
@@ -526,6 +536,9 @@
   void SendDelegatedFrameAck(uint32 output_surface_id);
   void SendReturnedDelegatedResources(uint32 output_surface_id);
 
+  // DelegatedFrameEvictorClient implementation.
+  virtual void EvictDelegatedFrame() OVERRIDE;
+
   // cc::DelegatedFrameProviderClient implementation.
   virtual void UnusedResourcesAreAvailable() OVERRIDE;
 
@@ -613,8 +626,8 @@
   // The current frontbuffer texture.
   scoped_refptr<ui::Texture> current_surface_;
 
-  // This holds the current software framebuffer.
-  scoped_refptr<MemoryHolder> framebuffer_holder_;
+  // This holds the current software framebuffer, if any.
+  scoped_ptr<SoftwareFrameManager> software_frame_manager_;
 
   // With delegated renderer, this is the last output surface, used to
   // disambiguate resources with the same id coming from different output
@@ -753,7 +766,9 @@
     unsigned frame_id;
   };
   scoped_ptr<ReleasedFrameInfo> released_software_frame_;
+  scoped_ptr<DelegatedFrameEvictor> delegated_frame_evictor_;
 
+  base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
 };
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index eb197d6..88669e0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -25,6 +25,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/layout_manager.h"
 #include "ui/aura/root_window.h"
@@ -36,6 +38,7 @@
 #include "ui/aura/window_observer.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/compositor.h"
+#include "ui/compositor/test/test_context_factory.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 
@@ -43,6 +46,36 @@
 
 namespace content {
 namespace {
+
+// Simple screen position client to test coordinate system conversion.
+class TestScreenPositionClient
+    : public aura::client::ScreenPositionClient {
+ public:
+  TestScreenPositionClient() {}
+  virtual ~TestScreenPositionClient() {}
+
+  // aura::client::ScreenPositionClient overrides:
+  virtual void ConvertPointToScreen(const aura::Window* window,
+      gfx::Point* point) OVERRIDE {
+    point->Offset(-1, -1);
+  }
+
+  virtual void ConvertPointFromScreen(const aura::Window* window,
+      gfx::Point* point) OVERRIDE {
+    point->Offset(1, 1);
+  }
+
+  virtual void ConvertHostPointToScreen(aura::Window* window,
+      gfx::Point* point) OVERRIDE {
+    ConvertPointToScreen(window, point);
+  }
+
+  virtual void SetBounds(aura::Window* window,
+      const gfx::Rect& bounds,
+      const gfx::Display& display) OVERRIDE {
+  }
+};
+
 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
  public:
   MockRenderWidgetHostDelegate() {}
@@ -100,7 +133,7 @@
   }
 
   void RunOnCompositingDidCommit() {
-    OnCompositingDidCommit(window()->GetRootWindow()->compositor());
+    OnCompositingDidCommit(window()->GetDispatcher()->compositor());
   }
 
   // A lock that doesn't actually do anything to the compositor, and does not
@@ -121,26 +154,27 @@
       : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
 
   virtual void SetUp() {
-    ImageTransportFactory::InitializeForUnitTests();
+    ImageTransportFactory::InitializeForUnitTests(
+        scoped_ptr<ui::ContextFactory>(new ui::TestContextFactory));
     aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
     aura_test_helper_->SetUp();
 
     browser_context_.reset(new TestBrowserContext);
-    MockRenderProcessHost* process_host =
-        new MockRenderProcessHost(browser_context_.get());
+    process_host_ = new MockRenderProcessHost(browser_context_.get());
 
-    sink_ = &process_host->sink();
+    sink_ = &process_host_->sink();
 
     parent_host_ = new RenderWidgetHostImpl(
-        &delegate_, process_host, MSG_ROUTING_NONE, false);
+        &delegate_, process_host_, MSG_ROUTING_NONE, false);
     parent_view_ = static_cast<RenderWidgetHostViewAura*>(
         RenderWidgetHostView::CreateViewForWidget(parent_host_));
     parent_view_->InitAsChild(NULL);
-    parent_view_->GetNativeView()->SetDefaultParentByRootWindow(
-        aura_test_helper_->root_window(), gfx::Rect());
+    aura::client::ParentWindowWithContext(parent_view_->GetNativeView(),
+                                          aura_test_helper_->root_window(),
+                                          gfx::Rect());
 
     widget_host_ = new RenderWidgetHostImpl(
-        &delegate_, process_host, MSG_ROUTING_NONE, false);
+        &delegate_, process_host_, MSG_ROUTING_NONE, false);
     widget_host_->Init();
     widget_host_->OnMessageReceived(
         ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
@@ -149,6 +183,7 @@
 
   virtual void TearDown() {
     sink_ = NULL;
+    process_host_ = NULL;
     if (view_)
       view_->Destroy();
     delete widget_host_;
@@ -170,6 +205,7 @@
   scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
   scoped_ptr<BrowserContext> browser_context_;
   MockRenderWidgetHostDelegate delegate_;
+  MockRenderProcessHost* process_host_;
 
   // Tests should set these to NULL if they've already triggered their
   // destruction.
@@ -245,6 +281,44 @@
   EXPECT_TRUE(view_->ShouldActivate());
 }
 
+// Checks that a popup is positioned correctly relative to its parent using
+// screen coordinates.
+TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) {
+  TestScreenPositionClient screen_position_client;
+
+  aura::Window* window = parent_view_->GetNativeView();
+  aura::Window* root = window->GetRootWindow();
+  aura::client::SetScreenPositionClient(root, &screen_position_client);
+
+  parent_view_->SetBounds(gfx::Rect(10, 10, 800, 600));
+  gfx::Rect bounds_in_screen = parent_view_->GetViewBounds();
+  int horiz = bounds_in_screen.width() / 4;
+  int vert = bounds_in_screen.height() / 4;
+  bounds_in_screen.Inset(horiz, vert);
+
+  // Verify that when the popup is initialized for the first time, it correctly
+  // treats the input bounds as screen coordinates.
+  view_->InitAsPopup(parent_view_, bounds_in_screen);
+
+  gfx::Rect final_bounds_in_screen = view_->GetViewBounds();
+  EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
+
+  // Verify that directly setting the bounds via SetBounds() treats the input
+  // as screen coordinates.
+  bounds_in_screen = gfx::Rect(60, 60, 100, 100);
+  view_->SetBounds(bounds_in_screen);
+  final_bounds_in_screen = view_->GetViewBounds();
+  EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
+
+  // Verify that setting the size does not alter the origin.
+  gfx::Point original_origin = window->bounds().origin();
+  view_->SetSize(gfx::Size(120, 120));
+  gfx::Point new_origin = window->bounds().origin();
+  EXPECT_EQ(original_origin.ToString(), new_origin.ToString());
+
+  aura::client::SetScreenPositionClient(root, NULL);
+}
+
 // Checks that a fullscreen view is destroyed when it loses the focus.
 TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
   view_->InitAsFullscreen(parent_view_);
@@ -465,8 +539,10 @@
 
 TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
   view_->InitAsChild(NULL);
-  view_->GetNativeView()->SetDefaultParentByRootWindow(
-      parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(),
+      parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
   sink_->ClearMessages();
   view_->SetSize(gfx::Size(100, 100));
   EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
@@ -523,8 +599,10 @@
 // to the renderer at the correct times.
 TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
   view_->InitAsChild(NULL);
-  view_->GetNativeView()->SetDefaultParentByRootWindow(
-      parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(),
+      parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
   view_->SetSize(gfx::Size(100, 100));
 
   aura::test::TestCursorClient cursor_client(
@@ -699,8 +777,10 @@
   gfx::Rect view_rect(view_size);
 
   view_->InitAsChild(NULL);
-  view_->GetNativeView()->SetDefaultParentByRootWindow(
-      parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(),
+      parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
   view_->SetSize(view_size);
   view_->WasShown();
 
@@ -787,8 +867,10 @@
   gfx::Size frame_size = view_rect.size();
 
   view_->InitAsChild(NULL);
-  view_->GetNativeView()->SetDefaultParentByRootWindow(
-      parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(),
+      parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
   view_->SetSize(view_rect.size());
 
   MockWindowObserver observer;
@@ -858,8 +940,10 @@
   gfx::Size frame_size = view_rect.size();
 
   view_->InitAsChild(NULL);
-  view_->GetNativeView()->SetDefaultParentByRootWindow(
-      parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(),
+      parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
   view_->SetSize(view_rect.size());
 
   MockWindowObserver observer;
@@ -895,4 +979,103 @@
   view_->window_->RemoveObserver(&observer);
 }
 
+TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
+  size_t max_renderer_frames =
+      RendererFrameManager::GetInstance()->max_number_of_saved_frames();
+  ASSERT_LE(2u, max_renderer_frames);
+  size_t renderer_count = max_renderer_frames + 1;
+  gfx::Rect view_rect(100, 100);
+  gfx::Size frame_size = view_rect.size();
+
+  scoped_ptr<RenderWidgetHostImpl * []> hosts(
+      new RenderWidgetHostImpl* [renderer_count]);
+  scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
+      new FakeRenderWidgetHostViewAura* [renderer_count]);
+
+  // Create a bunch of renderers.
+  for (size_t i = 0; i < renderer_count; ++i) {
+    hosts[i] = new RenderWidgetHostImpl(
+        &delegate_, process_host_, MSG_ROUTING_NONE, false);
+    hosts[i]->Init();
+    hosts[i]->OnMessageReceived(
+        ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
+    views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
+    views[i]->InitAsChild(NULL);
+    aura::client::ParentWindowWithContext(
+        views[i]->GetNativeView(),
+        parent_view_->GetNativeView()->GetRootWindow(),
+        gfx::Rect());
+    views[i]->SetSize(view_rect.size());
+  }
+
+  // Make each renderer visible, and swap a frame on it, then make it invisible.
+  for (size_t i = 0; i < renderer_count; ++i) {
+    views[i]->WasShown();
+    views[i]->OnSwapCompositorFrame(
+        1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+    EXPECT_TRUE(views[i]->frame_provider_);
+    views[i]->WasHidden();
+  }
+
+  // There should be max_renderer_frames with a frame in it, and one without it.
+  // Since the logic is LRU eviction, the first one should be without.
+  EXPECT_FALSE(views[0]->frame_provider_);
+  for (size_t i = 1; i < renderer_count; ++i)
+    EXPECT_TRUE(views[i]->frame_provider_);
+
+  // LRU renderer is [0], make it visible, it shouldn't evict anything yet.
+  views[0]->WasShown();
+  EXPECT_FALSE(views[0]->frame_provider_);
+  EXPECT_TRUE(views[1]->frame_provider_);
+
+  // Swap a frame on it, it should evict the next LRU [1].
+  views[0]->OnSwapCompositorFrame(
+      1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+  EXPECT_TRUE(views[0]->frame_provider_);
+  EXPECT_FALSE(views[1]->frame_provider_);
+  views[0]->WasHidden();
+
+  // LRU renderer is [1], still hidden. Swap a frame on it, it should evict
+  // the next LRU [2].
+  views[1]->OnSwapCompositorFrame(
+      1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+  EXPECT_TRUE(views[0]->frame_provider_);
+  EXPECT_TRUE(views[1]->frame_provider_);
+  EXPECT_FALSE(views[2]->frame_provider_);
+  for (size_t i = 3; i < renderer_count; ++i)
+    EXPECT_TRUE(views[i]->frame_provider_);
+
+  // Make all renderers but [0] visible and swap a frame on them, keep [0]
+  // hidden, it becomes the LRU.
+  for (size_t i = 1; i < renderer_count; ++i) {
+    views[i]->WasShown();
+    views[i]->OnSwapCompositorFrame(
+        1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+    EXPECT_TRUE(views[i]->frame_provider_);
+  }
+  EXPECT_FALSE(views[0]->frame_provider_);
+
+  // Swap a frame on [0], it should be evicted immediately.
+  views[0]->OnSwapCompositorFrame(
+      1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+  EXPECT_FALSE(views[0]->frame_provider_);
+
+  // Make [0] visible, and swap a frame on it. Nothing should be evicted
+  // although we're above the limit.
+  views[0]->WasShown();
+  views[0]->OnSwapCompositorFrame(
+      1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+  for (size_t i = 0; i < renderer_count; ++i)
+    EXPECT_TRUE(views[i]->frame_provider_);
+
+  // Make [0] hidden, it should evict its frame.
+  views[0]->WasHidden();
+  EXPECT_FALSE(views[0]->frame_provider_);
+
+  for (size_t i = 0; i < renderer_count; ++i) {
+    views[i]->Destroy();
+    delete hosts[i];
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 4f1e7a8..199d58a 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -591,9 +591,9 @@
     SkBitmap bitmap;
     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
                      video_frame->visible_rect().width(),
-                     video_frame->visible_rect().height());
+                     video_frame->visible_rect().height(),
+                     0, kOpaque_SkAlphaType);
     bitmap.allocPixels();
-    bitmap.setIsOpaque(true);
 
     SkBitmapDevice device(bitmap);
     SkCanvas canvas(&device);
diff --git a/content/browser/renderer_host/render_widget_host_view_guest.cc b/content/browser/renderer_host/render_widget_host_view_guest.cc
index 9d0cb8d..87765b5 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_guest.cc
@@ -402,7 +402,8 @@
   RenderWidgetHostViewPort* embedder_view =
       RenderWidgetHostViewPort::FromRWHV(
           guest_->GetEmbedderRenderWidgetHostView());
-  embedder_view->GetScreenInfo(results);
+  if (embedder_view)
+    embedder_view->GetScreenInfo(results);
 }
 
 void RenderWidgetHostViewGuest::OnAccessibilityEvents(
@@ -514,7 +515,7 @@
   return true;
 }
 
-void RenderWidgetHostViewGuest::DispatchLongPressGestureEvent(
+void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent(
     ui::GestureEvent* event) {
   ForwardGestureEventToRenderer(event);
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_guest.h b/content/browser/renderer_host/render_widget_host_view_guest.h
index c69321b..c050aaa 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest.h
+++ b/content/browser/renderer_host/render_widget_host_view_guest.h
@@ -187,7 +187,7 @@
 
   // Overridden from ui::GestureEventHelper.
   virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
-  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchPostponedGestureEvent(ui::GestureEvent* event) OVERRIDE;
   virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
  protected:
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 6a9caaa..da16bc2 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -18,6 +18,7 @@
 #include "base/time/time.h"
 #include "content/browser/accessibility/browser_accessibility_delegate_mac.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/renderer_host/software_frame_manager.h"
 #include "content/common/edit_command.h"
 #import "content/public/browser/render_widget_host_view_mac_base.h"
 #include "ipc/ipc_sender.h"
@@ -196,7 +197,8 @@
 //
 // RenderWidgetHostView class hierarchy described in render_widget_host_view.h.
 class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
-                                public IPC::Sender {
+                                public IPC::Sender,
+                                public SoftwareFrameManagerClient {
  public:
   virtual ~RenderWidgetHostViewMac();
 
@@ -283,6 +285,8 @@
   virtual void BeginFrameSubscription(
       scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE;
   virtual void EndFrameSubscription() OVERRIDE;
+  virtual void OnSwapCompositorFrame(
+      uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
   virtual void OnAcceleratedCompositingStateChange() OVERRIDE;
   virtual void OnAccessibilityEvents(
       const std::vector<AccessibilityHostMsg_EventParams>& params
@@ -316,6 +320,11 @@
   // IPC::Sender implementation.
   virtual bool Send(IPC::Message* message) OVERRIDE;
 
+  // SoftwareFrameManagerClient implementation:
+  virtual void SoftwareFrameWasFreed(
+      uint32 output_surface_id, unsigned frame_id) OVERRIDE;
+  virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE;
+
   // Forwards the mouse event to the renderer.
   void ForwardMouseEvent(const WebKit::WebMouseEvent& event);
 
@@ -412,6 +421,9 @@
   scoped_ptr<CompositingIOSurfaceMac> compositing_iosurface_;
   scoped_refptr<CompositingIOSurfaceContext> compositing_iosurface_context_;
 
+  // This holds the current software compositing framebuffer, if any.
+  scoped_ptr<SoftwareFrameManager> software_frame_manager_;
+
   // Whether to allow overlapping views.
   bool allow_overlapping_views_;
 
@@ -552,6 +564,8 @@
   // Subscriber that listens to frame presentation events.
   scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
 
+  base::WeakPtrFactory<RenderWidgetHostViewMac>
+      software_frame_weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
 };
 
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 02c66aa..71dfb16 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -46,6 +46,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #import "content/public/browser/render_widget_host_view_mac_delegate.h"
+#include "content/public/browser/user_metrics.h"
 #include "content/public/common/content_switches.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -426,7 +427,10 @@
       weak_factory_(this),
       fullscreen_parent_host_view_(NULL),
       pending_swap_buffers_acks_weak_factory_(this),
-      next_swap_ack_time_(base::Time::Now()) {
+      next_swap_ack_time_(base::Time::Now()),
+      software_frame_weak_ptr_factory_(this) {
+  software_frame_manager_.reset(new SoftwareFrameManager(
+      software_frame_weak_ptr_factory_.GetWeakPtr()));
   // |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
   // goes away.  Since we autorelease it, our caller must put
   // |GetNativeView()| into the view hierarchy right after calling us.
@@ -732,6 +736,7 @@
   if (web_contents_switch_paint_time_.is_null())
     web_contents_switch_paint_time_ = base::TimeTicks::Now();
   render_widget_host_->WasShown();
+  software_frame_manager_->SetVisibility(true);
 
   // We're messing with the window, so do this to ensure no flashes.
   if (!use_core_animation_)
@@ -751,6 +756,7 @@
   // If we have a renderer, then inform it that we are being hidden so it can
   // reduce its resource utilization.
   render_widget_host_->WasHidden();
+  software_frame_manager_->SetVisibility(false);
 
   // There can be a transparent flash as this view is removed and the next is
   // added, because of OSX windowing races between displaying the contents of
@@ -1650,17 +1656,50 @@
 
 bool RenderWidgetHostViewMac::HasAcceleratedSurface(
       const gfx::Size& desired_size) {
-  return last_frame_was_accelerated_ &&
-         compositing_iosurface_ &&
-         compositing_iosurface_->HasIOSurface() &&
-         (desired_size.IsEmpty() ||
-          compositing_iosurface_->dip_io_surface_size() == desired_size);
+  if (last_frame_was_accelerated_) {
+    return compositing_iosurface_ &&
+           compositing_iosurface_->HasIOSurface() &&
+           (desired_size.IsEmpty() ||
+               compositing_iosurface_->dip_io_surface_size() == desired_size);
+  } else {
+    return (software_frame_manager_->HasCurrentFrame() &&
+           (desired_size.IsEmpty() ||
+               software_frame_manager_->GetCurrentFrameSizeInDIP() ==
+                   desired_size));
+  }
+  return false;
 }
 
 void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() {
   AckPendingSwapBuffers();
 }
 
+void RenderWidgetHostViewMac::OnSwapCompositorFrame(
+    uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) {
+  // Only software compositor frames are accepted.
+  if (!frame->software_frame_data) {
+    DLOG(ERROR) << "Received unexpected frame type.";
+    RecordAction(
+        UserMetricsAction("BadMessageTerminate_UnexpectedFrameType"));
+    render_widget_host_->GetProcess()->ReceivedBadMessage();
+    return;
+  }
+
+  GotSoftwareFrame();
+  if (!software_frame_manager_->SwapToNewFrame(
+          output_surface_id,
+          frame->software_frame_data.get(),
+          frame->metadata.device_scale_factor,
+          render_widget_host_->GetProcess()->GetHandle())) {
+    render_widget_host_->GetProcess()->ReceivedBadMessage();
+    return;
+  }
+  software_frame_manager_->SwapToNewFrameComplete(
+      !render_widget_host_->is_hidden());
+
+  [cocoa_view_ setNeedsDisplay:YES];
+}
+
 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() {
 }
 
@@ -1741,6 +1780,19 @@
   return false;
 }
 
+void RenderWidgetHostViewMac::SoftwareFrameWasFreed(
+    uint32 output_surface_id, unsigned frame_id) {
+  cc::CompositorFrameAck ack;
+  ack.last_software_frame_id = frame_id;
+  RenderWidgetHostImpl::SendReclaimCompositorResources(
+      render_widget_host_->GetRoutingID(),
+      output_surface_id,
+      render_widget_host_->GetProcess()->GetID(),
+      ack);
+}
+
+void RenderWidgetHostViewMac::ReleaseReferencesToSoftwareFrame() {
+}
 
 void RenderWidgetHostViewMac::ShutdownHost() {
   weak_factory_.InvalidateWeakPtrs();
@@ -1764,6 +1816,7 @@
 
     // Delete software backingstore.
     BackingStoreManager::RemoveBackingStore(render_widget_host_);
+    software_frame_manager_->DiscardCurrentFrame();
   }
 }
 
@@ -2718,29 +2771,62 @@
 - (void)drawBackingStore:(BackingStoreMac*)backingStore
                dirtyRect:(CGRect)dirtyRect
                inContext:(CGContextRef)context {
-  if (backingStore) {
+  content::SoftwareFrameManager* software_frame_manager =
+      renderWidgetHostView_->software_frame_manager_.get();
+  // There should never be both a legacy software and software composited
+  // frame.
+  DCHECK(!backingStore || !software_frame_manager->HasCurrentFrame());
+
+  if (backingStore || software_frame_manager->HasCurrentFrame()) {
     // Note: All coordinates are in view units, not pixels.
-    gfx::Rect bitmapRect(0, 0,
-                         backingStore->size().width(),
-                         backingStore->size().height());
+    gfx::Rect bitmapRect(
+        software_frame_manager->HasCurrentFrame() ?
+            software_frame_manager->GetCurrentFrameSizeInDIP() :
+            backingStore->size());
 
     // Specify the proper y offset to ensure that the view is rooted to the
     // upper left corner.  This can be negative, if the window was resized
     // smaller and the renderer hasn't yet repainted.
-    int yOffset = NSHeight([self bounds]) - backingStore->size().height();
+    int yOffset = NSHeight([self bounds]) - bitmapRect.height();
 
     NSRect nsDirtyRect = NSRectFromCGRect(dirtyRect);
     const gfx::Rect damagedRect([self flipNSRectToRect:nsDirtyRect]);
 
     gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect);
     if (!paintRect.IsEmpty()) {
-      // if we have a CGLayer, draw that into the window
-      if (backingStore->cg_layer()) {
+      if (software_frame_manager->HasCurrentFrame()) {
+        // If a software compositor framebuffer is present, draw using that.
+        gfx::Size sizeInPixels =
+            software_frame_manager->GetCurrentFrameSizeInPixels();
+        base::ScopedCFTypeRef<CGDataProviderRef> dataProvider(
+            CGDataProviderCreateWithData(
+                NULL,
+                software_frame_manager->GetCurrentFramePixels(),
+                4 * sizeInPixels.width() * sizeInPixels.height(),
+                NULL));
+        base::ScopedCFTypeRef<CGImageRef> image(
+            CGImageCreate(
+                sizeInPixels.width(),
+                sizeInPixels.height(),
+                8,
+                32,
+                4 * sizeInPixels.width(),
+                base::mac::GetSystemColorSpace(),
+                kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+                dataProvider,
+                NULL,
+                false,
+                kCGRenderingIntentDefault));
+        CGRect imageRect = bitmapRect.ToCGRect();
+        imageRect.origin.y = yOffset;
+        CGContextDrawImage(context, imageRect, image);
+      } else if (backingStore->cg_layer()) {
+        // If we have a CGLayer, draw that into the window
         // TODO: add clipping to dirtyRect if it improves drawing performance.
         CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset),
                                   backingStore->cg_layer());
       } else {
-        // if we haven't created a layer yet, draw the cached bitmap into
+        // If we haven't created a layer yet, draw the cached bitmap into
         // the window.  The CGLayer will be created the next time the renderer
         // paints.
         base::ScopedCFTypeRef<CGImageRef> image(
diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc
index 1f382f4..97ec948 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc
@@ -324,7 +324,7 @@
 
   WebKit::WebScreenInfo screen_info;
   screen_info.depth = dev_mode.dmBitsPerPel;
-  screen_info.depthPerComponent = dev_mode.dmBitsPerPel / 3;  // Assumes RGB
+  screen_info.depthPerComponent = 8;
   screen_info.deviceScaleFactor = gfx::win::GetDeviceScaleFactor();
   screen_info.isMonochrome = dev_mode.dmColor == DMCOLOR_MONOCHROME;
   screen_info.rect = gfx::Rect(monitor_info.rcMonitor);
@@ -500,7 +500,7 @@
 }
 
 void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) {
-  if (being_destroyed_ || render_widget_host_->is_hidden())
+  if (being_destroyed_)
     return;
 
   // No SWP_NOREDRAW as autofill popups can move and the underneath window
@@ -951,7 +951,7 @@
   return true;
 }
 
-void RenderWidgetHostViewWin::DispatchLongPressGestureEvent(
+void RenderWidgetHostViewWin::DispatchPostponedGestureEvent(
     ui::GestureEvent* event) {
   ForwardGestureEventToRenderer(event);
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_win.h b/content/browser/renderer_host/render_widget_host_view_win.h
index 7b13a60..fc48414 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.h
+++ b/content/browser/renderer_host/render_widget_host_view_win.h
@@ -260,7 +260,7 @@
 
   // Overridden from ui::GestureEventHelper.
   virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
-  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchPostponedGestureEvent(ui::GestureEvent* event) OVERRIDE;
   virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
   // Overridden from ui::TextInputClient for Win8/metro TSF support.
diff --git a/content/browser/renderer_host/render_widget_host_view_win_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_win_browsertest.cc
deleted file mode 100644
index fc73601..0000000
--- a/content/browser/renderer_host/render_widget_host_view_win_browsertest.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) 2012 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 <vector>
-
-#include "base/command_line.h"
-#include "base/win/metro.h"
-#include "content/browser/renderer_host/render_widget_host_view_win.h"
-#include "content/public/browser/render_view_host.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 "content/shell/browser/shell.h"
-#include "content/test/content_browser_test.h"
-#include "content/test/content_browser_test_utils.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ime/win/imm32_manager.h"
-#include "ui/base/ime/win/mock_tsf_bridge.h"
-#include "ui/base/ime/win/tsf_bridge.h"
-
-namespace content {
-namespace {
-
-class MockIMM32Manager : public ui::IMM32Manager {
- public:
-   MockIMM32Manager()
-       : window_handle_(NULL),
-         input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
-         call_count_(0) {
-   }
-  virtual ~MockIMM32Manager() {}
-
-  virtual void SetTextInputMode(HWND window_handle,
-                                ui::TextInputMode input_mode) OVERRIDE {
-    ++call_count_;
-    window_handle_ = window_handle;
-    input_mode_ = input_mode;
-  }
-
-  void Reset() {
-    window_handle_ = NULL;
-    input_mode_ = ui::TEXT_INPUT_MODE_DEFAULT;
-    call_count_ = 0;
-  }
-
-  HWND window_handle() const { return window_handle_; }
-  ui::TextInputMode input_mode() const { return input_mode_; }
-  size_t call_count() const { return call_count_; }
-
- private:
-  HWND window_handle_;
-  ui::TextInputMode input_mode_;
-  size_t call_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockIMM32Manager);
-};
-
-// Testing class serving initialized RenderWidgetHostViewWin instance;
-class RenderWidgetHostViewWinBrowserTest : public ContentBrowserTest {
- public:
-  RenderWidgetHostViewWinBrowserTest() {}
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    ContentBrowserTest::SetUpOnMainThread();
-
-    NavigateToURL(shell(), GURL("about:blank"));
-
-    view_ = static_cast<RenderWidgetHostViewWin*>(
-        RenderWidgetHostViewPort::FromRWHV(
-            shell()->web_contents()->GetRenderViewHost()->GetView()));
-    CHECK(view_);
-  }
-
- protected:
-  RenderWidgetHostViewWin* view_;
-};
-
-}  // namespace
-
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinBrowserTest,
-                       TextInputTypeChanged) {
-  ASSERT_TRUE(view_->m_hWnd);
-
-  MockIMM32Manager* mock = new MockIMM32Manager();
-  mock->Reset();
-  view_->imm32_manager_.reset(mock);
-  view_->TextInputTypeChanged(ui::TEXT_INPUT_TYPE_NONE,
-                              ui::TEXT_INPUT_MODE_EMAIL, false);
-
-  EXPECT_EQ(1, mock->call_count());
-  EXPECT_EQ(view_->m_hWnd, mock->window_handle());
-  EXPECT_EQ(ui::TEXT_INPUT_MODE_EMAIL, mock->input_mode());
-
-  mock->Reset();
-  view_->TextInputTypeChanged(ui::TEXT_INPUT_TYPE_NONE,
-                              ui::TEXT_INPUT_MODE_EMAIL, false);
-  EXPECT_EQ(0, mock->call_count());
-}
-
-class RenderWidgetHostViewWinTSFTest : public ContentBrowserTest {
- public:
-  RenderWidgetHostViewWinTSFTest() {}
-
-  virtual void SetUpCommandLine(CommandLine* command_line) {
-    command_line->AppendSwitch(switches::kEnableTextServicesFramework);
-  }
-};
-
-// crbug.com/151798
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTSFTest,
-                       DISABLED_SwichToPasswordField) {
-  ui::MockTSFBridge mock_bridge;
-  ui::TSFBridge* old_bridge = ui::TSFBridge::ReplaceForTesting(&mock_bridge);
-  GURL test_url = GetTestUrl("textinput", "ime_enable_disable_test.html");
-
-  NavigateToURL(shell(), test_url);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
-
-  // Focus to the text field, the IME should be enabled.
-  bool success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(text01_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
-
-  // Focus to the password field, the IME should be disabled.
-  success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(password02_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
-
-  ui::TSFBridge::ReplaceForTesting(old_bridge);
-}
-
-// crbug.com/151798
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTSFTest,
-                       DISABLED_SwitchToSameField) {
-  ui::MockTSFBridge mock_bridge;
-  ui::TSFBridge* old_bridge = ui::TSFBridge::ReplaceForTesting(&mock_bridge);
-  GURL test_url = GetTestUrl("textinput", "ime_enable_disable_test.html");
-
-  NavigateToURL(shell(), test_url);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
-
-  // Focus to the text field, the IME should be enabled.
-  bool success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(text01_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
-
-  // Focus to another text field, the IME should be enabled.
-  success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(text02_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
-
-  ui::TSFBridge::ReplaceForTesting(old_bridge);
-}
-
-// crbug.com/151798
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTSFTest,
-                       DISABLED_SwitchToSamePasswordField) {
-  ui::MockTSFBridge mock_bridge;
-  ui::TSFBridge* old_bridge = ui::TSFBridge::ReplaceForTesting(&mock_bridge);
-  GURL test_url = GetTestUrl("textinput", "ime_enable_disable_test.html");
-
-  NavigateToURL(shell(), test_url);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
-
-  // Focus to the password field, the IME should be disabled.
-  bool success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(password01_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
-
-  // Focus to the another password field, the IME should be disabled.
-  success = false;
-  EXPECT_TRUE(ExecuteScriptAndExtractBool(
-      shell()->web_contents(),
-      "window.domAutomationController.send(password02_focus());",
-      &success));
-  EXPECT_TRUE(success);
-  WaitForLoadStop(shell()->web_contents());
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
-
-  ui::TSFBridge::ReplaceForTesting(old_bridge);
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/renderer_frame_manager.cc b/content/browser/renderer_host/renderer_frame_manager.cc
new file mode 100644
index 0000000..3d16361
--- /dev/null
+++ b/content/browser/renderer_host/renderer_frame_manager.cc
@@ -0,0 +1,60 @@
+// Copyright 2013 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/renderer_host/renderer_frame_manager.h"
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+
+namespace content {
+
+RendererFrameManager* RendererFrameManager::GetInstance() {
+  return Singleton<RendererFrameManager>::get();
+}
+
+void RendererFrameManager::AddFrame(RendererFrameManagerClient* frame,
+                                    bool visible) {
+  RemoveFrame(frame);
+  if (visible)
+    visible_frames_.insert(frame);
+  else
+    hidden_frames_.push_front(frame);
+  CullHiddenFrames();
+}
+
+void RendererFrameManager::RemoveFrame(RendererFrameManagerClient* frame) {
+  visible_frames_.erase(frame);
+  hidden_frames_.remove(frame);
+}
+
+void RendererFrameManager::SetFrameVisibility(RendererFrameManagerClient* frame,
+                                              bool visible) {
+  if (visible) {
+    hidden_frames_.remove(frame);
+    visible_frames_.insert(frame);
+  } else {
+    visible_frames_.erase(frame);
+    hidden_frames_.push_front(frame);
+    CullHiddenFrames();
+  }
+}
+
+RendererFrameManager::RendererFrameManager()
+    : max_number_of_saved_frames_(
+          std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256))) {}
+
+RendererFrameManager::~RendererFrameManager() {}
+
+void RendererFrameManager::CullHiddenFrames() {
+  while (!hidden_frames_.empty() &&
+         hidden_frames_.size() + visible_frames_.size() >
+             max_number_of_saved_frames()) {
+    size_t old_size = hidden_frames_.size();
+    // Should remove self from list.
+    hidden_frames_.back()->EvictCurrentFrame();
+    DCHECK_EQ(hidden_frames_.size() + 1, old_size);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/renderer_frame_manager.h b/content/browser/renderer_host/renderer_frame_manager.h
new file mode 100644
index 0000000..134e1ef
--- /dev/null
+++ b/content/browser/renderer_host/renderer_frame_manager.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_RENDERER_FRAME_MANAGER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RENDERER_FRAME_MANAGER_H_
+
+#include <list>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/memory/singleton.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT RendererFrameManagerClient {
+ public:
+  virtual ~RendererFrameManagerClient() {}
+  virtual void EvictCurrentFrame() = 0;
+};
+
+class CONTENT_EXPORT RendererFrameManager {
+ public:
+  static RendererFrameManager* GetInstance();
+
+  void AddFrame(RendererFrameManagerClient*, bool visible);
+  void RemoveFrame(RendererFrameManagerClient*);
+  void SetFrameVisibility(RendererFrameManagerClient*, bool visible);
+
+  size_t max_number_of_saved_frames() const {
+    return max_number_of_saved_frames_;
+  }
+
+ private:
+  RendererFrameManager();
+  ~RendererFrameManager();
+  void CullHiddenFrames();
+  friend struct DefaultSingletonTraits<RendererFrameManager>;
+
+  std::set<RendererFrameManagerClient*> visible_frames_;
+  std::list<RendererFrameManagerClient*> hidden_frames_;
+  size_t max_number_of_saved_frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(RendererFrameManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_RENDERER_FRAME_MANAGER_H_
diff --git a/content/browser/renderer_host/software_frame_manager.cc b/content/browser/renderer_host/software_frame_manager.cc
new file mode 100644
index 0000000..b36c750
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager.cc
@@ -0,0 +1,221 @@
+// Copyright 2013 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/renderer_host/software_frame_manager.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/debug/alias.h"
+#include "content/browser/renderer_host/dip_util.h"
+#include "content/public/browser/user_metrics.h"
+
+namespace {
+
+void ReleaseMailbox(scoped_refptr<content::SoftwareFrame> frame,
+                    unsigned sync_point,
+                    bool lost_resource) {}
+
+}  // namespace
+
+namespace content {
+
+// Keep a count of how many memory buffers are in existence.
+// TODO(jbauman): remove once we have enough info.
+static int g_outstanding_buffers;
+
+#if defined(OS_WIN)
+unsigned int g_crash_count;
+
+// Capture a stack dump.
+// TODO(jbauman): Remove this terrible layering violation once we have some
+// dumps. http://crbug.com/311792
+void DumpWithoutCrashing() {
+  if (++g_crash_count > 2)
+    return;
+  int saved_buffers = g_outstanding_buffers;
+  base::debug::Alias(static_cast<void*>(&saved_buffers));
+  // Get the breakpad pointer from chrome.exe
+  typedef void(__cdecl * DumpProcessFunction)();
+  DumpProcessFunction DumpProcess =
+      reinterpret_cast<DumpProcessFunction>(::GetProcAddress(
+          ::GetModuleHandle(L"chrome.exe"), "DumpProcessWithoutCrash"));
+  if (DumpProcess)
+    DumpProcess();
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// SoftwareFrame
+
+class CONTENT_EXPORT SoftwareFrame : public base::RefCounted<SoftwareFrame> {
+ private:
+  friend class base::RefCounted<SoftwareFrame>;
+  friend class SoftwareFrameManager;
+
+  SoftwareFrame(
+    base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
+    uint32 output_surface_id,
+    unsigned frame_id,
+    gfx::Size frame_size_dip,
+    gfx::Size frame_size_pixels,
+    scoped_ptr<base::SharedMemory> shared_memory);
+  ~SoftwareFrame();
+
+  base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client_;
+  const uint32 output_surface_id_;
+  const unsigned frame_id_;
+  const gfx::Size frame_size_dip_;
+  const gfx::Size frame_size_pixels_;
+  scoped_ptr<base::SharedMemory> shared_memory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoftwareFrame);
+};
+
+SoftwareFrame::SoftwareFrame(
+    base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
+    uint32 output_surface_id,
+    unsigned frame_id,
+    gfx::Size frame_size_dip,
+    gfx::Size frame_size_pixels,
+    scoped_ptr<base::SharedMemory> shared_memory)
+    : frame_manager_client_(frame_manager_client),
+      output_surface_id_(output_surface_id),
+      frame_id_(frame_id),
+      frame_size_dip_(frame_size_dip),
+      frame_size_pixels_(frame_size_pixels),
+      shared_memory_(shared_memory.Pass()) {
+  ++g_outstanding_buffers;
+}
+
+SoftwareFrame::~SoftwareFrame() {
+  --g_outstanding_buffers;
+  if (frame_manager_client_) {
+    frame_manager_client_->SoftwareFrameWasFreed(
+        output_surface_id_, frame_id_);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SoftwareFrameManager
+
+SoftwareFrameManager::SoftwareFrameManager(
+    base::WeakPtr<SoftwareFrameManagerClient> client)
+      : client_(client) {}
+
+SoftwareFrameManager::~SoftwareFrameManager() {
+  DiscardCurrentFrame();
+}
+
+bool SoftwareFrameManager::SwapToNewFrame(
+    uint32 output_surface_id,
+    const cc::SoftwareFrameData* frame_data,
+    float frame_device_scale_factor,
+    base::ProcessHandle process_handle) {
+
+#ifdef OS_WIN
+  scoped_ptr<base::SharedMemory> shared_memory(
+      new base::SharedMemory(frame_data->handle, true,
+                             process_handle));
+#else
+  scoped_ptr<base::SharedMemory> shared_memory(
+      new base::SharedMemory(frame_data->handle, true));
+#endif
+
+  // The NULL handle is used in testing.
+  if (base::SharedMemory::IsHandleValid(shared_memory->handle())) {
+    const size_t size_in_bytes = 4 * frame_data->size.GetArea();
+#ifdef OS_WIN
+    if (!shared_memory->Map(0)) {
+      DumpWithoutCrashing();
+      DLOG(ERROR) << "Unable to map renderer memory.";
+      RecordAction(
+          UserMetricsAction("BadMessageTerminate_SharedMemoryManager1"));
+      return false;
+    }
+
+    if (shared_memory->mapped_size() < size_in_bytes) {
+      DumpWithoutCrashing();
+      DLOG(ERROR) << "Shared memory too small for given rectangle";
+      RecordAction(
+          UserMetricsAction("BadMessageTerminate_SharedMemoryManager2"));
+      return false;
+    }
+#else
+    if (!shared_memory->Map(size_in_bytes)) {
+      DLOG(ERROR) << "Unable to map renderer memory.";
+      RecordAction(
+          UserMetricsAction("BadMessageTerminate_SharedMemoryManager1"));
+      return false;
+    }
+#endif
+  }
+
+  scoped_refptr<SoftwareFrame> next_frame(new SoftwareFrame(
+      client_,
+      output_surface_id,
+      frame_data->id,
+      ConvertSizeToDIP(frame_device_scale_factor, frame_data->size),
+      frame_data->size,
+      shared_memory.Pass()));
+  current_frame_.swap(next_frame);
+  return true;
+}
+
+bool SoftwareFrameManager::HasCurrentFrame() const {
+  return current_frame_.get() ? true : false;
+}
+
+void SoftwareFrameManager::DiscardCurrentFrame() {
+  if (!HasCurrentFrame())
+    return;
+  current_frame_ = NULL;
+  RendererFrameManager::GetInstance()->RemoveFrame(this);
+}
+
+void SoftwareFrameManager::SwapToNewFrameComplete(bool visible) {
+  DCHECK(HasCurrentFrame());
+  RendererFrameManager::GetInstance()->AddFrame(this, visible);
+}
+
+void SoftwareFrameManager::SetVisibility(bool visible) {
+  if (HasCurrentFrame()) {
+    RendererFrameManager::GetInstance()->SetFrameVisibility(this, visible);
+  }
+}
+
+void SoftwareFrameManager::GetCurrentFrameMailbox(
+    cc::TextureMailbox* mailbox,
+    scoped_ptr<cc::SingleReleaseCallback>* callback) {
+  DCHECK(HasCurrentFrame());
+  *mailbox = cc::TextureMailbox(
+      current_frame_->shared_memory_.get(), current_frame_->frame_size_pixels_);
+  *callback = cc::SingleReleaseCallback::Create(
+      base::Bind(ReleaseMailbox, current_frame_));
+}
+
+const void* SoftwareFrameManager::GetCurrentFramePixels() const {
+  DCHECK(HasCurrentFrame());
+  DCHECK(base::SharedMemory::IsHandleValid(
+      current_frame_->shared_memory_->handle()));
+  return current_frame_->shared_memory_->memory();
+}
+
+gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInPixels() const {
+  DCHECK(HasCurrentFrame());
+  return current_frame_->frame_size_pixels_;
+}
+
+gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInDIP() const {
+  DCHECK(HasCurrentFrame());
+  return current_frame_->frame_size_dip_;
+}
+
+void SoftwareFrameManager::EvictCurrentFrame() {
+  DCHECK(HasCurrentFrame());
+  DiscardCurrentFrame();
+  if (client_)
+    client_->ReleaseReferencesToSoftwareFrame();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/software_frame_manager.h b/content/browser/renderer_host/software_frame_manager.h
new file mode 100644
index 0000000..503a40d
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager.h
@@ -0,0 +1,77 @@
+// Copyright 2013 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_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
+
+#include <list>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/output/software_frame_data.h"
+#include "cc/resources/single_release_callback.h"
+#include "cc/resources/texture_mailbox.h"
+#include "content/browser/renderer_host/renderer_frame_manager.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+class SoftwareFrame;
+
+class CONTENT_EXPORT SoftwareFrameManagerClient {
+ public:
+  // Called when the memory for the current software frame was freed.
+  virtual void SoftwareFrameWasFreed(
+      uint32 output_surface_id, unsigned frame_id) = 0;
+
+  // Called when the SoftwareFrameMemoryManager has requested that the frame
+  // be evicted. Upon receiving this callback, the client should release any
+  // references that it may hold to the current frame, to ensure that its memory
+  // is freed expediently.
+  virtual void ReleaseReferencesToSoftwareFrame() = 0;
+};
+
+class CONTENT_EXPORT SoftwareFrameManager : public RendererFrameManagerClient {
+ public:
+  explicit SoftwareFrameManager(
+      base::WeakPtr<SoftwareFrameManagerClient> client);
+  virtual ~SoftwareFrameManager();
+
+  // Swaps to a new frame from shared memory. This frame is guaranteed to
+  // not be evicted until SwapToNewFrameComplete is called.
+  bool SwapToNewFrame(
+      uint32 output_surface_id,
+      const cc::SoftwareFrameData* frame_data,
+      float frame_device_scale_factor,
+      base::ProcessHandle process_handle);
+  void SwapToNewFrameComplete(bool visible);
+  void SetVisibility(bool visible);
+  bool HasCurrentFrame() const;
+  void DiscardCurrentFrame();
+  void GetCurrentFrameMailbox(
+      cc::TextureMailbox* mailbox,
+      scoped_ptr<cc::SingleReleaseCallback>* callback);
+  const void* GetCurrentFramePixels() const;
+  gfx::Size GetCurrentFrameSizeInPixels() const;
+  gfx::Size GetCurrentFrameSizeInDIP() const;
+
+ private:
+  // Called by SoftwareFrameMemoryManager to demand that the current frame
+  // be evicted.
+  virtual void EvictCurrentFrame() OVERRIDE;
+
+  base::WeakPtr<SoftwareFrameManagerClient> client_;
+
+  // This holds the current software framebuffer.
+  scoped_refptr<SoftwareFrame> current_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
diff --git a/content/browser/renderer_host/software_frame_manager_unittest.cc b/content/browser/renderer_host/software_frame_manager_unittest.cc
new file mode 100644
index 0000000..e234f57
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager_unittest.cc
@@ -0,0 +1,255 @@
+// Copyright 2013 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/renderer_host/software_frame_manager.h"
+
+#include <vector>
+
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient {
+ public:
+  FakeSoftwareFrameManagerClient()
+      : evicted_count_(0), weak_ptr_factory_(this) {
+    software_frame_manager_.reset(new SoftwareFrameManager(
+        weak_ptr_factory_.GetWeakPtr()));
+  }
+  virtual ~FakeSoftwareFrameManagerClient() {}
+  virtual void SoftwareFrameWasFreed(
+      uint32 output_surface_id, unsigned frame_id) OVERRIDE {
+    freed_frames_.push_back(std::make_pair(output_surface_id, frame_id));
+  }
+  virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE {
+    ++evicted_count_;
+  }
+
+  bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) {
+    cc::SoftwareFrameData frame;
+    frame.id = frame_id;
+    frame.size = gfx::Size(1, 1);
+    frame.damage_rect = gfx::Rect(frame.size);
+    frame.handle = base::SharedMemory::NULLHandle();
+    return software_frame_manager_->SwapToNewFrame(
+        output_surface, &frame, 1.0, base::GetCurrentProcessHandle());
+  }
+
+  SoftwareFrameManager* software_frame_manager() {
+    return software_frame_manager_.get();
+  }
+  size_t freed_frame_count() const { return freed_frames_.size(); }
+  size_t evicted_frame_count() const { return evicted_count_; }
+
+ private:
+  std::vector<std::pair<uint32,unsigned> > freed_frames_;
+  size_t evicted_count_;
+
+  scoped_ptr<SoftwareFrameManager> software_frame_manager_;
+  base::WeakPtrFactory<FakeSoftwareFrameManagerClient>
+      weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFrameManagerClient);
+};
+
+class SoftwareFrameManagerTest : public testing::Test {
+ public:
+  SoftwareFrameManagerTest() {}
+  void AllocateClients(size_t num_clients) {
+    for (size_t i = 0; i < num_clients; ++i)
+      clients_.push_back(new FakeSoftwareFrameManagerClient);
+  }
+  void FreeClients() {
+    for (size_t i = 0; i < clients_.size(); ++i)
+      delete clients_[i];
+    clients_.clear();
+  }
+  size_t MaxNumberOfSavedFrames() const {
+    size_t result =
+        RendererFrameManager::GetInstance()->max_number_of_saved_frames();
+    return result;
+  }
+
+ protected:
+  std::vector<FakeSoftwareFrameManagerClient*> clients_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManagerTest);
+};
+
+TEST_F(SoftwareFrameManagerTest, DoNotEvictVisible) {
+  // Create twice as many frames as are allowed.
+  AllocateClients(2 * MaxNumberOfSavedFrames());
+
+  // Swap a visible frame to all clients_. Because they are all visible,
+  // the should not be evicted.
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    bool swap_result = clients_[i]->SwapToNewFrame(
+        static_cast<uint32>(i), 0);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+
+  // Swap another frame and make sure the original was freed (but not evicted).
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    bool swap_result = clients_[i]->SwapToNewFrame(
+        static_cast<uint32>(i), 1);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+  }
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+  }
+
+  // Mark the frames as nonvisible and make sure they start getting evicted.
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    clients_[i]->software_frame_manager()->SetVisibility(false);
+    if (clients_.size() - i > MaxNumberOfSavedFrames()) {
+      EXPECT_EQ(1u, clients_[i]->evicted_frame_count());
+      EXPECT_EQ(2u, clients_[i]->freed_frame_count());
+    } else {
+      EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+      EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+    }
+  }
+
+  // Clean up.
+  FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, DoNotEvictDuringSwap) {
+  // Create twice as many frames as are allowed.
+  AllocateClients(2 * MaxNumberOfSavedFrames());
+
+  // Swap a visible frame to all clients_. Because they are all visible,
+  // the should not be evicted.
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+
+  // Now create a test non-visible client, and swap a non-visible frame in.
+  scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
+      new FakeSoftwareFrameManagerClient);
+  test_client->software_frame_manager()->SetVisibility(false);
+  {
+    bool swap_result = test_client->SwapToNewFrame(
+        static_cast<uint32>(500), 0);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, test_client->evicted_frame_count());
+    EXPECT_EQ(0u, test_client->freed_frame_count());
+    test_client->software_frame_manager()->SwapToNewFrameComplete(false);
+    EXPECT_EQ(1u, test_client->evicted_frame_count());
+    EXPECT_EQ(1u, test_client->freed_frame_count());
+  }
+
+  // Clean up.
+  FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, Cleanup) {
+  // Create twice as many frames as are allowed.
+  AllocateClients(2 * MaxNumberOfSavedFrames());
+
+  // Swap a visible frame to all clients_. Because they are all visible,
+  // the should not be evicted.
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+
+  // Destroy them.
+  FreeClients();
+
+  // Create the maximum number of frames, all non-visible. They should not
+  // be evicted, because the previous frames were cleaned up at destruction.
+  AllocateClients(MaxNumberOfSavedFrames());
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    cc::SoftwareFrameData frame;
+    bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_TRUE(swap_result);
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+    EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+  }
+
+  // Clean up.
+  FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, EvictVersusFree) {
+  // Create twice as many frames as are allowed and swap a visible frame to all
+  // clients_. Because they are all visible, the should not be evicted.
+  AllocateClients(2 * MaxNumberOfSavedFrames());
+  for (size_t i = 0; i < clients_.size(); ++i) {
+    clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+    clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+  }
+
+  // Create a test client with a frame that is not evicted.
+  scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
+      new FakeSoftwareFrameManagerClient);
+  bool swap_result = test_client->SwapToNewFrame(static_cast<uint32>(500), 0);
+  EXPECT_TRUE(swap_result);
+  test_client->software_frame_manager()->SwapToNewFrameComplete(true);
+  EXPECT_EQ(0u, test_client->evicted_frame_count());
+  EXPECT_EQ(0u, test_client->freed_frame_count());
+
+  // Take out a reference on the current frame and make the memory manager
+  // evict it. The frame will not be freed until this reference is released.
+  cc::TextureMailbox mailbox;
+  scoped_ptr<cc::SingleReleaseCallback> callback;
+  test_client->software_frame_manager()->GetCurrentFrameMailbox(
+      &mailbox, &callback);
+  test_client->software_frame_manager()->SetVisibility(false);
+  EXPECT_EQ(1u, test_client->evicted_frame_count());
+  EXPECT_EQ(0u, test_client->freed_frame_count());
+
+  // Swap a few frames. The frames will be freed as they are swapped out.
+  for (size_t frame = 0; frame < 10; ++frame) {
+    bool swap_result = test_client->SwapToNewFrame(
+        static_cast<uint32>(500), 1 + static_cast<int>(frame));
+    EXPECT_TRUE(swap_result);
+    test_client->software_frame_manager()->SwapToNewFrameComplete(true);
+    EXPECT_EQ(frame, test_client->freed_frame_count());
+    EXPECT_EQ(1u, test_client->evicted_frame_count());
+  }
+
+  // The reference to the frame that we didn't free is in the callback
+  // object. It will go away when the callback is destroyed.
+  EXPECT_EQ(9u, test_client->freed_frame_count());
+  EXPECT_EQ(1u, test_client->evicted_frame_count());
+  callback->Run(0, false);
+  callback.reset();
+  EXPECT_EQ(10u, test_client->freed_frame_count());
+  EXPECT_EQ(1u, test_client->evicted_frame_count());
+
+  FreeClients();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/touch_smooth_scroll_gesture_aura.cc b/content/browser/renderer_host/touch_smooth_scroll_gesture_aura.cc
index 5df932d..659cd99 100644
--- a/content/browser/renderer_host/touch_smooth_scroll_gesture_aura.cc
+++ b/content/browser/renderer_host/touch_smooth_scroll_gesture_aura.cc
@@ -16,16 +16,15 @@
                       ui::EventType type,
                       aura::Window* window) {
   gfx::Point screen_location = location;
+  aura::Window* root_window = window->GetRootWindow();
   // First convert the location from Window to RootWindow.
-  aura::RootWindow* root_window = window->GetRootWindow();
   aura::Window::ConvertPointToTarget(window, root_window, &screen_location);
   // Then convert the location from RootWindow to screen.
-  root_window->ConvertPointToHost(&screen_location);
+  aura::WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+  dispatcher->ConvertPointToHost(&screen_location);
   ui::TouchEvent touch(type, screen_location, 0, 0, ui::EventTimeForNow(),
                        1.0f, 1.0f, 1.0f, 1.0f);
-  aura::RootWindowHostDelegate* root_window_host_delegate =
-        root_window->AsRootWindowHostDelegate();
-  root_window_host_delegate->OnHostTouchEvent(&touch);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&touch);
 }
 
 }  // namespace
diff --git a/content/browser/renderer_host/ui_events_helper.cc b/content/browser/renderer_host/ui_events_helper.cc
index 78a7bff..d1fbcfa 100644
--- a/content/browser/renderer_host/ui_events_helper.cc
+++ b/content/browser/renderer_host/ui_events_helper.cc
@@ -166,6 +166,13 @@
       gesture_event.data.tapDown.height =
           event.details().bounding_box().height();
       break;
+    case ui::ET_GESTURE_SHOW_PRESS:
+      gesture_event.type = WebKit::WebInputEvent::GestureShowPress;
+      gesture_event.data.showPress.width =
+          event.details().bounding_box().width();
+      gesture_event.data.showPress.height =
+          event.details().bounding_box().height();
+      break;
     case ui::ET_GESTURE_TAP_CANCEL:
       gesture_event.type = WebKit::WebInputEvent::GestureTapCancel;
       break;
diff --git a/content/browser/renderer_host/websocket_dispatcher_host.cc b/content/browser/renderer_host/websocket_dispatcher_host.cc
index 902664e..f5e9e96 100644
--- a/content/browser/renderer_host/websocket_dispatcher_host.cc
+++ b/content/browser/renderer_host/websocket_dispatcher_host.cc
@@ -14,6 +14,15 @@
 
 namespace content {
 
+namespace {
+
+// Many methods defined in this file return a WebSocketHostState enum
+// value. Make WebSocketHostState visible at file scope so it doesn't have to be
+// fully-qualified every time.
+typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState;
+
+}  // namespace
+
 WebSocketDispatcherHost::WebSocketDispatcherHost(
     const GetRequestContextCallback& get_context_callback)
     : get_context_callback_(get_context_callback),
@@ -73,45 +82,59 @@
   return it == hosts_.end() ? NULL : it->second;
 }
 
-void WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) {
+WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) {
   if (!Send(message)) {
     DVLOG(1) << "Sending of message type " << message->type()
              << " failed. Dropping channel.";
     DeleteWebSocketHost(message->routing_id());
+    return WEBSOCKET_HOST_DELETED;
   }
+  return WEBSOCKET_HOST_ALIVE;
 }
 
-void WebSocketDispatcherHost::SendAddChannelResponse(
+WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse(
     int routing_id,
     bool fail,
     const std::string& selected_protocol,
     const std::string& extensions) {
-  SendOrDrop(new WebSocketMsg_AddChannelResponse(
-      routing_id, fail, selected_protocol, extensions));
-  if (fail)
+  if (SendOrDrop(new WebSocketMsg_AddChannelResponse(
+          routing_id, fail, selected_protocol, extensions)) ==
+      WEBSOCKET_HOST_DELETED)
+    return WEBSOCKET_HOST_DELETED;
+  if (fail) {
     DeleteWebSocketHost(routing_id);
+    return WEBSOCKET_HOST_DELETED;
+  }
+  return WEBSOCKET_HOST_ALIVE;
 }
 
-void WebSocketDispatcherHost::SendFrame(int routing_id,
-                                        bool fin,
-                                        WebSocketMessageType type,
-                                        const std::vector<char>& data) {
-  SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data));
+WebSocketHostState WebSocketDispatcherHost::SendFrame(
+    int routing_id,
+    bool fin,
+    WebSocketMessageType type,
+    const std::vector<char>& data) {
+  return SendOrDrop(new WebSocketMsg_SendFrame(routing_id, fin, type, data));
 }
 
-void WebSocketDispatcherHost::SendFlowControl(int routing_id, int64 quota) {
-  SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota));
+WebSocketHostState WebSocketDispatcherHost::SendFlowControl(int routing_id,
+                                                            int64 quota) {
+  return SendOrDrop(new WebSocketMsg_FlowControl(routing_id, quota));
 }
 
-void WebSocketDispatcherHost::SendClosing(int routing_id) {
+WebSocketHostState WebSocketDispatcherHost::SendClosing(int routing_id) {
   // TODO(ricea): Implement the SendClosing IPC.
+  return WEBSOCKET_HOST_ALIVE;
 }
 
-void WebSocketDispatcherHost::DoDropChannel(int routing_id,
-                                            uint16 code,
-                                            const std::string& reason) {
-  SendOrDrop(new WebSocketMsg_DropChannel(routing_id, code, reason));
+WebSocketHostState WebSocketDispatcherHost::DoDropChannel(
+    int routing_id,
+    uint16 code,
+    const std::string& reason) {
+  if (SendOrDrop(new WebSocketMsg_DropChannel(routing_id, code, reason)) ==
+      WEBSOCKET_HOST_DELETED)
+    return WEBSOCKET_HOST_DELETED;
   DeleteWebSocketHost(routing_id);
+  return WEBSOCKET_HOST_DELETED;
 }
 
 WebSocketDispatcherHost::~WebSocketDispatcherHost() {
@@ -120,10 +143,9 @@
 
 void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) {
   WebSocketHostTable::iterator it = hosts_.find(routing_id);
-  if (it != hosts_.end()) {
-    delete it->second;
-    hosts_.erase(it);
-  }
+  DCHECK(it != hosts_.end());
+  delete it->second;
+  hosts_.erase(it);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/websocket_dispatcher_host.h b/content/browser/renderer_host/websocket_dispatcher_host.h
index f991486..0572201 100644
--- a/content/browser/renderer_host/websocket_dispatcher_host.h
+++ b/content/browser/renderer_host/websocket_dispatcher_host.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
 #include "content/common/content_export.h"
 #include "content/common/websocket.h"
@@ -33,6 +34,15 @@
   // WebSocketHost or its subclass.
   typedef base::Callback<WebSocketHost*(int)> WebSocketHostFactory;
 
+  // Return value for methods that may delete the WebSocketHost. This enum is
+  // binary-compatible with net::WebSocketEventInterface::ChannelState, to make
+  // conversion cheap. By using a separate enum including net/ header files can
+  // be avoided.
+  enum WebSocketHostState {
+    WEBSOCKET_HOST_ALIVE,
+    WEBSOCKET_HOST_DELETED
+  };
+
   explicit WebSocketDispatcherHost(
       const GetRequestContextCallback& get_context_callback);
 
@@ -48,30 +58,36 @@
 
   // The following methods are used by WebSocketHost::EventInterface to send
   // IPCs from the browser to the renderer or child process. Any of them may
-  // delete the WebSocketHost on failure, leading to the WebSocketChannel and
-  // EventInterface also being deleted.
+  // return WEBSOCKET_HOST_DELETED and delete the WebSocketHost on failure,
+  // leading to the WebSocketChannel and EventInterface also being deleted.
 
   // Sends a WebSocketMsg_AddChannelResponse IPC, and then deletes and
   // unregisters the WebSocketHost if |fail| is true.
-  void SendAddChannelResponse(int routing_id,
-                              bool fail,
-                              const std::string& selected_protocol,
-                              const std::string& extensions);
+  WebSocketHostState SendAddChannelResponse(
+      int routing_id,
+      bool fail,
+      const std::string& selected_protocol,
+      const std::string& extensions) WARN_UNUSED_RESULT;
 
   // Sends a WebSocketMsg_SendFrame IPC.
-  void SendFrame(int routing_id,
-                 bool fin,
-                 WebSocketMessageType type,
-                 const std::vector<char>& data);
+  WebSocketHostState SendFrame(int routing_id,
+                               bool fin,
+                               WebSocketMessageType type,
+                               const std::vector<char>& data);
 
   // Sends a WebSocketMsg_FlowControl IPC.
-  void SendFlowControl(int routing_id, int64 quota);
+  WebSocketHostState SendFlowControl(int routing_id,
+                                     int64 quota) WARN_UNUSED_RESULT;
 
   // Sends a WebSocketMsg_SendClosing IPC
-  void SendClosing(int routing_id);
+  WebSocketHostState SendClosing(int routing_id) WARN_UNUSED_RESULT;
 
-  // Sends a WebSocketMsg_DropChannel IPC and delete and unregister the channel.
-  void DoDropChannel(int routing_id, uint16 code, const std::string& reason);
+  // Sends a WebSocketMsg_DropChannel IPC and deletes and unregisters the
+  // channel.
+  WebSocketHostState DoDropChannel(
+      int routing_id,
+      uint16 code,
+      const std::string& reason) WARN_UNUSED_RESULT;
 
  private:
   typedef base::hash_map<int, WebSocketHost*> WebSocketHostTable;
@@ -85,13 +101,13 @@
   WebSocketHost* GetHost(int routing_id) const;
 
   // Sends the passed in IPC::Message via the BrowserMessageFilter::Send()
-  // method. If the Send() fails, logs it and deletes the corresponding
-  // WebSocketHost object (the client is probably dead).
-  void SendOrDrop(IPC::Message* message);
+  // method. If sending the IPC fails, assumes that this connection is no
+  // longer useable, calls DeleteWebSocketHost(), and returns
+  // WEBSOCKET_HOST_DELETED. The behaviour is the same for all message types.
+  WebSocketHostState SendOrDrop(IPC::Message* message) WARN_UNUSED_RESULT;
 
   // Deletes the WebSocketHost object associated with the given |routing_id| and
-  // removes it from the |hosts_| table. Does nothing if the |routing_id| is
-  // unknown, since SendAddChannelResponse() may call this method twice.
+  // removes it from the |hosts_| table.
   void DeleteWebSocketHost(int routing_id);
 
   // Table of WebSocketHost objects, owned by this object, indexed by
diff --git a/content/browser/renderer_host/websocket_host.cc b/content/browser/renderer_host/websocket_host.cc
index 4284743..4b5faec 100644
--- a/content/browser/renderer_host/websocket_host.cc
+++ b/content/browser/renderer_host/websocket_host.cc
@@ -17,6 +17,8 @@
 
 namespace {
 
+typedef net::WebSocketEventInterface::ChannelState ChannelState;
+
 // Convert a content::WebSocketMessageType to a
 // net::WebSocketFrameHeader::OpCode
 net::WebSocketFrameHeader::OpCode MessageTypeToOpCode(
@@ -48,6 +50,25 @@
   return static_cast<WebSocketMessageType>(opCode);
 }
 
+ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) {
+  const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_ALIVE =
+      WebSocketDispatcherHost::WEBSOCKET_HOST_ALIVE;
+  const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_DELETED =
+      WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED;
+
+  DCHECK(host_state == WEBSOCKET_HOST_ALIVE ||
+         host_state == WEBSOCKET_HOST_DELETED);
+  // These compile asserts verify that we can get away with using static_cast<>
+  // for the conversion.
+  COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_ALIVE) ==
+                     net::WebSocketEventInterface::CHANNEL_ALIVE,
+                 enum_values_must_match_for_state_alive);
+  COMPILE_ASSERT(static_cast<ChannelState>(WEBSOCKET_HOST_DELETED) ==
+                     net::WebSocketEventInterface::CHANNEL_DELETED,
+                 enum_values_must_match_for_state_deleted);
+  return static_cast<ChannelState>(host_state);
+}
+
 // Implementation of net::WebSocketEventInterface. Receives events from our
 // WebSocketChannel object. Each event is translated to an IPC and sent to the
 // renderer or child process via WebSocketDispatcherHost.
@@ -61,16 +82,16 @@
   // TODO(ricea): Add |extensions| parameter to pass the list of enabled
   // WebSocket extensions through to the renderer to make it visible to
   // Javascript.
-  virtual void OnAddChannelResponse(
+  virtual ChannelState OnAddChannelResponse(
       bool fail,
       const std::string& selected_subprotocol) OVERRIDE;
-  virtual void OnDataFrame(bool fin,
-                           WebSocketMessageType type,
-                           const std::vector<char>& data) OVERRIDE;
-  virtual void OnClosingHandshake() OVERRIDE;
-  virtual void OnFlowControl(int64 quota) OVERRIDE;
-  virtual void OnDropChannel(uint16 code,
-                             const std::string& reason) OVERRIDE;
+  virtual ChannelState OnDataFrame(bool fin,
+                                   WebSocketMessageType type,
+                                   const std::vector<char>& data) OVERRIDE;
+  virtual ChannelState OnClosingHandshake() OVERRIDE;
+  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE;
+  virtual ChannelState OnDropChannel(uint16 code,
+                                     const std::string& reason) OVERRIDE;
 
  private:
   WebSocketDispatcherHost* const dispatcher_;
@@ -88,35 +109,32 @@
   DVLOG(1) << "WebSocketEventHandler destroyed routing_id= " << routing_id_;
 }
 
-void WebSocketEventHandler::OnAddChannelResponse(
+ChannelState WebSocketEventHandler::OnAddChannelResponse(
     bool fail,
     const std::string& selected_protocol) {
-  dispatcher_->SendAddChannelResponse(
-      routing_id_, fail, selected_protocol, std::string());
-  // |this| may have been deleted here.
+  return StateCast(dispatcher_->SendAddChannelResponse(
+      routing_id_, fail, selected_protocol, std::string()));
 }
 
-void WebSocketEventHandler::OnDataFrame(bool fin,
-                                        net::WebSocketFrameHeader::OpCode type,
-                                        const std::vector<char>& data) {
-  dispatcher_->SendFrame(routing_id_, fin, OpCodeToMessageType(type), data);
-  // |this| may have been deleted here.
+ChannelState WebSocketEventHandler::OnDataFrame(
+    bool fin,
+    net::WebSocketFrameHeader::OpCode type,
+    const std::vector<char>& data) {
+  return StateCast(dispatcher_->SendFrame(
+      routing_id_, fin, OpCodeToMessageType(type), data));
 }
 
-void WebSocketEventHandler::OnClosingHandshake() {
-  dispatcher_->SendClosing(routing_id_);
-  // |this| may have been deleted here.
+ChannelState WebSocketEventHandler::OnClosingHandshake() {
+  return StateCast(dispatcher_->SendClosing(routing_id_));
 }
 
-void WebSocketEventHandler::OnFlowControl(int64 quota) {
-  dispatcher_->SendFlowControl(routing_id_, quota);
-  // |this| may have been deleted here.
+ChannelState WebSocketEventHandler::OnFlowControl(int64 quota) {
+  return StateCast(dispatcher_->SendFlowControl(routing_id_, quota));
 }
 
-void WebSocketEventHandler::OnDropChannel(uint16 code,
-                                          const std::string& reason) {
-  dispatcher_->DoDropChannel(routing_id_, code, reason);
-  // |this| has been deleted here.
+ChannelState WebSocketEventHandler::OnDropChannel(uint16 code,
+                                                  const std::string& reason) {
+  return StateCast(dispatcher_->DoDropChannel(routing_id_, code, reason));
 }
 
 }  // namespace
diff --git a/content/browser/renderer_host/websocket_host.h b/content/browser/renderer_host/websocket_host.h
index 06f82f7..ffeb0b8 100644
--- a/content/browser/renderer_host/websocket_host.h
+++ b/content/browser/renderer_host/websocket_host.h
@@ -27,8 +27,8 @@
 
 class WebSocketDispatcherHost;
 
-// Host of WebSocketChannel. The lifetime of an instance of this class is
-// completely controlled by the WebSocketDispatcherHost.
+// Host of net::WebSocketChannel. The lifetime of an instance of this class is
+// completely controlled by the WebSocketDispatcherHost object.
 class CONTENT_EXPORT WebSocketHost {
  public:
   WebSocketHost(int routing_id,
diff --git a/content/browser/resource_context_impl.cc b/content/browser/resource_context_impl.cc
index 4480158..c026d93 100644
--- a/content/browser/resource_context_impl.cc
+++ b/content/browser/resource_context_impl.cc
@@ -13,6 +13,7 @@
 #include "content/browser/webui/url_data_manager_backend.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/ssl/client_cert_store.h"
 
 using base::UserDataAdapter;
 
@@ -54,6 +55,10 @@
   DetachUserDataThread();
 }
 
+scoped_ptr<net::ClientCertStore> ResourceContext::CreateClientCertStore() {
+  return scoped_ptr<net::ClientCertStore>();
+}
+
 ChromeBlobStorageContext* GetChromeBlobStorageContextForResourceContext(
     ResourceContext* resource_context) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/content/browser/resources/gpu/gpu_internals.html b/content/browser/resources/gpu/gpu_internals.html
index ad59aa8..ef4def7 100644
--- a/content/browser/resources/gpu/gpu_internals.html
+++ b/content/browser/resources/gpu/gpu_internals.html
@@ -40,8 +40,8 @@
 <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
 <script src="chrome://resources/js/cr/ui/tabs.js"></script>
 <script src="chrome://resources/js/util.js"></script>
-<script src="chrome://gpu/gpu_internals.js"></script>
-<script src="chrome://gpu/strings.js"></script>
+<script src="gpu_internals.js"></script>
+<script src="strings.js"></script>
 </head>
 <body>
   <div id="debug-div">
diff --git a/content/browser/resources/media/media_internals.html b/content/browser/resources/media/media_internals.html
index 6bfc481..16d0c55 100644
--- a/content/browser/resources/media/media_internals.html
+++ b/content/browser/resources/media/media_internals.html
@@ -52,6 +52,6 @@
       </table>
     </div>
   </div>
-  <script src="chrome://media-internals/media_internals.js"></script>
+  <script src="media_internals.js"></script>
 </body>
 </html>
diff --git a/content/browser/resources/media/webrtc_internals.html b/content/browser/resources/media/webrtc_internals.html
index 7257620..53ca9e0 100644
--- a/content/browser/resources/media/webrtc_internals.html
+++ b/content/browser/resources/media/webrtc_internals.html
@@ -5,7 +5,7 @@
     <title>WebRTC Internals</title>
     <link rel="stylesheet" href="webrtc_internals.css">
     <script src="chrome://resources/js/util.js"></script>
-    <script src="chrome://webrtc-internals/webrtc_internals.js"></script>
+    <script src="webrtc_internals.js"></script>
   </head>
   <body>
     <h2>WebRTC Internals</h2>
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index c531e91..7bea336 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -12,14 +12,13 @@
 namespace content {
 
 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
-    ServiceWorkerContext* context)
-    : context_(context) {}
+    int render_process_id,
+    ServiceWorkerContext* context) : context_(context) {}
 
 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {}
 
 bool ServiceWorkerDispatcherHost::OnMessageReceived(const IPC::Message& message,
                                                     bool* message_was_ok) {
-
   if (IPC_MESSAGE_CLASS(message) != ServiceWorkerMsgStart)
     return false;
 
@@ -36,15 +35,37 @@
   return handled;
 }
 
-void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(int32 registry_id,
-                                                       const string16& scope,
-                                                       const GURL& script_url) {
-  // TODO(alecflett): Enforce that script_url must have the same
-  // origin as the registering document.
+// TODO(alecflett): Store the service_worker_id keyed by (domain+pattern,
+// script) so we don't always return a new service worker id.
+static int64 NextWorkerId() {
+  static int64 service_worker_id = 0;
+  return service_worker_id++;
 }
 
-void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
-    int32 registry_id,
-    const string16& scope) {}
+void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
+    int32 thread_id,
+    int32 request_id,
+    const GURL& scope,
+    const GURL& script_url) {
+  // TODO(alecflett): add a ServiceWorker-specific policy query in
+  // ChildProcessSecurityImpl. See http://crbug.com/311631.
+
+  // TODO(alecflett): Throw an error for origin mismatch, rather than
+  // just returning.
+  if (scope.GetOrigin() != script_url.GetOrigin())
+    return;
+
+  Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
+      thread_id, request_id, NextWorkerId()));
+}
+
+void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(int32 thread_id,
+                                                            int32 request_id,
+                                                            const GURL& scope) {
+  // TODO(alecflett): add a ServiceWorker-specific policy query in
+  // ChildProcessSecurityImpl. See http://crbug.com/311631.
+
+  Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
+}
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 3692781..9414cf5 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -15,7 +15,8 @@
 
 class ServiceWorkerDispatcherHost : public BrowserMessageFilter {
  public:
-  explicit ServiceWorkerDispatcherHost(ServiceWorkerContext* context);
+  ServiceWorkerDispatcherHost(int render_process_id,
+                              ServiceWorkerContext* context);
 
   // BrowserIOMessageFilter implementation
   virtual bool OnMessageReceived(const IPC::Message& message,
@@ -26,12 +27,13 @@
 
  private:
   // IPC Message handlers
-
-  void OnRegisterServiceWorker(int32 registry_id,
-                            const string16& scope,
-                            const GURL& script_url);
-  void OnUnregisterServiceWorker(int32 registry_id, const string16& scope);
-
+  void OnRegisterServiceWorker(int32 thread_id,
+                               int32 request_id,
+                               const GURL& scope,
+                               const GURL& script_url);
+  void OnUnregisterServiceWorker(int32 thread_id,
+                                 int32 request_id,
+                                 const GURL& scope);
   scoped_refptr<ServiceWorkerContext> context_;
 };
 
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 094b0a7..5b7606d 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -9,11 +9,11 @@
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/browsing_instance.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/test_render_view_host.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/public/common/content_client.h"
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index c288f3a..72de096 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -5,7 +5,7 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "content/browser/renderer_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/content/browser/speech/OWNERS b/content/browser/speech/OWNERS
index 2c6195e..b38caa6 100644
--- a/content/browser/speech/OWNERS
+++ b/content/browser/speech/OWNERS
@@ -1,4 +1,3 @@
 hans@chromium.org
-primiano@chromium.org
 tommi@chromium.org
 xians@chromium.org
diff --git a/content/browser/speech/proto/speech_proto.target.darwin-arm.mk b/content/browser/speech/proto/speech_proto.target.darwin-arm.mk
index d6074fc..bf30207 100644
--- a/content/browser/speech/proto/speech_proto.target.darwin-arm.mk
+++ b/content/browser/speech/proto/speech_proto.target.darwin-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/speech/proto/speech_proto.target.darwin-mips.mk b/content/browser/speech/proto/speech_proto.target.darwin-mips.mk
index 505d10b..8553b6d 100644
--- a/content/browser/speech/proto/speech_proto.target.darwin-mips.mk
+++ b/content/browser/speech/proto/speech_proto.target.darwin-mips.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/speech/proto/speech_proto.target.darwin-x86.mk b/content/browser/speech/proto/speech_proto.target.darwin-x86.mk
index fe27626..6ed90b3 100644
--- a/content/browser/speech/proto/speech_proto.target.darwin-x86.mk
+++ b/content/browser/speech/proto/speech_proto.target.darwin-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/speech/proto/speech_proto.target.linux-arm.mk b/content/browser/speech/proto/speech_proto.target.linux-arm.mk
index d6074fc..bf30207 100644
--- a/content/browser/speech/proto/speech_proto.target.linux-arm.mk
+++ b/content/browser/speech/proto/speech_proto.target.linux-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/speech/proto/speech_proto.target.linux-mips.mk b/content/browser/speech/proto/speech_proto.target.linux-mips.mk
index 505d10b..8553b6d 100644
--- a/content/browser/speech/proto/speech_proto.target.linux-mips.mk
+++ b/content/browser/speech/proto/speech_proto.target.linux-mips.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/speech/proto/speech_proto.target.linux-x86.mk b/content/browser/speech/proto/speech_proto.target.linux-x86.mk
index fe27626..6ed90b3 100644
--- a/content/browser/speech/proto/speech_proto.target.linux-x86.mk
+++ b/content/browser/speech/proto/speech_proto.target.linux-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/browser/ssl/ssl_client_auth_handler.cc b/content/browser/ssl/ssl_client_auth_handler.cc
index 3340334..60d57d4 100644
--- a/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/content/browser/ssl/ssl_client_auth_handler.cc
@@ -11,18 +11,21 @@
 #include "content/public/browser/content_browser_client.h"
 #include "net/cert/x509_certificate.h"
 #include "net/http/http_transaction_factory.h"
+#include "net/ssl/client_cert_store.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 
 namespace content {
 
 SSLClientAuthHandler::SSLClientAuthHandler(
+    scoped_ptr<net::ClientCertStore> client_cert_store,
     net::URLRequest* request,
     net::SSLCertRequestInfo* cert_request_info)
     : request_(request),
       http_network_session_(
           request_->context()->http_transaction_factory()->GetSession()),
-      cert_request_info_(cert_request_info) {
+      cert_request_info_(cert_request_info),
+      client_cert_store_(client_cert_store.Pass()) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 }
 
@@ -39,6 +42,43 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DCHECK(request_);
 
+  if (client_cert_store_) {
+    client_cert_store_->GetClientCerts(
+        *cert_request_info_,
+        &cert_request_info_->client_certs,
+        base::Bind(&SSLClientAuthHandler::DidGetClientCerts, this));
+  } else {
+    DidGetClientCerts();
+  }
+}
+
+void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  VLOG(1) << this << " CertificateSelected " << cert;
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &SSLClientAuthHandler::DoCertificateSelected, this,
+          make_scoped_refptr(cert)));
+}
+
+void SSLClientAuthHandler::DidGetClientCerts() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  // Request may have cancelled while we were getting client certs.
+  if (!request_)
+    return;
+
+  // Note that if |client_cert_store_| is NULL, we intentionally fall through to
+  // DoCertificateSelected. This is for platforms where the client cert matching
+  // is not performed by Chrome, the platform can handle the cert matching
+  // before showing the dialog.
+  if (client_cert_store_ && cert_request_info_->client_certs.empty()) {
+    // No need to query the user if there are no certs to choose from.
+    DoCertificateSelected(NULL);
+    return;
+  }
+
   int render_process_host_id;
   int render_view_host_id;
   if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView(
@@ -57,17 +97,6 @@
           render_process_host_id, render_view_host_id));
 }
 
-void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  VLOG(1) << this << " CertificateSelected " << cert;
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(
-          &SSLClientAuthHandler::DoCertificateSelected, this,
-          make_scoped_refptr(cert)));
-}
-
 void SSLClientAuthHandler::DoCertificateSelected(net::X509Certificate* cert) {
   VLOG(1) << this << " DoCertificateSelected " << cert;
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/content/browser/ssl/ssl_client_auth_handler.h b/content/browser/ssl/ssl_client_auth_handler.h
index 9bd8275..bbc7747 100644
--- a/content/browser/ssl/ssl_client_auth_handler.h
+++ b/content/browser/ssl/ssl_client_auth_handler.h
@@ -13,6 +13,7 @@
 #include "net/ssl/ssl_cert_request_info.h"
 
 namespace net {
+class ClientCertStore;
 class HttpNetworkSession;
 class URLRequest;
 class X509Certificate;
@@ -20,6 +21,8 @@
 
 namespace content {
 
+class ResourceContext;
+
 // This class handles the approval and selection of a certificate for SSL client
 // authentication by the user.
 // It is self-owned and deletes itself when the UI reports the user selection or
@@ -28,7 +31,8 @@
     : public base::RefCountedThreadSafe<
           SSLClientAuthHandler, BrowserThread::DeleteOnIOThread> {
  public:
-  SSLClientAuthHandler(net::URLRequest* request,
+  SSLClientAuthHandler(scoped_ptr<net::ClientCertStore> client_cert_store,
+                       net::URLRequest* request,
                        net::SSLCertRequestInfo* cert_request_info);
 
   // Selects a certificate and resumes the URL request with that certificate.
@@ -53,6 +57,9 @@
   friend class BrowserThread;
   friend class base::DeleteHelper<SSLClientAuthHandler>;
 
+  // Called when ClientCertStore is done retrieving the cert list.
+  void DidGetClientCerts();
+
   // Notifies that the user has selected a cert.
   // Called on the IO thread.
   void DoCertificateSelected(net::X509Certificate* cert);
@@ -70,6 +77,8 @@
   // The certs to choose from.
   scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
 
+  scoped_ptr<net::ClientCertStore> client_cert_store_;
+
   DISALLOW_COPY_AND_ASSIGN(SSLClientAuthHandler);
 };
 
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc
index 85cb3a4..8a322f7 100644
--- a/content/browser/ssl/ssl_error_handler.cc
+++ b/content/browser/ssl/ssl_error_handler.cc
@@ -5,9 +5,9 @@
 #include "content/browser/ssl/ssl_error_handler.h"
 
 #include "base/bind.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/ssl/ssl_cert_error_handler.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index 6a6572a..9dd91d7 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -9,12 +9,12 @@
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/supports_user_data.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/ssl/ssl_cert_error_handler.h"
 #include "content/browser/ssl/ssl_policy.h"
 #include "content/browser/ssl/ssl_request_info.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/ssl_status_serialization.h"
 #include "content/public/browser/browser_context.h"
@@ -207,10 +207,12 @@
 
   SSLStatus original_ssl_status = entry->GetSSL();  // Copy!
 
-  policy()->UpdateEntry(entry, controller_->web_contents());
+  WebContentsImpl* contents =
+      static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents());
+  policy()->UpdateEntry(entry, contents);
 
   if (!entry->GetSSL().Equals(original_ssl_status))
-    controller_->web_contents()->DidChangeVisibleSSLState();
+    contents->DidChangeVisibleSSLState();
 }
 
 }  // namespace content
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index d4e943e..58cf975 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -10,12 +10,12 @@
 #include "base/memory/singleton.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/ssl/ssl_cert_error_handler.h"
 #include "content/browser/ssl/ssl_request_info.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/ssl_status.h"
diff --git a/content/browser/ssl/ssl_policy_backend.cc b/content/browser/ssl/ssl_policy_backend.cc
index 57e0570..3eb4f46 100644
--- a/content/browser/ssl/ssl_policy_backend.cc
+++ b/content/browser/ssl/ssl_policy_backend.cc
@@ -4,8 +4,8 @@
 
 #include "content/browser/ssl/ssl_policy_backend.h"
 
+#include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/ssl/ssl_host_state.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
 #include "content/public/browser/browser_context.h"
 
 namespace content {
diff --git a/content/browser/tracing/trace_controller_impl.cc b/content/browser/tracing/trace_controller_impl.cc
index 1294b01..bda8e69 100644
--- a/content/browser/tracing/trace_controller_impl.cc
+++ b/content/browser/tracing/trace_controller_impl.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/debug/trace_event.h"
 #include "base/strings/string_number_conversions.h"
+#include "components/tracing/tracing_messages.h"
 #include "content/browser/tracing/trace_message_filter.h"
 #include "content/browser/tracing/trace_subscriber_stdio.h"
 #include "content/common/child_process_messages.h"
@@ -56,6 +57,7 @@
     pending_bpf_ack_count_(0),
     maximum_bpf_(0.0f),
     is_tracing_(false),
+    is_tracing_startup_(false),
     is_get_category_groups_(false),
     category_filter_(
         base::debug::CategoryFilter::kDefaultCategoryFilterString) {
@@ -101,6 +103,7 @@
     delay_secs = 5;
   }
 
+  is_tracing_startup_ = true;
   OnTracingBegan(subscriber.get());
   BrowserThread::PostDelayedTask(
       BrowserThread::UI,
@@ -156,6 +159,7 @@
   // Disable local trace early to avoid traces during end-tracing process from
   // interfering with the process.
   TraceLog::GetInstance()->SetDisabled();
+  is_tracing_startup_ = false;
 
 #if defined(OS_ANDROID)
   if (!is_get_category_groups_)
@@ -268,7 +272,7 @@
   filters_.insert(filter);
   if (is_tracing_enabled()) {
     std::string cf_str = category_filter_.ToString();
-    filter->SendBeginTracing(cf_str, trace_options_);
+    filter->SendBeginTracing(cf_str, trace_options_, is_tracing_startup_);
     if (!watch_category_.empty())
       filter->SendSetWatchEvent(watch_category_, watch_name_);
   }
@@ -295,7 +299,8 @@
 
   // Notify all child processes.
   for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
-    it->get()->SendBeginTracing(category_filter_.ToString(), trace_options_);
+    it->get()->SendBeginTracing(category_filter_.ToString(), trace_options_,
+                                is_tracing_startup_);
   }
 }
 
diff --git a/content/browser/tracing/trace_controller_impl.h b/content/browser/tracing/trace_controller_impl.h
index 6f2ccb5..087b10c 100644
--- a/content/browser/tracing/trace_controller_impl.h
+++ b/content/browser/tracing/trace_controller_impl.h
@@ -25,6 +25,7 @@
   // Called on the main thread of the browser process to initialize
   // startup tracing.
   void InitStartupTracing(const CommandLine& command_line);
+  bool is_tracing_startup() const { return is_tracing_startup_; }
 
   // TraceController implementation:
   virtual bool BeginTracing(TraceSubscriber* subscriber,
@@ -94,6 +95,7 @@
   int pending_bpf_ack_count_;
   float maximum_bpf_;
   bool is_tracing_;
+  bool is_tracing_startup_;
   bool is_get_category_groups_;
   std::set<std::string> known_category_groups_;
   std::string watch_category_;
diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc
index 628a92f..3de5d38 100644
--- a/content/browser/tracing/trace_message_filter.cc
+++ b/content/browser/tracing/trace_message_filter.cc
@@ -57,11 +57,13 @@
 
 void TraceMessageFilter::SendBeginTracing(
     const std::string& category_filter_str,
-    base::debug::TraceLog::Options options) {
+    base::debug::TraceLog::Options options,
+    bool tracing_startup) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   Send(new TracingMsg_BeginTracing(category_filter_str,
                                    base::TimeTicks::NowFromSystemTraceTime(),
-                                   options));
+                                   options,
+                                   tracing_startup));
 }
 
 void TraceMessageFilter::SendEndTracing() {
diff --git a/content/browser/tracing/trace_message_filter.h b/content/browser/tracing/trace_message_filter.h
index c8290d9..f77902f 100644
--- a/content/browser/tracing/trace_message_filter.h
+++ b/content/browser/tracing/trace_message_filter.h
@@ -26,7 +26,8 @@
                                  bool* message_was_ok) OVERRIDE;
 
   void SendBeginTracing(const std::string& category_filter_str,
-                        base::debug::TraceLog::Options options);
+                        base::debug::TraceLog::Options options,
+                        bool tracing_startup);
   void SendEndTracing();
   void SendEnableMonitoring(const std::string& category_filter_str,
                             base::debug::TraceLog::Options options);
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index c7f7b52..d2e8a31 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -84,7 +84,8 @@
 
   // Notify all child processes.
   for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
-    it->get()->SendBeginTracing(category_filter_.ToString(), trace_options_);
+    it->get()->SendBeginTracing(
+        category_filter_.ToString(), trace_options_, false);
   }
 
   if (!callback.is_null())
@@ -256,7 +257,7 @@
   filters_.insert(filter);
   if (can_disable_recording()) {
     std::string cf_str = category_filter_.ToString();
-    filter->SendBeginTracing(cf_str, trace_options_);
+    filter->SendBeginTracing(cf_str, trace_options_, false);
   }
 }
 
diff --git a/content/browser/web_contents/debug_urls.cc b/content/browser/web_contents/debug_urls.cc
deleted file mode 100644
index 1f1222c..0000000
--- a/content/browser/web_contents/debug_urls.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2012 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/web_contents/debug_urls.h"
-
-#include <vector>
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/gpu/gpu_process_host_ui_shim.h"
-#include "content/browser/ppapi_plugin_process_host.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/url_constants.h"
-#include "ppapi/proxy/ppapi_messages.h"
-#include "url/gurl.h"
-
-namespace content {
-
-namespace {
-
-void HandlePpapiFlashDebugURL(const GURL& url) {
-#if defined(ENABLE_PLUGINS)
-  bool crash = url == GURL(kChromeUIPpapiFlashCrashURL);
-
-  std::vector<PpapiPluginProcessHost*> hosts;
-  PpapiPluginProcessHost::FindByName(UTF8ToUTF16(kFlashPluginName), &hosts);
-  for (std::vector<PpapiPluginProcessHost*>::iterator iter = hosts.begin();
-       iter != hosts.end(); ++iter) {
-    if (crash)
-      (*iter)->Send(new PpapiMsg_Crash());
-    else
-      (*iter)->Send(new PpapiMsg_Hang());
-  }
-#endif
-}
-
-}  // namespace
-
-bool HandleDebugURL(const GURL& url, PageTransition transition) {
-  // Ensure that the user explicitly navigated to this URL.
-  if (!(transition & PAGE_TRANSITION_FROM_ADDRESS_BAR))
-    return false;
-
-  if (url.host() == kChromeUIBrowserCrashHost) {
-    // Induce an intentional crash in the browser process.
-    CHECK(false);
-    return true;
-  }
-
-  if (url == GURL(kChromeUIGpuCleanURL)) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateRemoveAllContext();
-    return true;
-  }
-
-  if (url == GURL(kChromeUIGpuCrashURL)) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateCrash();
-    return true;
-  }
-
-  if (url == GURL(kChromeUIGpuHangURL)) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateHang();
-    return true;
-  }
-
-  if (url == GURL(kChromeUIPpapiFlashCrashURL) ||
-      url == GURL(kChromeUIPpapiFlashHangURL)) {
-    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                            base::Bind(&HandlePpapiFlashDebugURL, url));
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/debug_urls.h b/content/browser/web_contents/debug_urls.h
deleted file mode 100644
index 79da209..0000000
--- a/content/browser/web_contents/debug_urls.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_WEB_CONTENTS_DEBUG_URLS_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_DEBUG_URLS_H_
-
-#include "content/public/common/page_transition_types.h"
-
-class GURL;
-
-namespace content {
-
-// Checks if the given url is a url used for debugging purposes, and if so
-// handles it and returns true.
-bool HandleDebugURL(const GURL& url, PageTransition transition);
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_DEBUG_URLS_H_
diff --git a/content/browser/web_contents/interstitial_page_impl.cc b/content/browser/web_contents/interstitial_page_impl.cc
deleted file mode 100644
index 6489569..0000000
--- a/content/browser/web_contents/interstitial_page_impl.cc
+++ /dev/null
@@ -1,827 +0,0 @@
-// Copyright (c) 2012 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/web_contents/interstitial_page_impl.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread.h"
-#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
-#include "content/browser/dom_storage/session_storage_namespace_impl.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/browser/renderer_host/render_view_host_factory.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/view_messages.h"
-#include "content/port/browser/render_view_host_delegate_view.h"
-#include "content/port/browser/render_widget_host_view_port.h"
-#include "content/port/browser/web_contents_view_port.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/dom_operation_notification_details.h"
-#include "content/public/browser/interstitial_page_delegate.h"
-#include "content/public/browser/invalidate_type.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/bindings_policy.h"
-#include "content/public/common/page_transition_types.h"
-#include "net/base/escape.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using WebKit::WebDragOperation;
-using WebKit::WebDragOperationsMask;
-
-namespace content {
-namespace {
-
-void ResourceRequestHelper(ResourceDispatcherHostImpl* rdh,
-                           int process_id,
-                           int render_view_host_id,
-                           ResourceRequestAction action) {
-  switch (action) {
-    case BLOCK:
-      rdh->BlockRequestsForRoute(process_id, render_view_host_id);
-      break;
-    case RESUME:
-      rdh->ResumeBlockedRequestsForRoute(process_id, render_view_host_id);
-      break;
-    case CANCEL:
-      rdh->CancelBlockedRequestsForRoute(process_id, render_view_host_id);
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-}  // namespace
-
-class InterstitialPageImpl::InterstitialPageRVHDelegateView
-  : public RenderViewHostDelegateView {
- public:
-  explicit InterstitialPageRVHDelegateView(InterstitialPageImpl* page);
-
-  // RenderViewHostDelegateView implementation:
-  virtual void ShowPopupMenu(const gfx::Rect& bounds,
-                             int item_height,
-                             double item_font_size,
-                             int selected_item,
-                             const std::vector<MenuItem>& items,
-                             bool right_aligned,
-                             bool allow_multiple_selection) OVERRIDE;
-  virtual void StartDragging(const DropData& drop_data,
-                             WebDragOperationsMask operations_allowed,
-                             const gfx::ImageSkia& image,
-                             const gfx::Vector2d& image_offset,
-                             const DragEventSourceInfo& event_info) OVERRIDE;
-  virtual void UpdateDragCursor(WebDragOperation operation) OVERRIDE;
-  virtual void GotFocus() OVERRIDE;
-  virtual void TakeFocus(bool reverse) OVERRIDE;
-  virtual void OnFindReply(int request_id,
-                           int number_of_matches,
-                           const gfx::Rect& selection_rect,
-                           int active_match_ordinal,
-                           bool final_update);
-
- private:
-  InterstitialPageImpl* interstitial_page_;
-
-  DISALLOW_COPY_AND_ASSIGN(InterstitialPageRVHDelegateView);
-};
-
-
-// We keep a map of the various blocking pages shown as the UI tests need to
-// be able to retrieve them.
-typedef std::map<WebContents*, InterstitialPageImpl*> InterstitialPageMap;
-static InterstitialPageMap* g_web_contents_to_interstitial_page;
-
-// Initializes g_web_contents_to_interstitial_page in a thread-safe manner.
-// Should be called before accessing g_web_contents_to_interstitial_page.
-static void InitInterstitialPageMap() {
-  if (!g_web_contents_to_interstitial_page)
-    g_web_contents_to_interstitial_page = new InterstitialPageMap;
-}
-
-InterstitialPage* InterstitialPage::Create(WebContents* web_contents,
-                                           bool new_navigation,
-                                           const GURL& url,
-                                           InterstitialPageDelegate* delegate) {
-  return new InterstitialPageImpl(web_contents, new_navigation, url, delegate);
-}
-
-InterstitialPage* InterstitialPage::GetInterstitialPage(
-    WebContents* web_contents) {
-  InitInterstitialPageMap();
-  InterstitialPageMap::const_iterator iter =
-      g_web_contents_to_interstitial_page->find(web_contents);
-  if (iter == g_web_contents_to_interstitial_page->end())
-    return NULL;
-
-  return iter->second;
-}
-
-InterstitialPageImpl::InterstitialPageImpl(WebContents* web_contents,
-                                           bool new_navigation,
-                                           const GURL& url,
-                                           InterstitialPageDelegate* delegate)
-    : WebContentsObserver(web_contents),
-      web_contents_(static_cast<WebContentsImpl*>(web_contents)),
-      url_(url),
-      new_navigation_(new_navigation),
-      should_discard_pending_nav_entry_(new_navigation),
-      reload_on_dont_proceed_(false),
-      enabled_(true),
-      action_taken_(NO_ACTION),
-      render_view_host_(NULL),
-      original_child_id_(web_contents->GetRenderProcessHost()->GetID()),
-      original_rvh_id_(web_contents->GetRenderViewHost()->GetRoutingID()),
-      should_revert_web_contents_title_(false),
-      web_contents_was_loading_(false),
-      resource_dispatcher_host_notified_(false),
-      rvh_delegate_view_(new InterstitialPageRVHDelegateView(this)),
-      create_view_(true),
-      delegate_(delegate),
-      weak_ptr_factory_(this) {
-  InitInterstitialPageMap();
-  // It would be inconsistent to create an interstitial with no new navigation
-  // (which is the case when the interstitial was triggered by a sub-resource on
-  // a page) when we have a pending entry (in the process of loading a new top
-  // frame).
-  DCHECK(new_navigation || !web_contents->GetController().GetPendingEntry());
-}
-
-InterstitialPageImpl::~InterstitialPageImpl() {
-}
-
-void InterstitialPageImpl::Show() {
-  if (!enabled())
-    return;
-
-  // If an interstitial is already showing or about to be shown, close it before
-  // showing the new one.
-  // Be careful not to take an action on the old interstitial more than once.
-  InterstitialPageMap::const_iterator iter =
-      g_web_contents_to_interstitial_page->find(web_contents_);
-  if (iter != g_web_contents_to_interstitial_page->end()) {
-    InterstitialPageImpl* interstitial = iter->second;
-    if (interstitial->action_taken_ != NO_ACTION) {
-      interstitial->Hide();
-    } else {
-      // If we are currently showing an interstitial page for which we created
-      // a transient entry and a new interstitial is shown as the result of a
-      // new browser initiated navigation, then that transient entry has already
-      // been discarded and a new pending navigation entry created.
-      // So we should not discard that new pending navigation entry.
-      // See http://crbug.com/9791
-      if (new_navigation_ && interstitial->new_navigation_)
-        interstitial->should_discard_pending_nav_entry_= false;
-      interstitial->DontProceed();
-    }
-  }
-
-  // Block the resource requests for the render view host while it is hidden.
-  TakeActionOnResourceDispatcher(BLOCK);
-  // We need to be notified when the RenderViewHost is destroyed so we can
-  // cancel the blocked requests.  We cannot do that on
-  // NOTIFY_WEB_CONTENTS_DESTROYED as at that point the RenderViewHost has
-  // already been destroyed.
-  notification_registrar_.Add(
-      this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-      Source<RenderWidgetHost>(web_contents_->GetRenderViewHost()));
-
-  // Update the g_web_contents_to_interstitial_page map.
-  iter = g_web_contents_to_interstitial_page->find(web_contents_);
-  DCHECK(iter == g_web_contents_to_interstitial_page->end());
-  (*g_web_contents_to_interstitial_page)[web_contents_] = this;
-
-  if (new_navigation_) {
-    NavigationEntryImpl* entry = new NavigationEntryImpl;
-    entry->SetURL(url_);
-    entry->SetVirtualURL(url_);
-    entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
-
-    // Give delegates a chance to set some states on the navigation entry.
-    delegate_->OverrideEntry(entry);
-
-    web_contents_->GetController().SetTransientEntry(entry);
-  }
-
-  DCHECK(!render_view_host_);
-  render_view_host_ = static_cast<RenderViewHostImpl*>(CreateRenderViewHost());
-  render_view_host_->AttachToFrameTree();
-  CreateWebContentsView();
-
-  std::string data_url = "data:text/html;charset=utf-8," +
-                         net::EscapePath(delegate_->GetHTMLContents());
-  render_view_host_->NavigateToURL(GURL(data_url));
-
-  notification_registrar_.Add(this, NOTIFICATION_NAV_ENTRY_PENDING,
-      Source<NavigationController>(&web_contents_->GetController()));
-  notification_registrar_.Add(
-      this, NOTIFICATION_DOM_OPERATION_RESPONSE,
-      Source<RenderViewHost>(render_view_host_));
-}
-
-void InterstitialPageImpl::Hide() {
-  // We may have already been hidden, and are just waiting to be deleted.
-  // We can't check for enabled() here, because some callers have already
-  // called Disable.
-  if (!render_view_host_)
-    return;
-
-  Disable();
-
-  RenderWidgetHostView* old_view =
-      web_contents_->GetRenderViewHost()->GetView();
-  if (web_contents_->GetInterstitialPage() == this &&
-      old_view && !old_view->IsShowing() && !web_contents_->IsHidden()) {
-    // Show the original RVH since we're going away.  Note it might not exist if
-    // the renderer crashed while the interstitial was showing.
-    // Note that it is important that we don't call Show() if the view is
-    // already showing. That would result in bad things (unparented HWND on
-    // Windows for example) happening.
-    old_view->Show();
-  }
-
-  // If the focus was on the interstitial, let's keep it to the page.
-  // (Note that in unit-tests the RVH may not have a view).
-  if (render_view_host_->GetView() &&
-      render_view_host_->GetView()->HasFocus() &&
-      web_contents_->GetRenderViewHost()->GetView()) {
-    RenderWidgetHostViewPort::FromRWHV(
-        web_contents_->GetRenderViewHost()->GetView())->Focus();
-  }
-
-  // Shutdown the RVH asynchronously, as we may have been called from a RVH
-  // delegate method, and we can't delete the RVH out from under itself.
-  base::MessageLoop::current()->PostNonNestableTask(
-      FROM_HERE,
-      base::Bind(&InterstitialPageImpl::Shutdown,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 render_view_host_));
-  render_view_host_ = NULL;
-  frame_tree_.SwapMainFrame(NULL);
-  web_contents_->DetachInterstitialPage();
-  // Let's revert to the original title if necessary.
-  NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
-  if (!new_navigation_ && should_revert_web_contents_title_) {
-    entry->SetTitle(original_web_contents_title_);
-    web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
-  }
-
-  InterstitialPageMap::iterator iter =
-      g_web_contents_to_interstitial_page->find(web_contents_);
-  DCHECK(iter != g_web_contents_to_interstitial_page->end());
-  if (iter != g_web_contents_to_interstitial_page->end())
-    g_web_contents_to_interstitial_page->erase(iter);
-
-  // Clear the WebContents pointer, because it may now be deleted.
-  // This signifies that we are in the process of shutting down.
-  web_contents_ = NULL;
-}
-
-void InterstitialPageImpl::Observe(
-    int type,
-    const NotificationSource& source,
-    const NotificationDetails& details) {
-  switch (type) {
-    case NOTIFICATION_NAV_ENTRY_PENDING:
-      // We are navigating away from the interstitial (the user has typed a URL
-      // in the location bar or clicked a bookmark).  Make sure clicking on the
-      // interstitial will have no effect.  Also cancel any blocked requests
-      // on the ResourceDispatcherHost.  Note that when we get this notification
-      // the RenderViewHost has not yet navigated so we'll unblock the
-      // RenderViewHost before the resource request for the new page we are
-      // navigating arrives in the ResourceDispatcherHost.  This ensures that
-      // request won't be blocked if the same RenderViewHost was used for the
-      // new navigation.
-      Disable();
-      TakeActionOnResourceDispatcher(CANCEL);
-      break;
-    case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED:
-      if (action_taken_ == NO_ACTION) {
-        // The RenderViewHost is being destroyed (as part of the tab being
-        // closed); make sure we clear the blocked requests.
-        RenderViewHost* rvh = static_cast<RenderViewHost*>(
-            static_cast<RenderViewHostImpl*>(
-                RenderWidgetHostImpl::From(
-                    Source<RenderWidgetHost>(source).ptr())));
-        DCHECK(rvh->GetProcess()->GetID() == original_child_id_ &&
-               rvh->GetRoutingID() == original_rvh_id_);
-        TakeActionOnResourceDispatcher(CANCEL);
-      }
-      break;
-    case NOTIFICATION_DOM_OPERATION_RESPONSE:
-      if (enabled()) {
-        Details<DomOperationNotificationDetails> dom_op_details(
-            details);
-        delegate_->CommandReceived(dom_op_details->json);
-      }
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-void InterstitialPageImpl::NavigationEntryCommitted(
-    const LoadCommittedDetails& load_details) {
-  OnNavigatingAwayOrTabClosing();
-}
-
-void InterstitialPageImpl::WebContentsDestroyed(WebContents* web_contents) {
-  OnNavigatingAwayOrTabClosing();
-}
-
-RenderViewHostDelegateView* InterstitialPageImpl::GetDelegateView() {
-  return rvh_delegate_view_.get();
-}
-
-const GURL& InterstitialPageImpl::GetURL() const {
-  return url_;
-}
-
-void InterstitialPageImpl::RenderViewTerminated(
-    RenderViewHost* render_view_host,
-    base::TerminationStatus status,
-    int error_code) {
-  // Our renderer died. This should not happen in normal cases.
-  // If we haven't already started shutdown, just dismiss the interstitial.
-  // We cannot check for enabled() here, because we may have called Disable
-  // without calling Hide.
-  if (render_view_host_)
-    DontProceed();
-}
-
-void InterstitialPageImpl::DidNavigate(
-    RenderViewHost* render_view_host,
-    const ViewHostMsg_FrameNavigate_Params& params) {
-  // A fast user could have navigated away from the page that triggered the
-  // interstitial while the interstitial was loading, that would have disabled
-  // us. In that case we can dismiss ourselves.
-  if (!enabled()) {
-    DontProceed();
-    return;
-  }
-  if (PageTransitionCoreTypeIs(params.transition,
-                               PAGE_TRANSITION_AUTO_SUBFRAME)) {
-    // No need to handle navigate message from iframe in the interstitial page.
-    return;
-  }
-
-  // The RenderViewHost has loaded its contents, we can show it now.
-  if (!web_contents_->IsHidden())
-    render_view_host_->GetView()->Show();
-  web_contents_->AttachInterstitialPage(this);
-
-  RenderWidgetHostView* rwh_view =
-      web_contents_->GetRenderViewHost()->GetView();
-
-  // The RenderViewHost may already have crashed before we even get here.
-  if (rwh_view) {
-    // If the page has focus, focus the interstitial.
-    if (rwh_view->HasFocus())
-      Focus();
-
-    // Hide the original RVH since we're showing the interstitial instead.
-    rwh_view->Hide();
-  }
-
-  // Notify the tab we are not loading so the throbber is stopped. It also
-  // causes a WebContentsObserver::DidStopLoading callback that the
-  // AutomationProvider (used by the UI tests) expects to consider a navigation
-  // as complete. Without this, navigating in a UI test to a URL that triggers
-  // an interstitial would hang.
-  web_contents_was_loading_ = web_contents_->IsLoading();
-  web_contents_->SetIsLoading(web_contents_->GetRenderViewHost(), false, NULL);
-}
-
-void InterstitialPageImpl::UpdateTitle(
-    RenderViewHost* render_view_host,
-    int32 page_id,
-    const string16& title,
-    base::i18n::TextDirection title_direction) {
-  if (!enabled())
-    return;
-
-  DCHECK(render_view_host == render_view_host_);
-  NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
-  if (!entry) {
-    // Crash reports from the field indicate this can be NULL.
-    // This is unexpected as InterstitialPages constructed with the
-    // new_navigation flag set to true create a transient navigation entry
-    // (that is returned as the active entry). And the only case so far of
-    // interstitial created with that flag set to false is with the
-    // SafeBrowsingBlockingPage, when the resource triggering the interstitial
-    // is a sub-resource, meaning the main page has already been loaded and a
-    // navigation entry should have been created.
-    NOTREACHED();
-    return;
-  }
-
-  // If this interstitial is shown on an existing navigation entry, we'll need
-  // to remember its title so we can revert to it when hidden.
-  if (!new_navigation_ && !should_revert_web_contents_title_) {
-    original_web_contents_title_ = entry->GetTitle();
-    should_revert_web_contents_title_ = true;
-  }
-  // TODO(evan): make use of title_direction.
-  // http://code.google.com/p/chromium/issues/detail?id=27094
-  entry->SetTitle(title);
-  web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
-}
-
-RendererPreferences InterstitialPageImpl::GetRendererPrefs(
-    BrowserContext* browser_context) const {
-  delegate_->OverrideRendererPrefs(&renderer_preferences_);
-  return renderer_preferences_;
-}
-
-WebPreferences InterstitialPageImpl::GetWebkitPrefs() {
-  if (!enabled())
-    return WebPreferences();
-
-  return WebContentsImpl::GetWebkitPrefs(render_view_host_, url_);
-}
-
-void InterstitialPageImpl::RenderWidgetDeleted(
-    RenderWidgetHostImpl* render_widget_host) {
-  delete this;
-}
-
-bool InterstitialPageImpl::PreHandleKeyboardEvent(
-    const NativeWebKeyboardEvent& event,
-    bool* is_keyboard_shortcut) {
-  if (!enabled())
-    return false;
-  return web_contents_->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
-}
-
-void InterstitialPageImpl::HandleKeyboardEvent(
-      const NativeWebKeyboardEvent& event) {
-  if (enabled())
-    web_contents_->HandleKeyboardEvent(event);
-}
-
-#if defined(OS_WIN) && defined(USE_AURA)
-gfx::NativeViewAccessible
-InterstitialPageImpl::GetParentNativeViewAccessible() {
-  return web_contents_->GetParentNativeViewAccessible();
-}
-#endif
-
-WebContents* InterstitialPageImpl::web_contents() const {
-  return web_contents_;
-}
-
-RenderViewHost* InterstitialPageImpl::CreateRenderViewHost() {
-  if (!enabled())
-    return NULL;
-
-  // Interstitial pages don't want to share the session storage so we mint a
-  // new one.
-  BrowserContext* browser_context = web_contents()->GetBrowserContext();
-  scoped_refptr<SiteInstance> site_instance =
-      SiteInstance::Create(browser_context);
-  DOMStorageContextWrapper* dom_storage_context =
-      static_cast<DOMStorageContextWrapper*>(
-          BrowserContext::GetStoragePartition(
-              browser_context, site_instance.get())->GetDOMStorageContext());
-  session_storage_namespace_ =
-      new SessionStorageNamespaceImpl(dom_storage_context);
-
-  return RenderViewHostFactory::Create(site_instance.get(),
-                                       this,
-                                       this,
-                                       MSG_ROUTING_NONE,
-                                       MSG_ROUTING_NONE,
-                                       false,
-                                       false);
-}
-
-WebContentsView* InterstitialPageImpl::CreateWebContentsView() {
-  if (!enabled() || !create_view_)
-    return NULL;
-  WebContentsView* web_contents_view = web_contents()->GetView();
-  WebContentsViewPort* web_contents_view_port =
-      static_cast<WebContentsViewPort*>(web_contents_view);
-  RenderWidgetHostView* view =
-      web_contents_view_port->CreateViewForWidget(render_view_host_);
-  render_view_host_->SetView(view);
-  render_view_host_->AllowBindings(BINDINGS_POLICY_DOM_AUTOMATION);
-
-  int32 max_page_id = web_contents()->
-      GetMaxPageIDForSiteInstance(render_view_host_->GetSiteInstance());
-  render_view_host_->CreateRenderView(string16(),
-                                      MSG_ROUTING_NONE,
-                                      max_page_id);
-  web_contents_->RenderViewForInterstitialPageCreated(render_view_host_);
-  view->SetSize(web_contents_view->GetContainerSize());
-  // Don't show the interstitial until we have navigated to it.
-  view->Hide();
-  return web_contents_view;
-}
-
-void InterstitialPageImpl::Proceed() {
-  // Don't repeat this if we are already shutting down.  We cannot check for
-  // enabled() here, because we may have called Disable without calling Hide.
-  if (!render_view_host_)
-    return;
-
-  if (action_taken_ != NO_ACTION) {
-    NOTREACHED();
-    return;
-  }
-  Disable();
-  action_taken_ = PROCEED_ACTION;
-
-  // Resumes the throbber, if applicable.
-  if (web_contents_was_loading_)
-    web_contents_->SetIsLoading(web_contents_->GetRenderViewHost(), true, NULL);
-
-  // If this is a new navigation, the old page is going away, so we cancel any
-  // blocked requests for it.  If it is not a new navigation, then it means the
-  // interstitial was shown as a result of a resource loading in the page.
-  // Since the user wants to proceed, we'll let any blocked request go through.
-  if (new_navigation_)
-    TakeActionOnResourceDispatcher(CANCEL);
-  else
-    TakeActionOnResourceDispatcher(RESUME);
-
-  // No need to hide if we are a new navigation, we'll get hidden when the
-  // navigation is committed.
-  if (!new_navigation_) {
-    Hide();
-    delegate_->OnProceed();
-    return;
-  }
-
-  delegate_->OnProceed();
-}
-
-void InterstitialPageImpl::DontProceed() {
-  // Don't repeat this if we are already shutting down.  We cannot check for
-  // enabled() here, because we may have called Disable without calling Hide.
-  if (!render_view_host_)
-    return;
-  DCHECK(action_taken_ != DONT_PROCEED_ACTION);
-
-  Disable();
-  action_taken_ = DONT_PROCEED_ACTION;
-
-  // If this is a new navigation, we are returning to the original page, so we
-  // resume blocked requests for it.  If it is not a new navigation, then it
-  // means the interstitial was shown as a result of a resource loading in the
-  // page and we won't return to the original page, so we cancel blocked
-  // requests in that case.
-  if (new_navigation_)
-    TakeActionOnResourceDispatcher(RESUME);
-  else
-    TakeActionOnResourceDispatcher(CANCEL);
-
-  if (should_discard_pending_nav_entry_) {
-    // Since no navigation happens we have to discard the transient entry
-    // explicitely.  Note that by calling DiscardNonCommittedEntries() we also
-    // discard the pending entry, which is what we want, since the navigation is
-    // cancelled.
-    web_contents_->GetController().DiscardNonCommittedEntries();
-  }
-
-  if (reload_on_dont_proceed_)
-    web_contents_->GetController().Reload(true);
-
-  Hide();
-  delegate_->OnDontProceed();
-}
-
-void InterstitialPageImpl::CancelForNavigation() {
-  // The user is trying to navigate away.  We should unblock the renderer and
-  // disable the interstitial, but keep it visible until the navigation
-  // completes.
-  Disable();
-  // If this interstitial was shown for a new navigation, allow any navigations
-  // on the original page to resume (e.g., subresource requests, XHRs, etc).
-  // Otherwise, cancel the pending, possibly dangerous navigations.
-  if (new_navigation_)
-    TakeActionOnResourceDispatcher(RESUME);
-  else
-    TakeActionOnResourceDispatcher(CANCEL);
-}
-
-void InterstitialPageImpl::SetSize(const gfx::Size& size) {
-  if (!enabled())
-    return;
-#if !defined(OS_MACOSX)
-  // When a tab is closed, we might be resized after our view was NULLed
-  // (typically if there was an info-bar).
-  if (render_view_host_->GetView())
-    render_view_host_->GetView()->SetSize(size);
-#else
-  // TODO(port): Does Mac need to SetSize?
-  NOTIMPLEMENTED();
-#endif
-}
-
-void InterstitialPageImpl::Focus() {
-  // Focus the native window.
-  if (!enabled())
-    return;
-  RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus();
-}
-
-void InterstitialPageImpl::FocusThroughTabTraversal(bool reverse) {
-  if (!enabled())
-    return;
-  render_view_host_->SetInitialFocus(reverse);
-}
-
-RenderWidgetHostView* InterstitialPageImpl::GetView() {
-  return render_view_host_->GetView();
-}
-
-RenderViewHost* InterstitialPageImpl::GetRenderViewHostForTesting() const {
-  return render_view_host_;
-}
-
-#if defined(OS_ANDROID)
-RenderViewHost* InterstitialPageImpl::GetRenderViewHost() const {
-  return render_view_host_;
-}
-#endif
-
-InterstitialPageDelegate* InterstitialPageImpl::GetDelegateForTesting() {
-  return delegate_.get();
-}
-
-void InterstitialPageImpl::DontCreateViewForTesting() {
-  create_view_ = false;
-}
-
-gfx::Rect InterstitialPageImpl::GetRootWindowResizerRect() const {
-  return gfx::Rect();
-}
-
-void InterstitialPageImpl::CreateNewWindow(
-    int route_id,
-    int main_frame_route_id,
-    const ViewHostMsg_CreateWindow_Params& params,
-    SessionStorageNamespace* session_storage_namespace) {
-  NOTREACHED() << "InterstitialPage does not support showing popups yet.";
-}
-
-void InterstitialPageImpl::CreateNewWidget(int route_id,
-                                           WebKit::WebPopupType popup_type) {
-  NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
-}
-
-void InterstitialPageImpl::CreateNewFullscreenWidget(int route_id) {
-  NOTREACHED()
-      << "InterstitialPage does not support showing full screen popups.";
-}
-
-void InterstitialPageImpl::ShowCreatedWindow(int route_id,
-                                             WindowOpenDisposition disposition,
-                                             const gfx::Rect& initial_pos,
-                                             bool user_gesture) {
-  NOTREACHED() << "InterstitialPage does not support showing popups yet.";
-}
-
-void InterstitialPageImpl::ShowCreatedWidget(int route_id,
-                                             const gfx::Rect& initial_pos) {
-  NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
-}
-
-void InterstitialPageImpl::ShowCreatedFullscreenWidget(int route_id) {
-  NOTREACHED()
-      << "InterstitialPage does not support showing full screen popups.";
-}
-
-SessionStorageNamespace* InterstitialPageImpl::GetSessionStorageNamespace(
-    SiteInstance* instance) {
-  return session_storage_namespace_.get();
-}
-
-FrameTree* InterstitialPageImpl::GetFrameTree() {
-  return &frame_tree_;
-}
-
-void InterstitialPageImpl::Disable() {
-  enabled_ = false;
-}
-
-void InterstitialPageImpl::Shutdown(RenderViewHostImpl* render_view_host) {
-  render_view_host->Shutdown();
-  // We are deleted now.
-}
-
-void InterstitialPageImpl::OnNavigatingAwayOrTabClosing() {
-  if (action_taken_ == NO_ACTION) {
-    // We are navigating away from the interstitial or closing a tab with an
-    // interstitial.  Default to DontProceed(). We don't just call Hide as
-    // subclasses will almost certainly override DontProceed to do some work
-    // (ex: close pending connections).
-    DontProceed();
-  } else {
-    // User decided to proceed and either the navigation was committed or
-    // the tab was closed before that.
-    Hide();
-  }
-}
-
-void InterstitialPageImpl::TakeActionOnResourceDispatcher(
-    ResourceRequestAction action) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) <<
-      "TakeActionOnResourceDispatcher should be called on the main thread.";
-
-  if (action == CANCEL || action == RESUME) {
-    if (resource_dispatcher_host_notified_)
-      return;
-    resource_dispatcher_host_notified_ = true;
-  }
-
-  // The tab might not have a render_view_host if it was closed (in which case,
-  // we have taken care of the blocked requests when processing
-  // NOTIFY_RENDER_WIDGET_HOST_DESTROYED.
-  // Also we need to test there is a ResourceDispatcherHostImpl, as when unit-
-  // tests we don't have one.
-  RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(original_child_id_,
-                                                       original_rvh_id_);
-  if (!rvh || !ResourceDispatcherHostImpl::Get())
-    return;
-
-  BrowserThread::PostTask(
-      BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(
-          &ResourceRequestHelper,
-          ResourceDispatcherHostImpl::Get(),
-          original_child_id_,
-          original_rvh_id_,
-          action));
-}
-
-InterstitialPageImpl::InterstitialPageRVHDelegateView::
-    InterstitialPageRVHDelegateView(InterstitialPageImpl* page)
-    : interstitial_page_(page) {
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::ShowPopupMenu(
-    const gfx::Rect& bounds,
-    int item_height,
-    double item_font_size,
-    int selected_item,
-    const std::vector<MenuItem>& items,
-    bool right_aligned,
-    bool allow_multiple_selection) {
-  NOTREACHED() << "InterstitialPage does not support showing popup menus.";
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::StartDragging(
-    const DropData& drop_data,
-    WebDragOperationsMask allowed_operations,
-    const gfx::ImageSkia& image,
-    const gfx::Vector2d& image_offset,
-    const DragEventSourceInfo& event_info) {
-  NOTREACHED() << "InterstitialPage does not support dragging yet.";
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::UpdateDragCursor(
-    WebDragOperation) {
-  NOTREACHED() << "InterstitialPage does not support dragging yet.";
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::GotFocus() {
-  WebContents* web_contents = interstitial_page_->web_contents();
-  if (web_contents && web_contents->GetDelegate())
-    web_contents->GetDelegate()->WebContentsFocused(web_contents);
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::TakeFocus(
-    bool reverse) {
-  if (!interstitial_page_->web_contents())
-    return;
-  WebContentsImpl* web_contents =
-      static_cast<WebContentsImpl*>(interstitial_page_->web_contents());
-  if (!web_contents->GetDelegateView())
-    return;
-
-  web_contents->GetDelegateView()->TakeFocus(reverse);
-}
-
-void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply(
-    int request_id, int number_of_matches, const gfx::Rect& selection_rect,
-    int active_match_ordinal, bool final_update) {
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/interstitial_page_impl.h b/content/browser/web_contents/interstitial_page_impl.h
deleted file mode 100644
index 63d7ab4..0000000
--- a/content/browser/web_contents/interstitial_page_impl.h
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_WEB_CONTENTS_INTERSTITIAL_PAGE_IMPL_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_INTERSTITIAL_PAGE_IMPL_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/renderer_host/frame_tree.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_widget_host_delegate.h"
-#include "content/public/browser/interstitial_page.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/renderer_preferences.h"
-#include "url/gurl.h"
-
-namespace content {
-class NavigationEntry;
-class RenderViewHostImpl;
-class RenderWidgetHostView;
-class WebContentsView;
-class WebContentsImpl;
-
-enum ResourceRequestAction {
-  BLOCK,
-  RESUME,
-  CANCEL
-};
-
-class CONTENT_EXPORT InterstitialPageImpl
-    : public NON_EXPORTED_BASE(InterstitialPage),
-      public NotificationObserver,
-      public WebContentsObserver,
-      public RenderViewHostDelegate,
-      public RenderWidgetHostDelegate {
- public:
-  // The different state of actions the user can take in an interstitial.
-  enum ActionState {
-    NO_ACTION,           // No action has been taken yet.
-    PROCEED_ACTION,      // "Proceed" was selected.
-    DONT_PROCEED_ACTION  // "Don't proceed" was selected.
-  };
-
-  InterstitialPageImpl(WebContents* web_contents,
-                       bool new_navigation,
-                       const GURL& url,
-                       InterstitialPageDelegate* delegate);
-  virtual ~InterstitialPageImpl();
-
-  // InterstitialPage implementation:
-  virtual void Show() OVERRIDE;
-  virtual void Hide() OVERRIDE;
-  virtual void DontProceed() OVERRIDE;
-  virtual void Proceed() OVERRIDE;
-  virtual RenderViewHost* GetRenderViewHostForTesting() const OVERRIDE;
-  virtual InterstitialPageDelegate* GetDelegateForTesting() OVERRIDE;
-  virtual void DontCreateViewForTesting() OVERRIDE;
-  virtual void SetSize(const gfx::Size& size) OVERRIDE;
-  virtual void Focus() OVERRIDE;
-
-  // Allows the user to navigate away by disabling the interstitial, canceling
-  // the pending request, and unblocking the hidden renderer.  The interstitial
-  // will stay visible until the navigation completes.
-  void CancelForNavigation();
-
-  // Focus the first (last if reverse is true) element in the interstitial page.
-  // Called when tab traversing.
-  void FocusThroughTabTraversal(bool reverse);
-
-  RenderWidgetHostView* GetView();
-
-  // See description above field.
-  void set_reload_on_dont_proceed(bool value) {
-    reload_on_dont_proceed_ = value;
-  }
-  bool reload_on_dont_proceed() const { return reload_on_dont_proceed_; }
-
-#if defined(OS_ANDROID)
-  // Android shares a single platform window for all tabs, so we need to expose
-  // the RenderViewHost to properly route gestures to the interstitial.
-  RenderViewHost* GetRenderViewHost() const;
-#endif
-
- protected:
-  // NotificationObserver method:
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  // WebContentsObserver implementation:
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
-  virtual void NavigationEntryCommitted(
-      const LoadCommittedDetails& load_details) OVERRIDE;
-
-  // RenderViewHostDelegate implementation:
-  virtual RenderViewHostDelegateView* GetDelegateView() OVERRIDE;
-  virtual const GURL& GetURL() const OVERRIDE;
-  virtual void RenderViewTerminated(RenderViewHost* render_view_host,
-                                    base::TerminationStatus status,
-                                    int error_code) OVERRIDE;
-  virtual void DidNavigate(
-      RenderViewHost* render_view_host,
-      const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE;
-  virtual void UpdateTitle(RenderViewHost* render_view_host,
-                           int32 page_id,
-                           const string16& title,
-                           base::i18n::TextDirection title_direction) OVERRIDE;
-  virtual RendererPreferences GetRendererPrefs(
-      BrowserContext* browser_context) const OVERRIDE;
-  virtual WebPreferences GetWebkitPrefs() OVERRIDE;
-  virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE;
-  virtual void CreateNewWindow(
-      int route_id,
-      int main_frame_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
-      SessionStorageNamespace* session_storage_namespace) OVERRIDE;
-  virtual void CreateNewWidget(int route_id,
-                               WebKit::WebPopupType popup_type) OVERRIDE;
-  virtual void CreateNewFullscreenWidget(int route_id) OVERRIDE;
-  virtual void ShowCreatedWindow(int route_id,
-                                 WindowOpenDisposition disposition,
-                                 const gfx::Rect& initial_pos,
-                                 bool user_gesture) OVERRIDE;
-  virtual void ShowCreatedWidget(int route_id,
-                                 const gfx::Rect& initial_pos) OVERRIDE;
-  virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
-
-  virtual SessionStorageNamespace* GetSessionStorageNamespace(
-      SiteInstance* instance) OVERRIDE;
-
-  virtual FrameTree* GetFrameTree() OVERRIDE;
-
-  // RenderWidgetHostDelegate implementation:
-  virtual void RenderWidgetDeleted(
-      RenderWidgetHostImpl* render_widget_host) OVERRIDE;
-  virtual bool PreHandleKeyboardEvent(
-      const NativeWebKeyboardEvent& event,
-      bool* is_keyboard_shortcut) OVERRIDE;
-  virtual void HandleKeyboardEvent(
-      const NativeWebKeyboardEvent& event) OVERRIDE;
-#if defined(OS_WIN) && defined(USE_AURA)
-  virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() OVERRIDE;
-#endif
-
-  bool enabled() const { return enabled_; }
-  WebContents* web_contents() const;
-  const GURL& url() const { return url_; }
-
-  // Creates the RenderViewHost containing the interstitial content.
-  // Overriden in unit tests.
-  virtual RenderViewHost* CreateRenderViewHost();
-
-  // Creates the WebContentsView that shows the interstitial RVH.
-  // Overriden in unit tests.
-  virtual WebContentsView* CreateWebContentsView();
-
-  // Notification magic.
-  NotificationRegistrar notification_registrar_;
-
- private:
-  class InterstitialPageRVHDelegateView;
-
-  // Disable the interstitial:
-  // - if it is not yet showing, then it won't be shown.
-  // - any command sent by the RenderViewHost will be ignored.
-  void Disable();
-
-  // Shutdown the RVH.  We will be deleted by the time this method returns.
-  void Shutdown(RenderViewHostImpl* render_view_host);
-
-  void OnNavigatingAwayOrTabClosing();
-
-  // Executes the passed action on the ResourceDispatcher (on the IO thread).
-  // Used to block/resume/cancel requests for the RenderViewHost hidden by this
-  // interstitial.
-  void TakeActionOnResourceDispatcher(ResourceRequestAction action);
-
-  // The contents in which we are displayed.  This is valid until Hide is
-  // called, at which point it will be set to NULL because the WebContents
-  // itself may be deleted.
-  WebContentsImpl* web_contents_;
-
-  // The URL that is shown when the interstitial is showing.
-  GURL url_;
-
-  // Whether this interstitial is shown as a result of a new navigation (in
-  // which case a transient navigation entry is created).
-  bool new_navigation_;
-
-  // Whether we should discard the pending navigation entry when not proceeding.
-  // This is to deal with cases where |new_navigation_| is true but a new
-  // pending entry was created since this interstitial was shown and we should
-  // not discard it.
-  bool should_discard_pending_nav_entry_;
-
-  // If true and the user chooses not to proceed the target NavigationController
-  // is reloaded. This is used when two NavigationControllers are merged
-  // (CopyStateFromAndPrune).
-  // The default is false.
-  bool reload_on_dont_proceed_;
-
-  // Whether this interstitial is enabled.  See Disable() for more info.
-  bool enabled_;
-
-  // Whether the Proceed or DontProceed methods have been called yet.
-  ActionState action_taken_;
-
-  // The RenderViewHost displaying the interstitial contents.  This is valid
-  // until Hide is called, at which point it will be set to NULL, signifying
-  // that shutdown has started.
-  RenderViewHostImpl* render_view_host_;
-
-  // The frame tree structure of the current page.
-  FrameTree frame_tree_;
-
-  // The IDs for the Render[View|Process]Host hidden by this interstitial.
-  int original_child_id_;
-  int original_rvh_id_;
-
-  // Whether or not we should change the title of the contents when hidden (to
-  // revert it to its original value).
-  bool should_revert_web_contents_title_;
-
-  // Whether or not the contents was loading resources when the interstitial was
-  // shown.  We restore this state if the user proceeds from the interstitial.
-  bool web_contents_was_loading_;
-
-  // Whether the ResourceDispatcherHost has been notified to cancel/resume the
-  // resource requests blocked for the RenderViewHost.
-  bool resource_dispatcher_host_notified_;
-
-  // The original title of the contents that should be reverted to when the
-  // interstitial is hidden.
-  string16 original_web_contents_title_;
-
-  // Our RenderViewHostViewDelegate, necessary for accelerators to work.
-  scoped_ptr<InterstitialPageRVHDelegateView> rvh_delegate_view_;
-
-  // Settings passed to the renderer.
-  mutable RendererPreferences renderer_preferences_;
-
-  bool create_view_;
-
-  scoped_ptr<InterstitialPageDelegate> delegate_;
-
-  base::WeakPtrFactory<InterstitialPageImpl> weak_ptr_factory_;
-
-  scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
-
-  DISALLOW_COPY_AND_ASSIGN(InterstitialPageImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_INTERSTITIAL_PAGE_IMPL_H_
diff --git a/content/browser/web_contents/navigation_controller_impl.cc b/content/browser/web_contents/navigation_controller_impl.cc
deleted file mode 100644
index ebbd866..0000000
--- a/content/browser/web_contents/navigation_controller_impl.cc
+++ /dev/null
@@ -1,1707 +0,0 @@
-// Copyright (c) 2012 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/web_contents/navigation_controller_impl.h"
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"  // Temporary
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "content/browser/browser_url_handler_impl.h"
-#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
-#include "content/browser/dom_storage/session_storage_namespace_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"  // Temporary
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/debug_urls.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/browser/web_contents/web_contents_screenshot_manager.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/invalidate_type.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/escape.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_util.h"
-#include "skia/ext/platform_canvas.h"
-
-namespace content {
-namespace {
-
-const int kInvalidateAll = 0xFFFFFFFF;
-
-// Invoked when entries have been pruned, or removed. For example, if the
-// current entries are [google, digg, yahoo], with the current entry google,
-// and the user types in cnet, then digg and yahoo are pruned.
-void NotifyPrunedEntries(NavigationControllerImpl* nav_controller,
-                         bool from_front,
-                         int count) {
-  PrunedDetails details;
-  details.from_front = from_front;
-  details.count = count;
-  NotificationService::current()->Notify(
-      NOTIFICATION_NAV_LIST_PRUNED,
-      Source<NavigationController>(nav_controller),
-      Details<PrunedDetails>(&details));
-}
-
-// Ensure the given NavigationEntry has a valid state, so that WebKit does not
-// get confused if we navigate back to it.
-//
-// An empty state is treated as a new navigation by WebKit, which would mean
-// losing the navigation entries and generating a new navigation entry after
-// this one. We don't want that. To avoid this we create a valid state which
-// WebKit will not treat as a new navigation.
-void SetPageStateIfEmpty(NavigationEntryImpl* entry) {
-  if (!entry->GetPageState().IsValid())
-    entry->SetPageState(PageState::CreateFromURL(entry->GetURL()));
-}
-
-NavigationEntryImpl::RestoreType ControllerRestoreTypeToEntryType(
-    NavigationController::RestoreType type) {
-  switch (type) {
-    case NavigationController::RESTORE_CURRENT_SESSION:
-      return NavigationEntryImpl::RESTORE_CURRENT_SESSION;
-    case NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY:
-      return NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY;
-    case NavigationController::RESTORE_LAST_SESSION_CRASHED:
-      return NavigationEntryImpl::RESTORE_LAST_SESSION_CRASHED;
-  }
-  NOTREACHED();
-  return NavigationEntryImpl::RESTORE_CURRENT_SESSION;
-}
-
-// Configure all the NavigationEntries in entries for restore. This resets
-// the transition type to reload and makes sure the content state isn't empty.
-void ConfigureEntriesForRestore(
-    std::vector<linked_ptr<NavigationEntryImpl> >* entries,
-    NavigationController::RestoreType type) {
-  for (size_t i = 0; i < entries->size(); ++i) {
-    // Use a transition type of reload so that we don't incorrectly increase
-    // the typed count.
-    (*entries)[i]->SetTransitionType(PAGE_TRANSITION_RELOAD);
-    (*entries)[i]->set_restore_type(ControllerRestoreTypeToEntryType(type));
-    // NOTE(darin): This code is only needed for backwards compat.
-    SetPageStateIfEmpty((*entries)[i].get());
-  }
-}
-
-// See NavigationController::IsURLInPageNavigation for how this works and why.
-bool AreURLsInPageNavigation(const GURL& existing_url,
-                             const GURL& new_url,
-                             bool renderer_says_in_page,
-                             NavigationType navigation_type) {
-  if (existing_url == new_url)
-    return renderer_says_in_page;
-
-  if (!new_url.has_ref()) {
-    // When going back from the ref URL to the non ref one the navigation type
-    // is IN_PAGE.
-    return navigation_type == NAVIGATION_TYPE_IN_PAGE;
-  }
-
-  url_canon::Replacements<char> replacements;
-  replacements.ClearRef();
-  return existing_url.ReplaceComponents(replacements) ==
-      new_url.ReplaceComponents(replacements);
-}
-
-// Determines whether or not we should be carrying over a user agent override
-// between two NavigationEntries.
-bool ShouldKeepOverride(const NavigationEntry* last_entry) {
-  return last_entry && last_entry->GetIsOverridingUserAgent();
-}
-
-}  // namespace
-
-// NavigationControllerImpl ----------------------------------------------------
-
-const size_t kMaxEntryCountForTestingNotSet = -1;
-
-// static
-size_t NavigationControllerImpl::max_entry_count_for_testing_ =
-    kMaxEntryCountForTestingNotSet;
-
-// Should Reload check for post data? The default is true, but is set to false
-// when testing.
-static bool g_check_for_repost = true;
-
-// static
-NavigationEntry* NavigationController::CreateNavigationEntry(
-      const GURL& url,
-      const Referrer& referrer,
-      PageTransition transition,
-      bool is_renderer_initiated,
-      const std::string& extra_headers,
-      BrowserContext* browser_context) {
-  // Allow the browser URL handler to rewrite the URL. This will, for example,
-  // remove "view-source:" from the beginning of the URL to get the URL that
-  // will actually be loaded. This real URL won't be shown to the user, just
-  // used internally.
-  GURL loaded_url(url);
-  bool reverse_on_redirect = false;
-  BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
-      &loaded_url, browser_context, &reverse_on_redirect);
-
-  NavigationEntryImpl* entry = new NavigationEntryImpl(
-      NULL,  // The site instance for tabs is sent on navigation
-             // (WebContents::GetSiteInstance).
-      -1,
-      loaded_url,
-      referrer,
-      string16(),
-      transition,
-      is_renderer_initiated);
-  entry->SetVirtualURL(url);
-  entry->set_user_typed_url(url);
-  entry->set_update_virtual_url_with_url(reverse_on_redirect);
-  entry->set_extra_headers(extra_headers);
-  return entry;
-}
-
-// static
-void NavigationController::DisablePromptOnRepost() {
-  g_check_for_repost = false;
-}
-
-base::Time NavigationControllerImpl::TimeSmoother::GetSmoothedTime(
-    base::Time t) {
-  // If |t| is between the water marks, we're in a run of duplicates
-  // or just getting out of it, so increase the high-water mark to get
-  // a time that probably hasn't been used before and return it.
-  if (low_water_mark_ <= t && t <= high_water_mark_) {
-    high_water_mark_ += base::TimeDelta::FromMicroseconds(1);
-    return high_water_mark_;
-  }
-
-  // Otherwise, we're clear of the last duplicate run, so reset the
-  // water marks.
-  low_water_mark_ = high_water_mark_ = t;
-  return t;
-}
-
-NavigationControllerImpl::NavigationControllerImpl(
-    WebContentsImpl* web_contents,
-    BrowserContext* browser_context)
-    : browser_context_(browser_context),
-      pending_entry_(NULL),
-      last_committed_entry_index_(-1),
-      pending_entry_index_(-1),
-      transient_entry_index_(-1),
-      web_contents_(web_contents),
-      max_restored_page_id_(-1),
-      ssl_manager_(this),
-      needs_reload_(false),
-      is_initial_navigation_(true),
-      pending_reload_(NO_RELOAD),
-      get_timestamp_callback_(base::Bind(&base::Time::Now)),
-      screenshot_manager_(new WebContentsScreenshotManager(this)) {
-  DCHECK(browser_context_);
-}
-
-NavigationControllerImpl::~NavigationControllerImpl() {
-  DiscardNonCommittedEntriesInternal();
-}
-
-WebContents* NavigationControllerImpl::GetWebContents() const {
-  return web_contents_;
-}
-
-BrowserContext* NavigationControllerImpl::GetBrowserContext() const {
-  return browser_context_;
-}
-
-void NavigationControllerImpl::SetBrowserContext(
-    BrowserContext* browser_context) {
-  browser_context_ = browser_context;
-}
-
-void NavigationControllerImpl::Restore(
-    int selected_navigation,
-    RestoreType type,
-    std::vector<NavigationEntry*>* entries) {
-  // Verify that this controller is unused and that the input is valid.
-  DCHECK(GetEntryCount() == 0 && !GetPendingEntry());
-  DCHECK(selected_navigation >= 0 &&
-         selected_navigation < static_cast<int>(entries->size()));
-
-  needs_reload_ = true;
-  for (size_t i = 0; i < entries->size(); ++i) {
-    NavigationEntryImpl* entry =
-        NavigationEntryImpl::FromNavigationEntry((*entries)[i]);
-    entries_.push_back(linked_ptr<NavigationEntryImpl>(entry));
-  }
-  entries->clear();
-
-  // And finish the restore.
-  FinishRestore(selected_navigation, type);
-}
-
-void NavigationControllerImpl::Reload(bool check_for_repost) {
-  ReloadInternal(check_for_repost, RELOAD);
-}
-void NavigationControllerImpl::ReloadIgnoringCache(bool check_for_repost) {
-  ReloadInternal(check_for_repost, RELOAD_IGNORING_CACHE);
-}
-void NavigationControllerImpl::ReloadOriginalRequestURL(bool check_for_repost) {
-  ReloadInternal(check_for_repost, RELOAD_ORIGINAL_REQUEST_URL);
-}
-
-void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
-                                              ReloadType reload_type) {
-  if (transient_entry_index_ != -1) {
-    // If an interstitial is showing, treat a reload as a navigation to the
-    // transient entry's URL.
-    NavigationEntryImpl* transient_entry =
-        NavigationEntryImpl::FromNavigationEntry(GetTransientEntry());
-    if (!transient_entry)
-      return;
-    LoadURL(transient_entry->GetURL(),
-            Referrer(),
-            PAGE_TRANSITION_RELOAD,
-            transient_entry->extra_headers());
-    return;
-  }
-
-  NavigationEntryImpl* entry = NULL;
-  int current_index = -1;
-
-  // If we are reloading the initial navigation, just use the current
-  // pending entry.  Otherwise look up the current entry.
-  if (IsInitialNavigation() && pending_entry_) {
-    entry = pending_entry_;
-    // The pending entry might be in entries_ (e.g., after a Clone), so we
-    // should also update the current_index.
-    current_index = pending_entry_index_;
-  } else {
-    DiscardNonCommittedEntriesInternal();
-    current_index = GetCurrentEntryIndex();
-    if (current_index != -1) {
-      entry = NavigationEntryImpl::FromNavigationEntry(
-          GetEntryAtIndex(current_index));
-    }
-  }
-
-  // If we are no where, then we can't reload.  TODO(darin): We should add a
-  // CanReload method.
-  if (!entry)
-    return;
-
-  if (reload_type == NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL &&
-      entry->GetOriginalRequestURL().is_valid() && !entry->GetHasPostData()) {
-    // We may have been redirected when navigating to the current URL.
-    // Use the URL the user originally intended to visit, if it's valid and if a
-    // POST wasn't involved; the latter case avoids issues with sending data to
-    // the wrong page.
-    entry->SetURL(entry->GetOriginalRequestURL());
-  }
-
-  if (g_check_for_repost && check_for_repost &&
-      entry->GetHasPostData()) {
-    // The user is asking to reload a page with POST data. Prompt to make sure
-    // they really want to do this. If they do, the dialog will call us back
-    // with check_for_repost = false.
-    web_contents_->NotifyBeforeFormRepostWarningShow();
-
-    pending_reload_ = reload_type;
-    web_contents_->Activate();
-    web_contents_->GetDelegate()->ShowRepostFormWarningDialog(web_contents_);
-  } else {
-    if (!IsInitialNavigation())
-      DiscardNonCommittedEntriesInternal();
-
-    // If we are reloading an entry that no longer belongs to the current
-    // site instance (for example, refreshing a page for just installed app),
-    // the reload must happen in a new process.
-    // The new entry must have a new page_id and site instance, so it behaves
-    // as new navigation (which happens to clear forward history).
-    // Tabs that are discarded due to low memory conditions may not have a site
-    // instance, and should not be treated as a cross-site reload.
-    SiteInstanceImpl* site_instance = entry->site_instance();
-    if (site_instance &&
-        site_instance->HasWrongProcessForURL(entry->GetURL())) {
-      // Create a navigation entry that resembles the current one, but do not
-      // copy page id, site instance, content state, or timestamp.
-      NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry(
-          CreateNavigationEntry(
-              entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(),
-              false, entry->extra_headers(), browser_context_));
-
-      // Mark the reload type as NO_RELOAD, so navigation will not be considered
-      // a reload in the renderer.
-      reload_type = NavigationController::NO_RELOAD;
-
-      nav_entry->set_should_replace_entry(true);
-      pending_entry_ = nav_entry;
-    } else {
-      pending_entry_ = entry;
-      pending_entry_index_ = current_index;
-
-      // The title of the page being reloaded might have been removed in the
-      // meanwhile, so we need to revert to the default title upon reload and
-      // invalidate the previously cached title (SetTitle will do both).
-      // See Chromium issue 96041.
-      pending_entry_->SetTitle(string16());
-
-      pending_entry_->SetTransitionType(PAGE_TRANSITION_RELOAD);
-    }
-
-    NavigateToPendingEntry(reload_type);
-  }
-}
-
-void NavigationControllerImpl::CancelPendingReload() {
-  DCHECK(pending_reload_ != NO_RELOAD);
-  pending_reload_ = NO_RELOAD;
-}
-
-void NavigationControllerImpl::ContinuePendingReload() {
-  if (pending_reload_ == NO_RELOAD) {
-    NOTREACHED();
-  } else {
-    ReloadInternal(false, pending_reload_);
-    pending_reload_ = NO_RELOAD;
-  }
-}
-
-bool NavigationControllerImpl::IsInitialNavigation() const {
-  return is_initial_navigation_;
-}
-
-NavigationEntryImpl* NavigationControllerImpl::GetEntryWithPageID(
-  SiteInstance* instance, int32 page_id) const {
-  int index = GetEntryIndexWithPageID(instance, page_id);
-  return (index != -1) ? entries_[index].get() : NULL;
-}
-
-void NavigationControllerImpl::LoadEntry(NavigationEntryImpl* entry) {
-  // When navigating to a new page, we don't know for sure if we will actually
-  // end up leaving the current page.  The new page load could for example
-  // result in a download or a 'no content' response (e.g., a mailto: URL).
-  SetPendingEntry(entry);
-  NavigateToPendingEntry(NO_RELOAD);
-}
-
-void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) {
-  DiscardNonCommittedEntriesInternal();
-  pending_entry_ = entry;
-  NotificationService::current()->Notify(
-      NOTIFICATION_NAV_ENTRY_PENDING,
-      Source<NavigationController>(this),
-      Details<NavigationEntry>(entry));
-}
-
-NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
-  if (transient_entry_index_ != -1)
-    return entries_[transient_entry_index_].get();
-  if (pending_entry_)
-    return pending_entry_;
-  return GetLastCommittedEntry();
-}
-
-NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
-  if (transient_entry_index_ != -1)
-    return entries_[transient_entry_index_].get();
-  // The pending entry is safe to return for new (non-history), browser-
-  // initiated navigations.  Most renderer-initiated navigations should not
-  // show the pending entry, to prevent URL spoof attacks.
-  //
-  // We make an exception for renderer-initiated navigations in new tabs, as
-  // long as no other page has tried to access the initial empty document in
-  // the new tab.  If another page modifies this blank page, a URL spoof is
-  // possible, so we must stop showing the pending entry.
-  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
-      web_contents_->GetRenderViewHost());
-  bool safe_to_show_pending =
-      pending_entry_ &&
-      // Require a new navigation.
-      pending_entry_->GetPageID() == -1 &&
-      // Require either browser-initiated or an unmodified new tab.
-      (!pending_entry_->is_renderer_initiated() ||
-       (IsInitialNavigation() &&
-        !GetLastCommittedEntry() &&
-        !rvh->has_accessed_initial_document()));
-
-  // Also allow showing the pending entry for history navigations in a new tab,
-  // such as Ctrl+Back.  In this case, no existing page is visible and no one
-  // can script the new tab before it commits.
-  if (!safe_to_show_pending &&
-      pending_entry_ &&
-      pending_entry_->GetPageID() != -1 &&
-      IsInitialNavigation() &&
-      !pending_entry_->is_renderer_initiated())
-    safe_to_show_pending = true;
-
-  if (safe_to_show_pending)
-    return pending_entry_;
-  return GetLastCommittedEntry();
-}
-
-int NavigationControllerImpl::GetCurrentEntryIndex() const {
-  if (transient_entry_index_ != -1)
-    return transient_entry_index_;
-  if (pending_entry_index_ != -1)
-    return pending_entry_index_;
-  return last_committed_entry_index_;
-}
-
-NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
-  if (last_committed_entry_index_ == -1)
-    return NULL;
-  return entries_[last_committed_entry_index_].get();
-}
-
-bool NavigationControllerImpl::CanViewSource() const {
-  const std::string& mime_type = web_contents_->GetContentsMimeType();
-  bool is_viewable_mime_type = net::IsSupportedNonImageMimeType(mime_type) &&
-      !net::IsSupportedMediaMimeType(mime_type);
-  NavigationEntry* visible_entry = GetVisibleEntry();
-  return visible_entry && !visible_entry->IsViewSourceMode() &&
-      is_viewable_mime_type && !web_contents_->GetInterstitialPage();
-}
-
-int NavigationControllerImpl::GetLastCommittedEntryIndex() const {
-  return last_committed_entry_index_;
-}
-
-int NavigationControllerImpl::GetEntryCount() const {
-  DCHECK(entries_.size() <= max_entry_count());
-  return static_cast<int>(entries_.size());
-}
-
-NavigationEntry* NavigationControllerImpl::GetEntryAtIndex(
-    int index) const {
-  return entries_.at(index).get();
-}
-
-NavigationEntry* NavigationControllerImpl::GetEntryAtOffset(
-    int offset) const {
-  int index = GetIndexForOffset(offset);
-  if (index < 0 || index >= GetEntryCount())
-    return NULL;
-
-  return entries_[index].get();
-}
-
-int NavigationControllerImpl::GetIndexForOffset(int offset) const {
-  return GetCurrentEntryIndex() + offset;
-}
-
-void NavigationControllerImpl::TakeScreenshot() {
-  screenshot_manager_->TakeScreenshot();
-}
-
-void NavigationControllerImpl::SetScreenshotManager(
-    WebContentsScreenshotManager* manager) {
-  screenshot_manager_.reset(manager ? manager :
-                            new WebContentsScreenshotManager(this));
-}
-
-bool NavigationControllerImpl::CanGoBack() const {
-  return entries_.size() > 1 && GetCurrentEntryIndex() > 0;
-}
-
-bool NavigationControllerImpl::CanGoForward() const {
-  int index = GetCurrentEntryIndex();
-  return index >= 0 && index < (static_cast<int>(entries_.size()) - 1);
-}
-
-bool NavigationControllerImpl::CanGoToOffset(int offset) const {
-  int index = GetIndexForOffset(offset);
-  return index >= 0 && index < GetEntryCount();
-}
-
-void NavigationControllerImpl::GoBack() {
-  if (!CanGoBack()) {
-    NOTREACHED();
-    return;
-  }
-
-  // Base the navigation on where we are now...
-  int current_index = GetCurrentEntryIndex();
-
-  DiscardNonCommittedEntries();
-
-  pending_entry_index_ = current_index - 1;
-  entries_[pending_entry_index_]->SetTransitionType(
-      PageTransitionFromInt(
-          entries_[pending_entry_index_]->GetTransitionType() |
-          PAGE_TRANSITION_FORWARD_BACK));
-  NavigateToPendingEntry(NO_RELOAD);
-}
-
-void NavigationControllerImpl::GoForward() {
-  if (!CanGoForward()) {
-    NOTREACHED();
-    return;
-  }
-
-  bool transient = (transient_entry_index_ != -1);
-
-  // Base the navigation on where we are now...
-  int current_index = GetCurrentEntryIndex();
-
-  DiscardNonCommittedEntries();
-
-  pending_entry_index_ = current_index;
-  // If there was a transient entry, we removed it making the current index
-  // the next page.
-  if (!transient)
-    pending_entry_index_++;
-
-  entries_[pending_entry_index_]->SetTransitionType(
-      PageTransitionFromInt(
-          entries_[pending_entry_index_]->GetTransitionType() |
-          PAGE_TRANSITION_FORWARD_BACK));
-  NavigateToPendingEntry(NO_RELOAD);
-}
-
-void NavigationControllerImpl::GoToIndex(int index) {
-  if (index < 0 || index >= static_cast<int>(entries_.size())) {
-    NOTREACHED();
-    return;
-  }
-
-  if (transient_entry_index_ != -1) {
-    if (index == transient_entry_index_) {
-      // Nothing to do when navigating to the transient.
-      return;
-    }
-    if (index > transient_entry_index_) {
-      // Removing the transient is goint to shift all entries by 1.
-      index--;
-    }
-  }
-
-  DiscardNonCommittedEntries();
-
-  pending_entry_index_ = index;
-  entries_[pending_entry_index_]->SetTransitionType(
-      PageTransitionFromInt(
-          entries_[pending_entry_index_]->GetTransitionType() |
-          PAGE_TRANSITION_FORWARD_BACK));
-  NavigateToPendingEntry(NO_RELOAD);
-}
-
-void NavigationControllerImpl::GoToOffset(int offset) {
-  if (!CanGoToOffset(offset))
-    return;
-
-  GoToIndex(GetIndexForOffset(offset));
-}
-
-bool NavigationControllerImpl::RemoveEntryAtIndex(int index) {
-  if (index == last_committed_entry_index_ ||
-      index == pending_entry_index_)
-    return false;
-
-  RemoveEntryAtIndexInternal(index);
-  return true;
-}
-
-void NavigationControllerImpl::UpdateVirtualURLToURL(
-    NavigationEntryImpl* entry, const GURL& new_url) {
-  GURL new_virtual_url(new_url);
-  if (BrowserURLHandlerImpl::GetInstance()->ReverseURLRewrite(
-          &new_virtual_url, entry->GetVirtualURL(), browser_context_)) {
-    entry->SetVirtualURL(new_virtual_url);
-  }
-}
-
-void NavigationControllerImpl::LoadURL(
-    const GURL& url,
-    const Referrer& referrer,
-    PageTransition transition,
-    const std::string& extra_headers) {
-  LoadURLParams params(url);
-  params.referrer = referrer;
-  params.transition_type = transition;
-  params.extra_headers = extra_headers;
-  LoadURLWithParams(params);
-}
-
-void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
-  TRACE_EVENT0("browser", "NavigationControllerImpl::LoadURLWithParams");
-  if (HandleDebugURL(params.url, params.transition_type))
-    return;
-
-  // Checks based on params.load_type.
-  switch (params.load_type) {
-    case LOAD_TYPE_DEFAULT:
-      break;
-    case LOAD_TYPE_BROWSER_INITIATED_HTTP_POST:
-      if (!params.url.SchemeIs(kHttpScheme) &&
-          !params.url.SchemeIs(kHttpsScheme)) {
-        NOTREACHED() << "Http post load must use http(s) scheme.";
-        return;
-      }
-      break;
-    case LOAD_TYPE_DATA:
-      if (!params.url.SchemeIs(chrome::kDataScheme)) {
-        NOTREACHED() << "Data load must use data scheme.";
-        return;
-      }
-      break;
-    default:
-      NOTREACHED();
-      break;
-  };
-
-  // The user initiated a load, we don't need to reload anymore.
-  needs_reload_ = false;
-
-  bool override = false;
-  switch (params.override_user_agent) {
-    case UA_OVERRIDE_INHERIT:
-      override = ShouldKeepOverride(GetLastCommittedEntry());
-      break;
-    case UA_OVERRIDE_TRUE:
-      override = true;
-      break;
-    case UA_OVERRIDE_FALSE:
-      override = false;
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-      CreateNavigationEntry(
-          params.url,
-          params.referrer,
-          params.transition_type,
-          params.is_renderer_initiated,
-          params.extra_headers,
-          browser_context_));
-  if (params.should_replace_current_entry)
-    entry->set_should_replace_entry(true);
-  entry->set_should_clear_history_list(params.should_clear_history_list);
-  entry->SetIsOverridingUserAgent(override);
-  entry->set_transferred_global_request_id(
-      params.transferred_global_request_id);
-  entry->SetFrameToNavigate(params.frame_name);
-
-  switch (params.load_type) {
-    case LOAD_TYPE_DEFAULT:
-      break;
-    case LOAD_TYPE_BROWSER_INITIATED_HTTP_POST:
-      entry->SetHasPostData(true);
-      entry->SetBrowserInitiatedPostData(
-          params.browser_initiated_post_data.get());
-      break;
-    case LOAD_TYPE_DATA:
-      entry->SetBaseURLForDataURL(params.base_url_for_data_url);
-      entry->SetVirtualURL(params.virtual_url_for_data_url);
-      entry->SetCanLoadLocalResources(params.can_load_local_resources);
-      break;
-    default:
-      NOTREACHED();
-      break;
-  };
-
-  LoadEntry(entry);
-}
-
-bool NavigationControllerImpl::RendererDidNavigate(
-    const ViewHostMsg_FrameNavigate_Params& params,
-    LoadCommittedDetails* details) {
-  is_initial_navigation_ = false;
-
-  // Save the previous state before we clobber it.
-  if (GetLastCommittedEntry()) {
-    details->previous_url = GetLastCommittedEntry()->GetURL();
-    details->previous_entry_index = GetLastCommittedEntryIndex();
-  } else {
-    details->previous_url = GURL();
-    details->previous_entry_index = -1;
-  }
-
-  // If we have a pending entry at this point, it should have a SiteInstance.
-  // Restored entries start out with a null SiteInstance, but we should have
-  // assigned one in NavigateToPendingEntry.
-  DCHECK(pending_entry_index_ == -1 || pending_entry_->site_instance());
-
-  // If we are doing a cross-site reload, we need to replace the existing
-  // navigation entry, not add another entry to the history. This has the side
-  // effect of removing forward browsing history, if such existed.
-  // Or if we are doing a cross-site redirect navigation,
-  // we will do a similar thing.
-  details->did_replace_entry =
-      pending_entry_ && pending_entry_->should_replace_entry();
-
-  // Do navigation-type specific actions. These will make and commit an entry.
-  details->type = ClassifyNavigation(params);
-
-  // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = IsURLInPageNavigation(
-      params.url, params.was_within_same_page, details->type);
-
-  switch (details->type) {
-    case NAVIGATION_TYPE_NEW_PAGE:
-      RendererDidNavigateToNewPage(params, details->did_replace_entry);
-      break;
-    case NAVIGATION_TYPE_EXISTING_PAGE:
-      RendererDidNavigateToExistingPage(params);
-      break;
-    case NAVIGATION_TYPE_SAME_PAGE:
-      RendererDidNavigateToSamePage(params);
-      break;
-    case NAVIGATION_TYPE_IN_PAGE:
-      RendererDidNavigateInPage(params, &details->did_replace_entry);
-      break;
-    case NAVIGATION_TYPE_NEW_SUBFRAME:
-      RendererDidNavigateNewSubframe(params);
-      break;
-    case NAVIGATION_TYPE_AUTO_SUBFRAME:
-      if (!RendererDidNavigateAutoSubframe(params))
-        return false;
-      break;
-    case NAVIGATION_TYPE_NAV_IGNORE:
-      // If a pending navigation was in progress, this canceled it.  We should
-      // discard it and make sure it is removed from the URL bar.  After that,
-      // there is nothing we can do with this navigation, so we just return to
-      // the caller that nothing has happened.
-      if (pending_entry_) {
-        DiscardNonCommittedEntries();
-        web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
-      }
-      return false;
-    default:
-      NOTREACHED();
-  }
-
-  // At this point, we know that the navigation has just completed, so
-  // record the time.
-  //
-  // TODO(akalin): Use "sane time" as described in
-  // http://www.chromium.org/developers/design-documents/sane-time .
-  base::Time timestamp =
-      time_smoother_.GetSmoothedTime(get_timestamp_callback_.Run());
-  DVLOG(1) << "Navigation finished at (smoothed) timestamp "
-           << timestamp.ToInternalValue();
-
-  // We should not have a pending entry anymore.  Clear it again in case any
-  // error cases above forgot to do so.
-  DiscardNonCommittedEntriesInternal();
-
-  // All committed entries should have nonempty content state so WebKit doesn't
-  // get confused when we go back to them (see the function for details).
-  DCHECK(params.page_state.IsValid());
-  NavigationEntryImpl* active_entry =
-      NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
-  active_entry->SetTimestamp(timestamp);
-  active_entry->SetHttpStatusCode(params.http_status_code);
-  active_entry->SetPageState(params.page_state);
-  // No longer needed since content state will hold the post data if any.
-  active_entry->SetBrowserInitiatedPostData(NULL);
-
-  // Once committed, we do not need to track if the entry was initiated by
-  // the renderer.
-  active_entry->set_is_renderer_initiated(false);
-
-  // Once committed, we no longer need to track whether the session history was
-  // cleared. Navigating to this entry again shouldn't clear it again.
-  active_entry->set_should_clear_history_list(false);
-
-  // The active entry's SiteInstance should match our SiteInstance.
-  CHECK(active_entry->site_instance() == web_contents_->GetSiteInstance());
-
-  // Remember the bindings the renderer process has at this point, so that
-  // we do not grant this entry additional bindings if we come back to it.
-  active_entry->SetBindings(
-      web_contents_->GetRenderViewHost()->GetEnabledBindings());
-
-  // Now prep the rest of the details for the notification and broadcast.
-  details->entry = active_entry;
-  details->is_main_frame =
-      PageTransitionIsMainFrame(params.transition);
-  details->serialized_security_info = params.security_info;
-  details->http_status_code = params.http_status_code;
-  NotifyNavigationEntryCommitted(details);
-
-  return true;
-}
-
-NavigationType NavigationControllerImpl::ClassifyNavigation(
-    const ViewHostMsg_FrameNavigate_Params& params) const {
-  if (params.page_id == -1) {
-    // The renderer generates the page IDs, and so if it gives us the invalid
-    // page ID (-1) we know it didn't actually navigate. This happens in a few
-    // cases:
-    //
-    // - If a page makes a popup navigated to about blank, and then writes
-    //   stuff like a subframe navigated to a real page. We'll get the commit
-    //   for the subframe, but there won't be any commit for the outer page.
-    //
-    // - We were also getting these for failed loads (for example, bug 21849).
-    //   The guess is that we get a "load commit" for the alternate error page,
-    //   but that doesn't affect the page ID, so we get the "old" one, which
-    //   could be invalid. This can also happen for a cross-site transition
-    //   that causes us to swap processes. Then the error page load will be in
-    //   a new process with no page IDs ever assigned (and hence a -1 value),
-    //   yet the navigation controller still might have previous pages in its
-    //   list.
-    //
-    // In these cases, there's nothing we can do with them, so ignore.
-    return NAVIGATION_TYPE_NAV_IGNORE;
-  }
-
-  if (params.page_id > web_contents_->GetMaxPageID()) {
-    // Greater page IDs than we've ever seen before are new pages. We may or may
-    // not have a pending entry for the page, and this may or may not be the
-    // main frame.
-    if (PageTransitionIsMainFrame(params.transition))
-      return NAVIGATION_TYPE_NEW_PAGE;
-
-    // When this is a new subframe navigation, we should have a committed page
-    // for which it's a suframe in. This may not be the case when an iframe is
-    // navigated on a popup navigated to about:blank (the iframe would be
-    // written into the popup by script on the main page). For these cases,
-    // there isn't any navigation stuff we can do, so just ignore it.
-    if (!GetLastCommittedEntry())
-      return NAVIGATION_TYPE_NAV_IGNORE;
-
-    // Valid subframe navigation.
-    return NAVIGATION_TYPE_NEW_SUBFRAME;
-  }
-
-  // We only clear the session history when navigating to a new page.
-  DCHECK(!params.history_list_was_cleared);
-
-  // Now we know that the notification is for an existing page. Find that entry.
-  int existing_entry_index = GetEntryIndexWithPageID(
-      web_contents_->GetSiteInstance(),
-      params.page_id);
-  if (existing_entry_index == -1) {
-    // The page was not found. It could have been pruned because of the limit on
-    // back/forward entries (not likely since we'll usually tell it to navigate
-    // to such entries). It could also mean that the renderer is smoking crack.
-    NOTREACHED();
-
-    // Because the unknown entry has committed, we risk showing the wrong URL in
-    // release builds. Instead, we'll kill the renderer process to be safe.
-    LOG(ERROR) << "terminating renderer for bad navigation: " << params.url;
-    RecordAction(UserMetricsAction("BadMessageTerminate_NC"));
-
-    // Temporary code so we can get more information.  Format:
-    //  http://url/foo.html#page1#max3#frame1#ids:2_Nx,1_1x,3_2
-    std::string temp = params.url.spec();
-    temp.append("#page");
-    temp.append(base::IntToString(params.page_id));
-    temp.append("#max");
-    temp.append(base::IntToString(web_contents_->GetMaxPageID()));
-    temp.append("#frame");
-    temp.append(base::IntToString(params.frame_id));
-    temp.append("#ids");
-    for (int i = 0; i < static_cast<int>(entries_.size()); ++i) {
-      // Append entry metadata (e.g., 3_7x):
-      //  3: page_id
-      //  7: SiteInstance ID, or N for null
-      //  x: appended if not from the current SiteInstance
-      temp.append(base::IntToString(entries_[i]->GetPageID()));
-      temp.append("_");
-      if (entries_[i]->site_instance())
-        temp.append(base::IntToString(entries_[i]->site_instance()->GetId()));
-      else
-        temp.append("N");
-      if (entries_[i]->site_instance() != web_contents_->GetSiteInstance())
-        temp.append("x");
-      temp.append(",");
-    }
-    GURL url(temp);
-    static_cast<RenderViewHostImpl*>(
-        web_contents_->GetRenderViewHost())->Send(
-            new ViewMsg_TempCrashWithData(url));
-    return NAVIGATION_TYPE_NAV_IGNORE;
-  }
-  NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
-
-  if (!PageTransitionIsMainFrame(params.transition)) {
-    // All manual subframes would get new IDs and were handled above, so we
-    // know this is auto. Since the current page was found in the navigation
-    // entry list, we're guaranteed to have a last committed entry.
-    DCHECK(GetLastCommittedEntry());
-    return NAVIGATION_TYPE_AUTO_SUBFRAME;
-  }
-
-  // Anything below here we know is a main frame navigation.
-  if (pending_entry_ &&
-      !pending_entry_->is_renderer_initiated() &&
-      existing_entry != pending_entry_ &&
-      pending_entry_->GetPageID() == -1 &&
-      existing_entry == GetLastCommittedEntry()) {
-    // In this case, we have a pending entry for a URL but WebCore didn't do a
-    // new navigation. This happens when you press enter in the URL bar to
-    // reload. We will create a pending entry, but WebKit will convert it to
-    // a reload since it's the same page and not create a new entry for it
-    // (the user doesn't want to have a new back/forward entry when they do
-    // this). If this matches the last committed entry, we want to just ignore
-    // the pending entry and go back to where we were (the "existing entry").
-    return NAVIGATION_TYPE_SAME_PAGE;
-  }
-
-  // Any toplevel navigations with the same base (minus the reference fragment)
-  // are in-page navigations. We weeded out subframe navigations above. Most of
-  // the time this doesn't matter since WebKit doesn't tell us about subframe
-  // navigations that don't actually navigate, but it can happen when there is
-  // an encoding override (it always sends a navigation request).
-  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page,
-                              NAVIGATION_TYPE_UNKNOWN)) {
-    return NAVIGATION_TYPE_IN_PAGE;
-  }
-
-  // Since we weeded out "new" navigations above, we know this is an existing
-  // (back/forward) navigation.
-  return NAVIGATION_TYPE_EXISTING_PAGE;
-}
-
-bool NavigationControllerImpl::IsRedirect(
-  const ViewHostMsg_FrameNavigate_Params& params) {
-  // For main frame transition, we judge by params.transition.
-  // Otherwise, by params.redirects.
-  if (PageTransitionIsMainFrame(params.transition)) {
-    return PageTransitionIsRedirect(params.transition);
-  }
-  return params.redirects.size() > 1;
-}
-
-void NavigationControllerImpl::RendererDidNavigateToNewPage(
-    const ViewHostMsg_FrameNavigate_Params& params, bool replace_entry) {
-  NavigationEntryImpl* new_entry;
-  bool update_virtual_url;
-  // Only make a copy of the pending entry if it is appropriate for the new page
-  // that was just loaded.  We verify this at a coarse grain by checking that
-  // the SiteInstance hasn't been assigned to something else.
-  if (pending_entry_ &&
-      (!pending_entry_->site_instance() ||
-       pending_entry_->site_instance() == web_contents_->GetSiteInstance())) {
-    new_entry = new NavigationEntryImpl(*pending_entry_);
-
-    // Don't use the page type from the pending entry. Some interstitial page
-    // may have set the type to interstitial. Once we commit, however, the page
-    // type must always be normal.
-    new_entry->set_page_type(PAGE_TYPE_NORMAL);
-    update_virtual_url = new_entry->update_virtual_url_with_url();
-  } else {
-    new_entry = new NavigationEntryImpl;
-
-    // Find out whether the new entry needs to update its virtual URL on URL
-    // change and set up the entry accordingly. This is needed to correctly
-    // update the virtual URL when replaceState is called after a pushState.
-    GURL url = params.url;
-    bool needs_update = false;
-    BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
-        &url, browser_context_, &needs_update);
-    new_entry->set_update_virtual_url_with_url(needs_update);
-
-    // When navigating to a new page, give the browser URL handler a chance to
-    // update the virtual URL based on the new URL. For example, this is needed
-    // to show chrome://bookmarks/#1 when the bookmarks webui extension changes
-    // the URL.
-    update_virtual_url = needs_update;
-  }
-
-  new_entry->SetURL(params.url);
-  if (update_virtual_url)
-    UpdateVirtualURLToURL(new_entry, params.url);
-  new_entry->SetReferrer(params.referrer);
-  new_entry->SetPageID(params.page_id);
-  new_entry->SetTransitionType(params.transition);
-  new_entry->set_site_instance(
-      static_cast<SiteInstanceImpl*>(web_contents_->GetSiteInstance()));
-  new_entry->SetHasPostData(params.is_post);
-  new_entry->SetPostID(params.post_id);
-  new_entry->SetOriginalRequestURL(params.original_request_url);
-  new_entry->SetIsOverridingUserAgent(params.is_overriding_user_agent);
-
-  DCHECK(!params.history_list_was_cleared || !replace_entry);
-  // The browser requested to clear the session history when it initiated the
-  // navigation. Now we know that the renderer has updated its state accordingly
-  // and it is safe to also clear the browser side history.
-  if (params.history_list_was_cleared) {
-    DiscardNonCommittedEntriesInternal();
-    entries_.clear();
-    last_committed_entry_index_ = -1;
-  }
-
-  InsertOrReplaceEntry(new_entry, replace_entry);
-}
-
-void NavigationControllerImpl::RendererDidNavigateToExistingPage(
-    const ViewHostMsg_FrameNavigate_Params& params) {
-  // We should only get here for main frame navigations.
-  DCHECK(PageTransitionIsMainFrame(params.transition));
-
-  // This is a back/forward navigation. The existing page for the ID is
-  // guaranteed to exist by ClassifyNavigation, and we just need to update it
-  // with new information from the renderer.
-  int entry_index = GetEntryIndexWithPageID(web_contents_->GetSiteInstance(),
-                                            params.page_id);
-  DCHECK(entry_index >= 0 &&
-         entry_index < static_cast<int>(entries_.size()));
-  NavigationEntryImpl* entry = entries_[entry_index].get();
-
-  // The URL may have changed due to redirects.
-  entry->SetURL(params.url);
-  if (entry->update_virtual_url_with_url())
-    UpdateVirtualURLToURL(entry, params.url);
-
-  // The redirected to page should not inherit the favicon from the previous
-  // page.
-  if (PageTransitionIsRedirect(params.transition))
-    entry->GetFavicon() = FaviconStatus();
-
-  // The site instance will normally be the same except during session restore,
-  // when no site instance will be assigned.
-  DCHECK(entry->site_instance() == NULL ||
-         entry->site_instance() == web_contents_->GetSiteInstance());
-  entry->set_site_instance(
-      static_cast<SiteInstanceImpl*>(web_contents_->GetSiteInstance()));
-
-  entry->SetHasPostData(params.is_post);
-  entry->SetPostID(params.post_id);
-
-  // The entry we found in the list might be pending if the user hit
-  // back/forward/reload. This load should commit it (since it's already in the
-  // list, we can just discard the pending pointer).  We should also discard the
-  // pending entry if it corresponds to a different navigation, since that one
-  // is now likely canceled.  If it is not canceled, we will treat it as a new
-  // navigation when it arrives, which is also ok.
-  //
-  // Note that we need to use the "internal" version since we don't want to
-  // actually change any other state, just kill the pointer.
-  DiscardNonCommittedEntriesInternal();
-
-  // If a transient entry was removed, the indices might have changed, so we
-  // have to query the entry index again.
-  last_committed_entry_index_ =
-      GetEntryIndexWithPageID(web_contents_->GetSiteInstance(), params.page_id);
-}
-
-void NavigationControllerImpl::RendererDidNavigateToSamePage(
-    const ViewHostMsg_FrameNavigate_Params& params) {
-  // This mode implies we have a pending entry that's the same as an existing
-  // entry for this page ID. This entry is guaranteed to exist by
-  // ClassifyNavigation. All we need to do is update the existing entry.
-  NavigationEntryImpl* existing_entry = GetEntryWithPageID(
-      web_contents_->GetSiteInstance(), params.page_id);
-
-  // We assign the entry's unique ID to be that of the new one. Since this is
-  // always the result of a user action, we want to dismiss infobars, etc. like
-  // a regular user-initiated navigation.
-  existing_entry->set_unique_id(pending_entry_->GetUniqueID());
-
-  // The URL may have changed due to redirects.
-  if (existing_entry->update_virtual_url_with_url())
-    UpdateVirtualURLToURL(existing_entry, params.url);
-  existing_entry->SetURL(params.url);
-
-  DiscardNonCommittedEntries();
-}
-
-void NavigationControllerImpl::RendererDidNavigateInPage(
-    const ViewHostMsg_FrameNavigate_Params& params, bool* did_replace_entry) {
-  DCHECK(PageTransitionIsMainFrame(params.transition)) <<
-      "WebKit should only tell us about in-page navs for the main frame.";
-  // We're guaranteed to have an entry for this one.
-  NavigationEntryImpl* existing_entry = GetEntryWithPageID(
-      web_contents_->GetSiteInstance(), params.page_id);
-
-  // Reference fragment navigation. We're guaranteed to have the last_committed
-  // entry and it will be the same page as the new navigation (minus the
-  // reference fragments, of course).  We'll update the URL of the existing
-  // entry without pruning the forward history.
-  existing_entry->SetURL(params.url);
-  if (existing_entry->update_virtual_url_with_url())
-    UpdateVirtualURLToURL(existing_entry, params.url);
-
-  // This replaces the existing entry since the page ID didn't change.
-  *did_replace_entry = true;
-
-  DiscardNonCommittedEntriesInternal();
-
-  // If a transient entry was removed, the indices might have changed, so we
-  // have to query the entry index again.
-  last_committed_entry_index_ =
-      GetEntryIndexWithPageID(web_contents_->GetSiteInstance(), params.page_id);
-}
-
-void NavigationControllerImpl::RendererDidNavigateNewSubframe(
-    const ViewHostMsg_FrameNavigate_Params& params) {
-  if (PageTransitionCoreTypeIs(params.transition,
-                               PAGE_TRANSITION_AUTO_SUBFRAME)) {
-    // This is not user-initiated. Ignore.
-    DiscardNonCommittedEntriesInternal();
-    return;
-  }
-
-  // Manual subframe navigations just get the current entry cloned so the user
-  // can go back or forward to it. The actual subframe information will be
-  // stored in the page state for each of those entries. This happens out of
-  // band with the actual navigations.
-  DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee "
-                                  << "that a last committed entry exists.";
-  NavigationEntryImpl* new_entry = new NavigationEntryImpl(
-      *NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()));
-  new_entry->SetPageID(params.page_id);
-  InsertOrReplaceEntry(new_entry, false);
-}
-
-bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
-    const ViewHostMsg_FrameNavigate_Params& params) {
-  // We're guaranteed to have a previously committed entry, and we now need to
-  // handle navigation inside of a subframe in it without creating a new entry.
-  DCHECK(GetLastCommittedEntry());
-
-  // Handle the case where we're navigating back/forward to a previous subframe
-  // navigation entry. This is case "2." in NAV_AUTO_SUBFRAME comment in the
-  // header file. In case "1." this will be a NOP.
-  int entry_index = GetEntryIndexWithPageID(
-      web_contents_->GetSiteInstance(),
-      params.page_id);
-  if (entry_index < 0 ||
-      entry_index >= static_cast<int>(entries_.size())) {
-    NOTREACHED();
-    return false;
-  }
-
-  // Update the current navigation entry in case we're going back/forward.
-  if (entry_index != last_committed_entry_index_) {
-    last_committed_entry_index_ = entry_index;
-    DiscardNonCommittedEntriesInternal();
-    return true;
-  }
-
-  // We do not need to discard the pending entry in this case, since we will
-  // not generate commit notifications for this auto-subframe navigation.
-  return false;
-}
-
-int NavigationControllerImpl::GetIndexOfEntry(
-    const NavigationEntryImpl* entry) const {
-  const NavigationEntries::const_iterator i(std::find(
-      entries_.begin(),
-      entries_.end(),
-      entry));
-  return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin());
-}
-
-bool NavigationControllerImpl::IsURLInPageNavigation(
-    const GURL& url,
-    bool renderer_says_in_page,
-    NavigationType navigation_type) const {
-  NavigationEntry* last_committed = GetLastCommittedEntry();
-  return last_committed && AreURLsInPageNavigation(
-      last_committed->GetURL(), url, renderer_says_in_page, navigation_type);
-}
-
-void NavigationControllerImpl::CopyStateFrom(
-    const NavigationController& temp) {
-  const NavigationControllerImpl& source =
-      static_cast<const NavigationControllerImpl&>(temp);
-  // Verify that we look new.
-  DCHECK(GetEntryCount() == 0 && !GetPendingEntry());
-
-  if (source.GetEntryCount() == 0)
-    return;  // Nothing new to do.
-
-  needs_reload_ = true;
-  InsertEntriesFrom(source, source.GetEntryCount());
-
-  for (SessionStorageNamespaceMap::const_iterator it =
-           source.session_storage_namespace_map_.begin();
-       it != source.session_storage_namespace_map_.end();
-       ++it) {
-    SessionStorageNamespaceImpl* source_namespace =
-        static_cast<SessionStorageNamespaceImpl*>(it->second.get());
-    session_storage_namespace_map_[it->first] = source_namespace->Clone();
-  }
-
-  FinishRestore(source.last_committed_entry_index_, RESTORE_CURRENT_SESSION);
-
-  // Copy the max page id map from the old tab to the new tab.  This ensures
-  // that new and existing navigations in the tab's current SiteInstances
-  // are identified properly.
-  web_contents_->CopyMaxPageIDsFrom(source.web_contents());
-}
-
-void NavigationControllerImpl::CopyStateFromAndPrune(
-    NavigationController* temp) {
-  // It is up to callers to check the invariants before calling this.
-  CHECK(CanPruneAllButVisible());
-
-  NavigationControllerImpl* source =
-      static_cast<NavigationControllerImpl*>(temp);
-  // The SiteInstance and page_id of the last committed entry needs to be
-  // remembered at this point, in case there is only one committed entry
-  // and it is pruned.  We use a scoped_refptr to ensure the SiteInstance
-  // can't be freed during this time period.
-  NavigationEntryImpl* last_committed =
-      NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
-  scoped_refptr<SiteInstance> site_instance(
-      last_committed->site_instance());
-  int32 minimum_page_id = last_committed->GetPageID();
-  int32 max_page_id =
-      web_contents_->GetMaxPageIDForSiteInstance(site_instance.get());
-
-  // Remove all the entries leaving the active entry.
-  PruneAllButVisibleInternal();
-
-  // We now have one entry, possibly with a new pending entry.  Ensure that
-  // adding the entries from source won't put us over the limit.
-  DCHECK_EQ(1, GetEntryCount());
-  source->PruneOldestEntryIfFull();
-
-  // Insert the entries from source. Don't use source->GetCurrentEntryIndex as
-  // we don't want to copy over the transient entry.  Ignore any pending entry,
-  // since it has not committed in source.
-  int max_source_index = source->last_committed_entry_index_;
-  if (max_source_index == -1)
-    max_source_index = source->GetEntryCount();
-  else
-    max_source_index++;
-  InsertEntriesFrom(*source, max_source_index);
-
-  // Adjust indices such that the last entry and pending are at the end now.
-  last_committed_entry_index_ = GetEntryCount() - 1;
-
-  web_contents_->SetHistoryLengthAndPrune(site_instance.get(),
-                                          max_source_index,
-                                          minimum_page_id);
-
-  // Copy the max page id map from the old tab to the new tab.  This ensures
-  // that new and existing navigations in the tab's current SiteInstances
-  // are identified properly.
-  web_contents_->CopyMaxPageIDsFrom(source->web_contents());
-
-  // If there is a last committed entry, be sure to include it in the new
-  // max page ID map.
-  if (max_page_id > -1) {
-    web_contents_->UpdateMaxPageIDForSiteInstance(site_instance.get(),
-                                                  max_page_id);
-  }
-}
-
-bool NavigationControllerImpl::CanPruneAllButVisible() {
-  // If there is no last committed entry, we cannot prune.  Even if there is a
-  // pending entry, it may not commit, leaving this WebContents blank, despite
-  // possibly giving it new entries via CopyStateFromAndPrune.
-  if (last_committed_entry_index_ == -1)
-    return false;
-
-  // We cannot prune if there is a pending entry at an existing entry index.
-  // It may not commit, so we have to keep the last committed entry, and thus
-  // there is no sensible place to keep the pending entry.  It is ok to have
-  // a new pending entry, which can optionally commit as a new navigation.
-  if (pending_entry_index_ != -1)
-    return false;
-
-  // We should not prune if we are currently showing a transient entry.
-  if (transient_entry_index_ != -1)
-    return false;
-
-  return true;
-}
-
-void NavigationControllerImpl::PruneAllButVisible() {
-  PruneAllButVisibleInternal();
-
-  // We should still have a last committed entry.
-  DCHECK_NE(-1, last_committed_entry_index_);
-
-  // We pass 0 instead of GetEntryCount() for the history_length parameter of
-  // SetHistoryLengthAndPrune, because it will create history_length additional
-  // history entries.
-  // TODO(jochen): This API is confusing and we should clean it up.
-  // http://crbug.com/178491
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(GetVisibleEntry());
-  web_contents_->SetHistoryLengthAndPrune(
-      entry->site_instance(), 0, entry->GetPageID());
-}
-
-void NavigationControllerImpl::PruneAllButVisibleInternal() {
-  // It is up to callers to check the invariants before calling this.
-  CHECK(CanPruneAllButVisible());
-
-  // Erase all entries but the last committed entry.  There may still be a
-  // new pending entry after this.
-  entries_.erase(entries_.begin(),
-                 entries_.begin() + last_committed_entry_index_);
-  entries_.erase(entries_.begin() + 1, entries_.end());
-  last_committed_entry_index_ = 0;
-}
-
-void NavigationControllerImpl::ClearAllScreenshots() {
-  screenshot_manager_->ClearAllScreenshots();
-}
-
-void NavigationControllerImpl::SetSessionStorageNamespace(
-    const std::string& partition_id,
-    SessionStorageNamespace* session_storage_namespace) {
-  if (!session_storage_namespace)
-    return;
-
-  // We can't overwrite an existing SessionStorage without violating spec.
-  // Attempts to do so may give a tab access to another tab's session storage
-  // so die hard on an error.
-  bool successful_insert = session_storage_namespace_map_.insert(
-      make_pair(partition_id,
-                static_cast<SessionStorageNamespaceImpl*>(
-                    session_storage_namespace)))
-          .second;
-  CHECK(successful_insert) << "Cannot replace existing SessionStorageNamespace";
-}
-
-void NavigationControllerImpl::SetMaxRestoredPageID(int32 max_id) {
-  max_restored_page_id_ = max_id;
-}
-
-int32 NavigationControllerImpl::GetMaxRestoredPageID() const {
-  return max_restored_page_id_;
-}
-
-SessionStorageNamespace*
-NavigationControllerImpl::GetSessionStorageNamespace(SiteInstance* instance) {
-  std::string partition_id;
-  if (instance) {
-    // TODO(ajwong): When GetDefaultSessionStorageNamespace() goes away, remove
-    // this if statement so |instance| must not be NULL.
-    partition_id =
-        GetContentClient()->browser()->GetStoragePartitionIdForSite(
-            browser_context_, instance->GetSiteURL());
-  }
-
-  SessionStorageNamespaceMap::const_iterator it =
-      session_storage_namespace_map_.find(partition_id);
-  if (it != session_storage_namespace_map_.end())
-    return it->second.get();
-
-  // Create one if no one has accessed session storage for this partition yet.
-  //
-  // TODO(ajwong): Should this use the |partition_id| directly rather than
-  // re-lookup via |instance|?  http://crbug.com/142685
-  StoragePartition* partition =
-              BrowserContext::GetStoragePartition(browser_context_, instance);
-  SessionStorageNamespaceImpl* session_storage_namespace =
-      new SessionStorageNamespaceImpl(
-          static_cast<DOMStorageContextWrapper*>(
-              partition->GetDOMStorageContext()));
-  session_storage_namespace_map_[partition_id] = session_storage_namespace;
-
-  return session_storage_namespace;
-}
-
-SessionStorageNamespace*
-NavigationControllerImpl::GetDefaultSessionStorageNamespace() {
-  // TODO(ajwong): Remove if statement in GetSessionStorageNamespace().
-  return GetSessionStorageNamespace(NULL);
-}
-
-const SessionStorageNamespaceMap&
-NavigationControllerImpl::GetSessionStorageNamespaceMap() const {
-  return session_storage_namespace_map_;
-}
-
-bool NavigationControllerImpl::NeedsReload() const {
-  return needs_reload_;
-}
-
-void NavigationControllerImpl::SetNeedsReload() {
-  needs_reload_ = true;
-}
-
-void NavigationControllerImpl::RemoveEntryAtIndexInternal(int index) {
-  DCHECK(index < GetEntryCount());
-  DCHECK(index != last_committed_entry_index_);
-
-  DiscardNonCommittedEntries();
-
-  entries_.erase(entries_.begin() + index);
-  if (last_committed_entry_index_ > index)
-    last_committed_entry_index_--;
-}
-
-void NavigationControllerImpl::DiscardNonCommittedEntries() {
-  bool transient = transient_entry_index_ != -1;
-  DiscardNonCommittedEntriesInternal();
-
-  // If there was a transient entry, invalidate everything so the new active
-  // entry state is shown.
-  if (transient) {
-    web_contents_->NotifyNavigationStateChanged(kInvalidateAll);
-  }
-}
-
-NavigationEntry* NavigationControllerImpl::GetPendingEntry() const {
-  return pending_entry_;
-}
-
-int NavigationControllerImpl::GetPendingEntryIndex() const {
-  return pending_entry_index_;
-}
-
-void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry,
-                                                    bool replace) {
-  DCHECK(entry->GetTransitionType() != PAGE_TRANSITION_AUTO_SUBFRAME);
-
-  // Copy the pending entry's unique ID to the committed entry.
-  // I don't know if pending_entry_index_ can be other than -1 here.
-  const NavigationEntryImpl* const pending_entry =
-      (pending_entry_index_ == -1) ?
-          pending_entry_ : entries_[pending_entry_index_].get();
-  if (pending_entry)
-    entry->set_unique_id(pending_entry->GetUniqueID());
-
-  DiscardNonCommittedEntriesInternal();
-
-  int current_size = static_cast<int>(entries_.size());
-
-  if (current_size > 0) {
-    // Prune any entries which are in front of the current entry.
-    // Also prune the current entry if we are to replace the current entry.
-    // last_committed_entry_index_ must be updated here since calls to
-    // NotifyPrunedEntries() below may re-enter and we must make sure
-    // last_committed_entry_index_ is not left in an invalid state.
-    if (replace)
-      --last_committed_entry_index_;
-
-    int num_pruned = 0;
-    while (last_committed_entry_index_ < (current_size - 1)) {
-      num_pruned++;
-      entries_.pop_back();
-      current_size--;
-    }
-    if (num_pruned > 0)  // Only notify if we did prune something.
-      NotifyPrunedEntries(this, false, num_pruned);
-  }
-
-  PruneOldestEntryIfFull();
-
-  entries_.push_back(linked_ptr<NavigationEntryImpl>(entry));
-  last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1;
-
-  // This is a new page ID, so we need everybody to know about it.
-  web_contents_->UpdateMaxPageID(entry->GetPageID());
-}
-
-void NavigationControllerImpl::PruneOldestEntryIfFull() {
-  if (entries_.size() >= max_entry_count()) {
-    DCHECK_EQ(max_entry_count(), entries_.size());
-    DCHECK_GT(last_committed_entry_index_, 0);
-    RemoveEntryAtIndex(0);
-    NotifyPrunedEntries(this, true, 1);
-  }
-}
-
-void NavigationControllerImpl::NavigateToPendingEntry(ReloadType reload_type) {
-  needs_reload_ = false;
-
-  // If we were navigating to a slow-to-commit page, and the user performs
-  // a session history navigation to the last committed page, RenderViewHost
-  // will force the throbber to start, but WebKit will essentially ignore the
-  // navigation, and won't send a message to stop the throbber. To prevent this
-  // from happening, we drop the navigation here and stop the slow-to-commit
-  // page from loading (which would normally happen during the navigation).
-  if (pending_entry_index_ != -1 &&
-      pending_entry_index_ == last_committed_entry_index_ &&
-      (entries_[pending_entry_index_]->restore_type() ==
-          NavigationEntryImpl::RESTORE_NONE) &&
-      (entries_[pending_entry_index_]->GetTransitionType() &
-          PAGE_TRANSITION_FORWARD_BACK)) {
-    web_contents_->Stop();
-
-    // If an interstitial page is showing, we want to close it to get back
-    // to what was showing before.
-    if (web_contents_->GetInterstitialPage())
-      web_contents_->GetInterstitialPage()->DontProceed();
-
-    DiscardNonCommittedEntries();
-    return;
-  }
-
-  // If an interstitial page is showing, the previous renderer is blocked and
-  // cannot make new requests.  Unblock (and disable) it to allow this
-  // navigation to succeed.  The interstitial will stay visible until the
-  // resulting DidNavigate.
-  if (web_contents_->GetInterstitialPage()) {
-    static_cast<InterstitialPageImpl*>(web_contents_->GetInterstitialPage())->
-        CancelForNavigation();
-  }
-
-  // For session history navigations only the pending_entry_index_ is set.
-  if (!pending_entry_) {
-    DCHECK_NE(pending_entry_index_, -1);
-    pending_entry_ = entries_[pending_entry_index_].get();
-  }
-
-  if (!web_contents_->NavigateToPendingEntry(reload_type))
-    DiscardNonCommittedEntries();
-
-  // If the entry is being restored and doesn't have a SiteInstance yet, fill
-  // it in now that we know. This allows us to find the entry when it commits.
-  // This works for browser-initiated navigations. We handle renderer-initiated
-  // navigations to restored entries in WebContentsImpl::OnGoToEntryAtOffset.
-  if (pending_entry_ && !pending_entry_->site_instance() &&
-      pending_entry_->restore_type() != NavigationEntryImpl::RESTORE_NONE) {
-    pending_entry_->set_site_instance(static_cast<SiteInstanceImpl*>(
-        web_contents_->GetPendingSiteInstance()));
-    pending_entry_->set_restore_type(NavigationEntryImpl::RESTORE_NONE);
-  }
-}
-
-void NavigationControllerImpl::NotifyNavigationEntryCommitted(
-    LoadCommittedDetails* details) {
-  details->entry = GetLastCommittedEntry();
-
-  // We need to notify the ssl_manager_ before the web_contents_ so the
-  // location bar will have up-to-date information about the security style
-  // when it wants to draw.  See http://crbug.com/11157
-  ssl_manager_.DidCommitProvisionalLoad(*details);
-
-  web_contents_->NotifyNavigationStateChanged(kInvalidateAll);
-  web_contents_->NotifyNavigationEntryCommitted(*details);
-
-  // TODO(avi): Remove. http://crbug.com/170921
-  NotificationDetails notification_details =
-      Details<LoadCommittedDetails>(details);
-  NotificationService::current()->Notify(
-      NOTIFICATION_NAV_ENTRY_COMMITTED,
-      Source<NavigationController>(this),
-      notification_details);
-}
-
-// static
-size_t NavigationControllerImpl::max_entry_count() {
-  if (max_entry_count_for_testing_ != kMaxEntryCountForTestingNotSet)
-     return max_entry_count_for_testing_;
-  return kMaxSessionHistoryEntries;
-}
-
-void NavigationControllerImpl::SetActive(bool is_active) {
-  if (is_active && needs_reload_)
-    LoadIfNecessary();
-}
-
-void NavigationControllerImpl::LoadIfNecessary() {
-  if (!needs_reload_)
-    return;
-
-  // Calling Reload() results in ignoring state, and not loading.
-  // Explicitly use NavigateToPendingEntry so that the renderer uses the
-  // cached state.
-  pending_entry_index_ = last_committed_entry_index_;
-  NavigateToPendingEntry(NO_RELOAD);
-}
-
-void NavigationControllerImpl::NotifyEntryChanged(const NavigationEntry* entry,
-                                                  int index) {
-  EntryChangedDetails det;
-  det.changed_entry = entry;
-  det.index = index;
-  NotificationService::current()->Notify(
-      NOTIFICATION_NAV_ENTRY_CHANGED,
-      Source<NavigationController>(this),
-      Details<EntryChangedDetails>(&det));
-}
-
-void NavigationControllerImpl::FinishRestore(int selected_index,
-                                             RestoreType type) {
-  DCHECK(selected_index >= 0 && selected_index < GetEntryCount());
-  ConfigureEntriesForRestore(&entries_, type);
-
-  SetMaxRestoredPageID(static_cast<int32>(GetEntryCount()));
-
-  last_committed_entry_index_ = selected_index;
-}
-
-void NavigationControllerImpl::DiscardNonCommittedEntriesInternal() {
-  DiscardPendingEntry();
-  DiscardTransientEntry();
-}
-
-void NavigationControllerImpl::DiscardPendingEntry() {
-  if (pending_entry_index_ == -1)
-    delete pending_entry_;
-  pending_entry_ = NULL;
-  pending_entry_index_ = -1;
-}
-
-void NavigationControllerImpl::DiscardTransientEntry() {
-  if (transient_entry_index_ == -1)
-    return;
-  entries_.erase(entries_.begin() + transient_entry_index_);
-  if (last_committed_entry_index_ > transient_entry_index_)
-    last_committed_entry_index_--;
-  transient_entry_index_ = -1;
-}
-
-int NavigationControllerImpl::GetEntryIndexWithPageID(
-    SiteInstance* instance, int32 page_id) const {
-  for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
-    if ((entries_[i]->site_instance() == instance) &&
-        (entries_[i]->GetPageID() == page_id))
-      return i;
-  }
-  return -1;
-}
-
-NavigationEntry* NavigationControllerImpl::GetTransientEntry() const {
-  if (transient_entry_index_ == -1)
-    return NULL;
-  return entries_[transient_entry_index_].get();
-}
-
-void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) {
-  // Discard any current transient entry, we can only have one at a time.
-  int index = 0;
-  if (last_committed_entry_index_ != -1)
-    index = last_committed_entry_index_ + 1;
-  DiscardTransientEntry();
-  entries_.insert(
-      entries_.begin() + index, linked_ptr<NavigationEntryImpl>(
-          NavigationEntryImpl::FromNavigationEntry(entry)));
-  transient_entry_index_ = index;
-  web_contents_->NotifyNavigationStateChanged(kInvalidateAll);
-}
-
-void NavigationControllerImpl::InsertEntriesFrom(
-    const NavigationControllerImpl& source,
-    int max_index) {
-  DCHECK_LE(max_index, source.GetEntryCount());
-  size_t insert_index = 0;
-  for (int i = 0; i < max_index; i++) {
-    // When cloning a tab, copy all entries except interstitial pages
-    if (source.entries_[i].get()->GetPageType() !=
-        PAGE_TYPE_INTERSTITIAL) {
-      entries_.insert(entries_.begin() + insert_index++,
-                      linked_ptr<NavigationEntryImpl>(
-                          new NavigationEntryImpl(*source.entries_[i])));
-    }
-  }
-}
-
-void NavigationControllerImpl::SetGetTimestampCallbackForTest(
-    const base::Callback<base::Time()>& get_timestamp_callback) {
-  get_timestamp_callback_ = get_timestamp_callback;
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/navigation_controller_impl.h b/content/browser/web_contents/navigation_controller_impl.h
deleted file mode 100644
index 6e6f333..0000000
--- a/content/browser/web_contents/navigation_controller_impl.h
+++ /dev/null
@@ -1,413 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_WEB_CONTENTS_NAVIGATION_CONTROLLER_IMPL_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_NAVIGATION_CONTROLLER_IMPL_H_
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/linked_ptr.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/browser/ssl/ssl_manager.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_type.h"
-
-struct ViewHostMsg_FrameNavigate_Params;
-
-namespace content {
-class NavigationEntryImpl;
-class RenderViewHost;
-class WebContentsImpl;
-class WebContentsScreenshotManager;
-class SiteInstance;
-struct LoadCommittedDetails;
-
-class CONTENT_EXPORT NavigationControllerImpl
-    : public NON_EXPORTED_BASE(NavigationController) {
- public:
-  NavigationControllerImpl(
-      WebContentsImpl* web_contents,
-      BrowserContext* browser_context);
-  virtual ~NavigationControllerImpl();
-
-  // NavigationController implementation:
-  virtual WebContents* GetWebContents() const OVERRIDE;
-  virtual BrowserContext* GetBrowserContext() const OVERRIDE;
-  virtual void SetBrowserContext(
-      BrowserContext* browser_context) OVERRIDE;
-  virtual void Restore(
-      int selected_navigation,
-      RestoreType type,
-      std::vector<NavigationEntry*>* entries) OVERRIDE;
-  virtual NavigationEntry* GetActiveEntry() const OVERRIDE;
-  virtual NavigationEntry* GetVisibleEntry() const OVERRIDE;
-  virtual int GetCurrentEntryIndex() const OVERRIDE;
-  virtual NavigationEntry* GetLastCommittedEntry() const OVERRIDE;
-  virtual int GetLastCommittedEntryIndex() const OVERRIDE;
-  virtual bool CanViewSource() const OVERRIDE;
-  virtual int GetEntryCount() const OVERRIDE;
-  virtual NavigationEntry* GetEntryAtIndex(int index) const OVERRIDE;
-  virtual NavigationEntry* GetEntryAtOffset(int offset) const OVERRIDE;
-  virtual void DiscardNonCommittedEntries() OVERRIDE;
-  virtual NavigationEntry* GetPendingEntry() const OVERRIDE;
-  virtual int GetPendingEntryIndex() const OVERRIDE;
-  virtual NavigationEntry* GetTransientEntry() const OVERRIDE;
-  virtual void SetTransientEntry(NavigationEntry* entry) OVERRIDE;
-  virtual void LoadURL(const GURL& url,
-                       const Referrer& referrer,
-                       PageTransition type,
-                       const std::string& extra_headers) OVERRIDE;
-  virtual void LoadURLWithParams(const LoadURLParams& params) OVERRIDE;
-  virtual void LoadIfNecessary() OVERRIDE;
-  virtual bool CanGoBack() const OVERRIDE;
-  virtual bool CanGoForward() const OVERRIDE;
-  virtual bool CanGoToOffset(int offset) const OVERRIDE;
-  virtual void GoBack() OVERRIDE;
-  virtual void GoForward() OVERRIDE;
-  virtual void GoToIndex(int index) OVERRIDE;
-  virtual void GoToOffset(int offset) OVERRIDE;
-  virtual bool RemoveEntryAtIndex(int index) OVERRIDE;
-  virtual const SessionStorageNamespaceMap&
-      GetSessionStorageNamespaceMap() const OVERRIDE;
-  virtual SessionStorageNamespace*
-      GetDefaultSessionStorageNamespace() OVERRIDE;
-  virtual void SetMaxRestoredPageID(int32 max_id) OVERRIDE;
-  virtual int32 GetMaxRestoredPageID() const OVERRIDE;
-  virtual bool NeedsReload() const OVERRIDE;
-  virtual void SetNeedsReload() OVERRIDE;
-  virtual void CancelPendingReload() OVERRIDE;
-  virtual void ContinuePendingReload() OVERRIDE;
-  virtual bool IsInitialNavigation() const OVERRIDE;
-  virtual void Reload(bool check_for_repost) OVERRIDE;
-  virtual void ReloadIgnoringCache(bool check_for_repost) OVERRIDE;
-  virtual void ReloadOriginalRequestURL(bool check_for_repost) OVERRIDE;
-  virtual void NotifyEntryChanged(const NavigationEntry* entry,
-                                 int index) OVERRIDE;
-  virtual void CopyStateFrom(
-      const NavigationController& source) OVERRIDE;
-  virtual void CopyStateFromAndPrune(
-      NavigationController* source) OVERRIDE;
-  virtual bool CanPruneAllButVisible() OVERRIDE;
-  virtual void PruneAllButVisible() OVERRIDE;
-  virtual void ClearAllScreenshots() OVERRIDE;
-
-  // The session storage namespace that all child RenderViews belonging to
-  // |instance| should use.
-  SessionStorageNamespace* GetSessionStorageNamespace(
-      SiteInstance* instance);
-
-  // Returns the index of the specified entry, or -1 if entry is not contained
-  // in this NavigationController.
-  int GetIndexOfEntry(const NavigationEntryImpl* entry) const;
-
-  // Return the index of the entry with the corresponding instance and page_id,
-  // or -1 if not found.
-  int GetEntryIndexWithPageID(SiteInstance* instance,
-                              int32 page_id) const;
-
-  // Return the entry with the corresponding instance and page_id, or NULL if
-  // not found.
-  NavigationEntryImpl* GetEntryWithPageID(
-      SiteInstance* instance,
-      int32 page_id) const;
-
-  // WebContentsImpl -----------------------------------------------------------
-
-  WebContentsImpl* web_contents() const {
-    return web_contents_;
-  }
-
-  // For use by WebContentsImpl ------------------------------------------------
-
-  // Allow renderer-initiated navigations to create a pending entry when the
-  // provisional load starts.
-  void SetPendingEntry(content::NavigationEntryImpl* entry);
-
-  // Handles updating the navigation state after the renderer has navigated.
-  // This is used by the WebContentsImpl.
-  //
-  // If a new entry is created, it will return true and will have filled the
-  // given details structure and broadcast the NOTIFY_NAV_ENTRY_COMMITTED
-  // notification. The caller can then use the details without worrying about
-  // listening for the notification.
-  //
-  // In the case that nothing has changed, the details structure is undefined
-  // and it will return false.
-  bool RendererDidNavigate(const ViewHostMsg_FrameNavigate_Params& params,
-                           LoadCommittedDetails* details);
-
-  // Notifies us that we just became active. This is used by the WebContentsImpl
-  // so that we know to load URLs that were pending as "lazy" loads.
-  void SetActive(bool is_active);
-
-  // Returns true if the given URL would be an in-page navigation (i.e. only
-  // the reference fragment is different) from the "last committed entry". We do
-  // not compare it against the "active entry" since the active entry can be
-  // pending and in page navigations only happen on committed pages. If there
-  // is no last committed entry, then nothing will be in-page.
-  //
-  // Special note: if the URLs are the same, it does NOT automatically count as
-  // an in-page navigation. Neither does an input URL that has no ref, even if
-  // the rest is the same. This may seem weird, but when we're considering
-  // whether a navigation happened without loading anything, the same URL could
-  // be a reload, while only a different ref would be in-page (pages can't clear
-  // refs without reload, only change to "#" which we don't count as empty).
-  bool IsURLInPageNavigation(const GURL& url) const {
-    return IsURLInPageNavigation(url, false, NAVIGATION_TYPE_UNKNOWN);
-  }
-
-  // The situation is made murkier by history.replaceState(), which could
-  // provide the same URL as part of an in-page navigation, not a reload. So
-  // we need this form which lets the (untrustworthy) renderer resolve the
-  // ambiguity, but only when the URLs are equal. This should be safe since the
-  // origin isn't changing.
-  bool IsURLInPageNavigation(
-      const GURL& url,
-      bool renderer_says_in_page,
-      NavigationType navigation_type) const;
-
-  // Sets the SessionStorageNamespace for the given |partition_id|. This is
-  // used during initialization of a new NavigationController to allow
-  // pre-population of the SessionStorageNamespace objects. Session restore,
-  // prerendering, and the implementaion of window.open() are the primary users
-  // of this API.
-  //
-  // Calling this function when a SessionStorageNamespace has already been
-  // associated with a |partition_id| will CHECK() fail.
-  void SetSessionStorageNamespace(
-      const std::string& partition_id,
-      SessionStorageNamespace* session_storage_namespace);
-
-  // Random data ---------------------------------------------------------------
-
-  SSLManager* ssl_manager() { return &ssl_manager_; }
-
-  // Maximum number of entries before we start removing entries from the front.
-  static void set_max_entry_count_for_testing(size_t max_entry_count) {
-    max_entry_count_for_testing_ = max_entry_count;
-  }
-  static size_t max_entry_count();
-
-  void SetGetTimestampCallbackForTest(
-      const base::Callback<base::Time()>& get_timestamp_callback);
-
-  // Takes a screenshot of the page at the current state.
-  void TakeScreenshot();
-
-  // Sets the screenshot manager for this NavigationControllerImpl. The
-  // controller takes ownership of the screenshot manager and destroys it when
-  // a new screenshot-manager is set, or when the controller is destroyed.
-  // Setting a NULL manager recreates the default screenshot manager and uses
-  // that.
-  void SetScreenshotManager(WebContentsScreenshotManager* manager);
-
- private:
-  friend class RestoreHelper;
-  friend class WebContentsImpl;  // For invoking OnReservedPageIDRange.
-
-  FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest,
-                           PurgeScreenshot);
-  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, Basic);
-  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, SingleDuplicate);
-  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ManyDuplicates);
-  FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ClockBackwardsJump);
-
-  // Helper class to smooth out runs of duplicate timestamps while still
-  // allowing time to jump backwards.
-  class CONTENT_EXPORT TimeSmoother {
-   public:
-    // Returns |t| with possibly some time added on.
-    base::Time GetSmoothedTime(base::Time t);
-
-   private:
-    // |low_water_mark_| is the first time in a sequence of adjusted
-    // times and |high_water_mark_| is the last.
-    base::Time low_water_mark_;
-    base::Time high_water_mark_;
-  };
-
-  // Classifies the given renderer navigation (see the NavigationType enum).
-  NavigationType ClassifyNavigation(
-      const ViewHostMsg_FrameNavigate_Params& params) const;
-
-  // Causes the controller to load the specified entry. The function assumes
-  // ownership of the pointer since it is put in the navigation list.
-  // NOTE: Do not pass an entry that the controller already owns!
-  void LoadEntry(NavigationEntryImpl* entry);
-
-  // Handlers for the different types of navigation types. They will actually
-  // handle the navigations corresponding to the different NavClasses above.
-  // They will NOT broadcast the commit notification, that should be handled by
-  // the caller.
-  //
-  // RendererDidNavigateAutoSubframe is special, it may not actually change
-  // anything if some random subframe is loaded. It will return true if anything
-  // changed, or false if not.
-  //
-  // The functions taking |did_replace_entry| will fill into the given variable
-  // whether the last entry has been replaced or not.
-  // See LoadCommittedDetails.did_replace_entry.
-  void RendererDidNavigateToNewPage(
-      const ViewHostMsg_FrameNavigate_Params& params, bool replace_entry);
-  void RendererDidNavigateToExistingPage(
-      const ViewHostMsg_FrameNavigate_Params& params);
-  void RendererDidNavigateToSamePage(
-      const ViewHostMsg_FrameNavigate_Params& params);
-  void RendererDidNavigateInPage(
-      const ViewHostMsg_FrameNavigate_Params& params, bool* did_replace_entry);
-  void RendererDidNavigateNewSubframe(
-      const ViewHostMsg_FrameNavigate_Params& params);
-  bool RendererDidNavigateAutoSubframe(
-      const ViewHostMsg_FrameNavigate_Params& params);
-
-  // Helper function for code shared between Reload() and ReloadIgnoringCache().
-  void ReloadInternal(bool check_for_repost, ReloadType reload_type);
-
-  // Actually issues the navigation held in pending_entry.
-  void NavigateToPendingEntry(ReloadType reload_type);
-
-  // Allows the derived class to issue notifications that a load has been
-  // committed. This will fill in the active entry to the details structure.
-  void NotifyNavigationEntryCommitted(LoadCommittedDetails* details);
-
-  // Updates the virtual URL of an entry to match a new URL, for cases where
-  // the real renderer URL is derived from the virtual URL, like view-source:
-  void UpdateVirtualURLToURL(NavigationEntryImpl* entry,
-                             const GURL& new_url);
-
-  // Invoked after session/tab restore or cloning a tab. Resets the transition
-  // type of the entries, updates the max page id and creates the active
-  // contents.
-  void FinishRestore(int selected_index, RestoreType type);
-
-  // Inserts a new entry or replaces the current entry with a new one, removing
-  // all entries after it. The new entry will become the active one.
-  void InsertOrReplaceEntry(NavigationEntryImpl* entry, bool replace);
-
-  // Removes the entry at |index|, as long as it is not the current entry.
-  void RemoveEntryAtIndexInternal(int index);
-
-  // Discards both the pending and transient entries.
-  void DiscardNonCommittedEntriesInternal();
-
-  // Discards only the pending entry.
-  void DiscardPendingEntry();
-
-  // Discards only the transient entry.
-  void DiscardTransientEntry();
-
-  // If we have the maximum number of entries, remove the oldest one in
-  // preparation to add another.
-  void PruneOldestEntryIfFull();
-
-  // Removes all entries except the last committed entry.  If there is a new
-  // pending navigation it is preserved. In contrast to PruneAllButVisible()
-  // this does not update the session history of the RenderView.  Callers
-  // must ensure that |CanPruneAllButVisible| returns true before calling this.
-  void PruneAllButVisibleInternal();
-
-  // Returns true if the navigation is redirect.
-  bool IsRedirect(const ViewHostMsg_FrameNavigate_Params& params);
-
-  // Returns true if the navigation is likley to be automatic rather than
-  // user-initiated.
-  bool IsLikelyAutoNavigation(base::TimeTicks now);
-
-  // Inserts up to |max_index| entries from |source| into this. This does NOT
-  // adjust any of the members that reference entries_
-  // (last_committed_entry_index_, pending_entry_index_ or
-  // transient_entry_index_).
-  void InsertEntriesFrom(const NavigationControllerImpl& source, int max_index);
-
-  // Returns the navigation index that differs from the current entry by the
-  // specified |offset|.  The index returned is not guaranteed to be valid.
-  int GetIndexForOffset(int offset) const;
-
-  // ---------------------------------------------------------------------------
-
-  // The user browser context associated with this controller.
-  BrowserContext* browser_context_;
-
-  // List of NavigationEntry for this tab
-  typedef std::vector<linked_ptr<NavigationEntryImpl> > NavigationEntries;
-  NavigationEntries entries_;
-
-  // An entry we haven't gotten a response for yet.  This will be discarded
-  // when we navigate again.  It's used only so we know what the currently
-  // displayed tab is.
-  //
-  // This may refer to an item in the entries_ list if the pending_entry_index_
-  // == -1, or it may be its own entry that should be deleted. Be careful with
-  // the memory management.
-  NavigationEntryImpl* pending_entry_;
-
-  // currently visible entry
-  int last_committed_entry_index_;
-
-  // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
-  // new entry (created by LoadURL).
-  int pending_entry_index_;
-
-  // The index for the entry that is shown until a navigation occurs.  This is
-  // used for interstitial pages. -1 if there are no such entry.
-  // Note that this entry really appears in the list of entries, but only
-  // temporarily (until the next navigation).  Any index pointing to an entry
-  // after the transient entry will become invalid if you navigate forward.
-  int transient_entry_index_;
-
-  // The WebContents associated with the controller. Possibly NULL during
-  // setup.
-  WebContentsImpl* web_contents_;
-
-  // The max restored page ID in this controller, if it was restored.  We must
-  // store this so that WebContentsImpl can tell any renderer in charge of one
-  // of the restored entries to update its max page ID.
-  int32 max_restored_page_id_;
-
-  // Manages the SSL security UI.
-  SSLManager ssl_manager_;
-
-  // Whether we need to be reloaded when made active.
-  bool needs_reload_;
-
-  // Whether this is the initial navigation.
-  // Becomes false when initial navigation commits.
-  bool is_initial_navigation_;
-
-  // Used to find the appropriate SessionStorageNamespace for the storage
-  // partition of a NavigationEntry.
-  //
-  // A NavigationController may contain NavigationEntries that correspond to
-  // different StoragePartitions. Even though they are part of the same
-  // NavigationController, only entries in the same StoragePartition may
-  // share session storage state with one another.
-  SessionStorageNamespaceMap session_storage_namespace_map_;
-
-  // The maximum number of entries that a navigation controller can store.
-  static size_t max_entry_count_for_testing_;
-
-  // If a repost is pending, its type (RELOAD or RELOAD_IGNORING_CACHE),
-  // NO_RELOAD otherwise.
-  ReloadType pending_reload_;
-
-  // Used to get timestamps for newly-created navigation entries.
-  base::Callback<base::Time()> get_timestamp_callback_;
-
-  // Used to smooth out timestamps from |get_timestamp_callback_|.
-  // Without this, whenever there is a run of redirects or
-  // code-generated navigations, those navigations may occur within
-  // the timer resolution, leading to things sometimes showing up in
-  // the wrong order in the history view.
-  TimeSmoother time_smoother_;
-
-  scoped_ptr<WebContentsScreenshotManager> screenshot_manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_NAVIGATION_CONTROLLER_IMPL_H_
diff --git a/content/browser/web_contents/navigation_controller_impl_unittest.cc b/content/browser/web_contents/navigation_controller_impl_unittest.cc
deleted file mode 100644
index 2d8758b..0000000
--- a/content/browser/web_contents/navigation_controller_impl_unittest.cc
+++ /dev/null
@@ -1,3794 +0,0 @@
-// Copyright (c) 2012 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/basictypes.h"
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "content/browser/renderer_host/test_render_view_host.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/browser/web_contents/web_contents_screenshot_manager.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/page_state.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_notification_tracker.h"
-#include "content/public/test/test_utils.h"
-#include "content/test/test_web_contents.h"
-#include "net/base/net_util.h"
-#include "skia/ext/platform_canvas.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::Time;
-
-namespace {
-
-// Creates an image with a 1x1 SkBitmap of the specified |color|.
-gfx::Image CreateImage(SkColor color) {
-  SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
-  bitmap.allocPixels();
-  bitmap.eraseColor(color);
-  return gfx::Image::CreateFrom1xBitmap(bitmap);
-}
-
-// Returns true if images |a| and |b| have the same pixel data.
-bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
-  // Assume that if the 1x bitmaps match, the images match.
-  SkBitmap a_bitmap = a.AsBitmap();
-  SkBitmap b_bitmap = b.AsBitmap();
-
-  if (a_bitmap.width() != b_bitmap.width() ||
-      a_bitmap.height() != b_bitmap.height()) {
-    return false;
-  }
-  SkAutoLockPixels a_bitmap_lock(a_bitmap);
-  SkAutoLockPixels b_bitmap_lock(b_bitmap);
-  return memcmp(a_bitmap.getPixels(),
-                b_bitmap.getPixels(),
-                a_bitmap.getSize()) == 0;
-}
-
-class MockScreenshotManager : public content::WebContentsScreenshotManager {
- public:
-  explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
-      : content::WebContentsScreenshotManager(owner),
-        encoding_screenshot_in_progress_(false) {
-  }
-
-  virtual ~MockScreenshotManager() {
-  }
-
-  void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
-    SkBitmap bitmap;
-    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
-    bitmap.allocPixels();
-    bitmap.eraseRGB(0, 0, 0);
-    encoding_screenshot_in_progress_ = true;
-    OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
-    WaitUntilScreenshotIsReady();
-  }
-
-  int GetScreenshotCount() {
-    return content::WebContentsScreenshotManager::GetScreenshotCount();
-  }
-
-  void WaitUntilScreenshotIsReady() {
-    if (!encoding_screenshot_in_progress_)
-      return;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-  }
-
- private:
-  // Overridden from content::WebContentsScreenshotManager:
-  virtual void TakeScreenshotImpl(
-      content::RenderViewHost* host,
-      content::NavigationEntryImpl* entry) OVERRIDE {
-  }
-
-  virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
-    encoding_screenshot_in_progress_ = false;
-    WebContentsScreenshotManager::OnScreenshotSet(entry);
-    if (message_loop_runner_.get())
-      message_loop_runner_->Quit();
-  }
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  bool encoding_screenshot_in_progress_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
-};
-
-}  // namespace
-
-namespace content {
-
-// TimeSmoother tests ----------------------------------------------------------
-
-// With no duplicates, GetSmoothedTime should be the identity
-// function.
-TEST(TimeSmoother, Basic) {
-  NavigationControllerImpl::TimeSmoother smoother;
-  for (int64 i = 1; i < 1000; ++i) {
-    base::Time t = base::Time::FromInternalValue(i);
-    EXPECT_EQ(t, smoother.GetSmoothedTime(t));
-  }
-}
-
-// With a single duplicate and timestamps thereafter increasing by one
-// microsecond, the smoothed time should always be one behind.
-TEST(TimeSmoother, SingleDuplicate) {
-  NavigationControllerImpl::TimeSmoother smoother;
-  base::Time t = base::Time::FromInternalValue(1);
-  EXPECT_EQ(t, smoother.GetSmoothedTime(t));
-  for (int64 i = 1; i < 1000; ++i) {
-    base::Time expected_t = base::Time::FromInternalValue(i + 1);
-    t = base::Time::FromInternalValue(i);
-    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
-  }
-}
-
-// With k duplicates and timestamps thereafter increasing by one
-// microsecond, the smoothed time should always be k behind.
-TEST(TimeSmoother, ManyDuplicates) {
-  const int64 kNumDuplicates = 100;
-  NavigationControllerImpl::TimeSmoother smoother;
-  base::Time t = base::Time::FromInternalValue(1);
-  for (int64 i = 0; i < kNumDuplicates; ++i) {
-    base::Time expected_t = base::Time::FromInternalValue(i + 1);
-    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
-  }
-  for (int64 i = 1; i < 1000; ++i) {
-    base::Time expected_t =
-        base::Time::FromInternalValue(i + kNumDuplicates);
-    t = base::Time::FromInternalValue(i);
-    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
-  }
-}
-
-// If the clock jumps far back enough after a run of duplicates, it
-// should immediately jump to that value.
-TEST(TimeSmoother, ClockBackwardsJump) {
-  const int64 kNumDuplicates = 100;
-  NavigationControllerImpl::TimeSmoother smoother;
-  base::Time t = base::Time::FromInternalValue(1000);
-  for (int64 i = 0; i < kNumDuplicates; ++i) {
-    base::Time expected_t = base::Time::FromInternalValue(i + 1000);
-    EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
-  }
-  t = base::Time::FromInternalValue(500);
-  EXPECT_EQ(t, smoother.GetSmoothedTime(t));
-}
-
-// NavigationControllerTest ----------------------------------------------------
-
-class NavigationControllerTest
-    : public RenderViewHostImplTestHarness,
-      public WebContentsObserver {
- public:
-  NavigationControllerTest() : navigation_entry_committed_counter_(0) {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    RenderViewHostImplTestHarness::SetUp();
-    WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
-    ASSERT_TRUE(web_contents);  // The WebContents should be created by now.
-    WebContentsObserver::Observe(web_contents);
-  }
-
-  // WebContentsObserver:
-  virtual void NavigateToPendingEntry(
-      const GURL& url,
-      NavigationController::ReloadType reload_type) OVERRIDE {
-    navigated_url_ = url;
-  }
-
-  virtual void NavigationEntryCommitted(
-      const LoadCommittedDetails& load_details) OVERRIDE {
-    navigation_entry_committed_counter_++;
-  }
-
-  const GURL& navigated_url() const {
-    return navigated_url_;
-  }
-
-  NavigationControllerImpl& controller_impl() {
-    return static_cast<NavigationControllerImpl&>(controller());
-  }
-
- protected:
-  GURL navigated_url_;
-  size_t navigation_entry_committed_counter_;
-};
-
-void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
-                                    NavigationController* controller) {
-  tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED,
-                     Source<NavigationController>(controller));
-  tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED,
-                     Source<NavigationController>(controller));
-}
-
-SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
-  return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
-}
-
-class TestWebContentsDelegate : public WebContentsDelegate {
- public:
-  explicit TestWebContentsDelegate() :
-      navigation_state_change_count_(0) {}
-
-  int navigation_state_change_count() {
-    return navigation_state_change_count_;
-  }
-
-  // Keep track of whether the tab has notified us of a navigation state change.
-  virtual void NavigationStateChanged(const WebContents* source,
-                                      unsigned changed_flags) OVERRIDE {
-    navigation_state_change_count_++;
-  }
-
- private:
-  // The number of times NavigationStateChanged has been called.
-  int navigation_state_change_count_;
-};
-
-// -----------------------------------------------------------------------------
-
-TEST_F(NavigationControllerTest, Defaults) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
-  EXPECT_EQ(controller.GetEntryCount(), 0);
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-TEST_F(NavigationControllerTest, GoToOffset) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const int kNumUrls = 5;
-  std::vector<GURL> urls(kNumUrls);
-  for (int i = 0; i < kNumUrls; ++i) {
-    urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
-  }
-
-  test_rvh()->SendNavigate(0, urls[0]);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_FALSE(controller.CanGoToOffset(1));
-
-  for (int i = 1; i <= 4; ++i) {
-    test_rvh()->SendNavigate(i, urls[i]);
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-    EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL());
-    EXPECT_TRUE(controller.CanGoToOffset(-i));
-    EXPECT_FALSE(controller.CanGoToOffset(-(i + 1)));
-    EXPECT_FALSE(controller.CanGoToOffset(1));
-  }
-
-  // We have loaded 5 pages, and are currently at the last-loaded page.
-  int url_index = 4;
-
-  enum Tests {
-    GO_TO_MIDDLE_PAGE = -2,
-    GO_FORWARDS = 1,
-    GO_BACKWARDS = -1,
-    GO_TO_BEGINNING = -2,
-    GO_TO_END = 4,
-    NUM_TESTS = 5,
-  };
-
-  const int test_offsets[NUM_TESTS] = {
-    GO_TO_MIDDLE_PAGE,
-    GO_FORWARDS,
-    GO_BACKWARDS,
-    GO_TO_BEGINNING,
-    GO_TO_END
-  };
-
-  for (int test = 0; test < NUM_TESTS; ++test) {
-    int offset = test_offsets[test];
-    controller.GoToOffset(offset);
-    url_index += offset;
-    // Check that the GoToOffset will land on the expected page.
-    EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
-    test_rvh()->SendNavigate(url_index, urls[url_index]);
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-    // Check that we can go to any valid offset into the history.
-    for (size_t j = 0; j < urls.size(); ++j)
-      EXPECT_TRUE(controller.CanGoToOffset(j - url_index));
-    // Check that we can't go beyond the beginning or end of the history.
-    EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1)));
-    EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index));
-  }
-}
-
-TEST_F(NavigationControllerTest, LoadURL) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  // Creating a pending notification should not have issued any of the
-  // notifications we're listening for.
-  EXPECT_EQ(0U, notifications.size());
-
-  // The load should now be pending.
-  EXPECT_EQ(controller.GetEntryCount(), 0);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
-  ASSERT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(contents()->GetMaxPageID(), -1);
-
-  // Neither the timestamp nor the status code should have been set yet.
-  EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
-  EXPECT_EQ(0, controller.GetPendingEntry()->GetHttpStatusCode());
-
-  // We should have gotten no notifications from the preceeding checks.
-  EXPECT_EQ(0U, notifications.size());
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The load should now be committed.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(contents()->GetMaxPageID(), 0);
-  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
-      controller.GetLastCommittedEntry())->bindings());
-
-  // The timestamp should have been set.
-  EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
-
-  // Load another...
-  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  // The load should now be pending.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  ASSERT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
-  // TODO(darin): maybe this should really be true?
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(contents()->GetMaxPageID(), 0);
-
-  EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
-
-  // Simulate the beforeunload ack for the cross-site transition, and then the
-  // commit.
-  test_rvh()->SendShouldCloseACK(true);
-  static_cast<TestRenderViewHost*>(
-      contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The load should now be committed.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(contents()->GetMaxPageID(), 1);
-
-  EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
-}
-
-namespace {
-
-base::Time GetFixedTime(base::Time time) {
-  return time;
-}
-
-}  // namespace
-
-TEST_F(NavigationControllerTest, LoadURLSameTime) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Set the clock to always return a timestamp of 1.
-  controller.SetGetTimestampCallbackForTest(
-      base::Bind(&GetFixedTime, base::Time::FromInternalValue(1)));
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Load another...
-  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  // Simulate the beforeunload ack for the cross-site transition, and then the
-  // commit.
-  test_rvh()->SendShouldCloseACK(true);
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The two loads should now be committed.
-  ASSERT_EQ(controller.GetEntryCount(), 2);
-
-  // Timestamps should be distinct despite the clock returning the
-  // same value.
-  EXPECT_EQ(1u,
-            controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
-  EXPECT_EQ(2u,
-            controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
-}
-
-void CheckNavigationEntryMatchLoadParams(
-    NavigationController::LoadURLParams& load_params,
-    NavigationEntryImpl* entry) {
-  EXPECT_EQ(load_params.url, entry->GetURL());
-  EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
-  EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy);
-  EXPECT_EQ(load_params.transition_type, entry->GetTransitionType());
-  EXPECT_EQ(load_params.extra_headers, entry->extra_headers());
-
-  EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated());
-  EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL());
-  if (!load_params.virtual_url_for_data_url.is_empty()) {
-    EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL());
-  }
-  if (NavigationController::UA_OVERRIDE_INHERIT !=
-      load_params.override_user_agent) {
-    bool should_override = (NavigationController::UA_OVERRIDE_TRUE ==
-        load_params.override_user_agent);
-    EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
-  }
-  EXPECT_EQ(load_params.browser_initiated_post_data,
-      entry->GetBrowserInitiatedPostData());
-  EXPECT_EQ(load_params.transferred_global_request_id,
-      entry->transferred_global_request_id());
-}
-
-TEST_F(NavigationControllerTest, LoadURLWithParams) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  NavigationController::LoadURLParams load_params(GURL("http://foo"));
-  load_params.referrer =
-      Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault);
-  load_params.transition_type = PAGE_TRANSITION_GENERATED;
-  load_params.extra_headers = "content-type: text/plain";
-  load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
-  load_params.is_renderer_initiated = true;
-  load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
-  load_params.transferred_global_request_id = GlobalRequestID(2, 3);
-
-  controller.LoadURLWithParams(load_params);
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetPendingEntry());
-
-  // The timestamp should not have been set yet.
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->GetTimestamp().is_null());
-
-  CheckNavigationEntryMatchLoadParams(load_params, entry);
-}
-
-TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  NavigationController::LoadURLParams load_params(
-      GURL("data:text/html,dataurl"));
-  load_params.load_type = NavigationController::LOAD_TYPE_DATA;
-  load_params.base_url_for_data_url = GURL("http://foo");
-  load_params.virtual_url_for_data_url = GURL(kAboutBlankURL);
-  load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
-
-  controller.LoadURLWithParams(load_params);
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetPendingEntry());
-
-  CheckNavigationEntryMatchLoadParams(load_params, entry);
-}
-
-TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  NavigationController::LoadURLParams load_params(GURL("https://posturl"));
-  load_params.transition_type = PAGE_TRANSITION_TYPED;
-  load_params.load_type =
-      NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
-  load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
-
-
-  const unsigned char* raw_data =
-      reinterpret_cast<const unsigned char*>("d\n\0a2");
-  const int length = 5;
-  std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
-  scoped_refptr<base::RefCountedBytes> data =
-      base::RefCountedBytes::TakeVector(&post_data_vector);
-  load_params.browser_initiated_post_data = data.get();
-
-  controller.LoadURLWithParams(load_params);
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetPendingEntry());
-
-  CheckNavigationEntryMatchLoadParams(load_params, entry);
-}
-
-// Tests what happens when the same page is loaded again.  Should not create a
-// new session history entry. This is what happens when you press enter in the
-// URL bar to reload: a pending entry is created and then it is discarded when
-// the load commits (because WebCore didn't actually make a new entry).
-TEST_F(NavigationControllerTest, LoadURL_SamePage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
-  EXPECT_FALSE(timestamp.is_null());
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // We should not have produced a new session history entry.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-
-  // The timestamp should have been updated.
-  //
-  // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
-  // EXPECT_GT once we guarantee that timestamps are unique.
-  EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
-}
-
-// Tests loading a URL but discarding it before the load commits.
-TEST_F(NavigationControllerTest, LoadURL_Discarded) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
-  EXPECT_FALSE(timestamp.is_null());
-
-  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  controller.DiscardNonCommittedEntries();
-  EXPECT_EQ(0U, notifications.size());
-
-  // Should not have produced a new session history entry.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-
-  // Timestamp should not have changed.
-  EXPECT_EQ(timestamp, controller.GetVisibleEntry()->GetTimestamp());
-}
-
-// Tests navigations that come in unrequested. This happens when the user
-// navigates from the web page, and here we test that there is no pending entry.
-TEST_F(NavigationControllerTest, LoadURL_NoPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make an existing committed entry.
-  const GURL kExistingURL1("http://eh");
-  controller.LoadURL(
-      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, kExistingURL1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Do a new navigation without making a pending one.
-  const GURL kNewURL("http://see");
-  test_rvh()->SendNavigate(99, kNewURL);
-
-  // There should no longer be any pending entry, and the third navigation we
-  // just made should be committed.
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
-}
-
-// Tests navigating to a new URL when there is a new pending navigation that is
-// not the one that just loaded. This will happen if the user types in a URL to
-// somewhere slow, and then navigates the current page before the typed URL
-// commits.
-TEST_F(NavigationControllerTest, LoadURL_NewPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make an existing committed entry.
-  const GURL kExistingURL1("http://eh");
-  controller.LoadURL(
-      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, kExistingURL1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Make a pending entry to somewhere new.
-  const GURL kExistingURL2("http://bee");
-  controller.LoadURL(
-      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-
-  // After the beforeunload but before it commits, do a new navigation.
-  test_rvh()->SendShouldCloseACK(true);
-  const GURL kNewURL("http://see");
-  static_cast<TestRenderViewHost*>(
-      contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
-
-  // There should no longer be any pending entry, and the third navigation we
-  // just made should be committed.
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
-}
-
-// Tests navigating to a new URL when there is a pending back/forward
-// navigation. This will happen if the user hits back, but before that commits,
-// they navigate somewhere new.
-TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make some history.
-  const GURL kExistingURL1("http://foo/eh");
-  controller.LoadURL(
-      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, kExistingURL1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  const GURL kExistingURL2("http://foo/bee");
-  controller.LoadURL(
-      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(1, kExistingURL2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now make a pending back/forward navigation. The zeroth entry should be
-  // pending.
-  controller.GoBack();
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(0, controller.GetPendingEntryIndex());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-
-  // Before that commits, do a new navigation.
-  const GURL kNewURL("http://foo/see");
-  LoadCommittedDetails details;
-  test_rvh()->SendNavigate(3, kNewURL);
-
-  // There should no longer be any pending entry, and the third navigation we
-  // just made should be committed.
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
-}
-
-// Tests navigating to a new URL when there is a pending back/forward
-// navigation to a cross-process, privileged URL. This will happen if the user
-// hits back, but before that commits, they navigate somewhere new.
-TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make some history, starting with a privileged URL.
-  const GURL kExistingURL1("http://privileged");
-  controller.LoadURL(
-      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  // Pretend it has bindings so we can tell if we incorrectly copy it.
-  test_rvh()->AllowBindings(2);
-  test_rvh()->SendNavigate(0, kExistingURL1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Navigate cross-process to a second URL.
-  const GURL kExistingURL2("http://foo/eh");
-  controller.LoadURL(
-      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendShouldCloseACK(true);
-  TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetPendingRenderViewHost());
-  foo_rvh->SendNavigate(1, kExistingURL2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now make a pending back/forward navigation to a privileged entry.
-  // The zeroth entry should be pending.
-  controller.GoBack();
-  foo_rvh->SendShouldCloseACK(true);
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(0, controller.GetPendingEntryIndex());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
-                controller.GetPendingEntry())->bindings());
-
-  // Before that commits, do a new navigation.
-  const GURL kNewURL("http://foo/bee");
-  LoadCommittedDetails details;
-  foo_rvh->SendNavigate(3, kNewURL);
-
-  // There should no longer be any pending entry, and the third navigation we
-  // just made should be committed.
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
-                controller.GetLastCommittedEntry())->bindings());
-}
-
-// Tests navigating to an existing URL when there is a pending new navigation.
-// This will happen if the user enters a URL, but before that commits, the
-// current page fires history.back().
-TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make some history.
-  const GURL kExistingURL1("http://foo/eh");
-  controller.LoadURL(
-      kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, kExistingURL1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  const GURL kExistingURL2("http://foo/bee");
-  controller.LoadURL(
-      kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(1, kExistingURL2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now make a pending new navigation.
-  const GURL kNewURL("http://foo/see");
-  controller.LoadURL(
-      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-
-  // Before that commits, a back navigation from the renderer commits.
-  test_rvh()->SendNavigate(0, kExistingURL1);
-
-  // There should no longer be any pending entry, and the back navigation we
-  // just made should be committed.
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kExistingURL1, controller.GetVisibleEntry()->GetURL());
-}
-
-// Tests an ignored navigation when there is a pending new navigation.
-// This will happen if the user enters a URL, but before that commits, the
-// current blank page reloads.  See http://crbug.com/77507.
-TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Set a WebContentsDelegate to listen for state changes.
-  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
-  EXPECT_FALSE(contents()->GetDelegate());
-  contents()->SetDelegate(delegate.get());
-
-  // Without any navigations, the renderer starts at about:blank.
-  const GURL kExistingURL(kAboutBlankURL);
-
-  // Now make a pending new navigation.
-  const GURL kNewURL("http://eh");
-  controller.LoadURL(
-      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(1, delegate->navigation_state_change_count());
-
-  // Before that commits, a document.write and location.reload can cause the
-  // renderer to send a FrameNavigate with page_id -1.
-  test_rvh()->SendNavigate(-1, kExistingURL);
-
-  // This should clear the pending entry and notify of a navigation state
-  // change, so that we do not keep displaying kNewURL.
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(2, delegate->navigation_state_change_count());
-
-  contents()->SetDelegate(NULL);
-}
-
-// Tests that the pending entry state is correct after an abort.
-// We do not want to clear the pending entry, so that the user doesn't
-// lose a typed URL.  (See http://crbug.com/9682.)
-TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Set a WebContentsDelegate to listen for state changes.
-  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
-  EXPECT_FALSE(contents()->GetDelegate());
-  contents()->SetDelegate(delegate.get());
-
-  // Start with a pending new navigation.
-  const GURL kNewURL("http://eh");
-  controller.LoadURL(
-      kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(1, delegate->navigation_state_change_count());
-
-  // It may abort before committing, if it's a download or due to a stop or
-  // a new navigation from the user.
-  ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
-  params.frame_id = 1;
-  params.is_main_frame = true;
-  params.error_code = net::ERR_ABORTED;
-  params.error_description = string16();
-  params.url = kNewURL;
-  params.showing_repost_interstitial = false;
-  test_rvh()->OnMessageReceived(
-          ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
-                                                      params));
-
-  // This should not clear the pending entry or notify of a navigation state
-  // change, so that we keep displaying kNewURL (until the user clears it).
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(1, delegate->navigation_state_change_count());
-  NavigationEntry* pending_entry = controller.GetPendingEntry();
-
-  // Ensure that a reload keeps the same pending entry.
-  controller.Reload(true);
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(pending_entry, controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-
-  contents()->SetDelegate(NULL);
-}
-
-// Tests that the pending URL is not visible during a renderer-initiated
-// redirect and abort.  See http://crbug.com/83031.
-TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // First make an existing committed entry.
-  const GURL kExistingURL("http://foo/eh");
-  controller.LoadURL(kExistingURL, content::Referrer(),
-                     content::PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, kExistingURL);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Set a WebContentsDelegate to listen for state changes.
-  scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
-  EXPECT_FALSE(contents()->GetDelegate());
-  contents()->SetDelegate(delegate.get());
-
-  // Now make a pending new navigation, initiated by the renderer.
-  const GURL kNewURL("http://foo/bee");
-  NavigationController::LoadURLParams load_url_params(kNewURL);
-  load_url_params.transition_type = PAGE_TRANSITION_TYPED;
-  load_url_params.is_renderer_initiated = true;
-  controller.LoadURLWithParams(load_url_params);
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(0, delegate->navigation_state_change_count());
-
-  // The visible entry should be the last committed URL, not the pending one.
-  EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
-
-  // Now the navigation redirects.
-  const GURL kRedirectURL("http://foo/see");
-  test_rvh()->OnMessageReceived(
-      ViewHostMsg_DidRedirectProvisionalLoad(0,  // routing_id
-                                             -1,  // pending page_id
-                                             kNewURL,  // old url
-                                             kRedirectURL));  // new url
-
-  // We don't want to change the NavigationEntry's url, in case it cancels.
-  // Prevents regression of http://crbug.com/77786.
-  EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
-
-  // It may abort before committing, if it's a download or due to a stop or
-  // a new navigation from the user.
-  ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
-  params.frame_id = 1;
-  params.is_main_frame = true;
-  params.error_code = net::ERR_ABORTED;
-  params.error_description = string16();
-  params.url = kRedirectURL;
-  params.showing_repost_interstitial = false;
-  test_rvh()->OnMessageReceived(
-          ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
-                                                      params));
-
-  // Because the pending entry is renderer initiated and not visible, we
-  // clear it when it fails.
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(0, delegate->navigation_state_change_count());
-
-  // The visible entry should be the last committed URL, not the pending one,
-  // so that no spoof is possible.
-  EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
-
-  contents()->SetDelegate(NULL);
-}
-
-// Ensure that NavigationEntries track which bindings their RenderViewHost had
-// at the time they committed.  http://crbug.com/173672.
-TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  // Navigate to a first, unprivileged URL.
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
-            NavigationEntryImpl::FromNavigationEntry(
-                controller.GetPendingEntry())->bindings());
-
-  // Commit.
-  TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh());
-  orig_rvh->SendNavigate(0, url1);
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
-      controller.GetLastCommittedEntry())->bindings());
-
-  // Manually increase the number of active views in the SiteInstance
-  // that orig_rvh belongs to, to prevent it from being destroyed when
-  // it gets swapped out, so that we can reuse orig_rvh when the
-  // controller goes back.
-  static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
-      increment_active_view_count();
-
-  // Navigate to a second URL, simulate the beforeunload ack for the cross-site
-  // transition, and set bindings on the pending RenderViewHost to simulate a
-  // privileged url.
-  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  orig_rvh->SendShouldCloseACK(true);
-  contents()->GetPendingRenderViewHost()->AllowBindings(1);
-  static_cast<TestRenderViewHost*>(
-      contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
-
-  // The second load should be committed, and bindings should be remembered.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
-      controller.GetLastCommittedEntry())->bindings());
-
-  // Going back, the first entry should still appear unprivileged.
-  controller.GoBack();
-  orig_rvh->SendNavigate(0, url1);
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
-      controller.GetLastCommittedEntry())->bindings());
-}
-
-TEST_F(NavigationControllerTest, Reload) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title"));
-  controller.Reload(true);
-  EXPECT_EQ(0U, notifications.size());
-
-  const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
-  EXPECT_FALSE(timestamp.is_null());
-
-  // The reload is pending.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  // Make sure the title has been cleared (will be redrawn just after reload).
-  // Avoids a stale cached title when the new page being reloaded has no title.
-  // See http://crbug.com/96041.
-  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now the reload is committed.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-
-  // The timestamp should have been updated.
-  ASSERT_TRUE(controller.GetVisibleEntry());
-  EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
-}
-
-// Tests what happens when a reload navigation produces a new page.
-TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.Reload(true);
-  EXPECT_EQ(0U, notifications.size());
-
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now the reload is committed.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-#if !defined(OS_ANDROID)  // http://crbug.com/157428
-TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL original_url("http://foo1");
-  const GURL final_url("http://foo2");
-
-  // Load up the original URL, but get redirected.
-  controller.LoadURL(
-      original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url, original_url);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The NavigationEntry should save both the original URL and the final
-  // redirected URL.
-  EXPECT_EQ(
-      original_url, controller.GetVisibleEntry()->GetOriginalRequestURL());
-  EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL());
-
-  // Reload using the original URL.
-  controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title"));
-  controller.ReloadOriginalRequestURL(false);
-  EXPECT_EQ(0U, notifications.size());
-
-  // The reload is pending.  The request should point to the original URL.
-  EXPECT_EQ(original_url, navigated_url());
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-
-  // Make sure the title has been cleared (will be redrawn just after reload).
-  // Avoids a stale cached title when the new page being reloaded has no title.
-  // See http://crbug.com/96041.
-  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
-
-  // Send that the navigation has proceeded; say it got redirected again.
-  test_rvh()->SendNavigate(0, final_url);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now the reload is committed.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-#endif  // !defined(OS_ANDROID)
-
-// Tests what happens when we navigate back successfully
-TEST_F(NavigationControllerTest, Back) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  const GURL url2("http://foo2");
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoBack();
-  EXPECT_EQ(0U, notifications.size());
-
-  // We should now have a pending navigation to go back.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoToOffset(-1));
-  EXPECT_TRUE(controller.CanGoForward());
-  EXPECT_TRUE(controller.CanGoToOffset(1));
-  EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
-
-  // Timestamp for entry 1 should be on or after that of entry 0.
-  EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
-  EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
-            controller.GetEntryAtIndex(0)->GetTimestamp());
-
-  test_rvh()->SendNavigate(0, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The back navigation completed successfully.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoToOffset(-1));
-  EXPECT_TRUE(controller.CanGoForward());
-  EXPECT_TRUE(controller.CanGoToOffset(1));
-  EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
-
-  // Timestamp for entry 0 should be on or after that of entry 1
-  // (since we went back to it).
-  EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
-            controller.GetEntryAtIndex(1)->GetTimestamp());
-}
-
-// Tests what happens when a back navigation produces a new page.
-TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoBack();
-  EXPECT_EQ(0U, notifications.size());
-
-  // We should now have a pending navigation to go back.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_TRUE(controller.CanGoForward());
-
-  test_rvh()->SendNavigate(2, url3);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The back navigation resulted in a completely new navigation.
-  // TODO(darin): perhaps this behavior will be confusing to users?
-  EXPECT_EQ(controller.GetEntryCount(), 3);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-// Receives a back message when there is a new pending navigation entry.
-TEST_F(NavigationControllerTest, Back_NewPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL kUrl1("http://foo1");
-  const GURL kUrl2("http://foo2");
-  const GURL kUrl3("http://foo3");
-
-  // First navigate two places so we have some back history.
-  test_rvh()->SendNavigate(0, kUrl1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
-  test_rvh()->SendNavigate(1, kUrl2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Now start a new pending navigation and go back before it commits.
-  controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
-  controller.GoBack();
-
-  // The pending navigation should now be the "back" item and the new one
-  // should be gone.
-  EXPECT_EQ(0, controller.GetPendingEntryIndex());
-  EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
-}
-
-// Receives a back message when there is a different renavigation already
-// pending.
-TEST_F(NavigationControllerTest, Back_OtherBackPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL kUrl1("http://foo/1");
-  const GURL kUrl2("http://foo/2");
-  const GURL kUrl3("http://foo/3");
-
-  // First navigate three places so we have some back history.
-  test_rvh()->SendNavigate(0, kUrl1);
-  test_rvh()->SendNavigate(1, kUrl2);
-  test_rvh()->SendNavigate(2, kUrl3);
-
-  // With nothing pending, say we get a navigation to the second entry.
-  test_rvh()->SendNavigate(1, kUrl2);
-
-  // We know all the entries have the same site instance, so we can just grab
-  // a random one for looking up other entries.
-  SiteInstance* site_instance =
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetLastCommittedEntry())->site_instance();
-
-  // That second URL should be the last committed and it should have gotten the
-  // new title.
-  EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
-  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-
-  // Now go forward to the last item again and say it was committed.
-  controller.GoForward();
-  test_rvh()->SendNavigate(2, kUrl3);
-
-  // Now start going back one to the second page. It will be pending.
-  controller.GoBack();
-  EXPECT_EQ(1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
-
-  // Not synthesize a totally new back event to the first page. This will not
-  // match the pending one.
-  test_rvh()->SendNavigate(0, kUrl1);
-
-  // The committed navigation should clear the pending entry.
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-
-  // But the navigated entry should be the last committed.
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
-}
-
-// Tests what happens when we navigate forward successfully.
-TEST_F(NavigationControllerTest, Forward) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoBack();
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoForward();
-
-  // We should now have a pending navigation to go forward.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_TRUE(controller.CanGoToOffset(-1));
-  EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_FALSE(controller.CanGoToOffset(1));
-
-  // Timestamp for entry 0 should be on or after that of entry 1
-  // (since we went back to it).
-  EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
-  EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
-            controller.GetEntryAtIndex(1)->GetTimestamp());
-
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // The forward navigation completed successfully.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_TRUE(controller.CanGoToOffset(-1));
-  EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_FALSE(controller.CanGoToOffset(1));
-
-  // Timestamp for entry 1 should be on or after that of entry 0
-  // (since we went forward to it).
-  EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
-            controller.GetEntryAtIndex(0)->GetTimestamp());
-}
-
-// Tests what happens when a forward navigation produces a new page.
-TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoBack();
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  controller.GoForward();
-  EXPECT_EQ(0U, notifications.size());
-
-  // Should now have a pending navigation to go forward.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-
-  test_rvh()->SendNavigate(2, url3);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
-
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-// Two consequent navigation for the same URL entered in should be considered
-// as SAME_PAGE navigation even when we are redirected to some other page.
-TEST_F(NavigationControllerTest, Redirect) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");  // Redirection target
-
-  // First request
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Second request
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
-  params.redirects.push_back(GURL("http://foo1"));
-  params.redirects.push_back(GURL("http://foo2"));
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  LoadCommittedDetails details;
-
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-// Similar to Redirect above, but the first URL is requested by POST,
-// the second URL is requested by GET. NavigationEntry::has_post_data_
-// must be cleared. http://crbug.com/21245
-TEST_F(NavigationControllerTest, PostThenRedirect) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");  // Redirection target
-
-  // First request as POST
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  controller.GetVisibleEntry()->SetHasPostData(true);
-
-  EXPECT_EQ(0U, notifications.size());
-  test_rvh()->SendNavigate(0, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Second request
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
-  params.redirects.push_back(GURL("http://foo1"));
-  params.redirects.push_back(GURL("http://foo2"));
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  LoadCommittedDetails details;
-
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-  EXPECT_FALSE(controller.GetVisibleEntry()->GetHasPostData());
-
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-// A redirect right off the bat should be a NEW_PAGE.
-TEST_F(NavigationControllerTest, ImmediateRedirect) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");  // Redirection target
-
-  // First request
-  controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
-  params.redirects.push_back(GURL("http://foo1"));
-  params.redirects.push_back(GURL("http://foo2"));
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  LoadCommittedDetails details;
-
-  EXPECT_EQ(0U, notifications.size());
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-// Tests navigation via link click within a subframe. A new navigation entry
-// should be created.
-TEST_F(NavigationControllerTest, NewSubframe) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  const GURL url2("http://foo2");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 1;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  LoadCommittedDetails details;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(url1, details.previous_url);
-  EXPECT_FALSE(details.is_in_page);
-  EXPECT_FALSE(details.is_main_frame);
-
-  // The new entry should be appended.
-  EXPECT_EQ(2, controller.GetEntryCount());
-
-  // New entry should refer to the new page, but the old URL (entries only
-  // reflect the toplevel URL).
-  EXPECT_EQ(url1, details.entry->GetURL());
-  EXPECT_EQ(params.page_id, details.entry->GetPageID());
-}
-
-// Some pages create a popup, then write an iframe into it. This causes a
-// subframe navigation without having any committed entry. Such navigations
-// just get thrown on the ground, but we shouldn't crash.
-TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Navigation controller currently has no entries.
-  const GURL url("http://foo2");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 1;
-  params.url = url;
-  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url);
-
-  LoadCommittedDetails details;
-  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(0U, notifications.size());
-}
-
-// Auto subframes are ones the page loads automatically like ads. They should
-// not create new navigation entries.
-TEST_F(NavigationControllerTest, AutoSubframe) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  const GURL url2("http://foo2");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  // Navigating should do nothing.
-  LoadCommittedDetails details;
-  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(0U, notifications.size());
-
-  // There should still be only one entry.
-  EXPECT_EQ(1, controller.GetEntryCount());
-}
-
-// Tests navigation and then going back to a subframe navigation.
-TEST_F(NavigationControllerTest, BackSubframe) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Main page.
-  const GURL url1("http://foo1");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // First manual subframe navigation.
-  const GURL url2("http://foo2");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 1;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  // This should generate a new entry.
-  LoadCommittedDetails details;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(2, controller.GetEntryCount());
-
-  // Second manual subframe navigation should also make a new entry.
-  const GURL url3("http://foo3");
-  params.page_id = 2;
-  params.url = url3;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
-
-  // Go back one.
-  controller.GoBack();
-  params.url = url2;
-  params.page_id = 1;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-
-  // Go back one more.
-  controller.GoBack();
-  params.url = url1;
-  params.page_id = 0;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-}
-
-TEST_F(NavigationControllerTest, LinkClick) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  test_rvh()->SendNavigate(1, url2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Should not have produced a new session history entry.
-  EXPECT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-}
-
-TEST_F(NavigationControllerTest, InPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Main page.
-  const GURL url1("http://foo");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Ensure main page navigation to same url respects the was_within_same_page
-  // hint provided in the params.
-  ViewHostMsg_FrameNavigate_Params self_params;
-  self_params.page_id = 0;
-  self_params.url = url1;
-  self_params.transition = PAGE_TRANSITION_LINK;
-  self_params.should_update_history = false;
-  self_params.gesture = NavigationGestureUser;
-  self_params.is_post = false;
-  self_params.page_state = PageState::CreateFromURL(url1);
-  self_params.was_within_same_page = true;
-
-  LoadCommittedDetails details;
-  EXPECT_TRUE(controller.RendererDidNavigate(self_params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(details.is_in_page);
-  EXPECT_TRUE(details.did_replace_entry);
-  EXPECT_EQ(1, controller.GetEntryCount());
-
-  // Fragment navigation to a new page_id.
-  const GURL url2("http://foo#a");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 1;
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_LINK;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-  params.was_within_same_page = true;
-
-  // This should generate a new entry.
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(details.is_in_page);
-  EXPECT_FALSE(details.did_replace_entry);
-  EXPECT_EQ(2, controller.GetEntryCount());
-
-  // Go back one.
-  ViewHostMsg_FrameNavigate_Params back_params(params);
-  controller.GoBack();
-  back_params.url = url1;
-  back_params.page_id = 0;
-  EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(details.is_in_page);
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
-  EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
-
-  // Go forward
-  ViewHostMsg_FrameNavigate_Params forward_params(params);
-  controller.GoForward();
-  forward_params.url = url2;
-  forward_params.page_id = 1;
-  EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(details.is_in_page);
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
-  EXPECT_EQ(forward_params.url,
-            controller.GetVisibleEntry()->GetURL());
-
-  // Now go back and forward again. This is to work around a bug where we would
-  // compare the incoming URL with the last committed entry rather than the
-  // one identified by an existing page ID. This would result in the second URL
-  // losing the reference fragment when you navigate away from it and then back.
-  controller.GoBack();
-  EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
-  controller.GoForward();
-  EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
-  EXPECT_EQ(forward_params.url,
-            controller.GetVisibleEntry()->GetURL());
-
-  // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
-  const GURL url3("http://bar");
-  params.page_id = 2;
-  params.url = url3;
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_FALSE(details.is_in_page);
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
-}
-
-TEST_F(NavigationControllerTest, InPage_Replace) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Main page.
-  const GURL url1("http://foo");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // First navigation.
-  const GURL url2("http://foo#a");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;  // Same page_id
-  params.url = url2;
-  params.transition = PAGE_TRANSITION_LINK;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url2);
-
-  // This should NOT generate a new entry, nor prune the list.
-  LoadCommittedDetails details;
-  EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(details.is_in_page);
-  EXPECT_TRUE(details.did_replace_entry);
-  EXPECT_EQ(1, controller.GetEntryCount());
-}
-
-// Tests for http://crbug.com/40395
-// Simulates this:
-//   <script>
-//     window.location.replace("#a");
-//     window.location='http://foo3/';
-//   </script>
-TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Load an initial page.
-  {
-    const GURL url("http://foo/");
-    test_rvh()->SendNavigate(0, url);
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-  }
-
-  // Navigate to a new page.
-  {
-    const GURL url("http://foo2/");
-    test_rvh()->SendNavigate(1, url);
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-  }
-
-  // Navigate within the page.
-  {
-    const GURL url("http://foo2/#a");
-    ViewHostMsg_FrameNavigate_Params params;
-    params.page_id = 1;  // Same page_id
-    params.url = url;
-    params.transition = PAGE_TRANSITION_LINK;
-    params.redirects.push_back(url);
-    params.should_update_history = true;
-    params.gesture = NavigationGestureUnknown;
-    params.is_post = false;
-    params.page_state = PageState::CreateFromURL(url);
-
-    // This should NOT generate a new entry, nor prune the list.
-    LoadCommittedDetails details;
-    EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-    EXPECT_TRUE(details.is_in_page);
-    EXPECT_TRUE(details.did_replace_entry);
-    EXPECT_EQ(2, controller.GetEntryCount());
-  }
-
-  // Perform a client redirect to a new page.
-  {
-    const GURL url("http://foo3/");
-    ViewHostMsg_FrameNavigate_Params params;
-    params.page_id = 2;  // New page_id
-    params.url = url;
-    params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
-    params.redirects.push_back(GURL("http://foo2/#a"));
-    params.redirects.push_back(url);
-    params.should_update_history = true;
-    params.gesture = NavigationGestureUnknown;
-    params.is_post = false;
-    params.page_state = PageState::CreateFromURL(url);
-
-    // This SHOULD generate a new entry.
-    LoadCommittedDetails details;
-    EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-    EXPECT_FALSE(details.is_in_page);
-    EXPECT_EQ(3, controller.GetEntryCount());
-  }
-
-  // Verify that BACK brings us back to http://foo2/.
-  {
-    const GURL url("http://foo2/");
-    controller.GoBack();
-    test_rvh()->SendNavigate(1, url);
-    EXPECT_EQ(1U, navigation_entry_committed_counter_);
-    navigation_entry_committed_counter_ = 0;
-    EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
-  }
-}
-
-// NotificationObserver implementation used in verifying we've received the
-// NOTIFICATION_NAV_LIST_PRUNED method.
-class PrunedListener : public NotificationObserver {
- public:
-  explicit PrunedListener(NavigationControllerImpl* controller)
-      : notification_count_(0) {
-    registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED,
-                   Source<NavigationController>(controller));
-  }
-
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE {
-    if (type == NOTIFICATION_NAV_LIST_PRUNED) {
-      notification_count_++;
-      details_ = *(Details<PrunedDetails>(details).ptr());
-    }
-  }
-
-  // Number of times NAV_LIST_PRUNED has been observed.
-  int notification_count_;
-
-  // Details from the last NAV_LIST_PRUNED.
-  PrunedDetails details_;
-
- private:
-  NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(PrunedListener);
-};
-
-// Tests that we limit the number of navigation entries created correctly.
-TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
-  NavigationControllerImpl& controller = controller_impl();
-  size_t original_count = NavigationControllerImpl::max_entry_count();
-  const int kMaxEntryCount = 5;
-
-  NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
-
-  int url_index;
-  // Load up to the max count, all entries should be there.
-  for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
-    GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
-    controller.LoadURL(
-        url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-    test_rvh()->SendNavigate(url_index, url);
-  }
-
-  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
-
-  // Created a PrunedListener to observe prune notifications.
-  PrunedListener listener(&controller);
-
-  // Navigate some more.
-  GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
-  controller.LoadURL(
-      url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(url_index, url);
-  url_index++;
-
-  // We should have got a pruned navigation.
-  EXPECT_EQ(1, listener.notification_count_);
-  EXPECT_TRUE(listener.details_.from_front);
-  EXPECT_EQ(1, listener.details_.count);
-
-  // We expect http://www.a.com/0 to be gone.
-  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
-            GURL("http:////www.a.com/1"));
-
-  // More navigations.
-  for (int i = 0; i < 3; i++) {
-    url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
-    controller.LoadURL(
-        url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-    test_rvh()->SendNavigate(url_index, url);
-    url_index++;
-  }
-  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
-            GURL("http:////www.a.com/4"));
-
-  NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
-}
-
-// Tests that we can do a restore and navigate to the restored entries and
-// everything is updated properly. This can be tricky since there is no
-// SiteInstance for the entries created initially.
-TEST_F(NavigationControllerTest, RestoreNavigate) {
-  // Create a NavigationController with a restored set of tabs.
-  GURL url("http://foo");
-  std::vector<NavigationEntry*> entries;
-  NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
-      url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
-      browser_context());
-  entry->SetPageID(0);
-  entry->SetTitle(ASCIIToUTF16("Title"));
-  entry->SetPageState(PageState::CreateFromEncodedData("state"));
-  const base::Time timestamp = base::Time::Now();
-  entry->SetTimestamp(timestamp);
-  entries.push_back(entry);
-  scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
-      WebContents::Create(WebContents::CreateParams(browser_context()))));
-  NavigationControllerImpl& our_controller = our_contents->GetController();
-  our_controller.Restore(
-      0,
-      NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-      &entries);
-  ASSERT_EQ(0u, entries.size());
-
-  // Before navigating to the restored entry, it should have a restore_type
-  // and no SiteInstance.
-  ASSERT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetEntryAtIndex(0))->restore_type());
-  EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
-      our_controller.GetEntryAtIndex(0))->site_instance());
-
-  // After navigating, we should have one entry, and it should be "pending".
-  // It should now have a SiteInstance and no restore_type.
-  our_controller.GoToIndex(0);
-  EXPECT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(our_controller.GetEntryAtIndex(0),
-            our_controller.GetPendingEntry());
-  EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
-            NavigationEntryImpl::FromNavigationEntry
-                (our_controller.GetEntryAtIndex(0))->restore_type());
-  EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
-      our_controller.GetEntryAtIndex(0))->site_instance());
-
-  // Timestamp should remain the same before the navigation finishes.
-  EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
-
-  // Say we navigated to that entry.
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url;
-  params.transition = PAGE_TRANSITION_LINK;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url);
-  LoadCommittedDetails details;
-  our_controller.RendererDidNavigate(params, &details);
-
-  // There should be no longer any pending entry and one committed one. This
-  // means that we were able to locate the entry, assign its site instance, and
-  // commit it properly.
-  EXPECT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
-  EXPECT_FALSE(our_controller.GetPendingEntry());
-  EXPECT_EQ(url,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetLastCommittedEntry())->site_instance()->
-                    GetSiteURL());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetEntryAtIndex(0))->restore_type());
-
-  // Timestamp should have been updated.
-  EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
-}
-
-// Tests that we can still navigate to a restored entry after a different
-// navigation fails and clears the pending entry.  http://crbug.com/90085
-TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
-  // Create a NavigationController with a restored set of tabs.
-  GURL url("http://foo");
-  std::vector<NavigationEntry*> entries;
-  NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
-      url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
-      browser_context());
-  entry->SetPageID(0);
-  entry->SetTitle(ASCIIToUTF16("Title"));
-  entry->SetPageState(PageState::CreateFromEncodedData("state"));
-  entries.push_back(entry);
-  scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
-      WebContents::Create(WebContents::CreateParams(browser_context()))));
-  NavigationControllerImpl& our_controller = our_contents->GetController();
-  our_controller.Restore(
-      0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
-  ASSERT_EQ(0u, entries.size());
-
-  // Before navigating to the restored entry, it should have a restore_type
-  // and no SiteInstance.
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetEntryAtIndex(0))->restore_type());
-  EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
-      our_controller.GetEntryAtIndex(0))->site_instance());
-
-  // After navigating, we should have one entry, and it should be "pending".
-  // It should now have a SiteInstance and no restore_type.
-  our_controller.GoToIndex(0);
-  EXPECT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(our_controller.GetEntryAtIndex(0),
-            our_controller.GetPendingEntry());
-  EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetEntryAtIndex(0))->restore_type());
-  EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
-      our_controller.GetEntryAtIndex(0))->site_instance());
-
-  // This pending navigation may have caused a different navigation to fail,
-  // which causes the pending entry to be cleared.
-  TestRenderViewHost* rvh =
-      static_cast<TestRenderViewHost*>(our_contents->GetRenderViewHost());
-  ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
-  fail_load_params.frame_id = 1;
-  fail_load_params.is_main_frame = true;
-  fail_load_params.error_code = net::ERR_ABORTED;
-  fail_load_params.error_description = string16();
-  fail_load_params.url = url;
-  fail_load_params.showing_repost_interstitial = false;
-  rvh->OnMessageReceived(
-      ViewHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
-                                                  fail_load_params));
-
-  // Now the pending restored entry commits.
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = url;
-  params.transition = PAGE_TRANSITION_LINK;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureUser;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url);
-  LoadCommittedDetails details;
-  our_controller.RendererDidNavigate(params, &details);
-
-  // There should be no pending entry and one committed one.
-  EXPECT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
-  EXPECT_FALSE(our_controller.GetPendingEntry());
-  EXPECT_EQ(url,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetLastCommittedEntry())->site_instance()->
-                    GetSiteURL());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
-            NavigationEntryImpl::FromNavigationEntry(
-                our_controller.GetEntryAtIndex(0))->restore_type());
-}
-
-// Make sure that the page type and stuff is correct after an interstitial.
-TEST_F(NavigationControllerTest, Interstitial) {
-  NavigationControllerImpl& controller = controller_impl();
-  // First navigate somewhere normal.
-  const GURL url1("http://foo");
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url1);
-
-  // Now navigate somewhere with an interstitial.
-  const GURL url2("http://bar");
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-      set_page_type(PAGE_TYPE_INTERSTITIAL);
-
-  // At this point the interstitial will be displayed and the load will still
-  // be pending. If the user continues, the load will commit.
-  test_rvh()->SendNavigate(1, url2);
-
-  // The page should be a normal page again.
-  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
-  EXPECT_EQ(PAGE_TYPE_NORMAL,
-            controller.GetLastCommittedEntry()->GetPageType());
-}
-
-TEST_F(NavigationControllerTest, RemoveEntry) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-  const GURL url4("http://foo/4");
-  const GURL url5("http://foo/5");
-  const GURL pending_url("http://foo/pending");
-  const GURL default_url("http://foo/default");
-
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url1);
-  controller.LoadURL(
-      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(1, url2);
-  controller.LoadURL(
-      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(2, url3);
-  controller.LoadURL(
-      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(3, url4);
-  controller.LoadURL(
-      url5, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(4, url5);
-
-  // Try to remove the last entry.  Will fail because it is the current entry.
-  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
-  EXPECT_EQ(5, controller.GetEntryCount());
-  EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
-
-  // Go back, but don't commit yet. Check that we can't delete the current
-  // and pending entries.
-  controller.GoBack();
-  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
-  EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
-
-  // Now commit and delete the last entry.
-  test_rvh()->SendNavigate(3, url4);
-  EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
-  EXPECT_EQ(4, controller.GetEntryCount());
-  EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-
-  // Remove an entry which is not the last committed one.
-  EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-
-  // Remove the 2 remaining entries.
-  controller.RemoveEntryAtIndex(1);
-  controller.RemoveEntryAtIndex(0);
-
-  // This should leave us with only the last committed entry.
-  EXPECT_EQ(1, controller.GetEntryCount());
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-}
-
-// Tests the transient entry, making sure it goes away with all navigations.
-TEST_F(NavigationControllerTest, TransientEntry) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url0("http://foo/0");
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-  const GURL url3_ref("http://foo/3#bar");
-  const GURL url4("http://foo/4");
-  const GURL transient_url("http://foo/transient");
-
-  controller.LoadURL(
-      url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url0);
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(1, url1);
-
-  notifications.Reset();
-
-  // Adding a transient with no pending entry.
-  NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-
-  // We should not have received any notifications.
-  EXPECT_EQ(0U, notifications.size());
-
-  // Check our state.
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(controller.GetEntryCount(), 3);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
-  EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(contents()->GetMaxPageID(), 1);
-
-  // Navigate.
-  controller.LoadURL(
-      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(2, url2);
-
-  // We should have navigated, transient entry should be gone.
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(controller.GetEntryCount(), 3);
-
-  // Add a transient again, then navigate with no pending entry this time.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(3, url3);
-  // Transient entry should be gone.
-  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(controller.GetEntryCount(), 4);
-
-  // Initiate a navigation, add a transient then commit navigation.
-  controller.LoadURL(
-      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(4, url4);
-  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(controller.GetEntryCount(), 5);
-
-  // Add a transient and go back.  This should simply remove the transient.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  EXPECT_TRUE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  controller.GoBack();
-  // Transient entry should be gone.
-  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(controller.GetEntryCount(), 5);
-  test_rvh()->SendNavigate(3, url3);
-
-  // Add a transient and go to an entry before the current one.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  controller.GoToIndex(1);
-  // The navigation should have been initiated, transient entry should be gone.
-  EXPECT_FALSE(controller.GetTransientEntry());
-  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
-  // Visible entry does not update for history navigations until commit.
-  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(1, url1);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-
-  // Add a transient and go to an entry after the current one.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  controller.GoToIndex(3);
-  // The navigation should have been initiated, transient entry should be gone.
-  // Because of the transient entry that is removed, going to index 3 makes us
-  // land on url2 (which is visible after the commit).
-  EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(2, url2);
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-
-  // Add a transient and go forward.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  EXPECT_TRUE(controller.CanGoForward());
-  controller.GoForward();
-  // We should have navigated, transient entry should be gone.
-  EXPECT_FALSE(controller.GetTransientEntry());
-  EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(3, url3);
-  EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
-
-  // Add a transient and do an in-page navigation, replacing the current entry.
-  transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(3, url3_ref);
-  // Transient entry should be gone.
-  EXPECT_FALSE(controller.GetTransientEntry());
-  EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL());
-
-  // Ensure the URLs are correct.
-  EXPECT_EQ(controller.GetEntryCount(), 5);
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
-  EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
-  EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
-  EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref);
-  EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
-}
-
-// Test that Reload initiates a new navigation to a transient entry's URL.
-TEST_F(NavigationControllerTest, ReloadTransient) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url0("http://foo/0");
-  const GURL url1("http://foo/1");
-  const GURL transient_url("http://foo/transient");
-
-  // Load |url0|, and start a pending navigation to |url1|.
-  controller.LoadURL(
-      url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  test_rvh()->SendNavigate(0, url0);
-  controller.LoadURL(
-      url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  // A transient entry is added, interrupting the navigation.
-  NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
-  transient_entry->SetURL(transient_url);
-  controller.SetTransientEntry(transient_entry);
-  EXPECT_TRUE(controller.GetTransientEntry());
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-
-  // The page is reloaded, which should remove the pending entry for |url1| and
-  // the transient entry for |transient_url|, and start a navigation to
-  // |transient_url|.
-  controller.Reload(true);
-  EXPECT_FALSE(controller.GetTransientEntry());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
-  ASSERT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
-
-  // Load of |transient_url| completes.
-  test_rvh()->SendNavigate(1, transient_url);
-  ASSERT_EQ(controller.GetEntryCount(), 2);
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
-  EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
-}
-
-// Ensure that renderer initiated pending entries get replaced, so that we
-// don't show a stale virtual URL when a navigation commits.
-// See http://crbug.com/266922.
-TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  const GURL url1("nonexistent:12121");
-  const GURL url1_fixed("http://nonexistent:12121/");
-  const GURL url2("http://foo");
-
-  // We create pending entries for renderer-initiated navigations so that we
-  // can show them in new tabs when it is safe.
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, url1);
-
-  // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
-  // the virtual URL to differ from the URL.
-  controller.GetPendingEntry()->SetURL(url1_fixed);
-  controller.GetPendingEntry()->SetVirtualURL(url1);
-
-  EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL());
-  EXPECT_TRUE(
-      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-          is_renderer_initiated());
-
-  // If the user clicks another link, we should replace the pending entry.
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, url2);
-  EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
-
-  // Once it commits, the URL and virtual URL should reflect the actual page.
-  test_rvh()->SendNavigate(0, url2);
-  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
-  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
-
-  // We should not replace the pending entry for an error URL.
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, url1);
-  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, GURL(kUnreachableWebDataURL));
-  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
-
-  // We should remember if the pending entry will replace the current one.
-  // http://crbug.com/308444.
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, url1);
-  NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-      set_should_replace_entry(true);
-  contents()->DidStartProvisionalLoadForFrame(
-      test_rvh(), 1, -1, true, url2);
-  EXPECT_TRUE(
-      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-          should_replace_entry());
-  test_rvh()->SendNavigate(0, url2);
-  EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
-}
-
-// Tests that the URLs for renderer-initiated navigations are not displayed to
-// the user until the navigation commits, to prevent URL spoof attacks.
-// See http://crbug.com/99016.
-TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url0("http://foo/0");
-  const GURL url1("http://foo/1");
-
-  // For typed navigations (browser-initiated), both pending and visible entries
-  // should update before commit.
-  controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
-  test_rvh()->SendNavigate(0, url0);
-
-  // For link clicks (renderer-initiated navigations), the pending entry should
-  // update before commit but the visible should not.
-  NavigationController::LoadURLParams load_url_params(url1);
-  load_url_params.is_renderer_initiated = true;
-  controller.LoadURLWithParams(load_url_params);
-  EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
-  EXPECT_TRUE(
-      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-          is_renderer_initiated());
-
-  // After commit, both visible should be updated, there should be no pending
-  // entry, and we should no longer treat the entry as renderer-initiated.
-  test_rvh()->SendNavigate(1, url1);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetLastCommittedEntry())->is_renderer_initiated());
-
-  notifications.Reset();
-}
-
-// Tests that the URLs for renderer-initiated navigations in new tabs are
-// displayed to the user before commit, as long as the initial about:blank
-// page has not been modified.  If so, we must revert to showing about:blank.
-// See http://crbug.com/9682.
-TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url("http://foo");
-
-  // For renderer-initiated navigations in new tabs (with no committed entries),
-  // we show the pending entry's URL as long as the about:blank page is not
-  // modified.
-  NavigationController::LoadURLParams load_url_params(url);
-  load_url_params.transition_type = PAGE_TRANSITION_LINK;
-  load_url_params.is_renderer_initiated = true;
-  controller.LoadURLWithParams(load_url_params);
-  EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
-  EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
-  EXPECT_TRUE(
-      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-          is_renderer_initiated());
-  EXPECT_TRUE(controller.IsInitialNavigation());
-  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
-
-  // There should be no title yet.
-  EXPECT_TRUE(contents()->GetTitle().empty());
-
-  // If something else modifies the contents of the about:blank page, then
-  // we must revert to showing about:blank to avoid a URL spoof.
-  test_rvh()->OnMessageReceived(
-        ViewHostMsg_DidAccessInitialDocument(0));
-  EXPECT_TRUE(test_rvh()->has_accessed_initial_document());
-  EXPECT_FALSE(controller.GetVisibleEntry());
-  EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
-
-  notifications.Reset();
-}
-
-TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  const GURL url1("http://foo/eh");
-  const GURL url2("http://foo/bee");
-
-  // For renderer-initiated navigations in new tabs (with no committed entries),
-  // we show the pending entry's URL as long as the about:blank page is not
-  // modified.
-  NavigationController::LoadURLParams load_url_params(url1);
-  load_url_params.transition_type = PAGE_TRANSITION_LINK;
-  load_url_params.is_renderer_initiated = true;
-  controller.LoadURLWithParams(load_url_params);
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-  EXPECT_TRUE(
-      NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
-          is_renderer_initiated());
-  EXPECT_TRUE(controller.IsInitialNavigation());
-  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
-
-  // Simulate a commit and then starting a new pending navigation.
-  test_rvh()->SendNavigate(0, url1);
-  NavigationController::LoadURLParams load_url2_params(url2);
-  load_url2_params.transition_type = PAGE_TRANSITION_LINK;
-  load_url2_params.is_renderer_initiated = true;
-  controller.LoadURLWithParams(load_url2_params);
-
-  // We should not consider this an initial navigation, and thus should
-  // not show the pending URL.
-  EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
-  EXPECT_FALSE(controller.IsInitialNavigation());
-  EXPECT_TRUE(controller.GetVisibleEntry());
-  EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
-
-  notifications.Reset();
-}
-
-// Tests that IsInPageNavigation returns appropriate results.  Prevents
-// regression for bug 1126349.
-TEST_F(NavigationControllerTest, IsInPageNavigation) {
-  NavigationControllerImpl& controller = controller_impl();
-  // Navigate to URL with no refs.
-  const GURL url("http://www.google.com/home.html");
-  test_rvh()->SendNavigate(0, url);
-
-  // Reloading the page is not an in-page navigation.
-  EXPECT_FALSE(controller.IsURLInPageNavigation(url));
-  const GURL other_url("http://www.google.com/add.html");
-  EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
-  const GURL url_with_ref("http://www.google.com/home.html#my_ref");
-  EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref));
-
-  // Navigate to URL with refs.
-  test_rvh()->SendNavigate(1, url_with_ref);
-
-  // Reloading the page is not an in-page navigation.
-  EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref));
-  EXPECT_FALSE(controller.IsURLInPageNavigation(url));
-  EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
-  const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
-  EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref));
-
-  // Going to the same url again will be considered in-page
-  // if the renderer says it is even if the navigation type isn't IN_PAGE.
-  EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
-      NAVIGATION_TYPE_UNKNOWN));
-
-  // Going back to the non ref url will be considered in-page if the navigation
-  // type is IN_PAGE.
-  EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
-      NAVIGATION_TYPE_IN_PAGE));
-}
-
-// Some pages can have subframes with the same base URL (minus the reference) as
-// the main page. Even though this is hard, it can happen, and we don't want
-// these subframe navigations to affect the toplevel document. They should
-// instead be ignored.  http://crbug.com/5585
-TEST_F(NavigationControllerTest, SameSubframe) {
-  NavigationControllerImpl& controller = controller_impl();
-  // Navigate the main frame.
-  const GURL url("http://www.google.com/");
-  test_rvh()->SendNavigate(0, url);
-
-  // We should be at the first navigation entry.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-
-  // Navigate a subframe that would normally count as in-page.
-  const GURL subframe("http://www.google.com/#");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 0;
-  params.url = subframe;
-  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(subframe);
-  LoadCommittedDetails details;
-  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
-
-  // Nothing should have changed.
-  EXPECT_EQ(controller.GetEntryCount(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
-}
-
-// Make sure that on cloning a WebContentsImpl and going back needs_reload is
-// false.
-TEST_F(NavigationControllerTest, CloneAndGoBack) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const string16 title(ASCIIToUTF16("Title"));
-
-  NavigateAndCommit(url1);
-  controller.GetVisibleEntry()->SetTitle(title);
-  NavigateAndCommit(url2);
-
-  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
-
-  ASSERT_EQ(2, clone->GetController().GetEntryCount());
-  EXPECT_TRUE(clone->GetController().NeedsReload());
-  clone->GetController().GoBack();
-  // Navigating back should have triggered needs_reload_ to go false.
-  EXPECT_FALSE(clone->GetController().NeedsReload());
-
-  // Ensure that the pending URL and its title are visible.
-  EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL());
-  EXPECT_EQ(title, clone->GetTitle());
-}
-
-// Make sure that reloading a cloned tab doesn't change its pending entry index.
-// See http://crbug.com/234491.
-TEST_F(NavigationControllerTest, CloneAndReload) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const string16 title(ASCIIToUTF16("Title"));
-
-  NavigateAndCommit(url1);
-  controller.GetVisibleEntry()->SetTitle(title);
-  NavigateAndCommit(url2);
-
-  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
-  clone->GetController().LoadIfNecessary();
-
-  ASSERT_EQ(2, clone->GetController().GetEntryCount());
-  EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
-
-  clone->GetController().Reload(true);
-  EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
-}
-
-// Make sure that cloning a WebContentsImpl doesn't copy interstitials.
-TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-
-  // Add an interstitial entry.  Should be deleted with controller.
-  NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
-  interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
-  controller.SetTransientEntry(interstitial_entry);
-
-  scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
-
-  ASSERT_EQ(2, clone->GetController().GetEntryCount());
-}
-
-// Test requesting and triggering a lazy reload.
-TEST_F(NavigationControllerTest, LazyReload) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url("http://foo");
-  NavigateAndCommit(url);
-  ASSERT_FALSE(controller.NeedsReload());
-
-  // Request a reload to happen when the controller becomes active (e.g. after
-  // the renderer gets killed in background on Android).
-  controller.SetNeedsReload();
-  ASSERT_TRUE(controller.NeedsReload());
-
-  // Set the controller as active, triggering the requested reload.
-  controller.SetActive(true);
-  ASSERT_FALSE(controller.NeedsReload());
-}
-
-// Tests a subframe navigation while a toplevel navigation is pending.
-// http://crbug.com/43967
-TEST_F(NavigationControllerTest, SubframeWhilePending) {
-  NavigationControllerImpl& controller = controller_impl();
-  // Load the first page.
-  const GURL url1("http://foo/");
-  NavigateAndCommit(url1);
-
-  // Now start a pending load to a totally different page, but don't commit it.
-  const GURL url2("http://bar/");
-  controller.LoadURL(
-      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-
-  // Send a subframe update from the first page, as if one had just
-  // automatically loaded. Auto subframes don't increment the page ID.
-  const GURL url1_sub("http://foo/subframe");
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = controller.GetLastCommittedEntry()->GetPageID();
-  params.url = url1_sub;
-  params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(url1_sub);
-  LoadCommittedDetails details;
-
-  // This should return false meaning that nothing was actually updated.
-  EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
-
-  // The notification should have updated the last committed one, and not
-  // the pending load.
-  EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
-
-  // The active entry should be unchanged by the subframe load.
-  EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
-}
-
-// Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
-TEST_F(NavigationControllerTest, CopyStateFrom) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_controller.CopyStateFrom(controller);
-
-  // other_controller should now contain 2 urls.
-  ASSERT_EQ(2, other_controller.GetEntryCount());
-  // We should be looking at the first one.
-  ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
-  // This is a different site than url1, so the IDs start again at 0.
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-
-  // Ensure the SessionStorageNamespaceMaps are the same size and have
-  // the same partitons loaded.
-  //
-  // TODO(ajwong): We should load a url from a different partition earlier
-  // to make sure this map has more than one entry.
-  const SessionStorageNamespaceMap& session_storage_namespace_map =
-      controller.GetSessionStorageNamespaceMap();
-  const SessionStorageNamespaceMap& other_session_storage_namespace_map =
-      other_controller.GetSessionStorageNamespaceMap();
-  EXPECT_EQ(session_storage_namespace_map.size(),
-            other_session_storage_namespace_map.size());
-  for (SessionStorageNamespaceMap::const_iterator it =
-           session_storage_namespace_map.begin();
-       it != session_storage_namespace_map.end();
-       ++it) {
-    SessionStorageNamespaceMap::const_iterator other =
-        other_session_storage_namespace_map.find(it->first);
-    EXPECT_TRUE(other != other_session_storage_namespace_map.end());
-  }
-}
-
-// Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
-TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-
-  // First two entries should have the same SiteInstance.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
-  SiteInstance* instance2 =
-      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
-  EXPECT_EQ(instance1, instance2);
-  EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
-  EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain the 3 urls: url1, url2 and url3.
-
-  ASSERT_EQ(3, other_controller.GetEntryCount());
-
-  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
-
-  // A new SiteInstance should be used for the new tab.
-  SiteInstance* instance3 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
-  EXPECT_NE(instance3, instance1);
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
-}
-
-// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
-// the target.
-TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain: url1, url3
-
-  ASSERT_EQ(2, other_controller.GetEntryCount());
-  ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
-// the target.
-TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-  const GURL url4("http://foo4");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_contents->NavigateAndCommit(url4);
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain: url1, url2, url4
-
-  ASSERT_EQ(3, other_controller.GetEntryCount());
-  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
-// not the last entry selected in the target.
-TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-  const GURL url4("http://foo4");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_contents->NavigateAndCommit(url4);
-  other_controller.GoBack();
-  other_contents->CommitPendingNavigation();
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain: url1, url2, url3
-
-  ASSERT_EQ(3, other_controller.GetEntryCount());
-  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
-// a pending entry in the target.
-TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-  const GURL url4("http://foo4");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_controller.LoadURL(
-      url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain url1, url3, and a pending entry
-  // for url4.
-
-  ASSERT_EQ(2, other_controller.GetEntryCount());
-  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
-
-  // And there should be a pending entry for url4.
-  ASSERT_TRUE(other_controller.GetPendingEntry());
-  EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
-// client redirect entry (with the same page ID) in the target.  This used to
-// crash because the last committed entry would be pruned but max_page_id
-// remembered the page ID (http://crbug.com/234809).
-TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2a("http://foo2/a");
-  const GURL url2b("http://foo2/b");
-
-  NavigateAndCommit(url1);
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url2a);
-  // Simulate a client redirect, which has the same page ID as entry 2a.
-  other_controller.LoadURL(
-      url2b, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  other_controller.GetPendingEntry()->SetPageID(
-      other_controller.GetLastCommittedEntry()->GetPageID());
-
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain url1, url2a, and a pending entry
-  // for url2b.
-
-  ASSERT_EQ(2, other_controller.GetEntryCount());
-  EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL());
-
-  // And there should be a pending entry for url4.
-  ASSERT_TRUE(other_controller.GetPendingEntry());
-  EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
-
-  // Let the pending entry commit.
-  other_contents->CommitPendingNavigation();
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
-// source, and 1 entry in the target. The back pending entry should be ignored.
-TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  controller.GoBack();
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url3);
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // other_controller should now contain: url1, url2, url3
-
-  ASSERT_EQ(3, other_controller.GetEntryCount());
-  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
-
-  // The max page ID map should be copied over and updated with the max page ID
-  // from the current tab.
-  SiteInstance* instance1 =
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
-  EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
-}
-
-// Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
-// when the max entry count is 3.  We should prune one entry.
-TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
-  NavigationControllerImpl& controller = controller_impl();
-  size_t original_count = NavigationControllerImpl::max_entry_count();
-  const int kMaxEntryCount = 3;
-
-  NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
-
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-  const GURL url4("http://foo/4");
-
-  // Create a PrunedListener to observe prune notifications.
-  PrunedListener listener(&controller);
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  NavigateAndCommit(url3);
-
-  scoped_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
-  NavigationControllerImpl& other_controller = other_contents->GetController();
-  other_contents->NavigateAndCommit(url4);
-  other_contents->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
-      other_controller.GetEntryAtIndex(0)->GetPageID());
-  other_controller.CopyStateFromAndPrune(&controller);
-
-  // We should have received a pruned notification.
-  EXPECT_EQ(1, listener.notification_count_);
-  EXPECT_TRUE(listener.details_.from_front);
-  EXPECT_EQ(1, listener.details_.count);
-
-  // other_controller should now contain only 3 urls: url2, url3 and url4.
-
-  ASSERT_EQ(3, other_controller.GetEntryCount());
-
-  ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
-
-  EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
-  EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
-  EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
-  EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
-  EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
-
-  NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
-}
-
-// Tests that navigations initiated from the page (with the history object)
-// work as expected without navigation entries.
-TEST_F(NavigationControllerTest, HistoryNavigate) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  NavigateAndCommit(url3);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  // Simulate the page calling history.back(), it should not create a pending
-  // entry.
-  contents()->OnGoToEntryAtOffset(-1);
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  // The actual cross-navigation is suspended until the current RVH tells us
-  // it unloaded, simulate that.
-  contents()->ProceedWithCrossSiteNavigation();
-  // Also make sure we told the page to navigate.
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
-  ASSERT_TRUE(message != NULL);
-  Tuple1<ViewMsg_Navigate_Params> nav_params;
-  ViewMsg_Navigate::Read(message, &nav_params);
-  EXPECT_EQ(url1, nav_params.a.url);
-  process()->sink().ClearMessages();
-
-  // Now test history.forward()
-  contents()->OnGoToEntryAtOffset(1);
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  // The actual cross-navigation is suspended until the current RVH tells us
-  // it unloaded, simulate that.
-  contents()->ProceedWithCrossSiteNavigation();
-  message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
-  ASSERT_TRUE(message != NULL);
-  ViewMsg_Navigate::Read(message, &nav_params);
-  EXPECT_EQ(url3, nav_params.a.url);
-  process()->sink().ClearMessages();
-
-  // Make sure an extravagant history.go() doesn't break.
-  contents()->OnGoToEntryAtOffset(120);  // Out of bounds.
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
-  EXPECT_TRUE(message == NULL);
-}
-
-// Test call to PruneAllButVisible for the only entry.
-TEST_F(NavigationControllerTest, PruneAllButVisibleForSingle) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo1");
-  NavigateAndCommit(url1);
-
-  contents()->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
-      controller.GetEntryAtIndex(0)->GetPageID());
-
-  controller.PruneAllButVisible();
-
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
-}
-
-// Test call to PruneAllButVisible for first entry.
-TEST_F(NavigationControllerTest, PruneAllButVisibleForFirst) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  NavigateAndCommit(url3);
-  controller.GoBack();
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  contents()->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
-      controller.GetEntryAtIndex(0)->GetPageID());
-
-  controller.PruneAllButVisible();
-
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
-}
-
-// Test call to PruneAllButVisible for intermediate entry.
-TEST_F(NavigationControllerTest, PruneAllButVisibleForIntermediate) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  NavigateAndCommit(url3);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  contents()->ExpectSetHistoryLengthAndPrune(
-      GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
-      controller.GetEntryAtIndex(1)->GetPageID());
-
-  controller.PruneAllButVisible();
-
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
-}
-
-// Test call to PruneAllButVisible for a pending entry that is not yet in the
-// list of entries.
-TEST_F(NavigationControllerTest, PruneAllButVisibleForPendingNotInList) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url1("http://foo/1");
-  const GURL url2("http://foo/2");
-  const GURL url3("http://foo/3");
-
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-
-  // Create a pending entry that is not in the entry list.
-  controller.LoadURL(
-      url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(2, controller.GetEntryCount());
-
-  contents()->ExpectSetHistoryLengthAndPrune(
-      NULL, 0, controller.GetPendingEntry()->GetPageID());
-  controller.PruneAllButVisible();
-
-  // We should only have the last committed and pending entries at this point,
-  // and the pending entry should still not be in the entry list.
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(1, controller.GetEntryCount());
-
-  // Try to commit the pending entry.
-  test_rvh()->SendNavigate(2, url3);
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL());
-}
-
-// Test to ensure that when we do a history navigation back to the current
-// committed page (e.g., going forward to a slow-loading page, then pressing
-// the back button), we just stop the navigation to prevent the throbber from
-// running continuously. Otherwise, the RenderViewHost forces the throbber to
-// start, but WebKit essentially ignores the navigation and never sends a
-// message to stop the throbber.
-TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
-  NavigationControllerImpl& controller = controller_impl();
-  const GURL url0("http://foo/0");
-  const GURL url1("http://foo/1");
-
-  NavigateAndCommit(url0);
-  NavigateAndCommit(url1);
-
-  // Go back to the original page, then forward to the slow page, then back
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-
-  controller.GoForward();
-  EXPECT_EQ(1, controller.GetPendingEntryIndex());
-
-  controller.GoBack();
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-}
-
-TEST_F(NavigationControllerTest, IsInitialNavigation) {
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  // Initial state.
-  EXPECT_TRUE(controller.IsInitialNavigation());
-
-  // After commit, it stays false.
-  const GURL url1("http://foo1");
-  test_rvh()->SendNavigate(0, url1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  EXPECT_FALSE(controller.IsInitialNavigation());
-
-  // After starting a new navigation, it stays false.
-  const GURL url2("http://foo2");
-  controller.LoadURL(
-      url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-}
-
-// Check that the favicon is not reused across a client redirect.
-// (crbug.com/28515)
-TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
-  const GURL kPageWithFavicon("http://withfavicon.html");
-  const GURL kPageWithoutFavicon("http://withoutfavicon.html");
-  const GURL kIconURL("http://withfavicon.ico");
-  const gfx::Image kDefaultFavicon = FaviconStatus().image;
-
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  test_rvh()->SendNavigate(0, kPageWithFavicon);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  NavigationEntry* entry = controller.GetLastCommittedEntry();
-  EXPECT_TRUE(entry);
-  EXPECT_EQ(kPageWithFavicon, entry->GetURL());
-
-  // Simulate Chromium having set the favicon for |kPageWithFavicon|.
-  content::FaviconStatus& favicon_status = entry->GetFavicon();
-  favicon_status.image = CreateImage(SK_ColorWHITE);
-  favicon_status.url = kIconURL;
-  favicon_status.valid = true;
-  EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
-
-  test_rvh()->SendNavigateWithTransition(
-      0,  // same page ID.
-      kPageWithoutFavicon,
-      PAGE_TRANSITION_CLIENT_REDIRECT);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  entry = controller.GetLastCommittedEntry();
-  EXPECT_TRUE(entry);
-  EXPECT_EQ(kPageWithoutFavicon, entry->GetURL());
-
-  EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
-}
-
-// Check that the favicon is not cleared for NavigationEntries which were
-// previously navigated to.
-TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
-  const GURL kUrl1("http://www.a.com/1");
-  const GURL kUrl2("http://www.a.com/2");
-  const GURL kIconURL("http://www.a.com/1/favicon.ico");
-
-  NavigationControllerImpl& controller = controller_impl();
-  TestNotificationTracker notifications;
-  RegisterForAllNavNotifications(&notifications, &controller);
-
-  test_rvh()->SendNavigate(0, kUrl1);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Simulate Chromium having set the favicon for |kUrl1|.
-  gfx::Image favicon_image = CreateImage(SK_ColorWHITE);
-  content::NavigationEntry* entry = controller.GetLastCommittedEntry();
-  EXPECT_TRUE(entry);
-  content::FaviconStatus& favicon_status = entry->GetFavicon();
-  favicon_status.image = favicon_image;
-  favicon_status.url = kIconURL;
-  favicon_status.valid = true;
-
-  // Navigate to another page and go back to the original page.
-  test_rvh()->SendNavigate(1, kUrl2);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-  test_rvh()->SendNavigateWithTransition(
-      0,
-      kUrl1,
-      PAGE_TRANSITION_FORWARD_BACK);
-  EXPECT_EQ(1U, navigation_entry_committed_counter_);
-  navigation_entry_committed_counter_ = 0;
-
-  // Verify that the favicon for the page at |kUrl1| was not cleared.
-  entry = controller.GetEntryAtIndex(0);
-  EXPECT_TRUE(entry);
-  EXPECT_EQ(kUrl1, entry->GetURL());
-  EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
-}
-
-// The test crashes on android: http://crbug.com/170449
-#if defined(OS_ANDROID)
-#define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
-#else
-#define MAYBE_PurgeScreenshot PurgeScreenshot
-#endif
-// Tests that screenshot are purged correctly.
-TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
-  NavigationControllerImpl& controller = controller_impl();
-
-  NavigationEntryImpl* entry;
-
-  // Navigate enough times to make sure that some screenshots are purged.
-  for (int i = 0; i < 12; ++i) {
-    const GURL url(base::StringPrintf("http://foo%d/", i));
-    NavigateAndCommit(url);
-    EXPECT_EQ(i, controller.GetCurrentEntryIndex());
-  }
-
-  MockScreenshotManager* screenshot_manager =
-      new MockScreenshotManager(&controller);
-  controller.SetScreenshotManager(screenshot_manager);
-  for (int i = 0; i < controller.GetEntryCount(); ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    screenshot_manager->TakeScreenshotFor(entry);
-    EXPECT_TRUE(entry->screenshot().get());
-  }
-
-  NavigateAndCommit(GURL("https://foo/"));
-  EXPECT_EQ(13, controller.GetEntryCount());
-  entry = NavigationEntryImpl::FromNavigationEntry(
-      controller.GetEntryAtIndex(11));
-  screenshot_manager->TakeScreenshotFor(entry);
-
-  for (int i = 0; i < 2; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-  }
-
-  for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
-  }
-
-  // Navigate to index 5 and then try to assign screenshot to all entries.
-  controller.GoToIndex(5);
-  contents()->CommitPendingNavigation();
-  EXPECT_EQ(5, controller.GetCurrentEntryIndex());
-  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  for (int i = 10; i <= 12; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  // Navigate to index 7 and assign screenshot to all entries.
-  controller.GoToIndex(7);
-  contents()->CommitPendingNavigation();
-  EXPECT_EQ(7, controller.GetCurrentEntryIndex());
-  for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    screenshot_manager->TakeScreenshotFor(entry);
-  }
-
-  for (int i = 0; i < 2; ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not purged";
-  }
-
-  // Clear all screenshots.
-  EXPECT_EQ(13, controller.GetEntryCount());
-  EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
-  controller.ClearAllScreenshots();
-  EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
-  for (int i = 0; i < controller.GetEntryCount(); ++i) {
-    entry = NavigationEntryImpl::FromNavigationEntry(
-        controller.GetEntryAtIndex(i));
-    EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
-                                            << " not cleared";
-  }
-}
-
-// Test that the navigation controller clears its session history when a
-// navigation commits with the clear history list flag set.
-TEST_F(NavigationControllerTest, ClearHistoryList) {
-  const GURL url1("http://foo1");
-  const GURL url2("http://foo2");
-  const GURL url3("http://foo3");
-  const GURL url4("http://foo4");
-
-  NavigationControllerImpl& controller = controller_impl();
-
-  // Create a session history with three entries, second entry is active.
-  NavigateAndCommit(url1);
-  NavigateAndCommit(url2);
-  NavigateAndCommit(url3);
-  controller.GoBack();
-  contents()->CommitPendingNavigation();
-  EXPECT_EQ(3, controller.GetEntryCount());
-  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
-
-  // Create a new pending navigation, and indicate that the session history
-  // should be cleared.
-  NavigationController::LoadURLParams params(url4);
-  params.should_clear_history_list = true;
-  controller.LoadURLWithParams(params);
-
-  // Verify that the pending entry correctly indicates that the session history
-  // should be cleared.
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(
-          controller.GetPendingEntry());
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->should_clear_history_list());
-
-  // Assume that the RV correctly cleared its history and commit the navigation.
-  static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())->
-      set_simulate_history_list_was_cleared(true);
-  contents()->CommitPendingNavigation();
-
-  // Verify that the NavigationController's session history was correctly
-  // cleared.
-  EXPECT_EQ(1, controller.GetEntryCount());
-  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
-  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(-1, controller.GetPendingEntryIndex());
-  EXPECT_FALSE(controller.CanGoBack());
-  EXPECT_FALSE(controller.CanGoForward());
-  EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/navigation_entry_impl.cc b/content/browser/web_contents/navigation_entry_impl.cc
deleted file mode 100644
index 10d50ca..0000000
--- a/content/browser/web_contents/navigation_entry_impl.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2012 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/web_contents/navigation_entry_impl.h"
-
-#include "base/metrics/histogram.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/net_util.h"
-#include "ui/gfx/text_elider.h"
-
-// Use this to get a new unique ID for a NavigationEntry during construction.
-// The returned ID is guaranteed to be nonzero (which is the "no ID" indicator).
-static int GetUniqueIDInConstructor() {
-  static int unique_id_counter = 0;
-  return ++unique_id_counter;
-}
-
-namespace content {
-
-int NavigationEntryImpl::kInvalidBindings = -1;
-
-NavigationEntry* NavigationEntry::Create() {
-  return new NavigationEntryImpl();
-}
-
-NavigationEntry* NavigationEntry::Create(const NavigationEntry& copy) {
-  return new NavigationEntryImpl(static_cast<const NavigationEntryImpl&>(copy));
-}
-
-NavigationEntryImpl* NavigationEntryImpl::FromNavigationEntry(
-    NavigationEntry* entry) {
-  return static_cast<NavigationEntryImpl*>(entry);
-}
-
-NavigationEntryImpl::NavigationEntryImpl()
-    : unique_id_(GetUniqueIDInConstructor()),
-      site_instance_(NULL),
-      bindings_(kInvalidBindings),
-      page_type_(PAGE_TYPE_NORMAL),
-      update_virtual_url_with_url_(false),
-      page_id_(-1),
-      transition_type_(PAGE_TRANSITION_LINK),
-      has_post_data_(false),
-      post_id_(-1),
-      restore_type_(RESTORE_NONE),
-      is_overriding_user_agent_(false),
-      http_status_code_(0),
-      is_renderer_initiated_(false),
-      should_replace_entry_(false),
-      should_clear_history_list_(false),
-      can_load_local_resources_(false) {
-}
-
-NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
-                                         int page_id,
-                                         const GURL& url,
-                                         const Referrer& referrer,
-                                         const string16& title,
-                                         PageTransition transition_type,
-                                         bool is_renderer_initiated)
-    : unique_id_(GetUniqueIDInConstructor()),
-      site_instance_(instance),
-      bindings_(kInvalidBindings),
-      page_type_(PAGE_TYPE_NORMAL),
-      url_(url),
-      referrer_(referrer),
-      update_virtual_url_with_url_(false),
-      title_(title),
-      page_id_(page_id),
-      transition_type_(transition_type),
-      has_post_data_(false),
-      post_id_(-1),
-      restore_type_(RESTORE_NONE),
-      is_overriding_user_agent_(false),
-      http_status_code_(0),
-      is_renderer_initiated_(is_renderer_initiated),
-      should_replace_entry_(false),
-      should_clear_history_list_(false),
-      can_load_local_resources_(false) {
-}
-
-NavigationEntryImpl::~NavigationEntryImpl() {
-}
-
-int NavigationEntryImpl::GetUniqueID() const {
-  return unique_id_;
-}
-
-PageType NavigationEntryImpl::GetPageType() const {
-  return page_type_;
-}
-
-void NavigationEntryImpl::SetURL(const GURL& url) {
-  url_ = url;
-  cached_display_title_.clear();
-}
-
-const GURL& NavigationEntryImpl::GetURL() const {
-  return url_;
-}
-
-void NavigationEntryImpl::SetBaseURLForDataURL(const GURL& url) {
-  base_url_for_data_url_ = url;
-}
-
-const GURL& NavigationEntryImpl::GetBaseURLForDataURL() const {
-  return base_url_for_data_url_;
-}
-
-void NavigationEntryImpl::SetReferrer(const Referrer& referrer) {
-  referrer_ = referrer;
-}
-
-const Referrer& NavigationEntryImpl::GetReferrer() const {
-  return referrer_;
-}
-
-void NavigationEntryImpl::SetVirtualURL(const GURL& url) {
-  virtual_url_ = (url == url_) ? GURL() : url;
-  cached_display_title_.clear();
-}
-
-const GURL& NavigationEntryImpl::GetVirtualURL() const {
-  return virtual_url_.is_empty() ? url_ : virtual_url_;
-}
-
-void NavigationEntryImpl::SetTitle(const string16& title) {
-  title_ = title;
-  cached_display_title_.clear();
-}
-
-const string16& NavigationEntryImpl::GetTitle() const {
-  return title_;
-}
-
-void NavigationEntryImpl::SetPageState(const PageState& state) {
-  page_state_ = state;
-}
-
-const PageState& NavigationEntryImpl::GetPageState() const {
-  return page_state_;
-}
-
-void NavigationEntryImpl::SetPageID(int page_id) {
-  page_id_ = page_id;
-}
-
-int32 NavigationEntryImpl::GetPageID() const {
-  return page_id_;
-}
-
-void NavigationEntryImpl::set_site_instance(SiteInstanceImpl* site_instance) {
-  site_instance_ = site_instance;
-}
-
-void NavigationEntryImpl::SetBindings(int bindings) {
-  // Ensure this is set to a valid value, and that it stays the same once set.
-  CHECK_NE(bindings, kInvalidBindings);
-  CHECK(bindings_ == kInvalidBindings || bindings_ == bindings);
-  bindings_ = bindings;
-}
-
-const string16& NavigationEntryImpl::GetTitleForDisplay(
-    const std::string& languages) const {
-  // Most pages have real titles. Don't even bother caching anything if this is
-  // the case.
-  if (!title_.empty())
-    return title_;
-
-  // More complicated cases will use the URLs as the title. This result we will
-  // cache since it's more complicated to compute.
-  if (!cached_display_title_.empty())
-    return cached_display_title_;
-
-  // Use the virtual URL first if any, and fall back on using the real URL.
-  string16 title;
-  if (!virtual_url_.is_empty()) {
-    title = net::FormatUrl(virtual_url_, languages);
-  } else if (!url_.is_empty()) {
-    title = net::FormatUrl(url_, languages);
-  }
-
-  // For file:// URLs use the filename as the title, not the full path.
-  if (url_.SchemeIsFile()) {
-    string16::size_type slashpos = title.rfind('/');
-    if (slashpos != string16::npos)
-      title = title.substr(slashpos + 1);
-  }
-
-  gfx::ElideString(title, kMaxTitleChars, &cached_display_title_);
-  return cached_display_title_;
-}
-
-bool NavigationEntryImpl::IsViewSourceMode() const {
-  return virtual_url_.SchemeIs(kViewSourceScheme);
-}
-
-void NavigationEntryImpl::SetTransitionType(
-    PageTransition transition_type) {
-  transition_type_ = transition_type;
-}
-
-PageTransition NavigationEntryImpl::GetTransitionType() const {
-  return transition_type_;
-}
-
-const GURL& NavigationEntryImpl::GetUserTypedURL() const {
-  return user_typed_url_;
-}
-
-void NavigationEntryImpl::SetHasPostData(bool has_post_data) {
-  has_post_data_ = has_post_data;
-}
-
-bool NavigationEntryImpl::GetHasPostData() const {
-  return has_post_data_;
-}
-
-void NavigationEntryImpl::SetPostID(int64 post_id) {
-  post_id_ = post_id;
-}
-
-int64 NavigationEntryImpl::GetPostID() const {
-  return post_id_;
-}
-
-void NavigationEntryImpl::SetBrowserInitiatedPostData(
-    const base::RefCountedMemory* data) {
-  browser_initiated_post_data_ = data;
-}
-
-const base::RefCountedMemory*
-NavigationEntryImpl::GetBrowserInitiatedPostData() const {
-  return browser_initiated_post_data_.get();
-}
-
-
-const FaviconStatus& NavigationEntryImpl::GetFavicon() const {
-  return favicon_;
-}
-
-FaviconStatus& NavigationEntryImpl::GetFavicon() {
-  return favicon_;
-}
-
-const SSLStatus& NavigationEntryImpl::GetSSL() const {
-  return ssl_;
-}
-
-SSLStatus& NavigationEntryImpl::GetSSL() {
-  return ssl_;
-}
-
-void NavigationEntryImpl::SetOriginalRequestURL(const GURL& original_url) {
-  original_request_url_ = original_url;
-}
-
-const GURL& NavigationEntryImpl::GetOriginalRequestURL() const {
-  return original_request_url_;
-}
-
-void NavigationEntryImpl::SetIsOverridingUserAgent(bool override) {
-  is_overriding_user_agent_ = override;
-}
-
-bool NavigationEntryImpl::GetIsOverridingUserAgent() const {
-  return is_overriding_user_agent_;
-}
-
-void NavigationEntryImpl::SetTimestamp(base::Time timestamp) {
-  timestamp_ = timestamp;
-}
-
-base::Time NavigationEntryImpl::GetTimestamp() const {
-  return timestamp_;
-}
-
-void NavigationEntryImpl::SetHttpStatusCode(int http_status_code) {
-  http_status_code_ = http_status_code;
-}
-
-int NavigationEntryImpl::GetHttpStatusCode() const {
-  return http_status_code_;
-}
-
-void NavigationEntryImpl::SetCanLoadLocalResources(bool allow) {
-  can_load_local_resources_ = allow;
-}
-
-bool NavigationEntryImpl::GetCanLoadLocalResources() const {
-  return can_load_local_resources_;
-}
-
-void NavigationEntryImpl::SetFrameToNavigate(const std::string& frame_name) {
-  frame_to_navigate_ = frame_name;
-}
-
-const std::string& NavigationEntryImpl::GetFrameToNavigate() const {
-  return frame_to_navigate_;
-}
-
-void NavigationEntryImpl::SetExtraData(const std::string& key,
-                                       const string16& data) {
-  extra_data_[key] = data;
-}
-
-bool NavigationEntryImpl::GetExtraData(const std::string& key,
-                                       string16* data) const {
-  std::map<std::string, string16>::const_iterator iter = extra_data_.find(key);
-  if (iter == extra_data_.end())
-    return false;
-  *data = iter->second;
-  return true;
-}
-
-void NavigationEntryImpl::ClearExtraData(const std::string& key) {
-  extra_data_.erase(key);
-}
-
-void NavigationEntryImpl::SetScreenshotPNGData(
-    scoped_refptr<base::RefCountedBytes> png_data) {
-  screenshot_ = png_data;
-  if (screenshot_.get())
-    UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size());
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/navigation_entry_impl.h b/content/browser/web_contents/navigation_entry_impl.h
deleted file mode 100644
index 63924b8..0000000
--- a/content/browser/web_contents/navigation_entry_impl.h
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_WEB_CONTENTS_NAVIGATION_ENTRY_IMPL_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_NAVIGATION_ENTRY_IMPL_H_
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/global_request_id.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/common/page_state.h"
-#include "content/public/common/ssl_status.h"
-
-namespace content {
-
-class CONTENT_EXPORT NavigationEntryImpl
-    : public NON_EXPORTED_BASE(NavigationEntry) {
- public:
-  static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry);
-
-  // The value of bindings() before it is set during commit.
-  static int kInvalidBindings;
-
-  NavigationEntryImpl();
-  NavigationEntryImpl(SiteInstanceImpl* instance,
-                      int page_id,
-                      const GURL& url,
-                      const Referrer& referrer,
-                      const string16& title,
-                      PageTransition transition_type,
-                      bool is_renderer_initiated);
-  virtual ~NavigationEntryImpl();
-
-  // NavigationEntry implementation:
-  virtual int GetUniqueID() const OVERRIDE;
-  virtual PageType GetPageType() const OVERRIDE;
-  virtual void SetURL(const GURL& url) OVERRIDE;
-  virtual const GURL& GetURL() const OVERRIDE;
-  virtual void SetBaseURLForDataURL(const GURL& url) OVERRIDE;
-  virtual const GURL& GetBaseURLForDataURL() const OVERRIDE;
-  virtual void SetReferrer(const Referrer& referrer) OVERRIDE;
-  virtual const Referrer& GetReferrer() const OVERRIDE;
-  virtual void SetVirtualURL(const GURL& url) OVERRIDE;
-  virtual const GURL& GetVirtualURL() const OVERRIDE;
-  virtual void SetTitle(const string16& title) OVERRIDE;
-  virtual const string16& GetTitle() const OVERRIDE;
-  virtual void SetPageState(const PageState& state) OVERRIDE;
-  virtual const PageState& GetPageState() const OVERRIDE;
-  virtual void SetPageID(int page_id) OVERRIDE;
-  virtual int32 GetPageID() const OVERRIDE;
-  virtual const string16& GetTitleForDisplay(
-      const std::string& languages) const OVERRIDE;
-  virtual bool IsViewSourceMode() const OVERRIDE;
-  virtual void SetTransitionType(PageTransition transition_type) OVERRIDE;
-  virtual PageTransition GetTransitionType() const OVERRIDE;
-  virtual const GURL& GetUserTypedURL() const OVERRIDE;
-  virtual void SetHasPostData(bool has_post_data) OVERRIDE;
-  virtual bool GetHasPostData() const OVERRIDE;
-  virtual void SetPostID(int64 post_id) OVERRIDE;
-  virtual int64 GetPostID() const OVERRIDE;
-  virtual void SetBrowserInitiatedPostData(
-      const base::RefCountedMemory* data) OVERRIDE;
-  virtual const base::RefCountedMemory*
-      GetBrowserInitiatedPostData() const OVERRIDE;
-  virtual const FaviconStatus& GetFavicon() const OVERRIDE;
-  virtual FaviconStatus& GetFavicon() OVERRIDE;
-  virtual const SSLStatus& GetSSL() const OVERRIDE;
-  virtual SSLStatus& GetSSL() OVERRIDE;
-  virtual void SetOriginalRequestURL(const GURL& original_url) OVERRIDE;
-  virtual const GURL& GetOriginalRequestURL() const OVERRIDE;
-  virtual void SetIsOverridingUserAgent(bool override) OVERRIDE;
-  virtual bool GetIsOverridingUserAgent() const OVERRIDE;
-  virtual void SetTimestamp(base::Time timestamp) OVERRIDE;
-  virtual base::Time GetTimestamp() const OVERRIDE;
-  virtual void SetCanLoadLocalResources(bool allow) OVERRIDE;
-  virtual bool GetCanLoadLocalResources() const OVERRIDE;
-  virtual void SetFrameToNavigate(const std::string& frame_name) OVERRIDE;
-  virtual const std::string& GetFrameToNavigate() const OVERRIDE;
-  virtual void SetExtraData(const std::string& key,
-                            const string16& data) OVERRIDE;
-  virtual bool GetExtraData(const std::string& key,
-                            string16* data) const OVERRIDE;
-  virtual void ClearExtraData(const std::string& key) OVERRIDE;
-  virtual void SetHttpStatusCode(int http_status_code) OVERRIDE;
-  virtual int GetHttpStatusCode() const OVERRIDE;
-
-  void set_unique_id(int unique_id) {
-    unique_id_ = unique_id;
-  }
-
-  // The SiteInstance tells us how to share sub-processes. This is a reference
-  // counted pointer to a shared site instance.
-  //
-  // Note that the SiteInstance should usually not be changed after it is set,
-  // but this may happen if the NavigationEntry was cloned and needs to use a
-  // different SiteInstance.
-  void set_site_instance(SiteInstanceImpl* site_instance);
-  SiteInstanceImpl* site_instance() const {
-    return site_instance_.get();
-  }
-
-  // Remember the set of bindings granted to this NavigationEntry at the time
-  // of commit, to ensure that we do not grant it additional bindings if we
-  // navigate back to it in the future.  This can only be changed once.
-  void SetBindings(int bindings);
-  int bindings() const {
-    return bindings_;
-  }
-
-  void set_page_type(PageType page_type) {
-    page_type_ = page_type;
-  }
-
-  bool has_virtual_url() const {
-    return !virtual_url_.is_empty();
-  }
-
-  bool update_virtual_url_with_url() const {
-    return update_virtual_url_with_url_;
-  }
-  void set_update_virtual_url_with_url(bool update) {
-    update_virtual_url_with_url_ = update;
-  }
-
-  // Extra headers (separated by \n) to send during the request.
-  void set_extra_headers(const std::string& extra_headers) {
-    extra_headers_ = extra_headers;
-  }
-  const std::string& extra_headers() const {
-    return extra_headers_;
-  }
-
-  // Whether this (pending) navigation is renderer-initiated.  Resets to false
-  // for all types of navigations after commit.
-  void set_is_renderer_initiated(bool is_renderer_initiated) {
-    is_renderer_initiated_ = is_renderer_initiated;
-  }
-  bool is_renderer_initiated() const {
-    return is_renderer_initiated_;
-  }
-
-  void set_user_typed_url(const GURL& user_typed_url) {
-    user_typed_url_ = user_typed_url;
-  }
-
-  // Enumerations of the possible restore types.
-  enum RestoreType {
-    // Restore from the previous session.
-    RESTORE_LAST_SESSION_EXITED_CLEANLY,
-    RESTORE_LAST_SESSION_CRASHED,
-
-    // The entry has been restored from the current session. This is used when
-    // the user issues 'reopen closed tab'.
-    RESTORE_CURRENT_SESSION,
-
-    // The entry was not restored.
-    RESTORE_NONE
-  };
-
-  // The RestoreType for this entry. This is set if the entry was retored. This
-  // is set to RESTORE_NONE once the entry is loaded.
-  void set_restore_type(RestoreType type) {
-    restore_type_ = type;
-  }
-  RestoreType restore_type() const {
-    return restore_type_;
-  }
-
-  void set_transferred_global_request_id(
-      const GlobalRequestID& transferred_global_request_id) {
-    transferred_global_request_id_ = transferred_global_request_id;
-  }
-
-  GlobalRequestID transferred_global_request_id() const {
-    return transferred_global_request_id_;
-  }
-
-  // Whether this (pending) navigation needs to replace current entry.
-  // Resets to false after commit.
-  bool should_replace_entry() const {
-    return should_replace_entry_;
-  }
-
-  void set_should_replace_entry(bool should_replace_entry) {
-    should_replace_entry_ = should_replace_entry;
-  }
-
-  void SetScreenshotPNGData(scoped_refptr<base::RefCountedBytes> png_data);
-  const scoped_refptr<base::RefCountedBytes> screenshot() const {
-    return screenshot_;
-  }
-
-  // Whether this (pending) navigation should clear the session history. Resets
-  // to false after commit.
-  bool should_clear_history_list() const {
-    return should_clear_history_list_;
-  }
-  void set_should_clear_history_list(bool should_clear_history_list) {
-    should_clear_history_list_ = should_clear_history_list;
-  }
-
- private:
-  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-  // Session/Tab restore save portions of this class so that it can be recreated
-  // later. If you add a new field that needs to be persisted you'll have to
-  // update SessionService/TabRestoreService and Android WebView
-  // state_serializer.cc appropriately.
-  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-
-  // See the accessors above for descriptions.
-  int unique_id_;
-  scoped_refptr<SiteInstanceImpl> site_instance_;
-  // TODO(creis): Persist bindings_. http://crbug.com/173672.
-  int bindings_;
-  PageType page_type_;
-  GURL url_;
-  Referrer referrer_;
-  GURL virtual_url_;
-  bool update_virtual_url_with_url_;
-  string16 title_;
-  FaviconStatus favicon_;
-  PageState page_state_;
-  int32 page_id_;
-  SSLStatus ssl_;
-  PageTransition transition_type_;
-  GURL user_typed_url_;
-  bool has_post_data_;
-  int64 post_id_;
-  RestoreType restore_type_;
-  GURL original_request_url_;
-  bool is_overriding_user_agent_;
-  base::Time timestamp_;
-  int http_status_code_;
-
-  // This member is not persisted with session restore because it is transient.
-  // If the post request succeeds, this field is cleared since the same
-  // information is stored in |content_state_| above. It is also only shallow
-  // copied with compiler provided copy constructor.
-  scoped_refptr<const base::RefCountedMemory> browser_initiated_post_data_;
-
-  // This is also a transient member (i.e. is not persisted with session
-  // restore). The screenshot of a page is taken when navigating away from the
-  // page. This screenshot is displayed during an overscroll-navigation
-  // gesture. |screenshot_| will be NULL when the screenshot is not available
-  // (e.g. after a session restore, or if taking the screenshot of a page
-  // failed). The UI is responsible for dealing with missing screenshots
-  // appropriately (e.g. display a placeholder image instead).
-  scoped_refptr<base::RefCountedBytes> screenshot_;
-
-  // This member is not persisted with session restore.
-  std::string extra_headers_;
-
-  // Used for specifying base URL for pages loaded via data URLs. Only used and
-  // persisted by Android WebView.
-  GURL base_url_for_data_url_;
-
-  // Whether the entry, while loading, was created for a renderer-initiated
-  // navigation.  This dictates whether the URL should be displayed before the
-  // navigation commits.  It is cleared on commit and not persisted.
-  bool is_renderer_initiated_;
-
-  // This is a cached version of the result of GetTitleForDisplay. It prevents
-  // us from having to do URL formatting on the URL every time the title is
-  // displayed. When the URL, virtual URL, or title is set, this should be
-  // cleared to force a refresh.
-  mutable string16 cached_display_title_;
-
-  // In case a navigation is transferred to a new RVH but the request has
-  // been generated in the renderer already, this identifies the old request so
-  // that it can be resumed. The old request is stored until the
-  // ResourceDispatcher receives the navigation from the renderer which
-  // carries this |transferred_global_request_id_| annotation. Once the request
-  // is transferred to the new process, this is cleared and the request
-  // continues as normal.
-  GlobalRequestID transferred_global_request_id_;
-
-  // This is set to true when this entry is being reloaded and due to changes in
-  // the state of the URL, it has to be reloaded in a different site instance.
-  // In such case, we must treat it as an existing navigation in the new site
-  // instance, instead of a new navigation. This value should not be persisted
-  // and is not needed after the entry commits.
-  //
-  // We also use this flag for cross-process redirect navigations, so that the
-  // browser will replace the current navigation entry (which is the page
-  // doing the redirect).
-  bool should_replace_entry_;
-
-  // This is set to true when this entry's navigation should clear the session
-  // history both on the renderer and browser side. The browser side history
-  // won't be cleared until the renderer has committed this navigation. This
-  // entry is not persisted by the session restore system, as it is always
-  // reset to false after commit.
-  bool should_clear_history_list_;
-
-  // Set when this entry should be able to access local file:// resources. This
-  // value is not needed after the entry commits and is not persisted.
-  bool can_load_local_resources_;
-
-  // If not empty, the name of the frame to navigate. This field is not
-  // persisted, because it is currently only used in tests.
-  std::string frame_to_navigate_;
-
-  // Used to store extra data to support browser features. This member is not
-  // persisted, unless specific data is taken out/put back in at save/restore
-  // time (see TabNavigation for an example of this).
-  std::map<std::string, string16> extra_data_;
-
-  // Copy and assignment is explicitly allowed for this class.
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_NAVIGATION_ENTRY_IMPL_H_
diff --git a/content/browser/web_contents/navigation_entry_impl_unittest.cc b/content/browser/web_contents/navigation_entry_impl_unittest.cc
deleted file mode 100644
index 138ed74..0000000
--- a/content/browser/web_contents/navigation_entry_impl_unittest.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/public/common/ssl_status.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class NavigationEntryTest : public testing::Test {
- public:
-  NavigationEntryTest() : instance_(NULL) {
-  }
-
-  virtual void SetUp() {
-    entry1_.reset(new NavigationEntryImpl);
-
-#if !defined(OS_IOS)
-    instance_ = static_cast<SiteInstanceImpl*>(SiteInstance::Create(NULL));
-#endif
-    entry2_.reset(new NavigationEntryImpl(
-          instance_, 3,
-          GURL("test:url"),
-          Referrer(GURL("from"), WebKit::WebReferrerPolicyDefault),
-          ASCIIToUTF16("title"),
-          PAGE_TRANSITION_TYPED,
-          false));
-  }
-
-  virtual void TearDown() {
-  }
-
- protected:
-  scoped_ptr<NavigationEntryImpl> entry1_;
-  scoped_ptr<NavigationEntryImpl> entry2_;
-  // SiteInstances are deleted when their NavigationEntries are gone.
-  SiteInstanceImpl* instance_;
-};
-
-// Test unique ID accessors
-TEST_F(NavigationEntryTest, NavigationEntryUniqueIDs) {
-  // Two entries should have different IDs by default
-  EXPECT_NE(entry1_->GetUniqueID(), entry2_->GetUniqueID());
-
-  // Can set an entry to have the same ID as another
-  entry2_->set_unique_id(entry1_->GetUniqueID());
-  EXPECT_EQ(entry1_->GetUniqueID(), entry2_->GetUniqueID());
-}
-
-// Test URL accessors
-TEST_F(NavigationEntryTest, NavigationEntryURLs) {
-  // Start with no virtual_url (even if a url is set)
-  EXPECT_FALSE(entry1_->has_virtual_url());
-  EXPECT_FALSE(entry2_->has_virtual_url());
-
-  EXPECT_EQ(GURL(), entry1_->GetURL());
-  EXPECT_EQ(GURL(), entry1_->GetVirtualURL());
-  EXPECT_TRUE(entry1_->GetTitleForDisplay(std::string()).empty());
-
-  // Setting URL affects virtual_url and GetTitleForDisplay
-  entry1_->SetURL(GURL("http://www.google.com"));
-  EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetURL());
-  EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetVirtualURL());
-  EXPECT_EQ(ASCIIToUTF16("www.google.com"),
-            entry1_->GetTitleForDisplay(std::string()));
-
-  // file:/// URLs should only show the filename.
-  entry1_->SetURL(GURL("file:///foo/bar baz.txt"));
-  EXPECT_EQ(ASCIIToUTF16("bar baz.txt"),
-            entry1_->GetTitleForDisplay(std::string()));
-
-  // Title affects GetTitleForDisplay
-  entry1_->SetTitle(ASCIIToUTF16("Google"));
-  EXPECT_EQ(ASCIIToUTF16("Google"), entry1_->GetTitleForDisplay(std::string()));
-
-  // Setting virtual_url doesn't affect URL
-  entry2_->SetVirtualURL(GURL("display:url"));
-  EXPECT_TRUE(entry2_->has_virtual_url());
-  EXPECT_EQ(GURL("test:url"), entry2_->GetURL());
-  EXPECT_EQ(GURL("display:url"), entry2_->GetVirtualURL());
-
-  // Having a title set in constructor overrides virtual URL
-  EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitleForDisplay(std::string()));
-
-  // User typed URL is independent of the others
-  EXPECT_EQ(GURL(), entry1_->GetUserTypedURL());
-  EXPECT_EQ(GURL(), entry2_->GetUserTypedURL());
-  entry2_->set_user_typed_url(GURL("typedurl"));
-  EXPECT_EQ(GURL("typedurl"), entry2_->GetUserTypedURL());
-}
-
-// Test Favicon inner class construction.
-TEST_F(NavigationEntryTest, NavigationEntryFavicons) {
-  EXPECT_EQ(GURL(), entry1_->GetFavicon().url);
-  EXPECT_FALSE(entry1_->GetFavicon().valid);
-}
-
-// Test SSLStatus inner class
-TEST_F(NavigationEntryTest, NavigationEntrySSLStatus) {
-  // Default (unknown)
-  EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry1_->GetSSL().security_style);
-  EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry2_->GetSSL().security_style);
-  EXPECT_EQ(0, entry1_->GetSSL().cert_id);
-  EXPECT_EQ(0U, entry1_->GetSSL().cert_status);
-  EXPECT_EQ(-1, entry1_->GetSSL().security_bits);
-  int content_status = entry1_->GetSSL().content_status;
-  EXPECT_FALSE(!!(content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT));
-  EXPECT_FALSE(!!(content_status & SSLStatus::RAN_INSECURE_CONTENT));
-}
-
-// Test other basic accessors
-TEST_F(NavigationEntryTest, NavigationEntryAccessors) {
-  // SiteInstance
-  EXPECT_TRUE(entry1_->site_instance() == NULL);
-  EXPECT_EQ(instance_, entry2_->site_instance());
-  entry1_->set_site_instance(instance_);
-  EXPECT_EQ(instance_, entry1_->site_instance());
-
-  // Page type
-  EXPECT_EQ(PAGE_TYPE_NORMAL, entry1_->GetPageType());
-  EXPECT_EQ(PAGE_TYPE_NORMAL, entry2_->GetPageType());
-  entry2_->set_page_type(PAGE_TYPE_INTERSTITIAL);
-  EXPECT_EQ(PAGE_TYPE_INTERSTITIAL, entry2_->GetPageType());
-
-  // Referrer
-  EXPECT_EQ(GURL(), entry1_->GetReferrer().url);
-  EXPECT_EQ(GURL("from"), entry2_->GetReferrer().url);
-  entry2_->SetReferrer(
-      Referrer(GURL("from2"), WebKit::WebReferrerPolicyDefault));
-  EXPECT_EQ(GURL("from2"), entry2_->GetReferrer().url);
-
-  // Title
-  EXPECT_EQ(string16(), entry1_->GetTitle());
-  EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitle());
-  entry2_->SetTitle(ASCIIToUTF16("title2"));
-  EXPECT_EQ(ASCIIToUTF16("title2"), entry2_->GetTitle());
-
-  // State
-  EXPECT_FALSE(entry1_->GetPageState().IsValid());
-  EXPECT_FALSE(entry2_->GetPageState().IsValid());
-  entry2_->SetPageState(PageState::CreateFromEncodedData("state"));
-  EXPECT_EQ("state", entry2_->GetPageState().ToEncodedData());
-
-  // Page ID
-  EXPECT_EQ(-1, entry1_->GetPageID());
-  EXPECT_EQ(3, entry2_->GetPageID());
-  entry2_->SetPageID(2);
-  EXPECT_EQ(2, entry2_->GetPageID());
-
-  // Transition type
-  EXPECT_EQ(PAGE_TRANSITION_LINK, entry1_->GetTransitionType());
-  EXPECT_EQ(PAGE_TRANSITION_TYPED, entry2_->GetTransitionType());
-  entry2_->SetTransitionType(PAGE_TRANSITION_RELOAD);
-  EXPECT_EQ(PAGE_TRANSITION_RELOAD, entry2_->GetTransitionType());
-
-  // Is renderer initiated
-  EXPECT_FALSE(entry1_->is_renderer_initiated());
-  EXPECT_FALSE(entry2_->is_renderer_initiated());
-  entry2_->set_is_renderer_initiated(true);
-  EXPECT_TRUE(entry2_->is_renderer_initiated());
-
-  // Post Data
-  EXPECT_FALSE(entry1_->GetHasPostData());
-  EXPECT_FALSE(entry2_->GetHasPostData());
-  entry2_->SetHasPostData(true);
-  EXPECT_TRUE(entry2_->GetHasPostData());
-
-  // Restored
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, entry1_->restore_type());
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, entry2_->restore_type());
-  entry2_->set_restore_type(
-      NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY);
-  EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-            entry2_->restore_type());
-
-  // Original URL
-  EXPECT_EQ(GURL(), entry1_->GetOriginalRequestURL());
-  EXPECT_EQ(GURL(), entry2_->GetOriginalRequestURL());
-  entry2_->SetOriginalRequestURL(GURL("original_url"));
-  EXPECT_EQ(GURL("original_url"), entry2_->GetOriginalRequestURL());
-
-  // User agent override
-  EXPECT_FALSE(entry1_->GetIsOverridingUserAgent());
-  EXPECT_FALSE(entry2_->GetIsOverridingUserAgent());
-  entry2_->SetIsOverridingUserAgent(true);
-  EXPECT_TRUE(entry2_->GetIsOverridingUserAgent());
-
-  // Browser initiated post data
-  EXPECT_EQ(NULL, entry1_->GetBrowserInitiatedPostData());
-  EXPECT_EQ(NULL, entry2_->GetBrowserInitiatedPostData());
-  const int length = 11;
-  const unsigned char* raw_data =
-      reinterpret_cast<const unsigned char*>("post\n\n\0data");
-  std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
-  scoped_refptr<base::RefCountedBytes> post_data =
-      base::RefCountedBytes::TakeVector(&post_data_vector);
-  entry2_->SetBrowserInitiatedPostData(post_data.get());
-  EXPECT_EQ(post_data->front(),
-      entry2_->GetBrowserInitiatedPostData()->front());
-
- // Frame to navigate.
-  EXPECT_TRUE(entry1_->GetFrameToNavigate().empty());
-  EXPECT_TRUE(entry2_->GetFrameToNavigate().empty());
-}
-
-// Test timestamps.
-TEST_F(NavigationEntryTest, NavigationEntryTimestamps) {
-  EXPECT_EQ(base::Time(), entry1_->GetTimestamp());
-  const base::Time now = base::Time::Now();
-  entry1_->SetTimestamp(now);
-  EXPECT_EQ(now, entry1_->GetTimestamp());
-}
-
-// Test extra data stored in the navigation entry.
-TEST_F(NavigationEntryTest, NavigationEntryExtraData) {
-  string16 test_data = ASCIIToUTF16("my search terms");
-  string16 output;
-  entry1_->SetExtraData("search_terms", test_data);
-
-  EXPECT_FALSE(entry1_->GetExtraData("non_existent_key", &output));
-  EXPECT_EQ(ASCIIToUTF16(""), output);
-  EXPECT_TRUE(entry1_->GetExtraData("search_terms", &output));
-  EXPECT_EQ(test_data, output);
-  // Data is cleared.
-  entry1_->ClearExtraData("search_terms");
-  // Content in |output| is not modified if data is not present at the key.
-  EXPECT_FALSE(entry1_->GetExtraData("search_terms", &output));
-  EXPECT_EQ(test_data, output);
-  // Using an empty string shows that the data is not present in the map.
-  string16 output2;
-  EXPECT_FALSE(entry1_->GetExtraData("search_terms", &output2));
-  EXPECT_EQ(ASCIIToUTF16(""), output2);
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc
deleted file mode 100644
index 392b869..0000000
--- a/content/browser/web_contents/render_view_host_manager.cc
+++ /dev/null
@@ -1,1093 +0,0 @@
-// Copyright (c) 2012 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/web_contents/render_view_host_manager.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "content/browser/devtools/render_view_devtools_agent_host.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/browser/renderer_host/render_view_host_factory.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/webui/web_ui_controller_factory_registry.h"
-#include "content/browser/webui/web_ui_impl.h"
-#include "content/common/view_messages.h"
-#include "content/port/browser/render_widget_host_view_port.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_widget_host_iterator.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-
-namespace content {
-
-RenderViewHostManager::PendingNavigationParams::PendingNavigationParams()
-    : is_transfer(false), frame_id(-1) {
-}
-
-RenderViewHostManager::PendingNavigationParams::PendingNavigationParams(
-    const GlobalRequestID& global_request_id,
-    bool is_transfer,
-    const GURL& transfer_url,
-    Referrer referrer,
-    int64 frame_id)
-    : global_request_id(global_request_id),
-      is_transfer(is_transfer),
-      transfer_url(transfer_url),
-      referrer(referrer),
-      frame_id(frame_id) {
-}
-
-RenderViewHostManager::RenderViewHostManager(
-    RenderViewHostDelegate* render_view_delegate,
-    RenderWidgetHostDelegate* render_widget_delegate,
-    Delegate* delegate)
-    : delegate_(delegate),
-      cross_navigation_pending_(false),
-      render_view_delegate_(render_view_delegate),
-      render_widget_delegate_(render_widget_delegate),
-      render_view_host_(NULL),
-      pending_render_view_host_(NULL),
-      interstitial_page_(NULL) {
-}
-
-RenderViewHostManager::~RenderViewHostManager() {
-  if (pending_render_view_host_)
-    CancelPending();
-
-  // We should always have a main RenderViewHost except in some tests.
-  RenderViewHostImpl* render_view_host = render_view_host_;
-  render_view_host_ = NULL;
-  if (render_view_host)
-    render_view_host->Shutdown();
-
-  // Shut down any swapped out RenderViewHosts.
-  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
-       iter != swapped_out_hosts_.end();
-       ++iter) {
-    iter->second->Shutdown();
-  }
-}
-
-void RenderViewHostManager::Init(BrowserContext* browser_context,
-                                 SiteInstance* site_instance,
-                                 int routing_id,
-                                 int main_frame_routing_id) {
-  // Create a RenderViewHost, once we have an instance.  It is important to
-  // immediately give this SiteInstance to a RenderViewHost so that it is
-  // ref counted.
-  if (!site_instance)
-    site_instance = SiteInstance::Create(browser_context);
-  render_view_host_ = static_cast<RenderViewHostImpl*>(
-      RenderViewHostFactory::Create(
-          site_instance, render_view_delegate_, render_widget_delegate_,
-          routing_id, main_frame_routing_id, false,
-          delegate_->IsHidden()));
-  render_view_host_->AttachToFrameTree();
-
-  // Keep track of renderer processes as they start to shut down or are
-  // crashed/killed.
-  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                 NotificationService::AllSources());
-  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
-                 NotificationService::AllSources());
-}
-
-RenderViewHostImpl* RenderViewHostManager::current_host() const {
-  return render_view_host_;
-}
-
-RenderViewHostImpl* RenderViewHostManager::pending_render_view_host() const {
-  return pending_render_view_host_;
-}
-
-RenderWidgetHostView* RenderViewHostManager::GetRenderWidgetHostView() const {
-  if (interstitial_page_)
-    return interstitial_page_->GetView();
-  if (!render_view_host_)
-    return NULL;
-  return render_view_host_->GetView();
-}
-
-void RenderViewHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
-  pending_web_ui_.reset(
-      delegate_->CreateWebUIForRenderManager(entry.GetURL()));
-  pending_and_current_web_ui_.reset();
-
-  // If we have assigned (zero or more) bindings to this NavigationEntry in the
-  // past, make sure we're not granting it different bindings than it had
-  // before.  If so, note it and don't give it any bindings, to avoid a
-  // potential privilege escalation.
-  if (pending_web_ui_.get() &&
-      entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
-      pending_web_ui_->GetBindings() != entry.bindings()) {
-    RecordAction(UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
-    pending_web_ui_.reset();
-  }
-}
-
-RenderViewHostImpl* RenderViewHostManager::Navigate(
-    const NavigationEntryImpl& entry) {
-  TRACE_EVENT0("browser", "RenderViewHostManager:Navigate");
-  // Create a pending RenderViewHost. It will give us the one we should use
-  RenderViewHostImpl* dest_render_view_host =
-      static_cast<RenderViewHostImpl*>(UpdateRendererStateForNavigate(entry));
-  if (!dest_render_view_host)
-    return NULL;  // We weren't able to create a pending render view host.
-
-  // If the current render_view_host_ isn't live, we should create it so
-  // that we don't show a sad tab while the dest_render_view_host fetches
-  // its first page.  (Bug 1145340)
-  if (dest_render_view_host != render_view_host_ &&
-      !render_view_host_->IsRenderViewLive()) {
-    // Note: we don't call InitRenderView here because we are navigating away
-    // soon anyway, and we don't have the NavigationEntry for this host.
-    delegate_->CreateRenderViewForRenderManager(render_view_host_,
-                                                MSG_ROUTING_NONE);
-  }
-
-  // If the renderer crashed, then try to create a new one to satisfy this
-  // navigation request.
-  if (!dest_render_view_host->IsRenderViewLive()) {
-    // Recreate the opener chain.
-    int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
-        dest_render_view_host->GetSiteInstance());
-    if (!InitRenderView(dest_render_view_host, opener_route_id))
-      return NULL;
-
-    // Now that we've created a new renderer, be sure to hide it if it isn't
-    // our primary one.  Otherwise, we might crash if we try to call Show()
-    // on it later.
-    if (dest_render_view_host != render_view_host_ &&
-        dest_render_view_host->GetView()) {
-      dest_render_view_host->GetView()->Hide();
-    } else {
-      // This is our primary renderer, notify here as we won't be calling
-      // CommitPending (which does the notify).
-      delegate_->NotifySwappedFromRenderManager(NULL, render_view_host_);
-    }
-  }
-
-  return dest_render_view_host;
-}
-
-void RenderViewHostManager::Stop() {
-  render_view_host_->Stop();
-
-  // If we are cross-navigating, we should stop the pending renderers.  This
-  // will lead to a DidFailProvisionalLoad, which will properly destroy them.
-  if (cross_navigation_pending_) {
-    pending_render_view_host_->Send(
-        new ViewMsg_Stop(pending_render_view_host_->GetRoutingID()));
-  }
-}
-
-void RenderViewHostManager::SetIsLoading(bool is_loading) {
-  render_view_host_->SetIsLoading(is_loading);
-  if (pending_render_view_host_)
-    pending_render_view_host_->SetIsLoading(is_loading);
-}
-
-bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
-  if (!cross_navigation_pending_)
-    return true;
-
-  // We should always have a pending RVH when there's a cross-process navigation
-  // in progress.  Sanity check this for http://crbug.com/276333.
-  CHECK(pending_render_view_host_);
-
-  // If the tab becomes unresponsive during {before}unload while doing a
-  // cross-site navigation, proceed with the navigation.  (This assumes that
-  // the pending RenderViewHost is still responsive.)
-  if (render_view_host_->is_waiting_for_unload_ack()) {
-    // The request has been started and paused while we're waiting for the
-    // unload handler to finish.  We'll pretend that it did.  The pending
-    // renderer will then be swapped in as part of the usual DidNavigate logic.
-    // (If the unload handler later finishes, this call will be ignored because
-    // the pending_nav_params_ state will already be cleaned up.)
-    current_host()->OnSwappedOut(true);
-  } else if (render_view_host_->is_waiting_for_beforeunload_ack()) {
-    // Haven't gotten around to starting the request, because we're still
-    // waiting for the beforeunload handler to finish.  We'll pretend that it
-    // did finish, to let the navigation proceed.  Note that there's a danger
-    // that the beforeunload handler will later finish and possibly return
-    // false (meaning the navigation should not proceed), but we'll ignore it
-    // in this case because it took too long.
-    if (pending_render_view_host_->are_navigations_suspended())
-      pending_render_view_host_->SetNavigationsSuspended(
-          false, base::TimeTicks::Now());
-  }
-  return false;
-}
-
-void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) {
-  // Make sure this is from our current RVH, and that we have a pending
-  // navigation from OnCrossSiteResponse.  (There may be no pending navigation
-  // for data URLs that don't make network requests, for example.)   If not,
-  // just return early and ignore.
-  if (render_view_host != render_view_host_ || !pending_nav_params_.get()) {
-    pending_nav_params_.reset();
-    return;
-  }
-
-  // Now that the unload handler has run, we need to either initiate the
-  // pending transfer (if there is one) or resume the paused response (if not).
-  // TODO(creis): The blank swapped out page is visible during this time, but
-  // we can shorten this by delivering the response directly, rather than
-  // forcing an identical request to be made.
-  if (pending_nav_params_->is_transfer) {
-    // We don't know whether the original request had |user_action| set to true.
-    // However, since we force the navigation to be in the current tab, it
-    // doesn't matter.
-    render_view_host->GetDelegate()->RequestTransferURL(
-        pending_nav_params_->transfer_url,
-        pending_nav_params_->referrer,
-        CURRENT_TAB,
-        pending_nav_params_->frame_id,
-        pending_nav_params_->global_request_id,
-        false,
-        true);
-  } else if (pending_render_view_host_) {
-    RenderProcessHostImpl* pending_process =
-        static_cast<RenderProcessHostImpl*>(
-            pending_render_view_host_->GetProcess());
-    pending_process->ResumeDeferredNavigation(
-        pending_nav_params_->global_request_id);
-  }
-  pending_nav_params_.reset();
-}
-
-void RenderViewHostManager::DidNavigateMainFrame(
-    RenderViewHost* render_view_host) {
-  if (!cross_navigation_pending_) {
-    DCHECK(!pending_render_view_host_);
-
-    // We should only hear this from our current renderer.
-    DCHECK(render_view_host == render_view_host_);
-
-    // Even when there is no pending RVH, there may be a pending Web UI.
-    if (pending_web_ui())
-      CommitPending();
-    return;
-  }
-
-  if (render_view_host == pending_render_view_host_) {
-    // The pending cross-site navigation completed, so show the renderer.
-    // If it committed without sending network requests (e.g., data URLs),
-    // then we still need to swap out the old RVH first and run its unload
-    // handler.  OK for that to happen in the background.
-    if (pending_render_view_host_->HasPendingCrossSiteRequest())
-      SwapOutOldPage();
-
-    CommitPending();
-    cross_navigation_pending_ = false;
-  } else if (render_view_host == render_view_host_) {
-    // A navigation in the original page has taken place.  Cancel the pending
-    // one.
-    CancelPending();
-    cross_navigation_pending_ = false;
-  } else {
-    // No one else should be sending us DidNavigate in this state.
-    DCHECK(false);
-  }
-}
-
-void RenderViewHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
-  // Notify all swapped out hosts, including the pending RVH.
-  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
-       iter != swapped_out_hosts_.end();
-       ++iter) {
-    DCHECK_NE(iter->second->GetSiteInstance(),
-              current_host()->GetSiteInstance());
-    iter->second->DisownOpener();
-  }
-}
-
-void RenderViewHostManager::RendererAbortedProvisionalLoad(
-    RenderViewHost* render_view_host) {
-  // We used to cancel the pending renderer here for cross-site downloads.
-  // However, it's not safe to do that because the download logic repeatedly
-  // looks for this WebContents based on a render view ID.  Instead, we just
-  // leave the pending renderer around until the next navigation event
-  // (Navigate, DidNavigate, etc), which will clean it up properly.
-  // TODO(creis): All of this will go away when we move the cross-site logic
-  // to ResourceDispatcherHost, so that we intercept responses rather than
-  // navigation events.  (That's necessary to support onunload anyway.)  Once
-  // we've made that change, we won't create a pending renderer until we know
-  // the response is not a download.
-}
-
-void RenderViewHostManager::RendererProcessClosing(
-    RenderProcessHost* render_process_host) {
-  // Remove any swapped out RVHs from this process, so that we don't try to
-  // swap them back in while the process is exiting.  Start by finding them,
-  // since there could be more than one.
-  std::list<int> ids_to_remove;
-  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
-       iter != swapped_out_hosts_.end();
-       ++iter) {
-    if (iter->second->GetProcess() == render_process_host)
-      ids_to_remove.push_back(iter->first);
-  }
-
-  // Now delete them.
-  while (!ids_to_remove.empty()) {
-    swapped_out_hosts_[ids_to_remove.back()]->Shutdown();
-    swapped_out_hosts_.erase(ids_to_remove.back());
-    ids_to_remove.pop_back();
-  }
-}
-
-void RenderViewHostManager::ShouldClosePage(
-    bool for_cross_site_transition,
-    bool proceed,
-    const base::TimeTicks& proceed_time) {
-  if (for_cross_site_transition) {
-    // Ignore if we're not in a cross-site navigation.
-    if (!cross_navigation_pending_)
-      return;
-
-    if (proceed) {
-      // Ok to unload the current page, so proceed with the cross-site
-      // navigation.  Note that if navigations are not currently suspended, it
-      // might be because the renderer was deemed unresponsive and this call was
-      // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
-      // is ok to do nothing here.
-      if (pending_render_view_host_ &&
-          pending_render_view_host_->are_navigations_suspended()) {
-        pending_render_view_host_->SetNavigationsSuspended(false, proceed_time);
-      }
-    } else {
-      // Current page says to cancel.
-      CancelPending();
-      cross_navigation_pending_ = false;
-    }
-  } else {
-    // Non-cross site transition means closing the entire tab.
-    bool proceed_to_fire_unload;
-    delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
-                                                  &proceed_to_fire_unload);
-
-    if (proceed_to_fire_unload) {
-      // If we're about to close the tab and there's a pending RVH, cancel it.
-      // Otherwise, if the navigation in the pending RVH completes before the
-      // close in the current RVH, we'll lose the tab close.
-      if (pending_render_view_host_) {
-        CancelPending();
-        cross_navigation_pending_ = false;
-      }
-
-      // This is not a cross-site navigation, the tab is being closed.
-      render_view_host_->ClosePage();
-    }
-  }
-}
-
-void RenderViewHostManager::OnCrossSiteResponse(
-    RenderViewHost* pending_render_view_host,
-    const GlobalRequestID& global_request_id,
-    bool is_transfer,
-    const GURL& transfer_url,
-    const Referrer& referrer,
-    int64 frame_id) {
-  // This should be called either when the pending RVH is ready to commit or
-  // when we realize that the current RVH's request requires a transfer.
-  DCHECK(
-      pending_render_view_host == pending_render_view_host_ ||
-      pending_render_view_host == render_view_host_);
-
-  // TODO(creis): Eventually we will want to check all navigation responses
-  // here, but currently we pass information for a transfer if
-  // ShouldSwapProcessesForRedirect returned true in the network stack.
-  // In that case, we should set up a transfer after the unload handler runs.
-  // If is_transfer is false, we will just run the unload handler and resume.
-  pending_nav_params_.reset(new PendingNavigationParams(
-      global_request_id, is_transfer, transfer_url, referrer, frame_id));
-
-  // Run the unload handler of the current page.
-  SwapOutOldPage();
-}
-
-void RenderViewHostManager::SwapOutOldPage() {
-  // Should only see this while we have a pending renderer or transfer.
-  CHECK(cross_navigation_pending_ || pending_nav_params_.get());
-
-  // First close any modal dialogs that would prevent us from swapping out.
-  delegate_->CancelModalDialogsForRenderManager();
-
-  // Tell the old renderer it is being swapped out.  This will fire the unload
-  // handler (without firing the beforeunload handler a second time).  When the
-  // unload handler finishes and the navigation completes, we will send a
-  // message to the ResourceDispatcherHost, allowing the pending RVH's response
-  // to resume.
-  render_view_host_->SwapOut();
-
-  // ResourceDispatcherHost has told us to run the onunload handler, which
-  // means it is not a download or unsafe page, and we are going to perform the
-  // navigation.  Thus, we no longer need to remember that the RenderViewHost
-  // is part of a pending cross-site request.
-  if (pending_render_view_host_)
-    pending_render_view_host_->SetHasPendingCrossSiteRequest(false);
-}
-
-void RenderViewHostManager::Observe(
-    int type,
-    const NotificationSource& source,
-    const NotificationDetails& details) {
-  switch (type) {
-    case NOTIFICATION_RENDERER_PROCESS_CLOSED:
-    case NOTIFICATION_RENDERER_PROCESS_CLOSING:
-      RendererProcessClosing(
-          Source<RenderProcessHost>(source).ptr());
-      break;
-
-    default:
-      NOTREACHED();
-  }
-}
-
-bool RenderViewHostManager::ShouldTransitionCrossSite() {
-  // False in the single-process mode, as it makes RVHs to accumulate
-  // in swapped_out_hosts_.
-  // True if we are using process-per-site-instance (default) or
-  // process-per-site (kProcessPerSite).
-  return
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
-}
-
-bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
-    const NavigationEntry* curr_entry,
-    const NavigationEntryImpl* new_entry) const {
-  DCHECK(new_entry);
-
-  // Check for reasons to swap processes even if we are in a process model that
-  // doesn't usually swap (e.g., process-per-tab).
-
-  // For security, we should transition between processes when one is a Web UI
-  // page and one isn't.  If there's no curr_entry, check the current RVH's
-  // site, which might already be committed to a Web UI URL (such as the NTP).
-  const GURL& current_url = (curr_entry) ? curr_entry->GetURL() :
-      render_view_host_->GetSiteInstance()->GetSiteURL();
-  BrowserContext* browser_context =
-      delegate_->GetControllerForRenderManager().GetBrowserContext();
-  if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
-          browser_context, current_url)) {
-    // Force swap if it's not an acceptable URL for Web UI.
-    // Here, data URLs are never allowed.
-    if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
-            browser_context, new_entry->GetURL(), false)) {
-      return true;
-    }
-  } else {
-    // Force swap if it's a Web UI URL.
-    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
-            browser_context, new_entry->GetURL())) {
-      return true;
-    }
-  }
-
-  if (GetContentClient()->browser()->ShouldSwapProcessesForNavigation(
-          render_view_host_->GetSiteInstance(),
-          curr_entry ? curr_entry->GetURL() : GURL(),
-          new_entry->GetURL())) {
-    return true;
-  }
-
-  if (!curr_entry)
-    return false;
-
-  // We can't switch a RenderView between view source and non-view source mode
-  // without screwing up the session history sometimes (when navigating between
-  // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat
-  // it as a new navigation). So require a view switch.
-  if (curr_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
-    return true;
-
-  return false;
-}
-
-bool RenderViewHostManager::ShouldReuseWebUI(
-    const NavigationEntry* curr_entry,
-    const NavigationEntryImpl* new_entry) const {
-  NavigationControllerImpl& controller =
-      delegate_->GetControllerForRenderManager();
-  return curr_entry && web_ui_.get() &&
-      (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
-          controller.GetBrowserContext(), curr_entry->GetURL()) ==
-       WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
-          controller.GetBrowserContext(), new_entry->GetURL()));
-}
-
-SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
-    const NavigationEntryImpl& entry,
-    SiteInstance* curr_instance) {
-  // NOTE: This is only called when ShouldTransitionCrossSite is true.
-
-  const GURL& dest_url = entry.GetURL();
-  NavigationControllerImpl& controller =
-      delegate_->GetControllerForRenderManager();
-  BrowserContext* browser_context = controller.GetBrowserContext();
-
-  // If the entry has an instance already we should use it.
-  if (entry.site_instance())
-    return entry.site_instance();
-
-  // (UGLY) HEURISTIC, process-per-site only:
-  //
-  // If this navigation is generated, then it probably corresponds to a search
-  // query.  Given that search results typically lead to users navigating to
-  // other sites, we don't really want to use the search engine hostname to
-  // determine the site instance for this navigation.
-  //
-  // NOTE: This can be removed once we have a way to transition between
-  //       RenderViews in response to a link click.
-  //
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
-      PageTransitionCoreTypeIs(entry.GetTransitionType(),
-                               PAGE_TRANSITION_GENERATED)) {
-    return curr_instance;
-  }
-
-  SiteInstanceImpl* curr_site_instance =
-      static_cast<SiteInstanceImpl*>(curr_instance);
-
-  // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
-  // for this entry.  We won't commit the SiteInstance to this site until the
-  // navigation commits (in DidNavigate), unless the navigation entry was
-  // restored or it's a Web UI as described below.
-  if (!curr_site_instance->HasSite()) {
-    // If we've already created a SiteInstance for our destination, we don't
-    // want to use this unused SiteInstance; use the existing one.  (We don't
-    // do this check if the curr_instance has a site, because for now, we want
-    // to compare against the current URL and not the SiteInstance's site.  In
-    // this case, there is no current URL, so comparing against the site is ok.
-    // See additional comments below.)
-    //
-    // Also, if the URL should use process-per-site mode and there is an
-    // existing process for the site, we should use it.  We can call
-    // GetRelatedSiteInstance() for this, which will eagerly set the site and
-    // thus use the correct process.
-    bool use_process_per_site =
-        RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
-        RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
-    if (curr_site_instance->HasRelatedSiteInstance(dest_url) ||
-        use_process_per_site) {
-      return curr_site_instance->GetRelatedSiteInstance(dest_url);
-    }
-
-    // For extensions, Web UI URLs (such as the new tab page), and apps we do
-    // not want to use the curr_instance if it has no site, since it will have a
-    // RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for this
-    // URL instead (with the correct process type).
-    if (curr_site_instance->HasWrongProcessForURL(dest_url))
-      return curr_site_instance->GetRelatedSiteInstance(dest_url);
-
-    // View-source URLs must use a new SiteInstance and BrowsingInstance.
-    // TODO(nasko): This is the same condition as later in the function. This
-    // should be taken into account when refactoring this method as part of
-    // http://crbug.com/123007.
-    if (entry.IsViewSourceMode())
-      return SiteInstance::CreateForURL(browser_context, dest_url);
-
-    // If we are navigating from a blank SiteInstance to a WebUI, make sure we
-    // create a new SiteInstance.
-    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
-            browser_context, dest_url)) {
-        return SiteInstance::CreateForURL(browser_context, dest_url);
-    }
-
-    // Normally the "site" on the SiteInstance is set lazily when the load
-    // actually commits. This is to support better process sharing in case
-    // the site redirects to some other site: we want to use the destination
-    // site in the site instance.
-    //
-    // In the case of session restore, as it loads all the pages immediately
-    // we need to set the site first, otherwise after a restore none of the
-    // pages would share renderers in process-per-site.
-    if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
-      curr_site_instance->SetSite(dest_url);
-
-    return curr_site_instance;
-  }
-
-  // Otherwise, only create a new SiteInstance for cross-site navigation.
-
-  // TODO(creis): Once we intercept links and script-based navigations, we
-  // will be able to enforce that all entries in a SiteInstance actually have
-  // the same site, and it will be safe to compare the URL against the
-  // SiteInstance's site, as follows:
-  // const GURL& current_url = curr_instance->site();
-  // For now, though, we're in a hybrid model where you only switch
-  // SiteInstances if you type in a cross-site URL.  This means we have to
-  // compare the entry's URL to the last committed entry's URL.
-  NavigationEntry* curr_entry = controller.GetLastCommittedEntry();
-  if (interstitial_page_) {
-    // The interstitial is currently the last committed entry, but we want to
-    // compare against the last non-interstitial entry.
-    curr_entry = controller.GetEntryAtOffset(-1);
-  }
-  // If there is no last non-interstitial entry (and curr_instance already
-  // has a site), then we must have been opened from another tab.  We want
-  // to compare against the URL of the page that opened us, but we can't
-  // get to it directly.  The best we can do is check against the site of
-  // the SiteInstance.  This will be correct when we intercept links and
-  // script-based navigations, but for now, it could place some pages in a
-  // new process unnecessarily.  We should only hit this case if a page tries
-  // to open a new tab to an interstitial-inducing URL, and then navigates
-  // the page to a different same-site URL.  (This seems very unlikely in
-  // practice.)
-  const GURL& current_url = (curr_entry) ? curr_entry->GetURL() :
-      curr_instance->GetSiteURL();
-
-  // View-source URLs must use a new SiteInstance and BrowsingInstance.
-  // TODO(creis): Refactor this method so this duplicated code isn't needed.
-  // See http://crbug.com/123007.
-  if (curr_entry &&
-      curr_entry->IsViewSourceMode() != entry.IsViewSourceMode()) {
-    return SiteInstance::CreateForURL(browser_context, dest_url);
-  }
-
-  // Use the current SiteInstance for same site navigations, as long as the
-  // process type is correct.  (The URL may have been installed as an app since
-  // the last time we visited it.)
-  if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
-      !static_cast<SiteInstanceImpl*>(curr_instance)->HasWrongProcessForURL(
-          dest_url)) {
-    return curr_instance;
-  } else if (ShouldSwapProcessesForNavigation(curr_entry, &entry)) {
-    // When we're swapping, we need to force the site instance AND browsing
-    // instance to be different ones. This addresses special cases where we use
-    // a single BrowsingInstance for all pages of a certain type (e.g., New Tab
-    // Pages), keeping them in the same process. When you navigate away from
-    // that page, we want to explicity ignore that BrowsingInstance and group
-    // this page into the appropriate SiteInstance for its URL.
-    return SiteInstance::CreateForURL(browser_context, dest_url);
-  } else {
-    // Start the new renderer in a new SiteInstance, but in the current
-    // BrowsingInstance.  It is important to immediately give this new
-    // SiteInstance to a RenderViewHost (if it is different than our current
-    // SiteInstance), so that it is ref counted.  This will happen in
-    // CreateRenderView.
-    return curr_instance->GetRelatedSiteInstance(dest_url);
-  }
-}
-
-int RenderViewHostManager::CreateRenderView(
-    SiteInstance* instance,
-    int opener_route_id,
-    bool swapped_out,
-    bool hidden) {
-  CHECK(instance);
-  DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
-
-  // Check if we've already created an RVH for this SiteInstance.  If so, try
-  // to re-use the existing one, which has already been initialized.  We'll
-  // remove it from the list of swapped out hosts if it commits.
-  RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>(
-      GetSwappedOutRenderViewHost(instance));
-  if (new_render_view_host) {
-    // Prevent the process from exiting while we're trying to use it.
-    if (!swapped_out)
-      new_render_view_host->GetProcess()->AddPendingView();
-  } else {
-    // Create a new RenderViewHost if we don't find an existing one.
-    new_render_view_host = static_cast<RenderViewHostImpl*>(
-        RenderViewHostFactory::Create(instance,
-                                      render_view_delegate_,
-                                      render_widget_delegate_,
-                                      MSG_ROUTING_NONE,
-                                      MSG_ROUTING_NONE,
-                                      swapped_out,
-                                      hidden));
-
-    // If the new RVH is swapped out already, store it.  Otherwise prevent the
-    // process from exiting while we're trying to navigate in it.
-    if (swapped_out) {
-      swapped_out_hosts_[instance->GetId()] = new_render_view_host;
-    } else {
-      new_render_view_host->GetProcess()->AddPendingView();
-    }
-
-    bool success = InitRenderView(new_render_view_host, opener_route_id);
-    if (success) {
-      // Don't show the view until we get a DidNavigate from it.
-      new_render_view_host->GetView()->Hide();
-    } else if (!swapped_out) {
-      CancelPending();
-    }
-  }
-
-  // Use this as our new pending RVH if it isn't swapped out.
-  if (!swapped_out)
-    pending_render_view_host_ = new_render_view_host;
-
-  return new_render_view_host->GetRoutingID();
-}
-
-bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
-                                           int opener_route_id) {
-  // If the pending navigation is to a WebUI and the RenderView is not in a
-  // guest process, tell the RenderView about any bindings it will need enabled.
-  if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest())
-    render_view_host->AllowBindings(pending_web_ui()->GetBindings());
-
-  return delegate_->CreateRenderViewForRenderManager(render_view_host,
-                                                     opener_route_id);
-}
-
-void RenderViewHostManager::CommitPending() {
-  // First check whether we're going to want to focus the location bar after
-  // this commit.  We do this now because the navigation hasn't formally
-  // committed yet, so if we've already cleared |pending_web_ui_| the call chain
-  // this triggers won't be able to figure out what's going on.
-  bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
-
-  // Next commit the Web UI, if any. Either replace |web_ui_| with
-  // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
-  // leave |web_ui_| as is if reusing it.
-  DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
-  if (pending_web_ui_)
-    web_ui_.reset(pending_web_ui_.release());
-  else if (!pending_and_current_web_ui_.get())
-    web_ui_.reset();
-
-  // It's possible for the pending_render_view_host_ to be NULL when we aren't
-  // crossing process boundaries. If so, we just needed to handle the Web UI
-  // committing above and we're done.
-  if (!pending_render_view_host_) {
-    if (will_focus_location_bar)
-      delegate_->SetFocusToLocationBar(false);
-    return;
-  }
-
-  // Remember if the page was focused so we can focus the new renderer in
-  // that case.
-  bool focus_render_view = !will_focus_location_bar &&
-      render_view_host_->GetView() && render_view_host_->GetView()->HasFocus();
-
-  // Swap in the pending view and make it active. Also ensure the FrameTree
-  // stays in sync.
-  RenderViewHostImpl* old_render_view_host = render_view_host_;
-  render_view_host_ = pending_render_view_host_;
-  pending_render_view_host_ = NULL;
-  render_view_host_->AttachToFrameTree();
-
-  // The process will no longer try to exit, so we can decrement the count.
-  render_view_host_->GetProcess()->RemovePendingView();
-
-  // If the view is gone, then this RenderViewHost died while it was hidden.
-  // We ignored the RenderProcessGone call at the time, so we should send it now
-  // to make sure the sad tab shows up, etc.
-  if (!render_view_host_->GetView())
-    delegate_->RenderProcessGoneFromRenderManager(render_view_host_);
-  else if (!delegate_->IsHidden())
-    render_view_host_->GetView()->Show();
-
-  // Hide the old view now that the new one is visible.
-  if (old_render_view_host->GetView()) {
-    old_render_view_host->GetView()->Hide();
-    old_render_view_host->WasSwappedOut();
-  }
-
-  // Make sure the size is up to date.  (Fix for bug 1079768.)
-  delegate_->UpdateRenderViewSizeForRenderManager();
-
-  if (will_focus_location_bar)
-    delegate_->SetFocusToLocationBar(false);
-  else if (focus_render_view && render_view_host_->GetView())
-    RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus();
-
-  // Notify that we've swapped RenderViewHosts. We do this
-  // before shutting down the RVH so that we can clean up
-  // RendererResources related to the RVH first.
-  delegate_->NotifySwappedFromRenderManager(old_render_view_host,
-                                            render_view_host_);
-
-  // If the pending view was on the swapped out list, we can remove it.
-  swapped_out_hosts_.erase(render_view_host_->GetSiteInstance()->GetId());
-
-  // If there are no active RVHs in this SiteInstance, it means that
-  // this RVH was the last active one in the SiteInstance. Now that we
-  // know that all RVHs are swapped out, we can delete all the RVHs in
-  // this SiteInstance.
-  if (!static_cast<SiteInstanceImpl*>(old_render_view_host->GetSiteInstance())->
-          active_view_count()) {
-    ShutdownRenderViewHostsInSiteInstance(
-        old_render_view_host->GetSiteInstance()->GetId());
-    // This is deleted while cleaning up the SitaInstance's views.
-    old_render_view_host = NULL;
-  } else if (old_render_view_host->IsRenderViewLive()) {
-    // If the old RVH is live, we are swapping it out and should keep track of
-    // it in case we navigate back to it.
-    DCHECK(old_render_view_host->is_swapped_out());
-    // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
-    // sure we don't get different rvh instances for the same site instance
-    // in the same rvhmgr.
-    // TODO(creis): Clean this up.
-    int32 old_site_instance_id =
-        old_render_view_host->GetSiteInstance()->GetId();
-    RenderViewHostMap::iterator iter =
-        swapped_out_hosts_.find(old_site_instance_id);
-    if (iter != swapped_out_hosts_.end() &&
-        iter->second != old_render_view_host) {
-      // Shutdown the RVH that will be replaced in the map to avoid a leak.
-      iter->second->Shutdown();
-    }
-    swapped_out_hosts_[old_site_instance_id] = old_render_view_host;
-  } else {
-    old_render_view_host->Shutdown();
-    old_render_view_host = NULL;  // Shutdown() deletes it.
-  }
-}
-
-void RenderViewHostManager::ShutdownRenderViewHostsInSiteInstance(
-    int32 site_instance_id) {
-  // First remove any swapped out RVH for this SiteInstance from our
-  // list.
-  swapped_out_hosts_.erase(site_instance_id);
-
-  scoped_ptr<RenderWidgetHostIterator> widgets(
-      RenderWidgetHostImpl::GetAllRenderWidgetHosts());
-  while (RenderWidgetHost* widget = widgets->GetNextHost()) {
-    if (!widget->IsRenderView())
-      continue;
-    RenderViewHostImpl* rvh =
-        static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
-    if (site_instance_id == rvh->GetSiteInstance()->GetId())
-      rvh->Shutdown();
-  }
-}
-
-RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
-    const NavigationEntryImpl& entry) {
-  // If we are cross-navigating, then we want to get back to normal and navigate
-  // as usual.
-  if (cross_navigation_pending_) {
-    if (pending_render_view_host_)
-      CancelPending();
-    cross_navigation_pending_ = false;
-  }
-
-  // render_view_host_ will not be deleted before the end of this method, so we
-  // don't have to worry about this SiteInstance's ref count dropping to zero.
-  SiteInstance* curr_instance = render_view_host_->GetSiteInstance();
-
-  // Determine if we need a new SiteInstance for this entry.
-  // Again, new_instance won't be deleted before the end of this method, so it
-  // is safe to use a normal pointer here.
-  SiteInstance* new_instance = curr_instance;
-  const NavigationEntry* curr_entry =
-      delegate_->GetLastCommittedNavigationEntryForRenderManager();
-  bool is_guest_scheme = curr_instance->GetSiteURL().SchemeIs(kGuestScheme);
-  bool force_swap = ShouldSwapProcessesForNavigation(curr_entry, &entry);
-  if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
-    new_instance = GetSiteInstanceForEntry(entry, curr_instance);
-
-  if (!is_guest_scheme && (new_instance != curr_instance || force_swap)) {
-    // New SiteInstance.
-    DCHECK(!cross_navigation_pending_);
-
-    // This will possibly create (set to NULL) a Web UI object for the pending
-    // page. We'll use this later to give the page special access. This must
-    // happen before the new renderer is created below so it will get bindings.
-    // It must also happen after the above conditional call to CancelPending(),
-    // otherwise CancelPending may clear the pending_web_ui_ and the page will
-    // not have its bindings set appropriately.
-    SetPendingWebUI(entry);
-
-    // Ensure that we have created RVHs for the new RVH's opener chain if
-    // we are staying in the same BrowsingInstance. This allows the pending RVH
-    // to send cross-process script calls to its opener(s).
-    int opener_route_id = MSG_ROUTING_NONE;
-    if (new_instance->IsRelatedSiteInstance(curr_instance)) {
-      opener_route_id =
-          delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
-    }
-
-    // Create a non-swapped-out pending RVH with the given opener and navigate
-    // it.
-    int route_id = CreateRenderView(new_instance, opener_route_id, false,
-                                    delegate_->IsHidden());
-    if (route_id == MSG_ROUTING_NONE)
-      return NULL;
-
-    // Check if our current RVH is live before we set up a transition.
-    if (!render_view_host_->IsRenderViewLive()) {
-      if (!cross_navigation_pending_) {
-        // The current RVH is not live.  There's no reason to sit around with a
-        // sad tab or a newly created RVH while we wait for the pending RVH to
-        // navigate.  Just switch to the pending RVH now and go back to non
-        // cross-navigating (Note that we don't care about on{before}unload
-        // handlers if the current RVH isn't live.)
-        CommitPending();
-        return render_view_host_;
-      } else {
-        NOTREACHED();
-        return render_view_host_;
-      }
-    }
-    // Otherwise, it's safe to treat this as a pending cross-site transition.
-
-    // We need to wait until the beforeunload handler has run, unless we are
-    // transferring an existing request (in which case it has already run).
-    // Suspend the new render view (i.e., don't let it send the cross-site
-    // Navigate message) until we hear back from the old renderer's
-    // beforeunload handler.  If the handler returns false, we'll have to
-    // cancel the request.
-    DCHECK(!pending_render_view_host_->are_navigations_suspended());
-    bool is_transfer =
-        entry.transferred_global_request_id() != GlobalRequestID();
-    if (is_transfer) {
-      // We don't need to stop the old renderer or run beforeunload/unload
-      // handlers, because those have already been done.
-      DCHECK(pending_nav_params_->global_request_id ==
-                entry.transferred_global_request_id());
-    } else {
-      // Also make sure the old render view stops, in case a load is in
-      // progress.  (We don't want to do this for transfers, since it will
-      // interrupt the transfer with an unexpected DidStopLoading.)
-      render_view_host_->Send(
-          new ViewMsg_Stop(render_view_host_->GetRoutingID()));
-
-      pending_render_view_host_->SetNavigationsSuspended(true,
-                                                         base::TimeTicks());
-
-      // Tell the CrossSiteRequestManager that this RVH has a pending cross-site
-      // request, so that ResourceDispatcherHost will know to tell us to run the
-      // old page's unload handler before it sends the response.
-      pending_render_view_host_->SetHasPendingCrossSiteRequest(true);
-    }
-
-    // We now have a pending RVH.
-    DCHECK(!cross_navigation_pending_);
-    cross_navigation_pending_ = true;
-
-    // Unless we are transferring an existing request, we should now
-    // tell the old render view to run its beforeunload handler, since it
-    // doesn't otherwise know that the cross-site request is happening.  This
-    // will trigger a call to ShouldClosePage with the reply.
-    if (!is_transfer)
-      render_view_host_->FirePageBeforeUnload(true);
-
-    return pending_render_view_host_;
-  } else {
-    if (ShouldReuseWebUI(curr_entry, &entry)) {
-      pending_web_ui_.reset();
-      pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
-    } else {
-      SetPendingWebUI(entry);
-
-      // Make sure the new RenderViewHost has the right bindings.
-      if (pending_web_ui() && !render_view_host_->GetProcess()->IsGuest())
-        render_view_host_->AllowBindings(pending_web_ui()->GetBindings());
-    }
-
-    if (pending_web_ui() && render_view_host_->IsRenderViewLive())
-      pending_web_ui()->GetController()->RenderViewReused(render_view_host_);
-
-    // The renderer can exit view source mode when any error or cancellation
-    // happen. We must overwrite to recover the mode.
-    if (entry.IsViewSourceMode()) {
-      render_view_host_->Send(
-          new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID()));
-    }
-  }
-
-  // Same SiteInstance can be used.  Navigate render_view_host_ if we are not
-  // cross navigating.
-  DCHECK(!cross_navigation_pending_);
-  return render_view_host_;
-}
-
-void RenderViewHostManager::CancelPending() {
-  RenderViewHostImpl* pending_render_view_host = pending_render_view_host_;
-  pending_render_view_host_ = NULL;
-
-  RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
-      pending_render_view_host,
-      render_view_host_);
-
-  // We no longer need to prevent the process from exiting.
-  pending_render_view_host->GetProcess()->RemovePendingView();
-
-  // The pending RVH may already be on the swapped out list if we started to
-  // swap it back in and then canceled.  If so, make sure it gets swapped out
-  // again.  If it's not on the swapped out list (e.g., aborting a pending
-  // load), then it's safe to shut down.
-  if (IsOnSwappedOutList(pending_render_view_host)) {
-    // Any currently suspended navigations are no longer needed.
-    pending_render_view_host->CancelSuspendedNavigations();
-
-    pending_render_view_host->SwapOut();
-  } else {
-    // We won't be coming back, so shut this one down.
-    pending_render_view_host->Shutdown();
-  }
-
-  pending_web_ui_.reset();
-  pending_and_current_web_ui_.reset();
-}
-
-void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) {
-  // We are doing this in order to work around and to track a crasher
-  // (http://crbug.com/23411) where it seems that pending_render_view_host_ is
-  // deleted (not sure from where) but not NULLed.
-  if (rvh == pending_render_view_host_) {
-    // If you hit this NOTREACHED, please report it in the following bug
-    // http://crbug.com/23411 Make sure to include what you were doing when it
-    // happened  (navigating to a new page, closing a tab...) and if you can
-    // reproduce.
-    NOTREACHED();
-    pending_render_view_host_ = NULL;
-  }
-
-  // Make sure deleted RVHs are not kept in the swapped out list while we are
-  // still alive.  (If render_view_host_ is null, we're already being deleted.)
-  if (!render_view_host_)
-    return;
-  // We can't look it up by SiteInstance ID, which may no longer be valid.
-  for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
-       iter != swapped_out_hosts_.end();
-       ++iter) {
-    if (iter->second == rvh) {
-      swapped_out_hosts_.erase(iter);
-      break;
-    }
-  }
-}
-
-bool RenderViewHostManager::IsOnSwappedOutList(RenderViewHost* rvh) const {
-  if (!rvh->GetSiteInstance())
-    return false;
-
-  RenderViewHostMap::const_iterator iter = swapped_out_hosts_.find(
-      rvh->GetSiteInstance()->GetId());
-  if (iter == swapped_out_hosts_.end())
-    return false;
-
-  return iter->second == rvh;
-}
-
-RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost(
-    SiteInstance* instance) {
-  RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId());
-  if (iter != swapped_out_hosts_.end())
-    return iter->second;
-
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/render_view_host_manager.h b/content/browser/web_contents/render_view_host_manager.h
deleted file mode 100644
index 9162f10..0000000
--- a/content/browser/web_contents/render_view_host_manager.h
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/common/referrer.h"
-
-
-namespace content {
-class BrowserContext;
-class InterstitialPageImpl;
-class NavigationControllerImpl;
-class NavigationEntry;
-class NavigationEntryImpl;
-class RenderViewHost;
-class RenderViewHostImpl;
-class RenderViewHostManagerTest;
-class RenderWidgetHostDelegate;
-class RenderWidgetHostView;
-class TestWebContents;
-class WebUIImpl;
-
-// Manages RenderViewHosts for a WebContentsImpl. Normally there is only one and
-// it is easy to do. But we can also have transitions of processes (and hence
-// RenderViewHosts) that can get complex.
-class CONTENT_EXPORT RenderViewHostManager
-    : public RenderViewHostDelegate::RendererManagement,
-      public NotificationObserver {
- public:
-  // Functions implemented by our owner that we need.
-  //
-  // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl
-  // that are required to run this class. The design should probably be better
-  // such that these are more clear.
-  //
-  // There is additional complexity that some of the functions we need in
-  // WebContentsImpl are inherited and non-virtual. These are named with
-  // "RenderManager" so that the duplicate implementation of them will be clear.
-  class CONTENT_EXPORT Delegate {
-   public:
-    // Initializes the given renderer if necessary and creates the view ID
-    // corresponding to this view host. If this method is not called and the
-    // process is not shared, then the WebContentsImpl will act as though the
-    // renderer is not running (i.e., it will render "sad tab"). This method is
-    // automatically called from LoadURL.
-    //
-    // If you are attaching to an already-existing RenderView, you should call
-    // InitWithExistingID.
-    virtual bool CreateRenderViewForRenderManager(
-        RenderViewHost* render_view_host, int opener_route_id) = 0;
-    virtual void BeforeUnloadFiredFromRenderManager(
-        bool proceed, const base::TimeTicks& proceed_time,
-        bool* proceed_to_fire_unload) = 0;
-    virtual void RenderProcessGoneFromRenderManager(
-        RenderViewHost* render_view_host) = 0;
-    virtual void UpdateRenderViewSizeForRenderManager() = 0;
-    virtual void CancelModalDialogsForRenderManager() = 0;
-    virtual void NotifySwappedFromRenderManager(
-        RenderViewHost* old_host, RenderViewHost* new_host) = 0;
-    virtual NavigationControllerImpl&
-        GetControllerForRenderManager() = 0;
-
-    // Create swapped out RenderViews in the given SiteInstance for each tab in
-    // the opener chain of this tab, if any.  This allows the current tab to
-    // make cross-process script calls to its opener(s).  Returns the route ID
-    // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE).
-    virtual int CreateOpenerRenderViewsForRenderManager(
-        SiteInstance* instance) = 0;
-
-    // Creates a WebUI object for the given URL if one applies. Ownership of the
-    // returned pointer will be passed to the caller. If no WebUI applies,
-    // returns NULL.
-    virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
-
-    // Returns the navigation entry of the current navigation, or NULL if there
-    // is none.
-    virtual NavigationEntry*
-        GetLastCommittedNavigationEntryForRenderManager() = 0;
-
-    // Returns true if the location bar should be focused by default rather than
-    // the page contents. The view calls this function when the tab is focused
-    // to see what it should do.
-    virtual bool FocusLocationBarByDefault() = 0;
-
-    // Focuses the location bar.
-    virtual void SetFocusToLocationBar(bool select_all) = 0;
-
-    // Creates a view and sets the size for the specified RVH.
-    virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
-
-    // Returns true if views created for this delegate should be created in a
-    // hidden state.
-    virtual bool IsHidden() = 0;
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
-  // All three delegate pointers must be non-NULL and are not owned by this
-  // class.  They must outlive this class. The RenderViewHostDelegate and
-  // RenderWidgetHostDelegate are what will be installed into all
-  // RenderViewHosts that are created.
-  //
-  // You must call Init() before using this class.
-  RenderViewHostManager(
-      RenderViewHostDelegate* render_view_delegate,
-      RenderWidgetHostDelegate* render_widget_delegate,
-      Delegate* delegate);
-  virtual ~RenderViewHostManager();
-
-  // For arguments, see WebContentsImpl constructor.
-  void Init(BrowserContext* browser_context,
-            SiteInstance* site_instance,
-            int routing_id,
-            int main_frame_routing_id);
-
-  // Returns the currently active RenderViewHost.
-  //
-  // This will be non-NULL between Init() and Shutdown(). You may want to NULL
-  // check it in many cases, however. Windows can send us messages during the
-  // destruction process after it has been shut down.
-  RenderViewHostImpl* current_host() const;
-
-  // Returns the view associated with the current RenderViewHost, or NULL if
-  // there is no current one.
-  RenderWidgetHostView* GetRenderWidgetHostView() const;
-
-  // Returns the pending render view host, or NULL if there is no pending one.
-  RenderViewHostImpl* pending_render_view_host() const;
-
-  // Returns the current committed Web UI or NULL if none applies.
-  WebUIImpl* web_ui() const { return web_ui_.get(); }
-
-  // Returns the Web UI for the pending navigation, or NULL of none applies.
-  WebUIImpl* pending_web_ui() const {
-    return pending_web_ui_.get() ? pending_web_ui_.get() :
-                                   pending_and_current_web_ui_.get();
-  }
-
-  // Sets the pending Web UI for the pending navigation, ensuring that the
-  // bindings are appropriate for the given NavigationEntry.
-  void SetPendingWebUI(const NavigationEntryImpl& entry);
-
-  // Called when we want to instruct the renderer to navigate to the given
-  // navigation entry. It may create a new RenderViewHost or re-use an existing
-  // one. The RenderViewHost to navigate will be returned. Returns NULL if one
-  // could not be created.
-  RenderViewHostImpl* Navigate(const NavigationEntryImpl& entry);
-
-  // Instructs the various live views to stop. Called when the user directed the
-  // page to stop loading.
-  void Stop();
-
-  // Notifies the regular and pending RenderViewHosts that a load is or is not
-  // happening. Even though the message is only for one of them, we don't know
-  // which one so we tell both.
-  void SetIsLoading(bool is_loading);
-
-  // Whether to close the tab or not when there is a hang during an unload
-  // handler. If we are mid-crosssite navigation, then we should proceed
-  // with the navigation instead of closing the tab.
-  bool ShouldCloseTabOnUnresponsiveRenderer();
-
-  // The RenderViewHost has been swapped out, so we should resume the pending
-  // network response and allow the pending RenderViewHost to commit.
-  void SwappedOut(RenderViewHost* render_view_host);
-
-  // Called when a renderer's main frame navigates.
-  void DidNavigateMainFrame(RenderViewHost* render_view_host);
-
-  // Called when a renderer sets its opener to null.
-  void DidDisownOpener(RenderViewHost* render_view_host);
-
-  // Helper method to create a RenderViewHost.  If |swapped_out| is true, it
-  // will be initially placed on the swapped out hosts list.  Otherwise, it
-  // will be used for a pending cross-site navigation.
-  int CreateRenderView(SiteInstance* instance,
-                       int opener_route_id,
-                       bool swapped_out,
-                       bool hidden);
-
-  // Called when a provisional load on the given renderer is aborted.
-  void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host);
-
-  // Sets the passed passed interstitial as the currently showing interstitial.
-  // |interstitial_page| should be non NULL (use the remove_interstitial_page
-  // method to unset the interstitial) and no interstitial page should be set
-  // when there is already a non NULL interstitial page set.
-  void set_interstitial_page(InterstitialPageImpl* interstitial_page) {
-    DCHECK(!interstitial_page_ && interstitial_page);
-    interstitial_page_ = interstitial_page;
-  }
-
-  // Unsets the currently showing interstitial.
-  void remove_interstitial_page() {
-    DCHECK(interstitial_page_);
-    interstitial_page_ = NULL;
-  }
-
-  // Returns the currently showing interstitial, NULL if no interstitial is
-  // showing.
-  InterstitialPageImpl* interstitial_page() const { return interstitial_page_; }
-
-  // RenderViewHostDelegate::RendererManagement implementation.
-  virtual void ShouldClosePage(
-      bool for_cross_site_transition,
-      bool proceed,
-      const base::TimeTicks& proceed_time) OVERRIDE;
-  virtual void OnCrossSiteResponse(
-      RenderViewHost* pending_render_view_host,
-      const GlobalRequestID& global_request_id,
-      bool is_transfer,
-      const GURL& transfer_url,
-      const Referrer& referrer,
-      int64 frame_id) OVERRIDE;
-
-  // NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  // Called when a RenderViewHost is about to be deleted.
-  void RenderViewDeleted(RenderViewHost* rvh);
-
-  // Returns whether the given RenderViewHost is on the list of swapped out
-  // RenderViewHosts.
-  bool IsOnSwappedOutList(RenderViewHost* rvh) const;
-
-  // Returns the swapped out RenderViewHost for the given SiteInstance, if any.
-  RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance);
-
-  // Runs the unload handler in the current page, when we know that a pending
-  // cross-process navigation is going to commit.  We may initiate a transfer
-  // to a new process after this completes or times out.
-  void SwapOutOldPage();
-
- private:
-  friend class RenderViewHostManagerTest;
-  friend class TestWebContents;
-
-  // Tracks information about a navigation while a cross-process transition is
-  // in progress, in case we need to transfer it to a new RenderViewHost.
-  struct PendingNavigationParams {
-    PendingNavigationParams();
-    PendingNavigationParams(const GlobalRequestID& global_request_id,
-                            bool is_transfer,
-                            const GURL& transfer_url,
-                            Referrer referrer,
-                            int64 frame_id);
-
-    // The child ID and request ID for the pending navigation.  Present whether
-    // |is_transfer| is true or false.
-    GlobalRequestID global_request_id;
-
-    // Whether this pending navigation needs to be transferred to another
-    // process than the one it was going to commit in.  If so, the
-    // |transfer_url|, |referrer|, and |frame_id| parameters will be set.
-    bool is_transfer;
-
-    // If |is_transfer|, this is the destination URL to request in the new
-    // process.
-    GURL transfer_url;
-
-    // If |is_transfer|, this is the referrer to use for the request in the new
-    // process.
-    Referrer referrer;
-
-    // If |is_transfer|, this is the frame ID to use in RequestTransferURL.
-    int64 frame_id;
-  };
-
-  // Returns whether this tab should transition to a new renderer for
-  // cross-site URLs.  Enabled unless we see the --process-per-tab command line
-  // switch.  Can be overridden in unit tests.
-  bool ShouldTransitionCrossSite();
-
-  // Returns true if the two navigation entries are incompatible in some way
-  // other than site instances. Cases where this can happen include Web UI
-  // to regular web pages. It will cause us to swap RenderViewHosts (and hence
-  // RenderProcessHosts) even if the site instance would otherwise be the same.
-  // As part of this, we'll also force new SiteInstances and BrowsingInstances.
-  // Either of the entries may be NULL.
-  bool ShouldSwapProcessesForNavigation(
-      const NavigationEntry* curr_entry,
-      const NavigationEntryImpl* new_entry) const;
-
-  bool ShouldReuseWebUI(
-      const NavigationEntry* curr_entry,
-      const NavigationEntryImpl* new_entry) const;
-
-  // Returns an appropriate SiteInstance object for the given NavigationEntry,
-  // possibly reusing the current SiteInstance.
-  // Never called if --process-per-tab is used.
-  SiteInstance* GetSiteInstanceForEntry(
-      const NavigationEntryImpl& entry,
-      SiteInstance* curr_instance);
-
-  // Sets up the necessary state for a new RenderViewHost with the given opener.
-  bool InitRenderView(RenderViewHost* render_view_host, int opener_route_id);
-
-  // Sets the pending RenderViewHost/WebUI to be the active one. Note that this
-  // doesn't require the pending render_view_host_ pointer to be non-NULL, since
-  // there could be Web UI switching as well. Call this for every commit.
-  void CommitPending();
-
-  // Shutdown all RenderViewHosts in a SiteInstance. This is called
-  // to shutdown views when all the views in a SiteInstance are
-  // confirmed to be swapped out.
-  void ShutdownRenderViewHostsInSiteInstance(int32 site_instance_id);
-
-  // Helper method to terminate the pending RenderViewHost.
-  void CancelPending();
-
-  RenderViewHostImpl* UpdateRendererStateForNavigate(
-      const NavigationEntryImpl& entry);
-
-  // Called when a renderer process is starting to close.  We should not
-  // schedule new navigations in its swapped out RenderViewHosts after this.
-  void RendererProcessClosing(RenderProcessHost* render_process_host);
-
-  // Our delegate, not owned by us. Guaranteed non-NULL.
-  Delegate* delegate_;
-
-  // Whether a navigation requiring different RenderView's is pending. This is
-  // either cross-site request is (in the new process model), or when required
-  // for the view type (like view source versus not).
-  bool cross_navigation_pending_;
-
-  // Implemented by the owner of this class, these delegates are installed into
-  // all the RenderViewHosts that we create.
-  RenderViewHostDelegate* render_view_delegate_;
-  RenderWidgetHostDelegate* render_widget_delegate_;
-
-  // Our RenderView host and its associated Web UI (if any, will be NULL for
-  // non-DOM-UI pages). This object is responsible for all communication with
-  // a child RenderView instance.
-  RenderViewHostImpl* render_view_host_;
-  scoped_ptr<WebUIImpl> web_ui_;
-
-  // A RenderViewHost used to load a cross-site page. This remains hidden
-  // while a cross-site request is pending until it calls DidNavigate. It may
-  // have an associated Web UI, in which case the Web UI pointer will be non-
-  // NULL.
-  //
-  // The |pending_web_ui_| may be non-NULL even when the
-  // |pending_render_view_host_| is NULL. This will happen when we're
-  // transitioning between two Web UI pages: the RVH won't be swapped, so the
-  // pending pointer will be unused, but there will be a pending Web UI
-  // associated with the navigation.
-  RenderViewHostImpl* pending_render_view_host_;
-
-  // Tracks information about any current pending cross-process navigation.
-  scoped_ptr<PendingNavigationParams> pending_nav_params_;
-
-  // If either of these is non-NULL, the pending navigation is to a chrome:
-  // page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
-  // used for when they reference the same object. If either is non-NULL, the
-  // other should be NULL.
-  scoped_ptr<WebUIImpl> pending_web_ui_;
-  base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
-
-  // A map of site instance ID to swapped out RenderViewHosts.  This may include
-  // pending_render_view_host_ for navigations to existing entries.
-  typedef base::hash_map<int32, RenderViewHostImpl*> RenderViewHostMap;
-  RenderViewHostMap swapped_out_hosts_;
-
-  // The intersitial page currently shown if any, not own by this class
-  // (the InterstitialPage is self-owned, it deletes itself when hidden).
-  InterstitialPageImpl* interstitial_page_;
-
-  NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
diff --git a/content/browser/web_contents/render_view_host_manager_unittest.cc b/content/browser/web_contents/render_view_host_manager_unittest.cc
deleted file mode 100644
index 7888ada..0000000
--- a/content/browser/web_contents/render_view_host_manager_unittest.cc
+++ /dev/null
@@ -1,1308 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/renderer_host/test_render_view_host.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/web_contents/render_view_host_manager.h"
-#include "content/browser/webui/web_ui_controller_factory_registry.h"
-#include "content/common/view_messages.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host_observer.h"
-#include "content/public/browser/render_widget_host_iterator.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/common/bindings_policy.h"
-#include "content/public/common/javascript_message_type.h"
-#include "content/public/common/page_transition_types.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/common/url_utils.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_notification_tracker.h"
-#include "content/test/test_content_browser_client.h"
-#include "content/test/test_content_client.h"
-#include "content/test/test_web_contents.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-class RenderViewHostManagerTestWebUIControllerFactory
-    : public WebUIControllerFactory {
- public:
-  RenderViewHostManagerTestWebUIControllerFactory()
-    : should_create_webui_(false) {
-  }
-  virtual ~RenderViewHostManagerTestWebUIControllerFactory() {}
-
-  void set_should_create_webui(bool should_create_webui) {
-    should_create_webui_ = should_create_webui;
-  }
-
-  // WebUIFactory implementation.
-  virtual WebUIController* CreateWebUIControllerForURL(
-      WebUI* web_ui, const GURL& url) const OVERRIDE {
-    if (!(should_create_webui_ && HasWebUIScheme(url)))
-      return NULL;
-    return new WebUIController(web_ui);
-  }
-
-   virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-      const GURL& url) const OVERRIDE {
-    return WebUI::kNoWebUI;
-  }
-
-  virtual bool UseWebUIForURL(BrowserContext* browser_context,
-                              const GURL& url) const OVERRIDE {
-    return HasWebUIScheme(url);
-  }
-
-  virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                                      const GURL& url) const OVERRIDE {
-    return HasWebUIScheme(url);
-  }
-
- private:
-  bool should_create_webui_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostManagerTestWebUIControllerFactory);
-};
-
-class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
- public:
-  BeforeUnloadFiredWebContentsDelegate() {}
-  virtual ~BeforeUnloadFiredWebContentsDelegate() {}
-
-  virtual void BeforeUnloadFired(WebContents* web_contents,
-                                 bool proceed,
-                                 bool* proceed_to_fire_unload) OVERRIDE {
-    *proceed_to_fire_unload = proceed;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate);
-};
-
-}  // namespace
-
-class RenderViewHostManagerTest
-    : public RenderViewHostImplTestHarness {
- public:
-  virtual void SetUp() OVERRIDE {
-    RenderViewHostImplTestHarness::SetUp();
-    WebUIControllerFactory::RegisterFactory(&factory_);
-  }
-
-  virtual void TearDown() OVERRIDE {
-    RenderViewHostImplTestHarness::TearDown();
-    WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
-  }
-
-  void set_should_create_webui(bool should_create_webui) {
-    factory_.set_should_create_webui(should_create_webui);
-  }
-
-  void NavigateActiveAndCommit(const GURL& url) {
-    // Note: we navigate the active RenderViewHost because previous navigations
-    // won't have committed yet, so NavigateAndCommit does the wrong thing
-    // for us.
-    controller().LoadURL(url, Referrer(), PAGE_TRANSITION_LINK, std::string());
-    TestRenderViewHost* old_rvh = test_rvh();
-
-    // Simulate the ShouldClose_ACK that is received from the current renderer
-    // for a cross-site navigation.
-    if (old_rvh != active_rvh())
-      old_rvh->SendShouldCloseACK(true);
-
-    // Commit the navigation with a new page ID.
-    int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
-        active_rvh()->GetSiteInstance());
-
-    // Simulate the SwapOut_ACK that fires if you commit a cross-site
-    // navigation.
-    if (old_rvh != active_rvh())
-      old_rvh->OnSwappedOut(false);
-
-    active_test_rvh()->SendNavigate(max_page_id + 1, url);
-  }
-
-  bool ShouldSwapProcesses(RenderViewHostManager* manager,
-                           const NavigationEntryImpl* cur_entry,
-                           const NavigationEntryImpl* new_entry) const {
-    return manager->ShouldSwapProcessesForNavigation(cur_entry, new_entry);
-  }
-
-  // Creates a test RenderViewHost that's swapped out.
-  TestRenderViewHost* CreateSwappedOutRenderViewHost() {
-    const GURL kChromeURL("chrome://foo");
-    const GURL kDestUrl("http://www.google.com/");
-
-    // Navigate our first tab to a chrome url and then to the destination.
-    NavigateActiveAndCommit(kChromeURL);
-    TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-        contents()->GetRenderManagerForTesting()->current_host());
-
-    // Navigate to a cross-site URL.
-    contents()->GetController().LoadURL(
-        kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-    EXPECT_TRUE(contents()->cross_navigation_pending());
-
-    // Manually increase the number of active views in the
-    // SiteInstance that ntp_rvh belongs to, to prevent it from being
-    // destroyed when it gets swapped out.
-    static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
-        increment_active_view_count();
-
-    TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
-        contents()->GetRenderManagerForTesting()->pending_render_view_host());
-    CHECK(dest_rvh);
-    EXPECT_NE(ntp_rvh, dest_rvh);
-
-    // BeforeUnload finishes.
-    ntp_rvh->SendShouldCloseACK(true);
-
-    // Assume SwapOutACK times out, so the dest_rvh proceeds and commits.
-    dest_rvh->SendNavigate(101, kDestUrl);
-
-    EXPECT_TRUE(ntp_rvh->is_swapped_out());
-    return ntp_rvh;
-  }
-
- private:
-  RenderViewHostManagerTestWebUIControllerFactory factory_;
-};
-
-// Tests that when you navigate from a chrome:// url to another page, and
-// then do that same thing in another tab, that the two resulting pages have
-// different SiteInstances, BrowsingInstances, and RenderProcessHosts. This is
-// a regression test for bug 9364.
-TEST_F(RenderViewHostManagerTest, NewTabPageProcesses) {
-  set_should_create_webui(true);
-  const GURL kChromeUrl("chrome://foo");
-  const GURL kDestUrl("http://www.google.com/");
-
-  // Navigate our first tab to the chrome url and then to the destination,
-  // ensuring we grant bindings to the chrome URL.
-  NavigateActiveAndCommit(kChromeUrl);
-  EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-  NavigateActiveAndCommit(kDestUrl);
-
-  // Make a second tab.
-  scoped_ptr<TestWebContents> contents2(
-      TestWebContents::Create(browser_context(), NULL));
-
-  // Load the two URLs in the second tab. Note that the first navigation creates
-  // a RVH that's not pending (since there is no cross-site transition), so
-  // we use the committed one.
-  contents2->GetController().LoadURL(
-      kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  TestRenderViewHost* ntp_rvh2 = static_cast<TestRenderViewHost*>(
-      contents2->GetRenderManagerForTesting()->current_host());
-  EXPECT_FALSE(contents2->cross_navigation_pending());
-  ntp_rvh2->SendNavigate(100, kChromeUrl);
-
-  // The second one is the opposite, creating a cross-site transition and
-  // requiring a beforeunload ack.
-  contents2->GetController().LoadURL(
-      kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  EXPECT_TRUE(contents2->cross_navigation_pending());
-  TestRenderViewHost* dest_rvh2 = static_cast<TestRenderViewHost*>(
-      contents2->GetRenderManagerForTesting()->pending_render_view_host());
-  ASSERT_TRUE(dest_rvh2);
-
-  ntp_rvh2->SendShouldCloseACK(true);
-  ntp_rvh2->OnSwappedOut(false);
-  dest_rvh2->SendNavigate(101, kDestUrl);
-
-  // The two RVH's should be different in every way.
-  EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
-  EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
-  EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
-                   dest_rvh2->GetSiteInstance()));
-
-  // Navigate both to the new tab page, and verify that they share a
-  // RenderProcessHost (not a SiteInstance).
-  NavigateActiveAndCommit(kChromeUrl);
-
-  contents2->GetController().LoadURL(
-      kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  dest_rvh2->SendShouldCloseACK(true);
-  dest_rvh2->OnSwappedOut(false);
-  static_cast<TestRenderViewHost*>(contents2->GetRenderManagerForTesting()->
-     pending_render_view_host())->SendNavigate(102, kChromeUrl);
-
-  EXPECT_NE(active_rvh()->GetSiteInstance(),
-            contents2->GetRenderViewHost()->GetSiteInstance());
-  EXPECT_EQ(active_rvh()->GetSiteInstance()->GetProcess(),
-            contents2->GetRenderViewHost()->GetSiteInstance()->GetProcess());
-}
-
-// Ensure that the browser ignores most IPC messages that arrive from a
-// RenderViewHost that has been swapped out.  We do not want to take
-// action on requests from a non-active renderer.  The main exception is
-// for synchronous messages, which cannot be ignored without leaving the
-// renderer in a stuck state.  See http://crbug.com/93427.
-TEST_F(RenderViewHostManagerTest, FilterMessagesWhileSwappedOut) {
-  const GURL kChromeURL("chrome://foo");
-  const GURL kDestUrl("http://www.google.com/");
-
-  // Navigate our first tab to a chrome url and then to the destination.
-  NavigateActiveAndCommit(kChromeURL);
-  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->current_host());
-
-  // Send an update title message and make sure it works.
-  const string16 ntp_title = ASCIIToUTF16("NTP Title");
-  WebKit::WebTextDirection direction = WebKit::WebTextDirectionLeftToRight;
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
-  EXPECT_EQ(ntp_title, contents()->GetTitle());
-
-  // Navigate to a cross-site URL.
-  contents()->GetController().LoadURL(
-      kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->pending_render_view_host());
-  ASSERT_TRUE(dest_rvh);
-  EXPECT_NE(ntp_rvh, dest_rvh);
-
-  // Create one more view in the same SiteInstance where dest_rvh2
-  // exists so that it doesn't get deleted on navigation to another
-  // site.
-  static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
-      increment_active_view_count();
-
-  // BeforeUnload finishes.
-  ntp_rvh->SendShouldCloseACK(true);
-
-  // Assume SwapOutACK times out, so the dest_rvh proceeds and commits.
-  dest_rvh->SendNavigate(101, kDestUrl);
-
-  // The new RVH should be able to update its title.
-  const string16 dest_title = ASCIIToUTF16("Google");
-  EXPECT_TRUE(dest_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 101, dest_title,
-                              direction)));
-  EXPECT_EQ(dest_title, contents()->GetTitle());
-
-  // The old renderer, being slow, now updates the title. It should be filtered
-  // out and not take effect.
-  EXPECT_TRUE(ntp_rvh->is_swapped_out());
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
-  EXPECT_EQ(dest_title, contents()->GetTitle());
-
-  // We cannot filter out synchronous IPC messages, because the renderer would
-  // be left waiting for a reply.  We pick RunBeforeUnloadConfirm as an example
-  // that can run easily within a unit test, and that needs to receive a reply
-  // without showing an actual dialog.
-  MockRenderProcessHost* ntp_process_host =
-      static_cast<MockRenderProcessHost*>(ntp_rvh->GetProcess());
-  ntp_process_host->sink().ClearMessages();
-  const string16 msg = ASCIIToUTF16("Message");
-  bool result = false;
-  string16 unused;
-  ViewHostMsg_RunBeforeUnloadConfirm before_unload_msg(
-      rvh()->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
-  // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
-  before_unload_msg.EnableMessagePumping();
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(before_unload_msg));
-  EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
-
-  // Also test RunJavaScriptMessage.
-  ntp_process_host->sink().ClearMessages();
-  ViewHostMsg_RunJavaScriptMessage js_msg(
-      rvh()->GetRoutingID(), msg, msg, kChromeURL,
-      JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
-  js_msg.EnableMessagePumping();
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(js_msg));
-  EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
-}
-
-TEST_F(RenderViewHostManagerTest, WhiteListSwapCompositorFrame) {
-  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
-  TestRenderWidgetHostView* swapped_out_rwhv =
-      static_cast<TestRenderWidgetHostView*>(swapped_out_rvh->GetView());
-  EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
-
-  MockRenderProcessHost* process_host =
-      static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
-  process_host->sink().ClearMessages();
-
-  cc::CompositorFrame frame;
-  ViewHostMsg_SwapCompositorFrame msg(rvh()->GetRoutingID(), 0, frame);
-
-  EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
-  EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
-}
-
-TEST_F(RenderViewHostManagerTest, WhiteListDidActivateAcceleratedCompositing) {
-  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
-
-  MockRenderProcessHost* process_host =
-      static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
-  process_host->sink().ClearMessages();
-  ViewHostMsg_DidActivateAcceleratedCompositing msg(
-      rvh()->GetRoutingID(), true);
-  EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
-  EXPECT_TRUE(swapped_out_rvh->is_accelerated_compositing_active());
-}
-
-// Test if RenderViewHost::GetRenderWidgetHosts() only returns active
-// widgets.
-TEST_F(RenderViewHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
-  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
-  EXPECT_TRUE(swapped_out_rvh->is_swapped_out());
-
-  scoped_ptr<RenderWidgetHostIterator> widgets(
-      RenderWidgetHost::GetRenderWidgetHosts());
-  // We know that there is the only one active widget. Another view is
-  // now swapped out, so the swapped out view is not included in the
-  // list.
-  RenderWidgetHost* widget = widgets->GetNextHost();
-  EXPECT_FALSE(widgets->GetNextHost());
-  RenderViewHost* rvh = RenderViewHost::From(widget);
-  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(rvh)->is_swapped_out());
-}
-
-// Test if RenderViewHost::GetRenderWidgetHosts() returns a subset of
-// RenderViewHostImpl::GetAllRenderWidgetHosts().
-// RenderViewHost::GetRenderWidgetHosts() returns only active widgets, but
-// RenderViewHostImpl::GetAllRenderWidgetHosts() returns everything
-// including swapped out ones.
-TEST_F(RenderViewHostManagerTest,
-       GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
-  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
-  EXPECT_TRUE(swapped_out_rvh->is_swapped_out());
-
-  scoped_ptr<RenderWidgetHostIterator> widgets(
-      RenderWidgetHost::GetRenderWidgetHosts());
-
-  while (RenderWidgetHost* w = widgets->GetNextHost()) {
-    bool found = false;
-    scoped_ptr<RenderWidgetHostIterator> all_widgets(
-        RenderWidgetHostImpl::GetAllRenderWidgetHosts());
-    while (RenderWidgetHost* widget = all_widgets->GetNextHost()) {
-      if (w == widget) {
-        found = true;
-        break;
-      }
-    }
-    EXPECT_TRUE(found);
-  }
-}
-
-// Test if SiteInstanceImpl::active_view_count() is correctly updated
-// as views in a SiteInstance get swapped out and in.
-TEST_F(RenderViewHostManagerTest, ActiveViewCountWhileSwappingInandOut) {
-  const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
-
-  // Navigate to an initial URL.
-  contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-
-  SiteInstanceImpl* instance1 =
-      static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance());
-  EXPECT_EQ(instance1->active_view_count(), 1U);
-
-  // Create 2 new tabs and simulate them being the opener chain for the main
-  // tab.  They should be in the same SiteInstance.
-  scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), instance1));
-  contents()->SetOpener(opener1.get());
-
-  scoped_ptr<TestWebContents> opener2(
-      TestWebContents::Create(browser_context(), instance1));
-  opener1->SetOpener(opener2.get());
-
-  EXPECT_EQ(instance1->active_view_count(), 3U);
-
-  // Navigate to a cross-site URL (different SiteInstance but same
-  // BrowsingInstance).
-  contents()->NavigateAndCommit(kUrl2);
-  TestRenderViewHost* rvh2 = test_rvh();
-  SiteInstanceImpl* instance2 =
-      static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance());
-
-  // rvh2 is on chromium.org which is different from google.com on
-  // which other tabs are.
-  EXPECT_EQ(instance2->active_view_count(), 1U);
-
-  // There are two active views on google.com now.
-  EXPECT_EQ(instance1->active_view_count(), 2U);
-
-  // Navigate to the original origin (google.com).
-  contents()->NavigateAndCommit(kUrl1);
-
-  EXPECT_EQ(instance1->active_view_count(), 3U);
-}
-
-// This deletes a WebContents when the given RVH is deleted. This is
-// only for testing whether deleting an RVH does not cause any UaF in
-// other parts of the system. For now, this class is only used for the
-// next test cases to detect the bug mentioned at
-// http://crbug.com/259859.
-class RenderViewHostDestroyer : public content::RenderViewHostObserver {
- public:
-  RenderViewHostDestroyer(RenderViewHost* render_view_host,
-                          WebContents* web_contents)
-      : content::RenderViewHostObserver(render_view_host),
-        web_contents_(web_contents) {}
-
-  virtual void RenderViewHostDestroyed(RenderViewHost* render_view_host)
-      OVERRIDE {
-    delete web_contents_;
-  }
-
- private:
-  WebContents* web_contents_;
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestroyer);
-};
-
-// Test if ShutdownRenderViewHostsInSiteInstance() does not touch any
-// RenderWidget that has been freed while deleting a RenderViewHost in
-// a previous iteration. This is a regression test for
-// http://crbug.com/259859.
-TEST_F(RenderViewHostManagerTest,
-       DetectUseAfterFreeInShutdownRenderViewHostsInSiteInstance) {
-  const GURL kChromeURL("chrome://newtab");
-  const GURL kUrl1("http://www.google.com");
-  const GURL kUrl2("http://www.chromium.org");
-
-  // Navigate our first tab to a chrome url and then to the destination.
-  NavigateActiveAndCommit(kChromeURL);
-  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->current_host());
-
-  // Create one more tab and navigate to kUrl1.  web_contents is not
-  // wrapped as scoped_ptr since it intentionally deleted by destroyer
-  // below as part of this test.
-  TestWebContents* web_contents =
-      TestWebContents::Create(browser_context(), ntp_rvh->GetSiteInstance());
-  web_contents->NavigateAndCommit(kUrl1);
-  RenderViewHostDestroyer destroyer(ntp_rvh, web_contents);
-
-  // This causes the first tab to navigate to kUrl2, which destroys
-  // the ntp_rvh in ShutdownRenderViewHostsInSiteInstance(). When
-  // ntp_rvh is destroyed, it also destroys the RVHs in web_contents
-  // too. This can test whether
-  // SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
-  // touch any object freed in this way or not while iterating through
-  // all widgets.
-  contents()->NavigateAndCommit(kUrl2);
-}
-
-// When there is an error with the specified page, renderer exits view-source
-// mode. See WebFrameImpl::DidFail(). We check by this test that
-// EnableViewSourceMode message is sent on every navigation regardless
-// RenderView is being newly created or reused.
-TEST_F(RenderViewHostManagerTest, AlwaysSendEnableViewSourceMode) {
-  const GURL kChromeUrl("chrome://foo");
-  const GURL kUrl("view-source:http://foo");
-
-  // We have to navigate to some page at first since without this, the first
-  // navigation will reuse the SiteInstance created by Init(), and the second
-  // one will create a new SiteInstance. Because current_instance and
-  // new_instance will be different, a new RenderViewHost will be created for
-  // the second navigation. We have to avoid this in order to exercise the
-  // target code patch.
-  NavigateActiveAndCommit(kChromeUrl);
-
-  // Navigate.
-  controller().LoadURL(
-      kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  // Simulate response from RenderView for FirePageBeforeUnload.
-  base::TimeTicks now = base::TimeTicks::Now();
-  test_rvh()->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(
-      rvh()->GetRoutingID(), true, now, now));
-  ASSERT_TRUE(pending_rvh());  // New pending RenderViewHost will be created.
-  RenderViewHost* last_rvh = pending_rvh();
-  int32 new_id = contents()->GetMaxPageIDForSiteInstance(
-      active_rvh()->GetSiteInstance()) + 1;
-  pending_test_rvh()->SendNavigate(new_id, kUrl);
-  EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
-  ASSERT_TRUE(controller().GetLastCommittedEntry());
-  EXPECT_TRUE(kUrl == controller().GetLastCommittedEntry()->GetURL());
-  EXPECT_FALSE(controller().GetPendingEntry());
-  // Because we're using TestWebContents and TestRenderViewHost in this
-  // unittest, no one calls WebContentsImpl::RenderViewCreated(). So, we see no
-  // EnableViewSourceMode message, here.
-
-  // Clear queued messages before load.
-  process()->sink().ClearMessages();
-  // Navigate, again.
-  controller().LoadURL(
-      kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  // The same RenderViewHost should be reused.
-  EXPECT_FALSE(pending_rvh());
-  EXPECT_TRUE(last_rvh == rvh());
-  test_rvh()->SendNavigate(new_id, kUrl);  // The same page_id returned.
-  EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
-  EXPECT_FALSE(controller().GetPendingEntry());
-  // New message should be sent out to make sure to enter view-source mode.
-  EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
-      ViewMsg_EnableViewSourceMode::ID));
-}
-
-// Tests the Init function by checking the initial RenderViewHost.
-TEST_F(RenderViewHostManagerTest, Init) {
-  // Using TestBrowserContext.
-  SiteInstanceImpl* instance =
-      static_cast<SiteInstanceImpl*>(SiteInstance::Create(browser_context()));
-  EXPECT_FALSE(instance->HasSite());
-
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-
-  RenderViewHost* host = manager.current_host();
-  ASSERT_TRUE(host);
-  EXPECT_EQ(instance, host->GetSiteInstance());
-  EXPECT_EQ(web_contents.get(), host->GetDelegate());
-  EXPECT_TRUE(manager.GetRenderWidgetHostView());
-  EXPECT_FALSE(manager.pending_render_view_host());
-}
-
-// Tests the Navigate function. We navigate three sites consecutively and check
-// how the pending/committed RenderViewHost are modified.
-TEST_F(RenderViewHostManagerTest, Navigate) {
-  TestNotificationTracker notifications;
-
-  SiteInstance* instance = SiteInstance::Create(browser_context());
-
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                          Source<WebContents>(web_contents.get()));
-
-  // Create.
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-
-  RenderViewHost* host;
-
-  // 1) The first navigation. --------------------------
-  const GURL kUrl1("http://www.google.com/");
-  NavigationEntryImpl entry1(
-      NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
-      string16() /* title */, PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */);
-  host = manager.Navigate(entry1);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_TRUE(host == manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-  // Commit to SiteInstance should be delayed until RenderView commit.
-  EXPECT_TRUE(host == manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
-
-  // 2) Navigate to next site. -------------------------
-  const GURL kUrl2("http://www.google.com/foo");
-  NavigationEntryImpl entry2(
-      NULL /* instance */, -1 /* page_id */, kUrl2,
-      Referrer(kUrl1, WebKit::WebReferrerPolicyDefault),
-      string16() /* title */, PAGE_TRANSITION_LINK,
-      true /* is_renderer_init */);
-  host = manager.Navigate(entry2);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_TRUE(host == manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-  EXPECT_TRUE(host == manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-
-  // 3) Cross-site navigate to next site. --------------
-  const GURL kUrl3("http://webkit.org/");
-  NavigationEntryImpl entry3(
-      NULL /* instance */, -1 /* page_id */, kUrl3,
-      Referrer(kUrl2, WebKit::WebReferrerPolicyDefault),
-      string16() /* title */, PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */);
-  host = manager.Navigate(entry3);
-
-  // A new RenderViewHost should be created.
-  EXPECT_TRUE(manager.pending_render_view_host());
-  ASSERT_EQ(host, manager.pending_render_view_host());
-
-  notifications.Reset();
-
-  // Commit.
-  manager.DidNavigateMainFrame(manager.pending_render_view_host());
-  EXPECT_TRUE(host == manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-  // Check the pending RenderViewHost has been committed.
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-}
-
-// Tests the Navigate function. In this unit test we verify that the Navigate
-// function can handle a new navigation event before the previous navigation
-// has been committed. This is also a regression test for
-// http://crbug.com/104600.
-TEST_F(RenderViewHostManagerTest, NavigateWithEarlyReNavigation) {
-  TestNotificationTracker notifications;
-
-  SiteInstance* instance = SiteInstance::Create(browser_context());
-
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                          Source<WebContents>(web_contents.get()));
-
-  // Create.
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-
-  // 1) The first navigation. --------------------------
-  const GURL kUrl1("http://www.google.com/");
-  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
-                             Referrer(), string16() /* title */,
-                             PAGE_TRANSITION_TYPED,
-                             false /* is_renderer_init */);
-  RenderViewHost* host = manager.Navigate(entry1);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_TRUE(host == manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-  notifications.Reset();
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-
-  // Commit to SiteInstance should be delayed until RenderView commit.
-  EXPECT_TRUE(host == manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
-
-  // 2) Cross-site navigate to next site. -------------------------
-  const GURL kUrl2("http://www.example.com");
-  NavigationEntryImpl entry2(
-      NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
-      string16() /* title */, PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */);
-  RenderViewHostImpl* host2 = static_cast<RenderViewHostImpl*>(
-      manager.Navigate(entry2));
-  int host2_process_id = host2->GetProcess()->GetID();
-
-  // A new RenderViewHost should be created.
-  EXPECT_TRUE(manager.pending_render_view_host());
-  ASSERT_EQ(host2, manager.pending_render_view_host());
-  EXPECT_NE(host2, host);
-
-  // Check that the navigation is still suspended because the old RVH
-  // is not swapped out, yet.
-  EXPECT_TRUE(host2->are_navigations_suspended());
-  MockRenderProcessHost* test_process_host2 =
-      static_cast<MockRenderProcessHost*>(host2->GetProcess());
-  test_process_host2->sink().ClearMessages();
-  host2->NavigateToURL(kUrl2);
-  EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
-      ViewMsg_Navigate::ID));
-
-  // Allow closing the current Render View (precondition for swapping out
-  // the RVH): Simulate response from RenderView for ViewMsg_ShouldClose sent by
-  // FirePageBeforeUnload.
-  TestRenderViewHost* test_host = static_cast<TestRenderViewHost*>(host);
-  MockRenderProcessHost* test_process_host =
-      static_cast<MockRenderProcessHost*>(test_host->GetProcess());
-  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_ShouldClose::ID));
-  test_host->SendShouldCloseACK(true);
-
-  // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
-  // call of RenderViewHostManager::SwapOutOldPage before
-  // RenderViewHostManager::DidNavigateMainFrame is called.
-  // The RVH is not swapped out until the commit.
-  manager.SwapOutOldPage();
-  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_SwapOut::ID));
-  test_host->OnSwappedOut(false);
-
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
-      manager.current_host())->is_swapped_out());
-  EXPECT_EQ(host2, manager.pending_render_view_host());
-  // There should be still no navigation messages being sent.
-  EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
-      ViewMsg_Navigate::ID));
-
-  // 3) Cross-site navigate to next site before 2) has committed. --------------
-  const GURL kUrl3("http://webkit.org/");
-  NavigationEntryImpl entry3(NULL /* instance */, -1 /* page_id */, kUrl3,
-                             Referrer(), string16() /* title */,
-                             PAGE_TRANSITION_TYPED,
-                             false /* is_renderer_init */);
-  test_process_host->sink().ClearMessages();
-  RenderViewHost* host3 = manager.Navigate(entry3);
-
-  // A new RenderViewHost should be created. host2 is now deleted.
-  EXPECT_TRUE(manager.pending_render_view_host());
-  ASSERT_EQ(host3, manager.pending_render_view_host());
-  EXPECT_NE(host3, host);
-  EXPECT_NE(host3->GetProcess()->GetID(), host2_process_id);
-
-  // Navigations in the new RVH should be suspended, which is ok because the
-  // old RVH is not yet swapped out and can respond to a second beforeunload
-  // request.
-  EXPECT_TRUE(static_cast<RenderViewHostImpl*>(
-      host3)->are_navigations_suspended());
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
-      manager.current_host())->is_swapped_out());
-
-  // Simulate a response to the second beforeunload request.
-  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_ShouldClose::ID));
-  test_host->SendShouldCloseACK(true);
-
-  // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
-  // call of RenderViewHostManager::SwapOutOldPage before
-  // RenderViewHostManager::DidNavigateMainFrame is called.
-  // The RVH is not swapped out until the commit.
-  manager.SwapOutOldPage();
-  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_SwapOut::ID));
-  test_host->OnSwappedOut(false);
-
-  // Commit.
-  manager.DidNavigateMainFrame(host3);
-  EXPECT_TRUE(host3 == manager.current_host());
-  ASSERT_TRUE(host3);
-  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host3->GetSiteInstance())->
-      HasSite());
-  // Check the pending RenderViewHost has been committed.
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-}
-
-// Tests WebUI creation.
-TEST_F(RenderViewHostManagerTest, WebUI) {
-  set_should_create_webui(true);
-  SiteInstance* instance = SiteInstance::Create(browser_context());
-
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-  EXPECT_FALSE(manager.current_host()->IsRenderViewLive());
-
-  const GURL kUrl("chrome://foo");
-  NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
-                            Referrer(), string16() /* title */,
-                            PAGE_TRANSITION_TYPED,
-                            false /* is_renderer_init */);
-  RenderViewHost* host = manager.Navigate(entry);
-
-  // We commit the pending RenderViewHost immediately because the previous
-  // RenderViewHost was not live.  We test a case where it is live in
-  // WebUIInNewTab.
-  EXPECT_TRUE(host);
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // It's important that the site instance get set on the Web UI page as soon
-  // as the navigation starts, rather than lazily after it commits, so we don't
-  // try to re-use the SiteInstance/process for non Web UI things that may
-  // get loaded in between.
-  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-  EXPECT_EQ(kUrl, host->GetSiteInstance()->GetSiteURL());
-
-  // The Web UI is committed immediately because the RenderViewHost has not been
-  // used yet. UpdateRendererStateForNavigate() took the short cut path.
-  EXPECT_FALSE(manager.pending_web_ui());
-  EXPECT_TRUE(manager.web_ui());
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-  EXPECT_TRUE(host->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-}
-
-// Tests that we can open a WebUI link in a new tab from a WebUI page and still
-// grant the correct bindings.  http://crbug.com/189101.
-TEST_F(RenderViewHostManagerTest, WebUIInNewTab) {
-  set_should_create_webui(true);
-  SiteInstance* blank_instance = SiteInstance::Create(browser_context());
-
-  // Create a blank tab.
-  scoped_ptr<TestWebContents> web_contents1(
-      TestWebContents::Create(browser_context(), blank_instance));
-  RenderViewHostManager manager1(web_contents1.get(), web_contents1.get(),
-                                 web_contents1.get());
-  manager1.Init(
-      browser_context(), blank_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-  // Test the case that new RVH is considered live.
-  manager1.current_host()->CreateRenderView(string16(), -1, -1);
-
-  // Navigate to a WebUI page.
-  const GURL kUrl1("chrome://foo");
-  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
-                             Referrer(), string16() /* title */,
-                             PAGE_TRANSITION_TYPED,
-                             false /* is_renderer_init */);
-  RenderViewHost* host1 = manager1.Navigate(entry1);
-
-  // We should have a pending navigation to the WebUI RenderViewHost.
-  // It should already have bindings.
-  EXPECT_EQ(host1, manager1.pending_render_view_host());
-  EXPECT_NE(host1, manager1.current_host());
-  EXPECT_TRUE(host1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-
-  // Commit and ensure we still have bindings.
-  manager1.DidNavigateMainFrame(host1);
-  SiteInstance* webui_instance = host1->GetSiteInstance();
-  EXPECT_EQ(host1, manager1.current_host());
-  EXPECT_TRUE(host1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-
-  // Now simulate clicking a link that opens in a new tab.
-  scoped_ptr<TestWebContents> web_contents2(
-      TestWebContents::Create(browser_context(), webui_instance));
-  RenderViewHostManager manager2(web_contents2.get(), web_contents2.get(),
-                                 web_contents2.get());
-  manager2.Init(
-      browser_context(), webui_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-  // Make sure the new RVH is considered live.  This is usually done in
-  // RenderWidgetHost::Init when opening a new tab from a link.
-  manager2.current_host()->CreateRenderView(string16(), -1, -1);
-
-  const GURL kUrl2("chrome://foo/bar");
-  NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
-                             Referrer(), string16() /* title */,
-                             PAGE_TRANSITION_LINK,
-                             true /* is_renderer_init */);
-  RenderViewHost* host2 = manager2.Navigate(entry2);
-
-  // No cross-process transition happens because we are already in the right
-  // SiteInstance.  We should grant bindings immediately.
-  EXPECT_EQ(host2, manager2.current_host());
-  EXPECT_TRUE(host2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-
-  manager2.DidNavigateMainFrame(host2);
-}
-
-// Tests that we don't end up in an inconsistent state if a page does a back and
-// then reload. http://crbug.com/51680
-TEST_F(RenderViewHostManagerTest, PageDoesBackAndReload) {
-  const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.evil-site.com/");
-
-  // Navigate to a safe site, then an evil site.
-  // This will switch RenderViewHosts.  We cannot assert that the first and
-  // second RVHs are different, though, because the first one may be promptly
-  // deleted.
-  contents()->NavigateAndCommit(kUrl1);
-  contents()->NavigateAndCommit(kUrl2);
-  RenderViewHost* evil_rvh = contents()->GetRenderViewHost();
-
-  // Now let's simulate the evil page calling history.back().
-  contents()->OnGoToEntryAtOffset(-1);
-  // We should have a new pending RVH.
-  // Note that in this case, the navigation has not committed, so evil_rvh will
-  // not be deleted yet.
-  EXPECT_NE(evil_rvh, contents()->GetRenderManagerForTesting()->
-      pending_render_view_host());
-
-  // Before that RVH has committed, the evil page reloads itself.
-  ViewHostMsg_FrameNavigate_Params params;
-  params.page_id = 1;
-  params.url = kUrl2;
-  params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
-  params.should_update_history = false;
-  params.gesture = NavigationGestureAuto;
-  params.was_within_same_page = false;
-  params.is_post = false;
-  params.page_state = PageState::CreateFromURL(kUrl2);
-  contents()->DidNavigate(evil_rvh, params);
-
-  // That should have cancelled the pending RVH, and the evil RVH should be the
-  // current one.
-  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
-      pending_render_view_host() == NULL);
-  EXPECT_EQ(evil_rvh, contents()->GetRenderManagerForTesting()->current_host());
-
-  // Also we should not have a pending navigation entry.
-  EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
-  NavigationEntry* entry = contents()->GetController().GetVisibleEntry();
-  ASSERT_TRUE(entry != NULL);
-  EXPECT_EQ(kUrl2, entry->GetURL());
-}
-
-// Ensure that we can go back and forward even if a SwapOut ACK isn't received.
-// See http://crbug.com/93427.
-TEST_F(RenderViewHostManagerTest, NavigateAfterMissingSwapOutACK) {
-  const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
-
-  // Navigate to two pages.
-  contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-
-  // Keep active_view_count nonzero so that no swapped out views in
-  // this SiteInstance get forcefully deleted.
-  static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
-      increment_active_view_count();
-
-  contents()->NavigateAndCommit(kUrl2);
-  TestRenderViewHost* rvh2 = test_rvh();
-  static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
-      increment_active_view_count();
-
-  // Now go back, but suppose the SwapOut_ACK isn't received.  This shouldn't
-  // happen, but we have seen it when going back quickly across many entries
-  // (http://crbug.com/93427).
-  contents()->GetController().GoBack();
-  EXPECT_TRUE(rvh2->is_waiting_for_beforeunload_ack());
-  contents()->ProceedWithCrossSiteNavigation();
-  EXPECT_FALSE(rvh2->is_waiting_for_beforeunload_ack());
-  rvh2->SwapOut();
-  EXPECT_TRUE(rvh2->is_waiting_for_unload_ack());
-
-  // The back navigation commits.  We should proactively clear the
-  // is_waiting_for_unload_ack state to be safe.
-  const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
-  rvh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
-  EXPECT_TRUE(rvh2->is_swapped_out());
-  EXPECT_FALSE(rvh2->is_waiting_for_unload_ack());
-
-  // We should be able to navigate forward.
-  contents()->GetController().GoForward();
-  contents()->ProceedWithCrossSiteNavigation();
-  const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
-  rvh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
-  EXPECT_EQ(rvh2, rvh());
-  EXPECT_FALSE(rvh2->is_swapped_out());
-  EXPECT_TRUE(rvh1->is_swapped_out());
-}
-
-// Test that we create swapped out RVHs for the opener chain when navigating an
-// opened tab cross-process.  This allows us to support certain cross-process
-// JavaScript calls (http://crbug.com/99202).
-TEST_F(RenderViewHostManagerTest, CreateSwappedOutOpenerRVHs) {
-  const GURL kUrl1("http://www.google.com/");
-  const GURL kUrl2("http://www.chromium.org/");
-  const GURL kChromeUrl("chrome://foo");
-
-  // Navigate to an initial URL.
-  contents()->NavigateAndCommit(kUrl1);
-  RenderViewHostManager* manager = contents()->GetRenderManagerForTesting();
-  TestRenderViewHost* rvh1 = test_rvh();
-
-  // Create 2 new tabs and simulate them being the opener chain for the main
-  // tab.  They should be in the same SiteInstance.
-  scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
-  RenderViewHostManager* opener1_manager =
-      opener1->GetRenderManagerForTesting();
-  contents()->SetOpener(opener1.get());
-
-  scoped_ptr<TestWebContents> opener2(
-      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
-  RenderViewHostManager* opener2_manager =
-      opener2->GetRenderManagerForTesting();
-  opener1->SetOpener(opener2.get());
-
-  // Navigate to a cross-site URL (different SiteInstance but same
-  // BrowsingInstance).
-  contents()->NavigateAndCommit(kUrl2);
-  TestRenderViewHost* rvh2 = test_rvh();
-  EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
-  EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
-                  rvh2->GetSiteInstance()));
-
-  // Ensure rvh1 is placed on swapped out list of the current tab.
-  EXPECT_TRUE(manager->IsOnSwappedOutList(rvh1));
-  EXPECT_EQ(rvh1,
-            manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
-
-  // Ensure a swapped out RVH is created in the first opener tab.
-  TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
-      opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rvh));
-  EXPECT_TRUE(opener1_rvh->is_swapped_out());
-
-  // Ensure a swapped out RVH is created in the second opener tab.
-  TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
-      opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rvh));
-  EXPECT_TRUE(opener2_rvh->is_swapped_out());
-
-  // Navigate to a cross-BrowsingInstance URL.
-  contents()->NavigateAndCommit(kChromeUrl);
-  TestRenderViewHost* rvh3 = test_rvh();
-  EXPECT_NE(rvh1->GetSiteInstance(), rvh3->GetSiteInstance());
-  EXPECT_FALSE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
-                   rvh3->GetSiteInstance()));
-
-  // No scripting is allowed across BrowsingInstances, so we should not create
-  // swapped out RVHs for the opener chain in this case.
-  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
-                   rvh3->GetSiteInstance()));
-  EXPECT_FALSE(opener2_manager->GetSwappedOutRenderViewHost(
-                   rvh3->GetSiteInstance()));
-}
-
-// Test that we clean up swapped out RenderViewHosts when a process hosting
-// those associated RenderViews crashes. http://crbug.com/258993
-TEST_F(RenderViewHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
-  const GURL kUrl1("http://www.google.com/");
-
-  // Navigate to an initial URL.
-  contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-
-  // Create a new tab as an opener for the main tab.
-  scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
-  RenderViewHostManager* opener1_manager =
-      opener1->GetRenderManagerForTesting();
-  contents()->SetOpener(opener1.get());
-
-  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
-      rvh1->GetSiteInstance()));
-  opener1->CreateSwappedOutRenderView(rvh1->GetSiteInstance());
-  EXPECT_TRUE(opener1_manager->GetSwappedOutRenderViewHost(
-      rvh1->GetSiteInstance()));
-
-  // Fake a process crash.
-  RenderProcessHost::RendererClosedDetails details(
-      rvh1->GetProcess()->GetHandle(),
-      base::TERMINATION_STATUS_PROCESS_CRASHED,
-      0);
-  NotificationService::current()->Notify(
-      NOTIFICATION_RENDERER_PROCESS_CLOSED,
-      Source<RenderProcessHost>(rvh1->GetProcess()),
-      Details<RenderProcessHost::RendererClosedDetails>(&details));
-  rvh1->set_render_view_created(false);
-
-  // Ensure that the swapped out RenderViewHost has been deleted.
-  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
-      rvh1->GetSiteInstance()));
-
-  // Reload the initial tab. This should recreate the opener.
-  contents()->GetController().Reload(true);
-
-  EXPECT_EQ(opener1_manager->current_host()->GetRoutingID(),
-            test_rvh()->opener_route_id());
-}
-
-// Test that RenderViewHosts created for WebUI navigations are properly
-// granted WebUI bindings even if an unprivileged swapped out RenderViewHost
-// is in the same process (http://crbug.com/79918).
-TEST_F(RenderViewHostManagerTest, EnableWebUIWithSwappedOutOpener) {
-  set_should_create_webui(true);
-  const GURL kSettingsUrl("chrome://chrome/settings");
-  const GURL kPluginUrl("chrome://plugins");
-
-  // Navigate to an initial WebUI URL.
-  contents()->NavigateAndCommit(kSettingsUrl);
-
-  // Ensure the RVH has WebUI bindings.
-  TestRenderViewHost* rvh1 = test_rvh();
-  EXPECT_TRUE(rvh1->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-
-  // Create a new tab and simulate it being the opener for the main
-  // tab.  It should be in the same SiteInstance.
-  scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
-  RenderViewHostManager* opener1_manager =
-      opener1->GetRenderManagerForTesting();
-  contents()->SetOpener(opener1.get());
-
-  // Navigate to a different WebUI URL (different SiteInstance, same
-  // BrowsingInstance).
-  contents()->NavigateAndCommit(kPluginUrl);
-  TestRenderViewHost* rvh2 = test_rvh();
-  EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
-  EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
-                  rvh2->GetSiteInstance()));
-
-  // Ensure a swapped out RVH is created in the first opener tab.
-  TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
-      opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rvh));
-  EXPECT_TRUE(opener1_rvh->is_swapped_out());
-
-  // Ensure the new RVH has WebUI bindings.
-  EXPECT_TRUE(rvh2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
-}
-
-// Test that we reuse the same guest SiteInstance if we navigate across sites.
-TEST_F(RenderViewHostManagerTest, NoSwapOnGuestNavigations) {
-  TestNotificationTracker notifications;
-
-  GURL guest_url(std::string(kGuestScheme).append("://abc123"));
-  SiteInstance* instance =
-      SiteInstance::CreateForURL(browser_context(), guest_url);
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-
-  // Create.
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-
-  RenderViewHost* host;
-
-  // 1) The first navigation. --------------------------
-  const GURL kUrl1("http://www.google.com/");
-  NavigationEntryImpl entry1(
-      NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
-      string16() /* title */, PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */);
-  host = manager.Navigate(entry1);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_TRUE(host == manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-  EXPECT_EQ(manager.current_host()->GetSiteInstance(), instance);
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-  // Commit to SiteInstance should be delayed until RenderView commit.
-  EXPECT_EQ(host, manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-
-  // 2) Navigate to a different domain. -------------------------
-  // Guests stay in the same process on navigation.
-  const GURL kUrl2("http://www.chromium.org");
-  NavigationEntryImpl entry2(
-      NULL /* instance */, -1 /* page_id */, kUrl2,
-      Referrer(kUrl1, WebKit::WebReferrerPolicyDefault),
-      string16() /* title */, PAGE_TRANSITION_LINK,
-      true /* is_renderer_init */);
-  host = manager.Navigate(entry2);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-  EXPECT_EQ(host, manager.current_host());
-  ASSERT_TRUE(host);
-  EXPECT_EQ(static_cast<SiteInstanceImpl*>(host->GetSiteInstance()),
-      instance);
-}
-
-// Test that we cancel a pending RVH if we close the tab while it's pending.
-// http://crbug.com/294697.
-TEST_F(RenderViewHostManagerTest, NavigateWithEarlyClose) {
-  TestNotificationTracker notifications;
-
-  SiteInstance* instance = SiteInstance::Create(browser_context());
-
-  BeforeUnloadFiredWebContentsDelegate delegate;
-  scoped_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
-  web_contents->SetDelegate(&delegate);
-  notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                          Source<WebContents>(web_contents.get()));
-
-  // Create.
-  RenderViewHostManager manager(web_contents.get(), web_contents.get(),
-                                web_contents.get());
-
-  manager.Init(browser_context(), instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
-
-  // 1) The first navigation. --------------------------
-  const GURL kUrl1("http://www.google.com/");
-  NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
-                             Referrer(), string16() /* title */,
-                             PAGE_TRANSITION_TYPED,
-                             false /* is_renderer_init */);
-  RenderViewHost* host = manager.Navigate(entry1);
-
-  // The RenderViewHost created in Init will be reused.
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(manager.pending_render_view_host());
-
-  // We should observe a notification.
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-  notifications.Reset();
-
-  // Commit.
-  manager.DidNavigateMainFrame(host);
-
-  // Commit to SiteInstance should be delayed until RenderView commit.
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
-      HasSite());
-  static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
-
-  // 2) Cross-site navigate to next site. -------------------------
-  const GURL kUrl2("http://www.example.com");
-  NavigationEntryImpl entry2(
-      NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
-      string16() /* title */, PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */);
-  RenderViewHostImpl* host2 = static_cast<RenderViewHostImpl*>(
-      manager.Navigate(entry2));
-
-  // A new RenderViewHost should be created.
-  ASSERT_EQ(host2, manager.pending_render_view_host());
-  EXPECT_NE(host2, host);
-
-  EXPECT_EQ(host, manager.current_host());
-  EXPECT_FALSE(static_cast<RenderViewHostImpl*>(
-      manager.current_host())->is_swapped_out());
-  EXPECT_EQ(host2, manager.pending_render_view_host());
-
-  // 3) Close the tab. -------------------------
-  notifications.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-                          Source<RenderWidgetHost>(host2));
-  manager.ShouldClosePage(false, true, base::TimeTicks());
-
-  EXPECT_TRUE(
-      notifications.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED));
-  EXPECT_FALSE(manager.pending_render_view_host());
-  EXPECT_EQ(host, manager.current_host());
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc b/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
index 2cc1e99..4290e57 100644
--- a/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
+++ b/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
@@ -28,7 +28,6 @@
 
 namespace content {
 
-// TODO(mohsen): Remove logs if the test showed no flakiness anymore.
 class TestTouchEditableImplAura : public TouchEditableImplAura {
  public:
   TestTouchEditableImplAura()
@@ -37,62 +36,29 @@
         gesture_ack_callback_arrived_(false),
         waiting_for_gesture_ack_callback_(false) {}
 
-  void Reset() {
-    LOG(INFO) << "TestTouchEditableImplAura::Reset()";
+  virtual void Reset() {
     selection_changed_callback_arrived_ = false;
     waiting_for_selection_changed_callback_ = false;
     gesture_ack_callback_arrived_ = false;
     waiting_for_gesture_ack_callback_ = false;
   }
 
-  virtual void StartTouchEditing() OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::StartTouchEditing()";
-    TouchEditableImplAura::StartTouchEditing();
-  }
-
-  virtual void EndTouchEditing() OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::EndTouchEditing()";
-    TouchEditableImplAura::EndTouchEditing();
-  }
-
   virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
                                           const gfx::Rect& focus) OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::OnSelectionOrCursorChanged("
-              << anchor.ToString() << ", " << focus.ToString() << ")";
     selection_changed_callback_arrived_ = true;
     TouchEditableImplAura::OnSelectionOrCursorChanged(anchor, focus);
     if (waiting_for_selection_changed_callback_)
       selection_changed_wait_run_loop_->Quit();
   }
 
-  virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::OnTextInputTypeChanged("
-              << type << ")";
-    TouchEditableImplAura::OnTextInputTypeChanged(type);
-  }
-
-  virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::HandleInputEvent("
-              << event->type() << ")";
-    return TouchEditableImplAura::HandleInputEvent(event);
-  }
-
   virtual void GestureEventAck(int gesture_event_type) OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::GestureEventAck("
-              << gesture_event_type << ")";
     gesture_ack_callback_arrived_ = true;
     TouchEditableImplAura::GestureEventAck(gesture_event_type);
     if (waiting_for_gesture_ack_callback_)
       gesture_ack_wait_run_loop_->Quit();
   }
 
-  virtual void OnViewDestroyed() OVERRIDE {
-    LOG(INFO) << "TestTouchEditableImplAura::OnViewDestroyed()";
-    TouchEditableImplAura::OnViewDestroyed();
-  }
-
-  void WaitForSelectionChangeCallback() {
-    LOG(INFO) << "TestTouchEditableImplAura::WaitForSelectionChangeCallback()";
+  virtual void WaitForSelectionChangeCallback() {
     if (selection_changed_callback_arrived_)
       return;
     waiting_for_selection_changed_callback_ = true;
@@ -100,8 +66,7 @@
     selection_changed_wait_run_loop_->Run();
   }
 
-  void WaitForGestureAck() {
-    LOG(INFO) << "TestTouchEditableImplAura::WaitForGestureAck()";
+  virtual void WaitForGestureAck() {
     if (gesture_ack_callback_arrived_)
       return;
     waiting_for_gesture_ack_callback_ = true;
@@ -123,6 +88,83 @@
   DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
 };
 
+// This class decorates TestTouchEditableImplAura with some logs and also a
+// crash when it receives a non-touch, non-gesture event to help investigate
+// flakiness of some of the tests.
+// TODO(mohsen): Remove when flakiness of tests is resolved.
+class TestTouchEditableImplAuraWithLog
+    : public TestTouchEditableImplAura {
+ public:
+  TestTouchEditableImplAuraWithLog() {}
+
+  virtual void Reset() OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::Reset()";
+    TestTouchEditableImplAura::Reset();
+  }
+
+  virtual void StartTouchEditing() OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::StartTouchEditing()";
+    TestTouchEditableImplAura::StartTouchEditing();
+  }
+
+  virtual void EndTouchEditing() OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::EndTouchEditing()";
+    TestTouchEditableImplAura::EndTouchEditing();
+  }
+
+  virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+                                          const gfx::Rect& focus) OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::OnSelectionOrCursorChanged("
+              << anchor.ToString() << ", " << focus.ToString() << ")";
+    TestTouchEditableImplAura::OnSelectionOrCursorChanged(anchor, focus);
+  }
+
+  virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::OnTextInputTypeChanged("
+              << type << ")";
+    TestTouchEditableImplAura::OnTextInputTypeChanged(type);
+  }
+
+  virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::HandleInputEvent("
+              << event->type() << ")";
+    // In tests we should only receive touch or gesture events. In rare cases
+    // we receive events that are not touch or gesture that make tests flaky.
+    // The following CHECK will generate the stack trace which might be helpful
+    // in identifying source of those unexpected events.
+    CHECK(event->IsTouchEvent() || event->IsGestureEvent());
+    return TestTouchEditableImplAura::HandleInputEvent(event);
+  }
+
+  virtual void GestureEventAck(int gesture_event_type) OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::GestureEventAck("
+              << gesture_event_type << ")";
+    TestTouchEditableImplAura::GestureEventAck(gesture_event_type);
+  }
+
+  virtual void OnViewDestroyed() OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::OnViewDestroyed()";
+    TestTouchEditableImplAura::OnViewDestroyed();
+  }
+
+  virtual void WaitForSelectionChangeCallback() OVERRIDE {
+    LOG(INFO)
+        << "TestTouchEditableImplAuraWithLog::WaitForSelectionChangeCallback()";
+    TestTouchEditableImplAura::WaitForSelectionChangeCallback();
+  }
+
+  virtual void WaitForGestureAck() OVERRIDE {
+    LOG(INFO) << "TestTouchEditableImplAuraWithLog::WaitForGestureAck()";
+    TestTouchEditableImplAura::WaitForGestureAck();
+  }
+
+ protected:
+  virtual ~TestTouchEditableImplAuraWithLog() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAuraWithLog);
+};
+
 class TouchEditableImplAuraTest : public ContentBrowserTest {
  public:
   TouchEditableImplAuraTest() {}
@@ -147,7 +189,7 @@
     NavigateToURL(shell(), test_url);
     aura::Window* content =
         shell()->web_contents()->GetView()->GetContentNativeView();
-    content->GetRootWindow()->SetHostSize(gfx::Size(800, 600));
+    content->GetDispatcher()->SetHostSize(gfx::Size(800, 600));
   }
 
   // TODO(mohsen): Remove logs if the test showed no flakiness anymore.
@@ -160,7 +202,8 @@
         web_contents->GetRenderViewHost());
     WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
         web_contents->GetView());
-    TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+    TestTouchEditableImplAura* touch_editable =
+        new TestTouchEditableImplAuraWithLog;
     view_aura->SetTouchEditableForTest(touch_editable);
     RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
         web_contents->GetRenderWidgetHostView());
@@ -331,7 +374,8 @@
         web_contents->GetRenderViewHost());
     WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
         web_contents->GetView());
-    TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+    TestTouchEditableImplAura* touch_editable =
+        new TestTouchEditableImplAuraWithLog;
     view_aura->SetTouchEditableForTest(touch_editable);
     RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
         web_contents->GetRenderWidgetHostView());
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 35d1172..e7632e7 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -16,9 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/sys_info.h"
 #include "base/time/time.h"
-#include "cc/base/switches.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
@@ -29,9 +27,8 @@
 #include "content/browser/download/download_stats.h"
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/download/save_package.h"
-#include "content/browser/gpu/compositor_util.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/browser/gpu/gpu_process_host.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/host_zoom_map_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/message_port_message_filter.h"
@@ -41,8 +38,6 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_view_guest.h"
 #include "content/browser/webui/generic_handler.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
@@ -80,15 +75,11 @@
 #include "content/public/common/url_constants.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
-#include "net/base/network_change_notifier.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/layout.h"
-#include "ui/base/touch/touch_device.h"
-#include "ui/base/touch/touch_enabled.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/screen.h"
 #include "ui/gl/gl_switches.h"
@@ -96,6 +87,8 @@
 
 #if defined(OS_ANDROID)
 #include "content/browser/android/date_time_chooser_android.h"
+#include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h"
+#include "content/common/java_bridge_messages.h"
 #include "content/public/browser/android/content_view_core.h"
 #endif
 
@@ -104,10 +97,6 @@
 #include "ui/gl/io_surface_support_mac.h"
 #endif
 
-#if defined(OS_ANDROID)
-#include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h"
-#endif
-
 // Cross-Site Navigations
 //
 // If a WebContentsImpl is told to navigate to a different web site (as
@@ -253,6 +242,8 @@
             entry.GetBrowserInitiatedPostData()->size());
   }
 
+  params->redirects = entry.redirect_chain();
+
   params->can_load_local_resources = entry.GetCanLoadLocalResources();
   params->frame_to_navigate = entry.GetFrameToNavigate();
 
@@ -472,220 +463,6 @@
   return new_contents->browser_plugin_guest_.get();
 }
 
-WebPreferences WebContentsImpl::GetWebkitPrefs(RenderViewHost* rvh,
-                                               const GURL& url) {
-  TRACE_EVENT0("browser", "WebContentsImpl::GetWebkitPrefs");
-  WebPreferences prefs;
-
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
-  prefs.javascript_enabled =
-      !command_line.HasSwitch(switches::kDisableJavaScript);
-  prefs.web_security_enabled =
-      !command_line.HasSwitch(switches::kDisableWebSecurity);
-  prefs.plugins_enabled =
-      !command_line.HasSwitch(switches::kDisablePlugins);
-  prefs.java_enabled =
-      !command_line.HasSwitch(switches::kDisableJava);
-
-  prefs.remote_fonts_enabled =
-      !command_line.HasSwitch(switches::kDisableRemoteFonts);
-  prefs.xslt_enabled =
-      !command_line.HasSwitch(switches::kDisableXSLT);
-  prefs.xss_auditor_enabled =
-      !command_line.HasSwitch(switches::kDisableXSSAuditor);
-  prefs.application_cache_enabled =
-      !command_line.HasSwitch(switches::kDisableApplicationCache);
-
-  prefs.local_storage_enabled =
-      !command_line.HasSwitch(switches::kDisableLocalStorage);
-  prefs.databases_enabled =
-      !command_line.HasSwitch(switches::kDisableDatabases);
-  prefs.webaudio_enabled =
-      !command_line.HasSwitch(switches::kDisableWebAudio);
-
-  prefs.experimental_webgl_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisable3DAPIs) &&
-      !command_line.HasSwitch(switches::kDisableExperimentalWebGL);
-
-  prefs.flash_3d_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisableFlash3d);
-  prefs.flash_stage3d_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisableFlashStage3d);
-  prefs.flash_stage3d_baseline_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisableFlashStage3d);
-
-  prefs.gl_multisampling_enabled =
-      !command_line.HasSwitch(switches::kDisableGLMultisampling);
-  prefs.privileged_webgl_extensions_enabled =
-      command_line.HasSwitch(switches::kEnablePrivilegedWebGLExtensions);
-  prefs.site_specific_quirks_enabled =
-      !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks);
-  prefs.allow_file_access_from_file_urls =
-      command_line.HasSwitch(switches::kAllowFileAccessFromFiles);
-
-  prefs.accelerated_compositing_for_overflow_scroll_enabled = false;
-  if (command_line.HasSwitch(switches::kEnableAcceleratedOverflowScroll))
-    prefs.accelerated_compositing_for_overflow_scroll_enabled = true;
-  if (command_line.HasSwitch(switches::kDisableAcceleratedOverflowScroll))
-    prefs.accelerated_compositing_for_overflow_scroll_enabled = false;
-
-  prefs.accelerated_compositing_for_scrollable_frames_enabled = false;
-  if (command_line.HasSwitch(switches::kEnableAcceleratedScrollableFrames))
-    prefs.accelerated_compositing_for_scrollable_frames_enabled = true;
-  if (command_line.HasSwitch(switches::kDisableAcceleratedScrollableFrames))
-    prefs.accelerated_compositing_for_scrollable_frames_enabled = false;
-
-  prefs.composited_scrolling_for_frames_enabled = false;
-  if (command_line.HasSwitch(switches::kEnableCompositedScrollingForFrames))
-    prefs.composited_scrolling_for_frames_enabled = true;
-  if (command_line.HasSwitch(switches::kDisableCompositedScrollingForFrames))
-    prefs.composited_scrolling_for_frames_enabled = false;
-
-  prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = false;
-  if (command_line.HasSwitch(
-          switches::kEnableUniversalAcceleratedOverflowScroll))
-    prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = true;
-  if (command_line.HasSwitch(
-          switches::kDisableUniversalAcceleratedOverflowScroll))
-    prefs.universal_accelerated_compositing_for_overflow_scroll_enabled = false;
-
-  prefs.show_paint_rects =
-      command_line.HasSwitch(switches::kShowPaintRects);
-  prefs.accelerated_compositing_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisableAcceleratedCompositing);
-  prefs.force_compositing_mode =
-      content::IsForceCompositingModeEnabled() &&
-      !command_line.HasSwitch(switches::kDisableForceCompositingMode);
-  prefs.accelerated_2d_canvas_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      !command_line.HasSwitch(switches::kDisableAccelerated2dCanvas);
-  prefs.antialiased_2d_canvas_disabled =
-      command_line.HasSwitch(switches::kDisable2dCanvasAntialiasing);
-  prefs.accelerated_filters_enabled =
-      GpuProcessHost::gpu_enabled() &&
-      command_line.HasSwitch(switches::kEnableAcceleratedFilters);
-  prefs.accelerated_compositing_for_3d_transforms_enabled =
-      prefs.accelerated_compositing_for_animation_enabled =
-          !command_line.HasSwitch(switches::kDisableAcceleratedLayers);
-  prefs.accelerated_compositing_for_plugins_enabled =
-      !command_line.HasSwitch(switches::kDisableAcceleratedPlugins);
-  prefs.accelerated_compositing_for_video_enabled =
-      !command_line.HasSwitch(switches::kDisableAcceleratedVideo);
-  prefs.fullscreen_enabled =
-      !command_line.HasSwitch(switches::kDisableFullScreen);
-  prefs.lazy_layout_enabled =
-      command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures);
-  prefs.region_based_columns_enabled =
-      command_line.HasSwitch(switches::kEnableRegionBasedColumns);
-  prefs.threaded_html_parser =
-      !command_line.HasSwitch(switches::kDisableThreadedHTMLParser);
-  prefs.experimental_websocket_enabled =
-      command_line.HasSwitch(switches::kEnableExperimentalWebSocket);
-  if (command_line.HasSwitch(cc::switches::kEnablePinchVirtualViewport)) {
-    prefs.pinch_virtual_viewport_enabled = true;
-    prefs.pinch_overlay_scrollbar_thickness = 10;
-  }
-  prefs.use_solid_color_scrollbars = command_line.HasSwitch(
-      switches::kEnableOverlayScrollbars);
-
-#if defined(OS_ANDROID)
-  prefs.user_gesture_required_for_media_playback = !command_line.HasSwitch(
-      switches::kDisableGestureRequirementForMediaPlayback);
-  prefs.user_gesture_required_for_media_fullscreen = !command_line.HasSwitch(
-      switches::kDisableGestureRequirementForMediaFullscreen);
-#endif
-
-  prefs.touch_enabled = ui::AreTouchEventsEnabled();
-  prefs.device_supports_touch = prefs.touch_enabled &&
-      ui::IsTouchDevicePresent();
-#if defined(OS_ANDROID)
-  prefs.device_supports_mouse = false;
-#endif
-
-   prefs.touch_adjustment_enabled =
-       !command_line.HasSwitch(switches::kDisableTouchAdjustment);
-   prefs.compositor_touch_hit_testing =
-       !command_line.HasSwitch(cc::switches::kDisableCompositorTouchHitTesting);
-
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
-  bool default_enable_scroll_animator = true;
-#else
-  bool default_enable_scroll_animator = false;
-#endif
-  prefs.enable_scroll_animator = default_enable_scroll_animator;
-  if (command_line.HasSwitch(switches::kEnableSmoothScrolling))
-    prefs.enable_scroll_animator = true;
-  if (command_line.HasSwitch(switches::kDisableSmoothScrolling))
-    prefs.enable_scroll_animator = false;
-
-  prefs.visual_word_movement_enabled =
-      command_line.HasSwitch(switches::kEnableVisualWordMovement);
-
-  // Certain GPU features might have been blacklisted.
-  GpuDataManagerImpl::GetInstance()->UpdateRendererWebPrefs(&prefs);
-
-  if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
-          rvh->GetProcess()->GetID())) {
-    prefs.loads_images_automatically = true;
-    prefs.javascript_enabled = true;
-  }
-
-  prefs.is_online = !net::NetworkChangeNotifier::IsOffline();
-
-#if !defined(USE_AURA)
-  // Force accelerated compositing and 2d canvas off for chrome: and about:
-  // pages (unless it's specifically allowed).
-  if ((url.SchemeIs(chrome::kChromeUIScheme) ||
-      (url.SchemeIs(chrome::kAboutScheme) &&
-       url.spec() != kAboutBlankURL)) &&
-      !command_line.HasSwitch(switches::kAllowWebUICompositing)) {
-    prefs.accelerated_compositing_enabled = false;
-    prefs.accelerated_2d_canvas_enabled = false;
-  }
-#endif
-
-  prefs.fixed_position_creates_stacking_context = !command_line.HasSwitch(
-      switches::kDisableFixedPositionCreatesStackingContext);
-
-#if defined(OS_CHROMEOS)
-  prefs.gesture_tap_highlight_enabled = !command_line.HasSwitch(
-      switches::kDisableGestureTapHighlight);
-#else
-  prefs.gesture_tap_highlight_enabled = command_line.HasSwitch(
-      switches::kEnableGestureTapHighlight);
-#endif
-
-  prefs.number_of_cpu_cores = base::SysInfo::NumberOfProcessors();
-
-  prefs.viewport_enabled = command_line.HasSwitch(switches::kEnableViewport);
-
-  prefs.deferred_image_decoding_enabled =
-      command_line.HasSwitch(switches::kEnableDeferredImageDecoding) ||
-      cc::switches::IsImplSidePaintingEnabled();
-
-  prefs.spatial_navigation_enabled = command_line.HasSwitch(
-      switches::kEnableSpatialNavigation);
-
-  GetContentClient()->browser()->OverrideWebkitPrefs(rvh, url, &prefs);
-
-  // Disable compositing in guests until we have compositing path implemented
-  // for guests.
-  bool guest_compositing_enabled = !command_line.HasSwitch(
-      switches::kDisableBrowserPluginCompositing);
-  if (rvh->GetProcess()->IsGuest() && !guest_compositing_enabled) {
-    prefs.force_compositing_mode = false;
-    prefs.accelerated_compositing_enabled = false;
-  }
-
-  return prefs;
-}
-
 RenderViewHostManager* WebContentsImpl::GetRenderManagerForTesting() {
   return &render_manager_;
 }
@@ -748,6 +525,8 @@
                         OnFindMatchRectsReply)
     IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog,
                         OnOpenDateTimeDialog)
+    IPC_MESSAGE_HANDLER_DELAY_REPLY(JavaBridgeHostMsg_GetChannelHandle,
+                                    OnJavaBridgeGetChannelHandle)
 #endif
     IPC_MESSAGE_HANDLER(ViewHostMsg_MediaNotification, OnMediaNotification)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -1010,8 +789,9 @@
     max_page_ids_[site_instance->GetId()] = page_id;
 }
 
-void WebContentsImpl::CopyMaxPageIDsFrom(WebContentsImpl* web_contents) {
-  max_page_ids_ = web_contents->max_page_ids_;
+void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) {
+  WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents);
+  max_page_ids_ = contents->max_page_ids_;
 }
 
 SiteInstance* WebContentsImpl::GetSiteInstance() const {
@@ -1148,12 +928,6 @@
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown());
 
   should_normally_be_visible_ = true;
-
-  // TODO(avi): Remove. http://crbug.com/170921
-  NotificationService::current()->Notify(
-      NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      Source<WebContents>(this),
-      Details<const bool>(&should_normally_be_visible_));
 }
 
 void WebContentsImpl::WasHidden() {
@@ -1175,12 +949,6 @@
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
 
   should_normally_be_visible_ = false;
-
-  // TODO(avi): Remove. http://crbug.com/170921
-  NotificationService::current()->Notify(
-      NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      Source<WebContents>(this),
-      Details<const bool>(&should_normally_be_visible_));
 }
 
 bool WebContentsImpl::NeedToFireBeforeUnload() {
@@ -1230,6 +998,10 @@
   }
 }
 
+WebContents* WebContentsImpl::GetWebContents() {
+  return this;
+}
+
 void WebContentsImpl::Init(const WebContents::CreateParams& params) {
   // This is set before initializing the render_manager_ since render_manager_
   // init calls back into us via its delegate to ask if it should be hidden.
@@ -1278,9 +1050,6 @@
 #if defined(OS_ANDROID)
   java_bridge_dispatcher_host_manager_.reset(
       new JavaBridgeDispatcherHostManager(this));
-#endif
-
-#if defined(OS_ANDROID)
   date_time_chooser_.reset(new DateTimeChooserAndroid());
 #endif
 }
@@ -2209,10 +1978,10 @@
     // SiteInstance, and ensure the address bar updates accordingly.  We don't
     // know the referrer or extra headers at this point, but the referrer will
     // be set properly upon commit.
-    NavigationEntry* pending_entry = controller_.GetPendingEntry();
+    NavigationEntryImpl* pending_entry =
+        NavigationEntryImpl::FromNavigationEntry(controller_.GetPendingEntry());
     bool has_browser_initiated_pending_entry = pending_entry &&
-        !NavigationEntryImpl::FromNavigationEntry(pending_entry)->
-            is_renderer_initiated();
+        !pending_entry->is_renderer_initiated();
     if (!has_browser_initiated_pending_entry && !is_error_page) {
       NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
           controller_.CreateNavigationEntry(validated_url,
@@ -2225,10 +1994,11 @@
           static_cast<SiteInstanceImpl*>(GetSiteInstance()));
       // TODO(creis): If there's a pending entry already, find a safe way to
       // update it instead of replacing it and copying over things like this.
-      if (pending_entry &&
-          NavigationEntryImpl::FromNavigationEntry(pending_entry)->
-              should_replace_entry()) {
-        entry->set_should_replace_entry(true);
+      if (pending_entry) {
+        entry->set_transferred_global_request_id(
+            pending_entry->transferred_global_request_id());
+        entry->set_should_replace_entry(pending_entry->should_replace_entry());
+        entry->set_redirect_chain(pending_entry->redirect_chain());
       }
       controller_.SetPendingEntry(entry);
       NotifyNavigationStateChanged(content::INVALIDATE_TYPE_URL);
@@ -2537,6 +2307,11 @@
                                  value.step);
 }
 
+void WebContentsImpl::OnJavaBridgeGetChannelHandle(IPC::Message* reply_msg) {
+  java_bridge_dispatcher_host_manager_->OnGetChannelHandle(
+      message_source_, reply_msg);
+}
+
 #endif
 
 void WebContentsImpl::OnCrashedPlugin(const base::FilePath& plugin_path,
@@ -2694,6 +2469,13 @@
                     BeforeFormRepostWarningShow());
 }
 
+
+void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() {
+  Activate();
+  if (delegate_)
+    delegate_->ShowRepostFormWarningDialog(this);
+}
+
 // Notifies the RenderWidgetHost instance about the fact that the page is
 // loading, or done loading.
 void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
@@ -3320,49 +3102,58 @@
 
   // Delegate to RequestTransferURL because this is just the generic
   // case where |old_request_id| is empty.
-  RequestTransferURL(url, referrer, disposition, source_frame_id,
-                     GlobalRequestID(),
+  // TODO(creis): Pass the redirect_chain into this method to support client
+  // redirects.  http://crbug.com/311721.
+  std::vector<GURL> redirect_chain;
+  RequestTransferURL(url, redirect_chain, referrer, PAGE_TRANSITION_LINK,
+                     disposition, source_frame_id, GlobalRequestID(),
                      should_replace_current_entry, user_gesture);
 }
 
 void WebContentsImpl::RequestTransferURL(
     const GURL& url,
+    const std::vector<GURL>& redirect_chain,
     const Referrer& referrer,
+    PageTransition page_transition,
     WindowOpenDisposition disposition,
     int64 source_frame_id,
     const GlobalRequestID& old_request_id,
     bool should_replace_current_entry,
     bool user_gesture) {
   WebContents* new_contents = NULL;
-  PageTransition transition_type = PAGE_TRANSITION_LINK;
   GURL dest_url(url);
   if (!GetContentClient()->browser()->ShouldAllowOpenURL(
-      GetSiteInstance(), url))
+          GetSiteInstance(), url))
     dest_url = GURL(kAboutBlankURL);
 
+  OpenURLParams params(dest_url, referrer, source_frame_id, disposition,
+      page_transition, true /* is_renderer_initiated */);
+  if (redirect_chain.size() > 0)
+    params.redirect_chain = redirect_chain;
+  params.transferred_global_request_id = old_request_id;
+  params.should_replace_current_entry = should_replace_current_entry;
+  params.user_gesture = user_gesture;
+
   if (render_manager_.web_ui()) {
-    // When we're a Web UI, it will provide a page transition type for us (this
-    // is so the new tab page can specify AUTO_BOOKMARK for automatically
-    // generated suggestions).
-    //
+    // Web UI pages sometimes want to override the page transition type for
+    // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for
+    // automatically generated suggestions).  We don't override other types
+    // like TYPED because they have different implications (e.g., autocomplete).
+    if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK))
+      params.transition = render_manager_.web_ui()->GetLinkTransitionType();
+
     // Note also that we hide the referrer for Web UI pages. We don't really
     // want web sites to see a referrer of "chrome://blah" (and some
     // chrome: URLs might have search terms or other stuff we don't want to
     // send to the site), so we send no referrer.
-    OpenURLParams params(dest_url, Referrer(), source_frame_id, disposition,
-        render_manager_.web_ui()->GetLinkTransitionType(),
-        false /* is_renderer_initiated */);
-    params.transferred_global_request_id = old_request_id;
-    new_contents = OpenURL(params);
-    transition_type = render_manager_.web_ui()->GetLinkTransitionType();
-  } else {
-    OpenURLParams params(dest_url, referrer, source_frame_id, disposition,
-        PAGE_TRANSITION_LINK, true /* is_renderer_initiated */);
-    params.transferred_global_request_id = old_request_id;
-    params.should_replace_current_entry = should_replace_current_entry;
-    params.user_gesture = user_gesture;
-    new_contents = OpenURL(params);
+    params.referrer = Referrer();
+
+    // Navigations in Web UI pages count as browser-initiated navigations.
+    params.is_renderer_initiated = false;
   }
+
+  new_contents = OpenURL(params);
+
   if (new_contents) {
     // Notify observers.
     FOR_EACH_OBSERVER(WebContentsObserver, observers_,
@@ -3370,7 +3161,7 @@
                                           dest_url,
                                           referrer,
                                           disposition,
-                                          transition_type,
+                                          params.transition,
                                           source_frame_id));
   }
 }
@@ -3545,7 +3336,8 @@
   // as it is deprecated and can be out of sync with GetRenderViewHost().
   GURL url = controller_.GetActiveEntry()
       ? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL();
-  return GetWebkitPrefs(GetRenderViewHost(), url);
+
+  return render_manager_.current_host()->GetWebkitPrefs(url);
 }
 
 int WebContentsImpl::CreateSwappedOutRenderView(
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index fb81399..56d54a2 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -15,15 +15,17 @@
 #include "base/observer_list.h"
 #include "base/process/process.h"
 #include "base/values.h"
-#include "content/browser/renderer_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/navigation_controller_delegate.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/render_view_host_manager.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/render_view_host_manager.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/page_transition_types.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/three_d_api_types.h"
 #include "net/base/load_states.h"
@@ -76,7 +78,8 @@
       public RenderViewHostDelegate,
       public RenderWidgetHostDelegate,
       public RenderViewHostManager::Delegate,
-      public NotificationObserver {
+      public NotificationObserver,
+      public NON_EXPORTED_BASE(NavigationControllerDelegate) {
  public:
   virtual ~WebContentsImpl();
 
@@ -95,10 +98,6 @@
       int guest_instance_id,
       scoped_ptr<base::DictionaryValue> extra_params);
 
-  // Returns the content specific prefs for the given RVH.
-  static WebPreferences GetWebkitPrefs(
-      RenderViewHost* rvh, const GURL& url);
-
   // Creates a swapped out RenderView. This is used by the browser plugin to
   // create a swapped out RenderView in the embedder render process for the
   // guest, to expose the guest's window object to the embedder.
@@ -112,42 +111,6 @@
   // Returns the SavePackage which manages the page saving job. May be NULL.
   SavePackage* save_package() const { return save_package_.get(); }
 
-  // Updates the max page ID for the current SiteInstance in this
-  // WebContentsImpl to be at least |page_id|.
-  void UpdateMaxPageID(int32 page_id);
-
-  // Updates the max page ID for the given SiteInstance in this WebContentsImpl
-  // to be at least |page_id|.
-  void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
-                                      int32 page_id);
-
-  // Copy the current map of SiteInstance ID to max page ID from another tab.
-  // This is necessary when this tab adopts the NavigationEntries from
-  // |web_contents|.
-  void CopyMaxPageIDsFrom(WebContentsImpl* web_contents);
-
-  // Called by the NavigationController to cause the WebContentsImpl to navigate
-  // to the current pending entry. The NavigationController should be called
-  // back with RendererDidNavigate on success or DiscardPendingEntry on failure.
-  // The callbacks can be inside of this function, or at some future time.
-  //
-  // The entry has a PageID of -1 if newly created (corresponding to navigation
-  // to a new URL).
-  //
-  // If this method returns false, then the navigation is discarded (equivalent
-  // to calling DiscardPendingEntry on the NavigationController).
-  bool NavigateToPendingEntry(NavigationController::ReloadType reload_type);
-
-  // Called by InterstitialPageImpl when it creates a RenderViewHost.
-  void RenderViewForInterstitialPageCreated(RenderViewHost* render_view_host);
-
-  // Sets the passed interstitial as the currently showing interstitial.
-  // No interstitial page should already be attached.
-  void AttachInterstitialPage(InterstitialPageImpl* interstitial_page);
-
-  // Unsets the currently showing interstitial.
-  void DetachInterstitialPage();
-
 #if defined(OS_ANDROID)
   JavaBridgeDispatcherHostManager* java_bridge_dispatcher_host_manager() const {
     return java_bridge_dispatcher_host_manager_.get();
@@ -188,10 +151,6 @@
   // Invoked when visible SSL state (as defined by SSLStatus) changes.
   void DidChangeVisibleSSLState();
 
-  // Invoked before a form repost warning is shown.
-  void NotifyBeforeFormRepostWarningShow();
-
-
   // Informs the render view host and the BrowserPluginEmbedder, if present, of
   // a Drag Source End.
   void DragSourceEndedAt(int client_x, int client_y, int screen_x,
@@ -383,7 +342,9 @@
                               bool user_gesture) OVERRIDE;
   virtual void RequestTransferURL(
       const GURL& url,
+      const std::vector<GURL>& redirect_chain,
       const Referrer& referrer,
+      PageTransition page_transition,
       WindowOpenDisposition disposition,
       int64 source_frame_id,
       const GlobalRequestID& transferred_global_request_id,
@@ -510,6 +471,73 @@
                        const NotificationSource& source,
                        const NotificationDetails& details) OVERRIDE;
 
+  // NavigationControllerDelegate ----------------------------------------------
+
+  virtual WebContents* GetWebContents() OVERRIDE;
+  virtual void NotifyNavigationEntryCommitted(
+      const LoadCommittedDetails& load_details) OVERRIDE;
+
+  // Invoked before a form repost warning is shown.
+  virtual void NotifyBeforeFormRepostWarningShow() OVERRIDE;
+
+  // Activate this WebContents and show a form repost warning.
+  virtual void ActivateAndShowRepostFormWarningDialog() OVERRIDE;
+
+  // Updates the max page ID for the current SiteInstance in this
+  // WebContentsImpl to be at least |page_id|.
+  virtual void UpdateMaxPageID(int32 page_id) OVERRIDE;
+
+  // Updates the max page ID for the given SiteInstance in this WebContentsImpl
+  // to be at least |page_id|.
+  virtual void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
+                                              int32 page_id) OVERRIDE;
+
+  // Copy the current map of SiteInstance ID to max page ID from another tab.
+  // This is necessary when this tab adopts the NavigationEntries from
+  // |web_contents|.
+  virtual void CopyMaxPageIDsFrom(WebContents* web_contents) OVERRIDE;
+
+  // Called by the NavigationController to cause the WebContentsImpl to navigate
+  // to the current pending entry. The NavigationController should be called
+  // back with RendererDidNavigate on success or DiscardPendingEntry on failure.
+  // The callbacks can be inside of this function, or at some future time.
+  //
+  // The entry has a PageID of -1 if newly created (corresponding to navigation
+  // to a new URL).
+  //
+  // If this method returns false, then the navigation is discarded (equivalent
+  // to calling DiscardPendingEntry on the NavigationController).
+  virtual bool NavigateToPendingEntry(
+      NavigationController::ReloadType reload_type) OVERRIDE;
+
+  // Sets the history for this WebContentsImpl to |history_length| entries, and
+  // moves the current page_id to the last entry in the list if it's valid.
+  // This is mainly used when a prerendered page is swapped into the current
+  // tab. The method is virtual for testing.
+  virtual void SetHistoryLengthAndPrune(
+      const SiteInstance* site_instance,
+      int merge_history_length,
+      int32 minimum_page_id) OVERRIDE;
+
+  // Called by InterstitialPageImpl when it creates a RenderViewHost.
+  virtual void RenderViewForInterstitialPageCreated(
+      RenderViewHost* render_view_host) OVERRIDE;
+
+  // Sets the passed interstitial as the currently showing interstitial.
+  // No interstitial page should already be attached.
+  virtual void AttachInterstitialPage(
+      InterstitialPageImpl* interstitial_page) OVERRIDE;
+
+  // Unsets the currently showing interstitial.
+  virtual void DetachInterstitialPage() OVERRIDE;
+
+  // Changes the IsLoading state and notifies the delegate as needed.
+  // |details| is used to provide details on the load that just finished
+  // (but can be null if not applicable).
+  virtual void SetIsLoading(RenderViewHost* render_view_host,
+                            bool is_loading,
+                            LoadNotificationDetails* details) OVERRIDE;
+
 
  private:
   friend class NavigationControllerImpl;
@@ -608,6 +636,7 @@
 
   void OnOpenDateTimeDialog(
       const ViewHostMsg_DateTimeDialogValue_Params& value);
+  void OnJavaBridgeGetChannelHandle(IPC::Message* reply_msg);
 #endif
   void OnCrashedPlugin(const base::FilePath& plugin_path,
                        base::ProcessId plugin_pid);
@@ -638,13 +667,6 @@
                            bool has_audio,
                            bool is_playing);
 
-  // Changes the IsLoading state and notifies the delegate as needed.
-  // |details| is used to provide details on the load that just finished
-  // (but can be null if not applicable).
-  void SetIsLoading(RenderViewHost* render_view_host,
-                    bool is_loading,
-                    LoadNotificationDetails* details);
-
   // Called by derived classes to indicate that we're no longer waiting for a
   // response. This won't actually update the throbber, but it will get picked
   // up at the next animation step if the throbber is going.
@@ -693,15 +715,6 @@
   bool NavigateToEntry(const NavigationEntryImpl& entry,
                        NavigationController::ReloadType reload_type);
 
-  // Sets the history for this WebContentsImpl to |history_length| entries, and
-  // moves the current page_id to the last entry in the list if it's valid.
-  // This is mainly used when a prerendered page is swapped into the current
-  // tab. The method is virtual for testing.
-  virtual void SetHistoryLengthAndPrune(
-      const SiteInstance* site_instance,
-      int merge_history_length,
-      int32 minimum_page_id);
-
   // Recursively creates swapped out RenderViews for this tab's opener chain
   // (including this tab) in the given SiteInstance, allowing other tabs to send
   // cross-process JavaScript calls to their opener(s).  Returns the route ID of
@@ -739,7 +752,6 @@
   // Helper functions for sending notifications.
   void NotifySwapped(RenderViewHost* old_host, RenderViewHost* new_host);
   void NotifyDisconnected();
-  void NotifyNavigationEntryCommitted(const LoadCommittedDetails& load_details);
 
   void SetEncoding(const std::string& encoding);
 
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 2011603..ade955f 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/test_render_view_host.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/global_request_id.h"
@@ -113,8 +113,9 @@
                        InterstitialState* state,
                        bool* deleted)
       : InterstitialPageImpl(
-            contents, new_navigation, url,
-            new TestInterstitialPageDelegate(this)),
+            contents,
+            static_cast<RenderWidgetHostDelegate*>(contents),
+            new_navigation, url, new TestInterstitialPageDelegate(this)),
         state_(state),
         deleted_(deleted),
         command_received_count_(0),
@@ -1060,8 +1061,11 @@
 
   // Simulate the pending renderer's response, which leads to an unload request
   // being sent to orig_rvh.
+  std::vector<GURL> url_chain;
+  url_chain.push_back(GURL());
   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
-      pending_rvh, GlobalRequestID(0, 0), false, GURL(), Referrer(), 1);
+      pending_rvh, GlobalRequestID(0, 0), false, url_chain, Referrer(),
+      PAGE_TRANSITION_TYPED, 1);
 
   // Suppose the original renderer navigates now, while the unload request is in
   // flight.  We should ignore it, wait for the unload ack, and let the pending
diff --git a/content/browser/web_contents/web_contents_screenshot_manager.cc b/content/browser/web_contents/web_contents_screenshot_manager.cc
deleted file mode 100644
index 811e4ea..0000000
--- a/content/browser/web_contents/web_contents_screenshot_manager.cc
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright (c) 2013 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/web_contents/web_contents_screenshot_manager.h"
-
-#include "base/command_line.h"
-#include "base/threading/worker_pool.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/common/content_switches.h"
-#include "ui/gfx/codec/png_codec.h"
-
-namespace {
-
-// Minimum delay between taking screenshots.
-const int kMinScreenshotIntervalMS = 1000;
-
-}
-
-namespace content {
-
-// Encodes an SkBitmap to PNG data in a worker thread.
-class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
- public:
-  ScreenshotData() {
-  }
-
-  void EncodeScreenshot(const SkBitmap& bitmap, base::Closure callback) {
-    if (!base::WorkerPool::PostTaskAndReply(FROM_HERE,
-            base::Bind(&ScreenshotData::EncodeOnWorker,
-                       this,
-                       bitmap),
-            callback,
-            true)) {
-      callback.Run();
-    }
-  }
-
-  scoped_refptr<base::RefCountedBytes> data() const { return data_; }
-
- private:
-  friend class base::RefCountedThreadSafe<ScreenshotData>;
-  virtual ~ScreenshotData() {
-  }
-
-  void EncodeOnWorker(const SkBitmap& bitmap) {
-    std::vector<unsigned char> data;
-    if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data))
-      data_ = new base::RefCountedBytes(data);
-  }
-
-  scoped_refptr<base::RefCountedBytes> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenshotData);
-};
-
-WebContentsScreenshotManager::WebContentsScreenshotManager(
-    NavigationControllerImpl* owner)
-    : owner_(owner),
-      screenshot_factory_(this),
-      min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
-}
-
-WebContentsScreenshotManager::~WebContentsScreenshotManager() {
-}
-
-void WebContentsScreenshotManager::TakeScreenshot() {
-  static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
-      GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
-  if (!overscroll_enabled)
-    return;
-
-  NavigationEntryImpl* entry =
-      NavigationEntryImpl::FromNavigationEntry(owner_->GetLastCommittedEntry());
-  if (!entry)
-    return;
-
-  RenderViewHost* render_view_host =
-      owner_->web_contents()->GetRenderViewHost();
-  if (!static_cast<RenderViewHostImpl*>
-      (render_view_host)->overscroll_controller()) {
-    return;
-  }
-  content::RenderWidgetHostView* view = render_view_host->GetView();
-  if (!view)
-    return;
-
-  // Make sure screenshots aren't taken too frequently.
-  base::Time now = base::Time::Now();
-  if (now - last_screenshot_time_ <
-          base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
-    return;
-  }
-
-  last_screenshot_time_ = now;
-
-  TakeScreenshotImpl(render_view_host, entry);
-}
-
-// Implemented here and not in NavigationEntry because this manager keeps track
-// of the total number of screen shots across all entries.
-void WebContentsScreenshotManager::ClearAllScreenshots() {
-  int count = owner_->GetEntryCount();
-  for (int i = 0; i < count; ++i) {
-    ClearScreenshot(NavigationEntryImpl::FromNavigationEntry(
-        owner_->GetEntryAtIndex(i)));
-  }
-  DCHECK_EQ(GetScreenshotCount(), 0);
-}
-
-void WebContentsScreenshotManager::TakeScreenshotImpl(
-    RenderViewHost* host,
-    NavigationEntryImpl* entry) {
-  DCHECK(host && host->GetView());
-  DCHECK(entry);
-  host->CopyFromBackingStore(gfx::Rect(),
-      host->GetView()->GetViewBounds().size(),
-      base::Bind(&WebContentsScreenshotManager::OnScreenshotTaken,
-                 screenshot_factory_.GetWeakPtr(),
-                 entry->GetUniqueID()));
-}
-
-void WebContentsScreenshotManager::SetMinScreenshotIntervalMS(int interval_ms) {
-  DCHECK_GE(interval_ms, 0);
-  min_screenshot_interval_ms_ = interval_ms;
-}
-
-void WebContentsScreenshotManager::OnScreenshotTaken(int unique_id,
-                                                     bool success,
-                                                     const SkBitmap& bitmap) {
-  NavigationEntryImpl* entry = NULL;
-  int entry_count = owner_->GetEntryCount();
-  for (int i = 0; i < entry_count; ++i) {
-    NavigationEntry* iter = owner_->GetEntryAtIndex(i);
-    if (iter->GetUniqueID() == unique_id) {
-      entry = NavigationEntryImpl::FromNavigationEntry(iter);
-      break;
-    }
-  }
-
-  if (!entry) {
-    LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
-    return;
-  }
-
-  if (!success || bitmap.empty() || bitmap.isNull()) {
-    if (!ClearScreenshot(entry))
-      OnScreenshotSet(entry);
-    return;
-  }
-
-  scoped_refptr<ScreenshotData> screenshot = new ScreenshotData();
-  screenshot->EncodeScreenshot(
-      bitmap,
-      base::Bind(&WebContentsScreenshotManager::OnScreenshotEncodeComplete,
-                 screenshot_factory_.GetWeakPtr(),
-                 unique_id,
-                 screenshot));
-}
-
-int WebContentsScreenshotManager::GetScreenshotCount() const {
-  int screenshot_count = 0;
-  int entry_count = owner_->GetEntryCount();
-  for (int i = 0; i < entry_count; ++i) {
-    NavigationEntryImpl* entry =
-        NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(i));
-    if (entry->screenshot().get())
-      screenshot_count++;
-  }
-  return screenshot_count;
-}
-
-void WebContentsScreenshotManager::OnScreenshotEncodeComplete(
-    int unique_id,
-    scoped_refptr<ScreenshotData> screenshot) {
-  NavigationEntryImpl* entry = NULL;
-  int entry_count = owner_->GetEntryCount();
-  for (int i = 0; i < entry_count; ++i) {
-    NavigationEntry* iter = owner_->GetEntryAtIndex(i);
-    if (iter->GetUniqueID() == unique_id) {
-      entry = NavigationEntryImpl::FromNavigationEntry(iter);
-      break;
-    }
-  }
-  if (!entry)
-    return;
-  entry->SetScreenshotPNGData(screenshot->data());
-  OnScreenshotSet(entry);
-}
-
-void WebContentsScreenshotManager::OnScreenshotSet(NavigationEntryImpl* entry) {
-  if (entry->screenshot().get())
-    PurgeScreenshotsIfNecessary();
-}
-
-bool WebContentsScreenshotManager::ClearScreenshot(NavigationEntryImpl* entry) {
-  if (!entry->screenshot().get())
-    return false;
-
-  entry->SetScreenshotPNGData(NULL);
-  return true;
-}
-
-void WebContentsScreenshotManager::PurgeScreenshotsIfNecessary() {
-  // Allow only a certain number of entries to keep screenshots.
-  const int kMaxScreenshots = 10;
-  int screenshot_count = GetScreenshotCount();
-  if (screenshot_count < kMaxScreenshots)
-    return;
-
-  const int current = owner_->GetCurrentEntryIndex();
-  const int num_entries = owner_->GetEntryCount();
-  int available_slots = kMaxScreenshots;
-  if (NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(current))
-          ->screenshot().get()) {
-    --available_slots;
-  }
-
-  // Keep screenshots closer to the current navigation entry, and purge the ones
-  // that are farther away from it. So in each step, look at the entries at
-  // each offset on both the back and forward history, and start counting them
-  // to make sure that the correct number of screenshots are kept in memory.
-  // Note that it is possible for some entries to be missing screenshots (e.g.
-  // when taking the screenshot failed for some reason). So there may be a state
-  // where there are a lot of entries in the back history, but none of them has
-  // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
-  // entries in the forward history list.
-  int back = current - 1;
-  int forward = current + 1;
-  while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
-    if (back >= 0) {
-      NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-          owner_->GetEntryAtIndex(back));
-      if (entry->screenshot().get())
-        --available_slots;
-      --back;
-    }
-
-    if (available_slots > 0 && forward < num_entries) {
-      NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-          owner_->GetEntryAtIndex(forward));
-      if (entry->screenshot().get())
-        --available_slots;
-      ++forward;
-    }
-  }
-
-  // Purge any screenshot at |back| or lower indices, and |forward| or higher
-  // indices.
-  while (screenshot_count > kMaxScreenshots && back >= 0) {
-    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-        owner_->GetEntryAtIndex(back));
-    if (ClearScreenshot(entry))
-      --screenshot_count;
-    --back;
-  }
-
-  while (screenshot_count > kMaxScreenshots && forward < num_entries) {
-    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-        owner_->GetEntryAtIndex(forward));
-    if (ClearScreenshot(entry))
-      --screenshot_count;
-    ++forward;
-  }
-  CHECK_GE(screenshot_count, 0);
-  CHECK_LE(screenshot_count, kMaxScreenshots);
-}
-
-}  // namespace content
diff --git a/content/browser/web_contents/web_contents_screenshot_manager.h b/content/browser/web_contents/web_contents_screenshot_manager.h
deleted file mode 100644
index 23df41e..0000000
--- a/content/browser/web_contents/web_contents_screenshot_manager.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2013 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_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-
-class SkBitmap;
-
-namespace content {
-
-class NavigationControllerImpl;
-class NavigationEntryImpl;
-class RenderViewHost;
-class ScreenshotData;
-
-// WebContentsScreenshotManager takes care of taking image-captures for the
-// current navigation entry of a NavigationControllerImpl, and managing these
-// captured images. These image-captures are used for history navigation using
-// overscroll gestures.
-class CONTENT_EXPORT WebContentsScreenshotManager {
- public:
-  explicit WebContentsScreenshotManager(NavigationControllerImpl* controller);
-  virtual ~WebContentsScreenshotManager();
-
-  // Takes a screenshot of the last-committed entry of the controller.
-  void TakeScreenshot();
-
-  // Clears screenshots of all navigation entries.
-  void ClearAllScreenshots();
-
- protected:
-  virtual void TakeScreenshotImpl(RenderViewHost* host,
-                                  NavigationEntryImpl* entry);
-
-  // Called after a screenshot has been set on an NavigationEntryImpl.
-  // Overridden in tests to get notified of when a screenshot is set.
-  virtual void OnScreenshotSet(NavigationEntryImpl* entry);
-
-  NavigationControllerImpl* owner() { return owner_; }
-
-  void SetMinScreenshotIntervalMS(int interval_ms);
-
-  // The callback invoked when taking the screenshot of the page is complete.
-  // This sets the screenshot on the navigation entry.
-  void OnScreenshotTaken(int unique_id,
-                         bool success,
-                         const SkBitmap& bitmap);
-
-  // Returns the number of entries with screenshots.
-  int GetScreenshotCount() const;
-
- private:
-  // This is called when the screenshot data has beene encoded to PNG in a
-  // worker thread.
-  void OnScreenshotEncodeComplete(int unique_id,
-                                  scoped_refptr<ScreenshotData> data);
-
-  // Removes the screenshot for the entry, returning true if the entry had a
-  // screenshot.
-  bool ClearScreenshot(NavigationEntryImpl* entry);
-
-  // The screenshots in the NavigationEntryImpls can accumulate and consume a
-  // large amount of memory. This function makes sure that the memory
-  // consumption is within a certain limit.
-  void PurgeScreenshotsIfNecessary();
-
-  // The navigation controller that owns this screenshot-manager.
-  NavigationControllerImpl* owner_;
-
-  // Taking a screenshot and encoding them can be async. So use a weakptr for
-  // the callback to make sure that the screenshot/encoding completion callback
-  // does not trigger on a destroyed WebContentsScreenshotManager.
-  base::WeakPtrFactory<WebContentsScreenshotManager> screenshot_factory_;
-
-  base::Time last_screenshot_time_;
-  int min_screenshot_interval_ms_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebContentsScreenshotManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index b51449e..4aa02cb 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -6,11 +6,11 @@
 
 #include "base/logging.h"
 #include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents_delegate.h"
 
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 079ed23..3f520db 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -8,6 +8,8 @@
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/dip_util.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
@@ -17,8 +19,6 @@
 #include "content/browser/web_contents/aura/image_window_delegate.h"
 #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
 #include "content/browser/web_contents/aura/window_slider.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/touch_editable_impl_aura.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/notification_observer.h"
@@ -40,6 +40,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/drag_drop_client.h"
 #include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/root_window_observer.h"
@@ -658,8 +659,8 @@
 
   virtual ~WindowObserver() {
     view_->window_->RemoveObserver(this);
-    if (view_->window_->GetRootWindow())
-      view_->window_->GetRootWindow()->RemoveRootWindowObserver(this);
+    if (view_->window_->GetDispatcher())
+      view_->window_->GetDispatcher()->RemoveRootWindowObserver(this);
     if (parent_)
       parent_->RemoveObserver(this);
   }
@@ -686,12 +687,12 @@
 
   virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
     if (window != parent_)
-      window->GetRootWindow()->AddRootWindowObserver(this);
+      window->GetDispatcher()->AddRootWindowObserver(this);
   }
 
   virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE {
     if (window != parent_)
-      window->GetRootWindow()->RemoveRootWindowObserver(this);
+      window->GetDispatcher()->RemoveRootWindowObserver(this);
   }
 
   // Overridden RootWindowObserver:
@@ -860,7 +861,7 @@
 }
 
 void WebContentsViewAura::EndDrag(WebKit::WebDragOperationsMask ops) {
-  aura::RootWindow* root_window = GetNativeView()->GetRootWindow();
+  aura::Window* root_window = GetNativeView()->GetRootWindow();
   gfx::Point screen_loc =
       gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
   gfx::Point client_loc = screen_loc;
@@ -1145,7 +1146,7 @@
   window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
   window_->SetTransparent(false);
   window_->Init(ui::LAYER_NOT_DRAWN);
-  aura::RootWindow* root_window = context ? context->GetRootWindow() : NULL;
+  aura::Window* root_window = context ? context->GetRootWindow() : NULL;
   if (root_window) {
     // There are places where there is no context currently because object
     // hierarchies are built before they're attached to a Widget. (See
@@ -1156,8 +1157,8 @@
     // explicitly add this WebContentsViewAura to their tree after they create
     // us.
     if (root_window) {
-      window_->SetDefaultParentByRootWindow(
-          root_window, root_window->GetBoundsInScreen());
+      aura::client::ParentWindowWithContext(
+          window_.get(), root_window, root_window->GetBoundsInScreen());
     }
   }
   window_->layer()->SetMasksToBounds(true);
@@ -1281,7 +1282,7 @@
     const gfx::ImageSkia& image,
     const gfx::Vector2d& image_offset,
     const DragEventSourceInfo& event_info) {
-  aura::RootWindow* root_window = GetNativeView()->GetRootWindow();
+  aura::Window* root_window = GetNativeView()->GetRootWindow();
   if (!aura::client::GetDragDropClient(root_window)) {
     web_contents_->SystemDragEnded();
     return;
@@ -1353,6 +1354,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WebContentsViewAura, OverscrollControllerDelegate implementation:
 
+gfx::Rect WebContentsViewAura::GetVisibleBounds() const {
+  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
+  if (!rwhv || !rwhv->IsShowing())
+    return gfx::Rect();
+
+  return rwhv->GetViewBounds();
+}
+
 void WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
   if (current_overscroll_gesture_ == OVERSCROLL_NONE)
     return;
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index aca720e..bccb677 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -145,6 +145,7 @@
   virtual void TakeFocus(bool reverse) OVERRIDE;
 
   // Overridden from OverscrollControllerDelegate:
+  virtual gfx::Rect GetVisibleBounds() const OVERRIDE;
   virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE;
   virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) OVERRIDE;
   virtual void OnOverscrollModeChange(OverscrollMode old_mode,
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 0ccea28..39ff893 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -12,11 +12,11 @@
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #endif
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/web_contents_screenshot_manager.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/web_contents/navigation_controller_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
-#include "content/browser/web_contents/web_contents_screenshot_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/common/content_switches.h"
@@ -150,7 +150,7 @@
     NavigateToURL(shell(), test_url);
     aura::Window* content =
         shell()->web_contents()->GetView()->GetContentNativeView();
-    content->GetRootWindow()->SetHostSize(gfx::Size(800, 600));
+    content->GetDispatcher()->SetHostSize(gfx::Size(800, 600));
 
     WebContentsImpl* web_contents =
         static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -331,21 +331,21 @@
   EXPECT_EQ(1, GetCurrentIndex());
 
   aura::Window* content = web_contents->GetView()->GetContentNativeView();
-  aura::RootWindow* root_window = content->GetRootWindow();
+  aura::WindowEventDispatcher* dispatcher = content->GetDispatcher();
   gfx::Rect bounds = content->GetBoundsInRootWindow();
 
   base::TimeDelta timestamp;
   ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
       gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
       0, timestamp);
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
   EXPECT_EQ(1, GetCurrentIndex());
 
   timestamp += base::TimeDelta::FromMilliseconds(10);
   ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
       gfx::Point(bounds.right() - 10, bounds.y() + 5),
       0, timestamp);
-  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+  dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
   EXPECT_EQ(1, GetCurrentIndex());
 
   // Swipe back from the right edge, back to the left edge, back to the right
@@ -356,7 +356,7 @@
     ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
         gfx::Point(x, bounds.y() + 5),
         0, timestamp);
-    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
+    dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
     EXPECT_EQ(1, GetCurrentIndex());
   }
 
@@ -365,7 +365,7 @@
     ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
         gfx::Point(x, bounds.y() + 5),
         0, timestamp);
-    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
+    dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
     EXPECT_EQ(1, GetCurrentIndex());
   }
 
@@ -374,7 +374,7 @@
     ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
         gfx::Point(x, bounds.y() + 5),
         0, timestamp);
-    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
+    dispatcher->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
     EXPECT_EQ(1, GetCurrentIndex());
   }
 
diff --git a/content/browser/web_contents/web_contents_view_gtk.cc b/content/browser/web_contents/web_contents_view_gtk.cc
index b0fb1da..a3cbb0e 100644
--- a/content/browser/web_contents/web_contents_view_gtk.cc
+++ b/content/browser/web_contents/web_contents_view_gtk.cc
@@ -13,10 +13,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_gtk.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_drag_dest_gtk.h"
 #include "content/browser/web_contents/web_drag_source_gtk.h"
diff --git a/content/browser/web_contents/web_contents_view_guest.cc b/content/browser/web_contents/web_contents_view_guest.cc
index a9fc40f..8d70a56 100644
--- a/content/browser/web_contents/web_contents_view_guest.cc
+++ b/content/browser/web_contents/web_contents_view_guest.cc
@@ -7,10 +7,10 @@
 #include "build/build_config.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_guest.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/drag_messages.h"
 #include "content/public/browser/web_contents_delegate.h"
diff --git a/content/browser/web_contents/web_contents_view_win.cc b/content/browser/web_contents/web_contents_view_win.cc
index 0c65b1d..5c64162 100644
--- a/content/browser/web_contents/web_contents_view_win.cc
+++ b/content/browser/web_contents/web_contents_view_win.cc
@@ -6,10 +6,10 @@
 
 #include "base/bind.h"
 #include "base/memory/scoped_vector.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_win.h"
-#include "content/browser/web_contents/interstitial_page_impl.h"
 #include "content/browser/web_contents/web_contents_drag_win.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_drag_dest_win.h"
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index fea43b5..044dedc 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -407,41 +407,6 @@
 }
 #endif
 
-void ZygoteHostImpl::AdjustLowMemoryMargin(int64 margin_mb) {
-#if defined(OS_CHROMEOS)
-  // You can't change the low memory margin unless you're root. Because of this,
-  // we can't set the low memory margin from the browser process.
-  // So, we use the SUID binary to change it for us.
-  if (using_suid_sandbox_) {
-#if defined(USE_TCMALLOC)
-    // If heap profiling is running, these processes are not exiting, at least
-    // on ChromeOS. The easiest thing to do is not launch them when profiling.
-    // TODO(stevenjb): Investigate further and fix.
-    if (IsHeapProfilerRunning())
-      return;
-#endif
-    std::vector<std::string> adj_low_mem_commandline;
-    adj_low_mem_commandline.push_back(sandbox_binary_);
-    adj_low_mem_commandline.push_back(sandbox::kAdjustLowMemMarginSwitch);
-    adj_low_mem_commandline.push_back(base::Int64ToString(margin_mb));
-
-    base::ProcessHandle sandbox_helper_process;
-    if (base::LaunchProcess(adj_low_mem_commandline, base::LaunchOptions(),
-                            &sandbox_helper_process)) {
-      base::EnsureProcessGetsReaped(sandbox_helper_process);
-    } else {
-      LOG(ERROR) << "Unable to run suid sandbox to set low memory margin.";
-    }
-  }
-  // Don't adjust memory margin if we're not running with the sandbox: this
-  // isn't very common, and not doing it has little impact.
-#else
-  // Low memory notification is currently only implemented on ChromeOS.
-  NOTREACHED() << "AdjustLowMemoryMargin not implemented";
-#endif  // defined(OS_CHROMEOS)
-}
-
-
 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) {
   DCHECK(init_);
   Pickle pickle;
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.h b/content/browser/zygote_host/zygote_host_impl_linux.h
index 6a1aca5..95591a4 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -55,7 +55,6 @@
   virtual int GetSandboxStatus() const OVERRIDE;
   virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle,
                                       int score) OVERRIDE;
-  virtual void AdjustLowMemoryMargin(int64 margin_mb) OVERRIDE;
 
  private:
   friend struct DefaultSingletonTraits<ZygoteHostImpl>;
diff --git a/content/child/child_histogram_message_filter.cc b/content/child/child_histogram_message_filter.cc
index 427dd0d..f05d111 100644
--- a/content/child/child_histogram_message_filter.cc
+++ b/content/child/child_histogram_message_filter.cc
@@ -8,8 +8,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/pickle.h"
+#include "base/metrics/histogram_delta_serialization.h"
 #include "content/child/child_process.h"
 #include "content/child/child_thread.h"
 #include "content/common/child_process_messages.h"
@@ -18,8 +17,7 @@
 
 ChildHistogramMessageFilter::ChildHistogramMessageFilter()
     : channel_(NULL),
-      io_message_loop_(ChildProcess::current()->io_message_loop_proxy()),
-      histogram_snapshot_manager_(this) {
+      io_message_loop_(ChildProcess::current()->io_message_loop_proxy()) {
 }
 
 ChildHistogramMessageFilter::~ChildHistogramMessageFilter() {
@@ -54,53 +52,19 @@
 }
 
 void ChildHistogramMessageFilter::UploadAllHistograms(int sequence_number) {
-  DCHECK_EQ(0u, pickled_histograms_.size());
+  if (!histogram_delta_serialization_) {
+    histogram_delta_serialization_.reset(
+        new base::HistogramDeltaSerialization("ChildProcess"));
+  }
 
-  // Push snapshots into our pickled_histograms_ vector.
-  // Note: Before serializing, we set the kIPCSerializationSourceFlag for all
-  // the histograms, so that the receiving process can distinguish them from the
-  // local histograms.
-  histogram_snapshot_manager_.PrepareDeltas(
-      base::Histogram::kIPCSerializationSourceFlag, false);
+  std::vector<std::string> deltas;
+  histogram_delta_serialization_->PrepareAndSerializeDeltas(&deltas);
+  channel_->Send(
+      new ChildProcessHostMsg_ChildHistogramData(sequence_number, deltas));
 
-  channel_->Send(new ChildProcessHostMsg_ChildHistogramData(
-      sequence_number, pickled_histograms_));
-
-  pickled_histograms_.clear();
   static int count = 0;
   count++;
   DHISTOGRAM_COUNTS("Histogram.ChildProcessHistogramSentCount", count);
 }
 
-void ChildHistogramMessageFilter::RecordDelta(
-    const base::HistogramBase& histogram,
-    const base::HistogramSamples& snapshot) {
-  DCHECK_NE(0, snapshot.TotalCount());
-
-  Pickle pickle;
-  histogram.SerializeInfo(&pickle);
-  snapshot.Serialize(&pickle);
-
-  pickled_histograms_.push_back(
-      std::string(static_cast<const char*>(pickle.data()), pickle.size()));
-}
-
-void ChildHistogramMessageFilter::InconsistencyDetected(
-    base::HistogramBase::Inconsistency problem) {
-  UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesChildProcess",
-                            problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
-}
-
-void ChildHistogramMessageFilter::UniqueInconsistencyDetected(
-    base::HistogramBase::Inconsistency problem) {
-  UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesChildProcessUnique",
-                            problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
-}
-
-void ChildHistogramMessageFilter::InconsistencyDetectedInLoggedCount(
-    int amount) {
-  UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotChildProcess",
-                       std::abs(amount));
-}
-
 }  // namespace content
diff --git a/content/child/child_histogram_message_filter.h b/content/child/child_histogram_message_filter.h
index 85d2e20..98a30a2 100644
--- a/content/child/child_histogram_message_filter.h
+++ b/content/child/child_histogram_message_filter.h
@@ -9,20 +9,16 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_flattener.h"
-#include "base/metrics/histogram_snapshot_manager.h"
 #include "ipc/ipc_channel_proxy.h"
 
 namespace base {
-class HistogramSamples;
+class HistogramDeltaSerialization;
 class MessageLoopProxy;
 }  // namespace base
 
 namespace content {
 
-class ChildHistogramMessageFilter : public base::HistogramFlattener,
-                                    public IPC::ChannelProxy::MessageFilter {
+class ChildHistogramMessageFilter : public IPC::ChannelProxy::MessageFilter {
  public:
   ChildHistogramMessageFilter();
 
@@ -33,15 +29,6 @@
 
   void SendHistograms(int sequence_number);
 
-  // HistogramFlattener interface (override) methods.
-  virtual void RecordDelta(const base::HistogramBase& histogram,
-                           const base::HistogramSamples& snapshot) OVERRIDE;
-  virtual void InconsistencyDetected(
-      base::HistogramBase::Inconsistency problem) OVERRIDE;
-  virtual void UniqueInconsistencyDetected(
-      base::HistogramBase::Inconsistency problem) OVERRIDE;
-  virtual void InconsistencyDetectedInLoggedCount(int amount) OVERRIDE;
-
  private:
   typedef std::vector<std::string> HistogramPickledList;
 
@@ -58,11 +45,8 @@
 
   scoped_refptr<base::MessageLoopProxy> io_message_loop_;
 
-  // Collection of histograms to send to the browser.
-  HistogramPickledList pickled_histograms_;
-
-  // |histogram_snapshot_manager_| prepares histogram deltas for transmission.
-  base::HistogramSnapshotManager histogram_snapshot_manager_;
+  // Prepares histogram deltas for transmission.
+  scoped_ptr<base::HistogramDeltaSerialization> histogram_delta_serialization_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildHistogramMessageFilter);
 };
diff --git a/content/child/child_thread.cc b/content/child/child_thread.cc
index 95b36c6..276b3ad 100644
--- a/content/child/child_thread.cc
+++ b/content/child/child_thread.cc
@@ -4,6 +4,8 @@
 
 #include "content/child/child_thread.h"
 
+#include <string>
+
 #include "base/allocator/allocator_extension.h"
 #include "base/base_switches.h"
 #include "base/command_line.h"
@@ -25,6 +27,8 @@
 #include "content/child/quota_dispatcher.h"
 #include "content/child/quota_message_filter.h"
 #include "content/child/resource_dispatcher.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
+#include "content/child/service_worker/service_worker_message_filter.h"
 #include "content/child/socket_stream_dispatcher.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/child/websocket_dispatcher.h"
@@ -109,7 +113,7 @@
 // doesn't handle the case. Thus, we need our own class here.
 struct CondVarLazyInstanceTraits {
   static const bool kRegisterOnExit = true;
-  static const bool kAllowedToAccessOnNonjoinableThread = false;
+  static const bool kAllowedToAccessOnNonjoinableThread ALLOW_UNUSED = false;
   static base::ConditionVariable* New(void* instance) {
     return new (instance) base::ConditionVariable(
         g_lazy_child_thread_lock.Pointer());
@@ -133,7 +137,8 @@
 }  // namespace
 
 ChildThread::ChildThread()
-    : channel_connected_factory_(this) {
+    : channel_connected_factory_(this),
+      in_browser_process_(false) {
   channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
       switches::kProcessChannelID);
   Init();
@@ -141,7 +146,8 @@
 
 ChildThread::ChildThread(const std::string& channel_name)
     : channel_name_(channel_name),
-      channel_connected_factory_(this) {
+      channel_connected_factory_(this),
+      in_browser_process_(true) {
   Init();
 }
 
@@ -163,7 +169,8 @@
                            true,
                            ChildProcess::current()->GetShutDownEvent()));
 #ifdef IPC_MESSAGE_LOG_ENABLED
-  IPC::Logging::GetInstance()->SetIPCSender(this);
+  if (!in_browser_process_)
+    IPC::Logging::GetInstance()->SetIPCSender(this);
 #endif
 
   sync_message_filter_ =
@@ -180,6 +187,11 @@
   resource_message_filter_ =
       new ChildResourceMessageFilter(resource_dispatcher());
 
+  service_worker_message_filter_ =
+      new ServiceWorkerMessageFilter(thread_safe_sender_.get());
+  service_worker_dispatcher_.reset(
+      new ServiceWorkerDispatcher(thread_safe_sender_.get()));
+
   quota_message_filter_ =
       new QuotaMessageFilter(thread_safe_sender_.get());
   quota_dispatcher_.reset(new QuotaDispatcher(thread_safe_sender_.get(),
@@ -191,6 +203,7 @@
       ChildProcess::current()->io_message_loop_proxy()));
   channel_->AddFilter(resource_message_filter_.get());
   channel_->AddFilter(quota_message_filter_.get());
+  channel_->AddFilter(service_worker_message_filter_.get());
 
   // In single process mode we may already have a power monitor
   if (!base::PowerMonitor::Get()) {
@@ -252,6 +265,7 @@
   IPC::Logging::GetInstance()->SetIPCSender(NULL);
 #endif
 
+  channel_->RemoveFilter(service_worker_message_filter_.get());
   channel_->RemoveFilter(quota_message_filter_.get());
   channel_->RemoveFilter(histogram_message_filter_.get());
   channel_->RemoveFilter(sync_message_filter_.get());
diff --git a/content/child/child_thread.h b/content/child/child_thread.h
index 94918fe..2c1dcd0 100644
--- a/content/child/child_thread.h
+++ b/content/child/child_thread.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_CHILD_CHILD_THREAD_H_
 #define CONTENT_CHILD_CHILD_THREAD_H_
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
@@ -37,6 +39,8 @@
 class ChildHistogramMessageFilter;
 class ChildResourceMessageFilter;
 class FileSystemDispatcher;
+class ServiceWorkerDispatcher;
+class ServiceWorkerMessageFilter;
 class QuotaDispatcher;
 class QuotaMessageFilter;
 class ResourceDispatcher;
@@ -49,7 +53,7 @@
  public:
   // Creates the thread.
   ChildThread();
-  // Used for single-process mode.
+  // Used for single-process mode and for in process gpu mode.
   explicit ChildThread(const std::string& channel_name);
   // ChildProcess::main_thread() is reset after Shutdown(), and before the
   // destructor, so any subsystem that relies on ChildProcess::main_thread()
@@ -100,6 +104,10 @@
     return file_system_dispatcher_.get();
   }
 
+  ServiceWorkerDispatcher* service_worker_dispatcher() const {
+    return service_worker_dispatcher_.get();
+  }
+
   QuotaDispatcher* quota_dispatcher() const {
     return quota_dispatcher_.get();
   }
@@ -119,6 +127,10 @@
     return histogram_message_filter_.get();
   }
 
+  ServiceWorkerMessageFilter* service_worker_message_filter() const {
+    return service_worker_message_filter_.get();
+  }
+
   QuotaMessageFilter* quota_message_filter() const {
     return quota_message_filter_.get();
   }
@@ -195,12 +207,16 @@
 
   scoped_ptr<FileSystemDispatcher> file_system_dispatcher_;
 
+  scoped_ptr<ServiceWorkerDispatcher> service_worker_dispatcher_;
+
   scoped_ptr<QuotaDispatcher> quota_dispatcher_;
 
   scoped_refptr<ChildHistogramMessageFilter> histogram_message_filter_;
 
   scoped_refptr<ChildResourceMessageFilter> resource_message_filter_;
 
+  scoped_refptr<ServiceWorkerMessageFilter> service_worker_message_filter_;
+
   scoped_refptr<QuotaMessageFilter> quota_message_filter_;
 
   base::WeakPtrFactory<ChildThread> channel_connected_factory_;
@@ -211,6 +227,8 @@
 
   scoped_ptr<base::PowerMonitor> power_monitor_;
 
+  bool in_browser_process_;
+
   DISALLOW_COPY_AND_ASSIGN(ChildThread);
 };
 
diff --git a/content/child/fileapi/webfilewriter_base.cc b/content/child/fileapi/webfilewriter_base.cc
index 705f211..5a97b57 100644
--- a/content/child/fileapi/webfilewriter_base.cc
+++ b/content/child/fileapi/webfilewriter_base.cc
@@ -30,14 +30,6 @@
   DoTruncate(path_, length);
 }
 
-void WebFileWriterBase::write(long long position,
-                              const WebKit::WebURL& blob_url) {
-  DCHECK_EQ(kOperationNone, operation_);
-  DCHECK_EQ(kCancelNotInProgress, cancel_state_);
-  operation_ = kOperationWrite;
-  DoWriteDeprecated(path_, blob_url, position);
-}
-
 void WebFileWriterBase::write(
       long long position,
       const WebKit::WebString& id) {
diff --git a/content/child/fileapi/webfilewriter_base.h b/content/child/fileapi/webfilewriter_base.h
index 415d286..af63ffb 100644
--- a/content/child/fileapi/webfilewriter_base.h
+++ b/content/child/fileapi/webfilewriter_base.h
@@ -28,9 +28,6 @@
   virtual void write(long long position, const WebKit::WebString& id);
   virtual void cancel();
 
-  // DEPRECATED: see crbug/174200
-  virtual void write(long long position, const WebKit::WebURL& blobURL);
-
  protected:
   // This calls DidSucceed() or DidFail() based on the value of |error_code|.
   void DidFinish(base::PlatformFileError error_code);
@@ -43,9 +40,6 @@
   // the requested operation, and they must call the appropiate DidSomething
   // method upon completion and as progress is made in the Write case.
   virtual void DoTruncate(const GURL& path, int64 offset) = 0;
-  virtual void DoWriteDeprecated(const GURL& path,
-                                 const GURL& blob_url,
-                                 int64 offset) = 0;
   virtual void DoWrite(const GURL& path,
                        const std::string& blob_id,
                        int64 offset) = 0;
diff --git a/content/child/fileapi/webfilewriter_base_unittest.cc b/content/child/fileapi/webfilewriter_base_unittest.cc
index 329665a..95c849a 100644
--- a/content/child/fileapi/webfilewriter_base_unittest.cc
+++ b/content/child/fileapi/webfilewriter_base_unittest.cc
@@ -51,7 +51,6 @@
     received_write_ = false;
     received_write_path_ = GURL();
     received_write_offset_ = kNoOffset;
-    received_write_blob_url_ = GURL();
     received_write_blob_uuid_ = std::string();
     received_cancel_ = false;
   }
@@ -61,7 +60,6 @@
   int64 received_truncate_offset_;
   bool received_write_;
   GURL received_write_path_;
-  GURL received_write_blob_url_;
   std::string received_write_blob_uuid_;
   int64 received_write_offset_;
   bool received_cancel_;
@@ -89,41 +87,6 @@
     }
   }
 
-  virtual void DoWriteDeprecated(
-        const GURL& path, const GURL& blob_url,
-        int64 offset) OVERRIDE {
-    received_write_ = true;
-    received_write_path_ = path;
-    received_write_offset_ = offset;
-    received_write_blob_url_ = blob_url;
-
-    if (offset == kBasicFileWrite_Offset) {
-      DidWrite(1, true);
-    } else if (offset == kErrorFileWrite_Offset) {
-      DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND);
-    } else if (offset == kMultiFileWrite_Offset) {
-      DidWrite(1, false);
-      DidWrite(1, false);
-      DidWrite(1, true);
-    } else if (offset == kCancelFileWriteBeforeCompletion_Offset) {
-      DidWrite(1, false);
-      cancel();
-      DidWrite(1, false);
-      DidWrite(1, false);
-      DidFail(base::PLATFORM_FILE_ERROR_FAILED);  // write completion
-      DidSucceed();  // cancel completion
-    } else if (offset == kCancelFileWriteAfterCompletion_Offset) {
-      DidWrite(1, false);
-      cancel();
-      DidWrite(1, false);
-      DidWrite(1, false);
-      DidWrite(1, true);  // write completion
-      DidFail(base::PLATFORM_FILE_ERROR_FAILED);  // cancel completion
-    } else {
-      FAIL();
-    }
-  }
-
   virtual void DoWrite(
         const GURL& path, const std::string& blob_uuid,
         int64 offset) OVERRIDE {
@@ -228,13 +191,11 @@
   DISALLOW_COPY_AND_ASSIGN(FileWriterTest);
 };
 
-
-// TODO(michaeln): crbug/174200, update the tests once blink is migrated.
-
 TEST_F(FileWriterTest, BasicFileWrite) {
   // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kBasicFileWrite_Offset, kBlobUrl);
+  const std::string kBlobId("1234");
+  writer()->write(kBasicFileWrite_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
 
   // Check that the derived class gets called correctly.
   EXPECT_TRUE(testable_writer_->received_write_);
@@ -242,7 +203,7 @@
             mock_path_as_gurl());
   EXPECT_EQ(kBasicFileWrite_Offset,
             testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
   EXPECT_FALSE(testable_writer_->received_truncate_);
   EXPECT_FALSE(testable_writer_->received_cancel_);
 
@@ -275,8 +236,9 @@
 
 TEST_F(FileWriterTest, ErrorFileWrite) {
   // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kErrorFileWrite_Offset, kBlobUrl);
+  const std::string kBlobId("1234");
+  writer()->write(kErrorFileWrite_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
 
   // Check that the derived class gets called correctly.
   EXPECT_TRUE(testable_writer_->received_write_);
@@ -284,7 +246,7 @@
             mock_path_as_gurl());
   EXPECT_EQ(kErrorFileWrite_Offset,
             testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
   EXPECT_FALSE(testable_writer_->received_truncate_);
   EXPECT_FALSE(testable_writer_->received_cancel_);
 
@@ -317,8 +279,9 @@
 
 TEST_F(FileWriterTest, MultiFileWrite) {
   // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kMultiFileWrite_Offset, kBlobUrl);
+  const std::string kBlobId("1234");
+  writer()->write(kMultiFileWrite_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
 
   // Check that the derived class gets called correctly.
   EXPECT_TRUE(testable_writer_->received_write_);
@@ -326,7 +289,7 @@
             mock_path_as_gurl());
   EXPECT_EQ(kMultiFileWrite_Offset,
             testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
   EXPECT_FALSE(testable_writer_->received_truncate_);
   EXPECT_FALSE(testable_writer_->received_cancel_);
 
@@ -340,8 +303,9 @@
 
 TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) {
   // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kCancelFileWriteBeforeCompletion_Offset, kBlobUrl);
+  const std::string kBlobId("1234");
+  writer()->write(kCancelFileWriteBeforeCompletion_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
 
   // Check that the derived class gets called correctly.
   EXPECT_TRUE(testable_writer_->received_write_);
@@ -349,7 +313,7 @@
             mock_path_as_gurl());
   EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset,
             testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
   EXPECT_TRUE(testable_writer_->received_cancel_);
   EXPECT_FALSE(testable_writer_->received_truncate_);
 
@@ -364,8 +328,9 @@
 
 TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) {
   // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kCancelFileWriteAfterCompletion_Offset, kBlobUrl);
+  const std::string kBlobId("1234");
+  writer()->write(kCancelFileWriteAfterCompletion_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
 
   // Check that the derived class gets called correctly.
   EXPECT_TRUE(testable_writer_->received_write_);
@@ -373,7 +338,7 @@
             mock_path_as_gurl());
   EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset,
             testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
   EXPECT_TRUE(testable_writer_->received_cancel_);
   EXPECT_FALSE(testable_writer_->received_truncate_);
 
@@ -427,8 +392,10 @@
 }
 
 TEST_F(FileWriterTest, DeleteInCompletionCallbacks) {
+  const std::string kBlobId("1234");
   delete_in_client_callback_ = true;
-  writer()->write(kBasicFileWrite_Offset, GURL("blob://bloburl/"));
+  writer()->write(kBasicFileWrite_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
   EXPECT_FALSE(testable_writer_.get());
 
   reset();
@@ -438,7 +405,8 @@
 
   reset();
   delete_in_client_callback_ = true;
-  writer()->write(kErrorFileWrite_Offset, GURL("blob://bloburl/"));
+  writer()->write(kErrorFileWrite_Offset,
+                  WebKit::WebString::fromUTF8(kBlobId));
   EXPECT_FALSE(testable_writer_.get());
 
   reset();
diff --git a/content/child/fileapi/webfilewriter_impl.cc b/content/child/fileapi/webfilewriter_impl.cc
index bcdc0d2..bd5fbe3 100644
--- a/content/child/fileapi/webfilewriter_impl.cc
+++ b/content/child/fileapi/webfilewriter_impl.cc
@@ -50,20 +50,6 @@
         base::Bind(&WriterBridge::DidFinish, this));
   }
 
-  void WriteDeprecated(
-      const GURL& path, const GURL& blob_url, int64 offset,
-      const WriteCallback& write_callback,
-      const StatusCallback& error_callback) {
-    write_callback_ = write_callback;
-    status_callback_ = error_callback;
-    if (!GetFileSystemDispatcher())
-      return;
-    ChildThread::current()->file_system_dispatcher()->WriteDeprecated(
-        path, blob_url, offset, &request_id_,
-        base::Bind(&WriterBridge::DidWrite, this),
-        base::Bind(&WriterBridge::DidFinish, this));
-  }
-
   void Write(const GURL& path, const std::string& id, int64 offset,
              const WriteCallback& write_callback,
              const StatusCallback& error_callback) {
@@ -153,14 +139,6 @@
       base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
 }
 
-void WebFileWriterImpl::DoWriteDeprecated(
-    const GURL& path, const GURL& blob_url, int64 offset) {
-  RunOnMainThread(base::Bind(&WriterBridge::WriteDeprecated, bridge_,
-      path, blob_url, offset,
-      base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()),
-      base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr())));
-}
-
 void WebFileWriterImpl::DoWrite(
     const GURL& path, const std::string& blob_id, int64 offset) {
   RunOnMainThread(base::Bind(&WriterBridge::Write, bridge_,
diff --git a/content/child/fileapi/webfilewriter_impl.h b/content/child/fileapi/webfilewriter_impl.h
index c4a5995..c92ea1e 100644
--- a/content/child/fileapi/webfilewriter_impl.h
+++ b/content/child/fileapi/webfilewriter_impl.h
@@ -32,8 +32,6 @@
  protected:
   // WebFileWriterBase overrides
   virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE;
-  virtual void DoWriteDeprecated(
-      const GURL& path, const GURL& blob_url, int64 offset) OVERRIDE;
   virtual void DoWrite(const GURL& path, const std::string& blob_id,
                        int64 offset) OVERRIDE;
   virtual void DoCancel() OVERRIDE;
diff --git a/content/child/npapi/np_channel_base.cc b/content/child/npapi/np_channel_base.cc
index da77c44..081910c 100644
--- a/content/child/npapi/np_channel_base.cc
+++ b/content/child/npapi/np_channel_base.cc
@@ -4,12 +4,11 @@
 
 #include "content/child/npapi/np_channel_base.h"
 
-#include <stack>
-
 #include "base/auto_reset.h"
 #include "base/containers/hash_tables.h"
 #include "base/lazy_instance.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_local.h"
 #include "ipc/ipc_sync_message.h"
 
 #if defined(OS_POSIX)
@@ -18,13 +17,47 @@
 
 namespace content {
 
-typedef base::hash_map<std::string, scoped_refptr<NPChannelBase> > ChannelMap;
-static base::LazyInstance<ChannelMap>::Leaky
-     g_channels = LAZY_INSTANCE_INITIALIZER;
+namespace {
 
-typedef std::stack<scoped_refptr<NPChannelBase> > NPChannelRefStack;
-static base::LazyInstance<NPChannelRefStack>::Leaky
-    g_lazy_channel_stack = LAZY_INSTANCE_INITIALIZER;
+typedef base::hash_map<std::string, scoped_refptr<NPChannelBase> > ChannelMap;
+
+struct ChannelGlobals {
+  ChannelMap channel_map;
+  scoped_refptr<NPChannelBase> current_channel;
+};
+
+#if defined(OS_ANDROID)
+// Workaround for http://crbug.com/298179 - NPChannelBase is only intended
+// for use on one thread per process. Using TLS to store the globals removes the
+// worst thread hostility in this class, especially needed for webview which
+// runs in single-process mode. TODO(joth): Make a complete fix, most likely
+// as part of addressing http://crbug.com/258510.
+base::LazyInstance<base::ThreadLocalPointer<ChannelGlobals> >::Leaky
+    g_channels_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+
+ChannelGlobals* GetChannelGlobals() {
+  ChannelGlobals* globals = g_channels_tls_ptr.Get().Get();
+  if (!globals) {
+    globals = new ChannelGlobals;
+    g_channels_tls_ptr.Get().Set(globals);
+  }
+  return globals;
+}
+
+#else
+
+base::LazyInstance<ChannelGlobals>::Leaky g_channels_globals =
+    LAZY_INSTANCE_INITIALIZER;
+
+ChannelGlobals* GetChannelGlobals() { return g_channels_globals.Pointer(); }
+
+#endif  // OS_ANDROID
+
+ChannelMap* GetChannelMap() {
+  return &GetChannelGlobals()->channel_map;
+}
+
+}  // namespace
 
 NPChannelBase* NPChannelBase::GetChannel(
     const IPC::ChannelHandle& channel_handle, IPC::Channel::Mode mode,
@@ -32,8 +65,8 @@
     bool create_pipe_now, base::WaitableEvent* shutdown_event) {
   scoped_refptr<NPChannelBase> channel;
   std::string channel_key = channel_handle.name;
-  ChannelMap::const_iterator iter = g_channels.Get().find(channel_key);
-  if (iter == g_channels.Get().end()) {
+  ChannelMap::const_iterator iter = GetChannelMap()->find(channel_key);
+  if (iter == GetChannelMap()->end()) {
     channel = factory();
   } else {
     channel = iter->second;
@@ -49,7 +82,7 @@
     }
     channel->mode_ = mode;
     if (channel->Init(ipc_message_loop, create_pipe_now, shutdown_event)) {
-      g_channels.Get()[channel_key] = channel;
+      (*GetChannelMap())[channel_key] = channel;
     } else {
       channel = NULL;
     }
@@ -59,8 +92,8 @@
 }
 
 void NPChannelBase::Broadcast(IPC::Message* message) {
-  for (ChannelMap::iterator iter = g_channels.Get().begin();
-       iter != g_channels.Get().end();
+  for (ChannelMap::iterator iter = GetChannelMap()->begin();
+       iter != GetChannelMap()->end();
        ++iter) {
     iter->second->Send(new IPC::Message(*message));
   }
@@ -88,15 +121,15 @@
 }
 
 NPChannelBase* NPChannelBase::GetCurrentChannel() {
-  return g_lazy_channel_stack.Pointer()->top().get();
+  return GetChannelGlobals()->current_channel.get();
 }
 
 void NPChannelBase::CleanupChannels() {
   // Make a copy of the references as we can't iterate the map since items will
   // be removed from it as we clean them up.
   std::vector<scoped_refptr<NPChannelBase> > channels;
-  for (ChannelMap::const_iterator iter = g_channels.Get().begin();
-       iter != g_channels.Get().end();
+  for (ChannelMap::const_iterator iter = GetChannelMap()->begin();
+       iter != GetChannelMap()->end();
        ++iter) {
     channels.push_back(iter->second);
   }
@@ -106,7 +139,7 @@
 
   // This will clean up channels added to the map for which subsequent
   // AddRoute wasn't called
-  g_channels.Get().clear();
+  GetChannelMap()->clear();
 }
 
 NPObjectBase* NPChannelBase::GetNPObjectListenerForRoute(int route_id) {
@@ -164,14 +197,15 @@
 }
 
 int NPChannelBase::Count() {
-  return static_cast<int>(g_channels.Get().size());
+  return static_cast<int>(GetChannelMap()->size());
 }
 
 bool NPChannelBase::OnMessageReceived(const IPC::Message& message) {
-  // This call might cause us to be deleted, so keep an extra reference to
-  // ourself so that we can send the reply and decrement back in_dispatch_.
-  g_lazy_channel_stack.Pointer()->push(
-      scoped_refptr<NPChannelBase>(this));
+  // Push this channel as the current channel being processed. This also forms
+  // a stack of scoped_refptr avoiding ourselves (or any instance higher
+  // up the callstack) from being deleted while processing a message.
+  base::AutoReset<scoped_refptr<NPChannelBase> > keep_alive(
+      &GetChannelGlobals()->current_channel, this);
 
   bool handled;
   if (message.should_unblock())
@@ -191,7 +225,6 @@
   if (message.should_unblock())
     in_unblock_dispatch_--;
 
-  g_lazy_channel_stack.Pointer()->pop();
   return handled;
 }
 
@@ -242,10 +275,10 @@
       }
     }
 
-    for (ChannelMap::iterator iter = g_channels.Get().begin();
-         iter != g_channels.Get().end(); ++iter) {
+    for (ChannelMap::iterator iter = GetChannelMap()->begin();
+         iter != GetChannelMap()->end(); ++iter) {
       if (iter->second.get() == this) {
-        g_channels.Get().erase(iter);
+        GetChannelMap()->erase(iter);
         return;
       }
     }
@@ -267,12 +300,12 @@
   // Once an error is seen on a channel, remap the channel to prevent
   // it from being vended again.  Keep the channel in the map so
   // RemoveRoute() can clean things up correctly.
-  for (ChannelMap::iterator iter = g_channels.Get().begin();
-       iter != g_channels.Get().end(); ++iter) {
+  for (ChannelMap::iterator iter = GetChannelMap()->begin();
+       iter != GetChannelMap()->end(); ++iter) {
     if (iter->second.get() == this) {
       // Insert new element before invalidating |iter|.
-      g_channels.Get()[iter->first + "-error"] = iter->second;
-      g_channels.Get().erase(iter);
+      (*GetChannelMap())[iter->first + "-error"] = iter->second;
+      GetChannelMap()->erase(iter);
       break;
     }
   }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index aebad1c..158ec7c 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -44,6 +44,8 @@
   WebRuntimeFeatures::enableDataListElement(false);
   // Android does not yet support the Web Notification API. crbug.com/115320
   WebRuntimeFeatures::enableNotifications(false);
+  // Android does not yet support SharedWorker. crbug.com/154571
+  WebRuntimeFeatures::enableSharedWorker(false);
 #endif  // defined(OS_ANDROID)
 }
 
@@ -80,6 +82,9 @@
   if (command_line.HasSwitch(switches::kDisableUnprefixedMediaSource))
     WebRuntimeFeatures::enableMediaSource(false);
 
+  if (command_line.HasSwitch(switches::kDisableSharedWorkers))
+    WebRuntimeFeatures::enableSharedWorker(false);
+
 #if defined(OS_ANDROID)
   if (command_line.HasSwitch(switches::kDisableWebRTC)) {
     WebRuntimeFeatures::enableMediaStream(false);
diff --git a/content/child/service_worker/OWNERS b/content/child/service_worker/OWNERS
new file mode 100644
index 0000000..633b8a4
--- /dev/null
+++ b/content/child/service_worker/OWNERS
@@ -0,0 +1,3 @@
+alecflett@chromium.org
+kinuko@chromium.org
+michaeln@chromium.org
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
new file mode 100644
index 0000000..406de2d
--- /dev/null
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -0,0 +1,131 @@
+// Copyright 2013 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/child/service_worker/service_worker_dispatcher.h"
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
+#include "content/child/service_worker/web_service_worker_impl.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/common/service_worker_messages.h"
+#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+
+using WebKit::WebServiceWorkerProvider;
+using base::ThreadLocalPointer;
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+
+namespace {
+
+base::LazyInstance<ThreadLocalPointer<ServiceWorkerDispatcher> >::Leaky
+    g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
+
+ServiceWorkerDispatcher* const kHasBeenDeleted =
+    reinterpret_cast<ServiceWorkerDispatcher*>(0x1);
+
+int CurrentWorkerId() {
+  return WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+
+}  // namespace
+
+ServiceWorkerDispatcher::ServiceWorkerDispatcher(
+    ThreadSafeSender* thread_safe_sender)
+    : thread_safe_sender_(thread_safe_sender) {
+  g_dispatcher_tls.Pointer()->Set(this);
+}
+
+ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
+  g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
+}
+
+void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered,
+                        OnServiceWorkerRegistered)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistered,
+                        OnServiceWorkerUnregistered)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  DCHECK(handled) << "Unhandled message:" << msg.type();
+}
+
+bool ServiceWorkerDispatcher::Send(IPC::Message* msg) {
+  return thread_safe_sender_->Send(msg);
+}
+
+void ServiceWorkerDispatcher::RegisterServiceWorker(
+    const GURL& pattern,
+    const GURL& script_url,
+    WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = pending_callbacks_.Add(callbacks);
+  thread_safe_sender_->Send(new ServiceWorkerHostMsg_RegisterServiceWorker(
+      CurrentWorkerId(), request_id, pattern, script_url));
+}
+
+void ServiceWorkerDispatcher::UnregisterServiceWorker(
+    const GURL& pattern,
+    WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = pending_callbacks_.Add(callbacks);
+  thread_safe_sender_->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker(
+      CurrentWorkerId(), request_id, pattern));
+}
+
+ServiceWorkerDispatcher* ServiceWorkerDispatcher::ThreadSpecificInstance(
+    ThreadSafeSender* thread_safe_sender) {
+  if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
+    NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher.";
+    g_dispatcher_tls.Pointer()->Set(NULL);
+  }
+  if (g_dispatcher_tls.Pointer()->Get())
+    return g_dispatcher_tls.Pointer()->Get();
+
+  ServiceWorkerDispatcher* dispatcher =
+      new ServiceWorkerDispatcher(thread_safe_sender);
+  if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+    webkit_glue::WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
+  return dispatcher;
+}
+
+void ServiceWorkerDispatcher::OnServiceWorkerRegistered(
+    int32 thread_id,
+    int32 request_id,
+    int64 service_worker_id) {
+  WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks =
+      pending_callbacks_.Lookup(request_id);
+  DCHECK(callbacks);
+  if (!callbacks)
+    return;
+
+  // the browser has to generate the service_worker_id so the same
+  // worker can be called from different renderer contexts. However,
+  // the impl object doesn't have to be the same instance across calls
+  // unless we require the DOM objects to be identical when there's a
+  // duplicate registration. So for now we mint a new object each
+  // time.
+  scoped_ptr<WebServiceWorkerImpl> worker(
+      new WebServiceWorkerImpl(service_worker_id));
+  callbacks->onSuccess(worker.release());
+  pending_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerDispatcher::OnServiceWorkerUnregistered(int32 thread_id,
+                                                          int32 request_id) {
+  WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks =
+      pending_callbacks_.Lookup(request_id);
+  DCHECK(callbacks);
+  if (!callbacks)
+    return;
+
+  callbacks->onSuccess(NULL);
+  pending_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() { delete this; }
+
+}  // namespace content
diff --git a/content/child/service_worker/service_worker_dispatcher.h b/content/child/service_worker/service_worker_dispatcher.h
new file mode 100644
index 0000000..82a9f8b
--- /dev/null
+++ b/content/child/service_worker/service_worker_dispatcher.h
@@ -0,0 +1,76 @@
+// Copyright 2013 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_CHILD_SERVICE_WORKER_SERVICE_WORKER_DISPATCHER_H_
+#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_DISPATCHER_H_
+
+#include "base/id_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerProvider.h"
+#include "webkit/child/worker_task_runner.h"
+
+class GURL;
+
+namespace WebKit {
+class WebURL;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+class ServiceWorkerMessageFilter;
+class ThreadSafeSender;
+class WebServiceWorkerImpl;
+
+// This class manages communication with the browser process about
+// registration of the service worker, exposed to renderer and worker
+// scripts through methods like navigator.registerServiceWorker().
+class ServiceWorkerDispatcher : public webkit_glue::WorkerTaskRunner::Observer {
+ public:
+  explicit ServiceWorkerDispatcher(ThreadSafeSender* thread_safe_sender);
+  virtual ~ServiceWorkerDispatcher();
+
+  void OnMessageReceived(const IPC::Message& msg);
+  bool Send(IPC::Message* msg);
+
+  // Corresponds to navigator.registerServiceWorker()
+  void RegisterServiceWorker(
+      const GURL& pattern,
+      const GURL& script_url,
+      WebKit::WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks);
+  // Corresponds to navigator.unregisterServiceWorker()
+  void UnregisterServiceWorker(
+      const GURL& pattern,
+      WebKit::WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks);
+
+  // |thread_safe_sender| needs to be passed in because if the call leads to
+  // construction it will be needed.
+  static ServiceWorkerDispatcher* ThreadSpecificInstance(
+      ThreadSafeSender* thread_safe_sender);
+
+ private:
+  // webkit_glue::WorkerTaskRunner::Observer implementation.
+  virtual void OnWorkerRunLoopStopped() OVERRIDE;
+
+  // The asynchronous success response to RegisterServiceWorker.
+  void OnServiceWorkerRegistered(int32 thread_id,
+                                 int32 request_id,
+                                 int64 service_worker_id);
+  // The asynchronous success response to UregisterServiceWorker.
+  void OnServiceWorkerUnregistered(int32 thread_id, int32 request_id);
+
+  IDMap<WebKit::WebServiceWorkerProvider::WebServiceWorkerCallbacks,
+        IDMapOwnPointer> pending_callbacks_;
+
+  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDispatcher);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_DISPATCHER_H_
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
new file mode 100644
index 0000000..aaacabe
--- /dev/null
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 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/child/service_worker/service_worker_message_filter.h"
+
+#include "ipc/ipc_message_macros.h"
+#include "base/bind.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/pickle.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
+#include "content/child/thread_safe_sender.h"
+#include "webkit/child/worker_task_runner.h"
+
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+
+ServiceWorkerMessageFilter::ServiceWorkerMessageFilter(ThreadSafeSender* sender)
+    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
+      thread_safe_sender_(sender) {}
+
+ServiceWorkerMessageFilter::~ServiceWorkerMessageFilter() {}
+
+bool ServiceWorkerMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+  if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
+    return false;
+  int thread_id = 0;
+  bool result = PickleIterator(msg).ReadInt(&thread_id);
+  DCHECK(result);
+  base::Closure closure =
+      base::Bind(&ServiceWorkerMessageFilter::DispatchMessage, this, msg);
+  if (!thread_id) {
+    main_thread_loop_proxy_->PostTask(FROM_HERE, closure);
+    return true;
+  }
+  WorkerTaskRunner::Instance()->PostTask(thread_id, closure);
+  return true;
+}
+
+void ServiceWorkerMessageFilter::DispatchMessage(const IPC::Message& msg) {
+  ServiceWorkerDispatcher::ThreadSpecificInstance(thread_safe_sender_.get())
+      ->OnMessageReceived(msg);
+}
+
+}  // namespace content
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
new file mode 100644
index 0000000..5400e74
--- /dev/null
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -0,0 +1,40 @@
+// Copyright 2013 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_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
+
+#include <map>
+
+#include "content/common/content_export.h"
+#include "ipc/ipc_channel_proxy.h"
+
+namespace content {
+
+class ThreadSafeSender;
+class MessageLoopProxy;
+
+class CONTENT_EXPORT ServiceWorkerMessageFilter
+    : public IPC::ChannelProxy::MessageFilter {
+ public:
+  explicit ServiceWorkerMessageFilter(ThreadSafeSender* thread_safe_sender);
+
+  // IPC::Listener implementation
+  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+
+ protected:
+  virtual ~ServiceWorkerMessageFilter();
+
+ private:
+  void DispatchMessage(const IPC::Message& msg);
+
+  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
+  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMessageFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
diff --git a/content/child/service_worker/web_service_worker_impl.cc b/content/child/service_worker/web_service_worker_impl.cc
new file mode 100644
index 0000000..02d9cf8
--- /dev/null
+++ b/content/child/service_worker/web_service_worker_impl.cc
@@ -0,0 +1,11 @@
+// Copyright 2013 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/child/service_worker/web_service_worker_impl.h"
+
+namespace content {
+
+WebServiceWorkerImpl::~WebServiceWorkerImpl() {}
+
+}  // namespace content
diff --git a/content/child/service_worker/web_service_worker_impl.h b/content/child/service_worker/web_service_worker_impl.h
new file mode 100644
index 0000000..a310316
--- /dev/null
+++ b/content/child/service_worker/web_service_worker_impl.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_IMPL_H_
+#define CONTENT_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "third_party/WebKit/public/platform/WebServiceWorker.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+
+namespace content {
+
+class WebServiceWorkerImpl
+    : NON_EXPORTED_BASE(public WebKit::WebServiceWorker) {
+ public:
+  explicit WebServiceWorkerImpl(int64 service_worker_id)
+      : service_worker_id_(service_worker_id) {}
+  virtual ~WebServiceWorkerImpl();
+
+ private:
+  int64 service_worker_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_IMPL_H_
diff --git a/content/child/service_worker/web_service_worker_provider_impl.cc b/content/child/service_worker/web_service_worker_provider_impl.cc
new file mode 100644
index 0000000..3da391f
--- /dev/null
+++ b/content/child/service_worker/web_service_worker_provider_impl.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 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/child/service_worker/web_service_worker_provider_impl.h"
+
+#include "base/logging.h"
+#include "content/child/child_thread.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
+#include "content/child/service_worker/service_worker_message_filter.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/common/service_worker_messages.h"
+#include "ipc/ipc_sender.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+
+using WebKit::WebString;
+using WebKit::WebURL;
+
+namespace content {
+
+WebServiceWorkerProviderImpl::WebServiceWorkerProviderImpl(
+    ThreadSafeSender* thread_safe_sender,
+    ServiceWorkerMessageFilter* message_filter,
+    const WebKit::WebURL& origin,
+    scoped_ptr<WebKit::WebServiceWorkerProviderClient> client)
+    : thread_safe_sender_(thread_safe_sender), client_(client.Pass()) {}
+
+WebServiceWorkerProviderImpl::~WebServiceWorkerProviderImpl() {}
+
+void WebServiceWorkerProviderImpl::registerServiceWorker(
+    const WebURL& pattern,
+    const WebURL& script_url,
+    WebServiceWorkerCallbacks* callbacks) {
+  ServiceWorkerDispatcher::ThreadSpecificInstance(thread_safe_sender_)
+      ->RegisterServiceWorker(pattern, script_url, callbacks);
+}
+
+void WebServiceWorkerProviderImpl::unregisterServiceWorker(
+    const WebURL& pattern,
+    WebServiceWorkerCallbacks* callbacks) {
+  ServiceWorkerDispatcher::ThreadSpecificInstance(thread_safe_sender_)
+      ->UnregisterServiceWorker(pattern, callbacks);
+}
+
+}  // namespace content
diff --git a/content/child/service_worker/web_service_worker_provider_impl.h b/content/child/service_worker/web_service_worker_provider_impl.h
new file mode 100644
index 0000000..1bada5d
--- /dev/null
+++ b/content/child/service_worker/web_service_worker_provider_impl.h
@@ -0,0 +1,55 @@
+// Copyright 2013 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_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_PROVIDER_IMPL_H_
+#define CONTENT_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_PROVIDER_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerProvider.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+
+namespace WebKit {
+class WebString;
+class WebURL;
+}
+
+namespace IPC {
+class Sender;
+}
+
+namespace content {
+
+class ThreadSafeSender;
+class ServiceWorkerMessageFilter;
+
+class WebServiceWorkerProviderImpl
+    : NON_EXPORTED_BASE(public WebKit::WebServiceWorkerProvider) {
+ public:
+  WebServiceWorkerProviderImpl(
+      ThreadSafeSender* thread_safe_sender,
+      ServiceWorkerMessageFilter* message_filter,
+      const WebKit::WebURL& origin,
+      scoped_ptr<WebKit::WebServiceWorkerProviderClient> client);
+  virtual ~WebServiceWorkerProviderImpl();
+
+  virtual void registerServiceWorker(const WebKit::WebURL& pattern,
+                                     const WebKit::WebURL& script_url,
+                                     WebServiceWorkerCallbacks*);
+
+  virtual void unregisterServiceWorker(const WebKit::WebURL& pattern,
+                                       WebServiceWorkerCallbacks*);
+
+ private:
+  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  scoped_ptr<WebKit::WebServiceWorkerProviderClient> client_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerProviderImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_SERVICE_WORKER_WEB_SERVICE_WORKER_PROVIDER_IMPL_H_
diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc
index fb3ffd1..6d272ee 100644
--- a/content/child/webblobregistry_impl.cc
+++ b/content/child/webblobregistry_impl.cc
@@ -69,17 +69,10 @@
       case WebBlobData::Item::TypeBlob:
         if (data_item.length) {
           webkit_blob::BlobData::Item item;
-#ifdef USE_BLOB_UUIDS
           item.SetToBlobRange(
               data_item.blobUUID.utf8(),
               static_cast<uint64>(data_item.offset),
               static_cast<uint64>(data_item.length));
-#else
-          item.SetToBlobUrlRange(
-              data_item.blobURL,
-              static_cast<uint64>(data_item.offset),
-              static_cast<uint64>(data_item.length));
-#endif
           sender_->Send(
               new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
         }
@@ -155,33 +148,6 @@
   }
 }
 
-// DEPRECATED, almost. Until blink is updated, we implement these older methods
-// in terms of our newer blob storage system. We create a uuid for each 'data'
-// we see and construct a mapping from the private blob urls we're given to
-// that uuid. The mapping is maintained in the browser process.
-//
-// Chromium is setup to speak in terms of old-style private blob urls or
-// new-style uuid identifiers. Once blink has been migrated support for
-// the old-style will be deleted. Search for the term deprecated.
-
-void WebBlobRegistryImpl::registerBlobURL(
-    const WebURL& url, WebBlobData& data) {
-  std::string uuid = base::GenerateGUID();
-  registerBlobData(WebKit::WebString::fromUTF8(uuid), data);
-  sender_->Send(new BlobHostMsg_DeprecatedRegisterBlobURL(url, uuid));
-  sender_->Send(new BlobHostMsg_DecrementRefCount(uuid));
-}
-
-void WebBlobRegistryImpl::registerBlobURL(
-    const WebURL& url, const WebURL& src_url) {
-  sender_->Send(new BlobHostMsg_DeprecatedCloneBlobURL(url, src_url));
-}
-
-void WebBlobRegistryImpl::unregisterBlobURL(const WebURL& url) {
-  sender_->Send(new BlobHostMsg_DeprecatedRevokeBlobURL(url));
-}
-
-
 // ------ streams stuff -----
 
 void WebBlobRegistryImpl::registerStreamURL(
diff --git a/content/child/webblobregistry_impl.h b/content/child/webblobregistry_impl.h
index 1d6e54e..8a04abf 100644
--- a/content/child/webblobregistry_impl.h
+++ b/content/child/webblobregistry_impl.h
@@ -32,14 +32,6 @@
                                      const WebKit::WebString& uuid);
   virtual void revokePublicBlobURL(const WebKit::WebURL&);
 
-  // DEPRECATED
-  // TODO(michaeln): crbug/174200
-  virtual void registerBlobURL(const WebKit::WebURL& url,
-                               WebKit::WebBlobData& data);
-  virtual void registerBlobURL(const WebKit::WebURL& url,
-                               const WebKit::WebURL& src_url);
-  virtual void unregisterBlobURL(const WebKit::WebURL& url);
-
   // Additional support for Streams.
   virtual void registerStreamURL(const WebKit::WebURL& url,
                                  const WebKit::WebString& content_type);
diff --git a/content/common/cc_messages.cc b/content/common/cc_messages.cc
index dc389a6..8b54af2 100644
--- a/content/common/cc_messages.cc
+++ b/content/common/cc_messages.cc
@@ -242,106 +242,41 @@
 
 void ParamTraits<gfx::Transform>::Write(
     Message* m, const param_type& p) {
-  WriteParam(m, p.matrix().get(0, 0));
-  WriteParam(m, p.matrix().get(1, 0));
-  WriteParam(m, p.matrix().get(2, 0));
-  WriteParam(m, p.matrix().get(3, 0));
-  WriteParam(m, p.matrix().get(0, 1));
-  WriteParam(m, p.matrix().get(1, 1));
-  WriteParam(m, p.matrix().get(2, 1));
-  WriteParam(m, p.matrix().get(3, 1));
-  WriteParam(m, p.matrix().get(0, 2));
-  WriteParam(m, p.matrix().get(1, 2));
-  WriteParam(m, p.matrix().get(2, 2));
-  WriteParam(m, p.matrix().get(3, 2));
-  WriteParam(m, p.matrix().get(0, 3));
-  WriteParam(m, p.matrix().get(1, 3));
-  WriteParam(m, p.matrix().get(2, 3));
-  WriteParam(m, p.matrix().get(3, 3));
+#ifdef SK_MSCALAR_IS_FLOAT
+  float column_major_data[16];
+  p.matrix().asColMajorf(column_major_data);
+#else
+  double column_major_data[16];
+  p.matrix().asColMajord(column_major_data);
+#endif
+  m->WriteBytes(&column_major_data, sizeof(SkMScalar) * 16);
 }
 
 bool ParamTraits<gfx::Transform>::Read(
     const Message* m, PickleIterator* iter, param_type* r) {
-  // Note: In this function, "m12" means 1st row, 2nd column of the matrix.
-  // This is consistent with Skia's row-column notation, but backwards from
-  // WebCore's column-row notation.
-  SkMScalar m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41,
-      m42, m43, m44;
-
-  bool success =
-      ReadParam(m, iter, &m11) &&
-      ReadParam(m, iter, &m21) &&
-      ReadParam(m, iter, &m31) &&
-      ReadParam(m, iter, &m41) &&
-      ReadParam(m, iter, &m12) &&
-      ReadParam(m, iter, &m22) &&
-      ReadParam(m, iter, &m32) &&
-      ReadParam(m, iter, &m42) &&
-      ReadParam(m, iter, &m13) &&
-      ReadParam(m, iter, &m23) &&
-      ReadParam(m, iter, &m33) &&
-      ReadParam(m, iter, &m43) &&
-      ReadParam(m, iter, &m14) &&
-      ReadParam(m, iter, &m24) &&
-      ReadParam(m, iter, &m34) &&
-      ReadParam(m, iter, &m44);
-
-  if (success) {
-    r->matrix().set(0, 0, m11);
-    r->matrix().set(1, 0, m21);
-    r->matrix().set(2, 0, m31);
-    r->matrix().set(3, 0, m41);
-    r->matrix().set(0, 1, m12);
-    r->matrix().set(1, 1, m22);
-    r->matrix().set(2, 1, m32);
-    r->matrix().set(3, 1, m42);
-    r->matrix().set(0, 2, m13);
-    r->matrix().set(1, 2, m23);
-    r->matrix().set(2, 2, m33);
-    r->matrix().set(3, 2, m43);
-    r->matrix().set(0, 3, m14);
-    r->matrix().set(1, 3, m24);
-    r->matrix().set(2, 3, m34);
-    r->matrix().set(3, 3, m44);
-  }
-
-  return success;
+  const char* column_major_data;
+  if (!m->ReadBytes(iter, &column_major_data, sizeof(SkMScalar) * 16))
+    return false;
+  r->matrix().setColMajor(
+      reinterpret_cast<const SkMScalar*>(column_major_data));
+  return true;
 }
 
 void ParamTraits<gfx::Transform>::Log(
     const param_type& p, std::string* l) {
+#ifdef SK_MSCALAR_IS_FLOAT
+  float row_major_data[16];
+  p.matrix().asRowMajorf(row_major_data);
+#else
+  double row_major_data[16];
+  p.matrix().asRowMajord(row_major_data);
+#endif
   l->append("(");
-  LogParam(p.matrix().get(0, 0), l);
-  l->append(", ");
-  LogParam(p.matrix().get(1, 0), l);
-  l->append(", ");
-  LogParam(p.matrix().get(2, 0), l);
-  l->append(", ");
-  LogParam(p.matrix().get(3, 0), l);
-  l->append(", ");
-  LogParam(p.matrix().get(0, 1), l);
-  l->append(", ");
-  LogParam(p.matrix().get(1, 1), l);
-  l->append(", ");
-  LogParam(p.matrix().get(2, 1), l);
-  l->append(", ");
-  LogParam(p.matrix().get(3, 1), l);
-  l->append(", ");
-  LogParam(p.matrix().get(0, 2), l);
-  l->append(", ");
-  LogParam(p.matrix().get(1, 2), l);
-  l->append(", ");
-  LogParam(p.matrix().get(2, 2), l);
-  l->append(", ");
-  LogParam(p.matrix().get(3, 2), l);
-  l->append(", ");
-  LogParam(p.matrix().get(0, 3), l);
-  l->append(", ");
-  LogParam(p.matrix().get(1, 3), l);
-  l->append(", ");
-  LogParam(p.matrix().get(2, 3), l);
-  l->append(", ");
-  LogParam(p.matrix().get(3, 3), l);
+  for (int i = 0; i < 16; ++i) {
+    if (i > 0)
+      l->append(", ");
+    LogParam(row_major_data[i], l);
+  }
   l->append(") ");
 }
 
@@ -434,6 +369,19 @@
   }
 }
 
+static size_t ReserveSizeForRenderPassWrite(const cc::RenderPass& p) {
+  size_t to_reserve = sizeof(cc::RenderPass);
+
+  to_reserve += p.shared_quad_state_list.size() * sizeof(cc::SharedQuadState);
+
+  // The shared_quad_state_index for each quad.
+  to_reserve += p.quad_list.size() * sizeof(size_t);
+
+  // The largest quad type, verified by a unit test.
+  to_reserve += p.quad_list.size() * sizeof(cc::RenderPassDrawQuad);
+  return to_reserve;
+}
+
 template<typename QuadType>
 static scoped_ptr<cc::DrawQuad> ReadDrawQuad(const Message* m,
                                              PickleIterator* iter) {
@@ -745,6 +693,14 @@
 void ParamTraits<cc::DelegatedFrameData>::Write(Message* m,
                                                 const param_type& p) {
   DCHECK_NE(0u, p.render_pass_list.size());
+
+  size_t to_reserve = p.resource_list.size() * sizeof(cc::TransferableResource);
+  for (size_t i = 0; i < p.render_pass_list.size(); ++i) {
+    const cc::RenderPass* pass = p.render_pass_list[i];
+    to_reserve += ReserveSizeForRenderPassWrite(*pass);
+  }
+  m->Reserve(to_reserve);
+
   WriteParam(m, p.resource_list);
   WriteParam(m, p.render_pass_list.size());
   for (size_t i = 0; i < p.render_pass_list.size(); ++i)
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h
index b1271b3..7fee1e0 100644
--- a/content/common/cc_messages.h
+++ b/content/common/cc_messages.h
@@ -222,6 +222,7 @@
   IPC_STRUCT_TRAITS_MEMBER(filter)
   IPC_STRUCT_TRAITS_MEMBER(size)
   IPC_STRUCT_TRAITS_MEMBER(mailbox)
+  IPC_STRUCT_TRAITS_MEMBER(is_software)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::ReturnedResource)
diff --git a/content/common/cc_messages_perftest.cc b/content/common/cc_messages_perftest.cc
index afcdad3..a8e55b5 100644
--- a/content/common/cc_messages_perftest.cc
+++ b/content/common/cc_messages_perftest.cc
@@ -21,10 +21,45 @@
 namespace content {
 namespace {
 
-class CCMessagesPerfTest : public testing::Test {};
+static const int kTimeLimitMillis = 2000;
+static const int kNumWarmupRuns = 20;
+static const int kTimeCheckInterval = 10;
 
-const int kNumWarmupRuns = 10;
-const int kNumRuns = 100;
+class CCMessagesPerfTest : public testing::Test {
+ protected:
+  static void RunTest(std::string test_name, const CompositorFrame& frame) {
+    for (int i = 0; i < kNumWarmupRuns; ++i) {
+      IPC::Message msg(1, 2);
+      IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
+    }
+
+    base::TimeTicks start = base::TimeTicks::HighResNow();
+    base::TimeTicks end =
+        start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis);
+    base::TimeDelta min_time;
+    int count = 0;
+    while (start < end) {
+      for (int i = 0; i < kTimeCheckInterval; ++i) {
+        IPC::Message msg(1, 2);
+        IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
+        ++count;
+      }
+
+      base::TimeTicks now = base::TimeTicks::HighResNow();
+      if (now - start < min_time || min_time == base::TimeDelta())
+        min_time = now - start;
+      start = base::TimeTicks::HighResNow();
+    }
+
+    perf_test::PrintResult(
+        "min_frame_serialization_time",
+        "",
+        test_name,
+        min_time.InMillisecondsF() / kTimeCheckInterval * 1000,
+        "us",
+        true);
+  }
+};
 
 TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_1_4000) {
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
@@ -39,30 +74,15 @@
   frame->delegated_frame_data.reset(new DelegatedFrameData);
   frame->delegated_frame_data->render_pass_list.push_back(render_pass.Pass());
 
-  for (int i = 0; i < kNumWarmupRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-
-  base::TimeTicks start = base::TimeTicks::HighResNow();
-  for (int i = 0; i < kNumRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-  base::TimeTicks end = base::TimeTicks::HighResNow();
-
-  base::TimeDelta mean_time_delta = (end - start) / kNumRuns;
-  perf_test::PrintResult("mean_frame_serialization_time", "",
-                         "DelegatedFrame_ManyQuads_1_4000",
-                         mean_time_delta.InMicroseconds(), "us", true);
+  RunTest("DelegatedFrame_ManyQuads_1_4000", *frame);
 }
 
-TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_1_10000) {
+TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_1_100000) {
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
 
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   render_pass->shared_quad_state_list.push_back(SharedQuadState::Create());
-  for (int i = 0; i < 4000; ++i) {
+  for (int i = 0; i < 100000; ++i) {
     render_pass->quad_list.push_back(
         PictureDrawQuad::Create().PassAs<DrawQuad>());
   }
@@ -70,22 +90,7 @@
   frame->delegated_frame_data.reset(new DelegatedFrameData);
   frame->delegated_frame_data->render_pass_list.push_back(render_pass.Pass());
 
-  for (int i = 0; i < kNumWarmupRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-
-  base::TimeTicks start = base::TimeTicks::HighResNow();
-  for (int i = 0; i < kNumRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-  base::TimeTicks end = base::TimeTicks::HighResNow();
-
-  base::TimeDelta mean_time_delta = (end - start) / kNumRuns;
-  perf_test::PrintResult("mean_frame_serialization_time", "",
-                         "DelegatedFrame_ManyQuads_1_10000",
-                         mean_time_delta.InMicroseconds(), "us", true);
+  RunTest("DelegatedFrame_ManyQuads_1_100000", *frame);
 }
 
 TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_4000_4000) {
@@ -101,29 +106,14 @@
   frame->delegated_frame_data.reset(new DelegatedFrameData);
   frame->delegated_frame_data->render_pass_list.push_back(render_pass.Pass());
 
-  for (int i = 0; i < kNumWarmupRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-
-  base::TimeTicks start = base::TimeTicks::HighResNow();
-  for (int i = 0; i < kNumRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-  base::TimeTicks end = base::TimeTicks::HighResNow();
-
-  base::TimeDelta mean_time_delta = (end - start) / kNumRuns;
-  perf_test::PrintResult("mean_frame_serialization_time", "",
-                         "DelegatedFrame_ManyQuads_4000_4000",
-                         mean_time_delta.InMicroseconds(), "us", true);
+  RunTest("DelegatedFrame_ManyQuads_4000_4000", *frame);
 }
 
-TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_10000_10000) {
+TEST_F(CCMessagesPerfTest, DelegatedFrame_ManyQuads_100000_100000) {
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
 
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
-  for (int i = 0; i < 10000; ++i) {
+  for (int i = 0; i < 100000; ++i) {
     render_pass->shared_quad_state_list.push_back(SharedQuadState::Create());
     render_pass->quad_list.push_back(
         PictureDrawQuad::Create().PassAs<DrawQuad>());
@@ -132,22 +122,25 @@
   frame->delegated_frame_data.reset(new DelegatedFrameData);
   frame->delegated_frame_data->render_pass_list.push_back(render_pass.Pass());
 
-  for (int i = 0; i < kNumWarmupRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
+  RunTest("DelegatedFrame_ManyQuads_100000_100000", *frame);
+}
+
+TEST_F(CCMessagesPerfTest,
+       DelegatedFrame_ManyRenderPasses_10000_100) {
+  scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+  frame->delegated_frame_data.reset(new DelegatedFrameData);
+
+  for (int i = 0; i < 1000; ++i) {
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+    for (int j = 0; j < 100; ++j) {
+      render_pass->shared_quad_state_list.push_back(SharedQuadState::Create());
+      render_pass->quad_list.push_back(
+          PictureDrawQuad::Create().PassAs<DrawQuad>());
+    }
+    frame->delegated_frame_data->render_pass_list.push_back(render_pass.Pass());
   }
 
-  base::TimeTicks start = base::TimeTicks::HighResNow();
-  for (int i = 0; i < kNumRuns; ++i) {
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-    IPC::ParamTraits<CompositorFrame>::Write(&msg, *frame);
-  }
-  base::TimeTicks end = base::TimeTicks::HighResNow();
-
-  base::TimeDelta mean_time_delta = (end - start) / kNumRuns;
-  perf_test::PrintResult("mean_frame_serialization_time", "",
-                         "DelegatedFrame_ManyQuads_10000_10000",
-                         mean_time_delta.InMicroseconds(), "us", true);
+  RunTest("DelegatedFrame_ManyRenderPasses_10000_100", *frame);
 }
 
 }  // namespace
diff --git a/content/common/cc_messages_unittest.cc b/content/common/cc_messages_unittest.cc
index 6ba87ad..2c5637a 100644
--- a/content/common/cc_messages_unittest.cc
+++ b/content/common/cc_messages_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <string.h>
 
+#include <algorithm>
+
 #include "base/command_line.h"
 #include "cc/output/compositor_frame.h"
 #include "content/public/common/content_switches.h"
@@ -203,7 +205,7 @@
   if (!command_line.HasSwitch(switches::kAllowFiltersOverIPC))
     command_line.AppendSwitch(switches::kAllowFiltersOverIPC);
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
 
   Transform arbitrary_matrix;
   arbitrary_matrix.Scale(3, 3);
@@ -497,7 +499,7 @@
 }
 
 TEST_F(CCMessagesTest, Resources) {
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   gfx::Size arbitrary_size(757, 1281);
   unsigned int arbitrary_uint1 = 71234838;
   unsigned int arbitrary_uint2 = 53589793;
@@ -555,5 +557,54 @@
   Compare(arbitrary_resource2, frame_out.resource_list[1]);
 }
 
+TEST_F(CCMessagesTest, LargestQuadType) {
+  size_t largest = 0;
+
+  bool done = false;
+  for (int i = 0; !done; ++i) {
+    switch (static_cast<DrawQuad::Material>(i)) {
+      case cc::DrawQuad::CHECKERBOARD:
+        largest = std::max(largest, sizeof(cc::CheckerboardDrawQuad));
+        break;
+      case cc::DrawQuad::DEBUG_BORDER:
+        largest = std::max(largest, sizeof(cc::DebugBorderDrawQuad));
+        break;
+      case cc::DrawQuad::IO_SURFACE_CONTENT:
+        largest = std::max(largest, sizeof(cc::IOSurfaceDrawQuad));
+        break;
+      case cc::DrawQuad::PICTURE_CONTENT:
+        largest = std::max(largest, sizeof(cc::PictureDrawQuad));
+        break;
+      case cc::DrawQuad::TEXTURE_CONTENT:
+        largest = std::max(largest, sizeof(cc::TextureDrawQuad));
+        break;
+      case cc::DrawQuad::RENDER_PASS:
+        largest = std::max(largest, sizeof(cc::RenderPassDrawQuad));
+        break;
+      case cc::DrawQuad::SOLID_COLOR:
+        largest = std::max(largest, sizeof(cc::SolidColorDrawQuad));
+        break;
+      case cc::DrawQuad::TILED_CONTENT:
+        largest = std::max(largest, sizeof(cc::TileDrawQuad));
+        break;
+      case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+        largest = std::max(largest, sizeof(cc::StreamVideoDrawQuad));
+        break;
+      case cc::DrawQuad::YUV_VIDEO_CONTENT:
+        largest = std::max(largest, sizeof(cc::YUVVideoDrawQuad));
+        break;
+      case cc::DrawQuad::INVALID:
+        break;
+      default:
+        done = true;
+    }
+  }
+
+  // Verify the largest DrawQuad type is RenderPassDrawQuad. If this ever
+  // changes, then the ReserveSizeForRenderPassWrite() method needs to be
+  // updated as well to use the new largest quad.
+  EXPECT_EQ(sizeof(RenderPassDrawQuad), largest);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index fb058d3..a2f40d4 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -247,6 +247,8 @@
                           OnShutdownRequest)
       IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
                           OnAllocateSharedMemory)
+      IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+                          OnAllocateGpuMemoryBuffer)
       IPC_MESSAGE_UNHANDLED(handled = false)
     IPC_END_MESSAGE_MAP()
 
@@ -293,4 +295,11 @@
     Send(new ChildProcessMsg_Shutdown());
 }
 
+void ChildProcessHostImpl::OnAllocateGpuMemoryBuffer(
+    uint32 buffer_size,
+    gfx::GpuMemoryBufferHandle* handle) {
+  handle->type = gfx::SHARED_MEMORY_BUFFER;
+  AllocateSharedMemory(buffer_size, peer_handle_, &handle->handle);
+}
+
 }  // namespace content
diff --git a/content/common/child_process_host_impl.h b/content/common/child_process_host_impl.h
index a24f3b8..74700bc 100644
--- a/content/common/child_process_host_impl.h
+++ b/content/common/child_process_host_impl.h
@@ -22,6 +22,10 @@
 class FilePath;
 }
 
+namespace gfx {
+struct GpuMemoryBufferHandle;
+}
+
 namespace content {
 class ChildProcessHostDelegate;
 
@@ -75,6 +79,8 @@
   void OnShutdownRequest();
   void OnAllocateSharedMemory(uint32 buffer_size,
                               base::SharedMemoryHandle* handle);
+  void OnAllocateGpuMemoryBuffer(uint32 buffer_size,
+                                 gfx::GpuMemoryBufferHandle* handle);
 
   ChildProcessHostDelegate* delegate_;
   base::ProcessHandle peer_handle_;
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index 3f70bc3..c122588 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "content/common/content_export.h"
 #include "ipc/ipc_message_macros.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 
 IPC_ENUM_TRAITS(tracked_objects::ThreadData::Status)
 
@@ -54,6 +55,13 @@
   IPC_STRUCT_TRAITS_MEMBER(process_id)
 IPC_STRUCT_TRAITS_END()
 
+IPC_ENUM_TRAITS(gfx::GpuMemoryBufferType)
+
+IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
+  IPC_STRUCT_TRAITS_MEMBER(type)
+  IPC_STRUCT_TRAITS_MEMBER(handle)
+IPC_STRUCT_TRAITS_END()
+
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 
@@ -138,3 +146,8 @@
 IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_TcmallocStats,
                      std::string /* output */)
 #endif
+
+// Asks the browser to create a gpu memory buffer.
+IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+                            uint32 /* buffer size */,
+                            gfx::GpuMemoryBufferHandle)
diff --git a/content/common/common_param_traits_unittest.cc b/content/common/common_param_traits_unittest.cc
index 9566950..445fd1a 100644
--- a/content/common/common_param_traits_unittest.cc
+++ b/content/common/common_param_traits_unittest.cc
@@ -27,7 +27,7 @@
 
   for (size_t i = 0; i < arraysize(serialize_cases); i++) {
     GURL input(serialize_cases[i]);
-    IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+    IPC::Message msg(1, 2);
     IPC::ParamTraits<GURL>::Write(&msg, input);
 
     GURL output;
@@ -58,7 +58,7 @@
   }
 
   // Also test the corrupt case.
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   msg.WriteInt(99);
   GURL output;
   PickleIterator iter(msg);
@@ -70,7 +70,7 @@
   typedef std::pair<std::string, std::string> TestPair;
 
   TestPair input("foo", "bar");
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::ParamTraits<TestPair>::Write(&msg, input);
 
   TestPair output;
@@ -88,7 +88,7 @@
   bitmap.allocPixels();
   memset(bitmap.getPixels(), 'A', bitmap.getSize());
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::ParamTraits<SkBitmap>::Write(&msg, bitmap);
 
   SkBitmap output;
@@ -104,7 +104,7 @@
             0);
 
   // Also test the corrupt case.
-  IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, 2);
   // Copy the first message block over to |bad_msg|.
   const char* fixed_data;
   int fixed_data_size;
@@ -128,7 +128,7 @@
   input.Set(1, new base::StringValue("forty"));
   input.Set(2, base::Value::CreateNullValue());
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::WriteParam(&msg, input);
 
   base::ListValue output;
@@ -138,7 +138,7 @@
   EXPECT_TRUE(input.Equals(&output));
 
   // Also test the corrupt case.
-  IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, 2);
   bad_msg.WriteInt(99);
   iter = PickleIterator(bad_msg);
   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
@@ -162,7 +162,7 @@
 
   input.Set("dict", subdict.release());
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::WriteParam(&msg, input);
 
   base::DictionaryValue output;
@@ -172,7 +172,7 @@
   EXPECT_TRUE(input.Equals(&output));
 
   // Also test the corrupt case.
-  IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, 2);
   bad_msg.WriteInt(99);
   iter = PickleIterator(bad_msg);
   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
@@ -182,7 +182,7 @@
 TEST(IPCMessageTest, HostPortPair) {
   net::HostPortPair input("host.com", 12345);
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::ParamTraits<net::HostPortPair>::Write(&msg, input);
 
   net::HostPortPair output;
diff --git a/content/common/device_orientation/device_motion_messages.h b/content/common/device_orientation/device_motion_messages.h
index 657d3d7..4f8435d 100644
--- a/content/common/device_orientation/device_motion_messages.h
+++ b/content/common/device_orientation/device_motion_messages.h
@@ -12,14 +12,17 @@
 
 #define IPC_MESSAGE_START DeviceMotionMsgStart
 
-// Messages sent from the renderer to the browser.
-
-// Asks the browser process to start polling, and return a shared memory
-// handles that will hold the data from the hardware. See
-// device_motion_hardware_buffer.h for a description of how synchronization is
-// handled. The number of Starts should match the number of Stops.
+// Asks the browser process to activate Device Motion sensors if necessary.
 IPC_MESSAGE_CONTROL0(DeviceMotionHostMsg_StartPolling)
+
+// The browser process asynchronously returns the shared memory handle that will
+// hold the data from the hardware sensors.
+// See device_motion_hardware_buffer.h for a description of how
+// synchronization is handled.
 IPC_MESSAGE_CONTROL1(DeviceMotionMsg_DidStartPolling,
                      base::SharedMemoryHandle /* handle */)
 
+// Notifies the browser process that the renderer process is not using the
+// Device Motion data anymore. The number of Starts should match the number
+// of Stops.
 IPC_MESSAGE_CONTROL0(DeviceMotionHostMsg_StopPolling)
diff --git a/content/common/device_orientation/device_orientation_messages.h b/content/common/device_orientation/device_orientation_messages.h
index f4114df..43406c6 100644
--- a/content/common/device_orientation/device_orientation_messages.h
+++ b/content/common/device_orientation/device_orientation_messages.h
@@ -10,45 +10,17 @@
 
 #define IPC_MESSAGE_START DeviceOrientationMsgStart
 
-// Messages sent from the renderer to the browser.
-
-// Asks the browser process to start polling, and return a shared memory
-// handle that will hold the data from the hardware. See
-// device_orientation_hardware_buffer.h for a description of how synchronization
-// is handled. The number of Starts should match the number of Stops.
+// Asks the browser process to activate Device Orientation sensors if necessary.
 IPC_MESSAGE_CONTROL0(DeviceOrientationHostMsg_StartPolling)
+
+// The browser process asynchronously returns the shared memory handle that will
+// hold the data from the hardware sensors.
+// See device_orientation_hardware_buffer.h for a description of how
+// synchronization is handled.
 IPC_MESSAGE_CONTROL1(DeviceOrientationMsg_DidStartPolling,
                      base::SharedMemoryHandle /* handle */)
 
+// Notifies the browser process that the renderer process is not using the
+// Device Orientation data anymore. The number of Starts should match the
+// number of Stops.
 IPC_MESSAGE_CONTROL0(DeviceOrientationHostMsg_StopPolling)
-
-// TODO(timvolodine): remove the methods below once the shared memory
-// Device Orientation is implemented.
-
-IPC_STRUCT_BEGIN(DeviceOrientationMsg_Updated_Params)
-  // These fields have the same meaning as in content::Orientation.
-  IPC_STRUCT_MEMBER(bool, can_provide_alpha)
-  IPC_STRUCT_MEMBER(double, alpha)
-  IPC_STRUCT_MEMBER(bool, can_provide_beta)
-  IPC_STRUCT_MEMBER(double, beta)
-  IPC_STRUCT_MEMBER(bool, can_provide_gamma)
-  IPC_STRUCT_MEMBER(double, gamma)
-  IPC_STRUCT_MEMBER(bool, can_provide_absolute)
-  IPC_STRUCT_MEMBER(bool, absolute)
-IPC_STRUCT_END()
-
-// Messages sent from the browser to the renderer.
-
-// Notification that the device's orientation has changed.
-IPC_MESSAGE_ROUTED1(DeviceOrientationMsg_Updated,
-                    DeviceOrientationMsg_Updated_Params)
-
-// Messages sent from the renderer to the browser.
-
-// A RenderView requests to start receiving device orientation updates.
-IPC_MESSAGE_CONTROL1(DeviceOrientationHostMsg_StartUpdating,
-                     int /* render_view_id */)
-
-// A RenderView requests to stop receiving device orientation updates.
-IPC_MESSAGE_CONTROL1(DeviceOrientationHostMsg_StopUpdating,
-                     int /* render_view_id */)
diff --git a/content/common/fileapi/webblob_messages.h b/content/common/fileapi/webblob_messages.h
index 92a9816..b4399e7 100644
--- a/content/common/fileapi/webblob_messages.h
+++ b/content/common/fileapi/webblob_messages.h
@@ -39,18 +39,6 @@
 IPC_MESSAGE_CONTROL1(BlobHostMsg_RevokePublicURL,
                      GURL)
 
-// Temporary support for mapping old style blobUrls to new style uuids.
-IPC_MESSAGE_CONTROL2(BlobHostMsg_DeprecatedRegisterBlobURL,
-                     GURL,
-                     std::string /* uuid */)
-IPC_MESSAGE_CONTROL2(BlobHostMsg_DeprecatedCloneBlobURL,
-                     GURL,
-                     GURL)
-IPC_MESSAGE_CONTROL1(BlobHostMsg_DeprecatedRevokeBlobURL,
-                     GURL)
-
-
-
 // Stream messages sent from the renderer to the browser.
 
 // Registers a stream as being built.
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index 94abbe1..f1406a4 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -12,11 +12,11 @@
 #include "content/common/child_process_messages.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
 #include "content/common/gpu/client/gpu_video_decode_accelerator_host.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/common/gpu/gpu_messages.h"
 #include "content/common/view_messages.h"
 #include "gpu/command_buffer/common/cmd_buffer_common.h"
 #include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "ui/gfx/size.h"
 
 namespace content {
@@ -98,8 +98,7 @@
 }
 
 void CommandBufferProxyImpl::SetMemoryAllocationChangedCallback(
-    const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
-        callback) {
+    const MemoryAllocationChangedCallback& callback) {
   if (last_state_.error != gpu::error::kNoError)
     return;
 
@@ -118,7 +117,7 @@
 }
 
 void CommandBufferProxyImpl::OnSetMemoryAllocation(
-    const GpuMemoryAllocationForRenderer& allocation) {
+    const gpu::MemoryAllocation& allocation) {
   if (!memory_allocation_changed_callback_.is_null())
     memory_allocation_changed_callback_.Run(allocation);
 }
@@ -194,7 +193,7 @@
   if (last_state_.error != gpu::error::kNoError)
     return;
 
-  TRACE_EVENT1("gpu",
+  TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
                "CommandBufferProxyImpl::Flush",
                "put_offset",
                put_offset);
@@ -367,7 +366,7 @@
 }
 
 bool CommandBufferProxyImpl::SupportsGpuMemoryBuffer() {
-  return false;
+  return true;
 }
 
 gfx::GpuMemoryBuffer* CommandBufferProxyImpl::CreateGpuMemoryBuffer(
@@ -375,12 +374,58 @@
     size_t height,
     unsigned internalformat,
     int32* id) {
-  NOTREACHED();
-  return NULL;
+  *id = -1;
+
+  if (last_state_.error != gpu::error::kNoError)
+    return NULL;
+
+  int32 new_id = channel_->ReserveGpuMemoryBufferId();
+  DCHECK(gpu_memory_buffers_.find(new_id) == gpu_memory_buffers_.end());
+
+  scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer(
+      channel_->factory()->AllocateGpuMemoryBuffer(width,
+                                                   height,
+                                                   internalformat));
+  if (!gpu_memory_buffer)
+    return NULL;
+
+  DCHECK(GpuChannelHost::IsValidGpuMemoryBuffer(
+             gpu_memory_buffer->GetHandle()));
+
+  // This handle is owned by the GPU process and must be passed to it or it
+  // will leak. In otherwords, do not early out on error between here and the
+  // sending of the RegisterGpuMemoryBuffer IPC below.
+  gfx::GpuMemoryBufferHandle handle =
+      channel_->ShareGpuMemoryBufferToGpuProcess(
+          gpu_memory_buffer->GetHandle());
+
+  if (!Send(new GpuCommandBufferMsg_RegisterGpuMemoryBuffer(
+                route_id_,
+                new_id,
+                handle,
+                width,
+                height,
+                internalformat))) {
+    return NULL;
+  }
+
+  *id = new_id;
+  gpu_memory_buffers_[new_id] = gpu_memory_buffer.release();
+  return gpu_memory_buffers_[new_id];
 }
 
 void CommandBufferProxyImpl::DestroyGpuMemoryBuffer(int32 id) {
-  NOTREACHED();
+  if (last_state_.error != gpu::error::kNoError)
+    return;
+
+  // Remove the gpu memory buffer from the client side cache.
+  GpuMemoryBufferMap::iterator it = gpu_memory_buffers_.find(id);
+  if (it != gpu_memory_buffers_.end()) {
+    delete it->second;
+    gpu_memory_buffers_.erase(it);
+  }
+
+  Send(new GpuCommandBufferMsg_DestroyGpuMemoryBuffer(route_id_, id));
 }
 
 int CommandBufferProxyImpl::GetRouteID() const {
@@ -470,6 +515,14 @@
   signal_tasks_.insert(std::make_pair(signal_id, callback));
 }
 
+void CommandBufferProxyImpl::SendManagedMemoryStats(
+    const gpu::ManagedMemoryStats& stats) {
+  if (last_state_.error != gpu::error::kNoError)
+    return;
+
+  Send(new GpuCommandBufferMsg_SendClientManagedMemoryStats(route_id_,
+                                                            stats));
+}
 
 bool CommandBufferProxyImpl::GenerateMailboxNames(
     unsigned num,
@@ -555,13 +608,4 @@
     shared_state()->Read(&last_state_);
 }
 
-void CommandBufferProxyImpl::SendManagedMemoryStats(
-    const GpuManagedMemoryStats& stats) {
-  if (last_state_.error != gpu::error::kNoError)
-    return;
-
-  Send(new GpuCommandBufferMsg_SendClientManagedMemoryStats(route_id_,
-                                                            stats));
-}
-
 }  // namespace content
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index c891483..b018367 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -15,11 +15,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/command_buffer_shared.h"
 #include "gpu/command_buffer/common/gpu_control.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "ipc/ipc_listener.h"
 #include "media/video/video_decode_accelerator.h"
 #include "ui/events/latency_info.h"
@@ -30,6 +29,10 @@
 class SharedMemory;
 }
 
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
 namespace gpu {
 struct Mailbox;
 }
@@ -107,17 +110,18 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
-
+  virtual void SendManagedMemoryStats(const gpu::ManagedMemoryStats& stats)
+      OVERRIDE;
 
   int GetRouteID() const;
   bool Echo(const base::Closure& callback);
   bool ProduceFrontBuffer(const gpu::Mailbox& mailbox);
   void SetChannelErrorCallback(const base::Closure& callback);
 
+  typedef base::Callback<void(const gpu::MemoryAllocation&)>
+      MemoryAllocationChangedCallback;
   void SetMemoryAllocationChangedCallback(
-      const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
-          callback);
-
+      const MemoryAllocationChangedCallback& callback);
   void AddDeletionObserver(DeletionObserver* observer);
   void RemoveDeletionObserver(DeletionObserver* observer);
 
@@ -138,13 +142,12 @@
   // CommandBufferProxyImpl implementation.
   virtual gpu::error::Error GetLastError() OVERRIDE;
 
-  void SendManagedMemoryStats(const GpuManagedMemoryStats& stats);
-
   GpuChannelHost* channel() const { return channel_; }
 
  private:
   typedef std::map<int32, gpu::Buffer> TransferBufferMap;
   typedef base::hash_map<uint32, base::Closure> SignalTaskMap;
+  typedef std::map<int32, gfx::GpuMemoryBuffer*> GpuMemoryBufferMap;
 
   // Send an IPC message over the GPU channel. This is private to fully
   // encapsulate the channel; all callers of this function must explicitly
@@ -156,7 +159,7 @@
   void OnDestroyed(gpu::error::ContextLostReason reason);
   void OnEchoAck();
   void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message);
-  void OnSetMemoryAllocation(const GpuMemoryAllocationForRenderer& allocation);
+  void OnSetMemoryAllocation(const gpu::MemoryAllocation& allocation);
   void OnSignalSyncPointAck(uint32 id);
   void OnGenerateMailboxNamesReply(const std::vector<std::string>& names);
 
@@ -193,8 +196,7 @@
 
   base::Closure channel_error_callback_;
 
-  base::Callback<void(const GpuMemoryAllocationForRenderer&)>
-      memory_allocation_changed_callback_;
+  MemoryAllocationChangedCallback memory_allocation_changed_callback_;
 
   GpuConsoleMessageCallback console_message_callback_;
 
@@ -202,6 +204,9 @@
   uint32 next_signal_id_;
   SignalTaskMap signal_tasks_;
 
+  // Local cache of id to gpu memory buffer mapping.
+  GpuMemoryBufferMap gpu_memory_buffers_;
+
   DISALLOW_COPY_AND_ASSIGN(CommandBufferProxyImpl);
 };
 
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
index b620692..e992236 100644
--- a/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -13,7 +13,6 @@
 #include "cc/output/managed_memory_policy.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
-#include "webkit/common/gpu/managed_memory_policy_convert.h"
 
 namespace content {
 
@@ -59,28 +58,6 @@
   ContextProviderCommandBuffer* provider_;
 };
 
-class ContextProviderCommandBuffer::MemoryAllocationCallbackProxy
-    : public WebKit::WebGraphicsContext3D::
-          WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
- public:
-  explicit MemoryAllocationCallbackProxy(ContextProviderCommandBuffer* provider)
-      : provider_(provider) {
-    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
-  }
-
-  virtual ~MemoryAllocationCallbackProxy() {
-    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
-  }
-
-  virtual void onMemoryAllocationChanged(
-      WebKit::WebGraphicsMemoryAllocation allocation) {
-    provider_->OnMemoryAllocationChanged(allocation);
-  }
-
- private:
-  ContextProviderCommandBuffer* provider_;
-};
-
 scoped_refptr<ContextProviderCommandBuffer>
 ContextProviderCommandBuffer::Create(
     scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
@@ -110,7 +87,10 @@
   base::AutoLock lock(main_thread_lock_);
 
   // Destroy references to the context3d_ before leaking it.
-  memory_allocation_callback_proxy_.reset();
+  if (context3d_->GetCommandBufferProxy()) {
+    context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
+        CommandBufferProxyImpl::MemoryAllocationChangedCallback());
+  }
   swap_buffers_complete_callback_proxy_.reset();
   lost_context_callback_proxy_.reset();
 
@@ -144,8 +124,9 @@
   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
   swap_buffers_complete_callback_proxy_.reset(
       new SwapBuffersCompleteCallbackProxy(this));
-  memory_allocation_callback_proxy_.reset(
-      new MemoryAllocationCallbackProxy(this));
+  context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
+      base::Bind(&ContextProviderCommandBuffer::OnMemoryAllocationChanged,
+                 base::Unretained(this)));
   return true;
 }
 
@@ -212,25 +193,22 @@
 }
 
 void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
-    const WebKit::WebGraphicsMemoryAllocation& allocation) {
+    const gpu::MemoryAllocation& allocation) {
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
   if (gr_context_) {
-    bool nonzero_allocation = !!allocation.gpuResourceSizeInBytes;
+    bool nonzero_allocation = !!allocation.bytes_limit_when_visible;
     gr_context_->SetMemoryLimit(nonzero_allocation);
   }
 
   if (memory_policy_changed_callback_.is_null())
     return;
 
-  bool discard_backbuffer_when_not_visible;
-  cc::ManagedMemoryPolicy policy =
-      webkit::gpu::ManagedMemoryPolicyConvert::Convert(
-          allocation,
-          &discard_backbuffer_when_not_visible);
+  bool discard_backbuffer_when_not_visible =
+      !allocation.have_backbuffer_when_not_visible;
 
   memory_policy_changed_callback_.Run(
-      policy, discard_backbuffer_when_not_visible);
+      cc::ManagedMemoryPolicy(allocation), discard_backbuffer_when_not_visible);
 }
 
 bool ContextProviderCommandBuffer::InitializeCapabilities() {
@@ -277,6 +255,10 @@
 
   caps.texture_format_bgra8888 =
       extension_set.count("GL_EXT_texture_format_BGRA8888") > 0;
+
+  caps.texture_format_etc1 =
+      extension_set.count("GL_OES_compressed_ETC1_RGB8_texture") > 0;
+
   caps.texture_rectangle = extension_set.count("GL_ARB_texture_rectangle") > 0;
 
   caps.post_sub_buffer = extension_set.count("GL_CHROMIUM_post_sub_buffer") > 0;
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
index 3c988d7..cec651f 100644
--- a/content/common/gpu/client/context_provider_command_buffer.h
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -59,8 +59,7 @@
 
   void OnLostContext();
   void OnSwapBuffersComplete();
-  void OnMemoryAllocationChanged(
-      const WebKit::WebGraphicsMemoryAllocation& allocation);
+  void OnMemoryAllocationChanged(const gpu::MemoryAllocation& allocation);
 
  private:
   bool InitializeCapabilities();
@@ -88,9 +87,6 @@
   class SwapBuffersCompleteCallbackProxy;
   scoped_ptr<SwapBuffersCompleteCallbackProxy>
       swap_buffers_complete_callback_proxy_;
-
-  class MemoryAllocationCallbackProxy;
-  scoped_ptr<MemoryAllocationCallbackProxy> memory_allocation_callback_proxy_;
 };
 
 }  // namespace content
diff --git a/content/common/gpu/client/context_provider_command_buffer_browsertest.cc b/content/common/gpu/client/context_provider_command_buffer_browsertest.cc
index fd68aa4..e58e5d8 100644
--- a/content/common/gpu/client/context_provider_command_buffer_browsertest.cc
+++ b/content/common/gpu/client/context_provider_command_buffer_browsertest.cc
@@ -12,11 +12,27 @@
 namespace {
 
 class ContextProviderCommandBufferBrowserTest : public ContentBrowserTest {
+ public:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    if (!GetFactory())
+      BrowserGpuChannelHostFactory::Initialize(true);
+
+    CHECK(GetFactory());
+    ContentBrowserTest::SetUpOnMainThread();
+  }
+
  protected:
+  BrowserGpuChannelHostFactory* GetFactory() {
+    return BrowserGpuChannelHostFactory::instance();
+  }
+
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext3d() {
+    scoped_refptr<GpuChannelHost> gpu_channel_host(
+        GetFactory()->EstablishGpuChannelSync(
+            CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
     scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
         WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-            BrowserGpuChannelHostFactory::instance(),
+            gpu_channel_host.get(),
             WebKit::WebGraphicsContext3D::Attributes(),
             GURL("chrome://gpu/ContextProviderCommandBufferTest")));
     return context.Pass();
diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc
index dd39347..c90d5b5 100644
--- a/content/common/gpu/client/gl_helper.cc
+++ b/content/common/gpu/client/gl_helper.cc
@@ -284,6 +284,7 @@
     CopyTextureToImpl* copy_impl_;
     gfx::Size dst_size_;
     gfx::Rect dst_subrect_;
+    GLHelper::ScalerQuality quality_;
     ScalerHolder scaler_;
     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
@@ -891,12 +892,13 @@
       copy_impl_(copy_impl),
       dst_size_(dst_size),
       dst_subrect_(dst_subrect),
+      quality_(quality),
       scaler_(context, scaler_impl->CreateScaler(
           quality,
           src_size,
           src_subrect,
           dst_subrect.size(),
-          flip_vertically,
+          false,
           false)),
       pass1_shader_(scaler_impl->CreateYuvMrtShader(
           dst_subrect.size(),
@@ -905,7 +907,7 @@
                     dst_subrect.height()),
           gfx::Size((dst_subrect.width() + 3) / 4,
                     dst_subrect.height()),
-          false,
+          flip_vertically,
           GLHelperScaling::SHADER_YUV_MRT_PASS1)),
       pass2_shader_(scaler_impl->CreateYuvMrtShader(
           gfx::Size((dst_subrect.width() + 3) / 4,
@@ -952,15 +954,27 @@
   WebGLId mailbox_texture =
       copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
 
-  // Scale texture to right size.
-  scaler_.Scale(mailbox_texture);
-  context_->deleteTexture(mailbox_texture);
+  WebGLId texture;
+  if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
+    // Optimization: SCALER_QUALITY_FAST is just a single bilinear
+    // pass, which pass1_shader_ can do just as well, so let's skip
+    // the actual scaling in that case.
+    texture = mailbox_texture;
+  } else {
+    // Scale texture to right size.
+    scaler_.Scale(mailbox_texture);
+    texture = scaler_.texture();
+  }
+
 
   std::vector<WebKit::WebGLId> outputs(2);
   // Convert the scaled texture in to Y, U and V planes.
   outputs[0] = y_.texture();
   outputs[1] = uv_;
-  pass1_shader_->Execute(scaler_.texture(), outputs);
+  pass1_shader_->Execute(texture, outputs);
+
+  context_->deleteTexture(mailbox_texture);
+
   outputs[0] = u_.texture();
   outputs[1] = v_.texture();
   pass2_shader_->Execute(uv_, outputs);
diff --git a/content/common/gpu/client/gl_helper_benchmark.cc b/content/common/gpu/client/gl_helper_benchmark.cc
index 1c5bee2..6bb4309 100644
--- a/content/common/gpu/client/gl_helper_benchmark.cc
+++ b/content/common/gpu/client/gl_helper_benchmark.cc
@@ -66,7 +66,8 @@
         CreateOffscreenContext(attributes);
     context_->makeContextCurrent();
 
-    helper_.reset(new content::GLHelper(context_.get()));
+    helper_.reset(
+        new content::GLHelper(context_.get(), context_->GetContextSupport()));
     helper_scaling_.reset(new content::GLHelperScaling(
         context_.get(),
         helper_.get()));
@@ -108,7 +109,8 @@
     file_util::CloseFile(f);
   }
 
-  scoped_ptr<WebKit::WebGraphicsContext3D> context_;
+  scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl>
+      context_;
   scoped_ptr<content::GLHelper> helper_;
   scoped_ptr<content::GLHelperScaling> helper_scaling_;
   std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 27c71de..4624ec7 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -46,6 +46,17 @@
   return host;
 }
 
+// static
+bool GpuChannelHost::IsValidGpuMemoryBuffer(
+    gfx::GpuMemoryBufferHandle handle) {
+  switch (handle.type) {
+    case gfx::SHARED_MEMORY_BUFFER:
+      return true;
+    default:
+      return false;
+  }
+}
+
 GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory,
                                int gpu_host_id,
                                int client_id,
@@ -55,6 +66,7 @@
       gpu_host_id_(gpu_host_id),
       gpu_info_(gpu_info) {
   next_transfer_buffer_id_.GetNext();
+  next_gpu_memory_buffer_id_.GetNext();
 }
 
 void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle) {
@@ -285,6 +297,25 @@
   return next_transfer_buffer_id_.GetNext();
 }
 
+gfx::GpuMemoryBufferHandle GpuChannelHost::ShareGpuMemoryBufferToGpuProcess(
+    gfx::GpuMemoryBufferHandle source_handle) {
+  switch (source_handle.type) {
+    case gfx::SHARED_MEMORY_BUFFER: {
+      gfx::GpuMemoryBufferHandle handle;
+      handle.type = gfx::SHARED_MEMORY_BUFFER;
+      handle.handle = ShareToGpuProcess(source_handle.handle);
+      return handle;
+    }
+    default:
+      NOTREACHED();
+      return gfx::GpuMemoryBufferHandle();
+  }
+}
+
+int32 GpuChannelHost::ReserveGpuMemoryBufferId() {
+  return next_gpu_memory_buffer_id_.GetNext();
+}
+
 GpuChannelHost::~GpuChannelHost() {
   // channel_ must be destroyed on the main thread.
   if (!factory_->IsMainThread())
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 5efa98d..f248c77 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -24,6 +24,7 @@
 #include "ipc/ipc_sync_channel.h"
 #include "media/video/video_decode_accelerator.h"
 #include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/size.h"
 #include "ui/gl/gpu_preference.h"
@@ -71,12 +72,15 @@
   virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) = 0;
   virtual int32 CreateViewCommandBuffer(
       int32 surface_id, const GPUCreateCommandBufferConfig& init_params) = 0;
-  virtual GpuChannelHost* EstablishGpuChannelSync(CauseForGpuLaunch) = 0;
   virtual void CreateImage(
       gfx::PluginWindowHandle window,
       int32 image_id,
       const CreateImageCallback& callback) = 0;
   virtual void DeleteImage(int32 image_id, int32 sync_point) = 0;
+  virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat) = 0;
 };
 
 // Encapsulates an IPC channel between the client and one GPU process.
@@ -94,6 +98,10 @@
       const gpu::GPUInfo& gpu_info,
       const IPC::ChannelHandle& channel_handle);
 
+  // Returns true if |handle| is a valid GpuMemoryBuffer handle that
+  // can be shared to the GPU process.
+  static bool IsValidGpuMemoryBuffer(gfx::GpuMemoryBufferHandle handle);
+
   bool IsLost() const {
     DCHECK(channel_filter_.get());
     return channel_filter_->IsLost();
@@ -162,6 +170,15 @@
   // Reserve one unused transfer buffer ID.
   int32 ReserveTransferBufferId();
 
+  // Returns a GPU memory buffer handle to the buffer that can be sent via
+  // IPC to the GPU process. The caller is responsible for ensuring it is
+  // closed. Returns an invalid handle on failure.
+  gfx::GpuMemoryBufferHandle ShareGpuMemoryBufferToGpuProcess(
+      gfx::GpuMemoryBufferHandle source_handle);
+
+  // Reserve one unused gpu memory buffer ID.
+  int32 ReserveGpuMemoryBufferId();
+
  private:
   friend class base::RefCountedThreadSafe<GpuChannelHost>;
   GpuChannelHost(GpuChannelHostFactory* factory,
@@ -228,6 +245,7 @@
   // Threading notes: all fields are constant during the lifetime of |this|
   // except:
   // - |next_transfer_buffer_id_|, atomic type
+  // - |next_gpu_memory_buffer_id_|, atomic type
   // - |proxies_|, protected by |context_lock_|
   GpuChannelHostFactory* const factory_;
   const int client_id_;
@@ -244,6 +262,9 @@
   // Transfer buffer IDs are allocated in sequence.
   base::AtomicSequenceNumber next_transfer_buffer_id_;
 
+  // Gpu memory buffer IDs are allocated in sequence.
+  base::AtomicSequenceNumber next_gpu_memory_buffer_id_;
+
   // Protects proxies_.
   mutable base::Lock context_lock_;
   // Used to look up a proxy from its routing id.
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc
new file mode 100644
index 0000000..e5f6bc5
--- /dev/null
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 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/common/gpu/client/gpu_memory_buffer_impl.h"
+
+#include "ui/gl/gl_bindings.h"
+
+namespace content {
+
+GpuMemoryBufferImpl::GpuMemoryBufferImpl(
+    scoped_ptr<base::SharedMemory> shared_memory,
+    size_t width,
+    size_t height,
+    unsigned internalformat)
+    : shared_memory_(shared_memory.Pass()),
+      size_(gfx::Size(width, height)),
+      internalformat_(internalformat),
+      mapped_(false) {
+  DCHECK(!shared_memory_->memory());
+  DCHECK(IsFormatValid(internalformat));
+}
+
+GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
+}
+
+void GpuMemoryBufferImpl::Map(AccessMode mode, void** vaddr) {
+  DCHECK(!mapped_);
+  *vaddr = NULL;
+  if (!shared_memory_->Map(size_.GetArea() * BytesPerPixel(internalformat_)))
+    return;
+  *vaddr = shared_memory_->memory();
+  mapped_ = true;
+}
+
+void GpuMemoryBufferImpl::Unmap() {
+  DCHECK(mapped_);
+  shared_memory_->Unmap();
+  mapped_ = false;
+}
+
+bool GpuMemoryBufferImpl::IsMapped() const {
+  return mapped_;
+}
+
+uint32 GpuMemoryBufferImpl::GetStride() const {
+  return size_.width() * BytesPerPixel(internalformat_);
+}
+
+gfx::GpuMemoryBufferHandle GpuMemoryBufferImpl::GetHandle() const {
+  gfx::GpuMemoryBufferHandle handle;
+  handle.type = gfx::SHARED_MEMORY_BUFFER;
+  handle.handle = shared_memory_->handle();
+  return handle;
+}
+
+// static
+bool GpuMemoryBufferImpl::IsFormatValid(unsigned internalformat) {
+  // GL_RGBA8_OES is the only supported format at the moment.
+  switch (internalformat) {
+    case GL_RGBA8_OES:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// static
+size_t GpuMemoryBufferImpl::BytesPerPixel(unsigned internalformat) {
+  // GL_RGBA_OES has 4 bytes per pixel.
+  switch (internalformat) {
+    case GL_RGBA8_OES:
+      return 4;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+}  // namespace content
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.h b/content/common/gpu/client/gpu_memory_buffer_impl.h
new file mode 100644
index 0000000..3858c3f
--- /dev/null
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
+#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+
+// Provides common implementation of a GPU memory buffer based
+// on a shared memory handle.
+class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
+ public:
+  GpuMemoryBufferImpl(scoped_ptr<base::SharedMemory> shared_memory,
+                      size_t width,
+                      size_t height,
+                      unsigned internalformat);
+  virtual ~GpuMemoryBufferImpl();
+
+  // Overridden from gfx::GpuMemoryBuffer:
+  virtual void Map(AccessMode mode, void** vaddr) OVERRIDE;
+  virtual void Unmap() OVERRIDE;
+  virtual bool IsMapped() const OVERRIDE;
+  virtual uint32 GetStride() const OVERRIDE;
+  virtual gfx::GpuMemoryBufferHandle GetHandle() const OVERRIDE;
+
+  static bool IsFormatValid(unsigned internalformat);
+  static size_t BytesPerPixel(unsigned internalformat);
+
+ private:
+  scoped_ptr<base::SharedMemory> shared_memory_;
+  const gfx::Size size_;
+  unsigned internalformat_;
+  bool mapped_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index bd4ebab..5712842 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -24,8 +24,6 @@
 #include "base/metrics/histogram.h"
 #include "base/synchronization/lock.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -35,6 +33,7 @@
 #include "gpu/command_buffer/client/gles2_trace_implementation.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
 #include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "third_party/skia/include/core/SkTypes.h"
 #include "webkit/common/gpu/gl_bindings_skia_cmd_buffer.h"
@@ -147,6 +146,11 @@
   gl_->glname(a1, a2, a3);                                              \
 }
 
+#define DELEGATE_TO_GL_3R(name, glname, t1, t2, t3, rt)                 \
+rt WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3) {   \
+  return gl_->glname(a1, a2, a3);                                       \
+}
+
 #define DELEGATE_TO_GL_4(name, glname, t1, t2, t3, t4)                  \
 void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3,   \
                                                  t4 a4) {               \
@@ -213,16 +217,25 @@
   graphics_context_->OnErrorMessage(msg, id);
 }
 
+WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits::SharedMemoryLimits()
+    : command_buffer_size(kDefaultCommandBufferSize),
+      start_transfer_buffer_size(kDefaultStartTransferBufferSize),
+      min_transfer_buffer_size(kDefaultMinTransferBufferSize),
+      max_transfer_buffer_size(kDefaultMaxTransferBufferSize),
+      mapped_memory_reclaim_limit(gpu::gles2::GLES2Implementation::kNoLimit) {}
+
 WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl(
     int surface_id,
     const GURL& active_url,
-    GpuChannelHostFactory* factory,
-    const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client)
+    GpuChannelHost* host,
+    const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
+    const Attributes& attributes,
+    bool bind_generates_resources,
+    const SharedMemoryLimits& limits)
     : initialize_failed_(false),
-      factory_(factory),
       visible_(false),
       free_command_buffer_when_invisible_(false),
-      host_(NULL),
+      host_(host),
       surface_id_(surface_id),
       active_url_(active_url),
       swap_client_(swap_client),
@@ -230,18 +243,16 @@
       context_lost_reason_(GL_NO_ERROR),
       error_message_callback_(0),
       swapbuffers_complete_callback_(0),
-      gpu_preference_(gfx::PreferIntegratedGpu),
+      attributes_(attributes),
+      gpu_preference_(attributes.preferDiscreteGPU ? gfx::PreferDiscreteGpu
+                                                   : gfx::PreferIntegratedGpu),
       weak_ptr_factory_(this),
       initialized_(false),
       gl_(NULL),
       frame_number_(0),
-      bind_generates_resources_(false),
+      bind_generates_resources_(bind_generates_resources),
       use_echo_for_swap_ack_(true),
-      command_buffer_size_(0),
-      start_transfer_buffer_size_(0),
-      min_transfer_buffer_size_(0),
-      max_transfer_buffer_size_(0),
-      mapped_memory_limit_(gpu::gles2::GLES2Implementation::kNoLimit),
+      mem_limits_(limits),
       flush_id_(0) {
 #if (defined(OS_MACOSX) || defined(OS_WIN)) && !defined(USE_AURA)
   // Get ViewMsg_SwapBuffers_ACK from browser for single-threaded path.
@@ -264,54 +275,6 @@
   Destroy();
 }
 
-bool WebGraphicsContext3DCommandBufferImpl::InitializeWithDefaultBufferSizes(
-    const WebGraphicsContext3D::Attributes& attributes,
-    bool bind_generates_resources,
-    CauseForGpuLaunch cause) {
-  return Initialize(attributes,
-                    bind_generates_resources,
-                    cause,
-                    kDefaultCommandBufferSize,
-                    kDefaultStartTransferBufferSize,
-                    kDefaultMinTransferBufferSize,
-                    kDefaultMaxTransferBufferSize,
-                    gpu::gles2::GLES2Implementation::kNoLimit);
-}
-
-bool WebGraphicsContext3DCommandBufferImpl::Initialize(
-    const WebGraphicsContext3D::Attributes& attributes,
-    bool bind_generates_resources,
-    CauseForGpuLaunch cause,
-    size_t command_buffer_size,
-    size_t start_transfer_buffer_size,
-    size_t min_transfer_buffer_size,
-    size_t max_transfer_buffer_size,
-    size_t mapped_memory_limit) {
-  TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize");
-
-  attributes_ = attributes;
-  bind_generates_resources_ = bind_generates_resources;
-  DCHECK(!command_buffer_);
-
-  if (!factory_)
-    return false;
-
-  if (attributes.preferDiscreteGPU)
-    gpu_preference_ = gfx::PreferDiscreteGpu;
-
-  host_ = factory_->EstablishGpuChannelSync(cause);
-  if (!host_.get())
-    return false;
-
-  command_buffer_size_ = command_buffer_size;
-  start_transfer_buffer_size_ = start_transfer_buffer_size;
-  min_transfer_buffer_size_ = min_transfer_buffer_size;
-  max_transfer_buffer_size_ = max_transfer_buffer_size;
-  mapped_memory_limit_ = mapped_memory_limit;
-
-  return true;
-}
-
 bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() {
   if (initialized_)
     return true;
@@ -439,7 +402,7 @@
 
   // Create the GLES2 helper, which writes the command buffer protocol.
   gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get()));
-  if (!gles2_helper_->Initialize(command_buffer_size_))
+  if (!gles2_helper_->Initialize(mem_limits_.command_buffer_size))
     return false;
 
   if (attributes_.noAutomaticFlushes)
@@ -478,10 +441,10 @@
   }
 
   if (!real_gl_->Initialize(
-      start_transfer_buffer_size_,
-      min_transfer_buffer_size_,
-      max_transfer_buffer_size_,
-      mapped_memory_limit_)) {
+      mem_limits_.start_transfer_buffer_size,
+      mem_limits_.min_transfer_buffer_size,
+      mem_limits_.max_transfer_buffer_size,
+      mem_limits_.mapped_memory_reclaim_limit)) {
     return false;
   }
 
@@ -647,34 +610,6 @@
   command_buffer_->EnsureBackbuffer();
 }
 
-void WebGraphicsContext3DCommandBufferImpl::sendManagedMemoryStatsCHROMIUM(
-    const WebGraphicsManagedMemoryStats* stats)
-{
-  CHECK(command_buffer_);
-  command_buffer_->SendManagedMemoryStats(GpuManagedMemoryStats(
-      stats->bytesVisible,
-      stats->bytesVisibleAndNearby,
-      stats->bytesAllocated,
-      stats->backbufferRequested));
-}
-
-void WebGraphicsContext3DCommandBufferImpl::
-    setMemoryAllocationChangedCallbackCHROMIUM(
-        WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) {
-  if (!command_buffer_)
-    return;
-
-  if (callback)
-    command_buffer_->SetMemoryAllocationChangedCallback(base::Bind(
-        &WebGraphicsContext3DCommandBufferImpl::OnMemoryAllocationChanged,
-        weak_ptr_factory_.GetWeakPtr(),
-        callback));
-  else
-    command_buffer_->SetMemoryAllocationChangedCallback(
-        base::Callback<void(const GpuMemoryAllocationForRenderer&)>());
-}
-
-
 void WebGraphicsContext3DCommandBufferImpl::copyTextureToParentTextureCHROMIUM(
     WebGLId texture, WebGLId parentTexture) {
   NOTIMPLEMENTED();
@@ -1223,6 +1158,23 @@
 DELEGATE_TO_GL_4(viewport, Viewport,
                  WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei)
 
+DELEGATE_TO_GL_2(genBuffers, GenBuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genFramebuffers, GenFramebuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genRenderbuffers, GenRenderbuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genTextures, GenTextures, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteBuffers, DeleteBuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteFramebuffers, DeleteFramebuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteRenderbuffers, DeleteRenderbuffers, WGC3Dsizei,
+                 WebGLId*);
+
+DELEGATE_TO_GL_2(deleteTextures, DeleteTextures, WGC3Dsizei, WebGLId*);
+
 WebGLId WebGraphicsContext3DCommandBufferImpl::createBuffer() {
   GLuint o;
   gl_->GenBuffers(1, &o);
@@ -1235,16 +1187,12 @@
   return o;
 }
 
-DELEGATE_TO_GL_R(createProgram, CreateProgram, WebGLId)
-
 WebGLId WebGraphicsContext3DCommandBufferImpl::createRenderbuffer() {
   GLuint o;
   gl_->GenRenderbuffers(1, &o);
   return o;
 }
 
-DELEGATE_TO_GL_1R(createShader, CreateShader, WGC3Denum, WebGLId)
-
 WebGLId WebGraphicsContext3DCommandBufferImpl::createTexture() {
   GLuint o;
   gl_->GenTextures(1, &o);
@@ -1260,21 +1208,25 @@
   gl_->DeleteFramebuffers(1, &framebuffer);
 }
 
-DELEGATE_TO_GL_1(deleteProgram, DeleteProgram, WebGLId)
-
 void WebGraphicsContext3DCommandBufferImpl::deleteRenderbuffer(
     WebGLId renderbuffer) {
   gl_->DeleteRenderbuffers(1, &renderbuffer);
 }
 
-DELEGATE_TO_GL_1(deleteShader, DeleteShader, WebGLId)
-
 void WebGraphicsContext3DCommandBufferImpl::deleteTexture(WebGLId texture) {
   gl_->DeleteTextures(1, &texture);
 }
 
+DELEGATE_TO_GL_R(createProgram, CreateProgram, WebGLId)
+
+DELEGATE_TO_GL_1R(createShader, CreateShader, WGC3Denum, WebGLId)
+
+DELEGATE_TO_GL_1(deleteProgram, DeleteProgram, WebGLId)
+
+DELEGATE_TO_GL_1(deleteShader, DeleteShader, WebGLId)
+
 bool WebGraphicsContext3DCommandBufferImpl::ShouldUseSwapClient() {
-  return factory_ && factory_->IsMainThread() && swap_client_.get();
+  return !!swap_client_.get();
 }
 
 void WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete() {
@@ -1291,56 +1243,6 @@
     swapbuffers_complete_callback_->onSwapBuffersComplete();
 }
 
-WebGraphicsMemoryAllocation::PriorityCutoff
-    WebGraphicsContext3DCommandBufferImpl::WebkitPriorityCutoff(
-        GpuMemoryAllocationForRenderer::PriorityCutoff priorityCutoff) {
-  switch (priorityCutoff) {
-  case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNothing:
-    return WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing;
-  case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowOnlyRequired:
-    return WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly;
-  case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNiceToHave:
-    return WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleAndNearby;
-  case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything:
-    return WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything;
-  }
-  NOTREACHED();
-  return WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything;
-}
-
-void WebGraphicsContext3DCommandBufferImpl::OnMemoryAllocationChanged(
-    WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback,
-    const GpuMemoryAllocationForRenderer& allocation) {
-
-  // Convert the gpu structure to the WebKit structure.
-  WebGraphicsMemoryAllocation web_allocation;
-  web_allocation.bytesLimitWhenVisible =
-      ClampUint64ToSizeT(allocation.bytes_limit_when_visible);
-  web_allocation.priorityCutoffWhenVisible =
-      WebkitPriorityCutoff(allocation.priority_cutoff_when_visible);
-  web_allocation.bytesLimitWhenNotVisible =
-      ClampUint64ToSizeT(allocation.bytes_limit_when_not_visible);
-  web_allocation.priorityCutoffWhenNotVisible =
-      WebkitPriorityCutoff(allocation.priority_cutoff_when_not_visible);
-  web_allocation.haveBackbufferWhenNotVisible =
-      allocation.have_backbuffer_when_not_visible;
-
-  // Populate deprecated WebKit fields. These may be removed when references to
-  // them in WebKit are removed.
-  web_allocation.gpuResourceSizeInBytes =
-      ClampUint64ToSizeT(allocation.bytes_limit_when_visible);
-  web_allocation.suggestHaveBackbuffer =
-      allocation.have_backbuffer_when_not_visible;
-
-  if (callback)
-    callback->onMemoryAllocationChanged(web_allocation);
-
-  // We may have allocated transfer buffers in order to free GL resources in a
-  // backgrounded tab. Re-free the transfer buffers.
-  if (!visible_)
-    real_gl_->FreeEverything();
-}
-
 void WebGraphicsContext3DCommandBufferImpl::setErrorMessageCallback(
     WebGraphicsContext3D::WebGraphicsErrorMessageCallback* cb) {
   error_message_callback_ = cb;
@@ -1372,20 +1274,19 @@
 // static
 WebGraphicsContext3DCommandBufferImpl*
 WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-    GpuChannelHostFactory* factory,
+    GpuChannelHost* host,
     const WebGraphicsContext3D::Attributes& attributes,
     const GURL& active_url) {
-  if (!factory)
+  if (!host)
     return NULL;
   base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> null_client;
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
-      new WebGraphicsContext3DCommandBufferImpl(
-          0, active_url, factory, null_client));
-  CauseForGpuLaunch cause =
-      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
-  if (context->InitializeWithDefaultBufferSizes(attributes, false, cause))
-    return context.release();
-  return NULL;
+  return new WebGraphicsContext3DCommandBufferImpl(0,
+                                                   active_url,
+                                                   host,
+                                                   null_client,
+                                                   attributes,
+                                                   false,
+                                                   SharedMemoryLimits());
 }
 
 void WebGraphicsContext3DCommandBufferImpl::
@@ -1436,18 +1337,6 @@
 
 DELEGATE_TO_GL_1(waitSyncPoint, WaitSyncPointCHROMIUM, GLuint)
 
-void WebGraphicsContext3DCommandBufferImpl::signalSyncPoint(
-    unsigned sync_point,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
-void WebGraphicsContext3DCommandBufferImpl::signalQuery(
-    unsigned query,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
 void WebGraphicsContext3DCommandBufferImpl::loseContextCHROMIUM(
     WGC3Denum current, WGC3Denum other) {
   gl_->LoseContextCHROMIUM(current, other);
@@ -1525,6 +1414,20 @@
 DELEGATE_TO_GL_2(vertexAttribDivisorANGLE, VertexAttribDivisorANGLE, WGC3Duint,
                  WGC3Duint)
 
+DELEGATE_TO_GL_3R(createImageCHROMIUM, CreateImageCHROMIUM,
+                  WGC3Dsizei, WGC3Dsizei, WGC3Denum,
+                  WGC3Duint);
+
+DELEGATE_TO_GL_1(destroyImageCHROMIUM, DestroyImageCHROMIUM, WGC3Duint);
+
+DELEGATE_TO_GL_3(getImageParameterivCHROMIUM, GetImageParameterivCHROMIUM,
+                 WGC3Duint, WGC3Denum, GLint*);
+
+DELEGATE_TO_GL_2R(mapImageCHROMIUM, MapImageCHROMIUM,
+                  WGC3Duint, WGC3Denum, void*);
+
+DELEGATE_TO_GL_1(unmapImageCHROMIUM, UnmapImageCHROMIUM, WGC3Duint);
+
 GrGLInterface* WebGraphicsContext3DCommandBufferImpl::createGrGLInterface() {
   return webkit::gpu::CreateCommandBufferSkiaGLBinding();
 }
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index 7a03d33..221114a 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "ui/gfx/native_widget_types.h"
@@ -46,13 +45,9 @@
 using WebKit::WGC3Dclampf;
 using WebKit::WGC3Dintptr;
 using WebKit::WGC3Dsizeiptr;
-using WebKit::WebGraphicsManagedMemoryStats;
-using WebKit::WebGraphicsMemoryAllocation;
 
 namespace content {
 class GpuChannelHost;
-class GpuChannelHostFactory;
-struct GpuMemoryAllocationForRenderer;
 
 const size_t kDefaultCommandBufferSize = 1024 * 1024;
 const size_t kDefaultStartTransferBufferSize = 1 * 1024 * 1024;
@@ -80,27 +75,27 @@
     kNoLimit = 0,
   };
 
+  struct SharedMemoryLimits {
+    SharedMemoryLimits();
+
+    size_t command_buffer_size;
+    size_t start_transfer_buffer_size;
+    size_t min_transfer_buffer_size;
+    size_t max_transfer_buffer_size;
+    size_t mapped_memory_reclaim_limit;
+  };
+
   WebGraphicsContext3DCommandBufferImpl(
       int surface_id,
       const GURL& active_url,
-      GpuChannelHostFactory* factory,
-      const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client);
+      GpuChannelHost* host,
+      const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
+      const Attributes& attributes,
+      bool bind_generates_resources,
+      const SharedMemoryLimits& limits);
 
   virtual ~WebGraphicsContext3DCommandBufferImpl();
 
-  bool Initialize(const Attributes& attributes,
-                  bool bind_generates_resources,
-                  CauseForGpuLaunch cause,
-                  size_t command_buffer_size,
-                  size_t start_transfer_buffer_size,
-                  size_t min_transfer_buffer_size,
-                  size_t max_transfer_buffer_size,
-                  size_t mapped_memory_reclaim_limit);
-
-  bool InitializeWithDefaultBufferSizes(const Attributes& attributes,
-                                        bool bind_generates_resources,
-                                        CauseForGpuLaunch cause);
-
   // The following 3 IDs let one uniquely identify this context.
   // Gets the GPU process ID for this context.
   int GetGPUProcessID();
@@ -129,12 +124,12 @@
   // on any failure.
   static CONTENT_EXPORT WebGraphicsContext3DCommandBufferImpl*
       CreateOffscreenContext(
-          GpuChannelHostFactory* factory,
+          GpuChannelHost* host,
           const WebGraphicsContext3D::Attributes& attributes,
           const GURL& active_url);
 
   size_t GetMappedMemoryLimit() {
-    return mapped_memory_limit_;
+    return mem_limits_.mapped_memory_reclaim_limit;
   }
 
   //----------------------------------------------------------------------
@@ -149,10 +144,6 @@
 
   virtual unsigned int insertSyncPoint();
   virtual void waitSyncPoint(unsigned int sync_point);
-  virtual void signalSyncPoint(unsigned sync_point,
-                               WebGraphicsSyncPointCallback* callback);
-  virtual void signalQuery(unsigned query,
-                           WebGraphicsSyncPointCallback* callback);
 
   virtual void loseContextCHROMIUM(WGC3Denum current, WGC3Denum other);
 
@@ -475,20 +466,32 @@
                         WGC3Dsizei width, WGC3Dsizei height);
 
   // Support for buffer creation and deletion
+  virtual void genBuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genFramebuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genRenderbuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genTextures(WGC3Dsizei count, WebGLId* ids);
+
+  virtual void deleteBuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteFramebuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteRenderbuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteTextures(WGC3Dsizei count, WebGLId* ids);
+
   virtual WebGLId createBuffer();
   virtual WebGLId createFramebuffer();
-  virtual WebGLId createProgram();
   virtual WebGLId createRenderbuffer();
-  virtual WebGLId createShader(WGC3Denum);
   virtual WebGLId createTexture();
 
   virtual void deleteBuffer(WebGLId);
   virtual void deleteFramebuffer(WebGLId);
-  virtual void deleteProgram(WebGLId);
   virtual void deleteRenderbuffer(WebGLId);
-  virtual void deleteShader(WebGLId);
   virtual void deleteTexture(WebGLId);
 
+  virtual WebGLId createProgram();
+  virtual WebGLId createShader(WGC3Denum);
+
+  virtual void deleteProgram(WebGLId);
+  virtual void deleteShader(WebGLId);
+
   virtual void synthesizeGLError(WGC3Denum);
 
   virtual void* mapBufferSubDataCHROMIUM(
@@ -515,12 +518,6 @@
   virtual void discardBackbufferCHROMIUM();
   virtual void ensureBackbufferCHROMIUM();
 
-  virtual void setMemoryAllocationChangedCallbackCHROMIUM(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback);
-
-  virtual void sendManagedMemoryStatsCHROMIUM(
-      const WebGraphicsManagedMemoryStats* stats);
-
   virtual void copyTextureToParentTextureCHROMIUM(
       WebGLId texture, WebGLId parentTexture);
 
@@ -640,6 +637,15 @@
       WGC3Denum type, WGC3Dintptr offset, WGC3Dsizei primcount);
   virtual void vertexAttribDivisorANGLE(WGC3Duint index, WGC3Duint divisor);
 
+  // GL_CHROMIUM_map_image
+  virtual WGC3Duint createImageCHROMIUM(
+      WGC3Dsizei width, WGC3Dsizei height, WGC3Denum internalformat);
+  virtual void destroyImageCHROMIUM(WGC3Duint image_id);
+  virtual void getImageParameterivCHROMIUM(
+      WGC3Duint image_id, WGC3Denum pname, WGC3Dint* params);
+  virtual void* mapImageCHROMIUM(WGC3Duint image_id, WGC3Denum access);
+  virtual void unmapImageCHROMIUM(WGC3Duint image_id);
+
   virtual GrGLInterface* createGrGLInterface();
 
  private:
@@ -704,20 +710,8 @@
   // main thread.
   bool ShouldUseSwapClient();
 
-  // MemoryAllocationChanged callback.
-  void OnMemoryAllocationChanged(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback,
-      const GpuMemoryAllocationForRenderer& allocation);
-
-  // Convert the gpu cutoff enum to the WebKit enum.
-  static WebGraphicsMemoryAllocation::PriorityCutoff WebkitPriorityCutoff(
-      GpuMemoryAllocationForRenderer::PriorityCutoff priorityCutoff);
-
   bool initialize_failed_;
 
-  // The channel factory to talk to the GPU process
-  GpuChannelHostFactory* factory_;
-
   bool visible_;
   bool free_command_buffer_when_invisible_;
 
@@ -757,11 +751,7 @@
   int frame_number_;
   bool bind_generates_resources_;
   bool use_echo_for_swap_ack_;
-  size_t command_buffer_size_;
-  size_t start_transfer_buffer_size_;
-  size_t min_transfer_buffer_size_;
-  size_t max_transfer_buffer_size_;
-  size_t mapped_memory_limit_;
+  SharedMemoryLimits mem_limits_;
 
   uint32_t flush_id_;
 };
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index ddcd34e..fe6bb5b 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -961,6 +961,11 @@
       stats->total_processing_commands_time += total_processing_commands_time;
     }
   }
+
+  GPUVideoMemoryUsageStats usage_stats;
+  gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
+      &usage_stats);
+  stats->global_video_memory_bytes_allocated = usage_stats.bytes_allocated;
 }
 
 void GpuChannel::MessageProcessed() {
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 05792bf..b3ff05a 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -26,6 +26,8 @@
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
+#include "gpu/command_buffer/service/gpu_control_service.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/logger.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/query_manager.h"
@@ -223,6 +225,10 @@
     IPC_MESSAGE_HANDLER(
         GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback,
         OnSetClientHasMemoryAllocationChangedCallback)
+    IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterGpuMemoryBuffer,
+                        OnRegisterGpuMemoryBuffer);
+    IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyGpuMemoryBuffer,
+                        OnDestroyGpuMemoryBuffer);
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -403,6 +409,12 @@
     return;
   }
 
+  gpu_control_.reset(
+      new gpu::GpuControlService(context_group_->image_manager(),
+                                 NULL,
+                                 context_group_->mailbox_manager(),
+                                 NULL));
+
   decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
 
   scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
@@ -825,7 +837,7 @@
 
 
 void GpuCommandBufferStub::OnReceivedClientManagedMemoryStats(
-    const GpuManagedMemoryStats& stats) {
+    const gpu::ManagedMemoryStats& stats) {
   TRACE_EVENT0(
       "gpu",
       "GpuCommandBufferStub::OnReceivedClientManagedMemoryStats");
@@ -848,6 +860,28 @@
   }
 }
 
+void GpuCommandBufferStub::OnRegisterGpuMemoryBuffer(
+    int32 id,
+    gfx::GpuMemoryBufferHandle gpu_memory_buffer,
+    uint32 width,
+    uint32 height,
+    uint32 internalformat) {
+  TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnRegisterGpuMemoryBuffer");
+  if (gpu_control_) {
+    gpu_control_->RegisterGpuMemoryBuffer(id,
+                                          gpu_memory_buffer,
+                                          width,
+                                          height,
+                                          internalformat);
+  }
+}
+
+void GpuCommandBufferStub::OnDestroyGpuMemoryBuffer(int32 id) {
+  TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyGpuMemoryBuffer");
+  if (gpu_control_)
+    gpu_control_->DestroyGpuMemoryBuffer(id);
+}
+
 void GpuCommandBufferStub::SendConsoleMessage(
     int32 id,
     const std::string& message) {
@@ -898,28 +932,25 @@
 }
 
 void GpuCommandBufferStub::SetMemoryAllocation(
-    const GpuMemoryAllocation& allocation) {
+    const gpu::MemoryAllocation& allocation) {
   if (!last_memory_allocation_valid_ ||
-      !allocation.renderer_allocation.Equals(
-          last_memory_allocation_.renderer_allocation)) {
+      !allocation.Equals(last_memory_allocation_)) {
     Send(new GpuCommandBufferMsg_SetMemoryAllocation(
-        route_id_, allocation.renderer_allocation));
-  }
-
-  if (!last_memory_allocation_valid_ ||
-      !allocation.browser_allocation.Equals(
-          last_memory_allocation_.browser_allocation)) {
-    // This can be called outside of OnMessageReceived, so the context needs
-    // to be made current before calling methods on the surface.
-    if (surface_.get() && MakeCurrent())
-      surface_->SetFrontbufferAllocation(
-          allocation.browser_allocation.suggest_have_frontbuffer);
+        route_id_, allocation));
   }
 
   last_memory_allocation_valid_ = true;
   last_memory_allocation_ = allocation;
 }
 
+void GpuCommandBufferStub::SuggestHaveFrontBuffer(
+    bool suggest_have_frontbuffer) {
+  // This can be called outside of OnMessageReceived, so the context needs
+  // to be made current before calling methods on the surface.
+  if (surface_.get() && MakeCurrent())
+    surface_->SetFrontbufferAllocation(suggest_have_frontbuffer);
+}
+
 bool GpuCommandBufferStub::CheckContextLost() {
   DCHECK(command_buffer_);
   gpu::CommandBuffer::State state = command_buffer_->GetState();
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index 47c532b..bf1914a 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -13,10 +13,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "content/common/content_export.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/common/gpu/gpu_memory_manager.h"
 #include "content/common/gpu/gpu_memory_manager_client.h"
 #include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gpu_scheduler.h"
@@ -24,6 +24,7 @@
 #include "ipc/ipc_sender.h"
 #include "media/base/video_decoder_config.h"
 #include "ui/events/latency_info.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/size.h"
 #include "ui/gl/gl_surface.h"
@@ -31,6 +32,7 @@
 #include "url/gurl.h"
 
 namespace gpu {
+class GpuControlService;
 struct Mailbox;
 namespace gles2 {
 class ImageManager;
@@ -91,7 +93,8 @@
   virtual gfx::Size GetSurfaceSize() const OVERRIDE;
   virtual gpu::gles2::MemoryTracker* GetMemoryTracker() const OVERRIDE;
   virtual void SetMemoryAllocation(
-      const GpuMemoryAllocation& allocation) OVERRIDE;
+      const gpu::MemoryAllocation& allocation) OVERRIDE;
+  virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE;
   virtual bool GetTotalGpuMemory(uint64* bytes) OVERRIDE;
 
   // Whether this command buffer can currently handle IPC messages.
@@ -178,9 +181,16 @@
   void OnSignalSyncPointAck(uint32 id);
   void OnSignalQuery(uint32 query, uint32 id);
 
-  void OnReceivedClientManagedMemoryStats(const GpuManagedMemoryStats& stats);
+  void OnReceivedClientManagedMemoryStats(const gpu::ManagedMemoryStats& stats);
   void OnSetClientHasMemoryAllocationChangedCallback(bool has_callback);
 
+  void OnRegisterGpuMemoryBuffer(int32 id,
+                                 gfx::GpuMemoryBufferHandle gpu_memory_buffer,
+                                 uint32 width,
+                                 uint32 height,
+                                 uint32 internalformat);
+  void OnDestroyGpuMemoryBuffer(int32 id);
+
   void OnCommandProcessed();
   void OnParseError();
   void OnSetLatencyInfo(const ui::LatencyInfo& latency_info);
@@ -223,12 +233,13 @@
   scoped_ptr<gpu::gles2::GLES2Decoder> decoder_;
   scoped_ptr<gpu::GpuScheduler> scheduler_;
   scoped_refptr<gfx::GLSurface> surface_;
+  scoped_ptr<gpu::GpuControlService> gpu_control_;
 
   scoped_ptr<GpuMemoryManagerClientState> memory_manager_client_state_;
   // The last memory allocation received from the GpuMemoryManager (used to
   // elide redundant work).
   bool last_memory_allocation_valid_;
-  GpuMemoryAllocation last_memory_allocation_;
+  gpu::MemoryAllocation last_memory_allocation_;
 
   GpuWatchdog* watchdog_;
 
diff --git a/content/common/gpu/gpu_memory_allocation.h b/content/common/gpu/gpu_memory_allocation.h
deleted file mode 100644
index a2a9b9a..0000000
--- a/content/common/gpu/gpu_memory_allocation.h
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2012 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_GPU_MEMORY_ALLOCATION_H_
-#define CONTENT_COMMON_GPU_GPU_MEMORY_ALLOCATION_H_
-
-#include "base/basictypes.h"
-
-namespace content {
-
-// These are per context memory allocation limits set by the GpuMemoryManager
-// and assigned to the browser and renderer context.
-// They will change over time, given memory availability, and browser state.
-
-// Memory Allocation which will be assigned to the renderer context.
-struct GpuMemoryAllocationForRenderer {
-  enum PriorityCutoff {
-    // Allow no allocations.
-    kPriorityCutoffAllowNothing,
-    // Allow only allocations that are strictly required for correct rendering.
-    // For compositors, this is what is visible.
-    kPriorityCutoffAllowOnlyRequired,
-    // Allow allocations that are not strictly needed for correct rendering, but
-    // are nice to have for performance. For compositors, this includes textures
-    // that are a few screens away from being visible.
-    kPriorityCutoffAllowNiceToHave,
-    // Allow all allocations.
-    kPriorityCutoffAllowEverything,
-  };
-
-  // Limits when this renderer is visible.
-  uint64 bytes_limit_when_visible;
-  PriorityCutoff priority_cutoff_when_visible;
-
-  // Limits when this renderer is not visible.
-  uint64 bytes_limit_when_not_visible;
-  PriorityCutoff priority_cutoff_when_not_visible;
-  bool have_backbuffer_when_not_visible;
-
-  GpuMemoryAllocationForRenderer()
-      : bytes_limit_when_visible(0),
-        priority_cutoff_when_visible(kPriorityCutoffAllowNothing),
-        bytes_limit_when_not_visible(0),
-        priority_cutoff_when_not_visible(kPriorityCutoffAllowNothing),
-        have_backbuffer_when_not_visible(false) {
-  }
-
-  GpuMemoryAllocationForRenderer(uint64 bytes_limit_when_visible)
-      : bytes_limit_when_visible(bytes_limit_when_visible),
-        priority_cutoff_when_visible(kPriorityCutoffAllowEverything),
-        bytes_limit_when_not_visible(0),
-        priority_cutoff_when_not_visible(kPriorityCutoffAllowNothing),
-        have_backbuffer_when_not_visible(false) {
-  }
-
-  bool Equals(const GpuMemoryAllocationForRenderer& other) const {
-    return bytes_limit_when_visible ==
-               other.bytes_limit_when_visible &&
-        priority_cutoff_when_visible == other.priority_cutoff_when_visible &&
-        bytes_limit_when_not_visible == other.bytes_limit_when_not_visible &&
-        priority_cutoff_when_not_visible ==
-            other.priority_cutoff_when_not_visible &&
-        have_backbuffer_when_not_visible ==
-            other.have_backbuffer_when_not_visible;
-  }
-};
-
-// Memory Allocation which will be assigned to the browser.
-struct GpuMemoryAllocationForBrowser {
-  bool suggest_have_frontbuffer;
-
-  GpuMemoryAllocationForBrowser()
-      : suggest_have_frontbuffer(false) {
-  }
-
-  GpuMemoryAllocationForBrowser(bool suggest_have_frontbuffer)
-      : suggest_have_frontbuffer(suggest_have_frontbuffer) {
-  }
-
-  bool Equals(const GpuMemoryAllocationForBrowser& other) const {
-      return suggest_have_frontbuffer == other.suggest_have_frontbuffer;
-  }
-};
-
-// Combination of the above two Memory Allocations which will be created by the
-// GpuMemoryManager.
-struct GpuMemoryAllocation {
-  GpuMemoryAllocationForRenderer renderer_allocation;
-  GpuMemoryAllocationForBrowser browser_allocation;
-
-  enum BufferAllocation {
-    kHasNoFrontbuffer = 0,
-    kHasFrontbuffer = 1,
-  };
-
-  GpuMemoryAllocation() {
-  }
-
-  GpuMemoryAllocation(uint64 gpu_resource_size_in_bytes,
-                      BufferAllocation buffer_allocation)
-      : renderer_allocation(gpu_resource_size_in_bytes),
-        browser_allocation(buffer_allocation == kHasFrontbuffer) {
-  }
-
-  bool Equals(const GpuMemoryAllocation& other) const {
-      return renderer_allocation.Equals(other.renderer_allocation) &&
-          browser_allocation.Equals(other.browser_allocation);
-  }
-};
-
-// Memory Allocation request which is sent by a client, to help GpuMemoryManager
-// more ideally split memory allocations across clients.
-struct GpuManagedMemoryStats {
-  // Bytes required for correct rendering.
-  uint64 bytes_required;
-
-  // Bytes that are not strictly required for correctness, but, if allocated,
-  // will provide good performance.
-  uint64 bytes_nice_to_have;
-
-  // The number of bytes currently allocated.
-  uint64 bytes_allocated;
-
-  // Whether or not a backbuffer is currently requested (the memory usage
-  // of the buffer is known by the GPU process).
-  bool backbuffer_requested;
-
-  GpuManagedMemoryStats()
-      : bytes_required(0),
-        bytes_nice_to_have(0),
-        bytes_allocated(0),
-        backbuffer_requested(false) {
-  }
-
-  GpuManagedMemoryStats(uint64 bytes_required,
-                        uint64 bytes_nice_to_have,
-                        uint64 bytes_allocated,
-                        bool backbuffer_requested)
-      : bytes_required(bytes_required),
-        bytes_nice_to_have(bytes_nice_to_have),
-        bytes_allocated(bytes_allocated),
-        backbuffer_requested(backbuffer_requested) {
-  }
-
-  bool Equals(const GpuManagedMemoryStats& other) const {
-    return bytes_required == other.bytes_required &&
-        bytes_nice_to_have == other.bytes_nice_to_have &&
-        bytes_allocated == other.bytes_allocated &&
-        backbuffer_requested == other.backbuffer_requested;
-  }
-};
-
-}  // namespace content
-
-#endif // CONTENT_COMMON_GPU_GPU_MEMORY_ALLOCATION_H_
diff --git a/content/common/gpu/gpu_memory_manager.cc b/content/common/gpu/gpu_memory_manager.cc
index cb6b6c6..df9b24b 100644
--- a/content/common/gpu/gpu_memory_manager.cc
+++ b/content/common/gpu/gpu_memory_manager.cc
@@ -13,13 +13,16 @@
 #include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "content/common/gpu/gpu_channel_manager.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/common/gpu/gpu_memory_manager_client.h"
 #include "content/common/gpu/gpu_memory_tracking.h"
 #include "content/common/gpu/gpu_memory_uma_stats.h"
 #include "content/common/gpu/gpu_messages.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 
+using gpu::ManagedMemoryStats;
+using gpu::MemoryAllocation;
+
 namespace content {
 namespace {
 
@@ -337,7 +340,7 @@
 
 void GpuMemoryManager::SetClientStateManagedMemoryStats(
     GpuMemoryManagerClientState* client_state,
-    const GpuManagedMemoryStats& stats)
+    const ManagedMemoryStats& stats)
 {
   TrackValueChanged(client_state->managed_memory_stats_.bytes_allocated,
                     stats.bytes_allocated,
@@ -474,7 +477,7 @@
     uint64 bytes_above_required_cap,
     uint64 bytes_above_minimum_cap,
     uint64 bytes_overall_cap) {
-  GpuManagedMemoryStats* stats = &client_state->managed_memory_stats_;
+  ManagedMemoryStats* stats = &client_state->managed_memory_stats_;
 
   if (!client_state->managed_memory_stats_received_)
     return GetDefaultClientAllocation();
@@ -769,30 +772,28 @@
         3 * client_state->managed_memory_stats_.bytes_nice_to_have / 4;
 
     // Populate and send the allocation to the client
-    GpuMemoryAllocation allocation;
+    MemoryAllocation allocation;
 
-    allocation.browser_allocation.suggest_have_frontbuffer =
-        !client_state->hibernated_;
-
-    allocation.renderer_allocation.bytes_limit_when_visible =
+    allocation.bytes_limit_when_visible =
         client_state->bytes_allocation_when_visible_;
     // Use a more conservative memory allocation policy on Linux and Mac
     // because the platform is unstable when under memory pressure.
     // http://crbug.com/145600 (Linux)
     // http://crbug.com/141377 (Mac)
-    allocation.renderer_allocation.priority_cutoff_when_visible =
+    allocation.priority_cutoff_when_visible =
 #if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
-        GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNiceToHave;
+        MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
 #else
-        GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything;
+        MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
 #endif
 
-    allocation.renderer_allocation.bytes_limit_when_not_visible =
+    allocation.bytes_limit_when_not_visible =
         client_state->bytes_allocation_when_nonvisible_;
-    allocation.renderer_allocation.priority_cutoff_when_not_visible =
-        GpuMemoryAllocationForRenderer::kPriorityCutoffAllowOnlyRequired;
+    allocation.priority_cutoff_when_not_visible =
+        MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
 
     client_state->client_->SetMemoryAllocation(allocation);
+    client_state->client_->SuggestHaveFrontBuffer(!client_state->hibernated_);
   }
 }
 
@@ -801,13 +802,13 @@
        it != clients_nonsurface_.end();
        ++it) {
     GpuMemoryManagerClientState* client_state = *it;
-    GpuMemoryAllocation allocation;
+    MemoryAllocation allocation;
 
     if (!client_state->hibernated_) {
-      allocation.renderer_allocation.bytes_limit_when_visible =
+      allocation.bytes_limit_when_visible =
           GetMinimumClientAllocation();
-      allocation.renderer_allocation.priority_cutoff_when_visible =
-          GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything;
+      allocation.priority_cutoff_when_visible =
+          MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
     }
 
     client_state->client_->SetMemoryAllocation(allocation);
diff --git a/content/common/gpu/gpu_memory_manager.h b/content/common/gpu/gpu_memory_manager.h
index 9b2de82..3c9a223 100644
--- a/content/common/gpu/gpu_memory_manager.h
+++ b/content/common/gpu/gpu_memory_manager.h
@@ -14,8 +14,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/public/common/gpu_memory_stats.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 
 namespace content {
@@ -182,7 +182,7 @@
       GpuMemoryManagerClientState* client_state, bool visible);
   void SetClientStateManagedMemoryStats(
       GpuMemoryManagerClientState* client_state,
-      const GpuManagedMemoryStats& stats);
+      const gpu::ManagedMemoryStats& stats);
   void OnDestroyClientState(GpuMemoryManagerClientState* client);
 
   // Add or remove a client from its clients list (visible, nonvisible, or
diff --git a/content/common/gpu/gpu_memory_manager_client.cc b/content/common/gpu/gpu_memory_manager_client.cc
index 26fc95c..0ef3017 100644
--- a/content/common/gpu/gpu_memory_manager_client.cc
+++ b/content/common/gpu/gpu_memory_manager_client.cc
@@ -40,7 +40,7 @@
 }
 
 void GpuMemoryManagerClientState::SetManagedMemoryStats(
-    const GpuManagedMemoryStats& stats) {
+    const gpu::ManagedMemoryStats& stats) {
   memory_manager_->SetClientStateManagedMemoryStats(this, stats);
 }
 
diff --git a/content/common/gpu/gpu_memory_manager_client.h b/content/common/gpu/gpu_memory_manager_client.h
index 1579fb8..453e7a1 100644
--- a/content/common/gpu/gpu_memory_manager_client.h
+++ b/content/common/gpu/gpu_memory_manager_client.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "content/common/content_export.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "ui/gfx/size.h"
 
@@ -32,7 +32,9 @@
 
   // Sets buffer usage depending on Memory Allocation
   virtual void SetMemoryAllocation(
-      const GpuMemoryAllocation& allocation) = 0;
+      const gpu::MemoryAllocation& allocation) = 0;
+
+  virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) = 0;
 
   // Returns in bytes the total amount of GPU memory for the GPU which this
   // context is currently rendering on. Returns false if no extension exists
@@ -46,7 +48,7 @@
  public:
   ~GpuMemoryManagerClientState();
   void SetVisible(bool visible);
-  void SetManagedMemoryStats(const GpuManagedMemoryStats& stats);
+  void SetManagedMemoryStats(const gpu::ManagedMemoryStats& stats);
 
  private:
   friend class GpuMemoryManager;
@@ -80,7 +82,7 @@
   bool list_iterator_valid_;
 
   // Statistics about memory usage.
-  GpuManagedMemoryStats managed_memory_stats_;
+  gpu::ManagedMemoryStats managed_memory_stats_;
   bool managed_memory_stats_received_;
 
   // When managed_memory_stats_.bytes_nicetohave leaves the range
diff --git a/content/common/gpu/gpu_memory_manager_unittest.cc b/content/common/gpu/gpu_memory_manager_unittest.cc
index e008a47..ded1a28 100644
--- a/content/common/gpu/gpu_memory_manager_unittest.cc
+++ b/content/common/gpu/gpu_memory_manager_unittest.cc
@@ -2,14 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/common/gpu/gpu_memory_manager.h"
 #include "content/common/gpu/gpu_memory_manager_client.h"
 #include "content/common/gpu/gpu_memory_tracking.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "ui/gfx/size_conversions.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+using gpu::MemoryAllocation;
+using gpu::ManagedMemoryStats;
+
 #if defined(COMPILER_GCC)
 namespace BASE_HASH_NAMESPACE {
 template<>
@@ -43,7 +46,7 @@
 class ClientAssignmentCollector {
  public:
   struct ClientMemoryStat {
-    GpuMemoryAllocation allocation;
+    MemoryAllocation allocation;
   };
   typedef base::hash_map<GpuMemoryManagerClient*, ClientMemoryStat>
       ClientMemoryStatMap;
@@ -55,7 +58,7 @@
     client_memory_stats_for_last_manage_.clear();
   }
   static void AddClientStat(GpuMemoryManagerClient* client,
-                          const GpuMemoryAllocation& allocation) {
+                          const MemoryAllocation& allocation) {
     DCHECK(!client_memory_stats_for_last_manage_.count(client));
     client_memory_stats_for_last_manage_[client].allocation = allocation;
   }
@@ -70,7 +73,8 @@
 class FakeClient : public GpuMemoryManagerClient {
  public:
   GpuMemoryManager* memmgr_;
-  GpuMemoryAllocation allocation_;
+  bool suggest_have_frontbuffer_;
+  MemoryAllocation allocation_;
   uint64 total_gpu_memory_;
   gfx::Size surface_size_;
   GpuMemoryManagerClient* share_group_;
@@ -81,6 +85,7 @@
   // This will create a client with no surface
   FakeClient(GpuMemoryManager* memmgr, GpuMemoryManagerClient* share_group)
       : memmgr_(memmgr),
+        suggest_have_frontbuffer_(false),
         total_gpu_memory_(0),
         share_group_(share_group),
         memory_tracker_(NULL) {
@@ -95,6 +100,7 @@
   // This will create a client with a surface
   FakeClient(GpuMemoryManager* memmgr, int32 surface_id, bool visible)
       : memmgr_(memmgr),
+        suggest_have_frontbuffer_(false),
         total_gpu_memory_(0),
         share_group_(NULL),
         memory_tracker_(NULL) {
@@ -111,11 +117,15 @@
     memory_tracker_ = NULL;
   }
 
-  virtual void SetMemoryAllocation(const GpuMemoryAllocation& alloc) OVERRIDE {
+  virtual void SetMemoryAllocation(const MemoryAllocation& alloc) OVERRIDE {
     allocation_ = alloc;
     ClientAssignmentCollector::AddClientStat(this, alloc);
   }
 
+  virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE {
+    suggest_have_frontbuffer_ = suggest_have_frontbuffer;
+  }
+
   virtual bool GetTotalGpuMemory(uint64* bytes) OVERRIDE {
     if (total_gpu_memory_) {
       *bytes = total_gpu_memory_;
@@ -140,16 +150,16 @@
     client_state_->SetVisible(visible);
   }
 
-  void SetManagedMemoryStats(const GpuManagedMemoryStats& stats) {
+  void SetManagedMemoryStats(const ManagedMemoryStats& stats) {
     client_state_->SetManagedMemoryStats(stats);
   }
 
   uint64 BytesWhenVisible() const {
-    return allocation_.renderer_allocation.bytes_limit_when_visible;
+    return allocation_.bytes_limit_when_visible;
   }
 
   uint64 BytesWhenNotVisible() const {
-    return allocation_.renderer_allocation.bytes_limit_when_not_visible;
+    return allocation_.bytes_limit_when_not_visible;
   }
 };
 
@@ -172,39 +182,33 @@
   }
 
   bool IsAllocationForegroundForSurfaceYes(
-      const GpuMemoryAllocation& alloc) {
-    return alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible;
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible;
   }
   bool IsAllocationBackgroundForSurfaceYes(
-      const GpuMemoryAllocation& alloc) {
-    return alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible;
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible;
   }
   bool IsAllocationHibernatedForSurfaceYes(
-      const GpuMemoryAllocation& alloc) {
-    return !alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible;
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible;
   }
   bool IsAllocationForegroundForSurfaceNo(
-      const GpuMemoryAllocation& alloc) {
-    return !alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible &&
-           alloc.renderer_allocation.bytes_limit_when_visible ==
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible &&
+           alloc.bytes_limit_when_visible ==
                GetMinimumClientAllocation();
   }
   bool IsAllocationBackgroundForSurfaceNo(
-      const GpuMemoryAllocation& alloc) {
-    return !alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible &&
-           alloc.renderer_allocation.bytes_limit_when_visible ==
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible &&
+           alloc.bytes_limit_when_visible ==
                GetMinimumClientAllocation();
   }
   bool IsAllocationHibernatedForSurfaceNo(
-      const GpuMemoryAllocation& alloc) {
-    return !alloc.browser_allocation.suggest_have_frontbuffer &&
-           !alloc.renderer_allocation.have_backbuffer_when_not_visible &&
-           alloc.renderer_allocation.bytes_limit_when_visible == 0;
+      const MemoryAllocation& alloc) {
+    return !alloc.have_backbuffer_when_not_visible &&
+           alloc.bytes_limit_when_visible == 0;
   }
 
   void Manage() {
@@ -239,7 +243,7 @@
       uint64 required,
       uint64 nicetohave) {
     client->SetManagedMemoryStats(
-        GpuManagedMemoryStats(required, nicetohave, 0, false));
+        ManagedMemoryStats(required, nicetohave, 0, false));
   }
 
   GpuMemoryManager memmgr_;
@@ -474,51 +478,6 @@
   EXPECT_EQ(GetAvailableGpuMemory(), CalcAvailableClamped(bytes_expected));
 }
 
-
-// Test GpuMemoryAllocation comparison operators: Iterate over all possible
-// combinations of gpu_resource_size_in_bytes, suggest_have_backbuffer, and
-// suggest_have_frontbuffer, and make sure allocations with equal values test
-// equal and non equal values test not equal.
-TEST_F(GpuMemoryManagerTest, GpuMemoryAllocationCompareTests) {
-  std::vector<int> gpu_resource_size_in_bytes_values;
-  gpu_resource_size_in_bytes_values.push_back(0);
-  gpu_resource_size_in_bytes_values.push_back(1);
-  gpu_resource_size_in_bytes_values.push_back(12345678);
-
-  std::vector<GpuMemoryAllocation::BufferAllocation>
-      suggested_buffer_allocation_values;
-  suggested_buffer_allocation_values.push_back(
-      GpuMemoryAllocation::kHasFrontbuffer);
-  suggested_buffer_allocation_values.push_back(
-      GpuMemoryAllocation::kHasFrontbuffer);
-  suggested_buffer_allocation_values.push_back(
-      GpuMemoryAllocation::kHasNoFrontbuffer);
-  suggested_buffer_allocation_values.push_back(
-      GpuMemoryAllocation::kHasNoFrontbuffer);
-
-  for (size_t i = 0; i != gpu_resource_size_in_bytes_values.size(); ++i) {
-    for (size_t j = 0; j != suggested_buffer_allocation_values.size(); ++j) {
-      uint64 sz = gpu_resource_size_in_bytes_values[i];
-      GpuMemoryAllocation::BufferAllocation buffer_allocation =
-          suggested_buffer_allocation_values[j];
-      GpuMemoryAllocation allocation(sz, buffer_allocation);
-
-      EXPECT_TRUE(allocation.Equals(
-          GpuMemoryAllocation(sz, buffer_allocation)));
-      EXPECT_FALSE(allocation.Equals(
-          GpuMemoryAllocation(sz+1, buffer_allocation)));
-
-      for (size_t k = 0; k != suggested_buffer_allocation_values.size(); ++k) {
-        GpuMemoryAllocation::BufferAllocation buffer_allocation_other =
-            suggested_buffer_allocation_values[k];
-        if (buffer_allocation == buffer_allocation_other) continue;
-        EXPECT_FALSE(allocation.Equals(
-            GpuMemoryAllocation(sz, buffer_allocation_other)));
-      }
-    }
-  }
-}
-
 // Test GpuMemoryManager Stub Memory Stats functionality:
 // Creates various surface/non-surface stubs and switches stub visibility and
 // tests to see that stats data structure values are correct.
@@ -533,7 +492,7 @@
   Manage();
   stats = ClientAssignmentCollector::GetClientStatsForLastManage();
   uint64 stub1allocation1 =
-      stats[&stub1].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub1].allocation.bytes_limit_when_visible;
 
   EXPECT_EQ(stats.size(), 1ul);
   EXPECT_GT(stub1allocation1, 0ul);
@@ -543,10 +502,10 @@
   stats = ClientAssignmentCollector::GetClientStatsForLastManage();
   EXPECT_EQ(stats.count(&stub1), 1ul);
   uint64 stub1allocation2 =
-      stats[&stub1].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub1].allocation.bytes_limit_when_visible;
   EXPECT_EQ(stats.count(&stub2), 1ul);
   uint64 stub2allocation2 =
-      stats[&stub2].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub2].allocation.bytes_limit_when_visible;
 
   EXPECT_EQ(stats.size(), 2ul);
   EXPECT_GT(stub1allocation2, 0ul);
@@ -558,11 +517,11 @@
   Manage();
   stats = ClientAssignmentCollector::GetClientStatsForLastManage();
   uint64 stub1allocation3 =
-      stats[&stub1].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub1].allocation.bytes_limit_when_visible;
   uint64 stub2allocation3 =
-      stats[&stub2].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub2].allocation.bytes_limit_when_visible;
   uint64 stub3allocation3 =
-      stats[&stub3].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub3].allocation.bytes_limit_when_visible;
 
   EXPECT_EQ(stats.size(), 3ul);
   EXPECT_GT(stub1allocation3, 0ul);
@@ -576,11 +535,11 @@
   Manage();
   stats = ClientAssignmentCollector::GetClientStatsForLastManage();
   uint64 stub1allocation4 =
-      stats[&stub1].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub1].allocation.bytes_limit_when_visible;
   uint64 stub2allocation4 =
-      stats[&stub2].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub2].allocation.bytes_limit_when_visible;
   uint64 stub3allocation4 =
-      stats[&stub3].allocation.renderer_allocation.bytes_limit_when_visible;
+      stats[&stub3].allocation.bytes_limit_when_visible;
 
   EXPECT_EQ(stats.size(), 3ul);
   EXPECT_GT(stub1allocation4, 0ul);
@@ -598,8 +557,8 @@
   EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
   // Set memory allocations and verify the results are reflected.
-  stub1.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 5, false));
-  stub2.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 7, false));
+  stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 5, false));
+  stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 7, false));
   EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
@@ -612,7 +571,7 @@
   stub1.client_state_.reset(memmgr_.CreateClientState(&stub1, true, true));
   EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_);
-  stub1.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 5, false));
+  stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 5, false));
   EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
@@ -625,7 +584,7 @@
   stub2.client_state_.reset(memmgr_.CreateClientState(&stub2, true, false));
   EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_);
-  stub2.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 7, false));
+  stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 7, false));
   EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
@@ -633,8 +592,8 @@
   {
     FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true),
                stub4(&memmgr_, GenerateUniqueSurfaceId(), false);
-    stub3.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 1, false));
-    stub4.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 2, false));
+    stub3.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 1, false));
+    stub4.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 2, false));
     EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_visible_);
     EXPECT_EQ(9ul, memmgr_.bytes_allocated_managed_nonvisible_);
   }
@@ -654,14 +613,14 @@
   EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
   // Increase allocation amounts.
-  stub1.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 6, false));
-  stub2.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 8, false));
+  stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 6, false));
+  stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 8, false));
   EXPECT_EQ(8ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_nonvisible_);
 
   // Decrease allocation amounts.
-  stub1.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 4, false));
-  stub2.SetManagedMemoryStats(GpuManagedMemoryStats(0, 0, 6, false));
+  stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 4, false));
+  stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 6, false));
   EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_visible_);
   EXPECT_EQ(4ul, memmgr_.bytes_allocated_managed_nonvisible_);
 }
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 124815b..22f2a79 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -10,7 +10,6 @@
 
 #include "base/memory/shared_memory.h"
 #include "content/common/content_export.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
 #include "content/common/gpu/gpu_memory_uma_stats.h"
 #include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/gpu/gpu_rendering_stats.h"
@@ -18,6 +17,7 @@
 #include "content/public/common/gpu_memory_stats.h"
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/gpu_command_buffer_traits.h"
@@ -27,6 +27,7 @@
 #include "media/video/video_decode_accelerator.h"
 #include "media/video/video_encode_accelerator.h"
 #include "ui/events/latency_info.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/size.h"
 #include "ui/gl/gpu_preference.h"
@@ -182,16 +183,16 @@
   IPC_STRUCT_TRAITS_MEMBER(bytes_limit)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::GpuMemoryAllocationForRenderer)
+IPC_STRUCT_TRAITS_BEGIN(gpu::MemoryAllocation)
   IPC_STRUCT_TRAITS_MEMBER(bytes_limit_when_visible)
   IPC_STRUCT_TRAITS_MEMBER(priority_cutoff_when_visible)
   IPC_STRUCT_TRAITS_MEMBER(bytes_limit_when_not_visible)
   IPC_STRUCT_TRAITS_MEMBER(priority_cutoff_when_not_visible)
   IPC_STRUCT_TRAITS_MEMBER(have_backbuffer_when_not_visible)
 IPC_STRUCT_TRAITS_END()
-IPC_ENUM_TRAITS(content::GpuMemoryAllocationForRenderer::PriorityCutoff)
+IPC_ENUM_TRAITS(gpu::MemoryAllocation::PriorityCutoff)
 
-IPC_STRUCT_TRAITS_BEGIN(content::GpuManagedMemoryStats)
+IPC_STRUCT_TRAITS_BEGIN(gpu::ManagedMemoryStats)
   IPC_STRUCT_TRAITS_MEMBER(bytes_required)
   IPC_STRUCT_TRAITS_MEMBER(bytes_nice_to_have)
   IPC_STRUCT_TRAITS_MEMBER(bytes_allocated)
@@ -219,6 +220,7 @@
   IPC_STRUCT_TRAITS_MEMBER(total_texture_upload_time)
   IPC_STRUCT_TRAITS_MEMBER(global_total_processing_commands_time)
   IPC_STRUCT_TRAITS_MEMBER(total_processing_commands_time)
+  IPC_STRUCT_TRAITS_MEMBER(global_video_memory_bytes_allocated)
 IPC_STRUCT_TRAITS_END()
 
 IPC_ENUM_TRAITS(media::VideoFrame::Format)
@@ -548,7 +550,7 @@
 IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ConsoleMsg,
                     GPUCommandBufferConsoleMessage /* msg */)
 
-// Register an existing shared memory transfer buffer. Returns an id that can be
+// Register an existing shared memory transfer buffer. The id that can be
 // used to identify the transfer buffer from a command buffer.
 IPC_MESSAGE_ROUTED3(GpuCommandBufferMsg_RegisterTransferBuffer,
                     int32 /* id */,
@@ -594,13 +596,12 @@
 
 // Sent to proxy when the gpu memory manager changes its memory allocation.
 IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetMemoryAllocation,
-                    content::GpuMemoryAllocationForRenderer /* allocation */)
+                    gpu::MemoryAllocation /* allocation */)
 
 // Sent to stub from the proxy with statistics on managed memory usage and
 // requirements.
-IPC_MESSAGE_ROUTED1(
-    GpuCommandBufferMsg_SendClientManagedMemoryStats,
-    content::GpuManagedMemoryStats /* stats */)
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SendClientManagedMemoryStats,
+                    gpu::ManagedMemoryStats /* stats */)
 
 // Sent to stub when proxy is assigned a memory allocation changed callback.
 IPC_MESSAGE_ROUTED1(
@@ -637,6 +638,19 @@
                     uint32 /* query */,
                     uint32 /* signal_id */)
 
+// Register an existing gpu memory buffer. The id that can be
+// used to identify the gpu memory buffer from a command buffer.
+IPC_MESSAGE_ROUTED5(GpuCommandBufferMsg_RegisterGpuMemoryBuffer,
+                    int32 /* id */,
+                    gfx::GpuMemoryBufferHandle /* gpu_memory_buffer */,
+                    uint32 /* width */,
+                    uint32 /* height */,
+                    uint32 /* internalformat */)
+
+// Destroy a previously created gpu memory buffer.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyGpuMemoryBuffer,
+                    int32 /* id */)
+
 //------------------------------------------------------------------------------
 // Accelerated Video Decoder Messages
 // These messages are sent from Renderer process to GPU process.
diff --git a/content/common/gpu/gpu_rendering_stats.cc b/content/common/gpu/gpu_rendering_stats.cc
index 97a2435..88e54f0 100644
--- a/content/common/gpu/gpu_rendering_stats.cc
+++ b/content/common/gpu/gpu_rendering_stats.cc
@@ -8,7 +8,8 @@
 
 GpuRenderingStats::GpuRenderingStats()
     : global_texture_upload_count(0),
-      texture_upload_count(0) {
+      texture_upload_count(0),
+      global_video_memory_bytes_allocated(0) {
 }
 
 GpuRenderingStats::~GpuRenderingStats() {
@@ -27,6 +28,8 @@
       global_total_processing_commands_time);
   enumerator->AddTimeDeltaInSecondsF("totalProcessingCommandsTimeInSeconds",
                                      total_processing_commands_time);
+  enumerator->AddInt64("globalVideoMemoryBytesAllocated",
+                       global_video_memory_bytes_allocated);
 }
 
 }  // namespace content
diff --git a/content/common/gpu/gpu_rendering_stats.h b/content/common/gpu/gpu_rendering_stats.h
index f91e881..ab24853 100644
--- a/content/common/gpu/gpu_rendering_stats.h
+++ b/content/common/gpu/gpu_rendering_stats.h
@@ -21,6 +21,7 @@
   base::TimeDelta total_texture_upload_time;
   base::TimeDelta global_total_processing_commands_time;
   base::TimeDelta total_processing_commands_time;
+  int64 global_video_memory_bytes_allocated;
   // Note: when adding new members, please remember to update enumerateFields
   // in gpu_rendering_stats.cc.
 
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index b2cc9af..b7e9326 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
 #include "content/common/gpu/gpu_channel.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "media/base/bitstream_buffer.h"
@@ -59,8 +60,6 @@
       state_(NO_ERROR),
       surface_texture_id_(0),
       picturebuffers_requested_(false),
-      io_task_is_posted_(false),
-      decoder_met_eos_(false),
       gl_decoder_(decoder) {
 }
 
@@ -84,6 +83,10 @@
     return false;
   }
 
+  // Only consider using MediaCodec if it's likely backed by hardware.
+  if (media::VideoCodecBridge::IsKnownUnaccelerated(codec_))
+    return false;
+
   if (!make_context_current_.Run()) {
     LOG(ERROR) << "Failed to make this decoder's GL context current.";
     return false;
@@ -120,25 +123,12 @@
 }
 
 void AndroidVideoDecodeAccelerator::DoIOTask() {
-  io_task_is_posted_ = false;
   if (state_ == ERROR) {
     return;
   }
 
   QueueInput();
   DequeueOutput();
-
-  if (!pending_bitstream_buffers_.empty() ||
-      !free_picture_ids_.empty()) {
-    io_task_is_posted_ = true;
-    // TODO(dwkang): PostDelayedTask() does not guarantee the task will awake
-    //               at the exact time. Need a better way for polling.
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(
-            &AndroidVideoDecodeAccelerator::DoIOTask, base::AsWeakPtr(this)),
-            DecodePollDelay());
-  }
 }
 
 void AndroidVideoDecodeAccelerator::QueueInput() {
@@ -156,14 +146,18 @@
     return;
   }
 
+  base::Time queued_time = pending_bitstream_buffers_.front().second;
+  UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime",
+                      base::Time::Now() - queued_time);
   media::BitstreamBuffer& bitstream_buffer =
-      pending_bitstream_buffers_.front();
+      pending_bitstream_buffers_.front().first;
 
   if (bitstream_buffer.id() == -1) {
     media_codec_->QueueEOS(input_buf_index);
     pending_bitstream_buffers_.pop();
     return;
   }
+
   // Abuse the presentation time argument to propagate the bitstream
   // buffer ID to the output, so we can report it back to the client in
   // PictureReady().
@@ -185,7 +179,6 @@
   RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK,
                     "Failed to QueueInputBuffer: " << status,
                     PLATFORM_FAILURE);
-
   pending_bitstream_buffers_.pop();
 
   // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output
@@ -235,11 +228,11 @@
               &AndroidVideoDecodeAccelerator::RequestPictureBuffers,
               base::AsWeakPtr(this)));
         } else {
-          // TODO(dwkang): support the dynamic resolution change.
-          // Currently, we assume that there is no resolution change in the
-          // input stream. So, INFO_OUTPUT_FORMAT_CHANGED should not happen
-          // more than once. However, we allows it if resolution is the same
-          // as the previous one because |media_codec_| can be reset in Reset().
+          // Dynamic resolution change support is not specified by the Android
+          // platform at and before JB-MR1, so it's not possible to smoothly
+          // continue playback at this point.  Instead, error out immediately,
+          // expecting clients to Reset() as appropriate to avoid this.
+          // b/7093648
           RETURN_ON_FAILURE(size_ == gfx::Size(width, height),
                             "Dynamic resolution change is not supported.",
                             PLATFORM_FAILURE);
@@ -269,7 +262,6 @@
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &AndroidVideoDecodeAccelerator::NotifyFlushDone,
         base::AsWeakPtr(this)));
-    decoder_met_eos_ = true;
   } else {
     int64 bitstream_buffer_id = timestamp.InMicroseconds();
     SendCurrentSurfaceToClient(static_cast<int32>(bitstream_buffer_id));
@@ -352,40 +344,52 @@
     return;
   }
 
-  pending_bitstream_buffers_.push(bitstream_buffer);
+  pending_bitstream_buffers_.push(
+      std::make_pair(bitstream_buffer, base::Time::Now()));
 
-  if (!io_task_is_posted_)
-    DoIOTask();
+  DoIOTask();
 }
 
 void AndroidVideoDecodeAccelerator::AssignPictureBuffers(
     const std::vector<media::PictureBuffer>& buffers) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(output_picture_buffers_.empty());
+  DCHECK(free_picture_ids_.empty());
 
   for (size_t i = 0; i < buffers.size(); ++i) {
     RETURN_ON_FAILURE(buffers[i].size() == size_,
                       "Invalid picture buffer size was passed.",
                       INVALID_ARGUMENT);
-    output_picture_buffers_.insert(std::make_pair(buffers[i].id(), buffers[i]));
-    free_picture_ids_.push(buffers[i].id());
+    int32 id = buffers[i].id();
+    output_picture_buffers_.insert(std::make_pair(id, buffers[i]));
+    free_picture_ids_.push(id);
+    // Since the client might be re-using |picture_buffer_id| values, forget
+    // about previously-dismissed IDs now.  See ReusePictureBuffer() comment
+    // about "zombies" for why we maintain this set in the first place.
+    dismissed_picture_ids_.erase(id);
   }
 
   RETURN_ON_FAILURE(output_picture_buffers_.size() == kNumPictureBuffers,
                     "Invalid picture buffers were passed.",
                     INVALID_ARGUMENT);
 
-  if (!io_task_is_posted_)
-    DoIOTask();
+  DoIOTask();
 }
 
 void AndroidVideoDecodeAccelerator::ReusePictureBuffer(
     int32 picture_buffer_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  // This ReusePictureBuffer() might have been in a pipe somewhere (queued in
+  // IPC, or in a PostTask either at the sender or receiver) when we sent a
+  // DismissPictureBuffer() for this |picture_buffer_id|.  Account for such
+  // potential "zombie" IDs here.
+  if (dismissed_picture_ids_.erase(picture_buffer_id))
+    return;
+
   free_picture_ids_.push(picture_buffer_id);
 
-  if (!io_task_is_posted_)
-    DoIOTask();
+  DoIOTask();
 }
 
 void AndroidVideoDecodeAccelerator::Flush() {
@@ -408,6 +412,10 @@
            codec_, gfx::Size(320, 240), surface.j_surface().obj(), NULL)) {
     return false;
   }
+  io_timer_.Start(FROM_HERE,
+                  DecodePollDelay(),
+                  this,
+                  &AndroidVideoDecodeAccelerator::DoIOTask);
   return media_codec_->GetOutputBuffers();
 }
 
@@ -415,27 +423,36 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   while (!pending_bitstream_buffers_.empty()) {
-    media::BitstreamBuffer& bitstream_buffer =
-        pending_bitstream_buffers_.front();
+    int32 bitstream_buffer_id = pending_bitstream_buffers_.front().first.id();
     pending_bitstream_buffers_.pop();
 
-    if (bitstream_buffer.id() != -1) {
+    if (bitstream_buffer_id != -1) {
       base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
           &AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer,
-          base::AsWeakPtr(this), bitstream_buffer.id()));
+          base::AsWeakPtr(this), bitstream_buffer_id));
     }
   }
   bitstreams_notified_in_advance_.clear();
 
-  if (!decoder_met_eos_) {
-    media_codec_->Reset();
-  } else {
-    // MediaCodec should be usable after meeting EOS, but it is not on some
-    // devices. b/8125974 To avoid the case, we recreate a new one.
-    media_codec_->Stop();
-    ConfigureMediaCodec();
+  for (OutputBufferMap::iterator it = output_picture_buffers_.begin();
+       it != output_picture_buffers_.end();
+       ++it) {
+    client_->DismissPictureBuffer(it->first);
+    dismissed_picture_ids_.insert(it->first);
   }
-  decoder_met_eos_ = false;
+  output_picture_buffers_.clear();
+  std::queue<int32> empty;
+  std::swap(free_picture_ids_, empty);
+  CHECK(free_picture_ids_.empty());
+  picturebuffers_requested_ = false;
+
+  // On some devices, and up to at least JB-MR1,
+  // - flush() can fail after EOS (b/8125974); and
+  // - mid-stream resolution change is unsupported (b/7093648).
+  // To cope with these facts, we always stop & restart the codec on Reset().
+  io_timer_.Stop();
+  media_codec_->Stop();
+  ConfigureMediaCodec();
   state_ = NO_ERROR;
 
   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
@@ -445,8 +462,10 @@
 void AndroidVideoDecodeAccelerator::Destroy() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (media_codec_)
+  if (media_codec_) {
+    io_timer_.Stop();
     media_codec_->Stop();
+  }
   if (surface_texture_id_)
     glDeleteTextures(1, &surface_texture_id_);
   if (copier_)
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h
index 9354e5d..b2270a2 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_COMMON_GPU_MEDIA_ANDROID_VIDEO_DECODE_ACCELERATOR_H_
 #define CONTENT_COMMON_GPU_MEDIA_ANDROID_VIDEO_DECODE_ACCELERATOR_H_
 
-#include <dlfcn.h>
 #include <list>
 #include <map>
 #include <queue>
@@ -14,6 +13,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/media/video_decode_accelerator_impl.h"
 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
@@ -124,6 +124,11 @@
   // decoded frames to the client.
   std::queue<int32> free_picture_ids_;
 
+  // Picture buffer ids which have been dismissed and not yet re-assigned.  Used
+  // to ignore ReusePictureBuffer calls that were in flight when the
+  // DismissPictureBuffer call was made.
+  std::set<int32> dismissed_picture_ids_;
+
   // The low-level decoder which Android SDK provides.
   scoped_ptr<media::VideoCodecBridge> media_codec_;
 
@@ -136,19 +141,15 @@
   // Set to true after requesting picture buffers to the client.
   bool picturebuffers_requested_;
 
-  // Set to true when DoIOTask is in the message loop.
-  bool io_task_is_posted_;
-
-  // Set to true when decoder outputs EOS (end of stream).
-  bool decoder_met_eos_;
-
   // The resolution of the stream.
   gfx::Size size_;
 
   // Encoded bitstream buffers to be passed to media codec, queued until an
-  // input buffer is available.
-  typedef std::queue<media::BitstreamBuffer> BitstreamBufferList;
-  BitstreamBufferList pending_bitstream_buffers_;
+  // input buffer is available, along with the time when they were first
+  // enqueued.
+  typedef std::queue<std::pair<media::BitstreamBuffer, base::Time> >
+      PendingBitstreamBuffers;
+  PendingBitstreamBuffers pending_bitstream_buffers_;
 
   // Keeps track of bitstream ids notified to the client with
   // NotifyEndOfBitstreamBuffer() before getting output from the bitstream.
@@ -160,6 +161,9 @@
   // Used for copy the texture from |surface_texture_| to picture buffers.
   scoped_ptr<gpu::CopyTextureCHROMIUMResourceManager> copier_;
 
+  // Repeating timer responsible for draining pending IO to the codec.
+  base::RepeatingTimer<AndroidVideoDecodeAccelerator> io_timer_;
+
   friend class AndroidVideoDecodeAcceleratorTest;
 };
 
diff --git a/content/common/gpu/media/exynos_video_decode_accelerator.cc b/content/common/gpu/media/exynos_video_decode_accelerator.cc
index d184777..d6646d1 100644
--- a/content/common/gpu/media/exynos_video_decode_accelerator.cc
+++ b/content/common/gpu/media/exynos_video_decode_accelerator.cc
@@ -398,12 +398,10 @@
     return false;
 
   // MFC output format has to be setup before streaming starts.
-  // TODO(hshi): set format back to tiled (V4L2_PIX_FMT_NV12MT_16X16) when we
-  // fix the underlying driver/firmware issue. http://crbug.com/303300.
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-  format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
+  format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
   IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
 
   // Subscribe to the resolution change event.
@@ -2113,7 +2111,7 @@
   mfc_output_buffer_size_[0] = format.fmt.pix_mp.plane_fmt[0].sizeimage;
   mfc_output_buffer_size_[1] = format.fmt.pix_mp.plane_fmt[1].sizeimage;
   mfc_output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat;
-  DCHECK_EQ(mfc_output_buffer_pixelformat_, V4L2_PIX_FMT_NV12M);
+  DCHECK_EQ(mfc_output_buffer_pixelformat_, V4L2_PIX_FMT_NV12MT_16X16);
   DVLOG(3) << "CreateBuffersForFormat(): new resolution: "
            << frame_buffer_size_.ToString();
 
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc
index 4a67162..4c2ce95 100644
--- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -15,7 +15,6 @@
 //   infrastructure.
 
 #include <fcntl.h>
-#include <math.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <deque>
@@ -400,7 +399,6 @@
  public:
   // Doesn't take ownership of |rendering_helper| or |note|, which must outlive
   // |*this|.
-  // |num_fragments_per_decode| counts NALUs for h264 and frames for VP8.
   // |num_play_throughs| indicates how many times to play through the video.
   // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream
   // Reset() should be done after that frame number is delivered, or
@@ -419,7 +417,6 @@
                        int rendering_window_id,
                        ClientStateNotification<ClientState>* note,
                        const std::string& encoded_data,
-                       int num_fragments_per_decode,
                        int num_in_flight_decodes,
                        int num_play_throughs,
                        int reset_after_frame_num,
@@ -468,24 +465,23 @@
   void DeleteDecoder();
 
   // Compute & return the first encoded bytes (including a start frame) to send
-  // to the decoder, starting at |start_pos| and returning
-  // |num_fragments_per_decode| units. Skips to the first decodable position.
-  std::string GetBytesForFirstFragments(size_t start_pos, size_t* end_pos);
-  // Compute & return the next encoded bytes to send to the decoder (based on
-  // |start_pos| & |num_fragments_per_decode_|).
-  std::string GetBytesForNextFragments(size_t start_pos, size_t* end_pos);
-  // Helpers for GetRangeForNextFragments above.
+  // to the decoder, starting at |start_pos| and returning one fragment. Skips
+  // to the first decodable position.
+  std::string GetBytesForFirstFragment(size_t start_pos, size_t* end_pos);
+  // Compute & return the encoded bytes of next fragment to send to the decoder
+  // (based on |start_pos|).
+  std::string GetBytesForNextFragment(size_t start_pos, size_t* end_pos);
+  // Helpers for GetBytesForNextFragment above.
   void GetBytesForNextNALU(size_t start_pos, size_t* end_pos);  // For h.264.
-  std::string GetBytesForNextFrames(
+  std::string GetBytesForNextFrame(
       size_t start_pos, size_t* end_pos);  // For VP8.
 
-  // Request decode of the next batch of fragments in the encoded data.
-  void DecodeNextFragments();
+  // Request decode of the next fragment in the encoded data.
+  void DecodeNextFragment();
 
   RenderingHelper* rendering_helper_;
   int rendering_window_id_;
   std::string encoded_data_;
-  const int num_fragments_per_decode_;
   const int num_in_flight_decodes_;
   int outstanding_decodes_;
   size_t encoded_data_next_pos_to_decode_;
@@ -517,7 +513,6 @@
     int rendering_window_id,
     ClientStateNotification<ClientState>* note,
     const std::string& encoded_data,
-    int num_fragments_per_decode,
     int num_in_flight_decodes,
     int num_play_throughs,
     int reset_after_frame_num,
@@ -531,7 +526,6 @@
     : rendering_helper_(rendering_helper),
       rendering_window_id_(rendering_window_id),
       encoded_data_(encoded_data),
-      num_fragments_per_decode_(num_fragments_per_decode),
       num_in_flight_decodes_(num_in_flight_decodes),
       outstanding_decodes_(0),
       encoded_data_next_pos_to_decode_(0),
@@ -548,7 +542,6 @@
       profile_(profile),
       suppress_rendering_(suppress_rendering),
       delay_reuse_after_frame_num_(delay_reuse_after_frame_num) {
-  CHECK_GT(num_fragments_per_decode, 0);
   CHECK_GT(num_in_flight_decodes, 0);
   CHECK_GT(num_play_throughs, 0);
   CHECK_GE(rendering_fps, 0);
@@ -697,7 +690,7 @@
   }
 
   for (int i = 0; i < num_in_flight_decodes_; ++i)
-    DecodeNextFragments();
+    DecodeNextFragment();
   DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_);
 }
 
@@ -709,7 +702,7 @@
   // VaapiVideoDecodeAccelerator::FinishReset()).
   ++num_done_bitstream_buffers_;
   --outstanding_decodes_;
-  DecodeNextFragments();
+  DecodeNextFragment();
 }
 
 void GLRenderingVDAClient::NotifyFlushDone() {
@@ -730,12 +723,12 @@
 
   if (reset_after_frame_num_ == MID_STREAM_RESET) {
     reset_after_frame_num_ = END_OF_STREAM_RESET;
-    DecodeNextFragments();
+    DecodeNextFragment();
     return;
   } else if (reset_after_frame_num_ == START_OF_STREAM_RESET) {
     reset_after_frame_num_ = END_OF_STREAM_RESET;
     for (int i = 0; i < num_in_flight_decodes_; ++i)
-      DecodeNextFragments();
+      DecodeNextFragment();
     return;
   }
 
@@ -801,13 +794,13 @@
     SetState(static_cast<ClientState>(i));
 }
 
-std::string GLRenderingVDAClient::GetBytesForFirstFragments(
+std::string GLRenderingVDAClient::GetBytesForFirstFragment(
     size_t start_pos, size_t* end_pos) {
   if (profile_ < media::H264PROFILE_MAX) {
     *end_pos = start_pos;
     while (*end_pos + 4 < encoded_data_.size()) {
       if ((encoded_data_[*end_pos + 4] & 0x1f) == 0x7) // SPS start frame
-        return GetBytesForNextFragments(*end_pos, end_pos);
+        return GetBytesForNextFragment(*end_pos, end_pos);
       GetBytesForNextNALU(*end_pos, end_pos);
       num_skipped_fragments_++;
     }
@@ -815,25 +808,21 @@
     return std::string();
   }
   DCHECK_LE(profile_, media::VP8PROFILE_MAX);
-  return GetBytesForNextFragments(start_pos, end_pos);
+  return GetBytesForNextFragment(start_pos, end_pos);
 }
 
-std::string GLRenderingVDAClient::GetBytesForNextFragments(
+std::string GLRenderingVDAClient::GetBytesForNextFragment(
     size_t start_pos, size_t* end_pos) {
   if (profile_ < media::H264PROFILE_MAX) {
-    size_t new_end_pos = start_pos;
     *end_pos = start_pos;
-    for (int i = 0; i < num_fragments_per_decode_; ++i) {
-      GetBytesForNextNALU(*end_pos, &new_end_pos);
-      if (*end_pos == new_end_pos)
-        break;
-      *end_pos = new_end_pos;
+    GetBytesForNextNALU(*end_pos, end_pos);
+    if (start_pos != *end_pos) {
       num_queued_fragments_++;
     }
     return encoded_data_.substr(start_pos, *end_pos - start_pos);
   }
   DCHECK_LE(profile_, media::VP8PROFILE_MAX);
-  return GetBytesForNextFrames(start_pos, end_pos);
+  return GetBytesForNextFrame(start_pos, end_pos);
 }
 
 void GLRenderingVDAClient::GetBytesForNextNALU(
@@ -851,26 +840,22 @@
     *end_pos = encoded_data_.size();
 }
 
-std::string GLRenderingVDAClient::GetBytesForNextFrames(
+std::string GLRenderingVDAClient::GetBytesForNextFrame(
     size_t start_pos, size_t* end_pos) {
   // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
   std::string bytes;
   if (start_pos == 0)
     start_pos = 32;  // Skip IVF header.
   *end_pos = start_pos;
-  for (int i = 0; i < num_fragments_per_decode_; ++i) {
-    uint32 frame_size = *reinterpret_cast<uint32*>(&encoded_data_[*end_pos]);
-    *end_pos += 12;  // Skip frame header.
-    bytes.append(encoded_data_.substr(*end_pos, frame_size));
-    *end_pos += frame_size;
-    num_queued_fragments_++;
-    if (*end_pos + 12 >= encoded_data_.size())
-      return bytes;
-  }
+  uint32 frame_size = *reinterpret_cast<uint32*>(&encoded_data_[*end_pos]);
+  *end_pos += 12;  // Skip frame header.
+  bytes.append(encoded_data_.substr(*end_pos, frame_size));
+  *end_pos += frame_size;
+  num_queued_fragments_++;
   return bytes;
 }
 
-void GLRenderingVDAClient::DecodeNextFragments() {
+void GLRenderingVDAClient::DecodeNextFragment() {
   if (decoder_deleted())
     return;
   if (encoded_data_next_pos_to_decode_ == encoded_data_.size()) {
@@ -883,14 +868,14 @@
   size_t end_pos;
   std::string next_fragment_bytes;
   if (encoded_data_next_pos_to_decode_ == 0) {
-    next_fragment_bytes = GetBytesForFirstFragments(0, &end_pos);
+    next_fragment_bytes = GetBytesForFirstFragment(0, &end_pos);
   } else {
     next_fragment_bytes =
-        GetBytesForNextFragments(encoded_data_next_pos_to_decode_, &end_pos);
+        GetBytesForNextFragment(encoded_data_next_pos_to_decode_, &end_pos);
   }
   size_t next_fragment_size = next_fragment_bytes.size();
 
-  // Populate the shared memory buffer w/ the fragments, duplicate its handle,
+  // Populate the shared memory buffer w/ the fragment, duplicate its handle,
   // and hand it off to the decoder.
   base::SharedMemory shm;
   CHECK(shm.CreateAndMapAnonymous(next_fragment_size));
@@ -924,7 +909,6 @@
 }
 
 // Test parameters:
-// - Number of fragments per Decode() call.
 // - Number of concurrent decoders.
 // - Number of concurrent in-flight Decode() calls per decoder.
 // - Number of play-throughs.
@@ -934,16 +918,16 @@
 // - whether the video frames are rendered as thumbnails.
 class VideoDecodeAcceleratorTest
     : public ::testing::TestWithParam<
-  Tuple8<int, int, int, int, ResetPoint, ClientState, bool, bool> > {
+  Tuple7<int, int, int, ResetPoint, ClientState, bool, bool> > {
 };
 
 // Helper so that gtest failures emit a more readable version of the tuple than
 // its byte representation.
 ::std::ostream& operator<<(
     ::std::ostream& os,
-    const Tuple8<int, int, int, int, ResetPoint, ClientState, bool, bool>& t) {
+    const Tuple7<int, int, int, ResetPoint, ClientState, bool, bool>& t) {
   return os << t.a << ", " << t.b << ", " << t.c << ", " << t.d << ", " << t.e
-            << ", " << t.f << ", " << t.g << ", " << t.h;
+            << ", " << t.f << ", " << t.g;
 }
 
 // Wait for |note| to report a state and if it's not |expected_state| then
@@ -970,14 +954,13 @@
   // Required for Thread to work.  Not used otherwise.
   base::ShadowingAtExitManager at_exit_manager;
 
-  const int num_fragments_per_decode = GetParam().a;
-  const size_t num_concurrent_decoders = GetParam().b;
-  const size_t num_in_flight_decodes = GetParam().c;
-  const int num_play_throughs = GetParam().d;
-  const int reset_point = GetParam().e;
-  const int delete_decoder_state = GetParam().f;
-  bool test_reuse_delay = GetParam().g;
-  const bool render_as_thumbnails = GetParam().h;
+  const size_t num_concurrent_decoders = GetParam().a;
+  const size_t num_in_flight_decodes = GetParam().b;
+  const int num_play_throughs = GetParam().c;
+  const int reset_point = GetParam().d;
+  const int delete_decoder_state = GetParam().e;
+  bool test_reuse_delay = GetParam().f;
+  const bool render_as_thumbnails = GetParam().g;
 
   std::vector<TestVideoFile*> test_video_files;
   ParseAndReadTestVideoData(g_test_video_data,
@@ -986,10 +969,7 @@
                             &test_video_files);
 
   // Suppress GL rendering for all tests when the "--disable_rendering" is set.
-  // Otherwise, suppress rendering in all but a few tests, to cut down overall
-  // test runtime.
-  const bool suppress_rendering =
-      num_fragments_per_decode > 1 || g_disable_rendering;
+  const bool suppress_rendering = g_disable_rendering;
 
   std::vector<ClientStateNotification<ClientState>*>
       notes(num_concurrent_decoders, NULL);
@@ -1056,7 +1036,6 @@
                                  index,
                                  note,
                                  video_file->data_str,
-                                 num_fragments_per_decode,
                                  num_in_flight_decodes,
                                  num_play_throughs,
                                  video_file->reset_after_frame_num,
@@ -1136,8 +1115,7 @@
       EXPECT_EQ(video_file->num_fragments, client->num_skipped_fragments() +
                 client->num_queued_fragments());
       EXPECT_EQ(client->num_done_bitstream_buffers(),
-                ceil(static_cast<double>(client->num_queued_fragments()) /
-                     num_fragments_per_decode));
+                client->num_queued_fragments());
     }
     LOG(INFO) << "Decoder " << i << " fps: " << client->frames_per_second();
     if (!render_as_thumbnails) {
@@ -1230,7 +1208,7 @@
 INSTANTIATE_TEST_CASE_P(
     ReplayAfterEOS, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false)));
+        MakeTuple(1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false)));
 
 // This hangs on Exynos, preventing further testing and wasting test machine
 // time.
@@ -1240,7 +1218,7 @@
 INSTANTIATE_TEST_CASE_P(
     ResetBeforeDecode, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false)));
+        MakeTuple(1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false)));
 #endif  // ARCH_CPU_X86_FAMILY
 
 // Test that Reset() mid-stream works fine and doesn't affect decoding even when
@@ -1248,53 +1226,39 @@
 INSTANTIATE_TEST_CASE_P(
     MidStreamReset, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false)));
+        MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false)));
 
 INSTANTIATE_TEST_CASE_P(
     SlowRendering, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false)));
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false)));
 
 // Test that Destroy() mid-stream works fine (primarily this is testing that no
 // crashes occur).
 INSTANTIATE_TEST_CASE_P(
     TearDownTiming, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET, false,
-                  false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED, false,
-                  false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING, false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED, false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING, false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET,
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
                   static_cast<ClientState>(-1), false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET,
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
                   static_cast<ClientState>(-10), false, false),
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET,
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
                   static_cast<ClientState>(-100), false, false)));
 
-// Test that decoding various variation works: multiple fragments per Decode()
-// call and multiple in-flight decodes.
+// Test that decoding various variation works with multiple in-flight decodes.
 INSTANTIATE_TEST_CASE_P(
     DecodeVariations, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(1, 1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
+        MakeTuple(1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
         // Tests queuing.
-        MakeTuple(1, 1, 15, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(2, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(3, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(5, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(8, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
-        // TODO(fischman): decoding more than 15 NALUs at once breaks decode -
-        // visual artifacts are introduced as well as spurious frames are
-        // delivered (more pictures are returned than NALUs are fed to the
-        // decoder).  Increase the "15" below when
-        // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is
-        // fixed.
-        MakeTuple(15, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false)));
+        MakeTuple(1, 15, 1, END_OF_STREAM_RESET, CS_RESET, false, false)));
 
 // Find out how many concurrent decoders can go before we exhaust system
 // resources.
@@ -1302,16 +1266,16 @@
     ResourceExhaustion, VideoDecodeAcceleratorTest,
     ::testing::Values(
         // +0 hack below to promote enum to int.
-        MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1, 1,
+        MakeTuple(kMinSupportedNumConcurrentDecoders + 0, 1, 1,
                   END_OF_STREAM_RESET, CS_RESET, false, false),
-        MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1, 1,
+        MakeTuple(kMinSupportedNumConcurrentDecoders + 1, 1, 1,
                   END_OF_STREAM_RESET, CS_RESET, false, false)));
 
 // Thumbnailing test
 INSTANTIATE_TEST_CASE_P(
     Thumbnail, VideoDecodeAcceleratorTest,
     ::testing::Values(
-        MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true)));
+        MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true)));
 
 // TODO(fischman, vrk): add more tests!  In particular:
 // - Test life-cycle: Seek/Stop/Pause/Play for a single decoder.
diff --git a/content/common/input/synthetic_gesture_params.cc b/content/common/input/synthetic_gesture_params.cc
index a13ff1d..68ba38c 100644
--- a/content/common/input/synthetic_gesture_params.cc
+++ b/content/common/input/synthetic_gesture_params.cc
@@ -9,6 +9,10 @@
 SyntheticGestureParams::SyntheticGestureParams()
     : gesture_source_type(DEFAULT_INPUT) {}
 
+SyntheticGestureParams::SyntheticGestureParams(
+    const SyntheticGestureParams& other)
+    : gesture_source_type(other.gesture_source_type) {}
+
 SyntheticGestureParams::~SyntheticGestureParams() {}
 
 }  // namespace content
diff --git a/content/common/input/synthetic_gesture_params.h b/content/common/input/synthetic_gesture_params.h
index c553237..c3ce844 100644
--- a/content/common/input/synthetic_gesture_params.h
+++ b/content/common/input/synthetic_gesture_params.h
@@ -29,6 +29,10 @@
 //      correctly.
 // The details of each step should become clear when looking at other types.
 struct CONTENT_EXPORT SyntheticGestureParams {
+  SyntheticGestureParams();
+  SyntheticGestureParams(const SyntheticGestureParams& other);
+  virtual ~SyntheticGestureParams();
+
   // Describes which type of input events synthetic gesture objects should
   // generate. When specifying DEFAULT_INPUT the platform will be queried for
   // the preferred input event type.
@@ -38,10 +42,6 @@
     MOUSE_INPUT,
     GESTURE_SOURCE_TYPE_MAX = MOUSE_INPUT
   };
-
-  SyntheticGestureParams();
-  virtual ~SyntheticGestureParams();
-
   GestureSourceType gesture_source_type;
 
   enum GestureType {
diff --git a/content/common/input/synthetic_smooth_scroll_gesture_params.cc b/content/common/input/synthetic_smooth_scroll_gesture_params.cc
index 0d31987..9d50b76 100644
--- a/content/common/input/synthetic_smooth_scroll_gesture_params.cc
+++ b/content/common/input/synthetic_smooth_scroll_gesture_params.cc
@@ -13,6 +13,13 @@
 SyntheticSmoothScrollGestureParams::SyntheticSmoothScrollGestureParams()
     : distance(100), anchor_x(0), anchor_y(0) {}
 
+SyntheticSmoothScrollGestureParams::SyntheticSmoothScrollGestureParams(
+      const SyntheticSmoothScrollGestureParams& other)
+    : SyntheticGestureParams(other),
+      distance(other.distance),
+      anchor_x(other.anchor_x),
+      anchor_y(other.anchor_y) {}
+
 SyntheticSmoothScrollGestureParams::~SyntheticSmoothScrollGestureParams() {}
 
 SyntheticGestureParams::GestureType
diff --git a/content/common/input/synthetic_smooth_scroll_gesture_params.h b/content/common/input/synthetic_smooth_scroll_gesture_params.h
index a9a6f4a..5302371 100644
--- a/content/common/input/synthetic_smooth_scroll_gesture_params.h
+++ b/content/common/input/synthetic_smooth_scroll_gesture_params.h
@@ -15,6 +15,8 @@
     : public SyntheticGestureParams {
  public:
   SyntheticSmoothScrollGestureParams();
+  SyntheticSmoothScrollGestureParams(
+      const SyntheticSmoothScrollGestureParams& other);
   virtual ~SyntheticSmoothScrollGestureParams();
 
   virtual GestureType GetGestureType() const OVERRIDE;
diff --git a/content/common/java_bridge_messages.h b/content/common/java_bridge_messages.h
index 62923c7..7f2d8c1 100644
--- a/content/common/java_bridge_messages.h
+++ b/content/common/java_bridge_messages.h
@@ -16,9 +16,6 @@
 
 // Messages for handling Java objects injected into JavaScript -----------------
 
-// Sent from browser to renderer to initialize the Java Bridge.
-IPC_MESSAGE_ROUTED0(JavaBridgeMsg_Init)
-
 // Sent from browser to renderer to add a Java object with the given name.
 IPC_MESSAGE_ROUTED2(JavaBridgeMsg_AddNamedObject,
                     string16 /* name */,
diff --git a/content/common/media/media_param_traits.cc b/content/common/media/media_param_traits.cc
index 7c2bca4..18058d8 100644
--- a/content/common/media/media_param_traits.cc
+++ b/content/common/media/media_param_traits.cc
@@ -11,7 +11,7 @@
 
 using media::AudioParameters;
 using media::ChannelLayout;
-using media::VideoCaptureParams;
+using media::VideoCaptureFormat;
 using media::VideoCaptureSessionId;
 
 namespace IPC {
@@ -54,27 +54,24 @@
   l->append(base::StringPrintf("<AudioParameters>"));
 }
 
-void ParamTraits<VideoCaptureParams>::Write(Message* m,
-                                            const VideoCaptureParams& p) {
+void ParamTraits<VideoCaptureFormat>::Write(Message* m,
+                                            const VideoCaptureFormat& p) {
   m->WriteInt(p.width);
   m->WriteInt(p.height);
   m->WriteInt(p.frame_rate);
-  m->WriteInt(static_cast<int>(p.session_id));
   m->WriteInt(static_cast<int>(p.frame_size_type));
 }
 
-bool ParamTraits<VideoCaptureParams>::Read(const Message* m,
+bool ParamTraits<VideoCaptureFormat>::Read(const Message* m,
                                            PickleIterator* iter,
-                                           VideoCaptureParams* r) {
-  int session_id, frame_size_type;
+                                           VideoCaptureFormat* r) {
+  int frame_size_type;
   if (!m->ReadInt(iter, &r->width) ||
       !m->ReadInt(iter, &r->height) ||
       !m->ReadInt(iter, &r->frame_rate) ||
-      !m->ReadInt(iter, &session_id) ||
       !m->ReadInt(iter, &frame_size_type))
     return false;
 
-  r->session_id = static_cast<VideoCaptureSessionId>(session_id);
   r->frame_size_type =
       static_cast<media::VideoCaptureResolutionType>(
           frame_size_type);
@@ -83,9 +80,9 @@
   return true;
 }
 
-void ParamTraits<VideoCaptureParams>::Log(const VideoCaptureParams& p,
+void ParamTraits<VideoCaptureFormat>::Log(const VideoCaptureFormat& p,
                                           std::string* l) {
-  l->append(base::StringPrintf("<VideoCaptureParams>"));
+  l->append(base::StringPrintf("<VideoCaptureFormat>"));
 }
 
 }
diff --git a/content/common/media/media_param_traits.h b/content/common/media/media_param_traits.h
index f169619..94e2cd0 100644
--- a/content/common/media/media_param_traits.h
+++ b/content/common/media/media_param_traits.h
@@ -11,7 +11,7 @@
 
 namespace media {
 class AudioParameters;
-class VideoCaptureParams;
+class VideoCaptureFormat;
 }
 
 namespace IPC {
@@ -25,14 +25,13 @@
 };
 
 template <>
-struct CONTENT_EXPORT ParamTraits<media::VideoCaptureParams> {
-  typedef media::VideoCaptureParams param_type;
+struct CONTENT_EXPORT ParamTraits<media::VideoCaptureFormat> {
+  typedef media::VideoCaptureFormat param_type;
   static void Write(Message* m, const param_type& p);
   static bool Read(const Message* m, PickleIterator* iter, param_type* r);
   static void Log(const param_type& p, std::string* l);
 };
 
-
 } // namespace IPC
 
 #endif  // CONTENT_COMMON_MEDIA_MEDIA_PARAM_TRAITS_H_
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h
index 2229207..be13ecc 100644
--- a/content/common/media/media_player_messages_android.h
+++ b/content/common/media/media_player_messages_android.h
@@ -95,6 +95,18 @@
 // 1.1 Browser->Renderer MediaPlayerMsg_DemuxerSeekRequest
 // 1.2 Renderer->Browser MediaPlayerHostMsg_DemuxerSeekDone
 
+// Only in short-term hack to seek to reach I-Frame to feed a newly constructed
+// video decoder may the above IPC sequence be modified to exclude SeekRequest,
+// Seek and SeekCompleted, with condition that DemuxerSeekRequest's
+// |is_browser_seek| parameter be true. Regular seek messages must still be
+// handled even when a hack browser seek is in progress. In this case, the
+// browser seek request's |time_to_seek| may no longer be buffered and the
+// demuxer may instead seek to a future buffered time. The resulting
+// DemuxerSeekDone message's |actual_browser_seek_time| is the time actually
+// seeked-to, and is only meaningful for these hack browser seeks.
+// TODO(wolenetz): Instead of doing browser seek, replay cached data since last
+// keyframe. See http://crbug.com/304234.
+
 // Messages for notifying the render process of media playback status -------
 
 // Media buffering has updated.
@@ -161,9 +173,10 @@
                     int /* player_id */)
 
 // Requests renderer demuxer seek.
-IPC_MESSAGE_CONTROL2(MediaPlayerMsg_DemuxerSeekRequest,
+IPC_MESSAGE_CONTROL3(MediaPlayerMsg_DemuxerSeekRequest,
                      int /* demuxer_client_id */,
-                     base::TimeDelta /* time_to_seek */)
+                     base::TimeDelta /* time_to_seek */,
+                     bool /* is_browser_seek */)
 
 // The media source player reads data from demuxer
 IPC_MESSAGE_CONTROL2(MediaPlayerMsg_ReadFromDemuxer,
@@ -234,8 +247,9 @@
 IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_ExitFullscreen, int /* player_id */)
 
 // Sent after the renderer demuxer has seeked.
-IPC_MESSAGE_CONTROL1(MediaPlayerHostMsg_DemuxerSeekDone,
-                     int /* demuxer_client_id */)
+IPC_MESSAGE_CONTROL2(MediaPlayerHostMsg_DemuxerSeekDone,
+                     int /* demuxer_client_id */,
+                     base::TimeDelta /* actual_browser_seek_time */)
 
 // Inform the media source player that the demuxer is ready.
 IPC_MESSAGE_CONTROL2(MediaPlayerHostMsg_DemuxerReady,
diff --git a/content/common/media/midi_messages.h b/content/common/media/midi_messages.h
index bff0241..eced85d 100644
--- a/content/common/media/midi_messages.h
+++ b/content/common/media/midi_messages.h
@@ -30,6 +30,12 @@
                      int /* client id */,
                      GURL /* origin */)
 
+// Renderer request to browser for canceling a previous permission request.
+IPC_MESSAGE_CONTROL3(MIDIHostMsg_CancelSysExPermissionRequest,
+                     int /* render_view_id */,
+                     int /* bridge_id */,
+                     GURL /* GURL of the frame */)
+
 // Messages sent from the browser to the renderer.
 
 IPC_MESSAGE_ROUTED2(MIDIMsg_SysExPermissionApproved,
diff --git a/content/common/media/video_capture_messages.h b/content/common/media/video_capture_messages.h
index d1a0e24..50e6f9a 100644
--- a/content/common/media/video_capture_messages.h
+++ b/content/common/media/video_capture_messages.h
@@ -14,6 +14,16 @@
 #define IPC_MESSAGE_START VideoCaptureMsgStart
 
 IPC_ENUM_TRAITS(content::VideoCaptureState)
+IPC_ENUM_TRAITS_MAX_VALUE(media::VideoCaptureResolutionType,
+                          media::MaxVideoCaptureResolutionType - 1)
+
+IPC_STRUCT_TRAITS_BEGIN(media::VideoCaptureParams)
+  IPC_STRUCT_TRAITS_MEMBER(session_id)
+  IPC_STRUCT_TRAITS_MEMBER(requested_format)
+IPC_STRUCT_TRAITS_END()
+
+// TODO(nick): device_id in these messages is basically just a route_id. We
+// should shift to IPC_MESSAGE_ROUTED and use MessageRouter in the filter impls.
 
 // Notify the renderer process about the state update such as
 // Start/Pause/Stop.
@@ -28,27 +38,24 @@
                      int /* length */,
                      int /* buffer_id */)
 
+// Tell the renderer process that it should release a buffer previously
+// allocated by VideoCaptureMsg_NewBuffer.
+IPC_MESSAGE_CONTROL2(VideoCaptureMsg_FreeBuffer,
+                     int /* device id */,
+                     int /* buffer_id */)
+
 // Tell the renderer process that a buffer is available from video capture.
-IPC_MESSAGE_CONTROL3(VideoCaptureMsg_BufferReady,
+IPC_MESSAGE_CONTROL4(VideoCaptureMsg_BufferReady,
                      int /* device id */,
                      int /* buffer_id */,
-                     base::Time /* timestamp */)
+                     base::Time /* timestamp */,
+                     media::VideoCaptureFormat /* resolution */)
 
-// Tell the renderer process the width, height and frame rate the camera use.
-IPC_MESSAGE_CONTROL2(VideoCaptureMsg_DeviceInfo,
-                     int /* device_id */,
-                     media::VideoCaptureParams)
-
-// Tell the renderer process the newly changed width, height and frame rate
-// the video capture device will use.
-IPC_MESSAGE_CONTROL2(VideoCaptureMsg_DeviceInfoChanged,
-                     int /* device_id */,
-                     media::VideoCaptureParams)
-
-// Start the video capture specified by |device_id|.
+// Start a video capture as |device_id|, a new id picked by the renderer
+// process. The session to be started is determined by |params.session_id|.
 IPC_MESSAGE_CONTROL2(VideoCaptureHostMsg_Start,
                      int /* device_id */,
-                     media::VideoCaptureParams)
+                     media::VideoCaptureParams /* params */)
 
 // Pause the video capture specified by |device_id|.
 IPC_MESSAGE_CONTROL1(VideoCaptureHostMsg_Pause,
@@ -58,8 +65,8 @@
 IPC_MESSAGE_CONTROL1(VideoCaptureHostMsg_Stop,
                      int /* device_id */)
 
-// Tell the browser process that the video frame buffer |handle| is ready for
-// device |device_id| to fill up.
+// Tell the browser process that the renderer has finished reading from
+// a buffer previously delivered by VideoCaptureMsg_BufferReady.
 IPC_MESSAGE_CONTROL2(VideoCaptureHostMsg_BufferReady,
                      int /* device_id */,
                      int /* buffer_id */)
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index 0184677..e22cf41 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -58,7 +58,6 @@
   http_body->elements.push_back(element);
 }
 
-#ifdef USE_BLOB_UUIDS
 void AppendBlobToHttpBody(ExplodedHttpBody* http_body,
                           const std::string& uuid) {
   ExplodedHttpBodyElement element;
@@ -66,15 +65,6 @@
   element.blob_uuid = uuid;
   http_body->elements.push_back(element);
 }
-#else
-void DeprecatedAppendBlobToHttpBody(ExplodedHttpBody* http_body,
-                                    const GURL& url) {
-  ExplodedHttpBodyElement element;
-  element.type = WebKit::WebHTTPBody::Element::TypeBlob;
-  element.deprecated_blob_url = url;
-  http_body->elements.push_back(element);
-}
-#endif
 
 //----------------------------------------------------------------------------
 
@@ -202,15 +192,7 @@
 // See ReadPageState.
 //
 const int kMinVersion = 11;
-#ifdef USE_BLOB_UUIDS
-// This is not used yet, if a version bump is needed in advance of
-// this becoming used, bump both values by one and fixup the comment
-// and change the test for '16' in ReadHttpBody().
-// -- michaeln
 const int kCurrentVersion = 16;
-#else
-const int kCurrentVersion = 15;
-#endif
 
 // A bunch of convenience functions to read/write to SerializeObjects.  The
 // de-serializers assume the input data will be in the correct format and fall
@@ -444,11 +426,7 @@
       WriteReal(element.file_modification_time, obj);
     } else {
       DCHECK(element.type == WebKit::WebHTTPBody::Element::TypeBlob);
-#ifdef USE_BLOB_UUIDS
       WriteStdString(element.blob_uuid, obj);
-#else
-      WriteGURL(element.deprecated_blob_url, obj);
-#endif
     }
   }
   WriteInteger64(http_body.identifier, obj);
@@ -488,17 +466,12 @@
       AppendURLRangeToHttpBody(http_body, url, file_start, file_length,
                                file_modification_time);
     } else if (type == WebKit::WebHTTPBody::Element::TypeBlob) {
-#ifdef USE_BLOB_UUIDS
       if (obj->version >= 16) {
         std::string blob_uuid = ReadStdString(obj);
         AppendBlobToHttpBody(http_body, blob_uuid);
       } else {
         ReadGURL(obj); // Skip the obsolete blob url value.
       }
-#else
-      GURL blob_url = ReadGURL(obj);
-      DeprecatedAppendBlobToHttpBody(http_body, blob_url);
-#endif
     }
   }
   http_body->identifier = ReadInteger64(obj);
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index 7a3cb27..b46bc01 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -23,11 +23,7 @@
   int64 file_start;
   int64 file_length;
   double file_modification_time;
-#ifdef USE_BLOB_UUIDS
   std::string blob_uuid;
-#else
-  GURL deprecated_blob_url;
-#endif
 
   ExplodedHttpBodyElement();
   ~ExplodedHttpBodyElement();
diff --git a/content/common/page_state_serialization_unittest.cc b/content/common/page_state_serialization_unittest.cc
index 9138c15..d53300f 100644
--- a/content/common/page_state_serialization_unittest.cc
+++ b/content/common/page_state_serialization_unittest.cc
@@ -52,11 +52,7 @@
   EXPECT_EQ(a.file_length, b.file_length);
   if (!(isnan(a.file_modification_time) && isnan(b.file_modification_time)))
     EXPECT_DOUBLE_EQ(a.file_modification_time, b.file_modification_time);
-#ifdef USE_BLOB_UUIDS
   EXPECT_EQ(a.blob_uuid, b.blob_uuid);
-#else
-  EXPECT_EQ(a.deprecated_blob_url, b.deprecated_blob_url);
-#endif
 }
 
 template <>
diff --git a/content/common/pepper_plugin_list.cc b/content/common/pepper_plugin_list.cc
index a398ad2..ddb4af8 100644
--- a/content/common/pepper_plugin_list.cc
+++ b/content/common/pepper_plugin_list.cc
@@ -4,7 +4,9 @@
 
 #include "content/common/pepper_plugin_list.h"
 
+#include "base/basictypes.h"
 #include "base/command_line.h"
+#include "base/file_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -16,8 +18,23 @@
 namespace content {
 namespace {
 
+// The maximum number of plugins allowed to be registered from command line.
+const size_t kMaxPluginsToRegisterFromCommandLine = 64;
+
 // Appends any plugins from the command line to the given vector.
 void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
+  // On Linux, once we're sandboxed, we can't know if a plugin is available or
+  // not. But (on Linux) this function is always called once before we're
+  // sandboxed. So when this function is called for the first time we set a
+  // flag if the plugin file is available. Then we can skip the check on file
+  // existence in subsequent calls if the flag is set.
+  // NOTE: In theory we could have unlimited number of plugins registered in
+  // command line. But in practice, 64 plugins should be more than enough.
+  static uint64 skip_file_check_flags = 0;
+  COMPILE_ASSERT(
+      kMaxPluginsToRegisterFromCommandLine <= sizeof(skip_file_check_flags) * 8,
+      max_plugins_to_register_from_command_line_exceeds_limit);
+
   bool out_of_process = true;
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kPpapiInProcess))
     out_of_process = false;
@@ -36,7 +53,16 @@
   //    *1( LWS + ";" + LWS + <mime-type> )
   std::vector<std::string> modules;
   base::SplitString(value, ',', &modules);
-  for (size_t i = 0; i < modules.size(); ++i) {
+
+  size_t plugins_to_register = modules.size();
+  if (plugins_to_register > kMaxPluginsToRegisterFromCommandLine) {
+    DLOG(WARNING) << plugins_to_register << " pepper plugins registered from"
+        << " command line which exceeds the limit (maximum "
+        << kMaxPluginsToRegisterFromCommandLine << " plugins allowed)";
+    plugins_to_register = kMaxPluginsToRegisterFromCommandLine;
+  }
+
+  for (size_t i = 0; i < plugins_to_register; ++i) {
     std::vector<std::string> parts;
     base::SplitString(modules[i], ';', &parts);
     if (parts.size() < 2) {
@@ -57,6 +83,17 @@
 #else
     plugin.path = base::FilePath(name_parts[0]);
 #endif
+
+    uint64 index_mask = 1ULL << i;
+    if (!(skip_file_check_flags & index_mask)) {
+      if (base::PathExists(plugin.path)) {
+        skip_file_check_flags |= index_mask;
+      } else {
+        DLOG(ERROR) << "Plugin doesn't exist:" << plugin.path.MaybeAsASCII();
+        continue;
+      }
+    }
+
     if (name_parts.size() > 1)
       plugin.name = name_parts[1];
     if (name_parts.size() > 2)
diff --git a/content/common/plugin_list_win.cc b/content/common/plugin_list_win.cc
index 0e6c2f6..7d9706b 100644
--- a/content/common/plugin_list_win.cc
+++ b/content/common/plugin_list_win.cc
@@ -372,19 +372,28 @@
 bool PluginList::ShouldLoadPluginUsingPluginList(
     const WebPluginInfo& info,
     std::vector<WebPluginInfo>* plugins) {
-  // Version check
-  for (size_t j = 0; j < plugins->size(); ++j) {
-    base::FilePath::StringType plugin1 =
-        StringToLowerASCII((*plugins)[j].path.BaseName().value());
-    base::FilePath::StringType plugin2 =
-        StringToLowerASCII(info.path.BaseName().value());
-    if ((plugin1 == plugin2 && HaveSharedMimeType((*plugins)[j], info)) ||
-        (plugin1 == kJavaDeploy1 && plugin2 == kJavaDeploy2) ||
-        (plugin1 == kJavaDeploy2 && plugin2 == kJavaDeploy1)) {
-      if (IsNewerVersion(info.version, (*plugins)[j].version))
-        return false;  // We have loaded a plugin whose version is newer.
-      plugins->erase(plugins->begin() + j);
-      break;
+  bool should_check_version = true;
+  {
+    base::AutoLock lock(lock_);
+    should_check_version =
+        std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
+                  info.path) == extra_plugin_paths_.end();
+  }
+  // Version check for plugins that are not coming from |extra_plugin_paths_|.
+  if (should_check_version) {
+    for (size_t j = 0; j < plugins->size(); ++j) {
+      base::FilePath::StringType plugin1 =
+          StringToLowerASCII((*plugins)[j].path.BaseName().value());
+      base::FilePath::StringType plugin2 =
+          StringToLowerASCII(info.path.BaseName().value());
+      if ((plugin1 == plugin2 && HaveSharedMimeType((*plugins)[j], info)) ||
+          (plugin1 == kJavaDeploy1 && plugin2 == kJavaDeploy2) ||
+          (plugin1 == kJavaDeploy2 && plugin2 == kJavaDeploy1)) {
+        if (IsNewerVersion(info.version, (*plugins)[j].version))
+          return false;  // We have loaded a plugin whose version is newer.
+        plugins->erase(plugins->begin() + j);
+        break;
+      }
     }
   }
 
diff --git a/content/common/resource_messages.cc b/content/common/resource_messages.cc
index 72127b9..87f9e9f 100644
--- a/content/common/resource_messages.cc
+++ b/content/common/resource_messages.cc
@@ -59,7 +59,6 @@
     default: {
       DCHECK(p.type() == webkit_common::DataElement::TYPE_BLOB);
       WriteParam(m, p.blob_uuid());
-      WriteParam(m, p.blob_url());
       WriteParam(m, p.offset());
       WriteParam(m, p.length());
       break;
@@ -116,20 +115,14 @@
     default: {
       DCHECK(type == webkit_common::DataElement::TYPE_BLOB);
       std::string blob_uuid;
-      GURL blob_url;
       uint64 offset, length;
       if (!ReadParam(m, iter, &blob_uuid))
         return false;
-      if (!ReadParam(m, iter, &blob_url))
-        return false;
       if (!ReadParam(m, iter, &offset))
         return false;
       if (!ReadParam(m, iter, &length))
         return false;
-      if (!blob_uuid.empty())
-        r->SetToBlobRange(blob_uuid, offset, length);
-      else
-        r->SetToBlobUrlRange(blob_url, offset, length);
+      r->SetToBlobRange(blob_uuid, offset, length);
       break;
     }
   }
diff --git a/content/common/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_seccomp_bpf_linux.cc
index 57ba3ef..a3a1c54 100644
--- a/content/common/sandbox_seccomp_bpf_linux.cc
+++ b/content/common/sandbox_seccomp_bpf_linux.cc
@@ -1403,8 +1403,7 @@
 }
 #endif
 
-// TODO(jorgelo): using ENOENT here is a temporary fix. crbug.com/270326
-const int kFSDeniedErrno = ENOENT;
+const int kFSDeniedErrno = EPERM;
 
 ErrorCode BaselinePolicy(Sandbox* sandbox, int sysno) {
   if (IsBaselinePolicyAllowed(sysno)) {
@@ -1920,11 +1919,6 @@
     // Create a new broker process.
     InitGpuBrokerProcess(policy, broker_process);
 
-    // Preload the GL libraries. These are in the read whitelist but we have to
-    // preload them anyways to work around ld.so bugs. See crbug.com/268439.
-    dlopen(kLibGlesPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
-    dlopen(kLibEglPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
-
     // Preload the Tegra libraries.
     dlopen("/usr/lib/libnvrm.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
     dlopen("/usr/lib/libnvrm_graphics.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
@@ -1964,6 +1958,8 @@
   }
 
   if (process_type == switches::kUtilityProcess) {
+    // TODO(jorgelo): review sandbox initialization in utility_main.cc if we
+    // change this policy.
     return BlacklistDebugAndNumaPolicy;
   }
 
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index 1645548..e71cdaf 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -507,10 +507,8 @@
 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper.
 // Just have to figure out what needs to be warmed up first.
 void AddBaseHandleClosePolicy(sandbox::TargetPolicy* policy) {
-  // Being able to manipulate anything BaseNamedObjects is bad.
-  string16 object_path = PrependWindowsSessionPath(L"\\BaseNamedObjects");
-  policy->AddKernelObjectToClose(L"Directory", object_path.data());
-  object_path = PrependWindowsSessionPath(
+  // TODO(cpu): Add back the BaseNamedObjects policy.
+  string16 object_path = PrependWindowsSessionPath(
       L"\\BaseNamedObjects\\windows_shell_global_counters");
   policy->AddKernelObjectToClose(L"Section", object_path.data());
 }
diff --git a/content/common/service_worker_messages.h b/content/common/service_worker_messages.h
index 0f1dd4b..e426531 100644
--- a/content/common/service_worker_messages.h
+++ b/content/common/service_worker_messages.h
@@ -13,21 +13,26 @@
 
 // Messages sent from the child process to the browser.
 
-IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_RegisterServiceWorker,
-                     int32 /* callback_id */,
-                     string16 /* scope */,
+IPC_MESSAGE_CONTROL4(ServiceWorkerHostMsg_RegisterServiceWorker,
+                     int32 /* thread_id */,
+                     int32 /* request_id */,
+                     GURL /* scope */,
                      GURL /* script_url */)
 
-IPC_MESSAGE_CONTROL2(ServiceWorkerHostMsg_UnregisterServiceWorker,
-                     int32 /* callback_id */,
-                     string16 /* scope (url pattern) */)
+IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_UnregisterServiceWorker,
+                     int32 /* thread_id */,
+                     int32 /* request_id */,
+                     GURL /* scope (url pattern) */)
 
 // Messages sent from the browser to the child process.
 
 // Response to ServiceWorkerMsg_RegisterServiceWorker
-IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_ServiceWorkerRegistered,
-                     int32 /* callback_id */)
+IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_ServiceWorkerRegistered,
+                     int32 /* thread_id */,
+                     int32 /* request_id */,
+                     int64 /* service_worker_id */)
 
 // Response to ServiceWorkerMsg_UnregisterServiceWorker
-IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_ServiceWorkerUnregistered,
-                     int32 /* callback_id */)
+IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_ServiceWorkerUnregistered,
+                     int32 /* thread_id */,
+                     int32 /* request_id */)
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 3348bd9..356d33f 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -649,6 +649,10 @@
   // no referrer.
   IPC_STRUCT_MEMBER(content::Referrer, referrer)
 
+  // Any redirect URLs that occurred before |url|. Useful for cross-process
+  // navigations; defaults to empty.
+  IPC_STRUCT_MEMBER(std::vector<GURL>, redirects)
+
   // The type of transition.
   IPC_STRUCT_MEMBER(content::PageTransition, transition)
 
diff --git a/content/common/worker_messages.h b/content/common/worker_messages.h
index d66e456..04318d4 100644
--- a/content/common/worker_messages.h
+++ b/content/common/worker_messages.h
@@ -103,20 +103,6 @@
 // WorkerHost messages
 // These are messages sent from the worker process to the renderer process.
 // WorkerMsg_PostMessage is also sent here.
-IPC_MESSAGE_ROUTED3(WorkerHostMsg_PostExceptionToWorkerObject,
-                    string16  /* error_message */,
-                    int  /* line_number */,
-                    string16  /* source_url*/)
-
-IPC_MESSAGE_ROUTED1(WorkerHostMsg_PostConsoleMessageToWorkerObject,
-                    WorkerHostMsg_PostConsoleMessageToWorkerObject_Params)
-
-IPC_MESSAGE_ROUTED1(WorkerHostMsg_ConfirmMessageFromWorkerObject,
-                    bool /* bool has_pending_activity */)
-
-IPC_MESSAGE_ROUTED1(WorkerHostMsg_ReportPendingActivity,
-                    bool /* bool has_pending_activity */)
-
 IPC_MESSAGE_CONTROL1(WorkerHostMsg_WorkerContextClosed,
                      int /* worker_route_id */)
 IPC_MESSAGE_ROUTED0(WorkerHostMsg_WorkerContextDestroyed)
diff --git a/content/common_aidl.target.darwin-arm.mk b/content/common_aidl.target.darwin-arm.mk
index 8218a7f..4b9436a 100644
--- a/content/common_aidl.target.darwin-arm.mk
+++ b/content/common_aidl.target.darwin-arm.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/common_aidl.target.darwin-mips.mk b/content/common_aidl.target.darwin-mips.mk
index 9083217..72c8c88 100644
--- a/content/common_aidl.target.darwin-mips.mk
+++ b/content/common_aidl.target.darwin-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/common_aidl.target.darwin-x86.mk b/content/common_aidl.target.darwin-x86.mk
index be2767e..a81444b 100644
--- a/content/common_aidl.target.darwin-x86.mk
+++ b/content/common_aidl.target.darwin-x86.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/common_aidl.target.linux-arm.mk b/content/common_aidl.target.linux-arm.mk
index 8006fe6..3b8f52d 100644
--- a/content/common_aidl.target.linux-arm.mk
+++ b/content/common_aidl.target.linux-arm.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/common_aidl.target.linux-mips.mk b/content/common_aidl.target.linux-mips.mk
index 8dea08a..73f9076 100644
--- a/content/common_aidl.target.linux-mips.mk
+++ b/content/common_aidl.target.linux-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/common_aidl.target.linux-x86.mk b/content/common_aidl.target.linux-x86.mk
index e5f6fd5..c7b312a 100644
--- a/content/common_aidl.target.linux-x86.mk
+++ b/content/common_aidl.target.linux-x86.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.darwin-arm.mk b/content/content_app_both.target.darwin-arm.mk
index 6a75994..12e6dd2 100644
--- a/content/content_app_both.target.darwin-arm.mk
+++ b/content/content_app_both.target.darwin-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.darwin-mips.mk b/content/content_app_both.target.darwin-mips.mk
index c301966..7a48946 100644
--- a/content/content_app_both.target.darwin-mips.mk
+++ b/content/content_app_both.target.darwin-mips.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.darwin-x86.mk b/content/content_app_both.target.darwin-x86.mk
index d911ecf..6f25a62 100644
--- a/content/content_app_both.target.darwin-x86.mk
+++ b/content/content_app_both.target.darwin-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.linux-arm.mk b/content/content_app_both.target.linux-arm.mk
index 6a75994..12e6dd2 100644
--- a/content/content_app_both.target.linux-arm.mk
+++ b/content/content_app_both.target.linux-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.linux-mips.mk b/content/content_app_both.target.linux-mips.mk
index c301966..7a48946 100644
--- a/content/content_app_both.target.linux-mips.mk
+++ b/content/content_app_both.target.linux-mips.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_app_both.target.linux-x86.mk b/content/content_app_both.target.linux-x86.mk
index d911ecf..6f25a62 100644
--- a/content/content_app_both.target.linux-x86.mk
+++ b/content/content_app_both.target.linux-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 3bd337e..e9d7315 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -117,6 +117,8 @@
     'public/browser/load_notification_details.h',
     'public/browser/local_storage_usage_info.cc',
     'public/browser/local_storage_usage_info.h',
+    'public/browser/media_device_id.cc',
+    'public/browser/media_device_id.h',
     'public/browser/media_devices_monitor.h',
     'public/browser/native_web_keyboard_event.h',
     'public/browser/navigation_controller.cc',
@@ -147,8 +149,6 @@
     'public/browser/render_process_host.h',
     'public/browser/render_process_host_factory.h',
     'public/browser/render_view_host.h',
-    'public/browser/render_view_host_observer.cc',
-    'public/browser/render_view_host_observer.h',
     'public/browser/render_widget_host.h',
     'public/browser/render_widget_host_view.h',
     'public/browser/render_widget_host_view_mac_delegate.h',
@@ -308,6 +308,8 @@
     'browser/aura/resize_lock.h',
     'browser/aura/software_browser_compositor_output_surface.cc',
     'browser/aura/software_browser_compositor_output_surface.h',
+    'browser/aura/software_output_device_ozone.cc',
+    'browser/aura/software_output_device_ozone.h',
     'browser/aura/software_output_device_win.cc',
     'browser/aura/software_output_device_win.h',
     'browser/aura/software_output_device_x11.cc',
@@ -327,8 +329,6 @@
     'browser/browser_plugin/browser_plugin_geolocation_permission_context.h',
     'browser/browser_plugin/browser_plugin_guest.cc',
     'browser/browser_plugin/browser_plugin_guest.h',
-    'browser/browser_plugin/browser_plugin_guest_helper.cc',
-    'browser/browser_plugin/browser_plugin_guest_helper.h',
     'browser/browser_plugin/browser_plugin_guest_manager.cc',
     'browser/browser_plugin/browser_plugin_guest_manager.h',
     'browser/browser_plugin/browser_plugin_host_factory.h',
@@ -499,6 +499,27 @@
     'browser/fileapi/fileapi_message_filter.cc',
     'browser/fileapi/fileapi_message_filter.h',
     'browser/font_list_async.cc',
+    'browser/frame_host/debug_urls.cc',
+    'browser/frame_host/debug_urls.h',
+    'browser/frame_host/frame_tree.cc',
+    'browser/frame_host/frame_tree.h',
+    'browser/frame_host/frame_tree_node.cc',
+    'browser/frame_host/frame_tree_node.h',
+    'browser/frame_host/interstitial_page_impl.cc',
+    'browser/frame_host/interstitial_page_impl.h',
+    'browser/frame_host/navigation_controller_delegate.h',
+    'browser/frame_host/navigation_controller_impl.cc',
+    'browser/frame_host/navigation_controller_impl.h',
+    'browser/frame_host/navigation_entry_impl.cc',
+    'browser/frame_host/navigation_entry_impl.h',
+    'browser/frame_host/render_frame_host_impl.cc',
+    'browser/frame_host/render_frame_host_impl.h',
+    'browser/frame_host/render_frame_message_filter.cc',
+    'browser/frame_host/render_frame_message_filter.h',
+    'browser/frame_host/render_view_host_manager.cc',
+    'browser/frame_host/render_view_host_manager.h',
+    'browser/frame_host/web_contents_screenshot_manager.cc',
+    'browser/frame_host/web_contents_screenshot_manager.h',
     'browser/gamepad/gamepad_data_fetcher.h',
     'browser/gamepad/gamepad_platform_data_fetcher.h',
     'browser/gamepad/gamepad_platform_data_fetcher_linux.cc',
@@ -643,8 +664,6 @@
     'browser/loader/power_save_block_resource_throttle.h',
     'browser/loader/redirect_to_file_resource_handler.cc',
     'browser/loader/redirect_to_file_resource_handler.h',
-    'browser/loader/render_view_host_tracker.cc',
-    'browser/loader/render_view_host_tracker.h',
     'browser/loader/resource_buffer.cc',
     'browser/loader/resource_buffer.h',
     'browser/loader/resource_dispatcher_host_impl.cc',
@@ -783,16 +802,12 @@
     'browser/renderer_host/compositor_impl_android.h',
     'browser/renderer_host/database_message_filter.cc',
     'browser/renderer_host/database_message_filter.h',
+    'browser/renderer_host/delegated_frame_evictor.cc',
+    'browser/renderer_host/delegated_frame_evictor.h',
     'browser/renderer_host/dip_util.cc',
     'browser/renderer_host/dip_util.h',
     'browser/renderer_host/file_utilities_message_filter.cc',
     'browser/renderer_host/file_utilities_message_filter.h',
-    'browser/renderer_host/frame_memory_manager.cc',
-    'browser/renderer_host/frame_memory_manager.h',
-    'browser/renderer_host/frame_tree.cc',
-    'browser/renderer_host/frame_tree.h',
-    'browser/renderer_host/frame_tree_node.cc',
-    'browser/renderer_host/frame_tree_node.h',
     'browser/renderer_host/gamepad_browser_message_filter.cc',
     'browser/renderer_host/gamepad_browser_message_filter.h',
     'browser/renderer_host/gpu_message_filter.cc',
@@ -818,6 +833,15 @@
     'browser/renderer_host/input/input_ack_handler.h',
     'browser/renderer_host/input/input_router.h',
     'browser/renderer_host/input/input_router_client.h',
+    'browser/renderer_host/input/synthetic_gesture_controller_new.cc',
+    'browser/renderer_host/input/synthetic_gesture_controller_new.h',
+    'browser/renderer_host/input/synthetic_gesture_new.cc',
+    'browser/renderer_host/input/synthetic_gesture_new.h',
+    'browser/renderer_host/input/synthetic_gesture_target.h',
+    'browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc',
+    'browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.h',
+    'browser/renderer_host/input/synthetic_web_input_event_builders.cc',
+    'browser/renderer_host/input/synthetic_web_input_event_builders.h',
     'browser/renderer_host/input/tap_suppression_controller.cc',
     'browser/renderer_host/input/tap_suppression_controller.h',
     'browser/renderer_host/input/tap_suppression_controller_client.h',
@@ -965,10 +989,6 @@
     'browser/renderer_host/pepper/ssl_context_helper.h',
     'browser/renderer_host/popup_menu_helper_mac.h',
     'browser/renderer_host/popup_menu_helper_mac.mm',
-    'browser/renderer_host/render_frame_host_impl.cc',
-    'browser/renderer_host/render_frame_host_impl.h',
-    'browser/renderer_host/render_frame_message_filter.cc',
-    'browser/renderer_host/render_frame_message_filter.h',
     'browser/renderer_host/render_message_filter.cc',
     'browser/renderer_host/render_message_filter.h',
     'browser/renderer_host/render_process_host_impl.cc',
@@ -1005,6 +1025,10 @@
     'browser/renderer_host/render_widget_host_view_mac.mm',
     'browser/renderer_host/render_widget_host_view_win.cc',
     'browser/renderer_host/render_widget_host_view_win.h',
+    'browser/renderer_host/renderer_frame_manager.cc',
+    'browser/renderer_host/renderer_frame_manager.h',
+    'browser/renderer_host/software_frame_manager.cc',
+    'browser/renderer_host/software_frame_manager.h',
     'browser/renderer_host/synthetic_gesture_calculator.cc',
     'browser/renderer_host/synthetic_gesture_calculator.h',
     'browser/renderer_host/synthetic_gesture_controller.cc',
@@ -1129,26 +1153,14 @@
     'browser/web_contents/aura/shadow_layer_delegate.h',
     'browser/web_contents/aura/window_slider.cc',
     'browser/web_contents/aura/window_slider.h',
-    'browser/web_contents/debug_urls.cc',
-    'browser/web_contents/debug_urls.h',
     'browser/web_contents/drag_utils_gtk.cc',
     'browser/web_contents/drag_utils_gtk.h',
-    'browser/web_contents/interstitial_page_impl.cc',
-    'browser/web_contents/interstitial_page_impl.h',
-    'browser/web_contents/navigation_controller_impl.cc',
-    'browser/web_contents/navigation_controller_impl.h',
-    'browser/web_contents/navigation_entry_impl.cc',
-    'browser/web_contents/navigation_entry_impl.h',
-    'browser/web_contents/render_view_host_manager.cc',
-    'browser/web_contents/render_view_host_manager.h',
     'browser/web_contents/touch_editable_impl_aura.cc',
     'browser/web_contents/touch_editable_impl_aura.h',
     'browser/web_contents/web_contents_drag_win.cc',
     'browser/web_contents/web_contents_drag_win.h',
     'browser/web_contents/web_contents_impl.cc',
     'browser/web_contents/web_contents_impl.h',
-    'browser/web_contents/web_contents_screenshot_manager.cc',
-    'browser/web_contents/web_contents_screenshot_manager.h',
     'browser/web_contents/web_contents_view_android.cc',
     'browser/web_contents/web_contents_view_android.h',
     'browser/web_contents/web_contents_view_aura.cc',
diff --git a/content/content_browser.target.darwin-arm.mk b/content/content_browser.target.darwin-arm.mk
index 8765c43..d157145 100644
--- a/content/content_browser.target.darwin-arm.mk
+++ b/content/content_browser.target.darwin-arm.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -457,13 +461,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -587,13 +591,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.target.darwin-mips.mk b/content/content_browser.target.darwin-mips.mk
index f942811..c42774e 100644
--- a/content/content_browser.target.darwin-mips.mk
+++ b/content/content_browser.target.darwin-mips.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -456,13 +460,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -585,13 +589,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.target.darwin-x86.mk b/content/content_browser.target.darwin-x86.mk
index affc801..1c972d2 100644
--- a/content/content_browser.target.darwin-x86.mk
+++ b/content/content_browser.target.darwin-x86.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -459,13 +463,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -591,13 +595,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.target.linux-arm.mk b/content/content_browser.target.linux-arm.mk
index 8765c43..d157145 100644
--- a/content/content_browser.target.linux-arm.mk
+++ b/content/content_browser.target.linux-arm.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -457,13 +461,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -587,13 +591,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.target.linux-mips.mk b/content/content_browser.target.linux-mips.mk
index f942811..c42774e 100644
--- a/content/content_browser.target.linux-mips.mk
+++ b/content/content_browser.target.linux-mips.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -456,13 +460,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -585,13 +589,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browser.target.linux-x86.mk b/content/content_browser.target.linux-x86.mk
index affc801..1c972d2 100644
--- a/content/content_browser.target.linux-x86.mk
+++ b/content/content_browser.target.linux-x86.mk
@@ -59,11 +59,11 @@
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
 	content/public/browser/local_storage_usage_info.cc \
+	content/public/browser/media_device_id.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
 	content/public/browser/page_navigator.cc \
-	content/public/browser/render_view_host_observer.cc \
 	content/public/browser/resource_dispatcher_host_delegate.cc \
 	content/public/browser/resource_request_details.cc \
 	content/public/browser/speech_recognition_session_config.cc \
@@ -116,7 +116,6 @@
 	content/browser/browser_plugin/browser_plugin_embedder.cc \
 	content/browser/browser_plugin/browser_plugin_geolocation_permission_context.cc \
 	content/browser/browser_plugin/browser_plugin_guest.cc \
-	content/browser/browser_plugin/browser_plugin_guest_helper.cc \
 	content/browser/browser_plugin/browser_plugin_guest_manager.cc \
 	content/browser/browser_plugin/browser_plugin_message_filter.cc \
 	content/browser/browser_process_sub_thread.cc \
@@ -191,6 +190,16 @@
 	content/browser/fileapi/browser_file_system_helper.cc \
 	content/browser/fileapi/chrome_blob_storage_context.cc \
 	content/browser/fileapi/fileapi_message_filter.cc \
+	content/browser/frame_host/debug_urls.cc \
+	content/browser/frame_host/frame_tree.cc \
+	content/browser/frame_host/frame_tree_node.cc \
+	content/browser/frame_host/interstitial_page_impl.cc \
+	content/browser/frame_host/navigation_controller_impl.cc \
+	content/browser/frame_host/navigation_entry_impl.cc \
+	content/browser/frame_host/render_frame_host_impl.cc \
+	content/browser/frame_host/render_frame_message_filter.cc \
+	content/browser/frame_host/render_view_host_manager.cc \
+	content/browser/frame_host/web_contents_screenshot_manager.cc \
 	content/browser/gamepad/gamepad_provider.cc \
 	content/browser/gamepad/gamepad_service.cc \
 	content/browser/geolocation/empty_wifi_data_provider.cc \
@@ -243,7 +252,6 @@
 	content/browser/loader/offline_policy.cc \
 	content/browser/loader/power_save_block_resource_throttle.cc \
 	content/browser/loader/redirect_to_file_resource_handler.cc \
-	content/browser/loader/render_view_host_tracker.cc \
 	content/browser/loader/resource_buffer.cc \
 	content/browser/loader/resource_dispatcher_host_impl.cc \
 	content/browser/loader/resource_handler.cc \
@@ -293,17 +301,19 @@
 	content/browser/renderer_host/clipboard_message_filter.cc \
 	content/browser/renderer_host/compositor_impl_android.cc \
 	content/browser/renderer_host/database_message_filter.cc \
+	content/browser/renderer_host/delegated_frame_evictor.cc \
 	content/browser/renderer_host/dip_util.cc \
 	content/browser/renderer_host/file_utilities_message_filter.cc \
-	content/browser/renderer_host/frame_memory_manager.cc \
-	content/browser/renderer_host/frame_tree.cc \
-	content/browser/renderer_host/frame_tree_node.cc \
 	content/browser/renderer_host/gamepad_browser_message_filter.cc \
 	content/browser/renderer_host/gpu_message_filter.cc \
 	content/browser/renderer_host/image_transport_factory_android.cc \
 	content/browser/renderer_host/ime_adapter_android.cc \
 	content/browser/renderer_host/input/gesture_event_filter.cc \
 	content/browser/renderer_host/input/immediate_input_router.cc \
+	content/browser/renderer_host/input/synthetic_gesture_controller_new.cc \
+	content/browser/renderer_host/input/synthetic_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_smooth_scroll_gesture_new.cc \
+	content/browser/renderer_host/input/synthetic_web_input_event_builders.cc \
 	content/browser/renderer_host/input/touch_event_queue.cc \
 	content/browser/renderer_host/input/touchpad_tap_suppression_controller.cc \
 	content/browser/renderer_host/input/touchscreen_tap_suppression_controller_stub.cc \
@@ -343,8 +353,6 @@
 	content/browser/renderer_host/native_web_keyboard_event_android.cc \
 	content/browser/renderer_host/overscroll_configuration.cc \
 	content/browser/renderer_host/overscroll_controller.cc \
-	content/browser/renderer_host/render_frame_host_impl.cc \
-	content/browser/renderer_host/render_frame_message_filter.cc \
 	content/browser/renderer_host/render_message_filter.cc \
 	content/browser/renderer_host/render_process_host_impl.cc \
 	content/browser/renderer_host/render_view_host_delegate.cc \
@@ -356,6 +364,8 @@
 	content/browser/renderer_host/render_widget_host_view_android.cc \
 	content/browser/renderer_host/render_widget_host_view_base.cc \
 	content/browser/renderer_host/render_widget_host_view_guest.cc \
+	content/browser/renderer_host/renderer_frame_manager.cc \
+	content/browser/renderer_host/software_frame_manager.cc \
 	content/browser/renderer_host/synthetic_gesture_calculator.cc \
 	content/browser/renderer_host/synthetic_gesture_controller.cc \
 	content/browser/renderer_host/socket_stream_dispatcher_host.cc \
@@ -392,13 +402,7 @@
 	content/browser/tracing/tracing_controller_impl.cc \
 	content/browser/user_metrics.cc \
 	content/browser/utility_process_host_impl.cc \
-	content/browser/web_contents/debug_urls.cc \
-	content/browser/web_contents/interstitial_page_impl.cc \
-	content/browser/web_contents/navigation_controller_impl.cc \
-	content/browser/web_contents/navigation_entry_impl.cc \
-	content/browser/web_contents/render_view_host_manager.cc \
 	content/browser/web_contents/web_contents_impl.cc \
-	content/browser/web_contents/web_contents_screenshot_manager.cc \
 	content/browser/web_contents/web_contents_view_android.cc \
 	content/browser/web_contents/web_contents_view_guest.cc \
 	content/browser/webui/content_web_ui_controller_factory.cc \
@@ -459,13 +463,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -591,13 +595,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_browsertests.isolate b/content/content_browsertests.isolate
index 7312750..975c39e 100644
--- a/content/content_browsertests.isolate
+++ b/content/content_browsertests.isolate
@@ -26,7 +26,6 @@
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_tracked': [
@@ -76,7 +75,6 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
         ],
       },
diff --git a/content/content_child.gypi b/content/content_child.gypi
index 3fb005c..59bd64e 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -64,6 +64,14 @@
     'child/indexed_db/proxy_webidbdatabase_impl.h',
     'child/indexed_db/proxy_webidbfactory_impl.cc',
     'child/indexed_db/proxy_webidbfactory_impl.h',
+    'child/service_worker/service_worker_dispatcher.cc',
+    'child/service_worker/service_worker_dispatcher.h',
+    'child/service_worker/service_worker_message_filter.cc',
+    'child/service_worker/service_worker_message_filter.h',
+    'child/service_worker/web_service_worker_impl.cc',
+    'child/service_worker/web_service_worker_impl.h',
+    'child/service_worker/web_service_worker_provider_impl.cc',
+    'child/service_worker/web_service_worker_provider_impl.h',
     'child/npapi/np_channel_base.cc',
     'child/npapi/np_channel_base.h',
     'child/npapi/npobject_base.h',
diff --git a/content/content_child.target.darwin-arm.mk b/content/content_child.target.darwin-arm.mk
index aa1edb0..923ea64 100644
--- a/content/content_child.target.darwin-arm.mk
+++ b/content/content_child.target.darwin-arm.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -114,13 +118,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -227,13 +231,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_child.target.darwin-mips.mk b/content/content_child.target.darwin-mips.mk
index f7f0d2b..8207df5 100644
--- a/content/content_child.target.darwin-mips.mk
+++ b/content/content_child.target.darwin-mips.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -113,13 +117,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -225,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_child.target.darwin-x86.mk b/content/content_child.target.darwin-x86.mk
index 155f2d5..c735099 100644
--- a/content/content_child.target.darwin-x86.mk
+++ b/content/content_child.target.darwin-x86.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -116,13 +120,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -231,13 +235,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_child.target.linux-arm.mk b/content/content_child.target.linux-arm.mk
index aa1edb0..923ea64 100644
--- a/content/content_child.target.linux-arm.mk
+++ b/content/content_child.target.linux-arm.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -114,13 +118,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -227,13 +231,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_child.target.linux-mips.mk b/content/content_child.target.linux-mips.mk
index f7f0d2b..8207df5 100644
--- a/content/content_child.target.linux-mips.mk
+++ b/content/content_child.target.linux-mips.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -113,13 +117,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -225,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_child.target.linux-x86.mk b/content/content_child.target.linux-x86.mk
index 155f2d5..c735099 100644
--- a/content/content_child.target.linux-x86.mk
+++ b/content/content_child.target.linux-x86.mk
@@ -52,6 +52,10 @@
 	content/child/indexed_db/proxy_webidbcursor_impl.cc \
 	content/child/indexed_db/proxy_webidbdatabase_impl.cc \
 	content/child/indexed_db/proxy_webidbfactory_impl.cc \
+	content/child/service_worker/service_worker_dispatcher.cc \
+	content/child/service_worker/service_worker_message_filter.cc \
+	content/child/service_worker/web_service_worker_impl.cc \
+	content/child/service_worker/web_service_worker_provider_impl.cc \
 	content/child/npapi/np_channel_base.cc \
 	content/child/npapi/npobject_proxy.cc \
 	content/child/npapi/npobject_stub.cc \
@@ -116,13 +120,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -231,13 +235,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 18edca3..a021c94 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -10,7 +10,7 @@
     '../skia/skia.gyp:skia',
     '../third_party/icu/icu.gyp:icuuc',
     '../ui/gfx/gfx.gyp:gfx',
-    '../ui/ui.gyp:shell_dialogs',
+    '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
     '../ui/ui.gyp:ui',
     '../url/url.gyp:url_lib',
     '../webkit/common/user_agent/webkit_user_agent.gyp:user_agent',
@@ -190,6 +190,8 @@
     'common/gpu/client/gl_helper_scaling.h',
     'common/gpu/client/gpu_channel_host.cc',
     'common/gpu/client/gpu_channel_host.h',
+    'common/gpu/client/gpu_memory_buffer_impl.cc',
+    'common/gpu/client/gpu_memory_buffer_impl.h',
     'common/gpu/client/gpu_video_decode_accelerator_host.cc',
     'common/gpu/client/gpu_video_decode_accelerator_host.h',
     'common/gpu/client/gpu_video_encode_accelerator_host.cc',
@@ -203,7 +205,6 @@
     'common/gpu/gpu_command_buffer_stub.cc',
     'common/gpu/gpu_command_buffer_stub.h',
     'common/gpu/gpu_config.h',
-    'common/gpu/gpu_memory_allocation.h',
     'common/gpu/gpu_memory_manager.cc',
     'common/gpu/gpu_memory_manager.h',
     'common/gpu/gpu_memory_manager_client.cc',
diff --git a/content/content_common.target.darwin-arm.mk b/content/content_common.target.darwin-arm.mk
index ced2d98..31d22af 100644
--- a/content/content_common.target.darwin-arm.mk
+++ b/content/content_common.target.darwin-arm.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -181,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -296,13 +297,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.target.darwin-mips.mk b/content/content_common.target.darwin-mips.mk
index 26fb862..5b3e691 100644
--- a/content/content_common.target.darwin-mips.mk
+++ b/content/content_common.target.darwin-mips.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -180,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -294,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.target.darwin-x86.mk b/content/content_common.target.darwin-x86.mk
index 7fe9802..e375d52 100644
--- a/content/content_common.target.darwin-x86.mk
+++ b/content/content_common.target.darwin-x86.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -183,13 +184,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -300,13 +301,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.target.linux-arm.mk b/content/content_common.target.linux-arm.mk
index ced2d98..31d22af 100644
--- a/content/content_common.target.linux-arm.mk
+++ b/content/content_common.target.linux-arm.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -181,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -296,13 +297,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.target.linux-mips.mk b/content/content_common.target.linux-mips.mk
index 26fb862..5b3e691 100644
--- a/content/content_common.target.linux-mips.mk
+++ b/content/content_common.target.linux-mips.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -180,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -294,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_common.target.linux-x86.mk b/content/content_common.target.linux-x86.mk
index 7fe9802..e375d52 100644
--- a/content/content_common.target.linux-x86.mk
+++ b/content/content_common.target.linux-x86.mk
@@ -83,6 +83,7 @@
 	content/common/gpu/client/gl_helper.cc \
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.cc \
+	content/common/gpu/client/gpu_memory_buffer_impl.cc \
 	content/common/gpu/client/gpu_video_decode_accelerator_host.cc \
 	content/common/gpu/client/gpu_video_encode_accelerator_host.cc \
 	content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc \
@@ -183,13 +184,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -300,13 +301,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.darwin-arm.mk b/content/content_gpu.target.darwin-arm.mk
index c729d93..c30b833 100644
--- a/content/content_gpu.target.darwin-arm.mk
+++ b/content/content_gpu.target.darwin-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.darwin-mips.mk b/content/content_gpu.target.darwin-mips.mk
index 2b10ebb..fa3e7af 100644
--- a/content/content_gpu.target.darwin-mips.mk
+++ b/content/content_gpu.target.darwin-mips.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.darwin-x86.mk b/content/content_gpu.target.darwin-x86.mk
index a27b49f..a0a17da 100644
--- a/content/content_gpu.target.darwin-x86.mk
+++ b/content/content_gpu.target.darwin-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.linux-arm.mk b/content/content_gpu.target.linux-arm.mk
index c729d93..c30b833 100644
--- a/content/content_gpu.target.linux-arm.mk
+++ b/content/content_gpu.target.linux-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.linux-mips.mk b/content/content_gpu.target.linux-mips.mk
index 2b10ebb..fa3e7af 100644
--- a/content/content_gpu.target.linux-mips.mk
+++ b/content/content_gpu.target.linux-mips.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_gpu.target.linux-x86.mk b/content/content_gpu.target.linux-x86.mk
index a27b49f..a0a17da 100644
--- a/content/content_gpu.target.linux-x86.mk
+++ b/content/content_gpu.target.linux-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.darwin-arm.mk b/content/content_jni_headers.target.darwin-arm.mk
index c2211f8..b7961f8 100644
--- a/content/content_jni_headers.target.darwin-arm.mk
+++ b/content/content_jni_headers.target.darwin-arm.mk
@@ -430,13 +430,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -509,13 +509,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.darwin-mips.mk b/content/content_jni_headers.target.darwin-mips.mk
index b58d601..722d926 100644
--- a/content/content_jni_headers.target.darwin-mips.mk
+++ b/content/content_jni_headers.target.darwin-mips.mk
@@ -429,13 +429,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -507,13 +507,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.darwin-x86.mk b/content/content_jni_headers.target.darwin-x86.mk
index 84769e5..2536024 100644
--- a/content/content_jni_headers.target.darwin-x86.mk
+++ b/content/content_jni_headers.target.darwin-x86.mk
@@ -432,13 +432,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -514,13 +514,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.linux-arm.mk b/content/content_jni_headers.target.linux-arm.mk
index c2211f8..b7961f8 100644
--- a/content/content_jni_headers.target.linux-arm.mk
+++ b/content/content_jni_headers.target.linux-arm.mk
@@ -430,13 +430,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -509,13 +509,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.linux-mips.mk b/content/content_jni_headers.target.linux-mips.mk
index b58d601..722d926 100644
--- a/content/content_jni_headers.target.linux-mips.mk
+++ b/content/content_jni_headers.target.linux-mips.mk
@@ -429,13 +429,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -507,13 +507,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_jni_headers.target.linux-x86.mk b/content/content_jni_headers.target.linux-x86.mk
index 84769e5..2536024 100644
--- a/content/content_jni_headers.target.linux-x86.mk
+++ b/content/content_jni_headers.target.linux-x86.mk
@@ -432,13 +432,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -514,13 +514,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index b51c9ab..1e72a81 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -176,8 +176,6 @@
     'renderer/media/android/stream_texture_factory_android_synchronous_impl.h',
     'renderer/media/android/webmediaplayer_android.cc',
     'renderer/media/android/webmediaplayer_android.h',
-    'renderer/media/android/webmediaplayer_proxy_android.cc',
-    'renderer/media/android/webmediaplayer_proxy_android.h',
     'renderer/media/audio_decoder.cc',
     'renderer/media/audio_decoder.h',
     'renderer/media/audio_device_factory.cc',
@@ -212,6 +210,8 @@
     'renderer/media/media_stream_dispatcher.h',
     'renderer/media/media_stream_dispatcher_eventhandler.h',
     'renderer/media/media_stream_impl.h',
+    'renderer/media/media_stream_track_extra_data.cc',
+    'renderer/media/media_stream_track_extra_data.h',
     'renderer/media/midi_dispatcher.cc',
     'renderer/media/midi_dispatcher.h',
     'renderer/media/midi_message_filter.cc',
@@ -472,6 +472,8 @@
     'renderer/renderer_webcolorchooser_impl.h',
     'renderer/renderer_webkitplatformsupport_impl.cc',
     'renderer/renderer_webkitplatformsupport_impl.h',
+    'renderer/resizing_mode_selector.cc',
+    'renderer/resizing_mode_selector.h',
     'renderer/sad_plugin.cc',
     'renderer/sad_plugin.h',
     'renderer/savable_resources.cc',
@@ -480,6 +482,8 @@
     'renderer/scoped_clipboard_writer_glue.h',
     'renderer/shared_memory_seqlock_reader.cc',
     'renderer/shared_memory_seqlock_reader.h',
+    'renderer/shared_worker_repository.cc',
+    'renderer/shared_worker_repository.h',
     'renderer/skia_benchmarking_extension.cc',
     'renderer/skia_benchmarking_extension.h',
     'renderer/speech_recognition_dispatcher.cc',
@@ -505,8 +509,6 @@
     'renderer/webcrypto/webcrypto_impl_openssl.cc',
     'renderer/websharedworker_proxy.cc',
     'renderer/websharedworker_proxy.h',
-    'renderer/websharedworkerrepository_impl.cc',
-    'renderer/websharedworkerrepository_impl.h',
   ],
   'conditions': [
     ['notifications==0', {
diff --git a/content/content_renderer.target.darwin-arm.mk b/content/content_renderer.target.darwin-arm.mk
index 27b95b3..1ef39e9 100644
--- a/content/content_renderer.target.darwin-arm.mk
+++ b/content/content_renderer.target.darwin-arm.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -227,13 +227,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -368,13 +368,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.target.darwin-mips.mk b/content/content_renderer.target.darwin-mips.mk
index 76caaa9..7a76dba 100644
--- a/content/content_renderer.target.darwin-mips.mk
+++ b/content/content_renderer.target.darwin-mips.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -226,13 +226,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -366,13 +366,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.target.darwin-x86.mk b/content/content_renderer.target.darwin-x86.mk
index 4495613..c1aa334 100644
--- a/content/content_renderer.target.darwin-x86.mk
+++ b/content/content_renderer.target.darwin-x86.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -229,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -372,13 +372,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.target.linux-arm.mk b/content/content_renderer.target.linux-arm.mk
index 27b95b3..1ef39e9 100644
--- a/content/content_renderer.target.linux-arm.mk
+++ b/content/content_renderer.target.linux-arm.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -227,13 +227,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -368,13 +368,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.target.linux-mips.mk b/content/content_renderer.target.linux-mips.mk
index 76caaa9..7a76dba 100644
--- a/content/content_renderer.target.linux-mips.mk
+++ b/content/content_renderer.target.linux-mips.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -226,13 +226,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -366,13 +366,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_renderer.target.linux-x86.mk b/content/content_renderer.target.linux-x86.mk
index 4495613..c1aa334 100644
--- a/content/content_renderer.target.linux-x86.mk
+++ b/content/content_renderer.target.linux-x86.mk
@@ -100,7 +100,6 @@
 	content/renderer/media/android/stream_texture_factory_android_impl.cc \
 	content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc \
 	content/renderer/media/android/webmediaplayer_android.cc \
-	content/renderer/media/android/webmediaplayer_proxy_android.cc \
 	content/renderer/media/audio_decoder.cc \
 	content/renderer/media/audio_device_factory.cc \
 	content/renderer/media/audio_input_message_filter.cc \
@@ -169,10 +168,12 @@
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
+	content/renderer/resizing_mode_selector.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
 	content/renderer/shared_memory_seqlock_reader.cc \
+	content/renderer/shared_worker_repository.cc \
 	content/renderer/skia_benchmarking_extension.cc \
 	content/renderer/speech_recognition_dispatcher.cc \
 	content/renderer/stats_collection_controller.cc \
@@ -185,8 +186,7 @@
 	content/renderer/web_ui_extension_data.cc \
 	content/renderer/webcrypto/webcrypto_impl.cc \
 	content/renderer/webcrypto/webcrypto_impl_openssl.cc \
-	content/renderer/websharedworker_proxy.cc \
-	content/renderer/websharedworkerrepository_impl.cc
+	content/renderer/websharedworker_proxy.cc
 
 
 # Flags passed to both C and C++ files.
@@ -229,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -372,13 +372,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index e6cdd95..576b522 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -40,6 +40,7 @@
         'content_resources.gyp:content_resources',
         '../base/base.gyp:base',
         '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../components/components.gyp:breakpad_component',
         '../ipc/ipc.gyp:ipc',
         '../media/media.gyp:media',
         '../net/net.gyp:net',
@@ -67,6 +68,8 @@
         'shell/android/shell_manager.h',
         'shell/app/paths_mac.h',
         'shell/app/paths_mac.mm',
+        'shell/app/shell_breakpad_client.cc',
+        'shell/app/shell_breakpad_client.h',
         'shell/app/shell_main_delegate.cc',
         'shell/app/shell_main_delegate.h',
         'shell/app/shell_main_delegate_mac.h',
@@ -208,6 +211,11 @@
             'test_support_content',
           ],
         }],  # OS=="android"
+        ['os_posix == 1 and OS != "mac" and android_webview_build != 1', {
+          'dependencies': [
+            '../components/components.gyp:breakpad_host',
+          ],
+        }],
         ['(os_posix==1 and use_aura==1 and linux_use_tcmalloc==1) or (android_use_tcmalloc==1)', {
           'dependencies': [
             # This is needed by content/app/content_main_runner.cc
@@ -542,8 +550,15 @@
           'mac_bundle_resources': [
             'shell/app/English.lproj/HttpAuth.xib',
             'shell/app/English.lproj/MainMenu.xib',
-            '<(PRODUCT_DIR)/content_shell.pak'
+            '<(PRODUCT_DIR)/content_shell.pak',
+            'shell/app/framework-Info.plist',
           ],
+          'mac_bundle_resources!': [
+            'shell/app/framework-Info.plist',
+          ],
+          'xcode_settings': {
+            'INFOPLIST_FILE': 'shell/app/framework-Info.plist',
+          },
           'dependencies': [
             'content_shell_lib',
           ],
@@ -554,6 +569,24 @@
             'shell/app/shell_content_main.cc',
             'shell/app/shell_content_main.h',
           ],
+         'postbuilds': [
+           {
+             # Modify the Info.plist as needed.  The script explains why
+             # this is needed.  This is also done in the chrome target.
+             # The framework needs the Breakpad keys if this feature is
+             # enabled.  It does not need the Keystone keys; these always
+             # come from the outer application bundle.  The framework
+             # doesn't currently use the SCM keys for anything,
+             # but this seems like a really good place to store them.
+             'postbuild_name': 'Tweak Info.plist',
+             'action': ['../build/mac/tweak_info_plist.py',
+                        '--breakpad=1',
+                        '--keystone=0',
+                        '--scm=1',
+                        '--version=<(content_shell_version)',
+                        '--branding=<(content_shell_product_name)'],
+           },
+         ],
           'copies': [
             {
               # Copy FFmpeg binaries for audio/video support.
@@ -562,6 +595,13 @@
                 '<(PRODUCT_DIR)/ffmpegsumo.so',
               ],
             },
+            {
+              'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Resources',
+              'files': [
+                '<(PRODUCT_DIR)/crash_inspector',
+                '<(PRODUCT_DIR)/crash_report_sender.app'
+              ],
+            },
           ],
           'conditions': [
             ['enable_webrtc==1', {
@@ -768,6 +808,29 @@
         },
       ],
     }],  # OS=="android"
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'content_shell_crash_service',
+          'type': 'executable',
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../components/components.gyp:breakpad_crash_service',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'sources': [
+            'shell/tools/content_shell_crash_service.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+        },
+      ],
+    }],  # OS=="win"
     ['OS=="win" and fastbuild==0 and target_arch=="ia32"', {
       'variables': {
         'dest_dir': '<(PRODUCT_DIR)/syzygy',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 1fce231..a5f67d2 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -17,7 +17,7 @@
         '../ui/ui.gyp:keycode_converter',
         '../ui/ui.gyp:ui',
         '../ui/ui.gyp:ui_resources',
-        '../ui/ui.gyp:ui_test_support',
+        '../ui/ui_unittests.gyp:ui_test_support',
         '../url/url.gyp:url_lib',
         'browser/speech/proto/speech_proto.gyp:speech_proto',
         'content.gyp:content_app_both',
@@ -39,7 +39,6 @@
         'public/test/download_test_observer.h',
         'public/test/fake_speech_recognition_manager.cc',
         'public/test/fake_speech_recognition_manager.h',
-        'public/test/js_injection_ready_observer.h',
         'public/test/layouttest_support.h',
         'public/test/mock_download_item.cc',
         'public/test/mock_download_item.h',
@@ -290,7 +289,7 @@
         }],
         ['OS=="android"', {
           'dependencies': [
-            '../ui/ui.gyp:shell_dialogs',
+            '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
             'test_support_content_jni_headers',
           ],
         }],
@@ -325,6 +324,7 @@
         'browser/accessibility/browser_accessibility_manager_unittest.cc',
         'browser/accessibility/browser_accessibility_win_unittest.cc',
         'browser/appcache/chrome_appcache_service_unittest.cc',
+        'browser/aura/software_output_device_ozone_unittest.cc',
         'browser/browser_thread_unittest.cc',
         'browser/browser_url_handler_impl_unittest.cc',
         'browser/byte_stream_unittest.cc',
@@ -366,6 +366,10 @@
         'browser/fileapi/sandbox_file_system_backend_unittest.cc',
         'browser/fileapi/transient_file_util_unittest.cc',
         'browser/fileapi/upload_file_system_file_element_reader_unittest.cc',
+        'browser/frame_host/frame_tree_unittest.cc',
+        'browser/frame_host/navigation_controller_impl_unittest.cc',
+        'browser/frame_host/navigation_entry_impl_unittest.cc',
+        'browser/frame_host/render_view_host_manager_unittest.cc',
         'browser/gamepad/gamepad_provider_unittest.cc',
         'browser/gamepad/gamepad_test_helpers.cc',
         'browser/gamepad/gamepad_test_helpers.h',
@@ -387,6 +391,10 @@
         'browser/indexed_db/indexed_db_leveldb_coding_unittest.cc',
         'browser/indexed_db/indexed_db_quota_client_unittest.cc',
         'browser/indexed_db/indexed_db_unittest.cc',
+        'browser/indexed_db/mock_indexed_db_callbacks.cc',
+        'browser/indexed_db/mock_indexed_db_callbacks.h',
+        'browser/indexed_db/mock_indexed_db_database_callbacks.cc',
+        'browser/indexed_db/mock_indexed_db_database_callbacks.h',
         'browser/indexed_db/leveldb/leveldb_unittest.cc',
         'browser/indexed_db/list_set_unittest.cc',
         'browser/loader/offline_policy_unittest.cc',
@@ -403,7 +411,6 @@
         'browser/plugin_loader_posix_unittest.cc',
         'browser/power_monitor_message_broadcaster_unittest.cc',
         'browser/renderer_host/compositing_iosurface_transformer_mac_unittest.cc',
-        'browser/renderer_host/frame_tree_unittest.cc',
         'browser/renderer_host/gtk_key_bindings_handler_unittest.cc',
         'browser/renderer_host/input/gesture_event_filter_unittest.cc',
         'browser/renderer_host/input/immediate_input_router_unittest.cc',
@@ -413,8 +420,7 @@
         'browser/renderer_host/input/mock_input_ack_handler.h',
         'browser/renderer_host/input/mock_input_router_client.cc',
         'browser/renderer_host/input/mock_input_router_client.h',
-        'browser/renderer_host/input/mock_web_input_event_builders.cc',
-        'browser/renderer_host/input/mock_web_input_event_builders.h',
+        'browser/renderer_host/input/synthetic_gesture_controller_new_unittest.cc',
         'browser/renderer_host/input/tap_suppression_controller_unittest.cc',
         'browser/renderer_host/input/touch_event_queue_unittest.cc',
         'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
@@ -441,6 +447,7 @@
         'browser/renderer_host/render_widget_host_view_guest_unittest.cc',
         'browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm',
         'browser/renderer_host/render_widget_host_view_mac_unittest.mm',
+        'browser/renderer_host/software_frame_manager_unittest.cc',
         'browser/renderer_host/synthetic_gesture_controller_unittest.cc',
         'browser/renderer_host/text_input_client_mac_unittest.mm',
         'browser/renderer_host/web_input_event_aura_unittest.cc',
@@ -462,9 +469,6 @@
         'browser/system_message_window_win_unittest.cc',
         'browser/tracing/trace_subscriber_stdio_unittest.cc',
         'browser/web_contents/aura/window_slider_unittest.cc',
-        'browser/web_contents/navigation_controller_impl_unittest.cc',
-        'browser/web_contents/navigation_entry_impl_unittest.cc',
-        'browser/web_contents/render_view_host_manager_unittest.cc',
         'browser/web_contents/web_contents_delegate_unittest.cc',
         'browser/web_contents/web_contents_impl_unittest.cc',
         'browser/web_contents/web_contents_user_data_unittest.cc',
@@ -580,6 +584,7 @@
         '../webkit/browser/fileapi/sandbox_directory_database_unittest.cc',
         '../webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc',
         '../webkit/browser/fileapi/sandbox_origin_database_unittest.cc',
+        '../webkit/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc',
         '../webkit/browser/fileapi/test_file_set.cc',
         '../webkit/browser/fileapi/test_file_set.h',
         '../webkit/browser/fileapi/timed_task_helper_unittest.cc',
@@ -637,6 +642,7 @@
             '../third_party/icu/icu.gyp:icuuc',
             '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
             '../third_party/libjingle/libjingle.gyp:libjingle',
+            '../ui/compositor/compositor.gyp:compositor_test_support',
             '../ui/gl/gl.gyp:gl',
             '../v8/tools/gyp/v8.gyp:v8',
             '../webkit/common/webkit_common.gyp:webkit_common',
@@ -750,15 +756,6 @@
             'browser/accessibility/browser_accessibility_win_unittest.cc',
           ],
         }],
-        ['branding=="Chrome"', {
-          'sources!': [
-            # These tests depend on single process mode, which is disabled in
-            # official builds.
-            'renderer/dom_serializer_browsertest.cc',
-            'renderer/resource_fetcher_browsertest.cc',
-            'renderer/savable_resources_browsertest.cc',
-          ],
-        }],
         ['OS == "android"', {
           'sources': [
             'browser/renderer_host/java/jni_helper_unittest.cc',
@@ -795,6 +792,24 @@
     },
   ],
   'conditions': [
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+	{
+	  'target_name': 'content_unittests_run',
+	  'type': 'none',
+	  'dependencies': [
+	    'content_unittests',
+	  ],
+	  'includes': [
+	    '../build/isolate.gypi',
+	    'content_unittests.isolate',
+	  ],
+	  'sources': [
+	    'content_unittests.isolate',
+	  ],
+	},
+      ],
+    }],
     ['OS!="ios"', {
       'targets': [
         {
@@ -816,7 +831,7 @@
           ],
           'sources': [
             'common/cc_messages_perftest.cc',
-            'test/run_all_unittests.cc',
+            'test/run_all_perftests.cc',
           ],
         },
         {
@@ -849,8 +864,8 @@
             '../third_party/mesa/mesa.gyp:osmesa',
             '../ui/gfx/gfx.gyp:gfx',
             '../ui/gl/gl.gyp:gl',
+            '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
             '../ui/snapshot/snapshot.gyp:snapshot',
-            '../ui/ui.gyp:shell_dialogs',
             '../ui/ui.gyp:ui',
             '../ui/ui.gyp:ui_resources',
             '../webkit/glue/webkit_glue.gyp:glue',
@@ -893,11 +908,8 @@
             'browser/download/save_package_browsertest.cc',
             'browser/fileapi/file_system_browsertest.cc',
             'browser/gpu/compositor_util_browsertest.cc',
-            'browser/gpu/gpu_crash_browsertest.cc',
             'browser/gpu/gpu_functional_browsertest.cc',
-            'browser/gpu/gpu_info_browsertest.cc',
             'browser/gpu/gpu_ipc_browsertests.cc',
-            'browser/gpu/gpu_memory_test.cc',
             'browser/indexed_db/indexed_db_browsertest.cc',
             'browser/loader/resource_dispatcher_host_browsertest.cc',
             'browser/media/encrypted_media_browsertest.cc',
@@ -913,7 +925,6 @@
             'browser/renderer_host/render_view_host_manager_browsertest.cc',
             'browser/renderer_host/render_widget_host_browsertest.cc',
             'browser/renderer_host/render_widget_host_view_browsertest.cc',
-            'browser/renderer_host/render_widget_host_view_win_browsertest.cc',
             'browser/security_exploit_browsertest.cc',
             'browser/session_history_browsertest.cc',
             'browser/site_per_process_browsertest.cc',
@@ -1004,7 +1015,6 @@
             }, {  # OS!="win"
               'sources!': [
                 'browser/accessibility/accessibility_win_browsertest.cc',
-                'browser/renderer_host/render_widget_host_view_win_browsertest.cc',
               ],
             }],
             ['OS=="win" and win_use_allocator_shim==1', {
@@ -1039,7 +1049,7 @@
               'sources!': [
                 'browser/accessibility/accessibility_win_browsertest.cc',
                 'browser/accessibility/dump_accessibility_tree_browsertest.cc',
-                'browser/renderer_host/render_widget_host_view_win_browsertest.cc',
+                'browser/plugin_browsertest.cc',
               ],
             }, {
               'sources/': [
@@ -1077,6 +1087,15 @@
                 ['exclude', '^browser/speech/'],
               ]
             }],
+            ['branding=="Chrome"', {
+              'sources!': [
+                # These tests depend on single process mode, which is disabled
+                # in official builds.
+                'renderer/dom_serializer_browsertest.cc',
+                'renderer/resource_fetcher_browsertest.cc',
+                'renderer/savable_resources_browsertest.cc',
+              ],
+            }],
           ],
         },
         {
@@ -1312,7 +1331,6 @@
             'native_lib_target': 'libcontent_browsertests',
             'additional_input_paths': ['<(PRODUCT_DIR)/content_shell/assets/content_shell.pak'],
             'asset_location': '<(ant_build_out)/content_shell/assets',
-            'is_test_apk': 1,
           },
           'includes': [ '../build/java_apk.gypi' ],
         },
diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate
index b39101c..92a448b 100644
--- a/content/content_unittests.isolate
+++ b/content/content_unittests.isolate
@@ -12,58 +12,60 @@
         ],
       },
     }],
-    ['OS=="android" or OS=="mac"', {
+    ['OS=="android" or OS=="mac" or OS=="win"', {
       'variables': {
         'isolate_dependency_tracked': [
           '<(PRODUCT_DIR)/content_resources.pak',
         ],
       },
     }],
+    ['OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'isolate_dependency_tracked': [
+          '../testing/test_env.py',
+          '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+        'isolate_dependency_untracked': [
+          '../tools/swarm_client/',
+        ],
+      },
+    }],
     ['OS=="linux"', {
       'variables': {
         'command': [
           '../testing/xvfb.py',
           '<(PRODUCT_DIR)',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
         'isolate_dependency_tracked': [
+          '../testing/xvfb.py',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
-        ],
-        'isolate_dependency_untracked': [
-          '<(PRODUCT_DIR)/test_data/',
-        ],
-      },
-    }],
-    ['OS=="linux" or OS=="mac" or OS=="win"', {
-      'variables': {
-        'isolate_dependency_tracked': [
-          '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
-        ],
-        'isolate_dependency_untracked': [
-          '../tools/swarm_client/',
+          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
         ],
       },
     }],
     ['OS=="mac"', {
       'variables': {
+        'command': [
+          '../testing/test_env.py',
+          '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
+        ],
         'isolate_dependency_tracked': [
           '<(PRODUCT_DIR)/ffmpegsumo.so',
         ],
       },
     }],
-    ['OS=="mac" or OS=="win"', {
+    ['OS=="win"', {
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
-      },
-    }],
-    ['OS=="win"', {
-      'variables': {
         'isolate_dependency_tracked': [
+          '<(PRODUCT_DIR)/aura_test_support_resources.pak',
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/icudt.dll',
         ],
diff --git a/content/content_utility.target.darwin-arm.mk b/content/content_utility.target.darwin-arm.mk
index cb2accd..5bcbc5a 100644
--- a/content/content_utility.target.darwin-arm.mk
+++ b/content/content_utility.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_utility.target.darwin-mips.mk b/content/content_utility.target.darwin-mips.mk
index dc8fa6a..08847e3 100644
--- a/content/content_utility.target.darwin-mips.mk
+++ b/content/content_utility.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_utility.target.darwin-x86.mk b/content/content_utility.target.darwin-x86.mk
index 58a075e..c081039 100644
--- a/content/content_utility.target.darwin-x86.mk
+++ b/content/content_utility.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_utility.target.linux-arm.mk b/content/content_utility.target.linux-arm.mk
index cb2accd..5bcbc5a 100644
--- a/content/content_utility.target.linux-arm.mk
+++ b/content/content_utility.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_utility.target.linux-mips.mk b/content/content_utility.target.linux-mips.mk
index dc8fa6a..08847e3 100644
--- a/content/content_utility.target.linux-mips.mk
+++ b/content/content_utility.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/content_utility.target.linux-x86.mk b/content/content_utility.target.linux-x86.mk
index 58a075e..c081039 100644
--- a/content/content_utility.target.linux-x86.mk
+++ b/content/content_utility.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 9e29e03..c2ffd63 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -191,13 +191,13 @@
   DCHECK(command_line.HasSwitch(switches::kGpuVendorID) &&
          command_line.HasSwitch(switches::kGpuDeviceID) &&
          command_line.HasSwitch(switches::kGpuDriverVersion));
-  bool success = base::HexStringToInt(
+  bool success = base::HexStringToUInt(
       command_line.GetSwitchValueASCII(switches::kGpuVendorID),
-      reinterpret_cast<int*>(&(gpu_info.gpu.vendor_id)));
+      &gpu_info.gpu.vendor_id);
   DCHECK(success);
-  success = base::HexStringToInt(
+  success = base::HexStringToUInt(
       command_line.GetSwitchValueASCII(switches::kGpuDeviceID),
-      reinterpret_cast<int*>(&(gpu_info.gpu.device_id)));
+      &gpu_info.gpu.device_id);
   DCHECK(success);
   gpu_info.driver_vendor =
       command_line.GetSwitchValueASCII(switches::kGpuDriverVendor);
diff --git a/content/java_set_jni_headers.target.darwin-arm.mk b/content/java_set_jni_headers.target.darwin-arm.mk
index e03c4f7..fdd564a 100644
--- a/content/java_set_jni_headers.target.darwin-arm.mk
+++ b/content/java_set_jni_headers.target.darwin-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/java_set_jni_headers.target.darwin-mips.mk b/content/java_set_jni_headers.target.darwin-mips.mk
index 9a152bb..75c183d 100644
--- a/content/java_set_jni_headers.target.darwin-mips.mk
+++ b/content/java_set_jni_headers.target.darwin-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/java_set_jni_headers.target.darwin-x86.mk b/content/java_set_jni_headers.target.darwin-x86.mk
index d86d292..4190ec9 100644
--- a/content/java_set_jni_headers.target.darwin-x86.mk
+++ b/content/java_set_jni_headers.target.darwin-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/java_set_jni_headers.target.linux-arm.mk b/content/java_set_jni_headers.target.linux-arm.mk
index e03c4f7..fdd564a 100644
--- a/content/java_set_jni_headers.target.linux-arm.mk
+++ b/content/java_set_jni_headers.target.linux-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/java_set_jni_headers.target.linux-mips.mk b/content/java_set_jni_headers.target.linux-mips.mk
index 9a152bb..75c183d 100644
--- a/content/java_set_jni_headers.target.linux-mips.mk
+++ b/content/java_set_jni_headers.target.linux-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/java_set_jni_headers.target.linux-x86.mk b/content/java_set_jni_headers.target.linux-x86.mk
index d86d292..4190ec9 100644
--- a/content/java_set_jni_headers.target.linux-x86.mk
+++ b/content/java_set_jni_headers.target.linux-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.darwin-arm.mk b/content/page_transition_types_java.target.darwin-arm.mk
index ae43ec5..b672f24 100644
--- a/content/page_transition_types_java.target.darwin-arm.mk
+++ b/content/page_transition_types_java.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.darwin-mips.mk b/content/page_transition_types_java.target.darwin-mips.mk
index 99b420b..c0e90b8 100644
--- a/content/page_transition_types_java.target.darwin-mips.mk
+++ b/content/page_transition_types_java.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.darwin-x86.mk b/content/page_transition_types_java.target.darwin-x86.mk
index 5e4ca99..cf72f41 100644
--- a/content/page_transition_types_java.target.darwin-x86.mk
+++ b/content/page_transition_types_java.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.linux-arm.mk b/content/page_transition_types_java.target.linux-arm.mk
index ae43ec5..b672f24 100644
--- a/content/page_transition_types_java.target.linux-arm.mk
+++ b/content/page_transition_types_java.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.linux-mips.mk b/content/page_transition_types_java.target.linux-mips.mk
index 99b420b..c0e90b8 100644
--- a/content/page_transition_types_java.target.linux-mips.mk
+++ b/content/page_transition_types_java.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/page_transition_types_java.target.linux-x86.mk b/content/page_transition_types_java.target.linux-x86.mk
index 5e4ca99..cf72f41 100644
--- a/content/page_transition_types_java.target.linux-x86.mk
+++ b/content/page_transition_types_java.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/public/android/OWNERS b/content/public/android/OWNERS
index 7b7df6d..09b4067 100644
--- a/content/public/android/OWNERS
+++ b/content/public/android/OWNERS
@@ -2,3 +2,7 @@
 joth@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
+
+# Device Motion / Orientation API related
+per-file DeviceMotionAndOrientation*.java=timvolodine@chromium.org
+per-file DeviceMotionAndOrientation*.java=mvanouwerkerk@chromium.org
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
index ef00b36..b6d2e27 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -112,13 +112,15 @@
                 ContentViewCore.INPUT_EVENTS_DELIVERED_IMMEDIATELY);
     }
 
-    // PageInfo implementation.
-
-    @Override
+    /**
+     * @return The URL of the page.
+     */
     public String getUrl() {
         return mContentViewCore.getUrl();
     }
 
+    // PageInfo implementation.
+
     @Override
     public String getTitle() {
         return mContentViewCore.getTitle();
@@ -409,6 +411,12 @@
         return super.drawChild(canvas, child, drawingTime);
     }
 
+    // Needed by ContentViewCore.InternalAccessDelegate
+    @Override
+    public void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int ow, int oh) {
         TraceEvent.begin();
@@ -487,6 +495,7 @@
         MotionEvent offset = createOffsetMotionEvent(event);
         boolean consumed = mContentViewCore.onHoverEvent(offset);
         offset.recycle();
+        super.onHoverEvent(event);
         return consumed;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 63dde98..e4075f5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -172,6 +172,11 @@
         void super_onConfigurationChanged(Configuration newConfig);
 
         /**
+         * @see View#onScrollChanged(int, int, int, int)
+         */
+        void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
+
+        /**
          * @see View#awakenScrollBars()
          */
         boolean awakenScrollBars();
@@ -772,6 +777,15 @@
     }
 
     /**
+     * Set the Container view Internals.
+     * @param internalDispatcher Handles dispatching all hidden or super methods to the
+     *                           containerView.
+     */
+    public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) {
+        mContainerViewInternals = internalDispatcher;
+    }
+
+    /**
      * Initializes the View that will contain all Views created by the ContentViewCore.
      *
      * @param internalDispatcher Handles dispatching all hidden or super methods to the
@@ -1306,6 +1320,9 @@
             case ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL:
                 nativeShowPressCancel(mNativeContentViewCore, timeMs, x, y);
                 return true;
+            case ContentViewGestureHandler.GESTURE_TAP_DOWN:
+                nativeTapDown(mNativeContentViewCore, timeMs, x, y);
+                return true;
             case ContentViewGestureHandler.GESTURE_DOUBLE_TAP:
                 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
                 return true;
@@ -2399,6 +2416,14 @@
 
         if (needHidePopupZoomer) mPopupZoomer.hide(true);
 
+        if (scrollChanged) {
+            mContainerViewInternals.onScrollChanged(
+                    (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX),
+                    (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY),
+                    (int) mRenderCoordinates.getScrollXPix(),
+                    (int) mRenderCoordinates.getScrollYPix());
+        }
+
         mRenderCoordinates.updateFrameInfo(
                 scrollOffsetX, scrollOffsetY,
                 contentWidth, contentHeight,
@@ -3014,7 +3039,7 @@
      * Inform WebKit that Fullscreen mode has been exited by the user.
      */
     public void exitFullscreen() {
-        nativeExitFullscreen(mNativeContentViewCore);
+        if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore);
     }
 
     /**
@@ -3026,7 +3051,10 @@
      */
     public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
             boolean animate) {
-        nativeUpdateTopControlsState(mNativeContentViewCore, enableHiding, enableShowing, animate);
+        if (mNativeContentViewCore != 0) {
+            nativeUpdateTopControlsState(
+                    mNativeContentViewCore, enableHiding, enableShowing, animate);
+        }
     }
 
     /**
@@ -3217,6 +3245,9 @@
     private native void nativeShowPressCancel(
             int nativeContentViewCoreImpl, long timeMs, float x, float y);
 
+    private native void nativeTapDown(
+            int nativeContentViewCoreImpl, long timeMs, float x, float y);
+
     private native void nativeDoubleTap(
             int nativeContentViewCoreImpl, long timeMs, float x, float y);
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
index f0fb10a..2ccf09b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
@@ -18,6 +18,7 @@
 import org.chromium.content.browser.third_party.GestureDetector.OnGestureListener;
 import org.chromium.content.browser.LongPressDetector.LongPressDelegate;
 import org.chromium.content.browser.SnapScrollController;
+import org.chromium.content.common.CommandLine;
 import org.chromium.content.common.TraceEvent;
 
 import java.util.ArrayDeque;
@@ -166,6 +167,9 @@
     // to potentially use the event to send GESUTRE_SHOW_PRESS_CANCEL to remove ::active styling
     private MotionEvent mLastLongPressEvent;
 
+    // Whether the click delay should always be disabled by sending clicks for double tap gestures.
+    private final boolean mDisableClickDelay;
+
     static final int GESTURE_SHOW_PRESSED_STATE = 0;
     static final int GESTURE_DOUBLE_TAP = 1;
     static final int GESTURE_SINGLE_TAP_UP = 2;
@@ -182,6 +186,7 @@
     static final int GESTURE_PINCH_END = 13;
     static final int GESTURE_SHOW_PRESS_CANCEL = 14;
     static final int GESTURE_LONG_TAP = 15;
+    static final int GESTURE_TAP_DOWN = 16;
 
     // These have to be kept in sync with content/port/common/input_event_ack_state.h
     static final int INPUT_EVENT_ACK_STATE_UNKNOWN = 0;
@@ -350,6 +355,9 @@
                 inputEventDeliveryMode == ContentViewCore.INPUT_EVENTS_DELIVERED_AT_VSYNC;
         mPxToDp = 1.0f / context.getResources().getDisplayMetrics().density;
 
+        mDisableClickDelay = CommandLine.isInitialized() &&
+                CommandLine.getInstance().hasSwitch(CommandLine.DISABLE_CLICK_DELAY);
+
         initGestureDetectors(context);
     }
 
@@ -386,6 +394,7 @@
                         mLastRawY = e.getRawY();
                         mAccumulatedScrollErrorX = 0;
                         mAccumulatedScrollErrorY = 0;
+                        sendMotionEventAsGesture(GESTURE_TAP_DOWN, e, null);
                         // Return true to indicate that we want to handle touch
                         return true;
                     }
@@ -393,6 +402,7 @@
                     @Override
                     public boolean onScroll(MotionEvent e1, MotionEvent e2,
                             float distanceX, float distanceY) {
+                        assert e1.getEventTime() <= e2.getEventTime();
                         if (!mSeenFirstScrollEvent) {
                             // Remove the touch slop region from the first scroll event to avoid a
                             // jump.
@@ -424,7 +434,8 @@
                         if (!mTouchScrolling) {
                             sendShowPressCancelIfNecessary(e1);
                             endFlingIfNecessary(e2.getEventTime());
-                            if (sendMotionEventAsGesture(GESTURE_SCROLL_START, e1, null)) {
+                            if (sendGesture(GESTURE_SCROLL_START, e2.getEventTime(),
+                                        (int) e1.getX(), (int) e1.getY(), null)) {
                                 mTouchScrolling = true;
                             }
                         }
@@ -457,6 +468,7 @@
                     @Override
                     public boolean onFling(MotionEvent e1, MotionEvent e2,
                             float velocityX, float velocityY) {
+                        assert e1.getEventTime() <= e2.getEventTime();
                         if (mSnapScrollController.isSnappingScrolls()) {
                             if (mSnapScrollController.isSnapHorizontal()) {
                                 velocityY = 0;
@@ -465,7 +477,7 @@
                             }
                         }
 
-                        fling(e1.getEventTime(),(int) e1.getX(0), (int) e1.getY(0),
+                        fling(e2.getEventTime(),(int) e1.getX(0), (int) e1.getY(0),
                                         (int) velocityX, (int) velocityY);
                         return true;
                     }
@@ -497,7 +509,7 @@
                                 }
                                 setClickXAndY((int) x, (int) y);
                                 return true;
-                            } else if (isDoubleTapDisabled()) {
+                            } else if (isDoubleTapDisabled() || mDisableClickDelay) {
                                 // If double tap has been disabled, there is no need to wait
                                 // for the double tap timeout.
                                 return onSingleTapConfirmed(e);
@@ -534,7 +546,6 @@
 
                     @Override
                     public boolean onDoubleTapEvent(MotionEvent e) {
-                        if (isDoubleTapDisabled()) return false;
                         switch (e.getActionMasked()) {
                             case MotionEvent.ACTION_DOWN:
                                 sendShowPressCancelIfNecessary(e);
@@ -698,7 +709,7 @@
      *              to send. This argument is an optional and can be null.
      */
     void endDoubleTapDragIfNecessary(MotionEvent event) {
-        if (mDoubleTapMode == DOUBLE_TAP_MODE_DISABLED) return;
+        if (!isDoubleTapActive()) return;
         if (mDoubleTapMode == DOUBLE_TAP_MODE_DRAG_ZOOM) {
             if (event == null) event = obtainActionCancelMotionEvent();
             pinchEnd(event.getEventTime());
@@ -706,6 +717,7 @@
                     (int) event.getX(), (int) event.getY(), null);
         }
         mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+        updateDoubleTapListener();
     }
 
     /**
@@ -1215,8 +1227,7 @@
      * @param supportDoubleTap Whether double-tap gestures are supported.
      */
     public void updateDoubleTapSupport(boolean supportDoubleTap) {
-        assert (mDoubleTapMode == DOUBLE_TAP_MODE_DISABLED ||
-                mDoubleTapMode == DOUBLE_TAP_MODE_NONE);
+        assert !isDoubleTapActive();
         int doubleTapMode = supportDoubleTap ?
                 DOUBLE_TAP_MODE_NONE : DOUBLE_TAP_MODE_DISABLED;
         if (mDoubleTapMode == doubleTapMode) return;
@@ -1241,9 +1252,15 @@
                mHasFixedPageScale;
     }
 
+    private boolean isDoubleTapActive() {
+        return mDoubleTapMode != DOUBLE_TAP_MODE_DISABLED &&
+               mDoubleTapMode != DOUBLE_TAP_MODE_NONE;
+    }
+
     private void updateDoubleTapListener() {
         if (isDoubleTapDisabled()) {
-            endDoubleTapDragIfNecessary(null);
+            // Defer nulling the DoubleTapListener until the double tap gesture is complete.
+            if (isDoubleTapActive()) return;
             mGestureDetector.setOnDoubleTapListener(null);
         } else {
             mGestureDetector.setOnDoubleTapListener(mDoubleTapListener);
diff --git a/content/public/android/java/src/org/chromium/content/browser/GenericTouchGesture.java b/content/public/android/java/src/org/chromium/content/browser/GenericTouchGesture.java
index b0f97fe..daa6cc3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/GenericTouchGesture.java
+++ b/content/public/android/java/src/org/chromium/content/browser/GenericTouchGesture.java
@@ -8,7 +8,6 @@
 import android.animation.TimeAnimator.TimeListener;
 import android.os.Build;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerProperties;
@@ -17,6 +16,7 @@
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
 
 /**
  * Provides a Java-side implementation for simulating touch gestures,
@@ -26,7 +26,7 @@
 public class GenericTouchGesture {
     private final ContentViewCore mContentViewCore;
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Handler mHandler = new Handler(ThreadUtils.getUiThreadLooper());
 
     private TimeAnimator mTimeAnimator;
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java b/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
index 2274a41..afcc17a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
+++ b/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
@@ -10,7 +10,6 @@
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.os.Bundle;
-import android.os.Looper;
 import android.util.Log;
 
 import org.chromium.base.ActivityStatus;
@@ -153,11 +152,11 @@
             try {
                 Criteria criteria = new Criteria();
                 mLocationManager.requestLocationUpdates(0, 0, criteria, this,
-                        Looper.getMainLooper());
+                        ThreadUtils.getUiThreadLooper());
                 if (mIsGpsEnabled) {
                     criteria.setAccuracy(Criteria.ACCURACY_FINE);
                     mLocationManager.requestLocationUpdates(0, 0, criteria, this,
-                            Looper.getMainLooper());
+                            ThreadUtils.getUiThreadLooper());
                 }
             } catch(SecurityException e) {
                 Log.e(TAG, "Caught security exception registering for location updates from " +
@@ -255,7 +254,7 @@
      * Must be called only in the UI thread.
      */
     public boolean isRunning() {
-        assert Looper.myLooper() == Looper.getMainLooper();
+        assert ThreadUtils.runningOnUiThread();
         return mImpl.isRunning();
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/PageInfo.java b/content/public/android/java/src/org/chromium/content/browser/PageInfo.java
index 1a80b20..6e81cb5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/PageInfo.java
+++ b/content/public/android/java/src/org/chromium/content/browser/PageInfo.java
@@ -14,11 +14,6 @@
  */
 public interface PageInfo {
     /**
-     * @return The URL of the page.
-     */
-    String getUrl();
-
-    /**
      * @return The title of the page.
      */
     String getTitle();
diff --git a/content/public/android/java/src/org/chromium/content/common/CleanupReference.java b/content/public/android/java/src/org/chromium/content/common/CleanupReference.java
index 695e587..89b6197 100644
--- a/content/public/android/java/src/org/chromium/content/common/CleanupReference.java
+++ b/content/public/android/java/src/org/chromium/content/common/CleanupReference.java
@@ -9,6 +9,8 @@
 import android.os.Message;
 import android.util.Log;
 
+import org.chromium.base.ThreadUtils;
+
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.util.HashSet;
@@ -46,7 +48,7 @@
                     CleanupReference ref = (CleanupReference) sGcQueue.remove();
                     if (DEBUG) Log.d(TAG, "removed one ref from GC queue");
                     synchronized (sCleanupMonitor) {
-                        Message.obtain(sHandler, REMOVE_REF, ref).sendToTarget();
+                        Message.obtain(LazyHolder.sHandler, REMOVE_REF, ref).sendToTarget();
                         // Give the UI thread chance to run cleanup before looping around and
                         // taking the next item from the queue, to avoid Message bombing it.
                         sCleanupMonitor.wait(500);
@@ -73,37 +75,41 @@
     /**
      * This {@link Handler} polls {@link #sRefs}, looking for cleanup tasks that
      * are ready to run.
+     * This is lazily initialized as ThreadUtils.getUiThreadLooper() may not be
+     * set yet early in startup.
      */
-    private static Handler sHandler = new Handler(Looper.getMainLooper()) {
-        @Override
-        public void handleMessage(Message msg) {
-            TraceEvent.begin();
-            CleanupReference ref = (CleanupReference) msg.obj;
-            switch (msg.what) {
-                case ADD_REF:
-                    sRefs.add(ref);
-                    break;
-                case REMOVE_REF:
-                    ref.runCleanupTaskInternal();
-                    break;
-                default:
-                    Log.e(TAG, "Bad message=" + msg.what);
-                    break;
-            }
-
-            if (DEBUG) Log.d(TAG, "will try and cleanup; max = " + sRefs.size());
-
-            synchronized (sCleanupMonitor) {
-                // Always run the cleanup loop here even when adding or removing refs, to avoid
-                // falling behind on rapid garbage allocation inner loops.
-                while ((ref = (CleanupReference) sGcQueue.poll()) != null) {
-                    ref.runCleanupTaskInternal();
+    private static class LazyHolder {
+       static final Handler sHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                TraceEvent.begin();
+                CleanupReference ref = (CleanupReference) msg.obj;
+                switch (msg.what) {
+                    case ADD_REF:
+                        sRefs.add(ref);
+                        break;
+                    case REMOVE_REF:
+                        ref.runCleanupTaskInternal();
+                        break;
+                    default:
+                        Log.e(TAG, "Bad message=" + msg.what);
+                        break;
                 }
-                sCleanupMonitor.notifyAll();
+
+                if (DEBUG) Log.d(TAG, "will try and cleanup; max = " + sRefs.size());
+
+                synchronized (sCleanupMonitor) {
+                    // Always run the cleanup loop here even when adding or removing refs, to avoid
+                    // falling behind on rapid garbage allocation inner loops.
+                    while ((ref = (CleanupReference) sGcQueue.poll()) != null) {
+                        ref.runCleanupTaskInternal();
+                    }
+                    sCleanupMonitor.notifyAll();
+                }
+                TraceEvent.end();
             }
-            TraceEvent.end();
-        }
-    };
+        };
+    }
 
     /**
      * Keep a strong reference to {@link CleanupReference} so that it will
@@ -135,9 +141,9 @@
     }
 
     private void handleOnUiThread(int what) {
-        Message msg = Message.obtain(sHandler, what, this);
-        if (Looper.myLooper() == sHandler.getLooper()) {
-            sHandler.handleMessage(msg);
+        Message msg = Message.obtain(LazyHolder.sHandler, what, this);
+        if (Looper.myLooper() == msg.getTarget().getLooper()) {
+            msg.getTarget().handleMessage(msg);
             msg.recycle();
         } else {
             msg.sendToTarget();
diff --git a/content/public/android/java/src/org/chromium/content/common/CommandLine.java b/content/public/android/java/src/org/chromium/content/common/CommandLine.java
index 41e3249..be33ecc 100644
--- a/content/public/android/java/src/org/chromium/content/common/CommandLine.java
+++ b/content/public/android/java/src/org/chromium/content/common/CommandLine.java
@@ -36,6 +36,9 @@
     // Enables test intent handling.
     public static final String ENABLE_TEST_INTENTS = "enable-test-intents";
 
+    // Adds additional thread idle time information into the trace event output.
+    public static final String ENABLE_IDLE_TRACING = "enable-idle-tracing";
+
     // Dump frames-per-second to the log
     public static final String LOG_FPS = "log-fps";
 
@@ -79,6 +82,9 @@
     // Native switch - chrome_switches::kDisablePopupBlocking
     public static final String DISABLE_POPUP_BLOCKING = "disable-popup-blocking";
 
+    // Whether to disable the click delay by sending click events during double tap
+    public static final String DISABLE_CLICK_DELAY = "disable-click-delay";
+
     // Public abstract interface, implemented in derived classes.
     // All these methods reflect their native-side counterparts.
     /**
diff --git a/content/public/android/java/src/org/chromium/content/common/TraceEvent.java b/content/public/android/java/src/org/chromium/content/common/TraceEvent.java
index a5af6c2..a719653 100644
--- a/content/public/android/java/src/org/chromium/content/common/TraceEvent.java
+++ b/content/public/android/java/src/org/chromium/content/common/TraceEvent.java
@@ -11,6 +11,8 @@
 import android.util.Log;
 import android.util.Printer;
 
+import org.chromium.base.ThreadUtils;
+
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
@@ -25,8 +27,31 @@
 
     private static volatile boolean sEnabled = false;
 
+    private static class BasicLooperMonitor implements Printer {
+        private final static String DISPATCH_EVENT_NAME =
+                "Looper.dispatchMessage";
+
+        @Override
+        public void println(final String line) {
+            if (line.startsWith(">")) {
+                beginHandling(line);
+            } else {
+                assert line.startsWith("<");
+                endHandling(line);
+            }
+        }
+
+        void beginHandling(final String line) {
+            TraceEvent.begin(DISPATCH_EVENT_NAME, line);
+        }
+
+        void endHandling(final String line) {
+            TraceEvent.end(DISPATCH_EVENT_NAME);
+        }
+    }
+
     /**
-     * A class that records, traces and logs statistics about the main Looper.
+     * A class that records, traces and logs statistics about the UI thead's Looper.
      * The output of this class can be used in a number of interesting ways:
      * <p>
      * <ol><li>
@@ -46,12 +71,11 @@
      * accumulate between idle notifications and get reset when a new idle
      * notification is received.
      */
-    private final static class LooperMonitor implements Printer, MessageQueue.IdleHandler {
+    private final static class IdleTracingLooperMonitor extends BasicLooperMonitor
+            implements MessageQueue.IdleHandler {
         // Tags for dumping to logcat or TraceEvent
         private final static String TAG = "TraceEvent.LooperMonitor";
         private final static String IDLE_EVENT_NAME = "Looper.queueIdle";
-        private final static String DISPATCH_EVENT_NAME =
-                "Looper.dispatchMessage";
 
         // Calculation constants
         private final static long FRAME_DURATION_MILLIS = 1000L / 60L; // 60 FPS
@@ -72,16 +96,6 @@
         // State
         private boolean mIdleMonitorAttached = false;
 
-        @Override
-        public void println(final String line) {
-            if (line.startsWith(">")) {
-                begin(line);
-            } else {
-                assert line.startsWith("<");
-                end(line);
-            }
-        }
-
         // Called from within the begin/end methods only.
         // This method can only execute on the looper thread, because that is
         // the only thread that is permitted to call Looper.myqueue().
@@ -89,36 +103,36 @@
             if (sEnabled && !mIdleMonitorAttached) {
                 // approximate start time for computational purposes
                 mLastIdleStartedAt = SystemClock.elapsedRealtime();
-                Looper.myQueue().addIdleHandler(
-                        LooperMonitor.getInstance());
+                Looper.myQueue().addIdleHandler(this);
                 mIdleMonitorAttached = true;
                 Log.v(TAG, "attached idle handler");
             } else if (mIdleMonitorAttached && !sEnabled) {
-                Looper.myQueue().removeIdleHandler(
-                        LooperMonitor.getInstance());
+                Looper.myQueue().removeIdleHandler(this);
                 mIdleMonitorAttached = false;
                 Log.v(TAG, "detached idle handler");
             }
         }
 
-        private final void begin(final String line) {
+        @Override
+        final void beginHandling(final String line) {
             // Close-out any prior 'idle' period before starting new task.
             if (mNumTasksSinceLastIdle == 0) {
                 TraceEvent.end(IDLE_EVENT_NAME);
             }
-            TraceEvent.begin(DISPATCH_EVENT_NAME, line);
             mLastWorkStartedAt = SystemClock.elapsedRealtime();
             syncIdleMonitoring();
+            super.beginHandling(line);
         }
 
-        private final void end(final String line) {
+        @Override
+        final void endHandling(final String line) {
             final long elapsed = SystemClock.elapsedRealtime()
                     - mLastWorkStartedAt;
             if (elapsed > MIN_INTERESTING_DURATION_MILLIS) {
                 traceAndLog(Log.WARN, "observed a task that took "
                         + elapsed + "ms: " + line);
             }
-            TraceEvent.end(DISPATCH_EVENT_NAME);
+            super.endHandling(line);
             syncIdleMonitoring();
             mNumTasksSeen++;
             mNumTasksSinceLastIdle++;
@@ -148,14 +162,13 @@
             mNumTasksSinceLastIdle = 0;
             return true; // stay installed
         }
+    }
 
-        // Holder for monitor avoids unnecessary construction on non-debug runs
-        private final static class Holder {
-            private final static LooperMonitor sInstance = new LooperMonitor();
-        }
-        public final static LooperMonitor getInstance() {
-            return Holder.sInstance;
-        }
+    // Holder for monitor avoids unnecessary construction on non-debug runs
+    private final static class LooperMonitorHolder {
+        private final static BasicLooperMonitor sInstance =
+                CommandLine.getInstance().hasSwitch(CommandLine.ENABLE_IDLE_TRACING) ?
+                        new IdleTracingLooperMonitor() : new BasicLooperMonitor();
     }
 
     private static long sTraceTagView;
@@ -233,8 +246,8 @@
     public static synchronized void setEnabled(boolean enabled) {
         if (sEnabled == enabled) return;
         sEnabled = enabled;
-        Looper.getMainLooper().setMessageLogging(
-                enabled ? LooperMonitor.getInstance() : null);
+        ThreadUtils.getUiThreadLooper().setMessageLogging(
+                enabled ? LooperMonitorHolder.sInstance : null);
     }
 
     /**
diff --git a/content/public/android/java/strings/translations/android_content_strings_am.xtb b/content/public/android/java/strings/translations/android_content_strings_am.xtb
index aeef0d9..c3e4094 100644
--- a/content/public/android/java/strings/translations/android_content_strings_am.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_am.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="am">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">ዓመት</translation>
+<translation id="1256337885411059545">ቪዲዮ ማጫወት አልተቻለም</translation>
+<translation id="7821540960913969614">ቀን ያዘጋጁ</translation>
+<translation id="3845599764535987402">ሰዓት</translation>
 <translation id="4932733599132424254">ቀን</translation>
 <translation id="6727102863431372879">አዘጋጅ</translation>
+<translation id="273860350361291195">ይቅርታ፣ ይህ ቪዲዮ ወደዚህ መሣሪያ በዥረት ለመልቀቅ ልክ የሆነ አይደለም።</translation>
+<translation id="7102218676258945610">ደቂቃ</translation>
+<translation id="4768459022382175196">ሰከንድ</translation>
 <translation id="5966707198760109579">ሳምንት</translation>
+<translation id="2410828433627930127">ይቅርታ፣ ይህ ቪዲዮ ሊጫወት አልቻለም።</translation>
+<translation id="7575803462290353686">ሰዓት ያዘጋጁ</translation>
 <translation id="8987927404178983737">ወር</translation>
+<translation id="4247305538398689241">ሳምንት ያዘጋጁ</translation>
+<translation id="2532336938189706096">የድር ዕይታ</translation>
+<translation id="2732718972699418926">ጥዋት</translation>
+<translation id="7096034533295549981">ቪዲዮን በመጫን ላይ</translation>
+<translation id="1542044944667958430">የድር ፍለጋ</translation>
 <translation id="6527303717912515753">አጋራ</translation>
 <translation id="1822429046913737220">ጥዋት/ከሰዓት</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">ሚሊሰከንድ</translation>
 <translation id="2841013758207633010">ሰዓት</translation>
 <translation id="6643016212128521049">አጽዳ</translation>
+<translation id="2429669115401274487">ከሰዓት</translation>
+<translation id="7781164152564914424">ወር ያዘጋጁ</translation>
 <translation id="6965382102122355670">ይሁን</translation>
+<translation id="6444070574980481588">ቀን እና ሰዓት ያዘጋጁ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ar.xtb b/content/public/android/java/strings/translations/android_content_strings_ar.xtb
index 9dd409e..bfd0964 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ar.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ar.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ar">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">عام</translation>
+<translation id="1256337885411059545">لا يمكن تشغيل الفيديو</translation>
+<translation id="7821540960913969614">تعيين التاريخ</translation>
+<translation id="3845599764535987402">الساعات</translation>
 <translation id="4932733599132424254">التاريخ</translation>
 <translation id="6727102863431372879">تعيين</translation>
+<translation id="273860350361291195">عذرًا، هذا الفيديو غير صالح للبث إلى هذا الجهاز.</translation>
+<translation id="7102218676258945610">الدقائق</translation>
+<translation id="4768459022382175196">الثواني</translation>
 <translation id="5966707198760109579">الأسبوع</translation>
+<translation id="2410828433627930127">عذرًا، لا يمكن تشغيل هذا الفيديو.</translation>
+<translation id="7575803462290353686">تعيين الوقت</translation>
 <translation id="8987927404178983737">شهر</translation>
+<translation id="4247305538398689241">تعيين الأسبوع</translation>
+<translation id="2532336938189706096">عرض الويب</translation>
+<translation id="2732718972699418926">صباحًا</translation>
+<translation id="7096034533295549981">تحميل الفيديو</translation>
+<translation id="1542044944667958430">بحث الويب</translation>
 <translation id="6527303717912515753">مشاركة</translation>
 <translation id="1822429046913737220">صباحًا/مساءً</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">مللي ثانية</translation>
 <translation id="2841013758207633010">الوقت</translation>
 <translation id="6643016212128521049">محو</translation>
+<translation id="2429669115401274487">مساءً</translation>
+<translation id="7781164152564914424">تعيين الشهر</translation>
 <translation id="6965382102122355670">موافق</translation>
+<translation id="6444070574980481588">تعيين التاريخ والوقت</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_bg.xtb b/content/public/android/java/strings/translations/android_content_strings_bg.xtb
index bff5172..50b108c 100644
--- a/content/public/android/java/strings/translations/android_content_strings_bg.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_bg.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="bg">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Година</translation>
+<translation id="1256337885411059545">Видеоклипът не може да се пусне</translation>
+<translation id="7821540960913969614">Задаване на датата</translation>
+<translation id="3845599764535987402">Час</translation>
 <translation id="4932733599132424254">Дата</translation>
 <translation id="6727102863431372879">Задаване</translation>
+<translation id="273860350361291195">За съжаление този видеоклип не е валиден за поточно предаване към устройството.</translation>
+<translation id="7102218676258945610">Mинута</translation>
+<translation id="4768459022382175196">Секунда</translation>
 <translation id="5966707198760109579">Седмица</translation>
+<translation id="2410828433627930127">За съжаление този видеоклип не може да се пусне.</translation>
+<translation id="7575803462290353686">Задаване на часа</translation>
 <translation id="8987927404178983737">Месец</translation>
+<translation id="4247305538398689241">Задаване на седмицата</translation>
+<translation id="2532336938189706096">Изглед в мрежата</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Клип: Зарежда се</translation>
+<translation id="1542044944667958430">Търсене в мрежата</translation>
 <translation id="6527303717912515753">Споделяне</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Милисекунда</translation>
 <translation id="2841013758207633010">Време</translation>
 <translation id="6643016212128521049">Изчистване</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Задаване на месеца</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Задаване на датата и часа</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ca.xtb b/content/public/android/java/strings/translations/android_content_strings_ca.xtb
index e8ec42f..310f9ce 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ca.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ca.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ca">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Any</translation>
+<translation id="1256337885411059545">No es pot reproduir el vídeo.</translation>
+<translation id="7821540960913969614">Defineix la data</translation>
+<translation id="3845599764535987402">Hora</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Configura</translation>
+<translation id="273860350361291195">Aquest vídeo no és vàlid per reproduir-lo en temps real en aquest dispositiu.</translation>
+<translation id="7102218676258945610">Minut</translation>
+<translation id="4768459022382175196">Segon</translation>
 <translation id="5966707198760109579">Setmana</translation>
+<translation id="2410828433627930127">No es pot reproduir aquest vídeo.</translation>
+<translation id="7575803462290353686">Defineix l'hora</translation>
 <translation id="8987927404178983737">Mes</translation>
+<translation id="4247305538398689241">Defineix la setmana</translation>
+<translation id="2532336938189706096">Visualització web</translation>
+<translation id="2732718972699418926">a.m.</translation>
+<translation id="7096034533295549981">Carregant vídeo</translation>
+<translation id="1542044944667958430">Cerca al web</translation>
 <translation id="6527303717912515753">Comparteix</translation>
 <translation id="1822429046913737220">a. m./p. m.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Mil·lisegon</translation>
 <translation id="2841013758207633010">Hora</translation>
 <translation id="6643016212128521049">Esborra</translation>
+<translation id="2429669115401274487">p.m.</translation>
+<translation id="7781164152564914424">Defineix el mes</translation>
 <translation id="6965382102122355670">D'acord</translation>
+<translation id="6444070574980481588">Defineix la data i l'hora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_cs.xtb b/content/public/android/java/strings/translations/android_content_strings_cs.xtb
index a38f9c8..392ab26 100644
--- a/content/public/android/java/strings/translations/android_content_strings_cs.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_cs.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="cs">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Rok</translation>
+<translation id="1256337885411059545">Video nelze přehrát</translation>
+<translation id="7821540960913969614">Nastavení data</translation>
+<translation id="3845599764535987402">Hodina</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Nastavit</translation>
+<translation id="273860350361291195">Video do zařízení nelze streamovat.</translation>
+<translation id="7102218676258945610">Minuta</translation>
+<translation id="4768459022382175196">Sekunda</translation>
 <translation id="5966707198760109579">Týden</translation>
+<translation id="2410828433627930127">Toto video nelze přehrát.</translation>
+<translation id="7575803462290353686">Nastavení času</translation>
 <translation id="8987927404178983737">Měsíc</translation>
+<translation id="4247305538398689241">Nastavení týdne</translation>
+<translation id="2532336938189706096">Webové zobrazení</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Načítání videa</translation>
+<translation id="1542044944667958430">Vyhledávání na webu</translation>
 <translation id="6527303717912515753">Sdílet</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">,</translation>
+<translation id="1768717197362323622">Milisekunda</translation>
 <translation id="2841013758207633010">Čas</translation>
 <translation id="6643016212128521049">Vymazat</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Nastavení měsíce</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Nastavení data a času</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_da.xtb b/content/public/android/java/strings/translations/android_content_strings_da.xtb
index 57953fe..9eff714 100644
--- a/content/public/android/java/strings/translations/android_content_strings_da.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_da.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="da">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">År</translation>
+<translation id="1256337885411059545">Videoen kan ikke afspilles</translation>
+<translation id="7821540960913969614">Angiv dato</translation>
+<translation id="3845599764535987402">Time</translation>
 <translation id="4932733599132424254">Dato</translation>
 <translation id="6727102863431372879">Angiv</translation>
+<translation id="273860350361291195">Denne video er ikke gyldig til streaming på denne enhed.</translation>
+<translation id="7102218676258945610">Minut</translation>
+<translation id="4768459022382175196">Sekund</translation>
 <translation id="5966707198760109579">Uge</translation>
+<translation id="2410828433627930127">Denne video kan ikke afspilles.</translation>
+<translation id="7575803462290353686">Angiv klokkeslæt</translation>
 <translation id="8987927404178983737">Måned</translation>
+<translation id="4247305538398689241">Angiv uge</translation>
+<translation id="2532336938189706096">Webvisning</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Videoen indlæses</translation>
+<translation id="1542044944667958430">Websøgning</translation>
 <translation id="6527303717912515753">Del</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisekund</translation>
 <translation id="2841013758207633010">Tid</translation>
 <translation id="6643016212128521049">Ryd</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Angiv måned</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Angiv dato og klokkeslæt</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_de.xtb b/content/public/android/java/strings/translations/android_content_strings_de.xtb
index 7364859..3732fac 100644
--- a/content/public/android/java/strings/translations/android_content_strings_de.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_de.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="de">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Jahr</translation>
+<translation id="1256337885411059545">Videowiedergabe nicht möglich</translation>
+<translation id="7821540960913969614">Datum festlegen</translation>
+<translation id="3845599764535987402">Stunde</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Festlegen</translation>
+<translation id="273860350361291195">Leider ist dieses Video nicht für Streaming auf diesem Gerät gültig.</translation>
+<translation id="7102218676258945610">Minute</translation>
+<translation id="4768459022382175196">Sekunde</translation>
 <translation id="5966707198760109579">Woche</translation>
+<translation id="2410828433627930127">Dieses Video kann leider nicht abgespielt werden.</translation>
+<translation id="7575803462290353686">Uhrzeit festlegen</translation>
 <translation id="8987927404178983737">Monat</translation>
+<translation id="4247305538398689241">Woche festlegen</translation>
+<translation id="2532336938189706096">Web-Ansicht</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Video wird geladen</translation>
+<translation id="1542044944667958430">Websuche</translation>
 <translation id="6527303717912515753">Teilen</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisekunde</translation>
 <translation id="2841013758207633010">Zeit</translation>
 <translation id="6643016212128521049">Löschen</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Monat festlegen</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Datum und Uhrzeit festlegen</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_el.xtb b/content/public/android/java/strings/translations/android_content_strings_el.xtb
index 350459e..c90cdda 100644
--- a/content/public/android/java/strings/translations/android_content_strings_el.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_el.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="el">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Έτος</translation>
+<translation id="1256337885411059545">Αδύνατη αναπαραγωγή βίντεο</translation>
+<translation id="7821540960913969614">Ορισμός ημερομηνίας</translation>
+<translation id="3845599764535987402">Ώρα</translation>
 <translation id="4932733599132424254">Ημερομηνία</translation>
 <translation id="6727102863431372879">Ορισμός</translation>
+<translation id="273860350361291195">Δυστυχώς, αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτήν τη συσκευή.</translation>
+<translation id="7102218676258945610">Λεπτό</translation>
+<translation id="4768459022382175196">Δευτερόλεπτο</translation>
 <translation id="5966707198760109579">Εβδομάδα</translation>
+<translation id="2410828433627930127">Δυστυχώς, δεν είναι δυνατή η αναπαραγωγή αυτού του βίντεο.</translation>
+<translation id="7575803462290353686">Ορισμός χρόνου</translation>
 <translation id="8987927404178983737">Μήνας</translation>
+<translation id="4247305538398689241">Ορισμός εβδομάδας</translation>
+<translation id="2532336938189706096">Προβολή ιστού</translation>
+<translation id="2732718972699418926">π.μ.</translation>
+<translation id="7096034533295549981">Φόρτωση βίντεο</translation>
+<translation id="1542044944667958430">Αναζήτηση στον Ιστό</translation>
 <translation id="6527303717912515753">Κοινή χρήση</translation>
 <translation id="1822429046913737220">Π.Μ./Μ.Μ.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Χιλιοστό του δευτερολέπτου</translation>
 <translation id="2841013758207633010">Ώρα</translation>
 <translation id="6643016212128521049">Εκκαθάριση</translation>
+<translation id="2429669115401274487">μ.μ.</translation>
+<translation id="7781164152564914424">Ορισμός μήνα</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Ορισμός ημερομηνίας και ώρας</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_en-GB.xtb b/content/public/android/java/strings/translations/android_content_strings_en-GB.xtb
index 19f5386..d6d09ce 100644
--- a/content/public/android/java/strings/translations/android_content_strings_en-GB.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_en-GB.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="en-GB">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Year</translation>
+<translation id="1256337885411059545">Cannot play video</translation>
+<translation id="7821540960913969614">Set date</translation>
+<translation id="3845599764535987402">Hour</translation>
 <translation id="4932733599132424254">Date</translation>
 <translation id="6727102863431372879">Set</translation>
+<translation id="273860350361291195">Sorry, this video is not valid for streaming to this device.</translation>
+<translation id="7102218676258945610">Minute</translation>
+<translation id="4768459022382175196">Second</translation>
 <translation id="5966707198760109579">Week</translation>
+<translation id="2410828433627930127">Sorry, this video cannot be played.</translation>
+<translation id="7575803462290353686">Set time</translation>
 <translation id="8987927404178983737">Month</translation>
+<translation id="4247305538398689241">Set week</translation>
+<translation id="2532336938189706096">Web View</translation>
+<translation id="2732718972699418926">a.m.</translation>
+<translation id="7096034533295549981">Loading video</translation>
+<translation id="1542044944667958430">Web search</translation>
 <translation id="6527303717912515753">Share</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisecond</translation>
 <translation id="2841013758207633010">Time</translation>
 <translation id="6643016212128521049">Clear</translation>
+<translation id="2429669115401274487">p.m.</translation>
+<translation id="7781164152564914424">Set month</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Set date and time</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_es-419.xtb b/content/public/android/java/strings/translations/android_content_strings_es-419.xtb
index 7e44632..9e5d118 100644
--- a/content/public/android/java/strings/translations/android_content_strings_es-419.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_es-419.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="es-419">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Año</translation>
+<translation id="1256337885411059545">No se puede reproducir el video.</translation>
+<translation id="7821540960913969614">Establecer fecha</translation>
+<translation id="3845599764535987402">Hora</translation>
 <translation id="4932733599132424254">Fecha</translation>
 <translation id="6727102863431372879">Establecer</translation>
+<translation id="273860350361291195">El video no se puede transmitir a este dispositivo.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Segundo</translation>
 <translation id="5966707198760109579">Semana</translation>
+<translation id="2410828433627930127">El video no se puede reproducir.</translation>
+<translation id="7575803462290353686">Establecer hora</translation>
 <translation id="8987927404178983737">Mes</translation>
+<translation id="4247305538398689241">Establecer semana</translation>
+<translation id="2532336938189706096">Vista web</translation>
+<translation id="2732718972699418926">a. m.</translation>
+<translation id="7096034533295549981">Cargando video</translation>
+<translation id="1542044944667958430">Búsqueda en la Web</translation>
 <translation id="6527303717912515753">Compartir</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisegundo</translation>
 <translation id="2841013758207633010">Hora</translation>
 <translation id="6643016212128521049">Borrar</translation>
+<translation id="2429669115401274487">p. m.</translation>
+<translation id="7781164152564914424">Establecer mes</translation>
 <translation id="6965382102122355670">Aceptar</translation>
+<translation id="6444070574980481588">Establecer fecha y hora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_es.xtb b/content/public/android/java/strings/translations/android_content_strings_es.xtb
index 0e57dff..9306872 100644
--- a/content/public/android/java/strings/translations/android_content_strings_es.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_es.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="es">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Año</translation>
+<translation id="1256337885411059545">No se puede reproducir el vídeo.</translation>
+<translation id="7821540960913969614">Definir fecha</translation>
+<translation id="3845599764535987402">Hora</translation>
 <translation id="4932733599132424254">Fecha</translation>
 <translation id="6727102863431372879">Establecer</translation>
+<translation id="273860350361291195">Este vídeo no se puede reproducir en este dispositivo.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Segundo</translation>
 <translation id="5966707198760109579">Semana</translation>
+<translation id="2410828433627930127">Este vídeo no se puede reproducir.</translation>
+<translation id="7575803462290353686">Definir hora</translation>
 <translation id="8987927404178983737">Mes</translation>
+<translation id="4247305538398689241">Definir semana</translation>
+<translation id="2532336938189706096">Vista web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Cargando vídeo</translation>
+<translation id="1542044944667958430">Búsqueda web</translation>
 <translation id="6527303717912515753">Compartir</translation>
 <translation id="1822429046913737220">A.M./P.M.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisegundo</translation>
 <translation id="2841013758207633010">Hora</translation>
 <translation id="6643016212128521049">Eliminar</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Establecer mes</translation>
 <translation id="6965382102122355670">Aceptar</translation>
+<translation id="6444070574980481588">Establecer fecha y hora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_fa.xtb b/content/public/android/java/strings/translations/android_content_strings_fa.xtb
index 25a6418..a08f004 100644
--- a/content/public/android/java/strings/translations/android_content_strings_fa.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_fa.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="fa">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">سال</translation>
+<translation id="1256337885411059545">ویدیو پخش نمی‌شود</translation>
+<translation id="7821540960913969614">تنظیم تاریخ</translation>
+<translation id="3845599764535987402">ساعت</translation>
 <translation id="4932733599132424254">تاریخ</translation>
 <translation id="6727102863431372879">تنظیم</translation>
+<translation id="273860350361291195">با عرض پوزش، این ویدیو برای پخش هم‌زمان در این دستگاه معتبر نیست.</translation>
+<translation id="7102218676258945610">دقیقه</translation>
+<translation id="4768459022382175196">ثانیه</translation>
 <translation id="5966707198760109579">هفته</translation>
+<translation id="2410828433627930127">با عرض پوزش، این ویدیو پخش نمی‌شود.</translation>
+<translation id="7575803462290353686">تنظیم زمان</translation>
 <translation id="8987927404178983737">ماه</translation>
+<translation id="4247305538398689241">تنظیم هفته</translation>
+<translation id="2532336938189706096">نمای وب</translation>
+<translation id="2732718972699418926">ق.ظ</translation>
+<translation id="7096034533295549981">بارگیری ویدیو</translation>
+<translation id="1542044944667958430">جستجوی وب</translation>
 <translation id="6527303717912515753">اشتراک‌گذاری</translation>
 <translation id="1822429046913737220">ق.ظ/ب.ظ</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">میلی‌ثانیه</translation>
 <translation id="2841013758207633010">زمان</translation>
 <translation id="6643016212128521049">پاک کردن</translation>
+<translation id="2429669115401274487">ب.ظ</translation>
+<translation id="7781164152564914424">تنظیم ماه</translation>
 <translation id="6965382102122355670">تأیید</translation>
+<translation id="6444070574980481588">تنظیم تاریخ و زمان</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_fi.xtb b/content/public/android/java/strings/translations/android_content_strings_fi.xtb
index 4e6f828..e68f0c4 100644
--- a/content/public/android/java/strings/translations/android_content_strings_fi.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_fi.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="fi">
+<translation id="376869769528291915">.</translation>
 <translation id="6015796118275082299">Vuosi</translation>
+<translation id="1256337885411059545">Videon toistaminen epäonnistui</translation>
+<translation id="7821540960913969614">Aseta päivämäärä</translation>
+<translation id="3845599764535987402">Tunti</translation>
 <translation id="4932733599132424254">Päiväys</translation>
 <translation id="6727102863431372879">Aseta</translation>
+<translation id="273860350361291195">Videota ei voi suoratoistaa tällä laitteella.</translation>
+<translation id="7102218676258945610">Minuutti</translation>
+<translation id="4768459022382175196">Sekunti</translation>
 <translation id="5966707198760109579">Viikko</translation>
+<translation id="2410828433627930127">Tätä videota ei voi toistaa.</translation>
+<translation id="7575803462290353686">Aseta aika</translation>
 <translation id="8987927404178983737">Kuukausi</translation>
+<translation id="4247305538398689241">Aseta viikko</translation>
+<translation id="2532336938189706096">Verkkonäkymä</translation>
+<translation id="2732718972699418926">ap</translation>
+<translation id="7096034533295549981">Videota ladataan</translation>
+<translation id="1542044944667958430">Verkkohaku</translation>
 <translation id="6527303717912515753">Jaa</translation>
 <translation id="1822429046913737220">AP/IP</translation>
+<translation id="5789643057113097023">,</translation>
+<translation id="1768717197362323622">Millisekunti</translation>
 <translation id="2841013758207633010">Aika</translation>
 <translation id="6643016212128521049">Tyhjennä</translation>
+<translation id="2429669115401274487">ip</translation>
+<translation id="7781164152564914424">Aseta kuukausi</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Aseta päivämäärä ja aika</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_fil.xtb b/content/public/android/java/strings/translations/android_content_strings_fil.xtb
index d2121d6..83c432e 100644
--- a/content/public/android/java/strings/translations/android_content_strings_fil.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_fil.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="fil">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Taon</translation>
+<translation id="1256337885411059545">Hindi ma-play ang video</translation>
+<translation id="7821540960913969614">Magtakda ng petsa</translation>
+<translation id="3845599764535987402">Oras</translation>
 <translation id="4932733599132424254">Petsa</translation>
 <translation id="6727102863431372879">Itakda</translation>
+<translation id="273860350361291195">Paumanhin, di-wasto ang video na ito para sa pag-stream sa device na ito.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Segundo</translation>
 <translation id="5966707198760109579">Linggo</translation>
+<translation id="2410828433627930127">Paumanhin, hindi mape-play ang video na ito.</translation>
+<translation id="7575803462290353686">Itakda ang oras</translation>
 <translation id="8987927404178983737">Buwan</translation>
+<translation id="4247305538398689241">Itakda ang linggo</translation>
+<translation id="2532336938189706096">View ng Web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Naglo-load</translation>
+<translation id="1542044944667958430">Paghahanap sa web</translation>
 <translation id="6527303717912515753">Ibahagi</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisecond</translation>
 <translation id="2841013758207633010">Oras</translation>
 <translation id="6643016212128521049">I-clear</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Itakda ang buwan</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Itakda ang petsa at oras</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_fr.xtb b/content/public/android/java/strings/translations/android_content_strings_fr.xtb
index d842982..40551c3 100644
--- a/content/public/android/java/strings/translations/android_content_strings_fr.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_fr.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="fr">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Année</translation>
+<translation id="1256337885411059545">Impossible de lire la vidéo.</translation>
+<translation id="7821540960913969614">Définir la date</translation>
+<translation id="3845599764535987402">Heure</translation>
 <translation id="4932733599132424254">Date</translation>
 <translation id="6727102863431372879">Définir</translation>
+<translation id="273860350361291195">Désolé, impossible de lire cette vidéo en streaming sur cet appareil.</translation>
+<translation id="7102218676258945610">Minute</translation>
+<translation id="4768459022382175196">Seconde</translation>
 <translation id="5966707198760109579">Semaine</translation>
+<translation id="2410828433627930127">Désolé, impossible de lire cette vidéo.</translation>
+<translation id="7575803462290353686">Définir l'heure</translation>
 <translation id="8987927404178983737">Mois</translation>
+<translation id="4247305538398689241">Définir la semaine</translation>
+<translation id="2532336938189706096">Vue Web</translation>
+<translation id="2732718972699418926">a.m.</translation>
+<translation id="7096034533295549981">Chargement vidéo…</translation>
+<translation id="1542044944667958430">Recherche sur le Web</translation>
 <translation id="6527303717912515753">Partager</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milliseconde</translation>
 <translation id="2841013758207633010">Heure</translation>
 <translation id="6643016212128521049">Effacer</translation>
+<translation id="2429669115401274487">p.m.</translation>
+<translation id="7781164152564914424">Définir le mois</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Définir la date et l'heure</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_hi.xtb b/content/public/android/java/strings/translations/android_content_strings_hi.xtb
index 9633b54..fadd511 100644
--- a/content/public/android/java/strings/translations/android_content_strings_hi.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_hi.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="hi">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">वर्ष</translation>
+<translation id="1256337885411059545">वीडियो नहीं चलाया जा सकता</translation>
+<translation id="7821540960913969614">दिनांक सेट करें</translation>
+<translation id="3845599764535987402">घंटा</translation>
 <translation id="4932733599132424254">दिनांक</translation>
 <translation id="6727102863431372879">सेट करें</translation>
+<translation id="273860350361291195">क्षमा करें, यह वीडियो इस उपकरण पर स्‍ट्रीम करने के लिए मान्य नहीं है.</translation>
+<translation id="7102218676258945610">मिनट</translation>
+<translation id="4768459022382175196">सेकंड</translation>
 <translation id="5966707198760109579">सप्ताह</translation>
+<translation id="2410828433627930127">क्षमा करें, यह वीडियो नहीं चलाया जा सकता.</translation>
+<translation id="7575803462290353686">समय सेट करें</translation>
 <translation id="8987927404178983737">माह</translation>
+<translation id="4247305538398689241">सप्ताह सेट करें</translation>
+<translation id="2532336938189706096">वेब दृश्य</translation>
+<translation id="2732718972699418926">पूर्वाह्न</translation>
+<translation id="7096034533295549981">वीडियो लोड हो रहा है</translation>
+<translation id="1542044944667958430">वेब खोज</translation>
 <translation id="6527303717912515753">साझा करें</translation>
 <translation id="1822429046913737220">पूर्वाह्न/अपराह्न</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">मिलीसेकंड</translation>
 <translation id="2841013758207633010">समय</translation>
 <translation id="6643016212128521049">साफ़ करें</translation>
+<translation id="2429669115401274487">अपराह्न</translation>
+<translation id="7781164152564914424">माह सेट करें</translation>
 <translation id="6965382102122355670">ठीक</translation>
+<translation id="6444070574980481588">दिनांक और समय सेट करें</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_hr.xtb b/content/public/android/java/strings/translations/android_content_strings_hr.xtb
index 7ba62cc..fabd656 100644
--- a/content/public/android/java/strings/translations/android_content_strings_hr.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_hr.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="hr">
+<translation id="376869769528291915">.</translation>
 <translation id="6015796118275082299">Godina</translation>
+<translation id="1256337885411059545">Nije moguće reprod. videozapis</translation>
+<translation id="7821540960913969614">Postavite datum</translation>
+<translation id="3845599764535987402">sat</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Postavi</translation>
+<translation id="273860350361291195">Videozapis nije valjan za strujanje na uređaj.</translation>
+<translation id="7102218676258945610">minuta</translation>
+<translation id="4768459022382175196">sekunda</translation>
 <translation id="5966707198760109579">Tjedan</translation>
+<translation id="2410828433627930127">Nije moguće reproducirati taj videozapis.</translation>
+<translation id="7575803462290353686">Postavite vrijeme</translation>
 <translation id="8987927404178983737">Mjesec</translation>
+<translation id="4247305538398689241">Postavite tjedan</translation>
+<translation id="2532336938189706096">Web-prikaz</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Učitavanje videa</translation>
+<translation id="1542044944667958430">Pretraživanje weba</translation>
 <translation id="6527303717912515753">Podijeli</translation>
 <translation id="1822429046913737220">prijepodne/poslijepodne</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">milisekunda</translation>
 <translation id="2841013758207633010">Vrijeme</translation>
 <translation id="6643016212128521049">Izbriši</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Postavite mjesec</translation>
 <translation id="6965382102122355670">U redu</translation>
+<translation id="6444070574980481588">Postavite datum i vrijeme</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_hu.xtb b/content/public/android/java/strings/translations/android_content_strings_hu.xtb
index 14e38b5..e128430 100644
--- a/content/public/android/java/strings/translations/android_content_strings_hu.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_hu.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="hu">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Év</translation>
+<translation id="1256337885411059545">Nem lehet lejátszani a videót</translation>
+<translation id="7821540960913969614">Dátum beállítása</translation>
+<translation id="3845599764535987402">Óra</translation>
 <translation id="4932733599132424254">Dátum</translation>
 <translation id="6727102863431372879">Beállítás</translation>
+<translation id="273860350361291195">Sajnos ezt a videót nem lehet erre az eszközre sugározni.</translation>
+<translation id="7102218676258945610">Perc</translation>
+<translation id="4768459022382175196">Másodperc</translation>
 <translation id="5966707198760109579">Hét</translation>
+<translation id="2410828433627930127">Sajnos a videót nem lehet lejátszani.</translation>
+<translation id="7575803462290353686">Idő beállítása</translation>
 <translation id="8987927404178983737">hónap</translation>
+<translation id="4247305538398689241">Hét beállítása</translation>
+<translation id="2532336938189706096">Internetes megtekintés</translation>
+<translation id="2732718972699418926">de.</translation>
+<translation id="7096034533295549981">Videó betöltése</translation>
+<translation id="1542044944667958430">Internetes keresés</translation>
 <translation id="6527303717912515753">Megosztás</translation>
 <translation id="1822429046913737220">de./du.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Ezredmásodperc</translation>
 <translation id="2841013758207633010">Idő</translation>
 <translation id="6643016212128521049">Törlés</translation>
+<translation id="2429669115401274487">du.</translation>
+<translation id="7781164152564914424">Hónap beállítása</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Dátum és idő beállítása</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_id.xtb b/content/public/android/java/strings/translations/android_content_strings_id.xtb
index 20fb98a..75994c6 100644
--- a/content/public/android/java/strings/translations/android_content_strings_id.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_id.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="id">
+<translation id="376869769528291915">.</translation>
 <translation id="6015796118275082299">Tahun</translation>
+<translation id="1256337885411059545">Tidak dapat memutar video</translation>
+<translation id="7821540960913969614">Setel tanggal</translation>
+<translation id="3845599764535987402">Jam</translation>
 <translation id="4932733599132424254">Tanggal</translation>
 <translation id="6727102863431372879">Setel</translation>
+<translation id="273860350361291195">Maaf, video ini tidak dapat di-streaming ke perangkat ini.</translation>
+<translation id="7102218676258945610">Menit</translation>
+<translation id="4768459022382175196">Detik</translation>
 <translation id="5966707198760109579">Minggu</translation>
+<translation id="2410828433627930127">Maaf, video tidak dapat diputar.</translation>
+<translation id="7575803462290353686">Setel waktu</translation>
 <translation id="8987927404178983737">Bulan</translation>
+<translation id="4247305538398689241">Setel minggu</translation>
+<translation id="2532336938189706096">Tampilan Web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Memuat video</translation>
+<translation id="1542044944667958430">Penelusuran web</translation>
 <translation id="6527303717912515753">Bagikan</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">:</translation>
+<translation id="1768717197362323622">Milidetik</translation>
 <translation id="2841013758207633010">Waktu</translation>
 <translation id="6643016212128521049">Hapus</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Setel bulan</translation>
 <translation id="6965382102122355670">Oke</translation>
+<translation id="6444070574980481588">Setel tanggal dan waktu</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_it.xtb b/content/public/android/java/strings/translations/android_content_strings_it.xtb
index 8324cdb..a2ae291 100644
--- a/content/public/android/java/strings/translations/android_content_strings_it.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_it.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="it">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Anno</translation>
+<translation id="1256337885411059545">Impossibile riprodurre il video</translation>
+<translation id="7821540960913969614">Imposta data</translation>
+<translation id="3845599764535987402">Ora</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Imposta</translation>
+<translation id="273860350361291195">Spiacenti, questo video non può essere visualizzato in streaming su questo dispositivo.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Secondo</translation>
 <translation id="5966707198760109579">Settimana</translation>
+<translation id="2410828433627930127">Spiacenti, impossibile riprodurre il video.</translation>
+<translation id="7575803462290353686">Imposta ora</translation>
 <translation id="8987927404178983737">Mese</translation>
+<translation id="4247305538398689241">Imposta settimana</translation>
+<translation id="2532336938189706096">Visualizzazione web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Caricamento video</translation>
+<translation id="1542044944667958430">Ricerca Google</translation>
 <translation id="6527303717912515753">Condividi</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisecondo</translation>
 <translation id="2841013758207633010">Ora</translation>
 <translation id="6643016212128521049">Cancella</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Imposta mese</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Imposta data e ora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_iw.xtb b/content/public/android/java/strings/translations/android_content_strings_iw.xtb
index df129fb..3fba1ac 100644
--- a/content/public/android/java/strings/translations/android_content_strings_iw.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_iw.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="iw">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">שנה</translation>
+<translation id="1256337885411059545">לא ניתן להפעיל את הסרטון</translation>
+<translation id="7821540960913969614">הגדרת תאריך</translation>
+<translation id="3845599764535987402">שעה</translation>
 <translation id="4932733599132424254">תאריך</translation>
 <translation id="6727102863431372879">הגדר</translation>
+<translation id="273860350361291195">מצטערים. הזרמת הסרטון הזה למכשיר הזה אינה חוקית.</translation>
+<translation id="7102218676258945610">דקה</translation>
+<translation id="4768459022382175196">שנייה</translation>
 <translation id="5966707198760109579">שבוע</translation>
+<translation id="2410828433627930127">מצטערים. לא ניתן להפעיל את הסרטון הזה.</translation>
+<translation id="7575803462290353686">הגדרת שעה</translation>
 <translation id="8987927404178983737">חודש</translation>
+<translation id="4247305538398689241">הגדרת שבוע</translation>
+<translation id="2532336938189706096">תצוגת אינטרנט</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">טוען סרטון</translation>
+<translation id="1542044944667958430">‏חיפוש Google</translation>
 <translation id="6527303717912515753">שתף</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">אלפית שנייה</translation>
 <translation id="2841013758207633010">שעה</translation>
 <translation id="6643016212128521049">נקה</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">הגדרת חודש</translation>
 <translation id="6965382102122355670">אישור</translation>
+<translation id="6444070574980481588">הגדרת תאריך ושעה</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ja.xtb b/content/public/android/java/strings/translations/android_content_strings_ja.xtb
index ec4f15c..a425f6e 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ja.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ja.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ja">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">年</translation>
+<translation id="1256337885411059545">動画を再生できません</translation>
+<translation id="7821540960913969614">日付の設定</translation>
+<translation id="3845599764535987402">時</translation>
 <translation id="4932733599132424254">日付</translation>
 <translation id="6727102863431372879">設定</translation>
+<translation id="273860350361291195">この動画はご使用のデバイスではストリーミングできません。</translation>
+<translation id="7102218676258945610">分</translation>
+<translation id="4768459022382175196">秒</translation>
 <translation id="5966707198760109579">週</translation>
+<translation id="2410828433627930127">この動画は再生できません。</translation>
+<translation id="7575803462290353686">時間の設定</translation>
 <translation id="8987927404178983737">月</translation>
+<translation id="4247305538398689241">週の設定</translation>
+<translation id="2532336938189706096">ウェブ表示</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">動画を読み込み中</translation>
+<translation id="1542044944667958430">ウェブ検索</translation>
 <translation id="6527303717912515753">共有</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">ミリ秒</translation>
 <translation id="2841013758207633010">時間</translation>
 <translation id="6643016212128521049">クリア</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">月の設定</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">日時の設定</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ko.xtb b/content/public/android/java/strings/translations/android_content_strings_ko.xtb
index 6e12aba..703aa13 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ko.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ko.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ko">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">연도</translation>
+<translation id="1256337885411059545">동영상 재생 안됨</translation>
+<translation id="7821540960913969614">날짜 설정</translation>
+<translation id="3845599764535987402">시</translation>
 <translation id="4932733599132424254">날짜</translation>
 <translation id="6727102863431372879">설정</translation>
+<translation id="273860350361291195">죄송합니다. 이 동영상은 이 기기로 스트리밍할 수 없습니다.</translation>
+<translation id="7102218676258945610">분</translation>
+<translation id="4768459022382175196">초</translation>
 <translation id="5966707198760109579">주</translation>
+<translation id="2410828433627930127">동영상을 재생할 수 없습니다.</translation>
+<translation id="7575803462290353686">시간 설정</translation>
 <translation id="8987927404178983737">월</translation>
+<translation id="4247305538398689241">주 설정</translation>
+<translation id="2532336938189706096">웹 보기</translation>
+<translation id="2732718972699418926">오전</translation>
+<translation id="7096034533295549981">동영상 로드 중</translation>
+<translation id="1542044944667958430">웹 검색</translation>
 <translation id="6527303717912515753">공유</translation>
 <translation id="1822429046913737220">오전/오후</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">밀리초</translation>
 <translation id="2841013758207633010">시간</translation>
 <translation id="6643016212128521049">삭제</translation>
+<translation id="2429669115401274487">오후</translation>
+<translation id="7781164152564914424">월 설정</translation>
 <translation id="6965382102122355670">확인</translation>
+<translation id="6444070574980481588">날짜 및 시간 설정</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_lt.xtb b/content/public/android/java/strings/translations/android_content_strings_lt.xtb
index 22bed3d..3b52931 100644
--- a/content/public/android/java/strings/translations/android_content_strings_lt.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_lt.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="lt">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Metai</translation>
+<translation id="1256337885411059545">Nepavyksta paleisti vaizdo įrašo</translation>
+<translation id="7821540960913969614">Nustatykite datą</translation>
+<translation id="3845599764535987402">Valanda</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Nustatyti</translation>
+<translation id="273860350361291195">Apgailestaujame, šis vaizdo įrašas yra netinkamas perduoti srautu į šį įrenginį.</translation>
+<translation id="7102218676258945610">Minutė</translation>
+<translation id="4768459022382175196">Sekundė</translation>
 <translation id="5966707198760109579">Savaitė</translation>
+<translation id="2410828433627930127">Apgailestaujame, šio vaizdo įrašo negalima paleisti.</translation>
+<translation id="7575803462290353686">Nustatykite laiką</translation>
 <translation id="8987927404178983737">Mėnuo</translation>
+<translation id="4247305538398689241">Nustatykite savaitę</translation>
+<translation id="2532336938189706096">Žiniatinklio rodinys</translation>
+<translation id="2732718972699418926">priešpiet</translation>
+<translation id="7096034533295549981">Įkel. v. įrašas</translation>
+<translation id="1542044944667958430">Žiniatinklio paieška</translation>
 <translation id="6527303717912515753">Bendrinti</translation>
 <translation id="1822429046913737220">iki pietų / po pietų</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisekundė</translation>
 <translation id="2841013758207633010">Laikas</translation>
 <translation id="6643016212128521049">Išvalyti</translation>
+<translation id="2429669115401274487">popiet</translation>
+<translation id="7781164152564914424">Nustatykite mėnesį</translation>
 <translation id="6965382102122355670">Gerai</translation>
+<translation id="6444070574980481588">Nustatykite datą ir laiką</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_lv.xtb b/content/public/android/java/strings/translations/android_content_strings_lv.xtb
index eb3c516..512d302 100644
--- a/content/public/android/java/strings/translations/android_content_strings_lv.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_lv.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="lv">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Gads</translation>
+<translation id="1256337885411059545">Nevar atskaņot videoklipu.</translation>
+<translation id="7821540960913969614">Datuma iestatīšana</translation>
+<translation id="3845599764535987402">Stundas</translation>
 <translation id="4932733599132424254">Datums</translation>
 <translation id="6727102863431372879">Iestatīt</translation>
+<translation id="273860350361291195">Diemžēl šo videoklipu nevar straumēt šajā ierīcē.</translation>
+<translation id="7102218676258945610">Minūtes</translation>
+<translation id="4768459022382175196">Sekundes</translation>
 <translation id="5966707198760109579">Nedēļa</translation>
+<translation id="2410828433627930127">Diemžēl šo videoklipu nevar atskaņot.</translation>
+<translation id="7575803462290353686">Laika iestatīšana</translation>
 <translation id="8987927404178983737">Mēnesis</translation>
+<translation id="4247305538398689241">Nedēļas iestatīšana</translation>
+<translation id="2532336938189706096">Tīmekļa skatījums</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Video ielāde</translation>
+<translation id="1542044944667958430">Meklēšana tīmeklī</translation>
 <translation id="6527303717912515753">Kopīgot</translation>
 <translation id="1822429046913737220">priekšpusdienā/pēcpusdienā</translation>
+<translation id="5789643057113097023">:</translation>
+<translation id="1768717197362323622">Milisekundes</translation>
 <translation id="2841013758207633010">Laiks</translation>
 <translation id="6643016212128521049">Notīrīt</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Mēneša iestatīšana</translation>
 <translation id="6965382102122355670">Labi</translation>
+<translation id="6444070574980481588">Datuma un laika iestatīšana</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_nl.xtb b/content/public/android/java/strings/translations/android_content_strings_nl.xtb
index ee25418..55d31a6 100644
--- a/content/public/android/java/strings/translations/android_content_strings_nl.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_nl.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="nl">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Jaar</translation>
+<translation id="1256337885411059545">Kan video niet afspelen</translation>
+<translation id="7821540960913969614">Datum instellen</translation>
+<translation id="3845599764535987402">Uur</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Instellen</translation>
+<translation id="273860350361291195">Kan deze video niet streamen naar dit apparaat.</translation>
+<translation id="7102218676258945610">Minuut</translation>
+<translation id="4768459022382175196">Seconde</translation>
 <translation id="5966707198760109579">Week</translation>
+<translation id="2410828433627930127">Deze video kan niet worden afgespeeld.</translation>
+<translation id="7575803462290353686">Tijd instellen</translation>
 <translation id="8987927404178983737">Maand</translation>
+<translation id="4247305538398689241">Week instellen</translation>
+<translation id="2532336938189706096">Webweergave</translation>
+<translation id="2732718972699418926">a.m.</translation>
+<translation id="7096034533295549981">Video laden</translation>
+<translation id="1542044944667958430">Zoeken op internet</translation>
 <translation id="6527303717912515753">Delen</translation>
 <translation id="1822429046913737220">a.m./p.m.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milliseconde</translation>
 <translation id="2841013758207633010">Tijd</translation>
 <translation id="6643016212128521049">Wissen</translation>
+<translation id="2429669115401274487">p.m.</translation>
+<translation id="7781164152564914424">Maand instellen</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Datum en tijd instellen</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_no.xtb b/content/public/android/java/strings/translations/android_content_strings_no.xtb
index 0ce7c96..572994c 100644
--- a/content/public/android/java/strings/translations/android_content_strings_no.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_no.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="no">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">År</translation>
+<translation id="1256337885411059545">Kan ikke spille av videoen</translation>
+<translation id="7821540960913969614">Angi dato</translation>
+<translation id="3845599764535987402">Time</translation>
 <translation id="4932733599132424254">Dato</translation>
 <translation id="6727102863431372879">Angi</translation>
+<translation id="273860350361291195">Beklager, videoen er ikke gyldig for strømming på denne enheten.</translation>
+<translation id="7102218676258945610">Minutt</translation>
+<translation id="4768459022382175196">Sekund</translation>
 <translation id="5966707198760109579">Uke</translation>
+<translation id="2410828433627930127">Beklager, videoen kan ikke spilles av.</translation>
+<translation id="7575803462290353686">Angi tid</translation>
 <translation id="8987927404178983737">Måned</translation>
+<translation id="4247305538398689241">Angi uke</translation>
+<translation id="2532336938189706096">Nettvisning</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Laster inn videoen ...</translation>
+<translation id="1542044944667958430">Nettsøk</translation>
 <translation id="6527303717912515753">Del</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Millisekund</translation>
 <translation id="2841013758207633010">Klokkeslett</translation>
 <translation id="6643016212128521049">Tøm</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Angi måned</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Angi dato og klokkeslett</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_pl.xtb b/content/public/android/java/strings/translations/android_content_strings_pl.xtb
index 5438a5d..527450b 100644
--- a/content/public/android/java/strings/translations/android_content_strings_pl.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_pl.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="pl">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Rok</translation>
+<translation id="1256337885411059545">Nie można odtworzyć filmu</translation>
+<translation id="7821540960913969614">Ustaw datę</translation>
+<translation id="3845599764535987402">Godzina</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Ustaw</translation>
+<translation id="273860350361291195">Tego filmu nie można przesłać na to urządzenie.</translation>
+<translation id="7102218676258945610">Minuta</translation>
+<translation id="4768459022382175196">Sekunda</translation>
 <translation id="5966707198760109579">Tydzień</translation>
+<translation id="2410828433627930127">Tego filmu nie można odtworzyć.</translation>
+<translation id="7575803462290353686">Ustaw czas</translation>
 <translation id="8987927404178983737">Miesiąc</translation>
+<translation id="4247305538398689241">Ustaw tydzień</translation>
+<translation id="2532336938189706096">Widok sieci</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Wczytuję film</translation>
+<translation id="1542044944667958430">Wyszukaj w Google</translation>
 <translation id="6527303717912515753">Udostępnij</translation>
 <translation id="1822429046913737220">rano/po południu</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisekunda</translation>
 <translation id="2841013758207633010">Godzina</translation>
 <translation id="6643016212128521049">Wyczyść</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Ustaw miesiąc</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Ustaw datę i godzinę</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_pt-BR.xtb b/content/public/android/java/strings/translations/android_content_strings_pt-BR.xtb
index ff818b0..1688043 100644
--- a/content/public/android/java/strings/translations/android_content_strings_pt-BR.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_pt-BR.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="pt-BR">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Ano</translation>
+<translation id="1256337885411059545">Não é possível reproduzir vídeo</translation>
+<translation id="7821540960913969614">Definir data</translation>
+<translation id="3845599764535987402">Hora</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Definir</translation>
+<translation id="273860350361291195">Não é possível realizar o streaming deste vídeo para este dispositivo.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Segundo</translation>
 <translation id="5966707198760109579">Semana</translation>
+<translation id="2410828433627930127">Não é possível reproduzir este vídeo.</translation>
+<translation id="7575803462290353686">Definir hora</translation>
 <translation id="8987927404178983737">Mês</translation>
+<translation id="4247305538398689241">Definir semana</translation>
+<translation id="2532336938189706096">Visualização da Web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Carregando vídeo</translation>
+<translation id="1542044944667958430">Pesquisa da Web</translation>
 <translation id="6527303717912515753">Compartilhar</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milissegundo</translation>
 <translation id="2841013758207633010">Tempo</translation>
 <translation id="6643016212128521049">Limpar</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Definir mês</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Definir data e hora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_pt-PT.xtb b/content/public/android/java/strings/translations/android_content_strings_pt-PT.xtb
index 09060bd..5483b44 100644
--- a/content/public/android/java/strings/translations/android_content_strings_pt-PT.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_pt-PT.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="pt-PT">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Ano</translation>
+<translation id="1256337885411059545">Impossível reproduzir vídeo</translation>
+<translation id="7821540960913969614">Definir data</translation>
+<translation id="3845599764535987402">Hora</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Definir</translation>
+<translation id="273860350361291195">Este vídeo não é válido para transmissão em fluxo contínuo neste dispositivo.</translation>
+<translation id="7102218676258945610">Minuto</translation>
+<translation id="4768459022382175196">Segundo</translation>
 <translation id="5966707198760109579">Semana</translation>
+<translation id="2410828433627930127">Não é possível reproduzir este vídeo.</translation>
+<translation id="7575803462290353686">Definir hora</translation>
 <translation id="8987927404178983737">Mês</translation>
+<translation id="4247305538398689241">Definir semana</translation>
+<translation id="2532336938189706096">Visualização na Web</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">A carregar vídeo</translation>
+<translation id="1542044944667958430">Pesquisa Web</translation>
 <translation id="6527303717912515753">Partilhar</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milissegundo</translation>
 <translation id="2841013758207633010">Tempo</translation>
 <translation id="6643016212128521049">Limpar</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Definir mês</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Definir data e hora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ro.xtb b/content/public/android/java/strings/translations/android_content_strings_ro.xtb
index 1ba162e..43a5363 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ro.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ro.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ro">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">An</translation>
+<translation id="1256337885411059545">Nu se poate reda videoclipul</translation>
+<translation id="7821540960913969614">Setați data</translation>
+<translation id="3845599764535987402">Oră</translation>
 <translation id="4932733599132424254">Data</translation>
 <translation id="6727102863431372879">Setați</translation>
+<translation id="273860350361291195">Ne pare rău, acest videoclip nu este valid pentru transmitere în flux pe acest dispozitiv.</translation>
+<translation id="7102218676258945610">Minut</translation>
+<translation id="4768459022382175196">Secundă</translation>
 <translation id="5966707198760109579">Săptămână</translation>
+<translation id="2410828433627930127">Ne pare rău, acest videoclip nu poate fi redat.</translation>
+<translation id="7575803462290353686">Setați ora</translation>
 <translation id="8987927404178983737">Lună</translation>
+<translation id="4247305538398689241">Setați săptămâna</translation>
+<translation id="2532336938189706096">Vizualizare pe web</translation>
+<translation id="2732718972699418926">a.m.</translation>
+<translation id="7096034533295549981">Se încarcă video</translation>
+<translation id="1542044944667958430">Căutare pe web</translation>
 <translation id="6527303717912515753">Distribuiți</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisecundă</translation>
 <translation id="2841013758207633010">Oră</translation>
 <translation id="6643016212128521049">Ștergeți</translation>
+<translation id="2429669115401274487">p.m.</translation>
+<translation id="7781164152564914424">Setați luna</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Setați data și ora</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_ru.xtb b/content/public/android/java/strings/translations/android_content_strings_ru.xtb
index c4d317f..47d01f4 100644
--- a/content/public/android/java/strings/translations/android_content_strings_ru.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_ru.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ru">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Год</translation>
+<translation id="1256337885411059545">Не удается воспроизвести видео</translation>
+<translation id="7821540960913969614">Выберите дату</translation>
+<translation id="3845599764535987402">Часы</translation>
 <translation id="4932733599132424254">Дата</translation>
 <translation id="6727102863431372879">Установить</translation>
+<translation id="273860350361291195">Невозможно воспроизвести видео на этом устройстве</translation>
+<translation id="7102218676258945610">Минуты</translation>
+<translation id="4768459022382175196">Секунды</translation>
 <translation id="5966707198760109579">Неделя</translation>
+<translation id="2410828433627930127">Невозможно воспроизвести видео.</translation>
+<translation id="7575803462290353686">Установите время</translation>
 <translation id="8987927404178983737">Месяц</translation>
+<translation id="4247305538398689241">Выберите неделю</translation>
+<translation id="2532336938189706096">Веб-версия</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Загрузка видео…</translation>
+<translation id="1542044944667958430">Веб-поиск</translation>
 <translation id="6527303717912515753">Поделиться</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">:</translation>
+<translation id="1768717197362323622">Миллисекунды</translation>
 <translation id="2841013758207633010">Время</translation>
 <translation id="6643016212128521049">Очистить</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Выберите месяц</translation>
 <translation id="6965382102122355670">ОК</translation>
+<translation id="6444070574980481588">Установите дату и время</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_sk.xtb b/content/public/android/java/strings/translations/android_content_strings_sk.xtb
index 82e2d6e..5cbb638 100644
--- a/content/public/android/java/strings/translations/android_content_strings_sk.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_sk.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="sk">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Rok</translation>
+<translation id="1256337885411059545">Video sa nedá prehrať</translation>
+<translation id="7821540960913969614">Nastavenie dátumu</translation>
+<translation id="3845599764535987402">Hodina</translation>
 <translation id="4932733599132424254">Dátum</translation>
 <translation id="6727102863431372879">Nastaviť</translation>
+<translation id="273860350361291195">Je nám to ľúto, ale toto video sa nedá streamovať do tohto zariadenia.</translation>
+<translation id="7102218676258945610">Minúta</translation>
+<translation id="4768459022382175196">Sekunda</translation>
 <translation id="5966707198760109579">Týždeň</translation>
+<translation id="2410828433627930127">Je nám to ľúto, ale toto video sa nedá prehrať.</translation>
+<translation id="7575803462290353686">Nastavenie času</translation>
 <translation id="8987927404178983737">Mesiac</translation>
+<translation id="4247305538398689241">Nastavenie týždňa</translation>
+<translation id="2532336938189706096">Webové zobrazenie</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Načítanie videa</translation>
+<translation id="1542044944667958430">Vyhľadávanie na webe</translation>
 <translation id="6527303717912515753">Zdieľať</translation>
 <translation id="1822429046913737220">dop. / odp.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisekunda</translation>
 <translation id="2841013758207633010">Čas</translation>
 <translation id="6643016212128521049">Vymazať</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Nastavenie mesiaca</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Nastavenie dátumu a času</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_sl.xtb b/content/public/android/java/strings/translations/android_content_strings_sl.xtb
index 82d62c2..9cd710e 100644
--- a/content/public/android/java/strings/translations/android_content_strings_sl.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_sl.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="sl">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Leto</translation>
+<translation id="1256337885411059545">Videa ni mogoče predvajati</translation>
+<translation id="7821540960913969614">Nastavitev datuma</translation>
+<translation id="3845599764535987402">Ura</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Nastavi</translation>
+<translation id="273860350361291195">Ta video ni veljaven za pretakanje v to napravo.</translation>
+<translation id="7102218676258945610">Minuta</translation>
+<translation id="4768459022382175196">Sekunda</translation>
 <translation id="5966707198760109579">Teden</translation>
+<translation id="2410828433627930127">Tega videa ni mogoče predvajati.</translation>
+<translation id="7575803462290353686">Nastavitev časa</translation>
 <translation id="8987927404178983737">Mesec</translation>
+<translation id="4247305538398689241">Nastavitev tedna</translation>
+<translation id="2532336938189706096">Spletni pogled</translation>
+<translation id="2732718972699418926">dop.</translation>
+<translation id="7096034533295549981">Nalaganje videa</translation>
+<translation id="1542044944667958430">Spletno iskanje</translation>
 <translation id="6527303717912515753">Skupna raba</translation>
 <translation id="1822429046913737220">Dopoldne/popoldne</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisekunda</translation>
 <translation id="2841013758207633010">Čas</translation>
 <translation id="6643016212128521049">Počisti</translation>
+<translation id="2429669115401274487">pop.</translation>
+<translation id="7781164152564914424">Nastavitev meseca</translation>
 <translation id="6965382102122355670">V redu</translation>
+<translation id="6444070574980481588">Nastavitev datuma in časa</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_sr.xtb b/content/public/android/java/strings/translations/android_content_strings_sr.xtb
index 287f08e..dfa2434 100644
--- a/content/public/android/java/strings/translations/android_content_strings_sr.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_sr.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="sr">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Година</translation>
+<translation id="1256337885411059545">Није могуће пустити видео</translation>
+<translation id="7821540960913969614">Подесите датум</translation>
+<translation id="3845599764535987402">Сат</translation>
 <translation id="4932733599132424254">Датум</translation>
 <translation id="6727102863431372879">Постави</translation>
+<translation id="273860350361291195">Жао нам је, овај видео није погодан за стриминг на овом уређају.</translation>
+<translation id="7102218676258945610">Минут</translation>
+<translation id="4768459022382175196">Секунд</translation>
 <translation id="5966707198760109579">Недеља</translation>
+<translation id="2410828433627930127">Жао нам је, није могуће пустити овај видео.</translation>
+<translation id="7575803462290353686">Подесите време</translation>
 <translation id="8987927404178983737">Месец</translation>
+<translation id="4247305538398689241">Подесите недељу</translation>
+<translation id="2532336938189706096">Веб-приказ</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Учитавање видеа</translation>
+<translation id="1542044944667958430">Веб-претрага</translation>
 <translation id="6527303717912515753">Дели</translation>
 <translation id="1822429046913737220">пре подне/по подне</translation>
+<translation id="5789643057113097023">,</translation>
+<translation id="1768717197362323622">Милисекунд</translation>
 <translation id="2841013758207633010">Време</translation>
 <translation id="6643016212128521049">Обриши</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Подесите месец</translation>
 <translation id="6965382102122355670">Потврди</translation>
+<translation id="6444070574980481588">Подесите датум и време</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_sv.xtb b/content/public/android/java/strings/translations/android_content_strings_sv.xtb
index 2ec989e..7453238 100644
--- a/content/public/android/java/strings/translations/android_content_strings_sv.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_sv.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="sv">
+<translation id="376869769528291915">.</translation>
 <translation id="6015796118275082299">År</translation>
+<translation id="1256337885411059545">Det går inte att spela upp video</translation>
+<translation id="7821540960913969614">Ange datum</translation>
+<translation id="3845599764535987402">Timme</translation>
 <translation id="4932733599132424254">Datum</translation>
 <translation id="6727102863431372879">Ange</translation>
+<translation id="273860350361291195">Det går tyvärr inte att spela upp videon på den här enheten.</translation>
+<translation id="7102218676258945610">Minut</translation>
+<translation id="4768459022382175196">Sekund</translation>
 <translation id="5966707198760109579">Vecka</translation>
+<translation id="2410828433627930127">Det går tyvärr inte att spela upp den här videon.</translation>
+<translation id="7575803462290353686">Ange tid</translation>
 <translation id="8987927404178983737">Månad</translation>
+<translation id="4247305538398689241">Ange vecka</translation>
+<translation id="2532336938189706096">Webbvy</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Videon läses in</translation>
+<translation id="1542044944667958430">Webbsökning</translation>
 <translation id="6527303717912515753">Dela</translation>
 <translation id="1822429046913737220">FM/EM</translation>
+<translation id="5789643057113097023">,</translation>
+<translation id="1768717197362323622">Millisekund</translation>
 <translation id="2841013758207633010">Tid</translation>
 <translation id="6643016212128521049">Rensa</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Ange månad</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Ange datum och tid</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_sw.xtb b/content/public/android/java/strings/translations/android_content_strings_sw.xtb
index 7d84335..fa233c9 100644
--- a/content/public/android/java/strings/translations/android_content_strings_sw.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_sw.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="sw">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Mwaka</translation>
+<translation id="1256337885411059545">Haiwezi kucheza video</translation>
+<translation id="7821540960913969614">Weka tarehe</translation>
+<translation id="3845599764535987402">Saa</translation>
 <translation id="4932733599132424254">Tarehe</translation>
 <translation id="6727102863431372879">Weka</translation>
+<translation id="273860350361291195">Samahani, video hii sio sahihi kutiririshwa kwenye kifaa hiki.</translation>
+<translation id="7102218676258945610">Dakika</translation>
+<translation id="4768459022382175196">Sekunde</translation>
 <translation id="5966707198760109579">Juma</translation>
+<translation id="2410828433627930127">Samahani, video hii haiwezi kuchezwa.</translation>
+<translation id="7575803462290353686">Weka muda</translation>
 <translation id="8987927404178983737">Mwezi</translation>
+<translation id="4247305538398689241">Weka wiki</translation>
+<translation id="2532336938189706096">Mwonekano wa Wavuti</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">Inapakia video</translation>
+<translation id="1542044944667958430">Tafuta kwenye wavuti</translation>
 <translation id="6527303717912515753">Shiriki</translation>
 <translation id="1822429046913737220">AM / PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisekunde</translation>
 <translation id="2841013758207633010">Muda</translation>
 <translation id="6643016212128521049">Futa</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">Weka mwezi</translation>
 <translation id="6965382102122355670">Sawa</translation>
+<translation id="6444070574980481588">Weka tarehe na saa</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_th.xtb b/content/public/android/java/strings/translations/android_content_strings_th.xtb
index 17431d3..d6630fb 100644
--- a/content/public/android/java/strings/translations/android_content_strings_th.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_th.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="th">
+<translation id="376869769528291915">.</translation>
 <translation id="6015796118275082299">ปี</translation>
+<translation id="1256337885411059545">ไม่สามารถเล่นวิดีโอ</translation>
+<translation id="7821540960913969614">ตั้งวันที่</translation>
+<translation id="3845599764535987402">ชั่วโมง</translation>
 <translation id="4932733599132424254">วันที่</translation>
 <translation id="6727102863431372879">ตั้งค่า</translation>
+<translation id="273860350361291195">ขออภัย ไม่สามารถสตรีมวิดีโอไปยังอุปกรณ์นี้</translation>
+<translation id="7102218676258945610">นาที</translation>
+<translation id="4768459022382175196">วินาที</translation>
 <translation id="5966707198760109579">สัปดาห์</translation>
+<translation id="2410828433627930127">ขออภัย วิดีโอนี้เล่นไม่ได้</translation>
+<translation id="7575803462290353686">ตั้งเวลา</translation>
 <translation id="8987927404178983737">เดือน</translation>
+<translation id="4247305538398689241">ตั้งสัปดาห์</translation>
+<translation id="2532336938189706096">มุมมองเว็บ</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">กำลังโหลดวิดีโอ</translation>
+<translation id="1542044944667958430">ค้นเว็บ</translation>
 <translation id="6527303717912515753">แบ่งปัน</translation>
 <translation id="1822429046913737220">ก่อนเที่ยง/หลังเที่ยง</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">มิลลิวินาที</translation>
 <translation id="2841013758207633010">เวลา</translation>
 <translation id="6643016212128521049">ล้าง</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">ตั้งเดือน</translation>
 <translation id="6965382102122355670">ตกลง</translation>
+<translation id="6444070574980481588">ตั้งวันที่และเวลา</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_tr.xtb b/content/public/android/java/strings/translations/android_content_strings_tr.xtb
index 6cbf44f..84ff7ef 100644
--- a/content/public/android/java/strings/translations/android_content_strings_tr.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_tr.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="tr">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Yıl</translation>
+<translation id="1256337885411059545">Video oynatılamıyor</translation>
+<translation id="7821540960913969614">Tarihi ayarlayın</translation>
+<translation id="3845599764535987402">Saat</translation>
 <translation id="4932733599132424254">Tarih</translation>
 <translation id="6727102863431372879">Ayarla</translation>
+<translation id="273860350361291195">Bu video maalesef bu cihaza akışla gönderilmek için uygun değil.</translation>
+<translation id="7102218676258945610">Dakika</translation>
+<translation id="4768459022382175196">Saniye</translation>
 <translation id="5966707198760109579">Hafta</translation>
+<translation id="2410828433627930127">Maalesef bu video oynatılamıyor.</translation>
+<translation id="7575803462290353686">Saati ayarlayın</translation>
 <translation id="8987927404178983737">Ay</translation>
+<translation id="4247305538398689241">Haftayı ayarlayın</translation>
+<translation id="2532336938189706096">Web Görüntüleme</translation>
+<translation id="2732718972699418926">ÖÖ</translation>
+<translation id="7096034533295549981">Video yükleniyor</translation>
+<translation id="1542044944667958430">Web arama</translation>
 <translation id="6527303717912515753">Paylaş</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Milisaniye</translation>
 <translation id="2841013758207633010">Zaman</translation>
 <translation id="6643016212128521049">Temizle</translation>
+<translation id="2429669115401274487">ÖS</translation>
+<translation id="7781164152564914424">Ayı ayarlayın</translation>
 <translation id="6965382102122355670">Tamam</translation>
+<translation id="6444070574980481588">Tarihi ve saati ayarlayın</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_uk.xtb b/content/public/android/java/strings/translations/android_content_strings_uk.xtb
index 8844a04..557c883 100644
--- a/content/public/android/java/strings/translations/android_content_strings_uk.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_uk.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="uk">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Рік</translation>
+<translation id="1256337885411059545">Не вдається відтворити відео</translation>
+<translation id="7821540960913969614">Вибрати дату</translation>
+<translation id="3845599764535987402">Години</translation>
 <translation id="4932733599132424254">Дата</translation>
 <translation id="6727102863431372879">Встановити</translation>
+<translation id="273860350361291195">На жаль, це відео неможливо транслювати на цьому пристрої.</translation>
+<translation id="7102218676258945610">Хвилини</translation>
+<translation id="4768459022382175196">Секунди</translation>
 <translation id="5966707198760109579">Тиждень</translation>
+<translation id="2410828433627930127">На жаль, це відео неможливо відтворити.</translation>
+<translation id="7575803462290353686">Вибрати час</translation>
 <translation id="8987927404178983737">Місяць</translation>
+<translation id="4247305538398689241">Вибрати тиждень</translation>
+<translation id="2532336938189706096">Веб-версія</translation>
+<translation id="2732718972699418926">дп</translation>
+<translation id="7096034533295549981">Завантаж. відео</translation>
+<translation id="1542044944667958430">Веб-пошук</translation>
 <translation id="6527303717912515753">Надіслати</translation>
 <translation id="1822429046913737220">д.п./п.п.</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Мілісекунди</translation>
 <translation id="2841013758207633010">Час</translation>
 <translation id="6643016212128521049">Очистити</translation>
+<translation id="2429669115401274487">пп</translation>
+<translation id="7781164152564914424">Вибрати місяць</translation>
 <translation id="6965382102122355670">ОК</translation>
+<translation id="6444070574980481588">Вибрати дату й час</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_vi.xtb b/content/public/android/java/strings/translations/android_content_strings_vi.xtb
index 12580a0..f4b8bf2 100644
--- a/content/public/android/java/strings/translations/android_content_strings_vi.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_vi.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="vi">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">Năm</translation>
+<translation id="1256337885411059545">Không thể phát video</translation>
+<translation id="7821540960913969614">Đặt ngày</translation>
+<translation id="3845599764535987402">Giờ</translation>
 <translation id="4932733599132424254">Ngày</translation>
 <translation id="6727102863431372879">Đặt</translation>
+<translation id="273860350361291195">Rất tiếc, video này không hợp lệ để phát trực tuyến sang thiết bị này.</translation>
+<translation id="7102218676258945610">Phút</translation>
+<translation id="4768459022382175196">Giây</translation>
 <translation id="5966707198760109579">Tuần</translation>
+<translation id="2410828433627930127">Rất tiếc, không thể phát video này.</translation>
+<translation id="7575803462290353686">Đặt thời gian</translation>
 <translation id="8987927404178983737">Tháng</translation>
+<translation id="4247305538398689241">Đặt tuần</translation>
+<translation id="2532336938189706096">Lượt xem trên web</translation>
+<translation id="2732718972699418926">SA</translation>
+<translation id="7096034533295549981">Đang tải video</translation>
+<translation id="1542044944667958430">Tìm kiếm trên web</translation>
 <translation id="6527303717912515753">Chia sẻ</translation>
 <translation id="1822429046913737220">SA/CH</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">Mili giây</translation>
 <translation id="2841013758207633010">Thời gian</translation>
 <translation id="6643016212128521049">Xóa</translation>
+<translation id="2429669115401274487">CH</translation>
+<translation id="7781164152564914424">Đặt tháng</translation>
 <translation id="6965382102122355670">OK</translation>
+<translation id="6444070574980481588">Đặt ngày giờ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_zh-CN.xtb b/content/public/android/java/strings/translations/android_content_strings_zh-CN.xtb
index c58be0c..37ccc4d 100644
--- a/content/public/android/java/strings/translations/android_content_strings_zh-CN.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_zh-CN.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">年</translation>
+<translation id="1256337885411059545">无法播放视频</translation>
+<translation id="7821540960913969614">设置日期</translation>
+<translation id="3845599764535987402">小时</translation>
 <translation id="4932733599132424254">日期</translation>
 <translation id="6727102863431372879">设置</translation>
+<translation id="273860350361291195">抱歉,此视频无法流式传输到该设备。</translation>
+<translation id="7102218676258945610">分钟</translation>
+<translation id="4768459022382175196">秒</translation>
 <translation id="5966707198760109579">周</translation>
+<translation id="2410828433627930127">抱歉,此视频无法播放。</translation>
+<translation id="7575803462290353686">设置时间</translation>
 <translation id="8987927404178983737">月</translation>
+<translation id="4247305538398689241">设置星期</translation>
+<translation id="2532336938189706096">网页视图</translation>
+<translation id="2732718972699418926">上午</translation>
+<translation id="7096034533295549981">加载视频</translation>
+<translation id="1542044944667958430">网页搜索</translation>
 <translation id="6527303717912515753">分享</translation>
 <translation id="1822429046913737220">上午/下午</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">毫秒</translation>
 <translation id="2841013758207633010">时间</translation>
 <translation id="6643016212128521049">清除</translation>
+<translation id="2429669115401274487">下午</translation>
+<translation id="7781164152564914424">设置月份</translation>
 <translation id="6965382102122355670">确定</translation>
+<translation id="6444070574980481588">设置日期和时间</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/java/strings/translations/android_content_strings_zh-TW.xtb b/content/public/android/java/strings/translations/android_content_strings_zh-TW.xtb
index b017462..38f5e92 100644
--- a/content/public/android/java/strings/translations/android_content_strings_zh-TW.xtb
+++ b/content/public/android/java/strings/translations/android_content_strings_zh-TW.xtb
@@ -1,14 +1,33 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-TW">
+<translation id="376869769528291915">:</translation>
 <translation id="6015796118275082299">年</translation>
+<translation id="1256337885411059545">無法播放影片</translation>
+<translation id="7821540960913969614">設定日期</translation>
+<translation id="3845599764535987402">小時</translation>
 <translation id="4932733599132424254">日期</translation>
 <translation id="6727102863431372879">設定</translation>
+<translation id="273860350361291195">很抱歉,這部影片的格式有誤,無法透過這個裝置串流播放。</translation>
+<translation id="7102218676258945610">分鐘</translation>
+<translation id="4768459022382175196">秒</translation>
 <translation id="5966707198760109579">週</translation>
+<translation id="2410828433627930127">很抱歉,無法播放這部影片。</translation>
+<translation id="7575803462290353686">設定時間</translation>
 <translation id="8987927404178983737">月</translation>
+<translation id="4247305538398689241">設定週次</translation>
+<translation id="2532336938189706096">網頁檢視</translation>
+<translation id="2732718972699418926">AM</translation>
+<translation id="7096034533295549981">正在載入影片</translation>
+<translation id="1542044944667958430">網頁搜尋</translation>
 <translation id="6527303717912515753">分享</translation>
 <translation id="1822429046913737220">AM/PM</translation>
+<translation id="5789643057113097023">.</translation>
+<translation id="1768717197362323622">毫秒</translation>
 <translation id="2841013758207633010">時間</translation>
 <translation id="6643016212128521049">清除</translation>
+<translation id="2429669115401274487">PM</translation>
+<translation id="7781164152564914424">設定月份</translation>
 <translation id="6965382102122355670">確定</translation>
+<translation id="6444070574980481588">設定日期和時間</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
new file mode 100644
index 0000000..644216d
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
@@ -0,0 +1,97 @@
+// Copyright 2013 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.content.browser;
+
+import android.content.ClipboardManager;
+import android.content.ClipData;
+import android.content.Context;
+import android.os.Build;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.UrlUtils;
+import org.chromium.content.browser.input.ImeAdapter;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content_shell_apk.ContentShellTestBase;
+
+import java.util.concurrent.Callable;
+
+public class ClipboardTest extends ContentShellTestBase {
+    private static final String TEST_PAGE_DATA_URL = UrlUtils.encodeHtmlDataUri(
+            "<html><body>Hello, <a href=\"http://www.example.com/\">world</a>, how <b> " +
+            "Chromium</b> doing today?</body></html>");
+
+    private static final String EXPECTED_TEXT_RESULT = "Hello, world, how Chromium doing today?";
+
+    // String to search for in the HTML representation on the clipboard.
+    private static final String EXPECTED_HTML_NEEDLE = "http://www.example.com/";
+
+    /**
+     * Tests that copying document fragments will put at least a plain-text representation
+     * of the contents on the clipboard. For Android JellyBean and higher, we also expect
+     * the HTML representation of the fragment to be available.
+     */
+    @LargeTest
+    @Feature({"Clipboard","TextInput"})
+    public void testCopyDocumentFragment() throws Throwable {
+        launchContentShellWithUrl(TEST_PAGE_DATA_URL);
+        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+
+        final ClipboardManager clipboardManager = (ClipboardManager)
+                getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
+        assertNotNull(clipboardManager);
+
+        // Clear the clipboard to make sure we start with a clean state.
+        clipboardManager.setPrimaryClip(ClipData.newPlainText(null, ""));
+        assertFalse(hasPrimaryClip(clipboardManager));
+
+        getImeAdapter().selectAll();
+        getImeAdapter().copy();
+
+        // Waits until data has been made available on the Android clipboard.
+        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
+                    @Override
+                    public Boolean call() throws Exception {
+                        return hasPrimaryClip(clipboardManager);
+                    }
+                });
+            }
+        }));
+
+        // Verify that the data on the clipboard is what we expect it to be. For Android JB MR2
+        // and higher we expect HTML content, for other versions the plain-text representation.
+        final ClipData clip = clipboardManager.getPrimaryClip();
+        assertEquals(EXPECTED_TEXT_RESULT, clip.getItemAt(0).coerceToText(getActivity()));
+
+        // Android JellyBean and higher should have a HTML representation on the clipboard as well.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            String htmlText = clip.getItemAt(0).getHtmlText();
+
+            assertNotNull(htmlText);
+            assertTrue(htmlText.contains(EXPECTED_HTML_NEEDLE));
+        }
+    }
+
+    private ImeAdapter getImeAdapter() {
+        return getContentViewCore().getImeAdapterForTest();
+    }
+
+    // Returns whether there is a primary clip with content on the current clipboard.
+    private Boolean hasPrimaryClip(ClipboardManager clipboardManager) {
+        final ClipData clip = clipboardManager.getPrimaryClip();
+        if (clip != null && clip.getItemCount() > 0) {
+            return !TextUtils.isEmpty(clip.getItemAt(0).getText());
+        }
+
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
index c705563..f709056 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
@@ -642,8 +642,13 @@
         assertEquals("We should have started scrolling",
                 ContentViewGestureHandler.GESTURE_SCROLL_BY,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only scrollBegin and scrollBy should have been sent",
-                2, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only tapDown, scrollBegin and scrollBy should have been sent",
+                3, mockDelegate.mGestureTypeList.size());
+        assertEquals("scrollBegin should be sent before scrollBy",
+                ContentViewGestureHandler.GESTURE_SCROLL_START,
+                (int) mockDelegate.mGestureTypeList.get(1));
+        assertEquals("scrollBegin should have the time of the ACTION_MOVE",
+                eventTime + 1000, (long) mockDelegate.mGestureTimeList.get(1));
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 1000, endActionType, scrollToX, scrollToY, 0);
@@ -654,9 +659,9 @@
                         ContentViewGestureHandler.GESTURE_SCROLL_END));
         assertEquals("We should have stopped scrolling",
                 ContentViewGestureHandler.GESTURE_SCROLL_END,
-                mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only scrollBegin and scrollBy and scrollEnd should have been sent",
-                3, mockDelegate.mGestureTypeList.size());
+                (int) mockDelegate.mMostRecentGestureEvent.mType);
+        assertEquals("Only tapDown, scrollBegin and scrollBy and scrollEnd should have been sent",
+                4, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -693,8 +698,13 @@
         assertEquals("We should have started scrolling",
                 ContentViewGestureHandler.GESTURE_SCROLL_BY,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only scrollBegin and scrollBy should have been sent",
-                2, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only tapDown, scrollBegin and scrollBy should have been sent",
+                3, mockDelegate.mGestureTypeList.size());
+        assertEquals("scrollBegin should be sent before scrollBy",
+                ContentViewGestureHandler.GESTURE_SCROLL_START,
+                (int) mockDelegate.mGestureTypeList.get(1));
+        assertEquals("scrollBegin should have the time of the ACTION_MOVE",
+                eventTime + 10, (long) mockDelegate.mGestureTimeList.get(1));
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 15, MotionEvent.ACTION_UP,
@@ -708,15 +718,17 @@
                 !mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_SCROLL_END));
         assertEquals("The last up should have caused flingStart to be sent",
-                3, mockDelegate.mGestureTypeList.size());
+                4, mockDelegate.mGestureTypeList.size());
+        assertEquals("flingStart should have the time of the ACTION_UP",
+                eventTime + 15, (long) mockDelegate.mGestureTimeList.get(3));
 
         event = motionEvent(MotionEvent.ACTION_DOWN, downTime + 50, downTime + 50);
         assertTrue(mGestureHandler.onTouchEvent(event));
         assertTrue("A flingCancel should have been sent",
                 mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_FLING_CANCEL));
-        assertEquals("Only flingCancel should have been sent",
-                4, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only tapDown and flingCancel should have been sent",
+                6, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -795,26 +807,26 @@
         assertEquals("A show pressed state event should have been sent",
                 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
                         mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only showPressedState should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only showPressedState and tapDown should have been sent",
+                2, mockDelegate.mGestureTypeList.size());
 
         mLongPressDetector.startLongPressTimerIfNeeded(event);
         mLongPressDetector.sendLongPressGestureForTest();
 
         assertEquals("Only should have sent only LONG_PRESS event",
-                2, mockDelegate.mGestureTypeList.size());
+                3, mockDelegate.mGestureTypeList.size());
         assertEquals("Should have a long press event next",
                 ContentViewGestureHandler.GESTURE_LONG_PRESS,
-                mockDelegate.mGestureTypeList.get(1).intValue());
+                mockDelegate.mGestureTypeList.get(2).intValue());
 
         // The long press triggers window focus loss by opening a context menu
         mGestureHandler.onWindowFocusLost();
 
         assertEquals("Only should have sent only GESTURE_SHOW_PRESS_CANCEL event",
-                3, mockDelegate.mGestureTypeList.size());
-        assertEquals("Should have a long press event next",
+                4, mockDelegate.mGestureTypeList.size());
+        assertEquals("Should have a gesture show press cancel event next",
                 ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL,
-                mockDelegate.mGestureTypeList.get(2).intValue());
+                mockDelegate.mGestureTypeList.get(3).intValue());
     }
 
     /**
@@ -845,8 +857,8 @@
         assertEquals("A show pressed state event should have been sent",
                 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
                         mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only showPressedState should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only tapDown and showPressedState should have been sent",
+                2, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
@@ -859,9 +871,9 @@
         assertTrue("A show press cancel event should have been sent",
                 mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL));
-        assertEquals("Only showPressedState, showPressCancel, scrollBegin and scrollBy" +
+        assertEquals("Only tapDown, showPressedState, showPressCancel, scrollBegin and scrollBy" +
                 " should have been sent",
-                4, mockDelegate.mGestureTypeList.size());
+                5, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 15, MotionEvent.ACTION_UP,
@@ -874,7 +886,7 @@
                 !mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_SCROLL_END));
         assertEquals("The last up should have caused flingStart to be sent",
-                5, mockDelegate.mGestureTypeList.size());
+                6, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -904,8 +916,8 @@
         assertEquals("GESTURE_SHOW_PRESSED_STATE should have been sent",
                 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESSED_STATE should have been sent",
+                2, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 5, MotionEvent.ACTION_UP,
@@ -914,31 +926,36 @@
         assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
                 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE and " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE and " +
                 "GESTURE_SINGLE_TAP_UNCONFIRMED should have been sent",
-                2, mockDelegate.mGestureTypeList.size());
+                3, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
                 FAKE_COORD_X, FAKE_COORD_Y, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent ",
-                ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL,
+        assertEquals("A GESTURE_TAP_DOWN event should have been sent ",
+                ContentViewGestureHandler.GESTURE_TAP_DOWN,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
-                "GESTURE_SINGLE_TAP_UNCONFIRMED, and " +
-                "GESTURE_SHOW_PRESS_CANCEL should have been sent",
-                3, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
+                "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
+                "GESTURE_SHOW_PRESS_CANCEL and " +
+                "GESTURE_TAP_DOWN should have been sent",
+                5, mockDelegate.mGestureTypeList.size());
 
         // Moving a very small amount of distance should not trigger the double tap drag zoom mode.
         event = MotionEvent.obtain(
                 eventTime + 10, eventTime + 10, MotionEvent.ACTION_MOVE,
                 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
-                "GESTURE_SINGLE_TAP_UNCONFIRMED, and " +
-                "GESTURE_SHOW_PRESS_CANCEL should have been sent",
-                3, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
+                "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
+                "GESTURE_SHOW_PRESS_CANCEL and " +
+                "GESTURE_TAP_DOWN should have been sent",
+                5, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
@@ -947,11 +964,13 @@
         assertEquals("A double tap should have occurred",
                 ContentViewGestureHandler.GESTURE_DOUBLE_TAP,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
                 "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
-                "GESTURE_SHOW_PRESS_CANCEL, and " +
+                "GESTURE_SHOW_PRESS_CANCEL, " +
+                "GESTURE_TAP_DOWN and " +
                 "GESTURE_DOUBLE_TAP should have been sent",
-                4, mockDelegate.mGestureTypeList.size());
+                6, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -983,8 +1002,9 @@
         assertEquals("GESTURE_SHOW_PRESSED_STATE should have been sent",
                 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
                         mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESSED_STATE should have been sent",
+                2, mockDelegate.mGestureTypeList.size());
+
 
         event = MotionEvent.obtain(
                 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
@@ -993,22 +1013,25 @@
         assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
                 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE and " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE and " +
                 "GESTURE_TAB_UNCONFIRMED " +
                 "should have been sent",
-                2, mockDelegate.mGestureTypeList.size());
+                3, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime2, downTime2, MotionEvent.ACTION_DOWN,
                 FAKE_COORD_X, FAKE_COORD_Y, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertEquals("GESTURE_SHOW_PRESS_CANCEL should have been sent",
-                ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL,
+        assertEquals("GESTURE_TAP_DOWN should have been sent",
+                ContentViewGestureHandler.GESTURE_TAP_DOWN,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
-                "GESTURE_TAB_UNCONFIRMED, and " +
-                "GESTURE_SHOW_PRESS_CANCEL should have been sent",
-                3, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
+                "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
+                "GESTURE_SHOW_PRESS_CANCEL and " +
+                "GESTURE_TAP_DOWN should have been sent",
+                5, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
@@ -1020,12 +1043,14 @@
         assertEquals("GESTURE_PINCH_BEGIN should have been sent",
                 ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
                 "GESTURE_TAB_UNCONFIRMED," +
                 "GESTURE_SHOW_PRESS_CANCEL, " +
+                "GESTURE_TAP_DOWN, " +
                 "GESTURE_SCROLL_START, and " +
                 "GESTURE_PINCH_BEGIN should have been sent",
-                5, mockDelegate.mGestureTypeList.size());
+                7, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
@@ -1037,14 +1062,16 @@
         assertEquals("GESTURE_PINCH_BY should have been sent",
                 ContentViewGestureHandler.GESTURE_PINCH_BY,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
                 "GESTURE_TAB_UNCONFIRMED," +
                 "GESTURE_SHOW_PRESS_CANCEL, " +
+                "GESTURE_TAP_DOWN, " +
                 "GESTURE_SCROLL_START," +
                 "GESTURE_PINCH_BEGIN, " +
                 "GESTURE_SCROLL_BY, and " +
                 "GESTURE_PINCH_BY should have been sent",
-                7, mockDelegate.mGestureTypeList.size());
+                9, mockDelegate.mGestureTypeList.size());
         if (inputEventsDeliveredAtVSync) {
             assertEquals("Pinch zoom (SCROLL_BY + PINCH_BY) should trigger just one vsync",
                     1,
@@ -1071,16 +1098,18 @@
         assertEquals("GESTURE_SCROLL_END should have been sent",
                 ContentViewGestureHandler.GESTURE_SCROLL_END,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SHOW_PRESSED_STATE, " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SHOW_PRESSED_STATE, " +
                 "GESTURE_TAB_UNCONFIRMED," +
                 "GESTURE_SHOW_PRESS_CANCEL, " +
+                "GESTURE_TAP_DOWN, " +
                 "GESTURE_SCROLL_START," +
                 "GESTURE_PINCH_BEGIN, " +
                 "GESTURE_SCROLL_BY," +
                 "GESTURE_PINCH_BY, " +
                 "GESTURE_PINCH_END, and " +
                 "GESTURE_SCROLL_END should have been sent",
-                9, mockDelegate.mGestureTypeList.size());
+                11, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -1194,6 +1223,7 @@
         private boolean mMostRecentGestureEventWasLastForVSync;
         private int mTotalSentLastGestureForVSyncCount;
         private final ArrayList<Integer> mGestureTypeList = new ArrayList<Integer>();
+        private final ArrayList<Long> mGestureTimeList = new ArrayList<Long>();
 
         @Override
         public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) {
@@ -1207,6 +1237,7 @@
             mMostRecentGestureEvent = new GestureEvent(type, timeMs, x, y, extraParams);
             mMostRecentGestureEventWasLastForVSync = false;
             mGestureTypeList.add(mMostRecentGestureEvent.mType);
+            mGestureTimeList.add(timeMs);
             return true;
         }
 
@@ -1591,7 +1622,9 @@
 
         MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertNull(mockDelegate.getMostRecentGestureEvent());
+        assertEquals("A TAP_DOWN gesture should have been sent",
+                ContentViewGestureHandler.GESTURE_TAP_DOWN,
+                        mockDelegate.mMostRecentGestureEvent.mType);
 
         event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
         assertFalse(mGestureHandler.onTouchEvent(event));
@@ -1761,7 +1794,7 @@
         assertEquals(0, mMockMotionEventDelegate.mTotalSentGestureCount);
         mGestureHandler.confirmTouchEvent(
                 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-        assertEquals(6, mMockMotionEventDelegate.mTotalSentGestureCount);
+        assertEquals(8, mMockMotionEventDelegate.mTotalSentGestureCount);
 
         // If events are delivered at vsync, multiple SCROLL_BY and PINCH_BY events should still
         // trigger only a single vsync from any given call to confirmTouchEvent().
@@ -1794,8 +1827,8 @@
                 downTime, downTime, MotionEvent.ACTION_DOWN,
                 FAKE_COORD_X, FAKE_COORD_Y, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertEquals("No events should have been sent",
-                0, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN should have been sent",
+                1, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 downTime, eventTime + 5, MotionEvent.ACTION_UP,
@@ -1804,15 +1837,18 @@
         assertEquals("A GESTURE_SINGLE_TAP_CONFIRMED event should have been sent",
                 ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SINGLE_TAP_CONFIRMED should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SINGLE_TAP_CONFIRMED " +
+                "should have been sent",
+                2, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
                 FAKE_COORD_X, FAKE_COORD_Y, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-        assertEquals("Only GESTURE_SINGLE_TAP_CONFIRMED should have been sent",
-                1, mockDelegate.mGestureTypeList.size());
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SINGLE_TAP_CONFIRMED and " +
+                "GESTURE_TAP_DOWN should have been sent",
+                3, mockDelegate.mGestureTypeList.size());
 
         event = MotionEvent.obtain(
                 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
@@ -1821,9 +1857,11 @@
         assertEquals("A double tap should not have occurred",
                 ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED,
                 mockDelegate.mMostRecentGestureEvent.mType);
-        assertEquals("Only GESTURE_SINGLE_TAP_CONFIRMED and " +
+        assertEquals("Only GESTURE_TAP_DOWN, " +
+                "GESTURE_SINGLE_TAP_CONFIRMED, " +
+                "GESTURE_TAP_DOWN and " +
                 "GESTURE_SINGLE_TAP_CONFIRMED should have been sent",
-                2, mockDelegate.mGestureTypeList.size());
+                4, mockDelegate.mGestureTypeList.size());
     }
 
     /**
@@ -1894,4 +1932,121 @@
                 mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_PINCH_END));
     }
+
+    /**
+     * Verify that setting a fixed page scale during a double tap drag zoom disables
+     * double tap detection after the gesture has ended.
+     * @throws Exception
+     */
+    @SmallTest
+    @Feature({"Gestures"})
+    public void testFixedPageScaleDuringDoubleTapDragZoom() throws Exception {
+        long downTime1 = SystemClock.uptimeMillis();
+        long downTime2 = downTime1 + 100;
+
+        GestureRecordingMotionEventDelegate mockDelegate =
+                new GestureRecordingMotionEventDelegate();
+        mGestureHandler = new ContentViewGestureHandler(
+                getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager,
+                ContentViewCore.INPUT_EVENTS_DELIVERED_AT_VSYNC);
+        mLongPressDetector = new LongPressDetector(
+                getInstrumentation().getTargetContext(), mGestureHandler);
+
+        // Start a double-tap drag gesture.
+        MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        mGestureHandler.sendShowPressedStateGestureForTesting();
+        event = MotionEvent.obtain(
+                downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
+                FAKE_COORD_X, FAKE_COORD_Y, 0);
+        mGestureHandler.onTouchEvent(event);
+        event = MotionEvent.obtain(
+                downTime2, downTime2, MotionEvent.ACTION_DOWN,
+                FAKE_COORD_X, FAKE_COORD_Y, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
+                FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertTrue("GESTURE_SCROLL_START should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_START));
+        assertEquals("GESTURE_PINCH_BEGIN should have been sent",
+                ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
+                mockDelegate.mMostRecentGestureEvent.mType);
+
+        // Set a fixed page scale; this should not disrupt the current double-tap gesture.
+        mGestureHandler.updateHasFixedPageScale(true);
+
+        // Double tap zoom updates should continue.
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
+                FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertTrue("GESTURE_SCROLL_BY should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_BY));
+        assertEquals("GESTURE_PINCH_BY should have been sent",
+                ContentViewGestureHandler.GESTURE_PINCH_BY,
+                mockDelegate.mMostRecentGestureEvent.mType);
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
+                FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertTrue("GESTURE_PINCH_END should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_PINCH_END));
+        assertEquals("GESTURE_SCROLL_END should have been sent",
+                ContentViewGestureHandler.GESTURE_SCROLL_END,
+                mockDelegate.mMostRecentGestureEvent.mType);
+
+        // The double-tap gesture has finished, but the page scale is fixed.
+        // The same event sequence should not generate any double tap getsures.
+        mockDelegate.mGestureTypeList.clear();
+        downTime1 += 200;
+        downTime2 += 200;
+
+        // Start a double-tap drag gesture.
+        event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        event = MotionEvent.obtain(
+                downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
+                FAKE_COORD_X, FAKE_COORD_Y, 0);
+        mGestureHandler.onTouchEvent(event);
+        event = MotionEvent.obtain(
+                downTime2, downTime2, MotionEvent.ACTION_DOWN,
+                FAKE_COORD_X, FAKE_COORD_Y, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
+                FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertTrue("GESTURE_SCROLL_START should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_START));
+        assertFalse("GESTURE_PINCH_BEGIN should not have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_PINCH_BEGIN));
+
+        // Double tap zoom updates should not be sent.
+        // Instead, the second tap drag becomes a scroll gesture sequence.
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
+                FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertTrue("GESTURE_SCROLL_BY should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_BY));
+        assertFalse("GESTURE_PINCH_BY should not have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_PINCH_BY));
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
+                FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
+        assertTrue(mGestureHandler.onTouchEvent(event));
+        assertFalse("GESTURE_PINCH_END should not have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_PINCH_END));
+    }
+
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
index 998f036..72be732 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -4,11 +4,16 @@
 
 package org.chromium.content.browser;
 
-import android.test.FlakyTest;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
 
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
+import org.chromium.content.browser.ContentViewCore.InternalAccessDelegate;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content_shell_apk.ContentShellTestBase;
@@ -21,11 +26,78 @@
     private static final String LARGE_PAGE = UrlUtils.encodeHtmlDataUri(
             "<html><head>" +
             "<meta name=\"viewport\" content=\"width=device-width, " +
-            "initial-scale=1.0, maximum-scale=1.0\" />" +
+            "initial-scale=2.0, maximum-scale=2.0\" />" +
             "<style>body { width: 5000px; height: 5000px; }</style></head>" +
             "<body>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</body>" +
             "</html>");
 
+    /**
+     * InternalAccessDelegate to ensure AccessibilityEvent notifications (Eg:TYPE_VIEW_SCROLLED)
+     * are being sent properly on scrolling a page.
+     */
+    static class TestInternalAccessDelegate implements InternalAccessDelegate {
+
+        private boolean mScrollChanged;
+        private final Object mLock = new Object();
+
+
+
+        @Override
+        public boolean drawChild(Canvas canvas, View child, long drawingTime) {
+            return false;
+        }
+
+        @Override
+        public boolean super_onKeyUp(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean super_dispatchKeyEventPreIme(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean super_dispatchKeyEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean super_onGenericMotionEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public void super_onConfigurationChanged(Configuration newConfig) {
+        }
+
+        @Override
+        public void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix) {
+            synchronized (mLock) {
+                mScrollChanged = true;
+            }
+        }
+
+        @Override
+        public boolean awakenScrollBars() {
+            return false;
+        }
+
+        @Override
+        public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
+            return false;
+        }
+
+        /**
+         * @return Whether OnScrollChanged() has been called.
+         */
+        public boolean isScrollChanged() {
+            synchronized (mLock) {
+                return mScrollChanged;
+            }
+        }
+    }
+
     private void assertWaitForScroll(final boolean hugLeft, final boolean hugTop)
             throws InterruptedException {
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@@ -70,18 +142,14 @@
 
         launchContentShellWithUrl(LARGE_PAGE);
         assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
-        assertWaitForPageScaleFactorMatch(1.0f);
+        assertWaitForPageScaleFactorMatch(2.0f);
 
         assertEquals(0, getContentViewCore().getNativeScrollXForTest());
         assertEquals(0, getContentViewCore().getNativeScrollYForTest());
     }
 
-    /**
-     * @SmallTest
-     * @Feature({"Main"})
-     * crbug.com/224458
-     */
-    @FlakyTest
+    @SmallTest
+    @Feature({"Main"})
     public void testFling() throws Throwable {
         // Vertical fling to lower-left.
         fling(0, -1000);
@@ -104,12 +172,8 @@
         assertWaitForScroll(false, false);
     }
 
-    /**
-     * @SmallTest
-     * @Feature({"Main"})
-     * crbug.com/224458
-     */
-    @FlakyTest
+    @SmallTest
+    @Feature({"Main"})
     public void testScroll() throws Throwable {
         // Vertical scroll to lower-left.
         scrollTo(0, 2500);
@@ -131,4 +195,30 @@
         scrollTo(2500, 2500);
         assertWaitForScroll(false, false);
     }
+
+    /**
+     * To ensure the AccessibilityEvent notifications (Eg:TYPE_VIEW_SCROLLED) are being sent
+     * properly on scrolling a page.
+     */
+    @SmallTest
+    @Feature({"Main"})
+    public void testOnScrollChanged() throws Throwable {
+        final int scrollToX = 2500;
+        final int scrollToY = 2500;
+        final TestInternalAccessDelegate containerViewInternals = new TestInternalAccessDelegate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getContentViewCore().setContainerViewInternals(containerViewInternals);
+            }
+        });
+        scrollTo(scrollToX, scrollToY);
+        assertWaitForScroll(false, false);
+        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return containerViewInternals.isScrollChanged();
+            }
+        }));
+    }
 }
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index cbac82f..d6d8950 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -132,9 +132,17 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) = 0;
 
+  // Cancels a pending MIDI permission request.
+  virtual void CancelMIDISysExPermissionRequest(
+      int render_process_id,
+      int render_view_id,
+      int bridge_id,
+      const GURL& requesting_frame) = 0;
+
   // Returns the resource context.
   virtual ResourceContext* GetResourceContext() = 0;
 
diff --git a/content/public/browser/devtools_http_handler_delegate.h b/content/public/browser/devtools_http_handler_delegate.h
index 89e7ad8..2b64a7d 100644
--- a/content/public/browser/devtools_http_handler_delegate.h
+++ b/content/public/browser/devtools_http_handler_delegate.h
@@ -37,7 +37,7 @@
   virtual std::string GetPageThumbnailData(const GURL& url) = 0;
 
   // Creates new inspectable target.
-  virtual scoped_ptr<DevToolsTarget> CreateNewTarget() = 0;
+  virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) = 0;
 
   typedef std::vector<DevToolsTarget*> TargetList;
   typedef base::Callback<void(const TargetList&)> TargetCallback;
diff --git a/content/public/browser/media_device_id.cc b/content/public/browser/media_device_id.cc
new file mode 100644
index 0000000..c2e2c3c
--- /dev/null
+++ b/content/public/browser/media_device_id.cc
@@ -0,0 +1,36 @@
+// Copyright 2013 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/public/browser/media_device_id.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "crypto/hmac.h"
+
+namespace content {
+
+std::string GetHMACForMediaDeviceID(const GURL& security_origin,
+                                    const std::string& raw_unique_id) {
+  DCHECK(security_origin.is_valid());
+  DCHECK(!raw_unique_id.empty());
+  crypto::HMAC hmac(crypto::HMAC::SHA256);
+  const size_t digest_length = hmac.DigestLength();
+  std::vector<uint8> digest(digest_length);
+  bool result = hmac.Init(security_origin.spec()) &&
+      hmac.Sign(raw_unique_id, &digest[0], digest.size());
+  DCHECK(result);
+  return StringToLowerASCII(base::HexEncode(&digest[0], digest.size()));
+}
+
+bool DoesMediaDeviceIDMatchHMAC(const GURL& security_origin,
+                                const std::string& device_guid,
+                                const std::string& raw_unique_id) {
+  DCHECK(security_origin.is_valid());
+  DCHECK(!raw_unique_id.empty());
+  std::string guid_from_raw_device_id =
+      GetHMACForMediaDeviceID(security_origin, raw_unique_id);
+  return guid_from_raw_device_id == device_guid;
+}
+
+}  // namespace content
diff --git a/content/public/browser/media_device_id.h b/content/public/browser/media_device_id.h
new file mode 100644
index 0000000..5c7358c
--- /dev/null
+++ b/content/public/browser/media_device_id.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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.
+//
+// Media device IDs come in two flavors: The machine-wide unique ID of
+// the device, which is what we use on the browser side, and one-way
+// hashes over the unique ID and a security origin, which we provide
+// to code on the renderer side as per-security-origin IDs.
+
+#ifndef CONTENT_PUBLIC_BROWSER_MEDIA_DEVICE_ID_H_
+#define CONTENT_PUBLIC_BROWSER_MEDIA_DEVICE_ID_H_
+
+#include <string>
+
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// Generates a one-way hash of a device's unique ID usable by one
+// particular security origin.
+CONTENT_EXPORT std::string GetHMACForMediaDeviceID(
+    const GURL& security_origin,
+    const std::string& raw_unique_id);
+
+// Convenience method to check if |device_guid| is an HMAC of
+// |raw_device_id| for |security_origin|.
+CONTENT_EXPORT bool DoesMediaDeviceIDMatchHMAC(
+    const GURL& security_origin,
+    const std::string& device_guid,
+    const std::string& raw_unique_id);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_MEDIA_DEVICE_ID_H_
diff --git a/content/public/browser/navigation_controller.cc b/content/public/browser/navigation_controller.cc
index f6502a3..e88ba9e 100644
--- a/content/public/browser/navigation_controller.cc
+++ b/content/public/browser/navigation_controller.cc
@@ -47,6 +47,7 @@
   load_type = other.load_type;
   transition_type = other.transition_type;
   referrer = other.referrer;
+  redirect_chain = other.redirect_chain;
   extra_headers = other.extra_headers;
   is_renderer_initiated = other.is_renderer_initiated;
   override_user_agent = other.override_user_agent;
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index d186f7c..280e1cd 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -119,6 +119,10 @@
     // Referrer for this load. Empty if none.
     Referrer referrer;
 
+    // Any redirect URLs that occurred for this navigation before |url|.
+    // Defaults to an empty vector.
+    std::vector<GURL> redirect_chain;
+
     // Extra headers for this load, separated by \n.
     std::string extra_headers;
 
diff --git a/content/public/browser/notification_types.h b/content/public/browser/notification_types.h
index 17315ef..4e0eee1 100644
--- a/content/public/browser/notification_types.h
+++ b/content/public/browser/notification_types.h
@@ -134,13 +134,6 @@
   // DEPRECATED: Use WebContentsObserver::TitleWasSet()
   NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
 
-  // Indicates a WebContents has been hidden or restored.  The source is
-  // a Source<WebContents>. The details is a bool set to true if the new
-  // state is visible.
-  // DEPRECATED: Use WebContentsObserver::WasShown() and/or
-  // WebContentsObserver::WasHidden()
-  NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-
   // This notification is sent when a WebContents is being destroyed. Any
   // object holding a reference to a WebContents can listen to that
   // notification to properly reset the reference. The source is a
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index ac9b716..b097936 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -42,6 +42,9 @@
   GURL url;
   Referrer referrer;
 
+  // Any redirect URLs that occurred for this navigation before |url|.
+  std::vector<GURL> redirect_chain;
+
   // Indicates whether this navigation will be sent using POST.
   // The POST method is limited support for basic POST data by leveraging
   // NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST.
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
index 004d03f..12b162b 100644
--- a/content/public/browser/render_view_host.h
+++ b/content/public/browser/render_view_host.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
 #define CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
 
+#include <list>
+
 #include "base/callback_forward.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/render_widget_host.h"
@@ -25,6 +27,10 @@
 class Value;
 }
 
+namespace media {
+class AudioOutputController;
+}
+
 namespace ui {
 struct SelectedFileInfo;
 }
@@ -73,11 +79,6 @@
                         bool empty_allowed,
                         GURL* url);
 
-  // Adds/removes a callback called on creation of each new RenderViewHost.
-  typedef base::Callback<void(RenderViewHost*)> CreatedCallback;
-  static void AddCreatedCallback(const CreatedCallback& callback);
-  static void RemoveCreatedCallback(const CreatedCallback& callback);
-
   virtual ~RenderViewHost() {}
 
   // Tell the render view to enable a set of javascript bindings. The argument
@@ -273,6 +274,16 @@
   // Informs the renderer process of a change in timezone.
   virtual void NotifyTimezoneChange() = 0;
 
+  // Retrieves the list of AudioOutputController objects associated
+  // with this object and passes it to the callback you specify, on
+  // the same thread on which you called the method.
+  typedef std::list<scoped_refptr<media::AudioOutputController> >
+      AudioOutputControllerList;
+  typedef base::Callback<void(const AudioOutputControllerList&)>
+      GetAudioOutputControllersCallback;
+  virtual void GetAudioOutputControllers(
+      const GetAudioOutputControllersCallback& callback) const = 0;
+
 #if defined(OS_ANDROID)
   // Selects and zooms to the find result nearest to the point (x,y)
   // defined in find-in-page coordinates.
diff --git a/content/public/browser/render_view_host_observer.cc b/content/public/browser/render_view_host_observer.cc
deleted file mode 100644
index ef0f48f..0000000
--- a/content/public/browser/render_view_host_observer.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012 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/public/browser/render_view_host_observer.h"
-
-#include "content/browser/renderer_host/render_view_host_impl.h"
-
-namespace content {
-
-RenderViewHostObserver::RenderViewHostObserver(RenderViewHost* render_view_host)
-    : render_view_host_(static_cast<RenderViewHostImpl*>(render_view_host)),
-      routing_id_(render_view_host_->GetRoutingID()) {
-  render_view_host_->AddObserver(this);
-}
-
-RenderViewHostObserver::~RenderViewHostObserver() {
-  if (render_view_host_)
-    render_view_host_->RemoveObserver(this);
-}
-
-void RenderViewHostObserver::RenderViewHostInitialized() {
-}
-
-void RenderViewHostObserver::RenderViewHostDestroyed(RenderViewHost* rvh) {
-  delete this;
-}
-
-bool RenderViewHostObserver::OnMessageReceived(const IPC::Message& message) {
-  return false;
-}
-
-bool RenderViewHostObserver::Send(IPC::Message* message) {
-  if (!render_view_host_) {
-    delete message;
-    return false;
-  }
-
-  return render_view_host_->Send(message);
-}
-
-RenderViewHost* RenderViewHostObserver::render_view_host() const {
-  return render_view_host_;
-}
-
-void RenderViewHostObserver::RenderViewHostDestruction() {
-  render_view_host_->RemoveObserver(this);
-  RenderViewHost* rvh = render_view_host_;
-  render_view_host_ = NULL;
-  RenderViewHostDestroyed(rvh);
-}
-
-}  // namespace content
diff --git a/content/public/browser/render_view_host_observer.h b/content/public/browser/render_view_host_observer.h
deleted file mode 100644
index edc12b2..0000000
--- a/content/public/browser/render_view_host_observer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_RENDER_VIEW_HOST_OBSERVER_H_
-#define CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_OBSERVER_H_
-
-#include "base/compiler_specific.h"
-#include "ipc/ipc_listener.h"
-#include "ipc/ipc_sender.h"
-#include "content/common/content_export.h"
-
-class GURL;
-
-namespace content {
-
-class RenderViewHost;
-class RenderViewHostImpl;
-
-// An observer API implemented by classes which want to filter IPC messages from
-// RenderViewHost.
-class CONTENT_EXPORT RenderViewHostObserver : public IPC::Listener,
-                                              public IPC::Sender {
- public:
-
- protected:
-  explicit RenderViewHostObserver(RenderViewHost* render_view_host);
-
-  virtual ~RenderViewHostObserver();
-
-  // Invoked after the RenderViewHost is created in the renderer process.  After
-  // this point, messages can be sent to it (or to observers in the renderer).
-  virtual void RenderViewHostInitialized();
-
-  // Invoked when the RenderViewHost is being destroyed. Gives subclasses a
-  // chance to cleanup.  The base implementation will delete the object.
-  // |render_view_host| is passed as an argument since render_view_host() will
-  // return NULL once this method enters.
-  virtual void RenderViewHostDestroyed(RenderViewHost* render_view_host);
-
-  // IPC::Listener implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
-  // IPC::Sender implementation.
-  virtual bool Send(IPC::Message* message) OVERRIDE;
-
-  RenderViewHost* render_view_host() const;
-  int routing_id() { return routing_id_; }
-
- private:
-  friend class RenderViewHostImpl;
-
-  // Invoked from RenderViewHost. Invokes RenderViewHostDestroyed and NULL out
-  // |render_view_host_|.
-  void RenderViewHostDestruction();
-
-  RenderViewHostImpl* render_view_host_;
-
-  // The routing ID of the associated RenderViewHost.
-  int routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostObserver);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_OBSERVER_H_
diff --git a/content/public/browser/resource_context.h b/content/public/browser/resource_context.h
index 191f30a..7019fb7 100644
--- a/content/public/browser/resource_context.h
+++ b/content/public/browser/resource_context.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_RESOURCE_CONTEXT_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/supports_user_data.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
@@ -17,6 +18,7 @@
 }
 
 namespace net {
+class ClientCertStore;
 class HostResolver;
 class URLRequestContext;
 }
@@ -41,6 +43,9 @@
   // with a BrowsingContext.
   virtual net::URLRequestContext* GetRequestContext() = 0;
 
+  // Get platform ClientCertStore. May return NULL.
+  virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore();
+
   // Returns true if microphone access is allowed for |origin|. Used to
   // determine what level of authorization is given to |origin| to access
   // resource metadata.
diff --git a/content/public/browser/web_contents_observer.cc b/content/public/browser/web_contents_observer.cc
index 1479029..fc0fcf2 100644
--- a/content/public/browser/web_contents_observer.cc
+++ b/content/public/browser/web_contents_observer.cc
@@ -29,6 +29,10 @@
 }
 
 void WebContentsObserver::Observe(WebContents* web_contents) {
+  if (web_contents == web_contents_) {
+    // Early exit to avoid infinite loops if we're in the middle of a callback.
+    return;
+  }
   if (web_contents_)
     web_contents_->RemoveObserver(this);
   web_contents_ = static_cast<WebContentsImpl*>(web_contents);
diff --git a/content/public/browser/zygote_host_linux.h b/content/public/browser/zygote_host_linux.h
index a9798de..77cc00b 100644
--- a/content/public/browser/zygote_host_linux.h
+++ b/content/public/browser/zygote_host_linux.h
@@ -38,12 +38,6 @@
   // likely to be killed by the OOM killer.
   virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle,
                                       int score) = 0;
-
-  // Adjust the point at which the low memory notifier in the kernel tells
-  // us that we're low on memory.  When there is less than |margin_mb| left,
-  // then the notifier will notify us.  Set |margin_mb| to -1 to turn off
-  // low memory notification altogether.
-  virtual void AdjustLowMemoryMargin(int64 margin_mb) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/common/common_param_traits.cc b/content/public/common/common_param_traits.cc
index f2a5c8a..0501683 100644
--- a/content/public/common/common_param_traits.cc
+++ b/content/public/common/common_param_traits.cc
@@ -192,19 +192,21 @@
 void ParamTraits<gfx::Size>::Write(Message* m, const gfx::Size& p) {
   DCHECK_GE(p.width(), 0);
   DCHECK_GE(p.height(), 0);
-  m->WriteInt(p.width());
-  m->WriteInt(p.height());
+  int values[2] = { p.width(), p.height() };
+  m->WriteBytes(&values, sizeof(int) * 2);
 }
 
 bool ParamTraits<gfx::Size>::Read(const Message* m,
                                   PickleIterator* iter,
                                   gfx::Size* r) {
-  int w, h;
-  if (!m->ReadInt(iter, &w) || w < 0 ||
-      !m->ReadInt(iter, &h) || h < 0)
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(int) * 2))
     return false;
-  r->set_width(w);
-  r->set_height(h);
+  const int* values = reinterpret_cast<const int*>(char_values);
+  if (values[0] < 0 || values[1] < 0)
+    return false;
+  r->set_width(values[0]);
+  r->set_height(values[1]);
   return true;
 }
 
@@ -213,19 +215,19 @@
 }
 
 void ParamTraits<gfx::SizeF>::Write(Message* m, const gfx::SizeF& p) {
-  ParamTraits<float>::Write(m, p.width());
-  ParamTraits<float>::Write(m, p.height());
+  float values[2] = { p.width(), p.height() };
+  m->WriteBytes(&values, sizeof(float) * 2);
 }
 
 bool ParamTraits<gfx::SizeF>::Read(const Message* m,
                                    PickleIterator* iter,
-                                   gfx::SizeF* p) {
-  float w, h;
-  if (!ParamTraits<float>::Read(m, iter, &w) ||
-      !ParamTraits<float>::Read(m, iter, &h))
+                                   gfx::SizeF* r) {
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(float) * 2))
     return false;
-  p->set_width(w);
-  p->set_height(h);
+  const float* values = reinterpret_cast<const float*>(char_values);
+  r->set_width(values[0]);
+  r->set_height(values[1]);
   return true;
 }
 
@@ -233,20 +235,20 @@
   l->append(base::StringPrintf("(%f, %f)", p.width(), p.height()));
 }
 
-void ParamTraits<gfx::Vector2d>::Write(Message* m, const gfx::Vector2d& v) {
-  m->WriteInt(v.x());
-  m->WriteInt(v.y());
+void ParamTraits<gfx::Vector2d>::Write(Message* m, const gfx::Vector2d& p) {
+  int values[2] = { p.x(), p.y() };
+  m->WriteBytes(&values, sizeof(int) * 2);
 }
 
 bool ParamTraits<gfx::Vector2d>::Read(const Message* m,
                                       PickleIterator* iter,
                                       gfx::Vector2d* r) {
-  int x, y;
-  if (!m->ReadInt(iter, &x) ||
-      !m->ReadInt(iter, &y))
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(int) * 2))
     return false;
-  r->set_x(x);
-  r->set_y(y);
+  const int* values = reinterpret_cast<const int*>(char_values);
+  r->set_x(values[0]);
+  r->set_y(values[1]);
   return true;
 }
 
@@ -254,20 +256,20 @@
   l->append(base::StringPrintf("(%d, %d)", v.x(), v.y()));
 }
 
-void ParamTraits<gfx::Vector2dF>::Write(Message* m, const gfx::Vector2dF& v) {
-  ParamTraits<float>::Write(m, v.x());
-  ParamTraits<float>::Write(m, v.y());
+void ParamTraits<gfx::Vector2dF>::Write(Message* m, const gfx::Vector2dF& p) {
+  float values[2] = { p.x(), p.y() };
+  m->WriteBytes(&values, sizeof(float) * 2);
 }
 
 bool ParamTraits<gfx::Vector2dF>::Read(const Message* m,
                                       PickleIterator* iter,
                                       gfx::Vector2dF* r) {
-  float x, y;
-  if (!ParamTraits<float>::Read(m, iter, &x) ||
-      !ParamTraits<float>::Read(m, iter, &y))
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(float) * 2))
     return false;
-  r->set_x(x);
-  r->set_y(y);
+  const float* values = reinterpret_cast<const float*>(char_values);
+  r->set_x(values[0]);
+  r->set_y(values[1]);
   return true;
 }
 
@@ -276,20 +278,20 @@
 }
 
 void ParamTraits<gfx::Rect>::Write(Message* m, const gfx::Rect& p) {
-  WriteParam(m, p.origin());
-  WriteParam(m, p.size());
+  int values[4] = { p.x(), p.y(), p.width(), p.height() };
+  m->WriteBytes(&values, sizeof(int) * 4);
 }
 
 bool ParamTraits<gfx::Rect>::Read(const Message* m,
                                   PickleIterator* iter,
                                   gfx::Rect* r) {
-  gfx::Point origin;
-  gfx::Size size;
-  if (!ReadParam(m, iter, &origin) ||
-      !ReadParam(m, iter, &size))
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(int) * 4))
     return false;
-  r->set_origin(origin);
-  r->set_size(size);
+  const int* values = reinterpret_cast<const int*>(char_values);
+  if (values[2] < 0 || values[3] < 0)
+    return false;
+  r->SetRect(values[0], values[1], values[2], values[3]);
   return true;
 }
 
@@ -299,25 +301,18 @@
 }
 
 void ParamTraits<gfx::RectF>::Write(Message* m, const gfx::RectF& p) {
-  ParamTraits<float>::Write(m, p.x());
-  ParamTraits<float>::Write(m, p.y());
-  ParamTraits<float>::Write(m, p.width());
-  ParamTraits<float>::Write(m, p.height());
+  float values[4] = { p.x(), p.y(), p.width(), p.height() };
+  m->WriteBytes(&values, sizeof(float) * 4);
 }
 
 bool ParamTraits<gfx::RectF>::Read(const Message* m,
                                    PickleIterator* iter,
                                    gfx::RectF* r) {
-  float x, y, w, h;
-  if (!ParamTraits<float>::Read(m, iter, &x) ||
-      !ParamTraits<float>::Read(m, iter, &y) ||
-      !ParamTraits<float>::Read(m, iter, &w) ||
-      !ParamTraits<float>::Read(m, iter, &h))
+  const char* char_values;
+  if (!m->ReadBytes(iter, &char_values, sizeof(float) * 4))
     return false;
-  r->set_x(x);
-  r->set_y(y);
-  r->set_width(w);
-  r->set_height(h);
+  const float* values = reinterpret_cast<const float*>(char_values);
+  r->SetRect(values[0], values[1], values[2], values[3]);
   return true;
 }
 
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 10fddff..384a53a 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -140,6 +140,7 @@
   IPC_STRUCT_TRAITS_MEMBER(accelerated_2d_canvas_enabled)
   IPC_STRUCT_TRAITS_MEMBER(minimum_accelerated_2d_canvas_size)
   IPC_STRUCT_TRAITS_MEMBER(antialiased_2d_canvas_disabled)
+  IPC_STRUCT_TRAITS_MEMBER(accelerated_2d_canvas_msaa_sample_count)
   IPC_STRUCT_TRAITS_MEMBER(accelerated_filters_enabled)
   IPC_STRUCT_TRAITS_MEMBER(gesture_tap_highlight_enabled)
   IPC_STRUCT_TRAITS_MEMBER(accelerated_compositing_for_plugins_enabled)
@@ -159,6 +160,7 @@
   IPC_STRUCT_TRAITS_MEMBER(device_supports_touch)
   IPC_STRUCT_TRAITS_MEMBER(device_supports_mouse)
   IPC_STRUCT_TRAITS_MEMBER(touch_adjustment_enabled)
+  IPC_STRUCT_TRAITS_MEMBER(pointer_events_max_touch_points)
   IPC_STRUCT_TRAITS_MEMBER(fixed_position_creates_stacking_context)
   IPC_STRUCT_TRAITS_MEMBER(sync_xhr_in_documents_enabled)
   IPC_STRUCT_TRAITS_MEMBER(deferred_image_decoding_enabled)
@@ -185,6 +187,7 @@
   IPC_STRUCT_TRAITS_MEMBER(wide_viewport_quirk)
   IPC_STRUCT_TRAITS_MEMBER(use_wide_viewport)
   IPC_STRUCT_TRAITS_MEMBER(viewport_meta_layout_size_quirk)
+  IPC_STRUCT_TRAITS_MEMBER(viewport_meta_merge_content_quirk)
   IPC_STRUCT_TRAITS_MEMBER(viewport_meta_zero_values_quirk)
   IPC_STRUCT_TRAITS_MEMBER(ignore_main_frame_overflow_hidden_quirk)
   IPC_STRUCT_TRAITS_MEMBER(report_screen_size_in_physical_pixels_quirk)
diff --git a/content/public/common/content_constants.cc b/content/public/common/content_constants.cc
index 75e9273..2083d27 100644
--- a/content/public/common/content_constants.cc
+++ b/content/public/common/content_constants.cc
@@ -39,10 +39,6 @@
 
 const int kHistogramSynchronizerReservedSequenceNumber = 0;
 
-const char kGpuCompositingFieldTrialName[] = "ForceCompositingMode";
-const char kGpuCompositingFieldTrialForceCompositingEnabledName[] = "enabled";
-const char kGpuCompositingFieldTrialThreadEnabledName[] = "thread";
-
 const char kLowLatencyFlashAudioFieldTrialName[] = "LowLatencyFlashAudio";
 const char kLowLatencyFlashAudioFieldTrialEnabledName[] = "LowLatency";
 
diff --git a/content/public/common/content_constants.h b/content/public/common/content_constants.h
index 012b00f..a3473fd 100644
--- a/content/public/common/content_constants.h
+++ b/content/public/common/content_constants.h
@@ -61,11 +61,6 @@
 // a browser-supplied sequence number.
 CONTENT_EXPORT extern const int kHistogramSynchronizerReservedSequenceNumber;
 
-CONTENT_EXPORT extern const char kGpuCompositingFieldTrialName[];
-CONTENT_EXPORT extern const char
-    kGpuCompositingFieldTrialForceCompositingEnabledName[];
-CONTENT_EXPORT extern const char kGpuCompositingFieldTrialThreadEnabledName[];
-
 // Shared constants for the low latency flash audio field trial.
 CONTENT_EXPORT extern const char kLowLatencyFlashAudioFieldTrialName[];
 CONTENT_EXPORT extern const char kLowLatencyFlashAudioFieldTrialEnabledName[];
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 858a0d7..66403b2 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -6,6 +6,10 @@
 
 namespace switches {
 
+// The number of MSAA samples for canvas2D. Requires MSAA support by GPU to
+// have an effect. 0 disables MSAA.
+const char kAcceleratedCanvas2dMSAASampleCount[] = "canvas-msaa-sample-count";
+
 // By default, file:// URIs cannot read other file:// URIs. This is an
 // override for developers who need the old behavior for testing.
 const char kAllowFileAccessFromFiles[]      = "allow-file-access-from-files";
@@ -344,13 +348,7 @@
 // Turns on extremely verbose logging of accessibility events.
 const char kEnableAccessibilityLogging[]    = "enable-accessibility-logging";
 
-// Enable notifications of audible/silent audio output from a render view.
-//
-// TODO(miu): Remove --enable-audible-notifications once the feature goes
-// live.  http://crbug.com/178934
-const char kEnableAudibleNotifications[]    = "enable-audible-notifications";
-
-// Use a begin frame signal from browser to renderer to schedule rendering.
+// Use a BeginImplFrame signal from browser to renderer to schedule rendering.
 const char kEnableBeginFrameScheduling[]    = "enable-begin-frame-scheduling";
 
 // Enables browser plugin for all types of pages.
@@ -418,11 +416,6 @@
 // Enable the fast text autosizing implementation.
 const char kEnableFastTextAutosizing[]      = "enable-fast-text-autosizing";
 
-// By default, a page is laid out to fill the entire width of the window.
-// This flag fixes the layout of the page to a default of 980 CSS pixels,
-// or to a specified width and height using --enable-fixed-layout=w,h
-const char kEnableFixedLayout[]             = "enable-fixed-layout";
-
 const char kEnableFixedPositionCreatesStackingContext[]
     = "enable-fixed-position-creates-stacking-context";
 
@@ -821,10 +814,6 @@
 // Upscale defaults to "best".
 const char kTabCaptureUpscaleQuality[]      = "tab-capture-upscale-quality";
 
-// GestureTapDown events are deferred by this many miillseconds before
-// sending them to the renderer.
-const char kTapDownDeferralTimeMs[]         = "tap-down-deferral-time";
-
 // Allows for forcing socket connections to http/https to use fixed ports.
 const char kTestingFixedHttpPort[]          = "testing-fixed-http-port";
 const char kTestingFixedHttpsPort[]         = "testing-fixed-https-port";
@@ -1000,11 +989,6 @@
 const char kChildCleanExit[]                = "child-clean-exit";
 #endif
 
-#if defined(USE_AURA)
-// Forces usage of the test compositor. Needed to run ui tests on bots.
-extern const char kTestCompositor[]         = "test-compositor";
-#endif
-
 // Don't dump stuff here, follow the same order as the header.
 
 }  // namespace switches
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 725ef75..073d6a8 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -14,6 +14,7 @@
 
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
+CONTENT_EXPORT extern const char kAcceleratedCanvas2dMSAASampleCount[];
 CONTENT_EXPORT extern const char kAllowFileAccessFromFiles[];
 CONTENT_EXPORT extern const char kAllowFiltersOverIPC[];
 CONTENT_EXPORT extern const char kAllowNoSandboxJob[];
@@ -111,7 +112,6 @@
 extern const char kEnableAcceleratedOverflowScroll[];
 extern const char kEnableAcceleratedScrollableFrames[];
 extern const char kEnableAccessibilityLogging[];
-extern const char kEnableAudibleNotifications[];
 CONTENT_EXPORT extern const char kEnableBeginFrameScheduling[];
 CONTENT_EXPORT extern const char kEnableBrowserPluginForAllViewTypes[];
 CONTENT_EXPORT extern const char kEnableBrowserPluginDragDrop[];
@@ -127,7 +127,6 @@
 CONTENT_EXPORT extern const char kEnableExperimentalWebPlatformFeatures[];
 extern const char kEnableExperimentalWebSocket[];
 extern const char kEnableFastTextAutosizing[];
-CONTENT_EXPORT extern const char kEnableFixedLayout[];
 CONTENT_EXPORT extern const char kEnableFixedPositionCreatesStackingContext[];
 CONTENT_EXPORT extern const char kEnableGestureTapHighlight[];
 extern const char kEnableGpuBenchmarking[];
@@ -235,7 +234,6 @@
 CONTENT_EXPORT extern const char kStatsCollectionController[];
 extern const char kTabCaptureDownscaleQuality[];
 extern const char kTabCaptureUpscaleQuality[];
-extern const char kTapDownDeferralTimeMs[];
 CONTENT_EXPORT extern const char kTestingFixedHttpPort[];
 CONTENT_EXPORT extern const char kTestingFixedHttpsPort[];
 CONTENT_EXPORT extern const char kTestSandbox[];
@@ -296,10 +294,6 @@
 extern const char kChildCleanExit[];
 #endif
 
-#if defined(USE_AURA)
-CONTENT_EXPORT extern const char kTestCompositor[];
-#endif
-
 // DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
 // alphabetical order, or in one of the ifdefs (also in order in each section).
 
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index a8b7dee..9e612ad 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -174,10 +174,14 @@
 
   ~MediaStreamRequest();
 
-  // The render process id generating this request.
+  // This is the render process id for the renderer associated with generating
+  // frames for a MediaStream. Any indicators associated with a capture will be
+  // displayed for this renderer.
   int render_process_id;
 
-  // The render view id generating this request.
+  // This is the render view id for the renderer associated with generating
+  // frames for a MediaStream. Any indicators associated with a capture will be
+  // displayed for this renderer.
   int render_view_id;
 
   // The unique id combined with render_process_id and render_view_id for
diff --git a/content/public/renderer/history_item_serialization.cc b/content/public/renderer/history_item_serialization.cc
index d011fd2..6bef7de 100644
--- a/content/public/renderer/history_item_serialization.cc
+++ b/content/public/renderer/history_item_serialization.cc
@@ -48,11 +48,7 @@
       output->file_modification_time = input.modificationTime;
       break;
     case WebHTTPBody::Element::TypeBlob:
-#ifdef USE_BLOB_UUIDS
       output->blob_uuid = input.blobUUID.utf8();
-#else
-      output->deprecated_blob_url = input.blobURL;
-#endif
       break;
   }
 }
@@ -78,11 +74,7 @@
           element.file_modification_time);
       break;
     case WebHTTPBody::Element::TypeBlob:
-#ifdef USE_BLOB_UUIDS
       http_body->appendBlob(WebString::fromUTF8(element.blob_uuid));
-#else
-      http_body->appendBlob(element.deprecated_blob_url);
-#endif
       break;
   }
 }
diff --git a/content/public/test/android/OWNERS b/content/public/test/android/OWNERS
index 87d5d22..cfc5e65 100644
--- a/content/public/test/android/OWNERS
+++ b/content/public/test/android/OWNERS
@@ -1,2 +1,9 @@
+aruslan@chromium.org
 bulach@chromium.org
+dfalcantara@chromium.org
+dtrainor@chromium.org
+miguelg@chromium.org
+nyquist@chromium.org
+skyostil@chromium.org
+tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 5fed0cc..871c271 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -36,6 +36,11 @@
 #include "content/public/browser/browser_thread.h"
 #endif
 
+#if defined(USE_AURA)
+#include "content/browser/aura/image_transport_factory.h"
+#include "ui/compositor/test/test_context_factory.h"
+#endif
+
 namespace content {
 namespace {
 
@@ -114,8 +119,7 @@
 extern int BrowserMain(const MainFunctionParams&);
 
 BrowserTestBase::BrowserTestBase()
-    : embedded_test_server_io_thread_("EmbeddedTestServer io thread"),
-      allow_test_contexts_(true),
+    : allow_test_contexts_(true),
       allow_osmesa_(true) {
 #if defined(OS_MACOSX)
   base::mac::SetOverrideAmIBundled(true);
@@ -126,15 +130,7 @@
   handle_sigterm_ = true;
 #endif
 
-  // Create a separate thread for the test server to run on. It's tempting to
-  // use actual browser threads, but that doesn't work for cases where the test
-  // server needs to be started before the browser, for example when the server
-  // URL should be passed in command-line parameters.
-  base::Thread::Options thread_options;
-  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
-  CHECK(embedded_test_server_io_thread_.StartWithOptions(thread_options));
-  embedded_test_server_.reset(new net::test_server::EmbeddedTestServer(
-      embedded_test_server_io_thread_.message_loop_proxy()));
+  embedded_test_server_.reset(new net::test_server::EmbeddedTestServer);
 }
 
 BrowserTestBase::~BrowserTestBase() {
@@ -157,11 +153,23 @@
   // GPU blacklisting decisions were made.
   command_line->AppendSwitch(switches::kLogGpuControlListDecisions);
 
+#if defined(OS_CHROMEOS)
+  // If the test is running on the chromeos envrionment (such as
+  // device or vm bots), always use real contexts.
+  if (base::SysInfo::IsRunningOnChromeOS())
+    allow_test_contexts_ = false;
+#endif
+
 #if defined(USE_AURA)
+  if (command_line->HasSwitch(switches::kDisableTestCompositor))
+    allow_test_contexts_  = false;
+
   // Use test contexts for browser tests unless they override and force us to
   // use a real context.
-  if (allow_test_contexts_)
-    command_line->AppendSwitch(switches::kTestCompositor);
+  if (allow_test_contexts_) {
+    content::ImageTransportFactory::InitializeForUnitTests(
+        scoped_ptr<ui::ContextFactory>(new ui::TestContextFactory));
+  }
 #endif
 
   // When using real GL contexts, we usually use OSMesa as this works on all
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h
index 4203db3..f9171bb 100644
--- a/content/public/test/browser_test_base.h
+++ b/content/public/test/browser_test_base.h
@@ -133,7 +133,6 @@
   scoped_ptr<net::SpawnedTestServer> test_server_;
 
   // Embedded test server, cheap to create, started on demand.
-  base::Thread embedded_test_server_io_thread_;
   scoped_ptr<net::test_server::EmbeddedTestServer> embedded_test_server_;
 
   // Host resolver used during tests.
diff --git a/content/public/test/js_injection_ready_observer.h b/content/public/test/js_injection_ready_observer.h
deleted file mode 100644
index bb82231..0000000
--- a/content/public/test/js_injection_ready_observer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 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_TEST_JS_INJECTION_READY_OBSERVER_H_
-#define CONTENT_PUBLIC_TEST_JS_INJECTION_READY_OBSERVER_H_
-
-namespace content {
-class RenderViewHost;
-
-// Interface to notify when JavaScript injection is possible.
-class JsInjectionReadyObserver {
- public:
-  // Called to indicate page entry committed and ready for JavaScript
-  // injection. |render_view_host| may be used to route injection messages to
-  // the appropriate RenderView.
-  virtual void OnJsInjectionReady(RenderViewHost* render_view_host) = 0;
-
- protected:
-  virtual ~JsInjectionReadyObserver() {}
-};
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_TEST_JS_INJECTION_READY_OBSERVER_H_
diff --git a/content/public/test/layouttest_support.h b/content/public/test/layouttest_support.h
index 5d972f3..7e56763 100644
--- a/content/public/test/layouttest_support.h
+++ b/content/public/test/layouttest_support.h
@@ -67,6 +67,13 @@
 // Set the device scale factor and force the compositor to resize.
 void SetDeviceScaleFactor(RenderView* render_view, float factor);
 
+// Enables or disables synchronous resize mode. When enabled, all window-sizing
+// machinery is short-circuited inside the renderer. This mode is necessary for
+// some tests that were written before browsers had multi-process architecture
+// and rely on window resizes to happen synchronously.
+// See http://crbug.com/309760 for details.
+void UseSynchronousResizeMode(RenderView* render_view, bool enable);
+
 // Control auto resize mode.
 void EnableAutoResizeMode(RenderView* render_view,
                           const WebKit::WebSize& min_size,
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 309a099..a32cc89 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -187,12 +187,17 @@
 
 void RenderViewTest::TearDown() {
   // Try very hard to collect garbage before shutting down.
-  GetMainFrame()->collectGarbage();
-  GetMainFrame()->collectGarbage();
+  // "5" was chosen following http://crbug.com/46571#c9
+  const int kGCIterations = 5;
+  for (int i = 0; i < kGCIterations; i++)
+    GetMainFrame()->collectGarbage();
 
   // Run the loop so the release task from the renderwidget executes.
   ProcessPendingMessages();
 
+  for (int i = 0; i < kGCIterations; i++)
+    GetMainFrame()->collectGarbage();
+
   render_thread_->SendCloseMessage();
   view_ = NULL;
   mock_process_.reset();
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc
index 907f748..f194e7e 100644
--- a/content/public/test/test_browser_context.cc
+++ b/content/public/test/test_browser_context.cc
@@ -101,12 +101,20 @@
 void TestBrowserContext::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   // Always reject requests for testing.
   callback.Run(false);
 }
 
+void TestBrowserContext::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+}
+
 ResourceContext* TestBrowserContext::GetResourceContext() {
   if (!resource_context_)
     resource_context_.reset(new MockResourceContext(
diff --git a/content/public/test/test_browser_context.h b/content/public/test/test_browser_context.h
index 4799180..801e635 100644
--- a/content/public/test/test_browser_context.h
+++ b/content/public/test/test_browser_context.h
@@ -43,8 +43,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+        int render_process_id,
+        int render_view_id,
+        int bridge_id,
+        const GURL& requesting_frame) OVERRIDE;
   virtual ResourceContext* GetResourceContext() OVERRIDE;
   virtual GeolocationPermissionContext*
       GetGeolocationPermissionContext() OVERRIDE;
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index 0e75b52..97b2343 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -103,33 +103,26 @@
       const testing::TestInfo* test_info) OVERRIDE;
   virtual bool ShouldRunTest(const testing::TestCase* test_case,
                              const testing::TestInfo* test_info) OVERRIDE;
-  virtual void RunTest(
-      const testing::TestCase* test_case,
-      const testing::TestInfo* test_info,
-      const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE;
-  virtual void RunRemainingTests() OVERRIDE;
+  virtual size_t RunTests(base::TestLauncher* test_launcher,
+                          const std::vector<std::string>& test_names) OVERRIDE;
+  virtual size_t RetryTests(
+      base::TestLauncher* test_launcher,
+      const std::vector<std::string>& test_names) OVERRIDE;
 
  private:
-  struct TestInfo {
-    std::string GetFullName() const { return test_case_name + "." + test_name; }
+  void DoRunTest(base::TestLauncher* test_launcher,
+                 const std::string& test_name);
 
-    std::string test_case_name;
-    std::string test_name;
-    std::vector<base::TestLauncherDelegate::TestResultCallback> callbacks;
-  };
-
-  // Launches test from |test_info| using |command_line| and parallel launcher.
-  void DoRunTest(const TestInfo& test_info, const CommandLine& command_line);
-
-  // Launches test named |test_name| using |command_line| and parallel launcher,
+  // Launches test named |test_name| using parallel launcher,
   // given result of PRE_ test |pre_test_result|.
-  void RunDependentTest(const std::string test_name,
-                        const CommandLine& command_line,
+  void RunDependentTest(base::TestLauncher* test_launcher,
+                        const std::string test_name,
                         const base::TestResult& pre_test_result);
 
   // Callback to receive result of a test.
   void GTestCallback(
-      const TestInfo& test_info,
+      base::TestLauncher* test_launcher,
+      const std::string& test_name,
       int exit_code,
       const base::TimeDelta& elapsed_time,
       bool was_timeout,
@@ -146,10 +139,22 @@
 
   base::ParallelTestLauncher parallel_launcher_;
 
-  // Store all tests to run before running any of them to properly
-  // handle PRE_ tests. The map is indexed by test full name (e.g. "A.B").
-  typedef std::map<std::string, TestInfo> TestInfoMap;
-  TestInfoMap tests_to_run_;
+  // Store dependent test name (map is indexed by full test name).
+  typedef std::map<std::string, std::string> DependentTestMap;
+  DependentTestMap dependent_test_map_;
+  DependentTestMap reverse_dependent_test_map_;
+
+  // Store unique data directory prefix for test names (without PRE_ prefixes).
+  // PRE_ tests and tests that depend on them must share the same
+  // data directory. Using test name as directory name leads to too long
+  // names (exceeding UNIX_PATH_MAX, which creates a problem with
+  // process_singleton_linux). Create a randomly-named temporary directory
+  // and keep track of the names so that PRE_ tests can still re-use them.
+  typedef std::map<std::string, base::FilePath> UserDataDirMap;
+  UserDataDirMap user_data_dir_map_;
+
+  // Store names of all seen tests to properly handle PRE_ tests.
+  std::set<std::string> all_test_names_;
 
   // Temporary directory for user data directories.
   base::ScopedTempDir temp_dir_;
@@ -158,7 +163,8 @@
 };
 
 void WrapperTestLauncherDelegate::OnTestIterationStarting() {
-  tests_to_run_.clear();
+  dependent_test_map_.clear();
+  user_data_dir_map_.clear();
 }
 
 std::string WrapperTestLauncherDelegate::GetTestNameForFiltering(
@@ -171,11 +177,20 @@
 bool WrapperTestLauncherDelegate::ShouldRunTest(
     const testing::TestCase* test_case,
     const testing::TestInfo* test_info) {
+  all_test_names_.insert(
+      std::string(test_case->name()) + "." + test_info->name());
+
   if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) &&
       !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) {
     return false;
   }
 
+  if (StartsWithASCII(test_info->name(), kPreTestPrefix, true)) {
+    // We will actually run PRE_ tests, but to ensure they run on the same shard
+    // as dependent tests, handle all these details internally.
+    return false;
+  }
+
   // Stop test execution after too many timeouts.
   if (timeout_count_ > 5) {
     if (!printed_timeout_message_) {
@@ -188,74 +203,134 @@
   return true;
 }
 
-void WrapperTestLauncherDelegate::RunTest(
-    const testing::TestCase* test_case,
-    const testing::TestInfo* test_info,
-    const base::TestLauncherDelegate::TestResultCallback& callback) {
-  TestInfo run_test_info;
-  run_test_info.test_case_name = test_case->name();
-  run_test_info.test_name = test_info->name();
-  run_test_info.callbacks.push_back(callback);
-
-  DCHECK(!ContainsKey(tests_to_run_, run_test_info.GetFullName()));
-  tests_to_run_[run_test_info.GetFullName()] = run_test_info;
+std::string GetPreTestName(const std::string& full_name) {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  std::string test_case_name = full_name.substr(0, dot_pos);
+  std::string test_name = full_name.substr(dot_pos + 1);
+  return test_case_name + "." + kPreTestPrefix + test_name;
 }
 
-void WrapperTestLauncherDelegate::RunRemainingTests() {
-  // PRE_ tests and tests that depend on them must share the same
-  // data directory. Using test name as directory name leads to too long
-  // names (exceeding UNIX_PATH_MAX, which creates a problem with
-  // process_singleton_linux). Create a randomly-named temporary directory
-  // and keep track of the names so that PRE_ tests can still re-use them.
-  std::map<std::string, base::FilePath> temp_directories;
+size_t WrapperTestLauncherDelegate::RunTests(
+    base::TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  // Number of additional tests to run because of dependencies.
+  size_t additional_tests_to_run_count = 0;
 
-  // List of tests we can kick off right now, depending on no other tests.
-  std::vector<std::pair<std::string, CommandLine> > tests_to_run_now;
+  // Compute dependencies of tests to be run.
+  for (size_t i = 0; i < test_names.size(); i++) {
+    std::string full_name(test_names[i]);
+    std::string pre_test_name(GetPreTestName(full_name));
 
-  for (TestInfoMap::iterator i = tests_to_run_.begin();
-       i != tests_to_run_.end();
-       ++i) {
-    const TestInfo& test_info = i->second;
+    while (ContainsKey(all_test_names_, pre_test_name)) {
+      additional_tests_to_run_count++;
 
-    // Make sure PRE_ tests and tests that depend on them share the same
-    // data directory - based it on the test name without prefixes.
-    std::string test_name_no_pre(RemoveAnyPrePrefixes(test_info.GetFullName()));
-    if (!ContainsKey(temp_directories, test_name_no_pre)) {
+      DCHECK(!ContainsKey(dependent_test_map_, pre_test_name));
+      dependent_test_map_[pre_test_name] = full_name;
+
+      DCHECK(!ContainsKey(reverse_dependent_test_map_, full_name));
+      reverse_dependent_test_map_[full_name] = pre_test_name;
+
+      full_name = pre_test_name;
+      pre_test_name = GetPreTestName(pre_test_name);
+    }
+  }
+
+  for (size_t i = 0; i < test_names.size(); i++) {
+    std::string full_name(test_names[i]);
+
+    // Make sure no PRE_ tests were requested explicitly.
+    DCHECK_EQ(full_name, RemoveAnyPrePrefixes(full_name));
+
+    if (!ContainsKey(user_data_dir_map_, full_name)) {
       base::FilePath temp_dir;
       CHECK(file_util::CreateTemporaryDirInDir(
                 temp_dir_.path(), FILE_PATH_LITERAL("d"), &temp_dir));
-      temp_directories[test_name_no_pre] = temp_dir;
+      user_data_dir_map_[full_name] = temp_dir;
     }
 
-    CommandLine new_cmd_line(*CommandLine::ForCurrentProcess());
-    CHECK(launcher_delegate_->AdjustChildProcessCommandLine(
-              &new_cmd_line, temp_directories[test_name_no_pre]));
+    // If the test has any dependencies, get to the root and start with that.
+    while (ContainsKey(reverse_dependent_test_map_, full_name))
+      full_name = GetPreTestName(full_name);
 
-    std::string pre_test_name(
-        test_info.test_case_name + "." + kPreTestPrefix + test_info.test_name);
-    if (ContainsKey(tests_to_run_, pre_test_name)) {
-      tests_to_run_[pre_test_name].callbacks.push_back(
-          base::Bind(&WrapperTestLauncherDelegate::RunDependentTest,
-                     base::Unretained(this),
-                     test_info.GetFullName(),
-                     new_cmd_line));
-    } else {
-      tests_to_run_now.push_back(
-          std::make_pair(test_info.GetFullName(), new_cmd_line));
-    }
+    DoRunTest(test_launcher, full_name);
   }
 
-  for (size_t i = 0; i < tests_to_run_now.size(); i++) {
-    const TestInfo& test_info = tests_to_run_[tests_to_run_now[i].first];
-    const CommandLine& cmd_line = tests_to_run_now[i].second;
-    DoRunTest(test_info, cmd_line);
-  }
+  return test_names.size() + additional_tests_to_run_count;
 }
 
-void WrapperTestLauncherDelegate::DoRunTest(const TestInfo& test_info,
-                                            const CommandLine& command_line) {
-  CommandLine new_cmd_line(command_line.GetProgram());
-  CommandLine::SwitchMap switches = command_line.GetSwitches();
+size_t WrapperTestLauncherDelegate::RetryTests(
+    base::TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  // List of tests we can kick off right now, depending on no other tests.
+  std::vector<std::string> tests_to_run_now;
+
+  // We retry at least the tests requested to retry.
+  std::set<std::string> test_names_set(test_names.begin(), test_names.end());
+
+  // In the face of PRE_ tests, we need to retry the entire chain of tests,
+  // from the very first one.
+  for (size_t i = 0; i < test_names.size(); i++) {
+    std::string test_name(test_names[i]);
+    while (ContainsKey(reverse_dependent_test_map_, test_name)) {
+      test_name = reverse_dependent_test_map_[test_name];
+      test_names_set.insert(test_name);
+    }
+  }
+
+  // Discard user data directories from any previous runs. Start with
+  // fresh state.
+  for (UserDataDirMap::const_iterator i = user_data_dir_map_.begin();
+       i != user_data_dir_map_.end();
+       ++i) {
+    // Delete temporary directories now to avoid using too much space in /tmp.
+    if (!base::DeleteFile(i->second, true)) {
+      LOG(WARNING) << "Failed to delete " << i->second.value();
+    }
+  }
+  user_data_dir_map_.clear();
+
+  for (std::set<std::string>::const_iterator i = test_names_set.begin();
+       i != test_names_set.end();
+       ++i) {
+    std::string full_name(*i);
+
+    // Make sure PRE_ tests and tests that depend on them share the same
+    // data directory - based it on the test name without prefixes.
+    std::string test_name_no_pre(RemoveAnyPrePrefixes(full_name));
+    if (!ContainsKey(user_data_dir_map_, test_name_no_pre)) {
+      base::FilePath temp_dir;
+      CHECK(file_util::CreateTemporaryDirInDir(
+                temp_dir_.path(), FILE_PATH_LITERAL("d"), &temp_dir));
+      user_data_dir_map_[test_name_no_pre] = temp_dir;
+    }
+
+    size_t dot_pos = full_name.find('.');
+    CHECK_NE(dot_pos, std::string::npos);
+    std::string test_case_name = full_name.substr(0, dot_pos);
+    std::string test_name = full_name.substr(dot_pos + 1);
+    std::string pre_test_name(
+        test_case_name + "." + kPreTestPrefix + test_name);
+    if (!ContainsKey(test_names_set, pre_test_name))
+      tests_to_run_now.push_back(full_name);
+  }
+
+  for (size_t i = 0; i < tests_to_run_now.size(); i++)
+    DoRunTest(test_launcher, tests_to_run_now[i]);
+
+  return test_names_set.size();
+}
+
+void WrapperTestLauncherDelegate::DoRunTest(base::TestLauncher* test_launcher,
+                                            const std::string& test_name) {
+  std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
+
+  CommandLine cmd_line(*CommandLine::ForCurrentProcess());
+  CHECK(launcher_delegate_->AdjustChildProcessCommandLine(
+            &cmd_line, user_data_dir_map_[test_name_no_pre]));
+
+  CommandLine new_cmd_line(cmd_line.GetProgram());
+  CommandLine::SwitchMap switches = cmd_line.GetSwitches();
 
   // Strip out gtest_output flag because otherwise we would overwrite results
   // of the other tests.
@@ -269,55 +344,52 @@
   // Always enable disabled tests.  This method is not called with disabled
   // tests unless this flag was specified to the browser test executable.
   new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests");
-  new_cmd_line.AppendSwitchASCII(
-      "gtest_filter",
-      test_info.test_case_name + "." + test_info.test_name);
+  new_cmd_line.AppendSwitchASCII("gtest_filter", test_name);
   new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
 
   char* browser_wrapper = getenv("BROWSER_WRAPPER");
 
-  // PRE_ tests and tests that depend on them should share the sequence token
-  // name, so that they are run serially.
-  std::string test_name_no_pre = RemoveAnyPrePrefixes(
-      test_info.test_case_name + "." + test_info.test_name);
-
   parallel_launcher_.LaunchChildGTestProcess(
       new_cmd_line,
       browser_wrapper ? browser_wrapper : std::string(),
       TestTimeouts::action_max_timeout(),
       base::Bind(&WrapperTestLauncherDelegate::GTestCallback,
                  base::Unretained(this),
-                 test_info));
+                 test_launcher,
+                 test_name));
 }
 
 void WrapperTestLauncherDelegate::RunDependentTest(
+    base::TestLauncher* test_launcher,
     const std::string test_name,
-    const CommandLine& command_line,
     const base::TestResult& pre_test_result) {
-  const TestInfo& test_info = tests_to_run_[test_name];
   if (pre_test_result.status == base::TestResult::TEST_SUCCESS) {
     // Only run the dependent test if PRE_ test succeeded.
-    DoRunTest(test_info, command_line);
+    DoRunTest(test_launcher, test_name);
   } else {
     // Otherwise skip the test.
     base::TestResult test_result;
-    test_result.test_case_name = test_info.test_case_name;
-    test_result.test_name = test_info.test_name;
+    test_result.full_name = test_name;
     test_result.status = base::TestResult::TEST_SKIPPED;
-    for (size_t i = 0; i < test_info.callbacks.size(); i++)
-      test_info.callbacks[i].Run(test_result);
+    test_launcher->OnTestFinished(test_result);
+
+    if (ContainsKey(dependent_test_map_, test_name)) {
+      RunDependentTest(test_launcher,
+                       dependent_test_map_[test_name],
+                       test_result);
+    }
   }
 }
 
 void WrapperTestLauncherDelegate::GTestCallback(
-    const TestInfo& test_info,
+    base::TestLauncher* test_launcher,
+    const std::string& test_name,
     int exit_code,
     const base::TimeDelta& elapsed_time,
     bool was_timeout,
     const std::string& output) {
   base::TestResult result;
-  result.test_case_name = test_info.test_case_name;
-  result.test_name = test_info.test_name;
+  result.full_name = test_name;
 
   // TODO(phajdan.jr): Recognize crashes.
   if (exit_code == 0)
@@ -329,13 +401,24 @@
 
   result.elapsed_time = elapsed_time;
 
-  // TODO(phajdan.jr): Use base::PrintTestOutputSnippetOnFailure after migrating
-  // away from run_test_cases.py (http://crbug.com/236893).
-  fprintf(stdout, "%s", output.c_str());
-  fflush(stdout);
+  result.output_snippet = GetTestOutputSnippet(result, output);
 
-  for (size_t i = 0; i < test_info.callbacks.size(); i++)
-    test_info.callbacks[i].Run(result);
+  if (ContainsKey(dependent_test_map_, test_name)) {
+    RunDependentTest(test_launcher, dependent_test_map_[test_name], result);
+  } else {
+    // No other tests depend on this, we can delete the temporary directory now.
+    // Do so to avoid too many temporary files using lots of disk space.
+    std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
+    if (ContainsKey(user_data_dir_map_, test_name_no_pre)) {
+      if (!base::DeleteFile(user_data_dir_map_[test_name_no_pre], true)) {
+        LOG(WARNING) << "Failed to delete "
+                     << user_data_dir_map_[test_name_no_pre].value();
+      }
+      user_data_dir_map_.erase(test_name_no_pre);
+    }
+  }
+
+  test_launcher->OnTestFinished(result);
   parallel_launcher_.ResetOutputWatchdog();
 }
 
@@ -399,6 +482,7 @@
 }
 
 int LaunchTests(TestLauncherDelegate* launcher_delegate,
+                int default_jobs,
                 int argc,
                 char** argv) {
   DCHECK(!g_launcher_delegate);
@@ -430,22 +514,22 @@
   if (ShouldRunContentMain())
     return RunContentMain(argc, argv, launcher_delegate);
 
+  base::AtExitManager at_exit;
+  testing::InitGoogleTest(&argc, argv);
+  TestTimeouts::Initialize();
+
+  int jobs = default_jobs;
+  if (!GetSwitchValueAsInt(switches::kTestLauncherJobs, &jobs))
+    return 1;
+
   fprintf(stdout,
-      "Starting tests...\n"
+      "Starting tests (using %d parallel jobs)...\n"
       "IMPORTANT DEBUGGING NOTE: each test is run inside its own process.\n"
       "For debugging a test inside a debugger, use the\n"
       "--gtest_filter=<your_test_name> flag along with either\n"
       "--single_process (to run the test in one launcher/browser process) or\n"
       "--single-process (to do the above, and also run Chrome in single-"
-      "process mode).\n");
-
-  base::AtExitManager at_exit;
-  testing::InitGoogleTest(&argc, argv);
-  TestTimeouts::Initialize();
-
-  int jobs = 1;  // TODO(phajdan.jr): Default to half the number of CPU cores.
-  if (!GetSwitchValueAsInt(switches::kTestLauncherJobs, &jobs))
-    return 1;
+          "process mode).\n", jobs);
 
   base::MessageLoopForIO message_loop;
 
diff --git a/content/public/test/test_launcher.h b/content/public/test/test_launcher.h
index df3f56c..268eab5 100644
--- a/content/public/test/test_launcher.h
+++ b/content/public/test/test_launcher.h
@@ -43,7 +43,11 @@
   virtual ~TestLauncherDelegate();
 };
 
+// Launches tests using |launcher_delegate|. |default_jobs| is number
+// of test jobs to be run in parallel, unless overridden from the command line.
+// Returns exit code.
 int LaunchTests(TestLauncherDelegate* launcher_delegate,
+                int default_jobs,
                 int argc,
                 char** argv) WARN_UNUSED_RESULT;
 
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index 10acbad..80eada2 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -5,11 +5,11 @@
 #include "content/public/test/test_renderer_host.h"
 
 #include "base/run_loop.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/test_render_view_host.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
diff --git a/content/renderer/device_orientation/device_sensor_event_pump.cc b/content/renderer/device_orientation/device_sensor_event_pump.cc
index e4c0eb0..8e82d8f 100644
--- a/content/renderer/device_orientation/device_sensor_event_pump.cc
+++ b/content/renderer/device_orientation/device_sensor_event_pump.cc
@@ -9,7 +9,10 @@
 
 namespace content {
 
-const int DeviceSensorEventPump::kDefaultPumpDelayMillis = 40;
+// Default interval between successive polls, should take into account the
+// value of |kInertialSensorIntervalMillis| in
+// content/browser/device_orientation/inertial_sensor_consts.h.
+const int DeviceSensorEventPump::kDefaultPumpDelayMillis = 50;
 
 int DeviceSensorEventPump::GetDelayMillis() const {
   return pump_delay_millis_;
diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc
index cb9aeba..6b83e8d 100644
--- a/content/renderer/devtools/devtools_agent.cc
+++ b/content/renderer/devtools/devtools_agent.cc
@@ -43,6 +43,8 @@
 
 namespace content {
 
+base::subtle::AtomicWord DevToolsAgent::event_callback_;
+
 namespace {
 
 class WebKitClientMessageLoopImpl
@@ -135,7 +137,9 @@
 
 void DevToolsAgent::setTraceEventCallback(TraceEventCallback cb) {
   TraceLog* trace_log = TraceLog::GetInstance();
-  trace_log->SetEventCallback(cb);
+  trace_log->SetEventCallback(cb ? TraceEventCallbackWrapper : 0);
+  base::subtle::NoBarrier_Store(&event_callback_,
+                                reinterpret_cast<base::subtle::AtomicWord>(cb));
   if (!!cb) {
     trace_log->SetEnabled(base::debug::CategoryFilter(
         base::debug::CategoryFilter::kDefaultCategoryFilterString),
@@ -145,6 +149,27 @@
   }
 }
 
+void DevToolsAgent::TraceEventCallbackWrapper(
+    base::TimeTicks timestamp,
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char* const arg_names[],
+    const unsigned char arg_types[],
+    const unsigned long long arg_values[],
+    unsigned char flags) {
+  TraceEventCallback callback =
+      reinterpret_cast<TraceEventCallback>(
+          base::subtle::NoBarrier_Load(&event_callback_));
+  if (callback) {
+    double timestamp_seconds = (timestamp - base::TimeTicks()).InSecondsF();
+    callback(phase, category_group_enabled, name, id, num_args,
+             arg_names, arg_types, arg_values, flags, timestamp_seconds);
+  }
+}
+
 void DevToolsAgent::enableDeviceEmulation(
     const WebKit::WebSize& device_size,
     const WebKit::WebRect& view_rect,
@@ -209,6 +234,7 @@
 }
 
 void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
+  TRACE_EVENT0("devtools", "DevToolsAgent::OnDispatchOnInspectorBackend");
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent)
     web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
diff --git a/content/renderer/devtools/devtools_agent.h b/content/renderer/devtools/devtools_agent.h
index 9860ed7..45d5566 100644
--- a/content/renderer/devtools/devtools_agent.h
+++ b/content/renderer/devtools/devtools_agent.h
@@ -7,7 +7,9 @@
 
 #include <string>
 
+#include "base/atomicops.h"
 #include "base/basictypes.h"
+#include "base/time/time.h"
 #include "content/public/common/console_message_level.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "third_party/WebKit/public/web/WebDevToolsAgentClient.h"
@@ -52,7 +54,14 @@
   virtual void clearBrowserCache();
   virtual void clearBrowserCookies();
   virtual void visitAllocatedObjects(AllocatedObjectVisitor* visitor);
+
+  typedef void (*TraceEventCallback)(
+      char phase, const unsigned char*, const char* name, unsigned long long id,
+      int numArgs, const char* const* argNames, const unsigned char* argTypes,
+      const unsigned long long* argValues,
+      unsigned char flags, double timestamp);
   virtual void setTraceEventCallback(TraceEventCallback cb);
+
   virtual void enableDeviceEmulation(
       const WebKit::WebSize& device_size,
       const WebKit::WebRect& view_rect, float device_scale_factor,
@@ -69,9 +78,23 @@
   void ContinueProgram();
   void OnSetupDevToolsClient();
 
+  static void TraceEventCallbackWrapper(
+      base::TimeTicks timestamp,
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char* const arg_names[],
+      const unsigned char arg_types[],
+      const unsigned long long arg_values[],
+      unsigned char flags);
+
   bool is_attached_;
   bool is_devtools_client_;
 
+  static base::subtle::AtomicWord /* TraceEventCallback */ event_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(DevToolsAgent);
 };
 
diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc
index 5588e5f..cca73a7 100644
--- a/content/renderer/gpu/compositor_output_surface.cc
+++ b/content/renderer/gpu/compositor_output_surface.cc
@@ -77,7 +77,7 @@
 
 CompositorOutputSurface::~CompositorOutputSurface() {
   DCHECK(CalledOnValidThread());
-  SetNeedsBeginFrame(false);
+  SetNeedsBeginImplFrame(false);
   if (!HasClient())
     return;
   UpdateSmoothnessTakesPriority(false);
@@ -103,9 +103,9 @@
     // Without a GPU context, the memory policy otherwise wouldn't be set.
     client->SetMemoryPolicy(cc::ManagedMemoryPolicy(
         64 * 1024 * 1024,
-        cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
+        gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
         0,
-        cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
+        gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING,
         cc::ManagedMemoryPolicy::kDefaultNumResourcesLimit));
   }
 
@@ -144,7 +144,7 @@
     IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck);
     IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources);
 #if defined(OS_ANDROID)
-    IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrame);
+    IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginImplFrame);
 #endif
   IPC_END_MESSAGE_MAP()
 }
@@ -156,16 +156,16 @@
 }
 
 #if defined(OS_ANDROID)
-void CompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
+void CompositorOutputSurface::SetNeedsBeginImplFrame(bool enable) {
   DCHECK(CalledOnValidThread());
-  if (needs_begin_frame_ != enable)
+  if (needs_begin_impl_frame_ != enable)
     Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable));
-  OutputSurface::SetNeedsBeginFrame(enable);
+  OutputSurface::SetNeedsBeginImplFrame(enable);
 }
 
-void CompositorOutputSurface::OnBeginFrame(const cc::BeginFrameArgs& args) {
+void CompositorOutputSurface::OnBeginImplFrame(const cc::BeginFrameArgs& args) {
   DCHECK(CalledOnValidThread());
-  BeginFrame(args);
+  BeginImplFrame(args);
 }
 #endif  // defined(OS_ANDROID)
 
diff --git a/content/renderer/gpu/compositor_output_surface.h b/content/renderer/gpu/compositor_output_surface.h
index f8c7955..7afaa51 100644
--- a/content/renderer/gpu/compositor_output_surface.h
+++ b/content/renderer/gpu/compositor_output_surface.h
@@ -54,7 +54,7 @@
   virtual bool BindToClient(cc::OutputSurfaceClient* client) OVERRIDE;
   virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
 #if defined(OS_ANDROID)
-  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
+  virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE;
 #endif
 
   // TODO(epenner): This seems out of place here and would be a better fit
@@ -93,7 +93,7 @@
   void OnUpdateVSyncParameters(
       base::TimeTicks timebase, base::TimeDelta interval);
 #if defined(OS_ANDROID)
-  void OnBeginFrame(const cc::BeginFrameArgs& args);
+  void OnBeginImplFrame(const cc::BeginFrameArgs& args);
 #endif
   bool Send(IPC::Message* message);
 
diff --git a/content/renderer/gpu/compositor_software_output_device.cc b/content/renderer/gpu/compositor_software_output_device.cc
index 6132590..c37b958 100644
--- a/content/renderer/gpu/compositor_software_output_device.cc
+++ b/content/renderer/gpu/compositor_software_output_device.cc
@@ -201,6 +201,9 @@
   frame_data->size = viewport_size_;
   frame_data->damage_rect = damage_rect_;
   frame_data->handle = buffer->handle();
+
+  CHECK_LE(static_cast<size_t>(frame_data->size.GetArea()) * 4,
+           buffer->shared_memory()->mapped_size());
 }
 
 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
diff --git a/content/renderer/gpu/compositor_software_output_device.h b/content/renderer/gpu/compositor_software_output_device.h
index e658dfb..ce21b2b 100644
--- a/content/renderer/gpu/compositor_software_output_device.h
+++ b/content/renderer/gpu/compositor_software_output_device.h
@@ -49,6 +49,7 @@
 
     void* memory() const { return mem_->memory(); }
     base::SharedMemoryHandle handle() const { return mem_->handle(); }
+    base::SharedMemory* shared_memory() const { return mem_.get(); }
 
     bool free() const { return free_; }
     void SetFree(bool free) { free_ = free; }
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 12bf272..1af771d 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -17,6 +17,7 @@
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/v8_value_converter.h"
 #include "content/renderer/gpu/render_widget_compositor.h"
+#include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/skia_benchmarking_extension.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
@@ -258,6 +259,10 @@
           "  native function GetRenderingStats();"
           "  return GetRenderingStats();"
           "};"
+          "chrome.gpuBenchmarking.gpuRenderingStats = function() {"
+          "  native function GetGpuRenderingStats();"
+          "  return GetGpuRenderingStats();"
+          "};"
           "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
           "  native function PrintToSkPicture();"
           "  return PrintToSkPicture(dirname);"
@@ -303,6 +308,10 @@
           "  arguments = opt_arguments || {};"
           "  native function RunMicroBenchmark();"
           "  return RunMicroBenchmark(name, callback, arguments);"
+          "};"
+          "chrome.gpuBenchmarking.hasGpuProcess = function() {"
+          "  native function HasGpuProcess();"
+          "  return HasGpuProcess();"
           "};") {}
 
   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
@@ -313,6 +322,8 @@
       return v8::FunctionTemplate::New(SetRasterizeOnlyVisibleContent);
     if (name->Equals(v8::String::New("GetRenderingStats")))
       return v8::FunctionTemplate::New(GetRenderingStats);
+    if (name->Equals(v8::String::New("GetGpuRenderingStats")))
+      return v8::FunctionTemplate::New(GetGpuRenderingStats);
     if (name->Equals(v8::String::New("PrintToSkPicture")))
       return v8::FunctionTemplate::New(PrintToSkPicture);
     if (name->Equals(v8::String::New("BeginSmoothScroll")))
@@ -327,6 +338,8 @@
       return v8::FunctionTemplate::New(ClearImageCache);
     if (name->Equals(v8::String::New("RunMicroBenchmark")))
       return v8::FunctionTemplate::New(RunMicroBenchmark);
+    if (name->Equals(v8::String::New("HasGpuProcess")))
+      return v8::FunctionTemplate::New(HasGpuProcess);
 
     return v8::Handle<v8::FunctionTemplate>();
   }
@@ -373,6 +386,23 @@
     args.GetReturnValue().Set(stats_object);
   }
 
+  static void GetGpuRenderingStats(
+      const v8::FunctionCallbackInfo<v8::Value>& args) {
+
+    GpuBenchmarkingContext context;
+    if (!context.Init(false))
+      return;
+
+    content::GpuRenderingStats gpu_stats;
+    context.render_view_impl()->GetGpuRenderingStats(&gpu_stats);
+
+    v8::Handle<v8::Object> stats_object = v8::Object::New();
+    RenderingStatsEnumerator enumerator(stats_object);
+    gpu_stats.EnumerateFields(&enumerator);
+
+    args.GetReturnValue().Set(stats_object);
+  }
+
   static void PrintToSkPicture(
       const v8::FunctionCallbackInfo<v8::Value>& args) {
     if (args.Length() != 1)
@@ -655,6 +685,11 @@
         value.Pass(),
         base::Bind(&OnMicroBenchmarkCompleted, callback_and_context)));
   }
+
+  static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) {
+    GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
+    args.GetReturnValue().Set(!!gpu_channel);
+  }
 };
 
 v8::Extension* GpuBenchmarkingExtension::Get() {
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index d9ebdcb..634044a 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -104,7 +104,7 @@
 
   settings.throttle_frame_production =
       !cmd->HasSwitch(switches::kDisableGpuVsync);
-  settings.begin_frame_scheduling_enabled =
+  settings.begin_impl_frame_scheduling_enabled =
       cmd->HasSwitch(switches::kEnableBeginFrameScheduling);
   settings.deadline_scheduling_enabled =
       cmd->HasSwitch(switches::kEnableDeadlineScheduling) &&
@@ -340,6 +340,10 @@
   suppress_schedule_composite_ = suppress;
 }
 
+bool RenderWidgetCompositor::BeginMainFrameRequested() const {
+  return layer_tree_host_->BeginMainFrameRequested();
+}
+
 void RenderWidgetCompositor::Animate(base::TimeTicks time) {
   layer_tree_host_->UpdateClientAnimations(time);
 }
@@ -412,9 +416,8 @@
 bool RenderWidgetCompositor::initialize(cc::LayerTreeSettings settings) {
   scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy =
       RenderThreadImpl::current()->compositor_message_loop_proxy();
-  layer_tree_host_ = cc::LayerTreeHost::Create(this,
-                                               settings,
-                                               compositor_message_loop_proxy);
+  layer_tree_host_ = cc::LayerTreeHost::Create(
+      this, NULL, settings, compositor_message_loop_proxy);
   return layer_tree_host_;
 }
 
@@ -586,12 +589,12 @@
   layer_tree_host_->SetDebugState(debug_state);
 }
 
-void RenderWidgetCompositor::WillBeginFrame() {
+void RenderWidgetCompositor::WillBeginMainFrame() {
   widget_->InstrumentWillBeginFrame();
   widget_->willBeginCompositorFrame();
 }
 
-void RenderWidgetCompositor::DidBeginFrame() {
+void RenderWidgetCompositor::DidBeginMainFrame() {
   widget_->InstrumentDidBeginFrame();
 }
 
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index e88a995..2316bb8 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -42,6 +42,7 @@
 
   const base::WeakPtr<cc::InputHandler>& GetInputHandler();
   void SetSuppressScheduleComposite(bool suppress);
+  bool BeginMainFrameRequested() const;
   void Animate(base::TimeTicks time);
   void Composite(base::TimeTicks frame_begin_time);
   void SetNeedsDisplayOnAllLayers();
@@ -109,8 +110,8 @@
   virtual void setShowScrollBottleneckRects(bool show);
 
   // cc::LayerTreeHostClient implementation.
-  virtual void WillBeginFrame() OVERRIDE;
-  virtual void DidBeginFrame() OVERRIDE;
+  virtual void WillBeginMainFrame() OVERRIDE;
+  virtual void DidBeginMainFrame() OVERRIDE;
   virtual void Animate(double frame_begin_time) OVERRIDE;
   virtual void Layout() OVERRIDE;
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 87ecea5..ad6aab2 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -70,6 +70,9 @@
       audio_stream_(NULL),
       video_stream_(NULL),
       seeking_(false),
+      doing_browser_seek_(false),
+      browser_seek_time_(media::kNoTimestamp()),
+      expecting_regular_seek_(false),
 #if defined(GOOGLE_TV)
       key_added_(false),
 #endif
@@ -226,13 +229,22 @@
   DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
            << demuxer_client_id_;
 
-  if (chunk_demuxer_) {
-    // It is possible that we have just completed the seek,
-    // but caller does not know this yet. It is still safe to cancel in this
-    // case because the caller will always call StartWaitingForSeek() when it
-    // is notified of the completed seek.
-    chunk_demuxer_->CancelPendingSeek(seek_time);
+  if (!chunk_demuxer_)
+    return;
+
+  {
+    // Remember to trivially finish any newly arriving browser seek requests
+    // that may arrive prior to the next regular seek request.
+    base::AutoLock auto_lock(seeking_lock_);
+    expecting_regular_seek_ = true;
   }
+
+  // Cancel any previously expected or in-progress regular or browser seek.
+  // It is possible that we have just finished the seek, but caller does
+  // not know this yet. It is still safe to cancel in this case because the
+  // caller will always call StartWaitingForSeek() when it is notified of
+  // the finished seek.
+  chunk_demuxer_->CancelPendingSeek(seek_time);
 }
 
 void MediaSourceDelegate::StartWaitingForSeek(
@@ -240,20 +252,70 @@
   DCHECK(main_loop_->BelongsToCurrentThread());
   DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
            << demuxer_client_id_;
-  DCHECK(!IsSeeking());
 
-  if (chunk_demuxer_)
-    chunk_demuxer_->StartWaitingForSeek(seek_time);
+  if (!chunk_demuxer_)
+    return;
+
+  bool cancel_browser_seek = false;
+  {
+    // Remember to trivially finish any newly arriving browser seek requests
+    // that may arrive prior to the next regular seek request.
+    base::AutoLock auto_lock(seeking_lock_);
+    expecting_regular_seek_ = true;
+
+    // Remember to cancel any in-progress browser seek.
+    if (seeking_) {
+      DCHECK(doing_browser_seek_);
+      cancel_browser_seek = true;
+    }
+  }
+
+  if (cancel_browser_seek)
+    chunk_demuxer_->CancelPendingSeek(seek_time);
+  chunk_demuxer_->StartWaitingForSeek(seek_time);
 }
 
-void MediaSourceDelegate::Seek(const base::TimeDelta& seek_time) {
+void MediaSourceDelegate::Seek(
+    const base::TimeDelta& seek_time, bool is_browser_seek) {
   DCHECK(media_loop_->BelongsToCurrentThread());
-  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
+  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", "
+           << (is_browser_seek ? "browser seek" : "regular seek") << ") : "
            << demuxer_client_id_;
 
-  DCHECK(!IsSeeking());
-  SetSeeking(true);
-  SeekInternal(seek_time);
+  base::TimeDelta internal_seek_time = seek_time;
+  {
+    base::AutoLock auto_lock(seeking_lock_);
+    DCHECK(!seeking_);
+    seeking_ = true;
+    doing_browser_seek_ = is_browser_seek;
+
+    if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) {
+      // Trivially finish the browser seek without actually doing it. Reads will
+      // continue to be |kAborted| until the next regular seek is done. Browser
+      // seeking is not supported unless using a ChunkDemuxer; browser seeks are
+      // trivially finished if |chunk_demuxer_| is NULL.
+      seeking_ = false;
+      doing_browser_seek_ = false;
+      demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time);
+      return;
+    }
+
+    if (doing_browser_seek_) {
+      internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time);
+      browser_seek_time_ = internal_seek_time;
+    } else {
+      expecting_regular_seek_ = false;
+      browser_seek_time_ = media::kNoTimestamp();
+    }
+  }
+
+  // Prepare |chunk_demuxer_| for browser seek.
+  if (is_browser_seek) {
+    chunk_demuxer_->CancelPendingSeek(internal_seek_time);
+    chunk_demuxer_->StartWaitingForSeek(internal_seek_time);
+  }
+
+  SeekInternal(internal_seek_time);
 }
 
 void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) {
@@ -585,8 +647,12 @@
 void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
   DCHECK(media_loop_->BelongsToCurrentThread());
   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
-  SetSeeking(false);
-  demuxer_client_->DemuxerSeekDone(demuxer_client_id_);
+
+  base::AutoLock auto_lock(seeking_lock_);
+  DCHECK(seeking_);
+  seeking_ = false;
+  doing_browser_seek_ = false;
+  demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
 }
 
 void MediaSourceDelegate::OnDemuxerStopDone() {
@@ -716,14 +782,50 @@
           video_stream_->video_decoder_config().is_encrypted());
 }
 
-void MediaSourceDelegate::SetSeeking(bool seeking) {
-  base::AutoLock auto_lock(seeking_lock_);
-  seeking_ = seeking;
-}
-
 bool MediaSourceDelegate::IsSeeking() const {
   base::AutoLock auto_lock(seeking_lock_);
   return seeking_;
 }
 
+base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked(
+    const base::TimeDelta& seek_time) const {
+  seeking_lock_.AssertAcquired();
+  DCHECK(seeking_);
+  DCHECK(doing_browser_seek_);
+  DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer";
+
+  media::Ranges<base::TimeDelta> buffered =
+      chunk_demuxer_->GetBufferedRanges();
+
+  for (size_t i = 0; i < buffered.size(); ++i) {
+    base::TimeDelta range_start = buffered.start(i);
+    base::TimeDelta range_end = buffered.end(i);
+    if (range_start <= seek_time) {
+      if (range_end >= seek_time)
+        return seek_time;
+      continue;
+    }
+
+    // If the start of the next buffered range after |seek_time| is too far
+    // into the future, do not jump forward.
+    if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100))
+      break;
+
+    // TODO(wolenetz): Remove possibility that this browser seek jumps
+    // into future when the requested range is unbuffered but there is some
+    // other buffered range after it. See http://crbug.com/304234.
+    return range_start;
+  }
+
+  // We found no range containing |seek_time| or beginning shortly after
+  // |seek_time|. While possible that such data at and beyond the player's
+  // current time have been garbage collected or removed by the web app, this is
+  // unlikely. This may cause unexpected playback stall due to seek pending an
+  // append for a GOP prior to the last GOP demuxed.
+  // TODO(wolenetz): Remove the possibility for this seek to cause unexpected
+  // player stall by replaying cached data since last keyframe in browser player
+  // rather than issuing browser seek. See http://crbug.com/304234.
+  return seek_time;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index a13ea6b..4c3564e 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -79,16 +79,26 @@
   size_t AudioDecodedByteCount() const;
   size_t VideoDecodedByteCount() const;
 
-  // In MSE case, calls ChunkDemuxer::CancelPendingSeek().
+  // In MSE case, calls ChunkDemuxer::CancelPendingSeek(). Also sets the
+  // expectation that a regular seek will be arriving and to trivially finish
+  // any browser seeks that may be requested prior to the regular seek.
   void CancelPendingSeek(const base::TimeDelta& seek_time);
 
-  // In MSE case, calls ChunkDemuxer::StartWaitingForSeek().
+  // In MSE case, calls ChunkDemuxer::StartWaitingForSeek(), first calling
+  // ChunkDemuxer::CancelPendingSeek() if a browser seek is in progress.
+  // Also sets the expectation that a regular seek will be arriving and to
+  // trivially finish any browser seeks that may be requested prior to the
+  // regular seek.
   void StartWaitingForSeek(const base::TimeDelta& seek_time);
 
   // Seeks the demuxer and later calls OnDemuxerSeekDone() after the seek has
   // been completed. There must be no other seek of the demuxer currently in
   // process when this method is called.
-  void Seek(const base::TimeDelta& seek_time);
+  // If |is_browser_seek| is true, then this is a short-term hack browser
+  // seek.
+  // TODO(wolenetz): Instead of doing browser seek, browser player should replay
+  // cached data since last keyframe. See http://crbug.com/304234.
+  void Seek(const base::TimeDelta& seek_time, bool is_browser_seek);
 
   void NotifyKeyAdded(const std::string& key_system);
 
@@ -167,9 +177,16 @@
 
   bool HasEncryptedStream();
 
-  void SetSeeking(bool seeking);
   bool IsSeeking() const;
 
+  // Returns |seek_time| if it is still buffered or if there is no currently
+  // buffered range including or soon after |seek_time|. If |seek_time| is not
+  // buffered, but there is a later range buffered near to |seek_time|, returns
+  // next buffered range's start time instead. Only call this for browser seeks.
+  // |seeking_lock_| must be held by caller.
+  base::TimeDelta FindBufferedBrowserSeekTime_Locked(
+      const base::TimeDelta& seek_time) const;
+
   // Message loop for main renderer thread and corresponding weak pointer.
   const scoped_refptr<base::MessageLoopProxy> main_loop_;
   base::WeakPtrFactory<MediaSourceDelegate> main_weak_factory_;
@@ -218,6 +235,15 @@
   mutable base::Lock seeking_lock_;
   bool seeking_;
 
+  // Track if we are currently performing a browser seek, and track whether or
+  // not a regular seek is expected soon. If a regular seek is expected soon,
+  // then any in-progress browser seek will be canceled pending the
+  // regular seek, if using |chunk_demuxer_|, and any requested browser seek
+  // will be trivially finished. Access is serialized by |seeking_lock_|.
+  bool doing_browser_seek_;
+  base::TimeDelta browser_seek_time_;
+  bool expecting_regular_seek_;
+
 #if defined(GOOGLE_TV)
   bool key_added_;
   std::string key_system_;
diff --git a/content/renderer/media/android/proxy_media_keys.cc b/content/renderer/media/android/proxy_media_keys.cc
index 2beb66a..2df2dbc 100644
--- a/content/renderer/media/android/proxy_media_keys.cc
+++ b/content/renderer/media/android/proxy_media_keys.cc
@@ -8,15 +8,25 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
+#include "content/renderer/media/android/renderer_media_player_manager.h"
 #include "content/renderer/media/crypto/key_systems.h"
 
 namespace content {
 
-ProxyMediaKeys::ProxyMediaKeys(WebMediaPlayerProxyAndroid* proxy,
-                               int media_keys_id)
-    : proxy_(proxy), media_keys_id_(media_keys_id) {
-  DCHECK(proxy_);
+ProxyMediaKeys::ProxyMediaKeys(RendererMediaPlayerManager* manager,
+                               int media_keys_id,
+                               const media::KeyAddedCB& key_added_cb,
+                               const media::KeyErrorCB& key_error_cb,
+                               const media::KeyMessageCB& key_message_cb)
+    : manager_(manager),
+      media_keys_id_(media_keys_id),
+      key_added_cb_(key_added_cb),
+      key_error_cb_(key_error_cb),
+      key_message_cb_(key_message_cb) {
+  DCHECK(manager_);
+}
+
+ProxyMediaKeys::~ProxyMediaKeys() {
 }
 
 void ProxyMediaKeys::InitializeCDM(const std::string& key_system,
@@ -26,14 +36,14 @@
 #elif defined(OS_ANDROID)
   std::vector<uint8> uuid = GetUUID(key_system);
   DCHECK(!uuid.empty());
-  proxy_->InitializeCDM(media_keys_id_, uuid, frame_url);
+  manager_->InitializeCDM(media_keys_id_, this, uuid, frame_url);
 #endif
 }
 
 bool ProxyMediaKeys::GenerateKeyRequest(const std::string& type,
                                         const uint8* init_data,
                                         int init_data_length) {
-  proxy_->GenerateKeyRequest(
+  manager_->GenerateKeyRequest(
       media_keys_id_,
       type,
       std::vector<uint8>(init_data, init_data + init_data_length));
@@ -43,14 +53,30 @@
 void ProxyMediaKeys::AddKey(const uint8* key, int key_length,
                             const uint8* init_data, int init_data_length,
                             const std::string& session_id) {
-  proxy_->AddKey(media_keys_id_,
+  manager_->AddKey(media_keys_id_,
                  std::vector<uint8>(key, key + key_length),
                  std::vector<uint8>(init_data, init_data + init_data_length),
                  session_id);
 }
 
 void ProxyMediaKeys::CancelKeyRequest(const std::string& session_id) {
-  proxy_->CancelKeyRequest(media_keys_id_, session_id);
+  manager_->CancelKeyRequest(media_keys_id_, session_id);
+}
+
+void ProxyMediaKeys::OnKeyAdded(const std::string& session_id) {
+  key_added_cb_.Run(session_id);
+}
+
+void ProxyMediaKeys::OnKeyError(const std::string& session_id,
+                                media::MediaKeys::KeyError error_code,
+                                int system_code) {
+  key_error_cb_.Run(session_id, error_code, system_code);
+}
+
+void ProxyMediaKeys::OnKeyMessage(const std::string& session_id,
+                                  const std::vector<uint8>& message,
+                                  const std::string& destination_url) {
+  key_message_cb_.Run(session_id, message, destination_url);
 }
 
 }  // namespace content
diff --git a/content/renderer/media/android/proxy_media_keys.h b/content/renderer/media/android/proxy_media_keys.h
index 847a782..10ebf41 100644
--- a/content/renderer/media/android/proxy_media_keys.h
+++ b/content/renderer/media/android/proxy_media_keys.h
@@ -12,15 +12,20 @@
 
 namespace content {
 
-class WebMediaPlayerProxyAndroid;
+class RendererMediaPlayerManager;
 
-// MediaKeys wrapper of the WebMediaPlayerProxyAndroid.
-// TODO(xhwang): Remove |player_id| from WebMediaPlayerProxyAndroid, make
-// WebMediaPlayerProxyAndroid a subclass of media::MediaKeys, then remove this
-// class!
+// A MediaKeys proxy that wraps the EME part of RendererMediaPlayerManager.
+// TODO(xhwang): Instead of accessing RendererMediaPlayerManager directly, let
+// RendererMediaPlayerManager return a MediaKeys object that can be used by
+// ProxyDecryptor directly. Then we can remove this class!
 class ProxyMediaKeys : public media::MediaKeys {
  public:
-  ProxyMediaKeys(WebMediaPlayerProxyAndroid* proxy, int media_keys_id);
+  ProxyMediaKeys(RendererMediaPlayerManager* proxy,
+                 int media_keys_id,
+                 const media::KeyAddedCB& key_added_cb,
+                 const media::KeyErrorCB& key_error_cb,
+                 const media::KeyMessageCB& key_message_cb);
+  virtual ~ProxyMediaKeys();
 
   void InitializeCDM(const std::string& key_system, const GURL& frame_url);
 
@@ -33,11 +38,23 @@
                       const std::string& session_id) OVERRIDE;
   virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE;
 
- private:
-  WebMediaPlayerProxyAndroid* proxy_;
-  int media_keys_id_;
+  // Callbacks.
+  void OnKeyAdded(const std::string& session_id);
+  void OnKeyError(const std::string& session_id,
+                  media::MediaKeys::KeyError error_code,
+                  int system_code);
+  void OnKeyMessage(const std::string& session_id,
+                    const std::vector<uint8>& message,
+                    const std::string& destination_url);
 
-  DISALLOW_COPY_AND_ASSIGN (ProxyMediaKeys);
+ private:
+  RendererMediaPlayerManager* manager_;
+  int media_keys_id_;
+  media::KeyAddedCB key_added_cb_;
+  media::KeyErrorCB key_error_cb_;
+  media::KeyMessageCB key_message_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyMediaKeys);
 };
 
 }  // namespace content
diff --git a/content/renderer/media/android/renderer_demuxer_android.cc b/content/renderer/media/android/renderer_demuxer_android.cc
index 4e9749a..ab139b5 100644
--- a/content/renderer/media/android/renderer_demuxer_android.cc
+++ b/content/renderer/media/android/renderer_demuxer_android.cc
@@ -64,9 +64,11 @@
       demuxer_client_id, data));
 }
 
-void RendererDemuxerAndroid::DemuxerSeekDone(int demuxer_client_id) {
+void RendererDemuxerAndroid::DemuxerSeekDone(
+    int demuxer_client_id,
+    const base::TimeDelta& actual_browser_seek_time) {
   thread_safe_sender_->Send(new MediaPlayerHostMsg_DemuxerSeekDone(
-      demuxer_client_id));
+      demuxer_client_id, actual_browser_seek_time));
 }
 
 void RendererDemuxerAndroid::DurationChanged(int demuxer_client_id,
@@ -93,10 +95,11 @@
 
 void RendererDemuxerAndroid::OnDemuxerSeekRequest(
     int demuxer_client_id,
-    const base::TimeDelta& time_to_seek) {
+    const base::TimeDelta& time_to_seek,
+    bool is_browser_seek) {
   MediaSourceDelegate* delegate = delegates_.Lookup(demuxer_client_id);
   if (delegate)
-    delegate->Seek(time_to_seek);
+    delegate->Seek(time_to_seek, is_browser_seek);
 }
 
 void RendererDemuxerAndroid::OnMediaConfigRequest(int demuxer_client_id) {
diff --git a/content/renderer/media/android/renderer_demuxer_android.h b/content/renderer/media/android/renderer_demuxer_android.h
index 52fbb0d..c6538a1 100644
--- a/content/renderer/media/android/renderer_demuxer_android.h
+++ b/content/renderer/media/android/renderer_demuxer_android.h
@@ -51,7 +51,8 @@
                     const media::DemuxerConfigs& configs);
   void ReadFromDemuxerAck(int demuxer_client_id,
                           const media::DemuxerData& data);
-  void DemuxerSeekDone(int demuxer_client_id);
+  void DemuxerSeekDone(int demuxer_client_id,
+                       const base::TimeDelta& actual_browser_seek_time);
   void DurationChanged(int demuxer_client_id, const base::TimeDelta& duration);
 
  protected:
@@ -63,7 +64,8 @@
   void OnReadFromDemuxer(int demuxer_client_id,
                          media::DemuxerStream::Type type);
   void OnDemuxerSeekRequest(int demuxer_client_id,
-                            const base::TimeDelta& time_to_seek);
+                            const base::TimeDelta& time_to_seek,
+                            bool is_browser_seek);
   void OnMediaConfigRequest(int demuxer_client_id);
 
   base::AtomicSequenceNumber next_demuxer_client_id_;
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc
index 62a99c0..0d2392f 100644
--- a/content/renderer/media/android/renderer_media_player_manager.cc
+++ b/content/renderer/media/android/renderer_media_player_manager.cc
@@ -4,15 +4,20 @@
 
 #include "content/renderer/media/android/renderer_media_player_manager.h"
 
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "content/common/media/media_player_messages_android.h"
+#include "content/renderer/media/android/proxy_media_keys.h"
+#include "content/renderer/media/android/renderer_media_player_manager.h"
 #include "content/renderer/media/android/webmediaplayer_android.h"
 #include "ui/gfx/rect_f.h"
 
 namespace content {
 
-RendererMediaPlayerManager::RendererMediaPlayerManager()
-    : next_media_player_id_(0),
-      fullscreen_frame_(NULL) {
-}
+RendererMediaPlayerManager::RendererMediaPlayerManager(RenderView* render_view)
+    : RenderViewObserver(render_view),
+      next_media_player_id_(0),
+      fullscreen_frame_(NULL) {}
 
 RendererMediaPlayerManager::~RendererMediaPlayerManager() {
   std::map<int, WebMediaPlayerAndroid*>::iterator player_it;
@@ -21,6 +26,271 @@
     WebMediaPlayerAndroid* player = player_it->second;
     player->Detach();
   }
+
+  Send(new MediaPlayerHostMsg_DestroyAllMediaPlayers(routing_id()));
+}
+
+bool RendererMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(RendererMediaPlayerManager, msg)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaMetadataChanged,
+                        OnMediaMetadataChanged)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlaybackCompleted,
+                        OnMediaPlaybackCompleted)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaBufferingUpdate,
+                        OnMediaBufferingUpdate)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekRequest, OnSeekRequest)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekCompleted, OnSeekCompleted)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaError, OnMediaError)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaVideoSizeChanged,
+                        OnVideoSizeChanged)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaTimeUpdate, OnTimeUpdate)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlayerReleased,
+                        OnMediaPlayerReleased)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_ConnectedToRemoteDevice,
+                        OnConnectedToRemoteDevice)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DisconnectedFromRemoteDevice,
+                        OnDisconnectedFromRemoteDevice)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidEnterFullscreen, OnDidEnterFullscreen)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
+    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
+    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyAdded, OnKeyAdded)
+    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyError, OnKeyError)
+    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyMessage, OnKeyMessage)
+  IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void RendererMediaPlayerManager::Initialize(
+    MediaPlayerHostMsg_Initialize_Type type,
+    int player_id,
+    const GURL& url,
+    const GURL& first_party_for_cookies,
+    int demuxer_client_id) {
+  Send(new MediaPlayerHostMsg_Initialize(
+      routing_id(), type, player_id, url, first_party_for_cookies,
+      demuxer_client_id));
+}
+
+void RendererMediaPlayerManager::Start(int player_id) {
+  Send(new MediaPlayerHostMsg_Start(routing_id(), player_id));
+}
+
+void RendererMediaPlayerManager::Pause(
+    int player_id,
+    bool is_media_related_action) {
+  Send(new MediaPlayerHostMsg_Pause(
+      routing_id(), player_id, is_media_related_action));
+}
+
+void RendererMediaPlayerManager::Seek(
+    int player_id,
+    const base::TimeDelta& time) {
+  Send(new MediaPlayerHostMsg_Seek(routing_id(), player_id, time));
+}
+
+void RendererMediaPlayerManager::SetVolume(int player_id, double volume) {
+  Send(new MediaPlayerHostMsg_SetVolume(routing_id(), player_id, volume));
+}
+
+void RendererMediaPlayerManager::ReleaseResources(int player_id) {
+  Send(new MediaPlayerHostMsg_Release(routing_id(), player_id));
+}
+
+void RendererMediaPlayerManager::DestroyPlayer(int player_id) {
+  Send(new MediaPlayerHostMsg_DestroyMediaPlayer(routing_id(), player_id));
+}
+
+void RendererMediaPlayerManager::OnMediaMetadataChanged(
+    int player_id,
+    base::TimeDelta duration,
+    int width,
+    int height,
+    bool success) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnMediaMetadataChanged(duration, width, height, success);
+}
+
+void RendererMediaPlayerManager::OnMediaPlaybackCompleted(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnPlaybackComplete();
+}
+
+void RendererMediaPlayerManager::OnMediaBufferingUpdate(int player_id,
+                                                        int percent) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnBufferingUpdate(percent);
+}
+
+void RendererMediaPlayerManager::OnSeekRequest(
+    int player_id,
+    const base::TimeDelta& time_to_seek) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnSeekRequest(time_to_seek);
+}
+
+void RendererMediaPlayerManager::OnSeekCompleted(
+    int player_id,
+    const base::TimeDelta& current_time) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnSeekComplete(current_time);
+}
+
+void RendererMediaPlayerManager::OnMediaError(int player_id, int error) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnMediaError(error);
+}
+
+void RendererMediaPlayerManager::OnVideoSizeChanged(int player_id,
+                                                    int width,
+                                                    int height) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnVideoSizeChanged(width, height);
+}
+
+void RendererMediaPlayerManager::OnTimeUpdate(int player_id,
+                                              base::TimeDelta current_time) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnTimeUpdate(current_time);
+}
+
+void RendererMediaPlayerManager::OnMediaPlayerReleased(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnPlayerReleased();
+}
+
+void RendererMediaPlayerManager::OnConnectedToRemoteDevice(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnConnectedToRemoteDevice();
+}
+
+void RendererMediaPlayerManager::OnDisconnectedFromRemoteDevice(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnDisconnectedFromRemoteDevice();
+}
+
+void RendererMediaPlayerManager::OnDidEnterFullscreen(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnDidEnterFullscreen();
+}
+
+void RendererMediaPlayerManager::OnDidExitFullscreen(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnDidExitFullscreen();
+}
+
+void RendererMediaPlayerManager::OnPlayerPlay(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnMediaPlayerPlay();
+}
+
+void RendererMediaPlayerManager::OnPlayerPause(int player_id) {
+  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
+  if (player)
+    player->OnMediaPlayerPause();
+}
+
+void RendererMediaPlayerManager::EnterFullscreen(int player_id) {
+  Send(new MediaPlayerHostMsg_EnterFullscreen(routing_id(), player_id));
+}
+
+void RendererMediaPlayerManager::ExitFullscreen(int player_id) {
+  Send(new MediaPlayerHostMsg_ExitFullscreen(routing_id(), player_id));
+}
+
+#if defined(GOOGLE_TV)
+void RendererMediaPlayerManager::RequestExternalSurface(
+    int player_id,
+    const gfx::RectF& geometry) {
+  Send(new MediaPlayerHostMsg_NotifyExternalSurface(
+      routing_id(), player_id, true, geometry));
+}
+
+void RendererMediaPlayerManager::DidCommitCompositorFrame() {
+  std::map<int, gfx::RectF> geometry_change;
+  manager_->RetrieveGeometryChanges(&geometry_change);
+  for (std::map<int, gfx::RectF>::iterator it = geometry_change.begin();
+       it != geometry_change.end();
+       ++it) {
+    Send(new MediaPlayerHostMsg_NotifyExternalSurface(
+        routing_id(), it->first, false, it->second));
+  }
+}
+#endif
+
+void RendererMediaPlayerManager::InitializeCDM(int media_keys_id,
+                                               ProxyMediaKeys* media_keys,
+                                               const std::vector<uint8>& uuid,
+                                               const GURL& frame_url) {
+  RegisterMediaKeys(media_keys_id, media_keys);
+  Send(new MediaKeysHostMsg_InitializeCDM(
+      routing_id(), media_keys_id, uuid, frame_url));
+}
+
+void RendererMediaPlayerManager::GenerateKeyRequest(
+    int media_keys_id,
+    const std::string& type,
+    const std::vector<uint8>& init_data) {
+  Send(new MediaKeysHostMsg_GenerateKeyRequest(
+      routing_id(), media_keys_id, type, init_data));
+}
+
+void RendererMediaPlayerManager::AddKey(int media_keys_id,
+                                        const std::vector<uint8>& key,
+                                        const std::vector<uint8>& init_data,
+                                        const std::string& session_id) {
+  Send(new MediaKeysHostMsg_AddKey(
+      routing_id(), media_keys_id, key, init_data, session_id));
+}
+
+void RendererMediaPlayerManager::CancelKeyRequest(
+    int media_keys_id,
+    const std::string& session_id) {
+  Send(new MediaKeysHostMsg_CancelKeyRequest(
+      routing_id(), media_keys_id, session_id));
+}
+
+void RendererMediaPlayerManager::OnKeyAdded(int media_keys_id,
+                                            const std::string& session_id) {
+  ProxyMediaKeys* media_keys = GetMediaKeys(media_keys_id);
+  if (media_keys)
+    media_keys->OnKeyAdded(session_id);
+}
+
+void RendererMediaPlayerManager::OnKeyError(
+    int media_keys_id,
+    const std::string& session_id,
+    media::MediaKeys::KeyError error_code,
+    int system_code) {
+  ProxyMediaKeys* media_keys = GetMediaKeys(media_keys_id);
+  if (media_keys)
+    media_keys->OnKeyError(session_id, error_code, system_code);
+}
+
+void RendererMediaPlayerManager::OnKeyMessage(
+    int media_keys_id,
+    const std::string& session_id,
+    const std::vector<uint8>& message,
+    const std::string& destination_url) {
+  ProxyMediaKeys* media_keys = GetMediaKeys(media_keys_id);
+  if (media_keys)
+    media_keys->OnKeyMessage(session_id, message, destination_url);
 }
 
 int RendererMediaPlayerManager::RegisterMediaPlayer(
@@ -31,6 +301,20 @@
 
 void RendererMediaPlayerManager::UnregisterMediaPlayer(int player_id) {
   media_players_.erase(player_id);
+  media_keys_.erase(player_id);
+}
+
+void RendererMediaPlayerManager::RegisterMediaKeys(int media_keys_id,
+                                                   ProxyMediaKeys* media_keys) {
+  // WebMediaPlayerAndroid must have already been registered for
+  // |media_keys_id|. For now |media_keys_id| is the same as player_id
+  // used in other methods.
+  DCHECK(media_players_.find(media_keys_id) != media_players_.end());
+
+  // Only allowed to register once.
+  DCHECK(media_keys_.find(media_keys_id) == media_keys_.end());
+
+  media_keys_[media_keys_id] = media_keys;
 }
 
 void RendererMediaPlayerManager::ReleaseVideoResources() {
@@ -54,6 +338,12 @@
   return NULL;
 }
 
+ProxyMediaKeys* RendererMediaPlayerManager::GetMediaKeys(int media_keys_id) {
+  std::map<int, ProxyMediaKeys*>::iterator iter =
+      media_keys_.find(media_keys_id);
+  return (iter != media_keys_.end()) ? iter->second : NULL;
+}
+
 bool RendererMediaPlayerManager::CanEnterFullscreen(WebKit::WebFrame* frame) {
   return !fullscreen_frame_ || IsInFullscreen(frame);
 }
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h
index e565602..4a16b83 100644
--- a/content/renderer/media/android/renderer_media_player_manager.h
+++ b/content/renderer/media/android/renderer_media_player_manager.h
@@ -6,8 +6,20 @@
 #define CONTENT_RENDERER_MEDIA_ANDROID_RENDERER_MEDIA_PLAYER_MANAGER_H_
 
 #include <map>
+#include <string>
+#include <vector>
 
 #include "base/basictypes.h"
+#include "base/time/time.h"
+#include "content/common/media/media_player_messages_enums_android.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "media/base/android/media_player_android.h"
+#include "media/base/media_keys.h"
+#include "url/gurl.h"
+
+#if defined(GOOGLE_TV)
+#include "ui/gfx/rect_f.h"
+#endif
 
 namespace WebKit {
 class WebFrame;
@@ -19,46 +31,151 @@
 
 namespace content {
 
+class ProxyMediaKeys;
 class WebMediaPlayerAndroid;
 
 // Class for managing all the WebMediaPlayerAndroid objects in the same
 // RenderView.
-class RendererMediaPlayerManager {
+class RendererMediaPlayerManager : public RenderViewObserver {
  public:
-  RendererMediaPlayerManager();
+  // Constructs a RendererMediaPlayerManager object for the |render_view|.
+  RendererMediaPlayerManager(RenderView* render_view);
   virtual ~RendererMediaPlayerManager();
 
-  // Register and unregister a WebMediaPlayerAndroid object.
+  // RenderViewObserver overrides.
+  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+
+  // Initializes a MediaPlayerAndroid object in browser process.
+  void Initialize(MediaPlayerHostMsg_Initialize_Type type,
+                  int player_id,
+                  const GURL& url,
+                  const GURL& first_party_for_cookies,
+                  int demuxer_client_id);
+
+  // Starts the player.
+  void Start(int player_id);
+
+  // Pauses the player.
+  // is_media_related_action should be true if this pause is coming from an
+  // an action that explicitly pauses the video (user pressing pause, JS, etc.)
+  // Otherwise it should be false if Pause is being called due to other reasons
+  // (cleanup, freeing resources, etc.)
+  void Pause(int player_id, bool is_media_related_action);
+
+  // Performs seek on the player.
+  void Seek(int player_id, const base::TimeDelta& time);
+
+  // Sets the player volume.
+  void SetVolume(int player_id, double volume);
+
+  // Releases resources for the player.
+  void ReleaseResources(int player_id);
+
+  // Destroys the player in the browser process
+  void DestroyPlayer(int player_id);
+
+  // Requests the player to enter fullscreen.
+  void EnterFullscreen(int player_id);
+
+  // Requests the player to exit fullscreen.
+  void ExitFullscreen(int player_id);
+
+#if defined(GOOGLE_TV)
+  // Requests an external surface for out-of-band compositing.
+  void RequestExternalSurface(int player_id, const gfx::RectF& geometry);
+
+  // RenderViewObserver overrides.
+  virtual void DidCommitCompositorFrame() OVERRIDE;
+#endif
+
+  // Encrypted media related methods.
+  void InitializeCDM(int media_keys_id,
+                     ProxyMediaKeys* media_keys,
+                     const std::vector<uint8>& uuid,
+                     const GURL& frame_url);
+  void GenerateKeyRequest(int media_keys_id,
+                          const std::string& type,
+                          const std::vector<uint8>& init_data);
+  void AddKey(int media_keys_id,
+              const std::vector<uint8>& key,
+              const std::vector<uint8>& init_data,
+              const std::string& session_id);
+  void CancelKeyRequest(int media_keys_id, const std::string& session_id);
+
+  // Registers and unregisters a WebMediaPlayerAndroid object.
   int RegisterMediaPlayer(WebMediaPlayerAndroid* player);
   void UnregisterMediaPlayer(int player_id);
 
-  // Release the media resources managed by this object when a video
+  // Registers a ProxyMediaKeys object. There must be a WebMediaPlayerAndroid
+  // object already registered for this id, and it is unregistered when the
+  // player is unregistered. For now |media_keys_id| is the same as player_id
+  // used in other methods.
+  void RegisterMediaKeys(int media_keys_id, ProxyMediaKeys* media_keys);
+
+  // Releases the media resources managed by this object when a video
   // is playing.
   void ReleaseVideoResources();
 
-  // Check whether a player can enter fullscreen.
+  // Checks whether a player can enter fullscreen.
   bool CanEnterFullscreen(WebKit::WebFrame* frame);
 
   // Called when a player entered or exited fullscreen.
   void DidEnterFullscreen(WebKit::WebFrame* frame);
   void DidExitFullscreen();
 
-  // Check whether the Webframe is in fullscreen.
+  // Checks whether the Webframe is in fullscreen.
   bool IsInFullscreen(WebKit::WebFrame* frame);
 
-  // Get the pointer to WebMediaPlayerAndroid given the |player_id|.
+  // Gets the pointer to WebMediaPlayerAndroid given the |player_id|.
   WebMediaPlayerAndroid* GetMediaPlayer(int player_id);
 
+  // Gets the pointer to ProxyMediaKeys given the |media_keys_id|.
+  ProxyMediaKeys* GetMediaKeys(int media_keys_id);
+
 #if defined(GOOGLE_TV)
-  // Get the list of media players with video geometry changes.
+  // Gets the list of media players with video geometry changes.
   void RetrieveGeometryChanges(std::map<int, gfx::RectF>* changes);
 #endif
 
  private:
+  // Message handlers.
+  void OnMediaMetadataChanged(int player_id,
+                              base::TimeDelta duration,
+                              int width,
+                              int height,
+                              bool success);
+  void OnMediaPlaybackCompleted(int player_id);
+  void OnMediaBufferingUpdate(int player_id, int percent);
+  void OnSeekRequest(int player_id, const base::TimeDelta& time_to_seek);
+  void OnSeekCompleted(int player_id, const base::TimeDelta& current_time);
+  void OnMediaError(int player_id, int error);
+  void OnVideoSizeChanged(int player_id, int width, int height);
+  void OnTimeUpdate(int player_id, base::TimeDelta current_time);
+  void OnMediaPlayerReleased(int player_id);
+  void OnConnectedToRemoteDevice(int player_id);
+  void OnDisconnectedFromRemoteDevice(int player_id);
+  void OnDidExitFullscreen(int player_id);
+  void OnDidEnterFullscreen(int player_id);
+  void OnPlayerPlay(int player_id);
+  void OnPlayerPause(int player_id);
+  void OnKeyAdded(int media_keys_id, const std::string& session_id);
+  void OnKeyError(int media_keys_id,
+                  const std::string& session_id,
+                  media::MediaKeys::KeyError error_code,
+                  int system_code);
+  void OnKeyMessage(int media_keys_id,
+                    const std::string& session_id,
+                    const std::vector<uint8>& message,
+                    const std::string& destination_url);
+
   // Info for all available WebMediaPlayerAndroid on a page; kept so that
-  // we can enumerate them to send updates about tab focus and visibily.
+  // we can enumerate them to send updates about tab focus and visibility.
   std::map<int, WebMediaPlayerAndroid*> media_players_;
 
+  // Info for all available ProxyMediaKeys. There must be at most one
+  // ProxyMediaKeys for each available WebMediaPlayerAndroid.
+  std::map<int, ProxyMediaKeys*> media_keys_;
+
   int next_media_player_id_;
 
   // WebFrame of the fullscreen video.
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index efa5917..01bfa71 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -17,7 +17,6 @@
 #include "content/renderer/media/android/proxy_media_keys.h"
 #include "content/renderer/media/android/renderer_demuxer_android.h"
 #include "content/renderer/media/android/renderer_media_player_manager.h"
-#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
 #include "content/renderer/media/crypto/key_systems.h"
 #include "content/renderer/media/webmediaplayer_delegate.h"
 #include "content/renderer/media/webmediaplayer_util.h"
@@ -63,12 +62,23 @@
 
 namespace content {
 
+// static
+void WebMediaPlayerAndroid::OnReleaseRemotePlaybackTexture(
+    const scoped_refptr<base::MessageLoopProxy>& main_loop,
+    const base::WeakPtr<WebMediaPlayerAndroid>& player,
+    uint32 sync_point) {
+  main_loop->PostTask(
+      FROM_HERE,
+      base::Bind(&WebMediaPlayerAndroid::DoReleaseRemotePlaybackTexture,
+                 player,
+                 sync_point));
+}
+
 WebMediaPlayerAndroid::WebMediaPlayerAndroid(
     WebKit::WebFrame* frame,
     WebKit::WebMediaPlayerClient* client,
     base::WeakPtr<WebMediaPlayerDelegate> delegate,
     RendererMediaPlayerManager* manager,
-    WebMediaPlayerProxyAndroid* proxy,
     StreamTextureFactory* factory,
     const scoped_refptr<base::MessageLoopProxy>& media_loop,
     media::MediaLog* media_log)
@@ -106,11 +116,10 @@
 #endif  // defined(GOOGLE_TV)
       pending_playback_(false),
       player_type_(MEDIA_PLAYER_TYPE_URL),
-      proxy_(proxy),
       current_time_(0),
       is_remote_(false),
-      media_log_(media_log) {
-  DCHECK(proxy_);
+      media_log_(media_log),
+      weak_factory_(this) {
   DCHECK(manager_);
 
   DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -146,7 +155,7 @@
         client,
         frame,
 #else
-        proxy_,
+        manager_,
         player_id_,  // TODO(xhwang): Use media_keys_id when MediaKeys are
                      // separated from WebMediaPlayer.
 #endif  // defined(ENABLE_PEPPER_CDMS)
@@ -162,8 +171,10 @@
   SetVideoFrameProviderClient(NULL);
   client_->setWebLayer(NULL);
 
-  if (proxy_)
-    proxy_->DestroyPlayer(player_id_);
+  if (manager_) {
+    manager_->DestroyPlayer(player_id_);
+    manager_->UnregisterMediaPlayer(player_id_);
+  }
 
   if (stream_id_)
     stream_texture_factory_->DestroyStreamTexture(texture_id_);
@@ -175,9 +186,6 @@
       context->deleteTexture(remote_playback_texture_id_);
   }
 
-  if (manager_)
-    manager_->UnregisterMediaPlayer(player_id_);
-
   if (base::MessageLoop::current())
     base::MessageLoop::current()->RemoveDestructionObserver(this);
 
@@ -250,13 +258,13 @@
     if (player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE) {
       media_source_delegate_->InitializeMediaSource(
           base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,
-                     base::Unretained(this)),
+                     weak_factory_.GetWeakPtr()),
           base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)),
           set_decryptor_ready_cb,
           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
-                     base::Unretained(this)),
+                     weak_factory_.GetWeakPtr()),
           base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
-                     base::Unretained(this)));
+                     weak_factory_.GetWeakPtr()));
     }
 #if defined(GOOGLE_TV)
     // TODO(xhwang): Pass set_decryptor_ready_cb in InitializeMediaStream() to
@@ -265,7 +273,7 @@
       media_source_delegate_->InitializeMediaStream(
           demuxer_,
           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
-                     base::Unretained(this)));
+                     weak_factory_.GetWeakPtr()));
       audio_renderer_ = media_stream_client_->GetAudioRenderer(url);
       if (audio_renderer_)
         audio_renderer_->Start();
@@ -283,11 +291,11 @@
 
   url_ = url;
   GURL first_party_url = frame_->document().firstPartyForCookies();
-  proxy_->Initialize(
+  manager_->Initialize(
       player_type_, player_id_, url, first_party_url, demuxer_client_id);
 
   if (manager_->IsInFullscreen(frame_))
-    proxy_->EnterFullscreen(player_id_);
+    manager_->EnterFullscreen(player_id_);
 
   UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
   UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
@@ -320,7 +328,7 @@
   if (hasVideo() && needs_external_surface_ &&
       !manager_->IsInFullscreen(frame_)) {
     DCHECK(!needs_establish_peer_);
-    proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
+    manager_->RequestExternalSurface(player_id_, last_computed_rect_);
   }
   if (audio_renderer_ && paused())
     audio_renderer_->Play();
@@ -331,7 +339,7 @@
     EstablishSurfaceTexturePeer();
 
   if (paused())
-    proxy_->Start(player_id_);
+    manager_->Start(player_id_);
   UpdatePlayingState(true);
   UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
   playing_started_ = true;
@@ -346,7 +354,7 @@
   if (audio_renderer_ && !paused())
     audio_renderer_->Pause();
 #endif
-  proxy_->Pause(player_id_, is_media_related_action);
+  manager_->Pause(player_id_, is_media_related_action);
   UpdatePlayingState(false);
 }
 
@@ -391,7 +399,7 @@
     media_source_delegate_->StartWaitingForSeek(seek_time_);
 
   // Kick off the asynchronous seek!
-  proxy_->Seek(player_id_, seek_time_);
+  manager_->Seek(player_id_, seek_time_);
 }
 
 bool WebMediaPlayerAndroid::supportsFullscreen() const {
@@ -407,7 +415,7 @@
 }
 
 void WebMediaPlayerAndroid::setVolume(double volume) {
-  proxy_->SetVolume(player_id_, volume);
+  manager_->SetVolume(player_id_, volume);
 }
 
 bool WebMediaPlayerAndroid::hasVideo() const {
@@ -725,7 +733,7 @@
       media_source_delegate_) {
     needs_external_surface_ = true;
     if (!paused() && !manager_->IsInFullscreen(frame_))
-      proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
+      manager_->RequestExternalSurface(player_id_, last_computed_rect_);
   } else if (stream_texture_factory_ && !stream_id_) {
     // Do deferred stream texture creation finally.
     DoCreateStreamTexture();
@@ -763,7 +771,6 @@
     EstablishSurfaceTexturePeer();
   is_remote_ = false;
   ReallocateVideoFrame();
-  // TODO(sievers): Consider deleting remote_playback_texture_id_ here.
 }
 
 void WebMediaPlayerAndroid::OnDidEnterFullscreen() {
@@ -785,7 +792,7 @@
 
 #if defined(GOOGLE_TV)
   if (!paused() && needs_external_surface_)
-    proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
+    manager_->RequestExternalSurface(player_id_, last_computed_rect_);
 #endif
 
   frame_->view()->willExitFullScreen();
@@ -872,7 +879,7 @@
     case WebMediaPlayer::NetworkStateDecodeError:
       break;
   }
-  proxy_->ReleaseResources(player_id_);
+  manager_->ReleaseResources(player_id_);
   OnPlayerReleased();
 }
 
@@ -895,7 +902,6 @@
   }
   is_remote_ = false;
   manager_ = NULL;
-  proxy_ = NULL;
 }
 
 void WebMediaPlayerAndroid::DrawRemotePlaybackIcon() {
@@ -983,7 +989,9 @@
       new VideoFrame::MailboxHolder(
           texture_mailbox,
           texture_mailbox_sync_point,
-          VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
+          base::Bind(&WebMediaPlayerAndroid::OnReleaseRemotePlaybackTexture,
+                     main_loop_,
+                     weak_factory_.GetWeakPtr())),
       texture_target,
       canvas_size /* coded_size */,
       gfx::Rect(canvas_size) /* visible_rect */,
@@ -1037,10 +1045,8 @@
 
 void WebMediaPlayerAndroid::SetCurrentFrameInternal(
     scoped_refptr<media::VideoFrame>& video_frame) {
-  {
-    base::AutoLock auto_lock(current_frame_lock_);
-    current_frame_ = video_frame;
-  }
+  base::AutoLock auto_lock(current_frame_lock_);
+  current_frame_ = video_frame;
 }
 
 scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
@@ -1404,15 +1410,28 @@
 }
 #endif
 
+void WebMediaPlayerAndroid::DoReleaseRemotePlaybackTexture(uint32 sync_point) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK(remote_playback_texture_id_);
+
+  WebKit::WebGraphicsContext3D* context =
+      stream_texture_factory_->Context3d();
+
+  if (sync_point)
+    context->waitSyncPoint(sync_point);
+  context->deleteTexture(remote_playback_texture_id_);
+  remote_playback_texture_id_ = 0;
+}
+
 void WebMediaPlayerAndroid::enterFullscreen() {
   if (manager_->CanEnterFullscreen(frame_)) {
-    proxy_->EnterFullscreen(player_id_);
+    manager_->EnterFullscreen(player_id_);
     SetNeedsEstablishPeer(false);
   }
 }
 
 void WebMediaPlayerAndroid::exitFullscreen() {
-  proxy_->ExitFullscreen(player_id_);
+  manager_->ExitFullscreen(player_id_);
 }
 
 bool WebMediaPlayerAndroid::canEnterFullscreen() const {
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 3ad1e3c..0edc3ef 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -47,7 +47,6 @@
 namespace content {
 class WebMediaPlayerDelegate;
 class RendererMediaPlayerManager;
-class WebMediaPlayerProxyAndroid;
 
 #if defined(GOOGLE_TV)
 class MediaStreamAudioRenderer;
@@ -76,7 +75,6 @@
       WebKit::WebMediaPlayerClient* client,
       base::WeakPtr<WebMediaPlayerDelegate> delegate,
       RendererMediaPlayerManager* manager,
-      WebMediaPlayerProxyAndroid* proxy,
       StreamTextureFactory* factory,
       const scoped_refptr<base::MessageLoopProxy>& media_loop,
       media::MediaLog* media_log);
@@ -233,6 +231,12 @@
                          const base::Closure& destroy_demuxer_cb);
 #endif
 
+  // Can be called on any thread.
+  static void OnReleaseRemotePlaybackTexture(
+      const scoped_refptr<base::MessageLoopProxy>& main_loop,
+      const base::WeakPtr<WebMediaPlayerAndroid>& player,
+      uint32 sync_point);
+
  protected:
   // Helper method to update the playing state.
   void UpdatePlayingState(bool is_playing_);
@@ -261,6 +265,7 @@
   void ReallocateVideoFrame();
   void SetCurrentFrameInternal(scoped_refptr<media::VideoFrame>& frame);
   void DidLoadMediaInfo(MediaInfoLoader::Status status);
+  void DoReleaseRemotePlaybackTexture(uint32 sync_point);
 
   // Actually do the work for generateKeyRequest/addKey so they can easily
   // report results to UMA.
@@ -333,7 +338,8 @@
   // Whether loading has progressed since the last call to didLoadingProgress.
   mutable bool did_loading_progress_;
 
-  // Manager for managing this object.
+  // Manager for managing this object and for delegating method calls on
+  // Render Thread.
   RendererMediaPlayerManager* manager_;
 
   // Player ID assigned by the |manager_|.
@@ -360,7 +366,7 @@
   // Whether the mediaplayer is playing.
   bool is_playing_;
 
-  // Wether the mediaplayer has already started playing.
+  // Whether the mediaplayer has already started playing.
   bool playing_started_;
 
   // Whether media player needs to re-establish the surface texture peer.
@@ -417,11 +423,6 @@
 
   MediaPlayerHostMsg_Initialize_Type player_type_;
 
-  // Proxy object that delegates method calls on Render Thread.
-  // This object is created on the Render Thread and is only called in the
-  // destructor.
-  WebMediaPlayerProxyAndroid* proxy_;
-
   // The current playing time. Because the media player is in the browser
   // process, it will regularly update the |current_time_| by calling
   // OnTimeUpdate().
@@ -445,6 +446,8 @@
   // The decryptor that manages decryption keys and decrypts encrypted frames.
   scoped_ptr<ProxyDecryptor> decryptor_;
 
+  base::WeakPtrFactory<WebMediaPlayerAndroid> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerAndroid);
 };
 
diff --git a/content/renderer/media/android/webmediaplayer_proxy_android.cc b/content/renderer/media/android/webmediaplayer_proxy_android.cc
deleted file mode 100644
index f5137cb..0000000
--- a/content/renderer/media/android/webmediaplayer_proxy_android.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "content/common/media/media_player_messages_android.h"
-#include "content/renderer/media/android/renderer_media_player_manager.h"
-#include "content/renderer/media/android/webmediaplayer_android.h"
-
-namespace content {
-
-WebMediaPlayerProxyAndroid::WebMediaPlayerProxyAndroid(
-    RenderView* render_view,
-    RendererMediaPlayerManager* manager)
-    : RenderViewObserver(render_view),
-      manager_(manager) {}
-
-WebMediaPlayerProxyAndroid::~WebMediaPlayerProxyAndroid() {
-  Send(new MediaPlayerHostMsg_DestroyAllMediaPlayers(routing_id()));
-}
-
-bool WebMediaPlayerProxyAndroid::OnMessageReceived(const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(WebMediaPlayerProxyAndroid, msg)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaMetadataChanged,
-                        OnMediaMetadataChanged)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlaybackCompleted,
-                        OnMediaPlaybackCompleted)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaBufferingUpdate,
-                        OnMediaBufferingUpdate)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekRequest, OnSeekRequest)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekCompleted, OnSeekCompleted)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaError, OnMediaError)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaVideoSizeChanged,
-                        OnVideoSizeChanged)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaTimeUpdate, OnTimeUpdate)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlayerReleased,
-                        OnMediaPlayerReleased)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_ConnectedToRemoteDevice,
-                        OnConnectedToRemoteDevice)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DisconnectedFromRemoteDevice,
-                        OnDisconnectedFromRemoteDevice)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidEnterFullscreen, OnDidEnterFullscreen)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
-    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyAdded, OnKeyAdded)
-    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyError, OnKeyError)
-    IPC_MESSAGE_HANDLER(MediaKeysMsg_KeyMessage, OnKeyMessage)
-  IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void WebMediaPlayerProxyAndroid::Initialize(
-    MediaPlayerHostMsg_Initialize_Type type,
-    int player_id,
-    const GURL& url,
-    const GURL& first_party_for_cookies,
-    int demuxer_client_id) {
-  Send(new MediaPlayerHostMsg_Initialize(
-      routing_id(), type, player_id, url, first_party_for_cookies,
-      demuxer_client_id));
-}
-
-void WebMediaPlayerProxyAndroid::Start(int player_id) {
-  Send(new MediaPlayerHostMsg_Start(routing_id(), player_id));
-}
-
-void WebMediaPlayerProxyAndroid::Pause(
-    int player_id,
-    bool is_media_related_action) {
-  Send(new MediaPlayerHostMsg_Pause(
-      routing_id(), player_id, is_media_related_action));
-}
-
-void WebMediaPlayerProxyAndroid::Seek(
-    int player_id,
-    const base::TimeDelta& time) {
-  Send(new MediaPlayerHostMsg_Seek(routing_id(), player_id, time));
-}
-
-void WebMediaPlayerProxyAndroid::SetVolume(int player_id, double volume) {
-  Send(new MediaPlayerHostMsg_SetVolume(routing_id(), player_id, volume));
-}
-
-void WebMediaPlayerProxyAndroid::ReleaseResources(int player_id) {
-  Send(new MediaPlayerHostMsg_Release(routing_id(), player_id));
-}
-
-void WebMediaPlayerProxyAndroid::DestroyPlayer(int player_id) {
-  Send(new MediaPlayerHostMsg_DestroyMediaPlayer(routing_id(), player_id));
-}
-
-void WebMediaPlayerProxyAndroid::OnMediaMetadataChanged(
-    int player_id,
-    base::TimeDelta duration,
-    int width,
-    int height,
-    bool success) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnMediaMetadataChanged(duration, width, height, success);
-}
-
-void WebMediaPlayerProxyAndroid::OnMediaPlaybackCompleted(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnPlaybackComplete();
-}
-
-void WebMediaPlayerProxyAndroid::OnMediaBufferingUpdate(int player_id,
-                                                        int percent) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnBufferingUpdate(percent);
-}
-
-void WebMediaPlayerProxyAndroid::OnSeekRequest(
-    int player_id,
-    const base::TimeDelta& time_to_seek) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnSeekRequest(time_to_seek);
-}
-
-void WebMediaPlayerProxyAndroid::OnSeekCompleted(
-    int player_id,
-    const base::TimeDelta& current_time) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnSeekComplete(current_time);
-}
-
-void WebMediaPlayerProxyAndroid::OnMediaError(int player_id, int error) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnMediaError(error);
-}
-
-void WebMediaPlayerProxyAndroid::OnVideoSizeChanged(int player_id,
-                                                    int width,
-                                                    int height) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnVideoSizeChanged(width, height);
-}
-
-void WebMediaPlayerProxyAndroid::OnTimeUpdate(int player_id,
-                                              base::TimeDelta current_time) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnTimeUpdate(current_time);
-}
-
-void WebMediaPlayerProxyAndroid::OnMediaPlayerReleased(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnPlayerReleased();
-}
-
-void WebMediaPlayerProxyAndroid::OnConnectedToRemoteDevice(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnConnectedToRemoteDevice();
-}
-
-void WebMediaPlayerProxyAndroid::OnDisconnectedFromRemoteDevice(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnDisconnectedFromRemoteDevice();
-}
-
-void WebMediaPlayerProxyAndroid::OnDidEnterFullscreen(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnDidEnterFullscreen();
-}
-
-void WebMediaPlayerProxyAndroid::OnDidExitFullscreen(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnDidExitFullscreen();
-}
-
-void WebMediaPlayerProxyAndroid::OnPlayerPlay(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnMediaPlayerPlay();
-}
-
-void WebMediaPlayerProxyAndroid::OnPlayerPause(int player_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
-  if (player)
-    player->OnMediaPlayerPause();
-}
-
-void WebMediaPlayerProxyAndroid::EnterFullscreen(int player_id) {
-  Send(new MediaPlayerHostMsg_EnterFullscreen(routing_id(), player_id));
-}
-
-void WebMediaPlayerProxyAndroid::ExitFullscreen(int player_id) {
-  Send(new MediaPlayerHostMsg_ExitFullscreen(routing_id(), player_id));
-}
-
-#if defined(GOOGLE_TV)
-void WebMediaPlayerProxyAndroid::RequestExternalSurface(
-    int player_id,
-    const gfx::RectF& geometry) {
-  Send(new MediaPlayerHostMsg_NotifyExternalSurface(
-      routing_id(), player_id, true, geometry));
-}
-
-void WebMediaPlayerProxyAndroid::DidCommitCompositorFrame() {
-  std::map<int, gfx::RectF> geometry_change;
-  manager_->RetrieveGeometryChanges(&geometry_change);
-  for (std::map<int, gfx::RectF>::iterator it = geometry_change.begin();
-       it != geometry_change.end();
-       ++it) {
-    Send(new MediaPlayerHostMsg_NotifyExternalSurface(
-        routing_id(), it->first, false, it->second));
-  }
-}
-#endif
-
-void WebMediaPlayerProxyAndroid::InitializeCDM(int media_keys_id,
-                                               const std::vector<uint8>& uuid,
-                                               const GURL& frame_url) {
-  Send(new MediaKeysHostMsg_InitializeCDM(
-      routing_id(), media_keys_id, uuid, frame_url));
-}
-
-void WebMediaPlayerProxyAndroid::GenerateKeyRequest(
-    int media_keys_id,
-    const std::string& type,
-    const std::vector<uint8>& init_data) {
-  Send(new MediaKeysHostMsg_GenerateKeyRequest(
-      routing_id(), media_keys_id, type, init_data));
-}
-
-void WebMediaPlayerProxyAndroid::AddKey(int media_keys_id,
-                                        const std::vector<uint8>& key,
-                                        const std::vector<uint8>& init_data,
-                                        const std::string& session_id) {
-  Send(new MediaKeysHostMsg_AddKey(
-      routing_id(), media_keys_id, key, init_data, session_id));
-}
-
-void WebMediaPlayerProxyAndroid::CancelKeyRequest(
-    int media_keys_id,
-    const std::string& session_id) {
-  Send(new MediaKeysHostMsg_CancelKeyRequest(
-      routing_id(), media_keys_id, session_id));
-}
-
-WebMediaPlayerAndroid* WebMediaPlayerProxyAndroid::GetWebMediaPlayer(
-    int player_id) {
-  return static_cast<WebMediaPlayerAndroid*>(
-      manager_->GetMediaPlayer(player_id));
-}
-
-void WebMediaPlayerProxyAndroid::OnKeyAdded(int media_keys_id,
-                                            const std::string& session_id) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(media_keys_id);
-  if (player)
-    player->OnKeyAdded(session_id);
-}
-
-void WebMediaPlayerProxyAndroid::OnKeyError(
-    int media_keys_id,
-    const std::string& session_id,
-    media::MediaKeys::KeyError error_code,
-    int system_code) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(media_keys_id);
-  if (player)
-    player->OnKeyError(session_id, error_code, system_code);
-}
-
-void WebMediaPlayerProxyAndroid::OnKeyMessage(
-    int media_keys_id,
-    const std::string& session_id,
-    const std::vector<uint8>& message,
-    const std::string& destination_url) {
-  WebMediaPlayerAndroid* player = GetWebMediaPlayer(media_keys_id);
-  if (player)
-    player->OnKeyMessage(session_id, message, destination_url);
-}
-
-}  // namespace content
diff --git a/content/renderer/media/android/webmediaplayer_proxy_android.h b/content/renderer/media/android/webmediaplayer_proxy_android.h
deleted file mode 100644
index 168bd16..0000000
--- a/content/renderer/media/android/webmediaplayer_proxy_android.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
-#define CONTENT_RENDERER_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/time/time.h"
-#include "content/common/media/media_player_messages_enums_android.h"
-#include "content/public/renderer/render_view_observer.h"
-#include "media/base/android/media_player_android.h"
-#include "media/base/media_keys.h"
-#include "url/gurl.h"
-
-#if defined(GOOGLE_TV)
-#include "ui/gfx/rect_f.h"
-#endif
-
-namespace content {
-
-class RendererMediaPlayerManager;
-class WebMediaPlayerAndroid;
-
-// This class manages IPC communication between WebMediaPlayerAndroid and the
-// MediaPlayerManagerAndroid in the browser process.
-class WebMediaPlayerProxyAndroid : public RenderViewObserver {
- public:
-  // Construct a WebMediaPlayerProxyAndroid object for the |render_view|.
-  // |manager| is passed to this class so that it can find the right
-  // WebMediaPlayerAndroid using player IDs.
-  WebMediaPlayerProxyAndroid(
-      RenderView* render_view,
-      RendererMediaPlayerManager* manager);
-  virtual ~WebMediaPlayerProxyAndroid();
-
-  // RenderViewObserver overrides.
-  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
-
-  // Initializes a MediaPlayerAndroid object in browser process.
-  void Initialize(MediaPlayerHostMsg_Initialize_Type type,
-                  int player_id,
-                  const GURL& url,
-                  const GURL& first_party_for_cookies,
-                  int demuxer_client_id);
-
-  // Starts the player.
-  void Start(int player_id);
-
-  // Pauses the player.
-  // is_media_related_action should be true if this pause is coming from an
-  // an action that explicitly pauses the video (user pressing pause, JS, etc.)
-  // Otherwise it should be false if Pause is being called due to other reasons
-  // (cleanup, freeing resources, etc.)
-  void Pause(int player_id, bool is_media_related_action);
-
-  // Performs seek on the player.
-  void Seek(int player_id, const base::TimeDelta& time);
-
-  // Set the player volume.
-  void SetVolume(int player_id, double volume);
-
-  // Release resources for the player.
-  void ReleaseResources(int player_id);
-
-  // Destroy the player in the browser process
-  void DestroyPlayer(int player_id);
-
-  // Request the player to enter fullscreen.
-  void EnterFullscreen(int player_id);
-
-  // Request the player to exit fullscreen.
-  void ExitFullscreen(int player_id);
-
-#if defined(GOOGLE_TV)
-  // Request an external surface for out-of-band compositing.
-  void RequestExternalSurface(int player_id, const gfx::RectF& geometry);
-
-  // RenderViewObserver overrides.
-  virtual void DidCommitCompositorFrame() OVERRIDE;
-#endif
-
-  // Encrypted media related methods.
-  void InitializeCDM(int media_keys_id,
-                     const std::vector<uint8>& uuid,
-                     const GURL& frame_url);
-  void GenerateKeyRequest(int media_keys_id,
-                          const std::string& type,
-                          const std::vector<uint8>& init_data);
-  void AddKey(int media_keys_id,
-              const std::vector<uint8>& key,
-              const std::vector<uint8>& init_data,
-              const std::string& session_id);
-  void CancelKeyRequest(int media_keys_id, const std::string& session_id);
-
- private:
-  WebMediaPlayerAndroid* GetWebMediaPlayer(int player_id);
-
-  // Message handlers.
-  void OnMediaMetadataChanged(int player_id,
-                              base::TimeDelta duration,
-                              int width,
-                              int height,
-                              bool success);
-  void OnMediaPlaybackCompleted(int player_id);
-  void OnMediaBufferingUpdate(int player_id, int percent);
-  void OnSeekRequest(int player_id, const base::TimeDelta& time_to_seek);
-  void OnSeekCompleted(int player_id, const base::TimeDelta& current_time);
-  void OnMediaError(int player_id, int error);
-  void OnVideoSizeChanged(int player_id, int width, int height);
-  void OnTimeUpdate(int player_id, base::TimeDelta current_time);
-  void OnMediaPlayerReleased(int player_id);
-  void OnConnectedToRemoteDevice(int player_id);
-  void OnDisconnectedFromRemoteDevice(int player_id);
-  void OnDidExitFullscreen(int player_id);
-  void OnDidEnterFullscreen(int player_id);
-  void OnPlayerPlay(int player_id);
-  void OnPlayerPause(int player_id);
-  void OnKeyAdded(int media_keys_id, const std::string& session_id);
-  void OnKeyError(int media_keys_id,
-                  const std::string& session_id,
-                  media::MediaKeys::KeyError error_code,
-                  int system_code);
-  void OnKeyMessage(int media_keys_id,
-                    const std::string& session_id,
-                    const std::vector<uint8>& message,
-                    const std::string& destination_url);
-
-  RendererMediaPlayerManager* manager_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerProxyAndroid);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.cc b/content/renderer/media/crypto/content_decryption_module_factory.cc
index e53fa17..34f0525 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.cc
+++ b/content/renderer/media/crypto/content_decryption_module_factory.cc
@@ -17,7 +17,7 @@
 #include "third_party/WebKit/public/web/WebMediaPlayerClient.h"
 #elif defined(OS_ANDROID)
 #include "content/renderer/media/android/proxy_media_keys.h"
-#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
+#include "content/renderer/media/android/renderer_media_player_manager.h"
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
 namespace content {
@@ -94,7 +94,7 @@
     WebKit::WebFrame* web_frame,
     const base::Closure& destroy_plugin_cb,
 #elif defined(OS_ANDROID)
-    WebMediaPlayerProxyAndroid* proxy,
+    RendererMediaPlayerManager* manager,
     int media_keys_id,
     const GURL& frame_url,
 #endif  // defined(ENABLE_PEPPER_CDMS)
@@ -116,8 +116,8 @@
       key_system, key_added_cb, key_error_cb, key_message_cb,
       destroy_plugin_cb, web_media_player_client, web_frame);
 #elif defined(OS_ANDROID)
-  scoped_ptr<ProxyMediaKeys> proxy_media_keys(
-      new ProxyMediaKeys(proxy, media_keys_id));
+  scoped_ptr<ProxyMediaKeys> proxy_media_keys(new ProxyMediaKeys(
+      manager, media_keys_id, key_added_cb, key_error_cb, key_message_cb));
   proxy_media_keys->InitializeCDM(key_system, frame_url);
   return proxy_media_keys.PassAs<media::MediaKeys>();
 #else
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.h b/content/renderer/media/crypto/content_decryption_module_factory.h
index 01ab731..3d32832 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.h
+++ b/content/renderer/media/crypto/content_decryption_module_factory.h
@@ -21,7 +21,7 @@
 
 namespace content {
 
-class WebMediaPlayerProxyAndroid;
+class RendererMediaPlayerManager;
 
 class ContentDecryptionModuleFactory {
  public:
@@ -33,7 +33,7 @@
       WebKit::WebFrame* web_frame,
       const base::Closure& destroy_plugin_cb,
 #elif defined(OS_ANDROID)
-      WebMediaPlayerProxyAndroid* proxy,
+      RendererMediaPlayerManager* manager,
       int media_keys_id,
       const GURL& frame_url,
 #endif  // defined(ENABLE_PEPPER_CDMS)
diff --git a/content/renderer/media/crypto/key_systems.cc b/content/renderer/media/crypto/key_systems.cc
index 3cd9385..4201533 100644
--- a/content/renderer/media/crypto/key_systems.cc
+++ b/content/renderer/media/crypto/key_systems.cc
@@ -263,11 +263,6 @@
   else
     concrete_key_system = key_system;
 
-  // This method is only used by the canPlaytType() path (not the EME methods),
-  // so we check for suppressed key_systems here.
-  if(IsCanPlayTypeSuppressed(concrete_key_system))
-    return false;
-
   if (codecs.empty()) {
     return IsSupportedKeySystemWithContainerAndCodec(
         mime_type, std::string(), concrete_key_system);
diff --git a/content/renderer/media/crypto/key_systems_info.cc b/content/renderer/media/crypto/key_systems_info.cc
index 22bc718..2b1828c 100644
--- a/content/renderer/media/crypto/key_systems_info.cc
+++ b/content/renderer/media/crypto/key_systems_info.cc
@@ -10,26 +10,10 @@
 
 // The following must be after widevine_cdm_version.h.
 
-#if defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)
-#include "base/command_line.h"
-#include "media/base/media_switches.h"
-#endif
-
 namespace content {
 
 static const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
 
-bool IsCanPlayTypeSuppressed(const std::string& key_system) {
-#if defined(DISABLE_WIDEVINE_CDM_CANPLAYTYPE)
-  // See http://crbug.com/237627.
-  if (key_system == kWidevineKeySystem &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kOverrideEncryptedMediaCanPlayType))
-    return true;
-#endif
-  return false;
-}
-
 std::string KeySystemNameForUMAInternal(const WebKit::WebString& key_system) {
   if (key_system == kClearKeyKeySystem)
     return "ClearKey";
diff --git a/content/renderer/media/crypto/key_systems_info.h b/content/renderer/media/crypto/key_systems_info.h
index e2fe128..086c318 100644
--- a/content/renderer/media/crypto/key_systems_info.h
+++ b/content/renderer/media/crypto/key_systems_info.h
@@ -13,9 +13,6 @@
 
 namespace content {
 
-// Returns true if canPlayType should return an empty string for |key_system|.
-bool IsCanPlayTypeSuppressed(const std::string& key_system);
-
 // Returns the name that UMA will use for the given |key_system|.
 // This function can be called frequently. Hence this function should be
 // implemented not to impact performance and does not rely on the main
diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc
index 47c4fdd..d0b7084 100644
--- a/content/renderer/media/crypto/proxy_decryptor.cc
+++ b/content/renderer/media/crypto/proxy_decryptor.cc
@@ -8,6 +8,9 @@
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "content/renderer/media/crypto/content_decryption_module_factory.h"
+#if defined(OS_ANDROID)
+#include "content/renderer/media/android/renderer_media_player_manager.h"
+#endif  // defined(OS_ANDROID)
 
 namespace content {
 
@@ -23,7 +26,7 @@
     WebKit::WebMediaPlayerClient* web_media_player_client,
     WebKit::WebFrame* web_frame,
 #elif defined(OS_ANDROID)
-    WebMediaPlayerProxyAndroid* proxy,
+    RendererMediaPlayerManager* manager,
     int media_keys_id,
 #endif  // defined(ENABLE_PEPPER_CDMS)
     const media::KeyAddedCB& key_added_cb,
@@ -34,7 +37,7 @@
       web_media_player_client_(web_media_player_client),
       web_frame_(web_frame),
 #elif defined(OS_ANDROID)
-      proxy_(proxy),
+      manager_(manager),
       media_keys_id_(media_keys_id),
 #endif  // defined(ENABLE_PEPPER_CDMS)
       key_added_cb_(key_added_cb),
@@ -131,7 +134,7 @@
       base::Bind(&ProxyDecryptor::DestroyHelperPlugin,
                  weak_ptr_factory_.GetWeakPtr()),
 #elif defined(OS_ANDROID)
-      proxy_,
+      manager_,
       media_keys_id_,
       frame_url,
 #endif  // defined(ENABLE_PEPPER_CDMS)
diff --git a/content/renderer/media/crypto/proxy_decryptor.h b/content/renderer/media/crypto/proxy_decryptor.h
index 0202721..336819f 100644
--- a/content/renderer/media/crypto/proxy_decryptor.h
+++ b/content/renderer/media/crypto/proxy_decryptor.h
@@ -26,7 +26,9 @@
 
 namespace content {
 
-class WebMediaPlayerProxyAndroid;
+#if defined(OS_ANDROID)
+class RendererMediaPlayerManager;
+#endif  // defined(OS_ANDROID)
 
 // ProxyDecryptor is for EME v0.1b only. It should not be used for the WD API.
 // A decryptor proxy that creates a real decryptor object on demand and
@@ -41,7 +43,7 @@
       WebKit::WebMediaPlayerClient* web_media_player_client,
       WebKit::WebFrame* web_frame,
 #elif defined(OS_ANDROID)
-      WebMediaPlayerProxyAndroid* proxy,
+      RendererMediaPlayerManager* manager,
       int media_keys_id,
 #endif  // defined(ENABLE_PEPPER_CDMS)
       const media::KeyAddedCB& key_added_cb,
@@ -92,7 +94,7 @@
   WebKit::WebMediaPlayerClient* web_media_player_client_;
   WebKit::WebFrame* web_frame_;
 #elif defined(OS_ANDROID)
-  WebMediaPlayerProxyAndroid* proxy_;
+  RendererMediaPlayerManager* manager_;
   int media_keys_id_;
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
diff --git a/content/renderer/media/media_stream_center.cc b/content/renderer/media/media_stream_center.cc
index 31119ae..c3ae47a 100644
--- a/content/renderer/media/media_stream_center.cc
+++ b/content/renderer/media/media_stream_center.cc
@@ -33,30 +33,6 @@
 
 namespace content {
 
-static webrtc::MediaStreamInterface* GetNativeMediaStream(
-    const WebKit::WebMediaStream& stream) {
-  MediaStreamExtraData* extra_data =
-      static_cast<MediaStreamExtraData*>(stream.extraData());
-  return extra_data->stream().get();
-}
-
-static webrtc::MediaStreamTrackInterface* GetNativeMediaStreamTrack(
-      const WebKit::WebMediaStream& stream,
-      const WebKit::WebMediaStreamTrack& component) {
-  std::string track_id = UTF16ToUTF8(component.id());
-  webrtc::MediaStreamInterface* native_stream = GetNativeMediaStream(stream);
-  if (native_stream) {
-    if (component.source().type() == WebKit::WebMediaStreamSource::TypeAudio) {
-      return native_stream->FindAudioTrack(track_id);
-    }
-    if (component.source().type() == WebKit::WebMediaStreamSource::TypeVideo) {
-      return native_stream->FindVideoTrack(track_id);
-    }
-  }
-  NOTREACHED();
-  return NULL;
-}
-
 MediaStreamCenter::MediaStreamCenter(WebKit::WebMediaStreamCenterClient* client,
                                      MediaStreamDependencyFactory* factory)
     : rtc_factory_(factory), next_request_id_(0) {}
@@ -80,7 +56,7 @@
     const WebKit::WebMediaStream& stream,
     const WebKit::WebMediaStreamTrack& component) {
   webrtc::MediaStreamTrackInterface* track =
-      GetNativeMediaStreamTrack(stream, component);
+      MediaStreamDependencyFactory::GetNativeMediaStreamTrack(component);
   if (track)
     track->set_enabled(true);
 }
@@ -89,7 +65,7 @@
     const WebKit::WebMediaStream& stream,
     const WebKit::WebMediaStreamTrack& component) {
   webrtc::MediaStreamTrackInterface* track =
-      GetNativeMediaStreamTrack(stream, component);
+      MediaStreamDependencyFactory::GetNativeMediaStreamTrack(component);
   if (track)
     track->set_enabled(false);
 }
diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc
index 9e8b69b..f74f220 100644
--- a/content/renderer/media/media_stream_dependency_factory.cc
+++ b/content/renderer/media/media_stream_dependency_factory.cc
@@ -11,6 +11,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/media/media_stream_source_extra_data.h"
+#include "content/renderer/media/media_stream_track_extra_data.h"
 #include "content/renderer/media/peer_connection_identity_service.h"
 #include "content/renderer/media/rtc_media_constraints.h"
 #include "content/renderer/media/rtc_peer_connection_handler.h"
@@ -441,6 +442,8 @@
                               webaudio_source.get(),
                               source_data->local_audio_source(),
                               &track_constraints));
+    AddNativeTrackToBlinkTrack(audio_track.get(), track);
+
     audio_track->set_enabled(track.isEnabled());
     if (capturer.get()) {
       WebKit::WebMediaStreamTrack writable_track = track;
@@ -451,6 +454,7 @@
     DCHECK(source.type() == WebKit::WebMediaStreamSource::TypeVideo);
     scoped_refptr<webrtc::VideoTrackInterface> video_track(
         CreateLocalVideoTrack(track_id, source_data->video_source()));
+    AddNativeTrackToBlinkTrack(video_track.get(), track);
     video_track->set_enabled(track.isEnabled());
     return native_stream->AddTrack(video_track.get());
   }
@@ -483,7 +487,9 @@
   WebKit::WebMediaStreamSource::Type type =
       WebKit::WebMediaStreamSource::TypeVideo;
   webkit_source.initialize(webkit_track_id, type, webkit_track_id);
+
   webkit_track.initialize(webkit_track_id, webkit_source);
+  AddNativeTrackToBlinkTrack(native_track.get(), webkit_track);
 
   // Add the track to WebMediaStream.
   stream->addTrack(webkit_track);
@@ -502,10 +508,12 @@
   DCHECK(type == WebKit::WebMediaStreamSource::TypeAudio ||
          type == WebKit::WebMediaStreamSource::TypeVideo);
 
+  WebKit::WebMediaStreamTrack writable_track = track;
+  writable_track.setExtraData(NULL);
+
   std::string track_id = UTF16ToUTF8(track.id());
   if (type == WebKit::WebMediaStreamSource::TypeAudio) {
     // Remove the source provider as the track is going away.
-    WebKit::WebMediaStreamTrack writable_track = track;
     writable_track.setSourceProvider(NULL);
     return native_stream->RemoveTrack(native_stream->FindAudioTrack(track_id));
   }
@@ -845,4 +853,32 @@
   return capturer;
 }
 
+void MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack(
+    webrtc::MediaStreamTrackInterface* native_track,
+    const WebKit::WebMediaStreamTrack& webkit_track) {
+  DCHECK(!webkit_track.isNull() && !webkit_track.extraData());
+  WebKit::WebMediaStreamTrack track = webkit_track;
+  track.setExtraData(new MediaStreamTrackExtraData(native_track));
+}
+
+webrtc::MediaStreamInterface*
+MediaStreamDependencyFactory::GetNativeMediaStream(
+    const WebKit::WebMediaStream& stream) {
+  if (stream.isNull())
+    return NULL;
+  MediaStreamExtraData* extra_data =
+      static_cast<MediaStreamExtraData*>(stream.extraData());
+  return extra_data ? extra_data->stream().get() : NULL;
+}
+
+webrtc::MediaStreamTrackInterface*
+MediaStreamDependencyFactory::GetNativeMediaStreamTrack(
+      const WebKit::WebMediaStreamTrack& track) {
+  if (track.isNull())
+    return NULL;
+  MediaStreamTrackExtraData* extra_data =
+      static_cast<MediaStreamTrackExtraData*>(track.extraData());
+  return extra_data ? extra_data->track().get() : NULL;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/media_stream_dependency_factory.h b/content/renderer/media/media_stream_dependency_factory.h
index 5dad7c5..f8420d3 100644
--- a/content/renderer/media/media_stream_dependency_factory.h
+++ b/content/renderer/media/media_stream_dependency_factory.h
@@ -142,6 +142,16 @@
   RTCVideoDecoderFactoryTv* decoder_factory_tv() { return decoder_factory_tv_; }
 #endif
 
+  static void AddNativeTrackToBlinkTrack(
+      webrtc::MediaStreamTrackInterface* native_track,
+      const WebKit::WebMediaStreamTrack& webkit_track);
+
+  static webrtc::MediaStreamInterface* GetNativeMediaStream(
+      const WebKit::WebMediaStream& stream);
+
+  static webrtc::MediaStreamTrackInterface* GetNativeMediaStreamTrack(
+      const WebKit::WebMediaStreamTrack& track);
+
  protected:
   // Asks the PeerConnection factory to create a Local MediaStream object.
   virtual scoped_refptr<webrtc::MediaStreamInterface>
diff --git a/content/renderer/media/media_stream_track_extra_data.cc b/content/renderer/media/media_stream_track_extra_data.cc
new file mode 100644
index 0000000..07ac863
--- /dev/null
+++ b/content/renderer/media/media_stream_track_extra_data.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/media_stream_track_extra_data.h"
+
+#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
+
+namespace content {
+
+MediaStreamTrackExtraData::MediaStreamTrackExtraData(
+    webrtc::MediaStreamTrackInterface* track)
+    : track_(track) {
+}
+
+MediaStreamTrackExtraData::~MediaStreamTrackExtraData() {
+}
+
+}  // namespace content
diff --git a/content/renderer/media/media_stream_track_extra_data.h b/content/renderer/media/media_stream_track_extra_data.h
new file mode 100644
index 0000000..4ab9cff
--- /dev/null
+++ b/content/renderer/media/media_stream_track_extra_data.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_TRACK_EXTRA_DATA_H_
+#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_TRACK_EXTRA_DATA_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+
+namespace webrtc {
+class MediaStreamTrackInterface;
+}  // namespace webrtc
+
+namespace content {
+
+class CONTENT_EXPORT MediaStreamTrackExtraData
+    : NON_EXPORTED_BASE(public WebKit::WebMediaStreamTrack::ExtraData) {
+ public:
+  MediaStreamTrackExtraData(webrtc::MediaStreamTrackInterface* track);
+  virtual ~MediaStreamTrackExtraData();
+
+  const scoped_refptr<webrtc::MediaStreamTrackInterface>& track() const {
+    return track_;
+  }
+
+ private:
+  scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaStreamTrackExtraData);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_TRACK_EXTRA_DATA_H_
diff --git a/content/renderer/media/midi_dispatcher.cc b/content/renderer/media/midi_dispatcher.cc
index edd57c2..b9aae33 100644
--- a/content/renderer/media/midi_dispatcher.cc
+++ b/content/renderer/media/midi_dispatcher.cc
@@ -34,11 +34,11 @@
 
 void MIDIDispatcher::requestSysExPermission(
       const WebMIDIPermissionRequest& request) {
-  int client_id = requests_.Add(new WebMIDIPermissionRequest(request));
+  int bridge_id = requests_.Add(new WebMIDIPermissionRequest(request));
   WebSecurityOrigin security_origin = request.securityOrigin();
   std::string origin = security_origin.toString().utf8();
   GURL url(origin);
-  Send(new MIDIHostMsg_RequestSysExPermission(routing_id(), client_id, url));
+  Send(new MIDIHostMsg_RequestSysExPermission(routing_id(), bridge_id, url));
 }
 
 void MIDIDispatcher::cancelSysExPermissionRequest(
@@ -47,19 +47,23 @@
        !it.IsAtEnd();
        it.Advance()) {
     WebMIDIPermissionRequest* value = it.GetCurrentValue();
-    if (!value->equals(request))
-      continue;
-    requests_.Remove(it.GetCurrentKey());
+    if (value->equals(request)) {
+      string16 origin = request.securityOrigin().toString();
+      Send(new MIDIHostMsg_CancelSysExPermissionRequest(
+          routing_id(), it.GetCurrentKey(), GURL(origin)));
+      requests_.Remove(it.GetCurrentKey());
+      break;
+    }
   }
 }
 
-void MIDIDispatcher::OnSysExPermissionApproved(int client_id, bool is_allowed) {
+void MIDIDispatcher::OnSysExPermissionApproved(int bridge_id, bool is_allowed) {
   // |request| can be NULL when the request is canceled.
-  WebMIDIPermissionRequest* request = requests_.Lookup(client_id);
+  WebMIDIPermissionRequest* request = requests_.Lookup(bridge_id);
   if (!request)
     return;
   request->setIsAllowed(is_allowed);
-  requests_.Remove(client_id);
+  requests_.Remove(bridge_id);
 }
 
 }  // namespace content
diff --git a/content/renderer/media/peer_connection_handler_base.cc b/content/renderer/media/peer_connection_handler_base.cc
index 792e61b..b65a3aa 100644
--- a/content/renderer/media/peer_connection_handler_base.cc
+++ b/content/renderer/media/peer_connection_handler_base.cc
@@ -15,16 +15,6 @@
 
 namespace content {
 
-// TODO(hta): Unify implementations of these functions from MediaStreamCenter
-static webrtc::MediaStreamInterface* GetNativeMediaStream(
-    const WebKit::WebMediaStream& stream) {
-  MediaStreamExtraData* extra_data =
-      static_cast<MediaStreamExtraData*>(stream.extraData());
-  if (extra_data)
-    return extra_data->stream().get();
-  return NULL;
-}
-
 PeerConnectionHandlerBase::PeerConnectionHandlerBase(
     MediaStreamDependencyFactory* dependency_factory)
     : dependency_factory_(dependency_factory),
@@ -37,7 +27,8 @@
 bool PeerConnectionHandlerBase::AddStream(
     const WebKit::WebMediaStream& stream,
     const webrtc::MediaConstraintsInterface* constraints) {
-  webrtc::MediaStreamInterface* native_stream = GetNativeMediaStream(stream);
+  webrtc::MediaStreamInterface* native_stream =
+      MediaStreamDependencyFactory::GetNativeMediaStream(stream);
   if (!native_stream)
     return false;
   return native_peer_connection_->AddStream(native_stream, constraints);
@@ -45,29 +36,11 @@
 
 void PeerConnectionHandlerBase::RemoveStream(
     const WebKit::WebMediaStream& stream) {
-  webrtc::MediaStreamInterface* native_stream = GetNativeMediaStream(stream);
+  webrtc::MediaStreamInterface* native_stream =
+      MediaStreamDependencyFactory::GetNativeMediaStream(stream);
   if (native_stream)
     native_peer_connection_->RemoveStream(native_stream);
   DCHECK(native_stream);
 }
 
-webrtc::MediaStreamTrackInterface*
-PeerConnectionHandlerBase::GetNativeMediaStreamTrack(
-    const WebKit::WebMediaStream& stream,
-    const WebKit::WebMediaStreamTrack& track) {
-  std::string track_id = UTF16ToUTF8(track.id());
-  webrtc::MediaStreamInterface* native_stream = GetNativeMediaStream(stream);
-  if (!native_stream) {
-    return NULL;
-  }
-  if (track.source().type() == WebKit::WebMediaStreamSource::TypeAudio) {
-    return native_stream->FindAudioTrack(track_id);
-  }
-  if (track.source().type() == WebKit::WebMediaStreamSource::TypeVideo) {
-    return native_stream->FindVideoTrack(track_id);
-  }
-  NOTIMPLEMENTED();  // We have an unknown type of media stream track.
-  return NULL;
-}
-
 }  // namespace content
diff --git a/content/renderer/media/peer_connection_handler_base.h b/content/renderer/media/peer_connection_handler_base.h
index 54f1673..7c62b22 100644
--- a/content/renderer/media/peer_connection_handler_base.h
+++ b/content/renderer/media/peer_connection_handler_base.h
@@ -36,9 +36,6 @@
   bool AddStream(const WebKit::WebMediaStream& stream,
                  const webrtc::MediaConstraintsInterface* constraints);
   void RemoveStream(const WebKit::WebMediaStream& stream);
-  webrtc::MediaStreamTrackInterface* GetNativeMediaStreamTrack(
-      const WebKit::WebMediaStream& stream,
-      const WebKit::WebMediaStreamTrack& component);
 
   // dependency_factory_ is a raw pointer, and is valid for the lifetime of
   // MediaStreamImpl.
diff --git a/content/renderer/media/remote_media_stream_impl.cc b/content/renderer/media/remote_media_stream_impl.cc
index 7e481a6..e55d84f 100644
--- a/content/renderer/media/remote_media_stream_impl.cc
+++ b/content/renderer/media/remote_media_stream_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/renderer/media/media_stream_dependency_factory.h"
 #include "content/renderer/media/media_stream_extra_data.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 
@@ -52,6 +53,8 @@
 
   webkit_source.initialize(webkit_track_id, type, webkit_track_id);
   webkit_track->initialize(webkit_track_id, webkit_source);
+  content::MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack(track,
+      *webkit_track);
 }
 
 content::RemoteMediaStreamTrackObserver* FindTrackObserver(
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index 86d40cd..7d4db85 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -200,6 +200,10 @@
 
   gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
   gles2->WaitSyncPointCHROMIUM(sync_point);
+
+  // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
+  // flush the command buffers to ensure that.
+  gles2->ShallowFlushCHROMIUM();
 }
 
 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id,
@@ -257,11 +261,20 @@
   gles2->FramebufferTexture2D(
       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
   gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
+#if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
+    SK_A32_SHIFT == 24
+  GLenum skia_format = GL_BGRA_EXT;
+#elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
+    SK_A32_SHIFT == 24
+  GLenum skia_format = GL_RGBA;
+#else
+#error Unexpected Skia ARGB_8888 layout!
+#endif
   gles2->ReadPixels(0,
                     0,
                     size.width(),
                     size.height(),
-                    GL_BGRA_EXT,
+                    skia_format,
                     GL_UNSIGNED_BYTE,
                     read_pixels_bitmap_.pixelRef()->pixels());
   gles2->DeleteFramebuffers(1, &fb);
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 127a7e2..416a128 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -281,10 +281,6 @@
   return impl_.hasSelector();
 }
 
-WebKit::WebMediaStream LocalRTCStatsRequest::stream() const {
-  return impl_.stream();
-}
-
 WebKit::WebMediaStreamTrack LocalRTCStatsRequest::component() const {
   return impl_.component();
 }
@@ -564,8 +560,8 @@
       new talk_base::RefCountedObject<StatsResponse>(request));
   webrtc::MediaStreamTrackInterface* track = NULL;
   if (request->hasSelector()) {
-      track = GetNativeMediaStreamTrack(request->stream(),
-                                        request->component());
+      track = MediaStreamDependencyFactory::GetNativeMediaStreamTrack(
+          request->component());
     if (!track) {
       DVLOG(1) << "GetStats: Track not found.";
       // TODO(hta): Consider how to get an error back.
@@ -628,7 +624,7 @@
 
   webrtc::AudioTrackInterface* audio_track =
       static_cast<webrtc::AudioTrackInterface*>(
-          GetNativeMediaStreamTrack(track.stream(), track));
+          MediaStreamDependencyFactory::GetNativeMediaStreamTrack(track));
 
   talk_base::scoped_refptr<webrtc::DtmfSenderInterface> sender(
       native_peer_connection_->CreateDtmfSender(audio_track));
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index bb65010..c1f70cb 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -54,7 +54,6 @@
   LocalRTCStatsRequest();
 
   virtual bool hasSelector() const;
-  virtual WebKit::WebMediaStream stream() const;
   virtual WebKit::WebMediaStreamTrack component() const;
   virtual void requestSucceeded(const LocalRTCStatsResponse* response);
   virtual scoped_refptr<LocalRTCStatsResponse> createResponse();
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 9528cbe..ff4e7e5 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -76,15 +76,11 @@
  public:
   MockRTCStatsRequest()
       : has_selector_(false),
-        stream_(),
         request_succeeded_called_(false) {}
 
   virtual bool hasSelector() const OVERRIDE {
     return has_selector_;
   }
-  virtual WebKit::WebMediaStream stream() const OVERRIDE {
-    return stream_;
-  }
   virtual WebKit::WebMediaStreamTrack component() const OVERRIDE {
     return component_;
   }
@@ -101,10 +97,8 @@
   }
 
   // Function for setting whether or not a selector is available.
-  void setSelector(const WebKit::WebMediaStream& stream,
-                   const WebKit::WebMediaStreamTrack& component) {
+  void setSelector(const WebKit::WebMediaStreamTrack& component) {
     has_selector_ = true;
-    stream_ = stream;
     component_ = component;
   }
 
@@ -119,7 +113,6 @@
 
  private:
   bool has_selector_;
-  WebKit::WebMediaStream stream_;
   WebKit::WebMediaStreamTrack component_;
   scoped_refptr<MockRTCStatsResponse> response_;
   bool request_succeeded_called_;
@@ -255,6 +248,8 @@
         mock_dependency_factory_->CreateLocalAudioTrack(
             audio_track_id, capturer, NULL, NULL,
             &audio_constraints));
+    MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack(
+        audio_track.get(), audio_tracks[0]);
     native_stream->AddTrack(audio_track.get());
 
     local_stream.videoTracks(video_tracks);
@@ -263,6 +258,8 @@
     scoped_refptr<webrtc::VideoTrackInterface> video_track(
         mock_dependency_factory_->CreateLocalVideoTrack(
             video_track_id, source));
+    MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack(
+        video_track.get(), video_tracks[0]);
     native_stream->AddTrack(video_track.get());
 
     local_stream.setExtraData(
@@ -466,7 +463,7 @@
 
   scoped_refptr<MockRTCStatsRequest> request(
       new talk_base::RefCountedObject<MockRTCStatsRequest>());
-  request->setSelector(local_stream, tracks[0]);
+  request->setSelector(tracks[0]);
   pc_handler_->getStats(request.get());
   EXPECT_EQ(1, request->result()->report_count());
 }
@@ -483,7 +480,7 @@
 
   scoped_refptr<MockRTCStatsRequest> request(
       new talk_base::RefCountedObject<MockRTCStatsRequest>());
-  request->setSelector(remote_stream, tracks[0]);
+  request->setSelector(tracks[0]);
   pc_handler_->getStats(request.get());
   EXPECT_EQ(1, request->result()->report_count());
 }
@@ -502,7 +499,7 @@
 
   scoped_refptr<MockRTCStatsRequest> request(
       new talk_base::RefCountedObject<MockRTCStatsRequest>());
-  request->setSelector(local_stream, component);
+  request->setSelector(component);
   pc_handler_->getStats(request.get());
   EXPECT_EQ(0, request->result()->report_count());
 }
diff --git a/content/renderer/media/rtc_video_capture_delegate.cc b/content/renderer/media/rtc_video_capture_delegate.cc
index 8b038d5..9567e2c 100644
--- a/content/renderer/media/rtc_video_capture_delegate.cc
+++ b/content/renderer/media/rtc_video_capture_delegate.cc
@@ -26,7 +26,7 @@
 }
 
 void RtcVideoCaptureDelegate::StartCapture(
-    const media::VideoCaptureCapability& capability,
+    const media::VideoCaptureParams& params,
     const FrameCapturedCallback& captured_callback,
     const StateChangeCallback& state_callback) {
   DVLOG(3) << " RtcVideoCaptureDelegate::StartCapture ";
@@ -39,7 +39,7 @@
   // Increase the reference count to ensure we are not deleted until
   // The we are unregistered in RtcVideoCaptureDelegate::OnRemoved.
   AddRef();
-  capture_engine_->StartCapture(this, capability);
+  capture_engine_->StartCapture(this, params);
 }
 
 void RtcVideoCaptureDelegate::StopCapture() {
@@ -92,16 +92,6 @@
                  frame));
 }
 
-void RtcVideoCaptureDelegate::OnDeviceInfoReceived(
-    media::VideoCapture* capture,
-    const media::VideoCaptureParams& device_info) {
-}
-
-void RtcVideoCaptureDelegate::OnDeviceInfoChanged(
-    media::VideoCapture* capture,
-    const media::VideoCaptureParams& device_info) {
-}
-
 void RtcVideoCaptureDelegate::OnFrameReadyOnCaptureThread(
     media::VideoCapture* capture,
     const scoped_refptr<media::VideoFrame>& frame) {
diff --git a/content/renderer/media/rtc_video_capture_delegate.h b/content/renderer/media/rtc_video_capture_delegate.h
index 415b346..f081c37 100644
--- a/content/renderer/media/rtc_video_capture_delegate.h
+++ b/content/renderer/media/rtc_video_capture_delegate.h
@@ -36,7 +36,7 @@
   RtcVideoCaptureDelegate(const media::VideoCaptureSessionId id,
                           VideoCaptureImplManager* vc_manager);
 
-  void StartCapture(const media::VideoCaptureCapability& capability,
+  void StartCapture(const media::VideoCaptureParams& params,
                     const FrameCapturedCallback& captured_callback,
                     const StateChangeCallback& state_callback);
   void StopCapture();
@@ -51,12 +51,6 @@
   virtual void OnFrameReady(
       media::VideoCapture* capture,
       const scoped_refptr<media::VideoFrame>& frame) OVERRIDE;
-  virtual void OnDeviceInfoReceived(
-      media::VideoCapture* capture,
-      const media::VideoCaptureParams& device_info) OVERRIDE;
-  virtual void OnDeviceInfoChanged(
-      media::VideoCapture* capture,
-      const media::VideoCaptureParams& device_info) OVERRIDE;
 
  private:
   friend class base::RefCountedThreadSafe<RtcVideoCaptureDelegate>;
diff --git a/content/renderer/media/rtc_video_capturer.cc b/content/renderer/media/rtc_video_capturer.cc
index fec4d09..2cf0d91 100644
--- a/content/renderer/media/rtc_video_capturer.cc
+++ b/content/renderer/media/rtc_video_capturer.cc
@@ -29,24 +29,25 @@
     return cricket::CS_FAILED;
   }
 
-  media::VideoCaptureCapability cap;
-  cap.width = capture_format.width;
-  cap.height = capture_format.height;
-  cap.frame_rate = capture_format.framerate();
-  cap.color = media::PIXEL_FORMAT_I420;
+  media::VideoCaptureParams request;
+  request.requested_format =
+      media::VideoCaptureFormat(capture_format.width,
+                                capture_format.height,
+                                capture_format.framerate(),
+                                media::ConstantResolutionVideoCaptureDevice);
 
   SetCaptureFormat(&capture_format);
 
   state_ = VIDEO_CAPTURE_STATE_STARTED;
   first_frame_timestamp_ = media::kNoTimestamp();
   delegate_->StartCapture(
-      cap,
+      request,
       base::Bind(&RtcVideoCapturer::OnFrameCaptured, base::Unretained(this)),
       base::Bind(&RtcVideoCapturer::OnStateChange, base::Unretained(this)));
   // Update the desired aspect ratio so that later the video frame can be
   // cropped to meet the requirement if the camera returns a different
-  // resolution than the |cap|.
-  UpdateAspectRatio(cap.width, cap.height);
+  // resolution than the |request|.
+  UpdateAspectRatio(capture_format.width, capture_format.height);
   return cricket::CS_STARTING;
 }
 
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index 5c470fd..f85439a 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -184,24 +184,44 @@
   DVLOG(3) << "Decode";
 
   base::AutoLock auto_lock(lock_);
+
   if (state_ == UNINITIALIZED || decode_complete_callback_ == NULL) {
     LOG(ERROR) << "The decoder has not initialized.";
     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   }
+
   if (state_ == DECODE_ERROR) {
     LOG(ERROR) << "Decoding error occurred.";
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
+
   if (missingFrames || !inputImage._completeFrame) {
     DLOG(ERROR) << "Missing or incomplete frames.";
     // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames.
     // Return an error to request a key frame.
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
+
+  // Most platforms' VDA implementations support mid-stream resolution change
+  // internally.  Platforms whose VDAs fail to support mid-stream resolution
+  // change gracefully need to have their clients cover for them, and we do that
+  // here.
+#ifdef ANDROID
+  const bool kVDACanHandleMidstreamResize = false;
+#else
+  const bool kVDACanHandleMidstreamResize = true;
+#endif
+
+  bool need_to_reset_for_midstream_resize = false;
   if (inputImage._frameType == webrtc::kKeyFrame) {
     DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x"
              << inputImage._encodedHeight;
+    gfx::Size prev_frame_size = frame_size_;
     frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight);
+    if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() &&
+        prev_frame_size != frame_size_) {
+      need_to_reset_for_midstream_resize = true;
+    }
   } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_,
                                      reset_bitstream_buffer_id_)) {
     // TODO(wuchengli): VDA should handle it. Remove this when
@@ -219,15 +239,20 @@
   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
   next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST;
 
-  // If the shared memory is available and there are no pending buffers, send
-  // the buffer for decode. If not, save the buffer in the queue for decode
-  // later.
+  // If a shared memory segment is available, there are no pending buffers, and
+  // this isn't a mid-stream resolution change, then send the buffer for decode
+  // immediately. Otherwise, save the buffer in the queue for later decode.
   scoped_ptr<SHMBuffer> shm_buffer;
-  if (pending_buffers_.size() == 0)
+  if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0)
     shm_buffer = GetSHM_Locked(inputImage._length);
   if (!shm_buffer) {
-    int32_t result = SaveToPendingBuffers_Locked(inputImage, buffer_data);
-    return result ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR;
+    if (!SaveToPendingBuffers_Locked(inputImage, buffer_data))
+      return WEBRTC_VIDEO_CODEC_ERROR;
+    if (need_to_reset_for_midstream_resize) {
+      base::AutoUnlock auto_unlock(lock_);
+      Reset();
+    }
+    return WEBRTC_VIDEO_CODEC_OK;
   }
 
   SaveToDecodeBuffers_Locked(inputImage, shm_buffer.Pass(), buffer_data);
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 0fe2789..8cc06fd 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -17,20 +17,11 @@
     : public base::RefCountedThreadSafe<ClientBuffer> {
  public:
   ClientBuffer(scoped_ptr<base::SharedMemory> buffer,
-               size_t buffer_size,
-               int frame_width,
-               int frame_height,
-               int frame_stride)
+               size_t buffer_size)
       : buffer(buffer.Pass()),
-        buffer_size(buffer_size),
-        frame_width(frame_width),
-        frame_height(frame_height),
-        frame_stride(frame_stride) {}
+        buffer_size(buffer_size) {}
   const scoped_ptr<base::SharedMemory> buffer;
   const size_t buffer_size;
-  const int frame_width;   // In pixels.
-  const int frame_height;  // In pixels.
-  const int frame_stride;  // In pixels.
 
  private:
   friend class base::RefCountedThreadSafe<ClientBuffer>;
@@ -44,20 +35,12 @@
   return state_ == VIDEO_CAPTURE_STATE_STARTED;
 }
 
-int VideoCaptureImpl::CaptureWidth() {
-  return capture_format_.width;
-}
-
-int VideoCaptureImpl::CaptureHeight() {
-  return capture_format_.height;
-}
-
 int VideoCaptureImpl::CaptureFrameRate() {
-  return capture_format_.frame_rate;
+  return last_frame_format_.frame_rate;
 }
 
 VideoCaptureImpl::VideoCaptureImpl(
-    const media::VideoCaptureSessionId id,
+    const media::VideoCaptureSessionId session_id,
     base::MessageLoopProxy* capture_message_loop_proxy,
     VideoCaptureMessageFilter* filter)
     : VideoCapture(),
@@ -65,13 +48,11 @@
       capture_message_loop_proxy_(capture_message_loop_proxy),
       io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
       device_id_(0),
+      session_id_(session_id),
       client_buffer_weak_this_factory_(this),
-      video_type_(media::PIXEL_FORMAT_I420),
-      device_info_available_(false),
       suspended_(false),
       state_(VIDEO_CAPTURE_STATE_STOPPED) {
   DCHECK(filter);
-  capture_format_.session_id = id;
 }
 
 VideoCaptureImpl::~VideoCaptureImpl() {}
@@ -94,12 +75,10 @@
 
 void VideoCaptureImpl::StartCapture(
     media::VideoCapture::EventHandler* handler,
-    const media::VideoCaptureCapability& capability) {
-  DCHECK_EQ(capability.color, media::PIXEL_FORMAT_I420);
-
+    const media::VideoCaptureParams& params) {
   capture_message_loop_proxy_->PostTask(FROM_HERE,
       base::Bind(&VideoCaptureImpl::DoStartCaptureOnCaptureThread,
-                 base::Unretained(this), handler, capability));
+                 base::Unretained(this), handler, params));
 }
 
 void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) {
@@ -116,10 +95,19 @@
                  base::Unretained(this), handle, length, buffer_id));
 }
 
-void VideoCaptureImpl::OnBufferReceived(int buffer_id, base::Time timestamp) {
+void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
+  capture_message_loop_proxy_->PostTask(FROM_HERE,
+      base::Bind(&VideoCaptureImpl::DoBufferDestroyedOnCaptureThread,
+                 base::Unretained(this), buffer_id));
+}
+
+void VideoCaptureImpl::OnBufferReceived(
+    int buffer_id,
+    base::Time timestamp,
+    const media::VideoCaptureFormat& format) {
   capture_message_loop_proxy_->PostTask(FROM_HERE,
       base::Bind(&VideoCaptureImpl::DoBufferReceivedOnCaptureThread,
-                 base::Unretained(this), buffer_id, timestamp));
+                 base::Unretained(this), buffer_id, timestamp, format));
 }
 
 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
@@ -128,20 +116,6 @@
                  base::Unretained(this), state));
 }
 
-void VideoCaptureImpl::OnDeviceInfoReceived(
-    const media::VideoCaptureParams& device_info) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoDeviceInfoReceivedOnCaptureThread,
-                 base::Unretained(this), device_info));
-}
-
-void VideoCaptureImpl::OnDeviceInfoChanged(
-    const media::VideoCaptureParams& device_info) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoDeviceInfoChangedOnCaptureThread,
-                 base::Unretained(this), device_info));
-}
-
 void VideoCaptureImpl::OnDelegateAdded(int32 device_id) {
   capture_message_loop_proxy_->PostTask(FROM_HERE,
       base::Bind(&VideoCaptureImpl::DoDelegateAddedOnCaptureThread,
@@ -165,7 +139,7 @@
 
 void VideoCaptureImpl::DoStartCaptureOnCaptureThread(
     media::VideoCapture::EventHandler* handler,
-    const media::VideoCaptureCapability& capability) {
+    const media::VideoCaptureParams& params) {
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
 
   if (state_ == VIDEO_CAPTURE_STATE_ERROR) {
@@ -178,46 +152,31 @@
              clients_.find(handler) != clients_.end() ) {
     // This client has started.
   } else if (!device_id_) {
-    clients_pending_on_filter_[handler] = capability;
+    clients_pending_on_filter_[handler] = params;
   } else {
     handler->OnStarted(this);
     if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
-      // TODO(wjia): Temporarily disable restarting till client supports
-      // resampling.
-#if 0
-      if (capability.width > capture_format_.width ||
-          capability.height > capture_format_.height) {
-        StopDevice();
-        DVLOG(1) << "StartCapture: Got client with higher resolution ("
-                 << capability.width << ", " << capability.height << ") "
-                 << "after started, try to restart.";
-        clients_pending_on_restart_[handler] = capability;
-      } else {
-#endif
-      {
-        if (device_info_available_) {
-          handler->OnDeviceInfoReceived(this, device_info_);
-        }
-
-        clients_[handler] = capability;
-      }
+      clients_[handler] = params;
     } else if (state_ == VIDEO_CAPTURE_STATE_STOPPING) {
-      clients_pending_on_restart_[handler] = capability;
+      clients_pending_on_restart_[handler] = params;
       DVLOG(1) << "StartCapture: Got new resolution ("
-               << capability.width << ", " << capability.height << ") "
+               << params.requested_format.width << ", "
+               << params.requested_format.height << ") "
                << ", during stopping.";
     } else {
-      clients_[handler] = capability;
+      DCHECK_EQ(params.session_id, 0);
+      clients_[handler] = params;
       DCHECK_EQ(1ul, clients_.size());
-      video_type_ = capability.color;
-      int session_id = capture_format_.session_id;
-      DCHECK_EQ(capability.session_id, 0);
-      capture_format_ = capability;
-      capture_format_.session_id = session_id;
-      if (capture_format_.frame_rate > media::limits::kMaxFramesPerSecond)
-        capture_format_.frame_rate = media::limits::kMaxFramesPerSecond;
+      params_ = params;
+      params_.session_id = session_id_;
+      if (params_.requested_format.frame_rate >
+          media::limits::kMaxFramesPerSecond) {
+        params_.requested_format.frame_rate =
+            media::limits::kMaxFramesPerSecond;
+      }
       DVLOG(1) << "StartCapture: starting with first resolution ("
-               << capture_format_.width << "," << capture_format_.height << ")";
+               << params_.requested_format.width << ","
+               << params_.requested_format.height << ")";
 
       StartCaptureInternal();
     }
@@ -255,8 +214,6 @@
     return;
   }
 
-  DCHECK(device_info_available_);
-
   scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false));
   if (!shm->Map(length)) {
     DLOG(ERROR) << "DoBufferCreatedOnCaptureThread: Map() failed.";
@@ -267,15 +224,26 @@
       client_buffers_.insert(std::make_pair(
                                  buffer_id,
                                  new ClientBuffer(shm.Pass(),
-                                                  length,
-                                                  device_info_.width,
-                                                  device_info_.height,
-                                                  device_info_.width))).second;
+                                                  length))).second;
   DCHECK(inserted);
 }
 
+void VideoCaptureImpl::DoBufferDestroyedOnCaptureThread(int buffer_id) {
+  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
+
+  ClientBufferMap::iterator iter = client_buffers_.find(buffer_id);
+  if (iter == client_buffers_.end())
+    return;
+
+  DCHECK(!iter->second || iter->second->HasOneRef())
+      << "Instructed to delete buffer we are still using.";
+  client_buffers_.erase(iter);
+}
+
 void VideoCaptureImpl::DoBufferReceivedOnCaptureThread(
-    int buffer_id, base::Time timestamp) {
+    int buffer_id,
+    base::Time timestamp,
+    const media::VideoCaptureFormat& format) {
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
 
   if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) {
@@ -283,15 +251,16 @@
     return;
   }
 
+  last_frame_format_ = format;
+  gfx::Size size(format.width, format.height);
+
   ClientBufferMap::iterator iter = client_buffers_.find(buffer_id);
   DCHECK(iter != client_buffers_.end());
   scoped_refptr<ClientBuffer> buffer = iter->second;
   scoped_refptr<media::VideoFrame> frame =
       media::VideoFrame::WrapExternalSharedMemory(
           media::VideoFrame::I420,
-          gfx::Size(buffer->frame_stride, buffer->frame_height),
-          gfx::Rect(0, 0, buffer->frame_width, buffer->frame_height),
-          gfx::Size(buffer->frame_width, buffer->frame_height),
+          size, gfx::Rect(size), size,
           reinterpret_cast<uint8*>(buffer->buffer->memory()),
           buffer->buffer_size,
           buffer->buffer->handle(),
@@ -362,27 +331,6 @@
   }
 }
 
-void VideoCaptureImpl::DoDeviceInfoReceivedOnCaptureThread(
-    const media::VideoCaptureParams& device_info) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  DCHECK(client_buffers_.empty());
-
-  device_info_ = device_info;
-  device_info_available_ = true;
-  for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) {
-    it->first->OnDeviceInfoReceived(this, device_info);
-  }
-}
-
-void VideoCaptureImpl::DoDeviceInfoChangedOnCaptureThread(
-    const media::VideoCaptureParams& device_info) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-
-  for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) {
-    it->first->OnDeviceInfoChanged(this, device_info);
-  }
-}
-
 void VideoCaptureImpl::DoDelegateAddedOnCaptureThread(int32 device_id) {
   DVLOG(1) << "DoDelegateAdded: device_id " << device_id;
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
@@ -391,9 +339,9 @@
   for (ClientInfo::iterator it = clients_pending_on_filter_.begin();
        it != clients_pending_on_filter_.end(); ) {
     media::VideoCapture::EventHandler* handler = it->first;
-    const media::VideoCaptureCapability capability = it->second;
+    const media::VideoCaptureParams params = it->second;
     clients_pending_on_filter_.erase(it++);
-    StartCapture(handler, capability);
+    StartCapture(handler, params);
   }
 }
 
@@ -407,11 +355,10 @@
 void VideoCaptureImpl::StopDevice() {
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
 
-  device_info_available_ = false;
   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
     state_ = VIDEO_CAPTURE_STATE_STOPPING;
     Send(new VideoCaptureHostMsg_Stop(device_id_));
-    capture_format_.width = capture_format_.height = 0;
+    params_.requested_format.width = params_.requested_format.height = 0;
   }
 }
 
@@ -423,20 +370,20 @@
   int height = 0;
   for (ClientInfo::iterator it = clients_.begin();
        it != clients_.end(); ++it) {
-    width = std::max(width, it->second.width);
-    height = std::max(height, it->second.height);
+    width = std::max(width, it->second.requested_format.width);
+    height = std::max(height, it->second.requested_format.height);
   }
   for (ClientInfo::iterator it = clients_pending_on_restart_.begin();
        it != clients_pending_on_restart_.end(); ) {
-    width = std::max(width, it->second.width);
-    height = std::max(height, it->second.height);
+    width = std::max(width, it->second.requested_format.width);
+    height = std::max(height, it->second.requested_format.height);
     clients_[it->first] = it->second;
     clients_pending_on_restart_.erase(it++);
   }
-  capture_format_.width = width;
-  capture_format_.height = height;
-  DVLOG(1) << "RestartCapture, " << capture_format_.width << ", "
-           << capture_format_.height;
+  params_.requested_format.width = width;
+  params_.requested_format.height = height;
+  DVLOG(1) << "RestartCapture, " << params_.requested_format.width << ", "
+           << params_.requested_format.height;
   StartCaptureInternal();
 }
 
@@ -444,13 +391,7 @@
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
   DCHECK(device_id_);
 
-  media::VideoCaptureParams capability_as_params_copy;
-  capability_as_params_copy.width = capture_format_.width;
-  capability_as_params_copy.height = capture_format_.height;
-  capability_as_params_copy.frame_rate = capture_format_.frame_rate;
-  capability_as_params_copy.session_id = capture_format_.session_id;
-  capability_as_params_copy.frame_size_type = capture_format_.frame_size_type;
-  Send(new VideoCaptureHostMsg_Start(device_id_, capability_as_params_copy));
+  Send(new VideoCaptureHostMsg_Start(device_id_, params_));
   state_ = VIDEO_CAPTURE_STATE_STARTED;
 }
 
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index 03696a7..24a28d8 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -6,8 +6,8 @@
 // interfaces for clients to Start/Stop capture. It also communicates to clients
 // when buffer is ready, state of capture device is changed.
 
-// VideoCaptureImpl is also a delegate of VideoCaptureMessageFilter which
-// relays operation of capture device to browser process and receives response
+// VideoCaptureImpl is also a delegate of VideoCaptureMessageFilter which relays
+// operation of a capture device to the browser process and receives responses
 // from browser process.
 
 // The media::VideoCapture and VideoCaptureMessageFilter::Delegate are
@@ -52,22 +52,21 @@
   // media::VideoCapture interface.
   virtual void StartCapture(
       media::VideoCapture::EventHandler* handler,
-      const media::VideoCaptureCapability& capability) OVERRIDE;
+      const media::VideoCaptureParams& params) OVERRIDE;
   virtual void StopCapture(media::VideoCapture::EventHandler* handler) OVERRIDE;
   virtual bool CaptureStarted() OVERRIDE;
-  virtual int CaptureWidth() OVERRIDE;
-  virtual int CaptureHeight() OVERRIDE;
   virtual int CaptureFrameRate() OVERRIDE;
 
   // VideoCaptureMessageFilter::Delegate interface.
   virtual void OnBufferCreated(base::SharedMemoryHandle handle,
-                               int length, int buffer_id) OVERRIDE;
-  virtual void OnBufferReceived(int buffer_id, base::Time timestamp) OVERRIDE;
+                               int length,
+                               int buffer_id) OVERRIDE;
+  virtual void OnBufferDestroyed(int buffer_id) OVERRIDE;
+  virtual void OnBufferReceived(
+      int buffer_id,
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format) OVERRIDE;
   virtual void OnStateChanged(VideoCaptureState state) OVERRIDE;
-  virtual void OnDeviceInfoReceived(
-      const media::VideoCaptureParams& device_info) OVERRIDE;
-  virtual void OnDeviceInfoChanged(
-      const media::VideoCaptureParams& device_info) OVERRIDE;
   virtual void OnDelegateAdded(int32 device_id) OVERRIDE;
 
   // Stop/resume delivering video frames to clients, based on flag |suspend|.
@@ -80,28 +79,29 @@
 
   class ClientBuffer;
   typedef std::map<media::VideoCapture::EventHandler*,
-                   media::VideoCaptureCapability> ClientInfo;
+                   media::VideoCaptureParams> ClientInfo;
 
-  VideoCaptureImpl(media::VideoCaptureSessionId id,
+  VideoCaptureImpl(media::VideoCaptureSessionId session_id,
                    base::MessageLoopProxy* capture_message_loop_proxy,
                    VideoCaptureMessageFilter* filter);
   virtual ~VideoCaptureImpl();
 
   void DoStartCaptureOnCaptureThread(
       media::VideoCapture::EventHandler* handler,
-      const media::VideoCaptureCapability& capability);
+      const media::VideoCaptureParams& params);
   void DoStopCaptureOnCaptureThread(media::VideoCapture::EventHandler* handler);
   void DoBufferCreatedOnCaptureThread(base::SharedMemoryHandle handle,
-                                      int length, int buffer_id);
-  void DoBufferReceivedOnCaptureThread(int buffer_id, base::Time timestamp);
+                                      int length,
+                                      int buffer_id);
+  void DoBufferDestroyedOnCaptureThread(int buffer_id);
+  void DoBufferReceivedOnCaptureThread(
+      int buffer_id,
+      base::Time timestamp,
+      const media::VideoCaptureFormat& format);
   void DoClientBufferFinishedOnCaptureThread(
       int buffer_id,
       const scoped_refptr<ClientBuffer>& buffer);
   void DoStateChangedOnCaptureThread(VideoCaptureState state);
-  void DoDeviceInfoReceivedOnCaptureThread(
-      const media::VideoCaptureParams& device_info);
-  void DoDeviceInfoChangedOnCaptureThread(
-      const media::VideoCaptureParams& device_info);
   void DoDelegateAddedOnCaptureThread(int32 device_id);
 
   void DoSuspendCaptureOnCaptureThread(bool suspend);
@@ -124,6 +124,7 @@
   const scoped_refptr<base::MessageLoopProxy> capture_message_loop_proxy_;
   const scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
   int device_id_;
+  const int session_id_;
 
   // Buffers available for sending to the client.
   typedef std::map<int32, scoped_refptr<ClientBuffer> > ClientBufferMap;
@@ -138,15 +139,12 @@
   ClientInfo clients_pending_on_filter_;
   ClientInfo clients_pending_on_restart_;
 
-  media::VideoPixelFormat video_type_;
-
-  // Member capture_format_ represents the video format requested by the client
-  // to this class via DoStartCaptureOnCaptureThread.
-  media::VideoCaptureCapability capture_format_;
+  // Member params_ represents the video format requested by the
+  // client to this class via DoStartCaptureOnCaptureThread.
+  media::VideoCaptureParams params_;
 
   // The device's video capture format sent from browser process side.
-  media::VideoCaptureParams device_info_;
-  bool device_info_available_;
+  media::VideoCaptureFormat last_frame_format_;
 
   bool suspended_;
   VideoCaptureState state_;
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index 986106b..f0bf333 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -45,7 +45,7 @@
                     const scoped_refptr<media::VideoFrame>& frame));
   MOCK_METHOD2(OnDeviceInfoReceived,
                void(media::VideoCapture* capture,
-                    const media::VideoCaptureParams& device_info));
+                    const media::VideoCaptureFormat& device_info));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureClient);
@@ -82,8 +82,6 @@
 
     void DeviceStartCapture(int device_id,
                             const media::VideoCaptureParams& params) {
-      media::VideoCaptureParams device_info = params;
-      OnDeviceInfoReceived(device_info);
       OnStateChanged(VIDEO_CAPTURE_STATE_STARTED);
     }
 
@@ -96,21 +94,13 @@
     void DeviceReceiveEmptyBuffer(int device_id, int buffer_id) {}
   };
 
-  VideoCaptureImplTest()
-      : capability_small_(176,
-                          144,
-                          30,
-                          media::PIXEL_FORMAT_I420,
-                          0,
-                          false,
-                          media::ConstantResolutionVideoCaptureDevice),
-        capability_large_(320,
-                          240,
-                          30,
-                          media::PIXEL_FORMAT_I420,
-                          0,
-                          false,
-                          media::ConstantResolutionVideoCaptureDevice) {
+  VideoCaptureImplTest() {
+    params_small_.requested_format = media::VideoCaptureFormat(
+        176, 144, 30, media::ConstantResolutionVideoCaptureDevice);
+
+    params_large_.requested_format = media::VideoCaptureFormat(
+        320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
+
     message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
     message_loop_proxy_ = base::MessageLoopProxy::current().get();
     child_process_.reset(new ChildProcess());
@@ -135,8 +125,8 @@
   scoped_refptr<MockVideoCaptureMessageFilter> message_filter_;
   media::VideoCaptureSessionId session_id_;
   MockVideoCaptureImpl* video_capture_impl_;
-  const media::VideoCaptureCapability capability_small_;
-  const media::VideoCaptureCapability capability_large_;
+  media::VideoCaptureParams params_small_;
+  media::VideoCaptureParams params_large_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplTest);
@@ -148,10 +138,8 @@
 
   EXPECT_CALL(*client, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
 
-  video_capture_impl_->StartCapture(client.get(), capability_small_);
+  video_capture_impl_->StartCapture(client.get(), params_small_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client, OnStopped(_))
@@ -169,10 +157,8 @@
 
   EXPECT_CALL(*client, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
 
-  video_capture_impl_->StartCapture(client.get(), capability_small_);
+  video_capture_impl_->StartCapture(client.get(), params_small_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client, OnStopped(_))
@@ -185,10 +171,8 @@
 
   EXPECT_CALL(*client, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
 
-  video_capture_impl_->StartCapture(client.get(), capability_small_);
+  video_capture_impl_->StartCapture(client.get(), params_small_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client, OnStopped(_))
@@ -208,15 +192,11 @@
 
   EXPECT_CALL(*client_large, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client_large, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
   EXPECT_CALL(*client_small, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client_small, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
 
-  video_capture_impl_->StartCapture(client_large.get(), capability_large_);
-  video_capture_impl_->StartCapture(client_small.get(), capability_small_);
+  video_capture_impl_->StartCapture(client_large.get(), params_large_);
+  video_capture_impl_->StartCapture(client_small.get(), params_small_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client_large, OnStopped(_))
@@ -241,16 +221,11 @@
 
   EXPECT_CALL(*client_large, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client_large, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
   EXPECT_CALL(*client_small, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client_small, OnDeviceInfoReceived(_,_))
-      .Times(AtLeast(1))
-      .WillRepeatedly(Return());
 
-  video_capture_impl_->StartCapture(client_small.get(), capability_small_);
-  video_capture_impl_->StartCapture(client_large.get(), capability_large_);
+  video_capture_impl_->StartCapture(client_small.get(), params_small_);
+  video_capture_impl_->StartCapture(client_large.get(), params_large_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client_large, OnStopped(_))
@@ -275,15 +250,11 @@
 
   EXPECT_CALL(*client1, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client1, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
   EXPECT_CALL(*client2, OnStarted(_))
       .WillOnce(Return());
-  EXPECT_CALL(*client2, OnDeviceInfoReceived(_,_))
-      .WillOnce(Return());
 
-  video_capture_impl_->StartCapture(client1.get(), capability_small_);
-  video_capture_impl_->StartCapture(client2.get(), capability_small_);
+  video_capture_impl_->StartCapture(client1.get(), params_small_);
+  video_capture_impl_->StartCapture(client2.get(), params_small_);
   message_loop_->RunUntilIdle();
 
   EXPECT_CALL(*client1, OnStopped(_))
diff --git a/content/renderer/media/video_capture_message_filter.cc b/content/renderer/media/video_capture_message_filter.cc
index 0ef77fa..52847d9 100644
--- a/content/renderer/media/video_capture_message_filter.cc
+++ b/content/renderer/media/video_capture_message_filter.cc
@@ -60,7 +60,7 @@
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_BufferReady, OnBufferReceived)
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnDeviceStateChanged)
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnBufferCreated)
-    IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfoReceived)
+    IPC_MESSAGE_HANDLER(VideoCaptureMsg_FreeBuffer, OnBufferDestroyed)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -68,8 +68,6 @@
 
 void VideoCaptureMessageFilter::OnFilterAdded(IPC::Channel* channel) {
   DVLOG(1) << "VideoCaptureMessageFilter::OnFilterAdded()";
-  // Captures the message loop proxy for IPC.
-  message_loop_proxy_ = base::MessageLoopProxy::current();
   channel_ = channel;
 
   for (Delegates::iterator it = pending_delegates_.begin();
@@ -119,7 +117,8 @@
 void VideoCaptureMessageFilter::OnBufferReceived(
     int device_id,
     int buffer_id,
-    base::Time timestamp) {
+    base::Time timestamp,
+    const media::VideoCaptureFormat& format) {
   Delegate* delegate = find_delegate(device_id);
   if (!delegate) {
     DLOG(WARNING) << "OnBufferReceived: Got video frame buffer for a "
@@ -131,7 +130,20 @@
     return;
   }
 
-  delegate->OnBufferReceived(buffer_id, timestamp);
+  delegate->OnBufferReceived(buffer_id, timestamp, format);
+}
+
+void VideoCaptureMessageFilter::OnBufferDestroyed(
+    int device_id,
+    int buffer_id) {
+  Delegate* delegate = find_delegate(device_id);
+  if (!delegate) {
+    DLOG(WARNING) << "OnBufferDestroyed: Instructed to free buffer for a "
+        "non-existent or removed video capture.";
+    return;
+  }
+
+  delegate->OnBufferDestroyed(buffer_id);
 }
 
 void VideoCaptureMessageFilter::OnDeviceStateChanged(
@@ -146,16 +158,4 @@
   delegate->OnStateChanged(state);
 }
 
-void VideoCaptureMessageFilter::OnDeviceInfoReceived(
-    int device_id,
-    const media::VideoCaptureParams& params) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnDeviceInfoReceived: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnDeviceInfoReceived(params);
-}
-
 }  // namespace content
diff --git a/content/renderer/media/video_capture_message_filter.h b/content/renderer/media/video_capture_message_filter.h
index abbe23e..024c1bd 100644
--- a/content/renderer/media/video_capture_message_filter.h
+++ b/content/renderer/media/video_capture_message_filter.h
@@ -13,7 +13,6 @@
 #include <map>
 
 #include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/common/content_export.h"
 #include "content/common/media/video_capture.h"
 #include "ipc/ipc_channel_proxy.h"
@@ -28,25 +27,20 @@
    public:
     // Called when a video frame buffer is created in the browser process.
     virtual void OnBufferCreated(base::SharedMemoryHandle handle,
-                                 int length, int buffer_id) = 0;
+                                 int length,
+                                 int buffer_id) = 0;
+
+    virtual void OnBufferDestroyed(int buffer_id) = 0;
 
     // Called when a video frame buffer is received from the browser process.
-    virtual void OnBufferReceived(int buffer_id, base::Time timestamp) = 0;
+    virtual void OnBufferReceived(int buffer_id,
+                                  base::Time timestamp,
+                                  const media::VideoCaptureFormat& format) = 0;
 
     // Called when state of a video capture device has changed in the browser
     // process.
     virtual void OnStateChanged(VideoCaptureState state) = 0;
 
-    // Called when device info is received from video capture device in the
-    // browser process.
-    virtual void OnDeviceInfoReceived(
-        const media::VideoCaptureParams& device_info) = 0;
-
-    // Called when newly changed device info is received from video capture
-    // device in the browser process.
-    virtual void OnDeviceInfoChanged(
-        const media::VideoCaptureParams& device_info) {};
-
     // Called when the delegate has been added to filter's delegate list.
     // |device_id| is the device id for the delegate.
     virtual void OnDelegateAdded(int32 device_id) = 0;
@@ -76,26 +70,27 @@
   virtual ~VideoCaptureMessageFilter();
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(VideoCaptureMessageFilterTest, Basic);
-  FRIEND_TEST_ALL_PREFIXES(VideoCaptureMessageFilterTest, Delegates);
-
   typedef std::map<int32, Delegate*> Delegates;
 
   // Receive a newly created buffer from browser process.
   void OnBufferCreated(int device_id,
                        base::SharedMemoryHandle handle,
-                       int length, int buffer_id);
+                       int length,
+                       int buffer_id);
 
-  // Receive a buffer from browser process.
-  void OnBufferReceived(int device_id, int buffer_id, base::Time timestamp);
+  // Release a buffer received by OnBufferCreated.
+  void OnBufferDestroyed(int device_id,
+                         int buffer_id);
+
+  // Receive a filled buffer from browser process.
+  void OnBufferReceived(int device_id,
+                        int buffer_id,
+                        base::Time timestamp,
+                        const media::VideoCaptureFormat& format);
 
   // State of browser process' video capture device has changed.
   void OnDeviceStateChanged(int device_id, VideoCaptureState state);
 
-  // Receive device info from browser process.
-  void OnDeviceInfoReceived(int device_id,
-                            const media::VideoCaptureParams& params);
-
   // Finds the delegate associated with |device_id|, NULL if not found.
   Delegate* find_delegate(int device_id) const;
 
@@ -106,8 +101,6 @@
 
   IPC::Channel* channel_;
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
-
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureMessageFilter);
 };
 
diff --git a/content/renderer/media/video_capture_message_filter_unittest.cc b/content/renderer/media/video_capture_message_filter_unittest.cc
index 3dec39d..069673f 100644
--- a/content/renderer/media/video_capture_message_filter_unittest.cc
+++ b/content/renderer/media/video_capture_message_filter_unittest.cc
@@ -3,125 +3,68 @@
 // found in the LICENSE file.
 
 #include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop.h"
 #include "content/common/media/video_capture_messages.h"
 #include "content/renderer/media/video_capture_message_filter.h"
+#include "ipc/ipc_test_sink.h"
+#include "media/video/capture/video_capture_types.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AnyNumber;
+using ::testing::Field;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
 namespace content {
 namespace {
 
 class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate {
  public:
-  MockVideoCaptureDelegate() {
-    Reset();
-    device_id_received_ = false;
-    device_id_ = 0;
-  }
+  MockVideoCaptureDelegate() : device_id_(0) {}
 
-  virtual void OnBufferCreated(base::SharedMemoryHandle handle,
-                               int length, int buffer_id) OVERRIDE {
-    buffer_created_ = true;
-    handle_ = handle;
-  }
-
-  // Called when a video frame buffer is received from the browser process.
-  virtual void OnBufferReceived(int buffer_id, base::Time timestamp) OVERRIDE {
-    buffer_received_ = true;
-    buffer_id_ = buffer_id;
-    timestamp_ = timestamp;
-  }
-
-  virtual void OnStateChanged(VideoCaptureState state) OVERRIDE {
-    state_changed_received_ = true;
-    state_ = state;
-  }
-
-  virtual void OnDeviceInfoReceived(
-      const media::VideoCaptureParams& params) OVERRIDE {
-    device_info_received_ = true;
-    params_.width = params.width;
-    params_.height = params.height;
-    params_.frame_rate = params.frame_rate;
-  }
+  // VideoCaptureMessageFilter::Delegate implementation.
+  MOCK_METHOD3(OnBufferCreated, void(base::SharedMemoryHandle handle,
+                                     int length,
+                                     int buffer_id));
+  MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id));
+  MOCK_METHOD3(OnBufferReceived, void(int buffer_id,
+                                      base::Time timestamp,
+                                      const media::VideoCaptureFormat& format));
+  MOCK_METHOD1(OnStateChanged, void(VideoCaptureState state));
 
   virtual void OnDelegateAdded(int32 device_id) OVERRIDE {
-    device_id_received_ = true;
+    ASSERT_TRUE(device_id != 0);
+    ASSERT_TRUE(device_id_ == 0);
     device_id_ = device_id;
   }
 
-  void Reset() {
-    buffer_created_ = false;
-    handle_ = base::SharedMemory::NULLHandle();
-
-    buffer_received_ = false;
-    buffer_id_ = -1;
-    timestamp_ = base::Time();
-
-    state_changed_received_ = false;
-    state_ = VIDEO_CAPTURE_STATE_ERROR;
-
-    device_info_received_ = false;
-    params_.width = 0;
-    params_.height = 0;
-    params_.frame_rate = 0;
-  }
-
-  bool buffer_created() { return buffer_created_; }
-  base::SharedMemoryHandle received_buffer_handle() { return handle_; }
-
-  bool buffer_received() { return buffer_received_; }
-  int received_buffer_id() { return buffer_id_; }
-  base::Time received_buffer_ts() { return timestamp_; }
-
-  bool state_changed_received() { return state_changed_received_; }
-  VideoCaptureState state() { return state_; }
-
-  bool device_info_receive() { return device_info_received_; }
-  const media::VideoCaptureParams& received_device_info() { return params_; }
-
-  int32 device_id() { return device_id_; }
+  int device_id() { return device_id_; }
 
  private:
-  bool buffer_created_;
-  base::SharedMemoryHandle handle_;
-
-  bool buffer_received_;
-  int buffer_id_;
-  base::Time timestamp_;
-
-  bool state_changed_received_;
-  VideoCaptureState state_;
-
-  bool device_info_received_;
-  media::VideoCaptureParams params_;
-
-  bool device_id_received_;
-  int32 device_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureDelegate);
+  int device_id_;
 };
 
 }  // namespace
 
 TEST(VideoCaptureMessageFilterTest, Basic) {
-  base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
-
   scoped_refptr<VideoCaptureMessageFilter> filter(
       new VideoCaptureMessageFilter());
-  filter->channel_ = reinterpret_cast<IPC::Channel*>(1);
 
+  IPC::TestSink channel;
+  filter->OnFilterAdded(&channel);
   MockVideoCaptureDelegate delegate;
   filter->AddDelegate(&delegate);
+  ASSERT_EQ(1, delegate.device_id());
 
   // VideoCaptureMsg_StateChanged
-  EXPECT_FALSE(delegate.state_changed_received());
+  EXPECT_CALL(delegate, OnStateChanged(VIDEO_CAPTURE_STATE_STARTED));
   filter->OnMessageReceived(
       VideoCaptureMsg_StateChanged(delegate.device_id(),
                                    VIDEO_CAPTURE_STATE_STARTED));
-  EXPECT_TRUE(delegate.state_changed_received());
-  EXPECT_TRUE(VIDEO_CAPTURE_STATE_STARTED == delegate.state());
-  delegate.Reset();
+  Mock::VerifyAndClearExpectations(&delegate);
 
   // VideoCaptureMsg_NewBuffer
   const base::SharedMemoryHandle handle =
@@ -130,92 +73,70 @@
 #else
       base::SharedMemoryHandle(10, true);
 #endif
-  EXPECT_FALSE(delegate.buffer_created());
+  EXPECT_CALL(delegate, OnBufferCreated(handle, 100, 1));
   filter->OnMessageReceived(VideoCaptureMsg_NewBuffer(
-      delegate.device_id(), handle, 1, 1));
-  EXPECT_TRUE(delegate.buffer_created());
-  EXPECT_EQ(handle, delegate.received_buffer_handle());
-  delegate.Reset();
+      delegate.device_id(), handle, 100, 1));
+  Mock::VerifyAndClearExpectations(&delegate);
 
   // VideoCaptureMsg_BufferReady
-  int buffer_id = 1;
+  int buffer_id = 22;
   base::Time timestamp = base::Time::FromInternalValue(1);
 
-  EXPECT_FALSE(delegate.buffer_received());
+  media::VideoCaptureFormat format(234, 512, 30,
+      media::ConstantResolutionVideoCaptureDevice);
+  EXPECT_CALL(delegate, OnBufferReceived(buffer_id, timestamp,
+      AllOf(Field(&media::VideoCaptureFormat::width, 234),
+            Field(&media::VideoCaptureFormat::height, 512),
+            Field(&media::VideoCaptureFormat::frame_rate, 30))));
   filter->OnMessageReceived(VideoCaptureMsg_BufferReady(
-      delegate.device_id(), buffer_id, timestamp));
-  EXPECT_TRUE(delegate.buffer_received());
-  EXPECT_EQ(buffer_id, delegate.received_buffer_id());
-  EXPECT_TRUE(timestamp == delegate.received_buffer_ts());
-  delegate.Reset();
+      delegate.device_id(), buffer_id, timestamp, format));
+  Mock::VerifyAndClearExpectations(&delegate);
 
-  // VideoCaptureMsg_DeviceInfo
-  media::VideoCaptureParams params;
-  params.width = 320;
-  params.height = 240;
-  params.frame_rate = 30;
-
-  EXPECT_FALSE(delegate.device_info_receive());
-  filter->OnMessageReceived(VideoCaptureMsg_DeviceInfo(
-      delegate.device_id(), params));
-  EXPECT_TRUE(delegate.device_info_receive());
-  EXPECT_EQ(params.width, delegate.received_device_info().width);
-  EXPECT_EQ(params.height, delegate.received_device_info().height);
-  EXPECT_EQ(params.frame_rate,
-            delegate.received_device_info().frame_rate);
-  delegate.Reset();
-
-  message_loop.RunUntilIdle();
+  // VideoCaptureMsg_FreeBuffer
+  EXPECT_CALL(delegate, OnBufferDestroyed(buffer_id));
+  filter->OnMessageReceived(VideoCaptureMsg_FreeBuffer(
+      delegate.device_id(), buffer_id));
+  Mock::VerifyAndClearExpectations(&delegate);
 }
 
 TEST(VideoCaptureMessageFilterTest, Delegates) {
-  base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
-
   scoped_refptr<VideoCaptureMessageFilter> filter(
       new VideoCaptureMessageFilter());
-  filter->channel_ = reinterpret_cast<IPC::Channel*>(1);
 
-  MockVideoCaptureDelegate delegate1;
-  MockVideoCaptureDelegate delegate2;
+  IPC::TestSink channel;
+  filter->OnFilterAdded(&channel);
+
+  StrictMock<MockVideoCaptureDelegate> delegate1;
+  StrictMock<MockVideoCaptureDelegate> delegate2;
 
   filter->AddDelegate(&delegate1);
   filter->AddDelegate(&delegate2);
+  ASSERT_EQ(1, delegate1.device_id());
+  ASSERT_EQ(2, delegate2.device_id());
 
   // Send an IPC message. Make sure the correct delegate gets called.
-  EXPECT_FALSE(delegate1.state_changed_received());
-  EXPECT_FALSE(delegate2.state_changed_received());
+  EXPECT_CALL(delegate1, OnStateChanged(VIDEO_CAPTURE_STATE_STARTED));
   filter->OnMessageReceived(
       VideoCaptureMsg_StateChanged(delegate1.device_id(),
                                    VIDEO_CAPTURE_STATE_STARTED));
-  EXPECT_TRUE(delegate1.state_changed_received());
-  EXPECT_FALSE(delegate2.state_changed_received());
-  delegate1.Reset();
+  Mock::VerifyAndClearExpectations(&delegate1);
 
-  EXPECT_FALSE(delegate1.state_changed_received());
-  EXPECT_FALSE(delegate2.state_changed_received());
+  EXPECT_CALL(delegate2, OnStateChanged(VIDEO_CAPTURE_STATE_STARTED));
   filter->OnMessageReceived(
       VideoCaptureMsg_StateChanged(delegate2.device_id(),
                                    VIDEO_CAPTURE_STATE_STARTED));
-  EXPECT_FALSE(delegate1.state_changed_received());
-  EXPECT_TRUE(delegate2.state_changed_received());
-  delegate2.Reset();
+  Mock::VerifyAndClearExpectations(&delegate2);
 
   // Remove the delegates. Make sure they won't get called.
   filter->RemoveDelegate(&delegate1);
-  EXPECT_FALSE(delegate1.state_changed_received());
   filter->OnMessageReceived(
       VideoCaptureMsg_StateChanged(delegate1.device_id(),
-                                   VIDEO_CAPTURE_STATE_STARTED));
-  EXPECT_FALSE(delegate1.state_changed_received());
+                                   VIDEO_CAPTURE_STATE_ENDED));
 
   filter->RemoveDelegate(&delegate2);
-  EXPECT_FALSE(delegate2.state_changed_received());
   filter->OnMessageReceived(
       VideoCaptureMsg_StateChanged(delegate2.device_id(),
-                                   VIDEO_CAPTURE_STATE_STARTED));
-  EXPECT_FALSE(delegate2.state_changed_received());
-
-  message_loop.RunUntilIdle();
+                                   VIDEO_CAPTURE_STATE_ENDED));
 }
 
 }  // namespace content
diff --git a/content/renderer/p2p/ipc_socket_factory.cc b/content/renderer/p2p/ipc_socket_factory.cc
index ced8822..bd8fb31 100644
--- a/content/renderer/p2p/ipc_socket_factory.cc
+++ b/content/renderer/p2p/ipc_socket_factory.cc
@@ -256,7 +256,8 @@
 
   const char* data_char = reinterpret_cast<const char*>(data);
   std::vector<char> data_vector(data_char, data_char + data_size);
-  client_->Send(address_chrome, data_vector);
+  client_->SendWithDscp(address_chrome, data_vector,
+                        static_cast<net::DiffServCodePoint>(dscp));
 
   // Fake successful send. The caller ignores result anyway.
   return data_size;
diff --git a/content/renderer/p2p/socket_client.cc b/content/renderer/p2p/socket_client.cc
index 6404941..74ad2b3 100644
--- a/content/renderer/p2p/socket_client.cc
+++ b/content/renderer/p2p/socket_client.cc
@@ -69,7 +69,8 @@
     net::DiffServCodePoint dscp) {
   if (!ipc_message_loop_->BelongsToCurrentThread()) {
     ipc_message_loop_->PostTask(
-        FROM_HERE, base::Bind(&P2PSocketClient::Send, this, address, data));
+        FROM_HERE, base::Bind(
+            &P2PSocketClient::SendWithDscp, this, address, data, dscp));
     return;
   }
 
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
index 3c9dce2..7ebceb1 100644
--- a/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -218,6 +218,27 @@
   }
 }
 
+media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
+    PP_DecryptedSampleFormat result) {
+  switch (result) {
+    case PP_DECRYPTEDSAMPLEFORMAT_U8:
+      return media::kSampleFormatU8;
+    case PP_DECRYPTEDSAMPLEFORMAT_S16:
+      return media::kSampleFormatS16;
+    case PP_DECRYPTEDSAMPLEFORMAT_S32:
+      return media::kSampleFormatS32;
+    case PP_DECRYPTEDSAMPLEFORMAT_F32:
+      return media::kSampleFormatF32;
+    case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
+      return media::kSampleFormatPlanarS16;
+    case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
+      return media::kSampleFormatPlanarF32;
+    default:
+      NOTREACHED();
+      return media::kUnknownSampleFormat;
+  }
+}
+
 }  // namespace
 
 ContentDecryptorDelegate::ContentDecryptorDelegate(
@@ -232,10 +253,8 @@
       pending_video_decoder_init_request_id_(0),
       pending_audio_decode_request_id_(0),
       pending_video_decode_request_id_(0),
-      audio_sample_format_(media::kUnknownSampleFormat),
       audio_samples_per_second_(0),
       audio_channel_count_(0),
-      audio_bytes_per_frame_(0),
       weak_ptr_factory_(this) {
   weak_this_ = weak_ptr_factory_.GetWeakPtr();
 }
@@ -405,10 +424,8 @@
   pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
   pp_decoder_config.request_id = next_decryption_request_id_++;
 
-  audio_sample_format_ = decoder_config.sample_format();
   audio_samples_per_second_ = pp_decoder_config.samples_per_second;
   audio_channel_count_ = pp_decoder_config.channel_count;
-  audio_bytes_per_frame_ = decoder_config.bytes_per_frame();
 
   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
   if (!MakeBufferResource(pp_instance_,
@@ -852,12 +869,12 @@
 
 void ContentDecryptorDelegate::DeliverSamples(
     PP_Resource audio_frames,
-    const PP_DecryptedBlockInfo* block_info) {
-  DCHECK(block_info);
+    const PP_DecryptedSampleInfo* sample_info) {
+  DCHECK(sample_info);
 
-  FreeBuffer(block_info->tracking_info.buffer_id);
+  FreeBuffer(sample_info->tracking_info.buffer_id);
 
-  const uint32_t request_id = block_info->tracking_info.request_id;
+  const uint32_t request_id = sample_info->tracking_info.request_id;
   DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
 
   // If the request ID is not valid or does not match what's saved, do nothing.
@@ -874,15 +891,19 @@
   const media::Decryptor::AudioBuffers empty_frames;
 
   media::Decryptor::Status status =
-      PpDecryptResultToMediaDecryptorStatus(block_info->result);
+      PpDecryptResultToMediaDecryptorStatus(sample_info->result);
   if (status != media::Decryptor::kSuccess) {
     audio_decode_cb.Run(status, empty_frames);
     return;
   }
 
+  media::SampleFormat sample_format =
+      PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
+
   media::Decryptor::AudioBuffers audio_frame_list;
   if (!DeserializeAudioFrames(audio_frames,
-                              block_info->data_size,
+                              sample_info->data_size,
+                              sample_format,
                               &audio_frame_list)) {
     NOTREACHED() << "CDM did not serialize the buffer correctly.";
     audio_decode_cb.Run(media::Decryptor::kError, empty_frames);
@@ -995,6 +1016,7 @@
 bool ContentDecryptorDelegate::DeserializeAudioFrames(
     PP_Resource audio_frames,
     size_t data_size,
+    media::SampleFormat sample_format,
     media::Decryptor::AudioBuffers* frames) {
   DCHECK(frames);
   EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
@@ -1012,6 +1034,13 @@
   const uint8* cur = static_cast<uint8*>(mapper.data());
   size_t bytes_left = data_size;
 
+  const int audio_bytes_per_frame =
+      media::SampleFormatToBytesPerChannel(sample_format) *
+      audio_channel_count_;
+
+  // Allocate space for the channel pointers given to AudioBuffer.
+  std::vector<const uint8*> channel_ptrs(
+      audio_channel_count_, static_cast<const uint8*>(NULL));
   do {
     int64 timestamp = 0;
     int64 frame_size = -1;
@@ -1034,13 +1063,18 @@
       return false;
     }
 
-    const uint8* data[] = {cur};
-    int frame_count = frame_size / audio_bytes_per_frame_;
+    // Setup channel pointers.  AudioBuffer::CopyFrom() will only use the first
+    // one in the case of interleaved data.
+    const int size_per_channel = frame_size / audio_channel_count_;
+    for (int i = 0; i < audio_channel_count_; ++i)
+      channel_ptrs[i] = cur + i * size_per_channel;
+
+    const int frame_count = frame_size / audio_bytes_per_frame;
     scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
-        audio_sample_format_,
+        sample_format,
         audio_channel_count_,
         frame_count,
-        data,
+        &channel_ptrs[0],
         base::TimeDelta::FromMicroseconds(timestamp),
         base::TimeDelta::FromMicroseconds(audio_samples_per_second_ /
                                           frame_count));
diff --git a/content/renderer/pepper/content_decryptor_delegate.h b/content/renderer/pepper/content_decryptor_delegate.h
index 26989fa..efa7586 100644
--- a/content/renderer/pepper/content_decryptor_delegate.h
+++ b/content/renderer/pepper/content_decryptor_delegate.h
@@ -103,7 +103,7 @@
   void DeliverFrame(PP_Resource decrypted_frame,
                     const PP_DecryptedFrameInfo* frame_info);
   void DeliverSamples(PP_Resource audio_frames,
-                      const PP_DecryptedBlockInfo* block_info);
+                      const PP_DecryptedSampleInfo* sample_info);
 
  private:
   // Cancels the pending decrypt-and-decode callback for |stream_type|.
@@ -132,6 +132,7 @@
   // buffers in |frames|. Returns true upon success.
   bool DeserializeAudioFrames(PP_Resource audio_frames,
                               size_t data_size,
+                              media::SampleFormat sample_format,
                               media::Decryptor::AudioBuffers* frames);
 
   const PP_Instance pp_instance_;
@@ -178,10 +179,8 @@
   std::queue<uint32_t> free_buffers_;
 
   // Keep track of audio parameters.
-  media::SampleFormat audio_sample_format_;
   int audio_samples_per_second_;
   int audio_channel_count_;
-  int audio_bytes_per_frame_;
 
   base::WeakPtr<ContentDecryptorDelegate> weak_this_;
   base::WeakPtrFactory<ContentDecryptorDelegate> weak_ptr_factory_;
diff --git a/content/renderer/pepper/pepper_audio_input_host.cc b/content/renderer/pepper/pepper_audio_input_host.cc
index 331bb49..59b4f98 100644
--- a/content/renderer/pepper/pepper_audio_input_host.cc
+++ b/content/renderer/pepper/pepper_audio_input_host.cc
@@ -12,7 +12,6 @@
 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "ipc/ipc_message.h"
-#include "media/audio/shared_memory_util.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/dispatch_host_message.h"
 #include "ppapi/host/ppapi_host.h"
@@ -169,13 +168,7 @@
         scoped_socket, scoped_shared_memory, &temp_socket, &temp_shmem);
 
     serialized_socket_handle.set_socket(temp_socket);
-    // Note that we must call TotalSharedMemorySizeInBytes() because extra space
-    // in shared memory is allocated for book-keeping, so the actual size of the
-    // shared memory buffer is larger than |shared_memory_size|. When sending to
-    // NaCl, NaClIPCAdapter expects this size to match the size of the full
-    // shared memory buffer.
-    serialized_shared_memory_handle.set_shmem(
-        temp_shmem, media::TotalSharedMemorySizeInBytes(shared_memory_size));
+    serialized_shared_memory_handle.set_shmem(temp_shmem, shared_memory_size);
   }
 
   // Send all the values, even on error. This simplifies some of our cleanup
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc
index 1944ee3..50a52c7 100644
--- a/content/renderer/pepper/pepper_file_system_host.cc
+++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -25,23 +25,6 @@
 
 namespace content {
 
-namespace {
-
-bool LooksLikeAGuid(const std::string& fsid) {
-  const size_t kExpectedFsIdSize = 32;
-  if (fsid.size() != kExpectedFsIdSize)
-    return false;
-  for (std::string::const_iterator it = fsid.begin(); it != fsid.end(); ++it) {
-    if (('A' <= *it && *it <= 'F') ||
-        ('0' <= *it && *it <= '9'))
-      continue;
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
 PepperFileSystemHost::PepperFileSystemHost(RendererPpapiHost* host,
                                            PP_Instance instance,
                                            PP_Resource resource,
@@ -158,7 +141,7 @@
     return PP_ERROR_INPROGRESS;
   called_open_ = true;
   // Do a sanity check.
-  if (!LooksLikeAGuid(fsid))
+  if (!fileapi::ValidateIsolatedFileSystemId(fsid))
     return PP_ERROR_BADARGUMENT;
   RenderView* view =
       renderer_ppapi_host_->GetRenderViewForInstance(pp_instance());
diff --git a/content/renderer/pepper/pepper_platform_video_capture.cc b/content/renderer/pepper/pepper_platform_video_capture.cc
index 86ce45d..dc58ad4 100644
--- a/content/renderer/pepper/pepper_platform_video_capture.cc
+++ b/content/renderer/pepper/pepper_platform_video_capture.cc
@@ -46,7 +46,7 @@
 
 void PepperPlatformVideoCapture::StartCapture(
     media::VideoCapture::EventHandler* handler,
-    const media::VideoCaptureCapability& capability) {
+    const media::VideoCaptureParams& params) {
   DCHECK(handler == handler_);
 
   if (unbalanced_start_)
@@ -55,7 +55,7 @@
   if (video_capture_) {
     unbalanced_start_ = true;
     AddRef();  // Will be balanced in OnRemoved().
-    video_capture_->StartCapture(handler_proxy_.get(), capability);
+    video_capture_->StartCapture(handler_proxy_.get(), params);
   }
 }
 
@@ -75,14 +75,6 @@
   return handler_proxy_->state().started;
 }
 
-int PepperPlatformVideoCapture::CaptureWidth() {
-  return handler_proxy_->state().width;
-}
-
-int PepperPlatformVideoCapture::CaptureHeight() {
-  return handler_proxy_->state().height;
-}
-
 int PepperPlatformVideoCapture::CaptureFrameRate() {
   return handler_proxy_->state().frame_rate;
 }
@@ -146,13 +138,6 @@
     handler_->OnFrameReady(capture, frame);
 }
 
-void PepperPlatformVideoCapture::OnDeviceInfoReceived(
-    VideoCapture* capture,
-    const media::VideoCaptureParams& device_info) {
-  if (handler_)
-    handler_->OnDeviceInfoReceived(capture, device_info);
-}
-
 PepperPlatformVideoCapture::~PepperPlatformVideoCapture() {
   DCHECK(!video_capture_);
   DCHECK(label_.empty());
diff --git a/content/renderer/pepper/pepper_platform_video_capture.h b/content/renderer/pepper/pepper_platform_video_capture.h
index 5ecde2e..609eaa3 100644
--- a/content/renderer/pepper/pepper_platform_video_capture.h
+++ b/content/renderer/pepper/pepper_platform_video_capture.h
@@ -42,11 +42,9 @@
   // media::VideoCapture implementation.
   virtual void StartCapture(
       media::VideoCapture::EventHandler* handler,
-      const media::VideoCaptureCapability& capability) OVERRIDE;
+      const media::VideoCaptureParams& params) OVERRIDE;
   virtual void StopCapture(media::VideoCapture::EventHandler* handler) OVERRIDE;
   virtual bool CaptureStarted() OVERRIDE;
-  virtual int CaptureWidth() OVERRIDE;
-  virtual int CaptureHeight() OVERRIDE;
   virtual int CaptureFrameRate() OVERRIDE;
 
   // media::VideoCapture::EventHandler implementation
@@ -58,9 +56,6 @@
   virtual void OnFrameReady(
       VideoCapture* capture,
       const scoped_refptr<media::VideoFrame>& frame) OVERRIDE;
-  virtual void OnDeviceInfoReceived(
-      VideoCapture* capture,
-      const media::VideoCaptureParams& device_info) OVERRIDE;
 
  protected:
   friend class base::RefCounted<PepperPlatformVideoCapture>;
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 3973bb8..9282fcb 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2276,8 +2276,8 @@
 void PepperPluginInstanceImpl::DeliverSamples(
     PP_Instance instance,
     PP_Resource audio_frames,
-    const PP_DecryptedBlockInfo* block_info) {
-  content_decryptor_delegate_->DeliverSamples(audio_frames, block_info);
+    const PP_DecryptedSampleInfo* sample_info) {
+  content_decryptor_delegate_->DeliverSamples(audio_frames, sample_info);
 }
 
 void PepperPluginInstanceImpl::NumberOfFindResultsChanged(
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index 4398fd9..f28cd44 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -470,9 +470,10 @@
   virtual void DeliverFrame(PP_Instance instance,
                             PP_Resource decrypted_frame,
                             const PP_DecryptedFrameInfo* frame_info) OVERRIDE;
-  virtual void DeliverSamples(PP_Instance instance,
-                              PP_Resource audio_frames,
-                              const PP_DecryptedBlockInfo* block_info) OVERRIDE;
+  virtual void DeliverSamples(
+      PP_Instance instance,
+      PP_Resource audio_frames,
+      const PP_DecryptedSampleInfo* sample_info) OVERRIDE;
 
   // Reset this instance as proxied. Assigns the instance a new module, resets
   // cached interfaces to point to the out-of-process proxy and re-sends
diff --git a/content/renderer/pepper/pepper_video_capture_host.cc b/content/renderer/pepper/pepper_video_capture_host.cc
index cf06bca..9143aa9 100644
--- a/content/renderer/pepper/pepper_video_capture_host.cc
+++ b/content/renderer/pepper/pepper_video_capture_host.cc
@@ -118,6 +118,10 @@
                                      int error_code) {
   // Today, the media layer only sends "1" as an error.
   DCHECK(error_code == 1);
+  PostErrorReply();
+}
+
+void PepperVideoCaptureHost::PostErrorReply() {
   // It either comes because some error was detected while starting (e.g. 2
   // conflicting "master" resolution), or because the browser failed to start
   // the capture.
@@ -133,6 +137,12 @@
     media::VideoCapture* capture,
     const scoped_refptr<media::VideoFrame>& frame) {
   DCHECK(frame.get());
+
+  if (alloc_size_ != frame->coded_size()) {
+    AllocBuffers(frame->coded_size(), capture->CaptureFrameRate());
+    alloc_size_ = frame->coded_size();
+  }
+
   for (uint32_t i = 0; i < buffers_.size(); ++i) {
     if (!buffers_[i].in_use) {
       DCHECK_EQ(frame->format(), media::VideoFrame::I420);
@@ -165,13 +175,13 @@
   }
 }
 
-void PepperVideoCaptureHost::OnDeviceInfoReceived(
-    media::VideoCapture* capture,
-    const media::VideoCaptureParams& device_info) {
+void PepperVideoCaptureHost::AllocBuffers(
+    const gfx::Size& resolution,
+    int frame_rate) {
   PP_VideoCaptureDeviceInfo_Dev info = {
-    static_cast<uint32_t>(device_info.width),
-    static_cast<uint32_t>(device_info.height),
-    static_cast<uint32_t>(device_info.frame_rate)
+    static_cast<uint32_t>(resolution.width()),
+    static_cast<uint32_t>(resolution.height()),
+    static_cast<uint32_t>(frame_rate)
   };
   ReleaseBuffers();
 
@@ -246,7 +256,7 @@
     // capture.
     SetStatus(PP_VIDEO_CAPTURE_STATUS_STOPPING, true);
     platform_video_capture_->StopCapture(this);
-    OnError(capture, PP_ERROR_NOMEMORY);
+    PostErrorReply();
     return;
   }
 
@@ -292,7 +302,7 @@
 
   // It's safe to call this regardless it's capturing or not, because
   // PepperPlatformVideoCapture maintains the state.
-  platform_video_capture_->StartCapture(this, capability_);
+  platform_video_capture_->StartCapture(this, video_capture_params_);
   return PP_OK;
 }
 
@@ -358,12 +368,11 @@
   // Clamp the buffer count to between 1 and |kMaxBuffers|.
   buffer_count_hint_ = std::min(std::max(buffer_count, 1U), kMaxBuffers);
 
-  capability_.width = device_info.width;
-  capability_.height = device_info.height;
-  capability_.frame_rate = device_info.frames_per_second;
-  capability_.expected_capture_delay = 0;  // Ignored.
-  capability_.color = media::PIXEL_FORMAT_I420;
-  capability_.interlaced = false;  // Ignored.
+  video_capture_params_.requested_format =
+      media::VideoCaptureFormat(device_info.width,
+                                device_info.height,
+                                device_info.frames_per_second,
+                                media::ConstantResolutionVideoCaptureDevice);
 }
 
 void PepperVideoCaptureHost::DetachPlatformVideoCapture() {
diff --git a/content/renderer/pepper/pepper_video_capture_host.h b/content/renderer/pepper/pepper_video_capture_host.h
index ab6a304..a8312a2 100644
--- a/content/renderer/pepper/pepper_video_capture_host.h
+++ b/content/renderer/pepper/pepper_video_capture_host.h
@@ -47,9 +47,6 @@
   virtual void OnFrameReady(
       media::VideoCapture* capture,
       const scoped_refptr<media::VideoFrame>& frame) OVERRIDE;
-  virtual void OnDeviceInfoReceived(
-      media::VideoCapture* capture,
-      const media::VideoCaptureParams& device_info) OVERRIDE;
 
  private:
   int32_t OnOpen(ppapi::host::HostMessageContext* context,
@@ -64,6 +61,9 @@
 
   int32_t StopCapture();
   int32_t Close();
+  void PostErrorReply();
+  void AllocBuffers(const gfx::Size& resolution,
+                    int frame_rate);
   void ReleaseBuffers();
   void SendStatus();
 
@@ -88,10 +88,11 @@
 
   RendererPpapiHostImpl* renderer_ppapi_host_;
 
+  gfx::Size alloc_size_;
   std::vector<BufferInfo> buffers_;
   size_t buffer_count_hint_;
 
-  media::VideoCaptureCapability capability_;
+  media::VideoCaptureParams video_capture_params_;
 
   PP_VideoCaptureStatus_Dev status_;
 
diff --git a/content/renderer/pepper/ppb_image_data_impl.cc b/content/renderer/pepper/ppb_image_data_impl.cc
index 9ea83d5..57cdc92 100644
--- a/content/renderer/pepper/ppb_image_data_impl.cc
+++ b/content/renderer/pepper/ppb_image_data_impl.cc
@@ -198,7 +198,7 @@
       skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true);
 
   // Our platform bitmaps are set to opaque by default, which we don't want.
-  const_cast<SkBitmap&>(bitmap).setIsOpaque(false);
+  const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
 
   bitmap.lockPixels();
   return bitmap.getAddr32(0, 0);
@@ -273,7 +273,7 @@
     shared_memory_->Map(skia_bitmap_.getSize());
     skia_bitmap_.setPixels(shared_memory_->memory());
     // Our platform bitmaps are set to opaque by default, which we don't want.
-    skia_bitmap_.setIsOpaque(false);
+    skia_bitmap_.setAlphaType(kPremul_SkAlphaType);
     skia_canvas_.reset(new SkCanvas(skia_bitmap_));
     return skia_bitmap_.getAddr32(0, 0);
   }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 91475d3..a414e41 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4,6 +4,9 @@
 
 #include "content/renderer/render_frame_impl.h"
 
+#include <map>
+#include <string>
+
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -11,6 +14,7 @@
 #include "content/child/plugin_messages.h"
 #include "content/child/quota_dispatcher.h"
 #include "content/child/request_extra_data.h"
+#include "content/child/service_worker/web_service_worker_provider_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/socket_stream_handle_data.h"
 #include "content/common/swapped_out_messages.h"
@@ -60,6 +64,7 @@
 using WebKit::WebReferrerPolicy;
 using WebKit::WebSearchableFormData;
 using WebKit::WebSecurityOrigin;
+using WebKit::WebServiceWorkerProvider;
 using WebKit::WebStorageQuotaCallbacks;
 using WebKit::WebString;
 using WebKit::WebURL;
@@ -168,34 +173,6 @@
 #endif  // defined(ENABLE_PLUGINS)
 }
 
-WebKit::WebSharedWorker* RenderFrameImpl::createSharedWorker(
-    WebKit::WebFrame* frame,
-    const WebKit::WebURL& url,
-    const WebKit::WebString& name,
-    unsigned long long document_id) {
-  int route_id = MSG_ROUTING_NONE;
-  bool exists = false;
-  bool url_mismatch = false;
-  ViewHostMsg_CreateWorker_Params params;
-  params.url = url;
-  params.name = name;
-  params.document_id = document_id;
-  params.render_view_route_id = render_view_->GetRoutingID();
-  params.route_id = MSG_ROUTING_NONE;
-  params.script_resource_appcache_id = 0;
-  render_view_->Send(new ViewHostMsg_LookupSharedWorker(
-      params, &exists, &route_id, &url_mismatch));
-  if (url_mismatch) {
-    return NULL;
-  } else {
-    return new WebSharedWorkerProxy(RenderThreadImpl::current(),
-                                    document_id,
-                                    exists,
-                                    route_id,
-                                    render_view_->GetRoutingID());
-  }
-}
-
 WebKit::WebMediaPlayer* RenderFrameImpl::createMediaPlayer(
     WebKit::WebFrame* frame,
     const WebKit::WebURL& url,
@@ -220,6 +197,16 @@
   return render_view_->cookieJar(frame);
 }
 
+WebKit::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider(
+    WebKit::WebFrame* frame,
+    WebKit::WebServiceWorkerProviderClient* client) {
+  return new WebServiceWorkerProviderImpl(
+      ChildThread::current()->thread_safe_sender(),
+      ChildThread::current()->service_worker_message_filter(),
+      GURL(frame->document().securityOrigin().toString()),
+      make_scoped_ptr(client));
+}
+
 void RenderFrameImpl::didAccessInitialDocument(WebKit::WebFrame* frame) {
   render_view_->didAccessInitialDocument(frame);
 }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 78e75b0..0033457 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -40,11 +40,6 @@
   virtual WebKit::WebPlugin* createPlugin(
       WebKit::WebFrame* frame,
       const WebKit::WebPluginParams& params);
-  virtual WebKit::WebSharedWorker* createSharedWorker(
-      WebKit::WebFrame* frame,
-      const WebKit::WebURL& url,
-      const WebKit::WebString& name,
-      unsigned long long document_id);
   virtual WebKit::WebMediaPlayer* createMediaPlayer(
       WebKit::WebFrame* frame,
       const WebKit::WebURL& url,
@@ -53,6 +48,9 @@
       WebKit::WebFrame* frame,
       WebKit::WebApplicationCacheHostClient* client);
   virtual WebKit::WebCookieJar* cookieJar(WebKit::WebFrame* frame);
+  virtual WebKit::WebServiceWorkerProvider* createServiceWorkerProvider(
+      WebKit::WebFrame* frame,
+      WebKit::WebServiceWorkerProviderClient*);
   virtual void didAccessInitialDocument(WebKit::WebFrame* frame);
   virtual WebKit::WebFrame* createChildFrame(WebKit::WebFrame* parent,
                                              const WebKit::WebString& name);
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 4f719e3..266276e 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -44,7 +44,9 @@
 #include "content/common/dom_storage/dom_storage_messages.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
 #include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/resource_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_constants.h"
@@ -102,7 +104,6 @@
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebScriptController.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
-#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/layout.h"
 #include "ui/base/ui_base_switches.h"
@@ -636,8 +637,6 @@
 
   webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl);
   WebKit::initialize(webkit_platform_support_.get());
-  WebKit::setSharedWorkerRepository(
-      webkit_platform_support_.get()->sharedWorkerRepository());
 
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
 
@@ -869,24 +868,28 @@
 RenderThreadImpl::GetGpuFactories() {
   DCHECK(IsMainThread());
 
+  scoped_refptr<GpuChannelHost> gpu_channel_host = GetGpuChannel();
   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
   scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories;
   if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
     if (!gpu_va_context_provider_ ||
         gpu_va_context_provider_->DestroyedOnMainThread()) {
+      if (!gpu_channel_host) {
+        gpu_channel_host = EstablishGpuChannelSync(
+            CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
+      }
       gpu_va_context_provider_ = ContextProviderCommandBuffer::Create(
           make_scoped_ptr(
               WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-                  this,
+                  gpu_channel_host.get(),
                   WebKit::WebGraphicsContext3D::Attributes(),
                   GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D"))),
           "GPU-VideoAccelerator-Offscreen");
     }
   }
-  GpuChannelHost* gpu_channel_host = GetGpuChannel();
   if (gpu_channel_host) {
     gpu_factories = new RendererGpuVideoAcceleratorFactories(
-        gpu_channel_host, gpu_va_context_provider_);
+        gpu_channel_host.get(), gpu_va_context_provider_);
   }
   return gpu_factories;
 }
@@ -900,9 +903,11 @@
   attributes.antialias = false;
   attributes.noAutomaticFlushes = true;
 
+  scoped_refptr<GpuChannelHost> gpu_channel_host(EstablishGpuChannelSync(
+      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
   return make_scoped_ptr(
       WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-          this,
+          gpu_channel_host.get(),
           attributes,
           GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext3d")));
 }
@@ -1052,6 +1057,47 @@
   NOTREACHED();
 }
 
+scoped_ptr<gfx::GpuMemoryBuffer> RenderThreadImpl::AllocateGpuMemoryBuffer(
+    size_t width,
+    size_t height,
+    unsigned internalformat) {
+  if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  size_t size = width * height *
+      GpuMemoryBufferImpl::BytesPerPixel(internalformat);
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  gfx::GpuMemoryBufferHandle handle;
+  bool success;
+  IPC::Message* message =
+      new ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer(size, &handle);
+
+  // Allow calling this from the compositor thread.
+  if (base::MessageLoop::current() == message_loop())
+    success = ChildThread::Send(message);
+  else
+    success = sync_message_filter()->Send(message);
+
+  if (!success)
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  // Currently, shared memory is the only supported buffer type.
+  if (handle.type != gfx::SHARED_MEMORY_BUFFER)
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  if (!base::SharedMemory::IsHandleValid(handle.handle))
+    return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+  return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+      new GpuMemoryBufferImpl(
+          make_scoped_ptr(new base::SharedMemory(handle.handle, false)),
+          width,
+          height,
+          internalformat));
+}
+
 void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() {
   suspend_webkit_shared_timer_ = false;
 }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index b2e7e9b..b0c0317 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -18,7 +18,6 @@
 #include "content/child/child_thread.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
 #include "ipc/ipc_channel_proxy.h"
@@ -163,7 +162,7 @@
   // established or if it has been lost (for example if the GPU plugin crashed).
   // If there is a pending asynchronous request, it will be completed by the
   // time this routine returns.
-  virtual GpuChannelHost* EstablishGpuChannelSync(CauseForGpuLaunch) OVERRIDE;
+  GpuChannelHost* EstablishGpuChannelSync(CauseForGpuLaunch);
 
 
   // These methods modify how the next message is sent.  Normally, when sending
@@ -364,6 +363,10 @@
       int32 image_id,
       const CreateImageCallback& callback) OVERRIDE;
   virtual void DeleteImage(int32 image_id, int32 sync_point) OVERRIDE;
+  virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat) OVERRIDE;
 
   void Init();
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 7139a50..195f694 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1991,7 +1991,14 @@
   TestContentRendererClient client_;
 };
 
-TEST_F(SuppressErrorPageTest, Suppresses) {
+#if defined(OS_ANDROID)
+// Crashing on Android: http://crbug.com/311341
+#define MAYBE_Suppresses DISABLED_Suppresses
+#else
+#define MAYBE_Suppresses Suppresses
+#endif
+
+TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
   WebURLError error;
   error.domain = WebString::fromUTF8(net::kErrorDomain);
   error.reason = net::ERR_FILE_NOT_FOUND;
@@ -2012,7 +2019,14 @@
   EXPECT_EQ("", UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
 }
 
-TEST_F(SuppressErrorPageTest, DoesNotSuppress) {
+#if defined(OS_ANDROID)
+// Crashing on Android: http://crbug.com/311341
+#define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
+#else
+#define MAYBE_DoesNotSuppress DoesNotSuppress
+#endif
+
+TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
   WebURLError error;
   error.domain = WebString::fromUTF8(net::kErrorDomain);
   error.reason = net::ERR_FILE_NOT_FOUND;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index d123997..022fcf3 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -116,7 +116,9 @@
 #include "content/renderer/renderer_date_time_picker.h"
 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
 #include "content/renderer/renderer_webcolorchooser_impl.h"
+#include "content/renderer/resizing_mode_selector.h"
 #include "content/renderer/savable_resources.h"
+#include "content/renderer/shared_worker_repository.h"
 #include "content/renderer/speech_recognition_dispatcher.h"
 #include "content/renderer/stats_collection_controller.h"
 #include "content/renderer/stats_collection_observer.h"
@@ -218,7 +220,6 @@
 #include "content/renderer/media/android/renderer_media_player_manager.h"
 #include "content/renderer/media/android/stream_texture_factory_android_impl.h"
 #include "content/renderer/media/android/webmediaplayer_android.h"
-#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
@@ -315,7 +316,6 @@
 using WebKit::WebSecurityPolicy;
 using WebKit::WebSerializedScriptValue;
 using WebKit::WebSettings;
-using WebKit::WebSharedWorker;
 using WebKit::WebSize;
 using WebKit::WebSocketStreamHandle;
 using WebKit::WebStorageNamespace;
@@ -860,12 +860,11 @@
       devtools_agent_(NULL),
       accessibility_mode_(AccessibilityModeOff),
       renderer_accessibility_(NULL),
-      java_bridge_dispatcher_(NULL),
       mouse_lock_dispatcher_(NULL),
 #if defined(OS_ANDROID)
       body_background_color_(SK_ColorWHITE),
       expected_content_intent_id_(0),
-      media_player_proxy_(NULL),
+      media_player_manager_(NULL),
 #endif
 #if defined(OS_WIN)
       focused_plugin_id_(-1),
@@ -982,8 +981,11 @@
   new TextInputClientObserver(this);
 #endif  // defined(OS_MACOSX)
 
+  new SharedWorkerRepository(this);
+
 #if defined(OS_ANDROID)
-  media_player_manager_.reset(new RendererMediaPlayerManager());
+  media_player_manager_ = new RendererMediaPlayerManager(this);
+  new JavaBridgeDispatcher(this);
 #endif
 
   // The next group of objects all implement RenderViewObserver, so are deleted
@@ -1454,11 +1456,12 @@
     IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune,
                         OnSetHistoryLengthAndPrune)
     IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
-#if defined(OS_ANDROID)
-    IPC_MESSAGE_HANDLER(JavaBridgeMsg_Init, OnJavaBridgeInit)
-#endif
     IPC_MESSAGE_HANDLER(ViewMsg_SetAccessibilityMode, OnSetAccessibilityMode)
     IPC_MESSAGE_HANDLER(ViewMsg_DisownOpener, OnDisownOpener)
+    IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupDIB,
+                        OnReleaseDisambiguationPopupDIB)
+    IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted,
+                        OnWindowSnapshotCompleted)
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(InputMsg_ActivateNearestFindResult,
                         OnActivateNearestFindResult)
@@ -1478,10 +1481,8 @@
     IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
     IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
 #endif
-    IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupDIB,
-                        OnReleaseDisambiguationPopupDIB)
-    IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted,
-                        OnWindowSnapshotCompleted)
+    // Adding a new message? Add platform independent ones first, then put the
+    // platform specific ones at the end.
 
     // Have the super handle all other messages.
     IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
@@ -2115,8 +2116,13 @@
     // Send the user agent override back.
     params.is_overriding_user_agent = internal_data->is_overriding_user_agent();
 
-    // Track the URL of the original request.
-    params.original_request_url = original_request.url();
+    // Track the URL of the original request.  We use the first entry of the
+    // redirect chain if it exists because the chain may have started in another
+    // process.
+    if (params.redirects.size() > 0)
+      params.original_request_url = params.redirects.at(0);
+    else
+      params.original_request_url = original_request.url();
 
     params.history_list_was_cleared =
         navigation_state->history_list_was_cleared();
@@ -2469,6 +2475,7 @@
       log_severity = logging::LOG_VERBOSE;
       break;
     case WebConsoleMessage::LevelLog:
+    case WebConsoleMessage::LevelInfo:
       log_severity = logging::LOG_INFO;
       break;
     case WebConsoleMessage::LevelWarning:
@@ -3112,18 +3119,12 @@
         context_provider->Context3d(), gpu_channel_host, routing_id_));
   }
 
-  if (!media_player_proxy_) {
-    media_player_proxy_ = new WebMediaPlayerProxyAndroid(
-        this, media_player_manager_.get());
-  }
-
   scoped_ptr<WebMediaPlayerAndroid> web_media_player_android(
       new WebMediaPlayerAndroid(
           frame,
           client,
           AsWeakPtr(),
-          media_player_manager_.get(),
-          media_player_proxy_,
+          media_player_manager_,
           stream_texture_factory.release(),
           RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(),
           new RenderMediaLog()));
@@ -3462,6 +3463,15 @@
 void RenderViewImpl::didCreateDataSource(WebFrame* frame, WebDataSource* ds) {
   bool content_initiated = !pending_navigation_params_.get();
 
+  // Make sure any previous redirect URLs end up in our new data source.
+  if (pending_navigation_params_.get()) {
+    for (std::vector<GURL>::const_iterator i =
+             pending_navigation_params_->redirects.begin();
+         i != pending_navigation_params_->redirects.end(); ++i) {
+      ds->appendRedirect(*i);
+    }
+  }
+
   DocumentState* document_state = DocumentState::FromDataSource(ds);
   if (!document_state) {
     document_state = new DocumentState;
@@ -3606,10 +3616,6 @@
 void RenderViewImpl::ProcessViewLayoutFlags(const CommandLine& command_line) {
   bool enable_viewport =
       command_line.HasSwitch(switches::kEnableViewport);
-  bool enable_fixed_layout =
-      command_line.HasSwitch(switches::kEnableFixedLayout);
-
-  webview()->enableFixedLayoutMode(enable_fixed_layout || enable_viewport);
 
   // If viewport tag is enabled, then the WebKit side will take care
   // of setting the fixed layout size and page scale limits.
@@ -3619,18 +3625,6 @@
   // When navigating to a new page, reset the page scale factor to be 1.0.
   webview()->setInitialPageScaleOverride(1.f);
 
-  if (enable_fixed_layout) {
-    std::string str =
-        command_line.GetSwitchValueASCII(switches::kEnableFixedLayout);
-    std::vector<std::string> tokens;
-    base::SplitString(str, ',', &tokens);
-    if (tokens.size() == 2) {
-      int width, height;
-      if (base::StringToInt(tokens[0], &width) &&
-          base::StringToInt(tokens[1], &height))
-        webview()->setFixedLayoutSize(WebSize(width, height));
-    }
-  }
   float maxPageScaleFactor =
       command_line.HasSwitch(switches::kEnablePinch) ? 4.f : 1.f ;
   webview()->setPageScaleFactorLimits(1, maxPageScaleFactor);
@@ -5281,12 +5275,6 @@
 #endif  // defined(TOOLKIT_GTK)
 
     if (webview()) {
-#if defined(TOOLKIT_GTK)
-      webview()->setScrollbarColors(
-          renderer_prefs.thumb_inactive_color,
-          renderer_prefs.thumb_active_color,
-          renderer_prefs.track_color);
-#endif  // defined(TOOLKIT_GTK)
       webview()->setSelectionColors(
           renderer_prefs.active_selection_bg_color,
           renderer_prefs.active_selection_fg_color,
@@ -5320,6 +5308,7 @@
 }
 
 void RenderViewImpl::OnOrientationChangeEvent(int orientation) {
+  // Screen has rotated. 0 = default (portrait), 90 = one turn right, and so on.
   FOR_EACH_OBSERVER(RenderViewObserver,
                     observers_,
                     OrientationChangeEvent(orientation));
@@ -6438,13 +6427,6 @@
   main_frame->enableViewSourceMode(true);
 }
 
-#if defined(OS_ANDROID)
-void RenderViewImpl::OnJavaBridgeInit() {
-  DCHECK(!java_bridge_dispatcher_);
-  java_bridge_dispatcher_ = new JavaBridgeDispatcher(this);
-}
-#endif
-
 void RenderViewImpl::OnDisownOpener() {
   if (!webview())
     return;
@@ -6557,6 +6539,18 @@
   OnResize(params);
 }
 
+void RenderViewImpl::ForceResizeForTesting(const gfx::Size& new_size) {
+  gfx::Rect new_position(rootWindowRect().x,
+                         rootWindowRect().y,
+                         new_size.width(),
+                         new_size.height());
+  ResizeSynchronously(new_position);
+}
+
+void RenderViewImpl::UseSynchronousResizeModeForTesting(bool enable) {
+  resizing_mode_selector_->set_is_synchronous_mode(enable);
+}
+
 void RenderViewImpl::EnableAutoResizeForTesting(const gfx::Size& min_size,
                                                 const gfx::Size& max_size) {
   OnEnableAutoResize(min_size, max_size);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 6cf59f3..ccfd1b5 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -236,12 +236,6 @@
 
   RendererWebCookieJarImpl* cookie_jar() { return &cookie_jar_; }
 
-#if defined(OS_ANDROID)
-  RendererMediaPlayerManager* media_player_manager() {
-    return media_player_manager_.get();
-  }
-#endif
-
   // Lazily initialize this view's BrowserPluginManager and return it.
   BrowserPluginManager* GetBrowserPluginManager();
 
@@ -387,6 +381,11 @@
   // Change the device scale factor and force the compositor to resize.
   void SetDeviceScaleFactorForTesting(float factor);
 
+  // Used to force the size of a window when running layout tests.
+  void ForceResizeForTesting(const gfx::Size& new_size);
+
+  void UseSynchronousResizeModeForTesting(bool enable);
+
   // Control autoresize mode.
   void EnableAutoResizeForTesting(const gfx::Size& min_size,
                                   const gfx::Size& max_size);
@@ -919,7 +918,6 @@
   void OnSetEditCommandsForNextKeyEvent(const EditCommands& edit_commands);
   void OnUndo();
   void OnUnselect();
-
   void OnAllowBindings(int enabled_bindings_flags);
   void OnAllowScriptToClose(bool script_can_close);
   void OnCancelDownload(int32 download_id);
@@ -970,10 +968,7 @@
       const base::FilePath& local_directory_name);
   void OnMediaPlayerActionAt(const gfx::Point& location,
                              const WebKit::WebMediaPlayerAction& action);
-
-  // Screen has rotated. 0 = default (portrait), 90 = one turn right, and so on.
   void OnOrientationChangeEvent(int orientation);
-
   void OnPluginActionAt(const gfx::Point& location,
                         const WebKit::WebPluginAction& action);
   void OnMoveOrResizeStarted();
@@ -1010,16 +1005,12 @@
   void OnUpdateTargetURLAck();
   void OnUpdateTimezone();
   void OnUpdateWebPreferences(const WebPreferences& prefs);
-
   void OnZoom(PageZoom zoom);
   void OnZoomFactor(PageZoom zoom, int zoom_center_x, int zoom_center_y);
-
   void OnEnableViewSourceMode();
-
-  void OnJavaBridgeInit();
-
   void OnDisownOpener();
-
+  void OnWindowSnapshotCompleted(const int snapshot_id,
+      const gfx::Size& size, const std::vector<unsigned char>& png);
 #if defined(OS_ANDROID)
   void OnActivateNearestFindResult(int request_id, float x, float y);
   void OnFindMatchRects(int current_version);
@@ -1041,10 +1032,6 @@
                             const gfx::Rect& view_frame);
 #endif
 
-  void OnWindowSnapshotCompleted(const int snapshot_id,
-      const gfx::Size& size, const std::vector<unsigned char>& png);
-
-
   // Adding a new message handler? Please add it in alphabetical order above
   // and put it in the same position in the .cc file.
 
@@ -1419,9 +1406,6 @@
   // AccessibilityModeOff.
   RendererAccessibility* renderer_accessibility_;
 
-  // Java Bridge dispatcher attached to this view; lazily initialized.
-  JavaBridgeDispatcher* java_bridge_dispatcher_;
-
   // Mouse Lock dispatcher attached to this view.
   MouseLockDispatcher* mouse_lock_dispatcher_;
 
@@ -1441,12 +1425,9 @@
   typedef std::vector< linked_ptr<ContentDetector> > ContentDetectorList;
   ContentDetectorList content_detectors_;
 
-  // Proxy class for WebMediaPlayer to communicate with the real media player
-  // objects in browser process.
-  WebMediaPlayerProxyAndroid* media_player_proxy_;
-
-  // The media player manager for managing all the media players on this view.
-  scoped_ptr<RendererMediaPlayerManager> media_player_manager_;
+  // The media player manager for managing all the media players on this view
+  // for communicating with the real media player objects in browser process.
+  RendererMediaPlayerManager* media_player_manager_;
 
   // A date/time picker object for date and time related input elements.
   scoped_ptr<RendererDateTimePicker> date_time_picker_client_;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index c9eb7c8..5cd8cde 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -22,6 +22,7 @@
 #include "content/child/npapi/webplugin.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/input/web_input_event_traits.h"
 #include "content/common/input_messages.h"
 #include "content/common/swapped_out_messages.h"
@@ -40,6 +41,7 @@
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "content/renderer/resizing_mode_selector.h"
 #include "ipc/ipc_sync_message.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
@@ -55,6 +57,7 @@
 #include "third_party/WebKit/public/web/WebScreenInfo.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "ui/base/ui_base_switches.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/gfx/skia_util.h"
@@ -140,6 +143,12 @@
   return it->second;
 }
 
+// TODO(brianderson): Replace the hard-coded threshold with a fraction of
+// the BeginMainFrame interval.
+// 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to
+// be spent in input hanlders before input starts getting throttled.
+const int kInputHandlingTimeThrottlingThresholdMicroseconds = 4166;
+
 }  // namespace
 
 namespace content {
@@ -356,6 +365,7 @@
       outstanding_ime_acks_(0),
 #endif
       popup_origin_scale_for_emulation_(0.f),
+      resizing_mode_selector_(new ResizingModeSelector()),
       weak_ptr_factory_(this) {
   if (!swapped_out)
     RenderProcess::current()->AddRefProcess();
@@ -627,8 +637,7 @@
                           const gfx::Rect& resizer_rect,
                           bool is_fullscreen,
                           ResizeAck resize_ack) {
-  if (!RenderThreadImpl::current() ||  // Will be NULL during unit tests.
-      !RenderThreadImpl::current()->layout_test_mode()) {
+  if (!resizing_mode_selector_->is_synchronous_mode()) {
     // A resize ack shouldn't be requested if we have not ACK'd the previous
     // one.
     DCHECK(resize_ack != SEND_RESIZE_ACK || !next_paint_is_resize_ack());
@@ -667,14 +676,12 @@
     // send an ACK if we are resized to a non-empty rect.
     webwidget_->resize(new_size);
 
-    if (!RenderThreadImpl::current() ||  // Will be NULL during unit tests.
-        !RenderThreadImpl::current()->layout_test_mode()) {
+    if (!resizing_mode_selector_->is_synchronous_mode()) {
       // Resize should have caused an invalidation of the entire view.
       DCHECK(new_size.IsEmpty() || is_accelerated_compositing_active_ ||
              paint_aggregator_.HasPendingUpdate());
     }
-  } else if (!RenderThreadImpl::current() ||  // Will be NULL during unit tests.
-             !RenderThreadImpl::current()->layout_test_mode()) {
+  } else if (!resizing_mode_selector_->is_synchronous_mode()) {
     resize_ack = NO_RESIZE_ACK;
   }
 
@@ -696,6 +703,15 @@
   DCHECK(resize_ack != SEND_RESIZE_ACK || next_paint_is_resize_ack());
 }
 
+void RenderWidget::ResizeSynchronously(const gfx::Rect& new_position) {
+  Resize(new_position.size(), new_position.size(), overdraw_bottom_height_,
+         gfx::Rect(), is_fullscreen_, NO_RESIZE_ACK);
+  view_screen_rect_ = new_position;
+  window_screen_rect_ = new_position;
+  if (!did_show_)
+    initial_pos_ = new_position;
+}
+
 void RenderWidget::OnClose() {
   if (closing_)
     return;
@@ -726,6 +742,9 @@
 }
 
 void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) {
+  if (resizing_mode_selector_->ShouldAbortOnResize(this, params))
+    return;
+
   if (screen_metrics_emulator_) {
     screen_metrics_emulator_->OnResizeMessage(params);
     return;
@@ -1026,6 +1045,10 @@
     return;
   }
 
+  base::TimeTicks start_time;
+  if (base::TimeTicks::IsHighResNowFastAndReliable())
+    start_time = base::TimeTicks::HighResNow();
+
   const char* const event_name =
       WebInputEventTraits::GetName(input_event->type);
   TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent",
@@ -1105,7 +1128,7 @@
                                             input_event->type,
                                             ack_result,
                                             latency_info);
-  bool event_type_gets_rate_limited =
+  bool event_type_can_be_rate_limited =
       input_event->type == WebInputEvent::MouseMove ||
       input_event->type == WebInputEvent::MouseWheel ||
       input_event->type == WebInputEvent::TouchMove;
@@ -1113,12 +1136,27 @@
   bool frame_pending = paint_aggregator_.HasPendingUpdate();
   if (is_accelerated_compositing_active_) {
     frame_pending = compositor_ &&
-                    compositor_->commitRequested();
+                    compositor_->BeginMainFrameRequested();
   }
 
-  if (event_type_gets_rate_limited && frame_pending && !is_hidden_) {
+  // If we don't have a fast and accurate HighResNow, we assume the input
+  // handlers are heavy and rate limit them.
+  bool rate_limiting_wanted = true;
+  if (base::TimeTicks::IsHighResNowFastAndReliable()) {
+      base::TimeTicks end_time = base::TimeTicks::HighResNow();
+      total_input_handling_time_this_frame_ += (end_time - start_time);
+      rate_limiting_wanted =
+          total_input_handling_time_this_frame_.InMicroseconds() >
+          kInputHandlingTimeThrottlingThresholdMicroseconds;
+  }
+
+  if (rate_limiting_wanted && event_type_can_be_rate_limited &&
+      frame_pending && !is_hidden_) {
     // We want to rate limit the input events in this case, so we'll wait for
     // painting to finish before ACKing this message.
+    TRACE_EVENT_INSTANT0("renderer",
+      "RenderWidget::OnHandleInputEvent ack throttled",
+      TRACE_EVENT_SCOPE_THREAD);
     if (pending_input_event_ack_) {
       // As two different kinds of events could cause us to postpone an ack
       // we send it now, if we have one pending. The Browser should never
@@ -1374,11 +1412,15 @@
   DoDeferredUpdateAndSendInputAck();
 }
 
-void RenderWidget::DoDeferredUpdateAndSendInputAck() {
-  DoDeferredUpdate();
-
+void RenderWidget::FlushPendingInputEventAck() {
   if (pending_input_event_ack_)
     Send(pending_input_event_ack_.release());
+  total_input_handling_time_this_frame_ = base::TimeDelta();
+}
+
+void RenderWidget::DoDeferredUpdateAndSendInputAck() {
+  DoDeferredUpdate();
+  FlushPendingInputEventAck();
 }
 
 void RenderWidget::DoDeferredUpdate() {
@@ -1411,7 +1453,7 @@
   }
 
   // Tracking of frame rate jitter
-  base::TimeTicks frame_begin_ticks = base::TimeTicks::Now();
+  base::TimeTicks frame_begin_ticks = gfx::FrameTime::Now();
   InstrumentWillBeginFrame();
   AnimateIfNeeded();
 
@@ -1600,8 +1642,7 @@
   // UpdateReply message so we can receive another input event before the
   // UpdateRect_ACK on platforms where the UpdateRect_ACK is sent from within
   // the UpdateRect IPC message handler.
-  if (pending_input_event_ack_)
-    Send(pending_input_event_ack_.release());
+  FlushPendingInputEventAck();
 
   // If Composite() called SwapBuffers, pending_update_params_ will be reset (in
   // OnSwapBuffersPosted), meaning a message has been added to the
@@ -1714,7 +1755,7 @@
     // with invalid damage rects.
     paint_aggregator_.ClearPendingUpdate();
 
-    if (RenderThreadImpl::current()->layout_test_mode()) {
+    if (resizing_mode_selector_->is_synchronous_mode()) {
       WebRect new_pos(rootWindowRect().x,
                       rootWindowRect().y,
                       new_size.width,
@@ -1725,7 +1766,7 @@
 
     AutoResizeCompositor();
 
-    if (!RenderThreadImpl::current()->layout_test_mode())
+    if (!resizing_mode_selector_->is_synchronous_mode())
       need_update_rect_for_auto_resize_ = true;
   }
 }
@@ -1820,8 +1861,7 @@
 
 void RenderWidget::didBecomeReadyForAdditionalInput() {
   TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput");
-  if (pending_input_event_ack_)
-    Send(pending_input_event_ack_.release());
+  FlushPendingInputEventAck();
 }
 
 void RenderWidget::DidCommitCompositorFrame() {
@@ -1977,7 +2017,7 @@
         (pos.y - popup_view_origin_for_emulation_.y()) * scale;
   }
 
-  if (!RenderThreadImpl::current()->layout_test_mode()) {
+  if (!resizing_mode_selector_->is_synchronous_mode()) {
     if (did_show_) {
       Send(new ViewHostMsg_RequestMove(routing_id_, pos));
       SetPendingWindowRect(pos);
@@ -1985,13 +2025,7 @@
       initial_pos_ = pos;
     }
   } else {
-    WebSize new_size(pos.width, pos.height);
-    Resize(new_size, new_size, overdraw_bottom_height_,
-           WebRect(), is_fullscreen_, NO_RESIZE_ACK);
-    view_screen_rect_ = pos;
-    window_screen_rect_ = pos;
-    if (!did_show_)
-      initial_pos_ = pos;
+    ResizeSynchronously(pos);
   }
 }
 
@@ -2745,13 +2779,15 @@
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableGpuCompositing))
     return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
-      new WebGraphicsContext3DCommandBufferImpl(
-          surface_id(),
-          GetURLForGraphicsContext3D(),
-          RenderThreadImpl::current(),
-          weak_ptr_factory_.GetWeakPtr()));
+  if (!RenderThreadImpl::current())
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+  scoped_refptr<GpuChannelHost> gpu_channel_host(
+      RenderThreadImpl::current()->EstablishGpuChannelSync(
+          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
+  if (!gpu_channel_host)
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
 
+  WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
 #if defined(OS_ANDROID)
   // If we raster too fast we become upload bound, and pending
   // uploads consume memory. For maximum upload throughput, we would
@@ -2771,22 +2807,24 @@
   static const size_t kBytesPerMegabyte = 1024 * 1024;
   // We keep the MappedMemoryReclaimLimit the same as the upload limit
   // to avoid unnecessarily stalling the compositor thread.
-  const size_t mapped_memory_reclaim_limit =
+  limits.mapped_memory_reclaim_limit =
       max_transfer_buffer_usage_mb * kBytesPerMegabyte;
-#else
-  const size_t mapped_memory_reclaim_limit =
-      WebGraphicsContext3DCommandBufferImpl::kNoLimit;
 #endif
-  if (!context->Initialize(
+
+  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
+
+  if (!is_threaded_compositing_enabled_)
+    swap_client = weak_ptr_factory_.GetWeakPtr();
+
+  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
+      new WebGraphicsContext3DCommandBufferImpl(
+          surface_id(),
+          GetURLForGraphicsContext3D(),
+          gpu_channel_host.get(),
+          swap_client,
           attributes,
           false /* bind generates resources */,
-          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
-          kDefaultCommandBufferSize,
-          kDefaultStartTransferBufferSize,
-          kDefaultMinTransferBufferSize,
-          kDefaultMaxTransferBufferSize,
-          mapped_memory_reclaim_limit))
-    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+          limits));
   return context.Pass();
 }
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index fb6fbf4..85e7eb9 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -68,6 +68,7 @@
 class PepperPluginInstanceImpl;
 class RenderWidgetCompositor;
 class RenderWidgetTest;
+class ResizingModeSelector;
 struct ContextMenuParams;
 struct GpuRenderingStats;
 struct WebPluginGeometry;
@@ -291,6 +292,7 @@
   void AnimationCallback();
   void AnimateIfNeeded();
   void InvalidationCallback();
+  void FlushPendingInputEventAck();
   void DoDeferredUpdateAndSendInputAck();
   void DoDeferredUpdate();
   void DoDeferredClose();
@@ -309,6 +311,8 @@
               const gfx::Rect& resizer_rect,
               bool is_fullscreen,
               ResizeAck resize_ack);
+  // Used to force the size of a window when running layout tests.
+  void ResizeSynchronously(const gfx::Rect& new_position);
   virtual void SetScreenMetricsEmulationParameters(
       float device_scale_factor, float root_layer_scale);
   void SetExternalPopupOriginAdjustmentsForEmulation(
@@ -710,6 +714,9 @@
 
   scoped_ptr<IPC::Message> pending_input_event_ack_;
 
+  // The time spent in input handlers this frame. Used to throttle input acks.
+  base::TimeDelta total_input_handling_time_this_frame_;
+
   // Indicates if the next sequence of Char events should be suppressed or not.
   bool suppress_next_char_events_;
 
@@ -783,6 +790,8 @@
   gfx::Point popup_screen_origin_for_emulation_;
   float popup_origin_scale_for_emulation_;
 
+  scoped_ptr<ResizingModeSelector> resizing_mode_selector_;
+
   base::WeakPtrFactory<RenderWidget> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidget);
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc
index 30f2ed9..405b545 100644
--- a/content/renderer/render_widget_fullscreen_pepper.cc
+++ b/content/renderer/render_widget_fullscreen_pepper.cc
@@ -406,7 +406,8 @@
   bool compositing = !!layer_;
   if (compositing != is_accelerated_compositing_active_) {
     if (compositing) {
-      initializeLayerTreeView();
+      if (!layerTreeView())
+        initializeLayerTreeView();
       if (!layerTreeView())
         return;
       layer_->setBounds(WebKit::WebSize(size()));
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc
index fce9f2b..6f7dd05 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.cc
+++ b/content/renderer/renderer_webkitplatformsupport_impl.cc
@@ -25,7 +25,9 @@
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/file_utilities_messages.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/mime_registry_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_switches.h"
@@ -45,7 +47,6 @@
 #include "content/renderer/renderer_clipboard_client.h"
 #include "content/renderer/webclipboard_impl.h"
 #include "content/renderer/webcrypto/webcrypto_impl.h"
-#include "content/renderer/websharedworkerrepository_impl.h"
 #include "gpu/config/gpu_info.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "media/audio/audio_output_device.h"
@@ -203,7 +204,6 @@
       mime_registry_(new RendererWebKitPlatformSupportImpl::MimeRegistry),
       sudden_termination_disables_(0),
       plugin_refresh_allowed_(true),
-      shared_worker_repository_(new WebSharedWorkerRepositoryImpl),
       child_thread_loop_(base::MessageLoopProxy::current()) {
   if (g_sandbox_enabled && sandboxEnabled()) {
     sandbox_support_.reset(
@@ -217,6 +217,7 @@
     sync_message_filter_ = ChildThread::current()->sync_message_filter();
     thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
     quota_message_filter_ = ChildThread::current()->quota_message_filter();
+    blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_));
   }
 }
 
@@ -604,22 +605,6 @@
                                                  sync_message_filter_.get());
 }
 
-WebKit::WebSharedWorkerRepository*
-RendererWebKitPlatformSupportImpl::sharedWorkerRepository() {
-#if !defined(OS_ANDROID)
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableSharedWorkers)) {
-    return shared_worker_repository_.get();
-  } else {
-    return NULL;
-  }
-#else
-  // Shared workers are unsupported on Android. Returning NULL will prevent the
-  // window.SharedWorker constructor from being exposed. http://crbug.com/154571
-  return NULL;
-#endif
-}
-
 bool RendererWebKitPlatformSupportImpl::canAccelerate2dCanvas() {
   RenderThreadImpl* thread = RenderThreadImpl::current();
   GpuChannelHost* host = thread->EstablishGpuChannelSync(
@@ -842,9 +827,7 @@
 //------------------------------------------------------------------------------
 
 WebBlobRegistry* RendererWebKitPlatformSupportImpl::blobRegistry() {
-  // thread_safe_sender_ can be NULL when running some tests.
-  if (!blob_registry_.get() && thread_safe_sender_.get())
-    blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get()));
+  // blob_registry_ can be NULL when running some tests.
   return blob_registry_.get();
 }
 
@@ -936,8 +919,14 @@
 WebKit::WebGraphicsContext3D*
 RendererWebKitPlatformSupportImpl::createOffscreenGraphicsContext3D(
     const WebKit::WebGraphicsContext3D::Attributes& attributes) {
+  if (!RenderThreadImpl::current())
+    return NULL;
+
+  scoped_refptr<GpuChannelHost> gpu_channel_host(
+      RenderThreadImpl::current()->EstablishGpuChannelSync(
+          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
   return WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
-      RenderThreadImpl::current(),
+      gpu_channel_host.get(),
       attributes,
       GURL(attributes.topDocumentURL));
 }
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.h b/content/renderer/renderer_webkitplatformsupport_impl.h
index 8378c34..1a55021 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.h
+++ b/content/renderer/renderer_webkitplatformsupport_impl.h
@@ -10,7 +10,6 @@
 #include "base/platform_file.h"
 #include "content/child/webkitplatformsupport_impl.h"
 #include "content/common/content_export.h"
-#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/WebKit/public/platform/WebIDBFactory.h"
 #include "webkit/renderer/compositor_bindings/web_compositor_support_impl.h"
@@ -42,7 +41,6 @@
 class WebClipboardImpl;
 class WebCryptoImpl;
 class WebFileSystemImpl;
-class WebSharedWorkerRepositoryImpl;
 
 class CONTENT_EXPORT RendererWebKitPlatformSupportImpl
     : public WebKitPlatformSupportImpl {
@@ -92,7 +90,6 @@
   virtual void screenColorProfile(WebKit::WebVector<char>* to_profile);
   virtual WebKit::WebIDBFactory* idbFactory();
   virtual WebKit::WebFileSystem* fileSystem();
-  virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
   virtual bool canAccelerate2dCanvas();
   virtual bool isThreadedCompositingEnabled();
   virtual double audioHardwareSampleRate();
@@ -196,10 +193,6 @@
   // If true, then a GetPlugins call is allowed to rescan the disk.
   bool plugin_refresh_allowed_;
 
-  // Implementation of the WebSharedWorkerRepository APIs (provides an interface
-  // to WorkerService on the browser thread.
-  scoped_ptr<WebSharedWorkerRepositoryImpl> shared_worker_repository_;
-
   scoped_ptr<WebKit::WebIDBFactory> web_idb_factory_;
 
   scoped_ptr<WebFileSystemImpl> web_file_system_;
diff --git a/content/renderer/resizing_mode_selector.cc b/content/renderer/resizing_mode_selector.cc
new file mode 100644
index 0000000..f5cc6ca
--- /dev/null
+++ b/content/renderer/resizing_mode_selector.cc
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/resizing_mode_selector.h"
+
+#include "content/common/view_messages.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_widget.h"
+#include "third_party/WebKit/public/web/WebScreenInfo.h"
+
+namespace content {
+
+ResizingModeSelector::ResizingModeSelector()
+    : is_synchronous_mode_(false) {
+  // TODO(dglazkov): Remove this re-initialization once the transition to
+  // useUnfortunateAsynchronousResizeMode is complete.
+  // See http://crbug.com/309760 for details.
+  is_synchronous_mode_ = RenderThreadImpl::current() &&
+      RenderThreadImpl::current()->layout_test_mode();
+}
+
+bool ResizingModeSelector::ShouldAbortOnResize(
+    RenderWidget* widget,
+    const ViewMsg_Resize_Params& params) {
+  return is_synchronous_mode_ &&
+      params.is_fullscreen == widget->is_fullscreen() &&
+      params.screen_info.deviceScaleFactor ==
+        widget->screenInfo().deviceScaleFactor;
+}
+
+void ResizingModeSelector::set_is_synchronous_mode(bool mode) {
+  // TODO(dglazkov): Actually set is_synchronous_mode_ once the transition to
+  // useUnfortunateAsynchronousResizeMode is complete.
+}
+
+bool ResizingModeSelector::is_synchronous_mode() const {
+  return is_synchronous_mode_;
+}
+
+}  // namespace content
diff --git a/content/renderer/resizing_mode_selector.h b/content/renderer/resizing_mode_selector.h
new file mode 100644
index 0000000..67702fd
--- /dev/null
+++ b/content/renderer/resizing_mode_selector.h
@@ -0,0 +1,43 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_RESIZING_MODE_SELECTOR_H_
+#define CONTENT_RENDERER_RESIZING_MODE_SELECTOR_H_
+
+#include "base/basictypes.h"
+
+struct ViewMsg_Resize_Params;
+
+namespace content {
+
+class RenderWidget;
+
+// Enables switching between two modes of resizing:
+// 1) The "normal" (asynchronous) resizing, which involves sending messages to
+//    and receiving them from host; and
+// 2) The synchronous mode, which short-circuits the resizing logic to operate
+//    strictly inside renderer.
+// The latter is necessary to support a handful of layout tests that were
+// written with the expectation of a synchronous resize, and we're going to
+// eventually rewrite or remove all of them. See http://crbug.com/309760 for
+// details.
+class ResizingModeSelector {
+ public:
+  ResizingModeSelector();
+
+  bool ShouldAbortOnResize(RenderWidget* widget,
+                           const ViewMsg_Resize_Params& params);
+
+  void set_is_synchronous_mode(bool mode);
+  bool is_synchronous_mode() const;
+
+ private:
+  bool is_synchronous_mode_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResizingModeSelector);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_RESIZING_MODE_SELECTOR_H_
diff --git a/content/renderer/shared_worker_repository.cc b/content/renderer/shared_worker_repository.cc
new file mode 100644
index 0000000..e39fa37
--- /dev/null
+++ b/content/renderer/shared_worker_repository.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/shared_worker_repository.h"
+
+#include "content/child/child_thread.h"
+#include "content/common/view_messages.h"
+#include "content/renderer/render_view_impl.h"
+#include "content/renderer/websharedworker_proxy.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+namespace content {
+
+SharedWorkerRepository::SharedWorkerRepository(RenderViewImpl* render_view)
+    : RenderViewObserver(render_view) {
+  render_view->GetWebView()->setSharedWorkerRepositoryClient(this);
+}
+
+SharedWorkerRepository::~SharedWorkerRepository() {}
+
+WebKit::WebSharedWorker* SharedWorkerRepository::createSharedWorker(
+    const WebKit::WebURL& url,
+    const WebKit::WebString& name,
+    DocumentID document_id) {
+  int route_id = MSG_ROUTING_NONE;
+  bool exists = false;
+  bool url_mismatch = false;
+  ViewHostMsg_CreateWorker_Params params;
+  params.url = url;
+  params.name = name;
+  params.document_id = document_id;
+  params.render_view_route_id = render_view()->GetRoutingID();
+  params.route_id = MSG_ROUTING_NONE;
+  params.script_resource_appcache_id = 0;
+  Send(new ViewHostMsg_LookupSharedWorker(
+      params, &exists, &route_id, &url_mismatch));
+  if (url_mismatch)
+    return NULL;
+  documents_with_workers_.insert(document_id);
+  return new WebSharedWorkerProxy(ChildThread::current(),
+                                  document_id,
+                                  exists,
+                                  route_id,
+                                  render_view()->GetRoutingID());
+}
+
+void SharedWorkerRepository::documentDetached(DocumentID document) {
+  std::set<DocumentID>::iterator iter = documents_with_workers_.find(document);
+  if (iter != documents_with_workers_.end()) {
+    // Notify the browser process that the document has shut down.
+    Send(new ViewHostMsg_DocumentDetached(document));
+    documents_with_workers_.erase(iter);
+  }
+}
+
+}  // namespace content
diff --git a/content/renderer/shared_worker_repository.h b/content/renderer/shared_worker_repository.h
new file mode 100644
index 0000000..28c36d9
--- /dev/null
+++ b/content/renderer/shared_worker_repository.h
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SHARED_WORKER_REPOSITORY_H_
+#define CONTENT_RENDERER_SHARED_WORKER_REPOSITORY_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerRepositoryClient.h"
+
+namespace content {
+
+class RenderViewImpl;
+
+class SharedWorkerRepository : public RenderViewObserver,
+                               public WebKit::WebSharedWorkerRepositoryClient {
+ public:
+  explicit SharedWorkerRepository(RenderViewImpl* render_view);
+  virtual ~SharedWorkerRepository();
+
+  // WebSharedWorkerRepositoryClient overrides.
+  virtual WebKit::WebSharedWorker* createSharedWorker(
+      const WebKit::WebURL& url,
+      const WebKit::WebString& name,
+      DocumentID document_id) OVERRIDE;
+  virtual void documentDetached(DocumentID document_id) OVERRIDE;
+
+ private:
+  std::set<DocumentID> documents_with_workers_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedWorkerRepository);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SHARED_WORKER_REPOSITORY_H_
diff --git a/content/renderer/web_preferences.cc b/content/renderer/web_preferences.cc
index 5a71a8a..71c0ca0 100644
--- a/content/renderer/web_preferences.cc
+++ b/content/renderer/web_preferences.cc
@@ -237,6 +237,11 @@
   settings->setAntialiased2dCanvasEnabled(
       !prefs.antialiased_2d_canvas_disabled);
 
+  // Set MSAA sample count for 2d canvas if requested on the command line (or
+  // default value if not).
+  settings->setAccelerated2dCanvasMSAASampleCount(
+      prefs.accelerated_2d_canvas_msaa_sample_count);
+
   // Enable gpu-accelerated filters if requested on the command line.
   settings->setAcceleratedFiltersEnabled(prefs.accelerated_filters_enabled);
 
@@ -293,6 +298,7 @@
 
   WebRuntimeFeatures::enableLazyLayout(prefs.lazy_layout_enabled);
   WebRuntimeFeatures::enableTouch(prefs.touch_enabled);
+  settings->setMaxTouchPoints(prefs.pointer_events_max_touch_points);
   settings->setDeviceSupportsTouch(prefs.device_supports_touch);
   settings->setDeviceSupportsMouse(prefs.device_supports_mouse);
   settings->setEnableTouchAdjustment(prefs.touch_adjustment_enabled);
@@ -343,6 +349,8 @@
   settings->setUseWideViewport(prefs.use_wide_viewport);
   settings->setViewportMetaLayoutSizeQuirk(
       prefs.viewport_meta_layout_size_quirk);
+  settings->setViewportMetaMergeContentQuirk(
+      prefs.viewport_meta_merge_content_quirk);
   settings->setViewportMetaZeroValuesQuirk(
       prefs.viewport_meta_zero_values_quirk);
   settings->setIgnoreMainFrameOverflowHiddenQuirk(
diff --git a/content/renderer/webclipboard_impl.cc b/content/renderer/webclipboard_impl.cc
index c7f63be..0a73576 100644
--- a/content/renderer/webclipboard_impl.cc
+++ b/content/renderer/webclipboard_impl.cc
@@ -42,10 +42,6 @@
 WebClipboardImpl::~WebClipboardImpl() {
 }
 
-uint64 WebClipboardImpl::getSequenceNumber() {
-  return sequenceNumber(BufferStandard);
-}
-
 uint64 WebClipboardImpl::sequenceNumber(Buffer buffer) {
   ui::ClipboardType clipboard_type;
   if (!ConvertBufferType(buffer, &clipboard_type))
@@ -155,6 +151,11 @@
   return data;
 }
 
+void WebClipboardImpl::writePlainText(const WebString& plain_text) {
+  ScopedClipboardWriterGlue scw(client_);
+  scw.WriteText(plain_text);
+}
+
 void WebClipboardImpl::writeHTML(
     const WebString& html_text, const WebURL& source_url,
     const WebString& plain_text, bool write_smart_paste) {
@@ -166,19 +167,6 @@
     scw.WriteWebSmartPaste();
 }
 
-void WebClipboardImpl::writePlainText(const WebString& plain_text) {
-  ScopedClipboardWriterGlue scw(client_);
-  scw.WriteText(plain_text);
-}
-
-void WebClipboardImpl::writeURL(const WebURL& url, const WebString& title) {
-  ScopedClipboardWriterGlue scw(client_);
-
-  scw.WriteBookmark(title, url.spec());
-  scw.WriteHTML(UTF8ToUTF16(URLToMarkup(url, title)), std::string());
-  scw.WriteText(UTF8ToUTF16(std::string(url.spec())));
-}
-
 void WebClipboardImpl::writeImage(const WebImage& image,
                                   const WebURL& url,
                                   const WebString& title) {
diff --git a/content/renderer/webclipboard_impl.h b/content/renderer/webclipboard_impl.h
index 4e6a732..926ca2c 100644
--- a/content/renderer/webclipboard_impl.h
+++ b/content/renderer/webclipboard_impl.h
@@ -22,7 +22,6 @@
   virtual ~WebClipboardImpl();
 
   // WebClipboard methods:
-  virtual uint64 getSequenceNumber();
   virtual uint64 sequenceNumber(Buffer buffer);
   virtual bool isFormatAvailable(Format format, Buffer buffer);
   virtual WebKit::WebVector<WebKit::WebString> readAvailableTypes(
@@ -36,15 +35,12 @@
   virtual WebKit::WebData readImage(Buffer buffer);
   virtual WebKit::WebString readCustomData(
       Buffer buffer, const WebKit::WebString& type);
+  virtual void writePlainText(const WebKit::WebString& plain_text);
   virtual void writeHTML(
       const WebKit::WebString& html_text,
       const WebKit::WebURL& source_url,
       const WebKit::WebString& plain_text,
       bool write_smart_paste);
-  virtual void writePlainText(const WebKit::WebString& plain_text);
-  virtual void writeURL(
-      const WebKit::WebURL& url,
-      const WebKit::WebString& title);
   virtual void writeImage(
       const WebKit::WebImage& image,
       const WebKit::WebURL& source_url,
@@ -59,4 +55,3 @@
 }  // namespace content
 
 #endif  // CONTENT_RENDERER_WEBCLIPBOARD_IMPL_H_
-
diff --git a/content/renderer/webcrypto/webcrypto_impl.cc b/content/renderer/webcrypto/webcrypto_impl.cc
index f794c59..9275783 100644
--- a/content/renderer/webcrypto/webcrypto_impl.cc
+++ b/content/renderer/webcrypto/webcrypto_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/webcrypto/webcrypto_impl.h"
 
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
@@ -15,12 +16,41 @@
   Init();
 }
 
+// static
+// TODO(eroman): This works by re-allocating a new buffer. It would be better if
+//               the WebArrayBuffer could just be truncated instead.
+void WebCryptoImpl::ShrinkBuffer(
+    WebKit::WebArrayBuffer* buffer,
+    unsigned new_size) {
+  DCHECK_LE(new_size, buffer->byteLength());
+
+  if (new_size == buffer->byteLength())
+    return;
+
+  WebKit::WebArrayBuffer new_buffer =
+      WebKit::WebArrayBuffer::create(new_size, 1);
+  DCHECK(!new_buffer.isNull());
+  memcpy(new_buffer.data(), buffer->data(), new_size);
+  *buffer = new_buffer;
+}
+
+// static
+// TODO(eroman): Expose functionality in Blink instead.
+WebKit::WebCryptoKey WebCryptoImpl::NullKey() {
+  // Needs a non-null algorithm to succeed.
+  return WebKit::WebCryptoKey::create(
+      NULL, WebKit::WebCryptoKeyTypeSecret, false,
+      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
+          WebKit::WebCryptoAlgorithmIdAesGcm, NULL), 0);
+}
+
 void WebCryptoImpl::encrypt(
     const WebKit::WebCryptoAlgorithm& algorithm,
     const WebKit::WebCryptoKey& key,
     const unsigned char* data,
     unsigned data_size,
     WebKit::WebCryptoResult result) {
+  DCHECK(!algorithm.isNull());
   WebKit::WebArrayBuffer buffer;
   if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) {
     result.completeWithError();
@@ -35,6 +65,7 @@
     const unsigned char* data,
     unsigned data_size,
     WebKit::WebCryptoResult result) {
+  DCHECK(!algorithm.isNull());
   WebKit::WebArrayBuffer buffer;
   if (!DecryptInternal(algorithm, key, data, data_size, &buffer)) {
     result.completeWithError();
@@ -48,6 +79,7 @@
     const unsigned char* data,
     unsigned data_size,
     WebKit::WebCryptoResult result) {
+  DCHECK(!algorithm.isNull());
   WebKit::WebArrayBuffer buffer;
   if (!DigestInternal(algorithm, data, data_size, &buffer)) {
     result.completeWithError();
@@ -58,17 +90,18 @@
 
 void WebCryptoImpl::generateKey(
     const WebKit::WebCryptoAlgorithm& algorithm,
-    bool exportable,
-    WebKit::WebCryptoKeyUsageMask usage,
+    bool extractable,
+    WebKit::WebCryptoKeyUsageMask usage_mask,
     WebKit::WebCryptoResult result) {
-  scoped_ptr<WebKit::WebCryptoKeyHandle> handle;
-  WebKit::WebCryptoKeyType type;
-  if (!GenerateKeyInternal(algorithm, &handle, &type)) {
+  DCHECK(!algorithm.isNull());
+  WebKit::WebCryptoKey key = NullKey();
+  if (!GenerateKeyInternal(algorithm, extractable, usage_mask, &key)) {
     result.completeWithError();
   } else {
-    WebKit::WebCryptoKey key(
-        WebKit::WebCryptoKey::create(handle.release(), type, exportable,
-                                     algorithm, usage));
+    DCHECK(key.handle());
+    DCHECK_EQ(algorithm.id(), key.algorithm().id());
+    DCHECK_EQ(extractable, key.extractable());
+    DCHECK_EQ(usage_mask, key.usages());
     result.completeWithKey(key);
   }
 }
@@ -77,28 +110,24 @@
     WebKit::WebCryptoKeyFormat format,
     const unsigned char* key_data,
     unsigned key_data_size,
-    const WebKit::WebCryptoAlgorithm& algorithm,
+    const WebKit::WebCryptoAlgorithm& algorithm_or_null,
     bool extractable,
     WebKit::WebCryptoKeyUsageMask usage_mask,
     WebKit::WebCryptoResult result) {
-  WebKit::WebCryptoKeyType type;
-  scoped_ptr<WebKit::WebCryptoKeyHandle> handle;
-
+  WebKit::WebCryptoKey key = NullKey();
   if (!ImportKeyInternal(format,
                          key_data,
                          key_data_size,
-                         algorithm,
+                         algorithm_or_null,
+                         extractable,
                          usage_mask,
-                         &handle,
-                         &type)) {
+                         &key)) {
     result.completeWithError();
     return;
   }
-
-  WebKit::WebCryptoKey key(
-      WebKit::WebCryptoKey::create(
-          handle.release(), type, extractable, algorithm, usage_mask));
-
+  DCHECK(key.handle());
+  DCHECK(!key.algorithm().isNull());
+  DCHECK_EQ(extractable, key.extractable());
   result.completeWithKey(key);
 }
 
@@ -108,6 +137,7 @@
     const unsigned char* data,
     unsigned data_size,
     WebKit::WebCryptoResult result) {
+  DCHECK(!algorithm.isNull());
   WebKit::WebArrayBuffer buffer;
   if (!SignInternal(algorithm, key, data, data_size, &buffer)) {
     result.completeWithError();
@@ -124,6 +154,7 @@
     const unsigned char* data,
     unsigned data_size,
     WebKit::WebCryptoResult result) {
+  DCHECK(!algorithm.isNull());
   bool signature_match = false;
   if (!VerifySignatureInternal(algorithm,
                                key,
diff --git a/content/renderer/webcrypto/webcrypto_impl.h b/content/renderer/webcrypto/webcrypto_impl.h
index e808c11..5979b62 100644
--- a/content/renderer/webcrypto/webcrypto_impl.h
+++ b/content/renderer/webcrypto/webcrypto_impl.h
@@ -7,7 +7,6 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebCrypto.h"
 
@@ -38,13 +37,13 @@
   virtual void generateKey(
       const WebKit::WebCryptoAlgorithm& algorithm,
       bool extractable,
-      WebKit::WebCryptoKeyUsageMask usage,
+      WebKit::WebCryptoKeyUsageMask usage_mask,
       WebKit::WebCryptoResult result);
   virtual void importKey(
       WebKit::WebCryptoKeyFormat format,
       const unsigned char* key_data,
       unsigned key_data_size,
-      const WebKit::WebCryptoAlgorithm& algorithm,
+      const WebKit::WebCryptoAlgorithm& algorithm_or_null,
       bool extractable,
       WebKit::WebCryptoKeyUsageMask usage_mask,
       WebKit::WebCryptoResult result);
@@ -63,6 +62,9 @@
       unsigned data_size,
       WebKit::WebCryptoResult result);
 
+  static void ShrinkBuffer(WebKit::WebArrayBuffer* buffer, unsigned new_size);
+  static WebKit::WebCryptoKey NullKey();
+
  protected:
   friend class WebCryptoImplTest;
 
@@ -87,16 +89,17 @@
       WebKit::WebArrayBuffer* buffer);
   bool GenerateKeyInternal(
       const WebKit::WebCryptoAlgorithm& algorithm,
-      scoped_ptr<WebKit::WebCryptoKeyHandle>* key,
-      WebKit::WebCryptoKeyType* type);
+      bool extractable,
+      WebKit::WebCryptoKeyUsageMask usage_mask,
+      WebKit::WebCryptoKey* key);
   bool ImportKeyInternal(
       WebKit::WebCryptoKeyFormat format,
       const unsigned char* key_data,
       unsigned key_data_size,
-      const WebKit::WebCryptoAlgorithm& algorithm,
+      const WebKit::WebCryptoAlgorithm& algorithm_or_null,
+      bool extractable,
       WebKit::WebCryptoKeyUsageMask usage_mask,
-      scoped_ptr<WebKit::WebCryptoKeyHandle>* handle,
-      WebKit::WebCryptoKeyType* type);
+      WebKit::WebCryptoKey* key);
   bool SignInternal(
       const WebKit::WebCryptoAlgorithm& algorithm,
       const WebKit::WebCryptoKey& key,
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc
index 598828c..452d2a7 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -69,21 +69,6 @@
   }
 }
 
-// TODO(eroman): This works by re-allocating a new buffer. It would be better if
-//               the WebArrayBuffer could just be truncated instead.
-void ShrinkBuffer(WebKit::WebArrayBuffer* buffer, unsigned new_size) {
-  DCHECK_LE(new_size, buffer->byteLength());
-
-  if (new_size == buffer->byteLength())
-    return;
-
-  WebKit::WebArrayBuffer new_buffer =
-      WebKit::WebArrayBuffer::create(new_size, 1);
-  DCHECK(!new_buffer.isNull());
-  memcpy(new_buffer.data(), buffer->data(), new_size);
-  *buffer = new_buffer;
-}
-
 bool AesCbcEncryptDecrypt(
     CK_ATTRIBUTE_TYPE operation,
     const WebKit::WebCryptoAlgorithm& algorithm,
@@ -162,7 +147,7 @@
     return false;
   }
 
-  ShrinkBuffer(buffer, final_output_chunk_len + output_len);
+  WebCryptoImpl::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
   return true;
 }
 
@@ -278,8 +263,9 @@
 
 bool WebCryptoImpl::GenerateKeyInternal(
     const WebKit::WebCryptoAlgorithm& algorithm,
-    scoped_ptr<WebKit::WebCryptoKeyHandle>* key,
-    WebKit::WebCryptoKeyType* type) {
+    bool extractable,
+    WebKit::WebCryptoKeyUsageMask usage_mask,
+    WebKit::WebCryptoKey* key) {
 
   CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm);
   unsigned int keylen_bytes = 0;
@@ -332,9 +318,9 @@
     return false;
   }
 
-  key->reset(new SymKeyHandle(pk11_key.Pass()));
-  *type = key_type;
-
+  *key = WebKit::WebCryptoKey::create(
+      new SymKeyHandle(pk11_key.Pass()),
+      key_type, extractable, algorithm, usage_mask);
   return true;
 }
 
@@ -343,14 +329,21 @@
     WebKit::WebCryptoKeyFormat format,
     const unsigned char* key_data,
     unsigned key_data_size,
-    const WebKit::WebCryptoAlgorithm& algorithm,
+    const WebKit::WebCryptoAlgorithm& algorithm_or_null,
+    bool extractable,
     WebKit::WebCryptoKeyUsageMask usage_mask,
-    scoped_ptr<WebKit::WebCryptoKeyHandle>* handle,
-    WebKit::WebCryptoKeyType* type) {
+    WebKit::WebCryptoKey* key) {
+  // TODO(eroman): Currently expects algorithm to always be specified, as it is
+  //               required for raw format.
+  if (algorithm_or_null.isNull())
+    return false;
+  const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
+
+  WebKit::WebCryptoKeyType type;
   switch (algorithm.id()) {
     case WebKit::WebCryptoAlgorithmIdHmac:
     case WebKit::WebCryptoAlgorithmIdAesCbc:
-      *type = WebKit::WebCryptoKeyTypeSecret;
+      type = WebKit::WebCryptoKeyTypeSecret;
       break;
     // TODO(bryaneyler): Support more key types.
     default:
@@ -417,9 +410,8 @@
     return false;
   }
 
-  scoped_ptr<SymKeyHandle> sym_key(new SymKeyHandle(pk11_sym_key.Pass()));
-  *handle = sym_key.Pass();
-
+  *key = WebKit::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
+                                      type, extractable, algorithm, usage_mask);
   return true;
 }
 
diff --git a/content/renderer/webcrypto/webcrypto_impl_openssl.cc b/content/renderer/webcrypto/webcrypto_impl_openssl.cc
index 2bf800e..83ae45c 100644
--- a/content/renderer/webcrypto/webcrypto_impl_openssl.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_openssl.cc
@@ -5,9 +5,12 @@
 #include "content/renderer/webcrypto/webcrypto_impl.h"
 
 #include <vector>
+#include <openssl/aes.h>
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
 
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
@@ -33,29 +36,153 @@
   DISALLOW_COPY_AND_ASSIGN(SymKeyHandle);
 };
 
-}  // anonymous namespace
+const EVP_CIPHER* GetAESCipherByKeyLength(unsigned key_length_bytes) {
+  // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits
+  switch (key_length_bytes) {
+    case 16:
+      return EVP_aes_128_cbc();
+    case 24:
+      return EVP_aes_192_cbc();
+    case 32:
+      return EVP_aes_256_cbc();
+    default:
+      return NULL;
+  }
+}
+
+unsigned WebCryptoHmacParamsToBlockSize(
+    const WebKit::WebCryptoHmacKeyParams* params) {
+  DCHECK(params);
+  switch (params->hash().id()) {
+    case WebKit::WebCryptoAlgorithmIdSha1:
+      return SHA_DIGEST_LENGTH / 8;
+    case WebKit::WebCryptoAlgorithmIdSha224:
+      return SHA224_DIGEST_LENGTH / 8;
+    case WebKit::WebCryptoAlgorithmIdSha256:
+      return SHA256_DIGEST_LENGTH / 8;
+    case WebKit::WebCryptoAlgorithmIdSha384:
+      return SHA384_DIGEST_LENGTH / 8;
+    case WebKit::WebCryptoAlgorithmIdSha512:
+      return SHA512_DIGEST_LENGTH / 8;
+    default:
+      return 0;
+  }
+}
+
+// OpenSSL constants for EVP_CipherInit_ex(), do not change
+enum CipherOperation {
+  kDoDecrypt = 0,
+  kDoEncrypt = 1
+};
+
+bool AesCbcEncryptDecrypt(CipherOperation cipher_operation,
+                          const WebKit::WebCryptoAlgorithm& algorithm,
+                          const WebKit::WebCryptoKey& key,
+                          const unsigned char* data,
+                          unsigned data_size,
+                          WebKit::WebArrayBuffer* buffer) {
+
+  // TODO(padolph): Handle other encrypt operations and then remove this gate
+  if (algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc)
+    return false;
+
+  DCHECK_EQ(algorithm.id(), key.algorithm().id());
+  DCHECK_EQ(WebKit::WebCryptoKeyTypeSecret, key.type());
+
+  if (data_size >= INT_MAX - AES_BLOCK_SIZE) {
+    // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right
+    // now it doesn't make much difference since the one-shot API would end up
+    // blowing out the memory and crashing anyway. However a newer version of
+    // the spec allows for a sequence<CryptoData> so this will be relevant.
+    return false;
+  }
+
+  // Note: PKCS padding is enabled by default
+  crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context(
+      EVP_CIPHER_CTX_new());
+
+  if (!context.get())
+    return false;
+
+  SymKeyHandle* const sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
+
+  const EVP_CIPHER* const cipher =
+      GetAESCipherByKeyLength(sym_key->key().size());
+  DCHECK(cipher);
+
+  const WebKit::WebCryptoAesCbcParams* const params = algorithm.aesCbcParams();
+  if (params->iv().size() != AES_BLOCK_SIZE)
+    return false;
+
+  if (!EVP_CipherInit_ex(context.get(),
+                         cipher,
+                         NULL,
+                         &sym_key->key()[0],
+                         params->iv().data(),
+                         cipher_operation)) {
+    return false;
+  }
+
+  // According to the openssl docs, the amount of data written may be as large
+  // as (data_size + cipher_block_size - 1), constrained to a multiple of
+  // cipher_block_size.
+  unsigned output_max_len = data_size + AES_BLOCK_SIZE - 1;
+  const unsigned remainder = output_max_len % AES_BLOCK_SIZE;
+  if (remainder != 0)
+    output_max_len += AES_BLOCK_SIZE - remainder;
+  DCHECK_GT(output_max_len, data_size);
+
+  *buffer = WebKit::WebArrayBuffer::create(output_max_len, 1);
+
+  unsigned char* const buffer_data =
+      reinterpret_cast<unsigned char*>(buffer->data());
+
+  int output_len = 0;
+  if (!EVP_CipherUpdate(
+          context.get(), buffer_data, &output_len, data, data_size))
+    return false;
+  int final_output_chunk_len = 0;
+  if (!EVP_CipherFinal_ex(
+          context.get(), buffer_data + output_len, &final_output_chunk_len))
+    return false;
+
+  const unsigned final_output_len =
+      static_cast<unsigned>(output_len) +
+      static_cast<unsigned>(final_output_chunk_len);
+  DCHECK_LE(final_output_len, output_max_len);
+
+  WebCryptoImpl::ShrinkBuffer(buffer, final_output_len);
+
+  return true;
+}
+
+}  // namespace
 
 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); }
 
-bool WebCryptoImpl::EncryptInternal(
-    const WebKit::WebCryptoAlgorithm& algorithm,
-    const WebKit::WebCryptoKey& key,
-    const unsigned char* data,
-    unsigned data_size,
-    WebKit::WebArrayBuffer* buffer) {
-  // TODO(padolph): Placeholder for OpenSSL implementation.
-  // Issue http://crbug.com/267888.
+bool WebCryptoImpl::EncryptInternal(const WebKit::WebCryptoAlgorithm& algorithm,
+                                    const WebKit::WebCryptoKey& key,
+                                    const unsigned char* data,
+                                    unsigned data_size,
+                                    WebKit::WebArrayBuffer* buffer) {
+  if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) {
+    return AesCbcEncryptDecrypt(
+        kDoEncrypt, algorithm, key, data, data_size, buffer);
+  }
+
   return false;
 }
 
-bool WebCryptoImpl::DecryptInternal(
-    const WebKit::WebCryptoAlgorithm& algorithm,
-    const WebKit::WebCryptoKey& key,
-    const unsigned char* data,
-    unsigned data_size,
-    WebKit::WebArrayBuffer* buffer) {
-  // TODO(padolph): Placeholder for OpenSSL implementation.
-  // Issue http://crbug.com/267888.
+bool WebCryptoImpl::DecryptInternal(const WebKit::WebCryptoAlgorithm& algorithm,
+                                    const WebKit::WebCryptoKey& key,
+                                    const unsigned char* data,
+                                    unsigned data_size,
+                                    WebKit::WebArrayBuffer* buffer) {
+  if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc) {
+    return AesCbcEncryptDecrypt(
+        kDoDecrypt, algorithm, key, data, data_size, buffer);
+  }
+
   return false;
 }
 
@@ -121,21 +248,70 @@
 
 bool WebCryptoImpl::GenerateKeyInternal(
     const WebKit::WebCryptoAlgorithm& algorithm,
-    scoped_ptr<WebKit::WebCryptoKeyHandle>* key,
-    WebKit::WebCryptoKeyType* type) {
-  // TODO(ellyjones): Placeholder for OpenSSL implementation.
-  // Issue http://crbug.com/267888.
-  return false;
+    bool extractable,
+    WebKit::WebCryptoKeyUsageMask usage_mask,
+    WebKit::WebCryptoKey* key) {
+
+  unsigned keylen_bytes = 0;
+  WebKit::WebCryptoKeyType key_type;
+  switch (algorithm.id()) {
+    case WebKit::WebCryptoAlgorithmIdAesCbc: {
+      const WebKit::WebCryptoAesKeyGenParams* params =
+          algorithm.aesKeyGenParams();
+      DCHECK(params);
+      if (params->length() % 8)
+        return false;
+      keylen_bytes = params->length() / 8;
+      if (!GetAESCipherByKeyLength(keylen_bytes)) {
+        return false;
+      }
+      key_type = WebKit::WebCryptoKeyTypeSecret;
+      break;
+    }
+    case WebKit::WebCryptoAlgorithmIdHmac: {
+      const WebKit::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
+      DCHECK(params);
+      if (!params->getLength(keylen_bytes)) {
+        keylen_bytes = WebCryptoHmacParamsToBlockSize(params);
+      }
+      key_type = WebKit::WebCryptoKeyTypeSecret;
+      break;
+    }
+
+    default: { return false; }
+  }
+
+  if (keylen_bytes == 0) {
+    return false;
+  }
+
+  crypto::OpenSSLErrStackTracer(FROM_HERE);
+
+  std::vector<unsigned char> random_bytes(keylen_bytes, 0);
+  if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) {
+    return false;
+  }
+
+  *key = WebKit::WebCryptoKey::create(
+      new SymKeyHandle(&random_bytes[0], random_bytes.size()),
+      key_type, extractable, algorithm, usage_mask);
+
+  return true;
 }
 
 bool WebCryptoImpl::ImportKeyInternal(
     WebKit::WebCryptoKeyFormat format,
     const unsigned char* key_data,
     unsigned key_data_size,
-    const WebKit::WebCryptoAlgorithm& algorithm,
-    WebKit::WebCryptoKeyUsageMask /*usage_mask*/,
-    scoped_ptr<WebKit::WebCryptoKeyHandle>* handle,
-    WebKit::WebCryptoKeyType* type) {
+    const WebKit::WebCryptoAlgorithm& algorithm_or_null,
+    bool extractable,
+    WebKit::WebCryptoKeyUsageMask usage_mask,
+    WebKit::WebCryptoKey* key) {
+  // TODO(eroman): Currently expects algorithm to always be specified, as it is
+  //               required for raw format.
+  if (algorithm_or_null.isNull())
+    return false;
+  const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
 
   // TODO(padolph): Support all relevant alg types and then remove this gate.
   if (algorithm.id() != WebKit::WebCryptoAlgorithmIdHmac &&
@@ -152,7 +328,7 @@
   // they differ? (jwk, probably)
 
   // Symmetric keys are always type secret
-  *type = WebKit::WebCryptoKeyTypeSecret;
+  WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypeSecret;
 
   const unsigned char* raw_key_data;
   unsigned raw_key_data_size;
@@ -160,6 +336,12 @@
     case WebKit::WebCryptoKeyFormatRaw:
       raw_key_data = key_data;
       raw_key_data_size = key_data_size;
+      // The NSS implementation fails when importing a raw AES key with a length
+      // incompatible with AES. The line below is to match this behavior.
+      if (algorithm.id() == WebKit::WebCryptoAlgorithmIdAesCbc &&
+          !GetAESCipherByKeyLength(raw_key_data_size)) {
+        return false;
+      }
       break;
     case WebKit::WebCryptoKeyFormatJwk:
       // TODO(padolph): Handle jwk format; need simple JSON parser.
@@ -169,7 +351,9 @@
       return false;
   }
 
-  handle->reset(new SymKeyHandle(raw_key_data, raw_key_data_size));
+  *key = WebKit::WebCryptoKey::create(
+      new SymKeyHandle(raw_key_data, raw_key_data_size),
+      type, extractable, algorithm, usage_mask);
 
   return true;
 }
diff --git a/content/renderer/webcrypto/webcrypto_impl_unittest.cc b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
index 0ae3bbf..99d71ea 100644
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
@@ -43,6 +43,17 @@
       new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId)));
 }
 
+WebKit::WebCryptoAlgorithm CreateHmacKeyAlgorithm(
+    WebKit::WebCryptoAlgorithmId hashId,
+    unsigned hash_length) {
+  // hash_length < 0 means unspecified
+  return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
+      WebKit::WebCryptoAlgorithmIdHmac,
+      new WebKit::WebCryptoHmacKeyParams(CreateAlgorithm(hashId),
+                                         (hash_length != 0),
+                                         hash_length));
+}
+
 // Returns a pointer to the start of |data|, or NULL if it is empty. This is a
 // convenience function for getting the pointer, and should not be used beyond
 // the expected lifetime of |data|.
@@ -59,6 +70,13 @@
       new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size()));
 }
 
+WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm(
+    unsigned short key_length_bits) {
+  return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
+      WebKit::WebCryptoAlgorithmIdAesCbc,
+      new WebKit::WebCryptoAesKeyGenParams(key_length_bits));
+}
+
 }  // namespace
 
 namespace content {
@@ -69,24 +87,21 @@
       const std::string& key_hex,
       const WebKit::WebCryptoAlgorithm& algorithm,
       WebKit::WebCryptoKeyUsageMask usage) {
-    WebKit::WebCryptoKeyType type;
-    scoped_ptr<WebKit::WebCryptoKeyHandle> handle;
-
     std::vector<uint8> key_raw = HexStringToBytes(key_hex);
 
+    WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+    bool extractable = true;
     EXPECT_TRUE(crypto_.ImportKeyInternal(WebKit::WebCryptoKeyFormatRaw,
                                           Start(key_raw),
                                           key_raw.size(),
                                           algorithm,
+                                          extractable,
                                           usage,
-                                          &handle,
-                                          &type));
+                                          &key));
 
-    EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, type);
-    EXPECT_TRUE(handle.get());
-
-    return WebKit::WebCryptoKey::create(
-        handle.release(), type, false, algorithm, usage);
+    EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type());
+    EXPECT_TRUE(key.handle());
+    return key;
   }
 
   // Forwarding methods to gain access to protected methods of
@@ -101,9 +116,10 @@
 
   bool GenerateKeyInternal(
       const WebKit::WebCryptoAlgorithm& algorithm,
-      scoped_ptr<WebKit::WebCryptoKeyHandle>* handle,
-      WebKit::WebCryptoKeyType* type) {
-    return crypto_.GenerateKeyInternal(algorithm, handle, type);
+      WebKit::WebCryptoKey* key) {
+    bool extractable = true;
+    WebKit::WebCryptoKeyUsageMask usage_mask = 0;
+    return crypto_.GenerateKeyInternal(algorithm, extractable, usage_mask, key);
   }
 
   bool ImportKeyInternal(
@@ -111,15 +127,15 @@
       const std::vector<uint8>& key_data,
       const WebKit::WebCryptoAlgorithm& algorithm,
       WebKit::WebCryptoKeyUsageMask usage_mask,
-      scoped_ptr<WebKit::WebCryptoKeyHandle>* handle,
-      WebKit::WebCryptoKeyType* type) {
+      WebKit::WebCryptoKey* key) {
+    bool extractable = true;
     return crypto_.ImportKeyInternal(format,
                                      Start(key_data),
                                      key_data.size(),
                                      algorithm,
+                                     extractable,
                                      usage_mask,
-                                     handle,
-                                     type);
+                                     key);
   }
 
   bool SignInternal(
@@ -268,9 +284,6 @@
   }
 }
 
-// TODO(padolph) Enable these tests for OpenSSL once matching impl is available
-#if !defined(USE_OPENSSL)
-
 TEST_F(WebCryptoImplTest, HMACSampleSets) {
   struct TestCase {
     WebKit::WebCryptoAlgorithmId algorithm;
@@ -457,18 +470,15 @@
 
   // Fail importing the key (too few bytes specified)
   {
-    WebKit::WebCryptoKeyType type;
-    scoped_ptr<WebKit::WebCryptoKeyHandle> handle;
-
     std::vector<uint8> key_raw(1);
     std::vector<uint8> iv(16);
 
+    WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
     EXPECT_FALSE(ImportKeyInternal(WebKit::WebCryptoKeyFormatRaw,
                                    key_raw,
                                    CreateAesCbcAlgorithm(iv),
                                    WebKit::WebCryptoKeyUsageDecrypt,
-                                   &handle,
-                                   &type));
+                                   &key));
   }
 }
 
@@ -603,75 +613,50 @@
   }
 }
 
-#endif // !defined(USE_OPENSSL)
+// TODO (padolph): Add test to verify generated symmetric keys appear random.
 
-#if !defined(USE_OPENSSL)
+
 TEST_F(WebCryptoImplTest, GenerateKeyAes) {
-  scoped_ptr<WebKit::WebCryptoAesKeyGenParams> params(
-      new WebKit::WebCryptoAesKeyGenParams(128));
-  WebKit::WebCryptoAlgorithm algorithm(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdAesCbc, params.release()));
-
-  scoped_ptr<WebKit::WebCryptoKeyHandle> result;
-  WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic;
-
-  ASSERT_TRUE(GenerateKeyInternal(algorithm, &result, &type));
-  EXPECT_TRUE(bool(result));
-  EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret);
+  WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+  ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key));
+  EXPECT_TRUE(key.handle());
+  EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type());
 }
 
-TEST_F(WebCryptoImplTest, GenerateKeyAesOddLength) {
-  scoped_ptr<WebKit::WebCryptoAesKeyGenParams> params(
-      new WebKit::WebCryptoAesKeyGenParams(129));
-  WebKit::WebCryptoAlgorithm algorithm(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdAesCbc, params.release()));
-
-  WebCryptoImpl crypto;
-  scoped_ptr<WebKit::WebCryptoKeyHandle> result;
-  WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic;
-
-  EXPECT_FALSE(GenerateKeyInternal(algorithm, &result, &type));
-  EXPECT_FALSE(bool(result));
-  EXPECT_EQ(type, WebKit::WebCryptoKeyTypePublic);
+TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) {
+  WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+  EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key));
+  EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key));
 }
 
 TEST_F(WebCryptoImplTest, GenerateKeyHmac) {
-  WebKit::WebCryptoAlgorithm sha1_alg(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdSha1, NULL));
-  scoped_ptr<WebKit::WebCryptoHmacKeyParams> params(
-      new WebKit::WebCryptoHmacKeyParams(sha1_alg, true, 128));
-  WebKit::WebCryptoAlgorithm algorithm(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdHmac, params.release()));
-
-  scoped_ptr<WebKit::WebCryptoKeyHandle> result;
-  WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic;
-
-  ASSERT_TRUE(GenerateKeyInternal(algorithm, &result, &type));
-  EXPECT_TRUE(bool(result));
-  EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret);
+  WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+  WebKit::WebCryptoAlgorithm algorithm =
+      CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128);
+  ASSERT_TRUE(GenerateKeyInternal(algorithm, &key));
+  EXPECT_TRUE(key.handle());
+  EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type());
 }
 
 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) {
-  WebKit::WebCryptoAlgorithm sha1_alg(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdSha1, NULL));
-  scoped_ptr<WebKit::WebCryptoHmacKeyParams> params(
-      new WebKit::WebCryptoHmacKeyParams(sha1_alg, false, 0));
-  WebKit::WebCryptoAlgorithm algorithm(
-      WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(
-          WebKit::WebCryptoAlgorithmIdHmac, params.release()));
-
-  scoped_ptr<WebKit::WebCryptoKeyHandle> result;
-  WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic;
-
-  ASSERT_TRUE(GenerateKeyInternal(algorithm, &result, &type));
-  EXPECT_TRUE(bool(result));
-  EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret);
+  WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+  WebKit::WebCryptoAlgorithm algorithm =
+      CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0);
+  ASSERT_TRUE(GenerateKeyInternal(algorithm, &key));
+  EXPECT_TRUE(key.handle());
+  EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type());
 }
-#endif /* !defined(USE_OPENSSL) */
+
+TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) {
+  WebKit::WebCryptoKey key = WebCryptoImpl::NullKey();
+
+  // This fails because the algorithm is null.
+  EXPECT_FALSE(ImportKeyInternal(
+      WebKit::WebCryptoKeyFormatRaw,
+      HexStringToBytes("00000000000000000000"),
+      WebKit::WebCryptoAlgorithm::createNull(),
+      WebKit::WebCryptoKeyUsageSign,
+      &key));
+}
 
 }  // namespace content
diff --git a/content/renderer/websharedworkerrepository_impl.cc b/content/renderer/websharedworkerrepository_impl.cc
deleted file mode 100644
index d914cf7..0000000
--- a/content/renderer/websharedworkerrepository_impl.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/websharedworkerrepository_impl.h"
-
-#include "content/child/child_thread.h"
-#include "content/common/view_messages.h"
-#include "content/renderer/websharedworker_proxy.h"
-
-namespace content {
-
-WebSharedWorkerRepositoryImpl::WebSharedWorkerRepositoryImpl() {}
-
-WebSharedWorkerRepositoryImpl::~WebSharedWorkerRepositoryImpl() {}
-
-void WebSharedWorkerRepositoryImpl::addSharedWorker(
-    WebKit::WebSharedWorker* worker, DocumentID document) {
-  shared_worker_parents_.insert(document);
-}
-
-void WebSharedWorkerRepositoryImpl::documentDetached(DocumentID document) {
-  DocumentSet::iterator iter = shared_worker_parents_.find(document);
-  if (iter != shared_worker_parents_.end()) {
-    // Notify the browser process that the document has shut down.
-    ChildThread::current()->Send(new ViewHostMsg_DocumentDetached(document));
-    shared_worker_parents_.erase(iter);
-  }
-}
-
-bool WebSharedWorkerRepositoryImpl::hasSharedWorkers(DocumentID document) {
-  return shared_worker_parents_.find(document) != shared_worker_parents_.end();
-}
-
-}  // namespace content
diff --git a/content/renderer/websharedworkerrepository_impl.h b/content/renderer/websharedworkerrepository_impl.h
deleted file mode 100644
index ebe2a22..0000000
--- a/content/renderer/websharedworkerrepository_impl.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_WEBSHAREDWORKERREPOSITORY_IMPL_H_
-#define CONTENT_RENDERER_WEBSHAREDWORKERREPOSITORY_IMPL_H_
-
-#include "base/containers/hash_tables.h"
-#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h"
-
-namespace WebKit {
-class WebSharedWorker;
-}
-
-namespace content {
-
-class WebSharedWorkerRepositoryImpl : public WebKit::WebSharedWorkerRepository {
- public:
-  WebSharedWorkerRepositoryImpl();
-  virtual ~WebSharedWorkerRepositoryImpl();
-
-  virtual void addSharedWorker(WebKit::WebSharedWorker*, DocumentID document);
-  virtual void documentDetached(DocumentID document);
-
-  // Returns true if the document has created a SharedWorker (used by the
-  // WebKit code to determine if the document can be suspended).
-  virtual bool hasSharedWorkers(DocumentID document);
-
- private:
-  // The set of documents that have created a SharedWorker.
-  typedef base::hash_set<DocumentID> DocumentSet;
-  DocumentSet shared_worker_parents_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_WEBSHAREDWORKERREPOSITORY_IMPL_H_
diff --git a/content/result_codes_java.target.darwin-arm.mk b/content/result_codes_java.target.darwin-arm.mk
index d18eba1..14f8710 100644
--- a/content/result_codes_java.target.darwin-arm.mk
+++ b/content/result_codes_java.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/result_codes_java.target.darwin-mips.mk b/content/result_codes_java.target.darwin-mips.mk
index 5faa2d8..2521982 100644
--- a/content/result_codes_java.target.darwin-mips.mk
+++ b/content/result_codes_java.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/result_codes_java.target.darwin-x86.mk b/content/result_codes_java.target.darwin-x86.mk
index 69ac326..01f3a8c 100644
--- a/content/result_codes_java.target.darwin-x86.mk
+++ b/content/result_codes_java.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/result_codes_java.target.linux-arm.mk b/content/result_codes_java.target.linux-arm.mk
index d18eba1..14f8710 100644
--- a/content/result_codes_java.target.linux-arm.mk
+++ b/content/result_codes_java.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/result_codes_java.target.linux-mips.mk b/content/result_codes_java.target.linux-mips.mk
index 5faa2d8..2521982 100644
--- a/content/result_codes_java.target.linux-mips.mk
+++ b/content/result_codes_java.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/result_codes_java.target.linux-x86.mk b/content/result_codes_java.target.linux-x86.mk
index 69ac326..01f3a8c 100644
--- a/content/result_codes_java.target.linux-x86.mk
+++ b/content/result_codes_java.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/shell/DEPS b/content/shell/DEPS
index 0943fd0..3738104 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -22,6 +22,8 @@
 
   # For WebTestRunner library
   "+third_party/WebKit/public/testing",
+
+  "+components/breakpad",
 ]
 
 specific_include_rules = {
diff --git a/content/shell/android/shell_descriptors.h b/content/shell/android/shell_descriptors.h
index 8bcd376..9441813 100644
--- a/content/shell/android/shell_descriptors.h
+++ b/content/shell/android/shell_descriptors.h
@@ -5,10 +5,13 @@
 #ifndef CONTENT_SHELL_ANDROID_SHELL_DESCRIPTORS_H_
 #define CONTENT_SHELL_ANDROID_SHELL_DESCRIPTORS_H_
 
+#include "content/public/common/content_descriptors.h"
+
 // This is a list of global descriptor keys to be used with the
 // base::GlobalDescriptors object (see base/posix/global_descriptors.h)
 enum {
-  kShellPakDescriptor = 1,
+  kShellPakDescriptor = kContentIPCDescriptorMax + 1,
+  kAndroidMinidumpDescriptor,
 };
 
 #endif  // CONTENT_SHELL_ANDROID_SHELL_DESCRIPTORS_H_
diff --git a/content/shell/app/framework-Info.plist b/content/shell/app/framework-Info.plist
new file mode 100644
index 0000000..ee19476
--- /dev/null
+++ b/content/shell/app/framework-Info.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>org.chromium.ContentShell.framework</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+</dict>
+</plist>
diff --git a/content/shell/app/shell_breakpad_client.cc b/content/shell/app/shell_breakpad_client.cc
new file mode 100644
index 0000000..c4dd86d
--- /dev/null
+++ b/content/shell/app/shell_breakpad_client.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 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/shell/app/shell_breakpad_client.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/shell/common/shell_switches.h"
+
+#if defined(OS_ANDROID)
+#include "content/shell/android/shell_descriptors.h"
+#endif
+
+namespace content {
+
+ShellBreakpadClient::ShellBreakpadClient() {}
+ShellBreakpadClient::~ShellBreakpadClient() {}
+
+#if defined(OS_WIN)
+void ShellBreakpadClient::GetProductNameAndVersion(
+    const base::FilePath& exe_path,
+    base::string16* product_name,
+    base::string16* version,
+    base::string16* special_build,
+    base::string16* channel_name) {
+  *product_name = ASCIIToUTF16("content_shell");
+  *version = ASCIIToUTF16(CONTENT_SHELL_VERSION);
+  *special_build = string16();
+  *channel_name = string16();
+}
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+void ShellBreakpadClient::GetProductNameAndVersion(std::string* product_name,
+                                                   std::string* version) {
+  *product_name = "content_shell";
+  *version = CONTENT_SHELL_VERSION;
+}
+
+base::FilePath ShellBreakpadClient::GetReporterLogFilename() {
+  return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
+}
+#endif
+
+bool ShellBreakpadClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir))
+    return false;
+  *crash_dir = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+      switches::kCrashDumpsDir);
+  return true;
+}
+
+#if defined(OS_ANDROID)
+int ShellBreakpadClient::GetAndroidMinidumpDescriptor() {
+  return kAndroidMinidumpDescriptor;
+}
+#endif
+
+}  // namespace content
diff --git a/content/shell/app/shell_breakpad_client.h b/content/shell/app/shell_breakpad_client.h
new file mode 100644
index 0000000..63d3024
--- /dev/null
+++ b/content/shell/app/shell_breakpad_client.h
@@ -0,0 +1,52 @@
+// Copyright 2013 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_SHELL_APP_SHELL_BREAKPAD_CLIENT_H_
+#define CONTENT_SHELL_APP_SHELL_BREAKPAD_CLIENT_H_
+
+#include "base/compiler_specific.h"
+#include "components/breakpad/app/breakpad_client.h"
+
+namespace content {
+
+class ShellBreakpadClient : public breakpad::BreakpadClient {
+ public:
+  ShellBreakpadClient();
+  virtual ~ShellBreakpadClient();
+
+#if defined(OS_WIN)
+  // Returns a textual description of the product type and version to include
+  // in the crash report.
+  virtual void GetProductNameAndVersion(const base::FilePath& exe_path,
+                                        base::string16* product_name,
+                                        base::string16* version,
+                                        base::string16* special_build,
+                                        base::string16* channel_name) OVERRIDE;
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+  // Returns a textual description of the product type and version to include
+  // in the crash report.
+  virtual void GetProductNameAndVersion(std::string* product_name,
+                                        std::string* version) OVERRIDE;
+
+  virtual base::FilePath GetReporterLogFilename() OVERRIDE;
+#endif
+
+  // The location where minidump files should be written. Returns true if
+  // |crash_dir| was set.
+  virtual bool GetCrashDumpLocation(base::FilePath* crash_dir) OVERRIDE;
+
+#if defined(OS_ANDROID)
+  // Returns the descriptor key of the android minidump global descriptor.
+  virtual int GetAndroidMinidumpDescriptor() OVERRIDE;
+#endif
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ShellBreakpadClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_APP_SHELL_BREAKPAD_CLIENT_H_
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index f7f6e14..f6f5247 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -4,8 +4,10 @@
 
 #include "content/shell/app/shell_main_delegate.h"
 
+#include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "cc/base/switches.h"
@@ -13,6 +15,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/layouttest_support.h"
+#include "content/shell/app/shell_breakpad_client.h"
 #include "content/shell/app/webkit_test_platform_support.h"
 #include "content/shell/browser/shell_browser_main.h"
 #include "content/shell/browser/shell_content_browser_client.h"
@@ -42,17 +45,28 @@
 #endif
 
 #if defined(OS_MACOSX)
+#include "base/mac/os_crash_dumps.h"
+#include "components/breakpad/app/breakpad_mac.h"
 #include "content/shell/app/paths_mac.h"
 #include "content/shell/app/shell_main_delegate_mac.h"
 #endif  // OS_MACOSX
 
 #if defined(OS_WIN)
 #include <initguid.h>
+#include <windows.h>
 #include "base/logging_win.h"
+#include "components/breakpad/app/breakpad_win.h"
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "components/breakpad/app/breakpad_linux.h"
 #endif
 
 namespace {
 
+base::LazyInstance<content::ShellBreakpadClient>::Leaky
+    g_shell_breakpad_client = LAZY_INSTANCE_INITIALIZER;
+
 #if defined(OS_WIN)
 // If "Content Shell" doesn't show up in your list of trace providers in
 // Sawbuck, add these registry entries to your machine (NOTE the optional
@@ -149,12 +163,19 @@
         switches::kEnableExperimentalWebPlatformFeatures);
     }
 
-    if (!command_line.HasSwitch(switches::kEnableThreadedCompositing))
+    if (!command_line.HasSwitch(switches::kEnableThreadedCompositing)) {
+      command_line.AppendSwitch(switches::kDisableThreadedCompositing);
       command_line.AppendSwitch(cc::switches::kDisableThreadedAnimation);
+    }
 
     command_line.AppendSwitch(switches::kEnableInbandTextTracks);
     command_line.AppendSwitch(switches::kMuteAudio);
 
+#if defined(USE_AURA)
+    // TODO: crbug.com/311404 Make layout tests work w/ delegated renderer.
+    command_line.AppendSwitch(switches::kDisableDelegatedRenderer);
+#endif
+
     net::CookieMonster::EnableFileScheme();
 
     // Unless/until WebM files are added to the media layout tests, we need to
@@ -174,6 +195,33 @@
 }
 
 void ShellMainDelegate::PreSandboxStartup() {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableCrashReporter)) {
+    breakpad::SetBreakpadClient(g_shell_breakpad_client.Pointer());
+#if defined(OS_MACOSX)
+    base::mac::DisableOSCrashDumps();
+    breakpad::InitCrashReporter();
+    breakpad::InitCrashProcessInfo();
+#elif defined(OS_POSIX) && !defined(OS_MACOSX)
+    std::string process_type =
+        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kProcessType);
+    if (!process_type.empty() && process_type != switches::kZygoteProcess) {
+#if defined(OS_ANDROID)
+      breakpad::InitNonBrowserCrashReporterForAndroid();
+#else
+      breakpad::InitCrashReporter();
+#endif
+    }
+#elif defined(OS_WIN)
+    UINT new_flags =
+        SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
+    UINT existing_flags = SetErrorMode(new_flags);
+    SetErrorMode(existing_flags | new_flags);
+    breakpad::InitCrashReporter();
+#endif
+  }
+
   InitializeResourceBundle();
 }
 
@@ -193,6 +241,15 @@
   return ShellBrowserMain(main_function_params, browser_runner_);
 }
 
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+void ShellMainDelegate::ZygoteForked() {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableCrashReporter)) {
+    breakpad::InitCrashReporter();
+  }
+}
+#endif
+
 void ShellMainDelegate::InitializeResourceBundle() {
 #if defined(OS_ANDROID)
   // In the Android case, the renderer runs with a different UID and can never
diff --git a/content/shell/app/shell_main_delegate.h b/content/shell/app/shell_main_delegate.h
index 73c6d04..2d69d08 100644
--- a/content/shell/app/shell_main_delegate.h
+++ b/content/shell/app/shell_main_delegate.h
@@ -29,6 +29,9 @@
   virtual int RunProcess(
       const std::string& process_type,
       const MainFunctionParams& main_function_params) OVERRIDE;
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+  virtual void ZygoteForked() OVERRIDE;
+#endif
   virtual ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
   virtual ContentRendererClient* CreateContentRendererClient() OVERRIDE;
 
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index ba36749..1fbf174 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -269,7 +269,7 @@
 
   views::Widget* window_widget_;
 #else // defined(TOOLKIT_VIEWS)
-  scoped_ptr<ShellAuraPlatformData> platform_;
+  static ShellAuraPlatformData* platform_;
 #endif // defined(TOOLKIT_VIEWS)
 #elif defined(OS_MACOSX)
   int content_width_;
diff --git a/content/shell/browser/shell_aura.cc b/content/shell/browser/shell_aura.cc
index 2eb0dd7..c2f22a1 100644
--- a/content/shell/browser/shell_aura.cc
+++ b/content/shell/browser/shell_aura.cc
@@ -15,6 +15,7 @@
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/test_focus_client.h"
 #include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_delegate.h"
@@ -125,17 +126,12 @@
 
 }
 
+ShellAuraPlatformData* Shell::platform_ = NULL;
+
 ShellAuraPlatformData::ShellAuraPlatformData() {
-}
-
-ShellAuraPlatformData::~ShellAuraPlatformData() {
-}
-
-void ShellAuraPlatformData::CreateWindow(int width, int height) {
   aura::TestScreen* screen = aura::TestScreen::Create();
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen);
   root_window_.reset(screen->CreateRootWindowForPrimaryDisplay());
-  root_window_->SetHostSize(gfx::Size(width, height));
   root_window_->ShowRootWindow();
   root_window_->SetLayoutManager(new FillLayout(root_window_.get()));
 
@@ -146,15 +142,29 @@
       new aura::client::DefaultActivationClient(root_window_.get()));
   capture_client_.reset(
       new aura::client::DefaultCaptureClient(root_window_.get()));
+  window_tree_client_.reset(
+      new aura::test::TestWindowTreeClient(root_window_.get()));
   ime_filter_.reset(new MinimalInputEventFilter(root_window_.get()));
 }
 
+ShellAuraPlatformData::~ShellAuraPlatformData() {
+}
+
+void ShellAuraPlatformData::ResizeWindow(int width, int height) {
+  root_window_->SetHostSize(gfx::Size(width, height));
+}
+
 // static
 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+  CHECK(!platform_);
   aura::Env::CreateInstance();
+  platform_ = new ShellAuraPlatformData();
 }
 
 void Shell::PlatformExit() {
+  CHECK(platform_);
+  delete platform_;
+  platform_ = NULL;
   aura::Env::DeleteInstance();
 }
 
@@ -171,19 +181,25 @@
 }
 
 void Shell::PlatformCreateWindow(int width, int height) {
-  platform_.reset(new ShellAuraPlatformData());
-  platform_->CreateWindow(width, height);
+  CHECK(platform_);
+  platform_->ResizeWindow(width, height);
 }
 
 void Shell::PlatformSetContents() {
-  platform_->window()->AddChild(web_contents_->GetView()->GetNativeView());
-  web_contents_->GetView()->GetNativeView()->Show();
+  CHECK(platform_);
+  aura::Window* content = web_contents_->GetView()->GetNativeView();
+  aura::Window* parent = platform_->window();
+  if (parent->Contains(content))
+    return;
+  parent->AddChild(content);
+  content->Show();
 }
 
 void Shell::PlatformResizeSubViews() {
 }
 
 void Shell::Close() {
+  web_contents_.reset();
 }
 
 void Shell::PlatformSetTitle(const string16& title) {
diff --git a/content/shell/browser/shell_aura.h b/content/shell/browser/shell_aura.h
index cad7a30..f3f6692 100644
--- a/content/shell/browser/shell_aura.h
+++ b/content/shell/browser/shell_aura.h
@@ -12,6 +12,7 @@
 class DefaultActivationClient;
 class DefaultCaptureClient;
 class FocusClient;
+class WindowTreeClient;
 }
 class RootWindow;
 }
@@ -27,7 +28,7 @@
   ShellAuraPlatformData();
   ~ShellAuraPlatformData();
 
-  void CreateWindow(int width, int height);
+  void ResizeWindow(int width, int height);
 
   aura::RootWindow* window() { return root_window_.get(); }
 
@@ -36,6 +37,7 @@
   scoped_ptr<aura::client::FocusClient> focus_client_;
   scoped_ptr<aura::client::DefaultActivationClient> activation_client_;
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
+  scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
   scoped_ptr<ui::EventHandler> ime_filter_;
 
   DISALLOW_COPY_AND_ASSIGN(ShellAuraPlatformData);
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
index c6dbb99..8dee89a 100644
--- a/content/shell/browser/shell_browser_context.cc
+++ b/content/shell/browser/shell_browser_context.cc
@@ -179,6 +179,7 @@
 void ShellBrowserContext::RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) {
   // Always reject requests for LayoutTests for now.
@@ -191,6 +192,13 @@
   callback.Run(false);
 }
 
+void ShellBrowserContext::CancelMIDISysExPermissionRequest(
+    int render_process_id,
+    int render_view_id,
+    int bridge_id,
+    const GURL& requesting_frame) {
+}
+
 net::URLRequestContextGetter*
     ShellBrowserContext::CreateRequestContextForStoragePartition(
         const base::FilePath& partition_path,
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
index ec71591..f49fa28 100644
--- a/content/shell/browser/shell_browser_context.h
+++ b/content/shell/browser/shell_browser_context.h
@@ -46,8 +46,14 @@
   virtual void RequestMIDISysExPermission(
       int render_process_id,
       int render_view_id,
+      int bridge_id,
       const GURL& requesting_frame,
       const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual void CancelMIDISysExPermissionRequest(
+      int render_process_id,
+      int render_view_id,
+      int bridge_id,
+      const GURL& requesting_frame) OVERRIDE;
   virtual ResourceContext* GetResourceContext() OVERRIDE;
   virtual GeolocationPermissionContext*
       GetGeolocationPermissionContext() OVERRIDE;
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
index 688d6a7..6445cda 100644
--- a/content/shell/browser/shell_browser_main_parts.cc
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -4,6 +4,7 @@
 
 #include "content/shell/browser/shell_browser_main_parts.h"
 
+#include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -34,6 +35,7 @@
 #endif
 
 #if defined(OS_ANDROID)
+#include "components/breakpad/browser/crash_dump_manager_android.h"
 #include "net/android/network_change_notifier_factory_android.h"
 #include "net/base/network_change_notifier.h"
 #endif
@@ -42,6 +44,18 @@
 #include "ui/events/x/touch_factory_x11.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include "components/breakpad/app/breakpad_mac.h"
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "components/breakpad/app/breakpad_linux.h"
+#endif
+
+#if defined(OS_WIN)
+#include "components/breakpad/app/breakpad_win.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -114,6 +128,18 @@
 }
 
 void ShellBrowserMainParts::PreMainMessageLoopRun() {
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableCrashReporter)) {
+    breakpad::InitCrashReporter();
+#if defined(OS_ANDROID)
+    base::FilePath crash_dumps_dir =
+        CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+            switches::kCrashDumpsDir);
+    crash_dump_manager_.reset(new breakpad::CrashDumpManager(crash_dumps_dir));
+#endif
+  }
+#endif
   net_log_.reset(new ShellNetLog());
   browser_context_.reset(new ShellBrowserContext(false, net_log_.get()));
   off_the_record_browser_context_.reset(
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h
index 990e1c5..aa11dda 100644
--- a/content/shell/browser/shell_browser_main_parts.h
+++ b/content/shell/browser/shell_browser_main_parts.h
@@ -10,6 +10,12 @@
 #include "content/public/browser/browser_main_parts.h"
 #include "content/public/common/main_function_params.h"
 
+#if defined(OS_ANDROID)
+namespace breakpad {
+class CrashDumpManager;
+}
+#endif
+
 namespace base {
 class Thread;
 }
@@ -49,6 +55,9 @@
   net::NetLog* net_log() { return net_log_.get(); }
 
  private:
+#if defined(OS_ANDROID)
+  scoped_ptr<breakpad::CrashDumpManager> crash_dump_manager_;
+#endif
   scoped_ptr<net::NetLog> net_log_;
   scoped_ptr<ShellBrowserContext> browser_context_;
   scoped_ptr<ShellBrowserContext> off_the_record_browser_context_;
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 0facfae..17d03ba 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -4,6 +4,7 @@
 
 #include "content/shell/browser/shell_content_browser_client.h"
 
+#include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
@@ -35,10 +36,18 @@
 #if defined(OS_ANDROID)
 #include "base/android/path_utils.h"
 #include "base/path_service.h"
-#include "base/platform_file.h"
+#include "components/breakpad/browser/crash_dump_manager_android.h"
 #include "content/shell/android/shell_descriptors.h"
 #endif
 
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "base/debug/leak_annotations.h"
+#include "base/platform_file.h"
+#include "components/breakpad/app/breakpad_linux.h"
+#include "components/breakpad/browser/crash_handler_host_linux.h"
+#include "content/public/common/content_descriptors.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -46,6 +55,61 @@
 ShellContentBrowserClient* g_browser_client;
 bool g_swap_processes_for_redirect = false;
 
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
+    const std::string& process_type) {
+  base::FilePath dumps_path =
+      CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+          switches::kCrashDumpsDir);
+  {
+    ANNOTATE_SCOPED_MEMORY_LEAK;
+    breakpad::CrashHandlerHostLinux* crash_handler =
+        new breakpad::CrashHandlerHostLinux(
+            process_type, dumps_path, false);
+    crash_handler->StartUploaderThread();
+    return crash_handler;
+  }
+}
+
+int GetCrashSignalFD(const CommandLine& command_line) {
+  if (!breakpad::IsCrashReporterEnabled())
+    return -1;
+
+  std::string process_type =
+      command_line.GetSwitchValueASCII(switches::kProcessType);
+
+  if (process_type == switches::kRendererProcess) {
+    static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+    if (!crash_handler)
+      crash_handler = CreateCrashHandlerHost(process_type);
+    return crash_handler->GetDeathSignalSocket();
+  }
+
+  if (process_type == switches::kPluginProcess) {
+    static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+    if (!crash_handler)
+      crash_handler = CreateCrashHandlerHost(process_type);
+    return crash_handler->GetDeathSignalSocket();
+  }
+
+  if (process_type == switches::kPpapiPluginProcess) {
+    static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+    if (!crash_handler)
+      crash_handler = CreateCrashHandlerHost(process_type);
+    return crash_handler->GetDeathSignalSocket();
+  }
+
+  if (process_type == switches::kGpuProcess) {
+    static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+    if (!crash_handler)
+      crash_handler = CreateCrashHandlerHost(process_type);
+    return crash_handler->GetDeathSignalSocket();
+  }
+
+  return -1;
+}
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
+
 }  // namespace
 
 ShellContentBrowserClient* ShellContentBrowserClient::Get() {
@@ -146,6 +210,16 @@
     command_line->AppendSwitch(switches::kExposeInternalsForTesting);
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode))
     command_line->AppendSwitch(switches::kStableReleaseMode);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableCrashReporter)) {
+    command_line->AppendSwitch(switches::kEnableCrashReporter);
+  }
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) {
+    command_line->AppendSwitchPath(
+        switches::kCrashDumpsDir,
+        CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+            switches::kCrashDumpsDir));
+  }
 }
 
 void ShellContentBrowserClient::OverrideWebkitPrefs(
@@ -204,11 +278,12 @@
   return g_swap_processes_for_redirect;
 }
 
-#if defined(OS_ANDROID)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
     const CommandLine& command_line,
     int child_process_id,
     std::vector<content::FileDescriptorInfo>* mappings) {
+#if defined(OS_ANDROID)
   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
   base::FilePath pak_file;
   bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
@@ -225,8 +300,27 @@
   mappings->push_back(
       content::FileDescriptorInfo(kShellPakDescriptor,
                                   base::FileDescriptor(f, true)));
+
+  if (breakpad::IsCrashReporterEnabled()) {
+    f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
+        child_process_id);
+    if (f == base::kInvalidPlatformFileValue) {
+      LOG(ERROR) << "Failed to create file for minidump, crash reporting will "
+                 << "be disabled for this process.";
+    } else {
+      mappings->push_back(FileDescriptorInfo(kAndroidMinidumpDescriptor,
+                                             base::FileDescriptor(f, true)));
+    }
+  }
+#else  // !defined(OS_ANDROID)
+  int crash_signal_fd = GetCrashSignalFD(command_line);
+  if (crash_signal_fd >= 0) {
+    mappings->push_back(FileDescriptorInfo(
+        kCrashDumpSignal, base::FileDescriptor(crash_signal_fd, false)));
+  }
+#endif  // defined(OS_ANDROID)
 }
-#endif
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
 
 void ShellContentBrowserClient::Observe(int type,
                                         const NotificationSource& source,
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index b96b481..eb7bbe5 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -66,7 +66,7 @@
                                               const GURL& current_url,
                                               const GURL& new_url) OVERRIDE;
 
-#if defined(OS_ANDROID)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
   virtual void GetAdditionalMappedFilesForChildProcess(
       const CommandLine& command_line,
       int child_process_id,
diff --git a/content/shell/browser/shell_devtools_delegate.cc b/content/shell/browser/shell_devtools_delegate.cc
index 8e05bc3..d8fcfb5 100644
--- a/content/shell/browser/shell_devtools_delegate.cc
+++ b/content/shell/browser/shell_devtools_delegate.cc
@@ -21,7 +21,6 @@
 #include "content/public/common/url_constants.h"
 #include "content/shell/browser/shell.h"
 #include "grit/shell_resources.h"
-#include "net/base/escape.h"
 #include "net/socket/tcp_listen_socket.h"
 #include "ui/base/resource/resource_bundle.h"
 
@@ -102,7 +101,7 @@
   agent_host_ =
       DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost());
   id_ = agent_host_->GetId();
-  title_ = UTF16ToUTF8(net::EscapeForHTML(web_contents->GetTitle()));
+  title_ = UTF16ToUTF8(web_contents->GetTitle());
   url_ = web_contents->GetURL();
   content::NavigationController& controller = web_contents->GetController();
   content::NavigationEntry* entry = controller.GetActiveEntry();
@@ -167,9 +166,10 @@
   return std::string();
 }
 
-scoped_ptr<DevToolsTarget> ShellDevToolsDelegate::CreateNewTarget() {
+scoped_ptr<DevToolsTarget>
+ShellDevToolsDelegate::CreateNewTarget(const GURL& url) {
   Shell* shell = Shell::CreateNewWindow(browser_context_,
-                                        GURL(kAboutBlankURL),
+                                        url,
                                         NULL,
                                         MSG_ROUTING_NONE,
                                         gfx::Size());
diff --git a/content/shell/browser/shell_devtools_delegate.h b/content/shell/browser/shell_devtools_delegate.h
index f0da850..f200ed1 100644
--- a/content/shell/browser/shell_devtools_delegate.h
+++ b/content/shell/browser/shell_devtools_delegate.h
@@ -27,7 +27,7 @@
   virtual bool BundlesFrontendResources() OVERRIDE;
   virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
   virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE;
-  virtual scoped_ptr<DevToolsTarget> CreateNewTarget() OVERRIDE;
+  virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) OVERRIDE;
   virtual void EnumerateTargets(TargetCallback callback) OVERRIDE;
   virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
       net::StreamListenSocket::Delegate* delegate,
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc
index aa6afe1..a25dc38 100644
--- a/content/shell/browser/shell_devtools_frontend.cc
+++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -21,8 +21,6 @@
 
 namespace content {
 
-namespace {
-
 // DevTools frontend path for inspector LayoutTests.
 GURL GetDevToolsPathAsURL() {
   base::FilePath dir_exe;
@@ -41,8 +39,6 @@
   return net::FilePathToFileURL(dev_tools_path);
 }
 
-}  // namespace
-
 // static
 ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
     WebContents* inspected_contents) {
diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h
index 09a690a..ca11100 100644
--- a/content/shell/browser/shell_devtools_frontend.h
+++ b/content/shell/browser/shell_devtools_frontend.h
@@ -16,6 +16,8 @@
 
 namespace content {
 
+GURL GetDevToolsPathAsURL();
+
 class RenderViewHost;
 class Shell;
 class WebContents;
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc
index 7d8309a..a0f633a 100644
--- a/content/shell/browser/shell_views.cc
+++ b/content/shell/browser/shell_views.cc
@@ -361,7 +361,7 @@
   window_ = window_widget_->GetNativeWindow();
   // Call ShowRootWindow on RootWindow created by MinimalShell without
   // which XWindow owned by RootWindow doesn't get mapped.
-  window_->GetRootWindow()->ShowRootWindow();
+  window_->GetDispatcher()->ShowRootWindow();
   window_widget_->Show();
 }
 
diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc
index 434a2f9..90196e6 100644
--- a/content/shell/browser/webkit_test_controller.cc
+++ b/content/shell/browser/webkit_test_controller.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -21,12 +22,14 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/common/content_switches.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_frontend.h"
 #include "content/shell/common/shell_messages.h"
 #include "content/shell/common/shell_switches.h"
 #include "content/shell/common/webkit_test_helpers.h"
@@ -565,6 +568,12 @@
 }
 
 void WebKitTestController::OnShowDevTools() {
+  ShellBrowserContext* browser_context =
+      ShellContentBrowserClient::Get()->browser_context();
+  StoragePartition* storage_partition =
+      BrowserContext::GetStoragePartition(browser_context, NULL);
+  storage_partition->GetDOMStorageContext()->DeleteLocalStorage(
+      content::GetDevToolsPathAsURL().GetOrigin());
   main_window_->ShowDevTools();
 }
 
diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h
index eb54a7c..06bd7df 100644
--- a/content/shell/browser/webkit_test_controller.h
+++ b/content/shell/browser/webkit_test_controller.h
@@ -15,7 +15,6 @@
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/render_view_host_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/gfx/size.h"
 #include "webkit/common/webpreferences.h"
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index a00af45..dcd66a5 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -18,6 +18,9 @@
 // Makes Content Shell use the given path for its data directory.
 const char kContentShellDataPath[] = "data-path";
 
+// The directory breakpad should store minidumps in.
+const char kCrashDumpsDir[] = "crash-dumps-dir";
+
 // Request pages to be dumped as text once they finished loading.
 const char kDumpRenderTree[] = "dump-render-tree";
 
@@ -31,9 +34,6 @@
 // and debugging of layout tests that rely on it.
 const char kExposeInternalsForTesting[]     = "expose-internals-for-testing";
 
-// Save results when layout-as-browser tests fail.
-const char kOutputLayoutTestDifferences[] = "output-layout-test-differences";
-
 // This makes us disable some web-platform runtime features so that we test
 // content_shell as if it was a stable release. It is only followed when
 // kDumpRenderTree is set. For the features' level, see
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index d6b936a..72797f8 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -13,11 +13,11 @@
 extern const char kCheckLayoutTestSysDeps[];
 extern const char kContentBrowserTest[];
 extern const char kContentShellDataPath[];
+extern const char kCrashDumpsDir[];
 extern const char kDumpRenderTree[];
 extern const char kEnableAccelerated2DCanvas[];
 extern const char kEncodeBinary[];
 extern const char kExposeInternalsForTesting[];
-extern const char kOutputLayoutTestDifferences[];
 extern const char kStableReleaseMode[];
 
 }  // namespace switches
diff --git a/content/shell/renderer/webkit_test_runner.cc b/content/shell/renderer/webkit_test_runner.cc
index 0c8ce06..627a8b1 100644
--- a/content/shell/renderer/webkit_test_runner.cc
+++ b/content/shell/renderer/webkit_test_runner.cc
@@ -349,8 +349,8 @@
       domain.c_str(), code, error.unreachableURL.spec().data());
 }
 
-void WebKitTestRunner::setClientWindowRect(const WebRect& rect) {
-  ForceResizeRenderView(render_view(), WebSize(rect.width, rect.height));
+void WebKitTestRunner::useUnfortunateSynchronousResizeMode(bool enable) {
+  UseSynchronousResizeMode(render_view(), enable);
 }
 
 void WebKitTestRunner::enableAutoResizeMode(const WebSize& min_size,
@@ -589,8 +589,6 @@
   render_view()->GetWebView()->mainFrame()->clearOpener();
   render_view()->GetWebView()->setPageScaleFactorLimits(-1, -1);
   render_view()->GetWebView()->setPageScaleFactor(1, WebPoint(0, 0));
-  render_view()->GetWebView()->enableFixedLayoutMode(false);
-  render_view()->GetWebView()->setFixedLayoutSize(WebSize(0, 0));
 
   // Resetting the internals object also overrides the WebPreferences, so we
   // have to sync them to WebKit again.
diff --git a/content/shell/renderer/webkit_test_runner.h b/content/shell/renderer/webkit_test_runner.h
index de8d48f..6f40bfd 100644
--- a/content/shell/renderer/webkit_test_runner.h
+++ b/content/shell/renderer/webkit_test_runner.h
@@ -70,7 +70,7 @@
   virtual ::WebTestRunner::WebPreferences* preferences();
   virtual void applyPreferences();
   virtual std::string makeURLErrorDescription(const WebKit::WebURLError& error);
-  virtual void setClientWindowRect(const WebKit::WebRect& rect);
+  virtual void useUnfortunateSynchronousResizeMode(bool enable);
   virtual void enableAutoResizeMode(const WebKit::WebSize& min_size,
                                     const WebKit::WebSize& max_size);
   virtual void disableAutoResizeMode(const WebKit::WebSize& new_size);
diff --git a/content/shell/tools/DEPS b/content/shell/tools/DEPS
new file mode 100644
index 0000000..7083ae7
--- /dev/null
+++ b/content/shell/tools/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public",
+  "+components/breakpad",
+]
diff --git a/content/shell/tools/content_shell_crash_service.cc b/content/shell/tools/content_shell_crash_service.cc
new file mode 100644
index 0000000..3b82d1b
--- /dev/null
+++ b/content/shell/tools/content_shell_crash_service.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <stdlib.h>
+#include <tchar.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "components/breakpad/tools/crash_service.h"
+
+int __stdcall wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd_line,
+                       int show_mode) {
+  // Manages the destruction of singletons.
+  base::AtExitManager exit_manager;
+
+  CommandLine::Init(0, NULL);
+
+  // Logging to stderr.
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  // Logging with pid, tid and timestamp.
+  logging::SetLogItems(true, true, true, false);
+
+  VLOG(1) << "session start. cmdline is [" << cmd_line << "]";
+
+  breakpad::CrashService crash_service;
+  if (!crash_service.Initialize(base::FilePath(), base::FilePath()))
+    return 1;
+
+  VLOG(1) << "ready to process crash requests";
+
+  // Enter the message loop.
+  int retv = crash_service.ProcessingLoop();
+  // Time to exit.
+  VLOG(1) << "session end. return code is " << retv;
+  return retv;
+}
diff --git a/content/speech_recognition_error_java.target.darwin-arm.mk b/content/speech_recognition_error_java.target.darwin-arm.mk
index aff8270..c056165 100644
--- a/content/speech_recognition_error_java.target.darwin-arm.mk
+++ b/content/speech_recognition_error_java.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/speech_recognition_error_java.target.darwin-mips.mk b/content/speech_recognition_error_java.target.darwin-mips.mk
index 4df9536..5b66a90 100644
--- a/content/speech_recognition_error_java.target.darwin-mips.mk
+++ b/content/speech_recognition_error_java.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/speech_recognition_error_java.target.darwin-x86.mk b/content/speech_recognition_error_java.target.darwin-x86.mk
index 0a8438c..7e19785 100644
--- a/content/speech_recognition_error_java.target.darwin-x86.mk
+++ b/content/speech_recognition_error_java.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/speech_recognition_error_java.target.linux-arm.mk b/content/speech_recognition_error_java.target.linux-arm.mk
index aff8270..c056165 100644
--- a/content/speech_recognition_error_java.target.linux-arm.mk
+++ b/content/speech_recognition_error_java.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/speech_recognition_error_java.target.linux-mips.mk b/content/speech_recognition_error_java.target.linux-mips.mk
index 4df9536..5b66a90 100644
--- a/content/speech_recognition_error_java.target.linux-mips.mk
+++ b/content/speech_recognition_error_java.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/speech_recognition_error_java.target.linux-x86.mk b/content/speech_recognition_error_java.target.linux-x86.mk
index 0a8438c..7e19785 100644
--- a/content/speech_recognition_error_java.target.linux-x86.mk
+++ b/content/speech_recognition_error_java.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/content/test/content_browser_test.cc b/content/test/content_browser_test.cc
index 32ca2f0..46402cc 100644
--- a/content/test/content_browser_test.cc
+++ b/content/test/content_browser_test.cc
@@ -26,6 +26,10 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #endif
 
+#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(USE_X11)
+#include "ui/base/ime/input_method_initializer.h"
+#endif
+
 namespace content {
 
 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, MANUAL_ShouldntRun) {
@@ -85,10 +89,9 @@
                                  subprocess_path);
 #endif
 
-  // NOTE: should be kept in sync with
-  // chrome/browser/resources/software_rendering_list.json
-#if !defined(OS_WIN) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-  command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+  // LinuxInputMethodContextFactory has to be initialized.
+#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(USE_X11)
+  ui::InitializeInputMethodForTesting();
 #endif
 
   BrowserTestBase::SetUp();
@@ -97,6 +100,11 @@
 void ContentBrowserTest::TearDown() {
   BrowserTestBase::TearDown();
 
+  // LinuxInputMethodContextFactory has to be shutdown.
+#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(USE_X11)
+  ui::ShutdownInputMethodForTesting();
+#endif
+
   shell_main_delegate_.reset();
 }
 
diff --git a/content/test/content_test_launcher.cc b/content/test/content_test_launcher.cc
index 9a229a9..fae46c8 100644
--- a/content/test/content_test_launcher.cc
+++ b/content/test/content_test_launcher.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "base/sys_info.h"
 #include "base/test/test_suite.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/content_test_suite_base.h"
@@ -127,6 +128,7 @@
 }  // namespace content
 
 int main(int argc, char** argv) {
+  int default_jobs = std::max(1, base::SysInfo::NumberOfProcessors() / 2);
   content::ContentTestLauncherDelegate launcher_delegate;
-  return LaunchTests(&launcher_delegate, argc, argv);
+  return LaunchTests(&launcher_delegate, default_jobs, argc, argv);
 }
diff --git a/content/test/data/device_orientation/device_inertial_sensor_diagnostics.html b/content/test/data/device_orientation/device_inertial_sensor_diagnostics.html
index 0becdd5..796357d 100644
--- a/content/test/data/device_orientation/device_inertial_sensor_diagnostics.html
+++ b/content/test/data/device_orientation/device_inertial_sensor_diagnostics.html
@@ -52,6 +52,10 @@
         <td id="orientationValues"></td>
       </tr>
       <tr>
+        <td>orientation absolute</td>
+        <td id="orientationAbsolute"></td>
+      </tr>
+      <tr>
         <td>orientation frequency (Hz)</td>
         <td id="orientationFreq"></td>
       </tr>
@@ -101,6 +105,7 @@
       function onOrientation(event) {
         document.getElementById("orientationValues").innerHTML =
             roundToFixedArray([event.alpha, event.beta, event.gamma]);
+        document.getElementById("orientationAbsolute").innerHTML = event.absolute;
         ++numberOrientationEvents;
       }
 
diff --git a/content/test/gpu/gpu_tests/gpu_process.py b/content/test/gpu/gpu_tests/gpu_process.py
new file mode 100644
index 0000000..3143e42
--- /dev/null
+++ b/content/test/gpu/gpu_tests/gpu_process.py
@@ -0,0 +1,47 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import gpu_process_expectations as expectations
+
+from telemetry import test
+from telemetry.page import page_set
+from telemetry.page import page_test
+
+test_harness_script = r"""
+  var domAutomationController = {};
+  domAutomationController._finished = false;
+  domAutomationController.setAutomationId = function(id) {}
+  domAutomationController.send = function(msg) {
+    domAutomationController._finished = true;
+  }
+
+  window.domAutomationController = domAutomationController;
+"""
+
+class GpuProcessValidator(page_test.PageTest):
+  def __init__(self):
+    super(GpuProcessValidator, self).__init__('ValidatePage',
+        needs_browser_restart_after_each_run=True)
+
+  def CustomizeBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
+
+  def ValidatePage(self, page, tab, results):
+    has_gpu_process_js = 'chrome.gpuBenchmarking.hasGpuProcess()'
+    has_gpu_process = tab.EvaluateJavaScript(has_gpu_process_js)
+    if not has_gpu_process:
+      raise page_test.Failure('No GPU process detected')
+
+class GpuProcess(test.Test):
+  """Tests that accelerated content triggers the creation of a GPU process"""
+  test = GpuProcessValidator
+  page_set = 'page_sets/gpu_process_tests.json'
+
+  def CreateExpectations(self, page_set):
+    return expectations.GpuProcessExpectations()
+
+  def CreatePageSet(self, options):
+    page_set = super(GpuProcess, self).CreatePageSet(options)
+    for page in page_set.pages:
+      page.script_to_evaluate_on_commit = test_harness_script
+    return page_set
diff --git a/content/test/gpu/gpu_tests/gpu_process_expectations.py b/content/test/gpu/gpu_tests/gpu_process_expectations.py
new file mode 100644
index 0000000..e5a765c
--- /dev/null
+++ b/content/test/gpu/gpu_tests/gpu_process_expectations.py
@@ -0,0 +1,26 @@
+# Copyright 2013 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.
+
+from telemetry.page import test_expectations as expectations
+
+# Valid expectation conditions are:
+#
+# Operating systems:
+#     win, xp, vista, win7, mac, leopard, snowleopard, lion, mountainlion,
+#     linux, chromeos, android
+#
+# GPU vendors:
+#     amd, arm, broadcom, hisilicon, intel, imagination, nvidia, qualcomm,
+#     vivante
+#
+# Specific GPUs can be listed as a tuple with vendor name and device ID.
+# Examples: ('nvidia', 0x1234), ('arm', 'Mali-T604')
+# Device IDs must be paired with a GPU vendor.
+
+class GpuProcessExpectations(expectations.TestExpectations):
+  def SetExpectations(self):
+    # Accelerated 2D canvas is not available on Linux due to driver instability
+    self.Fail('GpuProcess.canvas2d', ['linux'], bug=254724)
+
+    self.Fail('GpuProcess.video', ['linux'], bug=257109)
diff --git a/content/test/gpu/gpu_tests/hardware_accelerated_feature.py b/content/test/gpu/gpu_tests/hardware_accelerated_feature.py
new file mode 100644
index 0000000..a584fa9
--- /dev/null
+++ b/content/test/gpu/gpu_tests/hardware_accelerated_feature.py
@@ -0,0 +1,69 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import hardware_accelerated_feature_expectations as expectations
+
+from telemetry import test
+from telemetry.page import page_set
+from telemetry.page import page_test
+
+test_harness_script = r"""
+  function VerifyHardwareAccelerated(feature) {
+    feature += ': '
+    var list = document.querySelector('.feature-status-list');
+    for (var i=0; i < list.childElementCount; i++) {
+      var span_list = list.children[i].getElementsByTagName('span');
+      var feature_str = span_list[0].textContent;
+      var value_str = span_list[1].textContent;
+      if ((feature_str == feature) &&
+          (value_str == 'Hardware accelerated')) {
+        return true;
+      }
+    }
+    return false;
+  };
+""";
+
+class HardwareAcceleratedFeatureValidator(page_test.PageTest):
+  def __init__(self):
+    super(HardwareAcceleratedFeatureValidator, self).__init__('ValidatePage')
+
+  def ValidatePage(self, page, tab, results):
+    feature = page.feature
+    if not tab.EvaluateJavaScript('VerifyHardwareAccelerated("%s")' % feature):
+      raise page_test.Failure('%s not hardware accelerated' % feature)
+
+def safe_feature_name(feature):
+  return feature.lower().replace(' ', '_')
+
+class HardwareAcceleratedFeature(test.Test):
+  """Tests GPU acceleration is reported as active for various features"""
+  test = HardwareAcceleratedFeatureValidator
+
+  def CreateExpectations(self, page_set):
+    return expectations.HardwareAcceleratedFeatureExpectations()
+
+  def CreatePageSet(self, options):
+    features = ['WebGL', 'Canvas', '3D CSS']
+
+    page_set_dict = {
+      'description': 'Tests GPU acceleration is reported as active',
+      'user_agent_type': 'desktop',
+      'pages': []
+    }
+
+    pages = page_set_dict['pages']
+
+    for feature in features:
+      pages.append({
+        'name': 'HardwareAcceleratedFeature.%s_accelerated' %
+            safe_feature_name(feature),
+        'url': 'chrome://gpu',
+        'navigate_steps': [
+          { "action": 'navigate' }
+        ],
+        'script_to_evaluate_on_commit': test_harness_script,
+        'feature': feature
+      })
+
+    return page_set.PageSet.FromDict(page_set_dict, '')
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/hardware_accelerated_feature_expectations.py b/content/test/gpu/gpu_tests/hardware_accelerated_feature_expectations.py
new file mode 100644
index 0000000..a301593
--- /dev/null
+++ b/content/test/gpu/gpu_tests/hardware_accelerated_feature_expectations.py
@@ -0,0 +1,25 @@
+# Copyright 2013 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.
+
+from telemetry.page import test_expectations as expectations
+
+# Valid expectation conditions are:
+#
+# Operating systems:
+#     win, xp, vista, win7, mac, leopard, snowleopard, lion, mountainlion,
+#     linux, chromeos, android
+#
+# GPU vendors:
+#     amd, arm, broadcom, hisilicon, intel, imagination, nvidia, qualcomm,
+#     vivante
+#
+# Specific GPUs can be listed as a tuple with vendor name and device ID.
+# Examples: ('nvidia', 0x1234), ('arm', 'Mali-T604')
+# Device IDs must be paired with a GPU vendor.
+
+class HardwareAcceleratedFeatureExpectations(expectations.TestExpectations):
+  def SetExpectations(self):
+    # Accelerated 2D canvas is not available on Linux due to driver instability
+    self.Fail('HardwareAcceleratedFeature.canvas_accelerated',
+        ['linux'], bug=254724)
diff --git a/content/test/gpu/gpu_tests/memory.py b/content/test/gpu/gpu_tests/memory.py
new file mode 100644
index 0000000..c83d7b7
--- /dev/null
+++ b/content/test/gpu/gpu_tests/memory.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2012 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.
+from telemetry import test
+from telemetry.page import page_test
+
+MEMORY_LIMIT_MB = 256
+SINGLE_TAB_LIMIT_MB = 128
+WIGGLE_ROOM_MB = 4
+
+test_harness_script = r"""
+  var domAutomationController = {};
+  domAutomationController._finished = false;
+
+  domAutomationController.send = function(msg) {
+    // This should wait until all effects of memory management complete.
+    // We will need to wait until all
+    // 1. pending commits from the main thread to the impl thread in the
+    //    compositor complete (for visible compositors).
+    // 2. allocations that the renderer's impl thread will make due to the
+    //    compositor and WebGL are completed.
+    // 3. pending GpuMemoryManager::Manage() calls to manage are made.
+    // 4. renderers' OnMemoryAllocationChanged callbacks in response to
+    //    manager are made.
+    // Each step in this sequence can cause trigger the next (as a 1-2-3-4-1
+    // cycle), so we will need to pump this cycle until it stabilizes.
+
+    // Pump the cycle 8 times (in principle it could take an infinite number
+    // of iterations to settle).
+
+    var rafCount = 0;
+    var totalRafCount = 8;
+
+    function pumpRAF() {
+      if (rafCount == totalRafCount) {
+        domAutomationController._finished = true;
+        return;
+      }
+      ++rafCount;
+      window.requestAnimationFrame(pumpRAF);
+    }
+    pumpRAF();
+  }
+
+  window.domAutomationController = domAutomationController;
+
+  window.addEventListener("load", function() {
+    useGpuMemory(%d);
+  }, false);
+""" % MEMORY_LIMIT_MB
+
+class MemoryValidator(page_test.PageTest):
+  def __init__(self):
+    super(MemoryValidator, self).__init__('ValidatePage')
+
+  def ValidatePage(self, page, tab, results):
+    mb_used = MemoryValidator.GpuMemoryUsageMbytes(tab)
+
+    if mb_used + WIGGLE_ROOM_MB < SINGLE_TAB_LIMIT_MB:
+      raise page_test.Failure('Memory allocation too low')
+
+    if mb_used - WIGGLE_ROOM_MB > MEMORY_LIMIT_MB:
+      raise page_test.Failure('Memory allocation too high')
+
+  @staticmethod
+  def GpuMemoryUsageMbytes(tab):
+    gpu_rendering_stats_js = 'chrome.gpuBenchmarking.gpuRenderingStats()'
+    gpu_rendering_stats = tab.EvaluateJavaScript(gpu_rendering_stats_js)
+    return gpu_rendering_stats['globalVideoMemoryBytesAllocated'] / 1048576
+
+  def CustomizeBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs('--enable-logging')
+    options.AppendExtraBrowserArgs(
+        '--force-gpu-mem-available-mb=%s' % MEMORY_LIMIT_MB)
+    options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
+
+class Memory(test.Test):
+  """Tests GPU memory limits"""
+  test = MemoryValidator
+  page_set = 'page_sets/memory_tests.json'
+
+  def CreatePageSet(self, options):
+    page_set = super(Memory, self).CreatePageSet(options)
+    for page in page_set.pages:
+      page.script_to_evaluate_on_commit = test_harness_script
+    return page_set
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/pixel.py b/content/test/gpu/gpu_tests/pixel.py
index ed7d4af..4df18f1 100644
--- a/content/test/gpu/gpu_tests/pixel.py
+++ b/content/test/gpu/gpu_tests/pixel.py
@@ -10,7 +10,6 @@
 from telemetry import test
 from telemetry.core.backends import png_bitmap
 from telemetry.page import page_test
-from telemetry.page import test_expectations
 
 test_data_dir = os.path.abspath(os.path.join(
     os.path.dirname(__file__), '..', '..', 'data', 'gpu'))
@@ -37,7 +36,6 @@
   }
 
   window.domAutomationController = domAutomationController;
-  console.log("Harness injected.");
 """
 
 class PixelTestFailure(Exception):
@@ -129,6 +127,11 @@
     full_image_name = img_name + '_' + str(build_revision)
     full_image_name = full_image_name + '.png'
 
+    # Save the reference image
+    # This ensures that we get the right revision number
+    PixelValidator.WriteImage(
+        os.path.join(img_dir, full_image_name), ref_png)
+
     PixelValidator.WriteImage(
         os.path.join(img_dir, 'FAIL_' + full_image_name), screenshot)
 
@@ -145,7 +148,6 @@
     png_image.WriteFile(image_path)
 
 class Pixel(test.Test):
-  enabled = False
   test = PixelValidator
   page_set = 'page_sets/pixel_tests.json'
 
@@ -164,9 +166,8 @@
         default="unknownrev")
     parser.add_option_group(group)
 
-  def CreateExpectations(self, page_set):
-    print page_set.pages
+  def CreatePageSet(self, options):
+    page_set = super(Pixel, self).CreatePageSet(options)
     for page in page_set.pages:
       page.script_to_evaluate_on_commit = test_harness_script
-
-    return test_expectations.TestExpectations()
+    return page_set
diff --git a/content/test/gpu/gpu_tests/webgl_conformance.py b/content/test/gpu/gpu_tests/webgl_conformance.py
index a575502..3ac7dca 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance.py
@@ -48,7 +48,6 @@
 
   window.webglTestHarness = testHarness;
   window.parent.webglTestHarness = testHarness;
-  console.log("Harness injected.");
   window.console.log = testHarness.log;
 """
 
@@ -73,7 +72,6 @@
 
 class WebglConformance(test_module.Test):
   """Conformance with Khronos WebGL Conformance Tests"""
-  enabled = False
   test = WebglConformanceValidator
 
   @staticmethod
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 4d0e73f..9706705 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -140,3 +140,7 @@
     # Android failures
     self.Fail('conformance/textures/texture-npot-video.html',
         ['android'], bug=306485)
+    # The following test is very slow and therefore times out on Android bot.
+    self.Skip('conformance/rendering/multisample-corruption.html',
+        ['android'])
+
diff --git a/content/test/gpu/gpu_tests/webgl_robustness.py b/content/test/gpu/gpu_tests/webgl_robustness.py
index 4cdc4cb..7e4a302 100644
--- a/content/test/gpu/gpu_tests/webgl_robustness.py
+++ b/content/test/gpu/gpu_tests/webgl_robustness.py
@@ -45,7 +45,6 @@
 
 
 class WebglRobustness(test.Test):
-  enabled = False
   test = WebglConformanceValidator
 
   def CreatePageSet(self, options):
diff --git a/content/test/gpu/page_sets/gpu_process_tests.json b/content/test/gpu/page_sets/gpu_process_tests.json
new file mode 100644
index 0000000..67bac7e
--- /dev/null
+++ b/content/test/gpu/page_sets/gpu_process_tests.json
@@ -0,0 +1,40 @@
+{
+  "description": "Tests that accelerated content triggers the creation of a GPU process",
+  "user_agent_type": "desktop",
+  "serving_dirs": [ "../../data" ],
+  "pages": [
+    {
+      "name": "GpuProcess.canvas2d",
+      "url": "file://../../data/gpu/functional_canvas_demo.html",
+      "navigate_steps": [
+        { "action": "navigate"}
+      ]
+    },
+    {
+      "name": "GpuProcess.css3d",
+      "url": "file://../../data/gpu/functional_3d_css.html",
+      "navigate_steps": [
+        { "action": "navigate"}
+      ]
+    },
+    {
+      "name": "GpuProcess.webgl",
+      "url": "file://../../data/gpu/functional_webgl.html",
+      "navigate_steps": [
+        { "action": "navigate"}
+      ]
+    },
+    {
+      "name": "GpuProcess.video",
+      "url": "file://../../data/gpu/functional_video.html",
+      "navigate_steps": [
+        { "action": "navigate"},
+        {
+          "action": "wait",
+          "javascript": "domAutomationController._finished",
+          "timeout": 30
+        }
+      ]
+    }
+  ]
+}
diff --git a/content/test/gpu/page_sets/memory_tests.json b/content/test/gpu/page_sets/memory_tests.json
new file mode 100644
index 0000000..9a29aab
--- /dev/null
+++ b/content/test/gpu/page_sets/memory_tests.json
@@ -0,0 +1,18 @@
+{
+  "description": "Tests that validate GPU memory management",
+  "user_agent_type": "desktop",
+  "pages": [
+    {
+      "name": "Memory.CSS3D",
+      "url": "file://../../data/gpu/mem_css3d.html",
+      "navigate_steps": [
+        { "action": "navigate" },
+        {
+          "action": "wait",
+          "javascript": "domAutomationController._finished",
+          "timeout": 60
+        }
+      ]
+    }
+  ]
+}
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index ad03eed..dccc77b 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -53,16 +53,20 @@
   return render_view_proxy;
 }
 
+WebTestProxyBase* GetWebTestProxyBase(RenderViewImpl* render_view) {
+  typedef WebTestProxy<RenderViewImpl, RenderViewImplParams*> ViewProxy;
+
+  ViewProxy* render_view_proxy = static_cast<ViewProxy*>(render_view);
+  return static_cast<WebTestProxyBase*>(render_view_proxy);
+}
+
 RenderFrameImpl* CreateWebFrameTestProxy(
     RenderViewImpl* render_view,
     int32 routing_id) {
-  typedef WebTestProxy<RenderViewImpl, RenderViewImplParams*> ViewProxy;
   typedef WebFrameTestProxy<RenderFrameImpl, RenderViewImpl*, int32> FrameProxy;
 
-  ViewProxy* render_view_proxy = static_cast<ViewProxy*>(render_view);
-  WebTestProxyBase* base = static_cast<WebTestProxyBase*>(render_view_proxy);
   FrameProxy* render_frame_proxy = new FrameProxy(render_view, routing_id);
-  render_frame_proxy->setBaseProxy(base);
+  render_frame_proxy->setBaseProxy(GetWebTestProxyBase(render_view));
   render_frame_proxy->setVersion(3);
 
   return render_frame_proxy;
@@ -106,8 +110,8 @@
 }
 
 int GetLocalSessionHistoryLength(RenderView* render_view) {
-  return static_cast<RenderViewImpl*>(render_view)
-      ->GetLocalSessionHistoryLengthForTesting();
+  return static_cast<RenderViewImpl*>(render_view)->
+      GetLocalSessionHistoryLengthForTesting();
 }
 
 void SyncNavigationState(RenderView* render_view) {
@@ -115,34 +119,37 @@
 }
 
 void SetFocusAndActivate(RenderView* render_view, bool enable) {
-  static_cast<RenderViewImpl*>(render_view)
-      ->SetFocusAndActivateForTesting(enable);
+  static_cast<RenderViewImpl*>(render_view)->
+      SetFocusAndActivateForTesting(enable);
 }
 
 void ForceResizeRenderView(RenderView* render_view,
                            const WebSize& new_size) {
   RenderViewImpl* render_view_impl = static_cast<RenderViewImpl*>(render_view);
-  render_view_impl->setWindowRect(WebRect(render_view_impl->rootWindowRect().x,
-                                          render_view_impl->rootWindowRect().y,
-                                          new_size.width,
-                                          new_size.height));
+  render_view_impl->ForceResizeForTesting(new_size);
+  GetWebTestProxyBase(render_view_impl)->didForceResize();
 }
 
 void SetDeviceScaleFactor(RenderView* render_view, float factor) {
-  static_cast<RenderViewImpl*>(render_view)
-      ->SetDeviceScaleFactorForTesting(factor);
+  static_cast<RenderViewImpl*>(render_view)->
+      SetDeviceScaleFactorForTesting(factor);
+}
+
+void UseSynchronousResizeMode(RenderView* render_view, bool enable) {
+  static_cast<RenderViewImpl*>(render_view)->
+      UseSynchronousResizeModeForTesting(enable);
 }
 
 void EnableAutoResizeMode(RenderView* render_view,
                           const WebSize& min_size,
                           const WebSize& max_size) {
-  static_cast<RenderViewImpl*>(render_view)
-      ->EnableAutoResizeForTesting(min_size, max_size);
+  static_cast<RenderViewImpl*>(render_view)->
+      EnableAutoResizeForTesting(min_size, max_size);
 }
 
 void DisableAutoResizeMode(RenderView* render_view, const WebSize& new_size) {
-  static_cast<RenderViewImpl*>(render_view)
-      ->DisableAutoResizeForTesting(new_size);
+  static_cast<RenderViewImpl*>(render_view)->
+      DisableAutoResizeForTesting(new_size);
 }
 
 void UseMockMediaStreams(RenderView* render_view) {
diff --git a/content/test/run_all_perftests.cc b/content/test/run_all_perftests.cc
new file mode 100644
index 0000000..d3d1d3a
--- /dev/null
+++ b/content/test/run_all_perftests.cc
@@ -0,0 +1,16 @@
+// Copyright 2013 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/public/test/unittest_test_suite.h"
+#include "content/test/content_test_suite.h"
+
+int main(int argc, char** argv) {
+  content::UnitTestTestSuite test_suite(
+      new content::ContentTestSuite(argc, argv));
+
+  // Always run the perf tests serially, to avoid distorting
+  // perf measurements with randomness resulting from running
+  // in parallel.
+  return test_suite.Run();
+}
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index a5e3a81..15d8a6a 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -7,10 +7,10 @@
 #include <utility>
 
 #include "content/browser/browser_url_handler_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/test_render_view_host.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/navigation_entry_impl.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_source.h"
diff --git a/content/test/web_layer_tree_view_impl_for_testing.cc b/content/test/web_layer_tree_view_impl_for_testing.cc
index 1bf4ee5..7545795 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.cc
+++ b/content/test/web_layer_tree_view_impl_for_testing.cc
@@ -20,6 +20,7 @@
 #include "third_party/WebKit/public/platform/WebLayerTreeView.h"
 #include "third_party/WebKit/public/platform/WebRenderingStats.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
+#include "ui/gfx/frame_time.h"
 #include "webkit/common/gpu/test_context_provider_factory.h"
 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
 
@@ -44,7 +45,7 @@
 
   // Accelerated animations are enabled for unit tests.
   settings.accelerated_animation_enabled = true;
-  layer_tree_host_ = cc::LayerTreeHost::Create(this, settings, NULL);
+  layer_tree_host_ = cc::LayerTreeHost::Create(this, NULL, settings, NULL);
   if (!layer_tree_host_)
     return false;
   return true;
@@ -127,7 +128,7 @@
 }
 
 void WebLayerTreeViewImplForTesting::composite() {
-  layer_tree_host_->Composite(base::TimeTicks::Now());
+  layer_tree_host_->Composite(gfx::FrameTime::Now());
 }
 
 void WebLayerTreeViewImplForTesting::didStopFlinging() {}
diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h
index 1b1157b..8811ac0 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.h
+++ b/content/test/web_layer_tree_view_impl_for_testing.h
@@ -57,8 +57,8 @@
       WebKit::WebRenderingStats& stats) const;  // NOLINT(runtime/references)
 
   // cc::LayerTreeHostClient implementation.
-  virtual void WillBeginFrame() OVERRIDE {}
-  virtual void DidBeginFrame() OVERRIDE {}
+  virtual void WillBeginMainFrame() OVERRIDE {}
+  virtual void DidBeginMainFrame() OVERRIDE {}
   virtual void Animate(double frame_begin_time) OVERRIDE {}
   virtual void Layout() OVERRIDE;
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float page_scale)
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index c93c1ec..29fd01b 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -17,6 +17,12 @@
 #include "sandbox/win/src/sandbox.h"
 #endif
 
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+
+#include "ui/gfx/gtk_util.h"
+#endif
+
 namespace content {
 
 // Mainline routine for running as the utility process.
@@ -26,10 +32,40 @@
   base::PlatformThread::SetName("CrUtilityMain");
 
 #if defined(OS_LINUX)
-  // Initialize the sandbox before any thread is created.
+  // Initializes the sandbox before any threads are created.
+  // TODO(jorgelo): move this after GTK initialization when we enable a strict
+  // Seccomp-BPF policy.
   LinuxSandbox::InitializeSandbox();
 #endif
 
+#if defined(OS_POSIX)
+  // The utility process is used to load plugins (see OnLoadPlugins() in
+  // utility_thread_impl.cc). Some plugins expect the browser to have loaded
+  // GLib/GTK.
+  // Due to bugs in GLib we need to initialize GLib/GTK before we start threads,
+  // see crbug.com/309093.
+
+#if defined(TOOLKIT_GTK)
+  bool is_sandboxed = false;
+
+#if defined(OS_LINUX)
+  // On Linux, we only initialize GLib/GTK if we're not sandboxed.
+  is_sandboxed = !parameters.command_line.HasSwitch(switches::kNoSandbox);
+#endif
+
+  if (!is_sandboxed) {
+    // g_thread_init() is deprecated since glib 2.31.0, please see release note:
+    // http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html
+#if !(GLIB_CHECK_VERSION(2, 31, 0))
+    if (!g_thread_get_initialized()) {
+      g_thread_init(NULL);
+    }
+#endif
+    gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
+  }
+#endif
+#endif
+
   ChildProcess utility_process;
   utility_process.set_main_thread(new UtilityThreadImpl());
 
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index ca03da4..ed7fbfe 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -19,12 +19,6 @@
 #include "ipc/ipc_sync_channel.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-
-#include "ui/gfx/gtk_util.h"
-#endif
-
 namespace content {
 
 namespace {
@@ -132,19 +126,6 @@
     const std::vector<base::FilePath>& plugin_paths) {
   PluginList* plugin_list = PluginList::Singleton();
 
-  // On Linux, some plugins expect the browser to have loaded glib/gtk. Do that
-  // before attempting to call into the plugin.
-  // g_thread_init API is deprecated since glib 2.31.0, please see release note:
-  // http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html
-#if defined(TOOLKIT_GTK)
-#if !(GLIB_CHECK_VERSION(2, 31, 0))
-  if (!g_thread_get_initialized()) {
-    g_thread_init(NULL);
-  }
-#endif
-  gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
-#endif
-
   std::vector<WebPluginInfo> plugins;
   // TODO(bauerb): If we restart loading plug-ins, we might mess up the logic in
   // PluginList::ShouldLoadPlugin due to missing the previously loaded plug-ins
diff --git a/content/worker/websharedworkerclient_proxy.cc b/content/worker/websharedworkerclient_proxy.cc
index 97fc224..21182b0 100644
--- a/content/worker/websharedworkerclient_proxy.cc
+++ b/content/worker/websharedworkerclient_proxy.cc
@@ -47,50 +47,6 @@
 WebSharedWorkerClientProxy::~WebSharedWorkerClientProxy() {
 }
 
-void WebSharedWorkerClientProxy::postMessageToWorkerObject(
-    const WebString& message,
-    const WebMessagePortChannelArray& channels) {
-  // TODO(marja): Clean up the interface; this function doesn't need to exist.
-  NOTREACHED();
-}
-
-void WebSharedWorkerClientProxy::postExceptionToWorkerObject(
-    const WebString& error_message,
-    int line_number,
-    const WebString& source_url) {
-  Send(new WorkerHostMsg_PostExceptionToWorkerObject(
-      route_id_, error_message, line_number, source_url));
-}
-
-void WebSharedWorkerClientProxy::postConsoleMessageToWorkerObject(
-    int source,
-    int type,
-    int level,
-    const WebString& message,
-    int line_number,
-    const WebString& source_url) {
-  WorkerHostMsg_PostConsoleMessageToWorkerObject_Params params;
-  params.source_identifier = source;
-  params.message_type = type;
-  params.message_level = level;
-  params.message = message;
-  params.line_number = line_number;
-  params.source_url = source_url;
-  Send(new WorkerHostMsg_PostConsoleMessageToWorkerObject(route_id_, params));
-}
-
-void WebSharedWorkerClientProxy::confirmMessageFromWorkerObject(
-    bool has_pending_activity) {
-  Send(new WorkerHostMsg_ConfirmMessageFromWorkerObject(
-      route_id_, has_pending_activity));
-}
-
-void WebSharedWorkerClientProxy::reportPendingActivity(
-    bool has_pending_activity) {
-  Send(new WorkerHostMsg_ReportPendingActivity(
-      route_id_, has_pending_activity));
-}
-
 void WebSharedWorkerClientProxy::workerContextClosed() {
   Send(new WorkerHostMsg_WorkerContextClosed(route_id_));
 }
diff --git a/content/worker/websharedworkerclient_proxy.h b/content/worker/websharedworkerclient_proxy.h
index 39d1203..aef978c 100644
--- a/content/worker/websharedworkerclient_proxy.h
+++ b/content/worker/websharedworkerclient_proxy.h
@@ -32,34 +32,6 @@
   virtual ~WebSharedWorkerClientProxy();
 
   // WebSharedWorkerClient implementation.
-  virtual void postMessageToWorkerObject(
-      const WebKit::WebString& message,
-      const WebKit::WebMessagePortChannelArray& channel);
-  virtual void postExceptionToWorkerObject(
-      const WebKit::WebString& error_message,
-      int line_number,
-      const WebKit::WebString& source_url);
-  // TODO(caseq): The overload before is obsolete and is preserved for
-  // WebKit/chromium compatibility only (pure virtual is base class).
-  // Should be removed once WebKit part is updated.
-  virtual void postConsoleMessageToWorkerObject(
-      int destination,
-      int source,
-      int type,
-      int level,
-      const WebKit::WebString& message,
-      int line_number,
-      const WebKit::WebString& source_url) {
-  }
-  virtual void postConsoleMessageToWorkerObject(
-      int source,
-      int type,
-      int level,
-      const WebKit::WebString& message,
-      int line_number,
-      const WebKit::WebString& source_url);
-  virtual void confirmMessageFromWorkerObject(bool has_pending_activity);
-  virtual void reportPendingActivity(bool has_pending_activity);
   virtual void workerContextClosed();
   virtual void workerContextDestroyed();
 
diff --git a/content/worker/worker_webkitplatformsupport_impl.cc b/content/worker/worker_webkitplatformsupport_impl.cc
index 2b0306f..f3dee36 100644
--- a/content/worker/worker_webkitplatformsupport_impl.cc
+++ b/content/worker/worker_webkitplatformsupport_impl.cc
@@ -83,6 +83,8 @@
       child_thread_loop_(base::MessageLoopProxy::current()),
       sync_message_filter_(sync_message_filter),
       quota_message_filter_(quota_message_filter) {
+  if (sender)
+    blob_registry_.reset(new WebBlobRegistryImpl(sender));
 }
 
 WorkerWebKitPlatformSupportImpl::~WorkerWebKitPlatformSupportImpl() {
@@ -275,8 +277,6 @@
 }
 
 WebBlobRegistry* WorkerWebKitPlatformSupportImpl::blobRegistry() {
-  if (!blob_registry_.get() && thread_safe_sender_.get())
-    blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get()));
   return blob_registry_.get();
 }
 
diff --git a/crypto/crypto.target.darwin-arm.mk b/crypto/crypto.target.darwin-arm.mk
index 79c20a0..2ea724f 100644
--- a/crypto/crypto.target.darwin-arm.mk
+++ b/crypto/crypto.target.darwin-arm.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/crypto.target.darwin-mips.mk b/crypto/crypto.target.darwin-mips.mk
index 0d55c9a..495d8d5 100644
--- a/crypto/crypto.target.darwin-mips.mk
+++ b/crypto/crypto.target.darwin-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/crypto.target.darwin-x86.mk b/crypto/crypto.target.darwin-x86.mk
index 7104a1b..16ff3d1 100644
--- a/crypto/crypto.target.darwin-x86.mk
+++ b/crypto/crypto.target.darwin-x86.mk
@@ -87,13 +87,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/crypto.target.linux-arm.mk b/crypto/crypto.target.linux-arm.mk
index 79c20a0..2ea724f 100644
--- a/crypto/crypto.target.linux-arm.mk
+++ b/crypto/crypto.target.linux-arm.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/crypto.target.linux-mips.mk b/crypto/crypto.target.linux-mips.mk
index 0d55c9a..495d8d5 100644
--- a/crypto/crypto.target.linux-mips.mk
+++ b/crypto/crypto.target.linux-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/crypto.target.linux-x86.mk b/crypto/crypto.target.linux-x86.mk
index 7104a1b..16ff3d1 100644
--- a/crypto/crypto.target.linux-x86.mk
+++ b/crypto/crypto.target.linux-x86.mk
@@ -87,13 +87,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/crypto/ec_signature_creator_openssl.cc b/crypto/ec_signature_creator_openssl.cc
index 8854f5e..7f0a873 100644
--- a/crypto/ec_signature_creator_openssl.cc
+++ b/crypto/ec_signature_creator_openssl.cc
@@ -4,13 +4,21 @@
 
 #include "crypto/ec_signature_creator_impl.h"
 
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
 #include "base/logging.h"
+#include "crypto/ec_private_key.h"
+#include "crypto/openssl_util.h"
 
 namespace crypto {
 
 ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key)
-    : key_(key) {
-  NOTIMPLEMENTED();
+    : key_(key), signature_len_(0) {
+  EnsureOpenSSLInit();
 }
 
 ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {}
@@ -18,14 +26,59 @@
 bool ECSignatureCreatorImpl::Sign(const uint8* data,
                                   int data_len,
                                   std::vector<uint8>* signature) {
-  NOTIMPLEMENTED();
-  return false;
+  OpenSSLErrStackTracer err_tracer(FROM_HERE);
+  ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx(EVP_MD_CTX_create());
+  size_t sig_len = 0;
+  if (!ctx.get() ||
+      !EVP_DigestSignInit(ctx.get(), NULL, EVP_sha256(), NULL, key_->key()) ||
+      !EVP_DigestSignUpdate(ctx.get(), data, data_len) ||
+      !EVP_DigestSignFinal(ctx.get(), NULL, &sig_len)) {
+    return false;
+  }
+
+  signature->resize(sig_len);
+  if (!EVP_DigestSignFinal(ctx.get(), &signature->front(), &sig_len))
+    return false;
+
+  // NOTE: A call to EVP_DigestSignFinal() with a NULL second parameter returns
+  // a maximum allocation size, while the call without a NULL returns the real
+  // one, which may be smaller.
+  signature->resize(sig_len);
+  return true;
 }
 
 bool ECSignatureCreatorImpl::DecodeSignature(const std::vector<uint8>& der_sig,
                                              std::vector<uint8>* out_raw_sig) {
-  NOTIMPLEMENTED();
-  return false;
+  OpenSSLErrStackTracer err_tracer(FROM_HERE);
+  // Create ECDSA_SIG object from DER-encoded data.
+  const unsigned char* der_data = &der_sig.front();
+  ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free> ecdsa_sig(
+      d2i_ECDSA_SIG(NULL, &der_data, static_cast<long>(der_sig.size())));
+  if (!ecdsa_sig.get())
+    return false;
+
+  // The result is made of two 32-byte vectors.
+  const size_t kMaxBytesPerBN = 32;
+  std::vector<uint8> result;
+  result.resize(2 * kMaxBytesPerBN);
+  memset(&result[0], 0, result.size());
+
+  BIGNUM* r = ecdsa_sig.get()->r;
+  BIGNUM* s = ecdsa_sig.get()->s;
+  int r_bytes = BN_num_bytes(r);
+  int s_bytes = BN_num_bytes(s);
+  // NOTE: Can't really check for equality here since sometimes the value
+  // returned by BN_num_bytes() will be slightly smaller than kMaxBytesPerBN.
+  if (r_bytes > static_cast<int>(kMaxBytesPerBN) ||
+      s_bytes > static_cast<int>(kMaxBytesPerBN)) {
+    DLOG(ERROR) << "Invalid key sizes r(" << r_bytes << ") s(" << s_bytes
+                << ")";
+    return false;
+  }
+  BN_bn2bin(ecdsa_sig.get()->r, &result[kMaxBytesPerBN - r_bytes]);
+  BN_bn2bin(ecdsa_sig.get()->s, &result[2 * kMaxBytesPerBN - s_bytes]);
+  out_raw_sig->swap(result);
+  return true;
 }
 
 }  // namespace crypto
diff --git a/crypto/ec_signature_creator_unittest.cc b/crypto/ec_signature_creator_unittest.cc
index bc0cb4a..2a40cfe 100644
--- a/crypto/ec_signature_creator_unittest.cc
+++ b/crypto/ec_signature_creator_unittest.cc
@@ -12,17 +12,9 @@
 #include "crypto/signature_verifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(USE_OPENSSL)
-// Once ECSignatureCreator is implemented for OpenSSL, remove this #if block.
-// TODO(rch): When that happens, also add some exported keys from each to
+// TODO(rch): Add some exported keys from each to
 // test interop between NSS and OpenSSL.
-TEST(ECSignatureCreatorTest, OpenSSLStub) {
-  scoped_ptr<crypto::ECSignatureCreator> signer(
-      crypto::ECSignatureCreator::Create(NULL));
-  ASSERT_TRUE(signer.get());
-  EXPECT_FALSE(signer->Sign(NULL, 0, NULL));
-}
-#else
+
 TEST(ECSignatureCreatorTest, BasicTest) {
   // Do a verify round trip.
   scoped_ptr<crypto::ECPrivateKey> key_original(
@@ -81,4 +73,3 @@
                         data.size());
   ASSERT_TRUE(verifier.VerifyFinal());
 }
-#endif  // !defined(USE_OPENSSL)
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 80191b3..04080ed 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -168,20 +168,6 @@
 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
 }
 
-PK11SlotInfo* FindSlotWithTokenName(const std::string& token_name) {
-  AutoSECMODListReadLock auto_lock;
-  SECMODModuleList* head = SECMOD_GetDefaultModuleList();
-  for (SECMODModuleList* item = head; item != NULL; item = item->next) {
-    int slot_count = item->module->loaded ? item->module->slotCount : 0;
-    for (int i = 0; i < slot_count; i++) {
-      PK11SlotInfo* slot = item->module->slots[i];
-      if (PK11_GetTokenName(slot) == token_name)
-        return PK11_ReferenceSlot(slot);
-    }
-  }
-  return NULL;
-}
-
 #endif  // defined(USE_NSS)
 
 // A singleton to initialize/deinitialize NSPR.
@@ -247,10 +233,14 @@
   }
 
   void EnableTPMTokenForNSS() {
+    // If this gets set, then we'll use the TPM for certs with
+    // private keys, otherwise we'll fall back to the software
+    // implementation.
     tpm_token_enabled_for_nss_ = true;
   }
 
   bool InitializeTPMToken(const std::string& token_name,
+                          int token_slot_id,
                           const std::string& user_pin) {
     // If EnableTPMTokenForNSS hasn't been called, return false.
     if (!tpm_token_enabled_for_nss_)
@@ -275,12 +265,15 @@
           //   read from this slot without requiring a call to C_Login.
           // askpw=only -- Only authenticate to the token when necessary.
           "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
+      if (!chaps_module_ && test_slot_) {
+        // chromeos_unittests try to test the TPM initialization process. If we
+        // have a test DB open, pretend that it is the TPM slot.
+        tpm_slot_ = PK11_ReferenceSlot(test_slot_);
+        return true;
+      }
     }
     if (chaps_module_){
-      // If this gets set, then we'll use the TPM for certs with
-      // private keys, otherwise we'll fall back to the software
-      // implementation.
-      tpm_slot_ = GetTPMSlot();
+      tpm_slot_ = GetTPMSlotForId(token_slot_id);
 
       return tpm_slot_ != NULL;
     }
@@ -302,10 +295,22 @@
     return tpm_slot_ != NULL;
   }
 
-  PK11SlotInfo* GetTPMSlot() {
-    std::string token_name;
-    GetTPMTokenInfo(&token_name, NULL);
-    return FindSlotWithTokenName(token_name);
+  // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
+  // id as an int. This should be safe since this is only used with chaps, which
+  // we also control.
+  PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) {
+    if (!chaps_module_)
+      return NULL;
+
+    VLOG(1) << "Poking chaps module.";
+    SECStatus rv = SECMOD_UpdateSlotList(chaps_module_);
+    if (rv != SECSuccess)
+      PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
+
+    PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id);
+    if (!slot)
+      LOG(ERROR) << "TPM slot " << slot_id << " not found.";
+    return slot;
   }
 #endif  // defined(OS_CHROMEOS)
 
@@ -526,7 +531,7 @@
 
     // Aw, snap.  Can't find/load root cert shared library.
     // This will make it hard to talk to anybody via https.
-    NOTREACHED();
+    // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
     return NULL;
   }
 
@@ -549,6 +554,12 @@
                  << GetNSSErrorMessage();
       return NULL;
     }
+    if (!module->loaded) {
+      LOG(ERROR) << "After loading " << name << ", loaded==false: "
+                 << GetNSSErrorMessage();
+      SECMOD_DestroyModule(module);
+      return NULL;
+    }
     return module;
   }
 #endif
@@ -752,8 +763,10 @@
 }
 
 bool InitializeTPMToken(const std::string& token_name,
+                        int token_slot_id,
                         const std::string& user_pin) {
-  return g_nss_singleton.Get().InitializeTPMToken(token_name, user_pin);
+  return g_nss_singleton.Get().InitializeTPMToken(
+      token_name, token_slot_id, user_pin);
 }
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/crypto/nss_util.h b/crypto/nss_util.h
index 1d7503d..2c825a0 100644
--- a/crypto/nss_util.h
+++ b/crypto/nss_util.h
@@ -116,6 +116,7 @@
 
 // Initialize the TPM token.  Does nothing if it is already initialized.
 CRYPTO_EXPORT bool InitializeTPMToken(const std::string& token_name,
+                                      int token_slot_id,
                                       const std::string& user_pin);
 #endif
 
diff --git a/crypto/scoped_nss_types.h b/crypto/scoped_nss_types.h
index da90fea..21f684f 100644
--- a/crypto/scoped_nss_types.h
+++ b/crypto/scoped_nss_types.h
@@ -38,6 +38,9 @@
 typedef scoped_ptr_malloc<
     PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot> > ScopedPK11Slot;
 typedef scoped_ptr_malloc<
+    PK11SlotList, NSSDestroyer<PK11SlotList,
+                               PK11_FreeSlotList> > ScopedPK11SlotList;
+typedef scoped_ptr_malloc<
     PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey> > ScopedPK11SymKey;
 typedef scoped_ptr_malloc<
     SECKEYPublicKey, NSSDestroyer<SECKEYPublicKey, SECKEY_DestroyPublicKey> >
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index b5f6ba0..319a6e9 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -7,10 +7,9 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
-#include "chromeos/chromeos_switches.h"
+#include "base/sys_info.h"
 #include "chromeos/dbus/bluetooth_adapter_client.h"
 #include "chromeos/dbus/bluetooth_device_client.h"
 #include "chromeos/dbus/bluetooth_input_client.h"
@@ -328,16 +327,7 @@
 }
 
 void BluetoothAdapterChromeOS::SetAdapterName() {
-  // Set a better name for the adapter than "BlueZ 5.x"; this isn't an ideal
-  // way to do this but it'll do for now. See http://crbug.com/126732 and
-  // http://crbug.com/126802.
-  std::string board;
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(chromeos::switches::kChromeOSReleaseBoard)) {
-    board = command_line->
-        GetSwitchValueASCII(chromeos::switches::kChromeOSReleaseBoard);
-  }
-
+  std::string board = base::SysInfo::GetLsbReleaseBoard();
   std::string alias;
   if (board.substr(0, 6) == "stumpy") {
     alias = "Chromebox";
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index 1c35d9c..3c1ac11 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -1,3 +1,30 @@
 include_rules = [
   "+content/public/browser",
+
+  # Temporarily allowed includes as part of the app shell/extensions refactor.
+  #
+  # NOTE: Please do not add includes without talking to the app shell team;
+  # see OWNERS for this directory.
+  #
+  # TODO(jamescook): Remove these. http://crbug.com/162530
+  "+chrome/browser/chrome_notification_types.h",
+  "+chrome/browser/extensions/extension_host.h",
+  "+chrome/browser/extensions/extension_process_manager.h",
+  "+chrome/browser/extensions/extension_service.h",
+  "+chrome/browser/extensions/extension_system.h",
+  "+chrome/browser/extensions/process_map.h",
+  "+chrome/common/extensions/background_info.h",
+  "+chrome/common/extensions/extension.h",
+  "+chrome/common/extensions/extension_messages.h",
 ]
+
+specific_include_rules = {
+  ".*test\.cc": [
+    # Temporarily allowed testing includes.  See above.
+    # TODO(jamescook): Remove these. http://crbug.com/159366
+    "+chrome/browser/extensions/extension_service_unittest.h",
+    "+chrome/browser/extensions/test_extension_system.h",
+    "+chrome/common/extensions/extension_builder.h",
+    "+chrome/test/base/testing_profile.h",
+  ]
+}
diff --git a/extensions/browser/OWNERS b/extensions/browser/OWNERS
new file mode 100644
index 0000000..b06f377
--- /dev/null
+++ b/extensions/browser/OWNERS
@@ -0,0 +1,7 @@
+# Please talk to the apps shell team before adding DEPS.
+per-file DEPS=set noparent
+per-file DEPS=benwells@chromium.org
+per-file DEPS=derat@chromium.org
+per-file DEPS=jamescook@chromium.org
+per-file DEPS=miket@chromium.org
+per-file DEPS=yoz@chromium.org
diff --git a/extensions/browser/extensions_browser_client.cc b/extensions/browser/extensions_browser_client.cc
new file mode 100644
index 0000000..2724d47
--- /dev/null
+++ b/extensions/browser/extensions_browser_client.cc
@@ -0,0 +1,28 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/extensions_browser_client.h"
+
+#include "base/basictypes.h"
+
+namespace extensions {
+
+namespace {
+
+ExtensionsBrowserClient* g_client = NULL;
+
+}  // namespace
+
+ExtensionsBrowserClient* ExtensionsBrowserClient::Get() {
+  return g_client;
+}
+
+void ExtensionsBrowserClient::Set(ExtensionsBrowserClient* client) {
+  // This can happen in tests.
+  if (g_client)
+    return;
+  g_client = client;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
new file mode 100644
index 0000000..4810836
--- /dev/null
+++ b/extensions/browser/extensions_browser_client.h
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSIONS_BROWSER_CLIENT_H_
+#define EXTENSIONS_BROWSER_EXTENSIONS_BROWSER_CLIENT_H_
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+// Interface to allow the extensions module to make browser-process-specific
+// queries of the embedder. Should be Set() once in the browser process.
+//
+// NOTE: Methods that do not require knowledge of browser concepts should be
+// added in ExtensionsClient (extensions/common/extensions_client.h) even if
+// they are only used in the browser process.
+class ExtensionsBrowserClient {
+ public:
+  virtual ~ExtensionsBrowserClient() {}
+
+  // Returns true if the embedder has started shutting down.
+  virtual bool IsShuttingDown() = 0;
+
+  // Returns true if the BrowserContexts could be considered equivalent, for
+  // example, if one is an off-the-record context owned by the other.
+  virtual bool IsSameContext(content::BrowserContext* first,
+                             content::BrowserContext* second) = 0;
+
+  // Returns true if |context| has an off-the-record content associated with it.
+  virtual bool HasOffTheRecordContext(content::BrowserContext* context) = 0;
+
+  // Returns the off-the-record context associated with |context|. If |context|
+  // is already off-the-record, returns |context|.
+  // WARNING: This may create a new off-the-record context. To avoid creating
+  // another context, check HasOffTheRecordContext() first.
+  virtual content::BrowserContext* GetOffTheRecordContext(
+      content::BrowserContext* context) = 0;
+
+  // Returns the single instance of |this|.
+  static ExtensionsBrowserClient* Get();
+
+  // Initialize the single instance.
+  static void Set(ExtensionsBrowserClient* client);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_EXTENSIONS_BROWSER_CLIENT_H_
diff --git a/extensions/browser/lazy_background_task_queue.cc b/extensions/browser/lazy_background_task_queue.cc
new file mode 100644
index 0000000..584d897
--- /dev/null
+++ b/extensions/browser/lazy_background_task_queue.cc
@@ -0,0 +1,191 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/lazy_background_task_queue.h"
+
+#include "base/callback.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/process_map.h"
+#include "chrome/common/extensions/background_info.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/common/view_type.h"
+
+namespace extensions {
+
+LazyBackgroundTaskQueue::LazyBackgroundTaskQueue(
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                 content::Source<content::BrowserContext>(browser_context));
+}
+
+LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() {
+}
+
+bool LazyBackgroundTaskQueue::ShouldEnqueueTask(
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  DCHECK(extension);
+  if (BackgroundInfo::HasBackgroundPage(extension)) {
+    ExtensionProcessManager* pm = ExtensionSystem::GetForBrowserContext(
+        browser_context)->process_manager();
+    DCHECK(pm);
+    ExtensionHost* background_host =
+        pm->GetBackgroundHostForExtension(extension->id());
+    if (!background_host || !background_host->did_stop_loading())
+      return true;
+    if (pm->IsBackgroundHostClosing(extension->id()))
+      pm->CancelSuspend(extension);
+  }
+
+  return false;
+}
+
+void LazyBackgroundTaskQueue::AddPendingTask(
+    content::BrowserContext* browser_context,
+    const std::string& extension_id,
+    const PendingTask& task) {
+  if (ExtensionsBrowserClient::Get()->IsShuttingDown()) {
+    task.Run(NULL);
+    return;
+  }
+  PendingTasksList* tasks_list = NULL;
+  PendingTasksKey key(browser_context, extension_id);
+  PendingTasksMap::iterator it = pending_tasks_.find(key);
+  if (it == pending_tasks_.end()) {
+    tasks_list = new PendingTasksList();
+    pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list);
+
+    ExtensionService* extension_service = ExtensionSystem::GetForBrowserContext(
+        browser_context)->extension_service();
+    DCHECK(extension_service);
+    const Extension* extension =
+        extension_service->extensions()->GetByID(extension_id);
+    if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) {
+      // If this is the first enqueued task, and we're not waiting for the
+      // background page to unload, ensure the background page is loaded.
+      ExtensionProcessManager* pm = ExtensionSystem::GetForBrowserContext(
+          browser_context)->process_manager();
+      pm->IncrementLazyKeepaliveCount(extension);
+      // Creating the background host may fail, e.g. if |profile| is incognito
+      // but the extension isn't enabled in incognito mode.
+      if (!pm->CreateBackgroundHost(
+            extension, BackgroundInfo::GetBackgroundURL(extension))) {
+        task.Run(NULL);
+        return;
+      }
+    }
+  } else {
+    tasks_list = it->second.get();
+  }
+
+  tasks_list->push_back(task);
+}
+
+void LazyBackgroundTaskQueue::ProcessPendingTasks(
+    ExtensionHost* host,
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  if (!ExtensionsBrowserClient::Get()->IsSameContext(browser_context,
+                                                     browser_context_))
+    return;
+
+  PendingTasksKey key(browser_context, extension->id());
+  PendingTasksMap::iterator map_it = pending_tasks_.find(key);
+  if (map_it == pending_tasks_.end()) {
+    if (BackgroundInfo::HasLazyBackgroundPage(extension))
+      CHECK(!host);  // lazy page should not load without any pending tasks
+    return;
+  }
+
+  // Swap the pending tasks to a temporary, to avoid problems if the task
+  // list is modified during processing.
+  PendingTasksList tasks;
+  tasks.swap(*map_it->second);
+  for (PendingTasksList::const_iterator it = tasks.begin();
+       it != tasks.end(); ++it) {
+    it->Run(host);
+  }
+
+  pending_tasks_.erase(key);
+
+  // Balance the keepalive in AddPendingTask. Note we don't do this on a
+  // failure to load, because the keepalive count is reset in that case.
+  if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) {
+    ExtensionSystem::GetForBrowserContext(browser_context)->process_manager()->
+        DecrementLazyKeepaliveCount(extension);
+  }
+}
+
+void LazyBackgroundTaskQueue::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  switch (type) {
+    case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
+      // If an on-demand background page finished loading, dispatch queued up
+      // events for it.
+      ExtensionHost* host =
+          content::Details<ExtensionHost>(details).ptr();
+      if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
+        CHECK(host->did_stop_loading());
+        ProcessPendingTasks(host, host->browser_context(), host->extension());
+      }
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
+      // Notify consumers about the load failure when the background host dies.
+      // This can happen if the extension crashes. This is not strictly
+      // necessary, since we also unload the extension in that case (which
+      // dispatches the tasks below), but is a good extra precaution.
+      content::BrowserContext* browser_context =
+          content::Source<content::BrowserContext>(source).ptr();
+      ExtensionHost* host =
+           content::Details<ExtensionHost>(details).ptr();
+      if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
+        ProcessPendingTasks(NULL, browser_context, host->extension());
+      }
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+      // Notify consumers that the page failed to load.
+      content::BrowserContext* browser_context =
+          content::Source<content::BrowserContext>(source).ptr();
+      UnloadedExtensionInfo* unloaded =
+          content::Details<UnloadedExtensionInfo>(details).ptr();
+      ProcessPendingTasks(NULL, browser_context, unloaded->extension);
+      // If this extension is also running in an off-the-record context,
+      // notify that task queue as well.
+      ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
+      if (browser_client->HasOffTheRecordContext(browser_context)) {
+        ProcessPendingTasks(
+            NULL,
+            browser_client->GetOffTheRecordContext(browser_context),
+            unloaded->extension);
+      }
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/lazy_background_task_queue.h b/extensions/browser/lazy_background_task_queue.h
new file mode 100644
index 0000000..a92ec7c
--- /dev/null
+++ b/extensions/browser/lazy_background_task_queue.h
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
+#define EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
+
+#include <map>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/linked_ptr.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+class Extension;
+class ExtensionHost;
+
+// This class maintains a queue of tasks that should execute when an
+// extension's lazy background page is loaded. It is also in charge of loading
+// the page when the first task is queued.
+//
+// It is the consumer's responsibility to use this class when appropriate, i.e.
+// only with extensions that have not-yet-loaded lazy background pages.
+class LazyBackgroundTaskQueue : public content::NotificationObserver {
+ public:
+  typedef base::Callback<void(ExtensionHost*)> PendingTask;
+
+  explicit LazyBackgroundTaskQueue(content::BrowserContext* browser_context);
+  virtual ~LazyBackgroundTaskQueue();
+
+  // Returns the number of extensions having pending tasks.
+  size_t extensions_with_pending_tasks() { return pending_tasks_.size(); }
+
+  // Returns true if the task should be added to the queue (that is, if the
+  // extension has a lazy background page that isn't ready yet). If the
+  // extension has a lazy background page that is being suspended this method
+  // cancels that suspension.
+  bool ShouldEnqueueTask(content::BrowserContext* context,
+                         const Extension* extension);
+
+  // Adds a task to the queue for a given extension. If this is the first
+  // task added for the extension, its lazy background page will be loaded.
+  // The task will be called either when the page is loaded, or when the
+  // page fails to load for some reason (e.g. a crash or browser
+  // shutdown). In the latter case, the ExtensionHost parameter is NULL.
+  void AddPendingTask(
+      content::BrowserContext* context,
+      const std::string& extension_id,
+      const PendingTask& task);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, ProcessPendingTasks);
+
+  // A map between a BrowserContext/extension_id pair and the queue of tasks
+  // pending the load of its background page.
+  typedef std::string ExtensionID;
+  typedef std::pair<content::BrowserContext*, ExtensionID> PendingTasksKey;
+  typedef std::vector<PendingTask> PendingTasksList;
+  typedef std::map<PendingTasksKey,
+                   linked_ptr<PendingTasksList> > PendingTasksMap;
+
+  // content::NotificationObserver interface.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Called when a lazy background page has finished loading, or has failed to
+  // load (host is NULL in that case). All enqueued tasks are run in order.
+  void ProcessPendingTasks(
+      ExtensionHost* host,
+      content::BrowserContext* context,
+      const Extension* extension);
+
+  content::BrowserContext* browser_context_;
+  content::NotificationRegistrar registrar_;
+  PendingTasksMap pending_tasks_;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc
new file mode 100644
index 0000000..27d8471
--- /dev/null
+++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/lazy_background_task_queue.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service_unittest.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+// An ExtensionProcessManager that doesn't create background host pages.
+class TestExtensionProcessManager : public ExtensionProcessManager {
+ public:
+  explicit TestExtensionProcessManager(Profile* profile)
+      : ExtensionProcessManager(profile),
+        create_count_(0) {}
+  virtual ~TestExtensionProcessManager() {}
+
+  int create_count() { return create_count_; }
+
+  // ExtensionProcessManager overrides:
+  virtual extensions::ExtensionHost* CreateBackgroundHost(
+      const extensions::Extension* extension,
+      const GURL& url) OVERRIDE {
+    // Don't actually try to create a web contents.
+    create_count_++;
+    return NULL;
+  }
+
+ private:
+  int create_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestExtensionProcessManager);
+};
+
+// Derives from ExtensionServiceTestBase because ExtensionService is difficult
+// to initialize alone.
+class LazyBackgroundTaskQueueTest : public ExtensionServiceTestBase {
+ public:
+  LazyBackgroundTaskQueueTest() : task_run_count_(0) {}
+  virtual ~LazyBackgroundTaskQueueTest() {}
+
+  int task_run_count() { return task_run_count_; }
+
+  // A simple callback for AddPendingTask.
+  void RunPendingTask(ExtensionHost* host) {
+    task_run_count_++;
+  }
+
+  // Creates and registers an extension without a background page.
+  scoped_refptr<Extension> CreateSimpleExtension() {
+    scoped_refptr<Extension> extension = ExtensionBuilder()
+        .SetManifest(DictionaryBuilder()
+                     .Set("name", "No background")
+                     .Set("version", "1")
+                     .Set("manifest_version", 2))
+        .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+        .Build();
+    service_->AddExtension(extension);
+    return extension;
+  }
+
+  // Creates and registers an extension with a lazy background page.
+  scoped_refptr<Extension> CreateLazyBackgroundExtension() {
+    scoped_refptr<Extension> extension = ExtensionBuilder()
+        .SetManifest(DictionaryBuilder()
+            .Set("name", "Lazy background")
+            .Set("version", "1")
+            .Set("manifest_version", 2)
+            .Set("background",
+                  DictionaryBuilder()
+                  .Set("page", "background.html")
+                  .SetBoolean("persistent", false)))
+        .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
+        .Build();
+    service_->AddExtension(extension);
+    return extension;
+  }
+
+ private:
+  // The total number of pending tasks that have been executed.
+  int task_run_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(LazyBackgroundTaskQueueTest);
+};
+
+// Tests that only extensions with background pages should have tasks queued.
+TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) {
+  InitializeEmptyExtensionService();
+  InitializeExtensionProcessManager();
+
+  LazyBackgroundTaskQueue queue(profile_.get());
+
+  // Build a simple extension with no background page.
+  scoped_refptr<Extension> no_background = CreateSimpleExtension();
+  EXPECT_FALSE(queue.ShouldEnqueueTask(profile_.get(), no_background.get()));
+
+  // Build another extension with a background page.
+  scoped_refptr<Extension> with_background = CreateLazyBackgroundExtension();
+  EXPECT_TRUE(queue.ShouldEnqueueTask(profile_.get(), with_background.get()));
+}
+
+// Tests that adding tasks actually increases the pending task count, and that
+// multiple extensions can have pending tasks.
+TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) {
+  InitializeEmptyExtensionService();
+
+  // Swap in our stub TestExtensionProcessManager.
+  TestExtensionSystem* extension_system =
+      static_cast<extensions::TestExtensionSystem*>(
+          ExtensionSystem::Get(profile_.get()));
+  // Owned by |extension_system|.
+  TestExtensionProcessManager* process_manager =
+      new TestExtensionProcessManager(profile_.get());
+  extension_system->SetExtensionProcessManager(process_manager);
+
+  LazyBackgroundTaskQueue queue(profile_.get());
+
+  // Build a simple extension with no background page.
+  scoped_refptr<Extension> no_background = CreateSimpleExtension();
+
+  // Adding a pending task increases the number of extensions with tasks, but
+  // doesn't run the task.
+  queue.AddPendingTask(profile_.get(),
+                       no_background->id(),
+                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                                  base::Unretained(this)));
+  EXPECT_EQ(1u, queue.extensions_with_pending_tasks());
+  EXPECT_EQ(0, task_run_count());
+
+  // Another task on the same extension doesn't increase the number of
+  // extensions that have tasks and doesn't run any tasks.
+  queue.AddPendingTask(profile_.get(),
+                       no_background->id(),
+                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                                  base::Unretained(this)));
+  EXPECT_EQ(1u, queue.extensions_with_pending_tasks());
+  EXPECT_EQ(0, task_run_count());
+
+  // Adding a task on an extension with a lazy background page tries to create
+  // a background host, and if that fails, runs the task immediately.
+  scoped_refptr<Extension> lazy_background = CreateLazyBackgroundExtension();
+  queue.AddPendingTask(profile_.get(),
+                       lazy_background->id(),
+                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                                  base::Unretained(this)));
+  EXPECT_EQ(2u, queue.extensions_with_pending_tasks());
+  // The process manager tried to create a background host.
+  EXPECT_EQ(1, process_manager->create_count());
+  // The task ran immediately because the creation failed.
+  EXPECT_EQ(1, task_run_count());
+}
+
+// Tests that pending tasks are actually run.
+TEST_F(LazyBackgroundTaskQueueTest, ProcessPendingTasks) {
+  InitializeEmptyExtensionService();
+
+  LazyBackgroundTaskQueue queue(profile_.get());
+
+  // ProcessPendingTasks is a no-op if there are no tasks.
+  scoped_refptr<Extension> extension = CreateSimpleExtension();
+  queue.ProcessPendingTasks(NULL, profile_.get(), extension);
+  EXPECT_EQ(0, task_run_count());
+
+  // Schedule a task to run.
+  queue.AddPendingTask(profile_.get(),
+                       extension->id(),
+                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                                  base::Unretained(this)));
+  EXPECT_EQ(0, task_run_count());
+  EXPECT_EQ(1u, queue.extensions_with_pending_tasks());
+
+  // Trying to run tasks for an unrelated profile should do nothing.
+  TestingProfile profile2;
+  queue.ProcessPendingTasks(NULL, &profile2, extension);
+  EXPECT_EQ(0, task_run_count());
+  EXPECT_EQ(1u, queue.extensions_with_pending_tasks());
+
+  // Processing tasks when there is one pending runs the task and removes the
+  // extension from the list of extensions with pending tasks.
+  queue.ProcessPendingTasks(NULL, profile_.get(), extension);
+  EXPECT_EQ(1, task_run_count());
+  EXPECT_EQ(0u, queue.extensions_with_pending_tasks());
+}
+
+}  // namespace extensions
diff --git a/extensions/common/extensions_client.h b/extensions/common/extensions_client.h
index ed06d32..71a4dfd 100644
--- a/extensions/common/extensions_client.h
+++ b/extensions/common/extensions_client.h
@@ -7,9 +7,12 @@
 
 #include <set>
 #include <string>
+#include <vector>
 
 namespace extensions {
 
+class APIPermissionSet;
+class Extension;
 class FeatureProvider;
 class PermissionMessage;
 class PermissionMessageProvider;
@@ -20,6 +23,8 @@
 // process. This should be implemented by the client of the extensions system.
 class ExtensionsClient {
  public:
+  typedef std::vector<std::string> ScriptingWhitelist;
+
   // Initializes global state. Not done in the constructor because unit tests
   // can create additional ExtensionsClients because the utility thread runs
   // in-process.
@@ -45,6 +50,19 @@
       URLPatternSet* new_hosts,
       std::set<PermissionMessage>* messages) const = 0;
 
+  // Replaces the scripting whitelist with |whitelist|. Used in the renderer;
+  // only used for testing in the browser process.
+  virtual void SetScriptingWhitelist(const ScriptingWhitelist& whitelist) = 0;
+
+  // Return the whitelist of extensions that can run content scripts on
+  // any origin.
+  virtual const ScriptingWhitelist& GetScriptingWhitelist() const = 0;
+
+  // Get the set of chrome:// hosts that |extension| can run content scripts on.
+  virtual URLPatternSet GetPermittedChromeSchemeHosts(
+      const Extension* extension,
+      const APIPermissionSet& api_permissions) const = 0;
+
   // Return the extensions client.
   static ExtensionsClient* Get();
 
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index c03e3f4..26df7ce 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -111,6 +111,8 @@
 const char kSandboxedPages[] = "sandbox.pages";
 const char kSandboxedPagesCSP[] = "sandbox.content_security_policy";
 const char kScriptBadge[] = "script_badge";
+const char kSearchProvider[] = "chrome_settings_overrides.search_provider";
+const char kSettingsOverride[] = "chrome_settings_overrides";
 const char kShiftKey[] = "shiftKey";
 const char kShortcutKey[] = "shortcutKey";
 const char kShortName[] = "short_name";
@@ -149,7 +151,6 @@
 const char kUrlHandlerTitle[] = "title";
 const char kVersion[] = "version";
 const char kWebAccessibleResources[] = "web_accessible_resources";
-const char kWebRtc[] = "webrtc";
 const char kWebURLs[] = "app.urls";
 const char kWebview[] = "webview";
 const char kWebviewAccessibleResources[] = "accessible_resources";
@@ -337,6 +338,8 @@
     "Invalid value for 'content_scripts[*].*[*]'.";
 const char kInvalidGlobList[] =
     "Invalid value for 'content_scripts[*].*'.";
+const char kInvalidHomepageOverrideURL[] =
+    "Invalid value for overriding homepage url: '[*]'.";
 const char kInvalidHomepageURL[] =
     "Invalid value for homepage url: '[*]'.";
 const char kInvalidIconPath[] =
@@ -528,6 +531,8 @@
     "Invalid value for 'sandbox.content_security_policy'.";
 const char kInvalidScriptBadge[] =
     "Invalid value for 'script_badge'.";
+const char kInvalidEmptySettingsOverrides[] =
+    "Empty dictionary for 'chrome_settings_overrides'.";
 const char kInvalidShortName[] =
     "Invalid value for 'short_name'.";
 const char kInvalidSignature[] =
@@ -542,6 +547,8 @@
     "Invalid value for spellcheck dictionary locale.";
 const char kInvalidSpellcheckDictionaryPath[] =
     "Invalid value for spellcheck dictionary path.";
+const char kInvalidStartupOverrideURL[] =
+    "Invalid value for overriding startup URL: '[*]'.";
 const char kInvalidSystemIndicator[] =
     "Invalid value for 'system_indicator'.";
 const char kInvalidTheme[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index bf78fa5..846845e 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -48,7 +48,6 @@
 extern const char kFileFilters[];
 extern const char kFileBrowserHandlers[];
 extern const char kGlobal[];
-extern const char kMediaGalleriesHandlers[];
 extern const char kHomepageURL[];
 extern const char kIcons[];
 extern const char kId[];
@@ -79,6 +78,7 @@
 extern const char kLayouts[];
 extern const char kManifestVersion[];
 extern const char kMatches[];
+extern const char kMediaGalleriesHandlers[];
 extern const char kMIMETypes[];
 extern const char kMimeTypesHandler[];
 extern const char kMinimumChromeVersion[];
@@ -120,6 +120,8 @@
 extern const char kSandboxedPages[];
 extern const char kSandboxedPagesCSP[];
 extern const char kScriptBadge[];
+extern const char kSearchProvider[];
+extern const char kSettingsOverride[];
 extern const char kShiftKey[];
 extern const char kShortcutKey[];
 extern const char kShortName[];
@@ -283,6 +285,7 @@
 extern const char kInvalidFileHandlerTypeElement[];
 extern const char kInvalidGlob[];
 extern const char kInvalidGlobList[];
+extern const char kInvalidHomepageOverrideURL[];
 extern const char kInvalidHomepageURL[];
 extern const char kInvalidIconPath[];
 extern const char kInvalidIcons[];
@@ -374,6 +377,7 @@
 extern const char kInvalidSandboxedPage[];
 extern const char kInvalidSandboxedPagesCSP[];
 extern const char kInvalidScriptBadge[];
+extern const char kInvalidEmptySettingsOverrides[];
 extern const char kInvalidShortName[];
 extern const char kInvalidSignature[];
 extern const char kInvalidSpellcheck[];
@@ -381,6 +385,7 @@
 extern const char kInvalidSpellcheckDictionaryLanguage[];
 extern const char kInvalidSpellcheckDictionaryLocale[];
 extern const char kInvalidSpellcheckDictionaryPath[];
+extern const char kInvalidStartupOverrideURL[];
 extern const char kInvalidSystemIndicator[];
 extern const char kInvalidTheme[];
 extern const char kInvalidThemeColors[];
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index 7dd42c0..2ff17ea 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -91,7 +91,6 @@
     kGeolocation,
     kHistory,
     kIdentity,
-    kIdentityEmail,
     kIdentityPrivate,
     kIdltest,
     kIdle,
@@ -154,6 +153,7 @@
     kWebRequestBlocking,
     kWebRequestInternal,
     kWebRtc,
+    kWebrtcAudioPrivate,
     kWebrtcLoggingPrivate,
     kWebstorePrivate,
     kWebView,
diff --git a/extensions/common/permissions/permission_message.h b/extensions/common/permissions/permission_message.h
index 3b745b2..19c5799 100644
--- a/extensions/common/permissions/permission_message.h
+++ b/extensions/common/permissions/permission_message.h
@@ -74,7 +74,6 @@
     kSignedInDevices,
     kWallpaper,
     kNetworkState,
-    kIdentityEmail,
     kEnumBoundary,
   };
   COMPILE_ASSERT(PermissionMessage::kNone > PermissionMessage::kUnknown,
diff --git a/extensions/common/permissions/permission_set.cc b/extensions/common/permissions/permission_set.cc
new file mode 100644
index 0000000..d3f46fc
--- /dev/null
+++ b/extensions/common/permissions/permission_set.cc
@@ -0,0 +1,251 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/permissions/permission_set.h"
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/url_pattern_set.h"
+#include "url/gurl.h"
+
+using extensions::URLPatternSet;
+
+namespace {
+
+void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
+  DCHECK(out);
+  for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
+    URLPattern p = *i;
+    p.SetPath("/*");
+    out->AddPattern(p);
+  }
+}
+
+}  // namespace
+
+namespace extensions {
+
+//
+// PermissionSet
+//
+
+PermissionSet::PermissionSet() {}
+
+PermissionSet::PermissionSet(
+    const APIPermissionSet& apis,
+    const URLPatternSet& explicit_hosts,
+    const URLPatternSet& scriptable_hosts)
+    : apis_(apis),
+      scriptable_hosts_(scriptable_hosts) {
+  AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
+  InitImplicitPermissions();
+  InitEffectiveHosts();
+}
+
+// static
+PermissionSet* PermissionSet::CreateDifference(
+    const PermissionSet* set1,
+    const PermissionSet* set2) {
+  scoped_refptr<PermissionSet> empty = new PermissionSet();
+  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
+  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
+
+  APIPermissionSet apis;
+  APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
+
+  URLPatternSet explicit_hosts;
+  URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
+                                  set2_safe->explicit_hosts(),
+                                  &explicit_hosts);
+
+  URLPatternSet scriptable_hosts;
+  URLPatternSet::CreateDifference(set1_safe->scriptable_hosts(),
+                                  set2_safe->scriptable_hosts(),
+                                  &scriptable_hosts);
+
+  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+}
+
+// static
+PermissionSet* PermissionSet::CreateIntersection(
+    const PermissionSet* set1,
+    const PermissionSet* set2) {
+  scoped_refptr<PermissionSet> empty = new PermissionSet();
+  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
+  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
+
+  APIPermissionSet apis;
+  APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
+
+  URLPatternSet explicit_hosts;
+  URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
+                                    set2_safe->explicit_hosts(),
+                                    &explicit_hosts);
+
+  URLPatternSet scriptable_hosts;
+  URLPatternSet::CreateIntersection(set1_safe->scriptable_hosts(),
+                                    set2_safe->scriptable_hosts(),
+                                    &scriptable_hosts);
+
+  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+}
+
+// static
+PermissionSet* PermissionSet::CreateUnion(
+    const PermissionSet* set1,
+    const PermissionSet* set2) {
+  scoped_refptr<PermissionSet> empty = new PermissionSet();
+  const PermissionSet* set1_safe = (set1 == NULL) ? empty.get() : set1;
+  const PermissionSet* set2_safe = (set2 == NULL) ? empty.get() : set2;
+
+  APIPermissionSet apis;
+  APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
+
+  URLPatternSet explicit_hosts;
+  URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
+                             set2_safe->explicit_hosts(),
+                             &explicit_hosts);
+
+  URLPatternSet scriptable_hosts;
+  URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
+                             set2_safe->scriptable_hosts(),
+                             &scriptable_hosts);
+
+  return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+}
+
+bool PermissionSet::operator==(
+    const PermissionSet& rhs) const {
+  return apis_ == rhs.apis_ &&
+      scriptable_hosts_ == rhs.scriptable_hosts_ &&
+      explicit_hosts_ == rhs.explicit_hosts_;
+}
+
+bool PermissionSet::Contains(const PermissionSet& set) const {
+  return apis_.Contains(set.apis()) &&
+         explicit_hosts().Contains(set.explicit_hosts()) &&
+         scriptable_hosts().Contains(set.scriptable_hosts());
+}
+
+std::set<std::string> PermissionSet::GetAPIsAsStrings() const {
+  std::set<std::string> apis_str;
+  for (APIPermissionSet::const_iterator i = apis_.begin();
+       i != apis_.end(); ++i) {
+    apis_str.insert(i->name());
+  }
+  return apis_str;
+}
+
+bool PermissionSet::IsEmpty() const {
+  // Not default if any host permissions are present.
+  if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
+    return false;
+
+  // Or if it has no api permissions.
+  return apis().empty();
+}
+
+bool PermissionSet::HasAPIPermission(
+    APIPermission::ID id) const {
+  return apis().find(id) != apis().end();
+}
+
+bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
+  const APIPermissionInfo* permission =
+      PermissionsInfo::GetInstance()->GetByName(permission_name);
+  CHECK(permission) << permission_name;
+  return (permission && apis_.count(permission->id()));
+}
+
+bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
+  return CheckAPIPermissionWithParam(permission, NULL);
+}
+
+bool PermissionSet::CheckAPIPermissionWithParam(
+    APIPermission::ID permission,
+    const APIPermission::CheckParam* param) const {
+  APIPermissionSet::const_iterator iter = apis().find(permission);
+  if (iter == apis().end())
+    return false;
+  return iter->Check(param);
+}
+
+bool PermissionSet::HasExplicitAccessToOrigin(
+    const GURL& origin) const {
+  return explicit_hosts().MatchesURL(origin);
+}
+
+bool PermissionSet::HasScriptableAccessToURL(
+    const GURL& origin) const {
+  // We only need to check our host list to verify access. The host list should
+  // already reflect any special rules (such as chrome://favicon, all hosts
+  // access, etc.).
+  return scriptable_hosts().MatchesURL(origin);
+}
+
+bool PermissionSet::HasEffectiveAccessToAllHosts() const {
+  // There are two ways this set can have effective access to all hosts:
+  //  1) it has an <all_urls> URL pattern.
+  //  2) it has a named permission with implied full URL access.
+  for (URLPatternSet::const_iterator host = effective_hosts().begin();
+       host != effective_hosts().end(); ++host) {
+    if (host->match_all_urls() ||
+        (host->match_subdomains() && host->host().empty()))
+      return true;
+  }
+
+  for (APIPermissionSet::const_iterator i = apis().begin();
+       i != apis().end(); ++i) {
+    if (i->info()->implies_full_url_access())
+      return true;
+  }
+  return false;
+}
+
+bool PermissionSet::HasEffectiveAccessToURL(const GURL& url) const {
+  return effective_hosts().MatchesURL(url);
+}
+
+bool PermissionSet::HasEffectiveFullAccess() const {
+  for (APIPermissionSet::const_iterator i = apis().begin();
+       i != apis().end(); ++i) {
+    if (i->info()->implies_full_access())
+      return true;
+  }
+  return false;
+}
+
+PermissionSet::~PermissionSet() {}
+
+void PermissionSet::InitImplicitPermissions() {
+  // The downloads permission implies the internal version as well.
+  if (apis_.find(APIPermission::kDownloads) != apis_.end())
+    apis_.insert(APIPermission::kDownloadsInternal);
+
+  // TODO(fsamuel): Is there a better way to request access to the WebRequest
+  // API without exposing it to the Chrome App?
+  if (apis_.find(APIPermission::kWebView) != apis_.end())
+    apis_.insert(APIPermission::kWebRequestInternal);
+
+  // The webRequest permission implies the internal version as well.
+  if (apis_.find(APIPermission::kWebRequest) != apis_.end())
+    apis_.insert(APIPermission::kWebRequestInternal);
+
+  // The fileBrowserHandler permission implies the internal version as well.
+  if (apis_.find(APIPermission::kFileBrowserHandler) != apis_.end())
+    apis_.insert(APIPermission::kFileBrowserHandlerInternal);
+}
+
+void PermissionSet::InitEffectiveHosts() {
+  effective_hosts_.ClearPatterns();
+
+  URLPatternSet::CreateUnion(
+      explicit_hosts(), scriptable_hosts(), &effective_hosts_);
+}
+
+}  // namespace extensions
diff --git a/extensions/common/permissions/permission_set.h b/extensions/common/permissions/permission_set.h
new file mode 100644
index 0000000..14ffe12
--- /dev/null
+++ b/extensions/common/permissions/permission_set.h
@@ -0,0 +1,143 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_SET_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_SET_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string16.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/url_pattern_set.h"
+
+namespace extensions {
+class Extension;
+
+// The PermissionSet is an immutable class that encapsulates an
+// extension's permissions. The class exposes set operations for combining and
+// manipulating the permissions.
+class PermissionSet
+    : public base::RefCountedThreadSafe<PermissionSet> {
+ public:
+  // Creates an empty permission set (e.g. default permissions).
+  PermissionSet();
+
+  // Creates a new permission set based on the specified data: the API
+  // permissions, host permissions, and scriptable hosts. The effective hosts
+  // of the newly created permission set will be inferred from the given
+  // host permissions.
+  PermissionSet(const APIPermissionSet& apis,
+                const URLPatternSet& explicit_hosts,
+                const URLPatternSet& scriptable_hosts);
+
+  // Creates a new permission set equal to |set1| - |set2|, passing ownership of
+  // the new set to the caller.
+  static PermissionSet* CreateDifference(
+      const PermissionSet* set1, const PermissionSet* set2);
+
+  // Creates a new permission set equal to the intersection of |set1| and
+  // |set2|, passing ownership of the new set to the caller.
+  static PermissionSet* CreateIntersection(
+      const PermissionSet* set1, const PermissionSet* set2);
+
+  // Creates a new permission set equal to the union of |set1| and |set2|.
+  // Passes ownership of the new set to the caller.
+  static PermissionSet* CreateUnion(
+      const PermissionSet* set1, const PermissionSet* set2);
+
+  bool operator==(const PermissionSet& rhs) const;
+
+  // Returns true if every API or host permission available to |set| is also
+  // available to this. In other words, if the API permissions of |set| are a
+  // subset of this, and the host permissions in this encompass those in |set|.
+  bool Contains(const PermissionSet& set) const;
+
+  // Gets the API permissions in this set as a set of strings.
+  std::set<std::string> GetAPIsAsStrings() const;
+
+  // Returns true if this is an empty set (e.g., the default permission set).
+  bool IsEmpty() const;
+
+  // Returns true if the set has the specified API permission.
+  bool HasAPIPermission(APIPermission::ID permission) const;
+
+  // Returns true if the |extension| explicitly requests access to the given
+  // |permission_name|. Note this does not include APIs without no corresponding
+  // permission, like "runtime" or "browserAction".
+  bool HasAPIPermission(const std::string& permission_name) const;
+
+  // Returns true if the set allows the given permission with the default
+  // permission detal.
+  bool CheckAPIPermission(APIPermission::ID permission) const;
+
+  // Returns true if the set allows the given permission and permission param.
+  bool CheckAPIPermissionWithParam(APIPermission::ID permission,
+      const APIPermission::CheckParam* param) const;
+
+  // Returns true if this includes permission to access |origin|.
+  bool HasExplicitAccessToOrigin(const GURL& origin) const;
+
+  // Returns true if this permission set includes access to script |url|.
+  bool HasScriptableAccessToURL(const GURL& url) const;
+
+  // Returns true if this permission set includes effective access to all
+  // origins.
+  bool HasEffectiveAccessToAllHosts() const;
+
+  // Returns true if this permission set includes effective access to |url|.
+  bool HasEffectiveAccessToURL(const GURL& url) const;
+
+  // Returns ture if this permission set effectively represents full access
+  // (e.g. native code).
+  bool HasEffectiveFullAccess() const;
+
+  const APIPermissionSet& apis() const { return apis_; }
+
+  const URLPatternSet& effective_hosts() const { return effective_hosts_; }
+
+  const URLPatternSet& explicit_hosts() const { return explicit_hosts_; }
+
+  const URLPatternSet& scriptable_hosts() const { return scriptable_hosts_; }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetWarningMessages_AudioVideo);
+  friend class base::RefCountedThreadSafe<PermissionSet>;
+
+  ~PermissionSet();
+
+  void AddAPIPermission(APIPermission::ID id);
+
+  // Adds permissions implied independently of other context.
+  void InitImplicitPermissions();
+
+  // Initializes the effective host permission based on the data in this set.
+  void InitEffectiveHosts();
+
+  // The api list is used when deciding if an extension can access certain
+  // extension APIs and features.
+  APIPermissionSet apis_;
+
+  // The list of hosts that can be accessed directly from the extension.
+  // TODO(jstritar): Rename to "hosts_"?
+  URLPatternSet explicit_hosts_;
+
+  // The list of hosts that can be scripted by content scripts.
+  // TODO(jstritar): Rename to "user_script_hosts_"?
+  URLPatternSet scriptable_hosts_;
+
+  // The list of hosts this effectively grants access to.
+  URLPatternSet effective_hosts_;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_SET_H_
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index 0db3b4f..e54d965 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'chromium_code': 1,
+  },
   'targets': [
     {
       'target_name': 'extensions_common',
@@ -72,6 +75,8 @@
         'common/permissions/permission_message.h',
         'common/permissions/permission_message_provider.cc',
         'common/permissions/permission_message_provider.h',
+        'common/permissions/permission_set.cc',
+        'common/permissions/permission_set.h',
         'common/permissions/permissions_info.cc',
         'common/permissions/permissions_info.h',
         'common/permissions/permissions_provider.h',
@@ -107,10 +112,14 @@
         'browser/extension_prefs_scope.h',
         'browser/extension_error.cc',
         'browser/extension_error.h',
+        'browser/extensions_browser_client.cc',
+        'browser/extensions_browser_client.h',
         'browser/file_highlighter.cc',
         'browser/file_highlighter.h',
         'browser/file_reader.cc',
         'browser/file_reader.h',
+        'browser/lazy_background_task_queue.cc',
+        'browser/lazy_background_task_queue.h',
         'browser/pref_names.cc',
         'browser/pref_names.h',
         'browser/view_type_utils.cc',
diff --git a/google_apis/gcm/base/mcs_util.cc b/google_apis/gcm/base/mcs_util.cc
new file mode 100644
index 0000000..b52d429
--- /dev/null
+++ b/google_apis/gcm/base/mcs_util.cc
@@ -0,0 +1,220 @@
+// Copyright 2013 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 "google_apis/gcm/base/mcs_util.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace gcm {
+
+namespace {
+
+// Type names corresponding to MCSProtoTags. Useful for identifying what type
+// of MCS protobuf is contained within a google::protobuf::MessageLite object.
+// WARNING: must match the order in MCSProtoTag.
+const char* kProtoNames[] = {
+  "mcs_proto.HeartbeatPing",
+  "mcs_proto.HeartbeatAck",
+  "mcs_proto.LoginRequest",
+  "mcs_proto.LoginResponse",
+  "mcs_proto.Close",
+  "mcs_proto.MessageStanza",
+  "mcs_proto.PresenceStanza",
+  "mcs_proto.IqStanza",
+  "mcs_proto.DataMessageStanza",
+  "mcs_proto.BatchPresenceStanza",
+  "mcs_proto.StreamErrorStanza",
+  "mcs_proto.HttpRequest",
+  "mcs_proto.HttpResponse",
+  "mcs_proto.BindAccountRequest",
+  "mcs_proto.BindAccountResponse",
+  "mcs_proto.TalkMetadata"
+};
+COMPILE_ASSERT(arraysize(kProtoNames) == kNumProtoTypes,
+               ProtoNamesMustIncludeAllTags);
+
+// TODO(zea): replace these with proper values.
+const char kLoginId[] = "login-1";
+const char kLoginDomain[] = "mcs.android.com";
+const char kLoginDeviceIdPrefix[] = "android-";
+const char kLoginSettingName[] = "new_vc";
+const char kLoginSettingValue[] = "1";
+
+}  // namespace
+
+scoped_ptr<mcs_proto::LoginRequest> BuildLoginRequest(
+    uint64 auth_id,
+    uint64 auth_token) {
+  // Create a hex encoded auth id for the device id field.
+  std::string auth_id_hex;
+  auth_id_hex = base::StringPrintf("%" PRIx64, auth_id);
+
+  std::string auth_id_str = base::Uint64ToString(auth_id);
+  std::string auth_token_str = base::Uint64ToString(auth_token);
+
+  scoped_ptr<mcs_proto::LoginRequest> login_request(
+      new mcs_proto::LoginRequest());
+
+  // TODO(zea): set better values.
+  login_request->set_account_id(1000000);
+  login_request->set_adaptive_heartbeat(false);
+  login_request->set_auth_service(mcs_proto::LoginRequest::ANDROID_ID);
+  login_request->set_auth_token(auth_token_str);
+  login_request->set_id(kLoginId);
+  login_request->set_domain(kLoginDomain);
+  login_request->set_device_id(kLoginDeviceIdPrefix + auth_id_hex);
+  login_request->set_network_type(1);
+  login_request->set_resource(auth_id_str);
+  login_request->set_user(auth_id_str);
+  login_request->set_use_rmq2(true);
+
+  login_request->add_setting();
+  login_request->mutable_setting(0)->set_name(kLoginSettingName);
+  login_request->mutable_setting(0)->set_value(kLoginSettingValue);
+  return login_request.Pass();
+}
+
+scoped_ptr<mcs_proto::IqStanza> BuildStreamAck() {
+  scoped_ptr<mcs_proto::IqStanza> stream_ack_iq(new mcs_proto::IqStanza());
+  stream_ack_iq->set_type(mcs_proto::IqStanza::SET);
+  stream_ack_iq->set_id("");
+  stream_ack_iq->mutable_extension()->set_id(kStreamAck);
+  stream_ack_iq->mutable_extension()->set_data("");
+  return stream_ack_iq.Pass();
+}
+
+// Utility method to build a google::protobuf::MessageLite object from a MCS
+// tag.
+scoped_ptr<google::protobuf::MessageLite> BuildProtobufFromTag(uint8 tag) {
+  switch(tag) {
+    case kHeartbeatPingTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::HeartbeatPing());
+    case kHeartbeatAckTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::HeartbeatAck());
+    case kLoginRequestTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::LoginRequest());
+    case kLoginResponseTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::LoginResponse());
+    case kCloseTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::Close());
+    case kIqStanzaTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::IqStanza());
+    case kDataMessageStanzaTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::DataMessageStanza());
+    case kStreamErrorStanzaTag:
+      return scoped_ptr<google::protobuf::MessageLite>(
+          new mcs_proto::StreamErrorStanza());
+    default:
+      return scoped_ptr<google::protobuf::MessageLite>();
+  }
+}
+
+// Utility method to extract a MCS tag from a google::protobuf::MessageLite
+// object.
+int GetMCSProtoTag(const google::protobuf::MessageLite& message) {
+  const std::string& type_name = message.GetTypeName();
+  if (type_name == kProtoNames[kHeartbeatPingTag]) {
+    return kHeartbeatPingTag;
+  } else if (type_name == kProtoNames[kHeartbeatAckTag]) {
+    return kHeartbeatAckTag;
+  } else if (type_name == kProtoNames[kLoginRequestTag]) {
+    return kLoginRequestTag;
+  } else if (type_name == kProtoNames[kLoginResponseTag]) {
+    return kLoginResponseTag;
+  } else if (type_name == kProtoNames[kCloseTag]) {
+    return kCloseTag;
+  } else if (type_name == kProtoNames[kIqStanzaTag]) {
+    return kIqStanzaTag;
+  } else if (type_name == kProtoNames[kDataMessageStanzaTag]) {
+    return kDataMessageStanzaTag;
+  } else if (type_name == kProtoNames[kStreamErrorStanzaTag]) {
+    return kStreamErrorStanzaTag;
+  }
+  return -1;
+}
+
+std::string GetPersistentId(const google::protobuf::MessageLite& protobuf) {
+  if (protobuf.GetTypeName() == kProtoNames[kIqStanzaTag]) {
+    return reinterpret_cast<const mcs_proto::IqStanza*>(&protobuf)->
+        persistent_id();
+  } else if (protobuf.GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
+    return reinterpret_cast<const mcs_proto::DataMessageStanza*>(&protobuf)->
+        persistent_id();
+  }
+  // Not all message types have persistent ids. Just return empty string;
+  return "";
+}
+
+void SetPersistentId(const std::string& persistent_id,
+                     google::protobuf::MessageLite* protobuf) {
+  if (protobuf->GetTypeName() == kProtoNames[kIqStanzaTag]) {
+    reinterpret_cast<mcs_proto::IqStanza*>(protobuf)->
+        set_persistent_id(persistent_id);
+    return;
+  } else if (protobuf->GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
+    reinterpret_cast<mcs_proto::DataMessageStanza*>(protobuf)->
+        set_persistent_id(persistent_id);
+    return;
+  }
+  NOTREACHED();
+}
+
+uint32 GetLastStreamIdReceived(const google::protobuf::MessageLite& protobuf) {
+  if (protobuf.GetTypeName() == kProtoNames[kIqStanzaTag]) {
+    return reinterpret_cast<const mcs_proto::IqStanza*>(&protobuf)->
+        last_stream_id_received();
+  } else if (protobuf.GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
+    return reinterpret_cast<const mcs_proto::DataMessageStanza*>(&protobuf)->
+        last_stream_id_received();
+  } else if (protobuf.GetTypeName() == kProtoNames[kHeartbeatPingTag]) {
+    return reinterpret_cast<const mcs_proto::HeartbeatPing*>(&protobuf)->
+        last_stream_id_received();
+  } else if (protobuf.GetTypeName() == kProtoNames[kHeartbeatAckTag]) {
+    return reinterpret_cast<const mcs_proto::HeartbeatAck*>(&protobuf)->
+        last_stream_id_received();
+  } else if (protobuf.GetTypeName() == kProtoNames[kLoginResponseTag]) {
+    return reinterpret_cast<const mcs_proto::LoginResponse*>(&protobuf)->
+        last_stream_id_received();
+  }
+  // Not all message types have last stream ids. Just return 0.
+  return 0;
+}
+
+void SetLastStreamIdReceived(uint32 val,
+                             google::protobuf::MessageLite* protobuf) {
+  if (protobuf->GetTypeName() == kProtoNames[kIqStanzaTag]) {
+    reinterpret_cast<mcs_proto::IqStanza*>(protobuf)->
+        set_last_stream_id_received(val);
+     return;
+  } else if (protobuf->GetTypeName() == kProtoNames[kHeartbeatPingTag]) {
+    reinterpret_cast<mcs_proto::HeartbeatPing*>(protobuf)->
+        set_last_stream_id_received(val);
+     return;
+  } else if (protobuf->GetTypeName() == kProtoNames[kHeartbeatAckTag]) {
+    reinterpret_cast<mcs_proto::HeartbeatAck*>(protobuf)->
+        set_last_stream_id_received(val);
+     return;
+  } else if (protobuf->GetTypeName() == kProtoNames[kDataMessageStanzaTag]) {
+    reinterpret_cast<mcs_proto::DataMessageStanza*>(protobuf)->
+        set_last_stream_id_received(val);
+     return;
+  } else if (protobuf->GetTypeName() == kProtoNames[kLoginResponseTag]) {
+    reinterpret_cast<mcs_proto::LoginResponse*>(protobuf)->
+        set_last_stream_id_received(val);
+     return;
+  }
+  NOTREACHED();
+}
+
+}  // namespace gcm
diff --git a/google_apis/gcm/base/mcs_util.h b/google_apis/gcm/base/mcs_util.h
new file mode 100644
index 0000000..d125af7
--- /dev/null
+++ b/google_apis/gcm/base/mcs_util.h
@@ -0,0 +1,79 @@
+// Copyright 2013 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.
+//
+// Utility methods for MCS interactions.
+
+#ifndef GOOGLE_APIS_GCM_BASE_MCS_UTIL_H_
+#define GOOGLE_APIS_GCM_BASE_MCS_UTIL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "google_apis/gcm/base/gcm_export.h"
+#include "google_apis/gcm/protocol/mcs.pb.h"
+
+namespace net {
+class StreamSocket;
+}
+
+namespace gcm {
+
+// MCS Message tags.
+// WARNING: the order of these tags must remain the same, as the tag values
+// must be consistent with those used on the server.
+enum MCSProtoTag {
+  kHeartbeatPingTag = 0,
+  kHeartbeatAckTag,
+  kLoginRequestTag,
+  kLoginResponseTag,
+  kCloseTag,
+  kMessageStanzaTag,
+  kPresenceStanzaTag,
+  kIqStanzaTag,
+  kDataMessageStanzaTag,
+  kBatchPresenceStanzaTag,
+  kStreamErrorStanzaTag,
+  kHttpRequestTag,
+  kHttpResponseTag,
+  kBindAccountRequestTag,
+  kBindAccountResponseTag,
+  kTalkMetadataTag,
+  kNumProtoTypes,
+};
+
+enum MCSIqStanzaExtension {
+  kSelectiveAck = 12,
+  kStreamAck = 13,
+};
+
+// Builds a LoginRequest with the hardcoded local data.
+GCM_EXPORT scoped_ptr<mcs_proto::LoginRequest> BuildLoginRequest(
+    uint64 auth_id,
+    uint64 auth_token);
+
+// Builds a StreamAck IqStanza message.
+GCM_EXPORT scoped_ptr<mcs_proto::IqStanza> BuildStreamAck();
+
+// Utility methods for building and identifying MCS protobufs.
+GCM_EXPORT scoped_ptr<google::protobuf::MessageLite>
+    BuildProtobufFromTag(uint8 tag);
+GCM_EXPORT int GetMCSProtoTag(const google::protobuf::MessageLite& message);
+
+// RMQ utility methods for extracting/setting common data from/to protobufs.
+GCM_EXPORT std::string GetPersistentId(
+    const google::protobuf::MessageLite& message);
+GCM_EXPORT void SetPersistentId(
+    const std::string& persistent_id,
+    google::protobuf::MessageLite* message);
+GCM_EXPORT uint32 GetLastStreamIdReceived(
+    const google::protobuf::MessageLite& protobuf);
+GCM_EXPORT void SetLastStreamIdReceived(
+    uint32 last_stream_id_received,
+    google::protobuf::MessageLite* protobuf);
+
+}  // namespace gcm
+
+#endif  // GOOGLE_APIS_GCM_BASE_MCS_UTIL_H_
diff --git a/google_apis/gcm/base/mcs_util_unittest.cc b/google_apis/gcm/base/mcs_util_unittest.cc
new file mode 100644
index 0000000..d259145
--- /dev/null
+++ b/google_apis/gcm/base/mcs_util_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 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 "google_apis/gcm/base/mcs_util.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gcm {
+namespace {
+
+const uint64 kAuthId = 4421448356646222460;
+const uint64 kAuthToken = 12345;
+
+// Build a login request protobuf.
+TEST(MCSUtilTest, BuildLoginRequest) {
+  scoped_ptr<mcs_proto::LoginRequest> login_request =
+      BuildLoginRequest(kAuthId, kAuthToken);
+  ASSERT_EQ("login-1", login_request->id());
+  ASSERT_EQ(base::Uint64ToString(kAuthToken), login_request->auth_token());
+  ASSERT_EQ(base::Uint64ToString(kAuthId), login_request->user());
+  ASSERT_EQ("android-3d5c23dac2a1fa7c", login_request->device_id());
+  // TODO(zea): test the other fields once they have valid values.
+}
+
+// Test building a protobuf and extracting the tag from a protobuf.
+TEST(MCSUtilTest, ProtobufToTag) {
+  for (size_t i = 0; i < kNumProtoTypes; ++i) {
+    scoped_ptr<google::protobuf::MessageLite> protobuf =
+        BuildProtobufFromTag(i);
+    if (!protobuf.get())  // Not all tags have protobuf definitions.
+      continue;
+    ASSERT_EQ((int)i, GetMCSProtoTag(*protobuf)) << "Type " << i;
+  }
+}
+
+// Test getting and setting persistent ids.
+TEST(MCSUtilTest, PersistentIds) {
+  COMPILE_ASSERT(kNumProtoTypes == 16U, UpdatePersistentIds);
+  const int kTagsWithPersistentIds[] = {
+    kIqStanzaTag,
+    kDataMessageStanzaTag
+  };
+  for (size_t i = 0; i < arraysize(kTagsWithPersistentIds); ++i) {
+    int tag = kTagsWithPersistentIds[i];
+    scoped_ptr<google::protobuf::MessageLite> protobuf =
+        BuildProtobufFromTag(tag);
+    ASSERT_TRUE(protobuf.get());
+    SetPersistentId(base::IntToString(tag), protobuf.get());
+    int get_val = 0;
+    base::StringToInt(GetPersistentId(*protobuf), &get_val);
+    ASSERT_EQ(tag, get_val);
+  }
+}
+
+// Test getting and setting stream ids.
+TEST(MCSUtilTest, StreamIds) {
+  COMPILE_ASSERT(kNumProtoTypes == 16U, UpdateStreamIds);
+  const int kTagsWithStreamIds[] = {
+    kIqStanzaTag,
+    kDataMessageStanzaTag,
+    kHeartbeatPingTag,
+    kHeartbeatAckTag,
+    kLoginResponseTag,
+  };
+  for (size_t i = 0; i < arraysize(kTagsWithStreamIds); ++i) {
+    int tag = kTagsWithStreamIds[i];
+    scoped_ptr<google::protobuf::MessageLite> protobuf =
+        BuildProtobufFromTag(tag);
+    ASSERT_TRUE(protobuf.get());
+    SetLastStreamIdReceived(tag, protobuf.get());
+    int get_id = GetLastStreamIdReceived(*protobuf);
+    ASSERT_EQ(tag, get_id);
+  }
+}
+
+}  // namespace
+}  // namespace gcm
diff --git a/google_apis/gcm/engine/connection_handler.cc b/google_apis/gcm/engine/connection_handler.cc
new file mode 100644
index 0000000..b4eb602
--- /dev/null
+++ b/google_apis/gcm/engine/connection_handler.cc
@@ -0,0 +1,401 @@
+// Copyright 2013 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 "google_apis/gcm/engine/connection_handler.h"
+
+#include "base/message_loop/message_loop.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google_apis/gcm/base/mcs_util.h"
+#include "google_apis/gcm/base/socket_stream.h"
+#include "net/base/net_errors.h"
+#include "net/socket/stream_socket.h"
+
+using namespace google::protobuf::io;
+
+namespace gcm {
+
+namespace {
+
+// # of bytes a MCS version packet consumes.
+const int kVersionPacketLen = 1;
+// # of bytes a tag packet consumes.
+const int kTagPacketLen = 1;
+// Max # of bytes a length packet consumes.
+const int kSizePacketLenMin = 1;
+const int kSizePacketLenMax = 2;
+
+// The current MCS protocol version.
+const int kMCSVersion = 38;
+
+}  // namespace
+
+ConnectionHandler::ConnectionHandler(base::TimeDelta read_timeout)
+    : read_timeout_(read_timeout),
+      handshake_complete_(false),
+      message_tag_(0),
+      message_size_(0),
+      weak_ptr_factory_(this) {
+}
+
+ConnectionHandler::~ConnectionHandler() {
+}
+
+void ConnectionHandler::Init(
+    scoped_ptr<net::StreamSocket> socket,
+    const google::protobuf::MessageLite& login_request,
+    const ProtoReceivedCallback& read_callback,
+    const ProtoSentCallback& write_callback,
+    const ConnectionChangedCallback& connection_callback) {
+  DCHECK(!read_callback.is_null());
+  DCHECK(!write_callback.is_null());
+  DCHECK(!connection_callback.is_null());
+
+  // Invalidate any previously outstanding reads.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+
+  handshake_complete_ = false;
+  message_tag_ = 0;
+  message_size_ = 0;
+  socket_ = socket.Pass();
+  input_stream_.reset(new SocketInputStream(socket_.get()));
+  output_stream_.reset(new SocketOutputStream(socket_.get()));
+  read_callback_ = read_callback;
+  write_callback_ = write_callback;
+  connection_callback_ = connection_callback;
+
+  Login(login_request);
+}
+
+bool ConnectionHandler::CanSendMessage() const {
+  return handshake_complete_ && output_stream_.get() &&
+      output_stream_->GetState() == SocketOutputStream::EMPTY;
+}
+
+void ConnectionHandler::SendMessage(
+    const google::protobuf::MessageLite& message) {
+  DCHECK_EQ(output_stream_->GetState(), SocketOutputStream::EMPTY);
+  DCHECK(handshake_complete_);
+
+  {
+    CodedOutputStream coded_output_stream(output_stream_.get());
+    DVLOG(1) << "Writing proto of size " << message.ByteSize();
+    int tag = GetMCSProtoTag(message);
+    DCHECK_NE(tag, -1);
+    coded_output_stream.WriteRaw(&tag, 1);
+    coded_output_stream.WriteVarint32(message.ByteSize());
+    message.SerializeToCodedStream(&coded_output_stream);
+  }
+
+  if (output_stream_->Flush(
+          base::Bind(&ConnectionHandler::OnMessageSent,
+                     weak_ptr_factory_.GetWeakPtr())) != net::ERR_IO_PENDING) {
+    OnMessageSent();
+  }
+}
+
+void ConnectionHandler::Login(
+    const google::protobuf::MessageLite& login_request) {
+  DCHECK_EQ(output_stream_->GetState(), SocketOutputStream::EMPTY);
+
+  const char version_byte[1] = {kMCSVersion};
+  const char login_request_tag[1] = {kLoginRequestTag};
+  {
+    CodedOutputStream coded_output_stream(output_stream_.get());
+    coded_output_stream.WriteRaw(version_byte, 1);
+    coded_output_stream.WriteRaw(login_request_tag, 1);
+    coded_output_stream.WriteVarint32(login_request.ByteSize());
+    login_request.SerializeToCodedStream(&coded_output_stream);
+  }
+
+  if (output_stream_->Flush(
+          base::Bind(&ConnectionHandler::OnMessageSent,
+                     weak_ptr_factory_.GetWeakPtr())) != net::ERR_IO_PENDING) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&ConnectionHandler::OnMessageSent,
+                   weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  read_timeout_timer_.Start(FROM_HERE,
+                            read_timeout_,
+                            base::Bind(&ConnectionHandler::OnTimeout,
+                                       weak_ptr_factory_.GetWeakPtr()));
+  WaitForData(MCS_VERSION_TAG_AND_SIZE);
+}
+
+void ConnectionHandler::OnMessageSent() {
+  if (!output_stream_.get()) {
+    // The connection has already been closed. Just return.
+    DCHECK(!input_stream_.get());
+    DCHECK(!read_timeout_timer_.IsRunning());
+    return;
+  }
+
+  if (output_stream_->GetState() != SocketOutputStream::EMPTY) {
+    int last_error = output_stream_->last_error();
+    CloseConnection();
+    // If the socket stream had an error, plumb it up, else plumb up FAILED.
+    if (last_error == net::OK)
+      last_error = net::ERR_FAILED;
+    connection_callback_.Run(last_error);
+    return;
+  }
+
+  write_callback_.Run();
+}
+
+void ConnectionHandler::GetNextMessage() {
+  DCHECK(SocketInputStream::EMPTY == input_stream_->GetState() ||
+         SocketInputStream::READY == input_stream_->GetState());
+  message_tag_ = 0;
+  message_size_ = 0;
+
+  WaitForData(MCS_TAG_AND_SIZE);
+}
+
+void ConnectionHandler::WaitForData(ProcessingState state) {
+  DVLOG(1) << "Waiting for MCS data: state == " << state;
+
+  if (!input_stream_) {
+    // The connection has already been closed. Just return.
+    DCHECK(!output_stream_.get());
+    DCHECK(!read_timeout_timer_.IsRunning());
+    return;
+  }
+
+  if (input_stream_->GetState() != SocketInputStream::EMPTY &&
+      input_stream_->GetState() != SocketInputStream::READY) {
+    // An error occurred.
+    int last_error = output_stream_->last_error();
+    CloseConnection();
+    // If the socket stream had an error, plumb it up, else plumb up FAILED.
+    if (last_error == net::OK)
+      last_error = net::ERR_FAILED;
+    connection_callback_.Run(last_error);
+    return;
+  }
+
+  // Used to determine whether a Socket::Read is necessary.
+  int min_bytes_needed = 0;
+  // Used to limit the size of the Socket::Read.
+  int max_bytes_needed = 0;
+
+  switch(state) {
+    case MCS_VERSION_TAG_AND_SIZE:
+      min_bytes_needed = kVersionPacketLen + kTagPacketLen + kSizePacketLenMin;
+      max_bytes_needed = kVersionPacketLen + kTagPacketLen + kSizePacketLenMax;
+      break;
+    case MCS_TAG_AND_SIZE:
+      min_bytes_needed = kTagPacketLen + kSizePacketLenMin;
+      max_bytes_needed = kTagPacketLen + kSizePacketLenMax;
+      break;
+    case MCS_FULL_SIZE:
+      // If in this state, the minimum size packet length must already have been
+      // insufficient, so set both to the max length.
+      min_bytes_needed = kSizePacketLenMax;
+      max_bytes_needed = kSizePacketLenMax;
+      break;
+    case MCS_PROTO_BYTES:
+      read_timeout_timer_.Reset();
+      // No variability in the message size, set both to the same.
+      min_bytes_needed = message_size_;
+      max_bytes_needed = message_size_;
+      break;
+    default:
+      NOTREACHED();
+  }
+  DCHECK_GE(max_bytes_needed, min_bytes_needed);
+
+  int byte_count = input_stream_->UnreadByteCount();
+  if (min_bytes_needed - byte_count > 0 &&
+      input_stream_->Refresh(
+          base::Bind(&ConnectionHandler::WaitForData,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     state),
+          max_bytes_needed - byte_count) == net::ERR_IO_PENDING) {
+    return;
+  }
+
+  // Check for refresh errors.
+  if (input_stream_->GetState() != SocketInputStream::READY) {
+    // An error occurred.
+    int last_error = output_stream_->last_error();
+    CloseConnection();
+    // If the socket stream had an error, plumb it up, else plumb up FAILED.
+    if (last_error == net::OK)
+      last_error = net::ERR_FAILED;
+    connection_callback_.Run(last_error);
+    return;
+  }
+
+  // Received enough bytes, process them.
+  DVLOG(1) << "Processing MCS data: state == " << state;
+  switch(state) {
+    case MCS_VERSION_TAG_AND_SIZE:
+      OnGotVersion();
+      break;
+    case MCS_TAG_AND_SIZE:
+      OnGotMessageTag();
+      break;
+    case MCS_FULL_SIZE:
+      OnGotMessageSize();
+      break;
+    case MCS_PROTO_BYTES:
+      OnGotMessageBytes();
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void ConnectionHandler::OnGotVersion() {
+  uint8 version = 0;
+  {
+    CodedInputStream coded_input_stream(input_stream_.get());
+    coded_input_stream.ReadRaw(&version, 1);
+  }
+  if (version < kMCSVersion) {
+    LOG(ERROR) << "Invalid GCM version response: " << static_cast<int>(version);
+    connection_callback_.Run(net::ERR_FAILED);
+    return;
+  }
+
+  input_stream_->RebuildBuffer();
+
+  // Process the LoginResponse message tag.
+  OnGotMessageTag();
+}
+
+void ConnectionHandler::OnGotMessageTag() {
+  if (input_stream_->GetState() != SocketInputStream::READY) {
+    LOG(ERROR) << "Failed to receive protobuf tag.";
+    read_callback_.Run(scoped_ptr<google::protobuf::MessageLite>());
+    return;
+  }
+
+  {
+    CodedInputStream coded_input_stream(input_stream_.get());
+    coded_input_stream.ReadRaw(&message_tag_, 1);
+  }
+
+  DVLOG(1) << "Received proto of type "
+           << static_cast<unsigned int>(message_tag_);
+
+  if (!read_timeout_timer_.IsRunning()) {
+    read_timeout_timer_.Start(FROM_HERE,
+                              read_timeout_,
+                              base::Bind(&ConnectionHandler::OnTimeout,
+                                         weak_ptr_factory_.GetWeakPtr()));
+  }
+  OnGotMessageSize();
+}
+
+void ConnectionHandler::OnGotMessageSize() {
+  if (input_stream_->GetState() != SocketInputStream::READY) {
+    LOG(ERROR) << "Failed to receive message size.";
+    read_callback_.Run(scoped_ptr<google::protobuf::MessageLite>());
+    return;
+  }
+
+  bool need_another_byte = false;
+  int prev_byte_count = input_stream_->ByteCount();
+  {
+    CodedInputStream coded_input_stream(input_stream_.get());
+    if (!coded_input_stream.ReadVarint32(&message_size_))
+      need_another_byte = true;
+  }
+
+  if (need_another_byte) {
+    DVLOG(1) << "Expecting another message size byte.";
+    if (prev_byte_count >= kSizePacketLenMax) {
+      // Already had enough bytes, something else went wrong.
+      LOG(ERROR) << "Failed to process message size.";
+      read_callback_.Run(scoped_ptr<google::protobuf::MessageLite>());
+      return;
+    }
+    // Back up by the amount read (should always be 1 byte).
+    int bytes_read = prev_byte_count - input_stream_->ByteCount();
+    DCHECK_EQ(bytes_read, 1);
+    input_stream_->BackUp(bytes_read);
+    WaitForData(MCS_FULL_SIZE);
+    return;
+  }
+
+  DVLOG(1) << "Proto size: " << message_size_;
+
+  if (message_size_ > 0)
+    WaitForData(MCS_PROTO_BYTES);
+  else
+    OnGotMessageBytes();
+}
+
+void ConnectionHandler::OnGotMessageBytes() {
+  read_timeout_timer_.Stop();
+  scoped_ptr<google::protobuf::MessageLite> protobuf(
+      BuildProtobufFromTag(message_tag_));
+  // Messages with no content are valid; just use the default protobuf for
+  // that tag.
+  if (protobuf.get() && message_size_ == 0) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&ConnectionHandler::GetNextMessage,
+                   weak_ptr_factory_.GetWeakPtr()));
+    read_callback_.Run(protobuf.Pass());
+    return;
+  }
+
+  if (!protobuf.get() ||
+      input_stream_->GetState() != SocketInputStream::READY) {
+    LOG(ERROR) << "Failed to extract protobuf bytes of type "
+               << static_cast<unsigned int>(message_tag_);
+    protobuf.reset();  // Return a null pointer to denote an error.
+    read_callback_.Run(protobuf.Pass());
+    return;
+  }
+
+  {
+    CodedInputStream coded_input_stream(input_stream_.get());
+    if (!protobuf->ParsePartialFromCodedStream(&coded_input_stream)) {
+      NOTREACHED() << "Unable to parse GCM message of type "
+                   << static_cast<unsigned int>(message_tag_);
+      protobuf.reset();  // Return a null pointer to denote an error.
+      read_callback_.Run(protobuf.Pass());
+      return;
+    }
+  }
+
+  input_stream_->RebuildBuffer();
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&ConnectionHandler::GetNextMessage,
+                 weak_ptr_factory_.GetWeakPtr()));
+  if (message_tag_ == kLoginResponseTag) {
+    if (handshake_complete_) {
+      LOG(ERROR) << "Unexpected login response.";
+    } else {
+      handshake_complete_ = true;
+      DVLOG(1) << "GCM Handshake complete.";
+    }
+  }
+  read_callback_.Run(protobuf.Pass());
+}
+
+void ConnectionHandler::OnTimeout() {
+  LOG(ERROR) << "Timed out waiting for GCM Protocol buffer.";
+  CloseConnection();
+  connection_callback_.Run(net::ERR_TIMED_OUT);
+}
+
+void ConnectionHandler::CloseConnection() {
+  DVLOG(1) << "Closing connection.";
+  read_callback_.Reset();
+  write_callback_.Reset();
+  read_timeout_timer_.Stop();
+  socket_->Disconnect();
+  input_stream_.reset();
+  output_stream_.reset();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+}  // namespace gcm
diff --git a/google_apis/gcm/engine/connection_handler.h b/google_apis/gcm/engine/connection_handler.h
new file mode 100644
index 0000000..6dd838c
--- /dev/null
+++ b/google_apis/gcm/engine/connection_handler.h
@@ -0,0 +1,145 @@
+// Copyright 2013 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 GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_
+#define GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "google_apis/gcm/base/gcm_export.h"
+#include "google_apis/gcm/protocol/mcs.pb.h"
+
+namespace net{
+class StreamSocket;
+}
+
+namespace gcm {
+
+class SocketInputStream;
+class SocketOutputStream;
+
+// Handles performing the protocol handshake and sending/receiving protobuf
+// messages. Note that no retrying or queueing is enforced at this layer.
+// Once a connection error is encountered, the ConnectionHandler will disconnect
+// the socket and must be reinitialized with a new StreamSocket before
+// messages can be sent/received again.
+class GCM_EXPORT ConnectionHandler {
+ public:
+  typedef base::Callback<void(scoped_ptr<google::protobuf::MessageLite>)>
+      ProtoReceivedCallback;
+  typedef base::Closure ProtoSentCallback;
+  typedef base::Callback<void(int)> ConnectionChangedCallback;
+
+  explicit ConnectionHandler(base::TimeDelta read_timeout);
+  ~ConnectionHandler();
+
+  // Starts a new MCS connection handshake (using |login_request|) and, upon
+  // success, begins listening for incoming/outgoing messages. A successful
+  // handshake is when a mcs_proto::LoginResponse is received, and is signaled
+  // via the |read_callback|.
+  // Outputs:
+  // |read_callback| will be invoked with the contents of any received protobuf
+  // message.
+  // |write_callback| will be invoked anytime a message has been successfully
+  // sent. Note: this just means the data was sent to the wire, not that the
+  // other end received it.
+  // |connection_callback| will be invoked with any fatal read/write errors
+  // encountered.
+  //
+  // Note: It is correct and expected to call Init more than once, as connection
+  // issues are encountered and new connections must be made.
+  void Init(scoped_ptr<net::StreamSocket> socket,
+            const google::protobuf::MessageLite& login_request,
+            const ProtoReceivedCallback& read_callback,
+            const ProtoSentCallback& write_callback,
+            const ConnectionChangedCallback& connection_callback);
+
+  // Checks that a handshake has been completed and a message is not already
+  // in flight.
+  bool CanSendMessage() const;
+
+  // Send an MCS protobuf message. CanSendMessage() must be true.
+  void SendMessage(const google::protobuf::MessageLite& message);
+
+ private:
+  // State machine for handling incoming data. See WaitForData(..) for usage.
+  enum ProcessingState {
+    // Processing the version, tag, and size packets (assuming minimum length
+    // size packet). Only used during the login handshake.
+    MCS_VERSION_TAG_AND_SIZE = 0,
+    // Processing the tag and size packets (assuming minimum length size
+    // packet). Used for normal messages.
+    MCS_TAG_AND_SIZE,
+    // Processing a maximum length size packet (for messages with length > 128).
+    // Used when a normal size packet was not sufficient to read the message
+    // size.
+    MCS_FULL_SIZE,
+    // Processing the protocol buffer bytes (for those messages with non-zero
+    // sizes).
+    MCS_PROTO_BYTES
+  };
+
+  // Sends the protocol version and login request. First step in the MCS
+  // connection handshake.
+  void Login(const google::protobuf::MessageLite& login_request);
+
+  // SendMessage continuation. Invoked when Socket::Write completes.
+  void OnMessageSent();
+
+  // Starts the message processing process, which is comprised of the tag,
+  // message size, and bytes packet types.
+  void GetNextMessage();
+
+  // Performs any necessary SocketInputStream refreshing until the data
+  // associated with |packet_type| is fully ready, then calls the appropriate
+  // OnGot* message to process the packet data. If the read times out,
+  // will close the stream and invoke the connection callback.
+  void WaitForData(ProcessingState state);
+
+  // Incoming data helper methods.
+  void OnGotVersion();
+  void OnGotMessageTag();
+  void OnGotMessageSize();
+  void OnGotMessageBytes();
+
+  // Timeout handler.
+  void OnTimeout();
+
+  // Closes the current connection.
+  void CloseConnection();
+
+  // Timeout policy: the timeout is only enforced while waiting on the
+  // handshake (version and/or LoginResponse) or once at least a tag packet has
+  // been received. It is reset every time new data is received, and is
+  // only stopped when a full message is processed.
+  // TODO(zea): consider enforcing a separate timeout when waiting for
+  // a message to send.
+  const base::TimeDelta read_timeout_;
+  base::OneShotTimer<ConnectionHandler> read_timeout_timer_;
+
+  // This connection's socket and the input/output streams attached to it.
+  scoped_ptr<net::StreamSocket> socket_;
+  scoped_ptr<SocketInputStream> input_stream_;
+  scoped_ptr<SocketOutputStream> output_stream_;
+
+  // Whether the MCS login handshake has successfully completed. See Init(..)
+  // description for more info on what the handshake involves.
+  bool handshake_complete_;
+
+  // State for the message currently being processed, if there is one.
+  uint8 message_tag_;
+  uint32 message_size_;
+
+  ProtoReceivedCallback read_callback_;
+  ProtoSentCallback write_callback_;
+  ConnectionChangedCallback connection_callback_;
+
+  base::WeakPtrFactory<ConnectionHandler> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectionHandler);
+};
+
+}  // namespace gcm
+
+#endif  // GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_
diff --git a/google_apis/gcm/engine/connection_handler_unittest.cc b/google_apis/gcm/engine/connection_handler_unittest.cc
new file mode 100644
index 0000000..d46c068
--- /dev/null
+++ b/google_apis/gcm/engine/connection_handler_unittest.cc
@@ -0,0 +1,626 @@
+// Copyright 2013 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 "google_apis/gcm/engine/connection_handler.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/test_timeouts.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+#include "google_apis/gcm/base/mcs_util.h"
+#include "google_apis/gcm/base/socket_stream.h"
+#include "google_apis/gcm/protocol/mcs.pb.h"
+#include "net/socket/socket_test_util.h"
+#include "net/socket/stream_socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gcm {
+namespace {
+
+typedef scoped_ptr<google::protobuf::MessageLite> ScopedMessage;
+typedef std::vector<net::MockRead> ReadList;
+typedef std::vector<net::MockWrite> WriteList;
+
+const uint64 kAuthId = 54321;
+const uint64 kAuthToken = 12345;
+const char kMCSVersion = 38;  // The protocol version.
+const int kMCSPort = 5228;    // The server port.
+const char kDataMsgFrom[] = "data_from";
+const char kDataMsgCategory[] = "data_category";
+const char kDataMsgFrom2[] = "data_from2";
+const char kDataMsgCategory2[] = "data_category2";
+const char kDataMsgFromLong[] =
+    "this is a long from that will result in a message > 128 bytes";
+const char kDataMsgCategoryLong[] =
+    "this is a long category that will result in a message > 128 bytes";
+const char kDataMsgFromLong2[] =
+    "this is a second long from that will result in a message > 128 bytes";
+const char kDataMsgCategoryLong2[] =
+    "this is a second long category that will result in a message > 128 bytes";
+
+// ---- Helpers for building messages. ----
+
+// Encode a protobuf packet with protobuf type |tag| and serialized protobuf
+// bytes |proto| into the MCS message form (tag + varint size + bytes).
+std::string EncodePacket(uint8 tag, const std::string& proto) {
+  std::string result;
+  google::protobuf::io::StringOutputStream string_output_stream(&result);
+  google::protobuf::io::CodedOutputStream coded_output_stream(
+      &string_output_stream);
+  const unsigned char tag_byte[1] = {tag};
+  coded_output_stream.WriteRaw(tag_byte, 1);
+  coded_output_stream.WriteVarint32(proto.size());
+  coded_output_stream.WriteRaw(proto.c_str(), proto.size());
+  return result;
+}
+
+// Encode a handshake request into the MCS message form.
+std::string EncodeHandshakeRequest() {
+  std::string result;
+  const char version_byte[1] = {kMCSVersion};
+  result.append(version_byte, 1);
+  ScopedMessage login_request(BuildLoginRequest(kAuthId, kAuthToken));
+  result.append(EncodePacket(kLoginRequestTag,
+                             login_request->SerializeAsString()));
+  return result;
+}
+
+// Build a serialized login response protobuf.
+std::string BuildLoginResponse() {
+  std::string result;
+  mcs_proto::LoginResponse login_response;
+  login_response.set_id("id");
+  result.append(login_response.SerializeAsString());
+  return result;
+}
+
+// Encoode a handshake response into the MCS message form.
+std::string EncodeHandshakeResponse() {
+  std::string result;
+  const char version_byte[1] = {kMCSVersion};
+  result.append(version_byte, 1);
+  result.append(EncodePacket(kLoginResponseTag, BuildLoginResponse()));
+  return result;
+}
+
+// Build a serialized data message stanza protobuf.
+std::string BuildDataMessage(const std::string& from,
+                             const std::string& category) {
+  std::string result;
+  mcs_proto::DataMessageStanza data_message;
+  data_message.set_from(from);
+  data_message.set_category(category);
+  return data_message.SerializeAsString();
+}
+
+class GCMConnectionHandlerTest : public testing::Test {
+ public:
+  GCMConnectionHandlerTest();
+  virtual ~GCMConnectionHandlerTest();
+
+  net::StreamSocket* BuildSocket(const ReadList& read_list,
+                                 const WriteList& write_list);
+
+  // Pump |message_loop_|, resetting |run_loop_| after completion.
+  void PumpLoop();
+
+  ConnectionHandler* connection_handler() { return &connection_handler_; }
+  base::MessageLoop* message_loop() { return &message_loop_; };
+  net::DelayedSocketData* data_provider() { return data_provider_.get(); }
+  int last_error() const { return last_error_; }
+
+  // Initialize the connection handler, setting |dst_proto| as the destination
+  // for any received messages.
+  void Connect(ScopedMessage* dst_proto);
+
+  // Runs the message loop until a message is received.
+  void WaitForMessage();
+
+ private:
+  void ReadContinuation(ScopedMessage* dst_proto, ScopedMessage new_proto);
+  void WriteContinuation();
+  void ConnectionContinuation(int error);
+
+  // SocketStreams and their data provider.
+  ReadList mock_reads_;
+  WriteList mock_writes_;
+  scoped_ptr<net::DelayedSocketData> data_provider_;
+  scoped_ptr<SocketInputStream> socket_input_stream_;
+  scoped_ptr<SocketOutputStream> socket_output_stream_;
+
+  // The connection handler being tested.
+  ConnectionHandler connection_handler_;
+
+  // The last connection error received.
+  int last_error_;
+
+  // net:: components.
+  scoped_ptr<net::StreamSocket> socket_;
+  net::MockClientSocketFactory socket_factory_;
+  net::AddressList address_list_;
+
+  base::MessageLoopForIO message_loop_;
+  scoped_ptr<base::RunLoop> run_loop_;
+};
+
+GCMConnectionHandlerTest::GCMConnectionHandlerTest()
+    : connection_handler_(TestTimeouts::tiny_timeout()),
+      last_error_(0) {
+  net::IPAddressNumber ip_number;
+  net::ParseIPLiteralToNumber("127.0.0.1", &ip_number);
+  address_list_ = net::AddressList::CreateFromIPAddress(ip_number, kMCSPort);
+}
+
+GCMConnectionHandlerTest::~GCMConnectionHandlerTest() {
+}
+
+net::StreamSocket* GCMConnectionHandlerTest::BuildSocket(
+    const ReadList& read_list,
+    const WriteList& write_list) {
+  mock_reads_ = read_list;
+  mock_writes_ = write_list;
+  data_provider_.reset(
+      new net::DelayedSocketData(0,
+                                 &(mock_reads_[0]), mock_reads_.size(),
+                                 &(mock_writes_[0]), mock_writes_.size()));
+  socket_factory_.AddSocketDataProvider(data_provider_.get());
+
+  socket_ = socket_factory_.CreateTransportClientSocket(
+      address_list_, NULL, net::NetLog::Source());
+  socket_->Connect(net::CompletionCallback());
+
+  run_loop_.reset(new base::RunLoop());
+  PumpLoop();
+
+  DCHECK(socket_->IsConnected());
+  return socket_.get();
+}
+
+void GCMConnectionHandlerTest::PumpLoop() {
+  run_loop_->RunUntilIdle();
+  run_loop_.reset(new base::RunLoop());
+}
+
+void GCMConnectionHandlerTest::Connect(
+    ScopedMessage* dst_proto) {
+  connection_handler_.Init(
+      socket_.Pass(),
+      *BuildLoginRequest(kAuthId, kAuthToken),
+      base::Bind(&GCMConnectionHandlerTest::ReadContinuation,
+                 base::Unretained(this),
+                 dst_proto),
+      base::Bind(&GCMConnectionHandlerTest::WriteContinuation,
+                 base::Unretained(this)),
+      base::Bind(&GCMConnectionHandlerTest::ConnectionContinuation,
+                 base::Unretained(this)));
+}
+
+void GCMConnectionHandlerTest::ReadContinuation(
+    ScopedMessage* dst_proto,
+    ScopedMessage new_proto) {
+  *dst_proto = new_proto.Pass();
+  run_loop_->Quit();
+}
+
+void GCMConnectionHandlerTest::WaitForMessage() {
+  run_loop_->Run();
+  run_loop_.reset(new base::RunLoop());
+}
+
+void GCMConnectionHandlerTest::WriteContinuation() {
+  run_loop_->Quit();
+}
+
+void GCMConnectionHandlerTest::ConnectionContinuation(int error) {
+  last_error_ = error;
+  run_loop_->Quit();
+}
+
+// Initialize the connection handler and ensure the handshake completes
+// successfully.
+TEST_F(GCMConnectionHandlerTest, Init) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+  ReadList read_list(1, net::MockRead(net::ASYNC,
+                                      handshake_response.c_str(),
+                                      handshake_response.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  Connect(&received_message);
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString());
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+}
+
+// Simulate the handshake response returning an older version. Initialization
+// should fail.
+TEST_F(GCMConnectionHandlerTest, InitFailedVersionCheck) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+  // Overwrite the version byte.
+  handshake_response[0] = 37;
+  ReadList read_list(1, net::MockRead(net::ASYNC,
+                                      handshake_response.c_str(),
+                                      handshake_response.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response. Should result in a connection error.
+  EXPECT_FALSE(received_message.get());
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  EXPECT_EQ(net::ERR_FAILED, last_error());
+}
+
+// Attempt to initialize, but receive no server response, resulting in a time
+// out.
+TEST_F(GCMConnectionHandlerTest, InitTimeout) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  ReadList read_list(1, net::MockRead(net::SYNCHRONOUS,
+                                      net::ERR_IO_PENDING));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response. Should result in a connection error.
+  EXPECT_FALSE(received_message.get());
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  EXPECT_EQ(net::ERR_TIMED_OUT, last_error());
+}
+
+// Attempt to initialize, but receive an incomplete server response, resulting
+// in a time out.
+TEST_F(GCMConnectionHandlerTest, InitIncompleteTimeout) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size() / 2));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS,
+                                    net::ERR_IO_PENDING));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response. Should result in a connection error.
+  EXPECT_FALSE(received_message.get());
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  EXPECT_EQ(net::ERR_TIMED_OUT, last_error());
+}
+
+// Reinitialize the connection handler after failing to initialize.
+TEST_F(GCMConnectionHandlerTest, ReInit) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  ReadList read_list(1, net::MockRead(net::SYNCHRONOUS,
+                                      net::ERR_IO_PENDING));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response. Should result in a connection error.
+  EXPECT_FALSE(received_message.get());
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  EXPECT_EQ(net::ERR_TIMED_OUT, last_error());
+
+  // Build a new socket and reconnect, successfully this time.
+  std::string handshake_response = EncodeHandshakeResponse();
+  read_list[0] = net::MockRead(net::ASYNC,
+                               handshake_response.c_str(),
+                               handshake_response.size());
+  BuildSocket(read_list, write_list);
+  Connect(&received_message);
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString());
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+}
+
+// Verify that messages can be received after initialization.
+TEST_F(GCMConnectionHandlerTest, RecvMsg) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
+                                                    kDataMsgCategory);
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message_proto);
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    data_message_pkt.c_str(),
+                                    data_message_pkt.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  WaitForMessage();  // The data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto, received_message->SerializeAsString());
+}
+
+// Verify that if two messages arrive at once, they're treated appropriately.
+TEST_F(GCMConnectionHandlerTest, Recv2Msgs) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
+                                                    kDataMsgCategory);
+  std::string data_message_proto2 = BuildDataMessage(kDataMsgFrom2,
+                                                     kDataMsgCategory2);
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message_proto);
+  data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2);
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS,
+                                    data_message_pkt.c_str(),
+                                    data_message_pkt.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  WaitForMessage();  // The first data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto, received_message->SerializeAsString());
+  received_message.reset();
+  WaitForMessage();  // The second data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto2, received_message->SerializeAsString());
+}
+
+// Receive a long (>128 bytes) message.
+TEST_F(GCMConnectionHandlerTest, RecvLongMsg) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_proto =
+      BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong);
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message_proto);
+  DCHECK_GT(data_message_pkt.size(), 128U);
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    data_message_pkt.c_str(),
+                                    data_message_pkt.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  WaitForMessage();  // The data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto, received_message->SerializeAsString());
+}
+
+// Receive two long (>128 bytes) message.
+TEST_F(GCMConnectionHandlerTest, Recv2LongMsgs) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_proto =
+      BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong);
+  std::string data_message_proto2 =
+      BuildDataMessage(kDataMsgFromLong2, kDataMsgCategoryLong2);
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message_proto);
+  data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2);
+  DCHECK_GT(data_message_pkt.size(), 256U);
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS,
+                                    data_message_pkt.c_str(),
+                                    data_message_pkt.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  WaitForMessage();  // The first data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto, received_message->SerializeAsString());
+  received_message.reset();
+  WaitForMessage();  // The second data message.
+  ASSERT_TRUE(received_message.get());
+  EXPECT_EQ(data_message_proto2, received_message->SerializeAsString());
+}
+
+// Simulate a message where the end of the data does not arrive in time and the
+// read times out.
+TEST_F(GCMConnectionHandlerTest, ReadTimeout) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
+                                                    kDataMsgCategory);
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message_proto);
+  int bytes_in_first_message = data_message_pkt.size() / 2;
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    data_message_pkt.c_str(),
+                                    bytes_in_first_message));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS,
+                                    net::ERR_IO_PENDING));
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    data_message_pkt.c_str() +
+                                        bytes_in_first_message,
+                                    data_message_pkt.size() -
+                                        bytes_in_first_message));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  received_message.reset();
+  WaitForMessage();  // Should time out.
+  EXPECT_FALSE(received_message.get());
+  EXPECT_EQ(net::ERR_TIMED_OUT, last_error());
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+
+  // Finish the socket read. Should have no effect.
+  data_provider()->ForceNextRead();
+}
+
+// Receive a message with zero data bytes.
+TEST_F(GCMConnectionHandlerTest, RecvMsgNoData) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list(1, net::MockWrite(net::ASYNC,
+                                         handshake_request.c_str(),
+                                         handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+
+  std::string data_message_pkt = EncodePacket(kHeartbeatPingTag, "");
+  ASSERT_EQ(data_message_pkt.size(), 2U);
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    data_message_pkt.c_str(),
+                                    data_message_pkt.size()));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  received_message.reset();
+  WaitForMessage();  // The heartbeat ping.
+  EXPECT_TRUE(received_message.get());
+  EXPECT_EQ(GetMCSProtoTag(*received_message), kHeartbeatPingTag);
+  EXPECT_EQ(net::OK, last_error());
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+}
+
+// Send a message after performing the handshake.
+TEST_F(GCMConnectionHandlerTest, SendMsg) {
+  mcs_proto::DataMessageStanza data_message;
+  data_message.set_from(kDataMsgFrom);
+  data_message.set_category(kDataMsgCategory);
+  std::string handshake_request = EncodeHandshakeRequest();
+  std::string data_message_pkt =
+      EncodePacket(kDataMessageStanzaTag, data_message.SerializeAsString());
+  WriteList write_list;
+  write_list.push_back(net::MockWrite(net::ASYNC,
+                                      handshake_request.c_str(),
+                                      handshake_request.size()));
+  write_list.push_back(net::MockWrite(net::ASYNC,
+                                      data_message_pkt.c_str(),
+                                      data_message_pkt.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
+  BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+  connection_handler()->SendMessage(data_message);
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  WaitForMessage();  // The message send.
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+}
+
+// Attempt to send a message after the socket is disconnected due to a timeout.
+TEST_F(GCMConnectionHandlerTest, SendMsgSocketDisconnected) {
+  std::string handshake_request = EncodeHandshakeRequest();
+  WriteList write_list;
+  write_list.push_back(net::MockWrite(net::ASYNC,
+                                      handshake_request.c_str(),
+                                      handshake_request.size()));
+  std::string handshake_response = EncodeHandshakeResponse();
+  ReadList read_list;
+  read_list.push_back(net::MockRead(net::ASYNC,
+                                    handshake_response.c_str(),
+                                    handshake_response.size()));
+  read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
+  net::StreamSocket* socket = BuildSocket(read_list, write_list);
+
+  ScopedMessage received_message;
+  Connect(&received_message);
+  WaitForMessage();  // The login send.
+  WaitForMessage();  // The login response.
+  EXPECT_TRUE(connection_handler()->CanSendMessage());
+  socket->Disconnect();
+  mcs_proto::DataMessageStanza data_message;
+  data_message.set_from(kDataMsgFrom);
+  data_message.set_category(kDataMsgCategory);
+  connection_handler()->SendMessage(data_message);
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  WaitForMessage();  // The message send. Should result in an error
+  EXPECT_FALSE(connection_handler()->CanSendMessage());
+  EXPECT_EQ(net::ERR_CONNECTION_CLOSED, last_error());
+}
+
+}  // namespace
+}  // namespace gcm
diff --git a/google_apis/gcm/gcm.gyp b/google_apis/gcm/gcm.gyp
index c1ab33b..f04fbee 100644
--- a/google_apis/gcm/gcm.gyp
+++ b/google_apis/gcm/gcm.gyp
@@ -12,7 +12,13 @@
     {
       'target_name': 'gcm',
       'type': '<(component)',
-      'variables': { 'enable_wexit_time_destructors': 1, },
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'proto_in_dir': './protocol',
+        'proto_out_dir': 'google_apis/gcm/protocol',
+        'cc_generator_options': 'dllexport_decl=GCM_EXPORT:',
+        'cc_include': 'google_apis/gcm/base/gcm_export.h',
+      },
       'include_dirs': [
         '../..',
       ],
@@ -28,8 +34,16 @@
         '../../third_party/protobuf/protobuf.gyp:protobuf_lite'
       ],
       'sources': [
+        'base/mcs_util.h',
+        'base/mcs_util.cc',
         'base/socket_stream.h',
         'base/socket_stream.cc',
+        'engine/connection_handler.h',
+        'engine/connection_handler.cc',
+        'protocol/mcs.proto',
+      ],
+      'includes': [
+        '../../build/protoc.gypi'
       ],
     },
 
@@ -46,10 +60,13 @@
         '../../base/base.gyp:base',
         '../../net/net.gyp:net_test_support',
         '../../testing/gtest.gyp:gtest',
+        '../../third_party/protobuf/protobuf.gyp:protobuf_lite',
         'gcm'
       ],
       'sources': [
+        'base/mcs_util_unittest.cc',
         'base/socket_stream_unittest.cc',
+        'engine/connection_handler_unittest.cc',
       ]
     },
   ],
diff --git a/google_apis/gcm/protocol/mcs.proto b/google_apis/gcm/protocol/mcs.proto
new file mode 100644
index 0000000..2926d10
--- /dev/null
+++ b/google_apis/gcm/protocol/mcs.proto
@@ -0,0 +1,269 @@
+// Copyright 2013 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.
+//
+// MCS protocol for communication between Chrome client and Mobile Connection
+// Server .
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option retain_unknown_fields = true;
+
+package mcs_proto;
+
+/*
+   Common fields/comments:
+
+    stream_id: no longer sent by server, each side keeps a counter
+    last_stream_id_received: sent only if a packet was received since last time
+    a last_stream was sent
+    status: new bitmask including the 'idle' as bit 0.
+
+ */
+
+/**
+  TAG: 0
+  */
+message HeartbeatPing {
+  optional int32 stream_id = 1;
+  optional int32 last_stream_id_received = 2;
+  optional int64 status = 3;
+}
+
+/**
+  TAG: 1
+  */
+message HeartbeatAck {
+  optional int32 stream_id = 1;
+  optional int32 last_stream_id_received = 2;
+  optional int64 status = 3;
+}
+
+message ErrorInfo {
+  required int32 code = 1;
+  optional string message = 2;
+  optional string type = 3;
+  optional  Extension extension = 4;
+}
+
+// MobileSettings class.
+// "u:f", "u:b", "u:s" - multi user devices reporting foreground, background
+// and stopped users.
+// hbping: heatbeat ping interval
+// rmq2v: include explicit stream IDs
+
+message Setting {
+  required string name = 1;
+  required string value = 2;
+}
+
+message HeartbeatStat {
+  required string ip = 1;
+  required bool timeout = 2;
+  required int32 interval_ms = 3;
+}
+
+message HeartbeatConfig {
+  optional bool upload_stat = 1;
+  optional string ip = 2;
+  optional int32 interval_ms = 3;
+}
+
+/**
+  TAG: 2
+  */
+message LoginRequest {
+  enum AuthService {
+    ANDROID_ID = 2;
+  }
+  required string id = 1; // Must be present ( proto required ), may be empty
+                          // string.
+  // mcs.android.com.
+  required string domain = 2;
+  // Decimal android ID
+  required string user = 3;
+
+  required string resource = 4;
+
+  // Secret
+  required string auth_token = 5;
+
+  // Format is: android-HEX_DEVICE_ID
+  // The user is the decimal value.
+  optional string device_id = 6;
+
+  // RMQ1 - no longer used
+  optional int64 last_rmq_id = 7;
+
+  repeated Setting setting = 8;
+  //optional int32 compress = 9;
+  repeated string received_persistent_id = 10;
+
+  // Replaced by "rmq2v" setting
+  // optional bool include_stream_ids = 11;
+
+  optional bool adaptive_heartbeat = 12;
+  optional HeartbeatStat heartbeat_stat = 13;
+  // Must be true.
+  optional bool use_rmq2 = 14;
+  optional int64 account_id = 15;
+
+  // ANDROID_ID = 2
+  optional AuthService auth_service = 16;
+
+  optional int32 network_type = 17;
+  optional int64 status = 18;
+}
+
+/**
+  * TAG: 3
+  */
+message LoginResponse {
+  required string id = 1;
+  // Not used.
+  optional string jid = 2;
+  // Null if login was ok.
+  optional ErrorInfo error = 3;
+  repeated Setting setting = 4;
+  optional int32 stream_id = 5;
+  // Should be "1"
+  optional int32 last_stream_id_received = 6;
+  optional HeartbeatConfig heartbeat_config = 7;
+  // used by the client to synchronize with the server timestamp.
+  optional int64 server_timestamp = 8;
+}
+
+message StreamErrorStanza {
+  required string type = 1;
+  optional string text = 2;
+}
+
+/**
+  * TAG: 4
+  */
+message Close {
+}
+
+message Extension {
+  // 12: SelectiveAck
+  // 13: StreamAck
+  required int32 id = 1;
+  required bytes data = 2;
+}
+
+/**
+  * TAG: 7
+  * IqRequest must contain a single extension.  IqResponse may contain 0 or 1
+  * extensions.
+  */
+message IqStanza {
+  enum IqType {
+    GET = 0;
+    SET = 1;
+    RESULT = 2;
+    IQ_ERROR = 3;
+  }
+
+  optional int64 rmq_id = 1;
+  required IqType type = 2;
+  required string id = 3;
+  optional string from = 4;
+  optional string to = 5;
+  optional ErrorInfo error = 6;
+
+  // Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)
+  optional Extension extension = 7;
+
+  optional string persistent_id = 8;
+  optional int32 stream_id = 9;
+  optional int32 last_stream_id_received = 10;
+  optional int64 account_id = 11;
+  optional int64 status = 12;
+}
+
+message AppData {
+  required string key = 1;
+  required string value = 2;
+}
+
+/**
+ * TAG: 8
+ */
+message DataMessageStanza {
+  // Not used.
+  // optional int64 rmq_id = 1;
+
+  // This is the message ID, set by client, DMP.9 (message_id)
+  optional string id = 2;
+
+  // Project ID of the sender, DMP.1
+  required string from = 3;
+
+  // Part of DMRequest - also the key in DataMessageProto.
+  optional string to = 4;
+
+  // Package name. DMP.2
+  required string category = 5;
+
+  // The collapsed key, DMP.3
+  optional string token = 6;
+
+  // User data + GOOGLE. prefixed special entries, DMP.4
+  repeated AppData app_data = 7;
+
+  // Not used.
+  optional bool from_trusted_server = 8;
+
+  // Part of the ACK protocol, returned in DataMessageResponse on server side.
+  // It's part of the key of DMP.
+  optional string persistent_id = 9;
+
+  // In-stream ack. Increments on each message sent - a bit redundant
+  // Not used in DMP/DMR.
+  optional int32 stream_id = 10;
+  optional int32 last_stream_id_received = 11;
+
+  // Not used.
+  // optional string permission = 12;
+
+  // Sent by the device shortly after registration.
+  optional string reg_id = 13;
+
+  // Not used.
+  // optional string pkg_signature = 14;
+  // Not used.
+  // optional string client_id = 15;
+
+  // serial number of the target user, DMP.8
+  // It is the 'serial number' according to user manager.
+  optional int64 device_user_id = 16;
+
+  // Time to live, in seconds.
+  optional int32 ttl = 17;
+  // Timestamp ( according to client ) when message was sent by app, in seconds
+  optional int64 sent = 18;
+
+  // How long has the message been queued before the flush, in seconds.
+  // This is needed to account for the time difference between server and
+  // client: server should adjust 'sent' based on his 'receive' time.
+  optional int32 queued = 19;
+
+  optional int64 status = 20;
+}
+
+/**
+  Included in IQ with ID 13, sent from client or server after 10 unconfirmed
+  messages.
+ */
+message StreamAck {
+  // No last_streamid_received required.  This is included within an IqStanza,
+  // which includes the last_stream_id_received.
+}
+
+/**
+  Included in IQ sent after LoginResponse from server with ID 12.
+*/
+message SelectiveAck {
+  repeated string id = 1;
+}
diff --git a/google_apis/google_apis.target.darwin-arm.mk b/google_apis/google_apis.target.darwin-arm.mk
index da9800f..8fbba6f 100644
--- a/google_apis/google_apis.target.darwin-arm.mk
+++ b/google_apis/google_apis.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/google_apis/google_apis.target.darwin-mips.mk b/google_apis/google_apis.target.darwin-mips.mk
index e85c8dc..0a97aa3 100644
--- a/google_apis/google_apis.target.darwin-mips.mk
+++ b/google_apis/google_apis.target.darwin-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/google_apis/google_apis.target.darwin-x86.mk b/google_apis/google_apis.target.darwin-x86.mk
index f52167c..891a92f 100644
--- a/google_apis/google_apis.target.darwin-x86.mk
+++ b/google_apis/google_apis.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/google_apis/google_apis.target.linux-arm.mk b/google_apis/google_apis.target.linux-arm.mk
index da9800f..8fbba6f 100644
--- a/google_apis/google_apis.target.linux-arm.mk
+++ b/google_apis/google_apis.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/google_apis/google_apis.target.linux-mips.mk b/google_apis/google_apis.target.linux-mips.mk
index e85c8dc..0a97aa3 100644
--- a/google_apis/google_apis.target.linux-mips.mk
+++ b/google_apis/google_apis.target.linux-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/google_apis/google_apis.target.linux-x86.mk b/google_apis/google_apis.target.linux-x86.mk
index f52167c..891a92f 100644
--- a/google_apis/google_apis.target.linux-x86.mk
+++ b/google_apis/google_apis.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 71bd004..ba90e00 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -12,6 +12,7 @@
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/compiler_specific.h"
 #include "gpu/command_buffer/common/gpu_control.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -100,6 +101,8 @@
                                      const base::Closure& callback));
 
   MOCK_METHOD2(SignalQuery, void(uint32 query, const base::Closure& callback));
+  MOCK_METHOD1(SendManagedMemoryStats,
+               void(const ManagedMemoryStats& stats));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockClientGpuControl);
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h
index eb50585..a620cd3 100644
--- a/gpu/command_buffer/client/context_support.h
+++ b/gpu/command_buffer/client/context_support.h
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 
 namespace gpu {
+struct ManagedMemoryStats;
 
 class ContextSupport {
  public:
@@ -19,6 +20,8 @@
   // passed the glEndQueryEXT() point.
   virtual void SignalQuery(uint32 query, const base::Closure& callback) = 0;
 
+  virtual void SendManagedMemoryStats(const ManagedMemoryStats& stats) = 0;
+
  protected:
   ContextSupport() {}
   virtual ~ContextSupport() {}
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 6ef8c9f..78eccf5 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -335,6 +335,12 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  callback));
 }
+
+void GLES2Implementation::SendManagedMemoryStats(
+    const ManagedMemoryStats& stats) {
+  gpu_control_->SendManagedMemoryStats(stats);
+}
+
 void GLES2Implementation::WaitForCmd() {
   TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
   helper_->CommandBufferHelper::Finish();
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 40eb50a..af791e5 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -231,6 +231,8 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
+  virtual void SendManagedMemoryStats(const ManagedMemoryStats& stats)
+      OVERRIDE;
 
   void SetErrorMessageCallback(ErrorMessageCallback* callback) {
     error_message_callback_ = callback;
diff --git a/gpu/command_buffer/common/gpu_control.h b/gpu/command_buffer/common/gpu_control.h
index 9c2879a..4fdab4b 100644
--- a/gpu/command_buffer/common/gpu_control.h
+++ b/gpu/command_buffer/common/gpu_control.h
@@ -17,6 +17,7 @@
 }
 
 namespace gpu {
+struct ManagedMemoryStats;
 
 // Common interface for GpuControl implementations.
 class GPU_EXPORT GpuControl {
@@ -54,6 +55,8 @@
   // passed the glEndQueryEXT() point.
   virtual void SignalQuery(uint32 query, const base::Closure& callback) = 0;
 
+  virtual void SendManagedMemoryStats(const ManagedMemoryStats& stats) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(GpuControl);
 };
diff --git a/gpu/command_buffer/common/gpu_memory_allocation.h b/gpu/command_buffer/common/gpu_memory_allocation.h
new file mode 100644
index 0000000..3057592
--- /dev/null
+++ b/gpu/command_buffer/common/gpu_memory_allocation.h
@@ -0,0 +1,111 @@
+// Copyright 2013 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 GPU_COMMAND_BUFFER_COMMON_GPU_MEMORY_ALLOCATION_H_
+#define GPU_COMMAND_BUFFER_COMMON_GPU_MEMORY_ALLOCATION_H_
+
+#include "base/basictypes.h"
+
+namespace gpu {
+
+// These are per context memory allocation limits set by the GpuMemoryManager
+// and assigned to the browser and renderer context.
+// They will change over time, given memory availability, and browser state.
+struct MemoryAllocation {
+  enum PriorityCutoff {
+    // Allow no allocations.
+    CUTOFF_ALLOW_NOTHING,
+    // Allow only allocations that are strictly required for correct rendering.
+    // For compositors, this is what is visible.
+    CUTOFF_ALLOW_REQUIRED_ONLY,
+    // Allow allocations that are not strictly needed for correct rendering, but
+    // are nice to have for performance. For compositors, this includes textures
+    // that are a few screens away from being visible.
+    CUTOFF_ALLOW_NICE_TO_HAVE,
+    // Allow all allocations.
+    CUTOFF_ALLOW_EVERYTHING,
+  };
+
+  // Limits when this renderer is visible.
+  uint64 bytes_limit_when_visible;
+  PriorityCutoff priority_cutoff_when_visible;
+
+  // Limits when this renderer is not visible.
+  uint64 bytes_limit_when_not_visible;
+  PriorityCutoff priority_cutoff_when_not_visible;
+  bool have_backbuffer_when_not_visible;
+
+  MemoryAllocation()
+      : bytes_limit_when_visible(0),
+        priority_cutoff_when_visible(CUTOFF_ALLOW_NOTHING),
+        bytes_limit_when_not_visible(0),
+        priority_cutoff_when_not_visible(CUTOFF_ALLOW_NOTHING),
+        have_backbuffer_when_not_visible(false) {
+  }
+
+  MemoryAllocation(uint64 bytes_limit_when_visible)
+      : bytes_limit_when_visible(bytes_limit_when_visible),
+        priority_cutoff_when_visible(CUTOFF_ALLOW_EVERYTHING),
+        bytes_limit_when_not_visible(0),
+        priority_cutoff_when_not_visible(CUTOFF_ALLOW_NOTHING),
+        have_backbuffer_when_not_visible(false) {
+  }
+
+  bool Equals(const MemoryAllocation& other) const {
+    return bytes_limit_when_visible ==
+               other.bytes_limit_when_visible &&
+        priority_cutoff_when_visible == other.priority_cutoff_when_visible &&
+        bytes_limit_when_not_visible == other.bytes_limit_when_not_visible &&
+        priority_cutoff_when_not_visible ==
+            other.priority_cutoff_when_not_visible &&
+        have_backbuffer_when_not_visible ==
+            other.have_backbuffer_when_not_visible;
+  }
+};
+
+// Memory Allocation request which is sent by a client, to help GpuMemoryManager
+// more ideally split memory allocations across clients.
+struct ManagedMemoryStats {
+  // Bytes required for correct rendering.
+  uint64 bytes_required;
+
+  // Bytes that are not strictly required for correctness, but, if allocated,
+  // will provide good performance.
+  uint64 bytes_nice_to_have;
+
+  // The number of bytes currently allocated.
+  uint64 bytes_allocated;
+
+  // Whether or not a backbuffer is currently requested (the memory usage
+  // of the buffer is known by the GPU process).
+  bool backbuffer_requested;
+
+  ManagedMemoryStats()
+      : bytes_required(0),
+        bytes_nice_to_have(0),
+        bytes_allocated(0),
+        backbuffer_requested(false) {
+  }
+
+  ManagedMemoryStats(uint64 bytes_required,
+                        uint64 bytes_nice_to_have,
+                        uint64 bytes_allocated,
+                        bool backbuffer_requested)
+      : bytes_required(bytes_required),
+        bytes_nice_to_have(bytes_nice_to_have),
+        bytes_allocated(bytes_allocated),
+        backbuffer_requested(backbuffer_requested) {
+  }
+
+  bool Equals(const ManagedMemoryStats& other) const {
+    return bytes_required == other.bytes_required &&
+        bytes_nice_to_have == other.bytes_nice_to_have &&
+        bytes_allocated == other.bytes_allocated &&
+        backbuffer_requested == other.backbuffer_requested;
+  }
+};
+
+}  // namespace content
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GPU_MEMORY_ALLOCATION_H_
diff --git a/gpu/command_buffer/common/mailbox.h b/gpu/command_buffer/common/mailbox.h
index d0e4c2c..938167f 100644
--- a/gpu/command_buffer/common/mailbox.h
+++ b/gpu/command_buffer/common/mailbox.h
@@ -5,6 +5,8 @@
 #ifndef GPU_COMMAND_BUFFER_MAILBOX_H_
 #define GPU_COMMAND_BUFFER_MAILBOX_H_
 
+#include <string.h>
+
 #include "gpu/command_buffer/common/types.h"
 #include "gpu/gpu_export.h"
 
@@ -16,6 +18,9 @@
   void SetZero();
   void SetName(const int8* name);
   int8 name[64];
+  bool operator<(const Mailbox& other) const {
+    return memcmp(this, &other, sizeof other) < 0;
+  }
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/gles2_utils.target.darwin-arm.mk b/gpu/command_buffer/gles2_utils.target.darwin-arm.mk
index ab7aafb..ce8b3db 100644
--- a/gpu/command_buffer/gles2_utils.target.darwin-arm.mk
+++ b/gpu/command_buffer/gles2_utils.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/gles2_utils.target.darwin-mips.mk b/gpu/command_buffer/gles2_utils.target.darwin-mips.mk
index 4493785..eb78e32 100644
--- a/gpu/command_buffer/gles2_utils.target.darwin-mips.mk
+++ b/gpu/command_buffer/gles2_utils.target.darwin-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/gles2_utils.target.darwin-x86.mk b/gpu/command_buffer/gles2_utils.target.darwin-x86.mk
index 1cc99a5..68219a6 100644
--- a/gpu/command_buffer/gles2_utils.target.darwin-x86.mk
+++ b/gpu/command_buffer/gles2_utils.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/gles2_utils.target.linux-arm.mk b/gpu/command_buffer/gles2_utils.target.linux-arm.mk
index ab7aafb..ce8b3db 100644
--- a/gpu/command_buffer/gles2_utils.target.linux-arm.mk
+++ b/gpu/command_buffer/gles2_utils.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/gles2_utils.target.linux-mips.mk b/gpu/command_buffer/gles2_utils.target.linux-mips.mk
index 4493785..eb78e32 100644
--- a/gpu/command_buffer/gles2_utils.target.linux-mips.mk
+++ b/gpu/command_buffer/gles2_utils.target.linux-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/gles2_utils.target.linux-x86.mk b/gpu/command_buffer/gles2_utils.target.linux-x86.mk
index 1cc99a5..68219a6 100644
--- a/gpu/command_buffer/gles2_utils.target.linux-x86.mk
+++ b/gpu/command_buffer/gles2_utils.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer/service/cmd_parser.cc b/gpu/command_buffer/service/cmd_parser.cc
index 0ca1e61..65abc71 100644
--- a/gpu/command_buffer/service/cmd_parser.cc
+++ b/gpu/command_buffer/service/cmd_parser.cc
@@ -7,9 +7,7 @@
 #include "gpu/command_buffer/service/cmd_parser.h"
 
 #include "base/logging.h"
-#include "base/command_line.h"
 #include "base/debug/trace_event.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
 
 namespace gpu {
 
@@ -18,10 +16,7 @@
       put_(0),
       buffer_(NULL),
       entry_count_(0),
-      handler_(handler),
-      trace_gl_commands_(false) {
-  trace_gl_commands_ =
-      CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceGL);
+      handler_(handler) {
 }
 
 void CommandParser::SetBuffer(
@@ -65,8 +60,8 @@
     return error::kOutOfBounds;
   }
 
-  if (trace_gl_commands_)
-    TRACE_EVENT_BEGIN0("cb_command", handler_->GetCommandName(header.command));
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cb_command"),
+               handler_->GetCommandName(header.command));
 
   error::Error result = handler_->DoCommand(
       header.command, header.size - 1, buffer_ + get);
@@ -82,8 +77,6 @@
   if (get == get_ && result != error::kDeferCommandUntilLater)
     get_ = (get + header.size) % entry_count_;
 
-  if (trace_gl_commands_)
-    TRACE_EVENT_END0("cb_command", handler_->GetCommandName(header.command));
   return result;
 }
 
diff --git a/gpu/command_buffer/service/cmd_parser.h b/gpu/command_buffer/service/cmd_parser.h
index c808c4e..de2fe29 100644
--- a/gpu/command_buffer/service/cmd_parser.h
+++ b/gpu/command_buffer/service/cmd_parser.h
@@ -69,7 +69,6 @@
   CommandBufferEntry* buffer_;
   int32 entry_count_;
   AsyncAPIInterface* handler_;
-  bool trace_gl_commands_;
 };
 
 // This class defines the interface for an asynchronous API handler, that
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index c8148a0..2e82d98 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -305,11 +305,11 @@
 // unit zero in case the client has changed that to something invalid.
 class ScopedTexture2DBinder {
  public:
-  ScopedTexture2DBinder(GLES2DecoderImpl* decoder, GLuint id);
+  ScopedTexture2DBinder(ContextState* state, GLuint id);
   ~ScopedTexture2DBinder();
 
  private:
-  GLES2DecoderImpl* decoder_;
+  ContextState* state_;
   DISALLOW_COPY_AND_ASSIGN(ScopedTexture2DBinder);
 };
 
@@ -357,7 +357,7 @@
 // Encapsulates an OpenGL texture.
 class BackTexture {
  public:
-  explicit BackTexture(GLES2DecoderImpl* decoder);
+  explicit BackTexture(MemoryTracker* memory_tracker, ContextState* state);
   ~BackTexture();
 
   // Create a new render texture.
@@ -390,8 +390,8 @@
   }
 
  private:
-  GLES2DecoderImpl* decoder_;
   MemoryTypeTracker memory_tracker_;
+  ContextState* state_;
   size_t bytes_allocated_;
   GLuint id_;
   gfx::Size size_;
@@ -628,7 +628,6 @@
 
   // Restores the current state to the user's settings.
   void RestoreCurrentFramebufferBindings();
-  void RestoreCurrentTexture2DBindings();
 
   // Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer.
   void ApplyDirtyState();
@@ -650,7 +649,6 @@
  private:
   friend class ScopedFrameBufferBinder;
   friend class ScopedResolvedFrameBufferBinder;
-  friend class BackTexture;
   friend class BackFramebuffer;
 
   // Initialize or re-initialize the shader translator.
@@ -1705,11 +1703,24 @@
   ERRORSTATE_CLEAR_REAL_GL_ERRORS(error_state_, function_name_);
 }
 
-ScopedTexture2DBinder::ScopedTexture2DBinder(GLES2DecoderImpl* decoder,
+static void RestoreCurrentTexture2DBindings(ContextState* state) {
+  TextureUnit& info = state->texture_units[0];
+  GLuint last_id;
+  if (info.bound_texture_2d.get()) {
+    last_id = info.bound_texture_2d->service_id();
+  } else {
+    last_id = 0;
+  }
+
+  glBindTexture(GL_TEXTURE_2D, last_id);
+  glActiveTexture(GL_TEXTURE0 + state->active_texture_unit);
+}
+
+ScopedTexture2DBinder::ScopedTexture2DBinder(ContextState* state,
                                              GLuint id)
-    : decoder_(decoder) {
+    : state_(state) {
   ScopedGLErrorSuppressor suppressor(
-      "ScopedTexture2DBinder::ctor", decoder_->GetErrorState());
+      "ScopedTexture2DBinder::ctor", state_->GetErrorState());
 
   // TODO(apatrick): Check if there are any other states that need to be reset
   // before binding a new texture.
@@ -1719,8 +1730,8 @@
 
 ScopedTexture2DBinder::~ScopedTexture2DBinder() {
   ScopedGLErrorSuppressor suppressor(
-      "ScopedTexture2DBinder::dtor", decoder_->GetErrorState());
-  decoder_->RestoreCurrentTexture2DBindings();
+      "ScopedTexture2DBinder::dtor", state_->GetErrorState());
+  RestoreCurrentTexture2DBindings(state_);
 }
 
 ScopedRenderBufferBinder::ScopedRenderBufferBinder(ContextState* state,
@@ -1774,7 +1785,7 @@
           new BackFramebuffer(decoder_));
       decoder_->offscreen_resolved_frame_buffer_->Create();
       decoder_->offscreen_resolved_color_texture_.reset(
-          new BackTexture(decoder_));
+          new BackTexture(decoder->memory_tracker(), &decoder->state_));
       decoder_->offscreen_resolved_color_texture_->Create();
 
       DCHECK(decoder_->offscreen_saved_color_format_);
@@ -1820,9 +1831,11 @@
   }
 }
 
-BackTexture::BackTexture(GLES2DecoderImpl* decoder)
-    : decoder_(decoder),
-      memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
+BackTexture::BackTexture(
+    MemoryTracker* memory_tracker,
+    ContextState* state)
+    : memory_tracker_(memory_tracker, MemoryTracker::kUnmanaged),
+      state_(state),
       bytes_allocated_(0),
       id_(0) {
 }
@@ -1836,10 +1849,10 @@
 
 void BackTexture::Create() {
   ScopedGLErrorSuppressor suppressor("BackTexture::Create",
-                                     decoder_->GetErrorState());
+                                     state_->GetErrorState());
   Destroy();
   glGenTextures(1, &id_);
-  ScopedTexture2DBinder binder(decoder_, id_);
+  ScopedTexture2DBinder binder(state_, id_);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1862,8 +1875,8 @@
     const gfx::Size& size, GLenum format, bool zero) {
   DCHECK_NE(id_, 0u);
   ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage",
-                                     decoder_->GetErrorState());
-  ScopedTexture2DBinder binder(decoder_, id_);
+                                     state_->GetErrorState());
+  ScopedTexture2DBinder binder(state_, id_);
   uint32 image_size = 0;
   GLES2Util::ComputeImageDataSizes(
       size.width(), size.height(), format, GL_UNSIGNED_BYTE, 8, &image_size,
@@ -1903,8 +1916,8 @@
 void BackTexture::Copy(const gfx::Size& size, GLenum format) {
   DCHECK_NE(id_, 0u);
   ScopedGLErrorSuppressor suppressor("BackTexture::Copy",
-                                     decoder_->GetErrorState());
-  ScopedTexture2DBinder binder(decoder_, id_);
+                                     state_->GetErrorState());
+  ScopedTexture2DBinder binder(state_, id_);
   glCopyTexImage2D(GL_TEXTURE_2D,
                    0,  // level
                    format,
@@ -1917,7 +1930,7 @@
 void BackTexture::Destroy() {
   if (id_ != 0) {
     ScopedGLErrorSuppressor suppressor("BackTexture::Destroy",
-                                       decoder_->GetErrorState());
+                                       state_->GetErrorState());
     glDeleteTextures(1, &id_);
     id_ = 0;
   }
@@ -2344,7 +2357,8 @@
           renderbuffer_manager(), memory_tracker(), &state_));
       offscreen_target_color_render_buffer_->Create();
     } else {
-      offscreen_target_color_texture_.reset(new BackTexture(this));
+      offscreen_target_color_texture_.reset(new BackTexture(
+          memory_tracker(), &state_));
       offscreen_target_color_texture_->Create();
     }
     offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(
@@ -2359,7 +2373,8 @@
     offscreen_saved_frame_buffer_.reset(new BackFramebuffer(this));
     offscreen_saved_frame_buffer_->Create();
     //
-    offscreen_saved_color_texture_.reset(new BackTexture(this));
+    offscreen_saved_color_texture_.reset(new BackTexture(
+        memory_tracker(), &state_));
     offscreen_saved_color_texture_->Create();
 
     // Allocate the render buffers at their initial size and check the status
@@ -2849,19 +2864,6 @@
   OnFboChanged();
 }
 
-void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() {
-  TextureUnit& info = state_.texture_units[0];
-  GLuint last_id;
-  if (info.bound_texture_2d.get()) {
-    last_id = info.bound_texture_2d->service_id();
-  } else {
-    last_id = 0;
-  }
-
-  glBindTexture(GL_TEXTURE_2D, last_id);
-  glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit);
-}
-
 bool GLES2DecoderImpl::CheckFramebufferValid(
     Framebuffer* framebuffer,
     GLenum target, const char* func_name) {
@@ -5758,7 +5760,7 @@
           GetErrorState());
       glBindTexture(textarget, texture->service_id());
       image->WillUseTexImage();
-      RestoreCurrentTexture2DBindings();
+      RestoreCurrentTexture2DBindings(&state_);
     }
   }
 }
@@ -5777,7 +5779,7 @@
           GetErrorState());
       glBindTexture(textarget, texture->service_id());
       image->DidUseTexImage();
-      RestoreCurrentTexture2DBindings();
+      RestoreCurrentTexture2DBindings(&state_);
     }
   }
 }
@@ -9674,7 +9676,7 @@
         0, internal_format, dest_type, NULL);
     GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM");
     if (error != GL_NO_ERROR) {
-      RestoreCurrentTexture2DBindings();
+      RestoreCurrentTexture2DBindings(&state_);
       return;
     }
 
diff --git a/gpu/command_buffer/service/gpu_control_service.cc b/gpu/command_buffer/service/gpu_control_service.cc
index c6a8b8d..8306ab0 100644
--- a/gpu/command_buffer/service/gpu_control_service.cc
+++ b/gpu/command_buffer/service/gpu_control_service.cc
@@ -88,6 +88,11 @@
     query->AddCallback(callback);
 }
 
+void GpuControlService::SendManagedMemoryStats(
+    const ManagedMemoryStats& stats) {
+  NOTREACHED();
+}
+
 bool GpuControlService::RegisterGpuMemoryBuffer(
     int32 id,
     gfx::GpuMemoryBufferHandle buffer,
diff --git a/gpu/command_buffer/service/gpu_control_service.h b/gpu/command_buffer/service/gpu_control_service.h
index 32016ba..b9e7474 100644
--- a/gpu/command_buffer/service/gpu_control_service.h
+++ b/gpu/command_buffer/service/gpu_control_service.h
@@ -44,6 +44,8 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
+  virtual void SendManagedMemoryStats(const ManagedMemoryStats& stats)
+      OVERRIDE;
 
   // Register an existing gpu memory buffer and get an ID that can be used
   // to identify it in the command buffer.
diff --git a/gpu/command_buffer/service/gpu_switches.cc b/gpu/command_buffer/service/gpu_switches.cc
index 221dd60..bff23c3 100644
--- a/gpu/command_buffer/service/gpu_switches.cc
+++ b/gpu/command_buffer/service/gpu_switches.cc
@@ -57,8 +57,6 @@
 // Sets the maximum size of the in-memory gpu program cache, in kb
 const char kGpuProgramCacheSizeKb[]         = "gpu-program-cache-size-kb";
 
-const char kTraceGL[]       = "trace-gl";
-
 // Disables the GPU shader on disk cache.
 const char kDisableGpuShaderDiskCache[]     = "disable-gpu-shader-disk-cache";
 
@@ -82,7 +80,6 @@
   kForceSynchronousGLReadPixels,
   kGpuDriverBugWorkarounds,
   kGpuProgramCacheSizeKb,
-  kTraceGL,
   kDisableGpuShaderDiskCache,
   kEnableShareGroupAsyncTextureUpload,
 };
diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h
index 7634c57..7916d69 100644
--- a/gpu/command_buffer/service/gpu_switches.h
+++ b/gpu/command_buffer/service/gpu_switches.h
@@ -26,7 +26,6 @@
 GPU_EXPORT extern const char kForceSynchronousGLReadPixels[];
 GPU_EXPORT extern const char kGpuDriverBugWorkarounds[];
 GPU_EXPORT extern const char kGpuProgramCacheSizeKb[];
-GPU_EXPORT extern const char kTraceGL[];
 GPU_EXPORT extern const char kDisableGpuShaderDiskCache[];
 GPU_EXPORT extern const char kEnableShareGroupAsyncTextureUpload[];
 
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 1d48a98..ca24a0d 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -730,6 +730,10 @@
                        WrapCallback(callback)));
 }
 
+void InProcessCommandBuffer::SendManagedMemoryStats(
+    const gpu::ManagedMemoryStats& stats) {
+}
+
 gpu::error::Error InProcessCommandBuffer::GetLastError() {
   CheckSequencedThread();
   return last_state_.error;
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 3fd0982..ee39df6 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -122,6 +122,8 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
+  virtual void SendManagedMemoryStats(const gpu::ManagedMemoryStats& stats)
+      OVERRIDE;
 
   // The serializer interface to the GPU service (i.e. thread).
   class SchedulerClient {
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 0fb6ab3..0437209 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -391,7 +391,7 @@
   name_buffer.reset(new char[max_len]);
 
   // Reads all the names.
-  std::vector<UniformData> uniform_data_;
+  std::vector<UniformData> uniform_data;
   for (GLint ii = 0; ii < num_uniforms; ++ii) {
     GLsizei length = 0;
     UniformData data;
@@ -405,7 +405,7 @@
       GetCorrectedVariableInfo(
           true, name_buffer.get(), &data.corrected_name, &data.original_name,
           &data.size, &data.type);
-      uniform_data_.push_back(data);
+      uniform_data.push_back(data);
     }
   }
 
@@ -419,8 +419,8 @@
 
   // Assigns the uniforms with bindings.
   size_t next_available_index = 0;
-  for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
-    UniformData& data = uniform_data_[ii];
+  for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
+    UniformData& data = uniform_data[ii];
     data.location = glGetUniformLocation(
         service_id_, data.queried_name.c_str());
     // remove "[0]"
@@ -439,8 +439,8 @@
   }
 
   // Assigns the uniforms that were not bound.
-  for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
-    const UniformData& data = uniform_data_[ii];
+  for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
+    const UniformData& data = uniform_data[ii];
     if (!data.added) {
       AddUniformInfo(
           data.size, data.type, data.location, -1, data.corrected_name,
@@ -672,6 +672,9 @@
       if (open_pos_2 == open_pos &&
           name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
         if (index >= 0 && index < info.size) {
+          DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
+          if (info.element_locations[index] == -1)
+            return -1;
           return ProgramManager::MakeFakeLocation(
               info.fake_location_base, index);
         }
@@ -1221,7 +1224,10 @@
       inputs->name_length = info.name.size();
       DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
       for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
-        *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
+        if (info.element_locations[jj] == -1)
+          *locations++ = -1;
+        else
+          *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
       }
       memcpy(strings, info.name.c_str(), info.name.size());
       strings += info.name.size();
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 43217f4..2c51c88 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -608,12 +608,19 @@
 TEST_F(ProgramManagerWithShaderTest, GetUniformFakeLocation) {
   const Program* program = manager_.GetProgram(kClientProgramId);
   ASSERT_TRUE(program != NULL);
+  // Emulate the situation that uniform3[1] isn't used and optimized out by
+  // a driver, so it's location is -1.
+  Program::UniformInfo* uniform = const_cast<Program::UniformInfo*>(
+      program->GetUniformInfo(2));
+  ASSERT_TRUE(uniform != NULL && kUniform3Size == 2);
+  EXPECT_EQ(kUniform3Size, uniform->size);
+  uniform->element_locations[1] = -1;
   EXPECT_EQ(kUniform1FakeLocation,
             program->GetUniformFakeLocation(kUniform1Name));
   EXPECT_EQ(kUniform2FakeLocation,
             program->GetUniformFakeLocation(kUniform2Name));
   EXPECT_EQ(kUniform3FakeLocation,
-             program->GetUniformFakeLocation(kUniform3BadName));
+            program->GetUniformFakeLocation(kUniform3BadName));
   // Check we can get uniform2 as "uniform2" even though the name is
   // "uniform2[0]"
   EXPECT_EQ(kUniform2FakeLocation,
@@ -628,8 +635,7 @@
   EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform2FakeLocation, 2),
             program->GetUniformFakeLocation("uniform2[2]"));
   EXPECT_EQ(-1, program->GetUniformFakeLocation("uniform2[3]"));
-  EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform3FakeLocation, 1),
-            program->GetUniformFakeLocation("uniform3[1]"));
+  EXPECT_EQ(-1, program->GetUniformFakeLocation("uniform3[1]"));
   EXPECT_EQ(-1, program->GetUniformFakeLocation("uniform3[2]"));
 }
 
@@ -1067,6 +1073,50 @@
             static_cast<uint32>(input - inputs));
 }
 
+// Some drivers optimize out unused uniform array elements, so their
+// location would be -1.
+TEST_F(ProgramManagerWithShaderTest, UnusedUniformArrayElements) {
+  CommonDecoder::Bucket bucket;
+  const Program* program = manager_.GetProgram(kClientProgramId);
+  ASSERT_TRUE(program != NULL);
+  // Emulate the situation that only the first element has a valid location.
+  // TODO(zmo): Don't assume these are in order.
+  for (size_t ii = 0; ii < arraysize(kUniforms); ++ii) {
+    Program::UniformInfo* uniform = const_cast<Program::UniformInfo*>(
+        program->GetUniformInfo(ii));
+    ASSERT_TRUE(uniform != NULL);
+    EXPECT_EQ(static_cast<size_t>(kUniforms[ii].size),
+              uniform->element_locations.size());
+    for (GLsizei jj = 1; jj < uniform->size; ++jj)
+      uniform->element_locations[jj] = -1;
+  }
+  program->GetProgramInfo(&manager_, &bucket);
+  ProgramInfoHeader* header =
+      bucket.GetDataAs<ProgramInfoHeader*>(0, sizeof(ProgramInfoHeader));
+  ASSERT_TRUE(header != NULL);
+  EXPECT_EQ(1u, header->link_status);
+  EXPECT_EQ(arraysize(kAttribs), header->num_attribs);
+  EXPECT_EQ(arraysize(kUniforms), header->num_uniforms);
+  const ProgramInput* inputs = bucket.GetDataAs<const ProgramInput*>(
+      sizeof(*header),
+      sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
+  ASSERT_TRUE(inputs != NULL);
+  const ProgramInput* input = inputs + header->num_attribs;
+  for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
+    const UniformInfo& expected = kUniforms[ii];
+    EXPECT_EQ(expected.size, input->size);
+    const int32* locations = bucket.GetDataAs<const int32*>(
+        input->location_offset, sizeof(int32) * input->size);
+    ASSERT_TRUE(locations != NULL);
+    EXPECT_EQ(
+        ProgramManager::MakeFakeLocation(expected.fake_location, 0),
+        locations[0]);
+    for (int32 jj = 1; jj < input->size; ++jj)
+      EXPECT_EQ(-1, locations[jj]);
+    ++input;
+  }
+}
+
 TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) {
   // Set up shader
   const GLuint kVShaderClientId = 1;
diff --git a/gpu/command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc b/gpu/command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc
index c1d3c98..4ade1e4 100644
--- a/gpu/command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc
+++ b/gpu/command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc
@@ -47,5 +47,115 @@
   GLTestHelper::CheckGLError("no errors", __LINE__);
 }
 
+TEST_F(GLChromiumFramebufferMultisampleTest, DrawAndResolve) {
+  if (!GLTestHelper::HasExtension("GL_CHROMIUM_framebuffer_multisample")) {
+    return;
+  }
+
+  static const char* v_shader_str =
+      "attribute vec4 a_Position;\n"
+      "void main()\n"
+      "{\n"
+      "   gl_Position = a_Position;\n"
+      "}\n";
+  static const char* f_shader_str =
+      "precision mediump float;\n"
+      "void main()\n"
+      "{\n"
+      "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+      "}\n";
+
+  GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
+  glUseProgram(program);
+  GLuint position_loc = glGetAttribLocation(program, "a_Position");
+
+  GLTestHelper::SetupUnitQuad(position_loc);
+
+  const GLuint width = 100;
+  const GLuint height = 100;
+
+  // Create a sample buffer.
+  GLsizei num_samples = 4, max_samples = 0;
+  glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+  num_samples = std::min(num_samples, max_samples);
+
+  GLuint sample_fbo, sample_rb;
+  glGenRenderbuffers(1, &sample_rb);
+  glBindRenderbuffer(GL_RENDERBUFFER, sample_rb);
+  glRenderbufferStorageMultisampleEXT(
+      GL_RENDERBUFFER, num_samples, GL_RGBA8_OES, width, height);
+  GLint param = 0;
+  glGetRenderbufferParameteriv(
+      GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &param);
+  EXPECT_GE(param, num_samples);
+
+  glGenFramebuffers(1, &sample_fbo);
+  glBindFramebuffer(GL_FRAMEBUFFER, sample_fbo);
+  glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                            GL_COLOR_ATTACHMENT0,
+                            GL_RENDERBUFFER,
+                            sample_rb);
+  EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+            glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+  // Create another FBO to resolve the multisample buffer into.
+  GLuint resolve_fbo, resolve_tex;
+  glGenTextures(1, &resolve_tex);
+  glBindTexture(GL_TEXTURE_2D, resolve_tex);
+  glTexImage2D(GL_TEXTURE_2D,
+               0,
+               GL_RGBA,
+               width,
+               height,
+               0,
+               GL_RGBA,
+               GL_UNSIGNED_BYTE,
+               NULL);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glGenFramebuffers(1, &resolve_fbo);
+  glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
+  glFramebufferTexture2D(GL_FRAMEBUFFER,
+                         GL_COLOR_ATTACHMENT0,
+                         GL_TEXTURE_2D,
+                         resolve_tex,
+                         0);
+  EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+            glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+  // Draw one triangle (bottom left half).
+  glViewport(0, 0, width, height);
+  glBindFramebuffer(GL_FRAMEBUFFER, sample_fbo);
+  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+  glDrawArrays(GL_TRIANGLES, 0, 3);
+
+  // Resolve.
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, sample_fbo);
+  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
+  glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+  glBlitFramebufferEXT(0,
+                       0,
+                       width,
+                       height,
+                       0,
+                       0,
+                       width,
+                       height,
+                       GL_COLOR_BUFFER_BIT,
+                       GL_NEAREST);
+
+  // Verify.
+  const uint8 green[] = {0, 255, 0, 255};
+  const uint8 black[] = {0, 0, 0, 0};
+  glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(width / 4, (3 * height) / 4, 1, 1, 0, green));
+  EXPECT_TRUE(GLTestHelper::CheckPixels(width - 1, 0, 1, 1, 0, black));
+}
+
 }  // namespace gpu
 
diff --git a/gpu/command_buffer_client.target.darwin-arm.mk b/gpu/command_buffer_client.target.darwin-arm.mk
index b24ef79..1d7fab3 100644
--- a/gpu/command_buffer_client.target.darwin-arm.mk
+++ b/gpu/command_buffer_client.target.darwin-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_client.target.darwin-mips.mk b/gpu/command_buffer_client.target.darwin-mips.mk
index 68dab02..9d02c0d 100644
--- a/gpu/command_buffer_client.target.darwin-mips.mk
+++ b/gpu/command_buffer_client.target.darwin-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_client.target.darwin-x86.mk b/gpu/command_buffer_client.target.darwin-x86.mk
index cb66f6f..a0fe6b9 100644
--- a/gpu/command_buffer_client.target.darwin-x86.mk
+++ b/gpu/command_buffer_client.target.darwin-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_client.target.linux-arm.mk b/gpu/command_buffer_client.target.linux-arm.mk
index b24ef79..1d7fab3 100644
--- a/gpu/command_buffer_client.target.linux-arm.mk
+++ b/gpu/command_buffer_client.target.linux-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_client.target.linux-mips.mk b/gpu/command_buffer_client.target.linux-mips.mk
index 68dab02..9d02c0d 100644
--- a/gpu/command_buffer_client.target.linux-mips.mk
+++ b/gpu/command_buffer_client.target.linux-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_client.target.linux-x86.mk b/gpu/command_buffer_client.target.linux-x86.mk
index cb66f6f..a0fe6b9 100644
--- a/gpu/command_buffer_client.target.linux-x86.mk
+++ b/gpu/command_buffer_client.target.linux-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.darwin-arm.mk b/gpu/command_buffer_common.target.darwin-arm.mk
index 2534038..c12d8ec 100644
--- a/gpu/command_buffer_common.target.darwin-arm.mk
+++ b/gpu/command_buffer_common.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.darwin-mips.mk b/gpu/command_buffer_common.target.darwin-mips.mk
index 35e20e4..8c53969 100644
--- a/gpu/command_buffer_common.target.darwin-mips.mk
+++ b/gpu/command_buffer_common.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.darwin-x86.mk b/gpu/command_buffer_common.target.darwin-x86.mk
index 4e85e9a..dd3f504 100644
--- a/gpu/command_buffer_common.target.darwin-x86.mk
+++ b/gpu/command_buffer_common.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.linux-arm.mk b/gpu/command_buffer_common.target.linux-arm.mk
index 2534038..c12d8ec 100644
--- a/gpu/command_buffer_common.target.linux-arm.mk
+++ b/gpu/command_buffer_common.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.linux-mips.mk b/gpu/command_buffer_common.target.linux-mips.mk
index 35e20e4..8c53969 100644
--- a/gpu/command_buffer_common.target.linux-mips.mk
+++ b/gpu/command_buffer_common.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_common.target.linux-x86.mk b/gpu/command_buffer_common.target.linux-x86.mk
index 4e85e9a..dd3f504 100644
--- a/gpu/command_buffer_common.target.linux-x86.mk
+++ b/gpu/command_buffer_common.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.darwin-arm.mk b/gpu/command_buffer_service.target.darwin-arm.mk
index b5e67eb..b2ed449 100644
--- a/gpu/command_buffer_service.target.darwin-arm.mk
+++ b/gpu/command_buffer_service.target.darwin-arm.mk
@@ -113,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,13 +212,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.darwin-mips.mk b/gpu/command_buffer_service.target.darwin-mips.mk
index 744a3da..e15bf4f 100644
--- a/gpu/command_buffer_service.target.darwin-mips.mk
+++ b/gpu/command_buffer_service.target.darwin-mips.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -210,13 +210,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.darwin-x86.mk b/gpu/command_buffer_service.target.darwin-x86.mk
index fe3e552..6c9ae83 100644
--- a/gpu/command_buffer_service.target.darwin-x86.mk
+++ b/gpu/command_buffer_service.target.darwin-x86.mk
@@ -115,13 +115,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.linux-arm.mk b/gpu/command_buffer_service.target.linux-arm.mk
index b5e67eb..b2ed449 100644
--- a/gpu/command_buffer_service.target.linux-arm.mk
+++ b/gpu/command_buffer_service.target.linux-arm.mk
@@ -113,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,13 +212,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.linux-mips.mk b/gpu/command_buffer_service.target.linux-mips.mk
index 744a3da..e15bf4f 100644
--- a/gpu/command_buffer_service.target.linux-mips.mk
+++ b/gpu/command_buffer_service.target.linux-mips.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -210,13 +210,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/command_buffer_service.target.linux-x86.mk b/gpu/command_buffer_service.target.linux-x86.mk
index fe3e552..6c9ae83 100644
--- a/gpu/command_buffer_service.target.linux-x86.mk
+++ b/gpu/command_buffer_service.target.linux-x86.mk
@@ -115,13 +115,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index 0c645b5..7c90035 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -837,15 +837,13 @@
 bool GpuControlList::GpuControlListEntry::SetVendorId(
     const std::string& vendor_id_string) {
   vendor_id_ = 0;
-  return base::HexStringToInt(vendor_id_string,
-                              reinterpret_cast<int*>(&vendor_id_));
+  return base::HexStringToUInt(vendor_id_string, &vendor_id_);
 }
 
 bool GpuControlList::GpuControlListEntry::AddDeviceId(
     const std::string& device_id_string) {
   uint32 device_id = 0;
-  if (base::HexStringToInt(device_id_string,
-                           reinterpret_cast<int*>(&device_id))) {
+  if (base::HexStringToUInt(device_id_string, &device_id)) {
     device_id_list_.push_back(device_id);
     return true;
   }
@@ -1035,8 +1033,8 @@
     const std::string& control_list_logging_name) const {
   static const char kControlListMatchMessage[] =
       "Control list match for rule #%u in %s.";
-  LOG(INFO) << base::StringPrintf(kControlListMatchMessage, id_,
-                                  control_list_logging_name.c_str());
+  VLOG(1) << base::StringPrintf(kControlListMatchMessage, id_,
+                                control_list_logging_name.c_str());
 }
 
 bool GpuControlList::GpuControlListEntry::Contains(
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index d7e7af6..dd38d57 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "2.24",
+  "version": "2.26",
   "entries": [
     {
       "id": 1,
@@ -607,6 +607,33 @@
       "features": [
         "unfold_short_circuit_as_ternary_operation"
       ]
+    },
+    {
+      "id": 46,
+      "description": "Using D3D11 causes browser crashes on certain Intel GPUs.",
+      "cr_bugs": [310808],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "features": [
+        "disable_d3d11"
+      ]
+    },
+    {
+      "id": 47,
+      "description": "The Mali T-6xx driver does not guarantee flush ordering.",
+      "cr_bugs": [285292],
+      "os": {
+        "type": "chromeos"
+      },
+      "cpu_info": {
+        "op": "=",
+        "value": "ARM"  // TODO(piman): change to GL_VENDOR/GL_RENDERER switch
+      },
+      "features": [
+        "use_virtualized_gl_contexts"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_test_expectations_parser.cc b/gpu/config/gpu_test_expectations_parser.cc
index 83bb300..dd08db6 100644
--- a/gpu/config/gpu_test_expectations_parser.cc
+++ b/gpu/config/gpu_test_expectations_parser.cc
@@ -449,8 +449,7 @@
   DCHECK(config);
   uint32 device_id = 0;
   if (config->gpu_device_id() != 0 ||
-      !base::HexStringToInt(gpu_device_id,
-                            reinterpret_cast<int*>(&device_id)) ||
+      !base::HexStringToUInt(gpu_device_id, &device_id) ||
       device_id == 0) {
     PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
                      line_number);
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 19a05ac..ce302c7 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@
 {
   "name": "software rendering list",
   // Please update the version number whenever you change this file.
-  "version": "6.12",
+  "version": "6.13",
   "entries": [
     {
       "id": 1,
@@ -652,7 +652,6 @@
     },
     {
       "id": 48,
-      // Please keep in sync with content/test/content_browser_test.cc.
       "description": "Accelerated video decode is unavailable on Mac and Linux.",
       "cr_bugs": [137247, 133828],
       "exceptions": [
@@ -1154,6 +1153,17 @@
         "flash_stage3d",
         "force_compositing_mode"
       ]
+    },
+    {
+      "id": 80,
+      "description": "Texture sharing should be disabled on all Windows machines",
+      "cr_bugs": [304369],
+      "os": {
+        "type": "win"
+      },
+      "features": [
+        "texture_sharing"
+      ]
     }
   ]
 }
diff --git a/gpu/disk_cache_proto.target.darwin-arm.mk b/gpu/disk_cache_proto.target.darwin-arm.mk
index 306a272..8183f58 100644
--- a/gpu/disk_cache_proto.target.darwin-arm.mk
+++ b/gpu/disk_cache_proto.target.darwin-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/disk_cache_proto.target.darwin-mips.mk b/gpu/disk_cache_proto.target.darwin-mips.mk
index 6da3e6a..769f76d 100644
--- a/gpu/disk_cache_proto.target.darwin-mips.mk
+++ b/gpu/disk_cache_proto.target.darwin-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/disk_cache_proto.target.darwin-x86.mk b/gpu/disk_cache_proto.target.darwin-x86.mk
index caef760..8c94dd5 100644
--- a/gpu/disk_cache_proto.target.darwin-x86.mk
+++ b/gpu/disk_cache_proto.target.darwin-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/disk_cache_proto.target.linux-arm.mk b/gpu/disk_cache_proto.target.linux-arm.mk
index 306a272..8183f58 100644
--- a/gpu/disk_cache_proto.target.linux-arm.mk
+++ b/gpu/disk_cache_proto.target.linux-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/disk_cache_proto.target.linux-mips.mk b/gpu/disk_cache_proto.target.linux-mips.mk
index 6da3e6a..769f76d 100644
--- a/gpu/disk_cache_proto.target.linux-mips.mk
+++ b/gpu/disk_cache_proto.target.linux-mips.mk
@@ -89,13 +89,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/disk_cache_proto.target.linux-x86.mk b/gpu/disk_cache_proto.target.linux-x86.mk
index caef760..8c94dd5 100644
--- a/gpu/disk_cache_proto.target.linux-x86.mk
+++ b/gpu/disk_cache_proto.target.linux-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -180,13 +180,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.darwin-arm.mk b/gpu/gles2_c_lib.target.darwin-arm.mk
index 9c8a686..0cb702e 100644
--- a/gpu/gles2_c_lib.target.darwin-arm.mk
+++ b/gpu/gles2_c_lib.target.darwin-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.darwin-mips.mk b/gpu/gles2_c_lib.target.darwin-mips.mk
index 305d887..5b5614d 100644
--- a/gpu/gles2_c_lib.target.darwin-mips.mk
+++ b/gpu/gles2_c_lib.target.darwin-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.darwin-x86.mk b/gpu/gles2_c_lib.target.darwin-x86.mk
index 7ffdad0..94f32e5 100644
--- a/gpu/gles2_c_lib.target.darwin-x86.mk
+++ b/gpu/gles2_c_lib.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.linux-arm.mk b/gpu/gles2_c_lib.target.linux-arm.mk
index 9c8a686..0cb702e 100644
--- a/gpu/gles2_c_lib.target.linux-arm.mk
+++ b/gpu/gles2_c_lib.target.linux-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.linux-mips.mk b/gpu/gles2_c_lib.target.linux-mips.mk
index 305d887..5b5614d 100644
--- a/gpu/gles2_c_lib.target.linux-mips.mk
+++ b/gpu/gles2_c_lib.target.linux-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_c_lib.target.linux-x86.mk b/gpu/gles2_c_lib.target.linux-x86.mk
index 7ffdad0..94f32e5 100644
--- a/gpu/gles2_c_lib.target.linux-x86.mk
+++ b/gpu/gles2_c_lib.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.darwin-arm.mk b/gpu/gles2_cmd_helper.target.darwin-arm.mk
index 6ac1829..ca5d401 100644
--- a/gpu/gles2_cmd_helper.target.darwin-arm.mk
+++ b/gpu/gles2_cmd_helper.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.darwin-mips.mk b/gpu/gles2_cmd_helper.target.darwin-mips.mk
index 4278e9d..1750888 100644
--- a/gpu/gles2_cmd_helper.target.darwin-mips.mk
+++ b/gpu/gles2_cmd_helper.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.darwin-x86.mk b/gpu/gles2_cmd_helper.target.darwin-x86.mk
index e59a0d3..284d670 100644
--- a/gpu/gles2_cmd_helper.target.darwin-x86.mk
+++ b/gpu/gles2_cmd_helper.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.linux-arm.mk b/gpu/gles2_cmd_helper.target.linux-arm.mk
index 6ac1829..ca5d401 100644
--- a/gpu/gles2_cmd_helper.target.linux-arm.mk
+++ b/gpu/gles2_cmd_helper.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.linux-mips.mk b/gpu/gles2_cmd_helper.target.linux-mips.mk
index 4278e9d..1750888 100644
--- a/gpu/gles2_cmd_helper.target.linux-mips.mk
+++ b/gpu/gles2_cmd_helper.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_cmd_helper.target.linux-x86.mk b/gpu/gles2_cmd_helper.target.linux-x86.mk
index e59a0d3..284d670 100644
--- a/gpu/gles2_cmd_helper.target.linux-x86.mk
+++ b/gpu/gles2_cmd_helper.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.darwin-arm.mk b/gpu/gles2_implementation.target.darwin-arm.mk
index 1c42c4e..b4afbfd 100644
--- a/gpu/gles2_implementation.target.darwin-arm.mk
+++ b/gpu/gles2_implementation.target.darwin-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.darwin-mips.mk b/gpu/gles2_implementation.target.darwin-mips.mk
index d2d30fd..cc889cc 100644
--- a/gpu/gles2_implementation.target.darwin-mips.mk
+++ b/gpu/gles2_implementation.target.darwin-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.darwin-x86.mk b/gpu/gles2_implementation.target.darwin-x86.mk
index b52f9cd..d08a755 100644
--- a/gpu/gles2_implementation.target.darwin-x86.mk
+++ b/gpu/gles2_implementation.target.darwin-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.linux-arm.mk b/gpu/gles2_implementation.target.linux-arm.mk
index 1c42c4e..b4afbfd 100644
--- a/gpu/gles2_implementation.target.linux-arm.mk
+++ b/gpu/gles2_implementation.target.linux-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.linux-mips.mk b/gpu/gles2_implementation.target.linux-mips.mk
index d2d30fd..cc889cc 100644
--- a/gpu/gles2_implementation.target.linux-mips.mk
+++ b/gpu/gles2_implementation.target.linux-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gles2_implementation.target.linux-x86.mk b/gpu/gles2_implementation.target.linux-x86.mk
index b52f9cd..d08a755 100644
--- a/gpu/gles2_implementation.target.linux-x86.mk
+++ b/gpu/gles2_implementation.target.linux-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.darwin-arm.mk b/gpu/gpu.target.darwin-arm.mk
index bacbcf0..391bbc3 100644
--- a/gpu/gpu.target.darwin-arm.mk
+++ b/gpu/gpu.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.darwin-mips.mk b/gpu/gpu.target.darwin-mips.mk
index c2e9e07..29ad2c6 100644
--- a/gpu/gpu.target.darwin-mips.mk
+++ b/gpu/gpu.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.darwin-x86.mk b/gpu/gpu.target.darwin-x86.mk
index db7c3fc..1f8d647 100644
--- a/gpu/gpu.target.darwin-x86.mk
+++ b/gpu/gpu.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.linux-arm.mk b/gpu/gpu.target.linux-arm.mk
index bacbcf0..391bbc3 100644
--- a/gpu/gpu.target.linux-arm.mk
+++ b/gpu/gpu.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.linux-mips.mk b/gpu/gpu.target.linux-mips.mk
index c2e9e07..29ad2c6 100644
--- a/gpu/gpu.target.linux-mips.mk
+++ b/gpu/gpu.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu.target.linux-x86.mk b/gpu/gpu.target.linux-x86.mk
index db7c3fc..1f8d647 100644
--- a/gpu/gpu.target.linux-x86.mk
+++ b/gpu/gpu.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.darwin-arm.mk b/gpu/gpu_config.target.darwin-arm.mk
index dd7c948..e234f9c 100644
--- a/gpu/gpu_config.target.darwin-arm.mk
+++ b/gpu/gpu_config.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.darwin-mips.mk b/gpu/gpu_config.target.darwin-mips.mk
index 32ded0f..aad7238 100644
--- a/gpu/gpu_config.target.darwin-mips.mk
+++ b/gpu/gpu_config.target.darwin-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.darwin-x86.mk b/gpu/gpu_config.target.darwin-x86.mk
index bad4539..eff8fda 100644
--- a/gpu/gpu_config.target.darwin-x86.mk
+++ b/gpu/gpu_config.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.linux-arm.mk b/gpu/gpu_config.target.linux-arm.mk
index dd7c948..e234f9c 100644
--- a/gpu/gpu_config.target.linux-arm.mk
+++ b/gpu/gpu_config.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.linux-mips.mk b/gpu/gpu_config.target.linux-mips.mk
index 32ded0f..aad7238 100644
--- a/gpu/gpu_config.target.linux-mips.mk
+++ b/gpu/gpu_config.target.linux-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_config.target.linux-x86.mk b/gpu/gpu_config.target.linux-x86.mk
index bad4539..eff8fda 100644
--- a/gpu/gpu_config.target.linux-x86.mk
+++ b/gpu/gpu_config.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.darwin-arm.mk b/gpu/gpu_ipc.target.darwin-arm.mk
index f9fd693..b2c3b78 100644
--- a/gpu/gpu_ipc.target.darwin-arm.mk
+++ b/gpu/gpu_ipc.target.darwin-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.darwin-mips.mk b/gpu/gpu_ipc.target.darwin-mips.mk
index 9997f45..9f2cfa9 100644
--- a/gpu/gpu_ipc.target.darwin-mips.mk
+++ b/gpu/gpu_ipc.target.darwin-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.darwin-x86.mk b/gpu/gpu_ipc.target.darwin-x86.mk
index 59c3c11..60a4bb3 100644
--- a/gpu/gpu_ipc.target.darwin-x86.mk
+++ b/gpu/gpu_ipc.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.linux-arm.mk b/gpu/gpu_ipc.target.linux-arm.mk
index f9fd693..b2c3b78 100644
--- a/gpu/gpu_ipc.target.linux-arm.mk
+++ b/gpu/gpu_ipc.target.linux-arm.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.linux-mips.mk b/gpu/gpu_ipc.target.linux-mips.mk
index 9997f45..9f2cfa9 100644
--- a/gpu/gpu_ipc.target.linux-mips.mk
+++ b/gpu/gpu_ipc.target.linux-mips.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/gpu/gpu_ipc.target.linux-x86.mk b/gpu/gpu_ipc.target.linux-x86.mk
index 59c3c11..60a4bb3 100644
--- a/gpu/gpu_ipc.target.linux-x86.mk
+++ b/gpu/gpu_ipc.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.darwin-arm.mk b/ipc/ipc.target.darwin-arm.mk
index 67d67bf..9a67c39 100644
--- a/ipc/ipc.target.darwin-arm.mk
+++ b/ipc/ipc.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.darwin-mips.mk b/ipc/ipc.target.darwin-mips.mk
index f408796..1a31d4f 100644
--- a/ipc/ipc.target.darwin-mips.mk
+++ b/ipc/ipc.target.darwin-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.darwin-x86.mk b/ipc/ipc.target.darwin-x86.mk
index 2686a14..d7af153 100644
--- a/ipc/ipc.target.darwin-x86.mk
+++ b/ipc/ipc.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.linux-arm.mk b/ipc/ipc.target.linux-arm.mk
index 67d67bf..9a67c39 100644
--- a/ipc/ipc.target.linux-arm.mk
+++ b/ipc/ipc.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.linux-mips.mk b/ipc/ipc.target.linux-mips.mk
index f408796..1a31d4f 100644
--- a/ipc/ipc.target.linux-mips.mk
+++ b/ipc/ipc.target.linux-mips.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc.target.linux-x86.mk b/ipc/ipc.target.linux-x86.mk
index 2686a14..d7af153 100644
--- a/ipc/ipc.target.linux-x86.mk
+++ b/ipc/ipc.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index a74178a..5b57100 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -745,8 +745,7 @@
 void Channel::ChannelImpl::QueueHelloMessage() {
   // Create the Hello message
   scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
-                                      HELLO_MESSAGE_TYPE,
-                                      IPC::Message::PRIORITY_NORMAL));
+                                      HELLO_MESSAGE_TYPE));
   if (!msg->WriteInt(GetHelloMessageProcId())) {
     NOTREACHED() << "Unable to pickle hello message proc id";
   }
@@ -939,8 +938,7 @@
     case 2: {
       // Create the message
       scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
-                                          CLOSE_FD_MESSAGE_TYPE,
-                                          IPC::Message::PRIORITY_NORMAL));
+                                          CLOSE_FD_MESSAGE_TYPE));
       if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) {
         NOTREACHED() << "Unable to pickle close fd.";
       }
diff --git a/ipc/ipc_channel_posix_unittest.cc b/ipc/ipc_channel_posix_unittest.cc
index 66ddeb2..3a00716 100644
--- a/ipc/ipc_channel_posix_unittest.cc
+++ b/ipc/ipc_channel_posix_unittest.cc
@@ -244,9 +244,8 @@
   SpinRunLoop(TestTimeouts::action_max_timeout());
   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
   ASSERT_TRUE(channel.HasAcceptedConnection());
-  IPC::Message* message = new IPC::Message(0,  // routing_id
-                                           kQuitMessage,  // message type
-                                           IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, /* routing_id */
+                                           kQuitMessage /* message type */);
   channel.Send(message);
   SpinRunLoop(TestTimeouts::action_timeout());
   int exit_code = 0;
@@ -283,9 +282,8 @@
   SpinRunLoop(TestTimeouts::action_max_timeout());
   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
   ASSERT_TRUE(channel.HasAcceptedConnection());
-  IPC::Message* message = new IPC::Message(0,  // routing_id
-                                           kQuitMessage,  // message type
-                                           IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, /* routing_id */
+                                           kQuitMessage /* message type */);
   channel.Send(message);
   SpinRunLoop(TestTimeouts::action_timeout());
   EXPECT_TRUE(base::KillProcess(handle, 0, false));
@@ -342,9 +340,8 @@
   EXPECT_EQ(exit_code, 0);
   ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
   ASSERT_TRUE(channel.HasAcceptedConnection());
-  IPC::Message* message = new IPC::Message(0,  // routing_id
-                                           kQuitMessage,  // message type
-                                           IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, /* routing_id */
+                                           kQuitMessage /* message type */);
   channel.Send(message);
   SpinRunLoop(TestTimeouts::action_timeout());
   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
diff --git a/ipc/ipc_channel_unittest.cc b/ipc/ipc_channel_unittest.cc
index eea432a..ead623e 100644
--- a/ipc/ipc_channel_unittest.cc
+++ b/ipc/ipc_channel_unittest.cc
@@ -23,9 +23,7 @@
 static void Send(IPC::Sender* sender, const char* text) {
   static int message_index = 0;
 
-  IPC::Message* message = new IPC::Message(0,
-                                           2,
-                                           IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, 2);
   message->WriteInt(message_index++);
   message->WriteString(std::string(text));
 
@@ -94,7 +92,7 @@
   std::string v2("foobar");
   std::wstring v3(L"hello world");
 
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(v1));
   EXPECT_TRUE(m.WriteString(v2));
   EXPECT_TRUE(m.WriteWString(v3));
diff --git a/ipc/ipc_channel_win.cc b/ipc/ipc_channel_win.cc
index 8c08500..d56b113 100644
--- a/ipc/ipc_channel_win.cc
+++ b/ipc/ipc_channel_win.cc
@@ -269,8 +269,7 @@
 
   // Create the Hello message to be sent when Connect is called
   scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
-                                    HELLO_MESSAGE_TYPE,
-                                    IPC::Message::PRIORITY_NORMAL));
+                                    HELLO_MESSAGE_TYPE));
 
   // Don't send the secret to the untrusted process, and don't send a secret
   // if the value is zero (for IPC backwards compatability).
diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc
index 3d2d497..07ff8d9 100644
--- a/ipc/ipc_fuzzing_tests.cc
+++ b/ipc/ipc_fuzzing_tests.cc
@@ -38,7 +38,7 @@
   //This was BUG 984408.
   uint32 v1 = kuint32max - 1;
   int v2 = 666;
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(v1));
   EXPECT_TRUE(m.WriteInt(v2));
 
@@ -51,7 +51,7 @@
   //This was BUG 984408.
   uint32 v1 = kuint32max - 1;
   int v2 = 777;
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(v1));
   EXPECT_TRUE(m.WriteInt(v2));
 
@@ -62,7 +62,7 @@
 
 TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
   // This was BUG 1035467.
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(1));
   EXPECT_TRUE(m.WriteInt(2));
 
@@ -75,7 +75,7 @@
   // A slight variation of BUG 984408. Note that the pickling of vector<char>
   // has a specialized template which is not vulnerable to this bug. So here
   // try to hit the non-specialized case vector<P>.
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(-1));   // This is the count of elements.
   EXPECT_TRUE(m.WriteInt(1));
   EXPECT_TRUE(m.WriteInt(2));
@@ -89,7 +89,7 @@
 TEST(IPCMessageIntegrity, ReadVectorTooLarge1) {
   // This was BUG 1006367. This is the large but positive length case. Again
   // we try to hit the non-specialized case vector<P>.
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(0x21000003));   // This is the count of elements.
   EXPECT_TRUE(m.WriteInt64(1));
   EXPECT_TRUE(m.WriteInt64(2));
@@ -103,7 +103,7 @@
   // This was BUG 1006367. This is the large but positive with an additional
   // integer overflow when computing the actual byte size. Again we try to hit
   // the non-specialized case vector<P>.
-  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message m(0, 1);
   EXPECT_TRUE(m.WriteInt(0x71000000));   // This is the count of elements.
   EXPECT_TRUE(m.WriteInt64(1));
   EXPECT_TRUE(m.WriteInt64(2));
@@ -164,8 +164,7 @@
   }
 
   bool RoundtripAckReply(int routing, uint32 type_id, int reply) {
-    IPC::Message* message = new IPC::Message(routing, type_id,
-                                             IPC::Message::PRIORITY_NORMAL);
+    IPC::Message* message = new IPC::Message(routing, type_id);
     message->WriteInt(reply + 1);
     message->WriteInt(reply);
     return other_->Send(message);
@@ -298,8 +297,7 @@
   ASSERT_TRUE(ConnectChannel());
   ASSERT_TRUE(StartClient());
 
-  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
-                                       IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID);
   msg->WriteInt(666);
   sender()->Send(msg);
   EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
@@ -326,8 +324,7 @@
   ASSERT_TRUE(ConnectChannel());
   ASSERT_TRUE(StartClient());
 
-  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
-                                       IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID);
   msg->WriteWString(L"d");
   msg->WriteInt(0);
   msg->WriteInt(0x65);  // Extra argument.
@@ -393,14 +390,12 @@
 
 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
   // Test a bad message.
-  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
-                         IPC::Message::PRIORITY_NORMAL);
+  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID);
   msg->WriteInt(2);
   EXPECT_FALSE(server.OnMessageReceived(*msg));
   delete msg;
 
-  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
-                         IPC::Message::PRIORITY_NORMAL);
+  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID);
   msg->WriteInt(0x64);
   msg->WriteInt(0x32);
   EXPECT_FALSE(server.OnMessageReceived(*msg));
diff --git a/ipc/ipc_logging.cc b/ipc/ipc_logging.cc
index 65d8890..40f0300 100644
--- a/ipc/ipc_logging.cc
+++ b/ipc/ipc_logging.cc
@@ -96,8 +96,7 @@
   if (!sender_)
     return;
 
-  Message* msg = new Message(
-      MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL);
+  Message* msg = new Message(MSG_ROUTING_CONTROL, IPC_LOGGING_ID);
   WriteParam(msg, queued_logs_);
   queued_logs_.clear();
   sender_->Send(msg);
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
index cf3a65e..b1eaaae 100644
--- a/ipc/ipc_message.cc
+++ b/ipc/ipc_message.cc
@@ -50,12 +50,11 @@
   InitLoggingVariables();
 }
 
-Message::Message(int32 routing_id, uint32 type, PriorityValue priority)
+Message::Message(int32 routing_id, uint32 type)
     : Pickle(sizeof(Header)) {
   header()->routing = routing_id;
   header()->type = type;
-  DCHECK((priority & 0xffffff00) == 0);
-  header()->flags = priority | GetRefNumUpper24();
+  header()->flags = GetRefNumUpper24();
 #if defined(OS_POSIX)
   header()->num_fds = 0;
   header()->pad = 0;
@@ -63,7 +62,8 @@
   InitLoggingVariables();
 }
 
-Message::Message(const char* data, int data_len) : Pickle(data, data_len) {
+Message::Message(const char* data, size_t data_len)
+    : Pickle(data, data_len) {
   InitLoggingVariables();
 }
 
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
index 4209016..c071703 100644
--- a/ipc/ipc_message.h
+++ b/ipc/ipc_message.h
@@ -34,17 +34,11 @@
 
 class IPC_EXPORT Message : public Pickle {
  public:
-  enum PriorityValue {
-    PRIORITY_LOW = 1,
-    PRIORITY_NORMAL,
-    PRIORITY_HIGH
-  };
-
   // Bit values used in the flags field.
   // Upper 24 bits of flags store a reference number, so this enum is limited to
   // 8 bits.
   enum {
-    PRIORITY_MASK     = 0x03,  // Low 2 bits of store the priority value.
+    UNUSED            = 0x03,  // Low 2 bits are not used.
     SYNC_BIT          = 0x04,
     REPLY_BIT         = 0x08,
     REPLY_ERROR_BIT   = 0x10,
@@ -57,22 +51,17 @@
 
   Message();
 
-  // Initialize a message with a user-defined type, priority value, and
-  // destination WebView ID.
-  Message(int32 routing_id, uint32 type, PriorityValue priority);
+  // Initialize a message with routing ID and a user-defined type.
+  Message(int32 routing_id, uint32 type);
 
   // Initializes a message from a const block of data.  The data is not copied;
   // instead the data is merely referenced by this message.  Only const methods
   // should be used on the message when initialized this way.
-  Message(const char* data, int data_len);
+  Message(const char* data, size_t data_len);
 
   Message(const Message& other);
   Message& operator=(const Message& other);
 
-  PriorityValue priority() const {
-    return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
-  }
-
   // True if this is a synchronous message.
   void set_sync() {
     header()->flags |= SYNC_BIT;
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
index c669adb..e9f54e2 100644
--- a/ipc/ipc_message_macros.h
+++ b/ipc/ipc_message_macros.h
@@ -614,7 +614,7 @@
    public:                                                                    \
     typedef IPC::Message Schema;                                              \
     enum { ID = IPC_MESSAGE_ID() };                                           \
-    msg_class() : IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) {}   \
+    msg_class() : IPC::Message(MSG_ROUTING_CONTROL, ID) {}                    \
     static void Log(std::string* name, const Message* msg, std::string* l);   \
   };
 
@@ -624,7 +624,7 @@
     typedef IPC::Message Schema;                                              \
     enum { ID = IPC_MESSAGE_ID() };                                           \
     msg_class(int32 routing_id)                                               \
-        : IPC::Message(routing_id, ID, PRIORITY_NORMAL) {}                    \
+        : IPC::Message(routing_id, ID) {}                                     \
     static void Log(std::string* name, const Message* msg, std::string* l);   \
   };
 
@@ -713,7 +713,7 @@
 
 #define IPC_ASYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
   msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list) :                        \
-      IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) {                \
+      IPC::Message(MSG_ROUTING_CONTROL, ID) {                                 \
         Schema::Write(this, IPC_NAME_IN_##in_cnt in_list);                    \
       }                                                                       \
   msg_class::~msg_class() {}                                                  \
@@ -724,7 +724,7 @@
 #define IPC_ASYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list)  \
   msg_class::msg_class(int32 routing_id IPC_COMMA_##in_cnt                    \
                        IPC_TYPE_IN_##in_cnt in_list) :                        \
-      IPC::Message(routing_id, ID, PRIORITY_NORMAL) {                         \
+      IPC::Message(routing_id, ID) {                                          \
         Schema::Write(this, IPC_NAME_IN_##in_cnt in_list);                    \
       }                                                                       \
   msg_class::~msg_class() {}                                                  \
@@ -736,7 +736,7 @@
   msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list                           \
                        IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt)            \
                        IPC_TYPE_OUT_##out_cnt out_list) :                     \
-      IPC::SyncMessage(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL,              \
+      IPC::SyncMessage(MSG_ROUTING_CONTROL, ID,                               \
                        new IPC::ParamDeserializer<Schema::ReplyParam>(        \
                            IPC_NAME_OUT_##out_cnt out_list)) {                \
         Schema::Write(this, IPC_NAME_IN_##in_cnt in_list);                    \
@@ -756,7 +756,7 @@
                        IPC_TYPE_IN_##in_cnt in_list                           \
                        IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt)            \
                        IPC_TYPE_OUT_##out_cnt out_list) :                     \
-      IPC::SyncMessage(routing_id, ID, PRIORITY_NORMAL,                       \
+      IPC::SyncMessage(routing_id, ID,                                        \
                        new IPC::ParamDeserializer<Schema::ReplyParam>(        \
                            IPC_NAME_OUT_##out_cnt out_list)) {                \
         Schema::Write(this, IPC_NAME_IN_##in_cnt in_list);                    \
@@ -996,8 +996,8 @@
                               ipc_message__.type())
 
 #define IPC_END_MESSAGE_MAP() \
-    DCHECK(msg_is_ok__); \
   } \
+  DCHECK(msg_is_ok__); \
 }
 
 #define IPC_END_MESSAGE_MAP_EX() \
diff --git a/ipc/ipc_message_unittest.cc b/ipc/ipc_message_unittest.cc
index 971314a..e5215ce 100644
--- a/ipc/ipc_message_unittest.cc
+++ b/ipc/ipc_message_unittest.cc
@@ -19,7 +19,7 @@
   input.Set(1, new base::StringValue("forty"));
   input.Set(2, base::Value::CreateNullValue());
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::WriteParam(&msg, input);
 
   base::ListValue output;
@@ -29,7 +29,7 @@
   EXPECT_TRUE(input.Equals(&output));
 
   // Also test the corrupt case.
-  IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, 2);
   bad_msg.WriteInt(99);
   iter = PickleIterator(bad_msg);
   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
@@ -54,7 +54,7 @@
 
   input.Set("dict", subdict.release());
 
-  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message msg(1, 2);
   IPC::WriteParam(&msg, input);
 
   base::DictionaryValue output;
@@ -64,7 +64,7 @@
   EXPECT_TRUE(input.Equals(&output));
 
   // Also test the corrupt case.
-  IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message bad_msg(1, 2);
   bad_msg.WriteInt(99);
   iter = PickleIterator(bad_msg);
   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
diff --git a/ipc/ipc_message_utils_unittest.cc b/ipc/ipc_message_utils_unittest.cc
index 2156eeb..9df1bef 100644
--- a/ipc/ipc_message_utils_unittest.cc
+++ b/ipc/ipc_message_utils_unittest.cc
@@ -16,16 +16,14 @@
   int32 nested_routing = 12;
   uint32 nested_type = 78;
   int nested_content = 456789;
-  Message::PriorityValue nested_priority = Message::PRIORITY_HIGH;
-  Message nested_msg(nested_routing, nested_type, nested_priority);
+  Message nested_msg(nested_routing, nested_type);
   nested_msg.set_sync();
   ParamTraits<int>::Write(&nested_msg, nested_content);
 
   // Outer message contains the nested one as its parameter.
   int32 outer_routing = 91;
   uint32 outer_type = 88;
-  Message::PriorityValue outer_priority = Message::PRIORITY_NORMAL;
-  Message outer_msg(outer_routing, outer_type, outer_priority);
+  Message outer_msg(outer_routing, outer_type);
   ParamTraits<Message>::Write(&outer_msg, nested_msg);
 
   // Read back the nested message.
@@ -36,7 +34,6 @@
   // Verify nested message headers.
   EXPECT_EQ(nested_msg.routing_id(), result_msg.routing_id());
   EXPECT_EQ(nested_msg.type(), result_msg.type());
-  EXPECT_EQ(nested_msg.priority(), result_msg.priority());
   EXPECT_EQ(nested_msg.flags(), result_msg.flags());
 
   // Verify nested message content
diff --git a/ipc/ipc_perftests.cc b/ipc/ipc_perftests.cc
index e7eeab9..8b651e2 100644
--- a/ipc/ipc_perftests.cc
+++ b/ipc/ipc_perftests.cc
@@ -122,7 +122,7 @@
           base::TimeTicks::FromInternalValue(time_internal), now);
     }
 
-    IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+    IPC::Message* msg = new IPC::Message(0, 2);
     msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
     msg->WriteInt(msgid);
     msg->WriteString(payload);
@@ -201,7 +201,7 @@
       }
     }
 
-    IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+    IPC::Message* msg = new IPC::Message(0, 2);
     msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
     msg->WriteInt(count_down_);
     msg->WriteString(payload_);
@@ -239,7 +239,7 @@
 
     // This initial message will kick-start the ping-pong of messages.
     IPC::Message* message =
-        new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+        new IPC::Message(0, 2);
     message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
     message->WriteInt(-1);
     message->WriteString("hello");
@@ -252,7 +252,7 @@
   }
 
   // Send quit message.
-  IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message* message = new IPC::Message(0, 2);
   message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
   message->WriteInt(-1);
   message->WriteString("quit");
diff --git a/ipc/ipc_send_fds_test.cc b/ipc/ipc_send_fds_test.cc
index 20c3ed5..7e36e73 100644
--- a/ipc/ipc_send_fds_test.cc
+++ b/ipc/ipc_send_fds_test.cc
@@ -106,8 +106,7 @@
       ASSERT_GE(fd, 0);
       base::FileDescriptor descriptor(fd, true);
 
-      IPC::Message* message =
-          new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
+      IPC::Message* message = new IPC::Message(0, 3);
       IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
       ASSERT_TRUE(sender()->Send(message));
     }
@@ -280,8 +279,7 @@
     ASSERT_GE(fd, 0);
     base::FileDescriptor descriptor(fd, true);
 
-    IPC::Message* message =
-        new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
+    IPC::Message* message = new IPC::Message(0, 3);
     IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
     ASSERT_TRUE(in->Send(message));
   }
diff --git a/ipc/ipc_sync_message.cc b/ipc/ipc_sync_message.cc
index 9e3acf8..5226878 100644
--- a/ipc/ipc_sync_message.cc
+++ b/ipc/ipc_sync_message.cc
@@ -39,9 +39,8 @@
 SyncMessage::SyncMessage(
     int32 routing_id,
     uint32 type,
-    PriorityValue priority,
     MessageReplyDeserializer* deserializer)
-    : Message(routing_id, type, priority),
+    : Message(routing_id, type),
       deserializer_(deserializer),
       pump_messages_event_(NULL)
       {
@@ -96,8 +95,7 @@
 Message* SyncMessage::GenerateReply(const Message* msg) {
   DCHECK(msg->is_sync());
 
-  Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
-                               msg->priority());
+  Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID);
   reply->set_reply();
 
   SyncHeader header;
diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h
index a741591..21db2e3 100644
--- a/ipc/ipc_sync_message.h
+++ b/ipc/ipc_sync_message.h
@@ -23,7 +23,7 @@
 
 class IPC_EXPORT SyncMessage : public Message {
  public:
-  SyncMessage(int32 routing_id, uint32 type, PriorityValue priority,
+  SyncMessage(int32 routing_id, uint32 type,
               MessageReplyDeserializer* deserializer);
   virtual ~SyncMessage();
 
diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc
index 6998890..daf9085 100644
--- a/media/audio/audio_device_thread.cc
+++ b/media/audio/audio_device_thread.cc
@@ -28,7 +28,8 @@
  public:
   Thread(AudioDeviceThread::Callback* callback,
          base::SyncSocket::Handle socket,
-         const char* thread_name);
+         const char* thread_name,
+         bool synchronized_buffers);
 
   void Start();
 
@@ -54,6 +55,7 @@
   base::CancelableSyncSocket socket_;
   base::Lock callback_lock_;
   const char* thread_name_;
+  const bool synchronized_buffers_;
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
@@ -67,10 +69,12 @@
 
 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
                               base::SyncSocket::Handle socket,
-                              const char* thread_name) {
+                              const char* thread_name,
+                              bool synchronized_buffers) {
   base::AutoLock auto_lock(thread_lock_);
-  CHECK(thread_.get() == NULL);
-  thread_ = new AudioDeviceThread::Thread(callback, socket, thread_name);
+  CHECK(!thread_);
+  thread_ = new AudioDeviceThread::Thread(
+      callback, socket, thread_name, synchronized_buffers);
   thread_->Start();
 }
 
@@ -84,17 +88,19 @@
 
 bool AudioDeviceThread::IsStopped() {
   base::AutoLock auto_lock(thread_lock_);
-  return thread_.get() == NULL;
+  return !thread_;
 }
 
 // AudioDeviceThread::Thread implementation
 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
                                   base::SyncSocket::Handle socket,
-                                  const char* thread_name)
+                                  const char* thread_name,
+                                  bool synchronized_buffers)
     : thread_(),
       callback_(callback),
       socket_(socket),
-      thread_name_(thread_name) {
+      thread_name_(thread_name),
+      synchronized_buffers_(synchronized_buffers) {
 }
 
 AudioDeviceThread::Thread::~Thread() {
@@ -156,6 +162,7 @@
 }
 
 void AudioDeviceThread::Thread::Run() {
+  uint32 buffer_index = 0;
   while (true) {
     int pending_data = 0;
     size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
@@ -164,9 +171,21 @@
       break;
     }
 
-    base::AutoLock auto_lock(callback_lock_);
-    if (callback_)
-      callback_->Process(pending_data);
+    {
+      base::AutoLock auto_lock(callback_lock_);
+      if (callback_)
+        callback_->Process(pending_data);
+    }
+
+    // Let the other end know which buffer we just filled.  The buffer index is
+    // used to ensure the other end is getting the buffer it expects.  For more
+    // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
+    if (synchronized_buffers_) {
+      ++buffer_index;
+      size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
+      if (bytes_sent != sizeof(buffer_index))
+        break;
+    }
   }
 }
 
diff --git a/media/audio/audio_device_thread.h b/media/audio/audio_device_thread.h
index 976f883..7a1a6ed 100644
--- a/media/audio/audio_device_thread.h
+++ b/media/audio/audio_device_thread.h
@@ -12,7 +12,6 @@
 #include "base/sync_socket.h"
 #include "base/synchronization/lock.h"
 #include "media/audio/audio_parameters.h"
-#include "media/audio/shared_memory_util.h"
 #include "media/base/media_export.h"
 
 namespace base {
@@ -74,10 +73,13 @@
   AudioDeviceThread();
   ~AudioDeviceThread();
 
-  // Starts the audio thread. The thread must not already be running.
+  // Starts the audio thread. The thread must not already be running.  If
+  // |sychronized_buffers| is set, the browser expects to be notified via the
+  // |socket| every time AudioDeviceThread::Process() completes.
   void Start(AudioDeviceThread::Callback* callback,
              base::SyncSocket::Handle socket,
-             const char* thread_name);
+             const char* thread_name,
+             bool synchronized_buffers);
 
   // This tells the audio thread to stop and clean up the data.
   // The method can stop the thread synchronously or asynchronously.
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index d768584..d1a6ab8 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -138,10 +138,10 @@
     return;
 
   DCHECK(audio_thread_.IsStopped());
-  audio_callback_.reset(
-      new AudioInputDevice::AudioThreadCallback(
-          audio_parameters_, handle, length, total_segments, callback_));
-  audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice");
+  audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
+      audio_parameters_, handle, length, total_segments, callback_));
+  audio_thread_.Start(
+      audio_callback_.get(), socket_handle, "AudioInputDevice", false);
 
   state_ = RECORDING;
   ipc_->RecordStream();
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h
index 891d2a2..ab9c82b 100644
--- a/media/audio/audio_manager.h
+++ b/media/audio/audio_manager.h
@@ -62,10 +62,16 @@
   // which must initially be empty. It is not guaranteed that all the
   // devices in the list support all formats and sample rates for
   // recording.
+  //
+  // Not threadsafe; in production this should only be called from the
+  // Audio IO thread (see GetMessageLoop).
   virtual void GetAudioInputDeviceNames(AudioDeviceNames* device_names) = 0;
 
   // Appends a list of available output devices to |device_names|,
   // which must initially be empty.
+  //
+  // Not threadsafe; in production this should only be called from the
+  // Audio IO thread (see GetMessageLoop).
   virtual void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) = 0;
 
   // Factory for all the supported stream formats. |params| defines parameters
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index 81eaab9..4f008c9 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -8,10 +8,10 @@
 #include "base/debug/trace_event.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/task_runner_util.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "media/audio/shared_memory_util.h"
 #include "media/base/scoped_histogram_timer.h"
 
 using base::Time;
@@ -111,6 +111,24 @@
       &AudioOutputController::DoSetVolume, this, volume));
 }
 
+void AudioOutputController::GetOutputDeviceId(
+    base::Callback<void(const std::string&)> callback) const {
+  base::PostTaskAndReplyWithResult(
+      message_loop_.get(),
+      FROM_HERE,
+      base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
+      callback);
+}
+
+void AudioOutputController::SwitchOutputDevice(
+    const std::string& output_device_id, const base::Closure& callback) {
+  message_loop_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
+                 output_device_id),
+      callback);
+}
+
 void AudioOutputController::DoCreate(bool is_for_device_change) {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
@@ -221,8 +239,10 @@
   if (state_ != kPaused)
     return;
 
-  // Send a special pause mark to the low-latency audio thread.
-  sync_reader_->UpdatePendingBytes(kPauseMark);
+  // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
+  // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
+  // a better way to know when it should exit PPB_Audio_Shared::Run().
+  sync_reader_->UpdatePendingBytes(-1);
 
 #if defined(AUDIO_POWER_MONITORING)
   // Paused means silence follows.
@@ -261,6 +281,28 @@
   }
 }
 
+std::string AudioOutputController::DoGetOutputDeviceId() const {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  return output_device_id_;
+}
+
+void AudioOutputController::DoSwitchOutputDevice(
+    const std::string& output_device_id) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  if (state_ == kClosed)
+    return;
+
+  output_device_id_ = output_device_id;
+
+  // If output is currently diverted, we must not call OnDeviceChange
+  // since it would break the diverted setup. Once diversion is
+  // finished using StopDiverting() the output will switch to the new
+  // device ID.
+  if (stream_ != diverting_to_stream_)
+    OnDeviceChange();
+}
+
 void AudioOutputController::DoReportError() {
   DCHECK(message_loop_->BelongsToCurrentThread());
   if (state_ != kClosed)
@@ -278,26 +320,9 @@
   DisallowEntryToOnMoreIOData();
   TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
 
-  // The OS level audio APIs on Linux and Windows all have problems requesting
-  // data on a fixed interval.  Sometimes they will issue calls back to back
-  // which can cause glitching, so wait until the renderer is ready.
-  //
-  // We also need to wait when diverting since the virtual stream will call this
-  // multiple times without waiting.
-  //
-  // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
-  // end up hanging the entire OS.
-  //
-  // See many bugs for context behind this decision: http://crbug.com/170498,
-  // http://crbug.com/171651, http://crbug.com/174985, and more.
-#if defined(OS_WIN) || defined(OS_LINUX)
-    const bool kShouldBlock = true;
-#else
-    const bool kShouldBlock = diverting_to_stream_ != NULL;
-#endif
+  sync_reader_->Read(source, dest);
 
-  const int frames = sync_reader_->Read(kShouldBlock, source, dest);
-  DCHECK_LE(0, frames);
+  const int frames = dest->frames();
   sync_reader_->UpdatePendingBytes(
       buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
 
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 615c6a5..b6fa5c4 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -91,11 +91,10 @@
     // prepare more data and perform synchronization.
     virtual void UpdatePendingBytes(uint32 bytes) = 0;
 
-    // Attempt to completely fill |dest|, return the actual number of frames
-    // that could be read.  |source| may optionally be provided for input data.
-    // If |block| is specified, the Read() will block until data is available
-    // or a timeout is reached.
-    virtual int Read(bool block, const AudioBus* source, AudioBus* dest) = 0;
+    // Attempts to completely fill |dest|, zeroing |dest| if the request can not
+    // be fulfilled (due to timeout).  |source| may optionally be provided for
+    // input data.
+    virtual void Read(const AudioBus* source, AudioBus* dest) = 0;
 
     // Close this synchronous reader.
     virtual void Close() = 0;
@@ -135,6 +134,23 @@
   // Sets the volume of the audio output stream.
   void SetVolume(double volume);
 
+  // Calls |callback| (on the caller's thread) with the current output
+  // device ID.
+  void GetOutputDeviceId(
+      base::Callback<void(const std::string&)> callback) const;
+
+  // Changes which output device to use. If desired, you can provide a
+  // callback that will be notified (on the thread you called from)
+  // when the function has completed execution.
+  //
+  // Changing the output device causes the controller to go through
+  // the same state transition back to the current state as a call to
+  // OnDeviceChange (unless it is currently diverting, see
+  // Start/StopDiverting below, in which case the state transition
+  // will happen when StopDiverting is called).
+  void SwitchOutputDevice(const std::string& output_device_id,
+                          const base::Closure& callback);
+
   // AudioSourceCallback implementation.
   virtual int OnMoreData(AudioBus* dest,
                          AudioBuffersState buffers_state) OVERRIDE;
@@ -185,6 +201,8 @@
   void DoPause();
   void DoClose();
   void DoSetVolume(double volume);
+  std::string DoGetOutputDeviceId() const;
+  void DoSwitchOutputDevice(const std::string& output_device_id);
   void DoReportError();
   void DoStartDiverting(AudioOutputStream* to_stream);
   void DoStopDiverting();
@@ -210,7 +228,7 @@
 
   // Specifies the device id of the output device to open or empty for the
   // default output device.
-  const std::string output_device_id_;
+  std::string output_device_id_;
 
   // Used by the unified IO to open the correct input device.
   const std::string input_device_id_;
diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc
index a7118e1..0347d0d 100644
--- a/media/audio/audio_output_controller_unittest.cc
+++ b/media/audio/audio_output_controller_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "media/audio/audio_manager_base.h"
 #include "media/audio/audio_output_controller.h"
 #include "media/audio/audio_parameters.h"
 #include "media/base/audio_bus.h"
@@ -53,7 +54,7 @@
   MockAudioOutputControllerSyncReader() {}
 
   MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes));
-  MOCK_METHOD3(Read, int(bool block, const AudioBus* source, AudioBus* dest));
+  MOCK_METHOD2(Read, void(const AudioBus* source, AudioBus* dest));
   MOCK_METHOD0(Close, void());
 
  private:
@@ -83,10 +84,10 @@
 
 static const float kBufferNonZeroData = 1.0f;
 ACTION(PopulateBuffer) {
-  arg2->Zero();
+  arg1->Zero();
   // Note: To confirm the buffer will be populated in these tests, it's
   // sufficient that only the first float in channel 0 is set to the value.
-  arg2->channel(0)[0] = kBufferNonZeroData;
+  arg1->channel(0)[0] = kBufferNonZeroData;
 }
 
 class AudioOutputControllerTest : public testing::Test {
@@ -141,10 +142,9 @@
     // sent from the render process.
     EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_))
         .Times(AtLeast(1));
-    EXPECT_CALL(mock_sync_reader_, Read(_, _, _))
+    EXPECT_CALL(mock_sync_reader_, Read(_, _))
         .WillRepeatedly(DoAll(PopulateBuffer(),
-                              SignalEvent(&read_event_),
-                              Return(params_.frames_per_buffer())));
+                              SignalEvent(&read_event_)));
     controller_->Play();
   }
 
@@ -216,6 +216,19 @@
     controller_->StopDiverting();
   }
 
+  void SwitchDevice(bool diverting) {
+    if (!diverting) {
+      // Expect the current stream to close and a new stream to start
+      // playing if not diverting. When diverting, nothing happens
+      // until diverting is stopped.
+      EXPECT_CALL(mock_event_handler_, OnPlaying())
+          .WillOnce(SignalEvent(&play_event_));
+    }
+
+    controller_->SwitchOutputDevice(AudioManagerBase::kDefaultDeviceName,
+                                    base::Bind(&base::DoNothing));
+  }
+
   void Close() {
     EXPECT_CALL(mock_sync_reader_, Close());
 
@@ -314,6 +327,18 @@
   Close();
 }
 
+TEST_F(AudioOutputControllerTest, PlaySwitchDeviceClose) {
+  Create(kSamplesPerPacket);
+  WaitForCreate();
+  Play();
+  WaitForPlay();
+  WaitForReads();
+  SwitchDevice(false);
+  WaitForPlay();
+  WaitForReads();
+  Close();
+}
+
 TEST_F(AudioOutputControllerTest, PlayDivertRevertClose) {
   Create(kSamplesPerPacket);
   WaitForCreate();
@@ -329,6 +354,22 @@
   Close();
 }
 
+TEST_F(AudioOutputControllerTest, PlayDivertSwitchDeviceRevertClose) {
+  Create(kSamplesPerPacket);
+  WaitForCreate();
+  Play();
+  WaitForPlay();
+  WaitForReads();
+  DivertWhilePlaying();
+  WaitForPlay();
+  SwitchDevice(true);
+  ReadDivertedAudioData();
+  RevertWhilePlaying();
+  WaitForPlay();
+  WaitForReads();
+  Close();
+}
+
 TEST_F(AudioOutputControllerTest, PlayDivertRevertDivertRevertClose) {
   Create(kSamplesPerPacket);
   WaitForCreate();
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index a5b239e..1f9efc1 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -10,7 +10,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "media/audio/audio_output_controller.h"
-#include "media/audio/shared_memory_util.h"
 #include "media/base/limits.h"
 
 namespace media {
@@ -244,8 +243,8 @@
   DCHECK(audio_thread_.IsStopped());
   audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
       audio_parameters_, handle, length, callback_));
-  audio_thread_.Start(audio_callback_.get(), socket_handle,
-      "AudioOutputDevice");
+  audio_thread_.Start(
+      audio_callback_.get(), socket_handle, "AudioOutputDevice", true);
   state_ = PAUSED;
 
   // We handle the case where Play() and/or Pause() may have been called
@@ -272,26 +271,21 @@
     base::SharedMemoryHandle memory,
     int memory_length,
     AudioRendererSink::RenderCallback* render_callback)
-    : AudioDeviceThread::Callback(audio_parameters,
-                                  memory,
-                                  memory_length,
-                                  1),
-      render_callback_(render_callback) {
-}
+    : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
+      render_callback_(render_callback) {}
 
 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() {
 }
 
 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() {
   CHECK_EQ(total_segments_, 1);
-  CHECK(shared_memory_.Map(TotalSharedMemorySizeInBytes(memory_length_)));
+  CHECK(shared_memory_.Map(memory_length_));
 
   // Calculate output and input memory size.
   int output_memory_size = AudioBus::CalculateMemorySize(audio_parameters_);
   int input_channels = audio_parameters_.input_channels();
   int frames = audio_parameters_.frames_per_buffer();
-  int input_memory_size =
-      AudioBus::CalculateMemorySize(input_channels, frames);
+  int input_memory_size = AudioBus::CalculateMemorySize(input_channels, frames);
 
   int io_size = output_memory_size + input_memory_size;
 
@@ -304,21 +298,17 @@
     // The input data is after the output data.
     char* input_data =
         static_cast<char*>(shared_memory_.memory()) + output_memory_size;
-    input_bus_ =
-        AudioBus::WrapMemory(input_channels, frames, input_data);
+    input_bus_ = AudioBus::WrapMemory(input_channels, frames, input_data);
   }
 }
 
 // Called whenever we receive notifications about pending data.
 void AudioOutputDevice::AudioThreadCallback::Process(int pending_data) {
-  if (pending_data == kPauseMark) {
-    memset(shared_memory_.memory(), 0, memory_length_);
-    SetActualDataSizeInBytes(&shared_memory_, memory_length_, 0);
+  // Negative |pending_data| indicates the browser side stream has stopped.
+  if (pending_data < 0)
     return;
-  }
 
-  // Convert the number of pending bytes in the render buffer
-  // into milliseconds.
+  // Convert the number of pending bytes in the render buffer into milliseconds.
   int audio_delay_milliseconds = pending_data / bytes_per_ms_;
 
   TRACE_EVENT0("audio", "AudioOutputDevice::FireRenderCallback");
@@ -327,25 +317,12 @@
   // |output_bus_| is wrapping the shared memory the Render() call is writing
   // directly into the shared memory.
   int input_channels = audio_parameters_.input_channels();
-  size_t num_frames = audio_parameters_.frames_per_buffer();
-
-  if (input_bus_.get() && input_channels > 0) {
-    render_callback_->RenderIO(input_bus_.get(),
-                               output_bus_.get(),
-                               audio_delay_milliseconds);
+  if (input_bus_ && input_channels > 0) {
+    render_callback_->RenderIO(
+        input_bus_.get(), output_bus_.get(), audio_delay_milliseconds);
   } else {
-    num_frames = render_callback_->Render(output_bus_.get(),
-                                          audio_delay_milliseconds);
+    render_callback_->Render(output_bus_.get(), audio_delay_milliseconds);
   }
-
-  // Let the host know we are done.
-  // TODO(dalecurtis): Technically this is not always correct.  Due to channel
-  // padding for alignment, there may be more data available than this.  We're
-  // relying on AudioSyncReader::Read() to parse this with that in mind.  Rename
-  // these methods to Set/GetActualFrameCount().
-  SetActualDataSizeInBytes(
-      &shared_memory_, memory_length_,
-      num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels());
 }
 
 }  // namespace media.
diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc
index e667c08..7aca262 100644
--- a/media/audio/audio_output_device_unittest.cc
+++ b/media/audio/audio_output_device_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/test/test_timeouts.h"
 #include "media/audio/audio_output_device.h"
 #include "media/audio/sample_rates.h"
-#include "media/audio/shared_memory_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -133,13 +132,7 @@
   int input_memory_size =
       AudioBus::CalculateMemorySize(input_channels_, frames);
 
-  int io_buffer_size = output_memory_size + input_memory_size;
-
-  // This is where it gets a bit hacky.  The shared memory contract between
-  // AudioOutputDevice and its browser side counter part includes a bit more
-  // than just the audio data, so we must call TotalSharedMemorySizeInBytes()
-  // to get the actual size needed to fit the audio data plus the extra data.
-  return TotalSharedMemorySizeInBytes(io_buffer_size);
+  return output_memory_size + input_memory_size;
 }
 
 AudioOutputDeviceTest::AudioOutputDeviceTest()
@@ -193,7 +186,7 @@
                                             &duplicated_memory_handle));
 
   audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket,
-                                 PacketSizeInBytes(kMemorySize));
+                                 kMemorySize);
   io_loop_.RunUntilIdle();
 }
 
diff --git a/media/audio/audio_parameters.cc b/media/audio/audio_parameters.cc
index 5e77c60..b7ea487 100644
--- a/media/audio/audio_parameters.cc
+++ b/media/audio/audio_parameters.cc
@@ -89,6 +89,12 @@
   return channels_ * bits_per_sample_ / 8;
 }
 
+base::TimeDelta AudioParameters::GetBufferDuration() const {
+  return base::TimeDelta::FromMicroseconds(
+      frames_per_buffer_ * base::Time::kMicrosecondsPerSecond /
+      static_cast<float>(sample_rate_));
+}
+
 void AudioParameters::SetDiscreteChannels(int channels) {
   channel_layout_ = CHANNEL_LAYOUT_DISCRETE;
   channels_ = channels;
diff --git a/media/audio/audio_parameters.h b/media/audio/audio_parameters.h
index bc629a7..9b86d31 100644
--- a/media/audio/audio_parameters.h
+++ b/media/audio/audio_parameters.h
@@ -6,6 +6,7 @@
 #define MEDIA_AUDIO_AUDIO_PARAMETERS_H_
 
 #include "base/basictypes.h"
+#include "base/time/time.h"
 #include "media/base/channel_layout.h"
 #include "media/base/media_export.h"
 
@@ -69,6 +70,10 @@
   // Returns the number of bytes representing a frame of audio.
   int GetBytesPerFrame() const;
 
+  // Returns the duration of this buffer as calculated from frames_per_buffer()
+  // and sample_rate().
+  base::TimeDelta GetBufferDuration() const;
+
   Format format() const { return format_; }
   ChannelLayout channel_layout() const { return channel_layout_; }
   int sample_rate() const { return sample_rate_; }
diff --git a/media/audio/cras/cras_unified.cc b/media/audio/cras/cras_unified.cc
index fe2c7b0..906f209 100644
--- a/media/audio/cras/cras_unified.cc
+++ b/media/audio/cras/cras_unified.cc
@@ -161,6 +161,23 @@
 
 void CrasUnifiedStream::Start(AudioSourceCallback* callback) {
   CHECK(callback);
+
+  // Channel map to CRAS_CHANNEL, values in the same order of
+  // corresponding source in Chromium defined Channels.
+  static const int kChannelMap[] = {
+    CRAS_CH_FL,
+    CRAS_CH_FR,
+    CRAS_CH_FC,
+    CRAS_CH_LFE,
+    CRAS_CH_RL,
+    CRAS_CH_RR,
+    CRAS_CH_FLC,
+    CRAS_CH_FRC,
+    CRAS_CH_RC,
+    CRAS_CH_SL,
+    CRAS_CH_SR
+  };
+
   source_callback_ = callback;
 
   // Only start if we can enter the playing state.
@@ -179,6 +196,22 @@
     return;
   }
 
+  // Initialize channel layout to all -1 to indicate that none of
+  // the channels is set in the layout.
+  int8 layout[CRAS_CH_MAX] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+  // Converts to CRAS defined channels. ChannelOrder will return -1
+  // for channels that does not present in params_.channel_layout().
+  for (size_t i = 0; i < arraysize(kChannelMap); ++i)
+    layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
+                                          static_cast<Channels>(i));
+
+  if (cras_audio_format_set_channel_layout(audio_format, layout)) {
+    LOG(WARNING) << "Error setting channel layout.";
+    callback->OnError(this);
+    return;
+  }
+
   cras_stream_params* stream_params = cras_client_unified_params_create(
       stream_direction_,
       params_.frames_per_buffer(),
diff --git a/media/audio/shared_memory_util.cc b/media/audio/shared_memory_util.cc
deleted file mode 100644
index 523cdb9..0000000
--- a/media/audio/shared_memory_util.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 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/audio/shared_memory_util.h"
-
-#include <algorithm>
-
-#include "base/atomicops.h"
-#include "base/logging.h"
-
-using base::subtle::Atomic32;
-
-static const uint32 kUnknownDataSize = static_cast<uint32>(-1);
-
-namespace media {
-
-uint32 TotalSharedMemorySizeInBytes(uint32 packet_size) {
-  // Need to reserve extra 4 bytes for size of data.
-  return packet_size + sizeof(Atomic32);
-}
-
-uint32 PacketSizeInBytes(uint32 shared_memory_created_size) {
-  return shared_memory_created_size - sizeof(Atomic32);
-}
-
-uint32 GetActualDataSizeInBytes(base::SharedMemory* shared_memory,
-                                uint32 packet_size) {
-  char* ptr = static_cast<char*>(shared_memory->memory()) + packet_size;
-  DCHECK_EQ(0u, reinterpret_cast<size_t>(ptr) & 3);
-
-  // Actual data size stored at the end of the buffer.
-  uint32 actual_data_size =
-      base::subtle::Acquire_Load(reinterpret_cast<volatile Atomic32*>(ptr));
-  return std::min(actual_data_size, packet_size);
-}
-
-void SetActualDataSizeInBytes(void* shared_memory_ptr,
-                              uint32 packet_size,
-                              uint32 actual_data_size) {
-  char* ptr = static_cast<char*>(shared_memory_ptr) + packet_size;
-  DCHECK_EQ(0u, reinterpret_cast<size_t>(ptr) & 3);
-
-  // Set actual data size at the end of the buffer.
-  base::subtle::Release_Store(reinterpret_cast<volatile Atomic32*>(ptr),
-                              actual_data_size);
-}
-
-void SetActualDataSizeInBytes(base::SharedMemory* shared_memory,
-                              uint32 packet_size,
-                              uint32 actual_data_size) {
-  SetActualDataSizeInBytes(shared_memory->memory(),
-                           packet_size, actual_data_size);
-}
-
-void SetUnknownDataSize(base::SharedMemory* shared_memory,
-                        uint32 packet_size) {
-  SetActualDataSizeInBytes(shared_memory, packet_size, kUnknownDataSize);
-}
-
-bool IsUnknownDataSize(base::SharedMemory* shared_memory,
-                       uint32 packet_size) {
-  char* ptr = static_cast<char*>(shared_memory->memory()) + packet_size;
-  DCHECK_EQ(0u, reinterpret_cast<size_t>(ptr) & 3);
-
-  // Actual data size stored at the end of the buffer.
-  uint32 actual_data_size =
-      base::subtle::Acquire_Load(reinterpret_cast<volatile Atomic32*>(ptr));
-  return actual_data_size == kUnknownDataSize;
-}
-
-}  // namespace media
diff --git a/media/audio/shared_memory_util.h b/media/audio/shared_memory_util.h
deleted file mode 100644
index 9186d5c..0000000
--- a/media/audio/shared_memory_util.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 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_AUDIO_SHARED_MEMORY_UTIL_H_
-#define MEDIA_AUDIO_SHARED_MEMORY_UTIL_H_
-
-#include "base/basictypes.h"
-#include "base/memory/shared_memory.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-// Value sent by the controller to the renderer in low-latency mode
-// indicating that the stream is paused.
-enum { kPauseMark = -1 };
-
-// Functions that handle data buffer passed between processes in the shared
-// memory.  Called on both IPC sides.  These are necessary because the shared
-// memory has a layout: the last word in the block is the data size in bytes.
-
-MEDIA_EXPORT uint32 TotalSharedMemorySizeInBytes(uint32 packet_size);
-MEDIA_EXPORT uint32 PacketSizeInBytes(uint32 shared_memory_created_size);
-MEDIA_EXPORT uint32 GetActualDataSizeInBytes(base::SharedMemory* shared_memory,
-                                             uint32 packet_size);
-MEDIA_EXPORT void SetActualDataSizeInBytes(base::SharedMemory* shared_memory,
-                                           uint32 packet_size,
-                                           uint32 actual_data_size);
-MEDIA_EXPORT void SetActualDataSizeInBytes(void* shared_memory_ptr,
-                                           uint32 packet_size,
-                                           uint32 actual_data_size);
-MEDIA_EXPORT void SetUnknownDataSize(base::SharedMemory* shared_memory,
-                                     uint32 packet_size);
-MEDIA_EXPORT bool IsUnknownDataSize(base::SharedMemory* shared_memory,
-                                    uint32 packet_size);
-
-}  // namespace media
-
-#endif  // MEDIA_AUDIO_SHARED_MEMORY_UTIL_H_
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc
index c5402fa..8ba8821 100644
--- a/media/audio/win/audio_low_latency_output_win.cc
+++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -25,23 +25,6 @@
 
 namespace media {
 
-typedef uint32 ChannelConfig;
-
-// Retrieves an integer mask which corresponds to the channel layout the
-// audio engine uses for its internal processing/mixing of shared-mode
-// streams. This mask indicates which channels are present in the multi-
-// channel stream. The least significant bit corresponds with the Front Left
-// speaker, the next least significant bit corresponds to the Front Right
-// speaker, and so on, continuing in the order defined in KsMedia.h.
-// See http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
-// for more details.
-static ChannelConfig GetChannelConfig() {
-  WAVEFORMATPCMEX format;
-  return SUCCEEDED(CoreAudioUtil::GetDefaultSharedModeMixFormat(
-                   eRender, eConsole, &format)) ?
-                   static_cast<int>(format.dwChannelMask) : 0;
-}
-
 // Compare two sets of audio parameters and return true if they are equal.
 // Note that bits_per_sample() is excluded from this comparison since Core
 // Audio can deal with most bit depths. As an example, if the native/mixing
@@ -55,40 +38,6 @@
           a.frames_per_buffer() == b.frames_per_buffer());
 }
 
-// Converts Microsoft's channel configuration to ChannelLayout.
-// This mapping is not perfect but the best we can do given the current
-// ChannelLayout enumerator and the Windows-specific speaker configurations
-// defined in ksmedia.h. Don't assume that the channel ordering in
-// ChannelLayout is exactly the same as the Windows specific configuration.
-// As an example: KSAUDIO_SPEAKER_7POINT1_SURROUND is mapped to
-// CHANNEL_LAYOUT_7_1 but the positions of Back L, Back R and Side L, Side R
-// speakers are different in these two definitions.
-static ChannelLayout ChannelConfigToChannelLayout(ChannelConfig config) {
-  switch (config) {
-    case KSAUDIO_SPEAKER_DIRECTOUT:
-      return CHANNEL_LAYOUT_NONE;
-    case KSAUDIO_SPEAKER_MONO:
-      return CHANNEL_LAYOUT_MONO;
-    case KSAUDIO_SPEAKER_STEREO:
-      return CHANNEL_LAYOUT_STEREO;
-    case KSAUDIO_SPEAKER_QUAD:
-      return CHANNEL_LAYOUT_QUAD;
-    case KSAUDIO_SPEAKER_SURROUND:
-      return CHANNEL_LAYOUT_4_0;
-    case KSAUDIO_SPEAKER_5POINT1:
-      return CHANNEL_LAYOUT_5_1_BACK;
-    case KSAUDIO_SPEAKER_5POINT1_SURROUND:
-      return CHANNEL_LAYOUT_5_1;
-    case KSAUDIO_SPEAKER_7POINT1:
-      return CHANNEL_LAYOUT_7_1_WIDE;
-    case KSAUDIO_SPEAKER_7POINT1_SURROUND:
-      return CHANNEL_LAYOUT_7_1;
-    default:
-      VLOG(1) << "Unsupported channel layout: " << config;
-      return CHANNEL_LAYOUT_UNSUPPORTED;
-  }
-}
-
 // static
 AUDCLNT_SHAREMODE WASAPIAudioOutputStream::GetShareMode() {
   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
@@ -98,19 +47,6 @@
 }
 
 // static
-int WASAPIAudioOutputStream::HardwareChannelCount() {
-  WAVEFORMATPCMEX format;
-  return SUCCEEDED(CoreAudioUtil::GetDefaultSharedModeMixFormat(
-      eRender, eConsole, &format)) ?
-      static_cast<int>(format.Format.nChannels) : 0;
-}
-
-// static
-ChannelLayout WASAPIAudioOutputStream::HardwareChannelLayout() {
-  return ChannelConfigToChannelLayout(GetChannelConfig());
-}
-
-// static
 int WASAPIAudioOutputStream::HardwareSampleRate(const std::string& device_id) {
   WAVEFORMATPCMEX format;
   ScopedComPtr<IAudioClient> client;
@@ -187,7 +123,7 @@
 
   // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE.
   format_.Samples.wValidBitsPerSample = params.bits_per_sample();
-  format_.dwChannelMask = GetChannelConfig();
+  format_.dwChannelMask = CoreAudioUtil::GetChannelConfig(device_id, eRender);
   format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
   // Store size (in different units) of audio packets which we expect to
diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h
index 51e7dee..4efc0f6 100644
--- a/media/audio/win/audio_low_latency_output_win.h
+++ b/media/audio/win/audio_low_latency_output_win.h
@@ -138,17 +138,6 @@
   virtual void SetVolume(double volume) OVERRIDE;
   virtual void GetVolume(double* volume) OVERRIDE;
 
-  // Retrieves the number of channels the audio engine uses for its internal
-  // processing/mixing of shared-mode streams for the default endpoint device.
-  static int HardwareChannelCount();
-
-  // Retrieves the channel layout the audio engine uses for its internal
-  // processing/mixing of shared-mode streams for the default endpoint device.
-  // Note that we convert an internal channel layout mask (see ChannelMask())
-  // into a Chrome-specific channel layout enumerator in this method, hence
-  // the match might not be perfect.
-  static ChannelLayout HardwareChannelLayout();
-
   // Retrieves the sample rate the audio engine uses for its internal
   // processing/mixing of shared-mode streams.  To fetch the settings for the
   // default device, pass an empty string as the |device_id|.
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 71d9dd8..254fe36 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -355,7 +355,8 @@
 
   if (!CoreAudioUtil::IsSupported()) {
     // Fall back to Windows Wave implementation on Windows XP or lower.
-    DLOG_IF(ERROR, !device_id.empty())
+    DLOG_IF(ERROR, !device_id.empty() &&
+        device_id != AudioManagerBase::kDefaultDeviceId)
         << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
     DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
     return new PCMWaveOutAudioOutputStream(
@@ -365,12 +366,19 @@
   // TODO(rtoy): support more than stereo input.
   if (params.input_channels() > 0) {
     DVLOG(1) << "WASAPIUnifiedStream is created.";
-    DLOG_IF(ERROR, !device_id.empty())
+    DLOG_IF(ERROR, !device_id.empty() &&
+        device_id != AudioManagerBase::kDefaultDeviceId)
         << "Opening by device id not supported by WASAPIUnifiedStream";
     return new WASAPIUnifiedStream(this, params, input_device_id);
   }
 
-  return new WASAPIAudioOutputStream(this, device_id, params, eConsole);
+  // Pass an empty string to indicate that we want the default device
+  // since we consistently only check for an empty string in
+  // WASAPIAudioOutputStream.
+  return new WASAPIAudioOutputStream(this,
+      device_id == AudioManagerBase::kDefaultDeviceId ?
+          std::string() : device_id,
+      params, eConsole);
 }
 
 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR
@@ -454,14 +462,14 @@
       // hardware (preferred) layout. We do this extra check to avoid the
       // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
       if (input_params.channel_layout() != channel_layout) {
-        // TODO(henrika): Use |output_device_id| here.
-        // Internally, IsChannelLayoutSupported does many of the operations
-        // that have already been done such as opening up a client and fetching
-        // the WAVEFORMATPCMEX format.  Ideally we should only do that once and
-        // do it for the requested device.  Then here, we can check the layout
-        // from the data we already hold.
+        // TODO(henrika): Internally, IsChannelLayoutSupported does many of the
+        // operations that have already been done such as opening up a client
+        // and fetching the WAVEFORMATPCMEX format.  Ideally we should only do
+        // that once.  Then here, we can check the layout from the data we
+        // already hold.
         if (CoreAudioUtil::IsChannelLayoutSupported(
-                eRender, eConsole, input_params.channel_layout())) {
+                output_device_id, eRender, eConsole,
+                input_params.channel_layout())) {
           // Open up using the same channel layout as the source if it is
           // supported by the hardware.
           channel_layout = input_params.channel_layout();
diff --git a/media/audio/win/audio_unified_win.cc b/media/audio/win/audio_unified_win.cc
index 5c1594e..848678d 100644
--- a/media/audio/win/audio_unified_win.cc
+++ b/media/audio/win/audio_unified_win.cc
@@ -51,23 +51,6 @@
 static const char kUnifiedAudioParamsFileName[] = "unified_win_params.txt";
 #endif
 
-typedef uint32 ChannelConfig;
-
-// Retrieves an integer mask which corresponds to the channel layout the
-// audio engine uses for its internal processing/mixing of shared-mode
-// streams. This mask indicates which channels are present in the multi-
-// channel stream. The least significant bit corresponds with the Front Left
-// speaker, the next least significant bit corresponds to the Front Right
-// speaker, and so on, continuing in the order defined in KsMedia.h.
-// See http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
-// for more details.
-static ChannelConfig GetChannelConfig(EDataFlow data_flow) {
-  WAVEFORMATPCMEX format;
-  return SUCCEEDED(media::CoreAudioUtil::GetDefaultSharedModeMixFormat(
-                   data_flow, eConsole, &format)) ?
-                   static_cast<int>(format.dwChannelMask) : 0;
-}
-
 // Use the acquired IAudioClock interface to derive a time stamp of the audio
 // sample which is currently playing through the speakers.
 static double SpeakerStreamPosInMilliseconds(IAudioClock* clock) {
@@ -575,8 +558,9 @@
     // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE.
     // Note that we always open up using the native channel layout.
     (*xformat).Samples.wValidBitsPerSample = format->wBitsPerSample;
-    (*xformat).dwChannelMask = (n == 0) ?
-        GetChannelConfig(eCapture) : GetChannelConfig(eRender);
+    (*xformat).dwChannelMask =
+        CoreAudioUtil::GetChannelConfig(
+            std::string(), n == 0 ? eCapture : eRender);
     (*xformat).SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
   }
 
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 4adfdda..4771460 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -25,8 +25,6 @@
 
 enum { KSAUDIO_SPEAKER_UNSUPPORTED = 0 };
 
-typedef uint32 ChannelConfig;
-
 // Converts Microsoft's channel configuration to ChannelLayout.
 // This mapping is not perfect but the best we can do given the current
 // ChannelLayout enumerator and the Windows-specific speaker configurations
@@ -401,7 +399,7 @@
   ScopedComPtr<IMMDevice> output_device;
   for (UINT i = 0; i < count; ++i) {
     collection->Item(i, output_device.Receive());
-    std::string output_controller_id(CoreAudioUtil::GetAudioControllerID(
+    std::string output_controller_id(GetAudioControllerID(
         output_device, enumerator));
     if (output_controller_id == controller_id)
       break;
@@ -478,6 +476,18 @@
       ScopedComPtr<IAudioClient>());
 }
 
+ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient(
+    const std::string& device_id, EDataFlow data_flow, ERole role) {
+  if (device_id.empty())
+    return CreateDefaultClient(data_flow, role);
+
+  ScopedComPtr<IMMDevice> device(CreateDevice(device_id));
+  if (!device)
+    return ScopedComPtr<IAudioClient>();
+
+ return CreateClient(device);
+}
+
 HRESULT CoreAudioUtil::GetSharedModeMixFormat(
     IAudioClient* client, WAVEFORMATPCMEX* format) {
   DCHECK(IsSupported());
@@ -496,18 +506,6 @@
   return hr;
 }
 
-HRESULT CoreAudioUtil::GetDefaultSharedModeMixFormat(
-    EDataFlow data_flow, ERole role, WAVEFORMATPCMEX* format) {
-  DCHECK(IsSupported());
-  ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
-  if (!client) {
-    // Map NULL-pointer to new error code which can be different from the
-    // actual error code. The exact value is not important here.
-    return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
-  }
-  return CoreAudioUtil::GetSharedModeMixFormat(client, format);
-}
-
 bool CoreAudioUtil::IsFormatSupported(IAudioClient* client,
                                       AUDCLNT_SHAREMODE share_mode,
                                       const WAVEFORMATPCMEX* format) {
@@ -529,18 +527,20 @@
   return (hr == S_OK);
 }
 
-bool CoreAudioUtil::IsChannelLayoutSupported(EDataFlow data_flow, ERole role,
+bool CoreAudioUtil::IsChannelLayoutSupported(const std::string& device_id,
+                                             EDataFlow data_flow,
+                                             ERole role,
                                              ChannelLayout channel_layout) {
   DCHECK(IsSupported());
 
   // First, get the preferred mixing format for shared mode streams.
 
-  ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
+  ScopedComPtr<IAudioClient> client(CreateClient(device_id, data_flow, role));
   if (!client)
     return false;
 
   WAVEFORMATPCMEX format;
-  HRESULT hr = CoreAudioUtil::GetSharedModeMixFormat(client, &format);
+  HRESULT hr = GetSharedModeMixFormat(client, &format);
   if (FAILED(hr))
     return false;
 
@@ -684,6 +684,18 @@
   return GetPreferredAudioParameters(client, params);
 }
 
+ChannelConfig CoreAudioUtil::GetChannelConfig(const std::string& device_id,
+                                              EDataFlow data_flow) {
+  ScopedComPtr<IAudioClient> client(
+      CreateClient(device_id, data_flow, eConsole));
+
+  WAVEFORMATPCMEX format = {0};
+  if (!client || FAILED(GetSharedModeMixFormat(client, &format)))
+    return 0;
+
+  return static_cast<ChannelConfig>(format.dwChannelMask);
+}
+
 HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client,
                                             const WAVEFORMATPCMEX* format,
                                             HANDLE event_handle,
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h
index cdf6dfb..a210af9 100644
--- a/media/audio/win/core_audio_util_win.h
+++ b/media/audio/win/core_audio_util_win.h
@@ -26,6 +26,12 @@
 
 namespace media {
 
+
+// Represents audio channel configuration constants as understood by Windows.
+// E.g. KSAUDIO_SPEAKER_MONO.  For a list of possible values see:
+// http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
+typedef uint32 ChannelConfig;
+
 class MEDIA_EXPORT CoreAudioUtil {
  public:
   // Returns true if Windows Core Audio is supported.
@@ -106,7 +112,7 @@
   // manage the flow of audio data between the application and an audio endpoint
   // device.
 
-  // Create an IAudioClient interface for the default IMMDevice where
+  // Create an IAudioClient instance for the default IMMDevice where
   // flow direction and role is define by |data_flow| and |role|.
   // The IAudioClient interface enables a client to create and initialize an
   // audio stream between an audio application and the audio engine (for a
@@ -115,6 +121,12 @@
   static ScopedComPtr<IAudioClient> CreateDefaultClient(EDataFlow data_flow,
                                                         ERole role);
 
+  // Create an IAudioClient instance for a specific device _or_ the default
+  // device if |device_id| is empty.
+  static ScopedComPtr<IAudioClient> CreateClient(const std::string& device_id,
+                                                 EDataFlow data_flow,
+                                                 ERole role);
+
   // Create an IAudioClient interface for an existing IMMDevice given by
   // |audio_device|. Flow direction and role is define by the |audio_device|.
   static ScopedComPtr<IAudioClient> CreateClient(IMMDevice* audio_device);
@@ -126,13 +138,6 @@
   static HRESULT GetSharedModeMixFormat(IAudioClient* client,
                                         WAVEFORMATPCMEX* format);
 
-  // Get the mix format that the audio engine uses internally for processing
-  // of shared-mode streams using the default IMMDevice where flow direction
-  // and role is define by |data_flow| and |role|.
-  static HRESULT GetDefaultSharedModeMixFormat(EDataFlow data_flow,
-                                               ERole role,
-                                               WAVEFORMATPCMEX* format);
-
   // Returns true if the specified |client| supports the format in |format|
   // for the given |share_mode| (shared or exclusive).
   static bool IsFormatSupported(IAudioClient* client,
@@ -144,7 +149,9 @@
   // and |role|. If this method returns true for a certain channel layout, it
   // means that SharedModeInitialize() will succeed using a format based on
   // the preferred format where the channel layout has been modified.
-  static bool IsChannelLayoutSupported(EDataFlow data_flow, ERole role,
+  static bool IsChannelLayoutSupported(const std::string& device_id,
+                                       EDataFlow data_flow,
+                                       ERole role,
                                        ChannelLayout channel_layout);
 
   // For a shared-mode stream, the audio engine periodically processes the
@@ -170,6 +177,19 @@
   static HRESULT GetPreferredAudioParameters(const std::string& device_id,
                                              AudioParameters* params);
 
+  // Retrieves an integer mask which corresponds to the channel layout the
+  // audio engine uses for its internal processing/mixing of shared-mode
+  // streams. This mask indicates which channels are present in the multi-
+  // channel stream. The least significant bit corresponds with the Front Left
+  // speaker, the next least significant bit corresponds to the Front Right
+  // speaker, and so on, continuing in the order defined in KsMedia.h.
+  // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
+  // for more details.
+  // To get the channel config of the default device, pass an empty string
+  // for |device_id|.
+  static ChannelConfig GetChannelConfig(const std::string& device_id,
+                                        EDataFlow data_flow);
+
   // After activating an IAudioClient interface on an audio endpoint device,
   // the client must initialize it once, and only once, to initialize the audio
   // stream between the client and the device. In shared mode, the client
diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc
index abef868..e9ed0c4 100644
--- a/media/audio/win/core_audio_util_win_unittest.cc
+++ b/media/audio/win/core_audio_util_win_unittest.cc
@@ -274,7 +274,7 @@
   EXPECT_TRUE(SUCCEEDED(hr));
   EXPECT_TRUE(mix_params.IsValid());
   EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
-      eRender, eConsole, mix_params.channel_layout()));
+      std::string(), eRender, eConsole, mix_params.channel_layout()));
 
   // Check if it is possible to modify the channel layout to stereo for a
   // device which reports that it prefers to be openen up in an other
@@ -284,7 +284,7 @@
     // TODO(henrika): it might be too pessimistic to assume false as return
     // value here.
     EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
-        eRender, eConsole, channel_layout));
+        std::string(), eRender, eConsole, channel_layout));
   }
 }
 
diff --git a/media/base/android/demuxer_android.h b/media/base/android/demuxer_android.h
index 5791545..865dc9d 100644
--- a/media/base/android/demuxer_android.h
+++ b/media/base/android/demuxer_android.h
@@ -32,7 +32,13 @@
   virtual void RequestDemuxerData(media::DemuxerStream::Type type) = 0;
 
   // Called to request the demuxer to seek to a particular media time.
-  virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek) = 0;
+  // |is_browser_seek| is true if the renderer is not previously expecting this
+  // seek and must coordinate with other regular seeks. Browser seek existence
+  // should be hidden as much as possible from the renderer player and web apps.
+  // TODO(wolenetz): Instead of doing browser seek, replay cached data since
+  // last keyframe. See http://crbug.com/304234.
+  virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
+                                  bool is_browser_seek) = 0;
 };
 
 // Defines the client callback interface.
@@ -50,7 +56,13 @@
   virtual void OnDemuxerDataAvailable(const DemuxerData& params) = 0;
 
   // Called in response to RequestDemuxerSeek().
-  virtual void OnDemuxerSeekDone() = 0;
+  // If this is in response to a request with |is_browser_seek| set to true,
+  // then |actual_browser_seek_time| may differ from the requested
+  // |time_to_seek|, and reflects the actual time seeked to by the demuxer.
+  // For regular demuxer seeks, |actual_browser_seek_time| is kNoTimestamp() and
+  // should be ignored by browser player.
+  virtual void OnDemuxerSeekDone(
+      const base::TimeDelta& actual_browser_seek_time) = 0;
 
   // Called whenever the demuxer has detected a duration change.
   virtual void OnDemuxerDurationChanged(base::TimeDelta duration) = 0;
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index d9bb48b..74bec56 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -81,11 +81,13 @@
      * This class represents supported android codec information.
      */
     private static class CodecInfo {
-        private final String mCodecType;
+        private final String mCodecType;  // e.g. "video/x-vnd.on2.vp8".
+        private final String mCodecName;  // e.g. "OMX.google.vp8.decoder".
         private final boolean mIsSecureDecoderSupported;
 
-        private CodecInfo(String codecType, boolean isSecureDecoderSupported) {
+        private CodecInfo(String codecType, String codecName, boolean isSecureDecoderSupported) {
             mCodecType = codecType;
+            mCodecName = codecName;
             mIsSecureDecoderSupported = isSecureDecoderSupported;
         }
 
@@ -93,6 +95,9 @@
         private String codecType() { return mCodecType; }
 
         @CalledByNative("CodecInfo")
+        private String codecName() { return mCodecName; }
+
+        @CalledByNative("CodecInfo")
         private boolean isSecureDecoderSupported() { return mIsSecureDecoderSupported; }
     }
 
@@ -159,8 +164,8 @@
             }
             for (int j = 0; j < supportedTypes.length; ++j) {
                 if (!CodecInfoMap.containsKey(supportedTypes[j]) || secureDecoderSupported) {
-                    CodecInfoMap.put(supportedTypes[j],
-                                     new CodecInfo(supportedTypes[j], secureDecoderSupported));
+                    CodecInfoMap.put(supportedTypes[j], new CodecInfo(
+                        supportedTypes[j], codecString, secureDecoderSupported));
                 }
             }
         }
diff --git a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
index 1de7e42..17720e6 100644
--- a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
@@ -21,7 +21,6 @@
 
 @JNINamespace("media")
 class WebAudioMediaCodecBridge {
-    private static final boolean DEBUG = true;
     static final String LOG_TAG = "WebAudioMediaCodec";
     // TODO(rtoy): What is the correct timeout value for reading
     // from a file in memory?
@@ -81,18 +80,8 @@
             }
         }
 
-        if (DEBUG) {
-            Log.d(LOG_TAG, "Tracks: " + extractor.getTrackCount()
-                  + " Rate: " + sampleRate
-                  + " Channels: " + inputChannelCount
-                  + " Mime: " + mime
-                  + " Duration: " + durationMicroseconds + " microsec");
-        }
-
-        nativeInitializeDestination(nativeMediaCodecBridge,
-                                    inputChannelCount,
-                                    sampleRate,
-                                    durationMicroseconds);
+        Log.d(LOG_TAG, "Initial: Tracks: " + extractor.getTrackCount() +
+              " Format: " + format);
 
         // Create decoder
         MediaCodec codec = MediaCodec.createDecoderByType(mime);
@@ -107,6 +96,7 @@
 
         boolean sawInputEOS = false;
         boolean sawOutputEOS = false;
+        boolean destinationInitialized = false;
 
         // Keep processing until the output is done.
         while (!sawOutputEOS) {
@@ -145,7 +135,24 @@
             if (outputBufIndex >= 0) {
                 ByteBuffer buf = codecOutputBuffers[outputBufIndex];
 
-                if (info.size > 0) {
+                if (!destinationInitialized) {
+                    // Initialize the destination as late as possible to
+                    // catch any changes in format. But be sure to
+                    // initialize it BEFORE we send any decoded audio,
+                    // and only initialize once.
+                    Log.d(LOG_TAG, "Final:  Rate: " + sampleRate +
+                          " Channels: " + inputChannelCount +
+                          " Mime: " + mime +
+                          " Duration: " + durationMicroseconds + " microsec");
+
+                    nativeInitializeDestination(nativeMediaCodecBridge,
+                                                inputChannelCount,
+                                                sampleRate,
+                                                durationMicroseconds);
+                    destinationInitialized = true;
+                }
+
+                if (destinationInitialized && info.size > 0) {
                     nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size,
                                          inputChannelCount, outputChannelCount);
                 }
@@ -161,6 +168,7 @@
             } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                 MediaFormat newFormat = codec.getOutputFormat();
                 outputChannelCount = newFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+                sampleRate = newFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                 Log.d(LOG_TAG, "output format changed to " + newFormat);
             }
         }
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index 75d103c..1c4928a 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -15,6 +15,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/safe_numerics.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "jni/MediaCodecBridge_jni.h"
 #include "media/base/bit_reader.h"
@@ -29,7 +30,7 @@
 
 enum { kBufferFlagEndOfStream = 4 };
 
-static const std::string AudioCodecToAndroidMimeType(const AudioCodec codec) {
+static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) {
   switch (codec) {
     case kCodecMP3:
       return "audio/mpeg";
@@ -42,7 +43,7 @@
   }
 }
 
-static const std::string VideoCodecToAndroidMimeType(const VideoCodec codec) {
+static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) {
   switch (codec) {
     case kCodecH264:
       return "video/avc";
@@ -106,6 +107,7 @@
     return;
 
   std::string mime_type;
+  std::string codec_name;
   ScopedJavaLocalRef<jobjectArray> j_codec_info_array =
       Java_MediaCodecBridge_getCodecsInfo(env);
   jsize len = env->GetArrayLength(j_codec_info_array.obj());
@@ -115,8 +117,11 @@
     ScopedJavaLocalRef<jstring> j_codec_type =
         Java_CodecInfo_codecType(env, j_info.obj());
     ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type);
+    ScopedJavaLocalRef<jstring> j_codec_name =
+        Java_CodecInfo_codecName(env, j_info.obj());
     CodecsInfo info;
     info.codecs = AndroidMimeTypeToCodecType(mime_type);
+    ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name);
     info.secure_decoder_supported =
         Java_CodecInfo_isSecureDecoderSupported(env, j_info.obj());
     codecs_info->push_back(info);
@@ -139,6 +144,22 @@
   return false;
 }
 
+// static
+bool MediaCodecBridge::IsKnownUnaccelerated(const std::string& mime_type) {
+  std::string codec_type = AndroidMimeTypeToCodecType(mime_type);
+  std::vector<media::MediaCodecBridge::CodecsInfo> codecs_info;
+  media::MediaCodecBridge::GetCodecsInfo(&codecs_info);
+  for (size_t i = 0; i < codecs_info.size(); ++i) {
+    if (codecs_info[i].codecs == codec_type) {
+      // It would be nice if MediaCodecInfo externalized some notion of
+      // HW-acceleration but it doesn't. Android Media guidance is that the
+      // prefix below is always used for SW decoders, so that's what we use.
+      return StartsWithASCII(codecs_info[i].name, "OMX.google.", true);
+    }
+  }
+  return true;
+}
+
 MediaCodecBridge::MediaCodecBridge(const std::string& mime, bool is_secure) {
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
@@ -312,7 +333,7 @@
 }
 
 bool AudioCodecBridge::Start(
-    const AudioCodec codec, int sample_rate, int channel_count,
+    const AudioCodec& codec, int sample_rate, int channel_count,
     const uint8* extra_data, size_t extra_data_size, bool play_audio,
     jobject media_crypto) {
   JNIEnv* env = AttachCurrentThread();
@@ -343,7 +364,7 @@
 }
 
 bool AudioCodecBridge::ConfigureMediaFormat(
-    jobject j_format, const AudioCodec codec, const uint8* extra_data,
+    jobject j_format, const AudioCodec& codec, const uint8* extra_data,
     size_t extra_data_size) {
   if (extra_data_size == 0)
     return true;
@@ -470,7 +491,7 @@
 }
 
 bool VideoCodecBridge::Start(
-    const VideoCodec codec, const gfx::Size& size, jobject surface,
+    const VideoCodec& codec, const gfx::Size& size, jobject surface,
     jobject media_crypto) {
   JNIEnv* env = AttachCurrentThread();
 
@@ -495,17 +516,29 @@
   return StartInternal();
 }
 
-AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) {
+AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
   const std::string mime = AudioCodecToAndroidMimeType(codec);
   return mime.empty() ? NULL : new AudioCodecBridge(mime);
 }
 
-VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec,
+// static
+bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
+  return MediaCodecBridge::IsKnownUnaccelerated(
+      AudioCodecToAndroidMimeType(codec));
+}
+
+VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec& codec,
                                            bool is_secure) {
   const std::string mime = VideoCodecToAndroidMimeType(codec);
   return mime.empty() ? NULL : new VideoCodecBridge(mime, is_secure);
 }
 
+// static
+bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec) {
+  return MediaCodecBridge::IsKnownUnaccelerated(
+      VideoCodecToAndroidMimeType(codec));
+}
+
 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index 15b707c..64c7357 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -54,6 +54,7 @@
   // need more specific codecs separated by comma. (e.g. "vp8" -> "vp8, vp8.0")
   struct CodecsInfo {
     std::string codecs;
+    std::string name;
     bool secure_decoder_supported;
   };
 
@@ -137,6 +138,10 @@
   static bool RegisterMediaCodecBridge(JNIEnv* env);
 
  protected:
+  // Returns true if |mime_type| is known to be unaccelerated (i.e. backed by a
+  // software codec instead of a hardware one).
+  static bool IsKnownUnaccelerated(const std::string& mime_type);
+
   MediaCodecBridge(const std::string& mime, bool is_secure);
 
   // Calls start() against the media codec instance. Used in StartXXX() after
@@ -163,10 +168,13 @@
  public:
   // Returns an AudioCodecBridge instance if |codec| is supported, or a NULL
   // pointer otherwise.
-  static AudioCodecBridge* Create(const AudioCodec codec);
+  static AudioCodecBridge* Create(const AudioCodec& codec);
+
+  // See MediaCodecBridge::IsKnownUnaccelerated().
+  static bool IsKnownUnaccelerated(const AudioCodec& codec);
 
   // Start the audio codec bridge.
-  bool Start(const AudioCodec codec, int sample_rate, int channel_count,
+  bool Start(const AudioCodec& codec, int sample_rate, int channel_count,
              const uint8* extra_data, size_t extra_data_size,
              bool play_audio, jobject media_crypto) WARN_UNUSED_RESULT;
 
@@ -181,7 +189,7 @@
   explicit AudioCodecBridge(const std::string& mime);
 
   // Configure the java MediaFormat object with the extra codec data passed in.
-  bool ConfigureMediaFormat(jobject j_format, const AudioCodec codec,
+  bool ConfigureMediaFormat(jobject j_format, const AudioCodec& codec,
                             const uint8* extra_data, size_t extra_data_size);
 };
 
@@ -189,11 +197,14 @@
  public:
   // Returns an VideoCodecBridge instance if |codec| is supported, or a NULL
   // pointer otherwise.
-  static VideoCodecBridge* Create(const VideoCodec codec, bool is_secure);
+  static VideoCodecBridge* Create(const VideoCodec& codec, bool is_secure);
+
+  // See MediaCodecBridge::IsKnownUnaccelerated().
+  static bool IsKnownUnaccelerated(const VideoCodec& codec);
 
   // Start the video codec bridge.
   // TODO(qinmin): Pass codec specific data if available.
-  bool Start(const VideoCodec codec, const gfx::Size& size, jobject surface,
+  bool Start(const VideoCodec& codec, const gfx::Size& size, jobject surface,
              jobject media_crypto);
 
  private:
diff --git a/media/base/android/media_decoder_job.cc b/media/base/android/media_decoder_job.cc
index 59db63a..cd8d04c 100644
--- a/media/base/android/media_decoder_job.cc
+++ b/media/base/android/media_decoder_job.cc
@@ -28,6 +28,7 @@
       media_codec_bridge_(media_codec_bridge),
       needs_flush_(false),
       input_eos_encountered_(false),
+      prerolling_(true),
       weak_this_(this),
       request_data_cb_(request_data_cb),
       access_unit_index_(0),
@@ -76,7 +77,7 @@
 bool MediaDecoderJob::Decode(
     const base::TimeTicks& start_time_ticks,
     const base::TimeDelta& start_presentation_timestamp,
-    const MediaDecoderJob::DecoderCallback& callback) {
+    const DecoderCallback& callback) {
   DCHECK(decode_cb_.is_null());
   DCHECK(on_data_received_cb_.is_null());
   DCHECK(ui_loop_->BelongsToCurrentThread());
@@ -121,10 +122,22 @@
   on_data_received_cb_.Reset();
 }
 
+void MediaDecoderJob::BeginPrerolling(
+    const base::TimeDelta& preroll_timestamp) {
+  DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
+  DCHECK(ui_loop_->BelongsToCurrentThread());
+  DCHECK(!is_decoding());
+
+  preroll_timestamp_ = preroll_timestamp;
+  prerolling_ = true;
+}
+
 void MediaDecoderJob::Release() {
   DCHECK(ui_loop_->BelongsToCurrentThread());
 
-  destroy_pending_ = is_decoding();
+  // If the decoder job is not waiting for data, and is still decoding, we
+  // cannot delete the job immediately.
+  destroy_pending_ = on_data_received_cb_.is_null() && is_decoding();
 
   request_data_cb_.Reset();
   on_data_received_cb_.Reset();
@@ -221,6 +234,19 @@
   DCHECK(ui_loop_->BelongsToCurrentThread());
   DCHECK(!decode_cb_.is_null());
 
+  // If the first access unit is a config change, request the player to dequeue
+  // the input buffer again so that it can request config data.
+  if (received_data_.access_units[access_unit_index_].status ==
+      DemuxerStream::kConfigChanged) {
+    ui_loop_->PostTask(FROM_HERE,
+                       base::Bind(&MediaDecoderJob::OnDecodeCompleted,
+                                  base::Unretained(this),
+                                  MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER,
+                                  kNoTimestamp(),
+                                  0));
+    return;
+  }
+
   decoder_loop_->PostTask(FROM_HERE, base::Bind(
       &MediaDecoderJob::DecodeInternal, base::Unretained(this),
       received_data_.access_units[access_unit_index_],
@@ -282,11 +308,9 @@
       &output_eos_encountered);
 
   if (status != MEDIA_CODEC_OK) {
-    if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED) {
-        if (media_codec_bridge_->GetOutputBuffers())
-          status = MEDIA_CODEC_OK;
-        else
-          status = MEDIA_CODEC_ERROR;
+    if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED &&
+        !media_codec_bridge_->GetOutputBuffers()) {
+      status = MEDIA_CODEC_ERROR;
     }
     callback.Run(status, kNoTimestamp(), 0);
     return;
@@ -299,9 +323,12 @@
     status = MEDIA_CODEC_INPUT_END_OF_STREAM;
 
   // Check whether we need to render the output.
-  // TODO(qinmin): comparing |unit.timestamp| with |preroll_timestamp_| is not
-  // accurate due to data reordering. Need to use the |presentation_timestamp|
-  // for video, and use |size| to calculate the timestamp for audio.
+  // TODO(qinmin): comparing most recently queued input's |unit.timestamp| with
+  // |preroll_timestamp_| is not accurate due to data reordering and possible
+  // input queueing without immediate dequeue when |input_status| !=
+  // |MEDIA_CODEC_OK|. Need to use the |presentation_timestamp| for video, and
+  // use |size| to calculate the timestamp for audio. See
+  // http://crbug.com/310823 and b/11356652.
   bool render_output  = unit.timestamp >= preroll_timestamp_ &&
       (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
   base::TimeDelta time_to_render;
@@ -350,6 +377,11 @@
   }
 
   DCHECK(!decode_cb_.is_null());
+
+  // If output was queued for rendering, then we have completed prerolling.
+  if (presentation_timestamp != kNoTimestamp())
+    prerolling_ = false;
+
   switch (status) {
     case MEDIA_CODEC_OK:
     case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
diff --git a/media/base/android/media_decoder_job.h b/media/base/android/media_decoder_job.h
index ea3956e..e9530b3 100644
--- a/media/base/android/media_decoder_job.h
+++ b/media/base/android/media_decoder_job.h
@@ -27,6 +27,9 @@
 
   // Callback when a decoder job finishes its work. Args: whether decode
   // finished successfully, presentation time, audio output bytes.
+  // If the presentation time is equal to kNoTimestamp(), the decoder job
+  // skipped rendering of the decoded output and the callback target should
+  // update its clock to avoid introducing extra delays to the next frame.
   typedef base::Callback<void(MediaCodecStatus, const base::TimeDelta&,
                               size_t)> DecoderCallback;
   // Callback when a decoder job finishes releasing the output buffer.
@@ -66,9 +69,10 @@
   // Flush the decoder.
   void Flush();
 
-  void set_preroll_timestamp(const base::TimeDelta& preroll_timestamp) {
-    preroll_timestamp_ = preroll_timestamp;
-  }
+  // Enter prerolling state. The job must not currently be decoding.
+  void BeginPrerolling(const base::TimeDelta& preroll_timestamp);
+
+  bool prerolling() const { return prerolling_; }
 
   bool is_decoding() const { return !decode_cb_.is_null(); }
 
@@ -120,9 +124,8 @@
                       const DecoderCallback& callback);
 
   // Called on the UI thread to indicate that one decode cycle has completed.
-  // If the |presentation_timestamp| is equal to kNoTimestamp(),
-  // the caller should ignore the output of this frame and update its clock to
-  // avoid introducing extra delays to the next frame.
+  // Completes any pending job destruction or any pending decode stop. If
+  // destruction was not pending, passes its arguments to |decode_cb_|.
   void OnDecodeCompleted(MediaCodecStatus status,
                          const base::TimeDelta& presentation_timestamp,
                          size_t audio_output_bytes);
@@ -149,6 +152,13 @@
   // is not very accurate.
   base::TimeDelta preroll_timestamp_;
 
+  // Indicates prerolling state. If true, this job has not yet decoded output
+  // that it will render, since the most recent of job construction or
+  // BeginPrerolling(). If false, |preroll_timestamp_| has been reached.
+  // TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
+  // is not very accurate.
+  bool prerolling_;
+
   // Weak pointer passed to media decoder jobs for callbacks. It is bounded to
   // the decoder thread.
   base::WeakPtrFactory<MediaDecoderJob> weak_this_;
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index 5f992dd..8e23a91 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -79,7 +79,9 @@
       is_video_encrypted_(false),
       volume_(-1.0),
       clock_(&default_tick_clock_),
-      surface_ever_set_(false),
+      next_video_data_is_iframe_(true),
+      doing_browser_seek_(false),
+      pending_seek_(false),
       reconfig_audio_decoder_(false),
       reconfig_video_decoder_(false),
       weak_this_(this),
@@ -108,52 +110,53 @@
   // processed.
   if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING))
     return;
+
+  // Eventual processing of surface change will take care of feeding the new
+  // video decoder initially with I-frame. See b/8950387.
   SetPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
 
-  // Setting a new surface will require a new MediaCodec to be created.
-  // Request a seek so that the new decoder will decode an I-frame first.
-  // Or otherwise, the new MediaCodec might crash. See b/8950387.
-
-  if (!surface_ever_set_) {
-    // Don't work-around to reach I-frame if we never previously set
-    // |surface_|. In this case, we never fed data to decoder, and next data
-    // should begin with I-frame.
-    surface_ever_set_ = true;
-
-    // If seek is already pending, process of the pending surface change
-    // event will occur in OnDemuxerSeekDone(). Otherwise, we need to
-    // trigger pending event processing now.
-    if (!IsEventPending(SEEK_EVENT_PENDING))
-      ProcessPendingEvents();
-
+  // If seek is already pending, processing of the pending surface change
+  // event will occur in OnDemuxerSeekDone().
+  if (IsEventPending(SEEK_EVENT_PENDING))
     return;
-  }
 
-  if (IsEventPending(SEEK_EVENT_PENDING)) {
-    // Waiting for the seek to finish.
+  // If video config change is already pending, processing of the pending
+  // surface change event will occur in OnDemuxerConfigsAvailable().
+  if (reconfig_video_decoder_ && IsEventPending(CONFIG_CHANGE_EVENT_PENDING))
     return;
-  }
 
-  // TODO(wolenetz): We need to either coordinate seek with renderer or
-  // add functionality to know which data contains I-frames and only begin
-  // feeding a new decoder with such frames. The following will likely cause
-  // ChunkDemuxer to fail in renderer because it is not setup to expect seek.
-  ScheduleSeekEventAndStopDecoding();
+  // Otherwise we need to trigger pending event processing now.
+  ProcessPendingEvents();
 }
 
-void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding() {
+void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding(
+    const base::TimeDelta& seek_time) {
+  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ")";
+  DCHECK(!IsEventPending(SEEK_EVENT_PENDING));
+
+  pending_seek_ = false;
+
+  clock_.SetTime(seek_time, seek_time);
+  if (audio_timestamp_helper_)
+    audio_timestamp_helper_->SetBaseTimestamp(seek_time);
+
   if (audio_decoder_job_ && audio_decoder_job_->is_decoding())
     audio_decoder_job_->StopDecode();
   if (video_decoder_job_ && video_decoder_job_->is_decoding())
     video_decoder_job_->StopDecode();
 
-  if (IsEventPending(SEEK_EVENT_PENDING))
-    return;
-
   SetPendingEvent(SEEK_EVENT_PENDING);
   ProcessPendingEvents();
 }
 
+void MediaSourcePlayer::BrowserSeekToCurrentTime() {
+  DVLOG(1) << __FUNCTION__;
+
+  DCHECK(!IsEventPending(SEEK_EVENT_PENDING));
+  doing_browser_seek_ = true;
+  ScheduleSeekEventAndStopDecoding(GetCurrentTime());
+}
+
 bool MediaSourcePlayer::Seekable() {
   // If the duration TimeDelta, converted to milliseconds from microseconds,
   // is >= 2^31, then the media is assumed to be unbounded and unseekable.
@@ -201,10 +204,20 @@
 void MediaSourcePlayer::SeekTo(const base::TimeDelta& timestamp) {
   DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")";
 
-  clock_.SetTime(timestamp, timestamp);
-  if (audio_timestamp_helper_)
-    audio_timestamp_helper_->SetBaseTimestamp(timestamp);
-  ScheduleSeekEventAndStopDecoding();
+  if (IsEventPending(SEEK_EVENT_PENDING)) {
+    DCHECK(doing_browser_seek_) << "SeekTo while SeekTo in progress";
+    DCHECK(!pending_seek_) << "SeekTo while SeekTo pending browser seek";
+
+    // There is a browser seek currently in progress to obtain I-frame to feed
+    // a newly constructed video decoder. Remember this real seek request so
+    // it can be initiated once OnDemuxerSeekDone() occurs for the browser seek.
+    pending_seek_ = true;
+    pending_seek_time_ = timestamp;
+    return;
+  }
+
+  doing_browser_seek_ = false;
+  ScheduleSeekEventAndStopDecoding(timestamp);
 }
 
 base::TimeDelta MediaSourcePlayer::GetCurrentTime() {
@@ -317,13 +330,8 @@
     if (reconfig_audio_decoder_)
       ConfigureAudioDecoderJob();
 
-    // If there is a pending surface change, we can merge it with the config
-    // change.
-    if (reconfig_video_decoder_) {
-      if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING))
-        ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
+    if (reconfig_video_decoder_)
       ConfigureVideoDecoderJob();
-    }
 
     ClearPendingEvent(CONFIG_CHANGE_EVENT_PENDING);
 
@@ -336,10 +344,13 @@
 void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
   DVLOG(1) << __FUNCTION__ << "(" << data.type << ")";
   DCHECK_LT(0u, data.access_units.size());
-  if (data.type == DemuxerStream::AUDIO && audio_decoder_job_)
+  if (data.type == DemuxerStream::AUDIO && audio_decoder_job_) {
     audio_decoder_job_->OnDataReceived(data);
-  else if (data.type == DemuxerStream::VIDEO && video_decoder_job_)
-    video_decoder_job_->OnDataReceived(data);
+  } else if (data.type == DemuxerStream::VIDEO) {
+    next_video_data_is_iframe_ = false;
+    if (video_decoder_job_)
+      video_decoder_job_->OnDataReceived(data);
+  }
 }
 
 void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) {
@@ -384,20 +395,51 @@
     StartInternal();
 }
 
-void MediaSourcePlayer::OnDemuxerSeekDone() {
+void MediaSourcePlayer::OnDemuxerSeekDone(
+    const base::TimeDelta& actual_browser_seek_time) {
   DVLOG(1) << __FUNCTION__;
 
   ClearPendingEvent(SEEK_EVENT_PENDING);
+
+  next_video_data_is_iframe_ = true;
+
+  if (pending_seek_) {
+    DVLOG(1) << __FUNCTION__ << "processing pending seek";
+    DCHECK(doing_browser_seek_);
+    pending_seek_ = false;
+    SeekTo(pending_seek_time_);
+    return;
+  }
+
+  // It is possible that a browser seek to I-frame had to seek to a buffered
+  // I-frame later than the requested one due to data removal or GC. Update
+  // player clock to the actual seek target.
+  if (doing_browser_seek_) {
+    DCHECK(actual_browser_seek_time != kNoTimestamp());
+    // A browser seek must not jump into the past. Ideally, it seeks to the
+    // requested time, but it might jump into the future.
+    DCHECK(actual_browser_seek_time >= GetCurrentTime());
+    DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: "
+             << actual_browser_seek_time.InSecondsF();
+    clock_.SetTime(actual_browser_seek_time, actual_browser_seek_time);
+    if (audio_timestamp_helper_)
+      audio_timestamp_helper_->SetBaseTimestamp(actual_browser_seek_time);
+  }
+
   base::TimeDelta current_time = GetCurrentTime();
-  manager()->OnSeekComplete(player_id(), current_time);
   // TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_|
   // to preroll media decoder jobs. Currently |start_presentation_timestamp_|
   // is calculated from decoder output, while preroll relies on the access
   // unit's timestamp. There are some differences between the two.
+  preroll_timestamp_ = current_time;
   if (audio_decoder_job_)
-    audio_decoder_job_->set_preroll_timestamp(current_time);
+    audio_decoder_job_->BeginPrerolling(preroll_timestamp_);
   if (video_decoder_job_)
-    video_decoder_job_->set_preroll_timestamp(current_time);
+    video_decoder_job_->BeginPrerolling(preroll_timestamp_);
+
+  if (!doing_browser_seek_)
+    manager()->OnSeekComplete(player_id(), current_time);
+
   ProcessPendingEvents();
 }
 
@@ -436,7 +478,7 @@
   if (IsEventPending(SEEK_EVENT_PENDING)) {
     DVLOG(1) << __FUNCTION__ << " : Handling SEEK_EVENT";
     ClearDecodingData();
-    demuxer_->RequestDemuxerSeek(GetCurrentTime());
+    demuxer_->RequestDemuxerSeek(GetCurrentTime(), doing_browser_seek_);
     return;
   }
 
@@ -450,9 +492,15 @@
 
   if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) {
     DVLOG(1) << __FUNCTION__ << " : Handling SURFACE_CHANGE_EVENT.";
+    // Setting a new surface will require a new MediaCodec to be created.
     video_decoder_job_.reset();
     ConfigureVideoDecoderJob();
-    ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
+
+    // Return early if we can't successfully configure a new video decoder job
+    // yet, except continue processing other pending events if |surface_| is
+    // empty.
+    if (!video_decoder_job_ && !surface_.IsEmpty())
+      return;
   }
 
   if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) {
@@ -485,7 +533,6 @@
     bool is_audio, MediaCodecStatus status,
     const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) {
   DVLOG(1) << __FUNCTION__ << ": " << is_audio << ", " << status;
-  DCHECK(!is_waiting_for_key_);
 
   // TODO(xhwang): Drop IntToString() when http://crbug.com/303899 is fixed.
   if (is_audio) {
@@ -599,6 +646,11 @@
   // Failed to start the next decode.
   // Wait for demuxer ready message.
   reconfig_video_decoder_ = true;
+
+  // After this detection of video config change, next video data received
+  // will begin with I-frame.
+  next_video_data_is_iframe_ = true;
+
   SetPendingEvent(CONFIG_CHANGE_EVENT_PENDING);
   ProcessPendingEvents();
 }
@@ -651,6 +703,8 @@
 
   DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding());
 
+  DVLOG(1) << __FUNCTION__ << " : creating new audio decoder job";
+
   audio_decoder_job_.reset(AudioDecoderJob::Create(
       audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0],
       audio_extra_data_.size(), media_crypto.obj(),
@@ -659,6 +713,7 @@
 
   if (audio_decoder_job_) {
     SetVolumeInternal();
+    audio_decoder_job_->BeginPrerolling(preroll_timestamp_);
     reconfig_audio_decoder_ =  false;
   }
 }
@@ -666,19 +721,39 @@
 void MediaSourcePlayer::ConfigureVideoDecoderJob() {
   if (!HasVideo() || surface_.IsEmpty()) {
     video_decoder_job_.reset();
+    if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING))
+      ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
     return;
   }
 
-  // Create video decoder job only if config changes.
+  // Create video decoder job only if config changes or we don't have a job.
   if (video_decoder_job_ && !reconfig_video_decoder_)
     return;
 
+  if (reconfig_video_decoder_) {
+    // No hack browser seek should be required. I-Frame must be next.
+    DCHECK(next_video_data_is_iframe_) << "Received video data between "
+        << "detecting video config change and reconfiguring video decoder";
+  }
+
+  // If uncertain that video I-frame data is next and there is no seek already
+  // in process, request browser demuxer seek so the new decoder will decode
+  // an I-frame first. Otherwise, the new MediaCodec might crash. See b/8950387.
+  // TODO(wolenetz): Instead of doing hack browser seek, replay cached data
+  // since last keyframe. See http://crbug.com/304234.
+  if (!next_video_data_is_iframe_ && !IsEventPending(SEEK_EVENT_PENDING)) {
+    BrowserSeekToCurrentTime();
+    return;
+  }
+
   base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
   if (is_video_encrypted_ && media_crypto.is_null())
     return;
 
   DCHECK(!video_decoder_job_ || !video_decoder_job_->is_decoding());
 
+  DVLOG(1) << __FUNCTION__ << " : creating new video decoder job";
+
   // Release the old VideoDecoderJob first so the surface can get released.
   // Android does not allow 2 MediaCodec instances use the same surface.
   video_decoder_job_.reset();
@@ -693,8 +768,13 @@
                               base::Bind(&DemuxerAndroid::RequestDemuxerData,
                                          base::Unretained(demuxer_.get()),
                                          DemuxerStream::VIDEO)));
-  if (video_decoder_job_)
+  if (video_decoder_job_) {
+    video_decoder_job_->BeginPrerolling(preroll_timestamp_);
     reconfig_video_decoder_ = false;
+  }
+
+  if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING))
+    ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
 
   // Inform the fullscreen view the player is ready.
   // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index 61215b4..3c16689 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -70,7 +70,8 @@
   // DemuxerAndroidClient implementation.
   virtual void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) OVERRIDE;
   virtual void OnDemuxerDataAvailable(const DemuxerData& params) OVERRIDE;
-  virtual void OnDemuxerSeekDone() OVERRIDE;
+  virtual void OnDemuxerSeekDone(
+      const base::TimeDelta& actual_browser_seek_time) OVERRIDE;
   virtual void OnDemuxerDurationChanged(base::TimeDelta duration) OVERRIDE;
 
  private:
@@ -127,8 +128,18 @@
   void StartStarvationCallback(const base::TimeDelta& presentation_timestamp);
 
   // Schedules a seek event in |pending_events_| and calls StopDecode() on all
-  // the MediaDecoderJobs.
-  void ScheduleSeekEventAndStopDecoding();
+  // the MediaDecoderJobs. Sets clock to |seek_time|, and resets
+  // |pending_seek_|. There must not already be a seek event in
+  // |pending_events_|.
+  void ScheduleSeekEventAndStopDecoding(const base::TimeDelta& seek_time);
+
+  // Schedules a browser seek event. We must not currently be processing any
+  // seek. Note that there is possibility that browser seek of renderer demuxer
+  // may unexpectedly stall due to lack of buffered data at or after the browser
+  // seek time.
+  // TODO(wolenetz): Instead of doing hack browser seek, replay cached data
+  // since last keyframe. See http://crbug.com/304234.
+  void BrowserSeekToCurrentTime();
 
   // Helper function to set the volume.
   void SetVolumeInternal();
@@ -197,8 +208,25 @@
   // The surface object currently owned by the player.
   gfx::ScopedJavaSurface surface_;
 
-  // Tracks whether or not the player has previously ever set |surface_|.
-  bool surface_ever_set_;
+  // Track whether or not the player has received any video data since the most
+  // recent of player construction, end of last seek, or receiving and
+  // detecting a |kConfigChanged| access unit from the demuxer.
+  // If no such video data has been received, the next video data begins with
+  // an I-frame. Otherwise, we have no such guarantee.
+  bool next_video_data_is_iframe_;
+
+  // Flag that is true if doing a hack browser seek or false if doing a
+  // regular seek. Only valid when |SEEK_EVENT_PENDING| is pending.
+  // TODO(wolenetz): Instead of doing hack browser seek, replay cached data
+  // since last keyframe. See http://crbug.com/304234.
+  bool doing_browser_seek_;
+
+  // If already doing a browser seek when a regular seek request arrives,
+  // these fields remember the regular seek so OnDemuxerSeekDone() can trigger
+  // it when the browser seek is done. These are only valid when
+  // |SEEK_EVENT_PENDING| is pending.
+  bool pending_seek_;
+  base::TimeDelta pending_seek_time_;
 
   // Decoder jobs.
   scoped_ptr<AudioDecoderJob, MediaDecoderJob::Deleter> audio_decoder_job_;
@@ -207,6 +235,10 @@
   bool reconfig_audio_decoder_;
   bool reconfig_video_decoder_;
 
+  // Track the most recent preroll target. Decoder re-creation needs this to
+  // resume any in-progress preroll.
+  base::TimeDelta preroll_timestamp_;
+
   // A cancelable task that is posted when the audio decoder starts requesting
   // new data. This callback runs if no data arrives before the timeout period
   // elapses.
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 8826848..e329ac6 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -92,23 +92,31 @@
   explicit MockDemuxerAndroid(base::MessageLoop* message_loop)
       : message_loop_(message_loop),
         num_data_requests_(0),
-        num_seek_requests_(0) {}
+        num_seek_requests_(0),
+        num_browser_seek_requests_(0),
+        num_config_requests_(0) {}
   virtual ~MockDemuxerAndroid() {}
 
   virtual void Initialize(DemuxerAndroidClient* client) OVERRIDE {}
-  virtual void RequestDemuxerConfigs() OVERRIDE {}
+  virtual void RequestDemuxerConfigs() OVERRIDE {
+    num_config_requests_++;
+  }
   virtual void RequestDemuxerData(DemuxerStream::Type type) OVERRIDE {
     num_data_requests_++;
     if (message_loop_->is_running())
       message_loop_->Quit();
   }
-  virtual void RequestDemuxerSeek(
-      const base::TimeDelta& time_to_seek) OVERRIDE {
+  virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
+                                  bool is_browser_seek) OVERRIDE {
     num_seek_requests_++;
+    if (is_browser_seek)
+      num_browser_seek_requests_++;
   }
 
   int num_data_requests() const { return num_data_requests_; }
   int num_seek_requests() const { return num_seek_requests_; }
+  int num_browser_seek_requests() const { return num_browser_seek_requests_; }
+  int num_config_requests() const { return num_config_requests_; }
 
  private:
   base::MessageLoop* message_loop_;
@@ -116,9 +124,15 @@
   // The number of encoded data requests this object has seen.
   int num_data_requests_;
 
-  // The number of seek requests this object has seen.
+  // The number of regular and browser seek requests this object has seen.
   int num_seek_requests_;
 
+  // The number of browser seek requests this object has seen.
+  int num_browser_seek_requests_;
+
+  // The number of demuxer config requests this object has seen.
+  int num_config_requests_;
+
   DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid);
 };
 
@@ -127,7 +141,8 @@
   MediaSourcePlayerTest()
       : manager_(&message_loop_),
         demuxer_(new MockDemuxerAndroid(&message_loop_)),
-        player_(0, &manager_, scoped_ptr<DemuxerAndroid>(demuxer_)) {}
+        player_(0, &manager_, scoped_ptr<DemuxerAndroid>(demuxer_)),
+        surface_texture_a_is_next_(true) {}
   virtual ~MediaSourcePlayerTest() {}
 
  protected:
@@ -141,8 +156,18 @@
         player_.video_decoder_job_.get());
   }
 
-  // Starts an audio decoder job.
-  void StartAudioDecoderJob() {
+  // Get the per-job prerolling status from the MediaSourcePlayer's job matching
+  // |is_audio|. Caller must guard against NPE if the player's job is NULL.
+  bool IsPrerolling(bool is_audio) {
+    return GetMediaDecoderJob(is_audio)->prerolling();
+  }
+
+  // Get the preroll timestamp from the MediaSourcePlayer.
+  base::TimeDelta GetPrerollTimestamp() {
+    return player_.preroll_timestamp_;
+  }
+
+  DemuxerConfigs CreateAudioDemuxerConfigs() {
     DemuxerConfigs configs;
     configs.audio_codec = kCodecVorbis;
     configs.audio_channels = 2;
@@ -153,38 +178,67 @@
     configs.audio_extra_data = std::vector<uint8>(
         buffer->data(),
         buffer->data() + buffer->data_size());
-    Start(configs);
+    return configs;
   }
 
-  void StartVideoDecoderJob() {
+  // Starts an audio decoder job.
+  void StartAudioDecoderJob() {
+    Start(CreateAudioDemuxerConfigs());
+  }
+
+  DemuxerConfigs CreateVideoDemuxerConfigs() {
     DemuxerConfigs configs;
     configs.video_codec = kCodecVP8;
     configs.video_size = gfx::Size(320, 240);
     configs.is_video_encrypted = false;
     configs.duration_ms = kDefaultDurationInMs;
-    Start(configs);
+    return configs;
+  }
+
+  DemuxerConfigs CreateAudioVideoDemuxerConfigs() {
+    DemuxerConfigs configs = CreateAudioDemuxerConfigs();
+    configs.video_codec = kCodecVP8;
+    configs.video_size = gfx::Size(320, 240);
+    configs.is_video_encrypted = false;
+    return configs;
+  }
+
+  void StartVideoDecoderJob() {
+    Start(CreateVideoDemuxerConfigs());
   }
 
   // Starts decoding the data.
   void Start(const DemuxerConfigs& configs) {
     player_.OnDemuxerConfigsAvailable(configs);
     player_.Start();
+    EXPECT_TRUE(player_.IsPlaying());
+  }
+
+  AccessUnit CreateAccessUnitWithData(bool is_audio, int audio_packet_id) {
+    AccessUnit unit;
+
+    unit.status = DemuxerStream::kOk;
+    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(
+        is_audio ? base::StringPrintf("vorbis-packet-%d", audio_packet_id)
+            : "vp8-I-frame-320x240");
+    unit.data = std::vector<uint8>(
+        buffer->data(), buffer->data() + buffer->data_size());
+
+    if (is_audio) {
+      // Vorbis needs 4 extra bytes padding on Android to decode properly. Check
+      // NuMediaExtractor.cpp in Android source code.
+      uint8 padding[4] = { 0xff , 0xff , 0xff , 0xff };
+      unit.data.insert(unit.data.end(), padding, padding + 4);
+    }
+
+    return unit;
   }
 
   DemuxerData CreateReadFromDemuxerAckForAudio(int packet_id) {
     DemuxerData data;
     data.type = DemuxerStream::AUDIO;
     data.access_units.resize(1);
-    data.access_units[0].status = DemuxerStream::kOk;
-    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(
-        base::StringPrintf("vorbis-packet-%d", packet_id));
-    data.access_units[0].data = std::vector<uint8>(
-        buffer->data(), buffer->data() + buffer->data_size());
-    // Vorbis needs 4 extra bytes padding on Android to decode properly. Check
-    // NuMediaExtractor.cpp in Android source code.
-    uint8 padding[4] = { 0xff , 0xff , 0xff , 0xff };
-    data.access_units[0].data.insert(
-        data.access_units[0].data.end(), padding, padding + 4);
+    data.access_units[0] = CreateAccessUnitWithData(true, packet_id);
     return data;
   }
 
@@ -192,23 +246,216 @@
     DemuxerData data;
     data.type = DemuxerStream::VIDEO;
     data.access_units.resize(1);
-    data.access_units[0].status = DemuxerStream::kOk;
-    scoped_refptr<DecoderBuffer> buffer =
-        ReadTestDataFile("vp8-I-frame-320x240");
-    data.access_units[0].data = std::vector<uint8>(
-        buffer->data(), buffer->data() + buffer->data_size());
+    data.access_units[0] = CreateAccessUnitWithData(false, 0);
     return data;
   }
 
   DemuxerData CreateEOSAck(bool is_audio) {
-      DemuxerData data;
-      data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
-      data.access_units.resize(1);
-      data.access_units[0].status = DemuxerStream::kOk;
-      data.access_units[0].end_of_stream = true;
-      return data;
+    DemuxerData data;
+    data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
+    data.access_units.resize(1);
+    data.access_units[0].status = DemuxerStream::kOk;
+    data.access_units[0].end_of_stream = true;
+    return data;
+  }
+
+  DemuxerData CreateAbortedAck(bool is_audio) {
+    DemuxerData data;
+    data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
+    data.access_units.resize(1);
+    data.access_units[0].status = DemuxerStream::kAborted;
+    return data;
+  }
+
+  // Seek, including simulated receipt of |kAborted| read between SeekTo()
+  // and OnDemuxerSeekDone(). Use this helper method only when the player
+  // already has created the decoder job.
+  void SeekPlayer(bool is_audio, const base::TimeDelta& seek_time) {
+    EXPECT_TRUE(GetMediaDecoderJob(is_audio));
+
+    int original_num_seeks = demuxer_->num_seek_requests();
+    int original_num_data_requests = demuxer_->num_data_requests();
+
+    // Initiate a seek. Skip the round-trip of requesting seek from renderer.
+    // Instead behave as if the renderer has asked us to seek.
+    player_.SeekTo(seek_time);
+
+    // Verify that the seek does not occur until previously outstanding data
+    // request is satisfied.
+    EXPECT_EQ(original_num_seeks, demuxer_->num_seek_requests());
+
+    // Simulate seeking causes the demuxer to abort the outstanding read caused
+    // by the seek.
+    player_.OnDemuxerDataAvailable(CreateAbortedAck(is_audio));
+
+    // Verify that the seek is requested now that the outstanding read is
+    // completed by aborted access unit.
+    EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
+
+    // Send back the seek done notification. This should trigger the player to
+    // call OnReadFromDemuxer() again.
+    EXPECT_EQ(original_num_data_requests, demuxer_->num_data_requests());
+    player_.OnDemuxerSeekDone(kNoTimestamp());
+    EXPECT_EQ(original_num_data_requests + 1, demuxer_->num_data_requests());
+
+    // No other seek should have been requested.
+    EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
+  }
+
+  DemuxerData CreateReadFromDemuxerAckWithConfigChanged(bool is_audio,
+                                                        int config_unit_index) {
+    DemuxerData data;
+    data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
+    data.access_units.resize(config_unit_index + 1);
+
+    for (int i = 0; i < config_unit_index; ++i)
+      data.access_units[i] = CreateAccessUnitWithData(is_audio, i);
+
+    data.access_units[config_unit_index].status = DemuxerStream::kConfigChanged;
+    return data;
+  }
+
+  // Valid only for video-only player tests. If |trigger_with_release_start| is
+  // true, triggers the browser seek with a Release() + video data received +
+  // Start() with a new surface. If false, triggers the browser seek by
+  // setting a new video surface after beginning decode of received video data.
+  // Such data receipt causes possibility that an I-frame is not next, and
+  // browser seek results once decode completes and surface change processing
+  // begins.
+  void BrowserSeekPlayer(bool trigger_with_release_start) {
+    int expected_num_data_requests = demuxer_->num_data_requests();
+    int expected_num_seek_requests = demuxer_->num_seek_requests();
+    int expected_num_browser_seek_requests =
+        demuxer_->num_browser_seek_requests();
+
+    EXPECT_FALSE(GetMediaDecoderJob(false));
+    CreateNextTextureAndSetVideoSurface();
+    StartVideoDecoderJob();
+    EXPECT_TRUE(GetMediaDecoderJob(false));
+    expected_num_data_requests++;
+    EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
+
+    if (trigger_with_release_start) {
+      player_.Release();
+
+      // Simulate demuxer's response to the video data request.
+      player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+      EXPECT_FALSE(GetMediaDecoderJob(false));
+      EXPECT_FALSE(player_.IsPlaying());
+      EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
+      EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
+
+      CreateNextTextureAndSetVideoSurface();
+      player_.Start();
+    } else {
+      // Simulate demuxer's response to the video data request.
+      player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+
+      // While the decoder is decoding, trigger a browser seek by changing
+      // surface. Demuxer does not know of browser seek in advance, so no
+      // |kAborted| data is required (though |kAborted| can certainly occur for
+      // any pending read in reality due to renderer preparing for a regular
+      // seek).
+      CreateNextTextureAndSetVideoSurface();
+
+      // Browser seek should not begin until decoding has completed.
+      EXPECT_TRUE(GetMediaDecoderJob(false));
+      EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
+      EXPECT_EQ(expected_num_browser_seek_requests,
+                demuxer_->num_browser_seek_requests());
+
+      // Wait for the decoder job to finish decoding and be reset pending the
+      // browser seek.
+      while (GetMediaDecoderJob(false) &&
+          GetMediaDecoderJob(false)->is_decoding()) {
+        message_loop_.RunUntilIdle();
+      }
     }
 
+    EXPECT_FALSE(GetMediaDecoderJob(false));
+    EXPECT_TRUE(player_.IsPlaying());
+
+    // Only one browser seek should have been initiated, and no further data
+    // should have been requested.
+    expected_num_seek_requests++;
+    expected_num_browser_seek_requests++;
+    EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
+    EXPECT_EQ(expected_num_browser_seek_requests,
+              demuxer_->num_browser_seek_requests());
+    EXPECT_EQ(expected_num_data_requests, demuxer_->num_seek_requests());
+  }
+
+  // Creates a new decoder job and feeds it data ending with a |kConfigChanged|
+  // access unit. If |config_unit_in_prefetch| is true, sends feeds the config
+  // change AU in response to the job's first read request (prefetch). If
+  // false, regular data is fed and decoded prior to feeding the config change
+  // AU in response to the second data request (after prefetch completed).
+  // |config_unit_index| controls which access unit is |kConfigChanged|.
+  void StartConfigChange(bool is_audio,
+                         bool config_unit_in_prefetch,
+                         int config_unit_index) {
+    int expected_num_data_requests = demuxer_->num_data_requests();
+    int expected_num_config_requests = demuxer_->num_config_requests();
+
+    EXPECT_FALSE(GetMediaDecoderJob(is_audio));
+    if (is_audio) {
+      StartAudioDecoderJob();
+    } else {
+      CreateNextTextureAndSetVideoSurface();
+      StartVideoDecoderJob();
+    }
+    EXPECT_TRUE(GetMediaDecoderJob(is_audio));
+    expected_num_data_requests++;
+    EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
+    EXPECT_EQ(expected_num_config_requests, demuxer_->num_config_requests());
+
+    // Feed and decode a standalone access unit so the player exits prefetch.
+    if (!config_unit_in_prefetch) {
+      if (is_audio)
+        player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
+      else
+        player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+
+      message_loop_.Run();
+
+      // We should have completed the prefetch phase at this point.
+      EXPECT_TRUE(GetMediaDecoderJob(is_audio));
+      expected_num_data_requests++;
+      EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
+      EXPECT_EQ(expected_num_config_requests, demuxer_->num_config_requests());
+    }
+
+    // Feed and decode access units with data for any units prior to
+    // |config_unit_index|, and a |kConfigChanged| unit at that index.
+    // Player should prepare to reconfigure the decoder job, and should request
+    // new demuxer configs.
+    player_.OnDemuxerDataAvailable(
+        CreateReadFromDemuxerAckWithConfigChanged(is_audio, config_unit_index));
+    while (GetMediaDecoderJob(is_audio)->is_decoding())
+      message_loop_.RunUntilIdle();
+
+    expected_num_config_requests++;
+    EXPECT_TRUE(player_.IsPlaying());
+    EXPECT_TRUE(GetMediaDecoderJob(is_audio));
+    EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
+    EXPECT_EQ(expected_num_config_requests, demuxer_->num_config_requests());
+  }
+
+  void CreateNextTextureAndSetVideoSurface() {
+    gfx::SurfaceTexture* surface_texture;
+    if (surface_texture_a_is_next_) {
+      surface_texture_a_ = new gfx::SurfaceTexture(next_texture_id_++);
+      surface_texture = surface_texture_a_.get();
+    } else {
+      surface_texture_b_ = new gfx::SurfaceTexture(next_texture_id_++);
+      surface_texture = surface_texture_b_.get();
+    }
+
+    surface_texture_a_is_next_ = !surface_texture_a_is_next_;
+    gfx::ScopedJavaSurface surface = gfx::ScopedJavaSurface(surface_texture);
+    player_.SetVideoSurface(surface.Pass());
+  }
+
   base::TimeTicks StartTimeTicks() {
     return player_.start_time_ticks_;
   }
@@ -221,23 +468,23 @@
         scheme_uuid, security_level, container, codecs);
   }
 
-  void CreateAndSetVideoSurface() {
-    surface_texture_ = new gfx::SurfaceTexture(0);
-    gfx::ScopedJavaSurface surface = gfx::ScopedJavaSurface(
-        surface_texture_.get());
-    player_.SetVideoSurface(surface.Pass());
-  }
-
  protected:
   base::MessageLoop message_loop_;
   MockMediaPlayerManager manager_;
   MockDemuxerAndroid* demuxer_;  // Owned by |player_|.
   MediaSourcePlayer player_;
+
   // We need to keep the surface texture while the decoder is actively decoding.
   // Otherwise, it may trigger unexpected crashes on some devices. To switch
-  // surfaces, tests need to create their own surface texture without releasing
-  // this one if they previously called CreateAndSetVideoSurface().
-  scoped_refptr<gfx::SurfaceTexture> surface_texture_;
+  // surfaces, tests need to create a new surface texture without releasing
+  // their previous one. In CreateNextTextureAndSetVideoSurface(), we toggle
+  // between two surface textures, only replacing the N-2 texture. Assumption is
+  // that no more than N-1 texture is in use by decoder when
+  // CreateNextTextureAndSetVideoSurface() is called.
+  scoped_refptr<gfx::SurfaceTexture> surface_texture_a_;
+  scoped_refptr<gfx::SurfaceTexture> surface_texture_b_;
+  bool surface_texture_a_is_next_;
+  int next_texture_id_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerTest);
 };
@@ -249,24 +496,23 @@
   StartAudioDecoderJob();
   EXPECT_TRUE(GetMediaDecoderJob(true));
   EXPECT_EQ(1, demuxer_->num_data_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithInvalidConfig) {
   SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
   // Test audio decoder job will not be created when failed to start the codec.
-  DemuxerConfigs configs;
-  configs.audio_codec = kCodecVorbis;
-  configs.audio_channels = 2;
-  configs.audio_sampling_rate = 44100;
-  configs.is_audio_encrypted = false;
-  configs.duration_ms = kDefaultDurationInMs;
+  DemuxerConfigs configs = CreateAudioDemuxerConfigs();
+  // Replace with invalid |audio_extra_data|
+  configs.audio_extra_data.clear();
   uint8 invalid_codec_data[] = { 0x00, 0xff, 0xff, 0xff, 0xff };
   configs.audio_extra_data.insert(configs.audio_extra_data.begin(),
                                  invalid_codec_data, invalid_codec_data + 4);
   Start(configs);
-  EXPECT_EQ(NULL, GetMediaDecoderJob(true));
+  EXPECT_FALSE(GetMediaDecoderJob(true));
   EXPECT_EQ(0, demuxer_->num_data_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, StartVideoCodecWithValidSurface) {
@@ -275,17 +521,27 @@
   // Test video decoder job will be created when surface is valid.
   StartVideoDecoderJob();
   // Video decoder job will not be created until surface is available.
-  EXPECT_EQ(NULL, GetMediaDecoderJob(false));
+  EXPECT_FALSE(GetMediaDecoderJob(false));
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
-  CreateAndSetVideoSurface();
+  // Set both an initial and a later video surface without receiving any
+  // demuxed data yet.
+  CreateNextTextureAndSetVideoSurface();
+  MediaDecoderJob* first_job = GetMediaDecoderJob(false);
+  EXPECT_TRUE(first_job);
+  CreateNextTextureAndSetVideoSurface();
 
-  // Player should not seek the demuxer on setting initial surface.
+  // Setting another surface will not create a new job until any pending
+  // read is satisfied (and job is no longer decoding).
+  EXPECT_EQ(first_job, GetMediaDecoderJob(false));
+
+  // No seeks, even on setting surface, should have occurred. (Browser seeks can
+  // occur on setting surface, but only after previously receiving video data.)
   EXPECT_EQ(0, demuxer_->num_seek_requests());
 
-  // The decoder job should be ready now.
-  EXPECT_TRUE(GetMediaDecoderJob(false));
-  EXPECT_EQ(1, demuxer_->num_data_requests());
+  // Note, the decoder job for the second surface set, above, will be created
+  // only after the pending read is satisfied and decoded, and the resulting
+  // browser seek is done. See BrowserSeek_* tests for this coverage.
 }
 
 TEST_F(MediaSourcePlayerTest, StartVideoCodecWithInvalidSurface) {
@@ -297,7 +553,7 @@
   gfx::ScopedJavaSurface surface(surface_texture.get());
   StartVideoDecoderJob();
   // Video decoder job will not be created until surface is available.
-  EXPECT_EQ(NULL, GetMediaDecoderJob(false));
+  EXPECT_FALSE(GetMediaDecoderJob(false));
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
   // Release the surface texture.
@@ -307,7 +563,7 @@
   // Player should not seek the demuxer on setting initial surface.
   EXPECT_EQ(0, demuxer_->num_seek_requests());
 
-  EXPECT_EQ(NULL, GetMediaDecoderJob(false));
+  EXPECT_FALSE(GetMediaDecoderJob(false));
   EXPECT_EQ(0, demuxer_->num_data_requests());
 }
 
@@ -318,34 +574,8 @@
   StartAudioDecoderJob();
   EXPECT_TRUE(GetMediaDecoderJob(true));
   EXPECT_EQ(1, demuxer_->num_data_requests());
-
-  // Initiate a seek. Skip the round-trip of requesting seek from renderer.
-  // Instead behave as if the renderer has asked us to seek.
-  player_.SeekTo(base::TimeDelta());
-
-  // Verify that the seek does not occur until the initial prefetch
-  // completes.
-  EXPECT_EQ(0, demuxer_->num_seek_requests());
-
-  // Simulate aborted read caused by the seek. This aborts the initial
-  // prefetch.
-  DemuxerData data;
-  data.type = DemuxerStream::AUDIO;
-  data.access_units.resize(1);
-  data.access_units[0].status = DemuxerStream::kAborted;
-  player_.OnDemuxerDataAvailable(data);
-
-  // Verify that the seek is requested now that the initial prefetch
-  // has completed.
-  EXPECT_EQ(1, demuxer_->num_seek_requests());
-
-  // Sending back the seek done notification. This should trigger the player to
-  // call OnReadFromDemuxer() again.
-  player_.OnDemuxerSeekDone();
+  SeekPlayer(true, base::TimeDelta());
   EXPECT_EQ(2, demuxer_->num_data_requests());
-
-  // Reconfirm exactly 1 seek request has been made of demuxer.
-  EXPECT_EQ(1, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, SetSurfaceWhileSeeking) {
@@ -357,35 +587,39 @@
   // Player is still waiting for SetVideoSurface(), so no request is sent.
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
-  // Initiate a seek. Skip the round-trip of requesting seek from renderer.
+  // Initiate a seek. Skip requesting element seek of renderer.
   // Instead behave as if the renderer has asked us to seek.
   EXPECT_EQ(0, demuxer_->num_seek_requests());
   player_.SeekTo(base::TimeDelta());
   EXPECT_EQ(1, demuxer_->num_seek_requests());
 
-  CreateAndSetVideoSurface();
-  EXPECT_TRUE(NULL == GetMediaDecoderJob(false));
+  CreateNextTextureAndSetVideoSurface();
+  EXPECT_FALSE(GetMediaDecoderJob(false));
   EXPECT_EQ(1, demuxer_->num_seek_requests());
 
   // Reconfirm player has not yet requested data.
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
   // Send the seek done notification. The player should start requesting data.
-  player_.OnDemuxerSeekDone();
+  player_.OnDemuxerSeekDone(kNoTimestamp());
   EXPECT_TRUE(GetMediaDecoderJob(false));
   EXPECT_EQ(1, demuxer_->num_data_requests());
 
-  // Reconfirm exactly 1 seek request has been made of demuxer.
+  // Reconfirm exactly 1 seek request has been made of demuxer, and that it
+  // was not a browser seek request.
   EXPECT_EQ(1, demuxer_->num_seek_requests());
+  EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, ChangeMultipleSurfaceWhileDecoding) {
   SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
   // Test MediaSourcePlayer can switch multiple surfaces during decoding.
-  CreateAndSetVideoSurface();
+  CreateNextTextureAndSetVideoSurface();
   StartVideoDecoderJob();
   EXPECT_EQ(1, demuxer_->num_data_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
 
   // Send the first input chunk.
   player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
@@ -394,47 +628,49 @@
   // surface first.
   gfx::ScopedJavaSurface empty_surface;
   player_.SetVideoSurface(empty_surface.Pass());
-  // Pass a new non-empty surface, don't call CreateAndSetVideoSurface() as
-  // it will release the old surface_texture_ and might cause unexpected
-  // behaviors on some devices.
-  scoped_refptr<gfx::SurfaceTexture> surface_texture(
-      new gfx::SurfaceTexture(1));
-  gfx::ScopedJavaSurface surface(surface_texture.get());
-  player_.SetVideoSurface(surface.Pass());
+  // Next, pass a new non-empty surface.
+  CreateNextTextureAndSetVideoSurface();
 
-  // Wait for the decoder job to finish decoding.
-  while(GetMediaDecoderJob(false)->is_decoding())
+  // Wait for the decoder job to finish decoding and be reset pending a browser
+  // seek.
+  while (GetMediaDecoderJob(false) && GetMediaDecoderJob(false)->is_decoding())
     message_loop_.RunUntilIdle();
-  // A seek should be initiated to request Iframe.
-  EXPECT_EQ(1, demuxer_->num_seek_requests());
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+
+  // Only one browser seek should have been initiated. No further data request
+  // should have been processed on |message_loop_| before surface change event
+  // became pending, above.
+  EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
   EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // Simulate browser seek is done and confirm player requests more data for new
+  // video decoder job.
+  player_.OnDemuxerSeekDone(player_.GetCurrentTime());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
 }
 
-TEST_F(MediaSourcePlayerTest, StartAfterSeekFinish) {
+TEST_F(MediaSourcePlayerTest, AudioOnlyStartAfterSeekFinish) {
   SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
-  // Test decoder job will not start until all pending seek event is handled.
-  DemuxerConfigs configs;
-  configs.audio_codec = kCodecVorbis;
-  configs.audio_channels = 2;
-  configs.audio_sampling_rate = 44100;
-  configs.is_audio_encrypted = false;
-  configs.duration_ms = kDefaultDurationInMs;
+  // Test audio decoder job will not start until pending seek event is handled.
+  DemuxerConfigs configs = CreateAudioDemuxerConfigs();
   player_.OnDemuxerConfigsAvailable(configs);
-  EXPECT_EQ(NULL, GetMediaDecoderJob(true));
+  EXPECT_FALSE(GetMediaDecoderJob(true));
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
-  // Initiate a seek. Skip the round-trip of requesting seek from renderer.
+  // Initiate a seek. Skip requesting element seek of renderer.
   // Instead behave as if the renderer has asked us to seek.
   player_.SeekTo(base::TimeDelta());
   EXPECT_EQ(1, demuxer_->num_seek_requests());
 
   player_.Start();
-  EXPECT_EQ(NULL, GetMediaDecoderJob(true));
+  EXPECT_FALSE(GetMediaDecoderJob(true));
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
   // Sending back the seek done notification.
-  player_.OnDemuxerSeekDone();
+  player_.OnDemuxerSeekDone(kNoTimestamp());
   EXPECT_TRUE(GetMediaDecoderJob(true));
   EXPECT_EQ(1, demuxer_->num_data_requests());
 
@@ -442,6 +678,33 @@
   EXPECT_EQ(1, demuxer_->num_seek_requests());
 }
 
+TEST_F(MediaSourcePlayerTest, VideoOnlyStartAfterSeekFinish) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test video decoder job will not start until pending seek event is handled.
+  CreateNextTextureAndSetVideoSurface();
+  DemuxerConfigs configs = CreateVideoDemuxerConfigs();
+  player_.OnDemuxerConfigsAvailable(configs);
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+
+  // Initiate a seek. Skip requesting element seek of renderer.
+  // Instead behave as if the renderer has asked us to seek.
+  player_.SeekTo(base::TimeDelta());
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
+
+  player_.Start();
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+  EXPECT_EQ(0, demuxer_->num_data_requests());
+
+  // Sending back the seek done notification.
+  player_.OnDemuxerSeekDone(kNoTimestamp());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // Reconfirm exactly 1 seek request has been made of demuxer.
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
+}
+
 TEST_F(MediaSourcePlayerTest, StartImmediatelyAfterPause) {
   SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
@@ -480,23 +743,11 @@
 
   // Test that when Start() is called, video decoder jobs will wait for audio
   // decoder job before start decoding the data.
-  DemuxerConfigs configs;
-  configs.audio_codec = kCodecVorbis;
-  configs.audio_channels = 2;
-  configs.audio_sampling_rate = 44100;
-  configs.is_audio_encrypted = false;
-  scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-extradata");
-  configs.audio_extra_data = std::vector<uint8>(
-      buffer->data(),
-      buffer->data() + buffer->data_size());
-  configs.video_codec = kCodecVP8;
-  configs.video_size = gfx::Size(320, 240);
-  configs.is_video_encrypted = false;
-  configs.duration_ms = kDefaultDurationInMs;
+  DemuxerConfigs configs = CreateAudioVideoDemuxerConfigs();
   Start(configs);
   EXPECT_EQ(0, demuxer_->num_data_requests());
 
-  CreateAndSetVideoSurface();
+  CreateNextTextureAndSetVideoSurface();
 
   // Player should not seek the demuxer on setting initial surface.
   EXPECT_EQ(0, demuxer_->num_seek_requests());
@@ -515,6 +766,9 @@
   player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
   EXPECT_TRUE(audio_decoder_job->is_decoding());
   EXPECT_TRUE(video_decoder_job->is_decoding());
+
+  // Reconfirm no seek occurred.
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
@@ -548,7 +802,7 @@
   // Send new data to the decoder so it can finish the currently
   // pending decode.
   player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(3));
-  while(GetMediaDecoderJob(true)->is_decoding())
+  while (GetMediaDecoderJob(true)->is_decoding())
     message_loop_.RunUntilIdle();
 
   // Verify the start time ticks is cleared at this point because the
@@ -569,7 +823,7 @@
 
   // Test MediaSourcePlayer will not request for new data after input EOS is
   // reached.
-  CreateAndSetVideoSurface();
+  CreateNextTextureAndSetVideoSurface();
   StartVideoDecoderJob();
   // Player should not seek the demuxer on setting initial surface.
   EXPECT_EQ(0, demuxer_->num_seek_requests());
@@ -585,6 +839,9 @@
   message_loop_.Run();
   // No more request for data should be made.
   EXPECT_EQ(2, demuxer_->num_data_requests());
+
+  // Reconfirm no seek request has occurred.
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, ReplayAfterInputEOS) {
@@ -592,7 +849,7 @@
 
   // Test MediaSourcePlayer can replay after input EOS is
   // reached.
-  CreateAndSetVideoSurface();
+  CreateNextTextureAndSetVideoSurface();
   StartVideoDecoderJob();
 
   // Player should not seek the demuxer on setting initial surface.
@@ -610,37 +867,40 @@
   // No more request for data should be made.
   EXPECT_EQ(2, demuxer_->num_data_requests());
 
-  // Initiate a seek. Skip the round-trip of requesting seek from renderer.
+  // Initiate a seek. Skip requesting element seek of renderer.
   // Instead behave as if the renderer has asked us to seek.
   player_.SeekTo(base::TimeDelta());
   StartVideoDecoderJob();
   EXPECT_EQ(1, demuxer_->num_seek_requests());
-  player_.OnDemuxerSeekDone();
+  player_.OnDemuxerSeekDone(kNoTimestamp());
   // Seek/Play after EOS should request more data.
   EXPECT_EQ(3, demuxer_->num_data_requests());
+
+  // Reconfirm only 1 seek request has occurred.
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, NoRequestForDataAfterAbort) {
   SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
-  // Test that the decoder will request new data after receiving an aborted
+  // Test that the decoder will not request new data after receiving an aborted
   // access unit.
   StartAudioDecoderJob();
   EXPECT_EQ(1, demuxer_->num_data_requests());
 
   // Send an aborted access unit.
-  DemuxerData data;
-  data.type = DemuxerStream::AUDIO;
-  data.access_units.resize(1);
-  data.access_units[0].status = DemuxerStream::kAborted;
-  player_.OnDemuxerDataAvailable(data);
+  player_.OnDemuxerDataAvailable(CreateAbortedAck(true));
+
   EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
   // Wait for the decoder job to finish decoding.
-  while(GetMediaDecoderJob(true)->is_decoding())
+  while (GetMediaDecoderJob(true)->is_decoding())
     message_loop_.RunUntilIdle();
 
   // No request will be sent for new data.
   EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // No seek requests should have occurred.
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 TEST_F(MediaSourcePlayerTest, DemuxerDataArrivesAfterRelease) {
@@ -649,7 +909,6 @@
   // Test that the decoder should not crash if demuxer data arrives after
   // Release().
   StartAudioDecoderJob();
-  EXPECT_TRUE(player_.IsPlaying());
   EXPECT_EQ(1, demuxer_->num_data_requests());
   EXPECT_TRUE(GetMediaDecoderJob(true));
 
@@ -659,37 +918,243 @@
   // The decoder job should have been released.
   EXPECT_FALSE(player_.IsPlaying());
   EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // No seek requests should have occurred.
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
-TEST_F(MediaSourcePlayerTest, PrerollAfterSeek) {
-  if (!MediaCodecBridge::IsAvailable()) {
-    LOG(INFO) << "Could not run test - not supported on device.";
-    return;
-  }
+TEST_F(MediaSourcePlayerTest, BrowserSeek_RegularSeekPendsBrowserSeekDone) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that a browser seek, once started, delays a newly arrived regular
+  // SeekTo() request's demuxer seek until the browser seek is done.
+  BrowserSeekPlayer(false);
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // Simulate renderer requesting a regular seek while browser seek in progress.
+  player_.SeekTo(base::TimeDelta());
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+
+  // Simulate browser seek is done. Confirm player requests the regular seek,
+  // still has no video decoder job configured, and has not requested any
+  // further data since the surface change event became pending in
+  // BrowserSeekPlayer().
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
+  player_.OnDemuxerSeekDone(base::TimeDelta());
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+  EXPECT_EQ(2, demuxer_->num_seek_requests());
+  EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // Simulate regular seek is done and confirm player requests more data for
+  // new video decoder job.
+  player_.OnDemuxerSeekDone(kNoTimestamp());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  EXPECT_EQ(2, demuxer_->num_seek_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, NoSeekForInitialReleaseAndStart) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that no seek is requested if player Release() + Start() occurs prior
+  // to receiving any data.
+  CreateNextTextureAndSetVideoSurface();
+  StartVideoDecoderJob();
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+
+  player_.Release();
+  EXPECT_FALSE(player_.IsPlaying());
+
+  // Pass a new non-empty surface.
+  CreateNextTextureAndSetVideoSurface();
+
+  player_.Start();
+
+  // TODO(wolenetz/qinmin): Multiple in-flight data requests for same stream
+  // should be prevented. See http://crbug.com/306314.
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+}
+
+TEST_F(MediaSourcePlayerTest, BrowserSeek_MidStreamReleaseAndStart) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that one browser seek is requested if player Release() + Start(), with
+  // video data received between Release() and Start().
+  BrowserSeekPlayer(true);
+  EXPECT_FALSE(GetMediaDecoderJob(false));
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  // Simulate browser seek is done and confirm player requests more data.
+  player_.OnDemuxerSeekDone(base::TimeDelta());
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, PrerollAudioAfterSeek) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
 
   // Test decoder job will preroll the media to the seek position.
   StartAudioDecoderJob();
   EXPECT_TRUE(GetMediaDecoderJob(true));
   EXPECT_EQ(1, demuxer_->num_data_requests());
 
-  // Initiate a seek to 100 ms. This will abort the intial prefetch.
-  player_.SeekTo(base::TimeDelta::FromMilliseconds(100));
-  DemuxerData data;
-  data.type = DemuxerStream::AUDIO;
-  data.access_units.resize(1);
-  data.access_units[0].status = DemuxerStream::kAborted;
-  player_.OnDemuxerDataAvailable(data);
-  EXPECT_EQ(1, demuxer_->num_seek_requests());
-  player_.OnDemuxerSeekDone();
-  EXPECT_EQ(2, demuxer_->num_data_requests());
+  SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(IsPrerolling(true));
+  EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
 
-  // Send some data with before the seek position.
+  // Send some data before the seek position.
   for (int i = 1; i < 4; ++i) {
     player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(i));
     EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
     message_loop_.Run();
   }
   EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_TRUE(IsPrerolling(true));
+
+  // Send data after the seek position.
+  DemuxerData data = CreateReadFromDemuxerAckForAudio(3);
+  data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(100);
+  player_.OnDemuxerDataAvailable(data);
+  message_loop_.Run();
+  EXPECT_LT(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_FALSE(IsPrerolling(true));
+}
+
+TEST_F(MediaSourcePlayerTest, PrerollVideoAfterSeek) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test decoder job will preroll the media to the seek position.
+  CreateNextTextureAndSetVideoSurface();
+  StartVideoDecoderJob();
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  SeekPlayer(false, base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(IsPrerolling(false));
+  EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
+
+  // Send some data before the seek position.
+  DemuxerData data;
+  for (int i = 1; i < 4; ++i) {
+    data = CreateReadFromDemuxerAckForVideo();
+    data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(i * 30);
+    player_.OnDemuxerDataAvailable(data);
+    EXPECT_TRUE(GetMediaDecoderJob(false)->is_decoding());
+    message_loop_.Run();
+  }
+  EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_TRUE(IsPrerolling(false));
+
+  // Send data at the seek position.
+  data = CreateReadFromDemuxerAckForVideo();
+  data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(100);
+  player_.OnDemuxerDataAvailable(data);
+  message_loop_.Run();
+
+  // TODO(wolenetz/qinmin): Player's maintenance of current time for video-only
+  // streams depends on decoder output, which may be initially inaccurate, and
+  // encoded video test data may also need updating. Verify at least that AU
+  // timestamp-based preroll logic has determined video preroll has completed.
+  EXPECT_FALSE(IsPrerolling(false));
+}
+
+TEST_F(MediaSourcePlayerTest, SeekingAfterCompletingPrerollRestartsPreroll) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test decoder job will begin prerolling upon seek, when it was not
+  // prerolling prior to the seek.
+  StartAudioDecoderJob();
+  MediaDecoderJob* decoder_job = GetMediaDecoderJob(true);
+  EXPECT_TRUE(decoder_job);
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+  EXPECT_TRUE(IsPrerolling(true));
+
+  // Complete the initial preroll by feeding data to the decoder.
+  for (int i = 0; i < 4; ++i) {
+    player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(i));
+    EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+    message_loop_.Run();
+  }
+  EXPECT_LT(0.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_FALSE(IsPrerolling(true));
+
+  SeekPlayer(true, base::TimeDelta::FromMilliseconds(500));
+
+  // Prerolling should have begun again.
+  EXPECT_TRUE(IsPrerolling(true));
+  EXPECT_EQ(500.0, GetPrerollTimestamp().InMillisecondsF());
+
+  // Send data at and after the seek position. Prerolling should complete.
+  for (int i = 0; i < 4; ++i) {
+    DemuxerData data = CreateReadFromDemuxerAckForAudio(i);
+    data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(
+        500 + 30 * (i - 1));
+    player_.OnDemuxerDataAvailable(data);
+    EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+    message_loop_.Run();
+  }
+  EXPECT_LT(500.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_FALSE(IsPrerolling(true));
+
+  // Throughout this test, we should have not re-created the decoder job, so
+  // IsPrerolling() transition from false to true was not due to constructor
+  // initialization. It was due to BeginPrerolling().
+  EXPECT_EQ(decoder_job, GetMediaDecoderJob(true));
+}
+
+TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossReleaseAndStart) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test decoder job will resume media prerolling if interrupted by Release()
+  // and Start().
+  StartAudioDecoderJob();
+  EXPECT_TRUE(GetMediaDecoderJob(true));
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(IsPrerolling(true));
+  EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
+
+  // Send some data before the seek position.
+  // Test uses 'large' number of iterations because decoder job may not get
+  // MEDIA_CODEC_OK output status until after a few dequeue output attempts.
+  // This allows decoder status to stabilize prior to AU timestamp reaching
+  // the preroll target.
+  DemuxerData data;
+  for (int i = 0; i < 10; ++i) {
+    data = CreateReadFromDemuxerAckForAudio(3);
+    data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(i * 10);
+    if (i == 1) {
+      // While still prerolling, Release() and Start() the player.
+      // TODO(qinmin): Simulation of multiple in-flight data requests (one from
+      // before Release(), one from after Start()) is not included here, and
+      // neither is any data enqueued for later decode if it arrives after
+      // Release() and before Start(). See http://crbug.com/306314. Assumption
+      // for this test, to prevent flakiness until the bug is fixed, is the
+      // first request's data arrives before Start(). Though that data is not
+      // seen by decoder, this assumption allows preroll continuation
+      // verification and prevents multiple in-flight data requests.
+      player_.Release();
+      player_.OnDemuxerDataAvailable(data);
+      message_loop_.RunUntilIdle();
+      EXPECT_FALSE(GetMediaDecoderJob(true));
+      StartAudioDecoderJob();
+      EXPECT_TRUE(GetMediaDecoderJob(true));
+    } else {
+      player_.OnDemuxerDataAvailable(data);
+      EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+      message_loop_.Run();
+    }
+    EXPECT_TRUE(IsPrerolling(true));
+  }
+  EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_TRUE(IsPrerolling(true));
 
   // Send data after the seek position.
   data = CreateReadFromDemuxerAckForAudio(3);
@@ -697,6 +1162,221 @@
   player_.OnDemuxerDataAvailable(data);
   message_loop_.Run();
   EXPECT_LT(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_FALSE(IsPrerolling(true));
+}
+
+TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossConfigChange) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test decoder job will resume media prerolling if interrupted by
+  // |kConfigChanged| and OnDemuxerConfigsAvailable().
+  StartAudioDecoderJob();
+  EXPECT_TRUE(GetMediaDecoderJob(true));
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+
+  SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(IsPrerolling(true));
+  EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
+
+  // In response to data request, simulate that demuxer signals config change by
+  // sending an AU with |kConfigChanged|. Player should prepare to reconfigure
+  // the audio decoder job, and should request new demuxer configs.
+  DemuxerData data = CreateReadFromDemuxerAckWithConfigChanged(true, 0);
+  EXPECT_EQ(0, demuxer_->num_config_requests());
+  player_.OnDemuxerDataAvailable(data);
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+
+  // Simulate arrival of new configs.
+  player_.OnDemuxerConfigsAvailable(CreateAudioDemuxerConfigs());
+
+  // Send some data before the seek position.
+  for (int i = 1; i < 4; ++i) {
+    player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(i));
+    EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+    message_loop_.Run();
+  }
+  EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_TRUE(IsPrerolling(true));
+
+  // Send data after the seek position.
+  data = CreateReadFromDemuxerAckForAudio(3);
+  data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(100);
+  player_.OnDemuxerDataAvailable(data);
+  message_loop_.Run();
+  EXPECT_LT(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_FALSE(IsPrerolling(true));
+}
+
+TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInPrefetchUnit0) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that the player detects need for and requests demuxer configs if
+  // the |kConfigChanged| unit is the very first unit in the set of units
+  // received in OnDemuxerDataAvailable() ostensibly while
+  // |PREFETCH_DONE_EVENT_PENDING|.
+  StartConfigChange(true, true, 0);
+}
+
+TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInPrefetchUnit1) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that the player detects need for and requests demuxer configs if
+  // the |kConfigChanged| unit is not the first unit in the set of units
+  // received in OnDemuxerDataAvailable() ostensibly while
+  // |PREFETCH_DONE_EVENT_PENDING|.
+  StartConfigChange(true, true, 1);
+}
+
+TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit0AfterPrefetch) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that the player detects need for and requests demuxer configs if
+  // the |kConfigChanged| unit is the very first unit in the set of units
+  // received in OnDemuxerDataAvailable() from data requested ostensibly while
+  // not prefetching.
+  StartConfigChange(true, false, 0);
+}
+
+TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit1AfterPrefetch) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that the player detects need for and requests demuxer configs if
+  // the |kConfigChanged| unit is not the first unit in the set of units
+  // received in OnDemuxerDataAvailable() from data requested ostensibly while
+  // not prefetching.
+  StartConfigChange(true, false, 1);
+}
+
+TEST_F(MediaSourcePlayerTest, BrowserSeek_PrerollAfterBrowserSeek) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test decoder job will preroll the media to the actual seek position
+  // resulting from a browser seek.
+  BrowserSeekPlayer(false);
+
+  // Simulate browser seek is done, but to a later time than was requested.
+  EXPECT_LT(player_.GetCurrentTime().InMillisecondsF(), 100);
+  player_.OnDemuxerSeekDone(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(GetMediaDecoderJob(false));
+  EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+  EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+
+  // Send some data with access unit timestamps before the actual browser seek
+  // position. This is a bit unrealistic in this case where the browser seek
+  // jumped forward and next data from demuxer would normally begin at this
+  // browser seek position, immediately completing preroll. For simplicity and
+  // coverage, this test simulates the more common condition that AUs received
+  // after browser seek begin with timestamps before the seek target, and don't
+  // immediately complete preroll.
+  DemuxerData data;
+  for (int i = 1; i < 4; ++i) {
+    data = CreateReadFromDemuxerAckForVideo();
+    data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(i * 30);
+    player_.OnDemuxerDataAvailable(data);
+    EXPECT_TRUE(GetMediaDecoderJob(false)->is_decoding());
+    message_loop_.Run();
+    EXPECT_TRUE(IsPrerolling(false));
+  }
+
+  EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
+
+  // Send data after the browser seek position.
+  data = CreateReadFromDemuxerAckForVideo();
+  data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(120);
+  player_.OnDemuxerDataAvailable(data);
+  message_loop_.Run();
+  EXPECT_FALSE(IsPrerolling(false));
+}
+
+TEST_F(MediaSourcePlayerTest, VideoDemuxerConfigChange) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that video config change notification results in request for demuxer
+  // configuration, and that a video decoder job results without any browser
+  // seek necessary once the new demuxer config arrives.
+  StartConfigChange(false, true, 1);
+  MediaDecoderJob* first_job = GetMediaDecoderJob(false);
+  EXPECT_TRUE(first_job);
+  EXPECT_EQ(1, demuxer_->num_data_requests());
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+
+  // Simulate arrival of new configs.
+  player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
+
+  // New video decoder job should have been created and configured, without any
+  // browser seek.
+  MediaDecoderJob* second_job = GetMediaDecoderJob(false);
+  EXPECT_TRUE(second_job);
+  EXPECT_NE(first_job, second_job);
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, VideoConfigChangeContinuesAcrossSeek) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test if a demuxer config request is pending (due to previously receiving
+  // |kConfigChanged|), and a seek request arrives prior to demuxer configs,
+  // then seek is processed first, followed by the decoder config change.
+  // This assumes the demuxer sends |kConfigChanged| read response prior to
+  // canceling any reads pending seek; no |kAborted| is involved in this test.
+  StartConfigChange(false, false, 1);
+  MediaDecoderJob* first_job = GetMediaDecoderJob(false);
+  EXPECT_TRUE(first_job);
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
+
+  player_.SeekTo(base::TimeDelta::FromMilliseconds(100));
+
+  // Verify that the seek is requested immediately.
+  EXPECT_EQ(1, demuxer_->num_seek_requests());
+
+  // Simulate unlikely delayed arrival of the demuxer configs, completing the
+  // config change.
+  // TODO(wolenetz): Is it even possible for requested demuxer configs to be
+  // delayed until after a SeekTo request arrives?
+  player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
+
+  MediaDecoderJob* second_job = GetMediaDecoderJob(false);
+  EXPECT_NE(first_job, second_job);
+  EXPECT_TRUE(second_job);
+
+  // Send back the seek done notification. This should finish the seek and
+  // trigger the player to request more data.
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+  player_.OnDemuxerSeekDone(kNoTimestamp());
+  EXPECT_EQ(3, demuxer_->num_data_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, NewSurfaceWhileChangingConfigs) {
+  SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+  // Test that no seek or duplicated demuxer config request results from a
+  // SetVideoSurface() that occurs while the player is expecting new demuxer
+  // configs. This test may be good to keep beyond browser seek hack.
+  StartConfigChange(false, false, 1);
+  MediaDecoderJob* first_job = GetMediaDecoderJob(false);
+  EXPECT_TRUE(first_job);
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+  EXPECT_EQ(2, demuxer_->num_data_requests());
+
+  CreateNextTextureAndSetVideoSurface();
+
+  // Surface change processing (including decoder job re-creation) should
+  // not occur until the pending video config change is completed.
+  EXPECT_EQ(first_job, GetMediaDecoderJob(false));
+
+  player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
+  MediaDecoderJob* second_job = GetMediaDecoderJob(false);
+  EXPECT_NE(first_job, second_job);
+  EXPECT_TRUE(second_job);
+
+  EXPECT_EQ(3, demuxer_->num_data_requests());
+  EXPECT_EQ(1, demuxer_->num_config_requests());
+  EXPECT_EQ(0, demuxer_->num_seek_requests());
 }
 
 // TODO(xhwang): Enable this test when the test devices are updated.
@@ -771,7 +1451,5 @@
 
 // TODO(xhwang): Are these IsTypeSupported tests device specific?
 // TODO(xhwang): Add more IsTypeSupported tests.
-// TODO(wolenetz): Add tests around second SetVideoSurface, once fix to reach
-// next I-frame is correct.
 
 }  // namespace media
diff --git a/media/base/audio_bus_perftest.cc b/media/base/audio_bus_perftest.cc
new file mode 100644
index 0000000..e4152fd
--- /dev/null
+++ b/media/base/audio_bus_perftest.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/time/time.h"
+#include "media/base/audio_bus.h"
+#include "media/base/fake_audio_render_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace media {
+
+static const int kBenchmarkIterations = 100;
+
+template <typename T>
+void RunInterleaveBench(AudioBus* bus, const std::string& trace_name) {
+  const int frame_size = bus->frames() * bus->channels();
+  scoped_ptr<T> interleaved(new T[frame_size]);
+  const int byte_size = sizeof(*interleaved);
+
+  base::TimeTicks start = base::TimeTicks::HighResNow();
+  for (int i = 0; i < kBenchmarkIterations; ++i) {
+    bus->ToInterleaved(bus->frames(), byte_size, interleaved.get());
+  }
+  double total_time_seconds =
+      (base::TimeTicks::HighResNow() - start).InSecondsF();
+  perf_test::PrintResult(
+      "audio_bus_to_interleaved", "", trace_name,
+      kBenchmarkIterations / total_time_seconds, "runs/s", true);
+
+  start = base::TimeTicks::HighResNow();
+  for (int i = 0; i < kBenchmarkIterations; ++i) {
+    bus->FromInterleaved(interleaved.get(), bus->frames(), byte_size);
+  }
+  total_time_seconds = (base::TimeTicks::HighResNow() - start).InSecondsF();
+  perf_test::PrintResult(
+      "audio_bus_from_interleaved", "", trace_name,
+      kBenchmarkIterations / total_time_seconds, "runs/s", true);
+}
+
+// Benchmark the FromInterleaved() and ToInterleaved() methods.
+TEST(AudioBusPerfTest, Interleave) {
+  scoped_ptr<AudioBus> bus = AudioBus::Create(2, 48000 * 120);
+  FakeAudioRenderCallback callback(0.2);
+  callback.Render(bus.get(), 0);
+
+  RunInterleaveBench<int8>(bus.get(), "int8");
+  RunInterleaveBench<int16>(bus.get(), "int16");
+  RunInterleaveBench<int32>(bus.get(), "int32");
+}
+
+} // namespace media
diff --git a/media/base/audio_bus_unittest.cc b/media/base/audio_bus_unittest.cc
index a82090b..e8c78a3 100644
--- a/media/base/audio_bus_unittest.cc
+++ b/media/base/audio_bus_unittest.cc
@@ -413,60 +413,4 @@
   }
 }
 
-// Benchmark the FromInterleaved() and ToInterleaved() methods.
-TEST_F(AudioBusTest, DISABLED_InterleaveBench) {
-  scoped_ptr<AudioBus> bus = AudioBus::Create(2, 48000 * 120);
-  const int frame_size = bus->frames() * bus->channels();
-  FakeAudioRenderCallback callback(0.2);
-  callback.Render(bus.get(), 0);
-  {
-    SCOPED_TRACE("uint8");
-    scoped_ptr<uint8> interleaved(new uint8[frame_size]);
-    const int byte_size = sizeof(*interleaved);
-
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    bus->ToInterleaved(bus->frames(), byte_size, interleaved.get());
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("ToInterleaved uint8 took %.2fms.\n", total_time_ms);
-
-    start = base::TimeTicks::HighResNow();
-    bus->FromInterleaved(interleaved.get(), bus->frames(), byte_size);
-    total_time_ms = (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("FromInterleaved uint8 took %.2fms.\n", total_time_ms);
-  }
-  {
-    SCOPED_TRACE("int16");
-    scoped_ptr<int16> interleaved(new int16[frame_size]);
-    const int byte_size = sizeof(*interleaved);
-
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    bus->ToInterleaved(bus->frames(), byte_size, interleaved.get());
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("ToInterleaved int16 took %.2fms.\n", total_time_ms);
-
-    start = base::TimeTicks::HighResNow();
-    bus->FromInterleaved(interleaved.get(), bus->frames(), byte_size);
-    total_time_ms = (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("FromInterleaved int16 took %.2fms.\n", total_time_ms);
-  }
-  {
-    SCOPED_TRACE("int32");
-    scoped_ptr<int32> interleaved(new int32[frame_size]);
-    const int byte_size = sizeof(*interleaved);
-
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    bus->ToInterleaved(bus->frames(), byte_size, interleaved.get());
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("ToInterleaved int32 took %.2fms.\n", total_time_ms);
-
-    start = base::TimeTicks::HighResNow();
-    bus->FromInterleaved(interleaved.get(), bus->frames(), byte_size);
-    total_time_ms = (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("FromInterleaved int32 took %.2fms.\n", total_time_ms);
-  }
-}
-
 }  // namespace media
diff --git a/media/base/audio_converter_perftest.cc b/media/base/audio_converter_perftest.cc
new file mode 100644
index 0000000..f8570e1
--- /dev/null
+++ b/media/base/audio_converter_perftest.cc
@@ -0,0 +1,79 @@
+// Copyright 2013 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/time/time.h"
+#include "media/base/audio_converter.h"
+#include "media/base/fake_audio_render_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace media {
+
+static const int kBenchmarkIterations = 500000;
+
+// InputCallback that zero's out the provided AudioBus.
+class NullInputProvider : public AudioConverter::InputCallback {
+ public:
+  NullInputProvider() {}
+  virtual ~NullInputProvider() {}
+
+  virtual double ProvideInput(AudioBus* audio_bus,
+                              base::TimeDelta buffer_delay) OVERRIDE {
+    audio_bus->Zero();
+    return 1;
+  }
+};
+
+void RunConvertBenchmark(const AudioParameters& in_params,
+                         const AudioParameters& out_params,
+                         bool fifo,
+                         const std::string& trace_name) {
+  NullInputProvider fake_input1;
+  NullInputProvider fake_input2;
+  NullInputProvider fake_input3;
+  scoped_ptr<AudioBus> output_bus = AudioBus::Create(out_params);
+
+  AudioConverter converter(in_params, out_params, !fifo);
+  converter.AddInput(&fake_input1);
+  converter.AddInput(&fake_input2);
+  converter.AddInput(&fake_input3);
+
+  base::TimeTicks start = base::TimeTicks::HighResNow();
+  for (int i = 0; i < kBenchmarkIterations; ++i) {
+    converter.Convert(output_bus.get());
+  }
+  double runs_per_second = kBenchmarkIterations /
+                           (base::TimeTicks::HighResNow() - start).InSecondsF();
+  perf_test::PrintResult(
+      "audio_converter", "", trace_name, runs_per_second, "runs/s", true);
+}
+
+TEST(AudioConverterPerfTest, ConvertBenchmark) {
+  // Create input and output parameters to convert between the two most common
+  // sets of parameters (as indicated via UMA data).
+  AudioParameters input_params(
+      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 48000, 16, 2048);
+  AudioParameters output_params(
+      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 44100, 16, 440);
+
+  RunConvertBenchmark(input_params, output_params, false, "convert");
+}
+
+TEST(AudioConverterPerfTest, ConvertBenchmarkFIFO) {
+  // Create input and output parameters to convert between common buffer sizes
+  // without any resampling for the FIFO vs no FIFO benchmarks.
+  AudioParameters input_params(AudioParameters::AUDIO_PCM_LINEAR,
+                               CHANNEL_LAYOUT_STEREO,
+                               44100,
+                               16,
+                               2048);
+  AudioParameters output_params(
+      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 44100, 16, 440);
+
+  RunConvertBenchmark(input_params, output_params, true, "convert_fifo_only");
+  RunConvertBenchmark(input_params, output_params, false,
+                      "convert_pass_through");
+}
+
+} // namespace media
diff --git a/media/base/audio_converter_unittest.cc b/media/base/audio_converter_unittest.cc
index d218ac8..aeb021c 100644
--- a/media/base/audio_converter_unittest.cc
+++ b/media/base/audio_converter_unittest.cc
@@ -7,12 +7,9 @@
 
 #include <cmath>
 
-#include "base/command_line.h"
-#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time/time.h"
 #include "media/base/audio_converter.h"
 #include "media/base/fake_audio_render_callback.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -20,10 +17,6 @@
 
 namespace media {
 
-// Command line switch for runtime adjustment of benchmark iterations.
-static const char kBenchmarkIterations[] = "audio-converter-iterations";
-static const int kDefaultIterations = 10;
-
 // Parameters which control the many input case tests.
 static const int kConvertInputs = 8;
 static const int kConvertCycles = 3;
@@ -234,107 +227,6 @@
             callback.last_audio_delay_milliseconds());
 }
 
-// InputCallback that zero's out the provided AudioBus.  Used for benchmarking.
-class NullInputProvider : public AudioConverter::InputCallback {
- public:
-  NullInputProvider() {}
-  virtual ~NullInputProvider() {}
-
-  virtual double ProvideInput(AudioBus* audio_bus,
-                              base::TimeDelta buffer_delay) OVERRIDE {
-    audio_bus->Zero();
-    return 1;
-  }
-};
-
-// Benchmark for audio conversion.  Original benchmarks were run with
-// --audio-converter-iterations=50000.
-TEST(AudioConverterTest, ConvertBenchmark) {
-  int benchmark_iterations = kDefaultIterations;
-  std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      kBenchmarkIterations));
-  base::StringToInt(iterations, &benchmark_iterations);
-  if (benchmark_iterations < kDefaultIterations)
-    benchmark_iterations = kDefaultIterations;
-
-  NullInputProvider fake_input1;
-  NullInputProvider fake_input2;
-  NullInputProvider fake_input3;
-
-  printf("Benchmarking %d iterations:\n", benchmark_iterations);
-
-  {
-    // Create input and output parameters to convert between the two most common
-    // sets of parameters (as indicated via UMA data).
-    AudioParameters input_params(
-        AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
-        48000, 16, 2048);
-    AudioParameters output_params(
-        AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
-        44100, 16, 440);
-    scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
-
-    scoped_ptr<AudioConverter> converter(
-        new AudioConverter(input_params, output_params, true));
-    converter->AddInput(&fake_input1);
-    converter->AddInput(&fake_input2);
-    converter->AddInput(&fake_input3);
-
-    // Benchmark Convert() w/ FIFO.
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    for (int i = 0; i < benchmark_iterations; ++i) {
-      converter->Convert(output_bus.get());
-    }
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("Convert() w/ Resampling took %.2fms.\n", total_time_ms);
-  }
-
-  // Create input and output parameters to convert between common buffer sizes
-  // without any resampling for the FIFO vs no FIFO benchmarks.
-  AudioParameters input_params(
-      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
-      44100, 16, 2048);
-  AudioParameters output_params(
-      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
-      44100, 16, 440);
-  scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
-
-  {
-    scoped_ptr<AudioConverter> converter(
-        new AudioConverter(input_params, output_params, false));
-    converter->AddInput(&fake_input1);
-    converter->AddInput(&fake_input2);
-    converter->AddInput(&fake_input3);
-
-    // Benchmark Convert() w/ FIFO.
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    for (int i = 0; i < benchmark_iterations; ++i) {
-      converter->Convert(output_bus.get());
-    }
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("Convert() w/ FIFO took %.2fms.\n", total_time_ms);
-  }
-
-  {
-    scoped_ptr<AudioConverter> converter(
-        new AudioConverter(input_params, output_params, true));
-    converter->AddInput(&fake_input1);
-    converter->AddInput(&fake_input2);
-    converter->AddInput(&fake_input3);
-
-    // Benchmark Convert() w/o FIFO.
-    base::TimeTicks start = base::TimeTicks::HighResNow();
-    for (int i = 0; i < benchmark_iterations; ++i) {
-      converter->Convert(output_bus.get());
-    }
-    double total_time_ms =
-        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-    printf("Convert() w/o FIFO took %.2fms.\n", total_time_ms);
-  }
-}
-
 TEST_P(AudioConverterTest, NoInputs) {
   FillAudioData(1.0f);
   EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index c295a0d..4e75216 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -21,10 +21,6 @@
 // Set number of threads to use for video decoding.
 const char kVideoThreads[] = "video-threads";
 
-// Override suppressed responses to canPlayType().
-const char kOverrideEncryptedMediaCanPlayType[] =
-    "override-encrypted-media-canplaytype";
-
 // Enables MP3 stream parser for Media Source Extensions.
 const char kEnableMP3StreamParser[] = "enable-mp3-stream-parser";
 
@@ -33,9 +29,6 @@
 const char kDisableInfobarForProtectedMediaIdentifier[] =
     "disable-infobar-for-protected-media-identifier";
 
-// Enables use of MediaDrm for Encrypted Media Extensions implementation.
-const char kEnableMediaDrm[] = "enable-mediadrm";
-
 // Enables use of non-compositing MediaDrm decoding by default for Encrypted
 // Media Extensions implementation.
 const char kMediaDrmEnableNonCompositing[] = "mediadrm-enable-non-compositing";
@@ -63,6 +56,13 @@
 // tested.  See http://crbug.com/158170.
 // TODO(dalecurtis): Remove this once we're sure nothing has exploded.
 const char kDisableMainThreadAudio[] = "disable-main-thread-audio";
+// AVFoundation is available in versions 10.7 and onwards, and is to be used
+// http://crbug.com/288562 for both audio and video device monitoring and for
+// video capture. Being a dynamically loaded NSBundle and library, it hits the
+// Chrome startup time (http://crbug.com/311325 and http://crbug.com/311437);
+// until development is finished and the library load time issue is solved, the
+// usage of this library is hidden behind this flag.
+const char kEnableAVFoundation[] = "enable-avfoundation";
 #endif
 
 #if defined(OS_WIN)
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 963a351..69fb10e 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -22,13 +22,10 @@
 
 MEDIA_EXPORT extern const char kVideoThreads[];
 
-MEDIA_EXPORT extern const char kOverrideEncryptedMediaCanPlayType[];
-
 MEDIA_EXPORT extern const char kEnableMP3StreamParser[];
 
 #if defined(OS_ANDROID)
 MEDIA_EXPORT extern const char kDisableInfobarForProtectedMediaIdentifier[];
-MEDIA_EXPORT extern const char kEnableMediaDrm[];
 MEDIA_EXPORT extern const char kMediaDrmEnableNonCompositing[];
 #endif
 
@@ -43,6 +40,7 @@
 
 #if defined(OS_MACOSX)
 MEDIA_EXPORT extern const char kDisableMainThreadAudio[];
+MEDIA_EXPORT extern const char kEnableAVFoundation[];
 #endif
 
 #if defined(OS_WIN)
diff --git a/media/base/sinc_resampler.h b/media/base/sinc_resampler.h
index 77f331b..2170778 100644
--- a/media/base/sinc_resampler.h
+++ b/media/base/sinc_resampler.h
@@ -75,7 +75,7 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve);
-  FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark);
+  FRIEND_TEST_ALL_PREFIXES(SincResamplerPerfTest, Convolve);
 
   void InitializeKernel();
   void UpdateRegions(bool second_load);
diff --git a/media/base/sinc_resampler_perftest.cc b/media/base/sinc_resampler_perftest.cc
new file mode 100644
index 0000000..c7e7517
--- /dev/null
+++ b/media/base/sinc_resampler_perftest.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/bind.h"
+#include "base/bind_helpers.h"
+#include "base/cpu.h"
+#include "base/time/time.h"
+#include "media/base/sinc_resampler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace media {
+
+static const int kBenchmarkIterations = 50000000;
+
+static const double kSampleRateRatio = 192000.0 / 44100.0;
+static const double kKernelInterpolationFactor = 0.5;
+
+// Helper function to provide no input to SincResampler's Convolve benchmark.
+static void DoNothing(int frames, float* destination) {}
+
+// Define platform independent function name for Convolve* tests.
+#if defined(ARCH_CPU_X86_FAMILY)
+#define CONVOLVE_FUNC Convolve_SSE
+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
+#define CONVOLVE_FUNC Convolve_NEON
+#endif
+
+static void RunConvolveBenchmark(
+    SincResampler* resampler,
+    float (*convolve_fn)(const float*, const float*, const float*, double),
+    bool aligned,
+    const std::string& trace_name) {
+  base::TimeTicks start = base::TimeTicks::HighResNow();
+  for (int i = 0; i < kBenchmarkIterations; ++i) {
+    convolve_fn(resampler->get_kernel_for_testing() + (aligned ? 0 : 1),
+                resampler->get_kernel_for_testing(),
+                resampler->get_kernel_for_testing(),
+                kKernelInterpolationFactor);
+  }
+  double total_time_seconds =
+      (base::TimeTicks::HighResNow() - start).InSecondsF();
+  perf_test::PrintResult("sinc_resampler_convolve",
+                         "",
+                         trace_name,
+                         kBenchmarkIterations / total_time_seconds,
+                         "runs/s",
+                         true);
+}
+
+// Benchmark for the various Convolve() methods.  Make sure to build with
+// branding=Chrome so that DCHECKs are compiled out when benchmarking.
+TEST(SincResamplerPerfTest, Convolve) {
+  SincResampler resampler(kSampleRateRatio,
+                          SincResampler::kDefaultRequestSize,
+                          base::Bind(&DoNothing));
+
+  RunConvolveBenchmark(
+      &resampler, SincResampler::Convolve_C, true, "unoptimized_aligned");
+
+#if defined(CONVOLVE_FUNC)
+#if defined(ARCH_CPU_X86_FAMILY)
+  ASSERT_TRUE(base::CPU().has_sse());
+#endif
+  RunConvolveBenchmark(
+      &resampler, SincResampler::CONVOLVE_FUNC, true, "optimized_aligned");
+  RunConvolveBenchmark(
+      &resampler, SincResampler::CONVOLVE_FUNC, false, "optimized_unaligned");
+#endif
+}
+
+#undef CONVOLVE_FUNC
+
+} // namespace media
diff --git a/media/base/sinc_resampler_unittest.cc b/media/base/sinc_resampler_unittest.cc
index 8b89a5d..3b460a3 100644
--- a/media/base/sinc_resampler_unittest.cc
+++ b/media/base/sinc_resampler_unittest.cc
@@ -9,11 +9,8 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/cpu.h"
-#include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/stringize_macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "media/base/sinc_resampler.h"
@@ -25,10 +22,6 @@
 namespace media {
 
 static const double kSampleRateRatio = 192000.0 / 44100.0;
-static const double kKernelInterpolationFactor = 0.5;
-
-// Command line switch for runtime adjustment of ConvolveBenchmark iterations.
-static const char kConvolveIterations[] = "convolve-iterations";
 
 // Helper class to ensure ChunkedResample() functions properly.
 class MockSource {
@@ -125,6 +118,8 @@
 // this test if other optimized methods exist, otherwise the default Convolve()
 // will be tested by the parameterized SincResampler tests below.
 #if defined(CONVOLVE_FUNC)
+static const double kKernelInterpolationFactor = 0.5;
+
 TEST(SincResamplerTest, Convolve) {
 #if defined(ARCH_CPU_X86_FAMILY)
   ASSERT_TRUE(base::CPU().has_sse());
@@ -161,74 +156,6 @@
 }
 #endif
 
-// Benchmark for the various Convolve() methods.  Make sure to build with
-// branding=Chrome so that DCHECKs are compiled out when benchmarking.  Original
-// benchmarks were run with --convolve-iterations=50000000.
-TEST(SincResamplerTest, ConvolveBenchmark) {
-  // Initialize a dummy resampler.
-  MockSource mock_source;
-  SincResampler resampler(
-      kSampleRateRatio, SincResampler::kDefaultRequestSize,
-      base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source)));
-
-  // Retrieve benchmark iterations from command line.
-  int convolve_iterations = 10;
-  std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      kConvolveIterations));
-  if (!iterations.empty())
-    base::StringToInt(iterations, &convolve_iterations);
-
-  printf("Benchmarking %d iterations:\n", convolve_iterations);
-
-  // Benchmark Convolve_C().
-  base::TimeTicks start = base::TimeTicks::HighResNow();
-  for (int i = 0; i < convolve_iterations; ++i) {
-    resampler.Convolve_C(
-        resampler.kernel_storage_.get(), resampler.kernel_storage_.get(),
-        resampler.kernel_storage_.get(), kKernelInterpolationFactor);
-  }
-  double total_time_c_ms =
-      (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf("Convolve_C took %.2fms.\n", total_time_c_ms);
-
-#if defined(CONVOLVE_FUNC)
-#if defined(ARCH_CPU_X86_FAMILY)
-  ASSERT_TRUE(base::CPU().has_sse());
-#endif
-
-  // Benchmark with unaligned input pointer.
-  start = base::TimeTicks::HighResNow();
-  for (int j = 0; j < convolve_iterations; ++j) {
-    resampler.CONVOLVE_FUNC(
-        resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(),
-        resampler.kernel_storage_.get(), kKernelInterpolationFactor);
-  }
-  double total_time_optimized_unaligned_ms =
-      (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(CONVOLVE_FUNC) " (unaligned) took %.2fms; which is %.2fx "
-         "faster than Convolve_C.\n", total_time_optimized_unaligned_ms,
-         total_time_c_ms / total_time_optimized_unaligned_ms);
-
-  // Benchmark with aligned input pointer.
-  start = base::TimeTicks::HighResNow();
-  for (int j = 0; j < convolve_iterations; ++j) {
-    resampler.CONVOLVE_FUNC(
-        resampler.kernel_storage_.get(), resampler.kernel_storage_.get(),
-        resampler.kernel_storage_.get(), kKernelInterpolationFactor);
-  }
-  double total_time_optimized_aligned_ms =
-      (base::TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(CONVOLVE_FUNC) " (aligned) took %.2fms; which is %.2fx "
-         "faster than Convolve_C and %.2fx faster than "
-         STRINGIZE(CONVOLVE_FUNC) " (unaligned).\n",
-         total_time_optimized_aligned_ms,
-         total_time_c_ms / total_time_optimized_aligned_ms,
-         total_time_optimized_unaligned_ms / total_time_optimized_aligned_ms);
-#endif
-}
-
-#undef CONVOLVE_FUNC
-
 // Fake audio source for testing the resampler.  Generates a sinusoidal linear
 // chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the
 // resampler for the specific sample rate conversion being used.
diff --git a/media/base/vector_math_perftest.cc b/media/base/vector_math_perftest.cc
new file mode 100644
index 0000000..78699c3
--- /dev/null
+++ b/media/base/vector_math_perftest.cc
@@ -0,0 +1,124 @@
+// Copyright 2013 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/cpu.h"
+#include "base/memory/aligned_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "media/base/vector_math.h"
+#include "media/base/vector_math_testing.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+using base::TimeTicks;
+using std::fill;
+
+namespace media {
+
+static const int kBenchmarkIterations = 200000;
+static const float kScale = 0.5;
+static const int kVectorSize = 8192;
+
+class VectorMathPerfTest : public testing::Test {
+ public:
+  VectorMathPerfTest() {
+    // Initialize input and output vectors.
+    input_vector_.reset(static_cast<float*>(base::AlignedAlloc(
+        sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
+    output_vector_.reset(static_cast<float*>(base::AlignedAlloc(
+        sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
+    fill(input_vector_.get(), input_vector_.get() + kVectorSize, 1.0f);
+    fill(output_vector_.get(), output_vector_.get() + kVectorSize, 0.0f);
+  }
+
+  void RunBenchmark(void (*fn)(const float[], float, int, float[]),
+                    bool aligned,
+                    const std::string& test_name,
+                    const std::string& trace_name) {
+    TimeTicks start = TimeTicks::HighResNow();
+    for (int i = 0; i < kBenchmarkIterations; ++i) {
+      fn(input_vector_.get(),
+         kScale,
+         kVectorSize - (aligned ? 0 : 1),
+         output_vector_.get());
+    }
+    double total_time_seconds = (TimeTicks::HighResNow() - start).InSecondsF();
+    perf_test::PrintResult(test_name,
+                           "",
+                           trace_name,
+                           kBenchmarkIterations / total_time_seconds,
+                           "runs/s",
+                           true);
+  }
+
+ protected:
+  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector_;
+  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector_;
+
+  DISALLOW_COPY_AND_ASSIGN(VectorMathPerfTest);
+};
+
+// Define platform independent function name for FMAC* perf tests.
+#if defined(ARCH_CPU_X86_FAMILY)
+#define FMAC_FUNC FMAC_SSE
+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
+#define FMAC_FUNC FMAC_NEON
+#endif
+
+// Benchmark for each optimized vector_math::FMAC() method.
+TEST_F(VectorMathPerfTest, FMAC) {
+  // Benchmark FMAC_C().
+  RunBenchmark(
+      vector_math::FMAC_C, true, "vector_math_fmac", "unoptimized");
+#if defined(FMAC_FUNC)
+#if defined(ARCH_CPU_X86_FAMILY)
+  ASSERT_TRUE(base::CPU().has_sse());
+#endif
+  // Benchmark FMAC_FUNC() with unaligned size.
+  ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment /
+                                 sizeof(float)), 0U);
+  RunBenchmark(
+      vector_math::FMAC_FUNC, false, "vector_math_fmac", "optimized_unaligned");
+  // Benchmark FMAC_FUNC() with aligned size.
+  ASSERT_EQ(kVectorSize % (vector_math::kRequiredAlignment / sizeof(float)),
+            0U);
+  RunBenchmark(
+      vector_math::FMAC_FUNC, true, "vector_math_fmac", "optimized_aligned");
+#endif
+}
+
+#undef FMAC_FUNC
+
+// Define platform independent function name for FMULBenchmark* tests.
+#if defined(ARCH_CPU_X86_FAMILY)
+#define FMUL_FUNC FMUL_SSE
+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
+#define FMUL_FUNC FMUL_NEON
+#endif
+
+// Benchmark for each optimized vector_math::FMUL() method.
+TEST_F(VectorMathPerfTest, FMUL) {
+  // Benchmark FMUL_C().
+  RunBenchmark(
+      vector_math::FMUL_C, true, "vector_math_fmul", "unoptimized");
+#if defined(FMUL_FUNC)
+#if defined(ARCH_CPU_X86_FAMILY)
+  ASSERT_TRUE(base::CPU().has_sse());
+#endif
+  // Benchmark FMUL_FUNC() with unaligned size.
+  ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment /
+                                 sizeof(float)), 0U);
+  RunBenchmark(
+      vector_math::FMUL_FUNC, false, "vector_math_fmac", "optimized_unaligned");
+  // Benchmark FMUL_FUNC() with aligned size.
+  ASSERT_EQ(kVectorSize % (vector_math::kRequiredAlignment / sizeof(float)),
+            0U);
+  RunBenchmark(
+      vector_math::FMUL_FUNC, true, "vector_math_fmac", "optimized_aligned");
+#endif
+}
+
+#undef FMUL_FUNC
+
+} // namespace media
diff --git a/media/base/vector_math_unittest.cc b/media/base/vector_math_unittest.cc
index 2c77401..32e5ea4 100644
--- a/media/base/vector_math_unittest.cc
+++ b/media/base/vector_math_unittest.cc
@@ -6,68 +6,50 @@
 #define _USE_MATH_DEFINES
 #include <cmath>
 
-#include "base/command_line.h"
 #include "base/cpu.h"
 #include "base/memory/aligned_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringize_macros.h"
-#include "base/time/time.h"
 #include "media/base/vector_math.h"
 #include "media/base/vector_math_testing.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::TimeTicks;
 using std::fill;
 
-// Command line switch for runtime adjustment of benchmark iterations.
-static const char kBenchmarkIterations[] = "vector-math-iterations";
-static const int kDefaultIterations = 10;
+namespace media {
 
 // Default test values.
 static const float kScale = 0.5;
 static const float kInputFillValue = 1.0;
 static const float kOutputFillValue = 3.0;
-
-namespace media {
+static const int kVectorSize = 8192;
 
 class VectorMathTest : public testing::Test {
  public:
-  static const int kVectorSize = 8192;
 
   VectorMathTest() {
     // Initialize input and output vectors.
-    input_vector.reset(static_cast<float*>(base::AlignedAlloc(
+    input_vector_.reset(static_cast<float*>(base::AlignedAlloc(
         sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
-    output_vector.reset(static_cast<float*>(base::AlignedAlloc(
+    output_vector_.reset(static_cast<float*>(base::AlignedAlloc(
         sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
   }
 
   void FillTestVectors(float input, float output) {
     // Setup input and output vectors.
-    fill(input_vector.get(), input_vector.get() + kVectorSize, input);
-    fill(output_vector.get(), output_vector.get() + kVectorSize, output);
+    fill(input_vector_.get(), input_vector_.get() + kVectorSize, input);
+    fill(output_vector_.get(), output_vector_.get() + kVectorSize, output);
   }
 
   void VerifyOutput(float value) {
     for (int i = 0; i < kVectorSize; ++i)
-      ASSERT_FLOAT_EQ(output_vector.get()[i], value);
-  }
-
-  int BenchmarkIterations() {
-    int vector_math_iterations = kDefaultIterations;
-    std::string iterations(
-        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            kBenchmarkIterations));
-    if (!iterations.empty())
-      base::StringToInt(iterations, &vector_math_iterations);
-    return vector_math_iterations;
+      ASSERT_FLOAT_EQ(output_vector_.get()[i], value);
   }
 
  protected:
-  int benchmark_iterations;
-  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector;
-  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector;
+  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> input_vector_;
+  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> output_vector_;
 
   DISALLOW_COPY_AND_ASSIGN(VectorMathTest);
 };
@@ -80,7 +62,7 @@
     SCOPED_TRACE("FMAC");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMAC(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 
@@ -88,7 +70,7 @@
     SCOPED_TRACE("FMAC_C");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMAC_C(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 
@@ -98,7 +80,7 @@
     SCOPED_TRACE("FMAC_SSE");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMAC_SSE(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 #endif
@@ -108,7 +90,7 @@
     SCOPED_TRACE("FMAC_NEON");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMAC_NEON(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 #endif
@@ -122,7 +104,7 @@
     SCOPED_TRACE("FMUL");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMUL(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 
@@ -130,7 +112,7 @@
     SCOPED_TRACE("FMUL_C");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMUL_C(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 
@@ -140,7 +122,7 @@
     SCOPED_TRACE("FMUL_SSE");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMUL_SSE(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 #endif
@@ -150,142 +132,10 @@
     SCOPED_TRACE("FMUL_NEON");
     FillTestVectors(kInputFillValue, kOutputFillValue);
     vector_math::FMUL_NEON(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
+        input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     VerifyOutput(kResult);
   }
 #endif
 }
 
-// Define platform independent function name for FMACBenchmark* tests.
-#if defined(ARCH_CPU_X86_FAMILY)
-#define FMAC_FUNC FMAC_SSE
-#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
-#define FMAC_FUNC FMAC_NEON
-#endif
-
-// Benchmark for each optimized vector_math::FMAC() method.  Original benchmarks
-// were run with --vector-fmac-iterations=200000.
-TEST_F(VectorMathTest, FMACBenchmark) {
-  static const int kBenchmarkIterations = BenchmarkIterations();
-
-  printf("Benchmarking %d iterations:\n", kBenchmarkIterations);
-
-  // Benchmark FMAC_C().
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  TimeTicks start = TimeTicks::HighResNow();
-  for (int i = 0; i < kBenchmarkIterations; ++i) {
-    vector_math::FMAC_C(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
-  }
-  double total_time_c_ms = (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf("FMAC_C took %.2fms.\n", total_time_c_ms);
-
-#if defined(FMAC_FUNC)
-#if defined(ARCH_CPU_X86_FAMILY)
-  ASSERT_TRUE(base::CPU().has_sse());
-#endif
-
-  // Benchmark FMAC_FUNC() with unaligned size.
-  ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment /
-            sizeof(float)), 0U);
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  start = TimeTicks::HighResNow();
-  for (int j = 0; j < kBenchmarkIterations; ++j) {
-    vector_math::FMAC_FUNC(
-        input_vector.get(), kScale, kVectorSize - 1, output_vector.get());
-  }
-  double total_time_optimized_unaligned_ms =
-      (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(FMAC_FUNC) " (unaligned size) took %.2fms; which is %.2fx "
-         "faster than FMAC_C.\n", total_time_optimized_unaligned_ms,
-         total_time_c_ms / total_time_optimized_unaligned_ms);
-
-  // Benchmark FMAC_FUNC() with aligned size.
-  ASSERT_EQ(kVectorSize % (vector_math::kRequiredAlignment / sizeof(float)),
-            0U);
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  start = TimeTicks::HighResNow();
-  for (int j = 0; j < kBenchmarkIterations; ++j) {
-    vector_math::FMAC_FUNC(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
-  }
-  double total_time_optimized_aligned_ms =
-      (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(FMAC_FUNC) " (aligned) took %.2fms; which is %.2fx "
-         "faster than FMAC_C and %.2fx faster than "
-         STRINGIZE(FMAC_FUNC) " (unaligned).\n",
-         total_time_optimized_aligned_ms,
-         total_time_c_ms / total_time_optimized_aligned_ms,
-         total_time_optimized_unaligned_ms / total_time_optimized_aligned_ms);
-#endif
-}
-
-#undef FMAC_FUNC
-
-// Define platform independent function name for FMULBenchmark* tests.
-#if defined(ARCH_CPU_X86_FAMILY)
-#define FMUL_FUNC FMUL_SSE
-#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
-#define FMUL_FUNC FMUL_NEON
-#endif
-
-// Benchmark for each optimized vector_math::FMUL() method.  Original benchmarks
-// were run with --vector-math-iterations=200000.
-TEST_F(VectorMathTest, FMULBenchmark) {
-  static const int kBenchmarkIterations = BenchmarkIterations();
-
-  printf("Benchmarking %d iterations:\n", kBenchmarkIterations);
-
-  // Benchmark FMUL_C().
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  TimeTicks start = TimeTicks::HighResNow();
-  for (int i = 0; i < kBenchmarkIterations; ++i) {
-    vector_math::FMUL_C(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
-  }
-  double total_time_c_ms = (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf("FMUL_C took %.2fms.\n", total_time_c_ms);
-
-#if defined(FMUL_FUNC)
-#if defined(ARCH_CPU_X86_FAMILY)
-  ASSERT_TRUE(base::CPU().has_sse());
-#endif
-
-  // Benchmark FMUL_SSE() with unaligned size.
-  ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment /
-            sizeof(float)), 0U);
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  start = TimeTicks::HighResNow();
-  for (int j = 0; j < kBenchmarkIterations; ++j) {
-    vector_math::FMUL_FUNC(
-        input_vector.get(), kScale, kVectorSize - 1, output_vector.get());
-  }
-  double total_time_optimized_unaligned_ms =
-      (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(FMUL_FUNC) " (unaligned size) took %.2fms; which is %.2fx "
-         "faster than FMUL_C.\n", total_time_optimized_unaligned_ms,
-         total_time_c_ms / total_time_optimized_unaligned_ms);
-
-  // Benchmark FMUL_SSE() with aligned size.
-  ASSERT_EQ(kVectorSize % (vector_math::kRequiredAlignment / sizeof(float)),
-            0U);
-  FillTestVectors(kInputFillValue, kOutputFillValue);
-  start = TimeTicks::HighResNow();
-  for (int j = 0; j < kBenchmarkIterations; ++j) {
-    vector_math::FMUL_FUNC(
-        input_vector.get(), kScale, kVectorSize, output_vector.get());
-  }
-  double total_time_optimized_aligned_ms =
-      (TimeTicks::HighResNow() - start).InMillisecondsF();
-  printf(STRINGIZE(FMUL_FUNC) " (aligned) took %.2fms; which is %.2fx "
-         "faster than FMUL_C and %.2fx faster than "
-         STRINGIZE(FMUL_FUNC) " (unaligned).\n",
-         total_time_optimized_aligned_ms,
-         total_time_c_ms / total_time_optimized_aligned_ms,
-         total_time_optimized_unaligned_ms / total_time_optimized_aligned_ms);
-#endif
-}
-
-#undef FMUL_FUNC
-
 }  // namespace media
diff --git a/media/cast/audio_receiver/audio_receiver.cc b/media/cast/audio_receiver/audio_receiver.cc
index 9329bf2..1a1c8e7 100644
--- a/media/cast/audio_receiver/audio_receiver.cc
+++ b/media/cast/audio_receiver/audio_receiver.cc
@@ -24,36 +24,19 @@
 // Used to pass payload data into the audio receiver.
 class LocalRtpAudioData : public RtpData {
  public:
-  LocalRtpAudioData(AudioReceiver* audio_receiver, base::TickClock* clock)
-      : audio_receiver_(audio_receiver),
-        time_first_incoming_packet_(),
-        first_incoming_rtp_timestamp_(0),
-        clock_(clock) {}
+  explicit LocalRtpAudioData(AudioReceiver* audio_receiver)
+      : audio_receiver_(audio_receiver) {}
 
   virtual void OnReceivedPayloadData(
       const uint8* payload_data,
       size_t payload_size,
       const RtpCastHeader* rtp_header) OVERRIDE {
-    // TODO(pwestin): update this as video to refresh over time.
-    if (time_first_incoming_packet_.is_null()) {
-      first_incoming_rtp_timestamp_ = rtp_header->webrtc.header.timestamp;
-      time_first_incoming_packet_ = clock_->NowTicks();
-    }
     audio_receiver_->IncomingParsedRtpPacket(payload_data, payload_size,
                                              *rtp_header);
   }
 
-  void GetFirstPacketInformation(base::TimeTicks* time_incoming_packet,
-                                 uint32* incoming_rtp_timestamp) {
-    *time_incoming_packet = time_first_incoming_packet_;
-    *incoming_rtp_timestamp = first_incoming_rtp_timestamp_;
-  }
-
  private:
   AudioReceiver* audio_receiver_;
-  base::TimeTicks time_first_incoming_packet_;
-  uint32 first_incoming_rtp_timestamp_;
-  base::TickClock* clock_;
 };
 
 // Local implementation of RtpPayloadFeedback (defined in rtp_defines.h)
@@ -105,8 +88,7 @@
       weak_factory_(this) {
   target_delay_delta_ =
       base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms);
-  incoming_payload_callback_.reset(
-      new LocalRtpAudioData(this, cast_environment->Clock()));
+  incoming_payload_callback_.reset(new LocalRtpAudioData(this));
   incoming_payload_feedback_.reset(new LocalRtpAudioFeedback(this));
   if (audio_config.use_external_decoder) {
     audio_buffer_.reset(new Framer(cast_environment->Clock(),
@@ -144,6 +126,12 @@
 void AudioReceiver::IncomingParsedRtpPacket(const uint8* payload_data,
                                             size_t payload_size,
                                             const RtpCastHeader& rtp_header) {
+  // TODO(pwestin): update this as video to refresh over time.
+  if (time_first_incoming_packet_.is_null()) {
+    first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp;
+    time_first_incoming_packet_ =  cast_environment_->Clock()->NowTicks();
+  }
+
   if (audio_decoder_) {
     DCHECK(!audio_buffer_) << "Invalid internal state";
     audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size,
@@ -206,9 +194,6 @@
     // Already released by incoming packet.
     return;
   }
-  AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front();
-  queued_encoded_callbacks_.pop_front();
-
   uint32 rtp_timestamp = 0;
   bool next_frame = false;
   scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame());
@@ -216,13 +201,17 @@
   if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(),
                                            &rtp_timestamp, &next_frame)) {
     // We have no audio frames. Wait for new packet(s).
-    DCHECK(false);
-    queued_encoded_callbacks_.push_front(callback);
+    // Since the application can post multiple AudioFrameEncodedCallback and
+    // we only check the next frame to play out we might have multiple timeout
+    // events firing after each other; however this should be a rare event.
+    VLOG(1) << "Failed to retrieved a complete frame at this point in time";
     return;
   }
-  // Put the callback back first in the queue on a wait event.
-  PostEncodedAudioFrame(true, callback, rtp_timestamp, next_frame,
-                        &encoded_frame);
+  if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp,
+                            next_frame, &encoded_frame)) {
+    // Call succeed remove callback from list.
+    queued_encoded_callbacks_.pop_front();
+  }
 }
 
 void AudioReceiver::GetEncodedAudioFrame(
@@ -240,12 +229,15 @@
     queued_encoded_callbacks_.push_back(callback);
     return;
   }
-  PostEncodedAudioFrame(false, callback, rtp_timestamp, next_frame,
-                        &encoded_frame);
+  if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame,
+                             &encoded_frame)) {
+    // We have an audio frame; however we are missing packets and we have time
+    // to wait for new packet(s).
+    queued_encoded_callbacks_.push_back(callback);
+  }
 }
 
-void AudioReceiver::PostEncodedAudioFrame(
-    bool on_wait_event_put_first_in_queue,
+bool AudioReceiver::PostEncodedAudioFrame(
     const AudioFrameEncodedCallback& callback,
     uint32 rtp_timestamp,
     bool next_frame,
@@ -257,27 +249,20 @@
       base::TimeDelta::FromMilliseconds(kMaxAudioFrameWaitMs);
 
   if (!next_frame && (time_until_playout  > min_wait_delta)) {
-    // We have an audio frame; however we are missing packets and we have time
-    // to wait for new packet(s).
-    if (on_wait_event_put_first_in_queue) {
-      queued_encoded_callbacks_.push_front(callback);
-    } else {
-      queued_encoded_callbacks_.push_back(callback);
-    }
-
     base::TimeDelta time_until_release = time_until_playout - min_wait_delta;
     cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
         base::Bind(&AudioReceiver::PlayoutTimeout, weak_factory_.GetWeakPtr()),
         time_until_release);
     VLOG(1) << "Wait until time to playout:"
             << time_until_release.InMilliseconds();
-    return;
+    return false;
   }
   (*encoded_frame)->codec = codec_;
   audio_buffer_->ReleaseFrame((*encoded_frame)->frame_id);
 
   cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
       base::Bind(callback, base::Passed(encoded_frame), playout_time));
+  return true;
 }
 
 void AudioReceiver::IncomingPacket(const uint8* packet, size_t length,
@@ -301,26 +286,19 @@
   // Note: the senders clock and our local clock might not be synced.
   base::TimeTicks rtp_timestamp_in_ticks;
   if (time_offset_ == base::TimeDelta()) {
-    base::TimeTicks time_first_incoming_packet;
-    uint32 first_incoming_rtp_timestamp;
-
-    incoming_payload_callback_->GetFirstPacketInformation(
-        &time_first_incoming_packet, &first_incoming_rtp_timestamp);
-
     if (rtcp_->RtpTimestampInSenderTime(frequency_,
-                                        first_incoming_rtp_timestamp,
+                                        first_incoming_rtp_timestamp_,
                                         &rtp_timestamp_in_ticks)) {
-      time_offset_ = time_first_incoming_packet - rtp_timestamp_in_ticks;
+      time_offset_ = time_first_incoming_packet_ - rtp_timestamp_in_ticks;
     } else {
       // We have not received any RTCP to sync the stream play it out as soon as
       // possible.
-      uint32 rtp_timestamp_diff =
-          rtp_timestamp - first_incoming_rtp_timestamp;
+      uint32 rtp_timestamp_diff = rtp_timestamp - first_incoming_rtp_timestamp_;
 
       int frequency_khz = frequency_ / 1000;
       base::TimeDelta rtp_time_diff_delta =
           base::TimeDelta::FromMilliseconds(rtp_timestamp_diff / frequency_khz);
-      base::TimeDelta time_diff_delta = now - time_first_incoming_packet;
+      base::TimeDelta time_diff_delta = now - time_first_incoming_packet_;
 
       return now + std::max(rtp_time_diff_delta - time_diff_delta,
                             base::TimeDelta());
diff --git a/media/cast/audio_receiver/audio_receiver.h b/media/cast/audio_receiver/audio_receiver.h
index f577b1e..742d343 100644
--- a/media/cast/audio_receiver/audio_receiver.h
+++ b/media/cast/audio_receiver/audio_receiver.h
@@ -67,8 +67,7 @@
   // Time to pull out the audio even though we are missing data.
   void PlayoutTimeout();
 
-  void PostEncodedAudioFrame(bool on_wait_event_put_first_in_queue,
-                             const AudioFrameEncodedCallback& callback,
+  bool PostEncodedAudioFrame(const AudioFrameEncodedCallback& callback,
                              uint32 rtp_timestamp,
                              bool next_frame,
                              scoped_ptr<EncodedAudioFrame>* encoded_frame);
@@ -103,6 +102,8 @@
   scoped_ptr<Rtcp> rtcp_;
   scoped_ptr<RtpReceiverStatistics> rtp_audio_receiver_statistics_;
   base::TimeDelta time_offset_;
+  base::TimeTicks time_first_incoming_packet_;
+  uint32 first_incoming_rtp_timestamp_;
 
   std::list<AudioFrameEncodedCallback> queued_encoded_callbacks_;
 };
diff --git a/media/cast/audio_receiver/audio_receiver_unittest.cc b/media/cast/audio_receiver/audio_receiver_unittest.cc
index fcf8517..bb26cb9 100644
--- a/media/cast/audio_receiver/audio_receiver_unittest.cc
+++ b/media/cast/audio_receiver/audio_receiver_unittest.cc
@@ -10,13 +10,13 @@
 #include "media/cast/cast_defines.h"
 #include "media/cast/cast_environment.h"
 #include "media/cast/pacing/mock_paced_packet_sender.h"
+#include "media/cast/rtcp/test_rtcp_packet_builder.h"
 #include "media/cast/test/fake_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace media {
 namespace cast {
 
-static const int kPacketSize = 1500;
 static const int64 kStartMillisecond = GG_INT64_C(12345678900000);
 
 class TestAudioEncoderCallback :
@@ -33,7 +33,7 @@
 
   void DeliverEncodedAudioFrame(scoped_ptr<EncodedAudioFrame> audio_frame,
                                 const base::TimeTicks& playout_time) {
-    EXPECT_EQ(0, audio_frame->frame_id);
+    EXPECT_EQ(expected_frame_id_, audio_frame->frame_id);
     EXPECT_EQ(kPcm16, audio_frame->codec);
     EXPECT_EQ(expected_playout_time_, playout_time);
     num_called_++;
@@ -87,8 +87,10 @@
 
   virtual ~AudioReceiverTest() {}
 
+  static void DummyDeletePacket(const uint8* packet) {};
+
   virtual void SetUp() {
-    payload_.assign(kPacketSize, 0);
+    payload_.assign(kIpPacketSize, 0);
     rtp_header_.is_key_frame = true;
     rtp_header_.frame_id = 0;
     rtp_header_.packet_id = 0;
@@ -111,6 +113,7 @@
 
 TEST_F(AudioReceiverTest, GetOnePacketEncodedframe) {
   Configure(true);
+  EXPECT_CALL(mock_transport_, SendRtcpPacket(testing::_)).Times(1);
 
   receiver_->IncomingParsedRtpPacket(payload_.data(),
       payload_.size(), rtp_header_);
@@ -127,6 +130,80 @@
   EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
 }
 
+TEST_F(AudioReceiverTest, MultiplePendingGetCalls) {
+  Configure(true);
+  EXPECT_CALL(mock_transport_, SendRtcpPacket(testing::_)).Times(2);
+
+  AudioFrameEncodedCallback frame_encoded_callback =
+      base::Bind(&TestAudioEncoderCallback::DeliverEncodedAudioFrame,
+                 test_audio_encoder_callback_.get());
+
+  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
+
+  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
+                                     rtp_header_);
+
+  EncodedAudioFrame audio_frame;
+  base::TimeTicks playout_time;
+  test_audio_encoder_callback_->SetExpectedResult(0, testing_clock_.NowTicks());
+
+  task_runner_->RunTasks();
+  EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
+
+  TestRtcpPacketBuilder rtcp_packet;
+
+  uint32 ntp_high;
+  uint32 ntp_low;
+  ConvertTimeToNtp(testing_clock_.NowTicks(), &ntp_high, &ntp_low);
+  rtcp_packet.AddSrWithNtp(audio_config_.feedback_ssrc, ntp_high, ntp_low,
+      rtp_header_.webrtc.header.timestamp);
+
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(20));
+
+  receiver_->IncomingPacket(rtcp_packet.Packet(), rtcp_packet.Length(),
+      base::Bind(AudioReceiverTest::DummyDeletePacket, rtcp_packet.Packet()));
+
+  // Make sure that we are not continuous and that the RTP timestamp represent a
+  // time in the future.
+  rtp_header_.is_key_frame = false;
+  rtp_header_.frame_id = 2;
+  rtp_header_.is_reference = true;
+  rtp_header_.reference_frame_id = 0;
+  rtp_header_.webrtc.header.timestamp = 960;
+  test_audio_encoder_callback_->SetExpectedResult(2,
+      testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(100));
+
+  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
+                                     rtp_header_);
+  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
+  task_runner_->RunTasks();
+
+  // Frame 2 should not come out at this point in time.
+  EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
+
+  // Through on one more pending callback.
+  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
+
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
+
+  task_runner_->RunTasks();
+  EXPECT_EQ(2, test_audio_encoder_callback_->number_times_called());
+
+  test_audio_encoder_callback_->SetExpectedResult(3, testing_clock_.NowTicks());
+
+  // Through on one more pending audio frame.
+  rtp_header_.frame_id = 3;
+  rtp_header_.is_reference = false;
+  rtp_header_.reference_frame_id = 0;
+  rtp_header_.webrtc.header.timestamp = 1280;
+  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
+                                     rtp_header_);
+
+  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
+  task_runner_->RunTasks();
+  EXPECT_EQ(3, test_audio_encoder_callback_->number_times_called());
+}
+
 // TODO(mikhal): Add encoded frames.
 TEST_F(AudioReceiverTest, GetRawFrame) {
 }
diff --git a/media/cast/cast.gyp b/media/cast/cast.gyp
index afa2f86..511ac29 100644
--- a/media/cast/cast.gyp
+++ b/media/cast/cast.gyp
@@ -5,6 +5,7 @@
 {
   'variables': {
     'include_tests%': 1,
+    'chromium_code': 1,
   },
   'targets': [
     {
@@ -31,6 +32,7 @@
             'cast_config',
             'cast_receiver.gyp:cast_receiver',
             'cast_sender.gyp:cast_sender',
+            'logging/logging.gyp:cast_logging',
             '<(DEPTH)/base/base.gyp:run_all_unittests',
             '<(DEPTH)/net/net.gyp:net',
             '<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/media/cast/congestion_control/congestion_control_unittest.cc b/media/cast/congestion_control/congestion_control_unittest.cc
index 1fd5efb..60c38b4 100644
--- a/media/cast/congestion_control/congestion_control_unittest.cc
+++ b/media/cast/congestion_control/congestion_control_unittest.cc
@@ -16,7 +16,6 @@
 static const int64 kStartMillisecond = GG_INT64_C(12345678900000);
 static const int64 kRttMs = 20;
 static const int64 kAckRateMs = 33;
-static const int64 kNackRateMs = 10;
 
 class CongestionControlTest : public ::testing::Test {
  protected:
diff --git a/media/cast/framer/cast_message_builder_unittest.cc b/media/cast/framer/cast_message_builder_unittest.cc
index 6275ad6..5bb38f7 100644
--- a/media/cast/framer/cast_message_builder_unittest.cc
+++ b/media/cast/framer/cast_message_builder_unittest.cc
@@ -172,7 +172,7 @@
   SetPacketId(5);
   InsertPacket();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(4, feedback_.num_missing_packets(0));
+  EXPECT_EQ(4u, feedback_.num_missing_packets(0));
 }
 
 TEST_F(CastMessageBuilderTest, CompleteFrameMissing) {
@@ -310,7 +310,7 @@
   SetPacketId(5);
   InsertPacket();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(4, feedback_.num_missing_packets(0));
+  EXPECT_EQ(4u, feedback_.num_missing_packets(0));
 }
 
 TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextFrame) {
@@ -326,7 +326,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(4, feedback_.num_missing_packets(0));
+  EXPECT_EQ(4u, feedback_.num_missing_packets(0));
   SetFrameId(1);
   SetMaxPacketId(2);
   SetPacketId(0);
@@ -335,7 +335,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(21 - 2, feedback_.num_missing_packets(0));
+  EXPECT_EQ(19u, feedback_.num_missing_packets(0));
 }
 
 TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextKey) {
@@ -351,7 +351,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(4, feedback_.num_missing_packets(0));
+  EXPECT_EQ(4u, feedback_.num_missing_packets(0));
   SetFrameId(1);
   SetMaxPacketId(0);
   SetPacketId(0);
@@ -360,7 +360,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.num_missing_packets(0));
+  EXPECT_EQ(0u, feedback_.num_missing_packets(0));
 }
 
 TEST_F(CastMessageBuilderTest, Reset) {
@@ -372,7 +372,7 @@
   // Should reset nack list state and request a key frame.
   cast_msg_builder_->UpdateCastMessage();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.num_missing_packets(0));
+  EXPECT_EQ(0u, feedback_.num_missing_packets(0));
 }
 
 TEST_F(CastMessageBuilderTest, DeltaAfterReset) {
@@ -382,7 +382,7 @@
   SetKeyFrame(true);
   InsertPacket();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.num_missing_packets(0));
+  EXPECT_EQ(0u, feedback_.num_missing_packets(0));
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   cast_msg_builder_->Reset();
@@ -402,19 +402,19 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.last_frame_acked());
+  EXPECT_EQ(0u, feedback_.last_frame_acked());
   SetFrameId(3);
   SetKeyFrame(false);
   SetReferenceFrameId(0);
   InsertPacket();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.last_frame_acked());
+  EXPECT_EQ(0u, feedback_.last_frame_acked());
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
   frame_id_map_.RemoveOldFrames(3);  // Simulate 3 being pulled for rendering.
   cast_msg_builder_->UpdateCastMessage();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(3, feedback_.last_frame_acked());
+  EXPECT_EQ(3u, feedback_.last_frame_acked());
 }
 
 TEST_F(CastMessageBuilderTest, InOrderRps) {
@@ -427,7 +427,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(0, feedback_.last_frame_acked());
+  EXPECT_EQ(0u, feedback_.last_frame_acked());
   SetFrameId(1);
   SetPacketId(0);
   SetMaxPacketId(1);
@@ -449,7 +449,7 @@
       base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
   cast_msg_builder_->UpdateCastMessage();
   EXPECT_TRUE(feedback_.triggered());
-  EXPECT_EQ(3, feedback_.last_frame_acked());
+  EXPECT_EQ(3u, feedback_.last_frame_acked());
   // Make an old frame complete - should not trigger an ack.
   SetFrameId(1);
   SetPacketId(1);
@@ -459,7 +459,7 @@
   testing_clock_.Advance(
       base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
   EXPECT_FALSE(feedback_.triggered());
-  EXPECT_EQ(3, feedback_.last_frame_acked());
+  EXPECT_EQ(3u, feedback_.last_frame_acked());
 }
 
 TEST_F(CastMessageBuilderTest, SlowDownAck) {
diff --git a/media/cast/framer/framer_unittest.cc b/media/cast/framer/framer_unittest.cc
index d4bc942..bfeb7de 100644
--- a/media/cast/framer/framer_unittest.cc
+++ b/media/cast/framer/framer_unittest.cc
@@ -10,8 +10,6 @@
 namespace media {
 namespace cast {
 
-static const int64 kFrameTimeMillisecond = 33;
-
 class FramerTest : public ::testing::Test {
  protected:
   FramerTest()
diff --git a/media/cast/logging/logging.cc b/media/cast/logging/logging.cc
new file mode 100644
index 0000000..ce68aa4
--- /dev/null
+++ b/media/cast/logging/logging.cc
@@ -0,0 +1,113 @@
+// Copyright 2013 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/cast/logging/logging.h"
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+
+namespace media {
+namespace cast {
+
+Logging::Logging(base::TickClock* clock)
+    : clock_(clock),
+      frame_map_(),
+      packet_map_(),
+      generic_map_(),
+      weak_factory_(this) {}
+
+Logging::~Logging() {}
+
+void Logging::InsertFrameEvent(CastLoggingEvent event,
+                               uint32 rtp_timestamp,
+                               uint8 frame_id) {
+  // Is this a new event?
+  FrameLogMap::iterator it = frame_map_.find(event);
+  if (it == frame_map_.end()) {
+    // Create new entry.
+    FrameLogData data(clock_);
+    data.Insert(rtp_timestamp, frame_id);
+    frame_map_.insert(std::make_pair(event, &data));
+  } else {
+    // Insert to existing entry.
+    it->second->Insert(rtp_timestamp, frame_id);
+  }
+}
+
+void Logging::InsertFrameEventWithSize(CastLoggingEvent event,
+                                       uint32 rtp_timestamp,
+                                       uint8 frame_id,
+                                       int size) {
+  // Is this a new event?
+  FrameLogMap::iterator it = frame_map_.find(event);
+  if (it == frame_map_.end()) {
+    // Create new entry.
+    FrameLogData data(clock_);
+    data.InsertWithSize(rtp_timestamp, frame_id, size);
+    frame_map_.insert(std::make_pair(event, &data));
+  } else {
+    // Insert to existing entry.
+    it->second->InsertWithSize(rtp_timestamp, frame_id, size);
+  }
+}
+
+void Logging::InsertFrameEventWithDelay(CastLoggingEvent event,
+                                        uint32 rtp_timestamp,
+                                        uint8 frame_id,
+                                        base::TimeDelta delay) {
+  // Is this a new event?
+  FrameLogMap::iterator it = frame_map_.find(event);
+  if (it == frame_map_.end()) {
+    // Create new entry.
+    FrameLogData data(clock_);
+    data.InsertWithDelay(rtp_timestamp, frame_id, delay);
+    frame_map_.insert(std::make_pair(event, &data));
+  } else {
+    // Insert to existing entry.
+    it->second->InsertWithDelay(rtp_timestamp, frame_id, delay);
+  }
+}
+
+void Logging::InsertPacketEvent(CastLoggingEvent event,
+                                uint32 rtp_timestamp,
+                                uint8 frame_id,
+                                uint16 packet_id,
+                                uint16 max_packet_id,
+                                int size) {
+  // Is this a new event?
+  PacketLogMap::iterator it = packet_map_.find(event);
+  if (it == packet_map_.end()) {
+    // Create new entry.
+    PacketLogData data(clock_);
+    data.Insert(rtp_timestamp, frame_id, packet_id, max_packet_id, size);
+    packet_map_.insert(std::make_pair(event, &data));
+  } else {
+    // Insert to existing entry.
+    it->second->Insert(rtp_timestamp, frame_id, packet_id, max_packet_id, size);
+  }
+}
+
+void Logging::InsertGenericEvent(CastLoggingEvent event, int value) {
+  // Is this a new event?
+  GenericLogMap::iterator it = generic_map_.find(event);
+  if (it == generic_map_.end()) {
+    // Create new entry.
+    GenericLogData data(clock_);
+    data.Insert(value);
+    generic_map_.insert(std::make_pair(event, &data));
+  } else {
+    // Insert to existing entry.
+    it->second->Insert(value);
+  }
+}
+
+void Logging::Reset() {
+  frame_map_.clear();
+  packet_map_.clear();
+  generic_map_.clear();
+}
+}  // namespace cast
+}  // namespace media
+
diff --git a/media/cast/logging/logging.gyp b/media/cast/logging/logging.gyp
new file mode 100644
index 0000000..d195348
--- /dev/null
+++ b/media/cast/logging/logging.gyp
@@ -0,0 +1,27 @@
+# Copyright 2013 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': 'cast_logging',
+      'type': 'static_library',
+      'include_dirs': [
+        '<(DEPTH)/',
+      ],
+      'sources': [
+        'logging.cc',
+        'logging.h',
+        'logging_defines.h',
+        'logging_internal.cc',
+        'logging_internal.h',
+      ],
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/base/base.gyp:test_support_base',
+      ],
+    },
+  ], # targets
+}
diff --git a/media/cast/logging/logging.h b/media/cast/logging/logging.h
new file mode 100644
index 0000000..426fe3a
--- /dev/null
+++ b/media/cast/logging/logging.h
@@ -0,0 +1,92 @@
+// Copyright 2013 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_CAST_LOGGING_LOGGING_H_
+#define MEDIA_CAST_LOGGING_LOGGING_H_
+
+// Generic class that handles event logging for the cast library.
+// Logging has three possible forms:
+// 1. [default] Raw data accessible by the application.
+// 2. [optional] UMA stats.
+// 3. [optional] Tracing.
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "media/cast/logging/logging_defines.h"
+#include "media/cast/logging/logging_internal.h"
+
+namespace media {
+namespace cast {
+
+// Store all log types in a map based on the event.
+typedef std::map<CastLoggingEvent, linked_ptr<FrameLogData> > FrameLogMap;
+typedef std::map<CastLoggingEvent, linked_ptr<PacketLogData> > PacketLogMap;
+typedef std::map<CastLoggingEvent, linked_ptr<GenericLogData> > GenericLogMap;
+
+
+// This class is not thread safe, and should only be called from the main
+// thread.
+class Logging : public base::NonThreadSafe,
+                public base::SupportsWeakPtr<Logging> {
+ public:
+  // When tracing is enabled - all events will be added to the trace.
+  Logging(base::TickClock* clock);
+  ~Logging();
+  // Inform of new event: three types of events: frame, packets and generic.
+  // Frame events can be inserted with different parameters.
+  void InsertFrameEvent(CastLoggingEvent event,
+                        uint32 rtp_timestamp,
+                        uint8 frame_id);
+  // Size - Inserting the size implies that this is an encoded frame.
+  void InsertFrameEventWithSize(CastLoggingEvent event,
+                                uint32 rtp_timestamp,
+                                uint8 frame_id,
+                                int frame_size);
+  // Render/playout delay
+  void InsertFrameEventWithDelay(CastLoggingEvent event,
+                                 uint32 rtp_timestamp,
+                                 uint8 frame_id,
+                                 base::TimeDelta delay);
+
+  // Insert a packet event.
+  void InsertPacketEvent(CastLoggingEvent event,
+                         uint32 rtp_timestamp,
+                         uint8 frame_id,
+                         uint16 packet_id,
+                         uint16 max_packet_id,
+                         int size);
+
+  void InsertGenericEvent(CastLoggingEvent event, int value);
+
+  // Get log data.
+  void GetRawFrameData(FrameLogMap frame_data);
+  void GetRawPacketData(PacketLogMap packet_data);
+  void GetRawGenericData(GenericLogMap generic_data);
+
+  // Reset all log data (not flags).
+  void Reset();
+
+ private:
+  base::WeakPtrFactory<Logging> weak_factory_;
+  base::TickClock* const clock_;  // Not owned by this class.
+  FrameLogMap frame_map_;
+  PacketLogMap packet_map_;
+  GenericLogMap generic_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(Logging);
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_LOGGING_LOGGING_H_
+
diff --git a/media/cast/logging/logging_defines.h b/media/cast/logging/logging_defines.h
new file mode 100644
index 0000000..724216d
--- /dev/null
+++ b/media/cast/logging/logging_defines.h
@@ -0,0 +1,91 @@
+// Copyright 2013 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_CAST_LOGGING_LOGGING_DEFINES_H_
+#define MEDIA_CAST_LOGGING_LOGGING_DEFINES_H_
+
+#include "base/logging.h"
+
+namespace media {
+namespace cast {
+
+enum CastLoggingEvent {
+  // Generic events.
+  kRtt,
+  kPacketLoss,
+  kJitter,
+  kAckReceived,
+  kAckSent,
+  kLastEvent,
+  // Audio sender.
+  kAudioFrameCaptured,
+  kAudioFrameEncoded,
+  // Audio receiver.
+  kAudioPlayoutDelay,
+  kAudioFrameDecoded,
+  // Video sender.
+  kVideoFrameCaptured,
+  kVideoFrameSentToEncoder,
+  kVideoFrameEncoded,
+  // Video receiver.
+  kVideoFrameDecoded,
+  kVideoRenderDelay,
+  // Send-side packet events.
+  kPacketSentToPacer,
+  kPacketSentToNetwork,
+  kPacketRetransmited,
+  // Receive-side packet events.
+  kPacketReceived,
+};
+
+std::string CastEnumToString(CastLoggingEvent event) {
+  switch (event) {
+    case(kRtt):
+      return "Rtt";
+    case(kPacketLoss):
+      return "PacketLoss";
+    case(kJitter):
+      return "Jitter";
+    case(kAckReceived):
+      return "AckReceived";
+    case(kAckSent):
+      return "AckSent";
+    case(kLastEvent):
+      return "LastEvent";
+    case(kAudioFrameCaptured):
+      return "AudioFrameCaptured";
+    case(kAudioFrameEncoded):
+      return "AudioFrameEncoded";
+    case(kAudioPlayoutDelay):
+      return "AudioPlayoutDelay";
+    case(kAudioFrameDecoded):
+      return "AudioFrameDecoded";
+    case(kVideoFrameCaptured):
+      return "VideoFrameCaptured";
+    case(kVideoFrameSentToEncoder):
+      return "VideoFrameSentToEncoder";
+    case(kVideoFrameEncoded):
+      return "VideoFrameEncoded";
+    case(kVideoFrameDecoded):
+      return "VideoFrameDecoded";
+    case(kVideoRenderDelay):
+      return "VideoRenderDelay";
+    case(kPacketSentToPacer):
+      return "PacketSentToPacer";
+    case(kPacketSentToNetwork):
+      return "PacketSentToNetwork";
+    case(kPacketRetransmited):
+      return "PacketRetransmited";
+    case(kPacketReceived):
+      return "PacketReceived";
+    default:
+      NOTREACHED();
+      return "";
+  }
+}
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_LOGGING_LOGGING_DEFINES_H_
diff --git a/media/cast/logging/logging_internal.cc b/media/cast/logging/logging_internal.cc
new file mode 100644
index 0000000..aec0c96
--- /dev/null
+++ b/media/cast/logging/logging_internal.cc
@@ -0,0 +1,79 @@
+// Copyright 2013 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/cast/logging/logging_internal.h"
+
+namespace media {
+namespace cast {
+
+FrameLogData::FrameLogData(base::TickClock* clock)
+    : clock_(clock),
+      frame_map_() {}
+
+FrameLogData::~FrameLogData() {}
+
+void FrameLogData::Insert(uint32 rtp_timestamp, uint8 frame_id) {
+  FrameEvent info;
+  InsertBase(rtp_timestamp, frame_id, info);
+}
+
+void FrameLogData::InsertWithSize(
+      uint32 rtp_timestamp, uint8 frame_id, int size) {
+  FrameEvent info;
+  info.size = size;
+  InsertBase(rtp_timestamp, frame_id, info);
+}
+
+void FrameLogData::InsertWithDelay(
+    uint32 rtp_timestamp, uint8 frame_id, base::TimeDelta delay) {
+  FrameEvent info;
+  info.delay_delta = delay;
+  InsertBase(rtp_timestamp, frame_id, info);
+}
+
+void FrameLogData::InsertBase(
+    uint32 rtp_timestamp, uint8 frame_id, FrameEvent info) {
+  info.timestamp = clock_->NowTicks();
+  info.frame_id = frame_id;
+  frame_map_.insert(std::make_pair(rtp_timestamp, info));
+}
+
+PacketLogData::PacketLogData(base::TickClock* clock)
+    : clock_(clock),
+      packet_map_() {}
+
+PacketLogData::~PacketLogData() {}
+
+void PacketLogData::Insert(uint32 rtp_timestamp,
+    uint8 frame_id, uint16 packet_id, uint16 max_packet_id, int size) {
+  PacketEvent info;
+  info.size = size;
+  info.max_packet_id = max_packet_id;
+  info.frame_id = frame_id;
+  info.timestamp = clock_->NowTicks();
+  // Is this a new frame?
+  PacketMap::iterator it = packet_map_.find(rtp_timestamp);
+  if (it == packet_map_.end()) {
+    // New rtp_timestamp id - create base packet map.
+    BasePacketMap base_map;
+    base_map.insert(std::make_pair(packet_id, info));
+    packet_map_.insert(std::make_pair(rtp_timestamp, base_map));
+  } else {
+    // Existing rtp_timestamp.
+    it->second.insert(std::make_pair(packet_id, info));
+  }
+}
+
+GenericLogData::GenericLogData(base::TickClock* clock)
+    : clock_(clock) {}
+
+GenericLogData::~GenericLogData() {}
+
+void GenericLogData::Insert(int data) {
+  data_.push_back(data);
+  timestamp_.push_back(clock_->NowTicks());
+}
+
+}  // namespace cast
+}  // namespace media
diff --git a/media/cast/logging/logging_internal.h b/media/cast/logging/logging_internal.h
new file mode 100644
index 0000000..0f787600
--- /dev/null
+++ b/media/cast/logging/logging_internal.h
@@ -0,0 +1,95 @@
+// Copyright 2013 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_CAST_LOGGING_LOGGING_INTERNAL_H_
+#define MEDIA_CAST_LOGGING_LOGGING_INTERNAL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+
+namespace media {
+namespace cast {
+
+// TODO(mikhal): Consider storing only the delta time and not absolute time.
+struct FrameEvent {
+  uint8 frame_id;
+  int size;
+  base::TimeTicks timestamp;
+  base::TimeDelta delay_delta;  // render/playout delay.
+};
+
+struct PacketEvent {
+  uint8 frame_id;
+  int max_packet_id;
+  int size;
+  base::TimeTicks timestamp;
+};
+
+// Frame and packet maps are sorted based on the rtp_timestamp.
+typedef std::map<uint32, FrameEvent> FrameMap;
+typedef std::map<uint16, PacketEvent> BasePacketMap;
+typedef std::map<uint32, BasePacketMap> PacketMap;
+
+class FrameLogData {
+ public:
+  explicit FrameLogData(base::TickClock* clock);
+  ~FrameLogData();
+  void Insert(uint32 rtp_timestamp, uint8 frame_id);
+  // Include size for encoded images (compute bitrate),
+  void InsertWithSize(uint32 rtp_timestamp, uint8 frame_id, int size);
+  // Include playout/render delay info.
+  void InsertWithDelay(
+      uint32 rtp_timestamp, uint8 frame_id, base::TimeDelta delay);
+  void Reset();
+
+ private:
+  void InsertBase(uint32 rtp_timestamp, uint8 frame_id, FrameEvent info);
+
+  base::TickClock* const clock_;  // Not owned by this class.
+  FrameMap frame_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameLogData);
+};
+
+// TODO(mikhal): Should be able to handle packet bursts.
+class PacketLogData {
+ public:
+  explicit PacketLogData(base::TickClock* clock);
+  ~PacketLogData();
+  void Insert(uint32 rtp_timestamp, uint8 frame_id, uint16 packet_id,
+      uint16 max_packet_id, int size);
+  void Reset();
+
+ private:
+  base::TickClock* const clock_;  // Not owned by this class.
+  PacketMap packet_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(PacketLogData);
+};
+
+class GenericLogData {
+ public:
+  explicit GenericLogData(base::TickClock* clock);
+  ~GenericLogData();
+  void Insert(int value);
+  void Reset();
+
+ private:
+  base::TickClock* const clock_;  // Not owned by this class.
+  std::vector<int> data_;
+  std::vector<base::TimeTicks> timestamp_;
+
+  DISALLOW_COPY_AND_ASSIGN(GenericLogData);
+};
+
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_LOGGING_LOGGING_INTERNAL_H_
diff --git a/media/cast/pacing/paced_sender_unittest.cc b/media/cast/pacing/paced_sender_unittest.cc
index f9e88b4..8ae4ea8 100644
--- a/media/cast/pacing/paced_sender_unittest.cc
+++ b/media/cast/pacing/paced_sender_unittest.cc
@@ -26,7 +26,7 @@
     PacketList::const_iterator it = packets.begin();
     for (; it != packets.end(); ++it) {
       EXPECT_FALSE(expected_packet_size_.empty());
-      int expected_packet_size = expected_packet_size_.front();
+      size_t expected_packet_size = expected_packet_size_.front();
       expected_packet_size_.pop_front();
       EXPECT_EQ(expected_packet_size, it->size());
     }
diff --git a/media/cast/rtcp/test_rtcp_packet_builder.cc b/media/cast/rtcp/test_rtcp_packet_builder.cc
index 56ddd8a..3a6a774 100644
--- a/media/cast/rtcp/test_rtcp_packet_builder.cc
+++ b/media/cast/rtcp/test_rtcp_packet_builder.cc
@@ -25,6 +25,19 @@
   big_endian_writer_.WriteU32(kSendOctetCount);
 }
 
+void TestRtcpPacketBuilder::AddSrWithNtp(uint32 sender_ssrc,
+                                         uint32 ntp_high,
+                                         uint32 ntp_low,
+                                         uint32 rtp_timestamp) {
+  AddRtcpHeader(200, 0);
+  big_endian_writer_.WriteU32(sender_ssrc);
+  big_endian_writer_.WriteU32(ntp_high);
+  big_endian_writer_.WriteU32(ntp_low);
+  big_endian_writer_.WriteU32(rtp_timestamp);
+  big_endian_writer_.WriteU32(kSendPacketCount);
+  big_endian_writer_.WriteU32(kSendOctetCount);
+}
+
 void TestRtcpPacketBuilder::AddRr(uint32 sender_ssrc,
                                   int number_of_report_blocks) {
   AddRtcpHeader(201, number_of_report_blocks);
diff --git a/media/cast/rtcp/test_rtcp_packet_builder.h b/media/cast/rtcp/test_rtcp_packet_builder.h
index 4c5cc89..8c5479f 100644
--- a/media/cast/rtcp/test_rtcp_packet_builder.h
+++ b/media/cast/rtcp/test_rtcp_packet_builder.h
@@ -56,6 +56,8 @@
   TestRtcpPacketBuilder();
 
   void AddSr(uint32 sender_ssrc, int number_of_report_blocks);
+  void AddSrWithNtp(uint32 sender_ssrc, uint32 ntp_high, uint32 ntp_low,
+                    uint32 rtp_timestamp);
   void AddRr(uint32 sender_ssrc, int number_of_report_blocks);
   void AddRb(uint32 rtp_ssrc);
   void AddSdesCname(uint32 sender_ssrc, const std::string& c_name);
diff --git a/media/cast/rtp_common/rtp_defines.h b/media/cast/rtp_common/rtp_defines.h
index dc64c36..ca5ca94 100644
--- a/media/cast/rtp_common/rtp_defines.h
+++ b/media/cast/rtp_common/rtp_defines.h
@@ -16,7 +16,7 @@
 const uint8 kRtpMarkerBitMask = 0x80;
 
 struct RtpCastHeader {
-  void InitRTPVideoHeaderCast() {
+  RtpCastHeader() {
     is_key_frame = false;
     frame_id = 0;
     packet_id = 0;
diff --git a/media/cast/rtp_receiver/rtp_parser/rtp_parser_unittest.cc b/media/cast/rtp_receiver/rtp_parser/rtp_parser_unittest.cc
index 8ce2f0f..a8ec6b3 100644
--- a/media/cast/rtp_receiver/rtp_parser/rtp_parser_unittest.cc
+++ b/media/cast/rtp_receiver/rtp_parser/rtp_parser_unittest.cc
@@ -14,7 +14,6 @@
 namespace cast {
 
 static const size_t kPacketLength = 1500;
-static const size_t kCastRtpLength = 7;
 static const int kTestPayloadType = 127;
 static const uint32 kTestSsrc = 1234;
 static const uint32 kTestTimestamp = 111111;
@@ -71,7 +70,6 @@
   virtual ~RtpParserTest() {}
 
   virtual void SetUp() {
-    cast_header_.InitRTPVideoHeaderCast();
     cast_header_.is_reference = true;
     cast_header_.reference_frame_id = kRefFrameId;
     packet_builder_.SetSsrc(kTestSsrc);
diff --git a/media/cast/rtp_sender/rtp_packetizer/rtp_packetizer_unittest.cc b/media/cast/rtp_sender/rtp_packetizer/rtp_packetizer_unittest.cc
index 34ba266..b5dd4d7 100644
--- a/media/cast/rtp_sender/rtp_packetizer/rtp_packetizer_unittest.cc
+++ b/media/cast/rtp_sender/rtp_packetizer/rtp_packetizer_unittest.cc
@@ -19,12 +19,9 @@
 static const int kPayload = 127;
 static const uint32 kTimestampMs = 10;
 static const uint16 kSeqNum = 33;
-static const int kTimeOffset = 22222;
 static const int kMaxPacketLength = 1500;
-static const bool kMarkerBit = true;
 static const int kSsrc = 0x12345;
 static const unsigned int kFrameSize = 5000;
-static const int kTotalHeaderLength = 19;
 static const int kMaxPacketStorageTimeMs = 300;
 static const int64 kStartMillisecond = 0;
 
@@ -64,7 +61,7 @@
   }
 
   virtual bool SendPackets(const PacketList& packets) OVERRIDE {
-    EXPECT_EQ(expected_number_of_packets_, packets.size());
+    EXPECT_EQ(expected_number_of_packets_, static_cast<int>(packets.size()));
     PacketList::const_iterator it = packets.begin();
     for (; it != packets.end(); ++it) {
       ++packets_sent_;
@@ -146,7 +143,7 @@
   EXPECT_FALSE(rtp_packetizer_->send_packets_count());
   EXPECT_FALSE(rtp_packetizer_->send_octet_count());
   // Insert packets at varying lengths.
-  unsigned int expected_num_of_packets = kFrameSize / kMaxPacketLength + 1;
+  int expected_num_of_packets = kFrameSize / kMaxPacketLength + 1;
   transport_->SetExpectedNumberOfPackets(expected_num_of_packets);
 
   testing_clock_.Advance(base::TimeDelta::FromMilliseconds(kTimestampMs));
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 724695b..3caa6e7 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -35,6 +35,8 @@
 static const int kSoundFrequency = 1234;  // Frequency of sinusoid wave.
 static const int kVideoWidth = 1280;
 static const int kVideoHeight = 720;
+static const int kCommonRtpHeaderLength = 12;
+static const uint8 kCastReferenceFrameIdBitReset = 0xDF;  // Mask is 0x40.
 
 // Since the video encoded and decoded an error will be introduced; when
 // comparing individual pixels the error can be quite large; we allow a PSNR of
@@ -58,6 +60,7 @@
       : packet_receiver_(NULL),
         send_packets_(true),
         drop_packets_belonging_to_odd_frames_(false),
+        reset_reference_frame_id_(false),
         cast_environment_(cast_environment) {
   }
 
@@ -91,6 +94,10 @@
       }
       uint8* packet_copy = new uint8[packet.size()];
       memcpy(packet_copy, packet.data(), packet.size());
+      if (reset_reference_frame_id_) {
+        // Reset the is_reference bit in the cast header.
+        packet_copy[kCommonRtpHeaderLength] &= kCastReferenceFrameIdBitReset;
+      }
       packet_receiver_->ReceivedPacket(packet_copy, packet.size(),
           base::Bind(PacketReceiver::DeletePacket, packet_copy));
     }
@@ -105,10 +112,15 @@
     drop_packets_belonging_to_odd_frames_ = true;
   }
 
+  void AlwaysResetReferenceFrameId() {
+    reset_reference_frame_id_ = true;
+  }
+
  private:
   PacketReceiver* packet_receiver_;
   bool send_packets_;
   bool drop_packets_belonging_to_odd_frames_;
+  bool reset_reference_frame_id_;
   scoped_refptr<CastEnvironment> cast_environment_;
 };
 
@@ -271,9 +283,9 @@
 
     // We need to convert our "coded" audio frame to our raw format.
     std::vector<int16> output_audio_samples;
-    int number_of_samples = audio_frame->data.size() / 2;
+    size_t number_of_samples = audio_frame->data.size() / 2;
 
-    for (int i = 0; i < number_of_samples; ++i) {
+    for (size_t i = 0; i < number_of_samples; ++i) {
       uint16 sample = (audio_frame->data[1 + i * sizeof(uint16)]) +
             (static_cast<uint16>(audio_frame->data[i * sizeof(uint16)]) << 8);
       output_audio_samples.push_back(static_cast<int16>(sample));
@@ -517,10 +529,10 @@
   scoped_refptr<FrameInput> frame_input_;
   scoped_refptr<FrameReceiver> frame_receiver_;
 
-  double audio_angle_;
-
   scoped_refptr<TestReceiverAudioCallback> test_receiver_audio_callback_;
   scoped_refptr<TestReceiverVideoCallback> test_receiver_video_callback_;
+
+  double audio_angle_;
 };
 
 // Audio and video test without packet loss using raw PCM 16 audio "codec";
@@ -586,7 +598,7 @@
   }
   std::cout << std::endl;
 
-  RunTasks(67);  // Empty the receiver pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the receiver pipeline.
   EXPECT_EQ(i - 1, test_receiver_audio_callback_->number_times_called());
   EXPECT_EQ(i, test_receiver_video_callback_->number_times_called());
 }
@@ -618,7 +630,7 @@
         base::Bind(&TestReceiverAudioCallback::CheckCodedPcmAudioFrame,
             test_receiver_audio_callback_));
   }
-  RunTasks(67);  // Empty the receiver pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the receiver pipeline.
   EXPECT_EQ(100, test_receiver_audio_callback_->number_times_called());
 }
 
@@ -659,7 +671,7 @@
               test_receiver_audio_callback_));
     }
   }
-  RunTasks(67);  // Empty the receiver pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the receiver pipeline.
   EXPECT_EQ(i - 1, test_receiver_audio_callback_->number_times_called());
 }
 
@@ -734,7 +746,7 @@
             test_receiver_video_callback_));
     video_start++;
   }
-  RunTasks(67);  // Empty the receiver pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the receiver pipeline.
   EXPECT_EQ(j - number_of_audio_frames_to_ignore,
             test_receiver_audio_callback_->number_times_called());
   EXPECT_EQ(j, test_receiver_video_callback_->number_times_called());
@@ -786,7 +798,7 @@
       base::Bind(&TestReceiverVideoCallback::CheckVideoFrame,
           test_receiver_video_callback_));
 
-  RunTasks(67);  // Empty the receiver pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the receiver pipeline.
   EXPECT_EQ(2, test_receiver_video_callback_->number_times_called());
 }
 
@@ -821,10 +833,37 @@
     video_start++;
   }
   std::cout << std::endl;
-  RunTasks(67);  // Empty the pipeline.
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
   EXPECT_EQ(i / 2, test_receiver_video_callback_->number_times_called());
 }
 
+TEST_F(End2EndTest, ResetReferenceFrameId) {
+  SetupConfig(kOpus, kAudioSamplingFrequency, false, 3);
+  video_sender_config_.rtp_max_delay_ms = 67;
+  video_receiver_config_.rtp_max_delay_ms = 67;
+  Create();
+  sender_to_receiver_.AlwaysResetReferenceFrameId();
+
+  int frames_counter = 0;
+  for (; frames_counter < 20; ++frames_counter) {
+    const base::TimeTicks send_time = testing_clock_.NowTicks();
+    SendVideoFrame(frames_counter, send_time);
+
+    test_receiver_video_callback_->AddExpectedResult(frames_counter,
+        video_sender_config_.width, video_sender_config_.height, send_time);
+
+    // GetRawVideoFrame will not return the frame until we are close to the
+    // time in which we should render the frame.
+    frame_receiver_->GetRawVideoFrame(
+        base::Bind(&TestReceiverVideoCallback::CheckVideoFrame,
+                   test_receiver_video_callback_));
+    RunTasks(kFrameTimerMs);
+  }
+  RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
+  EXPECT_EQ(frames_counter,
+            test_receiver_video_callback_->number_times_called());
+}
+
 // TODO(pwestin): Add repeatable packet loss test.
 // TODO(pwestin): Add test for misaligned send get calls.
 // TODO(pwestin): Add more tests that does not resample.
diff --git a/media/cast/video_receiver/codecs/vp8/vp8_decoder.cc b/media/cast/video_receiver/codecs/vp8/vp8_decoder.cc
index 23125b2..26113cd 100644
--- a/media/cast/video_receiver/codecs/vp8/vp8_decoder.cc
+++ b/media/cast/video_receiver/codecs/vp8/vp8_decoder.cc
@@ -64,14 +64,15 @@
          decoded_frame->y_plane.length);
 
   decoded_frame->u_plane.stride = img->stride[VPX_PLANE_U];
-  decoded_frame->u_plane.length = img->stride[VPX_PLANE_U] * img->d_h;
+  decoded_frame->u_plane.length = img->stride[VPX_PLANE_U] * (img->d_h + 1) / 2;
   decoded_frame->u_plane.data = new uint8[decoded_frame->u_plane.length];
   memcpy(decoded_frame->u_plane.data, img->planes[VPX_PLANE_U],
          decoded_frame->u_plane.length);
 
   decoded_frame->v_plane.stride = img->stride[VPX_PLANE_V];
-  decoded_frame->v_plane.length = img->stride[VPX_PLANE_V] * img->d_h;
+  decoded_frame->v_plane.length = img->stride[VPX_PLANE_V] * (img->d_h + 1) / 2;
   decoded_frame->v_plane.data = new uint8[decoded_frame->v_plane.length];
+
   memcpy(decoded_frame->v_plane.data, img->planes[VPX_PLANE_V],
          decoded_frame->v_plane.length);
 
diff --git a/media/cast/video_receiver/video_decoder_unittest.cc b/media/cast/video_receiver/video_decoder_unittest.cc
index 77f3efd..cb40e12 100644
--- a/media/cast/video_receiver/video_decoder_unittest.cc
+++ b/media/cast/video_receiver/video_decoder_unittest.cc
@@ -30,7 +30,8 @@
   VideoReceiverConfig config_;
 };
 
-TEST_F(VideoDecoderTest, SizeZero) {
+// TODO(pwestin): EXPECT_DEATH tests can not pass valgrind.
+TEST_F(VideoDecoderTest, DISABLED_SizeZero) {
   EncodedVideoFrame encoded_frame;
   I420VideoFrame video_frame;
   base::TimeTicks render_time;
@@ -41,7 +42,8 @@
      "Empty video frame");
 }
 
-TEST_F(VideoDecoderTest, InvalidCodec) {
+// TODO(pwestin): EXPECT_DEATH tests can not pass valgrind.
+TEST_F(VideoDecoderTest, DISABLED_InvalidCodec) {
   EncodedVideoFrame encoded_frame;
   I420VideoFrame video_frame;
   base::TimeTicks render_time;
diff --git a/media/cdm/ppapi/cdm_adapter.cc b/media/cdm/ppapi/cdm_adapter.cc
index 6814a5e..006ce09 100644
--- a/media/cdm/ppapi/cdm_adapter.cc
+++ b/media/cdm/ppapi/cdm_adapter.cc
@@ -46,8 +46,7 @@
 
   input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
   input_buffer->data_size = encrypted_block_info.data_size;
-  PP_DCHECK(encrypted_buffer.size() >=
-            static_cast<uint32_t>(input_buffer->data_size));
+  PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size);
   input_buffer->data_offset = encrypted_block_info.data_offset;
 
   PP_DCHECK(encrypted_block_info.key_id_size <=
@@ -107,6 +106,26 @@
   }
 }
 
+PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
+    cdm::AudioFormat format) {
+  switch (format) {
+    case cdm::kAudioFormatU8:
+      return PP_DECRYPTEDSAMPLEFORMAT_U8;
+    case cdm::kAudioFormatS16:
+      return PP_DECRYPTEDSAMPLEFORMAT_S16;
+    case cdm::kAudioFormatS32:
+      return PP_DECRYPTEDSAMPLEFORMAT_S32;
+    case cdm::kAudioFormatF32:
+      return PP_DECRYPTEDSAMPLEFORMAT_F32;
+    case cdm::kAudioFormatPlanarS16:
+      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
+    case cdm::kAudioFormatPlanarF32:
+      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
+    default:
+      return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
+  }
+}
+
 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
     PP_AudioCodec codec) {
   switch (codec) {
@@ -196,7 +215,11 @@
       query_output_protection_in_progress_(false),
 #endif
       allocator_(this),
-      cdm_(NULL) {
+      cdm_(NULL),
+      deferred_initialize_audio_decoder_(false),
+      deferred_audio_decoder_config_id_(0),
+      deferred_initialize_video_decoder_(false),
+      deferred_video_decoder_config_id_(0) {
   callback_factory_.Initialize(this);
 }
 
@@ -263,12 +286,12 @@
   }
 
   const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map());
-  int key_size = key.ByteLength();
+  const uint32_t key_size = key.ByteLength();
   const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map());
-  int init_data_size = init_data.ByteLength();
+  const uint32_t init_data_size = init_data.ByteLength();
   PP_DCHECK(!init_data_ptr == !init_data_size);
 
-  if (!key_ptr || key_size <= 0) {
+  if (!key_ptr || !key_size) {
     SendUnknownKeyError(key_system_, session_id);
     return;
   }
@@ -334,6 +357,8 @@
 void CdmAdapter::InitializeAudioDecoder(
     const PP_AudioDecoderConfig& decoder_config,
     pp::Buffer_Dev extra_data_buffer) {
+  PP_DCHECK(!deferred_initialize_audio_decoder_);
+  PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
   cdm::Status status = cdm::kSessionError;
   if (cdm_) {
     cdm::AudioDecoderConfig cdm_decoder_config;
@@ -344,11 +369,16 @@
     cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
     cdm_decoder_config.extra_data =
         static_cast<uint8_t*>(extra_data_buffer.data());
-    cdm_decoder_config.extra_data_size =
-        static_cast<int32_t>(extra_data_buffer.size());
+    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
     status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
   }
 
+  if (status == cdm::kDeferredInitialization) {
+    deferred_initialize_audio_decoder_ = true;
+    deferred_audio_decoder_config_id_ = decoder_config.request_id;
+    return;
+  }
+
   CallOnMain(callback_factory_.NewCallback(
       &CdmAdapter::DecoderInitializeDone,
       PP_DECRYPTORSTREAMTYPE_AUDIO,
@@ -359,6 +389,8 @@
 void CdmAdapter::InitializeVideoDecoder(
     const PP_VideoDecoderConfig& decoder_config,
     pp::Buffer_Dev extra_data_buffer) {
+  PP_DCHECK(!deferred_initialize_video_decoder_);
+  PP_DCHECK(deferred_video_decoder_config_id_ == 0);
   cdm::Status status = cdm::kSessionError;
   if (cdm_) {
     cdm::VideoDecoderConfig cdm_decoder_config;
@@ -372,11 +404,16 @@
     cdm_decoder_config.coded_size.height = decoder_config.height;
     cdm_decoder_config.extra_data =
         static_cast<uint8_t*>(extra_data_buffer.data());
-    cdm_decoder_config.extra_data_size =
-        static_cast<int32_t>(extra_data_buffer.size());
+    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
     status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
   }
 
+  if (status == cdm::kDeferredInitialization) {
+    deferred_initialize_video_decoder_ = true;
+    deferred_video_decoder_config_id_ = decoder_config.request_id;
+    return;
+  }
+
   CallOnMain(callback_factory_.NewCallback(
       &CdmAdapter::DecoderInitializeDone,
       PP_DECRYPTORSTREAMTYPE_VIDEO,
@@ -461,7 +498,7 @@
   }
 }
 
-cdm::Buffer* CdmAdapter::Allocate(int32_t capacity) {
+cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
   return allocator_.Allocate(capacity);
 }
 
@@ -485,9 +522,9 @@
 }
 
 void CdmAdapter::SendKeyMessage(
-    const char* session_id, int32_t session_id_length,
-    const char* message, int32_t message_length,
-    const char* default_url, int32_t default_url_length) {
+    const char* session_id, uint32_t session_id_length,
+    const char* message, uint32_t message_length,
+    const char* default_url, uint32_t default_url_length) {
   PP_DCHECK(!key_system_.empty());
   PostOnMain(callback_factory_.NewCallback(
       &CdmAdapter::KeyMessage,
@@ -498,7 +535,7 @@
 }
 
 void CdmAdapter::SendKeyError(const char* session_id,
-                              int32_t session_id_length,
+                              uint32_t session_id_length,
                               cdm::MediaKeyError error_code,
                               uint32_t system_code) {
   SendKeyErrorInternal(key_system_,
@@ -675,30 +712,32 @@
                                 const PP_DecryptTrackingInfo& tracking_info) {
   PP_DCHECK(result == PP_OK);
 
-  PP_DecryptedBlockInfo decrypted_block_info;
-  decrypted_block_info.tracking_info = tracking_info;
-  decrypted_block_info.tracking_info.timestamp = 0;
-  decrypted_block_info.tracking_info.buffer_id = 0;
-  decrypted_block_info.data_size = 0;
-  decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
+  PP_DecryptedSampleInfo decrypted_sample_info;
+  decrypted_sample_info.tracking_info = tracking_info;
+  decrypted_sample_info.tracking_info.timestamp = 0;
+  decrypted_sample_info.tracking_info.buffer_id = 0;
+  decrypted_sample_info.data_size = 0;
+  decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
 
   pp::Buffer_Dev buffer;
 
-  if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
+  if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
     PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
     if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
       PP_NOTREACHED();
-      decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
+      decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
     } else {
       PpbBuffer* ppb_buffer =
           static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
       buffer = ppb_buffer->buffer_dev();
-      decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
-      decrypted_block_info.data_size = ppb_buffer->Size();
+      decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
+      decrypted_sample_info.data_size = ppb_buffer->Size();
+      decrypted_sample_info.format =
+          CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
     }
   }
 
-  pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info);
+  pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
 }
 
 bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
@@ -711,7 +750,7 @@
 
   PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
 
-  for (int i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
+  for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
     int plane_height = (i == cdm::VideoFrame::kYPlane) ?
         video_frame->Size().height : (video_frame->Size().height + 1) / 2;
     cdm::VideoFrame::VideoPlane plane =
@@ -726,8 +765,8 @@
 }
 
 void CdmAdapter::SendPlatformChallenge(
-    const char* service_id, int32_t service_id_length,
-    const char* challenge, int32_t challenge_length) {
+    const char* service_id, uint32_t service_id_length,
+    const char* challenge, uint32_t challenge_length) {
 #if defined(OS_CHROMEOS)
   PP_DCHECK(!challenge_in_progress_);
 
@@ -793,6 +832,32 @@
   cdm_->OnQueryOutputProtectionStatus(0, 0);
 }
 
+void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
+                                              cdm::Status decoder_status) {
+  switch (stream_type) {
+    case cdm::kStreamTypeAudio:
+      PP_DCHECK(deferred_initialize_audio_decoder_);
+      CallOnMain(
+          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
+                                        PP_DECRYPTORSTREAMTYPE_AUDIO,
+                                        deferred_audio_decoder_config_id_,
+                                        decoder_status == cdm::kSuccess));
+      deferred_initialize_audio_decoder_ = false;
+      deferred_audio_decoder_config_id_ = 0;
+      break;
+    case cdm::kStreamTypeVideo:
+      PP_DCHECK(deferred_initialize_video_decoder_);
+      CallOnMain(
+          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
+                                        PP_DECRYPTORSTREAMTYPE_VIDEO,
+                                        deferred_video_decoder_config_id_,
+                                        decoder_status == cdm::kSuccess));
+      deferred_initialize_video_decoder_ = false;
+      deferred_video_decoder_config_id_ = 0;
+      break;
+  }
+}
+
 #if defined(OS_CHROMEOS)
 void CdmAdapter::SendPlatformChallengeDone(int32_t result) {
   challenge_in_progress_ = false;
@@ -810,13 +875,13 @@
 
   cdm::PlatformChallengeResponse response = {
     static_cast<uint8_t*>(signed_data_var.Map()),
-    static_cast<int32_t>(signed_data_var.ByteLength()),
+    signed_data_var.ByteLength(),
 
     static_cast<uint8_t*>(signed_data_signature_var.Map()),
-    static_cast<int32_t>(signed_data_signature_var.ByteLength()),
+    signed_data_signature_var.ByteLength(),
 
     reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()),
-    static_cast<int32_t>(platform_key_certificate_string.length())
+    static_cast<uint32_t>(platform_key_certificate_string.length())
   };
   cdm_->OnPlatformChallengeResponse(response);
 
@@ -849,10 +914,10 @@
 
   CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
   switch (host_interface_version) {
-    case cdm::kHostInterfaceVersion_1:
-      return static_cast<cdm::Host_1*>(cdm_adapter);
-    case cdm::kHostInterfaceVersion_2:
-      return static_cast<cdm::Host_2*>(cdm_adapter);
+    case cdm::ContentDecryptionModule_1::Host::kVersion:
+      return static_cast<cdm::ContentDecryptionModule_1::Host*>(cdm_adapter);
+    case cdm::ContentDecryptionModule_2::Host::kVersion:
+      return static_cast<cdm::ContentDecryptionModule_2::Host*>(cdm_adapter);
     default:
       PP_NOTREACHED();
       return NULL;
diff --git a/media/cdm/ppapi/cdm_adapter.h b/media/cdm/ppapi/cdm_adapter.h
index d2edefb..441dfe9 100644
--- a/media/cdm/ppapi/cdm_adapter.h
+++ b/media/cdm/ppapi/cdm_adapter.h
@@ -79,15 +79,15 @@
       const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
 
   // cdm::Host implementation.
-  virtual cdm::Buffer* Allocate(int32_t capacity) OVERRIDE;
+  virtual cdm::Buffer* Allocate(uint32_t capacity) OVERRIDE;
   virtual void SetTimer(int64_t delay_ms, void* context) OVERRIDE;
   virtual double GetCurrentWallTimeInSeconds() OVERRIDE;
   virtual void SendKeyMessage(
-      const char* session_id, int32_t session_id_length,
-      const char* message, int32_t message_length,
-      const char* default_url, int32_t default_url_length) OVERRIDE;
+      const char* session_id, uint32_t session_id_length,
+      const char* message, uint32_t message_length,
+      const char* default_url, uint32_t default_url_length) OVERRIDE;
   virtual void SendKeyError(const char* session_id,
-                            int32_t session_id_length,
+                            uint32_t session_id_length,
                             cdm::MediaKeyError error_code,
                             uint32_t system_code) OVERRIDE;
   virtual void GetPrivateData(int32_t* instance,
@@ -95,11 +95,14 @@
 
   // cdm::Host_2 implementation.
   virtual void SendPlatformChallenge(
-      const char* service_id, int32_t service_id_length,
-      const char* challenge, int32_t challenge_length) OVERRIDE;
+      const char* service_id, uint32_t service_id_length,
+      const char* challenge, uint32_t challenge_length) OVERRIDE;
   virtual void EnableOutputProtection(
       uint32_t desired_protection_mask) OVERRIDE;
   virtual void QueryOutputProtectionStatus() OVERRIDE;
+  virtual void OnDeferredInitializationDone(
+      cdm::StreamType stream_type,
+      cdm::Status decoder_status) OVERRIDE;
 
  private:
   struct SessionInfo {
@@ -197,6 +200,14 @@
   linked_ptr<CdmWrapper> cdm_;
   std::string key_system_;
 
+  // If the CDM returned kDeferredInitialization during InitializeAudioDecoder()
+  // or InitializeVideoDecoder(), the (Audio|Video)DecoderConfig.request_id is
+  // saved for the future call to OnDeferredInitializationDone().
+  bool deferred_initialize_audio_decoder_;
+  uint32_t deferred_audio_decoder_config_id_;
+  bool deferred_initialize_video_decoder_;
+  uint32_t deferred_video_decoder_config_id_;
+
   DISALLOW_COPY_AND_ASSIGN(CdmAdapter);
 };
 
diff --git a/media/cdm/ppapi/cdm_helpers.cc b/media/cdm/ppapi/cdm_helpers.cc
index c0db2ed..36b9502 100644
--- a/media/cdm/ppapi/cdm_helpers.cc
+++ b/media/cdm/ppapi/cdm_helpers.cc
@@ -20,10 +20,10 @@
 
 namespace media {
 
-cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) {
+cdm::Buffer* PpbBufferAllocator::Allocate(uint32_t capacity) {
   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
 
-  if (capacity <= 0)
+  if (!capacity)
     return NULL;
 
   pp::Buffer_Dev buffer;
@@ -64,19 +64,19 @@
   allocated_buffers_.erase(found);
 }
 
-pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) {
+pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(uint32_t capacity) {
   // Always pad new allocated buffer so that we don't need to reallocate
   // buffers frequently if requested sizes fluctuate slightly.
-  static const int kBufferPadding = 512;
+  static const uint32_t kBufferPadding = 512;
 
   // Maximum number of free buffers we can keep when allocating new buffers.
-  static const int kFreeLimit = 3;
+  static const uint32_t kFreeLimit = 3;
 
   // Destroy the smallest buffer before allocating a new bigger buffer if the
   // number of free buffers exceeds a limit. This mechanism helps avoid ending
   // up with too many small buffers, which could happen if the size to be
   // allocated keeps increasing.
-  if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit))
+  if (free_buffers_.size() >= kFreeLimit)
     free_buffers_.erase(free_buffers_.begin());
 
   // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls.
@@ -88,7 +88,7 @@
     : format_(cdm::kUnknownVideoFormat),
       frame_buffer_(NULL),
       timestamp_(0) {
-  for (int32_t i = 0; i < kMaxPlanes; ++i) {
+  for (uint32_t i = 0; i < kMaxPlanes; ++i) {
     plane_offsets_[i] = 0;
     strides_[i] = 0;
   }
diff --git a/media/cdm/ppapi/cdm_helpers.h b/media/cdm/ppapi/cdm_helpers.h
index 67ebf86..3d51759 100644
--- a/media/cdm/ppapi/cdm_helpers.h
+++ b/media/cdm/ppapi/cdm_helpers.h
@@ -37,16 +37,15 @@
   // cdm::Buffer implementation.
   virtual void Destroy() OVERRIDE { delete this; }
 
-  virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); }
+  virtual uint32_t Capacity() const OVERRIDE { return buffer_.size(); }
 
   virtual uint8_t* Data() OVERRIDE {
     return static_cast<uint8_t*>(buffer_.data());
   }
 
-  virtual void SetSize(int32_t size) OVERRIDE {
-    PP_DCHECK(size >= 0);
+  virtual void SetSize(uint32_t size) OVERRIDE {
     PP_DCHECK(size < Capacity());
-    if (size < 0 || size > Capacity()) {
+    if (size > Capacity()) {
       size_ = 0;
       return;
     }
@@ -54,7 +53,7 @@
     size_ = size;
   }
 
-  virtual int32_t Size() const OVERRIDE { return size_; }
+  virtual uint32_t Size() const OVERRIDE { return size_; }
 
   pp::Buffer_Dev buffer_dev() const { return buffer_; }
 
@@ -69,7 +68,7 @@
 
   pp::Buffer_Dev buffer_;
   uint32_t buffer_id_;
-  int32_t size_;
+  uint32_t size_;
 
   DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
 };
@@ -81,7 +80,7 @@
         next_buffer_id_(1) {}
   ~PpbBufferAllocator() {}
 
-  cdm::Buffer* Allocate(int32_t capacity);
+  cdm::Buffer* Allocate(uint32_t capacity);
 
   // Releases the buffer with |buffer_id|. A buffer can be recycled after
   // it is released.
@@ -89,10 +88,10 @@
 
  private:
   typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
-  typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> >
+  typedef std::multimap<uint32_t, std::pair<uint32_t, pp::Buffer_Dev> >
       FreeBufferMap;
 
-  pp::Buffer_Dev AllocateNewBuffer(int capacity);
+  pp::Buffer_Dev AllocateNewBuffer(uint32_t capacity);
 
   pp::Instance* const instance_;
   uint32_t next_buffer_id_;
@@ -143,22 +142,21 @@
   virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; }
 
   virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
-                              int32_t offset) OVERRIDE {
-    PP_DCHECK(0 <= plane && plane < kMaxPlanes);
-    PP_DCHECK(offset >= 0);
+                              uint32_t offset) OVERRIDE {
+    PP_DCHECK(plane < kMaxPlanes);
     plane_offsets_[plane] = offset;
   }
-  virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE {
-    PP_DCHECK(0 <= plane && plane < kMaxPlanes);
+  virtual uint32_t PlaneOffset(VideoPlane plane) OVERRIDE {
+    PP_DCHECK(plane < kMaxPlanes);
     return plane_offsets_[plane];
   }
 
-  virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE {
-    PP_DCHECK(0 <= plane && plane < kMaxPlanes);
+  virtual void SetStride(VideoPlane plane, uint32_t stride) OVERRIDE {
+    PP_DCHECK(plane < kMaxPlanes);
     strides_[plane] = stride;
   }
-  virtual int32_t Stride(VideoPlane plane) OVERRIDE {
-    PP_DCHECK(0 <= plane && plane < kMaxPlanes);
+  virtual uint32_t Stride(VideoPlane plane) OVERRIDE {
+    PP_DCHECK(plane < kMaxPlanes);
     return strides_[plane];
   }
 
@@ -178,12 +176,12 @@
   PpbBuffer* frame_buffer_;
 
   // Array of data pointers to each plane in the video frame buffer.
-  int32_t plane_offsets_[kMaxPlanes];
+  uint32_t plane_offsets_[kMaxPlanes];
 
   // Array of strides for each plane, typically greater or equal to the width
   // of the surface divided by the horizontal sampling period.  Note that
   // strides can be negative.
-  int32_t strides_[kMaxPlanes];
+  uint32_t strides_[kMaxPlanes];
 
   // Presentation timestamp in microseconds.
   int64_t timestamp_;
diff --git a/media/cdm/ppapi/cdm_wrapper.h b/media/cdm/ppapi/cdm_wrapper.h
index e660c25..f54d0d6 100644
--- a/media/cdm/ppapi/cdm_wrapper.h
+++ b/media/cdm/ppapi/cdm_wrapper.h
@@ -31,24 +31,24 @@
 class CdmWrapper {
  public:
   static CdmWrapper* Create(const char* key_system,
-                            int key_system_size,
+                            uint32_t key_system_size,
                             GetCdmHostFunc get_cdm_host_func,
                             void* user_data);
 
   virtual ~CdmWrapper() {};
 
   virtual cdm::Status GenerateKeyRequest(const char* type,
-                                         int type_size,
+                                         uint32_t type_size,
                                          const uint8_t* init_data,
-                                         int init_data_size) = 0;
+                                         uint32_t init_data_size) = 0;
   virtual cdm::Status AddKey(const char* session_id,
-                             int session_id_size,
+                             uint32_t session_id_size,
                              const uint8_t* key,
-                             int key_size,
+                             uint32_t key_size,
                              const uint8_t* key_id,
-                             int key_id_size) = 0;
+                             uint32_t key_id_size) = 0;
   virtual cdm::Status CancelKeyRequest(const char* session_id,
-                                       int session_id_size) = 0;
+                                       uint32_t session_id_size) = 0;
   virtual void TimerExpired(void* context) = 0;
   virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
                               cdm::DecryptedBlock* decrypted_buffer) = 0;
@@ -84,7 +84,7 @@
 class CdmWrapperImpl : public CdmWrapper {
  public:
   static CdmWrapper* Create(const char* key_system,
-                            int key_system_size,
+                            uint32_t key_system_size,
                             GetCdmHostFunc get_cdm_host_func,
                             void* user_data) {
     void* cdm_instance = ::CreateCdmInstance(
@@ -102,24 +102,24 @@
   }
 
   virtual cdm::Status GenerateKeyRequest(const char* type,
-                                         int type_size,
+                                         uint32_t type_size,
                                          const uint8_t* init_data,
-                                         int init_data_size) OVERRIDE {
+                                         uint32_t init_data_size) OVERRIDE {
     return cdm_->GenerateKeyRequest(type, type_size, init_data, init_data_size);
   }
 
   virtual cdm::Status AddKey(const char* session_id,
-                             int session_id_size,
+                             uint32_t session_id_size,
                              const uint8_t* key,
-                             int key_size,
+                             uint32_t key_size,
                              const uint8_t* key_id,
-                             int key_id_size) OVERRIDE {
+                             uint32_t key_id_size) OVERRIDE {
     return cdm_->AddKey(
         session_id, session_id_size, key, key_size, key_id, key_id_size);
   }
 
   virtual cdm::Status CancelKeyRequest(const char* session_id,
-                                       int session_id_size) OVERRIDE {
+                                       uint32_t session_id_size) OVERRIDE {
     return cdm_->CancelKeyRequest(session_id, session_id_size);
   }
 
@@ -212,7 +212,7 @@
 }
 
 CdmWrapper* CdmWrapper::Create(const char* key_system,
-                               int key_system_size,
+                               uint32_t key_system_size,
                                GetCdmHostFunc get_cdm_host_func,
                                void* user_data) {
   // Try to create the CDM using the latest CDM interface version.
@@ -229,10 +229,10 @@
 }
 
 // When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain
-// stub implementations for new or modified methods which the older CDM
-// interface does not have.
-COMPILE_ASSERT(cdm::ContentDecryptionModule_2::kVersion ==
-                   cdm::ContentDecryptionModule::kVersion,
+// stub implementations for new or modified methods that the older CDM interface
+// does not have.
+COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
+                   cdm::ContentDecryptionModule_2::kVersion,
                ensure_cdm_wrapper_templates_have_old_version_support);
 
 }  // namespace media
diff --git a/media/cdm/ppapi/clear_key_cdm.cc b/media/cdm/ppapi/clear_key_cdm.cc
index d732500..d7cd206 100644
--- a/media/cdm/ppapi/clear_key_cdm.cc
+++ b/media/cdm/ppapi/clear_key_cdm.cc
@@ -74,7 +74,7 @@
 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom(
     const cdm::InputBuffer& input_buffer) {
   if (!input_buffer.data) {
-    DCHECK_EQ(input_buffer.data_size, 0);
+    DCHECK(!input_buffer.data_size);
     return media::DecoderBuffer::CreateEOSBuffer();
   }
 
@@ -83,7 +83,7 @@
       media::DecoderBuffer::CopyFrom(input_buffer.data, input_buffer.data_size);
 
   std::vector<media::SubsampleEntry> subsamples;
-  for (int32_t i = 0; i < input_buffer.num_subsamples; ++i) {
+  for (uint32_t i = 0; i < input_buffer.num_subsamples; ++i) {
     media::SubsampleEntry subsample;
     subsample.clear_bytes = input_buffer.subsamples[i].clear_bytes;
     subsample.cypher_bytes = input_buffer.subsamples[i].cipher_bytes;
@@ -127,7 +127,7 @@
 
 void* CreateCdmInstance(
     int cdm_interface_version,
-    const char* key_system, int key_system_size,
+    const char* key_system, uint32_t key_system_size,
     GetCdmHostFunc get_cdm_host_func, void* user_data) {
   DVLOG(1) << "CreateCdmInstance()";
 
@@ -136,11 +136,12 @@
     return NULL;
   }
 
-  if (cdm_interface_version != cdm::ContentDecryptionModule_1::kVersion)
+  if (cdm_interface_version != cdm::ContentDecryptionModule_2::kVersion)
     return NULL;
 
-  cdm::Host* host = static_cast<cdm::Host*>(
-      get_cdm_host_func(cdm::ContentDecryptionModule_1::kVersion, user_data));
+  cdm::ContentDecryptionModule_2::Host* host =
+      static_cast<cdm::ContentDecryptionModule_2::Host*>(get_cdm_host_func(
+          cdm::ContentDecryptionModule_2::Host::kVersion, user_data));
   if (!host)
     return NULL;
 
@@ -203,9 +204,10 @@
 
 ClearKeyCdm::~ClearKeyCdm() {}
 
-cdm::Status ClearKeyCdm::GenerateKeyRequest(const char* type, int type_size,
+cdm::Status ClearKeyCdm::GenerateKeyRequest(const char* type,
+                                            uint32_t type_size,
                                             const uint8_t* init_data,
-                                            int init_data_size) {
+                                            uint32_t init_data_size) {
   DVLOG(1) << "GenerateKeyRequest()";
   base::AutoLock auto_lock(client_lock_);
   ScopedResetter<Client> auto_resetter(&client_);
@@ -230,11 +232,11 @@
 }
 
 cdm::Status ClearKeyCdm::AddKey(const char* session_id,
-                                int session_id_size,
+                                uint32_t session_id_size,
                                 const uint8_t* key,
-                                int key_size,
+                                uint32_t key_size,
                                 const uint8_t* key_id,
-                                int key_id_size) {
+                                uint32_t key_id_size) {
   DVLOG(1) << "AddKey()";
   base::AutoLock auto_lock(client_lock_);
   ScopedResetter<Client> auto_resetter(&client_);
@@ -253,7 +255,7 @@
 }
 
 cdm::Status ClearKeyCdm::CancelKeyRequest(const char* session_id,
-                                          int session_id_size) {
+                                          uint32_t session_id_size) {
   DVLOG(1) << "CancelKeyRequest()";
   base::AutoLock auto_lock(client_lock_);
   ScopedResetter<Client> auto_resetter(&client_);
@@ -417,7 +419,7 @@
 
 cdm::Status ClearKeyCdm::DecryptAndDecodeSamples(
     const cdm::InputBuffer& encrypted_buffer,
-    cdm::AudioFrames_1* audio_frames) {
+    cdm::AudioFrames* audio_frames) {
   DVLOG(1) << "DecryptAndDecodeSamples()";
 
   scoped_refptr<media::DecoderBuffer> buffer;
@@ -500,6 +502,16 @@
   return cdm::kSuccess;
 }
 
+void ClearKeyCdm::OnPlatformChallengeResponse(
+    const cdm::PlatformChallengeResponse& response) {
+  NOTIMPLEMENTED();
+}
+
+void ClearKeyCdm::OnQueryOutputProtectionStatus(
+    uint32_t link_mask, uint32_t output_protection_mask) {
+  NOTIMPLEMENTED();
+};
+
 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
 int64 ClearKeyCdm::CurrentTimeStampInMicroseconds() const {
   return output_timestamp_base_in_microseconds_ +
diff --git a/media/cdm/ppapi/clear_key_cdm.h b/media/cdm/ppapi/clear_key_cdm.h
index c77e4b4..5702905 100644
--- a/media/cdm/ppapi/clear_key_cdm.h
+++ b/media/cdm/ppapi/clear_key_cdm.h
@@ -28,20 +28,23 @@
 class FFmpegCdmAudioDecoder;
 
 // Clear key implementation of the cdm::ContentDecryptionModule interface.
-class ClearKeyCdm : public cdm::ContentDecryptionModule_1 {
+class ClearKeyCdm : public cdm::ContentDecryptionModule_2 {
  public:
   explicit ClearKeyCdm(cdm::Host* host);
   virtual ~ClearKeyCdm();
 
   // ContentDecryptionModule implementation.
   virtual cdm::Status GenerateKeyRequest(
-      const char* type, int type_size,
-      const uint8_t* init_data, int init_data_size) OVERRIDE;
-  virtual cdm::Status AddKey(const char* session_id, int session_id_size,
-                             const uint8_t* key, int key_size,
-                             const uint8_t* key_id, int key_id_size) OVERRIDE;
+      const char* type, uint32_t type_size,
+      const uint8_t* init_data, uint32_t init_data_size) OVERRIDE;
+  virtual cdm::Status AddKey(const char* session_id,
+                             uint32_t session_id_size,
+                             const uint8_t* key,
+                             uint32_t key_size,
+                             const uint8_t* key_id,
+                             uint32_t key_id_size) OVERRIDE;
   virtual cdm::Status CancelKeyRequest(const char* session_id,
-                                       int session_id_size) OVERRIDE;
+                                       uint32_t session_id_size) OVERRIDE;
   virtual void TimerExpired(void* context) OVERRIDE;
   virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
                               cdm::DecryptedBlock* decrypted_block) OVERRIDE;
@@ -56,8 +59,12 @@
       cdm::VideoFrame* video_frame) OVERRIDE;
   virtual cdm::Status DecryptAndDecodeSamples(
       const cdm::InputBuffer& encrypted_buffer,
-      cdm::AudioFrames_1* audio_frames) OVERRIDE;
+      cdm::AudioFrames* audio_frames) OVERRIDE;
   virtual void Destroy() OVERRIDE;
+  virtual void OnPlatformChallengeResponse(
+      const cdm::PlatformChallengeResponse& response) OVERRIDE;
+  virtual void OnQueryOutputProtectionStatus(
+      uint32_t link_mask, uint32_t output_protection_mask) OVERRIDE;
 
  private:
   // TODO(xhwang): After we removed DecryptorClient. We probably can also remove
diff --git a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc
index 3e2ca65..97d04e8 100644
--- a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc
+++ b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.cc
@@ -80,10 +80,59 @@
   }
 }
 
+static cdm::AudioFormat AVSampleFormatToCdmAudioFormat(
+    AVSampleFormat sample_format) {
+  switch (sample_format) {
+    case AV_SAMPLE_FMT_U8:
+      return cdm::kAudioFormatU8;
+    case AV_SAMPLE_FMT_S16:
+      return cdm::kAudioFormatS16;
+    case AV_SAMPLE_FMT_S32:
+      return cdm::kAudioFormatS32;
+    case AV_SAMPLE_FMT_FLT:
+      return cdm::kAudioFormatF32;
+    case AV_SAMPLE_FMT_S16P:
+      return cdm::kAudioFormatPlanarS16;
+    case AV_SAMPLE_FMT_FLTP:
+      return cdm::kAudioFormatPlanarF32;
+    default:
+      DVLOG(1) << "Unknown AVSampleFormat: " << sample_format;
+  }
+  return cdm::kUnknownAudioFormat;
+}
+
+static void CopySamples(cdm::AudioFormat cdm_format,
+                        int decoded_audio_size,
+                        const AVFrame& av_frame,
+                        uint8_t* output_buffer) {
+  switch (cdm_format) {
+    case cdm::kAudioFormatU8:
+    case cdm::kAudioFormatS16:
+    case cdm::kAudioFormatS32:
+    case cdm::kAudioFormatF32:
+      memcpy(output_buffer, av_frame.data[0], decoded_audio_size);
+      break;
+    case cdm::kAudioFormatPlanarS16:
+    case cdm::kAudioFormatPlanarF32: {
+      const int decoded_size_per_channel =
+          decoded_audio_size / av_frame.channels;
+      for (int i = 0; i < av_frame.channels; ++i) {
+        memcpy(output_buffer,
+               av_frame.extended_data[i],
+               decoded_size_per_channel);
+        output_buffer += decoded_size_per_channel;
+      }
+      break;
+    }
+    default:
+      NOTREACHED() << "Unsupported CDM Audio Format!";
+      memset(output_buffer, 0, decoded_audio_size);
+  }
+}
+
 FFmpegCdmAudioDecoder::FFmpegCdmAudioDecoder(cdm::Host* host)
     : is_initialized_(false),
       host_(host),
-      bits_per_channel_(0),
       samples_per_second_(0),
       channels_(0),
       av_sample_format_(0),
@@ -98,7 +147,6 @@
 
 bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) {
   DVLOG(1) << "Initialize()";
-
   if (!IsValidConfig(config)) {
     LOG(ERROR) << "Initialize(): invalid audio decoder configuration.";
     return false;
@@ -131,27 +179,12 @@
     return false;
   }
 
-  // Some codecs will only output float data, so we need to convert to integer
-  // before returning the decoded buffer.
-  if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP ||
-      codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
-    // Preallocate the AudioBus for float conversions.  We can treat interleaved
-    // float data as a single planar channel since our output is expected in an
-    // interleaved format anyways.
-    int channels = codec_context_->channels;
-    if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT)
-      channels = 1;
-    converter_bus_ = AudioBus::CreateWrapper(channels);
-  }
-
   // Success!
   av_frame_.reset(avcodec_alloc_frame());
-  bits_per_channel_ = config.bits_per_channel;
   samples_per_second_ = config.samples_per_second;
-  bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8;
+  bytes_per_frame_ = codec_context_->channels * config.bits_per_channel / 8;
   output_timestamp_helper_.reset(
       new AudioTimestampHelper(config.samples_per_second));
-  serialized_audio_frames_.reserve(bytes_per_frame_ * samples_per_second_);
   is_initialized_ = true;
 
   // Store initial values to guard against midstream configuration changes.
@@ -190,7 +223,7 @@
     const uint8_t* compressed_buffer,
     int32_t compressed_buffer_size,
     int64_t input_timestamp,
-    cdm::AudioFrames_1* decoded_frames) {
+    cdm::AudioFrames* decoded_frames) {
   DVLOG(1) << "DecodeBuffer()";
   const bool is_end_of_stream = !compressed_buffer;
   base::TimeDelta timestamp =
@@ -226,6 +259,12 @@
   packet.data = const_cast<uint8_t*>(compressed_buffer);
   packet.size = compressed_buffer_size;
 
+  // Tell the CDM what AudioFormat we're using.
+  const cdm::AudioFormat cdm_format = AVSampleFormatToCdmAudioFormat(
+      static_cast<AVSampleFormat>(av_sample_format_));
+  DCHECK_NE(cdm_format, cdm::kUnknownAudioFormat);
+  decoded_frames->SetFormat(cdm_format);
+
   // Each audio packet may contain several frames, so we must call the decoder
   // until we've exhausted the packet.  Regardless of the packet size we always
   // want to hand it to the decoder at least once, otherwise we would end up
@@ -289,76 +328,63 @@
       decoded_audio_size = av_samples_get_buffer_size(
           NULL, codec_context_->channels, av_frame_->nb_samples,
           codec_context_->sample_fmt, 1);
-      // If we're decoding into float, adjust audio size.
-      if (converter_bus_ && bits_per_channel_ / 8 != sizeof(float)) {
-        DCHECK(codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT ||
-               codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP);
-        decoded_audio_size *=
-            static_cast<float>(bits_per_channel_ / 8) / sizeof(float);
-      }
     }
 
-    int start_sample = 0;
     if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) {
       DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0)
           << "Decoder didn't output full frames";
 
       int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_);
-      start_sample = dropped_size / bytes_per_frame_;
       decoded_audio_size -= dropped_size;
       output_bytes_to_drop_ -= dropped_size;
     }
 
-    scoped_refptr<DataBuffer> output;
     if (decoded_audio_size > 0) {
       DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0)
           << "Decoder didn't output full frames";
 
-      // Convert float data using an AudioBus.
-      if (converter_bus_) {
-        // Setup the AudioBus as a wrapper of the AVFrame data and then use
-        // AudioBus::ToInterleaved() to convert the data as necessary.
-        int skip_frames = start_sample;
-        int total_frames = av_frame_->nb_samples;
-        int frames_to_interleave = decoded_audio_size / bytes_per_frame_;
-        if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
-          DCHECK_EQ(converter_bus_->channels(), 1);
-          total_frames *= codec_context_->channels;
-          skip_frames *= codec_context_->channels;
-          frames_to_interleave *= codec_context_->channels;
-        }
-
-        converter_bus_->set_frames(total_frames);
-        for (int i = 0; i < converter_bus_->channels(); ++i) {
-          converter_bus_->SetChannelData(i, reinterpret_cast<float*>(
-              av_frame_->extended_data[i]));
-        }
-
-        output = new DataBuffer(decoded_audio_size);
-        output->set_data_size(decoded_audio_size);
-
-        DCHECK_EQ(frames_to_interleave, converter_bus_->frames() - skip_frames);
-        converter_bus_->ToInterleavedPartial(
-            skip_frames, frames_to_interleave, bits_per_channel_ / 8,
-            output->writable_data());
-      } else {
-        output = DataBuffer::CopyFrom(
-            av_frame_->extended_data[0] + start_sample * bytes_per_frame_,
-            decoded_audio_size);
-      }
-
       base::TimeDelta output_timestamp =
           output_timestamp_helper_->GetTimestamp();
       output_timestamp_helper_->AddFrames(decoded_audio_size /
                                           bytes_per_frame_);
 
-      // Serialize the audio samples into |serialized_audio_frames_|.
+      // If we've exhausted the packet in the first decode we can write directly
+      // into the frame buffer instead of a multistep serialization approach.
+      if (serialized_audio_frames_.empty() && !packet.size) {
+        const uint32_t buffer_size = decoded_audio_size + sizeof(int64) * 2;
+        decoded_frames->SetFrameBuffer(host_->Allocate(buffer_size));
+        if (!decoded_frames->FrameBuffer()) {
+          LOG(ERROR) << "DecodeBuffer() cdm::Host::Allocate failed.";
+          return cdm::kDecodeError;
+        }
+        decoded_frames->FrameBuffer()->SetSize(buffer_size);
+        uint8_t* output_buffer = decoded_frames->FrameBuffer()->Data();
+
+        const int64 timestamp = output_timestamp.InMicroseconds();
+        memcpy(output_buffer, &timestamp, sizeof(timestamp));
+        output_buffer += sizeof(timestamp);
+
+        const int64 output_size = decoded_audio_size;
+        memcpy(output_buffer, &output_size, sizeof(output_size));
+        output_buffer += sizeof(output_size);
+
+        // Copy the samples and return success.
+        CopySamples(
+            cdm_format, decoded_audio_size, *av_frame_, output_buffer);
+        return cdm::kSuccess;
+      }
+
+      // There are still more frames to decode, so we need to serialize them in
+      // a secondary buffer since we don't know their sizes ahead of time (which
+      // is required to allocate the FrameBuffer object).
       SerializeInt64(output_timestamp.InMicroseconds());
-      SerializeInt64(output->data_size());
-      serialized_audio_frames_.insert(
-          serialized_audio_frames_.end(),
-          output->data(),
-          output->data() + output->data_size());
+      SerializeInt64(decoded_audio_size);
+
+      const size_t previous_size = serialized_audio_frames_.size();
+      serialized_audio_frames_.resize(previous_size + decoded_audio_size);
+      uint8_t* output_buffer = &serialized_audio_frames_[0] + previous_size;
+      CopySamples(
+          cdm_format, decoded_audio_size, *av_frame_, output_buffer);
     }
   } while (packet.size > 0);
 
@@ -395,7 +421,7 @@
 }
 
 void FFmpegCdmAudioDecoder::SerializeInt64(int64 value) {
-  int previous_size = serialized_audio_frames_.size();
+  const size_t previous_size = serialized_audio_frames_.size();
   serialized_audio_frames_.resize(previous_size + sizeof(value));
   memcpy(&serialized_audio_frames_[0] + previous_size, &value, sizeof(value));
 }
diff --git a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h
index 35a01df..6e170ad 100644
--- a/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h
+++ b/media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h
@@ -49,7 +49,7 @@
   cdm::Status DecodeBuffer(const uint8_t* compressed_buffer,
                            int32_t compressed_buffer_size,
                            int64_t timestamp,
-                           cdm::AudioFrames_1* decoded_frames);
+                           cdm::AudioFrames* decoded_frames);
 
  private:
   void ResetTimestampState();
@@ -68,7 +68,6 @@
   scoped_ptr_malloc<AVFrame, ScopedPtrAVFreeFrame> av_frame_;
 
   // Audio format.
-  int bits_per_channel_;
   int samples_per_second_;
   int channels_;
 
@@ -80,10 +79,6 @@
   int bytes_per_frame_;
   base::TimeDelta last_input_timestamp_;
 
-  // We may need to convert the audio data coming out of FFmpeg from planar
-  // float to integer.
-  scoped_ptr<AudioBus> converter_bus_;
-
   // Number of output sample bytes to drop before generating output buffers.
   // This is required for handling negative timestamps when decoding Vorbis
   // audio, for example.
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index dbf1b03..d4eff22 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -1045,7 +1045,7 @@
       base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
     }
 
-    ranges = GetBufferedRanges();
+    ranges = GetBufferedRanges_Locked();
   }
 
   for (size_t i = 0; i < ranges.size(); ++i)
@@ -1405,7 +1405,8 @@
 }
 
 void ChunkDemuxer::DecreaseDurationIfNecessary() {
-  Ranges<TimeDelta> ranges = GetBufferedRanges();
+  lock_.AssertAcquired();
+  Ranges<TimeDelta> ranges = GetBufferedRanges_Locked();
   if (ranges.size() == 0u)
     return;
 
@@ -1415,6 +1416,12 @@
 }
 
 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
+  base::AutoLock auto_lock(lock_);
+  return GetBufferedRanges_Locked();
+}
+
+Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges_Locked() const {
+  lock_.AssertAcquired();
   if (audio_ && !video_)
     return audio_->GetBufferedRanges(duration_);
   else if (!audio_ && video_)
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index e7f6cae..cb2b72c 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -140,6 +140,12 @@
 
   void SetMemoryLimitsForTesting(int memory_limit);
 
+  // Returns the ranges representing the buffered data in the demuxer.
+  // TODO(wolenetz): Remove this method once MediaSourceDelegate no longer
+  // requires it for doing hack browser seeks to I-frame on Android. See
+  // http://crbug.com/304234.
+  Ranges<base::TimeDelta> GetBufferedRanges() const;
+
  private:
   enum State {
     WAITING_FOR_INIT,
@@ -203,7 +209,7 @@
   void UpdateDuration(base::TimeDelta new_duration);
 
   // Returns the ranges representing the buffered data in the demuxer.
-  Ranges<base::TimeDelta> GetBufferedRanges() const;
+  Ranges<base::TimeDelta> GetBufferedRanges_Locked() const;
 
   // Start returning data on all DemuxerStreams.
   void StartReturningData();
@@ -230,6 +236,10 @@
   LogCB log_cb_;
 
   PipelineStatusCB init_cb_;
+  // Callback to execute upon seek completion.
+  // TODO(wolenetz/acolwell): Protect against possible double-locking by first
+  // releasing |lock_| before executing this callback. See
+  // http://crbug.com/308226
   PipelineStatusCB seek_cb_;
 
   scoped_ptr<ChunkDemuxerStream> audio_;
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index b97240e..4ffa0f2 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -282,25 +282,22 @@
     return;
   }
 
-  bool is_vorbis = codec_context_->codec_id == AV_CODEC_ID_VORBIS;
   if (!input->end_of_stream()) {
-    if (last_input_timestamp_ == kNoTimestamp()) {
-      if (is_vorbis && (input->timestamp() < base::TimeDelta())) {
-        // Dropping frames for negative timestamps as outlined in section A.2
-        // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html
-        output_frames_to_drop_ = floor(
-            0.5 + -input->timestamp().InSecondsF() * samples_per_second_);
-      } else {
-        last_input_timestamp_ = input->timestamp();
-      }
-    } else if (input->timestamp() != kNoTimestamp()) {
-      if (input->timestamp() < last_input_timestamp_) {
-        base::TimeDelta diff = input->timestamp() - last_input_timestamp_;
-        DVLOG(1) << "Input timestamps are not monotonically increasing! "
-                 << " ts " << input->timestamp().InMicroseconds() << " us"
-                 << " diff " << diff.InMicroseconds() << " us";
-        base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
-        return;
+    if (last_input_timestamp_ == kNoTimestamp() &&
+        codec_context_->codec_id == AV_CODEC_ID_VORBIS &&
+        input->timestamp() < base::TimeDelta()) {
+      // Dropping frames for negative timestamps as outlined in section A.2
+      // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html
+      output_frames_to_drop_ = floor(
+          0.5 + -input->timestamp().InSecondsF() * samples_per_second_);
+    } else {
+      if (last_input_timestamp_ != kNoTimestamp() &&
+          input->timestamp() < last_input_timestamp_) {
+        const base::TimeDelta diff = input->timestamp() - last_input_timestamp_;
+        DLOG(WARNING)
+            << "Input timestamps are not monotonically increasing! "
+            << " ts " << input->timestamp().InMicroseconds() << " us"
+            << " diff " << diff.InMicroseconds() << " us";
       }
 
       last_input_timestamp_ = input->timestamp();
@@ -434,14 +431,12 @@
           << "This is quite possibly a bug in the audio decoder not handling "
           << "end of stream AVPackets correctly.";
 
-      DLOG(ERROR)
-          << "Error decoding an audio frame with timestamp: "
+      DLOG(WARNING)
+          << "Failed to decode an audio frame with timestamp: "
           << input->timestamp().InMicroseconds() << " us, duration: "
           << input->duration().InMicroseconds() << " us, packet size: "
           << input->data_size() << " bytes";
 
-      // TODO(dalecurtis): We should return a kDecodeError here instead:
-      // http://crbug.com/145276
       break;
     }
 
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index 07ebf33..03de160 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -12,6 +12,22 @@
 #include "base/logging.h"
 
 namespace media {
+
+// Buffers with the same timestamp are only allowed under certain conditions.
+// Video: Allowed when the previous frame and current frame are NOT keyframes.
+//        This is the situation for VP8 Alt-Ref frames.
+// Otherwise: Allowed in all situations except where a non-keyframe is followed
+//            by a keyframe.
+// Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a
+// same timestamp situation that is allowed. False is returned otherwise.
+static bool AllowSameTimestamp(
+    bool prev_is_keyframe, bool current_is_keyframe, bool is_video) {
+  if (is_video)
+    return !prev_is_keyframe && !current_is_keyframe;
+
+  return prev_is_keyframe || !current_is_keyframe;
+}
+
 // Helper class representing a range of buffered data. All buffers in a
 // SourceBufferRange are ordered sequentially in presentation order with no
 // gaps.
@@ -28,7 +44,8 @@
   // empty and the front of |new_buffers| must be a keyframe.
   // |media_segment_start_time| refers to the starting timestamp for the media
   // segment to which these buffers belong.
-  SourceBufferRange(const BufferQueue& new_buffers,
+  SourceBufferRange(bool is_video,
+                    const BufferQueue& new_buffers,
                     base::TimeDelta media_segment_start_time,
                     const InterbufferDistanceCB& interbuffer_distance_cb);
 
@@ -165,10 +182,8 @@
   bool EndOverlaps(const SourceBufferRange& range) const;
 
   // Returns true if |timestamp| is the timestamp of the next buffer in
-  // sequence after |buffer|, false otherwise.
-  bool IsNextInSequence(
-      const scoped_refptr<media::StreamParserBuffer>& buffer,
-      base::TimeDelta timestamp) const;
+  // sequence after |buffers_.back()|, false otherwise.
+  bool IsNextInSequence(base::TimeDelta timestamp, bool is_keyframe) const;
 
   int size_in_bytes() const { return size_in_bytes_; }
 
@@ -213,6 +228,9 @@
   // Returns the approximate duration of a buffer in this range.
   base::TimeDelta GetApproximateDuration() const;
 
+  // True if this object stores video data.
+  bool is_video_;
+
   // An ordered list of buffers in this range.
   BufferQueue buffers_;
 
@@ -405,6 +423,14 @@
     return false;
   }
 
+  if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(),
+                            buffers.front()->IsKeyframe())) {
+    MEDIA_LOG(log_cb_) << "Invalid same timestamp construct detected at time "
+                       << buffers.front()->GetDecodeTimestamp().InSecondsF();
+
+    return false;
+  }
+
   UpdateMaxInterbufferDistance(buffers);
   SetConfigIds(buffers);
 
@@ -412,32 +438,60 @@
   base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
   BufferQueue deleted_buffers;
 
-  RangeList::iterator range_for_new_buffers = range_for_next_append_;
+  PrepareRangesForNextAppend(buffers, &deleted_buffers);
+
   // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
   // create a new range with |buffers|.
-  if (range_for_new_buffers != ranges_.end()) {
-    if (!InsertIntoExistingRange(range_for_new_buffers, buffers,
-                                 &deleted_buffers)) {
-      return false;
-    }
+  if (range_for_next_append_ != ranges_.end()) {
+    (*range_for_next_append_)->AppendBuffersToEnd(buffers);
+    last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
+    last_appended_buffer_is_keyframe_ = buffers.back()->IsKeyframe();
   } else {
-    DCHECK(new_media_segment_);
-    range_for_new_buffers =
+    base::TimeDelta new_range_start_time = media_segment_start_time_;
+    const BufferQueue* buffers_for_new_range = &buffers;
+    BufferQueue trimmed_buffers;
+
+    // If the new range is not being created because of a new media
+    // segment, then we must make sure that we start with a keyframe.
+    // This can happen if the GOP in the previous append gets destroyed
+    // by a Remove() call.
+    if (!new_media_segment_ && !buffers.front()->IsKeyframe()) {
+      BufferQueue::const_iterator itr = buffers.begin();
+
+      // Scan past all the non-keyframes.
+      while (itr != buffers.end() && !(*itr)->IsKeyframe()) {
+        ++itr;
+      }
+
+      // If we didn't find a keyframe, then update the last appended
+      // buffer state and return.
+      if (itr == buffers.end()) {
+        last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
+        last_appended_buffer_is_keyframe_ = buffers.back()->IsKeyframe();
+        return true;
+      }
+
+      // Copy the first keyframe and everything after it into |trimmed_buffers|.
+      trimmed_buffers.assign(itr, buffers.end());
+
+      new_range_start_time = trimmed_buffers.front()->GetDecodeTimestamp();
+      buffers_for_new_range = &trimmed_buffers;
+    }
+
+    range_for_next_append_ =
         AddToRanges(new SourceBufferRange(
-            buffers, media_segment_start_time_,
+            is_video(), *buffers_for_new_range, new_range_start_time,
             base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
                        base::Unretained(this))));
+    last_appended_buffer_timestamp_ =
+        buffers_for_new_range->back()->GetDecodeTimestamp();
+    last_appended_buffer_is_keyframe_ =
+        buffers_for_new_range->back()->IsKeyframe();
   }
 
-  range_for_next_append_ = range_for_new_buffers;
   new_media_segment_ = false;
-  last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
-  last_appended_buffer_is_keyframe_ = buffers.back()->IsKeyframe();
 
-  // Resolve overlaps.
-  ResolveCompleteOverlaps(range_for_new_buffers, &deleted_buffers);
-  ResolveEndOverlap(range_for_new_buffers, &deleted_buffers);
-  MergeWithAdjacentRangeIfNecessary(range_for_new_buffers);
+  MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
 
   // Seek to try to fulfill a previous call to Seek().
   if (seek_pending_) {
@@ -496,16 +550,34 @@
     remove_end_timestamp = end;
   }
 
+  BufferQueue deleted_buffers;
+  RemoveInternal(start, remove_end_timestamp, false, &deleted_buffers);
+
+  if (!deleted_buffers.empty())
+    SetSelectedRangeIfNeeded(deleted_buffers.front()->GetDecodeTimestamp());
+}
+
+void SourceBufferStream::RemoveInternal(
+    base::TimeDelta start, base::TimeDelta end, bool is_exclusive,
+    BufferQueue* deleted_buffers) {
+  DVLOG(1) << __FUNCTION__ << "(" << start.InSecondsF()
+           << ", " << end.InSecondsF()
+           << ", " << is_exclusive << ")";
+
+  DCHECK(start >= base::TimeDelta());
+  DCHECK(start < end) << "start " << start.InSecondsF()
+                      << " end " << end.InSecondsF();
+  DCHECK(deleted_buffers);
+
   RangeList::iterator itr = ranges_.begin();
 
   while (itr != ranges_.end()) {
     SourceBufferRange* range = *itr;
-    if (range->GetStartTimestamp() >= remove_end_timestamp)
+    if (range->GetStartTimestamp() >= end)
       break;
 
     // Split off any remaining end piece and add it to |ranges_|.
-    SourceBufferRange* new_range =
-        range->SplitRange(remove_end_timestamp, false);
+    SourceBufferRange* new_range = range->SplitRange(end, is_exclusive);
     if (new_range) {
       itr = ranges_.insert(++itr, new_range);
       --itr;
@@ -517,23 +589,50 @@
     }
 
     // If the current range now is completely covered by the removal
-    // range then delete it and move on.
-    if (start <= range->GetStartTimestamp()) {
-      DeleteAndRemoveRange(&itr);
-      continue;
-    }
+    // range then we want to delete it.
+    bool delete_range = start < range->GetStartTimestamp() ||
+        (!is_exclusive && start == range->GetStartTimestamp());
 
     // Truncate the current range so that it only contains data before
     // the removal range.
     BufferQueue saved_buffers;
-    range->TruncateAt(start, &saved_buffers, false);
+    range->TruncateAt(start, &saved_buffers, is_exclusive);
 
     // Check to see if the current playback position was removed and
     // update the selected range appropriately.
     if (!saved_buffers.empty()) {
       DCHECK(!range->HasNextBufferPosition());
+      DCHECK(deleted_buffers->empty());
+
+      *deleted_buffers = saved_buffers;
+    }
+
+    if (range == selected_range_ && !range->HasNextBufferPosition())
       SetSelectedRange(NULL);
-      SetSelectedRangeIfNeeded(saved_buffers.front()->GetDecodeTimestamp());
+
+    // If the current range now is completely covered by the removal
+    // range then delete it and move on.
+    if (delete_range) {
+      DeleteAndRemoveRange(&itr);
+      continue;
+    }
+
+    // Clear |range_for_next_append_| if we determine that the removal
+    // operation makes it impossible for the next append to be added
+    // to the current range.
+    if (range_for_next_append_ != ranges_.end() &&
+        *range_for_next_append_ == range &&
+        last_appended_buffer_timestamp_ != kNoTimestamp()) {
+      base::TimeDelta potential_next_append_timestamp =
+          last_appended_buffer_timestamp_ +
+          base::TimeDelta::FromInternalValue(1);
+
+      if (!range->BelongsToRange(potential_next_append_timestamp)) {
+        DVLOG(1) << "Resetting range_for_next_append_ since the next append"
+                 <<  " can't add to the current range.";
+        range_for_next_append_ =
+            FindExistingRangeFor(potential_next_append_timestamp);
+      }
     }
 
     // Move on to the next range.
@@ -542,6 +641,7 @@
 
   DCHECK(IsRangeListSorted(ranges_));
   DCHECK(OnlySelectedRangeIsSeeked());
+  DVLOG(1) << __FUNCTION__ << " : done";
 }
 
 void SourceBufferStream::ResetSeekState() {
@@ -561,21 +661,6 @@
           beginning_of_buffered < kSeekToStartFudgeRoom());
 }
 
-// Buffers with the same timestamp are only allowed under certain conditions.
-// Video: Allowed when the previous frame and current frame are NOT keyframes.
-//        This is the situation for VP8 Alt-Ref frames.
-// Otherwise: Allowed in all situations except where a non-keyframe is followed
-//            by a keyframe.
-// Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a
-// same timestamp situation that is allowed. False is returned otherwise.
-bool SourceBufferStream::AllowSameTimestamp(
-    bool prev_is_keyframe, bool current_is_keyframe) const {
-  if (video_configs_.size() > 0)
-    return !prev_is_keyframe && !current_is_keyframe;
-
-  return prev_is_keyframe || !current_is_keyframe;
-}
-
 bool SourceBufferStream::IsMonotonicallyIncreasing(
     const BufferQueue& buffers) const {
   DCHECK(!buffers.empty());
@@ -594,7 +679,8 @@
       }
 
       if (current_timestamp == prev_timestamp &&
-          !AllowSameTimestamp(prev_is_keyframe, current_is_keyframe)) {
+          !AllowSameTimestamp(prev_is_keyframe, current_is_keyframe,
+                              is_video())) {
         MEDIA_LOG(log_cb_) << "Unexpected combination of buffers with the"
                            << " same timestamp detected at "
                            << current_timestamp.InSecondsF();
@@ -608,6 +694,15 @@
   return true;
 }
 
+bool SourceBufferStream::IsNextTimestampValid(
+    base::TimeDelta next_timestamp, bool next_is_keyframe) const {
+  return (last_appended_buffer_timestamp_ != next_timestamp) ||
+      new_media_segment_ ||
+      AllowSameTimestamp(last_appended_buffer_is_keyframe_, next_is_keyframe,
+                         is_video());
+}
+
+
 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
   for (RangeList::const_iterator itr = ranges_.begin();
        itr != ranges_.end(); ++itr) {
@@ -767,9 +862,9 @@
       DCHECK(!new_range_for_append);
       // Create a new range containing these buffers.
       new_range_for_append = new SourceBufferRange(
-            buffers, kNoTimestamp(),
-            base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
-                       base::Unretained(this)));
+          is_video(), buffers, kNoTimestamp(),
+          base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
+                     base::Unretained(this)));
       range_for_next_append_ = ranges_.end();
     } else {
       bytes_to_free -= bytes_deleted;
@@ -805,23 +900,21 @@
   return bytes_freed;
 }
 
-bool SourceBufferStream::InsertIntoExistingRange(
-    const RangeList::iterator& range_for_new_buffers_itr,
+void SourceBufferStream::PrepareRangesForNextAppend(
     const BufferQueue& new_buffers, BufferQueue* deleted_buffers) {
   DCHECK(deleted_buffers);
 
-  SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr;
-
   bool temporarily_select_range = false;
   if (!track_buffer_.empty()) {
     base::TimeDelta tb_timestamp = track_buffer_.back()->GetDecodeTimestamp();
     base::TimeDelta seek_timestamp = FindKeyframeAfterTimestamp(tb_timestamp);
     if (seek_timestamp != kNoTimestamp() &&
         seek_timestamp < new_buffers.front()->GetDecodeTimestamp() &&
-        range_for_new_buffers->BelongsToRange(seek_timestamp)) {
+        range_for_next_append_ != ranges_.end() &&
+        (*range_for_next_append_)->BelongsToRange(seek_timestamp)) {
       DCHECK(tb_timestamp < seek_timestamp);
       DCHECK(!selected_range_);
-      DCHECK(!range_for_new_buffers->HasNextBufferPosition());
+      DCHECK(!(*range_for_next_append_)->HasNextBufferPosition());
 
       // If there are GOPs between the end of the track buffer and the
       // beginning of the new buffers, then temporarily seek the range
@@ -829,7 +922,7 @@
       // |deleted_buffers| as if they were part of the current playback
       // position.
       // TODO(acolwell): Figure out a more elegant way to do this.
-      SeekAndSetSelectedRange(range_for_new_buffers, seek_timestamp);
+      SeekAndSetSelectedRange(*range_for_next_append_, seek_timestamp);
       temporarily_select_range = true;
     }
   }
@@ -842,74 +935,35 @@
   if (prev_timestamp != kNoTimestamp() && prev_timestamp != next_timestamp) {
     // Clean up the old buffers between the last appended buffer and the
     // beginning of |new_buffers|.
-    DeleteBetween(
-        range_for_new_buffers_itr, prev_timestamp, next_timestamp, true,
-        deleted_buffers);
+    RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers);
   }
 
-  bool is_exclusive = false;
-  if (prev_timestamp == next_timestamp) {
-    if (!new_media_segment_ &&
-        !AllowSameTimestamp(prev_is_keyframe, next_is_keyframe)) {
-      MEDIA_LOG(log_cb_) << "Invalid same timestamp construct detected at time "
-                         << prev_timestamp.InSecondsF();
-      return false;
-    }
+  // Make the delete range exclusive if we are dealing with an allowed same
+  // timestamp situation. This prevents the first buffer in the current append
+  // from deleting the last buffer in the previous append if both buffers
+  // have the same timestamp.
+  bool is_exclusive = (prev_timestamp == next_timestamp) &&
+      AllowSameTimestamp(prev_is_keyframe, next_is_keyframe, is_video());
 
-    // Make the delete range exclusive if we are dealing with an allowed same
-    // timestamp situation so that the buffer with the same timestamp that is
-    // already stored in |*range_for_new_buffers_itr| doesn't get deleted.
-    is_exclusive = AllowSameTimestamp(prev_is_keyframe, next_is_keyframe);
+  // Delete the buffers that |new_buffers| overlaps.
+  base::TimeDelta start = new_buffers.front()->GetDecodeTimestamp();
+  base::TimeDelta end = new_buffers.back()->GetDecodeTimestamp();
+  base::TimeDelta duration = new_buffers.back()->duration();
+
+  if (duration != kNoTimestamp() && duration > base::TimeDelta()) {
+    end += duration;
+  } else {
+    // TODO(acolwell): Ensure all buffers actually have proper
+    // duration info so that this hack isn't needed.
+    // http://crbug.com/312836
+    end += base::TimeDelta::FromInternalValue(1);
   }
 
-  // If we cannot append the |new_buffers| to the end of the existing range,
-  // this is either a start overlap or a middle overlap. Delete the buffers
-  // that |new_buffers| overlaps.
-  if (!range_for_new_buffers->CanAppendBuffersToEnd(new_buffers)) {
-    DeleteBetween(
-        range_for_new_buffers_itr, new_buffers.front()->GetDecodeTimestamp(),
-        new_buffers.back()->GetDecodeTimestamp(), is_exclusive,
-        deleted_buffers);
-  }
+  RemoveInternal(start, end, is_exclusive, deleted_buffers);
 
   // Restore the range seek state if necessary.
   if (temporarily_select_range)
     SetSelectedRange(NULL);
-
-  range_for_new_buffers->AppendBuffersToEnd(new_buffers);
-  return true;
-}
-
-void SourceBufferStream::DeleteBetween(
-    const RangeList::iterator& range_itr, base::TimeDelta start_timestamp,
-    base::TimeDelta end_timestamp, bool is_range_exclusive,
-    BufferQueue* deleted_buffers) {
-  SourceBufferRange* new_next_range =
-      (*range_itr)->SplitRange(end_timestamp, is_range_exclusive);
-
-  // Insert the |new_next_range| into |ranges_| after |range|.
-  if (new_next_range) {
-    RangeList::iterator next_range_itr = range_itr;
-    ranges_.insert(++next_range_itr, new_next_range);
-  }
-
-  BufferQueue saved_buffers;
-  (*range_itr)->TruncateAt(start_timestamp, &saved_buffers, is_range_exclusive);
-
-  if (selected_range_ != *range_itr)
-    return;
-
-  DCHECK(deleted_buffers->empty());
-  *deleted_buffers = saved_buffers;
-
-  // If the next buffer position has transferred to the split range, set the
-  // selected range accordingly.
-  if (new_next_range && new_next_range->HasNextBufferPosition()) {
-    DCHECK(!(*range_itr)->HasNextBufferPosition());
-    SetSelectedRange(new_next_range);
-  } else if (!selected_range_->HasNextBufferPosition()) {
-    SetSelectedRange(NULL);
-  }
 }
 
 bool SourceBufferStream::AreAdjacentInSequence(
@@ -919,70 +973,6 @@
       first_timestamp + ComputeFudgeRoom(GetMaxInterbufferDistance());
 }
 
-void SourceBufferStream::ResolveCompleteOverlaps(
-    const RangeList::iterator& range_with_new_buffers_itr,
-    BufferQueue* deleted_buffers) {
-  DCHECK(deleted_buffers);
-
-  SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
-  RangeList::iterator next_range_itr = range_with_new_buffers_itr;
-  ++next_range_itr;
-
-  while (next_range_itr != ranges_.end() &&
-         range_with_new_buffers->CompletelyOverlaps(**next_range_itr)) {
-    if (*next_range_itr == selected_range_) {
-      DCHECK(deleted_buffers->empty());
-      selected_range_->DeleteAll(deleted_buffers);
-    }
-    DeleteAndRemoveRange(&next_range_itr);
-  }
-}
-
-void SourceBufferStream::ResolveEndOverlap(
-    const RangeList::iterator& range_with_new_buffers_itr,
-    BufferQueue* deleted_buffers) {
-  DCHECK(deleted_buffers);
-
-  SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
-  RangeList::iterator overlapped_range_itr = range_with_new_buffers_itr;
-  ++overlapped_range_itr;
-
-  if (overlapped_range_itr == ranges_.end() ||
-      !range_with_new_buffers->EndOverlaps(**overlapped_range_itr)) {
-    return;
-  }
-
-  // Split the overlapped range after |range_with_new_buffers|'s last buffer
-  // overlaps. Now |*overlapped_range_itr| contains only the buffers that do not
-  // belong in |ranges_| anymore, and |new_next_range| contains buffers that
-  // go after |range_with_new_buffers| (without overlap).
-  SourceBufferRange* new_next_range =
-      (*overlapped_range_itr)->SplitRange(
-          range_with_new_buffers->GetEndTimestamp(), true);
-
-  if (selected_range_ == *overlapped_range_itr) {
-    SourceBufferRange* overlapped_range = *overlapped_range_itr;
-    // If the |overlapped_range| transfers its next buffer position to
-    // |new_next_range|, make |new_next_range| the |selected_range_|.
-    if (new_next_range && new_next_range->HasNextBufferPosition()) {
-      DCHECK(!overlapped_range->HasNextBufferPosition());
-      SetSelectedRange(new_next_range);
-    } else {
-      // The |overlapped_range| still has the current playback position.
-      // Move the buffers for the current playback position in
-      // |overlapped_range| into |deleted_buffers|.
-      DCHECK(overlapped_range->HasNextBufferPosition());
-      DCHECK(deleted_buffers->empty());
-      overlapped_range->DeleteAll(deleted_buffers);
-    }
-  }
-  DeleteAndRemoveRange(&overlapped_range_itr);
-
-  // If there were non-overlapped buffers, add the new range to |ranges_|.
-  if (new_next_range)
-    AddToRanges(new_next_range);
-}
-
 void SourceBufferStream::PruneTrackBuffer(const base::TimeDelta timestamp) {
   // If we don't have the next timestamp, we don't have anything to delete.
   if (timestamp == kNoTimestamp())
@@ -1175,6 +1165,7 @@
 }
 
 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) {
+  DVLOG(1) << __FUNCTION__ << " : " << selected_range_ << " -> " << range;
   if (selected_range_)
     selected_range_->ResetNextBufferPosition();
   DCHECK(!range || range->HasNextBufferPosition());
@@ -1454,18 +1445,29 @@
 }
 
 void SourceBufferStream::DeleteAndRemoveRange(RangeList::iterator* itr) {
+  DVLOG(1) << __FUNCTION__;
+
   DCHECK(*itr != ranges_.end());
-  if (**itr == selected_range_)
+  if (**itr == selected_range_) {
+    DVLOG(1) << __FUNCTION__ << " deleting selected range.";
     SetSelectedRange(NULL);
+  }
+
+  if (*itr == range_for_next_append_) {
+    DVLOG(1) << __FUNCTION__ << " deleting range_for_next_append_.";
+    range_for_next_append_ = ranges_.end();
+  }
 
   delete **itr;
   *itr = ranges_.erase(*itr);
 }
 
 SourceBufferRange::SourceBufferRange(
-    const BufferQueue& new_buffers, base::TimeDelta media_segment_start_time,
+    bool is_video, const BufferQueue& new_buffers,
+    base::TimeDelta media_segment_start_time,
     const InterbufferDistanceCB& interbuffer_distance_cb)
-    : keyframe_map_index_base_(0),
+    : is_video_(is_video),
+      keyframe_map_index_base_(0),
       next_buffer_index_(-1),
       media_segment_start_time_(media_segment_start_time),
       interbuffer_distance_cb_(interbuffer_distance_cb),
@@ -1477,9 +1479,7 @@
 }
 
 void SourceBufferRange::AppendBuffersToEnd(const BufferQueue& new_buffers) {
-  DCHECK(buffers_.empty() ||
-         buffers_.back()->GetDecodeTimestamp() <=
-         new_buffers.front()->GetDecodeTimestamp());
+  DCHECK(buffers_.empty() || CanAppendBuffersToEnd(new_buffers));
 
   for (BufferQueue::const_iterator itr = new_buffers.begin();
        itr != new_buffers.end(); ++itr) {
@@ -1558,7 +1558,7 @@
   // Create a new range with |removed_buffers|.
   SourceBufferRange* split_range =
       new SourceBufferRange(
-          removed_buffers, kNoTimestamp(), interbuffer_distance_cb_);
+          is_video_, removed_buffers, kNoTimestamp(), interbuffer_distance_cb_);
 
   // If the next buffer position is now in |split_range|, update the state of
   // this range and |split_range| accordingly.
@@ -1865,14 +1865,14 @@
 bool SourceBufferRange::CanAppendBuffersToEnd(
     const BufferQueue& buffers) const {
   DCHECK(!buffers_.empty());
-  return IsNextInSequence(buffers_.back(),
-                          buffers.front()->GetDecodeTimestamp());
+  return IsNextInSequence(buffers.front()->GetDecodeTimestamp(),
+                          buffers.front()->IsKeyframe());
 }
 
 bool SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const {
   DCHECK(!buffers_.empty());
 
-  return (IsNextInSequence(buffers_.back(), timestamp) ||
+  return (IsNextInSequence(timestamp, false) ||
           (GetStartTimestamp() <= timestamp && timestamp <= GetEndTimestamp()));
 }
 
@@ -1939,10 +1939,11 @@
 }
 
 bool SourceBufferRange::IsNextInSequence(
-    const scoped_refptr<media::StreamParserBuffer>& buffer,
-    base::TimeDelta timestamp) const {
-  return buffer->GetDecodeTimestamp() < timestamp &&
-      timestamp <= buffer->GetDecodeTimestamp() + GetFudgeRoom();
+    base::TimeDelta timestamp, bool is_keyframe) const {
+  base::TimeDelta end = buffers_.back()->GetDecodeTimestamp();
+  return (end < timestamp && timestamp <= end + GetFudgeRoom()) ||
+      (timestamp == end && AllowSameTimestamp(
+          buffers_.back()->IsKeyframe(), is_keyframe, is_video_));
 }
 
 base::TimeDelta SourceBufferRange::GetFudgeRoom() const {
diff --git a/media/filters/source_buffer_stream.h b/media/filters/source_buffer_stream.h
index 9594d9d..e0848af 100644
--- a/media/filters/source_buffer_stream.h
+++ b/media/filters/source_buffer_stream.h
@@ -153,29 +153,14 @@
       base::TimeDelta end_timestamp, int byte_to_free,
       base::TimeDelta* removal_end_timestamp);
 
-  // Appends |new_buffers| into |range_for_new_buffers_itr|, handling start and
-  // end overlaps if necessary.
+  // Prepares |range_for_next_append_| so |new_buffers| can be appended.
+  // This involves removing buffers between the end of the previous append
+  // and any buffers covered by the time range in |new_buffers|.
   // |deleted_buffers| is an output parameter containing candidates for
-  // |track_buffer_|.
-  // Returns true if the buffers were successfully inserted into the existing
-  // range.
-  // Returns false if the buffers being inserted triggered an error.
-  bool InsertIntoExistingRange(
-      const RangeList::iterator& range_for_new_buffers_itr,
-      const BufferQueue& new_buffers,
-      BufferQueue* deleted_buffers);
-
-  // Resolve overlapping ranges such that no ranges overlap anymore.
-  // |range_with_new_buffers_itr| points to the range that has newly appended
-  // buffers.
-  // |deleted_buffers| is an output parameter containing candidates for
-  // |track_buffer_|.
-  void ResolveCompleteOverlaps(
-      const RangeList::iterator& range_with_new_buffers_itr,
-      BufferQueue* deleted_buffers);
-  void ResolveEndOverlap(
-      const RangeList::iterator& range_with_new_buffers_itr,
-      BufferQueue* deleted_buffers);
+  // |track_buffer_| if this method ends up removing the current playback
+  // position from the range.
+  void PrepareRangesForNextAppend(const BufferQueue& new_buffers,
+                                  BufferQueue* deleted_buffers);
 
   // Removes buffers, from the |track_buffer_|, that come after |timestamp|.
   void PruneTrackBuffer(const base::TimeDelta timestamp);
@@ -185,17 +170,6 @@
   void MergeWithAdjacentRangeIfNecessary(
       const RangeList::iterator& range_with_new_buffers_itr);
 
-  // Deletes the buffers between |start_timestamp|, |end_timestamp| from
-  // the range that |range_itr| points to. Deletes between [start,end] if
-  // |is_range_exclusive| is true, or (start,end) if |is_range_exclusive| is
-  // false. Buffers are deleted in GOPs, so this method may delete buffers past
-  // |end_timestamp| if the keyframe a buffer depends on was deleted.
-  void DeleteBetween(const RangeList::iterator& range_itr,
-                     base::TimeDelta start_timestamp,
-                     base::TimeDelta end_timestamp,
-                     bool is_range_exclusive,
-                     BufferQueue* deleted_buffers);
-
   // Returns true if |second_timestamp| is the timestamp of the next buffer in
   // sequence after |first_timestamp|, false otherwise.
   bool AreAdjacentInSequence(
@@ -239,16 +213,15 @@
   // in |ranges_|, false otherwise or if |ranges_| is empty.
   bool ShouldSeekToStartOfBuffered(base::TimeDelta seek_timestamp) const;
 
-  // Returns true if the |prev_is_keyframe| & |current_is_keyframe| combination
-  // on buffers with the same timestamp should be allowed. Returns false if the
-  // combination should signal an error.
-  bool AllowSameTimestamp(bool prev_is_keyframe,
-                          bool current_is_keyframe) const;
-
   // Returns true if the timestamps of |buffers| are monotonically increasing
   // since the previous append to the media segment, false otherwise.
   bool IsMonotonicallyIncreasing(const BufferQueue& buffers) const;
 
+  // Returns true if |next_timestamp| and |next_is_keyframe| are valid for
+  // the first buffer after the previous append.
+  bool IsNextTimestampValid(base::TimeDelta next_timestamp,
+                            bool next_is_keyframe) const;
+
   // Returns true if |selected_range_| is the only range in |ranges_| that
   // HasNextBufferPosition().
   bool OnlySelectedRangeIsSeeked() const;
@@ -297,6 +270,20 @@
   // was removed or to |ranges_.end()| if the last range was removed.
   void DeleteAndRemoveRange(RangeList::iterator* itr);
 
+  // Helper function used by Remove() and PrepareRangesForNextAppend() to
+  // remove buffers and ranges between |start| and |end|.
+  // |is_exclusive| - If set to true, buffers with timestamps that
+  // match |start| are not removed. If set to false, buffers with
+  // timestamps that match |start| will be removed.
+  // |*deleted_buffers| - Filled with buffers for the current playback position
+  // if the removal range included the current playback position. These buffers
+  // can be used as candidates for placing in the |track_buffer_|.
+  void RemoveInternal(
+      base::TimeDelta start, base::TimeDelta end, bool is_exclusive,
+      BufferQueue* deleted_buffers);
+
+  bool is_video() const { return video_configs_.size() > 0; }
+
   // Callback used to report error strings that can help the web developer
   // figure out what is wrong with the content.
   LogCB log_cb_;
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index d0d4df2..8d66adc 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -238,7 +238,7 @@
 
   void CheckNoNextBuffer() {
     scoped_refptr<StreamParserBuffer> buffer;
-    EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kNeedBuffer);
+    EXPECT_EQ(SourceBufferStream::kNeedBuffer, stream_->GetNextBuffer(&buffer));
   }
 
   void CheckConfig(const VideoDecoderConfig& config) {
@@ -3160,6 +3160,71 @@
   CheckExpectedBuffers("150 180K 210 240 270K 300 330");
 }
 
+// Test removing the entire range for the current media segment
+// being appended.
+TEST_F(SourceBufferStreamTest, Remove_MidSegment) {
+  Seek(0);
+  NewSegmentAppend("0K 30 60 90 120K 150 180 210");
+  CheckExpectedRangesByTimestamp("{ [0,240) }");
+
+  NewSegmentAppend("0K 30");
+
+  CheckExpectedBuffers("0K");
+
+  CheckExpectedRangesByTimestamp("{ [0,60) [120,240) }");
+
+  // Remove the entire range that is being appended to.
+  RemoveInMs(0, 60, 240);
+
+  // Verify that there is no next buffer since it was removed.
+  CheckNoNextBuffer();
+
+  CheckExpectedRangesByTimestamp("{ [120,240) }");
+
+  // Continue appending frames for the current GOP.
+  AppendBuffers("60 90");
+
+  // Verify that the non-keyframes are not added.
+  CheckExpectedRangesByTimestamp("{ [120,240) }");
+
+  // Finish the previous GOP and start the next one.
+  AppendBuffers("120 150K 180");
+
+  // Verify that new GOP replaces the existing range.
+  CheckExpectedRangesByTimestamp("{ [150,210) }");
+
+
+  SeekToTimestamp(base::TimeDelta::FromMilliseconds(150));
+  CheckExpectedBuffers("150K 180");
+  CheckNoNextBuffer();
+}
+
+// Test removing the current GOP being appended, while not removing
+// the entire range the GOP belongs to.
+TEST_F(SourceBufferStreamTest, Remove_GOPBeingAppended) {
+  Seek(0);
+  NewSegmentAppend("0K 30 60 90 120K 150 180");
+  CheckExpectedRangesByTimestamp("{ [0,210) }");
+
+  // Remove the current GOP being appended.
+  RemoveInMs(120, 150, 240);
+  CheckExpectedRangesByTimestamp("{ [0,120) }");
+
+  // Continue appending the current GOP and the next one.
+  AppendBuffers("210 240K 270 300");
+
+  // Verify that the non-keyframe in the previous GOP does
+  // not effect any existing ranges and a new range is started at the
+  // beginning of the next GOP.
+  CheckExpectedRangesByTimestamp("{ [0,120) [240,330) }");
+
+  // Verify the buffers in the ranges.
+  CheckExpectedBuffers("0K 30 60 90");
+  CheckNoNextBuffer();
+  SeekToTimestamp(base::TimeDelta::FromMilliseconds(240));
+  CheckExpectedBuffers("240K 270 300");
+}
+
 // TODO(vrk): Add unit tests where keyframes are unaligned between streams.
 // (crbug.com/133557)
 
diff --git a/media/media.gyp b/media/media.gyp
index dfcc858..1bc687f 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -393,6 +393,9 @@
         'video/capture/fake_video_capture_device.h',
         'video/capture/linux/video_capture_device_linux.cc',
         'video/capture/linux/video_capture_device_linux.h',
+        'video/capture/mac/avfoundation_glue.h',
+        'video/capture/mac/avfoundation_glue.mm',
+        'video/capture/mac/platform_video_capturing_mac.h',
         'video/capture/mac/video_capture_device_mac.h',
         'video/capture/mac/video_capture_device_mac.mm',
         'video/capture/mac/video_capture_device_qtkit_mac.h',
@@ -1065,10 +1068,31 @@
       ],
     },
     {
+      'target_name': 'media_perftests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'media',
+        'media_test_support',
+        'shared_memory_support',
+        '../base/base.gyp:test_support_base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../testing/perf/perf_test.gyp:perf_test',
+      ],
+      'sources': [
+        'base/audio_bus_perftest.cc',
+        'base/audio_converter_perftest.cc',
+        'base/sinc_resampler_perftest.cc',
+        'base/run_all_unittests.cc',
+        'base/vector_math_perftest.cc',
+      ],
+    },
+    {
       'target_name': 'media_test_support',
       'type': 'static_library',
       'dependencies': [
         'media',
+        'shared_memory_support',
         '../base/base.gyp:base',
         '../skia/skia.gyp:skia',
         '../testing/gmock.gyp:gmock',
diff --git a/media/media.target.darwin-arm.mk b/media/media.target.darwin-arm.mk
index d49022e..3521eac 100644
--- a/media/media.target.darwin-arm.mk
+++ b/media/media.target.darwin-arm.mk
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -325,13 +325,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media.target.darwin-mips.mk b/media/media.target.darwin-mips.mk
index ef4457c..165afca 100644
--- a/media/media.target.darwin-mips.mk
+++ b/media/media.target.darwin-mips.mk
@@ -213,13 +213,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -323,13 +323,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media.target.darwin-x86.mk b/media/media.target.darwin-x86.mk
index 0edc1d6..212ad45 100644
--- a/media/media.target.darwin-x86.mk
+++ b/media/media.target.darwin-x86.mk
@@ -217,13 +217,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -330,13 +330,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media.target.linux-arm.mk b/media/media.target.linux-arm.mk
index d49022e..3521eac 100644
--- a/media/media.target.linux-arm.mk
+++ b/media/media.target.linux-arm.mk
@@ -214,13 +214,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -325,13 +325,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media.target.linux-mips.mk b/media/media.target.linux-mips.mk
index ef4457c..165afca 100644
--- a/media/media.target.linux-mips.mk
+++ b/media/media.target.linux-mips.mk
@@ -213,13 +213,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -323,13 +323,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media.target.linux-x86.mk b/media/media.target.linux-x86.mk
index 0edc1d6..212ad45 100644
--- a/media/media.target.linux-x86.mk
+++ b/media/media.target.linux-x86.mk
@@ -217,13 +217,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -330,13 +330,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.darwin-arm.mk b/media/media_android_imageformat_list.target.darwin-arm.mk
index 4dc13f8..94261cc 100644
--- a/media/media_android_imageformat_list.target.darwin-arm.mk
+++ b/media/media_android_imageformat_list.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.darwin-mips.mk b/media/media_android_imageformat_list.target.darwin-mips.mk
index 32085bb..f77d082 100644
--- a/media/media_android_imageformat_list.target.darwin-mips.mk
+++ b/media/media_android_imageformat_list.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.darwin-x86.mk b/media/media_android_imageformat_list.target.darwin-x86.mk
index 0bc677d..d36c3ab 100644
--- a/media/media_android_imageformat_list.target.darwin-x86.mk
+++ b/media/media_android_imageformat_list.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.linux-arm.mk b/media/media_android_imageformat_list.target.linux-arm.mk
index 4dc13f8..94261cc 100644
--- a/media/media_android_imageformat_list.target.linux-arm.mk
+++ b/media/media_android_imageformat_list.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.linux-mips.mk b/media/media_android_imageformat_list.target.linux-mips.mk
index 32085bb..f77d082 100644
--- a/media/media_android_imageformat_list.target.linux-mips.mk
+++ b/media/media_android_imageformat_list.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_imageformat_list.target.linux-x86.mk b/media/media_android_imageformat_list.target.linux-x86.mk
index 0bc677d..d36c3ab 100644
--- a/media/media_android_imageformat_list.target.linux-x86.mk
+++ b/media/media_android_imageformat_list.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.darwin-arm.mk b/media/media_android_jni_headers.target.darwin-arm.mk
index c16ffe1..00ad823 100644
--- a/media/media_android_jni_headers.target.darwin-arm.mk
+++ b/media/media_android_jni_headers.target.darwin-arm.mk
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -218,13 +218,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.darwin-mips.mk b/media/media_android_jni_headers.target.darwin-mips.mk
index b37847c..7547e64 100644
--- a/media/media_android_jni_headers.target.darwin-mips.mk
+++ b/media/media_android_jni_headers.target.darwin-mips.mk
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.darwin-x86.mk b/media/media_android_jni_headers.target.darwin-x86.mk
index 57b7b50..74e1a96 100644
--- a/media/media_android_jni_headers.target.darwin-x86.mk
+++ b/media/media_android_jni_headers.target.darwin-x86.mk
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -223,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.linux-arm.mk b/media/media_android_jni_headers.target.linux-arm.mk
index c16ffe1..00ad823 100644
--- a/media/media_android_jni_headers.target.linux-arm.mk
+++ b/media/media_android_jni_headers.target.linux-arm.mk
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -218,13 +218,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.linux-mips.mk b/media/media_android_jni_headers.target.linux-mips.mk
index b37847c..7547e64 100644
--- a/media/media_android_jni_headers.target.linux-mips.mk
+++ b/media/media_android_jni_headers.target.linux-mips.mk
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_android_jni_headers.target.linux-x86.mk b/media/media_android_jni_headers.target.linux-x86.mk
index 57b7b50..74e1a96 100644
--- a/media/media_android_jni_headers.target.linux-x86.mk
+++ b/media/media_android_jni_headers.target.linux-x86.mk
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -223,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_asm.target.darwin-x86.mk b/media/media_asm.target.darwin-x86.mk
index b4f3682..bfaf5de 100644
--- a/media/media_asm.target.darwin-x86.mk
+++ b/media/media_asm.target.darwin-x86.mk
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -259,13 +259,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_asm.target.linux-x86.mk b/media/media_asm.target.linux-x86.mk
index b4f3682..bfaf5de 100644
--- a/media/media_asm.target.linux-x86.mk
+++ b/media/media_asm.target.linux-x86.mk
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -259,13 +259,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_mmx.target.darwin-x86.mk b/media/media_mmx.target.darwin-x86.mk
index 92e0ff3..bfdfd6a8 100644
--- a/media/media_mmx.target.darwin-x86.mk
+++ b/media/media_mmx.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_mmx.target.linux-x86.mk b/media/media_mmx.target.linux-x86.mk
index 92e0ff3..bfdfd6a8 100644
--- a/media/media_mmx.target.linux-x86.mk
+++ b/media/media_mmx.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_sse.target.darwin-x86.mk b/media/media_sse.target.darwin-x86.mk
index 3a8f94c..44de2e9 100644
--- a/media/media_sse.target.darwin-x86.mk
+++ b/media/media_sse.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_sse.target.linux-x86.mk b/media/media_sse.target.linux-x86.mk
index 3a8f94c..44de2e9 100644
--- a/media/media_sse.target.linux-x86.mk
+++ b/media/media_sse.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_sse2.target.darwin-x86.mk b/media/media_sse2.target.darwin-x86.mk
index 0c6e0f3..86927fa 100644
--- a/media/media_sse2.target.darwin-x86.mk
+++ b/media/media_sse2.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/media_sse2.target.linux-x86.mk b/media/media_sse2.target.linux-x86.mk
index 0c6e0f3..86927fa 100644
--- a/media/media_sse2.target.linux-x86.mk
+++ b/media/media_sse2.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/midi/midi_manager_mac.cc b/media/midi/midi_manager_mac.cc
index 42de02e..0294024 100644
--- a/media/midi/midi_manager_mac.cc
+++ b/media/midi/midi_manager_mac.cc
@@ -133,7 +133,7 @@
   uint32 port_index = source_map_[source];
 
   // Go through each packet and process separately.
-  for(size_t i = 0; i < packet_list->numPackets; i++) {
+  for (size_t i = 0; i < packet_list->numPackets; i++) {
     // Each packet contains MIDI data for one or more messages (like note-on).
     const MIDIPacket &packet = packet_list->packet[i];
     double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);
@@ -184,19 +184,39 @@
   MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
   string id = IntToString(id_number);
 
+  string manufacturer;
   CFStringRef manufacturer_ref = NULL;
-  MIDIObjectGetStringProperty(
+  OSStatus result = MIDIObjectGetStringProperty(
       endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
-  string manufacturer = SysCFStringRefToUTF8(manufacturer_ref);
+  if (result == noErr) {
+    manufacturer = SysCFStringRefToUTF8(manufacturer_ref);
+  } else {
+    // kMIDIPropertyManufacturer is not supported in IAC driver providing
+    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
+    DLOG(WARNING) << "Failed to get kMIDIPropertyManufacturer with status "
+                  << result;
+  }
 
+  string name;
   CFStringRef name_ref = NULL;
-  MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
-  string name = SysCFStringRefToUTF8(name_ref);
+  result = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
+  if (result == noErr)
+    name = SysCFStringRefToUTF8(name_ref);
+  else
+    DLOG(WARNING) << "Failed to get kMIDIPropertyName with status " << result;
 
+  string version;
   SInt32 version_number = 0;
-  MIDIObjectGetIntegerProperty(
+  result = MIDIObjectGetIntegerProperty(
       endpoint, kMIDIPropertyDriverVersion, &version_number);
-  string version = IntToString(version_number);
+  if (result == noErr) {
+    version = IntToString(version_number);
+  } else {
+    // kMIDIPropertyDriverVersion is not supported in IAC driver providing
+    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
+    DLOG(WARNING) << "Failed to get kMIDIPropertyDriverVersion with status "
+                  << result;
+  }
 
   return MIDIPortInfo(id, manufacturer, name, version);
 }
diff --git a/media/mp4/box_definitions.cc b/media/mp4/box_definitions.cc
index 218e5bb..74d216f 100644
--- a/media/mp4/box_definitions.cc
+++ b/media/mp4/box_definitions.cc
@@ -743,7 +743,8 @@
          reader->ReadChild(&decode_time) &&
          reader->MaybeReadChildren(&runs) &&
          reader->MaybeReadChild(&auxiliary_offset) &&
-         reader->MaybeReadChild(&auxiliary_size);
+         reader->MaybeReadChild(&auxiliary_size) &&
+         reader->MaybeReadChild(&sdtp);
 }
 
 MovieFragment::MovieFragment() {}
@@ -758,5 +759,38 @@
   return true;
 }
 
+IndependentAndDisposableSamples::IndependentAndDisposableSamples() {}
+IndependentAndDisposableSamples::~IndependentAndDisposableSamples() {}
+FourCC IndependentAndDisposableSamples::BoxType() const { return FOURCC_SDTP; }
+
+bool IndependentAndDisposableSamples::Parse(BoxReader* reader) {
+  RCHECK(reader->ReadFullBoxHeader());
+  RCHECK(reader->version() == 0);
+  RCHECK(reader->flags() == 0);
+
+  int sample_count = reader->size() - reader->pos();
+  sample_depends_on_.resize(sample_count);
+  for (int i = 0; i < sample_count; ++i) {
+    uint8 sample_info;
+    RCHECK(reader->Read1(&sample_info));
+    RCHECK((sample_info >> 6) == 0);  // reserved.
+
+    sample_depends_on_[i] =
+        static_cast<SampleDependsOn>((sample_info >> 4) & 0x3);
+
+    RCHECK(sample_depends_on_[i] != kSampleDependsOnReserved);
+  }
+
+  return true;
+}
+
+SampleDependsOn IndependentAndDisposableSamples::sample_depends_on(
+    size_t i) const {
+  if (i >= sample_depends_on_.size())
+    return kSampleDependsOnUnknown;
+
+  return sample_depends_on_[i];
+}
+
 }  // namespace mp4
 }  // namespace media
diff --git a/media/mp4/box_definitions.h b/media/mp4/box_definitions.h
index d2af86d..7499961 100644
--- a/media/mp4/box_definitions.h
+++ b/media/mp4/box_definitions.h
@@ -327,6 +327,27 @@
   std::vector<int32> sample_composition_time_offsets;
 };
 
+// sample_depends_on values in ISO/IEC 14496-12 Section 8.40.2.3.
+enum SampleDependsOn {
+  kSampleDependsOnUnknown = 0,
+  kSampleDependsOnOthers = 1,
+  kSampleDependsOnNoOther = 2,
+  kSampleDependsOnReserved = 3,
+};
+
+class MEDIA_EXPORT IndependentAndDisposableSamples : public Box {
+ public:
+  DECLARE_BOX_METHODS(IndependentAndDisposableSamples);
+
+  // Returns the SampleDependsOn value for the |i|'th value
+  // in the track. If no data was parsed for the |i|'th sample,
+  // then |kSampleDependsOnUnknown| is returned.
+  SampleDependsOn sample_depends_on(size_t i) const;
+
+ private:
+  std::vector<SampleDependsOn> sample_depends_on_;
+};
+
 struct MEDIA_EXPORT TrackFragment : Box {
   DECLARE_BOX_METHODS(TrackFragment);
 
@@ -335,6 +356,7 @@
   TrackFragmentDecodeTime decode_time;
   SampleAuxiliaryInformationOffset auxiliary_offset;
   SampleAuxiliaryInformationSize auxiliary_size;
+  IndependentAndDisposableSamples sdtp;
 };
 
 struct MEDIA_EXPORT MovieFragment : Box {
diff --git a/media/mp4/track_run_iterator.cc b/media/mp4/track_run_iterator.cc
index f16a8bf..116b806 100644
--- a/media/mp4/track_run_iterator.cc
+++ b/media/mp4/track_run_iterator.cc
@@ -76,7 +76,8 @@
                                const TrackFragmentRun& trun,
                                const int64 edit_list_offset,
                                const uint32 i,
-                               SampleInfo* sample_info) {
+                               SampleInfo* sample_info,
+                               const SampleDependsOn sample_depends_on) {
   if (i < trun.sample_sizes.size()) {
     sample_info->size = trun.sample_sizes[i];
   } else if (tfhd.default_sample_size > 0) {
@@ -108,7 +109,23 @@
   } else {
     flags = trex.default_sample_flags;
   }
-  sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask);
+
+  switch (sample_depends_on) {
+    case kSampleDependsOnUnknown:
+      sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask);
+      break;
+
+    case kSampleDependsOnOthers:
+      sample_info->is_keyframe = false;
+      break;
+
+    case kSampleDependsOnNoOther:
+      sample_info->is_keyframe = true;
+      break;
+
+    case kSampleDependsOnReserved:
+      CHECK(false);
+  }
 }
 
 // In well-structured encrypted media, each track run will be immediately
@@ -249,7 +266,7 @@
       tri.samples.resize(trun.sample_count);
       for (size_t k = 0; k < trun.sample_count; k++) {
         PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset,
-                           k, &tri.samples[k]);
+                           k, &tri.samples[k], traf.sdtp.sample_depends_on(k));
         run_start_dts += tri.samples[k].duration;
       }
       runs_.push_back(tri);
diff --git a/media/player_android.target.darwin-arm.mk b/media/player_android.target.darwin-arm.mk
index 904dd4f..d39c428 100644
--- a/media/player_android.target.darwin-arm.mk
+++ b/media/player_android.target.darwin-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/player_android.target.darwin-mips.mk b/media/player_android.target.darwin-mips.mk
index fcb2e2a..340a290 100644
--- a/media/player_android.target.darwin-mips.mk
+++ b/media/player_android.target.darwin-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/player_android.target.darwin-x86.mk b/media/player_android.target.darwin-x86.mk
index e222846..9a99881 100644
--- a/media/player_android.target.darwin-x86.mk
+++ b/media/player_android.target.darwin-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/player_android.target.linux-arm.mk b/media/player_android.target.linux-arm.mk
index 904dd4f..d39c428 100644
--- a/media/player_android.target.linux-arm.mk
+++ b/media/player_android.target.linux-arm.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/player_android.target.linux-mips.mk b/media/player_android.target.linux-mips.mk
index fcb2e2a..340a290 100644
--- a/media/player_android.target.linux-mips.mk
+++ b/media/player_android.target.linux-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/player_android.target.linux-x86.mk b/media/player_android.target.linux-x86.mk
index e222846..9a99881 100644
--- a/media/player_android.target.linux-x86.mk
+++ b/media/player_android.target.linux-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.gypi b/media/shared_memory_support.gypi
index 0f1c53a..65403f7 100644
--- a/media/shared_memory_support.gypi
+++ b/media/shared_memory_support.gypi
@@ -10,8 +10,6 @@
     'shared_memory_support_sources': [
       'audio/audio_parameters.cc',
       'audio/audio_parameters.h',
-      'audio/shared_memory_util.cc',
-      'audio/shared_memory_util.h',
       'base/audio_bus.cc',
       'base/audio_bus.h',
       'base/channel_layout.cc',
diff --git a/media/shared_memory_support.target.darwin-arm.mk b/media/shared_memory_support.target.darwin-arm.mk
index df71141..68c9ffd 100644
--- a/media/shared_memory_support.target.darwin-arm.mk
+++ b/media/shared_memory_support.target.darwin-arm.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -67,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.target.darwin-mips.mk b/media/shared_memory_support.target.darwin-mips.mk
index ea46082..1fcca92 100644
--- a/media/shared_memory_support.target.darwin-mips.mk
+++ b/media/shared_memory_support.target.darwin-mips.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -66,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.target.darwin-x86.mk b/media/shared_memory_support.target.darwin-x86.mk
index d48a887..e117864 100644
--- a/media/shared_memory_support.target.darwin-x86.mk
+++ b/media/shared_memory_support.target.darwin-x86.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -69,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.target.linux-arm.mk b/media/shared_memory_support.target.linux-arm.mk
index df71141..68c9ffd 100644
--- a/media/shared_memory_support.target.linux-arm.mk
+++ b/media/shared_memory_support.target.linux-arm.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -67,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.target.linux-mips.mk b/media/shared_memory_support.target.linux-mips.mk
index ea46082..1fcca92 100644
--- a/media/shared_memory_support.target.linux-mips.mk
+++ b/media/shared_memory_support.target.linux-mips.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -66,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support.target.linux-x86.mk b/media/shared_memory_support.target.linux-x86.mk
index d48a887..e117864 100644
--- a/media/shared_memory_support.target.linux-x86.mk
+++ b/media/shared_memory_support.target.linux-x86.mk
@@ -24,7 +24,6 @@
 
 LOCAL_SRC_FILES := \
 	media/audio/audio_parameters.cc \
-	media/audio/shared_memory_util.cc \
 	media/base/audio_bus.cc \
 	media/base/channel_layout.cc \
 	media/base/vector_math.cc
@@ -69,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support_sse.target.darwin-x86.mk b/media/shared_memory_support_sse.target.darwin-x86.mk
index 62cbddd..2ba5611 100644
--- a/media/shared_memory_support_sse.target.darwin-x86.mk
+++ b/media/shared_memory_support_sse.target.darwin-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/shared_memory_support_sse.target.linux-x86.mk b/media/shared_memory_support_sse.target.linux-x86.mk
index 62cbddd..2ba5611 100644
--- a/media/shared_memory_support_sse.target.linux-x86.mk
+++ b/media/shared_memory_support_sse.target.linux-x86.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/tools/layout_tests/layouttest_analyzer_helpers.py b/media/tools/layout_tests/layouttest_analyzer_helpers.py
index 2eb3c15..e5791bc 100644
--- a/media/tools/layout_tests/layouttest_analyzer_helpers.py
+++ b/media/tools/layout_tests/layouttest_analyzer_helpers.py
@@ -150,7 +150,7 @@
     if delta <= 0:
       raise ValueError('The number of tests in test group "whole" is equal or '
                        'less than that of "skip"')
-    return 100 - len(self.result_map['nonskip'].keys()) * 100 / delta
+    return 100 - len(self.result_map['nonskip'].keys()) * 100.0 / delta
 
   def ConvertToCSVText(self, current_time):
     """Convert |self.result_map| into stats and issues text in CSV format.
@@ -214,7 +214,7 @@
           '<li>The number of tests: %d (%s)</li>'
           '<li>The number of failing skipped tests: %d (%s)</li>'
           '<li>The number of failing non-skipped tests: %d (%s)</li>'
-          '<li>Passing rate: %d %%</li></ul>') % (
+          '<li>Passing rate: %.2f %%</li></ul>') % (
               prev_time, len(self.result_map['whole'].keys()),
               AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'),
               len(self.result_map['skip'].keys()),
diff --git a/media/video/capture/fake_video_capture_device.cc b/media/video/capture/fake_video_capture_device.cc
index 8b44e1f..278bfcb 100644
--- a/media/video/capture/fake_video_capture_device.cc
+++ b/media/video/capture/fake_video_capture_device.cc
@@ -89,8 +89,6 @@
 
   client_ = client.Pass();
   capture_format_.color = PIXEL_FORMAT_I420;
-  capture_format_.expected_capture_delay = 0;
-  capture_format_.interlaced = false;
   if (capture_format.width > 320) {  // VGA
     capture_format_.width = 640;
     capture_format_.height = 480;
@@ -222,24 +220,18 @@
                                     240,
                                     30,
                                     PIXEL_FORMAT_I420,
-                                    0,
-                                    false,
                                     VariableResolutionVideoCaptureDevice));
   capabilities_roster_.push_back(
       media::VideoCaptureCapability(640,
                                     480,
                                     30,
                                     PIXEL_FORMAT_I420,
-                                    0,
-                                    false,
                                     VariableResolutionVideoCaptureDevice));
   capabilities_roster_.push_back(
       media::VideoCaptureCapability(800,
                                     600,
                                     30,
                                     PIXEL_FORMAT_I420,
-                                    0,
-                                    false,
                                     VariableResolutionVideoCaptureDevice));
 
   capabilities_roster_index_ = 0;
diff --git a/media/video/capture/linux/video_capture_device_linux.cc b/media/video/capture/linux/video_capture_device_linux.cc
index f5c8147..1b9be94 100644
--- a/media/video/capture/linux/video_capture_device_linux.cc
+++ b/media/video/capture/linux/video_capture_device_linux.cc
@@ -415,8 +415,6 @@
   current_settings.width  = video_fmt.fmt.pix.width;
   current_settings.height = video_fmt.fmt.pix.height;
   current_settings.frame_rate = frame_rate;
-  current_settings.expected_capture_delay = 0;
-  current_settings.interlaced = false;
 
   // Report the resulting frame size to the client.
   client_->OnFrameInfo(current_settings);
diff --git a/media/video/capture/mac/avfoundation_glue.h b/media/video/capture/mac/avfoundation_glue.h
new file mode 100644
index 0000000..24da298
--- /dev/null
+++ b/media/video/capture/mac/avfoundation_glue.h
@@ -0,0 +1,67 @@
+// Copyright 2013 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.
+
+// AVFoundation API is only introduced in Mac OS X > 10.6, and there is only one
+// build of Chromium, so the (potential) linking with AVFoundation has to happen
+// in runtime. For this to be clean, a AVFoundationGlue class is defined to try
+// and load these AVFoundation system libraries. If it succeeds, subsequent
+// clients can use AVFoundation via the rest of the classes declared in this
+// file.
+
+#ifndef MEDIA_VIDEO_CAPTURE_MAC_AVFOUNDATION_GLUE_H_
+#define MEDIA_VIDEO_CAPTURE_MAC_AVFOUNDATION_GLUE_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/basictypes.h"
+#include "media/base/media_export.h"
+
+class MEDIA_EXPORT AVFoundationGlue {
+ public:
+  // This method returns true if the OS version supports AVFoundation and the
+  // AVFoundation bundle could be loaded correctly, or false otherwise.
+  static bool IsAVFoundationSupported();
+
+  static NSBundle const* AVFoundationBundle();
+
+  static void* AVFoundationLibraryHandle();
+
+  // Originally coming from AVCaptureDevice.h but in global namespace.
+  static NSString* AVCaptureDeviceWasConnectedNotification();
+  static NSString* AVCaptureDeviceWasDisconnectedNotification();
+
+  // Originally coming from AVMediaFormat.h but in global namespace.
+  static NSString* AVMediaTypeVideo();
+  static NSString* AVMediaTypeAudio();
+  static NSString* AVMediaTypeMuxed();
+
+ private:
+  static NSString* ReadNSStringPtr(const char* symbol);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(AVFoundationGlue);
+};
+
+// Originally AVCaptureDevice and coming from AVCaptureDevice.h
+MEDIA_EXPORT
+@interface CrAVCaptureDevice : NSObject
+
+- (BOOL)hasMediaType:(NSString*)mediaType;
+
+- (NSString*)uniqueID;
+
+@end
+
+MEDIA_EXPORT
+@interface AVCaptureDeviceGlue : NSObject
+
++ (NSArray*)devices;
+
++ (BOOL)hasMediaType:(NSString*)mediaType
+    forCaptureDevice:(CrAVCaptureDevice*)device;
+
++ (NSString*)uniqueID:(CrAVCaptureDevice*)device;
+
+@end
+
+#endif  // MEDIA_VIDEO_CAPTURE_MAC_AVFOUNDATION_GLUE_H_
diff --git a/media/video/capture/mac/avfoundation_glue.mm b/media/video/capture/mac/avfoundation_glue.mm
new file mode 100644
index 0000000..5510141
--- /dev/null
+++ b/media/video/capture/mac/avfoundation_glue.mm
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "media/video/capture/mac/avfoundation_glue.h"
+
+#include <dlfcn.h>
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "media/base/media_switches.h"
+
+bool AVFoundationGlue::IsAVFoundationSupported() {
+  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+  return cmd_line->HasSwitch(switches::kEnableAVFoundation) &&
+      base::mac::IsOSLionOrLater() && [AVFoundationBundle() load];
+}
+
+NSBundle const* AVFoundationGlue::AVFoundationBundle() {
+  static NSBundle* bundle = [NSBundle
+      bundleWithPath:@"/System/Library/Frameworks/AVFoundation.framework"];
+  return bundle;
+}
+
+void* AVFoundationGlue::AVFoundationLibraryHandle() {
+  const char* library_path =
+      [[AVFoundationBundle() executablePath] fileSystemRepresentation];
+  if (library_path == NULL) {
+    DCHECK(false);
+    return NULL;
+  }
+  static void* library_handle = dlopen(library_path, RTLD_LAZY | RTLD_LOCAL);
+  DCHECK(library_handle) << dlerror();
+  return library_handle;
+}
+
+NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() {
+  return ReadNSStringPtr("AVCaptureDeviceWasConnectedNotification");
+}
+
+NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() {
+  return ReadNSStringPtr("AVCaptureDeviceWasDisconnectedNotification");
+}
+
+NSString* AVFoundationGlue::AVMediaTypeVideo() {
+  return ReadNSStringPtr("AVMediaTypeVideo");
+}
+
+NSString* AVFoundationGlue::AVMediaTypeAudio() {
+  return ReadNSStringPtr("AVMediaTypeAudio");
+}
+
+NSString* AVFoundationGlue::AVMediaTypeMuxed() {
+  return ReadNSStringPtr("AVMediaTypeMuxed");
+}
+
+NSString* AVFoundationGlue::ReadNSStringPtr(const char* symbol) {
+  NSString** string_pointer = reinterpret_cast<NSString**>(
+      dlsym(AVFoundationLibraryHandle(), symbol));
+  DCHECK(string_pointer) << dlerror();
+  return *string_pointer;
+}
+
+@implementation AVCaptureDeviceGlue
+
++ (NSArray*)devices {
+  Class avcClass =
+      [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
+  SEL selectorDevices = NSSelectorFromString(@"devices");
+  if ([avcClass respondsToSelector:selectorDevices]) {
+    return [avcClass performSelector:selectorDevices];
+  }
+  return nil;
+}
+
++ (BOOL)hasMediaType:(NSString*)mediaType
+    forCaptureDevice:(CrAVCaptureDevice*)device {
+  SEL selectorHasMediaType = NSSelectorFromString(@"hasMediaType:");
+  if ([device respondsToSelector:selectorHasMediaType]) {
+    return [device hasMediaType:mediaType];
+  }
+  return NO;
+}
+
++ (NSString*)uniqueID:(CrAVCaptureDevice*)device {
+  SEL selectorUniqueID = NSSelectorFromString(@"uniqueID");
+  if ([device respondsToSelector:selectorUniqueID]) {
+    return [device uniqueID];
+  }
+  return nil;
+}
+
+@end  // @implementation AVCaptureDevice
diff --git a/media/video/capture/mac/platform_video_capturing_mac.h b/media/video/capture/mac/platform_video_capturing_mac.h
new file mode 100644
index 0000000..466ae1b
--- /dev/null
+++ b/media/video/capture/mac/platform_video_capturing_mac.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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_VIDEO_CAPTURE_MAC_PLATFORM_VIDEO_CAPTURING_MAC_H_
+#define MEDIA_VIDEO_CAPTURE_MAC_PLATFORM_VIDEO_CAPTURING_MAC_H_
+
+#import <Foundation/Foundation.h>
+
+namespace media {
+class VideoCaptureDeviceMac;
+}
+
+// Protocol representing platform-dependent video capture on Mac, implemented
+// by both QTKit and AVFoundation APIs.
+@protocol PlatformVideoCapturingMac <NSObject>
+
+// This method initializes the instance by calling NSObject |init| and registers
+// internally a frame receiver at the same time. The frame receiver is supposed
+// to be initialised before and outlive the VideoCapturingDeviceMac
+// implementation.
+- (id)initWithFrameReceiver:(media::VideoCaptureDeviceMac*)frameReceiver;
+
+// Set the frame receiver. This method executes the registration in mutual
+// exclusion.
+// TODO(mcasas): This method and stopCapture() are always called in sequence and
+// this one is only used to clear the frameReceiver, investigate if both can be
+// merged.
+- (void)setFrameReceiver:(media::VideoCaptureDeviceMac*)frameReceiver;
+
+// Sets which capture device to use by name passed as deviceId argument. The
+// device names are usually obtained via VideoCaptureDevice::GetDeviceNames()
+// method. This method will also configure all device properties except those in
+// setCaptureHeight:widht:frameRate. If |deviceId| is nil, all potential
+// configuration is torn down. Returns YES on sucess, NO otherwise.
+- (BOOL)setCaptureDevice:(NSString*)deviceId;
+
+// Configures the capture properties.
+- (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate;
+
+// Start video capturing, register observers. Returns YES on sucess, NO
+// otherwise.
+- (BOOL)startCapture;
+
+// Stops video capturing, unregisters observers.
+- (void)stopCapture;
+
+@end
+
+#endif  // MEDIA_VIDEO_CAPTURE_MAC_PLATFORM_VIDEO_CAPTURING_MAC_H_
diff --git a/media/video/capture/mac/video_capture_device_mac.h b/media/video/capture/mac/video_capture_device_mac.h
index f27b57a..5e08223 100644
--- a/media/video/capture/mac/video_capture_device_mac.h
+++ b/media/video/capture/mac/video_capture_device_mac.h
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// OS X implementation of VideoCaptureDevice, using QTKit as native capture API.
+// MacOSX implementation of generic VideoCaptureDevice, using either QTKit or
+// AVFoundation as native capture API. QTKit is used in OSX versions 10.6 and
+// previous, and AVFoundation is used in the rest.
 
 #ifndef MEDIA_VIDEO_CAPTURE_MAC_VIDEO_CAPTURE_DEVICE_MAC_H_
 #define MEDIA_VIDEO_CAPTURE_MAC_VIDEO_CAPTURE_DEVICE_MAC_H_
@@ -16,7 +18,7 @@
 #include "media/video/capture/video_capture_device.h"
 #include "media/video/capture/video_capture_types.h"
 
-@class VideoCaptureDeviceQTKit;
+@protocol PlatformVideoCapturingMac;
 
 namespace media {
 
@@ -71,7 +73,7 @@
   base::WeakPtrFactory<VideoCaptureDeviceMac> weak_factory_;
   base::WeakPtr<VideoCaptureDeviceMac> weak_this_;
 
-  VideoCaptureDeviceQTKit* capture_device_;
+  id<PlatformVideoCapturingMac> capture_device_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceMac);
 };
diff --git a/media/video/capture/mac/video_capture_device_mac.mm b/media/video/capture/mac/video_capture_device_mac.mm
index 2be65da..8235ede 100644
--- a/media/video/capture/mac/video_capture_device_mac.mm
+++ b/media/video/capture/mac/video_capture_device_mac.mm
@@ -4,12 +4,11 @@
 
 #include "media/video/capture/mac/video_capture_device_mac.h"
 
-#import <QTKit/QTKit.h>
-
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/time/time.h"
+#import "media/video/capture/mac/platform_video_capturing_mac.h"
 #include "media/video/capture/mac/video_capture_device_qtkit_mac.h"
 
 namespace {
@@ -129,11 +128,10 @@
   int height = capture_format.height;
   int frame_rate = capture_format.frame_rate;
 
-  // QTKit can scale captured frame to any size requested, which would lead to
-  // undesired aspect ratio change. Tries to open the camera with a natively
-  // supported format and let the client to crop/pad the captured frames.
-  GetBestMatchSupportedResolution(&width,
-                                  &height);
+  // The OS API can scale captured frame to any size requested, which would lead
+  // to undesired aspect ratio change. Try to open the camera with a natively
+  // supported format and let the client crop/pad the captured frames.
+  GetBestMatchSupportedResolution(&width, &height);
 
   client_ = client.Pass();
   NSString* deviceId =
@@ -154,8 +152,6 @@
   current_settings_.width = width;
   current_settings_.height = height;
   current_settings_.frame_rate = frame_rate;
-  current_settings_.expected_capture_delay = 0;
-  current_settings_.interlaced = false;
 
   if (width != kHD.width || height != kHD.height) {
     // If the resolution is VGA or QVGA, set the capture resolution to the
diff --git a/media/video/capture/mac/video_capture_device_qtkit_mac.h b/media/video/capture/mac/video_capture_device_qtkit_mac.h
index d032ef0..f3bdcc5 100644
--- a/media/video/capture/mac/video_capture_device_qtkit_mac.h
+++ b/media/video/capture/mac/video_capture_device_qtkit_mac.h
@@ -12,6 +12,8 @@
 
 #include <vector>
 
+#import "media/video/capture/mac/platform_video_capturing_mac.h"
+
 namespace media {
   class VideoCaptureDeviceMac;
 }
@@ -19,7 +21,7 @@
 @class QTCaptureDeviceInput;
 @class QTCaptureSession;
 
-@interface VideoCaptureDeviceQTKit : NSObject {
+@interface VideoCaptureDeviceQTKit : NSObject<PlatformVideoCapturingMac> {
  @private
   // Settings.
   int frameRate_;
diff --git a/media/video/capture/mac/video_capture_device_qtkit_mac.mm b/media/video/capture/mac/video_capture_device_qtkit_mac.mm
index 2b7e28e..e625d13 100644
--- a/media/video/capture/mac/video_capture_device_qtkit_mac.mm
+++ b/media/video/capture/mac/video_capture_device_qtkit_mac.mm
@@ -280,8 +280,6 @@
     captureCapability.height = frameHeight;
     captureCapability.frame_rate = frameRate_;
     captureCapability.color = media::PIXEL_FORMAT_UYVY;
-    captureCapability.expected_capture_delay = 0;
-    captureCapability.interlaced = false;
 
     // The aspect ratio dictionary is often missing, in which case we report
     // a pixel aspect ratio of 0:0.
diff --git a/media/video/capture/video_capture.h b/media/video/capture/video_capture.h
index 3a4eb0e..9a0e943 100644
--- a/media/video/capture/video_capture.h
+++ b/media/video/capture/video_capture.h
@@ -45,35 +45,23 @@
         VideoCapture* capture,
         const scoped_refptr<media::VideoFrame>& frame) = 0;
 
-    // Notify client about device info.
-    virtual void OnDeviceInfoReceived(
-        VideoCapture* capture,
-        const VideoCaptureParams& device_info) = 0;
-
-    // Notify client about the newly changed device info.
-    virtual void OnDeviceInfoChanged(
-        VideoCapture* capture,
-        const VideoCaptureParams& device_info) {};
-
    protected:
     virtual ~EventHandler() {}
   };
 
   VideoCapture() {}
 
-  // Request video capture to start capturing with |capability|.
+  // Request video capture to start capturing with |params|.
   // Also register |handler| with video capture for event handling.
   // |handler| must remain valid until it has received |OnRemoved()|.
   virtual void StartCapture(EventHandler* handler,
-                            const VideoCaptureCapability& capability) = 0;
+                            const VideoCaptureParams& params) = 0;
 
   // Request video capture to stop capturing for client |handler|.
   // |handler| must remain valid until it has received |OnRemoved()|.
   virtual void StopCapture(EventHandler* handler) = 0;
 
   virtual bool CaptureStarted() = 0;
-  virtual int CaptureWidth() = 0;
-  virtual int CaptureHeight() = 0;
   virtual int CaptureFrameRate() = 0;
 
  protected:
diff --git a/media/video/capture/video_capture_device.h b/media/video/capture/video_capture_device.h
index c10a3ae..2e60256 100644
--- a/media/video/capture/video_capture_device.h
+++ b/media/video/capture/video_capture_device.h
@@ -125,16 +125,17 @@
     // Reserve an output buffer into which a video frame can be captured
     // directly. If all buffers are currently busy, returns NULL.
     //
-    // The returned VideoFrames will always be allocated with a YV12 format. The
-    // size will match that specified by an earlier call to OnFrameInfo. It is
-    // the VideoCaptureDevice's responsibility to obey whatever stride and
-    // memory layout are indicated on the returned VideoFrame object.
+    // The returned VideoFrames will always be allocated with a YV12 format and
+    // have dimensions matching |size|. It is the VideoCaptureDevice's
+    // responsibility to obey whatever stride and memory layout are indicated on
+    // the returned VideoFrame object.
     //
     // The output buffer stays reserved for use by the calling
     // VideoCaptureDevice until either the last reference to the VideoFrame is
     // released, or until the buffer is passed back to the Client's
     // OnIncomingCapturedFrame() method.
-    virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() = 0;
+    virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer(
+        const gfx::Size& size) = 0;
 
     // Captured a new video frame as a raw buffer. The size, color format, and
     // layout are taken from the parameters specified by an earlier call to
diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc
index 517e7b2..f9d0ab2 100644
--- a/media/video/capture/video_capture_device_unittest.cc
+++ b/media/video/capture/video_capture_device_unittest.cc
@@ -64,7 +64,8 @@
 
 class MockClient : public media::VideoCaptureDevice::Client {
  public:
-  MOCK_METHOD0(ReserveOutputBuffer, scoped_refptr<media::VideoFrame>());
+  MOCK_METHOD1(ReserveOutputBuffer,
+      scoped_refptr<media::VideoFrame>(const gfx::Size&));
   MOCK_METHOD0(OnErr, void());
   MOCK_METHOD1(OnFrameInfo, void(const VideoCaptureCapability&));
   MOCK_METHOD1(OnFrameInfoChanged, void(const VideoCaptureCapability&));
@@ -161,8 +162,6 @@
                                         480,
                                         30,
                                         PIXEL_FORMAT_I420,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format,
                            client_.PassAs<Client>());
@@ -197,8 +196,6 @@
                                         720,
                                         30,
                                         PIXEL_FORMAT_I420,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format,
                            client_.PassAs<Client>());
@@ -229,8 +226,6 @@
                                         472,
                                         35,
                                         PIXEL_FORMAT_I420,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format,
                            client_.PassAs<Client>());
@@ -263,8 +258,6 @@
         resolution.height(),
         30,
         PIXEL_FORMAT_I420,
-        0,
-        false,
         ConstantResolutionVideoCaptureDevice);
 
     // The device (if it is an async implementation) may or may not get as far
@@ -283,8 +276,6 @@
       240,
       30,
       PIXEL_FORMAT_I420,
-      0,
-      false,
       ConstantResolutionVideoCaptureDevice);
 
   base::RunLoop run_loop;
@@ -329,8 +320,6 @@
                                         480,
                                         30,
                                         PIXEL_FORMAT_I420,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format, client_.PassAs<Client>());
   // Get captured video frames.
@@ -364,8 +353,6 @@
                                         480,
                                         30,
                                         PIXEL_FORMAT_I420,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format,
                            client_.PassAs<Client>());
@@ -399,8 +386,6 @@
                                         720,
                                         30,
                                         PIXEL_FORMAT_MJPEG,
-                                        0,
-                                        false,
                                         ConstantResolutionVideoCaptureDevice);
   device->AllocateAndStart(capture_format, client_.PassAs<Client>());
   // Get captured video frames.
diff --git a/media/video/capture/video_capture_proxy.cc b/media/video/capture/video_capture_proxy.cc
index 3adbb7c..bbbd610 100644
--- a/media/video/capture/video_capture_proxy.cc
+++ b/media/video/capture/video_capture_proxy.cc
@@ -16,8 +16,6 @@
     media::VideoCapture* capture) {
   media::VideoCaptureHandlerProxy::VideoCaptureState state;
   state.started = capture->CaptureStarted();
-  state.width = capture->CaptureWidth();
-  state.height = capture->CaptureHeight();
   state.frame_rate = capture->CaptureFrameRate();
   return state;
 }
@@ -89,17 +87,6 @@
                  frame));
 }
 
-void VideoCaptureHandlerProxy::OnDeviceInfoReceived(
-    VideoCapture* capture,
-    const VideoCaptureParams& device_info) {
-  main_message_loop_->PostTask(FROM_HERE, base::Bind(
-      &VideoCaptureHandlerProxy::OnDeviceInfoReceivedOnMainThread,
-      base::Unretained(this),
-      capture,
-      GetState(capture),
-      device_info));
-}
-
 void VideoCaptureHandlerProxy::OnStartedOnMainThread(
     VideoCapture* capture,
     const VideoCaptureState& state) {
@@ -144,12 +131,4 @@
   proxied_->OnFrameReady(capture, frame);
 }
 
-void VideoCaptureHandlerProxy::OnDeviceInfoReceivedOnMainThread(
-    VideoCapture* capture,
-    const VideoCaptureState& state,
-    const VideoCaptureParams& device_info) {
-  state_ = state;
-  proxied_->OnDeviceInfoReceived(capture, device_info);
-}
-
 }  // namespace media
diff --git a/media/video/capture/video_capture_proxy.h b/media/video/capture/video_capture_proxy.h
index fbb7577..fca0a80 100644
--- a/media/video/capture/video_capture_proxy.h
+++ b/media/video/capture/video_capture_proxy.h
@@ -28,10 +28,8 @@
     : public VideoCapture::EventHandler {
  public:
   struct VideoCaptureState {
-    VideoCaptureState() : started(false), width(0), height(0), frame_rate(0) {}
+    VideoCaptureState() : started(false), frame_rate(0) {}
     bool started;
-    int width;
-    int height;
     int frame_rate;
   };
 
@@ -52,9 +50,6 @@
   virtual void OnRemoved(VideoCapture* capture) OVERRIDE;
   virtual void OnFrameReady(VideoCapture* capture,
                             const scoped_refptr<VideoFrame>& frame) OVERRIDE;
-  virtual void OnDeviceInfoReceived(
-      VideoCapture* capture,
-      const VideoCaptureParams& device_info) OVERRIDE;
 
  private:
   // Called on main thread.
@@ -77,9 +72,6 @@
   void OnFrameReadyOnMainThread(VideoCapture* capture,
                                 const VideoCaptureState& state,
                                 const scoped_refptr<VideoFrame>& frame);
-  void OnDeviceInfoReceivedOnMainThread(VideoCapture* capture,
-                                        const VideoCaptureState& state,
-                                        const VideoCaptureParams& device_info);
 
   // Only accessed from main thread.
   VideoCapture::EventHandler* proxied_;
diff --git a/media/video/capture/video_capture_types.cc b/media/video/capture/video_capture_types.cc
index 5b8e226..48f03f1 100644
--- a/media/video/capture/video_capture_types.cc
+++ b/media/video/capture/video_capture_types.cc
@@ -38,23 +38,15 @@
     : session_id(0) {}
 
 VideoCaptureCapability::VideoCaptureCapability()
-    : color(PIXEL_FORMAT_UNKNOWN),
-      expected_capture_delay(0),
-      interlaced(false),
-      session_id(0) {}
+    : color(PIXEL_FORMAT_UNKNOWN) {}
 
 VideoCaptureCapability::VideoCaptureCapability(
     int width,
     int height,
     int frame_rate,
     VideoPixelFormat color,
-    int delay,
-    bool interlaced,
     VideoCaptureResolutionType frame_size_type)
     : VideoCaptureFormat(width, height, frame_rate, frame_size_type),
-      color(color),
-      expected_capture_delay(delay),
-      interlaced(interlaced),
-      session_id(0) {}
+      color(color) {}
 
 }  // namespace media
diff --git a/media/video/capture/video_capture_types.h b/media/video/capture/video_capture_types.h
index 003dc4e..489befe 100644
--- a/media/video/capture/video_capture_types.h
+++ b/media/video/capture/video_capture_types.h
@@ -51,15 +51,18 @@
   VideoCaptureResolutionType frame_size_type;
 };
 
-// Parameters for starting video capture and device information.
-class MEDIA_EXPORT VideoCaptureParams : public VideoCaptureFormat {
+// Parameters for starting video capture.
+class MEDIA_EXPORT VideoCaptureParams {
  public:
   VideoCaptureParams();
-  // TODO(mcasas): http://crbug.com/297597, investigate if session_id is in use.
+  // Identifies which device is to be started.
   VideoCaptureSessionId session_id;
+
+  // Requests a resolution and format at which the capture will occur.
+  VideoCaptureFormat requested_format;
 };
 
-// Capabilities describe the format a camera capture video in.
+// Capabilities describe the format a camera captures video in.
 class MEDIA_EXPORT VideoCaptureCapability : public VideoCaptureFormat {
  public:
   VideoCaptureCapability();
@@ -67,16 +70,9 @@
                          int height,
                          int frame_rate,
                          VideoPixelFormat color,
-                         int delay,
-                         bool interlaced,
                          VideoCaptureResolutionType frame_size_type);
 
   VideoPixelFormat color;      // Desired video type.
-  // TODO(mcasas): http://crbug.com/297597, investigate if the following three
-  // attributes are in use at all.
-  int expected_capture_delay;  // Expected delay in millisecond.
-  bool interlaced;             // Need interlace format.
-  VideoCaptureSessionId session_id;
 };
 
 typedef std::vector<VideoCaptureCapability> VideoCaptureCapabilities;
diff --git a/media/video/capture/win/sink_input_pin_win.cc b/media/video/capture/win/sink_input_pin_win.cc
index 1de1ea1..9d97918 100644
--- a/media/video/capture/win/sink_input_pin_win.cc
+++ b/media/video/capture/win/sink_input_pin_win.cc
@@ -147,8 +147,6 @@
   resulting_capability_.height = 0;
   resulting_capability_.frame_rate = 0;
   resulting_capability_.color = PIXEL_FORMAT_UNKNOWN;
-  resulting_capability_.expected_capture_delay = 0;
-  resulting_capability_.interlaced = false;
 }
 
 const VideoCaptureCapability& SinkInputPin::ResultingCapability() {
diff --git a/media/video/capture/win/video_capture_device_mf_win.cc b/media/video/capture/win/video_capture_device_mf_win.cc
index 2e9277a..8ffaab8 100644
--- a/media/video/capture/win/video_capture_device_mf_win.cc
+++ b/media/video/capture/win/video_capture_device_mf_win.cc
@@ -132,9 +132,6 @@
   capability->frame_rate =
       capability->frame_rate_numerator / capability->frame_rate_denominator;
 
-  capability->expected_capture_delay = 0;  // Currently not used.
-  capability->interlaced = false;          // Currently not used.
-
   return true;
 }
 
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index 1aa0954..5212db2 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -90,9 +90,9 @@
   // Returns true when command successfully accepted. Otherwise false.
   virtual bool Initialize(VideoCodecProfile profile) = 0;
 
-  // Decodes given bitstream buffer. Once decoder is done with processing
-  // |bitstream_buffer| it will call NotifyEndOfBitstreamBuffer() with the
-  // bitstream buffer id.
+  // Decodes given bitstream buffer that contains at most one frame. Once
+  // decoder is done with processing |bitstream_buffer| it will call
+  // NotifyEndOfBitstreamBuffer() with the bitstream buffer id.
   // Parameters:
   //  |bitstream_buffer| is the input bitstream that is sent for decoding.
   virtual void Decode(const BitstreamBuffer& bitstream_buffer) = 0;
diff --git a/media/video_capture_android_jni_headers.target.darwin-arm.mk b/media/video_capture_android_jni_headers.target.darwin-arm.mk
index 900bea9..acefbed 100644
--- a/media/video_capture_android_jni_headers.target.darwin-arm.mk
+++ b/media/video_capture_android_jni_headers.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/video_capture_android_jni_headers.target.darwin-mips.mk b/media/video_capture_android_jni_headers.target.darwin-mips.mk
index 6250428..3ed7400 100644
--- a/media/video_capture_android_jni_headers.target.darwin-mips.mk
+++ b/media/video_capture_android_jni_headers.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/video_capture_android_jni_headers.target.darwin-x86.mk b/media/video_capture_android_jni_headers.target.darwin-x86.mk
index cd88c11..5789520 100644
--- a/media/video_capture_android_jni_headers.target.darwin-x86.mk
+++ b/media/video_capture_android_jni_headers.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/video_capture_android_jni_headers.target.linux-arm.mk b/media/video_capture_android_jni_headers.target.linux-arm.mk
index 900bea9..acefbed 100644
--- a/media/video_capture_android_jni_headers.target.linux-arm.mk
+++ b/media/video_capture_android_jni_headers.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/video_capture_android_jni_headers.target.linux-mips.mk b/media/video_capture_android_jni_headers.target.linux-mips.mk
index 6250428..3ed7400 100644
--- a/media/video_capture_android_jni_headers.target.linux-mips.mk
+++ b/media/video_capture_android_jni_headers.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/media/video_capture_android_jni_headers.target.linux-x86.mk b/media/video_capture_android_jni_headers.target.linux-x86.mk
index cd88c11..5789520 100644
--- a/media/video_capture_android_jni_headers.target.linux-x86.mk
+++ b/media/video_capture_android_jni_headers.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/mojo/examples/sample_app/sample_app.cc b/mojo/examples/sample_app/sample_app.cc
new file mode 100644
index 0000000..820bdd4
--- /dev/null
+++ b/mojo/examples/sample_app/sample_app.cc
@@ -0,0 +1,73 @@
+// Copyright 2013 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 <stdio.h>
+
+#include "base/basictypes.h"
+#include "mojo/public/system/core.h"
+#include "mojo/system/core_impl.h"
+
+#if defined(OS_WIN)
+#if !defined(CDECL)
+#define CDECL __cdecl
+#endif
+#define SAMPLE_APP_EXPORT __declspec(dllexport)
+#else
+#define CDECL
+#define SAMPLE_APP_EXPORT __attribute__((visibility("default")))
+#endif
+
+char* ReadStringFromPipe(mojo::Handle pipe) {
+  uint32_t len = 0;
+  char* buf = NULL;
+  MojoResult result = mojo::ReadMessage(pipe, buf, &len, NULL, NULL,
+                                        MOJO_READ_MESSAGE_FLAG_NONE);
+  if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
+    buf = new char[len];
+    result = mojo::ReadMessage(pipe, buf, &len, NULL, NULL,
+                               MOJO_READ_MESSAGE_FLAG_NONE);
+  }
+  if (result < MOJO_RESULT_OK) {
+    // Failure..
+    if (buf)
+      delete[] buf;
+    return NULL;
+  }
+  return buf;
+}
+
+class SampleMessageWaiter {
+ public:
+  explicit SampleMessageWaiter(mojo::Handle pipe) : pipe_(pipe) {}
+  ~SampleMessageWaiter() {}
+
+  void Read() {
+    char* string = ReadStringFromPipe(pipe_);
+    if (string) {
+      printf("Read string from pipe: %s\n", string);
+      delete[] string;
+      string = NULL;
+    }
+  }
+
+  void WaitAndRead() {
+    MojoResult result = mojo::Wait(pipe_, MOJO_WAIT_FLAG_READABLE, 100);
+    if (result < MOJO_RESULT_OK) {
+      // Failure...
+    }
+
+    Read();
+  }
+
+ private:
+
+  mojo::Handle pipe_;
+  DISALLOW_COPY_AND_ASSIGN(SampleMessageWaiter);
+};
+
+extern "C" SAMPLE_APP_EXPORT MojoResult CDECL MojoMain(
+    mojo::Handle pipe) {
+  SampleMessageWaiter(pipe).WaitAndRead();
+  return MOJO_RESULT_OK;
+}
diff --git a/mojo/loader/DEPS b/mojo/loader/DEPS
deleted file mode 100644
index d97699d..0000000
--- a/mojo/loader/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+net",
-  "+url",
-]
diff --git a/mojo/loader/job.cc b/mojo/loader/job.cc
deleted file mode 100644
index a89030e..0000000
--- a/mojo/loader/job.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2013 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/loader/job.h"
-
-namespace mojo {
-namespace loader {
-
-Job::Delegate::~Delegate() {
-}
-
-Job::Job() {
-}
-
-Job::~Job() {
-}
-
-}  // namespace loader
-}  // namespace mojo
diff --git a/mojo/loader/job.h b/mojo/loader/job.h
deleted file mode 100644
index 2454368..0000000
--- a/mojo/loader/job.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2013 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_LOADER_JOB_H_
-#define MOJO_LOADER_JOB_H_
-
-#include "url/gurl.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace mojo {
-namespace loader {
-
-// A job represents an individual network load operation.
-class Job {
- public:
-  class Delegate {
-   public:
-    virtual void DidCompleteLoad(const GURL& app_url,
-                                 const base::FilePath& app_path) = 0;
-
-   protected:
-    virtual ~Delegate();
-  };
-
-  // You can cancel a job by deleting it.
-  virtual ~Job();
-
- protected:
-  // You can create a job using Loader.
-  Job();
-
-  DISALLOW_COPY_AND_ASSIGN(Job);
-};
-
-}  // namespace loader
-}  // namespace mojo
-
-#endif  // MOJO_LOADER_JOB_H_
diff --git a/mojo/loader/loader.cc b/mojo/loader/loader.cc
deleted file mode 100644
index 7faab92..0000000
--- a/mojo/loader/loader.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2013 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/loader/loader.h"
-
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread.h"
-#include "mojo/loader/url_request_context_getter.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-
-namespace mojo {
-namespace loader {
-
-namespace {
-
-class JobImpl : public net::URLFetcherDelegate, public Job {
- public:
-  JobImpl(const GURL& app_url, Job::Delegate* delegate);
-  virtual ~JobImpl();
-
-  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
-  net::URLFetcher* fetcher() const { return fetcher_.get(); }
-
- private:
-  scoped_ptr<net::URLFetcher> fetcher_;
-  Job::Delegate* delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(JobImpl);
-};
-
-JobImpl::JobImpl(const GURL& app_url, Job::Delegate* delegate)
-    : delegate_(delegate) {
-  fetcher_.reset(net::URLFetcher::Create(app_url, net::URLFetcher::GET, this));
-}
-
-JobImpl::~JobImpl() {
-}
-
-void JobImpl::OnURLFetchComplete(const net::URLFetcher* source) {
-  base::FilePath app_path;
-  source->GetResponseAsFilePath(true, &app_path);
-  delegate_->DidCompleteLoad(source->GetURL(), app_path);
-}
-
-scoped_ptr<base::Thread> CreateIOThread(const char* name) {
-  scoped_ptr<base::Thread> thread(new base::Thread(name));
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  thread->StartWithOptions(options);
-  return thread.Pass();
-}
-
-}  // namespace
-
-class Loader::Data {
- public:
-  scoped_refptr<base::SingleThreadTaskRunner> file_runner;
-  scoped_ptr<base::Thread> cache_thread;
-  scoped_refptr<URLRequestContextGetter> url_request_context_getter;
-};
-
-Loader::Loader(base::SingleThreadTaskRunner* network_runner,
-               base::SingleThreadTaskRunner* file_runner,
-               base::FilePath base_path)
-    : data_(new Data()) {
-  data_->file_runner = file_runner;
-  data_->cache_thread = CreateIOThread("cache_thread");
-  data_->url_request_context_getter = new URLRequestContextGetter(
-      base_path, network_runner, data_->cache_thread->message_loop_proxy());
-}
-
-Loader::~Loader() {
-}
-
-scoped_ptr<Job> Loader::Load(const GURL& app_url, Job::Delegate* delegate) {
-  JobImpl* job = new JobImpl(app_url, delegate);
-  job->fetcher()->SetRequestContext(data_->url_request_context_getter.get());
-  job->fetcher()->SaveResponseToTemporaryFile(data_->file_runner.get());
-  job->fetcher()->Start();
-  return make_scoped_ptr(static_cast<Job*>(job));
-}
-
-}  // namespace loader
-}  // namespace mojo
diff --git a/mojo/loader/loader.h b/mojo/loader/loader.h
deleted file mode 100644
index 90581e1..0000000
--- a/mojo/loader/loader.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2013 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_LOADER_LOADER_H_
-#define MOJO_LOADER_LOADER_H_
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "mojo/loader/job.h"
-#include "url/gurl.h"
-
-namespace mojo {
-namespace loader {
-
-class Loader {
- public:
-  Loader(base::SingleThreadTaskRunner* network_runner,
-         base::SingleThreadTaskRunner* file_runner,
-         base::FilePath base_path);
-  ~Loader();
-
-  scoped_ptr<Job> Load(const GURL& app_url, Job::Delegate* delegate);
-
- private:
-  class Data;
-
-  scoped_ptr<Data> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(Loader);
-};
-
-}  // namespace loader
-}  // namespace mojo
-
-#endif  // MOJO_LOADER_LOADER_H_
diff --git a/mojo/loader/url_request_context_getter.cc b/mojo/loader/url_request_context_getter.cc
deleted file mode 100644
index 992b36f..0000000
--- a/mojo/loader/url_request_context_getter.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013 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/loader/url_request_context_getter.h"
-
-#include "net/cookies/cookie_monster.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/proxy/proxy_service.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-#include "net/url_request/static_http_user_agent_settings.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job_factory_impl.h"
-
-namespace mojo {
-namespace loader {
-
-URLRequestContextGetter::URLRequestContextGetter(
-    base::FilePath base_path,
-    base::SingleThreadTaskRunner* network_task_runner,
-    base::MessageLoopProxy* cache_task_runner)
-    : base_path_(base_path),
-      network_task_runner_(network_task_runner),
-      cache_task_runner_(cache_task_runner),
-      net_log_(new net::NetLog()) {
-}
-
-URLRequestContextGetter::~URLRequestContextGetter() {
-}
-
-net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
-  if (!url_request_context_) {
-    url_request_context_.reset(new net::URLRequestContext());
-    url_request_context_->set_net_log(net_log_.get());
-
-    storage_.reset(
-        new net::URLRequestContextStorage(url_request_context_.get()));
-
-    storage_->set_cookie_store(new net::CookieMonster(NULL, NULL));
-    storage_->set_http_user_agent_settings(
-        new net::StaticHttpUserAgentSettings("en-us,en", "Mojo/0.1"));
-
-    storage_->set_proxy_service(net::ProxyService::CreateDirect());
-    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
-    storage_->set_http_server_properties(
-        scoped_ptr<net::HttpServerProperties>(
-            new net::HttpServerPropertiesImpl()));
-    storage_->set_host_resolver(net::HostResolver::CreateDefaultResolver(
-        url_request_context_->net_log()));
-
-    net::HttpNetworkSession::Params network_session_params;
-    network_session_params.net_log =
-        url_request_context_->net_log();
-    network_session_params.proxy_service =
-        url_request_context_->proxy_service();
-    network_session_params.ssl_config_service =
-        url_request_context_->ssl_config_service();
-    network_session_params.http_server_properties =
-        url_request_context_->http_server_properties();
-    network_session_params.host_resolver =
-        url_request_context_->host_resolver();
-
-    base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
-
-    net::HttpCache::DefaultBackend* main_backend =
-        new net::HttpCache::DefaultBackend(
-            net::DISK_CACHE,
-            net::CACHE_BACKEND_DEFAULT,
-            cache_path,
-            0,
-            cache_task_runner_.get());
-
-    net::HttpCache* main_cache = new net::HttpCache(
-        network_session_params, main_backend);
-    storage_->set_http_transaction_factory(main_cache);
-
-    scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
-        new net::URLRequestJobFactoryImpl());
-
-    storage_->set_job_factory(job_factory.release());
-  }
-
-  return url_request_context_.get();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-URLRequestContextGetter::GetNetworkTaskRunner() const {
-  return network_task_runner_;
-}
-
-}  // namespace loader
-}  // namespace mojo
diff --git a/mojo/loader/url_request_context_getter.h b/mojo/loader/url_request_context_getter.h
deleted file mode 100644
index 146420f..0000000
--- a/mojo/loader/url_request_context_getter.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2013 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_URL_REQUEST_CONTEXT_GETTER_H_
-#define MOJO_URL_REQUEST_CONTEXT_GETTER_H_
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_context_storage.h"
-
-namespace mojo {
-namespace loader {
-
-class URLRequestContextGetter : public net::URLRequestContextGetter {
- public:
-  URLRequestContextGetter(
-      base::FilePath base_path,
-      base::SingleThreadTaskRunner* network_task_runner,
-      base::MessageLoopProxy* cache_task_runner);
-
-  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
-  virtual scoped_refptr<base::SingleThreadTaskRunner>
-      GetNetworkTaskRunner() const OVERRIDE;
-
- protected:
-  virtual ~URLRequestContextGetter();
-
- private:
-  base::FilePath base_path_;
-  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
-  scoped_refptr<base::MessageLoopProxy> cache_task_runner_;
-  scoped_ptr<net::NetLog> net_log_;
-  scoped_ptr<net::URLRequestContextStorage> storage_;
-  scoped_ptr<net::URLRequestContext> url_request_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
-};
-
-}  // namespace loader
-}  // namespace mojo
-
-#endif  // MOJO_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index 9262cff..d363175 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -123,6 +123,7 @@
         'system/message_pipe_unittest.cc',
         'system/raw_channel_posix_unittest.cc',
         'system/simple_dispatcher_unittest.cc',
+        'system/test_utils.cc',
         'system/test_utils.h',
         'system/waiter_list_unittest.cc',
         'system/waiter_test_utils.cc',
@@ -131,8 +132,8 @@
       ],
     },
     {
-      'target_name': 'mojo_shell',
-      'type': 'executable',
+      'target_name': 'mojo_shell_lib',
+      'type': 'static_library',
       'dependencies': [
         '../base/base.gyp:base',
         '../net/net.gyp:net',
@@ -140,21 +141,45 @@
         'mojo_system',
       ],
       'sources': [
-        'loader/job.cc',
-        'loader/job.h',
-        'loader/loader.cc',
-        'loader/loader.h',
-        'loader/url_request_context_getter.cc',
-        'loader/url_request_context_getter.h',
         'shell/app_container.cc',
         'shell/app_container.h',
-        'shell/shell.cc',
+        'shell/context.cc',
+        'shell/context.h',
+        'shell/loader.cc',
+        'shell/loader.h',
+        'shell/network_delegate.cc',
+        'shell/network_delegate.h',
+        'shell/run.cc',
+        'shell/run.h',
         'shell/storage.cc',
         'shell/storage.h',
         'shell/switches.cc',
         'shell/switches.h',
         'shell/task_runners.cc',
         'shell/task_runners.h',
+        'shell/url_request_context_getter.cc',
+        'shell/url_request_context_getter.h',
+      ],
+      'conditions': [
+        ['OS == "win"', {
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [
+            4267,
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'mojo_shell',
+      'type': 'executable',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../url/url.gyp:url_lib',
+        'mojo_shell_lib',
+        'mojo_system',
+      ],
+      'sources': [
+        'shell/desktop/mojo_main.cc',
       ],
       'conditions': [
         ['OS == "win"', {
@@ -167,13 +192,13 @@
     },
     {
       'target_name': 'sample_app',
-      'type': '<(component)',
+      'type': 'shared_library',
       'dependencies': [
         '../base/base.gyp:base',
         'mojo_system',
       ],
       'sources': [
-        'shell/sample_app.cc',
+        'examples/sample_app/sample_app.cc',
       ],
     },
     {
@@ -205,12 +230,91 @@
         'mojo_bindings',
       ],
       'sources': [
+        'public/bindings/sample/generated/sample_bar.cc',
+        'public/bindings/sample/generated/sample_bar.h',
+        'public/bindings/sample/generated/sample_bar_serialization.cc',
+        'public/bindings/sample/generated/sample_bar_serialization.h',
+        'public/bindings/sample/generated/sample_foo.cc',
+        'public/bindings/sample/generated/sample_foo.h',
+        'public/bindings/sample/generated/sample_foo_serialization.cc',
+        'public/bindings/sample/generated/sample_foo_serialization.h',
         'public/bindings/sample/generated/sample_service.h',
         'public/bindings/sample/generated/sample_service_proxy.cc',
+        'public/bindings/sample/generated/sample_service_serialization.cc',
         'public/bindings/sample/generated/sample_service_serialization.h',
         'public/bindings/sample/generated/sample_service_stub.cc',
         'public/bindings/sample/sample_test.cc',
       ],
     },
   ],
+  'conditions': [
+    ['OS=="android"', {
+      'targets': [
+        {
+          'target_name': 'java_set_jni_headers',
+          'type': 'none',
+          'variables': {
+            'jni_gen_package': 'mojo',
+            'input_java_class': 'java/util/HashSet.class',
+          },
+          'includes': [ '../build/jar_file_jni_generator.gypi' ],
+        },
+        {
+          'target_name': 'mojo_jni_headers',
+          'type': 'none',
+          'dependencies': [
+            'java_set_jni_headers',
+          ],
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '<(SHARED_INTERMEDIATE_DIR)/mojo',
+            ],
+          },
+          'sources': [
+            'shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java',
+            'shell/android/apk/src/org/chromium/mojo_shell_apk/MojoView.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'mojo'
+          },
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          'target_name': 'libmojo_shell',
+          'type': 'shared_library',
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+            '../ui/gfx/gfx.gyp:gfx',
+            '../ui/gl/gl.gyp:gl',
+            'mojo_jni_headers',
+            'mojo_shell_lib',
+          ],
+          'sources': [
+            'shell/android/library_loader.cc',
+            'shell/android/mojo_main.cc',
+            'shell/android/mojo_main.h',
+            'shell/android/mojo_view.cc',
+            'shell/android/mojo_view.h',
+          ],
+        },
+        {
+          'target_name': 'mojo_shell_apk',
+          'type': 'none',
+          'dependencies': [
+            '../base/base.gyp:base_java',
+            '../net/net.gyp:net_java',
+            'libmojo_shell',
+          ],
+          'variables': {
+            'apk_name': 'MojoShell',
+            'java_in_dir': '<(DEPTH)/mojo/shell/android/apk',
+            'resource_dir': '<(DEPTH)/mojo/shell/android/apk/res',
+            'native_lib_target': 'libmojo_shell',
+          },
+          'includes': [ '../build/java_apk.gypi' ],
+        }
+      ],
+    }],
+  ],
 }
diff --git a/mojo/public/DEPS b/mojo/public/DEPS
new file mode 100644
index 0000000..0aaea41
--- /dev/null
+++ b/mojo/public/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+  "-base",
+  "-build",
+  "-mojo",
+  "-testing",
+
+  "+mojo/public",
+]
diff --git a/mojo/public/bindings/generators/__init__.py b/mojo/public/bindings/generators/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/bindings/generators/__init__.py
diff --git a/mojo/public/bindings/generators/module_interface.h b/mojo/public/bindings/generators/module_interface.h
new file mode 100644
index 0000000..d7c19db
--- /dev/null
+++ b/mojo/public/bindings/generators/module_interface.h
@@ -0,0 +1,19 @@
+// Copyright $YEAR 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 $HEADER_GUARD
+#define $HEADER_GUARD
+
+#include "mojo/public/bindings/lib/bindings.h"
+
+namespace $NAMESPACE {
+$FORWARDS
+class $CLASS {
+ public:
+$METHODS
+};
+
+}  // namespace $NAMESPACE
+
+#endif  // $HEADER_GUARD
diff --git a/mojo/public/bindings/generators/module_struct.cc b/mojo/public/bindings/generators/module_struct.cc
new file mode 100644
index 0000000..04b1630
--- /dev/null
+++ b/mojo/public/bindings/generators/module_struct.cc
@@ -0,0 +1,19 @@
+// Copyright $YEAR 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 "$HEADER"
+
+namespace $NAMESPACE {
+
+// static
+$CLASS* $CLASS::New(mojo::Buffer* buf) {
+  return new (buf->Allocate(sizeof($CLASS))) $CLASS();
+}
+
+$CLASS::$CLASS() {
+  _header_.num_bytes = sizeof(*this);
+  _header_.num_fields = $NUM_FIELDS;
+}
+
+}  // namespace $NAMESPACE
diff --git a/mojo/public/bindings/generators/module_struct.h b/mojo/public/bindings/generators/module_struct.h
new file mode 100644
index 0000000..8768781
--- /dev/null
+++ b/mojo/public/bindings/generators/module_struct.h
@@ -0,0 +1,38 @@
+// Copyright $YEAR 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 $HEADER_GUARD
+#define $HEADER_GUARD
+
+#include "mojo/public/bindings/lib/bindings.h"
+
+namespace $NAMESPACE {
+$FORWARDS
+#pragma pack(push, 1)
+
+class $CLASS {
+ public:
+  static $CLASS* New(mojo::Buffer* buf);
+
+$SETTERS
+
+$GETTERS
+
+ private:
+  friend class mojo::internal::ObjectTraits<$CLASS>;
+
+  $CLASS();
+  ~$CLASS();  // NOT IMPLEMENTED
+
+  mojo::internal::StructHeader _header_;
+$FIELDS
+};
+
+MOJO_COMPILE_ASSERT(sizeof($CLASS) == $SIZE, bad_sizeof_$CLASS);
+
+#pragma pack(pop)
+
+}  // namespace $NAMESPACE
+
+#endif  // $HEADER_GUARD
diff --git a/mojo/public/bindings/generators/mojom.py b/mojo/public/bindings/generators/mojom.py
index b12ec31..4f789b7 100644
--- a/mojo/public/bindings/generators/mojom.py
+++ b/mojo/public/bindings/generators/mojom.py
@@ -29,10 +29,11 @@
 FLOAT  = Kind('f')
 DOUBLE = Kind('d')
 STRING = Kind('s')
+HANDLE = Kind('h')
 
 
 # Collection of all Primitive types
-PRIMITIVES = [
+PRIMITIVES = (
   BOOL,
   INT8,
   INT16,
@@ -45,8 +46,8 @@
   FLOAT,
   DOUBLE,
   STRING,
-  // TODO(davemoore): Add HANDLE.
-]
+  HANDLE
+)
 
 
 class Field(object):
diff --git a/mojo/public/bindings/generators/mojom_cpp_generator.py b/mojo/public/bindings/generators/mojom_cpp_generator.py
new file mode 100644
index 0000000..713400e
--- /dev/null
+++ b/mojo/public/bindings/generators/mojom_cpp_generator.py
@@ -0,0 +1,233 @@
+# Copyright (c) 2013 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.
+
+"""Generates C++ source files from a mojom.Module."""
+
+import datetime
+import mojom
+import mojom_pack
+import os
+import sys
+
+from string import Template
+
+# mojom_cpp_generator provides a way to generate c++ code from a mojom.Module.
+# cpp = mojom_cpp_generator.CPPGenerator(module)
+# cpp.GenerateFiles("/tmp/g")
+def ReadTemplate(filename):
+  """Reads a string.Template from |filename|."""
+  dir = os.path.dirname(__file__)
+  with open(dir + '/' + filename, 'r') as file:
+    return Template(file.read())
+
+
+def AddForward(forwards, kind):
+  """Adds a forward class declaration line to the |forwards| set."""
+  if isinstance(kind, mojom.Struct):
+    forwards.add("class %s;" % kind.name.capitalize())
+  if isinstance(kind, mojom.Array):
+    AddForward(forwards, kind.kind)
+
+
+def GetForwards(forwards):
+  """Returns a string suitable for substituting into a $FORWARDS section."""
+  if len(forwards) > 0:
+    return '\n'.join(sorted(forwards)) + '\n'
+  return ""
+
+
+class CPPGenerator(object):
+
+  struct_header_template = ReadTemplate("module_struct.h")
+  struct_source_template = ReadTemplate("module_struct.cc")
+  interface_header_template = ReadTemplate("module_interface.h")
+  field_template = Template("  $itype ${field}_;")
+  bool_field_template = Template("  uint8_t ${field}_ : 1;")
+  setter_template = \
+      Template("  void set_$field($stype $field) { ${field}_ = $field; }")
+  getter_template = \
+      Template("  $gtype $field() const { return ${field}_; }")
+  ptr_getter_template = \
+      Template("  $gtype $field() const { return ${field}_.ptr; }")
+  pad_template = Template("  uint8_t _pad${count}_[$pad];")
+  HEADER_SIZE = 8
+
+  kind_to_type = {
+    mojom.BOOL:   "bool",
+    mojom.INT8:   "int8_t",
+    mojom.UINT8:  "uint8_t",
+    mojom.INT16:  "int16_t",
+    mojom.UINT16: "uint16_t",
+    mojom.INT32:  "int32_t",
+    mojom.UINT32: "uint32_t",
+    mojom.FLOAT:  "float",
+    mojom.HANDLE: "mojo::Handle",
+    mojom.INT64:  "int64_t",
+    mojom.UINT64: "uint64_t",
+    mojom.DOUBLE: "double",
+  }
+
+  @classmethod
+  def GetType(cls, kind):
+    if isinstance(kind, mojom.Struct):
+      return "%s*" % kind.name.capitalize()
+    if isinstance(kind, mojom.Array):
+      return "mojo::Array<%s>*" % cls.GetType(kind.kind)
+    if kind.spec == 's':
+      return "mojo::String*"
+    return cls.kind_to_type[kind]
+
+  @classmethod
+  def GetConstType(cls, kind):
+    if isinstance(kind, mojom.Struct):
+      return "const %s*" % kind.name.capitalize()
+    if isinstance(kind, mojom.Array):
+      return "const mojo::Array<%s>*" % cls.GetConstType(kind.kind)
+    if kind.spec == 's':
+      return "const mojo::String*"
+    return cls.kind_to_type[kind]
+
+  @classmethod
+  def GetGetterLine(cls, pf):
+    kind = pf.field.kind
+    template = None
+    gtype = cls.GetConstType(kind)
+    if isinstance(kind, (mojom.Struct, mojom.Array)) or kind.spec == 's':
+      template = cls.ptr_getter_template
+    else:
+      template = cls.getter_template
+    return template.substitute(field=pf.field.name, gtype=gtype)
+
+  @classmethod
+  def GetSetterLine(cls, pf):
+    stype = cls.GetType(pf.field.kind)
+    return cls.setter_template.substitute(field=pf.field.name, stype=stype)
+
+  @classmethod
+  def GetFieldLine(cls, pf):
+    kind = pf.field.kind
+    if kind.spec == 'b':
+      return cls.bool_field_template.substitute(field=pf.field.name)
+    itype = None
+    if isinstance(kind, mojom.Struct):
+      itype = "mojo::internal::StructPointer<%s>" % kind.name.capitalize()
+    elif isinstance(kind, mojom.Array):
+      itype = "mojo::internal::StructPointer<%s>" % cls.GetType(kind.kind)
+    elif kind.spec == 's':
+      itype = "mojo::internal::StringPointer"
+    else:
+      itype = cls.kind_to_type[kind]
+    return cls.field_template.substitute(field=pf.field.name, itype=itype)
+
+  def GetHeaderGuard(self, component):
+    return "MOJO_GENERATED_BINDINGS_%s_%s_H_" % \
+        (self.module.name.upper(), component.name.upper())
+
+  # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all files
+  # to stdout.
+  def __init__(self, module, header_dir, output_dir=None):
+    self.module = module
+    self.header_dir = header_dir
+    self.output_dir = output_dir
+
+  def WriteTemplateToFile(self, template, name, ext, **substitutions):
+    if self.output_dir is None:
+      file = sys.stdout
+    else:
+      filename = "%s_%s.%s" % \
+          (self.module.name.lower(), name.lower(), ext)
+      file = open(os.path.join(self.output_dir, filename), "w+")
+    try:
+      file.write(template.substitute(substitutions))
+    finally:
+      if self.output_dir is not None:
+        file.close()
+
+  def GenerateStructHeader(self, struct):
+    fields = []
+    setters = []
+    getters = []
+    forwards = set()
+
+    ps = mojom_pack.PackedStruct(struct)
+    pad_count = 0
+    num_fields = len(ps.packed_fields)
+    for i in xrange(num_fields):
+      pf = ps.packed_fields[i]
+      fields.append(self.GetFieldLine(pf))
+      AddForward(forwards, pf.field.kind)
+      if i < (num_fields - 2):
+        next_pf = ps.packed_fields[i+1]
+        pad = next_pf.offset - (pf.offset + pf.size)
+        if pad > 0:
+          fields.append(self.pad_template.substitute(count=pad_count, pad=pad))
+          pad_count += 1
+      setters.append(self.GetSetterLine(pf))
+      getters.append(self.GetGetterLine(pf))
+
+    if num_fields > 0:
+      last_field = ps.packed_fields[num_fields - 1]
+      offset = last_field.offset + last_field.size
+      pad = mojom_pack.GetPad(offset, 8)
+      if pad > 0:
+        fields.append(self.pad_template.substitute(count=pad_count, pad=pad))
+        pad_count += 1
+      size = offset + pad
+    else:
+      size = 0
+
+    self.WriteTemplateToFile(self.struct_header_template, struct.name, 'h',
+        YEAR = datetime.date.today().year,
+        HEADER_GUARD = self.GetHeaderGuard(struct),
+        NAMESPACE = self.module.namespace,
+        CLASS = struct.name.capitalize(),
+        SIZE = size + self.HEADER_SIZE,
+        FORWARDS = GetForwards(forwards),
+        SETTERS = '\n'.join(setters),
+        GETTERS = '\n'.join(getters),
+        FIELDS = '\n'.join(fields))
+
+  def GenerateStructSource(self, struct):
+    header = "%s_%s.h" % (self.module.name.lower(), struct.name.lower())
+    header = os.path.join(self.header_dir, header)
+    self.WriteTemplateToFile(self.struct_source_template, struct.name, 'cc',
+        YEAR = datetime.date.today().year,
+        NAMESPACE = self.module.namespace,
+        CLASS = struct.name.capitalize(),
+        NUM_FIELDS = len(struct.fields),
+        HEADER = header)
+
+  def GenerateInterfaceHeader(self, interface):
+    cpp_methods = []
+    forwards = set()
+    for method in interface.methods:
+      cpp_method = "  virtual void %s(" % method.name
+      first_param = True
+      for param in method.parameters:
+        if first_param == True:
+          first_param = False
+        else:
+          cpp_method += ", "
+        AddForward(forwards, param.kind)
+        cpp_method += "%s %s" % (self.GetConstType(param.kind), param.name)
+      cpp_method += ") = 0;"
+      cpp_methods.append(cpp_method)
+
+    self.WriteTemplateToFile(
+        self.interface_header_template,
+        interface.name,
+        'h',
+        YEAR = datetime.date.today().year,
+        HEADER_GUARD = self.GetHeaderGuard(interface),
+        NAMESPACE = self.module.namespace,
+        CLASS = interface.name.capitalize(),
+        FORWARDS = GetForwards(forwards),
+        METHODS = '\n'.join(cpp_methods))
+
+  def GenerateFiles(self):
+    for struct in self.module.structs:
+      self.GenerateStructHeader(struct)
+      self.GenerateStructSource(struct)
+    for interface in self.module.interfaces:
+      self.GenerateInterfaceHeader(interface)
diff --git a/mojo/public/bindings/generators/mojom_data_tests.py b/mojo/public/bindings/generators/mojom_data_tests.py
index c891bd4..e69de29 100644
--- a/mojo/public/bindings/generators/mojom_data_tests.py
+++ b/mojo/public/bindings/generators/mojom_data_tests.py
@@ -1,84 +0,0 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import mojom_data
-import mojom_test
-import sys
-
-EXPECT_EQ = mojom_test.EXPECT_EQ
-EXPECT_TRUE = mojom_test.EXPECT_TRUE
-RunTest = mojom_test.RunTest
-
-
-def DeepEquals(d1, d2):
-  if d1 == d2:
-    return True
-  if d2.__class__ != d2.__class__:
-    return False
-  if isinstance(d1, dict):
-    if set(d1.keys()) != set(d2.keys()):
-      return False
-    for key in d1.keys():
-      if not DeepEquals(d1[key], d2[key]):
-        return False
-    return True
-  if isinstance(d1, (list, tuple)):
-    if len(d1) != len(d2):
-      return False
-    for i in range(len(d1)):
-      if not DeepEquals(d1[i], d2[i]):
-        return False
-    return True
-  return False
-
-
-test_dict = {
-  'name': 'test',
-  'namespace': 'testspace',
-  'structs': [{
-    'name': 'teststruct',
-    'fields': [
-      {'name': 'testfield1', 'kind': 'i32'},
-      {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}],
-  'interfaces': [{
-    'name': 'Server',
-    'methods': [{
-      'name': 'Foo',
-      'parameters': [
-        {'name': 'foo', 'kind': 'i32'},
-        {'name': 'bar', 'kind': 'a:x:teststruct'}],
-    'ordinal': 42}]}]
-}
-
-
-def TestRead():
-  module = mojom_data.ModuleFromData(test_dict)
-  return mojom_test.TestTestModule(module)
-
-
-def TestWrite():
-  module = mojom_test.BuildTestModule()
-  d = mojom_data.ModuleToData(module)
-  return EXPECT_TRUE(DeepEquals(test_dict, d))
-
-
-def TestWriteRead():
-  module1 = mojom_test.BuildTestModule()
-
-  dict1 = mojom_data.ModuleToData(module1)
-  module2 = mojom_data.ModuleFromData(dict1)
-  return EXPECT_TRUE(mojom_test.ModulesAreEqual(module1, module2))
-
-
-def Main(args):
-  errors = 0
-  errors += RunTest(TestWriteRead)
-  errors += RunTest(TestRead)
-  errors += RunTest(TestWrite)
-
-  return errors
-
-
-if __name__ == '__main__':
-  sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/bindings/generators/mojom_pack.py b/mojo/public/bindings/generators/mojom_pack.py
new file mode 100644
index 0000000..521dc14
--- /dev/null
+++ b/mojo/public/bindings/generators/mojom_pack.py
@@ -0,0 +1,102 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import mojom
+
+# mojom_pack provides a mechanism for determining the packed order and offsets
+# of a mojom.Struct.
+#
+# ps = mojom_pack.PackedStruct(struct)
+# ps.packed_fields will access a list of PackedField objects, each of which
+# will have an offset, a size and a bit (for mojom.BOOLs).
+
+class PackedField(object):
+  kind_to_size = {
+    mojom.BOOL:   1,
+    mojom.INT8:   1,
+    mojom.UINT8:  1,
+    mojom.INT16:  2,
+    mojom.UINT16: 2,
+    mojom.INT32:  4,
+    mojom.UINT32: 4,
+    mojom.FLOAT:  4,
+    mojom.HANDLE: 4,
+    mojom.INT64:  8,
+    mojom.UINT64: 8,
+    mojom.DOUBLE: 8,
+    mojom.STRING: 8
+  }
+
+  @classmethod
+  def GetSizeForKind(cls, kind):
+    if isinstance(kind, mojom.Array) or isinstance(kind, mojom.Struct):
+      return 8
+    return cls.kind_to_size[kind]
+
+  def __init__(self, field, ordinal):
+    self.field = field
+    self.ordinal = ordinal
+    self.size = self.GetSizeForKind(field.kind)
+    self.offset = None
+    self.bit = None
+
+# Returns the pad necessary to reserve space for alignment of |size|.
+def GetPad(offset, size):
+  return (size - (offset % size)) % size
+
+# Returns a 2-tuple of the field offset and bit (for BOOLs)
+def GetFieldOffset(field, last_field):
+  if field.field.kind == mojom.BOOL and \
+      last_field.field.kind == mojom.BOOL and \
+      last_field.bit < 7:
+    return (last_field.offset, last_field.bit + 1)
+
+  offset = last_field.offset + last_field.size
+  pad = GetPad(offset, field.size)
+  return (offset + pad, 0)
+
+
+class PackedStruct(object):
+  def __init__(self, struct):
+    self.struct = struct
+    self.packed_fields = []
+
+    # No fields.
+    if (len(struct.fields) == 0):
+      return
+
+    # Start by sorting by ordinal.
+    src_fields = []
+    ordinal = 1
+    for field in struct.fields:
+      if field.ordinal is not None:
+        ordinal = field.ordinal
+      src_fields.append(PackedField(field, ordinal))
+      ordinal += 1
+    src_fields.sort(key=lambda field: field.ordinal)
+
+    src_field = src_fields[0]
+    src_field.offset = 0
+    src_field.bit = 0
+    # dst_fields will contain each of the fields, in increasing offset order.
+    dst_fields = self.packed_fields
+    dst_fields.append(src_field)
+
+    # Then find first slot that each field will fit.
+    for src_field in src_fields[1:]:
+      last_field = dst_fields[0]
+      for i in xrange(1, len(dst_fields)):
+        next_field = dst_fields[i]
+        offset, bit = GetFieldOffset(src_field, last_field)
+        if offset + src_field.size <= next_field.offset:
+          # Found hole.
+          src_field.offset = offset
+          src_field.bit = bit
+          dst_fields.insert(i, src_field)
+          break
+        last_field = next_field
+      if src_field.offset is None:
+        # Add to end
+        src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field)
+        dst_fields.append(src_field)
diff --git a/mojo/public/bindings/generators/mojom_pack_tests.py b/mojo/public/bindings/generators/mojom_pack_tests.py
new file mode 100644
index 0000000..6ff927d
--- /dev/null
+++ b/mojo/public/bindings/generators/mojom_pack_tests.py
@@ -0,0 +1,174 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import mojom
+import mojom_pack
+import mojom_test
+import sys
+
+EXPECT_EQ = mojom_test.EXPECT_EQ
+EXPECT_TRUE = mojom_test.EXPECT_TRUE
+RunTest = mojom_test.RunTest
+
+
+def TestOrdinalOrder():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT32, 2)
+  struct.AddField('testfield2', mojom.INT32, 1)
+  ps = mojom_pack.PackedStruct(struct)
+
+  errors += EXPECT_EQ(2, len(ps.packed_fields))
+  errors += EXPECT_EQ('testfield2', ps.packed_fields[0].field.name)
+  errors += EXPECT_EQ('testfield1', ps.packed_fields[1].field.name)
+
+  return errors
+
+def TestZeroFields():
+  errors = 0
+  struct = mojom.Struct('test')
+  ps = mojom_pack.PackedStruct(struct)
+  errors += EXPECT_EQ(0, len(ps.packed_fields))
+  return errors
+
+
+def TestOneField():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT8)
+  ps = mojom_pack.PackedStruct(struct)
+  errors += EXPECT_EQ(1, len(ps.packed_fields))
+  return errors
+
+# Pass three tuples.
+# |kinds| is a sequence of mojom.Kinds that specify the fields that are to
+# be created.
+# |fields| is the expected order of the resulting fields, with the integer
+# "1" first.
+# |offsets| is the expected order of offsets, with the integer "0" first.
+def TestSequence(kinds, fields, offsets):
+  errors = 0
+  struct = mojom.Struct('test')
+  index = 1
+  for kind in kinds:
+    struct.AddField("%d" % index, kind)
+    index += 1
+  ps = mojom_pack.PackedStruct(struct)
+  num_fields = len(ps.packed_fields)
+  errors += EXPECT_EQ(len(kinds), num_fields)
+  for i in xrange(num_fields):
+    EXPECT_EQ("%d" % fields[i], ps.packed_fields[i].field.name)
+    EXPECT_EQ(offsets[i], ps.packed_fields[i].offset)
+
+  return errors
+
+
+def TestPaddingPackedInOrder():
+  return TestSequence(
+      (mojom.INT8, mojom.UINT8, mojom.INT32),
+      (1, 2, 3),
+      (0, 1, 4))
+
+
+def TestPaddingPackedOutOfOrder():
+  return TestSequence(
+      (mojom.INT8, mojom.INT32, mojom.UINT8),
+      (1, 3, 2),
+      (0, 1, 4))
+
+
+def TestPaddingPackedOverflow():
+  kinds = (mojom.INT8, mojom.INT32, mojom.INT16, mojom.INT8, mojom.INT8)
+  # 2 bytes should be packed together first, followed by short, then by int.
+  fields = (1, 4, 3, 2, 5)
+  offsets = (0, 1, 2, 4, 8)
+  return TestSequence(kinds, fields, offsets)
+
+
+def TestAllTypes():
+  struct = mojom.Struct('test')
+  array = mojom.Array()
+  return TestSequence(
+      (mojom.BOOL, mojom.INT8, mojom.STRING, mojom.UINT8,
+       mojom.INT16, mojom.DOUBLE, mojom.UINT16,
+       mojom.INT32, mojom.UINT32, mojom.INT64,
+       mojom.FLOAT, mojom.STRING, mojom.HANDLE,
+       mojom.UINT64, mojom.Struct('test'), mojom.Array()),
+      (1, 2, 4, 5, 7, 3, 6,  8,  9,  10, 11, 13, 12, 14, 15, 16, 17),
+      (0, 1, 2, 4, 6, 8, 16, 24, 28, 32, 40, 44, 48, 56, 64, 72, 80))
+
+
+def TestPaddingPackedOutOfOrderByOrdinal():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('testfield1', mojom.INT8)
+  struct.AddField('testfield3', mojom.UINT8, 3)
+  struct.AddField('testfield2', mojom.INT32, 2)
+  ps = mojom_pack.PackedStruct(struct)
+  errors += EXPECT_EQ(3, len(ps.packed_fields))
+
+  # Second byte should be packed in behind first, altering order.
+  errors += EXPECT_EQ('testfield1', ps.packed_fields[0].field.name)
+  errors += EXPECT_EQ('testfield3', ps.packed_fields[1].field.name)
+  errors += EXPECT_EQ('testfield2', ps.packed_fields[2].field.name)
+
+  # Second byte should be packed with first.
+  errors += EXPECT_EQ(0, ps.packed_fields[0].offset)
+  errors += EXPECT_EQ(1, ps.packed_fields[1].offset)
+  errors += EXPECT_EQ(4, ps.packed_fields[2].offset)
+
+  return errors
+
+
+def TestBools():
+  errors = 0
+  struct = mojom.Struct('test')
+  struct.AddField('bit0', mojom.BOOL)
+  struct.AddField('bit1', mojom.BOOL)
+  struct.AddField('int', mojom.INT32)
+  struct.AddField('bit2', mojom.BOOL)
+  struct.AddField('bit3', mojom.BOOL)
+  struct.AddField('bit4', mojom.BOOL)
+  struct.AddField('bit5', mojom.BOOL)
+  struct.AddField('bit6', mojom.BOOL)
+  struct.AddField('bit7', mojom.BOOL)
+  struct.AddField('bit8', mojom.BOOL)
+  ps = mojom_pack.PackedStruct(struct)
+  errors += EXPECT_EQ(10, len(ps.packed_fields))
+
+  # First 8 bits packed together.
+  for i in xrange(8):
+    pf = ps.packed_fields[i]
+    errors += EXPECT_EQ(0, pf.offset)
+    errors += EXPECT_EQ("bit%d" % i, pf.field.name)
+    errors += EXPECT_EQ(i, pf.bit)
+
+  # Ninth bit goes into second byte.
+  errors += EXPECT_EQ("bit8", ps.packed_fields[8].field.name)
+  errors += EXPECT_EQ(1, ps.packed_fields[8].offset)
+  errors += EXPECT_EQ(0, ps.packed_fields[8].bit)
+
+  # int comes last.
+  errors += EXPECT_EQ("int", ps.packed_fields[9].field.name)
+  errors += EXPECT_EQ(4, ps.packed_fields[9].offset)
+
+  return errors
+
+
+def Main(args):
+  errors = 0
+  errors += RunTest(TestZeroFields)
+  errors += RunTest(TestOneField)
+  errors += RunTest(TestPaddingPackedInOrder)
+  errors += RunTest(TestPaddingPackedOutOfOrder)
+  errors += RunTest(TestPaddingPackedOverflow)
+  errors += RunTest(TestAllTypes)
+  errors += RunTest(TestPaddingPackedOutOfOrderByOrdinal)
+  errors += RunTest(TestBools)
+
+  return errors
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/mojo/public/bindings/generators/run_cpp_generator.py b/mojo/public/bindings/generators/run_cpp_generator.py
new file mode 100755
index 0000000..72a1a74
--- /dev/null
+++ b/mojo/public/bindings/generators/run_cpp_generator.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import ast
+import mojom
+import mojom_cpp_generator
+import mojom_data
+import mojom_pack
+import sys
+
+def ReadDict(file):
+  with open(file, 'r') as f:
+    s = f.read()
+    dict = ast.literal_eval(s)
+    return dict
+
+dict = ReadDict(sys.argv[1])
+module = mojom_data.ModuleFromData(dict)
+dir = None
+if len(sys.argv) > 2:
+  dir = sys.argv[2]
+cpp = mojom_cpp_generator.CPPGenerator(module, "src", dir)
+cpp.GenerateFiles()
diff --git a/mojo/public/bindings/generators/run_mojom_tests.py b/mojo/public/bindings/generators/run_mojom_tests.py
index ad41183..b9cefcd 100755
--- a/mojo/public/bindings/generators/run_mojom_tests.py
+++ b/mojo/public/bindings/generators/run_mojom_tests.py
@@ -24,6 +24,7 @@
   errors = 0
   errors += TestMojom('mojom_tests.py', ['--test'])
   errors += TestMojom('mojom_data_tests.py', ['--test'])
+  errors += TestMojom('mojom_pack_tests.py', ['--test'])
 
   if errors:
     print '\nFailed tests.'
diff --git a/mojo/public/bindings/lib/TODO b/mojo/public/bindings/lib/TODO
index 6d8aa3c..e81cc11 100644
--- a/mojo/public/bindings/lib/TODO
+++ b/mojo/public/bindings/lib/TODO
@@ -4,9 +4,6 @@
  - Add tests of Buffer classes
  - Optimize Buffer classes?
  - Make "Clone" method public?
- - Specify object packing and padding.
  - Add compile-time asserts to verify object packing and padding.
  - Pack boolean arrays?
- - Get rid of gratuitous use of Align() function in favor of adding padding.
  - Investigate making arrays of objects not be arrays of pointers.
- - Consider getting rid of Data structs (i.e., d_ member).
diff --git a/mojo/public/bindings/lib/bindings.h b/mojo/public/bindings/lib/bindings.h
index cd64223..c905062 100644
--- a/mojo/public/bindings/lib/bindings.h
+++ b/mojo/public/bindings/lib/bindings.h
@@ -60,10 +60,12 @@
   typedef typename internal::ArrayTraits<T>::StorageType StorageType;
 
   StorageType* storage() {
-    return reinterpret_cast<StorageType*>(this + 1);
+    return reinterpret_cast<StorageType*>(
+        reinterpret_cast<char*>(this) + sizeof(*this));
   }
   const StorageType* storage() const {
-    return reinterpret_cast<const StorageType*>(this + 1);
+    return reinterpret_cast<const StorageType*>(
+        reinterpret_cast<const char*>(this) + sizeof(*this));
   }
 
   Array(size_t num_bytes, size_t num_elements) {
@@ -76,6 +78,7 @@
 
   // Elements of type internal::ArrayTraits<T>::StorageType follow.
 };
+MOJO_COMPILE_ASSERT(sizeof(Array<char>) == 8, bad_sizeof_Array);
 
 // UTF-8 encoded
 typedef Array<char> String;
diff --git a/mojo/public/bindings/lib/bindings_internal.h b/mojo/public/bindings/lib/bindings_internal.h
index f6e7eb2..aa0dbe2 100644
--- a/mojo/public/bindings/lib/bindings_internal.h
+++ b/mojo/public/bindings/lib/bindings_internal.h
@@ -7,37 +7,48 @@
 
 #include <stdint.h>
 
+#include "mojo/public/system/macros.h"
+
 namespace mojo {
 template <typename T> class Array;
 
 namespace internal {
 
+#pragma pack(push, 1)
+
 struct StructHeader {
   uint32_t num_bytes;
   uint32_t num_fields;
 };
+MOJO_COMPILE_ASSERT(sizeof(StructHeader) == 8, bad_sizeof_StructHeader);
 
 struct ArrayHeader {
   uint32_t num_bytes;
   uint32_t num_elements;
 };
+MOJO_COMPILE_ASSERT(sizeof(ArrayHeader) == 8, bad_sizeof_ArrayHeader);
 
 template <typename T>
 union StructPointer {
   uint64_t offset;
   T* ptr;
 };
+MOJO_COMPILE_ASSERT(sizeof(StructPointer<char>) == 8, bad_sizeof_StructPointer);
 
 template <typename T>
 union ArrayPointer {
   uint64_t offset;
   Array<T>* ptr;
 };
+MOJO_COMPILE_ASSERT(sizeof(ArrayPointer<char>) == 8, bad_sizeof_ArrayPointer);
 
 union StringPointer {
   uint64_t offset;
   Array<char>* ptr;
 };
+MOJO_COMPILE_ASSERT(sizeof(StringPointer) == 8, bad_sizeof_StringPointer);
+
+#pragma pack(pop)
 
 template <typename T>
 struct ArrayTraits {
diff --git a/mojo/public/bindings/lib/bindings_serialization.h b/mojo/public/bindings/lib/bindings_serialization.h
index 57c1452..3d4ad45 100644
--- a/mojo/public/bindings/lib/bindings_serialization.h
+++ b/mojo/public/bindings/lib/bindings_serialization.h
@@ -51,8 +51,8 @@
 // specialization.
 
 template <typename T>
-inline size_t ComputeAlignedSizeOf(const T* obj) {
-  return obj ? ObjectTraits<T>::ComputeAlignedSizeOf(obj) : 0;
+inline size_t ComputeSizeOf(const T* obj) {
+  return obj ? ObjectTraits<T>::ComputeSizeOf(obj) : 0;
 }
 
 template <typename T>
@@ -102,8 +102,8 @@
 struct ArrayHelper {
   typedef T ElementType;
 
-  static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header,
-                                             const ElementType* elements) {
+  static size_t ComputeSizeOfElements(const ArrayHeader* header,
+                                      const ElementType* elements) {
     return 0;
   }
 
@@ -127,8 +127,8 @@
 struct ArrayHelper<Handle> {
   typedef Handle ElementType;
 
-  static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header,
-                                             const ElementType* elements) {
+  static size_t ComputeSizeOfElements(const ArrayHeader* header,
+                                      const ElementType* elements) {
     return 0;
   }
 
@@ -149,11 +149,11 @@
 struct ArrayHelper<P*> {
   typedef StructPointer<P> ElementType;
 
-  static size_t ComputeAlignedSizeOfElements(const ArrayHeader* header,
-                                             const ElementType* elements) {
+  static size_t ComputeSizeOfElements(const ArrayHeader* header,
+                                      const ElementType* elements) {
     size_t result = 0;
     for (uint32_t i = 0; i < header->num_elements; ++i)
-      result += ComputeAlignedSizeOf(elements[i].ptr);
+      result += ComputeSizeOf(elements[i].ptr);
     return result;
   }
 
@@ -184,10 +184,10 @@
 template <typename T>
 class ObjectTraits<Array<T> > {
  public:
-  static size_t ComputeAlignedSizeOf(const Array<T>* array) {
+  static size_t ComputeSizeOf(const Array<T>* array) {
     return Align(array->header_.num_bytes) +
-        ArrayHelper<T>::ComputeAlignedSizeOfElements(&array->header_,
-                                                     array->storage());
+        ArrayHelper<T>::ComputeSizeOfElements(&array->header_,
+                                              array->storage());
   }
 
   static Array<T>* Clone(const Array<T>* array, Buffer* buf) {
diff --git a/mojo/public/bindings/lib/message.h b/mojo/public/bindings/lib/message.h
index 19f4d10..38fdafc 100644
--- a/mojo/public/bindings/lib/message.h
+++ b/mojo/public/bindings/lib/message.h
@@ -11,15 +11,21 @@
 
 namespace mojo {
 
+#pragma pack(push, 1)
+
 struct MessageHeader {
   uint32_t num_bytes;
   uint32_t name;
 };
+MOJO_COMPILE_ASSERT(sizeof(MessageHeader) == 8, bad_sizeof_MessageHeader);
 
 struct MessageData {
   MessageHeader header;
   uint8_t payload[1];
 };
+MOJO_COMPILE_ASSERT(sizeof(MessageData) == 9, bad_sizeof_MessageData);
+
+#pragma pack(pop)
 
 struct Message {
   Message();
diff --git a/mojo/public/bindings/mojo_idl.py b/mojo/public/bindings/mojo_idl.py
new file mode 100755
index 0000000..4f149bc
--- /dev/null
+++ b/mojo/public/bindings/mojo_idl.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""The frontend for the Mojo bindings system."""
+
+
+import sys
+from optparse import OptionParser
+from parser import mojo_parser
+from parser import mojo_translate
+from generators import mojom_data
+from generators import mojom_cpp_generator
+
+
+def Main():
+  parser = OptionParser(usage="usage: %prog [options] filename1 [filename2...]")
+  parser.add_option("-i", "--include_dir", dest="include_dir", default=".",
+                    help="specify directory for #includes")
+  parser.add_option("-o", "--output_dir", dest="output_dir", default=".",
+                    help="specify output directory")
+  (options, args) = parser.parse_args()
+
+  if len(args) < 1:
+    parser.print_help()
+    sys.exit(1)
+
+  for filename in args:
+    # TODO(darin): There's clearly too many layers of translation here!  We can
+    # at least avoid generating the serialized Mojom IR.
+    tree = mojo_parser.Parse(filename)
+    mojom = mojo_translate.Translate(tree)
+    module = mojom_data.ModuleFromData(mojom)
+    cpp = mojom_cpp_generator.CPPGenerator(
+        module, options.include_dir, options.output_dir)
+    cpp.GenerateFiles()
+
+
+if __name__ == '__main__':
+  Main()
diff --git a/mojo/public/bindings/parser/__init__.py b/mojo/public/bindings/parser/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/public/bindings/parser/__init__.py
diff --git a/mojo/public/bindings/parser/mojo_parser.py b/mojo/public/bindings/parser/mojo_parser.py
new file mode 100755
index 0000000..a967fbc
--- /dev/null
+++ b/mojo/public/bindings/parser/mojo_parser.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""Generates a syntax tree from a Mojo IDL file."""
+
+
+import sys
+import os.path
+
+
+# Try to load the ply module, if not, then assume it is in the third_party
+# directory.
+try:
+  # Disable lint check which fails to find the ply module.
+  # pylint: disable=F0401
+  from ply import lex
+  from ply import yacc
+except ImportError:
+  module_path, module_name = os.path.split(__file__)
+  third_party = os.path.join(
+      module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party')
+  sys.path.append(third_party)
+  # pylint: disable=F0401
+  from ply import lex
+  from ply import yacc
+
+
+def ListFromConcat(*items):
+  """Generate list by concatenating inputs"""
+  itemsout = []
+  for item in items:
+    if item is None:
+      continue
+    if type(item) is not type([]):
+      itemsout.append(item)
+    else:
+      itemsout.extend(item)
+
+  return itemsout
+
+
+class Lexer(object):
+
+  # This field is required by lex to specify the complete list of valid tokens.
+  tokens = (
+    'NAME',
+    'NUMBER',
+
+    'ARRAY',
+    'ORDINAL',
+
+    'MODULE',
+    'STRUCT',
+    'INTERFACE',
+    'VOID',
+
+    'LCURLY',
+    'RCURLY',
+    'LPAREN',
+    'RPAREN',
+    'LBRACKET',
+    'RBRACKET',
+    'COMMA',
+    'SEMICOLON',
+    'EQUALS',
+  )
+
+  t_LCURLY     = r'{'
+  t_RCURLY     = r'}'
+  t_LPAREN     = r'\('
+  t_RPAREN     = r'\)'
+  t_LBRACKET   = r'\['
+  t_RBRACKET   = r'\]'
+  t_COMMA      = r','
+  t_SEMICOLON  = r';'
+  t_EQUALS     = r'='
+  t_NAME       = r'[a-zA-Z_][a-zA-Z0-9_]*'
+  t_ARRAY      = r'[a-zA-Z_][a-zA-Z0-9_]*\[\]'
+  t_NUMBER     = r'\d+'
+  t_ORDINAL    = r'@[0-9]*'
+
+  def t_MODULE(self, t):
+    r'module'
+    return t
+
+  def t_STRUCT(self, t):
+    r'struct'
+    return t
+
+  def t_INTERFACE(self, t):
+    r'interface'
+    return t
+
+  def t_VOID(self, t):
+    r'void'
+    return t
+
+  # Ignore C and C++ style comments
+  def t_COMMENT(self, t):
+    r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)'
+    pass
+
+  # Ignored characters
+  t_ignore = " \t"
+
+  def t_newline(self, t):
+    r'\n+'
+    t.lexer.lineno += t.value.count("\n")
+
+  def t_error(self, t):
+    print("Illegal character '%s'" % t.value[0])
+    t.lexer.skip(1)
+
+
+class Parser(object):
+
+  def __init__(self, lexer):
+    self.tokens = lexer.tokens
+
+  def p_module(self, p):
+    """module : MODULE NAME LCURLY definitions RCURLY"""
+    p[0] = ('MODULE', p[2], p[4])
+
+  def p_definitions(self, p):
+    """definitions : definition definitions
+                   |"""
+    if len(p) > 1:
+      p[0] = ListFromConcat(p[1], p[2])
+
+  def p_definition(self, p):
+    """definition : struct
+                  | interface"""
+    p[0] = p[1]
+
+  def p_attribute_section(self, p):
+    """attribute_section : LBRACKET attributes RBRACKET
+                         | """
+    if len(p) > 3:
+      p[0] = p[2]
+
+  def p_attributes(self, p):
+    """attributes : attribute
+                  | attribute COMMA attributes
+                  | """
+    if len(p) == 2:
+      p[0] = ListFromConcat(p[1])
+    elif len(p) > 3:
+      p[0] = ListFromConcat(p[1], p[3])
+
+  def p_attribute(self, p):
+    """attribute : NAME EQUALS NUMBER"""
+    p[0] = ('ATTRIBUTE', p[1], p[3])
+
+  def p_struct(self, p):
+    """struct : attribute_section STRUCT NAME LCURLY fields RCURLY SEMICOLON"""
+    p[0] = ('STRUCT', p[3], p[1], p[5])
+
+  def p_fields(self, p):
+    """fields : field fields
+              |"""
+    if len(p) > 1:
+      p[0] = ListFromConcat(p[1], p[2])
+
+  def p_field(self, p):
+    """field : typename NAME ordinal SEMICOLON"""
+    p[0] = ('FIELD', p[1], p[2], p[3])
+
+  def p_interface(self, p):
+    """interface : INTERFACE NAME LCURLY methods RCURLY SEMICOLON"""
+    p[0] = ('INTERFACE', p[2], p[4])
+
+  def p_methods(self, p):
+    """methods : method methods
+               | """
+    if len(p) > 1:
+      p[0] = ListFromConcat(p[1], p[2])
+
+  def p_method(self, p):
+    """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON"""
+    p[0] = ('METHOD', p[2], p[4], p[6])
+
+  def p_parameters(self, p):
+    """parameters : parameter
+                  | parameter COMMA parameters
+                  | """
+    if len(p) == 2:
+      p[0] = p[1]
+    elif len(p) > 3:
+      p[0] = ListFromConcat(p[1], p[3])
+
+  def p_parameter(self, p):
+    """parameter : typename NAME ordinal"""
+    p[0] = ('PARAM', p[1], p[2], p[3])
+
+  def p_typename(self, p):
+    """typename : NAME
+                | ARRAY"""
+    p[0] = p[1]
+
+  def p_ordinal(self, p):
+    """ordinal : ORDINAL
+               | """
+    if len(p) > 1:
+      p[0] = p[1]
+
+  def p_error(self, e):
+    print('error: %s'%e)
+
+
+def Parse(filename):
+  lexer = Lexer()
+  parser = Parser(lexer)
+
+  lex.lex(object=lexer)
+  yacc.yacc(module=parser, debug=0, write_tables=0)
+
+  tree = yacc.parse(open(filename).read())
+  return tree
+
+
+def Main():
+  if len(sys.argv) < 2:
+    print("usage: %s filename" % (sys.argv[0]))
+    sys.exit(1)
+  tree = Parse(filename=sys.argv[1])
+  print(tree)
+
+
+if __name__ == '__main__':
+  Main()
diff --git a/mojo/public/bindings/parser/mojo_translate.py b/mojo/public/bindings/parser/mojo_translate.py
new file mode 100755
index 0000000..c562b52
--- /dev/null
+++ b/mojo/public/bindings/parser/mojo_translate.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""Translate parse tree to Mojom IR"""
+
+
+import sys
+
+
+def MapKind(kind):
+  # todo: add more types
+  map_to_kind = { 'bool': 'b',
+                  'int8': 'i8',
+                  'int16': 'i16',
+                  'int32': 'i32',
+                  'int64': 'i64',
+                  'uint8': 'u8',
+                  'uint16': 'u16',
+                  'uint32': 'u32',
+                  'uint64': 'u64',
+                  'string': 's',
+                  'handle': 'h' }
+  if kind.endswith('[]'):
+    return 'a:' + MapKind(kind[0:len(kind)-2])
+  if kind in map_to_kind:
+    return map_to_kind[kind]
+  return 'x:' + kind
+
+
+def MapOrdinal(ordinal):
+  return int(ordinal[1:])  # Strip leading '@'
+
+
+def MapFields(fields):
+  out = []
+  for field in fields:
+    if field[0] == 'FIELD':
+      out.append({'name': field[2],
+                  'kind': MapKind(field[1]),
+                  'ordinal': MapOrdinal(field[3])})
+  return out
+
+
+def MapParameters(parameters):
+  out = []
+  for parameter in parameters:
+    if parameter[0] == 'PARAM':
+      out.append({'name': parameter[2],
+                  'kind': MapKind(parameter[1]),
+                  'ordinal': MapOrdinal(parameter[3])})
+  return out
+
+
+def MapMethods(methods):
+  out = []
+  for method in methods:
+    if method[0] == 'METHOD':
+      out.append({'name': method[1],
+                  'parameters': MapParameters(method[2]),
+                  'ordinal': MapOrdinal(method[3])})
+  return out
+
+
+class MojomBuilder():
+
+  def __init__(self):
+    self.mojom = {}
+
+  def AddStruct(self, name, attributes, fields):
+    struct = {}
+    struct['name'] = name
+    struct['fields'] = MapFields(fields)
+    self.mojom['structs'].append(struct)
+    # TODO(darin): Add support for |attributes|
+
+  def AddInterface(self, name, methods):
+    interface = {}
+    interface['name'] = name
+    interface['methods'] = MapMethods(methods)
+    self.mojom['interfaces'].append(interface)
+
+  def AddModule(self, name, contents):
+    self.mojom['name'] = name
+    self.mojom['namespace'] = name
+    self.mojom['structs'] = []
+    self.mojom['interfaces'] = []
+    for item in contents:
+      if item[0] == 'STRUCT':
+        self.AddStruct(name=item[1], attributes=item[2], fields=item[3])
+      elif item[0] == 'INTERFACE':
+        self.AddInterface(name=item[1], methods=item[2])
+
+  def Build(self, tree):
+    if tree[0] == 'MODULE':
+      self.AddModule(name=tree[1], contents=tree[2])
+    return self.mojom
+
+
+def Translate(tree):
+  return MojomBuilder().Build(tree)
+
+
+def Main():
+  if len(sys.argv) < 2:
+    print("usage: %s filename" % (sys.argv[0]))
+    sys.exit(1)
+  tree = eval(open(sys.argv[1]).read())
+  result = Translate(tree)
+  print(result)
+
+
+if __name__ == '__main__':
+  Main()
diff --git a/mojo/public/bindings/sample/generated/sample_bar.cc b/mojo/public/bindings/sample/generated/sample_bar.cc
new file mode 100644
index 0000000..e4f2daf
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_bar.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 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/public/bindings/sample/generated/sample_bar.h"
+
+namespace sample {
+
+// static
+Bar* Bar::New(mojo::Buffer* buf) {
+  return new (buf->Allocate(sizeof(Bar))) Bar();
+}
+
+Bar::Bar() {
+  _header_.num_bytes = sizeof(*this);
+  _header_.num_fields = 3;
+}
+
+}  // namespace sample
diff --git a/mojo/public/bindings/sample/generated/sample_bar.h b/mojo/public/bindings/sample/generated/sample_bar.h
new file mode 100644
index 0000000..d6ca189
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_bar.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_GENERATED_BINDINGS_SAMPLE_BAR_H_
+#define MOJO_GENERATED_BINDINGS_SAMPLE_BAR_H_
+
+#include "mojo/public/bindings/lib/bindings.h"
+
+namespace sample {
+
+#pragma pack(push, 1)
+
+class Bar {
+ public:
+  static Bar* New(mojo::Buffer* buf);
+
+  void set_alpha(uint8_t alpha) { alpha_ = alpha; }
+  void set_beta(uint8_t beta) { beta_ = beta; }
+  void set_gamma(uint8_t gamma) { gamma_ = gamma; }
+
+  uint8_t alpha() const { return alpha_; }
+  uint8_t beta() const { return beta_; }
+  uint8_t gamma() const { return gamma_; }
+
+ private:
+  friend class mojo::internal::ObjectTraits<Bar>;
+
+  Bar();
+  ~Bar();  // NOT IMPLEMENTED
+
+  mojo::internal::StructHeader _header_;
+  uint8_t alpha_;
+  uint8_t beta_;
+  uint8_t gamma_;
+  uint8_t _pad0_[5];
+};
+MOJO_COMPILE_ASSERT(sizeof(Bar) == 16, bad_sizeof_Bar);
+
+#pragma pack(pop)
+
+}  // namespace sample
+
+#endif  // MOJO_GENERATED_BINDINGS_SAMPLE_BAR_H_
diff --git a/mojo/public/bindings/sample/generated/sample_bar_serialization.cc b/mojo/public/bindings/sample/generated/sample_bar_serialization.cc
new file mode 100644
index 0000000..ec02505
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_bar_serialization.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 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/public/bindings/sample/generated/sample_bar_serialization.h"
+
+#include <string.h>
+
+#include "mojo/public/bindings/sample/generated/sample_bar.h"
+
+namespace mojo {
+namespace internal {
+
+// static
+size_t ObjectTraits<sample::Bar>::ComputeSizeOf(
+    const sample::Bar* bar) {
+  return sizeof(*bar);
+}
+
+// static
+sample::Bar* ObjectTraits<sample::Bar>::Clone(
+    const sample::Bar* bar, Buffer* buf) {
+  sample::Bar* clone = sample::Bar::New(buf);
+  memcpy(clone, bar, sizeof(*bar));
+  return clone;
+}
+
+// static
+void ObjectTraits<sample::Bar>::EncodePointersAndHandles(
+    sample::Bar* bar, std::vector<mojo::Handle>* handles) {
+}
+
+// static
+bool ObjectTraits<sample::Bar>::DecodePointersAndHandles(
+    sample::Bar* bar, const mojo::Message& message) {
+  return true;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/bindings/sample/generated/sample_bar_serialization.h b/mojo/public/bindings/sample/generated/sample_bar_serialization.h
new file mode 100644
index 0000000..8947e75
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_bar_serialization.h
@@ -0,0 +1,31 @@
+// Copyright 2013 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_GENERATED_BINDINGS_SAMPLE_BAR_SERIALIZATION_H_
+#define MOJO_GENERATED_BINDINGS_SAMPLE_BAR_SERIALIZATION_H_
+
+#include "mojo/public/bindings/lib/bindings_serialization.h"
+
+namespace sample {
+class Bar;
+}
+
+namespace mojo {
+namespace internal {
+
+template <>
+class ObjectTraits<sample::Bar> {
+ public:
+  static size_t ComputeSizeOf(const sample::Bar* bar);
+  static sample::Bar* Clone(const sample::Bar* bar, Buffer* buf);
+  static void EncodePointersAndHandles(sample::Bar* bar,
+                                       std::vector<mojo::Handle>* handles);
+  static bool DecodePointersAndHandles(sample::Bar* bar,
+                                       const mojo::Message& message);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_GENERATED_BINDINGS_SAMPLE_BAR_SERIALIZATION_H_
diff --git a/mojo/public/bindings/sample/generated/sample_foo.cc b/mojo/public/bindings/sample/generated/sample_foo.cc
new file mode 100644
index 0000000..d5d99e4
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_foo.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 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/public/bindings/sample/generated/sample_foo.h"
+
+namespace sample {
+
+// static
+Foo* Foo::New(mojo::Buffer* buf) {
+  return new (buf->Allocate(sizeof(Foo))) Foo();
+}
+
+Foo::Foo() {
+  _header_.num_bytes = sizeof(*this);
+  _header_.num_fields = 10;
+}
+
+}  // namespace sample
diff --git a/mojo/public/bindings/sample/generated/sample_foo.h b/mojo/public/bindings/sample/generated/sample_foo.h
new file mode 100644
index 0000000..396f209
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_foo.h
@@ -0,0 +1,81 @@
+// Copyright 2013 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_GENERATED_BINDINGS_SAMPLE_FOO_H_
+#define MOJO_GENERATED_BINDINGS_SAMPLE_FOO_H_
+
+#include "mojo/public/bindings/lib/bindings.h"
+
+namespace sample {
+class Bar;
+
+#pragma pack(push, 1)
+
+class Foo {
+ public:
+  static Foo* New(mojo::Buffer* buf);
+
+  void set_x(int32_t x) { x_ = x; }
+  void set_y(int32_t y) { y_ = y; }
+  void set_a(bool a) { a_ = a; }
+  void set_b(bool b) { b_ = b; }
+  void set_c(bool c) { c_ = c; }
+  void set_bar(Bar* bar) { bar_.ptr = bar; }
+  void set_data(mojo::Array<uint8_t>* data) { data_.ptr = data; }
+  void set_extra_bars(mojo::Array<Bar*>* extra_bars) {
+    extra_bars_.ptr = extra_bars;
+  }
+  void set_name(mojo::String* name) {
+    name_.ptr = name;
+  }
+  void set_files(mojo::Array<mojo::Handle>* files) {
+    files_.ptr = files;
+  }
+
+  int32_t x() const { return x_; }
+  int32_t y() const { return y_; }
+  bool a() const { return a_; }
+  bool b() const { return b_; }
+  bool c() const { return c_; }
+  const Bar* bar() const { return bar_.ptr; }
+  const mojo::Array<uint8_t>* data() const { return data_.ptr; }
+  const mojo::Array<Bar*>* extra_bars() const {
+    // NOTE: extra_bars is an optional field!
+    return _header_.num_fields >= 8 ? extra_bars_.ptr : NULL;
+  }
+  const mojo::String* name() const {
+    // NOTE: name is also an optional field!
+    return _header_.num_fields >= 9 ? name_.ptr : NULL;
+  }
+  const mojo::Array<mojo::Handle>* files() const {
+    // NOTE: files is also an optional field!
+    return _header_.num_fields >= 10 ? files_.ptr : NULL;
+  }
+
+ private:
+  friend class mojo::internal::ObjectTraits<Foo>;
+
+  Foo();
+  ~Foo();  // NOT IMPLEMENTED
+
+  mojo::internal::StructHeader _header_;
+  int32_t x_;
+  int32_t y_;
+  uint8_t a_ : 1;
+  uint8_t b_ : 1;
+  uint8_t c_ : 1;
+  uint8_t _pad0_[7];
+  mojo::internal::StructPointer<Bar> bar_;
+  mojo::internal::ArrayPointer<uint8_t> data_;
+  mojo::internal::ArrayPointer<Bar*> extra_bars_;
+  mojo::internal::StringPointer name_;
+  mojo::internal::ArrayPointer<mojo::Handle> files_;
+};
+MOJO_COMPILE_ASSERT(sizeof(Foo) == 64, bad_sizeof_Foo);
+
+#pragma pack(pop)
+
+}  // namespace sample
+
+#endif  // MOJO_GENERATED_BINDINGS_SAMPLE_FOO_H_
diff --git a/mojo/public/bindings/sample/generated/sample_foo_serialization.cc b/mojo/public/bindings/sample/generated/sample_foo_serialization.cc
new file mode 100644
index 0000000..e79ad24
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_foo_serialization.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/public/bindings/sample/generated/sample_foo_serialization.h"
+
+#include <string.h>
+
+#include "mojo/public/bindings/sample/generated/sample_bar_serialization.h"
+#include "mojo/public/bindings/sample/generated/sample_foo.h"
+
+namespace mojo {
+namespace internal {
+
+// static
+size_t ObjectTraits<sample::Foo>::ComputeSizeOf(
+    const sample::Foo* foo) {
+  return sizeof(*foo) +
+      mojo::internal::ComputeSizeOf(foo->bar()) +
+      mojo::internal::ComputeSizeOf(foo->data()) +
+      mojo::internal::ComputeSizeOf(foo->extra_bars()) +
+      mojo::internal::ComputeSizeOf(foo->name()) +
+      mojo::internal::ComputeSizeOf(foo->files());
+}
+
+// static
+sample::Foo* ObjectTraits<sample::Foo>::Clone(
+    const sample::Foo* foo, Buffer* buf) {
+  sample::Foo* clone = sample::Foo::New(buf);
+  memcpy(clone, foo, sizeof(*foo));
+
+  clone->set_bar(mojo::internal::Clone(foo->bar(), buf));
+  clone->set_data(mojo::internal::Clone(foo->data(), buf));
+  clone->set_extra_bars(mojo::internal::Clone(foo->extra_bars(), buf));
+  clone->set_name(mojo::internal::Clone(foo->name(), buf));
+  clone->set_files(mojo::internal::Clone(foo->files(), buf));
+
+  return clone;
+}
+
+// static
+void ObjectTraits<sample::Foo>::EncodePointersAndHandles(
+    sample::Foo* foo, std::vector<mojo::Handle>* handles) {
+  Encode(&foo->bar_, handles);
+  Encode(&foo->data_, handles);
+  Encode(&foo->extra_bars_, handles);
+  Encode(&foo->name_, handles);
+  Encode(&foo->files_, handles);
+}
+
+// static
+bool ObjectTraits<sample::Foo>::DecodePointersAndHandles(
+    sample::Foo* foo, const mojo::Message& message) {
+  if (!Decode(&foo->bar_, message))
+    return false;
+  if (!Decode(&foo->data_, message))
+    return false;
+  if (foo->_header_.num_fields >= 8) {
+    if (!Decode(&foo->extra_bars_, message))
+      return false;
+  }
+  if (foo->_header_.num_fields >= 9) {
+    if (!Decode(&foo->name_, message))
+      return false;
+  }
+  if (foo->_header_.num_fields >= 10) {
+    if (!Decode(&foo->files_, message))
+      return false;
+  }
+
+  // TODO: validate
+  return true;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/bindings/sample/generated/sample_foo_serialization.h b/mojo/public/bindings/sample/generated/sample_foo_serialization.h
new file mode 100644
index 0000000..58b7714
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_foo_serialization.h
@@ -0,0 +1,31 @@
+// Copyright 2013 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_GENERATED_BINDINGS_SAMPLE_FOO_SERIALIZATION_H_
+#define MOJO_GENERATED_BINDINGS_SAMPLE_FOO_SERIALIZATION_H_
+
+#include "mojo/public/bindings/lib/bindings_serialization.h"
+
+namespace sample {
+class Foo;
+}
+
+namespace mojo {
+namespace internal {
+
+template <>
+class ObjectTraits<sample::Foo> {
+ public:
+  static size_t ComputeSizeOf(const sample::Foo* foo);
+  static sample::Foo* Clone(const sample::Foo* foo, Buffer* buf);
+  static void EncodePointersAndHandles(sample::Foo* foo,
+                                       std::vector<mojo::Handle>* handles);
+  static bool DecodePointersAndHandles(sample::Foo* foo,
+                                       const mojo::Message& message);
+};
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_GENERATED_BINDINGS_SAMPLE_FOO_SERIALIZATION_H_
diff --git a/mojo/public/bindings/sample/generated/sample_service.h b/mojo/public/bindings/sample/generated/sample_service.h
index d73944c..0fe8466 100644
--- a/mojo/public/bindings/sample/generated/sample_service.h
+++ b/mojo/public/bindings/sample/generated/sample_service.h
@@ -8,104 +8,7 @@
 #include "mojo/public/bindings/lib/bindings.h"
 
 namespace sample {
-
-class Bar {
- public:
-  static Bar* New(mojo::Buffer* buf) {
-    return new (buf->Allocate(sizeof(Bar))) Bar();
-  }
-
-  void set_alpha(uint8_t alpha) { d_.alpha = alpha; }
-  void set_beta(uint8_t beta) { d_.beta = beta; }
-  void set_gamma(uint8_t gamma) { d_.gamma = gamma; }
-
-  uint8_t alpha() const { return d_.alpha; }
-  uint8_t beta() const { return d_.beta; }
-  uint8_t gamma() const { return d_.gamma; }
-
- private:
-  friend class mojo::internal::ObjectTraits<Bar>;
-
-  Bar() {
-    header_.num_bytes = sizeof(*this);
-    header_.num_fields = 3;
-  }
-  ~Bar();  // NOT IMPLEMENTED
-
-  mojo::internal::StructHeader header_;
-  struct Data {
-    uint8_t alpha;
-    uint8_t beta;
-    uint8_t gamma;
-  } d_;
-};
-
-class Foo {
- public:
-  static Foo* New(mojo::Buffer* buf) {
-    return new (buf->Allocate(sizeof(Foo))) Foo();
-  }
-
-  void set_x(int32_t x) { d_.x = x; }
-  void set_y(int32_t y) { d_.y = y; }
-  void set_a(bool a) { d_.a = a; }
-  void set_b(bool b) { d_.b = b; }
-  void set_c(bool c) { d_.c = c; }
-  void set_bar(Bar* bar) { d_.bar.ptr = bar; }
-  void set_data(mojo::Array<uint8_t>* data) { d_.data.ptr = data; }
-  void set_extra_bars(mojo::Array<Bar*>* extra_bars) {
-    d_.extra_bars.ptr = extra_bars;
-  }
-  void set_name(mojo::String* name) {
-    d_.name.ptr = name;
-  }
-  void set_files(mojo::Array<mojo::Handle>* files) {
-    d_.files.ptr = files;
-  }
-
-  int32_t x() const { return d_.x; }
-  int32_t y() const { return d_.y; }
-  bool a() const { return d_.a; }
-  bool b() const { return d_.b; }
-  bool c() const { return d_.c; }
-  const Bar* bar() const { return d_.bar.ptr; }
-  const mojo::Array<uint8_t>* data() const { return d_.data.ptr; }
-  const mojo::Array<Bar*>* extra_bars() const {
-    // NOTE: extra_bars is an optional field!
-    return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL;
-  }
-  const mojo::String* name() const {
-    // NOTE: name is also an optional field!
-    return header_.num_fields >= 9 ? d_.name.ptr : NULL;
-  }
-  const mojo::Array<mojo::Handle>* files() const {
-    // NOTE: files is also an optional field!
-    return header_.num_fields >= 10 ? d_.files.ptr : NULL;
-  }
-
- private:
-  friend class mojo::internal::ObjectTraits<Foo>;
-
-  Foo() {
-    header_.num_bytes = sizeof(*this);
-    header_.num_fields = 10;
-  }
-  ~Foo();  // NOT IMPLEMENTED
-
-  mojo::internal::StructHeader header_;
-  struct Data {
-    int32_t x;
-    int32_t y;
-    uint32_t a : 1;
-    uint32_t b : 1;
-    uint32_t c : 1;
-    mojo::internal::StructPointer<Bar> bar;
-    mojo::internal::ArrayPointer<uint8_t> data;
-    mojo::internal::ArrayPointer<Bar*> extra_bars;
-    mojo::internal::StringPointer name;
-    mojo::internal::ArrayPointer<mojo::Handle> files;
-  } d_;
-};
+class Foo;
 
 class Service {
  public:
diff --git a/mojo/public/bindings/sample/generated/sample_service_proxy.cc b/mojo/public/bindings/sample/generated/sample_service_proxy.cc
index 4f27203..3248c2a 100644
--- a/mojo/public/bindings/sample/generated/sample_service_proxy.cc
+++ b/mojo/public/bindings/sample/generated/sample_service_proxy.cc
@@ -19,7 +19,7 @@
 void ServiceProxy::Frobinate(const Foo* foo, bool baz, mojo::Handle port) {
   size_t payload_size =
       mojo::internal::Align(sizeof(internal::Service_Frobinate_Params));
-  payload_size += mojo::internal::ComputeAlignedSizeOf(foo);
+  payload_size += mojo::internal::ComputeSizeOf(foo);
 
   mojo::MessageBuilder builder(internal::kService_Frobinate_Name, payload_size);
 
diff --git a/mojo/public/bindings/sample/generated/sample_service_serialization.cc b/mojo/public/bindings/sample/generated/sample_service_serialization.cc
new file mode 100644
index 0000000..899f746
--- /dev/null
+++ b/mojo/public/bindings/sample/generated/sample_service_serialization.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 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/public/bindings/sample/generated/sample_service_serialization.h"
+
+namespace sample {
+namespace internal {
+
+// static
+Service_Frobinate_Params* Service_Frobinate_Params::New(mojo::Buffer* buf) {
+  return new (buf->Allocate(sizeof(Service_Frobinate_Params)))
+      Service_Frobinate_Params();
+}
+
+Service_Frobinate_Params::Service_Frobinate_Params() {
+  _header_.num_bytes = sizeof(*this);
+  _header_.num_fields = 3;
+}
+
+}  // namespace internal
+}  // namespace sample
+
+namespace mojo {
+namespace internal {
+
+// static
+void ObjectTraits<sample::internal::Service_Frobinate_Params>::
+    EncodePointersAndHandles(
+        sample::internal::Service_Frobinate_Params* params,
+        std::vector<mojo::Handle>* handles) {
+  Encode(&params->foo_, handles);
+  EncodeHandle(&params->port_, handles);
+}
+
+// static
+bool ObjectTraits<sample::internal::Service_Frobinate_Params>::
+    DecodePointersAndHandles(
+        sample::internal::Service_Frobinate_Params* params,
+        const mojo::Message& message) {
+  if (!Decode(&params->foo_, message))
+    return false;
+  if (params->_header_.num_fields >= 3) {
+    if (!DecodeHandle(&params->port_, message.handles))
+      return false;
+  }
+
+  // TODO: validate
+  return true;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/bindings/sample/generated/sample_service_serialization.h b/mojo/public/bindings/sample/generated/sample_service_serialization.h
index 849ed13..5a7044b 100644
--- a/mojo/public/bindings/sample/generated/sample_service_serialization.h
+++ b/mojo/public/bindings/sample/generated/sample_service_serialization.h
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include "mojo/public/bindings/lib/bindings_serialization.h"
+#include "mojo/public/bindings/sample/generated/sample_foo_serialization.h"
 #include "mojo/public/bindings/sample/generated/sample_service.h"
 
 namespace sample {
@@ -15,40 +16,39 @@
 
 const uint32_t kService_Frobinate_Name = 1;
 
+#pragma pack(push, 1)
+
 class Service_Frobinate_Params {
  public:
-  static Service_Frobinate_Params* New(mojo::Buffer* buf) {
-    return new (buf->Allocate(sizeof(Service_Frobinate_Params)))
-        Service_Frobinate_Params();
-  }
+  static Service_Frobinate_Params* New(mojo::Buffer* buf);
 
-  void set_foo(Foo* foo) { d_.foo.ptr = foo; }
-  void set_baz(bool baz) { d_.baz = baz; }
-  void set_port(mojo::Handle port) { d_.port = port; }
+  void set_foo(Foo* foo) { foo_.ptr = foo; }
+  void set_baz(bool baz) { baz_ = baz; }
+  void set_port(mojo::Handle port) { port_ = port; }
 
-  const Foo* foo() const { return d_.foo.ptr; }
-  bool baz() const { return d_.baz; }
+  const Foo* foo() const { return foo_.ptr; }
+  bool baz() const { return baz_; }
   mojo::Handle port() const {
     // NOTE: port is an optional field!
-    return header_.num_fields >= 3 ? d_.port : mojo::kInvalidHandle;
+    return _header_.num_fields >= 3 ? port_ : mojo::kInvalidHandle;
   }
 
  private:
   friend class mojo::internal::ObjectTraits<Service_Frobinate_Params>;
 
-  Service_Frobinate_Params() {
-    header_.num_bytes = sizeof(*this);
-    header_.num_fields = 3;
-  }
+  Service_Frobinate_Params();
   ~Service_Frobinate_Params();  // NOT IMPLEMENTED
 
-  mojo::internal::StructHeader header_;
-  struct Data {
-    mojo::internal::StructPointer<Foo> foo;
-    uint32_t baz : 1;
-    mojo::Handle port;
-  } d_;
+  mojo::internal::StructHeader _header_;
+  mojo::internal::StructPointer<Foo> foo_;
+  uint8_t baz_ : 1;
+  uint8_t _pad0_[3];
+  mojo::Handle port_;
 };
+MOJO_COMPILE_ASSERT(sizeof(Service_Frobinate_Params) == 24,
+                    bad_sizeof_Service_Frobinate_Params);
+
+#pragma pack(pop)
 
 }  // namespace internal
 }  // namespace sample
@@ -57,109 +57,14 @@
 namespace internal {
 
 template <>
-class ObjectTraits<sample::Bar> {
- public:
-  static size_t ComputeAlignedSizeOf(const sample::Bar* bar) {
-    return Align(sizeof(*bar));
-  }
-
-  static sample::Bar* Clone(const sample::Bar* bar, Buffer* buf) {
-    sample::Bar* clone = sample::Bar::New(buf);
-    memcpy(clone, bar, sizeof(*bar));
-    return clone;
-  }
-
-  static void EncodePointersAndHandles(sample::Bar* bar,
-                                       std::vector<mojo::Handle>* handles) {
-  }
-
-  static bool DecodePointersAndHandles(sample::Bar* bar,
-                                       const mojo::Message& message) {
-    return true;
-  }
-};
-
-template <>
-class ObjectTraits<sample::Foo> {
- public:
-  static size_t ComputeAlignedSizeOf(const sample::Foo* foo) {
-    return Align(sizeof(*foo)) +
-        mojo::internal::ComputeAlignedSizeOf(foo->bar()) +
-        mojo::internal::ComputeAlignedSizeOf(foo->data()) +
-        mojo::internal::ComputeAlignedSizeOf(foo->extra_bars()) +
-        mojo::internal::ComputeAlignedSizeOf(foo->name()) +
-        mojo::internal::ComputeAlignedSizeOf(foo->files());
-  }
-
-  static sample::Foo* Clone(const sample::Foo* foo, Buffer* buf) {
-    sample::Foo* clone = sample::Foo::New(buf);
-    memcpy(clone, foo, sizeof(*foo));
-
-    clone->set_bar(mojo::internal::Clone(foo->bar(), buf));
-    clone->set_data(mojo::internal::Clone(foo->data(), buf));
-    clone->set_extra_bars(mojo::internal::Clone(foo->extra_bars(), buf));
-    clone->set_name(mojo::internal::Clone(foo->name(), buf));
-    clone->set_files(mojo::internal::Clone(foo->files(), buf));
-
-    return clone;
-  }
-
-  static void EncodePointersAndHandles(sample::Foo* foo,
-                                       std::vector<mojo::Handle>* handles) {
-    Encode(&foo->d_.bar, handles);
-    Encode(&foo->d_.data, handles);
-    Encode(&foo->d_.extra_bars, handles);
-    Encode(&foo->d_.name, handles);
-    Encode(&foo->d_.files, handles);
-  }
-
-  static bool DecodePointersAndHandles(sample::Foo* foo,
-                                       const mojo::Message& message) {
-    if (!Decode(&foo->d_.bar, message))
-      return false;
-    if (!Decode(&foo->d_.data, message))
-      return false;
-    if (foo->header_.num_fields >= 8) {
-      if (!Decode(&foo->d_.extra_bars, message))
-        return false;
-    }
-    if (foo->header_.num_fields >= 9) {
-      if (!Decode(&foo->d_.name, message))
-        return false;
-    }
-    if (foo->header_.num_fields >= 10) {
-      if (!Decode(&foo->d_.files, message))
-        return false;
-    }
-
-    // TODO: validate
-    return true;
-  }
-};
-
-template <>
 class ObjectTraits<sample::internal::Service_Frobinate_Params> {
  public:
   static void EncodePointersAndHandles(
       sample::internal::Service_Frobinate_Params* params,
-      std::vector<mojo::Handle>* handles) {
-    Encode(&params->d_.foo, handles);
-    EncodeHandle(&params->d_.port, handles);
-  }
-
+      std::vector<mojo::Handle>* handles);
   static bool DecodePointersAndHandles(
       sample::internal::Service_Frobinate_Params* params,
-      const mojo::Message& message) {
-    if (!Decode(&params->d_.foo, message))
-      return false;
-    if (params->header_.num_fields >= 3) {
-      if (!DecodeHandle(&params->d_.port, message.handles))
-        return false;
-    }
-
-    // TODO: validate
-    return true;
-  }
+      const mojo::Message& message);
 };
 
 }  // namespace internal
diff --git a/mojo/public/bindings/sample/sample_service.idl b/mojo/public/bindings/sample/sample_service.idl
index ed611a4..3358a58 100644
--- a/mojo/public/bindings/sample/sample_service.idl
+++ b/mojo/public/bindings/sample/sample_service.idl
@@ -7,26 +7,27 @@
 module sample {
 
 struct Bar {
-  alpha @0 :uint8;
-  beta @1 :uint8;
-  gamma @2 :uint8;
+  uint8 alpha @0;
+  uint8 beta @1;
+  uint8 gamma @2;
 };
 
+[RequiredFields=7]
 struct Foo {
-  name @8 :string;
-  x @0 :int32;
-  y @1 :int32;
-  a @2 :bool;
-  b @3 :bool;
-  c @4 :bool;
-  bar @5 :Bar;
-  extra_bars @7 :array(Bar) [optional];
-  data @6 :array(uint8);
-  files @9 :array(handle);
+  string name @8;
+  int32 x @0;
+  int32 y @1;
+  bool a @2;
+  bool b @3;
+  bool c @4;
+  Bar bar @5;
+  Bar[] extra_bars @7;
+  uint8[] data @6;
+  handle[] files @9;
 };
 
 interface Service {
-  Frobinate @0 (foo @0 :Foo, baz @1 :bool, port @2 :handle);
+  void Frobinate(Foo foo @0, bool baz @1, handle port @2) @0;
 };
 
 }
diff --git a/mojo/public/bindings/sample/sample_service.mojom b/mojo/public/bindings/sample/sample_service.mojom
new file mode 100644
index 0000000..abbf28f
--- /dev/null
+++ b/mojo/public/bindings/sample/sample_service.mojom
@@ -0,0 +1,31 @@
+{
+  'name': 'sample',
+  'namespace': 'sample',
+  'structs': [{
+    'name': 'Bar',
+    'fields': [
+      {'name': 'alpha', 'kind': 'u8', 'ordinal': 0},
+      {'name': 'beta', 'kind': 'u8', 'ordinal': 1},
+      {'name': 'gamma', 'kind': 'u8', 'ordinal': 2}]}, {
+    'name': 'Foo',
+    'fields': [
+      {'name': 'name', 'kind': 's', 'ordinal': 8},
+      {'name': 'x', 'kind': 'i32', 'ordinal': 0},
+      {'name': 'y', 'kind': 'i32', 'ordinal': 1},
+      {'name': 'a', 'kind': 'b', 'ordinal': 2},
+      {'name': 'b', 'kind': 'b', 'ordinal': 3},
+      {'name': 'c', 'kind': 'b', 'ordinal': 4},
+      {'name': 'bar', 'kind': 'x:Bar', 'ordinal': 5},
+      {'name': 'extra_bars', 'kind': 'a:x:Bar', 'ordinal': 7},
+      {'name': 'data', 'kind': 'a:u8', 'ordinal': 6},
+      {'name': 'files', 'kind': 'a:h', 'ordinal': 9}]}],
+  'interfaces': [{
+    'name': 'Service',
+    'methods': [{
+      'name': 'Frobinate',
+      'ordinal': 0,
+      'parameters': [
+        {'name': 'foo', 'kind': 'x:Foo', 'ordinal': 0},
+        {'name': 'baz', 'kind': 'b', 'ordinal': 1},
+        {'name': 'port', 'kind': 'h', 'ordinal': 2}]}]}]
+}
diff --git a/mojo/public/bindings/sample/sample_test.cc b/mojo/public/bindings/sample/sample_test.cc
index 1f0c9a8..bad221d 100644
--- a/mojo/public/bindings/sample/sample_test.cc
+++ b/mojo/public/bindings/sample/sample_test.cc
@@ -6,6 +6,8 @@
 
 #include <string>
 
+#include "mojo/public/bindings/sample/generated/sample_bar.h"
+#include "mojo/public/bindings/sample/generated/sample_foo.h"
 #include "mojo/public/bindings/sample/generated/sample_service.h"
 #include "mojo/public/bindings/sample/generated/sample_service_proxy.h"
 #include "mojo/public/bindings/sample/generated/sample_service_stub.h"
diff --git a/mojo/public/system/macros.h b/mojo/public/system/macros.h
index 4a1c3ce..49c49f2 100644
--- a/mojo/public/system/macros.h
+++ b/mojo/public/system/macros.h
@@ -7,8 +7,6 @@
 
 #ifdef __cplusplus
 
-namespace mojo {
-
 // Annotate a virtual method indicating it must be overriding a virtual
 // method in the parent class.
 // Use like:
@@ -26,11 +24,9 @@
   void operator=(const TypeName&)
 
 // Used to assert things at compile time.
-namespace internal { template <bool> struct CompileAssert {}; }
+namespace mojo { template <bool> struct CompileAssert {}; }
 #define MOJO_COMPILE_ASSERT(expr, msg) \
-    typedef internal::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
-}  // namespace mojo
+    typedef ::mojo::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
 
 #endif  // __cplusplus
 
diff --git a/mojo/public/system/system_export.h b/mojo/public/system/system_export.h
index 8a1b1e7..8d240db 100644
--- a/mojo/public/system/system_export.h
+++ b/mojo/public/system/system_export.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/public/tests/DEPS b/mojo/public/tests/DEPS
new file mode 100644
index 0000000..318b722
--- /dev/null
+++ b/mojo/public/tests/DEPS
@@ -0,0 +1,7 @@
+# TODO(darin): Move this folder out of mojo/public/.
+include_rules = [
+  "+base",
+  "+build",
+  "+mojo",
+  "+testing",
+]
diff --git a/mojo/shell/DEPS b/mojo/shell/DEPS
new file mode 100644
index 0000000..4b4f60b
--- /dev/null
+++ b/mojo/shell/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+net",
+  "+ui/gl",
+]
diff --git a/mojo/shell/android/DEPS b/mojo/shell/android/DEPS
new file mode 100644
index 0000000..c80012b
--- /dev/null
+++ b/mojo/shell/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+jni",
+]
diff --git a/mojo/shell/android/apk/AndroidManifest.xml b/mojo/shell/android/apk/AndroidManifest.xml
new file mode 100644
index 0000000..61ca5d4
--- /dev/null
+++ b/mojo/shell/android/apk/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright 2013 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.chromium.mojo_shell_apk">
+
+    <application android:name="MojoShellApplication"
+            android:label="Mojo Shell">
+        <activity android:name="MojoShellActivity"
+                  android:launchMode="singleTask"
+                  android:theme="@android:style/Theme.Holo.Light.NoActionBar"
+                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
+                  android:hardwareAccelerated="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="18" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>
diff --git a/mojo/shell/android/apk/res/layout/mojo_shell_activity.xml b/mojo/shell/android/apk/res/layout/mojo_shell_activity.xml
new file mode 100644
index 0000000..5df9fde
--- /dev/null
+++ b/mojo/shell/android/apk/res/layout/mojo_shell_activity.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright 2013 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <org.chromium.mojo_shell_apk.MojoView
+        android:id="@+id/mojo_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/mojo/shell/android/apk/res/values/strings.xml b/mojo/shell/android/apk/res/values/strings.xml
new file mode 100644
index 0000000..ff3f8bb
--- /dev/null
+++ b/mojo/shell/android/apk/res/values/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright 2013 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.
+ -->
+
+<resources>
+</resources>
diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/LibraryLoader.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/LibraryLoader.java
new file mode 100644
index 0000000..940776b
--- /dev/null
+++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/LibraryLoader.java
@@ -0,0 +1,20 @@
+// Copyright 2013 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.mojo_shell_apk;
+
+import android.util.Log;
+
+public class LibraryLoader {
+    private static final String TAG = "LibraryLoader";
+    private static Boolean sInitialized = false;
+
+    public static void ensureInitialized() throws UnsatisfiedLinkError {
+        if (sInitialized)
+            return;
+        sInitialized = true;
+        System.loadLibrary("mojo_shell.cr");
+        Log.i(TAG, "libmojo_shell initialization success.");
+    }
+}
diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java
new file mode 100644
index 0000000..364f4d3
--- /dev/null
+++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java
@@ -0,0 +1,29 @@
+// Copyright 2013 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.mojo_shell_apk;
+
+import android.content.Context;
+
+import org.chromium.base.JNINamespace;
+
+@JNINamespace("mojo")
+public class MojoMain {
+    /**
+     * Initializes the native system.
+     **/
+    public static void init(Context context) {
+        nativeInit(context);
+    }
+
+    /**
+     * Starts the specified application in the specified context.
+     **/
+    public static void start(Context context, String appUrl) {
+        nativeStart(context, appUrl);
+    }
+
+    private static native void nativeInit(Context context);
+    private static native void nativeStart(Context context, String appUrl);
+};
diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java
new file mode 100644
index 0000000..bfb847b
--- /dev/null
+++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java
@@ -0,0 +1,45 @@
+// Copyright 2013 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.mojo_shell_apk;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import org.chromium.mojo_shell_apk.LibraryLoader;
+import org.chromium.mojo_shell_apk.MojoMain;
+import org.chromium.mojo_shell_apk.MojoView;
+
+/**
+ * Activity for managing the Mojo Shell.
+ */
+public class MojoShellActivity extends Activity {
+    private static final String TAG = "MojoShellActivity";
+
+    @Override
+    protected void onCreate(final Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        try {
+            LibraryLoader.ensureInitialized();
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "libmojo_shell initialization failed.", e);
+            finish();
+            return;
+        }
+
+        MojoMain.init(this);
+        setContentView(R.layout.mojo_shell_activity);
+
+        String appUrl = getUrlFromIntent(getIntent());
+        MojoMain.start(this, appUrl);
+        Log.i(TAG, "Mojo started: " + appUrl);
+    }
+
+    private static String getUrlFromIntent(Intent intent) {
+        return intent != null ? intent.getDataString() : null;
+    }
+}
diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellApplication.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellApplication.java
new file mode 100644
index 0000000..df927ee
--- /dev/null
+++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellApplication.java
@@ -0,0 +1,27 @@
+// Copyright 2013 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.mojo_shell_apk;
+
+import android.util.Log;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.PathUtils;
+
+public class MojoShellApplication extends BaseChromiumApplication {
+    private static final String TAG = "MojoShellApplication";
+    private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "mojo_shell";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        initializeApplicationParameters();
+    }
+
+    public static void initializeApplicationParameters() {
+        PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
+        Log.i(TAG, "MojoShellApplication.initializeApplicationParameters() success.");
+    }
+
+}
diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoView.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoView.java
new file mode 100644
index 0000000..946662d
--- /dev/null
+++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoView.java
@@ -0,0 +1,62 @@
+// Copyright 2013 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.mojo_shell_apk;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import org.chromium.base.JNINamespace;
+
+@JNINamespace("mojo")
+public class MojoView extends SurfaceView {
+
+    private int mNativeMojoView;
+    private final SurfaceHolder.Callback mSurfaceCallback;
+
+    public MojoView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mNativeMojoView = nativeInit();
+        assert mNativeMojoView != 0;
+
+        mSurfaceCallback = new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                assert mNativeMojoView != 0;
+                nativeSurfaceSetSize(mNativeMojoView, width, height);
+            }
+
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                assert mNativeMojoView != 0;
+                nativeSurfaceCreated(mNativeMojoView, holder.getSurface());
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                assert mNativeMojoView != 0;
+                nativeSurfaceDestroyed(mNativeMojoView);
+            }
+        };
+        getHolder().addCallback(mSurfaceCallback);
+
+    }
+
+    // TODO(abarth): Someone needs to call destroy at some point.
+    public void destroy() {
+        getHolder().removeCallback(mSurfaceCallback);
+        nativeDestroy(mNativeMojoView);
+        mNativeMojoView = 0;
+    }
+
+    private static native int nativeInit();
+    private static native void nativeDestroy(int nativeMojoView);
+    private static native void nativeSurfaceCreated(int nativeMojoView, Surface surface);
+    private static native void nativeSurfaceDestroyed(int nativeMojoView);
+    private static native void nativeSurfaceSetSize(int nativeMojoView, int width, int height);
+};
diff --git a/mojo/shell/android/library_loader.cc b/mojo/shell/android/library_loader.cc
new file mode 100644
index 0000000..4bb8f30
--- /dev/null
+++ b/mojo/shell/android/library_loader.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 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/android/base_jni_registrar.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/logging.h"
+#include "mojo/shell/android/mojo_main.h"
+#include "mojo/shell/android/mojo_view.h"
+#include "net/android/net_jni_registrar.h"
+
+namespace {
+
+base::android::RegistrationMethod kMojoRegisteredMethods[] = {
+  { "MojoMain", mojo::RegisterMojoMain },
+  { "MojoView", mojo::MojoView::Register },
+};
+
+bool RegisterMojoJni(JNIEnv* env) {
+  return RegisterNativeMethods(env, kMojoRegisteredMethods,
+                               arraysize(kMojoRegisteredMethods));
+}
+
+}  // namespace
+
+// This is called by the VM when the shared library is first loaded.
+JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+  base::android::InitVM(vm);
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  if (!base::android::RegisterJni(env))
+    return -1;
+
+  if (!net::android::RegisterJni(env))
+    return -1;
+
+  if (!RegisterMojoJni(env))
+    return -1;
+
+  return JNI_VERSION_1_4;
+}
diff --git a/mojo/shell/android/mojo_main.cc b/mojo/shell/android/mojo_main.cc
new file mode 100644
index 0000000..4b57fd8
--- /dev/null
+++ b/mojo/shell/android/mojo_main.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 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/android/mojo_main.h"
+
+#include "base/android/jni_string.h"
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread.h"
+#include "jni/MojoMain_jni.h"
+#include "mojo/shell/run.h"
+#include "ui/gl/gl_surface_egl.h"
+
+using base::LazyInstance;
+
+namespace mojo {
+
+namespace {
+
+base::AtExitManager* g_at_exit = 0;
+
+LazyInstance<scoped_ptr<base::Thread> > g_shell_thread =
+    LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<scoped_ptr<shell::Context> > g_context =
+    LAZY_INSTANCE_INITIALIZER;
+
+void InitializeLogging() {
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  settings.dcheck_state =
+      logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+  logging::InitLogging(settings);
+  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+  logging::SetLogItems(false,    // Process ID
+                       false,    // Thread ID
+                       false,    // Timestamp
+                       false);   // Tick count
+}
+
+void StartOnShellThread() {
+  g_context.Get().reset(new shell::Context());
+  shell::Run(g_context.Get().get());
+}
+
+}  // namspace
+
+static void Init(JNIEnv* env, jclass clazz, jobject context) {
+  base::android::ScopedJavaLocalRef<jobject> scoped_context(env, context);
+
+  base::android::InitApplicationContext(scoped_context);
+
+  if (g_at_exit)
+    return;
+  g_at_exit = new base::AtExitManager();
+  // TODO(abarth): Currently we leak g_at_exit.
+
+  CommandLine::Init(0, 0);
+  InitializeLogging();
+
+  // TODO(abarth): At which point should we switch to cross-platform
+  // initialization?
+
+  gfx::GLSurface::InitializeOneOff();
+}
+
+static void Start(JNIEnv* env, jclass clazz, jobject context, jstring jurl) {
+  if (jurl) {
+    std::string app_url = base::android::ConvertJavaStringToUTF8(env, jurl);
+    std::vector<std::string> argv;
+    argv.push_back("mojo_shell");
+    argv.push_back("--app=" + app_url);
+    CommandLine::ForCurrentProcess()->InitFromArgv(argv);
+  }
+
+  g_shell_thread.Get().reset(new base::Thread("shell_thread"));
+  g_shell_thread.Get()->Start();
+  g_shell_thread.Get()->message_loop()->PostTask(FROM_HERE,
+      base::Bind(StartOnShellThread));
+
+  // TODO(abarth): Currently we leak g_shell_thread.
+}
+
+bool RegisterMojoMain(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace mojo
diff --git a/mojo/shell/android/mojo_main.h b/mojo/shell/android/mojo_main.h
new file mode 100644
index 0000000..161ca71
--- /dev/null
+++ b/mojo/shell/android/mojo_main.h
@@ -0,0 +1,16 @@
+// Copyright 2013 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_ANDROID_MOJO_MAIN_H_
+#define MOJO_SHELL_ANDROID_MOJO_MAIN_H_
+
+#include <jni.h>
+
+namespace mojo {
+
+bool RegisterMojoMain(JNIEnv* env);
+
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_ANDROID_MOJO_MAIN_H_
diff --git a/mojo/shell/android/mojo_view.cc b/mojo/shell/android/mojo_view.cc
new file mode 100644
index 0000000..3ffcfef
--- /dev/null
+++ b/mojo/shell/android/mojo_view.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 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/android/mojo_view.h"
+
+#include <android/native_window_jni.h>
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "jni/MojoView_jni.h"
+
+namespace mojo {
+
+static jint Init(JNIEnv* env, jclass obj) {
+  MojoView* mojo_view = new MojoView(env, obj);
+  return reinterpret_cast<jint>(mojo_view);
+}
+
+MojoView::MojoView(JNIEnv* env, jobject obj) {
+}
+
+MojoView::~MojoView() {
+}
+
+void MojoView::Destroy(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+void MojoView::SurfaceCreated(JNIEnv* env, jobject obj, jobject jsurface) {
+  base::android::ScopedJavaLocalRef<jobject> protector(env, jsurface);
+  DCHECK(jsurface);
+  window_ = ANativeWindow_fromSurface(env, jsurface);
+  DCHECK(window_);
+
+  scoped_refptr<gfx::GLSurface> surface =
+      new gfx::NativeViewGLSurfaceEGL(window_);
+  CHECK(surface->Initialize());
+}
+
+void MojoView::SurfaceDestroyed(JNIEnv* env, jobject obj) {
+  DCHECK(window_);
+  ANativeWindow_release(window_);
+  window_ = NULL;
+}
+
+void MojoView::SurfaceSetSize(
+    JNIEnv* env, jobject obj, jint width, jint height) {
+}
+
+bool MojoView::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace mojo
diff --git a/mojo/shell/android/mojo_view.h b/mojo/shell/android/mojo_view.h
new file mode 100644
index 0000000..0d90dd6
--- /dev/null
+++ b/mojo/shell/android/mojo_view.h
@@ -0,0 +1,39 @@
+// Copyright 2013 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_ANDROID_MOJO_VIEW_H_
+#define MOJO_SHELL_ANDROID_MOJO_VIEW_H_
+
+#include "base/android/jni_helper.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "ui/gl/gl_surface_egl.h"
+
+struct ANativeWindow;
+
+namespace mojo {
+
+class MojoView {
+ public:
+  static bool Register(JNIEnv* env);
+
+  MojoView(JNIEnv* env, jobject obj);
+
+  void Destroy(JNIEnv* env, jobject obj);
+  void SurfaceCreated(JNIEnv* env, jobject obj, jobject jsurface);
+  void SurfaceDestroyed(JNIEnv* env, jobject obj);
+  void SurfaceSetSize(JNIEnv* env, jobject obj, jint width, jint height);
+
+ private:
+  ~MojoView();
+
+  ANativeWindow* window_;
+  scoped_refptr<gfx::GLSurface> surface_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoView);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_ANDROID_MOJO_VIEW_H_
diff --git a/mojo/shell/app_container.cc b/mojo/shell/app_container.cc
index 2c46400..0227e78 100644
--- a/mojo/shell/app_container.cc
+++ b/mojo/shell/app_container.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
@@ -12,6 +12,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "mojo/public/system/core.h"
+#include "mojo/shell/context.h"
 
 typedef MojoResult (*MojoMainFunction)(mojo::Handle pipe);
 
@@ -44,19 +45,26 @@
     goto completed;
   }
 
+  LOG(INFO) << "MojoMain succeeded: " << result;
+
 completed:
   base::UnloadNativeLibrary(app_library);
   base::DeleteFile(app_path, false);
   Close(app_handle);
 }
 
-AppContainer::AppContainer()
-    : weak_factory_(this) {
+AppContainer::AppContainer(Context* context)
+    : context_(context)
+    , weak_factory_(this) {
 }
 
 AppContainer::~AppContainer() {
 }
 
+void AppContainer::Load(const GURL& app_url) {
+  request_ = context_->loader()->Load(app_url, this);
+}
+
 void AppContainer::DidCompleteLoad(const GURL& app_url,
                                    const base::FilePath& app_path) {
   Handle app_handle;
@@ -83,7 +91,6 @@
   }
 }
 
-
 void AppContainer::AppCompleted() {
   thread_.reset();
   Close(shell_handle_);
diff --git a/mojo/shell/app_container.h b/mojo/shell/app_container.h
index b3d3830..a2691e8 100644
--- a/mojo/shell/app_container.h
+++ b/mojo/shell/app_container.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
@@ -8,8 +8,8 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "mojo/loader/job.h"
 #include "mojo/public/system/core.h"
+#include "mojo/shell/loader.h"
 
 namespace base {
 class FilePath;
@@ -19,19 +19,25 @@
 namespace mojo {
 namespace shell {
 
+class Context;
+
 // A container class that runs an app on its own thread.
-class AppContainer : public loader::Job::Delegate {
+class AppContainer : public Loader::Delegate {
  public:
-  AppContainer();
+  explicit AppContainer(Context* context);
   virtual ~AppContainer();
 
+  void Load(const GURL& app_url);
+
  private:
-  // From loader::Job::Delegate
+  // From Loader::Delegate
   virtual void DidCompleteLoad(const GURL& app_url,
                                const base::FilePath& app_path) OVERRIDE;
 
   void AppCompleted();
 
+  Context* context_;
+  scoped_ptr<Loader::Job> request_;
   scoped_ptr<base::Thread> thread_;
 
   // Following members are valid only on app thread.
diff --git a/mojo/shell/context.cc b/mojo/shell/context.cc
new file mode 100644
index 0000000..c2e2f90
--- /dev/null
+++ b/mojo/shell/context.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 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/context.h"
+
+#include "mojo/shell/network_delegate.h"
+#include "mojo/system/core_impl.h"
+
+namespace mojo {
+namespace shell {
+
+Context::Context()
+    : task_runners_(base::MessageLoop::current()->message_loop_proxy()),
+      storage_(),
+      loader_(task_runners_.io_runner(),
+              task_runners_.file_runner(),
+              scoped_ptr<net::NetworkDelegate>(new NetworkDelegate()),
+              storage_.profile_path()) {
+  system::CoreImpl::Init();
+}
+
+Context::~Context() {
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/context.h b/mojo/shell/context.h
new file mode 100644
index 0000000..30a955e
--- /dev/null
+++ b/mojo/shell/context.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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_CONTEXT_H_
+#define MOJO_SHELL_CONTEXT_H_
+
+#include "mojo/shell/loader.h"
+#include "mojo/shell/storage.h"
+#include "mojo/shell/task_runners.h"
+
+namespace mojo {
+namespace shell {
+
+class Context {
+ public:
+  Context();
+  ~Context();
+
+  TaskRunners* task_runners() { return &task_runners_; }
+  Storage* storage() { return &storage_; }
+  Loader* loader() { return &loader_; }
+
+ private:
+  TaskRunners task_runners_;
+  Storage storage_;
+  Loader loader_;
+
+  DISALLOW_COPY_AND_ASSIGN(Context);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_CONTEXT_H_
diff --git a/mojo/shell/desktop/mojo_main.cc b/mojo/shell/desktop/mojo_main.cc
new file mode 100644
index 0000000..bf1f973
--- /dev/null
+++ b/mojo/shell/desktop/mojo_main.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 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/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/shell/run.h"
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+  CommandLine::Init(argc, argv);
+
+  base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+  mojo::shell::Context context;
+
+  message_loop.PostTask(FROM_HERE, base::Bind(mojo::shell::Run,
+                                              &context));
+  message_loop.Run();
+
+  return 0;
+}
diff --git a/mojo/shell/loader.cc b/mojo/shell/loader.cc
new file mode 100644
index 0000000..7b73c7d
--- /dev/null
+++ b/mojo/shell/loader.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 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/loader.h"
+
+#include "base/message_loop/message_loop.h"
+#include "net/base/network_delegate.h"
+
+namespace mojo {
+namespace shell {
+
+namespace {
+
+scoped_ptr<base::Thread> CreateIOThread(const char* name) {
+  scoped_ptr<base::Thread> thread(new base::Thread(name));
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_IO;
+  thread->StartWithOptions(options);
+  return thread.Pass();
+}
+
+}  // namespace
+
+Loader::Delegate::~Delegate() {
+}
+
+Loader::Job::Job(const GURL& app_url, Delegate* delegate)
+    : delegate_(delegate) {
+  fetcher_.reset(net::URLFetcher::Create(app_url, net::URLFetcher::GET, this));
+}
+
+Loader::Job::~Job() {
+}
+
+void Loader::Job::OnURLFetchComplete(const net::URLFetcher* source) {
+  base::FilePath app_path;
+  source->GetResponseAsFilePath(true, &app_path);
+  delegate_->DidCompleteLoad(source->GetURL(), app_path);
+}
+
+Loader::Loader(base::SingleThreadTaskRunner* network_runner,
+               base::SingleThreadTaskRunner* file_runner,
+               scoped_ptr<net::NetworkDelegate> network_delegate,
+               base::FilePath base_path)
+    : file_runner_(file_runner),
+      cache_thread_(CreateIOThread("cache_thread")),
+      url_request_context_getter_(new URLRequestContextGetter(
+          base_path,
+          network_runner,
+          file_runner,
+          cache_thread_->message_loop_proxy(),
+          network_delegate.Pass())) {
+}
+
+Loader::~Loader() {
+}
+
+scoped_ptr<Loader::Job> Loader::Load(const GURL& app_url, Delegate* delegate) {
+  scoped_ptr<Job> job(new Job(app_url, delegate));
+  job->fetcher_->SetRequestContext(url_request_context_getter_.get());
+  job->fetcher_->SaveResponseToTemporaryFile(file_runner_.get());
+  job->fetcher_->Start();
+  return job.Pass();
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/loader.h b/mojo/shell/loader.h
new file mode 100644
index 0000000..ea77079
--- /dev/null
+++ b/mojo/shell/loader.h
@@ -0,0 +1,72 @@
+// Copyright 2013 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_LOADER_H_
+#define MOJO_SHELL_LOADER_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "mojo/shell/url_request_context_getter.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
+
+namespace net {
+class NetworkDelegate;
+}
+
+namespace mojo {
+namespace shell {
+
+class Loader {
+ public:
+  class Delegate {
+   public:
+    virtual void DidCompleteLoad(const GURL& app_url,
+                                 const base::FilePath& app_path) = 0;
+
+   protected:
+    virtual ~Delegate();
+  };
+
+  class Job : public net::URLFetcherDelegate {
+   public:
+    // You can cancel a job by deleting it.
+    virtual ~Job();
+
+   private:
+    friend class Loader;
+
+    // You can create a job using Loader::Load.
+    Job(const GURL& app_url, Delegate* delegate);
+    virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+    scoped_ptr<net::URLFetcher> fetcher_;
+    Delegate* delegate_;
+
+    DISALLOW_COPY_AND_ASSIGN(Job);
+  };
+
+  Loader(base::SingleThreadTaskRunner* network_runner,
+         base::SingleThreadTaskRunner* file_runner,
+         scoped_ptr<net::NetworkDelegate> network_delegate,
+         base::FilePath base_path);
+  ~Loader();
+
+  scoped_ptr<Job> Load(const GURL& app_url, Delegate* delegate);
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> file_runner_;
+  scoped_ptr<base::Thread> cache_thread_;
+  scoped_refptr<URLRequestContextGetter> url_request_context_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(Loader);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_LOADER_H_
diff --git a/mojo/shell/network_delegate.cc b/mojo/shell/network_delegate.cc
new file mode 100644
index 0000000..e27d1ad
--- /dev/null
+++ b/mojo/shell/network_delegate.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 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/network_delegate.h"
+
+#include "base/command_line.h"
+#include "mojo/shell/switches.h"
+#include "net/url_request/url_request.h"
+
+namespace mojo {
+namespace shell {
+
+NetworkDelegate::NetworkDelegate() {
+  DetachFromThread();
+}
+
+bool NetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
+                                      const base::FilePath& path) const {
+  // TODO(aa): We might want to add a --allow-file-urls or something, but
+  // starting conservative.
+  return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kApp)
+      == request.url().spec();
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/network_delegate.h b/mojo/shell/network_delegate.h
new file mode 100644
index 0000000..2110343
--- /dev/null
+++ b/mojo/shell/network_delegate.h
@@ -0,0 +1,24 @@
+// Copyright 2013 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_NETWORK_DELEGATE_H_
+#define MOJO_SHELL_NETWORK_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "net/base/network_delegate.h"
+
+namespace mojo {
+namespace shell {
+
+class NetworkDelegate : public net::NetworkDelegate {
+ public:
+  NetworkDelegate();
+  virtual bool OnCanAccessFile(const net::URLRequest& request,
+                               const base::FilePath& path) const OVERRIDE;
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_MOJO_NETWORK_DELEGATE_H_
diff --git a/mojo/shell/run.cc b/mojo/shell/run.cc
new file mode 100644
index 0000000..a7c3f33
--- /dev/null
+++ b/mojo/shell/run.cc
@@ -0,0 +1,31 @@
+// Copyright 2013 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/run.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/shell/app_container.h"
+#include "mojo/shell/switches.h"
+#include "url/gurl.h"
+
+namespace mojo {
+namespace shell {
+
+void Run(Context* context) {
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (!command_line.HasSwitch(switches::kApp)) {
+    LOG(ERROR) << "No app path specified.";
+    base::MessageLoop::current()->Quit();
+    return;
+  }
+
+  AppContainer* container = new AppContainer(context);
+  container->Load(GURL(command_line.GetSwitchValueASCII(switches::kApp)));
+  // TODO(abarth): Currently we leak |container|.
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/run.h b/mojo/shell/run.h
new file mode 100644
index 0000000..d554ffd
--- /dev/null
+++ b/mojo/shell/run.h
@@ -0,0 +1,18 @@
+// Copyright 2013 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_RUN_H_
+#define MOJO_SHELL_RUN_H_
+
+#include "mojo/shell/context.h"
+
+namespace mojo {
+namespace shell {
+
+void Run(Context* context);
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_RUN_H_
diff --git a/mojo/shell/sample_app.cc b/mojo/shell/sample_app.cc
deleted file mode 100644
index a3acbe3..0000000
--- a/mojo/shell/sample_app.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2013 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 <stdio.h>
-
-#include "base/basictypes.h"
-#include "mojo/public/system/core.h"
-#include "mojo/system/core_impl.h"
-
-#if defined(OS_WIN)
-#if !defined(CDECL)
-#define CDECL __cdecl
-#endif
-#define SAMPLE_APP_EXPORT __declspec(dllexport)
-#else
-#define CDECL
-#define SAMPLE_APP_EXPORT __attribute__((visibility("default")))
-#endif
-
-char* ReadStringFromPipe(mojo::Handle pipe) {
-  uint32_t len = 0;
-  char* buf = NULL;
-  MojoResult result = mojo::ReadMessage(pipe, buf, &len, NULL, NULL,
-                                        MOJO_READ_MESSAGE_FLAG_NONE);
-  if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
-    buf = new char[len];
-    result = mojo::ReadMessage(pipe, buf, &len, NULL, NULL,
-                               MOJO_READ_MESSAGE_FLAG_NONE);
-  }
-  if (result < MOJO_RESULT_OK) {
-    // Failure..
-    if (buf)
-      delete[] buf;
-    return NULL;
-  }
-  return buf;
-}
-
-class SampleMessageWaiter {
- public:
-  explicit SampleMessageWaiter(mojo::Handle pipe) : pipe_(pipe) {}
-  ~SampleMessageWaiter() {}
-
-  void Read() {
-    char* string = ReadStringFromPipe(pipe_);
-    if (string) {
-      printf("Read string from pipe: %s\n", string);
-      delete[] string;
-      string = NULL;
-    }
-  }
-
-  void WaitAndRead() {
-    MojoResult result = mojo::Wait(pipe_, MOJO_WAIT_FLAG_READABLE, 100);
-    if (result < MOJO_RESULT_OK) {
-      // Failure...
-    }
-
-    Read();
-  }
-
- private:
-
-  mojo::Handle pipe_;
-  DISALLOW_COPY_AND_ASSIGN(SampleMessageWaiter);
-};
-
-extern "C" SAMPLE_APP_EXPORT MojoResult CDECL MojoMain(
-    mojo::Handle pipe) {
-  SampleMessageWaiter(pipe).WaitAndRead();
-  return MOJO_RESULT_OK;
-}
diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc
deleted file mode 100644
index 69d13e9..0000000
--- a/mojo/shell/shell.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 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/at_exit.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "mojo/loader/loader.h"
-#include "mojo/shell/app_container.h"
-#include "mojo/shell/storage.h"
-#include "mojo/shell/switches.h"
-#include "mojo/shell/task_runners.h"
-#include "mojo/system/core_impl.h"
-#include "url/gurl.h"
-
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit;
-  CommandLine::Init(argc, argv);
-
-  mojo::system::CoreImpl::Init();
-
-  base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
-
-  // TODO(abarth): Group these objects into a "context" object.
-  mojo::shell::TaskRunners task_runners(message_loop.message_loop_proxy());
-  mojo::shell::Storage storage;
-
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (!command_line.HasSwitch(switches::kApp)) {
-    LOG(ERROR) << "No app path specified.";
-    return 0;
-  }
-
-  mojo::loader::Loader loader(task_runners.io_runner(),
-                              task_runners.file_runner(),
-                              storage.profile_path());
-
-  scoped_ptr<mojo::shell::AppContainer> container(
-      new mojo::shell::AppContainer);
-
-  scoped_ptr<mojo::loader::Job> job = loader.Load(
-    GURL(command_line.GetSwitchValueASCII(switches::kApp)),
-    container.get());
-
-  message_loop.Run();
-  return 0;
-}
diff --git a/mojo/shell/storage.cc b/mojo/shell/storage.cc
index dc1b83e..5dbaefb 100644
--- a/mojo/shell/storage.cc
+++ b/mojo/shell/storage.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/storage.h b/mojo/shell/storage.h
index 62cb0a2..08c1ea2 100644
--- a/mojo/shell/storage.h
+++ b/mojo/shell/storage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/switches.cc b/mojo/shell/switches.cc
index 0d3883d..00356ee 100644
--- a/mojo/shell/switches.cc
+++ b/mojo/shell/switches.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/switches.h b/mojo/shell/switches.h
index da0b345..2d633f1 100644
--- a/mojo/shell/switches.h
+++ b/mojo/shell/switches.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/task_runners.cc b/mojo/shell/task_runners.cc
index a75f3d3..ea87a73 100644
--- a/mojo/shell/task_runners.cc
+++ b/mojo/shell/task_runners.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/task_runners.h b/mojo/shell/task_runners.h
index 164310b..a7c4c99 100644
--- a/mojo/shell/task_runners.h
+++ b/mojo/shell/task_runners.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
 
diff --git a/mojo/shell/url_request_context_getter.cc b/mojo/shell/url_request_context_getter.cc
new file mode 100644
index 0000000..1d01c5e
--- /dev/null
+++ b/mojo/shell/url_request_context_getter.cc
@@ -0,0 +1,102 @@
+// Copyright 2013 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/url_request_context_getter.h"
+
+#include "net/cookies/cookie_monster.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/proxy/proxy_service.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/url_request/file_protocol_handler.h"
+#include "net/url_request/static_http_user_agent_settings.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+
+namespace mojo {
+namespace shell {
+
+URLRequestContextGetter::URLRequestContextGetter(
+    base::FilePath base_path,
+    base::SingleThreadTaskRunner* network_task_runner,
+    base::SingleThreadTaskRunner* file_task_runner,
+    base::MessageLoopProxy* cache_task_runner,
+    scoped_ptr<net::NetworkDelegate> network_delegate)
+    : base_path_(base_path),
+      file_task_runner_(file_task_runner),
+      network_task_runner_(network_task_runner),
+      cache_task_runner_(cache_task_runner),
+      network_delegate_(network_delegate.Pass()),
+      net_log_(new net::NetLog()) {
+}
+
+URLRequestContextGetter::~URLRequestContextGetter() {
+}
+
+net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
+  if (!url_request_context_) {
+    url_request_context_.reset(new net::URLRequestContext());
+    url_request_context_->set_net_log(net_log_.get());
+    url_request_context_->set_network_delegate(network_delegate_.get());
+
+    storage_.reset(
+        new net::URLRequestContextStorage(url_request_context_.get()));
+
+    storage_->set_cookie_store(new net::CookieMonster(NULL, NULL));
+    storage_->set_http_user_agent_settings(
+        new net::StaticHttpUserAgentSettings("en-us,en", "Mojo/0.1"));
+
+    storage_->set_proxy_service(net::ProxyService::CreateDirect());
+    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
+    storage_->set_http_server_properties(
+        scoped_ptr<net::HttpServerProperties>(
+            new net::HttpServerPropertiesImpl()));
+    storage_->set_host_resolver(net::HostResolver::CreateDefaultResolver(
+        url_request_context_->net_log()));
+
+    net::HttpNetworkSession::Params network_session_params;
+    network_session_params.net_log =
+        url_request_context_->net_log();
+    network_session_params.proxy_service =
+        url_request_context_->proxy_service();
+    network_session_params.ssl_config_service =
+        url_request_context_->ssl_config_service();
+    network_session_params.http_server_properties =
+        url_request_context_->http_server_properties();
+    network_session_params.host_resolver =
+        url_request_context_->host_resolver();
+
+    base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
+
+    net::HttpCache::DefaultBackend* main_backend =
+        new net::HttpCache::DefaultBackend(
+            net::DISK_CACHE,
+            net::CACHE_BACKEND_DEFAULT,
+            cache_path,
+            0,
+            cache_task_runner_.get());
+
+    net::HttpCache* main_cache = new net::HttpCache(
+        network_session_params, main_backend);
+    storage_->set_http_transaction_factory(main_cache);
+
+    scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
+        new net::URLRequestJobFactoryImpl());
+    job_factory->SetProtocolHandler(
+        "file",
+        new net::FileProtocolHandler(file_task_runner_));
+    storage_->set_job_factory(job_factory.release());
+  }
+
+  return url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+URLRequestContextGetter::GetNetworkTaskRunner() const {
+  return network_task_runner_;
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/url_request_context_getter.h b/mojo/shell/url_request_context_getter.h
new file mode 100644
index 0000000..cc9125d
--- /dev/null
+++ b/mojo/shell/url_request_context_getter.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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_URL_REQUEST_CONTEXT_GETTER_H_
+#define MOJO_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "net/base/network_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_context_storage.h"
+
+namespace mojo {
+namespace shell {
+
+class URLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+  URLRequestContextGetter(
+      base::FilePath base_path,
+      base::SingleThreadTaskRunner* network_task_runner,
+      base::SingleThreadTaskRunner* file_task_runner,
+      base::MessageLoopProxy* cache_task_runner,
+      scoped_ptr<net::NetworkDelegate> network_delegate);
+
+  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
+  virtual scoped_refptr<base::SingleThreadTaskRunner>
+      GetNetworkTaskRunner() const OVERRIDE;
+
+ protected:
+  virtual ~URLRequestContextGetter();
+
+ private:
+  base::FilePath base_path_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
+  scoped_refptr<base::MessageLoopProxy> cache_task_runner_;
+  scoped_ptr<net::NetworkDelegate> network_delegate_;
+  scoped_ptr<net::NetLog> net_log_;
+  scoped_ptr<net::URLRequestContextStorage> storage_;
+  scoped_ptr<net::URLRequestContext> url_request_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/mojo/system/raw_channel_posix_unittest.cc b/mojo/system/raw_channel_posix_unittest.cc
index 94d9943..16ebcf0 100644
--- a/mojo/system/raw_channel_posix_unittest.cc
+++ b/mojo/system/raw_channel_posix_unittest.cc
@@ -34,29 +34,13 @@
 #include "base/time/time.h"
 #include "mojo/system/message_in_transit.h"
 #include "mojo/system/platform_channel_handle.h"
+#include "mojo/system/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
 namespace system {
 namespace {
 
-void PostTaskAndWaitHelper(base::WaitableEvent* event,
-                           const base::Closure& task) {
-  task.Run();
-  event->Signal();
-}
-
-void PostTaskAndWait(base::MessageLoop* message_loop,
-                     const tracked_objects::Location& from_here,
-                     const base::Closure& task) {
-  base::WaitableEvent event(false, false);
-  message_loop->PostTask(from_here,
-                         base::Bind(&PostTaskAndWaitHelper, &event, task));
-  event.Wait();
-}
-
-// -----------------------------------------------------------------------------
-
 MessageInTransit* MakeTestMessage(uint32_t num_bytes) {
   std::vector<unsigned char> bytes(num_bytes, 0);
   for (size_t i = 0; i < num_bytes; i++)
@@ -110,7 +94,13 @@
   int fd(size_t i) { return fds_[i]; }
   void clear_fd(size_t i) { fds_[i] = -1; }
 
-  base::MessageLoop* message_loop() { return io_thread_.message_loop(); }
+  base::MessageLoop* io_thread_message_loop() {
+    return io_thread_.message_loop();
+  }
+
+  scoped_refptr<base::TaskRunner> io_thread_task_runner() {
+    return io_thread_message_loop()->message_loop_proxy();
+  }
 
  private:
   base::Thread io_thread_;
@@ -212,15 +202,16 @@
   WriteOnlyRawChannelDelegate delegate;
   scoped_ptr<RawChannel> rc(RawChannel::Create(PlatformChannelHandle(fd(0)),
                                                &delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(0);
 
   TestMessageReaderAndChecker checker(fd(1));
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init, base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(rc.get())));
 
   // Write and read, for a variety of sizes.
   for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) {
@@ -234,10 +225,10 @@
   for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1)
     EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size;
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(rc.get())));
 }
 
 // RawChannelPosixTest.OnReadMessage -------------------------------------------
@@ -307,13 +298,14 @@
   ReadCheckerRawChannelDelegate delegate;
   scoped_ptr<RawChannel> rc(RawChannel::Create(PlatformChannelHandle(fd(0)),
                                                &delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(0);
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init, base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(rc.get())));
 
   // Write and read, for a variety of sizes.
   for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) {
@@ -339,10 +331,10 @@
   }
   delegate.Wait();
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(rc.get())));
 }
 
 // RawChannelPosixTest.WriteMessageAndOnReadMessage ----------------------------
@@ -418,28 +410,28 @@
   scoped_ptr<RawChannel> writer_rc(
       RawChannel::Create(PlatformChannelHandle(fd(0)),
                                                &writer_delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(0);
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init,
-                             base::Unretained(writer_rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(writer_rc.get())));
 
   ReadCountdownRawChannelDelegate reader_delegate(
       kNumWriterThreads * kNumWriteMessagesPerThread);
   scoped_ptr<RawChannel> reader_rc(
       RawChannel::Create(PlatformChannelHandle(fd(1)),
                                                &reader_delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(1);
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init,
-                             base::Unretained(reader_rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(reader_rc.get())));
 
   {
     ScopedVector<RawChannelWriterThread> writer_threads;
@@ -458,15 +450,15 @@
   // Wait for reading to finish.
   reader_delegate.Wait();
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(reader_rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(reader_rc.get())));
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(writer_rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(writer_rc.get())));
 }
 
 // RawChannelPosixTest.OnFatalError --------------------------------------------
@@ -512,13 +504,14 @@
   FatalErrorRecordingRawChannelDelegate delegate;
   scoped_ptr<RawChannel> rc(RawChannel::Create(PlatformChannelHandle(fd(0)),
                                                &delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(0);
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init, base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(rc.get())));
 
   // Close the other end, which should make writing fail.
   CHECK_EQ(close(fd(1)), 0);
@@ -531,10 +524,10 @@
   EXPECT_EQ(RawChannel::Delegate::FATAL_ERROR_FAILED_WRITE,
             delegate.WaitForFatalError());
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(rc.get())));
 
 }
 
@@ -546,17 +539,18 @@
   WriteOnlyRawChannelDelegate delegate;
   scoped_ptr<RawChannel> rc(RawChannel::Create(PlatformChannelHandle(fd(0)),
                                                &delegate,
-                                               message_loop()));
+                                               io_thread_message_loop()));
   // |RawChannel::Create()| takes ownership of the FD.
   clear_fd(0);
 
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Init, base::Unretained(rc.get())));
-  PostTaskAndWait(message_loop(),
-                  FROM_HERE,
-                  base::Bind(&RawChannel::Shutdown,
-                             base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Init,
+                                   base::Unretained(rc.get())));
+  test::PostTaskAndWait(io_thread_task_runner(),
+                        FROM_HERE,
+                        base::Bind(&RawChannel::Shutdown,
+                                   base::Unretained(rc.get())));
 
   EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1)));
 }
diff --git a/mojo/system/test_utils.cc b/mojo/system/test_utils.cc
new file mode 100644
index 0000000..5c120a8
--- /dev/null
+++ b/mojo/system/test_utils.cc
@@ -0,0 +1,36 @@
+// Copyright 2013 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/system/test_utils.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace mojo {
+namespace system {
+namespace test {
+
+namespace {
+
+void PostTaskAndWaitHelper(base::WaitableEvent* event,
+                           const base::Closure& task) {
+  task.Run();
+  event->Signal();
+}
+
+}  // namespace
+
+void PostTaskAndWait(scoped_refptr<base::TaskRunner> task_runner,
+                     const tracked_objects::Location& from_here,
+                     const base::Closure& task) {
+  base::WaitableEvent event(false, false);
+  task_runner->PostTask(from_here,
+                        base::Bind(&PostTaskAndWaitHelper, &event, task));
+  event.Wait();
+}
+
+}  // namespace test
+}  // namespace system
+}  // namespace mojo
diff --git a/mojo/system/test_utils.h b/mojo/system/test_utils.h
index 2f1e956..d40490f 100644
--- a/mojo/system/test_utils.h
+++ b/mojo/system/test_utils.h
@@ -5,9 +5,18 @@
 #ifndef MOJO_SYSTEM_TEST_UTILS_H_
 #define MOJO_SYSTEM_TEST_UTILS_H_
 
+#include <stdint.h>
+
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
 #include "base/time/time.h"
 
+namespace tracked_objects {
+class Location;
+}
+
 namespace mojo {
 namespace system {
 namespace test {
@@ -31,6 +40,13 @@
   DISALLOW_COPY_AND_ASSIGN(Stopwatch);
 };
 
+// Posts the given task (to the given task runner) and waits for it to complete.
+// (Note: Doesn't spin the current thread's message loop, so if you're careless
+// this could easily deadlock.)
+void PostTaskAndWait(scoped_refptr<base::TaskRunner> task_runner,
+                     const tracked_objects::Location& from_here,
+                     const base::Closure& task);
+
 }  // namespace test
 }  // namespace system
 }  // namespace mojo
diff --git a/native_client_sdk/src/build_tools/build_app.py b/native_client_sdk/src/build_tools/build_app.py
index cf16f88..577fd97 100755
--- a/native_client_sdk/src/build_tools/build_app.py
+++ b/native_client_sdk/src/build_tools/build_app.py
@@ -31,8 +31,13 @@
     for f in files:
       path = os.path.join(root, f)
       ext = os.path.splitext(path)[1]
+      # Remove unwanted files from the package. Also remove manifest.json files
+      # (which we usually want). These ones are the manifests of the invidual
+      # examples, though, which CWS complains about. The master manifest.json
+      # is generated after we call RemoveBuildCruft.
       if (ext in ('.d', '.o') or
           f == 'dir.stamp' or
+          f == 'manifest.json' or
           re.search(r'_unstripped_.*?\.nexe', f)):
         buildbot_common.RemoveFile(path)
 
@@ -73,7 +78,13 @@
 
 def main(args):
   parser = optparse.OptionParser()
-  _, args = parser.parse_args(args[1:])
+  parser.add_option('-c', '--channel',
+      help='Channel to display in the name of the package.')
+  options, args = parser.parse_args(args[1:])
+
+  if options.channel:
+    if options.channel not in ('Dev', 'Beta'):
+      parser.error('Unknown channel: %s' % options.channel)
 
   toolchains = ['newlib', 'glibc']
 
@@ -120,18 +131,6 @@
     all_permissions.append({'socket': all_socket_permissions})
   pretty_permissions = json.dumps(all_permissions, sort_keys=True, indent=4)
 
-  template_dict = {
-    'name': 'Native Client SDK',
-    'description':
-        'Native Client SDK examples, showing API use and key concepts.',
-    'key': False,  # manifests with "key" are rejected when uploading to CWS.
-    'permissions': pretty_permissions,
-    'version': build_version.ChromeVersionNoTrunk()
-  }
-  easy_template.RunTemplateFile(
-      os.path.join(sdk_resources_dir, 'manifest.json.template'),
-      os.path.join(app_examples_dir, 'manifest.json'),
-      template_dict)
   for filename in ['background.js', 'icon128.png']:
     buildbot_common.CopyFile(os.path.join(sdk_resources_dir, filename),
                              os.path.join(app_examples_dir, filename))
@@ -144,6 +143,25 @@
   RemoveBuildCruft(app_dir)
   StripNexes(app_dir, platform, pepperdir)
 
+  # Add manifest.json after RemoveBuildCruft... that function removes the
+  # manifest.json files for the individual examples.
+  name = 'Native Client SDK'
+  if options.channel:
+    name += ' (%s)' % options.channel
+  template_dict = {
+    'name': name,
+    'channel': options.channel,
+    'description':
+        'Native Client SDK examples, showing API use and key concepts.',
+    'key': False,  # manifests with "key" are rejected when uploading to CWS.
+    'permissions': pretty_permissions,
+    'version': build_version.ChromeVersionNoTrunk()
+  }
+  easy_template.RunTemplateFile(
+      os.path.join(sdk_resources_dir, 'manifest.json.template'),
+      os.path.join(app_examples_dir, 'manifest.json'),
+      template_dict)
+
   app_zip = os.path.join(app_dir, 'examples.zip')
   os.chdir(app_examples_dir)
   oshelpers.Zip([app_zip, '-r', '*'])
diff --git a/native_client_sdk/src/build_tools/build_paths.py b/native_client_sdk/src/build_tools/build_paths.py
index 941f91b..9f1801f 100644
--- a/native_client_sdk/src/build_tools/build_paths.py
+++ b/native_client_sdk/src/build_tools/build_paths.py
@@ -16,5 +16,7 @@
 OUT_DIR = os.path.join(SRC_DIR, 'out')
 PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi')
 NACLPORTS_DIR = os.path.join(OUT_DIR, 'naclports')
+GONACL_APPENGINE_DIR = os.path.join(SDK_SRC_DIR, 'gonacl_appengine')
+GONACL_APPENGINE_SRC_DIR = os.path.join(GONACL_APPENGINE_DIR, 'src')
 
 GSTORE = 'https://commondatastorage.googleapis.com/nativeclient-mirror/nacl/'
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index 6db06d4..49d1cbe 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -42,7 +42,7 @@
 import verify_filelist
 
 from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR
-from build_paths import NACLPORTS_DIR, GSTORE
+from build_paths import NACLPORTS_DIR, GSTORE, GONACL_APPENGINE_SRC_DIR
 
 # Add SDK make tools scripts to the python path.
 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
@@ -426,9 +426,7 @@
       ['minidump_stackwalk', 'minidump_stackwalk']
     ]
 
-  if platform != 'mac':
-    # Mac doesn't build 64-bit binaries.
-    tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
+  tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
 
   if platform == 'linux':
     tools_files.append(['nacl_helper_bootstrap',
@@ -479,16 +477,15 @@
   platform = getos.GetPlatform()
   if platform == 'win':
     NinjaBuild('sel_ldr64', out_dir)
-  elif platform == 'linux':
+  else:
     out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64')
     GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64)
 
     # We only need sel_ldr from the 64-bit out directory.
     # sel_ldr needs to be renamed, so we'll call it sel_ldr64.
-    files_to_copy = [
-      ('sel_ldr', 'sel_ldr64'),
-      ('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'),
-    ]
+    files_to_copy = [('sel_ldr', 'sel_ldr64')]
+    if platform == 'linux':
+      files_to_copy.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'))
 
     for src, dst in files_to_copy:
       buildbot_common.CopyFile(
@@ -861,6 +858,15 @@
   buildbot_common.Run(cmd, cwd=NACL_DIR)
 
 
+def BuildStepBuildAppEngine(pepperdir, chrome_revision):
+  """Build the projects found in src/gonacl_appengine/src"""
+  buildbot_common.BuildStep('Build GoNaCl AppEngine Projects')
+  cmd = ['make', 'upload', 'REVISION=%s' % chrome_revision]
+  env = dict(os.environ)
+  env['NACL_SDK_ROOT'] = pepperdir
+  buildbot_common.Run(cmd, env=env, cwd=GONACL_APPENGINE_SRC_DIR)
+
+
 def main(args):
   parser = optparse.OptionParser()
   parser.add_option('--tar', help='Force the tar step.',
@@ -874,14 +880,15 @@
       dest='release', default=None)
   parser.add_option('--build-ports',
       help='Build naclport bundle.', action='store_true')
+  parser.add_option('--build-app-engine',
+      help='Build AppEngine demos.', action='store_true')
   parser.add_option('--experimental',
       help='build experimental examples and libraries', action='store_true',
       dest='build_experimental')
   parser.add_option('--skip-toolchain', help='Skip toolchain untar',
       action='store_true')
-  parser.add_option('--mac_sdk',
-      help='Set the mac_sdk (e.g. 10.6) to use when building with ninja.',
-      dest='mac_sdk')
+  parser.add_option('--mac-sdk',
+      help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.')
 
   global options
   options, args = parser.parse_args(args[1:])
@@ -890,6 +897,7 @@
   if buildbot_common.IsSDKBuilder():
     options.archive = True
     options.build_ports = True
+    options.build_app_engine = True
     options.tar = True
 
   toolchains = ['newlib', 'glibc', 'arm', 'pnacl', 'host']
@@ -948,6 +956,9 @@
     if options.tar:
       BuildStepTarNaClPorts(pepper_ver, ports_tarfile)
 
+  if options.build_app_engine and getos.GetPlatform() == 'linux':
+    BuildStepBuildAppEngine(pepperdir, chrome_revision)
+
   # Archive on non-trybots.
   if options.archive:
     BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision,
diff --git a/native_client_sdk/src/build_tools/generate_make.py b/native_client_sdk/src/build_tools/generate_make.py
index 2963d0b..f694ac9 100644
--- a/native_client_sdk/src/build_tools/generate_make.py
+++ b/native_client_sdk/src/build_tools/generate_make.py
@@ -157,6 +157,7 @@
       'name': desc['TITLE'],
       'description': '%s Example' % desc['TITLE'],
       'key': True,
+      'channel': None,
       'permissions': pretty_permissions,
       'version': build_version.ChromeVersionNoTrunk()
   }
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 5c8c765..73cd38a 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -85,6 +85,7 @@
 include/sdk_util/*
 [win]include/win/*
 include/win/poll.h
+include/win/sys/poll.h
 [linux]lib/${PLATFORM}_host/Debug/libgmock.a
 [linux]lib/${PLATFORM}_host/Debug/libgtest.a
 [linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
@@ -427,4 +428,4 @@
 tools/run.py
 tools/sel_ldr.py
 tools/sel_ldr_x86_32${EXE_EXT}
-[linux,win]tools/sel_ldr_x86_64${EXE_EXT}
+tools/sel_ldr_x86_64${EXE_EXT}
diff --git a/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst b/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
index 5c432e0..7ca1513 100644
--- a/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
+++ b/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
@@ -4,5 +4,509 @@
 3D Graphics
 ###########
 
-foo
+Native Client applications use the `OpenGL ES 2.0
+<http://en.wikipedia.org/wiki/OpenGL_ES>`_ API for 3D rendering. This document
+describes how to call the OpenGL ES 2.0 interface in a Native Client module and
+how to build an efficient rendering loop. It also explains how to validate GPU
+drivers and test for specific GPU capabilities, and provides tips to help ensure
+your rendering code runs efficiently.
 
+.. Note::
+  :class: note
+
+  **Note**: 3D drawing and OpenGL are complex topics. This document deals only
+  with issues directly related to programming in the Native Client
+  environment. To learn more about OpenGL ES 2.0 itself, see the `OpenGL ES 2.0
+  Programming Guide <http://opengles-book.com/>`_.
+
+Validating the client graphics platform
+=======================================
+
+Native Client is a software technology that lets you code an application once
+and run it on multiple platforms without worrying about the implementation
+details on every possible target platform. It's difficult to provide the same
+support at the hardware level. Graphics hardware comes from many different
+manufacturers and is controlled by drivers of varying quality. A particular GPU
+driver may not support every OpenGL ES 2.0 feature, and some drivers are known
+to have vulnerabilities that can be exploited.
+
+Even if the GPU driver is safe to use, your program should perform a validation
+check before you launch your application to ensure that the driver supports all
+the features you need.
+
+Vetting the driver in JavaScript
+--------------------------------
+
+At startup, the application should perform a few additional tests that can be
+implemented in JavaScript on its hosting web page. The script that performs
+these tests should be included before the module's ``embed`` tag, and ideally
+the ``embed`` tag should appear on the hosting page only if these tests succeed.
+
+The first thing to check is whether you can create a graphics context. If you
+can, use the context to confirm the existence of any required OpenGL ES 2.0
+extensions.  You may want to refer to the `extension registry
+<http://www.khronos.org/registry/webgl/extensions/>`_ and include `vendor
+prefixes <https://developer.mozilla.org/en-US/docs/WebGL/Using_Extensions>`_
+when checking for extensions.
+
+Vetting the driver in Native Client
+-----------------------------------
+
+Create a context
+^^^^^^^^^^^^^^^^
+
+Once you've passed the JavaScript validation tests, it's safe to add a Native
+Client embed tag to the hosting web page and load the module. As part of the
+module initialization code, you must create a graphics context for the app by
+either creating a C++ ``Graphics3D`` object or calling ``PPB_Graphics3D`` API
+function ``Create``. Don't assume this will always succeed; you still might have
+problems creating the context. If you are in development mode and can't create
+the context, try creating a simpler version to see if you're asking for an
+unsupported feature or exceeding a driver resource limit. Your production code
+should always check that the context was created and fail gracefully if that's
+not the case.
+
+Check for extensions and capabilities
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Not every GPU supports every extension or has the same amount of texture units,
+vertex attributes, etc. On startup, call ``glGetString(GLEXTENSIONS)`` and check
+for the extensions and the features you need. For example:
+
+* If you are using non power-of-2 texture with mipmaps, make sure
+  ``GL_OES_texture_npot`` exists.
+
+* If you are using floating point textures, make sure ``GL_OES_texture_float``
+  exists.
+
+* If you are using DXT1, DXT3, or DXT5 textures, make sure the corresponding
+  extensions ``EXT_texture_compression_dxt1``,
+  ``GL_CHROMIUM_texture_compression_dxt3``, and
+  ``GL_CHROMIUM_texture_compression_dxt5`` exist.
+
+Check for system capabilites with ``glGetIntegerv`` and adjust shader programs
+as well as texture and vertex data accordingly:
+
+* If you are using textures in vertex shaders, make sure
+  ``glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, ...)`` and
+  ``glGetIntegerv(GL_MAX_TEXTURE_SIZE, ...)`` return values greater than 0.
+
+* If you are using more than 8 textures in a single shader, make sure
+  ``glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)`` returns a value greater
+  than or equal to the number of simultaneous textures you need.
+
+Vetting the driver in the Chrome Web Store
+------------------------------------------
+
+If you choose to place your application in the `Chrome Web
+Store <https://developers.google.com/chrome/web-store/docs/>`_, its Web Store
+`manifest file <http://code.google.com/chrome/extensions/manifest.html>`_ can
+include the ``webgl`` feature in the requirements parameter. It looks like this:
+
+.. naclcode::
+
+  "requirements": {
+    "3D": {
+      "features": ["webgl"]
+    }
+  }
+
+While WebGL is technically a JavaScript API, specifying the ``webgl`` feature
+also works for OpenGL ES 2.0 because both interfaces use the same driver.
+
+This manifest item is not required, but if you include it, the Chrome Web Store
+will prevent a user from installing the application if the browser is running on
+a machine that does not support OpenGL ES 2.0 or that is using a known
+blacklisted GPU driver that could invite an attack.
+
+If the Web Store determines that the user's driver is deficient, the app won't
+appear on the store's tile display. However, it will appear in store search
+results or if the user links to it directly, in which case the user could still
+download it. But the manifest requirements will be checked when the user reaches
+the install page, and if there is a problem, the browser will display the
+message "This application is not supported on this computer. Installation has
+been disabled."
+
+The manifest-based check applies only to downloads directly from the Chrome Web
+Store. It is not performed when an application is loaded via `inline
+installation
+<https://developers.google.com/chrome/web-store/docs/inline_installation>`_.
+
+What to do when there are problems
+----------------------------------
+
+Using the vetting procedure described above, you should be able to detect the
+most common problems before your application runs. If there are problems, your
+code should describe the issue as clearly as possible. That's easy if there is a
+missing feature. Failure to create a graphics context is tougher to diagnose. At
+the very least, you can suggest that the user try to update the driver.  You
+might want to linke to the Chrome page that describes `how to do updates
+<http://support.google.com/chrome/bin/answer.py?hl=en&answer=1202946>`_.
+
+If a user can't update the driver, or their problem persists, be sure to gather
+information about their graphics environment. Ask for the contents of the Chrome
+``about:gpu`` page.
+
+Document unreliable drivers
+---------------------------
+
+It can be helpful to include information about known dubious drivers in your
+user documentation. This might help identify if a rogue driver is the cause of a
+problem. There are many sources of GPU driver blacklists. Two such lists can be
+found at the `Chromium project
+<http://src.chromium.org/viewvc/chrome/trunk/deps/gpu/software_rendering_list/software_rendering_list.json>`_
+and `Khronos <http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists>`_. You
+can use these lists to include information in your documentation that warns
+users about dangerous drivers.
+
+Test your defenses
+------------------
+
+You can test your driver validation code by running Chrome with the following
+flags (all at once) and watching how your application responds:
+
+* ``--disable-webgl``
+* ``--disable-pepper-3d``
+* ``--disable-gl-multisampling``
+* ``--disable-accelerated-compositing``
+* ``--disable-accelerated-2d-canvas``
+
+Calling OpenGL ES 2.0 commands
+==============================
+
+There are three ways to write OpenGL ES 2.0 calls in Native Client.
+
+Use "pure" OpenGL ES 2.0 function calls
+---------------------------------------
+
+You can make OpenGL ES 2.0 calls through a Pepper extension library.  The SDK
+example ``examples/api/graphics_3d`` works this way.  In the file
+``graphics_3d.cc``, the key initialization steps are as follows:
+
+* Add these includes at the top of the file:
+
+  .. naclcode::
+
+    #include <GLES2/gl2.h>
+    #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
+
+* Define the function ``InitGL``. The exact specification of ``attrib_list``
+  will be application specific.
+
+  .. naclcode::
+
+    bool InitGL(int32_t new_width, int32_t new_height) {
+      if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
+        fprintf(stderr, "Unable to initialize GL PPAPI!\n");
+        return false;
+      }
+
+      const int32_t attrib_list[] = {
+        PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
+        PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
+        PP_GRAPHICS3DATTRIB_WIDTH, new_width,
+        PP_GRAPHICS3DATTRIB_HEIGHT, new_height,
+        PP_GRAPHICS3DATTRIB_NONE
+      };
+
+      context_ = pp::Graphics3D(this, attrib_list);
+      if (!BindGraphics(context_)) {
+        fprintf(stderr, "Unable to bind 3d context!\n");
+        context_ = pp::Graphics3D();
+        glSetCurrentContextPPAPI(0);
+        return false;
+      }
+
+      glSetCurrentContextPPAPI(context_.pp_resource());
+      return true;
+    }
+
+* Include logic in ``Instance::DidChangeView`` to call ``InitGL`` whenever
+  necessary: upon application launch (when the graphics context is NULL) and
+  whenever the module's View changes size.
+
+Use Regal
+---------
+
+If you are porting an OpenGL ES 2.0 application, or are comfortable writing in
+OpenGL ES 2.0, you should stick with the Pepper APIs or pure OpenGL ES 2.0 calls
+described above. If you are porting an application that uses features not in
+OpenGL ES 2.0, consider using Regal. Regal is an open source library that
+supports many versions of OpenGL. Regal recently added support for Native
+Client. Regal forwards most OpenGL calls directly to the underlying graphics
+library, but it can also emulate other calls that are not included (when
+hardware support exists). See `libregal
+<http://www.altdevblogaday.com/2012/09/04/bringing-regal-opengl-to-native-client/>`_
+for more info.
+
+Use the Pepper API
+------------------
+
+Your code can call the Pepper `PPB_OpenGLES2
+<https://developers.google.com/native-client/pepperc/struct_p_p_b___open_g_l_e_s2>`_
+API directly, as with any Pepper interface. When you write in this way, each
+invocation of an OpenGL ES 2.0 function must begin with a reference to the
+Pepper interface, and the first argument is the graphics context. To invoke the
+function ``glCompileShader``, your code might look like:
+
+.. naclcode::
+
+  ppb_g3d_interface->CompileShader(graphicsContext, shader);
+
+This approach specifically targets the Pepper APIs. Each call corresponds to a
+OpenGL ES 2.0 function, but the syntax is unique to Native Client, so the source
+file is not portable.
+
+Implementing a rendering loop
+=============================
+
+Graphics applications require a continuous frame render-and-redraw cycle that
+runs at a high frequency. To achieve the best frame rate, is important to
+understand how the OpenGL ES 2.0 code in a Native Client module interacts with
+Chrome.
+
+The Chrome and Native Client processes
+--------------------------------------
+
+Chrome is a multi-process browser. Each Chrome tab is a separate process that is
+running an application with its own main thread (we'll call it the Chrome main
+thread). When an application launches a Native Client module, the module runs in
+a new, separate sandboxed process. The module's process has its own main thread
+(the Native Client thread). The Chrome and Native Client processes communicate
+with each other using Pepper API calls on their main threads.
+
+When the Chrome main thread calls the Native Client thread (keyboard and mouse
+callbacks, for example), the Chrome main thread will block. This means that
+lengthy operations on the Native Client thread can steal cycles from Chrome, and
+performing blocking operations on the Native Client thread can bring your app to
+a standstill.
+
+Native Client uses callback functions to synchronize the main threads of the two
+processes. Only certain Pepper functions use callbacks; `SwapBuffers
+<https://developers.google.com/native-client/pepperc/struct_p_p_b___graphics3_d__1__0#a293c6941c0da084267ffba3954793497>`_
+is one.
+
+``SwapBuffers`` and its callback function
+-----------------------------------------
+
+``SwapBuffers`` is non-blocking; it is called from the Native Client thread and
+returns immediately. When ``SwapBuffers`` is called, it runs asynchronously on
+the Chrome main thread. It switches the graphics data buffers, handles any
+needed compositing operations, and redraws the screen. When the screen update is
+complete, the callback function that was included as one of ``SwapBuffer``'s
+arguments will be called from the Chrome thread and executed on the Native
+Client thread.
+
+To create a rendering loop, your Native Client module should include a function
+that does the rendering work and then executes ``SwapBuffers``, passing itself
+as the ``SwapBuffer`` callback. If your rendering code is efficient and runs
+quickly, this scheme will achieve the highest frame rate possible. The
+documentation for ``SwapBuffers`` explains why this is optimal: because the
+callback is executed only when the plugin's current state is actually on the
+screen, this function provides a way to rate-limit animations. By waiting until
+the image is on the screen before painting the next frame, you can ensure you're
+not generating updates faster than the screen can be updated.
+
+The following diagram illustrates the interaction between the Chrome and Native
+Client processes. The application-specific rendering code runs in the function
+called ``Draw`` on the Native Client thread. Blue down-arrows are blocking calls
+from the main thread to Native Client, green up-arrows are non-blocking
+``SwapBuffers`` calls from Native Client to the main thread. All OpenGL ES 2.0
+calls are made from ``Draw`` in the Native Client thread.
+
+.. image:: /images/3d-graphics-render-loop.png
+
+SDK example ``graphics_3d``
+---------------------------
+
+The SDK example ``graphics_3d`` uses the function ``MainLoop`` (in
+``hello_world.cc``) to create a rendering loop as described above. ``MainLoop``
+calls ``Render`` to do the rendering work, and then invokes ``SwapBuffers``,
+passing itself as the callback.
+
+.. naclcode::
+
+  void MainLoop(void* foo, int bar) {
+    if (g_LoadCnt == 3) {
+      InitProgram();
+      g_LoadCnt++;
+    }
+    if (g_LoadCnt > 3) {
+      Render();
+      PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
+      ppb_g3d_interface->SwapBuffers(g_context, cc);
+    } else {
+      PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
+      ppb_core_interface->CallOnMainThread(0, cc, 0);
+    }
+  }
+
+Managing the OpenGL ES 2.0 pipeline
+===================================
+
+OpenGL ES 2.0 commands do not run in the Chrome or Native Client processes. They
+are passed into a FIFO queue in shared memory which is best understood as a `GPU
+command buffer
+<http://www.chromium.org/developers/design-documents/gpu-command-buffer>`_. The
+command buffer is shared by a dedicated GPU process. By using a separate GPU
+process, Chrome implements another layer of runtime security, vetting all OpenGL
+ES 2.0 commands and their arguments before they are sent on to the
+GPU. Buffering commands through the FIFO also speeds up your code, since each
+OpenGL ES 2.0 call in your Native Client thread returns immediately, while the
+processing may be delayed as the GPU works down the commands queued up in the
+FIFO.
+
+Before the screen is updated, all the intervening OpenGL ES 2.0 commands must be
+processed by the GPU. Programmers often try to ensure this by using the
+``glFlush`` and ``glFinish`` commands in their rendering code. In the case of
+Native Client this is usually unnecessary. The ``SwapBuffers`` command does an
+implicit flush, and the Chrome team is continually tweaking the GPU code to
+consume the OpenGL ES 2.0 FIFO as fast as possible.
+
+Sometimes a 3D application can write to the FIFO in a way that's difficult to
+handle. The command pipeline may fill up and your code will have to wait for the
+GPU to flush the FIFO. If this is the case, you may be able to add ``glFlush``
+calls to speed up the flow of the OpenGL ES 2.0 command FIFO. Before you start
+to add your own flushes, first try to determine if pipeline saturation is really
+the problem by monitoring the rendering time per frame and looking for irregular
+spikes that do not consistently fall on the same OpenGL ES 2.0 call. If you're
+convinced the pipeline needs to be accelerated, insert ``glFlush`` calls in your
+code before starting blocks of processing that do not generate OpenGL ES 2.0
+commands. For example, issue a flush before you begin any multithreaded particle
+work, so that the command buffer will be clear when you start doing OpenGL ES
+2.0 calls again. Determining where and how often to call ``glFlush`` can be
+tricky, you will need to experiment to find the sweet spot.
+
+Rendering and inactive tabs
+===========================
+
+Users will often switch between tabs in a multi-tab browser. A well-behaved
+application that's performing 3D rendering should pause any real-time processing
+and yield cycles to other processes when its tab becomes inactive.
+
+In Chrome, an inactive tab will continue to execute timed functions (such as
+``setInterval`` and ``setTimeout``) but the timer interval will be automatically
+overridden and limited to not less than one second while the tab is inactive. In
+addition, any callback associated with a ``SwapBuffers`` call will not be sent
+until the tab is active again. You may receive asynchronous callbacks from
+functions other than ``SwapBuffers`` while a tab is inactive. Depending on the
+design of your application, you might choose to handle them as they arrive, or
+to queue them in a buffer and process them when the tab becomes active.
+
+The time that passes while a tab is inactive can be considerable. If your main
+thread pulse is based on the ``SwapBuffers`` callback, your app won't update
+while a tab is inactive. A Native Client module should be able to detect and
+respond to the state of the tab in which it's running. For example, when a tab
+becomes inactive, you can set an atomic flag in the Native Client thread that
+will skip the 3D rendering and ``SwapBuffers`` calls and continue to call the
+main thread every 30 msec or so. This provides time to update features that
+should still run in the background, like audio. It may also be helpful to call
+``sched_yield`` or ``usleep`` on any worker threads to release resources and
+cede cycles to the OS.
+
+Handling tab activation from the main thread
+--------------------------------------------
+
+You can detect and respond to the activation or deactivation of a tab with
+JavaScript on your hosting page. Add an EventListener for ``visibilitychange``
+that sends a message to the Native Client module, as in this example:
+
+.. naclcode::
+
+  document.addEventListener('visibilitychange', function(){
+    if (document.hidden) {
+      // PostMessage to your Native Client module
+      document.nacl_module.postMessage('INACTIVE');
+    } else {
+      // PostMessage to your Native Client module
+      document.nacl_module.postMessage('ACTIVE');
+    }
+
+  }, false);
+
+Handling tab activation from the Native Client thread
+-----------------------------------------------------
+
+You can also detect and respond to the activation or deactivation of a tab
+directly from your Native Client module by including code in the function
+``pp::Instance::DidChangeView``, which is called whenever a change in the
+module's view occurs. The code can call ``ppb::View::IsPageVisible`` to
+determine if the page is visible or not. The most common cause of invisible
+pages is that the page is in a background tab.
+
+Tips and best practices
+=======================
+
+Here are some suggestions for writing safe code and getting the maximum
+performance with the Pepper 3D API.
+
+Do's
+----
+
+* **Make sure to enable attrib 0.** OpenGL requires that you enable attrib 0,
+  but OpenGL ES 2.0 does not. For example, you can define a vertex shader with 2
+  attributes, numbered like this:
+
+  .. naclcode::
+
+    glBindAttribLocation(program, "positions", 1);
+    glBindAttribLocation(program, "normals", 2);
+
+  In this case the shader is not using attrib 0 and Chrome may have to perform
+  some additional work if it is emulating OpenGL ES 2.0 on top of OpenGL. It's
+  always more efficient to enable attrib 0, even if you do not use it.
+
+* **Check how shaders compile.** Shaders can compile differently on different
+  systems, which can result in ``glGetAttrib*`` functions returning different
+  results. Be sure that the vertex attribute indices match the corresponding
+  name each time you recompile a shader.
+
+* **Update indices sparingly.** For security reasons, all indices must be
+  validated. If you change indices, Native Client will validate them
+  again. Structure your code so indices are not updated often.
+
+* **Use a smaller plugin and let CSS scale it.** If you're running into fillrate
+  issues, it may be beneficial to perform scaling via CSS. The size your plugin
+  renders is determined by the width and height attributes of the ``<embed>``
+  element for the module. The actual size displayed on the web page is
+  controlled by the CSS styles applied to the element.
+
+* **Avoid matrix-to-matrix conversions.** With some versions of Mac OS, there is
+  a driver problem when compiling shaders. If you get compiler errors for matrix
+  transforms, avoid matrix-to-matrix conversions. For instance, upres a vec3 to
+  a vec4 before transforming it by a mat4, rather than converting the mat4 to a
+  mat3.
+
+Don'ts
+------
+
+* **Don't use client side buffers.** OpenGL ES 2.0 can use client side data with
+  ``glVertexAttribPointer`` and ``glDrawElements``, but this is really slow. Try
+  to avoid client side buffers. Use Vertex Buffer Objects (VBOs) instead.
+
+* **Don't mix vertex data and index data.** By default, Pepper 3D binds buffers
+  to a single point. You could create a buffer and bind it to both
+  ``GL_ARRAY_BUFFER`` and ``GL_ELEMENT_ARRAY_BUFFER``, but that would be
+  expensive overhead and it is not recommended.
+
+* **Don't call ``glGet*`` or ``glCheck*`` during rendering.** This is normal
+  advice for OpenGL programs, but is particularly important for 3D on
+  Chrome. Calls to any OpenGL ES 2.0 function whose name begins with these
+  strings blocks the Native Client thread. This includes ``glGetError``; avoid
+  calling it in release builds.
+
+* **Don't use fixed point (``GL_FIXED``) vertex attributes.** Fixed point
+  attributes are not supported in OpenGL ES 2.0, so emulating them in OpenGL ES
+  2.0 is slow. By default, ``GL_FIXED`` support is turned off in the Pepper 3D
+  API.
+
+* **Don't read data from the GPU.** Don't call ``glReadPixels``, as it is slow.
+
+* **Don't update a small portion of a large buffer.** In the current OpenGL ES
+  2.0 implementation when you update a portion of a buffer (with
+  ``glSubBufferData`` for example) the entire buffer must be reprocessed. To
+  avoid this problem, keep static and dynamic data in different buffers.
+
+* **Don't call ``glDisable(GL_TEXTURE_2D)``.** This is an OpenGL ES 2.0
+  error. Each time it is called, an error messages will appear in Chrome's
+  ``about:gpu`` tab.
diff --git a/native_client_sdk/src/doc/devguide/coding/FileIO.rst b/native_client_sdk/src/doc/devguide/coding/FileIO.rst
index ed0867e..6e3a4a5 100644
--- a/native_client_sdk/src/doc/devguide/coding/FileIO.rst
+++ b/native_client_sdk/src/doc/devguide/coding/FileIO.rst
@@ -6,4 +6,6 @@
 
 foo
 
+.. _quota_management:
+
 .. _enabling_file_access:
diff --git a/native_client_sdk/src/doc/devguide/coding/audio.rst b/native_client_sdk/src/doc/devguide/coding/audio.rst
index f1696e5..6c76e9a 100644
--- a/native_client_sdk/src/doc/devguide/coding/audio.rst
+++ b/native_client_sdk/src/doc/devguide/coding/audio.rst
@@ -4,5 +4,385 @@
 Audio
 #####
 
-fooooooooooooooooooooo
+.. contents::
+  :local:
+  :backlinks: none
+  :depth: 2
 
+This chapter describes how to use the Pepper audio API to play an audio
+stream. The Pepper audio API provides a low-level means of playing a stream of
+audio samples generated by a Native Client module. The API generally works as
+follows: A Native Client module creates an audio resource that represents an
+audio stream, and tells the browser to start or stop playing the audio
+resource. The browser calls a function in the Native Client module to fill a
+buffer with audio samples every time it needs data to play from the audio
+stream.
+
+The code examples in this chapter describe a simple Native Client module that
+generates audio samples using a sine wave with a frequency of 440 Hz. The module
+starts playing the audio samples as soon as it is loaded into the browser. For a
+slightly more sophisticated example, see the ``audio`` example (source code in
+the SDK directory ``examples/api/audio``), which lets users specify a frequency
+for the sine wave and click buttons to start and stop audio playback.
+
+Reference information
+=====================
+
+For reference information related to the Pepper audio API, see the following
+documentation:
+
+* `pp::AudioConfig class
+  <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio_config>`_
+
+* `pp::Audio class
+  <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio>`_
+
+* `audio_config.h
+  <https://developers.google.com/native-client/peppercpp/audio__config_8h>`_
+
+* `audio.h <https://developers.google.com/native-client/peppercpp/audio_8h>`_
+
+* `PP_AudioSampleRate
+  <https://developers.google.com/native-client/pepperc/group___enums.html#gaee750c350655f2fb0fe04c04029e0ff8>`_
+
+About the Pepper audio API
+==========================
+
+The Pepper audio API lets Native Client modules play audio streams in a
+browser. To play an audio stream, a module generates audio samples and writes
+them into a buffer. The browser reads the audio samples from the buffer and
+plays them using an audio device on the client computer.
+
+.. image:: /images/pepper-audio-buffer.png
+
+This mechanism is simple but low-level. If you want to play plain sound files in
+a web application, you may want to consider higher-level alternatives such as
+using the HTML ``<audio>`` tag, JavaScript, or the new `Web Audio API
+<http://chromium.googlecode.com/svn/trunk/samples/audio/index.html>`_.
+
+The Pepper audio API is a good option for playing audio data if you want to do
+audio processing in your web application. You might use the audio API, for
+example, if you want to apply audio effects to sounds, synthesize your own
+sounds, or do any other type of CPU-intensive processing of audio
+samples. Another likely use case is gaming applications: you might use a gaming
+library to process audio data, and then simply use the audio API to output the
+processed data.
+
+The Pepper audio API is straightforward to use:
+
+#. Your module creates an audio configuration resource and an audio resource.
+
+#. Your module implements a callback function that fills an audio buffer with
+   data.
+
+#. Your module invokes the StartPlayback and StopPlayback methods of the audio
+   resource (e.g., when certain events occur).
+
+#. The browser invokes your callback function whenever it needs audio data to
+   play. Your callback function can generate the audio data in a number of
+   ways---e.g., it can generate new data, or it can copy pre-mixed data into the
+   audio buffer.
+
+This basic interaction is illustrated below, and described in detail in the
+sections that follow.
+
+.. image:: /images/pepper-audio-api.png
+
+Digital audio concepts
+======================
+
+Before you use the Pepper audio API, it's helpful to understand a few concepts
+that are fundamental to how digital audio is recorded and played back:
+
+sample rate
+  the number of times an input sound source is sampled per second;
+  correspondingly, the number of samples that are played back per second
+
+bit depth
+  the number of bits used to represent a sample
+
+channels
+  the number of input sources recorded in each sampling interval;
+  correspondingly, the number of outputs that are played back simultaneously
+  (typically using different speakers)
+
+The higher the sample rate and bit depth used to record a sound wave, the more
+accurately the sound wave can be reproduced, since it will have been sampled
+more frequently and stored using a higher level of quantization. Common sampling
+rates include 44,100 Hz (44,100 samples/second, the sample rate used on CDs),
+and 48,000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common
+bit depth is 16 bits per sample, and a common number of channels is 2 (left and
+right channels for stereo sound).
+
+.. _pepper_audio_configurations:
+
+The Pepper audio API currently lets Native Client modules play audio streams
+with the following configurations:
+
+* **sample rate**: 44,100 Hz or 48,000 Hz
+* **bit depth**: 16
+* **channels**: 2 (stereo)
+
+Setting up the module
+=====================
+
+The code examples below describe a simple Native Client module that generates
+audio samples using a sine wave with a frequency of 440 Hz. The module starts
+playing the audio samples as soon as it is loaded into the browser.
+
+The Native Client module is set up by implementing subclasses of the
+``pp::Module`` and ``pp::Instance`` classes, as normal.
+
+.. naclcode::
+
+  class SineSynthInstance : public pp::Instance {
+   public:
+    explicit SineSynthInstance(PP_Instance instance);
+    virtual ~SineSynthInstance() {}
+
+    // Called by the browser once the NaCl module is loaded and ready to
+    // initialize.  Creates a Pepper audio context and initializes it. Returns
+    // true on success.  Returning false causes the NaCl module to be deleted
+    // and no other functions to be called.
+    virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+
+   private:
+    // Function called by the browser when it needs more audio samples.
+    static void SineWaveCallback(void* samples,
+                                 uint32_t buffer_size,
+                                 void* data);
+
+    // Audio resource.
+    pp::Audio audio_;
+
+    ...
+
+  };
+
+  class SineSynthModule : public pp::Module {
+   public:
+    SineSynthModule() : pp::Module() {}
+    ~SineSynthModule() {}
+
+    // Create and return a SineSynthInstance object.
+    virtual pp::Instance* CreateInstance(PP_Instance instance) {
+      return new SineSynthInstance(instance);
+    }
+  };
+
+Creating an audio configuration resource
+========================================
+
+Resources
+---------
+
+Before the module can play an audio stream, it must create two resources: an
+audio configuration resource and an audio resource. Resources are handles to
+objects that the browser provides to module instances. An audio resource is an
+object that represents the state of an audio stream, including whether the
+stream is paused or being played back, and which callback function to invoke
+when the samples in the stream's buffer run out. An audio configuration resource
+is an object that stores configuration data for an audio resource, including the
+sampling frequency of the audio samples, and the number of samples that the
+callback function must provide when the browser invokes it.
+
+Sample frame count
+------------------
+
+Prior to creating an audio configuration resource, the module should call
+``RecommendSampleFrameCount`` to obtain a *sample frame count* from the
+browser. The sample frame count is the number of samples that the callback
+function must provide per channel each time the browser invokes the callback
+function. For example, if the sample frame count is 4096 for a stereo audio
+stream, the callback function must provide a 8192 samples (4096 for the left
+channel and 4096 for the right channel).
+
+The module can request a specific sample frame count, but the browser may return
+a different sample frame count depending on the capabilities of the client
+device. At present, ``RecommendSampleFrameCount`` simply bound-checks the
+requested sample frame count (see ``include/ppapi/c/ppb_audio_config.h`` for the
+minimum and maximum sample frame counts, currently 64 and 32768). In the future,
+``RecommendSampleFrameCount`` may perform a more sophisticated calculation,
+particularly if there is an intrinsic buffer size for the client device.
+
+Selecting a sample frame count for an audio stream involves a tradeoff between
+latency and CPU usage. If you want your module to have short audio latency so
+that it can rapidly change what's playing in the audio stream, you should
+request a small sample frame count. That could be useful in gaming applications,
+for example, where sounds have to change frequently in response to game
+action. However, a small sample frame count results in higher CPU usage, since
+the browser must invoke the callback function frequently to refill the audio
+buffer. Conversely, a large sample frame count results in higher latency but
+lower CPU usage. You should request a large sample frame count if your module
+will play long, uninterrupted audio segments.
+
+Supported audio configurations
+------------------------------
+
+After the module obtains a sample frame count, it can create an audio
+configuration resource. Currently the Pepper audio API supports audio streams
+with the configuration settings shown :ref:`above<pepper_audio_configurations>`.
+C++ modules can create a configuration resource by instantiating a
+``pp::AudioConfig`` object. Check ``audio_config.h`` for the latest
+configurations that are supported.
+
+.. naclcode::
+
+  bool SineSynthInstance::Init(uint32_t argc,
+                               const char* argn[],
+                               const char* argv[]) {
+
+    // Ask the browser/device for an appropriate sample frame count size.
+    sample_frame_count_ =
+        pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
+                                                   kSampleFrameCount);
+
+    // Create an audio configuration resource.
+    pp::AudioConfig audio_config = pp::AudioConfig(this,
+                                                   PP_AUDIOSAMPLERATE_44100,
+                                                   sample_frame_count_);
+
+    // Create an audio resource.
+    audio_ = pp::Audio(this,
+                       audio_config,
+                       SineWaveCallback,
+                       this);
+
+    // Start playback when the module instance is initialized.
+    return audio_.StartPlayback();
+  }
+
+Creating an audio resource
+==========================
+
+Once the module has created an audio configuration resource, it can create an
+audio resource. To do so, it instantiates a ``pp::Audio`` object, passing in a
+pointer to the module instance, the audio configuration resource, a callback
+function, and a pointer to user data (data that is used in the callback
+function).  See the example above.
+
+Implementing a callback function
+================================
+
+The browser calls the callback function associated with an audio resource every
+time it needs more samples to play. The callback function can generate new
+samples (e.g., by applying sound effects), or copy pre-mixed samples into the
+audio buffer. The example below generates new samples by computing values of a
+sine wave.
+
+The last parameter passed to the callback function is generic user data that the
+function can use in processing samples. In the example below, the user data is a
+pointer to the module instance, which includes member variables
+``sample_frame_count_`` (the sample frame count obtained from the browser) and
+``theta_`` (the last angle that was used to compute a sine value in the previous
+callback; this lets the function generate a smooth sine wave by starting at that
+angle plus a small delta).
+
+.. naclcode::
+
+  class SineSynthInstance : public pp::Instance {
+   public:
+    ...
+
+   private:
+    static void SineWaveCallback(void* samples,
+                                 uint32_t buffer_size,
+                                 void* data) {
+
+      // The user data in this example is a pointer to the module instance.
+      SineSynthInstance* sine_synth_instance =
+          reinterpret_cast<SineSynthInstance*>(data);
+
+      // Delta by which to increase theta_ for each sample.
+      const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100;
+      // Amount by which to scale up the computed sine value.
+      const int16_t max_int16 = std::numeric_limits<int16_t>::max();
+
+      int16_t* buff = reinterpret_cast<int16_t*>(samples);
+
+      // Make sure we can't write outside the buffer.
+      assert(buffer_size >= (sizeof(*buff) * kChannels *
+                             sine_synth_instance->sample_frame_count_));
+
+      for (size_t sample_i = 0;
+           sample_i < sine_synth_instance->sample_frame_count_;
+           ++sample_i, sine_synth_instance->theta_ += delta) {
+
+        // Keep theta_ from going beyond 2*Pi.
+        if (sine_synth_instance->theta_ > kTwoPi) {
+          sine_synth_instance->theta_ -= kTwoPi;
+        }
+
+        // Compute the sine value for the current theta_, scale it up,
+        // and write it into the buffer once for each channel.
+        double sin_value(std::sin(sine_synth_instance->theta_));
+        int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
+        for (size_t channel = 0; channel < kChannels; ++channel) {
+          *buff++ = scaled_value;
+        }
+      }
+    }
+
+    ...
+  };
+
+Application threads and real-time requirements
+----------------------------------------------
+
+The callback function runs in a background application thread. This allows audio
+processing to continue even when the application is busy doing something
+else. If the main application thread and the callback thread access the same
+data, you may be tempted to use a lock to control access to that data. You
+should avoid the use of locks in the callback thread, however, as attempting to
+acquire a lock may cause the thread to get swapped out, resulting in audio
+dropouts.
+
+In general, you must program the callback thread carefully, as the Pepper audio
+API is a very low level API that needs to meet hard real-time requirements. If
+the callback thread spends too much time processing, it can easily miss the
+real-time deadline, resulting in audio dropouts. One way the callback thread can
+miss the deadline is by taking too much time doing computation. Another way the
+callback thread can miss the deadline is by executing a function call that swaps
+out the callback thread. Unfortunately, such function calls include just about
+all C Run-Time (CRT) library calls and Pepper API calls. The callback thread
+should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical
+sections, and so forth; any such calls could attempt to take a lock and swap out
+the callback thread, which would be disastrous for audio playback. Similarly,
+the callback thread should avoid Pepper API calls. Audio dropouts due to thread
+swapping can be very rare and very hard to track down and debug---it's best to
+avoid making system/Pepper calls in the first place. In short, the audio
+(callback) thread should use "lock-free" techniques and avoid making CRT library
+calls.
+
+One other issue to be aware of is that the ``StartPlayback`` function (discussed
+below) is an asynchronous RPC; i.e., it does not block. That means that the
+callback function may not be called immediately after the call to
+``StartPlayback``. If it's important to synchronize the callback thread with
+another thread so that the audio stream starts playing simultaneously with
+another action in your application, you must handle such synchronization
+manually.
+
+Starting and stopping playback
+==============================
+
+To start and stop audio playback, the module simply reacts to JavaScript
+messages.
+
+.. naclcode::
+
+  const char* const kPlaySoundId = "playSound";
+  const char* const kStopSoundId = "stopSound";
+
+  void SineSynthInstance::HandleMessage(const pp::Var& var_message) {
+    if (!var_message.is_string()) {
+      return;
+    }
+    std::string message = var_message.AsString();
+    if (message == kPlaySoundId) {
+      audio_.StartPlayback();
+    } else if (message == kStopSoundId) {
+      audio_.StopPlayback();
+    } else if (...) {
+      ...
+    }
+  }
diff --git a/native_client_sdk/src/doc/devguide/coding/nacl_io.rst b/native_client_sdk/src/doc/devguide/coding/nacl_io.rst
new file mode 100644
index 0000000..6cee0f7
--- /dev/null
+++ b/native_client_sdk/src/doc/devguide/coding/nacl_io.rst
@@ -0,0 +1,225 @@
+###################
+The nacl_io Library
+###################
+
+.. contents::
+  :local:
+  :backlinks: none
+  :depth: 2
+
+Introduction
+============
+
+``nacl_io`` is a utility library that provides implementations of standard
+C APIs such as POSIX I/O (``stdio.h``) and BSD sockets (``sys/socket.h``).
+Its primary function is to allow code that uses these standard APIs to be
+compiled and used in a Native Client module. The library is included as part
+of Native Client SDK and is implemented in on top of Pepper API.
+
+Since Native Client modules cannot access the host machine's file system
+directly, nacl_io provides several alternative filesystem types which
+can be used by the application. For example, the Chrome browser supports the
+`HTML5 File System API
+<http://www.html5rocks.com/en/tutorials/file/filesystem/>`_ which provides
+access to a protected area of the local file system. This filesystem can
+be accessed by an HTML page using JavaScript commands, and also by a Native
+Client module using the Pepper :doc:`File IO API <FileIO>`. With nacl_io
+a Native Client application can mount an HTML5 filesystem and access it via
+standard POSIX I/O function such as ``fopen``, ``fseek``, ``fread``,
+``fwrite``, and ``fclose``, or their low level UNIX counterparts ``open``,
+``lseek``, ``read``, ``write`` and ``close``.
+
+As well as the HTML5 file system, nacl_io provides several other file system
+types which are described in the table below:
+
+=========== ==================================================================
+File System Description
+=========== ==================================================================
+memfs       An in-memory file system
+html5fs     An HTML5 local file system, which can be persistent or temporary
+http        Maps files on a remote webserver into the local filesystem.
+dev         A file system containing special files (e.g.: ``/dev/null``)
+=========== ==================================================================
+
+Using nacl_io
+=============
+
+Using nacl_io is mostly just a matter of using the standard POSIX C library
+functions. However, there are some steps required to initialize the library
+and setup the filesystem mounts. In general the following steps will be needed
+to use nacl_io in a NaCl application:
+
+#. Link the application with the nacl_io library (``-lnacl_io``)
+#. Initialize nacl_io at startup using the ``nacl_io_init_ppapi`` or
+   ``nacl_io_init`` functions.
+#. Mount any desired filesystems using the ``mount`` function. The arguments
+   to ``mount`` for the different filesystem types are detailed in
+   ``include/nacl_io/nacl_io.h``.
+#. If you are going to mount an HTML5 file system, be sure to allocate space
+   for it. You can either set the ``unlimitedStorage`` permission in the app's
+   Web Store manifest file, or call the HTML5 QuotaManagement API. These
+   options are explained in the :ref:`File IO documentation <quota_management>`.
+#. Make sure that file and socket API calls are all made from the background
+   thread. This is because the main Pepper thread does not support the blocking
+   behavior needed by the POSIX I/O operations.
+
+The nacl_io demo
+================
+
+Building and running the demo
+-----------------------------
+
+The demo application launches a Native Client module that mounts three file
+systems and displays a set of controls that let you work with them:
+
+.. image:: /images/nacl_io1.png
+
+Follow these steps to build and run the demo:
+
+* Open a terminal in the demo directory::
+
+    $ cd $NACL_SDK_ROOT/examples/demo/nacl_io
+
+* run the demo::
+
+    $ make run
+
+Once the demo is running, try these operations:
+
+#. select the fopen command (when you select a command the fields in the line
+   below will change according to the command)
+#. type in the filename ``/persistent/test``
+#. check the write checkbox and press the fopen button
+#. select the fwrite command and select the file ``/persistent/test`` in the
+   menu that appears below on the left
+#. enter some data and press the fwrite button
+#. select the fclose command, be sure the file ``/persistent/test`` is selected
+   in the menu, and press the fclose button
+#. select the fopen command
+#. type in the filename ``/persistent/test``
+#. check the fread checkbox and press the fopen button
+#. select the fread command, be sure the file /persistent/test is selected in
+   the menu, enter a byte count, and press the fread button
+
+A look at the code
+------------------
+
+The demo is written C and comprises three files.
+
+nacl_io_demo.c
+^^^^^^^^^^^^^^
+
+This is the demo's main file. The code here creates and initializes the Native
+Client module instance. The Pepper function ``Instance_DidCreate`` initializes
+nacl_io and mounts an HTML5 filesystem at ``/persistent``.
+
+.. naclcode::
+
+  static PP_Bool Instance_DidCreate(PP_Instance instance,
+                                    uint32_t argc,
+                                    const char* argn[],
+                                    const char* argv[]) {
+    g_instance = instance;
+    nacl_io_init_ppapi(instance, get_browser_interface);
+    mount(
+        "",  /* source */
+        "/persistent",  /* target */
+        "html5fs",  /* filesystemtype */
+        0,  /* mountflags */
+        "type=PERSISTENT,expected_size=1048576");  /* data specific to the html5fs type */
+
+    pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
+    InitializeMessageQueue();
+
+    return PP_TRUE;
+  }
+
+Space is allocated to the ``/persistent`` file system after the module is
+initialized. This is accomplished by the ``domContentLoaded`` function in
+the file ``example.js``. This script is included in the module's html page (see
+``examples/demo/index.html``):
+
+.. naclcode::
+
+  function domContentLoaded(name, tc, config, width, height) {
+    navigator.webkitPersistentStorage.requestQuota(window.PERSISTENT, 1024 * 1024,
+        function(bytes) {
+          common.updateStatus(
+              'Allocated ' + bytes + ' bytes of persistant storage.');
+          common.createNaClModule(name, tc, config, width, height);
+          common.attachDefaultListeners();
+        },
+        function(e) { alert('Failed to allocate space') });
+  }
+
+The ``Instance_DidCreate`` function also creates a worker thread that receives
+messages sent from the html page and performs the specified file system
+operations. The logic for the worker thread is encoded in the other two files,
+described below.
+
+queue.c
+^^^^^^^
+
+This file implements a circular queue that is used to receive messages from the
+browser UI to the Native Client module. The file system commands in the
+enqueued messages are executed on the worker thread. This keeps blocking calls
+(like fread) off the main Native Client thread, which is a good thing. The
+queue is initialized in nacl_io_demo.c ``Instance_DidCreate``.
+
+handlers.c
+^^^^^^^^^^
+
+This file implements the stdio calls associated with the commands sent from the
+browser. There is a separate ``Handle*`` function for each command: fopen,
+fclose, fseek, fread, fwrite. The handlers are called from the
+``HandleMessage`` function in nacl_io_demo.c, which runs in the worker
+thread managing the message queue. The code for the ``fwrite`` handler appears
+below. Notice that it does not contain any PPAPI calls and looks like
+"ordinary" C code.
+
+
+.. naclcode::
+
+  int HandleFwrite(int num_params, char** params, char** output) {
+    FILE* file;
+    const char* file_index_string;
+    const char* data;
+    size_t data_len;
+    size_t bytes_written;
+
+    if (num_params != 2) {
+      *output = PrintfToNewString("Error: fwrite takes 2 parameters.");
+      return 1;
+    }
+
+    file_index_string = params[0];
+    file = GetFileFromIndexString(file_index_string, NULL);
+    data = params[1];
+    data_len = strlen(data);
+
+    if (!file) {
+      *output = PrintfToNewString("Error: Unknown file handle %s.",
+                                  file_index_string);
+      return 2;
+    }
+
+    bytes_written = fwrite(data, 1, data_len, file);
+
+    *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string,
+                                bytes_written);
+    return 0;
+  }
+
+Reference information
+=====================
+
+The example discussed here is included in the SDK in the directory
+``examples/demo/nacl_io``.
+
+The nacl_io library is included in the SDK toolchain and is not a part of the
+Pepper API. For reference information related to the nacl_io interface see
+its header file in the SDK directory, located at
+``include/nacl_io/nacl_io.h``.
+
+For more about the HTML5 file system read the `specification
+<http://dev.w3.org/2009/dap/file-system/pub/FileSystem/>`_.
diff --git a/native_client_sdk/src/doc/devguide/devcycle/building.rst b/native_client_sdk/src/doc/devguide/devcycle/building.rst
index d1a6b04..8d5ab3d 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/building.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/building.rst
@@ -62,13 +62,14 @@
 for information about these libraries, including factors to help you
 decide which to use.
 
+.. _building_cpp_libraries:
 
 C++ libraries
 -------------
 
 The PNaCl SDK can use either
 `libstdc++ <http://gcc.gnu.org/libstdc++>`_ (the current default)
-or LLVM's `libc++ <http://libcxx.llvm.org/>`_ (preliminary support).
+or LLVM's `libc++ <http://libcxx.llvm.org/>`_ (experimental support).
 The ``-stdlib=[libstdc++|libc++]`` command line argument can be used
 to choose which standard library to use.
 
@@ -78,7 +79,8 @@
 C++11 library support is only complete in libc++ but other non-library
 language features should work regardless of which standard library is
 used. The ``-std=[c++98|c++11]`` command line argument can be used to
-indicate which C++ language standard to use.
+indicate which C++ language standard to use (or ``-std=gnu++11`` with
+non-standard extensions).
 
 SDK toolchains
 --------------
@@ -94,7 +96,7 @@
 * *<architecture>* is your target architecture (x86 or arm)
 * *<library>* is the C library you are compiling with (newlib or glibc)
 
-The compilers, linkers, and other tools are located in the ``bin/`` 
+The compilers, linkers, and other tools are located in the ``bin/``
 subdirectory in each toolchain. For example, the tools in the Windows SDK
 for PNaCl has a C++ compiler in ``toolchain/win_pnacl/bin/pnacl-clang++``.
 As another example, the GCC-based C++ compiler that targets the x86 and uses the
@@ -154,6 +156,8 @@
 Each tool's name is preceded by the prefix "pnacl-". Some of the useful
 tools include:
 
+pnacl-abicheck
+  Check that the **pexe** follows the PNaCl ABI rules.
 pnacl-ar
   Creates archives (e.g., static libraries)
 pnacl-clang
@@ -618,5 +622,37 @@
   <NACL_SDK_ROOT>/toolchain/<platform>_pnacl/bin/pnacl-nm -o \
     toolchain/<platform>_pnacl/usr/lib/*.a | grep <MySymbolName>
 
-.. TODO(jvoung): Add some notes about debugging GNU-extensions not
-.. supported by PNaCl ABI stabilization passes, like computed gotos?
+
+PNaCl ABI Verification errors
+-----------------------------
+
+PNaCl has restrictions on what is supported in bitcode. There is a bitcode
+ABI verifier which checks that the application conforms to the ABI restrictions,
+before it is translated and run in the browser. However, it is best to
+avoid runtime errors for users, so the verifier also runs on the developer's
+machine at link time.
+
+For example, the following program which uses 128-bit integers
+would compile with NaCl GCC for the x86-64 target. However, it is not
+portable and would not compile with NaCl GCC for the i686 target.
+With PNaCl, it would fail to pass the ABI verifier:
+
+.. naclcode::
+
+  typedef unsigned int uint128_t __attribute__((mode(TI)));
+
+  uint128_t foo(uint128_t x) {
+    return x;
+  }
+
+With PNaCl you would get the following error at link time:
+
+.. naclcode::
+
+  Function foo has disallowed type: i128 (i128)
+  LLVM ERROR: PNaCl ABI verification failed
+
+When faced with a PNaCl ABI verification error, check the list of features
+that are :ref:`not supported by PNaCl <when-to-use-nacl>`.
+If the problem you face is not listed as restricted,
+:ref:`let us know <help>`!
diff --git a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
index a0f8255..00b76bb 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
@@ -317,6 +317,8 @@
 ``lib64``.  These directories are used to collect all the shared libraries
 needed by the application, as discussed below.
 
+.. _dynamic_loading_manifest:
+
 Generating a Native Client manifest file for a dynamically linked application
 =============================================================================
 
diff --git a/native_client_sdk/src/doc/devguide/devcycle/running.rst b/native_client_sdk/src/doc/devguide/devcycle/running.rst
index 17d8ad5..3b3273a 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/running.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/running.rst
@@ -4,7 +4,7 @@
 Running
 #######
 
-.. contents:: Table Of Contents
+.. contents::
   :local:
   :backlinks: none
   :depth: 2
@@ -15,6 +15,27 @@
 This document describes how to run Native Client applications during
 development.
 
+The workflow for PNaCl applications is straightfoward and will only be discussed
+briefly. For NaCl applications distributed through the web-store, there is a
+number of options and these will be discussed more in-depth.
+
+Portable Native Client (PNaCl) applications
+===========================================
+
+Running PNaCl applications from the open web is enabled in Chrome version 31 and
+above; therefore, no special provisions are required to run and test such
+applications locally. An application that uses a PNaCl module can be tested
+similarly to any other web application that only consists of HTML, CSS and
+JavaScript.
+
+To better simulate a production environment, it's recommended to start a local
+web server to serve the application's files. The NaCl SDK comes with a simple
+local server built in, and the process of using it to run PNaCl applications is
+described in :ref:`the tutorial <tutorial_step_2>`.
+
+Native Client applications and the Chrome Web Store
+===================================================
+
 Before reading about how to run Native Client applications, it's important to
 understand a little bit about how Native Client applications are distributed.
 As explained in :doc:`Distributing Your Application <../distributing>`, Native
@@ -43,42 +64,67 @@
 CWS metadata); these are explained in the :ref:`Requirements <requirements>`
 section below.
 
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| Technique | Requires NaCl flag   | Requires web server | Requires CWS metadata | Description |
-+===========+======================+=====================+=======================+=============+
-| 1         | local server         |                     |                       |             |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 2         | packaged application |                     |                       |             |
-|           | loaded as an         |                     |                       |             |
-|           | unpacked extension   |                     |                       |             |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 3         | hosted application   |                     |                       |             |
-|           | loaded as an unpacked|                     |                       |             |
-|           | extension            |                     |                       |             |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 4         | Chrome Web Store     |                     |                       |             |
-|           | application with     |                     |                       |             |
-|           | trusted testers      |                     |                       |             |
-+-----------+----------------------+---------------------+-----------------------+-------------+
+.. list-table::
+   :header-rows: 1
 
-Which of the above techniques you use to run your application during
-development is largely a matter of personal preference (i.e., would you rather
-start a local server or create CWS metadata?). As a general rule, once you have
-an idea of how you plan to distribute your application, you should use the
-corresponding technique during development (technique # 2 for packaged
-applications and extensions; technique # 3 for hosted applications). Choosing a
-distribution option depends on a number of factors such as application size,
-application start-up time, hosting costs, offline functionality, etc. (see
-:doc:`Distributing Your Application <../distributing>` for details), but you
-don't need to make a decision about how to distribute your application at the
-outset.
+   * - #
+     - Technique
+     - Requires NaCl flag
+     - Requires Web Server
+     - Requires CWS Metadata
+     - Description
+   * - 1
+     - Local server
+     - |CHK|
+     - |CHK|
+     -
+     - Run a local server and simply point your browser to your application on
+       the server.
+   * - 2
+     - Packaged application loaded as an unpacked extension
+     -
+     -
+     - |CHK|
+     - Load your packaged application into Chrome as an unpacked extension and
+       run it without a server. An unpacked extension is simply an application
+       whose source and metadata files are located in a plain (unzipped) folder
+       on your development machine. The CWS manifest file (explained below) must
+       specify a ``local_path`` field.
+   * - 3
+     - Hosted application loaded as an unpacked extension
+     -
+     - |CHK|
+     - |CHK|
+     - Load your hosted application into Chrome as an unpacked extension and run
+       it from a server (which can be a local server). The CWS manifest file
+       must specify a ``web_url`` field.
+   * - 4
+     - CWS application with untrusted testers
+     -
+     -
+     - |CHK|
+     - This is the standard technique for distributing a packaged or hosted
+       application in the CWS, but you can limit the application to a few
+       trusted testers. This technique requires a server if your application is
+       a hosted application.
+
+.. |CHK| image:: /images/check-red.png
+
+Which of the above techniques you use to run your application during development
+is largely a matter of personal preference (i.e., would you rather start a local
+server or create CWS metadata?). As a general rule, once you have an idea of how
+you plan to distribute your application, you should use the corresponding
+technique during development. Choosing a distribution option depends on a number
+of factors such as application size, application start-up time, hosting costs,
+offline functionality, etc. (see :doc:`Distributing Your Application
+<../distributing>` for details), but you don't need to make a decision about how
+to distribute your application at the outset.
 
 The next two sections of this document describe a couple of prerequisites for
-running applications during development (using the correct version of Chrome
-and turning off the Chrome cache), and explain the three requirements listed in
-the table above (NaCl flag, web server, and CWS metadata). The subsequent
-sections of the document provide instructions for how to use each of the four
-techniques.
+running applications during development, and explain the three requirements
+listed in the table above (NaCl flag, web server, and CWS metadata). The
+subsequent sections of the document provide instructions for how to use each of
+the four techniques.
 
 Prerequisites
 =============
@@ -91,28 +137,17 @@
 version of the Pepper API. You (and your users) must use a version of Chrome
 that is equal to or higher than the version of the Pepper API that your
 application uses. For example, if you compiled your application using the
-``pepper_28`` bundle, your application uses the Pepper 28 API, and you must run
-the application in Chrome 28 or higher. To check which version of Chrome you're
-using, type ``about:chrome`` or ``about:version`` in the Chrome address bar
-(the latter address shows additional information such as the Chrome command
-line and profile path).
-
-If your application requires a minimum version of Chrome, you are encouraged to
-include code in the application to check that the user's browser is compatible
-with the application. For sample code that checks the user's browser version,
-refer to the ``load_progress`` example in the Native Client SDK.
+``pepper_31`` bundle, your application uses the Pepper 31 API, and you must run
+the application in Chrome 31 or higher. To check which version of Chrome you're
+using, type ``about:version`` in the Chrome address bar.
 
 Chrome Cache
 ------------
 
-Chrome caches resources aggressively. You should disable Chrome's cache
-whenever you are developing a Native Client application in order to make sure
-Chrome loads new versions of your application. To disable the cache:
-
-#. Open Chrome's developer tools by clicking the menu icon |menu-icon| and
-   choosing **Tools > Developer tools**.
-#. Click the gear icon  in the bottom right corner of the Chrome window.
-#. Under the "General" settings, check the box next to "Disable cache".
+Chrome caches resources aggressively. You should disable Chrome's cache whenever
+you are developing a Native Client application in order to make sure Chrome
+loads new versions of your application. Follow the instructions :ref:`in the
+tutorial <tutorial_step_3>`.
 
 .. _requirements:
 
@@ -136,9 +171,9 @@
 #. If the link below "Native Client" says "Enable":
 
    * Click the "Enable" link.
-   * Scroll down to the bottom of the page and click the "Relaunch Now" button.
-     **Native Client will not be enabled until you relaunch your browser**. All
-     browser windows will restart when you relaunch Chrome.
+   * Click the "Relaunch Now" button in the bottom of the screen. **Native
+     Client will not be enabled until you relaunch your browser**. All browser
+     windows will restart when you relaunch Chrome.
 
 If you enable the Native Client flag and still can't run applications from
 outside the Chrome Web Store, you may need to enable the Native Client plugin:
@@ -149,7 +184,6 @@
    the Native Client plugin. You do not need to relaunch Chrome after enabling
    the Native Client plugin.
 
-
 .. _web_server:
 
 Web server
@@ -158,27 +192,22 @@
 For security reasons, Native Client applications must come from a server (you
 can't simply drag HTML files into your browser). The Native Client SDK comes
 with a lightweight Python web server that you can run to serve your application
-locally. The server is included in the ``examples`` directory in the SDK
-bundles (e.g., ``pepper_28/examples``). Here is how to run the server:
+locally. The server can be invoked from a Makefile. Here is how to run the
+server:
 
-* Windows::
+.. naclcode::
+  :prettyprint: 0
 
-    cd examples
-    httpd.cmd
+  $ cd examples
+  $ make serve
 
-* Mac, Linux::
+By default, the server listens for requests on port 5103. You can use the server
+to run most applications under the ``examples`` directory where you started the
+server. For example, to run the ``flock`` example in the SDK, start the server
+and point your browser to http://localhost:5103/demo/flock/.
 
-    cd examples
-    python httpd.py
-
-By default, the server listens for requests on port 5103. To use a different
-port, simply specify a different port number, e.g.: ``python httpd.py 5104``.
-
-You can use the server to run any application under the ``examples`` directory
-where you started the server. For example, to run the
-``hello_world_interactive`` example in the SDK, start the server as described
-above and point your browser to
-http://localhost:5103/hello_world_interactive/hello_world.html.
+Some of the applications need special flags to Chrome, and must be run with the
+``make run`` command. See :ref:`running_the_sdk_examples` for more details.
 
 .. _metadata:
 
@@ -186,17 +215,19 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Applications published in the Chrome Web Store must be accompanied by CWS
-metadata—specifically, a Chrome Web Store manifest file named
+metadata; specifically, a Chrome Web Store manifest file named
 ``manifest.json``, and at least one icon.
 
-Below is an example of a CWS manifest file for a **hosted application**::
+Below is an example of a CWS manifest file for a **hosted application**:
+
+.. naclcode::
 
   {
     "name": "My NaCl App",
     "description": "Simple game implemented using Native Client",
     "version": "0.1",
     "icons": {
-      "128": "nacl_icon_128.jpg"
+      "128": "icon128.png"
     },
     "app": {
       "urls": [
@@ -210,15 +241,17 @@
 
 
 For a **packaged application**, you can omit the urls field, and replace the
-``web_url`` field with a ``local_path`` field, as shown below::
+``web_url`` field with a ``local_path`` field, as shown below:
+
+.. naclcode::
 
   {
     "name": "My NaCl App",
     "description": "Simple game implemented using Native Client",
     "version": "0.1",
     "icons": {
-      "16": "nacl_icon_16.jpg",
-      "128": "nacl_icon_128.jpg"
+      "16": "icon16.png",
+      "128": "icon128.png"
     },
     "app": {
       "launch": {
@@ -230,11 +263,18 @@
 You must put the ``manifest.json`` file in the same directory as your
 application's main HTML page.
 
-If you don't have icons for your application, you can use the following icons
-as placeholders: nacl_icon_16.jpg and nacl_icon_128.jpg. Put the icons in the
-same directory as the CWS manifest file.
+If you don't have icons for your application, you can use the following icons as
+placeholders:
 
-For more information about CWS manifest files and application icons, see:
+|ICON16|
+
+|ICON128|
+
+.. |ICON16| image:: /images/icon16.png
+.. |ICON128| image:: /images/icon128.png
+
+Put the icons in the same directory as the CWS manifest file. For more
+information about CWS manifest files and application icons, see:
 
 * `Chrome Web Store Tutorial: Getting Started
   <https://developers.google.com/chrome/web-store/docs/get_started_simple>`_
@@ -249,7 +289,7 @@
 * Enable the :ref:`Native Client flag <flag>` in Chrome.
 * Start a :ref:`local web server <web_server>`.
 * Put your application under the examples directory in the SDK bundle you are
-  using (e.g., in the directory ``pepper_28/examples/my_app``).
+  using (e.g., in the directory ``pepper_31/examples/my_app``).
 * Access your application on the local server by typing the location of its
   HTML file in Chrome, e.g.:
   ``http://localhost:5103/my_app/my_app_main_page.html``.
@@ -259,7 +299,7 @@
 
   **Note:** You don't have to use a local web server---you can use another
   server if you already have one running. You must still enable the Native
-  Client flag in order to run your application from your server.
+  Client flag in order to run your application from the server.
 
 Technique 2: Packaged application loaded as an unpacked extension
 =================================================================
@@ -297,10 +337,11 @@
 `Chrome Web Store Tutorial: Getting Started
 <https://developers.google.com/chrome/web-store/docs/get_started_simple>`_.
 
+See also :ref:`run_sdk_examples_as_packaged`.
+
 Technique 3: Hosted application loaded as an unpacked extension
 ===============================================================
 
-
 For development purposes, Chrome lets you load a hosted application as an
 unpacked extension. To load and run your hosted application as an unpacked
 extension:
@@ -315,7 +356,7 @@
    * If you're using the local server included with the Native Client SDK,
      simply put your application under the ``examples`` directory in the SDK
      bundle you are using (e.g., in the directory
-     ``pepper_28/examples/my_app``).
+     ``pepper_31/examples/my_app``).
 #. Create a Chrome Web Store manifest file and one or more icons for your
    application.
 
@@ -360,7 +401,8 @@
      your application, as described above under :ref:`Chrome Web Store metadata
      <metadata>`. Note that packaged applications must have at least two icons
      (a 16x16 icon and a 128x128 icon).
-   * You also need to create the following additional assets before you can publish your application:
+   * You also need to create the following additional assets before you can
+     publish your application:
 
      * a screenshot (size must be 640x400 or 1280x800)
      * a promotional image called a "small tile" (size must be 440x280)
diff --git a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
index 3570f1c..ccb87a9 100644
--- a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
+++ b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
@@ -1,8 +1,8 @@
 .. _tutorial:
 
-#############################
-C++ Tutorial: Getting Started
-#############################
+######################################
+C++ Tutorial: Getting Started (Part 1)
+######################################
 
 .. contents::
   :local:
@@ -44,8 +44,9 @@
 message to the server and returns immediately. The Native Client messaging
 system is part of the Pepper API, and is described in detail in
 :doc:`Developer's Guide: Messaging System </devguide/coding/message-system>`.
-
-TODO: would it be better to compare to web-worker communication?
+It is also similar to the way `web workers
+<http://en.wikipedia.org/wiki/Web_worker>`_ interact with the main document in
+JavaScript.
 
 Step 1: Download and install the Native Client SDK
 ==================================================
@@ -143,6 +144,8 @@
 except correctly initialize itself. The JavaScript code waits for the Native
 Client module to load and changes the status text on the web page accordingly.
 
+.. _tutorial_step_5:
+
 Step 5: Compile the Native Client module and run the stub application
 =====================================================================
 
diff --git a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst
new file mode 100644
index 0000000..91c9377
--- /dev/null
+++ b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst
@@ -0,0 +1,496 @@
+.. _tutorial2:
+
+######################################
+C++ Tutorial: Getting Started (Part 2)
+######################################
+
+.. contents::
+  :local:
+  :backlinks: none
+  :depth: 2
+
+Overview
+========
+
+This tutorial shows how to convert the finished PNaCl web application from
+:doc:`Part 1 <tutorial-part1>` to use the Native Client SDK build system and
+common JavaScript files. It also demonstrates some techniques to make your
+web application `Content Security Policy (CSP)-compliant
+<http://developer.chrome.com/apps/contentSecurityPolicy.html>`, which is
+necessary for `Chrome Apps
+<https://developer.chrome.com/apps/about_apps.html>`_.
+
+Using the Native Client SDK build system makes it easy to build with all of the
+SDK toolchains, and switch between the Debug and Release configurations. It
+also simplifies the makefiles for your project, as we'll see in the next
+section. Finally, it adds some useful commands for :ref:`running
+<running_the_sdk_examples>` and :ref:`debugging <debugging_the_sdk_examples>`
+your application.
+
+The finished code for this example can be found in the
+``pepper_$(VERSION)/getting_started/part2`` directory in the Native Client SDK
+download.
+
+Using the Native Client SDK build system
+========================================
+
+This section describes how to use the SDK build system. To do so, we'll make
+changes in the makefile. Because the makefile in part1 and part2 are so
+different, it is easier to start from scratch. Here is the contents of the new
+makefile. The following sections will describe it in more detail.
+
+Simplifying the Makefile
+------------------------
+
+The makefile from part1 only supports one toolchain (PNaCl) and one
+configuration (Release). It also only supports one source file. It's relatively
+simple, but if we want to add support for multiple toolchains, configurations,
+source files, or build steps, it would grow increasingly complex. The SDK build
+system uses a set of variables and macros to make this possible, without
+significantly increasing the complexity of the makefile.
+
+Here is the new makefile, supporting three toolchains (PNaCl, Newlib NaCl,
+Glibc NaCl) and two configurations (Debug, Release).
+
+.. naclcode::
+
+    VALID_TOOLCHAINS := pnacl newlib glibc
+
+    NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
+    include $(NACL_SDK_ROOT)/tools/common.mk
+
+    TARGET = part2
+    LIBS = ppapi_cpp ppapi
+
+    CFLAGS = -Wall
+    SOURCES = hello_tutorial.cc
+
+    # Build rules generated by macros from common.mk:
+
+    $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+    ifeq ($(CONFIG),Release)
+    $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+    $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+    else
+    $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+    endif
+
+    $(eval $(call NMF_RULE,$(TARGET),))
+
+Choosing valid toolchains, and including common.mk
+--------------------------------------------------
+
+The makefile begins by specifying the toolchains that are valid for this
+project. The Native Client SDK build system supports multi-toolchain projects
+for its examples and libraries, but generally you will choose one toolchain
+when you begin your project and never change it. Please see the
+:ref:`Toolchains section of the Native Client overview <toolchains>` for more
+information.
+
+For this example, we support the ``pnacl``, ``newlib`` and ``glibc`` toolchains.
+
+.. naclcode::
+
+    VALID_TOOLCHAINS := pnacl newlib glibc
+
+Next, as a convenience, we specify where to find ``NACL_SDK_ROOT``. Because
+this example is located in ``pepper_$(VERSION)/getting_started/part2``, the
+root of the SDK is two directories up.
+
+.. naclcode::
+
+    NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
+
+.. Note::
+  :class: note
+
+   In your own projects, you can use the absolute path to your installed SDK
+   here. You can also override this default by setting the ``NACL_SDK_ROOT``
+   environment variable. See :ref:`Step 5 of Part 1 of this tutorial
+   <tutorial_step_5>` for more details.
+
+Next, we include the file ``tools/common.mk``. This file provides the
+functionality for the Native Client SDK build system, including new build rules
+to compile and link a project, which we'll use below.
+
+.. naclcode::
+
+  include $(NACL_SDK_ROOT)/tools/common.mk
+
+Configuring your project
+------------------------
+
+After including ``tools/common.mk``, we configure the project by specifying its
+name, the sources and libraries it uses:
+
+.. naclcode::
+
+    TARGET = part2
+    LIBS = ppapi_cpp ppapi
+
+    CFLAGS = -Wall
+    SOURCES = hello_tutorial.cc
+
+These variable names are not required and not used by the SDK build system;
+they are only used in the rules described below. By convention, all SDK
+makefiles use the following variables:
+
+TARGET
+  The name of the project to build. This variable determines the name of the
+  library or executable that will be generated. In the above example, we call
+  the target ``part2``, which will generate an executable called
+  ``part2.pexe`` for PNaCl. For NaCl toolchains, the executable's file name
+  will be given a suffix for its architecture. For example, the ARM executable
+  is called ``part2_arm.nexe``.
+
+LIBS
+  A list of libraries that this executable needs to link against. The library
+  search path is already set up to only look in the directory for the current
+  toolchain and architecture. In this example, we link against ``ppapi_cpp``
+  and ``ppapi``. ``ppapi_cpp`` is needed to use the `Pepper C++ interface
+  <https://developers.google.com/native-client/peppercpp/>`_. ``ppapi`` is
+  needed for communicating with the browser.
+
+CFLAGS
+  A list of extra flags to pass to the compiler. In this example, we pass
+  ``-Wall``, which turns on all warnings.
+
+LDFLAGS
+  A list of additional flags to pass to the linker. This example does not need
+  any special linker flags, so this variable is omitted.
+
+SOURCES
+  A list of C or C++ sources to compile, separated by spaces. If you have a
+  long list of sources, it may be easier to read if you put each file on its
+  own line, and use ``\`` as a line-continuation character. Here's an example:
+
+.. naclcode::
+
+    SOURCES = foo.cc \
+              bar.cc \
+              baz.cc \
+              quux.cc
+
+Build macros
+------------
+
+For many projects, the following build macros do not need to be changed; they
+will use the variables we've defined above.
+
+.. naclcode::
+
+    $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+    ifeq ($(CONFIG),Release)
+    $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+    $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+    else
+    $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+    endif
+
+    $(eval $(call NMF_RULE,$(TARGET),))
+
+The first line defines rules to compile each source in ``SOURCES``, using the
+flags in ``CFLAGS``:
+
+.. naclcode::
+
+    $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+The next six lines define rules to link the object files into one or more
+executables. When ``TOOLCHAIN`` is ``pnacl``, there is only one executable
+generated: in the example above, ``part2.pexe``. When using a NaCl toolchain,
+there will be three executables generated, one for each architecture: in the
+example above, ``part2_arm.nexe``, ``part2_x86_32.nexe`` and
+``part2_x86_64.nexe``.
+
+When ``CONFIG`` is ``Release``, each executable is also stripped to remove
+debug information and reduce the file size:
+
+.. naclcode::
+
+    ifeq ($(CONFIG),Release)
+    $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+    $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+    else
+    $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+    endif
+
+Finally, the NMF rule generates a NaCl manifest file (``.nmf``) that references
+each executable generated in the previous step:
+
+.. naclcode::
+
+    $(eval $(call NMF_RULE,$(TARGET),))
+
+Making index.html work for Chrome Apps
+======================================
+
+This section describes the changes necessary to make the HTML and JavaScript
+in part1 CSP-compliant. This is required if you want to build a `Chrome App
+<https://developer.chrome.com/apps/about_apps.html>`_, but is not necessary
+if you want to use PNaCl on the open web.
+
+CSP rules
+---------
+
+`Chrome Apps CSP
+<http://developer.chrome.com/apps/contentSecurityPolicy.html#what>`_
+restricts you from doing the following:
+
+* You can’t use inline scripting in your Chrome App pages. The restriction
+  bans both ``<script>`` blocks and event handlers (``<button onclick="...">``).
+* You can’t reference any external resources in any of your app files (except
+  for video and audio resources). You can’t embed external resources in an
+  iframe.
+* You can’t use string-to-JavaScript methods like ``eval()`` and ``new
+  Function()``.
+
+Making index.html CSP-compliant
+-------------------------------
+
+To make our application CSP-compliant, we have to remove inline scripting. As
+described above, we can't use inline ``<script>`` blocks or event handlers. This
+is easy to do---we'll just reference some new files from our script tag, and
+remove all of our inlined scripts:
+
+.. naclcode::
+
+    <head>
+      ...
+      <script type="text/javascript" src="common.js"></script>
+      <script type="text/javascript" src="example.js"></script>
+    </head>
+
+``common.js`` has shared code used by all SDK examples, and is described
+later in this document. ``example.js`` is a script that has code specific to
+this example.
+
+We also need to remove the inline event handler on the body tag:
+
+.. naclcode::
+
+  <body onload="pageDidLoad()">
+  ...
+
+This logic is now handled by ``common.js``.
+
+Making index.html support different toolchains and configurations
+-----------------------------------------------------------------
+
+Finally, there are a few changes to ``index.html`` that are not necessary for
+CSP-compliance, but help make the SDK examples more generic.
+
+First, we add some `data attributes
+<https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes>`_
+to the body element to specify the name, supported toolchains, supported
+configurations, and path to the ``.nmf`` file:
+
+.. naclcode::
+
+    <body data-name="part2"
+        data-tools="newlib glibc pnacl"
+        data-configs="Debug Release"
+        data-path="{tc}/{config}">
+    ...
+
+``common.js`` will read these data attributes to allow you to load the same
+example with different toolchains by changing the URL's `query string
+<http://en.wikipedia.org/wiki/Query_string>`_. For example, you can load the
+glibc Debug version of this example by navigating to
+``index.html?tc=glibc&config=Debug``.
+
+Next, we remove the ``embed`` element that is described in HTML. This will be
+automatically added for us by ``common.js``, based on the current
+toolchain/configuration combination:
+
+.. naclcode::
+
+    <!--
+    Just as in part1, the <embed> element will be wrapped inside the <div>
+    element with the id "listener". In part1, the embed was specified in HTML,
+    here the common.js module creates a new <embed> element and adds it to the
+    <div> for us.
+    -->
+    <div id="listener"></div>
+
+Sharing common code with common.js
+==================================
+
+``common.js`` contains JavaScript code that each example uses to create a
+NaCl module, handle messages from that module and other common tasks like
+displaying the module load status and logging messages. Explaining all of
+``common.js`` is outside the scope of this document, but please look at the
+documentation in that file for more information.
+
+Loading the page and creating the module
+----------------------------------------
+
+Since we've added ``<script>`` tags for ``common.js`` and ``example.js`` to the
+``head`` element, they will be loaded and executed before the rest of the
+document has been parsed. As a result, we have to wait for the page to finish
+loading before we try to create the embed element and add it to the page.
+
+We can do that by calling ``addEventListener`` and listening for the
+``DOMContentLoaded`` event:
+
+.. naclcode::
+
+    // Listen for the DOM content to be loaded. This event is fired when parsing of
+    // the page's document has finished.
+    document.addEventListener('DOMContentLoaded', function() {
+      ...
+    });
+
+Inside this function, we parse the URL query string, and compare that to the
+data attributes:
+
+.. naclcode::
+
+    // From https://developer.mozilla.org/en-US/docs/DOM/window.location
+    var searchVars = {};
+    if (window.location.search.length > 1) {
+      var pairs = window.location.search.substr(1).split('&');
+      for (var key_ix = 0; key_ix < pairs.length; key_ix++) {
+        var keyValue = pairs[key_ix].split('=');
+        searchVars[unescape(keyValue[0])] =
+            keyValue.length > 1 ? unescape(keyValue[1]) : '';
+      }
+    }
+
+    ...
+
+    var toolchains = body.dataset.tools.split(' ');
+    var configs = body.dataset.configs.split(' ');
+
+    ...
+
+    var tc = toolchains.indexOf(searchVars.tc) !== -1 ?
+        searchVars.tc : toolchains[0];
+
+    // If the config value is included in the search vars, use that.
+    // Otherwise default to Release if it is valid, or the first value if
+    // Release is not valid.
+    if (configs.indexOf(searchVars.config) !== -1)
+      var config = searchVars.config;
+    else if (configs.indexOf('Release') !== -1)
+      var config = 'Release';
+    else
+      var config = configs[0];
+
+Then ``domContentLoaded`` is called, which performs some checks to see if the
+browser supports Native Client, then creates the NaCl module.
+
+.. naclcode::
+
+    function domContentLoaded(name, tool, path, width, height, attrs) {
+      updateStatus('Page loaded.');
+      if (!browserSupportsNaCl(tool)) {
+        updateStatus(
+            'Browser does not support NaCl (' + tool + '), or NaCl is disabled');
+      } else if (common.naclModule == null) {
+        updateStatus('Creating embed: ' + tool);
+
+        // We use a non-zero sized embed to give Chrome space to place the bad
+        // plug-in graphic, if there is a problem.
+        width = typeof width !== 'undefined' ? width : 200;
+        height = typeof height !== 'undefined' ? height : 200;
+        attachDefaultListeners();
+        createNaClModule(name, tool, path, width, height, attrs);
+      } else {
+        // It's possible that the Native Client module onload event fired
+        // before the page's onload event.  In this case, the status message
+        // will reflect 'SUCCESS', but won't be displayed.  This call will
+        // display the current message.
+        updateStatus('Waiting.');
+      }
+    }
+
+``attachDefaultListeners`` is added before the creation of the module, to make
+sure that no messages are lost. Note that ``window.attachListeners`` is also
+called; this is the way that ``common.js`` allows each example to configure
+itself differently. If an example defines the ``attachListeners`` function, it
+will be called by ``common.js``.
+
+.. naclcode::
+
+    function attachDefaultListeners() {
+      var listenerDiv = document.getElementById('listener');
+      listenerDiv.addEventListener('load', moduleDidLoad, true);
+      listenerDiv.addEventListener('message', handleMessage, true);
+      listenerDiv.addEventListener('crash', handleCrash, true);
+      if (typeof window.attachListeners !== 'undefined') {
+        window.attachListeners();
+      }
+    }
+
+Finally, ``createNaClModule`` actually creates the ``embed``, and appends it as
+a child of the element with id ``listener``:
+
+.. naclcode::
+
+    function createNaClModule(name, tool, path, width, height, attrs) {
+      var moduleEl = document.createElement('embed');
+      moduleEl.setAttribute('name', 'nacl_module');
+      moduleEl.setAttribute('id', 'nacl_module');
+      moduleEl.setAttribute('width', width);
+      moduleEl.setAttribute('height', height);
+      moduleEl.setAttribute('path', path);
+      moduleEl.setAttribute('src', path + '/' + name + '.nmf');
+
+      ...
+
+      var mimetype = mimeTypeForTool(tool);
+      moduleEl.setAttribute('type', mimetype);
+
+      var listenerDiv = document.getElementById('listener');
+      listenerDiv.appendChild(moduleEl);
+      ...
+    }
+
+When the module finishes loading, it will dispatch a ``load`` event, and the
+event listener function that was registered above (``moduleDidLoad``) will be
+called. Note that ``common.js`` allows each example to define a
+``window.moduleDidLoad`` function, that will be called here as well.
+
+.. naclcode::
+
+    function moduleDidLoad() {
+      common.naclModule = document.getElementById('nacl_module');
+      updateStatus('RUNNING');
+
+      if (typeof window.moduleDidLoad !== 'undefined') {
+        window.moduleDidLoad();
+      }
+    }
+
+Example-specific behavior with example.js
+=========================================
+
+As described in the previous section, ``common.js`` will call certain functions
+during the module loading process. This example only needs to respond to two:
+``moduleDidLoad`` and ``handleMessage``.
+
+.. naclcode::
+
+    // This function is called by common.js when the NaCl module is
+    // loaded.
+    function moduleDidLoad() {
+      // Once we load, hide the plugin. In this example, we don't display anything
+      // in the plugin, so it is fine to hide it.
+      common.hideModule();
+
+      // After the NaCl module has loaded, common.naclModule is a reference to the
+      // NaCl module's <embed> element.
+      //
+      // postMessage sends a message to it.
+      common.naclModule.postMessage('hello');
+    }
+
+    // This function is called by common.js when a message is received from the
+    // NaCl module.
+    function handleMessage(message) {
+      var logEl = document.getElementById('log');
+      logEl.textContent += message.data;
+    }
diff --git a/native_client_sdk/src/doc/faq.rst b/native_client_sdk/src/doc/faq.rst
index 021c475..6ac764d 100644
--- a/native_client_sdk/src/doc/faq.rst
+++ b/native_client_sdk/src/doc/faq.rst
@@ -63,7 +63,11 @@
   gains support for new processors and fully uses their capabilities.
 
 .. TODO Expand on the PNaCl performance section in another document, and
-.. link to it here.
+.. link to it here. How does one profile PNaCl code? What are common
+.. causes of slowness? How can code be made faster? What's the best way
+.. to use Pepper's asynchronous APIs? What do I need to know about
+.. threads and inter-thread communications? Can I use SIMD or other
+.. processor-specific instructions? What aboutt he GPU?
 
 For more details, refer to the :doc:`history behind and comparison of
 NaCl and PNaCl <nacl-and-pnacl>`.
@@ -91,29 +95,40 @@
 See :doc:`NaCl and PNaCl <nacl-and-pnacl>`. In short: PNaCl works on the
 open web whereas NaCl only works on the Chrome Web Store.
 
-How fast does code run in Native Client?
-----------------------------------------
+How fast does code run in Portable Native Client?
+-------------------------------------------------
 
-Fast! Benchmarks on x86-32 measured an average performance overhead of
-less than 5% compared to native C/C++ on applications such as Quake,
-bzip2, and Google Earth. For details of those benchmarks, see `Native
-Client: A Sandbox for Portable, Untrusted x86 Code
-<https://src.chromium.org/viewvc/native_client/data/docs_tarball/nacl/googleclient/native_client/documentation/nacl_paper.pdf>`_
-(PDF).
+Fast! The SPEC2k benchmarks (C, C++ and floating-point benchmarks) give
+the following overhead for optimized PNaCl compared to regular optimized
+LLVM:
 
-Benchmarks on x86-64 and ARM measured an average performance overhead of
-less than 5% on ARM and 7% on x86-64; however, benchmark performance was
-bimodal for x86-64, so different use cases are likely to achieve either
-significantly better or significantly worse performance than that
-average. For details, see `Adapting Software Fault Isolation to
-Contemporary CPU Architectures
-<https://nativeclient.googlecode.com/svn/data/site/NaCl_SFI.pdf>`_ (PDF).
++--------+-----+
+| x86-32 | 15% |
++--------+-----+
+| x86-64 | 20% |
++--------+-----+
+|  ARM   | 10% |
++--------+-----+
 
-.. TODO Update performance numbers.
+Note that benchmark performance is sometimes bimodal, so different use
+cases are likely to achieve better or worse performance than the above
+averages. For example floating-point heavy code usually exhibits much
+lower overheads whereas very branch-heavy code often performs worse.
+
+For details, see:
+
+* `Adapting Software Fault Isolation to Contemporary CPU Architectures
+  <https://nativeclient.googlecode.com/svn/data/site/NaCl_SFI.pdf>`_
+  (PDF).
+* `Native Client: A Sandbox for Portable, Untrusted x86 Code
+  <https://src.chromium.org/viewvc/native_client/data/docs_tarball/nacl/googleclient/native_client/documentation/nacl_paper.pdf>`_
+  (PDF).
 
 If your code isn't performing as close to native speed as you'd expect,
 :doc:`let us know <help>`!
 
+.. TODO Link to the non-existent performance page! (see above todo).
+
 Why use Portable Native Client instead of *<technology X>*?
 -----------------------------------------------------------
 
@@ -151,11 +166,8 @@
 self-hosting a full development environment on Portable Native Client.
 
 Any editor+shell combination should work as well as IDEs like Eclipse,
-Visual Studio with the `Native Client Add-In
-<https://developers.google.com/native-client/dev/devguide/devcycle/vs-addin>`_
-on Windows, or Xcode on Mac OSX.
-
-.. TODO: update link to Visual Studio when ReST-ified.
+Visual Studio with the :doc:`Native Client Add-In
+<devguide/devcycle/vs-addin>` on Windows, or Xcode on Mac OSX.
 
 I'm not familiar with native development tools, can I still use the Native Client SDK?
 --------------------------------------------------------------------------------------
@@ -184,10 +196,8 @@
 
 We consistenly try to document our design and implementation and hope to
 standardize Portable Native Client when it gains more traction. A good
-example is our `PNaCl bitcode reference manual
-<http://www.chromium.org/nativeclient/pnacl/bitcode-abi>`_.
-
-.. TODO Update the above bitcode-abi link to a :doc: once 3693 is fixed.
+example is our :doc:`PNaCl bitcode reference manual
+<reference/pnacl-bitcode-abi>`.
 
 What are the supported instruction set architectures?
 -----------------------------------------------------
@@ -210,6 +220,8 @@
 architectures without requiring recompilation. The web is better when
 it's platform-independent, and we'd like it to stay that way.
 
+.. _other_languages:
+
 Do I have to use C or C++? I'd really like to use another language.
 -------------------------------------------------------------------
 
@@ -274,12 +286,8 @@
 
 
 To alert the user regarding their hardware platform's 3D feature set
-before loading a large NaCl application, see `Vetting the driver in
-Javascript
-<https://developers.google.com/native-client/devguide/coding/3D-graphics>`_.
-
-.. TODO Update link to point to the right place in the document once
-.. it's ReST-ified.
+before loading a large NaCl application, see :doc:`Vetting the driver in
+Javascript <devguide/coding/3D-graphics>`.
 
 Some GL extensions are exposed to Native Client applications, see the
 `GL ES 2 file
@@ -301,13 +309,13 @@
 allowing your Native Client application to utilize several CPU cores.
 Note that this allows you to modify datastructures concurrently without
 needing to copy them, which is often a limitation of shared-nothing
-systems.
+systems. For more information see :ref:`memory model and atomics
+<memory_model_and_atomics>` and :ref:`threading
+<language_support_threading>`.
 
 Native Client doesn't support HTML5 Web Workers directly but can
 interact with JavaScript code which does.
 
-.. TODO Add link to relevant documentation, once written.
-
 
 Coming Soon
 ===========
@@ -387,13 +395,10 @@
 works, including:
 
 * Open source, peer-reviewed papers describing the design.
-* A `security contest
-  <https://developers.google.com/native-client/community/security-contest/>`_.
+* A :doc:`security contest <community/security-contest/index>`.
 * Multiple internal and external security reviews.
 * The ongoing vigilance of our engineering and developer community.
 
-.. TODO: Fix security contest link once ReST-ified.
-
 Google is committed to making Native Client safer than JavaScript and
 other popular browser technologies. If you have suggestions for security
 improvements, let the team know, by way of the `native-client-discuss
diff --git a/native_client_sdk/src/doc/images/3d-graphics-render-loop.png b/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
index 66e1121..3d2aac5 100644
--- a/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
+++ b/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/icon128.png b/native_client_sdk/src/doc/images/icon128.png
new file mode 100644
index 0000000..a10c52a
--- /dev/null
+++ b/native_client_sdk/src/doc/images/icon128.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/icon16.png b/native_client_sdk/src/doc/images/icon16.png
new file mode 100644
index 0000000..0a8d70c
--- /dev/null
+++ b/native_client_sdk/src/doc/images/icon16.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/naclmounts1.png b/native_client_sdk/src/doc/images/nacl_io1.png
similarity index 100%
rename from native_client_sdk/src/doc/images/naclmounts1.png
rename to native_client_sdk/src/doc/images/nacl_io1.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/pepper-audio-api.png b/native_client_sdk/src/doc/images/pepper-audio-api.png
index c3fd236..cbce867 100644
--- a/native_client_sdk/src/doc/images/pepper-audio-api.png
+++ b/native_client_sdk/src/doc/images/pepper-audio-api.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/pepper-audio-buffer.png b/native_client_sdk/src/doc/images/pepper-audio-buffer.png
index 10654f7..d7a55be 100644
--- a/native_client_sdk/src/doc/images/pepper-audio-buffer.png
+++ b/native_client_sdk/src/doc/images/pepper-audio-buffer.png
Binary files differ
diff --git a/native_client_sdk/src/doc/index.rst b/native_client_sdk/src/doc/index.rst
index 2d33727..194a00b 100644
--- a/native_client_sdk/src/doc/index.rst
+++ b/native_client_sdk/src/doc/index.rst
@@ -19,6 +19,7 @@
    devguide/index.rst
    devguide/tutorial/index.rst
    devguide/tutorial/tutorial-part1.rst
+   devguide/tutorial/tutorial-part2.rst
    devguide/devcycle/index.rst
    devguide/devcycle/building.rst
    devguide/devcycle/running.rst
@@ -31,6 +32,7 @@
    devguide/coding/application-structure.rst
    devguide/coding/native-client-modules.rst
    devguide/coding/FileIO.rst
+   devguide/coding/nacl_io.rst
    devguide/coding/message-system.rst
    devguide/coding/progress-events.rst
    devguide/coding/url-loading.rst
@@ -46,6 +48,7 @@
    peppercpp/index.rst
    reference/index.rst
    reference/pnacl-bitcode-abi.rst
+   reference/pnacl-c-cpp-language-support.rst
    reference/nacl-manifest-format.rst
    publications-and-presentations.rst
    faq.rst
diff --git a/native_client_sdk/src/doc/nacl-and-pnacl.rst b/native_client_sdk/src/doc/nacl-and-pnacl.rst
index 82cde79..caa8352 100644
--- a/native_client_sdk/src/doc/nacl-and-pnacl.rst
+++ b/native_client_sdk/src/doc/nacl-and-pnacl.rst
@@ -115,3 +115,6 @@
   ``newlib``). Dynamic linking and ``glibc`` are not yet supported.
   Work is under way to enable dynamic linking in future versions of PNaCl.
 * In the initial release, PNaCl does not support C++ exception handling. 
+* In the initial release, PNaCl does not support vector types and SIMD.
+* In the initial release, PNaCl does not support some GNU extensions like
+  taking the address of a label for computed gotos, or nested functions.
diff --git a/native_client_sdk/src/doc/overview.rst b/native_client_sdk/src/doc/overview.rst
index 3a5efed..e8ad2d7 100644
--- a/native_client_sdk/src/doc/overview.rst
+++ b/native_client_sdk/src/doc/overview.rst
@@ -181,6 +181,8 @@
 For more details on the difference between NaCl and PNaCl, see
 :doc:`NaCl and PNaCl <nacl-and-pnacl>`.
 
+.. _toolchains:
+
 Toolchains
 ----------
 
diff --git a/native_client_sdk/src/doc/publications-and-presentations.rst b/native_client_sdk/src/doc/publications-and-presentations.rst
index 5d27f0c..ccf5dc7 100644
--- a/native_client_sdk/src/doc/publications-and-presentations.rst
+++ b/native_client_sdk/src/doc/publications-and-presentations.rst
@@ -155,46 +155,3 @@
 porting process on their blog.
 
 `Read more <http://carbongames.com/2012/01/Native-Client>`__
-
-Porting XaoS
-^^^^^^^^^^^^
-
-Google engineers ported `XaoS <http://xaos.sourceforge.net/english.php>`_, an
-interactive graphical exploration tool for fractals, to Native Client. Many of
-the porting problems they encountered are quite common, and the techniques
-described here should help with similar porting efforts. Some of the background
-information might also benefit those who are writing new Native Client
-applications.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/xaos>`__
-
-.. TODO Fix link once it is ReST-ified.
-
-Porting MAME
-^^^^^^^^^^^^
-
-Multiple Arcade Machine Emulator (`MAME <http://mamedev.org>`_) is an
-emulator for a large number of classic arcade games. Google engineers
-ported it to Native Client. This article discusses the overall porting
-strategy, dealing with ``newlib`` incompatibilities, and handling
-binaries that are built and run as part of the build process.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/MAME>`__
-
-.. TODO Fix link once it is ReST-ified.
-
-How to Port SDL Games
-^^^^^^^^^^^^^^^^^^^^^
-
-`Simple Directmedia Layer <http://www.libsdl.org>`_ (SDL) is a popular
-library that many games and applications use to access sound and video
-capabilities on end-user machines. Native Client bindings for SDL are
-available on naclports, making it possible to port SDL-based games to
-Native Client. This article by Google engineers describes how to
-complete such a port, focusing on writing the glue code for fusing your
-game with the Pepper APIs.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/SDLgames>`__
diff --git a/native_client_sdk/src/doc/reference/nacl-manifest-format.rst b/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
index a218a69..a61cf55 100644
--- a/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
+++ b/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
@@ -180,20 +180,15 @@
   }
 
 
-Dynamic libraries that the dynamic program depends upon and links in
-at program startup must be listed in the ``files`` dictionary.
-Library files that are loaded after startup using ``dlopen()`` should either
-be listed in the ``files`` dictionary, or should be made accessible
-by the ``nacl_io`` library.  The ``nacl_io`` library provides various
-file system *mounts* such as HTTP-based file systems and memory-based
-file systems. The Native Client SDK includes helpful tools for
-determining library dependencies and generating NaCl manifest files
-for programs that that use dynamic linking. See
-`Generating a Native Client manifest file for a dynamically linked application
-<https://developers.google.com/native-client/devguide/devcycle/dynamic-loading#manifest>`_.
-
-.. TODO(jvoung) update the link when glibc document is linkable.
-
+Dynamic libraries that the dynamic program depends upon and links in at program
+startup must be listed in the ``files`` dictionary. Library files that are
+loaded after startup using ``dlopen()`` should either be listed in the ``files``
+dictionary, or should be made accessible by the ``nacl_io`` library.  The
+``nacl_io`` library provides various file system *mounts* such as HTTP-based
+file systems and memory-based file systems. The Native Client SDK includes
+helpful tools for determining library dependencies and generating NaCl manifest
+files for programs that that use dynamic linking. See
+:ref:`dynamic_loading_manifest`.
 
 Semantics
 =========
diff --git a/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst b/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
index b4cf4e8..0aa9a99 100644
--- a/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
+++ b/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
@@ -77,13 +77,12 @@
 
 Restrictions on global variables:
 
-* PNaCl bitcode does not support LLVM IR TLS models.
+* PNaCl bitcode does not support LLVM IR TLS models. See
+  :ref:`language_support_threading` for more details.
 * Restrictions on :ref:`linkage types <bitcode_linkagetypes>`.
 * The ``addrspace``, ``section``, ``unnamed_addr`` and
   ``externally_initialized`` attributes are not supported.
 
-.. TODO: link to developer's guide to explain TLS in more detail
-
 Every global variable must have an initializer. Each initializer must be
 either a *SimpleElement* or a *CompoundElement*, defined as follows.
 
@@ -162,9 +161,7 @@
 
 PNaCl bitcode does not support volatile memory accesses. The
 ``volatile`` attribute on loads and stores is not supported. See the
-`PNaCl Developer's Guide <PNaClDeveloperGuide.html>`_ for more details.
-
-.. TODO: link to developers guide once it's ported
+:doc:`pnacl-c-cpp-language-support` for more details.
 
 Memory Model for Concurrent Operations
 --------------------------------------
diff --git a/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst b/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst
new file mode 100644
index 0000000..bcbce53
--- /dev/null
+++ b/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst
@@ -0,0 +1,222 @@
+============================
+PNaCl C/C++ Language Support
+============================
+
+.. contents::
+   :local:
+   :backlinks: none
+   :depth: 3
+
+Source language support
+=======================
+
+The currently supported languages are C and C++. The PNaCl toolchain is
+based on Clang 3.3, which fully supports C++11 and most of C11. A
+detailed status of the language support is available `here
+<http://clang.llvm.org/cxx_status.html>`_.
+
+For information on using languages other than C/C++, see the :ref:`FAQ
+section on other languages <other_languages>`.
+
+As for the standard libraries, the PNaCl toolchain is currently based on
+``libstdc++`` version 4.6.1, and the ``newlib`` standard C library
+(version is available through the macro ``NEWLIB_VERSION``).
+Experimental ``libc++`` support is also included; see
+:ref:`building_cpp_libraries` for more details.
+
+Preprocessor definitions
+------------------------
+
+When compiling C/C++ code, the PNaCl toolchain defines the ``__pnacl__``
+macro. In addition, ``__native_client__`` is defined for compatibility
+with other NaCl toolchains.
+
+.. _memory_model_and_atomics:
+
+Memory Model and Atomics
+========================
+
+Memory Model for Concurrent Operations
+--------------------------------------
+
+The memory model offered by PNaCl relies on the same coding guidelines
+as the C11/C++11 one: concurrent accesses must always occur through
+atomic primitives (offered by `atomic intrinsics
+<PNaClLangRef.html#atomicintrinsics>`_), and these accesses must always
+occur with the same size for the same memory location. Visibility of
+stores is provided on a happens-before basis that relates memory
+locations to each other as the C11/C++11 standards do.
+
+Non-atomic memory accesses may be reordered, separated, elided or fused
+according to C and C++'s memory model before the pexe is created as well
+as after its creation.
+
+As in C11/C++11 some atomic accesses may be implemented with locks on
+certain platforms. The ``ATOMIC_*_LOCK_FREE`` macros will always be
+``1``, signifying that all types are sometimes lock-free. The
+``is_lock_free`` methods and ``atomic_is_lock_free`` will return the
+current platform's implementation at translation time. These macros,
+methods and functions are in the C11 header ``<stdatomic.h>`` and the
+C++11 header ``<atomic>``.
+
+The PNaCl toolchain supports concurrent memory accesses through legacy
+GCC-style ``__sync_*`` builtins, as well as through C11/C++11 atomic
+primitives. ``volatile`` memory accesses can also be used, though these
+are discouraged. See `Volatile Memory Accesses`_.
+
+PNaCl supports concurrency and parallelism with some restrictions:
+
+* Threading is explicitly supported and has no restrictions over what
+  prevalent implementations offer. See `Threading`_.
+
+* ``volatile`` and atomic operations are address-free (operations on the
+  same memory location via two different addresses work atomically), as
+  intended by the C11/C++11 standards. This is critical in supporting
+  synchronous "external modifications" such as mapping underlying memory
+  at multiple locations.
+
+* Inter-process communication through shared memory is currently not
+  supported. See `Future Directions`_.
+
+* Signal handling isn't supported, PNaCl therefore promotes all
+  primitives to cross-thread (instead of single-thread). This may change
+  at a later date. Note that using atomic operations which aren't
+  lock-free may lead to deadlocks when handling asynchronous
+  signals. See `Future Directions`_.
+
+* Direct interaction with device memory isn't supported, and there is no
+  intent to support it. The embedding sandbox's runtime can offer APIs
+  to indirectly access devices.
+
+Setting up the above mechanisms requires assistance from the embedding
+sandbox's runtime (e.g. NaCl's Pepper APIs), but using them once setup
+can be done through regular C/C++ code.
+
+Atomic Memory Ordering Constraints
+----------------------------------
+
+Atomics follow the same ordering constraints as in regular C11/C++11,
+but all accesses are promoted to sequential consistency (the strongest
+memory ordering) at pexe creation time. We plan to support more of the
+C11/C++11 memory orderings in the future.
+
+Some additional restrictions, following the C11/C++11 standards:
+
+- Atomic accesses must at least be naturally aligned.
+- Some accesses may not actually be atomic on certain platforms,
+  requiring an implementation that uses global locks.
+- An atomic memory location must always be accessed with atomic
+  primitives, and these primitives must always be of the same bit size
+  for that location.
+- Not all memory orderings are valid for all atomic operations.
+
+Volatile Memory Accesses
+------------------------
+
+The C11/C++11 standards mandate that ``volatile`` accesses execute in
+program order (but are not fences, so other memory operations can
+reorder around them), are not necessarily atomic, and can’t be
+elided. They can be separated into smaller width accesses.
+
+Before any optimizations occur, the PNaCl toolchain transforms
+``volatile`` loads and stores into sequentially consistent ``volatile``
+atomic loads and stores, and applies regular compiler optimizations
+along the above guidelines. This orders ``volatiles`` according to the
+atomic rules, and means that fences (including ``__sync_synchronize``)
+act in a better-defined manner. Regular memory accesses still do not
+have ordering guarantees with ``volatile`` and atomic accesses, though
+the internal representation of ``__sync_synchronize`` attempts to
+prevent reordering of memory accesses to objects which may escape.
+
+Relaxed ordering could be used instead, but for the first release it is
+more conservative to apply sequential consistency. Future releases may
+change what happens at compile-time, but already-released pexes will
+continue using sequential consistency.
+
+The PNaCl toolchain also requires that ``volatile`` accesses be at least
+naturally aligned, and tries to guarantee this alignment.
+
+The above guarantees ease the support of legacy (i.e. non-C11/C++11)
+code, and combined with builtin fences these programs can do meaningful
+cross-thread communication without changing code. They also better
+reflect the original code's intent and guarantee better portability.
+
+.. _language_support_threading:
+
+Threading
+=========
+
+Threading is explicitly supported through C11/C++11's threading
+libraries as well as POSIX threads.
+
+Communication between threads should use atomic primitives as described
+in `Memory Model and Atomics`_.
+
+``setjmp`` and ``longjmp``
+==========================
+
+PNaCl and NaCl support ``setjmp`` and ``longjmp`` without any
+restrictions beyond C's.
+
+Inline Assembly
+===============
+
+Inline assembly isn't supported by PNaCl because it isn't portable. The
+one current exception is the common compiler barrier idiom
+``asm("":::"memory")``, which gets transformed to a sequentially
+consistent memory barrier (equivalent to ``__sync_synchronize()``). In
+PNaCl this barrier is only guaranteed to order ``volatile`` and atomic
+memory accesses, though in practice the implementation attempts to also
+prevent reordering of memory accesses to objects which may escape.
+
+NaCl supports a fairly wide subset of inline assembly through GCC's
+inline assembly syntax, with the restriction that the sandboxing model
+for the target architecture has to be respected.
+
+Future Directions
+=================
+
+SIMD
+----
+
+PNaCl currently doesn't support SIMD. We plan to add SIMD support in the
+very near future.
+
+NaCl supports SIMD.
+
+Inter-Process Communication
+---------------------------
+
+Inter-process communication through shared memory is currently not
+supported by PNaCl/NaCl. When implemented, it may be limited to
+operations which are lock-free on the current platform (``is_lock_free``
+methods). It will rely on the address-free properly discussed in `Memory
+Model for Concurrent Operations`_.
+
+Signal Handling
+---------------
+
+Signal handling from user code currently isn't supported by PNaCl. When
+supported, the impact of ``volatile`` and atomics for same-thread signal
+handling will need to be carefully detailed.
+
+NaCl supports signal handling.
+
+Exception Handling
+------------------
+
+PNaCl currently doesn't support exception handling. It supports the
+usual ``-fno-exceptions`` flag, and by default it transforms all
+``throw`` statements into ``abort``. We plan to add exception-handling
+support in the very near future, and zero-cost exception handling soon
+thereafter.
+
+NaCl supports exception handling.
+
+Computed ``goto``
+-----------------
+
+PNaCl currently doesn't support computed ``goto``, a non-standard
+extension to C used by some interpreters.
+
+NaCl supports computed ``goto``.
diff --git a/native_client_sdk/src/doc/sdk/examples.rst b/native_client_sdk/src/doc/sdk/examples.rst
index 73c6a33..22404d4 100644
--- a/native_client_sdk/src/doc/sdk/examples.rst
+++ b/native_client_sdk/src/doc/sdk/examples.rst
@@ -159,6 +159,8 @@
 use the SDK toolchain itself, see :doc:`Building Native Client Modules
 <../devguide/devcycle/building>`.
 
+.. _running_the_sdk_examples:
+
 Run the SDK examples
 --------------------
 
@@ -202,6 +204,7 @@
 
   $ make run TOOLCHAIN=pnacl CONFIG=Debug
 
+.. _run_sdk_examples_as_packaged:
 
 Run the SDK examples as packaged apps
 -------------------------------------
diff --git a/native_client_sdk/src/examples/api/file_io/example.js b/native_client_sdk/src/examples/api/file_io/example.js
index 3fdc741..6143fd5 100644
--- a/native_client_sdk/src/examples/api/file_io/example.js
+++ b/native_client_sdk/src/examples/api/file_io/example.js
@@ -12,8 +12,8 @@
     function(bytes) {
       common.updateStatus(
           'Allocated ' + bytes + ' bytes of persistant storage.');
-      common.createNaClModule(name, tc, config, width, height);
       common.attachDefaultListeners();
+      common.createNaClModule(name, tc, config, width, height);
     },
     function(e) { alert('Failed to allocate space') });
 }
diff --git a/native_client_sdk/src/examples/demo/drive/example.dsc b/native_client_sdk/src/examples/demo/drive/example.dsc
index 8efe744..2f83aa1 100644
--- a/native_client_sdk/src/examples/demo/drive/example.dsc
+++ b/native_client_sdk/src/examples/demo/drive/example.dsc
@@ -8,13 +8,6 @@
       'LIBS': ['jsoncpp', 'ppapi_cpp', 'ppapi', 'pthread']
     }
   ],
-  'PRE': """
-#
-# We use the chrome.experimental.identity API, which requires the
-# --enable-experimental-expension-apis flag.
-#
-CHROME_ARGS += --enable-experimental-extension-apis
-""",
   'DATA': [
     'example.js',
   ],
@@ -23,7 +16,7 @@
   'TITLE': 'Google Drive',
   'GROUP': 'Demo',
   'PERMISSIONS': [
-    'experimental',
+    'identity',
     'https://www.googleapis.com/*/drive/*',
     'https://*.googleusercontent.com/*'
   ]
diff --git a/native_client_sdk/src/examples/demo/drive/example.js b/native_client_sdk/src/examples/demo/drive/example.js
index ce4279b..ae6326f 100644
--- a/native_client_sdk/src/examples/demo/drive/example.js
+++ b/native_client_sdk/src/examples/demo/drive/example.js
@@ -7,7 +7,7 @@
 var authToken = '';
 
 function getAuthToken(interactive) {
-  chrome.experimental.identity.getAuthToken(
+  chrome.identity.getAuthToken(
       {'interactive': interactive}, onGetAuthToken);
 }
 
@@ -38,7 +38,7 @@
 
   // Make sure this example is running as a packaged app. If not, display a
   // warning.
-  if (!chrome.experimental) {
+  if (!chrome.identity) {
     common.updateStatus('Error: must be run as a packged app.');
     return;
   }
diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.js b/native_client_sdk/src/examples/demo/nacl_io/example.js
index 6de6afb..0ccaf7d 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/example.js
+++ b/native_client_sdk/src/examples/demo/nacl_io/example.js
@@ -12,8 +12,8 @@
       function(bytes) {
         common.updateStatus(
             'Allocated ' + bytes + ' bytes of persistant storage.');
-        common.createNaClModule(name, tc, config, width, height);
         common.attachDefaultListeners();
+        common.createNaClModule(name, tc, config, width, height);
       },
       function(e) { alert('Failed to allocate space') });
 }
diff --git a/native_client_sdk/src/examples/tutorial/debugging/example.js b/native_client_sdk/src/examples/tutorial/debugging/example.js
index 7542844..3016eb7 100644
--- a/native_client_sdk/src/examples/tutorial/debugging/example.js
+++ b/native_client_sdk/src/examples/tutorial/debugging/example.js
@@ -6,8 +6,8 @@
 var crashed = false;
 
 function domContentLoaded(name, tc, config, width, height) {
-  common.createNaClModule(name, tc, config, width, height);
   common.attachDefaultListeners();
+  common.createNaClModule(name, tc, config, width, height);
 
   updateStatus('Page Loaded');
 }
diff --git a/native_client_sdk/src/gonacl_appengine/README b/native_client_sdk/src/gonacl_appengine/README
index ab51466..22db557 100644
--- a/native_client_sdk/src/gonacl_appengine/README
+++ b/native_client_sdk/src/gonacl_appengine/README
@@ -1,25 +1,65 @@
+GoNaCl App Engine
+=================
+
 This is a new App Engine Python 2.7 application for http://gonacl.com
 
 At this time it presents the existing functionality of redirecting
 to http://developers.google.com/native-client/
 
-Also, there are PNaCl demos added at /static/pnacl-demo-<name>/index.html
+Also, there are PNaCl demos added at ``/static/pnacl-demo-<name>/index.html``
 
-To upload, run this from the root directory of the AppEngine SDK:
 
-$ ./appcfg.py update <path-to-this-dir>
+To Run Locally
+--------------
+
+1. Download the App Engine SDK (https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python)
+
+2. Run ``<path/to/app/engine>/dev_appserver.py app.yaml``
+
+3. Navigate in your browser to http://localhost:8080/static/
+
+
+To Update App Engine (HTML/JS)
+------------------------------
+
+To upload, run this from the root directory of the App Engine SDK::
+
+    $ ./appcfg.py update <path-to-this-dir>
 
 It probably makes sense to bump the application version in app.yaml for each
-upload, as it lets us use AppEngine's versioning. The newly uploaded version can
-be tried before actually being activated, by going to the "Versions" section on
-the AppEngine dashboard. Note that the newly uploaded version only becomes
-active when it's set as the "default" version in the dashboard.
+upload, as it lets us use App Engine's versioning. The newly uploaded version
+can be tried before actually being activated, by going to the "Versions"
+section on the App Engine dashboard. Note that the newly uploaded version only
+becomes active when it's set as the "default" version in the dashboard.
 
-Included demos:
 
-* static/pnacl-demo-earth: the modified Earth demo.
-* static/pnacl-demo-bullet: a demo of bullet physics, using NaCl acceleration
-    modules.
+To Update the Binary files (.pexe/.nmf)
+---------------------------------------
 
-Only the source files (HTML and JS) are kept in source control. The pexe and
-images should be copied over from an SDK build when uploading to AppEngine.
+The build outputs are automatically uploaded to Google Cloud Storage
+(``commondatastorage.googleapis.com``) by the linux SDK builder
+(linux-sdk-multi).
+To publish a new version:
+
+1. Make and land your change to the demo, found in ``src/<demo-name>``.
+
+2. Wait for the linux SDK builder to build and upload your change. You can see
+   what's available by using gsutil::
+
+       $ gsutil ls gs://gonacl/demos/continuous
+
+       gs://gonacl/demos/continuous/229855/
+       gs://gonacl/demos/continuous/229860/
+       ...
+
+3. Update the URLs to use this new revision in each demo's JavaScript files:
+
+  * For ``earth``, this is found in ``/static/pnacl-demo-earth/example.js``, in
+    the ``getDataURL`` function.
+
+  * For ``bullet``, this is found in ``/static/pnacl-demo-bullet/main.js``, in
+    the ``pageDidLoad`` function.
+
+4. Land a CL with these changes.
+
+5. Update App Engine, using the instructions above.
diff --git a/native_client_sdk/src/gonacl_appengine/app.yaml b/native_client_sdk/src/gonacl_appengine/app.yaml
index 60a8fa1..6dbc6f0 100644
--- a/native_client_sdk/src/gonacl_appengine/app.yaml
+++ b/native_client_sdk/src/gonacl_appengine/app.yaml
@@ -22,3 +22,6 @@
 
 - url: /.*
   script: gonacl.application
+
+skip_files:
+- src/.*
diff --git a/native_client_sdk/src/gonacl_appengine/src/Makefile b/native_client_sdk/src/gonacl_appengine/src/Makefile
new file mode 100644
index 0000000..aef5995
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/Makefile
@@ -0,0 +1,255 @@
+# Copyright (c) 2013 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.
+
+#
+# This script allows you to build, upload, and publish demo binaries that will
+# go on Google Cloud Storage (commondatastorage).
+#
+# NOTE: you normally should not upload examples. This will be done
+# automatically by the buildbots.
+#
+# Building
+# --------
+#
+# * Build all examples.
+#
+#     $ make
+#
+# * Build a specific example.
+#
+#     $ make bullet
+#
+# Uploading
+# ---------
+#
+# * Build and upload all examples.
+#
+#     $ make upload REVISION=1234
+#
+# * Build and upload a single example
+#
+#     $ make upload-bullet REVISION=1234
+#
+# Publishing
+# ----------
+#
+# * Publish binaries for all examples.
+#
+#     $ make publish REVISION=1234
+#
+# * Publish binaries for one example.
+#
+#     $ make publish-bullet REVISION=1234
+#
+
+ifeq (,$(NACL_SDK_ROOT))
+  $(error NACL_SDK_ROOT is not defined)
+endif
+
+# Define default build target
+all:
+
+#
+# All projects built by this Makefile
+#
+PROJECTS = earth voronoi life bullet lua
+
+GS_URL_CONTINUOUS = gs://gonacl/demos/continuous
+GS_URL_PUBLISH = gs://gonacl/demos/publish
+
+#
+# Each project must define the following variables. All paths should be
+# absolute paths.
+#
+# foo_SRCS: src files for this project
+# foo_TGTS: generated files for this project
+# foo_EXTRA_UPLOADS: additional files to upload for this project (optional)
+#
+# And a recipe to build TGTS from SRCS:
+# $(foo_TGTS): $(foo_SRCS)
+# 	...
+#
+
+#
+# Earth
+#
+earth_SRC_DIR = earth
+earth_TGT_DIR = earth/pnacl/Release
+earth_JPG_DIR = ../../examples/demo/earth
+earth_SRCS = $(earth_SRC_DIR)/earth.cc \
+             $(earth_SRC_DIR)/Makefile
+earth_TGTS = $(earth_TGT_DIR)/earth.pexe \
+             $(earth_TGT_DIR)/earth.nmf
+earth_JPGS = $(earth_JPG_DIR)/earth.jpg \
+             $(earth_JPG_DIR)/earthnight.jpg
+earth_EXTRA_UPLOADS = $(earth_JPGS)
+
+$(earth_TGTS): $(earth_SRCS)
+	$(MAKE) -C earth TOOLCHAIN=pnacl CONFIG=Release
+
+
+#
+# Bullet
+#
+bullet_SRC_DIR = bullet
+bullet_TGT_DIR = bullet/out
+bullet_SRCS = $(bullet_SRC_DIR)/build.sh \
+              $(bullet_SRC_DIR)/Makefile
+bullet_TGTS = $(bullet_TGT_DIR)/NaClAMBullet.pexe \
+              $(bullet_TGT_DIR)/NaClAMBullet.nmf
+
+$(bullet_TGTS): $(bullet_SRCS)
+	bullet/build.sh
+
+#
+# Lua
+#
+lua_SRC_DIR = lua
+lua_TGT_DIR = lua/out/naclports/src/out/publish/lua/pnacl
+lua_SRCS = $(lua_SRC_DIR)/build.sh
+lua_TGTS = $(lua_TGT_DIR)/lua.pexe \
+           $(lua_TGT_DIR)/luadata.tar \
+           $(lua_TGT_DIR)/lua.nmf \
+           $(lua_TGT_DIR)/hterm.concat.js
+
+$(lua_TGTS): $(lua_SRCS)
+	lua/build.sh
+
+#
+# Voronoi
+#
+voronoi_SRC_DIR = voronoi
+voronoi_TGT_DIR = voronoi/pnacl/Release
+voronoi_SRCS = $(voronoi_SRC_DIR)/voronoi.cc \
+               $(voronoi_SRC_DIR)/Makefile
+voronoi_TGTS = $(voronoi_TGT_DIR)/voronoi.pexe \
+               $(voronoi_TGT_DIR)/voronoi.nmf
+
+$(voronoi_TGTS): $(voronoi_SRCS)
+	$(MAKE) -C voronoi TOOLCHAIN=pnacl CONFIG=Release
+
+#
+# Life
+#
+life_SRC_DIR = life
+life_TGT_DIR = life/pnacl/Release
+life_SRCS = $(life_SRC_DIR)/life.c \
+            $(life_SRC_DIR)/Makefile
+life_TGTS = $(life_TGT_DIR)/life.pexe \
+            $(life_TGT_DIR)/life.nmf
+
+$(life_TGTS): $(life_SRCS)
+	$(MAKE) -C life TOOLCHAIN=pnacl CONFIG=Release
+
+###############################################################################
+
+SHELL = /bin/bash
+
+OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
+GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
+WHICH := $(OSHELPERS) which
+
+# Try the location of gsutil on the bots first...
+BOT_GSUTIL = /b/build/scripts/slave/gsutil
+ifneq (,$(wildcard $(BOT_GSUTIL)))
+  GSUTIL = $(BOT_GSUTIL)
+else
+  GSUTIL = $(shell $(WHICH) gsutil)
+  ifeq (,$(wildcard $(GSUTIL)))
+    $(error Unable to find gstuil)
+  endif
+endif
+
+#
+# Define some variables for the given project.
+#
+# FOO_UPLOADS:
+#     All files to upload for this project.
+# FOO_CONTINUOUS_DIR:
+#     URL of the continuous build directory for this
+#     project and revision.
+# FOO_CONTINUOUS_UPLOADS:
+#     URLs of all files that will be uploaded for this
+#     project and revision.
+# FOO_PUBLISH_DIR:
+#     URL of the publish directory for this project and revision.
+#
+# $1 = NAME (e.g. earth)
+#
+define PROJECT
+  $(1)_UPLOADS = $$($(1)_TGTS) $$($(1)_EXTRA_UPLOADS)
+  $(1)_CONTINUOUS_DIR = $(GS_URL_CONTINUOUS)/$(REVISION)/$(1)
+  $(1)_CONTINUOUS_UPLOADS = $$(addprefix $$($(1)_CONTINUOUS_DIR)/,$$(notdir $$($(1)_UPLOADS)))
+  $(1)_PUBLISH_DIR = $(GS_URL_PUBLISH)/$(REVISION)/$(1)
+
+  all: $$($(1)_TGTS)
+
+  .PHONY: $(1)
+  $(1): $$($(1)_TGTS)
+endef
+
+
+#
+# Define rules to upload the project files to the continuous builder directory
+# on CDS.
+#
+# $1 = NAME (e.g. earth)
+#
+define UPLOAD_RULE
+.PHONY: upload-$(1)
+upload-$(1): revision-check
+	@echo "Uploading $$(notdir $$($(1)_UPLOADS)) to $$($(1)_CONTINUOUS_DIR)"
+	@$(GSUTIL) cp -q -a public-read $$($(1)_UPLOADS) $$($(1)_CONTINUOUS_DIR)
+
+upload: upload-$(1)
+endef
+
+#
+# Define rules to copy the project files from the continuous builder
+# directory to the publish directory.
+#
+# $1 = NAME (e.g. earth)
+#
+define PUBLISH_RULE
+.PHONY: publish-$(1)
+publish-$(1): revision-check
+	@echo "Testing that files to publish '$(1)' exist on CDS..."
+	@$(GSUTIL) ls $$($(1)_CONTINUOUS_UPLOADS)
+	@echo OK.
+	@echo "About to publish revision $(REVISION) of '$(1)'..."
+	@read -p "Continue? " -n 1 -r && \
+	  echo && \
+	  if [[ ! $$$${REPLY} =~ ^[Yy]$$$$ ]]; then \
+	    exit 1; \
+	  fi;
+	@echo "Publishing..."
+	@$(GSUTIL) cp -p -q $$($(1)_CONTINUOUS_UPLOADS) $$($(1)_PUBLISH_DIR)/
+	@echo "Done."
+
+publish: publish-$(1)
+endef
+
+
+###############################################################################
+# RULES
+
+.PHONY: all
+all:
+
+$(foreach project,$(PROJECTS),$(eval $(call PROJECT,$(project))))
+
+.PHONY: revision-check
+revision-check:
+ifeq (,$(REVISION))
+	$(error Unknown revision number. Run with REVSION=<...>)
+endif
+
+.PHONY: upload
+upload: all
+
+.PHONY: publish
+publish:
+
+$(foreach project,$(PROJECTS),$(eval $(call UPLOAD_RULE,$(project))))
+$(foreach project,$(PROJECTS),$(eval $(call PUBLISH_RULE,$(project))))
diff --git a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
index a327933..5ac2185 100755
--- a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
+++ b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
@@ -6,6 +6,17 @@
 set -o nounset
 set -o errexit
 
+SCRIPT_DIR="$(cd $(dirname $0) && pwd)"
+cd ${SCRIPT_DIR}
+
+OUT_DIR=out
+NACLPORTS_URL=https://chromium.googlesource.com/external/naclports
+NACLPORTS_SHA=0096083c0fa71c014f6218bb14d7e1742d9a6b0c
+NACLPORTS_DIR=${OUT_DIR}/naclports
+NACLAM_URL=https://github.com/johnmccutchan/NaClAMBase
+NACLAM_DIR=${OUT_DIR}/NaClAMBase
+NACLAM_SHA=0eb4647a3f99c6e66156959edc6c55d4a913468a
+
 if [ -z "${NACL_SDK_ROOT:-}" ]; then
   echo "-------------------------------------------------------------------"
   echo "NACL_SDK_ROOT is unset."
@@ -31,13 +42,18 @@
 Clone() {
   local url=$1
   local dir=$2
+  local sha=$3
   if [ ! -d $dir ]; then
     LogExecute git clone $url $dir
   else
     pushd $dir
-    LogExecute git pull origin master
+    LogExecute git fetch origin
     popd
   fi
+
+  pushd $dir
+  LogExecute git checkout $sha
+  popd
 }
 
 readonly OS_NAME=$(uname -s)
@@ -49,13 +65,8 @@
   OS_JOBS=1
 fi
 
-NACLPORTS_URL=https://chromium.googlesource.com/external/naclports
-NACLPORTS_DIR=naclports
-NACLAM_URL=https://github.com/johnmccutchan/NaClAMBase
-NACLAM_DIR=NaClAMBase
-
 Banner Cloning naclports
-Clone ${NACLPORTS_URL} ${NACLPORTS_DIR}
+Clone ${NACLPORTS_URL} ${NACLPORTS_DIR} ${NACLPORTS_SHA}
 
 Banner Building bullet
 pushd ${NACLPORTS_DIR}
@@ -63,7 +74,7 @@
 popd
 
 Banner Cloning NaClAMBase
-Clone ${NACLAM_URL} ${NACLAM_DIR}
+Clone ${NACLAM_URL} ${NACLAM_DIR} ${NACLAM_SHA}
 
 Banner Building NaClAM
 LogExecute cp Makefile ${NACLAM_DIR}
@@ -71,6 +82,6 @@
 LogExecute make -j${OS_JOBS}
 popd
 
-LogExecute cp ${NACLAM_DIR}/pnacl/Release/NaClAMBullet.{pexe,nmf} .
+LogExecute cp ${NACLAM_DIR}/pnacl/Release/NaClAMBullet.{pexe,nmf} ${OUT_DIR}
 
 Banner Done!
diff --git a/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore b/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore
new file mode 100644
index 0000000..b370218
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore
@@ -0,0 +1 @@
+pnacl
diff --git a/native_client_sdk/src/gonacl_appengine/src/life/Makefile b/native_client_sdk/src/gonacl_appengine/src/life/Makefile
new file mode 100644
index 0000000..e016af6
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/life/Makefile
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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.
+
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
+
+VALID_TOOLCHAINS := newlib glibc pnacl
+
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)
+include $(NACL_SDK_ROOT)/tools/common.mk
+
+TARGET = life
+LIBS = $(DEPS) ppapi_simple nacl_io sdk_util ppapi_cpp ppapi pthread
+
+CFLAGS = -Wall
+SOURCES = life.c
+
+# Build rules generated by macros from common.mk:
+
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ifeq ($(CONFIG),Release)
+$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+else
+$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+endif
+
+$(eval $(call NMF_RULE,$(TARGET),))
diff --git a/native_client_sdk/src/gonacl_appengine/src/life/life.c b/native_client_sdk/src/gonacl_appengine/src/life/life.c
new file mode 100644
index 0000000..4dbf57f
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/life/life.c
@@ -0,0 +1,317 @@
+/* Copyright (c) 2013 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 <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_view.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_main.h"
+
+PPB_Core* g_pCore;
+PPB_Graphics2D* g_pGraphics2D;
+PPB_ImageData* g_pImageData;
+PPB_Instance* g_pInstance;
+PPB_View* g_pView;
+PPB_InputEvent* g_pInputEvent;
+PPB_KeyboardInputEvent* g_pKeyboardInput;
+PPB_MouseInputEvent* g_pMouseInput;
+PPB_TouchInputEvent* g_pTouchInput;
+
+struct {
+  PP_Resource ctx;
+  struct PP_Size size;
+  int bound;
+  uint8_t* cell_in;
+  uint8_t* cell_out;
+} g_Context;
+
+
+const unsigned int kInitialRandSeed = 0xC0DE533D;
+
+/* BGRA helper macro, for constructing a pixel for a BGRA buffer. */
+#define MakeBGRA(b, g, r, a)  \
+  (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+
+/*
+ * Given a count of cells in a 3x3 grid where cells are worth 1 except for
+ * the center which is worth 9, this is a color representation of how
+ * "alive" that cell is making for a more interesting representation than
+ * a binary alive or dead.
+ */
+const uint32_t kNeighborColors[] = {
+    MakeBGRA(0x00, 0x00, 0x00, 0xff),
+    MakeBGRA(0x00, 0x40, 0x00, 0xff),
+    MakeBGRA(0x00, 0x60, 0x00, 0xff),
+    MakeBGRA(0x00, 0x80, 0x00, 0xff),
+    MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+    MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+    MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+    MakeBGRA(0x00, 0x00, 0x00, 0xff),
+    MakeBGRA(0x00, 0x40, 0x00, 0xff),
+    MakeBGRA(0x00, 0x60, 0x00, 0xff),
+    MakeBGRA(0x00, 0x80, 0x00, 0xff),
+    MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+    MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+    MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+    MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+    MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+    MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+    MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+};
+
+/*
+ * These represent the new health value of a cell based on its neighboring
+ * values.  The health is binary: either alive or dead.
+ */
+const uint8_t kIsAlive[] = {
+      0, 0, 0, 1, 0, 0, 0, 0, 0,  /* Values if the center cell is dead. */
+      0, 0, 1, 1, 0, 0, 0, 0, 0   /* Values if the center cell is alive. */
+};
+
+void UpdateContext(uint32_t width, uint32_t height) {
+  if (width != g_Context.size.width || height != g_Context.size.height) {
+    size_t size = width * height;
+    size_t index;
+
+    free(g_Context.cell_in);
+    free(g_Context.cell_out);
+
+    /* Create a new context */
+    g_Context.cell_in = (uint8_t*) malloc(size);
+    g_Context.cell_out = (uint8_t*) malloc(size);
+
+    memset(g_Context.cell_out, 0, size);
+    for (index = 0; index < size; index++) {
+      g_Context.cell_in[index] = rand() & 1;
+    }
+  }
+
+  /* Recreate the graphics context on a view change */
+  g_pCore->ReleaseResource(g_Context.ctx);
+  g_Context.size.width = width;
+  g_Context.size.height = height;
+  g_Context.ctx =
+      g_pGraphics2D->Create(PSGetInstanceId(), &g_Context.size, PP_TRUE);
+  g_Context.bound =
+      g_pInstance->BindGraphics(PSGetInstanceId(), g_Context.ctx);
+}
+
+void DrawCell(int32_t x, int32_t y) {
+  int32_t width = g_Context.size.width;
+  int32_t height = g_Context.size.height;
+
+  if (!g_Context.cell_in) return;
+
+  if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+    g_Context.cell_in[x - 1 + y * width] = 1;
+    g_Context.cell_in[x + 1 + y * width] = 1;
+    g_Context.cell_in[x + (y - 1) * width] = 1;
+    g_Context.cell_in[x + (y + 1) * width] = 1;
+  }
+}
+
+void ProcessTouchEvent(PSEvent* event) {
+  uint32_t count = g_pTouchInput->GetTouchCount(event->as_resource,
+      PP_TOUCHLIST_TYPE_TOUCHES);
+  uint32_t i, j;
+  for (i = 0; i < count; i++) {
+    struct PP_TouchPoint touch = g_pTouchInput->GetTouchByIndex(
+        event->as_resource, PP_TOUCHLIST_TYPE_TOUCHES, i);
+    int radius = (int)touch.radius.x;
+    int x = (int)touch.position.x;
+    int y = (int)touch.position.y;
+    /* num = 1/100th the area of touch point */
+    int num = (int)(M_PI * radius * radius / 100.0f);
+    for (j = 0; j < num; j++) {
+      int dx = rand() % (radius * 2) - radius;
+      int dy = rand() % (radius * 2) - radius;
+      /* only plot random cells within the touch area */
+      if (dx * dx + dy * dy <= radius * radius)
+        DrawCell(x + dx, y + dy);
+    }
+  }
+}
+
+void ProcessEvent(PSEvent* event) {
+  switch(event->type) {
+    /* If the view updates, build a new Graphics 2D Context */
+    case PSE_INSTANCE_DIDCHANGEVIEW: {
+      struct PP_Rect rect;
+
+      g_pView->GetRect(event->as_resource, &rect);
+      UpdateContext(rect.size.width, rect.size.height);
+      break;
+    }
+
+    case PSE_INSTANCE_HANDLEINPUT: {
+      PP_InputEvent_Type type = g_pInputEvent->GetType(event->as_resource);
+      PP_InputEvent_Modifier modifiers =
+          g_pInputEvent->GetModifiers(event->as_resource);
+
+      switch(type) {
+        case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+        case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
+          struct PP_Point location =
+              g_pMouseInput->GetPosition(event->as_resource);
+          /* If the button is down, draw */
+          if (modifiers & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
+            DrawCell(location.x, location.y);
+          }
+          break;
+        }
+
+        case PP_INPUTEVENT_TYPE_TOUCHSTART:
+        case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+          ProcessTouchEvent(event);
+          break;
+
+        default:
+          break;
+      }
+      /* case PSE_INSTANCE_HANDLEINPUT */
+      break;
+    }
+
+    default:
+      break;
+  }
+}
+
+
+void Stir(uint32_t width, uint32_t height) {
+  int i;
+  if (g_Context.cell_in == NULL || g_Context.cell_out == NULL)
+    return;
+
+  for (i = 0; i < width; ++i) {
+    g_Context.cell_in[i] = rand() & 1;
+    g_Context.cell_in[i + (height - 1) * width] = rand() & 1;
+  }
+  for (i = 0; i < height; ++i) {
+    g_Context.cell_in[i * width] = rand() & 1;
+    g_Context.cell_in[i * width + (width - 1)] = rand() & 1;
+  }
+}
+
+void Render() {
+  struct PP_Size* psize = &g_Context.size;
+  PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL;
+
+  /*
+   * Create a buffer to draw into.  Since we are waiting until the next flush
+   * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h.
+   */
+  PP_Resource image =
+      g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE);
+  uint8_t* pixels = g_pImageData->Map(image);
+
+  struct PP_ImageDataDesc desc;
+  uint8_t* cell_temp;
+  uint32_t x, y;
+
+  /* If we somehow have not allocated these pointers yet, skip this frame. */
+  if (!g_Context.cell_in || !g_Context.cell_out) return;
+
+  /* Get the stride. */
+  g_pImageData->Describe(image, &desc);
+
+  /* Stir up the edges to prevent the simulation from reaching steady state. */
+  Stir(desc.size.width, desc.size.height);
+
+  /* Do neighbor summation; apply rules, output pixel color. */
+  for (y = 1; y < desc.size.height - 1; ++y) {
+    uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1;
+    uint8_t *src1 = src0 + desc.size.width;
+    uint8_t *src2 = src1 + desc.size.width;
+    int count;
+    uint32_t color;
+    uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1;
+    uint32_t *pixel_line =  (uint32_t*) (pixels + y * desc.stride);
+
+    for (x = 1; x < (desc.size.width - 1); ++x) {
+      /* Build sum, weight center by 9x. */
+      count = src0[-1] + src0[0] +     src0[1] +
+              src1[-1] + src1[0] * 9 + src1[1] +
+              src2[-1] + src2[0] +     src2[1];
+      color = kNeighborColors[count];
+
+      *pixel_line++ = color;
+      *dst++ = kIsAlive[count];
+      ++src0;
+      ++src1;
+      ++src2;
+    }
+  }
+
+  cell_temp = g_Context.cell_in;
+  g_Context.cell_in = g_Context.cell_out;
+  g_Context.cell_out = cell_temp;
+
+  /* Unmap the range, we no longer need it. */
+  g_pImageData->Unmap(image);
+
+  /* Replace the contexts, and block until it's on the screen. */
+  g_pGraphics2D->ReplaceContents(g_Context.ctx, image);
+  g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete());
+
+  /* Release the image data, we no longer need it. */
+  g_pCore->ReleaseResource(image);
+}
+
+/*
+ * Starting point for the module.  We do not use main since it would
+ * collide with main in libppapi_cpp.
+ */
+int example_main(int argc, char *argv[]) {
+  fprintf(stdout,"Started main.\n");
+  g_pCore = (PPB_Core*)PSGetInterface(PPB_CORE_INTERFACE);
+  g_pGraphics2D = (PPB_Graphics2D*)PSGetInterface(PPB_GRAPHICS_2D_INTERFACE);
+  g_pInstance = (PPB_Instance*)PSGetInterface(PPB_INSTANCE_INTERFACE);
+  g_pImageData = (PPB_ImageData*)PSGetInterface(PPB_IMAGEDATA_INTERFACE);
+  g_pView = (PPB_View*)PSGetInterface(PPB_VIEW_INTERFACE);
+
+  g_pInputEvent =
+      (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE);
+  g_pKeyboardInput = (PPB_KeyboardInputEvent*)
+      PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE);
+  g_pMouseInput =
+      (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE);
+  g_pTouchInput =
+      (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE);
+
+  PSEventSetFilter(PSE_ALL);
+  while (1) {
+    /* Process all waiting events without blocking */
+    PSEvent* event;
+    while ((event = PSEventTryAcquire()) != NULL) {
+      ProcessEvent(event);
+      PSEventRelease(event);
+    }
+
+    /* Render a frame, blocking until complete. */
+    if (g_Context.bound) {
+      Render();
+    }
+  }
+  return 0;
+}
+
+/*
+ * Register the function to call once the Instance Object is initialized.
+ * see: pappi_simple/ps_main.h
+ */
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore b/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore
new file mode 100644
index 0000000..1fcb152
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore
@@ -0,0 +1 @@
+out
diff --git a/native_client_sdk/src/gonacl_appengine/src/lua/build.sh b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh
new file mode 100755
index 0000000..3891fa9
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# Copyright (c) 2012 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.
+
+set -o nounset
+set -o errexit
+set -o xtrace
+
+SCRIPT_DIR="$(cd $(dirname $0) && pwd)"
+cd ${SCRIPT_DIR}
+
+OUT_DIR=out
+NACLPORTS_URL=http://naclports.googlecode.com/svn/trunk/src
+NACLPORTS_REV=939
+NACLPORTS_DIR=${OUT_DIR}/naclports
+
+if [ -z "${NACL_SDK_ROOT:-}" ]; then
+  echo "-------------------------------------------------------------------"
+  echo "NACL_SDK_ROOT is unset."
+  echo "This environment variable needs to be pointed at some version of"
+  echo "the Native Client SDK (the directory containing toolchain/)."
+  echo "NOTE: set this to an absolute path."
+  echo "-------------------------------------------------------------------"
+  exit -1
+fi
+
+Banner() {
+  echo "######################################################################"
+  echo $*
+  echo "######################################################################"
+}
+
+# echo a command to stdout and then execute it.
+LogExecute() {
+  echo $*
+  $*
+}
+
+Clone() {
+  local url=$1
+  local dir=$2
+  local sha=$3
+  if [ ! -d $dir ]; then
+    LogExecute git clone $url $dir
+  else
+    pushd $dir
+    LogExecute git fetch origin
+    popd
+  fi
+
+  pushd $dir
+  LogExecute git checkout $sha
+  popd
+}
+
+Banner Cloning naclports
+if [ ! -d ${NACLPORTS_DIR} ]; then
+  mkdir -p ${NACLPORTS_DIR}
+  pushd ${NACLPORTS_DIR}
+  gclient config --name=src ${NACLPORTS_URL}
+  popd
+fi
+
+pushd ${NACLPORTS_DIR}
+gclient sync -r ${NACLPORTS_REV}
+popd
+
+Banner Building lua
+pushd ${NACLPORTS_DIR}/src
+make NACL_ARCH=pnacl lua_ppapi
+popd
+
+Banner Done!
diff --git a/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile b/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile
new file mode 100644
index 0000000..089bf90
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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.
+
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
+
+VALID_TOOLCHAINS := newlib glibc pnacl
+
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)
+include $(NACL_SDK_ROOT)/tools/common.mk
+
+TARGET = voronoi
+LIBS = $(DEPS) ppapi_simple nacl_io sdk_util ppapi_cpp ppapi pthread
+
+CFLAGS = -Wall
+SOURCES = voronoi.cc
+
+# Build rules generated by macros from common.mk:
+
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ifeq ($(CONFIG),Release)
+$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+else
+$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+endif
+
+$(eval $(call NMF_RULE,$(TARGET),))
diff --git a/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc b/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc
new file mode 100644
index 0000000..1e30047
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc
@@ -0,0 +1,499 @@
+// Copyright (c) 2013 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 <assert.h>
+#include <math.h>
+#include <ppapi/c/ppb_input_event.h>
+#include <ppapi/cpp/input_event.h>
+#include <ppapi/cpp/var.h>
+#include <ppapi/cpp/var_array.h>
+#include <ppapi/cpp/var_array_buffer.h>
+#include <ppapi/cpp/var_dictionary.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_main.h"
+#include "sdk_util/thread_pool.h"
+
+using namespace sdk_util;  // For sdk_util::ThreadPool
+
+// Global properties used to setup Voronoi demo.
+namespace {
+const int kMinRectSize = 4;
+const int kStartRecurseSize = 32;  // must be power-of-two
+const float kHugeZ = 1.0e38f;
+const float kPI = M_PI;
+const float kTwoPI = kPI * 2.0f;
+const unsigned int kRandomStartSeed = 0xC0DE533D;
+const int kMaxPointCount = 1024;
+const int kStartPointCount = 48;
+const int kDefaultNumRegions = 256;
+
+unsigned int g_rand_state = kRandomStartSeed;
+
+// random number helper
+inline unsigned char rand255() {
+  return static_cast<unsigned char>(rand_r(&g_rand_state) & 255);
+}
+
+// random number helper
+inline float frand() {
+  return (static_cast<float>(rand_r(&g_rand_state)) /
+      static_cast<float>(RAND_MAX));
+}
+
+// reset random seed
+inline void rand_reset(unsigned int seed) {
+  g_rand_state = seed;
+}
+
+inline uint32_t next_pow2(uint32_t x) {
+  // Via Hacker's Delight, section 3.2 "Rounding Up/Down to the Next Power of 2"
+  --x;
+  x |= (x >> 1);
+  x |= (x >> 2);
+  x |= (x >> 4);
+  x |= (x >> 8);
+  x |= (x >> 16);
+  return x + 1;
+}
+
+// BGRA helper function, for constructing a pixel for a BGRA buffer.
+inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
+  return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
+}
+}  // namespace
+
+// Vec2, simple 2D vector
+struct Vec2 {
+  float x, y;
+  Vec2() {}
+  Vec2(float px, float py) {
+    x = px;
+    y = py;
+  }
+  void Set(float px, float py) {
+    x = px;
+    y = py;
+  }
+};
+
+// The main object that runs Voronoi simulation.
+class Voronoi {
+ public:
+  Voronoi();
+  virtual ~Voronoi();
+  // Runs a tick of the simulations, update 2D output.
+  void Update();
+  // Handle event from user, or message from JS.
+  void HandleEvent(PSEvent* ps_event);
+
+ private:
+  // Methods prefixed with 'w' are run on worker threads.
+  uint32_t* wGetAddr(int x, int y);
+  int wCell(float x, float y);
+  inline void wFillSpan(uint32_t *pixels, uint32_t color, int width);
+  void wRenderTile(int x, int y, int w, int h);
+  void wProcessTile(int x, int y, int w, int h);
+  void wSubdivide(int x, int y, int w, int h);
+  void wMakeRect(int region, int *x, int *y, int *w, int *h);
+  bool wTestRect(int *m, int x, int y, int w, int h);
+  void wFillRect(int x, int y, int w, int h, uint32_t color);
+  void wRenderRect(int x0, int y0, int x1, int y1);
+  void wRenderRegion(int region);
+  static void wRenderRegionEntry(int region, void *thiz);
+
+  // These methods are only called by the main thread.
+  void Reset();
+  void UpdateSim();
+  void RenderDot(float x, float y, uint32_t color1, uint32_t color2);
+  void SuperimposePositions();
+  void Render();
+  void Draw();
+  // Helper to post small update messages to JS.
+  void PostUpdateMessage(const char* message_name, double value);
+
+  PSContext2D_t* ps_context_;
+  Vec2 positions_[kMaxPointCount];
+  Vec2 screen_positions_[kMaxPointCount];
+  Vec2 velocities_[kMaxPointCount];
+  uint32_t colors_[kMaxPointCount];
+  float ang_;
+  const int num_regions_;
+  int num_threads_;
+  int point_count_;
+  bool draw_points_;
+  bool draw_interiors_;
+  ThreadPool* workers_;
+};
+
+
+void Voronoi::Reset() {
+  rand_reset(kRandomStartSeed);
+  ang_ = 0.0f;
+  for (int i = 0; i < kMaxPointCount; i++) {
+    // random initial start position
+    const float x = frand();
+    const float y = frand();
+    positions_[i].Set(x, y);
+    // random directional velocity ( -1..1, -1..1 )
+    const float speed = 0.0005f;
+    const float u = (frand() * 2.0f - 1.0f) * speed;
+    const float v = (frand() * 2.0f - 1.0f) * speed;
+    velocities_[i].Set(u, v);
+    // 'unique' color (well... unique enough for our purposes)
+    colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255);
+  }
+}
+
+Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0),
+    point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true) {
+  Reset();
+  // By default, render from the dispatch thread.
+  workers_ = new ThreadPool(num_threads_);
+  PSEventSetFilter(PSE_ALL);
+  ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
+}
+
+Voronoi::~Voronoi() {
+  delete workers_;
+  PSContext2DFree(ps_context_);
+}
+
+inline uint32_t* Voronoi::wGetAddr(int x, int y) {
+  return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
+}
+
+// This is the core of the Voronoi calculation.  At a given point on the
+// screen, iterate through all voronoi positions and render them as 3D cones.
+// We're looking for the voronoi cell that generates the closest z value.
+// (not really cones - since it is all relative, we avoid doing the
+// expensive sqrt and test against z*z instead)
+// If multithreading, this function is only called by the worker threads.
+int Voronoi::wCell(float x, float y) {
+  int closest_cell = 0;
+  float zz = kHugeZ;
+  Vec2* pos = screen_positions_;
+  for (int i = 0; i < point_count_; ++i) {
+    // measured 5.18 cycles per iteration on a core2
+    float dx = x - pos[i].x;
+    float dy = y - pos[i].y;
+    float dd = (dx * dx + dy * dy);
+    if (dd < zz) {
+      zz = dd;
+      closest_cell = i;
+    }
+  }
+  return closest_cell;
+}
+
+// Given a region r, derive a non-overlapping rectangle for a thread to
+// work on.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) {
+  const int parts = 16;
+  assert(parts * parts == num_regions_);
+  // Round up to the nearest power of two so we can divide by parts cleanly. We
+  // could round up to the nearest 16 pixels, but it runs much faster when
+  // subdividing power-of-two squares.
+  //
+  // Many of these squares are outside of the canvas, but they will be
+  // trivially culled by wRenderRect.
+  *w = static_cast<int>(next_pow2(ps_context_->width)) / parts;
+  *h = static_cast<int>(next_pow2(ps_context_->height)) / parts;
+  *x = *w * (r % parts);
+  *y = *h * ((r / parts) % parts);
+}
+
+// Test 4 corners of a rectangle to see if they all belong to the same
+// voronoi cell.  Each test is expensive so bail asap.  Returns true
+// if all 4 corners match.
+// If multithreading, this function is only called by the worker threads.
+bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) {
+  // each test is expensive, so exit ASAP
+  const int m0 = wCell(x, y);
+  const int m1 = wCell(x + w - 1, y);
+  if (m0 != m1) return false;
+  const int m2 = wCell(x, y + h - 1);
+  if (m0 != m2) return false;
+  const int m3 = wCell(x + w - 1, y + h - 1);
+  if (m0 != m3) return false;
+  // all 4 corners belong to the same cell
+  *m = m0;
+  return true;
+}
+
+// Quickly fill a span of pixels with a solid color.
+// If multithreading, this function is only called by the worker threads.
+inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
+  if (!draw_interiors_) {
+    const uint32_t gray = MakeBGRA(128, 128, 128, 255);
+    color = gray;
+  }
+
+  for (int i = 0; i < width; ++i)
+    *pixels++ = color;
+}
+
+// Quickly fill a rectangle with a solid color.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
+  const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+  uint32_t* pixels = wGetAddr(x, y);
+  for (int j = 0; j < h; j++) {
+    wFillSpan(pixels, color, w);
+    pixels += stride_in_pixels;
+  }
+}
+
+// When recursive subdivision reaches a certain minimum without finding a
+// rectangle that has four matching corners belonging to the same voronoi
+// cell, this function will break the retangular 'tile' into smaller scanlines
+//  and look for opportunities to quick fill at the scanline level.  If the
+// scanline can't be quick filled, it will slow down even further and compute
+// voronoi membership per pixel.
+void Voronoi::wRenderTile(int x, int y, int w, int h) {
+  // rip through a tile
+  const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+  uint32_t* pixels = wGetAddr(x, y);
+  for (int j = 0; j < h; j++) {
+    // get start and end cell values
+    int ms = wCell(x + 0, y + j);
+    int me = wCell(x + w - 1, y + j);
+    // if the end points are the same, quick fill the span
+    if (ms == me) {
+      wFillSpan(pixels, colors_[ms], w);
+    } else {
+      // else compute each pixel in the span... this is the slow part!
+      uint32_t* p = pixels;
+      *p++ = colors_[ms];
+      for (int i = 1; i < (w - 1); i++) {
+        int m = wCell(x + i, y + j);
+        *p++ = colors_[m];
+      }
+      *p++ = colors_[me];
+    }
+    pixels += stride_in_pixels;
+  }
+}
+
+// Take a rectangular region and do one of -
+//   If all four corners below to the same voronoi cell, stop recursion and
+// quick fill the rectangle.
+//   If the minimum rectangle size has been reached, break out of recursion
+// and process the rectangle.  This small rectangle is called a tile.
+//   Otherwise, keep recursively subdividing the rectangle into 4 equally
+// sized smaller rectangles.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wSubdivide(int x, int y, int w, int h) {
+  int m;
+  // if all 4 corners are equal, quick fill interior
+  if (wTestRect(&m, x, y, w, h)) {
+    wFillRect(x, y, w, h, colors_[m]);
+  } else {
+    // did we reach the minimum rectangle size?
+    if ((w <= kMinRectSize) || (h <= kMinRectSize)) {
+      wRenderTile(x, y, w, h);
+    } else {
+      // else recurse into smaller rectangles
+      const int half_w = w / 2;
+      const int half_h = h / 2;
+      wSubdivide(x, y, half_w, half_h);
+      wSubdivide(x + half_w, y, w - half_w, half_h);
+      wSubdivide(x, y + half_h, half_w, h - half_h);
+      wSubdivide(x + half_w, y + half_h, w - half_w, h - half_h);
+    }
+  }
+}
+
+// This function cuts up the rectangle into squares (preferably power-of-two).
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wRenderRect(int x, int y, int w, int h) {
+  for (int iy = y; iy < (y + h); iy += kStartRecurseSize) {
+    for (int ix = x; ix < (x + w); ix += kStartRecurseSize) {
+      int iw = kStartRecurseSize;
+      int ih = kStartRecurseSize;
+      // Clamp width + height.
+      if (ix + iw > ps_context_->width)
+        iw = ps_context_->width - ix;
+      if (iy + ih > ps_context_->height)
+        ih = ps_context_->height - iy;
+      if (iw <= 0 || ih <= 0)
+        continue;
+
+      wSubdivide(ix, iy, iw, ih);
+    }
+  }
+}
+
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wRenderRegion(int region) {
+  // convert region # into x0, y0, x1, y1 rectangle
+  int x, y, w, h;
+  wMakeRect(region, &x, &y, &w, &h);
+  // render this rectangle
+  wRenderRect(x, y, w, h);
+}
+
+// Entry point for worker thread.  Can't pass a member function around, so we
+// have to do this little round-about.
+void Voronoi::wRenderRegionEntry(int region, void* thiz) {
+  static_cast<Voronoi*>(thiz)->wRenderRegion(region);
+}
+
+// Function Voronoi::UpdateSim()
+// Run a simple sim to move the voronoi positions.  This update loop
+// is run once per frame.  Called from the main thread only, and only
+// when the worker threads are idle.
+void Voronoi::UpdateSim() {
+  ang_ += 0.002f;
+  if (ang_ > kTwoPI) {
+    ang_ = ang_ - kTwoPI;
+  }
+  float z = cosf(ang_) * 3.0f;
+  // push the points around on the screen for animation
+  for (int j = 0; j < kMaxPointCount; j++) {
+    positions_[j].x += (velocities_[j].x) * z;
+    positions_[j].y += (velocities_[j].y) * z;
+    screen_positions_[j].x = positions_[j].x * ps_context_->width;
+    screen_positions_[j].y = positions_[j].y * ps_context_->height;
+  }
+}
+
+// Renders a small diamond shaped dot at x, y clipped against the window
+void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
+  const int ix = static_cast<int>(x);
+  const int iy = static_cast<int>(y);
+  const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+  // clip it against window
+  if (ix < 1) return;
+  if (ix >= (ps_context_->width - 1)) return;
+  if (iy < 1) return;
+  if (iy >= (ps_context_->height - 1)) return;
+  uint32_t* pixel = wGetAddr(ix, iy);
+  // render dot as a small diamond
+  *pixel = color1;
+  *(pixel - 1) = color2;
+  *(pixel + 1) = color2;
+  *(pixel - stride_in_pixels) = color2;
+  *(pixel + stride_in_pixels) = color2;
+}
+
+// Superimposes dots on the positions.
+void Voronoi::SuperimposePositions() {
+  const uint32_t white = MakeBGRA(255, 255, 255, 255);
+  const uint32_t gray = MakeBGRA(192, 192, 192, 255);
+  for (int i = 0; i < point_count_; i++) {
+    RenderDot(
+        screen_positions_[i].x, screen_positions_[i].y, white, gray);
+  }
+}
+
+// Renders the Voronoi diagram, dispatching the work to multiple threads.
+void Voronoi::Render() {
+  workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
+  if (draw_points_)
+    SuperimposePositions();
+}
+
+// Handle input events from the user and messages from JS.
+void Voronoi::HandleEvent(PSEvent* ps_event) {
+  // Give the 2D context a chance to process the event.
+  if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
+    return;
+  if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
+    // Convert Pepper Simple event to a PPAPI C++ event
+    pp::InputEvent event(ps_event->as_resource);
+    switch (event.GetType()) {
+      case PP_INPUTEVENT_TYPE_TOUCHSTART:
+      case PP_INPUTEVENT_TYPE_TOUCHMOVE: {
+        pp::TouchInputEvent touches = pp::TouchInputEvent(event);
+        uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
+        // Touch points 0..n directly set position of points 0..n in
+        // Voronoi diagram.
+        for (uint32_t i = 0; i < count; i++) {
+          pp::TouchPoint touch =
+              touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, i);
+          pp::FloatPoint point = touch.position();
+          positions_[i].Set(point.x() / ps_context_->width,
+                            point.y() / ps_context_->height);
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
+    // Convert Pepper Simple message to PPAPI C++ var
+    pp::Var var(ps_event->as_var);
+    if (var.is_dictionary()) {
+      pp::VarDictionary dictionary(var);
+      std::string message = dictionary.Get("message").AsString();
+      if (message == "draw_points")
+        draw_points_ = dictionary.Get("value").AsBool();
+      else if (message == "draw_interiors")
+        draw_interiors_ = dictionary.Get("value").AsBool();
+      else if (message == "set_points") {
+        int num_points = dictionary.Get("value").AsInt();
+        point_count_ = std::min(kMaxPointCount, std::max(0, num_points));
+      } else if (message == "set_threads") {
+        int thread_count = dictionary.Get("value").AsInt();
+        delete workers_;
+        workers_ = new ThreadPool(thread_count);
+      }
+    }
+  }
+}
+
+// PostUpdateMessage() helper function for sendimg small messages to JS.
+void Voronoi::PostUpdateMessage(const char* message_name, double value) {
+  pp::VarDictionary message;
+  message.Set("message", message_name);
+  message.Set("value", value);
+  PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
+}
+
+void Voronoi::Update() {
+  PSContext2DGetBuffer(ps_context_);
+  if (NULL == ps_context_->data)
+    return;
+
+  UpdateSim();
+  Render();
+
+  PSContext2DSwapBuffer(ps_context_);
+}
+
+// Starting point for the module.  We do not use main since it would
+// collide with main in libppapi_cpp.
+int example_main(int argc, char* argv[]) {
+  Voronoi voronoi;
+  while (true) {
+    PSEvent* ps_event;
+    // Consume all available events.
+    while ((ps_event = PSEventTryAcquire()) != NULL) {
+      voronoi.HandleEvent(ps_event);
+      PSEventRelease(ps_event);
+    }
+    // Do simulation, render and present.
+    voronoi.Update();
+  }
+
+  return 0;
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
index 3ab6eab..7af7346 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
@@ -61,8 +61,8 @@
           <button id="reload">Reload Scene</button>
         </div>
         <ul>
-          <li>Hold "h" to pick up an object</li>
-          <li>Click and drag to rotate the camera</li>
+          <li>Click and drag an object to move it</li>
+          <li>Click and drag elsewhere to rotate the camera</li>
           <li>Use the mousewheel to zoom in/out</li>
         </ul>
         <p class="small">
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
index b84c2ac..be091e2 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
@@ -75,7 +75,7 @@
   embed.setAttribute('width', '0');
   embed.setAttribute('height', '0');
   embed.setAttribute('type', 'application/x-pnacl');
-  embed.setAttribute('src', 'http://commondatastorage.googleapis.com/gonacl/pnacl-demo-bullet/NaClAMBullet.portable.nmf');
+  embed.setAttribute('src', 'http://commondatastorage.googleapis.com/gonacl/demos/publish/229855/bullet/NaClAMBullet.nmf');
   embedWrap.appendChild(embed);
 }
 
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
index 6740155..27ae546 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
@@ -194,8 +194,6 @@
 
   rendererContainer.appendChild(renderer.domElement);
 
-  controls = new THREE.OrbitControls (camera, rendererContainer);
-
   var idFuncHash = {
     jenga10: loadJenga10,
     jenga20: loadJenga20,
@@ -213,9 +211,13 @@
 
   $('reload').addEventListener('click', reloadScene, false);
 
-  renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false );
-  window.addEventListener('keydown', onDocumentKeyDown, false);
-  window.addEventListener('keyup', onDocumentKeyUp, false);
+  rendererContainer.addEventListener('mousedown', onMouseDown, false);
+  rendererContainer.addEventListener('mouseup', onMouseUp, false);
+  renderer.domElement.addEventListener('mousemove', onMouseMove, false);
+
+  // Add the OrbitControls after our own listeners -- that way we can prevent
+  // the camera rotation when dragging an object.
+  controls = new THREE.OrbitControls(camera, rendererContainer);
 
   window.setInterval(pollForRendererResize, 10);
 }
@@ -234,35 +236,35 @@
   lastRendererHeight = h;
 }
 
-function onDocumentKeyDown(event) {
-  if (event.keyCode == 72 || event.keyCode == 104) {
-    if (SELECTED != undefined) {
-      return;
-    }
-    hold = true;
-    var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
-    projector.unprojectVector( vector, camera );
-    var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
-    var intersects = ray.intersectObjects( objects );
-    if (intersects.length > 0) {
-      if (intersects[0].object != plane) {
-        SELECTED = intersects[0].object;
-        //console.log(SELECTED.objectTableIndex);
-        NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
-      }
+function onMouseDown(event) {
+  var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
+  projector.unprojectVector( vector, camera );
+  var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
+  var intersects = ray.intersectObjects( objects );
+  if (intersects.length > 0) {
+    if (intersects[0].object != plane) {
+      hold = true;
+      SELECTED = intersects[0].object;
+      //console.log(SELECTED.objectTableIndex);
+      NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
+      // stopImmediatePropagation() will prevent other event listeners on the
+      // same element from firing -- in this case, the OrbitControls camera
+      // rotation.
+      event.stopImmediatePropagation();
     }
   }
 }
 
-function onDocumentKeyUp(event) {
-  if (event.keyCode == 72 || event.keyCode == 104) {
+function onMouseUp(event) {
+  if (hold) {
     hold = false;
     SELECTED = undefined;
     NaClAMBulletDropObject();
+    event.stopImmediatePropagation();
   }
 }
 
-function onDocumentMouseMove( event ) {
+function onMouseMove( event ) {
   event.preventDefault();
 
   var rendererContainer = $('rendererContainer');
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
index fac8405..53e9e6d 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
@@ -42,9 +42,9 @@
  * @return {string}
  */
 function getDataURL(name) {
-  var baseUrl =
-    'http://commondatastorage.googleapis.com/gonacl/pnacl-earth-demo/';
-  return baseUrl + name;
+  var revision = 229855;
+  var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+  return baseUrl + revision + '/earth/' + name;
 }
 
 /**
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js
new file mode 100644
index 0000000..276aaed
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js
@@ -0,0 +1,194 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+var naclModule = null;
+
+/**
+ * A helper function to abbreviate getElementById.
+ *
+ * @param {string} elementId The id to get.
+ * @return {Element}
+ */
+function $(elementId) {
+  return document.getElementById(elementId);
+}
+
+/**
+ * MIME type for PNaCl
+ *
+ * @return {string} MIME type
+ */
+function PNaClmimeType() {
+  return 'application/x-pnacl';
+}
+
+/**
+ * Check if the browser supports PNaCl.
+ *
+ * @return {bool}
+ */
+function browserSupportsPNaCl() {
+  var mimetype = PNaClmimeType();
+  return navigator.mimeTypes[mimetype] !== undefined;
+}
+
+/**
+ * Get the URL for Google Cloud Storage.
+ *
+ * @param {string} name The relative path to the file.
+ * @return {string}
+ */
+function getDataURL(name) {
+  var revision = 231029;
+  var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+  return baseUrl + revision + '/life/' + name;
+}
+
+/**
+ * Create the Native Client <embed> element as a child of the DOM element
+ * named "listener".
+ *
+ * @param {string} name The name of the example.
+ * @param {number} width The width to create the plugin.
+ * @param {number} height The height to create the plugin.
+ * @param {Object} attrs Dictionary of attributes to set on the module.
+ */
+function createNaClModule(name, width, height, attrs) {
+  var moduleEl = document.createElement('embed');
+  moduleEl.setAttribute('name', 'nacl_module');
+  moduleEl.setAttribute('id', 'nacl_module');
+  moduleEl.setAttribute('width', width);
+  moduleEl.setAttribute('height', height);
+  moduleEl.setAttribute('path', '');
+  moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
+  moduleEl.setAttribute('type', PNaClmimeType());
+
+  // Add any optional arguments
+  if (attrs) {
+    for (var key in attrs) {
+      moduleEl.setAttribute(key, attrs[key]);
+    }
+  }
+
+  // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+  // and a 'message' event listener attached.  This wrapping method is used
+  // instead of attaching the event listeners directly to the <EMBED> element
+  // to ensure that the listeners are active before the NaCl module 'load'
+  // event fires.
+  var listenerDiv = $('listener');
+  listenerDiv.appendChild(moduleEl);
+}
+
+/**
+ * Add the default event listeners to the element with id "listener".
+ */
+function attachDefaultListeners() {
+  var listenerDiv = $('listener');
+  listenerDiv.addEventListener('load', moduleDidLoad, true);
+  listenerDiv.addEventListener('error', moduleLoadError, true);
+  listenerDiv.addEventListener('progress', moduleLoadProgress, true);
+  listenerDiv.addEventListener('crash', handleCrash, true);
+}
+
+/**
+ * Called when the Browser can not communicate with the Module
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ *
+ * @param {Object} event
+ */
+function handleCrash(event) {
+  if (naclModule.exitStatus == -1) {
+    updateStatus('CRASHED');
+  } else {
+    updateStatus('EXITED [' + naclModule.exitStatus + ']');
+  }
+}
+
+/**
+ * Called when the NaCl module is loaded.
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ */
+function moduleDidLoad() {
+  var bar = $('progress');
+  bar.value = 100;
+  bar.max = 100;
+  naclModule = $('nacl_module');
+  hideStatus();
+  setThreadCount();
+}
+
+/**
+ * Hide the status field and progress bar.
+ */
+function hideStatus() {
+  $('statusField').style.display = 'none';
+  $('progress').style.display = 'none';
+}
+
+/**
+ * Called when the plugin fails to load.
+ *
+ * @param {Object} event
+ */
+function moduleLoadError(event) {
+  updateStatus('Load failed.');
+}
+
+/**
+ * Called when the plugin reports progress events.
+ *
+ * @param {Object} event
+ */
+function moduleLoadProgress(event) {
+  $('progress').style.display = 'block';
+
+  var loadPercent = 0.0;
+  var bar = $('progress');
+  bar.max = 100;
+  if (event.lengthComputable && event.total > 0) {
+    loadPercent = event.loaded / event.total * 100.0;
+  } else {
+    // The total length is not yet known.
+    loadPercent = -1.0;
+  }
+  bar.value = loadPercent;
+}
+
+/**
+ * If the element with id 'statusField' exists, then set its HTML to the status
+ * message as well.
+ *
+ * @param {string} opt_message The message to set.
+ */
+function updateStatus(opt_message) {
+  var statusField = $('statusField');
+  if (statusField) {
+    statusField.style.display = 'block';
+    statusField.textContent = opt_message;
+  }
+}
+
+/**
+ * Listen for the DOM content to be loaded. This event is fired when parsing of
+ * the page's document has finished.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+  updateStatus('Loading...');
+  if (!browserSupportsPNaCl()) {
+    updateStatus('Browser does not support PNaCl or PNaCl is disabled');
+  } else if (naclModule == null) {
+    createNaClModule('life', 512, 512);
+    attachDefaultListeners();
+  } else {
+    // It's possible that the Native Client module onload event fired
+    // before the page's onload event.  In this case, the status message
+    // will reflect 'SUCCESS', but won't be displayed.  This call will
+    // display the current message.
+    updateStatus('Waiting.');
+  }
+});
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html
new file mode 100644
index 0000000..1b02777
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright (c) 2013 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.
+-->
+<head>
+  <meta charset="UTF-8">
+  <title>Life</title>
+  <script type="text/javascript" src="example.js"></script>
+  <link href="/static/common.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+  <div class="absolute-fill">
+    <div class="flex-container">
+      <div class="main absolute-fill-parent">
+        <div class="absolute-fill">
+          <div class="flex-container flex-column flex-justify-center">
+            <div id="message">
+              <div id="statusField"></div>
+              <progress id="progress"></progress>
+            </div>
+          </div>
+        </div>
+        <div id="listener" class="absolute-fill"></div>
+      </div>
+      <div class="sidebar">
+        <h1>Life</h1>
+        <p>
+          This demo renders <a
+            href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway's
+            Game of Life</a>.
+        </p>
+      </div>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html
new file mode 100644
index 0000000..c0371d2
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Lua</title>
+    <script type="text/javascript" src="http://commondatastorage.googleapis.com/gonacl/demos/publish/231022/lua/hterm.concat.js"></script>
+    <script type="text/javascript" src="naclterm.js"></script>
+    <script type="text/javascript" src="lua.js"></script>
+
+    <style type="text/css">
+      body {
+        position: absolute;
+        padding: 0;
+        margin: 0;
+        height: 100%;
+        width: 100%;
+        overflow: hidden;
+      }
+
+      #terminal {
+        display: block;
+        position: static;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="terminal"></div>
+  </body>
+</html>
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js
new file mode 100644
index 0000000..18b8427
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+NaClTerm.prefix = 'lua'
+NaClTerm.nmf = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/231022/lua/lua.nmf'
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js
new file mode 100644
index 0000000..d272a0b
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+'use strict';
+
+lib.rtdep('lib.f',
+          'hterm');
+
+// CSP means that we can't kick off the initialization from the html file,
+// so we do it like this instead.
+window.onload = function() {
+  lib.init(function() {
+    NaClTerm.init();
+  });
+};
+
+/**
+ * The hterm-powered terminal command.
+ *
+ * This class defines a command that can be run in an hterm.Terminal instance.
+ *
+ * @param {Object} argv The argument object passed in from the Terminal.
+ */
+function NaClTerm(argv) {
+  this.argv_ = argv;
+  this.io = null;
+};
+
+var embed;
+
+/**
+ * Static initialier called from index.html.
+ *
+ * This constructs a new Terminal instance and instructs it to run the NaClTerm
+ * command.
+ */
+NaClTerm.init = function() {
+  var profileName = lib.f.parseQuery(document.location.search)['profile'];
+  var terminal = new hterm.Terminal(profileName);
+  terminal.decorate(document.querySelector('#terminal'));
+
+  // Useful for console debugging.
+  window.term_ = terminal;
+
+  // We don't properly support the hterm bell sound, so we need to disable it.
+  terminal.prefs_.definePreference('audible-bell-sound', '');
+
+  terminal.setAutoCarriageReturn(true);
+  terminal.setCursorPosition(0, 0);
+  terminal.setCursorVisible(true);
+  terminal.runCommandClass(NaClTerm, document.location.hash.substr(1));
+
+  return true;
+};
+
+/**
+ * Handle messages sent to us from NaCl.
+ *
+ * @private
+ */
+NaClTerm.prototype.handleMessage_ = function(e) {
+  if (e.data.indexOf(NaClTerm.prefix) != 0) return;
+  var msg = e.data.substring(NaClTerm.prefix.length);
+  if (!this.loaded) {
+    this.bufferedOutput += msg;
+  } else {
+    term_.io.print(msg);
+  }
+}
+
+/**
+ * Handle load error event from NaCl.
+ */
+NaClTerm.prototype.handleLoadAbort_ = function(e) {
+  term_.io.print("Load aborted.\n");
+}
+
+/**
+ * Handle load abort event from NaCl.
+ */
+NaClTerm.prototype.handleLoadError_ = function(e) {
+  term_.io.print(embed.lastError + '\n');
+}
+
+/**
+ * Handle load end event from NaCl.
+ */
+NaClTerm.prototype.handleLoad_ = function(e) {
+  if (typeof(this.lastUrl) != 'undefined')
+    term_.io.print("\n");
+  term_.io.print("Loaded.\n");
+
+  // Now that have completed loading and displaying
+  // loading messages we output any messages from the
+  // NaCl module that were buffered up unto this point
+  this.loaded = true;
+  term_.io.print(this.bufferedOutput);
+  this.bufferedOutput = ''
+}
+
+/**
+ * Handle load progress event from NaCl.
+ */
+NaClTerm.prototype.handleProgress_ = function(e) {
+  var url = e.url.substring(e.url.lastIndexOf('/') + 1);
+  if (this.lastUrl != url) {
+    if (url != '') {
+      if (this.lastUrl)
+        term_.io.print("\n");
+      term_.io.print("Loading " + url + " .");
+    }
+  } else {
+    term_.io.print(".");
+  }
+  if (url)
+  this.lastUrl = url;
+}
+
+/**
+ * Handle crash event from NaCl.
+ */
+NaClTerm.prototype.handleCrash_ = function(e) {
+ if (embed.exitStatus == -1) {
+   term_.io.print("Program crashed (exit status -1)\n")
+ } else {
+   term_.io.print("Program exited (status=" + embed.exitStatus + ")\n");
+ }
+}
+
+
+NaClTerm.prototype.onTerminalResize_ = function() {
+  var width = term_.io.terminal_.screenSize.width;
+  var height = term_.io.terminal_.screenSize.height;
+  embed.postMessage({'tty_resize': [ width, height ]});
+}
+
+NaClTerm.prototype.onVTKeystroke_ = function(str) {
+  var message = {};
+  message[NaClTerm.prefix] = str;
+  embed.postMessage(message);
+}
+
+/*
+ * This is invoked by the terminal as a result of terminal.runCommandClass().
+ */
+NaClTerm.prototype.run = function() {
+  this.io = this.argv_.io.push();
+  this.bufferedOutput = '';
+  this.loaded = false;
+
+  embed = document.createElement('object');
+  embed.width = 0;
+  embed.height = 0;
+  embed.data = NaClTerm.nmf;
+  embed.type = 'application/x-pnacl';
+  embed.addEventListener('message', this.handleMessage_.bind(this));
+  embed.addEventListener('progress', this.handleProgress_.bind(this));
+  embed.addEventListener('load', this.handleLoad_.bind(this));
+  embed.addEventListener('error', this.handleLoadError_.bind(this));
+  embed.addEventListener('abort', this.handleLoadAbort_.bind(this));
+  embed.addEventListener('crash', this.handleCrash_.bind(this));
+
+  function addParam(name, value) {
+    var param = document.createElement('param');
+    param.name = name;
+    param.value = value;
+    embed.appendChild(param);
+  }
+
+  addParam('ps_tty_prefix', NaClTerm.prefix);
+  addParam('ps_tty_resize', 'tty_resize');
+  addParam('ps_stdin', '/dev/tty');
+  addParam('ps_stdout', '/dev/tty');
+  addParam('ps_stderr', '/dev/tty');
+  addParam('ps_verbosity', '2');
+  addParam('TERM', 'xterm-256color');
+
+  var args = lib.f.parseQuery(document.location.search);
+  var argn = 1;
+  while (true) {
+    var argname = 'arg' + argn;
+    var arg = args[argname];
+    if (typeof(arg) === 'undefined')
+      break;
+    addParam(argname, arg);
+    argn = argn + 1;
+  }
+
+  term_.io.print("Loading NaCl module.\n")
+  document.body.appendChild(embed);
+
+  this.io.onVTKeystroke = this.onVTKeystroke_.bind(this);
+  this.io.onTerminalResize = this.onTerminalResize_.bind(this);
+};
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js
new file mode 100644
index 0000000..ff83571
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js
@@ -0,0 +1,233 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+var naclModule = null;
+
+/**
+ * A helper function to abbreviate getElementById.
+ *
+ * @param {string} elementId The id to get.
+ * @return {Element}
+ */
+function $(elementId) {
+  return document.getElementById(elementId);
+}
+
+/**
+ * MIME type for PNaCl
+ *
+ * @return {string} MIME type
+ */
+function PNaClmimeType() {
+  return 'application/x-pnacl';
+}
+
+/**
+ * Check if the browser supports PNaCl.
+ *
+ * @return {bool}
+ */
+function browserSupportsPNaCl() {
+  var mimetype = PNaClmimeType();
+  return navigator.mimeTypes[mimetype] !== undefined;
+}
+
+/**
+ * Get the URL for Google Cloud Storage.
+ *
+ * @param {string} name The relative path to the file.
+ * @return {string}
+ */
+function getDataURL(name) {
+  var revision = 231029;
+  var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+  return baseUrl + revision + '/voronoi/' + name;
+}
+
+/**
+ * Create the Native Client <embed> element as a child of the DOM element
+ * named "listener".
+ *
+ * @param {string} name The name of the example.
+ * @param {number} width The width to create the plugin.
+ * @param {number} height The height to create the plugin.
+ * @param {Object} attrs Dictionary of attributes to set on the module.
+ */
+function createNaClModule(name, width, height, attrs) {
+  var moduleEl = document.createElement('embed');
+  moduleEl.setAttribute('name', 'nacl_module');
+  moduleEl.setAttribute('id', 'nacl_module');
+  moduleEl.setAttribute('width', width);
+  moduleEl.setAttribute('height', height);
+  moduleEl.setAttribute('path', '');
+  moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
+  moduleEl.setAttribute('type', PNaClmimeType());
+
+  // Add any optional arguments
+  if (attrs) {
+    for (var key in attrs) {
+      moduleEl.setAttribute(key, attrs[key]);
+    }
+  }
+
+  // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+  // and a 'message' event listener attached.  This wrapping method is used
+  // instead of attaching the event listeners directly to the <EMBED> element
+  // to ensure that the listeners are active before the NaCl module 'load'
+  // event fires.
+  var listenerDiv = $('listener');
+  listenerDiv.appendChild(moduleEl);
+}
+
+/**
+ * Add the default event listeners to the element with id "listener".
+ */
+function attachDefaultListeners() {
+  var listenerDiv = $('listener');
+  listenerDiv.addEventListener('load', moduleDidLoad, true);
+  listenerDiv.addEventListener('error', moduleLoadError, true);
+  listenerDiv.addEventListener('progress', moduleLoadProgress, true);
+  listenerDiv.addEventListener('crash', handleCrash, true);
+  attachListeners();
+}
+
+/**
+ * Called when the Browser can not communicate with the Module
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ *
+ * @param {Object} event
+ */
+function handleCrash(event) {
+  if (naclModule.exitStatus == -1) {
+    updateStatus('CRASHED');
+  } else {
+    updateStatus('EXITED [' + naclModule.exitStatus + ']');
+  }
+}
+
+/**
+ * Called when the NaCl module is loaded.
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ */
+function moduleDidLoad() {
+  var bar = $('progress');
+  bar.value = 100;
+  bar.max = 100;
+  naclModule = $('nacl_module');
+  hideStatus();
+  setThreadCount();
+}
+
+/**
+ * Hide the status field and progress bar.
+ */
+function hideStatus() {
+  $('statusField').style.display = 'none';
+  $('progress').style.display = 'none';
+}
+
+/**
+ * Called when the plugin fails to load.
+ *
+ * @param {Object} event
+ */
+function moduleLoadError(event) {
+  updateStatus('Load failed.');
+}
+
+/**
+ * Called when the plugin reports progress events.
+ *
+ * @param {Object} event
+ */
+function moduleLoadProgress(event) {
+  $('progress').style.display = 'block';
+
+  var loadPercent = 0.0;
+  var bar = $('progress');
+  bar.max = 100;
+  if (event.lengthComputable && event.total > 0) {
+    loadPercent = event.loaded / event.total * 100.0;
+  } else {
+    // The total length is not yet known.
+    loadPercent = -1.0;
+  }
+  bar.value = loadPercent;
+}
+
+/**
+ * If the element with id 'statusField' exists, then set its HTML to the status
+ * message as well.
+ *
+ * @param {string} opt_message The message to set.
+ */
+function updateStatus(opt_message) {
+  var statusField = $('statusField');
+  if (statusField) {
+    statusField.style.display = 'block';
+    statusField.textContent = opt_message;
+  }
+}
+
+/**
+ * Send the current value of the element threadCount to the NaCl module.
+ *
+ * @param {number} threads The number of threads to use to render.
+ */
+function setThreadCount(threads) {
+  var value = parseInt($('threadCount').value);
+  naclModule.postMessage({'message': 'set_threads',
+                          'value': value});
+}
+
+/**
+ * Add event listeners after the NaCl module has loaded.  These listeners will
+ * forward messages to the NaCl module via postMessage()
+ */
+function attachListeners() {
+  $('threadCount').addEventListener('change', setThreadCount);
+  $('drawPoints').addEventListener('click',
+    function() {
+      var checked = $('drawPoints').checked;
+      naclModule.postMessage({'message' : 'draw_points',
+                                     'value' : checked});
+    });
+  $('drawInteriors').addEventListener('click',
+    function() {
+      var checked = $('drawInteriors').checked;
+      naclModule.postMessage({'message' : 'draw_interiors',
+                                     'value' : checked});
+    });
+  $('pointRange').addEventListener('change',
+    function() {
+      var value = parseFloat($('pointRange').value);
+      naclModule.postMessage({'message' : 'set_points',
+                                     'value' : value});
+      $('pointCount').textContent = value + ' points';
+    });
+}
+
+/**
+ * Listen for the DOM content to be loaded. This event is fired when parsing of
+ * the page's document has finished.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+  updateStatus('Loading...');
+  if (!browserSupportsPNaCl()) {
+    updateStatus('Browser does not support PNaCl or PNaCl is disabled');
+  } else if (naclModule == null) {
+    createNaClModule('voronoi', 512, 512);
+    attachDefaultListeners();
+  } else {
+    // It's possible that the Native Client module onload event fired
+    // before the page's onload event.  In this case, the status message
+    // will reflect 'SUCCESS', but won't be displayed.  This call will
+    // display the current message.
+    updateStatus('Waiting.');
+  }
+});
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html
new file mode 100644
index 0000000..f5167b0
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright (c) 2013 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.
+-->
+<head>
+  <meta charset="UTF-8">
+  <title>Voronoi</title>
+  <script type="text/javascript" src="example.js"></script>
+  <link href="/static/common.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+  <div class="absolute-fill">
+    <div class="flex-container">
+      <div class="main absolute-fill-parent">
+        <div class="absolute-fill">
+          <div class="flex-container flex-column flex-justify-center">
+            <div id="message">
+              <div id="statusField"></div>
+              <progress id="progress"></progress>
+            </div>
+          </div>
+        </div>
+        <div id="listener" class="absolute-fill"></div>
+      </div>
+      <div class="sidebar">
+        <h1>Voronoi</h1>
+        <p>
+          This demo renders the Voronoi diagram for a moving set of points using
+          a brute force technique.
+        </p>
+        <table id="config">
+          <tbody>
+            <tr>
+              <td class="name">Points:</td>
+              <td class="value">
+                <input type="range" id="pointRange"
+                    min="1" max="1024" step="1" value="48">
+                <label id="pointCount">48 points</label>
+              </td>
+            </tr>
+            <tr>
+              <td class="name">Thread Count:</td>
+              <td class="value">
+                <select id="threadCount">
+                  <option value="0">Main Thread only</option>
+                  <option value="1">1 Thread</option>
+                  <option value="2" selected="selected">2 Threads</option>
+                  <option value="4">4 Threads</option>
+                  <option value="6">6 Threads</option>
+                  <option value="8">8 Threads</option>
+                  <option value="12">12 Threads</option>
+                  <option value="24">24 Threads</option>
+                  <option value="32">32 Threads</option>
+                </select>
+              </td>
+            </tr>
+            <tr>
+              <td class="name"><label for="drawPoints">Draw Points:</label></td>
+              <td class="value">
+                <input type="checkbox" id="drawPoints" checked="checked">
+              </td>
+            </tr>
+            <tr>
+              <td class="name">
+                <label for="drawInteriors">Draw Interiors:</label>
+              </td>
+              <td class="value">
+                <input type="checkbox" id="drawInteriors" checked="checked">
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/native_client_sdk/src/libraries/nacl_io/include/poll.h b/native_client_sdk/src/libraries/nacl_io/include/poll.h
new file mode 100644
index 0000000..553574d
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/poll.h
@@ -0,0 +1,5 @@
+/* Copyright (c) 2013 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 <sys/poll.h>
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/poll.h b/native_client_sdk/src/libraries/nacl_io/include/sys/poll.h
new file mode 100644
index 0000000..1784344
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/poll.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2013 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 LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_
+#define LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_
+
+#include <stdint.h>
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+/* This header adds definitions of flags and structures for use with poll on
+ * toolchains with 'C' libraries which do not normally supply poll. */
+
+/* Node state flags */
+#define POLLIN   0x0001   /* Will not block READ select/poll. */
+#define POLLPRI  0x0002   /* There is urgent data to read. */
+#define POLLOUT  0x0004   /* Will not block WRITE select/poll. */
+#define POLLERR  0x0008   /* Will not block EXECPT select/poll. */
+#define POLLHUP  0x0010   /* Connection closed on far side. */
+#define POLLNVAL 0x0020   /* Invalid FD. */
+
+/* Number of file descriptors. */
+typedef int nfds_t;
+
+struct pollfd {
+  int fd;
+  uint16_t events;
+  uint16_t revents;
+};
+
+int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout);
+
+EXTERN_C_END
+
+#endif  /* LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
index 6cb68fa..566bf90 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
@@ -145,6 +145,28 @@
   return 0;
 }
 
+Error KernelObject::GetFDFlags(int fd, int* out_flags) {
+  AUTO_LOCK(handle_lock_);
+  if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+    return EBADF;
+
+  *out_flags = handle_map_[fd].flags;
+  return 0;
+}
+
+Error KernelObject::SetFDFlags(int fd, int flags) {
+  AUTO_LOCK(handle_lock_);
+  if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+    return EBADF;
+
+  // Only setting of FD_CLOEXEC is supported.
+  if (flags & ~FD_CLOEXEC)
+    return EINVAL;
+
+  handle_map_[fd].flags = flags;
+  return 0;
+}
+
 Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
   out_handle->reset(NULL);
 
@@ -152,7 +174,7 @@
   if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
     return EBADF;
 
-  *out_handle = handle_map_[fd];
+  *out_handle = handle_map_[fd].handle;
   if (out_handle) return 0;
 
   return EBADF;
@@ -162,16 +184,18 @@
   AUTO_LOCK(handle_lock_);
   int id;
 
+  Descriptor_t descriptor(handle);
+
   // If we can recycle and FD, use that first
   if (free_fds_.size()) {
     id = free_fds_.front();
     // Force lower numbered FD to be available first.
     std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
     free_fds_.pop_back();
-    handle_map_[id] = handle;
+    handle_map_[id] = descriptor;
   } else {
     id = handle_map_.size();
-    handle_map_.push_back(handle);
+    handle_map_.push_back(descriptor);
   }
   return id;
 }
@@ -186,14 +210,14 @@
     if (fd >= (int)handle_map_.size())
       handle_map_.resize(fd + 1);
 
-    handle_map_[fd] = handle;
+    handle_map_[fd] = Descriptor_t(handle);
   }
 }
 
 void KernelObject::FreeFD(int fd) {
   AUTO_LOCK(handle_lock_);
 
-  handle_map_[fd].reset(NULL);
+  handle_map_[fd].handle.reset(NULL);
   free_fds_.push_back(fd);
 
   // Force lower numbered FD to be available first.
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
index 0426f15..df6dba2 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -29,7 +29,14 @@
 // All calls are assumed to be a relative path.
 class KernelObject {
  public:
-  typedef std::vector<ScopedKernelHandle> HandleMap_t;
+  struct Descriptor_t {
+    Descriptor_t() : flags(0) {}
+    explicit Descriptor_t(const ScopedKernelHandle& h) : handle(h), flags(0) {}
+
+    ScopedKernelHandle handle;
+    int flags;
+  };
+  typedef std::vector<Descriptor_t> HandleMap_t;
   typedef std::map<std::string, ScopedMount> MountMap_t;
 
   KernelObject();
@@ -56,6 +63,11 @@
                             ScopedMount* out_mount,
                             ScopedMountNode* out_node);
 
+  // Get FD-specific flags (currently only FD_CLOEXEC is supported).
+  Error GetFDFlags(int fd, int* out_flags);
+  // Set FD-specific flags (currently only FD_CLOEXEC is supported).
+  Error SetFDFlags(int fd, int flags);
+
   // Convert from FD to KernelHandle, and acquire the handle.
   // Assumes |out_handle| is non-NULL.
   Error AcquireHandle(int fd, ScopedKernelHandle* out_handle);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 38715ad..1ae9e5b 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -648,8 +648,34 @@
 }
 
 int KernelProxy::fcntl(int fd, int request, va_list args) {
+  Error error = 0;
+
+  // F_GETFD and F_SETFD are descirptor specific flags that
+  // are stored in the KernelObject's decriptor map unlink
+  // F_GETFL and F_SETFL which are handle specific.
+  switch (request) {
+    case F_GETFD: {
+      int rtn = -1;
+      error = GetFDFlags(fd, &rtn);
+      if (error) {
+        errno = error;
+        return -1;
+      }
+      return rtn;
+    }
+    case F_SETFD: {
+      int flags = va_arg(args, int);
+      error = SetFDFlags(fd, flags);
+      if (error) {
+        errno = error;
+        return -1;
+      }
+      return 0;
+    }
+  }
+
   ScopedKernelHandle handle;
-  Error error = AcquireHandle(fd, &handle);
+  error = AcquireHandle(fd, &handle);
   if (error) {
     errno = error;
     return -1;
@@ -1087,6 +1113,12 @@
 
   ScopedMountNode node(sock);
   ScopedKernelHandle new_handle(new KernelHandle(stream_mount_, node));
+  error = sock->Init(O_RDWR);
+  if (error != 0) {
+    errno = error;
+    return -1;
+  }
+
   return AllocateFD(new_handle);
 }
 
@@ -1419,6 +1451,12 @@
   }
 
   ScopedKernelHandle handle(new KernelHandle(stream_mount_, node));
+  rtn = handle->Init(O_RDWR);
+  if (rtn != 0) {
+    errno = rtn;
+    return -1;
+  }
+
   return AllocateFD(handle);
 }
 
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 11660d1..53336e8 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -219,6 +219,7 @@
         "poll.h",
         "sys/ioctl.h",
         "sys/mount.h",
+        "sys/poll.h",
         "sys/select.h",
         "sys/signal.h",
         "sys/socket.h",
@@ -237,6 +238,7 @@
         "poll.h",
         "sys/ioctl.h",
         "sys/mount.h",
+        "sys/poll.h",
         "sys/select.h",
         "sys/signal.h",
         "sys/socket.h",
@@ -248,6 +250,7 @@
     {
       'FILES': [
         "poll.h",
+        "sys/poll.h",
       ],
       'DEST': 'include/win',
     },
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
index 12c5b9d..1d8ac37 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
@@ -24,7 +24,9 @@
       local_addr_(0),
       remote_addr_(0),
       socket_flags_(0),
-      last_errno_(0) {
+      last_errno_(0),
+      keep_alive_(false) {
+  memset(&linger_, 0, sizeof(linger_));
   SetType(S_IFSOCK);
 }
 
@@ -34,7 +36,9 @@
       local_addr_(0),
       remote_addr_(0),
       socket_flags_(0),
-      last_errno_(0) {
+      last_errno_(0),
+      keep_alive_(false) {
+  memset(&linger_, 0, sizeof(linger_));
   SetType(S_IFSOCK);
   mount_->ppapi()->AddRefResource(socket_resource_);
 }
@@ -222,26 +226,41 @@
   if (lvl != SOL_SOCKET)
     return ENOPROTOOPT;
 
+  int value = 0;
+  socklen_t value_len = 0;
+  void* value_ptr = NULL;
+
   switch (optname) {
-    case SO_REUSEADDR: {
-      // SO_REUSEADDR is effectivly always on since we can't
+    case SO_REUSEADDR:
+      // SO_REUSEADDR is effectively always on since we can't
       // disable it with PPAPI sockets.
-      int value = 1;
-      int copy_bytes = std::min(sizeof(int), *len);
-      memcpy(optval, &value, copy_bytes);
-      *len = sizeof(int);
-      return 0;
-    }
-    case SO_ERROR: {
-      int copy_bytes = std::min(sizeof(int), *len);
-      memcpy(optval, &last_errno_, copy_bytes);
-      *len = sizeof(int);
+      value = 1;
+      value_ptr = &value;
+      value_len = sizeof(value);
+      break;
+    case SO_LINGER:
+      value_ptr = &linger_;
+      value_len = sizeof(linger_);
+      break;
+    case SO_KEEPALIVE:
+      value = keep_alive_;
+      value_ptr = &value;
+      value_len = sizeof(value);
+      break;
+    case SO_ERROR:
+      value_ptr = &last_errno_;
+      value_len = sizeof(last_errno_);
       last_errno_ = 0;
-      return 0;
-    }
+      break;
+    default:
+      return ENOPROTOOPT;
   }
 
-  return ENOPROTOOPT;
+
+  int copy_bytes = std::min(value_len, *len);
+  memcpy(optval, value_ptr, copy_bytes);
+  *len = value_len;
+  return 0;
 }
 
 Error MountNodeSocket::SetSockOpt(int lvl,
@@ -256,6 +275,32 @@
       // SO_REUSEADDR is effectivly always on since we can't
       // disable it with PPAPI sockets. Just return success
       // here regardless.
+      if (len < sizeof(int))
+        return EINVAL;
+      return 0;
+    }
+    case SO_LINGER: {
+      // Not supported by the PPAPI interface but we preserve
+      // the settings and pretend to support it.
+      if (len < sizeof(struct linger))
+        return EINVAL;
+      struct linger new_linger = *static_cast<const linger*>(optval);
+      // Don't allow setting linger to be enabled until we
+      // implement the required synchronous shutdown()/close().
+      // TODO(sbc): remove this after http://crbug.com/312401
+      // gets fixed.
+      if (new_linger.l_onoff != 0)
+        return EINVAL;
+      linger_ = new_linger;
+      return 0;
+    }
+    case SO_KEEPALIVE: {
+      // Not supported by the PPAPI interface but we preserve
+      // the flag and pretend to support it.
+      if (len < sizeof(int))
+        return EINVAL;
+      int value = *static_cast<const int*>(optval);
+      keep_alive_ = value != 0;
       return 0;
     }
   }
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
index 900247f..3ecb3db 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
@@ -157,6 +157,8 @@
   PP_Resource remote_addr_;
   uint32_t socket_flags_;
   int last_errno_;
+  bool keep_alive_;
+  struct linger linger_;
 
   friend class KernelProxy;
   friend class MountStream;
diff --git a/native_client_sdk/src/libraries/nacl_io/poll.h b/native_client_sdk/src/libraries/nacl_io/poll.h
deleted file mode 100644
index 842d1ee..0000000
--- a/native_client_sdk/src/libraries/nacl_io/poll.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2013 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 LIBRARIES_NACL_IO_POLL_H_
-#define LIBRARIES_NACL_IO_POLL_H_
-
-#include <stdint.h>
-
-#include "sdk_util/macros.h"
-
-EXTERN_C_BEGIN
-
-/* This header adds definitions of flags and structures for use with poll on
- * toolchains with 'C' libraries which do not normally supply poll. */
-
-/* Node state flags */
-#define POLLIN   0x0001   /* Will not block READ select/poll. */
-#define POLLPRI  0x0002   /* There is urgent data to read. */
-#define POLLOUT  0x0004   /* Will not block WRITE select/poll. */
-#define POLLERR  0x0008   /* Will not block EXECPT select/poll. */
-#define POLLHUP  0x0010   /* Connection closed on far side. */
-#define POLLNVAL 0x0020   /* Invalid FD. */
-
-/* Number of file descriptors. */
-typedef int nfds_t;
-
-struct pollfd {
-  int fd;
-  uint16_t events;
-  uint16_t revents;
-};
-
-int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
-
-EXTERN_C_END
-
-#endif  /* LIBRARIES_NACL_IO_POLL_H_ */
-
diff --git a/native_client_sdk/src/resources/manifest.json.template b/native_client_sdk/src/resources/manifest.json.template
index e7e9760..31882ce 100644
--- a/native_client_sdk/src/resources/manifest.json.template
+++ b/native_client_sdk/src/resources/manifest.json.template
@@ -1,6 +1,7 @@
 {
   "name": "{{name}}",
   "version": "{{version}}",
+  "minimum_chrome_version": "{{version}}",
   "manifest_version": 2,
   "description": "{{description}}",
   "offline_enabled": true,
@@ -16,7 +17,13 @@
   "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMN716Qyu0l2EHNFqIJVqVysFcTR6urqhaGGqW4UK7slBaURz9+Sb1b4Ot5P1uQNE5c+CTU5Vu61wpqmSqMMxqHLWdPPMh8uRlyctsb2cxWwG6XoGSvpX29NsQVUFXd4v2tkJm3G9t+V0X8TYskrvWQmnyOW8OEIDvrBhUEfFxWQIDAQAB",
 [[]]
   "oauth2": {
+[[if channel == 'Dev':]]
+    "client_id": "903965034255-q5lhuqj5eefbatdfif3gv0mdbo0a86pr.apps.googleusercontent.com",
+[[elif channel == 'Beta':]]
+    "client_id": "903965034255-gp3p4hqr1bd7a1v0etf6icdlu5rets1p.apps.googleusercontent.com",
+[[else:]]
     "client_id": "903965034255.apps.googleusercontent.com",
+[[]]
     "scopes": ["https://www.googleapis.com/auth/drive"]
   },
   "permissions": {{permissions}}
diff --git a/native_client_sdk/src/resources/screenshot_earth_1280.png b/native_client_sdk/src/resources/screenshot_earth_1280.png
new file mode 100644
index 0000000..912c0b3
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_earth_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_gles_1280.png b/native_client_sdk/src/resources/screenshot_gles_1280.png
deleted file mode 100644
index 853a6bc..0000000
--- a/native_client_sdk/src/resources/screenshot_gles_1280.png
+++ /dev/null
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_graphics2d_1280.png b/native_client_sdk/src/resources/screenshot_graphics2d_1280.png
new file mode 100644
index 0000000..44ac44f
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_graphics2d_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_graphics3d_1280.png b/native_client_sdk/src/resources/screenshot_graphics3d_1280.png
new file mode 100644
index 0000000..ee03087
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_graphics3d_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_life_1280.png b/native_client_sdk/src/resources/screenshot_life_1280.png
new file mode 100644
index 0000000..4a14e9b
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_life_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_pi_1280.png b/native_client_sdk/src/resources/screenshot_pi_1280.png
deleted file mode 100644
index 4dad188..0000000
--- a/native_client_sdk/src/resources/screenshot_pi_1280.png
+++ /dev/null
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_voronoi_1280.png b/native_client_sdk/src/resources/screenshot_voronoi_1280.png
new file mode 100644
index 0000000..1638ac7
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_voronoi_1280.png
Binary files differ
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
index 579337a..f0079da 100644
--- a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
@@ -281,13 +281,14 @@
   IP4ToSockAddr(LOCAL_HOST, PORT1, &addr);
 
   ASSERT_EQ(0, connect(sock_, (sockaddr*) &addr, addrlen))
-    << "Failed with " << errno << ": " << strerror(errno) << "\n";
+      << "Failed with " << errno << ": " << strerror(errno) << "\n";
 
   // Send two different messages to the echo server and verify the
   // response matches.
   strcpy(outbuf, "hello");
   memset(inbuf, 0, sizeof(inbuf));
-  ASSERT_EQ(sizeof(outbuf), write(sock_, outbuf, sizeof(outbuf)));
+  ASSERT_EQ(sizeof(outbuf), write(sock_, outbuf, sizeof(outbuf)))
+      << "socket write failed with: " << strerror(errno);
   ASSERT_EQ(sizeof(outbuf), read(sock_, inbuf, sizeof(inbuf)));
   EXPECT_EQ(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
 
@@ -340,11 +341,6 @@
   ASSERT_EQ(0, socket_error);
   ASSERT_EQ(sizeof(socket_error), len);
 
-  int reuse = 0;
-  len = sizeof(reuse);
-  ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &reuse, &len));
-  ASSERT_EQ(1, reuse);
-
   // Test for an invalid option (-1)
   ASSERT_EQ(-1, getsockopt(sock1_, SOL_SOCKET, -1, &socket_error, &len));
   ASSERT_EQ(ENOPROTOOPT, errno);
@@ -360,9 +356,72 @@
   ASSERT_EQ(-1, setsockopt(sock1_, SOL_SOCKET, SO_ERROR, &socket_error, len));
   ASSERT_EQ(ENOPROTOOPT, errno);
 
-  int reuse = 1;
-  len = sizeof(reuse);
-  ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &reuse, len));
+}
+
+TEST_F(SocketTest, Sockopt_KEEPALIVE) {
+  sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+  ASSERT_GT(sock1_, -1);
+  sock2_ = socket(AF_INET, SOCK_DGRAM, 0);
+  ASSERT_GT(sock2_, -1);
+
+  int value = 0;
+  socklen_t len = sizeof(value);
+  ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_KEEPALIVE, &value, &len));
+  ASSERT_EQ(0, value);
+  ASSERT_EQ(sizeof(int), len);
+}
+
+// Disabled until we support SO_LINGER (i.e. syncronouse close()/shutdown())
+// TODO(sbc): re-enable once we fix http://crbug.com/312401
+TEST_F(SocketTest, DISABLED_Sockopt_LINGER) {
+  sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+  ASSERT_GT(sock1_, -1);
+  sock2_ = socket(AF_INET, SOCK_DGRAM, 0);
+  ASSERT_GT(sock2_, -1);
+
+  struct linger linger = { 7, 8 };
+  socklen_t len = sizeof(linger);
+  ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, &len));
+  ASSERT_EQ(0, linger.l_onoff);
+  ASSERT_EQ(0, linger.l_linger);
+  ASSERT_EQ(sizeof(struct linger), len);
+  ASSERT_EQ(0, getsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, &len));
+  ASSERT_EQ(0, linger.l_onoff);
+  ASSERT_EQ(0, linger.l_linger);
+  ASSERT_EQ(sizeof(struct linger), len);
+
+  linger.l_onoff = 1;
+  linger.l_linger = 77;
+  len = sizeof(linger);
+  ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, len));
+  linger.l_onoff = 1;
+  linger.l_linger = 88;
+  ASSERT_EQ(0, setsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, len));
+
+  len = sizeof(linger);
+  ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, &len));
+  ASSERT_EQ(1, linger.l_onoff);
+  ASSERT_EQ(77, linger.l_linger);
+  ASSERT_EQ(sizeof(struct linger), len);
+  ASSERT_EQ(0, getsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, &len));
+  ASSERT_EQ(1, linger.l_onoff);
+  ASSERT_EQ(88, linger.l_linger);
+  ASSERT_EQ(sizeof(struct linger), len);
+}
+
+TEST_F(SocketTest, Sockopt_REUSEADDR) {
+  int value = 1;
+  socklen_t len = sizeof(value);
+  sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+
+  ASSERT_GT(sock1_, -1);
+  ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &value, len));
+
+  value = 0;
+  len = sizeof(value);
+  ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &value, &len));
+  ASSERT_EQ(1, value);
+  ASSERT_EQ(sizeof(int), len);
 }
 
 // The size of the data to send is deliberately chosen to be
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
index a7ea159..5c0a772 100644
--- a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
@@ -71,6 +71,39 @@
 
 }  // namespace
 
+static int ki_fcntl_wrapper(int fd, int request, ...) {
+  va_list ap;
+  va_start(ap, request);
+  int rtn = ki_fcntl(fd, request, ap);
+  va_end(ap);
+  return rtn;
+}
+
+/**
+ * Test for fcntl commands F_SETFD and F_GETFD.  This
+ * is tested here rather than in the mount_node tests
+ * since the fd flags are not stored in the kernel_handle
+ * or the mount node but directly in the FD mapping.
+ */
+TEST_F(KernelProxyTest, Fcntl_GETFD) {
+  int fd = ki_open("/test", O_RDWR | O_CREAT);
+  ASSERT_NE(-1, fd);
+
+  // FD flags should start as zero.
+  ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
+
+  // Check that setting FD_CLOEXEC works
+  int flags = FD_CLOEXEC;
+  ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
+    << "fcntl failed with: " << strerror(errno);
+  ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
+
+  // Check that setting invalid flag causes EINVAL
+  flags = FD_CLOEXEC + 1;
+  ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
+  ASSERT_EQ(EINVAL, errno);
+}
+
 TEST_F(KernelProxyTest, FileLeak) {
   const size_t buffer_size = 1024;
   char filename[128];
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
index 666b104..751e9fe 100644
--- a/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
@@ -161,13 +161,16 @@
   EXPECT_EQ(0, memcmp(buffer, data, 100));
 }
 
-TEST(MountNodeTest, Fcntl) {
+TEST(MountNodeTest, Fcntl_GETFL) {
   MockNode* node = new MockNode();
   ScopedMount mnt(new MockMount());
   ScopedMountNode file(node);
   KernelHandle handle(mnt, file);
   ASSERT_EQ(0, handle.Init(O_CREAT | O_APPEND));
 
+  // Test invalid fcntl command.
+  ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
+
   // Test F_GETFL
   ASSERT_EQ(0, node->Init(0));
   int flags = 0;
diff --git a/native_client_sdk/src/tools/nacl_llvm.mk b/native_client_sdk/src/tools/nacl_llvm.mk
index 6ed84dd..a3df271 100644
--- a/native_client_sdk/src/tools/nacl_llvm.mk
+++ b/native_client_sdk/src/tools/nacl_llvm.mk
@@ -130,11 +130,6 @@
 # using the finalizing to a .pexe.  This enables debugging.
 #
 define LINK_RULE
-ifeq ($(CONFIG),Debug)
-EXECUTABLES=$(OUTDIR)/$(1)_x86_32.nexe $(OUTDIR)/$(1)_x86_64.nexe $(OUTDIR)/$(1)_arm.nexe
-else
-EXECUTABLES=$(OUTDIR)/$(1).pexe
-endif
 $(call LINKER_RULE,$(OUTDIR)/$(1),$(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_pnacl)),$(filter-out pthread,$(3)),$(4),$(LIB_PATHS),$(5))
 endef
 
@@ -170,6 +165,12 @@
 #
 NMF:=python $(NACL_SDK_ROOT)/tools/create_nmf.py
 
+ifeq ($(CONFIG),Debug)
+EXECUTABLES=$(OUTDIR)/$(1)_x86_32.nexe $(OUTDIR)/$(1)_x86_64.nexe $(OUTDIR)/$(1)_arm.nexe
+else
+EXECUTABLES=$(OUTDIR)/$(1).pexe
+endif
+
 define NMF_RULE
 all: $(OUTDIR)/$(1).nmf
 $(OUTDIR)/$(1).nmf: $(EXECUTABLES)
diff --git a/native_client_sdk/src/tools/sel_ldr.py b/native_client_sdk/src/tools/sel_ldr.py
index e500192..d730ffb 100755
--- a/native_client_sdk/src/tools/sel_ldr.py
+++ b/native_client_sdk/src/tools/sel_ldr.py
@@ -59,8 +59,6 @@
     raise Error('not a file: %s' % nexe)
 
   arch, dynamic = create_nmf.ParseElfHeader(nexe)
-  if osname == 'mac' and arch == 'x86-64':
-    raise Error('Running of x86-64 executables is not supported on mac')
 
   if arch == 'arm':
     raise Error('Cannot run ARM executables under sel_ldr')
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
index a5de983..9de8c5c 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
@@ -51,7 +51,7 @@
     private static NetworkChangeNotifier sInstance;
 
     private NetworkChangeNotifier(Context context) {
-        mContext = context;
+        mContext = context.getApplicationContext();
         mNativeChangeNotifiers = new ArrayList<Integer>();
         mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
     }
diff --git a/net/android/java/src/org/chromium/net/ProxyChangeListener.java b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
index 9c59bcc..ce9aabb 100644
--- a/net/android/java/src/org/chromium/net/ProxyChangeListener.java
+++ b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
@@ -10,6 +10,9 @@
 import android.content.IntentFilter;
 import android.net.Proxy;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
 import org.chromium.base.NativeClassQualifiedName;
@@ -26,6 +29,15 @@
     private ProxyReceiver mProxyReceiver;
     private Delegate mDelegate;
 
+    private static class ProxyConfig {
+        public ProxyConfig(String host, int port) {
+            mHost = host;
+            mPort = port;
+        }
+        public final String mHost;
+        public final int mPort;
+    };
+
     public interface Delegate {
         public void proxySettingsChanged();
     }
@@ -69,12 +81,49 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
-                proxySettingsChanged();
+                proxySettingsChanged(extractNewProxy(intent));
+            }
+        }
+
+        // Extract a ProxyConfig object from the supplied Intent's extra data
+        // bundle. The android.net.ProxyProperties class is not exported from
+        // tne Android SDK, so we have to use reflection to get at it and invoke
+        // methods on it. If we fail, return an empty proxy config (meaning
+        // 'direct').
+        // TODO(ellyjones): once android.net.ProxyProperties is exported,
+        // rewrite this.
+        private ProxyConfig extractNewProxy(Intent intent) {
+            try {
+                final String CLASS_NAME = "android.net.ProxyProperties";
+                final String GET_HOST_NAME = "getHost";
+                final String GET_PORT_NAME = "getPort";
+                Object props = intent.getExtras().get("proxy");
+                if (props == null) {
+                    return null;
+                }
+                Class cls = Class.forName(CLASS_NAME);
+                Method getHostMethod = cls.getDeclaredMethod(GET_HOST_NAME);
+                Method getPortMethod = cls.getDeclaredMethod(GET_PORT_NAME);
+
+                String host = (String)getHostMethod.invoke(props);
+                int port = (Integer)getPortMethod.invoke(props);
+
+                return new ProxyConfig(host, port);
+            } catch (ClassNotFoundException ex) {
+                return null;
+            } catch (NoSuchMethodException ex) {
+                return null;
+            } catch (IllegalAccessException ex) {
+                return null;
+            } catch (InvocationTargetException ex) {
+                return null;
+            } catch (NullPointerException ex) {
+                return null;
             }
         }
     }
 
-    private void proxySettingsChanged() {
+    private void proxySettingsChanged(ProxyConfig cfg) {
         if (!sEnabled) {
             return;
         }
@@ -86,7 +135,11 @@
         }
         // Note that this code currently runs on a MESSAGE_LOOP_UI thread, but
         // the C++ code must run the callbacks on the network thread.
-        nativeProxySettingsChanged(mNativePtr);
+        if (cfg != null) {
+            nativeProxySettingsChangedTo(mNativePtr, cfg.mHost, cfg.mPort);
+        } else {
+            nativeProxySettingsChanged(mNativePtr);
+        }
     }
 
     private void registerReceiver() {
@@ -111,5 +164,9 @@
      * See net/proxy/proxy_config_service_android.cc
      */
     @NativeClassQualifiedName("ProxyConfigServiceAndroid::JNIDelegate")
+    private native void nativeProxySettingsChangedTo(int nativePtr,
+                                                     String host,
+                                                     int port);
+    @NativeClassQualifiedName("ProxyConfigServiceAndroid::JNIDelegate")
     private native void nativeProxySettingsChanged(int nativePtr);
 }
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java
index 30007ca..4358f2b 100644
--- a/net/android/java/src/org/chromium/net/X509Util.java
+++ b/net/android/java/src/org/chromium/net/X509Util.java
@@ -4,8 +4,14 @@
 
 package org.chromium.net;
 
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.security.KeyChain;
 import android.util.Log;
 
+import org.chromium.base.JNINamespace;
 import org.chromium.net.CertVerifyResultAndroid;
 
 import java.io.ByteArrayInputStream;
@@ -25,10 +31,30 @@
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+@JNINamespace("net")
 public class X509Util {
 
     private static final String TAG = "X509Util";
 
+    public static final class TrustStorageListener extends BroadcastReceiver {
+        @Override public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+                try {
+                    reloadDefaultTrustManager();
+                }
+                catch (CertificateException e) {
+                    Log.e(TAG, "Unable to reload the default TrustManager", e);
+                }
+                catch (KeyStoreException e) {
+                    Log.e(TAG, "Unable to reload the default TrustManager", e);
+                }
+                catch (NoSuchAlgorithmException e) {
+                    Log.e(TAG, "Unable to reload the default TrustManager", e);
+                }
+            }
+        }
+    }
+
     private static CertificateFactory sCertificateFactory;
 
     private static final String OID_TLS_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";
@@ -45,6 +71,12 @@
     private static X509TrustManager sDefaultTrustManager;
 
     /**
+     * BroadcastReceiver that listens to change in the system keystore to invalidate certificate
+     * caches.
+     */
+    private static TrustStorageListener sTrustStorageListener;
+
+    /**
      * Trust manager backed up by a custom certificate store. We need such manager to plant test
      * root CA to the trust store in testing.
      */
@@ -56,6 +88,13 @@
      */
     private static final Object sLock = new Object();
 
+    /*
+     * Allow disabling registering the observer for the certificat changes. Net unit tests do not
+     * load native libraries which prevent this to succeed. Moreover, the system does not allow to
+     * interact with the certificate store without user interaction.
+     */
+    private static boolean sDisableCertificateObservationForTest = false;
+
     /**
      * Ensures that the trust managers and certificate factory are initialized.
      */
@@ -77,6 +116,12 @@
             if (sTestTrustManager == null) {
                 sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
             }
+            if (!sDisableCertificateObservationForTest &&
+                    sTrustStorageListener == null) {
+                sTrustStorageListener = new TrustStorageListener();
+                nativeGetApplicationContext().registerReceiver(sTrustStorageListener,
+                        new IntentFilter(KeyChain.ACTION_STORAGE_CHANGED));
+            }
         }
     }
 
@@ -108,6 +153,16 @@
     }
 
     /**
+     * After each modification by the system of the key store, trust manager has to be regenerated.
+     */
+    private static void reloadDefaultTrustManager() throws KeyStoreException,
+            NoSuchAlgorithmException, CertificateException {
+        sDefaultTrustManager = null;
+        nativeNotifyKeyChainChanged();
+        ensureInitialized();
+    }
+
+    /**
      * Convert a DER encoded certificate to an X509Certificate.
      */
     public static X509Certificate createCertificateFromBytes(byte[] derBytes) throws
@@ -230,4 +285,18 @@
             }
         }
     }
+
+    public static void setDisableCertificateObservationForTest(boolean disabled) {
+        sDisableCertificateObservationForTest = disabled;
+    }
+    /**
+     * Notify the native net::CertDatabase instance that the system database has been updated.
+     */
+    private static native void nativeNotifyKeyChainChanged();
+
+    /**
+     * Returns the application context.
+     */
+    private static native Context nativeGetApplicationContext();
+
 }
diff --git a/net/android/javatests/src/org/chromium/net/X509UtilTest.java b/net/android/javatests/src/org/chromium/net/X509UtilTest.java
index 7dcbc68..e5c3f6f 100644
--- a/net/android/javatests/src/org/chromium/net/X509UtilTest.java
+++ b/net/android/javatests/src/org/chromium/net/X509UtilTest.java
@@ -71,6 +71,11 @@
         return bytes;
     }
 
+    @Override
+    public void setUp() {
+        X509Util.setDisableCertificateObservationForTest(true);
+    }
+
     @MediumTest
     public void testEkusVerified() throws GeneralSecurityException, IOException {
         X509Util.addTestRootCertificate(pemToDer(CERTS_DIRECTORY + BAD_EKU_TEST_ROOT));
diff --git a/net/android/net_jni_registrar.cc b/net/android/net_jni_registrar.cc
index a6e09b6..f7712bb 100644
--- a/net/android/net_jni_registrar.cc
+++ b/net/android/net_jni_registrar.cc
@@ -11,6 +11,7 @@
 #include "net/android/keystore.h"
 #include "net/android/network_change_notifier_android.h"
 #include "net/android/network_library.h"
+#include "net/cert/x509_util_android.h"
 #include "net/proxy/proxy_config_service_android.h"
 
 namespace net {
@@ -23,6 +24,7 @@
   { "NetworkChangeNotifierAndroid",
     net::NetworkChangeNotifierAndroid::Register },
   { "ProxyConfigService", net::ProxyConfigServiceAndroid::Register },
+  { "X509Util", net::RegisterX509Util },
 };
 
 bool RegisterJni(JNIEnv* env) {
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 837de5f..f31bcca 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -666,8 +666,8 @@
 EVENT_TYPE(TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS)
 
 
-// A backup socket is created due to slow connect
-EVENT_TYPE(SOCKET_BACKUP_CREATED)
+// A backup connect job is created due to slow connect.
+EVENT_TYPE(BACKUP_CONNECT_JOB_CREATED)
 
 // This event is sent when a connect job is eventually bound to a request
 // (because of late binding and socket backup jobs, we don't assign the job to
@@ -726,14 +726,16 @@
 //   }
 EVENT_TYPE(URL_REQUEST_REDIRECTED)
 
-// Measures the time a net::URLRequest is blocked waiting for either the
-// NetworkDelegate or a URLRequest::Delegate to respond.
-//
-// The parameters attached to the event are:
+// Measures the time between when a net::URLRequest calls a delegate that can
+// block it, and when the delegate allows the request to resume.
+EVENT_TYPE(URL_REQUEST_DELEGATE)
+
+// Logged when a delegate informs the URL_REQUEST of what's currently blocking
+// the request. The parameters attached to the begin event are:
 //   {
-//     "delegate": <What's blocking the request, if known>,
+//     "delegate_info": <Information about what's blocking the request>,
 //   }
-EVENT_TYPE(URL_REQUEST_BLOCKED_ON_DELEGATE)
+EVENT_TYPE(DELEGATE_INFO)
 
 // The specified number of bytes were read from the net::URLRequest.
 // The filtered event is used when the bytes were passed through a filter before
diff --git a/net/base/net_log_unittest.h b/net/base/net_log_unittest.h
index 32fb5f8..574e318 100644
--- a/net/base/net_log_unittest.h
+++ b/net/base/net_log_unittest.h
@@ -107,6 +107,23 @@
   return ::testing::AssertionSuccess();
 }
 
+// Check if the log contains any entry of the given type at |min_index| or
+// after.
+inline ::testing::AssertionResult LogContainsEntryWithTypeAfter(
+    const CapturingNetLog::CapturedEntryList& entries,
+    int min_index, // Negative indices are reverse indices.
+    NetLog::EventType type) {
+  // Negative indices are reverse indices.
+  size_t real_index = (min_index < 0) ?
+      static_cast<size_t>(static_cast<int>(entries.size()) + min_index) :
+      static_cast<size_t>(min_index);
+  for (size_t i = real_index; i < entries.size(); ++i) {
+    const CapturingNetLog::CapturedEntry& entry = entries[i];
+    if (entry.type == type)
+      return ::testing::AssertionSuccess();
+  }
+  return ::testing::AssertionFailure();
+}
 
 // Expect that the log contains an event, but don't care about where
 // as long as the first index where it is found is at least |min_index|.
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 5a69b86..834769c 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
 #include "net/url_request/url_request.h"
 
 namespace net {
@@ -92,6 +93,21 @@
   return OnAuthRequired(request, auth_info, callback, credentials);
 }
 
+int NetworkDelegate::NotifyBeforeSocketStreamConnect(
+    SocketStream* socket,
+    const CompletionCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(socket);
+  DCHECK(!callback.is_null());
+  return OnBeforeSocketStreamConnect(socket, callback);
+}
+
+void NetworkDelegate::NotifyRequestWaitStateChange(const URLRequest& request,
+                                                   RequestWaitState state) {
+  DCHECK(CalledOnValidThread());
+  OnRequestWaitStateChange(request, state);
+}
+
 bool NetworkDelegate::CanGetCookies(const URLRequest& request,
                                     const CookieList& cookie_list) {
   DCHECK(CalledOnValidThread());
@@ -125,26 +141,93 @@
   return OnCanEnablePrivacyMode(url, first_party_for_cookies);
 }
 
-bool NetworkDelegate::OnCanEnablePrivacyMode(
-    const GURL& url,
-    const GURL& first_party_for_cookies) const {
-  // Default implementation disables privacy mode.
+int NetworkDelegate::OnBeforeURLRequest(URLRequest* request,
+                                        const CompletionCallback& callback,
+                                        GURL* new_url) {
+  return OK;
+}
+
+int NetworkDelegate::OnBeforeSendHeaders(URLRequest* request,
+                                         const CompletionCallback& callback,
+                                         HttpRequestHeaders* headers) {
+  return OK;
+}
+
+void NetworkDelegate::OnSendHeaders(URLRequest* request,
+                                    const HttpRequestHeaders& headers) {
+}
+
+int NetworkDelegate::OnHeadersReceived(
+    URLRequest* request,
+    const CompletionCallback& callback,
+    const HttpResponseHeaders* original_response_headers,
+    scoped_refptr<HttpResponseHeaders>* override_response_headers) {
+  return OK;
+}
+
+void NetworkDelegate::OnBeforeRedirect(URLRequest* request,
+                                       const GURL& new_location) {
+}
+
+void NetworkDelegate::OnResponseStarted(URLRequest* request) {
+}
+
+void NetworkDelegate::OnRawBytesRead(const URLRequest& request,
+                                     int bytes_read) {
+}
+
+void NetworkDelegate::OnCompleted(URLRequest* request, bool started) {
+}
+
+void NetworkDelegate::OnURLRequestDestroyed(URLRequest* request) {
+}
+
+void NetworkDelegate::OnPACScriptError(int line_number,
+                                       const base::string16& error) {
+}
+
+NetworkDelegate::AuthRequiredResponse NetworkDelegate::OnAuthRequired(
+    URLRequest* request,
+    const AuthChallengeInfo& auth_info,
+    const AuthCallback& callback,
+    AuthCredentials* credentials) {
+  return AUTH_REQUIRED_RESPONSE_NO_ACTION;
+}
+
+bool NetworkDelegate::OnCanGetCookies(const URLRequest& request,
+                                      const CookieList& cookie_list)  {
+  return true;
+}
+
+bool NetworkDelegate::OnCanSetCookie(const URLRequest& request,
+                                     const std::string& cookie_line,
+                                     CookieOptions* options) {
+  return true;
+}
+
+bool NetworkDelegate::OnCanAccessFile(const URLRequest& request,
+                                      const base::FilePath& path) const  {
   return false;
 }
 
-int NetworkDelegate::NotifyBeforeSocketStreamConnect(
-    SocketStream* socket,
-    const CompletionCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(socket);
-  DCHECK(!callback.is_null());
-  return OnBeforeSocketStreamConnect(socket, callback);
+bool NetworkDelegate::OnCanThrottleRequest(const URLRequest& request) const {
+  return false;
 }
 
-void NetworkDelegate::NotifyRequestWaitStateChange(const URLRequest& request,
-                                                   RequestWaitState state) {
-  DCHECK(CalledOnValidThread());
-  OnRequestWaitStateChange(request, state);
+bool NetworkDelegate::OnCanEnablePrivacyMode(
+    const GURL& url,
+    const GURL& first_party_for_cookies) const {
+  return false;
+}
+
+int NetworkDelegate::OnBeforeSocketStreamConnect(
+    SocketStream* socket,
+    const CompletionCallback& callback) {
+  return OK;
+}
+
+void NetworkDelegate::OnRequestWaitStateChange(const URLRequest& request,
+                                               RequestWaitState state) {
 }
 
 }  // namespace net
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 4b64964..21c8e65 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -118,67 +118,66 @@
   // ERR_IO_PENDING if the result is not ready yet. A status code other than OK
   // and ERR_IO_PENDING will cancel the request and report the status code as
   // the reason.
+  //
+  // The default implementation returns OK (continue with request).
   virtual int OnBeforeURLRequest(URLRequest* request,
                                  const CompletionCallback& callback,
-                                 GURL* new_url) = 0;
+                                 GURL* new_url);
 
   // Called right before the HTTP headers are sent. Allows the delegate to
   // read/write |headers| before they get sent out. |callback| and |headers| are
   // valid only until OnCompleted or OnURLRequestDestroyed is called for this
   // request.
-  // Returns a net status code.
+  // See OnBeforeURLRequest for return value description. Returns OK by default.
   virtual int OnBeforeSendHeaders(URLRequest* request,
                                   const CompletionCallback& callback,
-                                  HttpRequestHeaders* headers) = 0;
+                                  HttpRequestHeaders* headers);
 
   // Called right before the HTTP request(s) are being sent to the network.
   // |headers| is only valid until OnCompleted or OnURLRequestDestroyed is
   // called for this request.
   virtual void OnSendHeaders(URLRequest* request,
-                             const HttpRequestHeaders& headers) = 0;
+                             const HttpRequestHeaders& headers);
 
-  // Called for HTTP requests when the headers have been received. Returns a net
-  // status code, generally either OK to continue with the request or
-  // ERR_IO_PENDING if the result is not ready yet.  A status code other than OK
-  // and ERR_IO_PENDING will cancel the request and report the status code as
-  // the reason.
+  // Called for HTTP requests when the headers have been received.
   // |original_response_headers| contains the headers as received over the
   // network, these must not be modified. |override_response_headers| can be set
   // to new values, that should be considered as overriding
   // |original_response_headers|.
   // |callback|, |original_response_headers|, and |override_response_headers|
   // are only valid until OnURLRequestDestroyed is called for this request.
+  // See OnBeforeURLRequest for return value description. Returns OK by default.
   virtual int OnHeadersReceived(
       URLRequest* request,
       const CompletionCallback& callback,
       const HttpResponseHeaders* original_response_headers,
-      scoped_refptr<HttpResponseHeaders>* override_response_headers) = 0;
+      scoped_refptr<HttpResponseHeaders>* override_response_headers);
 
   // Called right after a redirect response code was received.
   // |new_location| is only valid until OnURLRequestDestroyed is called for this
   // request.
   virtual void OnBeforeRedirect(URLRequest* request,
-                                const GURL& new_location) = 0;
+                                const GURL& new_location);
 
   // This corresponds to URLRequestDelegate::OnResponseStarted.
-  virtual void OnResponseStarted(URLRequest* request) = 0;
+  virtual void OnResponseStarted(URLRequest* request);
 
   // Called every time we read raw bytes.
-  virtual void OnRawBytesRead(const URLRequest& request, int bytes_read) = 0;
+  virtual void OnRawBytesRead(const URLRequest& request, int bytes_read);
 
   // Indicates that the URL request has been completed or failed.
   // |started| indicates whether the request has been started. If false,
   // some information like the socket address is not available.
-  virtual void OnCompleted(URLRequest* request, bool started) = 0;
+  virtual void OnCompleted(URLRequest* request, bool started);
 
   // Called when an URLRequest is being destroyed. Note that the request is
   // being deleted, so it's not safe to call any methods that may result in
   // a virtual method call.
-  virtual void OnURLRequestDestroyed(URLRequest* request) = 0;
+  virtual void OnURLRequestDestroyed(URLRequest* request);
 
   // Corresponds to ProxyResolverJSBindings::OnError.
   virtual void OnPACScriptError(int line_number,
-                                const base::string16& error) = 0;
+                                const base::string16& error);
 
   // Called when a request receives an authentication challenge
   // specified by |auth_info|, and is unable to respond using cached
@@ -201,31 +200,31 @@
       URLRequest* request,
       const AuthChallengeInfo& auth_info,
       const AuthCallback& callback,
-      AuthCredentials* credentials) = 0;
+      AuthCredentials* credentials);
 
   // Called when reading cookies to allow the network delegate to block access
   // to the cookie. This method will never be invoked when
   // LOAD_DO_NOT_SEND_COOKIES is specified.
   virtual bool OnCanGetCookies(const URLRequest& request,
-                               const CookieList& cookie_list) = 0;
+                               const CookieList& cookie_list);
 
   // Called when a cookie is set to allow the network delegate to block access
   // to the cookie. This method will never be invoked when
   // LOAD_DO_NOT_SAVE_COOKIES is specified.
   virtual bool OnCanSetCookie(const URLRequest& request,
                               const std::string& cookie_line,
-                              CookieOptions* options) = 0;
+                              CookieOptions* options);
 
   // Called when a file access is attempted to allow the network delegate to
   // allow or block access to the given file path.  Returns true if access is
   // allowed.
   virtual bool OnCanAccessFile(const URLRequest& request,
-                               const base::FilePath& path) const = 0;
+                               const base::FilePath& path) const;
 
   // Returns true if the given request may be rejected when the
   // URLRequestThrottlerManager believes the server servicing the
   // request is overloaded or down.
-  virtual bool OnCanThrottleRequest(const URLRequest& request) const = 0;
+  virtual bool OnCanThrottleRequest(const URLRequest& request) const;
 
   // Returns true if the given |url| has to be requested over connection that
   // is not tracked by the server. Usually is false, unless user privacy
@@ -235,15 +234,16 @@
       const GURL& first_party_for_cookies) const;
 
   // Called before a SocketStream tries to connect.
+  // See OnBeforeURLRequest for return value description. Returns OK by default.
   virtual int OnBeforeSocketStreamConnect(
-      SocketStream* socket, const CompletionCallback& callback) = 0;
+      SocketStream* socket, const CompletionCallback& callback);
 
   // Called when the completion of a URLRequest is blocking on a cache
   // action or a network action, or when that is no longer the case.
   // REQUEST_WAIT_STATE_RESET indicates for a given URLRequest
   // cancellation of any pending waits for this request.
   virtual void OnRequestWaitStateChange(const URLRequest& request,
-                                        RequestWaitState state) = 0;
+                                        RequestWaitState state);
 };
 
 }  // namespace net
diff --git a/net/base/priority_queue.h b/net/base/priority_queue.h
index c684580..7b7d97c 100644
--- a/net/base/priority_queue.h
+++ b/net/base/priority_queue.h
@@ -90,13 +90,16 @@
    private:
     friend class PriorityQueue;
 
-    // Note that we need iterator not const_iterator to pass to List::erase.
-    // When C++0x comes, this could be changed to const_iterator and const could
-    // be added to First, Last, and OldestLowest.
+    // Note that we need iterator and not const_iterator to pass to
+    // List::erase.  When C++11 is turned on for Chromium, this could
+    // be changed to const_iterator and the const_casts in the rest of
+    // the file can be removed.
     typedef typename PriorityQueue::List::iterator ListIterator;
 
     static const Priority kNullPriority = static_cast<Priority>(-1);
 
+    // It is guaranteed that Pointer will treat |iterator| as a
+    // const_iterator.
     Pointer(Priority priority, const ListIterator& iterator)
         : priority_(priority), iterator_(iterator) {
 #if !defined(NDEBUG)
@@ -175,50 +178,80 @@
 
   // Returns a pointer to the first value of minimum priority or a null-pointer
   // if empty.
-  Pointer FirstMin() {
+  Pointer FirstMin() const {
     DCHECK(CalledOnValidThread());
     for (size_t i = 0; i < lists_.size(); ++i) {
-      if (!lists_[i].empty())
-        return Pointer(i, lists_[i].begin());
+      List* list = const_cast<List*>(&lists_[i]);
+      if (!list->empty())
+        return Pointer(i, list->begin());
     }
     return Pointer();
   }
 
   // Returns a pointer to the last value of minimum priority or a null-pointer
   // if empty.
-  Pointer LastMin() {
+  Pointer LastMin() const {
     DCHECK(CalledOnValidThread());
     for (size_t i = 0; i < lists_.size(); ++i) {
-      if (!lists_[i].empty())
-        return Pointer(i, --lists_[i].end());
+      List* list = const_cast<List*>(&lists_[i]);
+      if (!list->empty())
+        return Pointer(i, --list->end());
     }
     return Pointer();
   }
 
   // Returns a pointer to the first value of maximum priority or a null-pointer
   // if empty.
-  Pointer FirstMax() {
+  Pointer FirstMax() const {
     DCHECK(CalledOnValidThread());
     for (size_t i = lists_.size(); i > 0; --i) {
       size_t index = i - 1;
-      if (!lists_[index].empty())
-        return Pointer(index, lists_[index].begin());
+      List* list = const_cast<List*>(&lists_[index]);
+      if (!list->empty())
+        return Pointer(index, list->begin());
     }
     return Pointer();
   }
 
   // Returns a pointer to the last value of maximum priority or a null-pointer
   // if empty.
-  Pointer LastMax() {
+  Pointer LastMax() const {
     DCHECK(CalledOnValidThread());
     for (size_t i = lists_.size(); i > 0; --i) {
       size_t index = i - 1;
-      if (!lists_[index].empty())
-        return Pointer(index, --lists_[index].end());
+      List* list = const_cast<List*>(&lists_[index]);
+      if (!list->empty())
+        return Pointer(index, --list->end());
     }
     return Pointer();
   }
 
+  // Given an ordering of the values in this queue by decreasing
+  // priority and then FIFO, returns a pointer to the value following
+  // the value of the given pointer (which must be non-NULL).
+  //
+  // (One could also implement GetNextTowardsFirstMin() [decreasing
+  // priority, then reverse FIFO] as well as
+  // GetNextTowards{First,Last}Max() [increasing priority, then
+  // {,reverse} FIFO].)
+  Pointer GetNextTowardsLastMin(const Pointer& pointer) const {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!pointer.is_null());
+    DCHECK_LT(pointer.priority_, lists_.size());
+
+    typename Pointer::ListIterator it = pointer.iterator_;
+    Priority priority = pointer.priority_;
+    DCHECK(it != lists_[priority].end());
+    ++it;
+    while (it == lists_[priority].end()) {
+      if (priority == 0u)
+        return Pointer();
+      --priority;
+      it = const_cast<List*>(&lists_[priority])->begin();
+    }
+    return Pointer(priority, it);
+  }
+
   // Empties the queue. All pointers become invalid.
   void Clear() {
     DCHECK(CalledOnValidThread());
@@ -232,7 +265,15 @@
   }
 
   // Returns the number of priorities the queue supports.
-  size_t num_priorities() const { return lists_.size(); }
+  size_t num_priorities() const {
+    DCHECK(CalledOnValidThread());
+    return lists_.size();
+  }
+
+  bool empty() const {
+    DCHECK(CalledOnValidThread());
+    return size_ == 0;
+  }
 
   // Returns number of queued values.
   size_t size() const {
diff --git a/net/base/priority_queue_unittest.cc b/net/base/priority_queue_unittest.cc
index 7e3e045..0baff6e 100644
--- a/net/base/priority_queue_unittest.cc
+++ b/net/base/priority_queue_unittest.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "net/base/priority_queue.h"
+
+#include <cstddef>
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -14,7 +17,7 @@
 const Priority kNumPriorities = 5;  // max(kPriorities) + 1
 const size_t kNumElements = arraysize(kPriorities);
 const int kFirstMinOrder[kNumElements] = { 3, 8, 1, 6, 0, 2, 5, 4, 7 };
-const int kLastMaxOrder[kNumElements] = { 7, 4, 5, 2, 0, 6, 1, 8, 3 };
+const int kLastMaxOrderErase[kNumElements] = { 7, 4, 5, 2, 0, 6, 1, 8, 3 };
 const int kFirstMaxOrder[kNumElements] = { 4, 7, 5, 0, 2, 1, 6, 3, 8 };
 const int kLastMinOrder[kNumElements] = { 8, 3, 6, 1, 2, 0, 5, 7, 4 };
 
@@ -27,11 +30,13 @@
     for (size_t i = 0; i < kNumElements; ++i) {
       EXPECT_EQ(i, queue_.size());
       pointers_[i] = queue_.Insert(static_cast<int>(i), kPriorities[i]);
+      EXPECT_FALSE(queue_.empty());
     }
     EXPECT_EQ(kNumElements, queue_.size());
   }
 
   void CheckEmpty() {
+    EXPECT_TRUE(queue_.empty());
     EXPECT_EQ(0u, queue_.size());
     EXPECT_TRUE(queue_.FirstMin().is_null());
     EXPECT_TRUE(queue_.LastMin().is_null());
@@ -72,6 +77,19 @@
 }
 
 TEST_F(PriorityQueueTest, FirstMaxOrder) {
+  PriorityQueue<int>::Pointer p = queue_.FirstMax();
+  size_t i = 0;
+  for (; !p.is_null() && i < kNumElements;
+       p = queue_.GetNextTowardsLastMin(p), ++i) {
+    EXPECT_EQ(kFirstMaxOrder[i], p.value());
+  }
+  EXPECT_TRUE(p.is_null());
+  EXPECT_EQ(kNumElements, i);
+  queue_.Clear();
+  CheckEmpty();
+}
+
+TEST_F(PriorityQueueTest, FirstMaxOrderErase) {
   for (size_t i = 0; i < kNumElements; ++i) {
     EXPECT_EQ(kFirstMaxOrder[i], queue_.FirstMax().value());
     queue_.Erase(queue_.FirstMax());
@@ -79,9 +97,9 @@
   CheckEmpty();
 }
 
-TEST_F(PriorityQueueTest, LastMaxOrder) {
+TEST_F(PriorityQueueTest, LastMaxOrderErase) {
   for (size_t i = 0; i < kNumElements; ++i) {
-    EXPECT_EQ(kLastMaxOrder[i], queue_.LastMax().value());
+    EXPECT_EQ(kLastMaxOrderErase[i], queue_.LastMax().value());
     queue_.Erase(queue_.LastMax());
   }
   CheckEmpty();
diff --git a/net/cert/cert_database.cc b/net/cert/cert_database.cc
index db54172..f36562a 100644
--- a/net/cert/cert_database.cc
+++ b/net/cert/cert_database.cc
@@ -30,10 +30,10 @@
   observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert));
 }
 
-void CertDatabase::NotifyObserversOfCertTrustChanged(
+void CertDatabase::NotifyObserversOfCACertChanged(
     const X509Certificate* cert) {
   observer_list_->Notify(
-      &Observer::OnCertTrustChanged, make_scoped_refptr(cert));
+      &Observer::OnCACertChanged, make_scoped_refptr(cert));
 }
 
 }  // namespace net
diff --git a/net/cert/cert_database.h b/net/cert/cert_database.h
index c4ead81..feadf4c 100644
--- a/net/cert/cert_database.h
+++ b/net/cert/cert_database.h
@@ -40,8 +40,9 @@
     // Will be called when a certificate is removed.
     virtual void OnCertRemoved(const X509Certificate* cert) {}
 
-    // Will be called when a certificate's trust is changed.
-    virtual void OnCertTrustChanged(const X509Certificate* cert) {}
+    // Will be called when a CA certificate was added, removed, or its trust
+    // changed. This can also mean that a client certificate's trust changed.
+    virtual void OnCACertChanged(const X509Certificate* cert) {}
 
    protected:
     Observer() {}
@@ -78,6 +79,12 @@
   void SetMessageLoopForKeychainEvents();
 #endif
 
+#if defined(OS_ANDROID)
+  // On android, the system database is used. When the system notifies the
+  // application that the certificates changed, the observers must be notified.
+  void OnAndroidKeyChainChanged();
+#endif
+
  private:
   friend struct DefaultSingletonTraits<CertDatabase>;
 
@@ -87,7 +94,7 @@
   // Broadcasts notifications to all registered observers.
   void NotifyObserversOfCertAdded(const X509Certificate* cert);
   void NotifyObserversOfCertRemoved(const X509Certificate* cert);
-  void NotifyObserversOfCertTrustChanged(const X509Certificate* cert);
+  void NotifyObserversOfCACertChanged(const X509Certificate* cert);
 
   const scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
 
diff --git a/net/cert/cert_database_android.cc b/net/cert/cert_database_android.cc
index 9755805..350028f 100644
--- a/net/cert/cert_database_android.cc
+++ b/net/cert/cert_database_android.cc
@@ -36,4 +36,9 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
+void CertDatabase::OnAndroidKeyChainChanged() {
+  observer_list_->Notify(&Observer::OnCACertChanged,
+                         scoped_refptr<X509Certificate>());
+}
+
 }  // namespace net
diff --git a/net/cert/cert_database_mac.cc b/net/cert/cert_database_mac.cc
index 7670196..9427be3 100644
--- a/net/cert/cert_database_mac.cc
+++ b/net/cert/cert_database_mac.cc
@@ -103,7 +103,7 @@
   switch (keychain_event) {
     case kSecKeychainListChangedEvent:
     case kSecTrustSettingsChangedEvent:
-      that->cert_db_->NotifyObserversOfCertTrustChanged(NULL);
+      that->cert_db_->NotifyObserversOfCACertChanged(NULL);
       break;
   }
 
diff --git a/net/cert/cert_database_nss.cc b/net/cert/cert_database_nss.cc
index 5fa2721..a1677fe 100644
--- a/net/cert/cert_database_nss.cc
+++ b/net/cert/cert_database_nss.cc
@@ -40,8 +40,8 @@
     cert_db_->NotifyObserversOfCertRemoved(cert);
   }
 
-  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE {
-    cert_db_->NotifyObserversOfCertTrustChanged(cert);
+  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE {
+    cert_db_->NotifyObserversOfCACertChanged(cert);
   }
 
  private:
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index 05f6c30..c6cf9b8 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -206,6 +206,13 @@
   int rv = VerifyInternal(cert, hostname, flags, crl_set,
                           additional_trust_anchors, verify_result);
 
+  UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback",
+                        verify_result->common_name_fallback_used);
+  if (!verify_result->is_issued_by_known_root) {
+    UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallbackPrivateCA",
+                          verify_result->common_name_fallback_used);
+  }
+
   // This check is done after VerifyInternal so that VerifyInternal can fill
   // in the list of public key hashes.
   if (IsPublicKeyBlacklisted(verify_result->public_key_hashes)) {
diff --git a/net/cert/cert_verify_proc_android.cc b/net/cert/cert_verify_proc_android.cc
index 9a8acf7..bca62bc 100644
--- a/net/cert/cert_verify_proc_android.cc
+++ b/net/cert/cert_verify_proc_android.cc
@@ -91,8 +91,10 @@
     CRLSet* crl_set,
     const CertificateList& additional_trust_anchors,
     CertVerifyResult* verify_result) {
-  if (!cert->VerifyNameMatch(hostname))
+  if (!cert->VerifyNameMatch(hostname,
+                             &verify_result->common_name_fallback_used)) {
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
+  }
 
   std::vector<std::string> cert_bytes;
   if (!GetChainDEREncodedBytes(cert, &cert_bytes))
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index 4efdaac..542fba1 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -656,8 +656,10 @@
   // Perform hostname verification independent of SecTrustEvaluate. In order to
   // do so, mask off any reported name errors first.
   verify_result->cert_status &= ~CERT_STATUS_COMMON_NAME_INVALID;
-  if (!cert->VerifyNameMatch(hostname))
+  if (!cert->VerifyNameMatch(hostname,
+                             &verify_result->common_name_fallback_used)) {
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
+  }
 
   // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be
   // compatible with Windows, which in turn implements this behavior to be
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index 0a0743c..31c38c7 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -763,9 +763,10 @@
   CERTCertificate* cert_handle = cert->os_cert_handle();
 #endif  // defined(OS_IOS)
 
-  // Make sure that the hostname matches with the common name of the cert.
-  if (!cert->VerifyNameMatch(hostname))
+  if (!cert->VerifyNameMatch(hostname,
+                             &verify_result->common_name_fallback_used)) {
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
+  }
 
   // Make sure that the cert is valid now.
   SECCertTimeValidity validity = CERT_CheckCertValidTimes(
diff --git a/net/cert/cert_verify_proc_openssl.cc b/net/cert/cert_verify_proc_openssl.cc
index a67f194..906e4cb 100644
--- a/net/cert/cert_verify_proc_openssl.cc
+++ b/net/cert/cert_verify_proc_openssl.cc
@@ -172,8 +172,10 @@
     CertVerifyResult* verify_result) {
   crypto::EnsureOpenSSLInit();
 
-  if (!cert->VerifyNameMatch(hostname))
+  if (!cert->VerifyNameMatch(hostname,
+                             &verify_result->common_name_fallback_used)) {
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
+  }
 
   crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(
       X509_STORE_CTX_new());
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index b64797a..29885ea 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -764,8 +764,10 @@
 
   // Perform hostname verification independent of
   // CertVerifyCertificateChainPolicy.
-  if (!cert->VerifyNameMatch(hostname))
+  if (!cert->VerifyNameMatch(hostname,
+                             &verify_result->common_name_fallback_used)) {
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
+  }
 
   if (!rev_checking_enabled) {
     // If we didn't do online revocation checking then Windows will report
diff --git a/net/cert/cert_verify_result.cc b/net/cert/cert_verify_result.cc
index 68e76a7..82df72c 100644
--- a/net/cert/cert_verify_result.cc
+++ b/net/cert/cert_verify_result.cc
@@ -23,6 +23,7 @@
   has_md4 = false;
   is_issued_by_known_root = false;
   is_issued_by_additional_trust_anchor = false;
+  common_name_fallback_used = false;
 
   public_key_hashes.clear();
 }
diff --git a/net/cert/cert_verify_result.h b/net/cert/cert_verify_result.h
index a00c03e..09deffa 100644
--- a/net/cert/cert_verify_result.h
+++ b/net/cert/cert_verify_result.h
@@ -62,6 +62,10 @@
   // is_issued_by_additional_trust_anchor is true if the root CA used for this
   // verification came from the list of additional trust anchors.
   bool is_issued_by_additional_trust_anchor;
+
+  // True if a fallback to the common name was used when matching the host
+  // name, rather than using the subjectAltName.
+  bool common_name_fallback_used;
 };
 
 }  // namespace net
diff --git a/net/cert/ev_root_ca_metadata.cc b/net/cert/ev_root_ca_metadata.cc
index 174a4ef..04f4bda 100644
--- a/net/cert/ev_root_ca_metadata.cc
+++ b/net/cert/ev_root_ca_metadata.cc
@@ -94,6 +94,18 @@
         0x55, 0x6c, 0x11, 0xa4, 0x37, 0xca, 0xeb, 0xff, 0xc3, 0xbb } },
     {"1.3.6.1.4.1.34697.2.4", ""},
   },
+  // Buypass Class 3 CA 1
+  // https://valid.evident.ca13.ssl.buypass.no/
+  { { { 0x61, 0x57, 0x3A, 0x11, 0xDF, 0x0E, 0xD8, 0x7E, 0xD5, 0x92,
+        0x65, 0x22, 0xEA, 0xD0, 0x56, 0xD7, 0x44, 0xB3, 0x23, 0x71 } },
+    {"2.16.578.1.26.1.3.3", ""},
+  },
+  // Buypass Class 3 Root CA
+  // https://valid.evident.ca23.ssl.buypass.no/
+  { { { 0xDA, 0xFA, 0xF7, 0xFA, 0x66, 0x84, 0xEC, 0x06, 0x8F, 0x14,
+        0x50, 0xBD, 0xC7, 0xC2, 0x81, 0xA5, 0xBC, 0xA9, 0x64, 0x57 } },
+    {"2.16.578.1.26.1.3.3", ""},
+  },
   // CertPlus Class 2 Primary CA (KEYNECTIS)
   // https://www.keynectis.com/
   { { { 0x74, 0x20, 0x74, 0x41, 0x72, 0x9c, 0xdd, 0x92, 0xec, 0x79,
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc
index 821cec1..4b2f37f 100644
--- a/net/cert/multi_threaded_cert_verifier.cc
+++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -556,7 +556,7 @@
   delete job;
 }
 
-void MultiThreadedCertVerifier::OnCertTrustChanged(
+void MultiThreadedCertVerifier::OnCACertChanged(
     const X509Certificate* cert) {
   DCHECK(CalledOnValidThread());
 
diff --git a/net/cert/multi_threaded_cert_verifier.h b/net/cert/multi_threaded_cert_verifier.h
index bc9cd4f..f4e2787 100644
--- a/net/cert/multi_threaded_cert_verifier.h
+++ b/net/cert/multi_threaded_cert_verifier.h
@@ -137,7 +137,7 @@
                     const CertVerifyResult& verify_result);
 
   // CertDatabase::Observer methods:
-  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE;
+  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE;
 
   // For unit testing.
   void ClearCache() { cache_.Clear(); }
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
index 8e9ef4e..0ba139b 100644
--- a/net/cert/nss_cert_database.cc
+++ b/net/cert/nss_cert_database.cc
@@ -16,6 +16,7 @@
 #include "base/observer_list_threadsafe.h"
 #include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
+#include "crypto/scoped_nss_types.h"
 #include "net/base/crypto_module.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_database.h"
@@ -93,25 +94,23 @@
                                   bool need_rw) const {
   modules->clear();
 
-  PK11SlotList* slot_list = NULL;
   // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
-  slot_list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
-                                need_rw ? PR_TRUE : PR_FALSE,  // needRW
-                                PR_TRUE,  // loadCerts (unused)
-                                NULL);  // wincx
+  crypto::ScopedPK11SlotList slot_list(
+      PK11_GetAllTokens(CKM_INVALID_MECHANISM,
+                        need_rw ? PR_TRUE : PR_FALSE,  // needRW
+                        PR_TRUE,                       // loadCerts (unused)
+                        NULL));                        // wincx
   if (!slot_list) {
     LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError();
     return;
   }
 
-  PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list);
+  PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get());
   while (slot_element) {
     modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot));
-    slot_element = PK11_GetNextSafe(slot_list, slot_element,
+    slot_element = PK11_GetNextSafe(slot_list.get(), slot_element,
                                     PR_FALSE);  // restart
   }
-
-  PK11_FreeSlotList(slot_list);
 }
 
 int NSSCertDatabase::ImportFromPKCS12(
@@ -168,7 +167,7 @@
   bool success = psm::ImportCACerts(certificates, root, trust_bits,
                                     not_imported);
   if (success)
-    NotifyObserversOfCertTrustChanged(NULL);
+    NotifyObserversOfCACertChanged(NULL);
 
   return success;
 }
@@ -284,7 +283,7 @@
                                 TrustBits trust_bits) {
   bool success = psm::SetCertTrust(cert, type, trust_bits);
   if (success)
-    NotifyObserversOfCertTrustChanged(cert);
+    NotifyObserversOfCACertChanged(cert);
 
   return success;
 }
@@ -336,10 +335,10 @@
   observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert));
 }
 
-void NSSCertDatabase::NotifyObserversOfCertTrustChanged(
+void NSSCertDatabase::NotifyObserversOfCACertChanged(
     const X509Certificate* cert) {
   observer_list_->Notify(
-      &Observer::OnCertTrustChanged, make_scoped_refptr(cert));
+      &Observer::OnCACertChanged, make_scoped_refptr(cert));
 }
 
 }  // namespace net
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h
index 9db1b75..a5d7eb8 100644
--- a/net/cert/nss_cert_database.h
+++ b/net/cert/nss_cert_database.h
@@ -39,10 +39,10 @@
     // Will be called when a certificate is removed.
     virtual void OnCertRemoved(const X509Certificate* cert) {}
 
-    // Will be called when a certificate's trust is changed.
+    // Will be called when a CA certificate is changed.
     // Called with |cert| == NULL after importing a list of certificates
     // in ImportCACerts().
-    virtual void OnCertTrustChanged(const X509Certificate* cert) {}
+    virtual void OnCACertChanged(const X509Certificate* cert) {}
 
    protected:
     Observer() {}
@@ -196,7 +196,7 @@
   // Broadcasts notifications to all registered observers.
   void NotifyObserversOfCertAdded(const X509Certificate* cert);
   void NotifyObserversOfCertRemoved(const X509Certificate* cert);
-  void NotifyObserversOfCertTrustChanged(const X509Certificate* cert);
+  void NotifyObserversOfCACertChanged(const X509Certificate* cert);
 
   const scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
 
diff --git a/net/cert/x509_certificate.cc b/net/cert/x509_certificate.cc
index 36e806e..862a202 100644
--- a/net/cert/x509_certificate.cc
+++ b/net/cert/x509_certificate.cc
@@ -504,7 +504,8 @@
     const std::string& hostname,
     const std::string& cert_common_name,
     const std::vector<std::string>& cert_san_dns_names,
-    const std::vector<std::string>& cert_san_ip_addrs) {
+    const std::vector<std::string>& cert_san_ip_addrs,
+    bool* common_name_fallback_used) {
   DCHECK(!hostname.empty());
   // Perform name verification following http://tools.ietf.org/html/rfc6125.
   // The terminology used in this method is as per that RFC:-
@@ -528,6 +529,7 @@
   // Allow fallback to Common name matching?
   const bool common_name_fallback = cert_san_dns_names.empty() &&
                                     cert_san_ip_addrs.empty();
+  *common_name_fallback_used = common_name_fallback;
 
   // Fully handle all cases where |hostname| contains an IP address.
   if (host_info.IsIPAddress()) {
@@ -649,10 +651,12 @@
   return false;
 }
 
-bool X509Certificate::VerifyNameMatch(const std::string& hostname) const {
+bool X509Certificate::VerifyNameMatch(const std::string& hostname,
+                                      bool* common_name_fallback_used) const {
   std::vector<std::string> dns_names, ip_addrs;
   GetSubjectAltName(&dns_names, &ip_addrs);
-  return VerifyHostname(hostname, subject_.common_name, dns_names, ip_addrs);
+  return VerifyHostname(hostname, subject_.common_name, dns_names, ip_addrs,
+                        common_name_fallback_used);
 }
 
 // static
diff --git a/net/cert/x509_certificate.h b/net/cert/x509_certificate.h
index ef55243..43ed014 100644
--- a/net/cert/x509_certificate.h
+++ b/net/cert/x509_certificate.h
@@ -313,8 +313,11 @@
   // Verifies that |hostname| matches this certificate.
   // Does not verify that the certificate is valid, only that the certificate
   // matches this host.
-  // Returns true if it matches.
-  bool VerifyNameMatch(const std::string& hostname) const;
+  // Returns true if it matches, and updates |*common_name_fallback_used|,
+  // setting it to true if a fallback to the CN was used, rather than
+  // subjectAltName.
+  bool VerifyNameMatch(const std::string& hostname,
+                       bool* common_name_fallback_used) const;
 
   // Obtains the DER encoded certificate data for |cert_handle|. On success,
   // returns true and writes the DER encoded certificate to |*der_encoded|.
@@ -425,10 +428,14 @@
   // extension, if present. Note these IP addresses are NOT ascii-encoded:
   // they must be 4 or 16 bytes of network-ordered data, for IPv4 and IPv6
   // addresses, respectively.
+  // |common_name_fallback_used| will be updated to true if cert_common_name
+  // was used to match the hostname, or false if either of the |cert_san_*|
+  // parameters was used to match the hostname.
   static bool VerifyHostname(const std::string& hostname,
                              const std::string& cert_common_name,
                              const std::vector<std::string>& cert_san_dns_names,
-                             const std::vector<std::string>& cert_san_ip_addrs);
+                             const std::vector<std::string>& cert_san_ip_addrs,
+                             bool* common_name_fallback_used);
 
   // Reads a single certificate from |pickle_iter| and returns a
   // platform-specific certificate handle. The format of the certificate
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index 04dbadd..83de91a 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -190,11 +190,12 @@
   EXPECT_EQ("webkit.org", dns_names[1]);
 
   // Test that the wildcard cert matches properly.
-  EXPECT_TRUE(webkit_cert->VerifyNameMatch("www.webkit.org"));
-  EXPECT_TRUE(webkit_cert->VerifyNameMatch("foo.webkit.org"));
-  EXPECT_TRUE(webkit_cert->VerifyNameMatch("webkit.org"));
-  EXPECT_FALSE(webkit_cert->VerifyNameMatch("www.webkit.com"));
-  EXPECT_FALSE(webkit_cert->VerifyNameMatch("www.foo.webkit.com"));
+  bool unused = false;
+  EXPECT_TRUE(webkit_cert->VerifyNameMatch("www.webkit.org", &unused));
+  EXPECT_TRUE(webkit_cert->VerifyNameMatch("foo.webkit.org", &unused));
+  EXPECT_TRUE(webkit_cert->VerifyNameMatch("webkit.org", &unused));
+  EXPECT_FALSE(webkit_cert->VerifyNameMatch("www.webkit.com", &unused));
+  EXPECT_FALSE(webkit_cert->VerifyNameMatch("www.foo.webkit.com", &unused));
 }
 
 TEST(X509CertificateTest, ThawteCertParsing) {
@@ -1139,8 +1140,9 @@
     }
   }
 
+  bool unused = false;
   EXPECT_EQ(test_data.expected, X509Certificate::VerifyHostname(
-      test_data.hostname, common_name, dns_names, ip_addressses));
+      test_data.hostname, common_name, dns_names, ip_addressses, &unused));
 }
 
 INSTANTIATE_TEST_CASE_P(, X509CertificateNameVerifyTest,
diff --git a/net/cert/x509_util_android.cc b/net/cert/x509_util_android.cc
new file mode 100644
index 0000000..1f6c3c6
--- /dev/null
+++ b/net/cert/x509_util_android.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 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 "net/cert/x509_util_android.h"
+
+#include "base/android/jni_android.h"
+#include "jni/X509Util_jni.h"
+#include "net/cert/cert_database.h"
+
+namespace net {
+
+void NotifyKeyChainChanged(JNIEnv* env, jclass clazz) {
+  CertDatabase::GetInstance()->OnAndroidKeyChainChanged();
+}
+
+jobject GetApplicationContext(JNIEnv* env, jclass clazz) {
+  return base::android::GetApplicationContext();
+}
+
+bool RegisterX509Util(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // net namespace
diff --git a/net/cert/x509_util_android.h b/net/cert/x509_util_android.h
new file mode 100644
index 0000000..205a60a
--- /dev/null
+++ b/net/cert/x509_util_android.h
@@ -0,0 +1,16 @@
+// Copyright 2013 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 NET_CERT_X509_UTIL_ANDROID_H_
+#define NET_CERT_X509_UTIL_ANDROID_H_
+
+#include <jni.h>
+
+namespace net {
+
+bool RegisterX509Util(JNIEnv* env);
+
+}  // net namespace
+
+#endif  // NET_CERT_X509_UTIL_ANDROID_H_
diff --git a/net/cert_verify_result_android_java.target.darwin-arm.mk b/net/cert_verify_result_android_java.target.darwin-arm.mk
index 1a4cd37..0019a6a 100644
--- a/net/cert_verify_result_android_java.target.darwin-arm.mk
+++ b/net/cert_verify_result_android_java.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cert_verify_result_android_java.target.darwin-mips.mk b/net/cert_verify_result_android_java.target.darwin-mips.mk
index e15399c..19c0b9e 100644
--- a/net/cert_verify_result_android_java.target.darwin-mips.mk
+++ b/net/cert_verify_result_android_java.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cert_verify_result_android_java.target.darwin-x86.mk b/net/cert_verify_result_android_java.target.darwin-x86.mk
index 126cda1..8212e7b 100644
--- a/net/cert_verify_result_android_java.target.darwin-x86.mk
+++ b/net/cert_verify_result_android_java.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cert_verify_result_android_java.target.linux-arm.mk b/net/cert_verify_result_android_java.target.linux-arm.mk
index 1a4cd37..0019a6a 100644
--- a/net/cert_verify_result_android_java.target.linux-arm.mk
+++ b/net/cert_verify_result_android_java.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cert_verify_result_android_java.target.linux-mips.mk b/net/cert_verify_result_android_java.target.linux-mips.mk
index e15399c..19c0b9e 100644
--- a/net/cert_verify_result_android_java.target.linux-mips.mk
+++ b/net/cert_verify_result_android_java.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cert_verify_result_android_java.target.linux-x86.mk b/net/cert_verify_result_android_java.target.linux-x86.mk
index 126cda1..8212e7b 100644
--- a/net/cert_verify_result_android_java.target.linux-x86.mk
+++ b/net/cert_verify_result_android_java.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.darwin-arm.mk b/net/certificate_mime_types_java.target.darwin-arm.mk
index d8efec3..e30f3d8 100644
--- a/net/certificate_mime_types_java.target.darwin-arm.mk
+++ b/net/certificate_mime_types_java.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.darwin-mips.mk b/net/certificate_mime_types_java.target.darwin-mips.mk
index 8223c24..563196e 100644
--- a/net/certificate_mime_types_java.target.darwin-mips.mk
+++ b/net/certificate_mime_types_java.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.darwin-x86.mk b/net/certificate_mime_types_java.target.darwin-x86.mk
index 1dd68f4..6f4f71c 100644
--- a/net/certificate_mime_types_java.target.darwin-x86.mk
+++ b/net/certificate_mime_types_java.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.linux-arm.mk b/net/certificate_mime_types_java.target.linux-arm.mk
index d8efec3..e30f3d8 100644
--- a/net/certificate_mime_types_java.target.linux-arm.mk
+++ b/net/certificate_mime_types_java.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.linux-mips.mk b/net/certificate_mime_types_java.target.linux-mips.mk
index 8223c24..563196e 100644
--- a/net/certificate_mime_types_java.target.linux-mips.mk
+++ b/net/certificate_mime_types_java.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/certificate_mime_types_java.target.linux-x86.mk b/net/certificate_mime_types_java.target.linux-x86.mk
index 1dd68f4..6f4f71c 100644
--- a/net/certificate_mime_types_java.target.linux-x86.mk
+++ b/net/certificate_mime_types_java.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 4900af9..f8dae50 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1474,21 +1474,31 @@
   StoreLoadedCookies(cookies);
 
   std::deque<scoped_refptr<CookieMonsterTask> > tasks_pending_for_key;
-  {
-    base::AutoLock autolock(lock_);
-    keys_loaded_.insert(key);
-    std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
-      ::iterator it = tasks_pending_for_key_.find(key);
-    if (it == tasks_pending_for_key_.end())
-      return;
-    it->second.swap(tasks_pending_for_key);
-    tasks_pending_for_key_.erase(it);
-  }
 
-  while (!tasks_pending_for_key.empty()) {
-    scoped_refptr<CookieMonsterTask> task = tasks_pending_for_key.front();
-    task->Run();
-    tasks_pending_for_key.pop_front();
+  // We need to do this repeatedly until no more tasks were added to the queue
+  // during the period where we release the lock.
+  while (true) {
+    {
+      base::AutoLock autolock(lock_);
+      std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
+        ::iterator it = tasks_pending_for_key_.find(key);
+      if (it == tasks_pending_for_key_.end()) {
+        keys_loaded_.insert(key);
+        return;
+      }
+      if (it->second.empty()) {
+        keys_loaded_.insert(key);
+        tasks_pending_for_key_.erase(it);
+        return;
+      }
+      it->second.swap(tasks_pending_for_key);
+    }
+
+    while (!tasks_pending_for_key.empty()) {
+      scoped_refptr<CookieMonsterTask> task = tasks_pending_for_key.front();
+      task->Run();
+      tasks_pending_for_key.pop_front();
+    }
   }
 }
 
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 746cd96..e84df75 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -1099,16 +1099,13 @@
 
   MockGetCookiesCallback get_cookies_callback;
   MockSetCookiesCallback set_cookies_callback;
-  MockClosure delete_cookie_callback;
   MockGetCookiesCallback get_cookies_callback_deferred;
 
   EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll(
       GetCookiesAction(
           &cookie_monster(), url_google_, &get_cookies_callback),
       SetCookieAction(
-          &cookie_monster(), url_google_, "A=B", &set_cookies_callback),
-      DeleteCookieAction(
-          &cookie_monster(), url_google_, "A", &delete_cookie_callback)));
+          &cookie_monster(), url_google_, "A=B", &set_cookies_callback)));
   ExpectLoadCall();
   ExpectLoadForKeyCall("google.izzle", false);
   Begin();
@@ -1117,10 +1114,9 @@
   EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
       GetCookiesAction(
           &cookie_monster(), url_google_, &get_cookies_callback_deferred));
-  EXPECT_CALL(get_cookies_callback_deferred, Invoke("X=1")).WillOnce(
-      QuitCurrentMessageLoop());
   EXPECT_CALL(set_cookies_callback, Invoke(true));
-  EXPECT_CALL(delete_cookie_callback, Invoke());
+  EXPECT_CALL(get_cookies_callback_deferred, Invoke("A=B; X=1")).WillOnce(
+      QuitCurrentMessageLoop());
 
   CompleteLoadingAndWait();
 }
diff --git a/net/data/url_request_unittest/filedir-sentinel b/net/data/url_request_unittest/filedir-sentinel
new file mode 100644
index 0000000..408adea
--- /dev/null
+++ b/net/data/url_request_unittest/filedir-sentinel
@@ -0,0 +1 @@
+This is the file that the URLRequestTest.FileDirOutputSanity test looks for.
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 6ccd1e0..ef9dd16 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -3470,8 +3470,4 @@
   EXPECT_TRUE(keys_to_match.empty());
 }
 
-// TODO(pasko): Add a Simple Cache test that would simulate upgrade from the
-// version with the index file in the cache directory to the version with the
-// index file in subdirectory.
-
 #endif  // defined(OS_POSIX)
diff --git a/net/disk_cache/cache_creator.cc b/net/disk_cache/cache_creator.cc
index 857d171..ccdab1f 100644
--- a/net/disk_cache/cache_creator.cc
+++ b/net/disk_cache/cache_creator.cc
@@ -113,6 +113,7 @@
 #endif
   } else {
     LOG(ERROR) << "Unable to create cache";
+    created_cache_.reset();
   }
   callback_.Run(result);
   delete this;
diff --git a/net/disk_cache/simple/simple_index_file_unittest.cc b/net/disk_cache/simple/simple_index_file_unittest.cc
index 0e9c2e8..6a79433 100644
--- a/net/disk_cache/simple/simple_index_file_unittest.cc
+++ b/net/disk_cache/simple/simple_index_file_unittest.cc
@@ -11,13 +11,18 @@
 #include "base/pickle.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "net/base/cache_type.h"
+#include "net/base/test_completion_callback.h"
+#include "net/disk_cache/disk_cache_test_util.h"
+#include "net/disk_cache/simple/simple_backend_impl.h"
 #include "net/disk_cache/simple/simple_backend_version.h"
 #include "net/disk_cache/simple/simple_entry_format.h"
 #include "net/disk_cache/simple/simple_index.h"
 #include "net/disk_cache/simple/simple_index_file.h"
 #include "net/disk_cache/simple/simple_util.h"
+#include "net/disk_cache/simple/simple_version_upgrade.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::Time;
@@ -257,6 +262,84 @@
   EXPECT_TRUE(load_index_result.flush_required);
 }
 
+// Tests that after an upgrade the backend has the index file put in place.
+TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
+  base::ScopedTempDir cache_dir;
+  ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
+  const base::FilePath cache_path = cache_dir.path();
+
+  // Write an old fake index file.
+  base::PlatformFileError error;
+  base::PlatformFile file = base::CreatePlatformFile(
+      cache_path.AppendASCII("index"),
+      base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
+      NULL,
+      &error);
+  disk_cache::FakeIndexData file_contents;
+  file_contents.initial_magic_number = disk_cache::kSimpleInitialMagicNumber;
+  file_contents.version = 5;
+  int bytes_written = base::WritePlatformFile(
+      file, 0, reinterpret_cast<char*>(&file_contents), sizeof(file_contents));
+  ASSERT_TRUE(base::ClosePlatformFile(file));
+  ASSERT_EQ((int)sizeof(file_contents), bytes_written);
+
+  // Write the index file. The format is incorrect, but for transitioning from
+  // v5 it does not matter.
+  const std::string index_file_contents("incorrectly serialized data");
+  const base::FilePath old_index_file =
+      cache_path.AppendASCII("the-real-index");
+  ASSERT_EQ(implicit_cast<int>(index_file_contents.size()),
+            file_util::WriteFile(old_index_file,
+                                 index_file_contents.data(),
+                                 index_file_contents.size()));
+
+  // Upgrade the cache.
+  ASSERT_TRUE(disk_cache::UpgradeSimpleCacheOnDisk(cache_path));
+
+  // Create the backend and initiate index flush by destroying the backend.
+  base::Thread cache_thread("CacheThread");
+  ASSERT_TRUE(cache_thread.StartWithOptions(
+      base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+  disk_cache::SimpleBackendImpl* simple_cache =
+      new disk_cache::SimpleBackendImpl(cache_path,
+                                        0,
+                                        net::DISK_CACHE,
+                                        cache_thread.message_loop_proxy().get(),
+                                        NULL);
+  net::TestCompletionCallback cb;
+  int rv = simple_cache->Init(cb.callback());
+  EXPECT_EQ(net::OK, cb.GetResult(rv));
+  rv = simple_cache->index()->ExecuteWhenReady(cb.callback());
+  EXPECT_EQ(net::OK, cb.GetResult(rv));
+  delete simple_cache;
+
+  // The backend flushes the index on destruction and does so on the cache
+  // thread, wait for the flushing to finish by posting a callback to the cache
+  // thread after that.
+  MessageLoopHelper helper;
+  CallbackTest cb_shutdown(&helper, false);
+  cache_thread.message_loop_proxy()->PostTask(
+      FROM_HERE,
+      base::Bind(&CallbackTest::Run, base::Unretained(&cb_shutdown), net::OK));
+  helper.WaitUntilCacheIoFinished(1);
+
+  // Verify that the index file exists.
+  const base::FilePath& index_file_path =
+      cache_path.AppendASCII("index-dir").AppendASCII("the-real-index");
+  EXPECT_TRUE(base::PathExists(index_file_path));
+
+  // Verify that the version of the index file is correct.
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(index_file_path, &contents));
+  base::Time when_index_last_saw_cache;
+  SimpleIndexLoadResult deserialize_result;
+  WrappedSimpleIndexFile::Deserialize(contents.data(),
+                                      contents.size(),
+                                      &when_index_last_saw_cache,
+                                      &deserialize_result);
+  EXPECT_TRUE(deserialize_result.did_load);
+}
+
 #endif  // defined(OS_POSIX)
 
 }  // namespace disk_cache
diff --git a/net/http/http_basic_state.cc b/net/http/http_basic_state.cc
new file mode 100644
index 0000000..c35a368
--- /dev/null
+++ b/net/http/http_basic_state.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 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 "net/http/http_basic_state.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_response_body_drainer.h"
+#include "net/http/http_stream_parser.h"
+#include "net/http/http_util.h"
+#include "net/socket/client_socket_handle.h"
+#include "url/gurl.h"
+
+namespace net {
+
+HttpBasicState::HttpBasicState(ClientSocketHandle* connection, bool using_proxy)
+    : read_buf_(new GrowableIOBuffer()),
+      connection_(connection),
+      using_proxy_(using_proxy),
+      request_info_(NULL) {}
+
+HttpBasicState::~HttpBasicState() {}
+
+int HttpBasicState::Initialize(const HttpRequestInfo* request_info,
+                               RequestPriority priority,
+                               const BoundNetLog& net_log,
+                               const CompletionCallback& callback) {
+  DCHECK(!parser_.get());
+  request_info_ = request_info;
+  parser_.reset(new HttpStreamParser(
+      connection_.get(), request_info, read_buf_.get(), net_log));
+  return OK;
+}
+
+scoped_ptr<ClientSocketHandle> HttpBasicState::ReleaseConnection() {
+  return connection_.Pass();
+}
+
+void HttpBasicState::DeleteParser() { parser_.reset(); }
+
+std::string HttpBasicState::GenerateRequestLine() const {
+  static const char kSuffix[] = " HTTP/1.1\r\n";
+  const size_t kSuffixLen = arraysize(kSuffix) - 1;
+  DCHECK(request_info_);
+  const GURL& url = request_info_->url;
+  const std::string path = using_proxy_ ? HttpUtil::SpecForRequest(url)
+                                        : HttpUtil::PathForRequest(url);
+  // Don't use StringPrintf for concatenation because it is very inefficient.
+  std::string request_line;
+  const size_t expected_size = request_info_->method.size() + 1 + path.size() +
+      kSuffixLen;
+  request_line.reserve(expected_size);
+  request_line.append(request_info_->method);
+  request_line.append(1, ' ');
+  request_line.append(path);
+  request_line.append(kSuffix, kSuffixLen);
+  DCHECK_EQ(expected_size, request_line.size());
+  return request_line;
+}
+
+}  // namespace net
diff --git a/net/http/http_basic_state.h b/net/http/http_basic_state.h
new file mode 100644
index 0000000..f9bf650
--- /dev/null
+++ b/net/http/http_basic_state.h
@@ -0,0 +1,70 @@
+// Copyright 2013 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.
+//
+// A class that stores the common state between HttpBasicStream and
+// WebSocketBasicHandshakeStream.
+
+#ifndef NET_HTTP_HTTP_BASIC_STATE_H_
+#define NET_HTTP_HTTP_BASIC_STATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
+
+namespace net {
+
+class BoundNetLog;
+class ClientSocketHandle;
+class GrowableIOBuffer;
+class HttpStreamParser;
+struct HttpRequestInfo;
+
+class NET_EXPORT_PRIVATE HttpBasicState {
+ public:
+  HttpBasicState(ClientSocketHandle* connection, bool using_proxy);
+  ~HttpBasicState();
+
+  // Initialize() must be called before using any of the other methods.
+  int Initialize(const HttpRequestInfo* request_info,
+                 RequestPriority priority,
+                 const BoundNetLog& net_log,
+                 const CompletionCallback& callback);
+
+  HttpStreamParser* parser() const { return parser_.get(); }
+
+  bool using_proxy() const { return using_proxy_; }
+
+  // Deletes |parser_| and sets it to NULL.
+  void DeleteParser();
+
+  ClientSocketHandle* connection() const { return connection_.get(); }
+
+  scoped_ptr<ClientSocketHandle> ReleaseConnection();
+
+  // Generates a string of the form "METHOD PATH HTTP/1.1\r\n", based on the
+  // values of request_info_ and using_proxy_.
+  std::string GenerateRequestLine() const;
+
+ private:
+  scoped_refptr<GrowableIOBuffer> read_buf_;
+
+  scoped_ptr<HttpStreamParser> parser_;
+
+  scoped_ptr<ClientSocketHandle> connection_;
+
+  const bool using_proxy_;
+
+  const HttpRequestInfo* request_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpBasicState);
+};
+
+}  // namespace net
+
+#endif  // NET_HTTP_HTTP_BASIC_STATE_H_
diff --git a/net/http/http_basic_state_unittest.cc b/net/http/http_basic_state_unittest.cc
new file mode 100644
index 0000000..e95cfd2
--- /dev/null
+++ b/net/http/http_basic_state_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2013 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 "net/http/http_basic_state.h"
+
+#include "net/base/completion_callback.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_request_info.h"
+#include "net/socket/client_socket_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+TEST(HttpBasicStateTest, ConstructsProperly) {
+  ClientSocketHandle* const handle = new ClientSocketHandle;
+  // Ownership of handle is passed to |state|.
+  const HttpBasicState state(handle, true);
+  EXPECT_EQ(handle, state.connection());
+  EXPECT_TRUE(state.using_proxy());
+}
+
+TEST(HttpBasicStateTest, UsingProxyCanBeFalse) {
+  const HttpBasicState state(new ClientSocketHandle(), false);
+  EXPECT_FALSE(state.using_proxy());
+}
+
+TEST(HttpBasicStateTest, ReleaseConnectionWorks) {
+  ClientSocketHandle* const handle = new ClientSocketHandle;
+  HttpBasicState state(handle, false);
+  const scoped_ptr<ClientSocketHandle> released_connection(
+      state.ReleaseConnection());
+  EXPECT_EQ(NULL, state.connection());
+  EXPECT_EQ(handle, released_connection.get());
+}
+
+TEST(HttpBasicStateTest, InitializeWorks) {
+  HttpBasicState state(new ClientSocketHandle(), false);
+  const HttpRequestInfo request_info;
+  EXPECT_EQ(OK,
+            state.Initialize(
+                &request_info, LOW, BoundNetLog(), CompletionCallback()));
+  EXPECT_TRUE(state.parser());
+}
+
+TEST(HttpBasicStateTest, DeleteParser) {
+  HttpBasicState state(new ClientSocketHandle(), false);
+  const HttpRequestInfo request_info;
+  state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+  EXPECT_TRUE(state.parser());
+  state.DeleteParser();
+  EXPECT_EQ(NULL, state.parser());
+}
+
+TEST(HttpBasicStateTest, GenerateRequestLineNoProxy) {
+  const bool use_proxy = false;
+  HttpBasicState state(new ClientSocketHandle(), use_proxy);
+  HttpRequestInfo request_info;
+  request_info.url = GURL("http://www.example.com/path?foo=bar#hoge");
+  request_info.method = "PUT";
+  state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+  EXPECT_EQ("PUT /path?foo=bar HTTP/1.1\r\n", state.GenerateRequestLine());
+}
+
+TEST(HttpBasicStateTest, GenerateRequestLineWithProxy) {
+  const bool use_proxy = true;
+  HttpBasicState state(new ClientSocketHandle(), use_proxy);
+  HttpRequestInfo request_info;
+  request_info.url = GURL("http://www.example.com/path?foo=bar#hoge");
+  request_info.method = "PUT";
+  state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+  EXPECT_EQ("PUT http://www.example.com/path?foo=bar HTTP/1.1\r\n",
+            state.GenerateRequestLine());
+}
+
+}  // namespace
+}  // namespace net
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index c30e17d..729e9c3 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -4,122 +4,101 @@
 
 #include "net/http/http_basic_stream.h"
 
-#include "base/strings/stringprintf.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_request_headers.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/http/http_request_info.h"
 #include "net/http/http_response_body_drainer.h"
 #include "net/http/http_stream_parser.h"
-#include "net/http/http_util.h"
 #include "net/socket/client_socket_handle.h"
 
 namespace net {
 
 HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection,
-                                 HttpStreamParser* parser,
                                  bool using_proxy)
-    : read_buf_(new GrowableIOBuffer()),
-      parser_(parser),
-      connection_(connection),
-      using_proxy_(using_proxy),
-      request_info_(NULL) {
-}
+    : state_(connection, using_proxy) {}
 
 HttpBasicStream::~HttpBasicStream() {}
 
-int HttpBasicStream::InitializeStream(
-    const HttpRequestInfo* request_info,
-    RequestPriority priority,
-    const BoundNetLog& net_log,
-    const CompletionCallback& callback) {
-  DCHECK(!parser_.get());
-  request_info_ = request_info;
-  parser_.reset(new HttpStreamParser(
-      connection_.get(), request_info, read_buf_.get(), net_log));
+int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
+                                      RequestPriority priority,
+                                      const BoundNetLog& net_log,
+                                      const CompletionCallback& callback) {
+  state_.Initialize(request_info, priority, net_log, callback);
   return OK;
 }
 
-
 int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers,
                                  HttpResponseInfo* response,
                                  const CompletionCallback& callback) {
-  DCHECK(parser_.get());
-  DCHECK(request_info_);
-  const std::string path = using_proxy_ ?
-                           HttpUtil::SpecForRequest(request_info_->url) :
-                           HttpUtil::PathForRequest(request_info_->url);
-  request_line_ = base::StringPrintf("%s %s HTTP/1.1\r\n",
-                                     request_info_->method.c_str(),
-                                     path.c_str());
-  return parser_->SendRequest(request_line_, headers, response, callback);
+  DCHECK(parser());
+  return parser()->SendRequest(
+      state_.GenerateRequestLine(), headers, response, callback);
 }
 
 UploadProgress HttpBasicStream::GetUploadProgress() const {
-  return parser_->GetUploadProgress();
+  return parser()->GetUploadProgress();
 }
 
 int HttpBasicStream::ReadResponseHeaders(const CompletionCallback& callback) {
-  return parser_->ReadResponseHeaders(callback);
+  return parser()->ReadResponseHeaders(callback);
 }
 
 const HttpResponseInfo* HttpBasicStream::GetResponseInfo() const {
-  return parser_->GetResponseInfo();
+  return parser()->GetResponseInfo();
 }
 
-int HttpBasicStream::ReadResponseBody(IOBuffer* buf, int buf_len,
+int HttpBasicStream::ReadResponseBody(IOBuffer* buf,
+                                      int buf_len,
                                       const CompletionCallback& callback) {
-  return parser_->ReadResponseBody(buf, buf_len, callback);
+  return parser()->ReadResponseBody(buf, buf_len, callback);
 }
 
 void HttpBasicStream::Close(bool not_reusable) {
-  parser_->Close(not_reusable);
+  parser()->Close(not_reusable);
 }
 
 HttpStream* HttpBasicStream::RenewStreamForAuth() {
   DCHECK(IsResponseBodyComplete());
-  DCHECK(!parser_->IsMoreDataBuffered());
-  parser_.reset();
-  return new HttpBasicStream(connection_.release(), NULL, using_proxy_);
+  DCHECK(!parser()->IsMoreDataBuffered());
+  // TODO(ricea): Why delete the parser here? crbug.com/311917
+  state_.DeleteParser();
+  return new HttpBasicStream(state_.ReleaseConnection().release(),
+                             state_.using_proxy());
 }
 
 bool HttpBasicStream::IsResponseBodyComplete() const {
-  return parser_->IsResponseBodyComplete();
+  return parser()->IsResponseBodyComplete();
 }
 
 bool HttpBasicStream::CanFindEndOfResponse() const {
-  return parser_->CanFindEndOfResponse();
+  return parser()->CanFindEndOfResponse();
 }
 
 bool HttpBasicStream::IsConnectionReused() const {
-  return parser_->IsConnectionReused();
+  return parser()->IsConnectionReused();
 }
 
-void HttpBasicStream::SetConnectionReused() {
-  parser_->SetConnectionReused();
-}
+void HttpBasicStream::SetConnectionReused() { parser()->SetConnectionReused(); }
 
 bool HttpBasicStream::IsConnectionReusable() const {
-  return parser_->IsConnectionReusable();
+  return parser()->IsConnectionReusable();
 }
 
 bool HttpBasicStream::GetLoadTimingInfo(
     LoadTimingInfo* load_timing_info) const {
-  return connection_->GetLoadTimingInfo(IsConnectionReused(), load_timing_info);
+  return state_.connection()->GetLoadTimingInfo(IsConnectionReused(),
+                                                load_timing_info);
 }
 
 void HttpBasicStream::GetSSLInfo(SSLInfo* ssl_info) {
-  parser_->GetSSLInfo(ssl_info);
+  parser()->GetSSLInfo(ssl_info);
 }
 
 void HttpBasicStream::GetSSLCertRequestInfo(
     SSLCertRequestInfo* cert_request_info) {
-  parser_->GetSSLCertRequestInfo(cert_request_info);
+  parser()->GetSSLCertRequestInfo(cert_request_info);
 }
 
-bool HttpBasicStream::IsSpdyHttpStream() const {
-  return false;
-}
+bool HttpBasicStream::IsSpdyHttpStream() const { return false; }
 
 void HttpBasicStream::Drain(HttpNetworkSession* session) {
   HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(this);
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 2057837..f9e4d49 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -12,13 +12,13 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "net/http/http_basic_state.h"
 #include "net/http/http_stream.h"
 
 namespace net {
 
 class BoundNetLog;
 class ClientSocketHandle;
-class GrowableIOBuffer;
 class HttpResponseInfo;
 struct HttpRequestInfo;
 class HttpRequestHeaders;
@@ -27,13 +27,9 @@
 
 class HttpBasicStream : public HttpStream {
  public:
-  // Constructs a new HttpBasicStream.  If |parser| is NULL, then
-  // InitializeStream should be called to initialize it correctly.  If
-  // |parser| is non-null, then InitializeStream should not be called,
-  // as the stream is already initialized.
-  HttpBasicStream(ClientSocketHandle* connection,
-                  HttpStreamParser* parser,
-                  bool using_proxy);
+  // Constructs a new HttpBasicStream. InitializeStream must be called to
+  // initialize it correctly.
+  HttpBasicStream(ClientSocketHandle* connection, bool using_proxy);
   virtual ~HttpBasicStream();
 
   // HttpStream methods:
@@ -52,7 +48,8 @@
 
   virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE;
 
-  virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
+  virtual int ReadResponseBody(IOBuffer* buf,
+                               int buf_len,
                                const CompletionCallback& callback) OVERRIDE;
 
   virtual void Close(bool not_reusable) OVERRIDE;
@@ -84,17 +81,9 @@
   virtual void SetPriority(RequestPriority priority) OVERRIDE;
 
  private:
-  scoped_refptr<GrowableIOBuffer> read_buf_;
+  HttpStreamParser* parser() const { return state_.parser(); }
 
-  scoped_ptr<HttpStreamParser> parser_;
-
-  scoped_ptr<ClientSocketHandle> connection_;
-
-  bool using_proxy_;
-
-  std::string request_line_;
-
-  const HttpRequestInfo* request_info_;
+  HttpBasicState state_;
 
   DISALLOW_COPY_AND_ASSIGN(HttpBasicStream);
 };
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index be123af..7af72c8 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -1518,20 +1518,12 @@
 }
 
 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
-#if defined(OS_ANDROID)
   if (result == ERR_NOT_IMPLEMENTED) {
     // Restart the request overwriting the cache entry.
-    //
-    // Note: this would have fixed range requests for debug builds on all OSes,
-    // not just Android, but karen@ prefers to limit the effect based on OS for
-    // cherry-picked fixes.
-    // TODO(pasko): remove the OS_ANDROID limitation as soon as the fix proves
-    // useful after the cherry-pick.
     // TODO(pasko): remove this workaround as soon as the SimpleBackendImpl
     // supports Sparse IO.
     return DoRestartPartialRequest();
   }
-#endif
   DCHECK_EQ(OK, result);
   if (!cache_.get())
     return ERR_UNEXPECTED;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 6e1adf7..03c9934 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -3455,8 +3455,6 @@
   RemoveMockTransaction(&kRangeGET_TransactionOK);
 }
 
-#if defined(OS_ANDROID)
-
 // Checks that with a cache backend having Sparse IO unimplementes the cache
 // entry would be doomed after a range request.
 // TODO(pasko): remove when the SimpleBackendImpl implements Sparse IO.
@@ -3529,8 +3527,6 @@
   RemoveMockTransaction(&transaction);
 }
 
-#endif  // OS_ANDROID
-
 // Tests that we can cache range requests and fetch random blocks from the
 // cache and the network, with synchronous responses.
 TEST(HttpCache, RangeGET_SyncOK) {
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 6d2ea35..b040595 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -48,6 +48,12 @@
     factory_.reset(new HttpNetworkLayer(network_session_.get()));
   }
 
+#if defined (SPDY_PROXY_AUTH_ORIGIN)
+  std::string GetChromeProxy() {
+    return HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString();
+  }
+#endif
+
   void ExecuteRequestExpectingContentAndHeader(const std::string& content,
                                                const std::string& header,
                                                const std::string& value) {
@@ -80,33 +86,41 @@
   }
 
   // Check that |proxy_count| proxies are in the retry list.
-  // These will be, in order, "bad:8080" and "alsobad:8080".
-  void TestBadProxies(unsigned int proxy_count) {
+  // These will be, in order, |bad_proxy| and |bad_proxy2|".
+  void TestBadProxies(unsigned int proxy_count, const std::string& bad_proxy,
+                      const std::string& bad_proxy2) {
     const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info();
     ASSERT_EQ(proxy_count, retry_info.size());
-    ASSERT_TRUE(retry_info.find("bad:8080") != retry_info.end());
+    ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end());
     if (proxy_count > 1)
-      ASSERT_TRUE(retry_info.find("alsobad:8080") != retry_info.end());
+      ASSERT_TRUE(retry_info.find(bad_proxy2) != retry_info.end());
   }
 
   // Simulates a request through a proxy which returns a bypass, which is then
   // retried through a second proxy that doesn't bypass.
   // Checks that the expected requests were issued, the expected content was
-  // recieved, and the first proxy ("bad:8080") was marked as bad.
-  void TestProxyFallback() {
+  // recieved, and the first proxy |bad_proxy| was marked as bad.
+  void TestProxyFallback(const std::string& bad_proxy) {
     MockRead data_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"
                "Connection: proxy-bypass\r\n\r\n"),
       MockRead("Bypass message"),
       MockRead(SYNCHRONOUS, OK),
     };
+    TestProxyFallbackWithMockReads(bad_proxy, data_reads,
+                                   arraysize(data_reads));
+  }
+
+  void TestProxyFallbackWithMockReads(const std::string& bad_proxy,
+                                      MockRead data_reads[],
+                                      int data_reads_size) {
     MockWrite data_writes[] = {
       MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
                 "Host: www.google.com\r\n"
                 "Proxy-Connection: keep-alive\r\n\r\n"),
     };
 
-    StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
+    StaticSocketDataProvider data1(data_reads, data_reads_size,
                                   data_writes, arraysize(data_writes));
     mock_socket_factory_.AddSocketDataProvider(&data1);
 
@@ -131,14 +145,14 @@
     ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
 
     // We should also observe the bad proxy in the retry list.
-    TestBadProxies(1u);
+    TestBadProxies(1u, bad_proxy, "");
   }
 
   // Simulates a request through a proxy which returns a bypass, which is then
   // retried through a direct connection to the origin site.
   // Checks that the expected requests were issued, the expected content was
-  // received, and the proxy ("bad:8080") was marked as bad.
-  void TestProxyFallbackToDirect() {
+  // received, and the proxy |bad_proxy| was marked as bad.
+  void TestProxyFallbackToDirect(const std::string& bad_proxy) {
     MockRead data_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"
                "Connection: proxy-bypass\r\n\r\n"),
@@ -175,7 +189,7 @@
     ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
 
     // We should also observe the bad proxy in the retry list.
-    TestBadProxies(1u);
+    TestBadProxies(1u, bad_proxy, "");
   }
 
   // Simulates a request through a proxy which returns a bypass, under a
@@ -183,7 +197,9 @@
   // are expected to be configured.
   // Checks that the expected requests were issued, the bypass message was the
   // final received content,  and all proxies were marked as bad.
-  void TestProxyFallbackFail(unsigned int proxy_count) {
+  void TestProxyFallbackFail(unsigned int proxy_count,
+                             const std::string& bad_proxy,
+                             const std::string& bad_proxy2) {
     MockRead data_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"
                "Connection: proxy-bypass\r\n\r\n"),
@@ -208,7 +224,7 @@
     ExecuteRequestExpectingContentAndHeader("Bypass message", "", "");
 
     // We should also observe the bad proxy or proxies in the retry list.
-    TestBadProxies(proxy_count);
+    TestBadProxies(proxy_count, bad_proxy, bad_proxy2);
   }
 
   MockClientSocketFactory mock_socket_factory_;
@@ -299,52 +315,68 @@
 //  - bypass with one proxy configured which is bypassed with no defined
 //    fallback
 
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassPac) {
+  std::string bad_proxy = GetChromeProxy();
   ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
-      "PROXY bad:8080; PROXY good:8080"));
-  TestProxyFallback();
+      "PROXY " + bad_proxy + "; PROXY good:8080"));
+  TestProxyFallback(bad_proxy);
 }
 
 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) {
-  ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080, good:8080"));
-  TestProxyFallback();
+  std::string bad_proxy = GetChromeProxy();
+  ConfigureTestDependencies(
+      ProxyService::CreateFixed(bad_proxy +", good:8080"));
+  TestProxyFallback(bad_proxy);
 }
 
 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) {
+  std::string bad_proxy = GetChromeProxy();
   ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
-      "PROXY bad:8080; DIRECT"));
-  TestProxyFallbackToDirect();
+      "PROXY " + bad_proxy + "; DIRECT"));
+  TestProxyFallbackToDirect(bad_proxy);
 }
 
 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassFixed) {
-  ConfigureTestDependencies(ProxyService::CreateFixed( "bad:8080, direct://"));
-  TestProxyFallbackToDirect();
+  std::string bad_proxy = GetChromeProxy();
+  ConfigureTestDependencies(
+      ProxyService::CreateFixed(bad_proxy + ", direct://"));
+  TestProxyFallbackToDirect(bad_proxy);
 }
 
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassPac) {
+  std::string bad_proxy = GetChromeProxy();
+  std::string bad_proxy2 =
+      HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
   ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
-      "PROXY bad:8080; PROXY alsobad:8080"));
-  TestProxyFallbackFail(2u);
+      "PROXY " + bad_proxy + "; PROXY " + bad_proxy2));
+  TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
 }
 
 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassFixed) {
+  std::string bad_proxy = GetChromeProxy();
+  std::string bad_proxy2 =
+      HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
   ConfigureTestDependencies(ProxyService::CreateFixed(
-    "bad:8080, alsobad:8080"));
-  TestProxyFallbackFail(2u);
+    bad_proxy + ", " + bad_proxy2));
+  TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
 }
+#endif
 
 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) {
+  std::string bad_proxy = GetChromeProxy();
   ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
-      "PROXY bad:8080"));
-  TestProxyFallbackFail(1u);
+      "PROXY " + bad_proxy));
+  TestProxyFallbackFail(1u, bad_proxy, "");
 }
 
 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) {
-  ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080"));
-  TestProxyFallbackFail(1u);
+  std::string bad_proxy = GetChromeProxy();
+  ConfigureTestDependencies(ProxyService::CreateFixed(bad_proxy));
+  TestProxyFallbackFail(1u, bad_proxy, "");
 }
 
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
 TEST_F(HttpNetworkLayerTest, ServerFallbackOnInternalServerError) {
   // Verify that "500 Internal Server Error" via the data reduction proxy
   // induces proxy fallback to a second proxy, if configured.
@@ -466,6 +498,28 @@
   ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size());
 }
 
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
+  // Verify that a Chrome-Proxy: bypass=<seconds> header induces proxy
+  // fallback to a second proxy, if configured.
+  std::string bad_proxy = GetChromeProxy();
+  ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
+      "PROXY " + bad_proxy + "; PROXY good:8080"));
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.1 200 OK\r\n"
+             "Connection: keep-alive\r\n"
+             "Chrome-Proxy: bypass=86400\r\n\r\n"),
+    MockRead("Bypass message"),
+    MockRead(SYNCHRONOUS, OK),
+  };
+
+  TestProxyFallbackWithMockReads(bad_proxy, data_reads, arraysize(data_reads));
+  EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
+            (*proxy_service_->proxy_retry_info().begin()).second.current_delay);
+}
+#endif  // defined(SPDY_PROXY_AUTH_ORIGIN)
+
 TEST_F(HttpNetworkLayerTest, NetworkVerified) {
   MockRead data_reads[] = {
     MockRead("HTTP/1.0 200 OK\r\n\r\n"),
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 346cbbc..3924082 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -71,7 +71,6 @@
       testing_fixed_https_port(0),
       force_spdy_single_domain(false),
       enable_spdy_ip_pooling(true),
-      enable_spdy_credential_frames(false),
       enable_spdy_compression(true),
       enable_spdy_ping_based_connection_checking(true),
       spdy_default_protocol(kProtoUnknown),
@@ -118,7 +117,6 @@
                          params.http_server_properties,
                          params.force_spdy_single_domain,
                          params.enable_spdy_ip_pooling,
-                         params.enable_spdy_credential_frames,
                          params.enable_spdy_compression,
                          params.enable_spdy_ping_based_connection_checking,
                          params.spdy_default_protocol,
@@ -128,7 +126,8 @@
                          params.time_func,
                          params.trusted_spdy_proxy),
       http_stream_factory_(new HttpStreamFactoryImpl(this, false)),
-      websocket_stream_factory_(new HttpStreamFactoryImpl(this, true)),
+      websocket_handshake_stream_factory_(
+          new HttpStreamFactoryImpl(this, true)),
       params_(params) {
   DCHECK(proxy_service_);
   DCHECK(ssl_config_service_.get());
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index c10bb14..5d0a7b9 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -77,7 +77,6 @@
     uint16 testing_fixed_https_port;
     bool force_spdy_single_domain;
     bool enable_spdy_ip_pooling;
-    bool enable_spdy_credential_frames;
     bool enable_spdy_compression;
     bool enable_spdy_ping_based_connection_checking;
     NextProto spdy_default_protocol;
@@ -141,8 +140,8 @@
   HttpStreamFactory* http_stream_factory() {
     return http_stream_factory_.get();
   }
-  HttpStreamFactory* websocket_stream_factory() {
-    return websocket_stream_factory_.get();
+  HttpStreamFactory* websocket_handshake_stream_factory() {
+    return websocket_handshake_stream_factory_.get();
   }
   NetLog* net_log() {
     return net_log_;
@@ -198,7 +197,7 @@
   QuicStreamFactory quic_stream_factory_;
   SpdySessionPool spdy_session_pool_;
   scoped_ptr<HttpStreamFactory> http_stream_factory_;
-  scoped_ptr<HttpStreamFactory> websocket_stream_factory_;
+  scoped_ptr<HttpStreamFactory> websocket_handshake_stream_factory_;
   std::set<HttpResponseBodyDrainer*> response_drainers_;
 
   Params params_;
diff --git a/net/http/http_network_session_peer.cc b/net/http/http_network_session_peer.cc
index 74b0d41..2a4ad33 100644
--- a/net/http/http_network_session_peer.cc
+++ b/net/http/http_network_session_peer.cc
@@ -36,7 +36,7 @@
 
 void HttpNetworkSessionPeer::SetWebSocketStreamFactory(
     HttpStreamFactory* http_stream_factory) {
-  session_->websocket_stream_factory_.reset(http_stream_factory);
+  session_->websocket_handshake_stream_factory_.reset(http_stream_factory);
 }
 
 }  // namespace net
diff --git a/net/http/http_network_session_peer.h b/net/http/http_network_session_peer.h
index eeccfef..ebe1af1 100644
--- a/net/http/http_network_session_peer.h
+++ b/net/http/http_network_session_peer.h
@@ -27,7 +27,8 @@
   void SetProxyService(ProxyService* proxy_service);
 
   void SetHttpStreamFactory(HttpStreamFactory* http_stream_factory);
-  void SetWebSocketStreamFactory(HttpStreamFactory* websocket_stream_factory);
+  void SetWebSocketStreamFactory(
+      HttpStreamFactory* websocket_handshake_stream_factory);
 
  private:
   const scoped_refptr<HttpNetworkSession> session_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 9101872..fcad53a 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -19,6 +19,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "net/base/auth.h"
@@ -446,10 +447,10 @@
   OnIOComplete(OK);
 }
 
-void HttpNetworkTransaction::OnWebSocketStreamReady(
+void HttpNetworkTransaction::OnWebSocketHandshakeStreamReady(
     const SSLConfig& used_ssl_config,
     const ProxyInfo& used_proxy_info,
-    WebSocketStreamBase* stream) {
+    WebSocketHandshakeStreamBase* stream) {
   NOTREACHED() << "This function should never be called.";
 }
 
@@ -925,24 +926,34 @@
   }
   DCHECK(response_.headers.get());
 
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
   // Server-induced fallback; see: http://crbug.com/143712
   if (response_.was_fetched_via_proxy && response_.headers.get() != NULL) {
-    bool should_fallback =
-        response_.headers->HasHeaderValue("connection", "proxy-bypass");
+    base::TimeDelta bypass_duration;
+    bool chrome_proxy_used =
+        proxy_info_.proxy_server().host_port_pair().Equals(
+            HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+    if (!chrome_proxy_used) {
+      chrome_proxy_used =
+          proxy_info_.proxy_server().host_port_pair().Equals(
+              HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)));
+    }
+#endif
+    bool should_fallback = chrome_proxy_used &&
+        response_.headers->GetChromeProxyInfo(&bypass_duration);
     // Additionally, fallback if a 500 is returned via the data reduction proxy.
     // This is conservative, as the 500 might have been generated by the origin,
     // and not the proxy.
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
     if (!should_fallback) {
-      should_fallback =
-          response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR &&
-          proxy_info_.proxy_server().host_port_pair().Equals(
-              HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
+      should_fallback = chrome_proxy_used &&
+          response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR;
     }
-#endif
+
     if (should_fallback) {
       ProxyService* proxy_service = session_->proxy_service();
-      if (proxy_service->MarkProxyAsBad(proxy_info_, net_log_)) {
+      if (proxy_service->MarkProxyAsBad(proxy_info_, bypass_duration,
+                                        net_log_)) {
         // Only retry in the case of GETs. We don't want to resubmit a POST
         // if the proxy took some action.
         if (request_->method == "GET") {
@@ -952,6 +963,7 @@
       }
     }
   }
+#endif
 
   // Like Net.HttpResponseCode, but only for MAIN_FRAME loads.
   if (request_->load_flags & LOAD_MAIN_FRAME) {
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 1c584ed..b0950a2 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -73,10 +73,10 @@
   virtual void OnStreamReady(const SSLConfig& used_ssl_config,
                              const ProxyInfo& used_proxy_info,
                              HttpStreamBase* stream) OVERRIDE;
-  virtual void OnWebSocketStreamReady(
+  virtual void OnWebSocketHandshakeStreamReady(
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
-      WebSocketStreamBase* stream) OVERRIDE;
+      WebSocketHandshakeStreamBase* stream) OVERRIDE;
   virtual void OnStreamFailed(int status,
                               const SSLConfig& used_ssl_config) OVERRIDE;
   virtual void OnCertificateError(int status,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index aee02b2..7846028 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -12032,13 +12032,13 @@
     return fake_request;
   }
 
-  virtual HttpStreamRequest* RequestWebSocketStream(
+  virtual HttpStreamRequest* RequestWebSocketHandshakeStream(
       const HttpRequestInfo& info,
       RequestPriority priority,
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       HttpStreamRequest::Delegate* delegate,
-      WebSocketStreamBase::Factory* factory,
+      WebSocketHandshakeStreamBase::Factory* factory,
       const BoundNetLog& net_log) OVERRIDE {
     ADD_FAILURE();
     return NULL;
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index 6047aa1..87e3cdb 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -1354,4 +1354,44 @@
       HasHeaderValue("Transfer-Encoding", "chunked");
 }
 
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+bool HttpResponseHeaders::GetChromeProxyInfo(
+    base::TimeDelta* bypass_duration) const {
+  const char kProxyBypass[] = "proxy-bypass";
+  *bypass_duration = base::TimeDelta();
+
+  // Support header of the form Chrome-Proxy: bypass=<duration>, where
+  // <duration> is the number of seconds to wait before retrying
+  // the proxy. If the duration is 0, then the default proxy retry delay
+  // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used.
+  std::string name = "chrome-proxy";
+  const char kBypassPrefix[] = "bypass=";
+  const size_t kBypassPrefixLen = arraysize(kBypassPrefix) - 1;
+
+  void* iter = NULL;
+  std::string value;
+  while (EnumerateHeader(&iter, name, &value)) {
+    if (value.size() > kBypassPrefixLen) {
+      if (LowerCaseEqualsASCII(value.begin(),
+                               value.begin() + kBypassPrefixLen,
+                               kBypassPrefix)) {
+        int64 seconds;
+        if (!base::StringToInt64(StringPiece(value.begin() + kBypassPrefixLen,
+                                             value.end()),
+                                 &seconds) || seconds < 0) {
+          continue;  // In case there is a well formed bypass instruction.
+        }
+        *bypass_duration = TimeDelta::FromSeconds(seconds);
+        return true;
+      }
+    }
+  }
+  // TODO(bengr): Deprecate the use of Connection: Proxy-Bypass.
+  if (HasHeaderValue("Connection", kProxyBypass))
+    return true;
+
+  return false;
+}
+#endif
+
 }  // namespace net
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index 6107597..a212980 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -250,6 +250,15 @@
   // Returns true if the response is chunk-encoded.
   bool IsChunkEncoded() const;
 
+#if defined (SPDY_PROXY_AUTH_ORIGIN)
+  // Returns true if the Chrome-Proxy header is present and contains a bypass
+  // delay. Sets |bypass_duration| to the specified delay if greater than 0, and
+  // to 0 otherwise to indicate that the default proxy delay (as specified in
+  // |ProxyList::UpdateRetryInfoOnFallback|) should be used. |bypass_duration|
+  // must be non-NULL.
+  bool GetChromeProxyInfo(base::TimeDelta* bypass_duration) const;
+#endif
+
   // Creates a Value for use with the NetLog containing the response headers.
   base::Value* NetLogCallback(NetLog::LogLevel log_level) const;
 
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 8bde289..5904bea 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1877,3 +1877,128 @@
   parsed->GetNormalizedHeaders(&normalized_recreated);
   EXPECT_EQ(normalized_parsed, normalized_recreated);
 }
+
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
+  const struct {
+     const char* headers;
+     bool expected_result;
+     int64 expected_retry_delay;
+  } tests[] = {
+    { "HTTP/1.1 200 OK\n"
+      "Content-Length: 999\n",
+      false,
+      0,
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Content-Length: 999\n",
+      false,
+      0,
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: proxy-bypass\n"
+      "Content-Length: 999\n",
+      true,
+      0,
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: proxy-bypass\n"
+      "Chrome-Proxy: bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=0\n"
+      "Content-Length: 999\n",
+      true,
+      0
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=-1\n"
+      "Content-Length: 999\n",
+      false,
+      0
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=xyz\n"
+      "Content-Length: 999\n",
+      false,
+      0
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass\n"
+      "Content-Length: 999\n",
+      false,
+      0
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: foo=abc, bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=86400, bar=abc\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=3600\n"
+      "Chrome-Proxy: bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      3600
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=3600, bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      3600
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass=, bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+    { "HTTP/1.1 200 OK\n"
+      "connection: keep-alive\n"
+      "Chrome-Proxy: bypass\n"
+      "Chrome-Proxy: bypass=86400\n"
+      "Content-Length: 999\n",
+      true,
+      86400
+    },
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+    std::string headers(tests[i].headers);
+    HeadersToRaw(&headers);
+    scoped_refptr<net::HttpResponseHeaders> parsed(
+        new net::HttpResponseHeaders(headers));
+
+    base::TimeDelta duration;
+    EXPECT_EQ(tests[i].expected_result,
+              parsed->GetChromeProxyInfo(&duration));
+    EXPECT_EQ(tests[i].expected_retry_delay, duration.InSeconds());
+  }
+}
+#endif  // defined(SPDY_PROXY_AUTH_ORIGIN)
diff --git a/net/http/http_stream_base.h b/net/http/http_stream_base.h
index 596ed75..f973f01 100644
--- a/net/http/http_stream_base.h
+++ b/net/http/http_stream_base.h
@@ -5,7 +5,7 @@
 // HttpStreamBase is an interface for reading and writing data to an
 // HTTP-like stream that keeps the client agnostic of the actual underlying
 // transport layer.  This provides an abstraction for HttpStream and
-// WebSocketStream.
+// WebSocketHandshakeStreamBase.
 
 #ifndef NET_HTTP_HTTP_STREAM_BASE_H_
 #define NET_HTTP_HTTP_STREAM_BASE_H_
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 2e83b10..d3f9686 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -21,7 +21,7 @@
 // This file can be included from net/http even though
 // it is in net/websockets because it doesn't
 // introduce any link dependency to net/websockets.
-#include "net/websockets/websocket_stream_base.h"
+#include "net/websockets/websocket_handshake_stream_base.h"
 
 class GURL;
 
@@ -71,17 +71,17 @@
         const ProxyInfo& used_proxy_info,
         HttpStreamBase* stream) = 0;
 
-    // This is the success case for RequestWebSocketStream.
+    // This is the success case for RequestWebSocketHandshakeStream.
     // |stream| is now owned by the delegate.
     // |used_ssl_config| indicates the actual SSL configuration used for this
     // stream, since the HttpStreamRequest may have modified the configuration
     // during stream processing.
     // |used_proxy_info| indicates the actual ProxyInfo used for this stream,
     // since the HttpStreamRequest performs the proxy resolution.
-    virtual void OnWebSocketStreamReady(
+    virtual void OnWebSocketHandshakeStreamReady(
         const SSLConfig& used_ssl_config,
         const ProxyInfo& used_proxy_info,
-        WebSocketStreamBase* stream) = 0;
+        WebSocketHandshakeStreamBase* stream) = 0;
 
     // This is the failure to create a stream case.
     // |used_ssl_config| indicates the actual SSL configuration used for this
@@ -197,15 +197,16 @@
       HttpStreamRequest::Delegate* delegate,
       const BoundNetLog& net_log) = 0;
 
-  // Request a WebSocket stream.
-  // Will call delegate->OnWebSocketStreamReady on successful completion.
-  virtual HttpStreamRequest* RequestWebSocketStream(
+  // Request a WebSocket handshake stream.
+  // Will call delegate->OnWebSocketHandshakeStreamReady on successful
+  // completion.
+  virtual HttpStreamRequest* RequestWebSocketHandshakeStream(
       const HttpRequestInfo& info,
       RequestPriority priority,
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       HttpStreamRequest::Delegate* delegate,
-      WebSocketStreamBase::Factory* factory,
+      WebSocketHandshakeStreamBase::Factory* factory,
       const BoundNetLog& net_log) = 0;
 
   // Requests that enough connections for |num_streams| be opened.
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index 1d413f5..1d5a826 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -82,13 +82,13 @@
                                net_log);
 }
 
-HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketStream(
+HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream(
     const HttpRequestInfo& request_info,
     RequestPriority priority,
     const SSLConfig& server_ssl_config,
     const SSLConfig& proxy_ssl_config,
     HttpStreamRequest::Delegate* delegate,
-    WebSocketStreamBase::Factory* factory,
+    WebSocketHandshakeStreamBase::Factory* factory,
     const BoundNetLog& net_log) {
   DCHECK(for_websockets_);
   DCHECK(factory);
@@ -107,12 +107,12 @@
     const SSLConfig& server_ssl_config,
     const SSLConfig& proxy_ssl_config,
     HttpStreamRequest::Delegate* delegate,
-    WebSocketStreamBase::Factory* websocket_stream_factory,
+    WebSocketHandshakeStreamBase::Factory* websocket_handshake_stream_factory,
     const BoundNetLog& net_log) {
   Request* request = new Request(request_info.url,
                                  this,
                                  delegate,
-                                 websocket_stream_factory,
+                                 websocket_handshake_stream_factory,
                                  net_log);
 
   GURL alternate_url;
@@ -289,11 +289,11 @@
                       using_spdy,
                       net_log);
     if (for_websockets_) {
-      WebSocketStreamBase::Factory* factory =
-          request->websocket_stream_factory();
+      WebSocketHandshakeStreamBase::Factory* factory =
+          request->websocket_handshake_stream_factory();
       DCHECK(factory);
       bool use_relative_url = direct || request->url().SchemeIs("wss");
-      request->OnWebSocketStreamReady(
+      request->OnWebSocketHandshakeStreamReady(
           NULL,
           used_ssl_config,
           used_proxy_info,
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 4339fd3..e234242 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -30,7 +30,8 @@
     public HttpPipelinedHostPool::Delegate {
  public:
   // RequestStream may only be called if |for_websockets| is false.
-  // RequestWebSocketStream may only be called if |for_websockets| is true.
+  // RequestWebSocketHandshakeStream may only be called if |for_websockets|
+  // is true.
   HttpStreamFactoryImpl(HttpNetworkSession* session, bool for_websockets);
   virtual ~HttpStreamFactoryImpl();
 
@@ -43,13 +44,13 @@
       HttpStreamRequest::Delegate* delegate,
       const BoundNetLog& net_log) OVERRIDE;
 
-  virtual HttpStreamRequest* RequestWebSocketStream(
+  virtual HttpStreamRequest* RequestWebSocketHandshakeStream(
       const HttpRequestInfo& info,
       RequestPriority priority,
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       HttpStreamRequest::Delegate* delegate,
-      WebSocketStreamBase::Factory* factory,
+      WebSocketHandshakeStreamBase::Factory* factory,
       const BoundNetLog& net_log) OVERRIDE;
 
   virtual void PreconnectStreams(int num_streams,
@@ -84,7 +85,7 @@
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       HttpStreamRequest::Delegate* delegate,
-      WebSocketStreamBase::Factory* factory,
+      WebSocketHandshakeStreamBase::Factory* factory,
       const BoundNetLog& net_log);
 
   PortAlternateProtocolPair GetAlternateProtocolRequestFor(
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 9528200..500c737 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -221,9 +221,9 @@
       connection_->socket()->Disconnect();
     stream_factory_->OnOrphanedJobComplete(this);
   } else if (stream_factory_->for_websockets_) {
-    // We cancel this job because WebSocketStream can't be created
-    // without a WebSocketStreamBase::Factory which is stored in Request class
-    // and isn't accessible from this job.
+    // We cancel this job because a WebSocketHandshakeStream can't be created
+    // without a WebSocketHandshakeStreamBase::Factory which is stored in the
+    // Request class and isn't accessible from this job.
     if (connection_ && connection_->socket())
       connection_->socket()->Disconnect();
     stream_factory_->OnOrphanedJobComplete(this);
@@ -314,7 +314,7 @@
   // |this| may be deleted after this call.
 }
 
-void HttpStreamFactoryImpl::Job::OnWebSocketStreamReadyCallback() {
+void HttpStreamFactoryImpl::Job::OnWebSocketHandshakeStreamReadyCallback() {
   DCHECK(websocket_stream_);
   DCHECK(!IsPreconnecting());
   DCHECK(stream_factory_->for_websockets_);
@@ -325,10 +325,10 @@
                      protocol_negotiated(),
                      using_spdy(),
                      net_log_);
-  request_->OnWebSocketStreamReady(this,
-                                   server_ssl_config_,
-                                   proxy_info_,
-                                   websocket_stream_.release());
+  request_->OnWebSocketHandshakeStreamReady(this,
+                                            server_ssl_config_,
+                                            proxy_info_,
+                                            websocket_stream_.release());
   // |this| may be deleted after this call.
 }
 
@@ -532,9 +532,8 @@
         DCHECK(websocket_stream_);
         base::MessageLoop::current()->PostTask(
             FROM_HERE,
-            base::Bind(
-                &Job::OnWebSocketStreamReadyCallback,
-                ptr_factory_.GetWeakPtr()));
+            base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback,
+                       ptr_factory_.GetWeakPtr()));
       } else {
         DCHECK(stream_.get());
         base::MessageLoop::current()->PostTask(
@@ -1065,9 +1064,9 @@
       CHECK(stream_.get());
     } else if (stream_factory_->for_websockets_) {
       DCHECK(request_);
-      DCHECK(request_->websocket_stream_factory());
+      DCHECK(request_->websocket_handshake_stream_factory());
       websocket_stream_.reset(
-          request_->websocket_stream_factory()->CreateBasicStream(
+          request_->websocket_handshake_stream_factory()->CreateBasicStream(
               connection_.release(), using_proxy));
     } else if (!using_proxy && IsRequestEligibleForPipelining()) {
       // TODO(simonjam): Support proxies.
@@ -1082,8 +1081,7 @@
               protocol_negotiated_));
       CHECK(stream_.get());
     } else {
-      stream_.reset(new HttpBasicStream(connection_.release(), NULL,
-                                        using_proxy));
+      stream_.reset(new HttpBasicStream(connection_.release(), using_proxy));
     }
     return OK;
   }
@@ -1143,10 +1141,10 @@
 
   if (stream_factory_->for_websockets_) {
     DCHECK(request_);
-    DCHECK(request_->websocket_stream_factory());
+    DCHECK(request_->websocket_handshake_stream_factory());
     bool use_relative_url = direct || request_info_.url.SchemeIs("wss");
     websocket_stream_.reset(
-        request_->websocket_stream_factory()->CreateSpdyStream(
+        request_->websocket_handshake_stream_factory()->CreateSpdyStream(
             spdy_session, use_relative_url));
   } else {
     bool use_relative_url = direct || request_info_.url.SchemeIs("https");
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index 01a794a..1970b5b 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -130,7 +130,7 @@
   };
 
   void OnStreamReadyCallback();
-  void OnWebSocketStreamReadyCallback();
+  void OnWebSocketHandshakeStreamReadyCallback();
   // This callback function is called when a new SPDY session is created.
   void OnNewSpdySessionReadyCallback();
   void OnStreamFailedCallback(int result);
@@ -297,7 +297,7 @@
   bool establishing_tunnel_;
 
   scoped_ptr<HttpStream> stream_;
-  scoped_ptr<WebSocketStreamBase> websocket_stream_;
+  scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
 
   // True if we negotiated NPN.
   bool was_npn_negotiated_;
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index 57190ed..ea4ca9b 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -17,11 +17,11 @@
     const GURL& url,
     HttpStreamFactoryImpl* factory,
     HttpStreamRequest::Delegate* delegate,
-    WebSocketStreamBase::Factory* websocket_stream_factory,
+    WebSocketHandshakeStreamBase::Factory* websocket_handshake_stream_factory,
     const BoundNetLog& net_log)
     : url_(url),
       factory_(factory),
-      websocket_stream_factory_(websocket_stream_factory),
+      websocket_handshake_stream_factory_(websocket_handshake_stream_factory),
       delegate_(delegate),
       net_log_(net_log),
       completed_(false),
@@ -110,17 +110,18 @@
   delegate_->OnStreamReady(used_ssl_config, used_proxy_info, stream);
 }
 
-void HttpStreamFactoryImpl::Request::OnWebSocketStreamReady(
+void HttpStreamFactoryImpl::Request::OnWebSocketHandshakeStreamReady(
     Job* job,
     const SSLConfig& used_ssl_config,
     const ProxyInfo& used_proxy_info,
-    WebSocketStreamBase* stream) {
+    WebSocketHandshakeStreamBase* stream) {
   DCHECK(factory_->for_websockets_);
   DCHECK(stream);
   DCHECK(completed_);
 
   OnJobSucceeded(job);
-  delegate_->OnWebSocketStreamReady(used_ssl_config, used_proxy_info, stream);
+  delegate_->OnWebSocketHandshakeStreamReady(
+      used_ssl_config, used_proxy_info, stream);
 }
 
 void HttpStreamFactoryImpl::Request::OnStreamFailed(
@@ -315,13 +316,13 @@
   // Cache this so we can still use it if the request is deleted.
   HttpStreamFactoryImpl* factory = factory_;
   if (factory->for_websockets_) {
-    DCHECK(websocket_stream_factory_);
+    DCHECK(websocket_handshake_stream_factory_);
     bool use_relative_url = direct || url().SchemeIs("wss");
-    delegate_->OnWebSocketStreamReady(
+    delegate_->OnWebSocketHandshakeStreamReady(
         job->server_ssl_config(),
         job->proxy_info(),
-        websocket_stream_factory_->CreateSpdyStream(spdy_session,
-                                                    use_relative_url));
+        websocket_handshake_stream_factory_->CreateSpdyStream(
+            spdy_session, use_relative_url));
   } else {
     bool use_relative_url = direct || url().SchemeIs("https");
     delegate_->OnStreamReady(
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index d6f9b02..a8a3c7d 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -20,11 +20,12 @@
 
 class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
  public:
-  Request(const GURL& url,
-          HttpStreamFactoryImpl* factory,
-          HttpStreamRequest::Delegate* delegate,
-          WebSocketStreamBase::Factory* websocket_stream_factory,
-          const BoundNetLog& net_log);
+  Request(
+      const GURL& url,
+      HttpStreamFactoryImpl* factory,
+      HttpStreamRequest::Delegate* delegate,
+      WebSocketHandshakeStreamBase::Factory* websocket_handshake_stream_factory,
+      const BoundNetLog& net_log);
   virtual ~Request();
 
   // The GURL from the HttpRequestInfo the started the Request.
@@ -66,8 +67,8 @@
                              const base::WeakPtr<SpdySession>& spdy_session,
                              bool direct);
 
-  WebSocketStreamBase::Factory* websocket_stream_factory() {
-    return websocket_stream_factory_;
+  WebSocketHandshakeStreamBase::Factory* websocket_handshake_stream_factory() {
+    return websocket_handshake_stream_factory_;
   }
 
   // HttpStreamRequest::Delegate methods which we implement. Note we don't
@@ -77,10 +78,10 @@
                      const SSLConfig& used_ssl_config,
                      const ProxyInfo& used_proxy_info,
                      HttpStreamBase* stream);
-  void OnWebSocketStreamReady(Job* job,
-                              const SSLConfig& used_ssl_config,
-                              const ProxyInfo& used_proxy_info,
-                              WebSocketStreamBase* stream);
+  void OnWebSocketHandshakeStreamReady(Job* job,
+                                       const SSLConfig& used_ssl_config,
+                                       const ProxyInfo& used_proxy_info,
+                                       WebSocketHandshakeStreamBase* stream);
   void OnStreamFailed(Job* job, int status, const SSLConfig& used_ssl_config);
   void OnCertificateError(Job* job,
                           int status,
@@ -124,7 +125,8 @@
 
   const GURL url_;
   HttpStreamFactoryImpl* const factory_;
-  WebSocketStreamBase::Factory* const websocket_stream_factory_;
+  WebSocketHandshakeStreamBase::Factory* const
+      websocket_handshake_stream_factory_;
   HttpStreamRequest::Delegate* const delegate_;
   const BoundNetLog net_log_;
 
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
index 5e96c3a..b3b12bf 100644
--- a/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -36,10 +36,10 @@
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
       HttpStreamBase* stream) OVERRIDE {}
-  virtual void OnWebSocketStreamReady(
+  virtual void OnWebSocketHandshakeStreamReady(
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
-      WebSocketStreamBase* stream) OVERRIDE {}
+      WebSocketHandshakeStreamBase* stream) OVERRIDE {}
   virtual void OnStreamFailed(
       int status,
       const SSLConfig& used_ssl_config) OVERRIDE {}
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 217fa50..0cf9e69 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -36,7 +36,7 @@
 // This file can be included from net/http even though
 // it is in net/websockets because it doesn't
 // introduce any link dependency to net/websockets.
-#include "net/websockets/websocket_stream_base.h"
+#include "net/websockets/websocket_handshake_stream_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -57,23 +57,65 @@
   bool use_alternate_protocols_;
 };
 
-class MockWebSocketStream : public WebSocketStreamBase {
+class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
  public:
   enum StreamType {
     kStreamTypeBasic,
     kStreamTypeSpdy,
   };
 
-  explicit MockWebSocketStream(StreamType type) : type_(type) {}
+  explicit MockWebSocketHandshakeStream(StreamType type) : type_(type) {}
 
-  virtual ~MockWebSocketStream() {}
-
-  virtual WebSocketStream* AsWebSocketStream() OVERRIDE { return NULL; }
+  virtual ~MockWebSocketHandshakeStream() {}
 
   StreamType type() const {
     return type_;
   }
 
+  // HttpStreamBase methods
+  virtual int InitializeStream(const HttpRequestInfo* request_info,
+                               RequestPriority priority,
+                               const BoundNetLog& net_log,
+                               const CompletionCallback& callback) OVERRIDE {
+    return ERR_IO_PENDING;
+  }
+  virtual int SendRequest(const HttpRequestHeaders& request_headers,
+                          HttpResponseInfo* response,
+                          const CompletionCallback& callback) OVERRIDE {
+    return ERR_IO_PENDING;
+  }
+  virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
+    return ERR_IO_PENDING;
+  }
+  virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE {
+    return NULL;
+  }
+  virtual int ReadResponseBody(IOBuffer* buf,
+                               int buf_len,
+                               const CompletionCallback& callback) OVERRIDE {
+    return ERR_IO_PENDING;
+  }
+  virtual void Close(bool not_reusable) OVERRIDE {}
+  virtual bool IsResponseBodyComplete() const OVERRIDE { return false; }
+  virtual bool CanFindEndOfResponse() const OVERRIDE { return false; }
+  virtual bool IsConnectionReused() const OVERRIDE { return false; }
+  virtual void SetConnectionReused() OVERRIDE {}
+  virtual bool IsConnectionReusable() const OVERRIDE { return false; }
+  virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const
+      OVERRIDE {
+    return false;
+  }
+  virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {}
+  virtual void GetSSLCertRequestInfo(
+      SSLCertRequestInfo* cert_request_info) OVERRIDE {}
+  virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
+  virtual void Drain(HttpNetworkSession* session) OVERRIDE {}
+  virtual void SetPriority(RequestPriority priority) OVERRIDE {}
+
+  virtual scoped_ptr<WebSocketStream> Upgrade() OVERRIDE {
+    return scoped_ptr<WebSocketStream>();
+  }
+
  private:
   const StreamType type_;
 };
@@ -128,10 +170,10 @@
     used_proxy_info_ = used_proxy_info;
   }
 
-  virtual void OnWebSocketStreamReady(
+  virtual void OnWebSocketHandshakeStreamReady(
       const SSLConfig& used_ssl_config,
       const ProxyInfo& used_proxy_info,
-      WebSocketStreamBase* stream) OVERRIDE {
+      WebSocketHandshakeStreamBase* stream) OVERRIDE {
     stream_done_ = true;
     if (waiting_for_stream_)
       base::MessageLoop::current()->Quit();
@@ -182,8 +224,8 @@
     return stream_.get();
   }
 
-  MockWebSocketStream* websocket_stream() {
-    return static_cast<MockWebSocketStream*>(websocket_stream_.get());
+  MockWebSocketHandshakeStream* websocket_stream() {
+    return static_cast<MockWebSocketHandshakeStream*>(websocket_stream_.get());
   }
 
   bool stream_done() const { return stream_done_; }
@@ -192,19 +234,21 @@
   bool waiting_for_stream_;
   bool stream_done_;
   scoped_ptr<HttpStreamBase> stream_;
-  scoped_ptr<WebSocketStreamBase> websocket_stream_;
+  scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
   SSLConfig used_ssl_config_;
   ProxyInfo used_proxy_info_;
 
   DISALLOW_COPY_AND_ASSIGN(StreamRequestWaiter);
 };
 
-class WebSocketSpdyStream : public MockWebSocketStream {
+class WebSocketSpdyHandshakeStream : public MockWebSocketHandshakeStream {
  public:
-  explicit WebSocketSpdyStream(const base::WeakPtr<SpdySession>& spdy_session)
-      : MockWebSocketStream(kStreamTypeSpdy), spdy_session_(spdy_session) {}
+  explicit WebSocketSpdyHandshakeStream(
+      const base::WeakPtr<SpdySession>& spdy_session)
+      : MockWebSocketHandshakeStream(kStreamTypeSpdy),
+        spdy_session_(spdy_session) {}
 
-  virtual ~WebSocketSpdyStream() {}
+  virtual ~WebSocketSpdyHandshakeStream() {}
 
   SpdySession* spdy_session() { return spdy_session_.get(); }
 
@@ -212,12 +256,13 @@
   base::WeakPtr<SpdySession> spdy_session_;
 };
 
-class WebSocketBasicStream : public MockWebSocketStream {
+class WebSocketBasicHandshakeStream : public MockWebSocketHandshakeStream {
  public:
-  explicit WebSocketBasicStream(ClientSocketHandle* connection)
-      : MockWebSocketStream(kStreamTypeBasic), connection_(connection) {}
+  explicit WebSocketBasicHandshakeStream(ClientSocketHandle* connection)
+      : MockWebSocketHandshakeStream(kStreamTypeBasic),
+        connection_(connection) {}
 
-  virtual ~WebSocketBasicStream() {
+  virtual ~WebSocketBasicHandshakeStream() {
     connection_->socket()->Disconnect();
   }
 
@@ -227,19 +272,20 @@
   scoped_ptr<ClientSocketHandle> connection_;
 };
 
-class WebSocketStreamFactory : public WebSocketStreamBase::Factory {
+class WebSocketStreamFactory : public WebSocketHandshakeStreamBase::Factory {
  public:
   virtual ~WebSocketStreamFactory() {}
 
-  virtual WebSocketStreamBase* CreateBasicStream(ClientSocketHandle* connection,
-                                                 bool using_proxy) OVERRIDE {
-    return new WebSocketBasicStream(connection);
+  virtual WebSocketHandshakeStreamBase* CreateBasicStream(
+      ClientSocketHandle* connection,
+      bool using_proxy) OVERRIDE {
+    return new WebSocketBasicHandshakeStream(connection);
   }
 
-  virtual WebSocketStreamBase* CreateSpdyStream(
+  virtual WebSocketHandshakeStreamBase* CreateSpdyStream(
       const base::WeakPtr<SpdySession>& spdy_session,
       bool use_relative_url) OVERRIDE {
-    return new WebSocketSpdyStream(spdy_session);
+    return new WebSocketSpdyHandshakeStream(spdy_session);
   }
 };
 
@@ -865,7 +911,7 @@
   EXPECT_FALSE(waiter.used_proxy_info().is_direct());
 }
 
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicStream) {
+TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) {
   SpdySessionDependencies session_deps(
       GetParam(), ProxyService::CreateDirect());
 
@@ -886,19 +932,19 @@
   StreamRequestWaiter waiter;
   WebSocketStreamFactory factory;
   scoped_ptr<HttpStreamRequest> request(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter,
+                                            &factory,
+                                            BoundNetLog()));
   waiter.WaitForStream();
   EXPECT_TRUE(waiter.stream_done());
   EXPECT_TRUE(NULL == waiter.stream());
   ASSERT_TRUE(NULL != waiter.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeBasic,
             waiter.websocket_stream()->type());
   EXPECT_EQ(0, GetSocketPoolGroupCount(
       session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
@@ -912,7 +958,7 @@
   EXPECT_TRUE(waiter.used_proxy_info().is_direct());
 }
 
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicStreamOverSSL) {
+TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) {
   SpdySessionDependencies session_deps(
       GetParam(), ProxyService::CreateDirect());
 
@@ -937,19 +983,19 @@
   StreamRequestWaiter waiter;
   WebSocketStreamFactory factory;
   scoped_ptr<HttpStreamRequest> request(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter,
+                                            &factory,
+                                            BoundNetLog()));
   waiter.WaitForStream();
   EXPECT_TRUE(waiter.stream_done());
   EXPECT_TRUE(NULL == waiter.stream());
   ASSERT_TRUE(NULL != waiter.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeBasic,
             waiter.websocket_stream()->type());
   EXPECT_EQ(0, GetSocketPoolGroupCount(
       session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
@@ -963,7 +1009,7 @@
   EXPECT_TRUE(waiter.used_proxy_info().is_direct());
 }
 
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicStreamOverProxy) {
+TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) {
   SpdySessionDependencies session_deps(
       GetParam(), ProxyService::CreateFixed("myproxy:8888"));
 
@@ -985,19 +1031,19 @@
   StreamRequestWaiter waiter;
   WebSocketStreamFactory factory;
   scoped_ptr<HttpStreamRequest> request(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter,
+                                            &factory,
+                                            BoundNetLog()));
   waiter.WaitForStream();
   EXPECT_TRUE(waiter.stream_done());
   EXPECT_TRUE(NULL == waiter.stream());
   ASSERT_TRUE(NULL != waiter.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeBasic,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeBasic,
             waiter.websocket_stream()->type());
   EXPECT_EQ(0, GetSocketPoolGroupCount(
       session->GetTransportSocketPool(
@@ -1072,7 +1118,7 @@
   EXPECT_TRUE(waiter.used_proxy_info().is_direct());
 }
 
-TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyStream) {
+TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStream) {
   SpdySessionDependencies session_deps(GetParam(),
                                        ProxyService::CreateDirect());
 
@@ -1099,42 +1145,42 @@
   StreamRequestWaiter waiter1;
   WebSocketStreamFactory factory;
   scoped_ptr<HttpStreamRequest> request1(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter1,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter1,
+                                            &factory,
+                                            BoundNetLog()));
   waiter1.WaitForStream();
   EXPECT_TRUE(waiter1.stream_done());
   ASSERT_TRUE(NULL != waiter1.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeSpdy,
             waiter1.websocket_stream()->type());
   EXPECT_TRUE(NULL == waiter1.stream());
 
   StreamRequestWaiter waiter2;
   scoped_ptr<HttpStreamRequest> request2(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter2,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter2,
+                                            &factory,
+                                            BoundNetLog()));
   waiter2.WaitForStream();
   EXPECT_TRUE(waiter2.stream_done());
   ASSERT_TRUE(NULL != waiter2.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeSpdy,
             waiter2.websocket_stream()->type());
   EXPECT_TRUE(NULL == waiter2.stream());
   EXPECT_NE(waiter2.websocket_stream(), waiter1.websocket_stream());
-  EXPECT_EQ(static_cast<WebSocketSpdyStream*>(waiter2.websocket_stream())->
-            spdy_session(),
-            static_cast<WebSocketSpdyStream*>(waiter1.websocket_stream())->
-            spdy_session());
+  EXPECT_EQ(static_cast<WebSocketSpdyHandshakeStream*>(
+                waiter2.websocket_stream())->spdy_session(),
+            static_cast<WebSocketSpdyHandshakeStream*>(
+                waiter1.websocket_stream())->spdy_session());
 
   EXPECT_EQ(0, GetSocketPoolGroupCount(
       session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)));
@@ -1189,19 +1235,19 @@
   StreamRequestWaiter waiter;
   WebSocketStreamFactory factory;
   scoped_ptr<HttpStreamRequest> request(
-      session->websocket_stream_factory()->RequestWebSocketStream(
-          request_info,
-          DEFAULT_PRIORITY,
-          ssl_config,
-          ssl_config,
-          &waiter,
-          &factory,
-          BoundNetLog()));
+      session->websocket_handshake_stream_factory()
+          ->RequestWebSocketHandshakeStream(request_info,
+                                            DEFAULT_PRIORITY,
+                                            ssl_config,
+                                            ssl_config,
+                                            &waiter,
+                                            &factory,
+                                            BoundNetLog()));
   waiter.WaitForStream();
   EXPECT_TRUE(waiter.stream_done());
   EXPECT_TRUE(NULL == waiter.stream());
   ASSERT_TRUE(NULL != waiter.websocket_stream());
-  EXPECT_EQ(MockWebSocketStream::kStreamTypeSpdy,
+  EXPECT_EQ(MockWebSocketHandshakeStream::kStreamTypeSpdy,
             waiter.websocket_stream()->type());
 
   // Make sure that there was an alternative connection
@@ -1219,7 +1265,7 @@
 
   // Make sure there is no orphaned job. it is already canceled.
   ASSERT_EQ(0u, static_cast<HttpStreamFactoryImpl*>(
-      session->websocket_stream_factory())->num_orphaned_jobs());
+      session->websocket_handshake_stream_factory())->num_orphaned_jobs());
 }
 
 }  // namespace
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index d238e99..df2d95f 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -522,6 +522,7 @@
   DOMAIN_CHROMIUM_ORG,
 
   DOMAIN_CRYPTO_CAT,
+  DOMAIN_LAVABIT_COM,
 
   // Boundary value for UMA_HISTOGRAM_ENUMERATION:
   DOMAIN_NUM_EVENTS
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs
index 90a11c9..dc71f3a 100644
--- a/net/http/transport_security_state_static.certs
+++ b/net/http/transport_security_state_static.certs
@@ -1323,3 +1323,41 @@
 2PftKlqZo3WAeJoUCPtQNsLnBFGvdUx2rUZwMhdgPuGeV4kEULAtu8M74xR5/Opz
 nRGP22zr1K4q
 -----END CERTIFICATE-----
+
+Libertylavabitcom
+-----BEGIN CERTIFICATE-----
+MIIGWjCCBUKgAwIBAgIHAMn6RGIIgjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
+BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
+aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
+IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
+ODcwHhcNMTMxMDExMDgzNjAyWhcNMTQxMDExMDgzNjAyWjBBMSEwHwYDVQQLExhE
+b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxHDAaBgNVBAMTE2xpYmVydHkubGF2YWJp
+dC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo/gQ2t5YtS2dj
+BhIo2ke667uC2qhnUbnroyuqyf+GZafWZC/cmPYpkAWclu14ETBsR3u+6QtDHhOe
+q3OBN0+IVLu5QwYSB2sqYUwyOHZ342uHQktWpPvNiwNHyfl1LsHL4WLuvQw3stK4
+DR+l6H/Ex11bl4KVvfk8uy+kXawcIQv7gr69OwEFEmGqeLSqr+fZdegLKPY20Ujx
+WHSe8ErtW0eMY2A/DvrDrnfw+rVX5sxJIKk77AutIoyt+Ce2TwMVQtfbeQVWy91g
+ST+sqC69wI5BOSguV5zECqIP1zxo939VVVciNGA3+3gyLJa+NDDpbT8xCwXClXN4
+3iektxfP7OgPjPwhDueZNhq54mA5mBY+qdkLyCmvURiczSNeoDTWouqaJq1lKjuh
+CgkAhgoaLueAQv+uGNlVFtbQHApEvYcdz8XTqoL24wf3kadu6vxhrYVS+hguVVEE
+YOc7LJsiQ3ERDjh1naFlL9h5khn6qhjw77oS6PWaCIJT8GfD8bjqCozdOdS1e+Sh
+Bbp2Yg48m/XyQ3ocpEUmTt7n3fRv41XOY4tmBhloqkdPIDccl5deUhI//1VgycJv
+uDqsMgRhyZvdS1kxhDAwbi1GtomURGdB/9kptYshUrR6xk1EP60pjWNxuvB7HMPg
+seGNxPa15U/4z+5h8iSFdKa2TLkk7wIDAQABo4IByzCCAccwDwYDVR0TAQH/BAUw
+AwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD
+AgWgMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rz
+MS0xMDAuY3JsMFMGA1UdIARMMEowSAYLYIZIAYb9bQEHFwEwOTA3BggrBgEFBQcC
+ARYraHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzCB
+gAYIKwYBBQUHAQEEdDByMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5
+LmNvbS8wSgYIKwYBBQUHMAKGPmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
+b20vcmVwb3NpdG9yeS9nZF9pbnRlcm1lZGlhdGUuY3J0MB8GA1UdIwQYMBaAFP2s
+YTKTbEXW4u6FX5q653aZaMznMDcGA1UdEQQwMC6CE2xpYmVydHkubGF2YWJpdC5j
+b22CF3d3dy5saWJlcnR5LmxhdmFiaXQuY29tMB0GA1UdDgQWBBSVRSbXCJKN6lms
+ZtlccHBz/xVLwDANBgkqhkiG9w0BAQUFAAOCAQEAKja1YxyoTuHD1RV4L7wULpiy
+ot4Z3OEuoOZTPJsoHfUCtOtKlUu2ZSwp5+IpaLnC3iCIxy1Yb6qu6Li5dqgtOkxl
+4JqrOooQ9IUzuTLhSzPf6rEtw9gnYN/dpQ2q0YLh+K5SgRUm9y0PHBV4acfSh2TJ
+vyaXDmuonX5zG7u3nz/oCo/qziW46Phz/leMhCAgLnZUYcAv6KPET+RMRmt4n8gg
+C0xlOcCQbMh9VIPZ0WSnmdFn5DUCW+oVlwhxDB/3CvWIa0k/WI6NNW8vg+VdSyW7
+p/dp4mikGH37Tc5VAhcYMbAem69nSg7Qfrs35tak/JPJlx1LWayERGHLvTy7Ag==
+-----END CERTIFICATE-----
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index be1f854..3bfc41b 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -246,6 +246,10 @@
     "\x4c\x87\xce\x85\x2c\xf4\xc0\x4d\x67\xa9"
     "\xe0\xec\x51\x0c\x7f\x3b\x14\xb3\xe9\xc9";
 
+static const char kSPKIHash_Libertylavabitcom[] =
+    "\x41\xbb\x3b\x8b\xc7\xcf\x3d\x13\x3f\x17"
+    "\xb3\x25\x7e\xe4\x03\xca\x8a\x5c\x6d\x36";
+
 // The following is static data describing the hosts that are hardcoded with
 // certificate pins or HSTS information.
 
@@ -399,6 +403,15 @@
   kNoRejectedPublicKeys, \
 }
 
+static const char* const kLavabitAcceptableCerts[] = {
+  kSPKIHash_Libertylavabitcom,
+  NULL,
+};
+#define kLavabitPins { \
+  kLavabitAcceptableCerts, \
+  kNoRejectedPublicKeys, \
+}
+
 #define kNoPins {\
   NULL, NULL, \
 }
@@ -880,6 +893,7 @@
   {12, true, "\006cybozu\003com", true, kNoPins, DOMAIN_NOT_PINNED },
   {17, true, "\013davidlyness\003com", true, kNoPins, DOMAIN_NOT_PINNED },
   {12, true, "\006medium\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+  {21, true, "\007liberty\007lavabit\003com", true, kLavabitPins, DOMAIN_LAVABIT_COM },
 };
 static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
 
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 8850fbd..b453e26 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -156,6 +156,12 @@
         "DigiCertEVRoot",
         "CryptoCat1"
       ]
+    },
+    {
+      "name": "lavabit",
+      "static_spki_hashes": [
+        "Libertylavabitcom"
+      ]
     }
   ],
 
@@ -654,6 +660,7 @@
     { "name": "cybozu.com", "include_subdomains": true,  "mode": "force-https" },
     { "name": "davidlyness.com", "include_subdomains": true,  "mode": "force-https" },
     { "name": "medium.com", "include_subdomains": true,  "mode": "force-https" },
+    { "name": "liberty.lavabit.com", "include_subdomains": true, "mode": "force-https", "pins": "lavabit" },
 
     // Entries that are only valid if the client supports SNI.
     { "name": "gmail.com", "mode": "force-https", "pins": "google", "snionly": true },
diff --git a/net/http_server.target.darwin-arm.mk b/net/http_server.target.darwin-arm.mk
index 3277aef..9411125 100644
--- a/net/http_server.target.darwin-arm.mk
+++ b/net/http_server.target.darwin-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/http_server.target.darwin-mips.mk b/net/http_server.target.darwin-mips.mk
index 2c0efef..2578fdf 100644
--- a/net/http_server.target.darwin-mips.mk
+++ b/net/http_server.target.darwin-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/http_server.target.darwin-x86.mk b/net/http_server.target.darwin-x86.mk
index fedaed8..435b681 100644
--- a/net/http_server.target.darwin-x86.mk
+++ b/net/http_server.target.darwin-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/http_server.target.linux-arm.mk b/net/http_server.target.linux-arm.mk
index 3277aef..9411125 100644
--- a/net/http_server.target.linux-arm.mk
+++ b/net/http_server.target.linux-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/http_server.target.linux-mips.mk b/net/http_server.target.linux-mips.mk
index 2c0efef..2578fdf 100644
--- a/net/http_server.target.linux-mips.mk
+++ b/net/http_server.target.linux-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/http_server.target.linux-x86.mk b/net/http_server.target.linux-x86.mk
index fedaed8..435b681 100644
--- a/net/http_server.target.linux-x86.mk
+++ b/net/http_server.target.linux-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.gyp b/net/net.gyp
index 451e2ac..114f8f1 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -303,8 +303,10 @@
         'cert/x509_certificate_nss.cc',
         'cert/x509_certificate_openssl.cc',
         'cert/x509_certificate_win.cc',
-        'cert/x509_util.h',
         'cert/x509_util.cc',
+        'cert/x509_util.h',
+        'cert/x509_util_android.cc',
+        'cert/x509_util_android.h',
         'cert/x509_util_ios.cc',
         'cert/x509_util_ios.h',
         'cert/x509_util_mac.cc',
@@ -543,6 +545,8 @@
         'http/http_auth_handler_ntlm_win.cc',
         'http/http_auth_sspi_win.cc',
         'http/http_auth_sspi_win.h',
+        'http/http_basic_state.cc',
+        'http/http_basic_state.h',
         'http/http_basic_stream.cc',
         'http/http_basic_stream.h',
         'http/http_byte_range.cc',
@@ -793,6 +797,8 @@
         'quic/crypto/strike_register.h',
         'quic/crypto/source_address_token.cc',
         'quic/crypto/source_address_token.h',
+        'quic/iovector.cc',
+        'quic/iovector.h',
         'quic/quic_ack_notifier.cc',
         'quic/quic_ack_notifier.h',
         'quic/quic_ack_notifier_manager.cc',
@@ -804,17 +810,10 @@
         'quic/quic_blocked_writer_interface.h',
         'quic/quic_client_session.cc',
         'quic/quic_client_session.h',
-        'quic/quic_config.cc',
-        'quic/quic_config.h',
-        'quic/quic_crypto_client_stream.cc',
-        'quic/quic_crypto_client_stream.h',
-        'quic/quic_crypto_client_stream_factory.h',
-        'quic/quic_crypto_server_stream.cc',
-        'quic/quic_crypto_server_stream.h',
-        'quic/quic_crypto_stream.cc',
-        'quic/quic_crypto_stream.h',
         'quic/quic_clock.cc',
         'quic/quic_clock.h',
+        'quic/quic_config.cc',
+        'quic/quic_config.h',
         'quic/quic_connection.cc',
         'quic/quic_connection.h',
         'quic/quic_connection_helper.cc',
@@ -823,10 +822,19 @@
         'quic/quic_connection_logger.h',
         'quic/quic_connection_stats.cc',
         'quic/quic_connection_stats.h',
+        'quic/quic_crypto_client_stream.cc',
+        'quic/quic_crypto_client_stream.h',
+        'quic/quic_crypto_client_stream_factory.h',
+        'quic/quic_crypto_server_stream.cc',
+        'quic/quic_crypto_server_stream.h',
+        'quic/quic_crypto_stream.cc',
+        'quic/quic_crypto_stream.h',
         'quic/quic_data_reader.cc',
         'quic/quic_data_reader.h',
         'quic/quic_data_writer.cc',
         'quic/quic_data_writer.h',
+        'quic/quic_default_packet_writer.cc',
+        'quic/quic_default_packet_writer.h',
         'quic/quic_fec_group.cc',
         'quic/quic_fec_group.h',
         'quic/quic_framer.cc',
@@ -839,6 +847,7 @@
         'quic/quic_packet_creator.h',
         'quic/quic_packet_generator.cc',
         'quic/quic_packet_generator.h',
+        'quic/quic_packet_writer.h',
         'quic/quic_protocol.cc',
         'quic/quic_protocol.h',
         'quic/quic_received_packet_manager.cc',
@@ -948,10 +957,6 @@
         'spdy/spdy_buffer.h',
         'spdy/spdy_buffer_producer.cc',
         'spdy/spdy_buffer_producer.h',
-        'spdy/spdy_credential_builder.cc',
-        'spdy/spdy_credential_builder.h',
-        'spdy/spdy_credential_state.cc',
-        'spdy/spdy_credential_state.h',
         'spdy/spdy_frame_builder.cc',
         'spdy/spdy_frame_builder.h',
         'spdy/spdy_frame_reader.cc',
@@ -1110,6 +1115,9 @@
         'websockets/websocket_basic_stream.h',
         'websockets/websocket_channel.cc',
         'websockets/websocket_channel.h',
+        'websockets/websocket_deflate_predictor.h',
+        'websockets/websocket_deflate_predictor_impl.cc',
+        'websockets/websocket_deflate_predictor_impl.h',
         'websockets/websocket_deflate_stream.cc',
         'websockets/websocket_deflate_stream.h',
         'websockets/websocket_deflater.cc',
@@ -1128,6 +1136,7 @@
         'websockets/websocket_handshake_constants.h',
         'websockets/websocket_handshake_handler.cc',
         'websockets/websocket_handshake_handler.h',
+        'websockets/websocket_handshake_stream_base.h',
         'websockets/websocket_inflater.cc',
         'websockets/websocket_inflater.h',
         'websockets/websocket_job.cc',
@@ -1137,7 +1146,6 @@
         'websockets/websocket_net_log_params.h',
         'websockets/websocket_stream.cc',
         'websockets/websocket_stream.h',
-        'websockets/websocket_stream_base.h',
         'websockets/websocket_throttle.cc',
         'websockets/websocket_throttle.h',
       ],
@@ -1645,13 +1653,14 @@
         'http/http_auth_handler_unittest.cc',
         'http/http_auth_sspi_win_unittest.cc',
         'http/http_auth_unittest.cc',
+        'http/http_basic_state_unittest.cc',
         'http/http_byte_range_unittest.cc',
         'http/http_cache_unittest.cc',
         'http/http_chunked_decoder_unittest.cc',
         'http/http_content_disposition_unittest.cc',
         'http/http_network_layer_unittest.cc',
-        'http/http_network_transaction_unittest.cc',
         'http/http_network_transaction_ssl_unittest.cc',
+        'http/http_network_transaction_unittest.cc',
         'http/http_pipelined_connection_impl_unittest.cc',
         'http/http_pipelined_host_forced_unittest.cc',
         'http/http_pipelined_host_impl_unittest.cc',
@@ -1765,6 +1774,8 @@
         'quic/test_tools/quic_session_peer.h',
         'quic/test_tools/quic_test_utils.cc',
         'quic/test_tools/quic_test_utils.h',
+        'quic/test_tools/quic_test_writer.cc',
+        'quic/test_tools/quic_test_writer.h',
         'quic/test_tools/reliable_quic_stream_peer.cc',
         'quic/test_tools/reliable_quic_stream_peer.h',
         'quic/test_tools/simple_quic_framer.cc',
@@ -1828,9 +1839,7 @@
         'socket_stream/socket_stream_metrics_unittest.cc',
         'socket_stream/socket_stream_unittest.cc',
         'spdy/buffered_spdy_framer_unittest.cc',
-        'spdy/spdy_credential_builder_unittest.cc',
         'spdy/spdy_buffer_unittest.cc',
-        'spdy/spdy_credential_state_unittest.cc',
         'spdy/spdy_frame_builder_test.cc',
         'spdy/spdy_frame_reader_test.cc',
         'spdy/spdy_framer_test.cc',
@@ -1894,6 +1903,7 @@
         'url_request/view_cache_helper_unittest.cc',
         'websockets/websocket_basic_stream_test.cc',
         'websockets/websocket_channel_test.cc',
+        'websockets/websocket_deflate_predictor_impl_test.cc',
         'websockets/websocket_deflate_stream_test.cc',
         'websockets/websocket_deflater_test.cc',
         'websockets/websocket_errors_test.cc',
@@ -1944,12 +1954,16 @@
             'tools/quic/test_tools/mock_epoll_server.h',
             'tools/quic/test_tools/mock_quic_dispatcher.cc',
             'tools/quic/test_tools/mock_quic_dispatcher.h',
+            'tools/quic/test_tools/packet_dropping_test_writer.cc',
+            'tools/quic/test_tools/packet_dropping_test_writer.h',
             'tools/quic/test_tools/quic_client_peer.cc',
             'tools/quic/test_tools/quic_client_peer.h',
-            'tools/quic/test_tools/quic_epoll_connection_helper_peer.cc',
-            'tools/quic/test_tools/quic_epoll_connection_helper_peer.h',
+            'tools/quic/test_tools/quic_dispatcher_peer.cc',
+            'tools/quic/test_tools/quic_dispatcher_peer.h',
             'tools/quic/test_tools/quic_in_memory_cache_peer.h',
             'tools/quic/test_tools/quic_in_memory_cache_peer.cc',
+            'tools/quic/test_tools/quic_server_peer.cc',
+            'tools/quic/test_tools/quic_server_peer.h',
             'tools/quic/test_tools/quic_test_client.cc',
             'tools/quic/test_tools/quic_test_client.h',
             'tools/quic/test_tools/quic_test_utils.cc',
@@ -2773,6 +2787,8 @@
             'tools/quic/quic_client.h',
             'tools/quic/quic_client_session.cc',
             'tools/quic/quic_client_session.h',
+            'tools/quic/quic_default_packet_writer.cc',
+            'tools/quic/quic_default_packet_writer.h',
             'tools/quic/quic_dispatcher.h',
             'tools/quic/quic_dispatcher.cc',
             'tools/quic/quic_epoll_clock.cc',
@@ -2781,7 +2797,6 @@
             'tools/quic/quic_epoll_connection_helper.h',
             'tools/quic/quic_in_memory_cache.cc',
             'tools/quic/quic_in_memory_cache.h',
-            'tools/quic/quic_packet_writer.h',
             'tools/quic/quic_reliable_client_stream.cc',
             'tools/quic/quic_reliable_client_stream.h',
             'tools/quic/quic_reliable_server_stream.cc',
@@ -2841,6 +2856,7 @@
             'android/java/src/org/chromium/net/GURLUtils.java',
             'android/java/src/org/chromium/net/NetworkChangeNotifier.java',
             'android/java/src/org/chromium/net/ProxyChangeListener.java',
+            'android/java/src/org/chromium/net/X509Util.java',
           ],
           'variables': {
             'jni_gen_package': 'net',
diff --git a/net/net.target.darwin-arm.mk b/net/net.target.darwin-arm.mk
index ffd2b46..04a09d1 100644
--- a/net/net.target.darwin-arm.mk
+++ b/net/net.target.darwin-arm.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -504,13 +507,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -597,13 +600,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.target.darwin-mips.mk b/net/net.target.darwin-mips.mk
index a86fb21..1e30736 100644
--- a/net/net.target.darwin-mips.mk
+++ b/net/net.target.darwin-mips.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -503,13 +506,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -595,13 +598,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.target.darwin-x86.mk b/net/net.target.darwin-x86.mk
index dd9baae..dbda18f 100644
--- a/net/net.target.darwin-x86.mk
+++ b/net/net.target.darwin-x86.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -506,13 +509,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -601,13 +604,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.target.linux-arm.mk b/net/net.target.linux-arm.mk
index ffd2b46..04a09d1 100644
--- a/net/net.target.linux-arm.mk
+++ b/net/net.target.linux-arm.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -504,13 +507,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -597,13 +600,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.target.linux-mips.mk b/net/net.target.linux-mips.mk
index a86fb21..1e30736 100644
--- a/net/net.target.linux-mips.mk
+++ b/net/net.target.linux-mips.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -503,13 +506,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -595,13 +598,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net.target.linux-x86.mk b/net/net.target.linux-x86.mk
index dd9baae..dbda18f 100644
--- a/net/net.target.linux-x86.mk
+++ b/net/net.target.linux-x86.mk
@@ -115,6 +115,7 @@
 	net/cert/x509_certificate_net_log_param.cc \
 	net/cert/x509_certificate_openssl.cc \
 	net/cert/x509_util.cc \
+	net/cert/x509_util_android.cc \
 	net/cert/x509_util_openssl.cc \
 	net/cookies/canonical_cookie.cc \
 	net/cookies/cookie_constants.cc \
@@ -209,6 +210,7 @@
 	net/http/http_auth_handler_factory.cc \
 	net/http/http_auth_handler_ntlm.cc \
 	net/http/http_auth_handler_ntlm_portable.cc \
+	net/http/http_basic_state.cc \
 	net/http/http_basic_stream.cc \
 	net/http/http_byte_range.cc \
 	net/http/http_cache.cc \
@@ -313,22 +315,24 @@
 	net/quic/crypto/scoped_evp_cipher_ctx.cc \
 	net/quic/crypto/strike_register.cc \
 	net/quic/crypto/source_address_token.cc \
+	net/quic/iovector.cc \
 	net/quic/quic_ack_notifier.cc \
 	net/quic/quic_ack_notifier_manager.cc \
 	net/quic/quic_alarm.cc \
 	net/quic/quic_bandwidth.cc \
 	net/quic/quic_client_session.cc \
-	net/quic/quic_config.cc \
-	net/quic/quic_crypto_client_stream.cc \
-	net/quic/quic_crypto_server_stream.cc \
-	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_clock.cc \
+	net/quic/quic_config.cc \
 	net/quic/quic_connection.cc \
 	net/quic/quic_connection_helper.cc \
 	net/quic/quic_connection_logger.cc \
 	net/quic/quic_connection_stats.cc \
+	net/quic/quic_crypto_client_stream.cc \
+	net/quic/quic_crypto_server_stream.cc \
+	net/quic/quic_crypto_stream.cc \
 	net/quic/quic_data_reader.cc \
 	net/quic/quic_data_writer.cc \
+	net/quic/quic_default_packet_writer.cc \
 	net/quic/quic_fec_group.cc \
 	net/quic/quic_framer.cc \
 	net/quic/quic_http_stream.cc \
@@ -383,8 +387,6 @@
 	net/spdy/buffered_spdy_framer.cc \
 	net/spdy/spdy_buffer.cc \
 	net/spdy/spdy_buffer_producer.cc \
-	net/spdy/spdy_credential_builder.cc \
-	net/spdy/spdy_credential_state.cc \
 	net/spdy/spdy_frame_builder.cc \
 	net/spdy/spdy_frame_reader.cc \
 	net/spdy/spdy_framer.cc \
@@ -451,6 +453,7 @@
 	net/url_request/view_cache_helper.cc \
 	net/websockets/websocket_basic_stream.cc \
 	net/websockets/websocket_channel.cc \
+	net/websockets/websocket_deflate_predictor_impl.cc \
 	net/websockets/websocket_deflate_stream.cc \
 	net/websockets/websocket_deflater.cc \
 	net/websockets/websocket_errors.cc \
@@ -506,13 +509,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -601,13 +604,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.darwin-arm.mk b/net/net_errors_java.target.darwin-arm.mk
index 878f6a1..f5d24df 100644
--- a/net/net_errors_java.target.darwin-arm.mk
+++ b/net/net_errors_java.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.darwin-mips.mk b/net/net_errors_java.target.darwin-mips.mk
index 84bea1c..d4d4a06 100644
--- a/net/net_errors_java.target.darwin-mips.mk
+++ b/net/net_errors_java.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.darwin-x86.mk b/net/net_errors_java.target.darwin-x86.mk
index 1c1f2d2..56996e7 100644
--- a/net/net_errors_java.target.darwin-x86.mk
+++ b/net/net_errors_java.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.linux-arm.mk b/net/net_errors_java.target.linux-arm.mk
index 878f6a1..f5d24df 100644
--- a/net/net_errors_java.target.linux-arm.mk
+++ b/net/net_errors_java.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.linux-mips.mk b/net/net_errors_java.target.linux-mips.mk
index 84bea1c..d4d4a06 100644
--- a/net/net_errors_java.target.linux-mips.mk
+++ b/net/net_errors_java.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_errors_java.target.linux-x86.mk b/net/net_errors_java.target.linux-x86.mk
index 1c1f2d2..56996e7 100644
--- a/net/net_errors_java.target.linux-x86.mk
+++ b/net/net_errors_java.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.darwin-arm.mk b/net/net_jni_headers.target.darwin-arm.mk
index e283b2c..8c3e3b0 100644
--- a/net/net_jni_headers.target.darwin-arm.mk
+++ b/net/net_jni_headers.target.darwin-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -128,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -206,13 +218,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.darwin-mips.mk b/net/net_jni_headers.target.darwin-mips.mk
index aaa5dd3..e6748df 100644
--- a/net/net_jni_headers.target.darwin-mips.mk
+++ b/net/net_jni_headers.target.darwin-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -127,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -204,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.darwin-x86.mk b/net/net_jni_headers.target.darwin-x86.mk
index 5d821b2..54f9450 100644
--- a/net/net_jni_headers.target.darwin-x86.mk
+++ b/net/net_jni_headers.target.darwin-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -130,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.linux-arm.mk b/net/net_jni_headers.target.linux-arm.mk
index e283b2c..8c3e3b0 100644
--- a/net/net_jni_headers.target.linux-arm.mk
+++ b/net/net_jni_headers.target.linux-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -128,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -206,13 +218,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.linux-mips.mk b/net/net_jni_headers.target.linux-mips.mk
index aaa5dd3..e6748df 100644
--- a/net/net_jni_headers.target.linux-mips.mk
+++ b/net/net_jni_headers.target.linux-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -127,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -204,13 +216,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_jni_headers.target.linux-x86.mk b/net/net_jni_headers.target.linux-x86.mk
index 5d821b2..54f9450 100644
--- a/net/net_jni_headers.target.linux-x86.mk
+++ b/net/net_jni_headers.target.linux-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "net_net_gyp_net_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/net/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/NetworkChangeNotifier.java', 'android/java/src/org/chromium/net/ProxyChangeListener.java', 'android/java/src/org/chromium/net/X509Util.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/net/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/net/jni/AndroidKeyStore_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: net_net_jni_headers_gyp_rule_trigger
 net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
 
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h: $(LOCAL_PATH)/net/android/java/src/org/chromium/net/X509Util.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/net/jni; cd $(gyp_local_path)/net; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/net/X509Util.java --output_dir "$(gyp_shared_intermediate_dir)/net/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: net_net_jni_headers_gyp_rule_trigger
+net_net_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
+
 ### Finished generating for all rules
 
 GYP_GENERATED_OUTPUTS := \
@@ -73,7 +83,8 @@
 	$(gyp_shared_intermediate_dir)/net/jni/AndroidNetworkLibrary_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
-	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h
+	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
@@ -84,6 +95,7 @@
 	$(gyp_shared_intermediate_dir)/net/jni/GURLUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/NetworkChangeNotifier_jni.h \
 	$(gyp_shared_intermediate_dir)/net/jni/ProxyChangeListener_jni.h \
+	$(gyp_shared_intermediate_dir)/net/jni/X509Util_jni.h \
 	net_net_jni_headers_gyp_rule_trigger
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
@@ -130,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/net_unittests.isolate b/net/net_unittests.isolate
index 61b8c47..2d120bf 100644
--- a/net/net_unittests.isolate
+++ b/net/net_unittests.isolate
@@ -20,8 +20,8 @@
       'variables': {
         'command': [
           '../testing/test_env.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/net_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
         ],
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
diff --git a/net/private_key_types_java.target.darwin-arm.mk b/net/private_key_types_java.target.darwin-arm.mk
index 85266e4..bb81760 100644
--- a/net/private_key_types_java.target.darwin-arm.mk
+++ b/net/private_key_types_java.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/private_key_types_java.target.darwin-mips.mk b/net/private_key_types_java.target.darwin-mips.mk
index dcb2883..c4be7e6 100644
--- a/net/private_key_types_java.target.darwin-mips.mk
+++ b/net/private_key_types_java.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/private_key_types_java.target.darwin-x86.mk b/net/private_key_types_java.target.darwin-x86.mk
index 83cd490f..1bff853 100644
--- a/net/private_key_types_java.target.darwin-x86.mk
+++ b/net/private_key_types_java.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/private_key_types_java.target.linux-arm.mk b/net/private_key_types_java.target.linux-arm.mk
index 85266e4..bb81760 100644
--- a/net/private_key_types_java.target.linux-arm.mk
+++ b/net/private_key_types_java.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/private_key_types_java.target.linux-mips.mk b/net/private_key_types_java.target.linux-mips.mk
index dcb2883..c4be7e6 100644
--- a/net/private_key_types_java.target.linux-mips.mk
+++ b/net/private_key_types_java.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/private_key_types_java.target.linux-x86.mk b/net/private_key_types_java.target.linux-x86.mk
index 83cd490f..1bff853 100644
--- a/net/private_key_types_java.target.linux-x86.mk
+++ b/net/private_key_types_java.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc
index 41bef8a..23a4206 100644
--- a/net/proxy/proxy_config_service_android.cc
+++ b/net/proxy/proxy_config_service_android.cc
@@ -18,6 +18,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "jni/ProxyChangeListener_jni.h"
 #include "net/base/host_port_pair.h"
 #include "net/proxy/proxy_config.h"
@@ -159,6 +160,16 @@
       std::string() : ConvertJavaStringToUTF8(env, result.obj());
 }
 
+void CreateStaticProxyConfig(const std::string& host, int port,
+                             ProxyConfig* config) {
+  if (port != 0) {
+    std::string rules = base::StringPrintf("%s:%d", host.c_str(), port);
+    config->proxy_rules().ParseFromString(rules);
+  } else {
+    *config = ProxyConfig::CreateDirect();
+  }
+}
+
 }  // namespace
 
 class ProxyConfigServiceAndroid::Delegate
@@ -237,6 +248,17 @@
             &Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
   }
 
+  // Called on the JNI thread.
+  void ProxySettingsChangedTo(const std::string& host, int port) {
+    DCHECK(OnJNIThread());
+    ProxyConfig proxy_config;
+    CreateStaticProxyConfig(host, port, &proxy_config);
+    network_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
+  }
+
  private:
   friend class base::RefCountedThreadSafe<Delegate>;
 
@@ -245,7 +267,13 @@
     explicit JNIDelegateImpl(Delegate* delegate) : delegate_(delegate) {}
 
     // ProxyConfigServiceAndroid::JNIDelegate overrides.
-    virtual void ProxySettingsChanged(JNIEnv*, jobject) OVERRIDE {
+    virtual void ProxySettingsChangedTo(JNIEnv* env, jobject jself,
+                                      jstring jhost, jint jport) OVERRIDE {
+      std::string host = ConvertJavaStringToUTF8(env, jhost);
+      delegate_->ProxySettingsChangedTo(host, jport);
+    }
+
+    virtual void ProxySettingsChanged(JNIEnv* env, jobject self) OVERRIDE {
       delegate_->ProxySettingsChanged();
     }
 
diff --git a/net/proxy/proxy_config_service_android.h b/net/proxy/proxy_config_service_android.h
index 3ddbaeb..949ec42 100644
--- a/net/proxy/proxy_config_service_android.h
+++ b/net/proxy/proxy_config_service_android.h
@@ -39,7 +39,12 @@
     virtual ~JNIDelegate() {}
 
     // Called from Java (on JNI thread) to signal that the proxy settings have
-    // changed.
+    // changed. The string and int arguments (the host/port pair for the proxy)
+    // are either a host/port pair or ("", 0) to indicate "no proxy".
+    virtual void ProxySettingsChangedTo(JNIEnv*, jobject, jstring, jint) = 0;
+
+    // Called from Java (on JNI thread) to signal that the proxy settings have
+    // changed. New proxy settings are fetched from the system property store.
     virtual void ProxySettingsChanged(JNIEnv*, jobject) = 0;
   };
 
diff --git a/net/proxy/proxy_list.cc b/net/proxy/proxy_list.cc
index baa638f..bd7cbfb 100644
--- a/net/proxy/proxy_list.cc
+++ b/net/proxy/proxy_list.cc
@@ -185,23 +185,27 @@
     NOTREACHED();
     return false;
   }
-  UpdateRetryInfoOnFallback(proxy_retry_info, net_log);
+  UpdateRetryInfoOnFallback(proxy_retry_info, base::TimeDelta(), net_log);
 
   // Remove this proxy from our list.
   proxies_.erase(proxies_.begin());
   return !proxies_.empty();
 }
 
-void ProxyList::UpdateRetryInfoOnFallback(
-    ProxyRetryInfoMap* proxy_retry_info, const BoundNetLog& net_log) const {
+void ProxyList::UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
+                                          base::TimeDelta retry_delay,
+                                          const BoundNetLog& net_log) const {
   // Time to wait before retrying a bad proxy server.
-#if defined(OS_ANDROID) || defined(OS_IOS)
-  // Randomize the timeout over a range from one to five minutes.
-  const TimeDelta proxy_retry_delay =
-      TimeDelta::FromMilliseconds(base::RandInt(1 * 60 * 1000, 5 * 60 * 1000));
+  if (retry_delay == base::TimeDelta()) {
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+    // Randomize the timeout over a range from one to five minutes.
+    retry_delay =
+        TimeDelta::FromMilliseconds(
+            base::RandInt(1 * 60 * 1000, 5 * 60 * 1000));
 #else
-  const TimeDelta proxy_retry_delay = TimeDelta::FromMinutes(5);
+    retry_delay = TimeDelta::FromMinutes(5);
 #endif
+  }
 
   if (proxies_.empty()) {
     NOTREACHED();
@@ -218,7 +222,7 @@
       iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay;
     } else {
       ProxyRetryInfo retry_info;
-      retry_info.current_delay = proxy_retry_delay;
+      retry_info.current_delay = retry_delay;
       retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay;
       (*proxy_retry_info)[key] = retry_info;
     }
diff --git a/net/proxy/proxy_list.h b/net/proxy/proxy_list.h
index 9f5fa59..33a78a8 100644
--- a/net/proxy/proxy_list.h
+++ b/net/proxy/proxy_list.h
@@ -14,6 +14,7 @@
 
 namespace base {
 class ListValue;
+class TimeDelta;
 }
 
 namespace net {
@@ -89,8 +90,11 @@
 
   // Updates |proxy_retry_info| to indicate that the first proxy in the list
   // is bad. This is distinct from Fallback(), above, to allow updating proxy
-  // retry information without modifying a given transction's proxy list.
+  // retry information without modifying a given transction's proxy list. Will
+  // retry after |retry_delay| if positive, and will use the default proxy retry
+  // duration otherwise.
   void UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
+                                 base::TimeDelta retry_delay,
                                  const BoundNetLog& net_log) const;
 
  private:
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index e3b13e3..4f9c8be 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -1179,8 +1179,10 @@
 }
 
 bool ProxyService::MarkProxyAsBad(const ProxyInfo& result,
+                                  base::TimeDelta retry_delay,
                                   const BoundNetLog& net_log) {
-  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, net_log);
+  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
+                                               net_log);
   return result.proxy_list_.HasUntriedProxies(proxy_retry_info_);
 }
 
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index 6639911..7e4e306 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -27,6 +27,7 @@
 namespace base {
 class MessageLoop;
 class SingleThreadTaskRunner;
+class TimeDelta;
 }  // namespace base
 
 namespace net {
@@ -147,10 +148,13 @@
                                 const BoundNetLog& net_log);
 
   // Explicitly trigger proxy fallback for the given |results| by updating our
-  // list of bad proxies to include the first entry of |results|. Returns true
-  // if there will be at least one proxy remaining in the list after fallback
-  // and false otherwise.
-  bool MarkProxyAsBad(const ProxyInfo& results, const BoundNetLog& net_log);
+  // list of bad proxies to include the first entry of |results|. Will retry
+  // after |retry_delay| if positive, and will use the default proxy retry
+  // duration otherwise. Returns true if there will be at least one proxy
+  // remaining in the list after fallback and false otherwise.
+  bool MarkProxyAsBad(const ProxyInfo& results,
+                      base::TimeDelta retry_delay,
+                      const BoundNetLog& net_log);
 
   // Called to report that the last proxy connection succeeded.  If |proxy_info|
   // has a non empty proxy_retry_info map, the proxies that have been tried (and
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 082264d..05fcb35 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -123,4 +123,11 @@
   return latest_rtt_.Add(latest_rtt_);
 }
 
+QuicByteCount FixRateSender::GetCongestionWindow() {
+  return 0;
+}
+
+void FixRateSender::SetCongestionWindow(QuicByteCount window) {
+}
+
 }  // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index b14e4d5..bbbee68 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -48,6 +48,8 @@
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
   virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
+  virtual QuicByteCount GetCongestionWindow() OVERRIDE;
+  virtual void SetCongestionWindow(QuicByteCount window) OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc
index 4ec40fb..2740f1e 100644
--- a/net/quic/congestion_control/inter_arrival_sender.cc
+++ b/net/quic/congestion_control/inter_arrival_sender.cc
@@ -324,6 +324,13 @@
   return smoothed_rtt_.Add(smoothed_rtt_);
 }
 
+QuicByteCount InterArrivalSender::GetCongestionWindow() {
+  return 0;
+}
+
+void InterArrivalSender::SetCongestionWindow(QuicByteCount window) {
+}
+
 void InterArrivalSender::EstimateNewBandwidth(QuicTime feedback_receive_time,
                                               QuicBandwidth sent_bandwidth) {
   QuicBandwidth new_bandwidth = bitrate_ramp_up_->GetNewBitrate(sent_bandwidth);
diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h
index 606956b..3961a2b 100644
--- a/net/quic/congestion_control/inter_arrival_sender.h
+++ b/net/quic/congestion_control/inter_arrival_sender.h
@@ -62,6 +62,8 @@
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
   virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
+  virtual QuicByteCount GetCongestionWindow() OVERRIDE;
+  virtual void SetCongestionWindow(QuicByteCount window) OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index c288a5c..ed133fc 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -215,6 +215,14 @@
   return send_algorithm_->BandwidthEstimate();
 }
 
+QuicByteCount QuicCongestionManager::GetCongestionWindow() {
+  return send_algorithm_->GetCongestionWindow();
+}
+
+void QuicCongestionManager::SetCongestionWindow(QuicByteCount window) {
+  send_algorithm_->SetCongestionWindow(window);
+}
+
 void QuicCongestionManager::CleanupPacketHistory() {
   const QuicTime::Delta kHistoryPeriod =
       QuicTime::Delta::FromMilliseconds(kHistoryPeriodMs);
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index d574e51..6d15719 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -95,6 +95,14 @@
   // Returns the estimated bandwidth calculated by the congestion algorithm.
   QuicBandwidth BandwidthEstimate();
 
+  // Returns the size of the current congestion window.  Note, this
+  // is not the *available* window.  Some send algorithms may not use a
+  // congestion window and will return 0.
+  QuicByteCount GetCongestionWindow();
+
+  // Sets the value of the current congestion window to |window|.
+  void SetCongestionWindow(QuicByteCount window);
+
  private:
   friend class test::QuicConnectionPeer;
   friend class test::QuicCongestionManagerPeer;
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index b0b4cac..8ff3961 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -87,6 +87,14 @@
   // Note 1: the caller is responsible for sanity checking this value.
   // Note 2: this will return zero if we don't have enough data for an estimate.
   virtual QuicTime::Delta RetransmissionDelay() = 0;
+
+  // Returns the size of the current congestion window.  Note, this
+  // is not the *available* window.  Some send algorithms may not use a
+  // congestion window and will return 0.
+  virtual QuicByteCount GetCongestionWindow() = 0;
+
+  // Sets the value of the current congestion window to |window|.
+  virtual void SetCongestionWindow(QuicByteCount window) = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 36164b1..0a7a897 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -12,8 +12,10 @@
 
 namespace {
 // Constants based on TCP defaults.
+//TODO(rch): set to 2.
+const QuicTcpCongestionWindow kMinimumCongestionWindow = 1;
 const int64 kHybridStartLowWindow = 16;
-const QuicByteCount kMaxSegmentSize = kMaxPacketSize;
+const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
 const QuicByteCount kDefaultReceiveWindow = 64000;
 const int64 kInitialCongestionWindow = 10;
 const int kMaxBurstLength = 3;
@@ -94,7 +96,7 @@
   }
   // Sanity, make sure that we don't end up with an empty window.
   if (congestion_window_ == 0) {
-    congestion_window_ = 1;
+    congestion_window_ = kMinimumCongestionWindow;
   }
   DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_;
 }
@@ -155,8 +157,7 @@
 
 QuicByteCount TcpCubicSender::SendWindow() {
   // What's the current send window in bytes.
-  return std::min(receive_window_,
-                  congestion_window_ * kMaxSegmentSize);
+  return std::min(receive_window_, GetCongestionWindow());
 }
 
 QuicBandwidth TcpCubicSender::BandwidthEstimate() {
@@ -178,6 +179,17 @@
       smoothed_rtt_.ToMicroseconds() + 4 * mean_deviation_.ToMicroseconds());
 }
 
+QuicByteCount TcpCubicSender::GetCongestionWindow() {
+  return congestion_window_ * kMaxSegmentSize;
+}
+
+void TcpCubicSender::SetCongestionWindow(QuicByteCount window) {
+  congestion_window_ = window / kMaxSegmentSize;
+  if (congestion_window_ < kMinimumCongestionWindow) {
+    congestion_window_ = kMinimumCongestionWindow;
+  }
+}
+
 void TcpCubicSender::Reset() {
   delay_min_ = QuicTime::Delta::Zero();
   hybrid_slow_start_.Restart();
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 603c73f..cf5f2ff 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -20,6 +20,9 @@
 
 namespace net {
 
+// Default maximum packet size used in Linux TCP implementations.
+const QuicByteCount kDefaultTCPMSS = 1460;
+
 namespace test {
 class TcpCubicSenderPeer;
 }  // namespace test
@@ -57,6 +60,8 @@
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
   virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
+  virtual QuicByteCount GetCongestionWindow() OVERRIDE;
+  virtual void SetCongestionWindow(QuicByteCount window) OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index f8013bc..15845cd 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -12,7 +12,7 @@
 namespace net {
 namespace test {
 
-const uint32 kDefaultWindowTCP = 10 * kMaxPacketSize;
+const uint32 kDefaultWindowTCP = 10 * kDefaultTCPMSS;
 // TODO(ianswett): Remove 10000 once b/10075719 is fixed.
 const QuicTcpCongestionWindow kDefaultMaxCongestionWindowTCP = 10000;
 
@@ -43,7 +43,7 @@
   void SendAvailableSendWindow() {
     QuicByteCount bytes_to_send = sender_->AvailableSendWindow();
     while (bytes_to_send > 0) {
-      QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send);
+      QuicByteCount bytes_in_packet = std::min(kDefaultTCPMSS, bytes_to_send);
       sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
                             NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
       bytes_to_send -= bytes_in_packet;
@@ -57,7 +57,7 @@
   void AckNPackets(int n) {
     for (int i = 0; i < n; ++i) {
       acked_sequence_number_++;
-      sender_->OnIncomingAck(acked_sequence_number_, kMaxPacketSize, rtt_);
+      sender_->OnIncomingAck(acked_sequence_number_, kDefaultTCPMSS, rtt_);
     }
     clock_.AdvanceTime(one_ms_);  // 1 millisecond.
   }
@@ -75,8 +75,8 @@
 TEST_F(TcpCubicSenderTest, SimpleSender) {
   QuicCongestionFeedbackFrame feedback;
   // At startup make sure we are at the default.
-  EXPECT_EQ(kDefaultWindowTCP,
-            sender_->AvailableSendWindow());
+  EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
+  EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
   // At startup make sure we can send.
   EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
       NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
@@ -89,6 +89,7 @@
       NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
   // And that window is un-affected.
   EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
+  EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
 
   // A retransmit should always return 0.
   EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
@@ -115,7 +116,7 @@
     AckNPackets(2);
   }
   QuicByteCount bytes_to_send = sender_->SendWindow();
-  EXPECT_EQ(kDefaultWindowTCP + kMaxPacketSize * 2 * kNumberOfAck,
+  EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAck,
             bytes_to_send);
 }
 
@@ -144,12 +145,13 @@
     AckNPackets(2);
   }
   QuicByteCount expected_send_window =
-      kDefaultWindowTCP + (kMaxPacketSize * 2 * kNumberOfAck);
+      kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAck);
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
+  EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
   // We should now have fallen out of slow start.
   SendAvailableSendWindow();
   AckNPackets(2);
-  expected_send_window += kMaxPacketSize;
+  expected_send_window += kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 
   // Testing Reno phase.
@@ -162,7 +164,7 @@
   }
   SendAvailableSendWindow();
   AckNPackets(2);
-  expected_send_window += kMaxPacketSize;
+  expected_send_window += kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 }
 
@@ -188,7 +190,7 @@
   }
   SendAvailableSendWindow();
   QuicByteCount expected_send_window = kDefaultWindowTCP +
-      (kMaxPacketSize * 2 * kNumberOfAck);
+      (kDefaultTCPMSS * 2 * kNumberOfAck);
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 
   sender_->OnIncomingLoss(clock_.Now());
@@ -204,13 +206,13 @@
 
   // Testing Reno phase.
   // We need to ack half of the pending packet before we can send again.
-  int number_of_packets_in_window = expected_send_window / kMaxPacketSize;
+  int number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
   AckNPackets(number_of_packets_in_window);
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
   EXPECT_EQ(0u, sender_->AvailableSendWindow());
 
   AckNPackets(1);
-  expected_send_window += kMaxPacketSize;
+  expected_send_window += kDefaultTCPMSS;
   number_of_packets_in_window++;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 
@@ -223,7 +225,7 @@
   }
   SendAvailableSendWindow();
   AckNPackets(1);
-  expected_send_window += kMaxPacketSize;
+  expected_send_window += kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 }
 
@@ -280,7 +282,7 @@
     AckNPackets(2);
   }
   QuicByteCount expected_send_window =
-      kMaxCongestionWindowTCP * kMaxPacketSize;
+      kMaxCongestionWindowTCP * kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 }
 
@@ -314,7 +316,7 @@
   }
 
   QuicByteCount expected_send_window =
-      kMaxCongestionWindowTCP * kMaxPacketSize;
+      kMaxCongestionWindowTCP * kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 }
 
@@ -348,7 +350,7 @@
   }
 
   QuicByteCount expected_send_window =
-      kMaxCongestionWindowTCP * kMaxPacketSize;
+      kMaxCongestionWindowTCP * kDefaultTCPMSS;
   EXPECT_EQ(expected_send_window, sender_->SendWindow());
 }
 
@@ -357,7 +359,7 @@
 
   // Send a packet with no retransmittable data, and ensure that the congestion
   // window doesn't change.
-  QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, send_window);
+  QuicByteCount bytes_in_packet = std::min(kDefaultTCPMSS, send_window);
   sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
                         NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
   EXPECT_EQ(send_window, sender_->AvailableSendWindow());
diff --git a/net/quic/congestion_control/tcp_receiver.cc b/net/quic/congestion_control/tcp_receiver.cc
index 465e40f..ecff130 100644
--- a/net/quic/congestion_control/tcp_receiver.cc
+++ b/net/quic/congestion_control/tcp_receiver.cc
@@ -7,8 +7,9 @@
 
 namespace net {
 
+// static
 // Originally 64K bytes for TCP, setting it to 256K to support higher bitrates.
-const QuicByteCount kReceiveWindowTCP = 256000;
+const QuicByteCount TcpReceiver::kReceiveWindowTCP = 256000;
 
 TcpReceiver::TcpReceiver()
     : accumulated_number_of_recoverd_lost_packets_(0),
diff --git a/net/quic/congestion_control/tcp_receiver.h b/net/quic/congestion_control/tcp_receiver.h
index 695ffbb..99cf93c 100644
--- a/net/quic/congestion_control/tcp_receiver.h
+++ b/net/quic/congestion_control/tcp_receiver.h
@@ -20,6 +20,9 @@
  public:
   TcpReceiver();
 
+  // Size of the (currently fixed) receive window.
+  static const QuicByteCount kReceiveWindowTCP;
+
   // Start implementation of SendAlgorithmInterface.
   virtual bool GenerateCongestionFeedback(
       QuicCongestionFeedbackFrame* feedback) OVERRIDE;
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h
index abea8ac..a2d1dc9 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter.h
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h
@@ -36,9 +36,6 @@
   Aes128Gcm12Encrypter();
   virtual ~Aes128Gcm12Encrypter();
 
-  // Returns true if the underlying crypto library supports AES GCM.
-  static bool IsSupported();
-
   // QuicEncrypter implementation
   virtual bool SetKey(base::StringPiece key) OVERRIDE;
   virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE;
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
index ae6adab..e100ede 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
@@ -256,14 +256,6 @@
 
 Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
 
-// static
-bool Aes128Gcm12Encrypter::IsSupported() {
-  // NSS 3.15 supports CKM_AES_GCM directly.
-  // NSS 3.14 supports CKM_AES_CTR, which can be used to emulate CKM_AES_GCM.
-  // Versions earlier than NSS 3.14 are not supported.
-  return NSS_VersionCheck("3.14") != PR_FALSE;
-}
-
 bool Aes128Gcm12Encrypter::SetKey(StringPiece key) {
   DCHECK_EQ(key.size(), sizeof(key_));
   if (key.size() != sizeof(key_)) {
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
index 166fd55..cc9bf35 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
@@ -25,9 +25,6 @@
 
 Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
 
-// static
-bool Aes128Gcm12Encrypter::IsSupported() { return true; }
-
 bool Aes128Gcm12Encrypter::SetKey(StringPiece key) {
   DCHECK_EQ(key.size(), sizeof(key_));
   if (key.size() != sizeof(key_)) {
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
index 0c9928b..bb641d6 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -261,11 +261,6 @@
 }
 
 TEST(Aes128Gcm12EncrypterTest, Encrypt) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   char key[1024];
   size_t key_len;
   char iv[1024];
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index 21553ab..0f3bb78 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -943,6 +943,9 @@
     QuicCryptoClientConfig* canonical_crypto_config) {
   CachedState* canonical_cached =
       canonical_crypto_config->LookupOrCreate(canonical_server_hostname);
+  if (!canonical_cached->proof_valid()) {
+    return;
+  }
   CachedState* cached = LookupOrCreate(server_hostname);
   cached->InitializeFrom(*canonical_cached);
 }
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index 1a344f6..4fefba5 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -394,7 +394,8 @@
 
   // Initialize the CachedState from |canonical_crypto_config| for the
   // |canonical_server_hostname| as the initial CachedState for
-  // |server_hostname|.
+  // |server_hostname|. We will copy config data only if
+  // |canonical_crypto_config| has valid proof.
   void InitializeFrom(const std::string& server_hostname,
                       const std::string& canonical_server_hostname,
                       QuicCryptoClientConfig* canonical_crypto_config);
diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc
index 3ad50bb..dcde964 100644
--- a/net/quic/crypto/crypto_handshake_test.cc
+++ b/net/quic/crypto/crypto_handshake_test.cc
@@ -155,11 +155,6 @@
 }
 
 TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   QuicRandom* rand = QuicRandom::GetInstance();
   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
   IPAddressNumber ip;
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index 4ff51c4..7fb4fa9 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -98,15 +98,6 @@
       Curve25519KeyExchange::New(curve25519_private_key));
   StringPiece curve25519_public_value = curve25519->public_value();
 
-  string p256_private_key;
-  StringPiece p256_public_value;
-  scoped_ptr<P256KeyExchange> p256;
-  if (options.p256) {
-    p256_private_key = P256KeyExchange::NewPrivateKey();
-    p256.reset(P256KeyExchange::New(p256_private_key));
-    p256_public_value = p256->public_value();
-  }
-
   string encoded_public_values;
   // First three bytes encode the length of the public value.
   encoded_public_values.push_back(curve25519_public_value.size());
@@ -114,11 +105,19 @@
   encoded_public_values.push_back(curve25519_public_value.size() >> 16);
   encoded_public_values.append(curve25519_public_value.data(),
                                curve25519_public_value.size());
-  encoded_public_values.push_back(p256_public_value.size());
-  encoded_public_values.push_back(p256_public_value.size() >> 8);
-  encoded_public_values.push_back(p256_public_value.size() >> 16);
-  encoded_public_values.append(p256_public_value.data(),
-                               p256_public_value.size());
+
+  string p256_private_key;
+  if (options.p256) {
+    p256_private_key = P256KeyExchange::NewPrivateKey();
+    scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key));
+    StringPiece p256_public_value = p256->public_value();
+
+    encoded_public_values.push_back(p256_public_value.size());
+    encoded_public_values.push_back(p256_public_value.size() >> 8);
+    encoded_public_values.push_back(p256_public_value.size() >> 16);
+    encoded_public_values.append(p256_public_value.data(),
+                                 p256_public_value.size());
+  }
 
   msg.set_tag(kSCFG);
   if (options.p256) {
@@ -140,14 +139,6 @@
     msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
   }
 
-  if (options.id.empty()) {
-    char scid_bytes[16];
-    rand->RandBytes(scid_bytes, sizeof(scid_bytes));
-    msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
-  } else {
-    msg.SetStringPiece(kSCID, options.id);
-  }
-
   char orbit_bytes[kOrbitSize];
   if (options.orbit.size() == sizeof(orbit_bytes)) {
     memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
@@ -161,6 +152,24 @@
     msg.SetTaglist(kPDMD, kCHID, 0);
   }
 
+  if (options.id.empty()) {
+    // We need to ensure that the SCID changes whenever the server config does
+    // thus we make it a hash of the rest of the server config.
+    scoped_ptr<QuicData> serialized(
+        CryptoFramer::ConstructHandshakeMessage(msg));
+    scoped_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256));
+    hash->Update(serialized->data(), serialized->length());
+
+    char scid_bytes[16];
+    hash->Finish(scid_bytes, sizeof(scid_bytes));
+    msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
+  } else {
+    msg.SetStringPiece(kSCID, options.id);
+  }
+  // Don't put new tags below this point. The SCID generation should hash over
+  // everything but itself and so extra tags should be added prior to the
+  // preceeding if block.
+
   scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg));
 
   scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf);
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc
index 348b31a..258afd5 100644
--- a/net/quic/crypto/crypto_server_test.cc
+++ b/net/quic/crypto/crypto_server_test.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/strings/string_number_conversions.h"
+#include "crypto/secure_hash.h"
 #include "net/quic/crypto/crypto_server_config.h"
 #include "net/quic/crypto/crypto_utils.h"
 #include "net/quic/crypto/quic_random.h"
@@ -258,6 +259,58 @@
   ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
 }
 
+TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
+  // This test ensures that the server config ID varies for different server
+  // configs.
+
+  MockRandom rand_a, rand_b;
+  const QuicCryptoServerConfig::ConfigOptions options;
+  MockClock clock;
+
+  QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
+  rand_b.ChangeValue();
+  QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b);
+  scoped_ptr<CryptoHandshakeMessage> scfg_a(
+      a.AddDefaultConfig(&rand_a, &clock, options));
+  scoped_ptr<CryptoHandshakeMessage> scfg_b(
+      b.AddDefaultConfig(&rand_b, &clock, options));
+
+  StringPiece scid_a, scid_b;
+  EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
+  EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
+
+  EXPECT_NE(scid_a, scid_b);
+}
+
+
+TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
+  MockRandom rand_a;
+  const QuicCryptoServerConfig::ConfigOptions options;
+  MockClock clock;
+
+  QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a);
+  scoped_ptr<CryptoHandshakeMessage> scfg(
+      a.AddDefaultConfig(&rand_a, &clock, options));
+
+  StringPiece scid;
+  EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
+  // Need to take a copy of |scid| has we're about to call |Erase|.
+  const string scid_str(scid.as_string());
+
+  scfg->Erase(kSCID);
+  scfg->MarkDirty();
+  const QuicData& serialized(scfg->GetSerialized());
+
+  scoped_ptr<crypto::SecureHash> hash(
+      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  hash->Update(serialized.data(), serialized.length());
+  uint8 digest[16];
+  hash->Finish(digest, sizeof(digest));
+
+  ASSERT_EQ(scid.size(), sizeof(digest));
+  EXPECT_TRUE(0 == memcmp(digest, scid_str.data(), sizeof(digest)));
+}
+
 class CryptoServerTestNoConfig : public CryptoServerTest {
  public:
   virtual void SetUp() {
diff --git a/net/quic/iovector.cc b/net/quic/iovector.cc
new file mode 100644
index 0000000..a6d2c61
--- /dev/null
+++ b/net/quic/iovector.cc
@@ -0,0 +1,13 @@
+// Copyright 2013 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 "net/quic/iovector.h"
+
+namespace net {
+
+IOVector::IOVector() {}
+
+IOVector::~IOVector() {}
+
+}  // namespace net
diff --git a/net/quic/iovector.h b/net/quic/iovector.h
new file mode 100644
index 0000000..74fcbef
--- /dev/null
+++ b/net/quic/iovector.h
@@ -0,0 +1,201 @@
+// Copyright 2013 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 NET_QUIC_IOVECTOR_H_
+#define NET_QUIC_IOVECTOR_H_
+
+#include <stddef.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "net/base/iovec.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// Calculate the total number of bytes in an array of iovec structures.
+inline size_t TotalIovecLength(const struct iovec* iov, size_t iovcnt) {
+  size_t length = 0;
+  if (iov != NULL) {
+    for (size_t i = 0; i < iovcnt; ++i) {
+      length += iov[i].iov_len;
+    }
+  }
+  return length;
+}
+
+// IOVector is a helper class that makes it easier to work with POSIX vector I/O
+// struct. It is a thin wrapper by design and thus has no virtual functions and
+// all inlined methods. This class makes no assumptions about the ordering of
+// the pointer values of the blocks appended, it simply counts bytes when asked
+// to consume bytes.
+//
+// IOVector is a bookkeeping object that collects a description of buffers to
+// be read or written together and in order. It does not take ownership of the
+// blocks appended.
+//
+// Because it is used for scatter-gather operations, the order in which the
+// buffer blocks are added to the IOVector is important to the client. The
+// intended usage pattern is:
+//
+//   iovector.Append(p0, len0);
+//   ...
+//   iovector.Append(pn, lenn);
+//   int bytes_written = writev(fd, iovector.iovec(), iovector.Size());
+//   if (bytes_written > 0)
+//     iovector.Consume(bytes_written);
+//
+// The sequence is the same for readv, except that Consume() in this case is
+// used to change the IOVector to only keep track of description of blocks of
+// memory not yet written to.
+//
+// IOVector does not have any method to change the iovec entries that it
+// accumulates. This is due to the block merging nature of Append(): we'd like
+// to avoid accidentally change an entry that is assembled by two or more
+// Append()'s by simply an index access.
+//
+
+class NET_EXPORT_PRIVATE IOVector {
+ public:
+  // Provide a default constructor so it'll never be inhibited by adding other
+  // constructors.
+  IOVector();
+  ~IOVector();
+
+  // Provides a way to convert system call-like iovec representation to
+  // IOVector.
+  void AppendIovec(const struct iovec* iov, size_t iovcnt) {
+    for (size_t i = 0; i < iovcnt; ++i)
+      Append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+  }
+
+  // Appends at most max_bytes from iovec to the IOVector.
+  size_t AppendIovecAtMostBytes(const struct iovec* iov,
+                                size_t iovcnt,
+                                size_t max_bytes) {
+    size_t bytes_appended = 0;
+    for (size_t i = 0; i < iovcnt && max_bytes > 0; ++i) {
+      const size_t length = std::min(max_bytes, iov[i].iov_len);
+      Append(static_cast<char*>(iov[i].iov_base), length);
+      max_bytes -= length;
+      bytes_appended += length;
+    }
+    return bytes_appended;
+  }
+
+  // Append another block to the IOVector. Since IOVector can be used for read
+  // and write, it always takes char*. Clients that writes will need to cast
+  // away the constant of the pointer before appending a block.
+  void Append(char* buffer, size_t length) {
+    if (buffer != NULL && length > 0) {
+      if (iovec_.size() > 0) {
+        struct iovec& last = iovec_.back();
+        // If the new block is contiguous with the last block, just extend.
+        if (static_cast<char*>(last.iov_base) + last.iov_len == buffer) {
+          last.iov_len += length;
+          return;
+        }
+      }
+      struct iovec tmp = {buffer, length};
+      iovec_.push_back(tmp);
+    }
+  }
+
+  // Same as Append, but doesn't do the tail merge optimization.
+  // Intended for testing.
+  void AppendNoCoalesce(char* buffer, size_t length) {
+    if (buffer != NULL && length > 0) {
+      struct iovec tmp = {buffer, length};
+      iovec_.push_back(tmp);
+    }
+  }
+
+  // Remove a number of bytes from the beginning of the IOVector. Since vector
+  // I/O operations always occur at the beginning of the block list, a method
+  // to remove bytes at the end is not provided.
+  // It returns the number of bytes actually consumed (it'll only be smaller
+  // than the requested number if the IOVector contains less data).
+  size_t Consume(size_t length) {
+    if (length == 0) return 0;
+
+    size_t bytes_to_consume = length;
+    std::vector<struct iovec>::iterator iter = iovec_.begin();
+    std::vector<struct iovec>::iterator end = iovec_.end();
+    for (; iter < end && bytes_to_consume >= iter->iov_len; ++iter) {
+      bytes_to_consume -= iter->iov_len;
+    }
+    iovec_.erase(iovec_.begin(), iter);
+    if (iovec_.size() > 0 && bytes_to_consume != 0) {
+      iovec_[0].iov_base =
+          static_cast<char*>(iovec_[0].iov_base) + bytes_to_consume;
+      iovec_[0].iov_len -= bytes_to_consume;
+      return length;
+    }
+    if (iovec_.size() == 0 && bytes_to_consume > 0) {
+      LOG(DFATAL) << "Attempting to consume " << bytes_to_consume
+                  << " non-existent bytes.";
+    }
+    // At this point bytes_to_consume is the number of wanted bytes left over
+    // after walking through all the iovec entries.
+    return length - bytes_to_consume;
+  }
+
+  // TODO(joechan): If capacity is large, swap out for a blank one.
+  // Clears the IOVector object to contain no blocks.
+  void Clear() { iovec_.clear(); }
+
+  // Swap the guts of two IOVector.
+  void Swap(IOVector* other) { iovec_.swap(other->iovec_); }
+
+  // Returns the number of valid blocks in the IOVector (not the number of
+  // bytes).
+  size_t Size() const { return iovec_.size(); }
+
+  // Returns the total storage used by the IOVector in number of blocks (not
+  // the number of bytes).
+  size_t Capacity() const { return iovec_.capacity(); }
+
+  // Returns true if there are no blocks in the IOVector.
+  bool Empty() const { return iovec_.empty(); }
+
+  // Returns the pointer to the beginning of the iovec to be used for vector
+  // I/O operations. If the IOVector has no blocks appened, this function
+  // returns NULL.
+  struct iovec* iovec() { return !Empty() ? &iovec_[0] : NULL; }
+
+  // Const version.
+  const struct iovec* iovec() const { return !Empty() ? &iovec_[0] : NULL; }
+
+  // Returns a pointer to one past the last byte of the last block. If the
+  // IOVector is empty, NULL is returned.
+  const char* LastBlockEnd() const {
+    return iovec_.size() > 0 ?
+        static_cast<char *>(iovec_.back().iov_base) + iovec_.back().iov_len :
+        NULL;
+  }
+
+  // Returns the total number of bytes in the IOVector.
+  size_t TotalBufferSize() const { return TotalIovecLength(iovec(), Size()); }
+
+  void Resize(size_t count) {
+    iovec_.resize(count);
+  }
+
+ private:
+  std::vector<struct iovec> iovec_;
+
+  // IOVector has value-semantics; copy and assignment are allowed.
+  // This class does not explicitly define copy/move constructors or the
+  // assignment operator to preserve compiler-generated copy/move constructors
+  // and assignment operators. Note that since IOVector does not own the
+  // actual buffers that the struct iovecs point to, copies and assignments
+  // result in a shallow copy of the buffers; resulting IOVectors will point
+  // to the same copy of the underlying data.
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_IOVECTOR_H_
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 4fc32c6..e662ca7 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -15,6 +15,7 @@
 #include "net/base/net_errors.h"
 #include "net/quic/quic_connection_helper.h"
 #include "net/quic/quic_crypto_client_stream_factory.h"
+#include "net/quic/quic_default_packet_writer.h"
 #include "net/quic/quic_stream_factory.h"
 #include "net/ssl/ssl_info.h"
 #include "net/udp/datagram_client_socket.h"
@@ -82,6 +83,7 @@
 QuicClientSession::QuicClientSession(
     QuicConnection* connection,
     scoped_ptr<DatagramClientSocket> socket,
+    scoped_ptr<QuicDefaultPacketWriter> writer,
     QuicStreamFactory* stream_factory,
     QuicCryptoClientStreamFactory* crypto_client_stream_factory,
     const string& server_hostname,
@@ -92,11 +94,13 @@
       require_confirmation_(false),
       stream_factory_(stream_factory),
       socket_(socket.Pass()),
+      writer_(writer.Pass()),
       read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
       read_pending_(false),
       num_total_streams_(0),
       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
       logger_(net_log_),
+      num_packets_read_(0),
       weak_factory_(this) {
   crypto_stream_.reset(
       crypto_client_stream_factory ?
@@ -336,9 +340,10 @@
   logger_.OnCryptoHandshakeMessageReceived(message);
 }
 
-void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
+void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
+                                           bool from_peer) {
   DCHECK(!connection()->connected());
-  logger_.OnConnectionClose(error, from_peer);
+  logger_.OnConnectionClosed(error, from_peer);
   if (from_peer) {
     UMA_HISTOGRAM_SPARSE_SLOWLY(
         "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
@@ -348,9 +353,16 @@
   }
 
   if (error == QUIC_CONNECTION_TIMED_OUT) {
-    UMA_HISTOGRAM_SPARSE_SLOWLY(
+    UMA_HISTOGRAM_COUNTS(
         "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
         GetNumOpenStreams());
+    if (!IsCryptoHandshakeConfirmed()) {
+      // If there have been any streams created, they were 0-RTT speculative
+      // requests that have not be serviced.
+      UMA_HISTOGRAM_COUNTS(
+          "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
+          num_total_streams_);
+    }
   }
 
   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
@@ -360,7 +372,7 @@
     base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
   }
   socket_->Close();
-  QuicSession::ConnectionClose(error, from_peer);
+  QuicSession::OnConnectionClosed(error, from_peer);
   NotifyFactoryOfSessionClosedLater();
 }
 
@@ -380,16 +392,22 @@
                          base::Bind(&QuicClientSession::OnReadComplete,
                                     weak_factory_.GetWeakPtr()));
   if (rv == ERR_IO_PENDING) {
+    num_packets_read_ = 0;
     return;
   }
 
-  // Data was read, process it.
-  // Schedule the work through the message loop to avoid recursive
-  // callbacks.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&QuicClientSession::OnReadComplete,
-                 weak_factory_.GetWeakPtr(), rv));
+  if (++num_packets_read_ > 32) {
+    num_packets_read_ = 0;
+    // Data was read, process it.
+    // Schedule the work through the message loop to avoid recursive
+    // callbacks.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&QuicClientSession::OnReadComplete,
+                   weak_factory_.GetWeakPtr(), rv));
+  } else {
+    OnReadComplete(rv);
+  }
 }
 
 void QuicClientSession::CloseSessionOnError(int error) {
@@ -438,6 +456,7 @@
   dict->SetInteger("total_streams", num_total_streams_);
   dict->SetString("peer_address", peer_address().ToString());
   dict->SetString("guid", base::Uint64ToString(guid()));
+  dict->SetBoolean("connected", connection()->connected());
   return dict;
 }
 
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index f1a328e..6e8ea47 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -25,6 +25,7 @@
 class DatagramClientSocket;
 class QuicConnectionHelper;
 class QuicCryptoClientStreamFactory;
+class QuicDefaultPacketWriter;
 class QuicStreamFactory;
 class SSLInfo;
 
@@ -84,6 +85,7 @@
   // TODO(rch): decouple the factory from the session via a Delegate interface.
   QuicClientSession(QuicConnection* connection,
                     scoped_ptr<DatagramClientSocket> socket,
+                    scoped_ptr<QuicDefaultPacketWriter> writer,
                     QuicStreamFactory* stream_factory,
                     QuicCryptoClientStreamFactory* crypto_client_stream_factory,
                     const std::string& server_hostname,
@@ -125,7 +127,7 @@
   virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE;
 
   // QuicConnectionVisitorInterface methods:
-  virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
+  virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
   virtual void OnSuccessfulVersionNegotiation(
       const QuicVersion& version) OVERRIDE;
 
@@ -197,6 +199,7 @@
   scoped_ptr<QuicCryptoClientStream> crypto_stream_;
   QuicStreamFactory* stream_factory_;
   scoped_ptr<DatagramClientSocket> socket_;
+  scoped_ptr<QuicDefaultPacketWriter> writer_;
   scoped_refptr<IOBufferWithSize> read_buffer_;
   ObserverSet observers_;
   StreamRequestQueue stream_requests_;
@@ -205,6 +208,8 @@
   size_t num_total_streams_;
   BoundNetLog net_log_;
   QuicConnectionLogger logger_;
+  // Number of packets read in the current read loop.
+  size_t num_packets_read_;
   base::WeakPtrFactory<QuicClientSession> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicClientSession);
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 65937de..f04e640 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -13,6 +13,7 @@
 #include "net/quic/crypto/crypto_protocol.h"
 #include "net/quic/crypto/quic_decrypter.h"
 #include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/quic_default_packet_writer.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
 #include "net/quic/test_tools/quic_client_session_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
@@ -27,13 +28,47 @@
 
 const char kServerHostname[] = "www.example.com";
 
+class TestPacketWriter : public QuicDefaultPacketWriter {
+ public:
+  TestPacketWriter() {
+  }
+
+  // QuicPacketWriter
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const IPAddressNumber& self_address,
+      const IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), true);
+    FramerVisitorCapturingFrames visitor;
+    framer.set_visitor(&visitor);
+    QuicEncryptedPacket packet(buffer, buf_len);
+    EXPECT_TRUE(framer.ProcessPacket(packet));
+    header_ = *visitor.header();
+    return WriteResult(WRITE_STATUS_OK, packet.length());
+  }
+
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
+    // Chrome sockets' Write() methods buffer the data until the Write is
+    // permitted.
+    return true;
+  }
+
+  // Returns the header from the last packet written.
+  const QuicPacketHeader& header() { return header_; }
+
+ private:
+  QuicPacketHeader header_;
+};
+
 class QuicClientSessionTest : public ::testing::Test {
  protected:
   QuicClientSessionTest()
       : guid_(1),
+        writer_(new TestPacketWriter()),
         connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
-        session_(connection_, GetSocket().Pass(), NULL,
-                 NULL, kServerHostname, DefaultQuicConfig(), &crypto_config_,
+        session_(connection_, GetSocket().Pass(), writer_.Pass(), NULL, NULL,
+                 kServerHostname, DefaultQuicConfig(), &crypto_config_,
                  &net_log_) {
     session_.config()->SetDefaults();
     crypto_config_.SetDefaults();
@@ -59,6 +94,7 @@
   }
 
   QuicGuid guid_;
+  scoped_ptr<QuicDefaultPacketWriter> writer_;
   PacketSavingConnection* connection_;
   CapturingNetLog net_log_;
   MockClientSocketFactory socket_factory_;
@@ -72,20 +108,10 @@
 };
 
 TEST_F(QuicClientSessionTest, CryptoConnect) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 }
 
 TEST_F(QuicClientSessionTest, MaxNumStreams) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   std::vector<QuicReliableClientStream*> streams;
@@ -102,11 +128,6 @@
 }
 
 TEST_F(QuicClientSessionTest, MaxNumStreamsViaRequest) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   std::vector<QuicReliableClientStream*> streams;
@@ -131,11 +152,6 @@
 }
 
 TEST_F(QuicClientSessionTest, GoAwayReceived) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   // After receiving a GoAway, I should no longer be able to create outgoing
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index e3926d5..4c9a6bc 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -14,11 +14,10 @@
 #include <utility>
 
 #include "base/logging.h"
-#include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "net/quic/crypto/quic_decrypter.h"
 #include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/iovector.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_utils.h"
 
@@ -57,8 +56,7 @@
 // initial congestion window(RFC 6928).
 const size_t kMaxRetransmissionsPerAck = 10;
 
-// TCP retransmits after 2 nacks.  We allow for a third in case of out-of-order
-// delivery.
+// TCP retransmits after 3 nacks.
 // TODO(ianswett): Change to match TCP's rule of retransmitting once an ack
 // at least 3 sequence numbers larger arrives.
 const size_t kNumberOfNacksBeforeRetransmission = 3;
@@ -178,10 +176,13 @@
 }
 
 net::IsHandshake HasCryptoHandshake(
-    const RetransmittableFrames& retransmittable_frames) {
-  for (size_t i = 0; i < retransmittable_frames.frames().size(); ++i) {
-    if (retransmittable_frames.frames()[i].type == STREAM_FRAME &&
-        retransmittable_frames.frames()[i].stream_frame->stream_id ==
+    const RetransmittableFrames* retransmittable_frames) {
+  if (!retransmittable_frames) {
+    return net::NOT_HANDSHAKE;
+  }
+  for (size_t i = 0; i < retransmittable_frames->frames().size(); ++i) {
+    if (retransmittable_frames->frames()[i].type == STREAM_FRAME &&
+        retransmittable_frames->frames()[i].stream_frame->stream_id ==
             kCryptoStreamId) {
       return net::IS_HANDSHAKE;
     }
@@ -191,25 +192,19 @@
 
 }  // namespace
 
-// TODO(rch): Remove this.
-// Because of a bug in the interaction between the TcpCubicSender and
-// QuicConnection, acks currently count against the congestion window.
-// This means that if acks are not acked, and data is only flowing in
-// one direction, then the connection will deadlock.
-// static
-bool QuicConnection::g_acks_do_not_instigate_acks = true;
-
 #define ENDPOINT (is_server_ ? "Server: " : " Client: ")
 
 QuicConnection::QuicConnection(QuicGuid guid,
                                IPEndPoint address,
                                QuicConnectionHelperInterface* helper,
+                               QuicPacketWriter* writer,
                                bool is_server,
-                               QuicVersion version)
-    : framer_(version,
+                               const QuicVersionVector& supported_versions)
+    : framer_(supported_versions,
               helper->GetClock()->ApproximateNow(),
               is_server),
       helper_(helper),
+      writer_(writer),
       encryption_level_(ENCRYPTION_NONE),
       clock_(helper->GetClock()),
       random_generator_(helper->GetRandomGenerator()),
@@ -241,18 +236,11 @@
       is_server_(is_server),
       connected_(true),
       received_truncated_ack_(false),
-      send_ack_in_response_to_packet_(false),
       address_migrating_(false) {
-  helper_->SetConnection(this);
+  DLOG(INFO) << ENDPOINT << "Created connection with guid: " << guid;
   timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
   framer_.set_visitor(this);
   framer_.set_received_entropy_calculator(&received_packet_manager_);
-
-  if (FLAGS_fake_packet_loss_percentage > 0) {
-    int64 seed = base::RandUint64();
-    LOG(INFO) << ENDPOINT << "Seeding packet loss with " << seed;
-    simple_random_.set_seed(seed);
-  }
 }
 
 QuicConnection::~QuicConnection() {
@@ -269,8 +257,9 @@
   // Try to find the highest mutual version by iterating over supported
   // versions, starting with the highest, and breaking out of the loop once we
   // find a matching version in the provided available_versions vector.
-  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
-    const QuicVersion& version = kSupportedQuicVersions[i];
+  const QuicVersionVector& supported_versions = framer_.supported_versions();
+  for (size_t i = 0; i < supported_versions.size(); ++i) {
+    const QuicVersion& version = supported_versions[i];
     if (std::find(available_versions.begin(), available_versions.end(),
                   version) != available_versions.end()) {
       framer_.set_version(version);
@@ -307,6 +296,8 @@
 }
 
 bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
+  DLOG(INFO) << ENDPOINT << "Received packet with mismatched version "
+             << received_version;
   // TODO(satyamshekhar): Implement no server state in this mode.
   if (!is_server_) {
     LOG(DFATAL) << ENDPOINT << "Framer called OnProtocolVersionMismatch. "
@@ -331,7 +322,7 @@
 
     case NEGOTIATION_IN_PROGRESS:
       if (!framer_.IsSupportedVersion(received_version)) {
-        // Drop packets which can't be parsed due to version mismatch.
+        SendVersionNegotiationPacket();
         return false;
       }
       break;
@@ -347,6 +338,7 @@
 
   version_negotiation_state_ = NEGOTIATED_VERSION;
   visitor_->OnSuccessfulVersionNegotiation(received_version);
+  DLOG(INFO) << ENDPOINT << "version negotiated " << received_version;
 
   // Store the new version.
   framer_.set_version(received_version);
@@ -391,6 +383,7 @@
     return;
   }
 
+  DLOG(INFO) << ENDPOINT << "negotiating version " << version();
   version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
   RetransmitUnackedPackets(ALL_PACKETS);
 }
@@ -676,7 +669,7 @@
   if (debug_visitor_) {
     debug_visitor_->OnConnectionCloseFrame(frame);
   }
-  DLOG(INFO) << ENDPOINT << "Connection " << guid() << "closed with error "
+  DLOG(INFO) << ENDPOINT << "Connection " << guid() << " closed with error "
              << QuicUtils::ErrorToString(frame.error_code)
              << " " << frame.error_details;
   CloseConnection(frame.error_code, true);
@@ -725,10 +718,15 @@
   bool send_ack_immediately =
       received_packet_manager_.GetNumMissingPackets() != 0;
 
+  // Ensure the visitor can process the stream frames before recording and
+  // processing the rest of the packet.
   if (last_stream_frames_.empty() ||
       visitor_->OnStreamFrames(last_stream_frames_)) {
     received_packet_manager_.RecordPacketReceived(
         last_header_, time_of_last_received_packet_);
+    for (size_t i = 0; i < last_stream_frames_.size(); ++i) {
+      stats_.stream_bytes_received += last_stream_frames_[i].data.length();
+    }
   }
 
   // Process stream resets, then acks, then congestion feedback.
@@ -801,26 +799,17 @@
   // |include_ack| is false since we decide about ack bundling below.
   ScopedPacketBundler bundler(this, false);
 
-  if (send_ack_immediately) {
-    send_ack_in_response_to_packet_ = true;
-  }
-
-  // TODO(rch): remove last_packet_should_instigate_ack when we remove
-  // g_acks_do_not_instigate_acks.
-  if (last_packet_should_instigate_ack ||
-      !g_acks_do_not_instigate_acks) {
-    if (send_ack_in_response_to_packet_) {
+  if (last_packet_should_instigate_ack) {
+    // In general, we ack every second packet.  When we don't ack the first
+    // packet, we set the delayed ack alarm.  Thus, if the ack alarm is set
+    // then we know this is the second packet, and we should send an ack.
+    if (send_ack_immediately || ack_alarm_->IsSet()) {
       SendAck();
-      DCHECK(!send_ack_in_response_to_packet_);
+      DCHECK(!ack_alarm_->IsSet());
     } else {
-      send_ack_in_response_to_packet_ = true;
-      DVLOG(1) << "Next received packet will trigger ACK.";
-      if (last_packet_should_instigate_ack && !ack_alarm_->IsSet()) {
-        // Set the ack alarm for when any retransmittable frame is received.
-        ack_alarm_->Set(clock_->ApproximateNow().Add(
-            congestion_manager_.DelayedAckTime()));
-        DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
-      }
+      ack_alarm_->Set(clock_->ApproximateNow().Add(
+          congestion_manager_.DelayedAckTime()));
+      DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
     }
   }
 
@@ -841,18 +830,19 @@
 }
 
 void QuicConnection::SendVersionNegotiationPacket() {
-  QuicVersionVector supported_versions;
-  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
-    supported_versions.push_back(kSupportedQuicVersions[i]);
-  }
   scoped_ptr<QuicEncryptedPacket> version_packet(
-      packet_creator_.SerializeVersionNegotiationPacket(supported_versions));
+      packet_creator_.SerializeVersionNegotiationPacket(
+          framer_.supported_versions()));
   // TODO(satyamshekhar): implement zero server state negotiation.
   WriteResult result =
-      helper_->WritePacketToWire(*version_packet);
+      writer_->WritePacket(version_packet->data(), version_packet->length(),
+                           self_address().address(), peer_address(), this);
+  if (result.status == WRITE_STATUS_BLOCKED) {
+    write_blocked_ = true;
+  }
   if (result.status == WRITE_STATUS_OK ||
       (result.status == WRITE_STATUS_BLOCKED &&
-          helper_->IsWriteBlockedDataBuffered())) {
+       writer_->IsWriteBlockedDataBuffered())) {
     pending_version_negotiation_packet_ = false;
     return;
   }
@@ -860,16 +850,12 @@
     // We can't send an error as the socket is presumably borked.
     CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
   }
-  if (result.status == WRITE_STATUS_BLOCKED) {
-    write_blocked_ = true;
-  }
   pending_version_negotiation_packet_ = true;
 }
 
-QuicConsumedData QuicConnection::SendvStreamDataInner(
+QuicConsumedData QuicConnection::SendStreamDataInner(
     QuicStreamId id,
-    const struct iovec* iov,
-    int iov_count,
+    const IOVector& data,
     QuicStreamOffset offset,
     bool fin,
     QuicAckNotifier* notifier) {
@@ -881,17 +867,18 @@
   size_t bytes_written = 0;
   bool fin_consumed = false;
 
-  for (int i = 0; i < iov_count; ++i) {
-    bool send_fin = fin && (i == iov_count - 1);
-    if (!send_fin && iov[i].iov_len == 0) {
+  for (size_t i = 0; i < data.Size(); ++i) {
+    bool send_fin = fin && (i == data.Size() - 1);
+    if (!send_fin && data.iovec()[i].iov_len == 0) {
       LOG(DFATAL) << "Attempt to send empty stream frame";
     }
 
-    StringPiece data(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+    StringPiece data_piece(static_cast<char*>(data.iovec()[i].iov_base),
+                           data.iovec()[i].iov_len);
     int currentOffset = offset + bytes_written;
     QuicConsumedData consumed_data =
         packet_generator_.ConsumeData(id,
-                                      data,
+                                      data_piece,
                                       currentOffset,
                                       send_fin,
                                       notifier);
@@ -901,37 +888,36 @@
     fin_consumed = consumed_data.fin_consumed;
     // If no bytes were consumed, bail now, because the stream can not write
     // more data.
-    if (consumed_data.bytes_consumed < iov[i].iov_len) {
+    if (consumed_data.bytes_consumed < data.iovec()[i].iov_len) {
       break;
     }
   }
   // Handle the 0 byte write properly.
-  if (iov_count == 0) {
+  if (data.Empty()) {
     DCHECK(fin);
     QuicConsumedData consumed_data = packet_generator_.ConsumeData(
         id, StringPiece(), offset, fin, NULL);
     fin_consumed = consumed_data.fin_consumed;
   }
 
+  stats_.stream_bytes_sent += bytes_written;
   return QuicConsumedData(bytes_written, fin_consumed);
 }
 
-QuicConsumedData QuicConnection::SendvStreamData(QuicStreamId id,
-                                                 const struct iovec* iov,
-                                                 int iov_count,
-                                                 QuicStreamOffset offset,
-                                                 bool fin) {
-  return SendvStreamDataInner(id, iov, iov_count, offset, fin, NULL);
+QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
+                                                const IOVector& data,
+                                                QuicStreamOffset offset,
+                                                bool fin) {
+  return SendStreamDataInner(id, data, offset, fin, NULL);
 }
 
-QuicConsumedData QuicConnection::SendvStreamDataAndNotifyWhenAcked(
+QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked(
     QuicStreamId id,
-    const struct iovec* iov,
-    int iov_count,
+    const IOVector& data,
     QuicStreamOffset offset,
     bool fin,
     QuicAckNotifier::DelegateInterface* delegate) {
-  if (!fin && iov_count == 0) {
+  if (!fin && data.Empty()) {
     LOG(DFATAL) << "Attempt to send empty stream frame";
   }
 
@@ -939,7 +925,7 @@
   // no data was consumed).
   QuicAckNotifier* notifier = new QuicAckNotifier(delegate);
   QuicConsumedData consumed_data =
-      SendvStreamDataInner(id, iov, iov_count, offset, fin, notifier);
+      SendStreamDataInner(id, data, offset, fin, notifier);
 
   if (consumed_data.bytes_consumed == 0) {
     // No data was consumed, delete the notifier.
@@ -1085,6 +1071,7 @@
                     packet_iterator->packet,
                     packet_iterator->transmission_type,
                     packet_iterator->retransmittable,
+                    packet_iterator->handshake,
                     packet_iterator->forced)) {
       packet_iterator = queued_packets_.erase(packet_iterator);
     } else {
@@ -1105,7 +1092,7 @@
         sent_packet_manager_.NextPendingRetransmission();
     if (HasForcedFrames(&pending.retransmittable_frames) == NO_FORCE &&
         !CanWrite(pending.transmission_type, HAS_RETRANSMITTABLE_DATA,
-                  HasCryptoHandshake(pending.retransmittable_frames))) {
+                  HasCryptoHandshake(&pending.retransmittable_frames))) {
       break;
     }
 
@@ -1136,6 +1123,8 @@
                       serialized_packet.entropy_hash,
                       pending.transmission_type,
                       HAS_RETRANSMITTABLE_DATA,
+                      HasCryptoHandshake(
+                          serialized_packet.retransmittable_frames),
                       HasForcedFrames(
                           serialized_packet.retransmittable_frames));
   }
@@ -1243,8 +1232,6 @@
           sent_packet_manager_.GetNumUnackedPackets(), consecutive_rto_count_);
   retransmission_alarm_->Set(
       clock_->ApproximateNow().Add(retransmission_delay));
-  // TODO(satyamshekhar): restore packet reordering with Ian's TODO in
-  // SendStreamData().
 }
 
 void QuicConnection::SetupAbandonFecTimer(
@@ -1263,70 +1250,18 @@
                                  QuicPacket* packet,
                                  TransmissionType transmission_type,
                                  HasRetransmittableData retransmittable,
+                                 IsHandshake handshake,
                                  Force forced) {
-  if (!connected_) {
-    DLOG(INFO) << ENDPOINT
-               << "Not sending packet as connection is disconnected.";
-    delete packet;
-    // Returning true because we deleted the packet and the caller shouldn't
-    // delete it again.
-    return true;
-  }
-
-  if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
-      level == ENCRYPTION_NONE) {
-    // Drop packets that are NULL encrypted since the peer won't accept them
-    // anymore.
-    DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
-               << " since the packet is NULL encrypted.";
-    sent_packet_manager_.DiscardUnackedPacket(sequence_number);
+  if (ShouldDiscardPacket(level, sequence_number, retransmittable)) {
     delete packet;
     return true;
   }
 
-  if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
-    if (!sent_packet_manager_.IsUnacked(sequence_number)) {
-      // This is a crazy edge case, but if we retransmit a packet,
-      // (but have to queue it for some reason) then receive an ack
-      // for the previous transmission (but not the retransmission)
-      // then receive a truncated ACK which causes us to raise the
-      // high water mark, all before we're able to send the packet
-      // then we can simply drop it.
-      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
-                 << " since it has already been acked.";
-      delete packet;
-      return true;
-    }
-
-    if (sent_packet_manager_.IsPreviousTransmission(sequence_number)) {
-      // If somehow we have already retransmitted this packet *before*
-      // we actually send it for the first time (I think this is probably
-      // impossible in the real world), then don't bother sending it.
-      // We don't want to call DiscardUnackedPacket because in this case
-      // the peer has not yet ACK'd the data.  We need the subsequent
-      // retransmission to be sent.
-      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
-                 << " since it has already been retransmitted.";
-      delete packet;
-      return true;
-    }
-
-    if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
-      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
-                 << " since a previous transmission has been acked.";
-      sent_packet_manager_.DiscardUnackedPacket(sequence_number);
-      delete packet;
-      return true;
-    }
+  // If we're write blocked, we know we can't write.
+  if (write_blocked_) {
+    return false;
   }
 
-  // TODO(wtc): use the same logic that is used in the packet generator.
-  // Namely, a packet is a handshake if it contains a stream frame for the
-  // crypto stream.  It should be possible to look at the RetransmittableFrames
-  // in the SerializedPacket to determine this for a packet.
-  IsHandshake handshake = level == ENCRYPTION_NONE ? IS_HANDSHAKE
-                                                   : NOT_HANDSHAKE;
-
   // If we are not forced and we can't write, then simply return false;
   if (forced == NO_FORCE &&
       !CanWrite(transmission_type, retransmittable, handshake)) {
@@ -1372,7 +1307,13 @@
                                         packet->is_fec_packet(),
                                         packet->length()));
 
-  WriteResult result = WritePacketToWire(sequence_number, level, *encrypted);
+  WriteResult result =
+      writer_->WritePacket(encrypted->data(), encrypted->length(),
+                           self_address().address(), peer_address(), this);
+  if (debug_visitor_) {
+    // Pass the write result to the visitor.
+    debug_visitor_->OnPacketSent(sequence_number, level, *encrypted, result);
+  }
   if (result.status == WRITE_STATUS_BLOCKED) {
     // TODO(satyashekhar): It might be more efficient (fewer system calls), if
     // all connections share this variable i.e this becomes a part of
@@ -1382,7 +1323,7 @@
     // be queued and sent again, which would result in an unnecessary
     // duplicate packet being sent.  The helper must call OnPacketSent
     // when the packet is actually sent.
-    if (helper_->IsWriteBlockedDataBuffered()) {
+    if (writer_->IsWriteBlockedDataBuffered()) {
       delete packet;
       return true;
     }
@@ -1397,6 +1338,62 @@
   return false;
 }
 
+bool QuicConnection::ShouldDiscardPacket(
+    EncryptionLevel level,
+    QuicPacketSequenceNumber sequence_number,
+    HasRetransmittableData retransmittable) {
+  if (!connected_) {
+    DLOG(INFO) << ENDPOINT
+        << "Not sending packet as connection is disconnected.";
+    return true;
+  }
+
+  if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+      level == ENCRYPTION_NONE) {
+    // Drop packets that are NULL encrypted since the peer won't accept them
+    // anymore.
+    DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
+        << " since the packet is NULL encrypted.";
+    sent_packet_manager_.DiscardUnackedPacket(sequence_number);
+    return true;
+  }
+
+  if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
+    if (!sent_packet_manager_.IsUnacked(sequence_number)) {
+      // This is a crazy edge case, but if we retransmit a packet,
+      // (but have to queue it for some reason) then receive an ack
+      // for the previous transmission (but not the retransmission)
+      // then receive a truncated ACK which causes us to raise the
+      // high water mark, all before we're able to send the packet
+      // then we can simply drop it.
+      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
+          << " since it has already been acked.";
+      return true;
+    }
+
+    if (sent_packet_manager_.IsPreviousTransmission(sequence_number)) {
+      // If somehow we have already retransmitted this packet *before*
+      // we actually send it for the first time (I think this is probably
+      // impossible in the real world), then don't bother sending it.
+      // We don't want to call DiscardUnackedPacket because in this case
+      // the peer has not yet ACK'd the data.  We need the subsequent
+      // retransmission to be sent.
+      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
+          << " since it has already been retransmitted.";
+      return true;
+    }
+
+    if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
+      DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number
+          << " since a previous transmission has been acked.";
+      sent_packet_manager_.DiscardUnackedPacket(sequence_number);
+      return true;
+    }
+  }
+
+  return false;
+}
+
 bool QuicConnection::OnPacketSent(WriteResult result) {
   DCHECK_NE(WRITE_STATUS_BLOCKED, result.status);
   if (pending_write_.get() == NULL) {
@@ -1413,6 +1410,7 @@
   pending_write_.reset();
 
   if (result.status == WRITE_STATUS_ERROR) {
+    DLOG(INFO) << "Write failed with error code: " << result.error_code;
     // We can't send an error as the socket is presumably borked.
     CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
     return false;
@@ -1456,18 +1454,6 @@
   return true;
 }
 
-WriteResult QuicConnection::WritePacketToWire(
-    QuicPacketSequenceNumber sequence_number,
-    EncryptionLevel level,
-    const QuicEncryptedPacket& packet) {
-  WriteResult result = helper_->WritePacketToWire(packet);
-  if (debug_visitor_) {
-    // Pass the write result to the visitor.
-    debug_visitor_->OnPacketSent(sequence_number, level, packet, result);
-  }
-  return result;
-}
-
 bool QuicConnection::OnSerializedPacket(
     const SerializedPacket& serialized_packet) {
   if (serialized_packet.retransmittable_frames) {
@@ -1486,6 +1472,8 @@
                            serialized_packet.retransmittable_frames != NULL ?
                                HAS_RETRANSMITTABLE_DATA :
                                NO_RETRANSMITTABLE_DATA,
+                           HasCryptoHandshake(
+                               serialized_packet.retransmittable_frames),
                            HasForcedFrames(
                                serialized_packet.retransmittable_frames));
 }
@@ -1509,32 +1497,19 @@
                                        QuicPacketEntropyHash entropy_hash,
                                        TransmissionType transmission_type,
                                        HasRetransmittableData retransmittable,
+                                       IsHandshake handshake,
                                        Force forced) {
   sent_entropy_manager_.RecordPacketEntropyHash(sequence_number, entropy_hash);
   if (!WritePacket(level, sequence_number, packet,
-                   transmission_type, retransmittable, forced)) {
+                   transmission_type, retransmittable, handshake, forced)) {
     queued_packets_.push_back(QueuedPacket(sequence_number, packet, level,
                                            transmission_type, retransmittable,
-                                           forced));
+                                           handshake, forced));
     return false;
   }
   return true;
 }
 
-uint64 QuicConnection::SimpleRandom::RandUint64() {
-  unsigned char hash[base::kSHA1Length];
-  base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
-                      hash);
-  memcpy(&seed_, hash, sizeof(seed_));
-  return seed_;
-}
-
-bool QuicConnection::ShouldSimulateLostPacket() {
-  return FLAGS_fake_packet_loss_percentage > 0 &&
-      simple_random_.RandUint64() % 100 <
-      static_cast<uint64>(FLAGS_fake_packet_loss_percentage);
-}
-
 void QuicConnection::UpdateSentPacketInfo(SentPacketInfo* sent_info) {
   sent_info->least_unacked = sent_packet_manager_.GetLeastUnackedSentPacket();
   sent_info->entropy_hash = sent_entropy_manager_.EntropyHash(
@@ -1543,7 +1518,6 @@
 
 void QuicConnection::SendAck() {
   ack_alarm_->Cancel();
-  send_ack_in_response_to_packet_ = false;
   // TODO(rch): delay this until the CreateFeedbackFrame
   // method is invoked.  This requires changes SetShouldSendAck
   // to be a no-arg method, and re-jiggering its implementation.
@@ -1573,6 +1547,8 @@
   // packets will be queued for future sending.
   SequenceNumberSet unacked_packets =
       sent_packet_manager_.GetUnackedPackets();
+  DLOG(INFO) << "OnRetransmissionTimeout() fired with "
+             << unacked_packets.size() << " unacked packets.";
 
   // Abandon all unacked packets to ensure the congestion window
   // opens up before we attempt to retransmit the packet.
@@ -1774,7 +1750,7 @@
 void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
   DCHECK(connected_);
   connected_ = false;
-  visitor_->ConnectionClose(error, from_peer);
+  visitor_->OnConnectionClosed(error, from_peer);
 }
 
 void QuicConnection::SendGoAway(QuicErrorCode error,
@@ -1900,9 +1876,7 @@
   if (FLAGS_bundle_ack_with_outgoing_packet &&
       include_ack && connection_->ack_alarm_->IsSet()) {
     DVLOG(1) << "Bundling ack with outgoing packet.";
-    DCHECK(connection_->send_ack_in_response_to_packet_);
     connection_->SendAck();
-    DCHECK(!connection_->send_ack_in_response_to_packet_);
   }
 }
 
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 1382e06..c5ad5c4 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -28,6 +28,7 @@
 #include "net/base/iovec.h"
 #include "net/base/ip_endpoint.h"
 #include "net/quic/congestion_control/quic_congestion_manager.h"
+#include "net/quic/iovector.h"
 #include "net/quic/quic_ack_notifier.h"
 #include "net/quic/quic_ack_notifier_manager.h"
 #include "net/quic/quic_alarm.h"
@@ -36,6 +37,7 @@
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
 #include "net/quic/quic_packet_generator.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_received_packet_manager.h"
 #include "net/quic/quic_sent_entropy_manager.h"
@@ -77,8 +79,8 @@
 
   // Called when the connection is closed either locally by the framer, or
   // remotely by the peer.
-  virtual void ConnectionClose(QuicErrorCode error,
-                               bool from_peer) = 0;
+  virtual void OnConnectionClosed(QuicErrorCode error,
+                                  bool from_peer) = 0;
 
   // Called once a specific QUIC version is agreed by both endpoints.
   virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0;
@@ -159,28 +161,12 @@
  public:
   virtual ~QuicConnectionHelperInterface() {}
 
-  // Sets the QuicConnection to be used by this helper.  This method
-  // must only be called once.
-  virtual void SetConnection(QuicConnection* connection) = 0;
-
   // Returns a QuicClock to be used for all time related functions.
   virtual const QuicClock* GetClock() const = 0;
 
   // Returns a QuicRandom to be used for all random number related functions.
   virtual QuicRandom* GetRandomGenerator() = 0;
 
-  // Sends the packet out to the peer, possibly simulating packet
-  // loss if FLAGS_fake_packet_loss_percentage is set.  If the write
-  // succeeded, the result's status is WRITE_STATUS_OK and bytes_written is
-  // populated. If the write failed, the result's status is WRITE_STATUS_BLOCKED
-  // or WRITE_STATUS_ERROR and error_code will populated.
-  virtual WriteResult WritePacketToWire(const QuicEncryptedPacket& packet) = 0;
-
-  // Returns true if the helper buffers and subsequently rewrites data
-  // when an attempt to write results in the underlying socket becoming
-  // write blocked.
-  virtual bool IsWriteBlockedDataBuffered() = 0;
-
   // Creates a new platform-specific alarm which will be configured to
   // notify |delegate| when the alarm fires.  Caller takes ownership
   // of the new alarm, which will not yet be "set" to fire.
@@ -204,32 +190,31 @@
   };
 
   // Constructs a new QuicConnection for the specified |guid| and |address|.
-  // |helper| will be owned by this connection.
+  // |helper| and |writer| must outlive this connection.
   QuicConnection(QuicGuid guid,
                  IPEndPoint address,
                  QuicConnectionHelperInterface* helper,
+                 QuicPacketWriter* writer,
                  bool is_server,
-                 QuicVersion version);
+                 const QuicVersionVector& supported_versions);
   virtual ~QuicConnection();
 
-  // Send the data in |iov| to the peer in as few packets as possible.
+  // Send the data in |data| to the peer in as few packets as possible.
   // Returns a pair with the number of bytes consumed from data, and a boolean
   // indicating if the fin bit was consumed.  This does not indicate the data
   // has been sent on the wire: it may have been turned into a packet and queued
   // if the socket was unexpectedly blocked.
-  QuicConsumedData SendvStreamData(QuicStreamId id,
-                                   const struct iovec* iov,
-                                   int iov_count,
-                                   QuicStreamOffset offset,
-                                   bool fin);
+  QuicConsumedData SendStreamData(QuicStreamId id,
+                                  const IOVector& data,
+                                  QuicStreamOffset offset,
+                                  bool fin);
 
-  // Same as SendvStreamData, except the provided delegate will be informed
+  // Same as SendStreamData, except the provided delegate will be informed
   // once ACKs have been received for all the packets written.
   // The |delegate| is not owned by the QuicConnection and must outlive it.
-  QuicConsumedData SendvStreamDataAndNotifyWhenAcked(
+  QuicConsumedData SendStreamDataAndNotifyWhenAcked(
       QuicStreamId id,
-      const struct iovec* iov,
-      int iov_count,
+      const IOVector& data,
       QuicStreamOffset offset,
       bool fin,
       QuicAckNotifier::DelegateInterface* delegate);
@@ -341,7 +326,7 @@
 
   QuicPacketCreator::Options* options() { return packet_creator_.options(); }
 
-  bool connected() { return connected_; }
+  bool connected() const { return connected_; }
 
   size_t NumFecGroups() const { return group_map_.size(); }
 
@@ -368,10 +353,6 @@
   // true.  Otherwise, it will return false and will reset the timeout alarm.
   bool CheckForTimeout();
 
-  // Returns true of the next packet to be sent should be "lost" by
-  // not actually writing it to the wire.
-  bool ShouldSimulateLostPacket();
-
   // Sets up a packet with an QuicAckFrame and sends it out.
   void SendAck();
 
@@ -419,8 +400,6 @@
 
   bool is_server() const { return is_server_; }
 
-  static bool g_acks_do_not_instigate_acks;
-
  protected:
   // Send a packet to the peer using encryption |level|. If |sequence_number|
   // is present in the |retransmission_map_|, then contents of this packet will
@@ -437,6 +416,7 @@
                                  QuicPacketEntropyHash entropy_hash,
                                  TransmissionType transmission_type,
                                  HasRetransmittableData retransmittable,
+                                 IsHandshake handshake,
                                  Force forced);
 
   // Writes the given packet to socket, encrypted with |level|, with the help
@@ -452,16 +432,13 @@
                    QuicPacket* packet,
                    TransmissionType transmission_type,
                    HasRetransmittableData retransmittable,
+                   IsHandshake handshake,
                    Force force);
 
-  WriteResult WritePacketToWire(QuicPacketSequenceNumber sequence_number,
-                                EncryptionLevel level,
-                                const QuicEncryptedPacket& packet);
-
   // Make sure an ack we got from our peer is sane.
   bool ValidateAckFrame(const QuicAckFrame& incoming_ack);
 
-  QuicConnectionHelperInterface* helper() { return helper_.get(); }
+  QuicConnectionHelperInterface* helper() { return helper_; }
 
   // Selects and updates the version of the protocol being used by selecting a
   // version from |available_versions| which is also supported. Returns true if
@@ -471,23 +448,6 @@
   QuicFramer framer_;
 
  private:
-  // Simple random number generator used to compute random numbers suitable
-  // for pseudo-randomly dropping packets in tests.  It works by computing
-  // the sha1 hash of the current seed, and using the first 64 bits as
-  // the next random number, and the next seed.
-  class SimpleRandom {
-   public:
-    SimpleRandom() : seed_(0) {}
-
-    // Returns a random number in the range [0, kuint64max].
-    uint64 RandUint64();
-
-    void set_seed(uint64 seed) { seed_ = seed; }
-
-   private:
-    uint64 seed_;
-  };
-
   // Stores current batch state for connection, puts the connection
   // into batch mode, and destruction restores the stored batch state.
   // While the bundler is in scope, any generated frames are bundled
@@ -523,12 +483,14 @@
                  EncryptionLevel level,
                  TransmissionType transmission_type,
                  HasRetransmittableData retransmittable,
+                 IsHandshake handshake,
                  Force forced)
         : sequence_number(sequence_number),
           packet(packet),
           encryption_level(level),
           transmission_type(transmission_type),
           retransmittable(retransmittable),
+          handshake(handshake),
           forced(forced) {
     }
 
@@ -537,6 +499,7 @@
     const EncryptionLevel encryption_level;
     TransmissionType transmission_type;
     HasRetransmittableData retransmittable;
+    IsHandshake handshake;
     Force forced;
   };
 
@@ -610,14 +573,13 @@
                               RetransmissionTimeComparator>
       RetransmissionTimeouts;
 
-  // Inner helper function for SendvStreamData and
-  // SendvStreamDataAndNotifyWhenAcked.
-  QuicConsumedData SendvStreamDataInner(QuicStreamId id,
-                                        const struct iovec* iov,
-                                        int iov_count,
-                                        QuicStreamOffset offset,
-                                        bool fin,
-                                        QuicAckNotifier *notifier);
+  // Inner helper function for SendStreamData and
+  // SendStreamDataAndNotifyWhenAcked.
+  QuicConsumedData SendStreamDataInner(QuicStreamId id,
+                                       const IOVector& data,
+                                       QuicStreamOffset offset,
+                                       bool fin,
+                                       QuicAckNotifier *notifier);
 
   // Sends a version negotiation packet to the peer.
   void SendVersionNegotiationPacket();
@@ -654,6 +616,11 @@
   // Writes as many pending retransmissions as possible.
   void WritePendingRetransmissions();
 
+  // Returns true if the packet should be discarded and not sent.
+  bool ShouldDiscardPacket(EncryptionLevel level,
+                           QuicPacketSequenceNumber sequence_number,
+                           HasRetransmittableData retransmittable);
+
   // Queues |packet| in the hopes that it can be decrypted in the
   // future, when a new key is installed.
   void QueueUndecryptablePacket(const QuicEncryptedPacket& packet);
@@ -685,7 +652,8 @@
   // Closes any FEC groups protecting packets before |sequence_number|.
   void CloseFecGroupsBefore(QuicPacketSequenceNumber sequence_number);
 
-  scoped_ptr<QuicConnectionHelperInterface> helper_;
+  QuicConnectionHelperInterface* helper_;  // Not owned.
+  QuicPacketWriter* writer_;  // Not owned.
   EncryptionLevel encryption_level_;
   const QuicClock* clock_;
   QuicRandom* random_generator_;
@@ -806,7 +774,6 @@
   // True if the last ack received from the peer may have been truncated.  False
   // otherwise.
   bool received_truncated_ack_;
-  bool send_ack_in_response_to_packet_;
 
   // Set to true if the udp packet headers have a new self or peer address.
   // This is checked later on validating a data or version negotiation packet.
@@ -817,9 +784,6 @@
   // maintains the currently active notifiers.
   AckNotifierManager ack_notifier_manager_;
 
-  // Only used to configure fake packet loss.
-  SimpleRandom simple_random_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicConnection);
 };
 
diff --git a/net/quic/quic_connection_helper.cc b/net/quic/quic_connection_helper.cc
index e0b9477..543bf09 100644
--- a/net/quic/quic_connection_helper.cc
+++ b/net/quic/quic_connection_helper.cc
@@ -93,11 +93,9 @@
 
 QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner,
                                            const QuicClock* clock,
-                                           QuicRandom* random_generator,
-                                           DatagramClientSocket* socket)
+                                           QuicRandom* random_generator)
     : weak_factory_(this),
       task_runner_(task_runner),
-      socket_(socket),
       clock_(clock),
       random_generator_(random_generator) {
 }
@@ -105,10 +103,6 @@
 QuicConnectionHelper::~QuicConnectionHelper() {
 }
 
-void QuicConnectionHelper::SetConnection(QuicConnection* connection) {
-  connection_ = connection;
-}
-
 const QuicClock* QuicConnectionHelper::GetClock() const {
   return clock_;
 }
@@ -117,48 +111,8 @@
   return random_generator_;
 }
 
-WriteResult QuicConnectionHelper::WritePacketToWire(
-    const QuicEncryptedPacket& packet) {
-  if (connection_->ShouldSimulateLostPacket()) {
-    DLOG(INFO) << "Dropping packet due to fake packet loss.";
-    return WriteResult(WRITE_STATUS_OK, packet.length());
-  }
-
-  scoped_refptr<StringIOBuffer> buf(
-      new StringIOBuffer(std::string(packet.data(),
-                                     packet.length())));
-  int rv = socket_->Write(buf.get(),
-                          packet.length(),
-                          base::Bind(&QuicConnectionHelper::OnWriteComplete,
-                                     weak_factory_.GetWeakPtr()));
-  WriteStatus status = WRITE_STATUS_OK;
-  if (rv < 0) {
-    if (rv != ERR_IO_PENDING) {
-      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
-      status = WRITE_STATUS_ERROR;
-    } else {
-      status = WRITE_STATUS_BLOCKED;
-    }
-  }
-
-  return WriteResult(status, rv);
-}
-
-bool QuicConnectionHelper::IsWriteBlockedDataBuffered() {
-  // Chrome sockets' Write() methods buffer the data until the Write is
-  // permitted.
-  return true;
-}
-
 QuicAlarm* QuicConnectionHelper::CreateAlarm(QuicAlarm::Delegate* delegate) {
   return new QuicChromeAlarm(clock_, task_runner_, delegate);
 }
 
-void QuicConnectionHelper::OnWriteComplete(int rv) {
-  DCHECK_NE(rv, ERR_IO_PENDING);
-  WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
-  connection_->OnPacketSent(result);
-  connection_->OnCanWrite();
-}
-
 }  // namespace net
diff --git a/net/quic/quic_connection_helper.h b/net/quic/quic_connection_helper.h
index 1733cda..7098039 100644
--- a/net/quic/quic_connection_helper.h
+++ b/net/quic/quic_connection_helper.h
@@ -27,39 +27,23 @@
 class QuicClock;
 class QuicRandom;
 
-namespace test {
-class QuicConnectionHelperPeer;
-}  // namespace test
-
 class NET_EXPORT_PRIVATE QuicConnectionHelper
     : public QuicConnectionHelperInterface {
  public:
   QuicConnectionHelper(base::TaskRunner* task_runner,
                        const QuicClock* clock,
-                       QuicRandom* random_generator,
-                       DatagramClientSocket* socket);
+                       QuicRandom* random_generator);
 
   virtual ~QuicConnectionHelper();
 
   // QuicConnectionHelperInterface
-  virtual void SetConnection(QuicConnection* connection) OVERRIDE;
   virtual const QuicClock* GetClock() const OVERRIDE;
   virtual QuicRandom* GetRandomGenerator() OVERRIDE;
-  virtual WriteResult WritePacketToWire(
-      const QuicEncryptedPacket& packet) OVERRIDE;
-  virtual bool IsWriteBlockedDataBuffered() OVERRIDE;
   virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) OVERRIDE;
 
  private:
-  friend class test::QuicConnectionHelperPeer;
-
-  // A completion callback invoked when a write completes.
-  void OnWriteComplete(int rv);
-
   base::WeakPtrFactory<QuicConnectionHelper> weak_factory_;
   base::TaskRunner* task_runner_;
-  DatagramClientSocket* socket_;
-  QuicConnection* connection_;
   const QuicClock* clock_;
   QuicRandom* random_generator_;
 
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 22b8e7d..d3d97e5 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -10,6 +10,7 @@
 #include "net/quic/crypto/quic_decrypter.h"
 #include "net/quic/crypto/quic_encrypter.h"
 #include "net/quic/quic_connection.h"
+#include "net/quic/quic_default_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
@@ -49,8 +50,10 @@
  public:
   TestConnection(QuicGuid guid,
                  IPEndPoint address,
-                 QuicConnectionHelper* helper)
-      : QuicConnection(guid, address, helper, false, QuicVersionMax()) {
+                 QuicConnectionHelper* helper,
+                 QuicPacketWriter* writer)
+      : QuicConnection(guid, address, helper, writer, false,
+                       QuicSupportedVersions()) {
   }
 
   void SendAck() {
@@ -77,7 +80,7 @@
 
   QuicConnectionHelperTest()
       : guid_(2),
-        framer_(QuicVersionMax(), QuicTime::Zero(), false),
+        framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         net_log_(BoundNetLog()),
         frame_(1, false, 0, kData) {
     Initialize();
@@ -119,19 +122,21 @@
                                           net_log_.net_log()));
     socket_->Connect(IPEndPoint());
     runner_ = new TestTaskRunner(&clock_);
-    helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
-                                       &random_generator_, socket_.get());
+    helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
+                                           &random_generator_));
     send_algorithm_ = new testing::StrictMock<MockSendAlgorithm>();
     EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _, _)).
         WillRepeatedly(Return(QuicTime::Delta::Zero()));
-    EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
-        Return(QuicBandwidth::FromKBitsPerSecond(100)));
-    EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(
-        Return(QuicTime::Delta::FromMilliseconds(100)));
+    EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(Return(
+        QuicBandwidth::FromKBitsPerSecond(100)));
+    EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(Return(
+        QuicTime::Delta::FromMilliseconds(100)));
     ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
         .WillByDefault(Return(true));
     EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
-    connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_));
+    writer_.reset(new QuicDefaultPacketWriter(socket_.get()));
+    connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_.get(),
+                                         writer_.get()));
     connection_->set_visitor(&visitor_);
     connection_->SetSendAlgorithm(send_algorithm_);
   }
@@ -196,13 +201,14 @@
 
   testing::StrictMock<MockSendAlgorithm>* send_algorithm_;
   scoped_refptr<TestTaskRunner> runner_;
-  QuicConnectionHelper* helper_;
+  scoped_ptr<QuicConnectionHelper> helper_;
+  scoped_ptr<TestConnection> connection_;
+  testing::StrictMock<MockConnectionVisitor> visitor_;
+  scoped_ptr<QuicDefaultPacketWriter> writer_;
   scoped_ptr<MockUDPClientSocket> socket_;
   scoped_ptr<MockWrite[]> mock_writes_;
   MockClock clock_;
   MockRandom random_generator_;
-  scoped_ptr<TestConnection> connection_;
-  testing::StrictMock<MockConnectionVisitor> visitor_;
 
  private:
   void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
@@ -350,15 +356,15 @@
       QuicTime::Delta::FromMilliseconds(500);
   QuicTime start = clock_.ApproximateNow();
 
+  char buffer[] = "foo";
+
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, NOT_RETRANSMISSION, _));
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
   EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true));
   EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
-
-  // Send a packet.
-  struct iovec iov = {const_cast<char*>(kData),
-                      static_cast<size_t>(strlen(kData))};
-  connection_->SendvStreamData(1, &iov, 1, 0, false);
+  IOVector data;
+  data.Append(buffer, 3);
+  connection_->SendStreamData(1, data, 0, false);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, RTO_RETRANSMISSION, _));
   // Since no ack was received, the retransmission alarm will fire and
   // retransmit it.
@@ -382,15 +388,16 @@
       QuicTime::Delta::FromMilliseconds(500);
   QuicTime start = clock_.ApproximateNow();
 
+  char buffer[] = "foo";
+
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, NOT_RETRANSMISSION, _));
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
   EXPECT_CALL(visitor_, OnCanWrite()).WillRepeatedly(Return(true));
   EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
 
-  // Send a packet.
-  struct iovec iov = {const_cast<char*>(kData),
-                      static_cast<size_t>(strlen(kData))};
-  connection_->SendvStreamData(1, &iov, 1, 0, false);
+  IOVector data;
+  data.Append(buffer, 3);
+  connection_->SendStreamData(1, data, 0, false);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, RTO_RETRANSMISSION, _));
   // Since no ack was received, the retransmission alarm will fire and
   // retransmit it.
@@ -425,7 +432,7 @@
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillOnce(
       Return(QuicTime::Delta::FromMicroseconds(1)));
   // After we run the next task, we should close the connection.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
 
   runner_->RunNextTask();
   EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(
@@ -435,30 +442,6 @@
   EXPECT_TRUE(AtEof());
 }
 
-TEST_F(QuicConnectionHelperTest, WritePacketToWire) {
-  AddWrite(SYNCHRONOUS, ConstructDataPacket(1));
-  Initialize();
-
-  int len = GetWrite(0)->length();
-  WriteResult result = helper_->WritePacketToWire(*GetWrite(0));
-  EXPECT_EQ(len, result.bytes_written);
-  EXPECT_EQ(WRITE_STATUS_OK, result.status);
-  EXPECT_TRUE(AtEof());
-}
-
-// TODO(rtenneti): rewrite WritePacketToWireAsync after merging all changes.
-TEST_F(QuicConnectionHelperTest, DISABLED_WritePacketToWireAsync) {
-  AddWrite(ASYNC, ConstructClosePacket(1, 0));
-  Initialize();
-
-  EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true));
-  WriteResult result = helper_->WritePacketToWire(*GetWrite(0));
-  EXPECT_EQ(-1, result.bytes_written);
-  EXPECT_EQ(WRITE_STATUS_BLOCKED, result.status);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(AtEof());
-}
-
 TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
   AddWrite(SYNCHRONOUS, ConstructAckPacket(1));
   AddWrite(SYNCHRONOUS, ConstructClosePacket(2, 1));
@@ -487,7 +470,8 @@
   EXPECT_TRUE(connection_->connected());
 
   // This time, we should time out.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
+  EXPECT_CALL(visitor_,
+              OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, NOT_RETRANSMISSION,
                                              HAS_RETRANSMITTABLE_DATA));
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillOnce(
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 6152293..9443c03 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -183,7 +183,7 @@
   return dict;
 }
 
-base::Value* NetLogQuicConnectionClosedCallback(
+base::Value* NetLogQuicOnConnectionClosedCallback(
     QuicErrorCode error,
     bool from_peer,
     NetLog::LogLevel /* log_level */) {
@@ -416,11 +416,11 @@
       base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
 }
 
-void QuicConnectionLogger::OnConnectionClose(QuicErrorCode error,
-                                             bool from_peer) {
+void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error,
+                                              bool from_peer) {
   net_log_.AddEvent(
       NetLog::TYPE_QUIC_SESSION_CLOSED,
-      base::Bind(&NetLogQuicConnectionClosedCallback, error, from_peer));
+      base::Bind(&NetLogQuicOnConnectionClosedCallback, error, from_peer));
 }
 
 void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index a7a8747..d162282 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -56,7 +56,7 @@
       const CryptoHandshakeMessage& message);
   void OnCryptoHandshakeMessageSent(
       const CryptoHandshakeMessage& message);
-  void OnConnectionClose(QuicErrorCode error, bool from_peer);
+  void OnConnectionClosed(QuicErrorCode error, bool from_peer);
   void OnSuccessfulVersionNegotiation(const QuicVersion& version);
 
  private:
diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc
index f66a5cb..500b5f3 100644
--- a/net/quic/quic_connection_stats.cc
+++ b/net/quic/quic_connection_stats.cc
@@ -4,13 +4,17 @@
 
 #include "net/quic/quic_connection_stats.h"
 
+using std::ostream;
+
 namespace net {
 
 QuicConnectionStats::QuicConnectionStats()
     : bytes_sent(0),
       packets_sent(0),
+      stream_bytes_sent(0),
       bytes_received(0),
       packets_received(0),
+      stream_bytes_received(0),
       bytes_retransmitted(0),
       packets_retransmitted(0),
       packets_revived(0),
@@ -22,4 +26,22 @@
 
 QuicConnectionStats::~QuicConnectionStats() {}
 
+ostream& operator<<(ostream& os, const QuicConnectionStats& s) {
+  os << "{ bytes sent: " << s.bytes_sent
+     << ", packets sent:" << s.packets_sent
+     << ", stream bytes sent: " << s.stream_bytes_sent
+     << ", bytes received: " << s.bytes_received
+     << ", packets received: " << s.packets_received
+     << ", stream bytes received: " << s.stream_bytes_received
+     << ", bytes retransmitted: " << s.bytes_retransmitted
+     << ", packets retransmitted: " << s.packets_retransmitted
+     << ", packets revived: " << s.packets_revived
+     << ", packets dropped:" << s.packets_dropped
+     << ", rto count: " << s.rto_count
+     << ", rtt(us): " << s.rtt
+     << ", estimated_bandwidth: " << s.estimated_bandwidth
+     << "}\n";
+  return os;
+}
+
 }  // namespace net
diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h
index f933662..b0761d9 100644
--- a/net/quic/quic_connection_stats.h
+++ b/net/quic/quic_connection_stats.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_QUIC_CONNECTION_STATS_H_
 #define NET_QUIC_QUIC_CONNECTION_STATS_H_
 
+#include <ostream>
+
 #include "base/basictypes.h"
 #include "net/base/net_export.h"
 
@@ -15,23 +17,26 @@
 // 3. CHLO sent to SHLO received time.
 // 4. Number of migrations.
 // 5. Number of out of order packets.
-// 6. Avg packet size.
-// 7. Number of connections that require more that 1-RTT.
-// 8. Avg number of streams / session.
-// 9. Number of duplicates received.
-// 10. Fraction of traffic sent/received that was not data (protocol overhead).
-// 11. Fraction of data transferred that was padding.
+// 6. Number of connections that require more that 1-RTT.
+// 7. Avg number of streams / session.
+// 8. Number of duplicates received.
+// 9. Fraction of data transferred that was padding.
 
 // Structure to hold stats for a QuicConnection.
 struct NET_EXPORT_PRIVATE QuicConnectionStats {
   QuicConnectionStats();
   ~QuicConnectionStats();
 
+  NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+      std::ostream& os, const QuicConnectionStats& s);
+
   uint64 bytes_sent;  // includes retransmissions, fec.
   uint32 packets_sent;
+  uint64 stream_bytes_sent;  // non-retransmitted bytes sent in a stream frame.
 
   uint64 bytes_received;  // includes duplicate data for a stream, fec.
   uint32 packets_received;  // includes dropped packets
+  uint64 stream_bytes_received;  // bytes received in a stream frame.
 
   uint64 bytes_retransmitted;
   uint32 packets_retransmitted;
@@ -40,7 +45,7 @@
   uint32 packets_dropped;  // duplicate or less than least unacked.
   uint32 rto_count;
 
-  uint32 rtt;
+  uint32 rtt;  // In microseconds
   uint64 estimated_bandwidth;
   // TODO(satyamshekhar): Add window_size, mss and mtu.
 };
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 5e0e86e..2433648 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -6,6 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/stl_util.h"
 #include "net/base/net_errors.h"
 #include "net/quic/congestion_control/receive_algorithm_interface.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
@@ -242,19 +243,11 @@
 
   TestConnectionHelper(MockClock* clock, MockRandom* random_generator)
       : clock_(clock),
-        random_generator_(random_generator),
-        last_packet_size_(0),
-        blocked_(false),
-        is_write_blocked_data_buffered_(false),
-        is_server_(true),
-        use_tagging_decrypter_(false),
-        packets_write_attempts_(0) {
+        random_generator_(random_generator) {
     clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   // QuicConnectionHelperInterface
-  virtual void SetConnection(QuicConnection* connection) OVERRIDE {}
-
   virtual const QuicClock* GetClock() const OVERRIDE {
     return clock_;
   }
@@ -263,8 +256,39 @@
     return random_generator_;
   }
 
-  virtual WriteResult WritePacketToWire(
-      const QuicEncryptedPacket& packet) OVERRIDE {
+  virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) OVERRIDE {
+    return new TestAlarm(delegate);
+  }
+
+ private:
+  MockClock* clock_;
+  MockRandom* random_generator_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
+};
+
+class TestPacketWriter : public QuicPacketWriter {
+ public:
+  TestPacketWriter()
+      : last_packet_size_(0),
+        blocked_(false),
+        is_write_blocked_data_buffered_(false),
+        is_server_(true),
+        use_tagging_decrypter_(false),
+        packets_write_attempts_(0) {
+  }
+
+  virtual ~TestPacketWriter() {
+    STLDeleteElements(&stream_data_);
+  }
+
+  // QuicPacketWriter
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const IPAddressNumber& self_address,
+      const IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
+    QuicEncryptedPacket packet(buffer, buf_len);
     ++packets_write_attempts_;
 
     if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
@@ -272,7 +296,7 @@
              sizeof(final_bytes_of_last_packet_));
     }
 
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), is_server_);
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), !is_server_);
     if (use_tagging_decrypter_) {
       framer.SetDecrypter(new TaggingDecrypter);
     }
@@ -289,6 +313,12 @@
     }
     if (visitor.stream_frames() != NULL && !visitor.stream_frames()->empty()) {
       stream_frames_ = *visitor.stream_frames();
+      // Also make a copy of underlying data, since the data that the frames in
+      // |stream_frames_| point to is bound to the |visitor|'s scope.
+      for (size_t i = 0; i < stream_frames_.size(); ++i) {
+        stream_data_.push_back(new string(*visitor.stream_data()[i]));
+        stream_frames_[i].data = *(stream_data_.back());
+      }
     }
     if (visitor.version_negotiation_packet() != NULL) {
       version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(
@@ -301,14 +331,10 @@
     return WriteResult(WRITE_STATUS_OK, last_packet_size_);
   }
 
-  virtual bool IsWriteBlockedDataBuffered() OVERRIDE {
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
     return is_write_blocked_data_buffered_;
   }
 
-  virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) OVERRIDE {
-    return new TestAlarm(delegate);
-  }
-
   QuicPacketHeader* header() { return &header_; }
 
   size_t frame_count() const { return frame_count_; }
@@ -350,13 +376,12 @@
   uint32 packets_write_attempts() { return packets_write_attempts_; }
 
  private:
-  MockClock* clock_;
-  MockRandom* random_generator_;
   QuicPacketHeader header_;
   size_t frame_count_;
   scoped_ptr<QuicAckFrame> ack_;
   scoped_ptr<QuicCongestionFeedbackFrame> feedback_;
   vector<QuicStreamFrame> stream_frames_;
+  vector<string*> stream_data_;
   scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
   size_t last_packet_size_;
   bool blocked_;
@@ -366,7 +391,7 @@
   bool use_tagging_decrypter_;
   uint32 packets_write_attempts_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
+  DISALLOW_COPY_AND_ASSIGN(TestPacketWriter);
 };
 
 class TestConnection : public QuicConnection {
@@ -374,10 +399,13 @@
   TestConnection(QuicGuid guid,
                  IPEndPoint address,
                  TestConnectionHelper* helper,
+                 TestPacketWriter* writer,
                  bool is_server)
-      : QuicConnection(guid, address, helper, is_server, QuicVersionMax()),
-        helper_(helper) {
-    helper_->set_is_server(!is_server);
+      : QuicConnection(guid, address, helper, writer, is_server,
+                       QuicSupportedVersions()),
+        helper_(helper),
+        writer_(writer) {
+    writer_->set_is_server(is_server);
   }
 
   void SendAck() {
@@ -405,33 +433,38 @@
                          packet, entropy_hash, retransmittable_frames));
   }
 
-  QuicConsumedData SendStreamData(QuicStreamId id,
-                                  StringPiece data,
-                                  QuicStreamOffset offset,
-                                  bool fin) {
-    struct iovec iov = {const_cast<char*>(data.data()),
-                        static_cast<size_t>(data.size())};
-    return SendvStreamData(id, &iov, 1, offset, fin);
+  QuicConsumedData SendStreamDataWithString(QuicStreamId id,
+                                            StringPiece data,
+                                            QuicStreamOffset offset,
+                                            bool fin) {
+    IOVector data_iov;
+    if (!data.empty()) {
+      data_iov.Append(const_cast<char*>(data.data()), data.size());
+    }
+    return QuicConnection::SendStreamData(id, data_iov, offset, fin);
   }
 
-  QuicConsumedData SendStreamDataAndNotifyWhenAcked(
+  QuicConsumedData SendStreamDataWithStringAndNotifyWhenAcked(
       QuicStreamId id,
       StringPiece data,
       QuicStreamOffset offset,
       bool fin,
       QuicAckNotifier::DelegateInterface* delegate) {
-    struct iovec iov = {const_cast<char*>(data.data()),
-                        static_cast<size_t>(data.size())};
-    return SendvStreamDataAndNotifyWhenAcked(id, &iov, 1, offset, fin,
-                                             delegate);
+    IOVector data_iov;
+    if (!data.empty()) {
+      data_iov.Append(const_cast<char*>(data.data()), data.size());
+    }
+    return QuicConnection::SendStreamDataAndNotifyWhenAcked(id, data_iov,
+                                                            offset, fin,
+                                                            delegate);
   }
 
   QuicConsumedData SendStreamData3() {
-    return SendStreamData(kStreamId3, "food", 0, !kFin);
+    return SendStreamDataWithString(kStreamId3, "food", 0, !kFin);
   }
 
   QuicConsumedData SendStreamData5() {
-    return SendStreamData(kStreamId5, "food2", 0, !kFin);
+    return SendStreamDataWithString(kStreamId5, "food2", 0, !kFin);
   }
 
   // The crypto stream has special semantics so that it is not blocked by a
@@ -442,7 +475,7 @@
   QuicConsumedData SendCryptoStreamData() {
     this->Flush();
     QuicConsumedData consumed =
-        SendStreamData(kCryptoStreamId, "chlo", 0, !kFin);
+        SendStreamDataWithString(kCryptoStreamId, "chlo", 0, !kFin);
     this->Flush();
     return consumed;
   }
@@ -456,7 +489,7 @@
   }
 
   void set_is_server(bool is_server) {
-    helper_->set_is_server(!is_server);
+    writer_->set_is_server(is_server);
     QuicPacketCreatorPeer::SetIsServer(
         QuicConnectionPeer::GetPacketCreator(this), is_server);
     QuicConnectionPeer::SetIsServer(this, is_server);
@@ -491,6 +524,7 @@
 
  private:
   TestConnectionHelper* helper_;
+  TestPacketWriter* writer_;
 
   DISALLOW_COPY_AND_ASSIGN(TestConnection);
 };
@@ -499,16 +533,16 @@
  protected:
   QuicConnectionTest()
       : guid_(42),
-        framer_(QuicVersionMax(), QuicTime::Zero(), false),
+        framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         creator_(guid_, &framer_, QuicRandom::GetInstance(), false),
         send_algorithm_(new StrictMock<MockSendAlgorithm>),
         helper_(new TestConnectionHelper(&clock_, &random_generator_)),
-        connection_(guid_, IPEndPoint(), helper_, false),
+        writer_(new TestPacketWriter()),
+        connection_(guid_, IPEndPoint(), helper_.get(), writer_.get(), false),
         frame1_(1, false, 0, data1),
         frame2_(1, false, 3, data2),
         accept_packet_(true) {
     // TODO(rtenneti): remove g_* flags.
-    QuicConnection::g_acks_do_not_instigate_acks = true;
     FLAGS_track_retransmission_history = true;
     connection_.set_visitor(&visitor_);
     connection_.SetSendAlgorithm(send_algorithm_);
@@ -534,11 +568,6 @@
         Return(true));
   }
 
-  ~QuicConnectionTest() {
-    // TODO(rch): remove this.
-    QuicConnection::g_acks_do_not_instigate_acks = false;
-  }
-
   void SetUp() {
     FLAGS_bundle_ack_with_outgoing_packet = GetParam();
   }
@@ -549,27 +578,27 @@
   }
 
   QuicAckFrame* last_ack() {
-    return helper_->ack();
+    return writer_->ack();
   }
 
   QuicCongestionFeedbackFrame* last_feedback() {
-    return helper_->feedback();
+    return writer_->feedback();
   }
 
   QuicPacketHeader* last_header() {
-    return helper_->header();
+    return writer_->header();
   }
 
   size_t last_sent_packet_size() {
-    return helper_->last_packet_size();
+    return writer_->last_packet_size();
   }
 
   uint32 final_bytes_of_last_packet() {
-    return helper_->final_bytes_of_last_packet();
+    return writer_->final_bytes_of_last_packet();
   }
 
   void use_tagging_decrypter() {
-    helper_->use_tagging_decrypter();
+    writer_->use_tagging_decrypter();
   }
 
   void ProcessPacket(QuicPacketSequenceNumber number) {
@@ -683,13 +712,15 @@
     return encrypted->length();
   }
 
-  QuicByteCount SendStreamDataToPeer(QuicStreamId id, StringPiece data,
-                                     QuicStreamOffset offset, bool fin,
+  QuicByteCount SendStreamDataToPeer(QuicStreamId id,
+                                     StringPiece data,
+                                     QuicStreamOffset offset,
+                                     bool fin,
                                      QuicPacketSequenceNumber* last_packet) {
     QuicByteCount packet_size;
     EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
         .WillOnce(DoAll(SaveArg<2>(&packet_size), Return(true)));
-    connection_.SendStreamData(id, data, offset, fin);
+    connection_.SendStreamDataWithString(id, data, offset, fin);
     if (last_packet != NULL) {
       *last_packet =
           QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number();
@@ -784,7 +815,8 @@
   TestReceiveAlgorithm* receive_algorithm_;
   MockClock clock_;
   MockRandom random_generator_;
-  TestConnectionHelper* helper_;
+  scoped_ptr<TestConnectionHelper> helper_;
+  scoped_ptr<TestPacketWriter> writer_;
   TestConnection connection_;
   StrictMock<MockConnectionVisitor> visitor_;
 
@@ -900,7 +932,7 @@
 TEST_P(QuicConnectionTest, RejectPacketTooFarOut) {
   // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
   // packet call to the visitor.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_PACKET_HEADER, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
   ProcessDataPacket(6000, 0, !kEntropyFlag);
 }
 
@@ -958,19 +990,19 @@
 
   ProcessPacket(3);
   // Should ack immediately since we have missing packets.
-  EXPECT_EQ(1u, helper_->packets_write_attempts());
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
 
   ProcessPacket(2);
   // Should ack immediately since we have missing packets.
-  EXPECT_EQ(2u, helper_->packets_write_attempts());
+  EXPECT_EQ(2u, writer_->packets_write_attempts());
 
   ProcessPacket(1);
   // Should ack immediately, since this fills the last hole.
-  EXPECT_EQ(3u, helper_->packets_write_attempts());
+  EXPECT_EQ(3u, writer_->packets_write_attempts());
 
   ProcessPacket(4);
   // Should not cause an ack.
-  EXPECT_EQ(3u, helper_->packets_write_attempts());
+  EXPECT_EQ(3u, writer_->packets_write_attempts());
 }
 
 TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
@@ -982,7 +1014,7 @@
       .WillOnce(DoAll(SaveArg<1>(&original), SaveArg<2>(&packet_size),
                       Return(true)));
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   QuicAckFrame frame(original, QuicTime::Zero(), 1);
   frame.received_info.missing_packets.insert(original);
   frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
@@ -1040,7 +1072,7 @@
 
   // Now claim it's one, but set the ordering so it was sent "after" the first
   // one.  This should cause a connection error.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   creator_.set_sequence_number(7);
   ProcessAckPacket(&frame2);
@@ -1062,14 +1094,14 @@
 
   // Now change it to 1, and it should cause a connection error.
   QuicAckFrame frame2(1, QuicTime::Zero(), 0);
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
   EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
   ProcessAckPacket(&frame2);
 }
 
 TEST_P(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   // Create an ack with least_unacked is 2 in packet number 1.
   creator_.set_sequence_number(0);
@@ -1086,7 +1118,7 @@
   SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
   SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
 
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   QuicAckFrame frame(0, QuicTime::Zero(), 1);
   frame.received_info.missing_packets.insert(3);
@@ -1096,7 +1128,7 @@
 
 TEST_P(QuicConnectionTest, AckUnsentData) {
   // Ack a packet which has not been sent.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   QuicAckFrame frame(1, QuicTime::Zero(), 0);
@@ -1279,8 +1311,8 @@
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
   // The first stream frame will consume 2 fewer bytes than the other three.
   const string payload(payload_length * 4 - 6, 'a');
-  connection_.SendStreamData(1, payload, 0, !kFin);
-  // Expect the FEC group to be closed after SendStreamData.
+  connection_.SendStreamDataWithString(1, payload, 0, !kFin);
+  // Expect the FEC group to be closed after SendStreamDataWithString.
   EXPECT_FALSE(creator_.ShouldSendFec(true));
 }
 
@@ -1295,9 +1327,9 @@
   connection_.options()->max_packets_per_fec_group = 2;
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
   const string payload(payload_length, 'a');
-  connection_.SendStreamData(1, payload, 0, !kFin);
+  connection_.SendStreamDataWithString(1, payload, 0, !kFin);
   EXPECT_FALSE(creator_.ShouldSendFec(true));
   // Expect the first data packet and the fec packet to be queued.
   EXPECT_EQ(2u, connection_.NumQueuedPackets());
@@ -1307,7 +1339,7 @@
   connection_.options()->max_packets_per_fec_group = 1;
   // 1 Data and 1 FEC packet.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
 
   const QuicTime::Delta retransmission_time =
       QuicTime::Delta::FromMilliseconds(5000);
@@ -1327,7 +1359,7 @@
 
   // 1 Data and 1 FEC packet.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
 
   QuicAckFrame ack_fec(2, QuicTime::Zero(), 1);
   // Data packet missing.
@@ -1374,11 +1406,11 @@
 
   // Parse the last packet and ensure it's an ack and two stream frames from
   // two different streams.
-  EXPECT_EQ(3u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
-  EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(kStreamId3, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(kStreamId5, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(3u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
+  EXPECT_EQ(2u, writer_->stream_frames()->size());
+  EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
 }
 
 TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
@@ -1405,10 +1437,10 @@
   EXPECT_FALSE(connection_.HasQueuedData());
 
   // Parse the last packet and ensure it's the crypto stream frame.
-  EXPECT_EQ(1u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
-  EXPECT_EQ(1u, helper_->stream_frames()->size());
-  EXPECT_EQ(kCryptoStreamId, (*helper_->stream_frames())[0].stream_id);
+  EXPECT_EQ(1u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
+  EXPECT_EQ(1u, writer_->stream_frames()->size());
+  EXPECT_EQ(kCryptoStreamId, (*writer_->stream_frames())[0].stream_id);
 }
 
 TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
@@ -1435,10 +1467,10 @@
   EXPECT_FALSE(connection_.HasQueuedData());
 
   // Parse the last packet and ensure it's the stream frame from stream 3.
-  EXPECT_EQ(1u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
-  EXPECT_EQ(1u, helper_->stream_frames()->size());
-  EXPECT_EQ(kStreamId3, (*helper_->stream_frames())[0].stream_id);
+  EXPECT_EQ(1u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
+  EXPECT_EQ(1u, writer_->stream_frames()->size());
+  EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
 }
 
 TEST_P(QuicConnectionTest, FramePackingFEC) {
@@ -1465,8 +1497,47 @@
   EXPECT_FALSE(connection_.HasQueuedData());
 
   // Parse the last packet and ensure it's in an fec group.
-  EXPECT_EQ(1u, helper_->header()->fec_group);
-  EXPECT_EQ(0u, helper_->frame_count());
+  EXPECT_EQ(1u, writer_->header()->fec_group);
+  EXPECT_EQ(0u, writer_->frame_count());
+}
+
+TEST_P(QuicConnectionTest, FramePackingAckResponse) {
+  if (!GetParam()) {
+    // This test depends on BundleAckWithPacket being true.
+    return;
+  }
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+  // Process a data packet to queue up a pending ack.
+  EXPECT_CALL(visitor_, OnStreamFrames(_)).WillOnce(Return(true));
+  ProcessDataPacket(1, 1, kEntropyFlag);
+
+  EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendStreamData3)),
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendStreamData5)),
+      Return(true)));
+
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, NOT_RETRANSMISSION, _))
+      .Times(1);
+
+  // Process an ack to cause the visitor's OnCanWrite to be invoked.
+  creator_.set_sequence_number(2);
+  QuicAckFrame ack_one(0, QuicTime::Zero(), 0);
+  ProcessAckPacket(&ack_one);
+
+  EXPECT_EQ(0u, connection_.NumQueuedPackets());
+  EXPECT_FALSE(connection_.HasQueuedData());
+
+  // Parse the last packet and ensure it's an ack and two stream frames from
+  // two different streams.
+  EXPECT_EQ(3u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
+  ASSERT_EQ(2u, writer_->stream_frames()->size());
+  EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
 }
 
 TEST_P(QuicConnectionTest, FramePackingSendv) {
@@ -1474,30 +1545,34 @@
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
 
   char data[] = "ABCD";
-  iovec iov[2] = { {static_cast<void*>(data), 2},
-      {static_cast<void*>(data + 2), 2} };
-  connection_.SendvStreamData(1, iov, 2, 0, !kFin);
+  IOVector data_iov;
+  data_iov.AppendNoCoalesce(data, 2);
+  data_iov.AppendNoCoalesce(data + 2, 2);
+  connection_.SendStreamData(1, data_iov, 0, !kFin);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
 
   // Parse the last packet and ensure it's two stream frames from one stream.
   // TODO(ianswett): Ideally this would arrive in one frame in the future.
-  EXPECT_EQ(2u, helper_->frame_count());
-  EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(2u, writer_->frame_count());
+  EXPECT_EQ(2u, writer_->stream_frames()->size());
+  EXPECT_EQ(1u, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_EQ(1u, (*writer_->stream_frames())[1].stream_id);
+  EXPECT_EQ("AB", (*writer_->stream_frames())[0].data.as_string());
+  EXPECT_EQ("CD", (*writer_->stream_frames())[1].data.as_string());
 }
 
 TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
   // Try to send two stream frames in 1 packet by using writev.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
 
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
   char data[] = "ABCD";
-  iovec iov[2] = { {static_cast<void*>(data), 2},
-      {static_cast<void*>(data + 2), 2} };
-  connection_.SendvStreamData(1, iov, 2, 0, !kFin);
+  IOVector data_iov;
+  data_iov.AppendNoCoalesce(data, 2);
+  data_iov.AppendNoCoalesce(data + 2, 2);
+  connection_.SendStreamData(1, data_iov, 0, !kFin);
 
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
   EXPECT_TRUE(connection_.HasQueuedData());
@@ -1508,34 +1583,33 @@
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
   // Unblock the writes and actually send.
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   EXPECT_TRUE(connection_.OnCanWrite());
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
 
   // Parse the last packet and ensure it's two stream frames from one stream.
   // TODO(ianswett): Ideally this would arrive in one frame in the future.
-  EXPECT_EQ(2u, helper_->frame_count());
-  EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(2u, writer_->frame_count());
+  EXPECT_EQ(2u, writer_->stream_frames()->size());
+  EXPECT_EQ(1u, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_EQ(1u, (*writer_->stream_frames())[1].stream_id);
 }
 
 TEST_P(QuicConnectionTest, SendingZeroBytes) {
   // Send a zero byte write with a fin using writev.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
-
-  iovec iov[1];
-  connection_.SendvStreamData(1, iov, 0, 0, kFin);
+  IOVector empty_iov;
+  connection_.SendStreamData(1, empty_iov, 0, kFin);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
 
   // Parse the last packet and ensure it's two stream frames from one stream.
   // TODO(ianswett): Ideally this would arrive in one frame in the future.
-  EXPECT_EQ(1u, helper_->frame_count());
-  EXPECT_EQ(1u, helper_->stream_frames()->size());
-  EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_TRUE((*helper_->stream_frames())[0].fin);
+  EXPECT_EQ(1u, writer_->frame_count());
+  EXPECT_EQ(1u, writer_->stream_frames()->size());
+  EXPECT_EQ(1u, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_TRUE((*writer_->stream_frames())[0].fin);
 }
 
 TEST_P(QuicConnectionTest, OnCanWrite) {
@@ -1555,10 +1629,10 @@
   connection_.OnCanWrite();
   // Parse the last packet and ensure it's the two stream frames from
   // two different streams.
-  EXPECT_EQ(2u, helper_->frame_count());
-  EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(kStreamId3, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(kStreamId5, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(2u, writer_->frame_count());
+  EXPECT_EQ(2u, writer_->stream_frames()->size());
+  EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
+  EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
 }
 
 TEST_P(QuicConnectionTest, RetransmitOnNack) {
@@ -1634,7 +1708,7 @@
 
   // The third nack should trigger a retransimission, but we'll be
   // write blocked, so the packet will be queued.
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
 
   ProcessAckPacket(&nack_two);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1651,7 +1725,7 @@
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, _, _, _, _)).Times(0);
 
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   connection_.OnCanWrite();
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1666,7 +1740,7 @@
       .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size),
                       Return(true)));
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   QuicAckFrame frame(1, QuicTime::Zero(), largest_observed);
   frame.received_info.missing_packets.insert(largest_observed);
   frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
@@ -1683,11 +1757,11 @@
 TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) {
   for (int i = 0; i < 10; ++i) {
     EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-    connection_.SendStreamData(1, "foo", i * 3, !kFin);
+    connection_.SendStreamDataWithString(1, "foo", i * 3, !kFin);
   }
 
   // Block the congestion window and ensure they're queued.
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
   clock_.AdvanceTime(DefaultRetransmissionTime());
   // Only one packet should be retransmitted.
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(10);
@@ -1695,7 +1769,7 @@
   EXPECT_TRUE(connection_.HasQueuedData());
 
   // Unblock the congestion window.
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
       2 * DefaultRetransmissionTime().ToMicroseconds()));
   // Retransmit already retransmitted packets event though the sequence number
@@ -1705,6 +1779,18 @@
   connection_.OnCanWrite();
 }
 
+TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
+  writer_->set_blocked(true);
+
+  writer_->set_is_write_blocked_data_buffered(true);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+  connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0));
+  EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+}
+
 TEST_P(QuicConnectionTest, ResumptionAlarmThenWriteBlocked) {
   // Set the send and resumption alarm, then block the connection.
   connection_.GetResumeWritesAlarm()->Set(clock_.ApproximateNow());
@@ -1717,18 +1803,6 @@
   EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_));
 }
 
-TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
-  helper_->set_blocked(true);
-
-  helper_->set_is_write_blocked_data_buffered(true);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
-  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
-
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-  connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0));
-  EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-}
-
 TEST_P(QuicConnectionTest, LimitPacketsPerNack) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1);
@@ -1944,9 +2018,9 @@
   // Attempt to send a handshake message while the congestion manager
   // does not permit sending.
   EXPECT_CALL(*send_algorithm_,
-              TimeUntilSend(_, _, _, _)).WillRepeatedly(
+              TimeUntilSend(_, _, _, IS_HANDSHAKE)).WillRepeatedly(
                   testing::Return(QuicTime::Delta::Infinite()));
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   // The packet should be serialized, but not queued.
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
@@ -1956,7 +2030,7 @@
 
   // Now become writeable and flush the packets.
   EXPECT_CALL(*send_algorithm_,
-              TimeUntilSend(_, _, _, _)).WillRepeatedly(
+              TimeUntilSend(_, _, _, IS_HANDSHAKE)).WillRepeatedly(
                   testing::Return(QuicTime::Delta::Zero()));
   EXPECT_CALL(visitor_, OnCanWrite());
   connection_.OnCanWrite();
@@ -2040,11 +2114,11 @@
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).WillOnce(
       DoAll(SaveArg<2>(&first_packet_size), Return(true)));
 
-  connection_.SendStreamData(1, "first_packet", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "first_packet", 0, !kFin);
   QuicByteCount second_packet_size;
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).WillOnce(
       DoAll(SaveArg<2>(&second_packet_size), Return(true)));
-  connection_.SendStreamData(1, "second_packet", 12, !kFin);
+  connection_.SendStreamDataWithString(1, "second_packet", 12, !kFin);
   EXPECT_NE(first_packet_size, second_packet_size);
   // Advance the clock by huge time to make sure packets will be retransmitted.
   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
@@ -2076,7 +2150,7 @@
   QuicPacketSequenceNumber original_sequence_number;
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _))
       .WillOnce(DoAll(SaveArg<1>(&original_sequence_number), Return(true)));
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
 
   EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
       &connection_, original_sequence_number));
@@ -2126,13 +2200,13 @@
 }
 
 TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
-  helper_->set_blocked(true);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  writer_->set_blocked(true);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   // Make sure that RTO is not started when the packet is queued.
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
 
   // Test that RTO is started once we write to the socket.
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   connection_.OnCanWrite();
   EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
 }
@@ -2141,8 +2215,8 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _))
       .Times(2);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
-  connection_.SendStreamData(2, "bar", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(2, "bar", 0, !kFin);
   QuicAlarm* retransmission_alarm = connection_.GetRetransmissionAlarm();
   EXPECT_TRUE(retransmission_alarm->IsSet());
 
@@ -2178,8 +2252,8 @@
 
 TEST_P(QuicConnectionTest, TestQueued) {
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
-  helper_->set_blocked(true);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  writer_->set_blocked(true);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
   // Attempt to send all packets, but since we're actually still
@@ -2188,7 +2262,7 @@
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
   // Unblock the writes and actually send.
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   EXPECT_TRUE(connection_.OnCanWrite());
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
 }
@@ -2242,7 +2316,7 @@
 
 TEST_P(QuicConnectionTest, InitialTimeout) {
   EXPECT_TRUE(connection_.connected());
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
 
   QuicTime default_timeout = clock_.ApproximateNow().Add(
@@ -2283,7 +2357,7 @@
             connection_.GetTimeoutAlarm()->deadline());
 
   // This time, we should time out.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
@@ -2332,7 +2406,7 @@
 
 TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
   QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
   EXPECT_CALL(*send_algorithm_,
               TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
                   testing::Return(QuicTime::Delta::Zero()));
@@ -2369,7 +2443,7 @@
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, 1, _, NOT_RETRANSMISSION, _));
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   // Advance the time for retransmission of lost packet.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501));
@@ -2486,7 +2560,8 @@
                   testing::Return(QuicTime::Delta::FromMicroseconds(10)));
   const string payload(payload_length, 'a');
   EXPECT_EQ(0u,
-            connection_.SendStreamData(3, payload, 0, !kFin).bytes_consumed);
+            connection_.SendStreamDataWithString(3, payload, 0,
+                                                 !kFin).bytes_consumed);
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
 }
 
@@ -2503,7 +2578,8 @@
   // The first stream frame will consume 2 fewer bytes than the other six.
   const string payload(payload_length * 7 - 12, 'a');
   EXPECT_EQ(payload.size(),
-            connection_.SendStreamData(1, payload, 0, !kFin).bytes_consumed);
+            connection_.SendStreamDataWithString(1, payload, 0,
+                                                 !kFin).bytes_consumed);
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckOnTimer) {
@@ -2517,8 +2593,8 @@
   // Simulate delayed ack alarm firing.
   connection_.GetAckAlarm()->Fire();
   // Check that ack is sent and that delayed ack alarm is reset.
-  EXPECT_EQ(1u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
+  EXPECT_EQ(1u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -2527,8 +2603,8 @@
   ProcessPacket(1);
   ProcessPacket(2);
   // Check that ack is sent and that delayed ack alarm is reset.
-  EXPECT_EQ(1u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
+  EXPECT_EQ(1u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -2539,11 +2615,11 @@
   }
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   ProcessPacket(1);
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   // Check that ack is bundled with outgoing data and that delayed ack
   // alarm is reset.
-  EXPECT_EQ(2u, helper_->frame_count());
-  EXPECT_TRUE(helper_->ack());
+  EXPECT_EQ(2u, writer_->frame_count());
+  EXPECT_TRUE(writer_->ack());
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -2551,14 +2627,14 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   ProcessPacket(1);
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0);
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, true));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   ProcessClosePacket(2, 0);
 }
 
 TEST_P(QuicConnectionTest, SendWhenDisconnected) {
   EXPECT_TRUE(connection_.connected());
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, false));
   connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false);
   EXPECT_FALSE(connection_.connected());
   QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
@@ -2575,7 +2651,7 @@
   header.rejected_sequence_number = 10101;
   scoped_ptr<QuicEncryptedPacket> packet(
       framer_.BuildPublicResetPacket(header));
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_PUBLIC_RESET, true));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PUBLIC_RESET, true));
   connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *packet);
 }
 
@@ -2728,17 +2804,17 @@
   framer_.set_version(QuicVersionMax());
   connection_.set_is_server(true);
   connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
-  EXPECT_TRUE(helper_->version_negotiation_packet() != NULL);
+  EXPECT_TRUE(writer_->version_negotiation_packet() != NULL);
 
   size_t num_versions = arraysize(kSupportedQuicVersions);
   EXPECT_EQ(num_versions,
-            helper_->version_negotiation_packet()->versions.size());
+            writer_->version_negotiation_packet()->versions.size());
 
   // We expect all versions in kSupportedQuicVersions to be
   // included in the packet.
   for (size_t i = 0; i < num_versions; ++i) {
     EXPECT_EQ(kSupportedQuicVersions[i],
-              helper_->version_negotiation_packet()->versions[i]);
+              writer_->version_negotiation_packet()->versions[i]);
   }
 }
 
@@ -2764,27 +2840,59 @@
 
   framer_.set_version(QuicVersionMax());
   connection_.set_is_server(true);
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
   connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
-  EXPECT_EQ(0u, helper_->last_packet_size());
+  EXPECT_EQ(0u, writer_->last_packet_size());
   EXPECT_TRUE(connection_.HasQueuedData());
+  EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_));
 
-  helper_->set_blocked(false);
+  writer_->set_blocked(false);
   connection_.OnCanWrite();
-  EXPECT_TRUE(helper_->version_negotiation_packet() != NULL);
+  EXPECT_TRUE(writer_->version_negotiation_packet() != NULL);
 
   size_t num_versions = arraysize(kSupportedQuicVersions);
   EXPECT_EQ(num_versions,
-            helper_->version_negotiation_packet()->versions.size());
+            writer_->version_negotiation_packet()->versions.size());
 
   // We expect all versions in kSupportedQuicVersions to be
   // included in the packet.
   for (size_t i = 0; i < num_versions; ++i) {
     EXPECT_EQ(kSupportedQuicVersions[i],
-              helper_->version_negotiation_packet()->versions[i]);
+              writer_->version_negotiation_packet()->versions[i]);
   }
 }
 
+TEST_P(QuicConnectionTest,
+       ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) {
+  framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
+
+  QuicPacketHeader header;
+  header.public_header.guid = guid_;
+  header.public_header.reset_flag = false;
+  header.public_header.version_flag = true;
+  header.entropy_flag = false;
+  header.fec_flag = false;
+  header.packet_sequence_number = 12;
+  header.fec_group = 0;
+
+  QuicFrames frames;
+  QuicFrame frame(&frame1_);
+  frames.push_back(frame);
+  scoped_ptr<QuicPacket> packet(
+      framer_.BuildUnsizedDataPacket(header, frames).packet);
+  scoped_ptr<QuicEncryptedPacket> encrypted(
+      framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
+
+  framer_.set_version(QuicVersionMax());
+  connection_.set_is_server(true);
+  writer_->set_blocked(true);
+  writer_->set_is_write_blocked_data_buffered(true);
+  connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+  EXPECT_EQ(0u, writer_->last_packet_size());
+  EXPECT_FALSE(connection_.HasQueuedData());
+  EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_));
+}
+
 TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
   // Start out with some unsupported version.
   QuicConnectionPeer::GetFramer(&connection_)->set_version_for_tests(
@@ -2844,8 +2952,9 @@
 
   // Send a version negotiation packet with the version the client started with.
   // It should be rejected.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
-                                        false));
+  EXPECT_CALL(visitor_,
+              OnConnectionClosed(QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+                                 false));
   scoped_ptr<QuicEncryptedPacket> encrypted(
       framer_.BuildVersionNegotiationPacket(
           header.public_header, supported_versions));
@@ -2855,12 +2964,12 @@
 TEST_P(QuicConnectionTest, CheckSendStats) {
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
-  connection_.SendStreamData(1u, "first", 0, !kFin);
+  connection_.SendStreamDataWithString(1u, "first", 0, !kFin);
   size_t first_packet_size = last_sent_packet_size();
 
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
-  connection_.SendStreamData(1u, "second", 0, !kFin);
+  connection_.SendStreamDataWithString(1u, "second", 0, !kFin);
   size_t second_packet_size = last_sent_packet_size();
 
   // 2 retransmissions due to rto, 1 due to explicit nack.
@@ -2979,7 +3088,7 @@
   scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
       ENCRYPTION_NONE, 1, *packet));
 
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, true));
   EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(0);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
@@ -2988,8 +3097,8 @@
 
 TEST_P(QuicConnectionTest, SelectMutualVersion) {
   // Set the connection to speak the lowest quic version.
-  connection_.set_version(QuicVersionMin());
-  EXPECT_EQ(QuicVersionMin(), connection_.version());
+  connection_.set_version(test::QuicVersionMin());
+  EXPECT_EQ(test::QuicVersionMin(), connection_.version());
 
   // Pass in available versions which includes a higher mutually supported
   // version.  The higher mutually supported version should be selected.
@@ -3003,11 +3112,11 @@
   // Expect that the lowest version is selected.
   // Ensure the lowest supported version is less than the max, unless they're
   // the same.
-  EXPECT_LE(QuicVersionMin(), QuicVersionMax());
+  EXPECT_LE(test::QuicVersionMin(), QuicVersionMax());
   QuicVersionVector lowest_version_vector;
-  lowest_version_vector.push_back(QuicVersionMin());
+  lowest_version_vector.push_back(test::QuicVersionMin());
   EXPECT_TRUE(connection_.SelectMutualVersion(lowest_version_vector));
-  EXPECT_EQ(QuicVersionMin(), connection_.version());
+  EXPECT_EQ(test::QuicVersionMin(), connection_.version());
 
   // Shouldn't be able to find a mutually supported version.
   QuicVersionVector unsupported_version;
@@ -3016,41 +3125,41 @@
 }
 
 TEST_P(QuicConnectionTest, ConnectionCloseWhenNotWriteBlocked) {
-  helper_->set_blocked(false);  // Already default.
+  writer_->set_blocked(false);  // Already default.
 
   // Send a packet (but write will not block).
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
-  EXPECT_EQ(1u, helper_->packets_write_attempts());
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
 
   // Send an erroneous packet to close the connection.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_PACKET_HEADER, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
   ProcessDataPacket(6000, 0, !kEntropyFlag);
-  EXPECT_EQ(2u, helper_->packets_write_attempts());
+  EXPECT_EQ(2u, writer_->packets_write_attempts());
 }
 
 TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
 
   // Send a packet to so that write will really block.
-  connection_.SendStreamData(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
-  EXPECT_EQ(1u, helper_->packets_write_attempts());
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
 
   // Send an erroneous packet to close the connection.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_PACKET_HEADER, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
   ProcessDataPacket(6000, 0, !kEntropyFlag);
-  EXPECT_EQ(1u, helper_->packets_write_attempts());
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
 }
 
 TEST_P(QuicConnectionTest, ConnectionCloseWhenNothingPending) {
-  helper_->set_blocked(true);
+  writer_->set_blocked(true);
 
   // Send an erroneous packet to close the connection.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_PACKET_HEADER, false));
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
   ProcessDataPacket(6000, 0, !kEntropyFlag);
-  EXPECT_EQ(1u, helper_->packets_write_attempts());
+  EXPECT_EQ(1u, writer_->packets_write_attempts());
 }
 
 TEST_P(QuicConnectionTest, AckNotifierTriggerCallback) {
@@ -3061,7 +3170,8 @@
   EXPECT_CALL(delegate, OnAckNotification()).Times(1);;
 
   // Send some data, which will register the delegate to be notified.
-  connection_.SendStreamDataAndNotifyWhenAcked(1, "foo", 0, !kFin, &delegate);
+  connection_.SendStreamDataWithStringAndNotifyWhenAcked(1, "foo", 0, !kFin,
+                                                         &delegate);
 
   // Process an ACK from the server which should trigger the callback.
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
@@ -3081,11 +3191,12 @@
 
   // Send some data, which will register the delegate to be notified. This will
   // not be ACKed and so the delegate should never be called.
-  connection_.SendStreamDataAndNotifyWhenAcked(1, "foo", 0, !kFin, &delegate);
+  connection_.SendStreamDataWithStringAndNotifyWhenAcked(1, "foo", 0, !kFin,
+                                                         &delegate);
 
   // Send some other data which we will ACK.
-  connection_.SendStreamData(1, "foo", 0, !kFin);
-  connection_.SendStreamData(1, "bar", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "bar", 0, !kFin);
 
   // Now we receive ACK for packets 2 and 3, but importantly missing packet 1
   // which we registered to be notified about.
@@ -3108,10 +3219,11 @@
   EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
 
   // Send four packets, and register to be notified on ACK of packet 2.
-  connection_.SendStreamData(1, "foo", 0, !kFin);
-  connection_.SendStreamDataAndNotifyWhenAcked(1, "bar", 0, !kFin, &delegate);
-  connection_.SendStreamData(1, "baz", 0, !kFin);
-  connection_.SendStreamData(1, "qux", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin);
+  connection_.SendStreamDataWithStringAndNotifyWhenAcked(1, "bar", 0, !kFin,
+                                                         &delegate);
+  connection_.SendStreamDataWithString(1, "baz", 0, !kFin);
+  connection_.SendStreamDataWithString(1, "qux", 0, !kFin);
 
   // Now we receive ACK for packets 1, 3, and 4.
   QuicAckFrame frame(4, QuicTime::Zero(), 0);
@@ -3146,7 +3258,8 @@
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
 
   // Send one packet, and register to be notified on ACK.
-  connection_.SendStreamDataAndNotifyWhenAcked(1, "foo", 0, !kFin, &delegate);
+  connection_.SendStreamDataWithStringAndNotifyWhenAcked(1, "foo", 0, !kFin,
+                                                         &delegate);
 
   // Ack packet gets dropped, but we receive an FEC packet that covers it.
   // Should recover the Ack packet and trigger the notification callback.
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 2ad9a3a..8595d6c 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -53,32 +53,17 @@
 };
 
 TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   EXPECT_FALSE(stream_->encryption_established());
   EXPECT_FALSE(stream_->handshake_confirmed());
 }
 
 TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
   EXPECT_TRUE(stream_->encryption_established());
   EXPECT_TRUE(stream_->handshake_confirmed());
 }
 
 TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   EXPECT_CALL(*connection_, SendConnectionClose(
@@ -89,11 +74,6 @@
 }
 
 TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   EXPECT_TRUE(stream_->CryptoConnect());
 
   message_.set_tag(kCHLO);
@@ -105,11 +85,6 @@
 }
 
 TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   const QuicConfig* config = session_->config();
@@ -127,11 +102,6 @@
 }
 
 TEST_F(QuicCryptoClientStreamTest, InvalidHostname) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   stream_.reset(new QuicCryptoClientStream("invalid", session_.get(),
                                            &crypto_config_));
   session_->SetCryptoStream(stream_.get());
@@ -146,7 +116,7 @@
   CompleteCryptoHandshake();
 
   connection_ = new PacketSavingConnection(1, addr_, true);
-  session_.reset(new TestSession(connection_, QuicConfig(), true));
+  session_.reset(new TestSession(connection_, DefaultQuicConfig(), true));
   stream_.reset(new QuicCryptoClientStream(kServerHostname, session_.get(),
                                            &crypto_config_));
 
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 9e92b2b..d622342 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -43,7 +43,7 @@
         addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
               ip_ : IPAddressNumber(), 1),
         connection_(new PacketSavingConnection(guid_, addr_, true)),
-        session_(connection_, QuicConfig(), true),
+        session_(connection_, DefaultQuicConfig(), true),
         crypto_config_(QuicCryptoServerConfig::TESTING,
                        QuicRandom::GetInstance()),
         stream_(crypto_config_, &session_) {
@@ -86,21 +86,11 @@
 };
 
 TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   EXPECT_FALSE(stream_.encryption_established());
   EXPECT_FALSE(stream_.handshake_confirmed());
 }
 
 TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   // CompleteCryptoHandshake returns the number of client hellos sent. This
   // test should send:
   //   * One to get a source-address token and certificates.
@@ -111,11 +101,6 @@
 }
 
 TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   QuicGuid guid(1);
   IPAddressNumber ip;
   ParseIPLiteralToNumber("127.0.0.1", &ip);
@@ -184,11 +169,6 @@
 }
 
 TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
   EXPECT_CALL(*connection_, SendConnectionClose(
       QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
@@ -198,11 +178,6 @@
 }
 
 TEST_F(QuicCryptoServerStreamTest, BadMessageType) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   message_.set_tag(kSHLO);
   ConstructHandshakeMessage();
   EXPECT_CALL(*connection_, SendConnectionClose(
@@ -211,11 +186,6 @@
 }
 
 TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   crypto_config_.SetProofSource(NULL);
   client_options_.dont_verify_certs = true;
 
@@ -227,11 +197,6 @@
 }
 
 TEST_F(QuicCryptoServerStreamTest, ChannelID) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   client_options_.channel_id_enabled = true;
   // TODO(rtenneti): Enable testing of ProofVerifier.
   // CompleteCryptoHandshake verifies
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 3c10c5b..e73e61d 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -24,7 +24,8 @@
 }
 
 void QuicCryptoStream::OnError(CryptoFramer* framer) {
-  session()->ConnectionClose(framer->error(), false);
+  DLOG(WARNING) << "Error processing crypto data: "
+                << QuicUtils::ErrorToString(framer->error());
 }
 
 void QuicCryptoStream::OnHandshakeMessage(
@@ -46,15 +47,6 @@
   return data_len;
 }
 
-void QuicCryptoStream::CloseConnection(QuicErrorCode error) {
-  session()->connection()->SendConnectionClose(error);
-}
-
-void QuicCryptoStream::CloseConnectionWithDetails(QuicErrorCode error,
-                                                  const string& details) {
-  session()->connection()->SendConnectionCloseWithDetails(error, details);
-}
-
 void QuicCryptoStream::SendHandshakeMessage(
     const CryptoHandshakeMessage& message) {
   session()->OnCryptoHandshakeMessageSent(message);
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index c402b0d..d5b3417 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -50,10 +50,6 @@
   const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const;
 
  protected:
-  // Closes the connection
-  void CloseConnection(QuicErrorCode error);
-  void CloseConnectionWithDetails(QuicErrorCode error, const string& details);
-
   bool encryption_established_;
   bool handshake_confirmed_;
 
diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc
index cc69304..0403eb3 100644
--- a/net/quic/quic_crypto_stream_test.cc
+++ b/net/quic/quic_crypto_stream_test.cc
@@ -78,12 +78,6 @@
   EXPECT_FALSE(stream_.handshake_confirmed());
 }
 
-TEST_F(QuicCryptoStreamTest, OnErrorClosesConnection) {
-  CryptoFramer framer;
-  EXPECT_CALL(session_, ConnectionClose(QUIC_NO_ERROR, false));
-  stream_.OnError(&framer);
-}
-
 TEST_F(QuicCryptoStreamTest, ProcessData) {
   EXPECT_EQ(message_data_->length(),
             stream_.ProcessData(message_data_->data(),
diff --git a/net/quic/quic_data_reader.cc b/net/quic/quic_data_reader.cc
index 3bb7fc3..b9a6acf 100644
--- a/net/quic/quic_data_reader.cc
+++ b/net/quic/quic_data_reader.cc
@@ -4,6 +4,9 @@
 
 #include "net/quic/quic_data_reader.h"
 
+#include "net/base/int128.h"
+#include "net/quic/quic_protocol.h"
+
 using base::StringPiece;
 
 namespace net {
@@ -59,6 +62,37 @@
   return true;
 }
 
+bool QuicDataReader::ReadUFloat16(uint64* result) {
+  uint16 value;
+  if (!ReadUInt16(&value)) {
+    return false;
+  }
+
+  *result = value;
+  if (*result < (1 << kUFloat16MantissaEffectiveBits)) {
+    // Fast path: either the value is denormalized (no hidden bit), or
+    // normalized (hidden bit set, exponent offset by one) with exponent zero.
+    // Zero exponent offset by one sets the bit exactly where the hidden bit is.
+    // So in both cases the value encodes itself.
+    return true;
+  }
+
+  uint16 exponent = value >> kUFloat16MantissaBits;  // No sign extend on uint!
+  // After the fast pass, the exponent is at least one (offset by one).
+  // Un-offset the exponent.
+  --exponent;
+  DCHECK_GE(exponent, 1);
+  DCHECK_LE(exponent, kUFloat16MaxExponent);
+  // Here we need to clear the exponent and set the hidden bit. We have already
+  // decremented the exponent, so when we subtract it, it leaves behind the
+  // hidden bit.
+  *result -= exponent << kUFloat16MantissaBits;
+  *result <<= exponent;
+  DCHECK_GE(value, 1 << kUFloat16MantissaEffectiveBits);
+  DCHECK_LE(value, kUFloat16MaxValue);
+  return true;
+}
+
 bool QuicDataReader::ReadStringPiece16(StringPiece* result) {
   // Read resultant length.
   uint16 result_len;
diff --git a/net/quic/quic_data_reader.h b/net/quic/quic_data_reader.h
index fff07dd..9effa1c 100644
--- a/net/quic/quic_data_reader.h
+++ b/net/quic/quic_data_reader.h
@@ -59,6 +59,11 @@
   // Returns true on success, false otherwise.
   bool ReadUInt128(uint128* result);
 
+  // Reads a 16-bit unsigned float into the given output parameter.
+  // Forwards the internal iterator on success.
+  // Returns true on success, false otherwise.
+  bool ReadUFloat16(uint64* result);
+
   // Reads a string prefixed with 16-bit length into the given output parameter.
   //
   // NOTE: Does not copy but rather references strings in the underlying buffer.
diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc
index 61e7292..65ce7be 100644
--- a/net/quic/quic_data_writer.cc
+++ b/net/quic/quic_data_writer.cc
@@ -56,6 +56,45 @@
   return WriteBytes(&value, sizeof(value));
 }
 
+bool QuicDataWriter::WriteUFloat16(uint64 value) {
+  uint16 result;
+  if (value < (GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
+    // Fast path: either the value is denormalized, or has exponent zero.
+    // Both cases are represented by the value itself.
+    result = value;
+  } else if (value >= kUFloat16MaxValue) {
+    // Value is out of range; clamp it to the maximum representable.
+    result = numeric_limits<uint16>::max();
+  } else {
+    // The highest bit is between position 13 and 42 (zero-based), which
+    // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10,
+    // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11
+    // and count the shifts.
+    uint16 exponent = 0;
+    for (uint16 offset = 16; offset > 0; offset /= 2) {
+      // Right-shift the value until the highest bit is in position 11.
+      // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30),
+      // shift if the bit is at or above 11 + offset.
+      if (value >= (GG_UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
+        exponent += offset;
+        value >>= offset;
+      }
+    }
+
+    DCHECK_GE(exponent, 1);
+    DCHECK_LE(exponent, kUFloat16MaxExponent);
+    DCHECK_GE(value, GG_UINT64_C(1) << kUFloat16MantissaBits);
+    DCHECK_LT(value, GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits);
+
+    // Hidden bit (position 11) is set. We should remove it and increment the
+    // exponent. Equivalently, we just add it to the exponent.
+    // This hides the bit.
+    result = value + (exponent << kUFloat16MantissaBits);
+  }
+
+  return WriteBytes(&result, sizeof(result));
+}
+
 bool QuicDataWriter::WriteStringPiece16(StringPiece val) {
   if (val.length() > numeric_limits<uint16>::max()) {
     return false;
diff --git a/net/quic/quic_data_writer.h b/net/quic/quic_data_writer.h
index b18121d..857bcc8 100644
--- a/net/quic/quic_data_writer.h
+++ b/net/quic/quic_data_writer.h
@@ -43,6 +43,10 @@
   bool WriteUInt32(uint32 value);
   bool WriteUInt48(uint64 value);
   bool WriteUInt64(uint64 value);
+  // Write unsigned floating point corresponding to the value. Large values are
+  // clamped to the maximum representable (kUFloat16MaxValue). Values that can
+  // not be represented directly are rounded down.
+  bool WriteUFloat16(uint64 value);
   bool WriteStringPiece16(base::StringPiece val);
   bool WriteBytes(const void* data, size_t data_len);
   bool WriteRepeatedByte(uint8 byte, size_t count);
diff --git a/net/quic/quic_data_writer_test.cc b/net/quic/quic_data_writer_test.cc
index 4fbd7e4..9106947 100644
--- a/net/quic/quic_data_writer_test.cc
+++ b/net/quic/quic_data_writer_test.cc
@@ -4,13 +4,15 @@
 
 #include "net/quic/quic_data_writer.h"
 
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_data_reader.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 namespace test {
 namespace {
 
-TEST(QuicDataWriterTest, WriteUint8ToOffset) {
+TEST(QuicDataWriterTest, WriteUInt8ToOffset) {
   QuicDataWriter writer(4);
 
   writer.WriteUInt32(0xfefdfcfb);
@@ -19,17 +21,15 @@
   EXPECT_TRUE(writer.WriteUInt8ToOffset(3, 2));
   EXPECT_TRUE(writer.WriteUInt8ToOffset(4, 3));
 
-  char* data = writer.take();
+  scoped_ptr<char[]> data(writer.take());
 
   EXPECT_EQ(1, data[0]);
   EXPECT_EQ(2, data[1]);
   EXPECT_EQ(3, data[2]);
   EXPECT_EQ(4, data[3]);
-
-  delete[] data;
 }
 
-TEST(QuicDataWriterDeathTest, WriteUint8ToOffset) {
+TEST(QuicDataWriterDeathTest, WriteUInt8ToOffset) {
   QuicDataWriter writer(4);
 
 #if !defined(WIN32) && defined(GTEST_HAS_DEATH_TEST)
@@ -41,6 +41,127 @@
 #endif
 }
 
+TEST(QuicDataWriterTest, SanityCheckUFloat16Consts) {
+  // Check the arithmetic on the constants - otherwise the values below make
+  // no sense.
+  EXPECT_EQ(30, kUFloat16MaxExponent);
+  EXPECT_EQ(11, kUFloat16MantissaBits);
+  EXPECT_EQ(12, kUFloat16MantissaEffectiveBits);
+  EXPECT_EQ(GG_UINT64_C(0x3FFC0000000), kUFloat16MaxValue);
+}
+
+TEST(QuicDataWriterTest, WriteUFloat16) {
+  struct TestCase {
+    uint64 decoded;
+    uint16 encoded;
+  };
+  TestCase test_cases[] = {
+    // Small numbers represent themselves.
+    { 0, 0 }, { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
+    { 7, 7 }, { 15, 15 }, { 31, 31 }, { 42, 42 }, { 123, 123 }, { 1234, 1234 },
+    // Check transition through 2^11.
+    { 2046, 2046 }, { 2047, 2047 }, { 2048, 2048 }, { 2049, 2049 },
+    // Running out of mantissa at 2^12.
+    { 4094, 4094 }, { 4095, 4095 }, { 4096, 4096 }, { 4097, 4096 },
+    { 4098, 4097 }, { 4099, 4097 }, { 4100, 4098 }, { 4101, 4098 },
+    // Check transition through 2^13.
+    { 8190, 6143 }, { 8191, 6143 }, { 8192, 6144 }, { 8193, 6144 },
+    { 8194, 6144 }, { 8195, 6144 }, { 8196, 6145 }, { 8197, 6145 },
+    // Half-way through the exponents.
+    { 0x7FF8000, 0x87FF }, { 0x7FFFFFF, 0x87FF }, { 0x8000000, 0x8800 },
+    { 0xFFF0000, 0x8FFF }, { 0xFFFFFFF, 0x8FFF }, { 0x10000000, 0x9000 },
+    // Transition into the largest exponent.
+    { 0x1FFFFFFFFFE, 0xF7FF}, { 0x1FFFFFFFFFF, 0xF7FF},
+    { 0x20000000000, 0xF800}, { 0x20000000001, 0xF800},
+    { 0x2003FFFFFFE, 0xF800}, { 0x2003FFFFFFF, 0xF800},
+    { 0x20040000000, 0xF801}, { 0x20040000001, 0xF801},
+    // Transition into the max value and clamping.
+    { 0x3FF80000000, 0xFFFE}, { 0x3FFBFFFFFFF, 0xFFFE},
+    { 0x3FFC0000000, 0xFFFF}, { 0x3FFC0000001, 0xFFFF},
+    { 0x3FFFFFFFFFF, 0xFFFF}, { 0x40000000000, 0xFFFF},
+    { 0xFFFFFFFFFFFFFFFF, 0xFFFF},
+  };
+  int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
+
+  for (int i = 0; i < num_test_cases; ++i) {
+    QuicDataWriter writer(2);
+    EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded));
+    scoped_ptr<char[]> data(writer.take());
+    EXPECT_EQ(test_cases[i].encoded, *reinterpret_cast<uint16*>(data.get()));
+  }
+}
+
+TEST(QuicDataWriterTest, ReadUFloat16) {
+  struct TestCase {
+    uint64 decoded;
+    uint16 encoded;
+  };
+  TestCase test_cases[] = {
+    // There are fewer decoding test cases because encoding truncates, and
+    // decoding returns the smallest expansion.
+    // Small numbers represent themselves.
+    { 0, 0 }, { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
+    { 7, 7 }, { 15, 15 }, { 31, 31 }, { 42, 42 }, { 123, 123 }, { 1234, 1234 },
+    // Check transition through 2^11.
+    { 2046, 2046 }, { 2047, 2047 }, { 2048, 2048 }, { 2049, 2049 },
+    // Running out of mantissa at 2^12.
+    { 4094, 4094 }, { 4095, 4095 }, { 4096, 4096 },
+    { 4098, 4097 }, { 4100, 4098 },
+    // Check transition through 2^13.
+    { 8190, 6143 }, { 8192, 6144 }, { 8196, 6145 },
+    // Half-way through the exponents.
+    { 0x7FF8000, 0x87FF }, { 0x8000000, 0x8800 },
+    { 0xFFF0000, 0x8FFF }, { 0x10000000, 0x9000 },
+    // Transition into the largest exponent.
+    { 0x1FFE0000000, 0xF7FF}, { 0x20000000000, 0xF800},
+    { 0x20040000000, 0xF801},
+    // Transition into the max value.
+    { 0x3FF80000000, 0xFFFE}, { 0x3FFC0000000, 0xFFFF},
+  };
+  int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
+
+  for (int i = 0; i < num_test_cases; ++i) {
+    QuicDataReader reader(reinterpret_cast<char*>(&test_cases[i].encoded), 2);
+    uint64 value;
+    EXPECT_TRUE(reader.ReadUFloat16(&value));
+    EXPECT_EQ(test_cases[i].decoded, value);
+  }
+}
+
+TEST(QuicDataWriterTest, RoundTripUFloat16) {
+  // Just test all 16-bit encoded values. 0 and max already tested above.
+  uint64 previous_value = 0;
+  for (uint16 i = 1; i < 0xFFFF; ++i) {
+    // Read the two bytes.
+    QuicDataReader reader(reinterpret_cast<char*>(&i), 2);
+    uint64 value;
+    // All values must be decodable.
+    EXPECT_TRUE(reader.ReadUFloat16(&value));
+    // Check that small numbers represent themselves
+    if (i < 4097)
+      EXPECT_EQ(i, value);
+    // Check there's monotonic growth.
+    EXPECT_LT(previous_value, value);
+    // Check that precision is within 0.5% away from the denormals.
+    if (i > 2000)
+      EXPECT_GT(previous_value * 1005, value * 1000);
+    // Check we're always within the promised range.
+    EXPECT_LT(value, GG_UINT64_C(0x3FFC0000000));
+    previous_value = value;
+    QuicDataWriter writer(6);
+    EXPECT_TRUE(writer.WriteUFloat16(value - 1));
+    EXPECT_TRUE(writer.WriteUFloat16(value));
+    EXPECT_TRUE(writer.WriteUFloat16(value + 1));
+    scoped_ptr<char[]> data(writer.take());
+    // Check minimal decoding (previous decoding has previous encoding).
+    EXPECT_EQ(i-1, *reinterpret_cast<uint16*>(data.get()));
+    // Check roundtrip.
+    EXPECT_EQ(i, *reinterpret_cast<uint16*>(data.get() + 2));
+    // Check next decoding.
+    EXPECT_EQ(i < 4096? i+1 : i, *reinterpret_cast<uint16*>(data.get() + 4));
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_default_packet_writer.cc b/net/quic/quic_default_packet_writer.cc
new file mode 100644
index 0000000..95a4d68
--- /dev/null
+++ b/net/quic/quic_default_packet_writer.cc
@@ -0,0 +1,63 @@
+// Copyright 2013 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 "net/quic/quic_default_packet_writer.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+QuicDefaultPacketWriter::QuicDefaultPacketWriter() : weak_factory_(this) {
+}
+
+QuicDefaultPacketWriter::QuicDefaultPacketWriter(DatagramClientSocket* socket)
+    : weak_factory_(this),
+      socket_(socket) {
+}
+
+QuicDefaultPacketWriter::~QuicDefaultPacketWriter() {}
+
+// QuicPacketWriter
+WriteResult QuicDefaultPacketWriter::WritePacket(
+    const char* buffer, size_t buf_len,
+    const net::IPAddressNumber& self_address,
+    const net::IPEndPoint& peer_address,
+    QuicBlockedWriterInterface* blocked_writer) {
+  scoped_refptr<StringIOBuffer> buf(
+      new StringIOBuffer(std::string(buffer, buf_len)));
+  int rv = socket_->Write(buf.get(),
+                          buf_len,
+                          base::Bind(&QuicDefaultPacketWriter::OnWriteComplete,
+                                     weak_factory_.GetWeakPtr()));
+  WriteStatus status = WRITE_STATUS_OK;
+  if (rv < 0) {
+    if (rv != ERR_IO_PENDING) {
+      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
+      status = WRITE_STATUS_ERROR;
+    } else {
+      status = WRITE_STATUS_BLOCKED;
+    }
+  }
+
+  return WriteResult(status, rv);
+}
+
+bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const {
+  // Chrome sockets' Write() methods buffer the data until the Write is
+  // permitted.
+  return true;
+}
+
+void QuicDefaultPacketWriter::OnWriteComplete(int rv) {
+  DCHECK_NE(rv, ERR_IO_PENDING);
+  WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
+  connection_->OnPacketSent(result);
+  connection_->OnCanWrite();
+}
+
+}  // namespace net
diff --git a/net/quic/quic_default_packet_writer.h b/net/quic/quic_default_packet_writer.h
new file mode 100644
index 0000000..f60c76e
--- /dev/null
+++ b/net/quic/quic_default_packet_writer.h
@@ -0,0 +1,50 @@
+// Copyright 2013 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 NET_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
+#define NET_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/ip_endpoint.h"
+#include "net/quic/quic_connection.h"
+#include "net/quic/quic_packet_writer.h"
+#include "net/quic/quic_protocol.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+class QuicBlockedWriterInterface;
+
+// Chrome specific packet writer which uses a DatagramClientSocket for writing
+// data.
+class NET_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter {
+ public:
+  QuicDefaultPacketWriter();
+  explicit QuicDefaultPacketWriter(DatagramClientSocket* socket);
+  virtual ~QuicDefaultPacketWriter();
+
+  // QuicPacketWriter
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const net::IPAddressNumber& self_address,
+      const net::IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+
+  void OnWriteComplete(int rv);
+  void SetConnection(QuicConnection* connection) {
+    connection_ = connection;
+  }
+
+ private:
+  base::WeakPtrFactory<QuicDefaultPacketWriter> weak_factory_;
+  DatagramClientSocket* socket_;
+  QuicConnection* connection_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index 2d6a51e..99a040d 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -138,6 +138,7 @@
     server_address_ = IPEndPoint(ip, 0);
     server_config_.SetDefaults();
     server_thread_.reset(new ServerThread(server_address_, server_config_,
+                                          QuicSupportedVersions(),
                                           strike_register_no_startup_period_));
     server_thread_->Start();
     server_thread_->listening()->Wait();
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 24bde81..493cf80 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -72,16 +72,6 @@
 const uint8 kQuicFrameTypeAckMask = 0x40;
 const uint8 kQuicFrameTypeCongestionFeedbackMask = 0x20;
 
-// Mask to determine if it's a special frame type(Stream, Ack, or
-// Congestion Control) by checking if the first bit is 0, then shifting right.
-// TODO(jri): Remove kQuicFrameType0BitMask constant from v. 10 onwards.
-// Replaced by kQuicFrameTypeStream defined above.
-const uint8 kQuicFrameType0BitMask = 0x01;
-
-// Default frame type shift and mask.
-const uint8 kQuicDefaultFrameTypeShift = 3;
-const uint8 kQuicDefaultFrameTypeMask = 0x07;
-
 // Stream frame relative shifts and masks for interpreting the stream flags.
 // StreamID may be 1, 2, 3, or 4 bytes.
 const uint8 kQuicStreamIdShift = 2;
@@ -124,7 +114,7 @@
 
 }  // namespace
 
-QuicFramer::QuicFramer(QuicVersion version,
+QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
                        QuicTime creation_time,
                        bool is_server)
     : visitor_(NULL),
@@ -132,13 +122,15 @@
       error_(QUIC_NO_ERROR),
       last_sequence_number_(0),
       last_serialized_guid_(0),
-      quic_version_(version),
-      decrypter_(QuicDecrypter::Create(GetNullTag(version))),
+      supported_versions_(supported_versions),
       alternative_decrypter_latch_(false),
       is_server_(is_server),
       creation_time_(creation_time) {
-  DCHECK(IsSupportedVersion(version));
-  encrypter_[ENCRYPTION_NONE].reset(QuicEncrypter::Create(GetNullTag(version)));
+  DCHECK(!supported_versions.empty());
+  quic_version_ = supported_versions_[0];
+  decrypter_.reset(QuicDecrypter::Create(GetNullTag(quic_version_)));
+  encrypter_[ENCRYPTION_NONE].reset(
+      QuicEncrypter::Create(GetNullTag(quic_version_)));
 }
 
 QuicFramer::~QuicFramer() {}
@@ -170,7 +162,7 @@
 // static
 size_t QuicFramer::GetMinConnectionCloseFrameSize() {
   return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize +
-      GetMinAckFrameSize();
+      GetMinAckFrameSize() - 1;  // Don't include the frame type again.
 }
 
 // static
@@ -239,26 +231,23 @@
 }
 
 bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
-  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
-    if (version == kSupportedQuicVersions[i]) {
+  for (size_t i = 0; i < supported_versions_.size(); ++i) {
+    if (version == supported_versions_[i]) {
       return true;
     }
   }
   return false;
 }
 
-size_t QuicFramer::GetSerializedFrameLength(
-    const QuicFrame& frame, size_t free_bytes, bool first_frame) {
+size_t QuicFramer::GetSerializedFrameLength(const QuicFrame& frame,
+                                            size_t free_bytes,
+                                            bool first_frame,
+                                            bool last_frame) {
   if (frame.type == PADDING_FRAME) {
     // PADDING implies end of packet.
     return free_bytes;
   }
-  // See if it fits as the non-last frame.
-  size_t frame_len = ComputeFrameLength(frame, false);
-  // STREAM frames save two bytes when they're the last frame in the packet.
-  if (frame_len > free_bytes && frame.type == STREAM_FRAME) {
-    frame_len = ComputeFrameLength(frame, true);
-  }
+  size_t frame_len = ComputeFrameLength(frame, last_frame);
   if (frame_len > free_bytes) {
     // Only truncate the first frame in a packet, so if subsequent ones go
     // over, stop including more frames.
@@ -292,8 +281,10 @@
   size_t packet_size = GetPacketHeaderSize(header);
   for (size_t i = 0; i < frames.size(); ++i) {
     DCHECK_LE(packet_size, max_plaintext_size);
+    bool first_frame = i == 0;
+    bool last_frame = i == frames.size() - 1;
     const size_t frame_size = GetSerializedFrameLength(
-        frames[i], max_plaintext_size - packet_size, i == 0);
+        frames[i], max_plaintext_size - packet_size, first_frame, last_frame);
     DCHECK(frame_size);
     packet_size += frame_size;
   }
@@ -936,11 +927,9 @@
       return RaiseError(QUIC_INVALID_FRAME_DATA);
     }
 
-    // TODO(jri): Remove this entire if block when support for
-    // QUIC version < 10 removed.
-    if (version() < QUIC_VERSION_10) {
-      // Special frame type processing for QUIC version < 10.
-      if ((frame_type & kQuicFrameType0BitMask) == 0) {
+    if (frame_type & kQuicFrameTypeSpecialMask) {
+      // Stream Frame
+      if (frame_type & kQuicFrameTypeStreamMask) {
         QuicStreamFrame frame;
         if (!ProcessStreamFrame(frame_type, &frame)) {
           return RaiseError(QUIC_INVALID_STREAM_DATA);
@@ -953,8 +942,8 @@
         continue;
       }
 
-      frame_type >>= 1;
-      if ((frame_type & kQuicFrameType0BitMask) == 0) {
+      // Ack Frame
+      if (frame_type & kQuicFrameTypeAckMask) {
         QuicAckFrame frame;
         if (!ProcessAckFrame(&frame)) {
           return RaiseError(QUIC_INVALID_ACK_DATA);
@@ -967,8 +956,8 @@
         continue;
       }
 
-      frame_type >>= 1;
-      if ((frame_type & kQuicFrameType0BitMask) == 0) {
+      // Congestion Feedback Frame
+      if (frame_type & kQuicFrameTypeCongestionFeedbackMask) {
         QuicCongestionFeedbackFrame frame;
         if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
           return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
@@ -981,178 +970,70 @@
         continue;
       }
 
-      frame_type >>= 1;
-      switch (frame_type) {
-        // STREAM_FRAME, ACK_FRAME, and CONGESTION_FEEDBACK_FRAME are handled
-        // above.
-        case PADDING_FRAME_OLD:
-          // We're done with the packet.
+      // This was a special frame type that did not match any
+      // of the known ones. Error.
+      set_detailed_error("Illegal frame type.");
+      DLOG(WARNING) << "Illegal frame type: "
+                    << static_cast<int>(frame_type);
+      return RaiseError(QUIC_INVALID_FRAME_DATA);
+    }
+
+    switch (frame_type) {
+      case PADDING_FRAME:
+        // We're done with the packet.
+        return true;
+
+      case RST_STREAM_FRAME: {
+        QuicRstStreamFrame frame;
+        if (!ProcessRstStreamFrame(&frame)) {
+          return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
+        }
+        if (!visitor_->OnRstStreamFrame(frame)) {
+          DLOG(INFO) << "Visitor asked to stop further processing.";
+          // Returning true since there was no parsing error.
           return true;
-
-        case RST_STREAM_FRAME_OLD: {
-          QuicRstStreamFrame frame;
-          if (!ProcessRstStreamFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
-          }
-          if (!visitor_->OnRstStreamFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
         }
-
-        case CONNECTION_CLOSE_FRAME_OLD: {
-          QuicConnectionCloseFrame frame;
-          if (!ProcessConnectionCloseFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
-          }
-
-          if (!visitor_->OnAckFrame(frame.ack_frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-
-          if (!visitor_->OnConnectionCloseFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
-        }
-
-        case GOAWAY_FRAME_OLD: {
-          QuicGoAwayFrame goaway_frame;
-          if (!ProcessGoAwayFrame(&goaway_frame)) {
-            return RaiseError(QUIC_INVALID_GOAWAY_DATA);
-          }
-          if (!visitor_->OnGoAwayFrame(goaway_frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
-        }
-
-          set_detailed_error("Illegal frame type.");
-          DLOG(WARNING) << "Illegal frame type: "
-                        << static_cast<int>(frame_type);
-          return RaiseError(QUIC_INVALID_FRAME_DATA);
+        continue;
       }
-    } else {
-      // TODO(jri): Retain this else block when support for
-      // QUIC version < 10 removed. Remove above if block.
 
-      // Special frame type processing for QUIC version >= 10.
-      if (frame_type & kQuicFrameTypeSpecialMask) {
-        // Stream Frame
-        if (frame_type & kQuicFrameTypeStreamMask) {
-          QuicStreamFrame frame;
-          if (!ProcessStreamFrame(frame_type, &frame)) {
-            return RaiseError(QUIC_INVALID_STREAM_DATA);
-          }
-          if (!visitor_->OnStreamFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
+      case CONNECTION_CLOSE_FRAME: {
+        QuicConnectionCloseFrame frame;
+        if (!ProcessConnectionCloseFrame(&frame)) {
+          return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
         }
 
-        // Ack Frame
-        if (frame_type & kQuicFrameTypeAckMask) {
-          QuicAckFrame frame;
-          if (!ProcessAckFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_ACK_DATA);
-          }
-          if (!visitor_->OnAckFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
+        if (!visitor_->OnAckFrame(frame.ack_frame)) {
+          DLOG(INFO) << "Visitor asked to stop further processing.";
+          // Returning true since there was no parsing error.
+          return true;
         }
 
-        // Congestion Feedback Frame
-        if (frame_type & kQuicFrameTypeCongestionFeedbackMask) {
-          QuicCongestionFeedbackFrame frame;
-          if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
-          }
-          if (!visitor_->OnCongestionFeedbackFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
+        if (!visitor_->OnConnectionCloseFrame(frame)) {
+          DLOG(INFO) << "Visitor asked to stop further processing.";
+          // Returning true since there was no parsing error.
+          return true;
         }
+        continue;
+      }
 
-        // This was a special frame type that did not match any
-        // of the known ones. Error.
+      case GOAWAY_FRAME: {
+        QuicGoAwayFrame goaway_frame;
+        if (!ProcessGoAwayFrame(&goaway_frame)) {
+          return RaiseError(QUIC_INVALID_GOAWAY_DATA);
+        }
+        if (!visitor_->OnGoAwayFrame(goaway_frame)) {
+          DLOG(INFO) << "Visitor asked to stop further processing.";
+          // Returning true since there was no parsing error.
+          return true;
+        }
+        continue;
+      }
+
+      default:
         set_detailed_error("Illegal frame type.");
         DLOG(WARNING) << "Illegal frame type: "
                       << static_cast<int>(frame_type);
         return RaiseError(QUIC_INVALID_FRAME_DATA);
-      }
-
-      switch (frame_type) {
-        case PADDING_FRAME:
-          // We're done with the packet.
-          return true;
-
-        case RST_STREAM_FRAME: {
-          QuicRstStreamFrame frame;
-          if (!ProcessRstStreamFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
-          }
-          if (!visitor_->OnRstStreamFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
-        }
-
-        case CONNECTION_CLOSE_FRAME: {
-          QuicConnectionCloseFrame frame;
-          if (!ProcessConnectionCloseFrame(&frame)) {
-            return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
-          }
-
-          if (!visitor_->OnAckFrame(frame.ack_frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-
-          if (!visitor_->OnConnectionCloseFrame(frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
-        }
-
-        case GOAWAY_FRAME: {
-          QuicGoAwayFrame goaway_frame;
-          if (!ProcessGoAwayFrame(&goaway_frame)) {
-            return RaiseError(QUIC_INVALID_GOAWAY_DATA);
-          }
-          if (!visitor_->OnGoAwayFrame(goaway_frame)) {
-            DLOG(INFO) << "Visitor asked to stop further processing.";
-            // Returning true since there was no parsing error.
-            return true;
-          }
-          continue;
-        }
-
-        default:
-          set_detailed_error("Illegal frame type.");
-          DLOG(WARNING) << "Illegal frame type: "
-                        << static_cast<int>(frame_type);
-          return RaiseError(QUIC_INVALID_FRAME_DATA);
-      }
     }
   }
 
@@ -1163,12 +1044,7 @@
                                     QuicStreamFrame* frame) {
   uint8 stream_flags = frame_type;
 
-  // TODO(jri): Remove if block after support for ver. < 10 removed.
-  if (version() < QUIC_VERSION_10) {
-    stream_flags >>= 1;
-  } else {
-    stream_flags &= ~kQuicFrameTypeStreamMask;
-  }
+  stream_flags &= ~kQuicFrameTypeStreamMask;
 
   // Read from right to left: StreamID, Offset, Data Length, Fin.
   const uint8 stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1;
@@ -1559,7 +1435,8 @@
   // level to hand. At the moment, the NullEncrypter has a tag length of 16
   // bytes and AES-GCM has a tag length of 12. We take the minimum plaintext
   // length just to be safe.
-  size_t min_plaintext_size = ciphertext_size;
+  // TODO(rtenneti): remove '- 16' after we delete QUIC_VERSION_10.
+  size_t min_plaintext_size = ciphertext_size - 16;
 
   for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
     if (encrypter_[i].get() != NULL) {
@@ -1716,45 +1593,21 @@
       // stream id 2 bits.
       type_byte <<= kQuicStreamIdShift;
       type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
-
-      // TODO(jri): Remove if block when support for QUIC ver. < 10 removed.
-      if (version() < QUIC_VERSION_10) {
-        type_byte <<= 1;  // Leaves the last bit as a 0.
-      } else {
-        type_byte |= kQuicFrameTypeStreamMask;  // Set Stream Frame Type to 1.
-      }
+      type_byte |= kQuicFrameTypeStreamMask;  // Set Stream Frame Type to 1.
       break;
     }
     case ACK_FRAME: {
       // TODO(ianswett): Use extra 5 bits in the ack framing.
-      // TODO(jri): Remove if block when support for QUIC ver. < 10 removed.
-      if (version() < QUIC_VERSION_10) {
-        type_byte = 0x01;
-      } else {
-        type_byte = kQuicFrameTypeAckMask;
-      }
+      type_byte = kQuicFrameTypeAckMask;
       break;
     }
     case CONGESTION_FEEDBACK_FRAME: {
       // TODO(ianswett): Use extra 5 bits in the congestion feedback framing.
-      // TODO(jri): Remove if block when support for QUIC ver. < 10 removed.
-      if (version() < QUIC_VERSION_10) {
-        type_byte = 0x03;
-      } else {
-        type_byte = kQuicFrameTypeCongestionFeedbackMask;
-      }
+      type_byte = kQuicFrameTypeCongestionFeedbackMask;
       break;
     }
     default:
       type_byte = frame.type;
-      // TODO(jri): Remove if block when support for QUIC ver. < 10 removed.
-      if (version() < QUIC_VERSION_10) {
-        if (type_byte > 0) {
-          type_byte += 3;
-        }
-        type_byte = (type_byte << kQuicDefaultFrameTypeShift) |
-            kQuicDefaultFrameTypeMask;
-      }
       break;
   }
 
@@ -1834,6 +1687,9 @@
 
 void QuicFramer::set_version(const QuicVersion version) {
   DCHECK(IsSupportedVersion(version));
+  // Handle version incompatibility between QUIC_VERSION_10 and QUIC_VERSION_11
+  // because of introduction of a new QUIC null encryption format in
+  // QUIC_VERSION_11.
   if ((quic_version_ > QUIC_VERSION_10 && version <= QUIC_VERSION_10) ||
       (quic_version_ <= QUIC_VERSION_10 && version > QUIC_VERSION_10)) {
     // TODO(rtenneti): remove the following code after we delete
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 94b77b1..5d55138 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -150,8 +150,10 @@
 class NET_EXPORT_PRIVATE QuicFramer {
  public:
   // Constructs a new framer that installs a kNULL QuicEncrypter and
-  // QuicDecrypter for level ENCRYPTION_NONE.
-  QuicFramer(QuicVersion quic_version,
+  // QuicDecrypter for level ENCRYPTION_NONE. |supported_versions| specifies the
+  // list of supported QUIC versions. |quic_version_| is set to the maximum
+  // version in |supported_versions|.
+  QuicFramer(const QuicVersionVector& supported_versions,
              QuicTime creation_time,
              bool is_server);
 
@@ -182,6 +184,10 @@
     fec_builder_ = builder;
   }
 
+  const QuicVersionVector& supported_versions() const {
+    return supported_versions_;
+  }
+
   QuicVersion version() const {
     return quic_version_;
   }
@@ -251,8 +257,10 @@
   // Returns the number of bytes added to the packet for the specified frame,
   // and 0 if the frame doesn't fit.  Includes the header size for the first
   // frame.
-  size_t GetSerializedFrameLength(
-      const QuicFrame& frame, size_t free_bytes, bool first_frame);
+  size_t GetSerializedFrameLength(const QuicFrame& frame,
+                                  size_t free_bytes,
+                                  bool first_frame,
+                                  bool last_frame);
 
   // Returns the associated data from the encrypted packet |encrypted| as a
   // stringpiece.
@@ -427,6 +435,11 @@
   scoped_ptr<QuicData> decrypted_;
   // Version of the protocol being used.
   QuicVersion quic_version_;
+  // This vector contains QUIC versions which we currently support.
+  // This should be ordered such that the highest supported version is the first
+  // element, with subsequent elements in descending order (versions can be
+  // skipped as necessary).
+  QuicVersionVector supported_versions_;
   // Primary decrypter used to decrypt packets during parsing.
   scoped_ptr<QuicDecrypter> decrypter_;
   // Alternative decrypter that can also be used to decrypt packets.
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index a0352de..31c7c45 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -309,7 +309,7 @@
       : encrypter_(new test::TestEncrypter()),
         decrypter_(new test::TestDecrypter()),
         start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
-        framer_(QuicVersionMax(), start_, true) {
+        framer_(QuicSupportedVersions(), start_, true) {
     version_ = GetParam();
     framer_.set_version(version_);
     framer_.SetDecrypter(decrypter_);
@@ -1038,8 +1038,7 @@
     0x00,
 
     // frame type (padding)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
   CheckProcessingFails(packet,
@@ -1064,8 +1063,7 @@
     0x00,
 
     // frame type (padding)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
   CheckProcessingFails(packet,
@@ -1090,8 +1088,7 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1116,8 +1113,7 @@
     0x10,
 
     // frame type (padding)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
   CheckProcessingFails(packet,
@@ -1162,12 +1158,10 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     // Ignored data (which in this case is a stream frame)
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1211,8 +1205,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1260,8 +1253,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFC : 0xFE),
+    0xFE,
     // stream id
     0x04, 0x03, 0x02,
     // offset
@@ -1310,8 +1302,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFA : 0xFD),
+    0xFD,
     // stream id
     0x04, 0x03,
     // offset
@@ -1360,8 +1351,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xF8 : 0xFC),
+    0xFC,
     // stream id
     0x04,
     // offset
@@ -1412,8 +1402,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1465,8 +1454,7 @@
     0x00,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1494,8 +1482,7 @@
 TEST_P(QuicFramerTest, RevivedStreamFrame) {
   unsigned char payload[] = {
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1564,8 +1551,7 @@
     0x02,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -1617,8 +1603,7 @@
     0x00,
 
     // frame type (ack frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40),
+    0x40,
     // entropy hash of sent packets till least awaiting - 1.
     0xAB,
     // least packet sequence number awaiting an ack
@@ -1711,8 +1696,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (tcp)
     0x00,
     // ack_frame.feedback.tcp.accumulated_number_of_lost_packets
@@ -1769,8 +1753,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (inter arrival)
     0x01,
     // accumulated_number_of_lost_packets
@@ -1866,8 +1849,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (fix rate)
     0x02,
     // bitrate_in_bytes_per_second;
@@ -1919,8 +1901,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (invalid)
     0x03,
   };
@@ -1945,8 +1926,7 @@
     0x00,
 
     // frame type (rst stream frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x27 : 0x01),
+    0x01,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // error code
@@ -2005,8 +1985,7 @@
     0x00,
 
     // frame type (connection close frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02),
+    0x02,
     // error code
     0x11, 0x00, 0x00, 0x00,
 
@@ -2093,8 +2072,7 @@
     0x00,
 
     // frame type (go away frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x37 : 0x03),
+    0x03,
     // error code
     0x09, 0x00, 0x00, 0x00,
     // stream id
@@ -2294,8 +2272,7 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
 
@@ -2308,9 +2285,11 @@
       framer_.BuildUnsizedDataPacket(header, frames).packet);
   ASSERT_TRUE(data != NULL);
 
+  // TODO(rtenneti): remove "- 16" when we remove QUIC_VERSION_10.
   test::CompareCharArraysWithHexError("constructed packet",
                                       data->data(), data->length(),
-                                      AsChars(packet), arraysize(packet));
+                                      AsChars(packet),
+                                      arraysize(packet) - 16);
 }
 
 TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
@@ -2341,8 +2320,7 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
 
@@ -2355,9 +2333,11 @@
       framer_.BuildUnsizedDataPacket(header, frames).packet);
   ASSERT_TRUE(data != NULL);
 
+  // TODO(rtenneti): remove "- 16" when we remove QUIC_VERSION_10.
   test::CompareCharArraysWithHexError("constructed packet",
                                       data->data(), data->length(),
-                                      AsChars(packet), arraysize(packet));
+                                      AsChars(packet),
+                                      arraysize(packet) - 16);
 }
 
 TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
@@ -2388,8 +2368,7 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
 
@@ -2402,9 +2381,11 @@
       framer_.BuildUnsizedDataPacket(header, frames).packet);
   ASSERT_TRUE(data != NULL);
 
+  // TODO(rtenneti): remove "- 16" when we remove QUIC_VERSION_10.
   test::CompareCharArraysWithHexError("constructed packet",
                                       data->data(), data->length(),
-                                      AsChars(packet), arraysize(packet));
+                                      AsChars(packet),
+                                      arraysize(packet) - 16);
 }
 
 TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
@@ -2435,8 +2416,7 @@
     0x00,
 
     // frame type (padding frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00),
+    0x00,
     0x00, 0x00, 0x00, 0x00
   };
 
@@ -2449,9 +2429,11 @@
       framer_.BuildUnsizedDataPacket(header, frames).packet);
   ASSERT_TRUE(data != NULL);
 
+  // TODO(rtenneti): remove "- 16" when we remove QUIC_VERSION_10.
   test::CompareCharArraysWithHexError("constructed packet",
                                       data->data(), data->length(),
-                                      AsChars(packet), arraysize(packet));
+                                      AsChars(packet),
+                                      arraysize(packet) - 16);
 }
 
 TEST_P(QuicFramerTest, BuildStreamFramePacket) {
@@ -2486,8 +2468,7 @@
     0x01,
 
     // frame type (stream frame with fin and no length)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF),
+    0xDF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -2542,8 +2523,7 @@
     0x01,
 
     // frame type (stream frame with fin and no length)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF),
+    0xDF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -2626,8 +2606,7 @@
     0x01,
 
     // frame type (ack frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40),
+    0x40,
     // entropy hash of sent packets till least awaiting - 1.
     0x14,
     // least packet sequence number awaiting an ack
@@ -2687,8 +2666,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (TCP)
     0x00,
     // accumulated number of lost packets
@@ -2747,8 +2725,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (inter arrival)
     0x01,
     // accumulated_number_of_lost_packets
@@ -2811,8 +2788,7 @@
     0x00,
 
     // frame type (congestion feedback frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20),
+    0x20,
     // congestion feedback type (fix rate)
     0x02,
     // bitrate_in_bytes_per_second;
@@ -2878,8 +2854,7 @@
     0x00,
 
     // frame type (rst stream frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x27 : 0x01),
+    0x01,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // error code
@@ -2942,8 +2917,7 @@
     0x01,
 
     // frame type (connection close frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02),
+    0x02,
     // error code
     0x08, 0x07, 0x06, 0x05,
     // error details length
@@ -3014,8 +2988,7 @@
     0x01,
 
     // frame type (go away frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x37 : 0x03),
+    0x03,
     // error code
     0x08, 0x07, 0x06, 0x05,
     // stream id
@@ -3356,8 +3329,7 @@
     0x01,
 
     // frame type (stream frame with fin and no length)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF),
+    0xDF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -3394,8 +3366,7 @@
     0xFF,
 
     // frame type (stream frame with fin and no length)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF),
+    0xDF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -3430,8 +3401,7 @@
     0x01,
 
     // frame type (stream frame with fin)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF),
+    0xFF,
     // stream id
     0x04, 0x03, 0x02, 0x01,
     // offset
@@ -3445,8 +3415,7 @@
     'r',  'l',  'd',  '!',
 
     // frame type (ack frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40),
+    0x40,
     // entropy hash of sent packets till least awaiting - 1.
     0x14,
     // least packet sequence number awaiting an ack
@@ -3491,8 +3460,7 @@
     0x00,
 
     // frame type (connection close frame)
-    static_cast<unsigned char>(
-        GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02),
+    0x02,
     // error code
     0x11, 0x00, 0x00, 0x00,
     // error details length
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 56936ed..2887207 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -218,9 +218,7 @@
   // Note: the not_reusable flag has no meaning for SPDY streams.
   if (stream_) {
     stream_->SetDelegate(NULL);
-    // TODO(rch): use new CANCELLED error code here once quic 11
-    // is everywhere.
-    stream_->Close(QUIC_ERROR_PROCESSING_STREAM);
+    stream_->Close(QUIC_STREAM_CANCELLED);
     stream_ = NULL;
   }
 }
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index ffbfad1..e3f3fd5 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -19,6 +19,7 @@
 #include "net/quic/quic_client_session.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_connection_helper.h"
+#include "net/quic/quic_default_packet_writer.h"
 #include "net/quic/quic_http_utils.h"
 #include "net/quic/quic_reliable_client_stream.h"
 #include "net/quic/spdy_utils.h"
@@ -51,8 +52,10 @@
  public:
   TestQuicConnection(QuicGuid guid,
                      IPEndPoint address,
-                     QuicConnectionHelper* helper)
-      : QuicConnection(guid, address, helper, false, QuicVersionMax()) {
+                     QuicConnectionHelper* helper,
+                     QuicPacketWriter* writer)
+      : QuicConnection(guid, address, helper, writer, false,
+                       QuicSupportedVersions()) {
   }
 
   void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
@@ -132,14 +135,12 @@
         use_closing_stream_(false),
         read_buffer_(new IOBufferWithSize(4096)),
         guid_(2),
-        framer_(QuicVersionMax(), QuicTime::Zero(), false),
+        framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         creator_(guid_, &framer_, &random_, false) {
     IPAddressNumber ip;
     CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
     peer_addr_ = IPEndPoint(ip, 443);
     self_addr_ = IPEndPoint(ip, 8435);
-    // TODO(rch): remove this.
-    QuicConnection::g_acks_do_not_instigate_acks = true;
   }
 
   ~QuicHttpStreamTest() {
@@ -147,8 +148,6 @@
     for (size_t i = 0; i < writes_.size(); i++) {
       delete writes_[i].packet;
     }
-    // TODO(rch): remove this.
-    QuicConnection::g_acks_do_not_instigate_acks = false;
   }
 
   // Adds a packet to the list of expected writes.
@@ -199,16 +198,19 @@
         Return(QuicTime::Delta::Zero()));
     EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
         Return(QuicBandwidth::Zero()));
-    helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
-                                       &random_generator_, socket);
-    connection_ = new TestQuicConnection(guid_, peer_addr_, helper_);
+    helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
+                                           &random_generator_));
+    writer_.reset(new QuicDefaultPacketWriter(socket));
+    connection_ = new TestQuicConnection(guid_, peer_addr_, helper_.get(),
+                                         writer_.get());
     connection_->set_visitor(&visitor_);
     connection_->SetSendAlgorithm(send_algorithm_);
     connection_->SetReceiveAlgorithm(receive_algorithm_);
     crypto_config_.SetDefaults();
     session_.reset(
         new QuicClientSession(connection_,
-                              scoped_ptr<DatagramClientSocket>(socket), NULL,
+                              scoped_ptr<DatagramClientSocket>(socket),
+                              writer_.Pass(), NULL,
                               &crypto_client_stream_factory_,
                               "www.google.com", DefaultQuicConfig(),
                               &crypto_config_, NULL));
@@ -267,7 +269,7 @@
   QuicEncryptedPacket* ConstructRstStreamPacket(
       QuicPacketSequenceNumber sequence_number) {
     InitializeHeader(sequence_number, false);
-    QuicRstStreamFrame frame(3, QUIC_ERROR_PROCESSING_STREAM);
+    QuicRstStreamFrame frame(3, QUIC_STREAM_CANCELLED);
     return ConstructPacket(header_, QuicFrame(&frame));
   }
 
@@ -304,9 +306,10 @@
   MockClock clock_;
   MockRandom random_generator_;
   TestQuicConnection* connection_;
-  QuicConnectionHelper* helper_;
+  scoped_ptr<QuicConnectionHelper> helper_;
   testing::StrictMock<MockConnectionVisitor> visitor_;
   scoped_ptr<QuicHttpStream> stream_;
+  scoped_ptr<QuicDefaultPacketWriter> writer_;
   scoped_ptr<QuicClientSession> session_;
   QuicCryptoClientConfig crypto_config_;
   TestCompletionCallback callback_;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 526cb68..137ceda 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -145,7 +145,7 @@
     feedback.tcp.accumulated_number_of_lost_packets = 0;
     feedback.tcp.receive_window = 256000;
 
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(QuicFrame(&ack));
     frames.push_back(QuicFrame(&feedback));
@@ -178,11 +178,8 @@
 
   std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) {
     QuicSpdyCompressor compressor;
-    if (QuicVersionMax() >= QUIC_VERSION_9) {
-      return compressor.CompressHeadersWithPriority(
-          ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers);
-    }
-    return compressor.CompressHeaders(headers);
+    return compressor.CompressHeadersWithPriority(
+        ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers);
   }
 
   // Returns a newly created packet to send kData on stream 1.
@@ -201,7 +198,7 @@
   scoped_ptr<QuicEncryptedPacket> ConstructPacket(
       const QuicPacketHeader& header,
       const QuicFrame& frame) {
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(frame);
     scoped_ptr<QuicPacket> packet(
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index d9ce156..17839af 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -17,6 +17,10 @@
 using std::pair;
 using std::vector;
 
+// If true, then QUIC handshake packets will be padded to the maximium packet
+// size.
+bool FLAGS_pad_quic_handshake_packets = false;
+
 namespace net {
 
 QuicPacketCreator::QuicPacketCreator(QuicGuid guid,
@@ -132,41 +136,42 @@
                     framer_->version(), id, offset, true);
   }
 
-  const size_t free_bytes = BytesFree();
-  size_t bytes_consumed = 0;
-
-  if (data.size() != 0) {
-    // When a STREAM frame is the last frame in a packet, it consumes two fewer
-    // bytes of framing overhead.
-    // Anytime more data is available than fits in with the extra two bytes,
-    // the frame will be the last, and up to two extra bytes are consumed.
-    // TODO(ianswett): If QUIC pads, the 1 byte PADDING frame does not fit when
-    // 1 byte is available, because then the STREAM frame isn't the last.
-
-    // The minimum frame size(0 bytes of data) if it's not the last frame.
-    size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
-        framer_->version(), id, offset, false);
-    // Check if it's the last frame in the packet.
-    if (data.size() + min_frame_size > free_bytes) {
-      // The minimum frame size(0 bytes of data) if it is the last frame.
-      size_t min_last_frame_size = QuicFramer::GetMinStreamFrameSize(
-          framer_->version(), id, offset, true);
-      bytes_consumed =
-          min<size_t>(free_bytes - min_last_frame_size, data.size());
-    } else {
-      DCHECK_LT(data.size(), BytesFree());
-      bytes_consumed = data.size();
-    }
-
-    bool set_fin = fin && bytes_consumed == data.size();  // Last frame.
-    StringPiece data_frame(data.data(), bytes_consumed);
-    *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, data_frame));
-  } else {
+  if (data.size() == 0) {
     DCHECK(fin);
     // Create a new packet for the fin, if necessary.
     *frame = QuicFrame(new QuicStreamFrame(id, true, offset, ""));
+    return 0;
   }
 
+  const size_t free_bytes = BytesFree();
+  size_t bytes_consumed = 0;
+
+  // When a STREAM frame is the last frame in a packet, it consumes two fewer
+  // bytes of framing overhead.
+  // Anytime more data is available than fits in with the extra two bytes,
+  // the frame will be the last, and up to two extra bytes are consumed.
+  // TODO(ianswett): If QUIC pads, the 1 byte PADDING frame does not fit when
+  // 1 byte is available, because then the STREAM frame isn't the last.
+
+  // The minimum frame size(0 bytes of data) if it's not the last frame.
+  size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
+      framer_->version(), id, offset, false);
+  // Check if it's the last frame in the packet.
+  if (data.size() + min_frame_size > free_bytes) {
+    // The minimum frame size(0 bytes of data) if it is the last frame.
+    size_t min_last_frame_size = QuicFramer::GetMinStreamFrameSize(
+        framer_->version(), id, offset, true);
+    bytes_consumed =
+        min<size_t>(free_bytes - min_last_frame_size, data.size());
+  } else {
+    DCHECK_LT(data.size(), BytesFree());
+    bytes_consumed = data.size();
+  }
+
+  bool set_fin = fin && bytes_consumed == data.size();  // Last frame.
+  StringPiece data_frame(data.data(), bytes_consumed);
+  *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, data_frame));
+
   return bytes_consumed;
 }
 
@@ -238,10 +243,20 @@
 size_t QuicPacketCreator::BytesFree() const {
   const size_t max_plaintext_size =
       framer_->GetMaxPlaintextSize(options_.max_packet_length);
-  if (PacketSize() >= max_plaintext_size) {
+  DCHECK_GE(max_plaintext_size, PacketSize());
+
+  // If the last frame in the packet is a stream frame, then it can be
+  // two bytes smaller than if it were not the last.  So this means that
+  // there are two fewer bytes available to the next frame in this case.
+  bool has_trailing_stream_frame =
+      !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME;
+  size_t expanded_packet_size = PacketSize() +
+      (has_trailing_stream_frame ? kQuicStreamPayloadLengthSize : 0);
+
+  if (expanded_packet_size  >= max_plaintext_size) {
     return 0;
   }
-  return max_plaintext_size - PacketSize();
+  return max_plaintext_size - expanded_packet_size;
 }
 
 size_t QuicPacketCreator::PacketSize() const {
@@ -272,8 +287,28 @@
   QuicPacketHeader header;
   FillPacketHeader(fec_group_number_, false, false, &header);
 
+  if (FLAGS_pad_quic_handshake_packets) {
+    MaybeAddPadding();
+  }
+
+  size_t max_plaintext_size =
+      framer_->GetMaxPlaintextSize(options_.max_packet_length);
+  DCHECK_GE(max_plaintext_size, packet_size_);
+  // ACK and CONNECTION_CLOSE Frames will only be truncated only if they're
+  // the first frame in the packet.  If truncation is to occure, then
+  // GetSerializedFrameLength will have returned all bytes free.
+  bool possibly_truncated =
+      packet_size_ != max_plaintext_size ||
+      queued_frames_.size() != 1 ||
+      (queued_frames_.back().type == ACK_FRAME ||
+       queued_frames_.back().type == CONNECTION_CLOSE_FRAME);
   SerializedPacket serialized =
       framer_->BuildDataPacket(header, queued_frames_, packet_size_);
+  DCHECK(serialized.packet);
+  // Because of possible truncation, we can't be confident that our
+  // packet size calculation worked correctly.
+  if (!possibly_truncated)
+    DCHECK_EQ(packet_size_, serialized.packet->length());
 
   packet_size_ = 0;
   queued_frames_.clear();
@@ -358,14 +393,18 @@
 bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
                                  bool save_retransmittable_frames) {
   size_t frame_len = framer_->GetSerializedFrameLength(
-      frame, BytesFree(), queued_frames_.empty());
+      frame, BytesFree(), queued_frames_.empty(), true);
   if (frame_len == 0) {
     return false;
   }
   DCHECK_LT(0u, packet_size_);
   MaybeStartFEC();
   packet_size_ += frame_len;
-
+  // If the last frame in the packet was a stream frame, then once we add the
+  // new frame it's serialization will be two bytes larger.
+  if (!queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME) {
+    packet_size_ += kQuicStreamPayloadLengthSize;
+  }
   if (save_retransmittable_frames && ShouldRetransmit(frame)) {
     if (queued_retransmittable_frames_.get() == NULL) {
       queued_retransmittable_frames_.reset(new RetransmittableFrames());
@@ -383,4 +422,29 @@
   return true;
 }
 
+void QuicPacketCreator::MaybeAddPadding() {
+  if (BytesFree() == 0) {
+    // Don't pad full packets.
+    return;
+  }
+
+  // If any of the frames in the current packet are on the crypto stream
+  // then they contain handshake messagses, and we should pad them.
+  bool is_handshake = false;
+  for (size_t i = 0; i < queued_frames_.size(); ++i) {
+    if (queued_frames_[i].type == STREAM_FRAME &&
+        queued_frames_[i].stream_frame->stream_id == kCryptoStreamId) {
+      is_handshake = true;
+      break;
+    }
+  }
+  if (!is_handshake) {
+    return;
+  }
+
+  QuicPaddingFrame padding;
+  bool success = AddFrame(QuicFrame(&padding), false);
+  DCHECK(success);
+}
+
 }  // namespace net
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 643c45b..614ebbc 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -18,6 +18,8 @@
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_protocol.h"
 
+NET_EXPORT_PRIVATE extern bool FLAGS_pad_quic_handshake_packets;
+
 namespace net {
 namespace test {
 class QuicPacketCreatorPeer;
@@ -32,13 +34,11 @@
   struct Options {
     Options()
         : max_packet_length(kMaxPacketSize),
-          random_reorder(false),
           max_packets_per_fec_group(0),
           send_guid_length(PACKET_8BYTE_GUID),
           send_sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER) {}
 
     size_t max_packet_length;
-    bool random_reorder;  // Inefficient: rewrite if used at scale.
     // 0 indicates fec is disabled.
     size_t max_packets_per_fec_group;
     // Length of guid to send over the wire.
@@ -116,10 +116,16 @@
   // Returns true if there are frames pending to be serialized.
   bool HasPendingFrames();
 
-  // Returns the number of bytes which are free to frames in the current packet.
+  // Returns the number of bytes which are available to be used by additional
+  // frames in the packet.  Since stream frames are slightly smaller when they
+  // are the last frame in a packet, this method will return a different
+  // value than max_packet_size - PacketSize(), in this case.
   size_t BytesFree() const;
 
-  // Returns the number of bytes in the current packet, including the header.
+  // Returns the number of bytes in the current packet, including the header,
+  // if serialized with the current frames.  Adding a frame to the packet
+  // may change the serialized length of existing frames, as per the comment
+  // in BytesFree.
   size_t PacketSize() const;
 
   // Adds |frame| to the packet creator's list of frames to be serialized.
@@ -185,6 +191,11 @@
   // Particularly useful for retransmits using SerializeAllFrames().
   bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames);
 
+  // Adds a padding frame to the current packet only if the current packet
+  // contains a handshake message, and there is sufficient room to fit a
+  // padding frame.
+  void MaybeAddPadding();
+
   Options options_;
   QuicGuid guid_;
   QuicFramer* framer_;
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index c6edf93..841d5d1 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -27,11 +27,30 @@
 namespace test {
 namespace {
 
+template<typename SaveType>
+class ValueRestore {
+ public:
+  ValueRestore(SaveType* name, SaveType value)
+      : name_(name),
+        value_(*name) {
+    *name_ = value;
+  }
+  ~ValueRestore() {
+    *name_ = value_;
+  }
+
+ private:
+  SaveType* name_;
+  SaveType value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueRestore);
+};
+
 class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
  protected:
   QuicPacketCreatorTest()
-      : server_framer_(QuicVersionMax(), QuicTime::Zero(), true),
-        client_framer_(QuicVersionMax(), QuicTime::Zero(), false),
+      : server_framer_(QuicSupportedVersions(), QuicTime::Zero(), true),
+        client_framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         sequence_number_(0),
         guid_(2),
         data_("foo"),
@@ -49,8 +68,11 @@
     server_framer_.ProcessPacket(*encrypted);
   }
 
-  void CheckStreamFrame(const QuicFrame& frame, QuicStreamId stream_id,
-                        const string& data, QuicStreamOffset offset, bool fin) {
+  void CheckStreamFrame(const QuicFrame& frame,
+                        QuicStreamId stream_id,
+                        const string& data,
+                        QuicStreamOffset offset,
+                        bool fin) {
     EXPECT_EQ(STREAM_FRAME, frame.type);
     ASSERT_TRUE(frame.stream_frame);
     EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
@@ -59,6 +81,33 @@
     EXPECT_EQ(fin, frame.stream_frame->fin);
   }
 
+  // Returns the number of bytes consumed by the header of packet, including
+  // the version, that is not in an FEC group.
+  size_t GetPacketHeaderOverhead() {
+    return GetPacketHeaderSize(creator_.options()->send_guid_length,
+                               kIncludeVersion,
+                               creator_.options()->send_sequence_number_length,
+                               NOT_IN_FEC_GROUP);
+  }
+
+  // Returns the number of bytes of overhead that will be added to a packet
+  // of maximum length.
+  size_t GetEncryptionOverhead() {
+    return creator_.options()->max_packet_length -
+        client_framer_.GetMaxPlaintextSize(
+            creator_.options()->max_packet_length);
+  }
+
+  // Returns the number of bytes consumed by the non-data fields of a stream
+  // frame, assuming it is the last frame in the packet
+  size_t GetStreamFrameOverhead() {
+    return QuicFramer::GetMinStreamFrameSize(
+        client_framer_.version(), kStreamId, kOffset, true);
+  }
+
+  static const QuicStreamId kStreamId = 1u;
+  static const QuicStreamOffset kOffset = 1u;
+
   QuicFrames frames_;
   QuicFramer server_framer_;
   QuicFramer client_framer_;
@@ -246,6 +295,7 @@
 TEST_F(QuicPacketCreatorTest, SerializeConnectionClose) {
   QuicConnectionCloseFrame frame;
   frame.error_code = QUIC_NO_ERROR;
+  frame.error_details = "error";
   frame.ack_frame = QuicAckFrame(0u, QuicTime::Zero(), 0u);
 
   SerializedPacket serialized = creator_.SerializeConnectionClose(&frame);
@@ -288,18 +338,10 @@
 }
 
 TEST_F(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
-  QuicStreamId kStreamId = 1u;
-  QuicStreamOffset kOffset = 1u;
-  for (int i = 0; i < 100; ++i) {
+  const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead();
+  for (size_t i = overhead; i < overhead + 100; ++i) {
     creator_.options()->max_packet_length = i;
-    const size_t max_plaintext_size = client_framer_.GetMaxPlaintextSize(i);
-    const bool should_have_room = max_plaintext_size >
-        (QuicFramer::GetMinStreamFrameSize(
-             client_framer_.version(), kStreamId, kOffset, true) +
-         GetPacketHeaderSize(creator_.options()->send_guid_length,
-                             kIncludeVersion,
-                             creator_.options()->send_sequence_number_length,
-                             NOT_IN_FEC_GROUP));
+    const bool should_have_room = i > overhead + GetStreamFrameOverhead();
     ASSERT_EQ(should_have_room,
               creator_.HasRoomForStreamFrame(kStreamId, kOffset));
     if (should_have_room) {
@@ -316,10 +358,104 @@
   }
 }
 
+TEST_F(QuicPacketCreatorTest, StreamFrameConsumption) {
+  // Compute the total overhead for a single frame in packet.
+  const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead()
+      + GetStreamFrameOverhead();
+  size_t capacity = kMaxPacketSize - overhead;
+  // Now, test various sizes around this size.
+  for (int delta = -5; delta <= 5; ++delta) {
+    string data(capacity + delta, 'A');
+    size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+    QuicFrame frame;
+    size_t bytes_consumed = creator_.CreateStreamFrame(
+        kStreamId, data, kOffset, false, &frame);
+    EXPECT_EQ(capacity - bytes_free, bytes_consumed);
+
+    ASSERT_TRUE(creator_.AddSavedFrame(frame));
+    // BytesFree() returns bytes available for the next frame, which will
+    // be two bytes smaller since the stream frame would need to be grown.
+    size_t expected_bytes_free = bytes_free < 3 ? 0 : bytes_free - 2;
+    EXPECT_EQ(expected_bytes_free, creator_.BytesFree()) << "delta: " << delta;
+    SerializedPacket serialized_packet = creator_.SerializePacket();
+    ASSERT_TRUE(serialized_packet.packet);
+    delete serialized_packet.packet;
+    delete serialized_packet.retransmittable_frames;
+  }
+}
+
+TEST_F(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
+  ValueRestore<bool> old_flag(&FLAGS_pad_quic_handshake_packets, true);
+
+  // Compute the total overhead for a single frame in packet.
+  const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead()
+      + GetStreamFrameOverhead();
+  ASSERT_GT(kMaxPacketSize, overhead);
+  size_t capacity = kMaxPacketSize - overhead;
+  // Now, test various sizes around this size.
+  for (int delta = -5; delta <= 5; ++delta) {
+    string data(capacity + delta, 'A');
+    size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+
+    QuicFrame frame;
+    size_t bytes_consumed = creator_.CreateStreamFrame(
+        kStreamId, data, kOffset, false, &frame);
+    EXPECT_LT(0u, bytes_consumed);
+    ASSERT_TRUE(creator_.AddSavedFrame(frame));
+    SerializedPacket serialized_packet = creator_.SerializePacket();
+    ASSERT_TRUE(serialized_packet.packet);
+    // If there is not enough space in the packet to fit a padding frame
+    // (1 byte) and to expand the stream frame (another 2 bytes) the packet
+    // will not be padded.
+    if (bytes_free < 3) {
+      EXPECT_EQ(client_framer_.GetMaxPlaintextSize(kMaxPacketSize) - bytes_free,
+                serialized_packet.packet->length());
+    } else {
+      EXPECT_EQ(client_framer_.GetMaxPlaintextSize(kMaxPacketSize),
+                serialized_packet.packet->length());
+    }
+    delete serialized_packet.packet;
+    delete serialized_packet.retransmittable_frames;
+  }
+}
+
+
+TEST_F(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
+  ValueRestore<bool> old_flag(&FLAGS_pad_quic_handshake_packets, true);
+
+  // Compute the total overhead for a single frame in packet.
+  const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead()
+      + GetStreamFrameOverhead();
+  ASSERT_GT(kMaxPacketSize, overhead);
+  size_t capacity = kMaxPacketSize - overhead;
+  // Now, test various sizes around this size.
+  for (int delta = -5; delta <= 5; ++delta) {
+    string data(capacity + delta, 'A');
+    size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+
+    QuicFrame frame;
+    size_t bytes_consumed = creator_.CreateStreamFrame(
+        kStreamId + 2, data, kOffset, false, &frame);
+    EXPECT_LT(0u, bytes_consumed);
+    ASSERT_TRUE(creator_.AddSavedFrame(frame));
+    SerializedPacket serialized_packet = creator_.SerializePacket();
+    ASSERT_TRUE(serialized_packet.packet);
+    if (bytes_free > 0) {
+      EXPECT_EQ(client_framer_.GetMaxPlaintextSize(kMaxPacketSize) - bytes_free,
+                serialized_packet.packet->length());
+    } else {
+      EXPECT_EQ(client_framer_.GetMaxPlaintextSize(kMaxPacketSize),
+                serialized_packet.packet->length());
+    }
+    delete serialized_packet.packet;
+    delete serialized_packet.retransmittable_frames;
+  }
+}
+
 TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
   QuicPacketCreatorPeer::SetIsServer(&creator_, true);
   QuicVersionVector versions;
-  versions.push_back(QuicVersionMax());
+  versions.push_back(test::QuicVersionMax());
   scoped_ptr<QuicEncryptedPacket> encrypted(
       creator_.SerializeVersionNegotiationPacket(versions));
 
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 68fcab5..a1e30aa 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -100,7 +100,7 @@
 class QuicPacketGeneratorTest : public ::testing::Test {
  protected:
   QuicPacketGeneratorTest()
-      : framer_(QuicVersionMax(), QuicTime::Zero(), false),
+      : framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         creator_(42, &framer_, &random_, false),
         generator_(&delegate_, NULL, &creator_),
         packet_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
@@ -481,9 +481,8 @@
 TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
   // Set the packet size be enough for two stream frames with 0 stream offset,
   // but not enough for a stream frame of 0 offset and one with non-zero offset.
-  bool use_short_hash = framer_.version() >= QUIC_VERSION_11;
   creator_.options()->max_packet_length =
-      NullEncrypter(use_short_hash).GetCiphertextSize(0) +
+      NullEncrypter(false).GetCiphertextSize(0) +
       GetPacketHeaderSize(creator_.options()->send_guid_length,
                           true,
                           creator_.options()->send_sequence_number_length,
diff --git a/net/quic/quic_packet_writer.h b/net/quic/quic_packet_writer.h
new file mode 100644
index 0000000..5df30c8
--- /dev/null
+++ b/net/quic/quic_packet_writer.h
@@ -0,0 +1,41 @@
+// Copyright 2013 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 NET_QUIC_QUIC_PACKET_WRITER_H_
+#define NET_QUIC_QUIC_PACKET_WRITER_H_
+
+#include "net/base/ip_endpoint.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class QuicBlockedWriterInterface;
+struct WriteResult;
+
+// An interface between writers and the entity managing the
+// socket (in our case the QuicDispatcher).  This allows the Dispatcher to
+// control writes, and manage any writers who end up write blocked.
+class NET_EXPORT_PRIVATE QuicPacketWriter {
+ public:
+  virtual ~QuicPacketWriter() {}
+
+  // Sends the packet out to the peer.  If the write succeeded, the result's
+  // status is WRITE_STATUS_OK and bytes_written is populated. If the write
+  // failed, the result's status is WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR
+  // and error_code is populated.
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const net::IPAddressNumber& self_address,
+      const net::IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) = 0;
+
+  // Returns true if the writer buffers and subsequently rewrites data
+  // when an attempt to write results in the underlying socket becoming
+  // write blocked.
+  virtual bool IsWriteBlockedDataBuffered() const = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_QUIC_PACKET_WRITER_H_
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 72843ef..23c3b4f 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -113,16 +113,16 @@
          static_cast<uint32>(d) << 24;
 }
 
-QuicVersion QuicVersionMax() { return kSupportedQuicVersions[0]; }
-
-QuicVersion QuicVersionMin() {
-  return kSupportedQuicVersions[arraysize(kSupportedQuicVersions) - 1];
+QuicVersionVector QuicSupportedVersions() {
+  QuicVersionVector supported_versions;
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    supported_versions.push_back(kSupportedQuicVersions[i]);
+  }
+  return supported_versions;
 }
 
 QuicTag QuicVersionToQuicTag(const QuicVersion version) {
   switch (version) {
-    case QUIC_VERSION_9:
-      return MakeQuicTag('Q', '0', '0', '9');
     case QUIC_VERSION_10:
       return MakeQuicTag('Q', '0', '1', '0');
     case QUIC_VERSION_11:
@@ -153,7 +153,6 @@
 
 string QuicVersionToString(const QuicVersion version) {
   switch (version) {
-    RETURN_STRING_LITERAL(QUIC_VERSION_9);
     RETURN_STRING_LITERAL(QUIC_VERSION_10);
     RETURN_STRING_LITERAL(QUIC_VERSION_11);
     default:
@@ -161,13 +160,13 @@
   }
 }
 
-string QuicVersionArrayToString(const QuicVersion versions[],
-                                int num_versions) {
+string QuicVersionVectorToString(const QuicVersionVector& versions) {
   string result = "";
-  for (int i = 0; i < num_versions; ++i) {
-    const QuicVersion& version = versions[i];
-    result.append(QuicVersionToString(version));
-    result.append(",");
+  for (size_t i = 0; i < versions.size(); ++i) {
+    if (i != 0) {
+      result.append(",");
+    }
+    result.append(QuicVersionToString(versions[i]));
   }
   return result;
 }
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 8b3c1e9..6c152e8 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -83,6 +83,23 @@
 const int64 kDefaultTimeoutSecs = 60 * 10;  // 10 minutes.
 const int64 kDefaultMaxTimeForCryptoHandshakeSecs = 5;  // 5 secs.
 
+// We define an unsigned 16-bit floating point value, inspired by IEEE floats
+// (http://en.wikipedia.org/wiki/Half_precision_floating-point_format),
+// with 5-bit exponent (bias 1), 11-bit mantissa (effective 12 with hidden
+// bit) and denormals, but without signs, transfinites or fractions. Wire format
+// 16 bits (little-endian byte order) are split into exponent (high 5) and
+// mantissa (low 11) and decoded as:
+//   uint64 value;
+//   if (exponent == 0) value = mantissa;
+//   else value = (mantissa | 1 << 11) << (exponent - 1)
+const int kUFloat16ExponentBits = 5;
+const int kUFloat16MaxExponent = (1 << kUFloat16ExponentBits) - 2;  // 30
+const int kUFloat16MantissaBits = 16 - kUFloat16ExponentBits;  // 11
+const int kUFloat16MantissaEffectiveBits = kUFloat16MantissaBits + 1;  // 12
+const uint64 kUFloat16MaxValue =  // 0x3FFC0000000
+    ((GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1) <<
+    kUFloat16MaxExponent;
+
 enum TransmissionType {
   NOT_RETRANSMISSION,
   NACK_RETRANSMISSION,
@@ -190,7 +207,6 @@
   // Special case to indicate unknown/unsupported QUIC version.
   QUIC_VERSION_UNSUPPORTED = 0,
 
-  QUIC_VERSION_9 = 9,
   QUIC_VERSION_10 = 10,
   QUIC_VERSION_11 = 11,  // Current version.
 };
@@ -200,15 +216,12 @@
 // element, with subsequent elements in descending order (versions can be
 // skipped as necessary).
 static const QuicVersion kSupportedQuicVersions[] =
-    {QUIC_VERSION_10, QUIC_VERSION_9};
+    {QUIC_VERSION_11};
 
 typedef std::vector<QuicVersion> QuicVersionVector;
 
-// Upper limit on versions we support.
-NET_EXPORT_PRIVATE QuicVersion QuicVersionMax();
-
-// Lower limit on versions we support.
-NET_EXPORT_PRIVATE QuicVersion QuicVersionMin();
+// Returns a vector of QUIC versions in kSupportedQuicVersions.
+NET_EXPORT_PRIVATE QuicVersionVector QuicSupportedVersions();
 
 // QuicTag is written to and read from the wire, but we prefer to use
 // the more readable QuicVersion at other levels.
@@ -220,18 +233,14 @@
 // Returns QUIC_VERSION_UNSUPPORTED if version_tag cannot be understood.
 NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag);
 
-// Returns the appropriate QuicTag for a properly formed version string
-// (e.g. Q010).
-NET_EXPORT_PRIVATE QuicTag StringToQuicTag(std::string version);
-
 // Helper function which translates from a QuicVersion to a string.
 // Returns strings corresponding to enum names (e.g. QUIC_VERSION_6).
 NET_EXPORT_PRIVATE std::string QuicVersionToString(const QuicVersion version);
 
 // Returns comma separated list of string representations of QuicVersion enum
-// values in the supplied QuicVersionArray.
-NET_EXPORT_PRIVATE std::string QuicVersionArrayToString(
-    const QuicVersion versions[], int num_versions);
+// values in the supplied |versions| vector.
+NET_EXPORT_PRIVATE std::string QuicVersionVectorToString(
+    const QuicVersionVector& versions);
 
 // Version and Crypto tags are written to the wire with a big-endian
 // representation of the name of the tag.  For example
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
index 0b96e4d..5162c45 100644
--- a/net/quic/quic_protocol_test.cc
+++ b/net/quic/quic_protocol_test.cc
@@ -56,8 +56,8 @@
 #endif
 
   // Explicitly test a specific version.
-  EXPECT_EQ(MakeQuicTag('Q', '0', '1', '0'),
-            QuicVersionToQuicTag(QUIC_VERSION_10));
+  EXPECT_EQ(MakeQuicTag('Q', '0', '1', '1'),
+            QuicVersionToQuicTag(QUIC_VERSION_11));
 
   // Loop over all supported versions and make sure that we never hit the
   // default case (i.e. all supported versions should be successfully converted
@@ -95,8 +95,8 @@
 #endif
 
   // Explicitly test specific versions.
-  EXPECT_EQ(QUIC_VERSION_10,
-            QuicTagToQuicVersion(MakeQuicTag('Q', '0', '1', '0')));
+  EXPECT_EQ(QUIC_VERSION_11,
+            QuicTagToQuicVersion(MakeQuicTag('Q', '0', '1', '1')));
 
   for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
     QuicVersion version = kSupportedQuicVersions[i];
@@ -132,13 +132,19 @@
             QuicVersionToString(QUIC_VERSION_UNSUPPORTED));
 
   QuicVersion single_version[] = {QUIC_VERSION_10};
-  EXPECT_EQ("QUIC_VERSION_10,",
-            QuicVersionArrayToString(single_version,
-                                     arraysize(single_version)));
-  QuicVersion multiple_versions[] = {QUIC_VERSION_10, QUIC_VERSION_9};
-  EXPECT_EQ("QUIC_VERSION_10,QUIC_VERSION_9,",
-            QuicVersionArrayToString(multiple_versions,
-                                     arraysize(multiple_versions)));
+  QuicVersionVector versions_vector;
+  for (size_t i = 0; i < arraysize(single_version); ++i) {
+    versions_vector.push_back(single_version[i]);
+  }
+  EXPECT_EQ("QUIC_VERSION_10", QuicVersionVectorToString(versions_vector));
+
+  QuicVersion multiple_versions[] = {QUIC_VERSION_11, QUIC_VERSION_10};
+  versions_vector.clear();
+  for (size_t i = 0; i < arraysize(multiple_versions); ++i) {
+    versions_vector.push_back(multiple_versions[i]);
+  }
+  EXPECT_EQ("QUIC_VERSION_11,QUIC_VERSION_10",
+            QuicVersionVectorToString(versions_vector));
 
   // Make sure that all supported versions are present in QuicVersionToString.
   for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 9389af4..77494b5 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -59,8 +59,9 @@
     session_->OnSuccessfulVersionNegotiation(version);
   }
 
-  virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE {
-    session_->ConnectionClose(error, from_peer);
+  virtual void OnConnectionClosed(QuicErrorCode error,
+                                  bool from_peer) OVERRIDE {
+    session_->OnConnectionClosed(error, from_peer);
     // The session will go away, so don't bother with cleanup.
   }
 
@@ -183,7 +184,7 @@
   goaway_received_ = true;
 }
 
-void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
+void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) {
   DCHECK(!connection_->connected());
   if (error_ == QUIC_NO_ERROR) {
     error_ = error;
@@ -192,10 +193,11 @@
   while (stream_map_.size() != 0) {
     ReliableStreamMap::iterator it = stream_map_.begin();
     QuicStreamId id = it->first;
-    it->second->ConnectionClose(error, from_peer);
-    // The stream should call CloseStream as part of ConnectionClose.
+    it->second->OnConnectionClosed(error, from_peer);
+    // The stream should call CloseStream as part of OnConnectionClosed.
     if (stream_map_.find(id) != stream_map_.end()) {
-      LOG(DFATAL) << ENDPOINT << "Stream failed to close under ConnectionClose";
+      LOG(DFATAL) << ENDPOINT
+                  << "Stream failed to close under OnConnectionClosed";
       CloseStream(id);
     }
   }
@@ -240,7 +242,9 @@
                                          int iov_count,
                                          QuicStreamOffset offset,
                                          bool fin) {
-  return connection_->SendvStreamData(id, iov, iov_count, offset, fin);
+  IOVector data;
+  data.AppendIovec(iov, iov_count);
+  return connection_->SendStreamData(id, data, offset, fin);
 }
 
 void QuicSession::SendRstStream(QuicStreamId id,
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index b58feb2..3867ff6 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -63,7 +63,7 @@
       const std::vector<QuicStreamFrame>& frames) OVERRIDE;
   virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE;
   virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE;
-  virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
+  virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
   virtual void OnSuccessfulVersionNegotiation(
       const QuicVersion& version) OVERRIDE{}
   // Not needed for HTTP.
@@ -162,6 +162,8 @@
 
   QuicErrorCode error() const { return error_; }
 
+  bool is_server() const { return is_server_; }
+
  protected:
   // Creates a new stream, owned by the caller, to handle a peer-initiated
   // stream.  Returns NULL and does error handling if the stream can not be
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 7df1f37..4df9610 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -18,6 +18,7 @@
 #include "net/dns/host_resolver.h"
 #include "net/dns/single_request_host_resolver.h"
 #include "net/http/http_server_properties.h"
+#include "net/quic/congestion_control/tcp_receiver.h"
 #include "net/quic/crypto/proof_verifier_chromium.h"
 #include "net/quic/crypto/quic_random.h"
 #include "net/quic/quic_client_session.h"
@@ -25,6 +26,7 @@
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_connection_helper.h"
 #include "net/quic/quic_crypto_client_stream_factory.h"
+#include "net/quic/quic_default_packet_writer.h"
 #include "net/quic/quic_http_stream.h"
 #include "net/quic/quic_protocol.h"
 #include "net/socket/client_socket_factory.h"
@@ -428,31 +430,36 @@
   socket->Connect(addr);
 
   // We should adaptively set this buffer size, but for now, we'll use a size
-  // that is more than large enough for a 100 packet congestion window, and yet
+  // that is more than large enough for a full receive window, and yet
   // does not consume "too much" memory.  If we see bursty packet loss, we may
   // revisit this setting and test for its impact.
-  const int32 kSocketBufferSize(kMaxPacketSize * 100);  // Support 100 packets.
+  const int32 kSocketBufferSize(TcpReceiver::kReceiveWindowTCP);
   socket->SetReceiveBufferSize(kSocketBufferSize);
   // Set a buffer large enough to contain the initial CWND's worth of packet
   // to work around the problem with CHLO packets being sent out with the
   // wrong encryption level, when the send buffer is full.
   socket->SetSendBufferSize(kMaxPacketSize * 20); // Support 20 packets.
 
-  QuicConnectionHelper* helper = new QuicConnectionHelper(
-      base::MessageLoop::current()->message_loop_proxy().get(),
-      clock_.get(),
-      random_generator_,
-      socket.get());
+  scoped_ptr<QuicDefaultPacketWriter> writer(
+      new QuicDefaultPacketWriter(socket.get()));
 
-  QuicConnection* connection = new QuicConnection(guid, addr, helper, false,
-                                                  QuicVersionMax());
+  if (!helper_.get()) {
+    helper_.reset(new QuicConnectionHelper(
+        base::MessageLoop::current()->message_loop_proxy().get(),
+        clock_.get(), random_generator_));
+  }
+
+  QuicConnection* connection = new QuicConnection(guid, addr, helper_.get(),
+                                                  writer.get(), false,
+                                                  QuicSupportedVersions());
+  writer->SetConnection(connection);
 
   QuicCryptoClientConfig* crypto_config =
       GetOrCreateCryptoConfig(host_port_proxy_pair);
   DCHECK(crypto_config);
 
   QuicClientSession* session =
-      new QuicClientSession(connection, socket.Pass(), this,
+      new QuicClientSession(connection, socket.Pass(), writer.Pass(), this,
                             quic_crypto_client_stream_factory_,
                             host_port_proxy_pair.first.host(), config_,
                             crypto_config, net_log.net_log());
@@ -490,9 +497,7 @@
     crypto_config = new QuicCryptoClientConfig();
     crypto_config->SetDefaults();
     all_crypto_configs_[host_port_proxy_pair] = crypto_config;
-    // TODO(rtenneti): Temporarily disabled using CanonicalConfig until we fix
-    // performance problems.
-    // PopulateFromCanonicalConfig(host_port_proxy_pair, crypto_config);
+    PopulateFromCanonicalConfig(host_port_proxy_pair, crypto_config);
   }
   return crypto_config;
 }
@@ -527,6 +532,8 @@
   crypto_config->InitializeFrom(server_hostname,
                                 canonical_host_port_proxy_pair.first.host(),
                                 canonical_crypto_config);
+  // Update canonical version to point at the "most recent" crypto_config.
+  canonical_hostname_to_origin_map_[canonical_host_port] = host_port_proxy_pair;
 }
 
 }  // namespace net
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 6316d62..f688dcb 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -28,6 +28,7 @@
 class HttpServerProperties;
 class QuicClock;
 class QuicClientSession;
+class QuicConnectionHelper;
 class QuicCryptoClientStreamFactory;
 class QuicRandom;
 class QuicStreamFactory;
@@ -136,6 +137,8 @@
     require_confirmation_ = require_confirmation;
   }
 
+  QuicConnectionHelper* helper() { return helper_.get(); }
+
  private:
   class Job;
   friend class test::QuicStreamFactoryPeer;
@@ -182,6 +185,9 @@
   QuicRandom* random_generator_;
   scoped_ptr<QuicClock> clock_;
 
+  // The helper used for all connections.
+  scoped_ptr<QuicConnectionHelper> helper_;
+
   // Contains owning pointers to all sessions that currently exist.
   SessionSet all_sessions_;
   // Contains non-owning pointers to currently active session
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 8f1291a..c5c75e3 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -85,7 +85,7 @@
     header.fec_flag = false;
     header.fec_group = 0;
 
-    QuicRstStreamFrame rst(stream_id, QUIC_ERROR_PROCESSING_STREAM);
+    QuicRstStreamFrame rst(stream_id, QUIC_STREAM_CANCELLED);
     return scoped_ptr<QuicEncryptedPacket>(
         ConstructPacket(header, QuicFrame(&rst)));
   }
@@ -108,7 +108,7 @@
     feedback.tcp.accumulated_number_of_lost_packets = 0;
     feedback.tcp.receive_window = 16000;
 
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(QuicFrame(&ack));
     frames.push_back(QuicFrame(&feedback));
@@ -142,7 +142,7 @@
   scoped_ptr<QuicEncryptedPacket> ConstructPacket(
       const QuicPacketHeader& header,
       const QuicFrame& frame) {
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(frame);
     scoped_ptr<QuicPacket> packet(
@@ -458,7 +458,7 @@
   EXPECT_TRUE(socket_data2.at_write_eof());
 }
 
-TEST_F(QuicStreamFactoryTest, DISABLED_SharedCryptoConfig) {
+TEST_F(QuicStreamFactoryTest, SharedCryptoConfig) {
   HostPortProxyPair host_port_proxy_pair1(HostPortPair("r1.c.youtube.com", 80),
                                           ProxyServer::Direct());
 
@@ -468,9 +468,13 @@
   DCHECK(crypto_config1);
   QuicCryptoClientConfig::CachedState* cached1 =
       crypto_config1->LookupOrCreate(host_port_proxy_pair1.first.host());
+  EXPECT_FALSE(cached1->proof_valid());
+  EXPECT_TRUE(cached1->source_address_token().empty());
+
   // Mutate the cached1 to have different data.
   // TODO(rtenneti): mutate other members of CachedState.
   cached1->set_source_address_token("c.youtube.com");
+  cached1->SetProofValid();
 
   HostPortProxyPair host_port_proxy_pair2(HostPortPair("r2.c.youtube.com", 80),
                                           ProxyServer::Direct());
@@ -481,6 +485,38 @@
   QuicCryptoClientConfig::CachedState* cached2 =
       crypto_config2->LookupOrCreate(host_port_proxy_pair2.first.host());
   EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token());
+  EXPECT_TRUE(cached2->proof_valid());
+}
+
+TEST_F(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
+  HostPortProxyPair host_port_proxy_pair1(HostPortPair("r1.c.youtube.com", 80),
+                                          ProxyServer::Direct());
+
+  QuicCryptoClientConfig* crypto_config1 =
+      QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
+                                                     host_port_proxy_pair1);
+  DCHECK(crypto_config1);
+  QuicCryptoClientConfig::CachedState* cached1 =
+      crypto_config1->LookupOrCreate(host_port_proxy_pair1.first.host());
+  EXPECT_FALSE(cached1->proof_valid());
+  EXPECT_TRUE(cached1->source_address_token().empty());
+
+  // Mutate the cached1 to have different data.
+  // TODO(rtenneti): mutate other members of CachedState.
+  cached1->set_source_address_token("c.youtube.com");
+  cached1->SetProofInvalid();
+
+  HostPortProxyPair host_port_proxy_pair2(HostPortPair("r2.c.youtube.com", 80),
+                                          ProxyServer::Direct());
+  QuicCryptoClientConfig* crypto_config2 =
+      QuicStreamFactoryPeer::GetOrCreateCryptoConfig(&factory_,
+                                                     host_port_proxy_pair2);
+  DCHECK(crypto_config2);
+  QuicCryptoClientConfig::CachedState* cached2 =
+      crypto_config2->LookupOrCreate(host_port_proxy_pair2.first.host());
+  EXPECT_NE(cached1->source_address_token(), cached2->source_address_token());
+  EXPECT_TRUE(cached2->source_address_token().empty());
+  EXPECT_FALSE(cached2->proof_valid());
 }
 
 }  // namespace test
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index a57c05f..e6050bc 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -80,7 +80,8 @@
 
   if (data_len == 0 && !frame.fin) {
     // Stream frames must have data or a fin flag.
-    stream_->ConnectionClose(QUIC_INVALID_STREAM_FRAME, false);
+    stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME,
+                                        "Empty stream frame without FIN set.");
     return false;
   }
 
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 21568d6..f572f9a 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -8,7 +8,9 @@
 #include <vector>
 
 #include "base/rand_util.h"
+#include "net/base/ip_endpoint.h"
 #include "net/quic/reliable_quic_stream.h"
+#include "net/quic/test_tools/quic_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -71,7 +73,8 @@
 
   MOCK_METHOD1(TerminateFromPeer, void(bool half_close));
   MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len));
-  MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer));
+  MOCK_METHOD2(CloseConnectionWithDetails, void(QuicErrorCode error,
+                                                const string& details));
   MOCK_METHOD1(Close, void(QuicRstStreamErrorCode error));
   MOCK_METHOD0(OnCanWrite, void());
 };
@@ -84,8 +87,9 @@
 class QuicStreamSequencerTest : public ::testing::Test {
  protected:
   QuicStreamSequencerTest()
-      : session_(NULL),
-        stream_(session_,  1),
+      : connection_(new MockConnection(1, IPEndPoint(), false)),
+        session_(connection_, true),
+        stream_(&session_, 1),
         sequencer_(new QuicStreamSequencerPeer(&stream_)) {
   }
 
@@ -127,7 +131,8 @@
     return true;
   }
 
-  QuicSession* session_;
+  MockConnection* connection_;
+  MockSession session_;
   testing::StrictMock<MockStream> stream_;
   scoped_ptr<QuicStreamSequencerPeer> sequencer_;
 };
@@ -183,7 +188,8 @@
 }
 
 TEST_F(QuicStreamSequencerTest, EmptyFrame) {
-  EXPECT_CALL(stream_, ConnectionClose(QUIC_INVALID_STREAM_FRAME, false));
+  EXPECT_CALL(stream_,
+              CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _));
   EXPECT_FALSE(sequencer_->OnFrame(0, ""));
   EXPECT_EQ(0u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index ed0cac3..bf1601f 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -230,7 +230,7 @@
 
   for (size_t i = 0; i < sizeof(chars); i++) {
     chars[i] = tag;
-    if (chars[i] == 0 && i == 3) {
+    if ((chars[i] == 0 || chars[i] == '\xff') && i == 3) {
       chars[i] = ' ';
     }
     if (!isprint(static_cast<unsigned char>(chars[i]))) {
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
index 0e50aec..0a0355f 100644
--- a/net/quic/quic_utils_test.cc
+++ b/net/quic/quic_utils_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/quic/quic_utils.h"
 
+#include "net/quic/crypto/crypto_protocol.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::StringPiece;
@@ -68,6 +69,21 @@
           string(reinterpret_cast<const char*>(kString), sizeof(kString))));
 }
 
+TEST(QuicUtilsTest, TagToString) {
+  EXPECT_EQ("SCFG",
+            QuicUtils::TagToString(kSCFG));
+  EXPECT_EQ("SNO ",
+            QuicUtils::TagToString(kServerNonceTag));
+  EXPECT_EQ("CRT ",
+            QuicUtils::TagToString(kCertificateTag));
+  EXPECT_EQ("CHLO",
+            QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', 'O')));
+  // A tag that contains a non-printing character will be printed as a decimal
+  // number.
+  EXPECT_EQ("525092931",
+            QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', '\x1f')));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index dea1e81..afba1f0 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -61,7 +61,8 @@
       write_side_closed_(false),
       priority_parsed_(false),
       fin_buffered_(false),
-      fin_sent_(false) {
+      fin_sent_(false),
+      is_server_(session_->is_server()) {
 }
 
 ReliableQuicStream::~ReliableQuicStream() {
@@ -82,7 +83,7 @@
 bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
   DCHECK_EQ(frame.stream_id, id_);
   if (read_side_closed_) {
-    DLOG(INFO) << "Ignoring frame " << frame.stream_id;
+    DLOG(INFO) << ENDPOINT << "Ignoring frame " << frame.stream_id;
     // We don't want to be reading: blackhole the data.
     return true;
   }
@@ -99,7 +100,8 @@
   TerminateFromPeer(false);  // Full close.
 }
 
-void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) {
+void ReliableQuicStream::OnConnectionClosed(QuicErrorCode error,
+                                            bool from_peer) {
   if (read_side_closed_ && write_side_closed_) {
     return;
   }
@@ -133,6 +135,15 @@
   }
 }
 
+void ReliableQuicStream::CloseConnection(QuicErrorCode error) {
+  session()->connection()->SendConnectionClose(error);
+}
+
+void ReliableQuicStream::CloseConnectionWithDetails(QuicErrorCode error,
+                                                    const string& details) {
+  session()->connection()->SendConnectionCloseWithDetails(error, details);
+}
+
 size_t ReliableQuicStream::Readv(const struct iovec* iov, size_t iov_len) {
   if (headers_decompressed_ && decompressed_headers_.empty()) {
     return sequencer_.Readv(iov, iov_len);
@@ -251,7 +262,7 @@
                                                         int iov_count,
                                                         bool fin) {
   if (write_side_closed_) {
-    DLOG(ERROR) << "Attempt to write when the write side is closed";
+    DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
     return QuicConsumedData(0, false);
   }
 
@@ -283,11 +294,11 @@
   if (read_side_closed_) {
     return;
   }
-  DLOG(INFO) << "Done reading from stream " << id();
+  DLOG(INFO) << ENDPOINT << "Done reading from stream " << id();
 
   read_side_closed_ = true;
   if (write_side_closed_) {
-    DLOG(INFO) << "Closing stream: " << id();
+    DLOG(INFO) << ENDPOINT << "Closing stream: " << id();
     session_->CloseStream(id());
   }
 }
@@ -328,7 +339,8 @@
   // Ensure that this header id looks sane.
   if (headers_id_ < current_header_id ||
       headers_id_ > kMaxHeaderIdDelta + current_header_id) {
-    DVLOG(1) << "Invalid headers for stream: " << id()
+    DVLOG(1) << ENDPOINT
+             << "Invalid headers for stream: " << id()
              << " header_id: " << headers_id_
              << " current_header_id: " << current_header_id;
     session_->connection()->SendConnectionClose(QUIC_INVALID_HEADER_ID);
@@ -338,7 +350,8 @@
   // If we are head-of-line blocked on decompression, then back up.
   if (current_header_id != headers_id_) {
     session_->MarkDecompressionBlocked(headers_id_, id());
-    DVLOG(1) << "Unable to decompress header data for stream: " << id()
+    DVLOG(1) << ENDPOINT
+             << "Unable to decompress header data for stream: " << id()
              << " header_id: " << headers_id_;
     return total_bytes_consumed;
   }
@@ -453,11 +466,11 @@
   if (write_side_closed_) {
     return;
   }
-  DLOG(INFO) << "Done writing to stream " << id();
+  DLOG(INFO) << ENDPOINT << "Done writing to stream " << id();
 
   write_side_closed_ = true;
   if (read_side_closed_) {
-    DLOG(INFO) << "Closing stream: " << id();
+    DLOG(INFO) << ENDPOINT << "Closing stream: " << id();
     session_->CloseStream(id());
   }
 }
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 807882c..bc7d29c 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -28,6 +28,8 @@
 class QuicSession;
 class SSLInfo;
 
+#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
+
 // All this does right now is send data to subclasses via the sequencer.
 class NET_EXPORT_PRIVATE ReliableQuicStream : public
     QuicSpdyDecompressor::Visitor {
@@ -66,7 +68,7 @@
   // Called when we get or send a connection close, and should immediately
   // close the stream.  This is not passed through the sequencer,
   // but is handled immediately.
-  virtual void ConnectionClose(QuicErrorCode error, bool from_peer);
+  virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer);
 
   // Called when we should process a stream termination or
   // stream close from the peer.
@@ -83,6 +85,11 @@
   // Called to close the stream from this end.
   virtual void Close(QuicRstStreamErrorCode error);
 
+  // Called to close the entire connection from this end.
+  virtual void CloseConnection(QuicErrorCode error);
+  virtual void CloseConnectionWithDetails(QuicErrorCode error,
+                                          const string& details);
+
   // This block of functions wraps the sequencer's functions of the same
   // name.  These methods return uncompressed data until that has
   // been fully processed.  Then they simply delegate to the sequencer.
@@ -219,6 +226,9 @@
   bool priority_parsed_;
   bool fin_buffered_;
   bool fin_sent_;
+
+  // True if the session this stream is running under is a server session.
+  bool is_server_;
 };
 
 }  // namespace net
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 063554d..7d1a1f1 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -222,7 +222,7 @@
   stream_->CloseWriteSide();
   EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
   EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
-  stream_->ConnectionClose(QUIC_INTERNAL_ERROR, false);
+  stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, false);
   EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
   EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
 }
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 73b5bab..76de7fa 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -136,7 +136,7 @@
   IPEndPoint addr = IPEndPoint(ip, 1);
   PacketSavingConnection* server_conn =
       new PacketSavingConnection(guid, addr, true);
-  TestSession server_session(server_conn, QuicConfig(), true);
+  TestSession server_session(server_conn, DefaultQuicConfig(), true);
 
   QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
                                        QuicRandom::GetInstance());
@@ -169,7 +169,7 @@
   IPEndPoint addr = IPEndPoint(ip, 1);
   PacketSavingConnection* client_conn =
       new PacketSavingConnection(guid, addr, false);
-  TestSession client_session(client_conn, QuicConfig(), false);
+  TestSession client_session(client_conn, DefaultQuicConfig(), false);
   QuicCryptoClientConfig crypto_config;
 
   client_session.config()->SetDefaults();
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 67e1746..7bdaec0 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -9,7 +9,9 @@
 #include "net/quic/congestion_control/receive_algorithm_interface.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
 #include "net/quic/quic_connection.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/test_tools/quic_framer_peer.h"
+#include "net/quic/test_tools/quic_test_writer.h"
 
 namespace net {
 namespace test {
@@ -152,7 +154,7 @@
 // static
 QuicConnectionHelperInterface* QuicConnectionPeer::GetHelper(
     QuicConnection* connection) {
-  return connection->helper_.get();
+  return connection->helper_;
 }
 
 // static
@@ -193,5 +195,16 @@
   return connection->timeout_alarm_.get();
 }
 
+// static
+QuicPacketWriter* QuicConnectionPeer::GetWriter(QuicConnection* connection) {
+  return connection->writer_;
+}
+
+// static
+void QuicConnectionPeer::SetWriter(QuicConnection* connection,
+                                   QuicTestWriter* writer) {
+  connection->writer_ = writer;
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 9064c97..faf9aed 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -22,11 +22,14 @@
 class QuicFecGroup;
 class QuicFramer;
 class QuicPacketCreator;
+class QuicPacketWriter;
 class ReceiveAlgorithmInterface;
 class SendAlgorithmInterface;
 
 namespace test {
 
+class QuicTestWriter;
+
 // Peer to make public a number of otherwise private QuicConnection methods.
 class QuicConnectionPeer {
  public:
@@ -102,6 +105,9 @@
   static QuicAlarm* GetResumeWritesAlarm(QuicConnection* connection);
   static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection);
 
+  static QuicPacketWriter* GetWriter(QuicConnection* connection);
+  static void SetWriter(QuicConnection* connection, QuicTestWriter* writer);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
 };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ceb6418..e1d148f 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -13,6 +13,7 @@
 #include "net/quic/crypto/quic_encrypter.h"
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/spdy/spdy_frame_builder.h"
 
 using base::StringPiece;
@@ -108,6 +109,7 @@
 }
 
 FramerVisitorCapturingFrames::~FramerVisitorCapturingFrames() {
+  STLDeleteElements(&stream_data_);
 }
 
 bool FramerVisitorCapturingFrames::OnPacketHeader(
@@ -118,9 +120,12 @@
 }
 
 bool FramerVisitorCapturingFrames::OnStreamFrame(const QuicStreamFrame& frame) {
-  // TODO(ianswett): Own the underlying string, so it will not exist outside
-  // this callback.
-  stream_frames_.push_back(frame);
+  // Make a copy of the frame and store a copy of underlying string, since
+  // frame.data may not exist outside this callback.
+  stream_data_.push_back(new string(frame.data.as_string()));
+  QuicStreamFrame frame_copy = frame;
+  stream_frames_.push_back(frame_copy);
+  stream_frames_.back().data = *(stream_data_.back());
   ++frame_count_;
   return true;
 }
@@ -207,15 +212,20 @@
                                IPEndPoint address,
                                bool is_server)
     : QuicConnection(guid, address, new testing::NiceMock<MockHelper>(),
-                     is_server, QuicVersionMax()),
-      has_mock_helper_(true) {
+                     new testing::NiceMock<MockPacketWriter>(),
+                     is_server, QuicSupportedVersions()),
+      has_mock_helper_(true),
+      writer_(QuicConnectionPeer::GetWriter(this)),
+      helper_(helper()) {
 }
 
 MockConnection::MockConnection(QuicGuid guid,
                                IPEndPoint address,
                                QuicConnectionHelperInterface* helper,
+                               QuicPacketWriter* writer,
                                bool is_server)
-    : QuicConnection(guid, address, helper, is_server, QuicVersionMax()),
+    : QuicConnection(guid, address, helper, writer, is_server,
+                     QuicSupportedVersions()),
       has_mock_helper_(false) {
 }
 
@@ -246,6 +256,7 @@
     QuicPacketEntropyHash /* entropy_hash */,
     TransmissionType /* transmission_type */,
     HasRetransmittableData /* retransmittable */,
+    IsHandshake /* handshake */,
     Force /* forced */) {
   packets_.push_back(packet);
   QuicEncryptedPacket* encrypted =
@@ -280,6 +291,12 @@
   return crypto_stream_;
 }
 
+MockPacketWriter::MockPacketWriter() {
+}
+
+MockPacketWriter::~MockPacketWriter() {
+}
+
 MockSendAlgorithm::MockSendAlgorithm() {
 }
 
@@ -333,12 +350,17 @@
 
 }  // namespace
 
+QuicVersion QuicVersionMax() { return QuicSupportedVersions().front(); }
+
+QuicVersion QuicVersionMin() { return QuicSupportedVersions().back(); }
+
 void CompareCharArraysWithHexError(
     const string& description,
     const char* actual,
     const int actual_len,
     const char* expected,
     const int expected_len) {
+  EXPECT_EQ(actual_len, expected_len);
   const int min_len = min(actual_len, expected_len);
   const int max_len = max(actual_len, expected_len);
   scoped_ptr<bool[]> marks(new bool[max_len]);
@@ -370,7 +392,7 @@
     bool should_include_version) {
   CryptoFramer crypto_framer;
   scoped_ptr<QuicData> data(crypto_framer.ConstructHandshakeMessage(message));
-  QuicFramer quic_framer(QuicVersionMax(), QuicTime::Zero(), false);
+  QuicFramer quic_framer(QuicSupportedVersions(), QuicTime::Zero(), false);
 
   QuicPacketHeader header;
   header.public_header.guid = guid;
@@ -404,13 +426,12 @@
     InFecGroup is_in_fec_group,
     size_t* payload_length) {
   *payload_length = 1;
-  bool use_short_hash = version >= QUIC_VERSION_11;
   const size_t stream_length =
-      NullEncrypter(use_short_hash).GetCiphertextSize(*payload_length) +
+      NullEncrypter(false).GetCiphertextSize(*payload_length) +
       QuicPacketCreator::StreamFramePacketOverhead(
           version, PACKET_8BYTE_GUID, include_version,
           sequence_number_length, is_in_fec_group);
-  const size_t ack_length = NullEncrypter(use_short_hash).GetCiphertextSize(
+  const size_t ack_length = NullEncrypter(false).GetCiphertextSize(
       QuicFramer::GetMinAckFrameSize()) +
       GetPacketHeaderSize(PACKET_8BYTE_GUID, include_version,
                           sequence_number_length, is_in_fec_group);
@@ -418,7 +439,7 @@
     *payload_length = 1 + ack_length - stream_length;
   }
 
-  return NullEncrypter(use_short_hash).GetCiphertextSize(*payload_length) +
+  return NullEncrypter(false).GetCiphertextSize(*payload_length) +
       QuicPacketCreator::StreamFramePacketOverhead(
           version, PACKET_8BYTE_GUID, include_version,
           sequence_number_length, is_in_fec_group);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 99bbd4d..3ad8e3d 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -25,6 +25,12 @@
 
 namespace test {
 
+// Upper limit on versions we support.
+QuicVersion QuicVersionMax();
+
+// Lower limit on versions we support.
+QuicVersion QuicVersionMin();
+
 void CompareCharArraysWithHexError(const std::string& description,
                                    const char* actual,
                                    const int actual_len,
@@ -147,6 +153,9 @@
   const std::vector<QuicStreamFrame>* stream_frames() const {
     return &stream_frames_;
   }
+  const std::vector<string*>& stream_data() const {
+    return stream_data_;
+  }
   QuicAckFrame* ack() { return ack_.get(); }
   QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); }
   QuicRstStreamFrame* rst() { return rst_.get(); }
@@ -160,6 +169,7 @@
   size_t frame_count_;
   QuicPacketHeader header_;
   std::vector<QuicStreamFrame> stream_frames_;
+  std::vector<std::string*> stream_data_;
   scoped_ptr<QuicAckFrame> ack_;
   scoped_ptr<QuicCongestionFeedbackFrame> feedback_;
   scoped_ptr<QuicRstStreamFrame> rst_;
@@ -178,7 +188,7 @@
   MOCK_METHOD1(OnStreamFrames, bool(const std::vector<QuicStreamFrame>& frame));
   MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame));
   MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame));
-  MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer));
+  MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
   MOCK_METHOD0(OnCanWrite, bool());
   MOCK_CONST_METHOD0(HasPendingHandshake, bool());
   MOCK_METHOD1(OnSuccessfulVersionNegotiation,
@@ -197,9 +207,6 @@
   const QuicClock* GetClock() const;
   QuicRandom* GetRandomGenerator();
   void AdvanceTime(QuicTime::Delta delta);
-  MOCK_METHOD1(WritePacketToWire,
-               WriteResult(const QuicEncryptedPacket& packet));
-  MOCK_METHOD0(IsWriteBlockedDataBuffered, bool());
   virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate);
 
  private:
@@ -214,6 +221,7 @@
   MockConnection(QuicGuid guid,
                  IPEndPoint address,
                  QuicConnectionHelperInterface* helper,
+                 QuicPacketWriter* writer,
                  bool is_server);
   virtual ~MockConnection();
 
@@ -247,6 +255,8 @@
 
  private:
   const bool has_mock_helper_;
+  scoped_ptr<QuicPacketWriter> writer_;
+  scoped_ptr<QuicConnectionHelperInterface> helper_;
 
   DISALLOW_COPY_AND_ASSIGN(MockConnection);
 };
@@ -263,6 +273,7 @@
       QuicPacketEntropyHash entropy_hash,
       TransmissionType transmission_type,
       HasRetransmittableData has_retransmittable_data,
+      IsHandshake handshake,
       Force forced) OVERRIDE;
 
   std::vector<QuicPacket*> packets_;
@@ -281,7 +292,7 @@
                               const IPEndPoint& peer_address,
                               const QuicPacketHeader& header,
                               const std::vector<QuicStreamFrame>& frame));
-  MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer));
+  MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
   MOCK_METHOD1(CreateIncomingReliableStream,
                ReliableQuicStream*(QuicStreamId id));
   MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
@@ -318,6 +329,20 @@
   DISALLOW_COPY_AND_ASSIGN(TestSession);
 };
 
+class MockPacketWriter : public QuicPacketWriter {
+ public:
+  MockPacketWriter();
+  virtual ~MockPacketWriter();
+
+  MOCK_METHOD5(WritePacket,
+               WriteResult(const char* buffer,
+                           size_t buf_len,
+                           const IPAddressNumber& self_address,
+                           const IPEndPoint& peer_address,
+                           QuicBlockedWriterInterface* blocked_writer));
+  MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
+};
+
 class MockSendAlgorithm : public SendAlgorithmInterface {
  public:
   MockSendAlgorithm();
@@ -341,6 +366,8 @@
   MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void));
   MOCK_METHOD0(SmoothedRtt, QuicTime::Delta(void));
   MOCK_METHOD0(RetransmissionDelay, QuicTime::Delta(void));
+  MOCK_METHOD0(GetCongestionWindow, QuicByteCount());
+  MOCK_METHOD1(SetCongestionWindow, void(QuicByteCount));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
diff --git a/net/quic/test_tools/quic_test_writer.cc b/net/quic/test_tools/quic_test_writer.cc
new file mode 100644
index 0000000..6755b2c
--- /dev/null
+++ b/net/quic/test_tools/quic_test_writer.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 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 "net/quic/test_tools/quic_test_writer.h"
+
+namespace net {
+namespace test {
+
+QuicTestWriter::QuicTestWriter() {}
+
+QuicTestWriter::~QuicTestWriter() {}
+
+QuicPacketWriter* QuicTestWriter::writer() {
+  return writer_.get();
+}
+
+void QuicTestWriter::set_writer(QuicPacketWriter* writer) {
+  writer_.reset(writer);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/test_tools/quic_test_writer.h b/net/quic/test_tools/quic_test_writer.h
new file mode 100644
index 0000000..ee33b7a
--- /dev/null
+++ b/net/quic/test_tools/quic_test_writer.h
@@ -0,0 +1,33 @@
+// Copyright 2013 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 NET_QUIC_TEST_TOOLS_QUIC_TEST_WRITER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_TEST_WRITER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_packet_writer.h"
+
+namespace net {
+namespace test {
+
+// Allows setting a writer for a QuicConnection, to allow
+// fine-grained control of writes.
+class QuicTestWriter : public QuicPacketWriter {
+ public:
+  QuicTestWriter();
+  virtual ~QuicTestWriter();
+  // Takes ownership of |writer|.
+  void set_writer(QuicPacketWriter* writer);
+
+ protected:
+  QuicPacketWriter* writer();
+
+ private:
+  scoped_ptr<QuicPacketWriter> writer_;
+};
+
+}  // namespace test
+}  // namespace net
+
+#endif  // NET_QUIC_TEST_TOOLS_QUIC_TEST_WRITER_H_
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 46be3a8..bb61a12 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -128,7 +128,7 @@
 };
 
 SimpleQuicFramer::SimpleQuicFramer()
-    : framer_(QuicVersionMax(), QuicTime::Zero(), true) {
+    : framer_(QuicSupportedVersions(), QuicTime::Zero(), true) {
 }
 
 SimpleQuicFramer::~SimpleQuicFramer() {
diff --git a/net/server/http_server_unittest.cc b/net/server/http_server_unittest.cc
index ede5066..0c3c97f 100644
--- a/net/server/http_server_unittest.cc
+++ b/net/server/http_server_unittest.cc
@@ -188,7 +188,7 @@
       {"HeaderWithColon", ": ", "1:1"},
       {"EmptyHeader", ":", ""},
       {"EmptyHeaderWithWhitespace", ":  \t  ", ""},
-      {"HeaderWithNonASCII", ":  ", "\u00f7"},
+      {"HeaderWithNonASCII", ":  ", "\xf7"},
   };
   std::string headers;
   for (size_t i = 0; i < arraysize(kHeaders); ++i) {
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index a86688e..9539145 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -60,10 +60,10 @@
     ClearSSLSessionCache();
   }
 
-  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE {
+  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE {
     // Per wtc, we actually only need to flush when trust is reduced.
-    // Always flush now because OnCertTrustChanged does not tell us this.
-    // See comments in ClientSocketPoolManager::OnCertTrustChanged.
+    // Always flush now because OnCACertChanged does not tell us this.
+    // See comments in ClientSocketPoolManager::OnCACertChanged.
     ClearSSLSessionCache();
   }
 
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 7c4136a..46de10e 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -39,28 +39,6 @@
 // after a certain timeout has passed without receiving an ACK.
 bool g_connect_backup_jobs_enabled = true;
 
-// Compares the effective priority of two results, and returns 1 if |request1|
-// has greater effective priority than |request2|, 0 if they have the same
-// effective priority, and -1 if |request2| has the greater effective priority.
-// Requests with |ignore_limits| set have higher effective priority than those
-// without.  If both requests have |ignore_limits| set/unset, then the request
-// with the highest Pririoty has the highest effective priority.  Does not take
-// into account the fact that Requests are serviced in FIFO order if they would
-// otherwise have the same priority.
-int CompareEffectiveRequestPriority(
-    const internal::ClientSocketPoolBaseHelper::Request& request1,
-    const internal::ClientSocketPoolBaseHelper::Request& request2) {
-  if (request1.ignore_limits() && !request2.ignore_limits())
-    return 1;
-  if (!request1.ignore_limits() && request2.ignore_limits())
-    return -1;
-  if (request1.priority() > request2.priority())
-    return 1;
-  if (request1.priority() < request2.priority())
-    return -1;
-  return 0;
-}
-
 }  // namespace
 
 ConnectJob::ConnectJob(const std::string& group_name,
@@ -430,9 +408,8 @@
     // If we don't have any sockets in this group, set a timer for potentially
     // creating a new one.  If the SYN is lost, this backup socket may complete
     // before the slow socket, improving end user latency.
-    if (connect_backup_jobs_enabled_ &&
-        group->IsEmpty() && !group->HasBackupJob()) {
-      group->StartBackupSocketTimer(group_name, this);
+    if (connect_backup_jobs_enabled_ && group->IsEmpty()) {
+      group->StartBackupJobTimer(group_name, this);
     }
 
     connecting_socket_count_++;
@@ -653,7 +630,8 @@
     group_dict->SetBoolean("is_stalled",
                            group->IsStalledOnPoolMaxSockets(
                                max_sockets_per_group_));
-    group_dict->SetBoolean("has_backup_job", group->HasBackupJob());
+    group_dict->SetBoolean("backup_job_timer_is_running",
+                           group->BackupJobTimerIsRunning());
 
     all_groups_dict->SetWithoutPathExpansion(it->first, group_dict);
   }
@@ -952,11 +930,6 @@
 
   DCHECK(group);
   group->RemoveJob(job);
-
-  // If we've got no more jobs for this group, then we no longer need a
-  // backup job either.
-  if (group->jobs().empty())
-    group->CleanupBackupJob();
 }
 
 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
@@ -1158,26 +1131,32 @@
 
 ClientSocketPoolBaseHelper::Group::Group()
     : unassigned_job_count_(0),
-      active_socket_count_(0),
-      weak_factory_(this) {}
+      // The number of priorities is doubled since requests with
+      // |ignore_limits| are prioritized over other requests.
+      pending_requests_(2 * NUM_PRIORITIES),
+      active_socket_count_(0) {}
 
 ClientSocketPoolBaseHelper::Group::~Group() {
-  CleanupBackupJob();
   DCHECK_EQ(0u, unassigned_job_count_);
 }
 
-void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
+void ClientSocketPoolBaseHelper::Group::StartBackupJobTimer(
     const std::string& group_name,
     ClientSocketPoolBaseHelper* pool) {
-  // Only allow one timer pending to create a backup socket.
-  if (weak_factory_.HasWeakPtrs())
+  // Only allow one timer to run at a time.
+  if (BackupJobTimerIsRunning())
     return;
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&Group::OnBackupSocketTimerFired, weak_factory_.GetWeakPtr(),
-                 group_name, pool),
-      pool->ConnectRetryInterval());
+  // Unretained here is okay because |backup_job_timer_| is
+  // automatically cancelled when it's destroyed.
+  backup_job_timer_.Start(
+      FROM_HERE, pool->ConnectRetryInterval(),
+      base::Bind(&Group::OnBackupJobTimerFired, base::Unretained(this),
+                 group_name, pool));
+}
+
+bool ClientSocketPoolBaseHelper::Group::BackupJobTimerIsRunning() const {
+  return backup_job_timer_.IsRunning();
 }
 
 bool ClientSocketPoolBaseHelper::Group::TryToUseUnassignedConnectJob() {
@@ -1211,9 +1190,14 @@
   size_t job_count = jobs_.size();
   if (job_count < unassigned_job_count_)
     unassigned_job_count_ = job_count;
+
+  // If we've got no more jobs for this group, then we no longer need a
+  // backup job either.
+  if (jobs_.empty())
+    backup_job_timer_.Stop();
 }
 
-void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
+void ClientSocketPoolBaseHelper::Group::OnBackupJobTimerFired(
     std::string group_name,
     ClientSocketPoolBaseHelper* pool) {
   // If there are no more jobs pending, there is no work to do.
@@ -1228,7 +1212,7 @@
   if (pool->ReachedMaxSocketsLimit() ||
       !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
       (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
-    StartBackupSocketTimer(group_name, pool);
+    StartBackupJobTimer(group_name, pool);
     return;
   }
 
@@ -1237,8 +1221,8 @@
 
   scoped_ptr<ConnectJob> backup_job =
       pool->connect_job_factory_->NewConnectJob(
-          group_name, **pending_requests_.begin(), pool);
-  backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED);
+          group_name, *pending_requests_.FirstMax().value(), pool);
+  backup_job->net_log().AddEvent(NetLog::TYPE_BACKUP_CONNECT_JOB_CREATED);
   SIMPLE_STATS_COUNTER("socket.backup_created");
   int rv = backup_job->Connect();
   pool->connecting_socket_count_++;
@@ -1259,13 +1243,14 @@
   STLDeleteElements(&jobs_);
   unassigned_job_count_ = 0;
 
-  // Cancel pending backup job.
-  weak_factory_.InvalidateWeakPtrs();
+  // Stop backup job timer.
+  backup_job_timer_.Stop();
 }
 
 const ClientSocketPoolBaseHelper::Request*
 ClientSocketPoolBaseHelper::Group::GetNextPendingRequest() const {
-  return pending_requests_.empty() ? NULL : *pending_requests_.begin();
+  return
+      pending_requests_.empty() ? NULL : pending_requests_.FirstMax().value();
 }
 
 bool ClientSocketPoolBaseHelper::Group::HasConnectJobForHandle(
@@ -1274,40 +1259,39 @@
   // If it's farther back in the deque than that, it doesn't have a
   // corresponding ConnectJob.
   size_t i = 0;
-  for (RequestQueue::const_iterator it = pending_requests_.begin();
-       it != pending_requests_.end() && i < jobs_.size(); ++it, ++i) {
-    if ((*it)->handle() == handle)
+  for (RequestQueue::Pointer pointer = pending_requests_.FirstMax();
+       !pointer.is_null() && i < jobs_.size();
+       pointer = pending_requests_.GetNextTowardsLastMin(pointer), ++i) {
+    if (pointer.value()->handle() == handle)
       return true;
   }
   return false;
 }
 
 void ClientSocketPoolBaseHelper::Group::InsertPendingRequest(
-    scoped_ptr<const Request> r) {
-  RequestQueue::iterator it = pending_requests_.begin();
-  // TODO(mmenke):  Should the network stack require requests with
-  //                |ignore_limits| have the highest priority?
-  while (it != pending_requests_.end() &&
-         CompareEffectiveRequestPriority(*r, *(*it)) <= 0) {
-    ++it;
-  }
-  pending_requests_.insert(it, r.release());
+    scoped_ptr<const Request> request) {
+  RequestQueue::Priority queue_priority = request->priority();
+  // Prioritize requests with |ignore_limits| over ones that don't.
+  if (request->ignore_limits())
+    queue_priority += NUM_PRIORITIES;
+  pending_requests_.Insert(request.release(), queue_priority);
 }
 
 scoped_ptr<const ClientSocketPoolBaseHelper::Request>
 ClientSocketPoolBaseHelper::Group::PopNextPendingRequest() {
   if (pending_requests_.empty())
     return scoped_ptr<const ClientSocketPoolBaseHelper::Request>();
-  return RemovePendingRequest(pending_requests_.begin());
+  return RemovePendingRequest(pending_requests_.FirstMax());
 }
 
 scoped_ptr<const ClientSocketPoolBaseHelper::Request>
 ClientSocketPoolBaseHelper::Group::FindAndRemovePendingRequest(
     ClientSocketHandle* handle) {
-  for (RequestQueue::iterator it = pending_requests_.begin();
-       it != pending_requests_.end(); ++it) {
-    if ((*it)->handle() == handle) {
-      scoped_ptr<const Request> request = RemovePendingRequest(it);
+  for (RequestQueue::Pointer pointer = pending_requests_.FirstMax();
+       !pointer.is_null();
+       pointer = pending_requests_.GetNextTowardsLastMin(pointer)) {
+    if (pointer.value()->handle() == handle) {
+      scoped_ptr<const Request> request = RemovePendingRequest(pointer);
       return request.Pass();
     }
   }
@@ -1316,12 +1300,12 @@
 
 scoped_ptr<const ClientSocketPoolBaseHelper::Request>
 ClientSocketPoolBaseHelper::Group::RemovePendingRequest(
-    const RequestQueue::iterator& it) {
-  scoped_ptr<const Request> request(*it);
-  pending_requests_.erase(it);
+    const RequestQueue::Pointer& pointer) {
+  scoped_ptr<const Request> request(pointer.value());
+  pending_requests_.Erase(pointer);
   // If there are no more requests, kill the backup timer.
   if (pending_requests_.empty())
-    CleanupBackupJob();
+    backup_job_timer_.Stop();
   return request.Pass();
 }
 
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index 31ec9bf..2c2ddb5 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -22,6 +22,7 @@
 #ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
 #define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
 
+#include <cstddef>
 #include <deque>
 #include <list>
 #include <map>
@@ -43,6 +44,7 @@
 #include "net/base/net_export.h"
 #include "net/base/net_log.h"
 #include "net/base/network_change_notifier.h"
+#include "net/base/priority_queue.h"
 #include "net/base/request_priority.h"
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/stream_socket.h"
@@ -182,12 +184,12 @@
 
    private:
     ClientSocketHandle* const handle_;
-    CompletionCallback callback_;
+    const CompletionCallback callback_;
     // TODO(akalin): Support reprioritization.
     const RequestPriority priority_;
-    bool ignore_limits_;
+    const bool ignore_limits_;
     const Flags flags_;
-    BoundNetLog net_log_;
+    const BoundNetLog net_log_;
 
     DISALLOW_COPY_AND_ASSIGN(Request);
   };
@@ -350,7 +352,7 @@
     base::TimeTicks start_time;
   };
 
-  typedef std::deque<const Request* > RequestQueue;
+  typedef PriorityQueue<const Request*> RequestQueue;
   typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
 
   // A Group is allocated per group_name when there are idle sockets or pending
@@ -380,19 +382,22 @@
           pending_requests_.size() > jobs_.size();
     }
 
+    // Returns the priority of the top of the pending request queue
+    // (which may be less than the maximum priority over the entire
+    // queue, due to how we prioritize requests with |ignore_limits|
+    // set over others).
     RequestPriority TopPendingPriority() const {
-      return pending_requests_.front()->priority();
+      // NOTE: FirstMax().value()->priority() is not the same as
+      // FirstMax().priority()!
+      return pending_requests_.FirstMax().value()->priority();
     }
 
-    bool HasBackupJob() const { return weak_factory_.HasWeakPtrs(); }
+    // Set a timer to create a backup job if it takes too long to
+    // create one and if a timer isn't already running.
+    void StartBackupJobTimer(const std::string& group_name,
+                             ClientSocketPoolBaseHelper* pool);
 
-    void CleanupBackupJob() {
-      weak_factory_.InvalidateWeakPtrs();
-    }
-
-    // Set a timer to create a backup socket if it takes too long to create one.
-    void StartBackupSocketTimer(const std::string& group_name,
-                                ClientSocketPoolBaseHelper* pool);
+    bool BackupJobTimerIsRunning() const;
 
     // If there's a ConnectJob that's never been assigned to Request,
     // decrements |unassigned_job_count_| and returns true.
@@ -422,7 +427,7 @@
     // Inserts the request into the queue based on priority
     // order. Older requests are prioritized over requests of equal
     // priority.
-    void InsertPendingRequest(scoped_ptr<const Request> r);
+    void InsertPendingRequest(scoped_ptr<const Request> request);
 
     // Gets and removes the next pending request. Returns NULL if
     // there are no pending requests.
@@ -446,10 +451,10 @@
     // Returns the iterator's pending request after removing it from
     // the queue.
     scoped_ptr<const Request> RemovePendingRequest(
-        const RequestQueue::iterator& it);
+        const RequestQueue::Pointer& pointer);
 
     // Called when the backup socket timer fires.
-    void OnBackupSocketTimerFired(
+    void OnBackupJobTimerFired(
         std::string group_name,
         ClientSocketPoolBaseHelper* pool);
 
@@ -469,8 +474,8 @@
     std::set<ConnectJob*> jobs_;
     RequestQueue pending_requests_;
     int active_socket_count_;  // number of active sockets used by clients
-    // A factory to pin the backup_job tasks.
-    base::WeakPtrFactory<Group> weak_factory_;
+    // A timer for when to start the backup job.
+    base::OneShotTimer<Group> backup_job_timer_;
   };
 
   typedef std::map<std::string, Group*> GroupMap;
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index b557874..35e7564 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -374,7 +374,7 @@
   FlushSocketPoolsWithError(ERR_NETWORK_CHANGED);
 }
 
-void ClientSocketPoolManagerImpl::OnCertTrustChanged(
+void ClientSocketPoolManagerImpl::OnCACertChanged(
     const X509Certificate* cert) {
   // We should flush the socket pools if we removed trust from a
   // cert, because a previously trusted server may have become
@@ -383,8 +383,8 @@
   // We should not flush the socket pools if we added trust to a
   // cert.
   //
-  // Since the OnCertTrustChanged method doesn't tell us what
-  // kind of trust change it is, we have to flush the socket
+  // Since the OnCACertChanged method doesn't tell us what
+  // kind of change it is, we have to flush the socket
   // pools to be safe.
   FlushSocketPoolsWithError(ERR_NETWORK_CHANGED);
 }
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h
index 8f6e618..7f92cb5 100644
--- a/net/socket/client_socket_pool_manager_impl.h
+++ b/net/socket/client_socket_pool_manager_impl.h
@@ -90,7 +90,7 @@
 
   // CertDatabase::Observer methods:
   virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE;
-  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE;
+  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE;
 
  private:
   typedef internal::OwnedPoolMap<HostPortPair, TransportClientSocketPool*>
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index b4fc306..a849488 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -4,7 +4,11 @@
 
 #include "net/socket/ssl_client_socket.h"
 
+#include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
+#include "crypto/ec_private_key.h"
+#include "net/ssl/server_bound_cert_service.h"
+#include "net/ssl/ssl_config_service.h"
 
 namespace net {
 
@@ -140,4 +144,58 @@
   channel_id_sent_ = channel_id_sent;
 }
 
+// static
+void SSLClientSocket::RecordChannelIDSupport(
+    ServerBoundCertService* server_bound_cert_service,
+    bool negotiated_channel_id,
+    bool channel_id_enabled,
+    bool supports_ecc) {
+  // Since this enum is used for a histogram, do not change or re-use values.
+  enum {
+    DISABLED = 0,
+    CLIENT_ONLY = 1,
+    CLIENT_AND_SERVER = 2,
+    CLIENT_NO_ECC = 3,
+    CLIENT_BAD_SYSTEM_TIME = 4,
+    CLIENT_NO_SERVER_BOUND_CERT_SERVICE = 5,
+    DOMAIN_BOUND_CERT_USAGE_MAX
+  } supported = DISABLED;
+  if (negotiated_channel_id) {
+    supported = CLIENT_AND_SERVER;
+  } else if (channel_id_enabled) {
+    if (!server_bound_cert_service)
+      supported = CLIENT_NO_SERVER_BOUND_CERT_SERVICE;
+    else if (!supports_ecc)
+      supported = CLIENT_NO_ECC;
+    else if (!server_bound_cert_service->IsSystemTimeValid())
+      supported = CLIENT_BAD_SYSTEM_TIME;
+    else
+      supported = CLIENT_ONLY;
+  }
+  UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
+                            DOMAIN_BOUND_CERT_USAGE_MAX);
+}
+
+// static
+bool SSLClientSocket::IsChannelIDEnabled(
+    const SSLConfig& ssl_config,
+    ServerBoundCertService* server_bound_cert_service) {
+  if (!ssl_config.channel_id_enabled)
+    return false;
+  if (!server_bound_cert_service) {
+    DVLOG(1) << "NULL server_bound_cert_service_, not enabling channel ID.";
+    return false;
+  }
+  if (!crypto::ECPrivateKey::IsSupported()) {
+    DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
+    return false;
+  }
+  if (!server_bound_cert_service->IsSystemTimeValid()) {
+    DVLOG(1) << "System time is not within the supported range for certificate "
+                "generation, not enabling channel ID.";
+    return false;
+  }
+  return true;
+}
+
 }  // namespace net
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 41ee087..9f8532a 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -18,6 +18,7 @@
 class CertVerifier;
 class ServerBoundCertService;
 class SSLCertRequestInfo;
+struct SSLConfig;
 class SSLInfo;
 class TransportSecurityState;
 
@@ -121,10 +122,26 @@
   // This may be useful for protocols, like SPDY, which allow the same
   // connection to be shared between multiple domains, each of which need
   // a channel ID.
+  //
+  // Public for ssl_client_socket_openssl_unittest.cc.
   virtual bool WasChannelIDSent() const;
 
+ protected:
   virtual void set_channel_id_sent(bool channel_id_sent);
 
+  // Records histograms for channel id support during full handshakes - resumed
+  // handshakes are ignored.
+  static void RecordChannelIDSupport(
+      ServerBoundCertService* server_bound_cert_service,
+      bool negotiated_channel_id,
+      bool channel_id_enabled,
+      bool supports_ecc);
+
+  // Returns whether TLS channel ID is enabled.
+  static bool IsChannelIDEnabled(
+      const SSLConfig& ssl_config,
+      ServerBoundCertService* server_bound_cert_service);
+
  private:
   // True if NPN was responded to, independent of selecting SPDY or HTTP.
   bool was_npn_negotiated_;
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index bfd0d0e..343bd20 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -757,7 +757,7 @@
   void UpdateConnectionStatus();
   // Record histograms for channel id support during full handshakes - resumed
   // handshakes are ignored.
-  void RecordChannelIDSupport();
+  void RecordChannelIDSupportOnNSSTaskRunner();
   // UpdateNextProto gets any application-layer protocol that may have been
   // negotiated by the TLS connection.
   void UpdateNextProto();
@@ -1009,19 +1009,12 @@
     return false;
   }
 
-  if (ssl_config_.channel_id_enabled) {
-    if (!server_bound_cert_service_) {
-      DVLOG(1) << "NULL server_bound_cert_service_, not enabling channel ID.";
-    } else if (!crypto::ECPrivateKey::IsSupported()) {
-      DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
-    } else if (!server_bound_cert_service_->IsSystemTimeValid()) {
-      DVLOG(1) << "System time is weird, not enabling channel ID.";
-    } else {
-      rv = SSL_SetClientChannelIDCallback(
-          nss_fd_, SSLClientSocketNSS::Core::ClientChannelIDHandler, this);
-      if (rv != SECSuccess)
-        LogFailedNSSFunction(*weak_net_log_, "SSL_SetClientChannelIDCallback",
-                             "");
+  if (IsChannelIDEnabled(ssl_config_, server_bound_cert_service_)) {
+    rv = SSL_SetClientChannelIDCallback(
+        nss_fd_, SSLClientSocketNSS::Core::ClientChannelIDHandler, this);
+    if (rv != SECSuccess) {
+      LogFailedNSSFunction(
+          *weak_net_log_, "SSL_SetClientChannelIDCallback", "");
     }
   }
 
@@ -1633,7 +1626,7 @@
     nss_state->resumed_handshake = false;
   }
 
-  core->RecordChannelIDSupport();
+  core->RecordChannelIDSupportOnNSSTaskRunner();
   core->UpdateServerCert();
   core->UpdateConnectionStatus();
   core->UpdateNextProto();
@@ -2506,7 +2499,7 @@
   }
 }
 
-void SSLClientSocketNSS::Core::RecordChannelIDSupport() {
+void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNSSTaskRunner() {
   DCHECK(OnNSSTaskRunner());
   if (nss_handshake_state_.resumed_handshake)
     return;
@@ -2529,30 +2522,10 @@
     bool supports_ecc) const {
   DCHECK(OnNetworkTaskRunner());
 
-  // Since this enum is used for a histogram, do not change or re-use values.
-  enum {
-    DISABLED = 0,
-    CLIENT_ONLY = 1,
-    CLIENT_AND_SERVER = 2,
-    CLIENT_NO_ECC = 3,
-    CLIENT_BAD_SYSTEM_TIME = 4,
-    CLIENT_NO_SERVER_BOUND_CERT_SERVICE = 5,
-    DOMAIN_BOUND_CERT_USAGE_MAX
-  } supported = DISABLED;
-  if (negotiated_channel_id) {
-    supported = CLIENT_AND_SERVER;
-  } else if (channel_id_enabled) {
-    if (!server_bound_cert_service_)
-      supported = CLIENT_NO_SERVER_BOUND_CERT_SERVICE;
-    else if (!supports_ecc)
-      supported = CLIENT_NO_ECC;
-    else if (!server_bound_cert_service_->IsSystemTimeValid())
-      supported = CLIENT_BAD_SYSTEM_TIME;
-    else
-      supported = CLIENT_ONLY;
-  }
-  UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
-                            DOMAIN_BOUND_CERT_USAGE_MAX);
+  RecordChannelIDSupport(server_bound_cert_service_,
+                         negotiated_channel_id,
+                         channel_id_enabled,
+                         supports_ecc);
 }
 
 int SSLClientSocketNSS::Core::DoBufferRecv(IOBuffer* read_buffer, int len) {
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 416ab87..45796fc 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -16,6 +16,7 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram.h"
 #include "base/synchronization/lock.h"
+#include "crypto/ec_private_key.h"
 #include "crypto/openssl_util.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_verifier.h"
@@ -348,6 +349,7 @@
     SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds);
     SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires);
     SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback);
+    SSL_CTX_set_channel_id_cb(ssl_ctx_.get(), ChannelIDCallback);
 #if defined(OPENSSL_NPN_NEGOTIATED)
     // TODO(kristianm): Only select this if ssl_config_.next_proto is not empty.
     // It would be better if the callback were not a global setting,
@@ -384,6 +386,12 @@
     return socket->ClientCertRequestCallback(ssl, x509, pkey);
   }
 
+  static void ChannelIDCallback(SSL* ssl, EVP_PKEY** pkey) {
+    SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
+    CHECK(socket);
+    socket->ChannelIDRequestCallback(ssl, pkey);
+  }
+
   static int SelectNextProtoCallback(SSL* ssl,
                                      unsigned char** out, unsigned char* outlen,
                                      const unsigned char* in,
@@ -437,6 +445,7 @@
       completed_handshake_(false),
       client_auth_cert_needed_(false),
       cert_verifier_(context.cert_verifier),
+      server_bound_cert_service_(context.server_bound_cert_service),
       ssl_(NULL),
       transport_bio_(NULL),
       transport_(transport_socket.Pass()),
@@ -446,6 +455,8 @@
       trying_cached_session_(false),
       next_handshake_state_(STATE_NONE),
       npn_status_(kNextProtoUnsupported),
+      channel_id_request_return_value_(ERR_UNEXPECTED),
+      channel_id_xtn_negotiated_(false),
       net_log_(transport_->socket()->NetLog()) {
 }
 
@@ -566,6 +577,12 @@
   // 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;
+
+  // TLS channel ids.
+  if (IsChannelIDEnabled(ssl_config_, server_bound_cert_service_)) {
+    SSL_enable_tls_channel_id(ssl_);
+  }
+
   return true;
 }
 
@@ -618,6 +635,44 @@
   return 0;
 }
 
+void SSLClientSocketOpenSSL::ChannelIDRequestCallback(SSL* ssl,
+                                                      EVP_PKEY** pkey) {
+  DVLOG(3) << "OpenSSL ChannelIDRequestCallback called";
+  DCHECK_EQ(ssl, ssl_);
+  DCHECK(!*pkey);
+
+  channel_id_xtn_negotiated_ = true;
+  if (!channel_id_private_key_.size()) {
+    channel_id_request_return_value_ =
+        server_bound_cert_service_->GetOrCreateDomainBoundCert(
+            host_and_port_.host(),
+            &channel_id_private_key_,
+            &channel_id_cert_,
+            base::Bind(&SSLClientSocketOpenSSL::OnHandshakeIOComplete,
+                       base::Unretained(this)),
+            &channel_id_request_handle_);
+    if (channel_id_request_return_value_ != OK)
+      return;
+  }
+
+  // Decode key.
+  std::vector<uint8> encrypted_private_key_info;
+  std::vector<uint8> subject_public_key_info;
+  encrypted_private_key_info.assign(
+      channel_id_private_key_.data(),
+      channel_id_private_key_.data() + channel_id_private_key_.size());
+  subject_public_key_info.assign(
+      channel_id_cert_.data(),
+      channel_id_cert_.data() + channel_id_cert_.size());
+  scoped_ptr<crypto::ECPrivateKey> ec_private_key(
+      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
+          ServerBoundCertService::kEPKIPassword,
+          encrypted_private_key_info,
+          subject_public_key_info));
+  set_channel_id_sent(true);
+  *pkey = EVP_PKEY_dup(ec_private_key->key());
+}
+
 // SSLClientSocket methods
 
 bool SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
@@ -635,6 +690,11 @@
       ssl_config_.send_client_cert && ssl_config_.client_cert.get();
   ssl_info->channel_id_sent = WasChannelIDSent();
 
+  RecordChannelIDSupport(server_bound_cert_service_,
+                         channel_id_xtn_negotiated_,
+                         ssl_config_.channel_id_enabled,
+                         crypto::ECPrivateKey::IsSupported());
+
   const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_);
   CHECK(cipher);
   ssl_info->security_bits = SSL_CIPHER_get_bits(cipher, NULL);
@@ -706,7 +766,7 @@
 
 ServerBoundCertService*
 SSLClientSocketOpenSSL::GetServerBoundCertService() const {
-  return NULL;
+  return server_bound_cert_service_;
 }
 
 void SSLClientSocketOpenSSL::DoReadCallback(int rv) {
@@ -863,7 +923,14 @@
     GotoState(STATE_VERIFY_CERT);
   } else {
     int ssl_error = SSL_get_error(ssl_, rv);
-    net_error = MapOpenSSLError(ssl_error, err_tracer);
+
+    if (ssl_error == SSL_ERROR_WANT_CHANNEL_ID_LOOKUP) {
+      // The server supports TLS channel id and the lookup is asynchronous.
+      // Retrieve the error from the call to |server_bound_cert_service_|.
+      net_error = channel_id_request_return_value_;
+    } else {
+      net_error = MapOpenSSLError(ssl_error, err_tracer);
+    }
 
     // If not done, stay in this state
     if (net_error == ERR_IO_PENDING) {
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index f66d95c..03e51e1 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -15,6 +15,7 @@
 #include "net/cert/cert_verify_result.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
+#include "net/ssl/server_bound_cert_service.h"
 #include "net/ssl/ssl_config_service.h"
 
 // Avoid including misc OpenSSL headers, i.e.:
@@ -56,6 +57,10 @@
   // a certificate for this client.
   int ClientCertRequestCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey);
 
+  // Callback from the SSL layer that indicates the remote server supports TLS
+  // Channel IDs.
+  void ChannelIDRequestCallback(SSL* ssl, EVP_PKEY** pkey);
+
   // Callback from the SSL layer to check which NPN protocol we are supporting
   int SelectNextProtoCallback(unsigned char** out, unsigned char* outlen,
                               const unsigned char* in, unsigned int inlen);
@@ -170,6 +175,9 @@
   CertVerifier* const cert_verifier_;
   scoped_ptr<SingleRequestCertVerifier> verifier_;
 
+  // The service for retrieving Channel ID keys.  May be NULL.
+  ServerBoundCertService* server_bound_cert_service_;
+
   // OpenSSL stuff
   SSL* ssl_;
   BIO* transport_bio_;
@@ -195,6 +203,15 @@
   NextProtoStatus npn_status_;
   std::string npn_proto_;
   std::string server_protos_;
+  // Written by the |server_bound_cert_service_|.
+  std::string channel_id_private_key_;
+  std::string channel_id_cert_;
+  // The return value of the last call to |server_bound_cert_service_|.
+  int channel_id_request_return_value_;
+  // True if channel ID extension was negotiated.
+  bool channel_id_xtn_negotiated_;
+  // The request handle for |server_bound_cert_service_|.
+  ServerBoundCertService::RequestHandle channel_id_request_handle_;
   BoundNetLog net_log_;
 };
 
diff --git a/net/socket/ssl_client_socket_openssl_unittest.cc b/net/socket/ssl_client_socket_openssl_unittest.cc
index 24c0605..48a4813 100644
--- a/net/socket/ssl_client_socket_openssl_unittest.cc
+++ b/net/socket/ssl_client_socket_openssl_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_handle.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/values.h"
 #include "crypto/openssl_util.h"
 #include "net/base/address_list.h"
@@ -34,7 +35,9 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/tcp_client_socket.h"
+#include "net/ssl/default_server_bound_cert_store.h"
 #include "net/ssl/openssl_client_key_store.h"
+#include "net/ssl/server_bound_cert_service.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/test/cert_test_util.h"
@@ -59,6 +62,35 @@
 
 const SSLConfig kDefaultSSLConfig;
 
+// A ServerBoundCertStore that always returns an error when asked for a
+// certificate.
+class FailingServerBoundCertStore : public ServerBoundCertStore {
+  virtual int GetServerBoundCert(const std::string& server_identifier,
+                                 base::Time* expiration_time,
+                                 std::string* private_key_result,
+                                 std::string* cert_result,
+                                 const GetCertCallback& callback) OVERRIDE {
+    return ERR_UNEXPECTED;
+  }
+  virtual void SetServerBoundCert(const std::string& server_identifier,
+                                  base::Time creation_time,
+                                  base::Time expiration_time,
+                                  const std::string& private_key,
+                                  const std::string& cert) OVERRIDE {}
+  virtual void DeleteServerBoundCert(const std::string& server_identifier,
+                                     const base::Closure& completion_callback)
+      OVERRIDE {}
+  virtual void DeleteAllCreatedBetween(base::Time delete_begin,
+                                       base::Time delete_end,
+                                       const base::Closure& completion_callback)
+      OVERRIDE {}
+  virtual void DeleteAll(const base::Closure& completion_callback) OVERRIDE {}
+  virtual void GetAllServerBoundCerts(const GetCertListCallback& callback)
+      OVERRIDE {}
+  virtual int GetCertCount() OVERRIDE { return 0; }
+  virtual void SetForceKeepSessionState() OVERRIDE {}
+};
+
 // Loads a PEM-encoded private key file into a scoped EVP_PKEY object.
 // |filepath| is the private key file path.
 // |*pkey| is reset to the new EVP_PKEY on success, untouched otherwise.
@@ -107,6 +139,20 @@
   }
 
  protected:
+  void EnabledChannelID() {
+    cert_service_.reset(
+        new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
+                                   base::MessageLoopProxy::current()));
+    context_.server_bound_cert_service = cert_service_.get();
+  }
+
+  void EnabledFailingChannelID() {
+    cert_service_.reset(
+        new ServerBoundCertService(new FailingServerBoundCertStore(),
+                                   base::MessageLoopProxy::current()));
+    context_.server_bound_cert_service = cert_service_.get();
+  }
+
   scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
       scoped_ptr<StreamSocket> transport_socket,
       const HostPortPair& host_and_port,
@@ -188,6 +234,7 @@
     return ssl_info.client_cert_sent;
   }
 
+  scoped_ptr<ServerBoundCertService> cert_service_;
   ClientSocketFactory* socket_factory_;
   scoped_ptr<MockCertVerifier> cert_verifier_;
   scoped_ptr<TransportSecurityState> transport_security_state_;
@@ -275,5 +322,44 @@
   EXPECT_FALSE(sock_->IsConnected());
 }
 
+// Connect to a server using channel id. It should allow the connection.
+TEST_F(SSLClientSocketOpenSSLClientAuthTest, SendChannelID) {
+  SpawnedTestServer::SSLOptions ssl_options;
+
+  ASSERT_TRUE(ConnectToTestServer(ssl_options));
+
+  EnabledChannelID();
+  SSLConfig ssl_config = kDefaultSSLConfig;
+  ssl_config.channel_id_enabled = true;
+
+  int rv;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+
+  EXPECT_EQ(OK, rv);
+  EXPECT_TRUE(sock_->IsConnected());
+  EXPECT_TRUE(sock_->WasChannelIDSent());
+
+  sock_->Disconnect();
+  EXPECT_FALSE(sock_->IsConnected());
+}
+
+// Connect to a server using channel id but without sending a key. It should
+// fail.
+TEST_F(SSLClientSocketOpenSSLClientAuthTest, FailingChannelID) {
+  SpawnedTestServer::SSLOptions ssl_options;
+
+  ASSERT_TRUE(ConnectToTestServer(ssl_options));
+
+  EnabledFailingChannelID();
+  SSLConfig ssl_config = kDefaultSSLConfig;
+  ssl_config.channel_id_enabled = true;
+
+  int rv;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+
+  EXPECT_EQ(ERR_UNEXPECTED, rv);
+  EXPECT_FALSE(sock_->IsConnected());
+}
+
 }  // namespace
 }  // namespace net
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc
index 6d996d2..049c3da 100644
--- a/net/spdy/buffered_spdy_framer.cc
+++ b/net/spdy/buffered_spdy_framer.cc
@@ -302,11 +302,6 @@
   return spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size);
 }
 
-SpdyFrame* BufferedSpdyFramer::CreateCredentialFrame(
-    const SpdyCredential& credential) const {
-  return spdy_framer_.CreateCredentialFrame(credential);
-}
-
 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
                                                const char* data,
                                                uint32 len,
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h
index 1786067..85ad537 100644
--- a/net/spdy/buffered_spdy_framer.h
+++ b/net/spdy/buffered_spdy_framer.h
@@ -185,8 +185,6 @@
   SpdyFrame* CreateWindowUpdate(
       SpdyStreamId stream_id,
       uint32 delta_window_size) const;
-  SpdyFrame* CreateCredentialFrame(
-      const SpdyCredential& credential) const;
   SpdyFrame* CreateDataFrame(SpdyStreamId stream_id,
                              const char* data,
                              uint32 len,
diff --git a/net/spdy/spdy_credential_builder.cc b/net/spdy/spdy_credential_builder.cc
deleted file mode 100644
index 79567b6..0000000
--- a/net/spdy/spdy_credential_builder.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2012 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 "net/spdy/spdy_credential_builder.h"
-
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-#include "crypto/ec_private_key.h"
-#include "crypto/ec_signature_creator.h"
-#include "net/base/net_errors.h"
-#include "net/cert/asn1_util.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/ssl/server_bound_cert_service.h"
-
-namespace net {
-
-namespace {
-
-std::vector<uint8> ToVector(base::StringPiece piece) {
-  return std::vector<uint8>(piece.data(), piece.data() + piece.length());
-}
-
-}  // namespace
-
-// static
-int SpdyCredentialBuilder::Build(const std::string& tls_unique,
-                                 const std::string& key,
-                                 const std::string& cert,
-                                 size_t slot,
-                                 SpdyCredential* credential) {
-  std::string secret = SpdyCredentialBuilder::GetCredentialSecret(tls_unique);
-
-  // Extract the SubjectPublicKeyInfo from the certificate.
-  base::StringPiece public_key_info;
-  if(!asn1::ExtractSPKIFromDERCert(cert, &public_key_info))
-    return ERR_BAD_SSL_CLIENT_AUTH_CERT;
-
-  // Next, extract the SubjectPublicKey data, which will actually
-  // be stored in the cert field of the credential frame.
-  base::StringPiece public_key;
-  if (!asn1::ExtractSubjectPublicKeyFromSPKI(public_key_info, &public_key))
-    return ERR_BAD_SSL_CLIENT_AUTH_CERT;
-  // Drop one byte of padding bits count from the BIT STRING
-  // (this will always be zero).  Drop one byte of X9.62 format specification
-  // (this will always be 4 to indicated an uncompressed point).
-  DCHECK_GT(public_key.length(), 2u);
-  DCHECK_EQ(0, static_cast<int>(public_key[0]));
-  DCHECK_EQ(4, static_cast<int>(public_key[1]));
-  public_key = public_key.substr(2, public_key.length());
-
-  // Convert the strings into a vector<unit8>
-  std::vector<uint8> der_signature;
-  scoped_ptr<crypto::ECPrivateKey> private_key(
-      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          ServerBoundCertService::kEPKIPassword,
-          ToVector(key), ToVector(public_key_info)));
-  scoped_ptr<crypto::ECSignatureCreator> creator(
-      crypto::ECSignatureCreator::Create(private_key.get()));
-  creator->Sign(reinterpret_cast<const unsigned char *>(secret.data()),
-                secret.length(), &der_signature);
-
-  std::vector<uint8> proof_vector;
-  if (!creator->DecodeSignature(der_signature, &proof_vector)) {
-    NOTREACHED();
-    return ERR_UNEXPECTED;
-  }
-
-  credential->slot = slot;
-  credential->certs.push_back(public_key.as_string());
-  credential->proof.assign(proof_vector.begin(), proof_vector.end());
-  return OK;
-}
-
-// static
-std::string SpdyCredentialBuilder::GetCredentialSecret(
-    const std::string& tls_unique) {
-  const char prefix[] = "SPDY CREDENTIAL ChannelID\0client -> server";
-  std::string secret(prefix, arraysize(prefix));
-  secret.append(tls_unique);
-
-  return secret;
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_credential_builder.h b/net/spdy/spdy_credential_builder.h
deleted file mode 100644
index 3bdc0a1..0000000
--- a/net/spdy/spdy_credential_builder.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 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 NET_SPDY_SPDY_CREDENTIAL_BUILDER_H_
-#define NET_SPDY_SPDY_CREDENTIAL_BUILDER_H_
-
-#include <string>
-
-#include "net/base/net_export.h"
-
-namespace net {
-
-class SSLClientSocket;
-struct SpdyCredential;
-
-// This class provides facilities for building the various fields of
-// SPDY CREDENTIAL frames.
-class NET_EXPORT_PRIVATE SpdyCredentialBuilder {
- public:
-  static int Build(const std::string& tls_unique,
-                   const std::string& key,
-                   const std::string& cert,
-                   size_t slot,
-                   SpdyCredential* credential);
-
- private:
-  friend class SpdyCredentialBuilderTest;
-
-  // Returns the secret data to be signed as part of a credential frame.
-  static std::string GetCredentialSecret(const std::string& tls_unique);
-};
-
-}  // namespace net
-
-#endif  // NET_SPDY_SPDY_CREDENTIAL_BUILDER_H_
diff --git a/net/spdy/spdy_credential_builder_unittest.cc b/net/spdy/spdy_credential_builder_unittest.cc
deleted file mode 100644
index 84aff7a..0000000
--- a/net/spdy/spdy_credential_builder_unittest.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2012 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 "net/spdy/spdy_credential_builder.h"
-
-#include "base/message_loop/message_loop_proxy.h"
-#include "crypto/ec_private_key.h"
-#include "crypto/ec_signature_creator.h"
-#include "net/cert/asn1_util.h"
-#include "net/spdy/spdy_test_util_common.h"
-#include "net/ssl/default_server_bound_cert_store.h"
-#include "net/ssl/server_bound_cert_service.h"
-#include "testing/platform_test.h"
-
-namespace net {
-
-namespace {
-
-const static size_t kSlot = 2;
-const static char kSecretPrefix[] =
-    "SPDY CREDENTIAL ChannelID\0client -> server";
-
-void CreateCertAndKey(std::string* cert, std::string* key) {
-  // TODO(rch): Share this code with ServerBoundCertServiceTest.
-  scoped_ptr<ServerBoundCertService> server_bound_cert_service(
-      new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 base::MessageLoopProxy::current()));
-
-  TestCompletionCallback callback;
-  ServerBoundCertService::RequestHandle request_handle;
-  int rv = server_bound_cert_service->GetOrCreateDomainBoundCert(
-      "www.google.com", key, cert, callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-  EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-}  // namespace
-
-class SpdyCredentialBuilderTest : public testing::Test {
- public:
-  SpdyCredentialBuilderTest() {
-    CreateCertAndKey(&cert_, &key_);
-  }
-
- protected:
-  int Build() {
-    return SpdyCredentialBuilder::Build(
-        MockClientSocket::kTlsUnique, key_, cert_, kSlot, &credential_);
-  }
-
-  std::string GetCredentialSecret() {
-    return SpdyCredentialBuilder::GetCredentialSecret(
-        MockClientSocket::kTlsUnique);
-  }
-
-  std::string cert_;
-  std::string key_;
-  SpdyCredential credential_;
-  MockECSignatureCreatorFactory ec_signature_creator_factory_;
-};
-
-// http://crbug.com/142833, http://crbug.com/140991. The following tests fail
-// with OpenSSL due to the unimplemented ec_private_key_openssl.cc.
-#if defined(USE_OPENSSL)
-#define MAYBE_GetCredentialSecret DISABLED_GetCredentialSecret
-#else
-#define MAYBE_GetCredentialSecret GetCredentialSecret
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_GetCredentialSecret) {
-  std::string secret_str(kSecretPrefix, arraysize(kSecretPrefix));
-  secret_str.append(MockClientSocket::kTlsUnique);
-
-  EXPECT_EQ(secret_str, GetCredentialSecret());
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_Succeeds DISABLED_Succeeds
-#else
-#define MAYBE_Succeeds Succeeds
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_Succeeds) {
-  EXPECT_EQ(OK, Build());
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_SetsSlotCorrectly DISABLED_SetsSlotCorrectly
-#else
-#define MAYBE_SetsSlotCorrectly SetsSlotCorrectly
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_SetsSlotCorrectly) {
-  ASSERT_EQ(OK, Build());
-  EXPECT_EQ(kSlot, credential_.slot);
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_SetsCertCorrectly DISABLED_SetsCertCorrectly
-#else
-#define MAYBE_SetsCertCorrectly SetsCertCorrectly
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_SetsCertCorrectly) {
-  ASSERT_EQ(OK, Build());
-  base::StringPiece spki;
-  ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(cert_, &spki));
-  base::StringPiece spk;
-  ASSERT_TRUE(asn1::ExtractSubjectPublicKeyFromSPKI(spki, &spk));
-  EXPECT_EQ(1u, credential_.certs.size());
-  EXPECT_EQ(0, (int)spk[0]);
-  EXPECT_EQ(4, (int)spk[1]);
-  EXPECT_EQ(spk.substr(2, spk.length()).as_string(), credential_.certs[0]);
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_SetsProofCorrectly DISABLED_SetsProofCorrectly
-#else
-#define MAYBE_SetsProofCorrectly SetsProofCorrectly
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_SetsProofCorrectly) {
-  ASSERT_EQ(OK, Build());
-  base::StringPiece spki;
-  ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(cert_, &spki));
-  std::vector<uint8> spki_data(spki.data(),
-                               spki.data() + spki.size());
-  std::vector<uint8> key_data(key_.data(),
-                              key_.data() + key_.length());
-  std::vector<uint8> proof_data;
-  scoped_ptr<crypto::ECPrivateKey> private_key(
-      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          ServerBoundCertService::kEPKIPassword, key_data, spki_data));
-  scoped_ptr<crypto::ECSignatureCreator> creator(
-      crypto::ECSignatureCreator::Create(private_key.get()));
-  std::string secret = GetCredentialSecret();
-  creator->Sign(reinterpret_cast<const unsigned char *>(secret.data()),
-                secret.length(), &proof_data);
-
-  std::string proof(proof_data.begin(), proof_data.end());
-  EXPECT_EQ(proof, credential_.proof);
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_credential_state.cc b/net/spdy/spdy_credential_state.cc
deleted file mode 100644
index 4549b37..0000000
--- a/net/spdy/spdy_credential_state.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012 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 "net/spdy/spdy_credential_state.h"
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "net/ssl/server_bound_cert_service.h"
-
-namespace net {
-
-namespace {
-
-GURL GetCanonicalOrigin(const GURL& url) {
-  std::string domain =
-      ServerBoundCertService::GetDomainForHost(url.host());
-  DCHECK(!domain.empty());
-  if (domain == url.host())
-    return url.GetOrigin();
-  return GURL(url.scheme() + "://" + domain + ":" + url.port());
-}
-
-}  // namespace
-
-const size_t SpdyCredentialState::kDefaultNumSlots = 8;
-const size_t SpdyCredentialState::kNoEntry = 0;
-
-SpdyCredentialState::SpdyCredentialState(size_t num_slots)
-  : slots_(num_slots),
-    last_added_(-1) {}
-
-SpdyCredentialState::~SpdyCredentialState() {}
-
-bool SpdyCredentialState::HasCredential(const GURL& origin) const {
-  return FindCredentialSlot(origin) != kNoEntry;
-}
-
-size_t SpdyCredentialState::SetHasCredential(const GURL& origin) {
-  size_t i = FindCredentialSlot(origin);
-  if (i != kNoEntry)
-    return i;
-  // Add the new entry at the next index following the index of the last
-  // entry added, or at index 0 if the last added index is the last index.
-  if (last_added_ + 1 == slots_.size()) {
-    last_added_ = 0;
-  } else {
-    last_added_++;
-  }
-  slots_[last_added_] = GetCanonicalOrigin(origin);
-  return last_added_ + 1;
-}
-
-size_t SpdyCredentialState::FindCredentialSlot(const GURL& origin) const {
-  GURL url = GetCanonicalOrigin(origin);
-  for (size_t i = 0; i < slots_.size(); i++) {
-    if (url == slots_[i])
-      return i + 1;
-  }
-  return kNoEntry;
-}
-
-void SpdyCredentialState::Resize(size_t size) {
-  slots_.resize(size);
-  if (last_added_ >= slots_.size())
-    last_added_ = slots_.size() - 1;
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_credential_state.h b/net/spdy/spdy_credential_state.h
deleted file mode 100644
index 505b012..0000000
--- a/net/spdy/spdy_credential_state.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012 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 NET_SPDY_SPDY_CREDENTIAL_STATE_H_
-#define NET_SPDY_SPDY_CREDENTIAL_STATE_H_
-
-#include <vector>
-
-#include "net/base/net_export.h"
-#include "url/gurl.h"
-
-namespace net {
-
-// A class for tracking the credentials associated with a SPDY session.
-class NET_EXPORT_PRIVATE SpdyCredentialState {
- public:
-  explicit SpdyCredentialState(size_t num_slots);
-  ~SpdyCredentialState();
-
-  // Changes the number of credentials being tracked.  If the new size is
-  // larger, then empty slots will be added to the end.  If the new size is
-  // smaller than the current size, then the extra slots will be truncated
-  // from the end.
-  void Resize(size_t size);
-
-  // Returns the one-based index in |slots_| for |url| or kNoEntry, if no entry
-  // for |url| exists.
-  size_t FindCredentialSlot(const GURL& url) const;
-
-  // Returns true if there is a credential associated with |url|.
-  bool HasCredential(const GURL& url) const;
-
-  // Adds the new credentials to be associated with all origins matching
-  // |url|.  If there is space, then it will add in the first available
-  // position.  Otherwise, an existing credential will be evicted.  Returns
-  // the slot in which this domain was added.
-  size_t SetHasCredential(const GURL& url);
-
-  // This value is defined as the default initial value in the SPDY spec unless
-  // otherwise negotiated via SETTINGS.
-  static const size_t kDefaultNumSlots;
-
-  // Sentinel value to be returned by FindCredentialSlot when no entry exists.
-  static const size_t kNoEntry;
-
- private:
-  // Vector of origins that have credentials.
-  std::vector<GURL> slots_;
-  // Index of the last origin added to |slots_|.
-  size_t last_added_;
-};
-
-}  // namespace net
-
-#endif  // NET_SPDY_SPDY_CREDENTIAL_STATE_H_
diff --git a/net/spdy/spdy_credential_state_unittest.cc b/net/spdy/spdy_credential_state_unittest.cc
deleted file mode 100644
index b512921..0000000
--- a/net/spdy/spdy_credential_state_unittest.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2012 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 "net/spdy/spdy_credential_state.h"
-
-#include "net/base/host_port_pair.h"
-#include "testing/platform_test.h"
-
-namespace net {
-
-class SpdyCredentialStateTest : public PlatformTest {
- public:
-  SpdyCredentialStateTest()
-    : state_(4),
-      origin1_("https://1.com"),
-      origin2_("https://2.com"),
-      origin3_("https://3.com"),
-      origin4_("https://4.com"),
-      origin5_("https://5.com"),
-      origin6_("https://6.com"),
-      origin11_("https://11.com"),
-      host1_("https://www.1.com:443") {
-  }
-
- protected:
-  SpdyCredentialState state_;
-  const GURL origin1_;
-  const GURL origin2_;
-  const GURL origin3_;
-  const GURL origin4_;
-  const GURL origin5_;
-  const GURL origin6_;
-  const GURL origin11_;
-  const GURL host1_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpdyCredentialStateTest);
-};
-
-TEST_F(SpdyCredentialStateTest, HasCredentialReturnsFalseWhenEmpty) {
-  EXPECT_FALSE(state_.HasCredential(origin1_));
-  EXPECT_FALSE(state_.HasCredential(origin2_));
-  EXPECT_FALSE(state_.HasCredential(origin3_));
-}
-
-TEST_F(SpdyCredentialStateTest, HasCredentialReturnsTrueWhenAdded) {
-  state_.SetHasCredential(origin1_);
-  EXPECT_TRUE(state_.HasCredential(origin1_));
-  EXPECT_TRUE(state_.HasCredential(host1_));
-  EXPECT_FALSE(state_.HasCredential(origin11_));
-  EXPECT_FALSE(state_.HasCredential(origin2_));
-  EXPECT_FALSE(state_.HasCredential(origin3_));
-}
-
-TEST_F(SpdyCredentialStateTest, SetCredentialAddsToEndOfList) {
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin3_)));
-}
-
-TEST_F(SpdyCredentialStateTest, SetReturnsPositionIfAlreadyInList) {
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-}
-
-TEST_F(SpdyCredentialStateTest, SetReplacesOldestElementWhenFull) {
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin3_)));
-  EXPECT_EQ(4u, (state_.SetHasCredential(origin4_)));
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin5_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin6_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(4u, (state_.SetHasCredential(origin2_)));
-}
-
-TEST_F(SpdyCredentialStateTest, ResizeAddsEmptySpaceAtEnd) {
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin3_)));
-  EXPECT_EQ(4u, (state_.SetHasCredential(origin4_)));
-  state_.Resize(6);
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin3_)));
-  EXPECT_EQ(4u, (state_.SetHasCredential(origin4_)));
-  EXPECT_EQ(5u, (state_.SetHasCredential(origin5_)));
-  EXPECT_EQ(6u, (state_.SetHasCredential(origin6_)));
-}
-
-TEST_F(SpdyCredentialStateTest, ResizeTrunatesFromEnd) {
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin1_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin2_)));
-  EXPECT_EQ(3u, (state_.SetHasCredential(origin3_)));
-  EXPECT_EQ(4u, (state_.SetHasCredential(origin4_)));
-  state_.Resize(2);
-  EXPECT_TRUE(state_.HasCredential(origin1_));
-  EXPECT_TRUE(state_.HasCredential(origin2_));
-  EXPECT_FALSE(state_.HasCredential(origin3_));
-  EXPECT_FALSE(state_.HasCredential(origin4_));
-  EXPECT_EQ(1u, (state_.SetHasCredential(origin5_)));
-  EXPECT_EQ(2u, (state_.SetHasCredential(origin6_)));
-}
-
-
-}  // namespace net
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 9627c8f..9ae1c89 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -19,6 +19,8 @@
 #include "net/spdy/spdy_header_block.h"
 #include "net/spdy/spdy_protocol.h"
 
+// TODO(akalin): Remove support for CREDENTIAL frames.
+
 typedef struct z_stream_s z_stream;  // Forward declaration for zlib.
 
 namespace net {
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index f132d6c..5a58703 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -23,7 +23,6 @@
 #include "net/http/http_response_info.h"
 #include "net/socket/next_proto.h"
 #include "net/socket/socket_test_util.h"
-#include "net/spdy/spdy_credential_builder.h"
 #include "net/spdy/spdy_http_utils.h"
 #include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_test_util_common.h"
@@ -533,159 +532,6 @@
   EXPECT_TRUE(data()->at_write_eof());
 }
 
-namespace {
-
-void GetECServerBoundCertAndProof(
-    const std::string& host,
-    ServerBoundCertService* server_bound_cert_service,
-    std::string* cert,
-    std::string* proof) {
-  TestCompletionCallback callback;
-  std::string key;
-  ServerBoundCertService::RequestHandle request_handle;
-  int rv = server_bound_cert_service->GetOrCreateDomainBoundCert(
-      host, &key, cert, callback.callback(),
-      &request_handle);
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-  EXPECT_EQ(OK, callback.WaitForResult());
-
-  SpdyCredential credential;
-  EXPECT_EQ(OK,
-            SpdyCredentialBuilder::Build(
-                MockClientSocket::kTlsUnique, key, *cert, 2, &credential));
-
-  ASSERT_FALSE(credential.certs.empty());
-  cert->assign(credential.certs[0]);
-  proof->assign(credential.proof);
-}
-
-// Constructs a standard SPDY SYN_STREAM frame for a GET request with
-// a credential set.
-SpdyFrame* ConstructCredentialRequestFrame(NextProto next_proto,
-                                           size_t slot, const GURL& url,
-                                           SpdyStreamId stream_id) {
-  SpdyTestUtil util(next_proto);
-
-  const SpdyHeaderInfo syn_headers = {
-    SYN_STREAM,
-    stream_id,
-    0,
-    ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
-    slot,
-    CONTROL_FLAG_FIN,
-    false,
-    RST_STREAM_INVALID,
-    NULL,
-    0,
-    DATA_FLAG_NONE
-  };
-
-  scoped_ptr<SpdyHeaderBlock> headers(util.ConstructGetHeaderBlock(url.spec()));
-  return util.ConstructSpdyFrame(syn_headers, headers.Pass());
-}
-
-}  // namespace
-
-// TODO(rch): When openssl supports server bound certifictes, this
-// guard can be removed
-#if !defined(USE_OPENSSL)
-// Test that if we request a resource for a new origin on a session that
-// used domain bound certificates, that we send a CREDENTIAL frame for
-// the new domain before we send the new request.
-void SpdyHttpStreamTest::TestSendCredentials(
-    ServerBoundCertService* server_bound_cert_service,
-    const std::string& cert,
-    const std::string& proof) {
-  const char* kUrl1 = "https://www.google.com/";
-  const char* kUrl2 = "https://www.gmail.com/";
-
-  SpdyCredential cred;
-  cred.slot = 2;
-  cred.proof = proof;
-  cred.certs.push_back(cert);
-
-  scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
-      GetParam(), 1, GURL(kUrl1), 1));
-  scoped_ptr<SpdyFrame> credential(
-      spdy_util_.ConstructSpdyCredential(cred));
-  scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
-      GetParam(), 2, GURL(kUrl2), 3));
-  MockWrite writes[] = {
-    CreateMockWrite(*req.get(), 0),
-    CreateMockWrite(*credential.get(), 2),
-    CreateMockWrite(*req2.get(), 3),
-  };
-
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
-  MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*resp2, 4),
-    MockRead(SYNCHRONOUS, 0, 5)  // EOF
-  };
-
-  HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
-  SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
-                     kPrivacyModeDisabled);
-
-  DeterministicMockClientSocketFactory* socket_factory =
-      session_deps_.deterministic_socket_factory.get();
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  socket_factory->AddSocketDataProvider(&data);
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  ssl.channel_id_sent = true;
-  ssl.server_bound_cert_service = server_bound_cert_service;
-  ssl.protocol_negotiated = GetParam();
-  socket_factory->AddSSLSocketDataProvider(&ssl);
-  http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
-      &session_deps_);
-  session_ = CreateSecureSpdySession(http_session_, key, BoundNetLog());
-
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL(kUrl1);
-  HttpResponseInfo response;
-  HttpRequestHeaders headers;
-  BoundNetLog net_log;
-  scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
-  ASSERT_EQ(
-      OK,
-      http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
-                                    net_log, CompletionCallback()));
-
-  //  EXPECT_FALSE(session_->NeedsCredentials(request.url));
-  //  GURL new_origin(kUrl2);
-  //  EXPECT_TRUE(session_->NeedsCredentials(new_origin));
-
-  TestCompletionCallback callback;
-  EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
-                                                     callback.callback()));
-  EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
-
-  data.RunFor(2);
-  callback.WaitForResult();
-
-  // Start up second request for resource on a new origin.
-  scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
-  request.url = GURL(kUrl2);
-  ASSERT_EQ(
-      OK,
-      http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
-                                     net_log, CompletionCallback()));
-  EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
-                                                      callback.callback()));
-  data.RunFor(2);
-  callback.WaitForResult();
-
-  EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
-      callback.callback()));
-  data.RunFor(1);
-  EXPECT_EQ(OK, callback.WaitForResult());
-  ASSERT_TRUE(response.headers.get() != NULL);
-  ASSERT_EQ(200, response.headers->response_code());
-}
-
 // The tests below are only for SPDY/3 and above.
 
 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
@@ -780,112 +626,6 @@
   EXPECT_TRUE(deterministic_data_->at_write_eof());
 }
 
-TEST_P(SpdyHttpStreamTest, SendCredentialsEC) {
-  if (GetParam() < kProtoSPDY3)
-    return;
-
-  scoped_ptr<ServerBoundCertService> server_bound_cert_service(
-      new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 base::MessageLoopProxy::current()));
-  std::string cert;
-  std::string proof;
-  GetECServerBoundCertAndProof("www.gmail.com",
-                               server_bound_cert_service.get(),
-                               &cert, &proof);
-
-  TestSendCredentials(server_bound_cert_service.get(), cert, proof);
-}
-
-TEST_P(SpdyHttpStreamTest, DontSendCredentialsForHttpUrlsEC) {
-  if (GetParam() < kProtoSPDY3)
-    return;
-
-  scoped_ptr<ServerBoundCertService> server_bound_cert_service(
-      new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 base::MessageLoopProxy::current()));
-  std::string cert;
-  std::string proof;
-  GetECServerBoundCertAndProof("proxy.google.com",
-                               server_bound_cert_service.get(),
-                               &cert, &proof);
-
-  const char* kUrl1 = "http://www.google.com/";
-  const char* kUrl2 = "http://www.gmail.com/";
-
-  SpdyCredential cred;
-  cred.slot = 2;
-  cred.proof = proof;
-  cred.certs.push_back(cert);
-
-  scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
-      GetParam(), 0, GURL(kUrl1), 1));
-  scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
-      GetParam(), 0, GURL(kUrl2), 3));
-  MockWrite writes[] = {
-    CreateMockWrite(*req.get(), 0),
-    CreateMockWrite(*req2.get(), 2),
-  };
-
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
-  MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*resp2, 3),
-    MockRead(ASYNC, 0, 4)  // EOF
-  };
-
-  HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
-  SpdySessionKey key(host_port_pair,
-                     ProxyServer::FromURI("proxy.google.com",
-                                          ProxyServer::SCHEME_HTTPS),
-                     kPrivacyModeDisabled);
-  InitSessionDeterministic(reads, arraysize(reads),
-                           writes, arraysize(writes),
-                           key);
-
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL(kUrl1);
-  HttpResponseInfo response;
-  HttpRequestHeaders headers;
-  BoundNetLog net_log;
-  scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
-  ASSERT_EQ(
-      OK,
-      http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
-                                    net_log, CompletionCallback()));
-
-  TestCompletionCallback callback;
-  EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
-                                                     callback.callback()));
-  EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
-
-  deterministic_data_->RunFor(2);
-  EXPECT_EQ(OK, callback.WaitForResult());
-
-  // Start up second request for resource on a new origin.
-  scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
-  request.url = GURL(kUrl2);
-  ASSERT_EQ(
-      OK,
-      http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
-                                     net_log, CompletionCallback()));
-  EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
-                                                      callback.callback()));
-  deterministic_data_->RunFor(1);
-  EXPECT_EQ(OK, callback.WaitForResult());
-
-  EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
-      callback.callback()));
-  deterministic_data_->RunFor(1);
-  EXPECT_EQ(OK, callback.WaitForResult());
-  ASSERT_TRUE(response.headers.get() != NULL);
-  ASSERT_EQ(200, response.headers->response_code());
-  deterministic_data_->RunFor(1);
-}
-
-#endif  // !defined(USE_OPENSSL)
-
 // TODO(willchan): Write a longer test for SpdyStream that exercises all
 // methods.
 
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 799b809..16a8d83 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -32,7 +32,6 @@
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties.h"
 #include "net/spdy/spdy_buffer_producer.h"
-#include "net/spdy/spdy_credential_builder.h"
 #include "net/spdy/spdy_frame_builder.h"
 #include "net/spdy/spdy_http_utils.h"
 #include "net/spdy/spdy_protocol.h"
@@ -378,7 +377,6 @@
     const base::WeakPtr<HttpServerProperties>& http_server_properties,
     bool verify_domain_authentication,
     bool enable_sending_initial_data,
-    bool enable_credential_frames,
     bool enable_compression,
     bool enable_ping_based_connection_checking,
     NextProto default_protocol,
@@ -433,12 +431,10 @@
       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
       verify_domain_authentication_(verify_domain_authentication),
       enable_sending_initial_data_(enable_sending_initial_data),
-      enable_credential_frames_(enable_credential_frames),
       enable_compression_(enable_compression),
       enable_ping_based_connection_checking_(
           enable_ping_based_connection_checking),
       protocol_(default_protocol),
-      credential_state_(SpdyCredentialState::kDefaultNumSlots),
       connection_at_risk_of_loss_time_(
           base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
       hung_interval_(
@@ -504,14 +500,6 @@
   DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
   DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
 
-  SSLClientSocket* ssl_socket = GetSSLClientSocket();
-  if (ssl_socket && ssl_socket->WasChannelIDSent()) {
-    // According to the SPDY spec, the credential associated with the TLS
-    // connection is stored in slot[1].
-    credential_state_.SetHasCredential(GURL("https://" +
-                                            host_port_pair().ToString()));
-  }
-
   if (protocol_ == kProtoHTTP2Draft04)
     send_connection_header_prefix_ = true;
 
@@ -569,11 +557,13 @@
   if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
     return true;   // This is not a secure session, so all domains are okay.
 
-  return !ssl_info.client_cert_sent &&
-      (enable_credential_frames_ || !ssl_info.channel_id_sent ||
-       ServerBoundCertService::GetDomainForHost(domain) ==
-       ServerBoundCertService::GetDomainForHost(host_port_pair().host())) &&
-       ssl_info.cert->VerifyNameMatch(domain);
+  bool unused = false;
+  return
+      !ssl_info.client_cert_sent &&
+      (!ssl_info.channel_id_sent ||
+       (ServerBoundCertService::GetDomainForHost(domain) ==
+        ServerBoundCertService::GetDomainForHost(host_port_pair().host()))) &&
+      ssl_info.cert->VerifyNameMatch(domain, &unused);
 }
 
 int SpdySession::GetPushStream(
@@ -775,15 +765,6 @@
   }
 }
 
-bool SpdySession::NeedsCredentials() const {
-  if (!is_secure_)
-    return false;
-  SSLClientSocket* ssl_socket = GetSSLClientSocket();
-  if (ssl_socket->GetNegotiatedProtocol() < kProtoSPDY3)
-    return false;
-  return ssl_socket->WasChannelIDSent();
-}
-
 void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
   pooled_aliases_.insert(alias_key);
 }
@@ -860,39 +841,6 @@
   return syn_frame.Pass();
 }
 
-int SpdySession::CreateCredentialFrame(
-    const std::string& origin,
-    const std::string& key,
-    const std::string& cert,
-    RequestPriority priority,
-    scoped_ptr<SpdyFrame>* credential_frame) {
-  DCHECK(is_secure_);
-  SSLClientSocket* ssl_socket = GetSSLClientSocket();
-  DCHECK(ssl_socket);
-  DCHECK(ssl_socket->WasChannelIDSent());
-
-  SpdyCredential credential;
-  std::string tls_unique;
-  ssl_socket->GetTLSUniqueChannelBinding(&tls_unique);
-  size_t slot = credential_state_.SetHasCredential(GURL(origin));
-  int rv = SpdyCredentialBuilder::Build(tls_unique, key, cert, slot,
-                                        &credential);
-  DCHECK_NE(rv, ERR_IO_PENDING);
-  if (rv != OK)
-    return rv;
-
-  DCHECK(buffered_spdy_framer_.get());
-  credential_frame->reset(
-      buffered_spdy_framer_->CreateCredentialFrame(credential));
-
-  if (net_log().IsLoggingAllEvents()) {
-    net_log().AddEvent(
-        NetLog::TYPE_SPDY_SESSION_SEND_CREDENTIAL,
-        base::Bind(&NetLogSpdyCredentialCallback, credential.slot, &origin));
-  }
-  return OK;
-}
-
 scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id,
                                                      IOBuffer* data,
                                                      int len,
@@ -1833,12 +1781,6 @@
   return true;
 }
 
-ServerBoundCertService* SpdySession::GetServerBoundCertService() const {
-  if (!is_secure_)
-    return NULL;
-  return GetSSLClientSocket()->GetServerBoundCertService();
-}
-
 void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
   CHECK(in_io_loop_);
 
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 9121a92..e81ab26 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -28,7 +28,6 @@
 #include "net/socket/stream_socket.h"
 #include "net/spdy/buffered_spdy_framer.h"
 #include "net/spdy/spdy_buffer.h"
-#include "net/spdy/spdy_credential_state.h"
 #include "net/spdy/spdy_framer.h"
 #include "net/spdy/spdy_header_block.h"
 #include "net/spdy/spdy_protocol.h"
@@ -207,7 +206,6 @@
               const base::WeakPtr<HttpServerProperties>& http_server_properties,
               bool verify_domain_authentication,
               bool enable_sending_initial_data,
-              bool enable_credential_frames,
               bool enable_compression,
               bool enable_ping_based_connection_checking,
               NextProto default_protocol,
@@ -292,15 +290,6 @@
       SpdyControlFlags flags,
       const SpdyHeaderBlock& headers);
 
-  // Tries to create a CREDENTIAL frame. If successful, fills in
-  // |credential_frame| and returns OK. Returns the error (guaranteed
-  // to not be ERR_IO_PENDING) otherwise.
-  int CreateCredentialFrame(const std::string& origin,
-                            const std::string& key,
-                            const std::string& cert,
-                            RequestPriority priority,
-                            scoped_ptr<SpdyFrame>* credential_frame);
-
   // Creates and returns a SpdyBuffer holding a data frame with the
   // given data. May return NULL if stalled by flow control.
   scoped_ptr<SpdyBuffer> CreateDataBuffer(SpdyStreamId stream_id,
@@ -341,10 +330,6 @@
   // true when SSL is in use.
   bool GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
 
-  // Returns the ServerBoundCertService used by this Socket, or NULL
-  // if server bound certs are not supported in this session.
-  ServerBoundCertService* GetServerBoundCertService() const;
-
   // Send a WINDOW_UPDATE frame for a stream. Called by a stream
   // whenever receive window size is increased.
   void SendStreamWindowUpdate(SpdyStreamId stream_id,
@@ -440,11 +425,6 @@
   int GetPeerAddress(IPEndPoint* address) const;
   int GetLocalAddress(IPEndPoint* address) const;
 
-  // Returns true if requests on this session require credentials.
-  bool NeedsCredentials() const;
-
-  SpdyCredentialState* credential_state() { return &credential_state_; }
-
   // Adds |alias| to set of aliases associated with this session.
   void AddPooledAlias(const SpdySessionKey& alias_key);
 
@@ -1094,7 +1074,6 @@
   // Outside of tests, these should always be true.
   bool verify_domain_authentication_;
   bool enable_sending_initial_data_;
-  bool enable_credential_frames_;
   bool enable_compression_;
   bool enable_ping_based_connection_checking_;
 
@@ -1102,8 +1081,6 @@
   // kProtoSPDYMaximumVersion.
   NextProto protocol_;
 
-  SpdyCredentialState credential_state_;
-
   // |connection_at_risk_of_loss_time_| is an optimization to avoid sending
   // wasteful preface pings (when we just got some data).
   //
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index e72064b..831e09d 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -33,7 +33,6 @@
     const base::WeakPtr<HttpServerProperties>& http_server_properties,
     bool force_single_domain,
     bool enable_ip_pooling,
-    bool enable_credential_frames,
     bool enable_compression,
     bool enable_ping_based_connection_checking,
     NextProto default_protocol,
@@ -49,7 +48,6 @@
       enable_sending_initial_data_(true),
       force_single_domain_(force_single_domain),
       enable_ip_pooling_(enable_ip_pooling),
-      enable_credential_frames_(enable_credential_frames),
       enable_compression_(enable_compression),
       enable_ping_based_connection_checking_(
           enable_ping_based_connection_checking),
@@ -99,7 +97,6 @@
                       http_server_properties_,
                       verify_domain_authentication_,
                       enable_sending_initial_data_,
-                      enable_credential_frames_,
                       enable_compression_,
                       enable_ping_based_connection_checking_,
                       default_protocol_,
@@ -293,11 +290,11 @@
   CloseCurrentSessions(ERR_NETWORK_CHANGED);
 }
 
-void SpdySessionPool::OnCertTrustChanged(const X509Certificate* cert) {
+void SpdySessionPool::OnCACertChanged(const X509Certificate* cert) {
   // Per wtc, we actually only need to CloseCurrentSessions when trust is
-  // reduced. CloseCurrentSessions now because OnCertTrustChanged does not
+  // reduced. CloseCurrentSessions now because OnCACertChanged does not
   // tell us this.
-  // See comments in ClientSocketPoolManager::OnCertTrustChanged.
+  // See comments in ClientSocketPoolManager::OnCACertChanged.
   CloseCurrentSessions(ERR_NETWORK_CHANGED);
 }
 
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 812b7bd..91e27e6 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -52,7 +52,6 @@
       const base::WeakPtr<HttpServerProperties>& http_server_properties,
       bool force_single_domain,
       bool enable_ip_pooling,
-      bool enable_credential_frames,
       bool enable_compression,
       bool enable_ping_based_connection_checking,
       NextProto default_protocol,
@@ -143,7 +142,7 @@
 
   // CertDatabase::Observer methods:
   virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE;
-  virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE;
+  virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE;
 
  private:
   friend class SpdySessionPoolPeer;  // For testing.
@@ -214,7 +213,6 @@
   bool enable_sending_initial_data_;
   bool force_single_domain_;
   bool enable_ip_pooling_;
-  bool enable_credential_frames_;
   bool enable_compression_;
   bool enable_ping_based_connection_checking_;
   const NextProto default_protocol_;
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 4d7c2c4..2f185c7 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -2285,38 +2285,6 @@
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
 }
 
-TEST_P(SpdySessionTest, NeedsCredentials) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  MockRead reads[] = {
-    MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
-  };
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
-  session_deps_.socket_factory->AddSocketDataProvider(&data);
-
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  ssl.channel_id_sent = true;
-  ssl.protocol_negotiated = GetParam();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-
-  CreateNetworkSession();
-
-  const GURL url("https://www.foo.com");
-  HostPortPair test_host_port_pair(url.host(), 443);
-  SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(),
-                     kPrivacyModeDisabled);
-
-  base::WeakPtr<SpdySession> session =
-      CreateSecureSpdySession(http_session_, key, BoundNetLog());
-
-  EXPECT_EQ(spdy_util_.spdy_version() >= SPDY3, session->NeedsCredentials());
-
-  // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
-
-  session->CloseSessionOnError(ERR_ABORTED, std::string());
-}
-
 // Test that SpdySession::DoReadLoop reads data from the socket
 // without yielding.  This test makes 32k - 1 bytes of data available
 // on the socket for reading. It then verifies that it has read all
@@ -3076,49 +3044,6 @@
 
 // The tests below are only for SPDY/3 and above.
 
-TEST_P(SpdySessionTest, SendCredentials) {
-  if (GetParam() < kProtoSPDY3)
-    return;
-
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  MockRead reads[] = {
-    MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
-  };
-  SettingsMap settings;
-  scoped_ptr<SpdyFrame> settings_frame(
-      spdy_util_.ConstructSpdySettings(settings));
-  MockWrite writes[] = {
-    CreateMockWrite(*settings_frame),
-  };
-  StaticSocketDataProvider data(reads, arraysize(reads),
-                                writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.socket_factory->AddSocketDataProvider(&data);
-
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  ssl.channel_id_sent = true;
-  ssl.protocol_negotiated = GetParam();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-
-  CreateNetworkSession();
-
-  const GURL kTestUrl("https://www.foo.com");
-  HostPortPair test_host_port_pair(kTestUrl.host(), 443);
-  SpdySessionKey key(test_host_port_pair, ProxyServer::Direct(),
-                     kPrivacyModeDisabled);
-
-  base::WeakPtr<SpdySession> session =
-      CreateSecureSpdySession(http_session_, key, BoundNetLog());
-
-  EXPECT_TRUE(session->NeedsCredentials());
-
-  // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
-
-  session->CloseSessionOnError(ERR_ABORTED, std::string());
-  EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key));
-}
-
 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
   if (GetParam() < kProtoSPDY3)
     return;
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 3500d1b..0a1f0e9 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -583,7 +583,7 @@
   CHECK_EQ(io_state_, STATE_NONE);
   request_headers_ = request_headers.Pass();
   send_status_ = send_status;
-  io_state_ = STATE_GET_DOMAIN_BOUND_CERT;
+  io_state_ = STATE_SEND_REQUEST_HEADERS;
   return DoLoop(OK);
 }
 
@@ -656,11 +656,6 @@
   return !GetUrlFromHeaders().is_empty();
 }
 
-void SpdyStream::OnGetDomainBoundCertComplete(int result) {
-  DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE);
-  DoLoop(result);
-}
-
 int SpdyStream::DoLoop(int result) {
   CHECK(!in_do_loop_);
   in_do_loop_ = true;
@@ -669,20 +664,6 @@
     State state = io_state_;
     io_state_ = STATE_NONE;
     switch (state) {
-      case STATE_GET_DOMAIN_BOUND_CERT:
-        CHECK_EQ(result, OK);
-        result = DoGetDomainBoundCert();
-        break;
-      case STATE_GET_DOMAIN_BOUND_CERT_COMPLETE:
-        result = DoGetDomainBoundCertComplete(result);
-        break;
-      case STATE_SEND_DOMAIN_BOUND_CERT:
-        CHECK_EQ(result, OK);
-        result = DoSendDomainBoundCert();
-        break;
-      case STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE:
-        result = DoSendDomainBoundCertComplete(result);
-        break;
       case STATE_SEND_REQUEST_HEADERS:
         CHECK_EQ(result, OK);
         result = DoSendRequestHeaders();
@@ -722,91 +703,6 @@
   return result;
 }
 
-int SpdyStream::DoGetDomainBoundCert() {
-  CHECK(request_headers_);
-  DCHECK_NE(type_, SPDY_PUSH_STREAM);
-  GURL url = GetUrlFromHeaders();
-  if (!session_->NeedsCredentials() || !url.SchemeIs("https")) {
-    // Proceed directly to sending the request headers
-    io_state_ = STATE_SEND_REQUEST_HEADERS;
-    return OK;
-  }
-
-  slot_ = session_->credential_state()->FindCredentialSlot(GetUrlFromHeaders());
-  if (slot_ != SpdyCredentialState::kNoEntry) {
-    // Proceed directly to sending the request headers
-    io_state_ = STATE_SEND_REQUEST_HEADERS;
-    return OK;
-  }
-
-  io_state_ = STATE_GET_DOMAIN_BOUND_CERT_COMPLETE;
-  ServerBoundCertService* sbc_service = session_->GetServerBoundCertService();
-  DCHECK(sbc_service != NULL);
-  int rv = sbc_service->GetOrCreateDomainBoundCert(
-      url.GetOrigin().host(),
-      &domain_bound_private_key_,
-      &domain_bound_cert_,
-      base::Bind(&SpdyStream::OnGetDomainBoundCertComplete, GetWeakPtr()),
-      &domain_bound_cert_request_handle_);
-  return rv;
-}
-
-int SpdyStream::DoGetDomainBoundCertComplete(int result) {
-  DCHECK_NE(type_, SPDY_PUSH_STREAM);
-  if (result != OK)
-    return result;
-
-  io_state_ = STATE_SEND_DOMAIN_BOUND_CERT;
-  slot_ =  session_->credential_state()->SetHasCredential(GetUrlFromHeaders());
-  return OK;
-}
-
-int SpdyStream::DoSendDomainBoundCert() {
-  CHECK(request_headers_);
-  DCHECK_NE(type_, SPDY_PUSH_STREAM);
-  io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE;
-
-  std::string origin = GetUrlFromHeaders().GetOrigin().spec();
-  DCHECK(origin[origin.length() - 1] == '/');
-  origin.erase(origin.length() - 1);  // Trim trailing slash.
-  scoped_ptr<SpdyFrame> frame;
-  int rv = session_->CreateCredentialFrame(
-      origin,
-      domain_bound_private_key_,
-      domain_bound_cert_,
-      priority_,
-      &frame);
-  if (rv != OK) {
-    DCHECK_NE(rv, ERR_IO_PENDING);
-    return rv;
-  }
-
-  DCHECK(frame);
-  // TODO(akalin): Fix the following race condition:
-  //
-  // Since this is decoupled from sending the SYN_STREAM frame, it is
-  // possible that other domain-bound cert frames will clobber ours
-  // before our SYN_STREAM frame gets sent. This can be solved by
-  // immediately enqueueing the SYN_STREAM frame here and adjusting
-  // the state machine appropriately.
-  session_->EnqueueStreamWrite(
-      GetWeakPtr(), CREDENTIAL,
-      scoped_ptr<SpdyBufferProducer>(
-          new SimpleBufferProducer(
-              scoped_ptr<SpdyBuffer>(new SpdyBuffer(frame.Pass())))));
-  return ERR_IO_PENDING;
-}
-
-int SpdyStream::DoSendDomainBoundCertComplete(int result) {
-  DCHECK_NE(type_, SPDY_PUSH_STREAM);
-  if (result != OK)
-    return result;
-
-  DCHECK_EQ(just_completed_frame_type_, CREDENTIAL);
-  io_state_ = STATE_SEND_REQUEST_HEADERS;
-  return OK;
-}
-
 int SpdyStream::DoSendRequestHeaders() {
   DCHECK_NE(type_, SPDY_PUSH_STREAM);
   io_state_ = STATE_SEND_REQUEST_HEADERS_COMPLETE;
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index 01d8ed6..02be61e 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -412,26 +412,16 @@
 
   enum State {
     STATE_NONE,
-    STATE_GET_DOMAIN_BOUND_CERT,
-    STATE_GET_DOMAIN_BOUND_CERT_COMPLETE,
-    STATE_SEND_DOMAIN_BOUND_CERT,
-    STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE,
     STATE_SEND_REQUEST_HEADERS,
     STATE_SEND_REQUEST_HEADERS_COMPLETE,
     STATE_IDLE,
     STATE_CLOSED
   };
 
-  void OnGetDomainBoundCertComplete(int result);
-
   // Try to make progress sending/receiving the request/response.
   int DoLoop(int result);
 
   // The implementations of each state of the state machine.
-  int DoGetDomainBoundCert();
-  int DoGetDomainBoundCertComplete(int result);
-  int DoSendDomainBoundCert();
-  int DoSendDomainBoundCertComplete(int result);
   int DoSendRequestHeaders();
   int DoSendRequestHeadersComplete();
   int DoReadHeaders();
diff --git a/net/ssl/client_cert_store.h b/net/ssl/client_cert_store.h
index 46ef336..394d774 100644
--- a/net/ssl/client_cert_store.h
+++ b/net/ssl/client_cert_store.h
@@ -6,6 +6,7 @@
 #define NET_SSL_CLIENT_CERT_STORE_H_
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
 #include "net/base/net_export.h"
 #include "net/cert/x509_certificate.h"
 
@@ -13,12 +14,19 @@
 
 class SSLCertRequestInfo;
 
+// The caller is expected to keep the ClientCertStore alive until the callback
+// supplied to GetClientCerts has been run.
 class NET_EXPORT ClientCertStore {
  public:
   virtual ~ClientCertStore() {}
 
-  virtual bool GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                              CertificateList* selected_certs) = 0;
+  // Get client certs matching the |cert_request_info|. On completion, the
+  // results will be stored in |selected_certs| and the |callback| will be run.
+  // The |callback| may be called sychronously. The caller must ensure the
+  // |selected_certs| object remains alive until the callback has been run.
+  virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
+                              CertificateList* selected_certs,
+                              const base::Closure& callback) = 0;
  protected:
   ClientCertStore() {}
 
diff --git a/net/ssl/client_cert_store_impl.h b/net/ssl/client_cert_store_impl.h
index e02cd1c..ff2759e 100644
--- a/net/ssl/client_cert_store_impl.h
+++ b/net/ssl/client_cert_store_impl.h
@@ -19,8 +19,9 @@
   virtual ~ClientCertStoreImpl() {}
 
   // ClientCertStore:
-  virtual bool GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                              CertificateList* selected_certs) OVERRIDE;
+  virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
+                              CertificateList* selected_certs,
+                              const base::Closure& callback) OVERRIDE;
 
  private:
   friend class ClientCertStoreImplTest;
diff --git a/net/ssl/client_cert_store_impl_mac.cc b/net/ssl/client_cert_store_impl_mac.cc
index 3345735..468ff03 100644
--- a/net/ssl/client_cert_store_impl_mac.cc
+++ b/net/ssl/client_cert_store_impl_mac.cc
@@ -13,6 +13,7 @@
 #include <algorithm>
 #include <string>
 
+#include "base/callback.h"
 #include "base/logging.h"
 #include "base/mac/mac_logging.h"
 #include "base/mac/scoped_cftyperef.h"
@@ -122,7 +123,7 @@
 // full certificate chains. If it is false, only the the certificates and their
 // intermediates (available via X509Certificate::GetIntermediateCertificates())
 // will be considered.
-bool GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert,
+void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert,
                         const CertificateList& regular_certs,
                         const SSLCertRequestInfo& request,
                         bool query_keychain,
@@ -167,13 +168,13 @@
     ++sort_begin;
   }
   sort(sort_begin, sort_end, x509_util::ClientCertSorter());
-  return true;
 }
 
 }  // namespace
 
-bool ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
-                                         CertificateList* selected_certs) {
+void ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
+                                         CertificateList* selected_certs,
+                                         const base::Closure& callback) {
   std::string server_domain =
       HostPortPair::FromString(request.host_and_port).host();
 
@@ -205,8 +206,11 @@
     base::AutoLock lock(crypto::GetMacSecurityServicesLock());
     err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search);
   }
-  if (err)
-    return false;
+  if (err) {
+    selected_certs->clear();
+    callback.Run();
+    return;
+  }
   ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search);
   while (!err) {
     SecIdentityRef identity = NULL;
@@ -239,19 +243,22 @@
 
   if (err != errSecItemNotFound) {
     OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error";
-    return false;
+    selected_certs->clear();
+    callback.Run();
+    return;
   }
 
-  return GetClientCertsImpl(preferred_cert, regular_certs, request, true,
-                            selected_certs);
+  GetClientCertsImpl(preferred_cert, regular_certs, request, true,
+                     selected_certs);
+  callback.Run();
 }
 
 bool ClientCertStoreImpl::SelectClientCertsForTesting(
     const CertificateList& input_certs,
     const SSLCertRequestInfo& request,
     CertificateList* selected_certs) {
-  return GetClientCertsImpl(NULL, input_certs, request, false,
-                            selected_certs);
+  GetClientCertsImpl(NULL, input_certs, request, false, selected_certs);
+  return true;
 }
 
 #if !defined(OS_IOS)
@@ -260,8 +267,9 @@
     const CertificateList& regular_certs,
     const SSLCertRequestInfo& request,
     CertificateList* selected_certs) {
-  return GetClientCertsImpl(preferred_cert, regular_certs, request, false,
-                            selected_certs);
+  GetClientCertsImpl(
+      preferred_cert, regular_certs, request, false, selected_certs);
+  return true;
 }
 #endif
 
diff --git a/net/ssl/client_cert_store_impl_nss.cc b/net/ssl/client_cert_store_impl_nss.cc
index ffab268..ab7144e 100644
--- a/net/ssl/client_cert_store_impl_nss.cc
+++ b/net/ssl/client_cert_store_impl_nss.cc
@@ -7,6 +7,7 @@
 #include <nss.h>
 #include <ssl.h>
 
+#include "base/callback.h"
 #include "base/logging.h"
 #include "net/cert/x509_util.h"
 
@@ -19,7 +20,7 @@
 // certificates in |selected_certs|.
 // If |query_nssdb| is true, NSS will be queried to construct full certificate
 // chains. If it is false, only the certificate will be considered.
-bool GetClientCertsImpl(CERTCertList* cert_list,
+void GetClientCertsImpl(CERTCertList* cert_list,
                         const SSLCertRequestInfo& request,
                         bool query_nssdb,
                         CertificateList* selected_certs) {
@@ -72,23 +73,26 @@
 
   std::sort(selected_certs->begin(), selected_certs->end(),
             x509_util::ClientCertSorter());
-  return true;
 }
 
 }  // namespace
 
-bool ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
-                                         CertificateList* selected_certs) {
+void ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
+                                         CertificateList* selected_certs,
+                                         const base::Closure& callback) {
   CERTCertList* client_certs = CERT_FindUserCertsByUsage(
       CERT_GetDefaultCertDB(), certUsageSSLClient,
       PR_FALSE, PR_FALSE, NULL);
   // It is ok for a user not to have any client certs.
-  if (!client_certs)
-    return true;
+  if (!client_certs) {
+    selected_certs->clear();
+    callback.Run();
+    return;
+  }
 
-  bool rv = GetClientCertsImpl(client_certs, request, true, selected_certs);
+  GetClientCertsImpl(client_certs, request, true, selected_certs);
   CERT_DestroyCertList(client_certs);
-  return rv;
+  callback.Run();
 }
 
 bool ClientCertStoreImpl::SelectClientCertsForTesting(
@@ -103,9 +107,9 @@
         cert_list, CERT_DupCertificate(input_certs[i]->os_cert_handle()));
   }
 
-  bool rv = GetClientCertsImpl(cert_list, request, false, selected_certs);
+  GetClientCertsImpl(cert_list, request, false, selected_certs);
   CERT_DestroyCertList(cert_list);
-  return rv;
+  return true;
 }
 
 }  // namespace net
diff --git a/net/ssl/client_cert_store_impl_win.cc b/net/ssl/client_cert_store_impl_win.cc
index 63ea6e4..de54fae 100644
--- a/net/ssl/client_cert_store_impl_win.cc
+++ b/net/ssl/client_cert_store_impl_win.cc
@@ -12,6 +12,7 @@
 #include <wincrypt.h>
 #include <security.h>
 
+#include "base/callback.h"
 #include "base/logging.h"
 #include "crypto/scoped_capi_types.h"
 #include "net/cert/x509_util.h"
@@ -63,7 +64,7 @@
   return TRUE;
 }
 
-bool GetClientCertsImpl(HCERTSTORE cert_store,
+void GetClientCertsImpl(HCERTSTORE cert_store,
                         const SSLCertRequestInfo& request,
                         CertificateList* selected_certs) {
   selected_certs->clear();
@@ -138,26 +139,26 @@
 
   std::sort(selected_certs->begin(), selected_certs->end(),
             x509_util::ClientCertSorter());
-  return true;
 }
 
 }  // namespace
 
-bool ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
-                                         CertificateList* selected_certs) {
+void ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
+                                         CertificateList* selected_certs,
+                                         const base::Closure& callback) {
   // Client certificates of the user are in the "MY" system certificate store.
   HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY");
   if (!my_cert_store) {
     PLOG(ERROR) << "Could not open the \"MY\" system certificate store: ";
-    return false;
+    selected_certs->clear();
+    callback.Run();
+    return;
   }
 
-  bool rv = GetClientCertsImpl(my_cert_store, request, selected_certs);
-  if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG)) {
+  GetClientCertsImpl(my_cert_store, request, selected_certs);
+  if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG))
     PLOG(ERROR) << "Could not close the \"MY\" system certificate store: ";
-    return false;
-  }
-  return rv;
+  callback.Run();
 }
 
 bool ClientCertStoreImpl::SelectClientCertsForTesting(
@@ -198,8 +199,8 @@
       return false;
   }
 
-  bool rv = GetClientCertsImpl(test_store.get(), request, selected_certs);
-  return rv;
+  GetClientCertsImpl(test_store.get(), request, selected_certs);
+  return true;
 }
 
 }  // namespace net
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 128597f..4bd68fe 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -99,13 +99,15 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 }
 
-EmbeddedTestServer::EmbeddedTestServer(
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_thread)
-    : io_thread_(io_thread),
+EmbeddedTestServer::EmbeddedTestServer()
+    : io_thread_("EmbeddedTestServer io thread"),
       port_(-1),
       weak_factory_(this) {
-  DCHECK(io_thread_.get());
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  base::Thread::Options thread_options;
+  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
+  CHECK(io_thread_.StartWithOptions(thread_options));
 }
 
 EmbeddedTestServer::~EmbeddedTestServer() {
@@ -135,7 +137,7 @@
 }
 
 void EmbeddedTestServer::InitializeOnIOThread() {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
   DCHECK(!Started());
 
   SocketDescriptor socket_descriptor =
@@ -156,7 +158,7 @@
 }
 
 void EmbeddedTestServer::ShutdownOnIOThread() {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   listen_socket_.reset();
   STLDeleteContainerPairSecondPointers(connections_.begin(),
@@ -166,7 +168,7 @@
 
 void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
                                scoped_ptr<HttpRequest> request) {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   bool request_handled = false;
 
@@ -215,7 +217,7 @@
 void EmbeddedTestServer::DidAccept(
     StreamListenSocket* server,
     scoped_ptr<StreamListenSocket> connection) {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = new HttpConnection(
       connection.Pass(),
@@ -228,7 +230,7 @@
 void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
                          const char* data,
                          int length) {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = FindConnection(connection);
   if (http_connection == NULL) {
@@ -239,7 +241,7 @@
 }
 
 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = FindConnection(connection);
   if (http_connection == NULL) {
@@ -252,7 +254,7 @@
 
 HttpConnection* EmbeddedTestServer::FindConnection(
     StreamListenSocket* socket) {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
   std::map<StreamListenSocket*, HttpConnection*>::iterator it =
       connections_.find(socket);
@@ -277,8 +279,10 @@
     temporary_loop.reset(new base::MessageLoop());
 
   base::RunLoop run_loop;
-  if (!io_thread_->PostTaskAndReply(FROM_HERE, closure, run_loop.QuitClosure()))
+  if (!io_thread_.message_loop_proxy()->PostTaskAndReply(
+          FROM_HERE, closure, run_loop.QuitClosure())) {
     return false;
+  }
   run_loop.Run();
 
   return true;
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index f8c1bb5..a419951 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -14,6 +14,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
 #include "net/socket/tcp_listen_socket.h"
 #include "url/gurl.h"
@@ -81,11 +82,9 @@
   typedef base::Callback<scoped_ptr<HttpResponse>(
       const HttpRequest& request)> HandleRequestCallback;
 
-  // Creates a http test server. |io_thread| is a task runner
-  // with IO message loop, used as a backend thread.
-  // InitializeAndWaitUntilReady() must be called to start the server.
-  explicit EmbeddedTestServer(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_thread);
+  // Creates a http test server. InitializeAndWaitUntilReady() must be called
+  // to start the server.
+  EmbeddedTestServer();
   virtual ~EmbeddedTestServer();
 
   // Initializes and waits until the server is ready to accept requests.
@@ -150,7 +149,7 @@
   bool PostTaskToIOThreadAndWait(
       const base::Closure& closure) WARN_UNUSED_RESULT;
 
-  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
+  base::Thread io_thread_;
 
   scoped_ptr<HttpListenSocket> listen_socket_;
   int port_;
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc
index 2c00518..a9c2efb 100644
--- a/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -57,7 +57,7 @@
     request_context_getter_ = new TestURLRequestContextGetter(
         io_thread_.message_loop_proxy());
 
-    server_.reset(new EmbeddedTestServer(io_thread_.message_loop_proxy()));
+    server_.reset(new EmbeddedTestServer);
     ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
   }
 
@@ -273,7 +273,7 @@
       loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
 
     // Create the test server instance.
-    EmbeddedTestServer server(io_thread_runner);
+    EmbeddedTestServer server;
     base::FilePath src_dir;
     ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
     ASSERT_TRUE(server.InitializeAndWaitUntilReady());
diff --git a/net/third_party/nss/patches/chacha20poly1305.patch b/net/third_party/nss/patches/chacha20poly1305.patch
index c858413..89a71bb 100644
--- a/net/third_party/nss/patches/chacha20poly1305.patch
+++ b/net/third_party/nss/patches/chacha20poly1305.patch
@@ -9,15 +9,15 @@
 +/* This is a bodge to allow this code to be compiled against older NSS
 + * headers. */
 +#ifndef CKM_NSS_CHACHA20_POLY1305
-+#define CKM_NSS_CHACHA20_POLY1305               (CKM_NSS + 25)
++#define CKM_NSS_CHACHA20_POLY1305               (CKM_NSS + 26)
 +
-+typedef struct CK_AEAD_PARAMS {
-+  CK_BYTE_PTR  pIv;  /* This is the nonce. */
-+  CK_ULONG     ulIvLen;
-+  CK_BYTE_PTR  pAAD;
-+  CK_ULONG     ulAADLen;
-+  CK_ULONG     ulTagBits;
-+} CK_AEAD_PARAMS;
++typedef struct CK_NSS_AEAD_PARAMS {
++    CK_BYTE_PTR  pIv;  /* This is the nonce. */
++    CK_ULONG     ulIvLen;
++    CK_BYTE_PTR  pAAD;
++    CK_ULONG     ulAADLen;
++    CK_ULONG     ulTagLen;
++} CK_NSS_AEAD_PARAMS;
 +
 +#endif
 +
@@ -77,18 +77,18 @@
 +    SECItem            param;
 +    SECStatus          rv = SECFailure;
 +    unsigned int       uOutLen;
-+    CK_AEAD_PARAMS     aeadParams;
++    CK_NSS_AEAD_PARAMS aeadParams;
 +    static const int   tagSize = 16;
 +
 +    param.type = siBuffer;
 +    param.len = sizeof(aeadParams);
 +    param.data = (unsigned char *) &aeadParams;
-+    memset(&aeadParams, 0, sizeof(CK_AEAD_PARAMS));
++    memset(&aeadParams, 0, sizeof(aeadParams));
 +    aeadParams.pIv = (unsigned char *) additionalData;
 +    aeadParams.ulIvLen = 8;
 +    aeadParams.pAAD = (unsigned char *) additionalData;
 +    aeadParams.ulAADLen = additionalDataLen;
-+    aeadParams.ulTagBits = tagSize * 8;
++    aeadParams.ulTagLen = tagSize;
 +
 +    if (doDecrypt) {
 +	rv = pk11_decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, &param,
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index 7b93a63..8395f61 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -43,15 +43,15 @@
 /* This is a bodge to allow this code to be compiled against older NSS
  * headers. */
 #ifndef CKM_NSS_CHACHA20_POLY1305
-#define CKM_NSS_CHACHA20_POLY1305               (CKM_NSS + 25)
+#define CKM_NSS_CHACHA20_POLY1305               (CKM_NSS + 26)
 
-typedef struct CK_AEAD_PARAMS {
-  CK_BYTE_PTR  pIv;  /* This is the nonce. */
-  CK_ULONG     ulIvLen;
-  CK_BYTE_PTR  pAAD;
-  CK_ULONG     ulAADLen;
-  CK_ULONG     ulTagBits;
-} CK_AEAD_PARAMS;
+typedef struct CK_NSS_AEAD_PARAMS {
+    CK_BYTE_PTR  pIv;  /* This is the nonce. */
+    CK_ULONG     ulIvLen;
+    CK_BYTE_PTR  pAAD;
+    CK_ULONG     ulAADLen;
+    CK_ULONG     ulTagLen;
+} CK_NSS_AEAD_PARAMS;
 
 #endif
 
@@ -2064,18 +2064,18 @@
     SECItem            param;
     SECStatus          rv = SECFailure;
     unsigned int       uOutLen;
-    CK_AEAD_PARAMS     aeadParams;
+    CK_NSS_AEAD_PARAMS aeadParams;
     static const int   tagSize = 16;
 
     param.type = siBuffer;
     param.len = sizeof(aeadParams);
     param.data = (unsigned char *) &aeadParams;
-    memset(&aeadParams, 0, sizeof(CK_AEAD_PARAMS));
+    memset(&aeadParams, 0, sizeof(aeadParams));
     aeadParams.pIv = (unsigned char *) additionalData;
     aeadParams.ulIvLen = 8;
     aeadParams.pAAD = (unsigned char *) additionalData;
     aeadParams.ulAADLen = additionalDataLen;
-    aeadParams.ulTagBits = tagSize * 8;
+    aeadParams.ulTagLen = tagSize;
 
     if (doDecrypt) {
 	rv = pk11_decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, &param,
diff --git a/net/tools/get_server_time/get_server_time.cc b/net/tools/get_server_time/get_server_time.cc
index 3fe6129..19a2010 100644
--- a/net/tools/get_server_time/get_server_time.cc
+++ b/net/tools/get_server_time/get_server_time.cc
@@ -83,17 +83,6 @@
     NOTREACHED();
   }
 
-  virtual void OnURLFetchDownloadData(
-      const net::URLFetcher* source,
-      scoped_ptr<std::string> download_data) OVERRIDE{
-    NOTREACHED();
-  }
-
-  virtual bool ShouldSendDownloadData() OVERRIDE {
-    NOTREACHED();
-    return false;
-  }
-
   virtual void OnURLFetchUploadProgress(const net::URLFetcher* source,
                                         int64 current, int64 total) OVERRIDE {
     NOTREACHED();
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index f453c60..b0a963f 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 #include <string>
+#include <vector>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
@@ -17,15 +18,18 @@
 #include "net/quic/quic_protocol.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_test_writer.h"
 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
 #include "net/tools/quic/quic_epoll_connection_helper.h"
 #include "net/tools/quic/quic_in_memory_cache.h"
 #include "net/tools/quic/quic_server.h"
 #include "net/tools/quic/quic_socket_utils.h"
 #include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/packet_dropping_test_writer.h"
 #include "net/tools/quic/test_tools/quic_client_peer.h"
-#include "net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h"
+#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
 #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
+#include "net/tools/quic/test_tools/quic_server_peer.h"
 #include "net/tools/quic/test_tools/quic_test_client.h"
 #include "net/tools/quic/test_tools/server_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -34,8 +38,13 @@
 using base::WaitableEvent;
 using net::test::QuicConnectionPeer;
 using net::test::QuicSessionPeer;
+using net::test::QuicTestWriter;
 using net::test::ReliableQuicStreamPeer;
+using net::tools::test::PacketDroppingTestWriter;
+using net::tools::test::QuicDispatcherPeer;
+using net::tools::test::QuicServerPeer;
 using std::string;
+using std::vector;
 
 namespace net {
 namespace tools {
@@ -58,7 +67,73 @@
   }
 }
 
-class EndToEndTest : public ::testing::TestWithParam<QuicVersion> {
+// Run all tests with the cross products of all versions
+// and all values of FLAGS_pad_quic_handshake_packets.
+struct TestParams {
+  TestParams(const QuicVersionVector& client_supported_versions,
+             const QuicVersionVector& server_supported_versions,
+             QuicVersion negotiated_version,
+             bool use_padding)
+      : client_supported_versions(client_supported_versions),
+        server_supported_versions(server_supported_versions),
+        negotiated_version(negotiated_version),
+        use_padding(use_padding) {
+  }
+
+  QuicVersionVector client_supported_versions;
+  QuicVersionVector server_supported_versions;
+  QuicVersion negotiated_version;
+  bool use_padding;
+};
+
+// Constructs various test permutations.
+vector<TestParams> GetTestParams() {
+  vector<TestParams> params;
+  QuicVersionVector all_supported_versions = QuicSupportedVersions();
+
+  // Add an entry for server and client supporting all versions.
+  params.push_back(TestParams(all_supported_versions, all_supported_versions,
+                              all_supported_versions[0], true));
+  params.push_back(TestParams(all_supported_versions, all_supported_versions,
+                              all_supported_versions[0], false));
+
+  // Test client supporting 1 version and server supporting all versions.
+  // Simulate an old client and exercise version downgrade in the server.
+  // No protocol negotiation should occur. Skip the i = 0 case because it
+  // is essentially the same as the default case.
+  for (size_t i = 1; i < all_supported_versions.size(); ++i) {
+    QuicVersionVector client_supported_versions;
+    client_supported_versions.push_back(all_supported_versions[i]);
+    params.push_back(TestParams(client_supported_versions,
+                                all_supported_versions,
+                                client_supported_versions[0],
+                                true));
+    params.push_back(TestParams(client_supported_versions,
+                                all_supported_versions,
+                                client_supported_versions[0],
+                                false));
+  }
+
+  // Test client supporting all versions and server supporting 1 version.
+  // Simulate an old server and exercise version downgrade in the client.
+  // Protocol negotiation should occur. Skip the i = 0 case because it is
+  // essentially the same as the default case.
+  for (size_t i = 1; i < all_supported_versions.size(); ++i) {
+    QuicVersionVector server_supported_versions;
+    server_supported_versions.push_back(all_supported_versions[i]);
+    params.push_back(TestParams(all_supported_versions,
+                                server_supported_versions,
+                                server_supported_versions[0],
+                                true));
+    params.push_back(TestParams(all_supported_versions,
+                                server_supported_versions,
+                                server_supported_versions[0],
+                                false));
+  }
+  return params;
+}
+
+class EndToEndTest : public ::testing::TestWithParam<TestParams> {
  protected:
   EndToEndTest()
       : server_hostname_("example.com"),
@@ -67,7 +142,6 @@
     net::IPAddressNumber ip;
     CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip));
     server_address_ = IPEndPoint(ip, 0);
-    QuicConnection::g_acks_do_not_instigate_acks = true;
     FLAGS_track_retransmission_history = true;
     client_config_.SetDefaults();
     server_config_.SetDefaults();
@@ -78,19 +152,33 @@
                "HTTP/1.1", "200", "OK", kFooResponseBody);
     AddToCache("GET", "https://www.google.com/bar",
                "HTTP/1.1", "200", "OK", kBarResponseBody);
-    version_ = GetParam();
+
+    client_supported_versions_ = GetParam().client_supported_versions;
+    server_supported_versions_ = GetParam().server_supported_versions;
+    negotiated_version_ = GetParam().negotiated_version;
+    FLAGS_pad_quic_handshake_packets = GetParam().use_padding;
+    LOG(INFO) << "server running " << QuicVersionVectorToString(
+        server_supported_versions_);
+    LOG(INFO) << "client running " << QuicVersionVectorToString(
+        client_supported_versions_);
+    LOG(INFO) << "negotiated_version_ " << QuicVersionToString(
+        negotiated_version_);
+    LOG(INFO) << "use_padding " << GetParam().use_padding;
   }
 
   virtual ~EndToEndTest() {
+    // TODO(rtenneti): port RecycleUnusedPort if needed.
+    // RecycleUnusedPort(server_address_.port());
     QuicInMemoryCachePeer::ResetForTests();
   }
 
-  virtual QuicTestClient* CreateQuicClient() {
+  virtual QuicTestClient* CreateQuicClient(QuicTestWriter* writer) {
     QuicTestClient* client = new QuicTestClient(server_address_,
                                                 server_hostname_,
                                                 false,  // not secure
                                                 client_config_,
-                                                version_);
+                                                client_supported_versions_);
+    client->UseWriter(writer);
     client->Connect();
     return client;
   }
@@ -99,21 +187,39 @@
     // Start the server first, because CreateQuicClient() attempts
     // to connect to the server.
     StartServer();
-    client_.reset(CreateQuicClient());
+    client_.reset(CreateQuicClient(client_writer_));
+    QuicEpollConnectionHelper* helper =
+        reinterpret_cast<QuicEpollConnectionHelper*>(
+            QuicConnectionPeer::GetHelper(
+                client_->client()->session()->connection()));
+    client_writer_->SetConnectionHelper(helper);
     return client_->client()->connected();
   }
 
+  virtual void SetUp() {
+    // The ownership of these gets transferred to the QuicTestWriter and
+    // QuicDispatcher when Initialize() is executed.
+    client_writer_ = new PacketDroppingTestWriter();
+    server_writer_ = new PacketDroppingTestWriter();
+  }
+
   virtual void TearDown() {
     StopServer();
   }
 
   void StartServer() {
     server_thread_.reset(new ServerThread(server_address_, server_config_,
+                                          server_supported_versions_,
                                           strike_register_no_startup_period_));
     server_thread_->Start();
     server_thread_->listening()->Wait();
     server_address_ = IPEndPoint(server_address_.address(),
                                  server_thread_->GetPort());
+    QuicDispatcher* dispatcher =
+        QuicServerPeer::GetDispatcher(server_thread_->server());
+    server_writer_->SetConnectionHelper(
+        QuicDispatcherPeer::GetHelper(dispatcher));
+    QuicDispatcherPeer::UseWriter(dispatcher, server_writer_);
     server_started_ = true;
   }
 
@@ -136,21 +242,46 @@
         method, path, version, response_code, response_detail, body);
   }
 
+  void SetPacketLossPercentage(int32 loss) {
+    // TODO(rtenneti): enable when we can do random packet loss tests in
+    // chrome's tree.
+    // client_writer_->set_fake_packet_loss_percentage(loss);
+    // server_writer_->set_fake_packet_loss_percentage(loss);
+  }
+
+  void SetPacketSendDelay(QuicTime::Delta delay) {
+    // TODO(rtenneti): enable when we can do random packet send delay tests in
+    // chrome's tree.
+    // client_writer_->set_fake_packet_delay(delay);
+    // server_writer_->set_fake_packet_delay(delay);
+  }
+
+  void SetReorderPercentage(int32 reorder) {
+    // TODO(rtenneti): enable when we can do random packet reorder tests in
+    // chrome's tree.
+    // client_writer_->set_fake_reorder_percentage(reorder);
+    // server_writer_->set_fake_reorder_percentage(reorder);
+  }
+
   IPEndPoint server_address_;
   string server_hostname_;
   scoped_ptr<ServerThread> server_thread_;
   scoped_ptr<QuicTestClient> client_;
+  PacketDroppingTestWriter* client_writer_;
+  PacketDroppingTestWriter* server_writer_;
   bool server_started_;
   QuicConfig client_config_;
   QuicConfig server_config_;
-  QuicVersion version_;
+  QuicVersionVector client_supported_versions_;
+  QuicVersionVector server_supported_versions_;
+  QuicVersion negotiated_version_;
   bool strike_register_no_startup_period_;
 };
 
 // Run all end to end tests with all supported versions.
 INSTANTIATE_TEST_CASE_P(EndToEndTests,
                         EndToEndTest,
-                        ::testing::ValuesIn(kSupportedQuicVersions));
+                        ::testing::ValuesIn(GetTestParams()));
 
 TEST_P(EndToEndTest, SimpleRequestResponse) {
   ASSERT_TRUE(Initialize());
@@ -206,7 +337,7 @@
 
 TEST_P(EndToEndTest, MultipleClients) {
   ASSERT_TRUE(Initialize());
-  scoped_ptr<QuicTestClient> client2(CreateQuicClient());
+  scoped_ptr<QuicTestClient> client2(CreateQuicClient(NULL));
 
   HTTPMessage request(HttpConstants::HTTP_1_1,
                       HttpConstants::POST, "/foo");
@@ -238,13 +369,12 @@
   const size_t kStreamDataLength = 3;
   const QuicStreamId kStreamId = 1u;
   const QuicStreamOffset kStreamOffset = 0u;
-  size_t stream_payload_size =
-      QuicFramer::GetMinStreamFrameSize(
-          GetParam(), kStreamId, kStreamOffset, true) + kStreamDataLength;
+  size_t stream_payload_size = QuicFramer::GetMinStreamFrameSize(
+      negotiated_version_, kStreamId, kStreamOffset, true) + kStreamDataLength;
   size_t min_payload_size =
       std::max(kCongestionFeedbackFrameSize, stream_payload_size);
   size_t ciphertext_size =
-      NullEncrypter(GetParam()).GetCiphertextSize(min_payload_size);
+      NullEncrypter(false).GetCiphertextSize(min_payload_size);
   // TODO(satyashekhar): Fix this when versioning is implemented.
   client_->options()->max_packet_length =
       GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
@@ -259,6 +389,8 @@
 
 TEST_P(EndToEndTest, MultipleFramesRandomOrder) {
   ASSERT_TRUE(Initialize());
+  SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
+  SetReorderPercentage(50);
   // Set things up so we have a small payload, to guarantee fragmentation.
   // A congestion feedback frame can't be split into multiple packets, make sure
   // that our packet have room for at least this amount after the normal headers
@@ -268,19 +400,17 @@
   const size_t kStreamDataLength = 3;
   const QuicStreamId kStreamId = 1u;
   const QuicStreamOffset kStreamOffset = 0u;
-  size_t stream_payload_size =
-      QuicFramer::GetMinStreamFrameSize(
-          GetParam(), kStreamId, kStreamOffset, true) + kStreamDataLength;
+  size_t stream_payload_size = QuicFramer::GetMinStreamFrameSize(
+      negotiated_version_, kStreamId, kStreamOffset, true) + kStreamDataLength;
   size_t min_payload_size =
       std::max(kCongestionFeedbackFrameSize, stream_payload_size);
   size_t ciphertext_size =
-      NullEncrypter(GetParam()).GetCiphertextSize(min_payload_size);
+      NullEncrypter(false).GetCiphertextSize(min_payload_size);
   // TODO(satyashekhar): Fix this when versioning is implemented.
   client_->options()->max_packet_length =
       GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                           PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP) +
       ciphertext_size;
-  client_->options()->random_reorder = true;
 
   // Make sure our request is too large to fit in one packet.
   EXPECT_GT(strlen(kLargeRequest), min_payload_size);
@@ -323,12 +453,12 @@
 TEST_P(EndToEndTest, LargePostWithPacketLoss) {
   // Connect with lower fake packet loss than we'd like to test.  Until
   // b/10126687 is fixed, losing handshake packets is pretty brutal.
-  // FLAGS_fake_packet_loss_percentage = 5;
+  SetPacketLossPercentage(5);
   ASSERT_TRUE(Initialize());
 
   // Wait for the server SHLO before upping the packet loss.
   client_->client()->WaitForCryptoHandshakeConfirmed();
-  // FLAGS_fake_packet_loss_percentage = 30;
+  SetPacketLossPercentage(30);
 
   // 10 Kb body.
   string body;
@@ -341,7 +471,50 @@
   EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
 }
 
-TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
+TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
+  ASSERT_TRUE(Initialize());
+
+  client_->client()->WaitForCryptoHandshakeConfirmed();
+  // Both of these must be called when the writer is not actively used.
+  SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
+  SetReorderPercentage(30);
+
+  // 1 Mb body.
+  string body;
+  GenerateBody(&body, 1024 * 1024);
+
+  HTTPMessage request(HttpConstants::HTTP_1_1,
+                      HttpConstants::POST, "/foo");
+  request.AddBody(body, true);
+
+  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+}
+
+TEST_P(EndToEndTest, LargePostWithPacketLossAndBlocketSocket) {
+  // Connect with lower fake packet loss than we'd like to test.  Until
+  // b/10126687 is fixed, losing handshake packets is pretty brutal.
+  SetPacketLossPercentage(5);
+  ASSERT_TRUE(Initialize());
+
+  // Wait for the server SHLO before upping the packet loss.
+  client_->client()->WaitForCryptoHandshakeConfirmed();
+  SetPacketLossPercentage(30);
+  client_writer_->set_fake_blocked_socket_percentage(10);
+
+  // 10 Kb body.
+  string body;
+  GenerateBody(&body, 1024 * 10);
+
+  HTTPMessage request(HttpConstants::HTTP_1_1,
+                      HttpConstants::POST, "/foo");
+  request.AddBody(body, true);
+
+  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+}
+
+// TODO(rtenneti): rch is investigating the root cause. Will enable after we
+// find the bug.
+TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
   // Have the server accept 0-RTT without waiting a startup period.
   strike_register_no_startup_period_ = true;
 
@@ -371,6 +544,7 @@
 
   // Restart the server so that the 0-RTT handshake will take 1 RTT.
   StopServer();
+  server_writer_ = new PacketDroppingTestWriter();
   StartServer();
 
   client_->Connect();
@@ -381,7 +555,7 @@
 
 // TODO(ianswett): Enable once b/9295090 is fixed.
 TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
-  // FLAGS_fake_packet_loss_percentage = 30;
+  SetPacketLossPercentage(30);
   ASSERT_TRUE(Initialize());
   client_->options()->max_packets_per_fec_group = 6;
 
@@ -399,6 +573,13 @@
   FLAGS_quic_allow_oversized_packets_for_test = true;
   ASSERT_TRUE(Initialize());
 
+  // If we use packet padding, then the CHLO is padded to such a large
+  // size that it is rejected by the server before the handshake can complete
+  // which results in a test timeout.
+  if (FLAGS_pad_quic_handshake_packets) {
+    return;
+  }
+
   string body;
   GenerateBody(&body, kMaxPacketSize);
 
@@ -507,7 +688,7 @@
 }
 
 TEST_P(EndToEndTest, MaxStreamsUberTest) {
-  // FLAGS_fake_packet_loss_percentage = 1;
+  SetPacketLossPercentage(1);
   ASSERT_TRUE(Initialize());
   string large_body;
   GenerateBody(&large_body, 10240);
@@ -516,7 +697,7 @@
   AddToCache("GET", "/large_response", "HTTP/1.1", "200", "OK", large_body);;
 
   client_->client()->WaitForCryptoHandshakeConfirmed();
-  // FLAGS_fake_packet_loss_percentage = 10;
+  SetPacketLossPercentage(10);
 
   for (int i = 0; i < max_streams; ++i) {
     EXPECT_LT(0, client_->SendRequest("/large_response"));
@@ -528,9 +709,9 @@
   }
 }
 
-class WrongAddressWriter : public QuicPacketWriter {
+class WrongAddressWriter : public QuicTestWriter {
  public:
-  explicit WrongAddressWriter(int fd) : fd_(fd) {
+  WrongAddressWriter() {
     IPAddressNumber ip;
     CHECK(net::ParseIPLiteralToNumber("127.0.0.2", &ip));
     self_address_ = IPEndPoint(ip, 0);
@@ -541,12 +722,15 @@
       const IPAddressNumber& real_self_address,
       const IPEndPoint& peer_address,
       QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
-    return QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
-                                        self_address_.address(), peer_address);
+    return writer()->WritePacket(buffer, buf_len, self_address_.address(),
+                                 peer_address, blocked_writer);
+  }
+
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
+    return false;
   }
 
   IPEndPoint self_address_;
-  int fd_;
 };
 
 TEST_P(EndToEndTest, ConnectionMigration) {
@@ -555,15 +739,15 @@
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
 
-  WrongAddressWriter writer(QuicClientPeer::GetFd(client_->client()));
-  QuicEpollConnectionHelper* helper =
-      reinterpret_cast<QuicEpollConnectionHelper*>(
-          QuicConnectionPeer::GetHelper(
-              client_->client()->session()->connection()));
-  QuicEpollConnectionHelperPeer::SetWriter(helper, &writer);
+  scoped_ptr<WrongAddressWriter> writer(new WrongAddressWriter());
+
+  writer->set_writer(new QuicDefaultPacketWriter(
+      QuicClientPeer::GetFd(client_->client())));
+  QuicConnectionPeer::SetWriter(
+      client_->client()->session()->connection(),
+      reinterpret_cast<QuicTestWriter*>(writer.get()));
 
   client_->SendSynchronousRequest("/bar");
-  QuicEpollConnectionHelperPeer::SetWriter(helper, NULL);
 
   EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
   EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS, client_->connection_error());
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 68cdf00..b1fa935 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -32,16 +32,17 @@
 
 QuicClient::QuicClient(IPEndPoint server_address,
                        const string& server_hostname,
-                       const QuicVersion version,
+                       const QuicVersionVector& supported_versions,
                        bool print_response)
     : server_address_(server_address),
       server_hostname_(server_hostname),
       local_port_(0),
       fd_(-1),
+      helper_(CreateQuicConnectionHelper()),
       initialized_(false),
       packets_dropped_(0),
       overflow_supported_(false),
-      version_(version),
+      supported_versions_(supported_versions),
       print_response_(print_response) {
   config_.SetDefaults();
 }
@@ -49,16 +50,17 @@
 QuicClient::QuicClient(IPEndPoint server_address,
                        const string& server_hostname,
                        const QuicConfig& config,
-                       const QuicVersion version)
+                       const QuicVersionVector& supported_versions)
     : server_address_(server_address),
       server_hostname_(server_hostname),
       config_(config),
       local_port_(0),
       fd_(-1),
+      helper_(CreateQuicConnectionHelper()),
       initialized_(false),
       packets_dropped_(0),
       overflow_supported_(false),
-      version_(version),
+      supported_versions_(supported_versions),
       print_response_(false) {
 }
 
@@ -153,13 +155,16 @@
 bool QuicClient::StartConnect() {
   DCHECK(!connected() && initialized_);
 
-  QuicGuid guid = QuicRandom::GetInstance()->RandUint64();
+  QuicPacketWriter* writer = CreateQuicPacketWriter();
+  if (writer_.get() != writer) {
+    writer_.reset(writer);
+  }
+
   session_.reset(new QuicClientSession(
       server_hostname_,
       config_,
-      new QuicConnection(guid, server_address_,
-                         CreateQuicConnectionHelper(), false,
-                         version_),
+      new QuicConnection(GenerateGuid(), server_address_, helper_.get(),
+                         writer_.get(), false, supported_versions_),
       &crypto_config_));
   return session_->CryptoConnect();
 }
@@ -268,8 +273,16 @@
       session_->connection()->connected();
 }
 
+QuicGuid QuicClient::GenerateGuid() {
+  return QuicRandom::GetInstance()->RandUint64();
+}
+
 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
-  return new QuicEpollConnectionHelper(fd_, &epoll_server_);
+  return new QuicEpollConnectionHelper(&epoll_server_);
+}
+
+QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
+  return new QuicDefaultPacketWriter(fd_);
 }
 
 bool QuicClient::ReadAndProcessPacket() {
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 8826815..4835f4b 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -39,12 +39,12 @@
  public:
   QuicClient(IPEndPoint server_address,
              const string& server_hostname,
-             const QuicVersion version,
+             const QuicVersionVector& supported_versions,
              bool print_response);
   QuicClient(IPEndPoint server_address,
              const std::string& server_hostname,
              const QuicConfig& config,
-             const QuicVersion version);
+             const QuicVersionVector& supported_versions);
 
   virtual ~QuicClient();
 
@@ -144,7 +144,9 @@
   }
 
  protected:
+  virtual QuicGuid GenerateGuid();
   virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper();
+  virtual QuicPacketWriter* CreateQuicPacketWriter();
 
  private:
   friend class net::tools::test::QuicClientPeer;
@@ -181,6 +183,12 @@
   // UDP socket.
   int fd_;
 
+  // Helper to be used by created connections.
+  scoped_ptr<QuicEpollConnectionHelper> helper_;
+
+  // Writer used to actually send packets to the wire.
+  scoped_ptr<QuicPacketWriter> writer_;
+
   // Tracks if the client is initialized to connect.
   bool initialized_;
 
@@ -193,8 +201,12 @@
   // because the socket would otherwise overflow.
   bool overflow_supported_;
 
-  // Which QUIC version does this client talk?
-  QuicVersion version_;
+  // This vector contains QUIC versions which we currently support.
+  // This should be ordered such that the highest supported version is the first
+  // element, with subsequent elements in descending order (versions can be
+  // skipped as necessary). We will always pick supported_versions_[0] as the
+  // initial version to use.
+  QuicVersionVector supported_versions_;
 
   // If true, then the contents of each response will be printed to stdout
   // when the stream is closed (in OnClose).
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index 5591b87..2f8cfac 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -59,8 +59,9 @@
   net::IPAddressNumber addr;
   CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
   // TODO(rjshade): Set version on command line.
-  net::tools::QuicClient client(net::IPEndPoint(addr, FLAGS_port),
-                                FLAGS_hostname, net::QuicVersionMax(), true);
+  net::tools::QuicClient client(
+      net::IPEndPoint(addr, FLAGS_port), FLAGS_hostname,
+      net::QuicSupportedVersions(), true);
 
   client.Initialize();
 
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 1b1ece6..50201c9 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -13,9 +13,10 @@
 #include "net/tools/quic/quic_reliable_client_stream.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using testing::_;
 using net::test::CryptoTestUtils;
+using net::test::DefaultQuicConfig;
 using net::test::PacketSavingConnection;
+using testing::_;
 
 namespace net {
 namespace tools {
@@ -30,7 +31,7 @@
       : guid_(1),
         connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)) {
     crypto_config_.SetDefaults();
-    session_.reset(new QuicClientSession(kServerHostname, QuicConfig(),
+    session_.reset(new QuicClientSession(kServerHostname, DefaultQuicConfig(),
                                          connection_, &crypto_config_));
     session_->config()->SetDefaults();
   }
@@ -48,19 +49,11 @@
 };
 
 TEST_F(ToolsQuicClientSessionTest, CryptoConnect) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
   CompleteCryptoHandshake();
 }
 
 TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
   session_->config()->set_max_streams_per_connection(1, 1);
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
   // FLAGS_max_streams_per_connection = 1;
   // Initialize crypto before the client session will create a stream.
   CompleteCryptoHandshake();
@@ -77,11 +70,6 @@
 }
 
 TEST_F(ToolsQuicClientSessionTest, GoAwayReceived) {
-  if (!Aes128Gcm12Encrypter::IsSupported()) {
-    LOG(INFO) << "AES GCM not supported. Test skipped.";
-    return;
-  }
-
   CompleteCryptoHandshake();
 
   // After receiving a GoAway, I should no longer be able to create outgoing
diff --git a/net/tools/quic/quic_default_packet_writer.cc b/net/tools/quic/quic_default_packet_writer.cc
new file mode 100644
index 0000000..541d86d
--- /dev/null
+++ b/net/tools/quic/quic_default_packet_writer.cc
@@ -0,0 +1,28 @@
+// Copyright 2013 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 "net/tools/quic/quic_default_packet_writer.h"
+
+#include "net/tools/quic/quic_socket_utils.h"
+
+namespace net {
+namespace tools {
+
+QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd) : fd_(fd) {}
+
+WriteResult QuicDefaultPacketWriter::WritePacket(
+    const char* buffer, size_t buf_len,
+    const net::IPAddressNumber& self_address,
+    const net::IPEndPoint& peer_address,
+    QuicBlockedWriterInterface* blocked_writer) {
+  return QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
+                                      self_address, peer_address);
+}
+
+bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const {
+  return false;
+}
+
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/quic_default_packet_writer.h b/net/tools/quic/quic_default_packet_writer.h
new file mode 100644
index 0000000..fb1dd4d
--- /dev/null
+++ b/net/tools/quic/quic_default_packet_writer.h
@@ -0,0 +1,40 @@
+// Copyright 2013 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 NET_TOOLS_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
+#define NET_TOOLS_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
+
+#include "base/basictypes.h"
+#include "net/base/ip_endpoint.h"
+#include "net/quic/quic_packet_writer.h"
+
+namespace net {
+
+class QuicBlockedWriterInterface;
+struct WriteResult;
+
+namespace tools {
+
+// Default packet writer which wraps QuicSocketUtils WritePacket.
+class QuicDefaultPacketWriter : public QuicPacketWriter {
+ public:
+  explicit QuicDefaultPacketWriter(int fd);
+  virtual ~QuicDefaultPacketWriter() {}
+
+  // QuicPacketWriter
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const net::IPAddressNumber& self_address,
+      const net::IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+
+ private:
+  int fd_;
+};
+
+}  // namespace tools
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_QUIC_DEFAULT_PACKET_WRITER_H_
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index b22b9dc..2e7b9e6 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "net/quic/quic_blocked_writer_interface.h"
 #include "net/quic/quic_utils.h"
+#include "net/tools/quic/quic_default_packet_writer.h"
 #include "net/tools/quic/quic_epoll_connection_helper.h"
 #include "net/tools/quic/quic_socket_utils.h"
 
@@ -36,16 +37,20 @@
 
 QuicDispatcher::QuicDispatcher(const QuicConfig& config,
                                const QuicCryptoServerConfig& crypto_config,
+                               const QuicVersionVector& supported_versions,
                                int fd,
                                EpollServer* epoll_server)
     : config_(config),
       crypto_config_(crypto_config),
       time_wait_list_manager_(
-          new QuicTimeWaitListManager(this, epoll_server)),
+          new QuicTimeWaitListManager(this, epoll_server, supported_versions)),
       delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
       epoll_server_(epoll_server),
       fd_(fd),
-      write_blocked_(false) {
+      write_blocked_(false),
+      helper_(new QuicEpollConnectionHelper(epoll_server_)),
+      writer_(new QuicDefaultPacketWriter(fd)),
+      supported_versions_(supported_versions) {
 }
 
 QuicDispatcher::~QuicDispatcher() {
@@ -53,17 +58,22 @@
   STLDeleteElements(&closed_session_list_);
 }
 
-WriteResult  QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
-                                         const IPAddressNumber& self_address,
-                                         const IPEndPoint& peer_address,
-                                         QuicBlockedWriterInterface* writer) {
+void QuicDispatcher::set_fd(int fd) {
+  fd_ = fd;
+  writer_.reset(new QuicDefaultPacketWriter(fd));
+}
+
+WriteResult QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
+                                        const IPAddressNumber& self_address,
+                                        const IPEndPoint& peer_address,
+                                        QuicBlockedWriterInterface* writer) {
   if (write_blocked_) {
     write_blocked_list_.insert(make_pair(writer, true));
     return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
   }
 
-  WriteResult result = QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
-                                                    self_address, peer_address);
+  WriteResult result =
+      writer_->WritePacket(buffer, buf_len, self_address, peer_address, writer);
   if (result.status == WRITE_STATUS_BLOCKED) {
     write_blocked_list_.insert(make_pair(writer, true));
     write_blocked_ = true;
@@ -71,6 +81,10 @@
   return result;
 }
 
+bool QuicDispatcher::IsWriteBlockedDataBuffered() const {
+  return writer_->IsWriteBlockedDataBuffered();
+}
+
 void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
                                    const IPEndPoint& client_address,
                                    QuicGuid guid,
@@ -86,13 +100,14 @@
                                              packet);
       return;
     }
-    session = CreateQuicSession(guid, client_address, fd_, epoll_server_);
+    session = CreateQuicSession(guid, client_address);
 
     if (session == NULL) {
       DLOG(INFO) << "Failed to create session for " << guid;
-      // Add this guid fo the time-wait state, to safely nack future packets.
+      // Add this guid fo the time-wait state, to safely reject future packets.
       // We don't know the version here, so assume latest.
-      time_wait_list_manager_->AddGuidToTimeWait(guid, QuicVersionMax());
+      time_wait_list_manager_->AddGuidToTimeWait(guid,
+                                                 supported_versions_.front());
       time_wait_list_manager_->ProcessPacket(server_address,
                                              client_address,
                                              guid,
@@ -121,6 +136,10 @@
   STLDeleteElements(&closed_session_list_);
 }
 
+void QuicDispatcher::UseWriter(QuicPacketWriter* writer) {
+  writer_.reset(writer);
+}
+
 bool QuicDispatcher::OnCanWrite() {
   // We got an EPOLLOUT: the socket should not be blocked.
   write_blocked_ = false;
@@ -161,7 +180,7 @@
   DeleteSessions();
 }
 
-void QuicDispatcher::OnConnectionClose(QuicGuid guid, QuicErrorCode error) {
+void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) {
   SessionMap::iterator it = session_map_.find(guid);
   if (it == session_map_.end()) {
     LOG(DFATAL) << "GUID " << guid << " does not exist in the session map.  "
@@ -183,19 +202,13 @@
 
 QuicSession* QuicDispatcher::CreateQuicSession(
     QuicGuid guid,
-    const IPEndPoint& client_address,
-    int fd,
-    EpollServer* epoll_server) {
-  QuicConnectionHelperInterface* helper =
-      new QuicEpollConnectionHelper(this, epoll_server);
+    const IPEndPoint& client_address) {
   QuicServerSession* session = new QuicServerSession(
-       config_, new QuicConnection(guid, client_address, helper, true,
-                                   QuicVersionMax()), this);
+      config_, new QuicConnection(guid, client_address, helper_.get(), this,
+                                  true, supported_versions_), this);
   session->InitializeSession(crypto_config_);
   return session;
 }
 
 }  // namespace tools
 }  // namespace net
-
-
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 584965c..280f8b2 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -11,12 +11,13 @@
 #include <list>
 
 #include "base/containers/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/linked_hash_map.h"
 #include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/tools/epoll_server/epoll_server.h"
-#include "net/tools/quic/quic_packet_writer.h"
 #include "net/tools/quic/quic_server_session.h"
 #include "net/tools/quic/quic_time_wait_list_manager.h"
 
@@ -46,15 +47,19 @@
 }  // namespace test
 
 class DeleteSessionsAlarm;
+class QuicEpollConnectionHelper;
+
 class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
  public:
   // Ideally we'd have a linked_hash_set: the  boolean is unused.
   typedef linked_hash_map<QuicBlockedWriterInterface*, bool> WriteBlockedList;
 
   // Due to the way delete_sessions_closure_ is registered, the Dispatcher
-  // must live until epoll_server Shutdown.
+  // must live until epoll_server Shutdown. |supported_versions| specifies the
+  // list of supported QUIC versions.
   QuicDispatcher(const QuicConfig& config,
                  const QuicCryptoServerConfig& crypto_config,
+                 const QuicVersionVector& supported_versions,
                  int fd,
                  EpollServer* epoll_server);
   virtual ~QuicDispatcher();
@@ -65,6 +70,7 @@
       const IPAddressNumber& self_address,
       const IPEndPoint& peer_address,
       QuicBlockedWriterInterface* writer) OVERRIDE;
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
 
   virtual void ProcessPacket(const IPEndPoint& server_address,
                              const IPEndPoint& client_address,
@@ -81,23 +87,26 @@
   void Shutdown();
 
   // Ensure that the closed connection is cleaned up asynchronously.
-  virtual void OnConnectionClose(QuicGuid guid, QuicErrorCode error) OVERRIDE;
+  virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) OVERRIDE;
 
-  void set_fd(int fd) { fd_ = fd; }
+  // Sets the fd and creates a default packet writer with that fd.
+  void set_fd(int fd);
 
   typedef base::hash_map<QuicGuid, QuicSession*> SessionMap;
 
   virtual QuicSession* CreateQuicSession(
       QuicGuid guid,
-      const IPEndPoint& client_address,
-      int fd,
-      EpollServer* epoll_server);
+      const IPEndPoint& client_address);
 
   // Deletes all sessions on the closed session list and clears the list.
   void DeleteSessions();
 
   const SessionMap& session_map() const { return session_map_; }
 
+  // Uses the specified |writer| instead of QuicSocketUtils and takes ownership
+  // of writer.
+  void UseWriter(QuicPacketWriter* writer);
+
   WriteBlockedList* write_blocked_list() { return &write_blocked_list_; }
 
  protected:
@@ -108,6 +117,13 @@
     return time_wait_list_manager_.get();
   }
 
+  QuicEpollConnectionHelper* helper() { return helper_.get(); }
+  EpollServer* epoll_server() { return epoll_server_; }
+
+  const QuicVersionVector& supported_versions() const {
+    return supported_versions_;
+  }
+
  private:
   friend class net::tools::test::QuicDispatcherPeer;
 
@@ -138,6 +154,18 @@
   // False if we have gotten a call to OnCanWrite after the last failed write.
   bool write_blocked_;
 
+  // The helper used for all connections.
+  scoped_ptr<QuicEpollConnectionHelper> helper_;
+
+  // The writer to write to the socket with.
+  scoped_ptr<QuicPacketWriter> writer_;
+
+  // This vector contains QUIC versions which we currently support.
+  // This should be ordered such that the highest supported version is the first
+  // element, with subsequent elements in descending order (versions can be
+  // skipped as necessary).
+  const QuicVersionVector supported_versions_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
 };
 
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 2f105e1..90b3074 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -14,6 +14,7 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/tools/epoll_server/epoll_server.h"
 #include "net/tools/quic/quic_time_wait_list_manager.h"
+#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
 #include "net/tools/quic/test_tools/quic_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,19 +34,6 @@
 namespace net {
 namespace tools {
 namespace test {
-class QuicDispatcherPeer {
- public:
-  static void SetTimeWaitListManager(
-      QuicDispatcher* dispatcher,
-      QuicTimeWaitListManager* time_wait_list_manager) {
-    dispatcher->time_wait_list_manager_.reset(time_wait_list_manager);
-  }
-
-  static void SetWriteBlocked(QuicDispatcher* dispatcher) {
-    dispatcher->write_blocked_ = true;
-  }
-};
-
 namespace {
 
 class TestDispatcher : public QuicDispatcher {
@@ -53,13 +41,12 @@
   explicit TestDispatcher(const QuicConfig& config,
                           const QuicCryptoServerConfig& crypto_config,
                           EpollServer* eps)
-      : QuicDispatcher(config, crypto_config, 1, eps) {}
+      : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), 1, eps) {
+  }
 
-  MOCK_METHOD4(CreateQuicSession, QuicSession*(
+  MOCK_METHOD2(CreateQuicSession, QuicSession*(
       QuicGuid guid,
-      const IPEndPoint& client_address,
-      int fd,
-      EpollServer* eps));
+      const IPEndPoint& client_address));
   using QuicDispatcher::write_blocked_list;
 };
 
@@ -77,9 +64,9 @@
       : MockConnection(guid, address, fd, eps, true),
         dispatcher_(dispatcher) {
   }
-  void UnregisterOnConnectionClose() {
+  void UnregisterOnConnectionClosed() {
     LOG(ERROR) << "Unregistering " << guid();
-    dispatcher_->OnConnectionClose(guid(), QUIC_NO_ERROR);
+    dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR);
   }
  private:
   QuicDispatcher* dispatcher_;
@@ -95,7 +82,7 @@
   *session = new MockSession(connection, true);
   ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
       WithoutArgs(Invoke(
-          connection, &MockServerConnection::UnregisterOnConnectionClose)));
+          connection, &MockServerConnection::UnregisterOnConnectionClosed)));
   EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()),
               ProcessUdpPacket(_, addr, _));
 
@@ -151,12 +138,12 @@
 TEST_F(QuicDispatcherTest, ProcessPackets) {
   IPEndPoint addr(Loopback4(), 1);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(1, addr, _, &eps_))
+  EXPECT_CALL(dispatcher_, CreateQuicSession(1, addr))
       .WillOnce(testing::Return(CreateSession(
           &dispatcher_, 1, addr, &session1_, &eps_)));
   ProcessPacket(addr, 1, "foo");
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(2, addr, _, &eps_))
+  EXPECT_CALL(dispatcher_, CreateQuicSession(2, addr))
       .WillOnce(testing::Return(CreateSession(
                     &dispatcher_, 2, addr, &session2_, &eps_)));
   ProcessPacket(addr, 2, "bar");
@@ -172,7 +159,7 @@
 TEST_F(QuicDispatcherTest, Shutdown) {
   IPEndPoint addr(Loopback4(), 1);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_))
+  EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr))
       .WillOnce(testing::Return(CreateSession(
                     &dispatcher_, 1, addr, &session1_, &eps_)));
 
@@ -188,7 +175,7 @@
  public:
   MockTimeWaitListManager(QuicPacketWriter* writer,
                           EpollServer* eps)
-      : QuicTimeWaitListManager(writer, eps) {
+      : QuicTimeWaitListManager(writer, eps, QuicSupportedVersions()) {
   }
 
   MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
@@ -199,14 +186,15 @@
 
 TEST_F(QuicDispatcherTest, TimeWaitListManager) {
   MockTimeWaitListManager* time_wait_list_manager =
-      new MockTimeWaitListManager(&dispatcher_, &eps_);
+      new MockTimeWaitListManager(
+          QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
   // dispatcher takes the ownership of time_wait_list_manager.
   QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
                                              time_wait_list_manager);
   // Create a new session.
   IPEndPoint addr(Loopback4(), 1);
   QuicGuid guid = 1;
-  EXPECT_CALL(dispatcher_, CreateQuicSession(guid, addr, _, &eps_))
+  EXPECT_CALL(dispatcher_, CreateQuicSession(guid, addr))
       .WillOnce(testing::Return(CreateSession(
                     &dispatcher_, guid, addr, &session1_, &eps_)));
   ProcessPacket(addr, guid, "foo");
@@ -220,10 +208,10 @@
   packet.nonce_proof = 132232;
   scoped_ptr<QuicEncryptedPacket> encrypted(
       QuicFramer::BuildPublicResetPacket(packet));
-  EXPECT_CALL(*session1_, ConnectionClose(QUIC_PUBLIC_RESET, true)).Times(1)
+  EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, true)).Times(1)
       .WillOnce(WithoutArgs(Invoke(
           reinterpret_cast<MockServerConnection*>(session1_->connection()),
-          &MockServerConnection::UnregisterOnConnectionClose)));
+          &MockServerConnection::UnregisterOnConnectionClosed)));
   EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
               ProcessUdpPacket(_, _, _))
       .WillOnce(Invoke(
@@ -243,12 +231,12 @@
   virtual void SetUp() {
     IPEndPoint addr(Loopback4(), 1);
 
-    EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_))
+    EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr))
         .WillOnce(testing::Return(CreateSession(
                       &dispatcher_, 1, addr, &session1_, &eps_)));
     ProcessPacket(addr, 1, "foo");
 
-    EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_))
+    EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr))
         .WillOnce(testing::Return(CreateSession(
                       &dispatcher_, 2, addr, &session2_, &eps_)));
     ProcessPacket(addr, 2, "bar");
diff --git a/net/tools/quic/quic_epoll_connection_helper.cc b/net/tools/quic/quic_epoll_connection_helper.cc
index b7158db..78bfe97 100644
--- a/net/tools/quic/quic_epoll_connection_helper.cc
+++ b/net/tools/quic/quic_epoll_connection_helper.cc
@@ -62,22 +62,8 @@
 
 }  // namespace
 
-QuicEpollConnectionHelper::QuicEpollConnectionHelper(
-  int fd, EpollServer* epoll_server)
-    : writer_(NULL),
-      epoll_server_(epoll_server),
-      fd_(fd),
-      connection_(NULL),
-      clock_(epoll_server),
-      random_generator_(QuicRandom::GetInstance()) {
-}
-
-QuicEpollConnectionHelper::QuicEpollConnectionHelper(QuicPacketWriter* writer,
-                                                     EpollServer* epoll_server)
-    : writer_(writer),
-      epoll_server_(epoll_server),
-      fd_(-1),
-      connection_(NULL),
+QuicEpollConnectionHelper::QuicEpollConnectionHelper(EpollServer* epoll_server)
+    : epoll_server_(epoll_server),
       clock_(epoll_server),
       random_generator_(QuicRandom::GetInstance()) {
 }
@@ -85,11 +71,6 @@
 QuicEpollConnectionHelper::~QuicEpollConnectionHelper() {
 }
 
-void QuicEpollConnectionHelper::SetConnection(QuicConnection* connection) {
-  DCHECK(!connection_);
-  connection_ = connection;
-}
-
 const QuicClock* QuicEpollConnectionHelper::GetClock() const {
   return &clock_;
 }
@@ -98,31 +79,6 @@
   return random_generator_;
 }
 
-WriteResult QuicEpollConnectionHelper::WritePacketToWire(
-    const QuicEncryptedPacket& packet) {
-  if (connection_->ShouldSimulateLostPacket()) {
-    DLOG(INFO) << "Dropping packet due to fake packet loss.";
-    return WriteResult(WRITE_STATUS_OK, packet.length());
-  }
-
-  // If we have a writer, delgate the write to it.
-  if (writer_) {
-    return writer_->WritePacket(packet.data(), packet.length(),
-                                connection_->self_address().address(),
-                                connection_->peer_address(),
-                                connection_);
-  } else {
-    return QuicSocketUtils::WritePacket(
-        fd_, packet.data(), packet.length(),
-        connection_->self_address().address(),
-        connection_->peer_address());
-  }
-}
-
-bool QuicEpollConnectionHelper::IsWriteBlockedDataBuffered() {
-  return false;
-}
-
 QuicAlarm* QuicEpollConnectionHelper::CreateAlarm(
     QuicAlarm::Delegate* delegate) {
   return new QuicEpollAlarm(epoll_server_, delegate);
diff --git a/net/tools/quic/quic_epoll_connection_helper.h b/net/tools/quic/quic_epoll_connection_helper.h
index f0795ad..3198a14 100644
--- a/net/tools/quic/quic_epoll_connection_helper.h
+++ b/net/tools/quic/quic_epoll_connection_helper.h
@@ -12,10 +12,11 @@
 #include <set>
 
 #include "net/quic/quic_connection.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_time.h"
+#include "net/tools/quic/quic_default_packet_writer.h"
 #include "net/tools/quic/quic_epoll_clock.h"
-#include "net/tools/quic/quic_packet_writer.h"
 
 namespace net {
 
@@ -29,36 +30,23 @@
 class SendAlarm;
 class TimeoutAlarm;
 
-namespace test {
-class QuicEpollConnectionHelperPeer;
-}  // namespace test
-
 class QuicEpollConnectionHelper : public QuicConnectionHelperInterface {
  public:
-  QuicEpollConnectionHelper(int fd, EpollServer* eps);
-  QuicEpollConnectionHelper(QuicPacketWriter* writer, EpollServer* eps);
+  explicit QuicEpollConnectionHelper(EpollServer* eps);
   virtual ~QuicEpollConnectionHelper();
 
   // QuicEpollConnectionHelperInterface
-  virtual void SetConnection(QuicConnection* connection) OVERRIDE;
   virtual const QuicClock* GetClock() const OVERRIDE;
   virtual QuicRandom* GetRandomGenerator() OVERRIDE;
-  virtual WriteResult WritePacketToWire(
-      const QuicEncryptedPacket& packet) OVERRIDE;
-  virtual bool IsWriteBlockedDataBuffered() OVERRIDE;
   virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) OVERRIDE;
 
   EpollServer* epoll_server() { return epoll_server_; }
 
  private:
   friend class QuicConnectionPeer;
-  friend class net::tools::test::QuicEpollConnectionHelperPeer;
 
-  QuicPacketWriter* writer_;  // Not owned
   EpollServer* epoll_server_;  // Not owned.
-  int fd_;
 
-  QuicConnection* connection_;
   const QuicEpollClock clock_;
   QuicRandom* random_generator_;
 
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index 0e5cd48..7d09d0b 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -33,23 +33,29 @@
 const char kData[] = "foo";
 const bool kFromPeer = true;
 
-class TestConnectionHelper : public QuicEpollConnectionHelper {
+class TestWriter : public QuicPacketWriter {
  public:
-  TestConnectionHelper(int fd, EpollServer* eps)
-      : QuicEpollConnectionHelper(fd, eps) {
-  }
-
-  virtual WriteResult WritePacketToWire(
-      const QuicEncryptedPacket& packet) OVERRIDE {
-    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), true);
+  // QuicPacketWriter
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const IPAddressNumber& self_address,
+      const IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
+    QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), true);
     FramerVisitorCapturingFrames visitor;
     framer.set_visitor(&visitor);
+    QuicEncryptedPacket packet(buffer, buf_len);
     EXPECT_TRUE(framer.ProcessPacket(packet));
     header_ = *visitor.header();
     return WriteResult(WRITE_STATUS_OK, packet.length());
   }
 
-  QuicPacketHeader* header() { return &header_; }
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
+    return false;
+  }
+
+  // Returns the header from the last packet written.
+  const QuicPacketHeader& header() { return header_; }
 
  private:
   QuicPacketHeader header_;
@@ -59,8 +65,10 @@
  public:
   TestConnection(QuicGuid guid,
                  IPEndPoint address,
-                 TestConnectionHelper* helper)
-      : QuicConnection(guid, address, helper, false, QuicVersionMax()) {
+                 QuicEpollConnectionHelper* helper,
+                 TestWriter* writer)
+      : QuicConnection(guid, address, helper, writer, false,
+                       QuicSupportedVersions()) {
   }
 
   void SendAck() {
@@ -76,10 +84,10 @@
  protected:
   QuicEpollConnectionHelperTest()
       : guid_(42),
-        framer_(QuicVersionMax(), QuicTime::Zero(), false),
+        framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
         send_algorithm_(new testing::StrictMock<MockSendAlgorithm>),
-        helper_(new TestConnectionHelper(0, &epoll_server_)),
-        connection_(guid_, IPEndPoint(), helper_),
+        helper_(&epoll_server_),
+        connection_(guid_, IPEndPoint(), &helper_, &writer_),
         frame_(3, false, 0, kData) {
     connection_.set_visitor(&visitor_);
     connection_.SetSendAlgorithm(send_algorithm_);
@@ -115,7 +123,8 @@
 
   MockEpollServer epoll_server_;
   testing::StrictMock<MockSendAlgorithm>* send_algorithm_;
-  TestConnectionHelper* helper_;
+  QuicEpollConnectionHelper helper_;
+  TestWriter writer_;
   TestConnection connection_;
   testing::StrictMock<MockConnectionVisitor> visitor_;
 
@@ -123,12 +132,11 @@
 };
 
 TEST_F(QuicEpollConnectionHelperTest, DISABLED_TestRTORetransmission) {
-  //FLAGS_fake_packet_loss_percentage = 100;
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
       Return(QuicTime::Delta::Zero()));
   const int64 kDefaultRetransmissionTimeMs = 500;
 
-  const char buffer[] = "foo";
+  char buffer[] = "foo";
   const size_t packet_size =
       QuicPacketCreator::StreamFramePacketOverhead(
           framer_.version(), PACKET_8BYTE_GUID, kIncludeVersion,
@@ -140,15 +148,15 @@
   EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, packet_size));
   EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true));
   EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
-  struct iovec iov = {const_cast<char*>(buffer),
-                      static_cast<size_t>(3)};
-  connection_.SendvStreamData(1, &iov, 1, 0, false);
-  EXPECT_EQ(1u, helper_->header()->packet_sequence_number);
+  IOVector data;
+  data.Append(buffer, 3);
+  connection_.SendStreamData(1, data, 0, false);
+  EXPECT_EQ(1u, writer_.header().packet_sequence_number);
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, 2, packet_size, RTO_RETRANSMISSION, _));
   epoll_server_.AdvanceByAndCallCallbacks(kDefaultRetransmissionTimeMs * 1000);
 
-  EXPECT_EQ(2u, helper_->header()->packet_sequence_number);
+  EXPECT_EQ(2u, writer_.header().packet_sequence_number);
 }
 
 TEST_F(QuicEpollConnectionHelperTest, InitialTimeout) {
@@ -158,7 +166,8 @@
                                              HAS_RETRANSMITTABLE_DATA));
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillOnce(
       Return(QuicTime::Delta::FromMicroseconds(1)));
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
+  EXPECT_CALL(visitor_,
+              OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
   epoll_server_.WaitForEventsAndExecuteCallbacks();
   EXPECT_FALSE(connection_.connected());
   EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000, epoll_server_.NowInUsec());
@@ -184,7 +193,8 @@
   EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000, epoll_server_.NowInUsec());
 
   // This time, we should time out.
-  EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
+  EXPECT_CALL(visitor_,
+              OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, NOT_RETRANSMISSION,
                                              HAS_RETRANSMITTABLE_DATA));
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillOnce(
diff --git a/net/tools/quic/quic_packet_writer.h b/net/tools/quic/quic_packet_writer.h
deleted file mode 100644
index 2d70e09..0000000
--- a/net/tools/quic/quic_packet_writer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2012 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 NET_TOOLS_QUIC_QUIC_PACKET_WRITER_H_
-#define NET_TOOLS_QUIC_QUIC_PACKET_WRITER_H_
-
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class QuicBlockedWriterInterface;
-struct WriteResult;
-
-namespace tools {
-
-// An interface between writers and the entity managing the
-// socket (in our case the QuicDispatcher).  This allows the Dispatcher to
-// control writes, and manage any writers who end up write blocked.
-class QuicPacketWriter {
- public:
-  virtual ~QuicPacketWriter() {}
-
-  virtual WriteResult WritePacket(
-      const char* buffer, size_t buf_len,
-      const net::IPAddressNumber& self_address,
-      const net::IPEndPoint& peer_address,
-      QuicBlockedWriterInterface* blocked_writer) = 0;
-};
-
-}  // namespace tools
-}  // namespace net
-
-#endif  // NET_TOOLS_QUIC_QUIC_PACKET_WRITER_H_
diff --git a/net/tools/quic/quic_reliable_client_stream_test.cc b/net/tools/quic/quic_reliable_client_stream_test.cc
index d004fac..bdb97cc 100644
--- a/net/tools/quic/quic_reliable_client_stream_test.cc
+++ b/net/tools/quic/quic_reliable_client_stream_test.cc
@@ -15,6 +15,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using net::test::DefaultQuicConfig;
 using testing::TestWithParam;
 
 namespace net {
@@ -25,7 +26,7 @@
 class QuicClientStreamTest : public ::testing::Test {
  public:
   QuicClientStreamTest()
-      : session_("example.com", QuicConfig(),
+      : session_("example.com", DefaultQuicConfig(),
                  new MockConnection(1, IPEndPoint(), 0, &eps_, false),
                  &crypto_config_),
         body_("hello world") {
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index a5c1e5b..66a9aa9 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -39,20 +39,23 @@
       packets_dropped_(0),
       overflow_supported_(false),
       use_recvmmsg_(false),
-      crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
+      crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
+      supported_versions_(QuicSupportedVersions()) {
   // Use hardcoded crypto parameters for now.
   config_.SetDefaults();
   Initialize();
 }
 
-QuicServer::QuicServer(const QuicConfig& config)
+QuicServer::QuicServer(const QuicConfig& config,
+                       const QuicVersionVector& supported_versions)
     : port_(0),
       fd_(-1),
       packets_dropped_(0),
       overflow_supported_(false),
       use_recvmmsg_(false),
       config_(config),
-      crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
+      crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
+      supported_versions_(supported_versions) {
   Initialize();
 }
 
@@ -141,8 +144,9 @@
   }
 
   epoll_server_.RegisterFD(fd_, this, kEpollFlags);
-  dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, fd_,
-                                       &epoll_server_));
+  dispatcher_.reset(new QuicDispatcher(config_, crypto_config_,
+                                       supported_versions_,
+                                       fd_, &epoll_server_));
 
   return true;
 }
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index e537c3b..f166555 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -20,12 +20,17 @@
 
 namespace tools {
 
+namespace test {
+class QuicServerPeer;
+}  // namespace test
+
 class QuicDispatcher;
 
 class QuicServer : public EpollCallbackInterface {
  public:
   QuicServer();
-  explicit QuicServer(const QuicConfig& config);
+  QuicServer(const QuicConfig& config,
+             const QuicVersionVector& supported_versions);
 
   virtual ~QuicServer();
 
@@ -76,6 +81,8 @@
   int port() { return port_; }
 
  private:
+  friend class net::tools::test::QuicServerPeer;
+
   // Initialize the internal state of the server.
   void Initialize();
 
@@ -108,6 +115,12 @@
   // crypto_config_ contains crypto parameters for the handshake.
   QuicCryptoServerConfig crypto_config_;
 
+  // This vector contains QUIC versions which we currently support.
+  // This should be ordered such that the highest supported version is the first
+  // element, with subsequent elements in descending order (versions can be
+  // skipped as necessary).
+  QuicVersionVector supported_versions_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicServer);
 };
 
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 7ec991c..bea957c 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -32,9 +32,10 @@
   return new QuicCryptoServerStream(crypto_config, this);
 }
 
-void QuicServerSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
-  QuicSession::ConnectionClose(error, from_peer);
-  owner_->OnConnectionClose(connection()->guid(), error);
+void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
+                                           bool from_peer) {
+  QuicSession::OnConnectionClosed(error, from_peer);
+  owner_->OnConnectionClosed(connection()->guid(), error);
 }
 
 bool QuicServerSession::ShouldCreateIncomingReliableStream(QuicStreamId id) {
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 2f03137..1a5bfa3 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -36,7 +36,7 @@
  public:
   virtual ~QuicSessionOwner() {}
 
-  virtual void OnConnectionClose(QuicGuid guid, QuicErrorCode error) = 0;
+  virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) = 0;
 };
 
 class QuicServerSession : public QuicSession {
@@ -46,7 +46,7 @@
                     QuicSessionOwner* owner);
 
   // Override the base class to notify the owner of the connection close.
-  virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
+  virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
 
   virtual ~QuicServerSession();
 
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 345ddb2..98d129b 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -92,8 +92,9 @@
 
 QuicTimeWaitListManager::QuicTimeWaitListManager(
     QuicPacketWriter* writer,
-    EpollServer* epoll_server)
-    : framer_(QuicVersionMax(),
+    EpollServer* epoll_server,
+    const QuicVersionVector& supported_versions)
+    : framer_(supported_versions,
               QuicTime::Zero(),  // unused
               true),
       epoll_server_(epoll_server),
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h
index 739e14b..f208395 100644
--- a/net/tools/quic/quic_time_wait_list_manager.h
+++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -14,10 +14,10 @@
 #include "base/strings/string_piece.h"
 #include "net/quic/quic_blocked_writer_interface.h"
 #include "net/quic/quic_framer.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/tools/epoll_server/epoll_server.h"
 #include "net/tools/quic/quic_epoll_clock.h"
-#include "net/tools/quic/quic_packet_writer.h"
 
 namespace net {
 namespace tools {
@@ -37,7 +37,8 @@
   // writer - the entity that writes to the socket. (Owned by the dispatcher)
   // epoll_server - used to run clean up alarms. (Owned by the dispatcher)
   QuicTimeWaitListManager(QuicPacketWriter* writer,
-                          EpollServer* epoll_server);
+                          EpollServer* epoll_server,
+                          const QuicVersionVector& supported_versions);
   virtual ~QuicTimeWaitListManager();
 
   // Adds the given guid to time wait state for kTimeWaitPeriod. Henceforth,
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 64abb61..92d1fc4 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -12,9 +12,9 @@
 #include "net/quic/crypto/quic_encrypter.h"
 #include "net/quic/quic_data_reader.h"
 #include "net/quic/quic_framer.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/quic/quic_packet_writer.h"
 #include "net/tools/quic/test_tools/mock_epoll_server.h"
 #include "net/tools/quic/test_tools/quic_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -38,7 +38,7 @@
  public:
   TestTimeWaitListManager(QuicPacketWriter* writer,
                           EpollServer* epoll_server)
-      : QuicTimeWaitListManager(writer, epoll_server) {
+      : QuicTimeWaitListManager(writer, epoll_server, QuicSupportedVersions()) {
   }
 
   using QuicTimeWaitListManager::is_write_blocked;
@@ -57,14 +57,14 @@
  protected:
   QuicTimeWaitListManagerTest()
       : time_wait_list_manager_(&writer_, &epoll_server_),
-        framer_(QuicVersionMax(),
-                QuicTime::Zero(),
-                true),
+        framer_(QuicSupportedVersions(), QuicTime::Zero(), true),
         guid_(45) {
   }
 
+  virtual ~QuicTimeWaitListManagerTest() {}
+
   void AddGuid(QuicGuid guid) {
-    time_wait_list_manager_.AddGuidToTimeWait(guid, QuicVersionMax());
+    time_wait_list_manager_.AddGuidToTimeWait(guid, test::QuicVersionMax());
   }
 
   void AddGuid(QuicGuid guid, QuicVersion version) {
@@ -132,7 +132,7 @@
       const std::tr1::tuple<const char*, int> packet_buffer,
       testing::MatchResultListener* /* listener */) const {
     FramerVisitorCapturingPublicReset visitor;
-    QuicFramer framer(QuicVersionMax(),
+    QuicFramer framer(QuicSupportedVersions(),
                       QuicTime::Zero(),
                       false);
     framer.set_visitor(&visitor);
@@ -159,9 +159,7 @@
     QuicPacketSequenceNumber expected_sequence_number,
     const std::tr1::tuple<const char*, int>& packet_buffer) {
   FramerVisitorCapturingPublicReset visitor;
-  QuicFramer framer(QuicVersionMax(),
-                    QuicTime::Zero(),
-                    false);
+  QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
   framer.set_visitor(&visitor);
   QuicEncryptedPacket encrypted(std::tr1::get<0>(packet_buffer),
                                 std::tr1::get<1>(packet_buffer));
@@ -348,28 +346,28 @@
   const int kRandomSequenceNumber = 1;
   scoped_ptr<QuicEncryptedPacket> packet;
 
-  AddGuid(guid_, QuicVersionMin());
-  framer_.set_version(QuicVersionMin());
+  AddGuid(guid_, test::QuicVersionMin());
+  framer_.set_version(test::QuicVersionMin());
   packet.reset(ConstructEncryptedPacket(guid_, kRandomSequenceNumber));
 
   // Reset packet should be written, using the minimum quic version.
   EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
       .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
   ProcessPacket(guid_, *packet);
-  EXPECT_EQ(time_wait_list_manager_.version(), QuicVersionMin());
+  EXPECT_EQ(time_wait_list_manager_.version(), test::QuicVersionMin());
 
   // New guid
   ++guid_;
 
-  AddGuid(guid_, QuicVersionMax());
-  framer_.set_version(QuicVersionMax());
+  AddGuid(guid_, test::QuicVersionMax());
+  framer_.set_version(test::QuicVersionMax());
   packet.reset(ConstructEncryptedPacket(guid_, kRandomSequenceNumber));
 
   // Reset packet should be written, using the maximum quic version.
   EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
     .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
   ProcessPacket(guid_, *packet);
-  EXPECT_EQ(time_wait_list_manager_.version(), QuicVersionMax());
+  EXPECT_EQ(time_wait_list_manager_.version(), test::QuicVersionMax());
 }
 
 TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
@@ -377,15 +375,15 @@
   const int kGuid2 = 456;
   const int kGuid3 = 789;
 
-  AddGuid(kGuid1, QuicVersionMin());
-  AddGuid(kGuid2, QuicVersionMax());
-  AddGuid(kGuid3, QuicVersionMax());
+  AddGuid(kGuid1, test::QuicVersionMin());
+  AddGuid(kGuid2, test::QuicVersionMax());
+  AddGuid(kGuid3, test::QuicVersionMax());
 
-  EXPECT_EQ(QuicVersionMin(),
+  EXPECT_EQ(test::QuicVersionMin(),
             time_wait_list_manager_.GetQuicVersionFromGuid(kGuid1));
-  EXPECT_EQ(QuicVersionMax(),
+  EXPECT_EQ(test::QuicVersionMax(),
             time_wait_list_manager_.GetQuicVersionFromGuid(kGuid2));
-  EXPECT_EQ(QuicVersionMax(),
+  EXPECT_EQ(test::QuicVersionMax(),
             time_wait_list_manager_.GetQuicVersionFromGuid(kGuid3));
 }
 
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
index 3a2b1d9..2d9c1ec 100644
--- a/net/tools/quic/test_tools/mock_quic_dispatcher.cc
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
@@ -13,7 +13,9 @@
     const QuicCryptoServerConfig& crypto_config,
     QuicGuid guid,
     EpollServer* eps)
-    : QuicDispatcher(config, crypto_config, guid, eps) { }
+    : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), guid,
+                     eps) {
+}
 MockQuicDispatcher::~MockQuicDispatcher() {}
 
 }  // namespace test
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
new file mode 100644
index 0000000..872b2a2
--- /dev/null
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -0,0 +1,168 @@
+// Copyright 2013 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 "net/tools/quic/test_tools/packet_dropping_test_writer.h"
+
+#include <limits>
+
+#include "base/rand_util.h"
+#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_socket_utils.h"
+
+using net::test::QuicTestWriter;
+
+namespace net {
+namespace tools {
+namespace test {
+
+// An alarm that is scheduled if a blocked socket is simulated to indicate
+// it's writable again.
+class WriteUnblockedAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
+      : writer_(writer) { }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    DCHECK(writer_->blocked_writer());
+    writer_->blocked_writer()->OnCanWrite();
+    return QuicTime::Zero();
+  }
+
+ private:
+  PacketDroppingTestWriter* writer_;
+};
+
+// An alarm that is scheduled every time a new packet is to be written at a
+// later point.
+class DelayAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit DelayAlarm(PacketDroppingTestWriter* writer)
+      : writer_(writer) { }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    return writer_->ReleaseNextPacket();
+  }
+
+ private:
+  PacketDroppingTestWriter* writer_;
+};
+
+PacketDroppingTestWriter::PacketDroppingTestWriter()
+    : clock_(NULL),
+      blocked_writer_(NULL),
+      config_mutex_(),
+      fake_packet_loss_percentage_(0),
+      fake_blocked_socket_percentage_(0),
+      fake_packet_reorder_percentage_(0),
+      fake_packet_delay_(QuicTime::Delta::Zero()) {
+  uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
+  LOG(INFO) << "Seeding packet loss with " << seed;
+  simple_random_.set_seed(seed);
+}
+
+PacketDroppingTestWriter::~PacketDroppingTestWriter() { }
+
+void PacketDroppingTestWriter::SetConnectionHelper(
+    QuicEpollConnectionHelper* helper) {
+  clock_ = helper->GetClock();
+  write_unblocked_alarm_.reset(
+      helper->CreateAlarm(new WriteUnblockedAlarm(this)));
+  delay_alarm_.reset(
+        helper->CreateAlarm(new DelayAlarm(this)));
+}
+
+WriteResult PacketDroppingTestWriter::WritePacket(
+    const char* buffer, size_t buf_len,
+    const net::IPAddressNumber& self_address,
+    const net::IPEndPoint& peer_address,
+    QuicBlockedWriterInterface* blocked_writer) {
+  base::AutoLock locked(config_mutex_);
+  if (fake_packet_loss_percentage_ > 0 &&
+      simple_random_.RandUint64() % 100 <
+          static_cast<uint64>(fake_packet_loss_percentage_)) {
+    DLOG(INFO) << "Dropping packet.";
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+  if (fake_blocked_socket_percentage_ > 0 &&
+      simple_random_.RandUint64() % 100 <
+          static_cast<uint64>(fake_blocked_socket_percentage_)) {
+    DLOG(INFO) << "Blocking socket.";
+    if (!write_unblocked_alarm_->IsSet()) {
+      blocked_writer_ = blocked_writer;
+      // Set the alarm for 1ms in the future.
+      write_unblocked_alarm_->Set(
+          clock_->ApproximateNow().Add(
+              QuicTime::Delta::FromMilliseconds(1)));
+    }
+    return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+  }
+
+  if (!fake_packet_delay_.IsZero()) {
+    // Queue it to be sent.
+    QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
+    delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address,
+                                            peer_address, send_time));
+    // Set the alarm if it's not yet set.
+    if (!delay_alarm_->IsSet()) {
+      delay_alarm_->Set(send_time);
+    }
+
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+
+  return writer()->WritePacket(buffer, buf_len, self_address, peer_address,
+                               blocked_writer);
+}
+
+bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const {
+  return false;
+}
+
+QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
+  if (delayed_packets_.empty()) {
+    return QuicTime::Zero();
+  }
+  base::AutoLock locked(config_mutex_);
+  DelayedPacketList::iterator iter = delayed_packets_.begin();
+  // Determine if we should re-order.
+  if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
+      simple_random_.RandUint64() % 100 <
+          static_cast<uint64>(fake_packet_reorder_percentage_)) {
+    DLOG(INFO) << "Reordering packets.";
+    ++iter;
+    // Swap the send times when re-ordering packets.
+    delayed_packets_.begin()->send_time = iter->send_time;
+  }
+
+  DLOG(INFO) << "Releasing packet.  " << (delayed_packets_.size() - 1)
+             << " remaining.";
+  // Grab the next one off the queue and send it.
+  writer()->WritePacket(iter->buffer.data(), iter->buffer.length(),
+                        iter->self_address, iter->peer_address, NULL);
+  delayed_packets_.erase(iter);
+
+  // If there are others, find the time for the next to be sent.
+  if (delayed_packets_.empty()) {
+    return QuicTime::Zero();
+  }
+  return delayed_packets_.begin()->send_time;
+}
+
+PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
+    const char* buffer,
+    size_t buf_len,
+    const net::IPAddressNumber& self_address,
+    const net::IPEndPoint& peer_address,
+    QuicTime send_time)
+    : buffer(buffer, buf_len),
+      self_address(self_address),
+      peer_address(peer_address),
+      send_time(send_time) {
+}
+
+PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h
new file mode 100644
index 0000000..d35f67f
--- /dev/null
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -0,0 +1,125 @@
+// Copyright 2013 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 NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
+
+#include <list>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "net/quic/quic_alarm.h"
+#include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_packet_writer.h"
+#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/tools/quic/quic_epoll_clock.h"
+#include "net/tools/quic/test_tools/quic_test_client.h"
+#include "net/tools/quic/test_tools/quic_test_utils.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+// Simulates a connection that drops packets a configured percentage of the time
+// and has a blocked socket a configured percentage of the time.  Also provides
+// the options to delay packets and reorder packets if delay is enabled.
+class PacketDroppingTestWriter : public net::test::QuicTestWriter {
+ public:
+  PacketDroppingTestWriter();
+
+  virtual ~PacketDroppingTestWriter();
+
+  void SetConnectionHelper(QuicEpollConnectionHelper* helper);
+
+  // QuicPacketWriter methods:
+  virtual WriteResult WritePacket(
+      const char* buffer, size_t buf_len,
+      const IPAddressNumber& self_address,
+      const IPEndPoint& peer_address,
+      QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+
+  virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+
+  // Writes out the next packet to the contained writer and returns the time
+  // for the next delayed packet to be written.
+  QuicTime ReleaseNextPacket();
+
+  QuicBlockedWriterInterface* blocked_writer() { return blocked_writer_; }
+
+  // The percent of time a packet is simulated as being lost.
+  void set_fake_packet_loss_percentage(int32 fake_packet_loss_percentage) {
+    base::AutoLock locked(config_mutex_);
+    fake_packet_loss_percentage_ = fake_packet_loss_percentage;
+  }
+
+  // The percent of time WritePacket will block and set WriteResult's status
+  // to WRITE_STATUS_BLOCKED.
+  void set_fake_blocked_socket_percentage(
+      int32 fake_blocked_socket_percentage) {
+    DCHECK(clock_);
+    base::AutoLock locked(config_mutex_);
+    fake_blocked_socket_percentage_  = fake_blocked_socket_percentage;
+  }
+
+  // The percent of time a packet is simulated as being reordered.
+  void set_fake_reorder_percentage(int32 fake_packet_reorder_percentage) {
+    DCHECK(clock_);
+    base::AutoLock locked(config_mutex_);
+    DCHECK(!fake_packet_delay_.IsZero());
+    fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
+  }
+
+  // The percent of time WritePacket will block and set WriteResult's status
+  // to WRITE_STATUS_BLOCKED.
+  void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
+    DCHECK(clock_);
+    base::AutoLock locked(config_mutex_);
+    fake_packet_delay_  = fake_packet_delay;
+  }
+
+  void set_seed(uint64 seed) {
+    simple_random_.set_seed(seed);
+  }
+
+ private:
+  // A single packet which will be sent at the supplied send_time.
+  class DelayedWrite {
+   public:
+    DelayedWrite(const char* buffer,
+                 size_t buf_len,
+                 const IPAddressNumber& self_address,
+                 const IPEndPoint& peer_address,
+                 QuicTime send_time);
+    ~DelayedWrite();
+
+    string buffer;
+    const IPAddressNumber self_address;
+    const IPEndPoint peer_address;
+    QuicTime send_time;
+  };
+
+  typedef std::list<DelayedWrite> DelayedPacketList;
+
+  const QuicClock* clock_;
+  scoped_ptr<QuicAlarm> write_unblocked_alarm_;
+  scoped_ptr<QuicAlarm> delay_alarm_;
+  QuicBlockedWriterInterface* blocked_writer_;
+  SimpleRandom simple_random_;
+  DelayedPacketList delayed_packets_;
+
+  base::Lock config_mutex_;
+  int32 fake_packet_loss_percentage_;
+  int32 fake_blocked_socket_percentage_;
+  int32 fake_packet_reorder_percentage_;
+  QuicTime::Delta fake_packet_delay_;
+
+  DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter);
+};
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
new file mode 100644
index 0000000..c96eafd
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 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 "net/tools/quic/test_tools/quic_dispatcher_peer.h"
+
+#include "net/tools/quic/quic_dispatcher.h"
+
+using net::test::QuicTestWriter;
+
+namespace net {
+namespace tools {
+namespace test {
+
+// static
+void QuicDispatcherPeer::SetTimeWaitListManager(
+    QuicDispatcher* dispatcher,
+    QuicTimeWaitListManager* time_wait_list_manager) {
+  dispatcher->time_wait_list_manager_.reset(time_wait_list_manager);
+}
+
+// static
+void QuicDispatcherPeer::SetWriteBlocked(QuicDispatcher* dispatcher) {
+  dispatcher->write_blocked_ = true;
+}
+
+// static
+void QuicDispatcherPeer::UseWriter(QuicDispatcher* dispatcher,
+                                   QuicTestWriter* writer) {
+  writer->set_writer(dispatcher->writer_.release());
+  dispatcher->writer_.reset(writer);
+}
+
+// static
+QuicPacketWriter* QuicDispatcherPeer::GetWriter(QuicDispatcher* dispatcher) {
+  return dispatcher->writer_.get();
+}
+
+// static
+QuicEpollConnectionHelper* QuicDispatcherPeer::GetHelper(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->helper_.get();
+}
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h
new file mode 100644
index 0000000..f463453
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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 NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
+
+#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/tools/quic/quic_dispatcher.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+class QuicDispatcherPeer {
+ public:
+  static void SetTimeWaitListManager(
+      QuicDispatcher* dispatcher,
+      QuicTimeWaitListManager* time_wait_list_manager);
+
+  static void SetWriteBlocked(QuicDispatcher* dispatcher);
+
+  static void UseWriter(QuicDispatcher* dispatcher,
+                        net::test::QuicTestWriter* writer);
+
+  static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher);
+
+  static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher);
+};
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
diff --git a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc
deleted file mode 100644
index e358273..0000000
--- a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2013 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 "net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h"
-
-#include "net/tools/quic/quic_epoll_connection_helper.h"
-
-namespace net {
-namespace tools {
-namespace test {
-
-// static
-void QuicEpollConnectionHelperPeer::SetWriter(QuicEpollConnectionHelper* helper,
-                                              QuicPacketWriter* writer) {
-  helper->writer_ = writer;
-}
-
-}  // namespace test
-}  // namespace tools
-}  // namespace net
diff --git a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h
deleted file mode 100644
index 72085df..0000000
--- a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2013 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 NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
-#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
-
-#include "base/basictypes.h"
-
-namespace net {
-namespace tools {
-
-class QuicPacketWriter;
-class QuicEpollConnectionHelper;
-
-namespace test {
-
-class QuicEpollConnectionHelperPeer {
- public:
-  static void SetWriter(QuicEpollConnectionHelper* helper,
-                        QuicPacketWriter* writer);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(QuicEpollConnectionHelperPeer);
-};
-
-}  // namespace test
-}  // namespace tools
-}  // namespace net
-
-#endif  // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
diff --git a/net/tools/quic/test_tools/quic_server_peer.cc b/net/tools/quic/test_tools/quic_server_peer.cc
new file mode 100644
index 0000000..15f3129
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_server_peer.cc
@@ -0,0 +1,38 @@
+// Copyright 2013 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 "net/tools/quic/test_tools/quic_server_peer.h"
+
+#include "net/tools/quic/quic_dispatcher.h"
+#include "net/tools/quic/quic_server.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+// static
+bool QuicServerPeer::SetSmallSocket(QuicServer* server) {
+  int size = 1024 * 10;
+  return setsockopt(
+      server->fd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != -1;
+}
+
+// static
+void QuicServerPeer::DisableRecvmmsg(QuicServer* server) {
+  server->use_recvmmsg_ = false;
+}
+
+// static
+QuicDispatcher* QuicServerPeer::GetDispatcher(QuicServer* server) {
+  return server->dispatcher_.get();
+}
+
+// static
+int QuicServerPeer::GetFD(QuicServer* server) {
+  return server->fd_;
+}
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/test_tools/quic_server_peer.h b/net/tools/quic/test_tools/quic_server_peer.h
new file mode 100644
index 0000000..65e2c5e
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_server_peer.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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 NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+
+namespace net {
+
+namespace tools {
+
+class QuicDispatcher;
+class QuicServer;
+
+namespace test {
+
+class QuicServerPeer {
+ public:
+  static bool SetSmallSocket(QuicServer* server);
+  static void DisableRecvmmsg(QuicServer* server);
+  static QuicDispatcher* GetDispatcher(QuicServer* server);
+  static int GetFD(QuicServer* server);
+};
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 0af8949..c188d5e 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -4,20 +4,24 @@
 
 #include "net/tools/quic/test_tools/quic_test_client.h"
 
+#include "base/time/time.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
 #include "net/quic/crypto/proof_verifier.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/tools/balsa/balsa_headers.h"
 #include "net/tools/quic/quic_epoll_connection_helper.h"
 #include "net/tools/quic/quic_spdy_client_stream.h"
 #include "net/tools/quic/test_tools/http_message_test_utils.h"
 #include "url/gurl.h"
 
+using base::StringPiece;
+using net::test::QuicConnectionPeer;
+using net::test::QuicTestWriter;
 using std::string;
 using std::vector;
-using base::StringPiece;
 
 namespace {
 
@@ -97,15 +101,17 @@
 
   QuicEpollClient(IPEndPoint server_address,
              const string& server_hostname,
-             const QuicVersion version)
-      : Super(server_address, server_hostname, version, false) {
+             const QuicVersionVector& supported_versions)
+      : Super(server_address, server_hostname, supported_versions, false),
+        override_guid_(0), test_writer_(NULL) {
   }
 
   QuicEpollClient(IPEndPoint server_address,
              const string& server_hostname,
              const QuicConfig& config,
-             const QuicVersion version)
-      : Super(server_address, server_hostname, config, version) {
+             const QuicVersionVector& supported_versions)
+      : Super(server_address, server_hostname, config, supported_versions),
+        override_guid_(0), test_writer_(NULL) {
   }
 
   virtual ~QuicEpollClient() {
@@ -114,32 +120,42 @@
     }
   }
 
-  virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper() OVERRIDE {
-    if (writer_.get() != NULL) {
-      writer_->set_fd(fd());
-      return new QuicEpollConnectionHelper(writer_.get(), epoll_server());
-    } else {
-      return Super::CreateQuicConnectionHelper();
+  virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE {
+    QuicPacketWriter* writer = Super::CreateQuicPacketWriter();
+    if (!test_writer_) {
+      return writer;
     }
+    test_writer_->set_writer(writer);
+    return test_writer_;
   }
 
-  void UseWriter(QuicTestWriter* writer) { writer_.reset(writer); }
+  virtual QuicGuid GenerateGuid() OVERRIDE {
+    return override_guid_ ? override_guid_ : Super::GenerateGuid();
+  }
+
+  // Takes ownership of writer.
+  void UseWriter(QuicTestWriter* writer) { test_writer_ = writer; }
+
+  void UseGuid(QuicGuid guid) {
+    override_guid_ = guid;
+  }
 
  private:
-  scoped_ptr<QuicTestWriter> writer_;
+  QuicGuid override_guid_;  // GUID to use, if nonzero
+  QuicTestWriter* test_writer_;
 };
 
 QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname,
-                               const QuicVersion version)
-    : client_(new QuicEpollClient(address, hostname, version)) {
+                               const QuicVersionVector& supported_versions)
+    : client_(new QuicEpollClient(address, hostname, supported_versions)) {
   Initialize(address, hostname, true);
 }
 
 QuicTestClient::QuicTestClient(IPEndPoint address,
                                const string& hostname,
                                bool secure,
-                               const QuicVersion version)
-    : client_(new QuicEpollClient(address, hostname, version)) {
+                               const QuicVersionVector& supported_versions)
+    : client_(new QuicEpollClient(address, hostname, supported_versions)) {
   Initialize(address, hostname, secure);
 }
 
@@ -147,8 +163,9 @@
                                const string& hostname,
                                bool secure,
                                const QuicConfig& config,
-                               const QuicVersion version)
-    : client_(new QuicEpollClient(address, hostname, config, version)) {
+                               const QuicVersionVector& supported_versions)
+    : client_(new QuicEpollClient(address, hostname, config,
+                                  supported_versions)) {
   Initialize(address, hostname, secure);
 }
 
@@ -161,7 +178,7 @@
   priority_ = 3;
   bytes_read_ = 0;
   bytes_written_= 0;
-  never_connected_ = true;
+  connect_attempted_ = false;
   secure_ = secure;
   auto_reconnect_ = false;
   proof_verifier_ = NULL;
@@ -235,7 +252,7 @@
 }
 
 QuicReliableClientStream* QuicTestClient::GetOrCreateStream() {
-  if (never_connected_ == true || auto_reconnect_) {
+  if (!connect_attempted_ || auto_reconnect_) {
     if (!connected()) {
       Connect();
     }
@@ -274,9 +291,11 @@
 
 void QuicTestClient::Connect() {
   DCHECK(!connected());
-  client_->Initialize();
+  if (!connect_attempted_) {
+    client_->Initialize();
+  }
   client_->Connect();
-  never_connected_ = false;
+  connect_attempted_ = true;
 }
 
 void QuicTestClient::ResetConnection() {
@@ -285,7 +304,10 @@
 }
 
 void QuicTestClient::Disconnect() {
-  client_->Disconnect();
+  if (client_->connected()) {
+    client_->Disconnect();
+  }
+  connect_attempted_ = false;
 }
 
 IPEndPoint QuicTestClient::LocalSocketAddress() const {
@@ -301,11 +323,47 @@
   bytes_written_ = 0;
 }
 
-void QuicTestClient::WaitForInitialResponse() {
-  DCHECK(stream_ != NULL);
-  while (stream_ && stream_->stream_bytes_read() == 0) {
+void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
+  int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
+  int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+  if (timeout_us > 0) {
+    client()->epoll_server()->set_timeout_in_us(timeout_us);
+  }
+  const QuicClock* clock =
+      QuicConnectionPeer::GetHelper(client()->session()->connection())->
+          GetClock();
+  QuicTime end_waiting_time = clock->Now().Add(
+      QuicTime::Delta::FromMicroseconds(timeout_us));
+  while (stream_ != NULL &&
+         !client_->session()->IsClosedStream(stream_->id()) &&
+         (timeout_us < 0 || clock->Now() < end_waiting_time)) {
     client_->WaitForEvents();
   }
+  if (timeout_us > 0) {
+    client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+  }
+}
+
+void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
+  int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
+  int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+  if (timeout_us > 0) {
+    client()->epoll_server()->set_timeout_in_us(timeout_us);
+  }
+  const QuicClock* clock =
+      QuicConnectionPeer::GetHelper(client()->session()->connection())->
+          GetClock();
+  QuicTime end_waiting_time = clock->Now().Add(
+      QuicTime::Delta::FromMicroseconds(timeout_us));
+  while (stream_ != NULL &&
+         !client_->session()->IsClosedStream(stream_->id()) &&
+         stream_->stream_bytes_read() == 0 &&
+         (timeout_us < 0 || clock->Now() < end_waiting_time)) {
+    client_->WaitForEvents();
+  }
+  if (timeout_us > 0) {
+    client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+  }
 }
 
 ssize_t QuicTestClient::Send(const void *buffer, size_t size) {
@@ -337,10 +395,14 @@
 }
 
 void QuicTestClient::UseWriter(QuicTestWriter* writer) {
-  DCHECK(!connected());
   reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer);
 }
 
+void QuicTestClient::UseGuid(QuicGuid guid) {
+  DCHECK(!connected());
+  reinterpret_cast<QuicEpollClient*>(client_.get())->UseGuid(guid);
+}
+
 }  // namespace test
 }  // namespace tools
 }  // namespace net
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 3cd71d5..c493b8c 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -12,8 +12,8 @@
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
 #include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/quic_test_writer.h"
 #include "net/tools/quic/quic_client.h"
-#include "net/tools/quic/quic_packet_writer.h"
 
 namespace net {
 
@@ -23,30 +23,22 @@
 
 namespace test {
 
-// Allows setting a writer for the client's QuicConnectionHelper, to allow
-// fine-grained control of writes.
-class QuicTestWriter : public QuicPacketWriter {
- public:
-  virtual ~QuicTestWriter() {}
-  virtual void set_fd(int fd) = 0;
-};
-
 class HTTPMessage;
 
 // A toy QUIC client used for testing.
 class QuicTestClient :  public ReliableQuicStream::Visitor {
  public:
   QuicTestClient(IPEndPoint server_address, const string& server_hostname,
-                 const QuicVersion version);
+                 const QuicVersionVector& supported_versions);
   QuicTestClient(IPEndPoint server_address,
                  const string& server_hostname,
                  bool secure,
-                 const QuicVersion version);
+                 const QuicVersionVector& supported_versions);
   QuicTestClient(IPEndPoint server_address,
                  const string& server_hostname,
                  bool secure,
                  const QuicConfig& config,
-                 const QuicVersion version);
+                 const QuicVersionVector& supported_versions);
 
   virtual ~QuicTestClient();
 
@@ -77,7 +69,8 @@
   void Disconnect();
   IPEndPoint LocalSocketAddress() const;
   void ClearPerRequestState();
-  void WaitForInitialResponse();
+  void WaitForResponseForMs(int timeout_ms);
+  void WaitForInitialResponseForMs(int timeout_ms);
   ssize_t Send(const void *buffer, size_t size);
   int response_size() const;
   size_t bytes_read() const;
@@ -88,7 +81,10 @@
 
   // Configures client_ to take ownership of and use the writer.
   // Must be called before initial connect.
-  void UseWriter(QuicTestWriter* writer);
+  void UseWriter(net::test::QuicTestWriter* writer);
+  // If the given GUID is nonzero, configures client_ to use a specific GUID
+  // instead of a random one.
+  void UseGuid(QuicGuid guid);
 
   // Returns NULL if the maximum number of streams have already been created.
   QuicReliableClientStream* GetOrCreateStream();
@@ -121,17 +117,15 @@
 
   BalsaHeaders headers_;
   QuicPriority priority_;
-
   string response_;
   uint64 bytes_read_;
   uint64 bytes_written_;
-  // True if the client has never connected before.  The client will
-  // auto-connect exactly once before sending data.  If something causes a
-  // connection reset, it will not automatically reconnect.
-  bool never_connected_;
+  // True if we tried to connect already since the last call to Disconnect().
+  bool connect_attempted_;
   bool secure_;
-  // If true, the client will always reconnect if necessary before creating a
-  // stream.
+  // The client will auto-connect exactly once before sending data.  If
+  // something causes a connection reset, it will not automatically reconnect
+  // unless auto_reconnect_ is true.
   bool auto_reconnect_;
 
   // proof_verifier_ points to a RecordingProofVerifier that is owned by
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index fa3627b..054c7fb 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -4,6 +4,9 @@
 
 #include "net/tools/quic/test_tools/quic_test_utils.h"
 
+#include "base/sha1.h"
+#include "net/quic/quic_connection.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/tools/quic/quic_epoll_connection_helper.h"
 
@@ -14,30 +17,42 @@
 namespace tools {
 namespace test {
 
+QuicVersion QuicVersionMax() { return QuicSupportedVersions().front(); }
+
+QuicVersion QuicVersionMin() { return QuicSupportedVersions().back(); }
+
 MockConnection::MockConnection(QuicGuid guid,
                                IPEndPoint address,
                                int fd,
                                EpollServer* eps,
                                bool is_server)
     : QuicConnection(guid, address,
-                     new QuicEpollConnectionHelper(fd, eps), is_server,
-                     QuicVersionMax()),
-      has_mock_helper_(false) {
+                     new QuicEpollConnectionHelper(eps),
+                     new QuicDefaultPacketWriter(fd), is_server,
+                     QuicSupportedVersions()),
+      has_mock_helper_(false),
+      writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+      helper_(helper()) {
 }
 
 MockConnection::MockConnection(QuicGuid guid,
                                IPEndPoint address,
                                bool is_server)
     : QuicConnection(guid, address, new testing::NiceMock<MockHelper>(),
-                     is_server, QuicVersionMax()),
-      has_mock_helper_(true) {
+                     new testing::NiceMock<MockPacketWriter>(),
+                     is_server, QuicSupportedVersions()),
+      has_mock_helper_(true),
+      writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+      helper_(helper()) {
 }
 
 MockConnection::MockConnection(QuicGuid guid,
                                IPEndPoint address,
                                QuicConnectionHelperInterface* helper,
+                               QuicPacketWriter* writer,
                                bool is_server)
-    : QuicConnection(guid, address, helper, is_server, QuicVersionMax()),
+    : QuicConnection(guid, address, helper, writer, is_server,
+                     QuicSupportedVersions()),
       has_mock_helper_(false) {
 }
 
@@ -50,6 +65,13 @@
   static_cast<MockHelper*>(helper())->AdvanceTime(delta);
 }
 
+uint64 SimpleRandom::RandUint64() {
+  unsigned char hash[base::kSHA1Length];
+  base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
+                      hash);
+  memcpy(&seed_, hash, sizeof(seed_));
+  return seed_;
+}
 
 MockQuicSessionOwner::MockQuicSessionOwner() {
 }
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index 2710a56..52b74c1 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -9,10 +9,10 @@
 
 #include "base/strings/string_piece.h"
 #include "net/quic/quic_connection.h"
+#include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_session.h"
 #include "net/quic/quic_spdy_decompressor.h"
 #include "net/spdy/spdy_framer.h"
-#include "net/tools/quic/quic_packet_writer.h"
 #include "net/tools/quic/quic_server_session.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -24,6 +24,29 @@
 namespace tools {
 namespace test {
 
+// Upper limit on versions we support.
+QuicVersion QuicVersionMax();
+
+// Lower limit on versions we support.
+QuicVersion QuicVersionMin();
+
+// Simple random number generator used to compute random numbers suitable
+// for pseudo-randomly dropping packets in tests.  It works by computing
+// the sha1 hash of the current seed, and using the first 64 bits as
+// the next random number, and the next seed.
+class SimpleRandom {
+ public:
+  SimpleRandom() : seed_(0) {}
+
+  // Returns a random number in the range [0, kuint64max].
+  uint64 RandUint64();
+
+  void set_seed(uint64 seed) { seed_ = seed; }
+
+ private:
+  uint64 seed_;
+};
+
 class MockConnection : public QuicConnection {
  public:
   // Uses a QuicConnectionHelper created with fd and eps.
@@ -36,7 +59,9 @@
   MockConnection(QuicGuid guid, IPEndPoint address, bool is_server);
   MockConnection(QuicGuid guid,
                  IPEndPoint address,
-                 QuicConnectionHelperInterface* helper, bool is_server);
+                 QuicConnectionHelperInterface* helper,
+                 QuicPacketWriter* writer,
+                 bool is_server);
   virtual ~MockConnection();
 
   // If the constructor that uses a MockHelper has been used then this method
@@ -67,31 +92,12 @@
 
  private:
   const bool has_mock_helper_;
+  scoped_ptr<QuicPacketWriter> writer_;
+  scoped_ptr<QuicConnectionHelperInterface> helper_;
 
   DISALLOW_COPY_AND_ASSIGN(MockConnection);
 };
 
-class MockQuicSessionOwner : public QuicSessionOwner {
- public:
-  MockQuicSessionOwner();
-  ~MockQuicSessionOwner();
-  MOCK_METHOD2(OnConnectionClose, void(QuicGuid guid, QuicErrorCode error));
-};
-
-class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
- public:
-  virtual ~TestDecompressorVisitor() {}
-  virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
-  virtual void OnDecompressionError() OVERRIDE;
-
-  std::string data() { return data_; }
-  bool error() { return error_; }
-
- private:
-  std::string data_;
-  bool error_;
-};
-
 class TestSession : public QuicSession {
  public:
   TestSession(QuicConnection* connection,
@@ -112,14 +118,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestSession);
 };
 
-class MockAckNotifierDelegate : public QuicAckNotifier::DelegateInterface {
- public:
-  MockAckNotifierDelegate();
-  virtual ~MockAckNotifierDelegate();
-
-  MOCK_METHOD0(OnAckNotification, void());
-};
-
 class MockPacketWriter : public QuicPacketWriter {
  public:
   MockPacketWriter();
@@ -131,6 +129,36 @@
                            const IPAddressNumber& self_address,
                            const IPEndPoint& peer_address,
                            QuicBlockedWriterInterface* blocked_writer));
+  MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
+};
+
+class MockQuicSessionOwner : public QuicSessionOwner {
+ public:
+  MockQuicSessionOwner();
+  ~MockQuicSessionOwner();
+  MOCK_METHOD2(OnConnectionClosed, void(QuicGuid guid, QuicErrorCode error));
+};
+
+class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
+ public:
+  virtual ~TestDecompressorVisitor() {}
+  virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
+  virtual void OnDecompressionError() OVERRIDE;
+
+  std::string data() { return data_; }
+  bool error() { return error_; }
+
+ private:
+  std::string data_;
+  bool error_;
+};
+
+class MockAckNotifierDelegate : public QuicAckNotifier::DelegateInterface {
+ public:
+  MockAckNotifierDelegate();
+  virtual ~MockAckNotifierDelegate();
+
+  MOCK_METHOD0(OnAckNotification, void());
 };
 
 }  // namespace test
diff --git a/net/tools/quic/test_tools/server_thread.cc b/net/tools/quic/test_tools/server_thread.cc
index e82b3b3..dc41e09 100644
--- a/net/tools/quic/test_tools/server_thread.cc
+++ b/net/tools/quic/test_tools/server_thread.cc
@@ -10,11 +10,12 @@
 
 ServerThread::ServerThread(IPEndPoint address,
                            const QuicConfig& config,
+                           const QuicVersionVector& supported_versions,
                            bool strike_register_no_startup_period)
     : SimpleThread("server_thread"),
       listening_(true, false),
       quit_(true, false),
-      server_(config),
+      server_(config, supported_versions),
       address_(address),
       port_(0) {
   if (strike_register_no_startup_period) {
diff --git a/net/tools/quic/test_tools/server_thread.h b/net/tools/quic/test_tools/server_thread.h
index 4263dac..2011882 100644
--- a/net/tools/quic/test_tools/server_thread.h
+++ b/net/tools/quic/test_tools/server_thread.h
@@ -19,6 +19,7 @@
  public:
   ServerThread(IPEndPoint address,
                const QuicConfig& config,
+               const QuicVersionVector& supported_versions,
                bool strike_register_no_startup_period);
 
   virtual ~ServerThread();
@@ -29,6 +30,7 @@
 
   base::WaitableEvent* listening() { return &listening_; }
   base::WaitableEvent* quit() { return &quit_; }
+  QuicServer* server() { return &server_; }
 
  private:
   base::WaitableEvent listening_;
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index e25fc95..bd28b4b 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -31,6 +31,8 @@
 bool g_interception_enabled = false;
 bool g_ignore_certificate_requests = false;
 
+void EmptyCompletionCallback(int result) {}
+
 }  // namespace
 
 namespace net {
@@ -425,7 +427,6 @@
 
     current_response_bytes_ += bytes_read;
     InformDelegateDownloadProgress();
-    InformDelegateDownloadDataIfNecessary(bytes_read);
 
     const int result =
         WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read));
@@ -650,7 +651,6 @@
   url_request_data_key_ = NULL;
   url_request_create_data_callback_.Reset();
   was_cancelled_ = true;
-  response_writer_.reset();
 }
 
 void URLFetcherCore::OnCompletedURLRequest(
@@ -801,12 +801,8 @@
         data->BytesRemaining(),
         base::Bind(&URLFetcherCore::DidWriteBuffer, this, data));
     if (result < 0) {
-      if (result != ERR_IO_PENDING) {
-        CancelURLRequest(result);
-        delegate_task_runner_->PostTask(
-            FROM_HERE,
-            base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
-      }
+      if (result != ERR_IO_PENDING)
+        DidWriteBuffer(data, result);
       return result;
     }
     data->DidConsume(result);
@@ -818,6 +814,7 @@
                                     int result) {
   if (result < 0) {  // Handle errors.
     CancelURLRequest(result);
+    response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
     delegate_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
@@ -892,24 +889,4 @@
     delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);
 }
 
-void URLFetcherCore::InformDelegateDownloadDataIfNecessary(int bytes_read) {
-  DCHECK(network_task_runner_->BelongsToCurrentThread());
-  if (delegate_ && delegate_->ShouldSendDownloadData()) {
-    scoped_ptr<std::string> download_data(
-        new std::string(buffer_->data(), bytes_read));
-    delegate_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &URLFetcherCore::InformDelegateDownloadDataInDelegateThread,
-            this, base::Passed(&download_data)));
-  }
-}
-
-void URLFetcherCore::InformDelegateDownloadDataInDelegateThread(
-    scoped_ptr<std::string> download_data) {
-  DCHECK(delegate_task_runner_->BelongsToCurrentThread());
-  if (delegate_)
-    delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass());
-}
-
 }  // namespace net
diff --git a/net/url_request/url_fetcher_core.h b/net/url_request/url_fetcher_core.h
index b266ff3..9ee58b6 100644
--- a/net/url_request/url_fetcher_core.h
+++ b/net/url_request/url_fetcher_core.h
@@ -204,9 +204,6 @@
   void InformDelegateDownloadProgress();
   void InformDelegateDownloadProgressInDelegateThread(int64 current,
                                                       int64 total);
-  void InformDelegateDownloadDataIfNecessary(int bytes_read);
-  void InformDelegateDownloadDataInDelegateThread(
-      scoped_ptr<std::string> download_data);
 
   URLFetcher* fetcher_;              // Corresponding fetcher object
   GURL original_url_;                // The URL we were asked to fetch
diff --git a/net/url_request/url_fetcher_delegate.cc b/net/url_request/url_fetcher_delegate.cc
index 1cc58e7..4f7cd65 100644
--- a/net/url_request/url_fetcher_delegate.cc
+++ b/net/url_request/url_fetcher_delegate.cc
@@ -9,16 +9,9 @@
 void URLFetcherDelegate::OnURLFetchDownloadProgress(
     const URLFetcher* source, int64 current, int64 total) {}
 
-void URLFetcherDelegate::OnURLFetchDownloadData(
-    const URLFetcher* source, scoped_ptr<std::string> download_data) {}
-
 void URLFetcherDelegate::OnURLFetchUploadProgress(
     const URLFetcher* source, int64 current, int64 total) {}
 
-bool URLFetcherDelegate::ShouldSendDownloadData() {
-  return false;
-}
-
 URLFetcherDelegate::~URLFetcherDelegate() {}
 
 }  // namespace net
diff --git a/net/url_request/url_fetcher_delegate.h b/net/url_request/url_fetcher_delegate.h
index ac7b2a6..e1b1352 100644
--- a/net/url_request/url_fetcher_delegate.h
+++ b/net/url_request/url_fetcher_delegate.h
@@ -28,19 +28,6 @@
   virtual void OnURLFetchDownloadProgress(const URLFetcher* source,
                                           int64 current, int64 total);
 
-  // This will be called when some part of the response is read.
-  // |download_data| contains the current bytes received since the last call.
-  // This will be called after ShouldSendDownloadData() and only if the latter
-  // returns true.
-  virtual void OnURLFetchDownloadData(const URLFetcher* source,
-                                      scoped_ptr<std::string> download_data);
-
-  // This indicates if OnURLFetchDownloadData should be called.
-  // This will be called before OnURLFetchDownloadData is called, and only if
-  // this returns true.
-  // Default implementation is false.
-  virtual bool ShouldSendDownloadData();
-
   // This will be called when uploading of POST or PUT requests proceeded.
   // |current| denotes the number of bytes sent so far, and |total| is the
   // total size of uploading data (or -1 if chunked upload is enabled).
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 37e505d..57e9fb8 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -15,7 +15,9 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/stats_counters.h"
 #include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
+#include "base/values.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
@@ -216,7 +218,8 @@
       redirect_limit_(kMaxRedirects),
       priority_(DEFAULT_PRIORITY),
       identifier_(GenerateURLRequestIdentifier()),
-      blocked_on_delegate_(false),
+      calling_delegate_(false),
+      delegate_info_usage_(DELEGATE_INFO_DEBUG_ONLY),
       before_request_callback_(base::Bind(&URLRequest::BeforeRequestComplete,
                                           base::Unretained(this))),
       has_notified_completion_(false),
@@ -252,7 +255,8 @@
       redirect_limit_(kMaxRedirects),
       priority_(DEFAULT_PRIORITY),
       identifier_(GenerateURLRequestIdentifier()),
-      blocked_on_delegate_(false),
+      calling_delegate_(false),
+      delegate_info_usage_(DELEGATE_INFO_DEBUG_ONLY),
       before_request_callback_(base::Bind(&URLRequest::BeforeRequestComplete,
                                           base::Unretained(this))),
       has_notified_completion_(false),
@@ -380,14 +384,87 @@
 }
 
 LoadStateWithParam URLRequest::GetLoadState() const {
-  if (blocked_on_delegate_) {
-    return LoadStateWithParam(LOAD_STATE_WAITING_FOR_DELEGATE,
-                              load_state_param_);
+  // The delegate_info_.empty() check allows |this| to report it's blocked on
+  // a delegate before it has been started.
+  if (calling_delegate_ || !delegate_info_.empty()) {
+    return LoadStateWithParam(
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        delegate_info_usage_ == DELEGATE_INFO_DISPLAY_TO_USER ?
+            UTF8ToUTF16(delegate_info_) : base::string16());
   }
   return LoadStateWithParam(job_.get() ? job_->GetLoadState() : LOAD_STATE_IDLE,
                             base::string16());
 }
 
+base::Value* URLRequest::GetStateAsValue() const {
+  DictionaryValue* dict = new DictionaryValue();
+  dict->SetString("url", original_url().possibly_invalid_spec());
+
+  if (url_chain_.size() > 1) {
+    ListValue* list = new ListValue();
+    for (std::vector<GURL>::const_iterator url = url_chain_.begin();
+         url != url_chain_.end(); ++url) {
+      list->AppendString(url->possibly_invalid_spec());
+    }
+    dict->Set("url_chain", list);
+  }
+
+  dict->SetInteger("load_flags", load_flags_);
+
+  LoadStateWithParam load_state = GetLoadState();
+  dict->SetInteger("load_state", load_state.state);
+  if (!load_state.param.empty())
+    dict->SetString("load_state_param", load_state.param);
+  if (!delegate_info_.empty())
+    dict->SetString("delegate_info", delegate_info_);
+
+  dict->SetString("method", method_);
+  dict->SetBoolean("has_upload", has_upload());
+  dict->SetBoolean("is_pending", is_pending_);
+
+  // Add the status of the request.  The status should always be IO_PENDING, and
+  // the error should always be OK, unless something is holding onto a request
+  // that has finished or a request was leaked.  Neither of these should happen.
+  switch (status_.status()) {
+    case URLRequestStatus::SUCCESS:
+      dict->SetString("status", "SUCCESS");
+      break;
+    case URLRequestStatus::IO_PENDING:
+      dict->SetString("status", "IO_PENDING");
+      break;
+    case URLRequestStatus::CANCELED:
+      dict->SetString("status", "CANCELED");
+      break;
+    case URLRequestStatus::FAILED:
+      dict->SetString("status", "FAILED");
+      break;
+  }
+  if (status_.error() != OK)
+    dict->SetInteger("net_error", status_.error());
+  return dict;
+}
+
+void URLRequest::SetDelegateInfo(const char* delegate_info,
+                                 DelegateInfoUsage delegate_info_usage) {
+  // Only log delegate information to NetLog during startup and certain
+  // deferring calls to delegates.  For all reads but the first, delegate info
+  // is currently ignored.
+  if (!calling_delegate_ && !response_info_.request_time.is_null())
+    return;
+
+  if (!delegate_info_.empty()) {
+    delegate_info_.clear();
+    net_log_.EndEvent(NetLog::TYPE_DELEGATE_INFO);
+  }
+  if (delegate_info) {
+    delegate_info_ = delegate_info;
+    delegate_info_usage_ = delegate_info_usage;
+    net_log_.BeginEvent(
+        NetLog::TYPE_DELEGATE_INFO,
+        NetLog::StringCallback("delegate_info", &delegate_info_));
+  }
+}
+
 UploadProgress URLRequest::GetUploadProgress() const {
   if (!job_.get()) {
     // We haven't started or the request was cancelled
@@ -539,6 +616,9 @@
 
 void URLRequest::Start() {
   DCHECK_EQ(network_delegate_, context_->network_delegate());
+  // Anything that set delegate information before start should have cleaned up
+  // after itself.
+  DCHECK(delegate_info_.empty());
 
   g_url_requests_started = true;
   response_info_.request_time = base::Time::Now();
@@ -549,14 +629,13 @@
 
   // Only notify the delegate for the initial request.
   if (network_delegate_) {
+    OnCallToDelegate();
     int error = network_delegate_->NotifyBeforeURLRequest(
         this, before_request_callback_, &delegate_redirect_url_);
-    if (error == net::ERR_IO_PENDING) {
-      // Paused on the delegate, will invoke |before_request_callback_| later.
-      SetBlockedOnDelegate();
-    } else {
+    // If ERR_IO_PENDING is returned, the delegate will invoke
+    // |before_request_callback_| later.
+    if (error != ERR_IO_PENDING)
       BeforeRequestComplete(error);
-    }
     return;
   }
 
@@ -574,8 +653,7 @@
   // Check that there are no callbacks to already canceled requests.
   DCHECK_NE(URLRequestStatus::CANCELED, status_.status());
 
-  if (blocked_on_delegate_)
-    SetUnblockedOnDelegate();
+  OnCallToDelegateComplete();
 
   if (error != OK) {
     std::string source("delegate");
@@ -658,6 +736,11 @@
 
 void URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
   DCHECK(error < 0);
+  // If cancelled while calling a delegate, clear delegate info.
+  if (calling_delegate_) {
+    SetDelegateInfo(NULL, DELEGATE_INFO_DEBUG_ONLY);
+    OnCallToDelegateComplete();
+  }
 
   // If the URL request already has an error status, then canceling is a no-op.
   // Plus, we don't want to change the error status once it has been set.
@@ -692,6 +775,10 @@
   DCHECK(bytes_read);
   *bytes_read = 0;
 
+  // If this is the first read, end the delegate call that may have started in
+  // OnResponseStarted.
+  OnCallToDelegateComplete();
+
   // This handles a cancel that happens while paused.
   // TODO(ahendrickson): DCHECK() that it is not done after
   // http://crbug.com/115705 is fixed.
@@ -732,6 +819,7 @@
   if (job) {
     RestartWithJob(job);
   } else if (delegate_) {
+    OnCallToDelegate();
     delegate_->OnReceivedRedirect(this, location, defer_redirect);
     // |this| may be have been destroyed here.
   }
@@ -762,6 +850,7 @@
       if (!has_notified_completion_ && !status_.is_success())
         NotifyRequestCompleted();
 
+      OnCallToDelegate();
       delegate_->OnResponseStarted(this);
       // Nothing may appear below this line as OnResponseStarted may delete
       // |this|.
@@ -837,6 +926,8 @@
 }
 
 int URLRequest::Redirect(const GURL& location, int http_status_code) {
+  // Matches call in NotifyReceivedRedirect.
+  OnCallToDelegateComplete();
   if (net_log_.IsLoggingAllEvents()) {
     net_log_.AddEvent(
         NetLog::TYPE_URL_REQUEST_REDIRECTED,
@@ -943,24 +1034,23 @@
       NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
   auth_info_ = auth_info;
   if (network_delegate_) {
+    OnCallToDelegate();
     rv = network_delegate_->NotifyAuthRequired(
         this,
         *auth_info,
         base::Bind(&URLRequest::NotifyAuthRequiredComplete,
                    base::Unretained(this)),
         &auth_credentials_);
+    if (rv == NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING)
+      return;
   }
 
-  if (rv == NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING) {
-    SetBlockedOnDelegate();
-  } else {
-    NotifyAuthRequiredComplete(rv);
-  }
+  NotifyAuthRequiredComplete(rv);
 }
 
 void URLRequest::NotifyAuthRequiredComplete(
     NetworkDelegate::AuthRequiredResponse result) {
-  SetUnblockedOnDelegate();
+  OnCallToDelegateComplete();
 
   // Check that there are no callbacks to already canceled requests.
   DCHECK_NE(URLRequestStatus::CANCELED, status_.status());
@@ -1085,22 +1175,20 @@
     network_delegate_->NotifyCompleted(this, job_.get() != NULL);
 }
 
-void URLRequest::SetBlockedOnDelegate() {
-  blocked_on_delegate_ = true;
-  if (!load_state_param_.empty()) {
-    net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE,
-                        NetLog::StringCallback("delegate", &load_state_param_));
-  } else {
-    net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE);
-  }
+void URLRequest::OnCallToDelegate() {
+  DCHECK(!calling_delegate_);
+  DCHECK(delegate_info_.empty());
+  calling_delegate_ = true;
+  net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
 }
 
-void URLRequest::SetUnblockedOnDelegate() {
-  if (!blocked_on_delegate_)
+void URLRequest::OnCallToDelegateComplete() {
+  // Delegates should clear their info when it becomes outdated.
+  DCHECK(delegate_info_.empty());
+  if (!calling_delegate_)
     return;
-  blocked_on_delegate_ = false;
-  load_state_param_.clear();
-  net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE);
+  calling_delegate_ = false;
+  net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
 }
 
 void URLRequest::set_stack_trace(const base::debug::StackTrace& stack_trace) {
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index a01656c..1145f63 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -37,10 +37,12 @@
 class URLRequestAutomationJob;
 
 namespace base {
+class Value;
+
 namespace debug {
 class StackTrace;
-}
-}
+}  // namespace debug
+}  // namespace base
 
 // Temporary layering violation to allow existing users of a deprecated
 // interface.
@@ -133,6 +135,15 @@
     NEVER_CLEAR_REFERRER,
   };
 
+  // Used with SetDelegateInfo to indicate how the string should be used.
+  // DELEGATE_INFO_DEBUG_ONLY indicates it should only be used when logged to
+  // NetLog, while DELEGATE_INFO_DISPLAY_TO_USER indicates it should also be
+  // returned by calls to GetLoadState for display to the user.
+  enum DelegateInfoUsage {
+    DELEGATE_INFO_DEBUG_ONLY,
+    DELEGATE_INFO_DISPLAY_TO_USER,
+  };
+
   // This class handles network interception.  Use with
   // (Un)RegisterRequestInterceptor.
   class NET_EXPORT Interceptor {
@@ -446,9 +457,19 @@
   // parameter describing details related to the load state. Not all load states
   // have a parameter.
   LoadStateWithParam GetLoadState() const;
-  void SetLoadStateParam(const base::string16& param) {
-    load_state_param_ = param;
-  }
+
+  // Returns a partial representation of the request's state as a value, for
+  // debugging.  Caller takes ownership of returned value.
+  base::Value* GetStateAsValue() const;
+
+  // Logs information about the delegate currently blocking the request.
+  // The delegate info must be cleared by sending NULL before resuming a
+  // request.  |delegate_info| will be copied as needed.  |delegate_info_usage|
+  // is used to indicate whether the value should be returned in the param field
+  // of GetLoadState.  |delegate_info_usage_| is ignored when |delegate_info| is
+  // NULL.
+  void SetDelegateInfo(const char* delegate_info,
+                       DelegateInfoUsage delegate_info_usage);
 
   // Returns the current upload progress in bytes. When the upload data is
   // chunked, size is set to zero, but position will not be.
@@ -754,10 +775,11 @@
                     CookieOptions* options) const;
   bool CanEnablePrivacyMode() const;
 
-  // Called when the delegate blocks or unblocks this request when intercepting
-  // certain requests.
-  void SetBlockedOnDelegate();
-  void SetUnblockedOnDelegate();
+  // Called just before calling a delegate that may block a request.
+  void OnCallToDelegate();
+  // Called when the delegate lets a request continue.  Also called on
+  // cancellation.
+  void OnCallToDelegateComplete();
 
   // Contextual information used for this request. Cannot be NULL. This contains
   // most of the dependencies which are shared between requests (disk cache,
@@ -824,13 +846,14 @@
   // A globally unique identifier for this request.
   const uint64 identifier_;
 
-  // True if this request is blocked waiting for the network delegate to resume
-  // it.
-  bool blocked_on_delegate_;
+  // True if this request is currently calling a delegate, or is blocked waiting
+  // for the URL request or network delegate to resume it.
+  bool calling_delegate_;
 
-  // An optional parameter that provides additional information about the load
-  // state. Only used with the LOAD_STATE_WAITING_FOR_DELEGATE state.
-  base::string16 load_state_param_;
+  // An optional parameter that provides additional information about the
+  // delegate |this| is currently blocked on.
+  std::string delegate_info_;
+  DelegateInfoUsage delegate_info_usage_;
 
   base::debug::LeakTracker<URLRequest> leak_tracker_;
 
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index 3909370..d98da02 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -119,7 +119,8 @@
   std::string raw_bytes;  // Empty on Windows means UTF-8 encoded name.
 #elif defined(OS_POSIX)
   // TOOD(jungshik): The same issue as for the directory name.
-  const std::string& raw_bytes = data.info.GetName().value();
+  base::FilePath filename = data.info.GetName();
+  const std::string& raw_bytes = filename.value();
 #endif
   data_.append(GetDirectoryListingEntry(
       data.info.GetName().LossyDisplayName(),
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 9d9a648..e6b39f6 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -439,15 +439,14 @@
 
 void URLRequestHttpJob::StartTransaction() {
   if (network_delegate()) {
+    OnCallToDelegate();
     int rv = network_delegate()->NotifyBeforeSendHeaders(
         request_, notify_before_headers_sent_callback_,
         &request_info_.extra_headers);
     // If an extension blocks the request, we rely on the callback to
     // MaybeStartTransactionInternal().
-    if (rv == ERR_IO_PENDING) {
-      SetBlockedOnDelegate();
+    if (rv == ERR_IO_PENDING)
       return;
-    }
     MaybeStartTransactionInternal(rv);
     return;
   }
@@ -455,8 +454,6 @@
 }
 
 void URLRequestHttpJob::NotifyBeforeSendHeadersCallback(int result) {
-  SetUnblockedOnDelegate();
-
   // Check that there are no callbacks to already canceled requests.
   DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
 
@@ -464,6 +461,7 @@
 }
 
 void URLRequestHttpJob::MaybeStartTransactionInternal(int result) {
+  OnCallToDelegateComplete();
   if (result == OK) {
     StartTransactionInternal();
   } else {
@@ -659,6 +657,9 @@
 }
 
 void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
+  // End of the call started in OnStartCompleted.
+  OnCallToDelegateComplete();
+
   if (result != net::OK) {
     std::string source("delegate");
     request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
@@ -867,6 +868,7 @@
       // Note that |this| may not be deleted until
       // |on_headers_received_callback_| or
       // |NetworkDelegate::URLRequestDestroyed()| has been called.
+      OnCallToDelegate();
       int error = network_delegate()->NotifyHeadersReceived(
           request_,
           on_headers_received_callback_,
@@ -875,12 +877,12 @@
       if (error != net::OK) {
         if (error == net::ERR_IO_PENDING) {
           awaiting_callback_ = true;
-          SetBlockedOnDelegate();
         } else {
           std::string source("delegate");
           request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
                                        NetLog::StringCallback("source",
                                                               &source));
+          OnCallToDelegateComplete();
           NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error));
         }
         return;
@@ -919,7 +921,6 @@
 }
 
 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
-  SetUnblockedOnDelegate();
   awaiting_callback_ = false;
 
   // Check that there are no callbacks to already canceled requests.
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index bf4aafc..1d6f0b4 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -204,8 +204,6 @@
   // It is also possible that FollowRedirect will drop the last reference to
   // this job, so we need to reset our members before calling it.
 
-  SetUnblockedOnDelegate();
-
   GURL redirect_url = deferred_redirect_url_;
   int redirect_status_code = deferred_redirect_status_code_;
 
@@ -336,7 +334,6 @@
       if (defer_redirect) {
         deferred_redirect_url_ = new_location;
         deferred_redirect_status_code_ = http_status_code;
-        SetBlockedOnDelegate();
       } else {
         FollowRedirect(new_location, http_status_code);
       }
@@ -488,12 +485,12 @@
     request_->Restart();
 }
 
-void URLRequestJob::SetBlockedOnDelegate() {
-  request_->SetBlockedOnDelegate();
+void URLRequestJob::OnCallToDelegate() {
+  request_->OnCallToDelegate();
 }
 
-void URLRequestJob::SetUnblockedOnDelegate() {
-  request_->SetUnblockedOnDelegate();
+void URLRequestJob::OnCallToDelegateComplete() {
+  request_->OnCallToDelegateComplete();
 }
 
 bool URLRequestJob::ReadRawData(IOBuffer* buf, int buf_size,
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 1acf475..9695f6a 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -260,10 +260,9 @@
   // Should only be called if the job has not started a resposne.
   void NotifyRestartRequired();
 
-  // Called when the network delegate blocks or unblocks this request when
-  // intercepting certain requests.
-  void SetBlockedOnDelegate();
-  void SetUnblockedOnDelegate();
+  // See corresponding functions in url_request.h.
+  void OnCallToDelegate();
+  void OnCallToDelegateComplete();
 
   // Called to read raw (pre-filtered) data from this Job.
   // If returning true, data was read from the job.  buf will contain
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index e0a32b3..31a07fe 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -36,9 +36,15 @@
 GURL URLRequestTestJob::test_url_3() {
   return GURL("test:url3");
 }
+GURL URLRequestTestJob::test_url_4() {
+  return GURL("test:url4");
+}
 GURL URLRequestTestJob::test_url_error() {
   return GURL("test:error");
 }
+GURL URLRequestTestJob::test_url_redirect_to_url_2() {
+  return GURL("test:redirect_to_2");
+}
 
 // static getters for known URL responses
 std::string URLRequestTestJob::test_data_1() {
@@ -50,6 +56,9 @@
 std::string URLRequestTestJob::test_data_3() {
   return std::string("<html><title>Test Three Three Three</title></html>");
 }
+std::string URLRequestTestJob::test_data_4() {
+  return std::string("<html><title>Test Four Four Four Four</title></html>");
+}
 
 // static getter for simple response headers
 std::string URLRequestTestJob::test_headers() {
@@ -69,6 +78,17 @@
   return std::string(kHeaders, arraysize(kHeaders));
 }
 
+// static getter for redirect response headers
+std::string URLRequestTestJob::test_redirect_to_url_2_headers() {
+  std::string headers = "HTTP/1.1 302 MOVED";
+  headers.push_back('\0');
+  headers += "Location: ";
+  headers += test_url_2().spec();
+  headers.push_back('\0');
+  headers.push_back('\0');
+  return headers;
+}
+
 // static getter for error response headers
 std::string URLRequestTestJob::test_error_headers() {
   static const char kHeaders[] =
@@ -162,6 +182,11 @@
       response_data_ = test_data_2();
     } else if (request_->url().spec() == test_url_3().spec()) {
       response_data_ = test_data_3();
+    } else if (request_->url().spec() == test_url_4().spec()) {
+      response_data_ = test_data_4();
+    } else if (request_->url().spec() == test_url_redirect_to_url_2().spec()) {
+      response_headers_ =
+          new HttpResponseHeaders(test_redirect_to_url_2_headers());
     } else {
       AdvanceJob();
 
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index d7f33d7..717cc0f 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -18,7 +18,7 @@
 // probably want to inherit from it to set up the state you want. Then install
 // it as the protocol handler for the "test" scheme.
 //
-// It will respond to three URLs, which you can retrieve using the test_url*
+// It will respond to several URLs, which you can retrieve using the test_url*
 // getters, which will in turn respond with the corresponding responses returned
 // by test_data*. Any other URLs that begin with "test:" will return an error,
 // which might also be useful, you can use test_url_error() to retreive a
@@ -57,18 +57,21 @@
                     const std::string& response_data,
                     bool auto_advance);
 
-  // The three canned URLs this handler will respond to without having been
+  // The canned URLs this handler will respond to without having been
   // explicitly initialized with response headers and data.
   // FIXME(brettw): we should probably also have a redirect one
   static GURL test_url_1();
   static GURL test_url_2();
   static GURL test_url_3();
+  static GURL test_url_4();
   static GURL test_url_error();
+  static GURL test_url_redirect_to_url_2();
 
   // The data that corresponds to each of the URLs above
   static std::string test_data_1();
   static std::string test_data_2();
   static std::string test_data_3();
+  static std::string test_data_4();
 
   // The headers that correspond to each of the URLs above
   static std::string test_headers();
@@ -76,6 +79,9 @@
   // The headers for a redirect response
   static std::string test_redirect_headers();
 
+  // The headers for a redirect response to the second test url.
+  static std::string test_redirect_to_url_2_headers();
+
   // The headers for a server error response
   static std::string test_error_headers();
 
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 6f5786e..08aa1b1 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -944,6 +944,43 @@
   NetModule::SetResourceProvider(NULL);
 }
 
+TEST_F(URLRequestTest, FileDirOutputSanity) {
+  // Verify the general sanity of the the output of the file:
+  // directory lister by checking for the output of a known existing
+  // file.
+  const char sentinel_name[] = "filedir-sentinel";
+
+  base::FilePath path;
+  PathService::Get(base::DIR_SOURCE_ROOT, &path);
+  path = path.Append(FILE_PATH_LITERAL("net"));
+  path = path.Append(FILE_PATH_LITERAL("data"));
+  path = path.Append(FILE_PATH_LITERAL("url_request_unittest"));
+
+  TestDelegate d;
+  URLRequest req(FilePathToFileURL(path), &d, &default_context_);
+  req.Start();
+  base::RunLoop().Run();
+
+  // Generate entry for the sentinel file.
+  base::FilePath sentinel_path = path.AppendASCII(sentinel_name);
+  base::PlatformFileInfo info;
+  EXPECT_TRUE(file_util::GetFileInfo(sentinel_path, &info));
+  EXPECT_GT(info.size, 0);
+  std::string sentinel_output = GetDirectoryListingEntry(
+      base::string16(sentinel_name, sentinel_name + strlen(sentinel_name)),
+      std::string(sentinel_name),
+      false /* is_dir */,
+      info.size,
+      info.last_modified);
+
+  ASSERT_LT(0, d.bytes_received());
+  ASSERT_FALSE(d.request_failed());
+  ASSERT_TRUE(req.status().is_success());
+  // Check for the entry generated for the "sentinel" file.
+  const std::string& data = d.data_received();
+  ASSERT_NE(data.find(sentinel_output), std::string::npos);
+}
+
 TEST_F(URLRequestTest, FileDirRedirectNoCrash) {
   // There is an implicit redirect when loading a file path that matches a
   // directory and does not end with a slash.  Ensure that following such
@@ -3548,6 +3585,682 @@
   EXPECT_EQ(destination_url, req.url_chain()[2]);
 }
 
+// First and second pieces of information logged by delegates to URLRequests.
+const char kFirstDelegateInfo[] = "Wonderful delegate";
+const char kSecondDelegateInfo[] = "Exciting delegate";
+
+// Logs delegate information to a URLRequest.  The first string is logged
+// synchronously on Start(), using DELEGATE_INFO_DEBUG_ONLY.  The second is
+// logged asynchronously, using DELEGATE_INFO_DISPLAY_TO_USER.  Then
+// another asynchronous call is used to clear the delegate information
+// before calling a callback.  The object then deletes itself.
+class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
+ public:
+  typedef base::Callback<void()> Callback;
+
+  // Each time delegate information is added to the URLRequest, the resulting
+  // load state is checked.  The expected load state after each request is
+  // passed in as an argument.
+  static void Run(URLRequest* url_request,
+                  LoadState expected_first_load_state,
+                  LoadState expected_second_load_state,
+                  LoadState expected_third_load_state,
+                  const Callback& callback) {
+    AsyncDelegateLogger* logger = new AsyncDelegateLogger(
+        url_request,
+        expected_first_load_state,
+        expected_second_load_state,
+        expected_third_load_state,
+        callback);
+    logger->Start();
+  }
+
+  // Checks that the log entries, starting with log_position, contain the
+  // DELEGATE_INFO NetLog events that an AsyncDelegateLogger should have
+  // recorded.  Returns the index of entry after the expected number of
+  // events this logged, or entries.size() if there aren't enough entries.
+  static size_t CheckDelegateInfo(
+      const CapturingNetLog::CapturedEntryList& entries, size_t log_position) {
+    // There should be 4 DELEGATE_INFO events: Two begins and two ends.
+    if (log_position + 3 >= entries.size()) {
+      ADD_FAILURE() << "Not enough log entries";
+      return entries.size();
+    }
+    std::string delegate_info;
+    EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_BEGIN, entries[log_position].phase);
+    EXPECT_TRUE(entries[log_position].GetStringValue("delegate_info",
+                                                     &delegate_info));
+    EXPECT_EQ(kFirstDelegateInfo, delegate_info);
+
+    ++log_position;
+    EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+    ++log_position;
+    EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_BEGIN, entries[log_position].phase);
+    EXPECT_TRUE(entries[log_position].GetStringValue("delegate_info",
+                                                     &delegate_info));
+    EXPECT_EQ(kSecondDelegateInfo, delegate_info);
+
+    ++log_position;
+    EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+    return log_position + 1;
+  }
+
+ private:
+  friend class base::RefCounted<AsyncDelegateLogger>;
+
+  AsyncDelegateLogger(URLRequest* url_request,
+                      LoadState expected_first_load_state,
+                      LoadState expected_second_load_state,
+                      LoadState expected_third_load_state,
+                      const Callback& callback)
+      : url_request_(url_request),
+        expected_first_load_state_(expected_first_load_state),
+        expected_second_load_state_(expected_second_load_state),
+        expected_third_load_state_(expected_third_load_state),
+        callback_(callback) {
+  }
+
+  ~AsyncDelegateLogger() {}
+
+  void Start() {
+    url_request_->SetDelegateInfo(kFirstDelegateInfo,
+                                  URLRequest::DELEGATE_INFO_DEBUG_ONLY);
+    LoadStateWithParam load_state = url_request_->GetLoadState();
+    EXPECT_EQ(expected_first_load_state_, load_state.state);
+    EXPECT_NE(ASCIIToUTF16(kFirstDelegateInfo), load_state.param);
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&AsyncDelegateLogger::LogSecondDelegate, this));
+  }
+
+  void LogSecondDelegate() {
+    url_request_->SetDelegateInfo(kSecondDelegateInfo,
+                                  URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+    LoadStateWithParam load_state = url_request_->GetLoadState();
+    EXPECT_EQ(expected_second_load_state_, load_state.state);
+    if (expected_second_load_state_ == LOAD_STATE_WAITING_FOR_DELEGATE) {
+      EXPECT_EQ(ASCIIToUTF16(kSecondDelegateInfo), load_state.param);
+    } else {
+      EXPECT_NE(ASCIIToUTF16(kSecondDelegateInfo), load_state.param);
+    }
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&AsyncDelegateLogger::LogComplete, this));
+  }
+
+  void LogComplete() {
+    url_request_->SetDelegateInfo(
+        NULL, URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+    LoadStateWithParam load_state = url_request_->GetLoadState();
+    EXPECT_EQ(expected_third_load_state_, load_state.state);
+    if (expected_second_load_state_ == LOAD_STATE_WAITING_FOR_DELEGATE)
+      EXPECT_EQ(string16(), load_state.param);
+    callback_.Run();
+  }
+
+  URLRequest* url_request_;
+  const int expected_first_load_state_;
+  const int expected_second_load_state_;
+  const int expected_third_load_state_;
+  const Callback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncDelegateLogger);
+};
+
+// NetworkDelegate that logs delegate information before a request is started,
+// before headers are sent, when headers are read, and when auth information
+// is requested.  Uses AsyncDelegateLogger.
+class AsyncLoggingNetworkDelegate : public TestNetworkDelegate {
+ public:
+  AsyncLoggingNetworkDelegate() {}
+  virtual ~AsyncLoggingNetworkDelegate() {}
+
+  // NetworkDelegate implementation.
+  virtual int OnBeforeURLRequest(URLRequest* request,
+                                 const CompletionCallback& callback,
+                                 GURL* new_url) OVERRIDE {
+    TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url);
+    return RunCallbackAsynchronously(request, callback);
+  }
+
+  virtual int OnBeforeSendHeaders(URLRequest* request,
+                                  const CompletionCallback& callback,
+                                  HttpRequestHeaders* headers) OVERRIDE {
+    TestNetworkDelegate::OnBeforeSendHeaders(request, callback, headers);
+    return RunCallbackAsynchronously(request, callback);
+  }
+
+  virtual int OnHeadersReceived(
+      URLRequest* request,
+      const CompletionCallback& callback,
+      const HttpResponseHeaders* original_response_headers,
+      scoped_refptr<HttpResponseHeaders>* override_response_headers) OVERRIDE {
+    TestNetworkDelegate::OnHeadersReceived(request, callback,
+                                           original_response_headers,
+                                           override_response_headers);
+    return RunCallbackAsynchronously(request, callback);
+  }
+
+  virtual NetworkDelegate::AuthRequiredResponse OnAuthRequired(
+      URLRequest* request,
+      const AuthChallengeInfo& auth_info,
+      const AuthCallback& callback,
+      AuthCredentials* credentials) OVERRIDE {
+    AsyncDelegateLogger::Run(
+        request,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        base::Bind(&AsyncLoggingNetworkDelegate::SetAuthAndResume,
+                   callback, credentials));
+    return AUTH_REQUIRED_RESPONSE_IO_PENDING;
+  }
+
+ private:
+  static int RunCallbackAsynchronously(
+      URLRequest* request,
+      const CompletionCallback& callback) {
+    AsyncDelegateLogger::Run(
+        request,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        base::Bind(callback, OK));
+    return ERR_IO_PENDING;
+  }
+
+  static void SetAuthAndResume(const AuthCallback& callback,
+                               AuthCredentials* credentials) {
+    *credentials = AuthCredentials(kUser, kSecret);
+    callback.Run(NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncLoggingNetworkDelegate);
+};
+
+// URLRequest::Delegate that logs delegate information when the headers
+// are received, when each read completes, and during redirects.  Uses
+// AsyncDelegateLogger.  Can optionally cancel a request in any phase.
+//
+// Inherits from TestDelegate to reuse the TestDelegate code to handle
+// advancing to the next step in most cases, as well as cancellation.
+class AsyncLoggingUrlRequestDelegate : public TestDelegate {
+ public:
+  enum CancelStage {
+    NO_CANCEL = 0,
+    CANCEL_ON_RECEIVED_REDIRECT,
+    CANCEL_ON_RESPONSE_STARTED,
+    CANCEL_ON_READ_COMPLETED
+  };
+
+  explicit AsyncLoggingUrlRequestDelegate(CancelStage cancel_stage)
+      : cancel_stage_(cancel_stage) {
+    if (cancel_stage == CANCEL_ON_RECEIVED_REDIRECT)
+      set_cancel_in_received_redirect(true);
+    else if (cancel_stage == CANCEL_ON_RESPONSE_STARTED)
+      set_cancel_in_response_started(true);
+    else if (cancel_stage == CANCEL_ON_READ_COMPLETED)
+      set_cancel_in_received_data(true);
+  }
+  virtual ~AsyncLoggingUrlRequestDelegate() {}
+
+  // URLRequest::Delegate implementation:
+  void virtual OnReceivedRedirect(URLRequest* request,
+                                  const GURL& new_url,
+                                  bool* defer_redirect) OVERRIDE {
+    *defer_redirect = true;
+    AsyncDelegateLogger::Run(
+        request,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        base::Bind(
+            &AsyncLoggingUrlRequestDelegate::OnReceivedRedirectLoggingComplete,
+            base::Unretained(this), request, new_url));
+  }
+
+  virtual void OnResponseStarted(URLRequest* request) OVERRIDE {
+    AsyncDelegateLogger::Run(
+      request,
+      LOAD_STATE_WAITING_FOR_DELEGATE,
+      LOAD_STATE_WAITING_FOR_DELEGATE,
+      LOAD_STATE_WAITING_FOR_DELEGATE,
+      base::Bind(
+          &AsyncLoggingUrlRequestDelegate::OnResponseStartedLoggingComplete,
+          base::Unretained(this), request));
+  }
+
+  virtual void OnReadCompleted(URLRequest* request,
+                               int bytes_read) OVERRIDE {
+    AsyncDelegateLogger::Run(
+        request,
+        LOAD_STATE_IDLE,
+        LOAD_STATE_IDLE,
+        LOAD_STATE_IDLE,
+        base::Bind(
+            &AsyncLoggingUrlRequestDelegate::AfterReadCompletedLoggingComplete,
+            base::Unretained(this), request, bytes_read));
+  }
+
+ private:
+  void OnReceivedRedirectLoggingComplete(URLRequest* request,
+                                         const GURL& new_url) {
+    bool defer_redirect = false;
+    TestDelegate::OnReceivedRedirect(request, new_url, &defer_redirect);
+    // FollowDeferredRedirect should not be called after cancellation.
+    if (cancel_stage_ == CANCEL_ON_RECEIVED_REDIRECT)
+      return;
+    if (!defer_redirect)
+      request->FollowDeferredRedirect();
+  }
+
+  void OnResponseStartedLoggingComplete(URLRequest* request) {
+    // The parent class continues the request.
+    TestDelegate::OnResponseStarted(request);
+  }
+
+  void AfterReadCompletedLoggingComplete(URLRequest* request, int bytes_read) {
+    // The parent class continues the request.
+    TestDelegate::OnReadCompleted(request, bytes_read);
+  }
+
+  const CancelStage cancel_stage_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncLoggingUrlRequestDelegate);
+};
+
+// Tests handling of delegate info before a request starts.
+TEST_F(URLRequestTestHTTP, DelegateInfoBeforeStart) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate request_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(NULL);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    URLRequest r(test_server_.GetURL("empty.html"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
+    EXPECT_EQ(string16(), load_state.param);
+
+    AsyncDelegateLogger::Run(
+        &r,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_WAITING_FOR_DELEGATE,
+        LOAD_STATE_IDLE,
+        base::Bind(&URLRequest::Start, base::Unretained(&r)));
+
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+  }
+
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+  size_t log_position = ExpectLogContainsSomewhereAfter(
+      entries,
+      0,
+      NetLog::TYPE_DELEGATE_INFO,
+      NetLog::PHASE_BEGIN);
+
+  log_position = AsyncDelegateLogger::CheckDelegateInfo(entries, log_position);
+
+  // Nothing else should add any delegate info to the request.
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+}
+
+// Tests handling of delegate info from a network delegate.
+TEST_F(URLRequestTestHTTP, NetworkDelegateInfo) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate request_delegate;
+  AsyncLoggingNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    URLRequest r(test_server_.GetURL("simple.html"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
+    EXPECT_EQ(string16(), load_state.param);
+
+    r.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+    EXPECT_EQ(1, network_delegate.created_requests());
+    EXPECT_EQ(0, network_delegate.destroyed_requests());
+  }
+  EXPECT_EQ(1, network_delegate.destroyed_requests());
+
+  size_t log_position = 0;
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+  for (size_t i = 0; i < 3; ++i) {
+    log_position = ExpectLogContainsSomewhereAfter(
+        entries,
+        log_position + 1,
+        NetLog::TYPE_URL_REQUEST_DELEGATE,
+        NetLog::PHASE_BEGIN);
+
+    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                          log_position + 1);
+
+    ASSERT_LT(log_position, entries.size());
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+  }
+
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+}
+
+// Tests handling of delegate info from a network delegate in the case of an
+// HTTP redirect.
+TEST_F(URLRequestTestHTTP, NetworkDelegateInfoRedirect) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate request_delegate;
+  AsyncLoggingNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    URLRequest r(test_server_.GetURL("server-redirect?simple.html"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
+    EXPECT_EQ(string16(), load_state.param);
+
+    r.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+    EXPECT_EQ(2, network_delegate.created_requests());
+    EXPECT_EQ(0, network_delegate.destroyed_requests());
+  }
+  EXPECT_EQ(1, network_delegate.destroyed_requests());
+
+  size_t log_position = 0;
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+  // The NetworkDelegate logged information in OnBeforeURLRequest,
+  // OnBeforeSendHeaders, and OnHeadersReceived.
+  for (size_t i = 0; i < 3; ++i) {
+    log_position = ExpectLogContainsSomewhereAfter(
+        entries,
+        log_position + 1,
+        NetLog::TYPE_URL_REQUEST_DELEGATE,
+        NetLog::PHASE_BEGIN);
+
+    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                          log_position + 1);
+
+    ASSERT_LT(log_position, entries.size());
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+  }
+
+  // The URLRequest::Delegate then gets informed about the redirect.
+  log_position = ExpectLogContainsSomewhereAfter(
+      entries,
+      log_position + 1,
+      NetLog::TYPE_URL_REQUEST_DELEGATE,
+      NetLog::PHASE_BEGIN);
+
+  // The NetworkDelegate logged information in the same three events as before.
+  for (size_t i = 0; i < 3; ++i) {
+    log_position = ExpectLogContainsSomewhereAfter(
+        entries,
+        log_position + 1,
+        NetLog::TYPE_URL_REQUEST_DELEGATE,
+        NetLog::PHASE_BEGIN);
+
+    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                          log_position + 1);
+
+    ASSERT_LT(log_position, entries.size());
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+  }
+
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+}
+
+// Tests handling of delegate info from a network delegate in the case of HTTP
+// AUTH.
+TEST_F(URLRequestTestHTTP, NetworkDelegateInfoAuth) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate request_delegate;
+  AsyncLoggingNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    URLRequest r(test_server_.GetURL("auth-basic"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
+    EXPECT_EQ(string16(), load_state.param);
+
+    r.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+    EXPECT_EQ(1, network_delegate.created_requests());
+    EXPECT_EQ(0, network_delegate.destroyed_requests());
+  }
+  EXPECT_EQ(1, network_delegate.destroyed_requests());
+
+  size_t log_position = 0;
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+  // The NetworkDelegate should have logged information in OnBeforeURLRequest,
+  // OnBeforeSendHeaders, OnHeadersReceived, OnAuthRequired, and then again in
+  // OnBeforeURLRequest and OnBeforeSendHeaders.
+  for (size_t i = 0; i < 6; ++i) {
+    log_position = ExpectLogContainsSomewhereAfter(
+        entries,
+        log_position + 1,
+        NetLog::TYPE_URL_REQUEST_DELEGATE,
+        NetLog::PHASE_BEGIN);
+
+    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                          log_position + 1);
+
+    ASSERT_LT(log_position, entries.size());
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+  }
+
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+}
+
+// Tests handling of delegate info from a URLRequest::Delegate.
+TEST_F(URLRequestTestHTTP, URLRequestDelegateInfo) {
+  ASSERT_TRUE(test_server_.Start());
+
+  AsyncLoggingUrlRequestDelegate request_delegate(
+      AsyncLoggingUrlRequestDelegate::NO_CANCEL);
+  TestURLRequestContext context(true);
+  context.set_network_delegate(NULL);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    // A chunked response with delays between chunks is used to make sure that
+    // attempts by the URLRequest delegate to log information while reading the
+    // body are ignored.  Since they are ignored, this test is robust against
+    // the possability of multiple reads being combined in the unlikely event
+    // that it occurs.
+    URLRequest r(test_server_.GetURL("chunked?waitBetweenChunks=20"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    r.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+  }
+
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+
+  // The delegate info should only have been logged on header complete.  Other
+  // times it should silently be ignored.
+
+  size_t log_position = ExpectLogContainsSomewhereAfter(
+          entries,
+          0,
+          NetLog::TYPE_URL_REQUEST_DELEGATE,
+          NetLog::PHASE_BEGIN);
+
+  log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                        log_position + 1);
+
+  ASSERT_LT(log_position, entries.size());
+  EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+  EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+}
+
+// Tests handling of delegate info from a URLRequest::Delegate in the case of
+// an HTTP redirect.
+TEST_F(URLRequestTestHTTP, URLRequestDelegateInfoOnRedirect) {
+  ASSERT_TRUE(test_server_.Start());
+
+  AsyncLoggingUrlRequestDelegate request_delegate(
+      AsyncLoggingUrlRequestDelegate::NO_CANCEL);
+  TestURLRequestContext context(true);
+  context.set_network_delegate(NULL);
+  context.set_net_log(&net_log_);
+  context.Init();
+
+  {
+    URLRequest r(test_server_.GetURL("server-redirect?simple.html"),
+                 &request_delegate, &context);
+    LoadStateWithParam load_state = r.GetLoadState();
+    r.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(200, r.GetResponseCode());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+  }
+
+  CapturingNetLog::CapturedEntryList entries;
+  net_log_.GetEntries(&entries);
+
+  // Delegate info should only have been logged in OnReceivedRedirect and
+  // OnResponseStarted.
+  size_t log_position = 0;
+  for (int i = 0; i < 2; ++i) {
+    log_position = ExpectLogContainsSomewhereAfter(
+            entries,
+            log_position,
+            NetLog::TYPE_URL_REQUEST_DELEGATE,
+            NetLog::PHASE_BEGIN);
+
+    log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                          log_position + 1);
+
+    ASSERT_LT(log_position, entries.size());
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+  }
+
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+  EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+      entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+}
+
+// Tests handling of delegate info from a URLRequest::Delegate in the case of
+// an HTTP redirect, with cancellation at various points.
+TEST_F(URLRequestTestHTTP, URLRequestDelegateOnRedirectCancelled) {
+  ASSERT_TRUE(test_server_.Start());
+
+  const AsyncLoggingUrlRequestDelegate::CancelStage kCancelStages[] = {
+    AsyncLoggingUrlRequestDelegate::CANCEL_ON_RECEIVED_REDIRECT,
+    AsyncLoggingUrlRequestDelegate::CANCEL_ON_RESPONSE_STARTED,
+    AsyncLoggingUrlRequestDelegate::CANCEL_ON_READ_COMPLETED,
+  };
+
+  for (size_t test_case = 0; test_case < arraysize(kCancelStages);
+       ++test_case) {
+    AsyncLoggingUrlRequestDelegate request_delegate(kCancelStages[test_case]);
+    TestURLRequestContext context(true);
+    CapturingNetLog net_log;
+    context.set_network_delegate(NULL);
+    context.set_net_log(&net_log);
+    context.Init();
+
+    {
+      URLRequest r(test_server_.GetURL("server-redirect?simple.html"),
+                   &request_delegate, &context);
+      LoadStateWithParam load_state = r.GetLoadState();
+      r.Start();
+      base::RunLoop().Run();
+      EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
+    }
+
+    CapturingNetLog::CapturedEntryList entries;
+    net_log.GetEntries(&entries);
+
+    // Delegate info is always logged in both OnReceivedRedirect and
+    // OnResponseStarted.  In the CANCEL_ON_RECEIVED_REDIRECT, the
+    // OnResponseStarted delegate call is after cancellation, but logging is
+    // still currently supported in that call.
+    size_t log_position = 0;
+    for (int i = 0; i < 2; ++i) {
+      log_position = ExpectLogContainsSomewhereAfter(
+              entries,
+              log_position,
+              NetLog::TYPE_URL_REQUEST_DELEGATE,
+              NetLog::PHASE_BEGIN);
+
+      log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
+                                                            log_position + 1);
+
+      ASSERT_LT(log_position, entries.size());
+      EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
+      EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+    }
+
+    EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+        entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+    EXPECT_FALSE(LogContainsEntryWithTypeAfter(
+        entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+  }
+}
+
 namespace {
 
 const char kExtraHeader[] = "Allow-Snafu";
diff --git a/net/websockets/README b/net/websockets/README
index bca38c9..ddd6f5b 100644
--- a/net/websockets/README
+++ b/net/websockets/README
@@ -35,6 +35,10 @@
 websocket_channel.cc
 websocket_channel.h
 websocket_channel_test.cc
+websocket_deflate_predictor.h
+websocket_deflate_predictor_impl.cc
+websocket_deflate_predictor_impl.h
+websocket_deflate_predictor_impl_test.cc
 websocket_deflate_stream.cc
 websocket_deflate_stream.h
 websocket_deflate_stream_test.cc
@@ -43,24 +47,24 @@
 websocket_deflater_test.cc
 websocket_errors.cc
 websocket_errors.h
+websocket_errors_test.cc
+websocket_event_interface.h
 websocket_extension.cc
 websocket_extension.h
 websocket_extension_parser.cc
 websocket_extension_parser.h
 websocket_extension_parser_test.cc
-websocket_errors_test.cc
-websocket_event_interface.h
 websocket_frame.cc
 websocket_frame.h
 websocket_frame_parser.cc
 websocket_frame_parser.h
 websocket_frame_parser_test.cc
 websocket_frame_test.cc
+websocket_handshake_stream_base.h
 websocket_inflater.cc
 websocket_inflater.h
 websocket_inflater_test.cc
 websocket_mux.h
-websocket_stream_base.h
 websocket_stream.cc
 websocket_stream.h
 websocket_test_util.cc
diff --git a/net/websockets/websocket_basic_stream.cc b/net/websockets/websocket_basic_stream.cc
index d3b1c40..fa598d0 100644
--- a/net/websockets/websocket_basic_stream.cc
+++ b/net/websockets/websocket_basic_stream.cc
@@ -50,8 +50,7 @@
   const int kMaximumTotalSize = std::numeric_limits<int>::max();
 
   int total_size = 0;
-  for (WebSocketFrameIterator it = frames->begin();
-       it != frames->end(); ++it) {
+  for (WebSocketFrameIterator it = frames->begin(); it != frames->end(); ++it) {
     WebSocketFrame* frame = *it;
     // Force the masked bit on.
     frame->header.masked = true;
@@ -137,8 +136,7 @@
 
   char* dest = combined_buffer->data();
   int remaining_size = total_size;
-  for (WebSocketFrameIterator it = frames->begin();
-       it != frames->end(); ++it) {
+  for (WebSocketFrameIterator it = frames->begin(); it != frames->end(); ++it) {
     WebSocketFrame* frame = *it;
     WebSocketMaskingKey mask = generate_websocket_masking_key_();
     int result =
@@ -173,22 +171,6 @@
 
 std::string WebSocketBasicStream::GetExtensions() const { return extensions_; }
 
-int WebSocketBasicStream::SendHandshakeRequest(
-    const GURL& url,
-    const HttpRequestHeaders& headers,
-    HttpResponseInfo* response_info,
-    const CompletionCallback& callback) {
-  // TODO(ricea): Implement handshake-related functionality.
-  NOTREACHED();
-  return ERR_NOT_IMPLEMENTED;
-}
-
-int WebSocketBasicStream::ReadHandshakeResponse(
-    const CompletionCallback& callback) {
-  NOTREACHED();
-  return ERR_NOT_IMPLEMENTED;
-}
-
 /*static*/
 scoped_ptr<WebSocketBasicStream>
 WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
diff --git a/net/websockets/websocket_basic_stream.h b/net/websockets/websocket_basic_stream.h
index a071e61..601a236 100644
--- a/net/websockets/websocket_basic_stream.h
+++ b/net/websockets/websocket_basic_stream.h
@@ -19,8 +19,6 @@
 class ClientSocketHandle;
 class DrainableIOBuffer;
 class GrowableIOBuffer;
-class HttpRequestHeaders;
-class HttpResponseInfo;
 class IOBufferWithSize;
 struct WebSocketFrame;
 struct WebSocketFrameChunk;
@@ -52,16 +50,6 @@
 
   virtual std::string GetExtensions() const OVERRIDE;
 
-  // Writes WebSocket handshake request HTTP-style to the connection. Adds
-  // "Sec-WebSocket-Key" header; this should not be included in |headers|.
-  virtual int SendHandshakeRequest(const GURL& url,
-                                   const HttpRequestHeaders& headers,
-                                   HttpResponseInfo* response_info,
-                                   const CompletionCallback& callback) OVERRIDE;
-
-  virtual int ReadHandshakeResponse(
-      const CompletionCallback& callback) OVERRIDE;
-
   ////////////////////////////////////////////////////////////////////////////
   // Methods for testing only.
 
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index c370bd7..8118611 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -8,8 +8,10 @@
 
 #include "base/basictypes.h"  // for size_t
 #include "base/bind.h"
+#include "base/compiler_specific.h"
 #include "base/safe_numerics.h"
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "net/base/big_endian.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_log.h"
@@ -26,6 +28,47 @@
 const int kDefaultSendQuotaLowWaterMark = 1 << 16;
 const int kDefaultSendQuotaHighWaterMark = 1 << 17;
 const size_t kWebSocketCloseCodeLength = 2;
+// This timeout is based on TCPMaximumSegmentLifetime * 2 from
+// MainThreadWebSocketChannel.cpp in Blink.
+const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
+
+typedef WebSocketEventInterface::ChannelState ChannelState;
+const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
+const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
+
+// Maximum close reason length = max control frame payload -
+//                               status code length
+//                             = 125 - 2
+const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength;
+
+// Check a close status code for strict compliance with RFC6455. This is only
+// used for close codes received from a renderer that we are intending to send
+// out over the network. See ParseClose() for the restrictions on incoming close
+// codes. The |code| parameter is type int for convenience of implementation;
+// the real type is uint16.
+bool IsStrictlyValidCloseStatusCode(int code) {
+  static const int kInvalidRanges[] = {
+      // [BAD, OK)
+      0,    1000,   // 1000 is the first valid code
+      1005, 1007,   // 1005 and 1006 MUST NOT be set.
+      1014, 3000,   // 1014 unassigned; 1015 up to 2999 are reserved.
+      5000, 65536,  // Codes above 5000 are invalid.
+  };
+  const int* const kInvalidRangesEnd =
+      kInvalidRanges + arraysize(kInvalidRanges);
+
+  DCHECK_GE(code, 0);
+  DCHECK_LT(code, 65536);
+  const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code);
+  DCHECK_NE(kInvalidRangesEnd, upper);
+  DCHECK_GT(upper, kInvalidRanges);
+  DCHECK_GT(*upper, code);
+  DCHECK_LE(*(upper - 1), code);
+  return ((upper - kInvalidRanges) % 2) == 0;
+}
+
+// This function avoids a bunch of boilerplate code.
+void AllowUnused(ChannelState ALLOW_UNUSED unused) {}
 
 }  // namespace
 
@@ -65,10 +108,12 @@
 
   virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
     creator_->OnConnectSuccess(stream.Pass());
+    // |this| may have been deleted.
   }
 
   virtual void OnFailure(uint16 websocket_error) OVERRIDE {
     creator_->OnConnectFailure(websocket_error);
+    // |this| has been deleted.
   }
 
  private:
@@ -89,6 +134,7 @@
       send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark),
       send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
       current_send_quota_(0),
+      timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
       closing_code_(0),
       state_(FRESHLY_CONSTRUCTED) {}
 
@@ -96,6 +142,9 @@
   // The stream may hold a pointer to read_frames_, and so it needs to be
   // destroyed first.
   stream_.reset();
+  // The timer may have a callback pointing back to us, so stop it just in case
+  // someone decides to run the event loop from their destructor.
+  timer_.Stop();
 }
 
 void WebSocketChannel::SendAddChannelRequest(
@@ -141,9 +190,10 @@
     return;
   }
   if (data.size() > base::checked_numeric_cast<size_t>(current_send_quota_)) {
-    FailChannel(SEND_GOING_AWAY,
-                kWebSocketMuxErrorSendQuotaViolation,
-                "Send quota exceeded");
+    AllowUnused(FailChannel(SEND_GOING_AWAY,
+                            kWebSocketMuxErrorSendQuotaViolation,
+                            "Send quota exceeded"));
+    // |this| is deleted here.
     return;
   }
   if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
@@ -160,7 +210,8 @@
   // TODO(ricea): For kOpCodeText, do UTF-8 validation?
   scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
   std::copy(data.begin(), data.end(), buffer->data());
-  SendIOBuffer(fin, op_code, buffer, data.size());
+  AllowUnused(SendIOBuffer(fin, op_code, buffer, data.size()));
+  // |this| may have been deleted.
 }
 
 void WebSocketChannel::SendFlowControl(int64 quota) {
@@ -180,9 +231,22 @@
     NOTREACHED() << "StartClosingHandshake() called in state " << state_;
     return;
   }
-  // TODO(ricea): Validate |code|? Check that |reason| is valid UTF-8?
-  // TODO(ricea): There should be a timeout for the closing handshake.
-  SendClose(code, reason);  // Sets state_ to SEND_CLOSED
+  // Javascript actually only permits 1000 and 3000-4999, but the implementation
+  // itself may produce different codes. The length of |reason| is also checked
+  // by Javascript.
+  if (!IsStrictlyValidCloseStatusCode(code) ||
+      reason.size() > kMaximumCloseReasonLength) {
+    // "InternalServerError" is actually used for errors from any endpoint, per
+    // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
+    // reason it must be malfunctioning in some way, and based on that we
+    // interpret this as an internal error.
+    AllowUnused(
+        SendClose(kWebSocketErrorInternalServerError, "Internal Error"));
+    // |this| may have been deleted.
+    return;
+  }
+  AllowUnused(SendClose(code, IsStringUTF8(reason) ? reason : std::string()));
+  // |this| may have been deleted.
 }
 
 void WebSocketChannel::SendAddChannelRequestForTesting(
@@ -190,10 +254,13 @@
     const std::vector<std::string>& requested_subprotocols,
     const GURL& origin,
     const WebSocketStreamFactory& factory) {
-  SendAddChannelRequestWithFactory(socket_url,
-                                   requested_subprotocols,
-                                   origin,
-                                   factory);
+  SendAddChannelRequestWithFactory(
+      socket_url, requested_subprotocols, origin, factory);
+}
+
+void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
+    base::TimeDelta delay) {
+  timeout_ = delay;
 }
 
 void WebSocketChannel::SendAddChannelRequestWithFactory(
@@ -219,41 +286,50 @@
   DCHECK_EQ(CONNECTING, state_);
   stream_ = stream.Pass();
   state_ = CONNECTED;
-  event_interface_->OnAddChannelResponse(false, stream_->GetSubProtocol());
+  if (event_interface_->OnAddChannelResponse(
+          false, stream_->GetSubProtocol()) == CHANNEL_DELETED)
+    return;
 
   // TODO(ricea): Get flow control information from the WebSocketStream once we
   // have a multiplexing WebSocketStream.
   current_send_quota_ = send_quota_high_water_mark_;
-  event_interface_->OnFlowControl(send_quota_high_water_mark_);
+  if (event_interface_->OnFlowControl(send_quota_high_water_mark_) ==
+      CHANNEL_DELETED)
+    return;
 
   // |stream_request_| is not used once the connection has succeeded.
   stream_request_.reset();
-  ReadFrames();
+  AllowUnused(ReadFrames());
+  // |this| may have been deleted.
 }
 
 void WebSocketChannel::OnConnectFailure(uint16 websocket_error) {
   DCHECK_EQ(CONNECTING, state_);
   state_ = CLOSED;
   stream_request_.reset();
-  event_interface_->OnAddChannelResponse(true, "");
+  AllowUnused(event_interface_->OnAddChannelResponse(true, ""));
+  // |this| has been deleted.
 }
 
-void WebSocketChannel::WriteFrames() {
+ChannelState WebSocketChannel::WriteFrames() {
   int result = OK;
   do {
     // This use of base::Unretained is safe because this object owns the
     // WebSocketStream and destroying it cancels all callbacks.
     result = stream_->WriteFrames(
         data_being_sent_->frames(),
-        base::Bind(
-            &WebSocketChannel::OnWriteDone, base::Unretained(this), false));
+        base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
+                   base::Unretained(this),
+                   false));
     if (result != ERR_IO_PENDING) {
-      OnWriteDone(true, result);
+      if (OnWriteDone(true, result) == CHANNEL_DELETED)
+        return CHANNEL_DELETED;
     }
   } while (result == OK && data_being_sent_);
+  return CHANNEL_ALIVE;
 }
 
-void WebSocketChannel::OnWriteDone(bool synchronous, int result) {
+ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
   DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
   DCHECK_NE(CONNECTING, state_);
   DCHECK_NE(ERR_IO_PENDING, result);
@@ -262,9 +338,8 @@
     case OK:
       if (data_to_send_next_) {
         data_being_sent_ = data_to_send_next_.Pass();
-        if (!synchronous) {
-          WriteFrames();
-        }
+        if (!synchronous)
+          return WriteFrames();
       } else {
         data_being_sent_.reset();
         if (current_send_quota_ < send_quota_low_water_mark_) {
@@ -279,10 +354,10 @@
           // server, if the protocol in use supports quota.
           int fresh_quota = send_quota_high_water_mark_ - current_send_quota_;
           current_send_quota_ += fresh_quota;
-          event_interface_->OnFlowControl(fresh_quota);
+          return event_interface_->OnFlowControl(fresh_quota);
         }
       }
-      return;
+      return CHANNEL_ALIVE;
 
     // If a recoverable error condition existed, it would go here.
 
@@ -290,16 +365,14 @@
       DCHECK_LT(result, 0)
           << "WriteFrames() should only return OK or ERR_ codes";
       stream_->Close();
-      if (state_ != CLOSED) {
-        state_ = CLOSED;
-        event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure,
-                                        "Abnormal Closure");
-      }
-      return;
+      DCHECK_NE(CLOSED, state_);
+      state_ = CLOSED;
+      return event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure,
+                                             "Abnormal Closure");
   }
 }
 
-void WebSocketChannel::ReadFrames() {
+ChannelState WebSocketChannel::ReadFrames() {
   int result = OK;
   do {
     // This use of base::Unretained is safe because this object owns the
@@ -307,15 +380,19 @@
     // destroyed.
     result = stream_->ReadFrames(
         &read_frames_,
-        base::Bind(
-            &WebSocketChannel::OnReadDone, base::Unretained(this), false));
+        base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone),
+                   base::Unretained(this),
+                   false));
     if (result != ERR_IO_PENDING) {
-      OnReadDone(true, result);
+      if (OnReadDone(true, result) == CHANNEL_DELETED)
+        return CHANNEL_DELETED;
     }
-  } while (result == OK && state_ != CLOSED);
+    DCHECK_NE(CLOSED, state_);
+  } while (result == OK);
+  return CHANNEL_ALIVE;
 }
 
-void WebSocketChannel::OnReadDone(bool synchronous, int result) {
+ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
   DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
   DCHECK_NE(CONNECTING, state_);
   DCHECK_NE(ERR_IO_PENDING, result);
@@ -328,74 +405,69 @@
       for (size_t i = 0; i < read_frames_.size(); ++i) {
         scoped_ptr<WebSocketFrame> frame(read_frames_[i]);
         read_frames_[i] = NULL;
-        ProcessFrame(frame.Pass());
+        if (ProcessFrame(frame.Pass()) == CHANNEL_DELETED)
+          return CHANNEL_DELETED;
       }
       read_frames_.clear();
       // There should always be a call to ReadFrames pending.
       // TODO(ricea): Unless we are out of quota.
-      if (!synchronous && state_ != CLOSED) {
-        ReadFrames();
-      }
-      return;
+      DCHECK_NE(CLOSED, state_);
+      if (!synchronous)
+        return ReadFrames();
+      return CHANNEL_ALIVE;
 
     case ERR_WS_PROTOCOL_ERROR:
-      FailChannel(SEND_REAL_ERROR,
-                  kWebSocketErrorProtocolError,
-                  "WebSocket Protocol Error");
-      return;
+      return FailChannel(SEND_REAL_ERROR,
+                         kWebSocketErrorProtocolError,
+                         "WebSocket Protocol Error");
 
     default:
       DCHECK_LT(result, 0)
           << "ReadFrames() should only return OK or ERR_ codes";
       stream_->Close();
-      if (state_ != CLOSED) {
-        state_ = CLOSED;
-        uint16 code = kWebSocketErrorAbnormalClosure;
-        std::string reason = "Abnormal Closure";
-        if (closing_code_ != 0) {
-          code = closing_code_;
-          reason = closing_reason_;
-        }
-        event_interface_->OnDropChannel(code, reason);
+      DCHECK_NE(CLOSED, state_);
+      state_ = CLOSED;
+      uint16 code = kWebSocketErrorAbnormalClosure;
+      std::string reason = "Abnormal Closure";
+      if (closing_code_ != 0) {
+        code = closing_code_;
+        reason = closing_reason_;
       }
-      return;
+      return event_interface_->OnDropChannel(code, reason);
   }
 }
 
-void WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) {
+ChannelState WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) {
   if (frame->header.masked) {
     // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
     // masked frame."
-    FailChannel(SEND_REAL_ERROR,
-                kWebSocketErrorProtocolError,
-                "Masked frame from server");
-    return;
+    return FailChannel(SEND_REAL_ERROR,
+                       kWebSocketErrorProtocolError,
+                       "Masked frame from server");
   }
   const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
   if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) &&
       !frame->header.final) {
-    FailChannel(SEND_REAL_ERROR,
-                kWebSocketErrorProtocolError,
-                "Control message with FIN bit unset received");
-    return;
+    return FailChannel(SEND_REAL_ERROR,
+                       kWebSocketErrorProtocolError,
+                       "Control message with FIN bit unset received");
   }
 
   // Respond to the frame appropriately to its type.
-  HandleFrame(
+  return HandleFrame(
       opcode, frame->header.final, frame->data, frame->header.payload_length);
 }
 
-void WebSocketChannel::HandleFrame(const WebSocketFrameHeader::OpCode opcode,
-                                   bool final,
-                                   const scoped_refptr<IOBuffer>& data_buffer,
-                                   size_t size) {
+ChannelState WebSocketChannel::HandleFrame(
+    const WebSocketFrameHeader::OpCode opcode,
+    bool final,
+    const scoped_refptr<IOBuffer>& data_buffer,
+    size_t size) {
   DCHECK_NE(RECV_CLOSED, state_)
       << "HandleFrame() does not support being called re-entrantly from within "
          "SendClose()";
-  if (state_ == CLOSED || state_ == CLOSE_WAIT) {
-    DVLOG_IF(1, state_ == CLOSED) << "A frame was received while in the CLOSED "
-                                     "state. This is possible after a channel "
-                                     "failed, but should be very rare.";
+  DCHECK_NE(CLOSED, state_);
+  if (state_ == CLOSE_WAIT) {
     std::string frame_name;
     switch (opcode) {
       case WebSocketFrameHeader::kOpCodeText:    // fall-thru
@@ -422,10 +494,9 @@
     }
     // SEND_REAL_ERROR makes no difference here, as FailChannel() won't send
     // another Close frame.
-    FailChannel(SEND_REAL_ERROR,
-                kWebSocketErrorProtocolError,
-                frame_name + " received after close");
-    return;
+    return FailChannel(SEND_REAL_ERROR,
+                       kWebSocketErrorProtocolError,
+                       frame_name + " received after close");
   }
   switch (opcode) {
     case WebSocketFrameHeader::kOpCodeText:    // fall-thru
@@ -444,26 +515,23 @@
         // cause of receiving very large chunks.
 
         // Sends the received frame to the renderer process.
-        event_interface_->OnDataFrame(final, opcode, data);
-      } else {
-        VLOG(3) << "Ignored data packet received in state " << state_;
+        return event_interface_->OnDataFrame(final, opcode, data);
       }
-      return;
+      VLOG(3) << "Ignored data packet received in state " << state_;
+      return CHANNEL_ALIVE;
 
     case WebSocketFrameHeader::kOpCodePing:
       VLOG(1) << "Got Ping of size " << size;
-      if (state_ == CONNECTED) {
-        SendIOBuffer(
+      if (state_ == CONNECTED)
+        return SendIOBuffer(
             true, WebSocketFrameHeader::kOpCodePong, data_buffer, size);
-      } else {
-        VLOG(3) << "Ignored ping in state " << state_;
-      }
-      return;
+      VLOG(3) << "Ignored ping in state " << state_;
+      return CHANNEL_ALIVE;
 
     case WebSocketFrameHeader::kOpCodePong:
       VLOG(1) << "Got Pong of size " << size;
       // There is no need to do anything with pong messages.
-      return;
+      return CHANNEL_ALIVE;
 
     case WebSocketFrameHeader::kOpCodeClose: {
       uint16 code = kWebSocketNormalClosure;
@@ -475,8 +543,11 @@
       switch (state_) {
         case CONNECTED:
           state_ = RECV_CLOSED;
-          SendClose(code, reason);  // Sets state_ to CLOSE_WAIT
-          event_interface_->OnClosingHandshake();
+          if (SendClose(code, reason) ==  // Sets state_ to CLOSE_WAIT
+              CHANNEL_DELETED)
+            return CHANNEL_DELETED;
+          if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
+            return CHANNEL_DELETED;
           closing_code_ = code;
           closing_reason_ = reason;
           break;
@@ -494,20 +565,20 @@
           LOG(DFATAL) << "Got Close in unexpected state " << state_;
           break;
       }
-      return;
+      return CHANNEL_ALIVE;
     }
 
     default:
-      FailChannel(
+      return FailChannel(
           SEND_REAL_ERROR, kWebSocketErrorProtocolError, "Unknown opcode");
-      return;
   }
 }
 
-void WebSocketChannel::SendIOBuffer(bool fin,
-                                    WebSocketFrameHeader::OpCode op_code,
-                                    const scoped_refptr<IOBuffer>& buffer,
-                                    size_t size) {
+ChannelState WebSocketChannel::SendIOBuffer(
+    bool fin,
+    WebSocketFrameHeader::OpCode op_code,
+    const scoped_refptr<IOBuffer>& buffer,
+    size_t size) {
   DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
   DCHECK(stream_);
   scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code));
@@ -524,20 +595,20 @@
     if (!data_to_send_next_)
       data_to_send_next_.reset(new SendBuffer);
     data_to_send_next_->AddFrame(frame.Pass());
-  } else {
-    data_being_sent_.reset(new SendBuffer);
-    data_being_sent_->AddFrame(frame.Pass());
-    WriteFrames();
+    return CHANNEL_ALIVE;
   }
+  data_being_sent_.reset(new SendBuffer);
+  data_being_sent_->AddFrame(frame.Pass());
+  return WriteFrames();
 }
 
-void WebSocketChannel::FailChannel(ExposeError expose,
-                                   uint16 code,
-                                   const std::string& reason) {
+ChannelState WebSocketChannel::FailChannel(ExposeError expose,
+                                           uint16 code,
+                                           const std::string& reason) {
   DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
   DCHECK_NE(CONNECTING, state_);
+  DCHECK_NE(CLOSED, state_);
   // TODO(ricea): Logging.
-  State old_state = state_;
   if (state_ == CONNECTED) {
     uint16 send_code = kWebSocketErrorGoingAway;
     std::string send_reason = "Internal Error";
@@ -545,7 +616,9 @@
       send_code = code;
       send_reason = reason;
     }
-    SendClose(send_code, send_reason);  // Sets state_ to SEND_CLOSED
+    if (SendClose(send_code, send_reason) ==  // Sets state_ to SEND_CLOSED
+        CHANNEL_DELETED)
+      return CHANNEL_DELETED;
   }
   // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
   // should close the connection itself without waiting for the closing
@@ -553,14 +626,13 @@
   stream_->Close();
   state_ = CLOSED;
 
-  if (old_state != CLOSED) {
-    event_interface_->OnDropChannel(code, reason);
-  }
+  return event_interface_->OnDropChannel(code, reason);
 }
 
-void WebSocketChannel::SendClose(uint16 code, const std::string& reason) {
+ChannelState WebSocketChannel::SendClose(uint16 code,
+                                         const std::string& reason) {
   DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
-  // TODO(ricea): Ensure reason.length() <= 123
+  DCHECK_LE(reason.size(), kMaximumCloseReasonLength);
   scoped_refptr<IOBuffer> body;
   size_t size = 0;
   if (code == kWebSocketErrorNoStatusReceived) {
@@ -577,8 +649,19 @@
     std::copy(
         reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
   }
-  SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size);
+  // This use of base::Unretained() is safe because we stop the timer in the
+  // destructor.
+  timer_.Start(
+      FROM_HERE,
+      timeout_,
+      base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
+  if (SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
+      CHANNEL_DELETED)
+    return CHANNEL_DELETED;
+  // SendIOBuffer() checks |state_|, so it is best not to change it until after
+  // SendIOBuffer() returns.
   state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT;
+  return CHANNEL_ALIVE;
 }
 
 void WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
@@ -611,11 +694,20 @@
     *code = kWebSocketErrorAbnormalClosure;
   }
   std::string text(data + kWebSocketCloseCodeLength, data + size);
-  // TODO(ricea): Is this check strict enough? In particular, check the
-  // "Security Considerations" from RFC3629.
+  // IsStringUTF8() blocks surrogate pairs and non-characters, so it is strictly
+  // stronger than required by RFC3629.
   if (IsStringUTF8(text)) {
     reason->swap(text);
   }
 }
 
+void WebSocketChannel::CloseTimeout() {
+  stream_->Close();
+  DCHECK_NE(CLOSED, state_);
+  state_ = CLOSED;
+  AllowUnused(event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure,
+                                              "Abnormal Closure"));
+  // |this| has been deleted.
+}
+
 }  // namespace net
diff --git a/net/websockets/websocket_channel.h b/net/websockets/websocket_channel.h
index d391f0e..9bd3623 100644
--- a/net/websockets/websocket_channel.h
+++ b/net/websockets/websocket_channel.h
@@ -10,9 +10,13 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/compiler_specific.h"  // for WARN_UNUSED_RESULT
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "net/base/net_export.h"
+#include "net/websockets/websocket_event_interface.h"
 #include "net/websockets/websocket_frame.h"
 #include "net/websockets/websocket_stream.h"
 #include "url/gurl.h"
@@ -22,7 +26,6 @@
 class BoundNetLog;
 class IOBuffer;
 class URLRequestContext;
-class WebSocketEventInterface;
 
 // Transport-independent implementation of WebSockets. Implements protocol
 // semantics that do not depend on the underlying transport. Provides the
@@ -93,7 +96,17 @@
       const GURL& origin,
       const WebSocketStreamFactory& factory);
 
+  // The default timout for the closing handshake is a sensible value (see
+  // kClosingHandshakeTimeoutSeconds in websocket_channel.cc). However, we can
+  // set it to a very small value for testing purposes.
+  void SetClosingHandshakeTimeoutForTesting(base::TimeDelta delay);
+
  private:
+  // Methods which return a value of type ChannelState may delete |this|. If the
+  // return value is CHANNEL_DELETED, then the caller must return without making
+  // any further access to member variables or methods.
+  typedef WebSocketEventInterface::ChannelState ChannelState;
+
   // The object passes through a linear progression of states from
   // FRESHLY_CONSTRUCTED to CLOSED, except that the SEND_CLOSED and RECV_CLOSED
   // states may be skipped in case of error.
@@ -135,55 +148,56 @@
       const WebSocketStreamFactory& factory);
 
   // Success callback from WebSocketStream::CreateAndConnectStream(). Reports
-  // success to the event interface.
+  // success to the event interface. May delete |this|.
   void OnConnectSuccess(scoped_ptr<WebSocketStream> stream);
 
   // Failure callback from WebSocketStream::CreateAndConnectStream(). Reports
-  // failure to the event interface.
+  // failure to the event interface. May delete |this|.
   void OnConnectFailure(uint16 websocket_error);
 
   // Returns true if state_ is SEND_CLOSED, CLOSE_WAIT or CLOSED.
   bool InClosingState() const;
 
   // Calls WebSocketStream::WriteFrames() with the appropriate arguments
-  void WriteFrames();
+  ChannelState WriteFrames() WARN_UNUSED_RESULT;
 
   // Callback from WebSocketStream::WriteFrames. Sends pending data or adjusts
   // the send quota of the renderer channel as appropriate. |result| is a net
   // error code, usually OK. If |synchronous| is true, then OnWriteDone() is
   // being called from within the WriteFrames() loop and does not need to call
   // WriteFrames() itself.
-  void OnWriteDone(bool synchronous, int result);
+  ChannelState OnWriteDone(bool synchronous, int result) WARN_UNUSED_RESULT;
 
   // Calls WebSocketStream::ReadFrames() with the appropriate arguments.
-  void ReadFrames();
+  ChannelState ReadFrames() WARN_UNUSED_RESULT;
 
   // Callback from WebSocketStream::ReadFrames. Handles any errors and processes
   // the returned chunks appropriately to their type. |result| is a net error
   // code. If |synchronous| is true, then OnReadDone() is being called from
   // within the ReadFrames() loop and does not need to call ReadFrames() itself.
-  void OnReadDone(bool synchronous, int result);
+  ChannelState OnReadDone(bool synchronous, int result) WARN_UNUSED_RESULT;
 
   // Processes a single frame that has been read from the stream.
-  void ProcessFrame(scoped_ptr<WebSocketFrame> frame);
+  ChannelState ProcessFrame(
+      scoped_ptr<WebSocketFrame> frame) WARN_UNUSED_RESULT;
 
   // Handles a frame that the object has received enough of to process. May call
   // |event_interface_| methods, send responses to the server, and change the
   // value of |state_|.
-  void HandleFrame(const WebSocketFrameHeader::OpCode opcode,
-                   bool final,
-                   const scoped_refptr<IOBuffer>& data_buffer,
-                   size_t size);
+  ChannelState HandleFrame(const WebSocketFrameHeader::OpCode opcode,
+                           bool final,
+                           const scoped_refptr<IOBuffer>& data_buffer,
+                           size_t size) WARN_UNUSED_RESULT;
 
   // Low-level method to send a single frame. Used for both data and control
   // frames. Either sends the frame immediately or buffers it to be scheduled
   // when the current write finishes. |fin| and |op_code| are defined as for
   // SendFrame() above, except that |op_code| may also be a control frame
   // opcode.
-  void SendIOBuffer(bool fin,
-                    WebSocketFrameHeader::OpCode op_code,
-                    const scoped_refptr<IOBuffer>& buffer,
-                    size_t size);
+  ChannelState SendIOBuffer(bool fin,
+                            WebSocketFrameHeader::OpCode op_code,
+                            const scoped_refptr<IOBuffer>& buffer,
+                            size_t size) WARN_UNUSED_RESULT;
 
   // Performs the "Fail the WebSocket Connection" operation as defined in
   // RFC6455. The supplied code and reason are sent back to the renderer in an
@@ -191,13 +205,18 @@
   // to the remote host. If |expose| is SEND_REAL_ERROR then the remote host is
   // given the same status code passed to the renderer; otherwise it is sent a
   // fixed "Going Away" code.  Closes the stream_ and sets state_ to CLOSED.
-  void FailChannel(ExposeError expose, uint16 code, const std::string& reason);
+  // FailChannel() always returns CHANNEL_DELETED. It is not valid to access any
+  // member variables or methods after calling FailChannel().
+  ChannelState FailChannel(ExposeError expose,
+                           uint16 code,
+                           const std::string& reason) WARN_UNUSED_RESULT;
 
   // Sends a Close frame to Start the WebSocket Closing Handshake, or to respond
   // to a Close frame from the server. As a special case, setting |code| to
   // kWebSocketErrorNoStatusReceived will create a Close frame with no payload;
   // this is symmetric with the behaviour of ParseClose.
-  void SendClose(uint16 code, const std::string& reason);
+  ChannelState SendClose(uint16 code,
+                         const std::string& reason) WARN_UNUSED_RESULT;
 
   // Parses a Close frame. If no status code is supplied, then |code| is set to
   // 1005 (No status code) with empty |reason|. If the supplied code is
@@ -209,6 +228,10 @@
                   uint16* code,
                   std::string* reason);
 
+  // Called if the closing handshake times out. Closes the connection and
+  // informs the |event_interface_| if appropriate.
+  void CloseTimeout();
+
   // The URL of the remote server.
   GURL socket_url_;
 
@@ -248,6 +271,12 @@
   // on this logical channel (quota units).
   int current_send_quota_;
 
+  // Timer for the closing handshake.
+  base::OneShotTimer<WebSocketChannel> timer_;
+
+  // Timeout for the closing handshake.
+  base::TimeDelta timeout_;
+
   // Storage for the status code and reason from the time the Close frame
   // arrives until the connection is closed and they are passed to
   // OnDropChannel().
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index e584860..083d99b 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -16,10 +16,12 @@
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/safe_numerics.h"
 #include "base/strings/string_piece.h"
 #include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
 #include "net/url_request/url_request_context.h"
 #include "net/websockets/websocket_errors.h"
 #include "net/websockets/websocket_event_interface.h"
@@ -84,7 +86,10 @@
 
 namespace {
 
+using ::base::TimeDelta;
+
 using ::testing::AnyNumber;
+using ::testing::DefaultValue;
 using ::testing::InSequence;
 using ::testing::MockFunction;
 using ::testing::Return;
@@ -116,29 +121,54 @@
 // kDefaultSendQuotaLowWaterMark change.
 const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;
 
+// TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world
+// in that time! I would like my tests to run a bit quicker.
+const int kVeryTinyTimeoutMillis = 1;
+
+typedef WebSocketEventInterface::ChannelState ChannelState;
+const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
+const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
+
+// This typedef mainly exists to avoid having to repeat the "NOLINT" incantation
+// all over the place.
+typedef MockFunction<void(int)> Checkpoint;  // NOLINT
+
 // This mock is for testing expectations about how the EventInterface is used.
 class MockWebSocketEventInterface : public WebSocketEventInterface {
  public:
-  MOCK_METHOD2(OnAddChannelResponse, void(bool, const std::string&));
+  MOCK_METHOD2(OnAddChannelResponse,
+               ChannelState(bool, const std::string&));  // NOLINT
   MOCK_METHOD3(OnDataFrame,
-               void(bool, WebSocketMessageType, const std::vector<char>&));
-  MOCK_METHOD1(OnFlowControl, void(int64));
-  MOCK_METHOD0(OnClosingHandshake, void(void));
-  MOCK_METHOD2(OnDropChannel, void(uint16, const std::string&));
+               ChannelState(bool,
+                            WebSocketMessageType,
+                            const std::vector<char>&));  // NOLINT
+  MOCK_METHOD1(OnFlowControl, ChannelState(int64));      // NOLINT
+  MOCK_METHOD0(OnClosingHandshake, ChannelState(void));  // NOLINT
+  MOCK_METHOD2(OnDropChannel,
+               ChannelState(uint16, const std::string&));  // NOLINT
 };
 
 // This fake EventInterface is for tests which need a WebSocketEventInterface
 // implementation but are not verifying how it is used.
 class FakeWebSocketEventInterface : public WebSocketEventInterface {
-  virtual void OnAddChannelResponse(
+  virtual ChannelState OnAddChannelResponse(
       bool fail,
-      const std::string& selected_protocol) OVERRIDE {}
-  virtual void OnDataFrame(bool fin,
-                           WebSocketMessageType type,
-                           const std::vector<char>& data) OVERRIDE {}
-  virtual void OnFlowControl(int64 quota) OVERRIDE {}
-  virtual void OnClosingHandshake() OVERRIDE {}
-  virtual void OnDropChannel(uint16 code, const std::string& reason) OVERRIDE {}
+      const std::string& selected_protocol) OVERRIDE {
+    return fail ? CHANNEL_DELETED : CHANNEL_ALIVE;
+  }
+  virtual ChannelState OnDataFrame(bool fin,
+                                   WebSocketMessageType type,
+                                   const std::vector<char>& data) OVERRIDE {
+    return CHANNEL_ALIVE;
+  }
+  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
+    return CHANNEL_ALIVE;
+  }
+  virtual ChannelState OnClosingHandshake() OVERRIDE { return CHANNEL_ALIVE; }
+  virtual ChannelState OnDropChannel(uint16 code,
+                                     const std::string& reason) OVERRIDE {
+    return CHANNEL_DELETED;
+  }
 };
 
 // This fake WebSocketStream is for tests that require a WebSocketStream but are
@@ -154,19 +184,6 @@
                       const std::string& extensions)
       : protocol_(protocol), extensions_(extensions) {}
 
-  virtual int SendHandshakeRequest(
-      const GURL& url,
-      const HttpRequestHeaders& headers,
-      HttpResponseInfo* response_info,
-      const CompletionCallback& callback) OVERRIDE {
-    return ERR_IO_PENDING;
-  }
-
-  virtual int ReadHandshakeResponse(
-      const CompletionCallback& callback) OVERRIDE {
-    return ERR_IO_PENDING;
-  }
-
   virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
     return ERR_IO_PENDING;
@@ -353,6 +370,27 @@
   return ::testing::MakeMatcher(new EqualsFramesMatcher<N>(&frames));
 }
 
+// TestClosure works like TestCompletionCallback, but doesn't take an argument.
+class TestClosure {
+ public:
+  base::Closure closure() { return base::Bind(callback_.callback(), OK); }
+
+  void WaitForResult() { callback_.WaitForResult(); }
+
+ private:
+  // Delegate to TestCompletionCallback for the implementation.
+  TestCompletionCallback callback_;
+};
+
+// A GoogleMock action to run a Closure.
+ACTION_P(InvokeClosure, closure) { closure.Run(); }
+
+// A GoogleMock action to run a Closure and return CHANNEL_DELETED.
+ACTION_P(InvokeClosureReturnDeleted, closure) {
+  closure.Run();
+  return WebSocketEventInterface::CHANNEL_DELETED;
+}
+
 // A FakeWebSocketStream whose ReadFrames() function returns data.
 class ReadableFakeWebSocketStream : public FakeWebSocketStream {
  public:
@@ -549,15 +587,28 @@
 // A FakeWebSocketStream where writes trigger a connection reset.
 // This differs from UnWriteableFakeWebSocketStream in that it is asynchronous
 // and triggers ReadFrames to return a reset as well. Tests using this need to
-// run the message loop.
+// run the message loop. There are two tricky parts here:
+// 1. Calling the write callback may call Close(), after which the read callback
+//    should not be called.
+// 2. Calling either callback may delete the stream altogether.
 class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
  public:
+  ResetOnWriteFakeWebSocketStream() : closed_(false), weak_ptr_factory_(this) {}
+
   virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                           const CompletionCallback& callback) OVERRIDE {
     base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(callback, ERR_CONNECTION_RESET));
+        FROM_HERE,
+        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   callback,
+                   ERR_CONNECTION_RESET));
     base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(read_callback_, ERR_CONNECTION_RESET));
+        FROM_HERE,
+        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   read_callback_,
+                   ERR_CONNECTION_RESET));
     return ERR_IO_PENDING;
   }
 
@@ -567,8 +618,19 @@
     return ERR_IO_PENDING;
   }
 
+  virtual void Close() OVERRIDE { closed_ = true; }
+
  private:
+  void CallCallbackUnlessClosed(const CompletionCallback& callback, int value) {
+    if (!closed_)
+      callback.Run(value);
+  }
+
   CompletionCallback read_callback_;
+  bool closed_;
+  // An IO error can result in the socket being deleted, so we use weak pointers
+  // to ensure correct behaviour in that case.
+  base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_;
 };
 
 // This mock is for verifying that WebSocket protocol semantics are obeyed (to
@@ -585,12 +647,6 @@
   MOCK_CONST_METHOD0(GetSubProtocol, std::string());
   MOCK_CONST_METHOD0(GetExtensions, std::string());
   MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
-  MOCK_METHOD4(SendHandshakeRequest,
-               int(const GURL& url,
-                   const HttpRequestHeaders& headers,
-                   HttpResponseInfo* response_info,
-                   const CompletionCallback& callback));
-  MOCK_METHOD1(ReadHandshakeResponse, int(const CompletionCallback& callback));
 };
 
 struct ArgumentCopyingWebSocketStreamFactory {
@@ -693,14 +749,41 @@
   scoped_ptr<WebSocketStream> stream_;
 };
 
+// enum of WebSocketEventInterface calls. These are intended to be or'd together
+// in order to instruct WebSocketChannelDeletingTest when it should fail.
+enum EventInterfaceCall {
+  EVENT_ON_ADD_CHANNEL_RESPONSE = 0x1,
+  EVENT_ON_DATA_FRAME = 0x2,
+  EVENT_ON_FLOW_CONTROL = 0x4,
+  EVENT_ON_CLOSING_HANDSHAKE = 0x8,
+  EVENT_ON_DROP_CHANNEL = 0x10,
+};
+
 class WebSocketChannelDeletingTest : public WebSocketChannelTest {
  public:
-  void ResetChannel() { channel_.reset(); }
+  ChannelState DeleteIfDeleting(EventInterfaceCall call) {
+    if (deleting_ & call) {
+      channel_.reset();
+      return CHANNEL_DELETED;
+    } else {
+      return CHANNEL_ALIVE;
+    }
+  }
 
  protected:
+  WebSocketChannelDeletingTest()
+      : deleting_(EVENT_ON_ADD_CHANNEL_RESPONSE | EVENT_ON_DATA_FRAME |
+                  EVENT_ON_FLOW_CONTROL |
+                  EVENT_ON_CLOSING_HANDSHAKE |
+                  EVENT_ON_DROP_CHANNEL) {}
   // Create a ChannelDeletingFakeWebSocketEventInterface. Defined out-of-line to
   // avoid circular dependency.
   virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE;
+
+  // Tests can set deleting_ to a bitmap of EventInterfaceCall members that they
+  // want to cause Channel deletion. The default is for all calls to cause
+  // deletion.
+  int deleting_;
 };
 
 // A FakeWebSocketEventInterface that deletes the WebSocketChannel on failure to
@@ -712,12 +795,29 @@
       WebSocketChannelDeletingTest* fixture)
       : fixture_(fixture) {}
 
-  virtual void OnAddChannelResponse(
+  virtual ChannelState OnAddChannelResponse(
       bool fail,
       const std::string& selected_protocol) OVERRIDE {
-    if (fail) {
-      fixture_->ResetChannel();
-    }
+    return fixture_->DeleteIfDeleting(EVENT_ON_ADD_CHANNEL_RESPONSE);
+  }
+
+  virtual ChannelState OnDataFrame(bool fin,
+                                   WebSocketMessageType type,
+                                   const std::vector<char>& data) OVERRIDE {
+    return fixture_->DeleteIfDeleting(EVENT_ON_DATA_FRAME);
+  }
+
+  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
+    return fixture_->DeleteIfDeleting(EVENT_ON_FLOW_CONTROL);
+  }
+
+  virtual ChannelState OnClosingHandshake() OVERRIDE {
+    return fixture_->DeleteIfDeleting(EVENT_ON_CLOSING_HANDSHAKE);
+  }
+
+  virtual ChannelState OnDropChannel(uint16 code,
+                                     const std::string& reason) OVERRIDE {
+    return fixture_->DeleteIfDeleting(EVENT_ON_DROP_CHANNEL);
   }
 
  private:
@@ -737,7 +837,17 @@
 class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
  protected:
   WebSocketChannelEventInterfaceTest()
-      : event_interface_(new StrictMock<MockWebSocketEventInterface>) {}
+      : event_interface_(new StrictMock<MockWebSocketEventInterface>) {
+    DefaultValue<ChannelState>::Set(CHANNEL_ALIVE);
+    ON_CALL(*event_interface_, OnAddChannelResponse(true, _))
+        .WillByDefault(Return(CHANNEL_DELETED));
+    ON_CALL(*event_interface_, OnDropChannel(_, _))
+        .WillByDefault(Return(CHANNEL_DELETED));
+  }
+
+  virtual ~WebSocketChannelEventInterfaceTest() {
+    DefaultValue<ChannelState>::Clear();
+  }
 
   // Tests using this fixture must set expectations on the event_interface_ mock
   // object before calling CreateChannelAndConnect() or
@@ -774,8 +884,7 @@
 
   CreateChannelAndConnect();
 
-  const ArgumentCopyingWebSocketStreamFactory& actual =
-      connect_data_.factory;
+  const ArgumentCopyingWebSocketStreamFactory& actual = connect_data_.factory;
 
   EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context);
 
@@ -785,18 +894,201 @@
   EXPECT_EQ(connect_data_.origin, actual.origin);
 }
 
-// The documentation for WebSocketEventInterface::OnAddChannelResponse() says
-// that if the first argument is true, ie. the connection failed, then we can
-// safely synchronously delete the WebSocketChannel. This test will only
-// reliably find problems if run with a memory debugger such as
-// AddressSanitizer.
-TEST_F(WebSocketChannelDeletingTest, DeletingFromOnAddChannelResponseWorks) {
+// Any WebSocketEventInterface methods can delete the WebSocketChannel and
+// return CHANNEL_DELETED. The WebSocketChannelDeletingTests are intended to
+// verify that there are no use-after-free bugs when this happens. Problems will
+// probably only be found when running under Address Sanitizer or a similar
+// tool.
+TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseFail) {
   CreateChannelAndConnect();
+  EXPECT_TRUE(channel_);
   connect_data_.factory.connect_delegate->OnFailure(
       kWebSocketErrorNoStatusReceived);
   EXPECT_EQ(NULL, channel_.get());
 }
 
+// Deletion is possible (due to IPC failure) even if the connect succeeds.
+TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseSuccess) {
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnDataFrameSync) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DATA_FRAME;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnDataFrameAsync) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DATA_FRAME;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_TRUE(channel_);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterConnect) {
+  deleting_ = EVENT_ON_FLOW_CONTROL;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterSend) {
+  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
+  // Avoid deleting the channel yet.
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  deleting_ = EVENT_ON_FLOW_CONTROL;
+  channel_->SendFrame(true,
+                      WebSocketFrameHeader::kOpCodeText,
+                      std::vector<char>(kDefaultInitialQuota, 'B'));
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeSync) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeAsync) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnDropChannelWriteError) {
+  set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  channel_->SendFrame(
+      true, WebSocketFrameHeader::kOpCodeText, AsVector("this will fail"));
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, OnDropChannelReadError) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
+                                 ERR_FAILED);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelInSendFrame) {
+  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  channel_->SendFrame(true,
+                      WebSocketFrameHeader::kOpCodeText,
+                      std::vector<char>(kDefaultInitialQuota * 2, 'T'));
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelInOnReadDone) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
+                                 ERR_WS_PROTOCOL_ERROR);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+  CreateChannelAndConnectSuccessfully();
+  ASSERT_TRUE(channel_);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelDueToMaskedFrame) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrame) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterClose) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+    {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
+     CLOSE_DATA(NORMAL_CLOSURE, "Success")},
+    {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
+TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCode) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, ""}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
+  set_stream(stream.Pass());
+  deleting_ = EVENT_ON_DROP_CHANNEL;
+
+  CreateChannelAndConnectSuccessfully();
+  EXPECT_EQ(NULL, channel_.get());
+}
+
 TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
   // false means success.
   EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, ""));
@@ -903,7 +1195,7 @@
       {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
   // We use this checkpoint object to verify that the callback isn't called
   // until we expect it to be.
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
   stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
   set_stream(stream.Pass());
   {
@@ -1191,7 +1483,7 @@
   set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
   // We use this checkpoint object to verify that the quota update comes after
   // the write.
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
@@ -1212,7 +1504,7 @@
 // Verify that our quota actually is refreshed when we are told it is.
 TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
   set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
@@ -1260,7 +1552,7 @@
 // If a write fails, the channel is dropped.
 TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
   set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
@@ -1366,6 +1658,69 @@
   base::MessageLoop::current()->RunUntilIdle();
 }
 
+// The closing handshake times out and sends an OnDropChannel event if no
+// response to the client Close message is received.
+TEST_F(WebSocketChannelEventInterfaceTest,
+       ClientInitiatedClosingHandshakeTimesOut) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
+                                 ERR_IO_PENDING);
+  set_stream(stream.Pass());
+  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
+  EXPECT_CALL(*event_interface_, OnFlowControl(_));
+  // This checkpoint object verifies that the OnDropChannel message comes after
+  // the timeout.
+  Checkpoint checkpoint;
+  TestClosure completion;
+  {
+    InSequence s;
+    EXPECT_CALL(checkpoint, Call(1));
+    EXPECT_CALL(*event_interface_,
+                OnDropChannel(kWebSocketErrorAbnormalClosure, _))
+        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
+  }
+  CreateChannelAndConnectSuccessfully();
+  // OneShotTimer is not very friendly to testing; there is no apparent way to
+  // set an expectation on it. Instead the tests need to infer that the timeout
+  // was fired by the behaviour of the WebSocketChannel object.
+  channel_->SetClosingHandshakeTimeoutForTesting(
+      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+  channel_->StartClosingHandshake(kWebSocketNormalClosure, "");
+  checkpoint.Call(1);
+  completion.WaitForResult();
+}
+
+// The closing handshake times out and sends an OnDropChannel event if a Close
+// message is received but the connection isn't closed by the remote host.
+TEST_F(WebSocketChannelEventInterfaceTest,
+       ServerInitiatedClosingHandshakeTimesOut) {
+  scoped_ptr<ReadableFakeWebSocketStream> stream(
+      new ReadableFakeWebSocketStream);
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
+  set_stream(stream.Pass());
+  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
+  EXPECT_CALL(*event_interface_, OnFlowControl(_));
+  Checkpoint checkpoint;
+  TestClosure completion;
+  {
+    InSequence s;
+    EXPECT_CALL(checkpoint, Call(1));
+    EXPECT_CALL(*event_interface_, OnClosingHandshake());
+    EXPECT_CALL(*event_interface_,
+                OnDropChannel(kWebSocketErrorAbnormalClosure, _))
+        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
+  }
+  CreateChannelAndConnectSuccessfully();
+  channel_->SetClosingHandshakeTimeoutForTesting(
+      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+  checkpoint.Call(1);
+  completion.WaitForResult();
+}
+
 // RFC6455 5.1 "a client MUST mask all frames that it sends to the server".
 // WebSocketChannel actually only sets the mask bit in the header, it doesn't
 // perform masking itself (not all transports actually use masking).
@@ -1435,7 +1790,7 @@
   ScopedVector<WebSocketFrame>* frames = NULL;
 
   // Use a checkpoint to make the ordering of events clearer.
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
@@ -1464,6 +1819,39 @@
   checkpoint.Call(3);
 }
 
+// Invalid close status codes should not be sent on the network.
+TEST_F(WebSocketChannelStreamTest, InvalidCloseStatusCodeNotSent) {
+  static const InitFrame expected[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       MASKED,      CLOSE_DATA(SERVER_ERROR, "Internal Error")}};
+
+  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+      .WillOnce(Return(ERR_IO_PENDING));
+
+  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));
+
+  CreateChannelAndConnectSuccessfully();
+  channel_->StartClosingHandshake(999, "");
+}
+
+// A Close frame with a reason longer than 123 bytes cannot be sent on the
+// network.
+TEST_F(WebSocketChannelStreamTest, LongCloseReasonNotSent) {
+  static const InitFrame expected[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       MASKED,      CLOSE_DATA(SERVER_ERROR, "Internal Error")}};
+
+  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+      .WillOnce(Return(ERR_IO_PENDING));
+
+  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));
+
+  CreateChannelAndConnectSuccessfully();
+  channel_->StartClosingHandshake(1000, std::string(124, 'A'));
+}
+
 // We generate code 1005, kWebSocketErrorNoStatusReceived, when there is no
 // status in the Close message from the other side. Code 1005 is not allowed to
 // appear on the wire, so we should not echo it back. See test
@@ -1554,7 +1942,7 @@
   static const InitFrame expected2[] = {
       {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}};
   CompletionCallback write_callback;
-  MockFunction<void(int)> checkpoint;
+  Checkpoint checkpoint;
 
   EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
   EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
@@ -1733,5 +2121,122 @@
   CreateChannelAndConnectSuccessfully();
 }
 
+// Set the closing handshake timeout to a very tiny value before connecting.
+class WebSocketChannelStreamTimeoutTest : public WebSocketChannelStreamTest {
+ protected:
+  WebSocketChannelStreamTimeoutTest() {}
+
+  virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
+    set_stream(mock_stream_.Pass());
+    CreateChannelAndConnect();
+    channel_->SetClosingHandshakeTimeoutForTesting(
+        TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+    connect_data_.factory.connect_delegate->OnSuccess(stream_.Pass());
+  }
+};
+
+// In this case the server initiates the closing handshake with a Close
+// message. WebSocketChannel responds with a matching Close message, and waits
+// for the server to close the TCP/IP connection. The server never closes the
+// connection, so the closing handshake times out and WebSocketChannel closes
+// the connection itself.
+TEST_F(WebSocketChannelStreamTimeoutTest, ServerInitiatedCloseTimesOut) {
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  static const InitFrame expected[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+      .WillOnce(ReturnFrames(&frames))
+      .WillRepeatedly(Return(ERR_IO_PENDING));
+  Checkpoint checkpoint;
+  TestClosure completion;
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
+        .WillOnce(Return(OK));
+    EXPECT_CALL(checkpoint, Call(1));
+    EXPECT_CALL(*mock_stream_, Close())
+        .WillOnce(InvokeClosure(completion.closure()));
+  }
+
+  CreateChannelAndConnectSuccessfully();
+  checkpoint.Call(1);
+  completion.WaitForResult();
+}
+
+// In this case the client initiates the closing handshake by sending a Close
+// message. WebSocketChannel waits for a Close message in response from the
+// server. The server never responds to the Close message, so the closing
+// handshake times out and WebSocketChannel closes the connection.
+TEST_F(WebSocketChannelStreamTimeoutTest, ClientInitiatedCloseTimesOut) {
+  static const InitFrame expected[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+      .WillRepeatedly(Return(ERR_IO_PENDING));
+  TestClosure completion;
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
+        .WillOnce(Return(OK));
+    EXPECT_CALL(*mock_stream_, Close())
+        .WillOnce(InvokeClosure(completion.closure()));
+  }
+
+  CreateChannelAndConnectSuccessfully();
+  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
+  completion.WaitForResult();
+}
+
+// In this case the client initiates the closing handshake and the server
+// responds with a matching Close message. WebSocketChannel waits for the server
+// to close the TCP/IP connection, but it never does. The closing handshake
+// times out and WebSocketChannel closes the connection.
+TEST_F(WebSocketChannelStreamTimeoutTest, ConnectionCloseTimesOut) {
+  static const InitFrame expected[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  static const InitFrame frames[] = {
+      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
+       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
+  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
+  TestClosure completion;
+  ScopedVector<WebSocketFrame>* read_frames = NULL;
+  CompletionCallback read_callback;
+  {
+    InSequence s;
+    // Copy the arguments to ReadFrames so that the test can call the callback
+    // after it has send the close message.
+    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+        .WillOnce(DoAll(SaveArg<0>(&read_frames),
+                        SaveArg<1>(&read_callback),
+                        Return(ERR_IO_PENDING)));
+    // The first real event that happens is the client sending the Close
+    // message.
+    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
+        .WillOnce(Return(OK));
+    // The |read_frames| callback is called (from this test case) at this
+    // point. ReadFrames is called again by WebSocketChannel, waiting for
+    // ERR_CONNECTION_CLOSED.
+    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
+        .WillOnce(Return(ERR_IO_PENDING));
+    // The timeout happens and so WebSocketChannel closes the stream.
+    EXPECT_CALL(*mock_stream_, Close())
+        .WillOnce(InvokeClosure(completion.closure()));
+  }
+
+  CreateChannelAndConnectSuccessfully();
+  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
+  ASSERT_TRUE(read_frames);
+  // Provide the "Close" message from the server.
+  *read_frames = CreateFrameVector(frames);
+  read_callback.Run(OK);
+  completion.WaitForResult();
+}
+
 }  // namespace
 }  // namespace net
diff --git a/net/websockets/websocket_deflate_predictor.h b/net/websockets/websocket_deflate_predictor.h
new file mode 100644
index 0000000..c786d80
--- /dev/null
+++ b/net/websockets/websocket_deflate_predictor.h
@@ -0,0 +1,58 @@
+// Copyright 2013 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 NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_H_
+#define NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+struct WebSocketFrame;
+
+// WebSocketDeflatePredictor is an interface class used for judging whether
+// a WebSocketDeflateStream should compress a message or not.
+class NET_EXPORT_PRIVATE WebSocketDeflatePredictor {
+ public:
+  enum Result {
+    // Deflate and send the message.
+    DEFLATE,
+    // Do not deflate and send the original message.
+    DO_NOT_DEFLATE,
+    // Try compressing the message and send the smaller one of the original
+    // and the compressed message.
+    // Returning this result implies that the deflater is running on
+    // DoNotTakeOverContext mode and the entire message is visible.
+    TRY_DEFLATE,
+  };
+
+  virtual ~WebSocketDeflatePredictor() {}
+
+  // Predicts and returns whether the deflater should deflate the message
+  // which begins with |frames[frame_index]| or not.
+  // |frames[(frame_index + 1):]| consists of future frames if any.
+  // |frames[frame_index]| must be the first frame of a data message,
+  // but future frames may contain control message frames.
+  // |frames[frame_index]| cannot be recorded yet and all preceding
+  // data frames have to be already recorded when this method is called.
+  virtual Result Predict(const ScopedVector<WebSocketFrame>& frames,
+                         size_t frame_index) = 0;
+
+  // Records frame data for future prediction.
+  // Only data frames should be recorded. Do not pass control frames' data.
+  // All input data frames for the stream must be recorded in order.
+  virtual void RecordInputDataFrame(const WebSocketFrame* frame) = 0;
+
+  // Records frame data for future prediction.
+  // Only data frames should be recorded. Do not pass control frames' data.
+  // All data frames written by the stream must be recorded in order
+  // regardless of whether they are compressed or not.
+  virtual void RecordWrittenDataFrame(const WebSocketFrame* frame) = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_H_
diff --git a/net/websockets/websocket_deflate_predictor_impl.cc b/net/websockets/websocket_deflate_predictor_impl.cc
new file mode 100644
index 0000000..0d1a5c2
--- /dev/null
+++ b/net/websockets/websocket_deflate_predictor_impl.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 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 "net/websockets/websocket_deflate_predictor_impl.h"
+
+namespace net {
+
+typedef WebSocketDeflatePredictor::Result Result;
+
+Result WebSocketDeflatePredictorImpl::Predict(
+    const ScopedVector<WebSocketFrame>& frames,
+    size_t frame_index) {
+  return DEFLATE;
+}
+
+void WebSocketDeflatePredictorImpl::RecordInputDataFrame(
+    const WebSocketFrame* frame) {}
+
+void WebSocketDeflatePredictorImpl::RecordWrittenDataFrame(
+    const WebSocketFrame* frame) {}
+
+}  // namespace net
diff --git a/net/websockets/websocket_deflate_predictor_impl.h b/net/websockets/websocket_deflate_predictor_impl.h
new file mode 100644
index 0000000..88a919c
--- /dev/null
+++ b/net/websockets/websocket_deflate_predictor_impl.h
@@ -0,0 +1,31 @@
+// Copyright 2013 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 NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_IMPL_H_
+#define NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
+#include "net/base/net_export.h"
+#include "net/websockets/websocket_deflate_predictor.h"
+
+namespace net {
+
+struct WebSocketFrame;
+
+class NET_EXPORT_PRIVATE WebSocketDeflatePredictorImpl
+    : public WebSocketDeflatePredictor {
+ public:
+  virtual ~WebSocketDeflatePredictorImpl() {}
+
+  virtual Result Predict(const ScopedVector<WebSocketFrame>& frames,
+                         size_t frame_index) OVERRIDE;
+  virtual void RecordInputDataFrame(const WebSocketFrame* frame) OVERRIDE;
+  virtual void RecordWrittenDataFrame(const WebSocketFrame* frame) OVERRIDE;
+};
+
+}  // namespace net
+
+#endif  // NET_WEBSOCKETS_WEBSOCKET_DEFLATE_PREDICTOR_IMPL_H_
diff --git a/net/websockets/websocket_deflate_predictor_impl_test.cc b/net/websockets/websocket_deflate_predictor_impl_test.cc
new file mode 100644
index 0000000..79c54e1
--- /dev/null
+++ b/net/websockets/websocket_deflate_predictor_impl_test.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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 "net/websockets/websocket_deflate_predictor_impl.h"
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+#include "net/websockets/websocket_frame.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+typedef WebSocketDeflatePredictor::Result Result;
+
+TEST(WebSocketDeflatePredictorImpl, Predict) {
+  WebSocketDeflatePredictorImpl predictor;
+  ScopedVector<WebSocketFrame> frames;
+  frames.push_back(new WebSocketFrame(WebSocketFrameHeader::kOpCodeText));
+  Result result = predictor.Predict(frames, 0);
+
+  EXPECT_EQ(WebSocketDeflatePredictor::DEFLATE, result);
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/websockets/websocket_deflate_stream.cc b/net/websockets/websocket_deflate_stream.cc
index d4fe775..601670d 100644
--- a/net/websockets/websocket_deflate_stream.cc
+++ b/net/websockets/websocket_deflate_stream.cc
@@ -15,6 +15,7 @@
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
+#include "net/websockets/websocket_deflate_predictor.h"
 #include "net/websockets/websocket_deflater.h"
 #include "net/websockets/websocket_errors.h"
 #include "net/websockets/websocket_frame.h"
@@ -33,14 +34,17 @@
 }  // namespace
 
 WebSocketDeflateStream::WebSocketDeflateStream(
-    scoped_ptr<WebSocketStream> stream)
+    scoped_ptr<WebSocketStream> stream,
+    WebSocketDeflater::ContextTakeOverMode mode,
+    scoped_ptr<WebSocketDeflatePredictor> predictor)
     : stream_(stream.Pass()),
-      deflater_(WebSocketDeflater::TAKE_OVER_CONTEXT),
+      deflater_(mode),
       inflater_(kChunkSize, kChunkSize),
       reading_state_(NOT_READING),
       writing_state_(NOT_WRITING),
       current_reading_opcode_(WebSocketFrameHeader::kOpCodeText),
-      current_writing_opcode_(WebSocketFrameHeader::kOpCodeText) {
+      current_writing_opcode_(WebSocketFrameHeader::kOpCodeText),
+      predictor_(predictor.Pass()) {
   DCHECK(stream_);
   deflater_.Initialize(kWindowBits);
   inflater_.Initialize(kWindowBits);
@@ -72,9 +76,7 @@
   return stream_->WriteFrames(frames, callback);
 }
 
-void WebSocketDeflateStream::Close() {
-  stream_->Close();
-}
+void WebSocketDeflateStream::Close() { stream_->Close(); }
 
 std::string WebSocketDeflateStream::GetSubProtocol() const {
   return stream_->GetSubProtocol();
@@ -84,23 +86,6 @@
   return stream_->GetExtensions();
 }
 
-int WebSocketDeflateStream::SendHandshakeRequest(
-    const GURL& url,
-    const HttpRequestHeaders& headers,
-    HttpResponseInfo* response_info,
-    const CompletionCallback& callback) {
-  // TODO(yhirano) handshake related functions will be moved to somewhere.
-  NOTIMPLEMENTED();
-  return OK;
-}
-
-int WebSocketDeflateStream::ReadHandshakeResponse(
-    const CompletionCallback& callback) {
-  // TODO(yhirano) handshake related functions will be moved to somewhere.
-  NOTIMPLEMENTED();
-  return OK;
-}
-
 void WebSocketDeflateStream::OnReadComplete(
     ScopedVector<WebSocketFrame>* frames,
     const CompletionCallback& callback,
@@ -118,34 +103,32 @@
 
 int WebSocketDeflateStream::Deflate(ScopedVector<WebSocketFrame>* frames) {
   ScopedVector<WebSocketFrame> frames_to_write;
+  // Store frames of the currently processed message if writing_state_ equals to
+  // WRITING_POSSIBLY_COMPRESSED_MESSAGE.
+  ScopedVector<WebSocketFrame> frames_of_message;
   for (size_t i = 0; i < frames->size(); ++i) {
-    scoped_ptr<WebSocketFrame> frame((*frames)[i]);
-    (*frames)[i] = NULL;
-    DCHECK(!frame->header.reserved1);
-    if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode)) {
-      frames_to_write.push_back(frame.release());
+    DCHECK(!(*frames)[i]->header.reserved1);
+    if (!WebSocketFrameHeader::IsKnownDataOpCode((*frames)[i]->header.opcode)) {
+      frames_to_write.push_back((*frames)[i]);
+      (*frames)[i] = NULL;
       continue;
     }
+    if (writing_state_ == NOT_WRITING)
+      OnMessageStart(*frames, i);
 
-    if (writing_state_ == NOT_WRITING) {
-      current_writing_opcode_ = frame->header.opcode;
-      DCHECK(current_writing_opcode_ == WebSocketFrameHeader::kOpCodeText ||
-             current_writing_opcode_ == WebSocketFrameHeader::kOpCodeBinary);
-      // TODO(yhirano): For now, we unconditionally compress data messages.
-      // Further optimization is needed.
-      // http://crbug.com/163882
-      writing_state_ = WRITING_COMPRESSED_MESSAGE;
-    }
+    scoped_ptr<WebSocketFrame> frame((*frames)[i]);
+    (*frames)[i] = NULL;
+    predictor_->RecordInputDataFrame(frame.get());
+
     if (writing_state_ == WRITING_UNCOMPRESSED_MESSAGE) {
       if (frame->header.final)
         writing_state_ = NOT_WRITING;
+      predictor_->RecordWrittenDataFrame(frame.get());
       frames_to_write.push_back(frame.release());
       current_writing_opcode_ = WebSocketFrameHeader::kOpCodeContinuation;
     } else {
-      DCHECK_EQ(WRITING_COMPRESSED_MESSAGE, writing_state_);
-      if (frame->data &&
-          !deflater_.AddBytes(frame->data->data(),
-                              frame->header.payload_length)) {
+      if (frame->data && !deflater_.AddBytes(frame->data->data(),
+                                             frame->header.payload_length)) {
         DVLOG(1) << "WebSocket protocol error. "
                  << "deflater_.AddBytes() returns an error.";
         return ERR_WS_PROTOCOL_ERROR;
@@ -155,35 +138,135 @@
                  << "deflater_.Finish() returns an error.";
         return ERR_WS_PROTOCOL_ERROR;
       }
-      if (deflater_.CurrentOutputSize() >= kChunkSize || frame->header.final) {
-        const WebSocketFrameHeader::OpCode opcode = current_writing_opcode_;
-        scoped_ptr<WebSocketFrame> compressed(new WebSocketFrame(opcode));
-        scoped_refptr<IOBufferWithSize> data =
-            deflater_.GetOutput(deflater_.CurrentOutputSize());
-        if (!data) {
-          DVLOG(1) << "WebSocket protocol error. "
-                   << "deflater_.GetOutput() returns an error.";
-          return ERR_WS_PROTOCOL_ERROR;
-        }
-        compressed->header.CopyFrom(frame->header);
-        compressed->header.opcode = opcode;
-        compressed->header.final = frame->header.final;
-        compressed->header.reserved1 =
-            (opcode != WebSocketFrameHeader::kOpCodeContinuation);
-        compressed->data = data;
-        compressed->header.payload_length = data->size();
 
-        current_writing_opcode_ = WebSocketFrameHeader::kOpCodeContinuation;
-        frames_to_write.push_back(compressed.release());
+      if (writing_state_ == WRITING_COMPRESSED_MESSAGE) {
+        if (deflater_.CurrentOutputSize() >= kChunkSize ||
+            frame->header.final) {
+          int result = AppendCompressedFrame(frame->header, &frames_to_write);
+          if (result != OK)
+            return result;
+        }
+        if (frame->header.final)
+          writing_state_ = NOT_WRITING;
+      } else {
+        DCHECK_EQ(WRITING_POSSIBLY_COMPRESSED_MESSAGE, writing_state_);
+        bool final = frame->header.final;
+        frames_of_message.push_back(frame.release());
+        if (final) {
+          int result = AppendPossiblyCompressedMessage(&frames_of_message,
+                                                       &frames_to_write);
+          if (result != OK)
+            return result;
+          frames_of_message.clear();
+          writing_state_ = NOT_WRITING;
+        }
       }
-      if (frame->header.final)
-        writing_state_ = NOT_WRITING;
     }
   }
+  DCHECK_NE(WRITING_POSSIBLY_COMPRESSED_MESSAGE, writing_state_);
   frames->swap(frames_to_write);
   return OK;
 }
 
+void WebSocketDeflateStream::OnMessageStart(
+    const ScopedVector<WebSocketFrame>& frames, size_t index) {
+  WebSocketFrame* frame = frames[index];
+  current_writing_opcode_ = frame->header.opcode;
+  DCHECK(current_writing_opcode_ == WebSocketFrameHeader::kOpCodeText ||
+         current_writing_opcode_ == WebSocketFrameHeader::kOpCodeBinary);
+  WebSocketDeflatePredictor::Result prediction =
+      predictor_->Predict(frames, index);
+
+  switch (prediction) {
+    case WebSocketDeflatePredictor::DEFLATE:
+      writing_state_ = WRITING_COMPRESSED_MESSAGE;
+      return;
+    case WebSocketDeflatePredictor::DO_NOT_DEFLATE:
+      writing_state_ = WRITING_UNCOMPRESSED_MESSAGE;
+      return;
+    case WebSocketDeflatePredictor::TRY_DEFLATE:
+      writing_state_ = WRITING_POSSIBLY_COMPRESSED_MESSAGE;
+      return;
+  }
+  NOTREACHED();
+}
+
+int WebSocketDeflateStream::AppendCompressedFrame(
+    const WebSocketFrameHeader& header,
+    ScopedVector<WebSocketFrame>* frames_to_write) {
+  const WebSocketFrameHeader::OpCode opcode = current_writing_opcode_;
+  scoped_refptr<IOBufferWithSize> compressed_payload =
+      deflater_.GetOutput(deflater_.CurrentOutputSize());
+  if (!compressed_payload) {
+    DVLOG(1) << "WebSocket protocol error. "
+             << "deflater_.GetOutput() returns an error.";
+    return ERR_WS_PROTOCOL_ERROR;
+  }
+  scoped_ptr<WebSocketFrame> compressed(new WebSocketFrame(opcode));
+  compressed->header.CopyFrom(header);
+  compressed->header.opcode = opcode;
+  compressed->header.final = header.final;
+  compressed->header.reserved1 =
+      (opcode != WebSocketFrameHeader::kOpCodeContinuation);
+  compressed->data = compressed_payload;
+  compressed->header.payload_length = compressed_payload->size();
+
+  current_writing_opcode_ = WebSocketFrameHeader::kOpCodeContinuation;
+  predictor_->RecordWrittenDataFrame(compressed.get());
+  frames_to_write->push_back(compressed.release());
+  return OK;
+}
+
+int WebSocketDeflateStream::AppendPossiblyCompressedMessage(
+    ScopedVector<WebSocketFrame>* frames,
+    ScopedVector<WebSocketFrame>* frames_to_write) {
+  DCHECK(!frames->empty());
+
+  const WebSocketFrameHeader::OpCode opcode = current_writing_opcode_;
+  scoped_refptr<IOBufferWithSize> compressed_payload =
+      deflater_.GetOutput(deflater_.CurrentOutputSize());
+  if (!compressed_payload) {
+    DVLOG(1) << "WebSocket protocol error. "
+             << "deflater_.GetOutput() returns an error.";
+    return ERR_WS_PROTOCOL_ERROR;
+  }
+
+  uint64 original_payload_length = 0;
+  for (size_t i = 0; i < frames->size(); ++i) {
+    WebSocketFrame* frame = (*frames)[i];
+    // Asserts checking that frames represent one whole data message.
+    DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode));
+    DCHECK_EQ(i == 0,
+              WebSocketFrameHeader::kOpCodeContinuation !=
+              frame->header.opcode);
+    DCHECK_EQ(i == frames->size() - 1, frame->header.final);
+    original_payload_length += frame->header.payload_length;
+  }
+  if (original_payload_length <=
+      static_cast<uint64>(compressed_payload->size())) {
+    // Compression is not effective. Use the original frames.
+    for (size_t i = 0; i < frames->size(); ++i) {
+      WebSocketFrame* frame = (*frames)[i];
+      frames_to_write->push_back(frame);
+      predictor_->RecordWrittenDataFrame(frame);
+      (*frames)[i] = NULL;
+    }
+    frames->weak_clear();
+    return OK;
+  }
+  scoped_ptr<WebSocketFrame> compressed(new WebSocketFrame(opcode));
+  compressed->header.CopyFrom((*frames)[0]->header);
+  compressed->header.opcode = opcode;
+  compressed->header.final = true;
+  compressed->header.reserved1 = true;
+  compressed->data = compressed_payload;
+  compressed->header.payload_length = compressed_payload->size();
+
+  predictor_->RecordWrittenDataFrame(compressed.get());
+  frames_to_write->push_back(compressed.release());
+  return OK;
+}
+
 int WebSocketDeflateStream::Inflate(ScopedVector<WebSocketFrame>* frames) {
   ScopedVector<WebSocketFrame> frames_to_output;
   ScopedVector<WebSocketFrame> frames_passed;
@@ -217,9 +300,8 @@
       frames_to_output.push_back(frame.release());
     } else {
       DCHECK_EQ(reading_state_, READING_COMPRESSED_MESSAGE);
-      if (frame->data &&
-          !inflater_.AddBytes(frame->data->data(),
-                              frame->header.payload_length)) {
+      if (frame->data && !inflater_.AddBytes(frame->data->data(),
+                                             frame->header.payload_length)) {
         DVLOG(1) << "WebSocket protocol error. "
                  << "inflater_.AddBytes() returns an error.";
         return ERR_WS_PROTOCOL_ERROR;
diff --git a/net/websockets/websocket_deflate_stream.h b/net/websockets/websocket_deflate_stream.h
index 224bfeb..a785944 100644
--- a/net/websockets/websocket_deflate_stream.h
+++ b/net/websockets/websocket_deflate_stream.h
@@ -21,16 +21,27 @@
 
 namespace net {
 
-class HttpRequestHeaders;
-class HttpResponseInfo;
+class WebSocketDeflatePredictor;
 
 // WebSocketDeflateStream is a WebSocketStream subclass.
 // WebSocketDeflateStream is for permessage-deflate WebSocket extension[1].
 //
+// WebSocketDeflateStream::ReadFrames and WriteFrames may change frame
+// boundary. In particular, if a control frame is placed in the middle of
+// data message frames, the control frame can overtake data frames.
+// Say there are frames df1, df2 and cf, df1 and df2 are frames of a
+// data message and cf is a control message frame. cf may arrive first and
+// data frames may follow cf.
+// Note that message boundary will be preserved, i.e. if the last frame of
+// a message m1 is read / written before the last frame of a message m2,
+// WebSocketDeflateStream will respect the order.
+//
 // [1]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-12
 class NET_EXPORT_PRIVATE WebSocketDeflateStream : public WebSocketStream {
  public:
-  explicit WebSocketDeflateStream(scoped_ptr<WebSocketStream> stream);
+  WebSocketDeflateStream(scoped_ptr<WebSocketStream> stream,
+                         WebSocketDeflater::ContextTakeOverMode mode,
+                         scoped_ptr<WebSocketDeflatePredictor> predictor);
   virtual ~WebSocketDeflateStream();
 
   // WebSocketStream functions.
@@ -41,12 +52,6 @@
   virtual void Close() OVERRIDE;
   virtual std::string GetSubProtocol() const OVERRIDE;
   virtual std::string GetExtensions() const OVERRIDE;
-  virtual int SendHandshakeRequest(const GURL& url,
-                                   const HttpRequestHeaders& headers,
-                                   HttpResponseInfo* response_info,
-                                   const CompletionCallback& callback) OVERRIDE;
-  virtual int ReadHandshakeResponse(const CompletionCallback& callback)
-      OVERRIDE;
 
  private:
   enum ReadingState {
@@ -58,6 +63,7 @@
   enum WritingState {
     WRITING_COMPRESSED_MESSAGE,
     WRITING_UNCOMPRESSED_MESSAGE,
+    WRITING_POSSIBLY_COMPRESSED_MESSAGE,
     NOT_WRITING,
   };
 
@@ -67,6 +73,12 @@
 
   // This function deflates |frames| and stores the result to |frames| itself.
   int Deflate(ScopedVector<WebSocketFrame>* frames);
+  void OnMessageStart(const ScopedVector<WebSocketFrame>& frames, size_t index);
+  int AppendCompressedFrame(const WebSocketFrameHeader& header,
+                            ScopedVector<WebSocketFrame>* frames_to_write);
+  int AppendPossiblyCompressedMessage(
+      ScopedVector<WebSocketFrame>* frames,
+      ScopedVector<WebSocketFrame>* frames_to_write);
 
   // This function inflates |frames| and stores the result to |frames| itself.
   int Inflate(ScopedVector<WebSocketFrame>* frames);
@@ -81,6 +93,7 @@
   WritingState writing_state_;
   WebSocketFrameHeader::OpCode current_reading_opcode_;
   WebSocketFrameHeader::OpCode current_writing_opcode_;
+  scoped_ptr<WebSocketDeflatePredictor> predictor_;
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketDeflateStream);
 };
diff --git a/net/websockets/websocket_deflate_stream_test.cc b/net/websockets/websocket_deflate_stream_test.cc
index 63955f1..1775962 100644
--- a/net/websockets/websocket_deflate_stream_test.cc
+++ b/net/websockets/websocket_deflate_stream_test.cc
@@ -5,6 +5,7 @@
 #include "net/websockets/websocket_deflate_stream.h"
 
 #include <stdint.h>
+#include <deque>
 #include <string>
 
 #include "base/basictypes.h"
@@ -15,7 +16,7 @@
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/http/http_request_headers.h"
+#include "net/websockets/websocket_deflate_predictor.h"
 #include "net/websockets/websocket_deflater.h"
 #include "net/websockets/websocket_frame.h"
 #include "net/websockets/websocket_inflater.h"
@@ -23,19 +24,15 @@
 #include "net/websockets/websocket_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
 
 namespace net {
-
-class HttpResponseInfo;
-
 namespace {
 
-typedef testing::MockFunction<void(int)> MockCallback;  // NOLINT
-using testing::_;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Return;
+typedef ::testing::MockFunction<void(int)> MockCallback;  // NOLINT
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
 
 typedef uint32_t FrameFlag;
 const FrameFlag kNoFlag = 0;
@@ -70,7 +67,7 @@
   return ToString(buffer.get(), size);
 }
 
-std::string ToString(WebSocketFrame* frame) {
+std::string ToString(const WebSocketFrame* frame) {
   return frame->data ? ToString(frame->data, frame->header.payload_length) : "";
 }
 
@@ -104,11 +101,109 @@
   MOCK_METHOD0(Close, void());
   MOCK_CONST_METHOD0(GetSubProtocol, std::string());
   MOCK_CONST_METHOD0(GetExtensions, std::string());
-  MOCK_METHOD4(SendHandshakeRequest, int(const GURL& url,
-                                         const HttpRequestHeaders& headers,
-                                         HttpResponseInfo* response_info,
-                                         const CompletionCallback& callback));
-  MOCK_METHOD1(ReadHandshakeResponse, int(const CompletionCallback& callback));
+};
+
+// This mock class relies on some assumptions.
+//  - RecordInputDataFrame is called after the corresponding WriteFrames
+//    call.
+//  - RecordWrittenDataFrame is called before writing the frame.
+class WebSocketDeflatePredictorMock : public WebSocketDeflatePredictor {
+ public:
+  WebSocketDeflatePredictorMock() : result_(DEFLATE) {}
+  virtual ~WebSocketDeflatePredictorMock() {
+    // Verify whether all expectaions are consumed.
+    if (!frames_to_be_input_.empty()) {
+      ADD_FAILURE() << "There are missing frames to be input.";
+      return;
+    }
+    if (!frames_written_.empty()) {
+      ADD_FAILURE() << "There are extra written frames.";
+      return;
+    }
+  }
+
+  // WebSocketDeflatePredictor functions.
+  virtual Result Predict(const ScopedVector<WebSocketFrame>& frames,
+                         size_t frame_index) OVERRIDE {
+    return result_;
+  }
+  virtual void RecordInputDataFrame(const WebSocketFrame* frame) OVERRIDE {
+    if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode)) {
+      ADD_FAILURE() << "Control frames should not be recorded.";
+      return;
+    }
+    if (frame->header.reserved1) {
+      ADD_FAILURE() << "Input frame may not be compressed.";
+      return;
+    }
+    if (frames_to_be_input_.empty()) {
+      ADD_FAILURE() << "Unexpected input data frame";
+      return;
+    }
+    if (frame != frames_to_be_input_.front()) {
+      ADD_FAILURE() << "Input data frame does not match the expectation.";
+      return;
+    }
+    frames_to_be_input_.pop_front();
+  }
+  virtual void RecordWrittenDataFrame(const WebSocketFrame* frame) OVERRIDE {
+    if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode)) {
+      ADD_FAILURE() << "Control frames should not be recorded.";
+      return;
+    }
+    frames_written_.push_back(frame);
+  }
+
+  // Sets |result_| for the |Predict| return value.
+  void set_result(Result result) { result_ = result; }
+
+  // Adds |frame| as an expectation of future |RecordInputDataFrame| call.
+  void AddFrameToBeInput(const WebSocketFrame* frame) {
+    if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode))
+      return;
+    frames_to_be_input_.push_back(frame);
+  }
+  // Verifies that |frame| is recorded in order.
+  void VerifySentFrame(const WebSocketFrame* frame) {
+    if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode))
+      return;
+    if (frames_written_.empty()) {
+      ADD_FAILURE() << "There are missing frames to be written.";
+      return;
+    }
+    if (frame != frames_written_.front()) {
+      ADD_FAILURE() << "Written data frame does not match the expectation.";
+      return;
+    }
+    frames_written_.pop_front();
+  }
+  void AddFramesToBeInput(const ScopedVector<WebSocketFrame>& frames) {
+    for (size_t i = 0; i < frames.size(); ++i)
+      AddFrameToBeInput(frames[i]);
+  }
+  void VerifySentFrames(const ScopedVector<WebSocketFrame>& frames) {
+    for (size_t i = 0; i < frames.size(); ++i)
+      VerifySentFrame(frames[i]);
+  }
+  // Call this method in order to disable checks in the destructor when
+  // WriteFrames fails.
+  void Clear() {
+    frames_to_be_input_.clear();
+    frames_written_.clear();
+  }
+
+ private:
+  Result result_;
+  // Data frames which will be recorded by |RecordInputFrames|.
+  // Pushed by |AddFrameToBeInput| and popped and verified by
+  // |RecordInputFrames|.
+  std::deque<const WebSocketFrame*> frames_to_be_input_;
+  // Data frames recorded by |RecordWrittenFrames|.
+  // Pushed by |RecordWrittenFrames| and popped and verified by
+  // |VerifySentFrame|.
+  std::deque<const WebSocketFrame*> frames_written_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebSocketDeflatePredictorMock);
 };
 
 class WebSocketDeflateStreamTest : public ::testing::Test {
@@ -116,15 +211,45 @@
   WebSocketDeflateStreamTest()
       : mock_stream_(NULL) {
     mock_stream_ = new testing::StrictMock<MockWebSocketStream>;
+    predictor_ = new WebSocketDeflatePredictorMock;
     deflate_stream_.reset(new WebSocketDeflateStream(
-        scoped_ptr<WebSocketStream>(mock_stream_)));
+        scoped_ptr<WebSocketStream>(mock_stream_),
+        WebSocketDeflater::TAKE_OVER_CONTEXT,
+        scoped_ptr<WebSocketDeflatePredictor>(predictor_)));
   }
   virtual ~WebSocketDeflateStreamTest() {}
 
  protected:
   scoped_ptr<WebSocketDeflateStream> deflate_stream_;
+  // Owned by |deflate_stream_|.
+  MockWebSocketStream* mock_stream_;
+  // Owned by |deflate_stream_|.
+  WebSocketDeflatePredictorMock* predictor_;
+};
+
+// Since WebSocketDeflater with DoNotTakeOverContext is well tested at
+// websocket_deflater_test.cc, we have only a few tests for this configuration
+// here.
+class WebSocketDeflateStreamWithDoNotTakeOverContextTest
+    : public ::testing::Test {
+ public:
+  WebSocketDeflateStreamWithDoNotTakeOverContextTest()
+      : mock_stream_(NULL) {
+    mock_stream_ = new testing::StrictMock<MockWebSocketStream>;
+    predictor_ = new WebSocketDeflatePredictorMock;
+    deflate_stream_.reset(new WebSocketDeflateStream(
+        scoped_ptr<WebSocketStream>(mock_stream_),
+        WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT,
+        scoped_ptr<WebSocketDeflatePredictor>(predictor_)));
+  }
+  virtual ~WebSocketDeflateStreamWithDoNotTakeOverContextTest() {}
+
+ protected:
+  scoped_ptr<WebSocketDeflateStream> deflate_stream_;
   // |mock_stream_| will be deleted when |deflate_stream_| is destroyed.
   MockWebSocketStream* mock_stream_;
+  // |predictor_| will be deleted when |deflate_stream_| is destroyed.
+  WebSocketDeflatePredictorMock* predictor_;
 };
 
 // ReadFrameStub is a stub for WebSocketStream::ReadFrames.
@@ -161,20 +286,21 @@
   ScopedVector<WebSocketFrame>* frames_passed_;
 };
 
-// WriteFrameStub is a stub for WebSocketStream::WriteFrames.
+// WriteFramesStub is a stub for WebSocketStream::WriteFrames.
 // It returns |result_| and |frames_| to the caller and
 // saves |callback| parameter to |callback_|.
 class WriteFramesStub {
  public:
-  explicit WriteFramesStub(int result) : result_(result) {}
+  explicit WriteFramesStub(WebSocketDeflatePredictorMock* predictor,
+                           int result)
+      : result_(result), predictor_(predictor) {}
 
   int Call(ScopedVector<WebSocketFrame>* frames,
            const CompletionCallback& callback) {
-    for (size_t i = 0; i < frames->size(); ++i) {
-      frames_.push_back((*frames)[i]);
-    }
+    frames_.insert(frames_.end(), frames->begin(), frames->end());
     frames->weak_clear();
     callback_ = callback;
+    predictor_->VerifySentFrames(frames_);
     return result_;
   }
 
@@ -186,6 +312,7 @@
   int result_;
   CompletionCallback callback_;
   ScopedVector<WebSocketFrame> frames_;
+  WebSocketDeflatePredictorMock* predictor_;
 };
 
 TEST_F(WebSocketDeflateStreamTest, ReadFailedImmediately) {
@@ -779,14 +906,17 @@
   }
 
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "hello");
+  predictor_->AddFramesToBeInput(frames);
   EXPECT_EQ(ERR_FAILED, deflate_stream_->WriteFrames(&frames, callback));
+  predictor_->Clear();
 }
 
 TEST_F(WebSocketDeflateStreamTest, WriteFrameImmediately) {
   ScopedVector<WebSocketFrame> frames;
   CompletionCallback callback;
-  WriteFramesStub stub(OK);
+  WriteFramesStub stub(predictor_, OK);
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  predictor_->AddFramesToBeInput(frames);
   {
     InSequence s;
     EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
@@ -803,7 +933,7 @@
 }
 
 TEST_F(WebSocketDeflateStreamTest, WriteFrameAsync) {
-  WriteFramesStub stub(ERR_IO_PENDING);
+  WriteFramesStub stub(predictor_, ERR_IO_PENDING);
   MockCallback mock_callback, checkpoint;
   CompletionCallback callback =
       base::Bind(&MockCallback::Call, base::Unretained(&mock_callback));
@@ -816,6 +946,7 @@
     EXPECT_CALL(mock_callback, Call(OK));
   }
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  predictor_->AddFramesToBeInput(frames);
   ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->WriteFrames(&frames, callback));
 
   checkpoint.Call(0);
@@ -835,7 +966,8 @@
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "Hel");
   AppendTo(&frames, WebSocketFrameHeader::kOpCodePing, kFinal);
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "lo");
-  WriteFramesStub stub(OK);
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
   CompletionCallback callback;
 
   {
@@ -859,7 +991,8 @@
 TEST_F(WebSocketDeflateStreamTest, WriteEmptyMessage) {
   ScopedVector<WebSocketFrame> frames;
   AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal);
-  WriteFramesStub stub(OK);
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
   CompletionCallback callback;
 
   {
@@ -876,10 +1009,39 @@
   EXPECT_EQ(std::string("\x02\x00", 2), ToString(frames_passed[0]));
 }
 
+TEST_F(WebSocketDeflateStreamTest, WriteUncompressedMessage) {
+  ScopedVector<WebSocketFrame> frames;
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "AAAA");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "AAA");
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
+  CompletionCallback callback;
+
+  predictor_->set_result(WebSocketDeflatePredictor::DO_NOT_DEFLATE);
+
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+        .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+  }
+  ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+  const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+  ASSERT_EQ(2u, frames_passed.size());
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+  EXPECT_FALSE(frames_passed[0]->header.final);
+  EXPECT_FALSE(frames_passed[0]->header.reserved1);
+  EXPECT_EQ("AAAA", ToString(frames_passed[0]));
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+            frames_passed[1]->header.opcode);
+  EXPECT_TRUE(frames_passed[1]->header.final);
+  EXPECT_FALSE(frames_passed[1]->header.reserved1);
+  EXPECT_EQ("AAA", ToString(frames_passed[1]));
+}
+
 TEST_F(WebSocketDeflateStreamTest, LargeDeflatedFramesShouldBeSplit) {
   WebSocketDeflater deflater(WebSocketDeflater::TAKE_OVER_CONTEXT);
   LinearCongruentialGenerator lcg(133);
-  WriteFramesStub stub(OK);
+  WriteFramesStub stub(predictor_, OK);
   CompletionCallback callback;
   const size_t size = 1024;
 
@@ -900,9 +1062,11 @@
     deflater.AddBytes(data.data(), data.size());
     FrameFlag flag = is_final ? kFinal : kNoFlag;
     AppendTo(&frames, WebSocketFrameHeader::kOpCodeBinary, flag, data);
+    predictor_->AddFramesToBeInput(frames);
     ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
-    for (size_t i = 0; i < stub.frames()->size(); ++i)
-      total_compressed_frames.push_back((*stub.frames())[i]);
+    total_compressed_frames.insert(total_compressed_frames.end(),
+                                   stub.frames()->begin(),
+                                   stub.frames()->end());
     stub.frames()->weak_clear();
     if (is_final)
       break;
@@ -929,6 +1093,114 @@
             ToString(deflater.GetOutput(deflater.CurrentOutputSize())));
 }
 
+TEST_F(WebSocketDeflateStreamTest, WriteMultipleMessages) {
+  ScopedVector<WebSocketFrame> frames;
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
+  CompletionCallback callback;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+        .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+  }
+  ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+  const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+  ASSERT_EQ(2u, frames_passed.size());
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+  EXPECT_TRUE(frames_passed[0]->header.final);
+  EXPECT_TRUE(frames_passed[0]->header.reserved1);
+  EXPECT_EQ(std::string("\xf2\x48\xcd\xc9\xc9\x07\x00", 7),
+            ToString(frames_passed[0]));
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[1]->header.opcode);
+  EXPECT_TRUE(frames_passed[1]->header.final);
+  EXPECT_TRUE(frames_passed[1]->header.reserved1);
+  EXPECT_EQ(std::string("\xf2\x00\x11\x00\x00", 5), ToString(frames_passed[1]));
+}
+
+TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
+       WriteMultipleMessages) {
+  ScopedVector<WebSocketFrame> frames;
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
+  CompletionCallback callback;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+        .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+  }
+  ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+  const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+  ASSERT_EQ(2u, frames_passed.size());
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+  EXPECT_TRUE(frames_passed[0]->header.final);
+  EXPECT_TRUE(frames_passed[0]->header.reserved1);
+  EXPECT_EQ(std::string("\xf2\x48\xcd\xc9\xc9\x07\x00", 7),
+            ToString(frames_passed[0]));
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[1]->header.opcode);
+  EXPECT_TRUE(frames_passed[1]->header.final);
+  EXPECT_TRUE(frames_passed[1]->header.reserved1);
+  EXPECT_EQ(std::string("\xf2\x48\xcd\xc9\xc9\x07\x00", 7),
+            ToString(frames_passed[1]));
+}
+
+// In order to check the stream works correctly for multiple
+// "PossiblyCompressedMessage"s, we test various messages at one test case.
+TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
+       WritePossiblyCompressMessages) {
+  ScopedVector<WebSocketFrame> frames;
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "He");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "llo");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "AAAAAAAAAA");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "AA");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "XX");
+  AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "YY");
+  predictor_->AddFramesToBeInput(frames);
+  WriteFramesStub stub(predictor_, OK);
+  CompletionCallback callback;
+  predictor_->set_result(WebSocketDeflatePredictor::TRY_DEFLATE);
+
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+        .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+  }
+  ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+  const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+  ASSERT_EQ(5u, frames_passed.size());
+
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+  EXPECT_FALSE(frames_passed[0]->header.final);
+  EXPECT_FALSE(frames_passed[0]->header.reserved1);
+  EXPECT_EQ("He", ToString(frames_passed[0]));
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+            frames_passed[1]->header.opcode);
+  EXPECT_TRUE(frames_passed[1]->header.final);
+  EXPECT_FALSE(frames_passed[1]->header.reserved1);
+  EXPECT_EQ("llo", ToString(frames_passed[1]));
+
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[2]->header.opcode);
+  EXPECT_TRUE(frames_passed[2]->header.final);
+  EXPECT_TRUE(frames_passed[2]->header.reserved1);
+  EXPECT_EQ(std::string("\x72\x74\x44\x00\x00\x00", 6),
+            ToString(frames_passed[2]));
+
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[3]->header.opcode);
+  EXPECT_FALSE(frames_passed[3]->header.final);
+  EXPECT_FALSE(frames_passed[3]->header.reserved1);
+  EXPECT_EQ("XX", ToString(frames_passed[3]));
+  EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+            frames_passed[4]->header.opcode);
+  EXPECT_TRUE(frames_passed[4]->header.final);
+  EXPECT_FALSE(frames_passed[4]->header.reserved1);
+  EXPECT_EQ("YY", ToString(frames_passed[4]));
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/websockets/websocket_event_interface.h b/net/websockets/websocket_event_interface.h
index 7eb54bf..baba88c 100644
--- a/net/websockets/websocket_event_interface.h
+++ b/net/websockets/websocket_event_interface.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/compiler_specific.h"  // for WARN_UNUSED_RESULT
 #include "net/base/net_export.h"
 
 namespace net {
@@ -18,35 +19,41 @@
 class NET_EXPORT WebSocketEventInterface {
  public:
   typedef int WebSocketMessageType;
+
+  // Any event can cause the Channel to be deleted. The Channel needs to avoid
+  // doing further processing in this case. It does not need to do cleanup, as
+  // cleanup will already have been done as a result of the deletion.
+  enum ChannelState {
+    CHANNEL_ALIVE,
+    CHANNEL_DELETED
+  };
+
   virtual ~WebSocketEventInterface() {}
   // Called in response to an AddChannelRequest. This generally means that a
   // response has been received from the remote server, but the response might
   // have been generated internally. If |fail| is true, the channel cannot be
-  // used and it is valid to delete the WebSocketChannel from within this
-  // callback.
-  virtual void OnAddChannelResponse(
+  // used and should be deleted, returning CHANNEL_DELETED.
+  virtual ChannelState OnAddChannelResponse(
       bool fail,
-      const std::string& selected_subprotocol) = 0;
+      const std::string& selected_subprotocol) WARN_UNUSED_RESULT = 0;
 
   // Called when a data frame has been received from the remote host and needs
-  // to be forwarded to the renderer process. It is not safe to delete the
-  // WebSocketChannel object from within this callback.
-  virtual void OnDataFrame(bool fin,
-                           WebSocketMessageType type,
-                           const std::vector<char>& data) = 0;
+  // to be forwarded to the renderer process.
+  virtual ChannelState OnDataFrame(
+      bool fin,
+      WebSocketMessageType type,
+      const std::vector<char>& data) WARN_UNUSED_RESULT = 0;
 
   // Called to provide more send quota for this channel to the renderer
   // process. Currently the quota units are always bytes of message body
-  // data. In future it might depend on the type of multiplexing in use. It is
-  // not safe to delete the WebSocketChannel from within this callback.
-  virtual void OnFlowControl(int64 quota) = 0;
+  // data. In future it might depend on the type of multiplexing in use.
+  virtual ChannelState OnFlowControl(int64 quota) WARN_UNUSED_RESULT = 0;
 
   // Called when the remote server has Started the WebSocket Closing
   // Handshake. The client should not attempt to send any more messages after
   // receiving this message. It will be followed by OnDropChannel() when the
-  // closing handshake is complete. It is not safe to delete the
-  // WebSocketChannel from within this callback.
-  virtual void OnClosingHandshake() = 0;
+  // closing handshake is complete.
+  virtual ChannelState OnClosingHandshake() WARN_UNUSED_RESULT = 0;
 
   // Called when the channel has been dropped, either due to a network close, a
   // network error, or a protocol error. This may or may not be preceeded by a
@@ -59,10 +66,10 @@
   // The channel should not be used again after OnDropChannel() has been
   // called.
   //
-  // It is not safe to delete the WebSocketChannel from within this
-  // callback. It is recommended to delete the channel after returning to the
-  // event loop.
-  virtual void OnDropChannel(uint16 code, const std::string& reason) = 0;
+  // This method returns a ChannelState for consistency, but all implementations
+  // must delete the Channel and return CHANNEL_DELETED.
+  virtual ChannelState OnDropChannel(uint16 code, const std::string& reason)
+      WARN_UNUSED_RESULT = 0;
 
  protected:
   WebSocketEventInterface() {}
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
index 0fd67f9..641b196 100644
--- a/net/websockets/websocket_handshake_handler.cc
+++ b/net/websockets/websocket_handshake_handler.cc
@@ -345,6 +345,16 @@
       static_cast<size_t>(original_header_length_) <= original_.size();
 }
 
+void ComputeSecWebSocketAccept(const std::string& key,
+                               std::string* accept) {
+  DCHECK(accept);
+
+  std::string hash =
+      base::SHA1HashString(key + websockets::kWebSocketGuid);
+  bool encode_success = base::Base64Encode(hash, accept);
+  DCHECK(encode_success);
+}
+
 bool WebSocketHandshakeResponseHandler::ParseResponseInfo(
     const HttpResponseInfo& response_info,
     const std::string& challenge) {
@@ -363,11 +373,8 @@
   AppendHeader(
       HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
 
-  std::string hash =
-      base::SHA1HashString(challenge + websockets::kWebSocketGuid);
   std::string websocket_accept;
-  bool encode_success = base::Base64Encode(hash, &websocket_accept);
-  DCHECK(encode_success);
+  ComputeSecWebSocketAccept(challenge, &websocket_accept);
   AppendHeader(
       websockets::kSecWebSocketAccept, websocket_accept, &response_message);
 
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h
index ee3749f..73af66d 100644
--- a/net/websockets/websocket_handshake_handler.h
+++ b/net/websockets/websocket_handshake_handler.h
@@ -23,6 +23,9 @@
 
 namespace net {
 
+void ComputeSecWebSocketAccept(const std::string& key,
+                               std::string* accept);
+
 class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler {
  public:
   WebSocketHandshakeRequestHandler();
diff --git a/net/websockets/websocket_handshake_stream_base.h b/net/websockets/websocket_handshake_stream_base.h
new file mode 100644
index 0000000..d81b626
--- /dev/null
+++ b/net/websockets/websocket_handshake_stream_base.h
@@ -0,0 +1,63 @@
+// Copyright 2013 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 NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_STREAM_BASE_H_
+#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_STREAM_BASE_H_
+
+// This file is included from net/http files.
+// Since net/http can be built without linking net/websockets code,
+// this file must not introduce any link-time dependencies on websockets.
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "net/http/http_stream_base.h"
+#include "net/websockets/websocket_stream.h"
+
+namespace net {
+
+class ClientSocketHandle;
+class SpdySession;
+
+// WebSocketHandshakeStreamBase is the base class of
+// WebSocketBasicHandshakeStream.  net/http code uses this interface to handle
+// WebSocketBasicHandshakeStream when it needs to be treated differently from
+// HttpStreamBase.
+class NET_EXPORT WebSocketHandshakeStreamBase : public HttpStreamBase {
+ public:
+  class Factory {
+   public:
+    virtual ~Factory() {}
+
+    // Create a WebSocketBasicHandshakeStream. This function (or the returned
+    // object) takes the ownership of |connection|. This is called after the
+    // underlying connection has been established but before any handshake data
+    // has been transferred.
+    virtual WebSocketHandshakeStreamBase* CreateBasicStream(
+        ClientSocketHandle* connection,
+        bool using_proxy) = 0;
+
+    // Create a WebSocketSpdyHandshakeStream (unimplemented as of October 2013)
+    virtual WebSocketHandshakeStreamBase* CreateSpdyStream(
+        const base::WeakPtr<SpdySession>& session,
+        bool use_relative_url) = 0;
+  };
+
+  virtual ~WebSocketHandshakeStreamBase() {}
+
+  // After the handshake has completed, this method creates a WebSocketStream
+  // (of the appropriate type) from the WebSocketHandshakeStreamBase object.
+  // The WebSocketHandshakeStreamBase object is unusable after Upgrade() has
+  // been called.
+  virtual scoped_ptr<WebSocketStream> Upgrade() = 0;
+
+ protected:
+  WebSocketHandshakeStreamBase() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeStreamBase);
+};
+
+}  // namespace net
+
+#endif  // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_STREAM_BASE_H_
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc
index b2d316b..9d1394c 100644
--- a/net/websockets/websocket_stream.cc
+++ b/net/websockets/websocket_stream.cc
@@ -27,6 +27,4 @@
   return make_scoped_ptr(new WebSocketStreamRequest());
 }
 
-WebSocketStream* WebSocketStream::AsWebSocketStream() { return this; }
-
 }  // namespace net
diff --git a/net/websockets/websocket_stream.h b/net/websockets/websocket_stream.h
index ca29f57..c5f6f97 100644
--- a/net/websockets/websocket_stream.h
+++ b/net/websockets/websocket_stream.h
@@ -14,15 +14,12 @@
 #include "base/memory/scoped_vector.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
-#include "net/websockets/websocket_stream_base.h"
 
 class GURL;
 
 namespace net {
 
 class BoundNetLog;
-class HttpRequestHeaders;
-class HttpResponseInfo;
 class URLRequestContext;
 struct WebSocketFrame;
 
@@ -49,7 +46,7 @@
 // |callback| will be called when the operation is finished. Non-null |callback|
 // must be provided to these functions.
 
-class NET_EXPORT_PRIVATE WebSocketStream : public WebSocketStreamBase {
+class NET_EXPORT_PRIVATE WebSocketStream {
  public:
   // A concrete object derived from ConnectDelegate is supplied by the caller to
   // CreateAndConnectStream() to receive the result of the connection.
@@ -122,6 +119,12 @@
   // ReadFrames may discard the incomplete frame. Since the renderer will
   // discard any incomplete messages when the connection is closed, this makes
   // no difference to the overall semantics.
+  //
+  // Implementations of ReadFrames() must be able to handle being deleted during
+  // the execution of callback.Run(). In practice this means that the method
+  // calling callback.Run() (and any calling methods in the same object) must
+  // return immediately without any further method calls or access to member
+  // variables. Implementors should write test(s) for this case.
   virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) = 0;
 
@@ -134,6 +137,11 @@
   //
   // This method will only return OK if all frames were written completely.
   // Otherwise it will return an appropriate net error code.
+  //
+  // The callback implementation is permitted to delete this
+  // object. Implementations of WriteFrames() should be robust against
+  // this. This generally means returning to the event loop immediately after
+  // calling the callback.
   virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                           const CompletionCallback& callback) = 0;
 
@@ -156,40 +164,6 @@
   // extensions were negotiated, the empty string is returned.
   virtual std::string GetExtensions() const = 0;
 
-  // TODO(yutak): Add following interfaces:
-  // - RenewStreamForAuth for authentication (is this necessary?)
-  // - GetSSLInfo, GetSSLCertRequestInfo for SSL
-
-  // WebSocketStreamBase derived functions
-  virtual WebSocketStream* AsWebSocketStream() OVERRIDE;
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Methods used during the stream handshake. These must not be called once a
-  // WebSocket protocol stream has been established (ie. after the
-  // SuccessCallback or FailureCallback has been called.)
-
-  // Writes WebSocket handshake request to the underlying socket. Must be called
-  // before ReadHandshakeResponse().
-  //
-  // |callback| will only be called if this method returns ERR_IO_PENDING.
-  //
-  // |response_info| must remain valid until the callback from
-  // ReadHandshakeResponse has been called.
-  //
-  // TODO(ricea): This function is only used during the handshake and is
-  // probably only applicable to certain subclasses of WebSocketStream. Move it
-  // somewhere else? Also applies to ReadHandshakeResponse.
-  virtual int SendHandshakeRequest(const GURL& url,
-                                   const HttpRequestHeaders& headers,
-                                   HttpResponseInfo* response_info,
-                                   const CompletionCallback& callback) = 0;
-
-  // Reads WebSocket handshake response from the underlying socket. Must be
-  // called after SendHandshakeRequest() completes.
-  //
-  // |callback| will only be called if this method returns ERR_IO_PENDING.
-  virtual int ReadHandshakeResponse(const CompletionCallback& callback) = 0;
-
  protected:
   WebSocketStream();
 
diff --git a/net/websockets/websocket_stream_base.h b/net/websockets/websocket_stream_base.h
deleted file mode 100644
index dc863d2..0000000
--- a/net/websockets/websocket_stream_base.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 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 NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_
-#define NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_
-
-// This file is included from net/http files.
-// Since net/http can be built without linking net/websockets code,
-// this file should not depend on net/websockets.
-
-#include <base/basictypes.h>
-
-namespace net {
-
-class ClientSocketHandle;
-class SpdySession;
-class WebSocketStream;
-
-// WebSocketStreamBase is the base class of WebSocketStream.
-// net/http code uses this interface to handle WebSocketStream.
-class NET_EXPORT WebSocketStreamBase {
- public:
-  class Factory {
-   public:
-    virtual ~Factory() {}
-
-    // Create a WebSocketBasicStream.
-    // This function (or the returned object) takes the ownership
-    // of |connection|.
-    virtual WebSocketStreamBase* CreateBasicStream(
-        ClientSocketHandle* connection,
-        bool using_proxy) = 0;
-
-    // Create a WebSocketSpdyStream.
-    virtual WebSocketStreamBase* CreateSpdyStream(
-        const base::WeakPtr<SpdySession>& session,
-        bool use_relative_url) = 0;
-  };
-
-  virtual ~WebSocketStreamBase() {}
-
-  // Return this object as a WebSocketStream.
-  virtual WebSocketStream* AsWebSocketStream() = 0;
-
- protected:
-  WebSocketStreamBase() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WebSocketStreamBase);
-};
-
-}  // namespace net
-
-#endif  // NET_WEBSOCKETS_WEBSOCKET_STREAM_BASE_H_
diff --git a/ppapi/api/dev/ppb_video_decoder_dev.idl b/ppapi/api/dev/ppb_video_decoder_dev.idl
index 5b1a94e..da408c9 100644
--- a/ppapi/api/dev/ppb_video_decoder_dev.idl
+++ b/ppapi/api/dev/ppb_video_decoder_dev.idl
@@ -62,7 +62,8 @@
    *
    * Parameters:
    *   |video_decoder| is the previously created handle to the decoder resource.
-   *   |bitstream_buffer| is the bitstream buffer that contains the input data.
+   *   |bitstream_buffer| is the bitstream buffer that contains at most one
+   *   input frame.
    *   |callback| will be called when |bitstream_buffer| has been processed by
    *   the decoder.
    *
diff --git a/ppapi/api/pp_array_output.idl b/ppapi/api/pp_array_output.idl
index be1aca7..8e04a4c 100644
--- a/ppapi/api/pp_array_output.idl
+++ b/ppapi/api/pp_array_output.idl
@@ -9,7 +9,7 @@
  *
  * This function will be called reentrantly. This means that if you call a
  * function PPB_Foo.GetData(&array_output), GetData will call your
- * GetDataBuffer function before it returns. 
+ * GetDataBuffer function before it returns.
  *
  * This function will be called even when returning 0-length arrays, so be sure
  * your implementation can support that. You can return NULL for 0 length
@@ -34,7 +34,10 @@
  * @param element_size The size of each element in bytes.
  *
  * @return Returns a pointer to the allocated memory. On failure, returns null.
- * You can also return null if the element_count is 0.
+ * You can also return null if the element_count is 0. When a non-null value is
+ * returned, the buffer must remain valid until after the callback runs. If used
+ * with a blocking callback, the buffer must remain valid until after the
+ * function returns. The plugin can then free any memory that it allocated.
  */
 typedef mem_t PP_ArrayOutput_GetDataBuffer([inout] mem_t user_data,
                                            [in] uint32_t element_count,
@@ -78,7 +81,7 @@
 [passByValue]
 struct PP_ArrayOutput {
   /**
-   * A pointer to the allocation function that the browser implements.
+   * A pointer to the allocation function that the browser will call.
    */
   PP_ArrayOutput_GetDataBuffer GetDataBuffer;
 
diff --git a/ppapi/api/ppb_file_io.idl b/ppapi/api/ppb_file_io.idl
index 2e43ec5..9b8c9e2 100644
--- a/ppapi/api/ppb_file_io.idl
+++ b/ppapi/api/ppb_file_io.idl
@@ -121,7 +121,9 @@
    * @param[out] info The <code>PP_FileInfo</code> structure representing all
    * information about the file.
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
-   * completion of Query().
+   * completion of Query(). <code>info</code> must remain valid until after the
+   * callback runs. If you pass a blocking callback, <code>info</code> must
+   * remain valid until after Query() returns.
    *
    * @return An int32_t containing an error code from <code>pp_errors.h</code>.
    * PP_ERROR_FAILED will be returned if the file isn't opened, and
@@ -158,6 +160,7 @@
    * large enough to hold the specified number of bytes to read.  This function
    * might perform a partial read, meaning all the requested bytes
    * might not be returned, even if the end of the file has not been reached.
+   * The FileIO object must have been opened with read access.
    *
    * ReadToArray() is preferred to Read() when doing asynchronous operations.
    *
@@ -168,7 +171,9 @@
    * @param[in] bytes_to_read The number of bytes to read from
    * <code>offset</code>.
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
-   * completion of Read().
+   * completion of Read(). <code>buffer</code> must remain valid until after
+   * the callback runs. If you pass a blocking callback, <code>buffer</code>
+   * must remain valid until after Read() returns.
    *
    * @return The number of bytes read or an error code from
    * <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
@@ -260,7 +265,8 @@
   /**
    * ReadToArray() reads from an offset in the file.  A PP_ArrayOutput must be
    * provided so that output will be stored in its allocated buffer.  This
-   * function might perform a partial read.
+   * function might perform a partial read. The FileIO object must have been
+   * opened with read access.
    *
    * @param[in] file_io A <code>PP_Resource</code> corresponding to a file
    * FileIO.
diff --git a/ppapi/api/private/pp_content_decryptor.idl b/ppapi/api/private/pp_content_decryptor.idl
index aba404f..41a3997 100644
--- a/ppapi/api/private/pp_content_decryptor.idl
+++ b/ppapi/api/private/pp_content_decryptor.idl
@@ -140,6 +140,20 @@
 };
 
 /**
+ * <code>PP_DecryptedSampleFormat</code> contains audio sample formats.
+ */
+[assert_size(4)]
+enum PP_DecryptedSampleFormat {
+  PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN = 0,
+  PP_DECRYPTEDSAMPLEFORMAT_U8 = 1,
+  PP_DECRYPTEDSAMPLEFORMAT_S16 = 2,
+  PP_DECRYPTEDSAMPLEFORMAT_S32 = 3,
+  PP_DECRYPTEDSAMPLEFORMAT_F32 = 4,
+  PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16 = 5,
+  PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32 = 6
+};
+
+/**
  * The <code>PP_DecryptResult</code> enum contains decryption and decoding
  * result constants.
  */
@@ -235,6 +249,40 @@
 };
 
 /**
+ * <code>PP_DecryptedSampleInfo</code> contains the result of the
+ * decrypt and decode operation on the associated samples, information required
+ * to access the sample data in buffer, and tracking info.
+ */
+[assert_size(32)]
+struct PP_DecryptedSampleInfo {
+  /**
+   * Result of the decrypt and decode operation.
+   */
+  PP_DecryptResult result;
+
+  /**
+   * Format of the decrypted samples.
+   */
+  PP_DecryptedSampleFormat format;
+
+  /**
+   * Size in bytes of decrypted samples.
+   */
+  uint32_t data_size;
+
+  /**
+   * 4-byte padding to make the size of <code>PP_DecryptedSampleInfo</code>
+   * a multiple of 8 bytes. The value of this field should not be used.
+   */
+  uint32_t padding;
+
+  /**
+   * Information needed by the client to track the decrypted samples.
+   */
+  PP_DecryptTrackingInfo tracking_info;
+};
+
+/**
  * <code>PP_AudioCodec</code> contains audio codec type constants.
  */
 [assert_size(4)]
diff --git a/ppapi/api/private/ppb_content_decryptor_private.idl b/ppapi/api/private/ppb_content_decryptor_private.idl
index 8859448..fbf4663 100644
--- a/ppapi/api/private/ppb_content_decryptor_private.idl
+++ b/ppapi/api/private/ppb_content_decryptor_private.idl
@@ -12,7 +12,8 @@
 [generate_thunk]
 
 label Chrome {
-  M31 = 0.7
+  M31 = 0.7,
+  M32 = 0.8
 };
 
 /**
@@ -228,12 +229,12 @@
    * <code>PPB_Buffer_Dev</code> resource that contains a decrypted buffer
    * of decoded audio samples.
    *
-   * @param[in] decrypted_block_info A <code>PP_DecryptedBlockInfo</code> that
-   * contains the tracking info and result code associated with the
-   * <code>decrypted_block</code>.
+   * @param[in] decrypted_sample_info A <code>PP_DecryptedSampleInfo</code> that
+   * contains the tracking info and result code associated with the decrypted
+   * samples.
    */
   void DeliverSamples(
       [in] PP_Instance instance,
       [in] PP_Resource audio_frames,
-      [in] PP_DecryptedBlockInfo decrypted_block_info);
+      [in] PP_DecryptedSampleInfo decrypted_sample_info);
 };
diff --git a/ppapi/api/private/ppb_nacl_private.idl b/ppapi/api/private/ppb_nacl_private.idl
index 4bb602f..3b965e9 100644
--- a/ppapi/api/private/ppb_nacl_private.idl
+++ b/ppapi/api/private/ppb_nacl_private.idl
@@ -147,10 +147,6 @@
    */
   PP_Bool IsOffTheRecord();
 
-  /* Return true if PNaCl is turned on.
-   */
-  PP_Bool IsPnaclEnabled();
-
   /* Display a UI message to the user. */
   PP_ExternalPluginResult ReportNaClError([in] PP_Instance instance,
                                           [in] PP_NaClError message_id);
diff --git a/ppapi/c/dev/ppb_video_decoder_dev.h b/ppapi/c/dev/ppb_video_decoder_dev.h
index fa57fd4..8b15fb0 100644
--- a/ppapi/c/dev/ppb_video_decoder_dev.h
+++ b/ppapi/c/dev/ppb_video_decoder_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/ppb_video_decoder_dev.idl modified Wed Dec 14 18:08:00 2011. */
+/* From dev/ppb_video_decoder_dev.idl modified Tue Oct 29 00:32:59 2013. */
 
 #ifndef PPAPI_C_DEV_PPB_VIDEO_DECODER_DEV_H_
 #define PPAPI_C_DEV_PPB_VIDEO_DECODER_DEV_H_
@@ -78,7 +78,8 @@
    *
    * Parameters:
    *   |video_decoder| is the previously created handle to the decoder resource.
-   *   |bitstream_buffer| is the bitstream buffer that contains the input data.
+   *   |bitstream_buffer| is the bitstream buffer that contains at most one
+   *   input frame.
    *   |callback| will be called when |bitstream_buffer| has been processed by
    *   the decoder.
    *
diff --git a/ppapi/c/pp_array_output.h b/ppapi/c/pp_array_output.h
index add873c..2272a8f 100644
--- a/ppapi/c/pp_array_output.h
+++ b/ppapi/c/pp_array_output.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From pp_array_output.idl modified Thu Mar 28 11:07:53 2013. */
+/* From pp_array_output.idl modified Tue Oct 22 15:09:25 2013. */
 
 #ifndef PPAPI_C_PP_ARRAY_OUTPUT_H_
 #define PPAPI_C_PP_ARRAY_OUTPUT_H_
@@ -43,7 +43,10 @@
  * @param element_size The size of each element in bytes.
  *
  * @return Returns a pointer to the allocated memory. On failure, returns null.
- * You can also return null if the element_count is 0.
+ * You can also return null if the element_count is 0. When a non-null value is
+ * returned, the buffer must remain valid until after the callback runs. If used
+ * with a blocking callback, the buffer must remain valid until after the
+ * function returns. The plugin can then free any memory that it allocated.
  */
 
 
@@ -99,7 +102,7 @@
  */
 struct PP_ArrayOutput {
   /**
-   * A pointer to the allocation function that the browser implements.
+   * A pointer to the allocation function that the browser will call.
    */
   PP_ArrayOutput_GetDataBuffer GetDataBuffer;
   /**
diff --git a/ppapi/c/ppb_file_io.h b/ppapi/c/ppb_file_io.h
index fe0e1bd..8f272bf 100644
--- a/ppapi/c/ppb_file_io.h
+++ b/ppapi/c/ppb_file_io.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_file_io.idl modified Tue Jun 11 15:21:38 2013. */
+/* From ppb_file_io.idl modified Tue Oct 22 15:09:47 2013. */
 
 #ifndef PPAPI_C_PPB_FILE_IO_H_
 #define PPAPI_C_PPB_FILE_IO_H_
@@ -135,7 +135,9 @@
    * @param[out] info The <code>PP_FileInfo</code> structure representing all
    * information about the file.
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
-   * completion of Query().
+   * completion of Query(). <code>info</code> must remain valid until after the
+   * callback runs. If you pass a blocking callback, <code>info</code> must
+   * remain valid until after Query() returns.
    *
    * @return An int32_t containing an error code from <code>pp_errors.h</code>.
    * PP_ERROR_FAILED will be returned if the file isn't opened, and
@@ -170,6 +172,7 @@
    * large enough to hold the specified number of bytes to read.  This function
    * might perform a partial read, meaning all the requested bytes
    * might not be returned, even if the end of the file has not been reached.
+   * The FileIO object must have been opened with read access.
    *
    * ReadToArray() is preferred to Read() when doing asynchronous operations.
    *
@@ -180,7 +183,9 @@
    * @param[in] bytes_to_read The number of bytes to read from
    * <code>offset</code>.
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
-   * completion of Read().
+   * completion of Read(). <code>buffer</code> must remain valid until after
+   * the callback runs. If you pass a blocking callback, <code>buffer</code>
+   * must remain valid until after Read() returns.
    *
    * @return The number of bytes read or an error code from
    * <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
@@ -267,7 +272,8 @@
   /**
    * ReadToArray() reads from an offset in the file.  A PP_ArrayOutput must be
    * provided so that output will be stored in its allocated buffer.  This
-   * function might perform a partial read.
+   * function might perform a partial read. The FileIO object must have been
+   * opened with read access.
    *
    * @param[in] file_io A <code>PP_Resource</code> corresponding to a file
    * FileIO.
diff --git a/ppapi/c/private/pp_content_decryptor.h b/ppapi/c/private/pp_content_decryptor.h
index 43ea559..a282abb 100644
--- a/ppapi/c/private/pp_content_decryptor.h
+++ b/ppapi/c/private/pp_content_decryptor.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/pp_content_decryptor.idl modified Tue Dec  4 16:42:46 2012. */
+/* From private/pp_content_decryptor.idl modified Mon Oct 21 18:38:44 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PP_CONTENT_DECRYPTOR_H_
 #define PPAPI_C_PRIVATE_PP_CONTENT_DECRYPTOR_H_
@@ -153,6 +153,20 @@
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_DecryptedFrameFormat, 4);
 
 /**
+ * <code>PP_DecryptedSampleFormat</code> contains audio sample formats.
+ */
+typedef enum {
+  PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN = 0,
+  PP_DECRYPTEDSAMPLEFORMAT_U8 = 1,
+  PP_DECRYPTEDSAMPLEFORMAT_S16 = 2,
+  PP_DECRYPTEDSAMPLEFORMAT_S32 = 3,
+  PP_DECRYPTEDSAMPLEFORMAT_F32 = 4,
+  PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16 = 5,
+  PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32 = 6
+} PP_DecryptedSampleFormat;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_DecryptedSampleFormat, 4);
+
+/**
  * The <code>PP_DecryptResult</code> enum contains decryption and decoding
  * result constants.
  */
@@ -259,6 +273,36 @@
   struct PP_DecryptTrackingInfo tracking_info;
 };
 PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_DecryptedFrameInfo, 56);
+
+/**
+ * <code>PP_DecryptedSampleInfo</code> contains the result of the
+ * decrypt and decode operation on the associated samples, information required
+ * to access the sample data in buffer, and tracking info.
+ */
+struct PP_DecryptedSampleInfo {
+  /**
+   * Result of the decrypt and decode operation.
+   */
+  PP_DecryptResult result;
+  /**
+   * Format of the decrypted samples.
+   */
+  PP_DecryptedSampleFormat format;
+  /**
+   * Size in bytes of decrypted samples.
+   */
+  uint32_t data_size;
+  /**
+   * 4-byte padding to make the size of <code>PP_DecryptedSampleInfo</code>
+   * a multiple of 8 bytes. The value of this field should not be used.
+   */
+  uint32_t padding;
+  /**
+   * Information needed by the client to track the decrypted samples.
+   */
+  struct PP_DecryptTrackingInfo tracking_info;
+};
+PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_DecryptedSampleInfo, 32);
 /**
  * @}
  */
diff --git a/ppapi/c/private/ppb_content_decryptor_private.h b/ppapi/c/private/ppb_content_decryptor_private.h
index 86f239a..5e3d1aa 100644
--- a/ppapi/c/private/ppb_content_decryptor_private.h
+++ b/ppapi/c/private/ppb_content_decryptor_private.h
@@ -4,7 +4,7 @@
  */
 
 /* From private/ppb_content_decryptor_private.idl,
- *   modified Tue Sep 17 11:31:05 2013.
+ *   modified Thu Oct 10 14:49:51 2013.
  */
 
 #ifndef PPAPI_C_PRIVATE_PPB_CONTENT_DECRYPTOR_PRIVATE_H_
@@ -234,14 +234,14 @@
    * <code>PPB_Buffer_Dev</code> resource that contains a decrypted buffer
    * of decoded audio samples.
    *
-   * @param[in] decrypted_block_info A <code>PP_DecryptedBlockInfo</code> that
-   * contains the tracking info and result code associated with the
-   * <code>decrypted_block</code>.
+   * @param[in] decrypted_sample_info A <code>PP_DecryptedSampleInfo</code> that
+   * contains the tracking info and result code associated with the decrypted
+   * samples.
    */
   void (*DeliverSamples)(
       PP_Instance instance,
       PP_Resource audio_frames,
-      const struct PP_DecryptedBlockInfo* decrypted_block_info);
+      const struct PP_DecryptedSampleInfo* decrypted_sample_info);
 };
 
 typedef struct PPB_ContentDecryptor_Private_0_7 PPB_ContentDecryptor_Private;
diff --git a/ppapi/c/private/ppb_nacl_private.h b/ppapi/c/private/ppb_nacl_private.h
index 6441efd..923e9cb 100644
--- a/ppapi/c/private/ppb_nacl_private.h
+++ b/ppapi/c/private/ppb_nacl_private.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_nacl_private.idl modified Thu Aug 29 17:42:12 2013. */
+/* From private/ppb_nacl_private.idl modified Fri Oct 18 08:23:34 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
 #define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
@@ -159,9 +159,6 @@
   /* Return true if we are off the record.
    */
   PP_Bool (*IsOffTheRecord)(void);
-  /* Return true if PNaCl is turned on.
-   */
-  PP_Bool (*IsPnaclEnabled)(void);
   /* Display a UI message to the user. */
   PP_ExternalPluginResult (*ReportNaClError)(PP_Instance instance,
                                              PP_NaClError message_id);
diff --git a/ppapi/cpp/file_io.h b/ppapi/cpp/file_io.h
index 99d8ce7..bbd6b57 100644
--- a/ppapi/cpp/file_io.h
+++ b/ppapi/cpp/file_io.h
@@ -71,7 +71,9 @@
   /// @param[in] result_buf The <code>PP_FileInfo</code> structure representing
   /// all information about the file.
   /// @param[in] cc A <code>CompletionCallback</code> to be called upon
-  /// completion of Query().
+  /// completion of Query(). <code>result_buf</code> must remain valid until
+  /// after the callback runs. If you pass a blocking callback,
+  /// <code>result_buf</code> must remain valid until after Query() returns.
   ///
   /// @return An int32_t containing an error code from
   /// <code>pp_errors.h</code>.
@@ -138,7 +140,9 @@
   /// @param[in] bytes_to_read The number of bytes to read from
   /// <code>offset</code>.
   /// @param[in] cc A <code>CompletionCallback</code> to be called upon
-  /// completion of Read().
+  /// completion of Read(). <code>buffer</code> must remain valid until after
+  /// the callback runs. If you pass a blocking callback, <code>buffer</code>
+  /// must remain valid until after Read() returns.
   ///
   /// @return An The number of bytes read an error code from
   /// <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
diff --git a/ppapi/cpp/file_ref.h b/ppapi/cpp/file_ref.h
index 56828f7..452d2a6 100644
--- a/ppapi/cpp/file_ref.h
+++ b/ppapi/cpp/file_ref.h
@@ -46,6 +46,9 @@
   /// A constructor that creates a weak pointer to a file in the given file
   /// system. File paths are POSIX style.
   ///
+  /// If the <code>path</code> is malformed, the resulting <code>FileRef</code>
+  /// will have a null <code>PP_Resource</code>.
+  ///
   /// @param[in] file_system A <code>FileSystem</code> corresponding to a file
   /// system type.
   /// @param[in] path A path to the file. Must begin with a '/' character.
diff --git a/ppapi/cpp/private/content_decryptor_private.cc b/ppapi/cpp/private/content_decryptor_private.cc
index 23417c3..8c7dcd2 100644
--- a/ppapi/cpp/private/content_decryptor_private.cc
+++ b/ppapi/cpp/private/content_decryptor_private.cc
@@ -330,12 +330,12 @@
 
 void ContentDecryptor_Private::DeliverSamples(
     pp::Buffer_Dev audio_frames,
-    const PP_DecryptedBlockInfo& decrypted_block_info) {
+    const PP_DecryptedSampleInfo& decrypted_sample_info) {
   if (has_interface<PPB_ContentDecryptor_Private>()) {
     get_interface<PPB_ContentDecryptor_Private>()->DeliverSamples(
         associated_instance_.pp_instance(),
         audio_frames.pp_resource(),
-        &decrypted_block_info);
+        &decrypted_sample_info);
   }
 }
 
diff --git a/ppapi/cpp/private/content_decryptor_private.h b/ppapi/cpp/private/content_decryptor_private.h
index a43a74c..ff98569 100644
--- a/ppapi/cpp/private/content_decryptor_private.h
+++ b/ppapi/cpp/private/content_decryptor_private.h
@@ -94,7 +94,7 @@
   // provided to DecryptAndDecode() when it calls this method. The browser will
   // reuse the buffer in a subsequent DecryptAndDecode() call.
   void DeliverSamples(pp::Buffer_Dev audio_frames,
-                      const PP_DecryptedBlockInfo& decrypted_block_info);
+                      const PP_DecryptedSampleInfo& decrypted_sample_info);
 
  private:
   InstanceHandle associated_instance_;
diff --git a/ppapi/host/resource_message_filter_unittest.cc b/ppapi/host/resource_message_filter_unittest.cc
index 78fc23c..38fd9d8f 100644
--- a/ppapi/host/resource_message_filter_unittest.cc
+++ b/ppapi/host/resource_message_filter_unittest.cc
@@ -64,8 +64,7 @@
       HostMessageContext* context) OVERRIDE {
     last_handled_msg_ = msg;
     if (msg.type() == msg_type_) {
-      context->reply_msg = IPC::Message(0, reply_msg_type_,
-                                        IPC::Message::PRIORITY_NORMAL);
+      context->reply_msg = IPC::Message(0, reply_msg_type_);
       return PP_OK;
     }
     return PP_ERROR_FAILED;
@@ -123,8 +122,7 @@
     last_handled_msg_ = msg;
     last_message_loop_ = base::MessageLoop::current();
     if (msg.type() == msg_type_) {
-      context->reply_msg = IPC::Message(0, reply_msg_type_,
-                                        IPC::Message::PRIORITY_NORMAL);
+      context->reply_msg = IPC::Message(0, reply_msg_type_);
       return PP_OK;
     }
     return PP_ERROR_FAILED;
@@ -166,9 +164,9 @@
   proxy::ResourceMessageCallParams params(resource, 1);
   params.set_has_callback();
   HostMessageContext context(params);
-  IPC::Message message1(0, MSG1_TYPE, IPC::Message::PRIORITY_NORMAL);
-  IPC::Message message2(0, MSG2_TYPE, IPC::Message::PRIORITY_NORMAL);
-  IPC::Message message3(0, MSG3_TYPE, IPC::Message::PRIORITY_NORMAL);
+  IPC::Message message1(0, MSG1_TYPE);
+  IPC::Message message2(0, MSG2_TYPE);
+  IPC::Message message3(0, MSG3_TYPE);
 
   // Message 1 handled by the first filter.
   host.HandleMessage(message1, &context);
diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.cc b/ppapi/native_client/src/trusted/plugin/file_downloader.cc
index 4bc1d4a..f8d3a4c 100644
--- a/ppapi/native_client/src/trusted/plugin/file_downloader.cc
+++ b/ppapi/native_client/src/trusted/plugin/file_downloader.cc
@@ -112,6 +112,9 @@
   if (!instance_->DocumentCanRequest(url))
     url_request.SetAllowCrossOriginRequests(true);
 
+  if (!extra_request_headers_.empty())
+    url_request.SetHeaders(extra_request_headers_);
+
   do {
     // Reset the url loader and file reader.
     // Note that we have the only reference to the underlying objects, so
diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.h b/ppapi/native_client/src/trusted/plugin/file_downloader.h
index 23f202c..4fd7997 100644
--- a/ppapi/native_client/src/trusted/plugin/file_downloader.h
+++ b/ppapi/native_client/src/trusted/plugin/file_downloader.h
@@ -149,6 +149,11 @@
   int status_code() const { return status_code_; }
   nacl::string GetResponseHeaders() const;
 
+  void set_request_headers(const nacl::string& extra_request_headers) {
+    extra_request_headers_ = extra_request_headers;
+  }
+
+
  private:
   NACL_DISALLOW_COPY_AND_ASSIGN(FileDownloader);
   // This class loads and opens the file in three steps for DOWNLOAD_TO_FILE:
@@ -175,6 +180,7 @@
   Plugin* instance_;
   nacl::string url_to_open_;
   nacl::string url_;
+  nacl::string extra_request_headers_;
   pp::URLResponseInfo url_response_;
   pp::CompletionCallback file_open_notify_callback_;
   pp::CompletionCallback stream_finish_callback_;
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc
index 8fb4c43..5a783af 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.cc
+++ b/ppapi/native_client/src/trusted/plugin/plugin.cc
@@ -29,28 +29,14 @@
 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
 
-#include "ppapi/c/dev/ppp_find_dev.h"
-#include "ppapi/c/dev/ppp_printing_dev.h"
-#include "ppapi/c/dev/ppp_selection_dev.h"
-#include "ppapi/c/dev/ppp_zoom_dev.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/ppb_console.h"
 #include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppp_input_event.h"
 #include "ppapi/c/ppp_instance.h"
-#include "ppapi/c/ppp_mouse_lock.h"
 #include "ppapi/c/private/ppb_nacl_private.h"
 #include "ppapi/c/private/ppb_uma_private.h"
-#include "ppapi/cpp/dev/find_dev.h"
-#include "ppapi/cpp/dev/printing_dev.h"
-#include "ppapi/cpp/dev/selection_dev.h"
 #include "ppapi/cpp/dev/url_util_dev.h"
-#include "ppapi/cpp/dev/zoom_dev.h"
-#include "ppapi/cpp/image_data.h"
-#include "ppapi/cpp/input_event.h"
 #include "ppapi/cpp/module.h"
-#include "ppapi/cpp/mouse_lock.h"
-#include "ppapi/cpp/rect.h"
 #include "ppapi/cpp/text_input_controller.h"
 
 #include "ppapi/native_client/src/trusted/plugin/file_utils.h"
@@ -300,11 +286,12 @@
 void Plugin::GetReadyStateProperty(NaClSrpcArg* prop_value) {
   PLUGIN_PRINTF(("GetReadyState (this=%p)\n", reinterpret_cast<void*>(this)));
   prop_value->tag = NACL_SRPC_ARG_TYPE_INT;
-  prop_value->u.ival = nacl_ready_state();
+  prop_value->u.ival = nacl_ready_state_;
 }
 
-bool Plugin::Init(int argc, char* argn[], char* argv[]) {
-  PLUGIN_PRINTF(("Plugin::Init (instance=%p)\n", static_cast<void*>(this)));
+bool Plugin::EarlyInit(int argc, const char* argn[], const char* argv[]) {
+  PLUGIN_PRINTF(("Plugin::EarlyInit (instance=%p)\n",
+                 static_cast<void*>(this)));
 
 #ifdef NACL_OSX
   // TODO(kochi): For crbug.com/102808, this is a stopgap solution for Lion
@@ -563,10 +550,10 @@
 }
 
 char* Plugin::LookupArgument(const char* key) {
-  char** keys = argn();
-  for (int ii = 0, len = argc(); ii < len; ++ii) {
+  char** keys = argn_;
+  for (int ii = 0, len = argc_; ii < len; ++ii) {
     if (!strcmp(keys[ii], key)) {
-      return argv()[ii];
+      return argv_[ii];
     }
   }
   return NULL;
@@ -632,9 +619,6 @@
   PLUGIN_PRINTF(("Plugin::New (pp_instance=%" NACL_PRId32 ")\n", pp_instance));
   Plugin* plugin = new Plugin(pp_instance);
   PLUGIN_PRINTF(("Plugin::New (plugin=%p)\n", static_cast<void*>(plugin)));
-  if (plugin == NULL) {
-    return NULL;
-  }
   return plugin;
 }
 
@@ -661,12 +645,7 @@
   PLUGIN_PRINTF(("Plugin::Init (url_util_=%p)\n",
                  static_cast<const void*>(url_util_)));
 
-  bool status = Plugin::Init(
-      static_cast<int>(argc),
-      // TODO(polina): Can we change the args on our end to be const to
-      // avoid these ugly casts?
-      const_cast<char**>(argn),
-      const_cast<char**>(argv));
+  bool status = EarlyInit(static_cast<int>(argc), argn, argv);
   if (status) {
     // Look for the developer attribute; if it's present, enable 'dev'
     // interfaces.
@@ -988,7 +967,7 @@
     PLUGIN_PRINTF(("Plugin::NexeDidCrash: error already reported;"
                    " suppressing\n"));
   } else {
-    if (nacl_ready_state() == DONE) {
+    if (nacl_ready_state_ == DONE) {
       ReportDeadNexe();
     } else {
       ErrorInfo error_info;
@@ -1055,7 +1034,7 @@
 void Plugin::ReportDeadNexe() {
   PLUGIN_PRINTF(("Plugin::ReportDeadNexe\n"));
 
-  if (nacl_ready_state() == DONE && !nexe_error_reported()) {  // After loadEnd.
+  if (nacl_ready_state_ == DONE && !nexe_error_reported()) {  // After loadEnd.
     int64_t crash_time = NaClGetTimeOfDayMicroseconds();
     // Crashes will be more likely near startup, so use a medium histogram
     // instead of a large one.
@@ -1199,11 +1178,10 @@
 
   if (manifest_->GetProgramURL(&program_url, &pnacl_options, &error_info)) {
     is_installed_ = GetUrlScheme(program_url) == SCHEME_CHROME_EXTENSION;
-    set_nacl_ready_state(LOADING);
+    nacl_ready_state_ = LOADING;
     // Inform JavaScript that we found a nexe URL to load.
     EnqueueProgressEvent(kProgressEventProgress);
     if (pnacl_options.translate()) {
-      CHECK(nacl_interface()->IsPnaclEnabled());
       pp::CompletionCallback translate_callback =
           callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
       // Will always call the callback on success or failure.
@@ -1259,7 +1237,7 @@
   set_manifest_base_url(nmf_resolved_url.AsString());
   set_manifest_url(url);
   // Inform JavaScript that a load is starting.
-  set_nacl_ready_state(OPENED);
+  nacl_ready_state_ = OPENED;
   EnqueueProgressEvent(kProgressEventLoadStart);
   bool is_data_uri = GetUrlScheme(nmf_resolved_url.AsString()) == SCHEME_DATA;
   HistogramEnumerateManifestIsDataURI(static_cast<int>(is_data_uri));
@@ -1378,7 +1356,7 @@
                                uint64_t loaded_bytes,
                                uint64_t total_bytes) {
   // Set the readyState attribute to indicate loaded.
-  set_nacl_ready_state(DONE);
+  nacl_ready_state_ = DONE;
   // Inform JavaScript that loading was successful and is complete.
   const nacl::string& url = nexe_downloader_.url_to_open();
   EnqueueProgressEvent(
@@ -1405,7 +1383,7 @@
   }
 
   // Set the readyState attribute to indicate we need to start over.
-  set_nacl_ready_state(DONE);
+  nacl_ready_state_ = DONE;
   set_nexe_error_reported(true);
   // Report an error in lastError and on the JavaScript console.
   nacl::string message = nacl::string("NaCl module load failed: ") +
@@ -1425,7 +1403,7 @@
 void Plugin::ReportLoadAbort() {
   PLUGIN_PRINTF(("Plugin::ReportLoadAbort\n"));
   // Set the readyState attribute to indicate we need to start over.
-  set_nacl_ready_state(DONE);
+  nacl_ready_state_ = DONE;
   set_nexe_error_reported(true);
   // Report an error in lastError and on the JavaScript console.
   nacl::string error_string("NaCl module load failed: user aborted");
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h
index 416ab5b..c1a9388 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.h
+++ b/ppapi/native_client/src/trusted/plugin/plugin.h
@@ -22,10 +22,7 @@
 #include "native_client/src/trusted/validator/nacl_file_info.h"
 
 #include "ppapi/c/private/ppb_nacl_private.h"
-#include "ppapi/cpp/private/var_private.h"
-// for pp::VarPrivate
 #include "ppapi/cpp/private/instance_private.h"
-#include "ppapi/cpp/rect.h"
 #include "ppapi/cpp/url_loader.h"
 #include "ppapi/cpp/var.h"
 #include "ppapi/cpp/view.h"
@@ -36,21 +33,14 @@
 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
 #include "ppapi/native_client/src/trusted/plugin/utility.h"
 
-struct NaClSrpcChannel;
-
 namespace nacl {
 class DescWrapper;
 class DescWrapperFactory;
 }  // namespace nacl
 
 namespace pp {
-class Find_Dev;
-class MouseLock;
-class Printing_Dev;
-class Selection_Dev;
 class URLLoader;
 class URLUtil_Dev;
-class Zoom_Dev;
 }
 
 namespace ppapi_proxy {
@@ -178,13 +168,6 @@
   // Report nexe death after load to JS and shut down the proxy.
   void ReportDeadNexe();
 
-  // The embed/object tag argument list.
-  int argc() const { return argc_; }
-  char** argn() const { return argn_; }
-  char** argv() const { return argv_; }
-
-  Plugin* plugin() const { return const_cast<Plugin*>(this); }
-
   // URL resolution support.
   // plugin_base_url is the URL used for resolving relative URLs used in
   // src="...".
@@ -218,10 +201,6 @@
     // interaction with the page.
     DONE = 4
   };
-  ReadyState nacl_ready_state() const { return nacl_ready_state_; }
-  void set_nacl_ready_state(ReadyState nacl_ready_state) {
-    nacl_ready_state_ = nacl_ready_state;
-  }
   bool nexe_error_reported() const { return nexe_error_reported_; }
   void set_nexe_error_reported(bool val) {
     nexe_error_reported_ = val;
@@ -311,7 +290,7 @@
   // pointer to this object, not from base's Delete().
   ~Plugin();
 
-  bool Init(int argc, char* argn[], char* argv[]);
+  bool EarlyInit(int argc, const char* argn[], const char* argv[]);
   // Shuts down socket connection, service runtime, and receive thread,
   // in this order, for the main nacl subprocess.
   void ShutDownSubprocesses();
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
index 26268bf..860a67e 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
@@ -233,13 +233,11 @@
                  reinterpret_cast<const void*>(coordinator->manifest_.get()),
                  coordinator->off_the_record_));
 
-  // First check that PNaCl is installed.
-  pp::CompletionCallback pnacl_installed_cb =
-      coordinator->callback_factory_.NewCallback(
-          &PnaclCoordinator::DidCheckPnaclInstalled);
-  plugin->nacl_interface()->EnsurePnaclInstalled(
-      plugin->pp_instance(),
-      pnacl_installed_cb.pp_completion_callback());
+  // First start a network request for the pexe, to tickle the component
+  // updater's On-Demand resource throttler, and to get Last-Modified/ETag
+  // cache information. We can cancel the request later if there's
+  // a bitcode->nexe cache hit.
+  coordinator->OpenBitcodeStream();
   return coordinator;
 }
 
@@ -470,13 +468,45 @@
     return;
   }
 
-  OpenBitcodeStream();
+  // Okay, now that we've started the HTTP request for the pexe
+  // and we've ensured that the PNaCl compiler + metadata is installed,
+  // get the cache key from the response headers and from the
+  // compiler's version metadata.
+  nacl::string headers = streaming_downloader_->GetResponseHeaders();
+  NaClHttpResponseHeaders parser;
+  parser.Parse(headers);
+
+  temp_nexe_file_.reset(new TempFile(plugin_));
+  pp::CompletionCallback cb =
+      callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen);
+  int32_t nexe_fd_err =
+      plugin_->nacl_interface()->GetNexeFd(
+          plugin_->pp_instance(),
+          streaming_downloader_->url().c_str(),
+          // TODO(dschuff): Get this value from the pnacl json file after it
+          // rolls in from NaCl.
+          1,
+          pnacl_options_.opt_level(),
+          parser.GetHeader("last-modified").c_str(),
+          parser.GetHeader("etag").c_str(),
+          PP_FromBool(parser.CacheControlNoStore()),
+          &is_cache_hit_,
+          temp_nexe_file_->existing_handle(),
+          cb.pp_completion_callback());
+  if (nexe_fd_err < PP_OK_COMPLETIONPENDING) {
+    ReportPpapiError(ERROR_PNACL_CREATE_TEMP, nexe_fd_err,
+                     nacl::string("Call to GetNexeFd failed"));
+  }
 }
 
 void PnaclCoordinator::OpenBitcodeStream() {
   // Now open the pexe stream.
   streaming_downloader_.reset(new FileDownloader());
   streaming_downloader_->Initialize(plugin_);
+  // Mark the request as requesting a PNaCl bitcode file,
+  // so that component updater can detect this user action.
+  streaming_downloader_->set_request_headers(
+      "Accept: application/x-pnacl, */*");
 
   // Even though we haven't started downloading, create the translation
   // thread object immediately. This ensures that any pieces of the file
@@ -509,32 +539,14 @@
     return;
   }
 
-  // Get the cache key and try to open an existing entry.
-  nacl::string headers = streaming_downloader_->GetResponseHeaders();
-  NaClHttpResponseHeaders parser;
-  parser.Parse(headers);
-
-  temp_nexe_file_.reset(new TempFile(plugin_));
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen);
-  int32_t nexe_fd_err =
-      plugin_->nacl_interface()->GetNexeFd(
-          plugin_->pp_instance(),
-          streaming_downloader_->url().c_str(),
-          // TODO(dschuff): Get this value from the pnacl json file after it
-          // rolls in from NaCl.
-          1,
-          pnacl_options_.opt_level(),
-          parser.GetHeader("last-modified").c_str(),
-          parser.GetHeader("etag").c_str(),
-          PP_FromBool(parser.CacheControlNoStore()),
-          &is_cache_hit_,
-          temp_nexe_file_->existing_handle(),
-          cb.pp_completion_callback());
-  if (nexe_fd_err < PP_OK_COMPLETIONPENDING) {
-    ReportPpapiError(ERROR_PNACL_CREATE_TEMP, nexe_fd_err,
-                     nacl::string("Call to GetNexeFd failed"));
-  }
+  // Now that we've started the url request for the response headers and
+  // for tickling the component updater's On-Demand API, check that the
+  // compiler is present, or block until it is present or an error is hit.
+  pp::CompletionCallback pnacl_installed_cb =
+      callback_factory_.NewCallback(&PnaclCoordinator::DidCheckPnaclInstalled);
+  plugin_->nacl_interface()->EnsurePnaclInstalled(
+      plugin_->pp_instance(),
+      pnacl_installed_cb.pp_completion_callback());
 }
 
 void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) {
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
index 9782864..4b65e9e 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
@@ -54,10 +54,10 @@
 // (2) ld links the object code in obj_file_ and produces a nexe in nexe_file_.
 //
 // The coordinator proceeds through several states.  They are
-// LOAD_TRANSLATOR_BINARIES
-//     Complete when ResourcesDidLoad is invoked.
 // OPEN_BITCODE_STREAM
 //       Complete when BitcodeStreamDidOpen is invoked
+// LOAD_TRANSLATOR_BINARIES
+//     Complete when ResourcesDidLoad is invoked.
 // GET_NEXE_FD
 //       Get an FD which contains the cached nexe, or is writeable for
 //       translation output. Complete when NexeFdDidOpen is called.
@@ -139,6 +139,12 @@
                    const PnaclOptions& pnacl_options,
                    const pp::CompletionCallback& translate_notify_callback);
 
+  // Invoke to issue a GET request for bitcode.
+  void OpenBitcodeStream();
+  // Invoked when we've started an URL fetch for the pexe to check for
+  // caching metadata.
+  void BitcodeStreamDidOpen(int32_t pp_error);
+
   // Callback for when we know PNaCl is installed.
   void DidCheckPnaclInstalled(int32_t pp_error);
 
@@ -147,14 +153,6 @@
 
   // Callback for when llc and ld have been downloaded.
   void ResourcesDidLoad(int32_t pp_error);
-
-  // Callbacks for temporary file related stages.
-  // They are invoked from ResourcesDidLoad and proceed in declaration order.
-  // Invoke to issue a GET request for bitcode.
-  void OpenBitcodeStream();
-  // Invoked when we've started an URL fetch for the pexe to check for
-  // caching metadata.
-  void BitcodeStreamDidOpen(int32_t pp_error);
   // Invoked when we've gotten a temp FD for the nexe, either with the nexe
   // data, or a writeable fd to save to.
   void NexeFdDidOpen(int32_t pp_error);
diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.cc b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
index 2795786..8f59f3a 100644
--- a/ppapi/native_client/src/trusted/plugin/service_runtime.cc
+++ b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
@@ -337,7 +337,6 @@
     NaClLog(4,
             "OpenManifestEntry_MainThreadContinuation: "
             "pulling down and translating.\n");
-    CHECK(plugin_->nacl_interface()->IsPnaclEnabled());
     pp::CompletionCallback translate_callback =
         WeakRefNewCallback(
             anchor_,
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 9e3b477..d8ca859 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -2523,9 +2523,9 @@
   iface->DeliverFrame(instance, decrypted_frame, decrypted_frame_info);
 }
 
-static void Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedBlockInfo* decrypted_block_info) {
+static void Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedSampleInfo* decrypted_sample_info) {
   const struct PPB_ContentDecryptor_Private_0_7 *iface = Pnacl_WrapperInfo_PPB_ContentDecryptor_Private_0_7.real_iface;
-  iface->DeliverSamples(instance, audio_frames, decrypted_block_info);
+  iface->DeliverSamples(instance, audio_frames, decrypted_sample_info);
 }
 
 /* End wrapper methods for PPB_ContentDecryptor_Private_0_7 */
@@ -3093,11 +3093,6 @@
   return iface->IsOffTheRecord();
 }
 
-static PP_Bool Pnacl_M25_PPB_NaCl_Private_IsPnaclEnabled(void) {
-  const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
-  return iface->IsPnaclEnabled();
-}
-
 static PP_ExternalPluginResult Pnacl_M25_PPB_NaCl_Private_ReportNaClError(PP_Instance instance, PP_NaClError message_id) {
   const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
   return iface->ReportNaClError(instance, message_id);
@@ -4800,7 +4795,7 @@
     .DecoderDeinitializeDone = (void (*)(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id))&Pnacl_M31_PPB_ContentDecryptor_Private_DecoderDeinitializeDone,
     .DecoderResetDone = (void (*)(PP_Instance instance, PP_DecryptorStreamType decoder_type, uint32_t request_id))&Pnacl_M31_PPB_ContentDecryptor_Private_DecoderResetDone,
     .DeliverFrame = (void (*)(PP_Instance instance, PP_Resource decrypted_frame, const struct PP_DecryptedFrameInfo* decrypted_frame_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverFrame,
-    .DeliverSamples = (void (*)(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedBlockInfo* decrypted_block_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples
+    .DeliverSamples = (void (*)(PP_Instance instance, PP_Resource audio_frames, const struct PP_DecryptedSampleInfo* decrypted_sample_info))&Pnacl_M31_PPB_ContentDecryptor_Private_DeliverSamples
 };
 
 struct PPB_Ext_CrxFileSystem_Private_0_1 Pnacl_Wrappers_PPB_Ext_CrxFileSystem_Private_0_1 = {
@@ -4955,7 +4950,6 @@
     .GetNexeFd = (int32_t (*)(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* last_modified, const char* etag, PP_Bool has_no_store_header, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_GetNexeFd,
     .ReportTranslationFinished = (void (*)(PP_Instance instance, PP_Bool success))&Pnacl_M25_PPB_NaCl_Private_ReportTranslationFinished,
     .IsOffTheRecord = (PP_Bool (*)(void))&Pnacl_M25_PPB_NaCl_Private_IsOffTheRecord,
-    .IsPnaclEnabled = (PP_Bool (*)(void))&Pnacl_M25_PPB_NaCl_Private_IsPnaclEnabled,
     .ReportNaClError = (PP_ExternalPluginResult (*)(PP_Instance instance, PP_NaClError message_id))&Pnacl_M25_PPB_NaCl_Private_ReportNaClError,
     .OpenNaClExecutable = (PP_FileHandle (*)(PP_Instance instance, const char* file_url, uint64_t* file_token_lo, uint64_t* file_token_hi))&Pnacl_M25_PPB_NaCl_Private_OpenNaClExecutable
 };
diff --git a/ppapi/proxy/audio_input_resource.cc b/ppapi/proxy/audio_input_resource.cc
index 4a7afff..7c29df5 100644
--- a/ppapi/proxy/audio_input_resource.cc
+++ b/ppapi/proxy/audio_input_resource.cc
@@ -8,7 +8,6 @@
 #include "base/logging.h"
 #include "ipc/ipc_platform_file.h"
 #include "media/audio/audio_parameters.h"
-#include "media/audio/shared_memory_util.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/proxy/resource_message_params.h"
@@ -168,15 +167,9 @@
         params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY);
     CHECK(serialized_shared_memory_handle.IsHandleValid());
 
-    // See the comment in pepper_audio_input_host.cc about how we must call
-    // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here,
-    // we must call PacketSizeInBytes to get back the size of the audio buffer,
-    // excluding the bytes that audio uses for book-keeping.
-    size_t shared_memory_size = media::PacketSizeInBytes(
-        serialized_shared_memory_handle.size());
-
     open_state_ = OPENED;
-    SetStreamInfo(serialized_shared_memory_handle.shmem(), shared_memory_size,
+    SetStreamInfo(serialized_shared_memory_handle.shmem(),
+                  serialized_shared_memory_handle.size(),
                   socket_handle);
   } else {
     capturing_ = false;
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc
index b1eb450..347d4ef 100644
--- a/ppapi/proxy/file_io_resource.cc
+++ b/ppapi/proxy/file_io_resource.cc
@@ -138,21 +138,33 @@
     return PP_ERROR_FAILED;
 
   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
-  scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
 
   // If the callback is blocking, perform the task on the calling thread.
   if (callback->is_blocking()) {
-    int32_t result;
+    int32_t result = PP_ERROR_FAILED;
+    base::PlatformFileInfo file_info;
+    // The plugin could release its reference to this instance when we release
+    // the proxy lock below.
+    scoped_refptr<FileIOResource> protect(this);
     {
       // Release the proxy lock while making a potentially slow file call.
       ProxyAutoUnlock unlock;
-      result = query_op->DoWork();
+      if (base::GetPlatformFileInfo(file_handle_->raw_handle(), &file_info))
+        result = PP_OK;
     }
-    return OnQueryComplete(query_op, info, result);
+    if (result == PP_OK) {
+      // This writes the file info into the plugin's PP_FileInfo struct.
+      ppapi::PlatformFileInfoToPepperFileInfo(file_info,
+                                              file_system_type_,
+                                              info);
+    }
+    state_manager_.SetOperationFinished();
+    return result;
   }
 
   // For the non-blocking case, post a task to the file thread and add a
   // completion task to write the result.
+  scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
   base::PostTaskAndReplyWithResult(
       PpapiGlobals::Get()->GetFileTaskRunner(),
       FROM_HERE,
@@ -316,19 +328,28 @@
   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
 
   bytes_to_read = std::min(bytes_to_read, kMaxReadSize);
-  scoped_refptr<ReadOp> read_op(
-      new ReadOp(file_handle_, offset, bytes_to_read));
   if (callback->is_blocking()) {
-    int32_t result;
-    {
+    char* buffer = static_cast<char*>(
+        array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
+    int32_t result = PP_ERROR_FAILED;
+    // The plugin could release its reference to this instance when we release
+    // the proxy lock below.
+    scoped_refptr<FileIOResource> protect(this);
+    if (buffer) {
       // Release the proxy lock while making a potentially slow file call.
       ProxyAutoUnlock unlock;
-      result = read_op->DoWork();
+      result = base::ReadPlatformFile(
+          file_handle_->raw_handle(), offset, buffer, bytes_to_read);
+      if (result < 0)
+        result = PP_ERROR_FAILED;
     }
-    return OnReadComplete(read_op, array_output, result);
+    state_manager_.SetOperationFinished();
+    return result;
   }
 
   // For the non-blocking case, post a task to the file thread.
+  scoped_refptr<ReadOp> read_op(
+      new ReadOp(file_handle_, offset, bytes_to_read));
   base::PostTaskAndReplyWithResult(
       PpapiGlobals::Get()->GetFileTaskRunner(),
       FROM_HERE,
diff --git a/ppapi/proxy/handle_converter.cc b/ppapi/proxy/handle_converter.cc
index 534a8ae..587585b 100644
--- a/ppapi/proxy/handle_converter.cc
+++ b/ppapi/proxy/handle_converter.cc
@@ -227,17 +227,14 @@
   // compatible with Windows IPC deserialization code; it is intended to be
   // passed to NaCl.
 #if defined(OS_WIN)
-  new_msg_ptr->reset(
-      new IPC::Message(msg.routing_id(), msg.type(), msg.priority()));
+  new_msg_ptr->reset(new IPC::Message(msg.routing_id(), msg.type()));
 #else
   // Even on POSIX, we have to rewrite messages to create channels, because
   // these contain a handle with an invalid (place holder) descriptor. The
   // message sending code sees this and doesn't pass the descriptor over
   // correctly.
-  if (msg.type() == PpapiMsg_CreateNaClChannel::ID) {
-    new_msg_ptr->reset(
-        new IPC::Message(msg.routing_id(), msg.type(), msg.priority()));
-  }
+  if (msg.type() == PpapiMsg_CreateNaClChannel::ID)
+    new_msg_ptr->reset(new IPC::Message(msg.routing_id(), msg.type()));
 #endif
 
   switch (msg.type()) {
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index 9ea9d69..063cafb 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -213,6 +213,11 @@
   NOTREACHED();
 }
 
+void PpapiCommandBufferProxy::SendManagedMemoryStats(
+    const gpu::ManagedMemoryStats& stats) {
+  NOTREACHED();
+}
+
 bool PpapiCommandBufferProxy::SupportsGpuMemoryBuffer() {
   return false;
 }
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index 430054d..bca5190 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -61,6 +61,8 @@
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(uint32 query,
                            const base::Closure& callback) OVERRIDE;
+  virtual void SendManagedMemoryStats(const gpu::ManagedMemoryStats& stats)
+      OVERRIDE;
 
  private:
   bool Send(IPC::Message* msg);
diff --git a/ppapi/proxy/ppb_audio_proxy.cc b/ppapi/proxy/ppb_audio_proxy.cc
index 49ed0af..58f5abc 100644
--- a/ppapi/proxy/ppb_audio_proxy.cc
+++ b/ppapi/proxy/ppb_audio_proxy.cc
@@ -6,7 +6,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/threading/simple_thread.h"
-#include "media/audio/shared_memory_util.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/ppb_audio.h"
 #include "ppapi/c/ppb_audio_config.h"
@@ -262,15 +261,7 @@
   // us, as long as the remote side always closes the handles it receives
   // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
   SerializedHandle fd_wrapper(SerializedHandle::SOCKET, socket_handle);
-
-  // Note that we must call TotalSharedMemorySizeInBytes because
-  // Audio allocates extra space in shared memory for book-keeping, so the
-  // actual size of the shared memory buffer is larger than audio_buffer_length.
-  // When sending to NaCl, NaClIPCAdapter expects this size to match the size
-  // of the full shared memory buffer.
-  SerializedHandle handle_wrapper(
-      shared_memory,
-      media::TotalSharedMemorySizeInBytes(audio_buffer_length));
+  SerializedHandle handle_wrapper(shared_memory, audio_buffer_length);
   dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
       API_ID_PPB_AUDIO, resource, result_code, fd_wrapper, handle_wrapper));
 }
@@ -333,13 +324,8 @@
   } else {
     EnterResourceNoLock<PPB_AudioConfig_API> config(
         static_cast<Audio*>(enter.object())->GetCurrentConfig(), true);
-    // See the comment above about how we must call
-    // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here,
-    // we must call PacketSizeInBytes to get back the size of the audio buffer,
-    // excluding the bytes that audio uses for book-keeping.
     static_cast<Audio*>(enter.object())->SetStreamInfo(
-        enter.resource()->pp_instance(), handle.shmem(),
-        media::PacketSizeInBytes(handle.size()),
+        enter.resource()->pp_instance(), handle.shmem(), handle.size(),
         IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor()),
         config.object()->GetSampleRate(),
         config.object()->GetSampleFrameCount());
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index fdaa8c4..1997f890 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -675,7 +675,7 @@
 void PPB_Instance_Proxy::DeliverSamples(
     PP_Instance instance,
     PP_Resource decrypted_samples,
-    const PP_DecryptedBlockInfo* block_info) {
+    const PP_DecryptedSampleInfo* sample_info) {
   PP_Resource host_resource = 0;
   if (decrypted_samples != 0) {
     ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker();
@@ -689,8 +689,8 @@
     host_resource = object->host_resource().host_resource();
   }
 
-  std::string serialized_block_info;
-  if (!SerializeBlockInfo(*block_info, &serialized_block_info)) {
+  std::string serialized_sample_info;
+  if (!SerializeBlockInfo(*sample_info, &serialized_sample_info)) {
     NOTREACHED();
     return;
   }
@@ -699,7 +699,7 @@
       new PpapiHostMsg_PPBInstance_DeliverSamples(API_ID_PPB_INSTANCE,
                                                   instance,
                                                   host_resource,
-                                                  serialized_block_info));
+                                                  serialized_sample_info));
 }
 #endif  // !defined(OS_NACL)
 
@@ -1165,16 +1165,16 @@
 void PPB_Instance_Proxy::OnHostMsgDeliverSamples(
     PP_Instance instance,
     PP_Resource audio_frames,
-    const std::string& serialized_block_info) {
+    const std::string& serialized_sample_info) {
   if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE))
     return;
-  PP_DecryptedBlockInfo block_info;
-  if (!DeserializeBlockInfo(serialized_block_info, &block_info))
+  PP_DecryptedSampleInfo sample_info;
+  if (!DeserializeBlockInfo(serialized_sample_info, &sample_info))
     return;
 
   EnterInstanceNoLock enter(instance);
   if (enter.succeeded())
-    enter.functions()->DeliverSamples(instance, audio_frames, &block_info);
+    enter.functions()->DeliverSamples(instance, audio_frames, &sample_info);
 }
 
 void PPB_Instance_Proxy::OnHostMsgSetCursor(
diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h
index a6516bc..5aaa2d1 100644
--- a/ppapi/proxy/ppb_instance_proxy.h
+++ b/ppapi/proxy/ppb_instance_proxy.h
@@ -146,9 +146,10 @@
   virtual void DeliverFrame(PP_Instance instance,
                             PP_Resource decrypted_frame,
                             const PP_DecryptedFrameInfo* frame_info) OVERRIDE;
-  virtual void DeliverSamples(PP_Instance instance,
-                              PP_Resource audio_frames,
-                              const PP_DecryptedBlockInfo* block_info) OVERRIDE;
+  virtual void DeliverSamples(
+      PP_Instance instance,
+      PP_Resource audio_frames,
+      const PP_DecryptedSampleInfo* sample_info) OVERRIDE;
 #endif  // !defined(OS_NACL)
 
   static const ApiID kApiID = API_ID_PPB_INSTANCE;
@@ -253,7 +254,7 @@
   virtual void OnHostMsgDeliverSamples(
       PP_Instance instance,
       PP_Resource audio_frames,
-      const std::string& serialized_block_info);
+      const std::string& serialized_sample_info);
 #endif  // !defined(OS_NACL)
 
   // Host -> Plugin message handlers.
diff --git a/ppapi/shared_impl/ppb_audio_shared.cc b/ppapi/shared_impl/ppb_audio_shared.cc
index 25d9011..b81cd3b 100644
--- a/ppapi/shared_impl/ppb_audio_shared.cc
+++ b/ppapi/shared_impl/ppb_audio_shared.cc
@@ -5,7 +5,6 @@
 #include "ppapi/shared_impl/ppb_audio_shared.h"
 
 #include "base/logging.h"
-#include "media/audio/shared_memory_util.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
 #include "ppapi/shared_impl/proxy_lock.h"
@@ -114,8 +113,7 @@
   bytes_per_second_ = kAudioOutputChannels * (kBitsPerAudioOutputSample / 8) *
                       sample_rate;
 
-  if (!shared_memory_->Map(
-          media::TotalSharedMemorySizeInBytes(shared_memory_size_))) {
+  if (!shared_memory_->Map(shared_memory_size_)) {
     PpapiGlobals::Get()->LogWithSource(
         instance,
         PP_LOGLEVEL_WARNING,
@@ -203,13 +201,11 @@
 #endif
 
 void PPB_Audio_Shared::Run() {
-  int pending_data;
-  const int bytes_per_frame =
-      sizeof(*audio_bus_->channel(0)) * audio_bus_->channels();
-
+  int pending_data = 0;
+  uint32_t buffer_index = 0;
   while (sizeof(pending_data) ==
       socket_->Receive(&pending_data, sizeof(pending_data)) &&
-      pending_data != media::kPauseMark) {
+      pending_data >= 0) {
     PP_TimeDelta latency =
         static_cast<double>(pending_data) / bytes_per_second_;
     callback_.Run(client_buffer_.get(), client_buffer_size_bytes_, latency,
@@ -220,14 +216,10 @@
         client_buffer_.get(), audio_bus_->frames(),
         kBitsPerAudioOutputSample / 8);
 
-    // Let the host know we are done.
-    // TODO(dalecurtis): Technically this is not the exact size.  Due to channel
-    // padding for alignment, there may be more data available than this.  We're
-    // relying on AudioSyncReader::Read() to parse this with that in mind.
-    // Rename these methods to Set/GetActualFrameCount().
-    media::SetActualDataSizeInBytes(
-        shared_memory_.get(), shared_memory_size_,
-        audio_bus_->frames() * bytes_per_frame);
+    ++buffer_index;
+    size_t bytes_sent = socket_->Send(&buffer_index, sizeof(buffer_index));
+    if (bytes_sent != sizeof(buffer_index))
+      break;
   }
 }
 
diff --git a/ppapi/shared_impl/ppb_image_data_shared.cc b/ppapi/shared_impl/ppb_image_data_shared.cc
index 50751a0..3900c92 100644
--- a/ppapi/shared_impl/ppb_image_data_shared.cc
+++ b/ppapi/shared_impl/ppb_image_data_shared.cc
@@ -26,7 +26,12 @@
   NOTIMPLEMENTED();
   return PP_IMAGEDATAFORMAT_BGRA_PREMUL;
 #else
-  return PP_IMAGEDATAFORMAT_BGRA_PREMUL;
+  if (SK_B32_SHIFT == 0)
+    return PP_IMAGEDATAFORMAT_BGRA_PREMUL;
+  else if (SK_R32_SHIFT == 0)
+    return PP_IMAGEDATAFORMAT_RGBA_PREMUL;
+  else
+    return PP_IMAGEDATAFORMAT_BGRA_PREMUL; // Default to something on failure
 #endif
 }
 
diff --git a/ppapi/thunk/ppb_content_decryptor_private_thunk.cc b/ppapi/thunk/ppb_content_decryptor_private_thunk.cc
index 7fe79e1..a43d24d 100644
--- a/ppapi/thunk/ppb_content_decryptor_private_thunk.cc
+++ b/ppapi/thunk/ppb_content_decryptor_private_thunk.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // From private/ppb_content_decryptor_private.idl,
-//   modified Tue Sep 17 11:31:05 2013.
+//   modified Thu Oct 10 14:49:51 2013.
 
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/private/ppb_content_decryptor_private.h"
@@ -123,14 +123,14 @@
 void DeliverSamples(
     PP_Instance instance,
     PP_Resource audio_frames,
-    const struct PP_DecryptedBlockInfo* decrypted_block_info) {
+    const struct PP_DecryptedSampleInfo* decrypted_sample_info) {
   VLOG(4) << "PPB_ContentDecryptor_Private::DeliverSamples()";
   EnterInstance enter(instance);
   if (enter.failed())
     return;
   enter.functions()->DeliverSamples(instance,
                                     audio_frames,
-                                    decrypted_block_info);
+                                    decrypted_sample_info);
 }
 
 const PPB_ContentDecryptor_Private_0_7
diff --git a/ppapi/thunk/ppb_instance_api.h b/ppapi/thunk/ppb_instance_api.h
index 0d424a5..93eba9c 100644
--- a/ppapi/thunk/ppb_instance_api.h
+++ b/ppapi/thunk/ppb_instance_api.h
@@ -173,7 +173,7 @@
                             const PP_DecryptedFrameInfo* frame_info) = 0;
   virtual void DeliverSamples(PP_Instance instance,
                               PP_Resource audio_frames,
-                              const PP_DecryptedBlockInfo* block_info) = 0;
+                              const PP_DecryptedSampleInfo* sample_info) = 0;
 
   // URLUtil.
   virtual PP_Var ResolveRelativeToDocument(
diff --git a/printing/DEPS b/printing/DEPS
index 00c20e2..64123b8 100644
--- a/printing/DEPS
+++ b/printing/DEPS
@@ -7,5 +7,6 @@
   "+ui/base/resource",
   "+ui/base/text",
   "+ui/gfx",
+  "+ui/shell_dialogs",
   "+win8/util",
 ]
diff --git a/printing/page_number.cc b/printing/page_number.cc
index 8e92870..db3861d 100644
--- a/printing/page_number.cc
+++ b/printing/page_number.cc
@@ -31,7 +31,7 @@
 
 void PageNumber::Init(const PrintSettings& settings, int document_page_count) {
   DCHECK(document_page_count);
-  ranges_ = settings.ranges.empty() ? NULL : &settings.ranges;
+  ranges_ = settings.ranges().empty() ? NULL : &settings.ranges();
   document_page_count_ = document_page_count;
   if (ranges_) {
     page_range_index_ = 0;
diff --git a/printing/print_dialog_gtk_interface.h b/printing/print_dialog_gtk_interface.h
index b361837..3b3fcdd 100644
--- a/printing/print_dialog_gtk_interface.h
+++ b/printing/print_dialog_gtk_interface.h
@@ -22,12 +22,12 @@
   // Tell the dialog to use the default print setting.
   virtual void UseDefaultSettings() = 0;
 
-  // Update the dialog to use |job_settings| and |ranges|, where |job_settings|
-  // is a dictionary of settings with possible keys from
-  // printing/print_job_constants.h. Only used when printing without the system
-  // print dialog. E.g. for Print Preview. Returns false on error.
-  virtual bool UpdateSettings(const base::DictionaryValue& job_settings,
-                              const PageRanges& ranges,
+  // Updates the dialog to use |settings|. Only used when printing without the
+  // system print dialog. E.g. for Print Preview. Returns false on error.
+  // |target_is_pdf| is true if implementation needs to generate PDF without
+  // actual printing. In this case implementation may avoid setup of native
+  // print system. Ex. "save to pdf" or Cloud Print.
+  virtual bool UpdateSettings(bool target_is_pdf,
                               PrintSettings* settings) = 0;
 
   // Shows the dialog and handles the response with |callback|. Only used when
diff --git a/printing/print_job_constants.cc b/printing/print_job_constants.cc
index f659aed..b2fefa8 100644
--- a/printing/print_job_constants.cc
+++ b/printing/print_job_constants.cc
@@ -129,9 +129,8 @@
 const int FIRST_PAGE_INDEX = 0;
 const int COMPLETE_PREVIEW_DOCUMENT_INDEX = -1;
 
-#if defined(OS_MACOSX)
+// Whether to show PDF in view provided by OS. Implemented for MacOS only.
 const char kSettingOpenPDFInPreview[] = "OpenPDFInPreview";
-#endif
 
 #if defined (USE_CUPS)
 const char kBlack[] = "Black";
diff --git a/printing/print_job_constants.h b/printing/print_job_constants.h
index c038eb0..526f8ee 100644
--- a/printing/print_job_constants.h
+++ b/printing/print_job_constants.h
@@ -53,10 +53,7 @@
 
 PRINTING_EXPORT extern const int FIRST_PAGE_INDEX;
 PRINTING_EXPORT extern const int COMPLETE_PREVIEW_DOCUMENT_INDEX;
-
-#if defined(OS_MACOSX)
 PRINTING_EXPORT extern const char kSettingOpenPDFInPreview[];
-#endif  // defined(OS_MACOSX)
 
 #if defined (USE_CUPS)
 // Printer color models
diff --git a/printing/print_settings.cc b/printing/print_settings.cc
index f024d2a..9e2a251 100644
--- a/printing/print_settings.cc
+++ b/printing/print_settings.cc
@@ -110,54 +110,49 @@
 // Global SequenceNumber used for generating unique cookie values.
 static base::StaticAtomicSequenceNumber cookie_seq;
 
-PrintSettings::PrintSettings()
-    : min_shrink(1.25),
-      max_shrink(2.0),
-      desired_dpi(72),
-      selection_only(false),
-      margin_type(DEFAULT_MARGINS),
-      display_header_footer(false),
-      should_print_backgrounds(false),
-      dpi_(0),
-      landscape_(false),
-      supports_alpha_blend_(true) {
+PrintSettings::PrintSettings() {
+  Clear();
 }
 
 PrintSettings::~PrintSettings() {
 }
 
 void PrintSettings::Clear() {
-  ranges.clear();
-  min_shrink = 1.25;
-  max_shrink = 2.;
-  desired_dpi = 72;
-  selection_only = false;
-  date = base::string16();
-  title = base::string16();
-  url = base::string16();
-  display_header_footer = false;
-  printer_name_.clear();
+  ranges_.clear();
+  margin_type_ = DEFAULT_MARGINS;
+  min_shrink_ = 1.25;
+  max_shrink_ = 2.;
+  desired_dpi_ = 72;
+  selection_only_ = false;
+  title_ = base::string16();
+  url_ = base::string16();
+  display_header_footer_ = false;
   device_name_.clear();
   page_setup_device_units_.Clear();
   dpi_ = 0;
   landscape_ = false;
   supports_alpha_blend_ = true;
-  should_print_backgrounds = false;
+  should_print_backgrounds_ = false;
+  collate_ = false;
+  color_ = UNKNOWN_COLOR_MODEL;
+  copies_ = 0;
+  duplex_mode_ = UNKNOWN_DUPLEX_MODE;
 }
 
 void PrintSettings::SetPrinterPrintableArea(
     gfx::Size const& physical_size_device_units,
     gfx::Rect const& printable_area_device_units,
-    int units_per_inch) {
+    int units_per_inch,
+    bool landscape_needs_flip) {
   int header_footer_text_height = 0;
-  if (display_header_footer) {
+  if (display_header_footer_) {
     // Hard-code text_height = 0.5cm = ~1/5 of inch.
     header_footer_text_height = ConvertUnit(kSettingHeaderFooterInterstice,
                                             kPointsPerInch, units_per_inch);
   }
 
   PageMargins margins;
-  switch (margin_type) {
+  switch (margin_type_) {
     case DEFAULT_MARGINS: {
       // Default margins 1.0cm = ~2/5 of an inch.
       int margin_printer_units = ConvertUnit(1000, kHundrethsMMPerInch,
@@ -206,7 +201,7 @@
     }
   }
 
-  if (margin_type == DEFAULT_MARGINS || margin_type == PRINTABLE_AREA_MARGINS)
+  if (margin_type_ == DEFAULT_MARGINS || margin_type_ == PRINTABLE_AREA_MARGINS)
     page_setup_device_units_.SetRequestedMargins(margins);
   else
     page_setup_device_units_.ForceRequestedMargins(margins);
@@ -214,27 +209,14 @@
   page_setup_device_units_.Init(physical_size_device_units,
                                 printable_area_device_units,
                                 header_footer_text_height);
+  if (landscape_ && landscape_needs_flip)
+    page_setup_device_units_.FlipOrientation();
 }
 
 void PrintSettings::SetCustomMargins(
     const PageMargins& requested_margins_in_points) {
   requested_custom_margins_in_points_ = requested_margins_in_points;
-  margin_type = CUSTOM_MARGINS;
-}
-
-bool PrintSettings::Equals(const PrintSettings& rhs) const {
-  // Do not test the display device name (printer_name_) for equality since it
-  // may sometimes be chopped off at 30 chars. As long as device_name is the
-  // same, that's fine.
-  return ranges == rhs.ranges &&
-      min_shrink == rhs.min_shrink &&
-      max_shrink == rhs.max_shrink &&
-      desired_dpi == rhs.desired_dpi &&
-      device_name_ == rhs.device_name_ &&
-      page_setup_device_units_.Equals(rhs.page_setup_device_units_) &&
-      dpi_ == rhs.dpi_ &&
-      landscape_ == rhs.landscape_ &&
-      should_print_backgrounds == rhs.should_print_backgrounds;
+  margin_type_ = CUSTOM_MARGINS;
 }
 
 int PrintSettings::NewCookie() {
diff --git a/printing/print_settings.h b/printing/print_settings.h
index f177699..b80d354 100644
--- a/printing/print_settings.h
+++ b/printing/print_settings.h
@@ -35,36 +35,38 @@
   // Reinitialize the settings to the default values.
   void Clear();
 
-  // Set printer printable area in in device units.
-  void SetPrinterPrintableArea(gfx::Size const& physical_size_device_units,
-                               gfx::Rect const& printable_area_device_units,
-                               int units_per_inch);
-
   void SetCustomMargins(const PageMargins& requested_margins_in_points);
+  void set_margin_type(MarginType margin_type) { margin_type_ = margin_type; }
+  MarginType margin_type() const { return margin_type_; }
 
-  // Equality operator.
-  // NOTE: printer_name is NOT tested for equality since it doesn't affect the
-  // output.
-  bool Equals(const PrintSettings& rhs) const;
+  // Updates the orientation and flip the page if needed.
+  void SetOrientation(bool landscape);
+  bool landscape() const { return landscape_; }
 
-  void set_landscape(bool landscape) { landscape_ = landscape; }
-  void set_printer_name(const base::string16& printer_name) {
-    printer_name_ = printer_name;
+  // Set printer printable area in in device units.
+  // Some platforms already provide flipped area. Set |landscape_needs_flip|
+  // to false on those platforms to avoid double flipping.
+  void SetPrinterPrintableArea(const gfx::Size& physical_size_device_units,
+                               const gfx::Rect& printable_area_device_units,
+                               int units_per_inch,
+                               bool landscape_needs_flip);
+  const PageSetup& page_setup_device_units() const {
+    return page_setup_device_units_;
   }
-  const base::string16& printer_name() const { return printer_name_; }
+
   void set_device_name(const base::string16& device_name) {
     device_name_ = device_name;
   }
   const base::string16& device_name() const { return device_name_; }
+
   void set_dpi(int dpi) { dpi_ = dpi; }
   int dpi() const { return dpi_; }
+
   void set_supports_alpha_blend(bool supports_alpha_blend) {
     supports_alpha_blend_ = supports_alpha_blend;
   }
   bool supports_alpha_blend() const { return supports_alpha_blend_; }
-  const PageSetup& page_setup_device_units() const {
-    return page_setup_device_units_;
-  }
+
   int device_units_per_inch() const {
 #if defined(OS_MACOSX)
     return 72;
@@ -73,58 +75,102 @@
 #endif  // defined(OS_MACOSX)
   }
 
-  // Multi-page printing. Each PageRange describes a from-to page combination.
-  // This permits printing selected pages only.
-  PageRanges ranges;
+  void set_ranges(const PageRanges& ranges) { ranges_ = ranges; };
+  const PageRanges& ranges() const { return ranges_; };
 
-  // By imaging to a width a little wider than the available pixels, thin pages
-  // will be scaled down a little, matching the way they print in IE and Camino.
-  // This lets them use fewer sheets than they would otherwise, which is
-  // presumably why other browsers do this. Wide pages will be scaled down more
-  // than this.
-  double min_shrink;
+  void set_selection_only(bool selection_only) {
+    selection_only_ = selection_only;
+  }
+  bool selection_only() const { return selection_only_; }
 
-  // This number determines how small we are willing to reduce the page content
-  // in order to accommodate the widest line. If the page would have to be
-  // reduced smaller to make the widest line fit, we just clip instead (this
-  // behavior matches MacIE and Mozilla, at least)
-  double max_shrink;
+  void set_should_print_backgrounds(bool should_print_backgrounds) {
+    should_print_backgrounds_ = should_print_backgrounds;
+  }
+  bool should_print_backgrounds() const { return should_print_backgrounds_; }
 
-  // Desired visible dots per inch rendering for output. Printing should be
-  // scaled to ScreenDpi/dpix*desired_dpi.
-  int desired_dpi;
+  void set_display_header_footer(bool display_header_footer) {
+    display_header_footer_ = display_header_footer;
+  }
+  bool display_header_footer() const { return display_header_footer_; }
 
-  // Indicates if the user only wants to print the current selection.
-  bool selection_only;
+  void set_title(const base::string16& title) { title_ = title; }
+  const base::string16& title() const { return title_; }
 
-  // Indicates what kind of margins should be applied to the printable area.
-  MarginType margin_type;
+  void set_url(const base::string16& url) { url_ = url; }
+  const base::string16& url() const { return url_; }
+
+  void set_collate(bool collate) { collate_ = collate; }
+  bool collate() const { return collate_; }
+
+  void set_color(ColorModel color) { color_ = color; }
+  ColorModel color() const { return color_; }
+
+  void set_copies(int copies) { copies_ = copies; }
+  int copies() const { return copies_; }
+
+  void set_duplex_mode(DuplexMode duplex_mode) { duplex_mode_ = duplex_mode; }
+  DuplexMode duplex_mode() const { return duplex_mode_; }
+
+  int desired_dpi() const { return desired_dpi_; }
+
+  double max_shrink() const { return max_shrink_; }
+
+  double min_shrink() const { return min_shrink_; }
 
   // Cookie generator. It is used to initialize PrintedDocument with its
   // associated PrintSettings, to be sure that each generated PrintedPage is
   // correctly associated with its corresponding PrintedDocument.
   static int NewCookie();
 
-  // Updates the orientation and flip the page if needed.
-  void SetOrientation(bool landscape);
+ private:
+  // Multi-page printing. Each PageRange describes a from-to page combination.
+  // This permits printing selected pages only.
+  PageRanges ranges_;
+
+  // By imaging to a width a little wider than the available pixels, thin pages
+  // will be scaled down a little, matching the way they print in IE and Camino.
+  // This lets them use fewer sheets than they would otherwise, which is
+  // presumably why other browsers do this. Wide pages will be scaled down more
+  // than this.
+  double min_shrink_;
+
+  // This number determines how small we are willing to reduce the page content
+  // in order to accommodate the widest line. If the page would have to be
+  // reduced smaller to make the widest line fit, we just clip instead (this
+  // behavior matches MacIE and Mozilla, at least)
+  double max_shrink_;
+
+  // Desired visible dots per inch rendering for output. Printing should be
+  // scaled to ScreenDpi/dpix*desired_dpi.
+  int desired_dpi_;
+
+  // Indicates if the user only wants to print the current selection.
+  bool selection_only_;
+
+  // Indicates what kind of margins should be applied to the printable area.
+  MarginType margin_type_;
 
   // Strings to be printed as headers and footers if requested by the user.
-  base::string16 date;
-  base::string16 title;
-  base::string16 url;
+  base::string16 title_;
+  base::string16 url_;
 
   // True if the user wants headers and footers to be displayed.
-  bool display_header_footer;
+  bool display_header_footer_;
 
   // True if the user wants to print CSS backgrounds.
-  bool should_print_backgrounds;
+  bool should_print_backgrounds_;
 
- private:
-  //////////////////////////////////////////////////////////////////////////////
-  // Settings that can't be changed without side-effects.
+  // True if the user wants to print with collate.
+  bool collate_;
 
-  // Printer name as shown to the user.
-  base::string16 printer_name_;
+  // True if the user wants to print with collate.
+  ColorModel color_;
+
+  // Number of copies user wants to print.
+  int copies_;
+
+  // Duplex type user wants to use.
+  DuplexMode duplex_mode_;
 
   // Printer device name as opened by the OS.
   base::string16 device_name_;
diff --git a/printing/print_settings_initializer.cc b/printing/print_settings_initializer.cc
index 9932536..565fc78 100644
--- a/printing/print_settings_initializer.cc
+++ b/printing/print_settings_initializer.cc
@@ -8,46 +8,99 @@
 #include <cmath>
 #include <string>
 
-#include "base/i18n/time_formatting.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "printing/page_size_margins.h"
 #include "printing/print_job_constants.h"
 #include "printing/print_settings.h"
 #include "printing/units.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/text_elider.h"
-#include "url/gurl.h"
 
 namespace printing {
 
-void PrintSettingsInitializer::InitHeaderFooterStrings(
-      const base::DictionaryValue& job_settings,
-      PrintSettings* print_settings) {
+bool PrintSettingsInitializer::InitSettings(
+    const base::DictionaryValue& job_settings,
+    const PageRanges& ranges,
+    PrintSettings* settings) {
+  bool display_header_footer = false;
   if (!job_settings.GetBoolean(kSettingHeaderFooterEnabled,
-                               &print_settings->display_header_footer)) {
-    NOTREACHED();
+                               &display_header_footer)) {
+    return false;
   }
-  if (!print_settings->display_header_footer)
-    return;
+  settings->set_display_header_footer(display_header_footer);
 
-  base::string16 date = base::TimeFormatShortDateNumeric(base::Time::Now());
-  base::string16 title;
-  base::string16 url;
-  if (!job_settings.GetString(kSettingHeaderFooterTitle, &title) ||
-      !job_settings.GetString(kSettingHeaderFooterURL, &url)) {
-    NOTREACHED();
+  if (settings->display_header_footer()) {
+    base::string16 title;
+    base::string16 url;
+    if (!job_settings.GetString(kSettingHeaderFooterTitle, &title) ||
+        !job_settings.GetString(kSettingHeaderFooterURL, &url)) {
+      return false;
+    }
+    settings->set_title(title);
+    settings->set_url(url);
   }
 
-  print_settings->date = date;
-  print_settings->title = title;
-  const gfx::FontList& default_fonts =
-      ui::ResourceBundle::GetSharedInstance().GetFontList(
-          ui::ResourceBundle::BaseFont);
-  print_settings->url = gfx::ElideUrl(GURL(url), default_fonts, 0,
-                                      std::string());
+  bool backgrounds = false;
+  bool selection_only = false;
+  if (!job_settings.GetBoolean(kSettingShouldPrintBackgrounds, &backgrounds) ||
+      !job_settings.GetBoolean(kSettingShouldPrintSelectionOnly,
+                               &selection_only)) {
+    return false;
+  }
+  settings->set_should_print_backgrounds(backgrounds);
+  settings->set_selection_only(selection_only);
+
+  int margin_type = DEFAULT_MARGINS;
+  if (!job_settings.GetInteger(kSettingMarginsType, &margin_type) ||
+      (margin_type != DEFAULT_MARGINS &&
+       margin_type != NO_MARGINS &&
+       margin_type != CUSTOM_MARGINS &&
+       margin_type != PRINTABLE_AREA_MARGINS)) {
+    margin_type = DEFAULT_MARGINS;
+  }
+  settings->set_margin_type(static_cast<MarginType>(margin_type));
+
+  if (margin_type == CUSTOM_MARGINS) {
+    PageSizeMargins page_size_margins;
+    GetCustomMarginsFromJobSettings(job_settings, &page_size_margins);
+
+    PageMargins margins_in_points;
+    margins_in_points.Clear();
+    margins_in_points.top = page_size_margins.margin_top;
+    margins_in_points.bottom = page_size_margins.margin_bottom;
+    margins_in_points.left = page_size_margins.margin_left;
+    margins_in_points.right = page_size_margins.margin_right;
+
+    settings->SetCustomMargins(margins_in_points);
+  }
+
+  settings->set_ranges(ranges);
+
+  int color = 0;
+  bool landscape = false;
+  int duplex_mode = 0;
+  base::string16 device_name;
+  bool collate = false;
+  int copies = 1;
+
+  if (!job_settings.GetBoolean(kSettingCollate, &collate) ||
+      !job_settings.GetInteger(kSettingCopies, &copies) ||
+      !job_settings.GetInteger(kSettingColor, &color) ||
+      !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
+      !job_settings.GetBoolean(kSettingLandscape, &landscape) ||
+      !job_settings.GetString(kSettingDeviceName, &device_name)) {
+    return false;
+  }
+
+  settings->set_collate(collate);
+  settings->set_copies(copies);
+  settings->SetOrientation(landscape);
+  settings->set_device_name(device_name);
+  settings->set_duplex_mode(static_cast<DuplexMode>(duplex_mode));
+  settings->set_color(static_cast<ColorModel>(color));
+
+  return true;
 }
 
 }  // namespace printing
diff --git a/printing/print_settings_initializer.h b/printing/print_settings_initializer.h
index 4897be8..a1093c5 100644
--- a/printing/print_settings_initializer.h
+++ b/printing/print_settings_initializer.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "printing/page_range.h"
 #include "printing/printing_export.h"
 
 namespace base {
@@ -21,8 +22,9 @@
 // provided |job_settings|.
 class PRINTING_EXPORT PrintSettingsInitializer {
  public:
-  static void InitHeaderFooterStrings(
+  static bool InitSettings(
       const base::DictionaryValue& job_settings,
+      const PageRanges& ranges,
       PrintSettings* print_settings);
 
  private:
diff --git a/printing/print_settings_initializer_gtk.cc b/printing/print_settings_initializer_gtk.cc
index b8931f5..793fdb8 100644
--- a/printing/print_settings_initializer_gtk.cc
+++ b/printing/print_settings_initializer_gtk.cc
@@ -18,8 +18,6 @@
 void PrintSettingsInitializerGtk::InitPrintSettings(
     GtkPrintSettings* settings,
     GtkPageSetup* page_setup,
-    const PageRanges& new_ranges,
-    bool print_selection_only,
     PrintSettings* print_settings) {
   DCHECK(settings);
   DCHECK(page_setup);
@@ -27,10 +25,7 @@
 
   base::string16 name(base::UTF8ToUTF16(static_cast<const char*>(
       gtk_print_settings_get_printer(settings))));
-  print_settings->set_printer_name(name);
-  print_settings->set_device_name(print_settings->printer_name());
-  print_settings->ranges = new_ranges;
-  print_settings->selection_only = print_selection_only;
+  print_settings->set_device_name(name);
 
   gfx::Size physical_size_device_units;
   gfx::Rect printable_area_device_units;
@@ -61,9 +56,6 @@
   }
 
   print_settings->set_dpi(dpi);
-  print_settings->SetPrinterPrintableArea(physical_size_device_units,
-                                          printable_area_device_units,
-                                          dpi);
 
   // Note: With the normal GTK print dialog, when the user selects the landscape
   // orientation, all that does is change the paper size. Which seems to be
@@ -73,7 +65,12 @@
   // Thus this is only useful in print preview mode, where we manually set the
   // orientation and change the paper size ourselves.
   GtkPageOrientation orientation = gtk_print_settings_get_orientation(settings);
+  // Set before SetPrinterPrintableArea to make it flip area if necessary.
   print_settings->SetOrientation(orientation == GTK_PAGE_ORIENTATION_LANDSCAPE);
+
+  print_settings->SetPrinterPrintableArea(physical_size_device_units,
+                                          printable_area_device_units,
+                                          dpi, true);
 }
 
 const double PrintSettingsInitializerGtk::kTopMarginInInch = 0.25;
diff --git a/printing/print_settings_initializer_gtk.h b/printing/print_settings_initializer_gtk.h
index 5807500..828c34d 100644
--- a/printing/print_settings_initializer_gtk.h
+++ b/printing/print_settings_initializer_gtk.h
@@ -20,8 +20,6 @@
  public:
   static void InitPrintSettings(GtkPrintSettings* settings,
                                 GtkPageSetup* page_setup,
-                                const PageRanges& new_ranges,
-                                bool print_selection_only,
                                 PrintSettings* print_settings);
 
   // The default margins, in points. These values are based on 72 dpi,
diff --git a/printing/print_settings_initializer_mac.cc b/printing/print_settings_initializer_mac.cc
index fd66598..9333ec9 100644
--- a/printing/print_settings_initializer_mac.cc
+++ b/printing/print_settings_initializer_mac.cc
@@ -13,21 +13,13 @@
 void PrintSettingsInitializerMac::InitPrintSettings(
     PMPrinter printer,
     PMPageFormat page_format,
-    const PageRanges& new_ranges,
-    bool print_selection_only,
     PrintSettings* print_settings) {
-  DCHECK(print_settings);
-
-  print_settings->set_printer_name(
-      base::SysCFStringRefToUTF16(PMPrinterGetName(printer)));
   print_settings->set_device_name(
       base::SysCFStringRefToUTF16(PMPrinterGetID(printer)));
-  print_settings->ranges = new_ranges;
 
   PMOrientation orientation = kPMPortrait;
   PMGetOrientation(page_format, &orientation);
-  print_settings->set_landscape(orientation == kPMLandscape);
-  print_settings->selection_only = print_selection_only;
+  print_settings->SetOrientation(orientation == kPMLandscape);
 
   UInt32 resolution_count = 0;
   PMResolution best_resolution = { 72.0, 72.0 };
@@ -64,7 +56,7 @@
 
   print_settings->SetPrinterPrintableArea(physical_size_device_units,
                                           printable_area_device_units,
-                                          72);
+                                          72, false);
 }
 
 }  // namespace printing
diff --git a/printing/print_settings_initializer_mac.h b/printing/print_settings_initializer_mac.h
index 2b79251..bbdd0b1 100644
--- a/printing/print_settings_initializer_mac.h
+++ b/printing/print_settings_initializer_mac.h
@@ -19,8 +19,6 @@
  public:
   static void InitPrintSettings(PMPrinter printer,
                                 PMPageFormat page_format,
-                                const PageRanges& new_ranges,
-                                bool print_selection_only,
                                 PrintSettings* print_settings);
 
  private:
diff --git a/printing/print_settings_initializer_win.cc b/printing/print_settings_initializer_win.cc
index 0ec96d0..ef46f8d 100644
--- a/printing/print_settings_initializer_win.cc
+++ b/printing/print_settings_initializer_win.cc
@@ -14,18 +14,10 @@
 void PrintSettingsInitializerWin::InitPrintSettings(
     HDC hdc,
     const DEVMODE& dev_mode,
-    const PageRanges& new_ranges,
-    const std::wstring& new_device_name,
-    bool print_selection_only,
     PrintSettings* print_settings) {
   DCHECK(hdc);
   DCHECK(print_settings);
-
-  print_settings->set_printer_name(dev_mode.dmDeviceName);
-  print_settings->set_device_name(new_device_name);
-  print_settings->ranges = const_cast<PageRanges&>(new_ranges);
-  print_settings->set_landscape(dev_mode.dmOrientation == DMORIENT_LANDSCAPE);
-  print_settings->selection_only = print_selection_only;
+  print_settings->SetOrientation(dev_mode.dmOrientation == DMORIENT_LANDSCAPE);
 
   int dpi = GetDeviceCaps(hdc, LOGPIXELSX);
   print_settings->set_dpi(dpi);
@@ -59,7 +51,7 @@
 
   print_settings->SetPrinterPrintableArea(physical_size_device_units,
                                           printable_area_device_units,
-                                          dpi);
+                                          dpi, false);
 }
 
 }  // namespace printing
diff --git a/printing/print_settings_initializer_win.h b/printing/print_settings_initializer_win.h
index 720abae..fcbacc2 100644
--- a/printing/print_settings_initializer_win.h
+++ b/printing/print_settings_initializer_win.h
@@ -22,9 +22,6 @@
  public:
   static void InitPrintSettings(HDC hdc,
                                 const DEVMODE& dev_mode,
-                                const PageRanges& new_ranges,
-                                const std::wstring& new_device_name,
-                                bool print_selection_only,
                                 PrintSettings* print_settings);
 
  private:
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index e2cd74a..1f08ac1 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -51,10 +51,10 @@
       immutable_(settings, source, cookie) {
 
   // Records the expected page count if a range is setup.
-  if (!settings.ranges.empty()) {
+  if (!settings.ranges().empty()) {
     // If there is a range, set the number of page
-    for (unsigned i = 0; i < settings.ranges.size(); ++i) {
-      const PageRange& range = settings.ranges[i];
+    for (unsigned i = 0; i < settings.ranges().size(); ++i) {
+      const PageRange& range = settings.ranges()[i];
       mutable_.expected_page_count_ += range.to - range.from + 1;
     }
   }
@@ -153,7 +153,7 @@
   base::AutoLock lock(lock_);
   DCHECK_EQ(0, mutable_.page_count_);
   mutable_.page_count_ = max_page;
-  if (immutable_.settings_.ranges.empty()) {
+  if (immutable_.settings_.ranges().empty()) {
     mutable_.expected_page_count_ = max_page;
   } else {
     // If there is a range, don't bother since expected_page_count_ is already
diff --git a/printing/printing.gyp b/printing/printing.gyp
index 455786e..5e6c388 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -18,6 +18,7 @@
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/icu/icu.gyp:icuuc',
         '../ui/gfx/gfx.gyp:gfx',
+        '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
         '../ui/ui.gyp:ui',
         '../url/url.gyp:url_lib',
       ],
diff --git a/printing/printing_context.cc b/printing/printing_context.cc
index 98ea11c..edbcaa4 100644
--- a/printing/printing_context.cc
+++ b/printing/printing_context.cc
@@ -24,7 +24,7 @@
 
 void PrintingContext::set_margin_type(MarginType type) {
   DCHECK(type != CUSTOM_MARGINS);
-  settings_.margin_type = type;
+  settings_.set_margin_type(type);
 }
 
 void PrintingContext::ResetSettings() {
@@ -47,41 +47,31 @@
     const PageRanges& ranges) {
   ResetSettings();
 
-  job_settings.GetBoolean(kSettingHeaderFooterEnabled,
-                          &settings_.display_header_footer);
+  if (settings_.dpi() == 0)
+    UseDefaultSettings();
 
-  int margin_type = DEFAULT_MARGINS;
-  if (!job_settings.GetInteger(kSettingMarginsType, &margin_type) ||
-      (margin_type != DEFAULT_MARGINS &&
-       margin_type != NO_MARGINS &&
-       margin_type != CUSTOM_MARGINS &&
-       margin_type != PRINTABLE_AREA_MARGINS)) {
-    margin_type = DEFAULT_MARGINS;
-  }
-  settings_.margin_type = static_cast<MarginType>(margin_type);
-
-  if (margin_type == CUSTOM_MARGINS) {
-    printing::PageSizeMargins page_size_margins;
-    GetCustomMarginsFromJobSettings(job_settings, &page_size_margins);
-
-    PageMargins margins_in_points;
-    margins_in_points.Clear();
-    margins_in_points.top = page_size_margins.margin_top;
-    margins_in_points.bottom = page_size_margins.margin_bottom;
-    margins_in_points.left = page_size_margins.margin_left;
-    margins_in_points.right = page_size_margins.margin_right;
-
-    settings_.SetCustomMargins(margins_in_points);
+  if (!PrintSettingsInitializer::InitSettings(job_settings, ranges,
+                                              &settings_)) {
+    NOTREACHED();
+    return OnError();
   }
 
-  PrintingContext::Result result = UpdatePrinterSettings(job_settings, ranges);
-  PrintSettingsInitializer::InitHeaderFooterStrings(job_settings, &settings_);
+  bool print_to_pdf = false;
+  bool is_cloud_dialog = false;
 
-  job_settings.GetBoolean(kSettingShouldPrintBackgrounds,
-                          &settings_.should_print_backgrounds);
-  job_settings.GetBoolean(kSettingShouldPrintSelectionOnly,
-                          &settings_.selection_only);
-  return result;
+  if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
+      !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog)) {
+    NOTREACHED();
+    return OnError();
+  }
+
+  bool print_to_cloud = job_settings.HasKey(kSettingCloudPrintId);
+  bool open_in_external_preview =
+      job_settings.HasKey(kSettingOpenPDFInPreview);
+
+  return UpdatePrinterSettings(
+      print_to_pdf || is_cloud_dialog || print_to_cloud,
+      open_in_external_preview);
 }
 
 }  // namespace printing
diff --git a/printing/printing_context.h b/printing/printing_context.h
index f4ba7ad..7fa90d2 100644
--- a/printing/printing_context.h
+++ b/printing/printing_context.h
@@ -51,11 +51,14 @@
   // default device settings.
   virtual Result UseDefaultSettings() = 0;
 
-  // Updates printer related settings. |job_settings| contains all print job
-  // settings information. |ranges| has the new page range settings.
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) = 0;
+  // Updates printer settings.
+  // |target_is_pdf| is true if implementation needs to generate PDF without
+  // actual printing. In this case implementation may avoid setup of native
+  // print system. Ex. "save to pdf" or Cloud Print.
+  // |external_preview| is true if pdf is going to be opened in external
+  // preview. Used by MacOS only now to open Preview.app.
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) = 0;
 
   // Updates Print Settings. |job_settings| contains all print job
   // settings information. |ranges| has the new page range settings.
diff --git a/printing/printing_context_android.h b/printing/printing_context_android.h
index ff0d222..67d68eb 100644
--- a/printing/printing_context_android.h
+++ b/printing/printing_context_android.h
@@ -37,9 +37,8 @@
       bool has_selection,
       const PrintSettingsCallback& callback) OVERRIDE;
   virtual Result UseDefaultSettings() OVERRIDE;
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) OVERRIDE;
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) OVERRIDE;
   virtual Result InitWithSettings(const PrintSettings& settings) OVERRIDE;
   virtual Result NewDocument(const base::string16& document_name) OVERRIDE;
   virtual Result NewPage() OVERRIDE;
diff --git a/printing/printing_context_gtk.cc b/printing/printing_context_gtk.cc
index 39d0ef5..6cf0015 100644
--- a/printing/printing_context_gtk.cc
+++ b/printing/printing_context_gtk.cc
@@ -79,15 +79,17 @@
 }
 
 PrintingContext::Result PrintingContextGtk::UpdatePrinterSettings(
-    const DictionaryValue& job_settings, const PageRanges& ranges) {
+    bool target_is_pdf,
+    bool external_preview) {
   DCHECK(!in_print_job_);
+  DCHECK(!external_preview) << "Not implemented";
 
   if (!print_dialog_) {
     print_dialog_ = create_dialog_func_(this);
     print_dialog_->AddRefToDialog();
   }
 
-  if (!print_dialog_->UpdateSettings(job_settings, ranges, &settings_))
+  if (!print_dialog_->UpdateSettings(target_is_pdf, &settings_))
     return OnError();
 
   return OK;
diff --git a/printing/printing_context_gtk.h b/printing/printing_context_gtk.h
index 3b4e831..1977893 100644
--- a/printing/printing_context_gtk.h
+++ b/printing/printing_context_gtk.h
@@ -38,9 +38,8 @@
       bool has_selection,
       const PrintSettingsCallback& callback) OVERRIDE;
   virtual Result UseDefaultSettings() OVERRIDE;
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) OVERRIDE;
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) OVERRIDE;
   virtual Result InitWithSettings(const PrintSettings& settings) OVERRIDE;
   virtual Result NewDocument(const base::string16& document_name) OVERRIDE;
   virtual Result NewPage() OVERRIDE;
diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h
index 8dc70ba..8e7e510 100644
--- a/printing/printing_context_mac.h
+++ b/printing/printing_context_mac.h
@@ -31,9 +31,8 @@
       bool has_selection,
       const PrintSettingsCallback& callback) OVERRIDE;
   virtual Result UseDefaultSettings() OVERRIDE;
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) OVERRIDE;
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) OVERRIDE;
   virtual Result InitWithSettings(const PrintSettings& settings) OVERRIDE;
   virtual Result NewDocument(const base::string16& document_name) OVERRIDE;
   virtual Result NewPage() OVERRIDE;
@@ -48,8 +47,8 @@
   // after changes to |print_info_| in order for the changes to take effect in
   // printing.
   // This function ignores the page range information specified in the print
-  // info object and use |ranges| instead.
-  void InitPrintSettingsFromPrintInfo(const PageRanges& ranges);
+  // info object and use |settings_.ranges| instead.
+  void InitPrintSettingsFromPrintInfo();
 
   // Returns the set of page ranges constructed from |print_info_|.
   PageRanges GetPageRangesFromPrintInfo();
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index bce03c8..9ed31dd 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -15,6 +15,7 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsexception_enabler.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "printing/print_settings_initializer_mac.h"
 
@@ -97,7 +98,8 @@
   NSInteger selection = [panel runModalWithPrintInfo:printInfo];
   if (selection == NSOKButton) {
     print_info_.reset([[panel printInfo] retain]);
-    InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo());
+    settings_.set_ranges(GetPageRangesFromPrintInfo());
+    InitPrintSettingsFromPrintInfo();
     callback.Run(OK);
   } else {
     callback.Run(CANCEL);
@@ -108,74 +110,40 @@
   DCHECK(!in_print_job_);
 
   print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
-  InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo());
+  settings_.set_ranges(GetPageRangesFromPrintInfo());
+  InitPrintSettingsFromPrintInfo();
 
   return OK;
 }
 
 PrintingContext::Result PrintingContextMac::UpdatePrinterSettings(
-    const DictionaryValue& job_settings, const PageRanges& ranges) {
+    bool target_is_pdf,
+    bool external_preview) {
   DCHECK(!in_print_job_);
 
   // NOTE: Reset |print_info_| with a copy of |sharedPrintInfo| so as to start
   // with a clean slate.
   print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
 
-  bool collate;
-  int color;
-  bool landscape;
-  bool print_to_pdf;
-  bool is_cloud_dialog;
-  int copies;
-  int duplex_mode;
-  std::string device_name;
-
-  if (!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
-      !job_settings.GetBoolean(kSettingCollate, &collate) ||
-      !job_settings.GetInteger(kSettingColor, &color) ||
-      !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
-      !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
-      !job_settings.GetInteger(kSettingCopies, &copies) ||
-      !job_settings.GetString(kSettingDeviceName, &device_name) ||
-      !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog)) {
-    return OnError();
-  }
-
-  bool print_to_cloud = job_settings.HasKey(kSettingCloudPrintId);
-  bool open_pdf_in_preview = job_settings.HasKey(kSettingOpenPDFInPreview);
-
-  if (!print_to_pdf && !print_to_cloud && !is_cloud_dialog) {
-    if (!SetPrinter(device_name))
-      return OnError();
-
-    if (!SetCopiesInPrintSettings(copies))
-      return OnError();
-
-    if (!SetCollateInPrintSettings(collate))
-      return OnError();
-
-    if (!SetDuplexModeInPrintSettings(
-            static_cast<DuplexMode>(duplex_mode))) {
+  if (!target_is_pdf) {
+    if (!SetPrinter(UTF16ToUTF8(settings_.device_name())) ||
+        !SetCopiesInPrintSettings(settings_.copies()) ||
+        !SetCollateInPrintSettings(settings_.collate()) ||
+        !SetDuplexModeInPrintSettings(settings_.duplex_mode()) ||
+        !SetOutputColor(settings_.color())) {
       return OnError();
     }
-
-    if (!SetOutputColor(color))
-      return OnError();
-  }
-  if (open_pdf_in_preview) {
-    if (!SetPrintPreviewJob())
-      return OnError();
   }
 
-  if (!UpdatePageFormatWithPaperInfo())
+  if ((external_preview && !SetPrintPreviewJob()) ||
+      !UpdatePageFormatWithPaperInfo() ||
+      !SetOrientationIsLandscape(settings_.landscape())) {
     return OnError();
-
-  if (!SetOrientationIsLandscape(landscape))
-    return OnError();
+  }
 
   [print_info_.get() updateFromPMPrintSettings];
 
-  InitPrintSettingsFromPrintInfo(ranges);
+  InitPrintSettingsFromPrintInfo();
   return OK;
 }
 
@@ -189,16 +157,16 @@
       NULL, NULL) == noErr;
 }
 
-void PrintingContextMac::InitPrintSettingsFromPrintInfo(
-    const PageRanges& ranges) {
+void PrintingContextMac::InitPrintSettingsFromPrintInfo() {
   PMPrintSession print_session =
       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
   PMPageFormat page_format =
       static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
   PMPrinter printer;
   PMSessionGetCurrentPrinter(print_session, &printer);
+  settings_.set_selection_only(false);
   PrintSettingsInitializerMac::InitPrintSettings(
-      printer, page_format, ranges, false, &settings_);
+      printer, page_format, &settings_);
 }
 
 bool PrintingContextMac::SetPrinter(const std::string& device_name) {
diff --git a/printing/printing_context_no_system_dialog.cc b/printing/printing_context_no_system_dialog.cc
index f02ef32..7fd2cee 100644
--- a/printing/printing_context_no_system_dialog.cc
+++ b/printing/printing_context_no_system_dialog.cc
@@ -73,24 +73,14 @@
   settings_.set_dpi(dpi);
   settings_.SetPrinterPrintableArea(physical_size_device_units,
                                     printable_area_device_units,
-                                    dpi);
+                                    dpi, true);
 
   return OK;
 }
 
 PrintingContext::Result PrintingContextNoSystemDialog::UpdatePrinterSettings(
-    const base::DictionaryValue& job_settings, const PageRanges& ranges) {
-  bool landscape = false;
-
-  if (!job_settings.GetBoolean(kSettingLandscape, &landscape))
-    return OnError();
-
-  if (settings_.dpi() == 0)
-    UseDefaultSettings();
-
-  settings_.SetOrientation(landscape);
-  settings_.ranges = ranges;
-
+    bool target_is_pdf,
+    bool external_preview) {
   return OK;
 }
 
diff --git a/printing/printing_context_no_system_dialog.h b/printing/printing_context_no_system_dialog.h
index 505f318..f45fb46 100644
--- a/printing/printing_context_no_system_dialog.h
+++ b/printing/printing_context_no_system_dialog.h
@@ -27,9 +27,8 @@
       bool has_selection,
       const PrintSettingsCallback& callback) OVERRIDE;
   virtual Result UseDefaultSettings() OVERRIDE;
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) OVERRIDE;
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) OVERRIDE;
   virtual Result InitWithSettings(const PrintSettings& settings) OVERRIDE;
   virtual Result NewDocument(const base::string16& document_name) OVERRIDE;
   virtual Result NewPage() OVERRIDE;
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index 642ada6..7a4a526 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -55,7 +55,7 @@
   HWND window = NULL;
 #if defined(USE_AURA)
   if (view)
-    window = view->GetRootWindow()->GetAcceleratedWidget();
+    window = view->GetDispatcher()->GetAcceleratedWidget();
 #else
   if (view && IsWindow(view)) {
     window = GetAncestor(view, GA_ROOTOWNER);
@@ -189,11 +189,11 @@
   ReleaseContext();
 }
 
-// TODO(vitalybuka): Implement as ui::BaseShellDialog crbug.com/180997.
 void PrintingContextWin::AskUserForSettings(
     gfx::NativeView view, int max_pages, bool has_selection,
     const PrintSettingsCallback& callback) {
   DCHECK(!in_print_job_);
+  // TODO(scottmg): Possibly this has to move into the threaded runner too?
   if (win8::IsSingleWindowMetroMode()) {
     // The system dialog can not be opened while running in Metro.
     // But we can programatically launch the Metro print device charm though.
@@ -226,40 +226,40 @@
   // - Cancel, the settings are not changed, the previous setting, if it was
   //   initialized before, are kept. CANCEL is returned.
   // On failure, the settings are reset and FAILED is returned.
-  PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) };
-  dialog_options.hwndOwner = window;
+  PRINTDLGEX* dialog_options =
+      reinterpret_cast<PRINTDLGEX*>(malloc(sizeof(PRINTDLGEX)));
+  ZeroMemory(dialog_options, sizeof(PRINTDLGEX));
+  dialog_options->lStructSize = sizeof(PRINTDLGEX);
+  dialog_options->hwndOwner = window;
   // Disable options we don't support currently.
   // TODO(maruel):  Reuse the previously loaded settings!
-  dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE  |
-                         PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
+  dialog_options->Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
+                          PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
   if (!has_selection)
-    dialog_options.Flags |= PD_NOSELECTION;
+    dialog_options->Flags |= PD_NOSELECTION;
 
-  PRINTPAGERANGE ranges[32];
-  dialog_options.nStartPage = START_PAGE_GENERAL;
+  const size_t max_page_ranges = 32;
+  PRINTPAGERANGE* ranges = new PRINTPAGERANGE[max_page_ranges];
+  dialog_options->lpPageRanges = ranges;
+  dialog_options->nStartPage = START_PAGE_GENERAL;
   if (max_pages) {
     // Default initialize to print all the pages.
     memset(ranges, 0, sizeof(ranges));
     ranges[0].nFromPage = 1;
     ranges[0].nToPage = max_pages;
-    dialog_options.nPageRanges = 1;
-    dialog_options.nMaxPageRanges = arraysize(ranges);
-    dialog_options.nMinPage = 1;
-    dialog_options.nMaxPage = max_pages;
-    dialog_options.lpPageRanges = ranges;
+    dialog_options->nPageRanges = 1;
+    dialog_options->nMaxPageRanges = max_page_ranges;
+    dialog_options->nMinPage = 1;
+    dialog_options->nMaxPage = max_pages;
   } else {
     // No need to bother, we don't know how many pages are available.
-    dialog_options.Flags |= PD_NOPAGENUMS;
+    dialog_options->Flags |= PD_NOPAGENUMS;
   }
 
-  HRESULT hr = (*print_dialog_func_)(&dialog_options);
-  if (hr != S_OK) {
-    ResetSettings();
-    callback.Run(FAILED);
-  }
-
-  // TODO(maruel):  Support PD_PRINTTOFILE.
-  callback.Run(ParseDialogResultEx(dialog_options));
+  callback_ = callback;
+  print_settings_dialog_ = new ui::PrintSettingsDialogWin(this);
+  print_settings_dialog_->GetPrintSettings(
+      print_dialog_func_, window, dialog_options);
 }
 
 PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
@@ -308,33 +308,12 @@
 }
 
 PrintingContext::Result PrintingContextWin::UpdatePrinterSettings(
-    const DictionaryValue& job_settings,
-    const PageRanges& ranges) {
+    bool target_is_pdf,
+    bool external_preview) {
   DCHECK(!in_print_job_);
+  DCHECK(!external_preview) << "Not implemented";
 
-  bool collate;
-  int color;
-  bool landscape;
-  bool print_to_pdf;
-  bool is_cloud_dialog;
-  int copies;
-  int duplex_mode;
-  base::string16 device_name;
-
-  if (!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
-      !job_settings.GetBoolean(kSettingCollate, &collate) ||
-      !job_settings.GetInteger(kSettingColor, &color) ||
-      !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
-      !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
-      !job_settings.GetInteger(kSettingCopies, &copies) ||
-      !job_settings.GetString(kSettingDeviceName, &device_name) ||
-      !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog)) {
-    return OnError();
-  }
-
-  bool print_to_cloud = job_settings.HasKey(kSettingCloudPrintId);
-
-  if (print_to_pdf || print_to_cloud || is_cloud_dialog) {
+  if (target_is_pdf) {
     // Default fallback to Letter size.
     gfx::Size paper_size;
     gfx::Rect paper_rect;
@@ -362,15 +341,14 @@
       }
     }
     paper_rect.SetRect(0, 0, paper_size.width(), paper_size.height());
-    settings_.SetPrinterPrintableArea(paper_size, paper_rect, kPDFDpi);
+    settings_.SetPrinterPrintableArea(paper_size, paper_rect, kPDFDpi, true);
     settings_.set_dpi(kPDFDpi);
-    settings_.SetOrientation(landscape);
-    settings_.ranges = ranges;
     return OK;
   }
 
   ScopedPrinterHandle printer;
-  LPWSTR device_name_wide = const_cast<wchar_t*>(device_name.c_str());
+  LPWSTR device_name_wide =
+      const_cast<wchar_t*>(settings_.device_name().c_str());
   if (!printer.OpenPrinter(device_name_wide))
     return OnError();
 
@@ -394,15 +372,17 @@
     return OnError();
   }
 
-  if (color == GRAY)
+  if (settings_.color() == GRAY)
     dev_mode->dmColor = DMCOLOR_MONOCHROME;
   else
     dev_mode->dmColor = DMCOLOR_COLOR;
 
-  dev_mode->dmCopies = std::max(copies, 1);
-  if (dev_mode->dmCopies > 1)  // do not change collate unless multiple copies
-    dev_mode->dmCollate = collate ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
-  switch (duplex_mode) {
+  dev_mode->dmCopies = std::max(settings_.copies(), 1);
+  if (dev_mode->dmCopies > 1) { // do not change collate unless multiple copies
+    dev_mode->dmCollate = settings_.collate() ? DMCOLLATE_TRUE :
+                                                DMCOLLATE_FALSE;
+  }
+  switch (settings_.duplex_mode()) {
     case LONG_EDGE:
       dev_mode->dmDuplex = DMDUP_VERTICAL;
       break;
@@ -415,7 +395,8 @@
     default:  // UNKNOWN_DUPLEX_MODE
       break;
   }
-  dev_mode->dmOrientation = landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
+  dev_mode->dmOrientation = settings_.landscape() ? DMORIENT_LANDSCAPE :
+                                                    DMORIENT_PORTRAIT;
 
   // Update data using DocumentProperties.
   if (DocumentProperties(NULL, printer, device_name_wide, dev_mode, dev_mode,
@@ -424,12 +405,11 @@
   }
 
   // Set printer then refresh printer settings.
-  if (!AllocateContext(device_name, dev_mode, &context_)) {
+  if (!AllocateContext(settings_.device_name(), dev_mode, &context_)) {
     return OnError();
   }
   PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode,
-                                                 ranges, device_name,
-                                                 false, &settings_);
+                                                 &settings_);
   return OK;
 }
 
@@ -565,6 +545,20 @@
   return context_;
 }
 
+void PrintingContextWin::PrintSettingsConfirmed(PRINTDLGEX* dialog_options) {
+  // TODO(maruel):  Support PD_PRINTTOFILE.
+  callback_.Run(ParseDialogResultEx(*dialog_options));
+  delete [] dialog_options->lpPageRanges;
+  free(dialog_options);
+}
+
+void PrintingContextWin::PrintSettingsCancelled(PRINTDLGEX* dialog_options) {
+  ResetSettings();
+  callback_.Run(FAILED);
+  delete [] dialog_options->lpPageRanges;
+  free(dialog_options);
+}
+
 // static
 BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) {
   if (nCode) {
@@ -612,11 +606,10 @@
     }
   }
 
-  PrintSettingsInitializerWin::InitPrintSettings(context_,
-                                                 dev_mode,
-                                                 ranges_vector,
-                                                 new_device_name,
-                                                 selection_only,
+  settings_.set_ranges(ranges_vector);
+  settings_.set_device_name(new_device_name);
+  settings_.set_selection_only(selection_only);
+  PrintSettingsInitializerWin::InitPrintSettings(context_, dev_mode,
                                                  &settings_);
 
   return true;
diff --git a/printing/printing_context_win.h b/printing/printing_context_win.h
index c54b531..37e5b04 100644
--- a/printing/printing_context_win.h
+++ b/printing/printing_context_win.h
@@ -14,10 +14,13 @@
 #include "build/build_config.h"
 #include "printing/printing_context.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/shell_dialogs/print_settings_dialog_win.h"
 
 namespace printing {
 
-class PRINTING_EXPORT PrintingContextWin : public PrintingContext {
+class PRINTING_EXPORT PrintingContextWin
+    : public PrintingContext,
+      public ui::PrintSettingsDialogWin::Observer {
  public:
   explicit PrintingContextWin(const std::string& app_locale);
   ~PrintingContextWin();
@@ -29,9 +32,8 @@
       bool has_selection,
       const PrintSettingsCallback& callback) OVERRIDE;
   virtual Result UseDefaultSettings() OVERRIDE;
-  virtual Result UpdatePrinterSettings(
-      const base::DictionaryValue& job_settings,
-      const PageRanges& ranges) OVERRIDE;
+  virtual Result UpdatePrinterSettings(bool target_is_pdf,
+                                       bool external_preview) OVERRIDE;
   virtual Result InitWithSettings(const PrintSettings& settings) OVERRIDE;
   virtual Result NewDocument(const base::string16& document_name) OVERRIDE;
   virtual Result NewPage() OVERRIDE;
@@ -41,6 +43,10 @@
   virtual void ReleaseContext() OVERRIDE;
   virtual gfx::NativeDrawingContext context() const OVERRIDE;
 
+  // PrintSettingsDialogWin::Observer implementation:
+  virtual void PrintSettingsConfirmed(PRINTDLGEX* dialog_options) OVERRIDE;
+  virtual void PrintSettingsCancelled(PRINTDLGEX* dialog_options) OVERRIDE;
+
 #if defined(UNIT_TEST) || defined(PRINTING_IMPLEMENTATION)
   // Sets a fake PrintDlgEx function pointer in tests.
   void SetPrintDialog(HRESULT (__stdcall *print_dialog_func)(LPPRINTDLGEX)) {
@@ -88,6 +94,12 @@
   // SetPrintDialog() in tests.
   HRESULT (__stdcall *print_dialog_func_)(LPPRINTDLGEX);
 
+  // Where to notify when the dialog is closed.
+  PrintSettingsCallback callback_;
+
+  // Wrapper around native print dialog that runs it on a background thread.
+  scoped_refptr<ui::PrintSettingsDialogWin> print_settings_dialog_;
+
   DISALLOW_COPY_AND_ASSIGN(PrintingContextWin);
 };
 
diff --git a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
index 07d896f..22cc376 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
@@ -230,9 +230,9 @@
 
                 // Send our HTTP request to the directory server.
                 URLConnection link =
-                        new URL(HOST_LIST_PATH + JniInterface.getApiKey()).openConnection();
-                link.addRequestProperty("client_id", JniInterface.getClientId());
-                link.addRequestProperty("client_secret", JniInterface.getClientSecret());
+                        new URL(HOST_LIST_PATH + JniInterface.nativeGetApiKey()).openConnection();
+                link.addRequestProperty("client_id", JniInterface.nativeGetClientId());
+                link.addRequestProperty("client_secret", JniInterface.nativeGetClientSecret());
                 link.setRequestProperty("Authorization", "OAuth " + authToken);
 
                 // Listen for the server to respond.
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
index 8a9917d..85e2493 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -42,7 +42,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        remoteHostDesktop.requestRecheckConstrainingDimension();
+        remoteHostDesktop.onScreenConfigurationChanged();
     }
 
     /** Called to initialize the action bar. */
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index 8209d28..26cf83a 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -9,16 +9,12 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Point;
-import android.os.Bundle;
 import android.os.Looper;
 import android.text.InputType;
 import android.util.Log;
-import android.view.GestureDetector;
 import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.inputmethod.EditorInfo;
@@ -32,62 +28,16 @@
  * multitouch pan and zoom gestures, and collects and forwards input events.
  */
 /** GUI element that holds the drawing canvas. */
-public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.Callback {
-    /**
-     * *Square* of the minimum displacement (in pixels) to be recognized as a scroll gesture.
-     * Setting this to a lower value forces more frequent canvas redraws during scrolling.
-     */
-    private static final int MIN_SCROLL_DISTANCE = 8 * 8;
-
-    /**
-     * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower
-     * values here will result in more frequent canvas redraws during zooming.
-     */
-    private static final double MIN_ZOOM_FACTOR = 0.05;
-
-    /*
-     * These constants must match those in the generated struct protoc::MouseEvent_MouseButton.
-     */
-    private static final int BUTTON_UNDEFINED = 0;
-    private static final int BUTTON_LEFT = 1;
-    private static final int BUTTON_RIGHT = 3;
-
-    /** Specifies one dimension of an image. */
-    private static enum Constraint {
-        UNDEFINED, WIDTH, HEIGHT
-    }
-
+public class DesktopView extends SurfaceView implements DesktopViewInterface, Runnable,
+        SurfaceHolder.Callback {
+    private RenderData mRenderData;
+    private TouchInputHandler mInputHandler;
     private ActionBar mActionBar;
 
-    private GestureDetector mScroller;
-    private ScaleGestureDetector mZoomer;
-
-    /** Stores pan and zoom configuration and converts image coordinates to screen coordinates. */
-    private Matrix mTransform;
-
-    private int mScreenWidth;
-    private int mScreenHeight;
-
-    /**
-     * Specifies the position, in image coordinates, at which the cursor image will be drawn.
-     * This will normally be at the location of the most recently injected motion event.
-     */
-    private Point mCursorPosition;
-
-    /** Specifies the dimension by which the zoom level is being lower-bounded. */
-    private Constraint mConstraint;
-
-    /** Whether the dimension of constraint should be reckecked on the next aspect ratio change. */
-    private boolean mRecheckConstraint;
-
-    /** Whether the right edge of the image was visible on-screen during the last render. */
-    private boolean mRightUsedToBeOut;
-
-    /** Whether the bottom edge of the image was visible on-screen during the last render. */
-    private boolean mBottomUsedToBeOut;
-
-    private int mMouseButton;
-    private boolean mMousePressed;
+    // Flag to prevent multiple repaint requests from being backed up. Requests for repainting will
+    // be dropped if this is already set to true. This is used by the main thread and the painting
+    // thread, so the access should be synchronized on |mRenderData|.
+    private boolean mRepaintPending;
 
     public DesktopView(Activity context) {
         super(context);
@@ -95,26 +45,30 @@
         // Give this view keyboard focus, allowing us to customize the soft keyboard's settings.
         setFocusableInTouchMode(true);
 
+        mRenderData = new RenderData();
+        mInputHandler = new TrackingInputHandler(this, context, mRenderData);
         mActionBar = context.getActionBar();
+        mRepaintPending = false;
 
         getHolder().addCallback(this);
-        DesktopListener listener = new DesktopListener();
-        mScroller = new GestureDetector(context, listener, null, false);
-        mZoomer = new ScaleGestureDetector(context, listener);
+    }
 
-        mTransform = new Matrix();
-        mScreenWidth = 0;
-        mScreenHeight = 0;
-        mCursorPosition = new Point();
+    /**
+     * Request repainting of the desktop view.
+     */
+    void requestRepaint() {
+        synchronized (mRenderData) {
+            if (mRepaintPending) {
+                return;
+            }
+            mRepaintPending = true;
+        }
+        JniInterface.redrawGraphics();
+    }
 
-        mConstraint = Constraint.UNDEFINED;
-        mRecheckConstraint = false;
-
-        mRightUsedToBeOut = false;
-        mBottomUsedToBeOut = false;
-
-        mMouseButton = BUTTON_UNDEFINED;
-        mMousePressed = false;
+    /** Called whenever the screen configuration is changed. */
+    public void onScreenConfigurationChanged() {
+        mInputHandler.onScreenConfigurationChanged();
     }
 
     /**
@@ -129,97 +83,28 @@
         }
 
         Bitmap image = JniInterface.getVideoFrame();
+
+        int width = image.getWidth();
+        int height = image.getHeight();
+        boolean sizeChanged = false;
+        synchronized (mRenderData) {
+            if (mRenderData.imageWidth != width || mRenderData.imageHeight != height) {
+                // TODO(lambroslambrou): Move this code into a sizeChanged() callback, to be
+                // triggered from JniInterface (on the display thread) when the remote screen size
+                // changes.
+                mRenderData.imageWidth = width;
+                mRenderData.imageHeight = height;
+                sizeChanged = true;
+            }
+        }
+        if (sizeChanged) {
+            mInputHandler.onHostSizeChanged(width, height);
+        }
+
         Canvas canvas = getHolder().lockCanvas();
-        synchronized (mTransform) {
-            canvas.setMatrix(mTransform);
-
-            // Internal parameters of the transformation matrix.
-            float[] values = new float[9];
-            mTransform.getValues(values);
-
-            // Screen coordinates of two defining points of the image.
-            float[] topleft = {0, 0};
-            mTransform.mapPoints(topleft);
-            float[] bottomright = {image.getWidth(), image.getHeight()};
-            mTransform.mapPoints(bottomright);
-
-            // Whether to rescale and recenter the view.
-            boolean recenter = false;
-
-            if (mConstraint == Constraint.UNDEFINED) {
-                mConstraint = (double)image.getWidth()/image.getHeight() >
-                        (double)mScreenWidth/mScreenHeight ? Constraint.WIDTH : Constraint.HEIGHT;
-                recenter = true;  // We always rescale and recenter after a rotation.
-            }
-
-            if (mConstraint == Constraint.WIDTH &&
-                    ((int)(bottomright[0] - topleft[0] + 0.5) < mScreenWidth || recenter)) {
-                // The vertical edges of the image are flush against the device's screen edges
-                // when the entire host screen is visible, and the user has zoomed out too far.
-                float imageMiddle = (float)image.getHeight() / 2;
-                float screenMiddle = (float)mScreenHeight / 2;
-                mTransform.setPolyToPoly(
-                        new float[] {0, imageMiddle, image.getWidth(), imageMiddle}, 0,
-                        new float[] {0, screenMiddle, mScreenWidth, screenMiddle}, 0, 2);
-            } else if (mConstraint == Constraint.HEIGHT &&
-                    ((int)(bottomright[1] - topleft[1] + 0.5) < mScreenHeight || recenter)) {
-                // The horizontal image edges are flush against the device's screen edges when
-                // the entire host screen is visible, and the user has zoomed out too far.
-                float imageCenter = (float)image.getWidth() / 2;
-                float screenCenter = (float)mScreenWidth / 2;
-                mTransform.setPolyToPoly(
-                        new float[] {imageCenter, 0, imageCenter, image.getHeight()}, 0,
-                        new float[] {screenCenter, 0, screenCenter, mScreenHeight}, 0, 2);
-            } else {
-                // It's fine for both members of a pair of image edges to be within the screen
-                // edges (or "out of bounds"); that simply means that the image is zoomed out as
-                // far as permissible. And both members of a pair can obviously be outside the
-                // screen's edges, which indicates that the image is zoomed in to far to see the
-                // whole host screen. However, if only one of a pair of edges has entered the
-                // screen, the user is attempting to scroll into a blank area of the canvas.
-
-                // A value of true means the corresponding edge has entered the screen's borders.
-                boolean leftEdgeOutOfBounds = values[Matrix.MTRANS_X] > 0;
-                boolean topEdgeOutOfBounds = values[Matrix.MTRANS_Y] > 0;
-                boolean rightEdgeOutOfBounds = bottomright[0] < mScreenWidth;
-                boolean bottomEdgeOutOfBounds = bottomright[1] < mScreenHeight;
-
-                // Prevent the user from scrolling past the left or right edge of the image.
-                if (leftEdgeOutOfBounds != rightEdgeOutOfBounds) {
-                    if (leftEdgeOutOfBounds != mRightUsedToBeOut) {
-                        // Make the left edge of the image flush with the left screen edge.
-                        values[Matrix.MTRANS_X] = 0;
-                    }
-                    else {
-                        // Make the right edge of the image flush with the right screen edge.
-                        values[Matrix.MTRANS_X] += mScreenWidth - bottomright[0];
-                    }
-                } else {
-                    // The else prevents this from being updated during the repositioning process,
-                    // in which case the view would begin to oscillate.
-                    mRightUsedToBeOut = rightEdgeOutOfBounds;
-                }
-
-                // Prevent the user from scrolling past the top or bottom edge of the image.
-                if (topEdgeOutOfBounds != bottomEdgeOutOfBounds) {
-                    if (topEdgeOutOfBounds != mBottomUsedToBeOut) {
-                        // Make the top edge of the image flush with the top screen edge.
-                        values[Matrix.MTRANS_Y] = 0;
-                    } else {
-                        // Make the bottom edge of the image flush with the bottom screen edge.
-                        values[Matrix.MTRANS_Y] += mScreenHeight - bottomright[1];
-                    }
-                }
-                else {
-                    // The else prevents this from being updated during the repositioning process,
-                    // in which case the view would begin to oscillate.
-                    mBottomUsedToBeOut = bottomEdgeOutOfBounds;
-                }
-
-                mTransform.setValues(values);
-            }
-
-            canvas.setMatrix(mTransform);
+        synchronized (mRenderData) {
+            mRepaintPending = false;
+            canvas.setMatrix(mRenderData.transform);
         }
 
         canvas.drawColor(Color.BLACK);
@@ -228,9 +113,9 @@
         if (cursorBitmap != null) {
             Point hotspot = JniInterface.getCursorHotspot();
             int bitmapX, bitmapY;
-            synchronized (mCursorPosition) {
-                bitmapX = mCursorPosition.x - hotspot.x;
-                bitmapY = mCursorPosition.y - hotspot.y;
+            synchronized (mRenderData) {
+                bitmapX = mRenderData.cursorPosition.x - hotspot.x;
+                bitmapY = mRenderData.cursorPosition.y - hotspot.y;
             }
             canvas.drawBitmap(cursorBitmap, bitmapX, bitmapY, new Paint());
         }
@@ -238,43 +123,21 @@
     }
 
     /**
-     * Causes the next canvas redraw to perform a check for which screen dimension more tightly
-     * constrains the view of the image. This should be called between the time that a screen size
-     * change is requested and the time it actually occurs. If it is not called in such a case, the
-     * screen will not be rearranged as aggressively (which is desirable when the software keyboard
-     * appears in order to allow it to cover the image without forcing a resize).
-     */
-    public void requestRecheckConstrainingDimension() {
-        mRecheckConstraint = true;
-    }
-
-    /**
-     * Called after the canvas is initially created, then after every
-     * subsequent resize, as when the display is rotated.
+     * Called after the canvas is initially created, then after every subsequent resize, as when
+     * the display is rotated.
      */
     @Override
-    public void surfaceChanged(
-            SurfaceHolder holder, int format, int width, int height) {
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         mActionBar.hide();
 
-        synchronized (mTransform) {
-            mScreenWidth = width;
-            mScreenHeight = height;
-
-            if (mRecheckConstraint) {
-                mConstraint = Constraint.UNDEFINED;
-                mRecheckConstraint = false;
-            }
+        synchronized (mRenderData) {
+            mRenderData.screenWidth = width;
+            mRenderData.screenHeight = height;
         }
 
-        synchronized (mCursorPosition) {
-            mCursorPosition.x = width / 2;
-            mCursorPosition.y = height / 2;
-        }
+        mInputHandler.onClientSizeChanged(width, height);
 
-        if (!JniInterface.redrawGraphics()) {
-            JniInterface.provideRedrawCallback(this);
-        }
+        JniInterface.provideRedrawCallback(this);
     }
 
     /** Called when the canvas is first created. */
@@ -313,174 +176,53 @@
         return null;
     }
 
-    /** Called when a mouse action is made. */
-    private void handleMouseMovement(float x, float y, int button, boolean pressed) {
-        float[] coordinates = {x, y};
-
-        // Coordinates are relative to the canvas, but we need image coordinates.
-        Matrix canvasToImage = new Matrix();
-        synchronized (mTransform) {
-            mTransform.invert(canvasToImage);
-        }
-        canvasToImage.mapPoints(coordinates);
-
-        int imageX = (int)coordinates[0];
-        int imageY = (int)coordinates[1];
-
-        synchronized (mCursorPosition) {
-            mCursorPosition.x = imageX;
-            mCursorPosition.y = imageY;
-        }
-
-        // Coordinates are now relative to the image, so transmit them to the host.
-        JniInterface.mouseAction(imageX, imageY, button, pressed);
-
-        // TODO(lambroslambrou): Optimize this to repaint only the areas covered by the old and new
-        // cursor positions.
-        JniInterface.redrawGraphics();
-    }
-
-    /**
-     * Called whenever the user attempts to touch the canvas. Forwards such
-     * events to the appropriate gesture detector until one accepts them.
-     */
+    /** Called whenever the user attempts to touch the canvas. */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (event.getPointerCount() == 3) {
-            mActionBar.show();
-        }
-
-        boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent(event);
-
-        if (event.getPointerCount() == 1) {
-            float x = event.getRawX();
-            float y = event.getY();
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    Log.i("mouse", "Found a finger");
-                    mMouseButton = BUTTON_UNDEFINED;
-                    mMousePressed = false;
-                    break;
-
-                case MotionEvent.ACTION_MOVE:
-                    Log.i("mouse", "Finger is dragging");
-                    if (mMouseButton == BUTTON_UNDEFINED) {
-                        Log.i("mouse", "\tStarting left click");
-                        mMouseButton = BUTTON_LEFT;
-                        mMousePressed = true;
-                    }
-                    break;
-
-                case MotionEvent.ACTION_UP:
-                    Log.i("mouse", "Lost the finger");
-                    if (mMouseButton == BUTTON_UNDEFINED) {
-                        // The user pressed and released without moving: do left click and release.
-                        Log.i("mouse", "\tStarting and finishing left click");
-                        handleMouseMovement(x, y, BUTTON_LEFT, true);
-                        mMouseButton = BUTTON_LEFT;
-                        mMousePressed = false;
-                    }
-                    else if (mMousePressed) {
-                        Log.i("mouse", "\tReleasing the currently-pressed button");
-                        mMousePressed = false;
-                    }
-                    else {
-                        Log.w("mouse", "Button already in released state before gesture ended");
-                    }
-                    break;
-
-                default:
-                    return handled;
-            }
-            handleMouseMovement(x, y, mMouseButton, mMousePressed);
-
-            return true;
-        }
-
-        return handled;
+        return mInputHandler.onTouchEvent(event);
     }
 
-    /** Responds to touch events filtered by the gesture detectors. */
-    private class DesktopListener extends GestureDetector.SimpleOnGestureListener
-            implements ScaleGestureDetector.OnScaleGestureListener {
-        /**
-         * Called when the user is scrolling. We refuse to accept or process the event unless it
-         * is being performed with 2 or more touch points, in order to reserve single-point touch
-         * events for emulating mouse input.
-         */
-        @Override
-        public boolean onScroll(
-                MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-            if (e2.getPointerCount() < 2 ||
-                    Math.pow(distanceX, 2) + Math.pow(distanceY, 2) < MIN_SCROLL_DISTANCE) {
-                return false;
+    @Override
+    public void injectMouseEvent(int x, int y, int button, boolean pressed) {
+        boolean cursorMoved = false;
+        synchronized (mRenderData) {
+            // Test if the cursor actually moved, which requires repainting the cursor. This
+            // requires that the TouchInputHandler doesn't mutate |mRenderData.cursorPosition|
+            // directly.
+            if (x != mRenderData.cursorPosition.x) {
+                mRenderData.cursorPosition.x = x;
+                cursorMoved = true;
             }
-
-            synchronized (mTransform) {
-                mTransform.postTranslate(-distanceX, -distanceY);
+            if (y != mRenderData.cursorPosition.y) {
+                mRenderData.cursorPosition.y = y;
+                cursorMoved = true;
             }
-            JniInterface.redrawGraphics();
-            return true;
         }
 
-        /** Called when the user is in the process of pinch-zooming. */
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_FACTOR) {
-                return false;
-            }
-
-            synchronized (mTransform) {
-                float scaleFactor = detector.getScaleFactor();
-                mTransform.postScale(
-                        scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
-            }
-            JniInterface.redrawGraphics();
-            return true;
+        if (button == TouchInputHandler.BUTTON_UNDEFINED && !cursorMoved) {
+            // No need to inject anything or repaint.
+            return;
         }
 
-        /** Called whenever a gesture starts. Always accepts the gesture so it isn't ignored. */
-        @Override
-        public boolean onDown(MotionEvent e) {
-            return true;
+        JniInterface.mouseAction(x, y, button, pressed);
+        if (cursorMoved) {
+            // TODO(lambroslambrou): Optimize this by only repainting the affected areas.
+            requestRepaint();
         }
+    }
 
-        /**
-         * Called when the user starts to zoom. Always accepts the zoom so that
-         * onScale() can decide whether to respond to it.
-         */
-        @Override
-        public boolean onScaleBegin(ScaleGestureDetector detector) {
-            return true;
-        }
+    @Override
+    public void showActionBar() {
+        mActionBar.show();
+    }
 
-        /** Called when the user is done zooming. Defers to onScale()'s judgement. */
-        @Override
-        public void onScaleEnd(ScaleGestureDetector detector) {
-            onScale(detector);
-        }
+    @Override
+    public void showKeyboard() {
+        // TODO(lambroslambrou): Implement this.
+    }
 
-        /** Called when the user holds down on the screen. Starts a right-click. */
-        @Override
-        public void onLongPress(MotionEvent e) {
-            if (e.getPointerCount() > 1) {
-                return;
-            }
-
-            float x = e.getRawX();
-            float y = e.getY();
-
-            Log.i("mouse", "Finger held down");
-            if (mMousePressed) {
-                Log.i("mouse", "\tReleasing the currently-pressed button");
-                handleMouseMovement(x, y, mMouseButton, false);
-            }
-
-            Log.i("mouse", "\tStarting right click");
-            mMouseButton = BUTTON_RIGHT;
-            mMousePressed = true;
-            handleMouseMovement(x, y, mMouseButton, mMousePressed);
-        }
+    @Override
+    public void transformationChanged() {
+        requestRepaint();
     }
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java b/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java
new file mode 100644
index 0000000..ba9e1e6
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java
@@ -0,0 +1,25 @@
+// Copyright 2013 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.chromoting;
+
+/**
+ * Callback interface to allow the TouchInputHandler to request actions on the DesktopView.
+ */
+interface DesktopViewInterface {
+    /** Inject a mouse-move event, with optional button press/release. */
+    public void injectMouseEvent(int x, int y, int button, boolean pressed);
+
+    /** Shows the action bar. */
+    public void showActionBar();
+
+    /** Shows the software keyboard. */
+    public void showKeyboard();
+
+    /**
+     * Informs the view that its transformation matrix (for rendering the remote desktop bitmap)
+     * has been changed by the TouchInputHandler, which requires repainting.
+     */
+    public void transformationChanged();
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/RenderData.java b/remoting/android/java/src/org/chromium/chromoting/RenderData.java
new file mode 100644
index 0000000..f161c9f
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/RenderData.java
@@ -0,0 +1,28 @@
+// Copyright 2013 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.chromoting;
+
+import android.graphics.Matrix;
+import android.graphics.Point;
+
+/**
+ * This class stores data that needs to be accessed on both the display thread and the
+ * event-processing thread.
+ */
+public class RenderData {
+    /** Stores pan and zoom configuration and converts image coordinates to screen coordinates. */
+    public Matrix transform = new Matrix();
+
+    public int screenWidth = 0;
+    public int screenHeight = 0;
+    public int imageWidth = 0;
+    public int imageHeight = 0;
+
+    /**
+     * Specifies the position, in image coordinates, at which the cursor image will be drawn.
+     * This will normally be at the location of the most recently injected motion event.
+     */
+    public Point cursorPosition = new Point();
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
new file mode 100644
index 0000000..85578b6
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
@@ -0,0 +1,49 @@
+// Copyright 2013 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.chromoting;
+
+import android.view.MotionEvent;
+
+/**
+ * This interface allows multiple styles of touchscreen UI to be implemented and dynamically
+ * switched. The DesktopView passes the low-level touchscreen events and other events via this
+ * interface. The implementation recognizes and processes the touchscreen gestures, and then
+ * performs actions on the DesktopView (such as panning/zooming the display, injecting input, or
+ * showing/hiding UI elements).
+ */
+interface TouchInputHandler {
+    // These constants must match those in the generated struct protoc::MouseEvent_MouseButton.
+    public static final int BUTTON_UNDEFINED = 0;
+    public static final int BUTTON_LEFT = 1;
+    public static final int BUTTON_MIDDLE = 2;
+    public static final int BUTTON_RIGHT = 3;
+
+    /**
+     * Processes a touch event. This should be called by the View in its onTouchEvent() handler.
+     */
+    boolean onTouchEvent(MotionEvent event);
+
+    /**
+     * Called when the screen configuration is changed, such as when the screen is rotated or an
+     * external display is plugged in. This is not called if the client display area changes as a
+     * result of showing/hiding UI elements such as a keyboard. For example, an implementation
+     * could set a flag to reset the zoom level when the screen is rotated, but not when the
+     * software keyboard appears. After this is called, the onClientSizeChanged() method will
+     * shortly be called with the dimensions of the new client display area.
+     */
+    void onScreenConfigurationChanged();
+
+    /**
+     * Called whenever the client display area changes size. The caller will handle repainting
+     * after this method returns.
+     */
+    void onClientSizeChanged(int width, int height);
+
+    /**
+     * Called when the host screen size is changed. The caller will handle repainting after this
+     * method returns.
+     */
+    void onHostSizeChanged(int width, int height);
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
new file mode 100644
index 0000000..e7500d8
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
@@ -0,0 +1,319 @@
+// Copyright 2013 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.chromoting;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+/**
+ * This class implements the cursor-tracking behavior and gestures.
+ */
+public class TrackingInputHandler implements TouchInputHandler {
+    /**
+     * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower
+     * values here will result in more frequent canvas redraws during zooming.
+     */
+    private static final double MIN_ZOOM_DELTA = 0.05;
+
+    /**
+     * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}.
+     */
+    private static final float MAX_ZOOM_FACTOR = 100.0f;
+
+    private DesktopViewInterface mViewer;
+    private RenderData mRenderData;
+
+    private GestureDetector mScroller;
+    private ScaleGestureDetector mZoomer;
+
+    /**
+     * The current cursor position is stored here as floats, so that the desktop image can be
+     * positioned with sub-pixel accuracy, to give a smoother panning animation at high zoom levels.
+     */
+    private PointF mCursorPosition;
+
+    private int mMouseButton;
+
+    /**
+     * Distinguish between finger tap and swipe. One-finger down then up should inject a
+     * left-click event. But if the finger is dragged before being released, this should move
+     * the cursor without injecting any button event. This flag is set when a motion event is
+     * detected.
+     */
+    private boolean mFingerMoved = false;
+
+    public TrackingInputHandler(DesktopViewInterface viewer, Context context,
+                                RenderData renderData) {
+        mViewer = viewer;
+        mRenderData = renderData;
+
+        GestureListener listener = new GestureListener();
+        mScroller = new GestureDetector(context, listener, null, false);
+
+        // If long-press is enabled, the gesture-detector will not emit any further onScroll
+        // notifications after the onLongPress notification. Since onScroll is being used for
+        // moving the cursor, it means that the cursor would become stuck if the finger were held
+        // down too long.
+        mScroller.setIsLongpressEnabled(false);
+
+        mZoomer = new ScaleGestureDetector(context, listener);
+
+        mCursorPosition = new PointF();
+
+        mMouseButton = BUTTON_UNDEFINED;
+        mFingerMoved = false;
+    }
+
+    /**
+     * Moves the mouse-cursor, injects a mouse-move event and repositions the image.
+     */
+    private void moveCursor(float newX, float newY) {
+        synchronized (mRenderData) {
+            // Constrain cursor to the image area.
+            if (newX < 0) newX = 0;
+            if (newY < 0) newY = 0;
+            if (newX > mRenderData.imageWidth) newX = mRenderData.imageWidth;
+            if (newY > mRenderData.imageHeight) newY = mRenderData.imageHeight;
+            mCursorPosition.set(newX, newY);
+            repositionImage();
+        }
+
+        mViewer.injectMouseEvent((int)newX, (int)newY, BUTTON_UNDEFINED, false);
+    }
+
+    /**
+     * Repositions the image by translating it (without affecting the zoom level) to place the
+     * cursor close to the center of the screen.
+     */
+    private void repositionImage() {
+        synchronized (mRenderData) {
+            // Get the current cursor position in screen coordinates.
+            float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y};
+            mRenderData.transform.mapPoints(cursorScreen);
+
+            // Translate so the cursor is displayed in the middle of the screen.
+            mRenderData.transform.postTranslate(
+                    (float)mRenderData.screenWidth / 2 - cursorScreen[0],
+                    (float)mRenderData.screenHeight / 2 - cursorScreen[1]);
+
+            // Now the cursor is displayed in the middle of the screen, see if the image can be
+            // panned so that more of it is visible. The primary goal is to show as much of the
+            // image as possible. The secondary goal is to keep the cursor in the middle.
+
+            // Get the coordinates of the desktop rectangle (top-left/bottom-right corners) in
+            // screen coordinates. Order is: left, top, right, bottom.
+            float[] rectScreen = {0, 0, mRenderData.imageWidth, mRenderData.imageHeight};
+            mRenderData.transform.mapPoints(rectScreen);
+
+            float leftDelta = rectScreen[0];
+            float rightDelta = rectScreen[2] - mRenderData.screenWidth;
+            float topDelta = rectScreen[1];
+            float bottomDelta = rectScreen[3] - mRenderData.screenHeight;
+            float xAdjust = 0;
+            float yAdjust = 0;
+
+            if (rectScreen[2] - rectScreen[0] < mRenderData.screenWidth) {
+                // Image is narrower than the screen, so center it.
+                xAdjust = -(rightDelta + leftDelta) / 2;
+            } else if (leftDelta > 0 && rightDelta > 0) {
+                // Panning the image left will show more of it.
+                xAdjust = -Math.min(leftDelta, rightDelta);
+            } else if (leftDelta < 0 && rightDelta < 0) {
+                // Pan the image right.
+                xAdjust = Math.min(-leftDelta, -rightDelta);
+            }
+
+            // Apply similar logic for yAdjust.
+            if (rectScreen[3] - rectScreen[1] < mRenderData.screenHeight) {
+                yAdjust = -(bottomDelta + topDelta) / 2;
+            } else if (topDelta > 0 && bottomDelta > 0) {
+                yAdjust = -Math.min(topDelta, bottomDelta);
+            } else if (topDelta < 0 && bottomDelta < 0) {
+                yAdjust = Math.min(-topDelta, -bottomDelta);
+            }
+
+            mRenderData.transform.postTranslate(xAdjust, yAdjust);
+        }
+        mViewer.transformationChanged();
+    }
+
+    /**
+     * Repositions the image by translating and zooming it, to keep the zoom level within sensible
+     * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The
+     * maximum zoom level is set arbitrarily, so that the user can zoom out again in a reasonable
+     * time, and to prevent arithmetic overflow problems from displaying the image.
+     */
+    private void repositionImageWithZoom() {
+        synchronized (mRenderData) {
+            // Avoid division by zero in case this gets called before the image size is initialized.
+            if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
+                return;
+            }
+
+            // Zoom out if the zoom level is too high.
+            float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
+            if (currentZoomLevel > MAX_ZOOM_FACTOR) {
+                mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
+            }
+
+            // Get image size scaled to screen coordinates.
+            float[] imageSize = {(float)mRenderData.imageWidth, (float)mRenderData.imageHeight};
+            mRenderData.transform.mapVectors(imageSize);
+
+            if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData.screenHeight) {
+                // Displayed image is too small in both directions, so apply the minimum zoom
+                // level needed to fit either the width or height.
+                float scale = Math.min((float)mRenderData.screenWidth / mRenderData.imageWidth,
+                                       (float)mRenderData.screenHeight / mRenderData.imageHeight);
+                mRenderData.transform.setScale(scale, scale);
+            }
+
+            repositionImage();
+        }
+    }
+
+    /** Injects a button event using the current cursor location. */
+    private void injectButtonEvent(int button, boolean pressed) {
+        mViewer.injectMouseEvent((int)mCursorPosition.x, (int)mCursorPosition.y, button, pressed);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // Avoid short-circuit logic evaluation - ensure both gesture detectors see all events so
+        // that they generate correct notifications.
+        boolean handled = mScroller.onTouchEvent(event);
+        handled = mZoomer.onTouchEvent(event) || handled;
+
+        int pointerCount = event.getPointerCount();
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_POINTER_DOWN:
+                switch (pointerCount) {
+                    case 1:
+                        mFingerMoved = false;
+                        mMouseButton = BUTTON_LEFT;
+                        break;
+                    case 2:
+                        mMouseButton = BUTTON_RIGHT;
+                        break;
+                    case 3:
+                        mMouseButton = BUTTON_UNDEFINED;
+                        // TODO(lambroslambrou): Add 3-finger-tap for middle-click, and use 3-finger
+                        // swipe to show the action-bar or keyboard.
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mFingerMoved) {
+                    // Don't inject anything.
+                    mFingerMoved = false;
+                } else {
+                    // The user pressed and released without moving. Inject a click event for a
+                    // mouse button according to how many fingers were used.
+                    injectButtonEvent(mMouseButton, true);
+                    injectButtonEvent(mMouseButton, false);
+                    handled = true;
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                // |pointerCount| is the number of fingers that were on the screen prior to the UP
+                // event.
+                if (pointerCount == 3) {
+                    mViewer.showActionBar();
+                    handled = true;
+                }
+                break;
+            default:
+                break;
+        }
+        return handled;
+    }
+
+    @Override
+    public void onScreenConfigurationChanged() {
+    }
+
+    @Override
+    public void onClientSizeChanged(int width, int height) {
+        repositionImageWithZoom();
+    }
+
+    @Override
+    public void onHostSizeChanged(int width, int height) {
+        moveCursor((float)width / 2, (float)height / 2);
+        repositionImageWithZoom();
+    }
+
+    /** Responds to touch events filtered by the gesture detectors. */
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener
+            implements ScaleGestureDetector.OnScaleGestureListener {
+        /**
+         * Called when the user drags one or more fingers across the touchscreen.
+         */
+        @Override
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            if (e2.getPointerCount() != 1) {
+                return false;
+            }
+            mFingerMoved = true;
+
+            float[] delta = {distanceX, distanceY};
+            synchronized (mRenderData) {
+                Matrix canvasToImage = new Matrix();
+                mRenderData.transform.invert(canvasToImage);
+                canvasToImage.mapVectors(delta);
+            }
+
+            moveCursor(mCursorPosition.x - delta[0], mCursorPosition.y - delta[1]);
+            return true;
+        }
+
+        /** Called when the user is in the process of pinch-zooming. */
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_DELTA) {
+                return false;
+            }
+            mFingerMoved = true;
+
+            float scaleFactor = detector.getScaleFactor();
+            synchronized (mRenderData) {
+                mRenderData.transform.postScale(
+                        scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
+            }
+            repositionImageWithZoom();
+            return true;
+        }
+
+        /** Called whenever a gesture starts. Always accepts the gesture so it isn't ignored. */
+        @Override
+        public boolean onDown(MotionEvent e) {
+            return true;
+        }
+
+        /**
+         * Called when the user starts to zoom. Always accepts the zoom so that
+         * onScale() can decide whether to respond to it.
+         */
+        @Override
+        public boolean onScaleBegin(ScaleGestureDetector detector) {
+            return true;
+        }
+
+        /** Called when the user is done zooming. Defers to onScale()'s judgement. */
+        @Override
+        public void onScaleEnd(ScaleGestureDetector detector) {
+            onScale(detector);
+        }
+    }
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
index fb9110d..d8ca6a7 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -22,6 +22,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
 import org.chromium.chromoting.R;
 
 import java.nio.ByteBuffer;
@@ -31,6 +33,7 @@
  * Initializes the Chromium remoting library, and provides JNI calls into it.
  * All interaction with the native code is centralized in this class.
  */
+@JNINamespace("remoting")
 public class JniInterface {
     /** The status code indicating successful connection. */
     private static final int SUCCESSFUL_CONNECTION = 3;
@@ -57,19 +60,20 @@
         }
 
         System.loadLibrary("remoting_client_jni");
-        loadNative(context);
+
+        nativeLoadNative(context);
         sLoaded = true;
     }
 
     /** Performs the native portion of the initialization. */
-    private static native void loadNative(Context context);
+    private static native void nativeLoadNative(Context context);
 
     /*
      * API/OAuth2 keys access.
      */
-    public static native String getApiKey();
-    public static native String getClientId();
-    public static native String getClientSecret();
+    public static native String nativeGetApiKey();
+    public static native String nativeGetClientId();
+    public static native String nativeGetClientSecret();
 
     /*
      * Connection-initiating state machine.
@@ -96,7 +100,7 @@
 
         sSuccessCallback = successCallback;
         SharedPreferences prefs = sContext.getPreferences(Activity.MODE_PRIVATE);
-        connectNative(username, authToken, hostJid, hostId, hostPubkey,
+        nativeConnect(username, authToken, hostJid, hostId, hostPubkey,
                 prefs.getString(hostId + "_id", ""), prefs.getString(hostId + "_secret", ""));
         sConnected = true;
     }
@@ -112,7 +116,7 @@
             }
         }
 
-        disconnectNative();
+        nativeDisconnect();
         sSuccessCallback = null;
         sConnected = false;
 
@@ -123,11 +127,11 @@
     }
 
     /** Performs the native portion of the connection. */
-    private static native void connectNative(String username, String authToken, String hostJid,
+    private static native void nativeConnect(String username, String authToken, String hostJid,
             String hostId, String hostPubkey, String pairId, String pairSecret);
 
     /** Performs the native portion of the cleanup. */
-    private static native void disconnectNative();
+    private static native void nativeDisconnect();
 
     /** Position of cursor hotspot within cursor image. */
     public static Point getCursorHotspot() { return sCursorHotspot; }
@@ -154,6 +158,7 @@
     private static Bitmap sCursorBitmap = null;
 
     /** Reports whenever the connection status changes. */
+    @CalledByNative
     private static void reportConnectionStatus(int state, int error) {
         if (state < SUCCESSFUL_CONNECTION && error == 0) {
             // The connection is still being established, so we'll report the current progress.
@@ -201,6 +206,7 @@
     }
 
     /** Prompts the user to enter a PIN. */
+    @CalledByNative
     private static void displayAuthenticationPrompt(boolean pairingSupported) {
         AlertDialog.Builder pinPrompt = new AlertDialog.Builder(sContext);
         pinPrompt.setTitle(sContext.getString(R.string.pin_entry_title));
@@ -223,8 +229,8 @@
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         Log.i("jniiface", "User provided a PIN code");
-                        authenticationResponse(String.valueOf(pinTextView.getText()),
-                                               pinCheckBox.isChecked());
+                        nativeAuthenticationResponse(String.valueOf(pinTextView.getText()),
+                                                     pinCheckBox.isChecked());
                     }
                 });
 
@@ -266,6 +272,7 @@
     }
 
     /** Saves newly-received pairing credentials to permanent storage. */
+    @CalledByNative
     private static void commitPairingCredentials(String host, byte[] id, byte[] secret) {
         synchronized (sContext) {
             sContext.getPreferences(Activity.MODE_PRIVATE).edit().
@@ -289,14 +296,16 @@
             if (!sConnected || sRedrawCallback == null) return false;
         }
 
-        scheduleRedrawNative();
+        nativeScheduleRedraw();
         return true;
     }
 
     /** Performs the redrawing callback. This is a no-op if the window isn't visible. */
+    @CalledByNative
     private static void redrawGraphicsInternal() {
-        if (sRedrawCallback != null)
+        if (sRedrawCallback != null) {
             sRedrawCallback.run();
+        }
     }
 
     /**
@@ -318,9 +327,9 @@
     }
 
     /**
-     * Sets a new video frame. Called from native code on the native graphics thread when a new
-     * frame is allocated.
+     * Sets a new video frame. Called on the native graphics thread when a new frame is allocated.
      */
+    @CalledByNative
     private static void setVideoFrame(Bitmap bitmap) {
         if (Looper.myLooper() == Looper.getMainLooper()) {
             Log.w("jniiface", "Video frame updated on UI thread");
@@ -335,14 +344,16 @@
      * Creates a new Bitmap to hold video frame pixels. Called by native code which stores a global
      * reference to the Bitmap and writes the decoded frame pixels to it.
      */
+    @CalledByNative
     private static Bitmap newBitmap(int width, int height) {
         return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
     }
 
     /**
-     * Updates the cursor shape. This is called from native code on the graphics thread when
-     * receiving a new cursor shape from the host.
+     * Updates the cursor shape. This is called on the graphics thread when receiving a new cursor
+     * shape from the host.
      */
+    @CalledByNative
     public static void updateCursorShape(int width, int height, int hotspotX, int hotspotY,
                                          ByteBuffer buffer) {
         sCursorHotspot = new Point(hotspotX, hotspotY);
@@ -359,7 +370,7 @@
             return;
         }
 
-        mouseActionNative(x, y, whichButton, buttonDown);
+        nativeMouseAction(x, y, whichButton, buttonDown);
     }
 
     /** Presses and releases the specified (nonnegative) key. */
@@ -368,18 +379,18 @@
             return;
         }
 
-        keyboardActionNative(keyCode, keyDown);
+        nativeKeyboardAction(keyCode, keyDown);
     }
 
     /** Performs the native response to the user's PIN. */
-    private static native void authenticationResponse(String pin, boolean createPair);
+    private static native void nativeAuthenticationResponse(String pin, boolean createPair);
 
     /** Schedules a redraw on the native graphics thread. */
-    private static native void scheduleRedrawNative();
+    private static native void nativeScheduleRedraw();
 
     /** Passes mouse information to the native handling code. */
-    private static native void mouseActionNative(int x, int y, int whichButton, boolean buttonDown);
+    private static native void nativeMouseAction(int x, int y, int whichButton, boolean buttonDown);
 
     /** Passes key press information to the native handling code. */
-    private static native void keyboardActionNative(int keyCode, boolean keyDown);
+    private static native void nativeKeyboardAction(int keyCode, boolean keyDown);
 }
diff --git a/remoting/client/jni/DEPS b/remoting/client/jni/DEPS
index 26dcd15..85fd773 100644
--- a/remoting/client/jni/DEPS
+++ b/remoting/client/jni/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+jni",
   "+ui/gfx/android",
 ]
diff --git a/remoting/client/jni/chromoting_jni_onload.cc b/remoting/client/jni/chromoting_jni_onload.cc
new file mode 100644
index 0000000..e82b757
--- /dev/null
+++ b/remoting/client/jni/chromoting_jni_onload.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 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/android/base_jni_registrar.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "net/android/net_jni_registrar.h"
+#include "remoting/client/jni/chromoting_jni_runtime.h"
+#include "ui/gfx/android/gfx_jni_registrar.h"
+
+extern "C" {
+
+JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+  base::android::InitVM(vm);
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  static base::android::RegistrationMethod kRemotingRegisteredMethods[] = {
+      {"base", base::android::RegisterJni},
+      {"gfx", gfx::android::RegisterJni},
+      {"net", net::android::RegisterJni},
+      {"remoting", remoting::RegisterJni},
+  };
+  if (!base::android::RegisterNativeMethods(
+      env, kRemotingRegisteredMethods, arraysize(kRemotingRegisteredMethods))) {
+    return -1;
+  }
+
+  return JNI_VERSION_1_4;
+}
+
+}  // extern "C"
diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc
index 11ca730..cbc7a35 100644
--- a/remoting/client/jni/chromoting_jni_runtime.cc
+++ b/remoting/client/jni/chromoting_jni_runtime.cc
@@ -4,21 +4,26 @@
 
 #include "remoting/client/jni/chromoting_jni_runtime.h"
 
-#include "base/android/base_jni_registrar.h"
 #include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/command_line.h"
 #include "base/memory/singleton.h"
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
+#include "google_apis/google_api_keys.h"
+#include "jni/JniInterface_jni.h"
 #include "media/base/yuv_convert.h"
-#include "net/android/net_jni_registrar.h"
 #include "remoting/base/url_request_context.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 
-namespace {
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ToJavaByteArray;
 
-// Class and package name of the Java class supporting the methods we call.
-const char* const kJavaClass = "org/chromium/chromoting/jni/JniInterface";
+namespace {
 
 const int kBytesPerPixel = 4;
 
@@ -26,22 +31,110 @@
 
 namespace remoting {
 
+bool RegisterJni(JNIEnv* env) {
+  return remoting::RegisterNativesImpl(env);
+}
+
+// Implementation of stubs defined in JniInterface_jni.h. These are the entry
+// points for JNI calls from Java into C++.
+
+static void LoadNative(JNIEnv* env, jclass clazz, jobject context) {
+  base::android::ScopedJavaLocalRef<jobject> context_activity(env, context);
+  base::android::InitApplicationContext(context_activity);
+
+  // The google_apis functions check the command-line arguments to make sure no
+  // runtime API keys have been specified by the environment. Unfortunately, we
+  // neither launch Chromium nor have a command line, so we need to prevent
+  // them from DCHECKing out when they go looking.
+  CommandLine::Init(0, NULL);
+
+  // Create the singleton now so that the Chromoting threads will be set up.
+  remoting::ChromotingJniRuntime::GetInstance();
+}
+
+static jstring GetApiKey(JNIEnv* env, jclass clazz) {
+  return env->NewStringUTF(google_apis::GetAPIKey().c_str());
+}
+
+static jstring GetClientId(JNIEnv* env, jclass clazz) {
+  return env->NewStringUTF(
+      google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING).c_str());
+}
+
+static jstring GetClientSecret(JNIEnv* env, jclass clazz) {
+  return env->NewStringUTF(
+      google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING).c_str());
+}
+
+static void Connect(JNIEnv* env,
+                    jclass clazz,
+                    jstring username,
+                    jstring authToken,
+                    jstring hostJid,
+                    jstring hostId,
+                    jstring hostPubkey,
+                    jstring pairId,
+                    jstring pairSecret) {
+  remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
+      ConvertJavaStringToUTF8(env, username).c_str(),
+      ConvertJavaStringToUTF8(env, authToken).c_str(),
+      ConvertJavaStringToUTF8(env, hostJid).c_str(),
+      ConvertJavaStringToUTF8(env, hostId).c_str(),
+      ConvertJavaStringToUTF8(env, hostPubkey).c_str(),
+      ConvertJavaStringToUTF8(env, pairId).c_str(),
+      ConvertJavaStringToUTF8(env, pairSecret).c_str());
+}
+
+static void Disconnect(JNIEnv* env, jclass clazz) {
+  remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
+}
+
+static void AuthenticationResponse(JNIEnv* env,
+                                   jclass clazz,
+                                   jstring pin,
+                                   jboolean createPair) {
+  remoting::ChromotingJniRuntime::GetInstance()->session()->ProvideSecret(
+      ConvertJavaStringToUTF8(env, pin).c_str(), createPair);
+}
+
+static void ScheduleRedraw(JNIEnv* env, jclass clazz) {
+  remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
+}
+
+static void MouseAction(JNIEnv* env,
+                        jclass clazz,
+                        jint x,
+                        jint y,
+                        jint whichButton,
+                        jboolean buttonDown) {
+  // Button must be within the bounds of the MouseEvent_MouseButton enum.
+  DCHECK(whichButton >= 0 && whichButton < 5);
+
+  remoting::ChromotingJniRuntime::GetInstance()->session()->PerformMouseAction(
+      x,
+      y,
+      static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton),
+      buttonDown);
+}
+
+static void KeyboardAction(JNIEnv* env,
+                           jclass clazz,
+                           jint keyCode,
+                           jboolean keyDown) {
+  remoting::ChromotingJniRuntime::GetInstance()
+      ->session()
+      ->PerformKeyboardAction(keyCode, keyDown);
+}
+
+// ChromotingJniRuntime implementation.
+
 // static
 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
   return Singleton<ChromotingJniRuntime>::get();
 }
 
 ChromotingJniRuntime::ChromotingJniRuntime() {
-  // Obtain a reference to the Java environment. (Future calls to this function
-  // made from the same thread return the same stored reference instead of
-  // repeating the work of attaching to the JVM.)
-  JNIEnv* env = base::android::AttachCurrentThread();
-
-  // The base and networks stacks must be registered with JNI in order to work
-  // on Android. An AtExitManager cleans this up at process exit.
   at_exit_manager_.reset(new base::AtExitManager());
-  base::android::RegisterJni(env);
-  net::android::RegisterJni(env);
 
   // On Android, the UI thread is managed by Java, so we need to attach and
   // start a special type of message loop to allow Chromium code to run tasks.
@@ -63,8 +156,6 @@
 
   // Allows later decoding of video frames.
   media::InitializeCPUSpecificYUVConversions();
-
-  class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(kJavaClass)));
 }
 
 ChromotingJniRuntime::~ChromotingJniRuntime() {
@@ -75,9 +166,6 @@
   // components' still being alive.
   DisconnectFromHost();
 
-  JNIEnv* env = base::android::AttachCurrentThread();
-  env->DeleteGlobalRef(class_);
-
   base::WaitableEvent done_event(false, false);
   network_task_runner_->PostTask(FROM_HERE, base::Bind(
       &ChromotingJniRuntime::DetachFromVmAndSignal,
@@ -125,21 +213,14 @@
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  env->CallStaticVoidMethod(
-    class_,
-    env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"),
-    state,
-    error);
+  Java_JniInterface_reportConnectionStatus(env, state, error);
 }
 
 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  env->CallStaticVoidMethod(
-      class_,
-      env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "(Z)V"),
-      pairing_supported);
+  Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported);
 }
 
 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
@@ -148,55 +229,27 @@
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  jstring host_jstr = env->NewStringUTF(host.c_str());
-  jbyteArray id_arr = env->NewByteArray(id.size());
-  env->SetByteArrayRegion(id_arr, 0, id.size(),
-      reinterpret_cast<const jbyte*>(id.c_str()));
-  jbyteArray secret_arr = env->NewByteArray(secret.size());
-  env->SetByteArrayRegion(secret_arr, 0, secret.size(),
-      reinterpret_cast<const jbyte*>(secret.c_str()));
+  ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host);
+  ScopedJavaLocalRef<jbyteArray> j_id = ToJavaByteArray(
+      env, reinterpret_cast<const uint8*>(id.data()), id.size());
+  ScopedJavaLocalRef<jbyteArray> j_secret = ToJavaByteArray(
+      env, reinterpret_cast<const uint8*>(secret.data()), secret.size());
 
-  env->CallStaticVoidMethod(
-      class_,
-      env->GetStaticMethodID(
-          class_,
-          "commitPairingCredentials",
-          "(Ljava/lang/String;[B[B)V"),
-      host_jstr,
-      id_arr,
-      secret_arr);
-
-  // Because we passed them as arguments, their corresponding Java objects were
-  // GCd as soon as the managed method returned, so we mustn't release it here.
+  Java_JniInterface_commitPairingCredentials(
+      env, j_host.obj(), j_id.obj(), j_secret.obj());
 }
 
 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap(
     webrtc::DesktopSize size) {
   JNIEnv* env = base::android::AttachCurrentThread();
-
-  jobject bitmap = env->CallStaticObjectMethod(
-      class_,
-      env->GetStaticMethodID(
-          class_,
-          "newBitmap",
-          "(II)Landroid/graphics/Bitmap;"),
-      size.width(),
-      size.height());
-  return base::android::ScopedJavaLocalRef<jobject>(env, bitmap);
+  return Java_JniInterface_newBitmap(env, size.width(), size.height());
 }
 
 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) {
   DCHECK(display_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
-
-  env->CallStaticVoidMethod(
-      class_,
-      env->GetStaticMethodID(
-          class_,
-          "setVideoFrame",
-          "(Landroid/graphics/Bitmap;)V"),
-      bitmap);
+  Java_JniInterface_setVideoFrame(env, bitmap);
 }
 
 void ChromotingJniRuntime::UpdateCursorShape(
@@ -214,26 +267,19 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> buffer(env,
       env->NewDirectByteBuffer(data, cursor_total_bytes));
-  env->CallStaticVoidMethod(
-      class_,
-      env->GetStaticMethodID(
-          class_,
-          "updateCursorShape",
-          "(IIIILjava/nio/ByteBuffer;)V"),
-      cursor_shape.width(),
-      cursor_shape.height(),
-      cursor_shape.hotspot_x(),
-      cursor_shape.hotspot_y(),
-      buffer.obj());
+  Java_JniInterface_updateCursorShape(env,
+                                      cursor_shape.width(),
+                                      cursor_shape.height(),
+                                      cursor_shape.hotspot_x(),
+                                      cursor_shape.hotspot_y(),
+                                      buffer.obj());
 }
 
 void ChromotingJniRuntime::RedrawCanvas() {
   DCHECK(display_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  env->CallStaticVoidMethod(
-      class_,
-      env->GetStaticMethodID(class_, "redrawGraphicsInternal", "()V"));
+  Java_JniInterface_redrawGraphicsInternal(env);
 }
 
 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
diff --git a/remoting/client/jni/chromoting_jni_runtime.h b/remoting/client/jni/chromoting_jni_runtime.h
index 93d77bd..bb356a1 100644
--- a/remoting/client/jni/chromoting_jni_runtime.h
+++ b/remoting/client/jni/chromoting_jni_runtime.h
@@ -19,6 +19,8 @@
 
 namespace remoting {
 
+bool RegisterJni(JNIEnv* env);
+
 // Houses the global resources on which the Chromoting components run
 // (e.g. message loops and task runners). Proxies outgoing JNI calls from its
 // ChromotingJniInstance member to Java. All its methods should be invoked
@@ -107,9 +109,6 @@
   // Detaches JVM from the current thread, then signals. Doesn't own |waiter|.
   void DetachFromVmAndSignal(base::WaitableEvent* waiter);
 
-  // Reference to the Java class into which we make JNI calls.
-  jclass class_;
-
   // Used by the Chromium libraries to clean up the base and net libraries' JNI
   // bindings. It must persist for the lifetime of the singleton.
   scoped_ptr<base::AtExitManager> at_exit_manager_;
diff --git a/remoting/client/jni/jni_interface.cc b/remoting/client/jni/jni_interface.cc
deleted file mode 100644
index 5180558..0000000
--- a/remoting/client/jni/jni_interface.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2013 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.
-
-// This file defines functions that implement the static methods declared in a
-// closely-related Java class in the platform-specific user interface
-// implementation.  In effect, it is the entry point for all JNI calls *into*
-// the C++ codebase from Java.  The separate ChromotingJniRuntime class serves
-// as the corresponding exit point, and is responsible for making all JNI calls
-// *out of* the C++ codebase into Java.
-
-#include <jni.h>
-
-#include "base/android/jni_android.h"
-#include "base/command_line.h"
-#include "base/memory/ref_counted.h"
-#include "google_apis/google_api_keys.h"
-#include "remoting/client/jni/chromoting_jni_instance.h"
-#include "remoting/client/jni/chromoting_jni_runtime.h"
-
-// Class and package name of the Java class that declares this file's functions.
-#define JNI_IMPLEMENTATION(method) \
-        Java_org_chromium_chromoting_jni_JniInterface_##method
-
-extern "C" {
-
-JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
-  base::android::InitVM(vm);
-  return JNI_VERSION_1_2;
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(loadNative)(JNIEnv* env,
-                                                      jobject that,
-                                                      jobject context) {
-  base::android::ScopedJavaLocalRef<jobject> context_activity(env, context);
-  base::android::InitApplicationContext(context_activity);
-
-  // The google_apis functions check the command-line arguments to make sure no
-  // runtime API keys have been specified by the environment. Unfortunately, we
-  // neither launch Chromium nor have a command line, so we need to prevent
-  // them from DCHECKing out when they go looking.
-  CommandLine::Init(0, NULL);
-
-  // Create the singleton now so that the Chromoting threads will be set up.
-  remoting::ChromotingJniRuntime::GetInstance();
-}
-
-JNIEXPORT jstring JNICALL JNI_IMPLEMENTATION(getApiKey)(JNIEnv* env,
-                                                        jobject that) {
-  return env->NewStringUTF(google_apis::GetAPIKey().c_str());
-}
-
-JNIEXPORT jstring JNICALL JNI_IMPLEMENTATION(getClientId)(JNIEnv* env,
-                                                          jobject that) {
-  return env->NewStringUTF(
-      google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING).c_str());
-}
-
-JNIEXPORT jstring JNICALL JNI_IMPLEMENTATION(getClientSecret)(JNIEnv* env,
-                                                              jobject that) {
-  return env->NewStringUTF(
-      google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING).c_str());
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(connectNative)(
-    JNIEnv* env,
-    jobject that,
-    jstring username_jstr,
-    jstring auth_token_jstr,
-    jstring host_jid_jstr,
-    jstring host_id_jstr,
-    jstring host_pubkey_jstr,
-    jstring pair_id_jstr,
-    jstring pair_secret_jstr) {
-  const char* username_cstr = env->GetStringUTFChars(username_jstr, NULL);
-  const char* auth_token_cstr = env->GetStringUTFChars(auth_token_jstr, NULL);
-  const char* host_jid_cstr = env->GetStringUTFChars(host_jid_jstr, NULL);
-  const char* host_id_cstr = env->GetStringUTFChars(host_id_jstr, NULL);
-  const char* host_pubkey_cstr = env->GetStringUTFChars(host_pubkey_jstr, NULL);
-  const char* pair_id_cstr = env->GetStringUTFChars(pair_id_jstr, NULL);
-  const char* pair_secret_cstr = env->GetStringUTFChars(pair_secret_jstr, NULL);
-
-  remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
-      username_cstr,
-      auth_token_cstr,
-      host_jid_cstr,
-      host_id_cstr,
-      host_pubkey_cstr,
-      pair_id_cstr,
-      pair_secret_cstr);
-
-  env->ReleaseStringUTFChars(username_jstr, username_cstr);
-  env->ReleaseStringUTFChars(auth_token_jstr, auth_token_cstr);
-  env->ReleaseStringUTFChars(host_jid_jstr, host_jid_cstr);
-  env->ReleaseStringUTFChars(host_id_jstr, host_id_cstr);
-  env->ReleaseStringUTFChars(host_pubkey_jstr, host_pubkey_cstr);
-  env->ReleaseStringUTFChars(pair_id_jstr, pair_id_cstr);
-  env->ReleaseStringUTFChars(pair_secret_jstr, pair_secret_cstr);
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(disconnectNative)(JNIEnv* env,
-                                                            jobject that) {
-  remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(authenticationResponse)(
-    JNIEnv* env,
-    jobject that,
-    jstring pin_jstr,
-    jboolean create_pair) {
-  const char* pin_cstr = env->GetStringUTFChars(pin_jstr, NULL);
-
-  remoting::ChromotingJniRuntime::GetInstance()->
-      session()->ProvideSecret(pin_cstr, create_pair);
-
-  env->ReleaseStringUTFChars(pin_jstr, pin_cstr);
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(scheduleRedrawNative)(
-    JNIEnv* env,
-    jobject that) {
-  remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(mouseActionNative)(
-    JNIEnv* env,
-    jobject that,
-    jint x,
-    jint y,
-    jint which_button,
-    jboolean button_down) {
-  // Button must be within the bounds of the MouseEvent_MouseButton enum.
-  DCHECK(which_button >= 0 && which_button < 5);
-
-  remoting::ChromotingJniRuntime::GetInstance()->session()->PerformMouseAction(
-      x,
-      y,
-      static_cast<remoting::protocol::MouseEvent_MouseButton>(which_button),
-      button_down);
-}
-
-JNIEXPORT void JNICALL JNI_IMPLEMENTATION(keyboardActionNative)(
-    JNIEnv* env,
-    jobject that,
-    jint key_code,
-    jboolean key_down) {
-  remoting::ChromotingJniRuntime::GetInstance()->session()->
-      PerformKeyboardAction(key_code, key_down);
-}
-
-}  // extern "C"
diff --git a/remoting/host/it2me/it2me_impl.cc b/remoting/host/it2me/it2me_impl.cc
new file mode 100644
index 0000000..7b1b4c4
--- /dev/null
+++ b/remoting/host/it2me/it2me_impl.cc
@@ -0,0 +1,468 @@
+// Copyright 2013 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 "remoting/host/it2me/it2me_impl.h"
+
+#include "base/bind.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "net/socket/client_socket_factory.h"
+#include "remoting/base/auto_thread.h"
+#include "remoting/base/rsa_key_pair.h"
+#include "remoting/host/chromoting_host.h"
+#include "remoting/host/chromoting_host_context.h"
+#include "remoting/host/host_event_logger.h"
+#include "remoting/host/host_secret.h"
+#include "remoting/host/it2me_desktop_environment.h"
+#include "remoting/host/policy_hack/policy_watcher.h"
+#include "remoting/host/register_support_host_request.h"
+#include "remoting/host/session_manager_factory.h"
+#include "remoting/jingle_glue/network_settings.h"
+#include "remoting/protocol/it2me_host_authenticator_factory.h"
+
+namespace remoting {
+
+namespace {
+
+// This is used for tagging system event logs.
+const char kApplicationName[] = "chromoting";
+const int kMaxLoginAttempts = 5;
+
+}  // namespace
+
+It2MeImpl::It2MeImpl(
+    scoped_ptr<ChromotingHostContext> host_context,
+    scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
+    base::WeakPtr<It2MeImpl::Observer> observer,
+    const XmppSignalStrategy::XmppServerConfig& xmpp_server_config,
+    const std::string& directory_bot_jid)
+  : host_context_(host_context.Pass()),
+    plugin_task_runner_(plugin_task_runner),
+    observer_(observer),
+    xmpp_server_config_(xmpp_server_config),
+    directory_bot_jid_(directory_bot_jid),
+    state_(kDisconnected),
+    failed_login_attempts_(0),
+    nat_traversal_enabled_(false),
+    policy_received_(false) {
+  DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+}
+
+void It2MeImpl::Connect() {
+  if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
+    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+    host_context_->ui_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&It2MeImpl::Connect, this));
+    return;
+  }
+
+  desktop_environment_factory_.reset(new It2MeDesktopEnvironmentFactory(
+      host_context_->network_task_runner(),
+      host_context_->input_task_runner(),
+      host_context_->ui_task_runner()));
+
+  // Start monitoring configured policies.
+  policy_watcher_.reset(
+      policy_hack::PolicyWatcher::Create(host_context_->network_task_runner()));
+  policy_watcher_->StartWatching(
+      base::Bind(&It2MeImpl::OnPolicyUpdate, this));
+
+  // Switch to the network thread to start the actual connection.
+  host_context_->network_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::ReadPolicyAndConnect, this));
+}
+
+void It2MeImpl::Disconnect() {
+  if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
+    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+    host_context_->network_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&It2MeImpl::Disconnect, this));
+    return;
+  }
+
+  switch (state_) {
+    case kDisconnected:
+      ShutdownOnNetworkThread();
+      return;
+
+    case kStarting:
+      SetState(kDisconnecting);
+      SetState(kDisconnected);
+      ShutdownOnNetworkThread();
+      return;
+
+    case kDisconnecting:
+      return;
+
+    default:
+      SetState(kDisconnecting);
+
+      if (!host_) {
+        SetState(kDisconnected);
+        ShutdownOnNetworkThread();
+        return;
+      }
+
+      // Deleting the host destroys SignalStrategy synchronously, but
+      // SignalStrategy::Listener handlers are not allowed to destroy
+      // SignalStrategy, so post task to destroy the host later.
+      host_context_->network_task_runner()->PostTask(
+          FROM_HERE, base::Bind(&It2MeImpl::ShutdownOnNetworkThread, this));
+      return;
+  }
+}
+
+void It2MeImpl::RequestNatPolicy() {
+  if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
+    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
+    host_context_->network_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&It2MeImpl::RequestNatPolicy, this));
+    return;
+  }
+
+  if (policy_received_)
+    UpdateNatPolicy(nat_traversal_enabled_);
+}
+
+void It2MeImpl::ReadPolicyAndConnect() {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  SetState(kStarting);
+
+  // Only proceed to FinishConnect() if at least one policy update has been
+  // received.
+  if (policy_received_) {
+    FinishConnect();
+  } else {
+    // Otherwise, create the policy watcher, and thunk the connect.
+    pending_connect_ =
+        base::Bind(&It2MeImpl::FinishConnect, this);
+  }
+}
+
+void It2MeImpl::FinishConnect() {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  if (state_ != kStarting) {
+    // Host has been stopped while we were fetching policy.
+    return;
+  }
+
+  // Check the host domain policy.
+  if (!required_host_domain_.empty() &&
+      !EndsWith(xmpp_server_config_.username,
+                std::string("@") + required_host_domain_, false)) {
+    SetState(kInvalidDomainError);
+    return;
+  }
+
+  // Generate a key pair for the Host to use.
+  // TODO(wez): Move this to the worker thread.
+  host_key_pair_ = RsaKeyPair::Generate();
+
+  // Create XMPP connection.
+  scoped_ptr<SignalStrategy> signal_strategy(
+      new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+                             host_context_->url_request_context_getter(),
+                             xmpp_server_config_));
+
+  // Request registration of the host for support.
+  scoped_ptr<RegisterSupportHostRequest> register_request(
+      new RegisterSupportHostRequest(
+          signal_strategy.get(), host_key_pair_, directory_bot_jid_,
+          base::Bind(&It2MeImpl::OnReceivedSupportID,
+                     base::Unretained(this))));
+
+  // Beyond this point nothing can fail, so save the config and request.
+  signal_strategy_ = signal_strategy.Pass();
+  register_request_ = register_request.Pass();
+
+  // If NAT traversal is off then limit port range to allow firewall pin-holing.
+  LOG(INFO) << "NAT state: " << nat_traversal_enabled_;
+  NetworkSettings network_settings(
+     nat_traversal_enabled_ ?
+     NetworkSettings::NAT_TRAVERSAL_ENABLED :
+     NetworkSettings::NAT_TRAVERSAL_DISABLED);
+  if (!nat_traversal_enabled_) {
+    network_settings.min_port = NetworkSettings::kDefaultMinPort;
+    network_settings.max_port = NetworkSettings::kDefaultMaxPort;
+  }
+
+  // Create the host.
+  host_.reset(new ChromotingHost(
+      signal_strategy_.get(),
+      desktop_environment_factory_.get(),
+      CreateHostSessionManager(network_settings,
+                               host_context_->url_request_context_getter()),
+      host_context_->audio_task_runner(),
+      host_context_->input_task_runner(),
+      host_context_->video_capture_task_runner(),
+      host_context_->video_encode_task_runner(),
+      host_context_->network_task_runner(),
+      host_context_->ui_task_runner()));
+  host_->AddStatusObserver(this);
+  log_to_server_.reset(
+      new LogToServer(host_->AsWeakPtr(), ServerLogEntry::IT2ME,
+                      signal_strategy_.get(), directory_bot_jid_));
+
+  // Disable audio by default.
+  // TODO(sergeyu): Add UI to enable it.
+  scoped_ptr<protocol::CandidateSessionConfig> protocol_config =
+      protocol::CandidateSessionConfig::CreateDefault();
+  protocol::CandidateSessionConfig::DisableAudioChannel(protocol_config.get());
+
+  // VP9 encode is not yet supported.
+  protocol::CandidateSessionConfig::DisableVideoCodec(
+      protocol_config.get(), protocol::ChannelConfig::CODEC_VP9);
+
+  host_->set_protocol_config(protocol_config.Pass());
+
+  // Create event logger.
+  host_event_logger_ =
+      HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
+
+  // Connect signaling and start the host.
+  signal_strategy_->Connect();
+  host_->Start(xmpp_server_config_.username);
+
+  SetState(kRequestedAccessCode);
+  return;
+}
+
+void It2MeImpl::ShutdownOnNetworkThread() {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+  DCHECK(state_ == kDisconnecting || state_ == kDisconnected);
+
+  if (state_ == kDisconnecting) {
+    host_event_logger_.reset();
+    host_->RemoveStatusObserver(this);
+    host_.reset();
+
+    register_request_.reset();
+    log_to_server_.reset();
+    signal_strategy_.reset();
+    SetState(kDisconnected);
+  }
+
+  host_context_->ui_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::ShutdownOnUiThread, this));
+}
+
+void It2MeImpl::ShutdownOnUiThread() {
+  DCHECK(host_context_->ui_task_runner()->BelongsToCurrentThread());
+
+  // Destroy the DesktopEnvironmentFactory, to free thread references.
+  desktop_environment_factory_.reset();
+
+  // Stop listening for policy updates.
+  if (policy_watcher_.get()) {
+    base::WaitableEvent policy_watcher_stopped_(true, false);
+    policy_watcher_->StopWatching(&policy_watcher_stopped_);
+    policy_watcher_stopped_.Wait();
+    policy_watcher_.reset();
+  }
+}
+
+void It2MeImpl::OnAccessDenied(const std::string& jid) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  ++failed_login_attempts_;
+  if (failed_login_attempts_ == kMaxLoginAttempts) {
+    Disconnect();
+  }
+}
+
+void It2MeImpl::OnClientAuthenticated(
+    const std::string& jid) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  if (state_ == kDisconnecting) {
+    // Ignore the new connection if we are disconnecting.
+    return;
+  }
+  if (state_ == kConnected) {
+    // If we already connected another client then one of the connections may be
+    // an attacker, so both are suspect and we have to reject the second
+    // connection and shutdown the host.
+    host_->RejectAuthenticatingClient();
+    Disconnect();
+    return;
+  }
+
+  std::string client_username = jid;
+  size_t pos = client_username.find('/');
+  if (pos != std::string::npos)
+    client_username.replace(pos, std::string::npos, "");
+
+  LOG(INFO) << "Client " << client_username << " connected.";
+
+  // Pass the client user name to the script object before changing state.
+  plugin_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::Observer::OnClientAuthenticated,
+                            observer_, client_username));
+
+  SetState(kConnected);
+}
+
+void It2MeImpl::OnClientDisconnected(
+    const std::string& jid) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  Disconnect();
+}
+
+void It2MeImpl::OnPolicyUpdate(
+    scoped_ptr<base::DictionaryValue> policies) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  bool nat_policy;
+  if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
+                           &nat_policy)) {
+    UpdateNatPolicy(nat_policy);
+  }
+  std::string host_domain;
+  if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
+                          &host_domain)) {
+    UpdateHostDomainPolicy(host_domain);
+  }
+
+  policy_received_ = true;
+
+  if (!pending_connect_.is_null()) {
+    pending_connect_.Run();
+    pending_connect_.Reset();
+  }
+}
+
+void It2MeImpl::UpdateNatPolicy(
+    bool nat_traversal_enabled) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled;
+
+  // When transitioning from enabled to disabled, force disconnect any
+  // existing session.
+  if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) {
+    Disconnect();
+  }
+
+  nat_traversal_enabled_ = nat_traversal_enabled;
+
+  // Notify the web-app of the policy setting.
+  plugin_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::Observer::OnNatPolicyChanged,
+                            observer_, nat_traversal_enabled_));
+}
+
+void It2MeImpl::UpdateHostDomainPolicy(
+    const std::string& host_domain) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  VLOG(2) << "UpdateHostDomainPolicy: " << host_domain;
+
+  // When setting a host domain policy, force disconnect any existing session.
+  if (!host_domain.empty() && IsConnected()) {
+    Disconnect();
+  }
+
+  required_host_domain_ = host_domain;
+}
+
+It2MeImpl::~It2MeImpl() {
+  // Check that resources that need to be torn down on the UI thread are gone.
+  DCHECK(!desktop_environment_factory_.get());
+  DCHECK(!policy_watcher_.get());
+}
+
+void It2MeImpl::SetState(It2MeHostState state) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  switch (state_) {
+    case kDisconnected:
+      DCHECK(state == kStarting ||
+             state == kError) << state;
+      break;
+    case kStarting:
+      DCHECK(state == kRequestedAccessCode ||
+             state == kDisconnecting ||
+             state == kError ||
+             state == kInvalidDomainError) << state;
+      break;
+    case kRequestedAccessCode:
+      DCHECK(state == kReceivedAccessCode ||
+             state == kDisconnecting ||
+             state == kError) << state;
+      break;
+    case kReceivedAccessCode:
+      DCHECK(state == kConnected ||
+             state == kDisconnecting ||
+             state == kError) << state;
+      break;
+    case kConnected:
+      DCHECK(state == kDisconnecting ||
+             state == kDisconnected ||
+             state == kError) << state;
+      break;
+    case kDisconnecting:
+      DCHECK(state == kDisconnected) << state;
+      break;
+    case kError:
+      DCHECK(state == kDisconnecting) << state;
+      break;
+    case kInvalidDomainError:
+      DCHECK(state == kDisconnecting) << state;
+      break;
+  };
+
+  state_ = state;
+
+  // Post a state-change notification to the web-app.
+  plugin_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::Observer::OnStateChanged,
+                            observer_, state));
+}
+
+bool It2MeImpl::IsConnected() const {
+  return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode ||
+      state_ == kConnected;
+}
+
+void It2MeImpl::OnReceivedSupportID(
+    bool success,
+    const std::string& support_id,
+    const base::TimeDelta& lifetime) {
+  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
+
+  if (!success) {
+    SetState(kError);
+    Disconnect();
+    return;
+  }
+
+  std::string host_secret = GenerateSupportHostSecret();
+  std::string access_code = support_id + host_secret;
+
+  std::string local_certificate = host_key_pair_->GenerateCertificate();
+  if (local_certificate.empty()) {
+    LOG(ERROR) << "Failed to generate host certificate.";
+    SetState(kError);
+    Disconnect();
+    return;
+  }
+
+  scoped_ptr<protocol::AuthenticatorFactory> factory(
+      new protocol::It2MeHostAuthenticatorFactory(
+          local_certificate, host_key_pair_, access_code));
+  host_->SetAuthenticatorFactory(factory.Pass());
+
+  // Pass the Access Code to the script object before changing state.
+  plugin_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&It2MeImpl::Observer::OnStoreAccessCode,
+                            observer_, access_code, lifetime));
+
+  SetState(kReceivedAccessCode);
+}
+
+}  // namespace remoting
diff --git a/remoting/host/it2me/it2me_impl.h b/remoting/host/it2me/it2me_impl.h
new file mode 100644
index 0000000..f31709b
--- /dev/null
+++ b/remoting/host/it2me/it2me_impl.h
@@ -0,0 +1,161 @@
+// Copyright 2013 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 REMOTING_HOST_IT2ME__IT2ME_IMPL_H_
+#define REMOTING_HOST_IT2ME__IT2ME_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "remoting/host/log_to_server.h"
+#include "remoting/jingle_glue/xmpp_signal_strategy.h"
+
+namespace remoting {
+
+class RegisterSupportHostRequest;
+class HostNPScriptObject;
+class DesktopEnvironmentFactory;
+class HostEventLogger;
+class ChromotingHost;
+class ChromotingHostContext;
+
+namespace policy_hack {
+
+class PolicyWatcher;
+
+}  // namespace policy_hack
+
+// These state values are duplicated in host_session.js. Remember to update
+// both copies when making changes.
+enum It2MeHostState {
+  kDisconnected,
+  kStarting,
+  kRequestedAccessCode,
+  kReceivedAccessCode,
+  kConnected,
+  kDisconnecting,
+  kError,
+  kInvalidDomainError
+};
+
+// Internal implementation of the plugin's It2Me host function.
+class It2MeImpl
+    : public base::RefCountedThreadSafe<It2MeImpl>,
+      public HostStatusObserver {
+ public:
+
+  class Observer {
+   public:
+    virtual void OnClientAuthenticated(const std::string& client_username) = 0;
+    virtual void OnStoreAccessCode(const std::string& access_code,
+                                   base::TimeDelta access_code_lifetime) = 0;
+    virtual void OnNatPolicyChanged(bool nat_traversal_enabled) = 0;
+    virtual void OnStateChanged(It2MeHostState state) = 0;
+  };
+
+  It2MeImpl(
+      scoped_ptr<ChromotingHostContext> context,
+      scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
+      base::WeakPtr<It2MeImpl::Observer> observer,
+      const XmppSignalStrategy::XmppServerConfig& xmpp_server_config,
+      const std::string& directory_bot_jid);
+
+  // Methods called by the script object, from the plugin thread.
+
+  // Creates It2Me host structures and starts the host.
+  void Connect();
+
+  // Disconnects the host, ready for tear-down.
+  // Also called internally, from the network thread.
+  void Disconnect();
+
+  // Request a NAT policy notification.
+  void RequestNatPolicy();
+
+  // remoting::HostStatusObserver implementation.
+  virtual void OnAccessDenied(const std::string& jid) OVERRIDE;
+  virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE;
+  virtual void OnClientDisconnected(const std::string& jid) OVERRIDE;
+
+ private:
+  friend class base::RefCountedThreadSafe<It2MeImpl>;
+
+  virtual ~It2MeImpl();
+
+  // Updates state of the host. Can be called only on the network thread.
+  void SetState(It2MeHostState state);
+
+  // Returns true if the host is connected.
+  bool IsConnected() const;
+
+  // Called by Connect() to check for policies and start connection process.
+  void ReadPolicyAndConnect();
+
+  // Called by ReadPolicyAndConnect once policies have been read.
+  void FinishConnect();
+
+  // Called when the support host registration completes.
+  void OnReceivedSupportID(bool success,
+                           const std::string& support_id,
+                           const base::TimeDelta& lifetime);
+
+  // Shuts down |host_| on the network thread and posts ShutdownOnUiThread()
+  // to shut down UI thread resources.
+  void ShutdownOnNetworkThread();
+
+  // Shuts down |desktop_environment_factory_| and |policy_watcher_| on
+  // the UI thread.
+  void ShutdownOnUiThread();
+
+  // Called when initial policies are read, and when they change.
+  void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
+
+  // Handlers for NAT traversal and host domain policies.
+  void UpdateNatPolicy(bool nat_traversal_enabled);
+  void UpdateHostDomainPolicy(const std::string& host_domain);
+
+  // Caller supplied fields.
+  scoped_ptr<ChromotingHostContext> host_context_;
+  scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner_;
+  base::WeakPtr<It2MeImpl::Observer> observer_;
+  XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
+  std::string directory_bot_jid_;
+
+  It2MeHostState state_;
+
+  scoped_refptr<RsaKeyPair> host_key_pair_;
+  scoped_ptr<SignalStrategy> signal_strategy_;
+  scoped_ptr<RegisterSupportHostRequest> register_request_;
+  scoped_ptr<LogToServer> log_to_server_;
+  scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
+  scoped_ptr<HostEventLogger> host_event_logger_;
+
+  scoped_ptr<ChromotingHost> host_;
+  int failed_login_attempts_;
+
+  scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
+
+  // Host the current nat traversal policy setting.
+  bool nat_traversal_enabled_;
+
+  // The host domain policy setting.
+  std::string required_host_domain_;
+
+  // Indicates whether or not a policy has ever been read. This is to ensure
+  // that on startup, we do not accidentally start a connection before we have
+  // queried our policy restrictions.
+  bool policy_received_;
+
+  // On startup, it is possible to have Connect() called before the policy read
+  // is completed.  Rather than just failing, we thunk the connection call so
+  // it can be executed after at least one successful policy read. This
+  // variable contains the thunk if it is necessary.
+  base::Closure pending_connect_;
+
+  DISALLOW_COPY_AND_ASSIGN(It2MeImpl);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_HOST_IT2ME__IT2ME_IMPL_H_
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc
index 3459bf8..66d228c 100644
--- a/remoting/host/plugin/host_script_object.cc
+++ b/remoting/host/plugin/host_script_object.cc
@@ -7,46 +7,29 @@
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/platform_thread.h"
-#include "base/values.h"
-#include "net/base/net_util.h"
-#include "net/socket/client_socket_factory.h"
 #include "remoting/base/auth_token_util.h"
 #include "remoting/base/auto_thread.h"
 #include "remoting/base/resources.h"
 #include "remoting/base/rsa_key_pair.h"
-#include "remoting/host/chromoting_host.h"
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/host_config.h"
-#include "remoting/host/host_event_logger.h"
-#include "remoting/host/host_secret.h"
-#include "remoting/host/host_status_observer.h"
-#include "remoting/host/it2me_desktop_environment.h"
 #include "remoting/host/pairing_registry_delegate.h"
 #include "remoting/host/pin_hash.h"
 #include "remoting/host/plugin/host_log_handler.h"
 #include "remoting/host/policy_hack/policy_watcher.h"
-#include "remoting/host/register_support_host_request.h"
 #include "remoting/host/service_urls.h"
-#include "remoting/host/session_manager_factory.h"
-#include "remoting/jingle_glue/network_settings.h"
-#include "remoting/jingle_glue/xmpp_signal_strategy.h"
-#include "remoting/protocol/it2me_host_authenticator_factory.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npfunctions.h"
 #include "third_party/npapi/bindings/npruntime.h"
 
 namespace remoting {
 
 namespace {
 
-// This is used for tagging system event logs.
-const char kApplicationName[] = "chromoting";
-
 const char* kAttrNameAccessCode = "accessCode";
 const char* kAttrNameAccessCodeLifetime = "accessCodeLifetime";
 const char* kAttrNameClient = "client";
@@ -86,558 +69,11 @@
 const char* kAttrNameError = "ERROR";
 const char* kAttrNameInvalidDomainError = "INVALID_DOMAIN_ERROR";
 
-const int kMaxLoginAttempts = 5;
-
 // Space separated list of features supported in addition to the base protocol.
 const char* kSupportedFeatures = "pairingRegistry";
 
 }  // namespace
 
-// Internal implementation of the plugin's It2Me host function.
-class HostNPScriptObject::It2MeImpl
-    : public base::RefCountedThreadSafe<It2MeImpl>,
-      public HostStatusObserver {
- public:
-  It2MeImpl(
-      scoped_ptr<ChromotingHostContext> context,
-      scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
-      base::WeakPtr<HostNPScriptObject> script_object,
-      const XmppSignalStrategy::XmppServerConfig& xmpp_server_config,
-      const std::string& directory_bot_jid);
-
-  // Methods called by the script object, from the plugin thread.
-
-  // Creates It2Me host structures and starts the host.
-  void Connect();
-
-  // Disconnects the host, ready for tear-down.
-  // Also called internally, from the network thread.
-  void Disconnect();
-
-  // Request a NAT policy notification.
-  void RequestNatPolicy();
-
-  // remoting::HostStatusObserver implementation.
-  virtual void OnAccessDenied(const std::string& jid) OVERRIDE;
-  virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE;
-  virtual void OnClientDisconnected(const std::string& jid) OVERRIDE;
-
- private:
-  friend class base::RefCountedThreadSafe<It2MeImpl>;
-
-  virtual ~It2MeImpl();
-
-  // Updates state of the host. Can be called only on the network thread.
-  void SetState(State state);
-
-  // Returns true if the host is connected.
-  bool IsConnected() const;
-
-  // Called by Connect() to check for policies and start connection process.
-  void ReadPolicyAndConnect();
-
-  // Called by ReadPolicyAndConnect once policies have been read.
-  void FinishConnect();
-
-  // Called when the support host registration completes.
-  void OnReceivedSupportID(bool success,
-                           const std::string& support_id,
-                           const base::TimeDelta& lifetime);
-
-  // Shuts down |host_| on the network thread and posts ShutdownOnUiThread()
-  // to shut down UI thread resources.
-  void ShutdownOnNetworkThread();
-
-  // Shuts down |desktop_environment_factory_| and |policy_watcher_| on
-  // the UI thread.
-  void ShutdownOnUiThread();
-
-  // Called when initial policies are read, and when they change.
-  void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
-
-  // Handlers for NAT traversal and host domain policies.
-  void UpdateNatPolicy(bool nat_traversal_enabled);
-  void UpdateHostDomainPolicy(const std::string& host_domain);
-
-  // Caller supplied fields.
-  scoped_ptr<ChromotingHostContext> host_context_;
-  scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner_;
-  base::WeakPtr<HostNPScriptObject> script_object_;
-  XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
-  std::string directory_bot_jid_;
-
-  State state_;
-
-  scoped_refptr<RsaKeyPair> host_key_pair_;
-  scoped_ptr<SignalStrategy> signal_strategy_;
-  scoped_ptr<RegisterSupportHostRequest> register_request_;
-  scoped_ptr<LogToServer> log_to_server_;
-  scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
-  scoped_ptr<HostEventLogger> host_event_logger_;
-
-  scoped_ptr<ChromotingHost> host_;
-  int failed_login_attempts_;
-
-  scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
-
-  // Host the current nat traversal policy setting.
-  bool nat_traversal_enabled_;
-
-  // The host domain policy setting.
-  std::string required_host_domain_;
-
-  // Indicates whether or not a policy has ever been read. This is to ensure
-  // that on startup, we do not accidentally start a connection before we have
-  // queried our policy restrictions.
-  bool policy_received_;
-
-  // On startup, it is possible to have Connect() called before the policy read
-  // is completed.  Rather than just failing, we thunk the connection call so
-  // it can be executed after at least one successful policy read. This
-  // variable contains the thunk if it is necessary.
-  base::Closure pending_connect_;
-
-  DISALLOW_COPY_AND_ASSIGN(It2MeImpl);
-};
-
-HostNPScriptObject::It2MeImpl::It2MeImpl(
-    scoped_ptr<ChromotingHostContext> host_context,
-    scoped_refptr<base::SingleThreadTaskRunner> plugin_task_runner,
-    base::WeakPtr<HostNPScriptObject> script_object,
-    const XmppSignalStrategy::XmppServerConfig& xmpp_server_config,
-    const std::string& directory_bot_jid)
-  : host_context_(host_context.Pass()),
-    plugin_task_runner_(plugin_task_runner),
-    script_object_(script_object),
-    xmpp_server_config_(xmpp_server_config),
-    directory_bot_jid_(directory_bot_jid),
-    state_(kDisconnected),
-    failed_login_attempts_(0),
-    nat_traversal_enabled_(false),
-    policy_received_(false) {
-  DCHECK(plugin_task_runner_->BelongsToCurrentThread());
-}
-
-void HostNPScriptObject::It2MeImpl::Connect() {
-  if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
-    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
-    host_context_->ui_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&It2MeImpl::Connect, this));
-    return;
-  }
-
-  desktop_environment_factory_.reset(new It2MeDesktopEnvironmentFactory(
-      host_context_->network_task_runner(),
-      host_context_->input_task_runner(),
-      host_context_->ui_task_runner()));
-
-  // Start monitoring configured policies.
-  policy_watcher_.reset(
-      policy_hack::PolicyWatcher::Create(host_context_->network_task_runner()));
-  policy_watcher_->StartWatching(
-      base::Bind(&It2MeImpl::OnPolicyUpdate, this));
-
-  // Switch to the network thread to start the actual connection.
-  host_context_->network_task_runner()->PostTask(
-      FROM_HERE, base::Bind(&It2MeImpl::ReadPolicyAndConnect, this));
-}
-
-void HostNPScriptObject::It2MeImpl::Disconnect() {
-  if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
-    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
-    host_context_->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&It2MeImpl::Disconnect, this));
-    return;
-  }
-
-  switch (state_) {
-    case kDisconnected:
-      ShutdownOnNetworkThread();
-      return;
-
-    case kStarting:
-      SetState(kDisconnecting);
-      SetState(kDisconnected);
-      ShutdownOnNetworkThread();
-      return;
-
-    case kDisconnecting:
-      return;
-
-    default:
-      SetState(kDisconnecting);
-
-      if (!host_) {
-        SetState(kDisconnected);
-        ShutdownOnNetworkThread();
-        return;
-      }
-
-      // Deleting the host destroys SignalStrategy synchronously, but
-      // SignalStrategy::Listener handlers are not allowed to destroy
-      // SignalStrategy, so post task to destroy the host later.
-      host_context_->network_task_runner()->PostTask(
-          FROM_HERE, base::Bind(&It2MeImpl::ShutdownOnNetworkThread, this));
-      return;
-  }
-}
-
-void HostNPScriptObject::It2MeImpl::RequestNatPolicy() {
-  if (!host_context_->network_task_runner()->BelongsToCurrentThread()) {
-    DCHECK(plugin_task_runner_->BelongsToCurrentThread());
-    host_context_->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&It2MeImpl::RequestNatPolicy, this));
-    return;
-  }
-
-  if (policy_received_)
-    UpdateNatPolicy(nat_traversal_enabled_);
-}
-
-void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect() {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  SetState(kStarting);
-
-  // Only proceed to FinishConnect() if at least one policy update has been
-  // received.
-  if (policy_received_) {
-    FinishConnect();
-  } else {
-    // Otherwise, create the policy watcher, and thunk the connect.
-    pending_connect_ =
-        base::Bind(&It2MeImpl::FinishConnect, this);
-  }
-}
-
-void HostNPScriptObject::It2MeImpl::FinishConnect() {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  if (state_ != kStarting) {
-    // Host has been stopped while we were fetching policy.
-    return;
-  }
-
-  // Check the host domain policy.
-  if (!required_host_domain_.empty() &&
-      !EndsWith(xmpp_server_config_.username,
-                std::string("@") + required_host_domain_, false)) {
-    SetState(kInvalidDomainError);
-    return;
-  }
-
-  // Generate a key pair for the Host to use.
-  // TODO(wez): Move this to the worker thread.
-  host_key_pair_ = RsaKeyPair::Generate();
-
-  // Create XMPP connection.
-  scoped_ptr<SignalStrategy> signal_strategy(
-      new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
-                             host_context_->url_request_context_getter(),
-                             xmpp_server_config_));
-
-  // Request registration of the host for support.
-  scoped_ptr<RegisterSupportHostRequest> register_request(
-      new RegisterSupportHostRequest(
-          signal_strategy.get(), host_key_pair_, directory_bot_jid_,
-          base::Bind(&It2MeImpl::OnReceivedSupportID,
-                     base::Unretained(this))));
-
-  // Beyond this point nothing can fail, so save the config and request.
-  signal_strategy_ = signal_strategy.Pass();
-  register_request_ = register_request.Pass();
-
-  // If NAT traversal is off then limit port range to allow firewall pin-holing.
-  LOG(INFO) << "NAT state: " << nat_traversal_enabled_;
-  NetworkSettings network_settings(
-     nat_traversal_enabled_ ?
-     NetworkSettings::NAT_TRAVERSAL_ENABLED :
-     NetworkSettings::NAT_TRAVERSAL_DISABLED);
-  if (!nat_traversal_enabled_) {
-    network_settings.min_port = NetworkSettings::kDefaultMinPort;
-    network_settings.max_port = NetworkSettings::kDefaultMaxPort;
-  }
-
-  // Create the host.
-  host_.reset(new ChromotingHost(
-      signal_strategy_.get(),
-      desktop_environment_factory_.get(),
-      CreateHostSessionManager(network_settings,
-                               host_context_->url_request_context_getter()),
-      host_context_->audio_task_runner(),
-      host_context_->input_task_runner(),
-      host_context_->video_capture_task_runner(),
-      host_context_->video_encode_task_runner(),
-      host_context_->network_task_runner(),
-      host_context_->ui_task_runner()));
-  host_->AddStatusObserver(this);
-  log_to_server_.reset(
-      new LogToServer(host_->AsWeakPtr(), ServerLogEntry::IT2ME,
-                      signal_strategy_.get(), directory_bot_jid_));
-
-  // Disable audio by default.
-  // TODO(sergeyu): Add UI to enable it.
-  scoped_ptr<protocol::CandidateSessionConfig> protocol_config =
-      protocol::CandidateSessionConfig::CreateDefault();
-  protocol::CandidateSessionConfig::DisableAudioChannel(protocol_config.get());
-
-  // VP9 encode is not yet supported.
-  protocol::CandidateSessionConfig::DisableVideoCodec(
-      protocol_config.get(), protocol::ChannelConfig::CODEC_VP9);
-
-  host_->set_protocol_config(protocol_config.Pass());
-
-  // Create event logger.
-  host_event_logger_ =
-      HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
-
-  // Connect signaling and start the host.
-  signal_strategy_->Connect();
-  host_->Start(xmpp_server_config_.username);
-
-  SetState(kRequestedAccessCode);
-  return;
-}
-
-void HostNPScriptObject::It2MeImpl::ShutdownOnNetworkThread() {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-  DCHECK(state_ == kDisconnecting || state_ == kDisconnected);
-
-  if (state_ == kDisconnecting) {
-    host_event_logger_.reset();
-    host_->RemoveStatusObserver(this);
-    host_.reset();
-
-    register_request_.reset();
-    log_to_server_.reset();
-    signal_strategy_.reset();
-    SetState(kDisconnected);
-  }
-
-  host_context_->ui_task_runner()->PostTask(
-      FROM_HERE, base::Bind(&It2MeImpl::ShutdownOnUiThread, this));
-}
-
-void HostNPScriptObject::It2MeImpl::ShutdownOnUiThread() {
-  DCHECK(host_context_->ui_task_runner()->BelongsToCurrentThread());
-
-  // Destroy the DesktopEnvironmentFactory, to free thread references.
-  desktop_environment_factory_.reset();
-
-  // Stop listening for policy updates.
-  if (policy_watcher_.get()) {
-    base::WaitableEvent policy_watcher_stopped_(true, false);
-    policy_watcher_->StopWatching(&policy_watcher_stopped_);
-    policy_watcher_stopped_.Wait();
-    policy_watcher_.reset();
-  }
-}
-
-void HostNPScriptObject::It2MeImpl::OnAccessDenied(const std::string& jid) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  ++failed_login_attempts_;
-  if (failed_login_attempts_ == kMaxLoginAttempts) {
-    Disconnect();
-  }
-}
-
-void HostNPScriptObject::It2MeImpl::OnClientAuthenticated(
-    const std::string& jid) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  if (state_ == kDisconnecting) {
-    // Ignore the new connection if we are disconnecting.
-    return;
-  }
-  if (state_ == kConnected) {
-    // If we already connected another client then one of the connections may be
-    // an attacker, so both are suspect and we have to reject the second
-    // connection and shutdown the host.
-    host_->RejectAuthenticatingClient();
-    Disconnect();
-    return;
-  }
-
-  std::string client_username = jid;
-  size_t pos = client_username.find('/');
-  if (pos != std::string::npos)
-    client_username.replace(pos, std::string::npos, "");
-
-  LOG(INFO) << "Client " << client_username << " connected.";
-
-  // Pass the client user name to the script object before changing state.
-  plugin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&HostNPScriptObject::StoreClientUsername,
-                            script_object_, client_username));
-
-  SetState(kConnected);
-}
-
-void HostNPScriptObject::It2MeImpl::OnClientDisconnected(
-    const std::string& jid) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  // Pass the client user name to the script object before changing state.
-  plugin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&HostNPScriptObject::StoreClientUsername,
-                            script_object_, std::string()));
-
-  Disconnect();
-}
-
-void HostNPScriptObject::It2MeImpl::OnPolicyUpdate(
-    scoped_ptr<base::DictionaryValue> policies) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  bool nat_policy;
-  if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
-                           &nat_policy)) {
-    UpdateNatPolicy(nat_policy);
-  }
-  std::string host_domain;
-  if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
-                          &host_domain)) {
-    UpdateHostDomainPolicy(host_domain);
-  }
-
-  policy_received_ = true;
-
-  if (!pending_connect_.is_null()) {
-    pending_connect_.Run();
-    pending_connect_.Reset();
-  }
-}
-
-void HostNPScriptObject::It2MeImpl::UpdateNatPolicy(
-    bool nat_traversal_enabled) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled;
-
-  // When transitioning from enabled to disabled, force disconnect any
-  // existing session.
-  if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) {
-    Disconnect();
-  }
-
-  nat_traversal_enabled_ = nat_traversal_enabled;
-
-  // Notify the web-app of the policy setting.
-  plugin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&HostNPScriptObject::NotifyNatPolicyChanged,
-                            script_object_, nat_traversal_enabled_));
-}
-
-void HostNPScriptObject::It2MeImpl::UpdateHostDomainPolicy(
-    const std::string& host_domain) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  VLOG(2) << "UpdateHostDomainPolicy: " << host_domain;
-
-  // When setting a host domain policy, force disconnect any existing session.
-  if (!host_domain.empty() && IsConnected()) {
-    Disconnect();
-  }
-
-  required_host_domain_ = host_domain;
-}
-
-HostNPScriptObject::It2MeImpl::~It2MeImpl() {
-  // Check that resources that need to be torn down on the UI thread are gone.
-  DCHECK(!desktop_environment_factory_.get());
-  DCHECK(!policy_watcher_.get());
-}
-
-void HostNPScriptObject::It2MeImpl::SetState(State state) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  switch (state_) {
-    case kDisconnected:
-      DCHECK(state == kStarting ||
-             state == kError) << state;
-      break;
-    case kStarting:
-      DCHECK(state == kRequestedAccessCode ||
-             state == kDisconnecting ||
-             state == kError ||
-             state == kInvalidDomainError) << state;
-      break;
-    case kRequestedAccessCode:
-      DCHECK(state == kReceivedAccessCode ||
-             state == kDisconnecting ||
-             state == kError) << state;
-      break;
-    case kReceivedAccessCode:
-      DCHECK(state == kConnected ||
-             state == kDisconnecting ||
-             state == kError) << state;
-      break;
-    case kConnected:
-      DCHECK(state == kDisconnecting ||
-             state == kDisconnected ||
-             state == kError) << state;
-      break;
-    case kDisconnecting:
-      DCHECK(state == kDisconnected) << state;
-      break;
-    case kError:
-      DCHECK(state == kDisconnecting) << state;
-      break;
-    case kInvalidDomainError:
-      DCHECK(state == kDisconnecting) << state;
-      break;
-  };
-
-  state_ = state;
-
-  // Post a state-change notification to the web-app.
-  plugin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&HostNPScriptObject::NotifyStateChanged,
-                            script_object_, state));
-}
-
-bool HostNPScriptObject::It2MeImpl::IsConnected() const {
-  return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode ||
-      state_ == kConnected;
-}
-
-void HostNPScriptObject::It2MeImpl::OnReceivedSupportID(
-    bool success,
-    const std::string& support_id,
-    const base::TimeDelta& lifetime) {
-  DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
-
-  if (!success) {
-    SetState(kError);
-    Disconnect();
-    return;
-  }
-
-  std::string host_secret = GenerateSupportHostSecret();
-  std::string access_code = support_id + host_secret;
-
-  std::string local_certificate = host_key_pair_->GenerateCertificate();
-  if (local_certificate.empty()) {
-    LOG(ERROR) << "Failed to generate host certificate.";
-    SetState(kError);
-    Disconnect();
-    return;
-  }
-
-  scoped_ptr<protocol::AuthenticatorFactory> factory(
-      new protocol::It2MeHostAuthenticatorFactory(
-          local_certificate, host_key_pair_, access_code));
-  host_->SetAuthenticatorFactory(factory.Pass());
-
-  // Pass the Access Code to the script object before changing state.
-  plugin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&HostNPScriptObject::StoreAccessCode,
-                            script_object_, access_code, lifetime));
-
-  SetState(kReceivedAccessCode);
-}
-
 HostNPScriptObject::HostNPScriptObject(
     NPP plugin,
     NPObject* parent,
@@ -1426,11 +862,14 @@
   return true;
 }
 
-void HostNPScriptObject::NotifyStateChanged(State state) {
+void HostNPScriptObject::OnStateChanged(It2MeHostState state) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
   state_ = state;
 
+  if (state_ == kDisconnected)
+    client_username_.clear();
+
   if (on_state_changed_func_.get()) {
     NPVariant state_var;
     INT32_TO_NPVARIANT(state, state_var);
@@ -1438,7 +877,7 @@
   }
 }
 
-void HostNPScriptObject::NotifyNatPolicyChanged(bool nat_traversal_enabled) {
+void HostNPScriptObject::OnNatPolicyChanged(bool nat_traversal_enabled) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
   if (on_nat_traversal_policy_changed_func_.get()) {
@@ -1450,8 +889,8 @@
 }
 
 // Stores the Access Code for the web-app to query.
-void HostNPScriptObject::StoreAccessCode(const std::string& access_code,
-                                         base::TimeDelta access_code_lifetime) {
+void HostNPScriptObject::OnStoreAccessCode(
+    const std::string& access_code, base::TimeDelta access_code_lifetime) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
   access_code_ = access_code;
@@ -1459,7 +898,7 @@
 }
 
 // Stores the client user's name for the web-app to query.
-void HostNPScriptObject::StoreClientUsername(
+void HostNPScriptObject::OnClientAuthenticated(
     const std::string& client_username) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
diff --git a/remoting/host/plugin/host_script_object.h b/remoting/host/plugin/host_script_object.h
index 91b9a0d..74abcd9 100644
--- a/remoting/host/plugin/host_script_object.h
+++ b/remoting/host/plugin/host_script_object.h
@@ -8,28 +8,16 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "base/synchronization/cancellation_flag.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
 #include "base/thread_task_runner_handle.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "remoting/base/auto_thread_task_runner.h"
-#include "remoting/host/chromoting_host_context.h"
-#include "remoting/host/log_to_server.h"
+#include "remoting/host/it2me/it2me_impl.h"
 #include "remoting/host/plugin/host_plugin_utils.h"
 #include "remoting/host/setup/daemon_controller.h"
 #include "remoting/jingle_glue/xmpp_signal_strategy.h"
 #include "remoting/protocol/pairing_registry.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npfunctions.h"
-#include "third_party/npapi/bindings/npruntime.h"
 
 namespace remoting {
 
@@ -37,7 +25,7 @@
 // HostNPScriptObject creates threads that are required to run
 // ChromotingHost and starts/stops the host on those threads. When
 // destroyed it synchronously shuts down the host and all threads.
-class HostNPScriptObject {
+class HostNPScriptObject : public It2MeImpl::Observer {
  public:
   HostNPScriptObject(NPP plugin,
                      NPObject* parent,
@@ -68,24 +56,6 @@
 
  private:
   //////////////////////////////////////////////////////////
-  // Definitions for It2Me host.
-
-  class It2MeImpl;
-
-  // These state values are duplicated in host_session.js. Remember to update
-  // both copies when making changes.
-  enum State {
-    kDisconnected,
-    kStarting,
-    kRequestedAccessCode,
-    kReceivedAccessCode,
-    kConnected,
-    kDisconnecting,
-    kError,
-    kInvalidDomainError
-  };
-
-  //////////////////////////////////////////////////////////
   // Plugin methods for It2Me host.
 
   // Start connection. args are:
@@ -187,21 +157,22 @@
   bool StopDaemon(const NPVariant* args, uint32_t arg_count, NPVariant* result);
 
   //////////////////////////////////////////////////////////
-  // Helper methods used by the It2Me host implementation.
+  // Implementation of It2MeImpl::Observer methods.
 
   // Notifies OnStateChanged handler of a state change.
-  void NotifyStateChanged(State state);
+  virtual void OnStateChanged(It2MeHostState state) OVERRIDE;
 
   // If the web-app has registered a callback to be notified of changes to the
   // NAT traversal policy, notify it.
-  void NotifyNatPolicyChanged(bool nat_traversal_enabled);
+  virtual void OnNatPolicyChanged(bool nat_traversal_enabled) OVERRIDE;
 
   // Stores the Access Code for the web-app to query.
-  void StoreAccessCode(const std::string& access_code,
-                       base::TimeDelta access_code_lifetime);
+  virtual void OnStoreAccessCode(const std::string& access_code,
+                                 base::TimeDelta access_code_lifetime) OVERRIDE;
 
   // Stores the client user's name for the web-app to query.
-  void StoreClientUsername(const std::string& client_username);
+  virtual void OnClientAuthenticated(
+      const std::string& client_username) OVERRIDE;
 
   // Used to generate localized strings to pass to the It2Me host core.
   void LocalizeStrings(NPObject* localize_func);
@@ -298,7 +269,7 @@
   scoped_refptr<It2MeImpl> it2me_impl_;
 
   // Cached, read-only copies of |it2me_impl_| session state.
-  State state_;
+  It2MeHostState state_;
   std::string access_code_;
   base::TimeDelta access_code_lifetime_;
   std::string client_username_;
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index d32f837..a100022 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -639,8 +639,9 @@
             'remoting_host',
             'remoting_host_event_logger',
             'remoting_host_logging',
-            'remoting_infoplist_strings',
             'remoting_host_setup_base',
+            'remoting_infoplist_strings',
+            'remoting_it2me_host_static',
             'remoting_jingle_glue',
             'remoting_resources',
           ],
@@ -731,6 +732,27 @@
           ],
         },  # end of target 'remoting_host_plugin'
         {
+          'target_name': 'remoting_it2me_host_static',
+          'type': 'static_library',
+          'variables': { 'enable_wexit_time_destructors': 1, },
+          'dependencies': [
+            '../base/base.gyp:base_i18n',
+            '../net/net.gyp:net',
+            'remoting_base',
+            'remoting_host',
+            'remoting_host_event_logger',
+            'remoting_host_logging',
+            'remoting_infoplist_strings',
+            'remoting_host_setup_base',
+            'remoting_jingle_glue',
+            'remoting_resources',
+          ],
+          'sources': [
+            'host/it2me/it2me_impl.cc',
+            'host/it2me/it2me_impl.h',
+          ],
+        },  # end of target 'remoting_it2me_host_static'
+        {
           'target_name': 'remoting_infoplist_strings',
           'type': 'none',
           'dependencies': [
@@ -1799,25 +1821,40 @@
     ['OS=="android"', {
       'targets': [
         {
+          'target_name': 'remoting_jni_headers',
+          'type': 'none',
+          'sources': [
+            'android/java/src/org/chromium/chromoting/jni/JniInterface.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'remoting',
+          },
+          'includes': [ '../build/jni_generator.gypi' ],
+        },  # end of target 'remoting_jni_headers'
+        {
           'target_name': 'remoting_client_jni',
           'type': 'shared_library',
           'dependencies': [
             'remoting_base',
             'remoting_client',
             'remoting_jingle_glue',
+            'remoting_jni_headers',
             'remoting_protocol',
             '../google_apis/google_apis.gyp:google_apis',
           ],
+          'include_dirs': [
+            '<(SHARED_INTERMEDIATE_DIR)/remoting',
+          ],
           'sources': [
             'client/jni/android_keymap.cc',
             'client/jni/android_keymap.h',
             'client/jni/chromoting_jni_instance.cc',
             'client/jni/chromoting_jni_instance.h',
+            'client/jni/chromoting_jni_onload.cc',
             'client/jni/chromoting_jni_runtime.cc',
             'client/jni/chromoting_jni_runtime.h',
             'client/jni/jni_frame_consumer.cc',
             'client/jni/jni_frame_consumer.h',
-            'client/jni/jni_interface.cc',
           ],
         },  # end of target 'remoting_client_jni'
         {
@@ -1871,10 +1908,6 @@
             'java_in_dir': 'android/java',
             'additional_res_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/remoting/android/res' ],
             'additional_input_paths': [
-              'android/java/src/org/chromium/chromoting/Chromoting.java',
-              'android/java/src/org/chromium/chromoting/Desktop.java',
-              'android/java/src/org/chromium/chromoting/DesktopView.java',
-              'android/java/src/org/chromium/chromoting/jni/JniInterface.java',
               '<(PRODUCT_DIR)/obj/remoting/remoting_android_resources.actions_rules_copies.stamp',
             ],
           },
diff --git a/remoting/webapp/paired_client_manager.js b/remoting/webapp/paired_client_manager.js
index 05d6fe9..d001cf3 100644
--- a/remoting/webapp/paired_client_manager.js
+++ b/remoting/webapp/paired_client_manager.js
@@ -57,6 +57,7 @@
   this.deleteButton.href = '#';
   this.deleteButton.innerText = chrome.i18n.getMessage(
       /*i18n-content*/'DELETE_PAIRED_CLIENT');
+  this.deleteButton.id = 'delete-client-' + this.clientId;
   this.deleteButton.addEventListener(
       'click',
       parent.deletePairedClient.bind(parent, this),
@@ -270,6 +271,17 @@
   this.pairedClients_ = [];
 };
 
+/**
+ * Get the id of the first paired client for testing.
+ *
+ * @private
+ * @return {string} The client id of the first paired client in the list.
+ */
+remoting.PairedClientManager.prototype.getFirstClientIdForTesting_ =
+    function() {
+  return this.pairedClients_.length > 0 ? this.pairedClients_[0].clientId : '';
+};
+
 
 /** @type {remoting.PairedClientManager} */
 remoting.pairedClientManager = null;
diff --git a/rlz/ios/lib/machine_id_ios.cc b/rlz/ios/lib/machine_id_ios.cc
new file mode 100644
index 0000000..3440978
--- /dev/null
+++ b/rlz/ios/lib/machine_id_ios.cc
@@ -0,0 +1,17 @@
+// Copyright 2013 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/ios/device_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace rlz_lib {
+
+bool GetRawMachineId(string16* data, int* more_data) {
+  *data = ASCIIToUTF16(ios::device_util::GetDeviceIdentifier(NULL));
+  *more_data = 1;
+  return true;
+}
+
+}  // namespace rlz_lib
diff --git a/rlz/lib/lib_values.cc b/rlz/lib/lib_values.cc
index c4ef460..8874a29 100644
--- a/rlz/lib/lib_values.cc
+++ b/rlz/lib/lib_values.cc
@@ -98,8 +98,8 @@
   case CHROMEOS_OMNIBOX:              return "CA";
   case CHROMEOS_HOME_PAGE:            return "CB";
   case CHROMEOS_RESERVED:             return "CC";
-  case UNDEFINED_AP_M:                return "RM";
-  case UNDEFINED_AP_N:                return "RN";
+  case CHROME_IOS_OMNIBOX:            return "RM";
+  case CHROME_IOS_HOME_PAGE:          return "RN";
   case UNDEFINED_AP_O:                return "RO";
   case UNDEFINED_AP_P:                return "RP";
   case UNDEFINED_AP_Q:                return "RQ";
diff --git a/rlz/lib/rlz_enums.h b/rlz/lib/rlz_enums.h
index 0fd0513..08d8bbb 100644
--- a/rlz/lib/rlz_enums.h
+++ b/rlz/lib/rlz_enums.h
@@ -62,11 +62,12 @@
   CHROMEOS_HOME_PAGE,  // ChromeOS searches through Google as home page.
   CHROMEOS_RESERVED,   // Reserved for ChromeOS.
 
+  CHROME_IOS_OMNIBOX,  // Chrome searches through the address bar omnibox (iOS).
+  CHROME_IOS_HOME_PAGE,// Chrome searches through Google as home page (iOS).
+
   // Unclaimed access points - should be used first before creating new APs.
   // Please also make sure you re-name the enum before using an unclaimed value;
   // this acts as a check to ensure we don't have collisions.
-  UNDEFINED_AP_M,
-  UNDEFINED_AP_N,
   UNDEFINED_AP_O,
   UNDEFINED_AP_P,
   UNDEFINED_AP_Q,
diff --git a/rlz/rlz.gyp b/rlz/rlz.gyp
index c38c4ff..1863705 100644
--- a/rlz/rlz.gyp
+++ b/rlz/rlz.gyp
@@ -34,6 +34,7 @@
         'chromeos/lib/machine_id_chromeos.cc',
         'chromeos/lib/rlz_value_store_chromeos.cc',
         'chromeos/lib/rlz_value_store_chromeos.h',
+        'ios/lib/machine_id_ios.cc',
         'lib/assert.cc',
         'lib/assert.h',
         'lib/crc32.h',
@@ -97,6 +98,15 @@
           },
         }],
       ],
+      'target_conditions': [
+        # Need 'target_conditions' to override default filename_rules to include
+        # the files on iOS.
+        ['OS=="ios"', {
+          'sources/': [
+            ['include', '^mac/lib/rlz_value_store_mac\\.'],
+          ],
+        }],
+      ],
       # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, ],
     },
diff --git a/sandbox/linux/suid/common/sandbox.h b/sandbox/linux/suid/common/sandbox.h
index aad4ff8..9345287 100644
--- a/sandbox/linux/suid/common/sandbox.h
+++ b/sandbox/linux/suid/common/sandbox.h
@@ -12,9 +12,6 @@
 // These are command line switches that may be used by other programs
 // (e.g. Chrome) to construct a command line for the sandbox.
 static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
-#if defined(OS_CHROMEOS)
-static const char kAdjustLowMemMarginSwitch[] = "--adjust-low-mem";
-#endif
 
 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
diff --git a/sandbox/linux/suid/process_util_linux.c b/sandbox/linux/suid/process_util_linux.c
index 5e6b33b..78c27ef 100644
--- a/sandbox/linux/suid/process_util_linux.c
+++ b/sandbox/linux/suid/process_util_linux.c
@@ -24,10 +24,6 @@
 static const int kMaxOomScore = 1000;
 static const int kMaxOldOomScore = 15;
 
-// Kernel pseudo-file that allows setting of the low memory margin.
-static const char kLowMemMarginFile[] =
-    "/sys/kernel/mm/chromeos-low_mem/margin";
-
 // NOTE: This is not the only version of this function in the source:
 // the base library (in process_util_linux.cc) also has its own C++ version.
 bool AdjustOOMScore(pid_t process, int score) {
@@ -77,30 +73,3 @@
   close(fd);
   return (bytes_written == len);
 }
-
-bool AdjustLowMemoryMargin(int64_t margin_mb) {
-  int file_descriptor = open(kLowMemMarginFile, O_WRONLY);
-  if (file_descriptor < 0)
-    return false;
-
-  // Only allow those values which are reasonable, to prevent mischief.
-  char value[21];
-  switch (margin_mb) {
-    case -1L:
-      snprintf(value, sizeof(value), "off");
-      break;
-    case 0L:
-    case 25L:
-    case 50L:
-    case 100L:
-    case 200L:
-      snprintf(value, sizeof(value), "%lld", (long long int)margin_mb);
-      break;
-    default:
-      return false;
-  }
-
-  bool success = (write(file_descriptor, value, strlen(value)) >= 0);
-  close(file_descriptor);
-  return success;
-}
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
index 32435a7..a161e19 100644
--- a/sandbox/linux/suid/sandbox.c
+++ b/sandbox/linux/suid/sandbox.c
@@ -450,16 +450,6 @@
       return 1;
     return AdjustOOMScore(pid, score);
   }
-#if defined(OS_CHROMEOS)
-  if (argc == 3 && (0 == strcmp(argv[1], kAdjustLowMemMarginSwitch))) {
-    char* endptr = NULL;
-    errno = 0;
-    unsigned long margin_mb = strtoul(argv[2], &endptr, 10);
-    if (!endptr || *endptr || errno != 0)
-      return 1;
-    return AdjustLowMemoryMargin(margin_mb);
-  }
-#endif
 
   // Protect the core setuid sandbox functionality with an API version
   if (!CheckAndExportApiVersion()) {
diff --git a/sandbox/sandbox_services.target.darwin-arm.mk b/sandbox/sandbox_services.target.darwin-arm.mk
index 236dc9d..48e606a 100644
--- a/sandbox/sandbox_services.target.darwin-arm.mk
+++ b/sandbox/sandbox_services.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services.target.darwin-mips.mk b/sandbox/sandbox_services.target.darwin-mips.mk
index b909d1a..4b72b57 100644
--- a/sandbox/sandbox_services.target.darwin-mips.mk
+++ b/sandbox/sandbox_services.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services.target.darwin-x86.mk b/sandbox/sandbox_services.target.darwin-x86.mk
index 4ef19f6..5ee4316 100644
--- a/sandbox/sandbox_services.target.darwin-x86.mk
+++ b/sandbox/sandbox_services.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services.target.linux-arm.mk b/sandbox/sandbox_services.target.linux-arm.mk
index 236dc9d..48e606a 100644
--- a/sandbox/sandbox_services.target.linux-arm.mk
+++ b/sandbox/sandbox_services.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -144,13 +144,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services.target.linux-mips.mk b/sandbox/sandbox_services.target.linux-mips.mk
index b909d1a..4b72b57 100644
--- a/sandbox/sandbox_services.target.linux-mips.mk
+++ b/sandbox/sandbox_services.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -142,13 +142,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services.target.linux-x86.mk b/sandbox/sandbox_services.target.linux-x86.mk
index 4ef19f6..5ee4316 100644
--- a/sandbox/sandbox_services.target.linux-x86.mk
+++ b/sandbox/sandbox_services.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services_headers.target.darwin-arm.mk b/sandbox/sandbox_services_headers.target.darwin-arm.mk
index cf0d956..c98bec3 100644
--- a/sandbox/sandbox_services_headers.target.darwin-arm.mk
+++ b/sandbox/sandbox_services_headers.target.darwin-arm.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services_headers.target.darwin-x86.mk b/sandbox/sandbox_services_headers.target.darwin-x86.mk
index 06425c6..5d24e9e 100644
--- a/sandbox/sandbox_services_headers.target.darwin-x86.mk
+++ b/sandbox/sandbox_services_headers.target.darwin-x86.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services_headers.target.linux-arm.mk b/sandbox/sandbox_services_headers.target.linux-arm.mk
index cf0d956..c98bec3 100644
--- a/sandbox/sandbox_services_headers.target.linux-arm.mk
+++ b/sandbox/sandbox_services_headers.target.linux-arm.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/sandbox_services_headers.target.linux-x86.mk b/sandbox/sandbox_services_headers.target.linux-x86.mk
index 06425c6..5d24e9e 100644
--- a/sandbox/sandbox_services_headers.target.linux-x86.mk
+++ b/sandbox/sandbox_services_headers.target.linux-x86.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/seccomp_bpf.target.darwin-arm.mk b/sandbox/seccomp_bpf.target.darwin-arm.mk
index 9e27cc9..3777c9d 100644
--- a/sandbox/seccomp_bpf.target.darwin-arm.mk
+++ b/sandbox/seccomp_bpf.target.darwin-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/seccomp_bpf.target.darwin-x86.mk b/sandbox/seccomp_bpf.target.darwin-x86.mk
index bb32741..037dd95 100644
--- a/sandbox/seccomp_bpf.target.darwin-x86.mk
+++ b/sandbox/seccomp_bpf.target.darwin-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/seccomp_bpf.target.linux-arm.mk b/sandbox/seccomp_bpf.target.linux-arm.mk
index 9e27cc9..3777c9d 100644
--- a/sandbox/seccomp_bpf.target.linux-arm.mk
+++ b/sandbox/seccomp_bpf.target.linux-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/seccomp_bpf.target.linux-x86.mk b/sandbox/seccomp_bpf.target.linux-x86.mk
index bb32741..037dd95 100644
--- a/sandbox/seccomp_bpf.target.linux-x86.mk
+++ b/sandbox/seccomp_bpf.target.linux-x86.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h
index 2e6dc8d..43126d0 100644
--- a/sandbox/win/src/interceptors.h
+++ b/sandbox/win/src/interceptors.h
@@ -39,10 +39,8 @@
   OPEN_KEY_ID,
   OPEN_KEY_EX_ID,
   // Sync dispatcher:
-  CREATE_EVENTW_ID,
-  CREATE_EVENTA_ID,
-  OPEN_EVENTW_ID,
-  OPEN_EVENTA_ID,
+  CREATE_EVENT_ID,
+  OPEN_EVENT_ID,
   // CSRSS bypasses for HandleCloser:
   CREATE_THREAD_ID,
   GET_USER_DEFAULT_LCID_ID,
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
index a363732..c71d5a2 100644
--- a/sandbox/win/src/interceptors_64.cc
+++ b/sandbox/win/src/interceptors_64.cc
@@ -249,36 +249,23 @@
 
 // -----------------------------------------------------------------------
 
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW64(
-    LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset,
-    BOOL initial_state, LPCWSTR name) {
-  CreateEventWFunction orig_fn = reinterpret_cast<
-      CreateEventWFunction>(g_originals[CREATE_EVENTW_ID]);
-  return TargetCreateEventW(orig_fn, security_attributes, manual_reset,
-                            initial_state, name);
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type,
+    BOOLEAN initial_state) {
+  NtCreateEventFunction orig_fn = reinterpret_cast<
+      NtCreateEventFunction>(g_originals[CREATE_EVENT_ID]);
+  return TargetNtCreateEvent(orig_fn, event_handle, desired_access,
+                             object_attributes, event_type, initial_state);
 }
 
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA64(
-    LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset,
-    BOOL initial_state, LPCSTR name) {
-  CreateEventAFunction orig_fn = reinterpret_cast<
-      CreateEventAFunction>(g_originals[CREATE_EVENTA_ID]);
-  return TargetCreateEventA(orig_fn, security_attributes, manual_reset,
-                            initial_state, name);
-}
-
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW64(
-    DWORD desired_access, BOOL inherit_handle, LPCWSTR name) {
-  OpenEventWFunction orig_fn = reinterpret_cast<
-      OpenEventWFunction>(g_originals[OPEN_EVENTW_ID]);
-  return TargetOpenEventW(orig_fn, desired_access, inherit_handle, name);
-}
-
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA64(
-    DWORD desired_access, BOOL inherit_handle, LPCSTR name) {
-  OpenEventAFunction orig_fn = reinterpret_cast<
-      OpenEventAFunction>(g_originals[OPEN_EVENTA_ID]);
-  return TargetOpenEventA(orig_fn, desired_access, inherit_handle, name);
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes) {
+  NtOpenEventFunction orig_fn = reinterpret_cast<
+      NtOpenEventFunction>(g_originals[OPEN_EVENT_ID]);
+  return TargetNtOpenEvent(orig_fn, event_handle, desired_access,
+                           object_attributes);
 }
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
index 717fb6d..ef2c10d 100644
--- a/sandbox/win/src/interceptors_64.h
+++ b/sandbox/win/src/interceptors_64.h
@@ -153,23 +153,15 @@
 // -----------------------------------------------------------------------
 // Interceptors handled by the sync dispatcher.
 
-// Interception of CreateEventW on the child process.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW64(
-    LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset,
-    BOOL initial_state, LPCWSTR name);
+// Interception of NtCreateEvent/NtOpenEvent on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type,
+    BOOLEAN initial_state);
 
-// Interception of CreateEventA on the child process.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA64(
-    LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset,
-    BOOL initial_state, LPCSTR name);
-
-// Interception of OpenEventW on the child process.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW64(
-    DWORD desired_access, BOOL inherit_handle, LPCWSTR name);
-
-// Interception of OpenEventA on the child process.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA64(
-    DWORD desired_access, BOOL inherit_handle, LPCSTR name);
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
 
 }  // extern "C"
 
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index c9aaf92..1423be4 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -615,5 +615,31 @@
   IN OUT PUNICODE_STRING DestinationString,
   IN PCWSTR SourceString);
 
+typedef enum _EVENT_TYPE {
+  NotificationEvent,
+  SynchronizationEvent
+} EVENT_TYPE, *PEVENT_TYPE;
+
+typedef NTSTATUS (WINAPI* NtOpenDirectoryObjectFunction) (
+    PHANDLE DirectoryHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NtQuerySymbolicLinkObjectFunction) (
+    HANDLE LinkHandle,
+    PUNICODE_STRING LinkTarget,
+    PULONG ReturnedLength);
+
+typedef NTSTATUS (WINAPI* NtOpenSymbolicLinkObjectFunction) (
+    PHANDLE LinkHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+#define DIRECTORY_QUERY               0x0001
+#define DIRECTORY_TRAVERSE            0x0002
+#define DIRECTORY_CREATE_OBJECT       0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS          0x000F
+
 #endif  // SANDBOX_WIN_SRC_NT_INTERNALS_H__
 
diff --git a/sandbox/win/src/sync_dispatcher.cc b/sandbox/win/src/sync_dispatcher.cc
index 6897dac..3769fc6 100644
--- a/sandbox/win/src/sync_dispatcher.cc
+++ b/sandbox/win/src/sync_dispatcher.cc
@@ -25,7 +25,7 @@
   };
 
   static const IPCCall open_params = {
-    {IPC_OPENEVENT_TAG, WCHAR_TYPE, ULONG_TYPE, ULONG_TYPE},
+    {IPC_OPENEVENT_TAG, WCHAR_TYPE, ULONG_TYPE},
     reinterpret_cast<CallbackGeneric>(&SyncDispatcher::OpenEvent)
   };
 
@@ -35,33 +35,16 @@
 
 bool SyncDispatcher::SetupService(InterceptionManager* manager,
                                   int service) {
-  bool ret = false;
-  // We need to intercept kernelbase.dll on Windows 7 and beyond and
-  // kernel32.dll for earlier versions.
-  static const wchar_t* kWin32SyncDllName =
-      base::win::GetVersion() >= base::win::VERSION_WIN7 ? kKernelBasedllName :
-          kKerneldllName;
-
   if (IPC_CREATEEVENT_TAG == service) {
-    ret = INTERCEPT_EAT(manager, kWin32SyncDllName, CreateEventW,
-                        CREATE_EVENTW_ID, 20);
-    if (ret) {
-      ret = INTERCEPT_EAT(manager, kWin32SyncDllName, CreateEventA,
-                          CREATE_EVENTA_ID, 20);
-    }
+    return INTERCEPT_NT(manager, NtCreateEvent, CREATE_EVENT_ID, 24);
   } else if (IPC_OPENEVENT_TAG == service) {
-    ret = INTERCEPT_EAT(manager, kWin32SyncDllName, OpenEventW, OPEN_EVENTW_ID,
-                        16);
-    if (ret) {
-      ret = INTERCEPT_EAT(manager, kWin32SyncDllName, OpenEventA,
-                          OPEN_EVENTA_ID, 16);
-    }
+    return INTERCEPT_NT(manager, NtOpenEvent, OPEN_EVENT_ID, 16);
   }
-  return ret;
+  return false;
 }
 
 bool SyncDispatcher::CreateEvent(IPCInfo* ipc, std::wstring* name,
-                                 DWORD manual_reset, DWORD initial_state) {
+                                 DWORD event_type, DWORD initial_state) {
   const wchar_t* event_name = name->c_str();
   CountedParameterSet<NameBased> params;
   params[NameBased::NAME] = ParamPickerMake(event_name);
@@ -70,16 +53,16 @@
                                                params.GetBase());
   HANDLE handle = NULL;
   DWORD ret = SyncPolicy::CreateEventAction(result, *ipc->client_info, *name,
-                                            manual_reset, initial_state,
+                                            event_type, initial_state,
                                             &handle);
   // Return operation status on the IPC.
-  ipc->return_info.win32_result = ret;
+  ipc->return_info.nt_status = ret;
   ipc->return_info.handle = handle;
   return true;
 }
 
 bool SyncDispatcher::OpenEvent(IPCInfo* ipc, std::wstring* name,
-                               DWORD desired_access, DWORD inherit_handle) {
+                               DWORD desired_access) {
   const wchar_t* event_name = name->c_str();
 
   CountedParameterSet<OpenEventParams> params;
@@ -90,8 +73,7 @@
                                                params.GetBase());
   HANDLE handle = NULL;
   DWORD ret = SyncPolicy::OpenEventAction(result, *ipc->client_info, *name,
-                                          desired_access, inherit_handle,
-                                          &handle);
+                                          desired_access, &handle);
   // Return operation status on the IPC.
   ipc->return_info.win32_result = ret;
   ipc->return_info.handle = handle;
diff --git a/sandbox/win/src/sync_dispatcher.h b/sandbox/win/src/sync_dispatcher.h
index 13c8b9d..1d1b978 100644
--- a/sandbox/win/src/sync_dispatcher.h
+++ b/sandbox/win/src/sync_dispatcher.h
@@ -22,12 +22,11 @@
 
 private:
   // Processes IPC requests coming from calls to CreateEvent in the target.
-  bool CreateEvent(IPCInfo* ipc, std::wstring* name, DWORD manual_reset,
+  bool CreateEvent(IPCInfo* ipc, std::wstring* name, DWORD event_type,
                    DWORD initial_state);
 
   // Processes IPC requests coming from calls to OpenEvent in the target.
-  bool OpenEvent(IPCInfo* ipc, std::wstring* name, DWORD desired_access,
-                 DWORD inherit_handle);
+  bool OpenEvent(IPCInfo* ipc, std::wstring* name, DWORD desired_access);
 
   PolicyBase* policy_base_;
   DISALLOW_COPY_AND_ASSIGN(SyncDispatcher);
diff --git a/sandbox/win/src/sync_interception.cc b/sandbox/win/src/sync_interception.cc
index ddbcc05..cafbcb0 100644
--- a/sandbox/win/src/sync_interception.cc
+++ b/sandbox/win/src/sync_interception.cc
@@ -17,33 +17,25 @@
 
 ResultCode ProxyCreateEvent(LPCWSTR name,
                             BOOL initial_state,
-                            BOOL manual_reset,
+                            EVENT_TYPE event_type,
+                            void* ipc_memory,
                             CrossCallReturn* answer) {
-  void* memory = GetGlobalIPCMemory();
-  if (!memory)
-    return SBOX_ERROR_GENERIC;
-
   CountedParameterSet<NameBased> params;
   params[NameBased::NAME] = ParamPickerMake(name);
 
   if (!QueryBroker(IPC_CREATEEVENT_TAG, params.GetBase()))
     return SBOX_ERROR_GENERIC;
 
-  SharedMemIPCClient ipc(memory);
-  ResultCode code = CrossCall(ipc, IPC_CREATEEVENT_TAG, name, manual_reset,
+  SharedMemIPCClient ipc(ipc_memory);
+  ResultCode code = CrossCall(ipc, IPC_CREATEEVENT_TAG, name, event_type,
                               initial_state, answer);
   return code;
 }
 
 ResultCode ProxyOpenEvent(LPCWSTR name,
                           ACCESS_MASK desired_access,
-                          BOOL inherit_handle,
+                          void* ipc_memory,
                           CrossCallReturn* answer) {
-  void* memory = GetGlobalIPCMemory();
-  if (!memory)
-    return SBOX_ERROR_GENERIC;
-
-  uint32 inherit_handle_ipc = inherit_handle;
   CountedParameterSet<OpenEventParams> params;
   params[OpenEventParams::NAME] = ParamPickerMake(name);
   params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
@@ -51,135 +43,119 @@
   if (!QueryBroker(IPC_OPENEVENT_TAG, params.GetBase()))
     return SBOX_ERROR_GENERIC;
 
-  SharedMemIPCClient ipc(memory);
+  SharedMemIPCClient ipc(ipc_memory);
   ResultCode code = CrossCall(ipc, IPC_OPENEVENT_TAG, name, desired_access,
-                              inherit_handle_ipc, answer);
+                              answer);
 
   return code;
 }
 
-HANDLE WINAPI TargetCreateEventW(CreateEventWFunction orig_CreateEvent,
-                                 LPSECURITY_ATTRIBUTES security_attributes,
-                                 BOOL manual_reset,
-                                 BOOL initial_state,
-                                 LPCWSTR name) {
-  // Check if the process can create it first.
-  HANDLE handle = orig_CreateEvent(security_attributes, manual_reset,
-                                   initial_state, name);
-  if (handle || !name)
-    return handle;
+NTSTATUS WINAPI TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
+                                    PHANDLE event_handle,
+                                    ACCESS_MASK desired_access,
+                                    POBJECT_ATTRIBUTES object_attributes,
+                                    EVENT_TYPE event_type,
+                                    BOOLEAN initial_state) {
+  NTSTATUS status = orig_CreateEvent(event_handle, desired_access,
+                                     object_attributes, event_type,
+                                     initial_state);
+  if (status != STATUS_ACCESS_DENIED || !object_attributes)
+    return status;
 
   // We don't trust that the IPC can work this early.
   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return NULL;
+    return status;
 
-  DWORD original_error = ::GetLastError();
+  do {
+    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+      break;
 
-  CrossCallReturn answer = {0};
-  ResultCode code = ProxyCreateEvent(name, initial_state, manual_reset,
-                                     &answer);
+    void* memory = GetGlobalIPCMemory();
+    if (memory == NULL)
+      break;
 
-  if (code == SBOX_ALL_OK) {
-    ::SetLastError(answer.win32_result);
-    return answer.handle;
-  }
-  ::SetLastError(original_error);
-  return NULL;
+    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+    // The RootDirectory points to BaseNamedObjects. We can ignore it.
+    object_attribs_copy.RootDirectory = NULL;
+
+    wchar_t* name = NULL;
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || name == NULL)
+      break;
+
+    CrossCallReturn answer = {0};
+    answer.nt_status = status;
+    ResultCode code = ProxyCreateEvent(name, initial_state, event_type, memory,
+                                       &answer);
+    operator delete(name, NT_ALLOC);
+
+    if (code != SBOX_ALL_OK) {
+      status = answer.nt_status;
+      break;
+    }
+    __try {
+      *event_handle = answer.handle;
+      status = STATUS_SUCCESS;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
 }
 
-HANDLE WINAPI TargetCreateEventA(CreateEventAFunction orig_CreateEvent,
-                                 LPSECURITY_ATTRIBUTES security_attributes,
-                                 BOOL manual_reset,
-                                 BOOL initial_state,
-                                 LPCSTR name) {
-  // Check if the process can create it first.
-  HANDLE handle = orig_CreateEvent(security_attributes, manual_reset,
-                                   initial_state, name);
-  if (handle || !name)
-    return handle;
+NTSTATUS WINAPI TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
+                                  PHANDLE event_handle,
+                                  ACCESS_MASK desired_access,
+                                  POBJECT_ATTRIBUTES object_attributes) {
+  NTSTATUS status = orig_OpenEvent(event_handle, desired_access,
+                                   object_attributes);
+  if (status != STATUS_ACCESS_DENIED || !object_attributes)
+    return status;
 
   // We don't trust that the IPC can work this early.
   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return NULL;
+    return status;
 
-  DWORD original_error = ::GetLastError();
+  do {
+    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+      break;
 
-  UNICODE_STRING* wide_name = AnsiToUnicode(name);
-  if (!wide_name)
-    return NULL;
+    void* memory = GetGlobalIPCMemory();
+    if (memory == NULL)
+      break;
 
-  CrossCallReturn answer = {0};
-  ResultCode code = ProxyCreateEvent(wide_name->Buffer, initial_state,
-                                     manual_reset, &answer);
-  operator delete(wide_name, NT_ALLOC);
+    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+    // The RootDirectory points to BaseNamedObjects. We can ignore it.
+    object_attribs_copy.RootDirectory = NULL;
 
-  if (code == SBOX_ALL_OK) {
-    ::SetLastError(answer.win32_result);
-    return answer.handle;
-  }
-  ::SetLastError(original_error);
-  return NULL;
-}
+    wchar_t* name = NULL;
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || name == NULL)
+      break;
 
-// Interception of OpenEventW on the child process.
-// It should never be called directly
-HANDLE WINAPI TargetOpenEventW(OpenEventWFunction orig_OpenEvent,
-                               DWORD desired_access,
-                               BOOL inherit_handle,
-                               LPCWSTR name) {
-  // Check if the process can open it first.
-  HANDLE handle = orig_OpenEvent(desired_access, inherit_handle, name);
-  if (handle || !name)
-    return handle;
+    CrossCallReturn answer = {0};
+    answer.nt_status = status;
+    ResultCode code = ProxyOpenEvent(name, desired_access, memory, &answer);
+    operator delete(name, NT_ALLOC);
 
-  // We don't trust that the IPC can work this early.
-  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return NULL;
+    if (code != SBOX_ALL_OK) {
+      status = answer.nt_status;
+      break;
+    }
+    __try {
+      *event_handle = answer.handle;
+      status = STATUS_SUCCESS;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
 
-  DWORD original_error = ::GetLastError();
-
-  CrossCallReturn answer = {0};
-
-  ResultCode code = ProxyOpenEvent(name, desired_access, inherit_handle,
-                                   &answer);
-  if (code == SBOX_ALL_OK) {
-    ::SetLastError(answer.win32_result);
-    return answer.handle;
-  }
-  ::SetLastError(original_error);
-  return NULL;
-}
-
-HANDLE WINAPI TargetOpenEventA(OpenEventAFunction orig_OpenEvent,
-                               DWORD desired_access,
-                               BOOL inherit_handle,
-                               LPCSTR name) {
-  // Check if the process can open it first.
-  HANDLE handle = orig_OpenEvent(desired_access, inherit_handle, name);
-  if (handle || !name)
-    return handle;
-
-  // We don't trust that the IPC can work this early.
-  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return NULL;
-
-  DWORD original_error = ::GetLastError();
-
-  UNICODE_STRING* wide_name = AnsiToUnicode(name);
-  if (!wide_name)
-    return NULL;
-
-  CrossCallReturn answer = {0};
-  ResultCode code = ProxyOpenEvent(wide_name->Buffer, desired_access,
-                                   inherit_handle, &answer);
-  operator delete(wide_name, NT_ALLOC);
-
-  if (code == SBOX_ALL_OK) {
-    ::SetLastError(answer.win32_result);
-    return answer.handle;
-  }
-  ::SetLastError(original_error);
-  return NULL;
+  return status;
 }
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/sync_interception.h b/sandbox/win/src/sync_interception.h
index 19790f7..0f985a8 100644
--- a/sandbox/win/src/sync_interception.h
+++ b/sandbox/win/src/sync_interception.h
@@ -12,55 +12,32 @@
 
 extern "C" {
 
-typedef HANDLE (WINAPI *CreateEventWFunction) (
-    LPSECURITY_ATTRIBUTES lpEventAttributes,
-    BOOL bManualReset,
-    BOOL bInitialState,
-    LPCWSTR lpName);
+typedef NTSTATUS (WINAPI* NtCreateEventFunction) (
+    PHANDLE EventHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes,
+    EVENT_TYPE EventType,
+    BOOLEAN InitialState);
 
-typedef HANDLE (WINAPI *CreateEventAFunction) (
-    LPSECURITY_ATTRIBUTES lpEventAttributes,
-    BOOL bManualReset,
-    BOOL bInitialState,
-    LPCSTR lpName);
+typedef NTSTATUS (WINAPI *NtOpenEventFunction) (
+    PHANDLE EventHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
 
-typedef HANDLE (WINAPI *OpenEventWFunction) (
-    DWORD dwDesiredAccess,
-    BOOL bInitialState,
-    LPCWSTR lpName);
+// Interceptors for NtCreateEvent/NtOpenEvent
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent(
+    NtCreateEventFunction orig_CreateEvent,
+    PHANDLE event_handle,
+    ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes,
+    EVENT_TYPE event_type,
+    BOOLEAN initial_state);
 
-typedef HANDLE (WINAPI *OpenEventAFunction) (
-    DWORD dwDesiredAccess,
-    BOOL bInheritHandle,
-    LPCSTR lpName);
-
-// Interceptors for CreateEventW/A
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW(
-    CreateEventWFunction orig_CreateEvent,
-    LPSECURITY_ATTRIBUTES security_attributes,
-    BOOL manual_reset,
-    BOOL initial_state,
-    LPCWSTR name);
-
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA(
-    CreateEventAFunction orig_CreateEvent,
-    LPSECURITY_ATTRIBUTES security_attributes,
-    BOOL manual_reset,
-    BOOL initial_state,
-    LPCSTR name);
-
-// Interceptors for OpenEventW/A
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW(
-    OpenEventWFunction orig_OpenEvent,
-    DWORD desired_access,
-    BOOL inherit_handle,
-    LPCWSTR name);
-
-SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA(
-    OpenEventAFunction orig_OpenEvent,
-    DWORD desired_access,
-    BOOL inherit_handle,
-    LPCSTR name);
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent(
+    NtOpenEventFunction orig_OpenEvent,
+    PHANDLE event_handle,
+    ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
 
 }  // extern "C"
 
diff --git a/sandbox/win/src/sync_policy.cc b/sandbox/win/src/sync_policy.cc
index 87ef0bd..e3b6530 100644
--- a/sandbox/win/src/sync_policy.cc
+++ b/sandbox/win/src/sync_policy.cc
@@ -7,14 +7,129 @@
 #include "sandbox/win/src/sync_policy.h"
 
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
 #include "sandbox/win/src/policy_engine_opcodes.h"
 #include "sandbox/win/src/policy_params.h"
 #include "sandbox/win/src/sandbox_types.h"
 #include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/win_utils.h"
 
 namespace sandbox {
 
+// Provides functionality to resolve a symbolic link within the object
+// directory passed in.
+NTSTATUS ResolveSymbolicLink(const std::wstring& directory_name,
+                             const std::wstring& name,
+                             std::wstring* target) {
+  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL;
+  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+  NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = NULL;
+  ResolveNTFunctionPtr("NtQuerySymbolicLinkObject",
+                       &NtQuerySymbolicLinkObject);
+
+  NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = NULL;
+  ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject);
+
+  NtCloseFunction NtClose = NULL;
+  ResolveNTFunctionPtr("NtClose", &NtClose);
+
+  OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {};
+  UNICODE_STRING symbolic_link_directory_string = {};
+  InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, NULL,
+                    &symbolic_link_directory_attributes,
+                    &symbolic_link_directory_string);
+
+  HANDLE symbolic_link_directory = NULL;
+  NTSTATUS status = NtOpenDirectoryObject(&symbolic_link_directory,
+                                          DIRECTORY_QUERY,
+                                          &symbolic_link_directory_attributes);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to open symbolic link directory. Error: "
+                << status;
+    return status;
+  }
+
+  OBJECT_ATTRIBUTES symbolic_link_attributes = {};
+  UNICODE_STRING name_string = {};
+  InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory,
+                    &symbolic_link_attributes, &name_string);
+
+  HANDLE symbolic_link = NULL;
+  status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ,
+                                    &symbolic_link_attributes);
+  NtClose(symbolic_link_directory);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to open symbolic link Error: " << status;
+    return status;
+  }
+
+  UNICODE_STRING target_path = {};
+  unsigned long target_length = 0;
+  status = NtQuerySymbolicLinkObject(symbolic_link, &target_path,
+                                     &target_length);
+  if (status != STATUS_BUFFER_TOO_SMALL) {
+    NtClose(symbolic_link);
+    DLOG(ERROR) << "Failed to get length for symbolic link target. Error: "
+                << status;
+    return status;
+  }
+
+  target_path.Buffer = new wchar_t[target_length + 1];
+  target_path.Length = 0;
+  target_path.MaximumLength = target_length;
+  status = NtQuerySymbolicLinkObject(symbolic_link, &target_path,
+                                     &target_length);
+  if (status == STATUS_SUCCESS) {
+    target->assign(target_path.Buffer, target_length);
+  } else {
+    DLOG(ERROR) << "Failed to resolve symbolic link. Error: " << status;
+  }
+
+  NtClose(symbolic_link);
+  delete[] target_path.Buffer;
+  return status;
+}
+
+NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) {
+  static HANDLE base_named_objects_handle = NULL;
+  if (base_named_objects_handle) {
+    *directory = base_named_objects_handle;
+    return STATUS_SUCCESS;
+  }
+
+  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL;
+  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+  DWORD session_id = 0;
+  ProcessIdToSessionId(::GetCurrentProcessId(), &session_id);
+
+  std::wstring base_named_objects_path;
+
+  NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS",
+                                        base::StringPrintf(L"%d", session_id),
+                                        &base_named_objects_path);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: "
+                << status;
+    return status;
+  }
+
+  UNICODE_STRING directory_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, NULL,
+                    &object_attributes, &directory_name);
+  status = NtOpenDirectoryObject(&base_named_objects_handle,
+                                 DIRECTORY_ALL_ACCESS,
+                                 &object_attributes);
+  if (status == STATUS_SUCCESS)
+    *directory = base_named_objects_handle;
+  return status;
+}
+
 bool SyncPolicy::GenerateRules(const wchar_t* name,
                                TargetPolicy::Semantics semantics,
                                LowLevelPolicy* policy) {
@@ -64,49 +179,75 @@
 DWORD SyncPolicy::CreateEventAction(EvalResult eval_result,
                                     const ClientInfo& client_info,
                                     const std::wstring &event_name,
-                                    uint32 manual_reset,
+                                    uint32 event_type,
                                     uint32 initial_state,
                                     HANDLE *handle) {
+  NtCreateEventFunction NtCreateEvent = NULL;
+  ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent);
+
   // The only action supported is ASK_BROKER which means create the requested
   // file as specified.
   if (ASK_BROKER != eval_result)
     return false;
 
-  HANDLE local_handle = ::CreateEvent(NULL, manual_reset, initial_state,
-                                     event_name.c_str());
+  HANDLE object_directory = NULL;
+  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+  if (status != STATUS_SUCCESS)
+    return status;
+
+  UNICODE_STRING unicode_event_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+                    &object_attributes, &unicode_event_name);
+
+  HANDLE local_handle = NULL;
+  status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes,
+                         static_cast<EVENT_TYPE>(event_type), initial_state);
   if (NULL == local_handle)
-    return ::GetLastError();
+    return status;
 
   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
                          client_info.process, handle, 0, FALSE,
                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
-    return ERROR_ACCESS_DENIED;
+    return STATUS_ACCESS_DENIED;
   }
-  return ERROR_SUCCESS;
+  return status;
 }
 
 DWORD SyncPolicy::OpenEventAction(EvalResult eval_result,
                                   const ClientInfo& client_info,
                                   const std::wstring &event_name,
                                   uint32 desired_access,
-                                  uint32 inherit_handle,
                                   HANDLE *handle) {
+  NtOpenEventFunction NtOpenEvent = NULL;
+  ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent);
+
   // The only action supported is ASK_BROKER which means create the requested
-  // file as specified.
+  // event as specified.
   if (ASK_BROKER != eval_result)
     return false;
 
-  HANDLE local_handle = ::OpenEvent(desired_access, FALSE,
-                                    event_name.c_str());
+  HANDLE object_directory = NULL;
+  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+  if (status != STATUS_SUCCESS)
+    return status;
+
+  UNICODE_STRING unicode_event_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+                    &object_attributes, &unicode_event_name);
+
+  HANDLE local_handle = NULL;
+  status = NtOpenEvent(&local_handle, desired_access, &object_attributes);
   if (NULL == local_handle)
-    return ::GetLastError();
+    return status;
 
   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
-                         client_info.process, handle, 0, inherit_handle,
+                         client_info.process, handle, 0, FALSE,
                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
-    return ERROR_ACCESS_DENIED;
+    return STATUS_ACCESS_DENIED;
   }
-  return ERROR_SUCCESS;
+  return status;
 }
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/sync_policy.h b/sandbox/win/src/sync_policy.h
index 2b8b422..93aef64 100644
--- a/sandbox/win/src/sync_policy.h
+++ b/sandbox/win/src/sync_policy.h
@@ -35,14 +35,13 @@
   static DWORD CreateEventAction(EvalResult eval_result,
                                  const ClientInfo& client_info,
                                  const std::wstring &event_name,
-                                 uint32 manual_reset,
+                                 uint32 event_type,
                                  uint32 initial_state,
                                  HANDLE *handle);
   static DWORD OpenEventAction(EvalResult eval_result,
                                const ClientInfo& client_info,
                                const std::wstring &event_name,
                                uint32 desired_access,
-                               uint32 inherit_handle,
                                HANDLE *handle);
 };
 
diff --git a/sandbox/win/src/sync_policy_test.cc b/sandbox/win/src/sync_policy_test.cc
index 87d03f1..ced5498 100644
--- a/sandbox/win/src/sync_policy_test.cc
+++ b/sandbox/win/src/sync_policy_test.cc
@@ -87,7 +87,7 @@
 }
 
 // Tests the creation of events using all the possible combinations.
-TEST(SyncPolicyTest, TestEvent) {
+TEST(SyncPolicyTest, DISABLED_TestEvent) {
   TestRunner runner;
   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
                              TargetPolicy::EVENTS_ALLOW_ANY,
@@ -111,7 +111,7 @@
 }
 
 // Tests opening events with read only access.
-TEST(SyncPolicyTest, TestEventReadOnly) {
+TEST(SyncPolicyTest, DISABLED_TestEventReadOnly) {
   TestRunner runner;
   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
                              TargetPolicy::EVENTS_ALLOW_READONLY,
diff --git a/sdch/sdch.target.darwin-arm.mk b/sdch/sdch.target.darwin-arm.mk
index 2fb28d6..25783e7 100644
--- a/sdch/sdch.target.darwin-arm.mk
+++ b/sdch/sdch.target.darwin-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sdch/sdch.target.darwin-mips.mk b/sdch/sdch.target.darwin-mips.mk
index 9c62181..e32123c 100644
--- a/sdch/sdch.target.darwin-mips.mk
+++ b/sdch/sdch.target.darwin-mips.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sdch/sdch.target.darwin-x86.mk b/sdch/sdch.target.darwin-x86.mk
index 613039c..fab21e8 100644
--- a/sdch/sdch.target.darwin-x86.mk
+++ b/sdch/sdch.target.darwin-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sdch/sdch.target.linux-arm.mk b/sdch/sdch.target.linux-arm.mk
index 2fb28d6..25783e7 100644
--- a/sdch/sdch.target.linux-arm.mk
+++ b/sdch/sdch.target.linux-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sdch/sdch.target.linux-mips.mk b/sdch/sdch.target.linux-mips.mk
index 9c62181..e32123c 100644
--- a/sdch/sdch.target.linux-mips.mk
+++ b/sdch/sdch.target.linux-mips.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sdch/sdch.target.linux-x86.mk b/sdch/sdch.target.linux-x86.mk
index 613039c..fab21e8 100644
--- a/sdch/sdch.target.linux-x86.mk
+++ b/sdch/sdch.target.linux-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/PRESUBMIT.py b/skia/PRESUBMIT.py
new file mode 100644
index 0000000..e22733c
--- /dev/null
+++ b/skia/PRESUBMIT.py
@@ -0,0 +1,18 @@
+# Copyright 2013 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.
+
+"""Top-level presubmit script for skia/
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def GetPreferredTrySlaves(project, change):
+  return [
+    'linux_gpu',
+    'win_gpu',
+    'mac_gpu',
+    'mac_gpu_retina',
+    'linux_layout_rel',
+    ]
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 302a072..d15882c 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -152,6 +152,12 @@
 
 // ===== Begin Chrome-specific definitions =====
 
+#ifdef SK_DEBUG
+#define SK_REF_CNT_MIXIN_INCLUDE "sk_ref_cnt_ext_debug.h"
+#else
+#define SK_REF_CNT_MIXIN_INCLUDE "sk_ref_cnt_ext_release.h"
+#endif
+
 #define SK_SCALAR_IS_FLOAT
 #undef SK_SCALAR_IS_FIXED
 
diff --git a/skia/config/sk_ref_cnt_ext_debug.h b/skia/config/sk_ref_cnt_ext_debug.h
new file mode 100644
index 0000000..b2b66ad
--- /dev/null
+++ b/skia/config/sk_ref_cnt_ext_debug.h
@@ -0,0 +1,48 @@
+// Copyright 2013 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 SK_REF_CNT_EXT_DEBUG_H_
+#define SK_REF_CNT_EXT_DEBUG_H_
+
+#ifdef SK_REF_CNT_EXT_RELEASE_H_
+#error Only one SkRefCnt should be used.
+#endif
+
+// Alternate implementation of SkRefCnt for Chromium debug builds
+class SK_API SkRefCnt : public SkRefCntBase {
+public:
+  SkRefCnt() : flags_(0) {}
+  void ref() const { SkASSERT(flags_ != AdoptionRequired_Flag); SkRefCntBase::ref(); }
+  void adopted() const { flags_ |= Adopted_Flag; }
+  void requireAdoption() const { flags_ |= AdoptionRequired_Flag; }
+  void deref() const { SkRefCntBase::unref(); }
+private:
+  enum {
+    Adopted_Flag = 0x1,
+    AdoptionRequired_Flag = 0x2,
+  };
+
+  mutable int flags_;
+};
+
+// Bootstrap for Blink's WTF::RefPtr
+
+namespace WTF {
+  inline void adopted(const SkRefCnt* object) {
+    if (!object)
+      return;
+    object->adopted();
+  }
+  inline void requireAdoption(const SkRefCnt* object) {
+    if (!object)
+      return;
+    object->requireAdoption();
+  }
+};
+
+using WTF::adopted;
+using WTF::requireAdoption;
+
+#endif
+
diff --git a/skia/config/sk_ref_cnt_ext_release.h b/skia/config/sk_ref_cnt_ext_release.h
new file mode 100644
index 0000000..7736c84
--- /dev/null
+++ b/skia/config/sk_ref_cnt_ext_release.h
@@ -0,0 +1,19 @@
+// Copyright 2013 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 SK_REF_CNT_EXT_RELEASE_H_
+#define SK_REF_CNT_EXT_RELEASE_H_
+
+#ifdef SK_REF_CNT_EXT_DEBUG_H_
+#error Only one SkRefCnt should be used.
+#endif
+
+// Alternate implementation of SkRefCnt for Chromium release builds
+class SK_API SkRefCnt : public SkRefCntBase {
+public:
+  void deref() const { SkRefCntBase::unref(); }
+};
+
+#endif
+
diff --git a/skia/ext/SkDiscardableMemory_chrome.cc b/skia/ext/SkDiscardableMemory_chrome.cc
index 6639a5a..886c995 100644
--- a/skia/ext/SkDiscardableMemory_chrome.cc
+++ b/skia/ext/SkDiscardableMemory_chrome.cc
@@ -34,8 +34,6 @@
 }
 
 SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) {
-  if (!base::DiscardableMemory::Supported())
-    return NULL;
   scoped_ptr<base::DiscardableMemory> discardable(
       base::DiscardableMemory::CreateLockedMemory(bytes));
   if (!discardable)
diff --git a/skia/ext/bitmap_platform_device_android.cc b/skia/ext/bitmap_platform_device_android.cc
index 32f447f..9d6051e 100644
--- a/skia/ext/bitmap_platform_device_android.cc
+++ b/skia/ext/bitmap_platform_device_android.cc
@@ -10,9 +10,9 @@
 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
                                                    bool is_opaque) {
   SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                   is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   if (bitmap.allocPixels()) {
-    bitmap.setIsOpaque(is_opaque);
     // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if it
     // is not opaque.
     if (!is_opaque)
@@ -35,13 +35,13 @@
                                                    bool is_opaque,
                                                    uint8_t* data) {
   SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                   is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   if (data)
     bitmap.setPixels(data);
   else if (!bitmap.allocPixels())
     return NULL;
 
-  bitmap.setIsOpaque(is_opaque);
   return new BitmapPlatformDevice(bitmap);
 }
 
@@ -87,11 +87,11 @@
 }
 
 bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) {
-  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                    is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   if (!bitmap_.allocPixels())
     return false;
 
-  bitmap_.setIsOpaque(is_opaque);
   surface_ = bitmap_.getPixels();
   return true;
 }
diff --git a/skia/ext/bitmap_platform_device_linux.cc b/skia/ext/bitmap_platform_device_linux.cc
index af26806..f259c6f 100644
--- a/skia/ext/bitmap_platform_device_linux.cc
+++ b/skia/ext/bitmap_platform_device_linux.cc
@@ -89,9 +89,9 @@
   }
   SkBitmap bitmap;
   bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height,
-                   cairo_image_surface_get_stride(surface));
+                   cairo_image_surface_get_stride(surface),
+                   is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   bitmap.setPixels(cairo_image_surface_get_data(surface));
-  bitmap.setIsOpaque(is_opaque);
 
   // The device object will take ownership of the graphics context.
   return new BitmapPlatformDevice
@@ -195,10 +195,10 @@
   // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
   // outlive the PlatformBitmap if additional copies are made.
   int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
-  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, stride);
+  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, stride,
+                    is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   if (!bitmap_.allocPixels())  // Using the default allocator.
     return false;
-  bitmap_.setIsOpaque(is_opaque);
 
   cairo_surface_t* surf = cairo_image_surface_create_for_data(
       reinterpret_cast<unsigned char*>(bitmap_.getPixels()),
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
index 66298b2..8525cd3 100644
--- a/skia/ext/bitmap_platform_device_mac.cc
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -127,7 +127,8 @@
   SkBitmap bitmap;
   // TODO: verify that the CG Context's pixels will have tight rowbytes or pass in the correct
   // rowbytes for the case when context != NULL.
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                   is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
 
   void* data;
   if (context) {
@@ -139,8 +140,6 @@
     data = bitmap.getPixels();
   }
 
-  bitmap.setIsOpaque(is_opaque);
-
   // If we were given data, then don't clobber it!
 #ifndef NDEBUG
   if (!context && is_opaque) {
@@ -285,13 +284,13 @@
   if (RasterDeviceTooBigToAllocate(width, height))
     return false;
     
-  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, width * 4);
+  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, width * 4,
+                    is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   if (!bitmap_.allocPixels())
       return false;
 
   if (!is_opaque)
     bitmap_.eraseColor(0);
-  bitmap_.setIsOpaque(is_opaque);
 
   surface_ = CGContextForData(bitmap_.getPixels(), bitmap_.width(),
                               bitmap_.height());
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index 0088403..203281d 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -171,9 +171,9 @@
     return NULL;
 
   SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                   is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   bitmap.setPixels(data);
-  bitmap.setIsOpaque(is_opaque);
 
 #ifndef NDEBUG
   // If we were given data, then don't clobber it!
@@ -343,11 +343,11 @@
   HGDIOBJ stock_bitmap = SelectObject(surface_, hbitmap);
   platform_extra_ = reinterpret_cast<intptr_t>(stock_bitmap);
 
-  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                    is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   // PlatformBitmapPixelRef takes ownership of |hbitmap|.
   bitmap_.setPixelRef(
       skia::AdoptRef(new PlatformBitmapPixelRef(hbitmap, data)).get());
-  bitmap_.setIsOpaque(is_opaque);
   bitmap_.lockPixels();
 
   return true;
diff --git a/skia/ext/image_operations.cc b/skia/ext/image_operations.cc
index c61da0c..3bb765f 100644
--- a/skia/ext/image_operations.cc
+++ b/skia/ext/image_operations.cc
@@ -394,7 +394,7 @@
   // Render into subpixels.
   SkBitmap result;
   result.setConfig(SkBitmap::kARGB_8888_Config, dest_subset.width(),
-                   dest_subset.height());
+                   dest_subset.height(), 0, img.alphaType());
   result.allocPixels(allocator, NULL);
   if (!result.readyToDraw())
     return img;
@@ -455,7 +455,6 @@
     src_row += h * row_words;
     dst_row += result.rowBytes() / 4;
   }
-  result.setIsOpaque(img.isOpaque());
   return result;
 #else
   return SkBitmap();
@@ -510,8 +509,8 @@
 
   // Convolve into the result.
   SkBitmap result;
-  result.setConfig(SkBitmap::kARGB_8888_Config,
-                   dest_subset.width(), dest_subset.height());
+  result.setConfig(SkBitmap::kARGB_8888_Config, dest_subset.width(),
+                   dest_subset.height(), 0, source.alphaType());
   result.allocPixels(allocator, NULL);
   if (!result.readyToDraw())
     return SkBitmap();
@@ -522,9 +521,6 @@
                  static_cast<unsigned char*>(result.getPixels()),
                  true);
 
-  // Preserve the "opaque" flag for use as an optimization later.
-  result.setIsOpaque(source.isOpaque());
-
   base::TimeDelta delta = base::TimeTicks::Now() - resize_start;
   UMA_HISTOGRAM_TIMES("Image.ResampleMS", delta);
 
diff --git a/skia/skia_chrome.target.darwin-arm.mk b/skia/skia_chrome.target.darwin-arm.mk
index 3d28576..554a4ec 100644
--- a/skia/skia_chrome.target.darwin-arm.mk
+++ b/skia/skia_chrome.target.darwin-arm.mk
@@ -86,13 +86,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome.target.darwin-mips.mk b/skia/skia_chrome.target.darwin-mips.mk
index 3071308..213cc33 100644
--- a/skia/skia_chrome.target.darwin-mips.mk
+++ b/skia/skia_chrome.target.darwin-mips.mk
@@ -86,13 +86,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome.target.darwin-x86.mk b/skia/skia_chrome.target.darwin-x86.mk
index a97eab0..47481fd 100644
--- a/skia/skia_chrome.target.darwin-x86.mk
+++ b/skia/skia_chrome.target.darwin-x86.mk
@@ -88,13 +88,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome.target.linux-arm.mk b/skia/skia_chrome.target.linux-arm.mk
index 3d28576..554a4ec 100644
--- a/skia/skia_chrome.target.linux-arm.mk
+++ b/skia/skia_chrome.target.linux-arm.mk
@@ -86,13 +86,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome.target.linux-mips.mk b/skia/skia_chrome.target.linux-mips.mk
index 3071308..213cc33 100644
--- a/skia/skia_chrome.target.linux-mips.mk
+++ b/skia/skia_chrome.target.linux-mips.mk
@@ -86,13 +86,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome.target.linux-x86.mk b/skia/skia_chrome.target.linux-x86.mk
index a97eab0..47481fd 100644
--- a/skia/skia_chrome.target.linux-x86.mk
+++ b/skia/skia_chrome.target.linux-x86.mk
@@ -88,13 +88,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome_opts.target.darwin-mips.mk b/skia/skia_chrome_opts.target.darwin-mips.mk
index 1649920..22655de 100644
--- a/skia/skia_chrome_opts.target.darwin-mips.mk
+++ b/skia/skia_chrome_opts.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome_opts.target.darwin-x86.mk b/skia/skia_chrome_opts.target.darwin-x86.mk
index 3147de5..be3869f 100644
--- a/skia/skia_chrome_opts.target.darwin-x86.mk
+++ b/skia/skia_chrome_opts.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome_opts.target.linux-mips.mk b/skia/skia_chrome_opts.target.linux-mips.mk
index 1649920..22655de 100644
--- a/skia/skia_chrome_opts.target.linux-mips.mk
+++ b/skia/skia_chrome_opts.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_chrome_opts.target.linux-x86.mk b/skia/skia_chrome_opts.target.linux-x86.mk
index 3147de5..be3869f 100644
--- a/skia/skia_chrome_opts.target.linux-x86.mk
+++ b/skia/skia_chrome_opts.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi
index 0eb3017..9d9a882 100644
--- a/skia/skia_library.gypi
+++ b/skia/skia_library.gypi
@@ -43,7 +43,7 @@
       'SK_ENABLE_LEGACY_API_ALIASING=1',
     ],
 
-    'default_font_cache_limit': '(20*1024*1024)',
+    'default_font_cache_limit%': '(20*1024*1024)',
 
     'conditions': [
       ['OS== "android"', {
diff --git a/skia/skia_library.target.darwin-arm.mk b/skia/skia_library.target.darwin-arm.mk
index b46e19c..6105d36 100644
--- a/skia/skia_library.target.darwin-arm.mk
+++ b/skia/skia_library.target.darwin-arm.mk
@@ -187,6 +187,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -419,13 +420,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -541,13 +542,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.target.darwin-mips.mk b/skia/skia_library.target.darwin-mips.mk
index cbf5d82..e0cf95a 100644
--- a/skia/skia_library.target.darwin-mips.mk
+++ b/skia/skia_library.target.darwin-mips.mk
@@ -187,6 +187,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -418,13 +419,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -539,13 +540,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.target.darwin-x86.mk b/skia/skia_library.target.darwin-x86.mk
index 273e494..612523f 100644
--- a/skia/skia_library.target.darwin-x86.mk
+++ b/skia/skia_library.target.darwin-x86.mk
@@ -188,6 +188,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -421,13 +422,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -545,13 +546,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.target.linux-arm.mk b/skia/skia_library.target.linux-arm.mk
index b46e19c..6105d36 100644
--- a/skia/skia_library.target.linux-arm.mk
+++ b/skia/skia_library.target.linux-arm.mk
@@ -187,6 +187,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -419,13 +420,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -541,13 +542,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.target.linux-mips.mk b/skia/skia_library.target.linux-mips.mk
index cbf5d82..e0cf95a 100644
--- a/skia/skia_library.target.linux-mips.mk
+++ b/skia/skia_library.target.linux-mips.mk
@@ -187,6 +187,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -418,13 +419,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -539,13 +540,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_library.target.linux-x86.mk b/skia/skia_library.target.linux-x86.mk
index 273e494..612523f 100644
--- a/skia/skia_library.target.linux-x86.mk
+++ b/skia/skia_library.target.linux-x86.mk
@@ -188,6 +188,7 @@
 	third_party/skia/src/core/SkTypefaceCache.cpp \
 	third_party/skia/src/core/SkUnPreMultiply.cpp \
 	third_party/skia/src/core/SkUtils.cpp \
+	third_party/skia/src/core/SkValidatingReadBuffer.cpp \
 	third_party/skia/src/core/SkWriter32.cpp \
 	third_party/skia/src/core/SkXfermode.cpp \
 	third_party/skia/src/doc/SkDocument.cpp \
@@ -421,13 +422,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -545,13 +546,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.darwin-arm.mk b/skia/skia_opts.target.darwin-arm.mk
index da5f72b..8d35073 100644
--- a/skia/skia_opts.target.darwin-arm.mk
+++ b/skia/skia_opts.target.darwin-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.darwin-mips.mk b/skia/skia_opts.target.darwin-mips.mk
index 53ba198..f210015 100644
--- a/skia/skia_opts.target.darwin-mips.mk
+++ b/skia/skia_opts.target.darwin-mips.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.darwin-x86.mk b/skia/skia_opts.target.darwin-x86.mk
index f43b6b7..2077e9d 100644
--- a/skia/skia_opts.target.darwin-x86.mk
+++ b/skia/skia_opts.target.darwin-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.linux-arm.mk b/skia/skia_opts.target.linux-arm.mk
index da5f72b..8d35073 100644
--- a/skia/skia_opts.target.linux-arm.mk
+++ b/skia/skia_opts.target.linux-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.linux-mips.mk b/skia/skia_opts.target.linux-mips.mk
index 53ba198..f210015 100644
--- a/skia/skia_opts.target.linux-mips.mk
+++ b/skia/skia_opts.target.linux-mips.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts.target.linux-x86.mk b/skia/skia_opts.target.linux-x86.mk
index f43b6b7..2077e9d 100644
--- a/skia/skia_opts.target.linux-x86.mk
+++ b/skia/skia_opts.target.linux-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts_neon.target.darwin-arm.mk b/skia/skia_opts_neon.target.darwin-arm.mk
index bb974a0..9f26c6f 100644
--- a/skia/skia_opts_neon.target.darwin-arm.mk
+++ b/skia/skia_opts_neon.target.darwin-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts_neon.target.linux-arm.mk b/skia/skia_opts_neon.target.linux-arm.mk
index bb974a0..9f26c6f 100644
--- a/skia/skia_opts_neon.target.linux-arm.mk
+++ b/skia/skia_opts_neon.target.linux-arm.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts_ssse3.target.darwin-x86.mk b/skia/skia_opts_ssse3.target.darwin-x86.mk
index 309685a..2f95f53 100644
--- a/skia/skia_opts_ssse3.target.darwin-x86.mk
+++ b/skia/skia_opts_ssse3.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_opts_ssse3.target.linux-x86.mk b/skia/skia_opts_ssse3.target.linux-x86.mk
index 309685a..2f95f53 100644
--- a/skia/skia_opts_ssse3.target.linux-x86.mk
+++ b/skia/skia_opts_ssse3.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/skia/skia_test_expectations.txt b/skia/skia_test_expectations.txt
index 476a0c2..72be78f 100644
--- a/skia/skia_test_expectations.txt
+++ b/skia/skia_test_expectations.txt
@@ -48,9 +48,24 @@
 #
 # START OVERRIDES HERE
 
-# The roll to r11833 altered the following 3 images
-crbug.com/308500 svg/W3C-SVG-1.1/pservers-grad-14-b.svg [ ImageOnlyFailure ]
-crbug.com/308500 virtual/gpu/fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ]
-crbug.com/308500 virtual/gpu/fast/canvas/canvas-composite.html [ ImageOnlyFailure ]
+# The Skia roll to r12012 introduced imperceptible image differences in the following tests:
+crbug.com/313226 compositing/geometry/layer-due-to-layer-children.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/geometry/vertical-scroll-composited.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/overflow/nested-render-surfaces-with-rotation.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/perpendicular-layer-sorting.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/reflections/animation-inside-reflection.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/reflections/transform-inside-reflection.html [ ImageOnlyFailure ]
+crbug.com/313226 fast/sub-pixel/transformed-iframe-copy-on-scroll.html [ ImageOnlyFailure ]
+crbug.com/313226 transforms/3d/point-mapping/3d-point-mapping-deep.html [ ImageOnlyFailure ]
+crbug.com/313226 transforms/3d/point-mapping/3d-point-mapping-origins.html [ ImageOnlyFailure ]
+crbug.com/313226 transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/gpu/compositedscrolling/overflow/nested-render-surfaces-with-rotation.html [ ImageOnlyFailure ]
+crbug.com/313226 compositing/geometry/fixed-position-transform-composited-page-scale-down.html [ ImageOnlyFailure ]
+crbug.com/313226 transforms/3d/general/perspective-units.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/softwarecompositing/geometry/vertical-scroll-composited.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/softwarecompositing/huge-layer-rotated.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/softwarecompositing/lots-of-img-layers-with-opacity.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/softwarecompositing/lots-of-img-layers.html [ ImageOnlyFailure ]
+crbug.com/313226 virtual/softwarecompositing/tiny-layer-rotated.html [ ImageOnlyFailure ]
 
 # END OVERRIDES HERE (this line ensures that the file is newline-terminated)
diff --git a/sql/sql.target.darwin-arm.mk b/sql/sql.target.darwin-arm.mk
index ce127ae..0f0bade 100644
--- a/sql/sql.target.darwin-arm.mk
+++ b/sql/sql.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/sql.target.darwin-mips.mk b/sql/sql.target.darwin-mips.mk
index 526ce5e..f20383b 100644
--- a/sql/sql.target.darwin-mips.mk
+++ b/sql/sql.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/sql.target.darwin-x86.mk b/sql/sql.target.darwin-x86.mk
index ac547aa..249a9ca 100644
--- a/sql/sql.target.darwin-x86.mk
+++ b/sql/sql.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/sql.target.linux-arm.mk b/sql/sql.target.linux-arm.mk
index ce127ae..0f0bade 100644
--- a/sql/sql.target.linux-arm.mk
+++ b/sql/sql.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/sql.target.linux-mips.mk b/sql/sql.target.linux-mips.mk
index 526ce5e..f20383b 100644
--- a/sql/sql.target.linux-mips.mk
+++ b/sql/sql.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/sql.target.linux-x86.mk b/sql/sql.target.linux-x86.mk
index ac547aa..249a9ca 100644
--- a/sql/sql.target.linux-x86.mk
+++ b/sql/sql.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/sql/statement.cc b/sql/statement.cc
index 67b7334..4f5e17f 100644
--- a/sql/statement.cc
+++ b/sql/statement.cc
@@ -16,11 +16,13 @@
 // only have to check the ref's validity bit.
 Statement::Statement()
     : ref_(new Connection::StatementRef(NULL, NULL, false)),
+      stepped_(false),
       succeeded_(false) {
 }
 
 Statement::Statement(scoped_refptr<Connection::StatementRef> ref)
     : ref_(ref),
+      stepped_(false),
       succeeded_(false) {
 }
 
@@ -50,10 +52,12 @@
 }
 
 bool Statement::Run() {
+  DCHECK(!stepped_);
   ref_->AssertIOAllowed();
   if (!CheckValid())
     return false;
 
+  stepped_ = true;
   return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_DONE;
 }
 
@@ -62,6 +66,7 @@
   if (!CheckValid())
     return false;
 
+  stepped_ = true;
   return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_ROW;
 }
 
@@ -77,6 +82,7 @@
   }
 
   succeeded_ = false;
+  stepped_ = false;
 }
 
 bool Statement::Succeeded() const {
@@ -87,6 +93,7 @@
 }
 
 bool Statement::BindNull(int col) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -98,6 +105,7 @@
 }
 
 bool Statement::BindInt(int col, int val) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -105,6 +113,7 @@
 }
 
 bool Statement::BindInt64(int col, int64 val) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -112,6 +121,7 @@
 }
 
 bool Statement::BindDouble(int col, double val) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -119,6 +129,7 @@
 }
 
 bool Statement::BindCString(int col, const char* val) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -127,6 +138,7 @@
 }
 
 bool Statement::BindString(int col, const std::string& val) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
@@ -142,6 +154,7 @@
 }
 
 bool Statement::BindBlob(int col, const void* val, int val_len) {
+  DCHECK(!stepped_);
   if (!is_valid())
     return false;
 
diff --git a/sql/statement.h b/sql/statement.h
index 5fedc53..acf89e7 100644
--- a/sql/statement.h
+++ b/sql/statement.h
@@ -178,6 +178,11 @@
   // guaranteed non-NULL.
   scoped_refptr<Connection::StatementRef> ref_;
 
+  // Set after Step() or Run() are called, reset by Reset().  Used to
+  // prevent accidental calls to API functions which would not work
+  // correctly after stepping has started.
+  bool stepped_;
+
   // See Succeeded() for what this holds.
   bool succeeded_;
 
diff --git a/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java b/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java
deleted file mode 100644
index 93685db..0000000
--- a/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright (c) 2013 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.sync.notifier;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.Intent;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-import com.google.protos.ipc.invalidation.Types;
-
-import org.chromium.base.ActivityStatus;
-import org.chromium.base.CalledByNative;
-import org.chromium.base.CollectionUtil;
-import org.chromium.sync.internal_api.pub.base.ModelType;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Controller used to send start, stop, and registration-change commands to the invalidation
- * client library used by Sync.
- */
-public class InvalidationController implements ActivityStatus.StateListener {
-    /**
-     * Constants and utility methods to create the intents used to communicate between the
-     * controller and the invalidation client library.
-     */
-    public static class IntentProtocol {
-        /**
-         * Action set on register intents.
-         */
-        public static final String ACTION_REGISTER =
-                "org.chromium.sync.notifier.ACTION_REGISTER_TYPES";
-
-        /**
-         * Parcelable-valued intent extra containing the account of the user.
-         */
-        public static final String EXTRA_ACCOUNT = "account";
-
-        /**
-         * String-list-valued intent extra of the syncable types to sync.
-         */
-        public static final String EXTRA_REGISTERED_TYPES = "registered_types";
-
-        /**
-         * Int-array-valued intent extra containing sources of objects to register for.
-         * The array is parallel to EXTRA_REGISTERED_OBJECT_NAMES.
-         */
-        public static final String EXTRA_REGISTERED_OBJECT_SOURCES = "registered_object_sources";
-
-        /**
-         * String-array-valued intent extra containing names of objects to register for.
-         * The array is parallel to EXTRA_REGISTERED_OBJECT_SOURCES.
-         */
-        public static final String EXTRA_REGISTERED_OBJECT_NAMES = "registered_object_names";
-
-        /**
-         * Boolean-valued intent extra indicating that the service should be stopped.
-         */
-        public static final String EXTRA_STOP = "stop";
-
-        /**
-         * Create an Intent that will start the invalidation listener service and
-         * register for the specified types.
-         */
-        public static Intent createRegisterIntent(Account account,
-                                                  boolean allTypes, Set<ModelType> types) {
-            Intent registerIntent = new Intent(ACTION_REGISTER);
-            String[] selectedTypesArray;
-            if (allTypes) {
-                selectedTypesArray = new String[]{ModelType.ALL_TYPES_TYPE};
-            } else {
-                selectedTypesArray = new String[types.size()];
-                int pos = 0;
-                for (ModelType type : types) {
-                    selectedTypesArray[pos++] = type.name();
-                }
-            }
-            registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_TYPES,
-                    CollectionUtil.newArrayList(selectedTypesArray));
-            registerIntent.putExtra(EXTRA_ACCOUNT, account);
-            return registerIntent;
-        }
-
-        /**
-         * Create an Intent that will start the invalidation listener service and
-         * register for the object ids with the specified sources and names.
-         * Sync-specific objects are filtered out of the request since Sync types
-         * are registered using the other version of createRegisterIntent.
-         */
-        public static Intent createRegisterIntent(Account account, int[] objectSources,
-                String[] objectNames) {
-            Preconditions.checkArgument(objectSources.length == objectNames.length,
-                "objectSources and objectNames must have the same length");
-
-            // Add all non-Sync objects to new lists.
-            ArrayList<Integer> sources = new ArrayList<Integer>();
-            ArrayList<String> names = new ArrayList<String>();
-            for (int i = 0; i < objectSources.length; i++) {
-                if (objectSources[i] != Types.ObjectSource.Type.CHROME_SYNC.getNumber()) {
-                    sources.add(objectSources[i]);
-                    names.add(objectNames[i]);
-                }
-            }
-
-            Intent registerIntent = new Intent(ACTION_REGISTER);
-            registerIntent.putIntegerArrayListExtra(EXTRA_REGISTERED_OBJECT_SOURCES, sources);
-            registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_OBJECT_NAMES, names);
-            registerIntent.putExtra(EXTRA_ACCOUNT, account);
-            return registerIntent;
-        }
-
-        /** Returns whether {@code intent} is a stop intent. */
-        public static boolean isStop(Intent intent) {
-            return intent.getBooleanExtra(EXTRA_STOP, false);
-        }
-
-        /** Returns whether {@code intent} is a registered types change intent. */
-        public static boolean isRegisteredTypesChange(Intent intent) {
-            return intent.hasExtra(EXTRA_REGISTERED_TYPES) ||
-                    intent.hasExtra(EXTRA_REGISTERED_OBJECT_SOURCES);
-        }
-
-        /** Returns the object ids for which to register contained in the intent. */
-        public static Set<ObjectId> getRegisteredObjectIds(Intent intent) {
-            ArrayList<Integer> objectSources =
-                    intent.getIntegerArrayListExtra(EXTRA_REGISTERED_OBJECT_SOURCES);
-            ArrayList<String> objectNames =
-                    intent.getStringArrayListExtra(EXTRA_REGISTERED_OBJECT_NAMES);
-            if (objectSources == null || objectNames == null ||
-                    objectSources.size() != objectNames.size()) {
-                return null;
-            }
-            Set<ObjectId> objectIds = new HashSet<ObjectId>(objectSources.size());
-            for (int i = 0; i < objectSources.size(); i++) {
-                objectIds.add(ObjectId.newInstance(
-                        objectSources.get(i), objectNames.get(i).getBytes()));
-            }
-            return objectIds;
-        }
-
-        private IntentProtocol() {
-            // Disallow instantiation.
-        }
-    }
-
-    private static final Object LOCK = new Object();
-
-    private static InvalidationController sInstance;
-
-    private final Context mContext;
-
-    /**
-     * Sets the types for which the client should register for notifications.
-     *
-     * @param account  Account of the user.
-     * @param allTypes If {@code true}, registers for all types, and {@code types} is ignored
-     * @param types    Set of types for which to register. Ignored if {@code allTypes == true}.
-     */
-    public void setRegisteredTypes(Account account, boolean allTypes, Set<ModelType> types) {
-        Intent registerIntent = IntentProtocol.createRegisterIntent(account, allTypes, types);
-        registerIntent.setClass(mContext, InvalidationService.class);
-        mContext.startService(registerIntent);
-    }
-
-    /**
-     * Reads all stored preferences and calls
-     * {@link #setRegisteredTypes(android.accounts.Account, boolean, java.util.Set)} with the stored
-     * values, refreshing the set of types with {@code types}. It can be used on startup of Chrome
-     * to ensure we always have a set of registrations consistent with the native code.
-     * @param types    Set of types for which to register.
-     */
-    public void refreshRegisteredTypes(Set<ModelType> types) {
-        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
-        Set<String> savedSyncedTypes = invalidationPreferences.getSavedSyncedTypes();
-        Account account = invalidationPreferences.getSavedSyncedAccount();
-        boolean allTypes = savedSyncedTypes != null &&
-                savedSyncedTypes.contains(ModelType.ALL_TYPES_TYPE);
-        setRegisteredTypes(account, allTypes, types);
-    }
-
-    /**
-     * Sets object ids for which the client should register for notification. This is intended for
-     * registering non-Sync types; Sync types are registered with {@code setRegisteredTypes}.
-     *
-     * @param objectSources The sources of the objects.
-     * @param objectNames   The names of the objects.
-     */
-    @CalledByNative
-    public void setRegisteredObjectIds(int[] objectSources, String[] objectNames) {
-        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
-        Account account = invalidationPreferences.getSavedSyncedAccount();
-        Intent registerIntent = IntentProtocol.createRegisterIntent(account, objectSources,
-                objectNames);
-        registerIntent.setClass(mContext, InvalidationService.class);
-        mContext.startService(registerIntent);
-    }
-
-    /**
-     * Starts the invalidation client.
-     */
-    public void start() {
-        Intent intent = new Intent(mContext, InvalidationService.class);
-        mContext.startService(intent);
-    }
-
-    /**
-     * Stops the invalidation client.
-     */
-    public void stop() {
-        Intent intent = new Intent(mContext, InvalidationService.class);
-        intent.putExtra(IntentProtocol.EXTRA_STOP, true);
-        mContext.startService(intent);
-    }
-
-    /**
-     * Returns the instance that will use {@code context} to issue intents.
-     *
-     * Calling this method will create the instance if it does not yet exist.
-     */
-    @CalledByNative
-    public static InvalidationController get(Context context) {
-        synchronized (LOCK) {
-            if (sInstance == null) {
-                sInstance = new InvalidationController(context);
-            }
-            return sInstance;
-        }
-    }
-
-    /**
-     * Creates an instance using {@code context} to send intents.
-     */
-    @VisibleForTesting
-    InvalidationController(Context context) {
-        mContext = Preconditions.checkNotNull(context.getApplicationContext());
-        ActivityStatus.registerStateListener(this);
-    }
-
-    @Override
-    public void onActivityStateChange(int newState) {
-        if (SyncStatusHelper.get(mContext).isSyncEnabled()) {
-            if (newState == ActivityStatus.PAUSED) {
-                stop();
-            } else if (newState == ActivityStatus.RESUMED) {
-                start();
-            }
-        }
-    }
-}
diff --git a/sync/android/java/src/org/chromium/sync/notifier/InvalidationIntentProtocol.java b/sync/android/java/src/org/chromium/sync/notifier/InvalidationIntentProtocol.java
new file mode 100644
index 0000000..c87b894
--- /dev/null
+++ b/sync/android/java/src/org/chromium/sync/notifier/InvalidationIntentProtocol.java
@@ -0,0 +1,142 @@
+// Copyright 2013 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.sync.notifier;
+
+import android.accounts.Account;
+import android.content.Intent;
+
+import com.google.common.base.Preconditions;
+import com.google.ipc.invalidation.external.client.types.ObjectId;
+import com.google.protos.ipc.invalidation.Types;
+
+import org.chromium.base.CollectionUtil;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Constants and utility methods to create the intents used to communicate between the
+ * controller and the invalidation client library.
+ */
+public class InvalidationIntentProtocol {
+    /**
+     * Action set on register intents.
+     */
+    public static final String ACTION_REGISTER =
+            "org.chromium.sync.notifier.ACTION_REGISTER_TYPES";
+
+    /**
+     * Parcelable-valued intent extra containing the account of the user.
+     */
+    public static final String EXTRA_ACCOUNT = "account";
+
+    /**
+     * String-list-valued intent extra of the syncable types to sync.
+     */
+    public static final String EXTRA_REGISTERED_TYPES = "registered_types";
+
+    /**
+     * Int-array-valued intent extra containing sources of objects to register for.
+     * The array is parallel to EXTRA_REGISTERED_OBJECT_NAMES.
+     */
+    public static final String EXTRA_REGISTERED_OBJECT_SOURCES = "registered_object_sources";
+
+    /**
+     * String-array-valued intent extra containing names of objects to register for.
+     * The array is parallel to EXTRA_REGISTERED_OBJECT_SOURCES.
+     */
+    public static final String EXTRA_REGISTERED_OBJECT_NAMES = "registered_object_names";
+
+    /**
+     * Boolean-valued intent extra indicating that the service should be stopped.
+     */
+    public static final String EXTRA_STOP = "stop";
+
+    /**
+     * Create an Intent that will start the invalidation listener service and
+     * register for the specified types.
+     */
+    public static Intent createRegisterIntent(Account account,
+                                              boolean allTypes, Set<ModelType> types) {
+        Intent registerIntent = new Intent(ACTION_REGISTER);
+        String[] selectedTypesArray;
+        if (allTypes) {
+            selectedTypesArray = new String[]{ModelType.ALL_TYPES_TYPE};
+        } else {
+            selectedTypesArray = new String[types.size()];
+            int pos = 0;
+            for (ModelType type : types) {
+                selectedTypesArray[pos++] = type.name();
+            }
+        }
+        registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_TYPES,
+                CollectionUtil.newArrayList(selectedTypesArray));
+        registerIntent.putExtra(EXTRA_ACCOUNT, account);
+        return registerIntent;
+    }
+
+    /**
+     * Create an Intent that will start the invalidation listener service and
+     * register for the object ids with the specified sources and names.
+     * Sync-specific objects are filtered out of the request since Sync types
+     * are registered using the other version of createRegisterIntent.
+     */
+    public static Intent createRegisterIntent(Account account, int[] objectSources,
+            String[] objectNames) {
+        Preconditions.checkArgument(objectSources.length == objectNames.length,
+            "objectSources and objectNames must have the same length");
+
+        // Add all non-Sync objects to new lists.
+        ArrayList<Integer> sources = new ArrayList<Integer>();
+        ArrayList<String> names = new ArrayList<String>();
+        for (int i = 0; i < objectSources.length; i++) {
+            if (objectSources[i] != Types.ObjectSource.Type.CHROME_SYNC.getNumber()) {
+                sources.add(objectSources[i]);
+                names.add(objectNames[i]);
+            }
+        }
+
+        Intent registerIntent = new Intent(ACTION_REGISTER);
+        registerIntent.putIntegerArrayListExtra(EXTRA_REGISTERED_OBJECT_SOURCES, sources);
+        registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_OBJECT_NAMES, names);
+        registerIntent.putExtra(EXTRA_ACCOUNT, account);
+        return registerIntent;
+    }
+
+    /** Returns whether {@code intent} is a stop intent. */
+    public static boolean isStop(Intent intent) {
+        return intent.getBooleanExtra(EXTRA_STOP, false);
+    }
+
+    /** Returns whether {@code intent} is a registered types change intent. */
+    public static boolean isRegisteredTypesChange(Intent intent) {
+        return intent.hasExtra(EXTRA_REGISTERED_TYPES) ||
+                intent.hasExtra(EXTRA_REGISTERED_OBJECT_SOURCES);
+    }
+
+    /** Returns the object ids for which to register contained in the intent. */
+    public static Set<ObjectId> getRegisteredObjectIds(Intent intent) {
+        ArrayList<Integer> objectSources =
+                intent.getIntegerArrayListExtra(EXTRA_REGISTERED_OBJECT_SOURCES);
+        ArrayList<String> objectNames =
+                intent.getStringArrayListExtra(EXTRA_REGISTERED_OBJECT_NAMES);
+        if (objectSources == null || objectNames == null ||
+                objectSources.size() != objectNames.size()) {
+            return null;
+        }
+        Set<ObjectId> objectIds = new HashSet<ObjectId>(objectSources.size());
+        for (int i = 0; i < objectSources.size(); i++) {
+            objectIds.add(ObjectId.newInstance(
+                    objectSources.get(i), objectNames.get(i).getBytes()));
+        }
+        return objectIds;
+    }
+
+    private InvalidationIntentProtocol() {
+        // Disallow instantiation.
+    }
+}
diff --git a/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java b/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java
index 536f3b1..ea3e73a 100644
--- a/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java
+++ b/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java
@@ -22,7 +22,7 @@
 import org.chromium.base.ActivityStatus;
 import org.chromium.base.CollectionUtil;
 import org.chromium.sync.internal_api.pub.base.ModelType;
-import org.chromium.sync.notifier.InvalidationController.IntentProtocol;
+import org.chromium.sync.notifier.InvalidationIntentProtocol;
 import org.chromium.sync.notifier.InvalidationPreferences.EditContext;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
@@ -82,21 +82,22 @@
         // match the stored account. Then, if a client should be running, ensureClientStartState
         // will start a new one if needed. I.e., these two functions work together to restart the
         // client when the account changes.
-        Account account = intent.hasExtra(IntentProtocol.EXTRA_ACCOUNT) ?
-                (Account) intent.getParcelableExtra(IntentProtocol.EXTRA_ACCOUNT) : null;
+        Account account = intent.hasExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT) ?
+                (Account) intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT)
+                : null;
         ensureAccount(account);
         ensureClientStartState();
 
         // Handle the intent.
-        if (IntentProtocol.isStop(intent) && sIsClientStarted) {
+        if (InvalidationIntentProtocol.isStop(intent) && sIsClientStarted) {
             // If the intent requests that the client be stopped, stop it.
             stopClient();
-        } else if (IntentProtocol.isRegisteredTypesChange(intent)) {
+        } else if (InvalidationIntentProtocol.isRegisteredTypesChange(intent)) {
             // If the intent requests a change in registrations, change them.
-            List<String> regTypes =
-                    intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES);
+            List<String> regTypes = intent.getStringArrayListExtra(
+                    InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES);
             setRegisteredTypes(regTypes != null ? new HashSet<String>(regTypes) : null,
-                    IntentProtocol.getRegisteredObjectIds(intent));
+                    InvalidationIntentProtocol.getRegisteredObjectIds(intent));
         } else {
             // Otherwise, we don't recognize the intent. Pass it to the notification client service.
             super.onHandleIntent(intent);
diff --git a/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java b/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
index cde85e2..35414b1 100644
--- a/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
+++ b/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
@@ -4,7 +4,6 @@
 
 package org.chromium.sync.notifier;
 
-
 import android.accounts.Account;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -26,6 +25,8 @@
  * It also provides an observer to be used whenever Android sync settings change.
  *
  * To retrieve an instance of this class, call SyncStatusHelper.get(someContext).
+ *
+ * All new public methods MUST call notifyObservers at the end.
  */
 @ThreadSafe
 public class SyncStatusHelper {
@@ -38,19 +39,68 @@
      * expensive calls to Android are made.
      */
     @NotThreadSafe
-    private class CachedAccountSyncSettings {
+    @VisibleForTesting
+    public static class CachedAccountSyncSettings {
+        private final String mContractAuthority;
+        private final SyncContentResolverDelegate mSyncContentResolverWrapper;
         private Account mAccount;
+        private boolean mDidUpdate;
         private boolean mSyncAutomatically;
         private int mIsSyncable;
 
+        public CachedAccountSyncSettings(String contractAuthority,
+                SyncContentResolverDelegate contentResolverWrapper) {
+            mContractAuthority = contractAuthority;
+            mSyncContentResolverWrapper = contentResolverWrapper;
+        }
+
         private void ensureSettingsAreForAccount(Account account) {
             assert account != null;
             if (account.equals(mAccount)) return;
             updateSyncSettingsForAccount(account);
+            mDidUpdate = true;
+        }
+
+        public void clearUpdateStatus() {
+            mDidUpdate = false;
+        }
+
+        public boolean getDidUpdateStatus() {
+            return mDidUpdate;
+        }
+
+        // Calling this method may have side-effects.
+        public boolean getSyncAutomatically(Account account) {
+            ensureSettingsAreForAccount(account);
+            return mSyncAutomatically;
         }
 
         public void updateSyncSettingsForAccount(Account account) {
             if (account == null) return;
+            updateSyncSettingsForAccountInternal(account);
+        }
+
+        public void setIsSyncable(Account account) {
+            ensureSettingsAreForAccount(account);
+            if (mIsSyncable == 1) return;
+            setIsSyncableInternal(account);
+        }
+
+        public void setSyncAutomatically(Account account, boolean value) {
+            ensureSettingsAreForAccount(account);
+            if (mSyncAutomatically == value) return;
+            setSyncAutomaticallyInternal(account, value);
+        }
+
+        @VisibleForTesting
+        protected void updateSyncSettingsForAccountInternal(Account account) {
+            // Null check here otherwise Findbugs complains.
+            if (account == null) return;
+
+            boolean oldSyncAutomatically = mSyncAutomatically;
+            int oldIsSyncable = mIsSyncable;
+            Account oldAccount = mAccount;
+
             mAccount = account;
 
             StrictMode.ThreadPolicy oldPolicy = temporarilyAllowDiskWritesAndDiskReads();
@@ -58,31 +108,27 @@
                     account, mContractAuthority);
             mIsSyncable = mSyncContentResolverWrapper.getIsSyncable(account, mContractAuthority);
             StrictMode.setThreadPolicy(oldPolicy);
+            mDidUpdate = (oldIsSyncable != mIsSyncable)
+                || (oldSyncAutomatically != mSyncAutomatically)
+                || (!account.equals(oldAccount));
         }
 
-        public boolean getSyncAutomatically(Account account) {
-            ensureSettingsAreForAccount(account);
-            return mSyncAutomatically;
-        }
-
-        public void setIsSyncable(Account account) {
-            ensureSettingsAreForAccount(account);
-            if (mIsSyncable == 0) return;
-
+        @VisibleForTesting
+        protected void setIsSyncableInternal(Account account) {
             mIsSyncable = 1;
             StrictMode.ThreadPolicy oldPolicy = temporarilyAllowDiskWritesAndDiskReads();
             mSyncContentResolverWrapper.setIsSyncable(account, mContractAuthority, 1);
             StrictMode.setThreadPolicy(oldPolicy);
+            mDidUpdate = true;
         }
 
-        public void setSyncAutomatically(Account account, boolean value) {
-            ensureSettingsAreForAccount(account);
-            if (mSyncAutomatically == value) return;
-
+        @VisibleForTesting
+        protected void setSyncAutomaticallyInternal(Account account, boolean value) {
             mSyncAutomatically = value;
             StrictMode.ThreadPolicy oldPolicy = temporarilyAllowDiskWritesAndDiskReads();
             mSyncContentResolverWrapper.setSyncAutomatically(account, mContractAuthority, value);
             StrictMode.setThreadPolicy(oldPolicy);
+            mDidUpdate = true;
         }
     }
 
@@ -108,7 +154,7 @@
     private boolean mCachedMasterSyncAutomatically;
 
     // Instantiation of SyncStatusHelper is guarded by a lock so volatile is unneeded.
-    private final CachedAccountSyncSettings mCachedSettings = new CachedAccountSyncSettings();
+    private CachedAccountSyncSettings mCachedSettings;
 
     private final ObserverList<SyncSettingsChangedObserver> mObservers =
             new ObserverList<SyncSettingsChangedObserver>();
@@ -125,10 +171,12 @@
      * @param syncContentResolverWrapper an implementation of SyncContentResolverWrapper
      */
     private SyncStatusHelper(Context context,
-            SyncContentResolverDelegate syncContentResolverWrapper) {
+            SyncContentResolverDelegate syncContentResolverWrapper,
+            CachedAccountSyncSettings cachedAccountSettings) {
         mApplicationContext = context.getApplicationContext();
         mSyncContentResolverWrapper = syncContentResolverWrapper;
         mContractAuthority = getContractAuthority();
+        mCachedSettings = cachedAccountSettings;
 
         updateMasterSyncAutomaticallySetting();
 
@@ -159,8 +207,11 @@
     public static SyncStatusHelper get(Context context) {
         synchronized (INSTANCE_LOCK) {
             if (sSyncStatusHelper == null) {
-                sSyncStatusHelper = new SyncStatusHelper(context,
-                        new SystemSyncContentResolverDelegate());
+                SyncContentResolverDelegate contentResolverDelegate =
+                        new SystemSyncContentResolverDelegate();
+                CachedAccountSyncSettings cache = new CachedAccountSyncSettings(
+                        context.getPackageName(), contentResolverDelegate);
+                sSyncStatusHelper = new SyncStatusHelper(context, contentResolverDelegate, cache);
             }
         }
         return sSyncStatusHelper;
@@ -175,15 +226,26 @@
      */
     @VisibleForTesting
     public static void overrideSyncStatusHelperForTests(Context context,
-            SyncContentResolverDelegate syncContentResolverWrapper) {
+            SyncContentResolverDelegate syncContentResolverWrapper,
+            CachedAccountSyncSettings cachedAccountSettings) {
         synchronized (INSTANCE_LOCK) {
             if (sSyncStatusHelper != null) {
                 throw new IllegalStateException("SyncStatusHelper already exists");
             }
-            sSyncStatusHelper = new SyncStatusHelper(context, syncContentResolverWrapper);
+            sSyncStatusHelper = new SyncStatusHelper(context, syncContentResolverWrapper,
+                    cachedAccountSettings);
         }
     }
 
+    @VisibleForTesting
+    public static void overrideSyncStatusHelperForTests(Context context,
+            SyncContentResolverDelegate syncContentResolverWrapper) {
+        CachedAccountSyncSettings cachedAccountSettings = new CachedAccountSyncSettings(
+                context.getPackageName(), syncContentResolverWrapper);
+        overrideSyncStatusHelperForTests(context, syncContentResolverWrapper,
+                cachedAccountSettings);
+    }
+
     /**
      * Returns the contract authority to use when requesting sync.
      */
@@ -216,9 +278,14 @@
      */
     public boolean isSyncEnabled(Account account) {
         if (account == null) return false;
+        boolean returnValue;
         synchronized (mCachedSettings) {
-            return mCachedMasterSyncAutomatically && mCachedSettings.getSyncAutomatically(account);
+            returnValue = mCachedMasterSyncAutomatically &&
+                mCachedSettings.getSyncAutomatically(account);
         }
+
+        notifyObservers();
+        return returnValue;
     }
 
     /**
@@ -244,9 +311,14 @@
      */
     public boolean isSyncEnabledForChrome(Account account) {
         if (account == null) return false;
+
+        boolean returnValue;
         synchronized (mCachedSettings) {
-            return mCachedSettings.getSyncAutomatically(account);
+            returnValue = mCachedSettings.getSyncAutomatically(account);
         }
+
+        notifyObservers();
+        return returnValue;
     }
 
     /**
@@ -271,6 +343,8 @@
         synchronized (mCachedSettings) {
             mCachedSettings.setSyncAutomatically(account, true);
         }
+
+        notifyObservers();
     }
 
     /**
@@ -282,6 +356,8 @@
         synchronized (mCachedSettings) {
             mCachedSettings.setSyncAutomatically(account, false);
         }
+
+        notifyObservers();
     }
 
     /**
@@ -327,11 +403,7 @@
                     mCachedSettings.updateSyncSettingsForAccount(
                             ChromeSigninController.get(mApplicationContext).getSignedInUser());
                 }
-
-                // Notify anyone else that's interested
-                for (SyncSettingsChangedObserver observer: mObservers) {
-                    observer.syncSettingsChanged();
-                }
+                notifyObservers();
             }
         }
     }
@@ -354,4 +426,20 @@
         StrictMode.setThreadPolicy(newPolicy.build());
         return oldPolicy;
     }
+
+    private boolean getAndClearDidUpdateStatus() {
+        boolean didGetStatusUpdate;
+        synchronized (mCachedSettings) {
+            didGetStatusUpdate = mCachedSettings.getDidUpdateStatus();
+            mCachedSettings.clearUpdateStatus();
+        }
+        return didGetStatusUpdate;
+    }
+
+    private void notifyObservers() {
+        if (!getAndClearDidUpdateStatus()) return;
+        for (SyncSettingsChangedObserver observer: mObservers) {
+            observer.syncSettingsChanged();
+        }
+    }
 }
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
deleted file mode 100644
index f38eebf..0000000
--- a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright (c) 2013 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.sync.notifier;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
-import org.chromium.base.ActivityStatus;
-import org.chromium.base.CollectionUtil;
-import org.chromium.base.test.util.AdvancedMockContext;
-import org.chromium.base.test.util.Feature;
-import org.chromium.sync.internal_api.pub.base.ModelType;
-import org.chromium.sync.notifier.InvalidationController.IntentProtocol;
-import org.chromium.sync.signin.AccountManagerHelper;
-import org.chromium.sync.signin.ChromeSigninController;
-import org.chromium.sync.test.util.MockSyncContentResolverDelegate;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Tests for the {@link InvalidationController}.
- */
-public class InvalidationControllerTest extends InstrumentationTestCase {
-    private IntentSavingContext mContext;
-    private InvalidationController mController;
-
-    @Override
-    protected void setUp() throws Exception {
-        mContext = new IntentSavingContext(getInstrumentation().getTargetContext());
-        mController = InvalidationController.get(mContext);
-        // We don't want to use the system content resolver, so we override it.
-        MockSyncContentResolverDelegate delegate = new MockSyncContentResolverDelegate();
-        // Android master sync can safely always be on.
-        delegate.setMasterSyncAutomatically(true);
-        SyncStatusHelper.overrideSyncStatusHelperForTests(mContext, delegate);
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testStart() throws Exception {
-        mController.start();
-        assertEquals(1, mContext.getNumStartedIntents());
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertNull(intent.getExtras());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testStop() throws Exception {
-        mController.stop();
-        assertEquals(1, mContext.getNumStartedIntents());
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertEquals(1, intent.getExtras().size());
-        assertTrue(intent.hasExtra(IntentProtocol.EXTRA_STOP));
-        assertTrue(intent.getBooleanExtra(IntentProtocol.EXTRA_STOP, false));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testResumingMainActivity() throws Exception {
-        // Resuming main activity should trigger a start if sync is enabled.
-        setupSync(true);
-        mController.onActivityStateChange(ActivityStatus.RESUMED);
-        assertEquals(1, mContext.getNumStartedIntents());
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertNull(intent.getExtras());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testResumingMainActivityWithSyncDisabled() throws Exception {
-        // Resuming main activity should NOT trigger a start if sync is disabled.
-        setupSync(false);
-        mController.onActivityStateChange(ActivityStatus.RESUMED);
-        assertEquals(0, mContext.getNumStartedIntents());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testPausingMainActivity() throws Exception {
-        // Resuming main activity should trigger a stop if sync is enabled.
-        setupSync(true);
-        mController.onActivityStateChange(ActivityStatus.PAUSED);
-        assertEquals(1, mContext.getNumStartedIntents());
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertEquals(1, intent.getExtras().size());
-        assertTrue(intent.hasExtra(IntentProtocol.EXTRA_STOP));
-        assertTrue(intent.getBooleanExtra(IntentProtocol.EXTRA_STOP, false));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testPausingMainActivityWithSyncDisabled() throws Exception {
-        // Resuming main activity should NOT trigger a stop if sync is disabled.
-        setupSync(false);
-        mController.onActivityStateChange(ActivityStatus.PAUSED);
-        assertEquals(0, mContext.getNumStartedIntents());
-    }
-
-    private void setupSync(boolean syncEnabled) {
-        Account account = AccountManagerHelper.createAccountFromName("test@gmail.com");
-        ChromeSigninController chromeSigninController = ChromeSigninController.get(mContext);
-        chromeSigninController.setSignedInAccountName(account.name);
-        SyncStatusHelper syncStatusHelper = SyncStatusHelper.get(mContext);
-        if (syncEnabled) {
-            syncStatusHelper.enableAndroidSync(account);
-        } else {
-            syncStatusHelper.disableAndroidSync(account);
-        }
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testEnsureConstructorRegistersListener() throws Exception {
-        final AtomicBoolean listenerCallbackCalled = new AtomicBoolean();
-
-        // Create instance.
-        new InvalidationController(mContext) {
-            @Override
-            public void onActivityStateChange(int newState) {
-                listenerCallbackCalled.set(true);
-            }
-        };
-
-        // Ensure initial state is correct.
-        assertFalse(listenerCallbackCalled.get());
-
-        // Ensure we get a callback, which means we have registered for them.
-        ActivityStatus.onStateChangeForTesting(new Activity(), ActivityStatus.RESUMED);
-        assertTrue(listenerCallbackCalled.get());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testRegisterForSpecificTypes() {
-        InvalidationController controller = new InvalidationController(mContext);
-        Account account = new Account("test@example.com", "bogus");
-        controller.setRegisteredTypes(account, false,
-                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
-        assertEquals(1, mContext.getNumStartedIntents());
-
-        // Validate destination.
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertEquals(IntentProtocol.ACTION_REGISTER, intent.getAction());
-
-        // Validate account.
-        Account intentAccount = intent.getParcelableExtra(IntentProtocol.EXTRA_ACCOUNT);
-        assertEquals(account, intentAccount);
-
-        // Validate registered types.
-        Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.BOOKMARK.name(),
-                ModelType.SESSION.name());
-        Set<String> actualTypes = new HashSet<String>();
-        actualTypes.addAll(intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES));
-        assertEquals(expectedTypes, actualTypes);
-        assertNull(IntentProtocol.getRegisteredObjectIds(intent));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testRegisterForAllTypes() {
-        Account account = new Account("test@example.com", "bogus");
-        mController.setRegisteredTypes(account, true,
-                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
-        assertEquals(1, mContext.getNumStartedIntents());
-
-        // Validate destination.
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertEquals(IntentProtocol.ACTION_REGISTER, intent.getAction());
-
-        // Validate account.
-        Account intentAccount = intent.getParcelableExtra(IntentProtocol.EXTRA_ACCOUNT);
-        assertEquals(account, intentAccount);
-
-        // Validate registered types.
-        Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE);
-        Set<String> actualTypes = new HashSet<String>();
-        actualTypes.addAll(intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES));
-        assertEquals(expectedTypes, actualTypes);
-        assertNull(IntentProtocol.getRegisteredObjectIds(intent));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testRefreshShouldReadValuesFromDiskWithSpecificTypes() {
-        // Store some preferences for ModelTypes and account. We are using the helper class
-        // for this, so we don't have to deal with low-level details such as preference keys.
-        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
-        InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
-        Set<String> storedModelTypes = new HashSet<String>();
-        storedModelTypes.add(ModelType.BOOKMARK.name());
-        storedModelTypes.add(ModelType.TYPED_URL.name());
-        Set<ModelType> refreshedTypes = new HashSet<ModelType>();
-        refreshedTypes.add(ModelType.BOOKMARK);
-        refreshedTypes.add(ModelType.TYPED_URL);
-        invalidationPreferences.setSyncTypes(edit, storedModelTypes);
-        Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
-        invalidationPreferences.setAccount(edit, storedAccount);
-        invalidationPreferences.commit(edit);
-
-        // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
-        // we can inspect in the test.
-        final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
-        final AtomicBoolean resultAllTypes = new AtomicBoolean();
-        final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
-        InvalidationController controller = new InvalidationController(mContext) {
-            @Override
-            public void setRegisteredTypes(
-                    Account account, boolean allTypes, Set<ModelType> types) {
-                resultAccount.set(account);
-                resultAllTypes.set(allTypes);
-                resultTypes.set(types);
-            }
-        };
-
-        // Execute the test.
-        controller.refreshRegisteredTypes(refreshedTypes);
-
-        // Validate the values.
-        assertEquals(storedAccount, resultAccount.get());
-        assertEquals(false, resultAllTypes.get());
-        assertEquals(ModelType.syncTypesToModelTypes(storedModelTypes), resultTypes.get());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testRefreshShouldReadValuesFromDiskWithAllTypes() {
-        // Store preferences for the ModelType.ALL_TYPES_TYPE and account. We are using the
-        // helper class for this, so we don't have to deal with low-level details such as preference
-        // keys.
-        InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
-        InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
-        List<String> storedModelTypes = new ArrayList<String>();
-        storedModelTypes.add(ModelType.ALL_TYPES_TYPE);
-        invalidationPreferences.setSyncTypes(edit, storedModelTypes);
-        Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
-        invalidationPreferences.setAccount(edit, storedAccount);
-        invalidationPreferences.commit(edit);
-
-        // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
-        // we can inspect in the test.
-        final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
-        final AtomicBoolean resultAllTypes = new AtomicBoolean();
-        final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
-        InvalidationController controller = new InvalidationController(mContext) {
-            @Override
-            public void setRegisteredTypes(
-                    Account account, boolean allTypes, Set<ModelType> types) {
-                resultAccount.set(account);
-                resultAllTypes.set(allTypes);
-                resultTypes.set(types);
-            }
-        };
-
-        // Execute the test.
-        controller.refreshRegisteredTypes(new HashSet<ModelType>());
-
-        // Validate the values.
-        assertEquals(storedAccount, resultAccount.get());
-        assertEquals(true, resultAllTypes.get());
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testSetRegisteredObjectIds() {
-        InvalidationController controller = new InvalidationController(mContext);
-        ObjectId bookmark = ModelType.BOOKMARK.toObjectId();
-        controller.setRegisteredObjectIds(new int[] {1, 2, bookmark.getSource()},
-                                          new String[] {"a", "b", new String(bookmark.getName())});
-        assertEquals(1, mContext.getNumStartedIntents());
-
-        // Validate destination.
-        Intent intent = mContext.getStartedIntent(0);
-        validateIntentComponent(intent);
-        assertEquals(IntentProtocol.ACTION_REGISTER, intent.getAction());
-
-        // Validate registered object ids. The bookmark object should not be registered since it is
-        // a Sync type.
-        assertNull(intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES));
-        Set<ObjectId> objectIds = IntentProtocol.getRegisteredObjectIds(intent);
-        assertEquals(2, objectIds.size());
-        assertTrue(objectIds.contains(ObjectId.newInstance(1, "a".getBytes())));
-        assertTrue(objectIds.contains(ObjectId.newInstance(2, "b".getBytes())));
-    }
-
-    /**
-     * Asserts that {@code intent} is destined for the correct component.
-     */
-    private static void validateIntentComponent(Intent intent) {
-        assertNotNull(intent.getComponent());
-        assertEquals(InvalidationService.class.getName(),
-                intent.getComponent().getClassName());
-    }
-
-    /**
-     * Mock context that saves all intents given to {@code startService}.
-     */
-    private static class IntentSavingContext extends AdvancedMockContext {
-        private final List<Intent> startedIntents = new ArrayList<Intent>();
-
-        IntentSavingContext(Context targetContext) {
-            super(targetContext);
-        }
-
-        @Override
-        public ComponentName startService(Intent intent) {
-            startedIntents.add(intent);
-            return new ComponentName(this, getClass());
-        }
-
-        int getNumStartedIntents() {
-            return startedIntents.size();
-        }
-
-        Intent getStartedIntent(int idx) {
-            return startedIntents.get(idx);
-        }
-
-        @Override
-        public PackageManager getPackageManager() {
-            return getBaseContext().getPackageManager();
-        }
-    }
-}
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java
index fd8e070..f0d021a 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java
@@ -21,7 +21,7 @@
 import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.Feature;
 import org.chromium.sync.internal_api.pub.base.ModelType;
-import org.chromium.sync.notifier.InvalidationController.IntentProtocol;
+import org.chromium.sync.notifier.InvalidationIntentProtocol;
 import org.chromium.sync.notifier.InvalidationPreferences.EditContext;
 import org.chromium.sync.signin.AccountManagerHelper;
 
@@ -65,7 +65,7 @@
     @Override
     public void tearDown() throws Exception {
         if (InvalidationService.getIsClientStartedForTest()) {
-            Intent stopIntent = new Intent().putExtra(IntentProtocol.EXTRA_STOP, true);
+            Intent stopIntent = new Intent().putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
             getService().onHandleIntent(stopIntent);
         }
         assertFalse(InvalidationService.getIsClientStartedForTest());
@@ -469,7 +469,7 @@
         getService().onHandleIntent(startIntent);
         assertTrue(InvalidationService.getIsClientStartedForTest());
 
-        Intent stopIntent = new Intent().putExtra(IntentProtocol.EXTRA_STOP, true);
+        Intent stopIntent = new Intent().putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
         getService().onHandleIntent(stopIntent);
         assertFalse(InvalidationService.getIsClientStartedForTest());
 
@@ -523,7 +523,7 @@
         Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet(
                 ModelType.BOOKMARK, ModelType.SESSION);
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
-        Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
+        Intent registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false,
                 desiredRegistrations);
         getService().onHandleIntent(registrationIntent);
 
@@ -539,7 +539,8 @@
 
         // Send another registration-change intent, this type with all-types set to true, and
         // verify that the on-disk state is updated and that no addition Intents are issued.
-        getService().onHandleIntent(IntentProtocol.createRegisterIntent(account, true, null));
+        getService().onHandleIntent(
+                InvalidationIntentProtocol.createRegisterIntent(account, true, null));
         assertEquals(account, invPrefs.getSavedSyncedAccount());
         assertEquals(CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE),
                 invPrefs.getSavedSyncedTypes());
@@ -549,7 +550,8 @@
         // and verify that it both updates the account, stops thye existing client, and
         // starts a new client.
         Account account2 = AccountManagerHelper.createAccountFromName("test2@example.com");
-        getService().onHandleIntent(IntentProtocol.createRegisterIntent(account2, true, null));
+        getService().onHandleIntent(
+                InvalidationIntentProtocol.createRegisterIntent(account2, true, null));
         assertEquals(account2, invPrefs.getSavedSyncedAccount());
         assertEquals(3, mStartServiceIntents.size());
         assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0)));
@@ -611,15 +613,16 @@
         // Register for some object ids.
         objectIds.add(ObjectId.newInstance(1, "obj1".getBytes()));
         objectIds.add(ObjectId.newInstance(2, "obj2".getBytes()));
-        Intent registrationIntent = IntentProtocol.createRegisterIntent(account, new int[] {1, 2},
-                new String[] {"obj1", "obj2"});
+        Intent registrationIntent =
+                InvalidationIntentProtocol.createRegisterIntent(account, new int[] {1, 2},
+                        new String[] {"obj1", "obj2"});
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, false /* isReady */));
 
         // Register for some types.
         types.add(ModelType.BOOKMARK);
         types.add(ModelType.SESSION);
-        registrationIntent = IntentProtocol.createRegisterIntent(account, false, types);
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false, types);
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, false /* isReady */));
 
@@ -629,33 +632,35 @@
 
         // Change object id registration with types registered.
         objectIds.add(ObjectId.newInstance(3, "obj3".getBytes()));
-        registrationIntent = IntentProtocol.createRegisterIntent(account, new int[] {1, 2, 3},
-                new String[] {"obj1", "obj2", "obj3"});
+        registrationIntent =
+                InvalidationIntentProtocol.createRegisterIntent(account, new int[] {1, 2, 3},
+                        new String[] {"obj1", "obj2", "obj3"});
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
 
         // Change type registration with object ids registered.
         types.remove(ModelType.BOOKMARK);
-        registrationIntent = IntentProtocol.createRegisterIntent(account, false, types);
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false, types);
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
 
         // Unregister all types.
         types.clear();
-        registrationIntent = IntentProtocol.createRegisterIntent(account, false, types);
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false, types);
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
 
         // Change object id registration with no types registered.
         objectIds.remove(ObjectId.newInstance(2, "obj2".getBytes()));
-        registrationIntent = IntentProtocol.createRegisterIntent(account, new int[] {1, 3},
-                new String[] {"obj1", "obj3"});
+        registrationIntent =
+                InvalidationIntentProtocol.createRegisterIntent(account, new int[] {1, 3},
+                        new String[] {"obj1", "obj3"});
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
 
         // Unregister all object ids.
         objectIds.clear();
-        registrationIntent = IntentProtocol.createRegisterIntent(account, new int[0],
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, new int[0],
                 new String[0]);
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
@@ -663,7 +668,7 @@
         // Change type registration with no object ids registered.
         types.add(ModelType.BOOKMARK);
         types.add(ModelType.PASSWORD);
-        registrationIntent = IntentProtocol.createRegisterIntent(account, false, types);
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false, types);
         getService().onHandleIntent(registrationIntent);
         assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady */));
     }
@@ -676,7 +681,8 @@
 
         // Send register Intent.
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
-        Intent registrationIntent = IntentProtocol.createRegisterIntent(account, true, null);
+        Intent registrationIntent =
+                InvalidationIntentProtocol.createRegisterIntent(account, true, null);
         getService().onHandleIntent(registrationIntent);
 
         // Verify client started and state written.
@@ -706,8 +712,8 @@
 
         // Send register Intent with no desired types.
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
-        Intent registrationIntent =
-                IntentProtocol.createRegisterIntent(account, false, new HashSet<ModelType>());
+        Intent registrationIntent = InvalidationIntentProtocol.createRegisterIntent(
+                account, false, new HashSet<ModelType>());
         getService().onHandleIntent(registrationIntent);
 
         // Verify client started and state written.
@@ -723,7 +729,7 @@
         assertTrue(Arrays.equals(CLIENT_ID, InvalidationService.getClientIdForTest()));
 
         // Choose to register for all types in an already ready client.
-        registrationIntent = IntentProtocol.createRegisterIntent(account, true, null);
+        registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, true, null);
         getService().onHandleIntent(registrationIntent);
 
         // Ensure registrations are correct.
@@ -746,7 +752,7 @@
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
         Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet(
                 ModelType.BOOKMARK, ModelType.SESSION);
-        Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
+        Intent registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false,
                 desiredRegistrations);
         getService().onHandleIntent(registrationIntent);
 
@@ -776,7 +782,7 @@
                 ModelType.BOOKMARK, ModelType.SESSION);
         Set<ObjectId> desiredObjectIds = ModelType.modelTypesToObjectIds(desiredRegistrations);
 
-        Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
+        Intent registrationIntent = InvalidationIntentProtocol.createRegisterIntent(account, false,
                 desiredRegistrations);
         getService().onHandleIntent(registrationIntent);
         assertTrue(InvalidationService.getIsClientStartedForTest());
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/signin/SyncStatusHelperTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/signin/SyncStatusHelperTest.java
index a2e83bc..44007cb 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/signin/SyncStatusHelperTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/signin/SyncStatusHelperTest.java
@@ -5,13 +5,15 @@
 package org.chromium.sync.notifier.signin;
 
 import android.accounts.Account;
+import android.content.Context;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
-import org.chromium.sync.notifier.InvalidationController;
 import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.notifier.SyncStatusHelper.CachedAccountSyncSettings;
+import org.chromium.sync.notifier.SyncStatusHelper.SyncSettingsChangedObserver;
 import org.chromium.sync.signin.ChromeSigninController;
 import org.chromium.sync.test.util.MockSyncContentResolverDelegate;
 
@@ -22,6 +24,8 @@
         private int mGetMasterSyncAutomaticallyCalls;
         private int mGetSyncAutomaticallyCalls;
         private int mGetIsSyncableCalls;
+        private int mSetIsSyncableCalls;
+        private int mSetSyncAutomaticallyCalls;
 
         @Override
         public boolean getMasterSyncAutomatically() {
@@ -40,23 +44,86 @@
             mGetIsSyncableCalls++;
             return super.getIsSyncable(account, authority);
         }
+
+        @Override
+        public void setIsSyncable(Account account, String authority, int syncable) {
+            mSetIsSyncableCalls++;
+            super.setIsSyncable(account, authority, syncable);
+        }
+
+        @Override
+        public void setSyncAutomatically(Account account, String authority, boolean sync) {
+            mSetSyncAutomaticallyCalls++;
+            super.setSyncAutomatically(account, authority, sync);
+        }
+    }
+
+    private static class CountingCachedAccountSyncSettings extends CachedAccountSyncSettings {
+        private int mUpdateSyncSettingsForAccountInternalCalls;
+        private int mSetIsSyncableInternalCalls;
+        private int mSetSyncAutomaticallyInternalCalls;
+
+        public CountingCachedAccountSyncSettings(String contractAuthority,
+                MockSyncContentResolverDelegate contentResolverWrapper) {
+            super(contractAuthority, contentResolverWrapper);
+        }
+
+        @Override
+        protected void updateSyncSettingsForAccountInternal(Account account) {
+            mUpdateSyncSettingsForAccountInternalCalls++;
+            super.updateSyncSettingsForAccountInternal(account);
+        }
+
+        @Override
+        protected void setIsSyncableInternal(Account account) {
+            mSetIsSyncableInternalCalls++;
+            super.setIsSyncableInternal(account);
+        }
+
+        @Override
+        protected void setSyncAutomaticallyInternal(Account account, boolean value) {
+            mSetSyncAutomaticallyInternalCalls++;
+            super.setSyncAutomaticallyInternal(account, value);
+        }
+
+        public void resetCount() {
+            mUpdateSyncSettingsForAccountInternalCalls = 0;
+        }
+    }
+
+    private static class MockSyncSettingsObserver implements SyncSettingsChangedObserver {
+        private boolean mReceivedNotification;
+
+        public void clearNotification() {
+            mReceivedNotification = false;
+        }
+
+        public boolean didReceiveNotification() {
+            return mReceivedNotification;
+        }
+
+        @Override
+        public void syncSettingsChanged() {
+            mReceivedNotification = true;
+        }
     }
 
     private SyncStatusHelper mHelper;
-
     private CountingMockSyncContentResolverDelegate mSyncContentResolverDelegate;
-
     private String mAuthority;
-
     private Account mTestAccount;
-
     private Account mAlternateTestAccount;
+    private CountingCachedAccountSyncSettings mCachedAccountSyncSettings;
+    private MockSyncSettingsObserver mSyncSettingsObserver;
 
     @Override
     protected void setUp() throws Exception {
         mSyncContentResolverDelegate = new CountingMockSyncContentResolverDelegate();
+        Context context = getInstrumentation().getTargetContext();
+        mCachedAccountSyncSettings = new CountingCachedAccountSyncSettings(
+                context.getPackageName(), mSyncContentResolverDelegate);
         SyncStatusHelper.overrideSyncStatusHelperForTests(
-                getInstrumentation().getTargetContext(), mSyncContentResolverDelegate);
+                context, mSyncContentResolverDelegate, mCachedAccountSyncSettings);
         mHelper = SyncStatusHelper.get(getInstrumentation().getTargetContext());
         // Need to set the signed in account name to ensure that sync settings notifications
         // update the right account.
@@ -67,6 +134,10 @@
                 .getContractAuthority();
         mTestAccount = new Account("account@example.com", "com.google");
         mAlternateTestAccount = new Account("alternateAccount@example.com", "com.google");
+
+        mSyncSettingsObserver = new MockSyncSettingsObserver();
+        mHelper.registerSyncSettingsChangedObserver(mSyncSettingsObserver);
+
         super.setUp();
     }
 
@@ -242,4 +313,144 @@
                 getInstrumentation().getTargetContext().getPackageName(),
                 mHelper.getContractAuthority());
     }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testCachedAccountSyncSettingsExitEarly() throws InterruptedException {
+        mSyncContentResolverDelegate.disableObserverNotifications();
+
+        mCachedAccountSyncSettings.updateSyncSettingsForAccount(null);
+        assertTrue("Update sync settings failed to exit early", mCachedAccountSyncSettings.
+                mUpdateSyncSettingsForAccountInternalCalls == 0);
+
+        mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount);
+        assertTrue("Update sync settings should not have exited early", mCachedAccountSyncSettings.
+                mUpdateSyncSettingsForAccountInternalCalls == 1);
+
+        mCachedAccountSyncSettings.setIsSyncable(mTestAccount);
+        assertTrue("setIsSyncable should not have exited early",
+                mCachedAccountSyncSettings.mSetIsSyncableInternalCalls == 1);
+
+        mCachedAccountSyncSettings.setIsSyncable(mTestAccount);
+        assertTrue("setIsSyncable failed to exit early", mCachedAccountSyncSettings.
+                mSetIsSyncableInternalCalls == 1);
+
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true);
+        assertTrue("setSyncAutomatically should not have to exited early",
+                mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 1);
+
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true);
+        assertTrue("setSyncAutomatically failed to exit early",
+                mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 1);
+
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false);
+        assertTrue("setSyncAutomatically should not have to exited early",
+                mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 2);
+
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false);
+        assertTrue("setSyncAutomatically failed to exit early",
+                mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 2);
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testCachedAccountSyncSettingsDidUpdate() throws InterruptedException {
+        // Since we're just testing the cache we disable observer notifications to prevent
+        // notifications to SyncStatusHelper from mutating it.
+        mSyncContentResolverDelegate.disableObserverNotifications();
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.getSyncAutomatically(mTestAccount);
+        assertTrue("getSyncAutomatically on un-populated cache failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.getSyncAutomatically(mTestAccount);
+        assertFalse("getSyncAutomatically on populated cache updated DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.updateSyncSettingsForAccount(mAlternateTestAccount);
+        assertTrue("updateSyncSettingsForAccount failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+
+        mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount);
+        assertTrue("updateSyncSettingsForAccount failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+
+        mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount);
+        assertFalse("updateSyncSettingsForAccount updated DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setIsSyncable(mTestAccount);
+        assertTrue("setIsSyncable failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setIsSyncable(mTestAccount);
+        assertFalse("setIsSyncable updated DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true);
+        assertTrue("setSyncAutomatically failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true);
+        assertFalse("setSyncAutomatically updated DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false);
+        assertTrue("setSyncAutomatically failed to update DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+
+        mCachedAccountSyncSettings.clearUpdateStatus();
+        mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false);
+        assertFalse("setSyncAutomatically updated DidUpdate flag",
+                mCachedAccountSyncSettings.getDidUpdateStatus());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSyncStatusHelperPostsNotifications() throws InterruptedException {
+        // Turn on syncability.
+        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
+        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.isSyncEnabled(mAlternateTestAccount);
+        assertTrue("isSyncEnabled on wrongly populated cache did not trigger observers",
+                mSyncSettingsObserver.didReceiveNotification());
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.isSyncEnabled(mTestAccount);
+        assertTrue("isSyncEnabled on wrongly populated cache did not trigger observers",
+                mSyncSettingsObserver.didReceiveNotification());
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.enableAndroidSync(mTestAccount);
+        assertTrue("enableAndroidSync did not trigger observers",
+                mSyncSettingsObserver.didReceiveNotification());
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.enableAndroidSync(mTestAccount);
+        assertFalse("enableAndroidSync triggered observers",
+                mSyncSettingsObserver.didReceiveNotification());
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.disableAndroidSync(mTestAccount);
+        assertTrue("disableAndroidSync did not trigger observers",
+                mSyncSettingsObserver.didReceiveNotification());
+
+        mSyncSettingsObserver.clearNotification();
+        mHelper.disableAndroidSync(mTestAccount);
+        assertFalse("disableAndroidSync triggered observers",
+                mSyncSettingsObserver.didReceiveNotification());
+    }
 }
diff --git a/sync/engine/all_status.cc b/sync/engine/all_status.cc
index af3d4fc..e5f5124 100644
--- a/sync/engine/all_status.cc
+++ b/sync/engine/all_status.cc
@@ -101,7 +101,6 @@
       status_ = CalcSyncing(event);
       break;
     case SyncEngineEvent::STOP_SYNCING_PERMANENTLY:
-    case SyncEngineEvent::UPDATED_TOKEN:
        break;
     case SyncEngineEvent::ACTIONABLE_ERROR:
       status_ = CreateBlankStatus();
diff --git a/sync/engine/download.cc b/sync/engine/download.cc
index acda834..9b74417 100644
--- a/sync/engine/download.cc
+++ b/sync/engine/download.cc
@@ -7,8 +7,8 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "sync/engine/process_updates_command.h"
-#include "sync/engine/store_timestamps_command.h"
+#include "sync/engine/process_updates_util.h"
+#include "sync/engine/sync_directory_update_handler.h"
 #include "sync/engine/syncer.h"
 #include "sync/engine/syncer_proto_util.h"
 #include "sync/sessions/nudge_tracker.h"
@@ -27,6 +27,8 @@
 
 namespace {
 
+typedef std::map<ModelType, size_t> TypeToIndexMap;
+
 SyncerError HandleGetEncryptionKeyResponse(
     const sync_pb::ClientToServerResponse& update_response,
     syncable::Directory* dir) {
@@ -98,7 +100,7 @@
     SyncSession* session,
     bool create_mobile_bookmarks_folder,
     sync_pb::ClientToServerMessage* message,
-    ModelTypeSet request_types) {
+    ModelTypeSet proto_request_types) {
   message->set_share(session->context()->account_name());
   message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES);
 
@@ -122,19 +124,93 @@
       session->context()->notifications_enabled());
 
   StatusController* status = session->mutable_status_controller();
-  status->set_updates_request_types(request_types);
+  status->set_updates_request_types(proto_request_types);
 
-  syncable::Directory* dir = session->context()->directory();
-  for (ModelTypeSet::Iterator it = request_types.First();
+  UpdateHandlerMap* handler_map = session->context()->update_handler_map();
+
+  for (ModelTypeSet::Iterator it = proto_request_types.First();
        it.Good(); it.Inc()) {
-    if (ProxyTypes().Has(it.Get()))
-      continue;
+    UpdateHandlerMap::iterator handler_it = handler_map->find(it.Get());
+    DCHECK(handler_it != handler_map->end());
     sync_pb::DataTypeProgressMarker* progress_marker =
         get_updates->add_from_progress_marker();
-    dir->GetDownloadProgress(it.Get(), progress_marker);
+    handler_it->second->GetDownloadProgress(progress_marker);
   }
 }
 
+// Builds a map of ModelTypes to indices to progress markers in the given
+// |gu_response| message.  The map is returned in the |index_map| parameter.
+void PartitionProgressMarkersByType(
+    const sync_pb::GetUpdatesResponse& gu_response,
+    ModelTypeSet request_types,
+    TypeToIndexMap* index_map) {
+  for (int i = 0; i < gu_response.new_progress_marker_size(); ++i) {
+    int field_number = gu_response.new_progress_marker(i).data_type_id();
+    ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
+    if (!IsRealDataType(model_type)) {
+      DLOG(WARNING) << "Unknown field number " << field_number;
+      continue;
+    }
+    if (!request_types.Has(model_type)) {
+      DLOG(WARNING)
+          << "Skipping unexpected progress marker for non-enabled type "
+          << ModelTypeToString(model_type);
+      continue;
+    }
+    index_map->insert(std::make_pair(model_type, i));
+  }
+}
+
+// Examines the contents of the GetUpdates response message and forwards
+// relevant data to the UpdateHandlers for processing and persisting.
+bool ProcessUpdateResponseMessage(
+    const sync_pb::GetUpdatesResponse& gu_response,
+    ModelTypeSet proto_request_types,
+    UpdateHandlerMap* handler_map,
+    StatusController* status) {
+  TypeSyncEntityMap updates_by_type;
+  PartitionUpdatesByType(gu_response, proto_request_types, &updates_by_type);
+  DCHECK_EQ(proto_request_types.Size(), updates_by_type.size());
+
+  TypeToIndexMap progress_index_by_type;
+  PartitionProgressMarkersByType(gu_response,
+                                 proto_request_types,
+                                 &progress_index_by_type);
+  if (proto_request_types.Size() != progress_index_by_type.size()) {
+    NOTREACHED() << "Missing progress markers in GetUpdates response.";
+    return false;
+  }
+
+  // Iterate over these maps in parallel, processing updates for each type.
+  TypeToIndexMap::iterator progress_marker_iter =
+      progress_index_by_type.begin();
+  TypeSyncEntityMap::iterator updates_iter = updates_by_type.begin();
+  for ( ; (progress_marker_iter != progress_index_by_type.end()
+           && updates_iter != updates_by_type.end());
+       ++progress_marker_iter, ++updates_iter) {
+    DCHECK_EQ(progress_marker_iter->first, updates_iter->first);
+    ModelType type = progress_marker_iter->first;
+
+    UpdateHandlerMap::iterator update_handler_iter = handler_map->find(type);
+
+    if (update_handler_iter != handler_map->end()) {
+      update_handler_iter->second->ProcessGetUpdatesResponse(
+          gu_response.new_progress_marker(progress_marker_iter->second),
+          updates_iter->second,
+          status);
+    } else {
+      DLOG(WARNING)
+          << "Ignoring received updates of a type we can't handle.  "
+          << "Type is: " << ModelTypeToString(type);
+      continue;
+    }
+  }
+  DCHECK(progress_marker_iter == progress_index_by_type.end()
+         && updates_iter == updates_by_type.end());
+
+  return true;
+}
+
 }  // namespace
 
 void BuildNormalDownloadUpdates(
@@ -147,7 +223,7 @@
       session,
       create_mobile_bookmarks_folder,
       client_to_server_message,
-      request_types);
+      Intersection(request_types, ProtocolTypes()));
   sync_pb::GetUpdatesMessage* get_updates =
       client_to_server_message->mutable_get_updates();
 
@@ -190,7 +266,7 @@
       session,
       create_mobile_bookmarks_folder,
       client_to_server_message,
-      request_types);
+      Intersection(request_types, ProtocolTypes()));
   sync_pb::GetUpdatesMessage* get_updates =
       client_to_server_message->mutable_get_updates();
 
@@ -217,7 +293,7 @@
       session,
       create_mobile_bookmarks_folder,
       client_to_server_message,
-      request_types);
+      Intersection(request_types, ProtocolTypes()));
   sync_pb::GetUpdatesMessage* get_updates =
       client_to_server_message->mutable_get_updates();
 
@@ -234,6 +310,7 @@
 }
 
 SyncerError ExecuteDownloadUpdates(
+    ModelTypeSet request_types,
     SyncSession* session,
     sync_pb::ClientToServerMessage* msg) {
   sync_pb::ClientToServerResponse update_response;
@@ -251,30 +328,41 @@
   if (result != SYNCER_OK) {
     status->mutable_updates_response()->Clear();
     LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
-  } else {
-    status->mutable_updates_response()->CopyFrom(update_response);
-
-    DVLOG(1) << "GetUpdates "
-             << " returned " << update_response.get_updates().entries_size()
-             << " updates and indicated "
-             << update_response.get_updates().changes_remaining()
-             << " updates left on server.";
-
-    if (need_encryption_key ||
-        update_response.get_updates().encryption_keys_size() > 0) {
-      syncable::Directory* dir = session->context()->directory();
-      status->set_last_get_key_result(
-          HandleGetEncryptionKeyResponse(update_response, dir));
-    }
+    return result;
   }
 
-  ProcessUpdatesCommand process_updates;
-  process_updates.Execute(session);
+  status->mutable_updates_response()->CopyFrom(update_response);
 
-  StoreTimestampsCommand store_timestamps;
-  store_timestamps.Execute(session);
+  DVLOG(1) << "GetUpdates "
+           << " returned " << update_response.get_updates().entries_size()
+           << " updates and indicated "
+           << update_response.get_updates().changes_remaining()
+           << " updates left on server.";
 
-  return result;
+  if (need_encryption_key ||
+      update_response.get_updates().encryption_keys_size() > 0) {
+    syncable::Directory* dir = session->context()->directory();
+    status->set_last_get_key_result(
+        HandleGetEncryptionKeyResponse(update_response, dir));
+  }
+
+  const sync_pb::GetUpdatesResponse& gu_response =
+      update_response.get_updates();
+  status->increment_num_updates_downloaded_by(gu_response.entries_size());
+  DCHECK(gu_response.has_changes_remaining());
+  status->set_num_server_changes_remaining(gu_response.changes_remaining());
+
+  const ModelTypeSet proto_request_types =
+      Intersection(request_types, ProtocolTypes());
+
+  if (!ProcessUpdateResponseMessage(gu_response,
+                                    proto_request_types,
+                                    session->context()->update_handler_map(),
+                                    status)) {
+    return SERVER_RESPONSE_VALIDATION_FAILED;
+  } else {
+    return result;
+  }
 }
 
 }  // namespace syncer
diff --git a/sync/engine/download.h b/sync/engine/download.h
index ddae79b..7c5c582 100644
--- a/sync/engine/download.h
+++ b/sync/engine/download.h
@@ -55,7 +55,8 @@
 // Sends the specified message to the server and stores the response in a member
 // of the |session|'s StatusController.
 SYNC_EXPORT_PRIVATE SyncerError
-    ExecuteDownloadUpdates(sessions::SyncSession* session,
+    ExecuteDownloadUpdates(ModelTypeSet request_types,
+                           sessions::SyncSession* session,
                            sync_pb::ClientToServerMessage* msg);
 
 }  // namespace syncer
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc
index 99e62b0..4927acd 100644
--- a/sync/engine/net/server_connection_manager.cc
+++ b/sync/engine/net/server_connection_manager.cc
@@ -178,12 +178,10 @@
     const string& server,
     int port,
     bool use_ssl,
-    bool use_oauth2_token,
     CancelationSignal* cancelation_signal)
     : sync_server_(server),
       sync_server_port_(port),
       use_ssl_(use_ssl),
-      use_oauth2_token_(use_oauth2_token),
       proto_sync_path_(kSyncServerSyncPath),
       server_status_(HttpResponse::NONE),
       terminated_(false),
diff --git a/sync/engine/net/server_connection_manager.h b/sync/engine/net/server_connection_manager.h
index 7496a53..e6a48f0 100644
--- a/sync/engine/net/server_connection_manager.h
+++ b/sync/engine/net/server_connection_manager.h
@@ -81,9 +81,6 @@
   // The size of a download request's payload.
   int64 payload_length;
 
-  // Value of the Update-Client-Auth header.
-  std::string update_client_auth_header;
-
   // Identifies the type of failure, if any.
   ServerConnectionCode server_status;
 
@@ -167,12 +164,10 @@
 
     void GetServerParams(std::string* server,
                          int* server_port,
-                         bool* use_ssl,
-                         bool* use_oauth2_token) const {
+                         bool* use_ssl) const {
       server->assign(scm_->sync_server_);
       *server_port = scm_->sync_server_port_;
       *use_ssl = scm_->use_ssl_;
-      *use_oauth2_token = scm_->use_oauth2_token_;
     }
 
     std::string buffer_;
@@ -186,7 +181,6 @@
   ServerConnectionManager(const std::string& server,
                           int port,
                           bool use_ssl,
-                          bool use_oauth2_token,
                           CancelationSignal* cancelation_signal);
 
   virtual ~ServerConnectionManager();
@@ -292,11 +286,6 @@
   // Indicates whether or not requests should be made using HTTPS.
   bool use_ssl_;
 
-  // Indicates if token should be handled as OAuth2 token. Connection should set
-  // auth header appropriately.
-  // TODO(pavely): Remove once sync on android switches to oauth2 tokens.
-  bool use_oauth2_token_;
-
   // The paths we post to.
   std::string proto_sync_path_;
 
diff --git a/sync/engine/process_updates_command.cc b/sync/engine/process_updates_command.cc
deleted file mode 100644
index d761cfc..0000000
--- a/sync/engine/process_updates_command.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright 2012 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 "sync/engine/process_updates_command.h"
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/location.h"
-#include "sync/engine/syncer.h"
-#include "sync/engine/syncer_proto_util.h"
-#include "sync/engine/syncer_util.h"
-#include "sync/sessions/sync_session.h"
-#include "sync/syncable/directory.h"
-#include "sync/syncable/model_neutral_mutable_entry.h"
-#include "sync/syncable/syncable_model_neutral_write_transaction.h"
-#include "sync/syncable/syncable_proto_util.h"
-#include "sync/syncable/syncable_util.h"
-#include "sync/util/cryptographer.h"
-
-using std::vector;
-
-namespace syncer {
-
-using sessions::SyncSession;
-using sessions::StatusController;
-
-using syncable::GET_BY_ID;
-
-ProcessUpdatesCommand::ProcessUpdatesCommand() {}
-ProcessUpdatesCommand::~ProcessUpdatesCommand() {}
-
-namespace {
-
-// This function attempts to determine whether or not this update is genuinely
-// new, or if it is a reflection of one of our own commits.
-//
-// There is a known inaccuracy in its implementation.  If this update ends up
-// being applied to a local item with a different ID, we will count the change
-// as being a non-reflection update.  Fortunately, the server usually updates
-// our IDs correctly in its commit response, so a new ID during GetUpdate should
-// be rare.
-//
-// The only secnarios I can think of where this might happen are:
-// - We commit a  new item to the server, but we don't persist the
-// server-returned new ID to the database before we shut down.  On the GetUpdate
-// following the next restart, we will receive an update from the server that
-// updates its local ID.
-// - When two attempts to create an item with identical UNIQUE_CLIENT_TAG values
-// collide at the server.  I have seen this in testing.  When it happens, the
-// test server will send one of the clients a response to upate its local ID so
-// that both clients will refer to the item using the same ID going forward.  In
-// this case, we're right to assume that the update is not a reflection.
-//
-// For more information, see FindLocalIdToUpdate().
-bool UpdateContainsNewVersion(syncable::BaseTransaction *trans,
-                              const sync_pb::SyncEntity &update) {
-  int64 existing_version = -1; // The server always sends positive versions.
-  syncable::Entry existing_entry(trans, GET_BY_ID,
-                                 SyncableIdFromProto(update.id_string()));
-  if (existing_entry.good())
-    existing_version = existing_entry.GetBaseVersion();
-
-  if (!existing_entry.good() && update.deleted()) {
-    // There are several possible explanations for this.  The most common cases
-    // will be first time sync and the redelivery of deletions we've already
-    // synced, accepted, and purged from our database.  In either case, the
-    // update is useless to us.  Let's count them all as "not new", even though
-    // that may not always be entirely accurate.
-    return false;
-  }
-
-  if (existing_entry.good() &&
-      !existing_entry.GetUniqueClientTag().empty() &&
-      existing_entry.GetIsDel() &&
-      update.deleted()) {
-    // Unique client tags will have their version set to zero when they're
-    // deleted.  The usual version comparison logic won't be able to detect
-    // reflections of these items.  Instead, we assume any received tombstones
-    // are reflections.  That should be correct most of the time.
-    return false;
-  }
-
-  return existing_version < update.version();
-}
-
-}  // namespace
-
-SyncerError ProcessUpdatesCommand::ExecuteImpl(SyncSession* session) {
-  syncable::Directory* dir = session->context()->directory();
-
-  syncable::ModelNeutralWriteTransaction trans(
-      FROM_HERE, syncable::SYNCER, dir);
-
-  sessions::StatusController* status = session->mutable_status_controller();
-  const sync_pb::GetUpdatesResponse& updates =
-      status->updates_response().get_updates();
-  int update_count = updates.entries().size();
-
-  ModelTypeSet requested_types = GetRoutingInfoTypes(
-      session->context()->routing_info());
-
-  DVLOG(1) << update_count << " entries to verify";
-  for (int i = 0; i < update_count; i++) {
-    const sync_pb::SyncEntity& update = updates.entries(i);
-
-    VerifyResult verify_result = VerifyUpdate(
-        &trans, update, requested_types, session->context()->routing_info());
-    status->increment_num_updates_downloaded_by(1);
-    if (!UpdateContainsNewVersion(&trans, update))
-      status->increment_num_reflected_updates_downloaded_by(1);
-    if (update.deleted())
-      status->increment_num_tombstone_updates_downloaded_by(1);
-
-    if (verify_result != VERIFY_SUCCESS && verify_result != VERIFY_UNDELETE)
-      continue;
-
-    ServerUpdateProcessingResult process_result =
-       ProcessUpdate(update, dir->GetCryptographer(&trans), &trans);
-
-    DCHECK(process_result == SUCCESS_PROCESSED ||
-           process_result == SUCCESS_STORED);
-  }
-
-  return SYNCER_OK;
-}
-
-namespace {
-
-// In the event that IDs match, but tags differ AttemptReuniteClient tag
-// will have refused to unify the update.
-// We should not attempt to apply it at all since it violates consistency
-// rules.
-VerifyResult VerifyTagConsistency(
-    const sync_pb::SyncEntity& entry,
-    const syncable::ModelNeutralMutableEntry& same_id) {
-  if (entry.has_client_defined_unique_tag() &&
-      entry.client_defined_unique_tag() !=
-          same_id.GetUniqueClientTag()) {
-    return VERIFY_FAIL;
-  }
-  return VERIFY_UNDECIDED;
-}
-
-}  // namespace
-
-VerifyResult ProcessUpdatesCommand::VerifyUpdate(
-    syncable::ModelNeutralWriteTransaction* trans,
-    const sync_pb::SyncEntity& entry,
-    ModelTypeSet requested_types,
-    const ModelSafeRoutingInfo& routes) {
-  syncable::Id id = SyncableIdFromProto(entry.id_string());
-  VerifyResult result = VERIFY_FAIL;
-
-  const bool deleted = entry.has_deleted() && entry.deleted();
-  const bool is_directory = IsFolder(entry);
-  const ModelType model_type = GetModelType(entry);
-
-  if (!id.ServerKnows()) {
-    LOG(ERROR) << "Illegal negative id in received updates";
-    return result;
-  }
-  {
-    const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry);
-    if (name.empty() && !deleted) {
-      LOG(ERROR) << "Zero length name in non-deleted update";
-      return result;
-    }
-  }
-
-  syncable::ModelNeutralMutableEntry same_id(trans, GET_BY_ID, id);
-  result = VerifyNewEntry(entry, &same_id, deleted);
-
-  ModelType placement_type = !deleted ? GetModelType(entry)
-      : same_id.good() ? same_id.GetModelType() : UNSPECIFIED;
-
-  if (VERIFY_UNDECIDED == result) {
-    result = VerifyTagConsistency(entry, same_id);
-  }
-
-  if (VERIFY_UNDECIDED == result) {
-    if (deleted) {
-      // For deletes the server could send tombostones for items that
-      // the client did not request. If so ignore those items.
-      if (IsRealDataType(placement_type) &&
-          !requested_types.Has(placement_type)) {
-        result = VERIFY_SKIP;
-      } else {
-        result = VERIFY_SUCCESS;
-      }
-    }
-  }
-
-  // If we have an existing entry, we check here for updates that break
-  // consistency rules.
-  if (VERIFY_UNDECIDED == result) {
-    result = VerifyUpdateConsistency(trans, entry, deleted,
-                                     is_directory, model_type, &same_id);
-  }
-
-  if (VERIFY_UNDECIDED == result)
-    result = VERIFY_SUCCESS;  // No news is good news.
-
-  return result;  // This might be VERIFY_SUCCESS as well
-}
-
-namespace {
-// Returns true if the entry is still ok to process.
-bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans,
-                   const sync_pb::SyncEntity& entry,
-                   syncable::ModelNeutralMutableEntry* same_id) {
-
-  const bool deleted = entry.has_deleted() && entry.deleted();
-  const bool is_directory = IsFolder(entry);
-  const ModelType model_type = GetModelType(entry);
-
-  return VERIFY_SUCCESS == VerifyUpdateConsistency(trans,
-                                                   entry,
-                                                   deleted,
-                                                   is_directory,
-                                                   model_type,
-                                                   same_id);
-}
-}  // namespace
-
-// Process a single update. Will avoid touching global state.
-ServerUpdateProcessingResult ProcessUpdatesCommand::ProcessUpdate(
-    const sync_pb::SyncEntity& update,
-    const Cryptographer* cryptographer,
-    syncable::ModelNeutralWriteTransaction* const trans) {
-  const syncable::Id& server_id = SyncableIdFromProto(update.id_string());
-  const std::string name = SyncerProtoUtil::NameFromSyncEntity(update);
-
-  // Look to see if there's a local item that should recieve this update,
-  // maybe due to a duplicate client tag or a lost commit response.
-  syncable::Id local_id = FindLocalIdToUpdate(trans, update);
-
-  // FindLocalEntryToUpdate has veto power.
-  if (local_id.IsNull()) {
-    return SUCCESS_PROCESSED;  // The entry has become irrelevant.
-  }
-
-  CreateNewEntry(trans, local_id);
-
-  // We take a two step approach. First we store the entries data in the
-  // server fields of a local entry and then move the data to the local fields
-  syncable::ModelNeutralMutableEntry target_entry(trans, GET_BY_ID, local_id);
-
-  // We need to run the Verify checks again; the world could have changed
-  // since we last verified.
-  if (!ReverifyEntry(trans, update, &target_entry)) {
-    return SUCCESS_PROCESSED;  // The entry has become irrelevant.
-  }
-
-  // If we're repurposing an existing local entry with a new server ID,
-  // change the ID now, after we're sure that the update can succeed.
-  if (local_id != server_id) {
-    DCHECK(!update.deleted());
-    ChangeEntryIDAndUpdateChildren(trans, &target_entry, server_id);
-    // When IDs change, versions become irrelevant.  Forcing BASE_VERSION
-    // to zero would ensure that this update gets applied, but would indicate
-    // creation or undeletion if it were committed that way.  Instead, prefer
-    // forcing BASE_VERSION to entry.version() while also forcing
-    // IS_UNAPPLIED_UPDATE to true.  If the item is UNSYNCED, it's committable
-    // from the new state; it may commit before the conflict resolver gets
-    // a crack at it.
-    if (target_entry.GetIsUnsynced() || target_entry.GetBaseVersion() > 0) {
-      // If either of these conditions are met, then we can expect valid client
-      // fields for this entry.  When BASE_VERSION is positive, consistency is
-      // enforced on the client fields at update-application time.  Otherwise,
-      // we leave the BASE_VERSION field alone; it'll get updated the first time
-      // we successfully apply this update.
-      target_entry.PutBaseVersion(update.version());
-    }
-    // Force application of this update, no matter what.
-    target_entry.PutIsUnappliedUpdate(true);
-  }
-
-  // If this is a newly received undecryptable update, and the only thing that
-  // has changed are the specifics, store the original decryptable specifics,
-  // (on which any current or future local changes are based) before we
-  // overwrite SERVER_SPECIFICS.
-  // MTIME, CTIME, and NON_UNIQUE_NAME are not enforced.
-
-  bool position_matches = false;
-  if (target_entry.ShouldMaintainPosition() && !update.deleted()) {
-    std::string update_tag = GetUniqueBookmarkTagFromUpdate(update);
-    if (UniquePosition::IsValidSuffix(update_tag)) {
-      position_matches = GetUpdatePosition(update, update_tag).Equals(
-          target_entry.GetServerUniquePosition());
-    } else {
-      NOTREACHED();
-    }
-  } else {
-    // If this item doesn't care about positions, then set this flag to true.
-    position_matches = true;
-  }
-
-  if (!update.deleted() && !target_entry.GetServerIsDel() &&
-      (SyncableIdFromProto(update.parent_id_string()) ==
-          target_entry.GetServerParentId()) &&
-      position_matches &&
-      update.has_specifics() && update.specifics().has_encrypted() &&
-      !cryptographer->CanDecrypt(update.specifics().encrypted())) {
-    sync_pb::EntitySpecifics prev_specifics =
-        target_entry.GetServerSpecifics();
-    // We only store the old specifics if they were decryptable and applied and
-    // there is no BASE_SERVER_SPECIFICS already. Else do nothing.
-    if (!target_entry.GetIsUnappliedUpdate() &&
-        !IsRealDataType(GetModelTypeFromSpecifics(
-            target_entry.GetBaseServerSpecifics())) &&
-        (!prev_specifics.has_encrypted() ||
-         cryptographer->CanDecrypt(prev_specifics.encrypted()))) {
-      DVLOG(2) << "Storing previous server specifcs: "
-               << prev_specifics.SerializeAsString();
-      target_entry.PutBaseServerSpecifics(prev_specifics);
-    }
-  } else if (IsRealDataType(GetModelTypeFromSpecifics(
-                 target_entry.GetBaseServerSpecifics()))) {
-    // We have a BASE_SERVER_SPECIFICS, but a subsequent non-specifics-only
-    // change arrived. As a result, we can't use the specifics alone to detect
-    // changes, so we clear BASE_SERVER_SPECIFICS.
-    target_entry.PutBaseServerSpecifics(
-                     sync_pb::EntitySpecifics());
-  }
-
-  UpdateServerFieldsFromUpdate(&target_entry, update, name);
-
-  return SUCCESS_PROCESSED;
-}
-
-}  // namespace syncer
diff --git a/sync/engine/process_updates_command.h b/sync/engine/process_updates_command.h
deleted file mode 100644
index 0868e98..0000000
--- a/sync/engine/process_updates_command.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2012 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 SYNC_ENGINE_PROCESS_UPDATES_COMMAND_H_
-#define SYNC_ENGINE_PROCESS_UPDATES_COMMAND_H_
-
-#include "base/compiler_specific.h"
-#include "sync/base/sync_export.h"
-#include "sync/engine/model_changing_syncer_command.h"
-#include "sync/engine/syncer_types.h"
-
-namespace sync_pb {
-class SyncEntity;
-}
-
-namespace syncer {
-
-namespace syncable {
-class ModelNeutralWriteTransaction;
-}
-
-class Cryptographer;
-
-// A syncer command for verifying and processing updates.
-//
-// Preconditions - Updates in the SyncerSesssion have been downloaded.
-//
-// Postconditions - All of the verified SyncEntity data will be copied to
-//                  the server fields of the corresponding syncable entries.
-class SYNC_EXPORT_PRIVATE ProcessUpdatesCommand : public SyncerCommand {
- public:
-  ProcessUpdatesCommand();
-  virtual ~ProcessUpdatesCommand();
-
- protected:
-  // SyncerCommand implementation.
-  virtual SyncerError ExecuteImpl(sessions::SyncSession* session) OVERRIDE;
-
- private:
-  VerifyResult VerifyUpdate(
-      syncable::ModelNeutralWriteTransaction* trans,
-      const sync_pb::SyncEntity& entry,
-      ModelTypeSet requested_types,
-      const ModelSafeRoutingInfo& routes);
-  ServerUpdateProcessingResult ProcessUpdate(
-      const sync_pb::SyncEntity& proto_update,
-      const Cryptographer* cryptographer,
-      syncable::ModelNeutralWriteTransaction* const trans);
-  DISALLOW_COPY_AND_ASSIGN(ProcessUpdatesCommand);
-};
-
-}  // namespace syncer
-
-#endif  // SYNC_ENGINE_PROCESS_UPDATES_COMMAND_H_
diff --git a/sync/engine/process_updates_command_unittest.cc b/sync/engine/process_updates_command_unittest.cc
deleted file mode 100644
index 44b308a..0000000
--- a/sync/engine/process_updates_command_unittest.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2012 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/basictypes.h"
-#include "sync/engine/process_updates_command.h"
-#include "sync/engine/syncer_proto_util.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/test/test_entry_factory.h"
-#include "sync/sessions/sync_session.h"
-#include "sync/syncable/mutable_entry.h"
-#include "sync/syncable/syncable_id.h"
-#include "sync/syncable/syncable_proto_util.h"
-#include "sync/syncable/syncable_read_transaction.h"
-#include "sync/syncable/syncable_write_transaction.h"
-#include "sync/test/engine/fake_model_worker.h"
-#include "sync/test/engine/syncer_command_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace syncer {
-
-using sync_pb::SyncEntity;
-using syncable::Id;
-using syncable::MutableEntry;
-using syncable::UNITTEST;
-using syncable::WriteTransaction;
-
-namespace {
-
-class ProcessUpdatesCommandTest : public SyncerCommandTest {
- protected:
-  ProcessUpdatesCommandTest() {}
-  virtual ~ProcessUpdatesCommandTest() {}
-
-  virtual void SetUp() {
-    workers()->push_back(
-        make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
-    workers()->push_back(
-        make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
-    (*mutable_routing_info())[PREFERENCES] = GROUP_UI;
-    (*mutable_routing_info())[BOOKMARKS] = GROUP_UI;
-    (*mutable_routing_info())[AUTOFILL] = GROUP_DB;
-    SyncerCommandTest::SetUp();
-    test_entry_factory_.reset(new TestEntryFactory(directory()));
-  }
-
-  void CreateLocalItem(const std::string& item_id,
-                       const std::string& parent_id,
-                       const ModelType& type) {
-    WriteTransaction trans(FROM_HERE, UNITTEST, directory());
-    MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
-        Id::CreateFromServerId(item_id));
-    ASSERT_TRUE(entry.good());
-
-    entry.PutBaseVersion(1);
-    entry.PutServerVersion(1);
-    entry.PutNonUniqueName(item_id);
-    entry.PutParentId(Id::CreateFromServerId(parent_id));
-    sync_pb::EntitySpecifics default_specifics;
-    AddDefaultFieldValue(type, &default_specifics);
-    entry.PutServerSpecifics(default_specifics);
-  }
-
-  SyncEntity* AddUpdate(sync_pb::GetUpdatesResponse* updates,
-      const std::string& id, const std::string& parent,
-      const ModelType& type) {
-    sync_pb::SyncEntity* e = updates->add_entries();
-    e->set_id_string(id);
-    e->set_parent_id_string(parent);
-    e->set_non_unique_name(id);
-    e->set_name(id);
-    e->set_version(1000);
-    AddDefaultFieldValue(type, e->mutable_specifics());
-    return e;
-  }
-
-  ProcessUpdatesCommand command_;
-  scoped_ptr<TestEntryFactory> test_entry_factory_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ProcessUpdatesCommandTest);
-};
-
-static const char kCacheGuid[] = "IrcjZ2jyzHDV9Io4+zKcXQ==";
-
-// Test that the bookmark tag is set on newly downloaded items.
-TEST_F(ProcessUpdatesCommandTest, NewBookmarkTag) {
-  std::string root = syncable::GetNullId().GetServerId();
-  sync_pb::GetUpdatesResponse* updates =
-      session()->mutable_status_controller()->
-      mutable_updates_response()->mutable_get_updates();
-  Id server_id = Id::CreateFromServerId("b1");
-  SyncEntity* e =
-      AddUpdate(updates, SyncableIdToProto(server_id), root, BOOKMARKS);
-
-  e->set_originator_cache_guid(
-      std::string(kCacheGuid, arraysize(kCacheGuid)-1));
-  Id client_id = Id::CreateFromClientString("-2");
-  e->set_originator_client_item_id(client_id.GetServerId());
-  e->set_position_in_parent(0);
-
-  command_.Execute(session());
-
-  syncable::ReadTransaction trans(FROM_HERE, directory());
-  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
-  ASSERT_TRUE(entry.good());
-  EXPECT_TRUE(
-      UniquePosition::IsValidSuffix(entry.GetUniqueBookmarkTag()));
-  EXPECT_TRUE(entry.GetServerUniquePosition().IsValid());
-
-  // If this assertion fails, that might indicate that the algorithm used to
-  // generate bookmark tags has been modified.  This could have implications for
-  // bookmark ordering.  Please make sure you know what you're doing if you
-  // intend to make such a change.
-  EXPECT_EQ("6wHRAb3kbnXV5GHrejp4/c1y5tw=",
-            entry.GetUniqueBookmarkTag());
-}
-
-TEST_F(ProcessUpdatesCommandTest, ReceiveServerCreatedBookmarkFolders) {
-  Id server_id = Id::CreateFromServerId("xyz");
-  std::string root = syncable::GetNullId().GetServerId();
-  sync_pb::GetUpdatesResponse* updates =
-      session()->mutable_status_controller()->
-      mutable_updates_response()->mutable_get_updates();
-
-  // Create an update that mimics the bookmark root.
-  SyncEntity* e =
-      AddUpdate(updates, SyncableIdToProto(server_id), root, BOOKMARKS);
-  e->set_server_defined_unique_tag("google_chrome_bookmarks");
-  e->set_folder(true);
-
-  EXPECT_FALSE(SyncerProtoUtil::ShouldMaintainPosition(*e));
-
-  command_.Execute(session());
-
-  syncable::ReadTransaction trans(FROM_HERE, directory());
-  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
-  ASSERT_TRUE(entry.good());
-
-  EXPECT_FALSE(entry.ShouldMaintainPosition());
-  EXPECT_FALSE(entry.GetUniquePosition().IsValid());
-  EXPECT_FALSE(entry.GetServerUniquePosition().IsValid());
-  EXPECT_TRUE(entry.GetUniqueBookmarkTag().empty());
-}
-
-TEST_F(ProcessUpdatesCommandTest, ReceiveNonBookmarkItem) {
-  Id server_id = Id::CreateFromServerId("xyz");
-  std::string root = syncable::GetNullId().GetServerId();
-  sync_pb::GetUpdatesResponse* updates =
-      session()->mutable_status_controller()->
-      mutable_updates_response()->mutable_get_updates();
-
-  SyncEntity* e =
-      AddUpdate(updates, SyncableIdToProto(server_id), root, AUTOFILL);
-  e->set_server_defined_unique_tag("9PGRuKdX5sHyGMB17CvYTXuC43I=");
-
-  EXPECT_FALSE(SyncerProtoUtil::ShouldMaintainPosition(*e));
-
-  command_.Execute(session());
-
-  syncable::ReadTransaction trans(FROM_HERE, directory());
-  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
-  ASSERT_TRUE(entry.good());
-
-  EXPECT_FALSE(entry.ShouldMaintainPosition());
-  EXPECT_FALSE(entry.GetUniquePosition().IsValid());
-  EXPECT_FALSE(entry.GetServerUniquePosition().IsValid());
-  EXPECT_TRUE(entry.GetUniqueBookmarkTag().empty());
-}
-
-}  // namespace
-
-}  // namespace syncer
diff --git a/sync/engine/process_updates_util.cc b/sync/engine/process_updates_util.cc
new file mode 100644
index 0000000..49e40b3
--- /dev/null
+++ b/sync/engine/process_updates_util.cc
@@ -0,0 +1,329 @@
+// Copyright 2013 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 "sync/engine/process_updates_util.h"
+
+#include "base/location.h"
+#include "sync/engine/syncer_proto_util.h"
+#include "sync/engine/syncer_util.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/model_neutral_mutable_entry.h"
+#include "sync/syncable/syncable_model_neutral_write_transaction.h"
+#include "sync/syncable/syncable_proto_util.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/util/cryptographer.h"
+
+namespace syncer {
+
+using sessions::StatusController;
+
+using syncable::GET_BY_ID;
+
+namespace {
+
+// This function attempts to determine whether or not this update is genuinely
+// new, or if it is a reflection of one of our own commits.
+//
+// There is a known inaccuracy in its implementation.  If this update ends up
+// being applied to a local item with a different ID, we will count the change
+// as being a non-reflection update.  Fortunately, the server usually updates
+// our IDs correctly in its commit response, so a new ID during GetUpdate should
+// be rare.
+//
+// The only secnarios I can think of where this might happen are:
+// - We commit a  new item to the server, but we don't persist the
+// server-returned new ID to the database before we shut down.  On the GetUpdate
+// following the next restart, we will receive an update from the server that
+// updates its local ID.
+// - When two attempts to create an item with identical UNIQUE_CLIENT_TAG values
+// collide at the server.  I have seen this in testing.  When it happens, the
+// test server will send one of the clients a response to upate its local ID so
+// that both clients will refer to the item using the same ID going forward.  In
+// this case, we're right to assume that the update is not a reflection.
+//
+// For more information, see FindLocalIdToUpdate().
+bool UpdateContainsNewVersion(syncable::BaseTransaction *trans,
+                              const sync_pb::SyncEntity &update) {
+  int64 existing_version = -1; // The server always sends positive versions.
+  syncable::Entry existing_entry(trans, GET_BY_ID,
+                                 SyncableIdFromProto(update.id_string()));
+  if (existing_entry.good())
+    existing_version = existing_entry.GetBaseVersion();
+
+  if (!existing_entry.good() && update.deleted()) {
+    // There are several possible explanations for this.  The most common cases
+    // will be first time sync and the redelivery of deletions we've already
+    // synced, accepted, and purged from our database.  In either case, the
+    // update is useless to us.  Let's count them all as "not new", even though
+    // that may not always be entirely accurate.
+    return false;
+  }
+
+  if (existing_entry.good() &&
+      !existing_entry.GetUniqueClientTag().empty() &&
+      existing_entry.GetIsDel() &&
+      update.deleted()) {
+    // Unique client tags will have their version set to zero when they're
+    // deleted.  The usual version comparison logic won't be able to detect
+    // reflections of these items.  Instead, we assume any received tombstones
+    // are reflections.  That should be correct most of the time.
+    return false;
+  }
+
+  return existing_version < update.version();
+}
+
+}  // namespace
+
+void PartitionUpdatesByType(
+    const sync_pb::GetUpdatesResponse& updates,
+    ModelTypeSet requested_types,
+    TypeSyncEntityMap* updates_by_type) {
+  int update_count = updates.entries().size();
+  for (ModelTypeSet::Iterator it = requested_types.First();
+       it.Good(); it.Inc()) {
+    updates_by_type->insert(std::make_pair(it.Get(), SyncEntityList()));
+  }
+  for (int i = 0; i < update_count; ++i) {
+    const sync_pb::SyncEntity& update = updates.entries(i);
+    ModelType type = GetModelType(update);
+    if (!IsRealDataType(type)) {
+      NOTREACHED() << "Received update with invalid type.";
+      continue;
+    }
+
+    TypeSyncEntityMap::iterator it = updates_by_type->find(type);
+    if (it == updates_by_type->end()) {
+      DLOG(WARNING) << "Skipping update for unexpected type "
+                    << ModelTypeToString(type);
+      continue;
+    }
+
+    it->second.push_back(&update);
+  }
+}
+
+void ProcessDownloadedUpdates(
+    syncable::Directory* dir,
+    syncable::ModelNeutralWriteTransaction* trans,
+    ModelType type,
+    const SyncEntityList& applicable_updates,
+    sessions::StatusController* status) {
+  for (SyncEntityList::const_iterator update_it = applicable_updates.begin();
+       update_it != applicable_updates.end(); ++update_it) {
+    DCHECK_EQ(type, GetModelType(**update_it));
+    if (!UpdateContainsNewVersion(trans, **update_it))
+      status->increment_num_reflected_updates_downloaded_by(1);
+    if ((*update_it)->deleted())
+      status->increment_num_tombstone_updates_downloaded_by(1);
+    VerifyResult verify_result = VerifyUpdate(trans, **update_it, type);
+    if (verify_result != VERIFY_SUCCESS && verify_result != VERIFY_UNDELETE)
+      continue;
+    ProcessUpdate(**update_it, dir->GetCryptographer(trans), trans);
+  }
+}
+
+namespace {
+
+// In the event that IDs match, but tags differ AttemptReuniteClient tag
+// will have refused to unify the update.
+// We should not attempt to apply it at all since it violates consistency
+// rules.
+VerifyResult VerifyTagConsistency(
+    const sync_pb::SyncEntity& entry,
+    const syncable::ModelNeutralMutableEntry& same_id) {
+  if (entry.has_client_defined_unique_tag() &&
+      entry.client_defined_unique_tag() !=
+          same_id.GetUniqueClientTag()) {
+    return VERIFY_FAIL;
+  }
+  return VERIFY_UNDECIDED;
+}
+
+}  // namespace
+
+VerifyResult VerifyUpdate(
+    syncable::ModelNeutralWriteTransaction* trans,
+    const sync_pb::SyncEntity& entry,
+    ModelType requested_type) {
+  syncable::Id id = SyncableIdFromProto(entry.id_string());
+  VerifyResult result = VERIFY_FAIL;
+
+  const bool deleted = entry.has_deleted() && entry.deleted();
+  const bool is_directory = IsFolder(entry);
+  const ModelType model_type = GetModelType(entry);
+
+  if (!id.ServerKnows()) {
+    LOG(ERROR) << "Illegal negative id in received updates";
+    return result;
+  }
+  {
+    const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry);
+    if (name.empty() && !deleted) {
+      LOG(ERROR) << "Zero length name in non-deleted update";
+      return result;
+    }
+  }
+
+  syncable::ModelNeutralMutableEntry same_id(trans, GET_BY_ID, id);
+  result = VerifyNewEntry(entry, &same_id, deleted);
+
+  ModelType placement_type = !deleted ? GetModelType(entry)
+      : same_id.good() ? same_id.GetModelType() : UNSPECIFIED;
+
+  if (VERIFY_UNDECIDED == result) {
+    result = VerifyTagConsistency(entry, same_id);
+  }
+
+  if (VERIFY_UNDECIDED == result) {
+    if (deleted) {
+      // For deletes the server could send tombostones for items that
+      // the client did not request. If so ignore those items.
+      if (IsRealDataType(placement_type) && requested_type != placement_type) {
+        result = VERIFY_SKIP;
+      } else {
+        result = VERIFY_SUCCESS;
+      }
+    }
+  }
+
+  // If we have an existing entry, we check here for updates that break
+  // consistency rules.
+  if (VERIFY_UNDECIDED == result) {
+    result = VerifyUpdateConsistency(trans, entry, deleted,
+                                     is_directory, model_type, &same_id);
+  }
+
+  if (VERIFY_UNDECIDED == result)
+    result = VERIFY_SUCCESS;  // No news is good news.
+
+  return result;  // This might be VERIFY_SUCCESS as well
+}
+
+namespace {
+// Returns true if the entry is still ok to process.
+bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans,
+                   const sync_pb::SyncEntity& entry,
+                   syncable::ModelNeutralMutableEntry* same_id) {
+
+  const bool deleted = entry.has_deleted() && entry.deleted();
+  const bool is_directory = IsFolder(entry);
+  const ModelType model_type = GetModelType(entry);
+
+  return VERIFY_SUCCESS == VerifyUpdateConsistency(trans,
+                                                   entry,
+                                                   deleted,
+                                                   is_directory,
+                                                   model_type,
+                                                   same_id);
+}
+}  // namespace
+
+// Process a single update. Will avoid touching global state.
+void ProcessUpdate(
+    const sync_pb::SyncEntity& update,
+    const Cryptographer* cryptographer,
+    syncable::ModelNeutralWriteTransaction* const trans) {
+  const syncable::Id& server_id = SyncableIdFromProto(update.id_string());
+  const std::string name = SyncerProtoUtil::NameFromSyncEntity(update);
+
+  // Look to see if there's a local item that should recieve this update,
+  // maybe due to a duplicate client tag or a lost commit response.
+  syncable::Id local_id = FindLocalIdToUpdate(trans, update);
+
+  // FindLocalEntryToUpdate has veto power.
+  if (local_id.IsNull()) {
+    return;  // The entry has become irrelevant.
+  }
+
+  CreateNewEntry(trans, local_id);
+
+  // We take a two step approach. First we store the entries data in the
+  // server fields of a local entry and then move the data to the local fields
+  syncable::ModelNeutralMutableEntry target_entry(trans, GET_BY_ID, local_id);
+
+  // We need to run the Verify checks again; the world could have changed
+  // since we last verified.
+  if (!ReverifyEntry(trans, update, &target_entry)) {
+    return;  // The entry has become irrelevant.
+  }
+
+  // If we're repurposing an existing local entry with a new server ID,
+  // change the ID now, after we're sure that the update can succeed.
+  if (local_id != server_id) {
+    DCHECK(!update.deleted());
+    ChangeEntryIDAndUpdateChildren(trans, &target_entry, server_id);
+    // When IDs change, versions become irrelevant.  Forcing BASE_VERSION
+    // to zero would ensure that this update gets applied, but would indicate
+    // creation or undeletion if it were committed that way.  Instead, prefer
+    // forcing BASE_VERSION to entry.version() while also forcing
+    // IS_UNAPPLIED_UPDATE to true.  If the item is UNSYNCED, it's committable
+    // from the new state; it may commit before the conflict resolver gets
+    // a crack at it.
+    if (target_entry.GetIsUnsynced() || target_entry.GetBaseVersion() > 0) {
+      // If either of these conditions are met, then we can expect valid client
+      // fields for this entry.  When BASE_VERSION is positive, consistency is
+      // enforced on the client fields at update-application time.  Otherwise,
+      // we leave the BASE_VERSION field alone; it'll get updated the first time
+      // we successfully apply this update.
+      target_entry.PutBaseVersion(update.version());
+    }
+    // Force application of this update, no matter what.
+    target_entry.PutIsUnappliedUpdate(true);
+  }
+
+  // If this is a newly received undecryptable update, and the only thing that
+  // has changed are the specifics, store the original decryptable specifics,
+  // (on which any current or future local changes are based) before we
+  // overwrite SERVER_SPECIFICS.
+  // MTIME, CTIME, and NON_UNIQUE_NAME are not enforced.
+
+  bool position_matches = false;
+  if (target_entry.ShouldMaintainPosition() && !update.deleted()) {
+    std::string update_tag = GetUniqueBookmarkTagFromUpdate(update);
+    if (UniquePosition::IsValidSuffix(update_tag)) {
+      position_matches = GetUpdatePosition(update, update_tag).Equals(
+          target_entry.GetServerUniquePosition());
+    } else {
+      NOTREACHED();
+    }
+  } else {
+    // If this item doesn't care about positions, then set this flag to true.
+    position_matches = true;
+  }
+
+  if (!update.deleted() && !target_entry.GetServerIsDel() &&
+      (SyncableIdFromProto(update.parent_id_string()) ==
+          target_entry.GetServerParentId()) &&
+      position_matches &&
+      update.has_specifics() && update.specifics().has_encrypted() &&
+      !cryptographer->CanDecrypt(update.specifics().encrypted())) {
+    sync_pb::EntitySpecifics prev_specifics =
+        target_entry.GetServerSpecifics();
+    // We only store the old specifics if they were decryptable and applied and
+    // there is no BASE_SERVER_SPECIFICS already. Else do nothing.
+    if (!target_entry.GetIsUnappliedUpdate() &&
+        !IsRealDataType(GetModelTypeFromSpecifics(
+            target_entry.GetBaseServerSpecifics())) &&
+        (!prev_specifics.has_encrypted() ||
+         cryptographer->CanDecrypt(prev_specifics.encrypted()))) {
+      DVLOG(2) << "Storing previous server specifcs: "
+               << prev_specifics.SerializeAsString();
+      target_entry.PutBaseServerSpecifics(prev_specifics);
+    }
+  } else if (IsRealDataType(GetModelTypeFromSpecifics(
+                 target_entry.GetBaseServerSpecifics()))) {
+    // We have a BASE_SERVER_SPECIFICS, but a subsequent non-specifics-only
+    // change arrived. As a result, we can't use the specifics alone to detect
+    // changes, so we clear BASE_SERVER_SPECIFICS.
+    target_entry.PutBaseServerSpecifics(
+                     sync_pb::EntitySpecifics());
+  }
+
+  UpdateServerFieldsFromUpdate(&target_entry, update, name);
+
+  return;
+}
+
+}  // namespace syncer
diff --git a/sync/engine/process_updates_util.h b/sync/engine/process_updates_util.h
new file mode 100644
index 0000000..6e8bc71
--- /dev/null
+++ b/sync/engine/process_updates_util.h
@@ -0,0 +1,73 @@
+// Copyright 2013 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 SYNC_ENGINE_PROCESS_UPDATES_UTIL_H_
+#define SYNC_ENGINE_PROCESS_UPDATES_UTIL_H_
+
+#include <map>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "sync/base/sync_export.h"
+#include "sync/engine/syncer_types.h"
+#include "sync/internal_api/public/base/model_type.h"
+
+namespace sync_pb {
+class GetUpdatesResponse;
+class SyncEntity;
+}
+
+namespace syncer {
+
+namespace sessions {
+class StatusController;
+}
+
+namespace syncable {
+class ModelNeutralWriteTransaction;
+class Directory;
+}
+
+class Cryptographer;
+
+// TODO(rlarocque): Move these definitions somewhere else?
+typedef std::vector<const sync_pb::SyncEntity*> SyncEntityList;
+typedef std::map<ModelType, SyncEntityList> TypeSyncEntityMap;
+
+// Given a GetUpdates response, iterates over all the returned items and
+// divides them according to their type.  Outputs a map from model types to
+// received SyncEntities.  The output map will have entries (possibly empty)
+// for all types in |requested_types|.
+void PartitionUpdatesByType(
+    const sync_pb::GetUpdatesResponse& updates,
+    ModelTypeSet requested_types,
+    TypeSyncEntityMap* updates_by_type);
+
+// Processes all the updates associated with a single ModelType.
+void ProcessDownloadedUpdates(
+    syncable::Directory* dir,
+    syncable::ModelNeutralWriteTransaction* trans,
+    ModelType type,
+    const SyncEntityList& applicable_updates,
+    sessions::StatusController* status);
+
+// Checks whether or not an update is fit for processing.
+//
+// The answer may be "no" if the update appears invalid, or it's not releveant
+// (ie. a delete for an item we've never heard of), or other reasons.
+VerifyResult VerifyUpdate(
+    syncable::ModelNeutralWriteTransaction* trans,
+    const sync_pb::SyncEntity& entry,
+    ModelType requested_type);
+
+// If the update passes a series of checks, this function will copy
+// the SyncEntity's data into the SERVER side of the syncable::Directory.
+void ProcessUpdate(
+    const sync_pb::SyncEntity& proto_update,
+    const Cryptographer* cryptographer,
+    syncable::ModelNeutralWriteTransaction* const trans);
+
+}  // namespace syncer
+
+#endif  // SYNC_ENGINE_PROCESS_UPDATES_UTIL_H_
diff --git a/sync/engine/store_timestamps_command.cc b/sync/engine/store_timestamps_command.cc
deleted file mode 100644
index cbff68f..0000000
--- a/sync/engine/store_timestamps_command.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2012 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 "sync/engine/store_timestamps_command.h"
-
-#include "base/logging.h"
-#include "sync/sessions/status_controller.h"
-#include "sync/sessions/sync_session.h"
-#include "sync/syncable/directory.h"
-
-namespace syncer {
-
-ModelTypeSet ProcessNewProgressMarkers(
-    const sync_pb::GetUpdatesResponse& response,
-    syncable::Directory* dir) {
-  ModelTypeSet forward_progress_types;
-  // If a marker was omitted for any one type, that indicates no
-  // change from the previous state.
-  for (int i = 0; i < response.new_progress_marker_size(); ++i) {
-    int field_number = response.new_progress_marker(i).data_type_id();
-    ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
-    if (!IsRealDataType(model_type)) {
-      DLOG(WARNING) << "Unknown field number " << field_number;
-      continue;
-    }
-    forward_progress_types.Put(model_type);
-    dir->SetDownloadProgress(model_type, response.new_progress_marker(i));
-  }
-  return forward_progress_types;
-}
-
-StoreTimestampsCommand::StoreTimestampsCommand() {}
-StoreTimestampsCommand::~StoreTimestampsCommand() {}
-
-SyncerError StoreTimestampsCommand::ExecuteImpl(
-    sessions::SyncSession* session) {
-  const sync_pb::GetUpdatesResponse& updates =
-      session->status_controller().updates_response().get_updates();
-
-  sessions::StatusController* status = session->mutable_status_controller();
-
-  ModelTypeSet forward_progress_types =
-      ProcessNewProgressMarkers(updates, session->context()->directory());
-  DCHECK(!forward_progress_types.Empty() ||
-         updates.changes_remaining() == 0);
-  if (VLOG_IS_ON(1)) {
-    DVLOG_IF(1, !forward_progress_types.Empty())
-        << "Get Updates got new progress marker for types: "
-        << ModelTypeSetToString(forward_progress_types)
-        << " out of possible: "
-        << ModelTypeSetToString(status->updates_request_types());
-  }
-  if (updates.has_changes_remaining()) {
-    int64 changes_left = updates.changes_remaining();
-    DVLOG(1) << "Changes remaining: " << changes_left;
-    status->set_num_server_changes_remaining(changes_left);
-  }
-
-  return SYNCER_OK;
-}
-
-}  // namespace syncer
diff --git a/sync/engine/store_timestamps_command.h b/sync/engine/store_timestamps_command.h
deleted file mode 100644
index a6426a8..0000000
--- a/sync/engine/store_timestamps_command.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012 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 SYNC_ENGINE_STORE_TIMESTAMPS_COMMAND_H_
-#define SYNC_ENGINE_STORE_TIMESTAMPS_COMMAND_H_
-
-#include "base/compiler_specific.h"
-#include "sync/base/sync_export.h"
-#include "sync/engine/syncer_command.h"
-#include "sync/engine/syncer_types.h"
-#include "sync/internal_api/public/base/model_type.h"
-
-namespace sync_pb {
-class GetUpdatesResponse;
-}  // namespace sync_pb
-
-namespace syncer {
-
-namespace syncable {
-class Directory;
-}  // namespace syncable
-
-// Sets |dir|'s progress markers from the data in |response|.  Returns
-// the set of model types with new progress markers.
-SYNC_EXPORT_PRIVATE ModelTypeSet ProcessNewProgressMarkers(
-    const sync_pb::GetUpdatesResponse& response,
-    syncable::Directory* dir);
-
-// A syncer command that extracts the changelog timestamp information from
-// a GetUpdatesResponse (fetched in DownloadUpdatesCommand) and stores
-// it in the directory.  This is meant to run immediately after
-// ProcessUpdatesCommand.
-//
-// Preconditions - all updates in the SyncerSesssion have been stored in the
-//                 database, meaning it is safe to update the persisted
-//                 timestamps.
-//
-// Postconditions - The next_timestamp returned by the server will be
-//                  saved into the directory (where it will be used
-//                  the next time that DownloadUpdatesCommand runs).
-class StoreTimestampsCommand : public SyncerCommand {
- public:
-  StoreTimestampsCommand();
-  virtual ~StoreTimestampsCommand();
-
-  // SyncerCommand implementation.
-  virtual SyncerError ExecuteImpl(sessions::SyncSession* session) OVERRIDE;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(StoreTimestampsCommand);
-};
-
-}  // namespace syncer
-
-#endif  // SYNC_ENGINE_STORE_TIMESTAMPS_COMMAND_H_
diff --git a/sync/engine/store_timestamps_command_unittest.cc b/sync/engine/store_timestamps_command_unittest.cc
deleted file mode 100644
index e49eb31..0000000
--- a/sync/engine/store_timestamps_command_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 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/basictypes.h"
-#include "sync/engine/store_timestamps_command.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/test/engine/syncer_command_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace syncer {
-
-namespace {
-
-// Adds a progress marker to |response| for the given field number and
-// token.
-void AddProgressMarkerForFieldNumber(
-    sync_pb::GetUpdatesResponse* response,
-    int field_number, const std::string& token) {
-  sync_pb::DataTypeProgressMarker* marker =
-      response->add_new_progress_marker();
-  marker->set_data_type_id(field_number);
-  marker->set_token(token);
-}
-
-// Adds a progress marker to |response| for the given model type and
-// token.
-void AddProgressMarkerForModelType(
-    sync_pb::GetUpdatesResponse* response,
-    ModelType model_type, const std::string& token) {
-  AddProgressMarkerForFieldNumber(
-      response, GetSpecificsFieldNumberFromModelType(model_type), token);
-}
-
-class StoreTimestampsCommandTest : public SyncerCommandTest {
- protected:
-  // Gets the directory's progress marker's token for the given model
-  // type.
-  std::string GetProgessMarkerToken(ModelType model_type) {
-    sync_pb::DataTypeProgressMarker progress_marker;
-    session()->context()->directory()->GetDownloadProgress(
-        model_type, &progress_marker);
-    EXPECT_EQ(
-        GetSpecificsFieldNumberFromModelType(model_type),
-        progress_marker.data_type_id());
-    return progress_marker.token();
-  }
-};
-
-// Builds a GetUpdatesResponse with some progress markers, including
-// invalid ones.  ProcessNewProgressMarkers() should return the model
-// types for the valid progress markers and fill in the progress
-// markers in the directory.
-TEST_F(StoreTimestampsCommandTest, ProcessNewProgressMarkers) {
-  sync_pb::GetUpdatesResponse response;
-  AddProgressMarkerForModelType(&response, BOOKMARKS, "token1");
-  AddProgressMarkerForModelType(&response,
-                                HISTORY_DELETE_DIRECTIVES, "token2");
-  AddProgressMarkerForFieldNumber(&response, -1, "bad token");
-
-  ModelTypeSet forward_progress_types =
-      ProcessNewProgressMarkers(
-          response, session()->context()->directory());
-
-  EXPECT_TRUE(
-      forward_progress_types.Equals(
-          ModelTypeSet(BOOKMARKS, HISTORY_DELETE_DIRECTIVES)));
-
-  EXPECT_EQ("token1", GetProgessMarkerToken(BOOKMARKS));
-  EXPECT_EQ("token2", GetProgessMarkerToken(HISTORY_DELETE_DIRECTIVES));
-
-  ModelTypeSet non_forward_progress_types =
-      Difference(ProtocolTypes(), forward_progress_types);
-  for (ModelTypeSet::Iterator it = non_forward_progress_types.First();
-       it.Good(); it.Inc()) {
-    EXPECT_TRUE(GetProgessMarkerToken(it.Get()).empty());
-  }
-}
-
-}  // namespace
-
-}  // namespace syncer
diff --git a/sync/engine/sync_directory_update_handler.cc b/sync/engine/sync_directory_update_handler.cc
new file mode 100644
index 0000000..0d7953b
--- /dev/null
+++ b/sync/engine/sync_directory_update_handler.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 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 "sync/engine/sync_directory_update_handler.h"
+
+#include "sync/engine/process_updates_util.h"
+#include "sync/sessions/status_controller.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/syncable_model_neutral_write_transaction.h"
+
+namespace syncer {
+
+using syncable::SYNCER;
+
+SyncDirectoryUpdateHandler::SyncDirectoryUpdateHandler(
+    syncable::Directory* dir, ModelType type)
+  : dir_(dir),
+    type_(type) {}
+
+SyncDirectoryUpdateHandler::~SyncDirectoryUpdateHandler() {}
+
+void SyncDirectoryUpdateHandler::GetDownloadProgress(
+    sync_pb::DataTypeProgressMarker* progress_marker) const {
+  dir_->GetDownloadProgress(type_, progress_marker);
+}
+
+void SyncDirectoryUpdateHandler::ProcessGetUpdatesResponse(
+    const sync_pb::DataTypeProgressMarker& progress_marker,
+    const SyncEntityList& applicable_updates,
+    sessions::StatusController* status) {
+  syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
+  UpdateSyncEntities(&trans, applicable_updates, status);
+  UpdateProgressMarker(progress_marker);
+}
+
+void SyncDirectoryUpdateHandler::UpdateSyncEntities(
+    syncable::ModelNeutralWriteTransaction* trans,
+    const SyncEntityList& applicable_updates,
+    sessions::StatusController* status) {
+  ProcessDownloadedUpdates(dir_, trans, type_, applicable_updates, status);
+}
+
+void SyncDirectoryUpdateHandler::UpdateProgressMarker(
+    const sync_pb::DataTypeProgressMarker& progress_marker) {
+  int field_number = progress_marker.data_type_id();
+  ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
+  if (!IsRealDataType(model_type) || type_ != model_type) {
+    NOTREACHED()
+        << "Update handler of type " << ModelTypeToString(type_)
+        << " asked to process progress marker with invalid type "
+        << field_number;
+  }
+  dir_->SetDownloadProgress(type_, progress_marker);
+}
+
+}  // namespace syncer
diff --git a/sync/engine/sync_directory_update_handler.h b/sync/engine/sync_directory_update_handler.h
new file mode 100644
index 0000000..38256a4
--- /dev/null
+++ b/sync/engine/sync_directory_update_handler.h
@@ -0,0 +1,82 @@
+// Copyright 2013 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 SYNC_ENGINE_SYNC_DIRECTORY_UPDATE_HANDLER_H_
+#define SYNC_ENGINE_SYNC_DIRECTORY_UPDATE_HANDLER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "sync/base/sync_export.h"
+#include "sync/engine/process_updates_util.h"
+#include "sync/internal_api/public/base/model_type.h"
+
+namespace sync_pb {
+class DataTypeProgressMarker;
+class GetUpdatesResponse;
+}
+
+namespace syncer {
+
+namespace sessions {
+class StatusController;
+}
+
+namespace syncable {
+class Directory;
+}
+
+// This class represents the syncable::Directory's processes for requesting and
+// processing updates from the sync server.
+//
+// Each instance of this class represents a particular type in the
+// syncable::Directory.  It can store and retreive that type's progress markers.
+// It can also process a set of received SyncEntities and store their data.
+class SYNC_EXPORT_PRIVATE SyncDirectoryUpdateHandler {
+ public:
+  SyncDirectoryUpdateHandler(syncable::Directory* dir, ModelType type);
+  ~SyncDirectoryUpdateHandler();
+
+  // Fills the given parameter with the stored progress marker for this type.
+  void GetDownloadProgress(
+      sync_pb::DataTypeProgressMarker* progress_marker) const;
+
+  // Processes the contents of a GetUpdates response message.
+  //
+  // Should be invoked with the progress marker and set of SyncEntities from a
+  // single GetUpdates response message.  The progress marker's type must match
+  // this update handler's type, and the set of SyncEntities must include all
+  // entities of this type found in the response message.
+  void ProcessGetUpdatesResponse(
+      const sync_pb::DataTypeProgressMarker& progress_marker,
+      const SyncEntityList& applicable_updates,
+      sessions::StatusController* status);
+
+ private:
+  friend class SyncDirectoryUpdateHandlerTest;
+
+  // Processes the given SyncEntities and stores their data in the directory.
+  // Their types must match this update handler's type.
+  void UpdateSyncEntities(
+      syncable::ModelNeutralWriteTransaction* trans,
+      const SyncEntityList& applicable_updates,
+      sessions::StatusController* status);
+
+  // Stores the given progress marker in the directory.
+  // Its type must match this update handler's type.
+  void UpdateProgressMarker(
+      const sync_pb::DataTypeProgressMarker& progress_marker);
+
+  syncable::Directory* dir_;
+  ModelType type_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncDirectoryUpdateHandler);
+};
+
+// TODO(rlarocque): Find a better place to define this.
+typedef std::map<ModelType, SyncDirectoryUpdateHandler*> UpdateHandlerMap;
+
+}  // namespace syncer
+
+#endif  // SYNC_ENGINE_SYNC_DIRECTORY_UPDATE_HANDLER_H_
diff --git a/sync/engine/sync_directory_update_handler_unittest.cc b/sync/engine/sync_directory_update_handler_unittest.cc
new file mode 100644
index 0000000..53589b8
--- /dev/null
+++ b/sync/engine/sync_directory_update_handler_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright 2013 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 "sync/engine/sync_directory_update_handler.h"
+
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "sync/engine/syncer_proto_util.h"
+#include "sync/internal_api/public/base/model_type.h"
+#include "sync/protocol/sync.pb.h"
+#include "sync/sessions/status_controller.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/syncable_model_neutral_write_transaction.h"
+#include "sync/syncable/syncable_proto_util.h"
+#include "sync/syncable/syncable_read_transaction.h"
+#include "sync/test/engine/test_directory_setter_upper.h"
+#include "sync/test/engine/test_syncable_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+using syncable::UNITTEST;
+
+class SyncDirectoryUpdateHandlerTest : public ::testing::Test {
+ public:
+  virtual void SetUp() OVERRIDE {
+    dir_maker_.SetUp();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    dir_maker_.TearDown();
+  }
+
+  syncable::Directory* dir() {
+    return dir_maker_.directory();
+  }
+ protected:
+  scoped_ptr<sync_pb::SyncEntity> CreateUpdate(
+      const std::string& id,
+      const std::string& parent,
+      const ModelType& type);
+
+  // This exists mostly to give tests access to the protected member function.
+  // Warning: This takes the syncable directory lock.
+  void UpdateSyncEntities(
+      SyncDirectoryUpdateHandler* handler,
+      const SyncEntityList& applicable_updates,
+      sessions::StatusController* status);
+
+  // Another function to access private member functions.
+  void UpdateProgressMarkers(
+      SyncDirectoryUpdateHandler* handler,
+      const sync_pb::DataTypeProgressMarker& progress);
+
+ private:
+  base::MessageLoop loop_;  // Needed to initialize the directory.
+  TestDirectorySetterUpper dir_maker_;
+};
+
+scoped_ptr<sync_pb::SyncEntity> SyncDirectoryUpdateHandlerTest::CreateUpdate(
+    const std::string& id,
+    const std::string& parent,
+    const ModelType& type) {
+  scoped_ptr<sync_pb::SyncEntity> e(new sync_pb::SyncEntity());
+  e->set_id_string(id);
+  e->set_parent_id_string(parent);
+  e->set_non_unique_name(id);
+  e->set_name(id);
+  e->set_version(1000);
+  AddDefaultFieldValue(type, e->mutable_specifics());
+  return e.Pass();
+}
+
+void SyncDirectoryUpdateHandlerTest::UpdateSyncEntities(
+    SyncDirectoryUpdateHandler* handler,
+    const SyncEntityList& applicable_updates,
+    sessions::StatusController* status) {
+  syncable::ModelNeutralWriteTransaction trans(FROM_HERE, UNITTEST, dir());
+  handler->UpdateSyncEntities(&trans, applicable_updates, status);
+}
+
+void SyncDirectoryUpdateHandlerTest::UpdateProgressMarkers(
+    SyncDirectoryUpdateHandler* handler,
+    const sync_pb::DataTypeProgressMarker& progress) {
+  handler->UpdateProgressMarker(progress);
+}
+
+static const char kCacheGuid[] = "IrcjZ2jyzHDV9Io4+zKcXQ==";
+
+// Test that the bookmark tag is set on newly downloaded items.
+TEST_F(SyncDirectoryUpdateHandlerTest, NewBookmarkTag) {
+  SyncDirectoryUpdateHandler handler(dir(), BOOKMARKS);
+  sync_pb::GetUpdatesResponse gu_response;
+  sessions::StatusController status;
+
+  // Add a bookmark item to the update message.
+  std::string root = syncable::GetNullId().GetServerId();
+  syncable::Id server_id = syncable::Id::CreateFromServerId("b1");
+  scoped_ptr<sync_pb::SyncEntity> e =
+      CreateUpdate(SyncableIdToProto(server_id), root, BOOKMARKS);
+  e->set_originator_cache_guid(
+      std::string(kCacheGuid, arraysize(kCacheGuid)-1));
+  syncable::Id client_id = syncable::Id::CreateFromClientString("-2");
+  e->set_originator_client_item_id(client_id.GetServerId());
+  e->set_position_in_parent(0);
+
+  // Add it to the applicable updates list.
+  SyncEntityList bookmark_updates;
+  bookmark_updates.push_back(e.get());
+
+  // Process the update.
+  UpdateSyncEntities(&handler, bookmark_updates, &status);
+
+  syncable::ReadTransaction trans(FROM_HERE, dir());
+  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
+  ASSERT_TRUE(entry.good());
+  EXPECT_TRUE(UniquePosition::IsValidSuffix(entry.GetUniqueBookmarkTag()));
+  EXPECT_TRUE(entry.GetServerUniquePosition().IsValid());
+
+  // If this assertion fails, that might indicate that the algorithm used to
+  // generate bookmark tags has been modified.  This could have implications for
+  // bookmark ordering.  Please make sure you know what you're doing if you
+  // intend to make such a change.
+  EXPECT_EQ("6wHRAb3kbnXV5GHrejp4/c1y5tw=", entry.GetUniqueBookmarkTag());
+}
+
+// Test the receipt of a type root node.
+TEST_F(SyncDirectoryUpdateHandlerTest, ReceiveServerCreatedBookmarkFolders) {
+  SyncDirectoryUpdateHandler handler(dir(), BOOKMARKS);
+  sync_pb::GetUpdatesResponse gu_response;
+  sessions::StatusController status;
+
+  // Create an update that mimics the bookmark root.
+  syncable::Id server_id = syncable::Id::CreateFromServerId("xyz");
+  std::string root = syncable::GetNullId().GetServerId();
+  scoped_ptr<sync_pb::SyncEntity> e =
+      CreateUpdate(SyncableIdToProto(server_id), root, BOOKMARKS);
+  e->set_server_defined_unique_tag("google_chrome_bookmarks");
+  e->set_folder(true);
+
+  // Add it to the applicable updates list.
+  SyncEntityList bookmark_updates;
+  bookmark_updates.push_back(e.get());
+
+  EXPECT_FALSE(SyncerProtoUtil::ShouldMaintainPosition(*e));
+
+  // Process it.
+  UpdateSyncEntities(&handler, bookmark_updates, &status);
+
+  // Verify the results.
+  syncable::ReadTransaction trans(FROM_HERE, dir());
+  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
+  ASSERT_TRUE(entry.good());
+
+  EXPECT_FALSE(entry.ShouldMaintainPosition());
+  EXPECT_FALSE(entry.GetUniquePosition().IsValid());
+  EXPECT_FALSE(entry.GetServerUniquePosition().IsValid());
+  EXPECT_TRUE(entry.GetUniqueBookmarkTag().empty());
+}
+
+// Test the receipt of a non-bookmark item.
+TEST_F(SyncDirectoryUpdateHandlerTest, ReceiveNonBookmarkItem) {
+  SyncDirectoryUpdateHandler handler(dir(), AUTOFILL);
+  sync_pb::GetUpdatesResponse gu_response;
+  sessions::StatusController status;
+
+  std::string root = syncable::GetNullId().GetServerId();
+  syncable::Id server_id = syncable::Id::CreateFromServerId("xyz");
+  scoped_ptr<sync_pb::SyncEntity> e =
+      CreateUpdate(SyncableIdToProto(server_id), root, AUTOFILL);
+  e->set_server_defined_unique_tag("9PGRuKdX5sHyGMB17CvYTXuC43I=");
+
+  // Add it to the applicable updates list.
+  SyncEntityList autofill_updates;
+  autofill_updates.push_back(e.get());
+
+  EXPECT_FALSE(SyncerProtoUtil::ShouldMaintainPosition(*e));
+
+  // Process it.
+  UpdateSyncEntities(&handler, autofill_updates, &status);
+
+  syncable::ReadTransaction trans(FROM_HERE, dir());
+  syncable::Entry entry(&trans, syncable::GET_BY_ID, server_id);
+  ASSERT_TRUE(entry.good());
+
+  EXPECT_FALSE(entry.ShouldMaintainPosition());
+  EXPECT_FALSE(entry.GetUniquePosition().IsValid());
+  EXPECT_FALSE(entry.GetServerUniquePosition().IsValid());
+  EXPECT_TRUE(entry.GetUniqueBookmarkTag().empty());
+}
+
+// Tests the setting of progress markers.
+TEST_F(SyncDirectoryUpdateHandlerTest, ProcessNewProgressMarkers) {
+  SyncDirectoryUpdateHandler handler(dir(), BOOKMARKS);
+
+  sync_pb::DataTypeProgressMarker progress;
+  progress.set_data_type_id(GetSpecificsFieldNumberFromModelType(BOOKMARKS));
+  progress.set_token("token");
+
+  UpdateProgressMarkers(&handler, progress);
+
+  sync_pb::DataTypeProgressMarker saved;
+  dir()->GetDownloadProgress(BOOKMARKS, &saved);
+
+  EXPECT_EQ(progress.token(), saved.token());
+  EXPECT_EQ(progress.data_type_id(), saved.data_type_id());
+}
+
+}  // namespace syncer
diff --git a/sync/engine/sync_engine_event.h b/sync/engine/sync_engine_event.h
index 3328ff3..25f9692 100644
--- a/sync/engine/sync_engine_event.h
+++ b/sync/engine/sync_engine_event.h
@@ -32,9 +32,6 @@
     ////////////////////////////////////////////////////////////////
     // Generated in response to specific protocol actions or events.
 
-    // New token in updated_token.
-    UPDATED_TOKEN,
-
     // This is sent after the Syncer (and SyncerThread) have initiated self
     // halt due to no longer being permitted to communicate with the server.
     // The listener should sever the sync / browser connections and delete sync
diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc
index 9f2c378..50cc167 100644
--- a/sync/engine/syncer.cc
+++ b/sync/engine/syncer.cc
@@ -61,6 +61,7 @@
   if (nudge_tracker.IsGetUpdatesRequired() ||
       session->context()->ShouldFetchUpdatesBeforeCommit()) {
     if (!DownloadAndApplyUpdates(
+            request_types,
             session,
             base::Bind(&BuildNormalDownloadUpdates,
                        session,
@@ -85,6 +86,7 @@
   HandleCycleBegin(session);
   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
   DownloadAndApplyUpdates(
+      request_types,
       session,
       base::Bind(&BuildDownloadUpdatesForConfigure,
                  session,
@@ -99,6 +101,7 @@
   HandleCycleBegin(session);
   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
   DownloadAndApplyUpdates(
+      request_types,
       session,
       base::Bind(&BuildDownloadUpdatesForPoll,
                  session,
@@ -122,13 +125,15 @@
 }
 
 bool Syncer::DownloadAndApplyUpdates(
+    ModelTypeSet request_types,
     SyncSession* session,
     base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn) {
   while (!session->status_controller().ServerSaysNothingMoreToDownload()) {
     TRACE_EVENT0("sync", "DownloadUpdates");
     sync_pb::ClientToServerMessage msg;
     build_fn.Run(&msg);
-    SyncerError download_result = ExecuteDownloadUpdates(session, &msg);
+    SyncerError download_result =
+        ExecuteDownloadUpdates(request_types, session, &msg);
     session->mutable_status_controller()->set_last_download_updates_result(
         download_result);
     if (download_result != SYNCER_OK) {
diff --git a/sync/engine/syncer.h b/sync/engine/syncer.h
index d943e5f..5661fff 100644
--- a/sync/engine/syncer.h
+++ b/sync/engine/syncer.h
@@ -70,6 +70,7 @@
  private:
   void ApplyUpdates(sessions::SyncSession* session);
   bool DownloadAndApplyUpdates(
+      ModelTypeSet request_types,
       sessions::SyncSession* session,
       base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn);
 
diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc
index 863a8c4..bfd8151 100644
--- a/sync/engine/syncer_proto_util.cc
+++ b/sync/engine/syncer_proto_util.cc
@@ -276,13 +276,6 @@
     return false;
   }
 
-  std::string new_token = params.response.update_client_auth_header;
-  if (!new_token.empty()) {
-    SyncEngineEvent event(SyncEngineEvent::UPDATED_TOKEN);
-    event.updated_token = new_token;
-    session->context()->NotifyListeners(event);
-  }
-
   if (response->ParseFromString(params.buffer_out)) {
     // TODO(tim): This is an egregious layering violation (bug 35060).
     switch (response->error_code()) {
diff --git a/sync/engine/syncer_proto_util_unittest.cc b/sync/engine/syncer_proto_util_unittest.cc
index ff37e56..ec023da 100644
--- a/sync/engine/syncer_proto_util_unittest.cc
+++ b/sync/engine/syncer_proto_util_unittest.cc
@@ -256,7 +256,7 @@
 class DummyConnectionManager : public ServerConnectionManager {
  public:
   DummyConnectionManager(CancelationSignal* signal)
-      : ServerConnectionManager("unused", 0, false, false, signal),
+      : ServerConnectionManager("unused", 0, false, signal),
         send_error_(false),
         access_denied_(false) {}
 
diff --git a/sync/engine/syncer_types.h b/sync/engine/syncer_types.h
index ada4d82..36f3dbc 100644
--- a/sync/engine/syncer_types.h
+++ b/sync/engine/syncer_types.h
@@ -45,26 +45,6 @@
   CONFLICT_SIMPLE
 };
 
-enum ServerUpdateProcessingResult {
-  // Success. Update applied and stored in SERVER_* fields or dropped if
-  // irrelevant.
-  SUCCESS_PROCESSED,
-
-  // Success. Update details stored in SERVER_* fields, but wasn't applied.
-  SUCCESS_STORED,
-
-  // Update is illegally inconsistent with earlier updates. e.g. A bookmark
-  // becoming a folder.
-  FAILED_INCONSISTENT,
-
-  // Update is illegal when considered alone. e.g. broken UTF-8 in the name.
-  FAILED_CORRUPT,
-
-  // Only used by VerifyUpdate. Indicates that an update is valid. As
-  // VerifyUpdate cannot return SUCCESS_STORED, we reuse the value.
-  SUCCESS_VALID = SUCCESS_STORED
-};
-
 // Different results from the verify phase will yield different methods of
 // processing in the ProcessUpdates phase. The SKIP result means the entry
 // doesn't go to the ProcessUpdates phase.
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index a7825dc..b9c7780 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -25,7 +25,6 @@
 #include "build/build_config.h"
 #include "sync/engine/get_commit_ids.h"
 #include "sync/engine/net/server_connection_manager.h"
-#include "sync/engine/process_updates_command.h"
 #include "sync/engine/sync_scheduler_impl.h"
 #include "sync/engine/syncer.h"
 #include "sync/engine/syncer_proto_util.h"
diff --git a/sync/internal_api/debug_info_event_listener.cc b/sync/internal_api/debug_info_event_listener.cc
index 222fa23..7875ed9 100644
--- a/sync/internal_api/debug_info_event_listener.cc
+++ b/sync/internal_api/debug_info_event_listener.cc
@@ -89,11 +89,6 @@
   CreateAndAddEvent(sync_pb::DebugEventInfo::STOP_SYNCING_PERMANENTLY);
 }
 
-void DebugInfoEventListener::OnUpdatedToken(const std::string& token) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  CreateAndAddEvent(sync_pb::DebugEventInfo::UPDATED_TOKEN);
-}
-
 void DebugInfoEventListener::OnEncryptedTypesChanged(
     ModelTypeSet encrypted_types,
     bool encrypt_everything) {
diff --git a/sync/internal_api/debug_info_event_listener.h b/sync/internal_api/debug_info_event_listener.h
index b0c079e..b7a187a 100644
--- a/sync/internal_api/debug_info_event_listener.h
+++ b/sync/internal_api/debug_info_event_listener.h
@@ -47,7 +47,6 @@
   virtual void OnConnectionStatusChange(
       ConnectionStatus connection_status) OVERRIDE;
   virtual void OnStopSyncingPermanently() OVERRIDE;
-  virtual void OnUpdatedToken(const std::string& token) OVERRIDE;
   virtual void OnActionableError(
       const SyncProtocolError& sync_error) OVERRIDE;
 
diff --git a/sync/internal_api/js_sync_manager_observer.cc b/sync/internal_api/js_sync_manager_observer.cc
index 01ddda8..9f8848d 100644
--- a/sync/internal_api/js_sync_manager_observer.cc
+++ b/sync/internal_api/js_sync_manager_observer.cc
@@ -49,15 +49,6 @@
                 "onConnectionStatusChange", JsEventDetails(&details));
 }
 
-void JsSyncManagerObserver::OnUpdatedToken(const std::string& token) {
-  if (!event_handler_.IsInitialized()) {
-    return;
-  }
-  base::DictionaryValue details;
-  details.SetString("token", "<redacted>");
-  HandleJsEvent(FROM_HERE, "onUpdatedToken", JsEventDetails(&details));
-}
-
 void JsSyncManagerObserver::OnActionableError(
     const SyncProtocolError& sync_error) {
   if (!event_handler_.IsInitialized()) {
diff --git a/sync/internal_api/js_sync_manager_observer.h b/sync/internal_api/js_sync_manager_observer.h
index bda6d8c..17a40e7 100644
--- a/sync/internal_api/js_sync_manager_observer.h
+++ b/sync/internal_api/js_sync_manager_observer.h
@@ -35,7 +35,6 @@
   virtual void OnSyncCycleCompleted(
       const sessions::SyncSessionSnapshot& snapshot) OVERRIDE;
   virtual void OnConnectionStatusChange(ConnectionStatus status) OVERRIDE;
-  virtual void OnUpdatedToken(const std::string& token) OVERRIDE;
   virtual void OnInitializationComplete(
       const WeakHandle<JsBackend>& js_backend,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
diff --git a/sync/internal_api/js_sync_manager_observer_unittest.cc b/sync/internal_api/js_sync_manager_observer_unittest.cc
index 65cb77e..e4b8c64 100644
--- a/sync/internal_api/js_sync_manager_observer_unittest.cc
+++ b/sync/internal_api/js_sync_manager_observer_unittest.cc
@@ -129,19 +129,5 @@
   PumpLoop();
 }
 
-TEST_F(JsSyncManagerObserverTest, SensitiveNotifiations) {
-  base::DictionaryValue redacted_token_details;
-  redacted_token_details.SetString("token", "<redacted>");
-  base::DictionaryValue redacted_bootstrap_token_details;
-  redacted_bootstrap_token_details.SetString("bootstrapToken", "<redacted>");
-
-  EXPECT_CALL(mock_js_event_handler_,
-              HandleJsEvent("onUpdatedToken",
-                           HasDetailsAsDictionary(redacted_token_details)));
-
-  js_sync_manager_observer_.OnUpdatedToken("sensitive_token");
-  PumpLoop();
-}
-
 }  // namespace
 }  // namespace syncer
diff --git a/sync/internal_api/public/base/DEPS b/sync/internal_api/public/base/DEPS
index 047cfd4..9d46a8a 100644
--- a/sync/internal_api/public/base/DEPS
+++ b/sync/internal_api/public/base/DEPS
@@ -6,6 +6,7 @@
   "-sync",
   "+sync/base",
   "+sync/internal_api/public/base",
+  "+sync/internal_api/public/util",
+  "+sync/notifier",
   "+sync/protocol",
-  "+sync/notifier"
 ]
diff --git a/sync/internal_api/public/base/invalidation.cc b/sync/internal_api/public/base/invalidation.cc
index 55fdcc7..1292a51 100644
--- a/sync/internal_api/public/base/invalidation.cc
+++ b/sync/internal_api/public/base/invalidation.cc
@@ -10,6 +10,8 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
+#include "sync/notifier/ack_handler.h"
+#include "sync/notifier/dropped_invalidation_tracker.h"
 #include "sync/notifier/invalidation_util.h"
 
 namespace syncer {
@@ -19,6 +21,7 @@
 const char kIsUnknownVersionKey[] = "isUnknownVersion";
 const char kVersionKey[] = "version";
 const char kPayloadKey[] = "payload";
+const int64 kInvalidVersion = -1;
 }
 
 Invalidation Invalidation::Init(
@@ -30,7 +33,14 @@
 
 Invalidation Invalidation::InitUnknownVersion(
     const invalidation::ObjectId& id) {
-  return Invalidation(id, true, -1, std::string(), AckHandle::CreateUnique());
+  return Invalidation(id, true, kInvalidVersion,
+                      std::string(), AckHandle::CreateUnique());
+}
+
+Invalidation Invalidation::InitFromDroppedInvalidation(
+    const Invalidation& dropped) {
+  return Invalidation(dropped.id_, true, kInvalidVersion,
+                      std::string(), dropped.ack_handle_);
 }
 
 scoped_ptr<Invalidation> Invalidation::InitFromValue(
@@ -52,7 +62,7 @@
     return scoped_ptr<Invalidation>(new Invalidation(
         id,
         true,
-        -1,
+        kInvalidVersion,
         std::string(),
         AckHandle::CreateUnique()));
   } else {
@@ -105,6 +115,32 @@
   ack_handle_ = ack_handle;
 }
 
+void Invalidation::set_ack_handler(syncer::WeakHandle<AckHandler> handler) {
+  ack_handler_ = handler;
+}
+
+bool Invalidation::SupportsAcknowledgement() const {
+  return ack_handler_.IsInitialized();
+}
+
+void Invalidation::Acknowledge() const {
+  if (SupportsAcknowledgement()) {
+    ack_handler_.Call(FROM_HERE,
+                      &AckHandler::Acknowledge,
+                      id_,
+                      ack_handle_);
+  }
+}
+
+void Invalidation::Drop(DroppedInvalidationTracker* tracker) const {
+  DCHECK(tracker->object_id() == object_id());
+  tracker->RecordDropEvent(ack_handler_, ack_handle_);
+  ack_handler_.Call(FROM_HERE,
+                    &AckHandler::Drop,
+                    id_,
+                    ack_handle_);
+}
+
 bool Invalidation::Equals(const Invalidation& other) const {
   return id_ == other.id_
       && is_unknown_version_ == other.is_unknown_version_
diff --git a/sync/internal_api/public/base/invalidation.h b/sync/internal_api/public/base/invalidation.h
index 2b83564..472f552 100644
--- a/sync/internal_api/public/base/invalidation.h
+++ b/sync/internal_api/public/base/invalidation.h
@@ -13,6 +13,7 @@
 #include "google/cacheinvalidation/include/types.h"
 #include "sync/base/sync_export.h"
 #include "sync/internal_api/public/base/ack_handle.h"
+#include "sync/internal_api/public/util/weak_handle.h"
 
 namespace syncer {
 
@@ -30,6 +31,7 @@
       int64 version,
       const std::string& payload);
   static Invalidation InitUnknownVersion(const invalidation::ObjectId& id);
+  static Invalidation InitFromDroppedInvalidation(const Invalidation& dropped);
   static scoped_ptr<Invalidation> InitFromValue(
       const base::DictionaryValue& value);
 
@@ -48,8 +50,24 @@
   const std::string& payload() const;
 
   const AckHandle& ack_handle() const;
+
+  // TODO(rlarocque): Remove this method and use AckHandlers instead.
   void set_ack_handle(const AckHandle& ack_handle);
 
+  // Functions from the alternative ack tracking framework.
+  // Currently unused.
+  void set_ack_handler(syncer::WeakHandle<AckHandler> ack_handler);
+  bool SupportsAcknowledgement() const;
+  void Acknowledge() const;
+
+  // Drops an invalidation.
+  //
+  // The drop record will be tracked by the specified
+  // DroppedInvalidationTracker.  The caller should hang on to this tracker.  It
+  // will need to use it when it recovers from this drop event.  See the
+  // documentation of DroppedInvalidationTracker for more details.
+  void Drop(DroppedInvalidationTracker* tracker) const;
+
   scoped_ptr<base::DictionaryValue> ToValue() const;
   std::string ToString() const;
 
@@ -76,6 +94,7 @@
 
   // A locally generated unique ID used to manage local acknowledgements.
   AckHandle ack_handle_;
+  syncer::WeakHandle<AckHandler> ack_handler_;
 };
 
 }  // namespace syncer
diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h
index 735e5ed..1cd3319 100644
--- a/sync/internal_api/public/sync_manager.h
+++ b/sync/internal_api/public/sync_manager.h
@@ -176,9 +176,6 @@
     // changed.
     virtual void OnConnectionStatusChange(ConnectionStatus status) = 0;
 
-    // Called when a new auth token is provided by the sync server.
-    virtual void OnUpdatedToken(const std::string& token) = 0;
-
     // Called when initialization is complete to the point that SyncManager can
     // process changes. This does not necessarily mean authentication succeeded
     // or that the SyncManager is online.
@@ -324,7 +321,6 @@
       Encryptor* encryptor,
       scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
       ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
-      bool use_oauth2_token,
       CancelationSignal* cancelation_signal) = 0;
 
   // Throw an unrecoverable error from a transaction (mostly used for
diff --git a/sync/internal_api/public/test/fake_sync_manager.h b/sync/internal_api/public/test/fake_sync_manager.h
index 300921c..a6e7b47 100644
--- a/sync/internal_api/public/test/fake_sync_manager.h
+++ b/sync/internal_api/public/test/fake_sync_manager.h
@@ -92,7 +92,6 @@
       Encryptor* encryptor,
       scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
       ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
-      bool use_oauth2_token,
       CancelationSignal* cancelation_signal) OVERRIDE;
   virtual void ThrowUnrecoverableError() OVERRIDE;
   virtual ModelTypeSet InitialSyncEndedTypes() OVERRIDE;
diff --git a/sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h b/sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h
new file mode 100644
index 0000000..d8615c0
--- /dev/null
+++ b/sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h
@@ -0,0 +1,30 @@
+// Copyright 2013 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 SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FACTORY_FOR_PROFILE_SYNC_TEST_H_
+#define SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FACTORY_FOR_PROFILE_SYNC_TEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "sync/internal_api/public/sync_manager_factory.h"
+
+namespace syncer {
+
+class SyncManagerFactoryForProfileSyncTest : public syncer::SyncManagerFactory {
+ public:
+  SyncManagerFactoryForProfileSyncTest(base::Closure init_callback,
+                                       bool set_initial_sync_ended);
+  virtual ~SyncManagerFactoryForProfileSyncTest();
+  virtual scoped_ptr<syncer::SyncManager> CreateSyncManager(
+      std::string name) OVERRIDE;
+ private:
+  base::Closure init_callback_;
+  bool set_initial_sync_ended_;
+};
+
+}  // namespace syncer
+
+#endif  // SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FACTORY_FOR_PROFILE_SYNC_TEST_H_
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index 6f7a1b9..336e57b 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -355,7 +355,6 @@
     Encryptor* encryptor,
     scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
     ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
-    bool use_oauth2_token,
     CancelationSignal* cancelation_signal) {
   CHECK(!initialized_);
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -410,18 +409,13 @@
 
   DVLOG(1) << "Username: " << username;
   if (!OpenDirectory(username)) {
-    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
-                      OnInitializationComplete(
-                          MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
-                          MakeWeakHandle(
-                              debug_info_event_listener_.GetWeakPtr()),
-                          false, ModelTypeSet()));
+    NotifyInitializationFailure();
     LOG(ERROR) << "Sync manager initialization failed!";
     return;
   }
 
   connection_manager_.reset(new SyncAPIServerConnectionManager(
-      sync_server_and_path, port, use_ssl, use_oauth2_token,
+      sync_server_and_path, port, use_ssl,
       post_factory.release(), cancelation_signal));
   connection_manager_->set_client_id(directory()->cache_guid());
   connection_manager_->AddListener(this);
@@ -462,6 +456,10 @@
 
   UpdateCredentials(credentials);
 
+  NotifyInitializationSuccess();
+}
+
+void SyncManagerImpl::NotifyInitializationSuccess() {
   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                     OnInitializationComplete(
                         MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
@@ -469,6 +467,14 @@
                         true, InitialSyncEndedTypes()));
 }
 
+void SyncManagerImpl::NotifyInitializationFailure() {
+  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
+                    OnInitializationComplete(
+                        MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
+                        MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
+                        false, ModelTypeSet()));
+}
+
 void SyncManagerImpl::OnPassphraseRequired(
     PassphraseRequiredReason reason,
     const sync_pb::EncryptedData& pending_keys) {
@@ -943,12 +949,6 @@
     return;
   }
 
-  if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
-    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
-                      OnUpdatedToken(event.updated_token));
-    return;
-  }
-
   if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
     FOR_EACH_OBSERVER(
         SyncManager::Observer, observers_,
diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h
index d9dd542..5d5cfaa 100644
--- a/sync/internal_api/sync_manager_impl.h
+++ b/sync/internal_api/sync_manager_impl.h
@@ -81,7 +81,6 @@
       scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
       ReportUnrecoverableErrorFunction
           report_unrecoverable_error_function,
-      bool use_oauth2_token,
       CancelationSignal* cancelation_signal) OVERRIDE;
   virtual void ThrowUnrecoverableError() OVERRIDE;
   virtual ModelTypeSet InitialSyncEndedTypes() OVERRIDE;
@@ -181,6 +180,11 @@
 
   bool GetHasInvalidAuthTokenForTest() const;
 
+ protected:
+  // Helper functions.  Virtual for testing.
+  virtual void NotifyInitializationSuccess();
+  virtual void NotifyInitializationFailure();
+
  private:
   friend class SyncManagerTest;
   FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, NudgeDelayTest);
diff --git a/sync/internal_api/sync_manager_impl_unittest.cc b/sync/internal_api/sync_manager_impl_unittest.cc
index 5549895..542b082 100644
--- a/sync/internal_api/sync_manager_impl_unittest.cc
+++ b/sync/internal_api/sync_manager_impl_unittest.cc
@@ -835,7 +835,6 @@
         scoped_ptr<UnrecoverableErrorHandler>(
             new TestUnrecoverableErrorHandler).Pass(),
         NULL,
-        false,
         &cancelation_signal_);
 
     sync_manager_.GetEncryptionHandler()->AddObserver(&encryption_observer_);
diff --git a/sync/internal_api/syncapi_server_connection_manager.cc b/sync/internal_api/syncapi_server_connection_manager.cc
index ccfa6e6..35ca1e2 100644
--- a/sync/internal_api/syncapi_server_connection_manager.cc
+++ b/sync/internal_api/syncapi_server_connection_manager.cc
@@ -31,8 +31,7 @@
   std::string sync_server;
   int sync_server_port = 0;
   bool use_ssl = false;
-  bool use_oauth2_token = false;
-  GetServerParams(&sync_server, &sync_server_port, &use_ssl, &use_oauth2_token);
+  GetServerParams(&sync_server, &sync_server_port, &use_ssl);
   std::string connection_url = MakeConnectionURL(sync_server, path, use_ssl);
 
   HttpPostProviderInterface* http = post_provider_;
@@ -40,10 +39,7 @@
 
   if (!auth_token.empty()) {
     std::string headers;
-    if (use_oauth2_token)
-      headers = "Authorization: Bearer " + auth_token;
-    else
-      headers = "Authorization: GoogleLogin auth=" + auth_token;
+    headers = "Authorization: Bearer " + auth_token;
     http->SetExtraRequestHeaders(headers.c_str());
   }
 
@@ -74,9 +70,6 @@
   else
     response->server_status = HttpResponse::SYNC_SERVER_ERROR;
 
-  response->update_client_auth_header =
-      http->GetResponseHeaderValue("Update-Client-Auth");
-
   // Write the content into our buffer.
   buffer_.assign(http->GetResponseContent(), http->GetResponseContentLength());
   return true;
@@ -91,13 +84,11 @@
     const std::string& server,
     int port,
     bool use_ssl,
-    bool use_oauth2_token,
     HttpPostProviderFactory* factory,
     CancelationSignal* cancelation_signal)
     : ServerConnectionManager(server,
                               port,
                               use_ssl,
-                              use_oauth2_token,
                               cancelation_signal),
       post_provider_factory_(factory) {
   DCHECK(post_provider_factory_.get());
diff --git a/sync/internal_api/syncapi_server_connection_manager.h b/sync/internal_api/syncapi_server_connection_manager.h
index 4805045..118d314 100644
--- a/sync/internal_api/syncapi_server_connection_manager.h
+++ b/sync/internal_api/syncapi_server_connection_manager.h
@@ -54,7 +54,6 @@
   SyncAPIServerConnectionManager(const std::string& server,
                                  int port,
                                  bool use_ssl,
-                                 bool use_oauth2_token,
                                  HttpPostProviderFactory* factory,
                                  CancelationSignal* cancelation_signal);
   virtual ~SyncAPIServerConnectionManager();
diff --git a/sync/internal_api/syncapi_server_connection_manager_unittest.cc b/sync/internal_api/syncapi_server_connection_manager_unittest.cc
index 543455e..2cb3dff 100644
--- a/sync/internal_api/syncapi_server_connection_manager_unittest.cc
+++ b/sync/internal_api/syncapi_server_connection_manager_unittest.cc
@@ -74,7 +74,7 @@
   CancelationSignal signal;
   signal.Signal();
   SyncAPIServerConnectionManager server(
-      "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
+      "server", 0, true, new BlockingHttpPostFactory(), &signal);
 
   ServerConnectionManager::PostBufferParams params;
   ScopedServerStatusWatcher watcher(&server, &params.response);
@@ -91,7 +91,7 @@
 TEST(SyncAPIServerConnectionManagerTest, EarlyAbortPost) {
   CancelationSignal signal;
   SyncAPIServerConnectionManager server(
-      "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
+      "server", 0, true, new BlockingHttpPostFactory(), &signal);
 
   ServerConnectionManager::PostBufferParams params;
   ScopedServerStatusWatcher watcher(&server, &params.response);
@@ -109,7 +109,7 @@
 TEST(SyncAPIServerConnectionManagerTest, AbortPost) {
   CancelationSignal signal;
   SyncAPIServerConnectionManager server(
-      "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
+      "server", 0, true, new BlockingHttpPostFactory(), &signal);
 
   ServerConnectionManager::PostBufferParams params;
   ScopedServerStatusWatcher watcher(&server, &params.response);
diff --git a/sync/internal_api/test/fake_sync_manager.cc b/sync/internal_api/test/fake_sync_manager.cc
index 362b74e..05bddd9 100644
--- a/sync/internal_api/test/fake_sync_manager.cc
+++ b/sync/internal_api/test/fake_sync_manager.cc
@@ -91,7 +91,6 @@
     Encryptor* encryptor,
     scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
     ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
-    bool use_oauth2_token,
     CancelationSignal* cancelation_signal) {
   sync_task_runner_ = base::ThreadTaskRunnerHandle::Get();
   PurgePartiallySyncedTypes();
diff --git a/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc b/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc
new file mode 100644
index 0000000..df4073b
--- /dev/null
+++ b/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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 "sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h"
+
+#include "sync/internal_api/test/sync_manager_for_profile_sync_test.h"
+
+namespace syncer {
+
+SyncManagerFactoryForProfileSyncTest::SyncManagerFactoryForProfileSyncTest(
+    base::Closure init_callback,
+    bool set_initial_sync_ended)
+  : init_callback_(init_callback),
+    set_initial_sync_ended_(set_initial_sync_ended) {
+}
+
+SyncManagerFactoryForProfileSyncTest::~SyncManagerFactoryForProfileSyncTest() {}
+
+scoped_ptr<syncer::SyncManager>
+SyncManagerFactoryForProfileSyncTest::CreateSyncManager(std::string name) {
+  return scoped_ptr<syncer::SyncManager>(
+      new SyncManagerForProfileSyncTest(
+          name,
+          init_callback_,
+          set_initial_sync_ended_));
+}
+
+}  // namespace syncer
diff --git a/sync/internal_api/test/sync_manager_for_profile_sync_test.cc b/sync/internal_api/test/sync_manager_for_profile_sync_test.cc
new file mode 100644
index 0000000..aaa6c8d
--- /dev/null
+++ b/sync/internal_api/test/sync_manager_for_profile_sync_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 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 "sync/internal_api/test/sync_manager_for_profile_sync_test.h"
+
+#include "sync/internal_api/public/test/test_user_share.h"
+#include "sync/internal_api/public/user_share.h"
+#include "sync/syncable/directory.h"
+
+namespace syncer {
+
+SyncManagerForProfileSyncTest::SyncManagerForProfileSyncTest(
+    std::string name,
+    base::Closure init_callback,
+    bool set_initial_sync_ended)
+  : SyncManagerImpl(name),
+    init_callback_(init_callback),
+    set_initial_sync_ended_(set_initial_sync_ended) {}
+
+SyncManagerForProfileSyncTest::~SyncManagerForProfileSyncTest() {}
+
+void SyncManagerForProfileSyncTest::NotifyInitializationSuccess() {
+  UserShare* user_share = GetUserShare();
+  syncable::Directory* directory = user_share->directory.get();
+
+  if (!init_callback_.is_null())
+    init_callback_.Run();
+
+  if (set_initial_sync_ended_) {
+    ModelTypeSet early_download_types;
+    early_download_types.PutAll(ControlTypes());
+    early_download_types.PutAll(PriorityUserTypes());
+    for (ModelTypeSet::Iterator it = early_download_types.First();
+         it.Good(); it.Inc()) {
+      if (!directory->InitialSyncEndedForType(it.Get())) {
+        syncer::TestUserShare::CreateRoot(it.Get(), user_share);
+      }
+    }
+  } else {
+    VLOG(2) << "Skipping directory init";
+  }
+
+  SyncManagerImpl::NotifyInitializationSuccess();
+}
+
+};
diff --git a/sync/internal_api/test/sync_manager_for_profile_sync_test.h b/sync/internal_api/test/sync_manager_for_profile_sync_test.h
new file mode 100644
index 0000000..c9af22d
--- /dev/null
+++ b/sync/internal_api/test/sync_manager_for_profile_sync_test.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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 SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FOR_PROFILE_SYNC_TEST_H_
+#define SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FOR_PROFILE_SYNC_TEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "sync/internal_api/sync_manager_impl.h"
+
+namespace syncer {
+
+// This class is used to help implement the TestProfileSyncService.
+// Those tests try to test sync without instantiating a real backend.
+class SyncManagerForProfileSyncTest
+    : public syncer::SyncManagerImpl {
+ public:
+  SyncManagerForProfileSyncTest(std::string name,
+                                base::Closure init_callback,
+                                bool set_initial_sync_ended);
+  virtual ~SyncManagerForProfileSyncTest();
+  virtual void NotifyInitializationSuccess() OVERRIDE;
+
+ private:
+  base::Closure init_callback_;
+  bool set_initial_sync_ended_;
+};
+
+}  // namespace syncer
+
+#endif  // SYNC_INTERNAL_API_PUBLIC_TEST_SYNC_MANAGER_FOR_PROFILE_SYNC_TEST_H_
diff --git a/sync/notifier/ack_handler.cc b/sync/notifier/ack_handler.cc
new file mode 100644
index 0000000..3b31b2b
--- /dev/null
+++ b/sync/notifier/ack_handler.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 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 "sync/notifier/ack_handler.h"
+
+#include "sync/internal_api/public/base/invalidation.h"
+
+namespace syncer {
+
+AckHandler::AckHandler() {}
+
+AckHandler::~AckHandler() {}
+
+}  // namespace syncer
diff --git a/sync/notifier/ack_handler.h b/sync/notifier/ack_handler.h
new file mode 100644
index 0000000..f1fc16f
--- /dev/null
+++ b/sync/notifier/ack_handler.h
@@ -0,0 +1,42 @@
+// Copyright 2013 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 SYNC_NOTIFIER_ACK_HANDLER_H_
+#define SYNC_NOTIFIER_ACK_HANDLER_H_
+
+#include <vector>
+
+#include "sync/base/sync_export.h"
+
+namespace invalidation {
+class ObjectId;
+}  // namespace invalidation
+
+namespace syncer {
+
+class AckHandle;
+
+// An interface for classes that keep track of invalidation acknowledgements.
+//
+// We don't expect to support more than one "real" implementation of AckHandler,
+// but this interface is very useful for testing and implementation hiding.
+class SYNC_EXPORT AckHandler {
+ public:
+  AckHandler();
+  virtual ~AckHandler() = 0;
+
+  // Record the local acknowledgement of an invalidation identified by |handle|.
+  virtual void Acknowledge(
+      const invalidation::ObjectId& id,
+      const AckHandle& handle) = 0;
+
+  // Record the drop of an invalidation identified by |handle|.
+  virtual void Drop(
+      const invalidation::ObjectId& id,
+      const AckHandle& handle) = 0;
+};
+
+}  // namespace syncer
+
+#endif  // SYNC_NOTIFIER_ACK_HANDLER_H_
diff --git a/sync/notifier/dropped_invalidation_tracker.cc b/sync/notifier/dropped_invalidation_tracker.cc
new file mode 100644
index 0000000..8599cc2
--- /dev/null
+++ b/sync/notifier/dropped_invalidation_tracker.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 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 "sync/notifier/dropped_invalidation_tracker.h"
+
+#include "sync/internal_api/public/base/invalidation.h"
+
+namespace syncer {
+
+DroppedInvalidationTracker::DroppedInvalidationTracker(
+    const invalidation::ObjectId& id)
+    : id_(id),
+      drop_ack_handle_(AckHandle::InvalidAckHandle()) {}
+
+DroppedInvalidationTracker::~DroppedInvalidationTracker() {}
+
+const invalidation::ObjectId& DroppedInvalidationTracker::object_id() const {
+  return id_;
+}
+
+void DroppedInvalidationTracker::RecordDropEvent(
+    WeakHandle<AckHandler> handler, AckHandle handle) {
+  drop_ack_handler_ = handler;
+  drop_ack_handle_ = handle;
+}
+
+void DroppedInvalidationTracker::RecordRecoveryFromDropEvent() {
+  if (drop_ack_handler_.IsInitialized()) {
+    drop_ack_handler_.Call(FROM_HERE,
+                           &AckHandler::Acknowledge,
+                           id_,
+                           drop_ack_handle_);
+  }
+  drop_ack_handler_ = syncer::WeakHandle<AckHandler>();
+}
+
+bool DroppedInvalidationTracker::IsRecoveringFromDropEvent() const {
+  return drop_ack_handler_.IsInitialized();
+}
+
+}  // namespace syncer
diff --git a/sync/notifier/dropped_invalidation_tracker.h b/sync/notifier/dropped_invalidation_tracker.h
new file mode 100644
index 0000000..877187e
--- /dev/null
+++ b/sync/notifier/dropped_invalidation_tracker.h
@@ -0,0 +1,67 @@
+// Copyright 2013 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 SYNC_NOTIFIER_DROPPED_INVALIDATION_TRACKER_H_
+#define SYNC_NOTIFIER_DROPPED_INVALIDATION_TRACKER_H_
+
+#include "google/cacheinvalidation/include/types.h"
+#include "sync/base/sync_export.h"
+#include "sync/internal_api/public/base/ack_handle.h"
+#include "sync/internal_api/public/util/weak_handle.h"
+#include "sync/notifier/ack_handler.h"
+
+namespace syncer {
+
+class Invalidation;
+
+// Helps InvalidationHandlers keep track of dropped invalidations for a given
+// ObjectId.
+//
+// The intent of this class is to hide some of the implementation details around
+// how the invalidations system manages dropping and drop recovery.  Any
+// invalidation handler that intends to buffer and occasionally drop
+// invalidations should keep one instance of it per registered ObjectId.
+//
+// When an invalidation handler wishes to drop an invalidation, it must provide
+// an instance of this class to that Invalidation's Drop() method.  In order to
+// indicate recovery from a drop, the handler can call this class'
+// RecordRecoveryFromDropEvent().
+class SYNC_EXPORT DroppedInvalidationTracker {
+ public:
+  explicit DroppedInvalidationTracker(const invalidation::ObjectId& id);
+  ~DroppedInvalidationTracker();
+
+  const invalidation::ObjectId& object_id() const;
+
+  // Called by Invalidation::Drop() to keep track of a drop event.
+  //
+  // Takes ownership of the internals belonging to a soon to be discarded
+  // dropped invalidation.  See also the comment for this class'
+  // |drop_ack_handler_| member.
+  void RecordDropEvent(WeakHandle<AckHandler> handler, AckHandle handle);
+
+  // Returns true if we're still recovering from a drop event.
+  bool IsRecoveringFromDropEvent() const;
+
+  // Called by the InvalidationHandler when it recovers from the drop event.
+  void RecordRecoveryFromDropEvent();
+
+ private:
+  invalidation::ObjectId id_;
+  AckHandle drop_ack_handle_;
+
+  // A WeakHandle to the enitity responsible for persisting invalidation
+  // acknowledgement state on disk.  We can get away with using a WeakHandle
+  // because we don't care if our drop recovery message doesn't gets delivered
+  // in some shutdown cases.  If that happens, we'll have to process the
+  // invalidation state again on the next restart.  It would be a waste of time
+  // and resources, but otherwise not particularly harmful.
+  WeakHandle<AckHandler> drop_ack_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(DroppedInvalidationTracker);
+};
+
+}  // namespace syncer
+
+#endif  // SYNC_NOTIFIER_DROPPED_INVALIDATION_TRACKER_H_
diff --git a/sync/notifier/invalidation_util.cc b/sync/notifier/invalidation_util.cc
index 7cc80d2..27acd38 100644
--- a/sync/notifier/invalidation_util.cc
+++ b/sync/notifier/invalidation_util.cc
@@ -12,6 +12,7 @@
 #include "base/values.h"
 #include "google/cacheinvalidation/include/types.h"
 #include "google/cacheinvalidation/types.pb.h"
+#include "sync/internal_api/public/base/invalidation.h"
 
 namespace invalidation {
 void PrintTo(const invalidation::ObjectId& id, std::ostream* os) {
@@ -27,6 +28,25 @@
          (lhs.source() == rhs.source() && lhs.name() < rhs.name());
 }
 
+bool InvalidationVersionLessThan::operator()(
+    const Invalidation& a,
+    const Invalidation& b) const {
+  DCHECK(a.object_id() == b.object_id())
+      << "a: " << ObjectIdToString(a.object_id()) << ", "
+      << "b: " << ObjectIdToString(a.object_id());
+
+  if (a.is_unknown_version() && !b.is_unknown_version())
+    return true;
+
+  if (!a.is_unknown_version() && b.is_unknown_version())
+    return false;
+
+  if (a.is_unknown_version() && b.is_unknown_version())
+    return false;
+
+  return a.version() < b.version();
+}
+
 bool RealModelTypeToObjectId(ModelType model_type,
                              invalidation::ObjectId* object_id) {
   std::string notification_type;
diff --git a/sync/notifier/invalidation_util.h b/sync/notifier/invalidation_util.h
index 670f612..699550e 100644
--- a/sync/notifier/invalidation_util.h
+++ b/sync/notifier/invalidation_util.h
@@ -32,11 +32,18 @@
 
 namespace syncer {
 
+class Invalidation;
+
 struct SYNC_EXPORT ObjectIdLessThan {
   bool operator()(const invalidation::ObjectId& lhs,
                   const invalidation::ObjectId& rhs) const;
 };
 
+struct InvalidationVersionLessThan {
+  bool operator()(const syncer::Invalidation& a,
+                  const syncer::Invalidation& b) const;
+};
+
 typedef std::set<invalidation::ObjectId, ObjectIdLessThan> ObjectIdSet;
 
 SYNC_EXPORT bool RealModelTypeToObjectId(ModelType model_type,
diff --git a/sync/notifier/mock_ack_handler.cc b/sync/notifier/mock_ack_handler.cc
new file mode 100644
index 0000000..6a4c834
--- /dev/null
+++ b/sync/notifier/mock_ack_handler.cc
@@ -0,0 +1,85 @@
+// Copyright 2013 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 "sync/notifier/mock_ack_handler.h"
+
+#include "sync/internal_api/public/base/ack_handle.h"
+#include "sync/internal_api/public/base/invalidation.h"
+
+namespace syncer {
+
+namespace {
+
+struct AckHandleMatcher {
+  AckHandleMatcher(const AckHandle& handle);
+  bool operator()(const syncer::Invalidation& invalidation) const;
+
+  syncer::AckHandle handle_;
+};
+
+AckHandleMatcher::AckHandleMatcher(const AckHandle& handle)
+  : handle_(handle) {}
+
+bool AckHandleMatcher::operator()(
+    const syncer::Invalidation& invalidation) const {
+  return handle_.Equals(invalidation.ack_handle());
+}
+
+}  // namespace
+
+MockAckHandler::MockAckHandler() {}
+
+MockAckHandler::~MockAckHandler() {}
+
+void MockAckHandler::RegisterInvalidation(Invalidation* invalidation) {
+  unacked_invalidations_.push_back(*invalidation);
+  invalidation->set_ack_handler(WeakHandleThis());
+}
+
+void MockAckHandler::RegisterUnsentInvalidation(Invalidation* invalidation) {
+  unsent_invalidations_.push_back(*invalidation);
+}
+
+bool MockAckHandler::IsUnacked(const Invalidation& invalidation) const {
+  AckHandleMatcher matcher(invalidation.ack_handle());
+  InvalidationVector::const_iterator it = std::find_if(
+      unacked_invalidations_.begin(),
+      unacked_invalidations_.end(),
+      matcher);
+  return it != unacked_invalidations_.end();
+}
+
+bool MockAckHandler::IsUnsent(const Invalidation& invalidation) const {
+  AckHandleMatcher matcher(invalidation.ack_handle());
+  InvalidationVector::const_iterator it1 = std::find_if(
+      unsent_invalidations_.begin(),
+      unsent_invalidations_.end(),
+      matcher);
+  return it1 != unsent_invalidations_.end();
+}
+
+void MockAckHandler::Acknowledge(
+    const invalidation::ObjectId& id,
+    const AckHandle& handle) {
+  AckHandleMatcher matcher(handle);
+  InvalidationVector::iterator it = std::find_if(
+      unacked_invalidations_.begin(),
+      unacked_invalidations_.end(),
+      matcher);
+  if (it != unacked_invalidations_.end()) {
+    acked_invalidations_.push_back(*it);
+    unacked_invalidations_.erase(it);
+  }
+}
+
+void MockAckHandler::Drop(
+    const invalidation::ObjectId& id,
+    const AckHandle& handle) {
+}
+
+WeakHandle<AckHandler> MockAckHandler::WeakHandleThis() {
+  return WeakHandle<AckHandler>(AsWeakPtr());
+}
+
+}  // namespace syncer
diff --git a/sync/notifier/mock_ack_handler.h b/sync/notifier/mock_ack_handler.h
new file mode 100644
index 0000000..6659558
--- /dev/null
+++ b/sync/notifier/mock_ack_handler.h
@@ -0,0 +1,64 @@
+// Copyright 2013 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 SYNC_NOTIFIER_MOCK_ACK_HANDLER_H_
+#define SYNC_NOTIFIER_MOCK_ACK_HANDLER_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "sync/base/sync_export.h"
+#include "sync/internal_api/public/util/weak_handle.h"
+#include "sync/notifier/ack_handler.h"
+
+namespace syncer {
+
+class Invalidation;
+
+// This AckHandler implementation colaborates with the FakeInvalidationService
+// to enable unit tests to assert that invalidations are being acked properly.
+class MockAckHandler
+  : public AckHandler,
+    public base::SupportsWeakPtr<MockAckHandler> {
+ public:
+  MockAckHandler();
+  virtual ~MockAckHandler();
+
+  // Sets up some internal state to track this invalidation, and modifies it so
+  // that its Acknowledge() and Drop() methods will route back to us.
+  void RegisterInvalidation(Invalidation* invalidation);
+
+  // No one was listening for this invalidation, so no one will receive it or
+  // ack it.  We keep track of it anyway to let tests make assertions about it.
+  void RegisterUnsentInvalidation(Invalidation* invalidation);
+
+  // Returns true if the specified invalidaition has been delivered, but has not
+  // been acknowledged yet.
+  bool IsUnacked(const Invalidation& invalidation) const;
+
+  // Returns true if the specified invalidation was never delivered.
+  bool IsUnsent(const Invalidation& invalidation) const;
+
+  // Implementation of AckHandler.
+  virtual void Acknowledge(
+      const invalidation::ObjectId& id,
+      const AckHandle& handle) OVERRIDE;
+  virtual void Drop(
+      const invalidation::ObjectId& id,
+      const AckHandle& handle) OVERRIDE;
+
+ private:
+  typedef std::vector<syncer::Invalidation> InvalidationVector;
+
+  WeakHandle<AckHandler> WeakHandleThis();
+
+  InvalidationVector unsent_invalidations_;
+  InvalidationVector unacked_invalidations_;
+  InvalidationVector acked_invalidations_;
+};
+
+}  // namespace syncer
+
+#endif  // SYNC_NOTIFIER_MOCK_ACK_HANDLER_H_
diff --git a/sync/notifier/single_object_invalidation_set.cc b/sync/notifier/single_object_invalidation_set.cc
index 55202bb..6da3972 100644
--- a/sync/notifier/single_object_invalidation_set.cc
+++ b/sync/notifier/single_object_invalidation_set.cc
@@ -9,25 +9,6 @@
 
 namespace syncer {
 
-bool InvalidationVersionLessThan::operator()(
-    const Invalidation& a,
-    const Invalidation& b) {
-  DCHECK(a.object_id() == b.object_id())
-      << "a: " << ObjectIdToString(a.object_id()) << ", "
-      << "b: " << ObjectIdToString(a.object_id());
-
-  if (a.is_unknown_version() && !b.is_unknown_version())
-    return true;
-
-  if (!a.is_unknown_version() && b.is_unknown_version())
-    return false;
-
-  if (a.is_unknown_version() && b.is_unknown_version())
-    return false;
-
-  return a.version() < b.version();
-}
-
 SingleObjectInvalidationSet::SingleObjectInvalidationSet() {}
 
 SingleObjectInvalidationSet::~SingleObjectInvalidationSet() {}
diff --git a/sync/notifier/single_object_invalidation_set.h b/sync/notifier/single_object_invalidation_set.h
index c4dd051..e6f4d75 100644
--- a/sync/notifier/single_object_invalidation_set.h
+++ b/sync/notifier/single_object_invalidation_set.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "sync/base/sync_export.h"
 #include "sync/internal_api/public/base/invalidation.h"
+#include "sync/notifier/invalidation_util.h"
 
 namespace base {
 class ListValue;
@@ -17,10 +18,6 @@
 
 namespace syncer {
 
-struct InvalidationVersionLessThan {
-  bool operator()(const Invalidation& a, const Invalidation& b);
-};
-
 // Holds a list of invalidations that all share the same Object ID.
 //
 // The list is kept sorted by version to make it easier to perform common
diff --git a/sync/notifier/unacked_invalidation_set.cc b/sync/notifier/unacked_invalidation_set.cc
new file mode 100644
index 0000000..705dbd2
--- /dev/null
+++ b/sync/notifier/unacked_invalidation_set.cc
@@ -0,0 +1,204 @@
+// Copyright 2013 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 "sync/notifier/unacked_invalidation_set.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "sync/internal_api/public/base/ack_handle.h"
+#include "sync/notifier/object_id_invalidation_map.h"
+#include "sync/notifier/sync_invalidation_listener.h"
+
+namespace {
+
+const char kSourceKey[] = "source";
+const char kNameKey[] = "name";
+const char kInvalidationListKey[] = "invalidation-list";
+
+}  // namespace
+
+namespace syncer {
+
+const size_t UnackedInvalidationSet::kMaxBufferedInvalidations = 5;
+
+// static
+UnackedInvalidationSet::UnackedInvalidationSet(
+    invalidation::ObjectId id)
+    : registered_(false),
+      object_id_(id) {}
+
+UnackedInvalidationSet::~UnackedInvalidationSet() {}
+
+const invalidation::ObjectId& UnackedInvalidationSet::object_id() const {
+  return object_id_;
+}
+
+void UnackedInvalidationSet::Add(
+    const Invalidation& invalidation) {
+  SingleObjectInvalidationSet set;
+  set.Insert(invalidation);
+  AddSet(set);
+  if (!registered_)
+    Truncate(kMaxBufferedInvalidations);
+}
+
+void UnackedInvalidationSet::AddSet(
+    const SingleObjectInvalidationSet& invalidations) {
+  invalidations_.insert(invalidations.begin(), invalidations.end());
+  if (!registered_)
+    Truncate(kMaxBufferedInvalidations);
+}
+
+void UnackedInvalidationSet::ExportInvalidations(
+    WeakHandle<AckHandler> ack_handler,
+    ObjectIdInvalidationMap* out) const {
+  for (SingleObjectInvalidationSet::const_iterator it = invalidations_.begin();
+       it != invalidations_.end(); ++it) {
+    // Copy the invalidation and set the copy's ack_handler.
+    Invalidation inv(*it);
+    inv.set_ack_handler(ack_handler);
+    out->Insert(inv);
+  }
+}
+
+void UnackedInvalidationSet::Clear() {
+  invalidations_.clear();
+}
+
+void UnackedInvalidationSet::SetHandlerIsRegistered() {
+  registered_ = true;
+}
+
+void UnackedInvalidationSet::SetHandlerIsUnregistered() {
+  registered_ = false;
+  Truncate(kMaxBufferedInvalidations);
+}
+
+// Removes the matching ack handle from the list.
+void UnackedInvalidationSet::Acknowledge(const AckHandle& handle) {
+  bool handle_found = false;
+  for (SingleObjectInvalidationSet::const_iterator it = invalidations_.begin();
+       it != invalidations_.end(); ++it) {
+    if (it->ack_handle().Equals(handle)) {
+      invalidations_.erase(*it);
+      handle_found = true;
+      break;
+    }
+  }
+  DLOG_IF(WARNING, !handle_found)
+      << "Unrecognized to ack for object " << ObjectIdToString(object_id_);
+  (void)handle_found;  // Silence unused variable warning in release builds.
+}
+
+// Erase the invalidation with matching ack handle from the list.  Also creates
+// an 'UnknownVersion' invalidation with the same ack handle and places it at
+// the beginning of the list.  If an unknown version invalidation currently
+// exists, it is replaced.
+void UnackedInvalidationSet::Drop(const AckHandle& handle) {
+  SingleObjectInvalidationSet::const_iterator it;
+  for (it = invalidations_.begin(); it != invalidations_.end(); ++it) {
+    if (it->ack_handle().Equals(handle)) {
+      break;
+    }
+  }
+  if (it == invalidations_.end()) {
+    DLOG(WARNING) << "Unrecognized drop request for object "
+                  << ObjectIdToString(object_id_);
+    return;
+  }
+
+  Invalidation unknown_version = Invalidation::InitFromDroppedInvalidation(*it);
+  invalidations_.erase(*it);
+
+  // If an unknown version is in the list, we remove it so we can replace it.
+  if (!invalidations_.empty() && invalidations_.begin()->is_unknown_version()) {
+    invalidations_.erase(*invalidations_.begin());
+  }
+
+  invalidations_.insert(unknown_version);
+}
+
+scoped_ptr<base::DictionaryValue> UnackedInvalidationSet::ToValue() const {
+  scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
+  value->SetString(kSourceKey, base::IntToString(object_id_.source()));
+  value->SetString(kNameKey, object_id_.name());
+
+  scoped_ptr<base::ListValue> list_value(new ListValue);
+  for (InvalidationsSet::const_iterator it = invalidations_.begin();
+       it != invalidations_.end(); ++it) {
+    list_value->Append(it->ToValue().release());
+  }
+  value->Set(kInvalidationListKey, list_value.release());
+
+  return value.Pass();
+}
+
+bool UnackedInvalidationSet::ResetFromValue(
+    const base::DictionaryValue& value) {
+  std::string source_str;
+  if (!value.GetString(kSourceKey, &source_str)) {
+    DLOG(WARNING) << "Unable to deserialize source";
+    return false;
+  }
+  int source = 0;
+  if (!base::StringToInt(source_str, &source)) {
+    DLOG(WARNING) << "Invalid source: " << source_str;
+    return false;
+  }
+  std::string name;
+  if (!value.GetString(kNameKey, &name)) {
+    DLOG(WARNING) << "Unable to deserialize name";
+    return false;
+  }
+  object_id_ = invalidation::ObjectId(source, name);
+  const base::ListValue* invalidation_list = NULL;
+  if (!value.GetList(kInvalidationListKey, &invalidation_list)
+      || !ResetListFromValue(*invalidation_list)) {
+    // Earlier versions of this class did not set this field, so we don't treat
+    // parsing errors here as a fatal failure.
+    DLOG(WARNING) << "Unable to deserialize invalidation list.";
+  }
+  return true;
+}
+
+bool UnackedInvalidationSet::ResetListFromValue(
+    const base::ListValue& list) {
+  for (size_t i = 0; i < list.GetSize(); ++i) {
+    const base::DictionaryValue* dict;
+    if (!list.GetDictionary(i, &dict)) {
+      DLOG(WARNING) << "Failed to get invalidation dictionary at index " << i;
+      return false;
+    }
+    scoped_ptr<Invalidation> invalidation = Invalidation::InitFromValue(*dict);
+    if (!invalidation) {
+      DLOG(WARNING) << "Failed to parse invalidation at index " << i;
+      return false;
+    }
+    invalidations_.insert(*invalidation.get());
+  }
+  return true;
+}
+
+void UnackedInvalidationSet::Truncate(size_t max_size) {
+  DCHECK_GT(max_size, 0U);
+
+  if (invalidations_.size() <= max_size) {
+    return;
+  }
+
+  while (invalidations_.size() > max_size) {
+    invalidations_.erase(*invalidations_.begin());
+  }
+
+  // We dropped some invalidations.  We remember the fact that an unknown
+  // amount of information has been lost by ensuring this list begins with
+  // an UnknownVersion invalidation.  We remove the oldest remaining
+  // invalidation to make room for it.
+  invalidation::ObjectId id = invalidations_.begin()->object_id();
+  invalidations_.erase(*invalidations_.begin());
+
+  Invalidation unknown_version = Invalidation::InitUnknownVersion(id);
+  invalidations_.insert(unknown_version);
+}
+
+}  // namespace syncer
diff --git a/sync/notifier/unacked_invalidation_set.h b/sync/notifier/unacked_invalidation_set.h
new file mode 100644
index 0000000..2824e6a
--- /dev/null
+++ b/sync/notifier/unacked_invalidation_set.h
@@ -0,0 +1,113 @@
+// Copyright 2013 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 SYNC_NOTIFIER_UNACKED_INVALIDATION_SET_H_
+#define SYNC_NOTIFIER_UNACKED_INVALIDATION_SET_H_
+
+#include <vector>
+
+#include "sync/base/sync_export.h"
+#include "sync/internal_api/public/base/invalidation.h"
+#include "sync/internal_api/public/util/weak_handle.h"
+#include "sync/notifier/invalidation_util.h"
+
+namespace base {
+class DictionaryValue;
+}  // namespace base
+
+namespace syncer {
+
+class SingleObjectInvalidationSet;
+class ObjectIdInvalidationMap;
+class AckHandle;
+
+// Manages the set of invalidations that are awaiting local acknowledgement for
+// a particular ObjectId.  This set of invalidations will be persisted across
+// restarts, though this class is not directly responsible for that.
+class SYNC_EXPORT UnackedInvalidationSet {
+ public:
+  static const size_t kMaxBufferedInvalidations;
+
+  UnackedInvalidationSet(invalidation::ObjectId id);
+  ~UnackedInvalidationSet();
+
+  // Returns the ObjectID of the invalidations this class is tracking.
+  const invalidation::ObjectId& object_id() const;
+
+  // Adds a new invalidation to the set awaiting acknowledgement.
+  void Add(const Invalidation& invalidation);
+
+  // Adds many new invalidations to the set awaiting acknowledgement.
+  void AddSet(const SingleObjectInvalidationSet& invalidations);
+
+  // Exports the set of invalidations awaiting acknowledgement as an
+  // ObjectIdInvalidationMap.  Each of these invalidations will be associated
+  // with the given |ack_handler|.
+  //
+  // The contents of the UnackedInvalidationSet are not directly modified by
+  // this procedure, but the AckHandles stored in those exported invalidations
+  // are likely to end up back here in calls to Acknowledge() or Drop().
+  void ExportInvalidations(WeakHandle<AckHandler> ack_handler,
+                           ObjectIdInvalidationMap* out) const;
+
+  // Removes all stored invalidations from this object.
+  void Clear();
+
+  // Indicates that a handler has registered to handle these invalidations.
+  //
+  // Registrations with the invalidations server persist across restarts, but
+  // registrations from InvalidationHandlers to the InvalidationService are not.
+  // In the time immediately after a restart, it's possible that the server
+  // will send us invalidations, and we won't have a handler to send them to.
+  //
+  // The SetIsRegistered() call indicates that this period has come to an end.
+  // There is now a handler that can receive these invalidations.  Once this
+  // function has been called, the kMaxBufferedInvalidations limit will be
+  // ignored.  It is assumed that the handler will manage its own buffer size.
+  void SetHandlerIsRegistered();
+
+  // Indicates that the handler has now unregistered itself.
+  //
+  // This causes the object to resume enforcement of the
+  // kMaxBufferedInvalidations limit.
+  void SetHandlerIsUnregistered();
+
+  // Given an AckHandle belonging to one of the contained invalidations, finds
+  // the invalidation and drops it from the list.  It is considered to be
+  // acknowledged, so there is no need to continue maintaining its state.
+  void Acknowledge(const AckHandle& handle);
+
+  // Given an AckHandle belonging to one of the contained invalidations, finds
+  // the invalidation, drops it from the list, and adds additional state to
+  // indicate that this invalidation has been lost without being acted on.
+  void Drop(const AckHandle& handle);
+
+  scoped_ptr<base::DictionaryValue> ToValue() const;
+  bool ResetFromValue(const base::DictionaryValue& value);
+
+ private:
+  // Allow this test helper to have access to our internals.
+  friend class UnackedInvalidationSetEqMatcher;
+
+  typedef std::set<Invalidation, InvalidationVersionLessThan> InvalidationsSet;
+
+  bool ResetListFromValue(const base::ListValue& value);
+
+  // Limits the list size to the given maximum.  This function will correctly
+  // update this class' internal data to indicate if invalidations have been
+  // dropped.
+  void Truncate(size_t max_size);
+
+  bool registered_;
+  invalidation::ObjectId object_id_;
+  InvalidationsSet invalidations_;
+};
+
+typedef std::map<invalidation::ObjectId,
+                 UnackedInvalidationSet,
+                 ObjectIdLessThan> UnackedInvalidationsMap;
+
+}  // namespace syncer
+
+#endif  // SYNC_NOTIFIER_UNACKED_INVALIDATION_SET_H_
diff --git a/sync/notifier/unacked_invalidation_set_unittest.cc b/sync/notifier/unacked_invalidation_set_unittest.cc
new file mode 100644
index 0000000..70cd232
--- /dev/null
+++ b/sync/notifier/unacked_invalidation_set_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright 2013 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 "sync/notifier/unacked_invalidation_set.h"
+
+#include "base/json/json_string_value_serializer.h"
+#include "sync/notifier/object_id_invalidation_map.h"
+#include "sync/notifier/single_object_invalidation_set.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+// Start with some helper functions and classes.
+
+using ::testing::MakeMatcher;
+using ::testing::MatchResultListener;
+using ::testing::Matcher;
+using ::testing::MatcherInterface;
+using ::testing::PrintToString;
+
+void PrintTo(
+    const UnackedInvalidationSet& invalidations, ::std::ostream* os);
+
+void PrintTo(
+    const UnackedInvalidationsMap& map, ::std::ostream* os);
+
+::testing::Matcher<const UnackedInvalidationSet&> Eq(
+    const UnackedInvalidationSet& expected);
+
+::testing::Matcher<const UnackedInvalidationsMap&> Eq(
+    const UnackedInvalidationsMap& expected);
+
+class UnackedInvalidationSetEqMatcher
+    : public testing::MatcherInterface<const UnackedInvalidationSet&> {
+ public:
+  explicit UnackedInvalidationSetEqMatcher(
+      const UnackedInvalidationSet& expected);
+
+  virtual bool MatchAndExplain(
+      const UnackedInvalidationSet& actual,
+      MatchResultListener* listener) const OVERRIDE;
+  virtual void DescribeTo(::std::ostream* os) const OVERRIDE;
+  virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE;
+
+ private:
+  const UnackedInvalidationSet expected_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnackedInvalidationSetEqMatcher);
+};
+
+UnackedInvalidationSetEqMatcher::UnackedInvalidationSetEqMatcher(
+    const UnackedInvalidationSet& expected)
+  : expected_(expected) {}
+
+namespace {
+
+struct InvalidationEq {
+  bool operator()(const syncer::Invalidation& a,
+                  const syncer::Invalidation& b) const {
+    return a.Equals(b);
+  }
+};
+
+}  // namespace
+
+bool UnackedInvalidationSetEqMatcher::MatchAndExplain(
+    const UnackedInvalidationSet& actual,
+    MatchResultListener* listener) const {
+  // Use our friendship with this class to compare the internals of two
+  // instances.
+  //
+  // Note that the registration status is intentionally not considered
+  // when performing this comparison.
+  return expected_.object_id_ == actual.object_id_
+      && std::equal(expected_.invalidations_.begin(),
+                    expected_.invalidations_.end(),
+                    actual.invalidations_.begin(),
+                    InvalidationEq());
+}
+
+void UnackedInvalidationSetEqMatcher::DescribeTo(::std::ostream* os) const {
+  *os << " is equal to " << PrintToString(expected_);
+}
+
+void UnackedInvalidationSetEqMatcher::DescribeNegationTo(
+    ::std::ostream* os) const {
+  *os << " isn't equal to " << PrintToString(expected_);
+}
+
+namespace {
+
+ObjectIdInvalidationMap UnackedInvalidationsMapToObjectIdInvalidationMap(
+    const UnackedInvalidationsMap& state_map) {
+  ObjectIdInvalidationMap object_id_invalidation_map;
+  for (UnackedInvalidationsMap::const_iterator it = state_map.begin();
+       it != state_map.end(); ++it) {
+    it->second.ExportInvalidations(syncer::WeakHandle<AckHandler>(),
+                                   &object_id_invalidation_map);
+  }
+  return object_id_invalidation_map;
+}
+
+class UnackedInvalidationsMapEqMatcher
+    : public testing::MatcherInterface<const UnackedInvalidationsMap&> {
+ public:
+  explicit UnackedInvalidationsMapEqMatcher(
+      const UnackedInvalidationsMap& expected);
+
+  virtual bool MatchAndExplain(const UnackedInvalidationsMap& actual,
+                               MatchResultListener* listener) const;
+  virtual void DescribeTo(::std::ostream* os) const;
+  virtual void DescribeNegationTo(::std::ostream* os) const;
+
+ private:
+  const UnackedInvalidationsMap expected_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnackedInvalidationsMapEqMatcher);
+};
+
+UnackedInvalidationsMapEqMatcher::UnackedInvalidationsMapEqMatcher(
+    const UnackedInvalidationsMap& expected)
+    : expected_(expected) {
+}
+
+bool UnackedInvalidationsMapEqMatcher::MatchAndExplain(
+    const UnackedInvalidationsMap& actual,
+    MatchResultListener* listener) const {
+  ObjectIdInvalidationMap expected_inv =
+      UnackedInvalidationsMapToObjectIdInvalidationMap(expected_);
+  ObjectIdInvalidationMap actual_inv =
+      UnackedInvalidationsMapToObjectIdInvalidationMap(actual);
+
+  return expected_inv == actual_inv;
+}
+
+void UnackedInvalidationsMapEqMatcher::DescribeTo(
+    ::std::ostream* os) const {
+  *os << " is equal to " << PrintToString(expected_);
+}
+
+void UnackedInvalidationsMapEqMatcher::DescribeNegationTo(
+    ::std::ostream* os) const {
+  *os << " isn't equal to " << PrintToString(expected_);
+}
+
+}  // namespace
+
+void PrintTo(const UnackedInvalidationSet& invalidations,
+             ::std::ostream* os) {
+  scoped_ptr<base::DictionaryValue> value = invalidations.ToValue();
+
+  std::string output;
+  JSONStringValueSerializer serializer(&output);
+  serializer.set_pretty_print(true);
+  serializer.Serialize(*value.get());
+
+  (*os) << output;
+}
+
+void PrintTo(const UnackedInvalidationsMap& map, ::std::ostream* os) {
+  scoped_ptr<base::ListValue> list(new base::ListValue);
+  for (UnackedInvalidationsMap::const_iterator it = map.begin();
+       it != map.end(); ++it) {
+    list->Append(it->second.ToValue().release());
+  }
+
+  std::string output;
+  JSONStringValueSerializer serializer(&output);
+  serializer.set_pretty_print(true);
+  serializer.Serialize(*list.get());
+
+  (*os) << output;
+}
+
+Matcher<const UnackedInvalidationSet&> Eq(
+    const UnackedInvalidationSet& expected) {
+  return MakeMatcher(new UnackedInvalidationSetEqMatcher(expected));
+}
+
+Matcher<const UnackedInvalidationsMap&> Eq(
+    const UnackedInvalidationsMap& expected) {
+  return MakeMatcher(new UnackedInvalidationsMapEqMatcher(expected));
+}
+
+class UnackedInvalidationSetTest : public testing::Test {
+ public:
+  UnackedInvalidationSetTest()
+      : kObjectId_(10, "ASDF"),
+        unacked_invalidations_(kObjectId_) {}
+
+  SingleObjectInvalidationSet GetStoredInvalidations() {
+    ObjectIdInvalidationMap map;
+    unacked_invalidations_.ExportInvalidations(WeakHandle<AckHandler>(), &map);
+    ObjectIdSet ids = map.GetObjectIds();
+    if (ids.find(kObjectId_) != ids.end()) {
+      return map.ForObject(kObjectId_);
+    } else {
+      return SingleObjectInvalidationSet();
+    }
+  }
+
+  const invalidation::ObjectId kObjectId_;
+  UnackedInvalidationSet unacked_invalidations_;
+};
+
+namespace {
+
+// Test storage and retrieval of zero invalidations.
+TEST_F(UnackedInvalidationSetTest, Empty) {
+  EXPECT_EQ(0U, GetStoredInvalidations().GetSize());
+}
+
+// Test storage and retrieval of a single invalidation.
+TEST_F(UnackedInvalidationSetTest, OneInvalidation) {
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  unacked_invalidations_.Add(inv1);
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(1U, set.GetSize());
+  EXPECT_FALSE(set.StartsWithUnknownVersion());
+}
+
+// Test that calling Clear() returns us to the empty state.
+TEST_F(UnackedInvalidationSetTest, Clear) {
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  unacked_invalidations_.Add(inv1);
+  unacked_invalidations_.Clear();
+
+  EXPECT_EQ(0U, GetStoredInvalidations().GetSize());
+}
+
+// Test that repeated unknown version invalidations are squashed together.
+TEST_F(UnackedInvalidationSetTest, UnknownVersions) {
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
+  Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_);
+  unacked_invalidations_.Add(inv1);
+  unacked_invalidations_.Add(inv2);
+  unacked_invalidations_.Add(inv3);
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(2U, set.GetSize());
+  EXPECT_TRUE(set.StartsWithUnknownVersion());
+}
+
+// Tests that no truncation occurs while we're under the limit.
+TEST_F(UnackedInvalidationSetTest, NoTruncation) {
+  size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
+
+  for (size_t i = 0; i < kMax; ++i) {
+    Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
+    unacked_invalidations_.Add(inv);
+  }
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(kMax, set.GetSize());
+  EXPECT_FALSE(set.StartsWithUnknownVersion());
+  EXPECT_EQ(0, set.begin()->version());
+  EXPECT_EQ(kMax-1, static_cast<size_t>(set.rbegin()->version()));
+}
+
+// Test that truncation happens as we reach the limit.
+TEST_F(UnackedInvalidationSetTest, Truncation) {
+  size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
+
+  for (size_t i = 0; i < kMax + 1; ++i) {
+    Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
+    unacked_invalidations_.Add(inv);
+  }
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(kMax, set.GetSize());
+  EXPECT_TRUE(set.StartsWithUnknownVersion());
+  EXPECT_TRUE(set.begin()->is_unknown_version());
+  EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version()));
+}
+
+// Test that we don't truncate while a handler is registered.
+TEST_F(UnackedInvalidationSetTest, RegistrationAndTruncation) {
+  unacked_invalidations_.SetHandlerIsRegistered();
+
+  size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
+
+  for (size_t i = 0; i < kMax + 1; ++i) {
+    Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
+    unacked_invalidations_.Add(inv);
+  }
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(kMax+1, set.GetSize());
+  EXPECT_FALSE(set.StartsWithUnknownVersion());
+  EXPECT_EQ(0, set.begin()->version());
+  EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version()));
+
+  // Unregistering should re-enable truncation.
+  unacked_invalidations_.SetHandlerIsUnregistered();
+  SingleObjectInvalidationSet set2 = GetStoredInvalidations();
+  ASSERT_EQ(kMax, set2.GetSize());
+  EXPECT_TRUE(set2.StartsWithUnknownVersion());
+  EXPECT_TRUE(set2.begin()->is_unknown_version());
+  EXPECT_EQ(kMax, static_cast<size_t>(set2.rbegin()->version()));
+}
+
+// Test acknowledgement.
+TEST_F(UnackedInvalidationSetTest, Acknowledge) {
+  // inv2 is included in this test just to make sure invalidations that
+  // are supposed to be unaffected by this operation will be unaffected.
+
+  // We don't expect to be receiving acks or drops unless this flag is set.
+  // Not that it makes much of a difference in behavior.
+  unacked_invalidations_.SetHandlerIsRegistered();
+
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
+  AckHandle inv1_handle = inv1.ack_handle();
+
+  unacked_invalidations_.Add(inv1);
+  unacked_invalidations_.Add(inv2);
+
+  unacked_invalidations_.Acknowledge(inv1_handle);
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  EXPECT_EQ(1U, set.GetSize());
+  EXPECT_TRUE(set.StartsWithUnknownVersion());
+}
+
+// Test drops.
+TEST_F(UnackedInvalidationSetTest, Drop) {
+  // inv2 is included in this test just to make sure invalidations that
+  // are supposed to be unaffected by this operation will be unaffected.
+
+  // We don't expect to be receiving acks or drops unless this flag is set.
+  // Not that it makes much of a difference in behavior.
+  unacked_invalidations_.SetHandlerIsRegistered();
+
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  Invalidation inv2 = Invalidation::Init(kObjectId_, 15, "payload");
+  AckHandle inv1_handle = inv1.ack_handle();
+
+  unacked_invalidations_.Add(inv1);
+  unacked_invalidations_.Add(inv2);
+
+  unacked_invalidations_.Drop(inv1_handle);
+
+  SingleObjectInvalidationSet set = GetStoredInvalidations();
+  ASSERT_EQ(2U, set.GetSize());
+  EXPECT_TRUE(set.StartsWithUnknownVersion());
+  EXPECT_EQ(15, set.rbegin()->version());
+}
+
+class UnackedInvalidationSetSerializationTest
+    : public UnackedInvalidationSetTest {
+ public:
+  UnackedInvalidationSet SerializeDeserialize() {
+    scoped_ptr<base::DictionaryValue> value = unacked_invalidations_.ToValue();
+    UnackedInvalidationSet deserialized(kObjectId_);
+    deserialized.ResetFromValue(*value.get());
+    return deserialized;
+  }
+};
+
+TEST_F(UnackedInvalidationSetSerializationTest, Empty) {
+  UnackedInvalidationSet deserialized = SerializeDeserialize();
+  EXPECT_THAT(unacked_invalidations_, Eq(deserialized));
+}
+
+TEST_F(UnackedInvalidationSetSerializationTest, OneInvalidation) {
+  Invalidation inv = Invalidation::Init(kObjectId_, 10, "payload");
+  unacked_invalidations_.Add(inv);
+
+  UnackedInvalidationSet deserialized = SerializeDeserialize();
+  EXPECT_THAT(unacked_invalidations_, Eq(deserialized));
+}
+
+TEST_F(UnackedInvalidationSetSerializationTest, WithUnknownVersion) {
+  Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
+  Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
+  Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_);
+  unacked_invalidations_.Add(inv1);
+  unacked_invalidations_.Add(inv2);
+  unacked_invalidations_.Add(inv3);
+
+  UnackedInvalidationSet deserialized = SerializeDeserialize();
+  EXPECT_THAT(unacked_invalidations_, Eq(deserialized));
+}
+
+}  // namespace
+
+}  // namespace syncer
diff --git a/sync/protocol/extension_specifics.proto b/sync/protocol/extension_specifics.proto
index e3e1dfb..4c8364a 100644
--- a/sync/protocol/extension_specifics.proto
+++ b/sync/protocol/extension_specifics.proto
@@ -29,6 +29,11 @@
   // Extensions Gallery) is used.
   optional string update_url = 3;
   // Whether or not this extension is enabled.
+  // TODO(yoz): New sync clients will ignore this state, but we must
+  // keep populating it because old clients behave incorrectly if it's
+  // not present. Temporarily, enabled changes will propagate from new
+  // clients to old, but not vice versa. Once all clients are updated to
+  // ignore this field, we can remove it. See crbug.com/303311.
   optional bool enabled = 4;
   // Whether or not this extension is enabled in incognito mode.
   optional bool incognito_enabled = 5;
diff --git a/sync/sessions/nudge_tracker.cc b/sync/sessions/nudge_tracker.cc
index 2794747..94bef81 100644
--- a/sync/sessions/nudge_tracker.cc
+++ b/sync/sessions/nudge_tracker.cc
@@ -40,6 +40,8 @@
 }
 
 bool NudgeTracker::IsGetUpdatesRequired() const {
+  if (invalidations_out_of_sync_)
+    return true;
   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
        it != type_trackers_.end(); ++it) {
     if (it->second.IsGetUpdatesRequired()) {
diff --git a/sync/sessions/nudge_tracker_unittest.cc b/sync/sessions/nudge_tracker_unittest.cc
index ea7f4c7..c76f3ec 100644
--- a/sync/sessions/nudge_tracker_unittest.cc
+++ b/sync/sessions/nudge_tracker_unittest.cc
@@ -26,97 +26,102 @@
 
 class NudgeTrackerTest : public ::testing::Test {
  public:
+  NudgeTrackerTest() {
+    SetInvalidationsInSync();
+  }
+
   static size_t GetHintBufferSize() {
     // Assumes that no test has adjusted this size.
     return NudgeTracker::kDefaultMaxPayloadsPerType;
   }
 
-  bool InvalidationsOutOfSync(const NudgeTracker& nudge_tracker) {
+  bool InvalidationsOutOfSync() const {
     // We don't currently track invalidations out of sync on a per-type basis.
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
     return gu_trigger.invalidations_out_of_sync();
   }
 
-  int ProtoLocallyModifiedCount(const NudgeTracker& nudge_tracker,
-                                ModelType type) {
+  int ProtoLocallyModifiedCount(ModelType type) const {
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(type, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(type, &gu_trigger);
     return gu_trigger.local_modification_nudges();
   }
 
-  int ProtoRefreshRequestedCount(const NudgeTracker& nudge_tracker,
-                                 ModelType type) {
+  int ProtoRefreshRequestedCount(ModelType type) const {
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(type, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(type, &gu_trigger);
     return gu_trigger.datatype_refresh_nudges();
   }
+
+  void SetInvalidationsInSync() {
+    nudge_tracker_.OnInvalidationsEnabled();
+    nudge_tracker_.RecordSuccessfulSyncCycle();
+  }
+
+ protected:
+  NudgeTracker nudge_tracker_;
 };
 
 // Exercise an empty NudgeTracker.
 // Use with valgrind to detect uninitialized members.
 TEST_F(NudgeTrackerTest, EmptyNudgeTracker) {
-  NudgeTracker nudge_tracker;
-
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  // Now we're at the normal, "idle" state.
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 
   sync_pb::GetUpdateTriggers gu_trigger;
-  nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+  nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
 
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 }
 
 // Verify that nudges override each other based on a priority order.
 // LOCAL < DATATYPE_REFRESH < NOTIFICATION
 TEST_F(NudgeTrackerTest, SourcePriorities) {
-  NudgeTracker nudge_tracker;
-
   // Track a local nudge.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 
   // A refresh request will override it.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 
   // Another local nudge will not be enough to change it.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 
   // An invalidation will override the refresh request source.
   ObjectIdInvalidationMap invalidation_map =
       BuildInvalidationMap(PREFERENCES, 1, "hint");
-  nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+  nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 
   // Neither local nudges nor refresh requests will override it.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker.updates_source());
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
+            nudge_tracker_.updates_source());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker.updates_source());
+            nudge_tracker_.updates_source());
 }
 
 TEST_F(NudgeTrackerTest, HintCoalescing) {
-  NudgeTracker nudge_tracker;
-
   // Easy case: record one hint.
   {
     ObjectIdInvalidationMap invalidation_map =
         BuildInvalidationMap(BOOKMARKS, 1, "bm_hint_1");
-    nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+    nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
 
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
     ASSERT_EQ(1, gu_trigger.notification_hint_size());
     EXPECT_EQ("bm_hint_1", gu_trigger.notification_hint(0));
     EXPECT_FALSE(gu_trigger.client_dropped_hints());
@@ -126,10 +131,10 @@
   {
     ObjectIdInvalidationMap invalidation_map =
         BuildInvalidationMap(BOOKMARKS, 2, "bm_hint_2");
-    nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+    nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
 
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
     ASSERT_EQ(2, gu_trigger.notification_hint_size());
 
     // Expect the most hint recent is last in the list.
@@ -142,11 +147,11 @@
   {
     ObjectIdInvalidationMap invalidation_map =
         BuildInvalidationMap(PASSWORDS, 1, "pw_hint_1");
-    nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+    nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
 
     // Re-verify the bookmarks to make sure they're unaffected.
     sync_pb::GetUpdateTriggers bm_gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &bm_gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &bm_gu_trigger);
     ASSERT_EQ(2, bm_gu_trigger.notification_hint_size());
     EXPECT_EQ("bm_hint_1", bm_gu_trigger.notification_hint(0));
     EXPECT_EQ("bm_hint_2",
@@ -155,7 +160,7 @@
 
     // Verify the new type, too.
     sync_pb::GetUpdateTriggers pw_gu_trigger;
-    nudge_tracker.FillProtoMessage(PASSWORDS, &pw_gu_trigger);
+    nudge_tracker_.FillProtoMessage(PASSWORDS, &pw_gu_trigger);
     ASSERT_EQ(1, pw_gu_trigger.notification_hint_size());
     EXPECT_EQ("pw_hint_1", pw_gu_trigger.notification_hint(0));
     EXPECT_FALSE(pw_gu_trigger.client_dropped_hints());
@@ -163,16 +168,15 @@
 }
 
 TEST_F(NudgeTrackerTest, DropHintsLocally) {
-  NudgeTracker nudge_tracker;
   ObjectIdInvalidationMap invalidation_map =
       BuildInvalidationMap(BOOKMARKS, 1, "hint");
 
   for (size_t i = 0; i < GetHintBufferSize(); ++i) {
-    nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+    nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
   }
   {
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
     EXPECT_EQ(GetHintBufferSize(),
               static_cast<size_t>(gu_trigger.notification_hint_size()));
     EXPECT_FALSE(gu_trigger.client_dropped_hints());
@@ -181,11 +185,11 @@
   // Force an overflow.
   ObjectIdInvalidationMap invalidation_map2 =
       BuildInvalidationMap(BOOKMARKS, 1000, "new_hint");
-  nudge_tracker.RecordRemoteInvalidation(invalidation_map2);
+  nudge_tracker_.RecordRemoteInvalidation(invalidation_map2);
 
   {
     sync_pb::GetUpdateTriggers gu_trigger;
-    nudge_tracker.FillProtoMessage(BOOKMARKS, &gu_trigger);
+    nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
     EXPECT_EQ(GetHintBufferSize(),
               static_cast<size_t>(gu_trigger.notification_hint_size()));
     EXPECT_TRUE(gu_trigger.client_dropped_hints());
@@ -203,225 +207,218 @@
 
 // Checks the behaviour of the invalidations-out-of-sync flag.
 TEST_F(NudgeTrackerTest, EnableDisableInvalidations) {
-  NudgeTracker nudge_tracker;
-
-  // By default, assume we're out of sync with the invalidation server.
-  EXPECT_TRUE(InvalidationsOutOfSync(nudge_tracker));
+  // Start with invalidations offline.
+  nudge_tracker_.OnInvalidationsDisabled();
+  EXPECT_TRUE(InvalidationsOutOfSync());
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // Simply enabling invalidations does not bring us back into sync.
-  nudge_tracker.OnInvalidationsEnabled();
-  EXPECT_TRUE(InvalidationsOutOfSync(nudge_tracker));
+  nudge_tracker_.OnInvalidationsEnabled();
+  EXPECT_TRUE(InvalidationsOutOfSync());
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // We must successfully complete a sync cycle while invalidations are enabled
   // to be sure that we're in sync.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(InvalidationsOutOfSync(nudge_tracker));
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(InvalidationsOutOfSync());
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // If the invalidator malfunctions, we go become unsynced again.
-  nudge_tracker.OnInvalidationsDisabled();
-  EXPECT_TRUE(InvalidationsOutOfSync(nudge_tracker));
+  nudge_tracker_.OnInvalidationsDisabled();
+  EXPECT_TRUE(InvalidationsOutOfSync());
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // A sync cycle while invalidations are disabled won't reset the flag.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_TRUE(InvalidationsOutOfSync(nudge_tracker));
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_TRUE(InvalidationsOutOfSync());
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // Nor will the re-enabling of invalidations be sufficient, even now that
   // we've had a successful sync cycle.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_TRUE(InvalidationsOutOfSync(nudge_tracker));
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_TRUE(InvalidationsOutOfSync());
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 }
 
 // Tests that locally modified types are correctly written out to the
 // GetUpdateTriggers proto.
 TEST_F(NudgeTrackerTest, WriteLocallyModifiedTypesToProto) {
-  NudgeTracker nudge_tracker;
-
   // Should not be locally modified by default.
-  EXPECT_EQ(0, ProtoLocallyModifiedCount(nudge_tracker, PREFERENCES));
+  EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES));
 
   // Record a local bookmark change.  Verify it was registered correctly.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(PREFERENCES));
-  EXPECT_EQ(1, ProtoLocallyModifiedCount(nudge_tracker, PREFERENCES));
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(PREFERENCES));
+  EXPECT_EQ(1, ProtoLocallyModifiedCount(PREFERENCES));
 
   // Record a successful sync cycle.  Verify the count is cleared.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_EQ(0, ProtoLocallyModifiedCount(nudge_tracker, PREFERENCES));
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES));
 }
 
 // Tests that refresh requested types are correctly written out to the
 // GetUpdateTriggers proto.
 TEST_F(NudgeTrackerTest, WriteRefreshRequestedTypesToProto) {
-  NudgeTracker nudge_tracker;
-
   // There should be no refresh requested by default.
-  EXPECT_EQ(0, ProtoRefreshRequestedCount(nudge_tracker, SESSIONS));
+  EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS));
 
   // Record a local refresh request.  Verify it was registered correctly.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
-  EXPECT_EQ(1, ProtoRefreshRequestedCount(nudge_tracker, SESSIONS));
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+  EXPECT_EQ(1, ProtoRefreshRequestedCount(SESSIONS));
 
   // Record a successful sync cycle.  Verify the count is cleared.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_EQ(0, ProtoRefreshRequestedCount(nudge_tracker, SESSIONS));
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS));
 }
 
 // Basic tests for the IsSyncRequired() flag.
 TEST_F(NudgeTrackerTest, IsSyncRequired) {
-  NudgeTracker nudge_tracker;
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // Local changes.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // Refresh requests.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // Invalidations.
   ObjectIdInvalidationMap invalidation_map =
       BuildInvalidationMap(PREFERENCES, 1, "hint");
-  nudge_tracker.RecordRemoteInvalidation(invalidation_map);
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 }
 
 // Basic tests for the IsGetUpdatesRequired() flag.
 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) {
-  NudgeTracker nudge_tracker;
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // Local changes.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(SESSIONS));
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // Refresh requests.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // Invalidations.
   ObjectIdInvalidationMap invalidation_map =
       BuildInvalidationMap(PREFERENCES, 1, "hint");
-  nudge_tracker.RecordRemoteInvalidation(invalidation_map);
-  EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordRemoteInvalidation(invalidation_map);
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 }
 
 // Test IsSyncRequired() responds correctly to data type throttling.
 TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) {
-  NudgeTracker nudge_tracker;
   const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
   const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10);
   const base::TimeTicks t1 = t0 + throttle_length;
 
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // A local change to sessions enables the flag.
-  nudge_tracker.RecordLocalChange(ModelTypeSet(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
 
   // But the throttling of sessions unsets it.
-  nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS),
+  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS),
                                        throttle_length,
                                        t0);
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // A refresh request for bookmarks means we have reason to sync again.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
 
   // A successful sync cycle means we took care of bookmarks.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
 
   // But we still haven't dealt with sessions.  We'll need to remember
   // that sessions are out of sync and re-enable the flag when their
   // throttling interval expires.
-  nudge_tracker.UpdateTypeThrottlingState(t1);
-  EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsSyncRequired());
+  nudge_tracker_.UpdateTypeThrottlingState(t1);
+  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsSyncRequired());
 }
 
 // Test IsGetUpdatesRequired() responds correctly to data type throttling.
 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired_Throttling) {
-  NudgeTracker nudge_tracker;
   const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
   const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10);
   const base::TimeTicks t1 = t0 + throttle_length;
 
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // A refresh request to sessions enables the flag.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // But the throttling of sessions unsets it.
-  nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS),
+  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS),
                                        throttle_length,
                                        t0);
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // A refresh request for bookmarks means we have reason to sync again.
-  nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
-  EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 
   // A successful sync cycle means we took care of bookmarks.
-  nudge_tracker.RecordSuccessfulSyncCycle();
-  EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.RecordSuccessfulSyncCycle();
+  EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
 
   // But we still haven't dealt with sessions.  We'll need to remember
   // that sessions are out of sync and re-enable the flag when their
   // throttling interval expires.
-  nudge_tracker.UpdateTypeThrottlingState(t1);
-  EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+  nudge_tracker_.UpdateTypeThrottlingState(t1);
+  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired());
 }
 
 // Tests throttling-related getter functions when no types are throttled.
 TEST_F(NudgeTrackerTest, NoTypesThrottled) {
-  NudgeTracker nudge_tracker;
-
-  EXPECT_FALSE(nudge_tracker.IsAnyTypeThrottled());
-  EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.GetThrottledTypes().Empty());
+  EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled());
+  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
 }
 
 // Tests throttling-related getter functions when some types are throttled.
 TEST_F(NudgeTrackerTest, ThrottleAndUnthrottle) {
-  NudgeTracker nudge_tracker;
   const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
   const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10);
   const base::TimeTicks t1 = t0 + throttle_length;
 
-  nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, PREFERENCES),
+  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, PREFERENCES),
                                        throttle_length,
                                        t0);
 
-  EXPECT_TRUE(nudge_tracker.IsAnyTypeThrottled());
-  EXPECT_TRUE(nudge_tracker.IsTypeThrottled(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.IsTypeThrottled(PREFERENCES));
-  EXPECT_FALSE(nudge_tracker.GetThrottledTypes().Empty());
-  EXPECT_EQ(throttle_length, nudge_tracker.GetTimeUntilNextUnthrottle(t0));
+  EXPECT_TRUE(nudge_tracker_.IsAnyTypeThrottled());
+  EXPECT_TRUE(nudge_tracker_.IsTypeThrottled(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.IsTypeThrottled(PREFERENCES));
+  EXPECT_FALSE(nudge_tracker_.GetThrottledTypes().Empty());
+  EXPECT_EQ(throttle_length, nudge_tracker_.GetTimeUntilNextUnthrottle(t0));
 
-  nudge_tracker.UpdateTypeThrottlingState(t1);
+  nudge_tracker_.UpdateTypeThrottlingState(t1);
 
-  EXPECT_FALSE(nudge_tracker.IsAnyTypeThrottled());
-  EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS));
-  EXPECT_TRUE(nudge_tracker.GetThrottledTypes().Empty());
+  EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled());
+  EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS));
+  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
 }
 
 TEST_F(NudgeTrackerTest, OverlappingThrottleIntervals) {
-  NudgeTracker nudge_tracker;
   const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
   const base::TimeDelta throttle1_length = base::TimeDelta::FromMinutes(10);
   const base::TimeDelta throttle2_length = base::TimeDelta::FromMinutes(20);
@@ -429,39 +426,39 @@
   const base::TimeTicks t2 = t0 + throttle2_length;
 
   // Setup the longer of two intervals.
-  nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, PREFERENCES),
+  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, PREFERENCES),
                                        throttle2_length,
                                        t0);
   EXPECT_TRUE(ModelTypeSetEquals(
           ModelTypeSet(SESSIONS, PREFERENCES),
-          nudge_tracker.GetThrottledTypes()));
+          nudge_tracker_.GetThrottledTypes()));
   EXPECT_EQ(throttle2_length,
-            nudge_tracker.GetTimeUntilNextUnthrottle(t0));
+            nudge_tracker_.GetTimeUntilNextUnthrottle(t0));
 
   // Setup the shorter interval.
-  nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, BOOKMARKS),
+  nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS, BOOKMARKS),
                                        throttle1_length,
                                        t0);
   EXPECT_TRUE(ModelTypeSetEquals(
           ModelTypeSet(SESSIONS, PREFERENCES, BOOKMARKS),
-          nudge_tracker.GetThrottledTypes()));
+          nudge_tracker_.GetThrottledTypes()));
   EXPECT_EQ(throttle1_length,
-            nudge_tracker.GetTimeUntilNextUnthrottle(t0));
+            nudge_tracker_.GetTimeUntilNextUnthrottle(t0));
 
   // Expire the first interval.
-  nudge_tracker.UpdateTypeThrottlingState(t1);
+  nudge_tracker_.UpdateTypeThrottlingState(t1);
 
   // SESSIONS appeared in both intervals.  We expect it will be throttled for
   // the longer of the two, so it's still throttled at time t1.
   EXPECT_TRUE(ModelTypeSetEquals(
           ModelTypeSet(SESSIONS, PREFERENCES),
-          nudge_tracker.GetThrottledTypes()));
+          nudge_tracker_.GetThrottledTypes()));
   EXPECT_EQ(throttle2_length - throttle1_length,
-            nudge_tracker.GetTimeUntilNextUnthrottle(t1));
+            nudge_tracker_.GetTimeUntilNextUnthrottle(t1));
 
   // Expire the second interval.
-  nudge_tracker.UpdateTypeThrottlingState(t2);
-  EXPECT_TRUE(nudge_tracker.GetThrottledTypes().Empty());
+  nudge_tracker_.UpdateTypeThrottlingState(t2);
+  EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty());
 }
 
 }  // namespace sessions
diff --git a/sync/sessions/sync_session_context.cc b/sync/sessions/sync_session_context.cc
index 78b3442..d44591d 100644
--- a/sync/sessions/sync_session_context.cc
+++ b/sync/sessions/sync_session_context.cc
@@ -23,6 +23,7 @@
     const std::string& invalidator_client_id)
     : connection_manager_(connection_manager),
       directory_(directory),
+      update_handler_deleter_(&update_handler_map_),
       commit_contributor_deleter_(&commit_contributor_map_),
       extensions_activity_(extensions_activity),
       notifications_enabled_(false),
@@ -50,14 +51,22 @@
   routing_info_ = routing_info;
 
   // TODO(rlarocque): This is not a good long-term solution.  We must find a
-  // better way to initialize the set of CommitContributors.
-  STLDeleteValues<CommitContributorMap>(&commit_contributor_map_);
+  // better way to initialize the set of CommitContributors and UpdateHandlers.
   ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
+
+  STLDeleteValues<CommitContributorMap>(&commit_contributor_map_);
   for (ModelTypeSet::Iterator it = enabled_types.First(); it.Good(); it.Inc()) {
     SyncDirectoryCommitContributor* contributor =
         new SyncDirectoryCommitContributor(directory(), it.Get());
     commit_contributor_map_.insert(std::make_pair(it.Get(), contributor));
   }
+
+  STLDeleteValues<UpdateHandlerMap>(&update_handler_map_);
+  for (ModelTypeSet::Iterator it = enabled_types.First(); it.Good(); it.Inc()) {
+    SyncDirectoryUpdateHandler* handler =
+        new SyncDirectoryUpdateHandler(directory(), it.Get());
+    update_handler_map_.insert(std::make_pair(it.Get(), handler));
+  }
 }
 
 }  // namespace sessions
diff --git a/sync/sessions/sync_session_context.h b/sync/sessions/sync_session_context.h
index 3133c32..d195943 100644
--- a/sync/sessions/sync_session_context.h
+++ b/sync/sessions/sync_session_context.h
@@ -25,6 +25,7 @@
 #include "base/stl_util.h"
 #include "sync/base/sync_export.h"
 #include "sync/engine/sync_directory_commit_contributor.h"
+#include "sync/engine/sync_directory_update_handler.h"
 #include "sync/engine/sync_engine_event.h"
 #include "sync/engine/syncer_types.h"
 #include "sync/engine/traffic_recorder.h"
@@ -75,6 +76,10 @@
 
   void set_routing_info(const ModelSafeRoutingInfo& routing_info);
 
+  UpdateHandlerMap* update_handler_map() {
+    return &update_handler_map_;
+  }
+
   CommitContributorMap* commit_contributor_map() {
     return &commit_contributor_map_;
   }
@@ -158,6 +163,14 @@
   // Must be updated manually when SBR's state is modified.
   ModelSafeRoutingInfo routing_info_;
 
+  // A map of 'update handlers', one for each enabled type.
+  // This must be kept in sync with the routing info.  Our temporary solution to
+  // that problem is to initialize this map in set_routing_info().
+  UpdateHandlerMap update_handler_map_;
+
+  // Deleter for the |update_handler_map_|.
+  STLValueDeleter<UpdateHandlerMap> update_handler_deleter_;
+
   // A map of 'commit contributors', one for each enabled type.
   // This must be kept in sync with the routing info.  Our temporary solution to
   // that problem is to initialize this map in set_routing_info().
diff --git a/sync/sync_android.gypi b/sync/sync_android.gypi
index b951b07..1964fbd 100644
--- a/sync/sync_android.gypi
+++ b/sync/sync_android.gypi
@@ -21,17 +21,6 @@
           ],
           'includes': [ '../build/java.gypi' ],
         },
-        {
-          'target_name': 'sync_jni_headers',
-          'type': 'none',
-          'sources': [
-            'android/java/src/org/chromium/sync/notifier/InvalidationController.java',
-          ],
-          'variables': {
-            'jni_gen_package': 'sync',
-          },
-          'includes': [ '../build/jni_generator.gypi' ],
-        },
       ],
     }],
   ],
diff --git a/sync/sync_core.gypi b/sync/sync_core.gypi
index 0d5cca7..5d6d989 100644
--- a/sync/sync_core.gypi
+++ b/sync/sync_core.gypi
@@ -40,6 +40,8 @@
     'engine/commit_util.h',
     'engine/commit.cc',
     'engine/commit.h',
+    'engine/sync_directory_update_handler.cc',
+    'engine/sync_directory_update_handler.h',
     'engine/sync_directory_commit_contribution.cc',
     'engine/sync_directory_commit_contribution.h',
     'engine/sync_directory_commit_contributor.cc',
@@ -60,10 +62,8 @@
     'engine/net/url_translator.h',
     'engine/nudge_source.cc',
     'engine/nudge_source.h',
-    'engine/process_updates_command.cc',
-    'engine/process_updates_command.h',
-    'engine/store_timestamps_command.cc',
-    'engine/store_timestamps_command.h',
+    'engine/process_updates_util.cc',
+    'engine/process_updates_util.h',
     'engine/sync_engine_event.cc',
     'engine/sync_engine_event.h',
     'engine/sync_scheduler.cc',
diff --git a/sync/sync_notifier.gypi b/sync/sync_notifier.gypi
index 365ed33..f745234 100644
--- a/sync/sync_notifier.gypi
+++ b/sync/sync_notifier.gypi
@@ -23,11 +23,17 @@
     '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
   ],
   'sources': [
+    'notifier/ack_handler.cc',
+    'notifier/ack_handler.h',
+    'notifier/dropped_invalidation_tracker.cc',
+    'notifier/dropped_invalidation_tracker.h',
     'notifier/invalidation_handler.h',
     'notifier/invalidation_state_tracker.cc',
     'notifier/invalidation_state_tracker.h',
     'notifier/invalidation_util.cc',
     'notifier/invalidation_util.h',
+    'notifier/unacked_invalidation_set.cc',
+    'notifier/unacked_invalidation_set.h',
     'notifier/invalidator.h',
     'notifier/invalidator_registrar.cc',
     'notifier/invalidator_registrar.h',
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index 535042f..cdf671d 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -119,6 +119,8 @@
         'notifier/fake_invalidator.h',
         'notifier/invalidator_test_template.cc',
         'notifier/invalidator_test_template.h',
+        'notifier/mock_ack_handler.cc',
+        'notifier/mock_ack_handler.h',
       ],
     },
 
@@ -150,10 +152,14 @@
         'internal_api/public/base/object_id_invalidation_map_test_util.cc',
         'internal_api/public/base/object_id_invalidation_map_test_util.h',
         'internal_api/public/test/fake_sync_manager.h',
+        'internal_api/public/test/sync_manager_factory_for_profile_sync_test.h',
         'internal_api/public/test/test_entry_factory.h',
         'internal_api/public/test/test_internal_components_factory.h',
         'internal_api/public/test/test_user_share.h',
         'internal_api/test/fake_sync_manager.cc',
+        'internal_api/test/sync_manager_factory_for_profile_sync_test.cc',
+        'internal_api/test/sync_manager_for_profile_sync_test.cc',
+        'internal_api/test/sync_manager_for_profile_sync_test.h',
         'internal_api/test/test_entry_factory.cc',
         'internal_api/test/test_internal_components_factory.cc',
         'internal_api/test/test_user_share.cc',
@@ -239,12 +245,11 @@
           'engine/backoff_delay_provider_unittest.cc',
           'engine/download_unittest.cc',
           'engine/model_changing_syncer_command_unittest.cc',
-          'engine/process_updates_command_unittest.cc',
-          'engine/store_timestamps_command_unittest.cc',
           'engine/sync_scheduler_unittest.cc',
           'engine/syncer_proto_util_unittest.cc',
           'engine/syncer_unittest.cc',
           'engine/sync_directory_commit_contribution_unittest.cc',
+          'engine/sync_directory_update_handler_unittest.cc',
           'engine/traffic_recorder_unittest.cc',
           'js/js_arg_list_unittest.cc',
           'js/js_event_details_unittest.cc',
@@ -331,12 +336,13 @@
               'notifier/invalidator_registrar_unittest.cc',
               'notifier/non_blocking_invalidator_unittest.cc',
               'notifier/object_id_invalidation_map_unittest.cc',
-              'notifier/single_object_invalidation_set_unittest.cc',
               'notifier/p2p_invalidator_unittest.cc',
               'notifier/push_client_channel_unittest.cc',
               'notifier/registration_manager_unittest.cc',
+              'notifier/single_object_invalidation_set_unittest.cc',
               'notifier/sync_invalidation_listener_unittest.cc',
               'notifier/sync_system_resources_unittest.cc',
+              'notifier/unacked_invalidation_set_unittest.cc',
             ],
           }],
         ],
diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc
index 3576413..aac057f 100644
--- a/sync/syncable/model_type.cc
+++ b/sync/syncable/model_type.cc
@@ -223,9 +223,6 @@
 ModelType GetModelType(const sync_pb::SyncEntity& sync_entity) {
   DCHECK(!IsRoot(sync_entity));  // Root shouldn't ever go over the wire.
 
-  if (sync_entity.deleted())
-    return UNSPECIFIED;
-
   // Backwards compatibility with old (pre-specifics) protocol.
   if (sync_entity.has_bookmarkdata())
     return BOOKMARKS;
diff --git a/sync/test/android/OWNERS b/sync/test/android/OWNERS
index 25c1d80..35d33f1 100644
--- a/sync/test/android/OWNERS
+++ b/sync/test/android/OWNERS
@@ -1,2 +1,3 @@
 nyquist@chromium.org
+shashishekhar@chromium.org
 yfriedman@chromium.org
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockSyncContentResolverDelegate.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockSyncContentResolverDelegate.java
index 213fcee..7a33f2f 100644
--- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockSyncContentResolverDelegate.java
+++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockSyncContentResolverDelegate.java
@@ -31,16 +31,20 @@
  */
 public class MockSyncContentResolverDelegate implements SyncContentResolverDelegate {
 
-    private final Map<String, Boolean> mSyncAutomaticallyMap;
+    private final Set<String> mSyncAutomaticallySet;
+    private final Map<String, Boolean> mIsSyncableMap;
+    private final Object mSyncableMapLock = new Object();
 
     private final Set<AsyncSyncStatusObserver> mObservers;
 
     private boolean mMasterSyncAutomatically;
+    private boolean mDisableObserverNotifications;
 
     private Semaphore mPendingObserverCount;
 
     public MockSyncContentResolverDelegate() {
-        mSyncAutomaticallyMap = new HashMap<String, Boolean>();
+        mSyncAutomaticallySet = new HashSet<String>();
+        mIsSyncableMap = new HashMap<String, Boolean>();
         mObservers = new HashSet<AsyncSyncStatusObserver>();
     }
 
@@ -80,22 +84,25 @@
     @Override
     public boolean getSyncAutomatically(Account account, String authority) {
         String key = createKey(account, authority);
-        synchronized (mSyncAutomaticallyMap) {
-            return mSyncAutomaticallyMap.containsKey(key) && mSyncAutomaticallyMap.get(key);
+        synchronized (mSyncableMapLock) {
+            return mSyncAutomaticallySet.contains(key);
         }
     }
 
     @Override
     public void setSyncAutomatically(Account account, String authority, boolean sync) {
         String key = createKey(account, authority);
-        synchronized (mSyncAutomaticallyMap) {
-            if (!mSyncAutomaticallyMap.containsKey(key)) {
+        synchronized (mSyncableMapLock) {
+            if (!mIsSyncableMap.containsKey(key) || !mIsSyncableMap.get(key)) {
                 throw new IllegalArgumentException("Account " + account +
                         " is not syncable for authority " + authority +
                         ". Can not set sync state to " + sync);
             }
-            if (mSyncAutomaticallyMap.get(key) == sync) return;
-            mSyncAutomaticallyMap.put(key, sync);
+            if (sync) {
+                mSyncAutomaticallySet.add(key);
+            } else if (mSyncAutomaticallySet.contains(key)) {
+                mSyncAutomaticallySet.remove(key);
+            }
         }
         notifyObservers();
     }
@@ -104,17 +111,22 @@
     public void setIsSyncable(Account account, String authority, int syncable) {
         String key = createKey(account, authority);
 
-        synchronized (mSyncAutomaticallyMap) {
+        synchronized (mSyncableMapLock) {
             switch (syncable) {
                 case 0:
-                    if (!mSyncAutomaticallyMap.containsKey(key)) return;
+                    if (mSyncAutomaticallySet.contains(key)) {
+                        mSyncAutomaticallySet.remove(key);
+                    }
 
-                    mSyncAutomaticallyMap.remove(key);
+                    mIsSyncableMap.put(key, false);
                     break;
                 case 1:
-                    if (mSyncAutomaticallyMap.containsKey(key)) return;
-
-                    mSyncAutomaticallyMap.put(key, false);
+                    mIsSyncableMap.put(key, true);
+                    break;
+                case -1:
+                    if (mIsSyncableMap.containsKey(key)) {
+                        mIsSyncableMap.remove(key);
+                    }
                     break;
                 default:
                     throw new IllegalArgumentException("Unable to understand syncable argument: " +
@@ -126,12 +138,13 @@
 
     @Override
     public int getIsSyncable(Account account, String authority) {
-        synchronized (mSyncAutomaticallyMap) {
-            final Boolean isSyncable = mSyncAutomaticallyMap.get(createKey(account, authority));
-            if (isSyncable == null) {
+        String key = createKey(account, authority);
+        synchronized (mSyncableMapLock) {
+            if (mIsSyncableMap.containsKey(key)) {
+                return mIsSyncableMap.containsKey(key) ? 1 : 0;
+            } else {
                 return -1;
             }
-            return isSyncable ? 1 : 0;
         }
     }
 
@@ -140,6 +153,7 @@
     }
 
     private void notifyObservers() {
+        if (mDisableObserverNotifications) return;
         synchronized (mObservers) {
             mPendingObserverCount = new Semaphore(1 - mObservers.size());
             for (AsyncSyncStatusObserver observer : mObservers) {
@@ -160,6 +174,10 @@
                 mPendingObserverCount.tryAcquire(5, TimeUnit.SECONDS));
     }
 
+    public void disableObserverNotifications() {
+        mDisableObserverNotifications = true;
+    }
+
     private static class AsyncSyncStatusObserver {
 
         private final SyncStatusObserver mSyncStatusObserver;
diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc
index 009b5a1..624e022 100644
--- a/sync/test/engine/mock_connection_manager.cc
+++ b/sync/test/engine/mock_connection_manager.cc
@@ -35,7 +35,7 @@
 
 MockConnectionManager::MockConnectionManager(syncable::Directory* directory,
                                              CancelationSignal* signal)
-    : ServerConnectionManager("unused", 0, false, false, signal),
+    : ServerConnectionManager("unused", 0, false, signal),
       server_reachable_(true),
       conflict_all_commits_(false),
       conflict_n_commits_(0),
@@ -431,6 +431,9 @@
   ent->set_version(0);
   ent->set_name("");
   ent->set_deleted(true);
+
+  // Make sure we can still extract the ModelType from this tombstone.
+  ent->mutable_specifics()->mutable_bookmark();
 }
 
 void MockConnectionManager::SetLastUpdateDeleted() {
@@ -530,12 +533,10 @@
   std::string token = response->get_updates().new_progress_marker(0).token();
   response->mutable_get_updates()->clear_new_progress_marker();
   for (int i = 0; i < gu.from_progress_marker_size(); ++i) {
-    if (gu.from_progress_marker(i).token() != token) {
-      sync_pb::DataTypeProgressMarker* new_marker =
-          response->mutable_get_updates()->add_new_progress_marker();
-      new_marker->set_data_type_id(gu.from_progress_marker(i).data_type_id());
-      new_marker->set_token(token);
-    }
+    sync_pb::DataTypeProgressMarker* new_marker =
+        response->mutable_get_updates()->add_new_progress_marker();
+    new_marker->set_data_type_id(gu.from_progress_marker(i).data_type_id());
+    new_marker->set_token(token);
   }
 
   // Fill the keystore key if requested.
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index 436b342..fb320a8 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -371,7 +371,7 @@
                     &null_encryptor,
                     scoped_ptr<UnrecoverableErrorHandler>(
                         new LoggingUnrecoverableErrorHandler).Pass(),
-                    &LogUnrecoverableErrorContext, false,
+                    &LogUnrecoverableErrorContext,
                     &scm_cancelation_signal);
   // TODO(akalin): Avoid passing in model parameters multiple times by
   // organizing handling of model types.
diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py
index d807486..7e898c2 100644
--- a/sync/tools/testserver/chromiumsync.py
+++ b/sync/tools/testserver/chromiumsync.py
@@ -451,8 +451,7 @@
         final_stamp = max(old_timestamp, new_timestamp)
         final_migration = self._migration_history.GetLatestVersion(data_type)
         new_marker.token = pickle.dumps((final_stamp, final_migration))
-        if new_marker not in self._original_request.from_progress_marker:
-          get_updates_response.new_progress_marker.add().MergeFrom(new_marker)
+        get_updates_response.new_progress_marker.add().MergeFrom(new_marker)
     elif self._original_request.HasField('from_timestamp'):
       if self._original_request.from_timestamp < new_timestamp:
         get_updates_response.new_timestamp = new_timestamp
@@ -930,7 +929,7 @@
     # tombstone.  A sync server must track deleted IDs forever, since it does
     # not keep track of client knowledge (there's no deletion ACK event).
     if entry.deleted:
-      def MakeTombstone(id_string):
+      def MakeTombstone(id_string, datatype):
         """Make a tombstone entry that will replace the entry being deleted.
 
         Args:
@@ -939,13 +938,11 @@
           A new SyncEntity reflecting the fact that the entry is deleted.
         """
         # Only the ID, version and deletion state are preserved on a tombstone.
-        # TODO(nick): Does the production server not preserve the type?  Not
-        # doing so means that tombstones cannot be filtered based on
-        # requested_types at GetUpdates time.
         tombstone = sync_pb2.SyncEntity()
         tombstone.id_string = id_string
         tombstone.deleted = True
         tombstone.name = ''
+        tombstone.specifics.CopyFrom(GetDefaultEntitySpecifics(datatype))
         return tombstone
 
       def IsChild(child_id):
@@ -968,10 +965,12 @@
 
       # Mark all children that were identified as deleted.
       for child_id in child_ids:
-        self._SaveEntry(MakeTombstone(child_id))
+        datatype = GetEntryType(self._entries[child_id])
+        self._SaveEntry(MakeTombstone(child_id, datatype))
 
       # Delete entry itself.
-      entry = MakeTombstone(entry.id_string)
+      datatype = GetEntryType(self._entries[entry.id_string])
+      entry = MakeTombstone(entry.id_string, datatype)
     else:
       # Comments in sync.proto detail how the representation of positional
       # ordering works.
diff --git a/sync/util/DEPS b/sync/util/DEPS
index 13d7bf1..d311654 100644
--- a/sync/util/DEPS
+++ b/sync/util/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chromeos",
   "+crypto",
   "+sync/base",
   "+sync/internal_api/public/base",
@@ -6,9 +7,6 @@
   "+sync/protocol",
   "+sync/test/fake_encryptor.h",
 
-  # TODO(rsimha): Remove this after http://crbug.com/126732 is fixed.
-  "+chromeos/chromeos_switches.h",
-
   # TODO(zea): remove this once we don't need the cryptographer to get the set
   # of encrypted types.
   "+sync/syncable/nigori_handler.h"
diff --git a/sync/util/get_session_name.cc b/sync/util/get_session_name.cc
index d51c93e..3a09c51 100644
--- a/sync/util/get_session_name.cc
+++ b/sync/util/get_session_name.cc
@@ -11,10 +11,7 @@
 #include "base/sys_info.h"
 #include "base/task_runner.h"
 
-#if defined(OS_CHROMEOS)
-#include "base/command_line.h"
-#include "chromeos/chromeos_switches.h"
-#elif defined(OS_LINUX)
+#if defined(OS_LINUX)
 #include "sync/util/get_session_name_linux.h"
 #elif defined(OS_IOS)
 #include "sync/util/get_session_name_ios.h"
@@ -33,27 +30,7 @@
 std::string GetSessionNameSynchronously() {
   std::string session_name;
 #if defined(OS_CHROMEOS)
-  // The approach below is similar to that used by the CrOs implementation of
-  // StatisticsProvider::GetMachineStatistic(CHROMEOS_RELEASE_BOARD).
-  // See chromeos/system/statistics_provider.{h|cc}.
-  //
-  // We cannot use StatisticsProvider here because of the mutual dependency
-  // it creates between sync.gyp:sync and chrome.gyp:browser.
-  //
-  // Even though this code is ad hoc and fragile, it remains the only means of
-  // determining the Chrome OS hardware platform so we can display the right
-  // device name in the "Other devices" section of the new tab page.
-  // TODO(rsimha): Change this once a better alternative is available.
-  // See http://crbug.com/126732.
-  std::string board;
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(chromeos::switches::kChromeOSReleaseBoard)) {
-    board = command_line->
-        GetSwitchValueASCII(chromeos::switches::kChromeOSReleaseBoard);
-  } else {
-    LOG(ERROR) << "Failed to get board information";
-  }
-
+  std::string board = base::SysInfo::GetLsbReleaseBoard();
   // Currently, only "stumpy" type of board is considered Chromebox, and
   // anything else is Chromebook.  On these devices, session_name should look
   // like "stumpy-signed-mp-v2keys" etc. The information can be checked on
diff --git a/sync/util/get_session_name_unittest.cc b/sync/util/get_session_name_unittest.cc
index e973945..724cd8b 100644
--- a/sync/util/get_session_name_unittest.cc
+++ b/sync/util/get_session_name_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
+#include "base/sys_info.h"
 #include "sync/util/get_session_name.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -42,15 +43,8 @@
 // Call GetSessionNameSynchronouslyForTesting on ChromeOS where the board type
 // is "lumpy-signed-mp-v2keys" and make sure the return value is "Chromebook".
 TEST_F(GetSessionNameTest, GetSessionNameSynchronouslyChromebook) {
-  // This test cannot be run on a real CrOs device, since it will already have a
-  // board type, and we cannot override it.
-  // TODO(rsimha): Rewrite this test once http://crbug.com/126732 is fixed.
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(chromeos::switches::kChromeOSReleaseBoard))
-    return;
-
-  command_line->AppendSwitchASCII(chromeos::switches::kChromeOSReleaseBoard,
-                                  "lumpy-signed-mp-v2keys");
+  const char* kLsbRelease = "CHROMEOS_RELEASE_BOARD=lumpy-signed-mp-v2keys\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
   const std::string& session_name = GetSessionNameSynchronouslyForTesting();
   EXPECT_EQ("Chromebook", session_name);
 }
@@ -58,15 +52,8 @@
 // Call GetSessionNameSynchronouslyForTesting on ChromeOS where the board type
 // is "stumpy-signed-mp-v2keys" and make sure the return value is "Chromebox".
 TEST_F(GetSessionNameTest, GetSessionNameSynchronouslyChromebox) {
-  // This test cannot be run on a real CrOs device, since it will already have a
-  // board type, and we cannot override it.
-  // TODO(rsimha): Rewrite this test once http://crbug.com/126732 is fixed.
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(chromeos::switches::kChromeOSReleaseBoard))
-    return;
-
-  command_line->AppendSwitchASCII(chromeos::switches::kChromeOSReleaseBoard,
-                                  "stumpy-signed-mp-v2keys");
+  const char* kLsbRelease = "CHROMEOS_RELEASE_BOARD=stumpy-signed-mp-v2keys\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
   const std::string& session_name = GetSessionNameSynchronouslyForTesting();
   EXPECT_EQ("Chromebox", session_name);
 }
diff --git a/testing/android/OWNERS b/testing/android/OWNERS
index 87d5d22..b7066d6 100644
--- a/testing/android/OWNERS
+++ b/testing/android/OWNERS
@@ -1,2 +1,8 @@
+aruslan@chromium.org
 bulach@chromium.org
+dtrainor@chromium.org
+miguelg@chromium.org
+nyquist@chromium.org
+skyostil@chromium.org
+tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/testing/gtest_prod.target.darwin-arm.mk b/testing/gtest_prod.target.darwin-arm.mk
index 731626e..5634d68 100644
--- a/testing/gtest_prod.target.darwin-arm.mk
+++ b/testing/gtest_prod.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/testing/gtest_prod.target.darwin-mips.mk b/testing/gtest_prod.target.darwin-mips.mk
index f137bd7..919378b 100644
--- a/testing/gtest_prod.target.darwin-mips.mk
+++ b/testing/gtest_prod.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/testing/gtest_prod.target.darwin-x86.mk b/testing/gtest_prod.target.darwin-x86.mk
index 98d3944..cf4798e 100644
--- a/testing/gtest_prod.target.darwin-x86.mk
+++ b/testing/gtest_prod.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/testing/gtest_prod.target.linux-arm.mk b/testing/gtest_prod.target.linux-arm.mk
index 731626e..5634d68 100644
--- a/testing/gtest_prod.target.linux-arm.mk
+++ b/testing/gtest_prod.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/testing/gtest_prod.target.linux-mips.mk b/testing/gtest_prod.target.linux-mips.mk
index f137bd7..919378b 100644
--- a/testing/gtest_prod.target.linux-mips.mk
+++ b/testing/gtest_prod.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/testing/gtest_prod.target.linux-x86.mk b/testing/gtest_prod.target.linux-x86.mk
index 98d3944..cf4798e 100644
--- a/testing/gtest_prod.target.linux-x86.mk
+++ b/testing/gtest_prod.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-arm.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-arm.mk
index 4c0f737..fb98009 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-arm.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-mips.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-mips.mk
index bc73dc1..d24bc44 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-mips.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-mips.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-x86.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-x86.mk
index f44e733..4fcd02d 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-x86.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.darwin-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-arm.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-arm.mk
index 4c0f737..fb98009 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-arm.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-mips.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-mips.mk
index bc73dc1..d24bc44 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-mips.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-mips.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-x86.mk b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-x86.mk
index f44e733..4fcd02d 100644
--- a/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-x86.mk
+++ b/third_party/harfbuzz-ng/harfbuzz-ng.target.linux-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.darwin-arm.mk b/third_party/iccjpeg/iccjpeg.target.darwin-arm.mk
index 9dbc4d3..4eb019d 100644
--- a/third_party/iccjpeg/iccjpeg.target.darwin-arm.mk
+++ b/third_party/iccjpeg/iccjpeg.target.darwin-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.darwin-mips.mk b/third_party/iccjpeg/iccjpeg.target.darwin-mips.mk
index a765944..e1bd3f5 100644
--- a/third_party/iccjpeg/iccjpeg.target.darwin-mips.mk
+++ b/third_party/iccjpeg/iccjpeg.target.darwin-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.darwin-x86.mk b/third_party/iccjpeg/iccjpeg.target.darwin-x86.mk
index 3965f59..7ff4635 100644
--- a/third_party/iccjpeg/iccjpeg.target.darwin-x86.mk
+++ b/third_party/iccjpeg/iccjpeg.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.linux-arm.mk b/third_party/iccjpeg/iccjpeg.target.linux-arm.mk
index 9dbc4d3..4eb019d 100644
--- a/third_party/iccjpeg/iccjpeg.target.linux-arm.mk
+++ b/third_party/iccjpeg/iccjpeg.target.linux-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.linux-mips.mk b/third_party/iccjpeg/iccjpeg.target.linux-mips.mk
index a765944..e1bd3f5 100644
--- a/third_party/iccjpeg/iccjpeg.target.linux-mips.mk
+++ b/third_party/iccjpeg/iccjpeg.target.linux-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/iccjpeg/iccjpeg.target.linux-x86.mk b/third_party/iccjpeg/iccjpeg.target.linux-x86.mk
index 3965f59..7ff4635 100644
--- a/third_party/iccjpeg/iccjpeg.target.linux-x86.mk
+++ b/third_party/iccjpeg/iccjpeg.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 2eb935b..961ad63 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -390,6 +390,66 @@
   return NONE;
 }
 
+// Keep in sync with LevelDBCorruptionTypes in histograms.xml. Also, don't
+// change the order because indices into this array have been recorded in uma
+// histograms.
+const char* patterns[] = {
+  "missing files",
+  "log record too small",
+  "corrupted internal key",
+  "partial record",
+  "missing start of fragmented record",
+  "error in middle of record",
+  "unknown record type",
+  "truncated record at end",
+  "bad record length",
+  "VersionEdit",
+  "FileReader invoked with unexpected value",
+  "corrupted key",
+  "CURRENT file does not end with newline",
+  "no meta-nextfile entry",
+  "no meta-lognumber entry",
+  "no last-sequence-number entry",
+  "malformed WriteBatch",
+  "bad WriteBatch Put",
+  "bad WriteBatch Delete",
+  "unknown WriteBatch tag",
+  "WriteBatch has wrong count",
+  "bad entry in block",
+  "bad block contents",
+  "bad block handle",
+  "truncated block read",
+  "block checksum mismatch",
+  "checksum mismatch",
+  "corrupted compressed block contents",
+  "bad block type",
+  "bad magic number",
+  "file is too short",
+};
+
+// Returns 1-based index into the above array or 0 if nothing matches.
+int ParseCorruptionMessage(const leveldb::Status& status) {
+  DCHECK(!status.IsIOError());
+  DCHECK(!status.ok());
+  const int kOtherError = 0;
+  int error = kOtherError;
+  const std::string& str_error = status.ToString();
+  const size_t kNumPatterns = arraysize(patterns);
+  for (size_t i = 0; i < kNumPatterns; ++i) {
+    if (str_error.find(patterns[i]) != std::string::npos) {
+      error = i + 1;
+      break;
+    }
+  }
+  return error;
+}
+
+int GetNumCorruptionPatterns() {
+  // + 1 for the "other" error that is returned when a corruption message
+  // doesn't match any of the patterns.
+  return arraysize(patterns) + 1;
+}
+
 bool IndicatesDiskFull(leveldb::Status status) {
   if (status.ok())
     return false;
@@ -674,19 +734,32 @@
 namespace {
 #if defined(OS_WIN)
 static base::PlatformFileError GetDirectoryEntries(
-    const base::FilePath& dir_filepath,
+    const base::FilePath& dir_param,
     std::vector<base::FilePath>* result) {
-  // TODO(dgrogan): Replace with FindFirstFile / FindNextFile. Note that until
-  // that happens this is filtering out directories whereas the Posix version
-  // below is not. There shouldn't be any directories so this shouldn't be an
-  // issue.
-  base::FileEnumerator iter(dir_filepath, false, base::FileEnumerator::FILES);
-  base::FilePath current = iter.Next();
-  while (!current.empty()) {
-    result->push_back(current.BaseName());
-    current = iter.Next();
+  result->clear();
+  base::FilePath dir_filepath = dir_param.Append(FILE_PATH_LITERAL("*"));
+  WIN32_FIND_DATA find_data;
+  HANDLE find_handle = FindFirstFile(dir_filepath.value().c_str(), &find_data);
+  if (find_handle == INVALID_HANDLE_VALUE) {
+    DWORD last_error = GetLastError();
+    if (last_error == ERROR_FILE_NOT_FOUND)
+      return base::PLATFORM_FILE_OK;
+    return base::LastErrorToPlatformFileError(last_error);
   }
-  return base::PLATFORM_FILE_OK;
+  do {
+    base::FilePath filepath(find_data.cFileName);
+    base::FilePath::StringType basename = filepath.BaseName().value();
+    if (basename == FILE_PATH_LITERAL(".") ||
+        basename == FILE_PATH_LITERAL(".."))
+      continue;
+    result->push_back(filepath.BaseName());
+  } while (FindNextFile(find_handle, &find_data));
+  DWORD last_error = GetLastError();
+  base::PlatformFileError return_value = base::PLATFORM_FILE_OK;
+  if (last_error != ERROR_NO_MORE_FILES)
+    return_value = base::LastErrorToPlatformFileError(last_error);
+  FindClose(find_handle);
+  return return_value;
 }
 #else
 static base::PlatformFileError GetDirectoryEntries(
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h
index 3afd462..e171cbd 100644
--- a/third_party/leveldatabase/env_chromium.h
+++ b/third_party/leveldatabase/env_chromium.h
@@ -69,6 +69,8 @@
 ErrorParsingResult ParseMethodAndError(const char* string,
                                        MethodID* method,
                                        int* error);
+int ParseCorruptionMessage(const leveldb::Status& status);
+int GetNumCorruptionPatterns();
 bool IndicatesDiskFull(leveldb::Status status);
 bool IsIOError(leveldb::Status status);
 std::string FilePathToString(const base::FilePath& file_path);
diff --git a/third_party/leveldatabase/env_chromium_unittest.cc b/third_party/leveldatabase/env_chromium_unittest.cc
index d110763..a995acd 100644
--- a/third_party/leveldatabase/env_chromium_unittest.cc
+++ b/third_party/leveldatabase/env_chromium_unittest.cc
@@ -187,4 +187,16 @@
   EXPECT_EQ(bak_files, ldb_files);
 }
 
+TEST(ChromiumEnv, GetChildrenEmptyDir) {
+  base::ScopedTempDir scoped_temp_dir;
+  scoped_temp_dir.CreateUniqueTempDir();
+  base::FilePath dir = scoped_temp_dir.path();
+
+  Env* env = IDBEnv();
+  std::vector<std::string> result;
+  leveldb::Status status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ(0, result.size());
+}
+
 int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); }
diff --git a/third_party/leveldatabase/leveldatabase.target.darwin-arm.mk b/third_party/leveldatabase/leveldatabase.target.darwin-arm.mk
index 2dfdd0f..53ca69f 100644
--- a/third_party/leveldatabase/leveldatabase.target.darwin-arm.mk
+++ b/third_party/leveldatabase/leveldatabase.target.darwin-arm.mk
@@ -103,13 +103,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +190,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/leveldatabase.target.darwin-mips.mk b/third_party/leveldatabase/leveldatabase.target.darwin-mips.mk
index b27f932..56abaaf 100644
--- a/third_party/leveldatabase/leveldatabase.target.darwin-mips.mk
+++ b/third_party/leveldatabase/leveldatabase.target.darwin-mips.mk
@@ -103,13 +103,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +190,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/leveldatabase.target.darwin-x86.mk b/third_party/leveldatabase/leveldatabase.target.darwin-x86.mk
index db971d2..f4d5dce 100644
--- a/third_party/leveldatabase/leveldatabase.target.darwin-x86.mk
+++ b/third_party/leveldatabase/leveldatabase.target.darwin-x86.mk
@@ -105,13 +105,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -195,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/leveldatabase.target.linux-arm.mk b/third_party/leveldatabase/leveldatabase.target.linux-arm.mk
index 2dfdd0f..53ca69f 100644
--- a/third_party/leveldatabase/leveldatabase.target.linux-arm.mk
+++ b/third_party/leveldatabase/leveldatabase.target.linux-arm.mk
@@ -103,13 +103,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +190,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/leveldatabase.target.linux-mips.mk b/third_party/leveldatabase/leveldatabase.target.linux-mips.mk
index b27f932..56abaaf 100644
--- a/third_party/leveldatabase/leveldatabase.target.linux-mips.mk
+++ b/third_party/leveldatabase/leveldatabase.target.linux-mips.mk
@@ -103,13 +103,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +190,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/leveldatabase/leveldatabase.target.linux-x86.mk b/third_party/leveldatabase/leveldatabase.target.linux-x86.mk
index db971d2..f4d5dce 100644
--- a/third_party/leveldatabase/leveldatabase.target.linux-x86.mk
+++ b/third_party/leveldatabase/leveldatabase.target.linux-x86.mk
@@ -105,13 +105,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -195,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.darwin-arm.mk b/third_party/libevent/libevent.target.darwin-arm.mk
index 37341d3..e701dc1 100644
--- a/third_party/libevent/libevent.target.darwin-arm.mk
+++ b/third_party/libevent/libevent.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.darwin-mips.mk b/third_party/libevent/libevent.target.darwin-mips.mk
index f10b9cc..b892fa9 100644
--- a/third_party/libevent/libevent.target.darwin-mips.mk
+++ b/third_party/libevent/libevent.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.darwin-x86.mk b/third_party/libevent/libevent.target.darwin-x86.mk
index 2814f82..3dc96fe 100644
--- a/third_party/libevent/libevent.target.darwin-x86.mk
+++ b/third_party/libevent/libevent.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.linux-arm.mk b/third_party/libevent/libevent.target.linux-arm.mk
index 37341d3..e701dc1 100644
--- a/third_party/libevent/libevent.target.linux-arm.mk
+++ b/third_party/libevent/libevent.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.linux-mips.mk b/third_party/libevent/libevent.target.linux-mips.mk
index f10b9cc..b892fa9 100644
--- a/third_party/libevent/libevent.target.linux-mips.mk
+++ b/third_party/libevent/libevent.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libevent/libevent.target.linux-x86.mk b/third_party/libevent/libevent.target.linux-x86.mk
index 2814f82..3dc96fe 100644
--- a/third_party/libevent/libevent.target.linux-x86.mk
+++ b/third_party/libevent/libevent.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.darwin-arm.mk b/third_party/libjingle/libjingle.target.darwin-arm.mk
index fd1e577..4d7ab0e 100644
--- a/third_party/libjingle/libjingle.target.darwin-arm.mk
+++ b/third_party/libjingle/libjingle.target.darwin-arm.mk
@@ -194,8 +194,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -205,6 +203,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -305,8 +305,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -316,6 +314,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.darwin-mips.mk b/third_party/libjingle/libjingle.target.darwin-mips.mk
index 8d3b359..7531cf8 100644
--- a/third_party/libjingle/libjingle.target.darwin-mips.mk
+++ b/third_party/libjingle/libjingle.target.darwin-mips.mk
@@ -194,8 +194,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -205,6 +203,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -305,8 +305,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -316,6 +314,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.darwin-x86.mk b/third_party/libjingle/libjingle.target.darwin-x86.mk
index c2b2d5f..a585cdf 100644
--- a/third_party/libjingle/libjingle.target.darwin-x86.mk
+++ b/third_party/libjingle/libjingle.target.darwin-x86.mk
@@ -196,8 +196,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -207,6 +205,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -309,8 +309,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -320,6 +318,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.linux-arm.mk b/third_party/libjingle/libjingle.target.linux-arm.mk
index fd1e577..4d7ab0e 100644
--- a/third_party/libjingle/libjingle.target.linux-arm.mk
+++ b/third_party/libjingle/libjingle.target.linux-arm.mk
@@ -194,8 +194,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -205,6 +203,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -305,8 +305,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -316,6 +314,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.linux-mips.mk b/third_party/libjingle/libjingle.target.linux-mips.mk
index 8d3b359..7531cf8 100644
--- a/third_party/libjingle/libjingle.target.linux-mips.mk
+++ b/third_party/libjingle/libjingle.target.linux-mips.mk
@@ -194,8 +194,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -205,6 +203,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -305,8 +305,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -316,6 +314,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle.target.linux-x86.mk b/third_party/libjingle/libjingle.target.linux-x86.mk
index c2b2d5f..a585cdf 100644
--- a/third_party/libjingle/libjingle.target.linux-x86.mk
+++ b/third_party/libjingle/libjingle.target.linux-x86.mk
@@ -196,8 +196,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -207,6 +205,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -309,8 +309,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -320,6 +318,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.darwin-arm.mk b/third_party/libjingle/libjingle_p2p_constants.target.darwin-arm.mk
index adfe31c..6f5d2a9 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.darwin-arm.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.darwin-arm.mk
@@ -79,8 +79,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -90,6 +88,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,8 +189,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -200,6 +198,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.darwin-mips.mk b/third_party/libjingle/libjingle_p2p_constants.target.darwin-mips.mk
index ac9d927..2e904f7 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.darwin-mips.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.darwin-mips.mk
@@ -79,8 +79,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -90,6 +88,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,8 +189,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -200,6 +198,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.darwin-x86.mk b/third_party/libjingle/libjingle_p2p_constants.target.darwin-x86.mk
index 6510549..05098a4 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.darwin-x86.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.darwin-x86.mk
@@ -81,8 +81,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -92,6 +90,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -193,8 +193,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -204,6 +202,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.linux-arm.mk b/third_party/libjingle/libjingle_p2p_constants.target.linux-arm.mk
index adfe31c..6f5d2a9 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.linux-arm.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.linux-arm.mk
@@ -79,8 +79,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -90,6 +88,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,8 +189,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -200,6 +198,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.linux-mips.mk b/third_party/libjingle/libjingle_p2p_constants.target.linux-mips.mk
index ac9d927..2e904f7 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.linux-mips.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.linux-mips.mk
@@ -79,8 +79,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -90,6 +88,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,8 +189,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -200,6 +198,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libjingle/libjingle_p2p_constants.target.linux-x86.mk b/third_party/libjingle/libjingle_p2p_constants.target.linux-x86.mk
index 6510549..05098a4 100644
--- a/third_party/libjingle/libjingle_p2p_constants.target.linux-x86.mk
+++ b/third_party/libjingle/libjingle_p2p_constants.target.linux-x86.mk
@@ -81,8 +81,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -92,6 +90,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -193,8 +193,6 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DLIBPEERCONNECTION_LIB=1' \
 	'-DSSL_USE_OPENSSL' \
@@ -204,6 +202,8 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.darwin-arm.mk b/third_party/libphonenumber/libphonenumber.target.darwin-arm.mk
index 64f936e..85944de 100644
--- a/third_party/libphonenumber/libphonenumber.target.darwin-arm.mk
+++ b/third_party/libphonenumber/libphonenumber.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.darwin-mips.mk b/third_party/libphonenumber/libphonenumber.target.darwin-mips.mk
index f1fa2ce..df3c4b3 100644
--- a/third_party/libphonenumber/libphonenumber.target.darwin-mips.mk
+++ b/third_party/libphonenumber/libphonenumber.target.darwin-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.darwin-x86.mk b/third_party/libphonenumber/libphonenumber.target.darwin-x86.mk
index 7b6cd29..76ba48e 100644
--- a/third_party/libphonenumber/libphonenumber.target.darwin-x86.mk
+++ b/third_party/libphonenumber/libphonenumber.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.linux-arm.mk b/third_party/libphonenumber/libphonenumber.target.linux-arm.mk
index 64f936e..85944de 100644
--- a/third_party/libphonenumber/libphonenumber.target.linux-arm.mk
+++ b/third_party/libphonenumber/libphonenumber.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.linux-mips.mk b/third_party/libphonenumber/libphonenumber.target.linux-mips.mk
index f1fa2ce..df3c4b3 100644
--- a/third_party/libphonenumber/libphonenumber.target.linux-mips.mk
+++ b/third_party/libphonenumber/libphonenumber.target.linux-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber.target.linux-x86.mk b/third_party/libphonenumber/libphonenumber.target.linux-x86.mk
index 7b6cd29..76ba48e 100644
--- a/third_party/libphonenumber/libphonenumber.target.linux-x86.mk
+++ b/third_party/libphonenumber/libphonenumber.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-arm.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-arm.mk
index f378b93..10a0fdd 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-arm.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-arm.mk
@@ -132,13 +132,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -228,13 +228,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-mips.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-mips.mk
index 4f55484..0abbfe1 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-mips.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-mips.mk
@@ -132,13 +132,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -228,13 +228,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-x86.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-x86.mk
index e2755a3..dbf6dee 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-x86.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.darwin-x86.mk
@@ -134,13 +134,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -233,13 +233,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-arm.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-arm.mk
index f378b93..10a0fdd 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-arm.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-arm.mk
@@ -132,13 +132,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -228,13 +228,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-mips.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-mips.mk
index 4f55484..0abbfe1 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-mips.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-mips.mk
@@ -132,13 +132,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -228,13 +228,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-x86.mk b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-x86.mk
index e2755a3..dbf6dee 100644
--- a/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-x86.mk
+++ b/third_party/libphonenumber/libphonenumber_without_metadata.target.linux-x86.mk
@@ -134,13 +134,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -233,13 +233,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.darwin-arm.mk b/third_party/libpng/libpng.target.darwin-arm.mk
index b81a25a..c20c6e2 100644
--- a/third_party/libpng/libpng.target.darwin-arm.mk
+++ b/third_party/libpng/libpng.target.darwin-arm.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.darwin-mips.mk b/third_party/libpng/libpng.target.darwin-mips.mk
index 802fdba..efa1adc 100644
--- a/third_party/libpng/libpng.target.darwin-mips.mk
+++ b/third_party/libpng/libpng.target.darwin-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.darwin-x86.mk b/third_party/libpng/libpng.target.darwin-x86.mk
index ac8d2b2..3afa004 100644
--- a/third_party/libpng/libpng.target.darwin-x86.mk
+++ b/third_party/libpng/libpng.target.darwin-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.linux-arm.mk b/third_party/libpng/libpng.target.linux-arm.mk
index b81a25a..c20c6e2 100644
--- a/third_party/libpng/libpng.target.linux-arm.mk
+++ b/third_party/libpng/libpng.target.linux-arm.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.linux-mips.mk b/third_party/libpng/libpng.target.linux-mips.mk
index 802fdba..efa1adc 100644
--- a/third_party/libpng/libpng.target.linux-mips.mk
+++ b/third_party/libpng/libpng.target.linux-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libpng/libpng.target.linux-x86.mk b/third_party/libpng/libpng.target.linux-x86.mk
index ac8d2b2..3afa004 100644
--- a/third_party/libpng/libpng.target.linux-x86.mk
+++ b/third_party/libpng/libpng.target.linux-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index e5a81aa..fb72237 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -27,3 +27,4 @@
   6284854b Support for "Do not blend" in mux and demux libraries
   40ae352 Fix memleak in WebPIDelete()
   92d47e4 improve VP8L signature detection by checking the version bits too
+  dde91fd Demux: Correct the extended format validation
diff --git a/third_party/libwebp/demux/demux.c b/third_party/libwebp/demux/demux.c
index 1d765c7..9966399 100644
--- a/third_party/libwebp/demux/demux.c
+++ b/third_party/libwebp/demux/demux.c
@@ -619,7 +619,7 @@
 static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
   const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
   const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
-  const Frame* f;
+  const Frame* f = dmux->frames_;
 
   if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
 
@@ -627,7 +627,7 @@
   if (dmux->loop_count_ < 0) return 0;
   if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
 
-  for (f = dmux->frames_; f != NULL; f = f->next_) {
+  while (f != NULL) {
     const int cur_frame_set = f->frame_num_;
     int frame_count = 0, fragment_count = 0;
 
diff --git a/third_party/libwebp/libwebp_dec.target.darwin-arm.mk b/third_party/libwebp/libwebp_dec.target.darwin-arm.mk
index f239548..860a49e 100644
--- a/third_party/libwebp/libwebp_dec.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_dec.target.darwin-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dec.target.darwin-mips.mk b/third_party/libwebp/libwebp_dec.target.darwin-mips.mk
index a70a0c2..705f483 100644
--- a/third_party/libwebp/libwebp_dec.target.darwin-mips.mk
+++ b/third_party/libwebp/libwebp_dec.target.darwin-mips.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dec.target.darwin-x86.mk b/third_party/libwebp/libwebp_dec.target.darwin-x86.mk
index c504773..a5e6cdd 100644
--- a/third_party/libwebp/libwebp_dec.target.darwin-x86.mk
+++ b/third_party/libwebp/libwebp_dec.target.darwin-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dec.target.linux-arm.mk b/third_party/libwebp/libwebp_dec.target.linux-arm.mk
index f239548..860a49e 100644
--- a/third_party/libwebp/libwebp_dec.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_dec.target.linux-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dec.target.linux-mips.mk b/third_party/libwebp/libwebp_dec.target.linux-mips.mk
index a70a0c2..705f483 100644
--- a/third_party/libwebp/libwebp_dec.target.linux-mips.mk
+++ b/third_party/libwebp/libwebp_dec.target.linux-mips.mk
@@ -76,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dec.target.linux-x86.mk b/third_party/libwebp/libwebp_dec.target.linux-x86.mk
index c504773..a5e6cdd 100644
--- a/third_party/libwebp/libwebp_dec.target.linux-x86.mk
+++ b/third_party/libwebp/libwebp_dec.target.linux-x86.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.darwin-arm.mk b/third_party/libwebp/libwebp_demux.target.darwin-arm.mk
index 2f35286..8253abc 100644
--- a/third_party/libwebp/libwebp_demux.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_demux.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.darwin-mips.mk b/third_party/libwebp/libwebp_demux.target.darwin-mips.mk
index ed7748f..0d4f2b6 100644
--- a/third_party/libwebp/libwebp_demux.target.darwin-mips.mk
+++ b/third_party/libwebp/libwebp_demux.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.darwin-x86.mk b/third_party/libwebp/libwebp_demux.target.darwin-x86.mk
index 3e21cb9..bfbd96e 100644
--- a/third_party/libwebp/libwebp_demux.target.darwin-x86.mk
+++ b/third_party/libwebp/libwebp_demux.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.linux-arm.mk b/third_party/libwebp/libwebp_demux.target.linux-arm.mk
index 2f35286..8253abc 100644
--- a/third_party/libwebp/libwebp_demux.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_demux.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.linux-mips.mk b/third_party/libwebp/libwebp_demux.target.linux-mips.mk
index ed7748f..0d4f2b6 100644
--- a/third_party/libwebp/libwebp_demux.target.linux-mips.mk
+++ b/third_party/libwebp/libwebp_demux.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,13 +146,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_demux.target.linux-x86.mk b/third_party/libwebp/libwebp_demux.target.linux-x86.mk
index 3e21cb9..bfbd96e 100644
--- a/third_party/libwebp/libwebp_demux.target.linux-x86.mk
+++ b/third_party/libwebp/libwebp_demux.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.darwin-arm.mk b/third_party/libwebp/libwebp_dsp.target.darwin-arm.mk
index 4b761f8..2425edb 100644
--- a/third_party/libwebp/libwebp_dsp.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_dsp.target.darwin-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.darwin-mips.mk b/third_party/libwebp/libwebp_dsp.target.darwin-mips.mk
index 50ca886..56fd1db 100644
--- a/third_party/libwebp/libwebp_dsp.target.darwin-mips.mk
+++ b/third_party/libwebp/libwebp_dsp.target.darwin-mips.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.darwin-x86.mk b/third_party/libwebp/libwebp_dsp.target.darwin-x86.mk
index fba8e22..7180001 100644
--- a/third_party/libwebp/libwebp_dsp.target.darwin-x86.mk
+++ b/third_party/libwebp/libwebp_dsp.target.darwin-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.linux-arm.mk b/third_party/libwebp/libwebp_dsp.target.linux-arm.mk
index 4b761f8..2425edb 100644
--- a/third_party/libwebp/libwebp_dsp.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_dsp.target.linux-arm.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.linux-mips.mk b/third_party/libwebp/libwebp_dsp.target.linux-mips.mk
index 50ca886..56fd1db 100644
--- a/third_party/libwebp/libwebp_dsp.target.linux-mips.mk
+++ b/third_party/libwebp/libwebp_dsp.target.linux-mips.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -154,13 +154,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp.target.linux-x86.mk b/third_party/libwebp/libwebp_dsp.target.linux-x86.mk
index fba8e22..7180001 100644
--- a/third_party/libwebp/libwebp_dsp.target.linux-x86.mk
+++ b/third_party/libwebp/libwebp_dsp.target.linux-x86.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -159,13 +159,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp_neon.target.darwin-arm.mk b/third_party/libwebp/libwebp_dsp_neon.target.darwin-arm.mk
index 82fb70c..278d665 100644
--- a/third_party/libwebp/libwebp_dsp_neon.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_dsp_neon.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_dsp_neon.target.linux-arm.mk b/third_party/libwebp/libwebp_dsp_neon.target.linux-arm.mk
index 82fb70c..278d665 100644
--- a/third_party/libwebp/libwebp_dsp_neon.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_dsp_neon.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.darwin-arm.mk b/third_party/libwebp/libwebp_enc.target.darwin-arm.mk
index 501f352..be45897 100644
--- a/third_party/libwebp/libwebp_enc.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_enc.target.darwin-arm.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.darwin-mips.mk b/third_party/libwebp/libwebp_enc.target.darwin-mips.mk
index 6d6302e..a3fe1b7 100644
--- a/third_party/libwebp/libwebp_enc.target.darwin-mips.mk
+++ b/third_party/libwebp/libwebp_enc.target.darwin-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.darwin-x86.mk b/third_party/libwebp/libwebp_enc.target.darwin-x86.mk
index 35f5b82..ff19087 100644
--- a/third_party/libwebp/libwebp_enc.target.darwin-x86.mk
+++ b/third_party/libwebp/libwebp_enc.target.darwin-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.linux-arm.mk b/third_party/libwebp/libwebp_enc.target.linux-arm.mk
index 501f352..be45897 100644
--- a/third_party/libwebp/libwebp_enc.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_enc.target.linux-arm.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.linux-mips.mk b/third_party/libwebp/libwebp_enc.target.linux-mips.mk
index 6d6302e..a3fe1b7 100644
--- a/third_party/libwebp/libwebp_enc.target.linux-mips.mk
+++ b/third_party/libwebp/libwebp_enc.target.linux-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_enc.target.linux-x86.mk b/third_party/libwebp/libwebp_enc.target.linux-x86.mk
index 35f5b82..ff19087 100644
--- a/third_party/libwebp/libwebp_enc.target.linux-x86.mk
+++ b/third_party/libwebp/libwebp_enc.target.linux-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.darwin-arm.mk b/third_party/libwebp/libwebp_utils.target.darwin-arm.mk
index 1e86bbf..eb75682 100644
--- a/third_party/libwebp/libwebp_utils.target.darwin-arm.mk
+++ b/third_party/libwebp/libwebp_utils.target.darwin-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.darwin-mips.mk b/third_party/libwebp/libwebp_utils.target.darwin-mips.mk
index e750232..5ad5f5a 100644
--- a/third_party/libwebp/libwebp_utils.target.darwin-mips.mk
+++ b/third_party/libwebp/libwebp_utils.target.darwin-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.darwin-x86.mk b/third_party/libwebp/libwebp_utils.target.darwin-x86.mk
index c0042f7..4f1c18b 100644
--- a/third_party/libwebp/libwebp_utils.target.darwin-x86.mk
+++ b/third_party/libwebp/libwebp_utils.target.darwin-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.linux-arm.mk b/third_party/libwebp/libwebp_utils.target.linux-arm.mk
index 1e86bbf..eb75682 100644
--- a/third_party/libwebp/libwebp_utils.target.linux-arm.mk
+++ b/third_party/libwebp/libwebp_utils.target.linux-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.linux-mips.mk b/third_party/libwebp/libwebp_utils.target.linux-mips.mk
index e750232..5ad5f5a 100644
--- a/third_party/libwebp/libwebp_utils.target.linux-mips.mk
+++ b/third_party/libwebp/libwebp_utils.target.linux-mips.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libwebp/libwebp_utils.target.linux-x86.mk b/third_party/libwebp/libwebp_utils.target.linux-x86.mk
index c0042f7..4f1c18b 100644
--- a/third_party/libwebp/libwebp_utils.target.linux-x86.mk
+++ b/third_party/libwebp/libwebp_utils.target.linux-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -161,13 +161,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.darwin-arm.mk b/third_party/libxml/libxml.target.darwin-arm.mk
index 10a82a7..5019809 100644
--- a/third_party/libxml/libxml.target.darwin-arm.mk
+++ b/third_party/libxml/libxml.target.darwin-arm.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -200,13 +200,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.darwin-mips.mk b/third_party/libxml/libxml.target.darwin-mips.mk
index 5c79f7f..910a9ef 100644
--- a/third_party/libxml/libxml.target.darwin-mips.mk
+++ b/third_party/libxml/libxml.target.darwin-mips.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -200,13 +200,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.darwin-x86.mk b/third_party/libxml/libxml.target.darwin-x86.mk
index 3602589..ec03314 100644
--- a/third_party/libxml/libxml.target.darwin-x86.mk
+++ b/third_party/libxml/libxml.target.darwin-x86.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -205,13 +205,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.linux-arm.mk b/third_party/libxml/libxml.target.linux-arm.mk
index 10a82a7..5019809 100644
--- a/third_party/libxml/libxml.target.linux-arm.mk
+++ b/third_party/libxml/libxml.target.linux-arm.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -200,13 +200,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.linux-mips.mk b/third_party/libxml/libxml.target.linux-mips.mk
index 5c79f7f..910a9ef 100644
--- a/third_party/libxml/libxml.target.linux-mips.mk
+++ b/third_party/libxml/libxml.target.linux-mips.mk
@@ -110,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -200,13 +200,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxml/libxml.target.linux-x86.mk b/third_party/libxml/libxml.target.linux-x86.mk
index 3602589..ec03314 100644
--- a/third_party/libxml/libxml.target.linux-x86.mk
+++ b/third_party/libxml/libxml.target.linux-x86.mk
@@ -112,13 +112,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -205,13 +205,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.darwin-arm.mk b/third_party/libxslt/libxslt.target.darwin-arm.mk
index 5fcf9dc..4729f4b 100644
--- a/third_party/libxslt/libxslt.target.darwin-arm.mk
+++ b/third_party/libxslt/libxslt.target.darwin-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.darwin-mips.mk b/third_party/libxslt/libxslt.target.darwin-mips.mk
index 0c5f8e2..b7a566c 100644
--- a/third_party/libxslt/libxslt.target.darwin-mips.mk
+++ b/third_party/libxslt/libxslt.target.darwin-mips.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.darwin-x86.mk b/third_party/libxslt/libxslt.target.darwin-x86.mk
index 2b4b537..1851188 100644
--- a/third_party/libxslt/libxslt.target.darwin-x86.mk
+++ b/third_party/libxslt/libxslt.target.darwin-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.linux-arm.mk b/third_party/libxslt/libxslt.target.linux-arm.mk
index 5fcf9dc..4729f4b 100644
--- a/third_party/libxslt/libxslt.target.linux-arm.mk
+++ b/third_party/libxslt/libxslt.target.linux-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.linux-mips.mk b/third_party/libxslt/libxslt.target.linux-mips.mk
index 0c5f8e2..b7a566c 100644
--- a/third_party/libxslt/libxslt.target.linux-mips.mk
+++ b/third_party/libxslt/libxslt.target.linux-mips.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/libxslt/libxslt.target.linux-x86.mk b/third_party/libxslt/libxslt.target.linux-x86.mk
index 2b4b537..1851188 100644
--- a/third_party/libxslt/libxslt.target.linux-x86.mk
+++ b/third_party/libxslt/libxslt.target.linux-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.darwin-arm.mk b/third_party/lzma_sdk/lzma_sdk.target.darwin-arm.mk
index e2fccc4..a0bdd7c 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.darwin-arm.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.darwin-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.darwin-mips.mk b/third_party/lzma_sdk/lzma_sdk.target.darwin-mips.mk
index a5dadbc..709ec2e 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.darwin-mips.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.darwin-mips.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.darwin-x86.mk b/third_party/lzma_sdk/lzma_sdk.target.darwin-x86.mk
index d770a31..a3aa372 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.darwin-x86.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.darwin-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.linux-arm.mk b/third_party/lzma_sdk/lzma_sdk.target.linux-arm.mk
index e2fccc4..a0bdd7c 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.linux-arm.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.linux-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.linux-mips.mk b/third_party/lzma_sdk/lzma_sdk.target.linux-mips.mk
index a5dadbc..709ec2e 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.linux-mips.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.linux-mips.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/lzma_sdk/lzma_sdk.target.linux-x86.mk b/third_party/lzma_sdk/lzma_sdk.target.linux-x86.mk
index d770a31..a3aa372 100644
--- a/third_party/lzma_sdk/lzma_sdk.target.linux-x86.mk
+++ b/third_party/lzma_sdk/lzma_sdk.target.linux-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.darwin-arm.mk b/third_party/modp_b64/modp_b64.target.darwin-arm.mk
index ab00a57..2323d76 100644
--- a/third_party/modp_b64/modp_b64.target.darwin-arm.mk
+++ b/third_party/modp_b64/modp_b64.target.darwin-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.darwin-mips.mk b/third_party/modp_b64/modp_b64.target.darwin-mips.mk
index 48c76f2..bc1411e 100644
--- a/third_party/modp_b64/modp_b64.target.darwin-mips.mk
+++ b/third_party/modp_b64/modp_b64.target.darwin-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.darwin-x86.mk b/third_party/modp_b64/modp_b64.target.darwin-x86.mk
index d340f3e..6974c18 100644
--- a/third_party/modp_b64/modp_b64.target.darwin-x86.mk
+++ b/third_party/modp_b64/modp_b64.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.linux-arm.mk b/third_party/modp_b64/modp_b64.target.linux-arm.mk
index ab00a57..2323d76 100644
--- a/third_party/modp_b64/modp_b64.target.linux-arm.mk
+++ b/third_party/modp_b64/modp_b64.target.linux-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.linux-mips.mk b/third_party/modp_b64/modp_b64.target.linux-mips.mk
index 48c76f2..bc1411e 100644
--- a/third_party/modp_b64/modp_b64.target.linux-mips.mk
+++ b/third_party/modp_b64/modp_b64.target.linux-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,13 +147,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/modp_b64/modp_b64.target.linux-x86.mk b/third_party/modp_b64/modp_b64.target.linux-x86.mk
index d340f3e..6974c18 100644
--- a/third_party/modp_b64/modp_b64.target.linux-x86.mk
+++ b/third_party/modp_b64/modp_b64.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -152,13 +152,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.darwin-arm.mk b/third_party/npapi/npapi.target.darwin-arm.mk
index 7184ff1..7081a04 100644
--- a/third_party/npapi/npapi.target.darwin-arm.mk
+++ b/third_party/npapi/npapi.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.darwin-mips.mk b/third_party/npapi/npapi.target.darwin-mips.mk
index b94a00b..4a5f036 100644
--- a/third_party/npapi/npapi.target.darwin-mips.mk
+++ b/third_party/npapi/npapi.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.darwin-x86.mk b/third_party/npapi/npapi.target.darwin-x86.mk
index 6d844cc..fd45be5 100644
--- a/third_party/npapi/npapi.target.darwin-x86.mk
+++ b/third_party/npapi/npapi.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.linux-arm.mk b/third_party/npapi/npapi.target.linux-arm.mk
index 7184ff1..7081a04 100644
--- a/third_party/npapi/npapi.target.linux-arm.mk
+++ b/third_party/npapi/npapi.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.linux-mips.mk b/third_party/npapi/npapi.target.linux-mips.mk
index b94a00b..4a5f036 100644
--- a/third_party/npapi/npapi.target.linux-mips.mk
+++ b/third_party/npapi/npapi.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/npapi/npapi.target.linux-x86.mk b/third_party/npapi/npapi.target.linux-x86.mk
index 6d844cc..fd45be5 100644
--- a/third_party/npapi/npapi.target.linux-x86.mk
+++ b/third_party/npapi/npapi.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.darwin-arm.mk b/third_party/opus/opus.target.darwin-arm.mk
index c1ba62a..0f48af9 100644
--- a/third_party/opus/opus.target.darwin-arm.mk
+++ b/third_party/opus/opus.target.darwin-arm.mk
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -276,13 +276,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.darwin-mips.mk b/third_party/opus/opus.target.darwin-mips.mk
index 15fa5b6..9758bf0 100644
--- a/third_party/opus/opus.target.darwin-mips.mk
+++ b/third_party/opus/opus.target.darwin-mips.mk
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -276,13 +276,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.darwin-x86.mk b/third_party/opus/opus.target.darwin-x86.mk
index fb56f45..b6f3890 100644
--- a/third_party/opus/opus.target.darwin-x86.mk
+++ b/third_party/opus/opus.target.darwin-x86.mk
@@ -188,13 +188,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -281,13 +281,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.linux-arm.mk b/third_party/opus/opus.target.linux-arm.mk
index c1ba62a..0f48af9 100644
--- a/third_party/opus/opus.target.linux-arm.mk
+++ b/third_party/opus/opus.target.linux-arm.mk
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -276,13 +276,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.linux-mips.mk b/third_party/opus/opus.target.linux-mips.mk
index 15fa5b6..9758bf0 100644
--- a/third_party/opus/opus.target.linux-mips.mk
+++ b/third_party/opus/opus.target.linux-mips.mk
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -276,13 +276,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/opus/opus.target.linux-x86.mk b/third_party/opus/opus.target.linux-x86.mk
index fb56f45..b6f3890 100644
--- a/third_party/opus/opus.target.linux-x86.mk
+++ b/third_party/opus/opus.target.linux-x86.mk
@@ -188,13 +188,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -281,13 +281,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-arm.mk b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-arm.mk
index 78b7714..89bcf4b 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-arm.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -137,13 +137,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-mips.mk b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-mips.mk
index 1d0784b..ee347bc 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-mips.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-x86.mk b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-x86.mk
index 354cead..0895dcb 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.darwin-x86.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.darwin-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.linux-arm.mk b/third_party/protobuf/protobuf_full_do_not_use.host.linux-arm.mk
index 832b37f..74fb12e 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.linux-arm.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.linux-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -137,13 +137,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.linux-mips.mk b/third_party/protobuf/protobuf_full_do_not_use.host.linux-mips.mk
index 94e8216..6e38e31 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.linux-mips.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.linux-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_full_do_not_use.host.linux-x86.mk b/third_party/protobuf/protobuf_full_do_not_use.host.linux-x86.mk
index 74e2f7b..40f60b1 100644
--- a/third_party/protobuf/protobuf_full_do_not_use.host.linux-x86.mk
+++ b/third_party/protobuf/protobuf_full_do_not_use.host.linux-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -139,13 +139,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.darwin-arm.mk b/third_party/protobuf/protobuf_lite.target.darwin-arm.mk
index 5fbbf9d..4958d77 100644
--- a/third_party/protobuf/protobuf_lite.target.darwin-arm.mk
+++ b/third_party/protobuf/protobuf_lite.target.darwin-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.darwin-mips.mk b/third_party/protobuf/protobuf_lite.target.darwin-mips.mk
index 6634ea4..57a7c95 100644
--- a/third_party/protobuf/protobuf_lite.target.darwin-mips.mk
+++ b/third_party/protobuf/protobuf_lite.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.darwin-x86.mk b/third_party/protobuf/protobuf_lite.target.darwin-x86.mk
index 775e2b8..6ba64bd 100644
--- a/third_party/protobuf/protobuf_lite.target.darwin-x86.mk
+++ b/third_party/protobuf/protobuf_lite.target.darwin-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.linux-arm.mk b/third_party/protobuf/protobuf_lite.target.linux-arm.mk
index 5fbbf9d..4958d77 100644
--- a/third_party/protobuf/protobuf_lite.target.linux-arm.mk
+++ b/third_party/protobuf/protobuf_lite.target.linux-arm.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.linux-mips.mk b/third_party/protobuf/protobuf_lite.target.linux-mips.mk
index 6634ea4..57a7c95 100644
--- a/third_party/protobuf/protobuf_lite.target.linux-mips.mk
+++ b/third_party/protobuf/protobuf_lite.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,13 +164,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protobuf_lite.target.linux-x86.mk b/third_party/protobuf/protobuf_lite.target.linux-x86.mk
index 775e2b8..6ba64bd 100644
--- a/third_party/protobuf/protobuf_lite.target.linux-x86.mk
+++ b/third_party/protobuf/protobuf_lite.target.linux-x86.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.darwin-arm.mk b/third_party/protobuf/protoc.host.darwin-arm.mk
index 7f64f74..7cdb7a2 100644
--- a/third_party/protobuf/protoc.host.darwin-arm.mk
+++ b/third_party/protobuf/protoc.host.darwin-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -138,13 +138,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.darwin-mips.mk b/third_party/protobuf/protoc.host.darwin-mips.mk
index 6716a32..1b2fdbd 100644
--- a/third_party/protobuf/protoc.host.darwin-mips.mk
+++ b/third_party/protobuf/protoc.host.darwin-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.darwin-x86.mk b/third_party/protobuf/protoc.host.darwin-x86.mk
index ad95a01..b60270c 100644
--- a/third_party/protobuf/protoc.host.darwin-x86.mk
+++ b/third_party/protobuf/protoc.host.darwin-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.linux-arm.mk b/third_party/protobuf/protoc.host.linux-arm.mk
index 1fe88f1..f74b891 100644
--- a/third_party/protobuf/protoc.host.linux-arm.mk
+++ b/third_party/protobuf/protoc.host.linux-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -138,13 +138,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.linux-mips.mk b/third_party/protobuf/protoc.host.linux-mips.mk
index 1526622..e1bc179 100644
--- a/third_party/protobuf/protoc.host.linux-mips.mk
+++ b/third_party/protobuf/protoc.host.linux-mips.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/protobuf/protoc.host.linux-x86.mk b/third_party/protobuf/protoc.host.linux-x86.mk
index 322ce95..2e153b6 100644
--- a/third_party/protobuf/protoc.host.linux-x86.mk
+++ b/third_party/protobuf/protoc.host.linux-x86.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -140,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.darwin-arm.mk b/third_party/qcms/qcms.target.darwin-arm.mk
index b6f543f..9af889a 100644
--- a/third_party/qcms/qcms.target.darwin-arm.mk
+++ b/third_party/qcms/qcms.target.darwin-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.darwin-mips.mk b/third_party/qcms/qcms.target.darwin-mips.mk
index fa23c9b..4b0a260 100644
--- a/third_party/qcms/qcms.target.darwin-mips.mk
+++ b/third_party/qcms/qcms.target.darwin-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.darwin-x86.mk b/third_party/qcms/qcms.target.darwin-x86.mk
index ab5f058..8abeefb 100644
--- a/third_party/qcms/qcms.target.darwin-x86.mk
+++ b/third_party/qcms/qcms.target.darwin-x86.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.linux-arm.mk b/third_party/qcms/qcms.target.linux-arm.mk
index b6f543f..9af889a 100644
--- a/third_party/qcms/qcms.target.linux-arm.mk
+++ b/third_party/qcms/qcms.target.linux-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.linux-mips.mk b/third_party/qcms/qcms.target.linux-mips.mk
index fa23c9b..4b0a260 100644
--- a/third_party/qcms/qcms.target.linux-mips.mk
+++ b/third_party/qcms/qcms.target.linux-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -149,13 +149,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/qcms/qcms.target.linux-x86.mk b/third_party/qcms/qcms.target.linux-x86.mk
index ab5f058..8abeefb 100644
--- a/third_party/qcms/qcms.target.linux-x86.mk
+++ b/third_party/qcms/qcms.target.linux-x86.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.darwin-arm.mk b/third_party/re2/re2.target.darwin-arm.mk
index 322e06b..e3d050f 100644
--- a/third_party/re2/re2.target.darwin-arm.mk
+++ b/third_party/re2/re2.target.darwin-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.darwin-mips.mk b/third_party/re2/re2.target.darwin-mips.mk
index 4df93a0..b3b4b3b 100644
--- a/third_party/re2/re2.target.darwin-mips.mk
+++ b/third_party/re2/re2.target.darwin-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.darwin-x86.mk b/third_party/re2/re2.target.darwin-x86.mk
index 09a686e..d04e3583 100644
--- a/third_party/re2/re2.target.darwin-x86.mk
+++ b/third_party/re2/re2.target.darwin-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -177,13 +177,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.linux-arm.mk b/third_party/re2/re2.target.linux-arm.mk
index 322e06b..e3d050f 100644
--- a/third_party/re2/re2.target.linux-arm.mk
+++ b/third_party/re2/re2.target.linux-arm.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.linux-mips.mk b/third_party/re2/re2.target.linux-mips.mk
index 4df93a0..b3b4b3b 100644
--- a/third_party/re2/re2.target.linux-mips.mk
+++ b/third_party/re2/re2.target.linux-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -172,13 +172,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/re2/re2.target.linux-x86.mk b/third_party/re2/re2.target.linux-x86.mk
index 09a686e..d04e3583 100644
--- a/third_party/re2/re2.target.linux-x86.mk
+++ b/third_party/re2/re2.target.linux-x86.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -177,13 +177,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.darwin-arm.mk b/third_party/smhasher/cityhash.target.darwin-arm.mk
index 1a51cb0..715197a 100644
--- a/third_party/smhasher/cityhash.target.darwin-arm.mk
+++ b/third_party/smhasher/cityhash.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.darwin-mips.mk b/third_party/smhasher/cityhash.target.darwin-mips.mk
index ee81ba8..500feef 100644
--- a/third_party/smhasher/cityhash.target.darwin-mips.mk
+++ b/third_party/smhasher/cityhash.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.darwin-x86.mk b/third_party/smhasher/cityhash.target.darwin-x86.mk
index 7445edb..9bbeaec 100644
--- a/third_party/smhasher/cityhash.target.darwin-x86.mk
+++ b/third_party/smhasher/cityhash.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.linux-arm.mk b/third_party/smhasher/cityhash.target.linux-arm.mk
index 1a51cb0..715197a 100644
--- a/third_party/smhasher/cityhash.target.linux-arm.mk
+++ b/third_party/smhasher/cityhash.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.linux-mips.mk b/third_party/smhasher/cityhash.target.linux-mips.mk
index ee81ba8..500feef 100644
--- a/third_party/smhasher/cityhash.target.linux-mips.mk
+++ b/third_party/smhasher/cityhash.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -145,13 +145,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/smhasher/cityhash.target.linux-x86.mk b/third_party/smhasher/cityhash.target.linux-x86.mk
index 7445edb..9bbeaec 100644
--- a/third_party/smhasher/cityhash.target.linux-x86.mk
+++ b/third_party/smhasher/cityhash.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.darwin-arm.mk b/third_party/sqlite/sqlite.target.darwin-arm.mk
index 2e67dac..51b01bc 100644
--- a/third_party/sqlite/sqlite.target.darwin-arm.mk
+++ b/third_party/sqlite/sqlite.target.darwin-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.darwin-mips.mk b/third_party/sqlite/sqlite.target.darwin-mips.mk
index cdb4a69..797579b 100644
--- a/third_party/sqlite/sqlite.target.darwin-mips.mk
+++ b/third_party/sqlite/sqlite.target.darwin-mips.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.darwin-x86.mk b/third_party/sqlite/sqlite.target.darwin-x86.mk
index 665217f..1f38c8e 100644
--- a/third_party/sqlite/sqlite.target.darwin-x86.mk
+++ b/third_party/sqlite/sqlite.target.darwin-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.linux-arm.mk b/third_party/sqlite/sqlite.target.linux-arm.mk
index 2e67dac..51b01bc 100644
--- a/third_party/sqlite/sqlite.target.linux-arm.mk
+++ b/third_party/sqlite/sqlite.target.linux-arm.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.linux-mips.mk b/third_party/sqlite/sqlite.target.linux-mips.mk
index cdb4a69..797579b 100644
--- a/third_party/sqlite/sqlite.target.linux-mips.mk
+++ b/third_party/sqlite/sqlite.target.linux-mips.mk
@@ -83,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +186,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/sqlite/sqlite.target.linux-x86.mk b/third_party/sqlite/sqlite.target.linux-x86.mk
index 665217f..1f38c8e 100644
--- a/third_party/sqlite/sqlite.target.linux-x86.mk
+++ b/third_party/sqlite/sqlite.target.linux-x86.mk
@@ -85,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -191,13 +191,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/swig/README.chromium b/third_party/swig/README.chromium
index 49754fa..d82b7de 100644
--- a/third_party/swig/README.chromium
+++ b/third_party/swig/README.chromium
@@ -15,6 +15,8 @@
 Local Modifications:
 - Removed all non-python bindings from Lib/.
 - Edit Lib/python/pyruntime.swg to include Python.h without the _DEBUG macro to
-avoid requiring python<ver>_d.lib since we do not intend to debug python. Also
-disable a MSVC warning about mixing headers with and without _DEBUG.
-
+  avoid requiring python<ver>_d.lib since we do not intend to debug python. Also
+  disable a MSVC warning about mixing headers with and without _DEBUG.
+- Edit Lib/python/pyruntime.swg to include <Python/Python.h> rather than
+  <Python.h> on the Mac.
+  http://crbug.com/305277 https://sourceforge.net/p/swig/bugs/1346/
diff --git a/third_party/widevine/cdm/widevine_cdm_common.h b/third_party/widevine/cdm/widevine_cdm_common.h
index 2b3ef0d..fb8ff85 100644
--- a/third_party/widevine/cdm/widevine_cdm_common.h
+++ b/third_party/widevine/cdm/widevine_cdm_common.h
@@ -45,6 +45,16 @@
     "libwidevinecdmadapter.so";
 #endif
 
+// The following strings are used to communicate supported codecs (from the
+// component manifest) via WebPluginInfo::WebPluginMimeType's additional params.
+const char kCdmSupportedCodecsParamName[] = "codecs";
+const char kCdmSupportedCodecsValueDelimiter = ',';
+const char kCdmSupportedCodecVorbis[] = "vorbis";
+const char kCdmSupportedCodecVp8[] = "vp8";
+#if defined(USE_PROPRIETARY_CODECS)
+const char kCdmSupportedCodecAac[] = "aac";
+const char kCdmSupportedCodecAvc1[] = "avc1";
+#endif  // defined(USE_PROPRIETARY_CODECS)
 
 #if defined(OS_MACOSX) || defined(OS_WIN)
 // CDM is installed by the component installer instead of the Chrome installer.
diff --git a/third_party/yasm/config_sources.host.darwin-x86.mk b/third_party/yasm/config_sources.host.darwin-x86.mk
index 8d91de8..f365e17 100644
--- a/third_party/yasm/config_sources.host.darwin-x86.mk
+++ b/third_party/yasm/config_sources.host.darwin-x86.mk
@@ -49,13 +49,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -101,13 +101,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/config_sources.host.linux-x86.mk b/third_party/yasm/config_sources.host.linux-x86.mk
index 8d91de8..f365e17 100644
--- a/third_party/yasm/config_sources.host.linux-x86.mk
+++ b/third_party/yasm/config_sources.host.linux-x86.mk
@@ -49,13 +49,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -101,13 +101,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/generate_files.host.darwin-x86.mk b/third_party/yasm/generate_files.host.darwin-x86.mk
index e0391d9..ad3a363 100644
--- a/third_party/yasm/generate_files.host.darwin-x86.mk
+++ b/third_party/yasm/generate_files.host.darwin-x86.mk
@@ -106,13 +106,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/generate_files.host.linux-x86.mk b/third_party/yasm/generate_files.host.linux-x86.mk
index e0391d9..ad3a363 100644
--- a/third_party/yasm/generate_files.host.linux-x86.mk
+++ b/third_party/yasm/generate_files.host.linux-x86.mk
@@ -106,13 +106,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genmacro.host.darwin-x86.mk b/third_party/yasm/genmacro.host.darwin-x86.mk
index 618c82c..c69fcc8 100644
--- a/third_party/yasm/genmacro.host.darwin-x86.mk
+++ b/third_party/yasm/genmacro.host.darwin-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genmacro.host.linux-x86.mk b/third_party/yasm/genmacro.host.linux-x86.mk
index 04eb007..d2a03c3 100644
--- a/third_party/yasm/genmacro.host.linux-x86.mk
+++ b/third_party/yasm/genmacro.host.linux-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genmodule.host.darwin-x86.mk b/third_party/yasm/genmodule.host.darwin-x86.mk
index c3b5548..33006aa 100644
--- a/third_party/yasm/genmodule.host.darwin-x86.mk
+++ b/third_party/yasm/genmodule.host.darwin-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genmodule.host.linux-x86.mk b/third_party/yasm/genmodule.host.linux-x86.mk
index 259518b..d843e6c 100644
--- a/third_party/yasm/genmodule.host.linux-x86.mk
+++ b/third_party/yasm/genmodule.host.linux-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genperf.host.darwin-x86.mk b/third_party/yasm/genperf.host.darwin-x86.mk
index 6f45071..56dc042 100644
--- a/third_party/yasm/genperf.host.darwin-x86.mk
+++ b/third_party/yasm/genperf.host.darwin-x86.mk
@@ -54,13 +54,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -109,13 +109,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genperf.host.linux-x86.mk b/third_party/yasm/genperf.host.linux-x86.mk
index dd2bdd6..45c6f25 100644
--- a/third_party/yasm/genperf.host.linux-x86.mk
+++ b/third_party/yasm/genperf.host.linux-x86.mk
@@ -54,13 +54,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -109,13 +109,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genperf_libs.host.darwin-x86.mk b/third_party/yasm/genperf_libs.host.darwin-x86.mk
index b5f26cf..7bd5dec 100644
--- a/third_party/yasm/genperf_libs.host.darwin-x86.mk
+++ b/third_party/yasm/genperf_libs.host.darwin-x86.mk
@@ -55,13 +55,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -113,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genperf_libs.host.linux-x86.mk b/third_party/yasm/genperf_libs.host.linux-x86.mk
index 3ac23bd..2c8dfcb 100644
--- a/third_party/yasm/genperf_libs.host.linux-x86.mk
+++ b/third_party/yasm/genperf_libs.host.linux-x86.mk
@@ -55,13 +55,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -113,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genstring.host.darwin-x86.mk b/third_party/yasm/genstring.host.darwin-x86.mk
index 9d480d8..4158f78 100644
--- a/third_party/yasm/genstring.host.darwin-x86.mk
+++ b/third_party/yasm/genstring.host.darwin-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genstring.host.linux-x86.mk b/third_party/yasm/genstring.host.linux-x86.mk
index 0ee5100..810569e 100644
--- a/third_party/yasm/genstring.host.linux-x86.mk
+++ b/third_party/yasm/genstring.host.linux-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genversion.host.darwin-x86.mk b/third_party/yasm/genversion.host.darwin-x86.mk
index a180a27..f4d5ae4 100644
--- a/third_party/yasm/genversion.host.darwin-x86.mk
+++ b/third_party/yasm/genversion.host.darwin-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/genversion.host.linux-x86.mk b/third_party/yasm/genversion.host.linux-x86.mk
index 53a506f..b29831e 100644
--- a/third_party/yasm/genversion.host.linux-x86.mk
+++ b/third_party/yasm/genversion.host.linux-x86.mk
@@ -52,13 +52,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -107,13 +107,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/re2c.host.darwin-x86.mk b/third_party/yasm/re2c.host.darwin-x86.mk
index 93f345f..a3c16ba 100644
--- a/third_party/yasm/re2c.host.darwin-x86.mk
+++ b/third_party/yasm/re2c.host.darwin-x86.mk
@@ -60,13 +60,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -115,13 +115,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/re2c.host.linux-x86.mk b/third_party/yasm/re2c.host.linux-x86.mk
index 239fee5..d6d7129 100644
--- a/third_party/yasm/re2c.host.linux-x86.mk
+++ b/third_party/yasm/re2c.host.linux-x86.mk
@@ -60,13 +60,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -115,13 +115,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/yasm.host.darwin-x86.mk b/third_party/yasm/yasm.host.darwin-x86.mk
index 539a59c..61160fa 100644
--- a/third_party/yasm/yasm.host.darwin-x86.mk
+++ b/third_party/yasm/yasm.host.darwin-x86.mk
@@ -268,13 +268,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -328,13 +328,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/yasm/yasm.host.linux-x86.mk b/third_party/yasm/yasm.host.linux-x86.mk
index c83b74c..ee98ca8 100644
--- a/third_party/yasm/yasm.host.linux-x86.mk
+++ b/third_party/yasm/yasm.host.linux-x86.mk
@@ -268,13 +268,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -328,13 +328,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.darwin-arm.mk b/third_party/zlib/google/zip.target.darwin-arm.mk
index 5166177..3ee0e14 100644
--- a/third_party/zlib/google/zip.target.darwin-arm.mk
+++ b/third_party/zlib/google/zip.target.darwin-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.darwin-mips.mk b/third_party/zlib/google/zip.target.darwin-mips.mk
index 3d89652..130cc58 100644
--- a/third_party/zlib/google/zip.target.darwin-mips.mk
+++ b/third_party/zlib/google/zip.target.darwin-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.darwin-x86.mk b/third_party/zlib/google/zip.target.darwin-x86.mk
index 5575a09..1051eed 100644
--- a/third_party/zlib/google/zip.target.darwin-x86.mk
+++ b/third_party/zlib/google/zip.target.darwin-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.linux-arm.mk b/third_party/zlib/google/zip.target.linux-arm.mk
index 5166177..3ee0e14 100644
--- a/third_party/zlib/google/zip.target.linux-arm.mk
+++ b/third_party/zlib/google/zip.target.linux-arm.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.linux-mips.mk b/third_party/zlib/google/zip.target.linux-mips.mk
index 3d89652..130cc58 100644
--- a/third_party/zlib/google/zip.target.linux-mips.mk
+++ b/third_party/zlib/google/zip.target.linux-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/google/zip.target.linux-x86.mk b/third_party/zlib/google/zip.target.linux-x86.mk
index 5575a09..1051eed 100644
--- a/third_party/zlib/google/zip.target.linux-x86.mk
+++ b/third_party/zlib/google/zip.target.linux-x86.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.darwin-arm.mk b/third_party/zlib/minizip.target.darwin-arm.mk
index bb789b0..7de24c7 100644
--- a/third_party/zlib/minizip.target.darwin-arm.mk
+++ b/third_party/zlib/minizip.target.darwin-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.darwin-mips.mk b/third_party/zlib/minizip.target.darwin-mips.mk
index b9f27e5..55e775e 100644
--- a/third_party/zlib/minizip.target.darwin-mips.mk
+++ b/third_party/zlib/minizip.target.darwin-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.darwin-x86.mk b/third_party/zlib/minizip.target.darwin-x86.mk
index 33f1ba2..ac24e11 100644
--- a/third_party/zlib/minizip.target.darwin-x86.mk
+++ b/third_party/zlib/minizip.target.darwin-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.linux-arm.mk b/third_party/zlib/minizip.target.linux-arm.mk
index bb789b0..7de24c7 100644
--- a/third_party/zlib/minizip.target.linux-arm.mk
+++ b/third_party/zlib/minizip.target.linux-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.linux-mips.mk b/third_party/zlib/minizip.target.linux-mips.mk
index b9f27e5..55e775e 100644
--- a/third_party/zlib/minizip.target.linux-mips.mk
+++ b/third_party/zlib/minizip.target.linux-mips.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -150,13 +150,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/minizip.target.linux-x86.mk b/third_party/zlib/minizip.target.linux-x86.mk
index 33f1ba2..ac24e11 100644
--- a/third_party/zlib/minizip.target.linux-x86.mk
+++ b/third_party/zlib/minizip.target.linux-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.darwin-arm.mk b/third_party/zlib/zlib.target.darwin-arm.mk
index 7b8c571..c239b91 100644
--- a/third_party/zlib/zlib.target.darwin-arm.mk
+++ b/third_party/zlib/zlib.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.darwin-mips.mk b/third_party/zlib/zlib.target.darwin-mips.mk
index d0eb55c..bbb2847 100644
--- a/third_party/zlib/zlib.target.darwin-mips.mk
+++ b/third_party/zlib/zlib.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.darwin-x86.mk b/third_party/zlib/zlib.target.darwin-x86.mk
index 2f04732..fa7c3e7 100644
--- a/third_party/zlib/zlib.target.darwin-x86.mk
+++ b/third_party/zlib/zlib.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.linux-arm.mk b/third_party/zlib/zlib.target.linux-arm.mk
index 7b8c571..c239b91 100644
--- a/third_party/zlib/zlib.target.linux-arm.mk
+++ b/third_party/zlib/zlib.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.linux-mips.mk b/third_party/zlib/zlib.target.linux-mips.mk
index d0eb55c..bbb2847 100644
--- a/third_party/zlib/zlib.target.linux-mips.mk
+++ b/third_party/zlib/zlib.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -160,13 +160,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/third_party/zlib/zlib.target.linux-x86.mk b/third_party/zlib/zlib.target.linux-x86.mk
index 2f04732..fa7c3e7 100644
--- a/third_party/zlib/zlib.target.linux-x86.mk
+++ b/third_party/zlib/zlib.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py
index 0d01def..3e7dfe2 100755
--- a/tools/bisect-perf-regression.py
+++ b/tools/bisect-perf-regression.py
@@ -69,13 +69,15 @@
     "src" : "src/",
     "recurse" : True,
     "depends" : None,
-    "from" : 'cros'
+    "from" : 'cros',
+    'viewvc': 'http://src.chromium.org/viewvc/chrome?view=revision&revision='
   },
   'webkit' : {
     "src" : "src/third_party/WebKit",
     "recurse" : True,
     "depends" : None,
-    "from" : 'chromium'
+    "from" : 'chromium',
+    'viewvc': 'http://src.chromium.org/viewvc/blink?view=revision&revision='
   },
   'angle' : {
     "src" : "src/third_party/angle_dx11",
@@ -90,7 +92,8 @@
     "recurse" : True,
     "depends" : None,
     "from" : 'chromium',
-    "custom_deps": bisect_utils.GCLIENT_CUSTOM_DEPS_V8
+    "custom_deps": bisect_utils.GCLIENT_CUSTOM_DEPS_V8,
+    'viewvc': 'https://code.google.com/p/v8/source/detail?r=',
   },
   'v8_bleeding_edge' : {
     "src" : "src/v8_bleeding_edge",
@@ -98,27 +101,31 @@
     "depends" : None,
     "svn": "https://v8.googlecode.com/svn/branches/bleeding_edge",
     "from" : 'v8',
+    'viewvc': 'https://code.google.com/p/v8/source/detail?r=',
   },
   'skia/src' : {
     "src" : "src/third_party/skia/src",
     "recurse" : True,
     "svn" : "http://skia.googlecode.com/svn/trunk/src",
     "depends" : ['skia/include', 'skia/gyp'],
-    "from" : 'chromium'
+    "from" : 'chromium',
+    'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
   },
   'skia/include' : {
     "src" : "src/third_party/skia/include",
     "recurse" : False,
     "svn" : "http://skia.googlecode.com/svn/trunk/include",
     "depends" : None,
-    "from" : 'chromium'
+    "from" : 'chromium',
+    'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
   },
   'skia/gyp' : {
     "src" : "src/third_party/skia/gyp",
     "recurse" : False,
     "svn" : "http://skia.googlecode.com/svn/trunk/gyp",
     "depends" : None,
-    "from" : 'chromium'
+    "from" : 'chromium',
+    'viewvc': 'https://code.google.com/p/skia/source/detail?r=',
   }
 }
 
@@ -826,12 +833,13 @@
         'email': %s,
         'date': %s,
         'subject': %s,
+        'body': %s,
       }
     """
     commit_info = {}
 
-    formats = ['%cN', '%cE', '%s', '%cD']
-    targets = ['author', 'email', 'subject', 'date']
+    formats = ['%cN', '%cE', '%s', '%cD', '%b']
+    targets = ['author', 'email', 'subject', 'date', 'body']
 
     for i in xrange(len(formats)):
       cmd = ['log', '--format=%s' % formats[i], '-1', revision]
@@ -1263,8 +1271,7 @@
 
     # If running a telemetry test for cros, insert the remote ip, and
     # identity parameters.
-    is_telemetry = ('tools/perf/run_' in command_to_run or
-        'tools\\perf\\run_' in command_to_run)
+    is_telemetry = bisect_utils.IsTelemetryCommand(command_to_run)
     if self.opts.target_platform == 'cros' and is_telemetry:
       args.append('--remote=%s' % self.opts.cros_remote_ip)
       args.append('--identity=%s' % CROS_TEST_KEY_PATH)
@@ -1554,8 +1561,9 @@
           return ('Skipped revision: [%s]' % str(revision),
               BUILD_RESULT_SKIPPED)
 
+        start_build_time = time.time()
         if self.BuildCurrentRevision(depot):
-          start_time = time.time()
+          after_build_time = time.time()
           results = self.RunPerformanceTestAndParseResults(command_to_run,
                                                            metric)
 
@@ -1565,7 +1573,8 @@
 
             if not external_revisions is None:
               return (results[0], results[1], external_revisions,
-                  time.time() - start_time)
+                  time.time() - after_build_time, time.time() -
+                  start_build_time)
             else:
               return ('Failed to parse DEPS file for external revisions.',
                   BUILD_RESULT_FAIL)
@@ -1759,7 +1768,8 @@
       revision_data[r] = {'revision' : r,
                           'depot' : depot,
                           'value' : None,
-                          'time' : 0,
+                          'perf_time' : 0,
+                          'build_time' : 0,
                           'passed' : '?',
                           'sort' : i + sort + 1}
 
@@ -1963,7 +1973,8 @@
                                               'passed' : '?',
                                               'depot' : target_depot,
                                               'external' : None,
-                                              'time' : 0,
+                                              'perf_time' : 0,
+                                              'build_time' : 0,
                                               'sort' : sort_key_ids}
         revision_list.append(current_revision_id)
 
@@ -2012,13 +2023,15 @@
       # already know the results.
       bad_revision_data = revision_data[revision_list[0]]
       bad_revision_data['external'] = bad_results[2]
-      bad_revision_data['time'] = bad_results[3]
+      bad_revision_data['perf_time'] = bad_results[3]
+      bad_revision_data['build_time'] = bad_results[4]
       bad_revision_data['passed'] = False
       bad_revision_data['value'] = known_bad_value
 
       good_revision_data = revision_data[revision_list[max_revision]]
       good_revision_data['external'] = good_results[2]
-      good_revision_data['time'] = good_results[3]
+      good_revision_data['perf_time'] = good_results[3]
+      good_revision_data['build_time'] = good_results[4]
       good_revision_data['passed'] = True
       good_revision_data['value'] = known_good_value
 
@@ -2116,7 +2129,8 @@
         if not run_results[1]:
           if len(run_results) > 2:
             next_revision_data['external'] = run_results[2]
-            next_revision_data['time'] = run_results[3]
+            next_revision_data['perf_time'] = run_results[3]
+            next_revision_data['build_time'] = run_results[4]
 
           passed_regression = self.CheckIfRunPassed(run_results[0],
                                                     known_good_value,
@@ -2151,76 +2165,53 @@
 
     return results
 
-  def _PrintRevisionInfo(self, cl, info):
+  def _PrintBanner(self, results_dict):
+    print
+    print " __o_\___          Aw Snap! We hit a speed bump!"
+    print "=-O----O-'__.~.___________________________________"
+    print
+    print 'Bisect reproduced a %.02f%% (+-%.02f%%) change in the %s metric.' % (
+        results_dict['regression_size'], results_dict['regression_std_err'],
+        '/'.join(self.opts.metric))
+    # The perf dashboard specifically looks for the string
+    # "Confidence in Bisection Results: 100%" to decide whether or not
+    # to cc the author(s). If you change this, please update the perf
+    # dashboard as well.
+    print 'Confidence in Bisection Results: %d%%' % results_dict['confidence']
+
+  def _PrintRevisionInfo(self, cl, info, depot=None):
     # The perf dashboard specifically looks for the string
     # "Author  : " to parse out who to cc on a bug. If you change the
     # formatting here, please update the perf dashboard as well.
     print
-    print 'Commit  : %s' % cl
-    print 'Author  : %s' % info['author']
-    print 'Email   : %s' % info['email']
-    print 'Date    : %s' % info['date']
     print 'Subject : %s' % info['subject']
+    print 'Author  : %s' % info['author']
+    if not info['email'].startswith(info['author']):
+      print 'Email   : %s' % info['email']
+    if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'):
+      try:
+        # Format is "git-svn-id: svn://....@123456 <other data>"
+        svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i]
+        svn_revision = svn_line[0].split('@')
+        svn_revision = svn_revision[1].split(' ')[0]
+        print 'Link    : %s' % DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision
+      except IndexError:
+        print
+        print 'Failed to parse svn revision from body:'
+        print
+        print info['body']
+        print
+    print 'Commit  : %s' % cl
+    print 'Date    : %s' % info['date']
 
-  def FormatAndPrintResults(self, bisect_results):
-    """Prints the results from a bisection run in a readable format.
-
-    Args
-      bisect_results: The results from a bisection test run.
-    """
-    revision_data = bisect_results['revision_data']
-    revision_data_sorted = sorted(revision_data.iteritems(),
-                                  key = lambda x: x[1]['sort'])
-
-    if self.opts.output_buildbot_annotations:
-      bisect_utils.OutputAnnotationStepStart('Build Status Per Revision')
-
-    print
-    print 'Full results of bisection:'
-    for current_id, current_data  in revision_data_sorted:
-      build_status = current_data['passed']
-
-      if type(build_status) is bool:
-        if build_status:
-          build_status = 'Good'
-        else:
-          build_status = 'Bad'
-
-      print '  %20s  %40s  %s' % (current_data['depot'],
-                                 current_id, build_status)
-    print
-
-    if self.opts.output_buildbot_annotations:
-      bisect_utils.OutputAnnotationStepClosed()
-      # The perf dashboard scrapes the "results" step in order to comment on
-      # bugs. If you change this, please update the perf dashboard as well.
-      bisect_utils.OutputAnnotationStepStart('Results')
-
-    # Find range where it possibly broke.
-    first_working_revision = None
-    first_working_revision_index = -1
-    last_broken_revision = None
-    last_broken_revision_index = -1
-
-    for i in xrange(len(revision_data_sorted)):
-      k, v = revision_data_sorted[i]
-      if v['passed'] == 1:
-        if not first_working_revision:
-          first_working_revision = k
-          first_working_revision_index = i
-
-      if not v['passed']:
-        last_broken_revision = k
-        last_broken_revision_index = i
-
+  def _PrintTestedCommitsTable(self, revision_data_sorted,
+                               first_working_revision, last_broken_revision):
     print
     print 'Tested commits:'
     print '  %20s  %40s  %12s %14s %13s' % ('Depot'.center(20, ' '),
         'Commit SHA'.center(40, ' '), 'Mean'.center(12, ' '),
         'Std. Error'.center(14, ' '), 'State'.center(13, ' '))
     state = 0
-    step_time_avg = 0.0
-    step_count = 0.0
     for current_id, current_data in revision_data_sorted:
       if current_data['value']:
         if (current_id == last_broken_revision or
@@ -2242,11 +2233,77 @@
             current_data['depot'].center(20, ' '), current_id, mean,
             std_error, state_str)
 
-        step_time_avg += current_data['time']
-        step_count += 1
+  def _PrintReproSteps(self):
+    print
+    print 'To reproduce locally:'
+    print '$ ' + self.opts.command
+    if bisect_utils.IsTelemetryCommand(self.opts.command):
+      print
+      print 'Also consider passing --profiler=list to see available profilers.'
 
+  def _PrintOtherRegressions(self, other_regressions, revision_data):
+    print
+    print 'Other regressions may have occurred:'
+    for regression in other_regressions:
+      current_id, previous_id, percent_change, deviations = regression
+      current_data = revision_data[current_id]
+      previous_data = revision_data[previous_id]
+
+      if deviations is None:
+        deviations = 'N/A'
+      else:
+        deviations = '%.2f' % deviations
+
+      if percent_change is None:
+        percent_change = 0
+
+      print '  %8s  %s  [%.2f%%, %s x std.dev]' % (
+          previous_data['depot'], previous_id, 100 * percent_change, deviations)
+      print '  %8s  %s' % (current_data['depot'], current_id)
+      print
+
+  def _PrintStepTime(self, revision_data_sorted):
+    step_perf_time_avg = 0.0
+    step_build_time_avg = 0.0
+    step_count = 0.0
+    for _, current_data in revision_data_sorted:
+      step_perf_time_avg += current_data['perf_time']
+      step_build_time_avg += current_data['build_time']
+      step_count += 1
     if step_count:
-      step_time_avg = step_time_avg / step_count
+      step_perf_time_avg = step_perf_time_avg / step_count
+      step_build_time_avg = step_build_time_avg / step_count
+    print
+    print 'Average build time : %s' % datetime.timedelta(
+        seconds=int(step_build_time_avg))
+    print 'Average test time  : %s' % datetime.timedelta(
+        seconds=int(step_perf_time_avg))
+
+  def _PrintWarnings(self):
+    if not self.warnings:
+      return
+    print
+    print 'WARNINGS:'
+    for w in self.warnings:
+      print '  !!! %s' % w
+
+  def _GetResultsDict(self, revision_data, revision_data_sorted):
+    # Find range where it possibly broke.
+    first_working_revision = None
+    first_working_revision_index = -1
+    last_broken_revision = None
+    last_broken_revision_index = -1
+
+    for i in xrange(len(revision_data_sorted)):
+      k, v = revision_data_sorted[i]
+      if v['passed'] == 1:
+        if not first_working_revision:
+          first_working_revision = k
+          first_working_revision_index = i
+
+      if not v['passed']:
+        last_broken_revision = k
+        last_broken_revision_index = i
 
     if last_broken_revision != None and first_working_revision != None:
       bounds_broken = [revision_data[last_broken_revision]['value']['mean'],
@@ -2278,14 +2335,9 @@
       regression_size = math.fabs(max(mean_of_good_runs, mean_of_bad_runs) /
           max(0.0001, min(mean_of_good_runs, mean_of_bad_runs))) * 100.0 - 100.0
 
-      regression_std_err = CalculatePooledStandardError(
-          [working_mean, broken_mean])
-
-      print
-      print 'Average step time: %s' % datetime.timedelta(
-          seconds=int(step_time_avg))
-      print 'Approximate size of regression: %.02f%%, +-%.02f%% std. err' % (
-          regression_size, regression_std_err)
+      regression_std_err = math.fabs(CalculatePooledStandardError(
+          [working_mean, broken_mean]) /
+          max(0.0001, min(mean_of_good_runs, mean_of_bad_runs))) * 100.0
 
       # Give a "confidence" in the bisect. At the moment we use how distinct the
       # values are before and after the last broken revision, and how noisy the
@@ -2297,27 +2349,9 @@
 
       confidence = (dist_between_groups / (
           max(0.0001, (len_broken_group + len_working_group ))))
-      confidence = min(1.0, max(confidence, 0.0)) * 100.0
+      confidence = int(min(1.0, max(confidence, 0.0)) * 100.0)
 
-      # The perf dashboard specifically looks for the string
-      # "Confidence in Bisection Results: 100%" to decide whether or not
-      # to cc the author(s). If you change this, please update the perf
-      # dashboard as well.
-      print 'Confidence in Bisection Results: %d%%' % int(confidence)
-      print
-      print 'Experimental - If confidence is less than 100%, there are could '\
-          'be some other strong candidates for this regression. You can '\
-          'try increasing the repeat_count, or looking for a sub-metric that '\
-          'shows the regression more clearly.'
-      print
-
-      print 'Results: Regression may have occurred in range:'
-      print '  -> First Bad Revision: [%40s] [%s]' %\
-            (last_broken_revision,
-            revision_data[last_broken_revision]['depot'])
-      print '  -> Last Good Revision: [%40s] [%s]' %\
-            (first_working_revision,
-            revision_data[first_working_revision]['depot'])
+      culprit_revisions = []
 
       cwd = os.getcwd()
       self.ChangeToDepotWorkingDirectory(
@@ -2332,10 +2366,8 @@
         (output, return_code) = RunProcessAndRetrieveOutput(cmd)
 
         changes = []
-
         assert not return_code, 'An error occurred while running'\
                                 ' "%s"' % ' '.join(cmd)
-
         last_depot = None
         cwd = os.getcwd()
         for l in output.split('\n'):
@@ -2353,49 +2385,27 @@
               contents = l.split(' ')
               if len(contents) > 1:
                 changes.append([last_depot, contents[0]])
-
-        print
         for c in changes:
           os.chdir(c[0])
           info = self.source_control.QueryRevisionInfo(c[1])
-
-          self._PrintRevisionInfo(c[1], info)
-        print
+          culprit_revisions.append((c[1], info, None))
       else:
-        multiple_commits = 0
         for i in xrange(last_broken_revision_index, len(revision_data_sorted)):
           k, v = revision_data_sorted[i]
           if k == first_working_revision:
             break
-
           self.ChangeToDepotWorkingDirectory(v['depot'])
-
           info = self.source_control.QueryRevisionInfo(k)
-
-          self._PrintRevisionInfo(k, info)
-
-          multiple_commits += 1
-        if multiple_commits > 1:
-          self.warnings.append('Due to build errors, regression range could'
-            ' not be narrowed down to a single commit.')
-      print
+          culprit_revisions.append((k, info, v['depot']))
       os.chdir(cwd)
 
-      # Give a warning if the values were very close together
+      # Check for any other possible regression ranges
       good_std_dev = revision_data[first_working_revision]['value']['std_err']
       good_mean = revision_data[first_working_revision]['value']['mean']
       bad_mean = revision_data[last_broken_revision]['value']['mean']
-
-      # A standard deviation of 0 could indicate either insufficient runs
-      # or a test that consistently returns the same value.
-      if self.opts.repeat_test_count == 1:
-        self.warnings.append('Tests were only set to run once. This '
-            'may be insufficient to get meaningful results.')
-
-      # Check for any other possible regression ranges
       prev_revision_data = revision_data_sorted[0][1]
       prev_revision_id = revision_data_sorted[0][0]
-      possible_regressions = []
+      other_regressions = []
       for current_id, current_data in revision_data_sorted:
         if current_data['value']:
           prev_mean = prev_revision_data['value']['mean']
@@ -2419,45 +2429,84 @@
 
           if deviations >= 1.5 or percent_change > 0.01:
             if current_id != first_working_revision:
-              possible_regressions.append(
+              other_regressions.append(
                   [current_id, prev_revision_id, percent_change, deviations])
           prev_revision_data = current_data
           prev_revision_id = current_id
 
-      if possible_regressions:
-        print
-        print 'Other regressions may have occurred:'
-        print
-        for p in possible_regressions:
-          current_id = p[0]
-          percent_change = p[2]
-          deviations = p[3]
-          current_data = revision_data[current_id]
-          previous_id = p[1]
-          previous_data = revision_data[previous_id]
+    # Check for warnings:
+    if len(culprit_revisions) > 1:
+      self.warnings.append('Due to build errors, regression range could '
+                           'not be narrowed down to a single commit.')
+    if self.opts.repeat_test_count == 1:
+      self.warnings.append('Tests were only set to run once. This may '
+                           'be insufficient to get meaningful results.')
+    if confidence < 100:
+      self.warnings.append(
+          'Confidence is less than 100%. There could be other candidates for '
+          'this regression. Try bisecting again with increased repeat_count or '
+          'on a sub-metric that shows the regression more clearly.')
 
-          if deviations is None:
-            deviations = 'N/A'
-          else:
-            deviations = '%.2f' % deviations
+    return {
+        'first_working_revision': first_working_revision,
+        'last_broken_revision': last_broken_revision,
+        'culprit_revisions': culprit_revisions,
+        'other_regressions': other_regressions,
+        'regression_size': regression_size,
+        'regression_std_err': regression_std_err,
+        'confidence': confidence,
+        }
 
-          if percent_change is None:
-            percent_change = 0
+  def FormatAndPrintResults(self, bisect_results):
+    """Prints the results from a bisection run in a readable format.
 
-          print '  %8s  %s  [%.2f%%, %s x std.dev]' % (
-              previous_data['depot'], previous_id, 100 * percent_change,
-              deviations)
-          print '  %8s  %s' % (
-              current_data['depot'], current_id)
-          print
+    Args
+      bisect_results: The results from a bisection test run.
+    """
+    revision_data = bisect_results['revision_data']
+    revision_data_sorted = sorted(revision_data.iteritems(),
+                                  key = lambda x: x[1]['sort'])
+    results_dict = self._GetResultsDict(revision_data, revision_data_sorted)
 
-      if self.warnings:
-        print
-        print 'The following warnings were generated:'
-        print
-        for w in self.warnings:
-          print '  - %s' % w
-        print
+    if self.opts.output_buildbot_annotations:
+      bisect_utils.OutputAnnotationStepStart('Build Status Per Revision')
+
+    print
+    print 'Full results of bisection:'
+    for current_id, current_data  in revision_data_sorted:
+      build_status = current_data['passed']
+
+      if type(build_status) is bool:
+        if build_status:
+          build_status = 'Good'
+        else:
+          build_status = 'Bad'
+
+      print '  %20s  %40s  %s' % (current_data['depot'],
+                                  current_id, build_status)
+    print
+
+    if self.opts.output_buildbot_annotations:
+      bisect_utils.OutputAnnotationStepClosed()
+      # The perf dashboard scrapes the "results" step in order to comment on
+      # bugs. If you change this, please update the perf dashboard as well.
+      bisect_utils.OutputAnnotationStepStart('Results')
+
+    if results_dict['culprit_revisions']:
+      self._PrintBanner(results_dict)
+      for culprit in results_dict['culprit_revisions']:
+        cl, info, depot = culprit
+        self._PrintRevisionInfo(cl, info, depot)
+      self._PrintReproSteps()
+      if results_dict['other_regressions']:
+        self._PrintOtherRegressions(results_dict['other_regressions'],
+                                    revision_data)
+
+    self._PrintTestedCommitsTable(revision_data_sorted,
+                                  results_dict['first_working_revision'],
+                                  results_dict['last_broken_revision'])
+    self._PrintStepTime(revision_data_sorted)
+    self._PrintWarnings()
 
     if self.opts.output_buildbot_annotations:
       bisect_utils.OutputAnnotationStepClosed()
diff --git a/tools/bisect_utils.py b/tools/bisect_utils.py
index c958f35..767d4f0 100644
--- a/tools/bisect_utils.py
+++ b/tools/bisect_utils.py
@@ -102,6 +102,11 @@
   sys.stdout.flush()
 
 
+def IsTelemetryCommand(command):
+  """Attempts to discern whether or not a given command is running telemetry."""
+  return ('tools/perf/run_' in command or 'tools\\perf\\run_' in command)
+
+
 def CreateAndChangeToSourceDirectory(working_directory):
   """Creates a directory 'bisect' as a subdirectory of 'working_directory'.  If
   the function is successful, the current working directory will change to that
@@ -283,6 +288,19 @@
   return True
 
 
+def _CleanupPreviousGitRuns():
+  """Performs necessary cleanup between runs."""
+  if os.name != 'nt':
+    return
+  # On windows, if a previous run of git crashed, bot was reset, etc... we
+  # might end up with leftover index.lock files.
+  for (path, dir, files) in os.walk(os.getcwd()):
+    for cur_file in files:
+      if cur_file.endswith('index.lock'):
+        path_to_file = os.path.join(path, cur_file)
+        os.remove(path_to_file)
+
+
 def RunGClientAndSync(cwd=None):
   """Runs gclient and does a normal sync.
 
@@ -329,6 +347,8 @@
       os.chdir(cwd)
 
     if passed_deps_check:
+      _CleanupPreviousGitRuns()
+
       RunGClient(['revert'])
       if not RunGClientAndSync():
         passed = True
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
index be1826c..b0a1a68 100755
--- a/tools/clang/scripts/update.sh
+++ b/tools/clang/scripts/update.sh
@@ -8,7 +8,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION=192635
+CLANG_REVISION=192869
 
 THIS_DIR="$(dirname "${0}")"
 LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
diff --git a/tools/deep_memory_profiler/visualizer/app.py b/tools/deep_memory_profiler/visualizer/app.py
index aa9bd99..caebd6f 100644
--- a/tools/deep_memory_profiler/visualizer/app.py
+++ b/tools/deep_memory_profiler/visualizer/app.py
@@ -2,6 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# This file is expected to be used under another directory to use,
+# so we disable checking import path of GAE tools from this directory.
+# pylint: disable=F0401,E0611,W0232
+
 import jinja2
 import json
 import os
@@ -92,4 +96,4 @@
   ('/', MainPage),
   ('/upload', UploadHandler),
   ('/share', ShareHandler)
-], debug=True)
\ No newline at end of file
+], debug=True)
diff --git a/tools/deep_memory_profiler/visualizer/app_unittest.py b/tools/deep_memory_profiler/visualizer/app_unittest.py
index 03110dc..cf30f7e 100644
--- a/tools/deep_memory_profiler/visualizer/app_unittest.py
+++ b/tools/deep_memory_profiler/visualizer/app_unittest.py
@@ -2,6 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# This file is expected to be used under another directory to use,
+# so we disable checking import path of GAE tools from this directory.
+# pylint: disable=F0401,E0611
+
 import json
 import unittest
 
diff --git a/tools/deep_memory_profiler/visualizer/run_tests.py b/tools/deep_memory_profiler/visualizer/run_tests.py
index 0fd3ff1..7a0669c 100755
--- a/tools/deep_memory_profiler/visualizer/run_tests.py
+++ b/tools/deep_memory_profiler/visualizer/run_tests.py
@@ -3,6 +3,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# This file is expected to be used under another directory to use,
+# so we disable checking import path of GAE tools from this directory.
+# pylint: disable=F0401
+
 import os
 import sys
 import unittest
@@ -25,4 +29,4 @@
 
 
 if __name__ == '__main__':
-  sys.exit(main())
\ No newline at end of file
+  sys.exit(main())
diff --git a/tools/deep_memory_profiler/visualizer/services.py b/tools/deep_memory_profiler/visualizer/services.py
index 1b9ad3c..8c8bc65 100644
--- a/tools/deep_memory_profiler/visualizer/services.py
+++ b/tools/deep_memory_profiler/visualizer/services.py
@@ -2,6 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# This file is expected to be used under another directory to use,
+# so we disable checking import path of GAE tools from this directory.
+# pylint: disable=F0401,E0611,W0232
+
 import json
 
 from google.appengine.ext import blobstore
diff --git a/tools/deep_memory_profiler/visualizer/static/dropdown-view.js b/tools/deep_memory_profiler/visualizer/static/dropdown-view.js
index 64820bb..61799ea 100644
--- a/tools/deep_memory_profiler/visualizer/static/dropdown-view.js
+++ b/tools/deep_memory_profiler/visualizer/static/dropdown-view.js
@@ -37,15 +37,22 @@
     });
   } else {
     this.$tree_.tree('loadData', data);
+    $(this.placeholder_).css('display', 'none');
   }
 };
 
 /**
  * Update dropdown view when new model is selected in menu view.
  * @param {string} id Model id.
+ * @param {Object} pos Clicked position.
  * @private
  */
-DropdownView.prototype.update_ = function(id) {
+DropdownView.prototype.update_ = function(id, pos) {
+  if (id == null) {
+    $(this.placeholder_).css('display', 'none');
+    return;
+  }
+
   var self = this;
 
   // Get all subs of selected model.
@@ -83,6 +90,19 @@
   if (curSub) {
     var node = $tree.tree('getNodeById', curSub);
     $tree.tree('selectNode', node);
-    $tree.tree('scrollToNode', node);
+  }
+
+  // If selected category has subs, display subs box.
+  $(this.placeholder_).css('display', 'none');
+  if (children.length > 0) {
+    var view = $(this.placeholder_);
+    view.css('display', 'block');
+    if (pos != undefined) {
+      view.css('position', 'fixed');
+      view.css('top', pos.pageY);
+      view.css('left', pos.pageX);
+    } else {
+      view.css('position', 'static');
+    }
   }
 };
diff --git a/tools/deep_memory_profiler/visualizer/static/graph-view.js b/tools/deep_memory_profiler/visualizer/static/graph-view.js
index b69c5d2..2cd596e 100644
--- a/tools/deep_memory_profiler/visualizer/static/graph-view.js
+++ b/tools/deep_memory_profiler/visualizer/static/graph-view.js
@@ -155,10 +155,12 @@
       }
 
       // If pos.y is higher than all lines, return.
-      if (i === lines.length)
+      if (i === lines.length) {
+        self.profiler_.setSelected(null);
         return;
+      }
 
-      self.profiler_.setSelected(lines[i].id);
+      self.profiler_.setSelected(lines[i].id, pos);
     });
   } else {
     this.graph_.setData(data);
diff --git a/tools/deep_memory_profiler/visualizer/static/index.css b/tools/deep_memory_profiler/visualizer/static/index.css
index ad35df6..d4ab2c7 100644
--- a/tools/deep_memory_profiler/visualizer/static/index.css
+++ b/tools/deep_memory_profiler/visualizer/static/index.css
@@ -32,19 +32,14 @@
 }
 
 #graph-div {
-  width: 1024px;
-  height: 600px;
   float: left;
+  height: 600px;
+  width: 1024px;
 }
 
 #info-div {
-  width: 240px;
-  height: 600px;
   float: left;
   margin-left: 50px;
-  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
-  outline: 1px solid rgba(0,0,0,0.2);
-  overflow: auto;
 }
 
 ul.jqtree-tree .jqtree-title {
@@ -53,9 +48,23 @@
 }
 
 #category-menu {
+  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
+  outline: 1px solid rgba(0,0,0,0.2);
+  overflow: auto;
+  padding-bottom: 15px;
   padding-left: 15px;
+  width: 240px;
 }
 
 #subs-dropdown {
+  background: rgb(255, 255, 255);
+  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
+  display: none;
+  margin-top: 10px;
+  outline: 1px solid rgba(0,0,0,0.2);
+  overflow: auto;
+  padding-bottom: 15px;
   padding-left: 15px;
+  position: fixed;
+  width: 240px;
 }
\ No newline at end of file
diff --git a/tools/deep_memory_profiler/visualizer/static/menu-view.js b/tools/deep_memory_profiler/visualizer/static/menu-view.js
index ff9ec7b..a2aeba2 100644
--- a/tools/deep_memory_profiler/visualizer/static/menu-view.js
+++ b/tools/deep_memory_profiler/visualizer/static/menu-view.js
@@ -18,14 +18,20 @@
 
 /**
  * Highlight the node being selected.
- * @param {string} id Model id.
+ * @param {string|null} id Model id.
+ * @param {Object} pos Clicked position. Not used
  * @private
  */
 MenuView.prototype.selectNode_ = function(id) {
   var $tree = this.$tree_;
+
+  if (id == null) {
+    $tree.tree('selectNode', null);
+    return;
+  }
+
   var node = $tree.tree('getNodeById', id);
   $tree.tree('selectNode', node);
-  $tree.tree('scrollToNode', node);
 };
 
 /**
@@ -48,25 +54,26 @@
     }
   }
 
-  function merge(left, right) {
-    if (!('children' in right) && 'children' in left)
+  function merge(origin, target) {
+    if (!('children' in origin))
       return;
-    if ('children' in right && !('children' in left))
-      left.children = right.children;
-    if ('children' in right && 'children' in left) {
-      right.children.forEach(function(child) {
-        // Find child with the same label in right tree.
-        var index = left.children.reduce(function(previous, current, index) {
-          if (child.label === current.label)
-            return index;
-          return previous;
-        }, -1);
-        if (index === -1)
-          left.children.push(child);
-        else
-          merge(left.children[index], child);
-      });
+    if (!('children' in target)) {
+      target.children = origin.children;
+      return;
     }
+
+    origin.children.forEach(function(child) {
+      // Find child with the same label in target tree.
+      var index = target.children.reduce(function(previous, current, index) {
+        if (child.label === current.label)
+        return index;
+        return previous;
+      }, -1);
+      if (index === -1)
+        target.children.push(child);
+      else
+        merge(child, target.children[index]);
+    });
   }
 
   var self = this;
@@ -79,7 +86,7 @@
     if (!union)
       union = data;
     else
-      merge(union, data);
+      merge(data, union);
   });
 
   // Draw breakdown menu.
@@ -93,11 +100,16 @@
       }
     });
 
-    // Delegate click event to profiler.
+    // Delegate events
     this.$tree_.bind('tree.click', function(event) {
       event.preventDefault();
       self.profiler_.setSelected(event.node.id);
     });
+    this.$tree_.bind('tree.close', function(event) {
+      event.preventDefault();
+      self.profiler_.unsetSub(event.node.id);
+      self.profiler_.setSelected(event.node.id);
+    });
   } else {
     this.$tree_.tree('loadData', data);
   }
diff --git a/tools/deep_memory_profiler/visualizer/static/profiler.js b/tools/deep_memory_profiler/visualizer/static/profiler.js
index e47a4c6..f76dbd2 100644
--- a/tools/deep_memory_profiler/visualizer/static/profiler.js
+++ b/tools/deep_memory_profiler/visualizer/static/profiler.js
@@ -80,10 +80,12 @@
 /**
  * To be called by view when new model being selected.
  * And then triggers all relative views to update.
+ * @param {string} id Model id.
+ * @param {Object} pos Clicked position.
  */
-Profiler.prototype.setSelected = function(id) {
+Profiler.prototype.setSelected = function(id, pos) {
   this.selected_ = id;
-  this.emit('changed:selected', id);
+  this.emit('changed:selected', id, pos);
 };
 
 /**
@@ -138,7 +140,7 @@
 Profiler.prototype.setSub = function(sub) {
   var selected = this.selected_;
   var path = selected.split(',');
-  var key = path[path.length-1];
+  var key = path[path.length - 1];
 
   // Add sub breakdown to template.
   var models = this.getModelsbyId(selected);
@@ -151,6 +153,25 @@
 };
 
 /**
+ * Remove children of figured node and reparse whole tree.
+ * @param {string} id World-breakdown like 'vm-map'.
+ */
+Profiler.prototype.unsetSub = function(id) {
+  var models = this.getModelsbyId(id);
+  if (!('template' in models[0]))
+    return;
+
+  var path = id.split(',');
+  var key = path[path.length - 1];
+  if (!(key in models[0].template[2]))
+    return;
+  delete (models[0].template[2][key]);
+
+  // Recalculate new template.
+  this.reparse();
+};
+
+/**
  * Calculate the model of certain snapshot.
  * @param {string} template Local template.
  * @param {Object} snapshot Current snapshot.
@@ -167,22 +188,24 @@
   var worldName = template[0];
   var breakdownName = template[1];
   var categories = snapshot.worlds[worldName].breakdown[breakdownName];
-  // Make deep copy of localUnits.
-  var remainderUnits = localUnits.slice(0);
+  var matchedUnitsSet = {};
   var model = {
     name: name || worldName + '-' + breakdownName,
     time: snapshot.time,
     children: []
   };
 
+  localUnits.sort(function(a, b) { return b - a; });
   Object.keys(categories).forEach(function(categoryName) {
     var category = categories[categoryName];
     if (category['hidden'] === true)
       return;
-
+    category.units.sort(function(a, b) { return b - a; });
     // Filter units.
-    var matchedUnits = intersection(category.units, localUnits);
-    remainderUnits = difference(remainderUnits, matchedUnits);
+    var matchedUnits = intersectionOfSorted(category.units, localUnits);
+    matchedUnits.forEach(function(unit) {
+      matchedUnitsSet[unit] = unit;
+    });
 
     // Accumulate categories.
     var size = matchedUnits.reduce(function(previous, current) {
@@ -253,7 +276,7 @@
             name: categoryName + '-remaining',
             size: size - retVal.totalSize
           });
-        } else {
+        } else if (size < retVal.totalSize) {
           // Output WARNING when sub-breakdown size is larger.
           console.log('WARNING: size of sub-breakdown is larger');
         }
@@ -261,6 +284,12 @@
     }
   });
 
+  var remainderUnits = localUnits.reduce(function(previous, current) {
+    if (!(current in matchedUnitsSet))
+      previous.push(current);
+    return previous;
+  }, []);
+
   return {
     model: model,
     totalSize: totalSize,
diff --git a/tools/deep_memory_profiler/visualizer/static/utility.js b/tools/deep_memory_profiler/visualizer/static/utility.js
index 85f6768..12649d7 100644
--- a/tools/deep_memory_profiler/visualizer/static/utility.js
+++ b/tools/deep_memory_profiler/visualizer/static/utility.js
@@ -27,30 +27,19 @@
 };
 
 /**
- * Return the intersection set of two arrays.
+ * Return the intersection set of two sorted arrays.
  * @param {Array.<*>} left
  * @param {Array.<*>} right
  * @return {Array.<*>}
  */
-var intersection = function(left, right) {
+var intersectionOfSorted = function(left, right) {
+  var from = 0;
   return left.reduce(function(previous, current) {
-    if (right.indexOf(current) != -1)
+    var idx = right.indexOf(current, from);
+    if (idx != -1) {
       previous.push(current);
-    return previous;
-  }, []);
-};
-
-/**
- * Return the difference set of left with right.
- * Notice: difference(left, right) differentiates with difference(right, left).
- * @param {Array.<*>} left
- * @param {Array.<*>} right
- * @return {Array.<*>}
- */
-var difference = function(left, right) {
-  return left.reduce(function(previous, current) {
-    if (right.indexOf(current) == -1)
-      previous.push(current);
+      from = idx;
+    }
     return previous;
   }, []);
 };
diff --git a/tools/deep_memory_profiler/visualizer/template.py b/tools/deep_memory_profiler/visualizer/template.py
index 3e2b15b..49aed79 100755
--- a/tools/deep_memory_profiler/visualizer/template.py
+++ b/tools/deep_memory_profiler/visualizer/template.py
@@ -42,8 +42,8 @@
   <h2>Deep Memory Profiler Visulaizer</h2>
   <div id="graph-div"></div>
   <div id="info-div">
-    <div id="subs-dropdown"></div>
     <div id="category-menu"></div>
+    <div id="subs-dropdown"></div>
   </div>
 </body>
 """
@@ -77,4 +77,4 @@
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv))
\ No newline at end of file
+  sys.exit(main(sys.argv))
diff --git a/tools/diagnose-me.py b/tools/diagnose-me.py
index bbd9429..970da8a 100755
--- a/tools/diagnose-me.py
+++ b/tools/diagnose-me.py
@@ -79,6 +79,20 @@
     return None
 
 
+@Check("build dependencies are satisfied")
+def CheckBuildDeps():
+    script_path = os.path.join(
+        os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'build',
+        'install-build-deps.sh')
+    proc = subprocess.Popen([script_path, '--quick-check'],
+                            stdout=subprocess.PIPE)
+    stdout = proc.communicate()[0]
+    if 'WARNING' in stdout:
+        return ("Your build dependencies are out-of-date.\n"
+                "Run '" + script_path + "' to update.")
+    return None
+
+
 def RunChecks():
     for name, check in all_checks:
         sys.stdout.write("* Checking %s: " % name)
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
index 4f746f0..2d9aa6e 100644
--- a/tools/gn/args.cc
+++ b/tools/gn/args.cc
@@ -55,10 +55,6 @@
     "  arguments to apply to multiple buildfiles.\n";
 
 Args::Args() {
-  // These system values are always overridden and won't appear in a
-  // declare_args call, so mark them as used to prevent a warning later.
-  declared_arguments_[variables::kOs] = Value();
-  declared_arguments_[variables::kCpuArch] = Value();
 }
 
 Args::Args(const Args& other)
@@ -139,9 +135,12 @@
     }
 
     // Only set on the current scope to the new value if it hasn't been already
-    // set.
-    if (!scope_to_set->GetValue(i->first))
+    // set. Mark the variable used so the build script can override it in
+    // certain cases without getting unused value errors.
+    if (!scope_to_set->GetValue(i->first)) {
       scope_to_set->SetValue(i->first, i->second, i->second.origin());
+      scope_to_set->MarkUsed(i->first);
+    }
   }
 
   return true;
@@ -178,8 +177,6 @@
   Value os_val(NULL, std::string(os));
   dest->SetValue(variables::kBuildOs, os_val, NULL);
   dest->SetValue(variables::kOs, os_val, NULL);
-  declared_arguments_[variables::kBuildOs] = os_val;
-  declared_arguments_[variables::kOs] = os_val;
 
   // Host architecture.
   static const char kIa32[] = "ia32";
@@ -221,11 +218,17 @@
   Value arch_val(NULL, std::string(arch));
   dest->SetValue(variables::kBuildCpuArch, arch_val, NULL);
   dest->SetValue(variables::kCpuArch, arch_val, NULL);
-  declared_arguments_[variables::kBuildOs] = arch_val;
-  declared_arguments_[variables::kOs] = arch_val;
 
+  // Save the OS and architecture as build arguments that are implicitly
+  // declared. This is so they can be overridden in a toolchain build args
+  // override, and so that they will appear in the "gn args" output.
+  //
+  // Do not declare the build* variants since these shouldn't be changed.
+  //
   // Mark these variables used so the build config file can override them
   // without geting a warning about overwriting an unused variable.
+  declared_arguments_[variables::kOs] = os_val;
+  declared_arguments_[variables::kCpuArch] = arch_val;
   dest->MarkUsed(variables::kCpuArch);
   dest->MarkUsed(variables::kOs);
 }
diff --git a/tools/gn/bin/README.txt b/tools/gn/bin/README.txt
new file mode 100644
index 0000000..99a7ef3
--- /dev/null
+++ b/tools/gn/bin/README.txt
@@ -0,0 +1,26 @@
+This folder contains GN binaries. They should be automatically downloaded from
+Google Storage by gclient runhooks for the current platform.
+
+
+To upload a file:
+  python ~/depot_tools/upload_to_google_storage.py -b chromium-gn <FILENAME>
+
+To download a file given a .sha1 file:
+  python ~/depot_tools/download_from_google_storage.py -b chromium-gn -s <FILENAME>.sha1
+
+List the contents of GN's Google Storage bucket:
+  python ~/depot_tools/third_party/gsutil/gsutil ls gs://chromium-gn/
+
+To initialize gsutil's credentials:
+  python ~/depot_tools/third_party/gsutil/gsutil config
+
+  That will give a URL which you should log into with your web browser. The
+  username should be the one that is on the ACL for the "chromium-gn" bucket
+  (probably your @google.com address). Contact the build team for help getting
+  access if necessary.
+
+  Copy the code back to the command line util. Ignore the project ID (it's OK
+  to just leave blank when prompted).
+
+gsutil documentation:
+  https://developers.google.com/storage/docs/gsutil
diff --git a/tools/gn/bin/linux/gn.sha1 b/tools/gn/bin/linux/gn.sha1
new file mode 100644
index 0000000..af60316
--- /dev/null
+++ b/tools/gn/bin/linux/gn.sha1
@@ -0,0 +1 @@
+9c71ff30a0781745029d018313783cc814a8c305
\ No newline at end of file
diff --git a/tools/gn/bin/win/gn.exe.sha1 b/tools/gn/bin/win/gn.exe.sha1
new file mode 100644
index 0000000..492ffbc
--- /dev/null
+++ b/tools/gn/bin/win/gn.exe.sha1
@@ -0,0 +1 @@
+afd819eef0c7a347b4021ac47b722e04e9ff3193
\ No newline at end of file
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index 2ac7389..0a75569 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -4,6 +4,7 @@
 
 #include "tools/gn/build_settings.h"
 
+#include "base/file_util.h"
 #include "tools/gn/filesystem_utils.h"
 
 BuildSettings::BuildSettings()
diff --git a/tools/gn/command_gyp.cc b/tools/gn/command_gyp.cc
index 4d75200..3c6bef9 100644
--- a/tools/gn/command_gyp.cc
+++ b/tools/gn/command_gyp.cc
@@ -233,9 +233,6 @@
   for (CorrelatedTargetsMap::iterator i = correlated.begin();
        i != correlated.end(); ++i) {
     const TargetGroup& group = i->second;
-    if (!EnsureTargetsMatch(group, err))
-      return std::make_pair(0, 0);
-
     if (!group.debug->item_node()->should_generate())
       continue;  // Skip non-generated ones.
     if (group.debug->external())
@@ -243,6 +240,9 @@
     if (group.debug->gyp_file().is_null())
       continue;  // Skip ones without GYP files.
 
+    if (!EnsureTargetsMatch(group, err))
+      return std::make_pair(0, 0);
+
     target_count++;
     grouped_targets[helper.GetGypFileForTarget(group.debug, err)].push_back(
         group);
@@ -270,7 +270,61 @@
 const char kGyp[] = "gyp";
 const char kGyp_HelpShort[] =
     "gyp: Make GYP files from GN.";
-const char kGyp_Help[] = "Doooooom.\n";
+const char kGyp_Help[] =
+    "gyp: Make GYP files from GN.\n"
+    "\n"
+    "  This command will generate GYP files from GN sources. You can then run\n"
+    "  GYP over the result to produce a build. Native GYP targets can depend\n"
+    "  on any GN target except source sets. GN targets can depend on native\n"
+    "  GYP targets, but all/direct dependent settings will NOT be pushed\n"
+    "  across the boundary.\n"
+    "\n"
+    "  To make this work you first need to manually run GN, then GYP, then\n"
+    "  do the build. Because GN doesn't generate the final .ninja files,\n"
+    "  there will be no rules to regenerate the .ninja files if the inputs\n"
+    "  change, so you will have to manually repeat these steps each time\n"
+    "  something changes:\n"
+    "\n"
+    "    out/Debug/gn gyp\n"
+    "    python build/gyp_chromiunm\n"
+    "    ninja -C out/Debug foo_target\n"
+    "\n"
+    "  Two variables are used to control how a target relates to GYP:\n"
+    "\n"
+    "  - \"external != true\" and \"gyp_file\" is set: This target will be\n"
+    "    written to the named GYP file in the source tree (not restricted to\n"
+    "    an output or generated files directory).\n"
+    "\n"
+    "  - \"external == true\" and \"gyp_file\" is set: The target will not\n"
+    "    be written to a GYP file. But other targets being written to GYP\n"
+    "    files can depend on it, and they will reference the given GYP file\n"
+    "    name for GYP to use. This allows you to specify how GN->GYP\n"
+    "    dependencies and named, and provides a place to manually set the\n"
+    "    dependent configs from GYP to GN.\n"
+    "\n"
+    "  - \"gyp_file\" is unset: Like the previous case, but if a GN target is\n"
+    "    being written to a GYP file that depends on this one, the default\n"
+    "    GYP file name will be assumed. The default name will match the name\n"
+    "    of the current directory, so \"//foo/bar:baz\" would be\n"
+    "    \"<(DEPTH)/foo/bar/bar.gyp:baz\".\n"
+    "\n"
+    "Example:\n"
+    "  # This target is assumed to be in the GYP build in the file\n"
+    "  # \"foo/foo.gyp\". This declaration tells GN where to find the GYP\n"
+    "  # equivalent, and gives it some direct dependent settings that targets\n"
+    "  # depending on it should receive (since these don't flow from GYP to\n"
+    "  # GN-generated targets).\n"
+    "  shared_library(\"gyp_target\") {\n"
+    "    gyp_file = \"//foo/foo.gyp\"\n"
+    "    external = true\n"
+    "    direct_dependen_configs = [ \":gyp_target_config\" ]\n"
+    "  }\n"
+    "\n"
+    "  executable(\"my_app\") {\n"
+    "    deps = [ \":gyp_target\" ]\n"
+    "    gyp_file = \"//foo/myapp.gyp\"\n"
+    "    sources = ...\n"
+    "  }\n";
 
 int RunGyp(const std::vector<std::string>& args) {
   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc
index 540d189..bf55165 100644
--- a/tools/gn/function_exec_script.cc
+++ b/tools/gn/function_exec_script.cc
@@ -348,6 +348,14 @@
 
   base::FilePath startup_dir =
       build_settings->GetFullPath(build_settings->build_dir());
+  // The first time a build is run, no targets will have been written so the
+  // build output directory won't exist. We need to make sure it does before
+  // running any scripts with this as its startup directory, although it will
+  // be relatively rare that the directory won't exist by the time we get here.
+  //
+  // If this shows up on benchmarks, we can cache whether we've done this
+  // or not and skip creating the directory.
+  file_util::CreateDirectory(startup_dir);
 
   // Execute the process.
   // TODO(brettw) set the environment block.
diff --git a/tools/gn/gyp_binary_target_writer.cc b/tools/gn/gyp_binary_target_writer.cc
index 7c4e7a3..bcbe7ee 100644
--- a/tools/gn/gyp_binary_target_writer.cc
+++ b/tools/gn/gyp_binary_target_writer.cc
@@ -10,6 +10,7 @@
 #include "tools/gn/config_values_extractors.h"
 #include "tools/gn/err.h"
 #include "tools/gn/escape.h"
+#include "tools/gn/filesystem_utils.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/target.h"
 
@@ -132,15 +133,12 @@
   WriteName(indent + kExtraIndent);
   WriteType(indent + kExtraIndent);
 
-  if (target_->settings()->IsLinux()) {
+  if (target_->settings()->IsLinux())
     WriteLinuxConfiguration(indent + kExtraIndent);
-  } else if (target_->settings()->IsWin()) {
+  else if (target_->settings()->IsWin())
     WriteVCConfiguration(indent + kExtraIndent);
-  } else if (target_->settings()->IsMac()) {
-    // TODO(brettw) mac.
-    NOTREACHED();
-    //WriteMacConfiguration();
-  }
+  else if (target_->settings()->IsMac())
+    WriteMacConfiguration(indent + kExtraIndent);
   WriteDirectDependentSettings(indent + kExtraIndent);
   WriteAllDependentSettings(indent + kExtraIndent);
 
@@ -256,6 +254,25 @@
   WriteDeps(target_, indent);
 }
 
+void GypBinaryTargetWriter::WriteMacConfiguration(int indent) {
+  Indent(indent) << "'configurations': {\n";
+
+  Indent(indent + kExtraIndent) << "'Debug': {\n";
+  Flags debug_flags(FlagsFromTarget(group_.debug));
+  WriteMacFlags(debug_flags, indent + kExtraIndent * 2);
+  Indent(indent + kExtraIndent) << "},\n";
+
+  Indent(indent + kExtraIndent) << "'Release': {\n";
+  Flags release_flags(FlagsFromTarget(group_.release));
+  WriteMacFlags(release_flags, indent + kExtraIndent * 2);
+  Indent(indent + kExtraIndent) << "},\n";
+
+  Indent(indent) << "},\n";
+
+  WriteSources(target_, indent);
+  WriteDeps(target_, indent);
+}
+
 void GypBinaryTargetWriter::WriteVCFlags(Flags& flags, int indent) {
   // Defines and includes go outside of the msvs settings.
   WriteNamedArray(out_, "defines", flags.defines, indent);
@@ -306,6 +323,78 @@
   Indent(indent) << "},\n";
 }
 
+void GypBinaryTargetWriter::WriteMacFlags(Flags& flags, int indent) {
+  WriteNamedArray(out_, "defines", flags.defines, indent);
+  WriteIncludeDirs(flags, indent);
+
+  // Libraries and library directories.
+  EscapeOptions escape_options;
+  escape_options.mode = ESCAPE_JSON;
+  if (!flags.lib_dirs.empty()) {
+    Indent(indent + kExtraIndent) << "'library_dirs': [";
+    for (size_t i = 0; i < flags.lib_dirs.size(); i++) {
+      out_ << " '";
+      EscapeStringToStream(out_,
+                           helper_.GetDirReference(flags.lib_dirs[i], false),
+                           escape_options);
+      out_ << "',";
+    }
+    out_ << " ],\n";
+  }
+  if (!flags.libs.empty()) {
+    Indent(indent) << "'link_settings': {\n";
+    Indent(indent + kExtraIndent) << "'libraries': [";
+    for (size_t i = 0; i < flags.libs.size(); i++) {
+      out_ << " '-l";
+      EscapeStringToStream(out_, flags.libs[i], escape_options);
+      out_ << "',";
+    }
+    out_ << " ],\n";
+    Indent(indent) << "},\n";
+  }
+
+  Indent(indent) << "'xcode_settings': {\n";
+
+  // C/C++ flags.
+  if (!flags.cflags.empty() || !flags.cflags_c.empty() ||
+      !flags.cflags_objc.empty()) {
+    Indent(indent + kExtraIndent) << "'OTHER_CFLAGS': [";
+    WriteArrayValues(out_, flags.cflags);
+    WriteArrayValues(out_, flags.cflags_c);
+    WriteArrayValues(out_, flags.cflags_objc);
+    out_ << " ],\n";
+  }
+  if (!flags.cflags.empty() || !flags.cflags_cc.empty() ||
+      !flags.cflags_objcc.empty()) {
+    Indent(indent + kExtraIndent) << "'OTHER_CPLUSPLUSFLAGS': [";
+    WriteArrayValues(out_, flags.cflags);
+    WriteArrayValues(out_, flags.cflags_cc);
+    WriteArrayValues(out_, flags.cflags_objcc);
+    out_ << " ],\n";
+  }
+
+  // Ld flags. Don't write these for static libraries. Otherwise, they'll be
+  // passed to the library tool which doesn't expect it (the toolchain does
+  // not use ldflags so these are ignored in the normal build).
+  if (target_->output_type() != Target::STATIC_LIBRARY) {
+    WriteNamedArray(out_, "OTHER_LDFLAGS", flags.ldflags,
+                    indent + kExtraIndent);
+  }
+
+  base::FilePath clang_path =
+      target_->settings()->build_settings()->GetFullPath(SourceFile(
+          "//third_party/llvm-build/Release+Asserts/bin/clang"));
+  base::FilePath clang_pp_path =
+      target_->settings()->build_settings()->GetFullPath(SourceFile(
+          "//third_party/llvm-build/Release+Asserts/bin/clang++"));
+
+  Indent(indent) << "'CC': '" << FilePathToUTF8(clang_path) << "',\n";
+  Indent(indent) << "'LDPLUSPLUS': '"
+                 << FilePathToUTF8(clang_pp_path) << "',\n";
+
+  Indent(indent) << "},\n";
+}
+
 void GypBinaryTargetWriter::WriteLinuxFlagsForTarget(const Target* target,
                                                      int indent) {
   Flags flags(FlagsFromTarget(target));
@@ -398,14 +487,12 @@
   out_ << "'direct_dependent_settings': {\n";
 
   Flags flags(FlagsFromConfigList(target_->direct_dependent_configs()));
-  if (target_->settings()->IsLinux()) {
+  if (target_->settings()->IsLinux())
     WriteLinuxFlags(flags, indent + kExtraIndent);
-  } else if (target_->settings()->IsWin()) {
+  else if (target_->settings()->IsWin())
     WriteVCFlags(flags, indent + kExtraIndent);
-  } else if (target_->settings()->IsMac()) {
-    // TODO(brettw) write mac.
-    NOTREACHED();
-  }
+  else if (target_->settings()->IsMac())
+    WriteMacFlags(flags, indent + kExtraIndent);
   Indent(indent) << "},\n";
 }
 
@@ -415,14 +502,12 @@
   Indent(indent) << "'all_dependent_settings': {\n";
 
   Flags flags(FlagsFromConfigList(target_->all_dependent_configs()));
-  if (target_->settings()->IsLinux()) {
+  if (target_->settings()->IsLinux())
     WriteLinuxFlags(flags, indent + kExtraIndent);
-  } else if (target_->settings()->IsWin()) {
+  else if (target_->settings()->IsWin())
     WriteVCFlags(flags, indent + kExtraIndent);
-  } else if (target_->settings()->IsMac()) {
-    // TODO(brettw) write mac.
-    NOTREACHED();
-  }
+  else if (target_->settings()->IsMac())
+    WriteMacFlags(flags, indent + kExtraIndent);
   Indent(indent) << "},\n";
 }
 
diff --git a/tools/gn/gyp_binary_target_writer.h b/tools/gn/gyp_binary_target_writer.h
index b12f154..226ffb8 100644
--- a/tools/gn/gyp_binary_target_writer.h
+++ b/tools/gn/gyp_binary_target_writer.h
@@ -48,11 +48,13 @@
   // Writes the flags, sources, and deps.
   void WriteVCConfiguration(int indent);
   void WriteLinuxConfiguration(int indent);
+  void WriteMacConfiguration(int indent);
 
-  // Writes the Visual Studio flags, defines, etc. The flags input is non-const
-  // because the cflags will be fixed up to account for things converted to
-  // VC settings (rather than compiler flags).
+  // Writes the flags, defines, etc. The flags input is non-const because the
+  // cflags will be fixed up to account for things converted to VC settings
+  // (rather than compiler flags).
   void WriteVCFlags(Flags& flags, int indent);
+  void WriteMacFlags(Flags& flags, int indent);
 
   // Writes the Linux compiler and linker flags. The first version does the
   // flags for the given target, the second version takes a pregenerted list of
diff --git a/tools/gn/gyp_target_writer.cc b/tools/gn/gyp_target_writer.cc
index 5f35054..8a55bdc 100644
--- a/tools/gn/gyp_target_writer.cc
+++ b/tools/gn/gyp_target_writer.cc
@@ -37,6 +37,19 @@
   file << "# Generated by GN. Do not edit.\n\n";
   file << "{\n";
   file << "  'skip_includes': 1,\n";
+
+  if (targets[0].debug->settings()->IsMac()) {
+    // Global settings for make/ninja. This must match common.gypi :(
+    file << "  'make_global_settings': [\n";
+    file << "    ['CC', 'third_party/llvm-build/Release+Asserts/bin/clang'],\n";
+    file <<
+        "    ['CXX', 'third_party/llvm-build/Release+Asserts/bin/clang++'],\n";
+    file << "    ['CC.host', '$(CC)'],\n";
+    file << "    ['CXX.host', '$(CXX)'],\n";
+    file << "  ],\n";
+  }
+  // TODO(brettw) android.
+
   file << "  'targets': [\n";
 
   for (size_t i = 0; i < targets.size(); i++) {
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index aefb513..85dd0cd 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -95,8 +95,6 @@
 }
 
 void NinjaBinaryTargetWriter::Run() {
-  WriteEnvironment();
-
   WriteCompilerVars();
 
   std::vector<OutputFile> obj_files;
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
index f57bb19..0bf4722 100644
--- a/tools/gn/ninja_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -1,89 +1,87 @@
-// Copyright (c) 2013 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 <sstream>

-

-#include "testing/gtest/include/gtest/gtest.h"

-#include "tools/gn/ninja_binary_target_writer.h"

-#include "tools/gn/test_with_scope.h"

-

-TEST(NinjaBinaryTargetWriter, SourceSet) {

-  TestWithScope setup;

-  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));

-  setup.settings()->set_target_os(Settings::WIN);

-

-  Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));

-  target.set_output_type(Target::SOURCE_SET);

-  target.sources().push_back(SourceFile("//foo/input1.cc"));

-  target.sources().push_back(SourceFile("//foo/input2.cc"));

-  target.OnResolved();

-

-  // Source set itself.

-  {

-    std::ostringstream out;

-    NinjaBinaryTargetWriter writer(&target, out);

-    writer.Run();

-

-    // TODO(brettw) I think we'll need to worry about backslashes here

-    // depending if we're on actual Windows or Linux pretending to be Windows.

-    const char expected_win[] =

-        "arch = environment.x86\n"

-        "defines =\n"

-        "includes =\n"

-        "cflags =\n"

-        "cflags_c =\n"

-        "cflags_cc =\n"

-        "cflags_objc =\n"

-        "cflags_objcc =\n"

-        "\n"

-        "build obj/foo/bar.input1.obj: tc_cxx ../../foo/input1.cc\n"

-        "build obj/foo/bar.input2.obj: tc_cxx ../../foo/input2.cc\n"

-        "\n"

-        "build obj/foo/bar.stamp: tc_stamp obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n";

-    std::string out_str = out.str();

-#if defined(OS_WIN)

-    std::replace(out_str.begin(), out_str.end(), '\\', '/');

-#endif

-    EXPECT_EQ(expected_win, out_str);

-  }

-

-  // A shared library that depends on the source set.

-  Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));

-  shlib_target.set_output_type(Target::SHARED_LIBRARY);

-  shlib_target.deps().push_back(&target);

-  shlib_target.OnResolved();

-

-  {

-    std::ostringstream out;

-    NinjaBinaryTargetWriter writer(&shlib_target, out);

-    writer.Run();

-

-    // TODO(brettw) I think we'll need to worry about backslashes here

-    // depending if we're on actual Windows or Linux pretending to be Windows.

-    const char expected_win[] =

-        "arch = environment.x86\n"

-        "defines =\n"

-        "includes =\n"

-        "cflags =\n"

-        "cflags_c =\n"

-        "cflags_cc =\n"

-        "cflags_objc =\n"

-        "cflags_objcc =\n"

-        "\n"

-        "\n"

-        "manifests = obj/foo/shlib.intermediate.manifest\n"

-        "ldflags = /MANIFEST /ManifestFile:obj/foo/shlib.intermediate.manifest\n"

-        "libs =\n"

-        "build shlib.dll shlib.dll.lib: tc_solink obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n"

-        "  soname = shlib.dll\n"

-        "  lib = shlib.dll\n"

-        "  dll = shlib.dll\n"

-        "  implibflag = /IMPLIB:shlib.dll.lib\n\n";

-    std::string out_str = out.str();

-#if defined(OS_WIN)

-    std::replace(out_str.begin(), out_str.end(), '\\', '/');

-#endif

-    EXPECT_EQ(expected_win, out_str);

-  }

-}

+// Copyright (c) 2013 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 <sstream>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/ninja_binary_target_writer.h"
+#include "tools/gn/test_with_scope.h"
+
+TEST(NinjaBinaryTargetWriter, SourceSet) {
+  TestWithScope setup;
+  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+  setup.settings()->set_target_os(Settings::WIN);
+
+  Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+  target.set_output_type(Target::SOURCE_SET);
+  target.sources().push_back(SourceFile("//foo/input1.cc"));
+  target.sources().push_back(SourceFile("//foo/input2.cc"));
+  target.OnResolved();
+
+  // Source set itself.
+  {
+    std::ostringstream out;
+    NinjaBinaryTargetWriter writer(&target, out);
+    writer.Run();
+
+    // TODO(brettw) I think we'll need to worry about backslashes here
+    // depending if we're on actual Windows or Linux pretending to be Windows.
+    const char expected_win[] =
+        "defines =\n"
+        "includes =\n"
+        "cflags =\n"
+        "cflags_c =\n"
+        "cflags_cc =\n"
+        "cflags_objc =\n"
+        "cflags_objcc =\n"
+        "\n"
+        "build obj/foo/bar.input1.obj: tc_cxx ../../foo/input1.cc\n"
+        "build obj/foo/bar.input2.obj: tc_cxx ../../foo/input2.cc\n"
+        "\n"
+        "build obj/foo/bar.stamp: tc_stamp obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n";
+    std::string out_str = out.str();
+#if defined(OS_WIN)
+    std::replace(out_str.begin(), out_str.end(), '\\', '/');
+#endif
+    EXPECT_EQ(expected_win, out_str);
+  }
+
+  // A shared library that depends on the source set.
+  Target shlib_target(setup.settings(), Label(SourceDir("//foo/"), "shlib"));
+  shlib_target.set_output_type(Target::SHARED_LIBRARY);
+  shlib_target.deps().push_back(&target);
+  shlib_target.OnResolved();
+
+  {
+    std::ostringstream out;
+    NinjaBinaryTargetWriter writer(&shlib_target, out);
+    writer.Run();
+
+    // TODO(brettw) I think we'll need to worry about backslashes here
+    // depending if we're on actual Windows or Linux pretending to be Windows.
+    const char expected_win[] =
+        "defines =\n"
+        "includes =\n"
+        "cflags =\n"
+        "cflags_c =\n"
+        "cflags_cc =\n"
+        "cflags_objc =\n"
+        "cflags_objcc =\n"
+        "\n"
+        "\n"
+        "manifests = obj/foo/shlib.intermediate.manifest\n"
+        "ldflags = /MANIFEST /ManifestFile:obj/foo/shlib.intermediate.manifest\n"
+        "libs =\n"
+        "build shlib.dll shlib.dll.lib: tc_solink obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n"
+        "  soname = shlib.dll\n"
+        "  lib = shlib.dll\n"
+        "  dll = shlib.dll\n"
+        "  implibflag = /IMPLIB:shlib.dll.lib\n\n";
+    std::string out_str = out.str();
+#if defined(OS_WIN)
+    std::replace(out_str.begin(), out_str.end(), '\\', '/');
+#endif
+    EXPECT_EQ(expected_win, out_str);
+  }
+}
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index a6d6485..b7cfdd7 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -51,6 +51,12 @@
 
   EscapeOptions escape_shell;
   escape_shell.mode = ESCAPE_SHELL;
+#if defined(OS_WIN)
+  // The command line code quoting varies by platform. We have one string,
+  // possibly with spaces, that we want to quote. The Windows command line
+  // quotes again, so we don't want quoting. The Posix one doesn't.
+  escape_shell.inhibit_quoting = true;
+#endif
 
   const CommandLine& our_cmdline = *CommandLine::ForCurrentProcess();
   const CommandLine::SwitchMap& switches = our_cmdline.GetSwitches();
diff --git a/tools/gn/ninja_script_target_writer.cc b/tools/gn/ninja_script_target_writer.cc
index 4678ba0..1b8358c 100644
--- a/tools/gn/ninja_script_target_writer.cc
+++ b/tools/gn/ninja_script_target_writer.cc
@@ -22,8 +22,6 @@
 }
 
 void NinjaScriptTargetWriter::Run() {
-  WriteEnvironment();
-
   FileTemplate args_template(target_->script_values().args());
   std::string custom_rule_name = WriteRuleDefinition(args_template);
   std::string implicit_deps = GetSourcesImplicitDeps();
@@ -77,7 +75,11 @@
     out_ << "rule " << custom_rule_name << std::endl;
     out_ << "  command = ";
     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
-    out_ << " gyp-win-tool action-wrapper $arch " << rspfile << std::endl;
+    // TODO(brettw) this hardcodes "environment.x86" which is something that
+    // the Chrome Windows toolchain writes. We should have a way to invoke
+    // python without requiring this gyp_win_tool thing.
+    out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
+         << std::endl;
     out_ << "  description = CUSTOM " << target_label << std::endl;
     out_ << "  restat = 1" << std::endl;
     out_ << "  rspfile = " << rspfile << std::endl;
@@ -92,10 +94,9 @@
   } else {
     // Posix can execute Python directly.
     out_ << "rule " << custom_rule_name << std::endl;
-    out_ << "  command = cd ";
-    path_output_.WriteDir(out_, target_->label().dir(),
-                          PathOutput::DIR_NO_LAST_SLASH);
-    out_ << "; $pythonpath ";
+    out_ << "  command = ";
+    path_output_.WriteFile(out_, settings_->build_settings()->python_path());
+    out_ << " ";
     path_output_.WriteFile(out_, target_->script_values().script());
     args_template.WriteWithNinjaExpansions(out_);
     out_ << std::endl;
@@ -133,7 +134,7 @@
     out_ << "build";
     WriteOutputFilesForBuildLine(output_template, sources[i], output_files);
 
-    out_ << ": " << custom_rule_name;
+    out_ << ": " << custom_rule_name << " ";
     path_output_.WriteFile(out_, sources[i]);
     out_ << implicit_deps << std::endl;
 
diff --git a/tools/gn/ninja_script_target_writer_unittest.cc b/tools/gn/ninja_script_target_writer_unittest.cc
index 2057f07..1394717 100644
--- a/tools/gn/ninja_script_target_writer_unittest.cc
+++ b/tools/gn/ninja_script_target_writer_unittest.cc
@@ -84,6 +84,8 @@
   // Posix.
   {
     setup.settings()->set_target_os(Settings::LINUX);
+    setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
+        "/usr/bin/python")));
 
     std::ostringstream out;
     NinjaScriptTargetWriter writer(&target, out);
@@ -91,14 +93,17 @@
 
     const char expected_linux[] =
         "rule __foo_bar___rule\n"
-        "  command = cd ../../foo; $pythonpath ../../foo/script.py -i ${source} \"--out=foo$ bar${source_name_part}.o\"\n"
+        "  command = /usr/bin/python ../../foo/script.py -i ${source} "
+            "\"--out=foo$ bar${source_name_part}.o\"\n"
         "  description = CUSTOM //foo:bar()\n"
         "  restat = 1\n"
         "\n"
-        "build input1.out: __foo_bar___rule../../foo/input1.txt | ../../foo/included.txt\n"
+        "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
+            "../../foo/included.txt\n"
         "  source = ../../foo/input1.txt\n"
         "  source_name_part = input1\n"
-        "build input2.out: __foo_bar___rule../../foo/input2.txt | ../../foo/included.txt\n"
+        "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
+            "../../foo/included.txt\n"
         "  source = ../../foo/input2.txt\n"
         "  source_name_part = input2\n"
         "\n"
@@ -126,19 +131,22 @@
     // TODO(brettw) I think we'll need to worry about backslashes here
     // depending if we're on actual Windows or Linux pretending to be Windows.
     const char expected_win[] =
-        "arch = environment.x86\n"
         "rule __foo_bar___rule\n"
-        "  command = C:/python/python.exe gyp-win-tool action-wrapper $arch __foo_bar___rule.$unique_name.rsp\n"
+        "  command = C:/python/python.exe gyp-win-tool action-wrapper "
+            "environment.x86 __foo_bar___rule.$unique_name.rsp\n"
         "  description = CUSTOM //foo:bar()\n"
         "  restat = 1\n"
         "  rspfile = __foo_bar___rule.$unique_name.rsp\n"
-        "  rspfile_content = C:/python/python.exe ../../foo/script.py -i ${source} \"--out=foo$ bar${source_name_part}.o\"\n"
+        "  rspfile_content = C:/python/python.exe ../../foo/script.py -i "
+            "${source} \"--out=foo$ bar${source_name_part}.o\"\n"
         "\n"
-        "build input1.out: __foo_bar___rule../../foo/input1.txt | ../../foo/included.txt\n"
+        "build input1.out: __foo_bar___rule ../../foo/input1.txt | "
+            "../../foo/included.txt\n"
         "  unique_name = 0\n"
         "  source = ../../foo/input1.txt\n"
         "  source_name_part = input1\n"
-        "build input2.out: __foo_bar___rule../../foo/input2.txt | ../../foo/included.txt\n"
+        "build input2.out: __foo_bar___rule ../../foo/input2.txt | "
+            "../../foo/included.txt\n"
         "  unique_name = 1\n"
         "  source = ../../foo/input2.txt\n"
         "  source_name_part = input2\n"
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 4bbc1f5..a7bd6cc 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -85,12 +85,6 @@
                        static_cast<int>(contents.size()));
 }
 
-void NinjaTargetWriter::WriteEnvironment() {
-  // TODO(brettw) have a better way to do the environment setup on Windows.
-  if (target_->settings()->IsWin())
-    out_ << "arch = environment.x86\n";
-}
-
 const Toolchain* NinjaTargetWriter::GetToolchain() const {
   return target_->settings()->toolchain();
 }
diff --git a/tools/gn/ninja_target_writer.h b/tools/gn/ninja_target_writer.h
index 9e6f240..c9c72a7 100644
--- a/tools/gn/ninja_target_writer.h
+++ b/tools/gn/ninja_target_writer.h
@@ -27,8 +27,6 @@
   virtual void Run() = 0;
 
  protected:
-  void WriteEnvironment();
-
   // Returns the toolchain associated with the target.
   const Toolchain* GetToolchain() const;
 
diff --git a/tools/gn/secondary/BUILD.gn b/tools/gn/secondary/BUILD.gn
index 71c63f0..7a4f786 100644
--- a/tools/gn/secondary/BUILD.gn
+++ b/tools/gn/secondary/BUILD.gn
@@ -9,6 +9,7 @@
     "//base(//build/toolchain/nacl:x86_newlib)",
     "//chrome",
     "//crypto",
+    "//device/usb:device_usb",
     "//ipc",
     "//net",
     "//net/third_party/nss:ssl",
@@ -16,7 +17,7 @@
     "//third_party/icu:icudata",
     "//third_party/leveldatabase",
     "//third_party/zlib",
-    "//third_party/WebKit/Source/wtf",
+    "//third_party/WebKit/Source/weborigin",
     "//skia",
     "//tools/gn",
     "//url",
diff --git a/tools/gn/secondary/build/config/BUILDCONFIG.gn b/tools/gn/secondary/build/config/BUILDCONFIG.gn
index 1ae5e55..99e1e91 100644
--- a/tools/gn/secondary/build/config/BUILDCONFIG.gn
+++ b/tools/gn/secondary/build/config/BUILDCONFIG.gn
@@ -34,10 +34,13 @@
   is_clang = false
 
   # ASH is enabled.
+  # TODO(brettw) this should be moved out of the main build config file.
   use_ash = false
   # Aura is enabled.
+  # TODO(brettw) this should be moved out of the main build config file.
   use_aura = false
   # Ozone is enabled.
+  # TODO(brettw) this should be moved out of the main build config file.
   use_ozone = false
 }
 
@@ -76,6 +79,7 @@
   is_nacl = false
   is_posix = true
   is_win = false
+  is_clang = true  # Always use clang on Mac.
 } else if (os == "android") {
   is_android = false
   is_chromeos = false
diff --git a/tools/gn/secondary/build/config/compiler/BUILD.gn b/tools/gn/secondary/build/config/compiler/BUILD.gn
index 6174b2e..ef9d61f 100644
--- a/tools/gn/secondary/build/config/compiler/BUILD.gn
+++ b/tools/gn/secondary/build/config/compiler/BUILD.gn
@@ -116,9 +116,7 @@
 
     # Clang-specific compiler flags setup.
     # ------------------------------------
-    # TODO(brettw) these should be clang-only. For now, make it mac-only since
-    # that's where we always use clang.
-    if (is_mac) { # if (is_clang) {
+    if (is_clang) {
       cflags += [
         "-fcolor-diagnostics",
       ]
@@ -301,7 +299,7 @@
 
     # TODO(brettw) Ones below here should be clang-only when we have a flag
     # for it.
-    if (is_mac) { #if (is_clang) {
+    if (is_clang) {
       cflags += [
         "-Wheader-hygiene",
 
diff --git a/tools/gn/secondary/build/config/win/BUILD.gn b/tools/gn/secondary/build/config/win/BUILD.gn
index efdc5ab..e101c2b 100644
--- a/tools/gn/secondary/build/config/win/BUILD.gn
+++ b/tools/gn/secondary/build/config/win/BUILD.gn
@@ -3,7 +3,12 @@
 # found in the LICENSE file.
 
 declare_args() {
+  # Full path to the Windows SDK, not including a backslash at the end.
   windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.0"
+
+  # Full path to the Visual Studio installation, not including a backslash
+  # at the end.
+  visual_studio_path = "C:\Program Files (x86)\Microsoft Visual Studio 10.0"
 }
 
 # Compiler setup for the Windows SDK. Applied to all targets.
@@ -25,10 +30,15 @@
     "WINVER=0x0602",
   ]
 
+  # The Windows SDK include directories must be first. They both have a sal.h,
+  # and the SDK one is newer and the SDK uses some newer features from it not
+  # present in the Visual Studio one.
   include_dirs = [
     "$windows_sdk_path\Include\shared",
     "$windows_sdk_path\Include\um",
     "$windows_sdk_path\Include\winrt",
+    "$visual_studio_path\VC\include",
+    "$visual_studio_path\VC\atlmfc\include",
   ]
 }
 
@@ -39,14 +49,21 @@
 
   if (is_64bit) {
     ldflags = [ "/MACHINE:X64" ]
-    libs = [ "$windows_sdk_path\Lib\win8\um\x64" ]
+    lib_dirs = [
+      "$windows_sdk_path\Lib\win8\um\x64",
+      "$visual_studio_path\VC\lib\amd64",
+      "$visual_studio_path\VC\atlmfc\lib\amd64",
+    ]
   } else {
     ldflags = [
       "/MACHINE:X86",
       "/SAFESEH",  # Not compatible with x64 so use only for x86.
     ]
-    lib_dirs = [ "$windows_sdk_path\Lib\win8\um\x86" ]
-
+    lib_dirs = [
+      "$windows_sdk_path\Lib\win8\um\x86",
+      "$visual_studio_path\VC\lib",
+      "$visual_studio_path\VC\atlmfc\lib",
+    ]
     #if (!is_asan) {  TODO(brettw) Address Sanitizer
     #  ldflags += "/largeaddressaware"
     #}
diff --git a/tools/gn/secondary/build/toolchain/mac/BUILD.gn b/tools/gn/secondary/build/toolchain/mac/BUILD.gn
index 2752d5a..b8a3c5e 100644
--- a/tools/gn/secondary/build/toolchain/mac/BUILD.gn
+++ b/tools/gn/secondary/build/toolchain/mac/BUILD.gn
@@ -2,10 +2,19 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# Should only be running on Mac.
+assert(is_mac)
+
 cc = rebase_path("//third_party/llvm-build/Release+Asserts/bin/clang", ".", root_build_dir)
 cxx = rebase_path("//third_party/llvm-build/Release+Asserts/bin/clang++", ".", root_build_dir)
 ld = cxx
 
+# This will copy the gyp-mac-tool to the build directory. We pass in the source
+# file of the win tool.
+gyp_mac_tool_source =
+  rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", ".", root_build_dir)
+exec_script("setup_toolchain.py", [ gyp_mac_tool_source ], "value")
+
 toolchain("clang") {
   # Make these apply to all tools below.
   lib_prefix = "-l"
diff --git a/tools/gn/secondary/build/toolchain/mac/setup_toolchain.py b/tools/gn/secondary/build/toolchain/mac/setup_toolchain.py
new file mode 100644
index 0000000..431078f
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/mac/setup_toolchain.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import stat
+import sys
+
+def CopyTool(source_path):
+  """Copies the given tool to the current directory, including a warning not
+  to edit it."""
+  with open(source_path) as source_file:
+    tool_source = source_file.readlines()
+
+  # Add header and write it out to the current directory (which should be the
+  # root build dir).
+  out_path = 'gyp-mac-tool'
+  with open(out_path, 'w') as tool_file:
+    tool_file.write(''.join([tool_source[0],
+                             '# Generated by setup_toolchain.py do not edit.\n']
+                            + tool_source[1:]))
+  st = os.stat(out_path)
+  os.chmod(out_path, st.st_mode | stat.S_IEXEC)
+
+# Find the tool source, it's the first argument, and copy it.
+if len(sys.argv) != 2:
+  print "Need one argument (mac_tool source path)."
+  sys.exit(1)
+CopyTool(sys.argv[1])
diff --git a/tools/gn/secondary/build/toolchain/win/BUILD.gn b/tools/gn/secondary/build/toolchain/win/BUILD.gn
index 5887b92..95cd947 100644
--- a/tools/gn/secondary/build/toolchain/win/BUILD.gn
+++ b/tools/gn/secondary/build/toolchain/win/BUILD.gn
@@ -13,11 +13,16 @@
 #
 # The list contains the include path as its only element. (I'm expecting to
 # add more so it's currently a list inside a list.)
-msvc_config = [["foo"]]
 #exec_script("get_msvc_config.py",
                      #     [relative_root_output_dir],
                      #     "value")
 
+# This will save the environment block and and copy the gyp-win-tool to the
+# build directory. We pass in the source file of the win tool.
+gyp_win_tool_source =
+  rebase_path("//tools/gyp/pylib/gyp/win_tool.py", ".", root_build_dir)
+exec_script("setup_toolchain.py", [ gyp_win_tool_source ], "value")
+
 # 32-bit toolchain -------------------------------------------------------------
 
 toolchain("32") {
@@ -26,47 +31,47 @@
   lib_dir_prefix="/LIBPATH:"
 
   tool("cc") {
-    command = "ninja -t msvc -e \$arch -- cl.exe /nologo /showIncludes /FC @\$out.rsp /c \$in /Fo\$out /Fd\$pdbname"
+    command = "ninja -t msvc -e environment.x86 -- cl.exe /nologo /showIncludes /FC @\$out.rsp /c \$in /Fo\$out /Fd\$pdbname"
     description = "CC \$out"
     rspfile = "\$out.rsp"
     rspfile_content = "\$defines \$includes \$cflags \$cflags_c"
     deps = "msvc"
   }
   tool("cxx") {
-    command = "ninja -t msvc -e \$arch -- cl.exe /nologo /showIncludes /FC @\$out.rsp /c \$in /Fo\$out /Fd\$pdbname"
+    command = "ninja -t msvc -e environment.x86 -- cl.exe /nologo /showIncludes /FC @\$out.rsp /c \$in /Fo\$out /Fd\$pdbname"
     description = "CXX \$out"
     rspfile = "\$out.rsp"
     rspfile_content = "\$defines \$includes \$cflags \$cflags_cc"
     deps = "msvc"
   }
   #tool("idl") {
-  #  command = $python_path gyp-win-tool midl-wrapper \$arch \$outdir \$tlb \$h \$dlldata \$iid \$
+  #  command = $python_path gyp-win-tool midl-wrapper environment.x86 \$outdir \$tlb \$h \$dlldata \$iid \$
   #      \$proxy \$in \$idlflags
   #  description = IDL \$in
   #}
   tool("rc") {
-    command = "$python_path gyp-win-tool rc-wrapper \$arch rc.exe \$defines \$includes \$rcflags /fo\$out \$in"
+    command = "$python_path gyp-win-tool rc-wrapper environment.x86 rc.exe \$defines \$includes \$rcflags /fo\$out \$in"
     description = "RC \$in"
   }
   #tool("asm") {
-  #  command = $python_path gyp-win-tool asm-wrapper \$arch ml.exe \$defines \$includes /c /Fo \$
+  #  command = $python_path gyp-win-tool asm-wrapper environment.x86 ml.exe \$defines \$includes /c /Fo \$
   #      \$out \$in
   #  description = ASM \$in
   #}
   tool("alink") {
-    command = "$python_path gyp-win-tool link-wrapper \$arch lib.exe /nologo /ignore:4221 /OUT:\$out @\$out.rsp"
+    command = "$python_path gyp-win-tool link-wrapper environment.x86 lib.exe /nologo /ignore:4221 /OUT:\$out @\$out.rsp"
     description = "LIB \$out"
     rspfile = "\$out.rsp"
     rspfile_content = "\$in_newline \$libflags"
   }
   #tool("solink_embed_inc") {
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$implibflag \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$implibflag \$
   #      /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch cmd /c if exist \$dll.manifest del \$dll.manifest && \$
-  #      $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests \$
-  #      -out:\$dll.manifest && $python_path gyp-win-tool manifest-to-rc \$arch \$dll.manifest \$
-  #      \$dll.manifest.rc 2 && $python_path gyp-win-tool rc-wrapper \$arch rc.exe \$
-  #      \$dll.manifest.rc && $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$
+  #      manifest-wrapper environment.x86 cmd /c if exist \$dll.manifest del \$dll.manifest && \$
+  #      $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests \$
+  #      -out:\$dll.manifest && $python_path gyp-win-tool manifest-to-rc environment.x86 \$dll.manifest \$
+  #      \$dll.manifest.rc 2 && $python_path gyp-win-tool rc-wrapper environment.x86 rc.exe \$
+  #      \$dll.manifest.rc && $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$
   #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res
   #  description = LINK_EMBED_INC(DLL) \$dll
   #  restat = 1
@@ -74,13 +79,13 @@
   #  rspfile_content = \$libs \$in_newline \$ldflags
   #}
   #tool("solink_module_embed_inc") {
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$implibflag \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$implibflag \$
   #      /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch cmd /c if exist \$dll.manifest del \$dll.manifest && \$
-  #      $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests \$
-  #      -out:\$dll.manifest && $python_path gyp-win-tool manifest-to-rc \$arch \$dll.manifest \$
-  #      \$dll.manifest.rc 2 && $python_path gyp-win-tool rc-wrapper \$arch rc.exe \$
-  #      \$dll.manifest.rc && $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$
+  #      manifest-wrapper environment.x86 cmd /c if exist \$dll.manifest del \$dll.manifest && \$
+  #      $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests \$
+  #      -out:\$dll.manifest && $python_path gyp-win-tool manifest-to-rc environment.x86 \$dll.manifest \$
+  #      \$dll.manifest.rc 2 && $python_path gyp-win-tool rc-wrapper environment.x86 rc.exe \$
+  #      \$dll.manifest.rc && $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$
   #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res
   #  description = LINK_EMBED_INC(DLL) \$dll
   #  restat = 1
@@ -88,54 +93,54 @@
   #  rspfile_content = \$libs \$in_newline \$ldflags
   #}
   #rule link_embed_inc
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo /OUT:\$out \$
-  #      /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper \$arch cmd /c \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo /OUT:\$out \$
+  #      /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper environment.x86 cmd /c \$
   #      if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests -out:\$out.manifest && \$
-  #      $python_path gyp-win-tool manifest-to-rc \$arch \$out.manifest \$out.manifest.rc 1 && \$
-  #      $python_path gyp-win-tool rc-wrapper \$arch rc.exe \$out.manifest.rc && \$
-  #      $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo /OUT:\$out /PDB:\$out.pdb \$
+  #      manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests -out:\$out.manifest && \$
+  #      $python_path gyp-win-tool manifest-to-rc environment.x86 \$out.manifest \$out.manifest.rc 1 && \$
+  #      $python_path gyp-win-tool rc-wrapper environment.x86 rc.exe \$out.manifest.rc && \$
+  #      $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo /OUT:\$out /PDB:\$out.pdb \$
   #      @\$out.rsp \$out.manifest.res
   #  description = LINK_EMBED_INC \$out
   #  rspfile = \$out.rsp
   #  rspfile_content = \$in_newline \$libs \$ldflags
   #rule solink_embed
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$implibflag \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$implibflag \$
   #      /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch cmd /c if exist \$dll.manifest del \$dll.manifest && \$
-  #      $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests \$
+  #      manifest-wrapper environment.x86 cmd /c if exist \$dll.manifest del \$dll.manifest && \$
+  #      $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests \$
   #      -outputresource:\$dll;2
   #  description = LINK_EMBED(DLL) \$dll
   #  restat = 1
   #  rspfile = \$dll.rsp
   #  rspfile_content = \$libs \$in_newline \$ldflags
   #rule solink_module_embed
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$implibflag \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$implibflag \$
   #      /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch cmd /c if exist \$dll.manifest del \$dll.manifest && \$
-  #      $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests \$
+  #      manifest-wrapper environment.x86 cmd /c if exist \$dll.manifest del \$dll.manifest && \$
+  #      $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests \$
   #      -outputresource:\$dll;2
   #  description = LINK_EMBED(DLL) \$dll
   #  restat = 1
   #  rspfile = \$dll.rsp
   #  rspfile_content = \$libs \$in_newline \$ldflags
   #rule link_embed
-  #  command = cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo /OUT:\$out \$
-  #      /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper \$arch cmd /c \$
+  #  command = cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo /OUT:\$out \$
+  #      /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper environment.x86 cmd /c \$
   #      if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool \$
-  #      manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests -outputresource:\$out;1
+  #      manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests -outputresource:\$out;1
   #  description = LINK_EMBED \$out
   #  rspfile = \$out.rsp
   #  rspfile_content = \$in_newline \$libs \$ldflags
   tool("solink") {
-    command = "cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool manifest-wrapper \$arch cmd /c if exist \$dll.manifest del \$dll.manifest && $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests -out:\$dll.manifest"
+    command = "cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp && $python_path gyp-win-tool manifest-wrapper environment.x86 cmd /c if exist \$dll.manifest del \$dll.manifest && $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests -out:\$dll.manifest"
     description = "LINK(DLL) \$dll"
     restat = "1"
     rspfile = "\$dll.rsp"
     rspfile_content = "\$libs \$in_newline \$ldflags"
   }
   tool("link") {
-    command = "cmd /c $python_path gyp-win-tool link-wrapper \$arch link.exe /nologo /OUT:\$out /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper \$arch cmd /c if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool manifest-wrapper \$arch mt.exe -nologo -manifest \$manifests -out:\$out.manifest"
+    command = "cmd /c $python_path gyp-win-tool link-wrapper environment.x86 link.exe /nologo /OUT:\$out /PDB:\$out.pdb @\$out.rsp && $python_path gyp-win-tool manifest-wrapper environment.x86 cmd /c if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool manifest-wrapper environment.x86 mt.exe -nologo -manifest \$manifests -out:\$out.manifest"
     description = "LINK \$out"
     rspfile = "\$out.rsp"
     rspfile_content = "\$in_newline \$libs \$ldflags"
diff --git a/tools/gn/secondary/build/toolchain/win/setup_toolchain.py b/tools/gn/secondary/build/toolchain/win/setup_toolchain.py
new file mode 100644
index 0000000..bba18df
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/win/setup_toolchain.py
@@ -0,0 +1,72 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import sys
+
+def ExtractImportantEnvironment():
+  """Extracts environment variables required for the toolchain from the
+  current environment."""
+  envvars_to_save = (
+      'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
+      'Path',
+      'PATHEXT',
+      'SystemRoot',
+      'TEMP',
+      'TMP',
+      )
+  result = {}
+  for envvar in envvars_to_save:
+    if envvar in os.environ:
+      if envvar == 'Path':
+        # Our own rules (for running gyp-win-tool) and other actions in
+        # Chromium rely on python being in the path. Add the path to this
+        # python here so that if it's not in the path when ninja is run
+        # later, python will still be found.
+        result[envvar.upper()] = os.path.dirname(sys.executable) + \
+            os.pathsep + os.environ[envvar]
+      else:
+        result[envvar.upper()] = os.environ[envvar]
+  for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
+    if required not in result:
+      raise Exception('Environment variable "%s" '
+                      'required to be set to valid path' % required)
+  return result
+
+def FormatAsEnvironmentBlock(envvar_dict):
+  """Format as an 'environment block' directly suitable for CreateProcess.
+  Briefly this is a list of key=value\0, terminated by an additional \0. See
+  CreateProcess documentation for more details."""
+  block = ''
+  nul = '\0'
+  for key, value in envvar_dict.iteritems():
+    block += key + '=' + value + nul
+  block += nul
+  return block
+
+def CopyTool(source_path):
+  """Copies the given tool to the current directory, including a warning not
+  to edit it."""
+  with open(source_path) as source_file:
+    tool_source = source_file.readlines()
+
+  # Add header and write it out to the current directory (which should be the
+  # root build dir).
+  with open("gyp-win-tool", 'w') as tool_file:
+    tool_file.write(''.join([tool_source[0],
+                             '# Generated by setup_toolchain.py do not edit.\n']
+                            + tool_source[1:]))
+
+# Find the tool source, it's the first argument, and copy it.
+if len(sys.argv) != 2:
+  print "Need one argument (win_tool source path)."
+  sys.exit(1)
+CopyTool(sys.argv[1])
+
+# Write the environment file to the current directory.
+environ = FormatAsEnvironmentBlock(ExtractImportantEnvironment())
+with open('environment.x86', 'wb') as env_file:
+  env_file.write(environ)
+
diff --git a/tools/gn/secondary/device/usb/BUILD.gn b/tools/gn/secondary/device/usb/BUILD.gn
new file mode 100644
index 0000000..afe95dc
--- /dev/null
+++ b/tools/gn/secondary/device/usb/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.

+# Use of this source code is governed by a BSD-style license that can be

+# found in the LICENSE file.

+

+source_ids = "//third_party/usb_ids/usb.ids"

+generated_ids = "$target_gen_dir/usb_ids_gen.cc"

+

+static_library("device_usb") {

+  sources = [

+    "usb_ids.cc",

+    "usb_ids.h",

+    generated_ids,

+  ]

+  deps = [ ":device_usb_ids" ]

+}

+

+custom("device_usb_ids") {

+  script = "//tools/usb_ids/usb_ids.py"

+  source_prereqs = [ source_ids ]

+  outputs = [ generated_ids ]

+  args = [

+    "-i", rebase_path(source_ids, ".", root_build_dir),

+    "-o", rebase_path(generated_ids, ".", root_build_dir),

+  ]

+}

diff --git a/tools/gn/secondary/net/BUILD.gn b/tools/gn/secondary/net/BUILD.gn
index 4cf8eec..114da13 100644
--- a/tools/gn/secondary/net/BUILD.gn
+++ b/tools/gn/secondary/net/BUILD.gn
@@ -252,6 +252,8 @@
     "cert/x509_certificate_win.cc",
     "cert/x509_util.h",
     "cert/x509_util.cc",
+    "cert/x509_util_android.cc",
+    "cert/x509_util_android.h",
     "cert/x509_util_ios.cc",
     "cert/x509_util_ios.h",
     "cert/x509_util_mac.cc",
diff --git a/tools/gn/secondary/third_party/WebKit/Source/weborigin/BUILD.gn b/tools/gn/secondary/third_party/WebKit/Source/weborigin/BUILD.gn
new file mode 100644
index 0000000..64f8907
--- /dev/null
+++ b/tools/gn/secondary/third_party/WebKit/Source/weborigin/BUILD.gn
@@ -0,0 +1,69 @@
+# Copyright 2013 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.
+
+component("weborigin") {
+  sources = [
+    "DatabaseIdentifier.cpp",
+    "DatabaseIdentifier.h",
+    "KURL.cpp",
+    "KURL.h",
+    "KURLHash.h",
+    "KnownPorts.cpp",
+    "KnownPorts.h",
+    "OriginAccessEntry.cpp",
+    "OriginAccessEntry.h",
+    "ReferrerPolicy.h",
+    "SchemeRegistry.cpp",
+    "SchemeRegistry.h",
+    "SecurityOrigin.cpp",
+    "SecurityOrigin.h",
+    "SecurityOriginCache.h",
+    "SecurityOriginHash.h",
+    "SecurityPolicy.cpp",
+    "SecurityPolicy.h",
+    "WebOriginExport.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "../wtf:wtf-config"
+  ]
+
+  defines = [ "WEBORIGIN_IMPLEMENTATION=1" ]
+
+  deps = [
+    "//third_party/icu:icui18n",
+    "//third_party/icu:icuuc",
+    "//url",
+  ]
+}
+
+executable("weborigin_unittests") {
+  sources = [
+    "DatabaseIdentifierTest.cpp",
+    "KURLTest.cpp",
+    "SecurityOriginTest.cpp",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+     "../wtf:wtf-config"
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/icu:icu_config",
+  ]
+
+  deps = [
+    ":weborigin",
+    "../wtf:run_all_tests",
+  ]
+
+#  if (is_linux && use_tcmalloc) {
+#     deps += [
+#      "//base:base",
+#      "//base/allocator:allocator",
+#    ],
+#  }
+
+}
diff --git a/tools/gn/secondary/third_party/WebKit/Source/wtf/BUILD.gn b/tools/gn/secondary/third_party/WebKit/Source/wtf/BUILD.gn
index 4a3a6a9..da3f26e 100644
--- a/tools/gn/secondary/third_party/WebKit/Source/wtf/BUILD.gn
+++ b/tools/gn/secondary/third_party/WebKit/Source/wtf/BUILD.gn
@@ -6,7 +6,7 @@
   include_dirs = [ ".." ]
   if (is_win) {
     include_dirs += [ "os-win32" ]
-    defines += [
+    defines = [
       "__STD_C",
       "_CRT_SECURE_NO_DEPRECATE",
       "_SCL_SECURE_NO_DEPRECATE",
@@ -25,7 +25,7 @@
   if (is_linux) { # (gcc_version >= 46) {
     # Disable warnings about c++0x compatibility, as some names (such as
     # nullptr) conflict with upcoming c++0x types.
-    cflags_cc += [ "-Wno-c++0x-compat" ]
+    cflags_cc = [ "-Wno-c++0x-compat" ]
   }
 
 #  # Some warnings occur in WTF headers, so they must also be disabled
@@ -291,9 +291,9 @@
       "ThreadSpecificWin.cpp",
       "ThreadingWin.cpp",
     ]
-    include_dirs -= [
+#    include_dirs -= [
 #      "<(SHARED_INTERMEDIATE_DIR)/blink',
-    ]
+#    ]
   } else {
     sources += [
       "ThreadIdentifierDataPthreads.cpp",
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 7345b96..ea40ade 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -492,7 +492,13 @@
 const char kGypFile_HelpShort[] =
     "gyp_file: [file name] Name of GYP file to write to in GYP mode.";
 const char kGypFile_Help[] =
-    "gyp_file: Name of GYP file to write to in GYP mode.\n";
+    "gyp_file: Name of GYP file to write to in GYP mode.\n"
+    "\n"
+    "  See \"gn help gyp\" for an overview of how this works.\n"
+    "\n"
+    "  Tip: If all targets in a given BUILD.gn file should go in the same\n"
+    "  GYP file, just put gyp_file = \"foo\" at the top of the file and\n"
+    "  the variable will be in scope for all targets.\n";
 
 const char kHardDep[] = "hard_dep";
 const char kHardDep_HelpShort[] =
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index f02e9ec..29141fe 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -47,9 +47,6 @@
   "webkit/glue/resources/webkit_resources.grd": {
     "structures": [4700],
   },
-  "webkit/tools/test_shell/test_shell_resources.grd": {
-    "includes": [5000],
-  },
   "ui/resources/ui_resources.grd": {
     "structures": [5500],
   },
@@ -120,7 +117,7 @@
     "messages": [17500],
   },
   "webkit/glue/webkit_strings.grd": {
-    "messages": [18000],
+    "messages": [18500],
   },
 
   "chrome_frame/resources/chrome_frame_resources.grd": {
@@ -128,18 +125,11 @@
     "structures": [19500],
   },
 
- "ui/base/native_theme/resources/native_theme_resources.grd": {
-    "includes": [20000],
-  },
-
   "chrome/app/policy/policy_templates.grd": {
     "structures": [20500],
     "messages": [20510],
   },
 
-  "chrome/browser/autofill/autofill_resources.grd": {
-    "messages": [21000],
-  },
   "chrome/browser/resources/sync_internals_resources.grd": {
     "includes": [21500],
   },
@@ -147,15 +137,12 @@
     "includes": [21750],
   },
   # This file is generated during the build.
-  # devtools_resources.grd can be in two different places depending on whether
-  # we are in a chromium checkout or a webkit-only checkout.
   "<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd": {
     "includes": [22000],
   },
   "devtools_resources.grd": {
     "includes": [22000],
   },
-  # This file is generated during the build.
   "chrome/browser/devtools/frontend/devtools_discovery_page_resources.grd": {
     "includes": [22500],
   },
@@ -193,9 +180,6 @@
   "chrome/common/extensions_api_resources.grd": {
     "includes": [26500],
   },
-  "third_party/trace-viewer/src/tracing.grd": {
-    "includes": [27000],
-  },
   "chrome/browser/resources/memory_internals_resources.grd": {
     "includes": [27500],
   },
diff --git a/tools/heapcheck/chrome_tests.py b/tools/heapcheck/chrome_tests.py
index 60e8987..527bcc5 100755
--- a/tools/heapcheck/chrome_tests.py
+++ b/tools/heapcheck/chrome_tests.py
@@ -489,8 +489,10 @@
   options, args = parser.parse_args()
 
   # Bake target into build_dir.
-  assert not options.build_dir.endswith(options.target)
-  options.build_dir = os.path.join(os.path.abspath(options.build_dir),
+  if options.target and options.build_dir:
+    assert (options.target !=
+            os.path.basename(os.path.dirname(options.build_dir)))
+    options.build_dir = os.path.join(os.path.abspath(options.build_dir),
                                    options.target)
 
   if options.verbose:
diff --git a/tools/heapcheck/suppressions.txt b/tools/heapcheck/suppressions.txt
index acc57c1..5fd982c 100644
--- a/tools/heapcheck/suppressions.txt
+++ b/tools/heapcheck/suppressions.txt
@@ -878,3 +878,25 @@
    fun:views::BubbleDelegateView::CreateBubble
    fun:TranslateBubbleViewTest::SetUp
 }
+{
+   bug_313238
+   Heapcheck:Leak
+   fun:??
+   fun:GtkThemeService::GtkThemeService
+   fun:ThemeServiceFactory::BuildServiceInstanceFor
+   fun:BrowserContextKeyedServiceFactory::GetServiceForBrowserContext
+   fun:_init
+   fun:BrowserContextDependencyManager::DoCreateBrowserContextServices
+   fun:BrowserContextDependencyManager::CreateBrowserContextServicesForTest
+   fun:TestingProfile::Init
+   fun:TestingProfile::TestingProfile
+   fun:AppKeepAliveServiceUnitTest::AppKeepAliveServiceUnitTest
+   fun:AppKeepAliveServiceUnitTest_Basic_Test::AppKeepAliveServiceUnitTest_Basic_Test
+   fun:testing::internal::TestFactoryImpl::CreateTest
+}
+{
+   bug_313521
+   Heapcheck:Leak
+   ...
+   fun:app_list::AppListModelTest_FolderItem_Test::TestBody
+}
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 9935e1c..371c60d 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -784,7 +784,9 @@
                                  self._type_helper.GetEnumNoneValue(type_)))
       .Concat(self._GenerateError(
         '\"\'%%(key)s\': expected \\"' +
-        '\\" or \\"'.join(self._type_helper.FollowRef(type_).enum_values) +
+        '\\" or \\"'.join(
+            enum_value.name
+            for enum_value in self._type_helper.FollowRef(type_).enum_values) +
         '\\", got \\"" + %s + "\\""' % enum_as_string))
       .Append('return %s;' % failure_value)
       .Eblock('}')
@@ -820,7 +822,7 @@
     c.Sblock('switch (enum_param) {')
     for enum_value in self._type_helper.FollowRef(type_).enum_values:
       (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value))
-        .Append('  return "%s";' % enum_value))
+        .Append('  return "%s";' % enum_value.name))
     (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_))
       .Append('  return "";')
       .Eblock('}')
@@ -848,7 +850,7 @@
       # This is broken up into all ifs with no else ifs because we get
       # "fatal error C1061: compiler limit : blocks nested too deeply"
       # on Windows.
-      (c.Append('if (enum_string == "%s")' % enum_value)
+      (c.Append('if (enum_string == "%s")' % enum_value.name)
         .Append('  return %s;' %
             self._type_helper.GetEnumValue(type_, enum_value)))
     (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_))
diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
index 4c0306d..d485b46 100644
--- a/tools/json_schema_compiler/cpp_type_generator.py
+++ b/tools/json_schema_compiler/cpp_type_generator.py
@@ -65,7 +65,7 @@
     e.g VAR_STRING
     """
     value = '%s_%s' % (self.FollowRef(type_).unix_name.upper(),
-                       cpp_util.Classname(enum_value.upper()))
+                       cpp_util.Classname(enum_value.name.upper()))
     # To avoid collisions with built-in OS_* preprocessor definitions, we add a
     # trailing slash to enum names that start with OS_.
     if value.startswith("OS_"):
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
index 44a4a55..238fb05 100644
--- a/tools/json_schema_compiler/idl_schema.py
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -292,7 +292,13 @@
     enum = []
     for node in self.node.children:
       if node.cls == 'EnumItem':
-        enum.append(node.GetName())
+        enum_value = {'name': node.GetName()}
+        for child in node.children:
+          if child.cls == 'Comment':
+            enum_value['description'] = ProcessComment(child.GetName())[0]
+          else:
+            raise ValueError('Did not process %s %s' % (child.cls, child))
+        enum.append(enum_value)
       elif node.cls == 'Comment':
         self.description = ProcessComment(node.GetName())[0]
       else:
@@ -313,10 +319,16 @@
   dictionary that the JSON schema compiler expects to see.
   '''
 
-  def __init__(self, namespace_node, description, nodoc=False, internal=False):
+  def __init__(self,
+               namespace_node,
+               description,
+               nodoc=False,
+               internal=False,
+               platforms=None):
     self.namespace = namespace_node
     self.nodoc = nodoc
     self.internal = internal
+    self.platforms = platforms
     self.events = []
     self.functions = []
     self.types = []
@@ -344,7 +356,8 @@
             'types': self.types,
             'functions': self.functions,
             'internal': self.internal,
-            'events': self.events}
+            'events': self.events,
+            'platforms': self.platforms}
 
   def process_interface(self, node):
     members = []
@@ -369,6 +382,7 @@
     nodoc = False
     internal = False
     description = None
+    platforms = None
     for node in self.idl:
       if node.cls == 'Namespace':
         if not description:
@@ -376,10 +390,11 @@
           print('%s must have a namespace-level comment. This will '
                            'appear on the API summary page.' % node.GetName())
           description = ''
-        namespace = Namespace(node, description, nodoc, internal)
+        namespace = Namespace(node, description, nodoc, internal, platforms)
         namespaces.append(namespace.process())
         nodoc = False
         internal = False
+        platforms = None
       elif node.cls == 'Copyright':
         continue
       elif node.cls == 'Comment':
@@ -389,6 +404,8 @@
           nodoc = bool(node.value)
         elif node.name == 'internal':
           internal = bool(node.value)
+        elif node.name == 'platforms':
+          platforms = list(node.value)
         else:
           continue
       else:
diff --git a/tools/json_schema_compiler/idl_schema_test.py b/tools/json_schema_compiler/idl_schema_test.py
index 1f5d7d6..0840058 100755
--- a/tools/json_schema_compiler/idl_schema_test.py
+++ b/tools/json_schema_compiler/idl_schema_test.py
@@ -77,7 +77,9 @@
 
   def testEnum(self):
     schema = self.idl_basics
-    expected = {'enum': ['name1', 'name2'], 'description': 'Enum description',
+    expected = {'enum': [{'name': 'name1', 'description': 'comment1'},
+                         {'name': 'name2'}],
+                'description': 'Enum description',
                 'type': 'string', 'id': 'EnumType'}
     self.assertEquals(expected, getType(schema, expected['id']))
 
@@ -108,6 +110,25 @@
     self.assertTrue(idl_basics['internal'])
     self.assertFalse(idl_basics['nodoc'])
 
+  def testChromeOSPlatformsNamespace(self):
+    schema = idl_schema.Load('test/idl_namespace_chromeos.idl')[0]
+    self.assertEquals('idl_namespace_chromeos', schema['namespace'])
+    expected = ['chromeos']
+    self.assertEquals(expected, schema['platforms'])
+
+  def testAllPlatformsNamespace(self):
+    schema = idl_schema.Load('test/idl_namespace_all_platforms.idl')[0]
+    self.assertEquals('idl_namespace_all_platforms', schema['namespace'])
+    expected = ['chromeos', 'chromeos_touch', 'linux', 'mac', 'win']
+    self.assertEquals(expected, schema['platforms'])
+
+  def testNonSpecificPlatformsNamespace(self):
+    schema = idl_schema.Load('test/idl_namespace_non_specific_platforms.idl')[0]
+    self.assertEquals('idl_namespace_non_specific_platforms',
+                      schema['namespace'])
+    expected = None
+    self.assertEquals(expected, schema['platforms'])
+
   def testCallbackComment(self):
     schema = self.idl_basics
     self.assertEquals('A comment on a callback.',
@@ -143,10 +164,12 @@
     schema = idl_schema.Load('test/idl_reserved_words.idl')[0]
 
     foo_type = getType(schema, 'Foo')
-    self.assertEquals(['float', 'DOMString'], foo_type['enum'])
+    self.assertEquals([{'name': 'float'}, {'name': 'DOMString'}],
+                      foo_type['enum'])
 
     enum_type = getType(schema, 'enum')
-    self.assertEquals(['callback', 'namespace'], enum_type['enum'])
+    self.assertEquals([{'name': 'callback'}, {'name': 'namespace'}],
+                      enum_type['enum'])
 
     dictionary = getType(schema, 'dictionary')
     self.assertEquals('integer', dictionary['properties']['long']['type'])
diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py
index cc876df..3de975c 100644
--- a/tools/json_schema_compiler/model.py
+++ b/tools/json_schema_compiler/model.py
@@ -141,7 +141,7 @@
       self.ref_type = json['$ref']
     elif 'enum' in json and json_type == 'string':
       self.property_type = PropertyType.ENUM
-      self.enum_values = [value for value in json['enum']]
+      self.enum_values = [EnumValue(value) for value in json['enum']]
     elif json_type == 'any':
       self.property_type = PropertyType.ANY
     elif json_type == 'binary':
@@ -343,6 +343,20 @@
 
   unix_name = property(GetUnixName, SetUnixName)
 
+class EnumValue(object):
+  """A single value from an enum.
+  Properties:
+  - |name| name of the property as in the json.
+  - |description| a description of the property (if provided)
+  """
+  def __init__(self, json):
+    if isinstance(json, dict):
+      self.name = json['name']
+      self.description = json.get('description')
+    else:
+      self.name = json
+      self.description = None
+
 class _Enum(object):
   """Superclass for enum types with a "name" field, setting up repr/eq/ne.
   Enums need to do this so that equality/non-equality work over pickling.
@@ -486,8 +500,11 @@
   WIN = _PlatformInfo("win")
 
 def _GetPlatforms(json):
-  if 'platforms' not in json:
+  if 'platforms' not in json or json['platforms'] == None:
     return None
+  # Sanity check: platforms should not be an empty list.
+  if not json['platforms']:
+    raise ValueError('"platforms" cannot be an empty list')
   platforms = []
   for platform_name in json['platforms']:
     for platform_enum in _Enum.GetAll(Platforms):
diff --git a/tools/json_schema_compiler/model_test.py b/tools/json_schema_compiler/model_test.py
index bdd2009..0e398a5 100755
--- a/tools/json_schema_compiler/model_test.py
+++ b/tools/json_schema_compiler/model_test.py
@@ -4,6 +4,8 @@
 # found in the LICENSE file.
 
 from json_schema import CachedLoad
+from idl_schema import Load
+from model import Platforms
 import model
 import unittest
 
@@ -22,9 +24,25 @@
     self.model.AddNamespace(self.tabs_json[0],
         'path/to/tabs.json')
     self.tabs = self.model.namespaces.get('tabs')
+    self.idl_chromeos = Load('test/idl_namespace_chromeos.idl')
+    self.model.AddNamespace(self.idl_chromeos[0],
+        'path/to/idl_namespace_chromeos.idl')
+    self.idl_namespace_chromeos = self.model.namespaces.get(
+        'idl_namespace_chromeos')
+    self.idl_all_platforms = Load('test/idl_namespace_all_platforms.idl')
+    self.model.AddNamespace(self.idl_all_platforms[0],
+        'path/to/idl_namespace_all_platforms.idl')
+    self.idl_namespace_all_platforms = self.model.namespaces.get(
+        'idl_namespace_all_platforms')
+    self.idl_non_specific_platforms = Load(
+        'test/idl_namespace_non_specific_platforms.idl')
+    self.model.AddNamespace(self.idl_non_specific_platforms[0],
+        'path/to/idl_namespace_non_specific_platforms.idl')
+    self.idl_namespace_non_specific_platforms = self.model.namespaces.get(
+        'idl_namespace_non_specific_platforms')
 
   def testNamespaces(self):
-    self.assertEquals(3, len(self.model.namespaces))
+    self.assertEquals(6, len(self.model.namespaces))
     self.assertTrue(self.permissions)
 
   def testHasFunctions(self):
@@ -100,6 +118,15 @@
     for name in expectations:
       self.assertEquals(expectations[name], model.UnixName(name))
 
+  def testPlatforms(self):
+    self.assertEqual([Platforms.CHROMEOS],
+                     self.idl_namespace_chromeos.platforms)
+    self.assertEqual(
+        [Platforms.CHROMEOS, Platforms.CHROMEOS_TOUCH, Platforms.LINUX,
+         Platforms.MAC, Platforms.WIN],
+        self.idl_namespace_all_platforms.platforms)
+    self.assertEqual(None,
+        self.idl_namespace_non_specific_platforms.platforms)
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/json_schema_compiler/test/idl_basics.idl b/tools/json_schema_compiler/test/idl_basics.idl
index 08d369c..05b09c5 100644
--- a/tools/json_schema_compiler/test/idl_basics.idl
+++ b/tools/json_schema_compiler/test/idl_basics.idl
@@ -7,6 +7,7 @@
 [internal] namespace idl_basics {
   // Enum description
   enum EnumType {
+    // comment1
     name1,
     name2
   };
diff --git a/tools/json_schema_compiler/test/idl_namespace_all_platforms.idl b/tools/json_schema_compiler/test/idl_namespace_all_platforms.idl
new file mode 100644
index 0000000..7ffd84a
--- /dev/null
+++ b/tools/json_schema_compiler/test/idl_namespace_all_platforms.idl
@@ -0,0 +1,10 @@
+// Copyright 2013 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.
+
+// Tests a variety of basic API definition features.
+
+[platforms=("chromeos", "chromeos_touch", "linux", "mac", "win")]
+namespace idl_namespace_all_platforms {
+
+};
diff --git a/tools/json_schema_compiler/test/idl_namespace_chromeos.idl b/tools/json_schema_compiler/test/idl_namespace_chromeos.idl
new file mode 100644
index 0000000..ad748ff
--- /dev/null
+++ b/tools/json_schema_compiler/test/idl_namespace_chromeos.idl
@@ -0,0 +1,10 @@
+// Copyright 2013 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.
+
+// Tests the case of a namespace with chromeos platforms.
+
+[platforms=("chromeos")]
+namespace idl_namespace_chromeos {
+
+};
diff --git a/tools/json_schema_compiler/test/idl_namespace_non_specific_platforms.idl b/tools/json_schema_compiler/test/idl_namespace_non_specific_platforms.idl
new file mode 100644
index 0000000..cff64f8
--- /dev/null
+++ b/tools/json_schema_compiler/test/idl_namespace_non_specific_platforms.idl
@@ -0,0 +1,9 @@
+// Copyright 2013 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.
+
+// Tests the case of a namespace with non specific platforms.
+
+namespace idl_namespace_non_specific_platforms {
+
+};
diff --git a/tools/lsan/suppressions.txt b/tools/lsan/suppressions.txt
index 00d3c04..f61bbda 100644
--- a/tools/lsan/suppressions.txt
+++ b/tools/lsan/suppressions.txt
@@ -15,6 +15,9 @@
 leak:net::(anonymous namespace)::InitResolver
 leak:net::ProxyResolverScriptData::FromUTF8
 
+# A small string is leaked here (57 bytes per process). http://crbug.com/46571#c9
+leak:WebCore::V8GCController::collectGarbage
+
 # http://crbug.com/270180
 leak:net::ProxyResolverV8::Context::ResolveProxy
 
@@ -64,5 +67,15 @@
 leak:GlobalMenuBar::GlobalMenuBar
 leak:BookmarkBubbleGtk::InitFolderComboModel
 leak:TranslateInfoBarBase::CreateLanguageCombobox
+leak:GtkNativeViewManager
+leak:_gdk_x11_window_get_toplevel
+leak:gtk_util::*AppModal
+
+# Infobar-related leaks in browser tests. Retriage them once
+# http://crbug.com/62154 is fixed.
+leak:chrome::ShowBadFlagsPrompt
+leak:TranslateInfoBarDelegate::Create
+leak:TranslateLanguageList::TranslateLanguageList
+leak:SimpleAlertInfoBarDelegate::Create
 
 # PLEASE DO NOT ADD NEW SUPPRESSIONS HERE. See the comment above.
diff --git a/tools/metrics/actions/chromeactions.txt b/tools/metrics/actions/chromeactions.txt
index 624cd51..7693832 100644
--- a/tools/metrics/actions/chromeactions.txt
+++ b/tools/metrics/actions/chromeactions.txt
@@ -160,6 +160,11 @@
 0xb4074307cbcb96bd	BadMessageTerminate_RWH3
 0xa00e08812a4284c2	BadMessageTerminate_RWH4
 0xefc9deffa33ee67d	BadMessageTerminate_RWH5
+0x5378a4f2a775cb88	BadMessageTerminate_RWHVA1
+0x3ceaa56d35b39da4	BadMessageTerminate_RWHVA2
+0x2996df71030ce814	BadMessageTerminate_SharedMemoryManager1
+0xf0a271d3e39e7deb	BadMessageTerminate_SharedMemoryManager2
+0xb22079c43bc5b72e	BadMessageTerminate_UnexpectedFrameType
 0xc4874f0e8e8b60aa	BadMessageTerminate_WPH
 0x56649dd19258ed1f	BindingsMismatchTerminate_RVH_WebUI
 0x85a700c6e9915ca8	BindingsMismatch_GetProcessHostPerSite
@@ -381,6 +386,7 @@
 0x4268aeb48d5c0d1e	FileBrowser.CreateNewFolder
 0x604a1468d08b7c7b	FileBrowser.PhotoEditor.Edit
 0xca74d47b273dd801	FileBrowser.PhotoEditor.View
+0xf94a9b198a97d95b	FileBrowser.SuggestApps.ShowDialog
 0xd1b4f6b656a826e8	FilterURLTermiate_About
 0x933a3a418a658dec	FilterURLTermiate_Blocked
 0x6a372395e62bd36e	FilterURLTermiate_Invalid
@@ -1099,6 +1105,9 @@
 0x470fb8fde85c094b	MobileContextMenuShareLink
 0xb177bc454b6a2105	MobileContextMenuText
 0xac284cf4338f8a66	MobileContextMenuViewImage
+0x145c1748b4db8fb5	MobileFocusedFakeboxOnNtp
+0x92ade4e05606fe2d	MobileFocusedOmniboxNotOnNtp
+0x5b1e74ed79deac48	MobileFocusedOmniboxOnNtp
 0xaa0f56a837e6fc61	MobileFreAttemptSignIn
 0xe18a359c1fcb3fbb	MobileFreSignInSuccessful
 0x1d68dcd4ec7fdadc	MobileFreSkipSignIn
@@ -1170,6 +1179,7 @@
 0x1b40c6b1b5dd7106	MostVisited9
 0x245e4aa9fe5a8a3c	MostVisitedReordered
 0x9c6a4ef293d946ca	MostVisited_BlacklistCleared
+0x110c33db0e4c6ebf	MostVisited_Clicked
 0x018c0ec301cb02ae	MostVisited_UrlBlacklisted
 0x4cbb82140919fe65	MostVisited_UrlPinned
 0xa90e38146e0a4399	MostVisited_UrlRemoved
diff --git a/tools/metrics/actions/extract_actions.py b/tools/metrics/actions/extract_actions.py
index 3890fc3..5d3f5a0 100755
--- a/tools/metrics/actions/extract_actions.py
+++ b/tools/metrics/actions/extract_actions.py
@@ -224,6 +224,9 @@
   actions.add('MobileContextMenuShareLink')
   actions.add('MobileContextMenuText')
   actions.add('MobileContextMenuViewImage')
+  actions.add('MobileFocusedFakeboxOnNtp')
+  actions.add('MobileFocusedOmniboxNotOnNtp')
+  actions.add('MobileFocusedOmniboxOnNtp')
   actions.add('MobileFreAttemptSignIn')
   actions.add('MobileFreSignInSuccessful')
   actions.add('MobileFreSkipSignIn')
@@ -360,6 +363,7 @@
   actions.add('FileBrowser.CreateNewFolder')
   actions.add('FileBrowser.PhotoEditor.Edit')
   actions.add('FileBrowser.PhotoEditor.View')
+  actions.add('FileBrowser.SuggestApps.ShowDialog')
 
   # Actions sent by Google Now client.
   actions.add('GoogleNow.MessageClicked')
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f335cdf..56cefde 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -62,10 +62,24 @@
   </summary>
 </histogram>
 
+<histogram name="Accessibility.CrosAutoclick" enum="BooleanEnabled">
+  <summary>
+    Whether the Chrome OS Autoclick feature is on (checked once 45 secs after
+    startup).
+  </summary>
+</histogram>
+
+<histogram name="Accessibility.CrosAutoclickDelay" units="milliseconds">
+  <summary>
+    If the user has enabled Autoclick, this is the delay set by the user for
+    autoclicks to occur, in milliseconds.
+  </summary>
+</histogram>
+
 <histogram name="Accessibility.CrosHighContrast" enum="BooleanEnabled">
   <summary>
-    Whether the Chrome OS High Constrast mode feature is on (checked once 45
-    secs after startup).
+    Whether the Chrome OS High Contrast mode feature is on (checked once 45 secs
+    after startup).
   </summary>
 </histogram>
 
@@ -1253,6 +1267,13 @@
   </summary>
 </histogram>
 
+<histogram name="Chrome.Browser.ExecutionPhase" enum="ExecutionPhase">
+  <summary>
+    Indicates the execution phase the browser was in when browser didn't exit
+    cleanly.
+  </summary>
+</histogram>
+
 <histogram name="Chrome.BrowserCrashDumpAttempts">
   <summary>
     The total number of times the browser process has attempted to generate a
@@ -1351,6 +1372,13 @@
   </summary>
 </histogram>
 
+<histogram name="clickjacking.dismiss_download" units="ms">
+  <summary>
+    The length of time between a dangerous download appearing on the downloads
+    shelf, and the &quot;Dismiss&quot; button being clicked.
+  </summary>
+</histogram>
+
 <histogram name="clickjacking.launch_url" units="ms">
   <summary>
     The length of time between the external protocol dialog being shown and the
@@ -3040,6 +3068,14 @@
   </summary>
 </histogram>
 
+<histogram name="Drive.MetadataDBVersionBeforeUpgradeCheck">
+  <summary>
+    Version number of drive resource metadata DB found on the disk before
+    checking whether it should be upgraded. Recorded during Drive metadata
+    initialization triggered by profile initialization.
+  </summary>
+</histogram>
+
 <histogram name="Drive.NumberOfHostedDocuments">
   <summary>
     Number of hosted documents (spreadsheets etc.) on Drive. Logged when Drive
@@ -3075,6 +3111,16 @@
   </summary>
 </histogram>
 
+<histogram name="Drive.SearchMetadataTime" units="microseconds">
+  <summary>
+    Time spent to perform an incremental search for auto completion of files on
+    Drive. This time is collected for every partial query the user types for
+    auto completion.  For instance, if the user types &quot;faq&quot;,
+    incremental searches are performed for &quot;f&quot;, &quot;fa&quot;, and
+    &quot;faq&quot; respectively.
+  </summary>
+</histogram>
+
 <histogram name="Enterprise.AutoEnrollmentExtraTime" units="milliseconds">
   <summary>
     Time since the user logged in until the auto-enrollment protocol completed.
@@ -4818,6 +4864,36 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.SuggestApps.Close"
+    enum="SuggestAppsDialogCloseReason">
+  <summary>
+    Chrome OS File Browser: the reason why the suggest apps dialog was closed.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.SuggestApps.Install"
+    enum="SuggestAppsDialogInstall">
+  <summary>
+    Chrome OS File Browser: whether the Webstore item user selected was
+    successfully installed or not.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.SuggestApps.Load" enum="SuggestAppsDialogLoad">
+  <summary>
+    Chrome OS File Browser: whether the initialization of the dialog succeeded
+    or not.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.SuggestApps.LoadTime" units="milliseconds">
+  <summary>
+    Chrome OS File Browser: time to load the suggest apps dialog. Measured
+    between the moment window appears and the moment all the contants in the
+    dialog including the Chrome Webstore widget are ready.
+  </summary>
+</histogram>
+
 <histogram name="FileBrowser.ViewingFileType" enum="ViewFileType">
   <summary>
     File types that were tried to be viewed through browser. This is recorded
@@ -5247,6 +5323,10 @@
 
 <histogram name="InstantExtended.InstantNavigation"
     enum="InstantExtended_InstantNavigation">
+  <obsolete>
+    Deprecated as of 10/2013. This histogram is no longer relevant since the
+    HTML overlay went away.
+  </obsolete>
   <summary>
     Records a histogram for instant extended (Local NTP and Online NTP) and
     non-extended navigations.
@@ -6802,6 +6882,25 @@
   <summary>The time to generate an NTLM HTTP authentication token.</summary>
 </histogram>
 
+<histogram name="Net.CertCommonNameFallback" enum="BooleanCommonNameMatch">
+  <summary>
+    Whether the certificate common name was used for matching the hostname,
+    instead of the subjectAlternativeName.
+
+    Measures results for all CAs (internal and publicly-trusted).
+  </summary>
+</histogram>
+
+<histogram name="Net.CertCommonNameFallbackPrivateCA"
+    enum="BooleanCommonNameMatch">
+  <summary>
+    Whether the certificate common name was used for matching the hostname,
+    instead of the subjectAlternativeName.
+
+    Measures results ony for internal (non-publicly-trusted) CAs.
+  </summary>
+</histogram>
+
 <histogram name="Net.CertificatePinSuccess" enum="BooleanSuccess">
   <obsolete>
     Renamed to Net.PublicKeyPinSuccess 28 Oct 2011.
@@ -8374,6 +8473,14 @@
   <summary>The number of streams open when a QUIC session timed out.</summary>
 </histogram>
 
+<histogram
+    name="Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut">
+  <summary>
+    The number of total streams created when a QUIC session crypto handshake
+    timed out.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.ConnectionCloseErrorCode"
     enum="QuicErrorCodes">
   <summary>
@@ -11336,6 +11443,15 @@
   </summary>
 </histogram>
 
+<histogram name="PerformanceMonitor.AverageCPU.BrowserProcess"
+    units="PercentCPUUsage">
+  <summary>
+    Average CPU utilization of the browser process, read out at each two-minute
+    interval. The utilization is in the 0-100% range per CPU, which is then
+    summed up. I.e. a quadcore system fully loaded would read as 400%.
+  </summary>
+</histogram>
+
 <histogram name="PerformanceMonitor.HighCPU.BrowserProcess" enum="BooleanHit">
   <summary>
     The number of times a browser process has continuously stayed above a
@@ -13989,6 +14105,9 @@
 </histogram>
 
 <histogram name="Renderer.unloadEventsDurationMS" units="milliseconds">
+  <obsolete>
+    Deprecated as of 10/2013.
+  </obsolete>
   <summary>
     This measures how long all unload event handlers required to run whenever an
     unload event is processed.
@@ -17971,6 +18090,14 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.BackendInitializeRestoreState"
+    enum="SyncBackendInitializeRestoreState">
+  <summary>
+    Compares sync's has_setup_completed pref against the set of types actually
+    restored from the sync DB.  Mismatches should be rare.
+  </summary>
+</histogram>
+
 <histogram name="Sync.RefreshTokenAvailable" enum="BooleanSuccess">
   <summary>
     Whether OAuth2 refresh token was available at the time when
@@ -18032,12 +18159,22 @@
 
 <histogram name="Tab.StatusWhenSwitchedBackToForeground" enum="TabStatus">
   <summary>
-    The status of a tab collected each time the user switches to it on Android.
+    The status of a tab collected each time the user switches to it on mobile.
     That does not include tabs being created at the time the user switches to
     them, such as NTP or tabs opened to handle intents.
   </summary>
 </histogram>
 
+<histogram name="Tab.StatusWhenSwitchedBackToForegroundDataProxyEnabled"
+    enum="TabStatus">
+  <summary>
+    The status of a tab collected each time the user switches to it on mobile
+    with the data reduction proxy enabled. This is populated identically, and in
+    addition to Tab.StatusWhenSwitchedBackToForeground for any given tab
+    switching event if the proxy is enabled.
+  </summary>
+</histogram>
+
 <histogram name="Tab.SwitchedToForegroundAge" units="ms">
   <summary>Age (in ms) when the tab was switched to foreground.</summary>
 </histogram>
@@ -18104,6 +18241,13 @@
   </summary>
 </histogram>
 
+<histogram name="Tabs.SpeculativeRestoreTargetStatus"
+    enum="SpeculativeRestoreTabStatus">
+  <summary>
+    Status of a tab recorded when the tab is targeted with speculative restore.
+  </summary>
+</histogram>
+
 <histogram name="Tabs.SpeculativeRestoreTimeAhead.SideSwipe" units="ms">
   <summary>
     Time between starting the speculative load and actual tab switch for correct
@@ -20071,6 +20215,11 @@
   <int value="1" label="Attempted"/>
 </enum>
 
+<enum name="BooleanCommonNameMatch" type="int">
+  <int value="0" label="subjectAltName used"/>
+  <int value="1" label="Common Name used"/>
+</enum>
+
 <enum name="BooleanCorrupt" type="int">
   <int value="0" label="Not Corrupt"/>
   <int value="1" label="Corrupt"/>
@@ -20933,6 +21082,18 @@
   <int value="18" label="Missing licenses">
     No licenses left for that domain.
   </int>
+  <int value="19" label="Robot auth code fetch failed">
+    Enrollment failed due to an error fetching the device robot authorization
+    code from the DM Server.
+  </int>
+  <int value="20" label="Robot refresh token fetch failed">
+    Enrollment failed due to an error fetching the device robot refresh token
+    from Gaia.
+  </int>
+  <int value="21" label="Robot refresh token store failed">
+    Enrollment failed due to an error persisting the device robot refresh token
+    on the device.
+  </int>
 </enum>
 
 <enum name="EnterprisePolicies" type="int">
@@ -21061,8 +21222,8 @@
       label="Enable submission of documents to Google Cloud Print"/>
   <int value="110" label="Set disk cache size in bytes"/>
   <int value="111" label="Set media disk cache size in bytes"/>
-  <int value="112" label="Enterprise web store URL"/>
-  <int value="113" label="Enterprise web store name"/>
+  <int value="112" label="Enterprise web store URL (deprecated)"/>
+  <int value="113" label="Enterprise web store name (deprecated)"/>
   <int value="114" label="Enable TLS domain-bound certificates extension"/>
   <int value="115" label="Enable reporting memory info (JS heap size) to page"/>
   <int value="116" label="Proxy settings"/>
@@ -21093,8 +21254,10 @@
   <int value="137" label="Load specified urls on demo login"/>
   <int value="138"
       label="Continue running background apps when Google Chrome is closed"/>
-  <int value="139" label="Disables Drive"/>
-  <int value="140" label="Disables Google Drive over Cellular connections"/>
+  <int value="139" label="Disables Drive in the Chrome OS Files app"/>
+  <int value="140"
+      label="Disables Google Drive over Cellular connections in the Chrome OS
+             Files app"/>
   <int value="141"
       label="Additional command line parameters for Google Chrome"/>
   <int value="142" label="Target Auto Update Version"/>
@@ -21151,9 +21314,10 @@
   <int value="183"
       label="Specify whether video activity affects power management"/>
   <int value="184"
-      label="Percentage by which to scale the idle delay in presentation mode"/>
+      label="Percentage by which to scale the idle delay in presentation mode
+             (deprecated)"/>
   <int value="185"
-      label="Allow users to redeem offers through Chrome OS Registration."/>
+      label="Allow users to redeem offers through Chrome OS Registration"/>
   <int value="186" label="Set the Terms of Service for a device-local account"/>
   <int value="187" label="Enable deleting browser and download history"/>
   <int value="188" label="Show accessibility options in system tray menu"/>
@@ -21169,6 +21333,86 @@
       label="Set the restriction on the fetching of the Variations seed"/>
   <int value="197" label="Idle warning delay when running on AC power"/>
   <int value="198" label="Idle warning delay when running on battery power"/>
+  <int value="199"
+      label="Set the restriction on the fetching of the Variations seed"/>
+  <int value="200" label="Enable remote attestation for the user"/>
+  <int value="201"
+      label="Extensions allowed to to use the remote attestation API"/>
+  <int value="202" label="Enable bailout keyboard shortcut for auto-login"/>
+  <int value="203" label="Allow screen wake locks"/>
+  <int value="204" label="Default behavior for sites not in any content pack"/>
+  <int value="205" label="Managed user manual exception hosts"/>
+  <int value="206" label="Managed user manual exception URLs"/>
+  <int value="207" label="Enable remote attestation for the device"/>
+  <int value="208"
+      label="URLs that will be granted access to audio capture devices
+             without prompt"/>
+  <int value="209"
+      label="URLs that will be granted access to video capture devices
+             without prompt"/>
+  <int value="210"
+      label="Percentage by which to scale the screen dim delay if the user
+             becomes active after dimming"/>
+  <int value="211" label="Enable large cursor"/>
+  <int value="212" label="Enable spoken feedback"/>
+  <int value="213" label="Enable high contrast mode"/>
+  <int value="214" label="Set screen magnifier type"/>
+  <int value="215"
+      label="Set default state of the large cursor on the login screen"/>
+  <int value="216"
+      label="Set the default state of spoken feedback on the login screen"/>
+  <int value="217"
+      label="Set the default state of high contrast mode on the login screen"/>
+  <int value="218"
+      label="Set the default screen magnifier type enabled on the login
+             screen"/>
+  <int value="219" label="Enable supervised users"/>
+  <int value="220"
+      label="Percentage by which to scale the screen dim delay in
+             presentation mode"/>
+  <int value="221" label="Suppress the Google Chrome Frame turndown prompt"/>
+  <int value="222"
+      label="Action to take when the idle delay is reached while running on
+             battery power"/>
+  <int value="223" label="Enable creation of supervised users"/>
+  <int value="224" label="Report device network interfaces"/>
+  <int value="225" label="Power mangement on the login screen"/>
+  <int value="226"
+      label="Action to take when the idle delay is reached while running on
+             AC power"/>
+  <int value="227" label="Managed Bookmarks"/>
+  <int value="228" label="Maximum fetch delay after a policy invalidation"/>
+  <int value="229"
+      label="Parameter providing search-by-image feature for the default
+             search provider"/>
+  <int value="230" label="Parameters for search URL which uses POST"/>
+  <int value="231" label="Parameters for suggest URL which uses POST"/>
+  <int value="232" label="Parameters for instant URL which uses POST"/>
+  <int value="233" label="Parameters for image URL which uses POST"/>
+  <int value="234" label="Enable or disable PIN-less authentication"/>
+  <int value="235"
+      label="Whether online OCSP/CRL checks are required for local trust
+             anchors"/>
+  <int value="236" label="Use 24 hour clock by default"/>
+  <int value="237" label="Default search provider new tab page URL"/>
+  <int value="238" label="Skip the meta tag check in Google Chrome Frame"/>
+  <int value="239"
+      label="Enable the use of remote attestation for content protection for
+             the device"/>
+  <int value="240" label="Allow fullscreen mode"/>
+  <int value="241" label="Enable the data compression proxy feature"/>
+  <int value="242" label="Auto update p2p enabled"/>
+  <int value="243" label="Allow autoupdate downloads via HTTP"/>
+  <int value="244" label="Control the user behavior in a multiprofile session"/>
+  <int value="245" label="Ephemeral profile"/>
+  <int value="246"
+      label="Selects the strategy used to free up disk space during automatic
+             clean-up"/>
+  <int value="247"
+      label="Specify whether power management delays and the session length
+             limit should only start running after initial user activity in a
+             session"/>
+  <int value="248" label="Report device users"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations" type="int">
@@ -21356,6 +21600,16 @@
   <int value="11004" label="WSANO_DATA"/>
 </enum>
 
+<enum name="ExecutionPhase" type="int">
+  <int value="0" label="CLEAN_SHUTDOWN"/>
+  <int value="100" label="START_METRICS_RECORDING"/>
+  <int value="200" label="CREATE_PROFILE"/>
+  <int value="300" label="STARTUP_TIMEBOMB_ARM"/>
+  <int value="400" label="THREAD_WATCHER_START"/>
+  <int value="500" label="MAIN_MESSAGE_LOOP_RUN"/>
+  <int value="600" label="SHUTDOWN_TIMEBOMB_ARM"/>
+</enum>
+
 <enum name="ExtensionBackgroundPageType" type="int">
   <int value="0" label="None"/>
   <int value="1" label="Persistent"/>
@@ -21910,6 +22164,7 @@
   <int value="519" label="WALLPAPER_SETWALLPAPER"/>
   <int value="520" label="VIRTUALKEYBOARDPRIVATE_HIDEKEYBOARD"/>
   <int value="521" label="SYSTEM_STORAGE_GETAVAILABLECAPACITY"/>
+  <int value="522" label="VIRTUALKEYBOARDPRIVATE_KEYBOARDLOADED"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -22213,6 +22468,39 @@
   <int value="151" label="HTMLAppletElementLegacyCall"/>
   <int value="152" label="HTMLEmbedElementLegacyCall"/>
   <int value="153" label="HTMLObjectElementLegacyCall"/>
+  <int value="154" label="BeforeLoadEvent"/>
+  <int value="155" label="GetMatchedCSSRules"/>
+  <int value="156" label="SVGFontInCSS"/>
+  <int value="157" label="ScrollTopBodyNotQuirksMode"/>
+  <int value="158" label="ScrollLeftBodyNotQuirksMode"/>
+  <int value="159" label="AttributeIsId"/>
+  <int value="160" label="AttributeOwnerElement"/>
+  <int value="161" label="AttributeSetPrefix"/>
+  <int value="162" label="AttributeSpecified"/>
+  <int value="163" label="BeforeLoadEventInIsolatedWorld"/>
+  <int value="164" label="PrefixedAudioDecodedByteCount"/>
+  <int value="165" label="PrefixedVideoDecodedByteCount"/>
+  <int value="166" label="PrefixedVideoSupportsFullscreen"/>
+  <int value="167" label="PrefixedVideoDisplayingFullscreen"/>
+  <int value="168" label="PrefixedVideoEnterFullscreen"/>
+  <int value="169" label="PrefixedVideoExitFullscreen"/>
+  <int value="170" label="PrefixedVideoEnterFullScreen"/>
+  <int value="171" label="PrefixedVideoExitFullScreen"/>
+  <int value="172" label="PrefixedVideoDecodedFrameCount"/>
+  <int value="173" label="PrefixedVideoDroppedFrameCount"/>
+  <int value="174" label="SourceElementCandidate"/>
+  <int value="175" label="SourceElementNonMatchingMedia"/>
+  <int value="176" label="PrefixedElementRequestFullscreen"/>
+  <int value="177" label="PrefixedElementRequestFullScreen"/>
+  <int value="178" label="BarPropLocationbar"/>
+  <int value="179" label="BarPropMenubar"/>
+  <int value="180" label="BarPropPersonalbar"/>
+  <int value="181" label="BarPropScrollbars"/>
+  <int value="182" label="BarPropStatusbar"/>
+  <int value="183" label="BarPropToolbar"/>
+  <int value="184" label="input[type=email][multiple]"/>
+  <int value="185" label="input[type=email][maxlength]"/>
+  <int value="186" label="input[type=email][multiple][maxlength]"/>
 </enum>
 
 <enum name="FFmpegCodecs" type="int">
@@ -23085,6 +23373,9 @@
 </enum>
 
 <enum name="InstantExtended_InstantNavigation" type="int">
+  <obsolete>
+    Deprecated as of 10/2013.
+  </obsolete>
   <int value="0" label="Local click"/>
   <int value="1" label="Local submit"/>
   <int value="2" label="Online click"/>
@@ -26981,6 +27272,11 @@
   <int value="2" label="Miss (tab not switched)"/>
 </enum>
 
+<enum name="SpeculativeRestoreTabStatus" type="int">
+  <int value="0" label="Already loaded"/>
+  <int value="1" label="Needs restore"/>
+</enum>
+
 <enum name="SqliteErrorCode" type="int">
   <summary>Error codes returned by SQLite - see sqlite3.h</summary>
   <int value="0" label="SQLITE_OK">Successful result</int>
@@ -27493,6 +27789,25 @@
   <int value="2" label="Reset migration"/>
 </enum>
 
+<enum name="SuggestAppsDialogCloseReason" type="int">
+  <int value="0" label="Unknown error"/>
+  <int value="1" label="Item installed"/>
+  <int value="2" label="User cancelled"/>
+  <int value="3" label="Webstore link clicked"/>
+</enum>
+
+<enum name="SuggestAppsDialogInstall" type="int">
+  <int value="0" label="Install succeeded"/>
+  <int value="1" label="Install cancelled"/>
+  <int value="2" label="Install failed"/>
+</enum>
+
+<enum name="SuggestAppsDialogLoad" type="int">
+  <int value="0" label="Load succeeded"/>
+  <int value="1" label="Load cancelled"/>
+  <int value="2" label="Load failed"/>
+</enum>
+
 <enum name="SuspendStatus" type="int">
   <int value="0" label="Success"/>
   <int value="1" label="Failure"/>
@@ -27500,6 +27815,13 @@
   <int value="3" label="Attempted"/>
 </enum>
 
+<enum name="SyncBackendInitializeRestoreState" type="int">
+  <int value="0" label="Expected restored types and found some"/>
+  <int value="1" label="Expected restored types but found none"/>
+  <int value="2" label="Did not expect restored types and found none"/>
+  <int value="3" label="Did not expect restored types but found some"/>
+</enum>
+
 <enum name="SyncedNotificationActionType" type="int">
   <int value="0" label="Unknown"/>
   <int value="1" label="Notification clicked"/>
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS
index d2f40c6..572570b 100644
--- a/tools/perf/OWNERS
+++ b/tools/perf/OWNERS
@@ -1,7 +1,8 @@
 set noparent
 dtu@chromium.org
-nduca@chromium.org
-tonyg@chromium.org
+ernstm@chromium.org
 hartmanng@chromium.org
 marja@chromium.org
-ernstm@chromium.org
+nduca@chromium.org
+qyearsley@chromium.org
+tonyg@chromium.org
diff --git a/tools/perf/benchmarks/blink_perf.js b/tools/perf/benchmarks/blink_perf.js
new file mode 100644
index 0000000..59539aa
--- /dev/null
+++ b/tools/perf/benchmarks/blink_perf.js
@@ -0,0 +1,20 @@
+// Copyright 2013 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.
+
+(function() {
+window.testRunner = {};
+window.testRunner.isDone = false;
+
+testRunner.waitUntilDone = function() {};
+testRunner.dumpAsText = function() {};
+testRunner.notifyDone = function() {
+  this.isDone = true;
+};
+
+window.GCController = {};
+
+GCController.collect = function() {
+  gc();
+};
+})();
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index f212043..979f60b 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -3,18 +3,134 @@
 # found in the LICENSE file.
 
 import os
+import sys
 
 from telemetry import test
 from telemetry.core import util
+from telemetry.page import page_measurement
+from telemetry.page import page_set
 
-from measurements import blink_perf
+
+def _CreatePageSetFromPath(path):
+  assert os.path.exists(path)
+
+  page_set_dict = {'pages': []}
+
+  def _AddPage(path):
+    if not path.endswith('.html'):
+      return
+    if '../' in open(path, 'r').read():
+      # If the page looks like it references its parent dir, include it.
+      page_set_dict['serving_dirs'] = [os.path.dirname(os.path.dirname(path))]
+    page_set_dict['pages'].append({'url':
+                                   'file://' + path.replace('\\', '/')})
+
+  def _AddDir(dir_path, skipped):
+    for candidate_path in os.listdir(dir_path):
+      if candidate_path == 'resources':
+        continue
+      candidate_path = os.path.join(dir_path, candidate_path)
+      if candidate_path.startswith(tuple([os.path.join(path, s)
+                                          for s in skipped])):
+        continue
+      if os.path.isdir(candidate_path):
+        _AddDir(candidate_path, skipped)
+      else:
+        _AddPage(candidate_path)
+
+  if os.path.isdir(path):
+    skipped = []
+    skipped_file = os.path.join(path, 'Skipped')
+    if os.path.exists(skipped_file):
+      for line in open(skipped_file, 'r').readlines():
+        line = line.strip()
+        if line and not line.startswith('#'):
+          skipped.append(line.replace('/', os.sep))
+    _AddDir(path, skipped)
+  else:
+    _AddPage(path)
+  return page_set.PageSet.FromDict(page_set_dict, os.getcwd() + os.sep)
+
+
+class _BlinkPerfMeasurement(page_measurement.PageMeasurement):
+  """Tuns a blink performance test and reports the results."""
+  def __init__(self):
+    super(_BlinkPerfMeasurement, self).__init__('')
+    with open(os.path.join(os.path.dirname(__file__),
+                           'blink_perf.js'), 'r') as f:
+      self._blink_perf_js = f.read()
+
+  def CreatePageSet(self, args, options):
+    if len(args) < 2:
+      print 'Must specify a file or directory to run.'
+      sys.exit(1)
+
+    page_set_arg = args[1]
+
+    if not os.path.exists(page_set_arg):
+      print '%s does not exist.' % page_set_arg
+      sys.exit(1)
+
+    return _CreatePageSetFromPath(page_set_arg)
+
+  @property
+  def results_are_the_same_on_every_page(self):
+    return False
+
+  def WillNavigateToPage(self, page, tab):
+    page.script_to_evaluate_on_commit = self._blink_perf_js
+
+  def CustomizeBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs([
+        '--js-flags=--expose_gc',
+        '--enable-experimental-web-platform-features'
+    ])
+
+  def MeasurePage(self, page, tab, results):
+    tab.WaitForJavaScriptExpression('testRunner.isDone', 600)
+
+    log = tab.EvaluateJavaScript('document.getElementById("log").innerHTML')
+
+    for line in log.splitlines():
+      if not line.startswith('values '):
+        continue
+      parts = line.split()
+      values = [float(v.replace(',', '')) for v in parts[1:-1]]
+      units = parts[-1]
+      metric = page.display_name.split('.')[0].replace('/', '_')
+      results.Add(metric, units, values)
+      break
+
+    print log
 
 
 class BlinkPerfAll(test.Test):
   tag = 'all'
-  test = blink_perf.BlinkPerf
+  test = _BlinkPerfMeasurement
 
   def CreatePageSet(self, options):
     path = os.path.join(
         util.GetChromiumSrcDir(), 'third_party', 'WebKit', 'PerformanceTests')
-    return blink_perf.CreatePageSetFromPath(path)
+    return _CreatePageSetFromPath(path)
+
+class BlinkPerfAnimation(test.Test):
+  tag = 'animation'
+  test = _BlinkPerfMeasurement
+
+  def CreatePageSet(self, options):
+    path = os.path.join(util.GetChromiumSrcDir(),
+        'third_party', 'WebKit', 'PerformanceTests', 'Animation')
+    return _CreatePageSetFromPath(path)
+
+class BlinkPerfWebAnimations(test.Test):
+  tag = 'web_animations'
+  test = _BlinkPerfMeasurement
+  enabled = False
+
+  def CreatePageSet(self, options):
+    path = os.path.join(util.GetChromiumSrcDir(),
+        'third_party', 'WebKit', 'PerformanceTests', 'Animation')
+    return _CreatePageSetFromPath(path)
+
+  def CustomizeBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs('--enable-web-animations-css')
diff --git a/tools/perf/benchmarks/canvasmark.py b/tools/perf/benchmarks/canvasmark.py
new file mode 100644
index 0000000..56f3018
--- /dev/null
+++ b/tools/perf/benchmarks/canvasmark.py
@@ -0,0 +1,60 @@
+# Copyright 2013 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.
+
+"""Runs Canvasmark HTML5, Canvas 2D rendering and javascript benchmark.
+
+CanvasMark tests the HTML5 <canvas> rendering performance for commonly used
+operations in HTML5 games: bitmaps, canvas drawing, alpha blending, polygon
+fills, shadows and text functions.
+"""
+
+import os
+
+from telemetry import test
+from telemetry.page import page_measurement
+from telemetry.page import page_set
+
+class _CanvasMarkMeasurement(page_measurement.PageMeasurement):
+
+  def WillNavigateToPage(self, page, tab):
+    page.script_to_evaluate_on_commit = """
+        var __results = [];
+        var __real_log = window.console.log;
+        window.console.log = function(msg) {
+          __results.push(msg);
+          __real_log.apply(this, [msg]);
+        }
+        """
+
+  def MeasurePage(self, _, tab, results):
+    tab.WaitForJavaScriptExpression('__results.length == 8', 300)
+    results_log = tab.EvaluateJavaScript('__results')
+    total = 0
+    for output in results_log:
+      # Split the results into score and test name.
+      # results log e.g., "489 [Test 1 - Asteroids - Bitmaps]"
+      score_and_name = output.split(' [', 2)
+      assert len(score_and_name) == 2, \
+        'Unexpected result format "%s"' % score_and_name
+      score = int(score_and_name[0])
+      name = score_and_name[1][:-1]
+      results.Add(name, 'score', score, data_type='unimportant')
+      # Aggregate total score for all tests.
+      total += score
+    results.Add('Score', 'score', total)
+
+
+class CanvasMark(test.Test):
+  test = _CanvasMarkMeasurement
+
+  def CreatePageSet(self, options):
+    return page_set.PageSet.FromDict({
+        'archive_data_file': '../page_sets/data/canvasmark.json',
+        'make_javascript_deterministic': False,
+        'pages': [
+          { 'url':
+            'http://www.kevs3d.co.uk/dev/canvasmark/?auto=true'}
+          ]
+        }, os.path.abspath(__file__))
+
diff --git a/tools/perf/benchmarks/dom_perf.py b/tools/perf/benchmarks/dom_perf.py
index e2b74a2..56aa59b 100644
--- a/tools/perf/benchmarks/dom_perf.py
+++ b/tools/perf/benchmarks/dom_perf.py
@@ -35,7 +35,7 @@
 SCORE_TRACE_NAME = 'score'
 
 
-class DomPerfMeasurement(page_measurement.PageMeasurement):
+class _DomPerfMeasurement(page_measurement.PageMeasurement):
   @property
   def results_are_the_same_on_every_page(self):
     return False
@@ -44,7 +44,7 @@
     try:
       def _IsDone():
         return tab.GetCookieByName('__domperf_finished') == '1'
-      util.WaitFor(_IsDone, 600, poll_interval=5)
+      util.WaitFor(_IsDone, 600)
 
       data = json.loads(tab.EvaluateJavaScript('__domperf_result'))
       for suite in data['BenchmarkSuites']:
@@ -55,7 +55,7 @@
     finally:
       tab.EvaluateJavaScript('document.cookie = "__domperf_finished=0"')
 
-  def DidRunTest(self, tab, results):
+  def DidRunTest(self, browser, results):
     # Now give the geometric mean as the total for the combined runs.
     scores = []
     for result in results.page_results:
@@ -70,7 +70,7 @@
   The final score is computed as the geometric mean of the individual results.
   Scores are not comparable across benchmark suite versions and higher scores
   means better performance: Bigger is better!"""
-  test = DomPerfMeasurement
+  test = _DomPerfMeasurement
 
   def CreatePageSet(self, options):
     dom_perf_dir = os.path.join(util.GetChromiumSrcDir(), 'data', 'dom_perf')
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py
index 530674f..e8c6cc3 100644
--- a/tools/perf/benchmarks/dromaeo.py
+++ b/tools/perf/benchmarks/dromaeo.py
@@ -6,14 +6,36 @@
 
 from telemetry import test
 from telemetry.core import util
+from telemetry.page import page_measurement
 from telemetry.page import page_set
 
-from measurements import dromaeo
+
+class _DromaeoMeasurement(page_measurement.PageMeasurement):
+  def MeasurePage(self, page, tab, results):
+    tab.WaitForJavaScriptExpression(
+        'window.document.cookie.indexOf("__done=1") >= 0', 600)
+
+    js_get_results = 'JSON.stringify(window.automation.GetResults())'
+    print js_get_results
+    score = eval(tab.EvaluateJavaScript(js_get_results))
+
+    def Escape(k):
+      chars = [' ', '-', '/', '(', ')', '*']
+      for c in chars:
+        k = k.replace(c, '_')
+      return k
+
+    suffix = page.url[page.url.index('?') + 1 : page.url.index('&')]
+    for k, v in score.iteritems():
+      data_type = 'unimportant'
+      if k == suffix:
+        data_type = 'default'
+      results.Add(Escape(k), 'runs/s', v, data_type=data_type)
 
 
-class DromaeoBenchmark(test.Test):
+class _DromaeoBenchmark(test.Test):
   """A base class for Dromaeo benchmarks."""
-  test = dromaeo.Dromaeo
+  test = _DromaeoMeasurement
 
   def CreatePageSet(self, options):
     """Makes a PageSet for Dromaeo benchmarks."""
@@ -33,85 +55,85 @@
     return page_set.PageSet.FromDict(page_set_dict, dromaeo_dir)
 
 
-class DromaeoDomCoreAttr(DromaeoBenchmark):
+class DromaeoDomCoreAttr(_DromaeoBenchmark):
   """Dromaeo DOMCore attr JavaScript benchmark."""
   tag = 'domcoreattr'
   query_param = 'dom-attr'
 
 
-class DromaeoDomCoreModify(DromaeoBenchmark):
+class DromaeoDomCoreModify(_DromaeoBenchmark):
   """Dromaeo DOMCore modify JavaScript benchmark."""
   tag = 'domcoremodify'
   query_param = 'dom-modify'
 
 
-class DromaeoDomCoreQuery(DromaeoBenchmark):
+class DromaeoDomCoreQuery(_DromaeoBenchmark):
   """Dromaeo DOMCore query JavaScript benchmark."""
   tag = 'domcorequery'
   query_param = 'dom-query'
 
 
-class DromaeoDomCoreTraverse(DromaeoBenchmark):
+class DromaeoDomCoreTraverse(_DromaeoBenchmark):
   """Dromaeo DOMCore traverse JavaScript benchmark."""
   tag = 'domcoretraverse'
   query_param = 'dom-traverse'
 
 
-class DromaeoJslibAttrJquery(DromaeoBenchmark):
+class DromaeoJslibAttrJquery(_DromaeoBenchmark):
   """Dromaeo JSLib attr jquery JavaScript benchmark"""
   tag = 'jslibattrjquery'
   query_param = 'jslib-attr-jquery'
 
 
-class DromaeoJslibAttrPrototype(DromaeoBenchmark):
+class DromaeoJslibAttrPrototype(_DromaeoBenchmark):
   """Dromaeo JSLib attr prototype JavaScript benchmark"""
   tag = 'jslibattrprototype'
   query_param = 'jslib-attr-prototype'
 
 
-class DromaeoJslibEventJquery(DromaeoBenchmark):
+class DromaeoJslibEventJquery(_DromaeoBenchmark):
   """Dromaeo JSLib event jquery JavaScript benchmark"""
   tag = 'jslibeventjquery'
   query_param = 'jslib-event-jquery'
 
 
-class DromaeoJslibEventPrototype(DromaeoBenchmark):
+class DromaeoJslibEventPrototype(_DromaeoBenchmark):
   """Dromaeo JSLib event prototype JavaScript benchmark"""
   tag = 'jslibeventprototype'
   query_param = 'jslib-event-prototype'
 
 
-class DromaeoJslibModifyJquery(DromaeoBenchmark):
+class DromaeoJslibModifyJquery(_DromaeoBenchmark):
   """Dromaeo JSLib modify jquery JavaScript benchmark"""
   tag = 'jslibmodifyjquery'
   query_param = 'jslib-modify-jquery'
 
 
-class DromaeoJslibModifyPrototype(DromaeoBenchmark):
+class DromaeoJslibModifyPrototype(_DromaeoBenchmark):
   """Dromaeo JSLib modify prototype JavaScript benchmark"""
   tag = 'jslibmodifyprototype'
   query_param = 'jslib-modify-prototype'
 
 
-class DromaeoJslibStyleJquery(DromaeoBenchmark):
+class DromaeoJslibStyleJquery(_DromaeoBenchmark):
   """Dromaeo JSLib style jquery JavaScript benchmark"""
   tag = 'jslibstylejquery'
   query_param = 'jslib-style-jquery'
 
 
-class DromaeoJslibStylePrototype(DromaeoBenchmark):
+class DromaeoJslibStylePrototype(_DromaeoBenchmark):
   """Dromaeo JSLib style prototype JavaScript benchmark"""
   tag = 'jslibstyleprototype'
   query_param = 'jslib-style-prototype'
 
 
-class DromaeoJslibTraverseJquery(DromaeoBenchmark):
+class DromaeoJslibTraverseJquery(_DromaeoBenchmark):
   """Dromaeo JSLib traverse jquery JavaScript benchmark"""
   tag = 'jslibtraversejquery'
   query_param = 'jslib-traverse-jquery'
 
 
-class DromaeoJslibTraversePrototype(DromaeoBenchmark):
+class DromaeoJslibTraversePrototype(_DromaeoBenchmark):
   """Dromaeo JSLib traverse prototype JavaScript benchmark"""
   tag = 'jslibtraverseprototype'
   query_param = 'jslib-traverse-prototype'
diff --git a/tools/perf/benchmarks/html5gaming.py b/tools/perf/benchmarks/html5gaming.py
new file mode 100644
index 0000000..341d0cd
--- /dev/null
+++ b/tools/perf/benchmarks/html5gaming.py
@@ -0,0 +1,44 @@
+# Copyright 2013 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.
+
+"""Impact HTML5 Gaming benchmark.
+
+Tests one very specific use case: smooth running games rendered with the
+<canvas> element. The score for the HTML5-Benchmark takes the total time the
+browser spent rendering frames (formula is 1000000/(sqrt(totalTime) + lagTime *
+0.1)). The benchmark automatically runs at a reasonable screen size. Final
+score is a indicator for the browser's ability to smoothly run HTML5 games."""
+
+import os
+
+from telemetry import test
+from telemetry.page import page_measurement
+from telemetry.page import page_set
+
+
+class _HTML5GamingMeasurement(page_measurement.PageMeasurement):
+  def MeasurePage(self, _, tab, results):
+    tab.ExecuteJavaScript('benchmark();')
+    # Default value of score element is 87485, its value is updated with actual
+    # score when test finish.
+    tab.WaitForJavaScriptExpression(
+        'document.getElementById("score").innerHTML != "87485"', 200)
+    result = int(tab.EvaluateJavaScript(
+        'document.getElementById("score").innerHTML'))
+    results.Add('Score', 'score', result)
+
+
+class HTML5Gaming(test.Test):
+  """Imapct HTML5 smooth running games benchmark suite."""
+  test = _HTML5GamingMeasurement
+  def CreatePageSet(self, options):
+    return page_set.PageSet.FromDict({
+        'archive_data_file': '../page_sets/data/html5gaming.json',
+        'make_javascript_deterministic': False,
+        'pages': [
+          { 'url':
+              'http://html5-benchmark.com/'}
+           ]
+        }, os.path.abspath(__file__))
+
diff --git a/tools/perf/benchmarks/jsgamebench.py b/tools/perf/benchmarks/jsgamebench.py
index d982f75..e872b55c 100644
--- a/tools/perf/benchmarks/jsgamebench.py
+++ b/tools/perf/benchmarks/jsgamebench.py
@@ -7,20 +7,15 @@
 import os
 
 from telemetry import test
-from telemetry.core import util
 from telemetry.page import page_measurement
 from telemetry.page import page_set
 
 
-class JsgamebenchMeasurement(page_measurement.PageMeasurement):
+class _JsgamebenchMeasurement(page_measurement.PageMeasurement):
   def MeasurePage(self, _, tab, results):
     tab.ExecuteJavaScript('UI.call({}, "perftest")')
-
-    js_is_done = 'document.getElementById("perfscore0") != null'
-    def _IsDone():
-      return bool(tab.EvaluateJavaScript(js_is_done))
-    util.WaitFor(_IsDone, 1200)
-
+    tab.WaitForJavaScriptExpression(
+        'document.getElementById("perfscore0") != null', 1200)
     js_get_results = 'document.getElementById("perfscore0").innerHTML'
     result = int(tab.EvaluateJavaScript(js_get_results))
     results.Add('Score', 'score (bigger is better)', result)
@@ -28,7 +23,7 @@
 
 class Jsgamebench(test.Test):
   """Counts how many animating sprites can move around on the screen at once."""
-  test = JsgamebenchMeasurement
+  test = _JsgamebenchMeasurement
 
   def CreatePageSet(self, options):
     return page_set.PageSet.FromDict({
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py
index 2fda99b..0fd4291 100644
--- a/tools/perf/benchmarks/kraken.py
+++ b/tools/perf/benchmarks/kraken.py
@@ -7,7 +7,6 @@
 import os
 
 from telemetry import test
-from telemetry.core import util
 from telemetry.page import page_measurement
 from telemetry.page import page_set
 
@@ -16,14 +15,11 @@
   return float(sum(l)) / len(l) if len(l) > 0 else 0.0
 
 
-class KrakenMeasurement(page_measurement.PageMeasurement):
+class _KrakenMeasurement(page_measurement.PageMeasurement):
   def MeasurePage(self, _, tab, results):
-    js_is_done = """
-document.title.indexOf("Results") != -1 && document.readyState == "complete"
-"""
-    def _IsDone():
-      return bool(tab.EvaluateJavaScript(js_is_done))
-    util.WaitFor(_IsDone, 500, poll_interval=5)
+    tab.WaitForDocumentReadyStateToBeComplete()
+    tab.WaitForJavaScriptExpression(
+        'document.title.indexOf("Results") != -1', 500)
 
     js_get_results = """
 var formElement = document.getElementsByTagName("input")[0];
@@ -41,7 +37,7 @@
 
 class Kraken(test.Test):
   """Mozilla's Kraken JavaScript benchmark."""
-  test = KrakenMeasurement
+  test = _KrakenMeasurement
 
   def CreatePageSet(self, options):
     return page_set.PageSet.FromDict({
diff --git a/tools/perf/benchmarks/memory_pressure.py b/tools/perf/benchmarks/memory_pressure.py
new file mode 100644
index 0000000..4088a9f
--- /dev/null
+++ b/tools/perf/benchmarks/memory_pressure.py
@@ -0,0 +1,12 @@
+# Copyright 2013 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.
+
+from telemetry import test
+from measurements import memory_pressure
+
+class MemoryPressure(test.Test):
+  test = memory_pressure.MemoryPressure
+  page_set = 'page_sets/typical_25.json'
+  options = {'cold': True,
+             'pageset_repeat_iters': 6}
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py
index e3d3e01..91eb99f 100644
--- a/tools/perf/benchmarks/octane.py
+++ b/tools/perf/benchmarks/octane.py
@@ -10,13 +10,10 @@
 from telemetry.page import page_set
 
 
-class OctaneMeasurement(page_measurement.PageMeasurement):
+class _OctaneMeasurement(page_measurement.PageMeasurement):
   def MeasurePage(self, _, tab, results):
-    js_is_done = """
-completed && !document.getElementById("progress-bar-container")"""
-    def _IsDone():
-      return bool(tab.EvaluateJavaScript(js_is_done))
-    util.WaitFor(_IsDone, 300, poll_interval=5)
+    tab.WaitForJavaScriptExpression(
+        'completed && !document.getElementById("progress-bar-container")', 300)
 
     js_get_results = """
 var results = {};
@@ -44,7 +41,7 @@
 
 class Octane(test.Test):
   """Google's Octane JavaScript benchmark."""
-  test = OctaneMeasurement
+  test = _OctaneMeasurement
 
   def CreatePageSet(self, options):
     octane_dir = os.path.join(util.GetChromiumSrcDir(), 'chrome', 'test',
diff --git a/tools/perf/benchmarks/pica.py b/tools/perf/benchmarks/pica.py
index 800a4c9..9dfb752 100644
--- a/tools/perf/benchmarks/pica.py
+++ b/tools/perf/benchmarks/pica.py
@@ -5,7 +5,7 @@
 from telemetry import test
 from telemetry.page import page_measurement
 
-class PicaMeasurement(page_measurement.PageMeasurement):
+class _PicaMeasurement(page_measurement.PageMeasurement):
   def CustomizeBrowserOptions(self, options):
     # Needed for native custom elements (document.register)
     options.AppendExtraBrowserArgs(
@@ -17,5 +17,5 @@
 
 
 class Pica(test.Test):
-  test = PicaMeasurement
+  test = _PicaMeasurement
   page_set = 'page_sets/pica.json'
diff --git a/tools/perf/benchmarks/rasterize_and_record.py b/tools/perf/benchmarks/rasterize_and_record.py
new file mode 100644
index 0000000..f9410ec
--- /dev/null
+++ b/tools/perf/benchmarks/rasterize_and_record.py
@@ -0,0 +1,22 @@
+# Copyright 2013 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.
+from telemetry import test
+
+from measurements import rasterize_and_record
+
+
+class RasterizeAndRecordTop25(test.Test):
+  """Measures rasterize and record performance on the top 25 web pages.
+
+  http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
+  test = rasterize_and_record.RasterizeAndRecord
+  page_set = 'page_sets/top_25.json'
+
+
+class RasterizeAndRecordKeyMobileSites(test.Test):
+  """Measures rasterize and record performance on the key mobile sites.
+
+  http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
+  test = rasterize_and_record.RasterizeAndRecord
+  page_set = 'page_sets/key_mobile_sites.json'
diff --git a/tools/perf/benchmarks/robohornet_pro.py b/tools/perf/benchmarks/robohornet_pro.py
index f14e782..1809b7b 100644
--- a/tools/perf/benchmarks/robohornet_pro.py
+++ b/tools/perf/benchmarks/robohornet_pro.py
@@ -7,26 +7,22 @@
 import os
 
 from telemetry import test
-from telemetry.core import util
 from telemetry.page import page_measurement
 from telemetry.page import page_set
 
 
-class RobohornetProMeasurement(page_measurement.PageMeasurement):
+class _RobohornetProMeasurement(page_measurement.PageMeasurement):
   def MeasurePage(self, _, tab, results):
     tab.ExecuteJavaScript('ToggleRoboHornet()')
-
-    done = 'document.getElementById("results").innerHTML.indexOf("Total") != -1'
-    def _IsDone():
-      return tab.EvaluateJavaScript(done)
-    util.WaitFor(_IsDone, 120)
-
+    tab.WaitForJavaScriptExpression(
+        'document.getElementById("results").innerHTML.indexOf("Total") != -1',
+        120)
     result = int(tab.EvaluateJavaScript('stopTime - startTime'))
     results.Add('Total', 'ms', result)
 
 
 class RobohornetPro(test.Test):
-  test = RobohornetProMeasurement
+  test = _RobohornetProMeasurement
 
   def CreatePageSet(self, options):
     return page_set.PageSet.FromDict({
diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py
new file mode 100644
index 0000000..016d482
--- /dev/null
+++ b/tools/perf/benchmarks/session_restore.py
@@ -0,0 +1,22 @@
+# Copyright 2013 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.
+from telemetry import test
+
+from measurements import session_restore
+
+
+class SessionRestoreColdTypical25(test.Test):
+  tag = 'cold'
+  test = session_restore.SessionRestore
+  page_set = 'page_sets/typical_25.json'
+  options = {'cold': True,
+             'pageset_repeat_iters': 5}
+
+
+class SessionRestoreWarmTypical25(test.Test):
+  tag = 'warm'
+  test = session_restore.SessionRestore
+  page_set = 'page_sets/typical_25.json'
+  options = {'warm': True,
+             'pageset_repeat_iters': 20}
diff --git a/tools/perf/benchmarks/silk.py b/tools/perf/benchmarks/silk.py
new file mode 100644
index 0000000..5ea21cf
--- /dev/null
+++ b/tools/perf/benchmarks/silk.py
@@ -0,0 +1,15 @@
+# Copyright 2013 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.
+from telemetry import test
+
+from measurements import smoothness
+
+
+class SilkKeySilkCases(test.Test):
+  """Measures timeline metrics while scrolling down the key_silk_cases pages.
+
+  http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
+  test = smoothness.Smoothness
+  page_set = 'page_sets/key_silk_cases.json'
+  options = {'metric': 'timeline'}
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 90b5826..0d3a836 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -12,9 +12,16 @@
   http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
   test = smoothness.Smoothness
   page_set = 'page_sets/top_25.json'
-  options = {'report_all_results': False}
 
 
 class SmoothnessToughCanvasCases(test.Test):
   test = smoothness.Smoothness
   page_set = 'page_sets/tough_canvas_cases.json'
+
+
+class SmoothnessKeyMobileSites(test.Test):
+  """Measures rendering statistics while scrolling down the key mobile sites.
+
+  http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
+  test = smoothness.Smoothness
+  page_set = 'page_sets/key_mobile_sites.json'
diff --git a/tools/perf/benchmarks/spaceport.py b/tools/perf/benchmarks/spaceport.py
index fdd2934..34baaac 100644
--- a/tools/perf/benchmarks/spaceport.py
+++ b/tools/perf/benchmarks/spaceport.py
@@ -13,13 +13,13 @@
 from telemetry.page import page_set
 
 
-class SpaceportMeasurement(page_measurement.PageMeasurement):
+class _SpaceportMeasurement(page_measurement.PageMeasurement):
   def CustomizeBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--disable-gpu-vsync')
 
   def MeasurePage(self, _, tab, results):
-    util.WaitFor(lambda: tab.EvaluateJavaScript(
-        '!document.getElementById("start-performance-tests").disabled'), 60)
+    tab.WaitForJavaScriptExpression(
+        '!document.getElementById("start-performance-tests").disabled', 60)
 
     tab.ExecuteJavaScript("""
         window.__results = {};
@@ -32,20 +32,18 @@
         document.getElementById('start-performance-tests').click();
     """)
 
-    js_get_results = 'JSON.stringify(window.__results)'
-    num_tests_complete = [0]  # A list to work around closure issue.
-    def _IsDone():
-      num_tests_in_measurement = 24
-      num_results = len(eval(tab.EvaluateJavaScript(js_get_results)))
-      if num_results > num_tests_complete[0]:
-        num_tests_complete[0] = num_results
-        logging.info('Completed measurement %d of %d'
-                     % (num_tests_complete[0],
-                        num_tests_in_measurement))
-      return num_tests_complete[0] >= num_tests_in_measurement
-    util.WaitFor(_IsDone, 1200, poll_interval=5)
+    num_results = 0
+    num_tests_in_spaceport = 24
+    while num_results < num_tests_in_spaceport:
+      tab.WaitForJavaScriptExpression(
+          'Object.keys(window.__results).length > %d' % num_results, 180)
+      num_results = tab.EvaluateJavaScript(
+          'Object.keys(window.__results).length')
+      logging.info('Completed test %d of %d' %
+                   (num_results, num_tests_in_spaceport))
 
-    result_dict = eval(tab.EvaluateJavaScript(js_get_results))
+    result_dict = eval(tab.EvaluateJavaScript(
+        'JSON.stringify(window.__results)'))
     for key in result_dict:
       chart, trace = key.split('.', 1)
       results.Add(trace, 'objects (bigger is better)', float(result_dict[key]),
@@ -56,7 +54,7 @@
 
 class Spaceport(test.Test):
   """spaceport.io's PerfMarks benchmark."""
-  test = SpaceportMeasurement
+  test = _SpaceportMeasurement
 
   def CreatePageSet(self, options):
     spaceport_dir = os.path.join(util.GetChromiumSrcDir(), 'chrome', 'test',
diff --git a/tools/perf/benchmarks/sunspider.py b/tools/perf/benchmarks/sunspider.py
index 2ec91a9..7295a7e 100644
--- a/tools/perf/benchmarks/sunspider.py
+++ b/tools/perf/benchmarks/sunspider.py
@@ -11,13 +11,11 @@
 from telemetry.page import page_set
 
 
-class SunspiderMeasurement(page_measurement.PageMeasurement):
+class _SunspiderMeasurement(page_measurement.PageMeasurement):
   def MeasurePage(self, _, tab, results):
-    js_is_done = ('window.location.pathname.indexOf("results.html") >= 0'
-                  '&& typeof(output) != "undefined"')
-    def _IsDone():
-      return tab.EvaluateJavaScript(js_is_done)
-    util.WaitFor(_IsDone, 300, poll_interval=1)
+    tab.WaitForJavaScriptExpression(
+        'window.location.pathname.indexOf("results.html") >= 0'
+        '&& typeof(output) != "undefined"', 300)
 
     js_get_results = 'JSON.stringify(output);'
     js_results = json.loads(tab.EvaluateJavaScript(js_get_results))
@@ -39,7 +37,7 @@
 
 class Sunspider(test.Test):
   """Apple's SunSpider JavaScript benchmark."""
-  test = SunspiderMeasurement
+  test = _SunspiderMeasurement
 
   def CreatePageSet(self, options):
     sunspider_dir = os.path.join(util.GetChromiumSrcDir(),
diff --git a/tools/perf/measurements/blink_perf.js b/tools/perf/measurements/blink_perf.js
deleted file mode 100644
index 155f22f..0000000
--- a/tools/perf/measurements/blink_perf.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2013 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.
-
-(function() {
-window.testRunner = {};
-window.testRunner.isDone = false;
-
-testRunner.waitUntilDone = function() {};
-testRunner.dumpAsText = function() {};
-testRunner.notifyDone = function() {
-  this.isDone = true;
-};
-
-window.GCController = {};
-
-GCController.collect = function() {
-  gc();
-};
-})();
diff --git a/tools/perf/measurements/blink_perf.py b/tools/perf/measurements/blink_perf.py
deleted file mode 100644
index 98ada31..0000000
--- a/tools/perf/measurements/blink_perf.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) 2013 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.
-
-"""This measurement runs a blink performance test and reports the results."""
-
-import os
-import sys
-
-from telemetry.core import util
-from telemetry.page import page_measurement
-from telemetry.page import page_set
-
-
-def CreatePageSetFromPath(path):
-  assert os.path.exists(path)
-
-  page_set_dict = {'pages': []}
-
-  def _AddPage(path):
-    if not path.endswith('.html'):
-      return
-    if '../' in open(path, 'r').read():
-      # If the page looks like it references its parent dir, include it.
-      page_set_dict['serving_dirs'] = [os.path.dirname(os.path.dirname(path))]
-    page_set_dict['pages'].append({'url':
-                                   'file://' + path.replace('\\', '/')})
-
-  def _AddDir(dir_path, skipped):
-    for candidate_path in os.listdir(dir_path):
-      if candidate_path == 'resources':
-        continue
-      candidate_path = os.path.join(dir_path, candidate_path)
-      if candidate_path.startswith(tuple([os.path.join(path, s)
-                                          for s in skipped])):
-        continue
-      if os.path.isdir(candidate_path):
-        _AddDir(candidate_path, skipped)
-      else:
-        _AddPage(candidate_path)
-
-  if os.path.isdir(path):
-    skipped = []
-    skipped_file = os.path.join(path, 'Skipped')
-    if os.path.exists(skipped_file):
-      for line in open(skipped_file, 'r').readlines():
-        line = line.strip()
-        if line and not line.startswith('#'):
-          skipped.append(line.replace('/', os.sep))
-    _AddDir(path, skipped)
-  else:
-    _AddPage(path)
-  return page_set.PageSet.FromDict(page_set_dict, os.getcwd() + os.sep)
-
-
-class BlinkPerf(page_measurement.PageMeasurement):
-  def __init__(self):
-    super(BlinkPerf, self).__init__('')
-    with open(os.path.join(os.path.dirname(__file__),
-                           'blink_perf.js'), 'r') as f:
-      self._blink_perf_js = f.read()
-
-  def CreatePageSet(self, args, options):
-    if len(args) < 2:
-      print 'Must specify a file or directory to run.'
-      sys.exit(1)
-
-    page_set_arg = args[1]
-
-    if not os.path.exists(page_set_arg):
-      print '%s does not exist.' % page_set_arg
-      sys.exit(1)
-
-    return CreatePageSetFromPath(page_set_arg)
-
-  @property
-  def results_are_the_same_on_every_page(self):
-    return False
-
-  def WillNavigateToPage(self, page, tab):
-    page.script_to_evaluate_on_commit = self._blink_perf_js
-
-  def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArgs([
-        '--js-flags=--expose_gc',
-        '--enable-experimental-web-platform-features'
-    ])
-
-  def MeasurePage(self, page, tab, results):
-    def _IsDone():
-      return tab.EvaluateJavaScript('testRunner.isDone')
-    util.WaitFor(_IsDone, 600)
-
-    log = tab.EvaluateJavaScript('document.getElementById("log").innerHTML')
-
-    for line in log.splitlines():
-      if not line.startswith('values '):
-        continue
-      parts = line.split()
-      values = [float(v.replace(',', '')) for v in parts[1:-1]]
-      units = parts[-1]
-      metric = page.display_name.split('.')[0].replace('/', '_')
-      results.Add(metric, units, values)
-      break
-
-    print log
diff --git a/tools/perf/measurements/dromaeo.py b/tools/perf/measurements/dromaeo.py
deleted file mode 100644
index 96037ea..0000000
--- a/tools/perf/measurements/dromaeo.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (c) 2012 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.
-
-from telemetry.core import util
-from telemetry.page import page_measurement
-
-class Dromaeo(page_measurement.PageMeasurement):
-  def MeasurePage(self, page, tab, results):
-    js_is_done = 'window.document.cookie.indexOf("__done=1") >= 0'
-    def _IsDone():
-      return bool(tab.EvaluateJavaScript(js_is_done))
-    util.WaitFor(_IsDone, 600, poll_interval=5)
-
-    js_get_results = 'JSON.stringify(window.automation.GetResults())'
-    print js_get_results
-    score = eval(tab.EvaluateJavaScript(js_get_results))
-
-    def Escape(k):
-      chars = [' ', '-', '/', '(', ')', '*']
-      for c in chars:
-        k = k.replace(c, '_')
-      return k
-
-    suffix = page.url[page.url.index('?') + 1 : page.url.index('&')]
-    for k, v in score.iteritems():
-      data_type = 'unimportant'
-      if k == suffix:
-        data_type = 'default'
-      results.Add(Escape(k), 'runs/s', v, data_type=data_type)
diff --git a/tools/perf/measurements/endure.py b/tools/perf/measurements/endure.py
index 598166b..4b52ba2 100644
--- a/tools/perf/measurements/endure.py
+++ b/tools/perf/measurements/endure.py
@@ -77,7 +77,7 @@
   def CanRunForPage(self, page):
     return hasattr(page, 'endure')
 
-  def WillRunPageRepeats(self, page, tab):
+  def WillRunPageRepeats(self, page):
     """Set-up before starting a new page."""
     # Reset the starting time for each new page.
     self._start_time = time.time()
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py
index e838bfb..7207891 100644
--- a/tools/perf/measurements/image_decoding.py
+++ b/tools/perf/measurements/image_decoding.py
@@ -19,8 +19,8 @@
     """)
     tab.StartTimelineRecording()
 
-  def NeedsBrowserRestartAfterEachRun(self, tab):
-    return not tab.ExecuteJavaScript("""
+  def NeedsBrowserRestartAfterEachRun(self, browser):
+    return not browser.tabs[0].ExecuteJavaScript("""
         window.chrome &&
             chrome.gpuBenchmarking &&
             chrome.gpuBenchmarking.clearImageCache;
diff --git a/tools/perf/measurements/loading_profile.py b/tools/perf/measurements/loading_profile.py
index ddc145d..fcb8c9a 100644
--- a/tools/perf/measurements/loading_profile.py
+++ b/tools/perf/measurements/loading_profile.py
@@ -6,7 +6,6 @@
 import tempfile
 
 from metrics import loading
-from telemetry.core import util
 from telemetry.core.platform.profiler import perf_profiler
 from telemetry.page import page_measurement
 
@@ -39,9 +38,7 @@
   def MeasurePage(self, page, tab, results):
     # In current telemetry tests, all tests wait for DocumentComplete state,
     # but we need to wait for the load event.
-    def IsLoaded():
-      return bool(tab.EvaluateJavaScript('performance.timing.loadEventStart'))
-    util.WaitFor(IsLoaded, 300)
+    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
 
     profile_files = tab.browser.StopProfiling()
 
diff --git a/tools/perf/measurements/loading_timeline.py b/tools/perf/measurements/loading_timeline.py
index 113f2e1..28389b2 100644
--- a/tools/perf/measurements/loading_timeline.py
+++ b/tools/perf/measurements/loading_timeline.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 from metrics import timeline
 from metrics import loading
-from telemetry.core import util
 from telemetry.page import page_measurement
 
 class LoadingTimeline(page_measurement.PageMeasurement):
@@ -21,9 +20,7 @@
   def MeasurePage(self, page, tab, results):
     # In current telemetry tests, all tests wait for DocumentComplete state,
     # but we need to wait for the load event.
-    def IsLoaded():
-      return bool(tab.EvaluateJavaScript('performance.timing.loadEventStart'))
-    util.WaitFor(IsLoaded, 300)
+    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
 
     # TODO(nduca): when crbug.com/168431 is fixed, modify the page sets to
     # recognize loading as a toplevel action.
diff --git a/tools/perf/measurements/loading_trace.py b/tools/perf/measurements/loading_trace.py
index 16d9300..6cff3a0 100644
--- a/tools/perf/measurements/loading_trace.py
+++ b/tools/perf/measurements/loading_trace.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 from metrics import loading
 from metrics import timeline
-from telemetry.core import util
 from telemetry.page import page_measurement
 
 class LoadingTrace(page_measurement.PageMeasurement):
@@ -21,9 +20,7 @@
   def MeasurePage(self, page, tab, results):
     # In current telemetry tests, all tests wait for DocumentComplete state,
     # but we need to wait for the load event.
-    def IsLoaded():
-      return bool(tab.EvaluateJavaScript('performance.timing.loadEventStart'))
-    util.WaitFor(IsLoaded, 300)
+    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
 
     # TODO(nduca): when crbug.com/168431 is fixed, modify the page sets to
     # recognize loading as a toplevel action.
diff --git a/tools/perf/measurements/memory.py b/tools/perf/measurements/memory.py
index 894003f..00be503 100644
--- a/tools/perf/measurements/memory.py
+++ b/tools/perf/measurements/memory.py
@@ -41,5 +41,5 @@
         }
       """)
 
-  def DidRunTest(self, tab, results):
+  def DidRunTest(self, browser, results):
     self._memory_metric.AddSummaryResults(results)
diff --git a/tools/perf/measurements/memory_multi_tab.py b/tools/perf/measurements/memory_multi_tab.py
index dacc395..5148213 100644
--- a/tools/perf/measurements/memory_multi_tab.py
+++ b/tools/perf/measurements/memory_multi_tab.py
@@ -42,8 +42,8 @@
     # a high frequency.
     options.AppendExtraBrowserArgs('--memory-metrics')
 
-  def TabForPage(self, page, tab):
-    return tab.browser.tabs.New()
+  def TabForPage(self, page, browser):
+    return browser.tabs.New()
 
   def DidNavigateToPage(self, page, tab):
     # Start measurement on the first tab.
@@ -57,5 +57,5 @@
       self._memory_metric.Stop(page, self._first_tab)
       self._memory_metric.AddResults(self._first_tab, results)
 
-  def DidRunTest(self, tab, results):
+  def DidRunTest(self, browser, results):
     self._memory_metric.AddSummaryResults(results)
diff --git a/tools/perf/measurements/memory_pressure.py b/tools/perf/measurements/memory_pressure.py
new file mode 100644
index 0000000..92ee334
--- /dev/null
+++ b/tools/perf/measurements/memory_pressure.py
@@ -0,0 +1,57 @@
+# Copyright 2013 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.
+
+"""Multi tab memory test.
+
+This test is a multi tab test, but we're interested in measurements for
+the entire test rather than each single page.
+"""
+
+import logging
+
+from metrics import histogram_util
+from telemetry.page import page_measurement
+
+
+class MemoryPressure(page_measurement.PageMeasurement):
+  def __init__(self, *args, **kwargs):
+    super(MemoryPressure, self).__init__(*args, **kwargs)
+    # _first_tab is used to access histograms
+    self._is_first_page = True
+    self._tab_count = 0
+
+  # Allow histogram collection
+  def CustomizeBrowserOptions(self, options):
+    histogram_util.CustomizeBrowserOptions(options)
+
+  # Open a new tab at each page
+  def TabForPage(self, page, browser):
+    return browser.tabs.New()
+
+  def GetTabsHistogramCounts(self, tab):
+    histogram_type = histogram_util.BROWSER_HISTOGRAM
+    discard_count = histogram_util.GetHistogramCount(
+      histogram_type, "Tabs.Discard.DiscardCount", tab)
+    kill_count = histogram_util.GetHistogramCount(
+      histogram_type, "Tabs.SadTab.KillCreated", tab)
+    return (discard_count, kill_count)
+
+  def MeasurePage(self, page, tab, results):
+    # After navigating to each page, check if it triggered tab discards or
+    # kills.
+    (discard_count, kill_count) = self.GetTabsHistogramCounts(tab)
+    # Done with this tab.  Disconnect cleanly from it to avoid a possible
+    # TabCrashException if the tab is discarded or killed.
+    tab.Disconnect()
+    # Sanity check for first page
+    if self._is_first_page:
+      self._is_first_page = False
+      assert discard_count == 0 and kill_count == 0
+
+    self._tab_count += 1
+    # End the test at the first kill or discard.
+    if kill_count > 0 or discard_count > 0:
+      logging.info("test ending at tab %d, discards = %d, kills = %d" %
+        (self._tab_count, discard_count, kill_count))
+      self.RequestExit()
diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py
index 873a829..a0fdc47 100644
--- a/tools/perf/measurements/page_cycler.py
+++ b/tools/perf/measurements/page_cycler.py
@@ -43,6 +43,7 @@
     self._v8_object_stats_metric = None
     self._number_warm_runs = None
     self._cold_runs_requested = False
+    self._cold_run_start_index = None
     self._has_loaded_page = collections.defaultdict(int)
 
   def AddCommandLineOptions(self, parser):
@@ -62,7 +63,7 @@
         action='store_true',
         help='Enable the speed index metric.')
 
-    parser.add_option('--cold-load-percent', type='int', default=0,
+    parser.add_option('--cold-load-percent', type='int',
                       help='%d of page visits for which a cold load is forced')
 
   def DidStartBrowser(self, browser):
@@ -115,13 +116,14 @@
       print '%s is currently disabled on mac. Skipping test.' % sys.argv[-1]
       sys.exit(0)
 
+    self._cold_runs_requested = (options.cold_load_percent != None)
     # Handle requests for cold cache runs
-    if (options.cold_load_percent and
+    if (self._cold_runs_requested and
         (options.repeat_options.page_repeat_secs or
          options.repeat_options.pageset_repeat_secs)):
       raise Exception('--cold-load-percent is incompatible with timed repeat')
 
-    if (options.cold_load_percent and
+    if (self._cold_runs_requested and
         (options.cold_load_percent < 0 or options.cold_load_percent > 100)):
       raise Exception('--cold-load-percent must be in the range [0-100]')
 
@@ -129,24 +131,24 @@
     # dropping the first run.
     number_warm_pageset_runs = int(
         (int(options.repeat_options.pageset_repeat_iters) - 1) *
-        (100 - options.cold_load_percent) / 100)
+        (100 - int(options.cold_load_percent or 0)) / 100)
 
     # Make sure _number_cold_runs is an integer multiple of page_repeat.
     # Without this, --pageset_shuffle + --page_repeat could lead to
     # assertion failures on _started_warm in WillNavigateToPage.
     self._number_warm_runs = (number_warm_pageset_runs *
                               options.repeat_options.page_repeat_iters)
-    self._cold_runs_requested = bool(options.cold_load_percent)
-    self.discard_first_result = (bool(options.cold_load_percent) or
+    self._cold_run_start_index = (self._number_warm_runs +
+        options.repeat_options.page_repeat_iters)
+    self.discard_first_result = ((self._cold_runs_requested and
+                                  not options.cold_load_percent) or
                                  self.discard_first_result)
 
   def MeasurePage(self, page, tab, results):
-    def PageLoadIsFinished():
-      return bool(tab.EvaluateJavaScript('__pc_load_time'))
-    util.WaitFor(PageLoadIsFinished, 60)
+    tab.WaitForJavaScriptExpression('__pc_load_time', 60)
 
     chart_name_prefix = ('' if not self._cold_runs_requested else
-                         'cold_' if self.ShouldRunCold(page.url) else
+                         'cold_' if self.IsRunCold(page.url) else
                          'warm_')
 
     results.Add('page_load_time', 'ms',
@@ -173,9 +175,14 @@
       self._speedindex_metric.AddResults(
           tab, results, chart_name=chart_name_prefix+'speed_index')
 
-  def DidRunTest(self, tab, results):
+  def DidRunTest(self, browser, results):
     self._memory_metric.AddSummaryResults(results)
-    io.IOMetric().AddSummaryResults(tab, results)
+    io.IOMetric().AddSummaryResults(browser, results)
+
+  def IsRunCold(self, url):
+    return (self.ShouldRunCold(url) or
+            (self._cold_runs_requested and
+             self._has_loaded_page[url] == 0))
 
   def ShouldRunCold(self, url):
     # We do the warm runs first for two reasons.  The first is so we can
@@ -185,7 +192,8 @@
     # contribute to the cold data and warm the catch for the following
     # warm run, and clearing the cache before the load of the following
     # URL would eliminate the intended warmup for the previous URL.
-    return self._has_loaded_page[url] >= self._number_warm_runs + 1
+    return (self._cold_runs_requested and
+            self._has_loaded_page[url] >= self._cold_run_start_index)
 
   def results_are_the_same_on_every_page(self):
     return not self._cold_runs_requested
diff --git a/tools/perf/measurements/page_cycler_unittest.py b/tools/perf/measurements/page_cycler_unittest.py
index db8c198..89d0a57 100644
--- a/tools/perf/measurements/page_cycler_unittest.py
+++ b/tools/perf/measurements/page_cycler_unittest.py
@@ -107,6 +107,8 @@
         self.clear_cache_calls += 1
       def EvaluateJavaScript(self, _):
         return 1
+      def WaitForJavaScriptExpression(self, _, __):
+        pass
 
     url_name = "http://fakepage.com"
     page = FakePage(url_name)
diff --git a/tools/perf/measurements/rasterize_and_record.py b/tools/perf/measurements/rasterize_and_record.py
index e12d14f..ea67da3 100644
--- a/tools/perf/measurements/rasterize_and_record.py
+++ b/tools/perf/measurements/rasterize_and_record.py
@@ -2,10 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import sys
 import time
 
 from metrics import rendering_stats
 from telemetry.page import page_measurement
+from telemetry.core.timeline.model import MarkerMismatchError
+from telemetry.core.timeline.model import MarkerOverlapError
 
 
 class RasterizeAndRecord(page_measurement.PageMeasurement):
@@ -20,15 +23,21 @@
                       'Higher values reduce variance, but can cause' +
                       'instability (timeouts, event buffer overflows, etc.).')
     parser.add_option('--start-wait-time', dest='start_wait_time',
-                      default=2,
+                      default=5,
                       help='Wait time before the benchmark is started ' +
                       '(must be long enought to load all content)')
     parser.add_option('--stop-wait-time', dest='stop_wait_time',
-                      default=5,
+                      default=10,
                       help='Wait time before measurement is taken ' +
                       '(must be long enough to render one frame)')
 
   def CustomizeBrowserOptions(self, options):
+    # rasterize_and_record fails on the Linux perf bot.
+    # TODO(ernstm): Re-enable this test when crbug.com/311389 is fixed.
+    if 'linux' in sys.platform:
+      print 'This benchmark is temporarily disabled on Linux. Skipping test.'
+      sys.exit(0)
+
     # Run each raster task N times. This allows us to report the time for the
     # best run, effectively excluding cache effects and time when the thread is
     # de-scheduled.
@@ -44,6 +53,15 @@
     ])
 
   def MeasurePage(self, page, tab, results):
+    # TODO(ernstm): Remove this temporary workaround when reference build has
+    # been updated to branch 1671 or later.
+    backend = tab.browser._browser_backend # pylint: disable=W0212
+    if (not hasattr(backend, 'chrome_branch_number') or
+        (sys.platform != 'android' and backend.chrome_branch_number < 1671)):
+      print ('Warning: rasterize_and_record requires Chrome branch 1671 or '
+             'later. Skipping measurement.')
+      sys.exit(0)
+
     # Rasterize only what's visible.
     tab.ExecuteJavaScript(
         'chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent();')
@@ -81,8 +99,11 @@
         'console.timeEnd("' + rendering_stats.RENDER_PROCESS_MARKER + '")')
 
     timeline = tab.browser.StopTracing().AsTimelineModel()
-    timeline_markers = timeline.FindTimelineMarkers(
-        rendering_stats.RENDER_PROCESS_MARKER)
+    try:
+      timeline_markers = timeline.FindTimelineMarkers(
+          rendering_stats.RENDER_PROCESS_MARKER)
+    except (MarkerMismatchError, MarkerOverlapError) as e:
+      raise page_measurement.MeasurementFailure(str(e))
     stats = rendering_stats.RenderingStats(timeline_markers, timeline_markers)
 
     results.Add('rasterize_time', 'ms',
diff --git a/tools/perf/measurements/record_per_area.py b/tools/perf/measurements/record_per_area.py
index 5121f13..894f8fb 100644
--- a/tools/perf/measurements/record_per_area.py
+++ b/tools/perf/measurements/record_per_area.py
@@ -5,7 +5,6 @@
 import time
 
 from metrics import smoothness
-from telemetry.core import util
 from telemetry.page import page_measurement
 
 class RecordPerArea(page_measurement.PageMeasurement):
@@ -50,10 +49,7 @@
                 {width: 1024, height: 256}]);
     """)
 
-    def _IsDone():
-      return tab.EvaluateJavaScript(
-          'window.benchmark_results.done', timeout=300)
-    util.WaitFor(_IsDone, timeout=300)
+    tab.WaitForJavaScriptExpression('window.benchmark_results.done', 300)
 
     all_data = tab.EvaluateJavaScript('window.benchmark_results.results')
     for data in all_data:
diff --git a/tools/perf/measurements/session_restore.py b/tools/perf/measurements/session_restore.py
new file mode 100644
index 0000000..12fa39a
--- /dev/null
+++ b/tools/perf/measurements/session_restore.py
@@ -0,0 +1,63 @@
+# Copyright 2013 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.
+
+from measurements import startup
+from metrics import cpu
+from metrics import startup_metric
+
+
+class SessionRestore(startup.Startup):
+  """Performs a measurement of Chromium's Session restore performance.
+
+  This test is meant to be run against a generated profile.
+  This test inherits support for the --warm or --cold command line options -
+  see startup.py for details.
+  """
+
+  def __init__(self):
+    super(SessionRestore, self).__init__()
+    self.close_tabs_before_run = False
+    self._cpu_metric = None
+
+  def CustomizeBrowserOptions(self, options):
+    super(SessionRestore, self).CustomizeBrowserOptions(options)
+    options.AppendExtraBrowserArgs([
+        '--restore-last-session'
+    ])
+
+  def CanRunForPage(self, page):
+    # No matter how many pages in the pageset, just perform one test iteration.
+    return page.page_set.pages.index(page) == 0
+
+  def RunNavigateSteps(self, page, tab):
+    # Overriden so that no page navigation occurs.
+    pass
+
+  def ValidatePageSet(self, page_set):
+    # Reject any pageset that contains more than one WPR archive.
+    wpr_archives = {}
+    for page in page_set:
+      wpr_archives[page_set.WprFilePathForPage(page)] = True
+
+    if len(wpr_archives.keys()) > 1:
+      raise Exception("Invalid pageset: more than 1 WPR archive found.: " +
+          ', '.join(wpr_archives.keys()))
+
+  def WillStartBrowser(self, browser):
+    self._cpu_metric = cpu.CpuMetric(browser)
+    self._cpu_metric.Start(None, None)
+
+  def MeasurePage(self, page, tab, results):
+    # Wait for all tabs to finish loading.
+    for i in xrange(len(tab.browser.tabs)):
+      t = tab.browser.tabs[i]
+      t.WaitForDocumentReadyStateToBeComplete()
+
+    # Record CPU usage from browser start to when all pages have loaded.
+    self._cpu_metric.Stop(None, None)
+    self._cpu_metric.AddResults(tab, results, 'cpu_utilization')
+
+    startup_metric.StartupMetric().AddResults(tab, results)
+
+    # TODO(jeremy): Measure time to load - first, last and frontmost tab here.
\ No newline at end of file
diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py
index 7d3e391..3bfd0ce 100644
--- a/tools/perf/measurements/smoothness.py
+++ b/tools/perf/measurements/smoothness.py
@@ -3,16 +3,9 @@
 # found in the LICENSE file.
 
 from metrics import smoothness
-from metrics import rendering_stats
+from metrics import timeline
 from telemetry.page import page_test
 from telemetry.page import page_measurement
-from telemetry.core.timeline.model import MarkerMismatchError
-
-
-class NotEnoughFramesError(page_measurement.MeasurementFailure):
-  def __init__(self):
-    super(NotEnoughFramesError, self).__init__(
-        'Page output less than two frames')
 
 
 class MissingDisplayFrameRateError(page_measurement.MeasurementFailure):
@@ -21,28 +14,19 @@
         'Missing display frame rate metrics: ' + name)
 
 
-class NoSupportedActionError(page_measurement.MeasurementFailure):
-  def __init__(self):
-    super(NoSupportedActionError, self).__init__(
-        'None of the actions is supported by smoothness measurement')
-
-
-def GetTimelineMarkerLabelsFromAction(compound_action):
-  timeline_marker_labels = []
-  if not isinstance(compound_action, list):
-    compound_action = [compound_action]
-  for action in compound_action:
-    if action.GetTimelineMarkerLabel():
-      timeline_marker_labels.append(action.GetTimelineMarkerLabel())
-  if not timeline_marker_labels:
-    raise NoSupportedActionError()
-  return timeline_marker_labels
-
-
 class Smoothness(page_measurement.PageMeasurement):
   def __init__(self):
     super(Smoothness, self).__init__('smoothness')
     self._trace_result = None
+    self._metric = None
+
+  def AddCommandLineOptions(self, parser):
+    metric_choices = ['smoothness', 'timeline']
+    parser.add_option('--metric', dest='metric', type='choice',
+                      choices=metric_choices,
+                      default='smoothness',
+                      help=('Metric to use in the measurement. ' +
+                            'Supported values: ' + ', '.join(metric_choices)))
 
   def CustomizeBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
@@ -51,42 +35,25 @@
     return hasattr(page, 'smoothness')
 
   def WillRunAction(self, page, tab, action):
-    # TODO(ermst): Remove "webkit" category after Blink r157377 is picked up by
-    # the reference builds.
-    tab.browser.StartTracing('webkit,webkit.console,benchmark', 60)
+    if self.options.metric == 'smoothness':
+      compound_action = page_test.GetCompoundActionFromPage(
+          page, self._action_name_to_run)
+      self._metric = smoothness.SmoothnessMetric(compound_action)
+    elif self.options.metric == 'timeline':
+      self._metric = timeline.TimelineMetric(timeline.TRACING_MODE)
+
+    self._metric.Start(page, tab)
+
     if tab.browser.platform.IsRawDisplayFrameRateSupported():
       tab.browser.platform.StartRawDisplayFrameRateMeasurement()
-    tab.ExecuteJavaScript(
-        'console.time("' + rendering_stats.RENDER_PROCESS_MARKER + '")')
 
   def DidRunAction(self, page, tab, action):
-    tab.ExecuteJavaScript(
-        'console.timeEnd("' + rendering_stats.RENDER_PROCESS_MARKER + '")')
     if tab.browser.platform.IsRawDisplayFrameRateSupported():
       tab.browser.platform.StopRawDisplayFrameRateMeasurement()
-    self._trace_result = tab.browser.StopTracing()
+    self._metric.Stop(page, tab)
 
   def MeasurePage(self, page, tab, results):
-    timeline = self._trace_result.AsTimelineModel()
-    render_process_marker = timeline.FindTimelineMarkers(
-        rendering_stats.RENDER_PROCESS_MARKER)
-    compound_action = page_test.GetCompoundActionFromPage(
-        page, self._action_name_to_run)
-    timeline_marker_labels = GetTimelineMarkerLabelsFromAction(compound_action)
-    # TODO(ernstm): remove try-except when the reference build was updated?
-    try:
-      timeline_markers = timeline.FindTimelineMarkers(timeline_marker_labels)
-    except MarkerMismatchError:
-      timeline_markers = render_process_marker
-
-    stats = rendering_stats.RenderingStats(
-        render_process_marker, timeline_markers)
-
-    if not stats.frame_times:
-      raise NotEnoughFramesError()
-
-    smoothness_metric = smoothness.SmoothnessMetric(stats)
-    smoothness_metric.AddResults(tab, results)
+    self._metric.AddResults(tab, results)
 
     if tab.browser.platform.IsRawDisplayFrameRateSupported():
       for r in tab.browser.platform.GetRawDisplayFrameRateMeasurements():
diff --git a/tools/perf/measurements/startup.py b/tools/perf/measurements/startup.py
index 09e8cfc..0080091 100644
--- a/tools/perf/measurements/startup.py
+++ b/tools/perf/measurements/startup.py
@@ -2,8 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import json
-
+from metrics import startup_metric
 from telemetry.page import page_measurement
 
 class Startup(page_measurement.PageMeasurement):
@@ -15,12 +14,6 @@
   tests, you should repeat the page set to ensure it's cached.
   """
 
-  HISTOGRAMS_TO_RECORD = {
-    'messageloop_start_time' :
-        'Startup.BrowserMessageLoopStartTimeFromMainEntry',
-    'window_display_time' : 'Startup.BrowserWindowDisplay',
-    'open_tabs_time' : 'Startup.BrowserOpenTabs'}
-
   def __init__(self):
     super(Startup, self).__init__(needs_browser_restart_after_each_run=True)
 
@@ -46,19 +39,4 @@
     ])
 
   def MeasurePage(self, page, tab, results):
-    get_histogram_js = 'statsCollectionController.getBrowserHistogram("%s")'
-
-    for display_name, histogram_name in self.HISTOGRAMS_TO_RECORD.iteritems():
-      result = tab.EvaluateJavaScript(get_histogram_js % histogram_name)
-      result = json.loads(result)
-      measured_time = 0
-
-      if 'sum' in result:
-        # For all the histograms logged here, there's a single entry so sum
-        # is the exact value for that entry.
-        measured_time = result['sum']
-      elif 'buckets' in result:
-        measured_time = \
-            (result['buckets'][0]['high'] + result['buckets'][0]['low']) / 2
-
-      results.Add(display_name, 'ms', measured_time)
+    startup_metric.StartupMetric().AddResults(tab, results)
diff --git a/tools/perf/measurements/startwithurl.py b/tools/perf/measurements/startwithurl.py
new file mode 100644
index 0000000..dba7327
--- /dev/null
+++ b/tools/perf/measurements/startwithurl.py
@@ -0,0 +1,59 @@
+# Copyright 2013 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.
+
+from measurements import startup
+from metrics import startup_metric
+
+class StartWithUrl(startup.Startup):
+  """Measures Chromium's startup performance when started with a URL
+
+  This test inherits support for the --warm or --cold command line options -
+  see startup.py for details.
+  """
+
+  def __init__(self):
+    super(StartWithUrl, self).__init__()
+    self.close_tabs_before_run = False
+
+
+  def AddCommandLineOptions(self, parser):
+    super(StartWithUrl, self).AddCommandLineOptions(parser)
+    parser.add_option('--url', action='store', default=None,
+                      help='Start with a request to open a specific URL')
+
+  def CustomizeBrowserOptions(self, options):
+    super(StartWithUrl, self).CustomizeBrowserOptions(options)
+    if options.url:
+      browser_options = options.browser_options
+      browser_options.startup_url = options.url
+    options.AppendExtraBrowserArgs([
+        '--restore-last-session'
+    ])
+
+  def CanRunForPage(self, page):
+    # No matter how many pages in the pageset, just perform one test iteration.
+    return page.page_set.pages.index(page) == 0
+
+  def RunNavigateSteps(self, page, tab):
+    # Overriden so that no page navigation occurs.
+    pass
+
+  def ValidatePageSet(self, page_set):
+    # Reject any pageset that contains more than one WPR archive.
+    wpr_archives = {}
+    for page in page_set:
+      wpr_archives[page_set.WprFilePathForPage(page)] = True
+
+    if len(wpr_archives.keys()) > 1:
+      raise Exception("Invalid pageset: more than 1 WPR archive found.: " +
+          ', '.join(wpr_archives.keys()))
+
+  def MeasurePage(self, page, tab, results):
+    # Wait for all tabs to finish loading.
+    for i in xrange(len(tab.browser.tabs)):
+      t = tab.browser.tabs[i]
+      t.WaitForDocumentReadyStateToBeComplete()
+
+    startup_metric.StartupMetric().AddResults(tab, results)
+
diff --git a/tools/perf/measurements/tab_switching.py b/tools/perf/measurements/tab_switching.py
index dff8041..00511e2 100644
--- a/tools/perf/measurements/tab_switching.py
+++ b/tools/perf/measurements/tab_switching.py
@@ -28,8 +28,8 @@
         '--enable-stats-collection-bindings'
     ])
 
-  def TabForPage(self, page, tab):
-    return tab.browser.tabs.New()
+  def TabForPage(self, page, browser):
+    return browser.tabs.New()
 
   def DidStartBrowser(self, browser):
     self._cpu_metric = cpu.CpuMetric(browser)
diff --git a/tools/perf/metrics/histogram_util.py b/tools/perf/metrics/histogram_util.py
index a5501b5..2d20998 100644
--- a/tools/perf/metrics/histogram_util.py
+++ b/tools/perf/metrics/histogram_util.py
@@ -14,6 +14,12 @@
 BROWSER_HISTOGRAM = 'browser_histogram'
 RENDERER_HISTOGRAM = 'renderer_histogram'
 
+
+def CustomizeBrowserOptions(options):
+  """Allows histogram collection."""
+  options.AppendExtraBrowserArgs(['--enable-stats-collection-bindings'])
+
+
 def SubtractHistogram(histogram_json, start_histogram_json):
   """Subtracts a previous histogram from a histogram.
 
@@ -65,3 +71,13 @@
   if histogram_json:
     return histogram_json
   return None
+
+
+def GetHistogramCount(histogram_type, histogram_name, tab):
+  """Get the count of events for the given histograms."""
+  histogram_json = GetHistogram(histogram_type, histogram_name, tab)
+  histogram = json.loads(histogram_json)
+  if 'count' in histogram:
+    return histogram['count']
+  else:
+    return 0
diff --git a/tools/perf/metrics/io.py b/tools/perf/metrics/io.py
index e083fb1..998581c 100644
--- a/tools/perf/metrics/io.py
+++ b/tools/perf/metrics/io.py
@@ -21,9 +21,9 @@
     # This metric currently only returns summary results, not per-page results.
     raise NotImplementedError()
 
-  def AddSummaryResults(self, tab, results):
+  def AddSummaryResults(self, browser, results):
     """Add summary results to the results object."""
-    io_stats = tab.browser.io_stats
+    io_stats = browser.io_stats
     if not io_stats['Browser']:
       return
 
diff --git a/tools/perf/metrics/smoothness.py b/tools/perf/metrics/smoothness.py
index d78d909..b834444 100644
--- a/tools/perf/metrics/smoothness.py
+++ b/tools/perf/metrics/smoothness.py
@@ -2,29 +2,89 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from metrics import statistics
 from metrics import Metric
+from metrics import rendering_stats
+from metrics import statistics
+from telemetry.core.timeline.model import MarkerMismatchError
+from telemetry.core.timeline.model import MarkerOverlapError
+from telemetry.page import page_measurement
+
+TIMELINE_MARKER = 'SmoothnessMetric'
+
+
+class NotEnoughFramesError(page_measurement.MeasurementFailure):
+  def __init__(self):
+    super(NotEnoughFramesError, self).__init__(
+        'Page output less than two frames')
+
+
+class NoSupportedActionError(page_measurement.MeasurementFailure):
+  def __init__(self):
+    super(NoSupportedActionError, self).__init__(
+        'None of the actions is supported by smoothness measurement')
+
+
+def GetTimelineMarkerLabelsFromAction(compound_action):
+  timeline_marker_labels = []
+  if not isinstance(compound_action, list):
+    compound_action = [compound_action]
+  for action in compound_action:
+    if action.GetTimelineMarkerLabel():
+      timeline_marker_labels.append(action.GetTimelineMarkerLabel())
+  if not timeline_marker_labels:
+    raise NoSupportedActionError()
+  return timeline_marker_labels
 
 
 class SmoothnessMetric(Metric):
-  def __init__(self, rendering_stats):
+  def __init__(self, compound_action):
     super(SmoothnessMetric, self).__init__()
-    self.stats_ = rendering_stats
+    self._stats = None
+    self._compound_action = compound_action
+
+  def Start(self, page, tab):
+    # TODO(ermst): Remove "webkit" category after Blink r157377 is picked up by
+    # the reference builds.
+    tab.browser.StartTracing('webkit,webkit.console,benchmark', 60)
+    tab.ExecuteJavaScript('console.time("' + TIMELINE_MARKER + '")')
+
+  def Stop(self, page, tab):
+    tab.ExecuteJavaScript('console.timeEnd("' + TIMELINE_MARKER + '")')
+    timeline_model = tab.browser.StopTracing().AsTimelineModel()
+    render_process_marker = timeline_model.FindTimelineMarkers(TIMELINE_MARKER)
+    timeline_marker_labels = GetTimelineMarkerLabelsFromAction(
+        self._compound_action)
+    try:
+      timeline_markers = timeline_model.FindTimelineMarkers(
+          timeline_marker_labels)
+    except MarkerMismatchError:
+      # TODO(ernstm): re-raise exception as MeasurementFailure when the
+      # reference build was updated.
+      timeline_markers = render_process_marker
+    except MarkerOverlapError as e:
+      raise page_measurement.MeasurementFailure(str(e))
+
+    self._stats = rendering_stats.RenderingStats(
+        render_process_marker, timeline_markers)
+
+    if not self._stats.frame_times:
+      raise NotEnoughFramesError()
+
 
   def AddResults(self, tab, results):
     # List of raw frame times.
-    results.Add('frame_times', 'ms', self.stats_.frame_times)
+    results.Add('frame_times', 'ms', self._stats.frame_times)
 
     # Arithmetic mean of frame times.
-    mean_frame_time = statistics.ArithmeticMean(self.stats_.frame_times,
-                                                len(self.stats_.frame_times))
+    mean_frame_time = statistics.ArithmeticMean(self._stats.frame_times,
+                                                len(self._stats.frame_times))
     results.Add('mean_frame_time', 'ms', round(mean_frame_time, 3))
 
     # Absolute discrepancy of frame time stamps.
-    jank = statistics.FrameDiscrepancy(self.stats_.frame_timestamps)
+    jank = statistics.FrameDiscrepancy(self._stats.frame_timestamps)
     results.Add('jank', '', round(jank, 4))
 
     # Are we hitting 60 fps for 95 percent of all frames? (Boolean value)
     # We use 17ms as a slightly looser threshold, instead of 1000.0/60.0.
     results.Add('mostly_smooth', '',
-        statistics.Percentile(self.stats_.frame_times, 95.0) < 17.0)
+        statistics.Percentile(self._stats.frame_times, 95.0) < 17.0)
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py
index 1ff7a69..9a45341 100644
--- a/tools/perf/metrics/speedindex.py
+++ b/tools/perf/metrics/speedindex.py
@@ -46,7 +46,8 @@
   def AddResults(self, tab, results, chart_name=None):
     """Calculate the speed index and add it to the results."""
     events = tab.timeline_model.GetAllEvents()
-    results.Add('speed_index', 'ms', _SpeedIndex(events), chart_name=chart_name)
+    index = _SpeedIndex(events, _GetViewportSize(tab))
+    results.Add('speed_index', 'ms', index, chart_name=chart_name)
 
   def IsFinished(self, tab):
     """Decide whether the timeline recording should be stopped.
@@ -85,7 +86,12 @@
     return self._is_finished
 
 
-def _SpeedIndex(events):
+def _GetViewportSize(tab):
+  """Returns dimensions of the viewport."""
+  return tab.EvaluateJavaScript('[ window.innerWidth, window.innerHeight ]')
+
+
+def _SpeedIndex(events, viewport):
   """Calculate the speed index of a page load from a list of events.
 
   The speed index number conceptually represents the number of milliseconds
@@ -96,12 +102,13 @@
 
   Args:
     events: A list of telemetry.core.timeline.slice.Slice objects
+    viewport: A tuple (width, height) of the window.
 
   Returns:
     A single number, milliseconds of visual incompleteness.
   """
   paint_events = _IncludedPaintEvents(events)
-  time_area_dict = _TimeAreaDict(paint_events)
+  time_area_dict = _TimeAreaDict(paint_events, viewport)
   time_completeness_dict = _TimeCompletenessDict(time_area_dict)
   # The first time interval starts from the start of the first event.
   prev_time = events[0].start
@@ -155,12 +162,13 @@
         return event.start
     assert False, 'There were no layout events after resource receive events.'
 
+  first_layout_time = FirstLayoutTime(events)
   paint_events = [e for e in events
-                  if e.start >= FirstLayoutTime(events) and e.name == 'Paint']
+                  if e.start >= first_layout_time and e.name == 'Paint']
   return paint_events
 
 
-def _TimeAreaDict(paint_events):
+def _TimeAreaDict(paint_events, viewport):
   """Make a dict from time to adjusted area value for events at that time.
 
   The adjusted area value of each paint event is determined by how many paint
@@ -171,29 +179,39 @@
 
   Args:
     paint_events: A list of paint events
+    viewport: A tuple (width, height) of the window.
 
   Returns:
     A dictionary of times of each paint event (in milliseconds) to the
     adjusted area that the paint event is worth.
   """
+  width, height = viewport
+  fullscreen_area = width * height
+
+  def ClippedArea(rectangle):
+    """Returns rectangle area clipped to viewport size."""
+    _, x0, y0, x1, y1 = rectangle
+    x0 = max(0, x0)
+    y0 = max(0, y0)
+    x1 = min(width, x1)
+    y1 = min(height, y1)
+    return max(0, x1 - x0) * max(0, y1 - y0)
+
   grouped = _GroupEventByRectangle(paint_events)
-  # Note: It is assumed here that the fullscreen area is considered to be
-  # area of the largest paint event that has NOT been filtered out.
-  fullscreen_area = max([_RectangleArea(rect) for rect in grouped.keys()])
   event_area_dict = collections.defaultdict(int)
 
-  for rectangle in grouped:
+  for rectangle, events in grouped.items():
     # The area points for each rectangle are divided up among the paint
     # events in that rectangle.
-    area = _RectangleArea(rectangle)
-    update_count = len(grouped[rectangle])
+    area = ClippedArea(rectangle)
+    update_count = len(events)
     adjusted_area = float(area) / update_count
 
     # Paint events for the largest-area rectangle are counted as 50%.
     if area == fullscreen_area:
       adjusted_area /= 2
 
-    for event in grouped[rectangle]:
+    for event in events:
       # The end time for an event is used for that event's time.
       event_time = event.end
       event_area_dict[event_time] += adjusted_area
@@ -209,7 +227,7 @@
   In the WPT source, this 'rectangle' is also called a 'region'.
   """
   def GetBox(quad):
-    """Convert the "clip" data in a paint event to coordinates and dimensions.
+    """Gets top-left and bottom-right coordinates from paint event.
 
     In the timeline data from devtools, paint rectangle dimensions are
     represented x-y coordinates of four corners, clockwise from the top-left.
@@ -217,19 +235,11 @@
     in file src/out/Debug/obj/gen/devtools/TimelinePanel.js.
     """
     x0, y0, _, _, x1, y1, _, _ = quad
-    width, height = (x1 - x0), (y1 - y0)
-    return (x0, y0, width, height)
+    return (x0, y0, x1, y1)
 
   assert paint_event.name == 'Paint'
   frame = paint_event.args['frameId']
-  x, y, width, height = GetBox(paint_event.args['data']['clip'])
-  return (frame, x, y, width, height)
-
-
-def _RectangleArea(rectangle):
-  """Get the area of a rectangle as returned by _GetRectangle, above."""
-  # Width and height are the last two items in the 5-tuple.
-  return rectangle[3] * rectangle[4]
+  return (frame,) + GetBox(paint_event.args['data']['clip'])
 
 
 def _GroupEventByRectangle(paint_events):
diff --git a/tools/perf/metrics/speedindex_unittest.py b/tools/perf/metrics/speedindex_unittest.py
index f4a62ca..856127f 100644
--- a/tools/perf/metrics/speedindex_unittest.py
+++ b/tools/perf/metrics/speedindex_unittest.py
@@ -30,7 +30,8 @@
 class TimeAreaDictTest(unittest.TestCase):
   def testAdjustedAreaDict(self):
     paint_events = speedindex._IncludedPaintEvents(_SAMPLE_EVENTS)
-    time_area_dict = speedindex._TimeAreaDict(paint_events)
+    viewport = 1000, 1000
+    time_area_dict = speedindex._TimeAreaDict(paint_events, viewport)
     self.assertEquals(len(time_area_dict), 4)
     # The event that ends at time 100 is a fullscreen; it's discounted by half.
     self.assertEquals(time_area_dict[100], 500000)
@@ -41,6 +42,7 @@
 
 class SpeedIndexTest(unittest.TestCase):
   def testWithSampleData(self):
+    viewport = 1000, 1000
     # Add up the parts of the speed index for each time interval.
     # Each part is the time interval multiplied by the proportion of the
     # total area value that is not yet painted for that interval.
@@ -50,7 +52,7 @@
     parts.append(100 * 0.4)
     parts.append(400 * 0.2)
     expected = sum(parts)  # 330.0
-    actual = speedindex._SpeedIndex(_SAMPLE_EVENTS)
+    actual = speedindex._SpeedIndex(_SAMPLE_EVENTS, viewport)
     self.assertEqual(actual, expected)
 
 
@@ -62,7 +64,7 @@
   provides timeline data in json format along with the speed index results.
   """
 
-  def _TestJsonTimelineExpectation(self, filename, expected):
+  def _TestJsonTimelineExpectation(self, filename, viewport, expected):
     """Check whether the result for some timeline data is as expected.
 
     Args:
@@ -73,7 +75,7 @@
     with open(file_path) as json_file:
       raw_events = json.load(json_file)
       events = model.TimelineModel(event_data=raw_events).GetAllEvents()
-      actual = speedindex._SpeedIndex(events)
+      actual = speedindex._SpeedIndex(events, viewport)
       # The result might differ by 1 or more milliseconds due to rounding,
       # so compare to the nearest 10 milliseconds.
       self.assertAlmostEqual(actual, expected, places=-1)
@@ -81,17 +83,20 @@
   def testCern(self):
     # Page: http://info.cern.ch/hypertext/WWW/TheProject.html
     # This page has only one paint event.
-    self._TestJsonTimelineExpectation('cern_repeat_timeline.json', 379.0)
+    self._TestJsonTimelineExpectation(
+        'cern_repeat_timeline.json', (1014, 650), 379.0)
 
   def testBaidu(self):
     # Page: http://www.baidu.com/
     # This page has several paint events, but no nested paint events.
-    self._TestJsonTimelineExpectation('baidu_repeat_timeline.json', 1761.43)
+    self._TestJsonTimelineExpectation(
+        'baidu_repeat_timeline.json', (1014, 650), 1761.43)
 
   def test2ch(self):
     # Page: http://2ch.net/
     # This page has several paint events, including nested paint events.
-    self._TestJsonTimelineExpectation('2ch_repeat_timeline.json', 674.58)
+    self._TestJsonTimelineExpectation(
+        '2ch_repeat_timeline.json', (997, 650), 674.58)
 
 
 if __name__ == "__main__":
diff --git a/tools/perf/metrics/startup_metric.py b/tools/perf/metrics/startup_metric.py
new file mode 100644
index 0000000..1ebdbc3
--- /dev/null
+++ b/tools/perf/metrics/startup_metric.py
@@ -0,0 +1,40 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import json
+
+from metrics import Metric
+
+
+class StartupMetric(Metric):
+  "A metric for browser startup time."
+
+  HISTOGRAMS_TO_RECORD = {
+    'messageloop_start_time' :
+        'Startup.BrowserMessageLoopStartTimeFromMainEntry',
+    'window_display_time' : 'Startup.BrowserWindowDisplay',
+    'open_tabs_time' : 'Startup.BrowserOpenTabs'}
+
+  def Start(self, page, tab):
+    raise NotImplementedError()
+
+  def Stop(self, page, tab):
+    raise NotImplementedError()
+
+  def AddResults(self, tab, results):
+    get_histogram_js = 'statsCollectionController.getBrowserHistogram("%s")'
+
+    for display_name, histogram_name in self.HISTOGRAMS_TO_RECORD.iteritems():
+      result = tab.EvaluateJavaScript(get_histogram_js % histogram_name)
+      result = json.loads(result)
+      measured_time = 0
+
+      if 'sum' in result:
+        # For all the histograms logged here, there's a single entry so sum
+        # is the exact value for that entry.
+        measured_time = result['sum']
+      elif 'buckets' in result:
+        measured_time = \
+            (result['buckets'][0]['high'] + result['buckets'][0]['low']) / 2
+
+      results.Add(display_name, 'ms', measured_time)
diff --git a/tools/perf/metrics/timeline.py b/tools/perf/metrics/timeline.py
index 6d9ef26..5968f5e 100644
--- a/tools/perf/metrics/timeline.py
+++ b/tools/perf/metrics/timeline.py
@@ -24,12 +24,6 @@
       if not tab.browser.supports_tracing:
         raise Exception('Not supported')
       tab.browser.StartTracing()
-    else:
-      assert self._mode == TIMELINE_MODE
-      tab.StartTimelineRecording()
-
-  def Stop(self, page, tab):
-    if self._mode == TRACING_MODE:
       # This creates an async trace event in the render process for tab that
       # will allow us to find that tab during the AddTracingResultsForTab
       # function.
@@ -37,7 +31,12 @@
           console.time("__loading_measurement_was_here__");
           console.timeEnd("__loading_measurement_was_here__");
           """)
+    else:
+      assert self._mode == TIMELINE_MODE
+      tab.StartTimelineRecording()
 
+  def Stop(self, page, tab):
+    if self._mode == TRACING_MODE:
       trace_result = tab.browser.StopTracing()
       self._model = trace_result.AsTimelineModel()
       events = [s for
diff --git a/tools/perf/page_sets/PRESUBMIT.py b/tools/perf/page_sets/PRESUBMIT.py
index 51779eb..bc183d6 100644
--- a/tools/perf/page_sets/PRESUBMIT.py
+++ b/tools/perf/page_sets/PRESUBMIT.py
@@ -7,20 +7,20 @@
 import sys
 
 
+# Avoid leaking changes to global sys.path.
+_old_sys_path = sys.path
+try:
+  sys.path.append(os.path.join(os.pardir, os.pardir, 'telemetry'))
+  from telemetry.page import cloud_storage
+finally:
+  sys.path = _old_sys_path
+
+
 def _SyncFilesToCloud(input_api, output_api):
   """Searches for .sha1 files and uploads them to Cloud Storage.
 
   It validates all the hashes and skips upload if not necessary.
   """
-  # Because this script will be called from a magic PRESUBMIT demon,
-  # avoid angering it; don't pollute its sys.path.
-  old_sys_path = sys.path
-  try:
-    sys.path = [os.path.join(os.pardir, os.pardir, 'telemetry')] + sys.path
-    from telemetry.page import cloud_storage
-  finally:
-    sys.path = old_sys_path
-
   # Look in both buckets, in case the user uploaded the file manually. But this
   # script focuses on WPR archives, so it only uploads to the internal bucket.
   hashes_in_cloud_storage = cloud_storage.List(cloud_storage.INTERNAL_BUCKET)
@@ -55,6 +55,8 @@
 
     try:
       cloud_storage.Insert(cloud_storage.INTERNAL_BUCKET, file_hash, file_path)
+      results.append(output_api.PresubmitNotifyResult(
+          'Uploaded file to Cloud Storage: %s' % hash_path))
     except cloud_storage.CloudStorageError, e:
       results.append(output_api.PresubmitError(
           'Unable to upload to Cloud Storage: %s\n\n%s' % (hash_path, e)))
@@ -62,7 +64,9 @@
   return results
 
 
+def CheckChangeOnUpload(input_api, output_api):
+  return _SyncFilesToCloud(input_api, output_api)
+
+
 def CheckChangeOnCommit(input_api, output_api):
-  results = []
-  results += _SyncFilesToCloud(input_api, output_api)
-  return results
+  return _SyncFilesToCloud(input_api, output_api)
diff --git a/tools/perf/page_sets/data/canvasmark.json b/tools/perf/page_sets/data/canvasmark.json
new file mode 100644
index 0000000..d03a33a
--- /dev/null
+++ b/tools/perf/page_sets/data/canvasmark.json
@@ -0,0 +1,9 @@
+{
+    "page_set": "../canvasmark.json",
+    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.",
+    "archives": {
+        "canvasmark_000.wpr": [
+            "http://www.kevs3d.co.uk/dev/canvasmark/?auto=true"
+        ]
+    }
+}
diff --git a/tools/perf/page_sets/data/canvasmark_000.wpr.sha1 b/tools/perf/page_sets/data/canvasmark_000.wpr.sha1
new file mode 100644
index 0000000..c885d82
--- /dev/null
+++ b/tools/perf/page_sets/data/canvasmark_000.wpr.sha1
@@ -0,0 +1 @@
+e36078a35e69e492367a9cfc13c80f6e69311053
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/html5gaming.json b/tools/perf/page_sets/data/html5gaming.json
new file mode 100644
index 0000000..a556292
--- /dev/null
+++ b/tools/perf/page_sets/data/html5gaming.json
@@ -0,0 +1,9 @@
+{
+    "page_set": "../html5gaming.json", 
+    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
+    "archives": {
+        "html5gaming_000.wpr": [
+            "http://html5-benchmark.com/"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/html5gaming_000.wpr.sha1 b/tools/perf/page_sets/data/html5gaming_000.wpr.sha1
new file mode 100644
index 0000000..672a827
--- /dev/null
+++ b/tools/perf/page_sets/data/html5gaming_000.wpr.sha1
@@ -0,0 +1 @@
+3442b137da2c267c98b1053b5d0abbbfe0bf7a26
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_silk_cases.json b/tools/perf/page_sets/data/key_silk_cases.json
new file mode 100644
index 0000000..48532bf
--- /dev/null
+++ b/tools/perf/page_sets/data/key_silk_cases.json
@@ -0,0 +1,18 @@
+{
+    "page_set": "../key_silk_cases.json", 
+    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
+    "archives": {
+        "key_silk_cases_000.wpr": [
+            "http://groupcloned.com/test/plain/list-recycle-transform.html", 
+            "http://groupcloned.com/test/plain/list-animation-simple.html", 
+            "http://www.polymer-project.org/polymer-all/labs/list/static-scroll-display.html", 
+            "http://www.polymer-project.org/polymer-all/labs/list/virtual-scroll-examples.html", 
+            "http://groupcloned.com/test/plain/sticky-using-webkit-backface-visibility.html", 
+            "http://pr.gg/scroll6_even_faster.html", 
+            "http://staff.tumblr.com/", 
+            "http://jsfiddle.net/mdxJ7/3/show", 
+            "http://jsfiddle.net/3yDKh/1/show", 
+            "http://jsfiddle.net/3yDKh/3/show"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_silk_cases_000.wpr.sha1 b/tools/perf/page_sets/data/key_silk_cases_000.wpr.sha1
new file mode 100644
index 0000000..6a724a5
--- /dev/null
+++ b/tools/perf/page_sets/data/key_silk_cases_000.wpr.sha1
@@ -0,0 +1 @@
+ef615efddeb2d56756b8c8f6e78027cbe2e4fcfa
\ No newline at end of file
diff --git a/tools/perf/page_sets/key_silk_cases.json b/tools/perf/page_sets/key_silk_cases.json
new file mode 100644
index 0000000..b7f4485
--- /dev/null
+++ b/tools/perf/page_sets/key_silk_cases.json
@@ -0,0 +1,114 @@
+{
+  "description": "Pages hand-picked for project Silk.",
+  "archive_data_file": "data/key_silk_cases.json",
+  "credentials_path": "data/credentials.json",
+  "user_agent_type": "mobile",
+  "smoothness": { "action": "scroll" },
+  "pages": [
+    {
+      "url": "http://groupcloned.com/test/plain/list-recycle-transform.html",
+      "why": "best case infinite scroll from sencha",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { 
+        "action": "scroll",
+        "scrollable_element_function": "function(callback) { callback(document.getElementById('scrollable')); }" 
+      }
+    },
+    {
+      "url": "http://groupcloned.com/test/plain/list-animation-simple.html",
+      "why": "lots of layers all animating",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { "action": "wait", "seconds": 10 }
+    },
+    {
+      "url": "http://www.polymer-project.org/polymer-all/labs/list/static-scroll-display.html",
+      "why": "",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { 
+        "action": "scroll",
+        "scrollable_element_function": "function(callback) { callback(document.getElementById('list')); }" 
+      }
+    },
+    {
+      "url": "http://www.polymer-project.org/polymer-all/labs/list/virtual-scroll-examples.html",
+      "why": "",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { 
+        "action": "scroll",
+        "scrollable_element_function": "function(callback) { callback(document.getElementById('list')); }" 
+      }
+    },
+    {
+      "url": "http://groupcloned.com/test/plain/sticky-using-webkit-backface-visibility.html",
+      "why": "",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { 
+        "action": "scroll",
+        "scrollable_element_function": "function(callback) { callback(document.getElementById('container')); }" 
+      }
+    },
+    {
+      "url": "http://pr.gg/scroll6_even_faster.html",
+      "why": "reduced version of ui toolkit static scroll case",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { 
+        "action": "scroll",
+        "scrollable_element_function": "function(callback) { callback(document.getElementsByClassName('container')[0]); }" 
+      }
+    },
+    {
+      "url": "http://staff.tumblr.com/",
+      "why": "long jank at the start of every scroll gesture (due to layout?)",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { "action": "scroll" }
+    },
+    {
+      "url": "http://jsfiddle.net/mdxJ7/3/show",
+      "why": "only the green div should repaint",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { "action": "wait", "seconds": 5 }
+    },
+    {
+      "url": "http://jsfiddle.net/3yDKh/1/show",
+      "why": "only the red div should repaint",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { "action": "wait", "seconds": 5 }
+    },
+    {
+      "url": "http://jsfiddle.net/3yDKh/3/show",
+      "why": "margin top animation",
+      "navigate_steps" : [
+        { "action": "navigate" },
+        { "action": "wait", "seconds": 2 }
+      ],
+      "smoothness": { "action": "wait", "seconds": 5 }
+    }
+  ]
+}
diff --git a/tools/perf/page_sets/presubmit_unittest.py b/tools/perf/page_sets/presubmit_unittest.py
new file mode 100644
index 0000000..0852d81
--- /dev/null
+++ b/tools/perf/page_sets/presubmit_unittest.py
@@ -0,0 +1,125 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import unittest
+
+from telemetry.unittest import system_stub
+
+from page_sets import PRESUBMIT
+
+
+class AffectedFileStub(object):
+  def __init__(self, absolute_local_path):
+    self._absolute_local_path = absolute_local_path
+
+  def AbsoluteLocalPath(self):
+    return self._absolute_local_path
+
+
+class InputAPIStub(object):
+  def __init__(self, paths, deleted_paths=None):
+    self._paths = paths
+    if deleted_paths:
+      self._deleted_paths = deleted_paths
+    else:
+      self._deleted_paths = []
+
+  def AffectedFiles(self, include_deletes=True):
+    affected_files = [AffectedFileStub(path) for path in self._paths]
+    if include_deletes:
+      affected_files += [AffectedFileStub(path) for path in self._deleted_paths]
+    return affected_files
+
+  def AbsoluteLocalPaths(self):
+    return [af.AbsoluteLocalPath() for af in self.AffectedFiles()]
+
+
+class OutputAPIStub(object):
+  class PresubmitError(Exception):
+    pass
+
+  class PresubmitNotifyResult(Exception):
+    pass
+
+
+class PresubmitTest(unittest.TestCase):
+  def setUp(self):
+    success_file_hash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
+
+    self._stubs = system_stub.Override(
+        PRESUBMIT, ['cloud_storage', 'open', 'os'])
+    # Files in Cloud Storage.
+    self._stubs.cloud_storage.remote_paths = [
+        'skip'.zfill(40),
+    ]
+    # Local data files and their hashes.
+    self._stubs.cloud_storage.local_file_hashes = {
+        '/path/to/skip.wpr': 'skip'.zfill(40),
+        '/path/to/success.wpr': success_file_hash,
+        '/path/to/wrong_hash.wpr': success_file_hash,
+    }
+    # Local data files.
+    self._stubs.os.path.files = (
+        self._stubs.cloud_storage.local_file_hashes.keys())
+    # Local hash files and their contents.
+    self._stubs.open.files = {
+        '/path/to/invalid_hash.wpr.sha1': 'invalid_hash',
+        '/path/to/missing.wpr.sha1': 'missing'.zfill(40),
+        '/path/to/success.wpr.sha1': success_file_hash,
+        '/path/to/skip.wpr.sha1': 'skip'.zfill(40),
+        '/path/to/wrong_hash.wpr.sha1': 'wronghash'.zfill(40),
+    }
+
+  def tearDown(self):
+    self._stubs.Restore()
+
+  def assertResultCount(self, results, expected_errors, expected_notifications):
+    counts = collections.defaultdict(int)
+    for result in results:
+      counts[type(result)] += 1
+    actual_errors = counts[OutputAPIStub.PresubmitError]
+    actual_notifications = counts[OutputAPIStub.PresubmitNotifyResult]
+    self.assertEqual(expected_errors, actual_errors,
+        msg='Expected %d errors, but got %d. Results: %s' %
+        (expected_errors, actual_errors, results))
+    self.assertEqual(expected_notifications, actual_notifications,
+        msg='Expected %d notifications, but got %d. Results: %s' %
+        (expected_notifications, actual_notifications, results))
+
+  def _CheckUpload(self, paths, deleted_paths=None):
+    input_api = InputAPIStub(paths, deleted_paths)
+    return PRESUBMIT.CheckChangeOnUpload(input_api, OutputAPIStub())
+
+  def testIgnoreDeleted(self):
+    results = self._CheckUpload([], ['/path/to/deleted.wpr.sha1'])
+    self.assertResultCount(results, 0, 0)
+
+  def testIgnoreNonHashes(self):
+    results = self._CheckUpload(['/path/to/irrelevant.py'])
+    self.assertResultCount(results, 0, 0)
+
+  def testInvalidHash(self):
+    results = self._CheckUpload(['/path/to/invalid_hash.wpr.sha1'])
+    self.assertResultCount(results, 1, 0)
+    self.assertTrue('valid SHA-1 hash' in str(results[0]), msg=results[0])
+
+  def testMissingFile(self):
+    results = self._CheckUpload(['/path/to/missing.wpr.sha1'])
+    self.assertResultCount(results, 1, 0)
+    self.assertTrue('not found' in str(results[0]), msg=results[0])
+
+  def testSkip(self):
+    results = self._CheckUpload(['/path/to/skip.wpr.sha1'])
+    self.assertResultCount(results, 0, 1)
+    self.assertTrue('skipping' in str(results[0]), msg=results[0])
+
+  def testSuccess(self):
+    results = self._CheckUpload(['/path/to/success.wpr.sha1'])
+    self.assertResultCount(results, 0, 1)
+    self.assertTrue('Uploaded' in str(results[0]), msg=results[0])
+
+  def testWrongHash(self):
+    results = self._CheckUpload(['/path/to/wrong_hash.wpr.sha1'])
+    self.assertTrue('does not match' in str(results[0]), msg=results[0])
diff --git a/tools/perf/page_sets/top_25.json b/tools/perf/page_sets/top_25.json
index 3b6bcb4..d8bb35a 100644
--- a/tools/perf/page_sets/top_25.json
+++ b/tools/perf/page_sets/top_25.json
@@ -235,7 +235,6 @@
       },
       "stress_memory": [
         { "action": "click_element", "text": "About" },
-        { "action": "wait", "condition": "navigate" },
         { "action": "wait", "condition": "element", "text": "The Audacity of Hope" },
         { "action": "click_element", "text": "The Audacity of Hope" },
         { "action": "wait", "condition": "navigate" },
@@ -244,7 +243,6 @@
         { "action": "wait", "condition": "navigate" },
         { "action": "wait", "condition": "element", "text": "About" },
         { "action": "click_element", "text": "About" },
-        { "action": "wait", "condition": "navigate" },
         { "action": "wait", "condition": "element", "text": "Elected to U.S. Senate" },
         { "action": "click_element", "text": "Elected to U.S. Senate" },
         { "action": "wait", "condition": "navigate" },
diff --git a/tools/perf/profile_creators/small_profile_creator.py b/tools/perf/profile_creators/small_profile_creator.py
index 0f51a60..9df1637 100644
--- a/tools/perf/profile_creators/small_profile_creator.py
+++ b/tools/perf/profile_creators/small_profile_creator.py
@@ -22,13 +22,13 @@
     # are each opened in a new tab.
     self._NUM_TABS = 5
 
-  def TabForPage(self, page, tab):
+  def TabForPage(self, page, browser):
     idx = page.page_set.pages.index(page)
     # The last _NUM_TABS pages open a new tab.
     if idx <= (len(page.page_set.pages) - self._NUM_TABS):
-      return tab
+      return browser.tabs[0]
     else:
-      return tab.browser.tabs.New()
+      return browser.tabs.New()
 
   def MeasurePage(self, _, tab, results):
     # Can't use WaitForDocumentReadyStateToBeComplete() here due to
diff --git a/tools/perf/record_android_profile.py b/tools/perf/record_android_profile.py
index 262f442..8c8c5ab 100755
--- a/tools/perf/record_android_profile.py
+++ b/tools/perf/record_android_profile.py
@@ -18,6 +18,7 @@
   with browser_to_create.Create() as browser:
     browser.Start()
     output_file = os.path.join(tempfile.mkdtemp(), options.profiler)
+    raw_input('Press enter to start profiling...')
     print '>> Starting profiler', options.profiler
     browser.StartProfiling(options.profiler, output_file)
     print 'Press enter or CTRL+C to stop'
diff --git a/tools/perf/run_benchmark b/tools/perf/run_benchmark
index ea30680..12c0e9e 100755
--- a/tools/perf/run_benchmark
+++ b/tools/perf/run_benchmark
@@ -13,6 +13,7 @@
 
 if __name__ == '__main__':
   test_runner.test_aliases = {
+      'blink_perf': 'blink_perf.all',
       'image_decoding.tough_decoding_cases':
           'image_decoding.image_decoding_measurement',
       'media.tough_media_cases': 'media.tough_video_cases',
diff --git a/tools/perf/run_tests b/tools/perf/run_tests
index 24370d7..45761f6 100755
--- a/tools/perf/run_tests
+++ b/tools/perf/run_tests
@@ -18,15 +18,7 @@
 if __name__ == '__main__':
   top_level_dir = os.path.abspath(os.path.dirname(__file__))
   runner = gtest_testrunner.GTestTestRunner(print_result_after_run=False)
-
-  start_dir = os.path.join(top_level_dir, 'measurements')
-  ret = run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
-
-  start_dir = os.path.join(top_level_dir, 'perf_tools')
-  ret += run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
-
-  start_dir = os.path.join(top_level_dir, 'metrics')
-  ret += run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
+  ret = run_tests.Main(sys.argv[1:], top_level_dir, top_level_dir, runner)
 
   if runner.result:
     runner.result.PrintSummary()
diff --git a/tools/perf/test-info.json b/tools/perf/test-info.json
index faa7a1f..8f346c8 100644
--- a/tools/perf/test-info.json
+++ b/tools/perf/test-info.json
@@ -7,6 +7,10 @@
       "third_party/WebKit/PerformanceTests/"
     ]
   },
+  "canvasmark": {
+    "description": "Runs Canvasmark HTML5, Canvas 2D rendering and javascript benchmark.\n\nCanvasMark tests the HTML5 <canvas> rendering performance for commonly used operations in HTML5 games: bitmaps, canvas drawing, alpha blending, polygon fills, shadows and text functions.(http://www.kevs3d.co.uk/dev/canvasmark/)",
+    "code": ["chrome/src/tools/perf/benchmarks/canvasmark.py"]
+  },
   "cc_perftests":{
     "description":"Microbenchmarks for compositor (cc/) component.",
     "code":[
@@ -59,6 +63,10 @@
   "dromaeo.jslibtraverseprototype":{
     "description":"Traversing a DOM structure using the Prototype JavaScript Library."
   },
+   "html5gaming": {
+    "description": "Impact HTML5 Gaming benchmark.\n\nTests one very specific use case: smooth running games rendered with the <canvas> element. The score for the HTML5-Benchmark takes the total time the browser spent rendering frames (formula is 1000000/(sqrt(totalTime) + lagTime * 0.1)). The benchmark automatically runs at a reasonable screen size. Final score is a indicator for the browser's ability to smoothly run HTML5 games.",
+    "code": ["chrome/src/tools/perf/benchmark/html5gaming.py"]
+  },
   "idb_perf":{
     "description":"Benchmarks for a variety of IndexedDB operations.",
     "code":[
@@ -133,7 +141,7 @@
     "description":"Loading benchmark for the Polymer toolkit's [Pica](http://www.polymer-project.org/polymer-all/projects/pica/index.html) demo app"
   },
   "page_cycler.netsim.top_10":{
-    "description":"Page loading benchmark for a set of 25 top pages recorded in Q2, 2012.  Despite the name, network simulation has not actually been enabled on this test yet."
+    "description":"Page loading benchmark for a set of 10 top pages recorded in June, 2013.  Pages are loaded under the simplisticly simulated bandwidth and RTT constraints of a cable modem (5Mbit/s down, 1Mbit/s up, 28ms RTT). Contention is realistically simulated, but slow start is not. DNS lookups are 'free'."
   },
   "page_cycler.tough_layout_cases":{
     "description":"Page loading benchmark for the slowest layouts observed in the Alexa top 1 million sites in July 2013."
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index 2821e82..49b29a2 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -1,4 +1,4 @@
-{"linux-release-64/sizes/chrome-bss/bss": {"reva": 216421, "revb": 216430, "type": "absolute", "better": "lower", "improve": 523892, "regress": 579040, "sha1": "0b0195e2"},
+{"linux-release-64/sizes/chrome-bss/bss": {"reva": 230886, "revb": 230892, "type": "absolute", "better": "lower", "improve": 424408, "regress": 469084, "sha1": "f2ab2d21"},
  "linux-release-64/sizes/chrome-data/data": {"reva": 203454, "revb": 203474, "type": "absolute", "better": "lower", "improve": 3570183, "regress": 3946094, "sha1": "b0d5e0fc"},
  "linux-release-64/sizes/chrome-si/initializers": {"reva": 229901, "revb": 229901, "type": "absolute", "better": "lower", "improve": 31, "regress": 31, "tolerance": 0, "sha1": "d25642f5"},
  "linux-release-64/sizes/chrome-text/text": {"reva": 221383, "revb": 221385, "type": "absolute", "better": "lower", "improve": 99317037, "regress": 109921487, "sha1": "f4152946"},
@@ -738,7 +738,7 @@
  "xp-release/sizes/chrome.dll/chrome.dll": {"reva": 228457, "revb": 228507, "type": "absolute", "better": "lower", "improve": 34625356, "regress": 38270132, "sha1": "76c63db9"},
  "xp-release/sizes/chrome.exe/chrome.exe": {"reva": 183841, "revb": 184954, "type": "absolute", "better": "lower", "improve": 720358, "regress": 796186, "sha1": "b5aa4523"},
  "xp-release/sizes/mini_installer.exe/mini_installer.exe": {"reva": 223825, "revb": 224162, "type": "absolute", "better": "lower", "improve": 30193766, "regress": 33489255, "sha1": "1cd4e3aa"},
- "xp-release/sizes/npchrome_frame.dll/npchrome_frame.dll": {"reva": 213618, "revb": 213647, "type": "absolute", "better": "lower", "improve": 2320128, "regress": 2567040, "sha1": "a9618db1"},
+ "xp-release/sizes/npchrome_frame.dll/npchrome_frame.dll": {"reva": 230662, "revb": 230712, "type": "absolute", "better": "lower", "improve": 2426649, "regress": 2723482, "sha1": "1f39fef7"},
  "xp-release/sizes/setup.exe/setup.exe": {"reva": 183841, "revb": 184954, "type": "absolute", "better": "lower", "improve": 1080780, "regress": 1195085, "sha1": "c56e884e"},
  "load": true
 }
diff --git a/tools/run-bisect-perf-regression.py b/tools/run-bisect-perf-regression.py
index e8490ad..8180ef4 100755
--- a/tools/run-bisect-perf-regression.py
+++ b/tools/run-bisect-perf-regression.py
@@ -112,7 +112,7 @@
     print
     traceback.print_exc()
     print
-    return None
+    return {}
 
 
 def _OutputFailedResults(text_to_print):
@@ -211,6 +211,12 @@
   cloud_file_link = [t for t in output.splitlines()
       if 'storage.googleapis.com/chromium-telemetry/html-results/' in t]
   if cloud_file_link:
+    # What we're getting here is basically "View online at http://..." so parse
+    # out just the url portion.
+    cloud_file_link = cloud_file_link[0]
+    cloud_file_link = [t for t in cloud_file_link.split(' ')
+        if 'storage.googleapis.com/chromium-telemetry/html-results/' in t]
+    assert cloud_file_link, "Couldn't parse url from output."
     cloud_file_link = cloud_file_link[0]
   else:
     cloud_file_link = ''
@@ -260,7 +266,8 @@
     return 1
 
 
-def _RunBisectionScript(config, working_directory, path_to_file, path_to_goma):
+def _RunBisectionScript(config, working_directory, path_to_file, path_to_goma,
+    dry_run):
   """Attempts to execute src/tools/bisect-perf-regression.py with the parameters
   passed in.
 
@@ -271,10 +278,17 @@
       the depot.
     path_to_file: Path to the bisect-perf-regression.py script.
     path_to_goma: Path to goma directory.
+    dry_run: Do a dry run, skipping sync, build, and performance testing steps.
 
   Returns:
     0 on success, otherwise 1.
   """
+  bisect_utils.OutputAnnotationStepStart('Config')
+  print
+  for k, v in config.iteritems():
+    print '  %s : %s' % (k, v)
+  print
+  bisect_utils.OutputAnnotationStepClosed()
 
   cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'),
          '-c', config['command'],
@@ -313,6 +327,9 @@
   if path_to_goma:
     cmd.append('--use_goma')
 
+  if dry_run:
+    cmd.extend(['--debug_ignore_build', '--debug_ignore_sync',
+        '--debug_ignore_perf_test'])
   cmd = [str(c) for c in cmd]
 
   with Goma(path_to_goma) as goma:
@@ -342,6 +359,11 @@
                     type='str',
                     help='Path to goma directory. If this is supplied, goma '
                     'builds will be enabled.')
+  parser.add_option('--dry_run',
+                    action="store_true",
+                    help='The script will perform the full bisect, but '
+                    'without syncing, building, or running the performance '
+                    'tests.')
   (opts, args) = parser.parse_args()
 
   path_to_current_directory = os.path.abspath(os.path.dirname(sys.argv[0]))
@@ -361,21 +383,26 @@
       return 1
 
     return _RunBisectionScript(config, opts.working_directory,
-        path_to_current_directory, opts.path_to_goma)
+        path_to_current_directory, opts.path_to_goma, opts.dry_run)
   else:
-    path_to_perf_cfg = os.path.join(
-        os.path.abspath(os.path.dirname(sys.argv[0])), 'run-perf-test.cfg')
+    perf_cfg_files = ['run-perf-test.cfg', os.path.join('..', 'third_party',
+        'WebKit', 'Tools', 'run-perf-test.cfg')]
 
-    config = _LoadConfigFile(path_to_perf_cfg)
+    for current_perf_cfg_file in perf_cfg_files:
+      path_to_perf_cfg = os.path.join(
+          os.path.abspath(os.path.dirname(sys.argv[0])), current_perf_cfg_file)
 
-    if config:
-      return _SetupAndRunPerformanceTest(config, path_to_current_directory,
-          opts.path_to_goma)
-    else:
-      print 'Error: Could not load config file. Double check your changes to '\
-            'run-bisect-perf-regression.cfg for syntax errors.'
-      print
-      return 1
+      config = _LoadConfigFile(path_to_perf_cfg)
+      config_has_values = [v for v in config.values() if v]
+
+      if config and config_has_values:
+        return _SetupAndRunPerformanceTest(config, path_to_current_directory,
+            opts.path_to_goma)
+
+    print 'Error: Could not load config file. Double check your changes to '\
+          'run-bisect-perf-regression.cfg/run-perf-test.cfg for syntax errors.'
+    print
+    return 1
 
 
 if __name__ == '__main__':
diff --git a/tools/sharding_supervisor/sharding_supervisor.py b/tools/sharding_supervisor/sharding_supervisor.py
index 9967071..20d7db7 100755
--- a/tools/sharding_supervisor/sharding_supervisor.py
+++ b/tools/sharding_supervisor/sharding_supervisor.py
@@ -3,49 +3,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Defer to run_test_cases.py."""
+"""Defer to --brave-new-test-launcher."""
 
 import os
 import optparse
+import subprocess
 import sys
 
-ROOT_DIR = os.path.dirname(
-    os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-def pop_known_arguments(args):
-  """Extracts known arguments from the args if present."""
-  rest = []
-  run_test_cases_extra_args = []
-  for arg in args:
-    if arg.startswith(('--gtest_filter=', '--gtest_output=', '--clusters=')):
-      run_test_cases_extra_args.append(arg)
-    elif arg in ('--run-manual', '--verbose'):
-      run_test_cases_extra_args.append(arg)
-    elif arg == '--gtest_print_time':
-      # Ignore.
-      pass
-    elif 'interactive_ui_tests' in arg:
-      # Run this test in a single thread. It is useful to run it under
-      # run_test_cases so automatic flaky test workaround is still used.
-      run_test_cases_extra_args.append('-j1')
-      rest.append(arg)
-    elif 'browser_tests' in arg:
-      # Test cases in this executable fire up *a lot* of child processes,
-      # causing huge memory bottleneck. So use less than N-cpus jobs.
-      run_test_cases_extra_args.append('--use-less-jobs')
-      rest.append(arg)
-    else:
-      rest.append(arg)
-
-  # Use --jobs arg if exist.
-  for arg in args:
-    if arg.startswith('--jobs='):
-      run_test_cases_extra_args.append(arg)
-      break
-
-  return run_test_cases_extra_args, rest
-
 
 def main():
   parser = optparse.OptionParser()
@@ -68,34 +32,27 @@
   group.add_option(
       '--retries', type='int', help='Kept as --retries')
   group.add_option(
+      '-j', '--jobs', type='int', help='Number of parallel jobs')
+  group.add_option(
+      '--clusters', type='int', help='Maximum number of tests in a batch')
+  group.add_option(
       '--verbose', action='count', default=0, help='Kept as --verbose')
   parser.add_option_group(group)
 
   parser.disable_interspersed_args()
   options, args = parser.parse_args()
 
-  swarm_client_dir = os.path.join(
-      ROOT_DIR, 'tools', 'swarm_client', 'googletest')
-  sys.path.insert(0, swarm_client_dir)
+  env = os.environ
+  env['GTEST_TOTAL_SHARDS'] = str(options.total_slaves)
+  env['GTEST_SHARD_INDEX'] = str(options.slave_index)
 
-  cmd = [
-    '--shards', str(options.total_slaves),
-    '--index', str(options.slave_index),
-    '--no-dump',
-    '--no-cr',
-  ]
-  if options.timeout is not None:
-    cmd.extend(['--timeout', str(options.timeout)])
-  if options.retries is not None:
-    cmd.extend(['--retries', str(options.retries)])
-  if options.verbose is not None:
-    cmd.extend(['--verbose'] * options.verbose)
+  if options.jobs:
+    args.append('--test-launcher-jobs=%d' % options.jobs)
 
-  run_test_cases_extra_args, rest = pop_known_arguments(args)
+  if options.clusters:
+    args.append('--test-launcher-batch-limit=%d' % options.clusters)
 
-  import run_test_cases  # pylint: disable=F0401
-
-  return run_test_cases.main(cmd + run_test_cases_extra_args + ['--'] + rest)
+  return subprocess.Popen(args + ['--brave-new-test-launcher'], env=env).wait()
 
 
 if __name__ == '__main__':
diff --git a/tools/telemetry/telemetry/core/backends/adb_commands.py b/tools/telemetry/telemetry/core/backends/adb_commands.py
index 24da0c1..eca8b83 100644
--- a/tools/telemetry/telemetry/core/backends/adb_commands.py
+++ b/tools/telemetry/telemetry/core/backends/adb_commands.py
@@ -232,7 +232,7 @@
 
   @property
   def url(self):
-    return 'http://localhost:%i' % self._host_port
+    return 'http://127.0.0.1:%i' % self._host_port
 
   def Close(self):
     for (device_port, _) in self._port_pairs:
diff --git a/tools/telemetry/telemetry/core/backends/chrome/android_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/android_browser_backend.py
index 7c1c1ca..656eb6a 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/android_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/android_browser_backend.py
@@ -17,12 +17,14 @@
 
 
 class AndroidBrowserBackendSettings(object):
-  def __init__(self, adb, activity, cmdline_file, package, pseudo_exec_name):
+  def __init__(self, adb, activity, cmdline_file, package, pseudo_exec_name,
+               supports_tab_control):
     self.adb = adb
     self.activity = activity
     self.cmdline_file = cmdline_file
     self.package = package
     self.pseudo_exec_name = pseudo_exec_name
+    self.supports_tab_control = supports_tab_control
 
   def GetDevtoolsRemotePort(self):
     raise NotImplementedError()
@@ -54,7 +56,8 @@
         activity='com.google.android.apps.chrome.Main',
         cmdline_file='/data/local/chrome-command-line',
         package=package,
-        pseudo_exec_name='chrome')
+        pseudo_exec_name='chrome',
+        supports_tab_control=True)
 
   def GetDevtoolsRemotePort(self):
     return 'localabstract:chrome_devtools_remote'
@@ -74,7 +77,8 @@
         activity='org.chromium.content_shell_apk.ContentShellActivity',
         cmdline_file='/data/local/tmp/content-shell-command-line',
         package=package,
-        pseudo_exec_name='content_shell')
+        pseudo_exec_name='content_shell',
+        supports_tab_control=False)
 
   def GetDevtoolsRemotePort(self):
     return 'localabstract:content_shell_devtools_remote'
@@ -95,7 +99,8 @@
           activity='org.chromium.chrome.testshell.ChromiumTestShellActivity',
           cmdline_file='/data/local/tmp/chromium-testshell-command-line',
           package=package,
-          pseudo_exec_name='chromium_testshell')
+          pseudo_exec_name='chromium_testshell',
+          supports_tab_control=False)
 
   def GetDevtoolsRemotePort(self):
     return 'localabstract:chromium_testshell_devtools_remote'
@@ -116,7 +121,8 @@
         activity='com.android.webview.chromium.shell.TelemetryActivity',
         cmdline_file='/data/local/tmp/webview-command-line',
         package=package,
-        pseudo_exec_name='webview')
+        pseudo_exec_name='webview',
+        supports_tab_control=False)
 
   def GetDevtoolsRemotePort(self):
     # The DevTools socket name for WebView depends on the activity PID's.
@@ -235,12 +241,16 @@
 
   def Start(self):
     self._adb.RunShellCommand('logcat -c')
+    if self.browser_options.startup_url:
+      url = self.browser_options.startup_url
+    else:
+      url = 'about:blank'
     self._adb.StartActivity(self._backend_settings.package,
                             self._backend_settings.activity,
                             True,
                             None,
                             None,
-                            'about:blank')
+                            url)
 
     self._adb.Forward('tcp:%d' % self._port,
                       self._backend_settings.GetDevtoolsRemotePort())
@@ -300,6 +310,10 @@
   def activity(self):
     return self._backend_settings.activity
 
+  @property
+  def supports_tab_control(self):
+    return self._backend_settings.supports_tab_control
+
   def __del__(self):
     self.Close()
 
diff --git a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
index d76316e..f8f620b 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
@@ -218,8 +218,8 @@
       if throw_network_exception:
         raise e
       if not self.IsBrowserRunning():
-        raise exceptions.BrowserGoneException()
-      raise exceptions.BrowserConnectionGoneException()
+        raise exceptions.BrowserGoneException(e)
+      raise exceptions.BrowserConnectionGoneException(e)
 
   @property
   def browser_directory(self):
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
index 6afd064..d3636e6 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
@@ -77,6 +77,8 @@
   def _LaunchBrowser(self):
     args = [self._executable]
     args.extend(self.GetBrowserStartupArgs())
+    if self.browser_options.startup_url:
+      args.append(self.browser_options.startup_url)
     env = os.environ.copy()
     env['CHROME_HEADLESS'] = '1'  # Don't upload minidumps.
     env['BREAKPAD_DUMP_LOCATION'] = self._tmp_minidump_dir
@@ -182,7 +184,9 @@
       return self.GetStandardOutput()
 
     symbols_path = os.path.join(self._tmp_minidump_dir, 'symbols')
-    for symbol in symbols:
+    for symbol in sorted(symbols, key=os.path.getmtime, reverse=True):
+      if not os.path.isfile(symbol):
+        continue
       with open(symbol, 'r') as f:
         fields = f.readline().split()
         if not fields:
@@ -190,6 +194,8 @@
         sha = fields[3]
         binary = ' '.join(fields[4:])
       symbol_path = os.path.join(symbols_path, binary, sha)
+      if os.path.exists(symbol_path):
+        continue
       os.makedirs(symbol_path)
       shutil.copyfile(symbol, os.path.join(symbol_path, binary + '.sym'))
 
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
index 7baed52..d06e07b 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
@@ -4,7 +4,6 @@
 """Finds desktop browsers that can be controlled by telemetry."""
 
 import logging
-from operator import attrgetter
 import os
 import platform
 import subprocess
@@ -41,7 +40,8 @@
     self.is_local_build = is_local_build
 
   def __repr__(self):
-    return 'PossibleDesktopBrowser(browser_type=%s)' % self.browser_type
+    return 'PossibleDesktopBrowser(browser_type=%s, executable=%s)' % (
+        self.browser_type, self._local_executable)
 
   def Create(self):
     backend = desktop_browser_backend.DesktopBrowserBackend(
@@ -61,7 +61,6 @@
   def UpdateExecutableIfNeeded(self):
     pass
 
-  @property
   def last_modification_time(self):
     if os.path.exists(self._local_executable):
       return os.path.getmtime(self._local_executable)
@@ -70,7 +69,7 @@
 def SelectDefaultBrowser(possible_browsers):
   local_builds_by_date = [
       b for b in sorted(possible_browsers,
-                        key=attrgetter('last_modification_time'))
+                        key=lambda b: b.last_modification_time())
       if b.is_local_build]
   if local_builds_by_date:
     return local_builds_by_date[-1]
@@ -97,8 +96,10 @@
   else:
     chrome_root = util.GetChromiumSrcDir()
 
+  chromium_app_names = []
   if sys.platform == 'darwin':
-    chromium_app_name = 'Chromium.app/Contents/MacOS/Chromium'
+    chromium_app_names.append('Chromium.app/Contents/MacOS/Chromium')
+    chromium_app_names.append('Google Chrome.app/Contents/MacOS/Google Chrome')
     content_shell_app_name = 'Content Shell.app/Contents/MacOS/Content Shell'
     mac_dir = 'mac'
     if platform.architecture()[0] == '64bit':
@@ -107,7 +108,7 @@
         chrome_root, 'third_party', 'adobe', 'flash', 'binaries', 'ppapi',
         mac_dir, 'PepperFlashPlayer.plugin')
   elif sys.platform.startswith('linux'):
-    chromium_app_name = 'chrome'
+    chromium_app_names.append('chrome')
     content_shell_app_name = 'content_shell'
     linux_dir = 'linux'
     if platform.architecture()[0] == '64bit':
@@ -116,7 +117,7 @@
         chrome_root, 'third_party', 'adobe', 'flash', 'binaries', 'ppapi',
         linux_dir, 'libpepflashplayer.so')
   elif sys.platform.startswith('win'):
-    chromium_app_name = 'chrome.exe'
+    chromium_app_names.append('chrome.exe')
     content_shell_app_name = 'content_shell.exe'
     win_dir = 'win'
     if platform.architecture()[0] == '64bit':
@@ -156,8 +157,9 @@
 
   # Add local builds
   for build_dir, build_type in util.GetBuildDirectories():
-    AddIfFound(build_type.lower(), build_dir, build_type,
-               chromium_app_name, False)
+    for chromium_app_name in chromium_app_names:
+      AddIfFound(build_type.lower(), build_dir, build_type,
+                 chromium_app_name, False)
     AddIfFound('content-shell-' + build_type.lower(), build_dir, build_type,
                content_shell_app_name, True)
 
@@ -203,11 +205,12 @@
 
     def AddIfFoundWin(browser_name, app_path):
       browser_directory = os.path.join(path, app_path)
-      app = os.path.join(browser_directory, chromium_app_name)
-      if IsExecutable(app):
-        browsers.append(PossibleDesktopBrowser(browser_name, finder_options,
-                                               app, flash_path, False,
-                                               browser_directory))
+      for chromium_app_name in chromium_app_names:
+        app = os.path.join(browser_directory, chromium_app_name)
+        if IsExecutable(app):
+          browsers.append(PossibleDesktopBrowser(browser_name, finder_options,
+                                                 app, flash_path, False,
+                                                 browser_directory))
         return True
       return False
 
diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
index 05b26a6..4770c4e 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
@@ -6,8 +6,8 @@
 import socket
 import sys
 
-from telemetry.core import util
 from telemetry.core import exceptions
+from telemetry.core import util
 from telemetry.core.backends import png_bitmap
 from telemetry.core.backends.chrome import inspector_console
 from telemetry.core.backends.chrome import inspector_memory
@@ -87,18 +87,6 @@
 
   # Public methods implemented in JavaScript.
 
-  def WaitForDocumentReadyStateToBeComplete(self, timeout):
-    util.WaitFor(
-        lambda: self._runtime.Evaluate('document.readyState') == 'complete',
-        timeout)
-
-  def WaitForDocumentReadyStateToBeInteractiveOrBetter(
-      self, timeout):
-    def IsReadyStateInteractiveOrBetter():
-      rs = self._runtime.Evaluate('document.readyState')
-      return rs == 'complete' or rs == 'interactive'
-    util.WaitFor(IsReadyStateInteractiveOrBetter, timeout)
-
   @property
   def screenshot_supported(self):
     if self._runtime.Evaluate(
diff --git a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py
index debb334..b7e957e 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py
@@ -129,7 +129,8 @@
                        if t is not None and t not in self._tab_list]
 
   def _FindTabInfo(self, debugger_url):
+    tab_id = debugger_url.split('/')[-1]
     for tab_info in self._ListTabs():
-      if tab_info.get('webSocketDebuggerUrl') == debugger_url:
+      if tab_info.get('id') == tab_id:
         return tab_info
     return None
diff --git a/tools/telemetry/telemetry/core/browser_finder.py b/tools/telemetry/telemetry/core/browser_finder.py
index 02e19b8..1895f34 100644
--- a/tools/telemetry/telemetry/core/browser_finder.py
+++ b/tools/telemetry/telemetry/core/browser_finder.py
@@ -1,6 +1,7 @@
 # Copyright (c) 2012 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.
+
 """Finds browsers that can be controlled by telemetry."""
 
 import logging
@@ -23,15 +24,22 @@
 class BrowserTypeRequiredException(Exception):
   pass
 
+
 class BrowserFinderException(Exception):
   pass
 
+
 def FindBrowser(options):
-  """Finds the best PossibleBrowser object to run given the provided
-  BrowserOptions object. The returned possiblity object can then be used to
-  connect to and control the located browser. A BrowserFinderException will
-  be raised if the BrowserOptions argument is improperly set or if an error
-  occurs when finding a browser.
+  """Finds the best PossibleBrowser object given a BrowserOptions object.
+
+  Args:
+    A BrowserOptions object.
+
+  Returns:
+    A PossibleBrowser object.
+
+  Raises:
+    BrowserFinderException: Options improperly set, or an error occurred.
   """
   if options.browser_type == 'exact' and options.browser_executable == None:
     raise BrowserFinderException(
@@ -50,32 +58,42 @@
         '--remote requires --browser=cros-chrome or cros-chrome-guest.')
 
   browsers = []
-  default_browser = None
+  default_browsers = []
   for finder in BROWSER_FINDERS:
     curr_browsers = finder.FindAllAvailableBrowsers(options)
-    if not default_browser:
-      default_browser = finder.SelectDefaultBrowser(curr_browsers)
+    new_default_browser = finder.SelectDefaultBrowser(curr_browsers)
+    if new_default_browser:
+      default_browsers.append(new_default_browser)
     browsers.extend(curr_browsers)
 
   if options.browser_type == None:
-    if default_browser:
+    if default_browsers:
+      default_browser = sorted(default_browsers,
+                               key=lambda b: b.last_modification_time())[-1]
+
       logging.warning('--browser omitted. Using most recent local build: %s' %
                       default_browser.browser_type)
       options.browser_type = default_browser.browser_type
       # TODO: We should do this even when --browser is specified.
       default_browser.UpdateExecutableIfNeeded()
       return default_browser
+
+    if len(browsers) == 1:
+      logging.warning('--browser omitted. Using only available browser: %s' %
+                      browsers[0].browser_type)
+      return browsers[0]
+
     raise BrowserTypeRequiredException(
         '--browser must be specified. Available browsers:\n%s' %
         '\n'.join(sorted(set([b.browser_type for b in browsers]))))
 
   if options.browser_type == 'any':
     types = ALL_BROWSER_TYPES.split(',')
-    def compare_browsers_on_type_priority(x, y):
+    def CompareBrowsersOnTypePriority(x, y):
       x_idx = types.index(x.browser_type)
       y_idx = types.index(y.browser_type)
       return x_idx - y_idx
-    browsers.sort(compare_browsers_on_type_priority)
+    browsers.sort(CompareBrowsersOnTypePriority)
     if len(browsers) >= 1:
       return browsers[0]
     else:
@@ -84,19 +102,32 @@
   matching_browsers = [b for b in browsers
       if b.browser_type == options.browser_type and b.SupportsOptions(options)]
 
+  chosen_browser = None
   if len(matching_browsers) == 1:
-    return matching_browsers[0]
+    chosen_browser = matching_browsers[0]
   elif len(matching_browsers) > 1:
     logging.warning('Multiple browsers of the same type found: %s' % (
                     repr(matching_browsers)))
-    return matching_browsers[0]
-  else:
-    return None
+    chosen_browser = sorted(matching_browsers,
+                            key=lambda b: b.last_modification_time())[-1]
+
+  if chosen_browser:
+    logging.info('Chose browser: %s' % (repr(chosen_browser)))
+
+  return chosen_browser
+
 
 def GetAllAvailableBrowserTypes(options):
-  """Returns an array of browser types supported on this system.
-  A BrowserFinderException will be raised if the BrowserOptions argument is
-  improperly set or if an error occurs when finding a browser.
+  """Returns a list of available browser types.
+
+  Args:
+    options: A BrowserOptions object.
+
+  Returns:
+    A list of browser type strings.
+
+  Raises:
+    BrowserFinderException: Options are improperly set, or an error occurred.
   """
   browsers = []
   for finder in BROWSER_FINDERS:
@@ -106,3 +137,4 @@
   type_list = list(type_list)
   type_list.sort()
   return type_list
+
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index cd12d65..7e9b68b 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -210,6 +210,7 @@
     self.browser_user_agent_type = None
 
     self.clear_sytem_cache_for_browser_and_profile_on_start = False
+    self.startup_url = None
 
     self.keep_test_server_ports = False
 
diff --git a/tools/telemetry/telemetry/core/discover.py b/tools/telemetry/telemetry/core/discover.py
index 28a1767..bfdd6e9 100644
--- a/tools/telemetry/telemetry/core/discover.py
+++ b/tools/telemetry/telemetry/core/discover.py
@@ -67,13 +67,27 @@
   classes = {}
   for module in modules:
     for _, obj in inspect.getmembers(module):
-      if (inspect.isclass(obj) and obj is not base_class and
-          issubclass(obj, base_class) and obj.__module__ == module.__name__
-          and len(obj.__subclasses__()) == 0):
-        if index_by_class_name:
-          key_name = camel_case.ToUnderscore(obj.__name__)
-        else:
-          key_name = module.__name__.split('.')[-1]
-        classes[key_name] = obj
+      # Ensure object is a class.
+      if not inspect.isclass(obj):
+        continue
+      # Include only subclasses of base_class.
+      if not issubclass(obj, base_class):
+        continue
+      # Exclude the base_class itself.
+      if obj is base_class:
+        continue
+      # Exclude protected or private classes.
+      if obj.__name__.startswith('_'):
+        continue
+      # Include only the module in which the class is defined.
+      # If a class is imported by another module, exclude those duplicates.
+      if obj.__module__ != module.__name__:
+        continue
+
+      if index_by_class_name:
+        key_name = camel_case.ToUnderscore(obj.__name__)
+      else:
+        key_name = module.__name__.split('.')[-1]
+      classes[key_name] = obj
 
   return classes
diff --git a/tools/telemetry/telemetry/core/discover_unittest.py b/tools/telemetry/telemetry/core/discover_unittest.py
index 9fa0c11..34bc891 100644
--- a/tools/telemetry/telemetry/core/discover_unittest.py
+++ b/tools/telemetry/telemetry/core/discover_unittest.py
@@ -8,16 +8,45 @@
 from telemetry.core import util
 
 class DiscoverTest(unittest.TestCase):
-  def testDiscoverClasses(self):
-    base_dir = util.GetUnittestDataDir()
-    start_dir = os.path.join(base_dir, 'discoverable_classes')
-    base_class = Exception
-    classes = discover.DiscoverClasses(start_dir, base_dir, base_class)
-    self.assertTrue(len(classes) > 0)
-    for c in classes.values():
-      self.assertTrue(issubclass(c, Exception))
+  def setUp(self):
+    self._base_dir = util.GetUnittestDataDir()
+    self._start_dir = os.path.join(self._base_dir, 'discoverable_classes')
+    self._base_class = Exception
 
-    # discover_dummyclass is a base class and should not show up.
-    self.assertFalse('discover_dummyclass' in classes)
-    self.assertEqual(classes['another_discover_dummyclass'].__name__,
-                     'AnotherDummyException')
+  def testDiscoverClassesBasic(self):
+    classes = discover.DiscoverClasses(
+        self._start_dir, self._base_dir, self._base_class)
+
+    actual_classes = dict(
+        (name, cls.__name__) for name, cls in classes.iteritems())
+    expected_classes = {
+        'discover_dummyclass': 'DummyException',
+        'another_discover_dummyclass': 'DummyExceptionImpl2',
+    }
+    self.assertEqual(actual_classes, expected_classes)
+
+  def testDiscoverClassesWithPattern(self):
+    classes = discover.DiscoverClasses(
+        self._start_dir, self._base_dir, self._base_class,
+        pattern='another*')
+
+    actual_classes = dict(
+        (name, cls.__name__) for name, cls in classes.iteritems())
+    expected_classes = {
+        'another_discover_dummyclass': 'DummyExceptionImpl2',
+    }
+    self.assertEqual(actual_classes, expected_classes)
+
+  def testDiscoverClassesByClassName(self):
+    classes = discover.DiscoverClasses(
+        self._start_dir, self._base_dir, self._base_class,
+        index_by_class_name=True)
+
+    actual_classes = dict(
+        (name, cls.__name__) for name, cls in classes.iteritems())
+    expected_classes = {
+        'dummy_exception': 'DummyException',
+        'dummy_exception_impl1': 'DummyExceptionImpl1',
+        'dummy_exception_impl2': 'DummyExceptionImpl2',
+    }
+    self.assertEqual(actual_classes, expected_classes)
diff --git a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
index e2bceaa..0182327 100644
--- a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
@@ -24,15 +24,24 @@
     assert flush_command, \
         'You must build %s first' % self.GetFlushUtilityName()
 
-    args = [flush_command, '--recurse']
+    args = []
     directory_contents = os.listdir(directory)
     for item in directory_contents:
       if not ignoring or item not in ignoring:
         args.append(os.path.join(directory, item))
 
-    if len(args) < 3:
+    if not args:
       return
 
-    p = subprocess.Popen(args)
-    p.wait()
-    assert p.returncode == 0, 'Failed to flush system cache'
+    # According to msdn:
+    # http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx
+    # there's a maximum allowable command line of 32,768 characters on windows.
+    while args:
+      # Small note about [:256] and [256:]
+      # [:N] will return a list with the first N elements, ie.
+      # with [1,2,3,4,5], [:2] -> [1,2], and [2:] -> [3,4,5]
+      # with [1,2,3,4,5], [:5] -> [1,2,3,4,5] and [5:] -> []
+      p = subprocess.Popen([flush_command, '--recurse'] + args[:256])
+      p.wait()
+      assert p.returncode == 0, 'Failed to flush system cache'
+      args = args[256:]
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
index afc43e7..ce120ab 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
@@ -70,8 +70,7 @@
       self._browser_backend.adb.RunShellCommand('am dumpheap %s %s' %
                                                 (pid, device_dump_file))
     if device_dump_file and wait_for_completion:
-      util.WaitFor(lambda: self._FileSize(device_dump_file) > 0,
-                   timeout=2, poll_interval=0.5)
+      util.WaitFor(lambda: self._FileSize(device_dump_file) > 0, timeout=2)
     self._run_count += 1
 
   def _FileSize(self, file_name):
diff --git a/tools/telemetry/telemetry/core/possible_browser.py b/tools/telemetry/telemetry/core/possible_browser.py
index 3907f63..2d6ce66 100644
--- a/tools/telemetry/telemetry/core/possible_browser.py
+++ b/tools/telemetry/telemetry/core/possible_browser.py
@@ -28,3 +28,6 @@
   def SupportsOptions(self, finder_options):
     """Tests for extension support."""
     raise NotImplementedError()
+
+  def last_modification_time(self):
+    return -1
diff --git a/tools/telemetry/telemetry/core/temporary_http_server_unittest.py b/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
index 1fa76fe..399a2a1 100644
--- a/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
+++ b/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
@@ -67,8 +67,7 @@
         xmlhttp.send();
     """ % (browser.http_server.UrlOf('/%s' % self.test_file),
            content_range_request))
-    util.WaitFor(lambda: tab.EvaluateJavaScript('loaded == true'),
-                 timeout=5, poll_interval=1)
+    tab.WaitForJavaScriptExpression('loaded', 5)
     content_range = tab.EvaluateJavaScript(
         'xmlhttp.getResponseHeader("Content-Range");')
     content_range_response = 'bytes %s/%d' % (
diff --git a/tools/telemetry/telemetry/core/timeline/thread.py b/tools/telemetry/telemetry/core/timeline/thread.py
index 47194ac..bd5f439 100644
--- a/tools/telemetry/telemetry/core/timeline/thread.py
+++ b/tools/telemetry/telemetry/core/timeline/thread.py
@@ -66,7 +66,6 @@
 
   def IterEventsInThisContainer(self):
     return itertools.chain(
-      iter(self._open_slices),
       iter(self._newly_added_slices),
       self.IterAllAsyncSlices(),
       self.IterAllSlices(),
@@ -99,8 +98,11 @@
     if len(self._open_slices) > 0 and timestamp < self._open_slices[-1].start:
       raise ValueError(
           'Slices must be added in increasing timestamp order')
-    self._open_slices.append(
-        tracing_slice.Slice(self, category, name, timestamp, args=args))
+    new_slice = tracing_slice.Slice(self, category, name, timestamp, args=args)
+    self._open_slices.append(new_slice)
+    new_slice.did_not_finish = True
+    self.PushSlice(new_slice)
+    return new_slice
 
   def EndSlice(self, end_timestamp):
     """ Ends the last begun slice in this group and pushes it onto the slice
@@ -118,16 +120,28 @@
       raise ValueError(
           'Slice %s end time is before its start.' % curr_slice.name)
     curr_slice.duration = end_timestamp - curr_slice.start
-    return self.PushSlice(curr_slice)
+    curr_slice.did_not_finish = False
+    return curr_slice
+
+  def PushCompleteSlice(self, category, name, timestamp, duration, args=None):
+    new_slice = tracing_slice.Slice(self, category, name, timestamp, args=args)
+    if duration == None:
+      new_slice.did_not_finish = True
+    else:
+      new_slice.duration = duration
+    self.PushSlice(new_slice)
+    return new_slice
 
   def PushSlice(self, new_slice):
     self._newly_added_slices.append(new_slice)
     return new_slice
 
   def AutoCloseOpenSlices(self, max_timestamp):
-    while len(self._open_slices) > 0:
-      curr_slice = self.EndSlice(max_timestamp)
-      curr_slice.did_not_finish = True
+    for s in self._newly_added_slices:
+      if s.did_not_finish:
+        s.duration = max_timestamp - s.start
+        assert s.duration >= 0
+    self._open_slices = []
 
   def IsTimestampValidForBeginOrEnd(self, timestamp):
     if not len(self._open_slices):
@@ -197,7 +211,11 @@
     of all other slices seen so far, we can just check the last slice
     of each row for bounding.
     '''
-    if child.start >= root.start and child.end <= root.end:
+    # Due to inaccuracy of floating-point calculation, the end times of slices
+    # from B/E pair (whose end = start + original_end - start) and an X Event
+    # (whose end = start + duration) at the same time may become not equal.
+    # Tolerate 1ps error for slice.end.
+    if child.start >= root.start and child.end - root.end < 1e-9:
       if len(root.sub_slices) > 0:
         if self._AddSliceIfBounds(root.sub_slices[-1], child):
           return True
diff --git a/tools/telemetry/telemetry/core/timeline/trace_event_importer.py b/tools/telemetry/telemetry/core/timeline/trace_event_importer.py
index c27a7d0..029c6c9 100644
--- a/tools/telemetry/telemetry/core/timeline/trace_event_importer.py
+++ b/tools/telemetry/telemetry/core/timeline/trace_event_importer.py
@@ -170,6 +170,15 @@
               'The value of the E phase event will be used.')
         new_slice.args[arg_name] = arg_value
 
+  def _ProcessCompleteEvent(self, event):
+    thread = (self._GetOrCreateProcess(event['pid'])
+        .GetOrCreateThread(event['tid']))
+    thread.PushCompleteSlice(event['cat'],
+                             event['name'],
+                             event['ts'] / 1000.0,
+                             event['dur'] / 1000.0 if 'dur' in event else None,
+                             event['args'])
+
   def _ProcessMetadataEvent(self, event):
     if event['name'] == 'thread_name':
       thread = (self._GetOrCreateProcess(event['pid'])
@@ -209,6 +218,8 @@
       phase = event.get('ph', None)
       if phase == 'B' or phase == 'E':
         self._ProcessDurationEvent(event)
+      elif phase == 'X':
+        self._ProcessCompleteEvent(event)
       elif phase == 'S' or phase == 'F' or phase == 'T':
         self._ProcessAsyncEvent(event)
       # Note, I is historic. The instant event marker got changed, but we
diff --git a/tools/telemetry/telemetry/core/timeline/trace_event_importer_unittest.py b/tools/telemetry/telemetry/core/timeline/trace_event_importer_unittest.py
index 1aa6a3b..2467913 100644
--- a/tools/telemetry/telemetry/core/timeline/trace_event_importer_unittest.py
+++ b/tools/telemetry/telemetry/core/timeline/trace_event_importer_unittest.py
@@ -919,3 +919,39 @@
     t = p.threads[53]
     self.assertEqual(3, len(t.samples))
     self.assertEqual(0, len(m.import_errors))
+
+  def testImportCompleteEvent(self):
+    events = [
+      {'name': 'a', 'args': {}, 'pid': 52, 'ts': 629, 'dur': 1, 'cat': 'baz',
+       'tid': 53, 'ph': 'X'},
+      {'name': 'b', 'args': {}, 'pid': 52, 'ts': 730, 'dur': 20, 'cat': 'foo',
+       'tid': 53, 'ph': 'X'},
+      {'name': 'c', 'args': {}, 'pid': 52, 'ts': 740, 'cat': 'baz',
+       'tid': 53, 'ph': 'X'},
+    ]
+    m = timeline_model.TimelineModel(event_data=events)
+    p = m.GetAllProcesses()[0]
+    t = p.threads[53]
+    self.assertEqual(3, len(t.all_slices))
+
+    slice_event = t.all_slices[0]
+    self.assertEqual('a', slice_event.name)
+    self.assertAlmostEqual(0.0, slice_event.start)
+    self.assertAlmostEqual(1 / 1000.0, slice_event.duration)
+    self.assertFalse(slice_event.did_not_finish)
+    self.assertEqual(0, len(slice_event.sub_slices))
+
+    slice_event = t.all_slices[1]
+    self.assertEqual('b', slice_event.name)
+    self.assertAlmostEqual((730 - 629) / 1000.0, slice_event.start)
+    self.assertAlmostEqual(20 / 1000.0, slice_event.duration)
+    self.assertFalse(slice_event.did_not_finish)
+    self.assertEqual(1, len(slice_event.sub_slices))
+    self.assertEqual(t.all_slices[2], slice_event.sub_slices[0])
+
+    slice_event = t.all_slices[2]
+    self.assertEqual('c', slice_event.name)
+    self.assertAlmostEqual((740 - 629) / 1000.0, slice_event.start)
+    self.assertAlmostEqual(10 / 1000.0, slice_event.duration)
+    self.assertTrue(slice_event.did_not_finish)
+    self.assertEqual(0, len(slice_event.sub_slices))
diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py
index 59cf52f..8d8eefb 100644
--- a/tools/telemetry/telemetry/core/util.py
+++ b/tools/telemetry/telemetry/core/util.py
@@ -39,18 +39,25 @@
     sys.path.append(path)
 
 
-def WaitFor(condition,
-            timeout, poll_interval=0.1,
-            pass_time_left_to_func=False):
+def WaitFor(condition, timeout, pass_time_left_to_func=False):
+  """Waits for up to |timeout| secs for the function |condition| to return True.
+
+  Polling frequency is (elapsed_time / 10), with a min of .1s and max of 5s.
+
+  Returns:
+    Result of |condition| function (if present).
+  """
   start_time = time.time()
   while True:
+    elapsed_time = time.time() - start_time
     if pass_time_left_to_func:
-      res = condition(max((start_time + timeout) - time.time(), 0.0))
+      remaining_time = timeout - elapsed_time
+      res = condition(max(remaining_time, 0.0))
     else:
       res = condition()
     if res:
       return res
-    if time.time() - start_time > timeout:
+    if elapsed_time > timeout:
       if condition.__name__ == '<lambda>':
         try:
           condition_string = inspect.getsource(condition).strip()
@@ -60,6 +67,7 @@
         condition_string = condition.__name__
       raise TimeoutException('Timed out while waiting %ds for %s.' %
                              (timeout, condition_string))
+    poll_interval = min(max(elapsed_time / 10., .1), 5)
     time.sleep(poll_interval)
 
 
@@ -113,7 +121,7 @@
 def GetBuildDirectories():
   """Yields all combination of Chromium build output directories."""
   build_dirs = ['build',
-                'out',
+                os.path.basename(os.environ.get('CHROMIUM_OUT_DIR', 'out')),
                 'xcodebuild']
 
   build_types = ['Debug', 'Debug_x64', 'Release', 'Release_x64']
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py
index ba10ebf..253b80d 100644
--- a/tools/telemetry/telemetry/core/web_contents.py
+++ b/tools/telemetry/telemetry/core/web_contents.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from telemetry.core import util
+
 DEFAULT_WEB_CONTENTS_TIMEOUT = 90
 
 # TODO(achuith, dtu, nduca): Add unit tests specifically for WebContents,
@@ -26,12 +28,29 @@
 
   def WaitForDocumentReadyStateToBeComplete(self,
       timeout=DEFAULT_WEB_CONTENTS_TIMEOUT):
-    self._inspector_backend.WaitForDocumentReadyStateToBeComplete(timeout)
+    self.WaitForJavaScriptExpression(
+        'document.readyState == "complete"', timeout)
 
   def WaitForDocumentReadyStateToBeInteractiveOrBetter(self,
       timeout=DEFAULT_WEB_CONTENTS_TIMEOUT):
-    self._inspector_backend.WaitForDocumentReadyStateToBeInteractiveOrBetter(
-        timeout)
+    self.WaitForJavaScriptExpression(
+        'document.readyState == "interactive" || '
+        'document.readyState == "complete"', timeout)
+
+  def WaitForJavaScriptExpression(self, expr, timeout):
+    """Waits for the given JavaScript expression to be True.
+
+    This method is robust against any given Evaluation timing out.
+    """
+    def IsTrue():
+      try:
+        return bool(self.EvaluateJavaScript(expr))
+      except util.TimeoutException:
+        # If the main thread is busy for longer than Evaluate's timeout, we
+        # may time out here early. Instead, we want to wait for the full
+        # timeout of this method.
+        return False
+    util.WaitFor(IsTrue, timeout)
 
   def ExecuteJavaScript(self, expr, timeout=DEFAULT_WEB_CONTENTS_TIMEOUT):
     """Executes expr in JavaScript. Does not return the result.
diff --git a/tools/telemetry/telemetry/page/actions/loop.py b/tools/telemetry/telemetry/page/actions/loop.py
index db6c220..1e96829 100644
--- a/tools/telemetry/telemetry/page/actions/loop.py
+++ b/tools/telemetry/telemetry/page/actions/loop.py
@@ -15,8 +15,8 @@
 """
 
 from telemetry.core import exceptions
+from telemetry.page.actions import media_action
 from telemetry.page.actions import page_action
-import telemetry.page.actions.media_action as media_action
 
 
 class LoopAction(media_action.MediaAction):
diff --git a/tools/telemetry/telemetry/page/actions/media_action.py b/tools/telemetry/telemetry/page/actions/media_action.py
index c68dcde..5baf023 100644
--- a/tools/telemetry/telemetry/page/actions/media_action.py
+++ b/tools/telemetry/telemetry/page/actions/media_action.py
@@ -24,8 +24,7 @@
       js = f.read()
       tab.ExecuteJavaScript(js)
 
-  def WaitForEvent(self, tab, selector, event_name, timeout,
-                   poll_interval=0.5):
+  def WaitForEvent(self, tab, selector, event_name, timeout):
     """Halts media action until the selector's event is fired.
 
     Args:
@@ -33,11 +32,10 @@
       selector: Media element selector.
       event_name: Name of the event to check if fired or not.
       timeout: Timeout to check for event, throws an exception if not fired.
-      poll_interval: Interval to poll for event firing status.
     """
     util.WaitFor(lambda: self.HasEventCompleted(tab, selector, event_name),
-                 timeout=timeout, poll_interval=poll_interval)
+                 timeout=timeout)
 
   def HasEventCompleted(self, tab, selector, event_name):
     return tab.EvaluateJavaScript(
-        'window.__hasEventCompleted("%s", "%s");' % (selector, event_name))
\ No newline at end of file
+        'window.__hasEventCompleted("%s", "%s");' % (selector, event_name))
diff --git a/tools/telemetry/telemetry/page/actions/pinch.py b/tools/telemetry/telemetry/page/actions/pinch.py
index d0e8f29..4fd5c86 100644
--- a/tools/telemetry/telemetry/page/actions/pinch.py
+++ b/tools/telemetry/telemetry/page/actions/pinch.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 import os
 
-from telemetry.core import util
 from telemetry.page.actions import page_action
 
 class PinchAction(page_action.PageAction):
@@ -39,9 +38,7 @@
     tab.ExecuteJavaScript('window.__pinchAction.start(%s, %f)'
                           % ("true" if zoom_in else "false", pixels_to_move))
 
-    # Poll for pinch action completion.
-    util.WaitFor(lambda: tab.EvaluateJavaScript(
-        'window.__pinchActionDone'), 60)
+    tab.WaitForJavaScriptExpression('window.__pinchActionDone', 60)
 
   def CanBeBound(self):
     return True
diff --git a/tools/telemetry/telemetry/page/actions/play.py b/tools/telemetry/telemetry/page/actions/play.py
index 3f67371..9fdf905 100644
--- a/tools/telemetry/telemetry/page/actions/play.py
+++ b/tools/telemetry/telemetry/page/actions/play.py
@@ -12,12 +12,12 @@
 the action to wait until playing and ended events get fired respectively.
 """
 
-from telemetry.page.actions.media_action import MediaAction
 from telemetry.core import exceptions
+from telemetry.page.actions import media_action
 from telemetry.page.actions import page_action
 
 
-class PlayAction(MediaAction):
+class PlayAction(media_action.MediaAction):
   def __init__(self, attributes=None):
     super(PlayAction, self).__init__(attributes)
 
diff --git a/tools/telemetry/telemetry/page/actions/scroll.py b/tools/telemetry/telemetry/page/actions/scroll.py
index e7f2680..0d7fc42 100644
--- a/tools/telemetry/telemetry/page/actions/scroll.py
+++ b/tools/telemetry/telemetry/page/actions/scroll.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 import os
 
-from telemetry.core import util
 from telemetry.page.actions import page_action
 
 class ScrollAction(page_action.PageAction):
@@ -68,9 +67,7 @@
             top_start_percentage: %s });"""
         % (left_start_percentage, top_start_percentage))
 
-    # Poll for scroll action completion.
-    util.WaitFor(lambda: tab.EvaluateJavaScript(
-        'window.__scrollActionDone'), 60)
+    tab.WaitForJavaScriptExpression('window.__scrollActionDone', 60)
 
   def CanBeBound(self):
     return True
diff --git a/tools/telemetry/telemetry/page/actions/scroll_unittest.py b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
index 3b1e53b..aace7c1 100644
--- a/tools/telemetry/telemetry/page/actions/scroll_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
@@ -5,7 +5,7 @@
 
 from telemetry.core import util
 from telemetry.page import page as page_module
-#from telemetry.page.actions import scroll
+from telemetry.page.actions import scroll
 from telemetry.unittest import tab_test_case
 
 class ScrollActionTest(tab_test_case.TabTestCase):
@@ -26,44 +26,44 @@
 
     return page
 
-#  crbug.com/308846, Blink roll 159695:159835.
-#
-#  def testScrollAction(self):
-#    page = self.CreateAndNavigateToPageFromUnittestDataDir(
-#        "blank.html",
-#        page_attributes={"smoothness": {
-#          "action": "scroll"
-#          }})
-#    # Make page bigger than window so it's scrollable.
-#    self._tab.ExecuteJavaScript("""document.body.style.height =
-#                              (2 * window.innerHeight + 1) + 'px';""")
-#
-#    self.assertEquals(
-#        self._tab.EvaluateJavaScript("""document.documentElement.scrollTop
-#                                   || document.body.scrollTop"""), 0)
-#
-#    i = scroll.ScrollAction()
-#    i.WillRunAction(page, self._tab)
-#
-#    self._tab.ExecuteJavaScript("""
-#        window.__scrollAction.beginMeasuringHook = function() {
-#            window.__didBeginMeasuring = true;
-#        };
-#        window.__scrollAction.endMeasuringHook = function() {
-#            window.__didEndMeasuring = true;
-#        };""")
-#    i.RunAction(page, self._tab, None)
-#
-#    self.assertTrue(self._tab.EvaluateJavaScript('window.__didBeginMeasuring'))
-#    self.assertTrue(self._tab.EvaluateJavaScript('window.__didEndMeasuring'))
-#
-#    # Allow for roundoff error in scaled viewport.
-#    scroll_position = self._tab.EvaluateJavaScript(
-#        """(document.documentElement.scrollTop || document.body.scrollTop)
-#        + window.innerHeight""")
-#    scroll_height = self._tab.EvaluateJavaScript('document.body.scrollHeight')
-#    difference = scroll_position - scroll_height
-#    self.assertTrue(abs(difference) <= 1)
+  def testScrollAction(self):
+    page = self.CreateAndNavigateToPageFromUnittestDataDir(
+        "blank.html",
+        page_attributes={"smoothness": {
+          "action": "scroll"
+          }})
+    # Make page bigger than window so it's scrollable.
+    self._tab.ExecuteJavaScript("""document.body.style.height =
+                              (2 * window.innerHeight + 1) + 'px';""")
+
+    self.assertEquals(
+        self._tab.EvaluateJavaScript("""document.documentElement.scrollTop
+                                   || document.body.scrollTop"""), 0)
+
+    i = scroll.ScrollAction()
+    i.WillRunAction(page, self._tab)
+
+    self._tab.ExecuteJavaScript("""
+        window.__scrollAction.beginMeasuringHook = function() {
+            window.__didBeginMeasuring = true;
+        };
+        window.__scrollAction.endMeasuringHook = function() {
+            window.__didEndMeasuring = true;
+        };""")
+    i.RunAction(page, self._tab, None)
+
+    self.assertTrue(self._tab.EvaluateJavaScript('window.__didBeginMeasuring'))
+    self.assertTrue(self._tab.EvaluateJavaScript('window.__didEndMeasuring'))
+
+    # Allow for roundoff error in scaled viewport.
+    scroll_position = self._tab.EvaluateJavaScript(
+        """(document.documentElement.scrollTop || document.body.scrollTop)
+        + window.innerHeight""")
+    scroll_height = self._tab.EvaluateJavaScript('document.body.scrollHeight')
+    difference = scroll_position - scroll_height
+    self.assertTrue(abs(difference) <= 1,
+                    msg='scroll_position=%d; scroll_height=%d' %
+                            (scroll_position, scroll_height))
 
   def testBoundingClientRect(self):
     self.CreateAndNavigateToPageFromUnittestDataDir('blank.html', {})
diff --git a/tools/telemetry/telemetry/page/actions/seek.py b/tools/telemetry/telemetry/page/actions/seek.py
index cf4d14a..8b99ee1 100644
--- a/tools/telemetry/telemetry/page/actions/seek.py
+++ b/tools/telemetry/telemetry/page/actions/seek.py
@@ -19,8 +19,8 @@
 """
 
 from telemetry.core import exceptions
+from telemetry.page.actions import media_action
 from telemetry.page.actions import page_action
-import telemetry.page.actions.media_action as media_action
 
 
 class SeekAction(media_action.MediaAction):
diff --git a/tools/telemetry/telemetry/page/actions/tap_element.py b/tools/telemetry/telemetry/page/actions/tap_element.py
index f8c669e..ff503e9 100644
--- a/tools/telemetry/telemetry/page/actions/tap_element.py
+++ b/tools/telemetry/telemetry/page/actions/tap_element.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 from telemetry.core import exceptions
-from telemetry.core import util
 from telemetry.page.actions import page_action
 
 class TapElementAction(page_action.PageAction):
@@ -36,7 +35,6 @@
               'function(){window.__tap_event_finished=true})')
       tab.ExecuteJavaScript(code % self.wait_for_event)
       DoTap()
-      util.WaitFor(lambda: tab.EvaluateJavaScript(
-          'window.__tap_event_finished'), 60)
+      tab.WaitForJavaScriptExpression('window.__tap_event_finished', 60)
     else:
       DoTap()
diff --git a/tools/telemetry/telemetry/page/actions/wait.py b/tools/telemetry/telemetry/page/actions/wait.py
index c3f80fb..3689a2b 100644
--- a/tools/telemetry/telemetry/page/actions/wait.py
+++ b/tools/telemetry/telemetry/page/actions/wait.py
@@ -39,8 +39,8 @@
       previous_action.WillRunAction(page, tab)
       old_url = tab.EvaluateJavaScript('document.location.href')
       previous_action.RunAction(page, tab, None)
-      util.WaitFor(lambda: tab.EvaluateJavaScript(
-          'document.location.href') != old_url, self.timeout)
+      tab.WaitForJavaScriptExpression(
+          'document.location.href != "%s"' % old_url, self.timeout)
 
     elif getattr(self, 'condition', None) == 'element':
       if hasattr(self, 'text'):
@@ -49,8 +49,8 @@
             lambda: util.FindElementAndPerformAction(
                 tab, self.text, callback_code), self.timeout)
       elif hasattr(self, 'selector'):
-        util.WaitFor(lambda: tab.EvaluateJavaScript(
-             'document.querySelector("%s") != null' % re.escape(self.selector)),
+        tab.WaitForJavaScriptExpression(
+             'document.querySelector("%s") != null' % re.escape(self.selector),
              self.timeout)
       elif hasattr(self, 'xpath'):
         code = ('document.evaluate("%s",'
@@ -59,14 +59,12 @@
                                    'XPathResult.FIRST_ORDERED_NODE_TYPE,'
                                    'null)'
                   '.singleNodeValue' % re.escape(self.xpath))
-        util.WaitFor(lambda: tab.EvaluateJavaScript('%s != null' % code),
-             self.timeout)
+        tab.WaitForJavaScriptExpression('%s != null' % code, self.timeout)
       else:
         raise page_action.PageActionFailed(
             'No element condition given to wait')
     elif hasattr(self, 'javascript'):
-      util.WaitFor(lambda: tab.EvaluateJavaScript(self.javascript),
-                   self.timeout)
+      tab.WaitForJavaScriptExpression(self.javascript, self.timeout)
     else:
       raise page_action.PageActionFailed('No wait condition found')
 
diff --git a/tools/telemetry/telemetry/page/page_filter.py b/tools/telemetry/telemetry/page/page_filter.py
index dcf30b8..a1c213a 100644
--- a/tools/telemetry/telemetry/page/page_filter.py
+++ b/tools/telemetry/telemetry/page/page_filter.py
@@ -25,10 +25,14 @@
       self._page_exclude_regex = None
 
   def IsSelected(self, page):
-    if self._page_exclude_regex and self._page_exclude_regex.search(page.url):
+    if self._page_exclude_regex and (
+        self._page_exclude_regex.search(page.url) or
+        (page.name and self._page_exclude_regex.search(page.name))):
       return False
     if self._page_regex:
-      return self._page_regex.search(page.url)
+      return (
+          self._page_regex.search(page.url) or
+          (page.name and self._page_regex.search(page.name)))
     return True
 
   @staticmethod
diff --git a/tools/telemetry/telemetry/page/page_filter_unittest.py b/tools/telemetry/telemetry/page/page_filter_unittest.py
new file mode 100644
index 0000000..924d46a
--- /dev/null
+++ b/tools/telemetry/telemetry/page/page_filter_unittest.py
@@ -0,0 +1,69 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import unittest
+
+from telemetry.page import page as page_module
+from telemetry.page import page_filter as page_filter_module
+from telemetry.page import page_set
+
+class MockOptions(object):
+  def __init__(self, page_filter, page_filter_exclude):
+    self.page_filter = page_filter
+    self.page_filter_exclude = page_filter_exclude
+
+class PageFilterTest(unittest.TestCase):
+  def setUp(self):
+    ps = page_set.PageSet()
+    self.p1 = page_module.Page(
+        'file://conformance/textures/tex-sub-image-2d.html',
+        ps,
+        { 'name': 'WebglConformance.conformance_textures_tex_sub_image_2d' })
+    self.p2 = page_module.Page(
+        'file://othersuite/textures/tex-sub-image-3d.html',
+        ps,
+        { 'name': 'OtherSuite.textures_tex_sub_image_3d' })
+    self.p3 = page_module.Page(
+        'file://othersuite/textures/tex-sub-image-3d.html',
+        ps,
+        { 'name': None })
+
+  def testURLPattern(self):
+    options = MockOptions('conformance/textures', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertTrue(page_filter.IsSelected(self.p1))
+    self.assertFalse(page_filter.IsSelected(self.p2))
+    options = MockOptions('textures', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertTrue(page_filter.IsSelected(self.p1))
+    self.assertTrue(page_filter.IsSelected(self.p2))
+    options = MockOptions('somethingelse', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertFalse(page_filter.IsSelected(self.p1))
+    self.assertFalse(page_filter.IsSelected(self.p2))
+
+  def testName(self):
+    options = MockOptions('somethingelse', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertFalse(page_filter.IsSelected(self.p1))
+    self.assertFalse(page_filter.IsSelected(self.p2))
+    options = MockOptions('textures_tex_sub_image', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertTrue(page_filter.IsSelected(self.p1))
+    self.assertTrue(page_filter.IsSelected(self.p2))
+    options = MockOptions('WebglConformance', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertTrue(page_filter.IsSelected(self.p1))
+    self.assertFalse(page_filter.IsSelected(self.p2))
+    options = MockOptions('OtherSuite', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertFalse(page_filter.IsSelected(self.p1))
+    self.assertTrue(page_filter.IsSelected(self.p2))
+
+  def testNameNone(self):
+    options = MockOptions('othersuite/textures', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertTrue(page_filter.IsSelected(self.p3))
+    options = MockOptions('conformance/textures', '')
+    page_filter = page_filter_module.PageFilter(options)
+    self.assertFalse(page_filter.IsSelected(self.p3))
diff --git a/tools/telemetry/telemetry/page/page_runner.py b/tools/telemetry/telemetry/page/page_runner.py
index 12ed918..1ff2c74 100644
--- a/tools/telemetry/telemetry/page/page_runner.py
+++ b/tools/telemetry/telemetry/page/page_runner.py
@@ -27,7 +27,6 @@
 class _RunState(object):
   def __init__(self):
     self.browser = None
-    self.tab = None
 
     self._append_to_existing_wpr = False
     self._last_archive_path = None
@@ -41,7 +40,6 @@
     started_browser = not self.browser
     # Create a browser.
     if not self.browser:
-      assert not self.tab
       self.browser = possible_browser.Create()
       self.browser.credentials.credentials_path = credentials_path
 
@@ -84,7 +82,7 @@
             page_set.make_javascript_deterministic)
         self._last_archive_path = page.archive_path
 
-    if self.browser.supports_tab_control:
+    if self.browser.supports_tab_control and test.close_tabs_before_run:
       # Create a tab if there's none.
       if len(self.browser.tabs) == 0:
         self.browser.tabs.New()
@@ -105,17 +103,10 @@
       if started_browser:
         self.browser.tabs[0].WaitForDocumentReadyStateToBeComplete()
 
-    if not self.tab:
-      self.tab = self.browser.tabs[0]
-
     if self.first_page[page]:
       self.first_page[page] = False
 
   def StopBrowser(self):
-    if self.tab:
-      self.tab.Disconnect()
-      self.tab = None
-
     if self.browser:
       self.browser.Close()
       self.browser = None
@@ -139,41 +130,50 @@
 
 
 class PageState(object):
-  def __init__(self):
+  def __init__(self, page, tab):
+    self.page = page
+    self.tab = tab
+
     self._did_login = False
 
-  def PreparePage(self, page, tab, test=None):
-    if page.is_file:
-      server_started = tab.browser.SetHTTPServerDirectories(
-        page.page_set.serving_dirs | set([page.serving_dir]))
+  def PreparePage(self, test=None):
+    if self.page.is_file:
+      server_started = self.tab.browser.SetHTTPServerDirectories(
+        self.page.page_set.serving_dirs | set([self.page.serving_dir]))
       if server_started and test:
-        test.DidStartHTTPServer(tab)
+        test.DidStartHTTPServer(self.tab)
 
-    if page.credentials:
-      if not tab.browser.credentials.LoginNeeded(tab, page.credentials):
-        raise page_test.Failure('Login as ' + page.credentials + ' failed')
+    if self.page.credentials:
+      if not self.tab.browser.credentials.LoginNeeded(
+          self.tab, self.page.credentials):
+        raise page_test.Failure('Login as ' + self.page.credentials + ' failed')
       self._did_login = True
 
     if test:
       if test.clear_cache_before_each_run:
-        tab.ClearCache()
+        self.tab.ClearCache()
 
-  def ImplicitPageNavigation(self, page, tab, test=None):
+  def ImplicitPageNavigation(self, test=None):
     """Executes the implicit navigation that occurs for every page iteration.
 
     This function will be called once per page before any actions are executed.
     """
     if test:
-      test.WillNavigateToPage(page, tab)
-      test.RunNavigateSteps(page, tab)
-      test.DidNavigateToPage(page, tab)
+      test.WillNavigateToPage(self.page, self.tab)
+      test.RunNavigateSteps(self.page, self.tab)
+      test.DidNavigateToPage(self.page, self.tab)
     else:
       i = navigate.NavigateAction()
-      i.RunAction(page, tab, None)
+      i.RunAction(self.page, self.tab, None)
 
-  def CleanUpPage(self, page, tab):
-    if page.credentials and self._did_login:
-      tab.browser.credentials.LoginNoLongerNeeded(tab, page.credentials)
+  def CleanUpPage(self):
+    if self.page.credentials and self._did_login:
+      self.tab.browser.credentials.LoginNoLongerNeeded(
+          self.tab, self.page.credentials)
+
+    if self.tab:
+      self.tab.Disconnect()
+      self.tab = None
 
 
 def AddCommandLineOptions(parser):
@@ -235,7 +235,7 @@
       if finder_options.profiler:
         state.StopProfiling()
 
-      if test.NeedsBrowserRestartAfterEachRun(state.tab):
+      if test.NeedsBrowserRestartAfterEachRun(state.browser):
         state.StopBrowser()
 
       break
@@ -259,6 +259,8 @@
   results = results_options.PrepareResults(test, finder_options)
   browser_options = finder_options.browser_options
 
+  test.ValidatePageSet(page_set)
+
   # Create a possible_browser with the given options.
   test.CustomizeBrowserOptions(finder_options)
   try:
@@ -312,26 +314,27 @@
   # TODO(dtu): Move results creation and results_for_current_run into RunState.
 
   try:
-    # TODO(dtu): state.tab is always None here, maybe we should not pass it?
-    test.WillRunTest(state.tab)
+    test.WillRunTest()
     state.repeat_state = page_runner_repeat.PageRunnerRepeatState(
                              finder_options.repeat_options)
 
     state.repeat_state.WillRunPageSet()
-    while state.repeat_state.ShouldRepeatPageSet():
+    while state.repeat_state.ShouldRepeatPageSet() and not test.IsExiting():
       for page in pages:
         state.repeat_state.WillRunPage()
-        test.WillRunPageRepeats(page, state.tab)
+        test.WillRunPageRepeats(page)
         while state.repeat_state.ShouldRepeatPage():
           # execute test on page
           _PrepareAndRunPage(test, page_set, expectations, finder_options,
                              browser_options, page, credentials_path,
                              possible_browser, results, state)
           state.repeat_state.DidRunPage()
-        test.DidRunPageRepeats(page, state.tab)
+        test.DidRunPageRepeats(page)
+        if test.IsExiting():
+          break
       state.repeat_state.DidRunPageSet()
 
-    test.DidRunTest(state.tab, results)
+    test.DidRunTest(state.browser, results)
   finally:
     state.StopBrowser()
 
@@ -419,9 +422,7 @@
 
   logging.info('Running %s' % page.url)
 
-  page_state = PageState()
-  tab = test.TabForPage(page, state.tab)
-  state.tab = tab
+  page_state = PageState(page, test.TabForPage(page, state.browser))
 
   def ProcessError():
     logging.error('%s:\n%s', page.url, traceback.format_exc())
@@ -432,12 +433,12 @@
       results.AddError(page, sys.exc_info())
 
   try:
-    page_state.PreparePage(page, tab, test)
+    page_state.PreparePage(test)
     if state.repeat_state.ShouldNavigate(
         finder_options.skip_navigate_on_repeat):
-      page_state.ImplicitPageNavigation(page, tab, test)
-    test.Run(finder_options, page, tab, results)
-    util.CloseConnections(tab)
+      page_state.ImplicitPageNavigation(test)
+    test.Run(finder_options, page, page_state.tab, results)
+    util.CloseConnections(page_state.tab)
   except page_test.Failure:
     logging.warning('%s:\n%s', page.url, traceback.format_exc())
     if expectation == 'fail':
@@ -459,7 +460,7 @@
       logging.warning('%s was expected to fail, but passed.\n', page.url)
     results.AddSuccess(page)
   finally:
-    page_state.CleanUpPage(page, tab)
+    page_state.CleanUpPage()
 
 
 def _GetSequentialFileName(base_name):
diff --git a/tools/telemetry/telemetry/page/page_test.py b/tools/telemetry/telemetry/page/page_test.py
index 9e22ad6..43f6d02 100644
--- a/tools/telemetry/telemetry/page/page_test.py
+++ b/tools/telemetry/telemetry/page/page_test.py
@@ -59,12 +59,13 @@
       self._test_method = getattr(self, test_method_name)
     except AttributeError:
       raise ValueError, 'No such method %s.%s' % (
-        self.__class_, test_method_name) # pylint: disable=E1101
+        self.__class_, test_method_name)  # pylint: disable=E1101
     self._action_name_to_run = action_name_to_run
     self._needs_browser_restart_after_each_run = (
         needs_browser_restart_after_each_run)
     self._discard_first_result = discard_first_result
     self._clear_cache_before_each_run = clear_cache_before_each_run
+    self._close_tabs_before_run = True
     # If the test overrides the TabForPage method, it is considered a multi-tab
     # test.  The main difference between this and a single-tab test is that we
     # do not attempt recovery for the former if a tab or the browser crashes,
@@ -72,6 +73,8 @@
     self.is_multi_tab_test = (self.__class__ is not PageTest and
                               self.TabForPage.__func__ is not
                               self.__class__.__bases__[0].TabForPage.__func__)
+    # _exit_requested is set to true when the test requests an early exit.
+    self._exit_requested = False
 
   @property
   def discard_first_result(self):
@@ -90,7 +93,17 @@
     before each run."""
     return self._clear_cache_before_each_run
 
-  def NeedsBrowserRestartAfterEachRun(self, tab): # pylint: disable=W0613
+  @property
+  def close_tabs_before_run(self):
+    """When set to True, all tabs are closed before running the test for the
+    first time."""
+    return self._close_tabs_before_run
+
+  @close_tabs_before_run.setter
+  def close_tabs_before_run(self, close_tabs):
+    self._close_tabs_before_run = close_tabs
+
+  def NeedsBrowserRestartAfterEachRun(self, browser):  # pylint: disable=W0613
     """Override to specify browser restart after each run."""
     return self._needs_browser_restart_after_each_run
 
@@ -121,26 +134,26 @@
     """Override to customize the browser right after it has launched."""
     pass
 
-  def CanRunForPage(self, page): #pylint: disable=W0613
+  def CanRunForPage(self, page):  # pylint: disable=W0613
     """Override to customize if the test can be ran for the given page."""
     return True
 
-  def WillRunTest(self, tab):
+  def WillRunTest(self):
     """Override to do operations before the page set(s) are navigated."""
     pass
 
-  def DidRunTest(self, tab, results):
+  def DidRunTest(self, browser, results):
     """Override to do operations after all page set(s) are completed.
 
     This will occur before the browser is torn down.
     """
     pass
 
-  def WillRunPageRepeats(self, page, tab):
+  def WillRunPageRepeats(self, page):
     """Override to do operations before each page is iterated over."""
     pass
 
-  def DidRunPageRepeats(self, page, tab):
+  def DidRunPageRepeats(self, page):
     """Override to do operations after each page is iterated over."""
     pass
 
@@ -169,20 +182,25 @@
     """Override to do operations after running the action on the page."""
     pass
 
-  def CreatePageSet(self, args, options):  # pylint: disable=W0613
+  def CreatePageSet(self, args, options):   # pylint: disable=W0613
     """Override to make this test generate its own page set instead of
     allowing arbitrary page sets entered from the command-line."""
     return None
 
-  def CreateExpectations(self, page_set):  # pylint: disable=W0613
+  def CreateExpectations(self, page_set):   # pylint: disable=W0613
     """Override to make this test generate its own expectations instead of
     any that may have been defined in the page set."""
     return test_expectations.TestExpectations()
 
-  def TabForPage(self, page, tab):  # pylint: disable=W0613
+  def TabForPage(self, page, browser):   # pylint: disable=W0613
     """Override to select a different tab for the page.  For instance, to
-    create a new tab for every page, return tab.browser.tabs.New()."""
-    return tab
+    create a new tab for every page, return browser.tabs.New()."""
+    return browser.tabs[0]
+
+  def ValidatePageSet(self, page_set):
+    """Override to examine the page set before the test run.  Useful for
+    example to validate that the pageset can be used with the test."""
+    pass
 
   def Run(self, options, page, tab, results):
     self.options = options
@@ -231,6 +249,12 @@
 
     self._RunCompoundAction(page, tab, navigate_actions, False)
 
+  def IsExiting(self):
+    return self._exit_requested
+
+  def RequestExit(self):
+    self._exit_requested = True
+
   @property
   def action_name_to_run(self):
     return self._action_name_to_run
diff --git a/tools/telemetry/telemetry/page/test_expectations.py b/tools/telemetry/telemetry/page/test_expectations.py
index 2c2f2c6..df2e686 100644
--- a/tools/telemetry/telemetry/page/test_expectations.py
+++ b/tools/telemetry/telemetry/page/test_expectations.py
@@ -12,9 +12,10 @@
 CONFIG_MODIFIERS = ['debug', 'release']
 
 class Expectation(object):
-  def __init__(self, expectation, url_pattern, conditions=None, bug=None):
+  def __init__(self, expectation, pattern, conditions=None, bug=None):
     self.expectation = expectation.lower()
-    self.url_pattern = url_pattern
+    self.name_pattern = pattern
+    self.url_pattern = pattern
     self.bug = bug
 
     self.os_conditions = []
@@ -71,7 +72,9 @@
     gpu_info = None
 
     for e in self.expectations:
-      if fnmatch.fnmatch(page.url, e.url_pattern):
+      matches_url = fnmatch.fnmatch(page.url, e.url_pattern)
+      matches_name = page.name and fnmatch.fnmatch(page.name, e.name_pattern)
+      if matches_url or matches_name:
         if gpu_info == None and browser.supports_system_info:
           gpu_info = browser.GetSystemInfo().gpu
         if self._ModifiersApply(platform, gpu_info, e):
diff --git a/tools/telemetry/telemetry/page/test_expectations_unittest.py b/tools/telemetry/telemetry/page/test_expectations_unittest.py
index 20ffcb3..53314db 100644
--- a/tools/telemetry/telemetry/page/test_expectations_unittest.py
+++ b/tools/telemetry/telemetry/page/test_expectations_unittest.py
@@ -58,6 +58,7 @@
     self.Fail('page8.html', ['win', 'intel', ('amd', 0x1001)], bug=123)
     self.Fail('page9.html', ['imagination'])
     self.Fail('page10.html', [('imagination', 'PowerVR SGX 554')])
+    self.Fail('Pages.page_11')
 
 class TestExpectationsTest(unittest.TestCase):
   def setUp(self):
@@ -181,3 +182,10 @@
     self.assertExpectationEquals('pass', page,
                                  vendor_string='Acme',
                                  device_string=DEVICE_STRING_SGX)
+
+  # Expectations can be set against page names as well as urls
+  def testPageNameExpectations(self):
+    ps = page_set.PageSet()
+    page = page_module.Page('http://test.com/page11.html', ps)
+    page.name = "Pages.page_11"
+    self.assertExpectationEquals('fail', page)
diff --git a/tools/telemetry/telemetry/test.py b/tools/telemetry/telemetry/test.py
index b3790c4..39003e2 100644
--- a/tools/telemetry/telemetry/test.py
+++ b/tools/telemetry/telemetry/test.py
@@ -39,6 +39,7 @@
       setattr(options, key, value)
 
     options.repeat_options = self._CreateRepeatOptions(options)
+    self.CustomizeBrowserOptions(options)
 
     test = self.test()
     ps = self.CreatePageSet(options)
@@ -90,3 +91,7 @@
   def AddTestCommandLineOptions(parser):
     """Override to accept custom command line options."""
     pass
+
+  def CustomizeBrowserOptions(self, options):
+    """Add browser options that are required by this benchmark."""
+    pass
diff --git a/tools/telemetry/telemetry/test_runner.py b/tools/telemetry/telemetry/test_runner.py
index 6380f3d..adb95a8 100644
--- a/tools/telemetry/telemetry/test_runner.py
+++ b/tools/telemetry/telemetry/test_runner.py
@@ -138,6 +138,9 @@
     self._test = matching_tests.popitem()[1]
 
   def Run(self, options, args):
+    if not self._test.enabled:
+      print >> sys.stderr, 'TEST IS DISABLED. SKIPPING.'
+      return 0
     return min(255, self._test().Run(copy.copy(options)))
 
 
@@ -170,8 +173,15 @@
         return True
     return False
 
+  # Exact matching.
   if input_test_name in test_aliases:
-    input_test_name = test_aliases[input_test_name]
+    exact_match = test_aliases[input_test_name]
+  else:
+    exact_match = input_test_name
+  if exact_match in _GetTests():
+    return {exact_match: _GetTests()[exact_match]}
+
+  # Fuzzy matching.
   return dict((test_name, test_class)
       for test_name, test_class in _GetTests().iteritems()
       if _Matches(input_test_name, test_name))
diff --git a/tools/telemetry/telemetry/unittest/system_stub.py b/tools/telemetry/telemetry/unittest/system_stub.py
index 922d37f..0e9511d 100644
--- a/tools/telemetry/telemetry/unittest/system_stub.py
+++ b/tools/telemetry/telemetry/unittest/system_stub.py
@@ -1,6 +1,7 @@
 # Copyright (c) 2012 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.
+
 """Provides stubs for os, sys and subprocess for testing
 
 This test allows one to test code that itself uses os, sys, and subprocess.
@@ -9,16 +10,19 @@
 import os
 import re
 import shlex
-import sys as real_sys
+import sys
+
 
 class Override(object):
   def __init__(self, base_module, module_list):
     stubs = {'adb_commands': AdbCommandsModuleStub,
-             'perf_control': PerfControlModuleStub,
-             'thermal_throttle': ThermalThrottleModuleStub,
+             'cloud_storage': CloudStorageModuleStub,
+             'open': OpenFunctionStub,
              'os': OsModuleStub,
+             'perf_control': PerfControlModuleStub,
              'subprocess': SubprocessModuleStub,
              'sys': SysModuleStub,
+             'thermal_throttle': ThermalThrottleModuleStub,
     }
     self.adb_commands = None
     self.os = None
@@ -29,7 +33,7 @@
     self._overrides = {}
 
     for module_name in module_list:
-      self._overrides[module_name] = getattr(base_module, module_name)
+      self._overrides[module_name] = getattr(base_module, module_name, None)
       setattr(self, module_name, stubs[module_name]())
       setattr(base_module, module_name, getattr(self, module_name))
 
@@ -44,6 +48,7 @@
       setattr(self._base_module, module_name, original_module)
     self._overrides = {}
 
+
 class AdbCommandsModuleStub(object):
 # adb not even found
 # android_browser_finder not returning
@@ -81,22 +86,50 @@
   def HasForwarder(_=None):
     return True
 
-class PerfControlModuleStub(object):
-  class PerfControlStub(object):
-    def __init__(self, adb):
-      pass
+
+class CloudStorageModuleStub(object):
+  INTERNAL_BUCKET = None
+  PUBLIC_BUCKET = None
+
+  class CloudStorageError(Exception):
+    pass
 
   def __init__(self):
-    self.PerfControl = PerfControlModuleStub.PerfControlStub
+    self.remote_paths = []
+    self.local_file_hashes = {}
+
+  def List(self, _):
+    return self.remote_paths
+
+  def Insert(self, bucket, remote_path, local_path):
+    pass
+
+  def GetHash(self, file_path):
+    return self.local_file_hashes[file_path]
 
 
-class ThermalThrottleModuleStub(object):
-  class ThermalThrottleStub(object):
-    def __init__(self, adb):
+class OpenFunctionStub(object):
+  class FileStub(object):
+    def __init__(self, data):
+      self._data = data
+
+    def __enter__(self):
+      return self
+
+    def __exit__(self, *args):
       pass
 
+    def read(self, size=None):
+      if size:
+        return self._data[:size]
+      else:
+        return self._data
+
   def __init__(self):
-    self.ThermalThrottle = ThermalThrottleModuleStub.ThermalThrottleStub
+    self.files = {}
+
+  def __call__(self, name, *args, **kwargs):
+    return OpenFunctionStub.FileStub(self.files[name])
 
 
 class OsModuleStub(object):
@@ -132,15 +165,21 @@
         tmp = os.path.join(*paths)
         return tmp.replace('\\', '/')
 
-    def expanduser(self, filename):
-      return os.path.expanduser(filename)
+    @staticmethod
+    def expanduser(path):
+      return os.path.expanduser(path)
 
-    def dirname(self, filename): # pylint: disable=R0201
-      return os.path.dirname(filename)
+    @staticmethod
+    def dirname(path):
+      return os.path.dirname(path)
+
+    @staticmethod
+    def splitext(path):
+      return os.path.splitext(path)
 
   X_OK = os.X_OK
 
-  def __init__(self, sys_module=real_sys):
+  def __init__(self, sys_module=sys):
     self.path = OsModuleStub.OsPathModuleStub(sys_module)
     self.display = ':0'
     self.local_app_data = None
@@ -162,6 +201,16 @@
       return self.program_files_x86
     raise Exception('Unsupported getenv')
 
+
+class PerfControlModuleStub(object):
+  class PerfControlStub(object):
+    def __init__(self, adb):
+      pass
+
+  def __init__(self):
+    self.PerfControl = PerfControlModuleStub.PerfControlStub
+
+
 class SubprocessModuleStub(object):
   class PopenStub(object):
     def __init__(self):
@@ -180,6 +229,16 @@
   def call(self, *args, **kwargs):
     raise NotImplementedError()
 
+
 class SysModuleStub(object):
   def __init__(self):
     self.platform = ''
+
+
+class ThermalThrottleModuleStub(object):
+  class ThermalThrottleStub(object):
+    def __init__(self, adb):
+      pass
+
+  def __init__(self):
+    self.ThermalThrottle = ThermalThrottleModuleStub.ThermalThrottleStub
diff --git a/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
index dc058fa..b7413ca 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Another dummy exception subclasses used by core/discover.py's unit tests."""
+"""More dummy exception subclasses used by core/discover.py's unit tests."""
 
 # Import class instead of module explicitly so that inspect.getmembers() returns
 # two Exception subclasses in this current file.
@@ -12,5 +12,13 @@
 from discoverable_classes.discover_dummyclass import DummyException
 
 
-class AnotherDummyException(DummyException):
+class _PrivateDummyException(DummyException):
+  pass
+
+
+class DummyExceptionImpl1(_PrivateDummyException):
+  pass
+
+
+class DummyExceptionImpl2(_PrivateDummyException):
   pass
diff --git a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
index afda1e5..b25cf9e 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""A dummy exception subclasses used by core/discover.py's unit tests."""
+"""A dummy exception subclass used by core/discover.py's unit tests."""
 
 class DummyException(Exception):
   pass
diff --git a/tools/update_reference_build.py b/tools/update_reference_build.py
index eaa9fc1..d77a099 100755
--- a/tools/update_reference_build.py
+++ b/tools/update_reference_build.py
@@ -34,9 +34,18 @@
 CHROMIUM_URL_FMT = ('http://commondatastorage.googleapis.com/'
                     'chromium-browser-snapshots/%s/%s/%s')
 
-# Example Chrome build location (no public wed URL's):
+# Chrome official build storage
+# https://wiki.corp.google.com/twiki/bin/view/Main/ChromeOfficialBuilds
+
+# Internal Google archive of official Chrome builds, example:
+# https://goto.google.com/chrome_official_builds/
+# 32.0.1677.0/precise32bit/chrome-precise32bit.zip
+CHROME_INTERNAL_URL_FMT = ('http://master.chrome.corp.google.com/'
+                           'official_builds/%s/%s/%s')
+
+# Google storage location (no public web URL's), example:
 # gs://chrome-archive/30/30.0.1595.0/precise32bit/chrome-precise32bit.zip
-CHROME_URL_FMT = ('gs://chrome-archive/%s/%s/%s/%s')
+CHROME_GS_URL_FMT = ('gs://chrome-archive/%s/%s/%s/%s')
 
 
 class BuildUpdater(object):
@@ -91,6 +100,7 @@
     self._platforms = options.platforms.split(',')
     self._revision = options.build_number or int(options.revision)
     self._use_build_number = bool(options.build_number)
+    self._use_gs = options.use_gs
 
   @staticmethod
   def _GetCmdStatusAndOutput(args, cwd=None, shell=False):
@@ -117,28 +127,41 @@
 
   def _GetBuildUrl(self, platform, revision, filename):
     if self._use_build_number:
-      release = revision[:revision.find('.')]
-      return (CHROME_URL_FMT %
-              (release, revision, self._BUILD_PLATFORM_MAP[platform], filename))
+      # Chrome Google storage bucket.
+      if self._use_gs:
+        release = revision[:revision.find('.')]
+        return (CHROME_GS_URL_FMT % (
+            release,
+            revision,
+            self._BUILD_PLATFORM_MAP[platform],
+            filename))
+      # Chrome internal archive.
+      return (CHROME_INTERNAL_URL_FMT % (
+          revision,
+          self._BUILD_PLATFORM_MAP[platform],
+          filename))
+    # Chromium archive.
     return CHROMIUM_URL_FMT % (urllib.quote_plus(platform), revision, filename)
 
   def _FindBuildRevision(self, platform, revision, filename):
     # TODO(shadi): Iterate over build numbers to find a valid one.
     if self._use_build_number:
       return (revision
-              if self._DoesChromeBuildExist(platform, revision, filename) else
-              None)
+              if self._DoesBuildExist(platform, revision, filename) else None)
 
     MAX_REVISIONS_PER_BUILD = 100
     for revision_guess in xrange(revision, revision + MAX_REVISIONS_PER_BUILD):
-      if self._DoesChromiumBuildExist(platform, revision_guess, filename):
+      if self._DoesBuildExist(platform, revision_guess, filename):
         return revision_guess
       else:
         time.sleep(.1)
     return None
 
-  def _DoesChromiumBuildExist(self, platform, build_number, filename):
+  def _DoesBuildExist(self, platform, build_number, filename):
     url = self._GetBuildUrl(platform, build_number, filename)
+    if self._use_gs:
+      return self._DoesGSFileExist(url)
+
     r = urllib2.Request(url)
     r.get_method = lambda: 'HEAD'
     try:
@@ -148,16 +171,9 @@
       if err.code == 404:
         return False
 
-  def _DoesChromeBuildExist(self, platform, build_number, filename):
-    release = build_number[:build_number.find('.')]
-    gs_file = (CHROME_URL_FMT %
-               (release,
-                build_number,
-                self._BUILD_PLATFORM_MAP[platform],
-                filename))
-    (exit_code, stdout) = BuildUpdater._GetCmdStatusAndOutput(
-        ['gsutil', 'ls', gs_file])
-
+  def _DoesGSFileExist(self, gs_file_name):
+    exit_code = BuildUpdater._GetCmdStatusAndOutput(
+        ['gsutil', 'ls', gs_file_name])[0]
     return not exit_code
 
   def _GetPlatformFiles(self, platform):
@@ -171,12 +187,12 @@
         output = os.path.join('dl', platform,
                               '%s_%s_%s' % (platform, self._revision, f))
         if os.path.exists(output):
-          logging.info('%s alread exists, skipping download' % output)
+          logging.info('%s alread exists, skipping download', output)
           continue
         build_revision = self._FindBuildRevision(platform, self._revision, f)
         if not build_revision:
-          logging.critical('Failed to find %s build for r%s\n' % (
-              platform, self._revision))
+          logging.critical('Failed to find %s build for r%s\n', platform,
+                           self._revision)
           sys.exit(1)
         dirname = os.path.dirname(output)
         if dirname and not os.path.exists(dirname):
@@ -185,8 +201,8 @@
         self._DownloadFile(url, output)
 
   def _DownloadFile(self, url, output):
-    logging.info('Downloading %s, saving to %s' % (url, output))
-    if self._use_build_number:
+    logging.info('Downloading %s, saving to %s', url, output)
+    if self._use_build_number and self._use_gs:
       BuildUpdater._GetCmdStatusAndOutput(['gsutil', 'cp', url, output])
     else:
       r = urllib2.urlopen(url)
@@ -206,7 +222,7 @@
   def _UnzipFile(self, dl_file, dest_dir):
     if not zipfile.is_zipfile(dl_file):
       return False
-    logging.info('Opening %s' % dl_file)
+    logging.info('Opening %s', dl_file)
     with zipfile.ZipFile(dl_file, 'r') as z:
       for content in z.namelist():
         dest = os.path.join(dest_dir, content[content.find('/')+1:])
@@ -217,7 +233,7 @@
         if not os.path.basename(dest):
           continue
         with z.open(content) as unzipped_content:
-          logging.info('Extracting %s to %s (%s)' % (content, dest, dl_file))
+          logging.info('Extracting %s to %s (%s)', content, dest, dl_file)
           with file(dest, 'wb') as dest_file:
             dest_file.write(unzipped_content.read())
           permissions = z.getinfo(content).external_attr >> 16
@@ -246,15 +262,18 @@
         for dl_file in dl_files:
           dl_file = os.path.join(root, dl_file)
           if not self._UnzipFile(dl_file, dest_dir):
-            logging.info('Copying %s to %s' % (dl_file, dest_dir))
+            logging.info('Copying %s to %s', dl_file, dest_dir)
             shutil.copy(dl_file, dest_dir)
 
   def _SvnAddAndRemove(self):
     svn_dir = os.path.join('reference_builds', 'reference_builds')
-    stat = BuildUpdater._GetCmdStatusAndOutput(['svn', 'stat'], svn_dir)[1]
+    # List all changes without ignoring any files.
+    stat = BuildUpdater._GetCmdStatusAndOutput(['svn', 'stat', '--no-ignore'],
+                                               svn_dir)[1]
     for line in stat.splitlines():
       action, filename = line.split(None, 1)
-      if action == '?':
+      # Add new and ignored files.
+      if action == '?' or action == 'I':
         BuildUpdater._GetCmdStatusAndOutput(
             ['svn', 'add', filename], svn_dir)
       elif action == '!':
@@ -278,12 +297,16 @@
   parser.set_usage(usage)
   parser.add_option('-b', dest='build_number',
                     help='Chrome official build number to pick up.')
-  parser.add_option('-r', dest='revision',
-                    help='Revision to pick up.')
+  parser.add_option('--gs', dest='use_gs', action='store_true', default=False,
+                    help='Use Google storage for official builds. Used with -b '
+                         'option. Default is false (i.e. use internal storage.')
   parser.add_option('-p', dest='platforms',
                     default='Win,Mac,Linux,Linux_x64',
                     help='Comma separated list of platforms to download '
                          '(as defined by the chromium builders).')
+  parser.add_option('-r', dest='revision',
+                    help='Revision to pick up.')
+
   (options, _) = parser.parse_args(argv)
   if not options.revision and not options.build_number:
     logging.critical('Must specify either -r or -b.\n')
@@ -291,6 +314,9 @@
   if options.revision and options.build_number:
     logging.critical('Must specify either -r or -b but not both.\n')
     sys.exit(1)
+  if options.use_gs and not options.build_number:
+    logging.critical('Can only use --gs with -b option.\n')
+    sys.exit(1)
 
   return options
 
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 791ac50..c88177c 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -600,10 +600,12 @@
 
   options, args = parser.parse_args()
 
-  # bake target into build_dir.
-  assert not options.build_dir.endswith(options.target)
-  options.build_dir = os.path.join(os.path.abspath(options.build_dir),
-                                   options.target)
+  # Bake target into build_dir.
+  if options.target and options.build_dir:
+    assert (options.target !=
+            os.path.basename(os.path.dirname(options.build_dir)))
+    options.build_dir = os.path.join(os.path.abspath(options.build_dir),
+                                     options.target)
 
   if options.verbose:
     logging_utils.config_root(logging.DEBUG)
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
index 24320f5..808c81b 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest.txt
@@ -31,3 +31,7 @@
 
 # Timing out all over the place. Disabling for now. http://crbug.com/164589
 StorageInfoProviderTest.*
+
+# Fail under Memcheck, see http://crbug.com/311564
+MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest.V1AppMenuGenerationTwoUsers
+MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest.BrowserMenuGenerationTwoUsers
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index d6e4c0f..97b8441 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -38,26 +38,6 @@
    fun:FcConfigAppFontAddFile
 }
 {
-   # See also http://www.gnome.org/~johan/gtk.suppression
-   # (which has a smattering of similar pango suppressions)
-   pango_font_leak_todo
-   Memcheck:Leak
-   ...
-   fun:FcFontRenderPrepare
-   obj:*
-   fun:pango_font_map_load_fontset
-}
-{
-   pango_font_leak_todo_2
-   Memcheck:Leak
-   fun:malloc
-   fun:g_malloc
-   fun:g_strdup
-   fun:pango_script_get_sample_language
-   ...
-   fun:pango_font_get_metrics
-}
-{
    pango_font_leak_todo_3
    Memcheck:Leak
    ...
@@ -110,15 +90,6 @@
    fun:FcPatternObjectAddWithBinding
 }
 {
-   # Another permutation of previous leak.
-   fontconfig_bug_8428_2
-   Memcheck:Leak
-   ...
-   fun:realloc
-   fun:FcPatternObjectInsertElt
-   fun:FcPatternObjectAdd
-}
-{
    bug_18590 (Third Party)
    Memcheck:Leak
    ...
@@ -130,84 +101,6 @@
    fun:FcConfigValues
 }
 {
-   bug_18590a (Third Party)
-   Memcheck:Leak
-   fun:malloc
-   fun:FcConfigValues
-   fun:FcConfigSubstituteWithPat
-   fun:*SkFontConfigInterfaceDirect*match*
-}
-{
-   bug_46177_a (Third Party)
-   Memcheck:Leak
-   ...
-   fun:FcCharSetOperate
-   fun:FcFontSetSort
-   fun:FcFontSort
-   ...
-   fun:pango_layout_get_pixel_size
-}
-{
-   bug_46177_b (Third Party)
-   Memcheck:Leak
-   ...
-   fun:FcCharSetFindLeafCreate
-   fun:FcCharSetAddLeaf
-   fun:FcCharSetOperate
-   fun:FcFontSetSort
-   fun:FcFontSort
-   ...
-   fun:pango_layout_get_iter
-}
-{
-   bug_46177_c (Third Party)
-   Memcheck:Leak
-   ...
-   fun:FcCharSetFindLeafCreate
-   fun:FcCharSetAddLeaf
-   fun:FcCharSetOperate
-   fun:FcFontSetSort
-   fun:FcFontSort
-   ...
-   fun:pango_layout_line_get_extents
-}
-{
-   bug_46177_d (Third Party)
-   Memcheck:Leak
-   fun:malloc
-   fun:FcFontSetCreate
-   fun:FcFontSetSort
-   fun:FcFontSort
-}
-{
-   bug_46177_e (Third Party)
-   Memcheck:Leak
-   ...
-   fun:FcCharSetFindLeafCreate
-   fun:FcCharSetAddChar
-}
-{
-   bug_181572 (Skia -- global cache of typefaces)
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN10SkFontHost14CreateTypefaceEPK10SkTypefacePKcNS0_5StyleE
-   fun:_ZN10SkTypeface14CreateFromNameEPKcNS_5StyleE
-}
-{
-   dlopen invalid read, probably a bug in glibc.  TODO(dkegel): file glibc bug
-   Memcheck:Uninitialized
-   ...
-   fun:dlopen@@GLIBC_2.1
-   fun:PR_LoadLibraryWithFlags
-}
-{
-   dlopen leak on error. See http://sourceware.org/bugzilla/show_bug.cgi?id=12878.
-   Memcheck:Leak
-   fun:calloc
-   fun:_dlerror_run
-   fun:dlopen@@GLIBC_2.1
-}
-{
    dlopen leak on error. Chromium issues 268368,273385. See http://sourceware.org/bugzilla/show_bug.cgi?id=12878.
    Memcheck:Leak
    fun:calloc
@@ -215,338 +108,6 @@
    fun:dlopen@@GLIBC_2.2.5
 }
 {
-   glibc leak.  See also http://sources.redhat.com/bugzilla/show_bug.cgi?id=2451
-   Memcheck:Leak
-   fun:malloc
-   fun:_dl_map_object_from_fd
-}
-{
-   Pure NSS leak, does not involve glibc.  TODO(dkegel): track down and fix or file bug.
-   Memcheck:Leak
-   ...
-   fun:NSS_NoDB_Init
-}
-{
-   Another pure NSS leak, does not involve glibc.  TODO(dkegel): track down and fix or file bug.  Shows up under --show-reachable=yes.
-   Memcheck:Leak
-   ...
-   fun:SECMOD_LoadUserModule
-}
-{
-   Pure NSS leak, does not involve glibc.
-   Memcheck:Leak
-   ...
-   fun:SECMOD_AddNewModule
-}
-{
-   bug_12614 (Third Party)
-   Memcheck:Leak
-   fun:?alloc
-   ...
-   fun:PR_LoadLibraryWithFlags
-   ...
-   fun:SECMOD_LoadModule
-}
-{
-   NSS leak - https://bugzilla.mozilla.org/show_bug.cgi?id=762351 - fixed in NSS 3.13.6/3.14
-   Memcheck:Leak
-   ...
-   fun:PKIX_PL_Malloc
-   ...
-   fun:PKIX_PL_OID_Create
-   ...
-   fun:cert_PKIXMakeOIDList
-   fun:cert_pkixSetParam
-   fun:CERT_PKIXVerifyCert
-}
-{
-   libc_dynamiclinker_foo
-   Memcheck:Uninitialized
-   obj:/lib*/ld-2.*.so
-   obj:/lib*/ld-2.*.so
-}
-{
-   libc_dynamiclinker_bar
-   Memcheck:Unaddressable
-   obj:/lib*/ld-2.*.so
-   obj:/lib*/ld-2.*.so
-}
-{
-   libc_dynamiclinker_bar_2
-   Memcheck:Jump
-   obj:*
-   obj:/lib*/ld-2.*.so
-}
-{
-   FIXME epoll uninitialized data 1
-   Memcheck:Param
-   epoll_ctl(epfd)
-   fun:syscall
-   fun:event_add
-}
-{
-   FIXME epoll uninitialized data 2
-   Memcheck:Param
-   epoll_ctl(epfd)
-   fun:syscall
-   fun:event_del
-}
-{
-   FIXME epoll uninitialized data 3
-   Memcheck:Param
-   epoll_wait(epfd)
-   fun:syscall
-   fun:event_base_loop
-}
-{
-   # "The section of the SQLite library identified works exactly as it should."
-   # http://www.sqlite.org/cvstrac/tktview?tn=536,39
-   # http://www.sqlite.org/cvstrac/tktview?tn=694,39
-   # http://www.sqlite.org/cvstrac/tktview?tn=964,39
-   # This looks like a case where an entire page was allocated, the header and
-   # perhaps some data was written, but the entire buffer was not written to.
-   # The SQLite authors aren't very interested in adding code to clear buffers
-   # for no reason other than pleasing valgrind, but a patch might be accepted
-   # under a macro like SQLITE_SECURE_DELETE which could be construed to apply
-   # to cases like this. (Note that we compile with SQLITE_SECURE_DELETE.)
-   bug_20653a (Third Party)
-   Memcheck:Param
-   write(buf)
-   ...
-   fun:sqlite3OsWrite
-   fun:pager_write_pagelist
-}
-{
-   bug_20653b (Third Party)
-   Memcheck:Param
-   write(buf)
-   ...
-   fun:*Write
-   fun:sqlite3OsWrite
-   ...
-   fun:pager_write
-}
-{
-   # array of weak references freed but not processed?
-   bug_16576
-   Memcheck:Leak
-   ...
-   fun:g_object_weak_ref
-   fun:g_object_add_weak_pointer
-}
-{
-   # Totem plugin leaks when we load it.
-   bug_21326 (Third Party)
-   Memcheck:Leak
-   ...
-   fun:_ZN56webkit5npapi9PluginLib17ReadWebPluginInfoE*
-}
-{
-   # NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=518443
-   https://bugzilla.mozilla.org/show_bug.cgi?id=518443
-   Memcheck:Leak
-   fun:calloc
-   ...
-   fun:PORT_ZAlloc_Util
-   fun:PORT_NewArena_Util
-   fun:PK11_ImportAndReturnPrivateKey
-}
-{
-   bug_23314 (Third Party)
-   Memcheck:Unaddressable
-   fun:sqlite3PcacheClearSyncFlags
-   fun:syncJournal
-   fun:sqlite3PagerCommitPhaseOne
-   fun:sqlite3BtreeCommitPhaseOne
-}
-{
-   bug_23314b (Third Party)
-   Memcheck:Unaddressable
-   fun:sqlite3PcacheClearSyncFlags
-   fun:syncJournal
-   fun:sqlite3PagerCommitPhaseOne
-   fun:sqlite3BtreeCommitPhaseOne
-}
-{
-   http://sources.redhat.com/bugzilla/show_bug.cgi?id=5171
-   Memcheck:Leak
-   fun:calloc
-   fun:allocate_dtv
-   fun:_dl_allocate_tls
-   fun:pthread_create@@GLIBC_2.1
-}
-{
-   bug_33394 (Third Party)
-   Memcheck:Leak
-   fun:calloc
-   fun:PR_Calloc
-   fun:PR_NewLock
-   fun:_PR_UnixInit
-   fun:_PR_ImplicitInitialization
-   ...
-   fun:_ZN4base14EnsureNSPRInitEv
-}
-{
-   bug_33394_b (Third Party)
-   Memcheck:Leak
-   fun:calloc
-   fun:PR_Calloc
-   fun:PR_NewMonitor
-   fun:_PR_UnixInit
-   fun:_PR_ImplicitInitialization
-   ...
-   fun:_ZN4base14EnsureNSPRInitEv
-}
-{
-   # Looks like a leak in gtk's code when loading the im context module.
-   bug_41231 (Third Party)
-   Memcheck:Leak
-   ...
-   fun:malloc
-   fun:g_malloc
-   fun:g_strdup
-   fun:gtk_im_multicontext_get_slave
-   fun:gtk_im_multicontext_set_client_window
-   fun:gtk_im_context_set_client_window
-}
-{
-   bug_51332a (Third Party)
-   Memcheck:Leak
-   ...
-   fun:PORT_NewArena_Util
-   fun:sec_pkcs7_create_content_info
-   fun:SEC_PKCS7CreateData
-   fun:sec_pkcs12_encoder_start_context
-   fun:SEC_PKCS12Encode
-}
-{
-   bug_51332b (Third Party)
-   Memcheck:Leak
-   ...
-   fun:PORT_ArenaZAlloc_Util
-   fun:sec_pkcs7_create_content_info
-   fun:SEC_PKCS7CreateData
-   fun:sec_pkcs12_encoder_start_context
-   fun:SEC_PKCS12Encode
-}
-{
-   bug_51332c (Third Party)
-   Memcheck:Leak
-   fun:calloc
-   fun:PORT_ZAlloc_Util
-   fun:PORT_NewArena_Util
-   fun:sec_pkcs7_create_content_info
-   fun:sec_pkcs12_encoder_start_context
-   fun:SEC_PKCS12Encode
-}
-{
-   bug_51330 (Third Party)
-   Memcheck:Leak
-   ...
-   fun:p12u_DigestOpen
-   ...
-   fun:SEC_PKCS12DecoderUpdate
-}
-{
-   bug_51328a (Third Party)
-   Memcheck:Leak
-   ...
-   fun:SEC_ASN1DecoderUpdate_Util
-   ...
-   fun:SEC_ASN1DecoderUpdate_Util
-   fun:SEC_PKCS7DecoderUpdate
-   ...
-   fun:SEC_ASN1DecoderUpdate_Util
-   fun:SEC_PKCS12DecoderUpdate
-}
-{
-   bug_51328b (Third Party)
-   Memcheck:Leak
-   ...
-   fun:SEC_PKCS7DecoderStart
-   ...
-   fun:SEC_ASN1DecoderUpdate_Util
-   fun:SEC_PKCS12DecoderUpdate
-}
-{
-   # See http://sourceware.org/bugzilla/show_bug.cgi?id=14015.
-   bug_51770 (Third Party)
-   Memcheck:Leak
-   fun:calloc
-   fun:_dlerror_run
-   fun:dlsym
-}
-{
-   bug_58730_strlen_addr8 (Third Party)
-   Memcheck:Unaddressable
-   fun:__strlen_sse2
-}
-{
-   bug_58730_strlen_cond (Third Party)
-   Memcheck:Uninitialized
-   fun:__strlen_sse2
-}
-{
-   bug_58730_strcmp_addr8 (Third Party)
-   Memcheck:Unaddressable
-   fun:__strcmp_ssse3
-}
-{
-   bug_58730_strcmp_cond (Third Party)
-   Memcheck:Uninitialized
-   fun:__strcmp_ssse3
-}
-{
-   bug_58730_strcmp_value8 (Third Party)
-   Memcheck:Uninitialized
-   fun:__strcmp_ssse3
-}
-{
-   bug_58730_strncmp_value8 (Third Party)
-   Memcheck:Uninitialized
-   fun:__strncmp_ssse3
-}
-{
-   bug_58730_memmove_value4 (Third Party)
-   Memcheck:Uninitialized
-   fun:__memmove_ssse3
-}
-{
-   bug_58730_memmove_cond (Third Party)
-   Memcheck:Uninitialized
-   fun:__memmove_ssse3
-}
-{
-   bug_58730_memcpy_value4 (Third Party)
-   Memcheck:Uninitialized
-   fun:__memcpy_ssse3
-}
-{
-   bug_58730_memcpy_addr8 (Third Party)
-   Memcheck:Unaddressable
-   fun:__memcpy_ssse3
-}
-{
-   bug_58730_memcpy_cond (Third Party)
-   Memcheck:Uninitialized
-   fun:__memcpy_ssse3
-}
-{
-   bug_58730_memmove_chk_cond (Third Party)
-   Memcheck:Uninitialized
-   fun:__memmove_chk_ssse3
-}
-{
-   bug_58730_libc.so_addr8 (Third Party)
-   Memcheck:Unaddressable
-   obj:/lib/libc-2.*.so
-}
-{
-   bug_58730_libc.so_cond (Third Party)
-   Memcheck:Uninitialized
-   obj:/lib/libc-2.*.so
-}
-{
    bug_58730_libc.so_value8 (Third Party)
    Memcheck:Uninitialized
    obj:/lib/libc-2.11.1.so
@@ -561,36 +122,6 @@
    fun:_ZN3netL8SniffXMLEPKcmPbPSs
 }
 {
-   # I believe it's a bug in gtk+-2.12.x and should already be fixed in recent gtk.
-   bug_61685 (Third Party)
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:gtk_text_buffer_select_range
-   fun:*OmniboxViewGtk16SetSelectedRange*
-}
-{
-   bug_66941 (Third Party)
-   Memcheck:Leak
-   ...
-   fun:STAN_ChangeCertTrust
-   fun:CERT_ChangeCertTrust
-}
-{
-   leaks in bash
-   Memcheck:Leak
-   ...
-   obj:/bin/bash
-}
-{
-   bug_73000_fixed_upstream_in_gtk
-   Memcheck:Uninitialized
-   fun:clipboard_clipboard_buffer_received
-   ...
-   fun:gtk_text_view_key_press_event
-   fun:_ZN14OmniboxViewGtk14HandleKeyPressEP10_GtkWidgetP12_GdkEventKey
-}
-{
    bug_76386a (Third Party)
    Memcheck:Leak
    fun:_Znw*
@@ -606,23 +137,6 @@
    fun:_ZNSs4_Rep8_M_cloneERKSaIcE*
 }
 {
-   bug_76386c (Third Party)
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZNSs4_Rep9_S_createE*RKSaIcE
-   fun:_ZNSs9_M_mutateEjjj
-}
-{
-   bug_80378_fixed_upstream_for_next_gtk
-   Memcheck:Leak
-   fun:malloc
-   fun:g_malloc
-   fun:g_slice_alloc
-   ...
-   fun:gtk_window_group_list_windows
-   fun:_ZN8gtk_util*AppModal*
-}
-{
    getpwuid_and_getgrouplist
    Memcheck:Leak
    fun:malloc
@@ -632,43 +146,6 @@
    ...
    fun:get*
 }
-{
-   dbus_x64_leaks
-   Memcheck:Leak
-   ...
-   obj:/usr/bin/dbus-launch
-}
-{
-   pulseaudio: pa_set_env_and_record
-   Memcheck:Leak
-   fun:malloc
-   fun:realloc
-   fun:pa_xrealloc
-   fun:pa_sprintf_malloc
-   fun:pa_set_env
-   fun:pa_set_env_and_record
-   fun:main
-}
-
-# The following stack suppresses Memcheck false positives on NaCl browser_tests
-# See https://bugs.kde.org/show_bug.cgi?id=270709#c4 for possible reason
-{
-   bug_101755 valgrind_bitfields_false_positive
-   Memcheck:Uninitialized
-   ...
-   fun:_ZN7WebCore13WidthIterator*
-   ...
-   fun:_ZNK7WebCore4Font*
-}
-
-# Invalid frees from exit() and accept().
-{
-   bug_108618 (Third party)
-   Memcheck:Free
-   fun:free
-   fun:__libc_freeres
-   fun:_vgnU_freeres
-}
 
 # XRandRInfo object seems to be leaking inside XRRFindDisplay.  This happens the
 # first time it is called, no matter who the caller is.  We have observed this
@@ -680,114 +157,6 @@
    fun:XRRFindDisplay
 }
 {
-   Flash Player Leak
-   Memcheck:Leak
-   ...
-   obj:/usr/lib/flashplugin-installer/libflashplayer.so
-}
-{
-   Flash Player Unaddressable
-   Memcheck:Unaddressable
-   ...
-   obj:/usr/lib/flashplugin-installer/libflashplayer.so
-}
-{
-   Flash Player Uninitialized
-   Memcheck:Uninitialized
-   ...
-   obj:/usr/lib/flashplugin-installer/libflashplayer.so
-}
-{
-   Occasional leak inside setlocale()
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:_nl_make_l10nflist
-   fun:_nl_find_locale
-   fun:setlocale
-   fun:_ZN12_GLOBAL__N_121ContentMainRunnerImpl10InitializeEiPPKcPN7content19ContentMainDelegateE
-   fun:_ZN7content11ContentMainEiPPKcPNS_19ContentMainDelegateE
-   fun:ChromeMain
-}
-{
-   Occasional leak inside gdk_init()
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:_nl_find_domain
-   fun:__dcigettext
-   fun:gdk_screen_class_intern_init
-   fun:g_type_class_ref
-   fun:g_type_class_ref
-   fun:g_object_newv
-   fun:g_object_new
-   fun:_gdk_x11_screen_new
-   fun:gdk_display_open
-   fun:gdk_display_open_default_libgtk_only
-   fun:gdk_init_check
-   fun:gdk_init
-}
-{
-   bug_130770_a
-   Memcheck:Unaddressable
-   ...
-   fun:_mesa_glsl_compile_shader
-}
-{
-   bug_130770_b
-   Memcheck:Unaddressable
-   ...
-   fun:_mesa_glsl_link_shader
-}
-# leak in OSMesa used to run compositor_unittests in bots.
-{
-   bug_148477
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:_ZN3gfx9GLApiBase17glCompileShaderFnEj
-   fun:_ZN6webkit3gpu33WebGraphicsContext3DInProcessImpl13compileShaderEj
-   fun:_ZN2cc18ProgramBindingBase10LoadShaderEPN6WebKit20WebGraphicsContext3DEjRKSs
-   fun:_ZN2cc18ProgramBindingBase4InitEPN6WebKit20WebGraphicsContext3DERKSsS5_
-}
-{
-   bug_148477_link
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:_ZN3gfx9GLApiBase15glLinkProgramFnEj
-   fun:_ZN6webkit3gpu33WebGraphicsContext3DInProcessImpl11linkProgramEj
-   fun:_ZN2cc18ProgramBindingBase4LinkEPN6WebKit20WebGraphicsContext3DE
-   fun:_ZN2cc14ProgramBindingINS_*
-}
-# bug_todo_getdelim, bug_todo_getdelim2 and bug_todo_grep used to happen on
-# Google Lucid workstations only.
-{
-   bug_todo_getdelim
-   Memcheck:Leak
-   fun:malloc
-   fun:getdelim
-   ...
-   fun:call_init
-   fun:_dl_init
-}
-{
-   bug_todo_getdelim2
-   Memcheck:Leak
-   fun:malloc
-   fun:getdelim
-   obj:/lib/libselinux.so.1
-   obj:/lib/libselinux.so.1
-   obj:/lib/libselinux.so.1
-}
-{
-   bug_todo_grep
-   Memcheck:Leak
-   fun:malloc
-   obj:/bin/grep
-   obj:/bin/grep
-}
-{
    Ubuntu_Precise_Fontconfig_Optimized_Code
    Memcheck:Unaddressable
    fun:FcConfigFileExists
@@ -806,29 +175,6 @@
    fun:wcscmp
    fun:_ZN7testing8internal6String17WideCStringEqualsEPKwS3_
 }
-{
-   # Most plugins return a constant char * string, but this totem plugin
-   # uses printf and allocates one.
-   Ubuntu_Precise_totem_mime_desc_leak
-   Memcheck:Leak
-   fun:g_strdup_printf
-   obj:*/libtotem-cone-plugin.so
-   fun:_ZN6webkit5npapi9PluginLib17ReadWebPluginInfoERKN4base8FilePathEPNS_13WebPluginInfoE
-}
-{
-   glib/gthread malloc leak in component build
-   Memcheck:Leak
-   fun:malloc
-   ...
-   fun:g_thread_proxy
-}
-{
-   glib/gthread calloc leak in component build
-   Memcheck:Leak
-   fun:calloc
-   ...
-   fun:g_thread_proxy
-}
 
 #-----------------------------------------------------------------------
 # 2. intentional unit test errors, or stuff that is somehow a false positive
@@ -942,31 +288,6 @@
    fun:_ZN4base12_GLOBAL__N_169MessageLoopProxyTest_PostTaskAndReply_DeadReplyLoopDoesNotDelete_Test8TestBodyEv
 }
 {
-   logging::InitLogging never frees filename. It would be hard to free properly.
-   Memcheck:Leak
-   ...
-   fun:_ZN7logging11InitLoggingEPKcNS_18LoggingDestinationENS_15LogLockingStateENS_20OldFileDeletionStateE
-}
-{
-   Linux tests don't bother to undo net::SpawnedTestServer::LoadTestRootCert().
-   Memcheck:Leak
-   ...
-   fun:_ZN3net10SpawnedTestServer16LoadTestRootCertEv
-}
-{
-   # uitest's ResourceDispatcherTest.CrossSiteAfterCrash crashes on purpose
-   Intentional_crash
-   Memcheck:Unaddressable
-   fun:_ZN12AboutHandler10AboutCrashEv
-}
-{
-   Intentional_browser_test_crash
-   Memcheck:Unaddressable
-   fun:_ZL18CrashIntentionallyv
-   fun:_ZL19MaybeHandleDebugURLRK4GURL
-   fun:_ZN14RenderViewImpl10OnNavigateERK23ViewMsg_Navigate_Params
-}
-{
    # Non-joinable thread doesn't clean up all state on program exit
    # very common in ui tests
    bug_16096 (WontFix)
@@ -989,12 +310,6 @@
    fun:_ZN7WebCore8SVGNames4initEv
 }
 {
-   intentional_BrowserThreadTest_NotReleasedIfTargetThreadNonExistent_Test_leak
-   Memcheck:Leak
-   fun:_Znw*
-   fun:*BrowserThreadTest_NotReleasedIfTargetThreadNonExistent_Test8TestBodyEv
-}
-{
    # This is an on demand initialization which is done and then intentionally
    # kept around (not freed) while the process is running.
    intentional_WebCore_XMLNames_init_leak
@@ -1003,46 +318,6 @@
    fun:_ZN7WebCore8XMLNames4initEv
 }
 {
-   # This is WebKit wide theading initialization which is intentionally kept
-   # around (not freed) while the process is running.
-   intentional_WTF_ThreadIdentifierData_initialize_leak
-   Memcheck:Leak
-   ...
-   fun:_ZN3WTF20ThreadIdentifierData10initializeEj
-}
-{
-   # This is WebKit wide theading initialization which is intentionally kept
-   # around (not freed) while the process is running.
-   intentional_WTF_wtfThreadData_leak
-   Memcheck:Leak
-   ...
-   fun:_ZN3WTF13wtfThreadDataEv
-}
-{
-   # Intentional crash test
-   intentional_RendererCrashTest
-   Memcheck:Unaddressable
-   fun:_Z*33HandleRendererErrorTestParametersRK11CommandLine
-   fun:_Z12RendererMainRKN7content18MainFunctionParams*
-}
-{
-   # PR_GetCurrentThread allocates a PRThread structure and stores it in
-   # thread-specific data.  The PRThread structure is freed by the
-   # PR_DetachThread call in CertVerifierWorker::Run or when the thread
-   # terminates.  Since we do not shut down worker threads, the PRThread
-   # structure created for a worker thread may be leaked at Chrome shutdown
-   # if the worker thread did not make it to the PR_DetachThread call.
-   bug_32624 (Intentional)
-   Memcheck:Leak
-   fun:calloc
-   fun:PR_Calloc
-   fun:PR_GetCurrentThread
-   ...
-   fun:_ZNK3net15X509Certificate14VerifyInternalERKSsiPNS_16CertVerifyResultE
-   fun:_ZNK3net15X509Certificate6VerifyERKSsiPNS_16CertVerifyResultE
-   fun:_ZN3net18CertVerifierWorker3RunEv
-}
-{
    # Intentionally leaking NSS to prevent shutdown crashes
    bug_61585a (Intentional)
    Memcheck:Leak
@@ -1057,20 +332,6 @@
    fun:_ZN3net10FileStreamC1EPNS_6NetLogE
 }
 {
-   Tasks posted to WorkerPool can leak by design
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base8internal20PostTaskAndReplyImpl16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEESA_
-   fun:_ZN4base10WorkerPool16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEES9_b
-}
-{
-   bug_61585b (Intentional)
-   Memcheck:Leak
-   fun:malloc
-   fun:PL_ArenaAllocate
-   fun:PORT_ArenaAlloc*
-}
-{
    # Histograms are used on un-joined threads, and can't be deleted atexit.
    Histograms via FactoryGet including Linear Custom Boolean and Basic
    Memcheck:Leak
@@ -1079,20 +340,6 @@
    fun:_ZN4base*Histogram10FactoryGet*
 }
 {
-   # Histograms are used on un-joined threads, and can't be deleted atexit.
-   Histograms via FactoryGet including Stats for disk_cache
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN10disk_cache14StatsHistogram10FactoryGet*
-}
-{
-   Intentional leak for Histogram (in StatisticsRecorderTest, NotInitialized).
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base42StatisticsRecorderTest_NotInitialized_Test8TestBodyEv
-}
-{
    Intentional leak for SampleMap (stores SparseHistogram counts).
    Memcheck:Leak
    ...
@@ -1100,23 +347,6 @@
    fun:_ZN4base15SparseHistogram3AddEi
 }
 {
-   Intentional leak for list<const BucketRanges*>(in StatisticsRecorderTest, RegisterBucketRanges).
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base18StatisticsRecorder31RegisterOrDeleteDuplicateRangesEPKNS_12BucketRangesE
-   fun:_ZN4base48StatisticsRecorderTest_RegisterBucketRanges_Test8TestBodyEv
-}
-{
-   # See http://code.google.com/p/chromium/issues/detail?id=70062#c8
-   bug_70062 (Intentional)
-   Memcheck:Leak
-   ...
-   fun:InitSessionCacheLocks
-   fun:initSessionCacheLocksLazily
-   ...
-   fun:ssl_InitSessionCacheLocks
-}
-{
    bug_73299 (Intentional)
    Memcheck:Leak
    fun:_Znw*
@@ -1141,42 +371,6 @@
    fun:_ZN10disk_cache9BackendIO16ExecuteOperationEv
 }
 {
-   bug_87500_b (Intentional)
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base4Bind*TaskClosureAdapterEFvvEPS2_EENS_8internal20InvokerStorageHolderINS6_15InvokerStorage1IT_T0_EEEES9_RKSA_
-   fun:_ZN4base11MessageLoop15PostDelayedTaskERKN15tracked_objects8LocationEP4Taskx
-   fun:_ZN4base20MessageLoopProxyImpl14PostTaskHelperERKN15tracked_objects8LocationEP4Taskxb
-   fun:_ZN4base20MessageLoopProxyImpl8PostTaskERKN15tracked_objects8LocationEP4Task
-   fun:_ZN10disk_cache10InFlightIO12OnIOCompleteEPNS_12BackgroundIOE
-}
-{
-   bug_87500_c (Intentional)
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN3net9HttpCache*EntryERKSsPPNS0_11ActiveEntryEPNS0_11TransactionE
-   fun:_ZN3net9HttpCache11Transaction13Do*EntryEv
-   fun:_ZN3net9HttpCache11Transaction6DoLoopEi
-   fun:_ZN3net9HttpCache11Transaction12OnIOCompleteEi
-}
-{
-   Intentional, see http://codereview.chromium.org/7670025
-   Memcheck:Param
-   msync(start)
-   fun:msync$UNIX2003
-   fun:mach_override_ptr
-   fun:_ZN4base33EnableTerminationOnHeapCorruptionEv
-}
-{
-   # Intentional - data is stored in thread-local storage for an unjoined
-   # worker thread, and so can occasionally leak. See crbug.com/89553 for
-   # additional info
-   bug_89553
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN12_GLOBAL__N_111DnsReloader11MaybeReloadEv
-}
-{
    bug_79322 (Intentional)
    Memcheck:Leak
    fun:_Znw*
@@ -1184,21 +378,6 @@
    fun:_ZN4base*StatisticsRecorderTest_*_Test8TestBodyEv
 }
 {
-   # This test simulates a ppapi plugin that fails to decrement a reference
-   # count. In that case, the ppapi runtime will clean up its internal data
-   # structures, but intentionally does not delete the plugin object's
-   # desctructor, because we don't want them to have the opportunity to do
-   # anything at that part of shutdown.
-   bug_145710 (Intentional)
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN12TestInstance27TestLeakedObjectDestructorsEv
-   fun:_ZN12TestInstance8RunTestsERKSs
-   fun:_ZN15TestingInstance12ExecuteTestsEi
-   fun:_ZN2pp25CompletionCallbackFactoryI15TestingInstanceNS_22ThreadSafeThreadTraitsEE11Dispatcher0IMS1_FviEEclEPS1_i
-   fun:_ZN2pp25CompletionCallbackFactoryI15TestingInstanceNS_22ThreadSafeThreadTraitsEE12CallbackDataINS3_11Dispatcher0IMS1_FviEEEE5ThunkEPvi
-}
-{
    intentional_see_bug_156466
    Memcheck:Leak
    fun:_Znw*
@@ -6063,7 +5242,7 @@
    bug_222898
    Memcheck:Leak
    fun:malloc
-   fun:_ZN3WTF10fastMallocEm
+   ...
    fun:_ZN3WTF9BitVector13OutOfLineBits6createEm
    fun:_ZN3WTF9BitVector15resizeOutOfLineEm
    fun:_ZN3WTF9BitVector10ensureSizeEm
@@ -6238,7 +5417,7 @@
    bug_239141
    Memcheck:Leak
    fun:malloc
-   fun:_ZN3WTF10fastMallocEm
+   ...
    fun:_ZN3WTF9BitVector13OutOfLineBits6createEm
    fun:_ZN3WTF9BitVector15resizeOutOfLineEm
    fun:_ZN3WTF9BitVector10ensureSizeEm
@@ -6331,7 +5510,7 @@
    bug_242672
    Memcheck:Leak
    fun:malloc
-   fun:_ZN3WTF10fastMallocEm
+   ...
    fun:_ZN3WTF9BitVector13OutOfLineBits6createEm
    fun:_ZN3WTF9BitVector15resizeOutOfLineEm
    fun:_ZN3WTF9BitVector10ensureSizeEm
@@ -7067,7 +6246,7 @@
    fun:_ZN3WTF10fastMallocEm
    fun:_ZN3WTF24ThreadSafeRefCountedBasenwEm
    fun:_ZN6WebKit12_GLOBAL__N_131AllowFileSystemMainThreadBridge6createEPN7WebCore17WorkerGlobalScopeEPNS_13WebWorkerBaseERKN3WTF6StringE
-   fun:_ZN6WebKit22WorkerFileSystemClient15allowFileSystemEPN7WebCore22ScriptExecutionContextE
+   fun:_ZN6WebKit22WorkerFileSystemClient15allowFileSystem*
    ...
    fun:_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE
 }
@@ -7228,3 +6407,44 @@
    fun:_ZN7content16RenderThreadImpl23EnsureWebKitInitializedEv
    fun:_ZN7content16RenderThreadImpl15OnCreateNewViewERK18ViewMsg_New_Params
 }
+{
+   bug_310351
+   Memcheck:Leak
+   ...
+   fun:_ZN3WTF12PthreadStatenwEm
+   fun:_ZN3WTFL35establishIdentifierForPthreadHandleERK*
+   fun:_ZN3WTF13currentThreadEv
+   fun:_ZN3WTF20initializeMainThreadEPFvPFvPvES0_E
+}
+{
+   bug_311229
+   Memcheck:Leak
+   fun:malloc
+   fun:_ZN3WTF10fastMallocEm
+   fun:_ZN3WTF24ThreadSafeRefCountedBasenwEm
+   fun:_ZN7WebCore18MessagePortChannel6createEPN6WebKit21WebMessagePortChannelE
+   fun:_ZN7WebCore18MessagePortChannel13createChannelEPNS_11MessagePortES2_
+   fun:_ZN7WebCore14MessageChannelC1EPNS_16ExecutionContextE
+   fun:_ZN7WebCore14MessageChannel6createEPNS_16ExecutionContextE
+   fun:_ZN7WebCore16V8MessageChannel17constructorCustomERKN2v820FunctionCallbackInfoINS1_5ValueEEE
+   fun:_ZN7WebCore16V8MessageChannel19constructorCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE
+   fun:_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE
+   fun:_ZN2v88internalL19HandleApiCallHelperILb1EEEPNS0_11MaybeObjectENS0_12_GLOBAL__N_116BuiltinArgumentsILNS0_21BuiltinExtraArgumentsE1EEEPNS0_7IsolateE
+   fun:_ZN2v88internalL34Builtin_implHandleApiCallConstructENS0_12_GLOBAL__N_116BuiltinArgumentsILNS0_21BuiltinExtraArgumentsE1EEEPNS0_7IsolateE
+   fun:_ZN2v88internalL30Builtin_HandleApiCallConstructEiPPNS0_6ObjectEPNS0_7IsolateE
+}
+{
+   bug_312332
+   Memcheck:Uninitialized
+   ...
+   fun:_ZNK7WebCore17RenderTextControl29computeIntrinsicLogicalWidthsERNS_10LayoutUnitES2_
+   fun:_ZN7WebCore17RenderTextControl29computePreferredLogicalWidthsEv
+   ...
+   fun:_ZN7WebCore11RenderBlock6layoutEv
+}
+{
+   bug_313521
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN8app_list32AppListModelTest_FolderItem_Test8TestBodyEv
+}
diff --git a/tools/valgrind/memcheck/suppressions_linux.txt b/tools/valgrind/memcheck/suppressions_linux.txt
index b37ce32..6ce4607 100644
--- a/tools/valgrind/memcheck/suppressions_linux.txt
+++ b/tools/valgrind/memcheck/suppressions_linux.txt
@@ -16,17 +16,6 @@
 #-----------------------------------------------------------------------
 
 # 1. Third party stuff we have no control over.
-{
-   # The InvalidRead error in rc4_wordconv is intentional.
-   # https://bugzilla.mozilla.org/show_bug.cgi?id=341127
-   # TODO(wtc): This invalid read has been fixed in NSS 3.15.  Remove this
-   # suppression when the system NSS libraries in Linux distributions are
-   # version 3.15 or later.
-   bug_43113 (Intentional)
-   Memcheck:Unaddressable
-   fun:rc4_wordconv
-   fun:RC4_Encrypt
-}
 
 # 2. Intentional unit test errors, stuff that is somehow a false positive
 # in our own code, or stuff that is so trivial it's not worth fixing.
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index 2124a79..b8dd333 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -29,65 +29,6 @@
    ...
 }
 {
-   # Mac system library bug?  See http://crbug.com/11327
-   bug_11327
-   Memcheck:Uninitialized
-   fun:_ZN19AudioConverterChain5ResetEv
-   fun:AudioConverterReset
-   obj:/System/Library/Components/CoreAudio.component/Contents/MacOS/CoreAudio
-}
-{
-   # Mac system library bug?  See http://crbug.com/11327
-   bug_11327b
-   Memcheck:Uninitialized
-   fun:AUNetSendEntry
-   fun:AUNetSendEntry
-   obj:/System/Library/Components/CoreAudio.component/Contents/MacOS/CoreAudio
-}
-{
-   # Filed with Apple as rdar://6915060; see http://crbug.com/11270
-   bug_11270
-   Memcheck:Leak
-   fun:calloc
-   fun:CMSSetLabCLUT
-}
-{
-   # Mac leak in CMOpenOrNewAccess in unit_tests PlatformCanvas_SkLayer_Test,
-   # ToolbarControllerTest_FocusLocation_Test. See http://crbug.com/11333.
-   bug_11333
-   Memcheck:Leak
-   fun:malloc
-   fun:stdSmartNewPtr
-   fun:stdSmartNewHandle
-   fun:IOCreateAndOpen
-   fun:ScratchInit
-   fun:CMOpenOrNewAccess
-}
-{
-   # suddenly very common as of 6 aug 2009
-   bug_11333b
-   Memcheck:Leak
-   fun:malloc
-   fun:stdSmartNewPtr
-   fun:stdSmartNewHandle
-   fun:IOCreateAndOpen
-   fun:ScratchInit
-   fun:CMNewAccessFromAnother
-}
-{
-   # Tiny one-time leak, widely seen by valgind users; everyone suppresses this.
-   # See related discussion at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39366
-   plugin_bundle_global_leak
-   Memcheck:Leak
-   fun:malloc
-   fun:__cxa_get_globals
-   fun:__cxa_allocate_exception
-   fun:_ZN4dyld4loadEPKcRKNS_11LoadContextE
-   fun:dlopen
-   fun:dlopen
-   fun:_CFBundleDlfcnCheckLoaded
-}
-{
    bug_18215
    Memcheck:Uninitialized
    fun:_DPSNextEvent
@@ -95,23 +36,6 @@
    fun:-[NSApplication run]
 }
 {
-   bug_18223
-   Memcheck:Uninitialized
-   fun:_ZNK8Security12UnixPlusPlus17StaticForkMonitorclEv
-   fun:_ZN12ocspdGlobals10serverPortEv
-}
-{
-   # Filed with Apple as rdar://7255382
-   bug_20459a
-   Memcheck:Leak
-   ...
-   fun:_CFRuntimeCreateInstance
-   fun:CFRunLoopSourceCreate
-   fun:CFMachPortCreateRunLoopSource
-   fun:_ZN8Security12MachPlusPlus10CFAutoPort6enableEv
-   fun:_ZN8Security14SecurityServer14ThreadNotifierC2Ev
-}
-{
    # Also filed with Apple as rdar://7255382
    bug_20459b
    Memcheck:Leak
@@ -122,97 +46,6 @@
    ...
    fun:_ZN8Security12KeychainCore5Trust8evaluate*
 }
-# See description of bug_20653a/b in suppressions.txt.
-{
-   bug_20653a_mac
-   Memcheck:Param
-   write(buf)
-   fun:write$UNIX2003
-   fun:pager_write_pagelist
-}
-{
-   bug_20653b_mac
-   Memcheck:Param
-   write(buf)
-   fun:write$UNIX2003
-   ...
-   fun:pager_write
-}
-
-# See http://www.openradar.me/8287193
-{
-   Invalid redzone accesses in DKeyHas8Words
-   Memcheck:Unaddressable
-   fun:DKeyHas8Words
-}
-
-# See https://bugs.kde.org/show_bug.cgi?id=188572
-# This suppression is missing in Valgrind on Mac 10.6
-# TODO(glider): remove it once it arrives in the trunk.
-{
-   Unavoidable leak in setenv()
-   Memcheck:Leak
-   fun:malloc_zone_malloc
-   fun:__setenv
-   fun:setenv$UNIX2003
-}
-{
-   # Reported to Apple as rdar://6915429
-   bug_12525
-   Memcheck:Leak
-   ...
-   fun:-[CIContextImpl render:toBitmap:rowBytes:bounds:format:colorSpace:]
-}
-{
-   bug_69436
-   Memcheck:Leak
-   ...
-   fun:-[CIKernel initWithCString:noCopy:]
-   ...
-   fun:-[NSPopUpButtonCell _drawIndicatorWithFrame:inView:]
-}
-{
-   # Capturer on Mac uses OpenGL driver, which triggers several warnings.
-   # The check has to be quite generic, as different hardware graphics cards
-   # will cause different sets of warnings.
-   bug_75037
-   Memcheck:Uninitialized
-   ...
-   fun:_ZN8remoting*CapturerMac*
-}
-{
-   # See also http://openradar.appspot.com/radar?id=1235407
-   bug_77063
-   Memcheck:Free
-   fun:_ZdlPv
-   fun:_ZN15THFSPlusCatalogD2Ev
-   fun:_ZN5TNode10SetCatalogEP15THFSPlusCatalog
-   fun:_ZN15TMountPointList9AddVolumeEsb
-   fun:_ZN15TMountPointList4FindEsPN5TNode12StPopulatingE
-   fun:_ZN15TMountPointList20SupportsInvisibleBitEsPN5TNode12StPopulatingEb
-   fun:_ZNK21THFSPlusPropertyStore4OpenEbb
-   fun:_ZNK21THFSPlusPropertyStore13GetPropertiesEb
-   fun:_ZN16TFSCopyOperation22GetSourcePropertyStoreERK11THFSPlusRef
-   fun:_ZN16TFSCopyOperation13DoMoveToTrashERK11THFSPlusRef
-   fun:_ZN16TFSCopyOperation3RunEv
-   fun:_FSOperation
-   fun:_FSOperateOnObjectSync
-   fun:FSMoveObjectToTrashSync
-   fun:_Z9TrashFunc*FilePath
-}
-{
-   # See also http://openradar.appspot.com/radar?id=1169404
-   bug_79533a
-   Memcheck:Uninitialized
-   ...
-   fun:_Z*19cssm_DataAbortQuery17cssm_dl_db_handlel
-   fun:CSSM_DL_DataAbortQuery
-   fun:_ZN11SSDLSession14DataAbortQueryEll
-   fun:_Z*19cssm_DataAbortQuery17cssm_dl_db_handlel
-   fun:CSSM_DL_DataAbortQuery
-   fun:tpDbFindIssuerCrl
-   fun:tpVerifyCertGroupWithCrls
-}
 {
    # See also http://openradar.appspot.com/radar?id=1169404
    bug_79533b
@@ -227,61 +60,6 @@
    fun:tpVerifyCertGroupWithCrls
 }
 {
-   bug_85213_a
-   Memcheck:Leak
-   ...
-   fun:_CFBundleCopyDirectoryContentsAtPath
-}
-{
-   bug_85213_b
-   Memcheck:Leak
-   ...
-   fun:_CFBundleCopyInfoDictionaryInDirectoryWithVersion
-}
-{
-   bug_85213_c
-   Memcheck:Leak
-   ...
-   fun:_CFBundleURLLooksLikeBundleVersion
-}
-{
-   bug_85213_d
-   Memcheck:Leak
-   ...
-   fun:_CFBundleCreate
-   fun:_ZN6webkit5npapi9PluginLib17ReadWebPluginInfoE*
-}
-{
-   bug_85213_e
-   Memcheck:Leak
-   ...
-   fun:CFBundlePreflightExecutable
-   fun:_ZN6webkit5npapi9PluginLib17ReadWebPluginInfoE*
-}
-{
-   bug_85213_f
-   Memcheck:Leak
-   ...
-   fun:CFBundleGetPackageInfo
-   fun:_ZN6webkit5npapi9PluginLib17ReadWebPluginInfoE*
-}
-{
-   bug_86927
-   Memcheck:Leak
-   fun:malloc
-   fun:CGSMapShmem
-   fun:CGSResolveShmemReference
-   fun:CGSScoreboard
-   fun:initCGDisplayState
-   fun:initCGDisplayMappings
-   fun:cgsInit
-   fun:pthread_once
-   fun:CGSInitialize
-   fun:CGSServerOperationState
-   fun:+[NSThemeFrame initialize]
-   fun:_class_initialize
-}
-{
    # QTKit leak. See http://crbug.com/100772 and rdar://10319535.
    bug_100772
    Memcheck:Leak
@@ -325,18 +103,6 @@
 # 2. Intentional unit test errors, stuff that is somehow a false positive
 # in our own code, or stuff that is so trivial it's not worth fixing.
 {
-   # Plugins are deliberately not unloaded (on shutdown) on the Mac, in order to
-   # prevent crashes for those that don't unload cleanly.
-   plugin_unload
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4base17LoadNativeLibraryE*
-   fun:_ZN6webkit5npapi9PluginLib4LoadEv
-   fun:_ZN6webkit5npapi9PluginLib13NP_InitializeEv
-   fun:_ZN6webkit5npapi21WebPluginDelegateImpl6CreateE*
-   fun:_ZN19TestWebViewDelegate20CreatePluginDelegateE*
-}
-{
    # Mac Sandbox test cases are registered in a global map.  This code is only
    # used in the unit test binary.
    Mac_Sandbox_Intentional_Leak1
@@ -350,22 +116,6 @@
    fun:_ZN4dyld24initializeMainExecutableEv
 }
 {
-   # The ConfirmQuitPanelController animates out and releases itself. And
-   # CocoaTest::TearDown() still sees this window and deques events for it,
-   # but one of those events creates this TSM Context that gets leaked.
-   # See http://crbug.com/61816 for more details.
-   # ut*AllSelectedIMInDoc = fun:utOpenActivateAllSelectedIMInDoc or
-   #                         fun:utDeactivateAllSelectedIMInDoc
-   Mac_Animated_Window_Close_ProcessNotification_Event
-   Memcheck:Leak
-   fun:malloc_zone_malloc
-   fun:_CFRuntimeCreateInstance
-   fun:__CFDictionaryInit
-   fun:ut*AllSelectedIMInDoc
-   ...
-   fun:My*ctivateTSMDocument
-}
-{
    # __cxa_get_globals leaks a structure when called for the first time
    __cxa_get_globals one-time leak
    Memcheck:Leak
@@ -373,20 +123,6 @@
    fun:__cxa_get_globals
 }
 {
-   bug_93711_a - intentional
-   Memcheck:Param
-   msync(start)
-   fun:msync$UNIX2003
-   fun:mach_override_ptr
-}
-{
-   bug_93711_b - likely induced by an intentional memory error
-   Memcheck:Leak
-   fun:malloc
-   fun:allocateBranchIsland
-   fun:mach_override_ptr
-}
-{
    # Intentional leak of a time-based self-deleting object.
    bug_264886
    Memcheck:Leak
@@ -1628,18 +1364,6 @@
    fun:_ZN14KeychainSearch17FindMatchingItemsEPSt6vectorIP24OpaqueSecKeychainItemRefSaIS2_EE
 }
 {
-   bug_96684a
-   Memcheck:Uninitialized
-   fun:_ZN7content20P2PSocketHostTcpBase4SendERKN3net10IPEndPointERKSt6vectorIcSaIcEE
-   fun:*SocketHost*TcpTest_*_Test8TestBodyEv
-}
-{
-   bug_96684b
-   Memcheck:Uninitialized
-   fun:_ZN7content16P2PSocketHostUdp4SendERKN3net10IPEndPointERKSt6vectorIcSaIcEE
-   fun:*SocketHostUdpTest_*_Test8TestBodyEv
-}
-{
    bug_96689
    Memcheck:Uninitialized
    fun:_ZN3net11SSLHostInfo10ParseInnerERKSs
@@ -2609,14 +2333,17 @@
    fun:_ZN10TType1Font7GetFontEPK5TFont
 }
 {
-   bug_308683_a
-   Memcheck:Uninitialized
-   fun:_ZN7content16P2PSocketHostUdp4SendERKN3net10IPEndPointERKSt6vectorIcSaIcEEy
-   fun:_ZN7content*P2PSocketHostUdpTest_Send*
+   bug_310761_a
+   Memcheck:Leak
+   fun:malloc
+   fun:_NPN_Get*Identifier
+   fun:_ZN6WebKit11WebBindings*get*Identifier*
 }
 {
-   bug_308683_b
-   Memcheck:Uninitialized
-   fun:_ZN7content20P2PSocketHostTcpBase4SendERKN3net10IPEndPointERKSt6vectorIcSaIcEEy
-   fun:_ZN7content*P2PSocketHost*
+   bug_310761_b
+   Memcheck:Leak
+   fun:malloc
+   fun:_ZN3WTF10fastMallocEm
+   fun:_ZN7WebCore*TerminatedArrayBuilder*
+   fun:_ZN7WebCore7RuleSet19compactPendingRules*
 }
diff --git a/tools/valgrind/test_suppressions.py b/tools/valgrind/test_suppressions.py
index 8c0900d..26eb8f5 100755
--- a/tools/valgrind/test_suppressions.py
+++ b/tools/valgrind/test_suppressions.py
@@ -126,7 +126,8 @@
       cur_supp += supp['win_suppressions']
     elif all([re.search("Linux%20", url) for url in all_reports[r]]):
       cur_supp += supp['linux_suppressions']
-    elif all([re.search("%20Heapcheck", url)
+    # Separate from OS matches as we want to match "Linux%20Heapcheck" twice:
+    if all([re.search("%20Heapcheck", url)
               for url in all_reports[r]]):
       cur_supp += supp['heapcheck_suppressions']
     if all(["DrMemory" in url for url in all_reports[r]]):
diff --git a/tools/valgrind/tsan_v2/suppressions.txt b/tools/valgrind/tsan_v2/suppressions.txt
index 6b1f12e..acd4c4a 100644
--- a/tools/valgrind/tsan_v2/suppressions.txt
+++ b/tools/valgrind/tsan_v2/suppressions.txt
@@ -137,3 +137,6 @@
 
 # http://crbug.com/305459
 race:base::debug::TraceEventTestFixture_TraceContinuousSampling_Test::TestBody
+
+# http://crbug.com/310851
+race:net::ProxyResolverV8Tracing::Job::~Job
diff --git a/ui/OWNERS b/ui/OWNERS
index 585112d..b88f27b 100644
--- a/ui/OWNERS
+++ b/ui/OWNERS
@@ -4,12 +4,6 @@
 # Mac stuff
 thakis@chromium.org
 
-# Android
-per-file *android*=bulach@chromium.org
-per-file *android*=tedchoc@chromium.org
-per-file *android*=yfriedman@chromium.org
-per-file *android*=newt@chromium.org
-
 per-file *.isolate=csharp@chromium.org
 per-file *.isolate=maruel@chromium.org
 
diff --git a/ui/android/java/src/org/chromium/ui/Clipboard.java b/ui/android/java/src/org/chromium/ui/Clipboard.java
index a66fa3d..b4e0c21 100644
--- a/ui/android/java/src/org/chromium/ui/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/Clipboard.java
@@ -10,6 +10,7 @@
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
+import android.os.Build;
 import android.text.TextUtils;
 
 /**
@@ -90,6 +91,22 @@
     }
 
     /**
+     * Writes HTML to the clipboard, together with a plain-text representation
+     * of that very data. This API is only available in Android JellyBean+ and
+     * will be a no-operation in older versions.
+     *
+     * @param html The HTML content to be pasted to the clipboard.
+     * @param text Plain-text representation of the HTML content.
+     */
+    @CalledByNative
+    private void setHTMLText(final String html, final String text) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            mClipboardManager.setPrimaryClip(
+                    ClipData.newHtmlText(null, text, html));
+        }
+    }
+
+    /**
      * Approximates the behavior of the now-deprecated
      * {@link android.text.ClipboardManager#hasText()}, returning true if and
      * only if the clipboard has a primary clip and that clip contains a plain
diff --git a/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java b/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java
index 895d347..89325fb 100644
--- a/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java
+++ b/ui/android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java
@@ -5,6 +5,8 @@
 package org.chromium.ui.gfx;
 
 import android.content.Context;
+import android.content.ComponentCallbacks;
+import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.Build;
 import android.util.DisplayMetrics;
@@ -124,6 +126,26 @@
       return mAppContext.getResources().getConfiguration().smallestScreenWidthDp;
   }
 
+  private void registerListener() {
+      mAppContext.registerComponentCallbacks(
+          new ComponentCallbacks() {
+              @Override
+              public void onConfigurationChanged(Configuration configuration) {
+                  updateNativeSharedDisplayInfo();
+              }
+
+              @Override
+              public void onLowMemory() {
+              }
+      });
+  }
+
+  private void updateNativeSharedDisplayInfo() {
+      nativeUpdateSharedDeviceDisplayInfo(getDisplayHeight(),
+          getDisplayWidth(), getBitsPerPixel(), getBitsPerComponent(),
+          getDIPScale(), getSmallestDIPWidth());
+  }
+
   private Display getDisplay() {
       return mWinManager.getDefaultDisplay();
   }
@@ -137,8 +159,20 @@
    * @param context A context to use.
    * @return DeviceDisplayInfo associated with a given Context.
    */
-  @CalledByNative
   public static DeviceDisplayInfo create(Context context) {
       return new DeviceDisplayInfo(context);
   }
+
+  @CalledByNative
+  private static DeviceDisplayInfo createWithListener(Context context) {
+      DeviceDisplayInfo deviceDisplayInfo = new DeviceDisplayInfo(context);
+      deviceDisplayInfo.registerListener();
+      return deviceDisplayInfo;
+  }
+
+  private native void nativeUpdateSharedDeviceDisplayInfo(int displayHeight,
+                        int displayWidth, int bitsPerPixel,
+                        int bitsPerComponent, double dipScale,
+                        int smallestDIPWidth);
+
 }
diff --git a/ui/android/java/strings/translations/android_ui_strings_am.xtb b/ui/android/java/strings/translations/android_ui_strings_am.xtb
index 5009378..dddfdd2 100644
--- a/ui/android/java/strings/translations/android_ui_strings_am.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_am.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="am">
 <translation id="7658239707568436148">ሰርዝ</translation>
+<translation id="9068849894565669697">ቀለም ይምረጡ</translation>
+<translation id="793640675459356075">የተመረጠውን ፋይል መክፈት አልተሳካም</translation>
 <translation id="6727102863431372879">አዘጋጅ</translation>
+<translation id="6315516427814392808">በአነስተኛ ማህደረ ትውስታ ምክንያት ቀዳሚውን ክወና ማጠናቀቅ አልተቻለም</translation>
 <translation id="6042308850641462728">ተጨማሪ</translation>
+<translation id="7535087603100972091">እሴት</translation>
+<translation id="8889402386540077796">ለይ ቀለም</translation>
+<translation id="3329013043687509092">የቀለም ሙሌት</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ar.xtb b/ui/android/java/strings/translations/android_ui_strings_ar.xtb
index 20d74b0..6683a96 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ar.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ar.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ar">
 <translation id="7658239707568436148">إلغاء</translation>
+<translation id="9068849894565669697">اختيار اللون</translation>
+<translation id="793640675459356075">أخفق فتح الملف المحدد</translation>
 <translation id="6727102863431372879">تعيين</translation>
+<translation id="6315516427814392808">تعذر إكمال العملية السابقة نظرًا لانخفاض الذاكرة</translation>
 <translation id="6042308850641462728">المزيد</translation>
+<translation id="7535087603100972091">القيمة</translation>
+<translation id="8889402386540077796">تدرج اللون</translation>
+<translation id="3329013043687509092">تشبع اللون</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_bg.xtb b/ui/android/java/strings/translations/android_ui_strings_bg.xtb
index 3f7f0ee..4890efd 100644
--- a/ui/android/java/strings/translations/android_ui_strings_bg.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_bg.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="bg">
 <translation id="7658239707568436148">Отказ</translation>
+<translation id="9068849894565669697">Избор на цвят</translation>
+<translation id="793640675459356075">Файлът не можа да се отвори</translation>
 <translation id="6727102863431372879">Задаване</translation>
+<translation id="6315516427814392808">Предишната операция не можа да завърши поради недостиг на памет</translation>
 <translation id="6042308850641462728">Още</translation>
+<translation id="7535087603100972091">Стойност</translation>
+<translation id="8889402386540077796">Цветови тон</translation>
+<translation id="3329013043687509092">Насищане</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ca.xtb b/ui/android/java/strings/translations/android_ui_strings_ca.xtb
index b19aac4..c2006d4 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ca.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ca.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ca">
 <translation id="7658239707568436148">Cancel·la</translation>
+<translation id="9068849894565669697">Selecció de color</translation>
+<translation id="793640675459356075">No s'ha pogut obrir fitxer sel.</translation>
 <translation id="6727102863431372879">Configura</translation>
+<translation id="6315516427814392808">No es pot completar l'operació anterior perquè hi ha poca memòria.</translation>
 <translation id="6042308850641462728">Més</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="8889402386540077796">To</translation>
+<translation id="3329013043687509092">Saturació</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_cs.xtb b/ui/android/java/strings/translations/android_ui_strings_cs.xtb
index b39bcf8..9d89dca 100644
--- a/ui/android/java/strings/translations/android_ui_strings_cs.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_cs.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="cs">
 <translation id="7658239707568436148">Zrušit</translation>
+<translation id="9068849894565669697">Výběr barvy</translation>
+<translation id="793640675459356075">Vybraný soubor nelze otevřít</translation>
 <translation id="6727102863431372879">Nastavit</translation>
+<translation id="6315516427814392808">Předchozí operaci nelze dokončit z důvodu nedostatku paměti</translation>
 <translation id="6042308850641462728">Více</translation>
+<translation id="7535087603100972091">Hodnota</translation>
+<translation id="8889402386540077796">Odstín</translation>
+<translation id="3329013043687509092">Sytost</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_da.xtb b/ui/android/java/strings/translations/android_ui_strings_da.xtb
index bdc4393..6dc993f 100644
--- a/ui/android/java/strings/translations/android_ui_strings_da.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_da.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="da">
 <translation id="7658239707568436148">Annuller</translation>
+<translation id="9068849894565669697">Vælg farve</translation>
+<translation id="793640675459356075">Den valgte fil kunne ikke åbnes</translation>
 <translation id="6727102863431372879">Angiv</translation>
+<translation id="6315516427814392808">Den tidligerere handling kunne ikke fuldføres på grund af manglende hukommelse</translation>
 <translation id="6042308850641462728">Mere</translation>
+<translation id="7535087603100972091">Værdi</translation>
+<translation id="8889402386540077796">Farvetone</translation>
+<translation id="3329013043687509092">Mætning</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_de.xtb b/ui/android/java/strings/translations/android_ui_strings_de.xtb
index 3226fe1..32fc348 100644
--- a/ui/android/java/strings/translations/android_ui_strings_de.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_de.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="de">
 <translation id="7658239707568436148">Abbrechen</translation>
+<translation id="9068849894565669697">Farbe auswählen</translation>
+<translation id="793640675459356075">Fehler beim Öffnen der Datei</translation>
 <translation id="6727102863431372879">Festlegen</translation>
+<translation id="6315516427814392808">Zu wenig Speicher für vorherige Operation</translation>
 <translation id="6042308850641462728">Mehr</translation>
+<translation id="7535087603100972091">Wert</translation>
+<translation id="8889402386540077796">Farbton</translation>
+<translation id="3329013043687509092">Sättigung</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_el.xtb b/ui/android/java/strings/translations/android_ui_strings_el.xtb
index 23bcfbb..e6eee43 100644
--- a/ui/android/java/strings/translations/android_ui_strings_el.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_el.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="el">
 <translation id="7658239707568436148">Ακύρωση</translation>
+<translation id="9068849894565669697">Επιλογή χρώματος</translation>
+<translation id="793640675459356075">Αποτυχ. ανοίγμ. επιλεγμ. αρχείου</translation>
 <translation id="6727102863431372879">Ορισμός</translation>
+<translation id="6315516427814392808">Δεν ήταν δυνατή η ολοκλήρωση της προηγούμενης λειτουργίας λόγω χαμηλού επιπέδου μνήμης</translation>
 <translation id="6042308850641462728">Περισσότερα</translation>
+<translation id="7535087603100972091">Τιμή</translation>
+<translation id="8889402386540077796">Απόχρωση</translation>
+<translation id="3329013043687509092">Κορεσμός</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_en-GB.xtb b/ui/android/java/strings/translations/android_ui_strings_en-GB.xtb
index 760ecfb..7e5cafd 100644
--- a/ui/android/java/strings/translations/android_ui_strings_en-GB.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_en-GB.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="en-GB">
 <translation id="7658239707568436148">Cancel</translation>
+<translation id="9068849894565669697">Select colour</translation>
+<translation id="793640675459356075">Failed to open selected file</translation>
 <translation id="6727102863431372879">Set</translation>
+<translation id="6315516427814392808">Unable to complete previous operation due to low memory</translation>
 <translation id="6042308850641462728">More</translation>
+<translation id="7535087603100972091">Value</translation>
+<translation id="8889402386540077796">Hue</translation>
+<translation id="3329013043687509092">Saturation</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_es-419.xtb b/ui/android/java/strings/translations/android_ui_strings_es-419.xtb
index a72fce8..820f446 100644
--- a/ui/android/java/strings/translations/android_ui_strings_es-419.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_es-419.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="es-419">
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="9068849894565669697">Seleccionar color</translation>
+<translation id="793640675459356075">Error al abrir el archivo</translation>
 <translation id="6727102863431372879">Establecer</translation>
+<translation id="6315516427814392808">Memoria insuficiente para completar la operación anterior</translation>
 <translation id="6042308850641462728">Más</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="8889402386540077796">Tono</translation>
+<translation id="3329013043687509092">Saturación</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_es.xtb b/ui/android/java/strings/translations/android_ui_strings_es.xtb
index 13d9dcb..306d8df 100644
--- a/ui/android/java/strings/translations/android_ui_strings_es.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_es.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="es">
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="9068849894565669697">Seleccionar color</translation>
+<translation id="793640675459356075">Error abrir archivo seleccionado</translation>
 <translation id="6727102863431372879">Establecer</translation>
+<translation id="6315516427814392808">No se ha podido completar la operación anterior por falta de memoria</translation>
 <translation id="6042308850641462728">Más</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="8889402386540077796">Matiz</translation>
+<translation id="3329013043687509092">Saturación</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_fa.xtb b/ui/android/java/strings/translations/android_ui_strings_fa.xtb
index a5250a0..77632c7 100644
--- a/ui/android/java/strings/translations/android_ui_strings_fa.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_fa.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="fa">
 <translation id="7658239707568436148">لغو</translation>
+<translation id="9068849894565669697">انتخاب رنگ</translation>
+<translation id="793640675459356075">باز کردن فایل انتخابی انجام نشد</translation>
 <translation id="6727102863431372879">تنظیم</translation>
+<translation id="6315516427814392808">به دلیل کم بودن حافظه، تکمیل عملیات قبلی امکان‌پذیر نیست</translation>
 <translation id="6042308850641462728">بیشتر</translation>
+<translation id="7535087603100972091">مقدار</translation>
+<translation id="8889402386540077796">رنگ‌مایه</translation>
+<translation id="3329013043687509092">اشباع</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_fi.xtb b/ui/android/java/strings/translations/android_ui_strings_fi.xtb
index 432a630..2dcee9d 100644
--- a/ui/android/java/strings/translations/android_ui_strings_fi.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_fi.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="fi">
 <translation id="7658239707568436148">Peruuta</translation>
+<translation id="9068849894565669697">Valitse väri</translation>
+<translation id="793640675459356075">Valittua tiedostoa ei voi avata</translation>
 <translation id="6727102863431372879">Aseta</translation>
+<translation id="6315516427814392808">Edellistä toimintoa ei voi suorittaa. Muisti ei riitä.</translation>
 <translation id="6042308850641462728">Lisää</translation>
+<translation id="7535087603100972091">Arvo</translation>
+<translation id="8889402386540077796">Sävy</translation>
+<translation id="3329013043687509092">Värikylläisyys</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_fil.xtb b/ui/android/java/strings/translations/android_ui_strings_fil.xtb
index 43d1a8d..e2a4b09 100644
--- a/ui/android/java/strings/translations/android_ui_strings_fil.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_fil.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="fil">
 <translation id="7658239707568436148">Kanselahin</translation>
+<translation id="9068849894565669697">Pumili ng kulay</translation>
+<translation id="793640675459356075">Hindi mabuksan ang napiling file</translation>
 <translation id="6727102863431372879">Itakda</translation>
+<translation id="6315516427814392808">Hindi makumpleto ang nakaraang operasyon dahil sa mababang memory</translation>
 <translation id="6042308850641462728">Higit pa</translation>
+<translation id="7535087603100972091">Value</translation>
+<translation id="8889402386540077796">Hue</translation>
+<translation id="3329013043687509092">Saturation</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_fr.xtb b/ui/android/java/strings/translations/android_ui_strings_fr.xtb
index 0996b59..c8bb250 100644
--- a/ui/android/java/strings/translations/android_ui_strings_fr.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_fr.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="fr">
 <translation id="7658239707568436148">Annuler</translation>
+<translation id="9068849894565669697">Sélectionner couleur</translation>
+<translation id="793640675459356075">Échec de l'ouverture du fichier.</translation>
 <translation id="6727102863431372879">Définir</translation>
+<translation id="6315516427814392808">Impossible de terminer l'opération précédente. Mémoire insuffisante.</translation>
 <translation id="6042308850641462728">Plus</translation>
+<translation id="7535087603100972091">Valeur</translation>
+<translation id="8889402386540077796">Teinte</translation>
+<translation id="3329013043687509092">Saturation</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_hi.xtb b/ui/android/java/strings/translations/android_ui_strings_hi.xtb
index ecd9dfd..bf0659d 100644
--- a/ui/android/java/strings/translations/android_ui_strings_hi.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_hi.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="hi">
 <translation id="7658239707568436148">रद्द करें</translation>
+<translation id="9068849894565669697">रंग चुनें</translation>
+<translation id="793640675459356075">चयनित फ़ाइल खोलने में विफल</translation>
 <translation id="6727102863431372879">सेट करें</translation>
+<translation id="6315516427814392808">कम स्‍मृति के कारण पिछली कार्रवाई पूरी करने में असमर्थ</translation>
 <translation id="6042308850641462728">अधिक</translation>
+<translation id="7535087603100972091">मान</translation>
+<translation id="8889402386540077796">रंग</translation>
+<translation id="3329013043687509092">संतृप्तता</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_hr.xtb b/ui/android/java/strings/translations/android_ui_strings_hr.xtb
index 39ab27b..0e8ef28 100644
--- a/ui/android/java/strings/translations/android_ui_strings_hr.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_hr.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="hr">
 <translation id="7658239707568436148">Odustani</translation>
+<translation id="9068849894565669697">Odaberite boju</translation>
+<translation id="793640675459356075">Odabrana datoteka nije otvorena</translation>
 <translation id="6727102863431372879">Postavi</translation>
+<translation id="6315516427814392808">Nije moguće dovršiti prethodnu operaciju jer nema dovoljno memorije</translation>
 <translation id="6042308850641462728">Više</translation>
+<translation id="7535087603100972091">Vrijednost</translation>
+<translation id="8889402386540077796">Ton</translation>
+<translation id="3329013043687509092">Zasićenje</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_hu.xtb b/ui/android/java/strings/translations/android_ui_strings_hu.xtb
index cf229bc..da30cfb 100644
--- a/ui/android/java/strings/translations/android_ui_strings_hu.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_hu.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="hu">
 <translation id="7658239707568436148">Mégse</translation>
+<translation id="9068849894565669697">Szín kiválasztása</translation>
+<translation id="793640675459356075">A fájl megnyitása sikertelen</translation>
 <translation id="6727102863431372879">Beállítás</translation>
+<translation id="6315516427814392808">Az előző műveletet memóriahiány miatt nem lehet elvégezni</translation>
 <translation id="6042308850641462728">Hosszabban</translation>
+<translation id="7535087603100972091">Érték</translation>
+<translation id="8889402386540077796">Színárnyalat</translation>
+<translation id="3329013043687509092">Telítettség</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_id.xtb b/ui/android/java/strings/translations/android_ui_strings_id.xtb
index 7f11b45..6825963 100644
--- a/ui/android/java/strings/translations/android_ui_strings_id.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_id.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="id">
 <translation id="7658239707568436148">Batal</translation>
+<translation id="9068849894565669697">Pilih warna</translation>
+<translation id="793640675459356075">Gagal membuka file terpilih</translation>
 <translation id="6727102863431372879">Setel</translation>
+<translation id="6315516427814392808">Tidak dapat menyelesaikan operasi sebelumnya karena sisa memori sedikit</translation>
 <translation id="6042308850641462728">Lainnya</translation>
+<translation id="7535087603100972091">Nilai</translation>
+<translation id="8889402386540077796">Rona</translation>
+<translation id="3329013043687509092">Saturasi</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_it.xtb b/ui/android/java/strings/translations/android_ui_strings_it.xtb
index 3bd89fe..fca9aa5 100644
--- a/ui/android/java/strings/translations/android_ui_strings_it.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_it.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="it">
 <translation id="7658239707568436148">Annulla</translation>
+<translation id="9068849894565669697">Seleziona colore</translation>
+<translation id="793640675459356075">Impossibile aprire file selez.</translation>
 <translation id="6727102863431372879">Imposta</translation>
+<translation id="6315516427814392808">Impossibile completare l'operazione precedente. Memoria insufficiente.</translation>
 <translation id="6042308850641462728">Più</translation>
+<translation id="7535087603100972091">Valore</translation>
+<translation id="8889402386540077796">Tonalità</translation>
+<translation id="3329013043687509092">Saturazione</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_iw.xtb b/ui/android/java/strings/translations/android_ui_strings_iw.xtb
index ea0a984..a8a4963 100644
--- a/ui/android/java/strings/translations/android_ui_strings_iw.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_iw.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="iw">
 <translation id="7658239707568436148">ביטול</translation>
+<translation id="9068849894565669697">בחירת צבע</translation>
+<translation id="793640675459356075">פתיחת הקובץ הנבחר נכשלה</translation>
 <translation id="6727102863431372879">הגדר</translation>
+<translation id="6315516427814392808">לא ניתן להשלים את הפעולה הקודמת עקב מחסור בזיכרון</translation>
 <translation id="6042308850641462728">עוד</translation>
+<translation id="7535087603100972091">ערך</translation>
+<translation id="8889402386540077796">גוון</translation>
+<translation id="3329013043687509092">רווייה</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ja.xtb b/ui/android/java/strings/translations/android_ui_strings_ja.xtb
index 1898964..fb7b780 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ja.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ja.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ja">
 <translation id="7658239707568436148">キャンセル</translation>
+<translation id="9068849894565669697">色の選択</translation>
+<translation id="793640675459356075">選択したファイルを開けません</translation>
 <translation id="6727102863431372879">設定</translation>
+<translation id="6315516427814392808">メモリ不足のため直前の操作を完了できません</translation>
 <translation id="6042308850641462728">詳細表示</translation>
+<translation id="7535087603100972091">値</translation>
+<translation id="8889402386540077796">色調</translation>
+<translation id="3329013043687509092">彩度</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ko.xtb b/ui/android/java/strings/translations/android_ui_strings_ko.xtb
index 3667057..ea8a5fc 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ko.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ko.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ko">
 <translation id="7658239707568436148">취소</translation>
+<translation id="9068849894565669697">색상 선택</translation>
+<translation id="793640675459356075">선택한 파일을 열지 못했습니다.</translation>
 <translation id="6727102863431372879">설정</translation>
+<translation id="6315516427814392808">메모리가 부족하여 이전 작업을 완료할 수 없습니다.</translation>
 <translation id="6042308850641462728">더보기</translation>
+<translation id="7535087603100972091">값</translation>
+<translation id="8889402386540077796">색조</translation>
+<translation id="3329013043687509092">채도</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_lt.xtb b/ui/android/java/strings/translations/android_ui_strings_lt.xtb
index 7396816..a9fa8e5 100644
--- a/ui/android/java/strings/translations/android_ui_strings_lt.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_lt.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="lt">
 <translation id="7658239707568436148">Atšaukti</translation>
+<translation id="9068849894565669697">Pasirinkite spalvą</translation>
+<translation id="793640675459356075">Atid. pasir. failą įvyko klaida</translation>
 <translation id="6727102863431372879">Nustatyti</translation>
+<translation id="6315516427814392808">Nepavyko baigti ankstesnio veiksmo dėl atminties trūkumo</translation>
 <translation id="6042308850641462728">Daugiau</translation>
+<translation id="7535087603100972091">Reikšmė</translation>
+<translation id="8889402386540077796">Spalva</translation>
+<translation id="3329013043687509092">Spalvų sodrumas</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_lv.xtb b/ui/android/java/strings/translations/android_ui_strings_lv.xtb
index 4d9f44c..7e39592 100644
--- a/ui/android/java/strings/translations/android_ui_strings_lv.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_lv.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="lv">
 <translation id="7658239707568436148">Atcelt</translation>
+<translation id="9068849894565669697">Krāsas izvēle</translation>
+<translation id="793640675459356075">Neizdevās atvērt atlasīto failu.</translation>
 <translation id="6727102863431372879">Iestatīt</translation>
+<translation id="6315516427814392808">Iepriekšējo darbību nevar pabeigt mazā atmiņas apjoma dēļ.</translation>
 <translation id="6042308850641462728">Vairāk</translation>
+<translation id="7535087603100972091">Vērtība</translation>
+<translation id="8889402386540077796">Nokrāsa</translation>
+<translation id="3329013043687509092">Piesātinājums</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_nl.xtb b/ui/android/java/strings/translations/android_ui_strings_nl.xtb
index c3a47d4..8eb1fc9 100644
--- a/ui/android/java/strings/translations/android_ui_strings_nl.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_nl.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="nl">
 <translation id="7658239707568436148">Annuleren</translation>
+<translation id="9068849894565669697">Kleur selecteren</translation>
+<translation id="793640675459356075">Kan geselec. bestand niet openen</translation>
 <translation id="6727102863431372879">Instellen</translation>
+<translation id="6315516427814392808">Kan vorige bewerking niet voltooien. Te weinig geheugen</translation>
 <translation id="6042308850641462728">Meer</translation>
+<translation id="7535087603100972091">Waarde</translation>
+<translation id="8889402386540077796">Kleurtoon</translation>
+<translation id="3329013043687509092">Verzadiging</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_no.xtb b/ui/android/java/strings/translations/android_ui_strings_no.xtb
index c91bc53..ed64205 100644
--- a/ui/android/java/strings/translations/android_ui_strings_no.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_no.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="no">
 <translation id="7658239707568436148">Avbryt</translation>
+<translation id="9068849894565669697">Velg farge</translation>
+<translation id="793640675459356075">Kunne ikke åpne den valgte filen</translation>
 <translation id="6727102863431372879">Angi</translation>
+<translation id="6315516427814392808">Kan ikke fullføre forrige handling på grunn av lite minne</translation>
 <translation id="6042308850641462728">Mer</translation>
+<translation id="7535087603100972091">Verdi</translation>
+<translation id="8889402386540077796">Fargetone</translation>
+<translation id="3329013043687509092">Metning</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_pl.xtb b/ui/android/java/strings/translations/android_ui_strings_pl.xtb
index 1fa6f0e..94b2b6f 100644
--- a/ui/android/java/strings/translations/android_ui_strings_pl.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_pl.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="pl">
 <translation id="7658239707568436148">Anuluj</translation>
+<translation id="9068849894565669697">Wybierz kolor</translation>
+<translation id="793640675459356075">Nie udało się otworzyć pliku</translation>
 <translation id="6727102863431372879">Ustaw</translation>
+<translation id="6315516427814392808">Zbyt mało pamięci, by ukończyć poprzednią operację</translation>
 <translation id="6042308850641462728">Więcej</translation>
+<translation id="7535087603100972091">Wartość</translation>
+<translation id="8889402386540077796">Odcień</translation>
+<translation id="3329013043687509092">Nasycenie</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_pt-BR.xtb b/ui/android/java/strings/translations/android_ui_strings_pt-BR.xtb
index 0c5f3f8..7715263 100644
--- a/ui/android/java/strings/translations/android_ui_strings_pt-BR.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_pt-BR.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="pt-BR">
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="9068849894565669697">Selecionar cor</translation>
+<translation id="793640675459356075">Erro ao abrir arq. selecionado</translation>
 <translation id="6727102863431372879">Definir</translation>
+<translation id="6315516427814392808">Devido à insuficiência de memória, não foi possível concluir a operação anterior</translation>
 <translation id="6042308850641462728">Mais</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="8889402386540077796">Matiz</translation>
+<translation id="3329013043687509092">Saturação</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_pt-PT.xtb b/ui/android/java/strings/translations/android_ui_strings_pt-PT.xtb
index 2f315af..d8f367f 100644
--- a/ui/android/java/strings/translations/android_ui_strings_pt-PT.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_pt-PT.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="pt-PT">
 <translation id="7658239707568436148">Cancelar</translation>
+<translation id="9068849894565669697">Selecionar cor</translation>
+<translation id="793640675459356075">Falha ao abrir o fich. selec.</translation>
 <translation id="6727102863431372879">Definir</translation>
+<translation id="6315516427814392808">Não foi possível concluir a operação anterior devido à baixa memória disponível</translation>
 <translation id="6042308850641462728">Mais</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="8889402386540077796">Tonalidade</translation>
+<translation id="3329013043687509092">Saturação</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ro.xtb b/ui/android/java/strings/translations/android_ui_strings_ro.xtb
index e0b2c50..6af1d3a 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ro.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ro.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ro">
 <translation id="7658239707568436148">Anulaţi</translation>
+<translation id="9068849894565669697">Selectați culoarea</translation>
+<translation id="793640675459356075">Fișier. select. nu s-a deschis</translation>
 <translation id="6727102863431372879">Setați</translation>
+<translation id="6315516427814392808">Operația anterioară nu se poate finaliza, din cauza memoriei insuficiente</translation>
 <translation id="6042308850641462728">Mai mult</translation>
+<translation id="7535087603100972091">Valoare</translation>
+<translation id="8889402386540077796">Nuanță</translation>
+<translation id="3329013043687509092">Saturație</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_ru.xtb b/ui/android/java/strings/translations/android_ui_strings_ru.xtb
index 827ac4b..c2af2e4 100644
--- a/ui/android/java/strings/translations/android_ui_strings_ru.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_ru.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ru">
 <translation id="7658239707568436148">Отмена</translation>
+<translation id="9068849894565669697">Выберите цвет</translation>
+<translation id="793640675459356075">Не удалось открыть файл</translation>
 <translation id="6727102863431372879">Установить</translation>
+<translation id="6315516427814392808">Не удалось завершить операцию (недостаточно памяти)</translation>
 <translation id="6042308850641462728">Подробнее...</translation>
+<translation id="7535087603100972091">Значение</translation>
+<translation id="8889402386540077796">Тон</translation>
+<translation id="3329013043687509092">Насыщенность</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_sk.xtb b/ui/android/java/strings/translations/android_ui_strings_sk.xtb
index 50599a2..2ee44ee 100644
--- a/ui/android/java/strings/translations/android_ui_strings_sk.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_sk.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="sk">
 <translation id="7658239707568436148">Zrušiť</translation>
+<translation id="9068849894565669697">Výber farby</translation>
+<translation id="793640675459356075">Vybr. súbor sa nepodar. otvoriť</translation>
 <translation id="6727102863431372879">Nastaviť</translation>
+<translation id="6315516427814392808">Predchádzajúca operácia sa nedokončila z dôvodu nedostatku pamäte</translation>
 <translation id="6042308850641462728">Viac</translation>
+<translation id="7535087603100972091">Hodnota</translation>
+<translation id="8889402386540077796">Odtieň</translation>
+<translation id="3329013043687509092">Sýtosť</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_sl.xtb b/ui/android/java/strings/translations/android_ui_strings_sl.xtb
index 5709345..223fafc 100644
--- a/ui/android/java/strings/translations/android_ui_strings_sl.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_sl.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="sl">
 <translation id="7658239707568436148">Prekliči</translation>
+<translation id="9068849894565669697">Izbira barve</translation>
+<translation id="793640675459356075">Izb. dat. ni bilo mogoče odpreti</translation>
 <translation id="6727102863431372879">Nastavi</translation>
+<translation id="6315516427814392808">Prejšnjega dejanja ni mogoče končati, ker primanjkuje pomnilnika</translation>
 <translation id="6042308850641462728">Več</translation>
+<translation id="7535087603100972091">Vrednost</translation>
+<translation id="8889402386540077796">Odtenek</translation>
+<translation id="3329013043687509092">Nasičenost</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_sr.xtb b/ui/android/java/strings/translations/android_ui_strings_sr.xtb
index 9475544..38d8fe8 100644
--- a/ui/android/java/strings/translations/android_ui_strings_sr.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_sr.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="sr">
 <translation id="7658239707568436148">Откажи</translation>
+<translation id="9068849894565669697">Изаберите боју</translation>
+<translation id="793640675459356075">Неуспешно отварање изабр. датот.</translation>
 <translation id="6727102863431372879">Постави</translation>
+<translation id="6315516427814392808">Није могуће довршити претходну радњу због недостатка меморије</translation>
 <translation id="6042308850641462728">Више</translation>
+<translation id="7535087603100972091">Вредност</translation>
+<translation id="8889402386540077796">Нијанса</translation>
+<translation id="3329013043687509092">Засићеност боја</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_sv.xtb b/ui/android/java/strings/translations/android_ui_strings_sv.xtb
index 092959a..5504d2c 100644
--- a/ui/android/java/strings/translations/android_ui_strings_sv.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_sv.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="sv">
 <translation id="7658239707568436148">Avbryt</translation>
+<translation id="9068849894565669697">Välj färg</translation>
+<translation id="793640675459356075">Det gick inte att öppna filen</translation>
 <translation id="6727102863431372879">Ange</translation>
+<translation id="6315516427814392808">Föregående åtgärd kan inte slutföras. För lite minne.</translation>
 <translation id="6042308850641462728">Mer</translation>
+<translation id="7535087603100972091">Värde</translation>
+<translation id="8889402386540077796">Nyans</translation>
+<translation id="3329013043687509092">Mättnad</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_sw.xtb b/ui/android/java/strings/translations/android_ui_strings_sw.xtb
index 1de7db2..b6da1ff 100644
--- a/ui/android/java/strings/translations/android_ui_strings_sw.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_sw.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="sw">
 <translation id="7658239707568436148">Ghairi</translation>
+<translation id="9068849894565669697">Chagua rangi</translation>
+<translation id="793640675459356075">Imeshindwa kufungua faili iliyochaguliwa</translation>
 <translation id="6727102863431372879">Weka</translation>
+<translation id="6315516427814392808">Imeshindwa kukamilisha jukumu lililotangulia kwa sababu ya nafasi ndogo ya hifadhi</translation>
 <translation id="6042308850641462728">Zaidi</translation>
+<translation id="7535087603100972091">Thamani</translation>
+<translation id="8889402386540077796">Rangi</translation>
+<translation id="3329013043687509092">Kukolea</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_th.xtb b/ui/android/java/strings/translations/android_ui_strings_th.xtb
index d8aec04..dd81a24 100644
--- a/ui/android/java/strings/translations/android_ui_strings_th.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_th.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="th">
 <translation id="7658239707568436148">ยกเลิก</translation>
+<translation id="9068849894565669697">เลือกสี</translation>
+<translation id="793640675459356075">ไม่สามารถเปิดไฟล์ที่เลือก</translation>
 <translation id="6727102863431372879">ตั้งค่า</translation>
+<translation id="6315516427814392808">ไม่สามารถดำเนินการก่อนหน้าให้สิ้นสุดได้เพราะหน่วยความจำเหลือน้อย</translation>
 <translation id="6042308850641462728">เพิ่มเติม</translation>
+<translation id="7535087603100972091">ราคา</translation>
+<translation id="8889402386540077796">โทนสี</translation>
+<translation id="3329013043687509092">ความอิ่มตัวของสี</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_tr.xtb b/ui/android/java/strings/translations/android_ui_strings_tr.xtb
index 2a37f79..a808b12 100644
--- a/ui/android/java/strings/translations/android_ui_strings_tr.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_tr.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="tr">
 <translation id="7658239707568436148">İptal</translation>
+<translation id="9068849894565669697">Renk seçin</translation>
+<translation id="793640675459356075">Seçilen dosya açılamadı</translation>
 <translation id="6727102863431372879">Ayarla</translation>
+<translation id="6315516427814392808">Bellek yetersiz olduğundan önceki işlem tamamlanamadı</translation>
 <translation id="6042308850641462728">Daha fazla</translation>
+<translation id="7535087603100972091">Değer</translation>
+<translation id="8889402386540077796">Ton</translation>
+<translation id="3329013043687509092">Doygunluk</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_uk.xtb b/ui/android/java/strings/translations/android_ui_strings_uk.xtb
index b9a0ae2..41d17cd 100644
--- a/ui/android/java/strings/translations/android_ui_strings_uk.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_uk.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="uk">
 <translation id="7658239707568436148">Скасувати</translation>
+<translation id="9068849894565669697">Вибрати колір</translation>
+<translation id="793640675459356075">Не вдалося відкрити файл</translation>
 <translation id="6727102863431372879">Встановити</translation>
+<translation id="6315516427814392808">Не вдається закінчити попередню операцію через нестачу пам’яті</translation>
 <translation id="6042308850641462728">Більше</translation>
+<translation id="7535087603100972091">Яскравість</translation>
+<translation id="8889402386540077796">Тон</translation>
+<translation id="3329013043687509092">Насиченість</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_vi.xtb b/ui/android/java/strings/translations/android_ui_strings_vi.xtb
index c66fb60..df58f21 100644
--- a/ui/android/java/strings/translations/android_ui_strings_vi.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_vi.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="vi">
 <translation id="7658239707568436148">Hủy</translation>
+<translation id="9068849894565669697">Chọn màu</translation>
+<translation id="793640675459356075">Không mở được tệp đã chọn</translation>
 <translation id="6727102863431372879">Đặt</translation>
+<translation id="6315516427814392808">Không thể hoàn tất thao tác trước do bộ nhớ thấp</translation>
 <translation id="6042308850641462728">Thêm</translation>
+<translation id="7535087603100972091">Giá trị</translation>
+<translation id="8889402386540077796">Màu sắc</translation>
+<translation id="3329013043687509092">Độ bão hòa</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_zh-CN.xtb b/ui/android/java/strings/translations/android_ui_strings_zh-CN.xtb
index 8228c71..259355d 100644
--- a/ui/android/java/strings/translations/android_ui_strings_zh-CN.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_zh-CN.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
 <translation id="7658239707568436148">取消</translation>
+<translation id="9068849894565669697">选择颜色</translation>
+<translation id="793640675459356075">无法打开所选文件</translation>
 <translation id="6727102863431372879">设置</translation>
+<translation id="6315516427814392808">内存不足,无法完成上一操作</translation>
 <translation id="6042308850641462728">更多</translation>
+<translation id="7535087603100972091">值</translation>
+<translation id="8889402386540077796">色调</translation>
+<translation id="3329013043687509092">饱和度</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/android/java/strings/translations/android_ui_strings_zh-TW.xtb b/ui/android/java/strings/translations/android_ui_strings_zh-TW.xtb
index edf79b5..10eef4f 100644
--- a/ui/android/java/strings/translations/android_ui_strings_zh-TW.xtb
+++ b/ui/android/java/strings/translations/android_ui_strings_zh-TW.xtb
@@ -2,6 +2,12 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-TW">
 <translation id="7658239707568436148">取消</translation>
+<translation id="9068849894565669697">選取顏色</translation>
+<translation id="793640675459356075">無法開啟選取的檔案</translation>
 <translation id="6727102863431372879">設定</translation>
+<translation id="6315516427814392808">記憶體不足,無法完成前一項操作</translation>
 <translation id="6042308850641462728">詳細資訊</translation>
+<translation id="7535087603100972091">值</translation>
+<translation id="8889402386540077796">色調</translation>
+<translation id="3329013043687509092">飽和度</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ui/app_list/DEPS b/ui/app_list/DEPS
index bfb1162..bd3bf14 100644
--- a/ui/app_list/DEPS
+++ b/ui/app_list/DEPS
@@ -2,6 +2,7 @@
   "+grit/ui_resources.h",
   "+grit/ui_strings.h",
   "+skia",
+  "+sync",
   "+third_party/skia",
   # Allow inclusion of third-party code:
   "+third_party/GTM", # Google Toolbox for Mac.
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp
index 007d64c..15bd6e1 100644
--- a/ui/app_list/app_list.gyp
+++ b/ui/app_list/app_list.gyp
@@ -31,6 +31,9 @@
         'app_list_export.h',
         'app_list_folder_item.cc',
         'app_list_folder_item.h',
+        'app_list_item_list.cc',
+        'app_list_item_list.h',
+        'app_list_item_list_observer.h',
         'app_list_item_model.cc',
         'app_list_item_model.h',
         'app_list_item_model_observer.h',
@@ -75,9 +78,13 @@
         'search_result.h',
         'signin_delegate.cc',
         'signin_delegate.h',
+        'views/apps_container_view.cc',
+        'views/apps_container_view.h',
         'views/app_list_background.cc',
         'views/app_list_background.h',
         'views/app_list_drag_and_drop_host.h',
+        'views/app_list_folder_view.cc',
+        'views/app_list_folder_view.h',
         'views/app_list_item_view.cc',
         'views/app_list_item_view.h',
         'views/app_list_main_view.cc',
@@ -93,6 +100,9 @@
         'views/cached_label.h',
         'views/contents_view.cc',
         'views/contents_view.h',
+        'views/folder_header_view.cc',
+        'views/folder_header_view.h',
+        'views/folder_header_view_delegate.h',
         'views/page_switcher.cc',
         'views/page_switcher.h',
         'views/progress_bar_view.cc',
@@ -158,13 +168,19 @@
       'dependencies': [
         '../../base/base.gyp:base',
         '../../base/base.gyp:test_support_base',
+        # TODO: Remove this dependency. See comment for views_unittests.
+        '../../chrome/chrome_resources.gyp:packed_resources',
         '../../skia/skia.gyp:skia',
         '../../testing/gtest.gyp:gtest',
         '../compositor/compositor.gyp:compositor',
-        '../ui.gyp:run_ui_unittests',
+        '../ui.gyp:ui',
+        '../ui.gyp:ui_resources',
+        '../ui_unittests.gyp:run_ui_unittests',
+        '../ui_unittests.gyp:ui_test_support',
         'app_list',
       ],
       'sources': [
+        'app_list_model_unittest.cc',
         'pagination_model_unittest.cc',
         'test/app_list_test_model.cc',
         'test/app_list_test_model.h',
@@ -197,7 +213,7 @@
         }],
         ['OS=="mac"', {
           'dependencies': [
-            '../ui.gyp:ui_test_support',
+            '../ui_unittests.gyp:ui_test_support',
           ],
           'conditions': [
             ['component=="static_library"', {
@@ -210,6 +226,11 @@
             ['exclude', 'cocoa/'],
           ],
         }],
+        ['use_glib == 1 or OS == "ios"', {
+          'dependencies': [
+            '../base/strings/ui_strings.gyp:ui_unittest_strings',
+          ],
+        }],
         # See http://crbug.com/162998#c4 for why this is needed.
         ['OS=="linux" and linux_use_tcmalloc==1', {
           'dependencies': [
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index 7fbf15c..b0a80af 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -36,6 +36,7 @@
 // Preferred number of columns and rows in apps grid.
 const int kPreferredCols = 4;
 const int kPreferredRows = 4;
+const int kPreferredIconDimension = 48;
 
 // Font style for app item labels.
 const ui::ResourceBundle::FontStyle kItemTextFontStyle =
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index 337fb67..217ebc7 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -35,6 +35,7 @@
 
 APP_LIST_EXPORT extern const int kPreferredCols;
 APP_LIST_EXPORT extern const int kPreferredRows;
+APP_LIST_EXPORT extern const int kPreferredIconDimension;
 
 APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle;
 
diff --git a/ui/app_list/app_list_folder_item.cc b/ui/app_list/app_list_folder_item.cc
index 0868d62..e7c505a 100644
--- a/ui/app_list/app_list_folder_item.cc
+++ b/ui/app_list/app_list_folder_item.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "ui/app_list/app_list_folder_item.h"
+
+#include "ui/app_list/app_list_item_list.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -15,7 +17,7 @@
 const size_t kNumTopApps = 4;
 const int kItemIconDimension = 16;
 
-// Genearats the folder icon with the top 4 child item icons laid in 2x2 tile.
+// Generates the folder icon with the top 4 child item icons laid in 2x2 tile.
 class FolderImageSource : public gfx::CanvasImageSource {
  public:
   typedef std::vector<gfx::ImageSkia> Icons;
@@ -45,11 +47,11 @@
   virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
     // Draw folder circle.
     gfx::Point center = gfx::Point(size().width() / 2 , size().height() / 2);
-    const SkColor kCirclColor = SkColorSetRGB(0xE1, 0xE1, 0xE1);
+    const SkColor kCircleColor = SkColorSetRGB(0xE1, 0xE1, 0xE1);
     SkPaint paint;
     paint.setStyle(SkPaint::kFill_Style);
     paint.setAntiAlias(true);
-    paint.setColor(kCirclColor);
+    paint.setColor(kCircleColor);
     canvas->DrawCircle(center, size().width() / 2, paint);
 
     if (icons_.size() == 0)
@@ -91,38 +93,14 @@
 
 AppListFolderItem::AppListFolderItem(const std::string& id)
     : AppListItemModel(id),
-      apps_(new Apps) {
+      item_list_(new AppListItemList) {
+  item_list_->AddObserver(this);
 }
 
 AppListFolderItem::~AppListFolderItem() {
   for (size_t i = 0; i < top_items_.size(); ++i)
     top_items_[i]->RemoveObserver(this);
-}
-
-void AppListFolderItem::AddItem(AppListItemModel* item) {
-  std::string sort_order = item->GetSortOrder();
-  // Note: ui::ListModel is not a sorted list.
-  size_t index = 0;
-  for (; index < apps_->item_count(); ++index) {
-    if (sort_order < apps_->GetItemAt(index)->GetSortOrder())
-      break;
-  }
-  apps_->AddAt(index, item);
-  if (index <= kNumTopApps)
-    UpdateTopItems();
-}
-
-void AppListFolderItem::DeleteItem(const std::string& id) {
-  for (size_t i = 0; i < apps_->item_count(); ++i) {
-    AppListItemModel* item = apps_->GetItemAt(i);
-    if (item->id() == id) {
-      scoped_ptr<AppListItemModel> to_be_deleted(apps_->RemoveAt(i));
-      DCHECK(item == to_be_deleted.get());
-      if (i <= kNumTopApps)
-        UpdateTopItems();
-      return;
-    }
-  }
+  item_list_->RemoveObserver(this);
 }
 
 void AppListFolderItem::UpdateIcon() {
@@ -137,15 +115,8 @@
   SetIcon(icon, false);
 }
 
-std::string AppListFolderItem::GetSortOrder() const {
-  // For now, put folders at the end of the list.
-  // TODO(stevenjb): Implement synced app list ordering.
-  return "zzzzzzzz";
-}
-
 void AppListFolderItem::Activate(int event_flags) {
-  // TODO(stevenjb/jennyz): Implement.
-  VLOG(1) << "AppListFolderItem::Activate";
+  // Folder handling is implemented by the View, so do nothing.
 }
 
 // static
@@ -176,13 +147,33 @@
 void AppListFolderItem::ItemPercentDownloadedChanged() {
 }
 
+void AppListFolderItem::OnListItemAdded(size_t index,
+                                        AppListItemModel* item) {
+  if (index <= kNumTopApps)
+    UpdateTopItems();
+}
+
+void AppListFolderItem::OnListItemRemoved(size_t index,
+                                          AppListItemModel* item) {
+  if (index <= kNumTopApps)
+    UpdateTopItems();
+}
+
+void AppListFolderItem::OnListItemMoved(size_t from_index,
+                                        size_t to_index,
+                                        AppListItemModel* item) {
+  if (from_index <= kNumTopApps || to_index <= kNumTopApps)
+    UpdateTopItems();
+}
+
 void AppListFolderItem::UpdateTopItems() {
   for (size_t i = 0; i < top_items_.size(); ++i)
     top_items_[i]->RemoveObserver(this);
   top_items_.clear();
 
-  for (size_t i = 0; i < kNumTopApps && i < apps_->item_count(); ++i) {
-    AppListItemModel* item = apps_->GetItemAt(i);
+  for (size_t i = 0;
+       i < kNumTopApps && i < item_list_->item_count(); ++i) {
+    AppListItemModel* item = item_list_->item_at(i);
     item->AddObserver(this);
     top_items_.push_back(item);
   }
diff --git a/ui/app_list/app_list_folder_item.h b/ui/app_list/app_list_folder_item.h
index db078ea..dd2ce7b 100644
--- a/ui/app_list/app_list_folder_item.h
+++ b/ui/app_list/app_list_folder_item.h
@@ -6,55 +6,56 @@
 #define UI_APP_LIST_APP_LIST_FOLDER_ITEM_H_
 
 #include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list_observer.h"
 #include "ui/app_list/app_list_item_model.h"
 #include "ui/app_list/app_list_item_model_observer.h"
 #include "ui/base/models/list_model.h"
 
 namespace app_list {
 
+class AppListItemList;
+
 // AppListFolderItem implements the model/controller for folders.
 class APP_LIST_EXPORT AppListFolderItem : public AppListItemModel,
+                                          public AppListItemListObserver,
                                           public AppListItemModelObserver {
  public:
-  typedef ui::ListModel<AppListItemModel> Apps;
-
   explicit AppListFolderItem(const std::string& id);
   virtual ~AppListFolderItem();
 
-  // Adds |item| to |apps_|. Takes ownership of |item|.
-  void AddItem(AppListItemModel* item);
-
-  // Finds |item| in |apps_| and deletes it.
-  void DeleteItem(const std::string& id);
-
   // Updates the folder's icon.
   void UpdateIcon();
 
-  Apps* apps() { return apps_.get(); }
+  AppListItemList* item_list() { return item_list_.get(); }
 
+  static const char kAppType[];
+
+ private:
   // AppListItemModel
-  virtual std::string GetSortOrder() const OVERRIDE;
   virtual void Activate(int event_flags) OVERRIDE;
   virtual const char* GetAppType() const OVERRIDE;
   virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
 
-  // AppListItemModelObserver overrides:
+  // AppListItemModelObserver
   virtual void ItemIconChanged() OVERRIDE;
   virtual void ItemTitleChanged() OVERRIDE;
   virtual void ItemHighlightedChanged() OVERRIDE;
   virtual void ItemIsInstallingChanged() OVERRIDE;
   virtual void ItemPercentDownloadedChanged() OVERRIDE;
 
-  static const char kAppType[];
-
- private:
-  typedef std::vector<AppListItemModel*> AppListItemList;
+  // AppListItemListObserver
+  virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
+  virtual void OnListItemRemoved(size_t index,
+                                 AppListItemModel* item) OVERRIDE;;
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               AppListItemModel* item) OVERRIDE;
 
   void UpdateTopItems();
 
-  scoped_ptr<Apps> apps_;
+  scoped_ptr<AppListItemList> item_list_;
   // Top items for generating folder icon.
-  AppListItemList top_items_;
+  std::vector<AppListItemModel*> top_items_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListFolderItem);
 };
diff --git a/ui/app_list/app_list_item_list.cc b/ui/app_list/app_list_item_list.cc
new file mode 100644
index 0000000..29578f2
--- /dev/null
+++ b/ui/app_list/app_list_item_list.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/app_list_item_list.h"
+
+#include "ui/app_list/app_list_item_model.h"
+
+namespace app_list {
+
+AppListItemList::AppListItemList() {
+}
+
+AppListItemList::~AppListItemList() {
+}
+
+void AppListItemList::AddObserver(AppListItemListObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+AppListItemModel* AppListItemList::FindItem(const std::string& id) {
+  for (size_t i = 0; i < app_list_items_.size(); ++i) {
+    AppListItemModel* item = app_list_items_[i];
+    if (item->id() == id)
+      return item;
+  }
+  return NULL;
+}
+
+size_t AppListItemList::AddItem(AppListItemModel* item) {
+  size_t index = GetItemSortOrderIndex(item);
+  app_list_items_.insert(app_list_items_.begin() + index, item);
+  FOR_EACH_OBSERVER(AppListItemListObserver,
+                    observers_,
+                    OnListItemAdded(index, item));
+  return index;
+}
+
+void AppListItemList::DeleteItem(const std::string& id) {
+  for (size_t i = 0; i < app_list_items_.size(); ++i) {
+    AppListItemModel* item = app_list_items_[i];
+    if (item->id() == id) {
+      DeleteItemAt(i);
+      break;
+    }
+  }
+}
+
+void AppListItemList::DeleteItemsByType(const char* type) {
+  for (int i = static_cast<int>(app_list_items_.size()) - 1;
+       i >= 0; --i) {
+    AppListItemModel* item = app_list_items_[i];
+    if (!type || item->GetAppType() == type)
+      DeleteItemAt(i);
+  }
+}
+
+void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
+  DCHECK_LT(from_index, item_count());
+  DCHECK_LT(to_index, item_count());
+  if (from_index == to_index)
+    return;
+
+  AppListItemModel* target_item = app_list_items_[from_index];
+  app_list_items_.weak_erase(app_list_items_.begin() + from_index);
+  app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
+
+  // Update position
+  AppListItemModel* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
+  AppListItemModel* next = to_index < app_list_items_.size() - 1 ?
+      app_list_items_[to_index + 1] : NULL;
+  CHECK_NE(prev, next);
+
+  // It is possible that items were added with the same ordinal. Rather than
+  // resolving a potentially complicated chain of conflicts, just set the
+  // ordinal before |next| (which will place it before both items).
+  if (prev && next && prev->position().Equals(next->position()))
+    prev = NULL;
+
+  VLOG(2) << "Move: " << target_item->position().ToDebugString()
+          << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
+          << " Next: " << (next ? next->position().ToDebugString() : "(none)");
+  if (!prev)
+    target_item->set_position(next->position().CreateBefore());
+  else if (!next)
+    target_item->set_position(prev->position().CreateAfter());
+  else
+    target_item->set_position(prev->position().CreateBetween(next->position()));
+  FOR_EACH_OBSERVER(AppListItemListObserver,
+                    observers_,
+                    OnListItemMoved(from_index, to_index, target_item));
+}
+
+// AppListItemList private
+
+void AppListItemList::DeleteItemAt(size_t index) {
+  DCHECK_LT(index, item_count());
+  AppListItemModel* item = app_list_items_[index];
+  app_list_items_.weak_erase(app_list_items_.begin() + index);
+  FOR_EACH_OBSERVER(AppListItemListObserver,
+                    observers_,
+                    OnListItemRemoved(index, item));
+  delete item;
+}
+
+size_t AppListItemList::GetItemSortOrderIndex(AppListItemModel* item) {
+  syncer::StringOrdinal position = item->position();
+  if (!position.IsValid()) {
+    size_t nitems = app_list_items_.size();
+    if (nitems == 0) {
+      position = syncer::StringOrdinal::CreateInitialOrdinal();
+    } else {
+      position = app_list_items_[nitems - 1]->position().CreateAfter();
+    }
+    item->set_position(position);
+    return nitems;
+  }
+  // Note: app_list_items_ is sorted by convention, but sorting is not enforced
+  // (items' positions might be changed outside this class).
+  size_t index = 0;
+  for (; index < app_list_items_.size(); ++index) {
+    if (position.LessThan(app_list_items_[index]->position()))
+      break;
+  }
+  return index;
+}
+
+}  // namespace app_list
diff --git a/ui/app_list/app_list_item_list.h b/ui/app_list/app_list_item_list.h
new file mode 100644
index 0000000..6b033c9
--- /dev/null
+++ b/ui/app_list/app_list_item_list.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2013 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_APP_LIST_APP_LIST_ITEM_LIST_H_
+#define UI_APP_LIST_APP_LIST_ITEM_LIST_H_
+
+#include <string>
+
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list_observer.h"
+
+namespace app_list {
+
+class AppListItemModel;
+
+// Class to manage items in the app list. Used both by AppListModel and
+// AppListFolderItem. Manages the position ordinal of items in the list, and
+// notifies observers when items in the list are added / deleted / moved.
+class APP_LIST_EXPORT AppListItemList {
+ public:
+  AppListItemList();
+  virtual ~AppListItemList();
+
+  void AddObserver(AppListItemListObserver* observer);
+  void RemoveObserver(AppListItemListObserver* observer);
+
+  // Find item matching |id|. NOTE: Requires a linear search.
+  AppListItemModel* FindItem(const std::string& id);
+
+  // Adds |item| to the end of |app_list_items_|. Takes ownership of |item|.
+  // Triggers observers_.OnListItemAdded(). Returns the index of the added item.
+  size_t AddItem(AppListItemModel* item);
+
+  // Finds item matching |id| in |app_list_items_| (linear search) and deletes
+  // it. Triggers observers_.OnListItemRemoved() after removing the item from
+  // the list and before deleting it.
+  void DeleteItem(const std::string& id);
+
+  // Deletes all items matching |type| which must be a statically defined
+  // type descriptor, e.g. AppListFolderItem::kAppType. If |type| is NULL,
+  // deletes all items. Triggers observers_.OnListItemRemoved() for each item
+  // as for DeleteItem.
+  void DeleteItemsByType(const char* type);
+
+  // Moves item at |from_index| to |to_index|.
+  // Triggers observers_.OnListItemMoved().
+  void MoveItem(size_t from_index, size_t to_index);
+
+  AppListItemModel* item_at(size_t index) { return app_list_items_[index]; }
+  size_t item_count() const { return app_list_items_.size(); }
+
+ private:
+  // Deletes item at |index| and signals observers.
+  void DeleteItemAt(size_t index);
+
+  // Returns the index at which to insert |item| in |app_list_items_| based on
+  // |item|->position(). If |item|->position() is not valid, returns
+  // |app_list_items_|.item_count() and sets |item|->position() appropriately.
+  size_t GetItemSortOrderIndex(AppListItemModel* item);
+
+  ScopedVector<AppListItemModel> app_list_items_;
+  ObserverList<AppListItemListObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListItemList);
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_APP_LIST_ITEM_LIST_H_
diff --git a/ui/app_list/app_list_item_list_observer.h b/ui/app_list/app_list_item_list_observer.h
new file mode 100644
index 0000000..bca7e90
--- /dev/null
+++ b/ui/app_list/app_list_item_list_observer.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
+#define UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
+
+#include "base/basictypes.h"
+
+namespace app_list {
+
+class AppListItemModel;
+
+class APP_LIST_EXPORT AppListItemListObserver {
+ public:
+  // Triggered after |item| has been added to the list at |index|.
+  virtual void OnListItemAdded(size_t index, AppListItemModel* item) {}
+
+  // Triggered after an item has been removed from the list at |index|, just
+  // before the item is deleted.
+  virtual void OnListItemRemoved(size_t index, AppListItemModel* item) {}
+
+  // Triggered after |item| has been moved from |from_index| to |to_index|.
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               AppListItemModel* item) {}
+
+ protected:
+  virtual ~AppListItemListObserver() {}
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
diff --git a/ui/app_list/app_list_item_model.cc b/ui/app_list/app_list_item_model.cc
index 87b6969..1846f5e 100644
--- a/ui/app_list/app_list_item_model.cc
+++ b/ui/app_list/app_list_item_model.cc
@@ -73,10 +73,6 @@
   observers_.RemoveObserver(observer);
 }
 
-std::string AppListItemModel::GetSortOrder() const {
-  return "";
-}
-
 void AppListItemModel::Activate(int event_flags) {
 }
 
diff --git a/ui/app_list/app_list_item_model.h b/ui/app_list/app_list_item_model.h
index 859b348..505bbb6 100644
--- a/ui/app_list/app_list_item_model.h
+++ b/ui/app_list/app_list_item_model.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/observer_list.h"
+#include "sync/api/string_ordinal.h"
 #include "ui/app_list/app_list_export.h"
 #include "ui/gfx/image/image_skia.h"
 
@@ -46,14 +47,15 @@
   int percent_downloaded() const { return percent_downloaded_; }
 
   const std::string& id() const { return id_; }
+  const syncer::StringOrdinal& position() const { return position_; }
+  void set_position(const syncer::StringOrdinal& new_position) {
+    DCHECK(new_position.IsValid());
+    position_ = new_position;
+  }
 
   void AddObserver(AppListItemModelObserver* observer);
   void RemoveObserver(AppListItemModelObserver* observer);
 
-  // Returns a string used for initially sorting the apps (used by
-  // AppListModel::AddItem). Defaults to an empty string.
-  virtual std::string GetSortOrder() const;
-
   // Activates (opens) the item. Does nothing by default.
   virtual void Activate(int event_flags);
 
@@ -67,7 +69,10 @@
   virtual ui::MenuModel* GetContextMenuModel();
 
  private:
+  friend class AppListModelTest;
+
   const std::string id_;
+  syncer::StringOrdinal position_;
   gfx::ImageSkia icon_;
   bool has_shadow_;
   std::string title_;
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc
index 2464656..40bb8e9 100644
--- a/ui/app_list/app_list_model.cc
+++ b/ui/app_list/app_list_model.cc
@@ -16,7 +16,7 @@
 AppListModel::User::~User() {}
 
 AppListModel::AppListModel()
-    : apps_(new Apps),
+    : item_list_(new AppListItemList),
       search_box_(new SearchBoxModel),
       results_(new SearchResults),
       signed_in_(false),
@@ -61,34 +61,4 @@
                     OnAppListModelSigninStatusChanged());
 }
 
-AppListItemModel* AppListModel::FindItem(const std::string& id) {
-  for (size_t i = 0; i < apps_->item_count(); ++i) {
-    AppListItemModel* item = apps_->GetItemAt(i);
-    if (item->id() == id)
-      return item;
-  }
-  return NULL;
-}
-
-void AppListModel::AddItem(AppListItemModel* item) {
-  std::string sort_order = item->GetSortOrder();
-  // Note: ui::ListModel is not a sorted list.
-  size_t index = 0;
-  for (; index < apps_->item_count(); ++index) {
-    if (sort_order < apps_->GetItemAt(index)->GetSortOrder())
-      break;
-  }
-  apps_->AddAt(index, item);
-}
-
-void AppListModel::DeleteItem(const std::string& id) {
-  for (size_t i = 0; i < apps_->item_count(); ++i) {
-    AppListItemModel* item = apps_->GetItemAt(i);
-    if (item->id() == id) {
-      apps_->DeleteAt(i);
-      return;
-    }
-  }
-}
-
 }  // namespace app_list
diff --git a/ui/app_list/app_list_model.h b/ui/app_list/app_list_model.h
index 2238941..fbc7970 100644
--- a/ui/app_list/app_list_model.h
+++ b/ui/app_list/app_list_model.h
@@ -13,18 +13,20 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list.h"
 #include "ui/base/models/list_model.h"
 
 namespace app_list {
 
+class AppListItemList;
 class AppListItemModel;
 class AppListModelObserver;
 class SearchBoxModel;
 class SearchResult;
 
-// Master model of app list that consists of three sub models: Apps,
-// SearchBoxModel and SearchResults. The Apps sub model owns a list of
-// AppListItemModel and is displayed in the grid view. SearchBoxModel is
+// Master model of app list that consists of three sub models: AppListItemList,
+// SearchBoxModel and SearchResults. The AppListItemList sub model owns a list
+// of AppListItemModel and is displayed in the grid view. SearchBoxModel is
 // the model for SearchBoxView. SearchResults owns a list of SearchResult.
 class APP_LIST_EXPORT AppListModel {
  public:
@@ -51,7 +53,6 @@
     STATUS_SYNCING,  // Syncing apps or installing synced apps.
   };
 
-  typedef ui::ListModel<AppListItemModel> Apps;
   typedef ui::ListModel<SearchResult> SearchResults;
   typedef std::vector<User> Users;
 
@@ -65,18 +66,7 @@
   void SetUsers(const Users& profile_menu_items);
   void SetSignedIn(bool signed_in);
 
-  // Find item matching |id|. NOTE: Requires a linear search.
-  AppListItemModel* FindItem(const std::string& id);
-
-  // Adds |item| to |apps_|. Takes ownership of |item|. Uses item->SortOrder()
-  // to insert in the correct place. TODO(stevenjb): Use synced app list order
-  // instead of SortOrder when available: crbug.com/305024.
-  void AddItem(AppListItemModel* item);
-
-  // Finds |item| in |apps_| and deletes it.
-  void DeleteItem(const std::string& id);
-
-  Apps* apps() { return apps_.get(); }
+  AppListItemList* item_list() { return item_list_.get(); }
   SearchBoxModel* search_box() { return search_box_.get(); }
   SearchResults* results() { return results_.get(); }
   Status status() const { return status_; }
@@ -87,8 +77,7 @@
   }
 
  private:
-  scoped_ptr<Apps> apps_;
-
+  scoped_ptr<AppListItemList> item_list_;
   scoped_ptr<SearchBoxModel> search_box_;
   scoped_ptr<SearchResults> results_;
 
diff --git a/ui/app_list/app_list_model_unittest.cc b/ui/app_list/app_list_model_unittest.cc
new file mode 100644
index 0000000..01df3e2
--- /dev/null
+++ b/ui/app_list/app_list_model_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/app_list_model.h"
+
+#include <map>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/app_list/app_list_folder_item.h"
+#include "ui/app_list/app_list_item_model.h"
+#include "ui/app_list/app_list_model_observer.h"
+#include "ui/app_list/test/app_list_test_model.h"
+#include "ui/base/models/list_model_observer.h"
+
+namespace app_list {
+
+namespace {
+
+class TestObserver : public AppListModelObserver,
+                     public AppListItemListObserver {
+ public:
+  TestObserver()
+      : status_changed_count_(0),
+        users_changed_count_(0),
+        signin_changed_count_(0),
+        items_added_(0),
+        items_removed_(0),
+        items_moved_(0) {
+  }
+  virtual ~TestObserver() {
+  }
+
+  // AppListModelObserver
+  virtual void OnAppListModelStatusChanged() OVERRIDE {
+    ++status_changed_count_;
+  }
+
+  virtual void OnAppListModelUsersChanged() OVERRIDE {
+    ++users_changed_count_;
+  }
+
+  virtual void OnAppListModelSigninStatusChanged() OVERRIDE {
+    ++signin_changed_count_;
+  }
+
+  // AppListItemListObserver
+  virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
+    items_added_++;
+  }
+
+  virtual void OnListItemRemoved(size_t index,
+                                 AppListItemModel* item) OVERRIDE {
+    items_removed_++;
+  }
+
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               AppListItemModel* item) OVERRIDE {
+    items_moved_++;
+  }
+
+  int status_changed_count() const { return status_changed_count_; }
+  int users_changed_count() const { return users_changed_count_; }
+  int signin_changed_count() const { return signin_changed_count_; }
+  size_t items_added() { return items_added_; }
+  size_t items_removed() { return items_removed_; }
+  size_t items_moved() { return items_moved_; }
+
+  void ResetCounts() {
+    status_changed_count_ = 0;
+    users_changed_count_ = 0;
+    signin_changed_count_ = 0;
+    items_added_ = 0;
+    items_removed_ = 0;
+    items_moved_ = 0;
+  }
+
+ private:
+  int status_changed_count_;
+  int users_changed_count_;
+  int signin_changed_count_;
+  size_t items_added_;
+  size_t items_removed_;
+  size_t items_moved_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
+}  // namespace
+
+class AppListModelTest : public testing::Test {
+ public:
+  AppListModelTest() {}
+  virtual ~AppListModelTest() {}
+
+  // testing::Test overrides:
+  virtual void SetUp() OVERRIDE {
+    model_.AddObserver(&observer_);
+    model_.item_list()->AddObserver(&observer_);
+  }
+  virtual void TearDown() OVERRIDE {
+    model_.RemoveObserver(&observer_);
+    model_.item_list()->RemoveObserver(&observer_);
+  }
+
+ protected:
+  bool ItemObservedByFolder(AppListFolderItem* folder,
+                            AppListItemModel* item) {
+    return item->observers_.HasObserver(folder);
+  }
+
+  test::AppListTestModel model_;
+  TestObserver observer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppListModelTest);
+};
+
+TEST_F(AppListModelTest, SetStatus) {
+  EXPECT_EQ(AppListModel::STATUS_NORMAL, model_.status());
+  model_.SetStatus(AppListModel::STATUS_SYNCING);
+  EXPECT_EQ(1, observer_.status_changed_count());
+  EXPECT_EQ(AppListModel::STATUS_SYNCING, model_.status());
+  model_.SetStatus(AppListModel::STATUS_NORMAL);
+  EXPECT_EQ(2, observer_.status_changed_count());
+  // Set the same status, no change is expected.
+  model_.SetStatus(AppListModel::STATUS_NORMAL);
+  EXPECT_EQ(2, observer_.status_changed_count());
+}
+
+TEST_F(AppListModelTest, SetUsers) {
+  EXPECT_EQ(0u, model_.users().size());
+  AppListModel::Users users;
+  users.push_back(AppListModel::User());
+  users[0].name = UTF8ToUTF16("test");
+  model_.SetUsers(users);
+  EXPECT_EQ(1, observer_.users_changed_count());
+  ASSERT_EQ(1u, model_.users().size());
+  EXPECT_EQ(UTF8ToUTF16("test"), model_.users()[0].name);
+}
+
+TEST_F(AppListModelTest, SetSignedIn) {
+  EXPECT_TRUE(model_.signed_in());
+  model_.SetSignedIn(false);
+  EXPECT_EQ(1, observer_.signin_changed_count());
+  EXPECT_FALSE(model_.signed_in());
+  model_.SetSignedIn(true);
+  EXPECT_EQ(2, observer_.signin_changed_count());
+  EXPECT_TRUE(model_.signed_in());
+  // Set the same signin state, no change is expected.
+  model_.SetSignedIn(true);
+  EXPECT_EQ(2, observer_.signin_changed_count());
+}
+
+TEST_F(AppListModelTest, AppsObserver) {
+  const size_t num_apps = 2;
+  model_.PopulateApps(num_apps);
+  EXPECT_EQ(num_apps, observer_.items_added());
+}
+
+TEST_F(AppListModelTest, ModelGetItem) {
+  const size_t num_apps = 2;
+  model_.PopulateApps(num_apps);
+  AppListItemModel* item0 = model_.item_list()->item_at(0);
+  ASSERT_TRUE(item0);
+  EXPECT_EQ(model_.GetItemName(0), item0->id());
+  AppListItemModel* item1 = model_.item_list()->item_at(1);
+  ASSERT_TRUE(item1);
+  EXPECT_EQ(model_.GetItemName(1), item1->id());
+}
+
+TEST_F(AppListModelTest, ModelFindItem) {
+  const size_t num_apps = 2;
+  model_.PopulateApps(num_apps);
+  std::string item_name0 = model_.GetItemName(0);
+  AppListItemModel* item0 = model_.item_list()->FindItem(item_name0);
+  ASSERT_TRUE(item0);
+  EXPECT_EQ(item_name0, item0->id());
+  std::string item_name1 = model_.GetItemName(1);
+  AppListItemModel* item1 = model_.item_list()->FindItem(item_name1);
+  ASSERT_TRUE(item1);
+  EXPECT_EQ(item_name1, item1->id());
+}
+
+TEST_F(AppListModelTest, ModelAddItem) {
+  const size_t num_apps = 2;
+  model_.PopulateApps(num_apps);
+  // Adding another item will add it to the end.
+  model_.CreateAndAddItem("Added Item 1");
+  ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
+  EXPECT_EQ("Added Item 1", model_.item_list()->item_at(num_apps)->id());
+  // Add an item between items 0 and 1.
+  app_list::AppListItemModel* item0 = model_.item_list()->item_at(0);
+  ASSERT_TRUE(item0);
+  app_list::AppListItemModel* item1 = model_.item_list()->item_at(1);
+  ASSERT_TRUE(item1);
+  app_list::AppListItemModel* item2 =
+      model_.CreateItem("Added Item 2", "Added Item 2");
+  item2->set_position(item0->position().CreateBetween(item1->position()));
+  model_.item_list()->AddItem(item2);
+  EXPECT_EQ(num_apps + 2, model_.item_list()->item_count());
+  EXPECT_EQ("Added Item 2", model_.item_list()->item_at(1)->id());
+}
+
+TEST_F(AppListModelTest, ModelMoveItem) {
+  const size_t num_apps = 3;
+  model_.PopulateApps(num_apps);
+  // Adding another item will add it to the end.
+  model_.CreateAndAddItem("Inserted Item");
+  ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
+  // Move it to the position 1.
+  model_.item_list()->MoveItem(num_apps, 1);
+  AppListItemModel* item = model_.item_list()->item_at(1);
+  ASSERT_TRUE(item);
+  EXPECT_EQ("Inserted Item", item->id());
+}
+
+TEST_F(AppListModelTest, ModelRemoveItem) {
+  const size_t num_apps = 4;
+  model_.PopulateApps(num_apps);
+  // Remove an item in the middle.
+  model_.item_list()->DeleteItem(model_.GetItemName(1));
+  EXPECT_EQ(num_apps - 1, model_.item_list()->item_count());
+  EXPECT_EQ(1u, observer_.items_removed());
+  // Remove the first item in the list.
+  model_.item_list()->DeleteItem(model_.GetItemName(0));
+  EXPECT_EQ(num_apps - 2, model_.item_list()->item_count());
+  EXPECT_EQ(2u, observer_.items_removed());
+  // Remove the last item in the list.
+  model_.item_list()->DeleteItem(model_.GetItemName(num_apps - 1));
+  EXPECT_EQ(num_apps - 3, model_.item_list()->item_count());
+  EXPECT_EQ(3u, observer_.items_removed());
+  // Ensure that the first item is the expected one
+  AppListItemModel* item0 = model_.item_list()->item_at(0);
+  ASSERT_TRUE(item0);
+  EXPECT_EQ(model_.GetItemName(2), item0->id());
+}
+
+TEST_F(AppListModelTest, ModelRemoveItemByType) {
+  const size_t num_apps = 4;
+  model_.PopulateApps(num_apps);
+  model_.item_list()->AddItem(new AppListFolderItem("folder1"));
+  model_.item_list()->AddItem(new AppListFolderItem("folder2"));
+  model_.item_list()->DeleteItemsByType(test::AppListTestModel::kAppType);
+  EXPECT_EQ(num_apps, observer_.items_removed());
+  EXPECT_EQ(2u, model_.item_list()->item_count());
+  model_.item_list()->DeleteItemsByType(AppListFolderItem::kAppType);
+  EXPECT_EQ(num_apps + 2, observer_.items_removed());
+  EXPECT_EQ(0u, model_.item_list()->item_count());
+  // Delete all items
+  observer_.ResetCounts();
+  model_.PopulateApps(num_apps);
+  model_.item_list()->AddItem(new AppListFolderItem("folder1"));
+  model_.item_list()->AddItem(new AppListFolderItem("folder2"));
+  model_.item_list()->DeleteItemsByType(NULL /* all items */);
+  EXPECT_EQ(num_apps + 2, observer_.items_removed());
+  EXPECT_EQ(0u, model_.item_list()->item_count());
+}
+
+TEST_F(AppListModelTest, AppOrder) {
+  const size_t num_apps = 5;
+  model_.PopulateApps(num_apps);
+  // Ensure order is preserved.
+  for (size_t i = 1; i < num_apps; ++i) {
+    EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
+        model_.item_list()->item_at(i - 1)->position()));
+  }
+  // Move an app
+  model_.item_list()->MoveItem(num_apps - 1, 1);
+  // Ensure order is preserved.
+  for (size_t i = 1; i < num_apps; ++i) {
+    EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
+        model_.item_list()->item_at(i - 1)->position()));
+  }
+}
+
+TEST_F(AppListModelTest, FolderItem) {
+  AppListFolderItem* folder = new AppListFolderItem("folder1");
+  const size_t num_folder_apps = 8;
+  const size_t num_observed_apps = 4;
+  for (int i = 0; static_cast<size_t>(i) < num_folder_apps; ++i) {
+    std::string name = model_.GetItemName(i);
+    folder->item_list()->AddItem(model_.CreateItem(name, name));
+  }
+  // Check that items 0 and 3 are observed.
+  EXPECT_TRUE(ItemObservedByFolder(folder, folder->item_list()->item_at(0)));
+  EXPECT_TRUE(ItemObservedByFolder(
+      folder, folder->item_list()->item_at(num_observed_apps - 1)));
+  // Check that item 4 is not observed.
+  EXPECT_FALSE(ItemObservedByFolder(
+      folder, folder->item_list()->item_at(num_observed_apps)));
+  folder->item_list()->MoveItem(num_observed_apps, 0);
+  // Confirm that everything was moved where expected.
+  EXPECT_EQ(model_.GetItemName(num_observed_apps),
+            folder->item_list()->item_at(0)->id());
+  EXPECT_EQ(model_.GetItemName(0),
+            folder->item_list()->item_at(1)->id());
+  EXPECT_EQ(model_.GetItemName(num_observed_apps - 1),
+            folder->item_list()->item_at(num_observed_apps)->id());
+  // Check that items 0 and 3 are observed.
+  EXPECT_TRUE(ItemObservedByFolder(folder, folder->item_list()->item_at(0)));
+  EXPECT_TRUE(ItemObservedByFolder(
+      folder, folder->item_list()->item_at(num_observed_apps - 1)));
+  // Check that item 4 is not observed.
+  EXPECT_FALSE(ItemObservedByFolder(
+      folder, folder->item_list()->item_at(num_observed_apps)));
+}
+
+}  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_grid_controller.h b/ui/app_list/cocoa/apps_grid_controller.h
index 77ad382..b53c814 100644
--- a/ui/app_list/cocoa/apps_grid_controller.h
+++ b/ui/app_list/cocoa/apps_grid_controller.h
@@ -23,7 +23,7 @@
 @protocol AppsPaginationModelObserver;
 @class AppsCollectionViewDragManager;
 
-// Controls a grid of views, representing AppListModel::Apps sub models.
+// Controls a grid of views, representing AppListItemList sub models.
 APP_LIST_EXPORT
 @interface AppsGridController : NSViewController<GestureScrollDelegate,
                                                  AppListPagerDelegate,
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
index 5fad26f..d450ef4 100644
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ b/ui/app_list/cocoa/apps_grid_controller.mm
@@ -76,12 +76,11 @@
 - (void)updatePageContent:(size_t)pageIndex
                resetModel:(BOOL)resetModel;
 
-// Bridged methods for ui::ListModelObserver.
-- (void)listItemsAdded:(size_t)start
-                 count:(size_t)count;
+// Bridged methods for AppListItemListObserver.
+- (void)listItemAdded:(size_t)index
+                 item:(app_list::AppListItemModel*)item;
 
-- (void)listItemsRemoved:(size_t)start
-                   count:(size_t)count;
+- (void)listItemRemoved:(size_t)index;
 
 - (void)listItemMovedFromIndex:(size_t)fromIndex
                   toModelIndex:(size_t)toIndex;
@@ -93,26 +92,25 @@
 
 namespace app_list {
 
-class AppsGridDelegateBridge : public ui::ListModelObserver {
+class AppsGridDelegateBridge : public AppListItemListObserver {
  public:
   AppsGridDelegateBridge(AppsGridController* parent) : parent_(parent) {}
 
  private:
-  // Overridden from ui::ListModelObserver:
-  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
-    [parent_ listItemsAdded:start
-                      count:count];
+  // Overridden from AppListItemListObserver:
+  virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
+    [parent_ listItemAdded:index
+                      item:item];
   }
-  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
-    [parent_ listItemsRemoved:start
-                        count:count];
+  virtual void OnListItemRemoved(size_t index,
+                                 AppListItemModel* item) OVERRIDE {
+    [parent_ listItemRemoved:index];
   }
-  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {
-    [parent_ listItemMovedFromIndex:index
-                       toModelIndex:target_index];
-  }
-  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE {
-    NOTREACHED();
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               AppListItemModel* item) OVERRIDE {
+    [parent_ listItemMovedFromIndex:from_index
+                       toModelIndex:to_index];
   }
 
   AppsGridController* parent_;  // Weak, owns us.
@@ -188,7 +186,7 @@
 
 - (void)setModel:(scoped_ptr<app_list::AppListModel>)newModel {
   if (model_) {
-    model_->apps()->RemoveObserver(bridge_.get());
+    model_->item_list()->RemoveObserver(bridge_.get());
 
     // Since the model is about to be deleted, and the AppKit objects might be
     // sitting in an NSAutoreleasePool, ensure there are no references to the
@@ -205,9 +203,13 @@
   if (!model_)
     return;
 
-  model_->apps()->AddObserver(bridge_.get());
-  [self listItemsAdded:0
-                 count:model_->apps()->item_count()];
+  model_->item_list()->AddObserver(bridge_.get());
+  for (size_t i = 0; i < model_->item_list()->item_count(); ++i) {
+    app_list::AppListItemModel* itemModel = model_->item_list()->item_at(i);
+    [items_ insertObject:[NSValue valueWithPointer:itemModel]
+                 atIndex:i];
+  }
+  [self updatePages:0];
 }
 
 - (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
@@ -522,9 +524,9 @@
   if (itemIndex == modelIndex)
     return;
 
-  model_->apps()->RemoveObserver(bridge_.get());
-  model_->apps()->Move(itemIndex, modelIndex);
-  model_->apps()->AddObserver(bridge_.get());
+  model_->item_list()->RemoveObserver(bridge_.get());
+  model_->item_list()->MoveItem(itemIndex, modelIndex);
+  model_->item_list()->AddObserver(bridge_.get());
 }
 
 - (AppsCollectionViewDragManager*)dragManager {
@@ -535,30 +537,25 @@
   return scheduledScrollPage_;
 }
 
-- (void)listItemsAdded:(size_t)start
-                 count:(size_t)count {
+- (void)listItemAdded:(size_t)index
+                 item:(app_list::AppListItemModel*)itemModel {
   // Cancel any drag, to ensure the model stays consistent.
   [dragManager_ cancelDrag];
 
-  for (size_t i = start; i < start + count; ++i) {
-    app_list::AppListItemModel* itemModel = model_->apps()->GetItemAt(i);
-    [items_ insertObject:[NSValue valueWithPointer:itemModel]
-                 atIndex:i];
-  }
+  [items_ insertObject:[NSValue valueWithPointer:itemModel]
+              atIndex:index];
 
-  [self updatePages:start];
+  [self updatePages:index];
 }
 
-- (void)listItemsRemoved:(size_t)start
-                   count:(size_t)count {
+- (void)listItemRemoved:(size_t)index {
   [dragManager_ cancelDrag];
 
   // Clear the models explicitly to avoid surprises from autorelease.
-  for (size_t i = start; i < start + count; ++i)
-    [[self itemAtIndex:i] setModel:NULL];
+  [[self itemAtIndex:index] setModel:NULL];
 
-  [items_ removeObjectsInRange:NSMakeRange(start, count)];
-  [self updatePages:start];
+  [items_ removeObjectsInRange:NSMakeRange(index, 1)];
+  [self updatePages:index];
 }
 
 - (void)listItemMovedFromIndex:(size_t)fromIndex
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
index 9ef2dae..5692574 100644
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
@@ -424,20 +424,20 @@
 // Test runtime updates: adding items, removing items, and moving items (e.g. in
 // response to app install, uninstall, and chrome sync changes. Also test
 // changing titles and icons.
-TEST_F(AppsGridControllerTest, ModelUpdates) {
+TEST_F(AppsGridControllerTest, ModelUpdate) {
   model()->PopulateApps(2);
   EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
   EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
 
-  // Add an item (PopulateApps will create a duplicate "Item 0").
+  // Add an item (PopulateApps will create a new "Item 2").
   model()->PopulateApps(1);
   EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
   NSButton* button = GetItemViewAt(2);
-  EXPECT_NSEQ(@"Item 0", [button title]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 0|"), GetViewContent());
+  EXPECT_NSEQ(@"Item 2", [button title]);
+  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
 
   // Update the title via the ItemModelObserver.
-  app_list::AppListItemModel* item_model = model()->apps()->GetItemAt(2);
+  app_list::AppListItemModel* item_model = model()->item_list()->item_at(2);
   item_model->SetTitleAndFullName("UpdatedItem", "UpdatedItem");
   EXPECT_NSEQ(@"UpdatedItem", [button title]);
   EXPECT_EQ(std::string("|Item 0,Item 1,UpdatedItem|"), GetViewContent());
@@ -456,39 +456,83 @@
   // Icon should always be resized to 48x48.
   EXPECT_EQ(kTargetImageSize, icon_size.width);
   EXPECT_EQ(kTargetImageSize, icon_size.height);
+}
+
+TEST_F(AppsGridControllerTest, ModelAdd) {
+  model()->PopulateApps(2);
+  EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
+  EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
+
+  app_list::AppListItemList* item_list = model()->item_list();
+
+  model()->CreateAndAddItem("Item 2");
+  ASSERT_EQ(3u, item_list->item_count());
+  EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
+  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
+
+  // Test adding an item whose position is in the middle.
+  app_list::AppListItemModel* item0 = item_list->item_at(0);
+  app_list::AppListItemModel* item1 = item_list->item_at(1);
+  app_list::AppListItemModel* item3 =
+      model()->CreateItem("Item Three", "Item Three");
+  item3->set_position(item0->position().CreateBetween(item1->position()));
+  item_list->AddItem(item3);
+  EXPECT_EQ(4u, [apps_grid_controller_ itemCount]);
+  EXPECT_EQ(std::string("|Item 0,Item Three,Item 1,Item 2|"), GetViewContent());
+}
+
+TEST_F(AppsGridControllerTest, ModelMove) {
+  model()->PopulateApps(3);
+  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
+
+  // Test swapping items (e.g. rearranging via sync).
+  model()->item_list()->MoveItem(1, 2);
+  EXPECT_EQ(std::string("|Item 0,Item 2,Item 1|"), GetViewContent());
+}
+
+TEST_F(AppsGridControllerTest, ModelRemove) {
+  model()->PopulateApps(3);
+  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
 
   // Test removing an item at the end.
-  model()->apps()->DeleteAt(2);
+  model()->item_list()->DeleteItem("Item 2");
   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
 
   // Test removing in the middle.
-  model()->AddItem("Item 2");
+  model()->CreateAndAddItem("Item 2");
   EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-  model()->apps()->DeleteAt(1);
+  model()->item_list()->DeleteItem("Item 1");
   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(std::string("|Item 0,Item 2|"), GetViewContent());
+}
 
-  // Test inserting in the middle.
-  model()->apps()->AddAt(1, model()->CreateItem("Item One", "Item One"));
-  EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item One,Item 2|"), GetViewContent());
-
-  // Test swapping items (e.g. rearranging via sync).
-  model()->apps()->Move(1, 2);
-  EXPECT_EQ(std::string("|Item 0,Item 2,Item One|"), GetViewContent());
+TEST_F(AppsGridControllerTest, ModelRemoveAlll) {
+  model()->PopulateApps(3);
+  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
 
   // Test removing multiple items via the model.
-  model()->apps()->DeleteAll();
+  model()->item_list()->DeleteItemsByType(NULL /* all items */);
   EXPECT_EQ(0u, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(std::string("||"), GetViewContent());
+}
 
-  // Test removing the last item when there is one item on the second page.
-  ReplaceTestModel(kItemsPerPage + 1);
+TEST_F(AppsGridControllerTest, ModelRemovePage) {
+  app_list::AppListItemList* item_list = model()->item_list();
+
+  model()->PopulateApps(kItemsPerPage + 1);
+  ASSERT_EQ(kItemsPerPage + 1, item_list->item_count());
   EXPECT_EQ(kItemsPerPage + 1, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-  model()->apps()->DeleteAt(kItemsPerPage);
+
+  // Test removing the last item when there is one item on the second page.
+  app_list::AppListItemModel* last_item = item_list->item_at(kItemsPerPage);
+  item_list->DeleteItem(last_item->id());
+  EXPECT_EQ(kItemsPerPage, item_list->item_count());
   EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ itemCount]);
   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
 }
@@ -499,7 +543,7 @@
   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
   app_list::AppListItemModel* item_model =
-      model()->apps()->GetItemAt(kItemsPerPage);
+      model()->item_list()->item_at(kItemsPerPage);
 
   // Highlighting an item should activate the page it is on.
   item_model->SetHighlighted(true);
@@ -535,7 +579,7 @@
   // Two things can be installing simultaneously. When one starts or completes
   // the model builder will ask for the item to be highlighted.
   app_list::AppListItemModel* alternate_item_model =
-      model()->apps()->GetItemAt(0);
+      model()->item_list()->item_at(0);
   item_model->SetHighlighted(false);
   alternate_item_model->SetHighlighted(true);
   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
@@ -906,8 +950,8 @@
 
 TEST_F(AppsGridControllerTest, ContextMenus) {
   AppListItemWithMenu* item_two_model = new AppListItemWithMenu("Item Two");
-  model()->apps()->AddAt(0, new AppListItemWithMenu("Item One"));
-  model()->apps()->AddAt(1, item_two_model);
+  model()->item_list()->AddItem(new AppListItemWithMenu("Item One"));
+  model()->item_list()->AddItem(item_two_model);
   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
 
   NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
index b6e4fb5..ccd6b80 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ b/ui/app_list/cocoa/apps_grid_view_item.mm
@@ -80,7 +80,7 @@
 
  private:
   AppsGridViewItem* parent_;  // Weak. Owns us.
-  AppListItemModel* model_;  // Weak. Owned by AppListModel::Apps.
+  AppListItemModel* model_;  // Weak. Owned by AppListModel.
   base::scoped_nsobject<MenuController> context_menu_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ItemModelObserverBridge);
diff --git a/ui/app_list/test/app_list_test_model.cc b/ui/app_list/test/app_list_test_model.cc
index dd7cab4..4fd1acc 100644
--- a/ui/app_list/test/app_list_test_model.cc
+++ b/ui/app_list/test/app_list_test_model.cc
@@ -10,6 +10,9 @@
 namespace app_list {
 namespace test {
 
+// static
+const char AppListTestModel::kAppType[] = "FolderItem";
+
 class AppListTestModel::AppListTestItemModel : public AppListItemModel {
  public:
   AppListTestItemModel(const std::string& id, AppListTestModel* model)
@@ -22,6 +25,10 @@
     model_->ItemActivated(this);
   }
 
+  virtual const char* GetAppType() const OVERRIDE {
+    return AppListTestModel::kAppType;
+  }
+
  private:
   AppListTestModel* model_;
   DISALLOW_COPY_AND_ASSIGN(AppListTestItemModel);
@@ -33,21 +40,26 @@
   SetSignedIn(true);
 }
 
+std::string AppListTestModel::GetItemName(int id) {
+  return base::StringPrintf("Item %d", id);
+}
+
 void AppListTestModel::PopulateApps(int n) {
+  int start_index = item_list()->item_count();
   for (int i = 0; i < n; ++i)
-    AddItem(base::StringPrintf("Item %d", i));
+    CreateAndAddItem(GetItemName(start_index + i));
 }
 
 void AppListTestModel::PopulateAppWithId(int id) {
-  AddItem(base::StringPrintf("Item %d", id));
+  CreateAndAddItem(GetItemName(id));
 }
 
 std::string AppListTestModel::GetModelContent() {
   std::string content;
-  for (size_t i = 0; i < apps()->item_count(); ++i) {
+  for (size_t i = 0; i < item_list()->item_count(); ++i) {
     if (i > 0)
       content += ',';
-    content += apps()->GetItemAt(i)->title();
+    content += item_list()->item_at(i)->title();
   }
   return content;
 }
@@ -55,21 +67,28 @@
 AppListItemModel* AppListTestModel::CreateItem(const std::string& title,
                                                const std::string& full_name) {
   AppListItemModel* item = new AppListTestItemModel(title, this);
+  size_t nitems = item_list()->item_count();
+  syncer::StringOrdinal position;
+  if (nitems == 0)
+    position = syncer::StringOrdinal::CreateInitialOrdinal();
+  else
+    position = item_list()->item_at(nitems - 1)->position().CreateAfter();
+  item->set_position(position);
   item->SetTitleAndFullName(title, full_name);
   return item;
 }
 
-void AppListTestModel::AddItem(const std::string& title) {
-  apps()->Add(CreateItem(title, title));
+void AppListTestModel::CreateAndAddItem(const std::string& title,
+                                        const std::string& full_name) {
+  item_list()->AddItem(CreateItem(title, full_name));
 }
 
-void AppListTestModel::AddItem(const std::string& title,
-                               const std::string& full_name) {
-  apps()->Add(CreateItem(title, full_name));
+void AppListTestModel::CreateAndAddItem(const std::string& title) {
+  CreateAndAddItem(title, title);
 }
 
 void AppListTestModel::HighlightItemAt(int index) {
-  AppListItemModel* item = apps()->GetItemAt(index);
+  AppListItemModel* item = item_list()->item_at(index);
   item->SetHighlighted(true);
 }
 
diff --git a/ui/app_list/test/app_list_test_model.h b/ui/app_list/test/app_list_test_model.h
index c0f9c0f..473152e 100644
--- a/ui/app_list/test/app_list_test_model.h
+++ b/ui/app_list/test/app_list_test_model.h
@@ -20,6 +20,9 @@
  public:
   AppListTestModel();
 
+  // Generates a name based on |id|.
+  std::string GetItemName(int id);
+
   // Populate the model with |n| items titled "Item #".
   void PopulateApps(int n);
 
@@ -29,15 +32,15 @@
   // Get a string of all apps in |model| joined with ','.
   std::string GetModelContent();
 
+  // Creates an item with |title| and |full_name|. Caller owns the result.
   AppListItemModel* CreateItem(const std::string& title,
                                const std::string& full_name);
 
-  // Add an item with arbitrary |title| and |full_name| to the model.
-  void AddItem(const std::string& title, const std::string& full_name);
+  // Creates and adds an item with |title| and |full_name| to the model.
+  void CreateAndAddItem(const std::string& title, const std::string& full_name);
 
-  // Add an item with arbitrary |title| to the model. This is a convenience
-  // version which will use the title for the full_name.
-  void AddItem(const std::string& title);
+  // Convenience version of CreateAndAddItem(title, title).
+  void CreateAndAddItem(const std::string& title);
 
   // Call SetHighlighted on the specified item.
   void HighlightItemAt(int index);
@@ -45,6 +48,8 @@
   int activate_count() { return activate_count_; }
   AppListItemModel* last_activated() { return last_activated_; }
 
+  static const char kAppType[];
+
  private:
   class AppListTestItemModel;
 
diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc
new file mode 100644
index 0000000..44d31b8
--- /dev/null
+++ b/ui/app_list/views/app_list_folder_view.cc
@@ -0,0 +1,95 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/views/app_list_folder_view.h"
+
+#include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/app_list_folder_item.h"
+#include "ui/app_list/app_list_model.h"
+#include "ui/app_list/pagination_model.h"
+#include "ui/app_list/views/app_list_main_view.h"
+#include "ui/app_list/views/apps_container_view.h"
+#include "ui/app_list/views/apps_grid_view.h"
+#include "ui/app_list/views/contents_view.h"
+#include "ui/app_list/views/folder_header_view.h"
+#include "ui/views/view_model.h"
+#include "ui/views/view_model_utils.h"
+
+namespace app_list {
+
+namespace {
+
+// Indexes of interesting views in ViewModel of AppListFolderView.
+const int kIndexFolderHeader = 0;
+const int kIndexChildItems = 1;
+
+}  // namespace
+
+AppListFolderView::AppListFolderView(AppsContainerView* container_view,
+                                     AppListModel* model,
+                                     AppListMainView* app_list_main_view,
+                                     content::WebContents* start_page_contents)
+    : container_view_(container_view),
+      folder_header_view_(new FolderHeaderView(this)),
+      view_model_(new views::ViewModel),
+      folder_item_(NULL),
+      pagination_model_(new PaginationModel) {
+  AddChildView(folder_header_view_);
+  view_model_->Add(folder_header_view_, kIndexFolderHeader);
+
+  items_grid_view_ = new AppsGridView(
+      app_list_main_view, pagination_model_.get(), NULL);
+  items_grid_view_->SetLayout(kPreferredIconDimension,
+                              kPreferredCols,
+                              kPreferredRows);
+  items_grid_view_->SetModel(model);
+  AddChildView(items_grid_view_);
+  view_model_->Add(items_grid_view_, kIndexChildItems);
+}
+
+AppListFolderView::~AppListFolderView() {
+  // Make sure |items_grid_view_| is deleted before |pagination_model_|.
+  RemoveAllChildViews(true);
+}
+
+void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) {
+  folder_item_ = folder;
+  items_grid_view_->SetItemList(folder_item_->item_list());
+  folder_header_view_->SetFolderItem(folder_item_);
+}
+
+gfx::Size AppListFolderView::GetPreferredSize() {
+  const gfx::Size header_size = folder_header_view_->GetPreferredSize();
+  const gfx::Size grid_size = items_grid_view_->GetPreferredSize();
+  int width = std::max(header_size.width(), grid_size.width());
+  int height = header_size.height() + grid_size.height();
+  return gfx::Size(width, height);
+}
+
+void AppListFolderView::Layout() {
+  CalculateIdealBounds();
+  views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
+}
+
+void AppListFolderView::CalculateIdealBounds() {
+  gfx::Rect rect(GetContentsBounds());
+  if (rect.IsEmpty())
+    return;
+
+  gfx::Rect header_frame(rect);
+  gfx::Size size = folder_header_view_->GetPreferredSize();
+  header_frame.set_height(size.height());
+  view_model_->set_ideal_bounds(kIndexFolderHeader, header_frame);
+
+  gfx::Rect grid_frame(rect);
+  grid_frame.set_y(header_frame.height());
+  view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
+}
+
+void AppListFolderView::NavigateBack(AppListFolderItem* item,
+                                     const ui::Event& event_flags) {
+  container_view_->ShowApps();
+}
+
+}  // namespace app_list
diff --git a/ui/app_list/views/app_list_folder_view.h b/ui/app_list/views/app_list_folder_view.h
new file mode 100644
index 0000000..ffa91e7
--- /dev/null
+++ b/ui/app_list/views/app_list_folder_view.h
@@ -0,0 +1,70 @@
+// Copyright 2013 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_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
+#define UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
+
+#include "ui/app_list/views/folder_header_view.h"
+#include "ui/app_list/views/folder_header_view_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace views {
+class ViewModel;
+}
+
+namespace app_list {
+
+class AppsContainerView;
+class AppsGridView;
+class AppListFolderItem;
+class AppListMainView;
+class AppListModel;
+class FolderHeaderView;
+class PaginationModel;
+
+class AppListFolderView : public views::View,
+                          public FolderHeaderViewDelegate {
+ public:
+  AppListFolderView(AppsContainerView* container_view,
+                    AppListModel* model,
+                    AppListMainView* app_list_main_view,
+                    content::WebContents* start_page_contents);
+  virtual ~AppListFolderView();
+
+  void SetAppListFolderItem(AppListFolderItem* folder);
+
+  // Overridden from views::View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Layout() OVERRIDE;
+
+ private:
+  void CalculateIdealBounds();
+
+  // Overridden from FolderHeaderViewDelegate:
+  virtual void NavigateBack(AppListFolderItem* item,
+                            const ui::Event& event_flags) OVERRIDE;
+
+  AppsContainerView* container_view_;  // Not owned.
+  FolderHeaderView* folder_header_view_;  // Owned by views hierarchy.
+  AppsGridView* items_grid_view_;  // Owned by the views hierarchy.
+
+  scoped_ptr<views::ViewModel> view_model_;
+
+  AppListFolderItem* folder_item_;  // Not owned.
+
+  scoped_ptr<PaginationModel> pagination_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListFolderView);
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
+
+
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h
index 311d721..08fe244 100644
--- a/ui/app_list/views/app_list_item_view.h
+++ b/ui/app_list/views/app_list_item_view.h
@@ -105,7 +105,7 @@
   // ui::EventHandler overrides:
   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
 
-  AppListItemModel* model_;  // Owned by AppListModel::Apps.
+  AppListItemModel* model_;  // Owned by AppListModel.
 
   AppsGridView* apps_grid_view_;  // Owned by views hierarchy.
   views::ImageView* icon_;  // Owned by views hierarchy.
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index 792c5bd..dd1a30c 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -12,6 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/app_list_folder_item.h"
 #include "ui/app_list/app_list_item_model.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_view_delegate.h"
@@ -160,12 +161,12 @@
   const int tiles_per_page = kPreferredCols * kPreferredRows;
   const int start_model_index = selected_page * tiles_per_page;
   const int end_model_index = std::min(
-      static_cast<int>(model_->apps()->item_count()),
+      static_cast<int>(model_->item_list()->item_count()),
       start_model_index + tiles_per_page);
 
   pending_icon_loaders_.clear();
   for (int i = start_model_index; i < end_model_index; ++i) {
-    AppListItemModel* item = model_->apps()->GetItemAt(i);
+    AppListItemModel* item = model_->item_list()->item_at(i);
     if (item->icon().HasRepresentation(scale))
       continue;
 
@@ -190,7 +191,11 @@
 }
 
 void AppListMainView::ActivateApp(AppListItemModel* item, int event_flags) {
-  item->Activate(event_flags);
+  // TODO(jennyz): Activate the folder via AppListModel notification.
+  if (item->GetAppType() == AppListFolderItem::kAppType)
+    contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
+  else
+    item->Activate(event_flags);
 }
 
 void AppListMainView::GetShortcutPathForApp(
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h
index 0c9a738..b9a5cdc 100644
--- a/ui/app_list/views/app_list_main_view.h
+++ b/ui/app_list/views/app_list_main_view.h
@@ -56,6 +56,8 @@
   void SetDragAndDropHostOfCurrentAppList(
       ApplicationDragAndDropHost* drag_and_drop_host);
 
+  ContentsView* contents_view() { return contents_view_; }
+
  private:
   class IconLoader;
 
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 5a9d79c..0f6d2df 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -168,7 +168,7 @@
 #if defined(USE_AURA)
   gfx::NativeWindow window =
       GetWidget()->GetTopLevelWidget()->GetNativeWindow();
-  return window->GetRootWindow()->GetAcceleratedWidget();
+  return window->GetDispatcher()->GetAcceleratedWidget();
 #else
   return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
 #endif
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index 3856494..9f95482 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -104,6 +104,7 @@
 #endif
 
   AppListModel* model() { return model_.get(); }
+  AppListMainView* app_list_main_view() { return app_list_main_view_; }
 
  private:
   void InitAsBubbleInternal(gfx::NativeView parent,
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc
new file mode 100644
index 0000000..6becc49
--- /dev/null
+++ b/ui/app_list/views/apps_container_view.cc
@@ -0,0 +1,90 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/views/apps_container_view.h"
+
+#include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/app_list_folder_item.h"
+#include "ui/app_list/pagination_model.h"
+#include "ui/app_list/views/app_list_folder_view.h"
+#include "ui/app_list/views/app_list_main_view.h"
+#include "ui/app_list/views/apps_grid_view.h"
+
+namespace app_list {
+
+AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
+                                     PaginationModel* pagination_model,
+                                     AppListModel* model,
+                                     content::WebContents* start_page_contents)
+    : model_(model),
+      show_state_(SHOW_APPS) {
+  apps_grid_view_ = new AppsGridView(
+      app_list_main_view, pagination_model, start_page_contents);
+  apps_grid_view_->SetLayout(kPreferredIconDimension,
+                             kPreferredCols,
+                             kPreferredRows);
+  AddChildView(apps_grid_view_);
+
+  app_list_folder_view_ = new AppListFolderView(
+      this,
+      model,
+      app_list_main_view,
+      start_page_contents);
+  AddChildView(app_list_folder_view_);
+
+  apps_grid_view_->SetModel(model_);
+  apps_grid_view_->SetItemList(model_->item_list());
+}
+
+AppsContainerView::~AppsContainerView() {
+}
+
+void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
+  app_list_folder_view_->SetAppListFolderItem(folder_item);
+  SetShowState(SHOW_ACTIVE_FOLDER);
+}
+
+void AppsContainerView::ShowApps() {
+  SetShowState(SHOW_APPS);
+}
+
+gfx::Size AppsContainerView::GetPreferredSize() {
+  const gfx::Size grid_size = apps_grid_view_->GetPreferredSize();
+  const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize();
+
+  int width = std::max(grid_size.width(), folder_view_size.width());
+  int height = std::max(grid_size.height(), folder_view_size.height());
+  return gfx::Size(width, height);
+}
+
+void AppsContainerView::Layout() {
+  gfx::Rect rect(GetContentsBounds());
+  if (rect.IsEmpty())
+    return;
+
+  switch(show_state_) {
+    case SHOW_APPS:
+      app_list_folder_view_->SetVisible(false);
+      apps_grid_view_->SetBoundsRect(rect);
+      apps_grid_view_->SetVisible(true);
+      break;
+    case SHOW_ACTIVE_FOLDER:
+      apps_grid_view_->SetVisible(false);
+      app_list_folder_view_->SetBoundsRect(rect);
+      app_list_folder_view_->SetVisible(true);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void AppsContainerView::SetShowState(ShowState show_state) {
+  if (show_state_ == show_state)
+    return;
+
+  show_state_ = show_state;
+  Layout();
+}
+
+}  // namespace app_list
diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h
new file mode 100644
index 0000000..625aec9
--- /dev/null
+++ b/ui/app_list/views/apps_container_view.h
@@ -0,0 +1,66 @@
+// Copyright 2013 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_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
+#define UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
+
+#include "ui/views/view.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace app_list {
+
+class AppsGridView;
+class AppListFolderItem;
+class AppListFolderView;
+class AppListMainView;
+class AppListModel;
+class ContentsView;
+class PaginationModel;
+
+// AppsContainerView contains a root level AppsGridView to render the root level
+// app items, and a AppListFolderView to render the app items inside the
+// active folder. Only one if them is visible to user at any time.
+class AppsContainerView : public views::View {
+ public:
+  AppsContainerView(AppListMainView* app_list_main_view,
+                    PaginationModel* pagination_model,
+                    AppListModel* model,
+                    content::WebContents* start_page_contents);
+  virtual ~AppsContainerView();
+
+  // Shows the active folder content specified by |folder_item|.
+  void ShowActiveFolder(AppListFolderItem* folder_item);
+
+  // Shows the apps list from root.
+  void ShowApps();
+
+  // Overridden from views::View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Layout() OVERRIDE;
+
+  AppsGridView* apps_grid_view() { return apps_grid_view_; }
+
+ private:
+  enum ShowState {
+    SHOW_APPS,
+    SHOW_ACTIVE_FOLDER,
+  };
+
+  void SetShowState(ShowState show_state);
+
+  AppListModel* model_;
+  AppsGridView* apps_grid_view_;  // Owned by views hierarchy.
+  AppListFolderView* app_list_folder_view_;  // Owned by views hierarchy.
+  ShowState show_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppsContainerView);
+};
+
+}  // namespace app_list
+
+
+#endif  // UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 491883e..d8f92c3 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -69,9 +69,6 @@
 // The drag and drop proxy should get scaled by this factor.
 const float kDragAndDropProxyScale = 1.5f;
 
-// For testing we remember the last created grid view.
-AppsGridView* last_created_grid_view_for_test = NULL;
-
 // RowMoveAnimationDelegate is used when moving an item into a different row.
 // Before running the animation, the item's layer is re-created and kept in
 // the original position, then the item is moved to just before its target
@@ -237,6 +234,7 @@
                            PaginationModel* pagination_model,
                            content::WebContents* start_page_contents)
     : model_(NULL),
+      item_list_(NULL),
       delegate_(delegate),
       pagination_model_(pagination_model),
       page_switcher_view_(new PageSwitcher(pagination_model)),
@@ -252,7 +250,6 @@
       page_flip_target_(-1),
       page_flip_delay_in_ms_(kPageFlipDelayInMs),
       bounds_animator_(this) {
-  last_created_grid_view_for_test = this;
   pagination_model_->AddObserver(this);
   AddChildView(page_switcher_view_);
 
@@ -272,11 +269,12 @@
   if (drag_view_)
     EndDrag(true);
 
-  if (model_) {
+  if (model_)
     model_->RemoveObserver(this);
-    model_->apps()->RemoveObserver(this);
-  }
   pagination_model_->RemoveObserver(this);
+
+  if (item_list_)
+    item_list_->RemoveObserver(this);
 }
 
 void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) {
@@ -291,16 +289,22 @@
 }
 
 void AppsGridView::SetModel(AppListModel* model) {
-  if (model_) {
+  if (model_)
     model_->RemoveObserver(this);
-    model_->apps()->RemoveObserver(this);
-  }
 
   model_ = model;
-  if (model_) {
+  if (model_)
     model_->AddObserver(this);
-    model_->apps()->AddObserver(this);
-  }
+
+  Update();
+}
+
+void AppsGridView::SetItemList(AppListItemList* item_list) {
+  if (item_list_)
+    item_list_->RemoveObserver(this);
+
+  item_list_ = item_list;
+  item_list_->AddObserver(this);
   Update();
 }
 
@@ -625,17 +629,23 @@
   }
 }
 
-// static
-AppsGridView* AppsGridView::GetLastGridViewForTest() {
-  return last_created_grid_view_for_test;
-}
-
 void AppsGridView::Update() {
   DCHECK(!selected_view_ && !drag_view_);
+  if (!item_list_)
+    return;
 
   view_model_.Clear();
-  if (model_ && model_->apps()->item_count())
-    ListItemsAdded(0, model_->apps()->item_count());
+  if (!item_list_->item_count())
+    return;
+  for (size_t i = 0; i < item_list_->item_count(); ++i) {
+    views::View* view = CreateViewForItemAtIndex(i);
+    view_model_.Add(view, i);
+    AddChildView(view);
+  }
+  UpdatePaging();
+  UpdatePulsingBlockViews();
+  Layout();
+  SchedulePaint();
 }
 
 void AppsGridView::UpdatePaging() {
@@ -648,7 +658,7 @@
 
 void AppsGridView::UpdatePulsingBlockViews() {
   const int available_slots =
-      tiles_per_page() - model_->apps()->item_count() % tiles_per_page();
+      tiles_per_page() - item_list_->item_count() % tiles_per_page();
   const int desired = model_->status() == AppListModel::STATUS_SYNCING ?
       available_slots : 0;
 
@@ -670,9 +680,9 @@
 }
 
 views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) {
-  DCHECK_LT(index, model_->apps()->item_count());
+  DCHECK_LT(index, item_list_->item_count());
   AppListItemView* view = new AppListItemView(this,
-                                              model_->apps()->GetItemAt(index));
+                                              item_list_->item_at(index));
   view->SetIconSize(icon_size_);
 #if defined(USE_AURA)
   view->SetPaintToLayer(true);
@@ -1107,10 +1117,10 @@
   if (target_model_index == current_model_index)
     return;
 
-  model_->apps()->RemoveObserver(this);
-  model_->apps()->Move(current_model_index, target_model_index);
+  item_list_->RemoveObserver(this);
+  item_list_->MoveItem(current_model_index, target_model_index);
   view_model_.Move(current_model_index, target_model_index);
-  model_->apps()->AddObserver(this);
+  item_list_->AddObserver(this);
 
   if (pagination_model_->selected_page() != target.page)
     pagination_model_->SelectPage(target.page, false);
@@ -1169,14 +1179,12 @@
   start_page_view_->SetBoundsRect(start_page_bounds);
 }
 
-void AppsGridView::ListItemsAdded(size_t start, size_t count) {
+void AppsGridView::OnListItemAdded(size_t index, AppListItemModel* item) {
   EndDrag(true);
 
-  for (size_t i = start; i < start + count; ++i) {
-    views::View* view = CreateViewForItemAtIndex(i);
-    view_model_.Add(view, i);
-    AddChildView(view);
-  }
+  views::View* view = CreateViewForItemAtIndex(index);
+  view_model_.Add(view, index);
+  AddChildView(view);
 
   UpdatePaging();
   UpdatePulsingBlockViews();
@@ -1184,14 +1192,12 @@
   SchedulePaint();
 }
 
-void AppsGridView::ListItemsRemoved(size_t start, size_t count) {
+void AppsGridView::OnListItemRemoved(size_t index, AppListItemModel* item) {
   EndDrag(true);
 
-  for (size_t i = 0; i < count; ++i) {
-    views::View* view = view_model_.view_at(start);
-    view_model_.Remove(start);
-    delete view;
-  }
+  views::View* view = view_model_.view_at(index);
+  view_model_.Remove(index);
+  delete view;
 
   UpdatePaging();
   UpdatePulsingBlockViews();
@@ -1199,18 +1205,16 @@
   SchedulePaint();
 }
 
-void AppsGridView::ListItemMoved(size_t index, size_t target_index) {
+void AppsGridView::OnListItemMoved(size_t from_index,
+                                   size_t to_index,
+                                   AppListItemModel* item) {
   EndDrag(true);
-  view_model_.Move(index, target_index);
+  view_model_.Move(from_index, to_index);
 
   UpdatePaging();
   AnimateToIdealBounds();
 }
 
-void AppsGridView::ListItemsChanged(size_t start, size_t count) {
-  NOTREACHED();
-}
-
 void AppsGridView::TotalPagesChanged() {
 }
 
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index 8d996a6..ec66746 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -48,10 +48,10 @@
 class PageSwitcher;
 class PaginationModel;
 
-// AppsGridView displays a grid for AppListModel::Apps sub model.
+// AppsGridView displays a grid for AppListItemList sub model.
 class APP_LIST_EXPORT AppsGridView : public views::View,
                                      public views::ButtonListener,
-                                     public ui::ListModelObserver,
+                                     public AppListItemListObserver,
                                      public PaginationModelObserver,
                                      public AppListModelObserver {
  public:
@@ -78,6 +78,10 @@
   // Sets |model| to use. Note this does not take ownership of |model|.
   void SetModel(AppListModel* model);
 
+  // Sets the |item_list| to render. Note this does not take ownership of
+  // |item_list|.
+  void SetItemList(AppListItemList* item_list);
+
   void SetSelectedView(views::View* view);
   void ClearSelectedView(views::View* view);
   bool IsSelectedView(const views::View* view) const;
@@ -131,9 +135,6 @@
   // Stops the timer that triggers a page flip during a drag.
   void StopPageFlipTimer();
 
-  // Get the last grid view which was created.
-  static AppsGridView* GetLastGridViewForTest();
-
   // Return the view model for test purposes.
   const views::ViewModel* view_model_for_test() const { return &view_model_; }
 
@@ -250,11 +251,12 @@
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE;
 
-  // Overridden from ListModelObserver:
-  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
-  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
-  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
-  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+  // Overridden from AppListItemListObserver:
+  virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
+  virtual void OnListItemRemoved(size_t index, AppListItemModel* item) OVERRIDE;
+  virtual void OnListItemMoved(size_t from_index,
+                               size_t to_index,
+                               AppListItemModel* item) OVERRIDE;
 
   // Overridden from PaginationModelObserver:
   virtual void TotalPagesChanged() OVERRIDE;
@@ -272,6 +274,7 @@
   void SetViewHidden(views::View* view, bool hide, bool immediate);
 
   AppListModel* model_;  // Owned by AppListView.
+  AppListItemList* item_list_;  // Not owned.
   AppsGridViewDelegate* delegate_;
   PaginationModel* pagination_model_;  // Owned by AppListController.
   PageSwitcher* page_switcher_view_;  // Owned by views hierarchy.
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index a6ef2ff..34c0c77 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -19,6 +19,7 @@
 #include "ui/app_list/test/app_list_test_model.h"
 #include "ui/app_list/views/app_list_item_view.h"
 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
+#include "ui/views/test/views_test_base.h"
 
 namespace app_list {
 namespace test {
@@ -91,13 +92,14 @@
 
 }  // namespace
 
-class AppsGridViewTest : public testing::Test {
+class AppsGridViewTest : public views::ViewsTestBase {
  public:
   AppsGridViewTest() {}
   virtual ~AppsGridViewTest() {}
 
   // testing::Test overrides:
   virtual void SetUp() OVERRIDE {
+    views::ViewsTestBase::SetUp();
     model_.reset(new AppListTestModel);
     pagination_model_.reset(new PaginationModel);
 
@@ -106,11 +108,13 @@
     apps_grid_view_->SetLayout(kIconDimension, kCols, kRows);
     apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
     apps_grid_view_->SetModel(model_.get());
+    apps_grid_view_->SetItemList(model_->item_list());
 
     test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
   }
   virtual void TearDown() OVERRIDE {
     apps_grid_view_.reset();  // Release apps grid view before models.
+    views::ViewsTestBase::TearDown();
   }
 
  protected:
@@ -120,7 +124,7 @@
   }
 
   AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
-    for (size_t i = 0; i < model_->apps()->item_count(); ++i) {
+    for (size_t i = 0; i < model_->item_list()->item_count(); ++i) {
       AppListItemView* view = GetItemViewAt(i);
       if (view->bounds().Contains(point))
         return view;
@@ -129,7 +133,7 @@
   }
 
   gfx::Rect GetItemTileRectAt(int row, int col) {
-    DCHECK_GT(model_->apps()->item_count(), 0u);
+    DCHECK_GT(model_->item_list()->item_count(), 0u);
 
     gfx::Insets insets(apps_grid_view_->GetInsets());
     gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
@@ -169,8 +173,6 @@
   scoped_ptr<AppsGridView> apps_grid_view_;
   scoped_ptr<AppsGridViewTestApi> test_api_;
 
-  base::MessageLoopForUI message_loop_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
 };
@@ -182,7 +184,7 @@
   EXPECT_EQ(kPages, pagination_model_->total_pages());
 
   // Adds one more and gets a new page created.
-  model_->AddItem(std::string("Extra"));
+  model_->CreateAndAddItem("Extra");
   EXPECT_EQ(kPages + 1, pagination_model_->total_pages());
 }
 
@@ -204,7 +206,7 @@
   EXPECT_EQ(1, pagination_model_->selected_page());
 
   // Highlight last one in the model and last page should be selected.
-  model_->HighlightItemAt(model_->apps()->item_count() - 1);
+  model_->HighlightItemAt(model_->item_list()->item_count() - 1);
   EXPECT_EQ(kPages - 1, pagination_model_->selected_page());
 }
 
@@ -216,7 +218,7 @@
 
   AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
   apps_grid_view_->SetSelectedView(last_view);
-  model_->apps()->DeleteAt(kLastItemIndex);
+  model_->item_list()->DeleteItem(model_->GetItemName(kLastItemIndex));
 
   EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
 
@@ -251,7 +253,7 @@
 
   // Deleting an item keeps remaining intact.
   SimulateDrag(AppsGridView::MOUSE, from, to);
-  model_->apps()->DeleteAt(1);
+  model_->item_list()->DeleteItem(model_->GetItemName(0));
   apps_grid_view_->EndDrag(false);
   EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
             model_->GetModelContent());
@@ -259,7 +261,7 @@
 
   // Adding a launcher item cancels the drag and respects the order.
   SimulateDrag(AppsGridView::MOUSE, from, to);
-  model_->AddItem(std::string("Extra"));
+  model_->CreateAndAddItem("Extra");
   apps_grid_view_->EndDrag(false);
   EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
             model_->GetModelContent());
@@ -270,7 +272,7 @@
   test_api_->SetPageFlipDelay(10);
   pagination_model_->SetTransitionDurations(10, 10);
 
-  PageFlipWaiter page_flip_waiter(&message_loop_,
+  PageFlipWaiter page_flip_waiter(message_loop(),
                                   pagination_model_.get());
 
   const int kPages = 3;
@@ -431,7 +433,7 @@
   // should always be the full name of the app.
   std::string expected_text("xyz");
   std::string expected_tooltip("tooltip");
-  model_->AddItem(expected_text, expected_tooltip);
+  model_->CreateAndAddItem(expected_text, expected_tooltip);
 
   string16 actual_tooltip;
   AppListItemView* item_view = GetItemViewAt(0);
@@ -447,7 +449,7 @@
   // If the app's full name and short name are the same, use the default tooltip
   // behavior of the label (only show a tooltip if the title is truncated).
   std::string title("a");
-  model_->AddItem(title, title);
+  model_->CreateAndAddItem(title, title);
 
   string16 actual_tooltip;
   AppListItemView* item_view = GetItemViewAt(0);
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 017c38c..225c119 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -11,6 +11,7 @@
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/pagination_model.h"
 #include "ui/app_list/views/app_list_main_view.h"
+#include "ui/app_list/views/apps_container_view.h"
 #include "ui/app_list/views/apps_grid_view.h"
 #include "ui/app_list/views/search_result_list_view.h"
 #include "ui/events/event.h"
@@ -22,10 +23,8 @@
 
 namespace {
 
-const int kPreferredIconDimension = 48;
-
 // Indexes of interesting views in ViewModel of ContentsView.
-const int kIndexAppsGrid = 0;
+const int kIndexAppsContainer = 0;
 const int kIndexSearchResults = 1;
 
 const int kMinMouseWheelToSwitchPage = 20;
@@ -34,9 +33,8 @@
 
 const double kFinishTransitionThreshold = 0.33;
 
-// Helpers to get certain child view from |model|.
-AppsGridView* GetAppsGridView(views::ViewModel* model) {
-  return static_cast<AppsGridView*>(model->view_at(kIndexAppsGrid));
+AppsContainerView* GetAppsContainerView(views::ViewModel* model) {
+  return static_cast<AppsContainerView*>(model->view_at(kIndexAppsContainer));
 }
 
 SearchResultListView* GetSearchResultListView(views::ViewModel* model) {
@@ -59,20 +57,16 @@
       kPageTransitionDurationInMs,
       kOverscrollPageTransitionDurationMs);
 
-  apps_grid_view_ = new AppsGridView(
-      app_list_main_view, pagination_model, start_page_contents);
-  apps_grid_view_->SetLayout(kPreferredIconDimension,
-                             kPreferredCols,
-                             kPreferredRows);
-  AddChildView(apps_grid_view_);
-  view_model_->Add(apps_grid_view_, kIndexAppsGrid);
+  apps_container_view_ = new AppsContainerView(
+      app_list_main_view, pagination_model, model, start_page_contents);
+  AddChildView(apps_container_view_);
+  view_model_->Add(apps_container_view_, kIndexAppsContainer);
 
   SearchResultListView* search_results_view = new SearchResultListView(
       app_list_main_view);
   AddChildView(search_results_view);
   view_model_->Add(search_results_view, kIndexSearchResults);
 
-  GetAppsGridView(view_model_.get())->SetModel(model);
   GetSearchResultListView(view_model_.get())->SetResults(model->results());
 }
 
@@ -80,13 +74,14 @@
 }
 
 void ContentsView::CancelDrag() {
-  if (apps_grid_view_ && apps_grid_view_->has_dragged_view())
-    apps_grid_view_->EndDrag(true);
+  if (apps_container_view_->apps_grid_view()->has_dragged_view())
+    apps_container_view_->apps_grid_view()->EndDrag(true);
 }
 
 void ContentsView::SetDragAndDropHostOfCurrentAppList(
     ApplicationDragAndDropHost* drag_and_drop_host) {
-  apps_grid_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+  apps_container_view_->apps_grid_view()->
+      SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
 }
 
 void ContentsView::SetShowState(ShowState show_state) {
@@ -114,7 +109,7 @@
   if (rect.IsEmpty())
     return;
 
-  gfx::Rect grid_frame(rect);
+  gfx::Rect container_frame(rect);
   gfx::Rect results_frame(rect);
 
   // Offsets apps grid and result list based on |show_state_|.
@@ -126,14 +121,14 @@
       results_frame.Offset(0, -contents_area_height);
       break;
     case SHOW_SEARCH_RESULTS:
-      grid_frame.Offset(0, contents_area_height);
+      container_frame.Offset(0, contents_area_height);
       break;
     default:
       NOTREACHED() << "Unknown show_state_ " << show_state_;
       break;
   }
 
-  view_model_->set_ideal_bounds(kIndexAppsGrid, grid_frame);
+  view_model_->set_ideal_bounds(kIndexAppsContainer, container_frame);
   view_model_->set_ideal_bounds(kIndexSearchResults, results_frame);
 }
 
@@ -149,19 +144,23 @@
   SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS);
 }
 
+void ContentsView::ShowFolderContent(AppListFolderItem* item) {
+  apps_container_view_->ShowActiveFolder(item);
+}
+
 void ContentsView::Prerender() {
   const int selected_page = std::max(0, pagination_model_->selected_page());
-  GetAppsGridView(view_model_.get())->Prerender(selected_page);
+  apps_container_view_->apps_grid_view()->Prerender(selected_page);
 }
 
 gfx::Size ContentsView::GetPreferredSize() {
-  const gfx::Size grid_size =
-      GetAppsGridView(view_model_.get())->GetPreferredSize();
+  const gfx::Size container_size = GetAppsContainerView(view_model_.get())->
+      apps_grid_view()->GetPreferredSize();
   const gfx::Size results_size =
       GetSearchResultListView(view_model_.get())->GetPreferredSize();
 
-  int width = std::max(grid_size.width(), results_size.width());
-  int height = std::max(grid_size.height(), results_size.height());
+  int width = std::max(container_size.width(), results_size.width());
+  int height = std::max(container_size.height(), results_size.height());
   return gfx::Size(width, height);
 }
 
@@ -173,7 +172,7 @@
 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
   switch (show_state_) {
     case SHOW_APPS:
-      return GetAppsGridView(view_model_.get())->OnKeyPressed(event);
+      return GetAppsContainerView(view_model_.get())->OnKeyPressed(event);
     case SHOW_SEARCH_RESULTS:
       return GetSearchResultListView(view_model_.get())->OnKeyPressed(event);
     default:
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index 4c2c6fe..1f3f938 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -23,9 +23,11 @@
 
 class AppsGridView;
 class ApplicationDragAndDropHost;
+class AppListFolderItem;
 class AppListMainView;
 class AppListModel;
 class AppListViewDelegate;
+class AppsContainerView;
 class PaginationModel;
 
 // A view to manage sub views under the search box (apps grid view + page
@@ -49,9 +51,12 @@
       ApplicationDragAndDropHost* drag_and_drop_host);
 
   void ShowSearchResults(bool show);
+  void ShowFolderContent(AppListFolderItem* folder);
 
   void Prerender();
 
+  AppsContainerView* apps_container_view() { return apps_container_view_; }
+
  private:
   enum ShowState {
     SHOW_APPS,
@@ -80,7 +85,7 @@
   ShowState show_state_;
   PaginationModel* pagination_model_;  // Owned by AppListController.
 
-  AppsGridView* apps_grid_view_;  // Owned by the view.
+  AppsContainerView* apps_container_view_; // Owned by the views hierarchy.
 
   scoped_ptr<views::ViewModel> view_model_;
   scoped_ptr<views::BoundsAnimator> bounds_animator_;
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
new file mode 100644
index 0000000..d600a46
--- /dev/null
+++ b/ui/app_list/views/folder_header_view.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/views/folder_header_view.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "grit/ui_resources.h"
+#include "grit/ui_strings.h"
+#include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/app_list_folder_item.h"
+#include "ui/app_list/views/app_list_folder_view.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/textfield/textfield.h"
+
+namespace app_list {
+
+namespace {
+
+const int kPreferredWidth = 360;
+const int kPreferredHeight = 48;
+const int kIconDimension = 32;
+const int kPadding = 14;
+const int kFolderNameWidth = 150;
+const int kFolderNameHeight = 30;
+const int kBottomSeparatorWidth = 380;
+const int kBottomSeparatorHeight = 1;
+
+const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
+
+}  // namespace
+
+class FolderHeaderView::FolderNameView : public views::Textfield {
+ public:
+  FolderNameView() {
+    set_border(views::Border::CreateEmptyBorder(1, 1, 1, 1));
+  }
+
+  virtual ~FolderNameView() {
+  }
+
+  // Overridden from views::View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE {
+    return gfx::Size(kFolderNameWidth, kFolderNameHeight);
+  }
+
+  virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE {
+    const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250);
+    if (HasFocus() && focusable()) {
+      gfx::Rect rect = GetLocalBounds();
+      rect.Inset(0, 0, 1, 1);
+      canvas->DrawRect(rect, kFocusBorderColor);
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FolderNameView);
+};
+
+FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate)
+    : folder_item_(NULL),
+      back_button_(new views::ImageButton(this)),
+      folder_name_view_(new FolderNameView),
+      delegate_(delegate) {
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  back_button_->SetImage(views::ImageButton::STATE_NORMAL,
+      rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
+  back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+      views::ImageButton::ALIGN_MIDDLE);
+  AddChildView(back_button_);
+
+  folder_name_view_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
+  folder_name_view_->set_placeholder_text_color(kHintTextColor);
+  folder_name_view_->set_placeholder_text(
+      rb.GetLocalizedString(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
+  folder_name_view_->RemoveBorder();
+  folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
+  folder_name_view_->SetController(this);
+  AddChildView(folder_name_view_);
+}
+
+FolderHeaderView::~FolderHeaderView() {
+  if (folder_item_)
+    folder_item_->RemoveObserver(this);
+}
+
+void FolderHeaderView::SetFolderItem(AppListFolderItem* folder_item) {
+  if (folder_item_)
+    folder_item_->RemoveObserver(this);
+
+  folder_item_ = folder_item;
+  if (!folder_item_)
+    return;
+  folder_item_->AddObserver(this);
+
+  Update();
+}
+
+void FolderHeaderView::Update() {
+  if (!folder_item_)
+    return;
+
+  folder_name_view_->SetText(UTF8ToUTF16(folder_item_->title()));
+}
+
+gfx::Size FolderHeaderView::GetPreferredSize() {
+  return gfx::Size(kPreferredWidth, kPreferredHeight);
+}
+
+void FolderHeaderView::Layout() {
+  gfx::Rect rect(GetContentsBounds());
+  if (rect.IsEmpty())
+    return;
+
+  gfx::Rect back_bounds(rect);
+  back_bounds.set_width(kIconDimension + 2 * kPadding);
+  back_button_->SetBoundsRect(back_bounds);
+
+  gfx::Rect text_bounds(rect);
+  int text_width = folder_name_view_->GetPreferredSize().width();
+  text_bounds.set_x(back_bounds.x() + (rect.width() - text_width) / 2);
+  text_bounds.set_width(text_width);
+  text_bounds.ClampToCenteredSize(gfx::Size(text_bounds.width(),
+      folder_name_view_->GetPreferredSize().height()));
+  folder_name_view_->SetBoundsRect(text_bounds);
+}
+
+void FolderHeaderView::OnPaint(gfx::Canvas* canvas) {
+  views::View::OnPaint(canvas);
+
+  gfx::Rect rect(GetContentsBounds());
+  if (rect.IsEmpty())
+    return;
+
+  // Draw bottom separator line.
+  rect.set_x((rect.width() - kBottomSeparatorWidth) / 2 + rect.x());
+  rect.set_y(rect.y() + rect.height() - kBottomSeparatorHeight);
+  rect.set_width(kBottomSeparatorWidth);
+  rect.set_height(kBottomSeparatorHeight);
+  canvas->FillRect(rect, kTopSeparatorColor);
+}
+
+void FolderHeaderView::ContentsChanged(views::Textfield* sender,
+                                       const base::string16& new_contents) {
+  // Temporarily remove from observer to ignore data change caused by us.
+  if (!folder_item_)
+    return;
+
+  folder_item_->RemoveObserver(this);
+  std::string name = UTF16ToUTF8(folder_name_view_->text());
+  folder_item_->SetTitleAndFullName(name, name);
+  folder_item_->AddObserver(this);
+}
+
+void FolderHeaderView::ButtonPressed(views::Button* sender,
+                                     const ui::Event& event) {
+  delegate_->NavigateBack(folder_item_, event);
+}
+
+void FolderHeaderView::ItemIconChanged() {
+}
+
+void FolderHeaderView::ItemTitleChanged() {
+  Update();
+}
+
+void FolderHeaderView::ItemHighlightedChanged() {
+}
+
+void FolderHeaderView::ItemIsInstallingChanged() {
+}
+
+void FolderHeaderView::ItemPercentDownloadedChanged() {
+}
+
+}  // namespace app_list
+
diff --git a/ui/app_list/views/folder_header_view.h b/ui/app_list/views/folder_header_view.h
new file mode 100644
index 0000000..f8d471b
--- /dev/null
+++ b/ui/app_list/views/folder_header_view.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2013 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_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
+#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
+
+#include <string>
+
+#include "ui/app_list/app_list_item_model_observer.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/view.h"
+
+namespace views {
+class ImageButton;
+}  // namespace views
+
+namespace app_list {
+
+class AppListFolderItem;
+class AppListFolderView;
+class FolderHeaderViewDelegate;
+
+// FolderHeaderView contains a back button and an editable folder name field.
+class FolderHeaderView : public views::View,
+                         public views::TextfieldController,
+                         public views::ButtonListener,
+                         public AppListItemModelObserver {
+ public:
+  explicit FolderHeaderView(FolderHeaderViewDelegate* delegate);
+  virtual ~FolderHeaderView();
+
+  void SetFolderItem(AppListFolderItem* folder_item);
+
+  // Overridden from views::View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ private:
+  class FolderNameView;
+
+  // Updates UI.
+  void Update();
+
+  // Overriden from views::View:
+  virtual void Layout() OVERRIDE;
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+  // Overridden from views::TextfieldController:
+  virtual void ContentsChanged(views::Textfield* sender,
+                               const base::string16& new_contents) OVERRIDE;
+
+  // Overridden from views::ButtonListener:
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+  // Overridden from AppListItemModelObserver:
+  virtual void ItemIconChanged() OVERRIDE;
+  virtual void ItemTitleChanged() OVERRIDE;
+  virtual void ItemHighlightedChanged() OVERRIDE;
+  virtual void ItemIsInstallingChanged() OVERRIDE;
+  virtual void ItemPercentDownloadedChanged() OVERRIDE;
+
+  AppListFolderItem* folder_item_;  // Not owned.
+
+  views::ImageButton* back_button_;  // Owned by views hierarchy.
+  FolderNameView* folder_name_view_;  // Owned by views hierarchy.
+
+  FolderHeaderViewDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(FolderHeaderView);
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
diff --git a/ui/app_list/views/folder_header_view_delegate.h b/ui/app_list/views/folder_header_view_delegate.h
new file mode 100644
index 0000000..e8591b6
--- /dev/null
+++ b/ui/app_list/views/folder_header_view_delegate.h
@@ -0,0 +1,27 @@
+// Copyright 2013 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_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
+#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
+
+namespace app_list {
+
+class AppListFolderItem;
+
+class FolderHeaderViewDelegate {
+ public:
+  // Invoked when the back button on the folder header view is clicked.
+  // |item| is the folder item which FolderHeaderview represents.
+  // |event_flags| contains the flags of the keyboard/mouse event that triggers
+  // the request.
+  virtual void NavigateBack(AppListFolderItem* item,
+                            const ui::Event& event_flags) = 0;
+
+ protected:
+  virtual ~FolderHeaderViewDelegate() {}
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp
index 954d8de..70334fe 100644
--- a/ui/aura/aura.gyp
+++ b/ui/aura/aura.gyp
@@ -62,8 +62,6 @@
         'client/focus_client.h',
         'client/screen_position_client.cc',
         'client/screen_position_client.h',
-        'client/stacking_client.cc',
-        'client/stacking_client.h',
         'client/tooltip_client.cc',
         'client/tooltip_client.h',
         'client/user_action_client.cc',
@@ -72,6 +70,8 @@
         'client/visibility_client.h',
         'client/window_move_client.cc',
         'client/window_move_client.h',
+        'client/window_tree_client.cc',
+        'client/window_tree_client.h',
         'client/window_types.h',
         'device_list_updater_aurax11.cc',
         'device_list_updater_aurax11.h',
@@ -124,11 +124,6 @@
           'sources!': [
             'input_state_lookup.cc',
           ],
-          'msvs_settings': {
-            'VCCLCompilerTool': {
-              'ForcedIncludeFiles': [ 'build/intsafe_workaround.h' ],
-            },
-          },
         }],
       ],
     },
@@ -138,10 +133,11 @@
       'dependencies': [
         '../../skia/skia.gyp:skia',
         '../../testing/gtest.gyp:gtest',
+        '../compositor/compositor.gyp:compositor_test_support',
         '../events/events.gyp:events',
         '../gfx/gfx.gyp:gfx',
         '../ui.gyp:ui',
-        '../ui.gyp:ui_test_support',
+        '../ui_unittests.gyp:ui_test_support',
         'aura',
         'aura_test_support_pak',
       ],
@@ -166,8 +162,8 @@
         'test/test_focus_client.h',
         'test/test_screen.cc',
         'test/test_screen.h',
-        'test/test_stacking_client.cc',
-        'test/test_stacking_client.h',
+        'test/test_window_tree_client.cc',
+        'test/test_window_tree_client.h',
         'test/test_windows.cc',
         'test/test_windows.h',
         'test/test_window_delegate.cc',
@@ -279,7 +275,7 @@
         '../gl/gl.gyp:gl',
         '../ui.gyp:ui',
         '../ui.gyp:ui_resources',
-        '../ui.gyp:ui_test_support',
+        '../ui_unittests.gyp:ui_test_support',
         'aura_test_support',
         'aura',
       ],
diff --git a/ui/aura/bench/bench_main.cc b/ui/aura/bench/bench_main.cc
index 67ba3a6..a8dd537 100644
--- a/ui/aura/bench/bench_main.cc
+++ b/ui/aura/bench/bench_main.cc
@@ -26,6 +26,7 @@
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/debug_utils.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/skia_util.h"
@@ -301,7 +302,7 @@
 
   // The ContextFactory must exist before any Compositors are created.
   bool allow_test_contexts = false;
-  ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
 
   ui::RegisterPathProvider();
   base::i18n::InitializeICU();
diff --git a/ui/aura/client/activation_client.cc b/ui/aura/client/activation_client.cc
index b557023..b4633ae 100644
--- a/ui/aura/client/activation_client.cc
+++ b/ui/aura/client/activation_client.cc
@@ -17,11 +17,11 @@
     ActivationClient*, kRootWindowActivationClientKey, NULL);
 DEFINE_WINDOW_PROPERTY_KEY(bool, kHideOnDeactivate, false);
 
-void SetActivationClient(RootWindow* root_window, ActivationClient* client) {
+void SetActivationClient(Window* root_window, ActivationClient* client) {
   root_window->SetProperty(kRootWindowActivationClientKey, client);
 }
 
-ActivationClient* GetActivationClient(RootWindow* root_window) {
+ActivationClient* GetActivationClient(Window* root_window) {
   return root_window ?
       root_window->GetProperty(kRootWindowActivationClientKey) : NULL;
 }
diff --git a/ui/aura/client/activation_client.h b/ui/aura/client/activation_client.h
index db4cd1b..054829e 100644
--- a/ui/aura/client/activation_client.h
+++ b/ui/aura/client/activation_client.h
@@ -6,14 +6,13 @@
 #define UI_AURA_CLIENT_ACTIVATION_CLIENT_H_
 
 #include "ui/aura/aura_export.h"
-#include "ui/aura/window.h"
 
 namespace ui {
 class Event;
 }
 
 namespace aura {
-class RootWindow;
+class Window;
 
 namespace client {
 class ActivationChangeObserver;
@@ -57,10 +56,10 @@
   virtual ~ActivationClient() {}
 };
 
-// Sets/Gets the activation client on the RootWindow.
-AURA_EXPORT void SetActivationClient(RootWindow* root_window,
+// Sets/Gets the activation client on the root Window.
+AURA_EXPORT void SetActivationClient(Window* root_window,
                                      ActivationClient* client);
-AURA_EXPORT ActivationClient* GetActivationClient(RootWindow* root_window);
+AURA_EXPORT ActivationClient* GetActivationClient(Window* root_window);
 
 // Some types of transient window are only visible when active.
 // The transient parents of these windows may have visual appearance properties
diff --git a/ui/aura/client/capture_client.cc b/ui/aura/client/capture_client.cc
index ec53fc2..cbcabd7 100644
--- a/ui/aura/client/capture_client.cc
+++ b/ui/aura/client/capture_client.cc
@@ -15,17 +15,17 @@
 DEFINE_WINDOW_PROPERTY_KEY(
     CaptureClient*, kRootWindowCaptureClientKey, NULL);
 
-void SetCaptureClient(RootWindow* root_window, CaptureClient* client) {
+void SetCaptureClient(Window* root_window, CaptureClient* client) {
   root_window->SetProperty(kRootWindowCaptureClientKey, client);
 }
 
-CaptureClient* GetCaptureClient(RootWindow* root_window) {
+CaptureClient* GetCaptureClient(Window* root_window) {
   return root_window ?
       root_window->GetProperty(kRootWindowCaptureClientKey) : NULL;
 }
 
 Window* GetCaptureWindow(Window* window) {
-  RootWindow* root_window = window->GetRootWindow();
+  Window* root_window = window->GetRootWindow();
   if (!root_window)
     return NULL;
   CaptureClient* capture_client = GetCaptureClient(root_window);
diff --git a/ui/aura/client/capture_client.h b/ui/aura/client/capture_client.h
index b244c0c..f801328 100644
--- a/ui/aura/client/capture_client.h
+++ b/ui/aura/client/capture_client.h
@@ -8,7 +8,6 @@
 #include "ui/aura/aura_export.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 
 namespace client {
@@ -29,10 +28,10 @@
   virtual ~CaptureClient() {}
 };
 
-// Sets/Gets the capture client on the RootWindow.
-AURA_EXPORT void SetCaptureClient(RootWindow* root_window,
+// Sets/Gets the capture client on the root Window.
+AURA_EXPORT void SetCaptureClient(Window* root_window,
                                   CaptureClient* client);
-AURA_EXPORT CaptureClient* GetCaptureClient(RootWindow* root_window);
+AURA_EXPORT CaptureClient* GetCaptureClient(Window* root_window);
 
 // A utility function to get the current capture window. Returns NULL
 // if the window doesn't have a root window, or there is no capture window.
diff --git a/ui/aura/client/capture_delegate.h b/ui/aura/client/capture_delegate.h
index c727b0a..7ebcaee 100644
--- a/ui/aura/client/capture_delegate.h
+++ b/ui/aura/client/capture_delegate.h
@@ -11,15 +11,20 @@
 class Window;
 namespace client {
 
-// This interface provides API to change the RootWindow's capture state
-// without exposing them as RootWindow API.
+// This interface provides API to change the root Window's capture state without
+// exposing them as RootWindow API.
 class AURA_EXPORT CaptureDelegate {
  public:
-  // Called when a capture is set on the |new_capture| which is owned by
-  // this root window, and/or a capture is released on the |old_capture|
-  // which is owned by this root window.
+  // Called when a capture is set on |new_capture| and/or a capture is
+  // released on |old_capture|.
+  // NOTE: |old_capture| and |new_capture| are not necessarily contained in the
+  // window hierarchy of the delegate.
   virtual void UpdateCapture(aura::Window* old_capture,
                              aura::Window* new_capture) = 0;
+
+  // Called when another root gets capture.
+  virtual void OnOtherRootGotCapture() = 0;
+
   // Sets/Release a native capture on host windows.
   virtual void SetNativeCapture() = 0;
   virtual void ReleaseNativeCapture() = 0;
diff --git a/ui/aura/client/default_activation_client.cc b/ui/aura/client/default_activation_client.cc
index 84ff282..629f12a 100644
--- a/ui/aura/client/default_activation_client.cc
+++ b/ui/aura/client/default_activation_client.cc
@@ -6,7 +6,6 @@
 
 #include "ui/aura/client/activation_change_observer.h"
 #include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 
 namespace aura {
@@ -15,7 +14,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // DefaultActivationClient, public:
 
-DefaultActivationClient::DefaultActivationClient(RootWindow* root_window)
+DefaultActivationClient::DefaultActivationClient(Window* root_window)
     : last_active_(NULL) {
   client::SetActivationClient(root_window, this);
 }
diff --git a/ui/aura/client/default_activation_client.h b/ui/aura/client/default_activation_client.h
index ebf04aa..842ee90 100644
--- a/ui/aura/client/default_activation_client.h
+++ b/ui/aura/client/default_activation_client.h
@@ -5,14 +5,16 @@
 #ifndef UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_
 #define UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_
 
+#include <vector>
+
 #include "base/compiler_specific.h"
 #include "base/logging.h"
+#include "base/observer_list.h"
 #include "ui/aura/aura_export.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/window_observer.h"
 
 namespace aura {
-class RootWindow;
 namespace client {
 class ActivationChangeObserver;
 }
@@ -25,7 +27,7 @@
 class AURA_EXPORT DefaultActivationClient : public client::ActivationClient,
                                             public WindowObserver {
  public:
-  explicit DefaultActivationClient(RootWindow* root_window);
+  explicit DefaultActivationClient(Window* root_window);
   virtual ~DefaultActivationClient();
 
   // Overridden from client::ActivationClient:
diff --git a/ui/aura/client/default_capture_client.cc b/ui/aura/client/default_capture_client.cc
index dae3b7d..6008a89 100644
--- a/ui/aura/client/default_capture_client.cc
+++ b/ui/aura/client/default_capture_client.cc
@@ -9,7 +9,7 @@
 namespace aura {
 namespace client {
 
-DefaultCaptureClient::DefaultCaptureClient(RootWindow* root_window)
+DefaultCaptureClient::DefaultCaptureClient(Window* root_window)
     : root_window_(root_window),
       capture_window_(NULL) {
   client::SetCaptureClient(root_window_, this);
@@ -30,7 +30,7 @@
   Window* old_capture_window = capture_window_;
   capture_window_ = window;
 
-  CaptureDelegate* capture_delegate = root_window_;
+  CaptureDelegate* capture_delegate = root_window_->GetDispatcher();
   if (capture_window_)
     capture_delegate->SetNativeCapture();
   else
diff --git a/ui/aura/client/default_capture_client.h b/ui/aura/client/default_capture_client.h
index a628b2d..fd95de0 100644
--- a/ui/aura/client/default_capture_client.h
+++ b/ui/aura/client/default_capture_client.h
@@ -15,7 +15,7 @@
 
 class AURA_EXPORT DefaultCaptureClient : public client::CaptureClient {
  public:
-  explicit DefaultCaptureClient(RootWindow* root_window);
+  explicit DefaultCaptureClient(Window* root_window);
   virtual ~DefaultCaptureClient();
 
  private:
@@ -24,7 +24,7 @@
   virtual void ReleaseCapture(Window* window) OVERRIDE;
   virtual Window* GetCaptureWindow() OVERRIDE;
 
-  RootWindow* root_window_;
+  Window* root_window_;
   Window* capture_window_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultCaptureClient);
diff --git a/ui/aura/client/dispatcher_client.cc b/ui/aura/client/dispatcher_client.cc
index 8a2d1c3..a9e1a7d 100644
--- a/ui/aura/client/dispatcher_client.cc
+++ b/ui/aura/client/dispatcher_client.cc
@@ -14,11 +14,14 @@
 
 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(DispatcherClient*, kDispatcherClientKey, NULL);
 
-void SetDispatcherClient(RootWindow* root_window, DispatcherClient* client) {
+void SetDispatcherClient(Window* root_window, DispatcherClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kDispatcherClientKey, client);
 }
 
-DispatcherClient* GetDispatcherClient(RootWindow* root_window) {
+DispatcherClient* GetDispatcherClient(Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
   return root_window ? root_window->GetProperty(kDispatcherClientKey) : NULL;
 }
 
diff --git a/ui/aura/client/dispatcher_client.h b/ui/aura/client/dispatcher_client.h
index c775611..f2d1ff8 100644
--- a/ui/aura/client/dispatcher_client.h
+++ b/ui/aura/client/dispatcher_client.h
@@ -10,7 +10,7 @@
 #include "ui/aura/window.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 namespace client {
 
 // An interface implemented by an object which handles nested dispatchers.
@@ -21,9 +21,9 @@
                                  bool nestable_tasks_allowed) = 0;
 };
 
-AURA_EXPORT void SetDispatcherClient(RootWindow* root_window,
+AURA_EXPORT void SetDispatcherClient(Window* root_window,
                                      DispatcherClient* client);
-AURA_EXPORT DispatcherClient* GetDispatcherClient(RootWindow* root_window);
+AURA_EXPORT DispatcherClient* GetDispatcherClient(Window* root_window);
 
 }  // namespace client
 }  // namespace aura
diff --git a/ui/aura/client/drag_drop_client.cc b/ui/aura/client/drag_drop_client.cc
index 1122c1b..abf5879 100644
--- a/ui/aura/client/drag_drop_client.cc
+++ b/ui/aura/client/drag_drop_client.cc
@@ -15,11 +15,14 @@
 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
     DragDropClient*, kRootWindowDragDropClientKey, NULL);
 
-void SetDragDropClient(RootWindow* root_window, DragDropClient* client) {
+void SetDragDropClient(Window* root_window, DragDropClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kRootWindowDragDropClientKey, client);
 }
 
-DragDropClient* GetDragDropClient(RootWindow* root_window) {
+DragDropClient* GetDragDropClient(Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
   return root_window ?
       root_window->GetProperty(kRootWindowDragDropClientKey) : NULL;
 }
diff --git a/ui/aura/client/drag_drop_client.h b/ui/aura/client/drag_drop_client.h
index c7b145b..7277d6b 100644
--- a/ui/aura/client/drag_drop_client.h
+++ b/ui/aura/client/drag_drop_client.h
@@ -19,7 +19,6 @@
 }
 
 namespace aura {
-class RootWindow;
 class Window;
 namespace client {
 
@@ -30,9 +29,9 @@
 
   // Initiates a drag and drop session. Returns the drag operation that was
   // applied at the end of the drag drop session. |root_location| is in the
-  // RootWindow's coordinate system.
+  // root Window's coordinate system.
   virtual int StartDragAndDrop(const ui::OSExchangeData& data,
-                               aura::RootWindow* root_window,
+                               aura::Window* root_window,
                                aura::Window* source_window,
                                const gfx::Point& root_location,
                                int operation,
@@ -53,9 +52,9 @@
   virtual bool IsDragDropInProgress() = 0;
 };
 
-AURA_EXPORT void SetDragDropClient(RootWindow* root_window,
+AURA_EXPORT void SetDragDropClient(Window* root_window,
                                    DragDropClient* client);
-AURA_EXPORT DragDropClient* GetDragDropClient(RootWindow* root_window);
+AURA_EXPORT DragDropClient* GetDragDropClient(Window* root_window);
 
 }  // namespace client
 }  // namespace aura
diff --git a/ui/aura/client/event_client.cc b/ui/aura/client/event_client.cc
index dfb3410..c669974 100644
--- a/ui/aura/client/event_client.cc
+++ b/ui/aura/client/event_client.cc
@@ -14,11 +14,14 @@
 
 DEFINE_WINDOW_PROPERTY_KEY(EventClient*, kRootWindowEventClientKey, NULL);
 
-void SetEventClient(RootWindow* root_window, EventClient* client) {
+void SetEventClient(Window* root_window, EventClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kRootWindowEventClientKey, client);
 }
 
-EventClient* GetEventClient(const RootWindow* root_window) {
+EventClient* GetEventClient(const Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
   return root_window ?
       root_window->GetProperty(kRootWindowEventClientKey) : NULL;
 }
diff --git a/ui/aura/client/event_client.h b/ui/aura/client/event_client.h
index 31565e2..3ce88e3 100644
--- a/ui/aura/client/event_client.h
+++ b/ui/aura/client/event_client.h
@@ -6,13 +6,13 @@
 #define UI_AURA_CLIENT_EVENT_CLIENT_H_
 
 #include "ui/aura/aura_export.h"
-#include "ui/aura/window.h"
+
+namespace ui {
+class EventTarget;
+}
 
 namespace aura {
-
-class Event;
-class RootWindow;
-
+class Window;
 namespace client {
 
 // An interface implemented by an object that alters event processing.
@@ -28,9 +28,9 @@
   virtual ~EventClient() {}
 };
 
-// Sets/Gets the event client on the RootWindow.
-AURA_EXPORT void SetEventClient(RootWindow* root_window, EventClient* client);
-AURA_EXPORT EventClient* GetEventClient(const RootWindow* root_window);
+// Sets/Gets the event client on the root Window.
+AURA_EXPORT void SetEventClient(Window* root_window, EventClient* client);
+AURA_EXPORT EventClient* GetEventClient(const Window* root_window);
 
 }  // namespace clients
 }  // namespace aura
diff --git a/ui/aura/client/focus_client.cc b/ui/aura/client/focus_client.cc
index 83ad1a9..0769b0d 100644
--- a/ui/aura/client/focus_client.cc
+++ b/ui/aura/client/focus_client.cc
@@ -15,7 +15,8 @@
 
 DEFINE_WINDOW_PROPERTY_KEY(FocusClient*, kRootWindowFocusClientKey, NULL);
 
-void SetFocusClient(RootWindow* root_window, FocusClient* client) {
+void SetFocusClient(Window* root_window, FocusClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kRootWindowFocusClientKey, client);
 }
 
@@ -24,7 +25,7 @@
 }
 
 FocusClient* GetFocusClient(const Window* window) {
-  const RootWindow* root_window = window->GetRootWindow();
+  const Window* root_window = window->GetRootWindow();
   return root_window ?
       root_window->GetProperty(kRootWindowFocusClientKey) : NULL;
 }
diff --git a/ui/aura/client/focus_client.h b/ui/aura/client/focus_client.h
index ad55d5e..cec64ec 100644
--- a/ui/aura/client/focus_client.h
+++ b/ui/aura/client/focus_client.h
@@ -12,9 +12,7 @@
 }
 
 namespace aura {
-class RootWindow;
 class Window;
-
 namespace client {
 class FocusChangeObserver;
 
@@ -37,8 +35,8 @@
   virtual Window* GetFocusedWindow() = 0;
 };
 
-// Sets/Gets the focus client on the RootWindow.
-AURA_EXPORT void SetFocusClient(RootWindow* root_window, FocusClient* client);
+// Sets/Gets the focus client on the root Window.
+AURA_EXPORT void SetFocusClient(Window* root_window, FocusClient* client);
 AURA_EXPORT FocusClient* GetFocusClient(Window* window);
 AURA_EXPORT FocusClient* GetFocusClient(const Window* window);
 
diff --git a/ui/aura/client/screen_position_client.cc b/ui/aura/client/screen_position_client.cc
index ac13156..1fb7521 100644
--- a/ui/aura/client/screen_position_client.cc
+++ b/ui/aura/client/screen_position_client.cc
@@ -16,13 +16,17 @@
                                  kScreenPositionClientKey,
                                  NULL);
 
-void SetScreenPositionClient(RootWindow* window,
+void SetScreenPositionClient(Window* root_window,
                              ScreenPositionClient* client) {
-  window->SetProperty(kScreenPositionClientKey, client);
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
+  root_window->SetProperty(kScreenPositionClientKey, client);
 }
 
-ScreenPositionClient* GetScreenPositionClient(const RootWindow* window) {
-  return window ? window->GetProperty(kScreenPositionClientKey) : NULL;
+ScreenPositionClient* GetScreenPositionClient(const Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
+  return root_window ?
+      root_window->GetProperty(kScreenPositionClientKey) : NULL;
 }
 
 }  // namespace client
diff --git a/ui/aura/client/screen_position_client.h b/ui/aura/client/screen_position_client.h
index e5505eb..9dceb22 100644
--- a/ui/aura/client/screen_position_client.h
+++ b/ui/aura/client/screen_position_client.h
@@ -14,17 +14,15 @@
 }
 
 namespace aura {
-
-class Event;
-class RootWindow;
 class Window;
-
 namespace client {
 
-// An interface implemented by an object that changes coordinates on a
-// RootWindow into system coordinates.
+// An interface implemented by an object that changes coordinates within a root
+// Window into system coordinates.
 class AURA_EXPORT ScreenPositionClient {
  public:
+  virtual ~ScreenPositionClient() {}
+
   // Converts the |screen_point| from a given |window|'s coordinate space
   // into screen coordinate space.
   virtual void ConvertPointToScreen(const Window* window,
@@ -36,21 +34,20 @@
   // A typical example of using this function instead of ConvertPointToScreen is
   // when X's native input is captured by a drag operation.
   // See the comments for ash::GetRootWindowRelativeToWindow for details.
-  virtual void ConvertHostPointToScreen(aura::RootWindow* root_window,
+  virtual void ConvertHostPointToScreen(Window* root_window,
                                         gfx::Point* point) = 0;
   // Sets the bounds of the window. The implementation is responsible
   // for finding out and translating the right coordinates for the |window|.
   virtual void SetBounds(Window* window,
                          const gfx::Rect& bounds,
                          const gfx::Display& display) = 0;
-  virtual ~ScreenPositionClient() {}
 };
 
 // Sets/Gets the activation client on the Window.
-AURA_EXPORT void SetScreenPositionClient(RootWindow* window,
+AURA_EXPORT void SetScreenPositionClient(Window* root_window,
                                          ScreenPositionClient* client);
 AURA_EXPORT ScreenPositionClient* GetScreenPositionClient(
-    const RootWindow* window);
+    const Window* root_window);
 
 }  // namespace clients
 }  // namespace aura
diff --git a/ui/aura/client/stacking_client.cc b/ui/aura/client/stacking_client.cc
deleted file mode 100644
index 5d93d98..0000000
--- a/ui/aura/client/stacking_client.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/stacking_client.h"
-
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::StackingClient*)
-
-namespace aura {
-namespace client {
-
-DEFINE_WINDOW_PROPERTY_KEY(
-    StackingClient*, kRootWindowStackingClientKey, NULL);
-
-void SetStackingClient(Window* window, StackingClient* stacking_client) {
-  DCHECK(window);
-
-  RootWindow* root_window = window->GetRootWindow();
-  DCHECK(root_window);
-  root_window->SetProperty(kRootWindowStackingClientKey, stacking_client);
-}
-
-StackingClient* GetStackingClient(Window* window) {
-  DCHECK(window);
-  RootWindow* root_window = window->GetRootWindow();
-  DCHECK(root_window);
-  StackingClient* root_window_stacking_client =
-      root_window->GetProperty(kRootWindowStackingClientKey);
-  DCHECK(root_window_stacking_client);
-  return root_window_stacking_client;
-}
-
-}  // namespace client
-}  // namespace aura
diff --git a/ui/aura/client/stacking_client.h b/ui/aura/client/stacking_client.h
deleted file mode 100644
index 89f83eb..0000000
--- a/ui/aura/client/stacking_client.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2012 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_AURA_CLIENT_STACKING_CLIENT_H_
-#define UI_AURA_CLIENT_STACKING_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-// An interface implemented by an object that stacks windows.
-class AURA_EXPORT StackingClient {
- public:
-  virtual ~StackingClient() {}
-
-  // Called by the Window when it looks for a default parent. Returns the
-  // window that |window| should be added to instead. |context| provides a
-  // Window (generally a RootWindow) that can be used to determine which
-  // desktop type the default parent should be chosen from.  NOTE: this may
-  // have side effects. It should only be used when |window| is going to be
-  // immediately added.
-  //
-  // TODO(erg): Remove |context|, and maybe after oshima's patch lands,
-  // |bounds|.
-  virtual Window* GetDefaultParent(
-      Window* context,
-      Window* window,
-      const gfx::Rect& bounds) = 0;
-};
-
-// Set/Get a stacking client for a specific window. Setting the stacking client
-// sets the stacking client on the window's RootWindow, not the window itself.
-// Likewise getting obtains it from the window's RootWindow. If |window| is
-// non-NULL it must be in a RootWindow. If |window| is NULL, the default
-// stacking client is used.
-AURA_EXPORT void SetStackingClient(Window* window,
-                                   StackingClient* stacking_client);
-StackingClient* GetStackingClient(Window* window);
-
-}  // namespace client
-}  // namespace aura
-
-#endif  // UI_AURA_CLIENT_STACKING_CLIENT_H_
diff --git a/ui/aura/client/tooltip_client.cc b/ui/aura/client/tooltip_client.cc
index a966c28..f018f26 100644
--- a/ui/aura/client/tooltip_client.cc
+++ b/ui/aura/client/tooltip_client.cc
@@ -17,11 +17,14 @@
     TooltipClient*, kRootWindowTooltipClientKey, NULL);
 DEFINE_LOCAL_WINDOW_PROPERTY_KEY(base::string16*, kTooltipTextKey, NULL);
 
-void SetTooltipClient(RootWindow* root_window, TooltipClient* client) {
+void SetTooltipClient(Window* root_window, TooltipClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kRootWindowTooltipClientKey, client);
 }
 
-TooltipClient* GetTooltipClient(RootWindow* root_window) {
+TooltipClient* GetTooltipClient(Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
   return root_window ?
       root_window->GetProperty(kRootWindowTooltipClientKey) : NULL;
 }
diff --git a/ui/aura/client/tooltip_client.h b/ui/aura/client/tooltip_client.h
index d6d33ce..c280b8a 100644
--- a/ui/aura/client/tooltip_client.h
+++ b/ui/aura/client/tooltip_client.h
@@ -9,9 +9,7 @@
 #include "ui/gfx/font.h"
 
 namespace aura {
-class RootWindow;
 class Window;
-
 namespace client {
 
 class AURA_EXPORT TooltipClient {
@@ -27,9 +25,9 @@
   virtual void SetTooltipsEnabled(bool enable) = 0;
 };
 
-AURA_EXPORT void SetTooltipClient(RootWindow* root_window,
+AURA_EXPORT void SetTooltipClient(Window* root_window,
                                   TooltipClient* client);
-AURA_EXPORT TooltipClient* GetTooltipClient(RootWindow* root_window);
+AURA_EXPORT TooltipClient* GetTooltipClient(Window* root_window);
 
 AURA_EXPORT void SetTooltipText(Window* window, base::string16* tooltip_text);
 AURA_EXPORT const base::string16 GetTooltipText(Window* window);
diff --git a/ui/aura/client/user_action_client.cc b/ui/aura/client/user_action_client.cc
index cfb5fe1..3dab666 100644
--- a/ui/aura/client/user_action_client.cc
+++ b/ui/aura/client/user_action_client.cc
@@ -14,11 +14,14 @@
                            kRootWindowUserActionClientKey,
                            NULL);
 
-void SetUserActionClient(RootWindow* root_window, UserActionClient* client) {
+void SetUserActionClient(Window* root_window, UserActionClient* client) {
+  DCHECK_EQ(root_window->GetRootWindow(), root_window);
   root_window->SetProperty(kRootWindowUserActionClientKey, client);
 }
 
-UserActionClient* GetUserActionClient(RootWindow* root_window) {
+UserActionClient* GetUserActionClient(Window* root_window) {
+  if (root_window)
+    DCHECK_EQ(root_window->GetRootWindow(), root_window);
   return root_window ?
       root_window->GetProperty(kRootWindowUserActionClientKey) : NULL;
 }
diff --git a/ui/aura/client/user_action_client.h b/ui/aura/client/user_action_client.h
index 16f0b9f..738a8d5 100644
--- a/ui/aura/client/user_action_client.h
+++ b/ui/aura/client/user_action_client.h
@@ -8,7 +8,7 @@
 #include "ui/aura/aura_export.h"
 
 namespace aura {
-class RootWindow;
+class Window;
 namespace client {
 
 // An interface for handling a user action that isn't handled by the standard
@@ -27,9 +27,9 @@
 };
 
 // Sets/gets the client for handling user action on the specified root window.
-AURA_EXPORT void SetUserActionClient(RootWindow* root_window,
+AURA_EXPORT void SetUserActionClient(Window* root_window,
                                      UserActionClient* client);
-AURA_EXPORT UserActionClient* GetUserActionClient(RootWindow* root_window);
+AURA_EXPORT UserActionClient* GetUserActionClient(Window* root_window);
 
 }  // namespace client
 }  // namespace aura
diff --git a/ui/aura/client/window_tree_client.cc b/ui/aura/client/window_tree_client.cc
new file mode 100644
index 0000000..de1ece5
--- /dev/null
+++ b/ui/aura/client/window_tree_client.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/client/window_tree_client.h"
+
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowTreeClient*)
+
+namespace aura {
+namespace client {
+
+DEFINE_WINDOW_PROPERTY_KEY(
+    WindowTreeClient*, kRootWindowWindowTreeClientKey, NULL);
+
+void SetWindowTreeClient(Window* window, WindowTreeClient* window_tree_client) {
+  DCHECK(window);
+
+  Window* root_window = window->GetRootWindow();
+  DCHECK(root_window);
+  root_window->SetProperty(kRootWindowWindowTreeClientKey, window_tree_client);
+}
+
+WindowTreeClient* GetWindowTreeClient(Window* window) {
+  DCHECK(window);
+  Window* root_window = window->GetRootWindow();
+  DCHECK(root_window);
+  WindowTreeClient* client =
+      root_window->GetProperty(kRootWindowWindowTreeClientKey);
+  DCHECK(client);
+  return client;
+}
+
+void ParentWindowWithContext(Window* window,
+                             Window* context,
+                             const gfx::Rect& screen_bounds) {
+  DCHECK(context);
+
+  // |context| must be attached to a hierarchy with a WindowTreeClient.
+  WindowTreeClient* client = GetWindowTreeClient(context);
+  DCHECK(client);
+  Window* default_parent =
+      client->GetDefaultParent(context, window, screen_bounds);
+  default_parent->AddChild(window);
+}
+
+}  // namespace client
+}  // namespace aura
diff --git a/ui/aura/client/window_tree_client.h b/ui/aura/client/window_tree_client.h
new file mode 100644
index 0000000..59cb132
--- /dev/null
+++ b/ui/aura/client/window_tree_client.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2013 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_AURA_CLIENT_WINDOW_TREE_CLIENT_H_
+#define UI_AURA_CLIENT_WINDOW_TREE_CLIENT_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+// Implementations of this object are used to help locate a default parent for
+// NULL-parented Windows.
+class AURA_EXPORT WindowTreeClient {
+ public:
+  virtual ~WindowTreeClient() {}
+
+  // Called by the Window when it looks for a default parent. Returns the
+  // window that |window| should be added to instead. |context| provides a
+  // Window (generally a RootWindow) that can be used to determine which
+  // desktop type the default parent should be chosen from.  NOTE: this may
+  // have side effects. It should only be used when |window| is going to be
+  // immediately added.
+  //
+  // TODO(erg): Remove |context|, and maybe after oshima's patch lands,
+  // |bounds|.
+  virtual Window* GetDefaultParent(
+      Window* context,
+      Window* window,
+      const gfx::Rect& bounds) = 0;
+};
+
+// Set/Get a window tree client for the RootWindow containing |window|. |window|
+// must not be NULL.
+AURA_EXPORT void SetWindowTreeClient(Window* window,
+                                     WindowTreeClient* window_tree_client);
+WindowTreeClient* GetWindowTreeClient(Window* window);
+
+// Adds |window| to an appropriate parent by consulting an implementation of
+// WindowTreeClient attached at the root Window containing |context|. The final
+// location may be a window hierarchy other than the one supplied via
+// |context|, which must not be NULL. |screen_bounds| may be empty.
+AURA_EXPORT void ParentWindowWithContext(Window* window,
+                                         Window* context,
+                                         const gfx::Rect& screen_bounds);
+
+}  // namespace client
+}  // namespace aura
+
+#endif  // UI_AURA_CLIENT_WINDOW_TREE_CLIENT_H_
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc
index abdd514..75b1d60 100644
--- a/ui/aura/demo/demo_main.cc
+++ b/ui/aura/demo/demo_main.cc
@@ -9,7 +9,7 @@
 #include "base/message_loop/message_loop.h"
 #include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/aura/client/default_capture_client.h"
-#include "ui/aura/client/stacking_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/test_focus_client.h"
@@ -19,7 +19,7 @@
 #include "ui/base/hit_test.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
-#include "ui/compositor/compositor.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/events/event.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/rect.h"
@@ -77,34 +77,33 @@
   DISALLOW_COPY_AND_ASSIGN(DemoWindowDelegate);
 };
 
-class DemoStackingClient : public aura::client::StackingClient {
+class DemoWindowTreeClient : public aura::client::WindowTreeClient {
  public:
-  explicit DemoStackingClient(aura::RootWindow* root_window)
-      : root_window_(root_window) {
-    aura::client::SetStackingClient(root_window_, this);
+  explicit DemoWindowTreeClient(aura::Window* window) : window_(window) {
+    aura::client::SetWindowTreeClient(window_, this);
   }
 
-  virtual ~DemoStackingClient() {
-    aura::client::SetStackingClient(root_window_, NULL);
+  virtual ~DemoWindowTreeClient() {
+    aura::client::SetWindowTreeClient(window_, NULL);
   }
 
-  // Overridden from aura::client::StackingClient:
+  // Overridden from aura::client::WindowTreeClient:
   virtual aura::Window* GetDefaultParent(aura::Window* context,
                                          aura::Window* window,
                                          const gfx::Rect& bounds) OVERRIDE {
     if (!capture_client_) {
       capture_client_.reset(
-          new aura::client::DefaultCaptureClient(root_window_));
+          new aura::client::DefaultCaptureClient(window_->GetRootWindow()));
     }
-    return root_window_;
+    return window_;
   }
 
  private:
-  aura::RootWindow* root_window_;
+  aura::Window* window_;
 
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
 
-  DISALLOW_COPY_AND_ASSIGN(DemoStackingClient);
+  DISALLOW_COPY_AND_ASSIGN(DemoWindowTreeClient);
 };
 
 int DemoMain() {
@@ -113,14 +112,14 @@
 
   // The ContextFactory must exist before any Compositors are created.
   bool allow_test_contexts = false;
-  ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
 
   aura::Env::CreateInstance();
   scoped_ptr<aura::TestScreen> test_screen(aura::TestScreen::Create());
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
   scoped_ptr<aura::RootWindow> root_window(
       test_screen->CreateRootWindowForPrimaryDisplay());
-  scoped_ptr<DemoStackingClient> stacking_client(new DemoStackingClient(
+  scoped_ptr<DemoWindowTreeClient> window_tree_client(new DemoWindowTreeClient(
       root_window.get()));
   aura::test::TestFocusClient focus_client;
   aura::client::SetFocusClient(root_window.get(), &focus_client);
@@ -132,7 +131,8 @@
   window1.Init(ui::LAYER_TEXTURED);
   window1.SetBounds(gfx::Rect(100, 100, 400, 400));
   window1.Show();
-  window1.SetDefaultParentByRootWindow(root_window.get(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      &window1, root_window.get(), gfx::Rect());
 
   DemoWindowDelegate window_delegate2(SK_ColorRED);
   aura::Window window2(&window_delegate2);
@@ -140,7 +140,8 @@
   window2.Init(ui::LAYER_TEXTURED);
   window2.SetBounds(gfx::Rect(200, 200, 350, 350));
   window2.Show();
-  window2.SetDefaultParentByRootWindow(root_window.get(), gfx::Rect());
+  aura::client::ParentWindowWithContext(
+      &window2, root_window.get(), gfx::Rect());
 
   DemoWindowDelegate window_delegate3(SK_ColorGREEN);
   aura::Window window3(&window_delegate3);
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 4b501c7..911f8d3 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -81,6 +81,7 @@
         long_press_(false),
         fling_(false),
         two_finger_tap_(false),
+        show_press_(false),
         swipe_left_(false),
         swipe_right_(false),
         swipe_up_(false),
@@ -119,6 +120,7 @@
     long_press_ = false;
     fling_ = false;
     two_finger_tap_ = false;
+    show_press_ = false;
     swipe_left_ = false;
     swipe_right_ = false;
     swipe_up_ = false;
@@ -159,6 +161,7 @@
   bool long_tap() const { return long_tap_; }
   bool fling() const { return fling_; }
   bool two_finger_tap() const { return two_finger_tap_; }
+  bool show_press() const { return show_press_; }
   bool swipe_left() const { return swipe_left_; }
   bool swipe_right() const { return swipe_right_; }
   bool swipe_up() const { return swipe_up_; }
@@ -264,6 +267,9 @@
       case ui::ET_GESTURE_TWO_FINGER_TAP:
         two_finger_tap_ = true;
         break;
+      case ui::ET_GESTURE_SHOW_PRESS:
+        show_press_ = true;
+        break;
       case ui::ET_GESTURE_MULTIFINGER_SWIPE:
         swipe_left_ = gesture->details().swipe_left();
         swipe_right_ = gesture->details().swipe_right();
@@ -299,6 +305,7 @@
   bool long_tap_;
   bool fling_;
   bool two_finger_tap_;
+  bool show_press_;
   bool swipe_left_;
   bool swipe_right_;
   bool swipe_up_;
@@ -693,6 +700,7 @@
                        kTouchId, tes.Now());
   root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
   EXPECT_FALSE(delegate->tap());
+  EXPECT_FALSE(delegate->show_press());
   EXPECT_TRUE(delegate->tap_down());
   EXPECT_FALSE(delegate->tap_cancel());
   EXPECT_TRUE(delegate->begin());
@@ -701,6 +709,11 @@
   EXPECT_FALSE(delegate->scroll_end());
   EXPECT_FALSE(delegate->long_press());
 
+  delegate->Reset();
+  delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
+  EXPECT_TRUE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_down());
+
   // Make sure there is enough delay before the touch is released so that it is
   // recognized as a tap.
   delegate->Reset();
@@ -1969,11 +1982,16 @@
   ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
                         kTouchId2, tes.Now());
   root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
-  // Since the touch points are far enough we will go to pinch rather than two
-  // finger tap.
-  EXPECT_TRUE(delegate->pinch_begin());
+  EXPECT_FALSE(delegate->pinch_begin());
 
+  // Touch move triggers pinch begin.
   tes.SendScrollEvent(root_window(), 130, 230, kTouchId1, delegate.get());
+  EXPECT_TRUE(delegate->pinch_begin());
+  EXPECT_FALSE(delegate->pinch_update());
+
+  // Touch move triggers pinch update.
+  tes.SendScrollEvent(root_window(), 160, 200, kTouchId1, delegate.get());
+  EXPECT_FALSE(delegate->pinch_begin());
   EXPECT_TRUE(delegate->pinch_update());
 
   // Pinch has started, now release the second finger
@@ -2025,17 +2043,14 @@
                   ui::ET_GESTURE_TAP_DOWN);
   EXPECT_TRUE(delegate->bounding_box().IsEmpty());
 
-  // Press the second finger far enough to break two finger tap. It should
-  // instead cause a scroll-begin and pinch-begin.
+  // Press the second finger far enough to break two finger tap.
   delegate->Reset();
   ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
                         kTouchId2, tes.Now());
   root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
-  EXPECT_4_EVENTS(delegate->events(),
+  EXPECT_2_EVENTS(delegate->events(),
                   ui::ET_GESTURE_TAP_CANCEL,
-                  ui::ET_GESTURE_BEGIN,
-                  ui::ET_GESTURE_PINCH_BEGIN,
-                  ui::ET_GESTURE_SCROLL_BEGIN);
+                  ui::ET_GESTURE_BEGIN);
   EXPECT_EQ(gfx::Rect(10, 10, 91, 291).ToString(),
             delegate->bounding_box().ToString());
 
@@ -2045,8 +2060,8 @@
                        kTouchId1, tes.Now());
   root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3);
   EXPECT_2_EVENTS(delegate->events(),
-                  ui::ET_GESTURE_PINCH_UPDATE,
-                  ui::ET_GESTURE_SCROLL_UPDATE);
+                  ui::ET_GESTURE_PINCH_BEGIN,
+                  ui::ET_GESTURE_SCROLL_BEGIN);
   EXPECT_EQ(gfx::Rect(10, 10, 55, 191).ToString(),
             delegate->bounding_box().ToString());
 
@@ -2824,6 +2839,21 @@
   EXPECT_FALSE(delegate->tap());
   EXPECT_FALSE(delegate->tap_down());  // no touch down for second tap.
   EXPECT_TRUE(delegate->tap_cancel());
+  EXPECT_FALSE(delegate->scroll_begin());
+  EXPECT_FALSE(delegate->scroll_update());
+  EXPECT_FALSE(delegate->scroll_end());
+  EXPECT_FALSE(delegate->long_press());
+  EXPECT_FALSE(delegate->two_finger_tap());
+  EXPECT_FALSE(delegate->pinch_begin());
+
+  delegate->Reset();
+  ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(530, 301),
+                       kTouchId2, tes.Now());
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+  EXPECT_FALSE(delegate->tap());
+  EXPECT_FALSE(delegate->tap_down());
+  EXPECT_FALSE(delegate->tap_cancel());
+  // Pinch & Scroll only when there is enough movement.
   EXPECT_TRUE(delegate->scroll_begin());
   EXPECT_FALSE(delegate->scroll_update());
   EXPECT_FALSE(delegate->scroll_end());
@@ -3001,11 +3031,10 @@
   root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
   tes.SendScrollEvent(root_window(), 161, 231, kTouchId2, delegate.get());
 
-  // PinchBegin & ScrollBegin were sent even though the touch-move events
-  // were consumed. This seems reasonable, as long as we don't send PinchUpdate
-  // ScrollUpdate when touch-move are consumed.
-  EXPECT_TRUE(delegate->pinch_begin());
-  EXPECT_TRUE(delegate->scroll_begin());
+  // PinchBegin & ScrollBegin were not sent if the touch-move events were
+  // consumed.
+  EXPECT_FALSE(delegate->pinch_begin());
+  EXPECT_FALSE(delegate->scroll_begin());
 
   EXPECT_FALSE(delegate->tap());
   EXPECT_FALSE(delegate->two_finger_tap());
@@ -3031,15 +3060,24 @@
   delegate->Reset();
   // Making a pinch gesture.
   tes.SendScrollEvent(root_window(), 161, 251, kTouchId1, delegate.get());
-  tes.SendScrollEvent(root_window(), 161, 241, kTouchId2, delegate.get());
-
-  // Now we see PinchUpdate & ScrollUpdate.
+  // If touch moves are ever consumed, we should not see PinchBegin/Update
+  // even touch moves become not consumed.
   EXPECT_FALSE(delegate->scroll_begin());
-  EXPECT_TRUE(delegate->scroll_update());
+  EXPECT_FALSE(delegate->scroll_update());
   EXPECT_FALSE(delegate->scroll_end());
 
   EXPECT_FALSE(delegate->pinch_begin());
-  EXPECT_TRUE(delegate->pinch_update());
+  EXPECT_FALSE(delegate->pinch_update());
+  EXPECT_FALSE(delegate->pinch_end());
+
+  delegate->Reset();
+  tes.SendScrollEvent(root_window(), 161, 241, kTouchId2, delegate.get());
+  EXPECT_FALSE(delegate->scroll_begin());
+  EXPECT_FALSE(delegate->scroll_update());
+  EXPECT_FALSE(delegate->scroll_end());
+
+  EXPECT_FALSE(delegate->pinch_begin());
+  EXPECT_FALSE(delegate->pinch_update());
   EXPECT_FALSE(delegate->pinch_end());
 
   delegate->Reset();
@@ -3051,16 +3089,17 @@
   root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
 
   EXPECT_FALSE(delegate->tap());
-  EXPECT_FALSE(delegate->two_finger_tap());
+  // Touch release is not consumed, so we still see two finger tap.
+  EXPECT_TRUE(delegate->two_finger_tap());
 
-  // Should see PinchEnd & ScrollEnd.
+  // Should not see PinchEnd & ScrollEnd.
   EXPECT_FALSE(delegate->scroll_begin());
   EXPECT_FALSE(delegate->scroll_update());
-  EXPECT_TRUE(delegate->scroll_end());
+  EXPECT_FALSE(delegate->scroll_end());
 
   EXPECT_FALSE(delegate->pinch_begin());
   EXPECT_FALSE(delegate->pinch_update());
-  EXPECT_TRUE(delegate->pinch_end());
+  EXPECT_FALSE(delegate->pinch_end());
 }
 
 // Like as GestureEventTouchMoveConsumed but tests the different behavior
@@ -3523,5 +3562,128 @@
   EXPECT_EQ(1, handler->touch_cancelled_count());
 }
 
+// Check that appropriate touch events generate show press events
+TEST_F(GestureRecognizerTest, GestureEventShowPress) {
+  scoped_ptr<GestureEventConsumeDelegate> delegate(
+      new GestureEventConsumeDelegate());
+  TimedEvents tes;
+  const int kWindowWidth = 123;
+  const int kWindowHeight = 45;
+  const int kTouchId = 2;
+  gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+  scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+      delegate.get(), -1234, bounds, root_window()));
+
+  delegate->Reset();
+
+  TimerTestGestureRecognizer* gesture_recognizer =
+      new TimerTestGestureRecognizer();
+
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
+
+  ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+                        kTouchId, tes.Now());
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+  EXPECT_TRUE(delegate->tap_down());
+  EXPECT_TRUE(delegate->begin());
+  EXPECT_FALSE(delegate->tap_cancel());
+
+  // We haven't pressed long enough for a show press to occur
+  EXPECT_FALSE(delegate->show_press());
+
+  // Wait until the timer runs out
+  delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
+  EXPECT_TRUE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_cancel());
+
+  delegate->Reset();
+  ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
+                          kTouchId, tes.Now());
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+  EXPECT_FALSE(delegate->long_press());
+
+  // Note the tap down isn't cancelled until the release
+  EXPECT_TRUE(delegate->tap_cancel());
+}
+
+// Check that scrolling cancels a show press
+TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
+  scoped_ptr<GestureEventConsumeDelegate> delegate(
+      new GestureEventConsumeDelegate());
+  TimedEvents tes;
+  const int kWindowWidth = 123;
+  const int kWindowHeight = 45;
+  const int kTouchId = 6;
+  gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+  scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+      delegate.get(), -1234, bounds, root_window()));
+
+  delegate->Reset();
+
+  TimerTestGestureRecognizer* gesture_recognizer =
+      new TimerTestGestureRecognizer();
+
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
+
+  TimerTestGestureSequence* gesture_sequence =
+      static_cast<TimerTestGestureSequence*>(
+          gesture_recognizer->GetGestureSequenceForTesting(window.get()));
+
+  ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+                        kTouchId, tes.Now());
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+  EXPECT_TRUE(delegate->tap_down());
+
+  // We haven't pressed long enough for a show press to occur
+  EXPECT_FALSE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_cancel());
+
+  // Scroll around, to cancel the show press
+  tes.SendScrollEvent(root_window(), 130, 230, kTouchId, delegate.get());
+  // Wait until the timer runs out
+  gesture_sequence->ForceTimeout();
+  EXPECT_FALSE(delegate->show_press());
+  EXPECT_TRUE(delegate->tap_cancel());
+
+  delegate->Reset();
+  ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
+                          kTouchId, tes.LeapForward(10));
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+  EXPECT_FALSE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_cancel());
+}
+
+// Test that show press events are sent immediately on tap
+TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) {
+  scoped_ptr<GestureEventConsumeDelegate> delegate(
+      new GestureEventConsumeDelegate());
+  TimedEvents tes;
+  const int kWindowWidth = 123;
+  const int kWindowHeight = 45;
+  const int kTouchId = 6;
+  gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+  scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+      delegate.get(), -1234, bounds, root_window()));
+
+  delegate->Reset();
+
+  ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+                        kTouchId, tes.Now());
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+  EXPECT_TRUE(delegate->tap_down());
+
+  // We haven't pressed long enough for a show press to occur
+  EXPECT_FALSE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_cancel());
+
+  delegate->Reset();
+  ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
+                          kTouchId, tes.LeapForward(50));
+  root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+  EXPECT_TRUE(delegate->show_press());
+  EXPECT_FALSE(delegate->tap_cancel());
+  EXPECT_TRUE(delegate->tap());
+}
+
 }  // namespace test
 }  // namespace aura
diff --git a/ui/aura/input_state_lookup.cc b/ui/aura/input_state_lookup.cc
index af6757d..86ab3cd 100644
--- a/ui/aura/input_state_lookup.cc
+++ b/ui/aura/input_state_lookup.cc
@@ -10,10 +10,6 @@
 
 // static
 scoped_ptr<InputStateLookup> InputStateLookup::Create() {
-#if !defined(OS_CHROMEOS)
-  // TODO: need to create input_state_lookup_x11.
-  NOTIMPLEMENTED();
-#endif
   return scoped_ptr<InputStateLookup>();
 }
 
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc
index 9b468bf..e79f8ac 100644
--- a/ui/aura/root_window.cc
+++ b/ui/aura/root_window.cc
@@ -56,8 +56,10 @@
 }
 
 float GetDeviceScaleFactorFromDisplay(Window* window) {
-  return gfx::Screen::GetScreenFor(window)->
-      GetDisplayNearestWindow(window).device_scale_factor();
+  gfx::Display display = gfx::Screen::GetScreenFor(window)->
+      GetDisplayNearestWindow(window);
+  DCHECK(display.is_valid());
+  return display.device_scale_factor();
 }
 
 Window* ConsumerToWindow(ui::GestureConsumer* consumer) {
@@ -130,8 +132,8 @@
 
 RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds)
     : initial_bounds(a_initial_bounds),
-      host(NULL) {
-}
+      use_software_renderer(false),
+      host(NULL) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // RootWindow, public:
@@ -149,9 +151,11 @@
       event_factory_(this),
       held_event_factory_(this),
       repostable_event_factory_(this) {
+  set_dispatcher(this);
   SetName("RootWindow");
 
-  compositor_.reset(new ui::Compositor(host_->GetAcceleratedWidget()));
+  compositor_.reset(new ui::Compositor(params.use_software_renderer,
+                                       host_->GetAcceleratedWidget()));
   DCHECK(compositor_.get());
 
   prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(),
@@ -181,6 +185,8 @@
   // Destroying/removing child windows may try to access |host_| (eg.
   // GetAcceleratedWidget())
   host_.reset(NULL);
+
+  set_dispatcher(NULL);
 }
 
 // static
@@ -226,17 +232,16 @@
             static_cast<const ui::MouseEvent&>(event),
             static_cast<aura::Window*>(event.target()),
             static_cast<aura::Window*>(this)));
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&RootWindow::DispatchHeldEvents,
+                   repostable_event_factory_.GetWeakPtr()));
   } else {
-    held_repostable_event_.reset(
-        new ui::GestureEvent(
-            static_cast<const ui::GestureEvent&>(event),
-            static_cast<aura::Window*>(event.target()),
-            static_cast<aura::Window*>(this)));
+    DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
+    held_repostable_event_.reset();
+    // TODO(rbyers): Reposing of gestures is tricky to get
+    // right, so it's not yet supported.  crbug.com/170987.
   }
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&RootWindow::DispatchHeldEvents,
-                  repostable_event_factory_.GetWeakPtr()));
 }
 
 RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() {
@@ -520,11 +525,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // RootWindow, Window overrides:
 
-RootWindow* RootWindow::GetRootWindow() {
+Window* RootWindow::GetRootWindow() {
   return this;
 }
 
-const RootWindow* RootWindow::GetRootWindow() const {
+const Window* RootWindow::GetRootWindow() const {
   return this;
 }
 
@@ -613,7 +618,7 @@
 }
 
 void RootWindow::OnWindowRemovedFromRootWindow(Window* detached,
-                                               RootWindow* new_root) {
+                                               Window* new_root) {
   DCHECK(aura::client::GetCaptureWindow(this) != this);
 
   DispatchMouseExitToHidingWindow(detached);
@@ -738,6 +743,11 @@
   mouse_pressed_handler_ = NULL;
 }
 
+void RootWindow::OnOtherRootGotCapture() {
+  mouse_moved_handler_ = NULL;
+  mouse_pressed_handler_ = NULL;
+}
+
 void RootWindow::SetNativeCapture() {
   host_->SetCapture();
 }
@@ -761,7 +771,7 @@
   return (window && window->GetRootWindow() == this);
 }
 
-void RootWindow::DispatchLongPressGestureEvent(ui::GestureEvent* event) {
+void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent* event) {
   DispatchGestureEvent(event);
 }
 
@@ -932,15 +942,15 @@
   if (event->type() != ui::ET_MOUSE_PRESSED)
     return;
   Window* target = client::GetCaptureWindow(this);
-  RootWindow* root = this;
+  WindowEventDispatcher* dispatcher = this;
   if (!target) {
     target = GetEventHandlerForPoint(event->location());
   } else {
-    root = target->GetRootWindow();
-    CHECK(root);  // Capture window better be in valid root.
+    dispatcher = target->GetDispatcher();
+    CHECK(dispatcher);  // Capture window better be in valid root.
   }
-  root->mouse_pressed_handler_ = NULL;
-  root->DispatchMouseEventToTarget(event, target);
+  dispatcher->mouse_pressed_handler_ = NULL;
+  dispatcher->DispatchMouseEventToTarget(event, target);
 }
 
 bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event,
@@ -1096,47 +1106,16 @@
   return ProcessGestures(gestures.get()) ? true : handled;
 }
 
-bool RootWindow::DispatchGestureEventRepost(ui::GestureEvent* event) {
-  if (event->type() != ui::ET_GESTURE_TAP_DOWN)
-    return false;
-
-  // Cleanup stale gesture events for the old gesture target.
-  GestureConsumer* old_consumer = GetGestureTarget(event);
-  if (old_consumer)
-    CleanupGestureRecognizerState(static_cast<aura::Window*>(old_consumer));
-
-  Window* new_consumer = GetEventHandlerForPoint(event->root_location());
-  if (new_consumer) {
-    ui::GestureEvent begin_gesture(
-        ui::ET_GESTURE_BEGIN,
-        event->x(),
-        event->y(),
-        event->flags(),
-        event->time_stamp(),
-        ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0),
-        event->touch_ids_bitfield());
-    ProcessEvent(new_consumer, &begin_gesture);
-    ProcessEvent(new_consumer, event);
-    return event->handled();
-  }
-  return false;
-}
-
 void RootWindow::DispatchHeldEvents() {
   if (held_repostable_event_) {
     if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
-      ui::MouseEvent mouse_event(
-          static_cast<const ui::MouseEvent&>(*held_repostable_event_.get()));
-      held_repostable_event_.reset();  // must be reset before dispatch
-      DispatchMouseEventRepost(&mouse_event);
+      scoped_ptr<ui::MouseEvent> mouse_event(
+          static_cast<ui::MouseEvent*>(held_repostable_event_.release()));
+      DispatchMouseEventRepost(mouse_event.get());
     } else {
-      DCHECK(held_repostable_event_->type() == ui::ET_GESTURE_TAP_DOWN);
-      ui::GestureEvent gesture_event(
-          static_cast<const ui::GestureEvent&>(*held_repostable_event_.get()));
-      held_repostable_event_.reset();  // must be reset before dispatch
-      DispatchGestureEventRepost(&gesture_event);
+      // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
+      NOTREACHED();
     }
-    held_repostable_event_.reset();
   }
   if (held_move_event_ && held_move_event_->IsMouseEvent()) {
     // If a mouse move has been synthesized, the target location is suspect,
diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h
index 7c84fa7..d5f22df 100644
--- a/ui/aura/root_window.h
+++ b/ui/aura/root_window.h
@@ -66,6 +66,9 @@
 
     gfx::Rect initial_bounds;
 
+    // If true, should try avoiding the use of a GPU for this window.
+    bool use_software_renderer;
+
     // A host to use in place of the default one that RootWindow will create.
     // NULL by default.
     RootWindowHost* host;
@@ -97,7 +100,7 @@
 
   // Repost event for re-processing. Used when exiting context menus.
   // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event
-  // types.
+  // types (although the latter is currently a no-op).
   void RepostEvent(const ui::LocatedEvent& event);
 
   RootWindowHostDelegate* AsRootWindowHostDelegate();
@@ -238,8 +241,8 @@
   gfx::Transform GetRootTransform() const;
 
   // Overridden from Window:
-  virtual RootWindow* GetRootWindow() OVERRIDE;
-  virtual const RootWindow* GetRootWindow() const OVERRIDE;
+  virtual Window* GetRootWindow() OVERRIDE;
+  virtual const Window* GetRootWindow() const OVERRIDE;
   virtual void SetTransform(const gfx::Transform& transform) OVERRIDE;
   virtual bool CanFocus() const OVERRIDE;
   virtual bool CanReceiveEvents() const OVERRIDE;
@@ -281,7 +284,7 @@
 
   // Called when a Window is attached or detached from the RootWindow.
   void OnWindowAddedToRootWindow(Window* window);
-  void OnWindowRemovedFromRootWindow(Window* window, RootWindow* new_root);
+  void OnWindowRemovedFromRootWindow(Window* window, Window* new_root);
 
   // Called when a window becomes invisible, either by being removed
   // from root window hierarchy, via SetVisible(false) or being destroyed.
@@ -304,6 +307,7 @@
 
   // Overridden from aura::client::CaptureDelegate:
   virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE;
+  virtual void OnOtherRootGotCapture() OVERRIDE;
   virtual void SetNativeCapture() OVERRIDE;
   virtual void ReleaseNativeCapture() OVERRIDE;
 
@@ -312,7 +316,7 @@
 
   // Overridden from ui::GestureEventHelper.
   virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
-  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchPostponedGestureEvent(ui::GestureEvent* event) OVERRIDE;
   virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
   // Overridden from ui::LayerAnimationObserver:
@@ -349,9 +353,6 @@
   void DispatchMouseEventRepost(ui::MouseEvent* event);
   bool DispatchMouseEventToTarget(ui::MouseEvent* event, Window* target);
   bool DispatchTouchEventImpl(ui::TouchEvent* event);
-  // Reposts the gesture event to the Window which is a target for the event
-  // passed in.
-  bool DispatchGestureEventRepost(ui::GestureEvent* event);
   void DispatchHeldEvents();
 
   // Posts a task to send synthesized mouse move event if there
diff --git a/ui/aura/root_window_host_ozone.cc b/ui/aura/root_window_host_ozone.cc
index 3af8289..dbdd762 100644
--- a/ui/aura/root_window_host_ozone.cc
+++ b/ui/aura/root_window_host_ozone.cc
@@ -13,8 +13,8 @@
    : delegate_(NULL),
       widget_(0),
       bounds_(bounds),
-      factory_(new ui::EventFactoryOzone()) {
-  factory_->CreateStartupEventConverters();
+      factory_(ui::EventFactoryOzone::GetInstance()) {
+  factory_->StartProcessingEvents();
   gfx::SurfaceFactoryOzone* surface_factory =
       gfx::SurfaceFactoryOzone::GetInstance();
   widget_ = surface_factory->GetAcceleratedWidget();
@@ -36,6 +36,9 @@
   } else if (event->IsKeyEvent()) {
     ui::KeyEvent* keyev = static_cast<ui::KeyEvent*>(ne);
     delegate_->OnHostKeyEvent(keyev);
+  } else if (event->IsMouseEvent()) {
+    ui::MouseEvent* mouseev = static_cast<ui::MouseEvent*>(ne);
+    delegate_->OnHostMouseEvent(mouseev);
   }
   return true;
 }
diff --git a/ui/aura/root_window_unittest.cc b/ui/aura/root_window_unittest.cc
index 02966e8..1c9742d 100644
--- a/ui/aura/root_window_unittest.cc
+++ b/ui/aura/root_window_unittest.cc
@@ -966,7 +966,8 @@
       0);
   root_window()->RepostEvent(event);
   RunAllPendingInMessageLoop();
-  EXPECT_TRUE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") !=
+  // TODO(rbyers): Currently disabled - crbug.com/170987
+  EXPECT_FALSE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") !=
               std::string::npos);
   filter->events().clear();
 }
@@ -992,7 +993,7 @@
         EXPECT_NE(repost_target_, event->target());
         reposted_ = true;
         events().clear();
-        repost_target_->GetRootWindow()->RepostEvent(*event);
+        repost_target_->GetDispatcher()->RepostEvent(*event);
         // Ensure that the reposted gesture event above goes to the
         // repost_target_;
         repost_source_->GetRootWindow()->RemoveChild(repost_source_);
@@ -1019,7 +1020,9 @@
 // be received after the reposted gesture event.
 TEST_F(RootWindowTest, GestureRepostEventOrder) {
   // Expected events at the end for the repost_target window defined below.
-  const char kExpectedTargetEvents[] = "GESTURE_BEGIN GESTURE_TAP_DOWN "
+  const char kExpectedTargetEvents[] =
+    // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039.
+    // "GESTURE_BEGIN GESTURE_TAP_DOWN "
     "TOUCH_RELEASED TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
     " GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED "
     "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
@@ -1063,7 +1066,8 @@
 
   // We expect two tap down events. One from the repost and the other one from
   // the scroll sequence posted above.
-  EXPECT_EQ(tap_down_count, 2);
+  // TODO(rbyers): Currently disabled - crbug.com/170987
+  EXPECT_EQ(1, tap_down_count);
 
   EXPECT_EQ(kExpectedTargetEvents,
             EventTypesToString(repost_event_recorder->events()));
@@ -1179,5 +1183,64 @@
   EXPECT_TRUE(has_valid_root);
 }
 
+namespace {
+
+// See description above DontResetHeldEvent for details.
+class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {
+ public:
+  explicit DontResetHeldEventWindowDelegate(aura::Window* root)
+      : root_(root),
+        mouse_event_count_(0) {}
+  virtual ~DontResetHeldEventWindowDelegate() {}
+
+  int mouse_event_count() const { return mouse_event_count_; }
+
+  // TestWindowDelegate:
+  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+    if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
+        mouse_event_count_++ == 0) {
+      ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
+                                 gfx::Point(10, 10), gfx::Point(10, 10),
+                                 ui::EF_SHIFT_DOWN);
+      root_->GetDispatcher()->RepostEvent(mouse_event);
+    }
+  }
+
+ private:
+  Window* root_;
+  int mouse_event_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate);
+};
+
+}  // namespace
+
+// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
+// dispatching. This is done by using DontResetHeldEventWindowDelegate, which
+// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
+// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
+// schedule another reposted event.
+TEST_F(RootWindowTest, DontResetHeldEvent) {
+  DontResetHeldEventWindowDelegate delegate(root_window());
+  scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
+  RootWindowHostDelegate* root_window_delegate =
+      static_cast<RootWindowHostDelegate*>(root_window()->GetDispatcher());
+  w1->SetBounds(gfx::Rect(0, 0, 40, 40));
+  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+                         gfx::Point(10, 10), gfx::Point(10, 10),
+                         ui::EF_SHIFT_DOWN);
+  root_window()->GetDispatcher()->RepostEvent(pressed);
+  ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED,
+                          gfx::Point(10, 10), gfx::Point(10, 10), 0);
+  // Invoke OnHostMouseEvent() to flush event scheduled by way of RepostEvent().
+  root_window_delegate->OnHostMouseEvent(&pressed2);
+  // Delegate should have seen reposted event (identified by way of
+  // EF_SHIFT_DOWN). Invoke OnHostMouseEvent() to flush the second
+  // RepostedEvent().
+  EXPECT_EQ(1, delegate.mouse_event_count());
+  root_window_delegate->OnHostMouseEvent(&pressed2);
+  EXPECT_EQ(2, delegate.mouse_event_count());
+}
+
 }  // namespace aura
 
diff --git a/ui/aura/test/aura_test_base.cc b/ui/aura/test/aura_test_base.cc
index 09e48b5..d5263e4 100644
--- a/ui/aura/test/aura_test_base.cc
+++ b/ui/aura/test/aura_test_base.cc
@@ -4,9 +4,10 @@
 
 #include "ui/aura/test/aura_test_base.h"
 
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/test/aura_test_helper.h"
 #include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/window.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/events/gestures/gesture_configuration.h"
 
@@ -35,6 +36,7 @@
   // testing.
   ui::GestureConfiguration::set_long_press_time_in_seconds(1.0);
   ui::GestureConfiguration::set_semi_long_press_time_in_seconds(0.4);
+  ui::GestureConfiguration::set_show_press_delay_in_ms(5);
   ui::GestureConfiguration::set_max_distance_for_two_finger_tap_in_pixels(300);
   ui::GestureConfiguration::set_max_seconds_between_double_click(0.7);
   ui::GestureConfiguration::
@@ -99,18 +101,18 @@
   window->set_id(id);
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_TEXTURED);
-  window->SetDefaultParentByRootWindow(root_window(), gfx::Rect());
+  aura::client::ParentWindowWithContext(window, root_window(), gfx::Rect());
   parent->AddTransientChild(window);
   return window;
 }
 
-void AuraTestBase::SetDefaultParentByPrimaryRootWindow(aura::Window* window) {
-  window->SetDefaultParentByRootWindow(root_window(), gfx::Rect());
-}
-
 void AuraTestBase::RunAllPendingInMessageLoop() {
   helper_->RunAllPendingInMessageLoop();
 }
 
+void AuraTestBase::ParentWindow(Window* window) {
+  client::ParentWindowWithContext(window, root_window(), gfx::Rect());
+}
+
 }  // namespace test
 }  // namespace aura
diff --git a/ui/aura/test/aura_test_base.h b/ui/aura/test/aura_test_base.h
index 791b955..fd6d29e 100644
--- a/ui/aura/test/aura_test_base.h
+++ b/ui/aura/test/aura_test_base.h
@@ -35,13 +35,13 @@
   // Creates a transient window that is transient to |parent|.
   aura::Window* CreateTransientChild(int id, aura::Window* parent);
 
-  // Attach |window| to the current shell's root window.
-  void SetDefaultParentByPrimaryRootWindow(aura::Window* window);
-
  protected:
   void RunAllPendingInMessageLoop();
 
+  void ParentWindow(Window* window);
+
   RootWindow* root_window() { return helper_->root_window(); }
+  TestScreen* test_screen() { return helper_->test_screen(); }
 
  private:
   bool setup_called_;
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc
index 36274c7..4d2e6a2 100644
--- a/ui/aura/test/aura_test_helper.cc
+++ b/ui/aura/test/aura_test_helper.cc
@@ -16,11 +16,13 @@
 #include "ui/aura/test/env_test_helper.h"
 #include "ui/aura/test/test_focus_client.h"
 #include "ui/aura/test/test_screen.h"
-#include "ui/aura/test/test_stacking_client.h"
+#include "ui/aura/test/test_window_tree_client.h"
 #include "ui/base/ime/dummy_input_method.h"
+#include "ui/base/ime/input_method_initializer.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/gfx/screen.h"
 
 #if defined(USE_X11)
@@ -65,7 +67,7 @@
 
   // The ContextFactory must exist before any Compositors are created.
   bool allow_test_contexts = true;
-  ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
+  ui::InitializeContextFactoryForTests(allow_test_contexts);
 
   Env::CreateInstance();
   // Unit tests generally don't want to query the system, rather use the state
@@ -73,13 +75,15 @@
   EnvTestHelper(Env::GetInstance()).SetInputStateLookup(
       scoped_ptr<InputStateLookup>());
 
+  ui::InitializeInputMethodForTesting();
+
   test_screen_.reset(TestScreen::Create());
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_.get());
   root_window_.reset(test_screen_->CreateRootWindowForPrimaryDisplay());
 
   focus_client_.reset(new TestFocusClient);
   client::SetFocusClient(root_window_.get(), focus_client_.get());
-  stacking_client_.reset(new TestStackingClient(root_window_.get()));
+  stacking_client_.reset(new TestWindowTreeClient(root_window_.get()));
   activation_client_.reset(
       new client::DefaultActivationClient(root_window_.get()));
   capture_client_.reset(new client::DefaultCaptureClient(root_window_.get()));
@@ -109,7 +113,11 @@
   ui::ResetXCursorCache();
 #endif
 
+  ui::ShutdownInputMethodForTesting();
+
   Env::DeleteInstance();
+
+  ui::TerminateContextFactoryForTests();
 }
 
 void AuraTestHelper::RunAllPendingInMessageLoop() {
diff --git a/ui/aura/test/aura_test_helper.h b/ui/aura/test/aura_test_helper.h
index 02f9c31..27cd442 100644
--- a/ui/aura/test/aura_test_helper.h
+++ b/ui/aura/test/aura_test_helper.h
@@ -30,7 +30,7 @@
 class FocusClient;
 }
 namespace test {
-class TestStackingClient;
+class TestWindowTreeClient;
 
 // A helper class owned by tests that does common initialization required for
 // Aura use. This class creates a root window with clients and other objects
@@ -60,7 +60,7 @@
   bool teardown_called_;
   bool owns_root_window_;
   scoped_ptr<RootWindow> root_window_;
-  scoped_ptr<TestStackingClient> stacking_client_;
+  scoped_ptr<TestWindowTreeClient> stacking_client_;
   scoped_ptr<client::DefaultActivationClient> activation_client_;
   scoped_ptr<client::DefaultCaptureClient> capture_client_;
   scoped_ptr<ui::InputMethod> test_input_method_;
diff --git a/ui/aura/test/event_generator.cc b/ui/aura/test/event_generator.cc
index ac46df1..dea96a5 100644
--- a/ui/aura/test/event_generator.cc
+++ b/ui/aura/test/event_generator.cc
@@ -31,13 +31,13 @@
 
 class DefaultEventGeneratorDelegate : public EventGeneratorDelegate {
  public:
-  explicit DefaultEventGeneratorDelegate(RootWindow* root_window)
+  explicit DefaultEventGeneratorDelegate(Window* root_window)
       : root_window_(root_window) {}
   virtual ~DefaultEventGeneratorDelegate() {}
 
   // EventGeneratorDelegate overrides:
   virtual RootWindow* GetRootWindowAt(const gfx::Point& point) const OVERRIDE {
-    return root_window_;
+    return root_window_->GetDispatcher();
   }
 
   virtual client::ScreenPositionClient* GetScreenPositionClient(
@@ -46,7 +46,7 @@
   }
 
  private:
-  RootWindow* root_window_;
+  Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultEventGeneratorDelegate);
 };
@@ -63,8 +63,9 @@
  public:
   TestTouchEvent(ui::EventType type,
                  const gfx::Point& root_location,
+                 int touch_id,
                  int flags)
-      : TouchEvent(type, root_location, flags, 0, ui::EventTimeForNow(),
+      : TouchEvent(type, root_location, flags, touch_id, ui::EventTimeForNow(),
                    1.0f, 1.0f, 1.0f, 1.0f) {
   }
 
@@ -76,7 +77,7 @@
 
 }  // namespace
 
-EventGenerator::EventGenerator(RootWindow* root_window)
+EventGenerator::EventGenerator(Window* root_window)
     : delegate_(new DefaultEventGeneratorDelegate(root_window)),
       current_root_window_(delegate_->GetRootWindowAt(current_location_)),
       flags_(0),
@@ -84,7 +85,7 @@
       async_(false) {
 }
 
-EventGenerator::EventGenerator(RootWindow* root_window, const gfx::Point& point)
+EventGenerator::EventGenerator(Window* root_window, const gfx::Point& point)
     : delegate_(new DefaultEventGeneratorDelegate(root_window)),
       current_location_(point),
       current_root_window_(delegate_->GetRootWindowAt(current_location_)),
@@ -93,7 +94,7 @@
       async_(false) {
 }
 
-EventGenerator::EventGenerator(RootWindow* root_window, Window* window)
+EventGenerator::EventGenerator(Window* root_window, Window* window)
     : delegate_(new DefaultEventGeneratorDelegate(root_window)),
       current_location_(CenterOfWindow(window)),
       current_root_window_(delegate_->GetRootWindowAt(current_location_)),
@@ -201,15 +202,23 @@
 }
 
 void EventGenerator::PressTouch() {
+  PressTouchId(0);
+}
+
+void EventGenerator::PressTouchId(int touch_id) {
   TestTouchEvent touchev(
-      ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), flags_);
+      ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), touch_id, flags_);
   Dispatch(&touchev);
 }
 
 void EventGenerator::MoveTouch(const gfx::Point& point) {
+  MoveTouchId(point, 0);
+}
+
+void EventGenerator::MoveTouchId(const gfx::Point& point, int touch_id) {
   current_location_ = point;
   TestTouchEvent touchev(
-      ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), flags_);
+      ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), touch_id, flags_);
   Dispatch(&touchev);
 
   if (!grab_)
@@ -217,8 +226,12 @@
 }
 
 void EventGenerator::ReleaseTouch() {
+  ReleaseTouchId(0);
+}
+
+void EventGenerator::ReleaseTouchId(int touch_id) {
   TestTouchEvent touchev(
-      ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), flags_);
+      ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), touch_id, flags_);
   Dispatch(&touchev);
 }
 
@@ -299,12 +312,26 @@
 }
 
 void EventGenerator::GestureMultiFingerScroll(int count,
-                                              const gfx::Point* start,
+                                              const gfx::Point start[],
                                               int event_separation_time_ms,
                                               int steps,
                                               int move_x,
                                               int move_y) {
   const int kMaxTouchPoints = 10;
+  int delays[kMaxTouchPoints] = { 0 };
+  GestureMultiFingerScrollWithDelays(
+      count, start, delays, event_separation_time_ms, steps, move_x, move_y);
+}
+
+void EventGenerator::GestureMultiFingerScrollWithDelays(
+    int count,
+    const gfx::Point start[],
+    const int delay_adding_finger_ms[],
+    int event_separation_time_ms,
+    int steps,
+    int move_x,
+    int move_y) {
+  const int kMaxTouchPoints = 10;
   gfx::Point points[kMaxTouchPoints];
   CHECK_LE(count, kMaxTouchPoints);
   CHECK_GT(steps, 0);
@@ -312,26 +339,48 @@
   int delta_x = move_x / steps;
   int delta_y = move_y / steps;
 
-  base::TimeDelta press_time = ui::EventTimeForNow();
   for (int i = 0; i < count; ++i) {
     points[i] = start[i];
-    ui::TouchEvent press(ui::ET_TOUCH_PRESSED, points[i], i, press_time);
-    Dispatch(&press);
   }
 
+  base::TimeDelta press_time_first = ui::EventTimeForNow();
+  base::TimeDelta press_time[kMaxTouchPoints];
+  bool pressed[kMaxTouchPoints];
+  for (int i = 0; i < count; ++i) {
+    pressed[i] = false;
+    press_time[i] = press_time_first +
+        base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]);
+  }
+
+  int last_id = 0;
   for (int step = 0; step < steps; ++step) {
-    base::TimeDelta move_time = press_time +
+    base::TimeDelta move_time = press_time_first +
         base::TimeDelta::FromMilliseconds(event_separation_time_ms * step);
+
+    while (last_id < count &&
+           !pressed[last_id] &&
+           move_time >= press_time[last_id]) {
+      ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
+                           points[last_id],
+                           last_id,
+                           press_time[last_id]);
+      Dispatch(&press);
+      pressed[last_id] = true;
+      last_id++;
+    }
+
     for (int i = 0; i < count; ++i) {
       points[i].Offset(delta_x, delta_y);
+      if (i >= last_id)
+        continue;
       ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time);
       Dispatch(&move);
     }
   }
 
-  base::TimeDelta release_time = press_time +
+  base::TimeDelta release_time = press_time_first +
       base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps);
-  for (int i = 0; i < count; ++i) {
+  for (int i = 0; i < last_id; ++i) {
     ui::TouchEvent release(
         ui::ET_TOUCH_RELEASED, points[i], i, release_time);
     Dispatch(&release);
diff --git a/ui/aura/test/event_generator.h b/ui/aura/test/event_generator.h
index 5f93c5c..ee9ebda 100644
--- a/ui/aura/test/event_generator.h
+++ b/ui/aura/test/event_generator.h
@@ -87,7 +87,7 @@
  public:
   // Creates an EventGenerator with the mouse/touch location (0,0),
   // which uses the |root_window|'s coordinates.
-  explicit EventGenerator(RootWindow* root_window);
+  explicit EventGenerator(Window* root_window);
 
   // Create an EventGenerator with EventGeneratorDelegate,
   // which uses the coordinates used by |delegate|.
@@ -95,11 +95,11 @@
 
   // Creates an EventGenerator with the mouse/touch location
   // at |initial_location|, which uses the |root_window|'s coordinates.
-  EventGenerator(RootWindow* root_window, const gfx::Point& initial_location);
+  EventGenerator(Window* root_window, const gfx::Point& initial_location);
 
   // Creates an EventGenerator with the mouse/touch location
   // centered over |window|, which uses the |root_window|'s coordinates.
-  EventGenerator(RootWindow* root_window, Window* window);
+  EventGenerator(Window* root_window, Window* window);
 
   virtual ~EventGenerator();
 
@@ -183,12 +183,21 @@
   // Generates a touch press event.
   void PressTouch();
 
+  // Generates a touch press event with |touch_id|.
+  void PressTouchId(int touch_id);
+
   // Generates a ET_TOUCH_MOVED event to |point|.
   void MoveTouch(const gfx::Point& point);
 
+  // Generates a ET_TOUCH_MOVED event to |point| with |touch_id|.
+  void MoveTouchId(const gfx::Point& point, int touch_id);
+
   // Generates a touch release event.
   void ReleaseTouch();
 
+  // Generates a touch release event with |touch_id|.
+  void ReleaseTouchId(int touch_id);
+
   // Generates press, move and release event to move touch
   // to be the given |point|.
   void PressMoveAndReleaseTouchTo(const gfx::Point& point);
@@ -241,14 +250,34 @@
   // of all the touch points. |steps| and |event_separation_time_ms| are
   // relevant when testing velocity/fling/swipe, otherwise these can be any
   // non-zero value. |delta_x| and |delta_y| are the amount that each finger
-  // should be moved.
+  // should be moved. Internally calls GestureMultiFingerScrollWithDelays
+  // with zeros as |delay_adding_finger_ms| forcing all touch down events to be
+  // immediate.
   void GestureMultiFingerScroll(int count,
-                                const gfx::Point* start,
+                                const gfx::Point start[],
                                 int event_separation_time_ms,
                                 int steps,
                                 int move_x,
                                 int move_y);
 
+  // Generates press, move, release touch-events to generate a sequence of
+  // multi-finger scroll events. |count| specifies the number of touch-points
+  // that should generate the scroll events. |start| are the starting positions
+  // of all the touch points. |delay_adding_finger_ms| are delays in ms from the
+  // starting time till touching down of each finger. |delay_adding_finger_ms|
+  // is useful when testing complex gestures that start with 1 or 2 fingers and
+  // add fingers with a delay. |steps| and |event_separation_time_ms| are
+  // relevant when testing velocity/fling/swipe, otherwise these can be any
+  // non-zero value. |delta_x| and |delta_y| are the amount that each finger
+  // should be moved.
+  void GestureMultiFingerScrollWithDelays(int count,
+                                          const gfx::Point start[],
+                                          const int delay_adding_finger_ms[],
+                                          int event_separation_time_ms,
+                                          int steps,
+                                          int move_x,
+                                          int move_y);
+
   // Generates scroll sequences of a FlingCancel, Scrolls, FlingStart, with
   // constant deltas to |x_offset| and |y_offset| in |steps|.
   void ScrollSequence(const gfx::Point& start,
diff --git a/ui/aura/test/test_stacking_client.cc b/ui/aura/test/test_stacking_client.cc
deleted file mode 100644
index 746ad6c..0000000
--- a/ui/aura/test/test_stacking_client.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/test/test_stacking_client.h"
-
-#include "ui/aura/root_window.h"
-
-namespace aura {
-namespace test {
-
-TestStackingClient::TestStackingClient(RootWindow* root_window)
-    : root_window_(root_window) {
-  client::SetStackingClient(root_window_, this);
-}
-
-TestStackingClient::~TestStackingClient() {
-  client::SetStackingClient(root_window_, NULL);
-}
-
-Window* TestStackingClient::GetDefaultParent(Window* context,
-                                             Window* window,
-                                             const gfx::Rect& bounds) {
-  return root_window_;
-}
-
-}  // namespace test
-}  // namespace aura
diff --git a/ui/aura/test/test_stacking_client.h b/ui/aura/test/test_stacking_client.h
deleted file mode 100644
index 7c9747b..0000000
--- a/ui/aura/test/test_stacking_client.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 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_AURA_TEST_TEST_STACKING_CLIENT_H_
-#define UI_AURA_TEST_TEST_STACKING_CLIENT_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/client/stacking_client.h"
-
-namespace aura {
-class RootWindow;
-namespace test {
-
-class TestStackingClient : public client::StackingClient {
- public:
-  explicit TestStackingClient(RootWindow* root_window);
-  virtual ~TestStackingClient();
-
-  // Overridden from client::StackingClient:
-  virtual Window* GetDefaultParent(Window* context,
-                                   Window* window,
-                                   const gfx::Rect& bounds) OVERRIDE;
-
- private:
-  RootWindow* root_window_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestStackingClient);
-};
-
-}  // namespace test
-}  // namespace aura
-
-#endif  // UI_AURA_TEST_TEST_STACKING_CLIENT_H_
diff --git a/ui/aura/test/test_window_tree_client.cc b/ui/aura/test/test_window_tree_client.cc
new file mode 100644
index 0000000..41faa9d
--- /dev/null
+++ b/ui/aura/test/test_window_tree_client.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/test/test_window_tree_client.h"
+
+#include "ui/aura/window.h"
+
+namespace aura {
+namespace test {
+
+TestWindowTreeClient::TestWindowTreeClient(Window* root_window)
+    : root_window_(root_window) {
+  client::SetWindowTreeClient(root_window_, this);
+}
+
+TestWindowTreeClient::~TestWindowTreeClient() {
+  client::SetWindowTreeClient(root_window_, NULL);
+}
+
+Window* TestWindowTreeClient::GetDefaultParent(Window* context,
+                                               Window* window,
+                                               const gfx::Rect& bounds) {
+  return root_window_;
+}
+
+}  // namespace test
+}  // namespace aura
diff --git a/ui/aura/test/test_window_tree_client.h b/ui/aura/test/test_window_tree_client.h
new file mode 100644
index 0000000..7b3c5ee
--- /dev/null
+++ b/ui/aura/test/test_window_tree_client.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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_AURA_TEST_TEST_WINDOW_TREE_CLIENT_H_
+#define UI_AURA_TEST_TEST_WINDOW_TREE_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/client/window_tree_client.h"
+
+namespace aura {
+namespace test {
+
+class TestWindowTreeClient : public client::WindowTreeClient {
+ public:
+  explicit TestWindowTreeClient(Window* root_window);
+  virtual ~TestWindowTreeClient();
+
+  // Overridden from client::WindowTreeClient:
+  virtual Window* GetDefaultParent(Window* context,
+                                   Window* window,
+                                   const gfx::Rect& bounds) OVERRIDE;
+ private:
+  Window* root_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient);
+};
+
+}  // namespace test
+}  // namespace aura
+
+#endif  // UI_AURA_TEST_TEST_WINDOW_TREE_CLIENT_H_
diff --git a/ui/aura/test/ui_controls_factory_aurawin.cc b/ui/aura/test/ui_controls_factory_aurawin.cc
index 48997fe..60a15c9 100644
--- a/ui/aura/test/ui_controls_factory_aurawin.cc
+++ b/ui/aura/test/ui_controls_factory_aurawin.cc
@@ -36,7 +36,7 @@
                             bool alt,
                             bool command) {
     DCHECK(!command);  // No command key on Aura
-    HWND window = native_window->GetRootWindow()->GetAcceleratedWidget();
+    HWND window = native_window->GetDispatcher()->GetAcceleratedWidget();
     return SendKeyPressImpl(
         window, key, control, shift, alt, base::Closure());
   }
@@ -48,7 +48,7 @@
                                           bool command,
                                           const base::Closure& task) {
     DCHECK(!command);  // No command key on Aura
-    HWND window = native_window->GetRootWindow()->GetAcceleratedWidget();
+    HWND window = native_window->GetDispatcher()->GetAcceleratedWidget();
     return SendKeyPressImpl(window, key, control, shift, alt, task);
   }
   virtual bool SendMouseMove(long x, long y) {
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index d761dae..bbb00b1 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -17,7 +17,6 @@
 #include "ui/aura/client/event_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/client/visibility_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/layout_manager.h"
@@ -35,7 +34,8 @@
 namespace aura {
 
 Window::Window(WindowDelegate* delegate)
-    : type_(client::WINDOW_TYPE_UNKNOWN),
+    : dispatcher_(NULL),
+      type_(client::WINDOW_TYPE_UNKNOWN),
       owned_by_parent_(true),
       delegate_(delegate),
       parent_(NULL),
@@ -64,9 +64,9 @@
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
 
   // Let the root know so that it can remove any references to us.
-  RootWindow* root_window = GetRootWindow();
-  if (root_window)
-    root_window->OnWindowDestroying(this);
+  WindowEventDispatcher* dispatcher = GetDispatcher();
+  if (dispatcher)
+    dispatcher->OnWindowDestroying(this);
 
   // Then destroy the children.
   RemoveOrDestroyChildren();
@@ -173,19 +173,27 @@
 
 void Window::SetTransparent(bool transparent) {
   transparent_ = transparent;
-  if (layer())
-    layer_->SetFillsBoundsOpaquely(!transparent_);
 }
 
-RootWindow* Window::GetRootWindow() {
-  return const_cast<RootWindow*>(
+Window* Window::GetRootWindow() {
+  return const_cast<Window*>(
       static_cast<const Window*>(this)->GetRootWindow());
 }
 
-const RootWindow* Window::GetRootWindow() const {
+const Window* Window::GetRootWindow() const {
   return parent_ ? parent_->GetRootWindow() : NULL;
 }
 
+WindowEventDispatcher* Window::GetDispatcher() {
+  return const_cast<WindowEventDispatcher*>(const_cast<const Window*>(this)->
+      GetDispatcher());
+}
+
+const WindowEventDispatcher* Window::GetDispatcher() const {
+  const Window* root_window = GetRootWindow();
+  return root_window ? root_window->dispatcher_ : NULL;
+}
+
 void Window::Show() {
   SetVisible(true);
 }
@@ -220,7 +228,7 @@
 
 gfx::Rect Window::GetBoundsInScreen() const {
   gfx::Rect bounds(GetBoundsInRootWindow());
-  const RootWindow* root = GetRootWindow();
+  const Window* root = GetRootWindow();
   if (root) {
     aura::client::ScreenPositionClient* screen_position_client =
         aura::client::GetScreenPositionClient(root);
@@ -234,12 +242,12 @@
 }
 
 void Window::SetTransform(const gfx::Transform& transform) {
-  RootWindow* root_window = GetRootWindow();
-  bool contained_mouse = IsVisible() && root_window &&
-      ContainsPointInRoot(root_window->GetLastMouseLocationInRoot());
+  WindowEventDispatcher* dispatcher = GetDispatcher();
+  bool contained_mouse = IsVisible() && dispatcher &&
+      ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
   layer()->SetTransform(transform);
-  if (root_window)
-    root_window->OnWindowTransformed(this, contained_mouse);
+  if (dispatcher)
+    dispatcher->OnWindowTransformed(this, contained_mouse);
 }
 
 void Window::SetLayoutManager(LayoutManager* layout_manager) {
@@ -265,7 +273,7 @@
 
 void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen,
                                const gfx::Display& dst_display) {
-  RootWindow* root = GetRootWindow();
+  Window* root = GetRootWindow();
   if (root) {
     gfx::Point origin = new_bounds_in_screen.origin();
     aura::client::ScreenPositionClient* screen_position_client =
@@ -291,19 +299,6 @@
   }
 }
 
-void Window::SetDefaultParentByRootWindow(RootWindow* root_window,
-                                          const gfx::Rect& bounds_in_screen) {
-  DCHECK(root_window);
-
-  // Stacking clients are mandatory on RootWindow objects.
-  client::StackingClient* client = client::GetStackingClient(root_window);
-  DCHECK(client);
-
-  aura::Window* default_parent = client->GetDefaultParent(
-      root_window, this, bounds_in_screen);
-  default_parent->AddChild(this);
-}
-
 void Window::StackChildAtTop(Window* child) {
   if (children_.size() <= 1 || child == children_.back())
     return;  // In the front already.
@@ -332,7 +327,7 @@
   params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
   NotifyWindowHierarchyChange(params);
 
-  RootWindow* old_root = child->GetRootWindow();
+  Window* old_root = child->GetRootWindow();
 
   DCHECK(std::find(children_.begin(), children_.end(), child) ==
       children_.end());
@@ -348,9 +343,9 @@
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowAdded(child));
   child->OnParentChanged();
 
-  RootWindow* root_window = GetRootWindow();
+  Window* root_window = GetRootWindow();
   if (root_window && old_root != root_window) {
-    root_window->OnWindowAddedToRootWindow(child);
+    root_window->GetDispatcher()->OnWindowAddedToRootWindow(child);
     child->NotifyAddedToRootWindow();
   }
 
@@ -426,11 +421,11 @@
     return;
   if (source->GetRootWindow() != target->GetRootWindow()) {
     client::ScreenPositionClient* source_client =
-        GetScreenPositionClient(source->GetRootWindow());
+        client::GetScreenPositionClient(source->GetRootWindow());
     source_client->ConvertPointToScreen(source, point);
 
     client::ScreenPositionClient* target_client =
-        GetScreenPositionClient(target->GetRootWindow());
+        client::GetScreenPositionClient(target->GetRootWindow());
     target_client->ConvertPointFromScreen(target, point);
   } else {
     ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point);
@@ -438,11 +433,11 @@
 }
 
 void Window::MoveCursorTo(const gfx::Point& point_in_window) {
-  RootWindow* root_window = GetRootWindow();
+  Window* root_window = GetRootWindow();
   DCHECK(root_window);
   gfx::Point point_in_root(point_in_window);
   ConvertPointToTarget(this, root_window, &point_in_root);
-  root_window->MoveCursorTo(point_in_root);
+  root_window->GetDispatcher()->MoveCursorTo(point_in_root);
 }
 
 gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const {
@@ -568,23 +563,25 @@
   if (!IsVisible())
     return;
 
-  RootWindow* root_window = GetRootWindow();
+  Window* root_window = GetRootWindow();
   if (!root_window)
     return;
   client::GetCaptureClient(root_window)->SetCapture(this);
 }
 
 void Window::ReleaseCapture() {
-  RootWindow* root_window = GetRootWindow();
+  Window* root_window = GetRootWindow();
   if (!root_window)
     return;
   client::GetCaptureClient(root_window)->ReleaseCapture(this);
 }
 
 bool Window::HasCapture() {
-  RootWindow* root_window = GetRootWindow();
-  return root_window &&
-      client::GetCaptureClient(root_window)->GetCaptureWindow() == this;
+  Window* root_window = GetRootWindow();
+  if (!root_window)
+    return false;
+  client::CaptureClient* capture_client = client::GetCaptureClient(root_window);
+  return capture_client && capture_client->GetCaptureWindow() == this;
 }
 
 void Window::SuppressPaint() {
@@ -708,9 +705,9 @@
   FOR_EACH_OBSERVER(WindowObserver, observers_,
                     OnWindowVisibilityChanging(this, visible));
 
-  RootWindow* root_window = GetRootWindow();
-  if (root_window)
-    root_window->DispatchMouseExitToHidingWindow(this);
+  WindowEventDispatcher* dispatcher = GetDispatcher();
+  if (dispatcher)
+    dispatcher->DispatchMouseExitToHidingWindow(this);
 
   client::VisibilityClient* visibility_client =
       client::GetVisibilityClient(this);
@@ -728,8 +725,8 @@
 
   NotifyWindowVisibilityChanged(this, visible);
 
-  if (root_window)
-    root_window->OnWindowVisibilityChanged(this, visible);
+  if (dispatcher)
+    dispatcher->OnWindowVisibilityChanged(this, visible);
 }
 
 void Window::SchedulePaint() {
@@ -796,10 +793,11 @@
   if (layout_manager_)
     layout_manager_->OnWillRemoveWindowFromLayout(child);
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child));
-  RootWindow* root_window = child->GetRootWindow();
-  RootWindow* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL;
+  Window* root_window = child->GetRootWindow();
+  Window* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL;
   if (root_window && root_window != new_root_window) {
-    root_window->OnWindowRemovedFromRootWindow(child, new_root_window);
+    root_window->GetDispatcher()->OnWindowRemovedFromRootWindow(
+        child, new_root_window);
     child->NotifyRemovingFromRootWindow();
   }
   child->parent_ = NULL;
@@ -1098,9 +1096,9 @@
   FOR_EACH_OBSERVER(WindowObserver,
                     observers_,
                     OnWindowBoundsChanged(this, old_bounds, bounds()));
-  RootWindow* root_window = GetRootWindow();
-  if (root_window)
-    root_window->OnWindowBoundsChanged(this, contained_mouse);
+  WindowEventDispatcher* dispatcher = GetDispatcher();
+  if (dispatcher)
+    dispatcher->OnWindowBoundsChanged(this, contained_mouse);
 }
 
 void Window::OnPaintLayer(gfx::Canvas* canvas) {
@@ -1148,9 +1146,9 @@
 bool Window::ContainsMouse() {
   bool contains_mouse = false;
   if (IsVisible()) {
-    RootWindow* root_window = GetRootWindow();
-    contains_mouse = root_window &&
-        ContainsPointInRoot(root_window->GetLastMouseLocationInRoot());
+    WindowEventDispatcher* dispatcher = GetDispatcher();
+    contains_mouse = dispatcher &&
+        ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
   }
   return contains_mouse;
 }
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 18c50e3..e11f83a 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -46,6 +46,9 @@
 class WindowDelegate;
 class WindowObserver;
 
+// TODO(beng): remove once RootWindow is renamed.
+typedef RootWindow WindowEventDispatcher;
+
 // Defined in window_property.h (which we do not include)
 template<typename T>
 struct WindowProperty;
@@ -108,10 +111,19 @@
   Window* parent() { return parent_; }
   const Window* parent() const { return parent_; }
 
-  // Returns the RootWindow that contains this Window or NULL if the Window is
-  // not contained by a RootWindow.
-  virtual RootWindow* GetRootWindow();
-  virtual const RootWindow* GetRootWindow() const;
+  // Returns the root Window that contains this Window. The root Window is
+  // defined as the Window that has a dispatcher. These functions return NULL if
+  // the Window is contained in a hierarchy that does not have a dispatcher at
+  // its root.
+  virtual Window* GetRootWindow();
+  virtual const Window* GetRootWindow() const;
+
+  WindowEventDispatcher* GetDispatcher();
+  const WindowEventDispatcher* GetDispatcher() const;
+  void set_dispatcher(WindowEventDispatcher* dispatcher) {
+    dispatcher_ = dispatcher;
+  }
+  bool HasDispatcher() const { return !!dispatcher_; }
 
   // The Window does not own this object.
   void set_user_data(void* user_data) { user_data_ = user_data; }
@@ -159,13 +171,6 @@
   // Marks the a portion of window as needing to be painted.
   void SchedulePaintInRect(const gfx::Rect& rect);
 
-  // Places this window per |root_window|'s stacking client. The final location
-  // may be a RootWindow other than the one passed in. |root_window| may not be
-  // NULL. |bounds_in_screen| may be empty; it is more optional context that
-  // may, but isn't necessarily used.
-  void SetDefaultParentByRootWindow(RootWindow* root_window,
-                                    const gfx::Rect& bounds_in_screen);
-
   // Stacks the specified child of this Window at the front of the z-order.
   void StackChildAtTop(Window* child);
 
@@ -482,6 +487,8 @@
   // Returns true if the mouse is currently within our bounds.
   bool ContainsMouse();
 
+  WindowEventDispatcher* dispatcher_;
+
   client::WindowType type_;
 
   // True if the Window is owned by its parent - i.e. it will be deleted by its
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index 620130a..dfe8a9c 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -15,8 +15,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/client/visibility_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/layout_manager.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/root_window_host.h"
@@ -67,11 +67,6 @@
         set_max_separation_for_gesture_touches_in_pixels(max_separation_);
   }
 
-  // Adds |window| to |root_window_|, through the StackingClient.
-  void SetDefaultParentByPrimaryRootWindow(aura::Window* window) {
-    window->SetDefaultParentByRootWindow(root_window(), gfx::Rect());
-  }
-
  private:
   int max_separation_;
 
@@ -480,7 +475,7 @@
   w1.Init(ui::LAYER_TEXTURED);
   w1.SetBounds(gfx::Rect(10, 20, 50, 60));
   w1.Show();
-  SetDefaultParentByPrimaryRootWindow(&w1);
+  ParentWindow(&w1);
 
   // Points are in the Window's coordinates.
   EXPECT_TRUE(w1.HitTest(gfx::Point(1, 1)));
@@ -512,7 +507,7 @@
   w1.Init(ui::LAYER_NOT_DRAWN);
   w1.SetBounds(gfx::Rect(10, 20, 50, 60));
   w1.Show();
-  SetDefaultParentByPrimaryRootWindow(&w1);
+  ParentWindow(&w1);
 
   // Points inside the mask.
   EXPECT_TRUE(w1.HitTest(gfx::Point(5, 6)));  // top-left
@@ -2645,7 +2640,7 @@
   w1->Init(ui::LAYER_NOT_DRAWN);
   w1->AddObserver(&observer);
 
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindow(w1.get());
   EXPECT_EQ(1, observer.added_count());
   EXPECT_EQ(0, observer.removed_count());
 
@@ -2665,7 +2660,7 @@
   EXPECT_EQ(0, observer.added_count());
   EXPECT_EQ(0, observer.removed_count());
 
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindow(w1.get());
   EXPECT_EQ(1, observer.added_count());
   EXPECT_EQ(0, observer.removed_count());
 
@@ -2691,7 +2686,7 @@
   EXPECT_EQ(0, observer.added_count());
   EXPECT_EQ(0, observer.removed_count());
 
-  SetDefaultParentByPrimaryRootWindow(w1.get());
+  ParentWindow(w1.get());
   EXPECT_EQ(2, observer.added_count());
   EXPECT_EQ(0, observer.removed_count());
 
diff --git a/ui/base/DEPS b/ui/base/DEPS
index fc943f4..cda1db3 100644
--- a/ui/base/DEPS
+++ b/ui/base/DEPS
@@ -9,7 +9,4 @@
   "+third_party/skia",
   "+ui/events",
   "+ui/gfx",
-  "+ui/aura/root_window.h",  # TODO(beng): resolve crazy layering violation
-  "+ui/aura/window.h",  # TODO(beng): resolve crazy layering violation
-  "+ui/views/view.h",  # TODO(beng): resolve crazy layering violation
 ]
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index 22f75c1..34d4a83 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -97,10 +97,26 @@
 
   map_[format] = data;
   if (format == kPlainTextFormat) {
-    ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(
-        env, data.c_str());
-    DCHECK(str.obj() && !ClearException(env));
+    ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, data);
+    DCHECK(str.obj());
+
     Java_Clipboard_setText(env, clipboard_manager_.obj(), str.obj());
+  } else if (format == kHTMLFormat) {
+    // Android's API for storing HTML content on the clipboard requires a plain-
+    // text representation to be available as well. ScopedClipboardWriter has a
+    // stable order for setting clipboard data, ensuring that plain-text data
+    // is available first. Do not write to the clipboard when only HTML data is
+    // available, because otherwise others apps may not be able to paste it.
+    if (!ContainsKey(map_, kPlainTextFormat))
+      return;
+
+    ScopedJavaLocalRef<jstring> html = ConvertUTF8ToJavaString(env, data);
+    ScopedJavaLocalRef<jstring> text = ConvertUTF8ToJavaString(
+        env, map_[kPlainTextFormat].c_str());
+
+    DCHECK(html.obj() && text.obj());
+    Java_Clipboard_setHTMLText(
+        env, clipboard_manager_.obj(), html.obj(), text.obj());
   }
 }
 
diff --git a/ui/base/cocoa/focus_window_set.mm b/ui/base/cocoa/focus_window_set.mm
index e260627..fb62727 100644
--- a/ui/base/cocoa/focus_window_set.mm
+++ b/ui/base/cocoa/focus_window_set.mm
@@ -16,16 +16,22 @@
 // In addition, limit to the windows on the current
 // workspace. Otherwise we jump spaces haphazardly.
 //
-// NOTE: This is not perfect. If clicking the dock icon resulted in
-// switching spaces, isOnActiveSpace gives the answer for the PREVIOUS
-// space. This means that we actually raise the wrong space's
-// windows. This seems to still work okay.
+// NOTE: If this is called in the
+// applicationShouldHandleReopen:hasVisibleWindows: hook when clicking
+// the dock icon, and that caused OS X to begin switch spaces,
+// isOnActiveSpace gives the answer for the PREVIOUS space. This means
+// that we actually raise and focus the wrong space's windows, leaving
+// the new key window off-screen. To detect this, check if the key
+// window prior to calling is on an active space.
 //
-// However, if we decide to deminiaturize a window instead, that
-// results in switching spaces and switching back. Fortunately, this
-// only happens if, say, space 1 contains an app, space 2 contains a
+// Also, if we decide to deminiaturize a window during a space switch,
+// that can switch spaces and then switch back. Fortunately, this only
+// happens if, say, space 1 contains an app, space 2 contains a
 // miniaturized browser. We click the icon, OS X switches to space 1,
 // we deminiaturize the browser, and that triggers switching back.
+//
+// TODO(davidben): To limit those cases, consider preferentially
+// deminiaturizing a window on the current space.
 void FocusWindowSet(const std::set<NSWindow*>& windows,
                     bool allow_workspace_switch) {
   NSArray* ordered_windows = [NSApp orderedWindows];
diff --git a/ui/base/gtk/gtk_im_context_util.cc b/ui/base/gtk/gtk_im_context_util.cc
deleted file mode 100644
index dfd5f3f..0000000
--- a/ui/base/gtk/gtk_im_context_util.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_im_context_util.h"
-
-#include "base/basictypes.h"
-#include "base/i18n/char_iterator.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/ime/composition_text.h"
-
-namespace ui {
-
-void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
-                                          PangoAttrList* attrs,
-                                          int cursor_position,
-                                          CompositionText* composition) {
-  composition->Clear();
-  composition->text = UTF8ToUTF16(utf8_text);
-
-  if (composition->text.empty())
-    return;
-
-  // Gtk/Pango uses character index for cursor position and byte index for
-  // attribute range, but we use char16 offset for them. So we need to do
-  // conversion here.
-  std::vector<size_t> char16_offsets;
-  size_t length = composition->text.length();
-  base::i18n::UTF16CharIterator char_iterator(&composition->text);
-  do {
-    char16_offsets.push_back(char_iterator.array_pos());
-  } while (char_iterator.Advance());
-
-  // The text length in Unicode characters.
-  int char_length = static_cast<int>(char16_offsets.size());
-  // Make sure we can convert the value of |char_length| as well.
-  char16_offsets.push_back(length);
-
-  size_t cursor_offset =
-      char16_offsets[std::max(0, std::min(char_length, cursor_position))];
-
-  composition->selection = gfx::Range(cursor_offset);
-
-  if (attrs) {
-    int utf8_length = strlen(utf8_text);
-    PangoAttrIterator* iter = pango_attr_list_get_iterator(attrs);
-
-    // We only care about underline and background attributes and convert
-    // background attribute into selection if possible.
-    do {
-      gint start, end;
-      pango_attr_iterator_range(iter, &start, &end);
-
-      start = std::min(start, utf8_length);
-      end = std::min(end, utf8_length);
-      if (start >= end)
-        continue;
-
-      start = g_utf8_pointer_to_offset(utf8_text, utf8_text + start);
-      end = g_utf8_pointer_to_offset(utf8_text, utf8_text + end);
-
-      // Double check, in case |utf8_text| is not a valid utf-8 string.
-      start = std::min(start, char_length);
-      end = std::min(end, char_length);
-      if (start >= end)
-        continue;
-
-      PangoAttribute* background_attr =
-          pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
-      PangoAttribute* underline_attr =
-          pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
-
-      if (background_attr || underline_attr) {
-        // Use a black thin underline by default.
-        CompositionUnderline underline(
-            char16_offsets[start], char16_offsets[end], SK_ColorBLACK, false);
-
-        // Always use thick underline for a range with background color, which
-        // is usually the selection range.
-        if (background_attr) {
-          underline.thick = true;
-          // If the cursor is at start or end of this underline, then we treat
-          // it as the selection range as well, but make sure to set the cursor
-          // position to the selection end.
-          if (underline.start_offset == cursor_offset) {
-            composition->selection.set_start(underline.end_offset);
-            composition->selection.set_end(cursor_offset);
-          } else if (underline.end_offset == cursor_offset) {
-            composition->selection.set_start(underline.start_offset);
-            composition->selection.set_end(cursor_offset);
-          }
-        }
-        if (underline_attr) {
-          int type = reinterpret_cast<PangoAttrInt*>(underline_attr)->value;
-          if (type == PANGO_UNDERLINE_DOUBLE)
-            underline.thick = true;
-          else if (type == PANGO_UNDERLINE_ERROR)
-            underline.color = SK_ColorRED;
-        }
-        composition->underlines.push_back(underline);
-      }
-    } while (pango_attr_iterator_next(iter));
-    pango_attr_iterator_destroy(iter);
-  }
-
-  // Use a black thin underline by default.
-  if (composition->underlines.empty()) {
-    composition->underlines.push_back(
-        CompositionUnderline(0, length, SK_ColorBLACK, false));
-  }
-}
-
-}  // namespace ui
diff --git a/ui/base/gtk/gtk_im_context_util.h b/ui/base/gtk/gtk_im_context_util.h
deleted file mode 100644
index 456d6ca..0000000
--- a/ui/base/gtk/gtk_im_context_util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011 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_BASE_GTK_GTK_IM_CONTEXT_UTIL_H_
-#define UI_BASE_GTK_GTK_IM_CONTEXT_UTIL_H_
-
-#include <pango/pango-attributes.h>
-
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-struct CompositionText;
-
-// Extracts composition text information (text, underlines, selection range)
-// from given Gtk preedit data (utf-8 text, pango attributes, cursor position).
-UI_EXPORT void ExtractCompositionTextFromGtkPreedit(
-    const gchar* utf8_text,
-    PangoAttrList* attrs,
-    int cursor_position,
-    CompositionText* composition);
-
-}  // namespace ui
-
-#endif  // UI_BASE_GTK_GTK_IM_CONTEXT_UTIL_H_
diff --git a/ui/base/gtk/gtk_im_context_util_unittest.cc b/ui/base/gtk/gtk_im_context_util_unittest.cc
deleted file mode 100644
index 89dff22..0000000
--- a/ui/base/gtk/gtk_im_context_util_unittest.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2011 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/basictypes.h"
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/gtk/gtk_im_context_util.h"
-#include "ui/base/ime/composition_text.h"
-
-namespace {
-
-struct AttributeInfo {
-  int type;
-  int value;
-  int start_offset;
-  int end_offset;
-};
-
-struct Underline {
-  unsigned start_offset;
-  unsigned end_offset;
-  uint32 color;
-  bool thick;
-};
-
-struct TestData {
-  const char* text;
-  const AttributeInfo attrs[10];
-  const Underline underlines[10];
-};
-
-const TestData kTestData[] = {
-  // Normal case
-  { "One Two Three",
-    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_DOUBLE, 4, 7 },
-      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
-      { 0, 0, 0, 0 } },
-    { { 0, 3, SK_ColorBLACK, false },
-      { 4, 7, SK_ColorBLACK, true },
-      { 8, 13, SK_ColorBLACK, false },
-      { 0, 0, 0, false } }
-  },
-
-  // Offset overflow.
-  { "One Two Three",
-    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
-      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 20 },
-      { 0, 0, 0, 0 } },
-    { { 0, 3, SK_ColorBLACK, false },
-      { 4, 7, SK_ColorBLACK, true },
-      { 8, 13, SK_ColorBLACK, false },
-      { 0, 0, 0, false} }
-  },
-
-  // Error underline.
-  { "One Two Three",
-    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_ERROR, 4, 7 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
-      { 0, 0, 0, 0 } },
-    { { 0, 3, SK_ColorBLACK, false },
-      { 4, 7, SK_ColorRED, false },
-      { 8, 13, SK_ColorBLACK, false },
-      { 0, 0, 0, false} }
-  },
-
-  // Default underline.
-  { "One Two Three",
-    { { 0, 0, 0, 0 } },
-    { { 0, 13, SK_ColorBLACK, false },
-      { 0, 0, 0, false } }
-  },
-
-  // Unicode, including non-BMP characters: "123你好𠀀𠀁一丁 456"
-  { "123\xE4\xBD\xA0\xE5\xA5\xBD\xF0\xA0\x80\x80\xF0\xA0\x80\x81\xE4\xB8\x80"
-    "\xE4\xB8\x81 456",
-    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 3, 5 },
-      { PANGO_ATTR_BACKGROUND, 0, 5, 7 },
-      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 7, 13 },
-      { 0, 0, 0, 0 } },
-    { { 0, 3, SK_ColorBLACK, false },
-      { 3, 5, SK_ColorBLACK, false },
-      { 5, 9, SK_ColorBLACK, true },
-      { 9, 15, SK_ColorBLACK, false },
-      { 0, 0, 0, false } }
-  },
-};
-
-void CompareUnderline(const Underline& a,
-                      const ui::CompositionUnderline& b) {
-  EXPECT_EQ(a.start_offset, b.start_offset);
-  EXPECT_EQ(a.end_offset, b.end_offset);
-  EXPECT_EQ(a.color, b.color);
-  EXPECT_EQ(a.thick, b.thick);
-}
-
-class GtkIMContextWrapperTest : public testing::Test {
-};
-
-TEST(GtkIMContextUtilTest, ExtractCompositionText) {
-  for (size_t i = 0; i < arraysize(kTestData); ++i) {
-    const char* text = kTestData[i].text;
-    const AttributeInfo* attrs = kTestData[i].attrs;
-    SCOPED_TRACE(testing::Message() << "Testing:" << i
-                 << " text:" << text);
-
-    PangoAttrList* pango_attrs = pango_attr_list_new();
-    for (size_t a = 0; attrs[a].type; ++a) {
-      PangoAttribute* pango_attr = NULL;
-      switch (attrs[a].type) {
-        case PANGO_ATTR_UNDERLINE:
-          pango_attr = pango_attr_underline_new(
-              static_cast<PangoUnderline>(attrs[a].value));
-          break;
-        case PANGO_ATTR_BACKGROUND:
-          pango_attr = pango_attr_background_new(0, 0, 0);
-          break;
-        default:
-          NOTREACHED();
-      }
-      pango_attr->start_index =
-          g_utf8_offset_to_pointer(text, attrs[a].start_offset) - text;
-      pango_attr->end_index =
-          g_utf8_offset_to_pointer(text, attrs[a].end_offset) - text;
-      pango_attr_list_insert(pango_attrs, pango_attr);
-    }
-
-    ui::CompositionText result;
-    ui::ExtractCompositionTextFromGtkPreedit(text, pango_attrs, 0, &result);
-
-    const Underline* underlines = kTestData[i].underlines;
-    for (size_t u = 0; underlines[u].color &&
-         u < result.underlines.size(); ++u) {
-      SCOPED_TRACE(testing::Message() << "Underline:" << u);
-      CompareUnderline(underlines[u], result.underlines[u]);
-    }
-
-    pango_attr_list_unref(pango_attrs);
-  }
-}
-
-}  // namespace
diff --git a/ui/base/ime/composition_text_util_pango.cc b/ui/base/ime/composition_text_util_pango.cc
new file mode 100644
index 0000000..737380b
--- /dev/null
+++ b/ui/base/ime/composition_text_util_pango.cc
@@ -0,0 +1,116 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/composition_text_util_pango.h"
+
+#include <pango/pango-attributes.h>
+
+#include "base/basictypes.h"
+#include "base/i18n/char_iterator.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/composition_text.h"
+
+namespace ui {
+
+void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
+                                          PangoAttrList* attrs,
+                                          int cursor_position,
+                                          CompositionText* composition) {
+  composition->Clear();
+  composition->text = UTF8ToUTF16(utf8_text);
+
+  if (composition->text.empty())
+    return;
+
+  // Gtk/Pango uses character index for cursor position and byte index for
+  // attribute range, but we use char16 offset for them. So we need to do
+  // conversion here.
+  std::vector<size_t> char16_offsets;
+  size_t length = composition->text.length();
+  base::i18n::UTF16CharIterator char_iterator(&composition->text);
+  do {
+    char16_offsets.push_back(char_iterator.array_pos());
+  } while (char_iterator.Advance());
+
+  // The text length in Unicode characters.
+  int char_length = static_cast<int>(char16_offsets.size());
+  // Make sure we can convert the value of |char_length| as well.
+  char16_offsets.push_back(length);
+
+  size_t cursor_offset =
+      char16_offsets[std::max(0, std::min(char_length, cursor_position))];
+
+  composition->selection = gfx::Range(cursor_offset);
+
+  if (attrs) {
+    int utf8_length = strlen(utf8_text);
+    PangoAttrIterator* iter = pango_attr_list_get_iterator(attrs);
+
+    // We only care about underline and background attributes and convert
+    // background attribute into selection if possible.
+    do {
+      gint start, end;
+      pango_attr_iterator_range(iter, &start, &end);
+
+      start = std::min(start, utf8_length);
+      end = std::min(end, utf8_length);
+      if (start >= end)
+        continue;
+
+      start = g_utf8_pointer_to_offset(utf8_text, utf8_text + start);
+      end = g_utf8_pointer_to_offset(utf8_text, utf8_text + end);
+
+      // Double check, in case |utf8_text| is not a valid utf-8 string.
+      start = std::min(start, char_length);
+      end = std::min(end, char_length);
+      if (start >= end)
+        continue;
+
+      PangoAttribute* background_attr =
+          pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
+      PangoAttribute* underline_attr =
+          pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
+
+      if (background_attr || underline_attr) {
+        // Use a black thin underline by default.
+        CompositionUnderline underline(
+            char16_offsets[start], char16_offsets[end], SK_ColorBLACK, false);
+
+        // Always use thick underline for a range with background color, which
+        // is usually the selection range.
+        if (background_attr) {
+          underline.thick = true;
+          // If the cursor is at start or end of this underline, then we treat
+          // it as the selection range as well, but make sure to set the cursor
+          // position to the selection end.
+          if (underline.start_offset == cursor_offset) {
+            composition->selection.set_start(underline.end_offset);
+            composition->selection.set_end(cursor_offset);
+          } else if (underline.end_offset == cursor_offset) {
+            composition->selection.set_start(underline.start_offset);
+            composition->selection.set_end(cursor_offset);
+          }
+        }
+        if (underline_attr) {
+          int type = reinterpret_cast<PangoAttrInt*>(underline_attr)->value;
+          if (type == PANGO_UNDERLINE_DOUBLE)
+            underline.thick = true;
+          else if (type == PANGO_UNDERLINE_ERROR)
+            underline.color = SK_ColorRED;
+        }
+        composition->underlines.push_back(underline);
+      }
+    } while (pango_attr_iterator_next(iter));
+    pango_attr_iterator_destroy(iter);
+  }
+
+  // Use a black thin underline by default.
+  if (composition->underlines.empty()) {
+    composition->underlines.push_back(
+        CompositionUnderline(0, length, SK_ColorBLACK, false));
+  }
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/composition_text_util_pango.h b/ui/base/ime/composition_text_util_pango.h
new file mode 100644
index 0000000..4f5123f
--- /dev/null
+++ b/ui/base/ime/composition_text_util_pango.h
@@ -0,0 +1,27 @@
+// Copyright 2013 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_BASE_IME_COMPOSITION_TEXT_UTIL_PANGO_H_
+#define UI_BASE_IME_COMPOSITION_TEXT_UTIL_PANGO_H_
+
+#include "ui/base/glib/glib_integers.h"
+#include "ui/base/ui_export.h"
+
+typedef struct _PangoAttrList PangoAttrList;
+
+namespace ui {
+
+struct CompositionText;
+
+// Extracts composition text information (text, underlines, selection range)
+// from given Gtk preedit data (utf-8 text, pango attributes, cursor position).
+UI_EXPORT void ExtractCompositionTextFromGtkPreedit(
+    const gchar* utf8_text,
+    PangoAttrList* attrs,
+    int cursor_position,
+    CompositionText* composition);
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_COMPOSITION_TEXT_UTIL_PANGO_H_
diff --git a/ui/base/ime/composition_text_util_pango_unittest.cc b/ui/base/ime/composition_text_util_pango_unittest.cc
new file mode 100644
index 0000000..957adf1
--- /dev/null
+++ b/ui/base/ime/composition_text_util_pango_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/composition_text_util_pango.h"
+
+#include <pango/pango-attributes.h>
+
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/composition_text.h"
+
+namespace {
+
+struct AttributeInfo {
+  int type;
+  int value;
+  int start_offset;
+  int end_offset;
+};
+
+struct Underline {
+  unsigned start_offset;
+  unsigned end_offset;
+  uint32 color;
+  bool thick;
+};
+
+struct TestData {
+  const char* text;
+  const AttributeInfo attrs[10];
+  const Underline underlines[10];
+};
+
+const TestData kTestData[] = {
+  // Normal case
+  { "One Two Three",
+    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_DOUBLE, 4, 7 },
+      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
+      { 0, 0, 0, 0 } },
+    { { 0, 3, SK_ColorBLACK, false },
+      { 4, 7, SK_ColorBLACK, true },
+      { 8, 13, SK_ColorBLACK, false },
+      { 0, 0, 0, false } }
+  },
+
+  // Offset overflow.
+  { "One Two Three",
+    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
+      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 20 },
+      { 0, 0, 0, 0 } },
+    { { 0, 3, SK_ColorBLACK, false },
+      { 4, 7, SK_ColorBLACK, true },
+      { 8, 13, SK_ColorBLACK, false },
+      { 0, 0, 0, false} }
+  },
+
+  // Error underline.
+  { "One Two Three",
+    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_ERROR, 4, 7 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
+      { 0, 0, 0, 0 } },
+    { { 0, 3, SK_ColorBLACK, false },
+      { 4, 7, SK_ColorRED, false },
+      { 8, 13, SK_ColorBLACK, false },
+      { 0, 0, 0, false} }
+  },
+
+  // Default underline.
+  { "One Two Three",
+    { { 0, 0, 0, 0 } },
+    { { 0, 13, SK_ColorBLACK, false },
+      { 0, 0, 0, false } }
+  },
+
+  // Unicode, including non-BMP characters: "123你好𠀀𠀁一丁 456"
+  { "123\xE4\xBD\xA0\xE5\xA5\xBD\xF0\xA0\x80\x80\xF0\xA0\x80\x81\xE4\xB8\x80"
+    "\xE4\xB8\x81 456",
+    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 3, 5 },
+      { PANGO_ATTR_BACKGROUND, 0, 5, 7 },
+      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 7, 13 },
+      { 0, 0, 0, 0 } },
+    { { 0, 3, SK_ColorBLACK, false },
+      { 3, 5, SK_ColorBLACK, false },
+      { 5, 9, SK_ColorBLACK, true },
+      { 9, 15, SK_ColorBLACK, false },
+      { 0, 0, 0, false } }
+  },
+};
+
+void CompareUnderline(const Underline& a,
+                      const ui::CompositionUnderline& b) {
+  EXPECT_EQ(a.start_offset, b.start_offset);
+  EXPECT_EQ(a.end_offset, b.end_offset);
+  EXPECT_EQ(a.color, b.color);
+  EXPECT_EQ(a.thick, b.thick);
+}
+
+TEST(CompositionTextUtilPangoTest, ExtractCompositionText) {
+  for (size_t i = 0; i < arraysize(kTestData); ++i) {
+    const char* text = kTestData[i].text;
+    const AttributeInfo* attrs = kTestData[i].attrs;
+    SCOPED_TRACE(testing::Message() << "Testing:" << i
+                 << " text:" << text);
+
+    PangoAttrList* pango_attrs = pango_attr_list_new();
+    for (size_t a = 0; attrs[a].type; ++a) {
+      PangoAttribute* pango_attr = NULL;
+      switch (attrs[a].type) {
+        case PANGO_ATTR_UNDERLINE:
+          pango_attr = pango_attr_underline_new(
+              static_cast<PangoUnderline>(attrs[a].value));
+          break;
+        case PANGO_ATTR_BACKGROUND:
+          pango_attr = pango_attr_background_new(0, 0, 0);
+          break;
+        default:
+          NOTREACHED();
+      }
+      pango_attr->start_index =
+          g_utf8_offset_to_pointer(text, attrs[a].start_offset) - text;
+      pango_attr->end_index =
+          g_utf8_offset_to_pointer(text, attrs[a].end_offset) - text;
+      pango_attr_list_insert(pango_attrs, pango_attr);
+    }
+
+    ui::CompositionText result;
+    ui::ExtractCompositionTextFromGtkPreedit(text, pango_attrs, 0, &result);
+
+    const Underline* underlines = kTestData[i].underlines;
+    for (size_t u = 0; underlines[u].color &&
+         u < result.underlines.size(); ++u) {
+      SCOPED_TRACE(testing::Message() << "Underline:" << u);
+      CompareUnderline(underlines[u], result.underlines[u]);
+    }
+
+    pango_attr_list_unref(pango_attrs);
+  }
+}
+
+}  // namespace
diff --git a/ui/base/ime/dummy_input_method.cc b/ui/base/ime/dummy_input_method.cc
index 2fc206d..b35313d 100644
--- a/ui/base/ime/dummy_input_method.cc
+++ b/ui/base/ime/dummy_input_method.cc
@@ -32,10 +32,6 @@
 void DummyInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
 }
 
-void DummyInputMethod::SetStickyFocusedTextInputClient(
-    TextInputClient* client) {
-}
-
 void DummyInputMethod::DetachTextInputClient(TextInputClient* client) {
 }
 
diff --git a/ui/base/ime/dummy_input_method.h b/ui/base/ime/dummy_input_method.h
index edceb0e..0e40c18 100644
--- a/ui/base/ime/dummy_input_method.h
+++ b/ui/base/ime/dummy_input_method.h
@@ -25,8 +25,6 @@
   virtual bool OnUntranslatedIMEMessage(
       const base::NativeEvent& event, NativeEventResult* result) OVERRIDE;
   virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE;
-  virtual void SetStickyFocusedTextInputClient(
-      TextInputClient* client) OVERRIDE;
   virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE;
   virtual TextInputClient* GetTextInputClient() const OVERRIDE;
   virtual bool DispatchKeyEvent(const base::NativeEvent& event) OVERRIDE;
diff --git a/ui/base/ime/fake_input_method.cc b/ui/base/ime/fake_input_method.cc
index 2173616..322130f 100644
--- a/ui/base/ime/fake_input_method.cc
+++ b/ui/base/ime/fake_input_method.cc
@@ -38,8 +38,7 @@
 
 FakeInputMethod::FakeInputMethod(internal::InputMethodDelegate* delegate)
     : delegate_(NULL),
-      text_input_client_(NULL),
-      is_sticky_text_input_client_(false) {
+      text_input_client_(NULL) {
   SetDelegate(delegate);
 }
 
@@ -51,24 +50,14 @@
 }
 
 void FakeInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
-  if (is_sticky_text_input_client_)
-    return;
   text_input_client_ = client;
   FOR_EACH_OBSERVER(InputMethodObserver, observers_,
                     OnTextInputStateChanged(client));
 }
 
-void FakeInputMethod::SetStickyFocusedTextInputClient(TextInputClient* client) {
-  text_input_client_ = client;
-  is_sticky_text_input_client_ = (client != NULL);
-  FOR_EACH_OBSERVER(InputMethodObserver, observers_,
-                    OnTextInputStateChanged(client));
-}
-
 void FakeInputMethod::DetachTextInputClient(TextInputClient* client) {
   if (text_input_client_ == client) {
     text_input_client_ = NULL;
-    is_sticky_text_input_client_ = false;
     FOR_EACH_OBSERVER(InputMethodObserver, observers_,
                       OnTextInputStateChanged(client));
   }
diff --git a/ui/base/ime/fake_input_method.h b/ui/base/ime/fake_input_method.h
index 42b8b02..9aca97c 100644
--- a/ui/base/ime/fake_input_method.h
+++ b/ui/base/ime/fake_input_method.h
@@ -34,8 +34,6 @@
   virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
                                         NativeEventResult* result) OVERRIDE;
   virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE;
-  virtual void SetStickyFocusedTextInputClient(
-      TextInputClient* client) OVERRIDE;
   virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE;
   virtual TextInputClient* GetTextInputClient() const OVERRIDE;
   virtual bool DispatchKeyEvent(const base::NativeEvent& native_event) OVERRIDE;
@@ -57,7 +55,6 @@
  private:
   internal::InputMethodDelegate* delegate_;
   TextInputClient* text_input_client_;
-  bool is_sticky_text_input_client_;
   ObserverList<InputMethodObserver> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeInputMethod);
diff --git a/ui/base/ime/ime.gypi b/ui/base/ime/ime.gypi
index 2b5efb0..785e977 100644
--- a/ui/base/ime/ime.gypi
+++ b/ui/base/ime/ime.gypi
@@ -3,69 +3,67 @@
 # found in the LICENSE file.
 
 {
-  'variables': {
-    'ime_files': [
-      'character_composer.cc',
-      'character_composer.h',
-      'composition_text.cc',
-      'composition_text.h',
-      'composition_underline.h',
-      'dummy_input_method_delegate.cc',
-      'dummy_input_method_delegate.h',
-      'input_method.h',
-      'input_method_base.cc',
-      'input_method_base.h',
-      'input_method_delegate.h',
-      'input_method_factory.cc',
-      'input_method_factory.h',
-      'input_method_ibus.cc',
-      'input_method_ibus.h',
-      'input_method_imm32.cc',
-      'input_method_imm32.h',
-      'input_method_initializer.h',
-      'input_method_initializer.cc',
-      'input_method_observer.h',
-      'input_method_tsf.cc',
-      'input_method_tsf.h',
-      'input_method_win.cc',
-      'input_method_win.h',
-      'mock_input_method.cc',
-      'mock_input_method.h',
-      'fake_input_method.cc',
-      'fake_input_method.h',
-      'text_input_client.cc',
-      'text_input_client.h',
-      'text_input_type.h',
-    ],
-    'win_ime_files': [
-      'win/imm32_manager.cc',
-      'win/imm32_manager.h',
-      'win/tsf_bridge.cc',
-      'win/tsf_bridge.h',
-      'win/tsf_event_router.cc',
-      'win/tsf_event_router.h',
-      'win/tsf_input_scope.cc',
-      'win/tsf_input_scope.h',
-      'win/tsf_text_store.cc',
-      'win/tsf_text_store.h',
-    ],
-  },
   'sources': [
-    '<@(ime_files)',
-    '<@(win_ime_files)',
+    'character_composer.cc',
+    'character_composer.h',
+    'composition_text.cc',
+    'composition_text.h',
+    'composition_text_util_pango.cc',
+    'composition_text_util_pango.h',
+    'composition_underline.h',
+    'dummy_input_method_delegate.cc',
+    'dummy_input_method_delegate.h',
+    'fake_input_method.cc',
+    'fake_input_method.h',
+    'input_method.h',
+    'input_method_base.cc',
+    'input_method_base.h',
+    'input_method_delegate.h',
+    'input_method_factory.cc',
+    'input_method_factory.h',
+    'input_method_ibus.cc',
+    'input_method_ibus.h',
+    'input_method_imm32.cc',
+    'input_method_imm32.h',
+    'input_method_initializer.cc',
+    'input_method_initializer.h',
+    'input_method_linux_x11.cc',
+    'input_method_linux_x11.h',
+    'input_method_observer.h',
+    'input_method_tsf.cc',
+    'input_method_tsf.h',
+    'input_method_win.cc',
+    'input_method_win.h',
+    'linux/fake_input_method_context.cc',
+    'linux/fake_input_method_context.h',
+    'linux/fake_input_method_context_factory.cc',
+    'linux/fake_input_method_context_factory.h',
+    'linux/linux_input_method_context.h',
+    'linux/linux_input_method_context_factory.cc',
+    'linux/linux_input_method_context_factory.h',
+    'mock_input_method.cc',
+    'mock_input_method.h',
+    'text_input_client.cc',
+    'text_input_client.h',
+    'text_input_type.h',
+    'win/imm32_manager.cc',
+    'win/imm32_manager.h',
+    'win/tsf_bridge.cc',
+    'win/tsf_bridge.h',
+    'win/tsf_event_router.cc',
+    'win/tsf_event_router.h',
+    'win/tsf_input_scope.cc',
+    'win/tsf_input_scope.h',
+    'win/tsf_text_store.cc',
+    'win/tsf_text_store.h',
   ],
   'conditions': [
-    ['use_aura==0 and OS!="win"', {
+    ['toolkit_views==0 and use_aura==0', {
       'sources!': [
-        '<@(ime_files)',
-      ],
-      'sources/': [
-        # gtk_im_context_util* use ui::CompositionText.
-        ['include', 'composition_text\\.(cc|h)$'],
-        # Initializer code is platform neutral.
-        ['include', 'input_method_initializer\\.(cc|h)$'],
-        # native_textfield_views* use ui::TextInputClient.
-        ['include', 'text_input_client\\.(cc|h)$'],
+        'fake_input_method.cc',
+        'fake_input_method.h',
+        'input_method_factory.cc',
+        'input_method_factory.h',
       ],
     }],
     ['chromeos==0 or use_x11==0', {
@@ -83,12 +81,30 @@
     }],
     ['OS!="win"', {
       'sources!': [
-        '<@(win_ime_files)',
         'input_method_imm32.cc',
         'input_method_imm32.h',
         'input_method_tsf.cc',
         'input_method_tsf.h',
       ],
     }],
+    ['use_aura==0 or use_x11==0 or desktop_linux==0', {
+      'sources!': [
+        'input_method_linux_x11.cc',
+        'input_method_linux_x11.h',
+        'linux/fake_input_method_context.cc',
+        'linux/fake_input_method_context.h',
+        'linux/fake_input_method_context_factory.cc',
+        'linux/fake_input_method_context_factory.h',
+        'linux/linux_input_method_context.h',
+        'linux/linux_input_method_context_factory.cc',
+        'linux/linux_input_method_context_factory.h',
+      ],
+    }],
+    ['use_x11==0', {
+      'sources!': [
+        'composition_text_util_pango.cc',
+        'composition_text_util_pango.h',
+      ],
+    }],
   ],
 }
diff --git a/ui/base/ime/ime_unittests.gypi b/ui/base/ime/ime_unittests.gypi
index 3dabb50..91c8e9a 100644
--- a/ui/base/ime/ime_unittests.gypi
+++ b/ui/base/ime/ime_unittests.gypi
@@ -5,6 +5,7 @@
 {
   'sources': [
     'character_composer_unittest.cc',
+    'composition_text_util_pango_unittest.cc',
     'input_method_base_unittest.cc',
     'input_method_ibus_unittest.cc',
     'win/imm32_manager_unittest.cc',
@@ -12,20 +13,15 @@
     'win/tsf_text_store_unittest.cc',
   ],
   'conditions': [
-    ['use_aura==0 or use_x11==0 or chromeos==0', {
+    ['chromeos==0 or use_x11==0', {
       'sources!': [
         'character_composer_unittest.cc',
         'input_method_ibus_unittest.cc',
       ],
     }],
-    ['use_aura==0 and OS!="win"', {
+    ['use_x11==0', {
       'sources!': [
-        'input_method_base_unittest.cc',
-      ],
-    }],
-    ['OS!="win"', {
-      'sources/': [
-        ['exclude', '^win'],
+        'composition_text_util_pango_unittest.cc',
       ],
     }],
   ],
diff --git a/ui/base/ime/input_method.h b/ui/base/ime/input_method.h
index ac24f77..2109a51 100644
--- a/ui/base/ime/input_method.h
+++ b/ui/base/ime/input_method.h
@@ -86,14 +86,6 @@
   // calling the method with NULL when it is unfocused.
   virtual void SetFocusedTextInputClient(TextInputClient* client) = 0;
 
-  // A variant of SetFocusedTextInputClient. Unlike SetFocusedTextInputClient,
-  // all the subsequent calls of SetFocusedTextInputClient will be ignored
-  // until |client| is detached. This method is introduced as a workaround
-  // against crbug.com/287620.
-  // NOTE: You can pass NULL to |client| to detach the sticky client.
-  // NOTE: You can also use DetachTextInputClient to remove the sticky client.
-  virtual void SetStickyFocusedTextInputClient(TextInputClient* client) = 0;
-
   // Detaches and forgets the |client| regardless of whether it has the focus or
   // not.  This method is meant to be called when the |client| is going to be
   // destroyed.
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index d377076..b143314 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -14,7 +14,6 @@
 InputMethodBase::InputMethodBase()
   : delegate_(NULL),
     text_input_client_(NULL),
-    is_sticky_text_input_client_(false),
     system_toplevel_window_focused_(false) {
 }
 
@@ -44,13 +43,6 @@
 }
 
 void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) {
-  if (is_sticky_text_input_client_)
-    return;
-  SetFocusedTextInputClientInternal(client);
-}
-
-void InputMethodBase::SetStickyFocusedTextInputClient(TextInputClient* client) {
-  is_sticky_text_input_client_ = (client != NULL);
   SetFocusedTextInputClientInternal(client);
 }
 
@@ -58,7 +50,6 @@
   if (text_input_client_ == client) {
     OnWillChangeFocusedClient(client, NULL);
     text_input_client_ = NULL;
-    is_sticky_text_input_client_ = false;
     OnDidChangeFocusedClient(client, NULL);
     NotifyTextInputStateChanged(text_input_client_);
   }
@@ -74,6 +65,20 @@
   NotifyTextInputStateChanged(client);
 }
 
+void InputMethodBase::OnCaretBoundsChanged(const TextInputClient* client) {
+  if (!IsTextInputClientFocused(client))
+    return;
+  FOR_EACH_OBSERVER(InputMethodObserver,
+                    observer_list_,
+                    OnCaretBoundsChanged(client));
+}
+
+void InputMethodBase::OnInputLocaleChanged() {
+  FOR_EACH_OBSERVER(InputMethodObserver,
+                    observer_list_,
+                    OnInputLocaleChanged());
+}
+
 TextInputType InputMethodBase::GetTextInputType() const {
   TextInputClient* client = GetTextInputClient();
   return client ? client->GetTextInputType() : TEXT_INPUT_TYPE_NONE;
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 665070a..1aebb97 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -37,14 +37,14 @@
   virtual void OnFocus() OVERRIDE;
   virtual void OnBlur() OVERRIDE;
   virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE;
-  virtual void SetStickyFocusedTextInputClient(
-      TextInputClient* client) OVERRIDE;
   virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE;
   virtual TextInputClient* GetTextInputClient() const OVERRIDE;
 
   // If a derived class overrides this method, it should call parent's
   // implementation.
   virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
+  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
+  virtual void OnInputLocaleChanged() OVERRIDE;
 
   virtual TextInputType GetTextInputType() const OVERRIDE;
   virtual TextInputMode GetTextInputMode() const OVERRIDE;
@@ -94,7 +94,6 @@
 
   internal::InputMethodDelegate* delegate_;
   TextInputClient* text_input_client_;
-  bool is_sticky_text_input_client_;
 
   ObserverList<InputMethodObserver> observer_list_;
 
diff --git a/ui/base/ime/input_method_base_unittest.cc b/ui/base/ime/input_method_base_unittest.cc
index 3d06a1a..45215e0 100644
--- a/ui/base/ime/input_method_base_unittest.cc
+++ b/ui/base/ime/input_method_base_unittest.cc
@@ -110,13 +110,11 @@
   DISALLOW_COPY_AND_ASSIGN(ClientChangeVerifier);
 };
 
-class MockInputMethodBase : public InputMethodBase {
+class SimpleMockInputMethodBase : public InputMethodBase {
  public:
-  // Note: this class does not take the ownership of |verifier|.
-  explicit MockInputMethodBase(ClientChangeVerifier* verifier)
-      : verifier_(verifier) {
+  SimpleMockInputMethodBase() {
   }
-  virtual ~MockInputMethodBase() {
+  virtual ~SimpleMockInputMethodBase() {
   }
 
  private:
@@ -132,13 +130,9 @@
   virtual bool DispatchFabricatedKeyEvent(const ui::KeyEvent&) OVERRIDE {
     return false;
   }
-  virtual void OnCaretBoundsChanged(const TextInputClient* clien) OVERRIDE {
+  virtual void CancelComposition(const TextInputClient* client) OVERRIDE {
   }
-  virtual void CancelComposition(const TextInputClient* clien) OVERRIDE {
-  }
-  virtual void OnInputLocaleChanged() OVERRIDE {
-  }
-  virtual std::string GetInputLocale() OVERRIDE {
+  virtual std::string GetInputLocale() OVERRIDE{
     return "";
   }
   virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
@@ -150,7 +144,19 @@
   virtual bool IsCandidatePopupOpen() const OVERRIDE {
     return false;
   }
+  DISALLOW_COPY_AND_ASSIGN(SimpleMockInputMethodBase);
+};
 
+class MockInputMethodBase : public SimpleMockInputMethodBase {
+ public:
+  // Note: this class does not take the ownership of |verifier|.
+  explicit MockInputMethodBase(ClientChangeVerifier* verifier)
+      : verifier_(verifier) {
+  }
+  virtual ~MockInputMethodBase() {
+  }
+
+ private:
   // Overriden from InputMethodBase.
   virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
                                          TextInputClient* focused) OVERRIDE {
@@ -166,7 +172,53 @@
   DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase);
 };
 
-class MockInputMethodObserver : public InputMethodObserver {
+class SimpleMockInputMethodObserver : public InputMethodObserver {
+ public:
+  SimpleMockInputMethodObserver()
+      : on_caret_bounds_changed_(0),
+        on_input_locale_changed_(0) {
+  }
+  virtual ~SimpleMockInputMethodObserver() {
+  }
+  void Reset() {
+    on_caret_bounds_changed_ = 0;
+    on_input_locale_changed_ = 0;
+  }
+  size_t on_caret_bounds_changed() const {
+    return on_caret_bounds_changed_;
+  }
+  size_t on_input_locale_changed() const {
+    return on_input_locale_changed_;
+  }
+
+ private:
+  // Overriden from InputMethodObserver.
+  virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE{
+  }
+  virtual void OnFocus() OVERRIDE{
+  }
+  virtual void OnBlur() OVERRIDE{
+  }
+  virtual void OnUntranslatedIMEMessage(
+    const base::NativeEvent& event) OVERRIDE{
+  }
+  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE{
+    ++on_caret_bounds_changed_;
+  }
+  virtual void OnInputLocaleChanged() OVERRIDE{
+    ++on_input_locale_changed_;
+  }
+  virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE{
+  }
+  virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE{
+  }
+
+  size_t on_caret_bounds_changed_;
+  size_t on_input_locale_changed_;
+  DISALLOW_COPY_AND_ASSIGN(SimpleMockInputMethodObserver);
+};
+
+class MockInputMethodObserver : public SimpleMockInputMethodObserver {
  public:
   // Note: this class does not take the ownership of |verifier|.
   explicit MockInputMethodObserver(ClientChangeVerifier* verifier)
@@ -176,24 +228,10 @@
   }
 
  private:
-  virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
-  }
-  virtual void OnFocus() OVERRIDE {
-  }
-  virtual void OnBlur() OVERRIDE {
-  }
-  virtual void OnUntranslatedIMEMessage(
-      const base::NativeEvent& event) OVERRIDE {
-  }
-  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
-  }
-  virtual void OnInputLocaleChanged() OVERRIDE {
-  }
-  virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE {
+  // Overriden from SimpleMockInputMethodObserver.
+  virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE{
     verifier_->OnTextInputStateChanged(client);
   }
-  virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
-  }
 
   ClientChangeVerifier* verifier_;
   DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
@@ -304,13 +342,12 @@
   }
 }
 
-TEST(InputMethodBaseTest, SetStickyFocusedTextInputClient) {
-  DummyTextInputClient sticky_client;
-  DummyTextInputClient non_sticky_client;
+TEST(InputMethodBaseTest, OnCaretBoundsChanged) {
+  DummyTextInputClient text_input_client;
+  DummyTextInputClient text_input_client_the_other;
 
-  ClientChangeVerifier verifier;
-  MockInputMethodBase input_method(&verifier);
-  MockInputMethodObserver input_method_observer(&verifier);
+  SimpleMockInputMethodBase input_method;
+  SimpleMockInputMethodObserver input_method_observer;
   InputMethodScopedObserver scoped_observer(&input_method_observer);
   scoped_observer.Add(&input_method);
 
@@ -318,77 +355,65 @@
   input_method.OnFocus();
 
   {
-    SCOPED_TRACE("Focus from NULL to non-sticky client");
-
+    SCOPED_TRACE("OnCaretBoundsChanged callback must not be fired when no text "
+        "input client is focused");
     ASSERT_EQ(NULL, input_method.GetTextInputClient());
-    verifier.ExpectClientChange(NULL, &non_sticky_client);
-    input_method.SetFocusedTextInputClient(&non_sticky_client);
-    EXPECT_EQ(&non_sticky_client, input_method.GetTextInputClient());
-    verifier.Verify();
+
+    input_method_observer.Reset();
+    input_method.OnCaretBoundsChanged(&text_input_client);
+    EXPECT_EQ(0u, input_method_observer.on_caret_bounds_changed());
+    input_method.OnCaretBoundsChanged(NULL);
+    EXPECT_EQ(0u, input_method_observer.on_caret_bounds_changed());
   }
 
   {
-    SCOPED_TRACE("Focus from non-sticky to sticky client");
+    SCOPED_TRACE("OnCaretBoundsChanged callback must be fired when and only "
+        "the event is notified from the focused text input client");
 
-    ASSERT_EQ(&non_sticky_client, input_method.GetTextInputClient());
-    verifier.ExpectClientChange(&non_sticky_client, &sticky_client);
-    input_method.SetStickyFocusedTextInputClient(&sticky_client);
-    EXPECT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.Verify();
+    input_method.SetFocusedTextInputClient(&text_input_client);
+    ASSERT_EQ(&text_input_client, input_method.GetTextInputClient());
+
+    // Must fire the event
+    input_method_observer.Reset();
+    input_method.OnCaretBoundsChanged(&text_input_client);
+    EXPECT_EQ(1u, input_method_observer.on_caret_bounds_changed());
+
+    // Must not fire the event
+    input_method_observer.Reset();
+    input_method.OnCaretBoundsChanged(NULL);
+    EXPECT_EQ(0u, input_method_observer.on_caret_bounds_changed());
+
+    // Must not fire the event
+    input_method_observer.Reset();
+    input_method.OnCaretBoundsChanged(&text_input_client_the_other);
+    EXPECT_EQ(0u, input_method_observer.on_caret_bounds_changed());
   }
+}
+
+TEST(InputMethodBaseTest, OnInputLocaleChanged) {
+  DummyTextInputClient text_input_client;
+
+  SimpleMockInputMethodBase input_method;
+  SimpleMockInputMethodObserver input_method_observer;
+  InputMethodScopedObserver scoped_observer(&input_method_observer);
+  scoped_observer.Add(&input_method);
+
+  // Assume that the top-level-widget gains focus.
+  input_method.OnFocus();
 
   {
-    SCOPED_TRACE("Focus from sticky to non-sticky client -> must fail");
+    SCOPED_TRACE("OnInputLocaleChanged callback can be fired even when no text "
+        "input client is focused");
+    ASSERT_EQ(NULL, input_method.GetTextInputClient());
 
-    ASSERT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.ExpectClientDoesNotChange();
-    input_method.SetFocusedTextInputClient(&non_sticky_client);
-    EXPECT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.Verify();
-  }
+    input_method_observer.Reset();
+    input_method.OnInputLocaleChanged();
+    EXPECT_EQ(1u, input_method_observer.on_input_locale_changed());
 
-  {
-    SCOPED_TRACE("Focus from sticky to NULL -> must fail");
-
-    verifier.ExpectClientDoesNotChange();
-    input_method.SetFocusedTextInputClient(NULL);
-    EXPECT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.Verify();
-  }
-
-  {
-    SCOPED_TRACE("SetStickyFocusedTextInputClient(NULL) must be supported");
-
-    ASSERT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.ExpectClientChange(&sticky_client, NULL);
-    input_method.SetStickyFocusedTextInputClient(NULL);
-    EXPECT_EQ(NULL, input_method.GetTextInputClient());
-    verifier.Verify();
-
-    // |SetStickyFocusedTextInputClient(NULL)| must be equivalent to
-    // |SetFocusedTextInputClient(NULL)|. We should be able to use
-    // |SetFocusedTextInputClient(&non_sticky_client)| here.
-    verifier.ExpectClientChange(NULL, &non_sticky_client);
-    input_method.SetFocusedTextInputClient(&non_sticky_client);
-    EXPECT_EQ(&non_sticky_client, input_method.GetTextInputClient());
-    verifier.Verify();
-  }
-
-  {
-    SCOPED_TRACE("Set stick client again for the next test");
-    verifier.ExpectClientChange(&non_sticky_client, &sticky_client);
-    input_method.SetStickyFocusedTextInputClient(&sticky_client);
-    verifier.Verify();
-  }
-
-  {
-    SCOPED_TRACE("DetachTextInputClient must be supported for sticky client");
-
-    ASSERT_EQ(&sticky_client, input_method.GetTextInputClient());
-    verifier.ExpectClientChange(&sticky_client, NULL);
-    input_method.DetachTextInputClient(&sticky_client);
-    EXPECT_EQ(NULL, input_method.GetTextInputClient());
-    verifier.Verify();
+    input_method.SetFocusedTextInputClient(&text_input_client);
+    input_method_observer.Reset();
+    input_method.OnInputLocaleChanged();
+    EXPECT_EQ(1u, input_method_observer.on_input_locale_changed());
   }
 }
 
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc
index 018823f..03bd5e4 100644
--- a/ui/base/ime/input_method_factory.cc
+++ b/ui/base/ime/input_method_factory.cc
@@ -13,6 +13,8 @@
 #include "base/win/metro.h"
 #include "ui/base/ime/input_method_imm32.h"
 #include "ui/base/ime/input_method_tsf.h"
+#elif defined(USE_AURA) && defined(USE_X11)
+#include "ui/base/ime/input_method_linux_x11.h"
 #else
 #include "ui/base/ime/fake_input_method.h"
 #endif
@@ -45,6 +47,8 @@
   return new InputMethodIBus(delegate);
 #elif defined(OS_WIN)
   return CreateInputMethodWinInternal(delegate, widget);
+#elif defined(USE_AURA) && defined(USE_X11)
+  return new InputMethodLinuxX11(delegate);
 #else
   return new FakeInputMethod(delegate);
 #endif
diff --git a/ui/base/ime/input_method_ibus.cc b/ui/base/ime/input_method_ibus.cc
index d712463..426b799 100644
--- a/ui/base/ime/input_method_ibus.cc
+++ b/ui/base/ime/input_method_ibus.cc
@@ -69,6 +69,57 @@
   return chromeos::IBusBridge::Get()->GetEngineHandler();
 }
 
+// Check ui::TextInputType and chrome::ibus::TextInputType is kept in sync.
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_NONE) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_NONE), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TEXT) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_TEXT), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_PASSWORD) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_PASSWORD),
+               mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_SEARCH) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_SEARCH), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_EMAIL) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_EMAIL), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_NUMBER) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_NUMBER), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TELEPHONE) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_TELEPHONE),
+               mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_URL) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_URL), mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_DATE) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_DATE), mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_DATE_TIME) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_DATE_TIME),
+               mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_DATE_TIME_LOCAL),
+               mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_MONTH) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_MONTH), mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TIME) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_TIME), mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_WEEK) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_WEEK), mismatching_enum);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_TEXT_AREA) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_TEXT_AREA),
+               mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_CONTENT_EDITABLE),
+               mismatching_enums);
+COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD) == \
+               int(chromeos::ibus::TEXT_INPUT_TYPE_DATE_TIME_FIELD),
+               mismatching_enums);
+
+chromeos::ibus::TextInputType UiToIbusTextInputType(ui::TextInputType type) {
+  // Check the type is in the range representable by
+  // chrome::ibus::TextInputType.
+  DCHECK_LE(type, static_cast<int>(chromeos::ibus::TEXT_INPUT_TYPE_MAX)) <<
+    "ui::TextInputType and chromeos::ibus::TextInputType not synchronized";
+  return static_cast<chromeos::ibus::TextInputType>(type);
+}
+
 }  // namespace
 
 namespace ui {
@@ -229,66 +280,14 @@
     UpdateContextFocusState();
     if (previous_textinput_type_ != client->GetTextInputType())
       OnInputMethodChanged();
+    previous_textinput_type_ = client->GetTextInputType();
   }
   InputMethodBase::OnTextInputTypeChanged(client);
 }
 
 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) {
-  if (!context_focused_ || !IsTextInputClientFocused(client))
-    return;
-
-  // The current text input type should not be NONE if |context_| is focused.
-  DCHECK(!IsTextInputTypeNone());
-  const gfx::Rect rect = GetTextInputClient()->GetCaretBounds();
-
-  gfx::Rect composition_head;
-  if (!GetTextInputClient()->GetCompositionCharacterBounds(0,
-                                                           &composition_head)) {
-    composition_head = rect;
-  }
-
-  chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
-      chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
-  if (!candidate_window)
-    return;
-  candidate_window->SetCursorLocation(
-      GfxRectToIBusRect(rect),
-      GfxRectToIBusRect(composition_head));
-
-  gfx::Range text_range;
-  gfx::Range selection_range;
-  string16 surrounding_text;
-  if (!GetTextInputClient()->GetTextRange(&text_range) ||
-      !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text) ||
-      !GetTextInputClient()->GetSelectionRange(&selection_range)) {
-    previous_surrounding_text_.clear();
-    previous_selection_range_ = gfx::Range::InvalidRange();
-    return;
-  }
-
-  if (previous_selection_range_ == selection_range &&
-      previous_surrounding_text_ == surrounding_text)
-    return;
-
-  previous_selection_range_ = selection_range;
-  previous_surrounding_text_ = surrounding_text;
-
-  if (!selection_range.IsValid()) {
-    // TODO(nona): Ideally selection_range should not be invalid.
-    // TODO(nona): If javascript changes the focus on page loading, even (0,0)
-    //             can not be obtained. Need investigation.
-    return;
-  }
-
-  // Here SetSurroundingText accepts relative position of |surrounding_text|, so
-  // we have to convert |selection_range| from node coordinates to
-  // |surrounding_text| coordinates.
-  if (!GetEngine())
-    return;
-  GetEngine()->SetSurroundingText(
-      UTF16ToUTF8(surrounding_text),
-      selection_range.start() - text_range.start(),
-      selection_range.end() - text_range.start());
+  OnCaretBoundsChangedInternal(client);
+  InputMethodBase::OnCaretBoundsChanged(client);
 }
 
 void InputMethodIBus::CancelComposition(const TextInputClient* client) {
@@ -296,10 +295,6 @@
     ResetContext();
 }
 
-void InputMethodIBus::OnInputLocaleChanged() {
-  // Not supported.
-}
-
 std::string InputMethodIBus::GetInputLocale() {
   // Not supported.
   return "";
@@ -383,8 +378,9 @@
 
 void InputMethodIBus::UpdateContextFocusState() {
   const bool old_context_focused = context_focused_;
+  const TextInputType current_text_input_type = GetTextInputType();
   // Use switch here in case we are going to add more text input types.
-  switch (GetTextInputType()) {
+  switch (current_text_input_type) {
     case TEXT_INPUT_TYPE_NONE:
     case TEXT_INPUT_TYPE_PASSWORD:
       context_focused_ = false;
@@ -401,7 +397,12 @@
   if (old_context_focused && !context_focused_) {
     GetEngine()->FocusOut();
   } else if (!old_context_focused && context_focused_) {
-    GetEngine()->FocusIn();
+    GetEngine()->FocusIn(UiToIbusTextInputType(current_text_input_type));
+    OnCaretBoundsChanged(GetTextInputClient());
+  } else if (context_focused_ &&
+             current_text_input_type != previous_textinput_type_) {
+    GetEngine()->FocusOut();
+    GetEngine()->FocusIn(UiToIbusTextInputType(current_text_input_type));
     OnCaretBoundsChanged(GetTextInputClient());
   }
 }
@@ -806,4 +807,63 @@
   }
 }
 
+void InputMethodIBus::OnCaretBoundsChangedInternal(
+    const TextInputClient* client) {
+  if (!context_focused_ || !IsTextInputClientFocused(client))
+    return;
+
+  // The current text input type should not be NONE if |context_| is focused.
+  DCHECK(!IsTextInputTypeNone());
+  const gfx::Rect rect = GetTextInputClient()->GetCaretBounds();
+
+  gfx::Rect composition_head;
+  if (!GetTextInputClient()->GetCompositionCharacterBounds(0,
+                                                           &composition_head)) {
+    composition_head = rect;
+  }
+
+  chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
+      chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
+  if (!candidate_window)
+    return;
+  candidate_window->SetCursorLocation(
+      GfxRectToIBusRect(rect),
+      GfxRectToIBusRect(composition_head));
+
+  gfx::Range text_range;
+  gfx::Range selection_range;
+  string16 surrounding_text;
+  if (!GetTextInputClient()->GetTextRange(&text_range) ||
+      !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text) ||
+      !GetTextInputClient()->GetSelectionRange(&selection_range)) {
+    previous_surrounding_text_.clear();
+    previous_selection_range_ = gfx::Range::InvalidRange();
+    return;
+  }
+
+  if (previous_selection_range_ == selection_range &&
+      previous_surrounding_text_ == surrounding_text)
+    return;
+
+  previous_selection_range_ = selection_range;
+  previous_surrounding_text_ = surrounding_text;
+
+  if (!selection_range.IsValid()) {
+    // TODO(nona): Ideally selection_range should not be invalid.
+    // TODO(nona): If javascript changes the focus on page loading, even (0,0)
+    //             can not be obtained. Need investigation.
+    return;
+  }
+
+  // Here SetSurroundingText accepts relative position of |surrounding_text|, so
+  // we have to convert |selection_range| from node coordinates to
+  // |surrounding_text| coordinates.
+  if (!GetEngine())
+    return;
+  GetEngine()->SetSurroundingText(
+      UTF16ToUTF8(surrounding_text),
+      selection_range.start() - text_range.start(),
+      selection_range.end() - text_range.start());
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/input_method_ibus.h b/ui/base/ime/input_method_ibus.h
index 1f0b194..b4aecde 100644
--- a/ui/base/ime/input_method_ibus.h
+++ b/ui/base/ime/input_method_ibus.h
@@ -47,7 +47,6 @@
   virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
   virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
   virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
-  virtual void OnInputLocaleChanged() OVERRIDE;
   virtual std::string GetInputLocale() OVERRIDE;
   virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
   virtual bool IsActive() OVERRIDE;
@@ -139,6 +138,9 @@
                            uint32 ibus_keyval, uint32 ibus_keycode,
                            uint32 ibus_state, bool is_handled);
 
+  // Processes a caret bounds changed event.
+  void OnCaretBoundsChangedInternal(const TextInputClient* client);
+
   // All pending key events. Note: we do not own these object, we just save
   // pointers to these object so that we can abandon them when necessary.
   // They will be deleted in ProcessKeyEventDone().
diff --git a/ui/base/ime/input_method_ibus_unittest.cc b/ui/base/ime/input_method_ibus_unittest.cc
index c691835..5de2557 100644
--- a/ui/base/ime/input_method_ibus_unittest.cc
+++ b/ui/base/ime/input_method_ibus_unittest.cc
@@ -609,16 +609,38 @@
   EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
 }
 
-// Confirm that IBusClient::FocusOut is NOT called.
-TEST_F(InputMethodIBusTest, FocusOut_Url) {
-  input_type_ = TEXT_INPUT_TYPE_TEXT;
+// FocusIn/FocusOut scenario test
+TEST_F(InputMethodIBusTest, Focus_Scenario) {
   ime_->Init(true);
+  // Confirm that both FocusIn and FocusOut are NOT called.
+  EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count());
+  EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+  EXPECT_EQ(chromeos::ibus::TEXT_INPUT_TYPE_NONE,
+            mock_ime_engine_handler_->last_text_input_type());
+
+  input_type_ = TEXT_INPUT_TYPE_TEXT;
+  ime_->OnTextInputTypeChanged(this);
+  // Confirm that only FocusIn is called and the TextInputType is TEXT.
   EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
   EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+  EXPECT_EQ(chromeos::ibus::TEXT_INPUT_TYPE_TEXT,
+            mock_ime_engine_handler_->last_text_input_type());
+
+  ime_->OnTextInputTypeChanged(this);
+  // Confirm that both FocusIn and FocusOut are NOT called.
+  EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+  EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+  EXPECT_EQ(chromeos::ibus::TEXT_INPUT_TYPE_TEXT,
+            mock_ime_engine_handler_->last_text_input_type());
+
   input_type_ = TEXT_INPUT_TYPE_URL;
   ime_->OnTextInputTypeChanged(this);
-  EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
-  EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+  // Confirm that both FocusIn and FocusOut are called and the TextInputType is
+  // URL.
+  EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count());
+  EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
+  EXPECT_EQ(chromeos::ibus::TEXT_INPUT_TYPE_URL,
+            mock_ime_engine_handler_->last_text_input_type());
 }
 
 // Test if the new |caret_bounds_| is correctly sent to ibus-daemon.
diff --git a/ui/base/ime/input_method_imm32.cc b/ui/base/ime/input_method_imm32.cc
index 4f17ea9..ca02fa3 100644
--- a/ui/base/ime/input_method_imm32.cc
+++ b/ui/base/ime/input_method_imm32.cc
@@ -94,26 +94,23 @@
 }
 
 void InputMethodIMM32::OnCaretBoundsChanged(const TextInputClient* client) {
-  if (!enabled_ || !IsTextInputClientFocused(client) ||
-      !IsWindowFocused(client)) {
-    return;
+  if (enabled_ && IsTextInputClientFocused(client) && IsWindowFocused(client)) {
+    // The current text input type should not be NONE if |client| is focused.
+    DCHECK(!IsTextInputTypeNone());
+    gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds());
+
+    HWND attached_window = GetAttachedWindowHandle(client);
+    // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
+    // conversion shouldn't be necessary.
+    RECT r = {};
+    GetClientRect(attached_window, &r);
+    POINT window_point = { screen_bounds.x(), screen_bounds.y() };
+    ScreenToClient(attached_window, &window_point);
+    gfx::Rect caret_rect(gfx::Point(window_point.x, window_point.y),
+                         screen_bounds.size());
+    imm32_manager_.UpdateCaretRect(attached_window, caret_rect);
   }
-
-  // The current text input type should not be NONE if |client| is focused.
-  DCHECK(!IsTextInputTypeNone());
-  gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds());
-
-  HWND attached_window = GetAttachedWindowHandle(client);
-  // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
-  // conversion shouldn't be necessary.
-  RECT r;
-  GetClientRect(attached_window, &r);
-  POINT window_point = { screen_bounds.x(), screen_bounds.y() };
-  ScreenToClient(attached_window, &window_point);
-  imm32_manager_.UpdateCaretRect(
-      attached_window,
-      gfx::Rect(gfx::Point(window_point.x, window_point.y),
-                screen_bounds.size()));
+  InputMethodWin::OnCaretBoundsChanged(client);
 }
 
 void InputMethodIMM32::CancelComposition(const TextInputClient* client) {
diff --git a/ui/base/ime/input_method_initializer.cc b/ui/base/ime/input_method_initializer.cc
index f488f4f..1840e72 100644
--- a/ui/base/ime/input_method_initializer.cc
+++ b/ui/base/ime/input_method_initializer.cc
@@ -10,16 +10,23 @@
 #include "base/logging.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/ime/ibus_bridge.h"
+#elif defined(USE_AURA) && defined(USE_X11)
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ime/linux/fake_input_method_context_factory.h"
 #elif defined(OS_WIN)
 #include "base/win/metro.h"
 #include "ui/base/ime/win/tsf_bridge.h"
 #endif
 
-#if defined(OS_CHROMEOS)
 namespace {
+
+#if defined(OS_CHROMEOS)
 bool dbus_thread_manager_was_initialized = false;
-}
-#endif  // OS_CHROMEOS
+#elif defined(USE_AURA) && defined(USE_X11)
+const ui::LinuxInputMethodContextFactory* g_linux_input_method_context_factory;
+#endif
+
+}  // namespace
 
 namespace ui {
 
@@ -50,6 +57,16 @@
     chromeos::DBusThreadManager::InitializeWithStub();
     dbus_thread_manager_was_initialized = true;
   }
+#elif defined(USE_AURA) && defined(USE_X11)
+  if (!g_linux_input_method_context_factory)
+    g_linux_input_method_context_factory = new FakeInputMethodContextFactory();
+  const LinuxInputMethodContextFactory* factory =
+      LinuxInputMethodContextFactory::instance();
+  CHECK(!factory || factory == g_linux_input_method_context_factory)
+      << "LinuxInputMethodContextFactory was already initialized somewhere "
+      << "else.";
+  LinuxInputMethodContextFactory::SetInstance(
+      g_linux_input_method_context_factory);
 #elif defined(OS_WIN)
   if (base::win::IsTSFAwareRequired()) {
     // Make sure COM is initialized because TSF depends on COM.
@@ -67,6 +84,14 @@
     chromeos::DBusThreadManager::Shutdown();
     dbus_thread_manager_was_initialized = false;
   }
+#elif defined(USE_AURA) && defined(USE_X11)
+  const LinuxInputMethodContextFactory* factory =
+      LinuxInputMethodContextFactory::instance();
+  CHECK(!factory || factory == g_linux_input_method_context_factory)
+      << "An unknown LinuxInputMethodContextFactory was set.";
+  LinuxInputMethodContextFactory::SetInstance(NULL);
+  delete g_linux_input_method_context_factory;
+  g_linux_input_method_context_factory = NULL;
 #elif defined(OS_WIN)
   ui::internal::DestroySharedInputMethod();
   if (base::win::IsTSFAwareRequired()) {
diff --git a/ui/base/ime/input_method_linux_x11.cc b/ui/base/ime/input_method_linux_x11.cc
new file mode 100644
index 0000000..5973761
--- /dev/null
+++ b/ui/base/ime/input_method_linux_x11.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/input_method_linux_x11.h"
+
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+
+namespace ui {
+
+InputMethodLinuxX11::InputMethodLinuxX11(
+    internal::InputMethodDelegate* delegate) {
+  SetDelegate(delegate);
+}
+
+InputMethodLinuxX11::~InputMethodLinuxX11() {}
+
+// Overriden from InputMethod.
+
+void InputMethodLinuxX11::Init(bool focused) {
+  CHECK(LinuxInputMethodContextFactory::instance());
+  input_method_context_ =
+      LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
+          this);
+  CHECK(input_method_context_.get());
+
+  InputMethodBase::Init(focused);
+
+  if (focused) {
+    input_method_context_->OnTextInputTypeChanged(
+        GetTextInputClient() ?
+        GetTextInputClient()->GetTextInputType() :
+        TEXT_INPUT_TYPE_TEXT);
+  }
+}
+
+bool InputMethodLinuxX11::OnUntranslatedIMEMessage(
+    const base::NativeEvent& event,
+    NativeEventResult* result) {
+  return false;
+}
+
+bool InputMethodLinuxX11::DispatchKeyEvent(
+    const base::NativeEvent& native_key_event) {
+  EventType event_type = EventTypeFromNative(native_key_event);
+  DCHECK(event_type == ET_KEY_PRESSED || event_type == ET_KEY_RELEASED);
+  DCHECK(system_toplevel_window_focused());
+
+  // If no text input client, do nothing.
+  if (!GetTextInputClient())
+    return DispatchKeyEventPostIME(native_key_event);
+
+  // Let an IME handle the key event first.
+  if (input_method_context_->DispatchKeyEvent(native_key_event)) {
+    if (event_type == ET_KEY_PRESSED)
+      DispatchFabricatedKeyEventPostIME(ET_KEY_PRESSED, VKEY_PROCESSKEY,
+                                        EventFlagsFromNative(native_key_event));
+    return true;
+  }
+
+  // Otherwise, insert the character.
+  const bool handled = DispatchKeyEventPostIME(native_key_event);
+  if (event_type == ET_KEY_PRESSED && GetTextInputClient()) {
+    uint16 ch = 0;
+    const int flags = EventFlagsFromNative(native_key_event);
+    if (!(flags & EF_CONTROL_DOWN))
+      ch = GetCharacterFromXEvent(native_key_event);
+    if (!ch)
+      ch = GetCharacterFromKeyCode(KeyboardCodeFromNative(native_key_event),
+                                   flags);
+    if (ch) {
+      GetTextInputClient()->InsertChar(ch, flags);
+      return true;
+    }
+  }
+  return handled;
+}
+
+bool InputMethodLinuxX11::DispatchFabricatedKeyEvent(
+    const ui::KeyEvent& event) {
+  // Let a post IME handler handle the key event.
+  if (DispatchFabricatedKeyEventPostIME(event.type(), event.key_code(),
+                                        event.flags()))
+    return true;
+
+  // Otherwise, insert the character.
+  if (event.type() == ET_KEY_PRESSED && GetTextInputClient()) {
+    const uint16 ch = event.GetCharacter();
+    if (ch) {
+      GetTextInputClient()->InsertChar(ch, event.flags());
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void InputMethodLinuxX11::OnTextInputTypeChanged(
+    const TextInputClient* client) {
+  if (IsTextInputClientFocused(client)) {
+    input_method_context_->Reset();
+    // TODO(yoichio): Support inputmode HTML attribute.
+    input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
+  }
+  InputMethodBase::OnTextInputTypeChanged(client);
+}
+
+void InputMethodLinuxX11::OnCaretBoundsChanged(const TextInputClient* client) {
+  if (IsTextInputClientFocused(client)) {
+    input_method_context_->OnCaretBoundsChanged(
+        GetTextInputClient()->GetCaretBounds());
+  }
+  InputMethodBase::OnCaretBoundsChanged(client);
+}
+
+void InputMethodLinuxX11::CancelComposition(const TextInputClient* client) {
+  if (!IsTextInputClientFocused(client))
+    return;
+
+  input_method_context_->Reset();
+  input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
+}
+
+void InputMethodLinuxX11::OnInputLocaleChanged() {
+  InputMethodBase::OnInputLocaleChanged();
+}
+
+std::string InputMethodLinuxX11::GetInputLocale() {
+  return "";
+}
+
+base::i18n::TextDirection InputMethodLinuxX11::GetInputTextDirection() {
+  return input_method_context_->GetInputTextDirection();
+}
+
+bool InputMethodLinuxX11::IsActive() {
+  // InputMethodLinuxX11 is always ready and up.
+  return true;
+}
+
+bool InputMethodLinuxX11::IsCandidatePopupOpen() const {
+  // There seems no way to detect candidate windows or any popups.
+  return false;
+}
+
+// Overriden from ui::LinuxInputMethodContextDelegate
+
+void InputMethodLinuxX11::OnCommit(const base::string16& text) {
+  TextInputClient* text_input_client = GetTextInputClient();
+  if (text_input_client)
+    text_input_client->InsertText(text);
+}
+
+void InputMethodLinuxX11::OnPreeditChanged(
+    const CompositionText& composition_text) {
+  TextInputClient* text_input_client = GetTextInputClient();
+  if (text_input_client)
+    text_input_client->SetCompositionText(composition_text);
+}
+
+void InputMethodLinuxX11::OnPreeditEnd() {
+  TextInputClient* text_input_client = GetTextInputClient();
+  if (text_input_client && text_input_client->HasCompositionText())
+    text_input_client->ClearCompositionText();
+}
+
+void InputMethodLinuxX11::OnPreeditStart() {}
+
+// Overridden from InputMethodBase.
+
+void InputMethodLinuxX11::OnDidChangeFocusedClient(
+    TextInputClient* focused_before,
+    TextInputClient* focused) {
+  input_method_context_->Reset();
+  input_method_context_->OnTextInputTypeChanged(
+      focused ? focused->GetTextInputType() : TEXT_INPUT_TYPE_NONE);
+
+  InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/input_method_linux_x11.h b/ui/base/ime/input_method_linux_x11.h
new file mode 100644
index 0000000..027dfa5
--- /dev/null
+++ b/ui/base/ime/input_method_linux_x11.h
@@ -0,0 +1,61 @@
+// Copyright 2013 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_BASE_IME_INPUT_METHOD_LINUX_X11_H_
+#define UI_BASE_IME_INPUT_METHOD_LINUX_X11_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ime/input_method_base.h"
+#include "ui/base/ime/linux/linux_input_method_context.h"
+
+typedef struct _GtkIMContext GtkIMContext;
+
+namespace ui {
+
+// A ui::InputMethod implementation for a X11 event loop on GNU/Linux.
+// This class is not designed for supporting CrOS.  The implementation details
+// are separated to ui::LinuxInputMethodContext interface.
+class InputMethodLinuxX11 : public InputMethodBase,
+                            public LinuxInputMethodContextDelegate {
+ public:
+  explicit InputMethodLinuxX11(internal::InputMethodDelegate* delegate);
+  virtual ~InputMethodLinuxX11();
+
+  // Overriden from InputMethod.
+  virtual void Init(bool focused) OVERRIDE;
+  virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+                                        NativeEventResult* result) OVERRIDE;
+  virtual bool DispatchKeyEvent(const base::NativeEvent& native_key_event)
+      OVERRIDE;
+  virtual bool DispatchFabricatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+  virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
+  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
+  virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
+  virtual void OnInputLocaleChanged() OVERRIDE;
+  virtual std::string GetInputLocale() OVERRIDE;
+  virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
+  virtual bool IsActive() OVERRIDE;
+  virtual bool IsCandidatePopupOpen() const OVERRIDE;
+
+  // Overriden from ui::LinuxInputMethodContextDelegate
+  virtual void OnCommit(const base::string16& text) OVERRIDE;
+  virtual void OnPreeditChanged(const CompositionText& composition_text)
+      OVERRIDE;
+  virtual void OnPreeditEnd() OVERRIDE;
+  virtual void OnPreeditStart() OVERRIDE;
+
+ protected:
+  // Overridden from InputMethodBase.
+  virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
+                                        TextInputClient* focused) OVERRIDE;
+
+ private:
+  scoped_ptr<LinuxInputMethodContext> input_method_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(InputMethodLinuxX11);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_INPUT_METHOD_LINUX_X11_H_
diff --git a/ui/base/ime/input_method_tsf.cc b/ui/base/ime/input_method_tsf.cc
index aaec2e0..944f977 100644
--- a/ui/base/ime/input_method_tsf.cc
+++ b/ui/base/ime/input_method_tsf.cc
@@ -108,6 +108,7 @@
 void InputMethodTSF::OnCaretBoundsChanged(const TextInputClient* client) {
   if (IsTextInputClientFocused(client) && IsWindowFocused(client))
     ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
+  InputMethodWin::OnCaretBoundsChanged(client);
 }
 
 void InputMethodTSF::CancelComposition(const TextInputClient* client) {
diff --git a/ui/base/ime/input_method_win.cc b/ui/base/ime/input_method_win.cc
index bf679ed..adefd88 100644
--- a/ui/base/ime/input_method_win.cc
+++ b/ui/base/ime/input_method_win.cc
@@ -94,6 +94,7 @@
   locale_ = imm32_manager_.GetInputLanguageName();
   direction_ = imm32_manager_.GetTextDirection();
   OnInputMethodChanged();
+  InputMethodBase::OnInputLocaleChanged();
 }
 
 std::string InputMethodWin::GetInputLocale() {
@@ -148,10 +149,6 @@
   if (GetTextInputClient()) {
     GetTextInputClient()->InsertChar(static_cast<char16>(wparam),
                                      ui::GetModifiersFromKeyState());
-
-    // If Windows sends a WM_CHAR, then any previously sent WM_DEADCHARs (which
-    // are displayed as the composition text) should be cleared.
-    GetTextInputClient()->ClearCompositionText();
   }
 
   // Explicitly show the system menu at a good location on [Alt]+[Space].
@@ -168,21 +165,6 @@
                                    LPARAM lparam,
                                    BOOL* handled) {
   *handled = TRUE;
-
-  if (IsTextInputTypeNone())
-    return 0;
-
-  if (!GetTextInputClient())
-    return 0;
-
-  // Shows the dead character as a composition text, so that the user can know
-  // what dead key was pressed.
-  ui::CompositionText composition;
-  composition.text.assign(1, static_cast<char16>(wparam));
-  composition.selection = gfx::Range(0, 1);
-  composition.underlines.push_back(
-      ui::CompositionUnderline(0, 1, SK_ColorBLACK, false));
-  GetTextInputClient()->SetCompositionText(composition);
   return 0;
 }
 
diff --git a/ui/base/ime/input_method_win.h b/ui/base/ime/input_method_win.h
index c69f2db..5e6ffad 100644
--- a/ui/base/ime/input_method_win.h
+++ b/ui/base/ime/input_method_win.h
@@ -47,6 +47,8 @@
                  LPARAM lparam,
                  BOOL* handled);
   // For both WM_DEADCHAR and WM_SYSDEADCHAR
+  // TODO(yukawa): Stop handling WM_DEADCHAR and WM_SYSDEADCHAR when non-Aura
+  // build is deprecated.
   LRESULT OnDeadChar(UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
 
   LRESULT OnDocumentFeed(RECONVERTSTRING* reconv);
diff --git a/ui/base/ime/linux/fake_input_method_context.cc b/ui/base/ime/linux/fake_input_method_context.cc
new file mode 100644
index 0000000..d52aa8a
--- /dev/null
+++ b/ui/base/ime/linux/fake_input_method_context.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/linux/fake_input_method_context.h"
+
+namespace ui {
+
+FakeInputMethodContext::FakeInputMethodContext() {}
+
+// Overriden from ui::LinuxInputMethodContext
+
+bool FakeInputMethodContext::DispatchKeyEvent(
+    const base::NativeEvent& /* native_key_event */) {
+  return false;
+}
+
+void FakeInputMethodContext::Reset() {
+}
+
+base::i18n::TextDirection FakeInputMethodContext::GetInputTextDirection()
+    const {
+  return base::i18n::UNKNOWN_DIRECTION;
+}
+
+void FakeInputMethodContext::OnTextInputTypeChanged(
+    ui::TextInputType /* text_input_type */) {
+}
+
+void FakeInputMethodContext::OnCaretBoundsChanged(
+    const gfx::Rect& /* caret_bounds */) {
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/linux/fake_input_method_context.h b/ui/base/ime/linux/fake_input_method_context.h
new file mode 100644
index 0000000..c27d778
--- /dev/null
+++ b/ui/base/ime/linux/fake_input_method_context.h
@@ -0,0 +1,32 @@
+// Copyright 2013 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_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_H_
+#define UI_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_H_
+
+#include "ui/base/ime/linux/linux_input_method_context.h"
+
+namespace ui {
+
+// A fake implementation of LinuxInputMethodContext, which does nothing.
+class FakeInputMethodContext : public LinuxInputMethodContext {
+ public:
+  FakeInputMethodContext();
+
+  // Overriden from ui::LinuxInputMethodContext
+  virtual bool DispatchKeyEvent(const base::NativeEvent& native_key_event)
+      OVERRIDE;
+  virtual void Reset() OVERRIDE;
+  virtual base::i18n::TextDirection GetInputTextDirection() const OVERRIDE;
+  virtual void OnTextInputTypeChanged(ui::TextInputType text_input_type)
+      OVERRIDE;
+  virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeInputMethodContext);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_H_
diff --git a/ui/base/ime/linux/fake_input_method_context_factory.cc b/ui/base/ime/linux/fake_input_method_context_factory.cc
new file mode 100644
index 0000000..ba9edf6
--- /dev/null
+++ b/ui/base/ime/linux/fake_input_method_context_factory.cc
@@ -0,0 +1,21 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/linux/fake_input_method_context_factory.h"
+
+#include "ui/base/ime/linux/fake_input_method_context.h"
+
+namespace ui {
+
+FakeInputMethodContextFactory::FakeInputMethodContextFactory() {}
+
+// Overriden from ui::LinuxInputMethodContextFactory
+
+scoped_ptr<LinuxInputMethodContext>
+FakeInputMethodContextFactory::CreateInputMethodContext(
+    LinuxInputMethodContextDelegate* /* delegate */) const {
+  return scoped_ptr<LinuxInputMethodContext>(new FakeInputMethodContext());
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/linux/fake_input_method_context_factory.h b/ui/base/ime/linux/fake_input_method_context_factory.h
new file mode 100644
index 0000000..b2f6b43
--- /dev/null
+++ b/ui/base/ime/linux/fake_input_method_context_factory.h
@@ -0,0 +1,28 @@
+// Copyright 2013 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_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_FACTORY_H_
+#define UI_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_FACTORY_H_
+
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+
+namespace ui {
+
+// An implementation of LinuxInputMethodContextFactory, which creates and
+// returns FakeInputMethodContext's.
+class FakeInputMethodContextFactory : public LinuxInputMethodContextFactory {
+ public:
+  FakeInputMethodContextFactory();
+
+  // Overriden from ui::LinuxInputMethodContextFactory
+  virtual scoped_ptr<LinuxInputMethodContext> CreateInputMethodContext(
+      LinuxInputMethodContextDelegate* delegate) const OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeInputMethodContextFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_LINUX_FAKE_INPUT_METHOD_CONTEXT_FACTORY_H_
diff --git a/ui/base/ime/linux/linux_input_method_context.h b/ui/base/ime/linux/linux_input_method_context.h
new file mode 100644
index 0000000..2c13a5c
--- /dev/null
+++ b/ui/base/ime/linux/linux_input_method_context.h
@@ -0,0 +1,69 @@
+// Copyright 2013 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_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_H_
+#define UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_H_
+
+#include "base/event_types.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/string16.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/base/ui_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+struct CompositionText;
+
+// An interface of input method context for input method frameworks on
+// GNU/Linux and likes.
+class UI_EXPORT LinuxInputMethodContext {
+ public:
+  virtual ~LinuxInputMethodContext() {}
+
+  // Dispatches the key event to an underlying IME.  Returns true if the key
+  // event is handled, otherwise false.  A client must set the text input type
+  // before dispatching a key event.
+  virtual bool DispatchKeyEvent(const base::NativeEvent& native_key_event) = 0;
+
+  // Resets the context.  A client needs to call OnTextInputTypeChanged() again
+  // before calling DispatchKeyEvent().
+  virtual void Reset() = 0;
+
+  // Returns the text direction of the current keyboard layout or input method.
+  virtual base::i18n::TextDirection GetInputTextDirection() const = 0;
+
+  // Notifies the context that the text input type has changed.
+  virtual void OnTextInputTypeChanged(TextInputType text_input_type) = 0;
+
+  // Notifies the context that the caret bounds have changed.  |caret_bounds| is
+  // relative to screen coordinates.
+  virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) = 0;
+};
+
+// An interface of callback functions called from LinuxInputMethodContext.
+class UI_EXPORT LinuxInputMethodContextDelegate {
+ public:
+  virtual ~LinuxInputMethodContextDelegate() {}
+
+  // Commits the |text| to the text input client.
+  virtual void OnCommit(const base::string16& text) = 0;
+
+  // Sets the composition text to the text input client.
+  virtual void OnPreeditChanged(const CompositionText& composition_text) = 0;
+
+  // Cleans up a composition session and makes sure that the composition text is
+  // cleared.
+  virtual void OnPreeditEnd() = 0;
+
+  // Prepares things for a new composition session.
+  virtual void OnPreeditStart() = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_H_
diff --git a/ui/base/ime/linux/linux_input_method_context_factory.cc b/ui/base/ime/linux/linux_input_method_context_factory.cc
new file mode 100644
index 0000000..4ba27502
--- /dev/null
+++ b/ui/base/ime/linux/linux_input_method_context_factory.cc
@@ -0,0 +1,28 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+
+namespace {
+
+const ui::LinuxInputMethodContextFactory* g_linux_input_method_context_factory =
+    NULL;
+
+}  // namespace
+
+namespace ui {
+
+// static
+const LinuxInputMethodContextFactory*
+LinuxInputMethodContextFactory::instance() {
+  return g_linux_input_method_context_factory;
+}
+
+// static
+void LinuxInputMethodContextFactory::SetInstance(
+    const LinuxInputMethodContextFactory* instance) {
+  g_linux_input_method_context_factory = instance;
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/linux/linux_input_method_context_factory.h b/ui/base/ime/linux/linux_input_method_context_factory.h
new file mode 100644
index 0000000..8ce1ec2
--- /dev/null
+++ b/ui/base/ime/linux/linux_input_method_context_factory.h
@@ -0,0 +1,38 @@
+// Copyright 2013 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_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_FACTORY_H_
+#define UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ui_export.h"
+
+namespace ui {
+
+class LinuxInputMethodContext;
+class LinuxInputMethodContextDelegate;
+
+// An interface that lets different Linux platforms override the
+// CreateInputMethodContext function declared here to return native input method
+// contexts.
+class UI_EXPORT LinuxInputMethodContextFactory {
+ public:
+  // Returns the current active factory or NULL.
+  static const LinuxInputMethodContextFactory* instance();
+
+  // Sets the dynamically loaded singleton that creates an input method context.
+  // This pointer is not owned, and if this method is called a second time,
+  // the first instance is not deleted.
+  static void SetInstance(const LinuxInputMethodContextFactory* instance);
+
+  virtual ~LinuxInputMethodContextFactory() {}
+
+  // Returns a native input method context.
+  virtual scoped_ptr<LinuxInputMethodContext> CreateInputMethodContext(
+      LinuxInputMethodContextDelegate* delegate) const = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_FACTORY_H_
diff --git a/ui/base/ime/mock_input_method.cc b/ui/base/ime/mock_input_method.cc
index c5fa4e2..48b2ca0 100644
--- a/ui/base/ime/mock_input_method.cc
+++ b/ui/base/ime/mock_input_method.cc
@@ -7,8 +7,7 @@
 namespace ui {
 
 MockInputMethod::MockInputMethod(internal::InputMethodDelegate* delegate)
-    : text_input_client_(NULL),
-      is_sticky_text_input_client_(false) {
+    : text_input_client_(NULL) {
 }
 
 MockInputMethod::~MockInputMethod() {
@@ -18,17 +17,6 @@
 }
 
 void MockInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
-  if (is_sticky_text_input_client_)
-    return;
-  if (text_input_client_ == client)
-    return;
-  text_input_client_ = client;
-  if (client)
-    OnTextInputTypeChanged(client);
-}
-
-void MockInputMethod::SetStickyFocusedTextInputClient(TextInputClient* client) {
-  is_sticky_text_input_client_ = (client != NULL);
   if (text_input_client_ == client)
     return;
   text_input_client_ = client;
@@ -39,7 +27,6 @@
 void MockInputMethod::DetachTextInputClient(TextInputClient* client) {
   if (text_input_client_ == client) {
     text_input_client_ = NULL;
-    is_sticky_text_input_client_ = false;
   }
 }
 
diff --git a/ui/base/ime/mock_input_method.h b/ui/base/ime/mock_input_method.h
index d1e2e8d..c60f3db 100644
--- a/ui/base/ime/mock_input_method.h
+++ b/ui/base/ime/mock_input_method.h
@@ -36,8 +36,6 @@
   virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
                                         NativeEventResult* result) OVERRIDE;
   virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE;
-  virtual void SetStickyFocusedTextInputClient(
-      TextInputClient* client) OVERRIDE;
   virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE;
   virtual TextInputClient* GetTextInputClient() const OVERRIDE;
   virtual bool DispatchKeyEvent(const base::NativeEvent& native_event) OVERRIDE;
@@ -58,7 +56,6 @@
 
  private:
   TextInputClient* text_input_client_;
-  bool is_sticky_text_input_client_;
   ObserverList<InputMethodObserver> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 9029b07..3a48203 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -442,7 +442,7 @@
     return E_INVALIDARG;
   }
   *acp_result_start = acp_test_start;
-  *acp_result_end = acp_test_start + text_size;
+  *acp_result_end = acp_test_end;
   return S_OK;
 }
 
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index f902428..3a23ef7 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -124,6 +124,10 @@
     text_store_ = NULL;
   }
 
+  // Accessors to the internal state of TSFTextStore.
+  string16* string_buffer() { return &text_store_->string_buffer_; }
+  size_t* committed_size() { return &text_store_->committed_size_; }
+
   base::win::ScopedCOMInitializer com_initializer_;
   MockTextInputClient text_input_client_;
   scoped_refptr<TSFTextStore> text_store_;
@@ -304,6 +308,43 @@
   EXPECT_EQ(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT, status.dwStaticFlags);
 }
 
+TEST_F(TSFTextStoreTest, QueryInsertTest) {
+  LONG result_start = 0;
+  LONG result_end = 0;
+  *string_buffer() = L"";
+  *committed_size() = 0;
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(0, 0, 0, NULL, &result_end));
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(0, 0, 0, &result_start, NULL));
+  EXPECT_EQ(S_OK,
+            text_store_->QueryInsert(0, 0, 0, &result_start, &result_end));
+  EXPECT_EQ(0, result_start);
+  EXPECT_EQ(0, result_end);
+  *string_buffer() = L"1234";
+  *committed_size() = 1;
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(0, 1, 0, &result_start, &result_end));
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(1, 0, 0, &result_start, &result_end));
+  EXPECT_EQ(S_OK,
+            text_store_->QueryInsert(2, 2, 0, &result_start, &result_end));
+  EXPECT_EQ(2, result_start);
+  EXPECT_EQ(2, result_end);
+  EXPECT_EQ(S_OK,
+            text_store_->QueryInsert(2, 3, 0, &result_start, &result_end));
+  EXPECT_EQ(2, result_start);
+  EXPECT_EQ(3, result_end);
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(3, 2, 0, &result_start, &result_end));
+  EXPECT_EQ(S_OK,
+            text_store_->QueryInsert(3, 4, 0, &result_start, &result_end));
+  EXPECT_EQ(3, result_start);
+  EXPECT_EQ(4, result_end);
+  EXPECT_EQ(E_INVALIDARG,
+            text_store_->QueryInsert(3, 5, 0, &result_start, &result_end));
+}
+
 class SyncRequestLockTestCallback : public TSFTextStoreTestCallback {
  public:
   explicit SyncRequestLockTestCallback(TSFTextStore* text_store)
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 8e8253f..c0338c0 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -673,9 +673,9 @@
   return str;
 }
 
-static string16 GetStringF(int message_id,
-                           const std::vector<string16>& replacements,
-                           std::vector<size_t>* offsets) {
+string16 GetStringFUTF16(int message_id,
+                         const std::vector<string16>& replacements,
+                         std::vector<size_t>* offsets) {
   // TODO(tc): We could save a string copy if we got the raw string as
   // a StringPiece and were able to call ReplaceStringPlaceholders with
   // a StringPiece format string and string16 substitution strings.  In
@@ -748,7 +748,7 @@
                          const string16& a) {
   std::vector<string16> replacements;
   replacements.push_back(a);
-  return GetStringF(message_id, replacements, NULL);
+  return GetStringFUTF16(message_id, replacements, NULL);
 }
 
 string16 GetStringFUTF16(int message_id,
@@ -765,7 +765,7 @@
   replacements.push_back(a);
   replacements.push_back(b);
   replacements.push_back(c);
-  return GetStringF(message_id, replacements, NULL);
+  return GetStringFUTF16(message_id, replacements, NULL);
 }
 
 string16 GetStringFUTF16(int message_id,
@@ -778,7 +778,7 @@
   replacements.push_back(b);
   replacements.push_back(c);
   replacements.push_back(d);
-  return GetStringF(message_id, replacements, NULL);
+  return GetStringFUTF16(message_id, replacements, NULL);
 }
 
 string16 GetStringFUTF16(int message_id,
@@ -793,7 +793,7 @@
   replacements.push_back(c);
   replacements.push_back(d);
   replacements.push_back(e);
-  return GetStringF(message_id, replacements, NULL);
+  return GetStringFUTF16(message_id, replacements, NULL);
 }
 
 string16 GetStringFUTF16(int message_id, const string16& a, size_t* offset) {
@@ -801,7 +801,7 @@
   std::vector<size_t> offsets;
   std::vector<string16> replacements;
   replacements.push_back(a);
-  string16 result = GetStringF(message_id, replacements, &offsets);
+  string16 result = GetStringFUTF16(message_id, replacements, &offsets);
   DCHECK(offsets.size() == 1);
   *offset = offsets[0];
   return result;
@@ -814,7 +814,7 @@
   std::vector<string16> replacements;
   replacements.push_back(a);
   replacements.push_back(b);
-  return GetStringF(message_id, replacements, offsets);
+  return GetStringFUTF16(message_id, replacements, offsets);
 }
 
 string16 GetStringFUTF16Int(int message_id, int a) {
diff --git a/ui/base/l10n/l10n_util.h b/ui/base/l10n/l10n_util.h
index 57793ec..2207e6d 100644
--- a/ui/base/l10n/l10n_util.h
+++ b/ui/base/l10n/l10n_util.h
@@ -90,8 +90,15 @@
 UI_EXPORT std::string GetStringUTF8(int message_id);
 UI_EXPORT string16 GetStringUTF16(int message_id);
 
-// Get a resource string and replace $1-$2-$3 with |a| and |b|
-// respectively.  Additionally, $$ is replaced by $.
+// Get a resource string and replace $i with replacements[i] for all
+// i < replacements.size(). Additionally, $$ is replaced by $.
+// If non-NULL |offsets| will be replaced with the start points of the replaced
+// strings.
+UI_EXPORT string16 GetStringFUTF16(int message_id,
+                                   const std::vector<string16>& replacements,
+                                   std::vector<size_t>* offsets);
+
+// Convenience wrappers for the above.
 UI_EXPORT string16 GetStringFUTF16(int message_id,
                                    const string16& a);
 UI_EXPORT string16 GetStringFUTF16(int message_id,
diff --git a/ui/base/strings/ui_strings.grd b/ui/base/strings/ui_strings.grd
index 5906138..cfe78f4 100644
--- a/ui/base/strings/ui_strings.grd
+++ b/ui/base/strings/ui_strings.grd
@@ -1599,6 +1599,9 @@
       <message name="IDS_APP_LIST_OPEN_FEEDBACK" desc="The menu entry to show the feedback UI.">
         Send feedback
       </message>
+      <message name="IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER" desc="The placeholder text for app list folder name.">
+        Unnamed Folder
+      </message>  
     </messages>
   </release>
 </grit>
diff --git a/ui/base/strings/ui_strings_ar.xtb b/ui/base/strings/ui_strings_ar.xtb
index 745b50e..29d95e8 100644
--- a/ui/base/strings/ui_strings_ar.xtb
+++ b/ui/base/strings/ui_strings_ar.xtb
@@ -98,7 +98,7 @@
 <translation id="7634624804467787019"><ph name="NUMBER_ONE"/> دقيقة واحدة</translation>
 <translation id="8448317557906454022">قبل <ph name="NUMBER_ZERO"/> ثانية</translation>
 <translation id="4927753642311223124">ليس هناك شيء تراه هنا، انتقل إلى مكان آخر.</translation>
-<translation id="2482878487686419369">التنبيهات</translation>
+<translation id="2482878487686419369">الاشعارات</translation>
 <translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> يوم</translation>
 <translation id="3183922693828471536">التمرير إلى هنا</translation>
 <translation id="4552416320897244156">‏مفتاح PgDwn (صفحة إلى أسفل)</translation>
diff --git a/ui/base/test/ui_controls_internal_win.cc b/ui/base/test/ui_controls_internal_win.cc
index 2521b98..45b8f45 100644
--- a/ui/base/test/ui_controls_internal_win.cc
+++ b/ui/base/test/ui_controls_internal_win.cc
@@ -12,12 +12,6 @@
 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
-// TODO(beng): wtf is this? layering violation!!!1
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#endif
-
 namespace {
 
 // InputDispatcher ------------------------------------------------------------
diff --git a/ui/base/test/ui_controls_win.cc b/ui/base/test/ui_controls_win.cc
index 65de0a1..fc3f6ea 100644
--- a/ui/base/test/ui_controls_win.cc
+++ b/ui/base/test/ui_controls_win.cc
@@ -8,7 +8,6 @@
 #include "base/message_loop/message_loop.h"
 #include "ui/base/test/ui_controls_internal_win.h"
 #include "ui/gfx/point.h"
-#include "ui/views/view.h"
 
 namespace ui_controls {
 bool g_ui_controls_enabled = false;
diff --git a/ui/base/touch/touch_device.cc b/ui/base/touch/touch_device.cc
index de7785c..944ba17 100644
--- a/ui/base/touch/touch_device.cc
+++ b/ui/base/touch/touch_device.cc
@@ -12,4 +12,8 @@
   return false;
 }
 
+int MaxTouchPoints() {
+  return 0;
+}
+
 }  // namespace ui
diff --git a/ui/base/touch/touch_device.h b/ui/base/touch/touch_device.h
index 8cc4b7d..b06c564 100644
--- a/ui/base/touch/touch_device.h
+++ b/ui/base/touch/touch_device.h
@@ -9,9 +9,23 @@
 
 namespace ui {
 
+// TODO(sblom): This is non-standard, and should be removed before
+// RuntimeEnabledFlags::PointerEventsMaxTouchPoints is marked stable.
+// Tracked by: http://crbug.com/308649
+const int kMaxTouchPointsUnknown = -1;
+
 // Returns true if a touch device is available.
 UI_EXPORT bool IsTouchDevicePresent();
 
+// Returns the maximum number of simultaneous touch contacts supported
+// by the device. In the case of devices with multiple digitizers (e.g.
+// multiple touchscreens), the value MUST be the maximum of the set of
+// maximum supported contacts by each individual digitizer.
+// For example, suppose a device has 3 touchscreens, which support 2, 5,
+// and 10 simultaneous touch contacts, respectively. This returns 10.
+// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints
+UI_EXPORT int MaxTouchPoints();
+
 }  // namespace ui
 
 #endif  // UI_BASE_TOUCH_TOUCH_DEVICE_H_
diff --git a/ui/base/touch/touch_device_android.cc b/ui/base/touch/touch_device_android.cc
index 39e34c2..2b359c0 100644
--- a/ui/base/touch/touch_device_android.cc
+++ b/ui/base/touch/touch_device_android.cc
@@ -10,4 +10,17 @@
   return true;
 }
 
+// Looks like the best we can do here is detect 1, 2+, or 5+ by
+// feature detecting:
+// FEATURE_TOUCHSCREEN (1),
+// FEATURE_TOUCHSCREEN_MULTITOUCH (2),
+// FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT (2+), or
+// FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHANDS (5+)
+//
+// Probably start from the biggest and detect down the list until we
+// find one that's supported and return its value.
+int MaxTouchPoints() {
+  return kMaxTouchPointsUnknown;
+}
+
 }  // namespace ui
diff --git a/ui/base/touch/touch_device_aurax11.cc b/ui/base/touch/touch_device_aurax11.cc
index 04d435e..d3b6df4 100644
--- a/ui/base/touch/touch_device_aurax11.cc
+++ b/ui/base/touch/touch_device_aurax11.cc
@@ -11,4 +11,8 @@
   return ui::TouchFactory::GetInstance()->IsTouchDevicePresent();
 }
 
+int MaxTouchPoints() {
+  return kMaxTouchPointsUnknown;
+}
+
 }  // namespace ui
diff --git a/ui/base/touch/touch_device_ozone.cc b/ui/base/touch/touch_device_ozone.cc
index 7cb2ecb..d97a70b 100644
--- a/ui/base/touch/touch_device_ozone.cc
+++ b/ui/base/touch/touch_device_ozone.cc
@@ -11,4 +11,8 @@
   return true;
 }
 
+int MaxTouchPoints() {
+  return kMaxTouchPointsUnknown;
+}
+
 }  // namespace ui
diff --git a/ui/base/touch/touch_device_win.cc b/ui/base/touch/touch_device_win.cc
index c07fbe9..ba5c260 100644
--- a/ui/base/touch/touch_device_win.cc
+++ b/ui/base/touch/touch_device_win.cc
@@ -14,4 +14,8 @@
       ((value & NID_INTEGRATED_TOUCH) || (value & NID_EXTERNAL_TOUCH));
 }
 
+int MaxTouchPoints() {
+  return GetSystemMetrics(SM_MAXIMUMTOUCHES);
+}
+
 }  // namespace ui
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 6266f00..0605f62 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -18,26 +18,18 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "cc/base/switches.h"
-#include "cc/debug/test_context_provider.h"
-#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/input/input_handler.h"
 #include "cc/layers/layer.h"
 #include "cc/output/context_provider.h"
-#include "cc/output/output_surface.h"
 #include "cc/trees/layer_tree_host.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/reflector.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gl/gl_context.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_switches.h"
-#include "webkit/common/gpu/context_provider_in_process.h"
-#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
 namespace {
 
@@ -52,7 +44,6 @@
 bool g_compositor_initialized = false;
 base::Thread* g_compositor_thread = NULL;
 
-ui::ContextFactory* g_implicit_factory = NULL;
 ui::ContextFactory* g_context_factory = NULL;
 
 const int kCompositorLockTimeoutMs = 67;
@@ -90,141 +81,6 @@
   g_context_factory = instance;
 }
 
-DefaultContextFactory::DefaultContextFactory() {
-}
-
-DefaultContextFactory::~DefaultContextFactory() {
-}
-
-bool DefaultContextFactory::Initialize() {
-  if (!gfx::GLSurface::InitializeOneOff() ||
-      gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
-    LOG(ERROR) << "Could not load the GL bindings";
-    return false;
-  }
-  return true;
-}
-
-scoped_ptr<cc::OutputSurface> DefaultContextFactory::CreateOutputSurface(
-    Compositor* compositor) {
-  WebKit::WebGraphicsContext3D::Attributes attrs;
-  attrs.depth = false;
-  attrs.stencil = false;
-  attrs.antialias = false;
-  attrs.shareResources = true;
-
-  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
-  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d(
-      WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
-          attrs, compositor->widget()));
-  CHECK(context3d);
-
-  using webkit::gpu::ContextProviderInProcess;
-  scoped_refptr<ContextProviderInProcess> context_provider =
-      ContextProviderInProcess::Create(context3d.Pass(),
-                                       "UICompositor");
-
-  return make_scoped_ptr(new cc::OutputSurface(context_provider));
-}
-
-scoped_refptr<Reflector> DefaultContextFactory::CreateReflector(
-    Compositor* mirroed_compositor,
-    Layer* mirroring_layer) {
-  return NULL;
-}
-
-void DefaultContextFactory::RemoveReflector(
-    scoped_refptr<Reflector> reflector) {
-}
-
-scoped_refptr<cc::ContextProvider>
-DefaultContextFactory::OffscreenCompositorContextProvider() {
-  if (!offscreen_compositor_contexts_.get() ||
-      !offscreen_compositor_contexts_->DestroyedOnMainThread()) {
-    offscreen_compositor_contexts_ =
-        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
-  }
-  return offscreen_compositor_contexts_;
-}
-
-scoped_refptr<cc::ContextProvider>
-DefaultContextFactory::SharedMainThreadContextProvider() {
-  if (shared_main_thread_contexts_ &&
-      !shared_main_thread_contexts_->DestroyedOnMainThread())
-    return shared_main_thread_contexts_;
-
-  if (ui::Compositor::WasInitializedWithThread()) {
-    shared_main_thread_contexts_ =
-        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
-  } else {
-    shared_main_thread_contexts_ =
-        static_cast<webkit::gpu::ContextProviderInProcess*>(
-            OffscreenCompositorContextProvider().get());
-  }
-  if (shared_main_thread_contexts_ &&
-      !shared_main_thread_contexts_->BindToCurrentThread())
-    shared_main_thread_contexts_ = NULL;
-
-  return shared_main_thread_contexts_;
-}
-
-void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
-}
-
-bool DefaultContextFactory::DoesCreateTestContexts() { return false; }
-
-TestContextFactory::TestContextFactory() {}
-
-TestContextFactory::~TestContextFactory() {}
-
-scoped_ptr<cc::OutputSurface> TestContextFactory::CreateOutputSurface(
-    Compositor* compositor) {
-  return make_scoped_ptr(
-      new cc::OutputSurface(cc::TestContextProvider::Create()));
-}
-
-scoped_refptr<Reflector> TestContextFactory::CreateReflector(
-    Compositor* mirrored_compositor,
-    Layer* mirroring_layer) {
-  return new Reflector();
-}
-
-void TestContextFactory::RemoveReflector(scoped_refptr<Reflector> reflector) {
-}
-
-scoped_refptr<cc::ContextProvider>
-TestContextFactory::OffscreenCompositorContextProvider() {
-  if (!offscreen_compositor_contexts_.get() ||
-      offscreen_compositor_contexts_->DestroyedOnMainThread())
-    offscreen_compositor_contexts_ = cc::TestContextProvider::Create();
-  return offscreen_compositor_contexts_;
-}
-
-scoped_refptr<cc::ContextProvider>
-TestContextFactory::SharedMainThreadContextProvider() {
-  if (shared_main_thread_contexts_ &&
-      !shared_main_thread_contexts_->DestroyedOnMainThread())
-    return shared_main_thread_contexts_;
-
-  if (ui::Compositor::WasInitializedWithThread()) {
-    shared_main_thread_contexts_ = cc::TestContextProvider::Create();
-  } else {
-    shared_main_thread_contexts_ =
-        static_cast<cc::TestContextProvider*>(
-            OffscreenCompositorContextProvider().get());
-  }
-  if (shared_main_thread_contexts_ &&
-      !shared_main_thread_contexts_->BindToCurrentThread())
-    shared_main_thread_contexts_ = NULL;
-
-  return shared_main_thread_contexts_;
-}
-
-void TestContextFactory::RemoveCompositor(Compositor* compositor) {
-}
-
-bool TestContextFactory::DoesCreateTestContexts() { return true; }
-
 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
     : size_(size),
       flipped_(flipped),
@@ -375,7 +231,8 @@
 
 namespace ui {
 
-Compositor::Compositor(gfx::AcceleratedWidget widget)
+Compositor::Compositor(bool use_software_renderer,
+                       gfx::AcceleratedWidget widget)
     : root_layer_(NULL),
       widget_(widget),
       posted_swaps_(new PostedSwapQueue()),
@@ -388,7 +245,8 @@
       defer_draw_scheduling_(false),
       waiting_on_compositing_end_(false),
       draw_on_compositing_end_(false),
-      schedule_draw_factory_(this) {
+      schedule_draw_factory_(this),
+      use_software_renderer_(use_software_renderer) {
   DCHECK(g_compositor_initialized)
       << "Compositor::Initialize must be called before creating a Compositor.";
 
@@ -432,7 +290,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner =
       g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL;
 
-  host_ = cc::LayerTreeHost::Create(this, settings, compositor_task_runner);
+  host_ =
+      cc::LayerTreeHost::Create(this, NULL, settings, compositor_task_runner);
   host_->SetRootLayer(root_web_layer_);
   host_->SetLayerTreeHostClientReady();
 }
@@ -456,44 +315,6 @@
 }
 
 // static
-void Compositor::InitializeContextFactoryForTests(bool allow_test_contexts) {
-  // The factory may already have been initialized by the content layer, in
-  // which case, use that one.
-  if (g_context_factory)
-    return;
-  DCHECK(!g_implicit_factory) <<
-      "ContextFactory for tests already initialized.";
-
-  bool use_test_contexts = true;
-
-  // Always use test contexts unless the disable command line flag is used.
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kDisableTestCompositor))
-    use_test_contexts = false;
-
-#if defined(OS_CHROMEOS)
-  // If the test is running on the chromeos envrionment (such as
-  // device or vm bots), always use real contexts.
-  if (base::SysInfo::IsRunningOnChromeOS())
-    use_test_contexts = false;
-#endif
-
-  if (!allow_test_contexts)
-    use_test_contexts = false;
-
-  if (use_test_contexts) {
-    g_implicit_factory = new ui::TestContextFactory;
-  } else {
-    DVLOG(1) << "Using DefaultContextFactory";
-    scoped_ptr<ui::DefaultContextFactory> instance(
-        new ui::DefaultContextFactory());
-    if (instance->Initialize())
-      g_implicit_factory = instance.release();
-  }
-  g_context_factory = g_implicit_factory;
-}
-
-// static
 void Compositor::Initialize() {
 #if defined(OS_CHROMEOS)
   bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
@@ -530,17 +351,7 @@
 
 // static
 void Compositor::Terminate() {
-  if (g_context_factory) {
-    if (g_implicit_factory) {
-      delete g_implicit_factory;
-      g_implicit_factory = NULL;
-    }
-    g_context_factory = NULL;
-  }
-
   if (g_compositor_thread) {
-    DCHECK(!g_context_factory)
-        << "The ContextFactory should not outlive the compositor thread.";
     g_compositor_thread->Stop();
     delete g_compositor_thread;
     g_compositor_thread = NULL;
@@ -552,7 +363,7 @@
 
 void Compositor::ScheduleDraw() {
   if (g_compositor_thread) {
-    host_->Composite(base::TimeTicks::Now());
+    host_->Composite(gfx::FrameTime::Now());
   } else if (!defer_draw_scheduling_) {
     defer_draw_scheduling_ = true;
     base::MessageLoop::current()->PostTask(
@@ -600,7 +411,7 @@
     // TODO(nduca): Temporary while compositor calls
     // compositeImmediately() directly.
     Layout();
-    host_->Composite(base::TimeTicks::Now());
+    host_->Composite(gfx::FrameTime::Now());
 
 #if defined(OS_WIN)
     // While we resize, we are usually a few frames behind. By blocking
@@ -737,7 +548,7 @@
 }
 
 void Compositor::DidCommitAndDrawFrame() {
-  base::TimeTicks start_time = base::TimeTicks::Now();
+  base::TimeTicks start_time = gfx::FrameTime::Now();
   FOR_EACH_OBSERVER(CompositorObserver,
                     observer_list_,
                     OnCompositingStarted(this, start_time));
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 00c6873..5c6291f 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -20,7 +20,6 @@
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gl/gl.gyp:gl',
         '<(DEPTH)/ui/ui.gyp:ui',
-        '<(DEPTH)/webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
       ],
       'defines': [
         'COMPOSITOR_IMPLEMENTATION',
@@ -78,16 +77,25 @@
       'type': 'static_library',
       'dependencies': [
         '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/cc/cc.gyp:cc',
         '<(DEPTH)/skia/skia.gyp:skia',
+        '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink_minimal',
         '<(DEPTH)/ui/events/events.gyp:events',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gl/gl.gyp:gl',
         '<(DEPTH)/ui/ui.gyp:ui',
+        '<(DEPTH)/webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
         'compositor',
       ],
       'sources': [
         'test/test_layers.cc',
         'test/test_layers.h',
+        'test/test_context_factory.cc',
+        'test/test_context_factory.h',
+        'test/default_context_factory.cc',
+        'test/default_context_factory.h',
+        'test/context_factories_for_test.cc',
+        'test/context_factories_for_test.h',
         'test/test_suite.cc',
         'test/test_suite.h',
       ],
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index ecf9c03..513822a 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -34,7 +34,6 @@
 class Layer;
 class LayerTreeDebugState;
 class LayerTreeHost;
-class TestContextProvider;
 }
 
 namespace gfx {
@@ -117,68 +116,6 @@
   virtual bool DoesCreateTestContexts() = 0;
 };
 
-// The default factory that creates in-process contexts.
-class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory {
- public:
-  DefaultContextFactory();
-  virtual ~DefaultContextFactory();
-
-  // ContextFactory implementation
-  virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
-      Compositor* compositor) OVERRIDE;
-
-  virtual scoped_refptr<Reflector> CreateReflector(
-      Compositor* compositor,
-      Layer* layer) OVERRIDE;
-  virtual void RemoveReflector(scoped_refptr<Reflector> reflector) OVERRIDE;
-
-  virtual scoped_refptr<cc::ContextProvider>
-      OffscreenCompositorContextProvider() OVERRIDE;
-  virtual scoped_refptr<cc::ContextProvider>
-      SharedMainThreadContextProvider() OVERRIDE;
-  virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
-  virtual bool DoesCreateTestContexts() OVERRIDE;
-
-  bool Initialize();
-
- private:
-  scoped_refptr<webkit::gpu::ContextProviderInProcess>
-      offscreen_compositor_contexts_;
-  scoped_refptr<webkit::gpu::ContextProviderInProcess>
-      shared_main_thread_contexts_;
-
-  DISALLOW_COPY_AND_ASSIGN(DefaultContextFactory);
-};
-
-// The factory that creates test contexts.
-class COMPOSITOR_EXPORT TestContextFactory : public ContextFactory {
- public:
-  TestContextFactory();
-  virtual ~TestContextFactory();
-
-  // ContextFactory implementation
-  virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
-      Compositor* compositor) OVERRIDE;
-
-  virtual scoped_refptr<Reflector> CreateReflector(
-      Compositor* mirrored_compositor,
-      Layer* mirroring_layer) OVERRIDE;
-  virtual void RemoveReflector(scoped_refptr<Reflector> reflector) OVERRIDE;
-
-  virtual scoped_refptr<cc::ContextProvider>
-      OffscreenCompositorContextProvider() OVERRIDE;
-  virtual scoped_refptr<cc::ContextProvider>
-      SharedMainThreadContextProvider() OVERRIDE;
-  virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
-  virtual bool DoesCreateTestContexts() OVERRIDE;
-
- private:
-  scoped_refptr<cc::TestContextProvider> offscreen_compositor_contexts_;
-  scoped_refptr<cc::TestContextProvider> shared_main_thread_contexts_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestContextFactory);
-};
-
 // Texture provide an abstraction over the external texture that can be passed
 // to a layer.
 class COMPOSITOR_EXPORT Texture : public base::RefCounted<Texture> {
@@ -284,17 +221,10 @@
     : NON_EXPORTED_BASE(public cc::LayerTreeHostClient),
       public base::SupportsWeakPtr<Compositor> {
  public:
-  explicit Compositor(gfx::AcceleratedWidget widget);
+  Compositor(bool use_software_renderer,
+             gfx::AcceleratedWidget widget);
   virtual ~Compositor();
 
-  // Set up the compositor ContextFactory for a test environment. Unit tests
-  // that do not have a full content environment need to call this before
-  // initializing the Compositor.
-  // Some tests expect pixel output, and they should pass false for
-  // |allow_test_contexts|. Most unit tests should pass true. Once this has been
-  // called, the Initialize() and Terminate() methods should be used as normal.
-  static void InitializeContextFactoryForTests(bool allow_test_contexts);
-
   static void Initialize();
   static bool WasInitializedWithThread();
   static scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop();
@@ -379,8 +309,8 @@
                                base::TimeDelta interval);
 
   // LayerTreeHostClient implementation.
-  virtual void WillBeginFrame() OVERRIDE {}
-  virtual void DidBeginFrame() OVERRIDE {}
+  virtual void WillBeginMainFrame() OVERRIDE {}
+  virtual void DidBeginMainFrame() OVERRIDE {}
   virtual void Animate(double frame_begin_time) OVERRIDE {}
   virtual void Layout() OVERRIDE;
   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
@@ -404,6 +334,10 @@
   const cc::LayerTreeDebugState& GetLayerTreeDebugState() const;
   void SetLayerTreeDebugState(const cc::LayerTreeDebugState& debug_state);
 
+  // Should the compositor use a software output device. If false, it may still
+  // use a software output device if no GPU is available.
+  bool use_software_renderer() { return use_software_renderer_; }
+
  private:
   friend class base::RefCounted<Compositor>;
   friend class CompositorLock;
@@ -453,6 +387,8 @@
 
   base::WeakPtrFactory<Compositor> schedule_draw_factory_;
 
+  bool use_software_renderer_;
+
   DISALLOW_COPY_AND_ASSIGN(Compositor);
 };
 
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc
index dd857d1..76f8ab7 100644
--- a/ui/compositor/layer_animation_element.cc
+++ b/ui/compositor/layer_animation_element.cc
@@ -345,19 +345,8 @@
   }
 
   virtual bool OnProgress(double t, LayerAnimationDelegate* delegate) OVERRIDE {
-    delegate->SetColorFromAnimation(SkColorSetARGB(
-        gfx::Tween::IntValueBetween(t,
-                                    static_cast<int>(SkColorGetA(start_)),
-                                    static_cast<int>(SkColorGetA(target_))),
-        gfx::Tween::IntValueBetween(t,
-                                    static_cast<int>(SkColorGetR(start_)),
-                                    static_cast<int>(SkColorGetR(target_))),
-        gfx::Tween::IntValueBetween(t,
-                                    static_cast<int>(SkColorGetG(start_)),
-                                    static_cast<int>(SkColorGetG(target_))),
-        gfx::Tween::IntValueBetween(t,
-                                    static_cast<int>(SkColorGetB(start_)),
-                                    static_cast<int>(SkColorGetB(target_)))));
+    delegate->SetColorFromAnimation(
+        gfx::Tween::ColorValueBetween(t, start_, target_));
     return true;
   }
 
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc
index c287574..dd727a6 100644
--- a/ui/compositor/layer_animator.cc
+++ b/ui/compositor/layer_animator.cc
@@ -8,12 +8,14 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "cc/animation/animation_id_provider.h"
+#include "cc/output/begin_frame_args.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_delegate.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/gfx/animation/animation_container.h"
+#include "ui/gfx/frame_time.h"
 
 #define SAFE_INVOKE_VOID(function, running_anim, ...) \
     if (running_anim.is_sequence_alive()) \
@@ -177,7 +179,7 @@
     if (GetAnimationContainer()->is_running())
       last_step_time_ = GetAnimationContainer()->last_tick_time();
     else
-      last_step_time_ = base::TimeTicks::Now();
+      last_step_time_ = gfx::FrameTime::Now();
   }
 
   // Collect all the affected properties.
@@ -768,7 +770,7 @@
   else if (GetAnimationContainer()->is_running())
     start_time = GetAnimationContainer()->last_tick_time();
   else
-    start_time = base::TimeTicks::Now();
+    start_time = gfx::FrameTime::Now();
 
   if (!sequence->animation_group_id())
     sequence->set_animation_group_id(cc::AnimationIdProvider::NextGroupId());
diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc
index 23052d7..7c52200 100644
--- a/ui/compositor/layer_animator_unittest.cc
+++ b/ui/compositor/layer_animator_unittest.cc
@@ -20,6 +20,7 @@
 #include "ui/compositor/test/test_layer_animation_delegate.h"
 #include "ui/compositor/test/test_layer_animation_observer.h"
 #include "ui/compositor/test/test_utils.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/transform.h"
 
@@ -168,7 +169,7 @@
   animator->set_disable_timer_for_test(true);
   TestLayerAnimationDelegate delegate;
   animator->SetDelegate(&delegate);
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = gfx::FrameTime::Now();
   animator->SetBrightness(0.5);
   EXPECT_TRUE(animator->is_animating());
   element->Step(now + base::TimeDelta::FromSeconds(1));
@@ -1035,7 +1036,7 @@
   // miniscule (fractions of a millisecond). If set correctly, then the delta
   // should be enormous. Arbitrarily choosing 1 minute as the threshold,
   // though a much smaller value would probably have sufficed.
-  delta = base::TimeTicks::Now() - animator->last_step_time();
+  delta = gfx::FrameTime::Now() - animator->last_step_time();
   EXPECT_GT(60.0, delta.InSecondsF());
 }
 
@@ -2149,9 +2150,9 @@
   TestLayerAnimationDelegate delegate;
   animator->SetDelegate(&delegate);
 
-  SkColor start_color  = SkColorSetARGB(  0, 20, 40,  60);
-  SkColor middle_color = SkColorSetARGB(127, 30, 60, 100);
-  SkColor target_color = SkColorSetARGB(254, 40, 80, 140);
+  SkColor start_color  = SkColorSetARGB( 64, 20, 40,  60);
+  SkColor middle_color = SkColorSetARGB(128, 35, 70, 120);
+  SkColor target_color = SkColorSetARGB(192, 40, 80, 140);
 
   base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
 
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index a229af3..ea21e24 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -22,6 +22,7 @@
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/layer_animator.h"
+#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/compositor/test/test_compositor_host.h"
 #include "ui/compositor/test/test_layers.h"
 #include "ui/gfx/canvas.h"
@@ -84,7 +85,7 @@
   // Overridden from testing::Test:
   virtual void SetUp() OVERRIDE {
     bool allow_test_contexts = false;
-    Compositor::InitializeContextFactoryForTests(allow_test_contexts);
+    InitializeContextFactoryForTests(allow_test_contexts);
     Compositor::Initialize();
 
     const gfx::Rect host_bounds(10, 10, 500, 500);
@@ -94,6 +95,7 @@
 
   virtual void TearDown() OVERRIDE {
     window_.reset();
+    TerminateContextFactoryForTests();
     Compositor::Terminate();
   }
 
@@ -351,14 +353,15 @@
   // Overridden from testing::Test:
   virtual void SetUp() OVERRIDE {
     bool allow_test_contexts = true;
-    Compositor::InitializeContextFactoryForTests(allow_test_contexts);
+    InitializeContextFactoryForTests(allow_test_contexts);
     Compositor::Initialize();
-    compositor_.reset(new Compositor(gfx::kNullAcceleratedWidget));
+    compositor_.reset(new Compositor(false, gfx::kNullAcceleratedWidget));
     compositor_->SetScaleAndSize(1.0f, gfx::Size(1000, 1000));
   }
 
   virtual void TearDown() OVERRIDE {
     compositor_.reset();
+    TerminateContextFactoryForTests();
     Compositor::Terminate();
   }
 
diff --git a/ui/compositor/reflector.h b/ui/compositor/reflector.h
index e6fb94c..4145695 100644
--- a/ui/compositor/reflector.h
+++ b/ui/compositor/reflector.h
@@ -5,12 +5,11 @@
 #ifndef UI_COMPOSITOR_REFLECTOR_H_
 #define UI_COMPOSITOR_REFLECTOR_H_
 
-#include "ui/compositor/compositor_export.h"
+#include "base/memory/ref_counted.h"
 
 namespace ui {
 
-class COMPOSITOR_EXPORT Reflector
-    : public base::RefCountedThreadSafe<Reflector> {
+class Reflector : public base::RefCountedThreadSafe<Reflector> {
  public:
   Reflector() {}
 
diff --git a/ui/compositor/test/context_factories_for_test.cc b/ui/compositor/test/context_factories_for_test.cc
new file mode 100644
index 0000000..795f56d
--- /dev/null
+++ b/ui/compositor/test/context_factories_for_test.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/test/context_factories_for_test.h"
+
+#include "base/command_line.h"
+#include "base/sys_info.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/compositor/test/default_context_factory.h"
+#include "ui/compositor/test/test_context_factory.h"
+
+namespace ui {
+
+static ContextFactory* g_implicit_factory = NULL;
+
+// static
+void InitializeContextFactoryForTests(bool allow_test_contexts) {
+  DCHECK(!g_implicit_factory) <<
+      "ContextFactory for tests already initialized.";
+
+  bool use_test_contexts = true;
+
+  // Always use test contexts unless the disable command line flag is used.
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kDisableTestCompositor))
+    use_test_contexts = false;
+
+#if defined(OS_CHROMEOS)
+  // If the test is running on the chromeos envrionment (such as
+  // device or vm bots), always use real contexts.
+  if (base::SysInfo::IsRunningOnChromeOS())
+    use_test_contexts = false;
+#endif
+
+  if (!allow_test_contexts)
+    use_test_contexts = false;
+
+  if (use_test_contexts) {
+    g_implicit_factory = new ui::TestContextFactory;
+  } else {
+    DVLOG(1) << "Using DefaultContextFactory";
+    scoped_ptr<ui::DefaultContextFactory> instance(
+        new ui::DefaultContextFactory());
+    if (instance->Initialize())
+      g_implicit_factory = instance.release();
+  }
+  ContextFactory::SetInstance(g_implicit_factory);
+}
+
+void TerminateContextFactoryForTests() {
+  ContextFactory::SetInstance(NULL);
+  delete g_implicit_factory;
+  g_implicit_factory = NULL;
+}
+
+}  // namespace ui
diff --git a/ui/compositor/test/context_factories_for_test.h b/ui/compositor/test/context_factories_for_test.h
new file mode 100644
index 0000000..a2b314f
--- /dev/null
+++ b/ui/compositor/test/context_factories_for_test.h
@@ -0,0 +1,16 @@
+// Copyright 2013 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.
+
+namespace ui {
+
+// Set up the compositor ContextFactory for a test environment. Unit tests
+// that do not have a full content environment need to call this before
+// initializing the Compositor.
+// Some tests expect pixel output, and they should pass false for
+// |allow_test_contexts|. Most unit tests should pass true. Once this has been
+// called, the caller must call TerminateContextFactoryForTests() to clean up.
+void InitializeContextFactoryForTests(bool allow_test_contexts);
+void TerminateContextFactoryForTests();
+
+}  // namespace ui
diff --git a/ui/compositor/test/default_context_factory.cc b/ui/compositor/test/default_context_factory.cc
new file mode 100644
index 0000000..c1700fe
--- /dev/null
+++ b/ui/compositor/test/default_context_factory.cc
@@ -0,0 +1,100 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/test/default_context_factory.h"
+
+#include "cc/output/output_surface.h"
+#include "ui/compositor/reflector.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "webkit/common/gpu/context_provider_in_process.h"
+#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
+#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
+
+namespace ui {
+
+DefaultContextFactory::DefaultContextFactory() {
+}
+
+DefaultContextFactory::~DefaultContextFactory() {
+}
+
+bool DefaultContextFactory::Initialize() {
+  if (!gfx::GLSurface::InitializeOneOff() ||
+      gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
+    LOG(ERROR) << "Could not load the GL bindings";
+    return false;
+  }
+  return true;
+}
+
+scoped_ptr<cc::OutputSurface> DefaultContextFactory::CreateOutputSurface(
+    Compositor* compositor) {
+  WebKit::WebGraphicsContext3D::Attributes attrs;
+  attrs.depth = false;
+  attrs.stencil = false;
+  attrs.antialias = false;
+  attrs.shareResources = true;
+
+  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d(
+      WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
+          attrs, compositor->widget()));
+  CHECK(context3d);
+
+  using webkit::gpu::ContextProviderInProcess;
+  scoped_refptr<ContextProviderInProcess> context_provider =
+      ContextProviderInProcess::Create(context3d.Pass(),
+                                       "UICompositor");
+
+  return make_scoped_ptr(new cc::OutputSurface(context_provider));
+}
+
+scoped_refptr<Reflector> DefaultContextFactory::CreateReflector(
+    Compositor* mirroed_compositor,
+    Layer* mirroring_layer) {
+  return NULL;
+}
+
+void DefaultContextFactory::RemoveReflector(
+    scoped_refptr<Reflector> reflector) {
+}
+
+scoped_refptr<cc::ContextProvider>
+DefaultContextFactory::OffscreenCompositorContextProvider() {
+  if (!offscreen_compositor_contexts_.get() ||
+      !offscreen_compositor_contexts_->DestroyedOnMainThread()) {
+    offscreen_compositor_contexts_ =
+        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
+  }
+  return offscreen_compositor_contexts_;
+}
+
+scoped_refptr<cc::ContextProvider>
+DefaultContextFactory::SharedMainThreadContextProvider() {
+  if (shared_main_thread_contexts_ &&
+      !shared_main_thread_contexts_->DestroyedOnMainThread())
+    return shared_main_thread_contexts_;
+
+  if (ui::Compositor::WasInitializedWithThread()) {
+    shared_main_thread_contexts_ =
+        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
+  } else {
+    shared_main_thread_contexts_ =
+        static_cast<webkit::gpu::ContextProviderInProcess*>(
+            OffscreenCompositorContextProvider().get());
+  }
+  if (shared_main_thread_contexts_ &&
+      !shared_main_thread_contexts_->BindToCurrentThread())
+    shared_main_thread_contexts_ = NULL;
+
+  return shared_main_thread_contexts_;
+}
+
+void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
+}
+
+bool DefaultContextFactory::DoesCreateTestContexts() { return false; }
+
+}  // namespace ui
diff --git a/ui/compositor/test/default_context_factory.h b/ui/compositor/test/default_context_factory.h
new file mode 100644
index 0000000..b89bdd8
--- /dev/null
+++ b/ui/compositor/test/default_context_factory.h
@@ -0,0 +1,53 @@
+// Copyright 2013 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_COMPOSITOR_TEST_DEFAULT_CONTEXT_FACTORY_H_
+#define UI_COMPOSITOR_TEST_DEFAULT_CONTEXT_FACTORY_H_
+
+#include "ui/compositor/compositor.h"
+
+namespace webkit {
+namespace gpu {
+class ContextProviderInProcess;
+}
+}
+
+namespace ui {
+
+// The default factory that creates in-process contexts.
+class DefaultContextFactory : public ContextFactory {
+ public:
+  DefaultContextFactory();
+  virtual ~DefaultContextFactory();
+
+  // ContextFactory implementation
+  virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
+      Compositor* compositor) OVERRIDE;
+
+  virtual scoped_refptr<Reflector> CreateReflector(
+      Compositor* compositor,
+      Layer* layer) OVERRIDE;
+  virtual void RemoveReflector(scoped_refptr<Reflector> reflector) OVERRIDE;
+
+  virtual scoped_refptr<cc::ContextProvider>
+      OffscreenCompositorContextProvider() OVERRIDE;
+  virtual scoped_refptr<cc::ContextProvider>
+      SharedMainThreadContextProvider() OVERRIDE;
+  virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
+  virtual bool DoesCreateTestContexts() OVERRIDE;
+
+  bool Initialize();
+
+ private:
+  scoped_refptr<webkit::gpu::ContextProviderInProcess>
+      offscreen_compositor_contexts_;
+  scoped_refptr<webkit::gpu::ContextProviderInProcess>
+      shared_main_thread_contexts_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultContextFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_COMPOSITOR_TEST_DEFAULT_CONTEXT_FACTORY_H_
diff --git a/ui/compositor/test/layer_animator_test_controller.cc b/ui/compositor/test/layer_animator_test_controller.cc
index 2b686cc..b7b8c40 100644
--- a/ui/compositor/test/layer_animator_test_controller.cc
+++ b/ui/compositor/test/layer_animator_test_controller.cc
@@ -5,6 +5,8 @@
 #include "cc/animation/animation.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/gfx/frame_time.h"
+#include "ui/gfx/rect.h"
 
 namespace ui {
 
@@ -52,7 +54,7 @@
         0,
         element->animation_group_id(),
         threaded_properties[i],
-        (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF()));
+        (gfx::FrameTime::Now() - base::TimeTicks()).InSecondsF()));
   }
 }
 
diff --git a/ui/compositor/test/test_compositor_host_win.cc b/ui/compositor/test/test_compositor_host_win.cc
index 5c7cdb4..140b0cd 100644
--- a/ui/compositor/test/test_compositor_host_win.cc
+++ b/ui/compositor/test/test_compositor_host_win.cc
@@ -16,7 +16,7 @@
  public:
   TestCompositorHostWin(const gfx::Rect& bounds) {
     Init(NULL, bounds);
-    compositor_.reset(new ui::Compositor(hwnd()));
+    compositor_.reset(new ui::Compositor(false, hwnd()));
     compositor_->SetScaleAndSize(1.0f, GetSize());
   }
 
diff --git a/ui/compositor/test/test_compositor_host_x11.cc b/ui/compositor/test/test_compositor_host_x11.cc
index 4215e27..578df6a 100644
--- a/ui/compositor/test/test_compositor_host_x11.cc
+++ b/ui/compositor/test/test_compositor_host_x11.cc
@@ -69,7 +69,7 @@
     if (event.type == MapNotify && event.xmap.window == window_)
       break;
   }
-  compositor_.reset(new ui::Compositor(window_));
+  compositor_.reset(new ui::Compositor(false, window_));
   compositor_->SetScaleAndSize(1.0f, bounds_.size());
 }
 
diff --git a/ui/compositor/test/test_context_factory.cc b/ui/compositor/test/test_context_factory.cc
new file mode 100644
index 0000000..30f84fb
--- /dev/null
+++ b/ui/compositor/test/test_context_factory.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/test/test_context_factory.h"
+
+#include "cc/debug/test_context_provider.h"
+#include "cc/output/output_surface.h"
+#include "ui/compositor/reflector.h"
+
+namespace ui {
+
+TestContextFactory::TestContextFactory() {}
+
+TestContextFactory::~TestContextFactory() {}
+
+scoped_ptr<cc::OutputSurface> TestContextFactory::CreateOutputSurface(
+    Compositor* compositor) {
+  return make_scoped_ptr(
+      new cc::OutputSurface(cc::TestContextProvider::Create()));
+}
+
+scoped_refptr<Reflector> TestContextFactory::CreateReflector(
+    Compositor* mirrored_compositor,
+    Layer* mirroring_layer) {
+  return new Reflector();
+}
+
+void TestContextFactory::RemoveReflector(scoped_refptr<Reflector> reflector) {
+}
+
+scoped_refptr<cc::ContextProvider>
+TestContextFactory::OffscreenCompositorContextProvider() {
+  if (!offscreen_compositor_contexts_.get() ||
+      offscreen_compositor_contexts_->DestroyedOnMainThread())
+    offscreen_compositor_contexts_ = cc::TestContextProvider::Create();
+  return offscreen_compositor_contexts_;
+}
+
+scoped_refptr<cc::ContextProvider>
+TestContextFactory::SharedMainThreadContextProvider() {
+  if (shared_main_thread_contexts_ &&
+      !shared_main_thread_contexts_->DestroyedOnMainThread())
+    return shared_main_thread_contexts_;
+
+  if (ui::Compositor::WasInitializedWithThread()) {
+    shared_main_thread_contexts_ = cc::TestContextProvider::Create();
+  } else {
+    shared_main_thread_contexts_ =
+        static_cast<cc::TestContextProvider*>(
+            OffscreenCompositorContextProvider().get());
+  }
+  if (shared_main_thread_contexts_ &&
+      !shared_main_thread_contexts_->BindToCurrentThread())
+    shared_main_thread_contexts_ = NULL;
+
+  return shared_main_thread_contexts_;
+}
+
+void TestContextFactory::RemoveCompositor(Compositor* compositor) {
+}
+
+bool TestContextFactory::DoesCreateTestContexts() { return true; }
+
+}  // namespace ui
diff --git a/ui/compositor/test/test_context_factory.h b/ui/compositor/test/test_context_factory.h
new file mode 100644
index 0000000..d419292
--- /dev/null
+++ b/ui/compositor/test/test_context_factory.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_COMPOSITOR_TEST_TEST_CONTEXT_FACTORY_H_
+#define UI_COMPOSITOR_TEST_TEST_CONTEXT_FACTORY_H_
+
+#include "ui/compositor/compositor.h"
+
+namespace cc { class TestContextProvider; }
+
+namespace ui {
+
+// The factory that creates test contexts.
+class TestContextFactory : public ContextFactory {
+ public:
+  TestContextFactory();
+  virtual ~TestContextFactory();
+
+  // ContextFactory implementation
+  virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
+      Compositor* compositor) OVERRIDE;
+
+  virtual scoped_refptr<Reflector> CreateReflector(
+      Compositor* mirrored_compositor,
+      Layer* mirroring_layer) OVERRIDE;
+  virtual void RemoveReflector(scoped_refptr<Reflector> reflector) OVERRIDE;
+
+  virtual scoped_refptr<cc::ContextProvider>
+      OffscreenCompositorContextProvider() OVERRIDE;
+  virtual scoped_refptr<cc::ContextProvider>
+      SharedMainThreadContextProvider() OVERRIDE;
+  virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
+  virtual bool DoesCreateTestContexts() OVERRIDE;
+
+ private:
+  scoped_refptr<cc::TestContextProvider> offscreen_compositor_contexts_;
+  scoped_refptr<cc::TestContextProvider> shared_main_thread_contexts_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestContextFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_COMPOSITOR_TEST_TEST_CONTEXT_FACTORY_H_
diff --git a/ui/events/OWNERS b/ui/events/OWNERS
index 0d062c2..14d1005 100644
--- a/ui/events/OWNERS
+++ b/ui/events/OWNERS
@@ -1,3 +1,6 @@
 sadrul@chromium.org
 per-file latency_info.*=jbauman@chromium.org
 per-file latency_info_unittest.cc=jbauman@chromium.org
+
+# If you're doing structural changes get a review from one of the OWNERS.
+per-file *.gyp*=*
diff --git a/ui/events/event.cc b/ui/events/event.cc
index d2a6592..a127bb9 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -81,6 +81,7 @@
     CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
     CASE_TYPE(ET_GESTURE_SCROLL_END);
     CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
+    CASE_TYPE(ET_GESTURE_SHOW_PRESS);
     CASE_TYPE(ET_GESTURE_TAP);
     CASE_TYPE(ET_GESTURE_TAP_DOWN);
     CASE_TYPE(ET_GESTURE_TAP_CANCEL);
@@ -571,7 +572,9 @@
 #if defined(USE_OZONE)
   KeyEvent* copy = new KeyEvent(*this);
 #else
-  KeyEvent* copy = new KeyEvent(::CopyNativeEvent(native_event()), is_char());
+  KeyEvent* copy = HasNativeEvent() ?
+      new KeyEvent(::CopyNativeEvent(native_event()), is_char()) :
+      new KeyEvent(*this);
 #endif
 #if defined(USE_X11)
   copy->set_delete_native_event(true);
diff --git a/ui/events/event.h b/ui/events/event.h
index 85fa6c0..d1eb97e 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -140,6 +140,7 @@
       case ET_GESTURE_LONG_PRESS:
       case ET_GESTURE_LONG_TAP:
       case ET_GESTURE_MULTIFINGER_SWIPE:
+      case ET_GESTURE_SHOW_PRESS:
         return true;
 
       case ET_SCROLL_FLING_CANCEL:
@@ -665,10 +666,6 @@
   // gesture. If there are no touches associated with this gesture, returns -1.
   int GetLowestTouchId() const;
 
-  unsigned int touch_ids_bitfield() const {
-    return touch_ids_bitfield_;
-  }
-
  private:
   GestureEventDetails details_;
 
diff --git a/ui/events/event_constants.h b/ui/events/event_constants.h
index 6c0e9f7..2a545b7 100644
--- a/ui/events/event_constants.h
+++ b/ui/events/event_constants.h
@@ -47,6 +47,7 @@
   // A SWIPE gesture can happen at the end of a TAP_UP gesture if the
   // finger(s) were moving quickly before they are released.
   ET_GESTURE_MULTIFINGER_SWIPE,
+  ET_GESTURE_SHOW_PRESS,
 
   // Scroll support.
   // TODO[davemoore] we need to unify these events w/ touch and gestures.
diff --git a/ui/events/event_dispatcher.cc b/ui/events/event_dispatcher.cc
index fda4b26..689dd81 100644
--- a/ui/events/event_dispatcher.cc
+++ b/ui/events/event_dispatcher.cc
@@ -78,7 +78,7 @@
   target->GetPreTargetHandlers(&handler_list_);
 
   dispatch_helper.set_phase(EP_PRETARGET);
-  DispatchEventToEventHandlers(handler_list_, event);
+  DispatchEventToEventHandlers(&handler_list_, event);
   if (event->handled())
     return;
 
@@ -100,7 +100,7 @@
   handler_list_.clear();
   target->GetPostTargetHandlers(&handler_list_);
   dispatch_helper.set_phase(EP_POSTTARGET);
-  DispatchEventToEventHandlers(handler_list_, event);
+  DispatchEventToEventHandlers(&handler_list_, event);
 }
 
 void EventDispatcher::OnDispatcherDelegateDestroyed() {
@@ -110,24 +110,24 @@
 ////////////////////////////////////////////////////////////////////////////////
 // EventDispatcher, private:
 
-void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList& list,
+void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
                                                    Event* event) {
-  for (EventHandlerList::const_iterator it = list.begin(),
-           end = list.end(); it != end; ++it) {
+  for (EventHandlerList::const_iterator it = list->begin(),
+           end = list->end(); it != end; ++it) {
     (*it)->dispatchers_.push(this);
   }
 
-  while (!list.empty()) {
-    EventHandler* handler = (*list.begin());
+  while (!list->empty()) {
+    EventHandler* handler = (*list->begin());
     if (delegate_ && !event->stopped_propagation())
       DispatchEvent(handler, event);
 
-    if (!list.empty() && *list.begin() == handler) {
+    if (!list->empty() && *list->begin() == handler) {
       // The handler has not been destroyed (because if it were, then it would
       // have been removed from the list).
       CHECK(handler->dispatchers_.top() == this);
       handler->dispatchers_.pop();
-      list.erase(list.begin());
+      list->erase(list->begin());
     }
   }
 }
diff --git a/ui/events/event_dispatcher.h b/ui/events/event_dispatcher.h
index ef8d6b1..02ad786 100644
--- a/ui/events/event_dispatcher.h
+++ b/ui/events/event_dispatcher.h
@@ -58,8 +58,7 @@
   void OnDispatcherDelegateDestroyed();
 
  private:
-  void DispatchEventToEventHandlers(EventHandlerList& list,
-                                    Event* event);
+  void DispatchEventToEventHandlers(EventHandlerList* list, Event* event);
 
   // Dispatches an event, and makes sure it sets ER_CONSUMED on the
   // event-handling result if the dispatcher itself has been destroyed during
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index cf8fba5..3b0e0ec 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -272,4 +272,11 @@
   }
 }
 
+TEST(EventTest, KeyEventCopy) {
+  KeyEvent key(ET_KEY_PRESSED, VKEY_A, EF_NONE, false);
+  scoped_ptr<KeyEvent> copied_key(key.Copy());
+  EXPECT_EQ(copied_key->type(), key.type());
+  EXPECT_EQ(copied_key->key_code(), key.key_code());
+}
+
 }  // namespace ui
diff --git a/ui/events/event_utils.cc b/ui/events/event_utils.cc
index 5504e4c..a8c95da 100644
--- a/ui/events/event_utils.cc
+++ b/ui/events/event_utils.cc
@@ -4,7 +4,11 @@
 
 #include "ui/events/event_utils.h"
 
+#include <vector>
+
 #include "ui/events/event.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
 
 namespace ui {
 
@@ -25,4 +29,19 @@
       base::TimeTicks::Now().ToInternalValue());
 }
 
+bool ShouldDefaultToNaturalScroll() {
+  gfx::Screen* screen = gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
+  if (!screen)
+    return false;
+  const std::vector<gfx::Display>& displays = screen->GetAllDisplays();
+  for (std::vector<gfx::Display>::const_iterator it = displays.begin();
+       it != displays.end(); ++it) {
+    const gfx::Display& display = *it;
+    if (display.IsInternal() &&
+        display.touch_support() == gfx::Display::TOUCH_SUPPORT_AVAILABLE)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace ui
diff --git a/ui/events/event_utils.h b/ui/events/event_utils.h
index bcf1213..be210e6 100644
--- a/ui/events/event_utils.h
+++ b/ui/events/event_utils.h
@@ -124,6 +124,9 @@
 // In natural scrolling enabled for touchpads?
 EVENTS_EXPORT bool IsNaturalScrollEnabled();
 
+// Returns whether natural scrolling should be used for touchpad.
+EVENTS_EXPORT bool ShouldDefaultToNaturalScroll();
+
 // Was this event generated by a touchpad device?
 // The caller is responsible for ensuring that this is a mouse/touchpad event
 // before calling this function.
diff --git a/ui/events/events.gyp b/ui/events/events.gyp
index 100601e..eb11794 100644
--- a/ui/events/events.gyp
+++ b/ui/events/events.gyp
@@ -65,16 +65,16 @@
         'keycodes/keyboard_codes.h',
         'latency_info.cc',
         'latency_info.h',
-        'ozone/evdev/event_factory_delegate.cc',
-        'ozone/evdev/event_factory_delegate.h',
+        'ozone/evdev/event_factory.cc',
+        'ozone/evdev/event_factory.h',
+        'ozone/evdev/event_modifiers.cc',
+        'ozone/evdev/event_modifiers.h',
         'ozone/evdev/key_event_converter.cc',
         'ozone/evdev/key_event_converter.h',
         'ozone/evdev/touch_event_converter.cc',
         'ozone/evdev/touch_event_converter.h',
         'ozone/event_converter_ozone.cc',
         'ozone/event_converter_ozone.h',
-        'ozone/event_factory_delegate_ozone.cc',
-        'ozone/event_factory_delegate_ozone.h',
         'ozone/event_factory_ozone.cc',
         'ozone/event_factory_ozone.h',
         'ozone/events_ozone.cc',
diff --git a/ui/events/events.target.darwin-arm.mk b/ui/events/events.target.darwin-arm.mk
index 0cbeec1..338032f 100644
--- a/ui/events/events.target.darwin-arm.mk
+++ b/ui/events/events.target.darwin-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/events.target.darwin-mips.mk b/ui/events/events.target.darwin-mips.mk
index 0d359ad..49c30de 100644
--- a/ui/events/events.target.darwin-mips.mk
+++ b/ui/events/events.target.darwin-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/events.target.darwin-x86.mk b/ui/events/events.target.darwin-x86.mk
index 75368ad..3478140 100644
--- a/ui/events/events.target.darwin-x86.mk
+++ b/ui/events/events.target.darwin-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -174,13 +174,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/events.target.linux-arm.mk b/ui/events/events.target.linux-arm.mk
index 0cbeec1..338032f 100644
--- a/ui/events/events.target.linux-arm.mk
+++ b/ui/events/events.target.linux-arm.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/events.target.linux-mips.mk b/ui/events/events.target.linux-mips.mk
index 0d359ad..49c30de 100644
--- a/ui/events/events.target.linux-mips.mk
+++ b/ui/events/events.target.linux-mips.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -167,13 +167,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/events.target.linux-x86.mk b/ui/events/events.target.linux-x86.mk
index 75368ad..3478140 100644
--- a/ui/events/events.target.linux-x86.mk
+++ b/ui/events/events.target.linux-x86.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -174,13 +174,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/events/gestures/gesture_configuration.cc b/ui/events/gestures/gesture_configuration.cc
index fb4ec7f..e48ae6d 100644
--- a/ui/events/gestures/gesture_configuration.cc
+++ b/ui/events/gestures/gesture_configuration.cc
@@ -40,6 +40,7 @@
 int GestureConfiguration::points_buffered_for_velocity_ = 8;
 double GestureConfiguration::rail_break_proportion_ = 15;
 double GestureConfiguration::rail_start_proportion_ = 2;
+int GestureConfiguration::show_press_delay_in_ms_ = 150;
 
 // Coefficients for a function that computes fling acceleration.
 // These are empirically determined defaults. Do not adjust without
diff --git a/ui/events/gestures/gesture_configuration.h b/ui/events/gestures/gesture_configuration.h
index 0d4d07f..a4bdcd3 100644
--- a/ui/events/gestures/gesture_configuration.h
+++ b/ui/events/gestures/gesture_configuration.h
@@ -173,6 +173,12 @@
   static void set_scroll_prediction_seconds(double val) {
     scroll_prediction_seconds_ = val;
   }
+  static int show_press_delay_in_ms() {
+    return show_press_delay_in_ms_;
+  }
+  static int set_show_press_delay_in_ms(int val) {
+    return show_press_delay_in_ms_ = val;
+  }
   static void set_fling_acceleration_curve_coefficients(int i, float val) {
     fling_acceleration_curve_coefficients_[i] = val;
   }
@@ -240,6 +246,7 @@
   static double rail_break_proportion_;
   static double rail_start_proportion_;
   static double scroll_prediction_seconds_;
+  static int show_press_delay_in_ms_;
   static float fling_acceleration_curve_coefficients_[NumAccelParams];
   static float fling_velocity_cap_;
   // TODO(davemoore): Move into chrome/browser/ui.
diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc
index 5a902e6..a3bb9cc 100644
--- a/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/ui/events/gestures/gesture_recognizer_impl.cc
@@ -222,12 +222,12 @@
     helpers_.erase(it);
 }
 
-void GestureRecognizerImpl::DispatchLongPressGestureEvent(GestureEvent* event) {
+void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
   GestureConsumer* consumer = GetTargetForGestureEvent(event);
   if (consumer) {
     GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
     if (helper)
-      helper->DispatchLongPressGestureEvent(event);
+      helper->DispatchPostponedGestureEvent(event);
   }
 }
 
diff --git a/ui/events/gestures/gesture_recognizer_impl.h b/ui/events/gestures/gesture_recognizer_impl.h
index a20d956..051454c 100644
--- a/ui/events/gestures/gesture_recognizer_impl.h
+++ b/ui/events/gestures/gesture_recognizer_impl.h
@@ -62,7 +62,7 @@
   virtual void RemoveGestureEventHelper(GestureEventHelper* helper) OVERRIDE;
 
   // Overridden from ui::GestureSequenceDelegate.
-  virtual void DispatchLongPressGestureEvent(GestureEvent* event) OVERRIDE;
+  virtual void DispatchPostponedGestureEvent(GestureEvent* event) OVERRIDE;
 
   // Convenience method to find the GestureEventHelper that can dispatch events
   // to a specific |consumer|.
diff --git a/ui/events/gestures/gesture_sequence.cc b/ui/events/gestures/gesture_sequence.cc
index e728cbc..f13af4a 100644
--- a/ui/events/gestures/gesture_sequence.cc
+++ b/ui/events/gestures/gesture_sequence.cc
@@ -155,10 +155,16 @@
       G(GS_PENDING_TWO_FINGER_TAP, 1, TS_RELEASED, TSI_PROCESSED),
 
   GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED =
-      G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, TSI_ALWAYS),
+      G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, TSI_NOT_PROCESSED),
 
   GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED =
-      G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, TSI_ALWAYS),
+      G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, TSI_NOT_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED =
+      G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, TSI_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED =
+      G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, TSI_PROCESSED),
 
   GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED =
       G(GS_PENDING_TWO_FINGER_TAP, 0, TS_CANCELLED, TSI_ALWAYS),
@@ -166,9 +172,75 @@
   GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED =
       G(GS_PENDING_TWO_FINGER_TAP, 1, TS_CANCELLED, TSI_ALWAYS),
 
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_RELEASED, TSI_NOT_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_RELEASED, TSI_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_RELEASED, TSI_NOT_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_RELEASED, TSI_PROCESSED),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_MOVED, TSI_ALWAYS),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_MOVED, TSI_ALWAYS),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 0, TS_CANCELLED, TSI_ALWAYS),
+
+  GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED =
+      G(GS_PENDING_TWO_FINGER_TAP_NO_PINCH, 1, TS_CANCELLED, TSI_ALWAYS),
+
   GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED =
       G(GS_PENDING_TWO_FINGER_TAP, 2, TS_PRESSED, TSI_NOT_PROCESSED),
 
+  GST_PENDING_PINCH_FIRST_MOVED =
+      G(GS_PENDING_PINCH, 0, TS_MOVED, TSI_NOT_PROCESSED),
+
+  GST_PENDING_PINCH_SECOND_MOVED =
+      G(GS_PENDING_PINCH, 1, TS_MOVED, TSI_NOT_PROCESSED),
+
+  GST_PENDING_PINCH_FIRST_MOVED_HANDLED =
+      G(GS_PENDING_PINCH, 0, TS_MOVED, TSI_PROCESSED),
+
+  GST_PENDING_PINCH_SECOND_MOVED_HANDLED =
+      G(GS_PENDING_PINCH, 1, TS_MOVED, TSI_PROCESSED),
+
+  GST_PENDING_PINCH_FIRST_CANCELLED =
+      G(GS_PENDING_PINCH, 0, TS_CANCELLED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_SECOND_CANCELLED =
+      G(GS_PENDING_PINCH, 1, TS_CANCELLED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_FIRST_RELEASED =
+      G(GS_PENDING_PINCH, 0, TS_RELEASED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_SECOND_RELEASED =
+      G(GS_PENDING_PINCH, 1, TS_RELEASED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED =
+      G(GS_PENDING_PINCH_NO_PINCH, 0, TS_MOVED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED =
+      G(GS_PENDING_PINCH_NO_PINCH, 1, TS_MOVED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED =
+      G(GS_PENDING_PINCH_NO_PINCH, 0, TS_CANCELLED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED =
+      G(GS_PENDING_PINCH_NO_PINCH, 1, TS_CANCELLED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED =
+      G(GS_PENDING_PINCH_NO_PINCH, 0, TS_RELEASED, TSI_ALWAYS),
+
+  GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED =
+      G(GS_PENDING_PINCH_NO_PINCH, 1, TS_RELEASED, TSI_ALWAYS),
+
   GST_PINCH_FIRST_MOVED =
       G(GS_PINCH, 0, TS_MOVED, TSI_NOT_PROCESSED),
 
@@ -280,9 +352,33 @@
     case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED:
     case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED:
     case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED:
+    case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED:
     case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED:
     case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED:
     case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED:
+    case GST_PENDING_PINCH_FIRST_MOVED:
+    case GST_PENDING_PINCH_SECOND_MOVED:
+    case GST_PENDING_PINCH_FIRST_MOVED_HANDLED:
+    case GST_PENDING_PINCH_SECOND_MOVED_HANDLED:
+    case GST_PENDING_PINCH_FIRST_RELEASED:
+    case GST_PENDING_PINCH_SECOND_RELEASED:
+    case GST_PENDING_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_PINCH_SECOND_CANCELLED:
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED:
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED:
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED:
     case GST_PINCH_FIRST_MOVED:
     case GST_PINCH_FIRST_MOVED_HANDLED:
     case GST_PINCH_SECOND_MOVED:
@@ -398,7 +494,7 @@
 GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
     const TouchEvent& event,
     EventResult result) {
-  StopLongPressTimerIfRequired(event);
+  StopTimersIfRequired(event);
   last_touch_location_ = event.location();
   if (result & ER_CONSUMED)
     return NULL;
@@ -526,6 +622,10 @@
       if (TwoFingerTouchMove(event, point, gestures.get()))
         set_state(GS_PINCH);
       break;
+    case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED_HANDLED:
+      set_state(GS_PENDING_TWO_FINGER_TAP_NO_PINCH);
+      break;
     case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED_HANDLED:
     case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED:
     case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED:
@@ -534,8 +634,58 @@
       set_state(GS_SCROLL);
       break;
     case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED:
-      PinchStart(event, point, gestures.get());
-      set_state(GS_PINCH);
+      set_state(GS_PENDING_PINCH);
+      break;
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_MOVED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_MOVED:
+      // No pinch allowed, so nothing happens.
+      break;
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED:
+      TwoFingerTouchReleased(event, point, gestures.get());
+      // We transit into GS_SCROLL even though the touch move can be
+      // consumed and no scroll should happen. crbug.com/240399.
+      set_state(GS_SCROLL);
+      break;
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED:
+      // We transit into GS_SCROLL even though the touch move can be
+      // consumed and no scroll should happen. crbug.com/240399.
+      scroll_type_ = ST_FREE;
+      set_state(GS_SCROLL);
+      break;
+    case GST_PENDING_PINCH_FIRST_MOVED:
+    case GST_PENDING_PINCH_SECOND_MOVED:
+      if (TwoFingerTouchMove(event, point, gestures.get()))
+        set_state(GS_PINCH);
+      break;
+    case GST_PENDING_PINCH_FIRST_MOVED_HANDLED:
+    case GST_PENDING_PINCH_SECOND_MOVED_HANDLED:
+      set_state(GS_PENDING_PINCH_NO_PINCH);
+      break;
+    case GST_PENDING_PINCH_FIRST_RELEASED:
+    case GST_PENDING_PINCH_SECOND_RELEASED:
+    case GST_PENDING_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_PINCH_SECOND_CANCELLED:
+      // We transit into GS_SCROLL even though the touch move can be
+      // consumed and no scroll should happen. crbug.com/240399.
+      scroll_type_ = ST_FREE;
+      set_state(GS_SCROLL);
+      break;
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED:
+      // No pinch allowed, so nothing happens.
+      break;
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_RELEASED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED:
+    case GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED:
+    case GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED:
+      // We transit into GS_SCROLL even though the touch move can be
+      // consumed and no scroll should happen. crbug.com/240399.
+      scroll_type_ = ST_FREE;
+      set_state(GS_SCROLL);
       break;
     case GST_PINCH_FIRST_MOVED_HANDLED:
     case GST_PINCH_SECOND_MOVED_HANDLED:
@@ -598,8 +748,10 @@
              << " State: " << state_
              << " touch id: " << event.touch_id();
 
-  if (last_state == GS_PENDING_SYNTHETIC_CLICK && state_ != last_state)
+  if (last_state == GS_PENDING_SYNTHETIC_CLICK && state_ != last_state) {
     GetLongPressTimer()->Stop();
+    GetShowPressTimer()->Stop();
+  }
 
   // The set of point_ids must be contiguous and include 0.
   // When a touch point is released, all points with ids greater than the
@@ -674,6 +826,12 @@
   return long_press_timer_.get();
 }
 
+base::OneShotTimer<GestureSequence>* GestureSequence::GetShowPressTimer() {
+  if (!show_press_timer_.get())
+    show_press_timer_.reset(CreateTimer());
+  return show_press_timer_.get();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // GestureSequence Private:
 
@@ -947,6 +1105,10 @@
       tap_count = 3;
     else if (point.IsInDoubleClickWindow(event))
       tap_count = 2;
+    if (tap_count == 1 && GetShowPressTimer()->IsRunning()) {
+      GetShowPressTimer()->Stop();
+      AppendShowPressGestureEvent();
+    }
     AppendClickGestureEvent(point, tap_count, gestures);
     return true;
   } else if (point.IsInsideManhattanSquare(event) &&
@@ -1005,6 +1167,14 @@
           GestureConfiguration::long_press_time_in_seconds() * 1000),
       this,
       &GestureSequence::AppendLongPressGestureEvent);
+
+  GetShowPressTimer()->Start(
+      FROM_HERE,
+      base::TimeDelta::FromMilliseconds(
+          GestureConfiguration::show_press_delay_in_ms()),
+      this,
+      &GestureSequence::AppendShowPressGestureEvent);
+
   return true;
 }
 
@@ -1026,7 +1196,8 @@
 bool GestureSequence::TwoFingerTouchMove(const TouchEvent& event,
                                          const GesturePoint& point,
                                          Gestures* gestures) {
-  DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP);
+  DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP ||
+         state_ == GS_PENDING_PINCH);
 
   base::TimeDelta time_delta = event.time_stamp() - second_touch_time_;
   base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
@@ -1041,7 +1212,8 @@
 bool GestureSequence::TwoFingerTouchReleased(const TouchEvent& event,
                                              const GesturePoint& point,
                                              Gestures* gestures) {
-  DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP);
+  DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP ||
+         state_ == GS_PENDING_TWO_FINGER_TAP_NO_PINCH);
   base::TimeDelta time_delta = event.time_stamp() - second_touch_time_;
   base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
       ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click());
@@ -1058,7 +1230,18 @@
       flags_,
       base::Time::FromDoubleT(point->last_touch_time()),
       1 << point->touch_id()));
-  delegate_->DispatchLongPressGestureEvent(gesture.get());
+  delegate_->DispatchPostponedGestureEvent(gesture.get());
+}
+
+void GestureSequence::AppendShowPressGestureEvent() {
+  const GesturePoint* point = GetPointByPointId(0);
+  scoped_ptr<GestureEvent> gesture(CreateGestureEvent(
+      GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS, 0, 0),
+      point->first_touch_position(),
+      flags_,
+      base::Time::FromDoubleT(point->last_touch_time()),
+      1 << point->touch_id()));
+  delegate_->DispatchPostponedGestureEvent(gesture.get());
 }
 
 void GestureSequence::AppendLongTapGestureEvent(const GesturePoint& point,
@@ -1091,8 +1274,8 @@
                                  const GesturePoint& point,
                                  Gestures* gestures) {
   DCHECK(state_ == GS_SCROLL ||
-         state_ == GS_PENDING_SYNTHETIC_CLICK ||
-         state_ == GS_PENDING_TWO_FINGER_TAP);
+         state_ == GS_PENDING_TWO_FINGER_TAP ||
+         state_ == GS_PENDING_PINCH);
 
   // Once pinch starts, we immediately break rail scroll.
   scroll_type_ = ST_FREE;
@@ -1105,8 +1288,8 @@
   latest_multi_scroll_update_location_ = bounding_box_.CenterPoint();
   AppendPinchGestureBegin(*point1, *point2, gestures);
 
-  if (state_ == GS_PENDING_SYNTHETIC_CLICK ||
-      state_ == GS_PENDING_TWO_FINGER_TAP) {
+  if (state_ == GS_PENDING_TWO_FINGER_TAP ||
+      state_ == GS_PENDING_PINCH) {
     gfx::Point center = bounding_box_.CenterPoint();
     AppendScrollGestureBegin(point, center, gestures);
   }
@@ -1239,22 +1422,24 @@
     TwoFingerTouchDown(event, point, gestures);
     set_state(GS_PENDING_TWO_FINGER_TAP);
   } else {
-    PinchStart(event, point, gestures);
-    set_state(GS_PINCH);
+    set_state(GS_PENDING_PINCH);
   }
 }
 
 
-void GestureSequence::StopLongPressTimerIfRequired(const TouchEvent& event) {
-  if (!GetLongPressTimer()->IsRunning() ||
+void GestureSequence::StopTimersIfRequired(const TouchEvent& event) {
+  if ((!GetLongPressTimer()->IsRunning() &&
+       !GetShowPressTimer()->IsRunning()) ||
       event.type() != ui::ET_TOUCH_MOVED)
     return;
 
-  // Since long press timer has been started, there should be a non-NULL point.
+  // Since a timer is running, there should be a non-NULL point.
   const GesturePoint* point = GetPointByPointId(0);
   if (!ui::gestures::IsInsideManhattanSquare(point->first_touch_position(),
-      event.location()))
+                                             event.location())) {
     GetLongPressTimer()->Stop();
+    GetShowPressTimer()->Stop();
+  }
 }
 
 }  // namespace ui
diff --git a/ui/events/gestures/gesture_sequence.h b/ui/events/gestures/gesture_sequence.h
index 9715194..b3255df 100644
--- a/ui/events/gestures/gesture_sequence.h
+++ b/ui/events/gestures/gesture_sequence.h
@@ -23,6 +23,9 @@
   GS_SCROLL,
   GS_PINCH,
   GS_PENDING_TWO_FINGER_TAP,
+  GS_PENDING_TWO_FINGER_TAP_NO_PINCH,
+  GS_PENDING_PINCH,
+  GS_PENDING_PINCH_NO_PINCH,
 };
 
 enum ScrollType {
@@ -35,7 +38,7 @@
 // have enough context to dispatch itself.
 class EVENTS_EXPORT GestureSequenceDelegate {
  public:
-  virtual void DispatchLongPressGestureEvent(GestureEvent* event) = 0;
+  virtual void DispatchPostponedGestureEvent(GestureEvent* event) = 0;
 
  protected:
   virtual ~GestureSequenceDelegate() {}
@@ -66,6 +69,7 @@
  protected:
   virtual base::OneShotTimer<GestureSequence>* CreateTimer();
   base::OneShotTimer<GestureSequence>* GetLongPressTimer();
+  base::OneShotTimer<GestureSequence>* GetShowPressTimer();
 
  private:
   // Recreates the axis-aligned bounding box that contains all the touch-points
@@ -105,6 +109,7 @@
   void AppendDoubleClickGestureEvent(const GesturePoint& point,
                                      Gestures* gestures);
   void AppendLongPressGestureEvent();
+  void AppendShowPressGestureEvent();
   void AppendLongTapGestureEvent(const GesturePoint& point,
                                  Gestures* gestures);
 
@@ -186,7 +191,7 @@
                            const GesturePoint& point,
                            Gestures* gestures);
 
-  void StopLongPressTimerIfRequired(const TouchEvent& event);
+  void StopTimersIfRequired(const TouchEvent& event);
 
   // Current state of gesture recognizer.
   GestureState state_;
@@ -222,6 +227,7 @@
 
   ScrollType scroll_type_;
   scoped_ptr<base::OneShotTimer<GestureSequence> > long_press_timer_;
+  scoped_ptr<base::OneShotTimer<GestureSequence> > show_press_timer_;
 
   GesturePoint points_[kMaxGesturePoints];
   int point_count_;
diff --git a/ui/events/gestures/gesture_types.h b/ui/events/gestures/gesture_types.h
index 80ee057..b0670fe 100644
--- a/ui/events/gestures/gesture_types.h
+++ b/ui/events/gestures/gesture_types.h
@@ -193,7 +193,7 @@
 
   // Returns true if this helper can dispatch events to |consumer|.
   virtual bool CanDispatchToConsumer(GestureConsumer* consumer) = 0;
-  virtual void DispatchLongPressGestureEvent(GestureEvent* event) = 0;
+  virtual void DispatchPostponedGestureEvent(GestureEvent* event) = 0;
   virtual void DispatchCancelTouchEvent(TouchEvent* event) = 0;
 };
 
diff --git a/ui/events/gestures/gestures.dot b/ui/events/gestures/gestures.dot
index 8524930..07883f8 100644
--- a/ui/events/gestures/gestures.dot
+++ b/ui/events/gestures/gestures.dot
@@ -19,27 +19,42 @@
 
 GS_NO_GESTURE ->  GS_PENDING_SYNTHETIC_CLICK [label= "D0"];
 
-GS_PENDING_SYNTHETIC_CLICK ->  GS_SCROLL [label= "M0\n S0"];
-GS_PENDING_SYNTHETIC_CLICK ->  GS_PENDING_SYNTHETIC_CLICK [label= "M0\n S0"];
-GS_PENDING_SYNTHETIC_CLICK ->  GS_NO_GESTURE [label= "C0\n R0"];
-GS_PENDING_SYNTHETIC_CLICK ->  GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0"];
-GS_PENDING_SYNTHETIC_CLICK ->  GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_SCROLL [label= "M0\n S0"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_SYNTHETIC_CLICK [label= "M0\n S0"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_NO_GESTURE [label= "C0\n R0"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_PINCH [label= "D1"];
 
-GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL ->  GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0\n S0"];
-GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL ->  GS_NO_GESTURE [label= "C0\n R0"];
-GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL ->  GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0\n S0"];
+GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_NO_GESTURE [label= "C0\n R0"];
+GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_PINCH [label= "D1"];
 
-GS_SCROLL ->  GS_SCROLL [label= "M0"];
-GS_SCROLL ->  GS_NO_GESTURE [label= "C0\n R0\n"];
-GS_SCROLL ->  GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_SCROLL -> GS_SCROLL [label= "M0"];
+GS_SCROLL -> GS_NO_GESTURE [label= "C0\n R0\n"];
+GS_SCROLL -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
 
+GS_PENDING_PINCH -> GS_PENDING_PINCH [label= "M0\n M1"];
+GS_PENDING_PINCH -> GS_PENDING_PINCH_NO_PINCH [label= "M0\n M1"];
+GS_PENDING_PINCH -> GS_PINCH [label= "M0\n M1"];
+GS_PENDING_PINCH -> GS_SCROLL [label= "R0\n R1\n C0\n C1"];
+
+GS_PENDING_PINCH_NO_PINCH -> GS_PENDING_PINCH_NO_PINCH [label= "M0\n M1"];
+GS_PENDING_PINCH_NO_PINCH -> GS_SCROLL [label= "R0\n R1\n C0\n C1"];
+
+GS_PENDING_TWO_FINGER_TAP -> GS_PENDING_TWO_FINGER_TAP [label= "M0\n M1"];
+GS_PENDING_TWO_FINGER_TAP -> GS_PENDING_TWO_FINGER_TAP_NO_PINCH [label= "M0\n M1"];
 GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M0\n M1"];
 GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M_Delay0\n M_Delay1"];
 GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "D2"];
 GS_PENDING_TWO_FINGER_TAP -> GS_SCROLL [label= "R0\n R1\n C0\n C1"];
 
-GS_PINCH ->  GS_PINCH [label= "M0\n M1"];
-GS_PINCH ->  GS_SCROLL [label= "C0\n R0\n C1\n R1"];
+GS_PENDING_TWO_FINGER_TAP_NO_PINCH -> GS_PENDING_TWO_FINGER_TAP_NO_PINCH [label= "M0\n M1"];
+GS_PENDING_TWO_FINGER_TAP_NO_PINCH -> GS_SCROLL [label= "R0\n R1\n C0\n C1"];
+
+GS_PINCH -> GS_PINCH [label= "M0\n M1"];
+GS_PINCH -> GS_SCROLL [label= "C0\n R0\n C1\n R1"];
 GS_PINCH -> GS_PENDING_THREE_FINGER_SWIPE [label= "D2"];
 
 GS_PENDING_THREE_FINGER_SWIPE -> GS_PINCH [label= "C0\n R0\n C1\n R1\n C2\n R2"];
diff --git a/ui/events/ozone/evdev/event_factory.cc b/ui/events/ozone/evdev/event_factory.cc
new file mode 100644
index 0000000..37e1f02
--- /dev/null
+++ b/ui/events/ozone/evdev/event_factory.cc
@@ -0,0 +1,60 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/event_factory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "base/strings/stringprintf.h"
+#include "ui/events/ozone/evdev/key_event_converter.h"
+#include "ui/events/ozone/evdev/touch_event_converter.h"
+#include "ui/events/ozone/event_factory_ozone.h"
+
+namespace ui {
+
+EventFactoryEvdev::EventFactoryEvdev() {}
+
+EventFactoryEvdev::~EventFactoryEvdev() {}
+
+void EventFactoryEvdev::StartProcessingEvents() {
+  // The number of devices in the directory is unknown without reading
+  // the contents of the directory. Further, with hot-plugging,  the entries
+  // might decrease during the execution of this loop. So exciting from the
+  // loop on the first failure of open below is both cheaper and more
+  // reliable.
+  for (int id = 0; true; id++) {
+    std::string path = base::StringPrintf("/dev/input/event%d", id);
+    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
+    if (fd < 0) {
+      DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno);
+      break;
+    }
+    size_t evtype = 0;
+    COMPILE_ASSERT(sizeof(evtype) * 8 >= EV_MAX, evtype_wide_enough);
+    if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype)), &evtype) == -1) {
+      DLOG(ERROR) << "failed ioctl EVIOCGBIT 0" << path;
+      close(fd);
+      continue;
+    }
+
+    scoped_ptr<EventConverterOzone> converter;
+    // TODO(rjkroege) Add more device types. Support hot-plugging.
+    if (evtype & (1 << EV_ABS))
+      converter.reset(new TouchEventConverterEvdev(fd, id));
+    else if (evtype & (1 << EV_KEY))
+      converter.reset(new KeyEventConverterEvdev(&modifiers_));
+
+    if (converter) {
+      AddEventConverter(fd, converter.Pass());
+    } else {
+      close(fd);
+    }
+  }
+}
+
+}  // namespace ui
diff --git a/ui/events/ozone/evdev/event_factory.h b/ui/events/ozone/evdev/event_factory.h
new file mode 100644
index 0000000..04a3a52
--- /dev/null
+++ b/ui/events/ozone/evdev/event_factory.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
+#define UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
+
+#include "base/compiler_specific.h"
+#include "ui/events/ozone/evdev/event_modifiers.h"
+#include "ui/events/ozone/event_factory_ozone.h"
+
+namespace ui {
+
+// Ozone events implementation for the Linux input subsystem ("evdev").
+class EventFactoryEvdev : public EventFactoryOzone {
+ public:
+  EventFactoryEvdev();
+  virtual ~EventFactoryEvdev();
+
+  virtual void StartProcessingEvents() OVERRIDE;
+
+ private:
+  EventModifiersEvdev modifiers_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventFactoryEvdev);
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
diff --git a/ui/events/ozone/evdev/event_factory_delegate.cc b/ui/events/ozone/evdev/event_factory_delegate.cc
deleted file mode 100644
index b122a6e..0000000
--- a/ui/events/ozone/evdev/event_factory_delegate.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/event_factory_delegate.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "base/strings/stringprintf.h"
-#include "ui/events/ozone/evdev/key_event_converter.h"
-#include "ui/events/ozone/evdev/touch_event_converter.h"
-#include "ui/events/ozone/event_factory_delegate_ozone.h"
-#include "ui/events/ozone/event_factory_ozone.h"
-
-namespace ui {
-
-EventFactoryDelegateEvdev::EventFactoryDelegateEvdev() {}
-
-EventFactoryDelegateEvdev::~EventFactoryDelegateEvdev() {}
-
-void EventFactoryDelegateEvdev::CreateStartupEventConverters(
-    EventFactoryOzone* factory) {
-  // The number of devices in the directory is unknown without reading
-  // the contents of the directory. Further, with hot-plugging,  the entries
-  // might decrease during the execution of this loop. So exciting from the
-  // loop on the first failure of open below is both cheaper and more
-  // reliable.
-  for (int id = 0; true; id++) {
-    std::string path = base::StringPrintf("/dev/input/event%d", id);
-    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
-    if (fd < 0) {
-      DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno);
-      break;
-    }
-    size_t evtype = 0;
-    COMPILE_ASSERT(sizeof(evtype) * 8 >= EV_MAX, evtype_wide_enough);
-    if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype)), &evtype) == -1) {
-      DLOG(ERROR) << "failed ioctl EVIOCGBIT 0" << path;
-      close(fd);
-      continue;
-    }
-
-    scoped_ptr<EventConverterOzone> converter;
-    // TODO(rjkroege) Add more device types. Support hot-plugging.
-    if (evtype & (1 << EV_ABS))
-      converter.reset(new TouchEventConverterEvdev(fd, id));
-    else if (evtype & (1 << EV_KEY))
-      converter.reset(new KeyEventConverterEvdev());
-
-    if (converter) {
-      factory->AddEventConverter(fd, converter.Pass());
-    } else {
-      close(fd);
-    }
-  }
-}
-
-}  // namespace ui
diff --git a/ui/events/ozone/evdev/event_factory_delegate.h b/ui/events/ozone/evdev/event_factory_delegate.h
deleted file mode 100644
index 8a121ec..0000000
--- a/ui/events/ozone/evdev/event_factory_delegate.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
-#define UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
-
-#include "base/compiler_specific.h"
-#include "ui/events/ozone/event_factory_delegate_ozone.h"
-
-namespace ui {
-
-// Ozone events implementation for the Linux input subsystem ("evdev").
-class EventFactoryDelegateEvdev : public EventFactoryDelegateOzone {
- public:
-  EventFactoryDelegateEvdev();
-  virtual ~EventFactoryDelegateEvdev();
-
-  virtual void CreateStartupEventConverters(
-      EventFactoryOzone* factory) OVERRIDE;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(EventFactoryDelegateEvdev);
-};
-
-}  // namespace ui
-
-#endif  // UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
diff --git a/ui/events/ozone/evdev/event_modifiers.cc b/ui/events/ozone/evdev/event_modifiers.cc
new file mode 100644
index 0000000..220ec08
--- /dev/null
+++ b/ui/events/ozone/evdev/event_modifiers.cc
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/event_modifiers.h"
+
+#include <linux/input.h>
+
+#include "ui/events/event.h"
+
+namespace ui {
+
+namespace {
+
+static const int kEventFlagFromModifiers[] = {
+    EF_NONE,                 // EVDEV_MODIFIER_NONE,
+    EF_CAPS_LOCK_DOWN,       // EVDEV_MODIFIER_CAPS_LOCK
+    EF_SHIFT_DOWN,           // EVDEV_MODIFIER_SHIFT
+    EF_CONTROL_DOWN,         // EVDEV_MODIFIER_CONTROL
+    EF_ALT_DOWN,             // EVDEV_MODIFIER_ALT
+    EF_LEFT_MOUSE_BUTTON,    // EVDEV_MODIFIER_LEFT_MOUSE_BUTTON
+    EF_MIDDLE_MOUSE_BUTTON,  // EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON
+    EF_RIGHT_MOUSE_BUTTON,   // EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON
+    EF_COMMAND_DOWN,         // EVDEV_MODIFIER_COMMAND
+    EF_ALTGR_DOWN,           // EVDEV_MODIFIER_ALTGR
+};
+
+}  // namespace
+
+EventModifiersEvdev::EventModifiersEvdev()
+    : modifier_flags_locked_(0), modifier_flags_(0) {
+  memset(modifiers_down_, 0, sizeof(modifiers_down_));
+}
+EventModifiersEvdev::~EventModifiersEvdev() {}
+
+void EventModifiersEvdev::UpdateModifier(unsigned int modifier, bool down) {
+  CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
+
+  if (down) {
+    modifiers_down_[modifier]++;
+  } else {
+    // Ignore spurious modifier "up" events. This might happen if the
+    // button is down during startup.
+    if (modifiers_down_[modifier])
+      modifiers_down_[modifier]--;
+  }
+
+  UpdateFlags(modifier);
+}
+
+void EventModifiersEvdev::UpdateModifierLock(unsigned int modifier, bool down) {
+  CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
+
+  if (down)
+    modifier_flags_locked_ ^= kEventFlagFromModifiers[modifier];
+
+  // TODO(spang): Synchronize with the CapsLock LED.
+
+  UpdateFlags(modifier);
+}
+
+void EventModifiersEvdev::UpdateFlags(unsigned int modifier) {
+  int mask = kEventFlagFromModifiers[modifier];
+  bool down = modifiers_down_[modifier];
+  bool locked = (modifier_flags_locked_ & mask);
+  if (down != locked)
+    modifier_flags_ |= mask;
+  else
+    modifier_flags_ &= ~mask;
+}
+
+int EventModifiersEvdev::GetModifierFlags() { return modifier_flags_; }
+
+}  // namespace ui
diff --git a/ui/events/ozone/evdev/event_modifiers.h b/ui/events/ozone/evdev/event_modifiers.h
new file mode 100644
index 0000000..5af3bb2
--- /dev/null
+++ b/ui/events/ozone/evdev/event_modifiers.h
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
+#define UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
+
+#include "ui/events/ozone/event_converter_ozone.h"
+
+namespace ui {
+
+enum {
+  EVDEV_MODIFIER_NONE,
+  EVDEV_MODIFIER_CAPS_LOCK,
+  EVDEV_MODIFIER_SHIFT,
+  EVDEV_MODIFIER_CONTROL,
+  EVDEV_MODIFIER_ALT,
+  EVDEV_MODIFIER_LEFT_MOUSE_BUTTON,
+  EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON,
+  EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON,
+  EVDEV_MODIFIER_COMMAND,
+  EVDEV_MODIFIER_ALTGR,
+  EVDEV_NUM_MODIFIERS
+};
+
+// Modifier key state for Evdev.
+//
+// Chrome relies on the underlying OS to interpret modifier keys such as Shift,
+// Ctrl, and Alt. The Linux input subsystem does not assign any special meaning
+// to these keys, so this work must happen at a higher layer (normally X11 or
+// the console driver). When using evdev directly, we must do it ourselves.
+//
+// The modifier state is shared between all input devices connected to the
+// system. This is to support actions such as Shift-Clicking that use multiple
+// devices.
+//
+// Normally a modifier is set if any of the keys or buttons assigned to it are
+// currently pressed. However some keys toggle a persistent "lock" for the
+// modifier instead, such as CapsLock. If a modifier is "locked" then its state
+// is inverted until it is unlocked.
+class EventModifiersEvdev {
+ public:
+  EventModifiersEvdev();
+  ~EventModifiersEvdev();
+
+  // Record key press or release for regular modifier key (shift, alt, etc).
+  void UpdateModifier(unsigned int modifier, bool down);
+
+  // Record key press or release for locking modifier key (caps lock).
+  void UpdateModifierLock(unsigned int modifier, bool down);
+
+  // Return current flags to use for incoming events.
+  int GetModifierFlags();
+
+ private:
+  // Count of keys pressed for each modifier.
+  int modifiers_down_[EVDEV_NUM_MODIFIERS];
+
+  // Mask of modifier flags currently "locked".
+  int modifier_flags_locked_;
+
+  // Mask of modifier flags currently active (nonzero keys pressed xor locked).
+  int modifier_flags_;
+
+  // Update modifier_flags_ from modifiers_down_ and modifier_flags_locked_.
+  void UpdateFlags(unsigned int modifier);
+
+  DISALLOW_COPY_AND_ASSIGN(EventModifiersEvdev);
+};
+
+}  // namspace ui
+
+#endif  // UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
diff --git a/ui/events/ozone/evdev/key_event_converter.cc b/ui/events/ozone/evdev/key_event_converter.cc
index a30dcc2..a1bc03e 100644
--- a/ui/events/ozone/evdev/key_event_converter.cc
+++ b/ui/events/ozone/evdev/key_event_converter.cc
@@ -8,6 +8,9 @@
 
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/evdev/event_modifiers.h"
+
+namespace ui {
 
 namespace {
 
@@ -150,12 +153,43 @@
   return ui::VKEY_UNKNOWN;
 }
 
+int ModifierFromButton(unsigned int code) {
+  switch (code) {
+    case KEY_CAPSLOCK:
+      return EVDEV_MODIFIER_CAPS_LOCK;
+    case KEY_LEFTSHIFT:
+    case KEY_RIGHTSHIFT:
+      return EVDEV_MODIFIER_SHIFT;
+    case KEY_LEFTCTRL:
+    case KEY_RIGHTCTRL:
+      return EVDEV_MODIFIER_CONTROL;
+    case KEY_LEFTALT:
+    case KEY_RIGHTALT:
+      return EVDEV_MODIFIER_ALT;
+    case BTN_LEFT:
+      return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
+    case BTN_MIDDLE:
+      return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
+    case BTN_RIGHT:
+      return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
+    case KEY_LEFTMETA:
+    case KEY_RIGHTMETA:
+      return EVDEV_MODIFIER_COMMAND;
+    default:
+      return EVDEV_MODIFIER_NONE;
+  }
+}
+
+bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
+
 }  // namespace
 
-namespace ui {
-
 // TODO(rjkroege): Stop leaking file descriptor.
-KeyEventConverterEvdev::KeyEventConverterEvdev() {}
+KeyEventConverterEvdev::KeyEventConverterEvdev(EventModifiersEvdev* modifiers)
+    : modifiers_(modifiers) {
+  // TODO(spang): Initialize modifiers using EVIOCGKEY.
+}
+
 KeyEventConverterEvdev::~KeyEventConverterEvdev() {}
 
 void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
@@ -165,23 +199,46 @@
     return;
 
   CHECK_EQ(read_size % sizeof(*inputs), 0u);
-  for (unsigned i = 0; i < read_size / sizeof(*inputs); ++i) {
+  ProcessEvents(inputs, read_size / sizeof(*inputs));
+}
+
+void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
+  NOTREACHED();
+}
+
+void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs,
+                                           int count) {
+  for (int i = 0; i < count; ++i) {
     const input_event& input = inputs[i];
     if (input.type == EV_KEY) {
-      scoped_ptr<KeyEvent> key(
-          new KeyEvent(input.value == 0 ? ET_KEY_RELEASED : ET_KEY_PRESSED,
-                       KeyboardCodeFromButton(input.code),
-                       0,
-                       true));
-      DispatchEvent(key.PassAs<ui::Event>());
+      ConvertKeyEvent(input.code, input.value);
     } else if (input.type == EV_SYN) {
       // TODO(sadrul): Handle this case appropriately.
     }
   }
 }
 
-void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
-  NOTREACHED();
+void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) {
+  int down = (value != 0);
+  int repeat = (value == 2);
+  int modifier = ModifierFromButton(key);
+  ui::KeyboardCode code = KeyboardCodeFromButton(key);
+
+  if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) {
+    if (IsLockButton(key)) {
+      // Locking modifier keys: CapsLock.
+      modifiers_->UpdateModifierLock(modifier, down);
+    } else {
+      // Regular modifier keys: Shift, Ctrl, Alt, etc.
+      modifiers_->UpdateModifier(modifier, down);
+    }
+  }
+
+  int flags = modifiers_->GetModifierFlags();
+
+  scoped_ptr<KeyEvent> key_event(
+      new KeyEvent(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, code, flags, true));
+  DispatchEvent(key_event.PassAs<ui::Event>());
 }
 
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/key_event_converter.h b/ui/events/ozone/evdev/key_event_converter.h
index f2af04e..558cc16 100644
--- a/ui/events/ozone/evdev/key_event_converter.h
+++ b/ui/events/ozone/evdev/key_event_converter.h
@@ -5,20 +5,30 @@
 #ifndef UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
 #define UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
 
+#include "ui/events/event.h"
+#include "ui/events/ozone/evdev/event_modifiers.h"
 #include "ui/events/ozone/event_converter_ozone.h"
 
+struct input_event;
+
 namespace ui {
 
 class KeyEventConverterEvdev : public EventConverterOzone {
  public:
-  KeyEventConverterEvdev();
+  KeyEventConverterEvdev(EventModifiersEvdev* modifiers);
   virtual ~KeyEventConverterEvdev();
 
- private:
   // Overidden from base::MessagePumpLibevent::Watcher.
   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
 
+  void ProcessEvents(const struct input_event* inputs, int count);
+
+ private:
+  EventModifiersEvdev* modifiers_;
+
+  void ConvertKeyEvent(int key, int value);
+
   DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdev);
 };
 
diff --git a/ui/events/ozone/evdev/key_event_converter_unittest.cc b/ui/events/ozone/evdev/key_event_converter_unittest.cc
new file mode 100644
index 0000000..d7b8876
--- /dev/null
+++ b/ui/events/ozone/evdev/key_event_converter_unittest.cc
@@ -0,0 +1,320 @@
+// Copyright 2013 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 <linux/input.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/evdev/key_event_converter.h"
+
+namespace ui {
+
+class MockKeyEventConverterEvdev : public KeyEventConverterEvdev {
+ public:
+  MockKeyEventConverterEvdev(EventModifiersEvdev* modifiers)
+      : KeyEventConverterEvdev(modifiers) {}
+  virtual ~MockKeyEventConverterEvdev() {};
+
+  unsigned size() { return dispatched_events_.size(); }
+  KeyEvent* event(unsigned index) { return dispatched_events_[index]; }
+
+  virtual void DispatchEvent(scoped_ptr<Event> event) OVERRIDE;
+
+ private:
+  ScopedVector<KeyEvent> dispatched_events_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockKeyEventConverterEvdev);
+};
+
+void MockKeyEventConverterEvdev::DispatchEvent(scoped_ptr<Event> event) {
+  dispatched_events_.push_back(static_cast<KeyEvent*>(event.release()));
+}
+
+}  // namespace ui
+
+// Test fixture.
+class KeyEventConverterEvdevTest : public testing::Test {
+ public:
+  KeyEventConverterEvdevTest() {}
+
+  // Overridden from testing::Test:
+  virtual void SetUp() OVERRIDE {
+    modifiers_ = new ui::EventModifiersEvdev();
+    device_ = new ui::MockKeyEventConverterEvdev(modifiers_);
+  }
+  virtual void TearDown() OVERRIDE {
+    delete device_;
+    delete modifiers_;
+  }
+
+  ui::MockKeyEventConverterEvdev* device() { return device_; }
+  ui::EventModifiersEvdev* modifiers() { return modifiers_; }
+
+ private:
+  ui::EventModifiersEvdev* modifiers_;
+  ui::MockKeyEventConverterEvdev* device_;
+  DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdevTest);
+};
+
+TEST_F(KeyEventConverterEvdevTest, KeyPress) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+
+  struct input_event mock_kernel_queue[] = {
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+  EXPECT_EQ(2u, dev->size());
+
+  ui::KeyEvent* event;
+
+  event = dev->event(0);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+
+  event = dev->event(1);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyRepeat) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+
+  struct input_event mock_kernel_queue[] = {
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+      {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+  EXPECT_EQ(4u, dev->size());
+
+  ui::KeyEvent* event;
+
+  event = dev->event(0);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+
+  event = dev->event(1);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+
+  event = dev->event(2);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+
+  event = dev->event(3);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+  EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, NoEvents) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+  dev->ProcessEvents(NULL, 0);
+  EXPECT_EQ(0u, dev->size());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithModifier) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+
+  struct input_event mock_kernel_queue[] = {
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+      {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
+      {{0, 0}, EV_KEY, KEY_A, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
+      {{0, 0}, EV_KEY, KEY_A, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+      {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+  EXPECT_EQ(4u, dev->size());
+
+  ui::KeyEvent* event;
+
+  event = dev->event(0);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
+  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+  event = dev->event(1);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_A, event->key_code());
+  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+  event = dev->event(2);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_A, event->key_code());
+  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+  event = dev->event(3);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
+  EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithDuplicateModifier) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+
+  struct input_event mock_kernel_queue[] = {
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+      {{0, 0}, EV_KEY, KEY_LEFTCTRL, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
+      {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
+      {{0, 0}, EV_KEY, KEY_Z, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
+      {{0, 0}, EV_KEY, KEY_Z, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+      {{0, 0}, EV_KEY, KEY_LEFTCTRL, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
+      {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+  EXPECT_EQ(6u, dev->size());
+
+  ui::KeyEvent* event;
+
+  event = dev->event(0);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+  event = dev->event(1);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+  event = dev->event(2);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_Z, event->key_code());
+  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+  event = dev->event(3);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_Z, event->key_code());
+  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+  event = dev->event(4);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+  event = dev->event(5);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+  EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithLock) {
+  ui::MockKeyEventConverterEvdev* dev = device();
+
+  struct input_event mock_kernel_queue[] = {
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
+      {{0, 0}, EV_KEY, KEY_Q, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
+      {{0, 0}, EV_KEY, KEY_Q, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+  EXPECT_EQ(6u, dev->size());
+
+  ui::KeyEvent* event;
+
+  event = dev->event(0);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+  EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+  event = dev->event(1);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+  EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+  event = dev->event(2);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_Q, event->key_code());
+  EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+  event = dev->event(3);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_Q, event->key_code());
+  EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+  event = dev->event(4);
+  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+  EXPECT_EQ(0, event->flags());
+
+  event = dev->event(5);
+  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+  EXPECT_EQ(0, event->flags());
+}
diff --git a/ui/events/ozone/event_converter_ozone.h b/ui/events/ozone/event_converter_ozone.h
index b28df34..ba35ea8 100644
--- a/ui/events/ozone/event_converter_ozone.h
+++ b/ui/events/ozone/event_converter_ozone.h
@@ -27,7 +27,7 @@
   // Subclasses should use this method to post a task that will dispatch
   // |event| from the UI message loop. This method takes ownership of
   // |event|. |event| will be deleted at the end of the posted task.
-  void DispatchEvent(scoped_ptr<ui::Event> event);
+  virtual void DispatchEvent(scoped_ptr<ui::Event> event);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(EventConverterOzone);
diff --git a/ui/events/ozone/event_factory_delegate_ozone.cc b/ui/events/ozone/event_factory_delegate_ozone.cc
deleted file mode 100644
index 7a657c8..0000000
--- a/ui/events/ozone/event_factory_delegate_ozone.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/event_factory_delegate_ozone.h"
-
-namespace ui {
-
-EventFactoryDelegateOzone::EventFactoryDelegateOzone() {}
-
-EventFactoryDelegateOzone::~EventFactoryDelegateOzone() {}
-
-}  // namespace ui
diff --git a/ui/events/ozone/event_factory_delegate_ozone.h b/ui/events/ozone/event_factory_delegate_ozone.h
deleted file mode 100644
index ad7fc52..0000000
--- a/ui/events/ozone/event_factory_delegate_ozone.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_OZONE_H_
-#define UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_OZONE_H_
-
-#include "base/basictypes.h"
-#include "ui/events/events_export.h"
-
-namespace ui {
-class Event;
-class EventFactoryOzone;
-
-// An embedder can install an instance of this interface to take control of
-// what |EventConverterOzone| objects get created on the creation of
-// the |RootWindowHostOzone| object.
-class EVENTS_EXPORT EventFactoryDelegateOzone {
- public:
-  EventFactoryDelegateOzone();
-  virtual ~EventFactoryDelegateOzone();
-
-  // Override this method with embedder-appropriate converter creation.
-  virtual void CreateStartupEventConverters(EventFactoryOzone* factory) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(EventFactoryDelegateOzone);
-};
-
-}  // namespace ui
-
-#endif  // UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_OZONE_H_
diff --git a/ui/events/ozone/event_factory_ozone.cc b/ui/events/ozone/event_factory_ozone.cc
index f3ba154..36cc37e 100644
--- a/ui/events/ozone/event_factory_ozone.cc
+++ b/ui/events/ozone/event_factory_ozone.cc
@@ -9,36 +9,31 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "ui/events/event_switches.h"
-#include "ui/events/ozone/event_factory_delegate_ozone.h"
 
 #if defined(USE_OZONE_EVDEV)
-#include "ui/events/ozone/evdev/event_factory_delegate.h"
+#include "ui/events/ozone/evdev/event_factory.h"
 #endif
 
 namespace ui {
 
 namespace {
 
+EventFactoryOzone* CreateFactory(const std::string& event_factory) {
 #if defined(USE_OZONE_EVDEV)
-static const char kEventFactoryEvdev[] = "evdev";
+  if (event_factory == "evdev" || event_factory == "default")
+    return new EventFactoryEvdev;
 #endif
 
-EventFactoryDelegateOzone* CreateDelegate(const std::string& event_delegate) {
-#if defined(USE_OZONE_EVDEV)
-  if (event_delegate == "evdev" || event_delegate == "default")
-    return new EventFactoryDelegateEvdev;
-#endif
-
-  if (event_delegate == "none" || event_delegate == "default") {
+  if (event_factory == "none" || event_factory == "default") {
     LOG(WARNING) << "No ozone events implementation - limited input support";
-    return NULL;
+    return new EventFactoryOzone;
   }
 
-  LOG(FATAL) << "Invalid ozone events implementation: " << event_delegate;
+  LOG(FATAL) << "Invalid ozone events implementation: " << event_factory;
   return NULL;  // not reached
 }
 
-std::string GetRequestedDelegate() {
+std::string GetRequestedFactory() {
   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kOzoneEvents))
     return "default";
   return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
@@ -48,7 +43,7 @@
 }  // namespace
 
 // static
-EventFactoryDelegateOzone* EventFactoryOzone::delegate_ = NULL;
+EventFactoryOzone* EventFactoryOzone::impl_ = NULL;
 
 EventFactoryOzone::EventFactoryOzone() {}
 
@@ -58,22 +53,18 @@
   STLDeleteValues<std::map<int, Converter> >(&converters_);
 }
 
-void EventFactoryOzone::CreateStartupEventConverters() {
-  if (!delegate_) {
-    std::string requested_delegate = GetRequestedDelegate();
-    SetEventFactoryDelegateOzone(CreateDelegate(requested_delegate));
+EventFactoryOzone* EventFactoryOzone::GetInstance() {
+  if (!impl_) {
+    std::string requested = GetRequestedFactory();
+    impl_ = CreateFactory(requested);
   }
-  if (delegate_)
-    delegate_->CreateStartupEventConverters(this);
+  CHECK(impl_) << "No EventFactoryOzone implementation set.";
+  return impl_;
 }
 
-// static
-void EventFactoryOzone::SetEventFactoryDelegateOzone(
-    EventFactoryDelegateOzone* delegate) {
-  // It should be unnecessary to call this more than once.
-  DCHECK(!delegate_);
-  delegate_ = delegate;
-}
+void EventFactoryOzone::SetInstance(EventFactoryOzone* impl) { impl_ = impl; }
+
+void EventFactoryOzone::StartProcessingEvents() {}
 
 void EventFactoryOzone::AddEventConverter(
     int fd,
diff --git a/ui/events/ozone/event_factory_ozone.h b/ui/events/ozone/event_factory_ozone.h
index c818ee0..389946a 100644
--- a/ui/events/ozone/event_factory_ozone.h
+++ b/ui/events/ozone/event_factory_ozone.h
@@ -14,8 +14,6 @@
 
 namespace ui {
 
-class EventFactoryDelegateOzone;
-
 // Creates and dispatches |ui.Event|'s. Ozone assumes that events arrive on file
 // descriptors with one  |EventConverterOzone| instance for each descriptor.
 // Ozone presumes that the set of file desctiprtors can vary at runtime so this
@@ -24,17 +22,21 @@
 class EVENTS_EXPORT EventFactoryOzone {
  public:
   EventFactoryOzone();
-  ~EventFactoryOzone();
+  virtual ~EventFactoryOzone();
 
-  // Sets an optional delegate responsible for creating the starting set of
-  // EventConvertOzones under management. This permits embedders to override the
-  // Linux /dev/input/*-based default as desired. The caller must manage the
-  // scope of this object.
-  static void SetEventFactoryDelegateOzone(EventFactoryDelegateOzone* delegate);
+  // Called from RootWindowHostOzone to initialize and start processing events.
+  // This should create the initial set of converters, and potentially arrange
+  // for more converters to be created as new event sources become available.
+  // No events processing should happen until this is called. All processes have
+  // an EventFactoryOzone but not all of them should process events. In chrome,
+  // events are dispatched in the browser process on the UI thread.
+  virtual void StartProcessingEvents();
 
-  // Called from RootWindowHostOzone to create the starting set of event
-  // converters.
-  void CreateStartupEventConverters();
+  // Returns the static instance last set using SetInstance().
+  static EventFactoryOzone* GetInstance();
+
+  // Sets the implementation delegate. Ownership is retained by the caller.
+  static void SetInstance(EventFactoryOzone*);
 
   // Add an |EventConverterOzone| instances for the given file descriptor.
   // Transfers ownership of the |EventConverterOzone| to this class.
@@ -50,7 +52,7 @@
   std::map<int, Converter> converters_;
   std::map<int, FDWatcher> watchers_;
 
-  static EventFactoryDelegateOzone* delegate_;
+  static EventFactoryOzone* impl_;  // not owned
 
   DISALLOW_COPY_AND_ASSIGN(EventFactoryOzone);
 };
diff --git a/ui/gfx/OWNERS b/ui/gfx/OWNERS
index 642fb61..563c600 100644
--- a/ui/gfx/OWNERS
+++ b/ui/gfx/OWNERS
@@ -18,3 +18,6 @@
 per-file transform*=shawnsingh@chromium.org
 per-file transform*=vollick@chromium.org
 per-file interpolated_transform*=vollick@chromium.org
+
+# If you're doing structural changes get a review from one of the OWNERS.
+per-file *.gyp*=*
diff --git a/ui/gfx/android/device_display_info.cc b/ui/gfx/android/device_display_info.cc
index 23c6c2e..2de8440 100644
--- a/ui/gfx/android/device_display_info.cc
+++ b/ui/gfx/android/device_display_info.cc
@@ -4,70 +4,39 @@
 
 #include "ui/gfx/android/device_display_info.h"
 
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
 #include "base/logging.h"
-#include "jni/DeviceDisplayInfo_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ScopedJavaLocalRef;
+#include "ui/gfx/android/shared_device_display_info.h"
 
 namespace gfx {
 
 DeviceDisplayInfo::DeviceDisplayInfo() {
-  JNIEnv* env = AttachCurrentThread();
-  j_device_info_.Reset(Java_DeviceDisplayInfo_create(env,
-      base::android::GetApplicationContext()));
 }
 
 DeviceDisplayInfo::~DeviceDisplayInfo() {
 }
 
 int DeviceDisplayInfo::GetDisplayHeight() {
-  JNIEnv* env = AttachCurrentThread();
-  jint result =
-      Java_DeviceDisplayInfo_getDisplayHeight(env, j_device_info_.obj());
-  return static_cast<int>(result);
+  return SharedDeviceDisplayInfo::GetInstance()->GetDisplayHeight();
 }
 
 int DeviceDisplayInfo::GetDisplayWidth() {
-  JNIEnv* env = AttachCurrentThread();
-  jint result =
-      Java_DeviceDisplayInfo_getDisplayWidth(env, j_device_info_.obj());
-  return static_cast<int>(result);
+  return SharedDeviceDisplayInfo::GetInstance()->GetDisplayWidth();
 }
 
 int DeviceDisplayInfo::GetBitsPerPixel() {
-  JNIEnv* env = AttachCurrentThread();
-  jint result =
-      Java_DeviceDisplayInfo_getBitsPerPixel(env, j_device_info_.obj());
-  return static_cast<int>(result);
+  return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerPixel();
 }
 
 int DeviceDisplayInfo::GetBitsPerComponent() {
-  JNIEnv* env = AttachCurrentThread();
-  jint result =
-      Java_DeviceDisplayInfo_getBitsPerComponent(env, j_device_info_.obj());
-  return static_cast<int>(result);
+  return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerComponent();
 }
 
 double DeviceDisplayInfo::GetDIPScale() {
-  JNIEnv* env = AttachCurrentThread();
-  jdouble result =
-      Java_DeviceDisplayInfo_getDIPScale(env, j_device_info_.obj());
-  return static_cast<double>(result);
+  return SharedDeviceDisplayInfo::GetInstance()->GetDIPScale();
 }
 
 int DeviceDisplayInfo::GetSmallestDIPWidth() {
-  JNIEnv* env = AttachCurrentThread();
-  jint result =
-      Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj());
-  return static_cast<int>(result);
-}
-
-// static
-bool DeviceDisplayInfo::RegisterDeviceDisplayInfo(JNIEnv* env) {
-  return RegisterNativesImpl(env);
+  return SharedDeviceDisplayInfo::GetInstance()->GetSmallestDIPWidth();
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/android/device_display_info.h b/ui/gfx/android/device_display_info.h
index ace8569..83968e9 100644
--- a/ui/gfx/android/device_display_info.h
+++ b/ui/gfx/android/device_display_info.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 #include <string>
 
-#include "base/android/scoped_java_ref.h"
 #include "base/basictypes.h"
 #include "ui/gfx/gfx_export.h"
 
@@ -40,12 +39,7 @@
   // Smallest possible screen size in density-independent pixels.
   int GetSmallestDIPWidth();
 
-  // Registers methods with JNI and returns true if succeeded.
-  static bool RegisterDeviceDisplayInfo(JNIEnv* env);
-
  private:
-  base::android::ScopedJavaGlobalRef<jobject> j_device_info_;
-
   DISALLOW_COPY_AND_ASSIGN(DeviceDisplayInfo);
 };
 
diff --git a/ui/gfx/android/gfx_jni_registrar.cc b/ui/gfx/android/gfx_jni_registrar.cc
index 8aa8551..be60a33 100644
--- a/ui/gfx/android/gfx_jni_registrar.cc
+++ b/ui/gfx/android/gfx_jni_registrar.cc
@@ -6,15 +6,16 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
-#include "ui/gfx/android/device_display_info.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/android/shared_device_display_info.h"
 
 namespace gfx {
 namespace android {
 
 static base::android::RegistrationMethod kGfxRegisteredMethods[] = {
-  { "DeviceDisplayInfo", gfx::DeviceDisplayInfo::RegisterDeviceDisplayInfo },
-  { "JavaBitmap", gfx::JavaBitmap::RegisterJavaBitmap },
+  { "SharedDeviceDisplayInfo",
+      SharedDeviceDisplayInfo::RegisterSharedDeviceDisplayInfo },
+  { "JavaBitmap", JavaBitmap::RegisterJavaBitmap },
 };
 
 bool RegisterJni(JNIEnv* env) {
diff --git a/ui/gfx/android/shared_device_display_info.cc b/ui/gfx/android/shared_device_display_info.cc
new file mode 100644
index 0000000..9ac18d0
--- /dev/null
+++ b/ui/gfx/android/shared_device_display_info.cc
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/android/shared_device_display_info.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+#include "jni/DeviceDisplayInfo_jni.h"
+
+namespace gfx {
+
+// static JNI call
+static void UpdateSharedDeviceDisplayInfo(JNIEnv* env,
+                                          jobject obj,
+                                          jint display_height,
+                                          jint display_width,
+                                          jint bits_per_pixel,
+                                          jint bits_per_component,
+                                          jdouble dip_scale,
+                                          jint smallest_dip_width) {
+  SharedDeviceDisplayInfo::GetInstance()->InvokeUpdate(env, obj,
+      display_height, display_width, bits_per_pixel, bits_per_component,
+      dip_scale, smallest_dip_width);
+}
+
+// static
+SharedDeviceDisplayInfo* SharedDeviceDisplayInfo::GetInstance() {
+  return Singleton<SharedDeviceDisplayInfo>::get();
+}
+
+int SharedDeviceDisplayInfo::GetDisplayHeight() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, display_height_);
+  return display_height_;
+}
+
+int SharedDeviceDisplayInfo::GetDisplayWidth() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, display_width_);
+  return display_width_;
+}
+
+int SharedDeviceDisplayInfo::GetBitsPerPixel() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, bits_per_pixel_);
+  return bits_per_pixel_;
+}
+
+int SharedDeviceDisplayInfo::GetBitsPerComponent() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, bits_per_component_);
+  return bits_per_component_;
+}
+
+double SharedDeviceDisplayInfo::GetDIPScale() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, dip_scale_);
+  return dip_scale_;
+}
+
+int SharedDeviceDisplayInfo::GetSmallestDIPWidth() {
+  base::AutoLock autolock(lock_);
+  DCHECK_NE(0, smallest_dip_width_);
+  return smallest_dip_width_;
+}
+
+// static
+bool SharedDeviceDisplayInfo::RegisterSharedDeviceDisplayInfo(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void SharedDeviceDisplayInfo::InvokeUpdate(JNIEnv* env,
+                                           jobject obj,
+                                           jint display_height,
+                                           jint display_width,
+                                           jint bits_per_pixel,
+                                           jint bits_per_component,
+                                           jdouble dip_scale,
+                                           jint smallest_dip_width) {
+  base::AutoLock autolock(lock_);
+
+  UpdateDisplayInfo(env, obj, display_height,
+      display_width, bits_per_pixel, bits_per_component, dip_scale,
+      smallest_dip_width);
+}
+
+SharedDeviceDisplayInfo::SharedDeviceDisplayInfo()
+    : display_height_(0),
+      display_width_(0),
+      bits_per_pixel_(0),
+      bits_per_component_(0),
+      dip_scale_(0),
+      smallest_dip_width_(0) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  j_device_info_.Reset(
+      Java_DeviceDisplayInfo_createWithListener(env,
+          base::android::GetApplicationContext()));
+  UpdateDisplayInfo(env, j_device_info_.obj(),
+      Java_DeviceDisplayInfo_getDisplayHeight(env, j_device_info_.obj()),
+      Java_DeviceDisplayInfo_getDisplayWidth(env, j_device_info_.obj()),
+      Java_DeviceDisplayInfo_getBitsPerPixel(env, j_device_info_.obj()),
+      Java_DeviceDisplayInfo_getBitsPerComponent(env, j_device_info_.obj()),
+      Java_DeviceDisplayInfo_getDIPScale(env, j_device_info_.obj()),
+      Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj()));
+}
+
+SharedDeviceDisplayInfo::~SharedDeviceDisplayInfo() {
+}
+
+void SharedDeviceDisplayInfo::UpdateDisplayInfo(JNIEnv* env,
+                                                jobject jobj,
+                                                jint display_height,
+                                                jint display_width,
+                                                jint bits_per_pixel,
+                                                jint bits_per_component,
+                                                jdouble dip_scale,
+                                                jint smallest_dip_width) {
+  display_height_ = static_cast<int>(display_height);
+  display_width_ = static_cast<int>(display_width);
+  bits_per_pixel_ = static_cast<int>(bits_per_pixel);
+  bits_per_component_ = static_cast<int>(bits_per_component);
+  dip_scale_ = static_cast<double>(dip_scale);
+  smallest_dip_width_ = static_cast<int>(smallest_dip_width);
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/android/shared_device_display_info.h b/ui/gfx/android/shared_device_display_info.h
new file mode 100644
index 0000000..1e1fc0c
--- /dev/null
+++ b/ui/gfx/android/shared_device_display_info.h
@@ -0,0 +1,68 @@
+// Copyright 2013 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_GFX_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_
+#define UI_GFX_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+
+namespace gfx {
+
+// Facilitates access to device information typically only
+// available using the Android SDK, including Display properties.
+class SharedDeviceDisplayInfo {
+ public:
+  static SharedDeviceDisplayInfo* GetInstance();
+
+  int GetDisplayHeight();
+  int GetDisplayWidth();
+  int GetBitsPerPixel();
+  int GetBitsPerComponent();
+  double GetDIPScale();
+  int GetSmallestDIPWidth();
+
+  // Registers methods with JNI and returns true if succeeded.
+  static bool RegisterSharedDeviceDisplayInfo(JNIEnv* env);
+
+  void InvokeUpdate(JNIEnv* env,
+                    jobject jobj,
+                    jint display_height,
+                    jint display_width,
+                    jint bits_per_pixel,
+                    jint bits_per_component,
+                    jdouble dip_scale,
+                    jint smallest_dip_width);
+ private:
+  friend struct DefaultSingletonTraits<SharedDeviceDisplayInfo>;
+
+  SharedDeviceDisplayInfo();
+  ~SharedDeviceDisplayInfo();
+  void UpdateDisplayInfo(JNIEnv* env,
+                         jobject jobj,
+                         jint display_height,
+                         jint display_width,
+                         jint bits_per_pixel,
+                         jint bits_per_component,
+                         jdouble dip_scale,
+                         jint smallest_dip_width);
+
+  base::Lock lock_;
+  base::android::ScopedJavaGlobalRef<jobject> j_device_info_;
+
+  int display_height_;
+  int display_width_;
+  int bits_per_pixel_;
+  int bits_per_component_;
+  double dip_scale_;
+  int smallest_dip_width_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedDeviceDisplayInfo);
+};
+
+}  // namespace gfx
+
+#endif // UI_GFX_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_
diff --git a/ui/gfx/animation/animation_container.cc b/ui/gfx/animation/animation_container.cc
index c76f1bb..d8290b2 100644
--- a/ui/gfx/animation/animation_container.cc
+++ b/ui/gfx/animation/animation_container.cc
@@ -6,6 +6,7 @@
 
 #include "ui/gfx/animation/animation_container_element.h"
 #include "ui/gfx/animation/animation_container_observer.h"
+#include "ui/gfx/frame_time.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
@@ -13,7 +14,7 @@
 namespace gfx {
 
 AnimationContainer::AnimationContainer()
-    : last_tick_time_(TimeTicks::Now()),
+    : last_tick_time_(gfx::FrameTime::Now()),
       observer_(NULL) {
 }
 
@@ -28,7 +29,7 @@
                                           // element isn't running.
 
   if (elements_.empty()) {
-    last_tick_time_ = TimeTicks::Now();
+    last_tick_time_ = gfx::FrameTime::Now();
     SetMinTimerInterval(element->GetTimerInterval());
   } else if (element->GetTimerInterval() < min_timer_interval_) {
     SetMinTimerInterval(element->GetTimerInterval());
@@ -61,7 +62,7 @@
   // ourself here to make sure we're still valid after running all the elements.
   scoped_refptr<AnimationContainer> this_ref(this);
 
-  TimeTicks current_time = TimeTicks::Now();
+  TimeTicks current_time = gfx::FrameTime::Now();
 
   last_tick_time_ = current_time;
 
diff --git a/ui/gfx/animation/tween.cc b/ui/gfx/animation/tween.cc
index 76944bf..2a0027a 100644
--- a/ui/gfx/animation/tween.cc
+++ b/ui/gfx/animation/tween.cc
@@ -10,7 +10,9 @@
 #include <float.h>
 #endif
 
+#include "base/basictypes.h"
 #include "base/logging.h"
+#include "ui/gfx/safe_integer_conversions.h"
 
 namespace gfx {
 
@@ -55,6 +57,58 @@
   return state;
 }
 
+namespace {
+uint8 FloatToColorByte(float f) {
+  return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255);
+}
+
+uint8 BlendColorComponents(uint8 start,
+                           uint8 target,
+                           float start_alpha,
+                           float target_alpha,
+                           float blended_alpha,
+                           double progress) {
+  // Since progress can be outside [0, 1], blending can produce a value outside
+  // [0, 255].
+  float blended_premultiplied = Tween::FloatValueBetween(
+      progress, start / 255.f * start_alpha, target / 255.f * target_alpha);
+  return FloatToColorByte(blended_premultiplied / blended_alpha);
+}
+
+}  // namespace
+
+// static
+SkColor Tween::ColorValueBetween(double value, SkColor start, SkColor target) {
+  float start_a = SkColorGetA(start) / 255.f;
+  float target_a = SkColorGetA(target) / 255.f;
+  float blended_a = FloatValueBetween(value, start_a, target_a);
+  if (blended_a <= 0.f)
+    return SkColorSetARGB(0, 0, 0, 0);
+  blended_a = std::min(blended_a, 1.f);
+
+  uint8 blended_r = BlendColorComponents(SkColorGetR(start),
+                                         SkColorGetR(target),
+                                         start_a,
+                                         target_a,
+                                         blended_a,
+                                         value);
+  uint8 blended_g = BlendColorComponents(SkColorGetG(start),
+                                         SkColorGetG(target),
+                                         start_a,
+                                         target_a,
+                                         blended_a,
+                                         value);
+  uint8 blended_b = BlendColorComponents(SkColorGetB(start),
+                                         SkColorGetB(target),
+                                         start_a,
+                                         target_a,
+                                         blended_a,
+                                         value);
+
+  return SkColorSetARGB(
+      FloatToColorByte(blended_a), blended_r, blended_g, blended_b);
+}
+
 // static
 double Tween::DoubleValueBetween(double value, double start, double target) {
   return start + (target - start) * value;
@@ -81,15 +135,21 @@
 #endif
 }
 
+//static
+int Tween::LinearIntValueBetween(double value, int start, int target) {
+  return std::floor(0.5 + DoubleValueBetween(value, start, target));
+}
+
 // static
 gfx::Rect Tween::RectValueBetween(double value,
                                   const gfx::Rect& start_bounds,
                                   const gfx::Rect& target_bounds) {
   return gfx::Rect(
-      IntValueBetween(value, start_bounds.x(), target_bounds.x()),
-      IntValueBetween(value, start_bounds.y(), target_bounds.y()),
-      IntValueBetween(value, start_bounds.width(), target_bounds.width()),
-      IntValueBetween(value, start_bounds.height(), target_bounds.height()));
+      LinearIntValueBetween(value, start_bounds.x(), target_bounds.x()),
+      LinearIntValueBetween(value, start_bounds.y(), target_bounds.y()),
+      LinearIntValueBetween(value, start_bounds.width(), target_bounds.width()),
+      LinearIntValueBetween(
+          value, start_bounds.height(), target_bounds.height()));
 }
 
 // static
diff --git a/ui/gfx/animation/tween.h b/ui/gfx/animation/tween.h
index d6abd35..04f353d 100644
--- a/ui/gfx/animation/tween.h
+++ b/ui/gfx/animation/tween.h
@@ -6,6 +6,7 @@
 #define UI_GFX_ANIMATION_TWEEN_H_
 
 #include "base/basictypes.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/gfx_export.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/transform.h"
@@ -30,9 +31,20 @@
   static double CalculateValue(Type type, double state);
 
   // Conveniences for getting a value between a start and end point.
+  static SkColor ColorValueBetween(double value, SkColor start, SkColor target);
   static double DoubleValueBetween(double value, double start, double target);
   static float FloatValueBetween(double value, float start, float target);
+
+  // Interpolated between start and target, with every integer in this range
+  // given equal weight.
   static int IntValueBetween(double value, int start, int target);
+
+  // Interpolates between start and target as real numbers, and rounds the
+  // result to the nearest integer, with ties broken by rounding towards
+  // positive infinity. This gives start and target half the weight of the
+  // other integers in the range. This is the integer interpolation approach
+  // specified by www.w3.org/TR/css3-transitions.
+  static int LinearIntValueBetween(double value, int start, int target);
   static gfx::Rect RectValueBetween(double value,
                                     const gfx::Rect& start_bounds,
                                     const gfx::Rect& target_bounds);
diff --git a/ui/gfx/animation/tween_unittest.cc b/ui/gfx/animation/tween_unittest.cc
new file mode 100644
index 0000000..d92fe1b
--- /dev/null
+++ b/ui/gfx/animation/tween_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/animation/tween.h"
+
+#include <math.h>
+
+#if defined(OS_WIN)
+#include <float.h>
+#endif
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/test/color_util.h"
+
+namespace gfx {
+namespace {
+
+double next_double(double d) {
+#if defined(OS_WIN)
+  return _nextafter(d, d+1);
+#else
+  return nextafter(d, d+1);
+#endif
+}
+
+// Validates that the same interpolations are made as in Blink.
+TEST(TweenTest, ColorValueBetween) {
+  // From blink's AnimatableColorTest.
+  EXPECT_SKCOLOR_EQ(0xFF00FF00,
+                  Tween::ColorValueBetween(-10.0, 0xFF00FF00, 0xFF00FF00));
+  EXPECT_SKCOLOR_EQ(0xFF00FF00,
+                  Tween::ColorValueBetween(-10.0, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFF00FF00,
+                  Tween::ColorValueBetween(0.0, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFF01FE01,
+                  Tween::ColorValueBetween(1.0 / 255, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFF808080,
+                  Tween::ColorValueBetween(0.5, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(
+      0xFFFE01FE,
+      Tween::ColorValueBetween(254.0 / 255.0, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFFFF00FF,
+                  Tween::ColorValueBetween(1.0, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFFFF00FF,
+                  Tween::ColorValueBetween(10.0, 0xFF00FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0xFF0C253E,
+                  Tween::ColorValueBetween(3.0 / 16.0, 0xFF001020, 0xFF4080C0));
+  EXPECT_SKCOLOR_EQ(0x80FF00FF,
+                  Tween::ColorValueBetween(0.5, 0x0000FF00, 0xFFFF00FF));
+  EXPECT_SKCOLOR_EQ(0x60AA55AA,
+                  Tween::ColorValueBetween(0.5, 0x4000FF00, 0x80FF00FF));
+  EXPECT_SKCOLOR_EQ(0x60FFAAFF,
+                  Tween::ColorValueBetween(0.5, 0x40FF00FF, 0x80FFFFFF));
+  EXPECT_SKCOLOR_EQ(0x103060A0,
+                  Tween::ColorValueBetween(0.5, 0x10204080, 0x104080C0));
+}
+
+// Ensures that each of the 3 integers in [0, 1, 2] ae selected with equal
+// weight.
+TEST(TweenTest, IntValueBetween) {
+  EXPECT_EQ(0, Tween::IntValueBetween(0.0, 0, 2));
+  EXPECT_EQ(0, Tween::IntValueBetween(0.5 / 3.0, 0, 2));
+  EXPECT_EQ(0, Tween::IntValueBetween(1.0 / 3.0, 0, 2));
+
+  EXPECT_EQ(1, Tween::IntValueBetween(next_double(1.0 / 3.0), 0, 2));
+  EXPECT_EQ(1, Tween::IntValueBetween(1.5 / 3.0, 0, 2));
+  EXPECT_EQ(1, Tween::IntValueBetween(2.0 / 3.0, 0, 2));
+
+  EXPECT_EQ(2, Tween::IntValueBetween(next_double(2.0 / 3.0), 0, 2));
+  EXPECT_EQ(2, Tween::IntValueBetween(2.5 / 3.0, 0, 2));
+  EXPECT_EQ(2, Tween::IntValueBetween(3.0 / 3.0, 0, 2));
+}
+
+TEST(TweenTest, IntValueBetweenNegative) {
+  EXPECT_EQ(-2, Tween::IntValueBetween(0.0, -2, 0));
+  EXPECT_EQ(-2, Tween::IntValueBetween(0.5 / 3.0, -2, 0));
+  EXPECT_EQ(-2, Tween::IntValueBetween(1.0 / 3.0, -2, 0));
+
+  EXPECT_EQ(-1, Tween::IntValueBetween(next_double(1.0 / 3.0), -2, 0));
+  EXPECT_EQ(-1, Tween::IntValueBetween(1.5 / 3.0, -2, 0));
+  EXPECT_EQ(-1, Tween::IntValueBetween(2.0 / 3.0, -2, 0));
+
+  EXPECT_EQ(0, Tween::IntValueBetween(next_double(2.0 / 3.0), -2, 0));
+  EXPECT_EQ(0, Tween::IntValueBetween(2.5 / 3.0, -2, 0));
+  EXPECT_EQ(0, Tween::IntValueBetween(3.0 / 3.0, -2, 0));
+}
+
+TEST(TweenTest, IntValueBetweenReverse) {
+  EXPECT_EQ(2, Tween::IntValueBetween(0.0, 2, 0));
+  EXPECT_EQ(2, Tween::IntValueBetween(0.5 / 3.0, 2, 0));
+  EXPECT_EQ(2, Tween::IntValueBetween(1.0 / 3.0, 2, 0));
+
+  EXPECT_EQ(1, Tween::IntValueBetween(next_double(1.0 / 3.0), 2, 0));
+  EXPECT_EQ(1, Tween::IntValueBetween(1.5 / 3.0, 2, 0));
+  EXPECT_EQ(1, Tween::IntValueBetween(2.0 / 3.0, 2, 0));
+
+  EXPECT_EQ(0, Tween::IntValueBetween(next_double(2.0 / 3.0), 2, 0));
+  EXPECT_EQ(0, Tween::IntValueBetween(2.5 / 3.0, 2, 0));
+  EXPECT_EQ(0, Tween::IntValueBetween(3.0 / 3.0, 2, 0));
+}
+
+TEST(TweenTest, LinearIntValueBetween) {
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(0.0, 0, 2));
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(0.5 / 4.0, 0, 2));
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(0.99 / 4.0, 0, 2));
+
+  EXPECT_EQ(1, Tween::LinearIntValueBetween(1.0 / 4.0, 0, 2));
+  EXPECT_EQ(1, Tween::LinearIntValueBetween(1.5 / 4.0, 0, 2));
+  EXPECT_EQ(1, Tween::LinearIntValueBetween(2.0 / 4.0, 0, 2));
+  EXPECT_EQ(1, Tween::LinearIntValueBetween(2.5 / 4.0, 0, 2));
+  EXPECT_EQ(1, Tween::LinearIntValueBetween(2.99 / 4.0, 0, 2));
+
+  EXPECT_EQ(2, Tween::LinearIntValueBetween(3.0 / 4.0, 0, 2));
+  EXPECT_EQ(2, Tween::LinearIntValueBetween(3.5 / 4.0, 0, 2));
+  EXPECT_EQ(2, Tween::LinearIntValueBetween(4.0 / 4.0, 0, 2));
+}
+
+TEST(TweenTest, LinearIntValueBetweenNegative) {
+  EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.0, -2, 0));
+  EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.5 / 4.0, -2, 0));
+  EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.99 / 4.0, -2, 0));
+
+  EXPECT_EQ(-1, Tween::LinearIntValueBetween(1.0 / 4.0, -2, 0));
+  EXPECT_EQ(-1, Tween::LinearIntValueBetween(1.5 / 4.0, -2, 0));
+  EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.0 / 4.0, -2, 0));
+  EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.5 / 4.0, -2, 0));
+  EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.99 / 4.0, -2, 0));
+
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(3.0 / 4.0, -2, 0));
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(3.5 / 4.0, -2, 0));
+  EXPECT_EQ(0, Tween::LinearIntValueBetween(4.0 / 4.0, -2, 0));
+}
+
+}  // namespace
+}  // namespace gfx
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 4470023..eb86e69 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -43,7 +43,6 @@
   enum TruncateFadeMode {
     TruncateFadeTail,
     TruncateFadeHead,
-    TruncateFadeHeadAndTail,
   };
 
   // Specifies the alignment for text rendered with the DrawStringInt method.
@@ -446,25 +445,20 @@
   // Apply transformation on the canvas.
   void Transform(const Transform& transform);
 
-  // Draws the given string with the beginning and/or the end using a fade
-  // gradient. When truncating the head
-  // |desired_characters_to_truncate_from_head| specifies the maximum number of
-  // characters that can be truncated.
+  // Draws the given string with the beginning or the end using a fade gradient.
   void DrawFadeTruncatingStringRect(
       const base::string16& text,
       TruncateFadeMode truncate_mode,
-      size_t desired_characters_to_truncate_from_head,
       const FontList& font_list,
       SkColor color,
       const Rect& display_rect);
-  // Obsolete version.  Use the above version which takes FontList.
-  void DrawFadeTruncatingString(
+  void DrawFadeTruncatingStringRectWithFlags(
       const base::string16& text,
       TruncateFadeMode truncate_mode,
-      size_t desired_characters_to_truncate_from_head,
-      const Font& font,
+      const FontList& font_list,
       SkColor color,
-      const Rect& display_rect);
+      const Rect& display_rect,
+      int flags);
 
   skia::PlatformCanvas* platform_canvas() const { return owned_canvas_.get(); }
   SkCanvas* sk_canvas() const { return canvas_; }
diff --git a/ui/gfx/canvas_paint_gtk.cc b/ui/gfx/canvas_paint_gtk.cc
index 3faa064..aef6fc9 100644
--- a/ui/gfx/canvas_paint_gtk.cc
+++ b/ui/gfx/canvas_paint_gtk.cc
@@ -10,6 +10,8 @@
 
 namespace gfx {
 
+// CanvasSkiaPaint
+
 CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event)
     : context_(NULL),
       window_(event->window),
@@ -52,8 +54,7 @@
 
 void CanvasSkiaPaint::Init(bool opaque) {
   GdkRectangle bounds = rectangle();
-  RecreateBackingCanvas(gfx::Size(bounds.width, bounds.height),
-                        1.0f, opaque);
+  RecreateBackingCanvas(Size(bounds.width, bounds.height), 1.0f, opaque);
 
   skia::PlatformCanvas* canvas = platform_canvas();
 
@@ -64,6 +65,43 @@
   context_ = skia::BeginPlatformPaint(canvas);
 }
 
+// CanvasSkiaPaintCairo
+
+CanvasSkiaPaintCairo::CanvasSkiaPaintCairo(cairo_t* cairo,
+                                           Size size,
+                                           bool opaque)
+    : context_(NULL),
+      dest_(cairo),
+      size_(size),
+      composite_alpha_(false) {
+  CHECK(dest_);
+  Init(opaque);
+}
+
+CanvasSkiaPaintCairo::~CanvasSkiaPaintCairo() {
+  if (!is_empty()) {
+    platform_canvas()->restoreToCount(1);
+
+    // Blit the dirty rect to the window.
+    if (composite_alpha_)
+      cairo_set_operator(dest_, CAIRO_OPERATOR_SOURCE);
+    cairo_surface_t* source_surface = cairo_get_target(context_);
+    CHECK(source_surface);
+    // Flush cairo's cache of the surface.
+    cairo_surface_mark_dirty(source_surface);
+    cairo_set_source_surface(dest_, source_surface, 0, 0);
+    GdkRectangle bounds = {0, 0, size_.width(), size_.height()};
+    gdk_cairo_rectangle(dest_, &bounds);
+    cairo_fill(dest_);
+  }
+}
+
+void CanvasSkiaPaintCairo::Init(bool opaque) {
+  RecreateBackingCanvas(size_, 1.0f, opaque);
+
+  context_ = skia::BeginPlatformPaint(platform_canvas());
+}
+
 } // namespace gfx
 
 
diff --git a/ui/gfx/canvas_paint_gtk.h b/ui/gfx/canvas_paint_gtk.h
index 649407a..487db79 100644
--- a/ui/gfx/canvas_paint_gtk.h
+++ b/ui/gfx/canvas_paint_gtk.h
@@ -57,6 +57,46 @@
   CanvasSkiaPaint& operator=(const CanvasSkiaPaint&);
 };
 
+// A class designed to translate skia painting into a region in a Cairo context.
+// On construction, it will set up a context for painting into, and on
+// destruction, it will commit it to the Cairo context. If there are any
+// transformations applied to the Cairo context, they will affect the drawing.
+class GFX_EXPORT CanvasSkiaPaintCairo : public Canvas {
+ public:
+  CanvasSkiaPaintCairo(cairo_t* cairo, Size size, bool opaque);
+  virtual ~CanvasSkiaPaintCairo();
+
+  // Sets whether the bitmap is composited in such a way that the alpha channel
+  // is honored. This is only useful if you've enabled an RGBA colormap on the
+  // widget. The default is false.
+  void set_composite_alpha(bool composite_alpha) {
+    composite_alpha_ = composite_alpha;
+  }
+
+  // Returns true if size of the drawing region is empty. The caller should call
+  // this function to determine if anything needs painting.
+  bool is_empty() const {
+    return size_.IsEmpty();
+  }
+
+  Size size() const {
+    return size_;
+  }
+
+ private:
+  void Init(bool opaque);
+
+  cairo_t* context_;
+  cairo_t* dest_;
+  Size size_;
+  // See description above setter.
+  bool composite_alpha_;
+
+  // Disallow copy and assign.
+  CanvasSkiaPaintCairo(const CanvasSkiaPaintCairo&);
+  CanvasSkiaPaintCairo& operator=(const CanvasSkiaPaintCairo&);
+};
+
 }  // namespace gfx
 
 #endif  // UI_GFX_CANVAS_PAINT_LINUX_H_
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index c259232..c919fe1 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -334,7 +334,7 @@
   // Create a temporary buffer filled with the halo color. It must leave room
   // for the 1-pixel border around the text.
   Size size(display_rect.width() + 2, display_rect.height() + 2);
-  Canvas text_canvas(size, image_scale(), true);
+  Canvas text_canvas(size, image_scale(), false);
   SkPaint bkgnd_paint;
   bkgnd_paint.setColor(halo_color);
   text_canvas.DrawRect(Rect(size), bkgnd_paint);
@@ -372,12 +372,20 @@
 void Canvas::DrawFadeTruncatingStringRect(
     const base::string16& text,
     TruncateFadeMode truncate_mode,
-    size_t desired_characters_to_truncate_from_head,
     const FontList& font_list,
     SkColor color,
     const Rect& display_rect) {
-  int flags = NO_ELLIPSIS;
+  DrawFadeTruncatingStringRectWithFlags(
+      text, truncate_mode, font_list, color, display_rect, NO_ELLIPSIS);
+}
 
+void Canvas::DrawFadeTruncatingStringRectWithFlags(
+    const base::string16& text,
+    TruncateFadeMode truncate_mode,
+    const FontList& font_list,
+    SkColor color,
+    const Rect& display_rect,
+    int flags) {
   // If the whole string fits in the destination then just draw it directly.
   if (GetStringWidth(text, font_list) <= display_rect.width()) {
     DrawStringRectWithFlags(text, font_list, color, display_rect, flags);
@@ -385,8 +393,8 @@
   }
 
   scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
-  base::string16 clipped_text = text;
-  const bool is_rtl = AdjustStringDirection(flags, &clipped_text);
+  const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
+                      base::i18n::RIGHT_TO_LEFT;
 
   switch (truncate_mode) {
     case TruncateFadeTail:
@@ -399,26 +407,6 @@
       if (!is_rtl)
         flags |= TEXT_ALIGN_RIGHT;
       break;
-    case TruncateFadeHeadAndTail:
-      DCHECK_GT(desired_characters_to_truncate_from_head, 0u);
-      // Due to the fade effect the first character is hard to see.
-      // We want to make sure that the first character starting at
-      // |desired_characters_to_truncate_from_head| is readable so we reduce
-      // the offset by a little bit.
-      desired_characters_to_truncate_from_head =
-          std::max<int>(0, desired_characters_to_truncate_from_head - 2);
-
-      if (desired_characters_to_truncate_from_head) {
-        // Make sure to clip the text at a UTF16 boundary.
-        U16_SET_CP_LIMIT(text.data(), 0,
-                         desired_characters_to_truncate_from_head,
-                         text.length());
-        clipped_text = text.substr(desired_characters_to_truncate_from_head);
-      }
-
-      render_text->set_fade_tail(true);
-      render_text->set_fade_head(true);
-      break;
   }
 
   // Default to left alignment unless right alignment was chosen above.
@@ -426,8 +414,7 @@
     flags |= TEXT_ALIGN_LEFT;
 
   Rect rect = display_rect;
-  UpdateRenderText(rect, clipped_text, font_list, flags, color,
-                   render_text.get());
+  UpdateRenderText(rect, text, font_list, flags, color, render_text.get());
 
   const int line_height = render_text->GetStringSize().height();
   // Center the text vertically.
@@ -441,16 +428,4 @@
   canvas_->restore();
 }
 
-void Canvas::DrawFadeTruncatingString(
-    const base::string16& text,
-    TruncateFadeMode truncate_mode,
-    size_t desired_characters_to_truncate_from_head,
-    const Font& font,
-    SkColor color,
-    const Rect& display_rect) {
-  DrawFadeTruncatingStringRect(text, truncate_mode,
-                               desired_characters_to_truncate_from_head,
-                               FontList(font), color, display_rect);
-}
-
 }  // namespace gfx
diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
index d0b348f..b3f4345 100644
--- a/ui/gfx/codec/png_codec.cc
+++ b/ui/gfx/codec/png_codec.cc
@@ -465,7 +465,8 @@
   }
 
   // Set the bitmap's opaqueness based on what we saw.
-  bitmap->setIsOpaque(state.is_opaque);
+  bitmap->setAlphaType(state.is_opaque ?
+                       kOpaque_SkAlphaType : kPremul_SkAlphaType);
 
   return true;
 }
diff --git a/ui/gfx/display.cc b/ui/gfx/display.cc
index ee650d8..024b1f9 100644
--- a/ui/gfx/display.cc
+++ b/ui/gfx/display.cc
@@ -57,13 +57,15 @@
 Display::Display()
     : id_(kInvalidDisplayID),
       device_scale_factor_(GetForcedDeviceScaleFactor()),
-      rotation_(ROTATE_0) {
+      rotation_(ROTATE_0),
+      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
 }
 
 Display::Display(int64 id)
     : id_(id),
       device_scale_factor_(GetForcedDeviceScaleFactor()),
-      rotation_(ROTATE_0) {
+      rotation_(ROTATE_0),
+      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
 }
 
 Display::Display(int64 id, const gfx::Rect& bounds)
@@ -71,7 +73,8 @@
       bounds_(bounds),
       work_area_(bounds),
       device_scale_factor_(GetForcedDeviceScaleFactor()),
-      rotation_(ROTATE_0) {
+      rotation_(ROTATE_0),
+      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
 #if defined(USE_AURA)
   SetScaleAndBounds(device_scale_factor_, bounds);
 #endif
diff --git a/ui/gfx/display.h b/ui/gfx/display.h
index 324b961..eb35a5f 100644
--- a/ui/gfx/display.h
+++ b/ui/gfx/display.h
@@ -30,6 +30,13 @@
     ROTATE_270,
   };
 
+  // Touch support for the display.
+  enum TouchSupport {
+    TOUCH_SUPPORT_UNKNOWN,
+    TOUCH_SUPPORT_AVAILABLE,
+    TOUCH_SUPPORT_UNAVAILABLE,
+  };
+
   // Creates a display with kInvalidDisplayID as default.
   Display();
   explicit Display(int64 id);
@@ -67,6 +74,9 @@
   Rotation rotation() const { return rotation_; }
   void set_rotation(Rotation rotation) { rotation_ = rotation; }
 
+  TouchSupport touch_support() const { return touch_support_; }
+  void set_touch_support(TouchSupport support) { touch_support_ = support; }
+
   // Utility functions that just return the size of display and
   // work area.
   const Size& size() const { return bounds_.size(); }
@@ -113,6 +123,7 @@
   Rect work_area_;
   float device_scale_factor_;
   Rotation rotation_;
+  TouchSupport touch_support_;
 };
 
 }  // namespace gfx
diff --git a/ui/gfx/frame_time.h b/ui/gfx/frame_time.h
new file mode 100644
index 0000000..8d143ee
--- /dev/null
+++ b/ui/gfx/frame_time.h
@@ -0,0 +1,37 @@
+// Copyright 2013 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_GFX_FRAME_TIME_H
+#define UI_GFX_FRAME_TIME_H
+
+#include "base/time/time.h"
+#include "base/logging.h"
+
+namespace gfx {
+
+// FrameTime::Now() should be used to get timestamps with a timebase that
+// is consistent across the graphics stack.
+class FrameTime {
+ public:
+  static base::TimeTicks Now() {
+    if (TimestampsAreHighRes())
+      return base::TimeTicks::HighResNow();
+    return base::TimeTicks::Now();
+  }
+
+#if defined(OS_WIN)
+  static base::TimeTicks FromQPCValue(LONGLONG qpc_value) {
+    DCHECK(TimestampsAreHighRes());
+    return base::TimeTicks::FromQPCValue(qpc_value);
+  }
+#endif
+
+  static bool TimestampsAreHighRes() {
+    return base::TimeTicks::IsHighResNowFastAndReliable();
+  }
+};
+
+}
+
+#endif // UI_GFX_FRAME_TIME_H
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index 09a4a53..7ab68a1 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -33,6 +33,8 @@
         'android/gfx_jni_registrar.h',
         'android/java_bitmap.cc',
         'android/java_bitmap.h',
+        'android/shared_device_display_info.cc',
+        'android/shared_device_display_info.h',
         'animation/animation.cc',
         'animation/animation.h',
         'animation/animation_container.cc',
@@ -84,6 +86,7 @@
         'display_observer.h',
         'favicon_size.cc',
         'favicon_size.h',
+        'frame_time.h',
         'font.cc',
         'font.h',
         'font_fallback_win.cc',
@@ -139,6 +142,8 @@
         'ozone/impl/drm_skbitmap_ozone.h',
         'ozone/impl/drm_wrapper_ozone.cc',
         'ozone/impl/drm_wrapper_ozone.h',
+        'ozone/impl/file_surface_factory_ozone.cc',
+        'ozone/impl/file_surface_factory_ozone.h',
         'ozone/impl/hardware_display_controller_ozone.cc',
         'ozone/impl/hardware_display_controller_ozone.h',
         'ozone/impl/software_surface_factory_ozone.cc',
@@ -332,12 +337,6 @@
           # C4324 is structure was padded due to __declspec(align()), which is
           # uninteresting.
           'msvs_disabled_warnings': [ 4267, 4324 ],
-
-          'msvs_settings': {
-            'VCCLCompilerTool': {
-              'ForcedIncludeFiles': [ 'build/intsafe_workaround.h' ],
-            },
-          },
         }],
         ['OS=="android"', {
           'sources!': [
diff --git a/ui/gfx/gfx.target.darwin-arm.mk b/ui/gfx/gfx.target.darwin-arm.mk
index c4986e8..470a885 100644
--- a/ui/gfx/gfx.target.darwin-arm.mk
+++ b/ui/gfx/gfx.target.darwin-arm.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -137,13 +138,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -250,13 +251,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx.target.darwin-mips.mk b/ui/gfx/gfx.target.darwin-mips.mk
index 35d884d..fc6050a 100644
--- a/ui/gfx/gfx.target.darwin-mips.mk
+++ b/ui/gfx/gfx.target.darwin-mips.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -136,13 +137,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -248,13 +249,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx.target.darwin-x86.mk b/ui/gfx/gfx.target.darwin-x86.mk
index 9a45ea7..d1f7463 100644
--- a/ui/gfx/gfx.target.darwin-x86.mk
+++ b/ui/gfx/gfx.target.darwin-x86.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -139,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -254,13 +255,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx.target.linux-arm.mk b/ui/gfx/gfx.target.linux-arm.mk
index c4986e8..470a885 100644
--- a/ui/gfx/gfx.target.linux-arm.mk
+++ b/ui/gfx/gfx.target.linux-arm.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -137,13 +138,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -250,13 +251,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx.target.linux-mips.mk b/ui/gfx/gfx.target.linux-mips.mk
index 35d884d..fc6050a 100644
--- a/ui/gfx/gfx.target.linux-mips.mk
+++ b/ui/gfx/gfx.target.linux-mips.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -136,13 +137,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -248,13 +249,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx.target.linux-x86.mk b/ui/gfx/gfx.target.linux-x86.mk
index 9a45ea7..d1f7463 100644
--- a/ui/gfx/gfx.target.linux-x86.mk
+++ b/ui/gfx/gfx.target.linux-x86.mk
@@ -32,6 +32,7 @@
 	ui/gfx/android/device_display_info.cc \
 	ui/gfx/android/gfx_jni_registrar.cc \
 	ui/gfx/android/java_bitmap.cc \
+	ui/gfx/android/shared_device_display_info.cc \
 	ui/gfx/animation/animation.cc \
 	ui/gfx/animation/animation_container.cc \
 	ui/gfx/animation/linear_animation.cc \
@@ -139,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -254,13 +255,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.darwin-arm.mk b/ui/gfx/gfx_jni_headers.target.darwin-arm.mk
index 8c76204..2519354 100644
--- a/ui/gfx/gfx_jni_headers.target.darwin-arm.mk
+++ b/ui/gfx/gfx_jni_headers.target.darwin-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.darwin-mips.mk b/ui/gfx/gfx_jni_headers.target.darwin-mips.mk
index 4c87b8e..f1774e7 100644
--- a/ui/gfx/gfx_jni_headers.target.darwin-mips.mk
+++ b/ui/gfx/gfx_jni_headers.target.darwin-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.darwin-x86.mk b/ui/gfx/gfx_jni_headers.target.darwin-x86.mk
index 430c4da..002ba8b 100644
--- a/ui/gfx/gfx_jni_headers.target.darwin-x86.mk
+++ b/ui/gfx/gfx_jni_headers.target.darwin-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.linux-arm.mk b/ui/gfx/gfx_jni_headers.target.linux-arm.mk
index 8c76204..2519354 100644
--- a/ui/gfx/gfx_jni_headers.target.linux-arm.mk
+++ b/ui/gfx/gfx_jni_headers.target.linux-arm.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.linux-mips.mk b/ui/gfx/gfx_jni_headers.target.linux-mips.mk
index 4c87b8e..f1774e7 100644
--- a/ui/gfx/gfx_jni_headers.target.linux-mips.mk
+++ b/ui/gfx/gfx_jni_headers.target.linux-mips.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/gfx_jni_headers.target.linux-x86.mk b/ui/gfx/gfx_jni_headers.target.linux-x86.mk
index 430c4da..002ba8b 100644
--- a/ui/gfx/gfx_jni_headers.target.linux-x86.mk
+++ b/ui/gfx/gfx_jni_headers.target.linux-x86.mk
@@ -94,13 +94,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gfx/image/image_unittest.cc b/ui/gfx/image/image_unittest.cc
index 3595828..22f343f 100644
--- a/ui/gfx/image/image_unittest.cc
+++ b/ui/gfx/image/image_unittest.cc
@@ -537,9 +537,9 @@
   const int width = 50;
   const int height = 50;
   SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
+                   kPremul_SkAlphaType);
   bitmap.allocPixels();
-  bitmap.setIsOpaque(false);
   bitmap.eraseARGB(0, 0, 255, 0);
 
   // Paint the upper half of the image in red (lower half is transparent).
diff --git a/ui/gfx/ozone/impl/drm_wrapper_ozone.cc b/ui/gfx/ozone/impl/drm_wrapper_ozone.cc
index 8536786..6697bc0 100644
--- a/ui/gfx/ozone/impl/drm_wrapper_ozone.cc
+++ b/ui/gfx/ozone/impl/drm_wrapper_ozone.cc
@@ -83,4 +83,11 @@
                           data);
 }
 
+bool DrmWrapperOzone::ConnectorSetProperty(uint32_t connector_id,
+                                           uint32_t property_id,
+                                           uint64_t value) {
+  CHECK(fd_ >= 0);
+  return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/ozone/impl/drm_wrapper_ozone.h b/ui/gfx/ozone/impl/drm_wrapper_ozone.h
index dbd12bc..6ff7945 100644
--- a/ui/gfx/ozone/impl/drm_wrapper_ozone.h
+++ b/ui/gfx/ozone/impl/drm_wrapper_ozone.h
@@ -63,6 +63,12 @@
   // will receive when processing the pageflip event.
   virtual bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, void* data);
 
+  // Sets the value of property with ID |property_id| to |value|. The property
+  // is applied to the connector with ID |connector_id|.
+  virtual bool ConnectorSetProperty(uint32_t connector_id,
+                                    uint32_t property_id,
+                                    uint64_t value);
+
   int get_fd() const { return fd_; }
 
  protected:
diff --git a/ui/gfx/ozone/impl/file_surface_factory_ozone.cc b/ui/gfx/ozone/impl/file_surface_factory_ozone.cc
new file mode 100644
index 0000000..0064af3
--- /dev/null
+++ b/ui/gfx/ozone/impl/file_surface_factory_ozone.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/ozone/impl/file_surface_factory_ozone.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/location.h"
+#include "base/stl_util.h"
+#include "base/threading/worker_pool.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+void WriteDataToFile(const base::FilePath& location,
+                     const SkBitmap& bitmap) {
+  std::vector<unsigned char> png_data;
+  gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, true, &png_data);
+  file_util::WriteFile(location,
+                       (char*)vector_as_array(&png_data),
+                       png_data.size());
+}
+
+}
+
+namespace gfx {
+
+FileSurfaceFactoryOzone::FileSurfaceFactoryOzone(
+    const base::FilePath& dump_location)
+    : location_(dump_location) {
+  CHECK(!base::DirectoryExists(location_))
+      << "Location cannot be a directory (" << location_.value() << ")";
+  CHECK(!base::PathExists(location_) || base::PathIsWritable(location_));
+}
+
+FileSurfaceFactoryOzone::~FileSurfaceFactoryOzone() {}
+
+SurfaceFactoryOzone::HardwareState
+FileSurfaceFactoryOzone::InitializeHardware() {
+  return INITIALIZED;
+}
+
+void FileSurfaceFactoryOzone::ShutdownHardware() {
+}
+
+AcceleratedWidget FileSurfaceFactoryOzone::GetAcceleratedWidget() {
+  return 1;
+}
+
+AcceleratedWidget FileSurfaceFactoryOzone::RealizeAcceleratedWidget(
+    AcceleratedWidget widget) {
+  return 1;
+}
+
+bool FileSurfaceFactoryOzone::LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  return false;
+}
+
+bool FileSurfaceFactoryOzone::AttemptToResizeAcceleratedWidget(
+    AcceleratedWidget widget,
+    const Rect& bounds) {
+  device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
+                                              bounds.width(),
+                                              bounds.height()));
+  canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
+  return true;
+}
+
+bool FileSurfaceFactoryOzone::SchedulePageFlip(AcceleratedWidget widget) {
+  SkBitmap bitmap;
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+                   device_->width(),
+                   device_->height());
+
+  if (canvas_->readPixels(&bitmap, 0, 0)) {
+    base::WorkerPool::PostTask(FROM_HERE,
+        base::Bind(&WriteDataToFile, location_, bitmap),
+        true);
+  }
+  return true;
+}
+
+SkCanvas* FileSurfaceFactoryOzone::GetCanvasForWidget(AcceleratedWidget w) {
+  return canvas_.get();
+}
+
+VSyncProvider* FileSurfaceFactoryOzone::GetVSyncProvider(AcceleratedWidget w) {
+  return NULL;
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/ozone/impl/file_surface_factory_ozone.h b/ui/gfx/ozone/impl/file_surface_factory_ozone.h
new file mode 100644
index 0000000..6b1df26
--- /dev/null
+++ b/ui/gfx/ozone/impl/file_surface_factory_ozone.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2013 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_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_OZONE_H_
+#define UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_OZONE_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/ozone/surface_factory_ozone.h"
+#include "ui/gfx/skia_util.h"
+
+class SkBitmapDevice;
+class SkCanvas;
+
+namespace gfx {
+
+class FileSurfaceFactoryOzone : public SurfaceFactoryOzone {
+ public:
+  explicit FileSurfaceFactoryOzone(const base::FilePath& dump_location);
+  virtual ~FileSurfaceFactoryOzone();
+
+ private:
+  // SurfaceFactoryOzone:
+  virtual HardwareState InitializeHardware() OVERRIDE;
+  virtual void ShutdownHardware() OVERRIDE;
+  virtual AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+  virtual AcceleratedWidget RealizeAcceleratedWidget(
+      AcceleratedWidget widget) OVERRIDE;
+  virtual bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+  virtual bool AttemptToResizeAcceleratedWidget(AcceleratedWidget widget,
+                                                const Rect& bounds) OVERRIDE;
+  virtual bool SchedulePageFlip(AcceleratedWidget widget) OVERRIDE;
+  virtual SkCanvas* GetCanvasForWidget(AcceleratedWidget widget) OVERRIDE;
+  virtual VSyncProvider* GetVSyncProvider(AcceleratedWidget widget) OVERRIDE;
+
+  base::FilePath location_;
+  skia::RefPtr<SkBitmapDevice> device_;
+  skia::RefPtr<SkCanvas> canvas_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileSurfaceFactoryOzone);
+};
+
+}  // namespace gfx
+
+#endif  // UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_OZONE_H_
diff --git a/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc b/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc
index 3f0a2ca..2885904 100644
--- a/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc
+++ b/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc
@@ -29,10 +29,12 @@
     DrmWrapperOzone* drm,
     uint32_t connector_id,
     uint32_t crtc_id,
+    uint32_t dpms_property_id,
     drmModeModeInfo mode) {
   drm_ = drm;
   connector_id_ = connector_id;
   crtc_id_ = crtc_id;
+  dpms_property_id_ = dpms_property_id;
   mode_ = mode;
   saved_crtc_ = drm_->GetCrtc(crtc_id_);
   state_ = UNINITIALIZED;
@@ -95,6 +97,11 @@
     } else {
       state_ = INITIALIZED;
     }
+
+    if (dpms_property_id_)
+      drm_->ConnectorSetProperty(connector_id_,
+                                 dpms_property_id_,
+                                 DRM_MODE_DPMS_ON);
   }
 
   if (!drm_->PageFlip(crtc_id_,
@@ -104,6 +111,7 @@
     LOG(ERROR) << "Cannot page flip: " << strerror(errno);
     return false;
   }
+
   return true;
 }
 
diff --git a/ui/gfx/ozone/impl/hardware_display_controller_ozone.h b/ui/gfx/ozone/impl/hardware_display_controller_ozone.h
index 470bd4a..354ad70 100644
--- a/ui/gfx/ozone/impl/hardware_display_controller_ozone.h
+++ b/ui/gfx/ozone/impl/hardware_display_controller_ozone.h
@@ -110,6 +110,7 @@
   void SetControllerInfo(DrmWrapperOzone* drm,
                          uint32_t connector_id,
                          uint32_t crtc_id,
+                         uint32_t dpms_property_id,
                          drmModeModeInfo mode);
 
   // Associate the HDCO with a surface implementation and initialize it.
@@ -151,6 +152,8 @@
 
   uint32_t crtc_id_;
 
+  uint32_t dpms_property_id_;
+
   // TODO(dnicoara) Need to store all the modes.
   drmModeModeInfo mode_;
 
diff --git a/ui/gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc b/ui/gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc
index c5d54bd..7d667ce 100644
--- a/ui/gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc
+++ b/ui/gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc
@@ -23,30 +23,32 @@
 // Mock CRTC ID.
 const uint32_t kCrtcId = 1;
 
+const uint32_t kDPMSPropertyId = 1;
+
 // The real DrmWrapper makes actual DRM calls which we can't use in unit tests.
 class MockDrmWrapperOzone : public gfx::DrmWrapperOzone {
  public:
   MockDrmWrapperOzone(int fd) : DrmWrapperOzone(""),
-                                get_crtc_call_count(0),
-                                free_crtc_call_count(0),
-                                restore_crtc_call_count(0),
-                                add_framebuffer_call_count(0),
-                                remove_framebuffer_call_count(0),
-                                set_crtc_expectation(true),
-                                add_framebuffer_expectation(true),
-                                page_flip_expectation(true) {
+                                get_crtc_call_count_(0),
+                                free_crtc_call_count_(0),
+                                restore_crtc_call_count_(0),
+                                add_framebuffer_call_count_(0),
+                                remove_framebuffer_call_count_(0),
+                                set_crtc_expectation_(true),
+                                add_framebuffer_expectation_(true),
+                                page_flip_expectation_(true) {
     fd_ = fd;
   }
 
   virtual ~MockDrmWrapperOzone() { fd_ = -1; }
 
   virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
-    get_crtc_call_count++;
+    get_crtc_call_count_++;
     return new drmModeCrtc;
   }
 
   virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
-    free_crtc_call_count++;
+    free_crtc_call_count_++;
     delete crtc;
   }
 
@@ -54,11 +56,11 @@
                        uint32_t framebuffer,
                        uint32_t* connectors,
                        drmModeModeInfo* mode) OVERRIDE {
-    return set_crtc_expectation;
+    return set_crtc_expectation_;
   }
 
   virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
-    restore_crtc_call_count++;
+    restore_crtc_call_count_++;
     return true;
   }
 
@@ -68,63 +70,67 @@
                               uint32_t stride,
                               uint32_t handle,
                               uint32_t* framebuffer) OVERRIDE {
-    add_framebuffer_call_count++;
-    return add_framebuffer_expectation;
+    add_framebuffer_call_count_++;
+    return add_framebuffer_expectation_;
   }
 
   virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE {
-    remove_framebuffer_call_count++;
+    remove_framebuffer_call_count_++;
     return true;
   }
 
   virtual bool PageFlip(uint32_t crtc_id,
                         uint32_t framebuffer,
                         void* data) OVERRIDE {
-    return page_flip_expectation;
+    return page_flip_expectation_;
   }
 
+  virtual bool ConnectorSetProperty(uint32_t connector_id,
+                                    uint32_t property_id,
+                                    uint64_t value) OVERRIDE { return true; }
+
   int get_get_crtc_call_count() const {
-    return get_crtc_call_count;
+    return get_crtc_call_count_;
   }
 
   int get_free_crtc_call_count() const {
-    return free_crtc_call_count;
+    return free_crtc_call_count_;
   }
 
   int get_restore_crtc_call_count() const {
-    return restore_crtc_call_count;
+    return restore_crtc_call_count_;
   }
 
   int get_add_framebuffer_call_count() const {
-    return add_framebuffer_call_count;
+    return add_framebuffer_call_count_;
   }
 
   int get_remove_framebuffer_call_count() const {
-    return remove_framebuffer_call_count;
+    return remove_framebuffer_call_count_;
   }
 
   void set_set_crtc_expectation(bool state) {
-    set_crtc_expectation = state;
+    set_crtc_expectation_ = state;
   }
 
   void set_add_framebuffer_expectation(bool state) {
-    add_framebuffer_expectation = state;
+    add_framebuffer_expectation_ = state;
   }
 
   void set_page_flip_expectation(bool state) {
-    page_flip_expectation = state;
+    page_flip_expectation_ = state;
   }
 
  private:
-  int get_crtc_call_count;
-  int free_crtc_call_count;
-  int restore_crtc_call_count;
-  int add_framebuffer_call_count;
-  int remove_framebuffer_call_count;
+  int get_crtc_call_count_;
+  int free_crtc_call_count_;
+  int restore_crtc_call_count_;
+  int add_framebuffer_call_count_;
+  int remove_framebuffer_call_count_;
 
-  bool set_crtc_expectation;
-  bool add_framebuffer_expectation;
-  bool page_flip_expectation;
+  bool set_crtc_expectation_;
+  bool add_framebuffer_expectation_;
+  bool page_flip_expectation_;
 
   DISALLOW_COPY_AND_ASSIGN(MockDrmWrapperOzone);
 };
@@ -189,7 +195,7 @@
 TEST_F(HardwareDisplayControllerOzoneTest,
        CheckStateAfterControllerIsInitialized) {
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
 
   EXPECT_EQ(1, drm_->get_get_crtc_call_count());
   EXPECT_EQ(gfx::HardwareDisplayControllerOzone::UNINITIALIZED,
@@ -198,7 +204,7 @@
 
 TEST_F(HardwareDisplayControllerOzoneTest, CheckStateAfterSurfaceIsBound) {
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
@@ -214,7 +220,7 @@
   drm_->set_add_framebuffer_expectation(false);
 
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
@@ -228,7 +234,7 @@
 
 TEST_F(HardwareDisplayControllerOzoneTest, CheckStateAfterPageFlip) {
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
@@ -245,7 +251,7 @@
   drm_->set_set_crtc_expectation(false);
 
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
@@ -262,7 +268,7 @@
   drm_->set_page_flip_expectation(false);
 
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
@@ -277,7 +283,7 @@
 
 TEST_F(HardwareDisplayControllerOzoneTest, CheckProperDestruction) {
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
   scoped_ptr<gfx::SoftwareSurfaceOzone> surface(
       new MockSoftwareSurfaceOzone(controller_.get()));
 
diff --git a/ui/gfx/ozone/impl/software_surface_factory_ozone.cc b/ui/gfx/ozone/impl/software_surface_factory_ozone.cc
index 23be6c2..c5515e9 100644
--- a/ui/gfx/ozone/impl/software_surface_factory_ozone.cc
+++ b/ui/gfx/ozone/impl/software_surface_factory_ozone.cc
@@ -22,6 +22,7 @@
 namespace {
 
 const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
+const char kDPMSProperty[] = "DPMS";
 
 const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
 
@@ -44,6 +45,23 @@
       ->SwapBuffers();
 }
 
+uint32_t GetDrmProperty(int fd, drmModeConnector* connector, const char* name) {
+  for (int i = 0; i < connector->count_props; ++i) {
+    drmModePropertyPtr property = drmModeGetProperty(fd, connector->props[i]);
+    if (!property)
+      continue;
+
+    if (strcmp(property->name, name) == 0) {
+      uint32_t id = property->prop_id;
+      drmModeFreeProperty(property);
+      return id;
+    }
+
+    drmModeFreeProperty(property);
+  }
+  return 0;
+}
+
 uint32_t GetCrtc(int fd, drmModeRes* resources, drmModeConnector* connector) {
   // If the connector already has an encoder try to re-use.
   if (connector->encoder_id) {
@@ -165,11 +183,12 @@
     return gfx::kNullAcceleratedWidget;
   }
 
-  return reinterpret_cast<gfx::AcceleratedWidget>(
-      controller_->get_surface()->GetDrawableForWidget());
+  return reinterpret_cast<gfx::AcceleratedWidget>(controller_->get_surface());
 }
 
-bool SoftwareSurfaceFactoryOzone::LoadEGLGLES2Bindings() {
+bool SoftwareSurfaceFactoryOzone::LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
   return false;
 }
 
@@ -211,6 +230,12 @@
   return true;
 }
 
+SkCanvas* SoftwareSurfaceFactoryOzone::GetCanvasForWidget(
+    gfx::AcceleratedWidget w) {
+  CHECK(state_ == INITIALIZED);
+  return reinterpret_cast<SoftwareSurfaceOzone*>(w)->GetDrawableForWidget();
+}
+
 gfx::VSyncProvider* SoftwareSurfaceFactoryOzone::GetVSyncProvider(
     gfx::AcceleratedWidget w) {
   return NULL;
@@ -255,6 +280,10 @@
     if (!crtc)
       continue;
 
+    uint32_t dpms_property_id = GetDrmProperty(drm->get_fd(),
+                                               connector,
+                                               kDPMSProperty);
+
     // TODO(dnicoara) Select one mode for now. In the future we may need to
     // save all the modes and allow the user to choose a specific mode. Or
     // even some fullscreen applications may need to change the mode.
@@ -262,6 +291,7 @@
         drm,
         connector->connector_id,
         crtc,
+        dpms_property_id,
         connector->modes[0]);
 
     drmModeFreeConnector(connector);
diff --git a/ui/gfx/ozone/impl/software_surface_factory_ozone.h b/ui/gfx/ozone/impl/software_surface_factory_ozone.h
index dbe9e8e..d6fa1e9 100644
--- a/ui/gfx/ozone/impl/software_surface_factory_ozone.h
+++ b/ui/gfx/ozone/impl/software_surface_factory_ozone.h
@@ -29,7 +29,9 @@
   virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
       gfx::AcceleratedWidget w) OVERRIDE;
 
-  virtual bool LoadEGLGLES2Bindings() OVERRIDE;
+  virtual bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
 
   virtual bool AttemptToResizeAcceleratedWidget(
       gfx::AcceleratedWidget w,
@@ -37,6 +39,8 @@
 
   virtual bool SchedulePageFlip(gfx::AcceleratedWidget w) OVERRIDE;
 
+  virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w) OVERRIDE;
+
   virtual gfx::VSyncProvider* GetVSyncProvider(
       gfx::AcceleratedWidget w) OVERRIDE;
 
diff --git a/ui/gfx/ozone/impl/software_surface_factory_ozone_unittest.cc b/ui/gfx/ozone/impl/software_surface_factory_ozone_unittest.cc
index 9daa0e8..add69c7 100644
--- a/ui/gfx/ozone/impl/software_surface_factory_ozone_unittest.cc
+++ b/ui/gfx/ozone/impl/software_surface_factory_ozone_unittest.cc
@@ -26,6 +26,8 @@
 // Mock CRTC ID.
 const uint32_t kCrtcId = 1;
 
+const uint32_t kDPMSPropertyId = 1;
+
 const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
 
 // The real DrmWrapper makes actual DRM calls which we can't use in unit tests.
@@ -77,6 +79,10 @@
     return page_flip_expectation_;
   }
 
+  virtual bool ConnectorSetProperty(uint32_t connector_id,
+                                    uint32_t property_id,
+                                    uint64_t value) OVERRIDE { return true; }
+
   void set_add_framebuffer_expectation(bool state) {
     add_framebuffer_expectation_ = state;
   }
@@ -171,6 +177,7 @@
       controller->SetControllerInfo(drm,
                                     kConnectorId,
                                     kCrtcId,
+                                    kDPMSPropertyId,
                                     kDefaultMode);
       return true;
     } else {
diff --git a/ui/gfx/ozone/impl/software_surface_ozone.cc b/ui/gfx/ozone/impl/software_surface_ozone.cc
index bb06d1e..54d8f95 100644
--- a/ui/gfx/ozone/impl/software_surface_ozone.cc
+++ b/ui/gfx/ozone/impl/software_surface_ozone.cc
@@ -65,7 +65,7 @@
   }
 
   skia_device_ = skia::AdoptRef(
-      new SkBitmapDevice(*bitmaps_[front_buffer_ ^ 1].get()));
+      new CustomSkBitmapDevice(*bitmaps_[front_buffer_ ^ 1].get()));
   skia_canvas_ = skia::AdoptRef(new SkCanvas(skia_device_.get()));
 
   return true;
diff --git a/ui/gfx/ozone/impl/software_surface_ozone_unittest.cc b/ui/gfx/ozone/impl/software_surface_ozone_unittest.cc
index 8f709cd..1eb73d4 100644
--- a/ui/gfx/ozone/impl/software_surface_ozone_unittest.cc
+++ b/ui/gfx/ozone/impl/software_surface_ozone_unittest.cc
@@ -25,6 +25,9 @@
 // Mock CRTC ID.
 const uint32_t kCrtcId = 1;
 
+// Mock DPMS property ID.
+const uint32_t kDPMSPropertyId = 1;
+
 class MockDrmWrapperOzone : public gfx::DrmWrapperOzone {
  public:
   MockDrmWrapperOzone() : DrmWrapperOzone(""), id_(1) { fd_ = kFd; }
@@ -54,6 +57,9 @@
                         void* data) OVERRIDE {
     return true;
   }
+  virtual bool ConnectorSetProperty(uint32_t connector_id,
+                                    uint32_t property_id,
+                                    uint64_t value) OVERRIDE { return true; }
 
  private:
   int id_;
@@ -127,7 +133,7 @@
   drm_.reset(new MockDrmWrapperOzone());
   controller_.reset(new gfx::HardwareDisplayControllerOzone());
   controller_->SetControllerInfo(
-      drm_.get(), kConnectorId, kCrtcId, kDefaultMode);
+      drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
 
   surface_.reset(new MockSoftwareSurfaceOzone(controller_.get()));
 }
diff --git a/ui/gfx/ozone/surface_factory_ozone.cc b/ui/gfx/ozone/surface_factory_ozone.cc
index 8c7cbb9..5ba8de0 100644
--- a/ui/gfx/ozone/surface_factory_ozone.cc
+++ b/ui/gfx/ozone/surface_factory_ozone.cc
@@ -6,6 +6,8 @@
 
 #include <stdlib.h>
 
+#include "base/command_line.h"
+#include "ui/gfx/ozone/impl/file_surface_factory_ozone.h"
 #include "ui/gfx/ozone/impl/software_surface_factory_ozone.h"
 
 namespace gfx {
@@ -25,7 +27,11 @@
       gfx::AcceleratedWidget w) OVERRIDE {
     return 0;
   }
-  virtual bool LoadEGLGLES2Bindings() OVERRIDE { return true; }
+  virtual bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE {
+    return true;
+  }
   virtual bool AttemptToResizeAcceleratedWidget(
       gfx::AcceleratedWidget w,
       const gfx::Rect& bounds) OVERRIDE {
@@ -45,9 +51,18 @@
 
 SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() {
   if (!impl_) {
-    LOG(WARNING) << "No SurfaceFactoryOzone implementation set. Using default "
-                    "gfx::SoftwareSurfaceFactoryOzone.";
-    impl_ = new SoftwareSurfaceFactoryOzone();
+    const char kOzoneFileSurface[] = "ozone-dump-file";
+    CommandLine* cmd = CommandLine::ForCurrentProcess();
+    if (cmd->HasSwitch(kOzoneFileSurface)) {
+      base::FilePath location = cmd->GetSwitchValuePath(kOzoneFileSurface);
+      if (location.empty())
+        location = base::FilePath("/dev/null");
+      impl_ = new FileSurfaceFactoryOzone(location);
+    } else {
+      LOG(WARNING) << "No SurfaceFactoryOzone implementation set. Using default"
+                      " gfx::SoftwareSurfaceFactoryOzone.";
+      impl_ = new SoftwareSurfaceFactoryOzone();
+    }
   }
   return impl_;
 }
@@ -71,10 +86,14 @@
   return 0;
 }
 
-bool SurfaceFactoryOzone::SchedulePageFlip(gfx::AcceleratedWidget) {
+bool SurfaceFactoryOzone::SchedulePageFlip(gfx::AcceleratedWidget w) {
   return true;
 }
 
+SkCanvas* SurfaceFactoryOzone::GetCanvasForWidget(gfx::AcceleratedWidget w) {
+  return NULL;
+}
+
 const int32* SurfaceFactoryOzone::GetEGLSurfaceProperties(
     const int32* desired_attributes) {
   return desired_attributes;
diff --git a/ui/gfx/ozone/surface_factory_ozone.h b/ui/gfx/ozone/surface_factory_ozone.h
index a7f4cd4..c09a65f 100644
--- a/ui/gfx/ozone/surface_factory_ozone.h
+++ b/ui/gfx/ozone/surface_factory_ozone.h
@@ -5,14 +5,45 @@
 #ifndef UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
 #define UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
 
+#include "base/callback.h"
+#include "base/native_library.h"
 #include "ui/gfx/gfx_export.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/rect.h"
 
+class SkCanvas;
+
 namespace gfx {
 class Screen;
 class VSyncProvider;
 
+// The Ozone interface allows external implementations to hook into Chromium to
+// provide a system specific implementation. The Ozone interface supports two
+// drawing modes: 1) accelerated drawing through EGL and 2) software drawing
+// through Skia.
+//
+// The following functionality is specific to the drawing mode and may not have
+// any meaningful implementation in the other mode. An implementation must
+// provide functionality for at least one mode.
+//
+// 1) Accelerated Drawing (EGL path):
+//
+// The following functions are specific to EGL:
+//  - GetNativeDisplay
+//  - LoadEGLGLES2Bindings
+//  - GetEGLSurfaceProperties (optional if the properties match the default
+//  Chromium ones).
+//
+// 2) Software Drawing (Skia):
+//
+// The following function is specific to the software path:
+//  - GetCanvasForWidget
+//
+// The accelerated path can optionally provide support for the software drawing
+// path.
+//
+// The remaining functions are not covered since they are needed in both drawing
+// modes (See comments bellow for descriptions).
 class GFX_EXPORT SurfaceFactoryOzone {
  public:
   // Describes the state of the hardware after initialization.
@@ -22,6 +53,11 @@
     FAILED,
   };
 
+  typedef void*(*GLGetProcAddressProc)(const char* name);
+  typedef base::Callback<void(base::NativeLibrary)> AddGLLibraryCallback;
+  typedef base::Callback<void(GLGetProcAddressProc)>
+      SetGLGetProcAddressProcCallback;
+
   SurfaceFactoryOzone();
   virtual ~SurfaceFactoryOzone();
 
@@ -47,8 +83,8 @@
   // This method must be safe to run inside of the sandbox.
   virtual void ShutdownHardware() = 0;
 
-  // Returns the native EGL display. This is generally needed in creating
-  // EGL windows.
+  // Returns native platform display handle. This is used to obtain the EGL
+  // display connection for the native display.
   virtual intptr_t GetNativeDisplay();
 
   // Obtains an AcceleratedWidget backed by a native Linux framebuffer.
@@ -62,8 +98,11 @@
   virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
       gfx::AcceleratedWidget w) = 0;
 
-  // Sets up GL bindings for the native surface.
-  virtual bool LoadEGLGLES2Bindings() = 0;
+  // Sets up GL bindings for the native surface. Takes two callback parameters
+  // that allow Ozone to register the GL bindings.
+  virtual bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) = 0;
 
   // If possible attempts to resize the given AcceleratedWidget instance and if
   // a resize action was performed returns true, otherwise false (native
@@ -76,6 +115,12 @@
   // is needed to perform the actual buffer swap.
   virtual bool SchedulePageFlip(gfx::AcceleratedWidget w);
 
+  // Returns a SkCanvas for the backing buffers. Drawing to the canvas will draw
+  // to the native surface. The canvas is intended for use when no EGL
+  // acceleration is possible. Its implementation is optional when an EGL
+  // backend is provided for rendering.
+  virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w);
+
   // Returns a gfx::VsyncProvider for the provided AcceleratedWidget. Note
   // that this may be called after we have entered the sandbox so if there are
   // operations (e.g. opening a file descriptor providing vsync events) that
diff --git a/ui/gfx/platform_font_mac.h b/ui/gfx/platform_font_mac.h
index e9d0714..02006c3 100644
--- a/ui/gfx/platform_font_mac.h
+++ b/ui/gfx/platform_font_mac.h
@@ -6,6 +6,7 @@
 #define UI_GFX_PLATFORM_FONT_MAC_H_
 
 #include "base/compiler_specific.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/gfx/platform_font.h"
 
 namespace gfx {
@@ -31,22 +32,25 @@
   virtual NativeFont GetNativeFont() const OVERRIDE;
 
  private:
-  PlatformFontMac(const std::string& font_name, int font_size, int style);
-  virtual ~PlatformFontMac() {}
+  PlatformFontMac(const std::string& font_name, int font_size, int font_style);
+  virtual ~PlatformFontMac();
 
-  // Initialize the object with the specified parameters.
-  void InitWithNameSizeAndStyle(const std::string& font_name,
-                                int font_size,
-                                int style);
-
-  // Calculate and cache the font metrics.
+  // Calculates and caches the font metrics.
   void CalculateMetrics();
 
-  std::string font_name_;
-  int font_size_;
-  int style_;
+  // The NSFont instance for this object. If this object was constructed from an
+  // NSFont instance, this holds that NSFont instance. Otherwise this NSFont
+  // instance is constructed from the name, size, and style, and if there is no
+  // active font that matched those criteria, this object may be nil.
+  base::scoped_nsobject<NSFont> native_font_;
 
-  // Cached metrics, generated at construction.
+  // The name/size/style trio that specify the font. Initialized in the
+  // constructors.
+  std::string font_name_;  // Corresponds to -[NSFont fontFamily].
+  int font_size_;
+  int font_style_;
+
+  // Cached metrics, generated in CalculateMetrics().
   int height_;
   int ascent_;
   int cap_height_;
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm
index c75bf66..fa9d589 100644
--- a/ui/gfx/platform_font_mac.mm
+++ b/ui/gfx/platform_font_mac.mm
@@ -15,33 +15,75 @@
 
 namespace gfx {
 
+namespace {
+
+// Returns an autoreleased NSFont created with the passed-in specifications.
+NSFont* NSFontWithSpec(const std::string& font_name,
+                       int font_size,
+                       int font_style) {
+  NSFontSymbolicTraits trait_bits = 0;
+  if (font_style & Font::BOLD)
+    trait_bits |= NSFontBoldTrait;
+  if (font_style & Font::ITALIC)
+    trait_bits |= NSFontItalicTrait;
+  // The Mac doesn't support underline as a font trait, so just drop it.
+  // (Underlines must be added as an attribute on an NSAttributedString.)
+  NSDictionary* traits = @{ NSFontSymbolicTrait : @(trait_bits) };
+
+  NSDictionary* attrs = @{
+    NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name),
+    NSFontTraitsAttribute : traits
+  };
+  NSFontDescriptor* descriptor =
+      [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
+  NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size];
+  if (font)
+    return font;
+
+  // Make one fallback attempt by looking up via font name rather than font
+  // family name.
+  attrs = @{
+    NSFontNameAttribute : base::SysUTF8ToNSString(font_name),
+    NSFontTraitsAttribute : traits
+  };
+  descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
+  return [NSFont fontWithDescriptor:descriptor size:font_size];
+}
+
+}  // namespace
+
 ////////////////////////////////////////////////////////////////////////////////
 // PlatformFontMac, public:
 
-PlatformFontMac::PlatformFontMac() {
-  font_size_ = [NSFont systemFontSize];
-  style_ = gfx::Font::NORMAL;
-  NSFont* system_font = [NSFont systemFontOfSize:font_size_];
-  font_name_ = base::SysNSStringToUTF8([system_font fontName]);
+PlatformFontMac::PlatformFontMac()
+    : native_font_([[NSFont systemFontOfSize:[NSFont systemFontSize]] retain]),
+      font_name_(base::SysNSStringToUTF8([native_font_ familyName])),
+      font_size_([NSFont systemFontSize]),
+      font_style_(Font::NORMAL) {
   CalculateMetrics();
 }
 
-PlatformFontMac::PlatformFontMac(NativeFont native_font) {
-  int style = 0;
+PlatformFontMac::PlatformFontMac(NativeFont native_font)
+    : native_font_([native_font retain]),
+      font_name_(base::SysNSStringToUTF8([native_font_ familyName])),
+      font_size_([native_font_ pointSize]),
+      font_style_(Font::NORMAL) {
   NSFontSymbolicTraits traits = [[native_font fontDescriptor] symbolicTraits];
   if (traits & NSFontItalicTrait)
-    style |= Font::ITALIC;
+    font_style_ |= Font::ITALIC;
   if (traits & NSFontBoldTrait)
-    style |= Font::BOLD;
+    font_style_ |= Font::BOLD;
 
-  InitWithNameSizeAndStyle(base::SysNSStringToUTF8([native_font familyName]),
-                           [native_font pointSize],
-                           style);
+  CalculateMetrics();
 }
 
 PlatformFontMac::PlatformFontMac(const std::string& font_name,
-                                 int font_size) {
-  InitWithNameSizeAndStyle(font_name, font_size, gfx::Font::NORMAL);
+                                 int font_size)
+    : native_font_([NSFontWithSpec(font_name, font_size, Font::NORMAL) retain]),
+      font_name_(font_name),
+      font_size_(font_size),
+      font_style_(Font::NORMAL) {
+  CalculateMetrics();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +119,7 @@
 }
 
 int PlatformFontMac::GetStyle() const {
-  return style_;
+  return font_style_;
 }
 
 std::string PlatformFontMac::GetFontName() const {
@@ -89,23 +131,7 @@
 }
 
 NativeFont PlatformFontMac::GetNativeFont() const {
-  // We could cache this, but then we'd have to conditionally change the
-  // dtor just for MacOS. Not sure if we want to/need to do that.
-  NSFont* font = [NSFont fontWithName:base::SysUTF8ToNSString(font_name_)
-                                 size:font_size_];
-
-  if (style_ & Font::BOLD) {
-    font = [[NSFontManager sharedFontManager] convertFont:font
-                                              toHaveTrait:NSBoldFontMask];
-  }
-  if (style_ & Font::ITALIC) {
-    font = [[NSFontManager sharedFontManager] convertFont:font
-                                              toHaveTrait:NSItalicFontMask];
-  }
-  // Mac doesn't support underline as a font trait, just drop it. Underlines
-  // can instead be added as an attribute on an NSAttributedString.
-
-  return font;
+  return [[native_font_.get() retain] autorelease];
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -113,21 +139,29 @@
 
 PlatformFontMac::PlatformFontMac(const std::string& font_name,
                                  int font_size,
-                                 int style) {
-  InitWithNameSizeAndStyle(font_name, font_size, style);
-}
-
-void PlatformFontMac::InitWithNameSizeAndStyle(const std::string& font_name,
-                                               int font_size,
-                                               int style) {
-  font_name_ = font_name;
-  font_size_ = font_size;
-  style_ = style;
+                                 int font_style)
+    : native_font_([NSFontWithSpec(font_name, font_size, font_style) retain]),
+      font_name_(font_name),
+      font_size_(font_size),
+      font_style_(font_style) {
   CalculateMetrics();
 }
 
+PlatformFontMac::~PlatformFontMac() {
+}
+
 void PlatformFontMac::CalculateMetrics() {
-  NSFont* font = GetNativeFont();
+  NSFont* font = native_font_.get();
+  if (!font) {
+    // This object was constructed from a font name that doesn't correspond to
+    // an actual font. Don't waste time working out metrics.
+    height_ = 0;
+    ascent_ = 0;
+    cap_height_ = 0;
+    average_width_ = 0;
+    return;
+  }
+
   base::scoped_nsobject<NSLayoutManager> layout_manager(
       [[NSLayoutManager alloc] init]);
   height_ = [layout_manager defaultLineHeightForFont:font];
diff --git a/ui/gfx/render_text_mac.cc b/ui/gfx/render_text_mac.cc
index d86975d..327fc52 100644
--- a/ui/gfx/render_text_mac.cc
+++ b/ui/gfx/render_text_mac.cc
@@ -112,10 +112,7 @@
   runs_valid_ = false;
 
   const Font& font = GetPrimaryFont();
-  base::ScopedCFTypeRef<CFStringRef> font_name_cf_string(
-      base::SysUTF8ToCFStringRef(font.GetFontName()));
-  base::ScopedCFTypeRef<CTFontRef> ct_font(
-      CTFontCreateWithName(font_name_cf_string, font.GetFontSize(), NULL));
+  CTFontRef ct_font = base::mac::NSToCFCast(font.GetNativeFont());
 
   const void* keys[] = { kCTFontAttributeName };
   const void* values[] = { ct_font };
diff --git a/ui/gfx/screen_mac.mm b/ui/gfx/screen_mac.mm
index 28707ca..a7ea204 100644
--- a/ui/gfx/screen_mac.mm
+++ b/ui/gfx/screen_mac.mm
@@ -140,6 +140,8 @@
     if (!window)
       return GetPrimaryDisplay();
     NSScreen* match_screen = [window screen];
+    if (!match_screen)
+      return GetPrimaryDisplay();
     return GetDisplayForScreen(match_screen, false /* may not be primary */);
   }
 
diff --git a/ui/gfx/skbitmap_operations.cc b/ui/gfx/skbitmap_operations.cc
index bcc2723..c891536 100644
--- a/ui/gfx/skbitmap_operations.cc
+++ b/ui/gfx/skbitmap_operations.cc
@@ -560,10 +560,9 @@
 
   SkBitmap shifted;
   shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(),
-                    bitmap.height(), 0);
+                    bitmap.height());
   shifted.allocPixels();
   shifted.eraseARGB(0, 0, 0, 0);
-  shifted.setIsOpaque(false);
 
   SkAutoLockPixels lock_bitmap(bitmap);
   SkAutoLockPixels lock_shifted(shifted);
@@ -704,7 +703,8 @@
     return bitmap;
 
   SkBitmap opaque_bitmap;
-  opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height());
+  opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height(),
+                          0, kOpaque_SkAlphaType);
   opaque_bitmap.allocPixels();
 
   {
@@ -720,7 +720,6 @@
     }
   }
 
-  opaque_bitmap.setIsOpaque(true);
   return opaque_bitmap;
 }
 
diff --git a/ui/gfx/skbitmap_operations_unittest.cc b/ui/gfx/skbitmap_operations_unittest.cc
index bfb208c..4e488aa 100644
--- a/ui/gfx/skbitmap_operations_unittest.cc
+++ b/ui/gfx/skbitmap_operations_unittest.cc
@@ -63,10 +63,9 @@
     color_utils::HSL hsl_shift) {
   SkBitmap shifted;
   shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(),
-                    bitmap.height(), 0);
+                    bitmap.height());
   shifted.allocPixels();
   shifted.eraseARGB(0, 0, 0, 0);
-  shifted.setIsOpaque(false);
 
   SkAutoLockPixels lock_bitmap(bitmap);
   SkAutoLockPixels lock_shifted(shifted);
diff --git a/ui/gfx/test/color_util.cc b/ui/gfx/test/color_util.cc
new file mode 100644
index 0000000..a1316f3
--- /dev/null
+++ b/ui/gfx/test/color_util.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/test/color_util.h"
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+namespace gfx {
+
+namespace {
+
+std::string ColorAsString(SkColor color) {
+  std::ostringstream stream;
+  stream << std::hex << std::uppercase << "#" << std::setfill('0')
+         << std::setw(2) << SkColorGetA(color)
+         << std::setw(2) << SkColorGetR(color)
+         << std::setw(2) << SkColorGetG(color)
+         << std::setw(2) << SkColorGetB(color);
+  return stream.str();
+}
+
+}  // namespace
+
+::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
+                                               const char* rhs_expr,
+                                               SkColor lhs,
+                                               SkColor rhs) {
+  if (lhs == rhs) {
+    return ::testing::AssertionSuccess();
+  }
+  return ::testing::AssertionFailure() << "Value of: " << rhs_expr
+                                       << "\n  Actual: " << ColorAsString(rhs)
+                                       << "\nExpected: " << lhs_expr
+                                       << "\nWhich is: " << ColorAsString(lhs);
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/test/color_util.h b/ui/gfx/test/color_util.h
new file mode 100644
index 0000000..8291701
--- /dev/null
+++ b/ui/gfx/test/color_util.h
@@ -0,0 +1,26 @@
+// Copyright 2013 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 CC_TEST_COLOR_UTIL_H_
+#define CC_TEST_COLOR_UTIL_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+
+#define EXPECT_SKCOLOR_EQ(a, b) \
+  EXPECT_PRED_FORMAT2(::gfx::AssertSkColorsEqual, a, b)
+
+::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
+                                               const char* rhs_expr,
+                                               SkColor lhs,
+                                               SkColor rhs);
+
+}  // namespace gfx
+
+#endif  // CC_TEST_COLOR_UTIL_H_
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index e129af5..7fe5174 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -389,10 +389,6 @@
 }
 
 Vector2dF Transform::To2dTranslation() const {
-  DCHECK(IsIdentityOrTranslation());
-  // Ensure that this translation is truly 2d.
-  const SkMScalar translate_z = matrix_.get(2, 3);
-  DCHECK_EQ(0.f, translate_z);
   return gfx::Vector2dF(SkMScalarToFloat(matrix_.get(0, 3)),
                         SkMScalarToFloat(matrix_.get(1, 3)));
 }
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index 3621741..5e3b830 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -181,8 +181,7 @@
   //
   void FlattenTo2d();
 
-  // Returns the translation components of the matrix. It is an error to call
-  // this function if the transform does not represent only a 2d translation.
+  // Returns the x and y translation components of the matrix.
   Vector2dF To2dTranslation() const;
 
   // Applies the transformation to the point.
diff --git a/ui/gfx/transform_util.cc b/ui/gfx/transform_util.cc
index 916b0b0..655ce57 100644
--- a/ui/gfx/transform_util.cc
+++ b/ui/gfx/transform_util.cc
@@ -7,8 +7,11 @@
 #include <algorithm>
 #include <cmath>
 
+#include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "ui/gfx/point.h"
+#include "ui/gfx/point3_f.h"
+#include "ui/gfx/rect.h"
 
 namespace gfx {
 
@@ -53,6 +56,10 @@
   out[2] = z;
 }
 
+SkMScalar Round(SkMScalar n) {
+  return SkDoubleToMScalar(std::floor(SkMScalarToDouble(n) + 0.5));
+}
+
 // Taken from http://www.w3.org/TR/css3-transforms/.
 bool Slerp(SkMScalar out[4],
            const SkMScalar q1[4],
@@ -108,6 +115,163 @@
   return true;
 }
 
+SkMatrix44 BuildPerspectiveMatrix(const DecomposedTransform& decomp) {
+  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+
+  for (int i = 0; i < 4; i++)
+    matrix.setDouble(3, i, decomp.perspective[i]);
+  return matrix;
+}
+
+SkMatrix44 BuildTranslationMatrix(const DecomposedTransform& decomp) {
+  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
+  // Implicitly calls matrix.setIdentity()
+  matrix.setTranslate(SkDoubleToMScalar(decomp.translate[0]),
+                      SkDoubleToMScalar(decomp.translate[1]),
+                      SkDoubleToMScalar(decomp.translate[2]));
+  return matrix;
+}
+
+SkMatrix44 BuildSnappedTranslationMatrix(DecomposedTransform decomp) {
+  decomp.translate[0] = Round(decomp.translate[0]);
+  decomp.translate[1] = Round(decomp.translate[1]);
+  decomp.translate[2] = Round(decomp.translate[2]);
+  return BuildTranslationMatrix(decomp);
+}
+
+SkMatrix44 BuildRotationMatrix(const DecomposedTransform& decomp) {
+  double x = decomp.quaternion[0];
+  double y = decomp.quaternion[1];
+  double z = decomp.quaternion[2];
+  double w = decomp.quaternion[3];
+
+  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
+
+  // Implicitly calls matrix.setIdentity()
+  matrix.set3x3(1.0 - 2.0 * (y * y + z * z),
+                2.0 * (x * y + z * w),
+                2.0 * (x * z - y * w),
+                2.0 * (x * y - z * w),
+                1.0 - 2.0 * (x * x + z * z),
+                2.0 * (y * z + x * w),
+                2.0 * (x * z + y * w),
+                2.0 * (y * z - x * w),
+                1.0 - 2.0 * (x * x + y * y));
+  return matrix;
+}
+
+SkMatrix44 BuildSnappedRotationMatrix(const DecomposedTransform& decomp) {
+  // Create snapped rotation.
+  SkMatrix44 rotation_matrix = BuildRotationMatrix(decomp);
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < 3; ++j) {
+      SkMScalar value = rotation_matrix.get(i, j);
+      // Snap values to -1, 0 or 1.
+      if (value < -0.5f) {
+        value = -1.0f;
+      } else if (value > 0.5f) {
+        value = 1.0f;
+      } else {
+        value = 0.0f;
+      }
+      rotation_matrix.set(i, j, value);
+    }
+  }
+  return rotation_matrix;
+}
+
+SkMatrix44 BuildSkewMatrix(const DecomposedTransform& decomp) {
+  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+
+  SkMatrix44 temp(SkMatrix44::kIdentity_Constructor);
+  if (decomp.skew[2]) {
+    temp.setDouble(1, 2, decomp.skew[2]);
+    matrix.preConcat(temp);
+  }
+
+  if (decomp.skew[1]) {
+    temp.setDouble(1, 2, 0);
+    temp.setDouble(0, 2, decomp.skew[1]);
+    matrix.preConcat(temp);
+  }
+
+  if (decomp.skew[0]) {
+    temp.setDouble(0, 2, 0);
+    temp.setDouble(0, 1, decomp.skew[0]);
+    matrix.preConcat(temp);
+  }
+  return matrix;
+}
+
+SkMatrix44 BuildScaleMatrix(const DecomposedTransform& decomp) {
+  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
+  matrix.setScale(SkDoubleToMScalar(decomp.scale[0]),
+                  SkDoubleToMScalar(decomp.scale[1]),
+                  SkDoubleToMScalar(decomp.scale[2]));
+  return matrix;
+}
+
+SkMatrix44 BuildSnappedScaleMatrix(DecomposedTransform decomp) {
+  decomp.scale[0] = Round(decomp.scale[0]);
+  decomp.scale[1] = Round(decomp.scale[1]);
+  decomp.scale[2] = Round(decomp.scale[2]);
+  return BuildScaleMatrix(decomp);
+}
+
+Transform ComposeTransform(const SkMatrix44& perspective,
+                           const SkMatrix44& translation,
+                           const SkMatrix44& rotation,
+                           const SkMatrix44& skew,
+                           const SkMatrix44& scale) {
+  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+
+  matrix.preConcat(perspective);
+  matrix.preConcat(translation);
+  matrix.preConcat(rotation);
+  matrix.preConcat(skew);
+  matrix.preConcat(scale);
+
+  Transform to_return;
+  to_return.matrix() = matrix;
+  return to_return;
+}
+
+bool CheckViewportPointMapsWithinOnePixel(const Point& point,
+                                          const Transform& transform) {
+  Point3F point_original(point);
+  Point3F point_transformed(point);
+
+  // Can't use TransformRect here since it would give us the axis-aligned
+  // bounding rect of the 4 points in the initial rectable which is not what we
+  // want.
+  transform.TransformPoint(&point_transformed);
+
+  if ((point_transformed - point_original).Length() > 1.f) {
+    // The changed distance should not be more than 1 pixel.
+    return false;
+  }
+  return true;
+}
+
+bool CheckTransformsMapsIntViewportWithinOnePixel(const Rect& viewport,
+                                                  const Transform& original,
+                                                  const Transform& snapped) {
+
+  Transform original_inv(Transform::kSkipInitialization);
+  bool invertible = true;
+  invertible &= original.GetInverse(&original_inv);
+  DCHECK(invertible) << "Non-invertible transform, cannot snap.";
+
+  Transform combined = snapped * original_inv;
+
+  return CheckViewportPointMapsWithinOnePixel(viewport.origin(), combined) &&
+         CheckViewportPointMapsWithinOnePixel(viewport.top_right(), combined) &&
+         CheckViewportPointMapsWithinOnePixel(viewport.bottom_left(),
+                                              combined) &&
+         CheckViewportPointMapsWithinOnePixel(viewport.bottom_right(),
+                                              combined);
+}
+
 }  // namespace
 
 Transform GetScaleTransform(const Point& anchor, float scale) {
@@ -270,54 +434,42 @@
 
 // Taken from http://www.w3.org/TR/css3-transforms/.
 Transform ComposeTransform(const DecomposedTransform& decomp) {
-  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
-  for (int i = 0; i < 4; i++)
-    matrix.set(3, i, decomp.perspective[i]);
+  SkMatrix44 perspective = BuildPerspectiveMatrix(decomp);
+  SkMatrix44 translation = BuildTranslationMatrix(decomp);
+  SkMatrix44 rotation = BuildRotationMatrix(decomp);
+  SkMatrix44 skew = BuildSkewMatrix(decomp);
+  SkMatrix44 scale = BuildScaleMatrix(decomp);
 
-  matrix.preTranslate(
-      decomp.translate[0], decomp.translate[1], decomp.translate[2]);
+  return ComposeTransform(perspective, translation, rotation, skew, scale);
+}
 
-  SkMScalar x = decomp.quaternion[0];
-  SkMScalar y = decomp.quaternion[1];
-  SkMScalar z = decomp.quaternion[2];
-  SkMScalar w = decomp.quaternion[3];
+bool SnapTransform(Transform* out,
+                   const Transform& transform,
+                   const Rect& viewport) {
+  DecomposedTransform decomp;
+  DecomposeTransform(&decomp, transform);
 
-  SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor);
-  rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z),
-                         2.0 * (x * y + z * w),
-                         2.0 * (x * z - y * w),
-                         2.0 * (x * y - z * w),
-                         1.0 - 2.0 * (x * x + z * z),
-                         2.0 * (y * z + x * w),
-                         2.0 * (x * z + y * w),
-                         2.0 * (y * z - x * w),
-                         1.0 - 2.0 * (x * x + y * y));
+  SkMatrix44 rotation_matrix = BuildSnappedRotationMatrix(decomp);
+  SkMatrix44 translation = BuildSnappedTranslationMatrix(decomp);
+  SkMatrix44 scale = BuildSnappedScaleMatrix(decomp);
 
-  matrix.preConcat(rotation_matrix);
+  // Rebuild matrices for other unchanged components.
+  SkMatrix44 perspective = BuildPerspectiveMatrix(decomp);
 
-  SkMatrix44 temp(SkMatrix44::kIdentity_Constructor);
-  if (decomp.skew[2]) {
-    temp.set(1, 2, decomp.skew[2]);
-    matrix.preConcat(temp);
+  // Completely ignore the skew.
+  SkMatrix44 skew(SkMatrix44::kIdentity_Constructor);
+
+  // Get full tranform
+  Transform snapped =
+      ComposeTransform(perspective, translation, rotation_matrix, skew, scale);
+
+  // Verify that viewport is not moved unnaturally.
+  bool snappable =
+    CheckTransformsMapsIntViewportWithinOnePixel(viewport, transform, snapped);
+  if (snappable) {
+    *out = snapped;
   }
-
-  if (decomp.skew[1]) {
-    temp.set(1, 2, 0);
-    temp.set(0, 2, decomp.skew[1]);
-    matrix.preConcat(temp);
-  }
-
-  if (decomp.skew[0]) {
-    temp.set(0, 2, 0);
-    temp.set(0, 1, decomp.skew[0]);
-    matrix.preConcat(temp);
-  }
-
-  matrix.preScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]);
-
-  Transform to_return;
-  to_return.matrix() = matrix;
-  return to_return;
+  return snappable;
 }
 
 std::string DecomposedTransform::ToString() const {
diff --git a/ui/gfx/transform_util.h b/ui/gfx/transform_util.h
index 07bf0d5..a77ded2 100644
--- a/ui/gfx/transform_util.h
+++ b/ui/gfx/transform_util.h
@@ -11,6 +11,7 @@
 namespace gfx {
 
 class Point;
+class Rect;
 
 // Returns a scale transform at |anchor| point.
 GFX_EXPORT Transform GetScaleTransform(const Point& anchor, float scale);
@@ -53,6 +54,10 @@
 // http://www.w3.org/TR/css3-3d-transforms/.
 GFX_EXPORT Transform ComposeTransform(const DecomposedTransform& decomp);
 
+GFX_EXPORT bool SnapTransform(Transform* out,
+                              const Transform& transform,
+                              const Rect& viewport);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_TRANSFORM_UTIL_H_
diff --git a/ui/gfx/transform_util_unittest.cc b/ui/gfx/transform_util_unittest.cc
index 94195c2..41bfc40 100644
--- a/ui/gfx/transform_util_unittest.cc
+++ b/ui/gfx/transform_util_unittest.cc
@@ -6,6 +6,8 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/point.h"
+#include "ui/gfx/point3_f.h"
+#include "ui/gfx/rect.h"
 
 namespace gfx {
 namespace {
@@ -30,5 +32,149 @@
   }
 }
 
+TEST(TransformUtilTest, SnapRotation) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+  transform.RotateAboutZAxis(89.99);
+
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_TRUE(snapped) << "Viewport should snap for this rotation.";
+}
+
+TEST(TransformUtilTest, SnapRotationDistantViewport) {
+  const int kOffset = 5000;
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+  transform.RotateAboutZAxis(89.99);
+
+  Rect viewport(kOffset, kOffset, 1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_FALSE(snapped) << "Distant viewport shouldn't snap by more than 1px.";
+}
+
+TEST(TransformUtilTest, NoSnapRotation) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+  const int kOffset = 5000;
+
+  transform.RotateAboutZAxis(89.9);
+
+  Rect viewport(kOffset, kOffset, 1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_FALSE(snapped) << "Viewport should not snap for this rotation.";
+}
+
+// Translations should always be snappable, the most we would move is 0.5
+// pixels towards either direction to the nearest value in each component.
+TEST(TransformUtilTest, SnapTranslation) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+  transform.Translate3d(
+      SkDoubleToMScalar(1.01), SkDoubleToMScalar(1.99), SkDoubleToMScalar(3.0));
+
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_TRUE(snapped) << "Viewport should snap for this translation.";
+}
+
+TEST(TransformUtilTest, SnapTranslationDistantViewport) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+  const int kOffset = 5000;
+
+  transform.Translate3d(
+      SkDoubleToMScalar(1.01), SkDoubleToMScalar(1.99), SkDoubleToMScalar(3.0));
+
+  Rect viewport(kOffset, kOffset, 1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_TRUE(snapped)
+      << "Distant viewport should still snap by less than 1px.";
+}
+
+TEST(TransformUtilTest, SnapScale) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+  transform.Scale3d(SkDoubleToMScalar(5.0),
+                    SkDoubleToMScalar(2.00001),
+                    SkDoubleToMScalar(1.0));
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_TRUE(snapped) << "Viewport should snap for this scaling.";
+}
+
+TEST(TransformUtilTest, NoSnapScale) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+  transform.Scale3d(
+    SkDoubleToMScalar(5.0), SkDoubleToMScalar(2.1), SkDoubleToMScalar(1.0));
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+
+  EXPECT_FALSE(snapped) << "Viewport shouldn't snap for this scaling.";
+}
+
+TEST(TransformUtilTest, SnapCompositeTransform) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+  transform.Translate3d(SkDoubleToMScalar(30.5), SkDoubleToMScalar(20.0),
+                        SkDoubleToMScalar(10.1));
+  transform.RotateAboutZAxis(89.99);
+  transform.Scale3d(SkDoubleToMScalar(1.0),
+                    SkDoubleToMScalar(3.00001),
+                    SkDoubleToMScalar(2.0));
+
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+  ASSERT_TRUE(snapped) << "Viewport should snap all components.";
+
+  Point3F point;
+
+  point = Point3F(viewport.origin());
+  result.TransformPoint(&point);
+  EXPECT_EQ(Point3F(31.f, 20.f, 10.f), point) << "Transformed origin";
+
+  point = Point3F(viewport.top_right());
+  result.TransformPoint(&point);
+  EXPECT_EQ(Point3F(31.f, 1940.f, 10.f), point) << "Transformed top-right";
+
+  point = Point3F(viewport.bottom_left());
+  result.TransformPoint(&point);
+  EXPECT_EQ(Point3F(-3569.f, 20.f, 10.f), point) << "Transformed bottom-left";
+
+  point = Point3F(viewport.bottom_right());
+  result.TransformPoint(&point);
+  EXPECT_EQ(Point3F(-3569.f, 1940.f, 10.f), point)
+      << "Transformed bottom-right";
+}
+
+TEST(TransformUtilTest, NoSnapSkewedCompositeTransform) {
+  Transform result(Transform::kSkipInitialization);
+  Transform transform;
+
+
+  transform.RotateAboutZAxis(89.99);
+  transform.Scale3d(SkDoubleToMScalar(1.0),
+                    SkDoubleToMScalar(3.00001),
+                    SkDoubleToMScalar(2.0));
+  transform.Translate3d(SkDoubleToMScalar(30.5), SkDoubleToMScalar(20.0),
+                        SkDoubleToMScalar(10.1));
+  transform.SkewX(20.0);
+  Rect viewport(1920, 1200);
+  bool snapped = SnapTransform(&result, transform, viewport);
+  EXPECT_FALSE(snapped) << "Skewed viewport should not snap.";
+}
+
 }  // namespace
 }  // namespace gfx
diff --git a/ui/gl/gl.target.darwin-arm.mk b/ui/gl/gl.target.darwin-arm.mk
index 73cd270..c45b9ec 100644
--- a/ui/gl/gl.target.darwin-arm.mk
+++ b/ui/gl/gl.target.darwin-arm.mk
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -291,13 +291,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl.target.darwin-mips.mk b/ui/gl/gl.target.darwin-mips.mk
index 7129bd3..4d23d46 100644
--- a/ui/gl/gl.target.darwin-mips.mk
+++ b/ui/gl/gl.target.darwin-mips.mk
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -289,13 +289,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl.target.darwin-x86.mk b/ui/gl/gl.target.darwin-x86.mk
index e3a7545..e1090cc 100644
--- a/ui/gl/gl.target.darwin-x86.mk
+++ b/ui/gl/gl.target.darwin-x86.mk
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -295,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl.target.linux-arm.mk b/ui/gl/gl.target.linux-arm.mk
index 73cd270..c45b9ec 100644
--- a/ui/gl/gl.target.linux-arm.mk
+++ b/ui/gl/gl.target.linux-arm.mk
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -291,13 +291,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl.target.linux-mips.mk b/ui/gl/gl.target.linux-mips.mk
index 7129bd3..4d23d46 100644
--- a/ui/gl/gl.target.linux-mips.mk
+++ b/ui/gl/gl.target.linux-mips.mk
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -289,13 +289,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl.target.linux-x86.mk b/ui/gl/gl.target.linux-x86.mk
index e3a7545..e1090cc 100644
--- a/ui/gl/gl.target.linux-x86.mk
+++ b/ui/gl/gl.target.linux-x86.mk
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -295,13 +295,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_implementation_ozone.cc b/ui/gl/gl_implementation_ozone.cc
index d4e3dda..2ca30a4 100644
--- a/ui/gl/gl_implementation_ozone.cc
+++ b/ui/gl/gl_implementation_ozone.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "ui/gfx/ozone/surface_factory_ozone.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_egl_api_implementation.h"
@@ -41,7 +42,9 @@
     case kGLImplementationOSMesaGL:
       return InitializeGLBindingsOSMesaGL();
     case kGLImplementationEGLGLES2:
-      if (!gfx::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings())
+      if (!gfx::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings(
+              base::Bind(&AddGLNativeLibrary),
+              base::Bind(&SetGLGetProcAddressProc)))
         return false;
       SetGLImplementation(kGLImplementationEGLGLES2);
       InitializeGLBindingsGL();
diff --git a/ui/gl/gl_jni_headers.target.darwin-arm.mk b/ui/gl/gl_jni_headers.target.darwin-arm.mk
index 05dd969..bf628c1 100644
--- a/ui/gl/gl_jni_headers.target.darwin-arm.mk
+++ b/ui/gl/gl_jni_headers.target.darwin-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_jni_headers.target.darwin-mips.mk b/ui/gl/gl_jni_headers.target.darwin-mips.mk
index e5d5582..fdee9e3 100644
--- a/ui/gl/gl_jni_headers.target.darwin-mips.mk
+++ b/ui/gl/gl_jni_headers.target.darwin-mips.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_jni_headers.target.darwin-x86.mk b/ui/gl/gl_jni_headers.target.darwin-x86.mk
index 2249324..896fff8 100644
--- a/ui/gl/gl_jni_headers.target.darwin-x86.mk
+++ b/ui/gl/gl_jni_headers.target.darwin-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_jni_headers.target.linux-arm.mk b/ui/gl/gl_jni_headers.target.linux-arm.mk
index 05dd969..bf628c1 100644
--- a/ui/gl/gl_jni_headers.target.linux-arm.mk
+++ b/ui/gl/gl_jni_headers.target.linux-arm.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_jni_headers.target.linux-mips.mk b/ui/gl/gl_jni_headers.target.linux-mips.mk
index e5d5582..fdee9e3 100644
--- a/ui/gl/gl_jni_headers.target.linux-mips.mk
+++ b/ui/gl/gl_jni_headers.target.linux-mips.mk
@@ -92,13 +92,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -169,13 +169,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_jni_headers.target.linux-x86.mk b/ui/gl/gl_jni_headers.target.linux-x86.mk
index 2249324..896fff8 100644
--- a/ui/gl/gl_jni_headers.target.linux-x86.mk
+++ b/ui/gl/gl_jni_headers.target.linux-x86.mk
@@ -95,13 +95,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc
index d535c06..ff2ed84 100644
--- a/ui/gl/gl_surface_win.cc
+++ b/ui/gl/gl_surface_win.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/win/windows_version.h"
 #include "third_party/mesa/src/include/GL/osmesa.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
@@ -56,8 +57,16 @@
     if (result != S_OK)
       return;
 
-    base::TimeTicks timebase = base::TimeTicks::FromQPCValue(
-        static_cast<LONGLONG>(timing_info.qpcVBlank));
+    base::TimeTicks timebase;
+    // If FrameTime is not high resolution, we do not want to translate the
+    // QPC value provided by DWM into the low-resolution timebase, which
+    // would be error prone and jittery. As a fallback, we assume the timebase
+    // is zero.
+    if (gfx::FrameTime::TimestampsAreHighRes()) {
+      timebase = gfx::FrameTime::FromQPCValue(
+          static_cast<LONGLONG>(timing_info.qpcVBlank));
+    }
+
     // Swap the numerator/denominator to convert frequency to period.
     if (timing_info.rateRefresh.uiDenominator > 0 &&
         timing_info.rateRefresh.uiNumerator > 0) {
diff --git a/ui/gl/surface_jni_headers.target.darwin-arm.mk b/ui/gl/surface_jni_headers.target.darwin-arm.mk
index 956ceab..90766b4 100644
--- a/ui/gl/surface_jni_headers.target.darwin-arm.mk
+++ b/ui/gl/surface_jni_headers.target.darwin-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/surface_jni_headers.target.darwin-mips.mk b/ui/gl/surface_jni_headers.target.darwin-mips.mk
index c928dc3..0a35877 100644
--- a/ui/gl/surface_jni_headers.target.darwin-mips.mk
+++ b/ui/gl/surface_jni_headers.target.darwin-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/surface_jni_headers.target.darwin-x86.mk b/ui/gl/surface_jni_headers.target.darwin-x86.mk
index 0c20e1c..057a691 100644
--- a/ui/gl/surface_jni_headers.target.darwin-x86.mk
+++ b/ui/gl/surface_jni_headers.target.darwin-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/surface_jni_headers.target.linux-arm.mk b/ui/gl/surface_jni_headers.target.linux-arm.mk
index 956ceab..90766b4 100644
--- a/ui/gl/surface_jni_headers.target.linux-arm.mk
+++ b/ui/gl/surface_jni_headers.target.linux-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -153,13 +153,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/surface_jni_headers.target.linux-mips.mk b/ui/gl/surface_jni_headers.target.linux-mips.mk
index c928dc3..0a35877 100644
--- a/ui/gl/surface_jni_headers.target.linux-mips.mk
+++ b/ui/gl/surface_jni_headers.target.linux-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -151,13 +151,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/gl/surface_jni_headers.target.linux-x86.mk b/ui/gl/surface_jni_headers.target.linux-x86.mk
index 0c20e1c..057a691 100644
--- a/ui/gl/surface_jni_headers.target.linux-x86.mk
+++ b/ui/gl/surface_jni_headers.target.linux-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keyboard/OWNERS b/ui/keyboard/OWNERS
index 93ca4b2..6f3bdd6 100644
--- a/ui/keyboard/OWNERS
+++ b/ui/keyboard/OWNERS
@@ -1,2 +1,4 @@
 bryeung@chromium.org
 sadrul@chromium.org
+bshe@chromium.org
+kevers@chromium.org
diff --git a/ui/keyboard/keyboard.gyp b/ui/keyboard/keyboard.gyp
index 4edb5ef..762b555 100644
--- a/ui/keyboard/keyboard.gyp
+++ b/ui/keyboard/keyboard.gyp
@@ -86,8 +86,8 @@
         '../aura/aura.gyp:aura_test_support',
         '../compositor/compositor.gyp:compositor',
         '../gfx/gfx.gyp:gfx',
-        '../ui.gyp:run_ui_unittests',
         '../ui.gyp:ui',
+        '../ui_unittests.gyp:run_ui_unittests',
         'keyboard',
       ],
       'sources': [
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 313bc04..00a3b1b 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -5,6 +5,7 @@
 #include "ui/keyboard/keyboard_controller.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "ui/aura/layout_manager.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
@@ -18,6 +19,7 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
 #include "ui/keyboard/keyboard_controller_proxy.h"
+#include "ui/keyboard/keyboard_switches.h"
 #include "ui/keyboard/keyboard_util.h"
 
 namespace {
@@ -188,10 +190,13 @@
   bool should_show = was_showing;
   ui::TextInputType type =
       client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
-  if (type == ui::TEXT_INPUT_TYPE_NONE) {
+  if (type == ui::TEXT_INPUT_TYPE_NONE &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kKeyboardUsabilityTest)) {
     should_show = false;
   } else {
     if (container_->children().empty()) {
+      keyboard::MarkKeyboardLoadStarted();
       aura::Window* keyboard = proxy_->GetKeyboardWindow();
       keyboard->Show();
       container_->AddChild(keyboard);
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc
index 407cc6a..35dbd9e 100644
--- a/ui/keyboard/keyboard_controller_unittest.cc
+++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,6 +20,7 @@
 #include "ui/gfx/rect.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_controller_proxy.h"
+#include "ui/keyboard/keyboard_switches.h"
 
 namespace keyboard {
 namespace {
@@ -329,4 +331,39 @@
   EXPECT_TRUE(keyboard_container->IsVisible());
 }
 
+class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
+ public:
+  KeyboardControllerUsabilityTest() {}
+  virtual ~KeyboardControllerUsabilityTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kKeyboardUsabilityTest);
+    KeyboardControllerTest::SetUp();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KeyboardControllerUsabilityTest);
+};
+
+TEST_F(KeyboardControllerUsabilityTest, KeyboardAlwaysVisibleInUsabilityTest) {
+  const gfx::Rect& root_bounds = root_window()->bounds();
+
+  ui::InputMethod* input_method = proxy()->GetInputMethod();
+  TestTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
+  TestTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
+  input_method->SetFocusedTextInputClient(&input_client);
+
+  aura::Window* keyboard_container(controller()->GetContainerWindow());
+  keyboard_container->SetBounds(root_bounds);
+  root_window()->AddChild(keyboard_container);
+
+  EXPECT_TRUE(keyboard_container->IsVisible());
+
+  input_method->SetFocusedTextInputClient(&no_input_client);
+  // Keyboard should not hide itself after lost focus.
+  EXPECT_TRUE(keyboard_container->IsVisible());
+  EXPECT_FALSE(WillHideKeyboard());
+}
+
 }  // namespace keyboard
diff --git a/ui/keyboard/keyboard_resources.grd b/ui/keyboard/keyboard_resources.grd
index f86ced5..d4e383b 100644
--- a/ui/keyboard/keyboard_resources.grd
+++ b/ui/keyboard/keyboard_resources.grd
@@ -29,6 +29,7 @@
       <include name="IDR_KEYBOARD_ELEMENTS_KEYBOARD" file="resources/elements/kb-keyboard.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEYSET" file="resources/elements/kb-keyset.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY" file="resources/elements/kb-modifier-key.html" type="BINDATA" />
+      <include name="IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU" file="resources/elements/kb-options-menu.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_ROW" file="resources/elements/kb-row.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_SHIFT_KEY" file="resources/elements/kb-shift-key.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_FUNCTION_KEY_ROW" file="resources/layouts/function-key-row.html" type="BINDATA" />
diff --git a/ui/keyboard/keyboard_switches.cc b/ui/keyboard/keyboard_switches.cc
index d1ea4e2..9776abf 100644
--- a/ui/keyboard/keyboard_switches.cc
+++ b/ui/keyboard/keyboard_switches.cc
@@ -7,7 +7,10 @@
 namespace keyboard {
 namespace switches {
 
+const char kEnableSwipeSelection[] = "enable-swipe-selection";
+
 const char kEnableVirtualKeyboard[] = "enable-virtual-keyboard";
+const char kKeyboardUsabilityTest[] = "keyboard-usability-test";
 
 }  // namespace switches
 }  // namespace keyboard
diff --git a/ui/keyboard/keyboard_switches.h b/ui/keyboard/keyboard_switches.h
index a7d0533..b6fae62 100644
--- a/ui/keyboard/keyboard_switches.h
+++ b/ui/keyboard/keyboard_switches.h
@@ -10,9 +10,15 @@
 namespace keyboard {
 namespace switches {
 
+// Enables the swipe selection feature on the virtual keyboard.
+KEYBOARD_EXPORT extern const char kEnableSwipeSelection[];
+
 // Enables the virtual keyboard.
 KEYBOARD_EXPORT extern const char kEnableVirtualKeyboard[];
 
+// Enables the keyboard usability test.
+KEYBOARD_EXPORT extern const char kKeyboardUsabilityTest[];
+
 }  // namespace switches
 }  // namespace keyboard
 
diff --git a/ui/keyboard/keyboard_ui_controller.cc b/ui/keyboard/keyboard_ui_controller.cc
index 677fc65..2bc6a57 100644
--- a/ui/keyboard/keyboard_ui_controller.cc
+++ b/ui/keyboard/keyboard_ui_controller.cc
@@ -38,6 +38,8 @@
                           IDR_KEYBOARD_ELEMENTS_KEYSET);
   source->AddResourcePath("elements/kb-modifier-key.html",
                           IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY);
+  source->AddResourcePath("elements/kb-options-menu.html",
+                          IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU);
   source->AddResourcePath("elements/kb-row.html", IDR_KEYBOARD_ELEMENTS_ROW);
   source->AddResourcePath("elements/kb-shift-key.html",
                           IDR_KEYBOARD_ELEMENTS_SHIFT_KEY);
diff --git a/ui/keyboard/keyboard_ui_handler.cc b/ui/keyboard/keyboard_ui_handler.cc
index 26909c2..610d0e2 100644
--- a/ui/keyboard/keyboard_ui_handler.cc
+++ b/ui/keyboard/keyboard_ui_handler.cc
@@ -54,7 +54,7 @@
     return;
   }
 
-  aura::RootWindow* root_window =
+  aura::Window* root_window =
       web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow();
   if (!root_window) {
     LOG(ERROR) << "insertText failed: no root window";
@@ -75,7 +75,7 @@
   base::DictionaryValue results;
   results.SetInteger("requestId", request_id);
 
-  aura::RootWindow* root_window =
+  aura::Window* root_window =
       web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow();
   if (!root_window) {
     LOG(ERROR) << "getInputContext failed: no root window";
@@ -102,29 +102,29 @@
   std::string type;
   int char_value;
   int key_code;
-  bool shift_modifier;
+  int modifiers;
 
   if (!args->GetDictionary(0, &params) ||
       !params->GetString("type", &type) ||
       !params->GetInteger("charValue", &char_value) ||
       !params->GetInteger("keyCode", &key_code) ||
-      !params->GetBoolean("shiftKey", &shift_modifier)) {
+      !params->GetInteger("modifiers", &modifiers)) {
     LOG(ERROR) << "SendKeyEvent failed: bad argument";
     return;
   }
 
-  aura::RootWindow* root_window =
-      web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow();
-  if (!root_window) {
-    LOG(ERROR) << "sendKeyEvent failed: no root window";
+  aura::WindowEventDispatcher* dispatcher =
+      web_ui()->GetWebContents()->GetView()->GetNativeView()->GetDispatcher();
+  if (!dispatcher) {
+    LOG(ERROR) << "sendKeyEvent failed: no dispatcher";
     return;
   }
 
   if (!keyboard::SendKeyEvent(type,
                               char_value,
                               key_code,
-                              shift_modifier,
-                              root_window)) {
+                              modifiers,
+                              dispatcher)) {
     LOG(ERROR) << "sendKeyEvent failed";
   }
 }
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc
index 8b0d817..aebfcf0 100644
--- a/ui/keyboard/keyboard_util.cc
+++ b/ui/keyboard/keyboard_util.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string16.h"
@@ -23,23 +24,30 @@
 const char kKeyDown[] ="keydown";
 const char kKeyUp[] = "keyup";
 
-void SendProcessKeyEvent(ui::EventType type, aura::RootWindow* root_window) {
+void SendProcessKeyEvent(ui::EventType type,
+                         aura::WindowEventDispatcher* dispatcher) {
   ui::TranslatedKeyEvent event(type == ui::ET_KEY_PRESSED,
                                ui::VKEY_PROCESSKEY,
                                ui::EF_NONE);
-  root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
+  dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
 }
 
+base::LazyInstance<base::Time> g_keyboard_load_time_start =
+    LAZY_INSTANCE_INITIALIZER;
+
 }  // namespace
 
 namespace keyboard {
 
 bool IsKeyboardEnabled() {
   return CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableVirtualKeyboard);
+      switches::kEnableVirtualKeyboard) ||
+          CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kKeyboardUsabilityTest);
+
 }
 
-bool InsertText(const base::string16& text, aura::RootWindow* root_window) {
+bool InsertText(const base::string16& text, aura::Window* root_window) {
   if (!root_window)
     return false;
 
@@ -63,8 +71,8 @@
 // ui::TextInputClient from that (see above in InsertText()).
 bool MoveCursor(int swipe_direction,
                 int modifier_flags,
-                aura::RootWindow* root_window) {
-  if (!root_window)
+                aura::WindowEventDispatcher* dispatcher) {
+  if (!dispatcher)
     return false;
   ui::KeyboardCode codex = ui::VKEY_UNKNOWN;
   ui::KeyboardCode codey = ui::VKEY_UNKNOWN;
@@ -81,17 +89,17 @@
   // First deal with the x movement.
   if (codex != ui::VKEY_UNKNOWN) {
     ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codex, modifier_flags, 0);
-    root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
+    dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
     ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codex, modifier_flags, 0);
-    root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
+    dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
   }
 
   // Then deal with the y movement.
   if (codey != ui::VKEY_UNKNOWN) {
     ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codey, modifier_flags, 0);
-    root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
+    dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
     ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codey, modifier_flags, 0);
-    root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
+    dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
   }
   return true;
 }
@@ -99,8 +107,8 @@
 bool SendKeyEvent(const std::string type,
                   int key_value,
                   int key_code,
-                  bool shift_modifier,
-                  aura::RootWindow* root_window) {
+                  int modifiers,
+                  aura::WindowEventDispatcher* dispatcher) {
   ui::EventType event_type = ui::ET_UNKNOWN;
   if (type == kKeyDown)
     event_type = ui::ET_KEY_PRESSED;
@@ -109,26 +117,22 @@
   if (event_type == ui::ET_UNKNOWN)
     return false;
 
-  int flags = ui::EF_NONE;
-  if (shift_modifier)
-    flags = ui::EF_SHIFT_DOWN;
-
   ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
 
   if (code == ui::VKEY_UNKNOWN) {
     // Handling of special printable characters (e.g. accented characters) for
     // which there is no key code.
     if (event_type == ui::ET_KEY_RELEASED) {
-      ui::InputMethod* input_method = root_window->GetProperty(
+      ui::InputMethod* input_method = dispatcher->GetProperty(
           aura::client::kRootWindowInputMethodKey);
       if (!input_method)
         return false;
 
       ui::TextInputClient* tic = input_method->GetTextInputClient();
 
-      SendProcessKeyEvent(ui::ET_KEY_PRESSED, root_window);
+      SendProcessKeyEvent(ui::ET_KEY_PRESSED, dispatcher);
       tic->InsertChar(static_cast<uint16>(key_value), ui::EF_NONE);
-      SendProcessKeyEvent(ui::ET_KEY_RELEASED, root_window);
+      SendProcessKeyEvent(ui::ET_KEY_RELEASED, dispatcher);
     }
   } else {
     if (event_type == ui::ET_KEY_RELEASED) {
@@ -146,12 +150,32 @@
       }
     }
 
-    ui::KeyEvent event(event_type, code, flags, false);
-    root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
+    ui::KeyEvent event(event_type, code, modifiers, false);
+    dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
   }
   return true;
 }
 
+const void MarkKeyboardLoadStarted() {
+  if (!g_keyboard_load_time_start.Get().ToInternalValue())
+    g_keyboard_load_time_start.Get() = base::Time::Now();
+}
+
+const void MarkKeyboardLoadFinished() {
+  // It should not be possible to finish loading the keyboard without starting
+  // to load it first.
+  DCHECK(g_keyboard_load_time_start.Get().ToInternalValue());
+
+  static bool logged = false;
+  if (!logged) {
+    // Log the delta only once.
+    UMA_HISTOGRAM_TIMES(
+        "VirtualKeyboard.FirstLoadTime",
+        base::Time::Now() - g_keyboard_load_time_start.Get());
+    logged = true;
+  }
+}
+
 const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
   // This looks a lot like the contents of a resource map; however it is
   // necessary to have a custom path for the extension path, so the resource
@@ -176,6 +200,8 @@
     {"keyboard/elements/kb-keyset.html", IDR_KEYBOARD_ELEMENTS_KEYSET},
     {"keyboard/elements/kb-modifier-key.html",
         IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY},
+    {"keyboard/elements/kb-options-menu.html",
+        IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU},
     {"keyboard/elements/kb-row.html", IDR_KEYBOARD_ELEMENTS_ROW},
     {"keyboard/elements/kb-shift-key.html", IDR_KEYBOARD_ELEMENTS_SHIFT_KEY},
     {"keyboard/layouts/function-key-row.html", IDR_KEYBOARD_FUNCTION_KEY_ROW},
diff --git a/ui/keyboard/keyboard_util.h b/ui/keyboard/keyboard_util.h
index 4797406..8769825 100644
--- a/ui/keyboard/keyboard_util.h
+++ b/ui/keyboard/keyboard_util.h
@@ -8,11 +8,10 @@
 #include <string>
 
 #include "base/strings/string16.h"
+// TODO(beng): replace with forward decl once RootWindow is renamed.
+#include "ui/aura/window.h"
 #include "ui/keyboard/keyboard_export.h"
 
-namespace aura {
-class RootWindow;
-}
 struct GritResourceMap;
 
 namespace keyboard {
@@ -41,24 +40,33 @@
 // that this may convert |text| into ui::KeyEvents for injection in some
 // special circumstances (i.e. VKEY_RETURN, VKEY_BACK).
 KEYBOARD_EXPORT bool InsertText(const base::string16& text,
-                                aura::RootWindow* root_window);
+                                aura::Window* root_window);
 
 // Move cursor when swipe on the virtualkeyboard. Returns true if cursor was
 // successfully moved according to |swipe_direction|.
 KEYBOARD_EXPORT bool MoveCursor(int swipe_direction,
                                 int modifier_flags,
-                                aura::RootWindow* root_window);
+                                aura::WindowEventDispatcher* dispatcher);
 
 // Sends a fabricated key event, where |type| is the event type, |key_value|
 // is the unicode value of the character, |key_code| is the legacy key code
-// value, and |shift_modifier| indicates if the shift key is being virtually
+// value, and |modifier| indicates if any modifier keys are being virtually
 // pressed. The event is dispatched to the active TextInputClient associated
 // with |root_window|. The type may be "keydown" or "keyup".
 KEYBOARD_EXPORT bool SendKeyEvent(std::string type,
                                    int key_value,
                                    int key_code,
-                                   bool shift_modifier,
-                                   aura::RootWindow* root_window);
+                                   int modifiers,
+                                   aura::WindowEventDispatcher* dispatcher);
+
+// Marks that the keyboard load has started. This is used to measure the time it
+// takes to fully load the keyboard. This should be called before
+// MarkKeyboardLoadFinished.
+KEYBOARD_EXPORT const void MarkKeyboardLoadStarted();
+
+// Marks that the keyboard load has ended. This finishes measuring that the
+// keyboard is loaded.
+KEYBOARD_EXPORT const void MarkKeyboardLoadFinished();
 
 // Get the list of keyboard resources. |size| is populated with the number of
 // resources in the returned array.
diff --git a/ui/keyboard/resources/api_adapter.js b/ui/keyboard/resources/api_adapter.js
index 0cedf4b..1be04e6 100644
--- a/ui/keyboard/resources/api_adapter.js
+++ b/ui/keyboard/resources/api_adapter.js
@@ -24,6 +24,10 @@
   chrome.virtualKeyboardPrivate.hideKeyboard(logIfError);
 }
 
+function keyboardLoaded() {
+  chrome.virtualKeyboardPrivate.keyboardLoaded(logIfError);
+}
+
 chrome.virtualKeyboardPrivate.onTextInputBoxFocused.addListener(
   function (inputContext) {
     keyboard.inputTypeValue = inputContext.type;
diff --git a/ui/keyboard/resources/elements/kb-key-base.html b/ui/keyboard/resources/elements/kb-key-base.html
index 963097e..f522370 100644
--- a/ui/keyboard/resources/elements/kb-key-base.html
+++ b/ui/keyboard/resources/elements/kb-key-base.html
@@ -6,7 +6,7 @@
 
 <polymer-element name="kb-key-base"
     on-pointerdown="down" on-pointerup="up" on-pointerout="out"
-    attributes="accents char invert repeat hintText toKeyset toLayout">
+    attributes="char invert repeat hintText toKeyset toLayout">
   <script>
     /**
      * The long-press delay in milliseconds before long-press handler is
@@ -121,7 +121,7 @@
         clearTimeout(this.longPressTimer);
       },
       up: function(event) {
-        this.autoRelease();
+        this.generateKeyup();
       },
 
       /**
@@ -130,15 +130,7 @@
        * released yet.
        */
       autoRelease: function() {
-        if (this.pointerId === undefined)
-          return;
-
-        // Invalidates the pointerId so the subsequent pointerup event is a
-        // noop.
-        this.pointerId = undefined;
-        clearTimeout(this.longPressTimer);
-        var detail = this.populateDetails('up');
-        this.fire('key-up', detail);
+        this.generateKeyup();
       },
 
       /**
@@ -151,6 +143,21 @@
       },
 
       /**
+       * Populates details for this key, and then fires a key-up event.
+       */
+      generateKeyup: function() {
+        if (this.pointerId === undefined)
+          return;
+
+        // Invalidates the pointerId so the subsequent pointerup event is a
+        // noop.
+        this.pointerId = undefined;
+        clearTimeout(this.longPressTimer);
+        var detail = this.populateDetails('up');
+        this.fire('key-up', detail);
+      },
+
+      /**
        * Character value associated with the key. Typically, the value is a
        * single character, but may be multi-character in cases like a ".com"
        * button.
diff --git a/ui/keyboard/resources/elements/kb-key-codes.html b/ui/keyboard/resources/elements/kb-key-codes.html
index 6a10d84..d076ec5 100644
--- a/ui/keyboard/resources/elements/kb-key-codes.html
+++ b/ui/keyboard/resources/elements/kb-key-codes.html
@@ -7,6 +7,17 @@
 <polymer-element name="kb-key-codes">
 <script>
   (function() {
+
+    // Flag values for ctrl, alt and shift as defined by EventFlags
+    // in "event_constants.h".
+    // @enum {number}
+    var Modifier = {
+      NONE: 0,
+      ALT: 8,
+      CONTROL: 4,
+      SHIFT: 2
+    }
+
     // Each virtual key event is assigned a unique ID.
     var nextRequestID = 0;
 
@@ -18,7 +29,9 @@
     // keyCode attribute for kb-key or kb-keysequence elements to refer to
     // indices in this table in order to emulate a physical keyboard with an
     // alternate layout.  Not all keys on a virtual keyboard are required to
-    // have keyCodes.
+    // have keyCodes. The shiftModifier specifies whether to always include or
+    // exclude the shift modifer when sending key events for this key. If it's
+    // undefined, it will defer to state of the keyboard.
     // TODO(rsadam): Correctly propagate shutdown keycode. This is currently
     // ignored due to chromoting (crbug/146609)
     var keyCodes = {
@@ -27,6 +40,10 @@
       '\n': {keyCode: 0x0D, shiftModifier: false},
       'Esc': {keyCode: 0x1B, shiftModifier: false},
       ' ': {keyCode: 0x20, shiftModifier: false},
+      'Arrow-Left': {keyCode: 0x25, shiftModifier: undefined},
+      'Arrow-Up': {keyCode: 0x26, shiftModifier: undefined},
+      'Arrow-Right': {keyCode: 0x27, shiftModifier: undefined},
+      'Arrow-Down': {keyCode: 0x28, shiftModifier: undefined},
       '0': {keyCode: 0x30, shiftModifier: false},
       ')': {keyCode: 0x30, shiftModifier: true},
       '1': {keyCode: 0x31, shiftModifier: false},
@@ -169,23 +186,33 @@
      createVirtualKeyEvent: function(detail, type) {
        var char = detail.char;
        var keyCode = detail.keyCode;
+       // The shift modifier is handled specially. Some charactares like '+'
+       // {keyCode: 0xBB, shiftModifier: true}, are available on non-upper
+       // keysets, and so we rely on caching the correct shiftModifier. If
+       // the cached value of the shiftModifier is undefined, we defer to
+       // the shiftModifier in the detail.
        var shiftModifier = detail.shiftModifier;
        if (keyCode == undefined) {
          var state = this.GetKeyCodeAndModifiers(char);
          if (state) {
            keyCode = state.keyCode;
-           shiftModifier = state.shiftModifier;
+           shiftModifier = (state.shiftModifier == undefined) ?
+               shiftModifier : state.shiftModifier;
          } else {
            // Keycode not defined.
            return;
          }
        }
-       // TODO(rsadam@): Add ctrl and alt modifiers to the message being sent.
+       var modifiers = Modifier.NONE;
+       modifiers = shiftModifier ? modifiers | Modifier.SHIFT : modifiers;
+       modifiers = detail.controlModifier ?
+           modifiers | Modifier.CONTROL : modifiers;
+       modifiers = detail.altModifier ? modifiers | Modifier.ALT : modifiers;
        return {
          type: type,
          charValue: char.charCodeAt(0),
          keyCode: keyCode,
-         shiftKey: shiftModifier
+         modifiers: modifiers
        };
      },
     });
diff --git a/ui/keyboard/resources/elements/kb-key.html b/ui/keyboard/resources/elements/kb-key.html
index bc1011a..6edac37 100644
--- a/ui/keyboard/resources/elements/kb-key.html
+++ b/ui/keyboard/resources/elements/kb-key.html
@@ -77,26 +77,39 @@
   </script>
 </polymer-element>
 
-<!--
-  -- TODO(kevers): Rip this out if and when we are done implementing the proper
-  -- layout switcher.
-  -->
-<polymer-element name="kb-layout-selector" class="layout-selector dark" char="Invalid"
-    extends="kb-key">
-  <script>
-    Polymer('kb-layout-selector', {
-      toLayout: 'qwerty'
-    });
-  </script>
-</polymer-element>
-
-<polymer-element name="kb-hide-keyboard-key" class="hide-keyboard dark" char="Invalid"
-    extends="kb-key">
+<polymer-element name="kb-hide-keyboard-key" class="hide-keyboard dark"
+    char="Invalid" extends="kb-key">
   <script>
     Polymer('kb-hide-keyboard-key', {
-      down: function(event) {},
+      /**
+       * Timer for a long press event which triggers the display of a keyboard
+       * options menu.
+       * @type {?Function}
+       */
+      longPressTimer: undefined,
+
+      down: function(event) {
+         var self = this;
+         this.longPressTimer = this.asyncMethod(function() {
+           if (self.longPressTimer) {
+             clearTimeout(self.longPressTimer);
+             self.longPressTimer = undefined;
+             var details = {
+               left: this.offsetLeft,
+               top: this.offsetTop,
+               width: this.clientWidth,
+             };
+             this.fire('show-options', details);
+           }
+         }, null, LONGPRESS_DELAY_MSEC);
+      },
+
       up: function(event) {
-        hideKeyboard();
+        if (this.longPressTimer) {
+          clearTimeout(this.longPressTimer);
+          hideKeyboard();
+          this.longPressTimer = undefined;
+        }
       }
     });
   </script>
diff --git a/ui/keyboard/resources/elements/kb-keyboard.html b/ui/keyboard/resources/elements/kb-keyboard.html
index 23d8227..c7a3988 100644
--- a/ui/keyboard/resources/elements/kb-keyboard.html
+++ b/ui/keyboard/resources/elements/kb-keyboard.html
@@ -7,8 +7,9 @@
 <polymer-element name="kb-keyboard" on-key-over="keyOver" on-key-up="keyUp"
     on-key-down="keyDown" on-key-longpress="keyLongpress" on-pointerup="up"
     on-pointerdown="down" on-enable-sel="enableSel"
-    on-enable-dbl="enableDbl"  on-key-out="keyOut"
-    attributes="keyset layout rows inputType inputTypeToLayoutMap">
+    on-enable-dbl="enableDbl"  on-key-out="keyOut" on-show-options="showOptions"
+    on-set-layout="setLayout"
+    attributes="keyset layout inputType inputTypeToLayoutMap">
   <template>
     <style>
       @host {
@@ -24,6 +25,7 @@
       -- keyboard layouts.
       -->
     <content select="#{{layout}}-{{keyset}}"></content>
+    <kb-keyboard-overlay id="overlay" hidden></kb-keyboard-overlay>
     <kb-key-codes id="keyCodeMetadata"></kb-key-codes>
   </template>
   <script>
@@ -114,17 +116,7 @@
      * @const
      * @type {number}
      */
-    var MIN_SWIPE_DIST = 30;
-
-    /**
-     * The flags constants when shift is on. It is according to the EventFlags
-     * in event_constants.h in chromium c++ code.
-     * @const
-     * @type {number}
-     * TODO(zyaozhujun): Might add more flags here according to the defination
-     * in EventFlags.
-     */
-    var SHIFT = 2;
+    var MIN_SWIPE_DIST = 60;
 
     /**
      * The boolean to decide if it is swipe in process or finished.
@@ -140,6 +132,16 @@
      */
     var isReady = false;
 
+    // Flag values for ctrl, alt and shift as defined by EventFlags
+    // in "event_constants.h".
+    // @enum {number}
+    var Modifier = {
+      NONE: 0,
+      ALT: 8,
+      CONTROL: 4,
+      SHIFT: 2
+    };
+
     /**
      * The enumeration of swipe directions.
      * @const
@@ -184,6 +186,12 @@
       swipeDirection : 0,
 
       /**
+       * The number of times we've swiped within a single swipe.
+       * @type {number}
+       */
+      swipeIndex: 0,
+
+      /**
        * Reset all the values when swipe finished.
        */
       resetAll: function() {
@@ -193,6 +201,7 @@
         this.pre_y = 0;
         this.swipeFlags = 0;
         this.swipeDirection = 0;
+        this.swipeIndex = 0;
       }
     };
 
@@ -215,7 +224,7 @@
       inputTypeToLayoutMap: {
         number: "numeric",
         text: "qwerty",
-        password: "system-qwerty"
+        password: "qwerty"
       },
 
       /**
@@ -286,43 +295,43 @@
         if (!event.isPrimary)
           return;
         swipeStatus.offset_x += event.screenX - swipeStatus.pre_x;
-        swipeStatus.offset_y += event.screenY - swipeStatus.pre_y;
-        // Inflates the initial minimal swipe distance that triggers swipe
-        // gesture. It can reduce the accidental cursor movements during fast
-        // typing. After entered swipe gesture mode, the minimal swipe distance
-        // is set to a smaller distance to allow for more responsive cursor
-        // movement.
-        var minSwipeDist =
-            swipeInProgress ? MIN_SWIPE_DIST : 2 * MIN_SWIPE_DIST;
-        if (Math.abs(swipeStatus.offset_x) > minSwipeDist ||
-            Math.abs(swipeStatus.offset_y) > minSwipeDist) {
+        // swipeStatus.offset_y += event.screenY - swipeStatus.pre_y;
+        if (Math.abs(swipeStatus.offset_x) > MIN_SWIPE_DIST ||
+            Math.abs(swipeStatus.offset_y) > MIN_SWIPE_DIST) {
           swipeInProgress = true;
           if (this.lastPressedKey) {
             this.lastPressedKey.classList.remove('active');
             this.lastPressedKey = null;
           }
         }
-        if (swipeStatus.offset_x > minSwipeDist) {
+        if (swipeStatus.offset_x > MIN_SWIPE_DIST) {
           swipeStatus.swipeDirection |= SWIPE_DIRECTION.RIGHT;
+          swipeStatus.swipeIndex++;
           swipeStatus.offset_x = 0;
-        } else if (swipeStatus.offset_x < -minSwipeDist) {
+        } else if (swipeStatus.offset_x < -MIN_SWIPE_DIST) {
           swipeStatus.swipeDirection |= SWIPE_DIRECTION.LEFT;
+          swipeStatus.swipeIndex--;
           swipeStatus.offset_x = 0;
         }
         // Swipe vertically only when the swipe reaches the gradient of 45
         // degree. This can also be larger.
         if (Math.abs(event.screenY - swipeStatus.pre_y) >
             Math.abs(event.screenX - swipeStatus.pre_x)) {
-          if (swipeStatus.offset_y > minSwipeDist) {
+          if (swipeStatus.offset_y > MIN_SWIPE_DIST) {
             swipeStatus.swipeDirection |= SWIPE_DIRECTION.DOWN;
             swipeStatus.offset_y = 0;
-          } else if (swipeStatus.offset_y < -minSwipeDist) {
+          } else if (swipeStatus.offset_y < -MIN_SWIPE_DIST) {
             swipeStatus.swipeDirection |= SWIPE_DIRECTION.UP;
             swipeStatus.offset_y = 0;
           }
         }
         if (swipeStatus.swipeDirection) {
-          MoveCursor(swipeStatus.swipeDirection, swipeStatus.swipeFlags);
+          var modifiers = 0;
+          if (swipeStatus.swipeIndex % 2 != 0) {
+            modifiers |= Modifier.SHIFT;
+            modifiers |= Modifier.CONTROL;
+          }
+          MoveCursor(swipeStatus.swipeDirection, modifiers);
           swipeStatus.swipeDirection = 0;
         }
         swipeStatus.pre_x = event.screenX;
@@ -350,6 +359,8 @@
         var char = detail.char;
         switch(char) {
           case 'Shift':
+            this.classList.remove('caps-locked');
+            break;
           case 'Alt':
           case 'Ctrl':
             var modifier = char.toLowerCase() + "-active";
@@ -361,12 +372,17 @@
             // Notify shift key.
             if (this.shift)
               this.shift.onNonControlKeyDown();
+            if (this.ctrl)
+              this.ctrl.onNonControlKeyDown();
+            if (this.alt)
+              this.alt.onNonControlKeyDown();
             break;
         }
         if(this.changeKeyset(detail))
           return;
         if (detail.repeat) {
           this.keyTyped(detail);
+          this.onNonControlKeyTyped();
           repeatKey.key = this.lastPressedKey;
           var self = this;
           repeatKey.timer = setTimeout(function() {
@@ -412,7 +428,8 @@
        *    kb-shift-key.
        */
       enableSel: function(event) {
-        swipeStatus.swipeFlags = SHIFT;
+        // TODO(rsadam): Disabled for now. May come back if we revert swipe
+        // selection to not do word selection.
       },
 
       /**
@@ -523,6 +540,7 @@
             }
           }
         }
+        this.lastPressedKey = null;
         switch(char) {
           case 'Invalid':
           case 'Shift':
@@ -543,13 +561,7 @@
         }
         if(!this.keyTyped(detail))
           insertText(char);
-        if (this.ctrl)
-          this.ctrl.onNonControlKeyUp();
-        if (this.alt)
-          this.alt.onNonControlKeyUp();
-        this.classList.remove('ctrl-active');
-        this.classList.remove('alt-active');
-        this.lastPressedKey = null;
+        this.onNonControlKeyTyped();
       },
 
       /*
@@ -573,6 +585,41 @@
       },
 
       /**
+       * Show menu for selecting a keyboard layout.
+       * @param {!Event} event The triggering event.
+       * @param {{left: number, top: number, width: number}} details Location of
+       *     the button that triggered the popup.
+       */
+      showOptions: function(event, details) {
+        var overlay = this.$.overlay;
+        if (!overlay) {
+          console.error('Missing overlay.');
+          return;
+        }
+        var menu = overlay.$.options;
+        if (!menu) {
+           console.error('Missing options menu.');
+        }
+
+        menu.hidden = false;
+        overlay.hidden = false;
+        var left = details.left + details.width - menu.clientWidth;
+        var top = details.top - menu.clientHeight;
+        menu.style.left = left + 'px';
+        menu.style.top = top + 'px';
+      },
+
+      /**
+       * Handler for the 'set-layout' event.
+       * @param {!Event} event The triggering event.
+       * @param {{layout: string}} details Details of the event, which contains
+       *     the name of the layout to activate.
+       */
+      setLayout: function(event, details) {
+        this.layout = details.layout;
+      },
+
+      /**
        * Handles a change in the keyboard layout. Auto-selects the default
        * keyset for the new layout.
        */
@@ -610,6 +657,22 @@
       },
 
       /**
+       * Notifies the modifier keys that a non-control key was typed. This
+       * lets them reset sticky behaviour. A non-control key is defined as
+       * any key that is not Control, Alt, or Shift.
+       */
+      onNonControlKeyTyped: function() {
+        if (this.shift)
+          this.shift.onNonControlKeyTyped();
+        if (this.ctrl)
+          this.ctrl.onNonControlKeyTyped();
+        if (this.alt)
+          this.alt.onNonControlKeyTyped();
+        this.classList.remove('ctrl-active');
+        this.classList.remove('alt-active');
+      },
+
+      /**
        * Indicate if the keyboard is ready for user input.
        * @type {boolean}
        */
@@ -661,6 +724,8 @@
        */
       keyTyped: function(detail) {
         var builder = this.$.keyCodeMetadata;
+        if (this.shift)
+          detail.shiftModifier = this.shift.isActive();
         if (this.ctrl)
           detail.controlModifier = this.ctrl.isActive();
         if (this.alt)
@@ -710,6 +775,7 @@
                  state: 'keysetLoaded',
                  keyset: this.keyset,
                });
+               keyboardLoaded();
                return true;
              }
           }
diff --git a/ui/keyboard/resources/elements/kb-keyset.html b/ui/keyboard/resources/elements/kb-keyset.html
index d5e35e2..933e7ba 100644
--- a/ui/keyboard/resources/elements/kb-keyset.html
+++ b/ui/keyboard/resources/elements/kb-keyset.html
@@ -4,9 +4,8 @@
   -- found in the LICENSE file.
   -->
 
-<polymer-element name="kb-keyset" attributes="nextKeyset isDefault
-    capsLocksTo capsLockable" on-key-up="keyUp"
-    on-key-longpress="keyLongpress">
+<polymer-element name="kb-keyset" attributes="nextKeyset isDefault"
+    on-key-up="keyUp" on-key-longpress="keyLongpress">
   <template>
     <style>
       @host {
@@ -28,6 +27,14 @@
       nextKeyset: undefined,
       // TODO(bshe): support select keyset on down, long and dbl events.
       keyUp: function(event, detail) {
+        switch (detail.char) {
+          case 'Shift':
+          case 'Alt':
+          case 'Ctrl':
+            return;
+          default:
+            break;
+        }
         if (!detail.toKeyset)
           detail.toKeyset = this.nextKeyset;
       },
diff --git a/ui/keyboard/resources/elements/kb-modifier-key.html b/ui/keyboard/resources/elements/kb-modifier-key.html
index e3c2ca1..572ae15 100644
--- a/ui/keyboard/resources/elements/kb-modifier-key.html
+++ b/ui/keyboard/resources/elements/kb-modifier-key.html
@@ -4,7 +4,8 @@
   -- found in the LICENSE file.
   -->
 
-<polymer-element name="kb-modifier-key" class="unlocked dark" extends="kb-key">
+<polymer-element name="kb-modifier-key" class="unlocked dark" extends="kb-key"
+    on-pointerout="out">
   <script>
     (function () {
 
@@ -17,6 +18,7 @@
         PRESSED: "pressed", // Key-down.
         UNLOCKED: "unlocked", // Default state.
         TAPPED: "tapped", // Key-down followed by key-up.
+        CHORDING: "chording", // Chording mode.
       };
 
       /**
@@ -37,7 +39,7 @@
         down: function(event) {
           // First transition state so that populateDetails generates
           // correct data.
-          switch(this.state) {
+          switch (this.state) {
             case KEY_STATES.UNLOCKED:
               this.state = KEY_STATES.PRESSED;
               break;
@@ -45,6 +47,7 @@
               this.state = KEY_STATES.UNLOCKED;
               break;
             case KEY_STATES.PRESSED:
+            case KEY_STATES.CHORDING:
               // We pressed another key at the same time,
               // so ignore second press.
               return;
@@ -64,10 +67,22 @@
         },
 
         /**
-         * Notifies key that a non-control keyed up.
+         * Notifies key that a non-control keyed down.
          * A control key is defined as one of shift, control or alt.
          */
-        onNonControlKeyUp: function() {
+        onNonControlKeyDown: function() {
+          switch(this.state) {
+            case (KEY_STATES.PRESSED):
+              this.state = KEY_STATES.CHORDING;
+              break;
+          }
+        },
+
+        /**
+         * Notifies key that a non-control keyed was typed.
+         * A control key is defined as one of shift, control or alt.
+         */
+        onNonControlKeyTyped: function() {
            switch(this.state) {
              case (KEY_STATES.TAPPED):
                this.state = KEY_STATES.UNLOCKED;
@@ -75,6 +90,24 @@
            }
         },
 
+        /**
+         * Called on a pointer-out event. Ends chording.
+         * @param {event} event The pointer-out event.
+         */
+        out: function(event) {
+          // TODO(rsadam): Add chording event so that we don't reset
+          // when shift-chording.
+          if (this.state == KEY_STATES.CHORDING) {
+            this.state = KEY_STATES.UNLOCKED;
+          }
+        },
+
+        /*
+         * Overrides the autoRelease function to enable chording.
+         */
+        autoRelease: function() {
+        },
+
         populateDetails: function(caller) {
           var detail = this.super([caller]);
           if (this.state != KEY_STATES.UNLOCKED)
diff --git a/ui/keyboard/resources/elements/kb-options-menu.html b/ui/keyboard/resources/elements/kb-options-menu.html
new file mode 100644
index 0000000..f33bd3c
--- /dev/null
+++ b/ui/keyboard/resources/elements/kb-options-menu.html
@@ -0,0 +1,111 @@
+<!--
+  -- Copyright 2013 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.
+  -->
+
+<polymer-element name="kb-options-menu-item" attributes="layout label active"
+    on-pointerup="up" on-pointerover="over" on-pointerout="out">
+  <template>
+    <style>
+      @host {
+        * {
+          -webkit-padding-end: 5px;
+          -webkit-padding-start: 5px;
+          color: #fff;
+          display: -webkit-box;
+          font-family: 'Open Sans', 'Noto Sans UI', sans-serif;
+          font-weight: 300;
+          height: 28px;
+        }
+        *.active {
+          background-color: #848490;
+        }
+    </style>
+    <span>{{label}}</span>
+  </template>
+  <script>
+    Polymer('kb-options-menu-item', {
+      /**
+       * Layout to select on a key press.
+       */
+      layout: null,
+
+      up: function(event) {
+        if (this.layout == 'none') 
+          hideKeyboard();
+        else
+          this.fire('set-layout', {layout: this.layout});
+        this.hidden = true;
+      },
+
+      over: function(event) {
+        this.classList.add('active');
+      },
+
+      out: function(event) {
+        this.classList.remove('active');
+      },
+    });
+  </script>
+</polymer>
+
+<polymer-element name="kb-options-menu">
+  <template>
+    <style>
+      @host {
+        * {
+          -webkit-box-orient: vertical;
+          background-color: #3b3b3e;
+          border-radius: 2px;
+          display: -webkit-box;
+          left: 0;
+          position: absolute;
+          top: 0;
+          z-index: 1;
+        }
+      }
+    </style>
+    <!-- TODO(kevers): This is a temporary placeholder to enable testing
+      -- of layout switching.  Deprecate once a decision is reached on
+      -- a more permanent solution for layout selection. -->
+    <kb-options-menu-item layout="system-qwerty" label="System QWERTY">
+    </kb-options-menu-item>
+    <kb-options-menu-item layout="qwerty" label="QWERTY">
+    </kb-options-menu-item>
+    <kb-options-menu-item layout="dvorak" label="Dvorak">
+    </kb-options-menu-item>
+    <kb-options-menu-item layout="none" label="Hide keyboard">
+    </kb-options-menu-item>
+  </template>
+  <script>
+    Polymer('kb-options-menu', {});
+   </script>
+</polymer>
+
+<polymer-element name="kb-keyboard-overlay" attributes="keyset"
+    on-pointerup="up">
+  <template>
+    <style>
+      @host {
+        * {
+          background-color: rgba(0, 0, 0, 0.6);
+          bottom: 0;
+          left: 0;
+          position: absolute;
+          right: 0;
+          top: 0;
+        }
+      }
+    </style>
+    <!-- Insert popups here. -->
+    <kb-options-menu id="options" hidden></kb-options-menu>
+  </template>
+  <script>
+    Polymer('kb-keyboard-overlay', {
+      up: function() {
+        this.hidden = true;
+      }
+    });
+  </script>
+</polymer-element>
diff --git a/ui/keyboard/resources/elements/kb-shift-key.html b/ui/keyboard/resources/elements/kb-shift-key.html
index b2dac6b..12f568c 100644
--- a/ui/keyboard/resources/elements/kb-shift-key.html
+++ b/ui/keyboard/resources/elements/kb-shift-key.html
@@ -144,6 +144,11 @@
           }, null, LONGPRESS_DELAY_MSEC);
         },
 
+        // @return Whether the shift modifier is currently active.
+        isActive: function() {
+          return state != KEY_STATES.UNLOCKED;
+        },
+
         /**
          * Callback function for when a double click is triggered.
          */
@@ -156,19 +161,25 @@
          * A control key is defined as one of shift, control or alt.
          */
         onNonControlKeyDown: function() {
-           switch (state) {
-             case (KEY_STATES.TAPPED):
-               state = KEY_STATES.UNLOCKED;
-               break;
-             case (KEY_STATES.PRESSED):
-               state = KEY_STATES.CHORDING;
-               // Disable longpress timer.
-               clearTimeout(shiftLongPressTimer);
-               break;
-             default:
-               break;
-           }
-         },
+          switch (state) {
+            case (KEY_STATES.PRESSED):
+              state = KEY_STATES.CHORDING;
+              // Disable longpress timer.
+              clearTimeout(shiftLongPressTimer);
+              break;
+            default:
+              break;
+          }
+        },
+
+        /**
+         * Notifies key that a non-control keyed was typed.
+         * A control key is defined as one of shift, control or alt.
+         */
+        onNonControlKeyTyped: function() {
+          if (state == KEY_STATES.TAPPED)
+            state = KEY_STATES.UNLOCKED;
+        },
 
         /**
          * Callback function for when a space is pressed after punctuation.
diff --git a/ui/keyboard/resources/index.html b/ui/keyboard/resources/index.html
index 08a2b69..c4890d8 100644
--- a/ui/keyboard/resources/index.html
+++ b/ui/keyboard/resources/index.html
@@ -33,6 +33,7 @@
     <link rel="import" href="elements/kb-shift-key.html">
     <link rel="import" href="elements/kb-key-sequence.html">
     <link rel="import" href="elements/kb-key-import.html">
+    <link rel="import" href="elements/kb-options-menu.html">
     <!-- New layouts are dynamically loaded on demand. The link elements are
       -- inserted here.
       -->
diff --git a/ui/keyboard/resources/layouts/dvorak.html b/ui/keyboard/resources/layouts/dvorak.html
index 7d93577..6da7862 100644
--- a/ui/keyboard/resources/layouts/dvorak.html
+++ b/ui/keyboard/resources/layouts/dvorak.html
@@ -10,8 +10,10 @@
   <kb-keyset id="dvorak-upper">
     <kb-row>
       <kb-key class="tab dark" char="&#x0009;" align="left">tab</kb-key>
-      <kb-key-sequence keys="&quot;,.PYFGCRL" hintTexts="1234567890"></kb-key-sequence>
-      <kb-key class="backspace dark" char="&#x0008;" repeat align="right">backspace</kb-key>
+      <kb-key-sequence keys="&quot;,.PYFGCRL" hintTexts="1234567890">
+       </kb-key-sequence>
+      <kb-key class="backspace dark" char="&#x0008;" repeat
+          align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
       <kb-key class="microphone dark" char="Microphone"></kb-key>
@@ -24,10 +26,12 @@
       <kb-shift-key weight="1.8" align="right">shift</kb-shift-key>
     </kb-row>
     <kb-row>
-      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid" align="left">#123</kb-key>
+      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
+          align="left">#123</kb-key>
       <kb-key-import importId="spacebar-row"></kb-key-import>
-      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid" align="right">#123</kb-key>
-      <kb-layout-selector></kb-layout-selector>
+      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
+          align="right">#123</kb-key>
+      <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
     <kb-altkey-container hidden>
     </kb-altkey-container>
@@ -36,8 +40,10 @@
   <kb-keyset id="dvorak-lower" isDefault=true>
     <kb-row>
       <kb-key class="tab dark" char="&#x0009;" align="left">tab</kb-key>
-      <kb-key-sequence keys="&quot;,.pyfgcrl" hintTexts="1234567890"></kb-key-sequence>
-      <kb-key class="backspace dark" char="&#x0008;" repeat align="right">backspace</kb-key>
+      <kb-key-sequence keys="&quot;,.pyfgcrl" hintTexts="1234567890">
+      </kb-key-sequence>
+      <kb-key class="backspace dark" char="&#x0008;" repeat
+          align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
       <kb-key class="microphone dark" char="Microphone"></kb-key>
@@ -50,10 +56,12 @@
       <kb-shift-key weight="1.8" align="right">shift</kb-shift-key>
     </kb-row>
     <kb-row>
-      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid" align="left">#123</kb-key>
+      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
+          align="left">#123</kb-key>
       <kb-key-import importId="spacebar-row"></kb-key-import>
-      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid" align="right">#123</kb-key>
-      <kb-layout-selector></kb-layout-selector>
+      <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
+          align="right">#123</kb-key>
+      <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
     <kb-altkey-container hidden>
     </kb-altkey-container>
@@ -63,7 +71,8 @@
     <kb-row>
       <kb-key class="tab dark" char="&#x0009;" align="left">tab</kb-key>
       <kb-key-sequence keys="1234567890"></kb-key-sequence>
-      <kb-key class="backspace dark" char="&#x0008;" repeat align="right">backspace</kb-key>
+      <kb-key class="backspace dark" char="&#x0008;" repeat
+          align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
       <kb-key class="microphone dark" char="Microphone"></kb-key>
@@ -71,15 +80,17 @@
       <kb-key class='return dark' char="&#x000A;" align="right">enter</kb-key>
     </kb-row>
     <kb-row>
-      <kb-key class="left-more dark" toKeyset="down:more" char="Invalid" align="left">more</kb-key>
+      <kb-key class="left-more dark" toKeyset="down:more" char="Invalid"
+          align="left">more</kb-key>
       <kb-key-sequence keys="!&quot;':;/?"></kb-key-sequence>
-      <kb-key class="right-more dark" toKeyset="down:more" char="Invalid" align="right">more</kb-key>
+      <kb-key class="right-more dark" toKeyset="down:more" char="Invalid"
+          align="right">more</kb-key>
     </kb-row>
     <kb-row>
       <kb-abc-key align="left">abc</kb-abc-key>
       <kb-key-import importId="spacebar-row"></kb-key-import>
       <kb-abc-key align="right">abc</kb-abc-key>
-      <kb-layout-selector></kb-layout-selector>
+      <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
     <kb-altkey-container hidden>
     </kb-altkey-container>
@@ -91,27 +102,30 @@
       <kb-key>~</kb-key><kb-key>`</kb-key><kb-key>|</kb-key><kb-key>^</kb-key>
       <kb-key>+</kb-key><kb-key>=</kb-key><kb-key>{</kb-key><kb-key>}</kb-key>
       <kb-key>&#x003C;</kb-key><kb-key>&#x003E;</kb-key>
-      <kb-key class="backspace dark" char="&#x0008;" repeat align="right">backspace</kb-key>
+      <kb-key class="backspace dark" char="&#x0008;" repeat
+          align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
       <kb-key class="microphone dark" char="Microphone"></kb-key>
-      <kb-key>&#x00A3</kb-key><kb-key>&#x00A2</kb-key><kb-key>&#x20AC</kb-key><kb-key>&#x2122</kb-key>
-      <kb-key>&#x00A9</kb-key><kb-key>&#x00AE</kb-key><kb-key>\</kb-key><kb-key>[</kb-key>
-      <kb-key>]</kb-key>
+      <kb-key>&#x00A3</kb-key><kb-key>&#x00A2</kb-key><kb-key>&#x20AC</kb-key>
+      <kb-key>&#x2122</kb-key><kb-key>&#x00A9</kb-key><kb-key>&#x00AE</kb-key>
+      <kb-key>\</kb-key><kb-key>[</kb-key><kb-key>]</kb-key>
       <kb-key class='return dark' char="&#x000A;" align="right">enter</kb-key>
     </kb-row>
     <kb-row>
-      <kb-key class="left-more dark" toKeyset="down:symbol" char="Invalid" align="left">#123</kb-key>
-      <kb-key>&#x00D7</kb-key><kb-key>&#x00F7</kb-key><kb-key>_</kb-key><kb-key>&#x00A7</kb-key>
-      <kb-key>&#x00B6</kb-key><kb-key>&#x00A1</kb-key><kb-key>&#x00BF</kb-key><kb-key>&#x2022</kb-key>
-      <kb-key>&#x0394</kb-key>
-      <kb-key class="right-more dark" toKeyset="down:symbol" char="Invalid" align="right">#123</kb-key>
+      <kb-key class="left-more dark" toKeyset="down:symbol" char="Invalid"
+          align="left">#123</kb-key>
+      <kb-key>&#x00D7</kb-key><kb-key>&#x00F7</kb-key><kb-key>_</kb-key>
+      <kb-key>&#x00A7</kb-key><kb-key>&#x00B6</kb-key><kb-key>&#x00A1</kb-key>
+      <kb-key>&#x00BF</kb-key><kb-key>&#x2022</kb-key><kb-key>&#x0394</kb-key>
+      <kb-key class="right-more dark" toKeyset="down:symbol" char="Invalid"
+          align="right">#123</kb-key>
     </kb-row>
     <kb-row>
       <kb-abc-key align="left">abc</kb-abc-key>
       <kb-key-import importId="spacebar-row"></kb-key-import>
       <kb-abc-key align="right">abc</kb-abc-key>
-      <kb-layout-selector></kb-layout-selector>
+      <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
   </kb-keyset>
 </template>
diff --git a/ui/keyboard/resources/layouts/function-key-row.html b/ui/keyboard/resources/layouts/function-key-row.html
index 581f1e7..6c89359 100644
--- a/ui/keyboard/resources/layouts/function-key-row.html
+++ b/ui/keyboard/resources/layouts/function-key-row.html
@@ -16,5 +16,4 @@
   <kb-key class="mute dark" char="Mute"></kb-key> 
   <kb-key class="volume-down dark" repeat char="Volume-Down"></kb-key>
   <kb-key class="volume-up dark" repeat char="Volume-Up"></kb-key>
-  <kb-key class="shutdown dark" char="Shutdown"></kb-key>
 </template>
diff --git a/ui/keyboard/resources/layouts/system-qwerty.html b/ui/keyboard/resources/layouts/system-qwerty.html
index 2b85748..6c25a2c 100644
--- a/ui/keyboard/resources/layouts/system-qwerty.html
+++ b/ui/keyboard/resources/layouts/system-qwerty.html
@@ -15,7 +15,7 @@
     <kb-row>
       <kb-key-sequence invert=true keys="'1234567890-="
           hintTexts="~!@#$%^&*()_+"> </kb-key-sequence>
-      <kb-key class="backspace dark" char="&#x0008;"
+      <kb-key class="backspace dark" weight="2.6" char="&#x0008;"
           repeat align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
@@ -38,15 +38,15 @@
       <kb-shift-key weight="1.8" align="right">shift</kb-shift-key>
     </kb-row>
     <kb-row>
-      <kb-modifier-key class="symbol dark" char="Ctrl"
+      <kb-modifier-key class="symbol dark" weight="2.0" char="Ctrl"
           align="left">ctrl</kb-modifier-key>
-      <kb-modifier-key class="symbol dark" char="Alt"
+      <kb-modifier-key class="symbol dark" weight="2.0" char="Alt"
           align="left">alt</kb-modifier-key>
-      <kb-key char=" " class="space dark" weight="6.0"></kb-key>
-      <kb-modifier-key class="symbol dark" char="Alt"
-          align="right">alt</kb-modifier-key>
-      <kb-modifier-key class="symbol dark" char="Ctrl"
-          align="right">ctrl</kb-modifier-key>
+      <kb-key char=" " class="space dark" weight="10.0"></kb-key>
+      <kb-key class="arrow-left dark" repeat char="Arrow-Left"></kb-key>
+      <kb-key class="arrow-up dark" repeat char="Arrow-Up"></kb-key>
+      <kb-key class="arrow-down dark" repeat char="Arrow-Down"></kb-key>
+      <kb-key class="arrow-right dark" repeat char="Arrow-Right"></kb-key>
       <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
     <kb-altkey-container hidden>
@@ -60,7 +60,7 @@
     <kb-row>
       <kb-key-sequence keys="'1234567890-=" hintTexts="~!@#$%^&*()_+">
       </kb-key-sequence>
-      <kb-key class="backspace dark" char="&#x0008;"
+      <kb-key class="backspace dark" weight="2.6" char="&#x0008;"
           repeat align="right">backspace</kb-key>
     </kb-row>
     <kb-row>
@@ -81,15 +81,15 @@
       <kb-shift-key weight="1.8" align="right">shift</kb-shift-key>
     </kb-row>
     <kb-row>
-      <kb-modifier-key class="symbol dark" char="Ctrl"
+      <kb-modifier-key class="symbol dark" weight="2.0" char="Ctrl"
           align="left">ctrl</kb-modifier-key>
-      <kb-modifier-key class="symbol dark" char="Alt"
+      <kb-modifier-key class="symbol dark" weight="2.0" char="Alt"
           align="left">alt</kb-modifier-key>
-      <kb-key char=" " class="space dark" weight="6.0"></kb-key>
-      <kb-modifier-key class="symbol dark" char="Alt"
-          align="right">alt</kb-modifier-key>
-      <kb-modifier-key class="symbol dark" char="Ctrl"
-          align="right">ctrl</kb-modifier-key>
+      <kb-key char=" " class="space dark" weight="10.0"></kb-key>
+      <kb-key class="arrow-left dark" repeat char="Arrow-Left"></kb-key>
+      <kb-key class="arrow-up dark" repeat char="Arrow-Up"></kb-key>
+      <kb-key class="arrow-down dark" repeat char="Arrow-Down"></kb-key>
+      <kb-key class="arrow-right dark" repeat char="Arrow-Right"></kb-key>
       <kb-hide-keyboard-key></kb-hide-keyboard-key>
     </kb-row>
     <kb-altkey-container hidden>
diff --git a/ui/keyboard/resources/main.css b/ui/keyboard/resources/main.css
index ddca809..6ab675d 100644
--- a/ui/keyboard/resources/main.css
+++ b/ui/keyboard/resources/main.css
@@ -173,6 +173,22 @@
 /**
  * Images for keys.
  */
+.arrow-down {
+ background-image: url('images/down.svg');
+}
+
+.arrow-left {
+ background-image: url('images/left.svg');
+}
+
+.arrow-right {
+ background-image: url('images/right.svg');
+}
+
+.arrow-up {
+ background-image: url('images/up.svg');
+}
+
 .back {
   background-image: url('images/back.svg');
 }
diff --git a/ui/keyboard/resources/webui/api_adapter.js b/ui/keyboard/resources/webui/api_adapter.js
index 415a042..206f60d 100644
--- a/ui/keyboard/resources/webui/api_adapter.js
+++ b/ui/keyboard/resources/webui/api_adapter.js
@@ -14,6 +14,10 @@
   chrome.send('hideKeyboard');
 }
 
+function keyboardLoaded() {
+  chrome.send('keyboardLoaded');
+}
+
 (function(exports) {
   /**
    * An array to save callbacks of each request.
diff --git a/ui/keycode_converter.target.darwin-arm.mk b/ui/keycode_converter.target.darwin-arm.mk
index 11d242b..f32be04 100644
--- a/ui/keycode_converter.target.darwin-arm.mk
+++ b/ui/keycode_converter.target.darwin-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keycode_converter.target.darwin-mips.mk b/ui/keycode_converter.target.darwin-mips.mk
index c1629fe..d39fa22 100644
--- a/ui/keycode_converter.target.darwin-mips.mk
+++ b/ui/keycode_converter.target.darwin-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keycode_converter.target.darwin-x86.mk b/ui/keycode_converter.target.darwin-x86.mk
index 8686cc0..4d486ea 100644
--- a/ui/keycode_converter.target.darwin-x86.mk
+++ b/ui/keycode_converter.target.darwin-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keycode_converter.target.linux-arm.mk b/ui/keycode_converter.target.linux-arm.mk
index 11d242b..f32be04 100644
--- a/ui/keycode_converter.target.linux-arm.mk
+++ b/ui/keycode_converter.target.linux-arm.mk
@@ -63,13 +63,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -143,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keycode_converter.target.linux-mips.mk b/ui/keycode_converter.target.linux-mips.mk
index c1629fe..d39fa22 100644
--- a/ui/keycode_converter.target.linux-mips.mk
+++ b/ui/keycode_converter.target.linux-mips.mk
@@ -62,13 +62,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -141,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/keycode_converter.target.linux-x86.mk b/ui/keycode_converter.target.linux-x86.mk
index 8686cc0..4d486ea 100644
--- a/ui/keycode_converter.target.linux-x86.mk
+++ b/ui/keycode_converter.target.linux-x86.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,13 +148,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/message_center/message_center.gyp b/ui/message_center/message_center.gyp
index 0d96cb2..e8ceb78 100644
--- a/ui/message_center/message_center.gyp
+++ b/ui/message_center/message_center.gyp
@@ -164,11 +164,11 @@
         '../../base/base.gyp:test_support_base',
         '../../skia/skia.gyp:skia',
         '../../testing/gtest.gyp:gtest',
+        '../../url/url.gyp:url_lib',
         '../events/events.gyp:events',
         '../gfx/gfx.gyp:gfx',
-        '../ui.gyp:run_ui_unittests',
         '../ui.gyp:ui',
-        '../../url/url.gyp:url_lib',
+        '../ui_unittests.gyp:run_ui_unittests',
         'message_center',
         'message_center_test_support',
       ],
@@ -188,7 +188,7 @@
       'conditions': [
         ['OS=="mac"', {
           'dependencies': [
-            '../ui.gyp:ui_test_support',
+            '../ui_unittests.gyp:ui_test_support',
           ],
         }],
         ['toolkit_views==1', {
diff --git a/ui/message_center/views/notifier_settings_view.cc b/ui/message_center/views/notifier_settings_view.cc
index 4098274..63e72a4 100644
--- a/ui/message_center/views/notifier_settings_view.cc
+++ b/ui/message_center/views/notifier_settings_view.cc
@@ -418,15 +418,10 @@
       0, kMenuButtonInnateMargin, 0, kMenuButtonInnateMargin));
   contents_title_view->AddChildView(top_label);
 
-  string16 notifier_group_text;
-  if (provider_ && provider_->GetNotifierGroupCount() > 0) {
-    const NotifierGroup& active_group = provider_->GetActiveNotifierGroup();
-    notifier_group_text = active_group.login_info.empty()
-                              ? active_group.name
-                              : active_group.login_info;
-  }
-
   if (need_account_switcher) {
+    const NotifierGroup& active_group = provider_->GetActiveNotifierGroup();
+    string16 notifier_group_text = active_group.login_info.empty() ?
+        active_group.name : active_group.login_info;
     notifier_group_selector_ =
         new views::MenuButton(NULL, notifier_group_text, this, true);
     notifier_group_selector_->set_border(new NotifierGroupMenuButtonBorder);
diff --git a/ui/native_theme/native_theme.target.darwin-arm.mk b/ui/native_theme/native_theme.target.darwin-arm.mk
index 687b5d1..3007230 100644
--- a/ui/native_theme/native_theme.target.darwin-arm.mk
+++ b/ui/native_theme/native_theme.target.darwin-arm.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/native_theme/native_theme.target.darwin-mips.mk b/ui/native_theme/native_theme.target.darwin-mips.mk
index 9272b5e..c9ef67a 100644
--- a/ui/native_theme/native_theme.target.darwin-mips.mk
+++ b/ui/native_theme/native_theme.target.darwin-mips.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/native_theme/native_theme.target.darwin-x86.mk b/ui/native_theme/native_theme.target.darwin-x86.mk
index 1879640..ea3b82b 100644
--- a/ui/native_theme/native_theme.target.darwin-x86.mk
+++ b/ui/native_theme/native_theme.target.darwin-x86.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/native_theme/native_theme.target.linux-arm.mk b/ui/native_theme/native_theme.target.linux-arm.mk
index 687b5d1..3007230 100644
--- a/ui/native_theme/native_theme.target.linux-arm.mk
+++ b/ui/native_theme/native_theme.target.linux-arm.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -178,13 +178,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/native_theme/native_theme.target.linux-mips.mk b/ui/native_theme/native_theme.target.linux-mips.mk
index 9272b5e..c9ef67a 100644
--- a/ui/native_theme/native_theme.target.linux-mips.mk
+++ b/ui/native_theme/native_theme.target.linux-mips.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -176,13 +176,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/native_theme/native_theme.target.linux-x86.mk b/ui/native_theme/native_theme.target.linux-x86.mk
index 1879640..ea3b82b 100644
--- a/ui/native_theme/native_theme.target.linux-x86.mk
+++ b/ui/native_theme/native_theme.target.linux-x86.mk
@@ -73,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -182,13 +182,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 67b913b..dee0e0d 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -6,9 +6,6 @@
     </output>
     <output filename="grit/ui_resources_map.cc" type="resource_map_source" context="default_100_percent" />
     <output filename="grit/ui_resources_map.h" type="resource_map_header" context="default_100_percent" />
-    <!-- TODO(oshima): Remove gfx_resources.pak once DumpRenderTree.gyp
-         is updated. -->
-    <output filename="gfx_resources.pak" type="data_package" context="default_100_percent" />
     <output filename="ui_resources_100_percent.pak" type="data_package" context="default_100_percent" />
     <output filename="ui_resources_200_percent.pak" type="data_package" context="default_200_percent" />
     <output filename="ui_resources_touch_100_percent.pak" type="data_package" context="touch_100_percent" />
@@ -28,6 +25,7 @@
         <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_HOVER" file="common/app_list_tools_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_NORMAL" file="common/app_list_tools_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_PRESSED" file="common/app_list_tools_pressed.png" />
+        <structure type="chrome_scaled_image" name="IDR_APP_LIST_FOLDER_BACK_NORMAL" file="common/app_list_folder_back_normal.png" />
         <if expr="is_win">
           <structure type="chrome_scaled_image" name="IDR_APP_LIST_USER_INDICATOR" file="win/app_list_user_indicator.png" />
         </if>
diff --git a/ui/shell/minimal_shell.cc b/ui/shell/minimal_shell.cc
index 556c16e..3e01ef6 100644
--- a/ui/shell/minimal_shell.cc
+++ b/ui/shell/minimal_shell.cc
@@ -20,7 +20,7 @@
       aura::RootWindow::CreateParams(
           gfx::Rect(default_window_size))));
   root_window_->Init();
-  aura::client::SetStackingClient(root_window_.get(), this);
+  aura::client::SetWindowTreeClient(root_window_.get(), this);
 
   focus_client_.reset(new aura::test::TestFocusClient);
   aura::client::SetFocusClient(root_window_.get(), focus_client_.get());
diff --git a/ui/shell/minimal_shell.h b/ui/shell/minimal_shell.h
index f8ae67b..22c160b 100644
--- a/ui/shell/minimal_shell.h
+++ b/ui/shell/minimal_shell.h
@@ -7,7 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/stacking_client.h"
+#include "ui/aura/client/window_tree_client.h"
 
 namespace aura {
 class RootWindow;
@@ -36,14 +36,14 @@
 // Creates a minimal environment for running the shell. We can't pull in all of
 // ash here, but we can create attach several of the same things we'd find in
 // the ash parts of the code.
-class MinimalShell : public aura::client::StackingClient {
+class MinimalShell : public aura::client::WindowTreeClient {
  public:
   explicit MinimalShell(const gfx::Size& default_window_size);
   virtual ~MinimalShell();
 
   aura::RootWindow* root_window() { return root_window_.get(); }
 
-  // Overridden from client::StackingClient:
+  // Overridden from client::WindowTreeClient:
   virtual aura::Window* GetDefaultParent(aura::Window* context,
                                          aura::Window* window,
                                          const gfx::Rect& bounds) OVERRIDE;
diff --git a/ui/shell/shell.gyp b/ui/shell/shell.gyp
index 7c5c595..71ce102 100644
--- a/ui/shell/shell.gyp
+++ b/ui/shell/shell.gyp
@@ -3,14 +3,17 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'chromium_code': 1,
+  },
   'targets': [
     {
       'target_name': 'shell',
       'type': 'static_library',
       'dependencies': [
+        '../../skia/skia.gyp:skia',
         '../aura/aura.gyp:aura',
         '../views/views.gyp:views',
-        '../../skia/skia.gyp:skia',
       ],
       'sources': [
         'minimal_shell.cc',
diff --git a/ui/shell_dialogs.gypi b/ui/shell_dialogs.gypi
deleted file mode 100644
index 2675d73..0000000
--- a/ui/shell_dialogs.gypi
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (c) 2013 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': 'shell_dialogs',
-      'type': '<(component)',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/base.gyp:base_i18n',
-        'base/strings/ui_strings.gyp:ui_strings',
-        '../skia/skia.gyp:skia',
-        'ui',
-      ],
-      'defines': [
-        'SHELL_DIALOGS_IMPLEMENTATION',
-      ],
-      'sources': [
-        'shell_dialogs/android/shell_dialogs_jni_registrar.cc',
-        'shell_dialogs/android/shell_dialogs_jni_registrar.h',
-        'shell_dialogs/base_shell_dialog.cc',
-        'shell_dialogs/base_shell_dialog.h',
-        'shell_dialogs/base_shell_dialog_win.cc',
-        'shell_dialogs/base_shell_dialog_win.h',
-        'shell_dialogs/gtk/select_file_dialog_impl.cc',
-        'shell_dialogs/gtk/select_file_dialog_impl.h',
-        'shell_dialogs/gtk/select_file_dialog_impl_gtk.cc',
-        'shell_dialogs/gtk/select_file_dialog_impl_kde.cc',
-        'shell_dialogs/linux_shell_dialog.cc',
-        'shell_dialogs/linux_shell_dialog.h',
-        'shell_dialogs/select_file_dialog.cc',
-        'shell_dialogs/select_file_dialog.h',
-        'shell_dialogs/select_file_dialog_android.cc',
-        'shell_dialogs/select_file_dialog_android.h',
-        'shell_dialogs/select_file_dialog_factory.cc',
-        'shell_dialogs/select_file_dialog_factory.h',
-        'shell_dialogs/select_file_dialog_mac.h',
-        'shell_dialogs/select_file_dialog_mac.mm',
-        'shell_dialogs/select_file_dialog_win.cc',
-        'shell_dialogs/select_file_dialog_win.h',
-        'shell_dialogs/select_file_policy.cc',
-        'shell_dialogs/select_file_policy.h',
-        'shell_dialogs/selected_file_info.cc',
-        'shell_dialogs/selected_file_info.h',
-      ],
-      'include_dirs': [
-        '../',
-      ],
-      'conditions': [
-        ['use_aura==1', {
-          'dependencies': [
-            'aura/aura.gyp:aura',
-          ],
-          'sources/': [
-            ['exclude', 'shell_dialogs/select_file_dialog_mac.mm'],
-           ],
-        }],
-        ['OS=="android"', {
-          'dependencies': [
-            'ui_jni_headers',
-          ],
-          'include_dirs': [
-            '<(SHARED_INTERMEDIATE_DIR)/ui',
-          ],
-          'link_settings': {
-            'libraries': [
-              '-ljnigraphics',
-            ],
-          },
-        }],
-        ['OS=="android" and android_webview_build==0', {
-          'dependencies': [
-            'ui_java',
-          ],
-        }],
-      ],
-    },  # target_name: shell_dialogs
-  ],
-}
diff --git a/ui/shell_dialogs.target.darwin-arm.mk b/ui/shell_dialogs.target.darwin-arm.mk
deleted file mode 100644
index 3096a7f..0000000
--- a/ui/shell_dialogs.target.darwin-arm.mk
+++ /dev/null
@@ -1,326 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-fno-tree-sra \
-	-fuse-ld=gold \
-	-Wno-psabi \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-fno-tree-sra \
-	-fuse-ld=gold \
-	-Wno-psabi \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-Wl,-z,relro \
-	-Wl,-z,now \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--icf=safe \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-Wl,-z,relro \
-	-Wl,-z,now \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--icf=safe \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs.target.darwin-mips.mk b/ui/shell_dialogs.target.darwin-mips.mk
deleted file mode 100644
index 2fc7488..0000000
--- a/ui/shell_dialogs.target.darwin-mips.mk
+++ /dev/null
@@ -1,320 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-EL \
-	-mhard-float \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-EL \
-	-mhard-float \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-EL \
-	-Wl,--no-keep-memory \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-EL \
-	-Wl,--no-keep-memory \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs.target.darwin-x86.mk b/ui/shell_dialogs.target.darwin-x86.mk
deleted file mode 100644
index ff065ee..0000000
--- a/ui/shell_dialogs.target.darwin-x86.mk
+++ /dev/null
@@ -1,324 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-m32 \
-	-mmmx \
-	-march=pentium4 \
-	-msse2 \
-	-mfpmath=sse \
-	-fuse-ld=gold \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-fno-stack-protector \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-m32 \
-	-mmmx \
-	-march=pentium4 \
-	-msse2 \
-	-mfpmath=sse \
-	-fuse-ld=gold \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-fno-stack-protector \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer \
-	-fno-unwind-tables \
-	-fno-asynchronous-unwind-tables
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-m32 \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-m32 \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs.target.linux-arm.mk b/ui/shell_dialogs.target.linux-arm.mk
deleted file mode 100644
index 3096a7f..0000000
--- a/ui/shell_dialogs.target.linux-arm.mk
+++ /dev/null
@@ -1,326 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-fno-tree-sra \
-	-fuse-ld=gold \
-	-Wno-psabi \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-fno-tree-sra \
-	-fuse-ld=gold \
-	-Wno-psabi \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-Wl,-z,relro \
-	-Wl,-z,now \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--icf=safe \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-Wl,-z,relro \
-	-Wl,-z,now \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--icf=safe \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs.target.linux-mips.mk b/ui/shell_dialogs.target.linux-mips.mk
deleted file mode 100644
index 2fc7488..0000000
--- a/ui/shell_dialogs.target.linux-mips.mk
+++ /dev/null
@@ -1,320 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-EL \
-	-mhard-float \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-EL \
-	-mhard-float \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fstack-protector \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-EL \
-	-Wl,--no-keep-memory \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-EL \
-	-Wl,--no-keep-memory \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs.target.linux-x86.mk b/ui/shell_dialogs.target.linux-x86.mk
deleted file mode 100644
index ff065ee..0000000
--- a/ui/shell_dialogs.target.linux-x86.mk
+++ /dev/null
@@ -1,324 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := ui_shell_dialogs_gyp
-LOCAL_MODULE_SUFFIX := .a
-LOCAL_MODULE_TAGS := optional
-gyp_intermediate_dir := $(call local-intermediates-dir)
-gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
-
-# Make sure our deps are built first.
-GYP_TARGET_DEPENDENCIES := \
-	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
-	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
-
-GYP_GENERATED_OUTPUTS :=
-
-# Make sure our deps and generated files are built first.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_GENERATED_SOURCES :=
-
-GYP_COPIED_SOURCE_ORIGIN_DIRS :=
-
-LOCAL_SRC_FILES := \
-	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
-	ui/shell_dialogs/base_shell_dialog.cc \
-	ui/shell_dialogs/linux_shell_dialog.cc \
-	ui/shell_dialogs/select_file_dialog.cc \
-	ui/shell_dialogs/select_file_dialog_android.cc \
-	ui/shell_dialogs/select_file_dialog_factory.cc \
-	ui/shell_dialogs/select_file_policy.cc \
-	ui/shell_dialogs/selected_file_info.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-m32 \
-	-mmmx \
-	-march=pentium4 \
-	-msse2 \
-	-mfpmath=sse \
-	-fuse-ld=gold \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-fno-stack-protector \
-	-Os \
-	-g \
-	-fomit-frame-pointer \
-	-fdata-sections \
-	-ffunction-sections
-
-MY_DEFS_Debug := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
-	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
-	'-D_DEBUG'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Debug := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Debug := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-Werror \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wall \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-m32 \
-	-mmmx \
-	-march=pentium4 \
-	-msse2 \
-	-mfpmath=sse \
-	-fuse-ld=gold \
-	-ffunction-sections \
-	-funwind-tables \
-	-g \
-	-fno-short-enums \
-	-finline-limit=64 \
-	-Wa,--noexecstack \
-	-U_FORTIFY_SOURCE \
-	-Wno-extra \
-	-Wno-ignored-qualifiers \
-	-Wno-type-limits \
-	-fno-stack-protector \
-	-Os \
-	-fno-ident \
-	-fdata-sections \
-	-ffunction-sections \
-	-fomit-frame-pointer \
-	-fno-unwind-tables \
-	-fno-asynchronous-unwind-tables
-
-MY_DEFS_Release := \
-	'-DANGLE_DX11' \
-	'-D_FILE_OFFSET_BITS=64' \
-	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DDISABLE_NACL' \
-	'-DCHROMIUM_BUILD' \
-	'-DUSE_LIBJPEG_TURBO=1' \
-	'-DUSE_PROPRIETARY_CODECS' \
-	'-DENABLE_CONFIGURATION_POLICY' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DCLD_VERSION=1' \
-	'-DSHELL_DIALOGS_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-D__STDC_CONSTANT_MACROS' \
-	'-D__STDC_FORMAT_MACROS' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
-	'-D_FORTIFY_SOURCE=2'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui \
-	$(LOCAL_PATH) \
-	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
-	$(gyp_shared_intermediate_dir)/ui/ui_strings \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/third_party/skia/include/core \
-	$(LOCAL_PATH)/third_party/skia/include/effects \
-	$(LOCAL_PATH)/third_party/skia/include/pdf \
-	$(LOCAL_PATH)/third_party/skia/include/gpu \
-	$(LOCAL_PATH)/third_party/skia/include/lazy \
-	$(LOCAL_PATH)/third_party/skia/include/pathops \
-	$(LOCAL_PATH)/third_party/skia/include/pipe \
-	$(LOCAL_PATH)/third_party/skia/include/ports \
-	$(LOCAL_PATH)/third_party/skia/include/utils \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/skia/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(PWD)/frameworks/wilhelm/include \
-	$(PWD)/bionic \
-	$(PWD)/external/stlport/stlport
-
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS_Release := \
-	-fno-rtti \
-	-fno-threadsafe-statics \
-	-fvisibility-inlines-hidden \
-	-Wsign-compare \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo
-
-
-LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
-LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
-LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
-### Rules for final target.
-
-LOCAL_LDFLAGS_Debug := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-m32 \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,--fatal-warnings \
-	-Wl,--gc-sections \
-	-Wl,--warn-shared-textrel \
-	-Wl,-O1 \
-	-Wl,--as-needed
-
-
-LOCAL_LDFLAGS_Release := \
-	-Wl,-z,now \
-	-Wl,-z,relro \
-	-Wl,-z,noexecstack \
-	-fPIC \
-	-m32 \
-	-fuse-ld=gold \
-	-nostdlib \
-	-Wl,--no-undefined \
-	-Wl,--exclude-libs=ALL \
-	-Wl,-O1 \
-	-Wl,--as-needed \
-	-Wl,--gc-sections \
-	-Wl,--fatal-warnings \
-	-Wl,--warn-shared-textrel
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
-
-# Enable grouping to fix circular references
-LOCAL_GROUP_STATIC_LIBRARIES := true
-
-LOCAL_SHARED_LIBRARIES := \
-	libstlport \
-	libdl
-
-# Add target alias to "gyp_all_modules" target.
-.PHONY: gyp_all_modules
-gyp_all_modules: ui_shell_dialogs_gyp
-
-# Alias gyp target name.
-.PHONY: shell_dialogs
-shell_dialogs: ui_shell_dialogs_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/base_shell_dialog_win.cc b/ui/shell_dialogs/base_shell_dialog_win.cc
index 9ccd1bb..e121fbf 100644
--- a/ui/shell_dialogs/base_shell_dialog_win.cc
+++ b/ui/shell_dialogs/base_shell_dialog_win.cc
@@ -30,7 +30,9 @@
   DCHECK(!IsRunningDialogForOwner(owner));
   // The owner must be a top level window, otherwise we could end up with two
   // entries in our map for the same top level window.
-  DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
+  // TODO(scottmg): This should be re-enabled when Chrome Frame is removed.
+  // http://crbug.com/310264
+  // DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
   RunState run_state;
   run_state.dialog_thread = CreateDialogThread();
   run_state.owner = owner;
diff --git a/ui/shell_dialogs/print_settings_dialog_win.cc b/ui/shell_dialogs/print_settings_dialog_win.cc
new file mode 100644
index 0000000..f3f89b3
--- /dev/null
+++ b/ui/shell_dialogs/print_settings_dialog_win.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/shell_dialogs/print_settings_dialog_win.h"
+
+#include "base/bind.h"
+#include "base/threading/thread.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/root_window.h"
+#endif
+
+namespace ui {
+
+PrintSettingsDialogWin::PrintSettingsDialogWin(
+    PrintSettingsDialogWin::Observer* observer)
+    : observer_(observer) {
+}
+
+PrintSettingsDialogWin::~PrintSettingsDialogWin() {
+}
+
+void PrintSettingsDialogWin::GetPrintSettings(PrintDialogFunc print_dialog_func,
+                                              HWND owning_window,
+                                              PRINTDLGEX* dialog_options) {
+  DCHECK(observer_);
+
+  ExecutePrintSettingsParams execute_params(BeginRun(owning_window),
+                                            owning_window,
+                                            print_dialog_func,
+                                            dialog_options);
+  execute_params.run_state.dialog_thread->message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &PrintSettingsDialogWin::ExecutePrintSettings, this, execute_params));
+}
+
+void PrintSettingsDialogWin::ExecutePrintSettings(
+    const ExecutePrintSettingsParams& params) {
+  HRESULT hr = (*params.print_dialog_func)(params.dialog_options);
+  params.ui_proxy->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &PrintSettingsDialogWin::PrintSettingsCompleted, this, hr, params));
+}
+
+void PrintSettingsDialogWin::PrintSettingsCompleted(
+    HRESULT hresult,
+    const ExecutePrintSettingsParams& params) {
+  EndRun(params.run_state);
+  if (hresult != S_OK)
+    observer_->PrintSettingsCancelled(params.dialog_options);
+  else
+    observer_->PrintSettingsConfirmed(params.dialog_options);
+}
+
+}  // namespace ui
diff --git a/ui/shell_dialogs/print_settings_dialog_win.h b/ui/shell_dialogs/print_settings_dialog_win.h
new file mode 100644
index 0000000..6a1efed
--- /dev/null
+++ b/ui/shell_dialogs/print_settings_dialog_win.h
@@ -0,0 +1,83 @@
+// Copyright 2013 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_PRINT_SETTINGS_DIALOG_WIN_H_
+#define UI_SHELL_DIALOGS_PRINT_SETTINGS_DIALOG_WIN_H_
+
+#include <ocidl.h>
+#include <commdlg.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "ui/shell_dialogs/base_shell_dialog_win.h"
+#include "ui/shell_dialogs/shell_dialogs_export.h"
+
+namespace ui {
+
+// A thin wrapper around the native window print dialog that uses
+// BaseShellDialog to have the dialog run on a background thread.
+class SHELL_DIALOGS_EXPORT PrintSettingsDialogWin
+    : public base::RefCountedThreadSafe<PrintSettingsDialogWin>,
+      public BaseShellDialogImpl {
+ public:
+  class SHELL_DIALOGS_EXPORT Observer {
+   public:
+    virtual void PrintSettingsConfirmed(PRINTDLGEX* dialog_options) = 0;
+    virtual void PrintSettingsCancelled(PRINTDLGEX* dialog_options) = 0;
+  };
+  typedef HRESULT(__stdcall* PrintDialogFunc)(PRINTDLGEX*);
+
+  explicit PrintSettingsDialogWin(Observer* observer);
+  virtual ~PrintSettingsDialogWin();
+
+  // Called to open the system print dialog on a background thread.
+  // |print_dialog_func| should generally be ::PrintDlgEx, however alternate
+  // functions are used for testing. |owning_window| is the parent HWND, and
+  // |dialog_options| is passed to |print_dialog_func|.
+  void GetPrintSettings(
+      PrintDialogFunc print_dialog_func,
+      HWND owning_window,
+      PRINTDLGEX* dialog_options);
+
+ private:
+  // A struct for holding all the state necessary for displaying the print
+  // settings dialog.
+  struct ExecutePrintSettingsParams {
+    ExecutePrintSettingsParams(RunState run_state,
+                               HWND owner,
+                               PrintDialogFunc print_dialog_func,
+                               PRINTDLGEX* dialog_options)
+        : run_state(run_state),
+          owner(owner),
+          print_dialog_func(print_dialog_func),
+          dialog_options(dialog_options),
+          ui_proxy(base::MessageLoopForUI::current()->message_loop_proxy()) {}
+
+    RunState run_state;
+    HWND owner;
+    PrintDialogFunc print_dialog_func;
+    PRINTDLGEX* dialog_options;
+    scoped_refptr<base::MessageLoopProxy> ui_proxy;
+  };
+
+  // Runs the print dialog. Should be run on the the BaseShellDialogImpl thread.
+  // Posts back to PrintSettingsCompleted on the UI thread on completion.
+  void ExecutePrintSettings(const ExecutePrintSettingsParams& params);
+
+  // Handler for the result of the print settings dialog. Should be run on the
+  // UI thread, and notifies the observer of the result of the dialog.
+  void PrintSettingsCompleted(HRESULT hresult,
+                              const ExecutePrintSettingsParams& params);
+
+  // Observer that's notified when the dialog is confirmed or cancelled.
+  Observer* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintSettingsDialogWin);
+};
+
+}  // namespace ui
+
+#endif  // UI_SHELL_DIALOGS_PRINT_SETTINGS_DIALOG_WIN_H_
diff --git a/ui/shell_dialogs/select_file_dialog_win.cc b/ui/shell_dialogs/select_file_dialog_win.cc
index c028d22..7cec71d 100644
--- a/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/ui/shell_dialogs/select_file_dialog_win.cc
@@ -599,7 +599,7 @@
     }
   }
   HWND owner = owning_window && owning_window->GetRootWindow()
-               ? owning_window->GetRootWindow()->GetAcceleratedWidget() : NULL;
+               ? owning_window->GetDispatcher()->GetAcceleratedWidget() : NULL;
 #else
   HWND owner = owning_window;
 #endif
@@ -621,7 +621,7 @@
 #if defined(USE_AURA)
   if (!owning_window->GetRootWindow())
     return false;
-  HWND owner = owning_window->GetRootWindow()->GetAcceleratedWidget();
+  HWND owner = owning_window->GetDispatcher()->GetAcceleratedWidget();
 #else
   HWND owner = owning_window;
 #endif
diff --git a/ui/shell_dialogs/shell_dialogs.gyp b/ui/shell_dialogs/shell_dialogs.gyp
new file mode 100644
index 0000000..5f52d0c
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.gyp
@@ -0,0 +1,89 @@
+# Copyright 2013 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'shell_dialogs',
+      'type': '<(component)',
+      'dependencies': [
+        '../../base/base.gyp:base',
+        '../../base/base.gyp:base_i18n',
+        '../../skia/skia.gyp:skia',
+        '../base/strings/ui_strings.gyp:ui_strings',
+        '../ui.gyp:ui',
+      ],
+      'defines': [
+        'SHELL_DIALOGS_IMPLEMENTATION',
+      ],
+      'sources': [
+        'android/shell_dialogs_jni_registrar.cc',
+        'android/shell_dialogs_jni_registrar.h',
+        'base_shell_dialog.cc',
+        'base_shell_dialog.h',
+        'base_shell_dialog_win.cc',
+        'base_shell_dialog_win.h',
+        'gtk/select_file_dialog_impl.cc',
+        'gtk/select_file_dialog_impl.h',
+        'gtk/select_file_dialog_impl_gtk.cc',
+        'gtk/select_file_dialog_impl_kde.cc',
+        'linux_shell_dialog.cc',
+        'linux_shell_dialog.h',
+        'print_settings_dialog_win.cc',
+        'print_settings_dialog_win.h',
+        'select_file_dialog.cc',
+        'select_file_dialog.h',
+        'select_file_dialog_android.cc',
+        'select_file_dialog_android.h',
+        'select_file_dialog_factory.cc',
+        'select_file_dialog_factory.h',
+        'select_file_dialog_mac.h',
+        'select_file_dialog_mac.mm',
+        'select_file_dialog_win.cc',
+        'select_file_dialog_win.h',
+        'select_file_policy.cc',
+        'select_file_policy.h',
+        'selected_file_info.cc',
+        'selected_file_info.h',
+      ],
+      'conditions': [
+        ['use_aura==1',
+          {
+            'dependencies': [
+              '../aura/aura.gyp:aura',
+            ],
+            'sources/': [
+              ['exclude', 'select_file_dialog_mac.mm'],
+            ],
+          }
+        ],
+        ['OS=="android"',
+          {
+            'dependencies': [
+              '../ui.gyp:ui_jni_headers',
+            ],
+            'include_dirs': [
+              '<(SHARED_INTERMEDIATE_DIR)/ui',
+            ],
+            'link_settings': {
+              'libraries': [
+                '-ljnigraphics',
+              ],
+            },
+          }
+        ],
+        ['OS=="android" and android_webview_build==0',
+          {
+            'dependencies': [
+              '../ui.gyp:ui_java',
+            ],
+          }
+        ],
+      ],
+    },  # target_name: shell_dialogs
+  ],
+}
diff --git a/ui/shell_dialogs/shell_dialogs.target.darwin-arm.mk b/ui/shell_dialogs/shell_dialogs.target.darwin-arm.mk
new file mode 100644
index 0000000..1d2a21f
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.darwin-arm.mk
@@ -0,0 +1,324 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/shell_dialogs.target.darwin-mips.mk b/ui/shell_dialogs/shell_dialogs.target.darwin-mips.mk
new file mode 100644
index 0000000..a47ccf0
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.darwin-mips.mk
@@ -0,0 +1,318 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-EL \
+	-mhard-float \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-EL \
+	-mhard-float \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-EL \
+	-Wl,--no-keep-memory \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-EL \
+	-Wl,--no-keep-memory \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/shell_dialogs.target.darwin-x86.mk b/ui/shell_dialogs/shell_dialogs.target.darwin-x86.mk
new file mode 100644
index 0000000..180533e
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.darwin-x86.mk
@@ -0,0 +1,322 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-m32 \
+	-mmmx \
+	-march=pentium4 \
+	-msse2 \
+	-mfpmath=sse \
+	-fuse-ld=gold \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-fno-stack-protector \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-m32 \
+	-mmmx \
+	-march=pentium4 \
+	-msse2 \
+	-mfpmath=sse \
+	-fuse-ld=gold \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-fno-stack-protector \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-fno-unwind-tables \
+	-fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-m32 \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-m32 \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/shell_dialogs.target.linux-arm.mk b/ui/shell_dialogs/shell_dialogs.target.linux-arm.mk
new file mode 100644
index 0000000..1d2a21f
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.linux-arm.mk
@@ -0,0 +1,324 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/shell_dialogs.target.linux-mips.mk b/ui/shell_dialogs/shell_dialogs.target.linux-mips.mk
new file mode 100644
index 0000000..a47ccf0
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.linux-mips.mk
@@ -0,0 +1,318 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-EL \
+	-mhard-float \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-EL \
+	-mhard-float \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DPOSIX_AVOID_MMAP' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-EL \
+	-Wl,--no-keep-memory \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-EL \
+	-Wl,--no-keep-memory \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/shell_dialogs/shell_dialogs.target.linux-x86.mk b/ui/shell_dialogs/shell_dialogs.target.linux-x86.mk
new file mode 100644
index 0000000..180533e
--- /dev/null
+++ b/ui/shell_dialogs/shell_dialogs.target.linux-x86.mk
@@ -0,0 +1,322 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := ui_shell_dialogs_shell_dialogs_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_base_strings_ui_strings_gyp)/ui_strings.stamp \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
+	$(call intermediates-dir-for,GYP,ui_ui_jni_headers_gyp)/ui_jni_headers.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc \
+	ui/shell_dialogs/base_shell_dialog.cc \
+	ui/shell_dialogs/linux_shell_dialog.cc \
+	ui/shell_dialogs/select_file_dialog.cc \
+	ui/shell_dialogs/select_file_dialog_android.cc \
+	ui/shell_dialogs/select_file_dialog_factory.cc \
+	ui/shell_dialogs/select_file_policy.cc \
+	ui/shell_dialogs/selected_file_info.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-m32 \
+	-mmmx \
+	-march=pentium4 \
+	-msse2 \
+	-mfpmath=sse \
+	-fuse-ld=gold \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-fno-stack-protector \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-m32 \
+	-mmmx \
+	-march=pentium4 \
+	-msse2 \
+	-mfpmath=sse \
+	-fuse-ld=gold \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-fno-stack-protector \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-fno-unwind-tables \
+	-fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DCLD_VERSION=1' \
+	'-DSHELL_DIALOGS_IMPLEMENTATION' \
+	'-DSK_ENABLE_INST_COUNT=0' \
+	'-DSK_SUPPORT_GPU=1' \
+	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
+	'-DSK_ENABLE_LEGACY_API_ALIASING=1' \
+	'-DSK_BUILD_FOR_ANDROID' \
+	'-DSK_USE_POSIX_THREADS' \
+	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/icuuc/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/icui18n/target \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir)/ui \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/skia/src/core \
+	$(LOCAL_PATH)/third_party/skia/include/core \
+	$(LOCAL_PATH)/third_party/skia/include/effects \
+	$(LOCAL_PATH)/third_party/skia/include/pdf \
+	$(LOCAL_PATH)/third_party/skia/include/gpu \
+	$(LOCAL_PATH)/third_party/skia/include/lazy \
+	$(LOCAL_PATH)/third_party/skia/include/pathops \
+	$(LOCAL_PATH)/third_party/skia/include/pipe \
+	$(LOCAL_PATH)/third_party/skia/include/ports \
+	$(LOCAL_PATH)/third_party/skia/include/utils \
+	$(LOCAL_PATH)/skia/config \
+	$(LOCAL_PATH)/skia/ext \
+	$(gyp_shared_intermediate_dir)/ui/app_locale_settings \
+	$(gyp_shared_intermediate_dir)/ui/ui_strings \
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-m32 \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--fatal-warnings \
+	-Wl,--gc-sections \
+	-Wl,--warn-shared-textrel \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-m32 \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections \
+	-Wl,--fatal-warnings \
+	-Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES := \
+	skia_skia_library_gyp \
+	ui_ui_gyp
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: ui_shell_dialogs_shell_dialogs_gyp
+
+# Alias gyp target name.
+.PHONY: shell_dialogs
+shell_dialogs: ui_shell_dialogs_shell_dialogs_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ui/snapshot/snapshot.target.darwin-arm.mk b/ui/snapshot/snapshot.target.darwin-arm.mk
index 2fc3e46..f184b43 100644
--- a/ui/snapshot/snapshot.target.darwin-arm.mk
+++ b/ui/snapshot/snapshot.target.darwin-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot.target.darwin-mips.mk b/ui/snapshot/snapshot.target.darwin-mips.mk
index 0ed64d7..21b510e 100644
--- a/ui/snapshot/snapshot.target.darwin-mips.mk
+++ b/ui/snapshot/snapshot.target.darwin-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot.target.darwin-x86.mk b/ui/snapshot/snapshot.target.darwin-x86.mk
index 4b151bb..26a32b3 100644
--- a/ui/snapshot/snapshot.target.darwin-x86.mk
+++ b/ui/snapshot/snapshot.target.darwin-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -177,13 +177,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot.target.linux-arm.mk b/ui/snapshot/snapshot.target.linux-arm.mk
index 2fc3e46..f184b43 100644
--- a/ui/snapshot/snapshot.target.linux-arm.mk
+++ b/ui/snapshot/snapshot.target.linux-arm.mk
@@ -66,13 +66,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot.target.linux-mips.mk b/ui/snapshot/snapshot.target.linux-mips.mk
index 0ed64d7..21b510e 100644
--- a/ui/snapshot/snapshot.target.linux-mips.mk
+++ b/ui/snapshot/snapshot.target.linux-mips.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -171,13 +171,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot.target.linux-x86.mk b/ui/snapshot/snapshot.target.linux-x86.mk
index 4b151bb..26a32b3 100644
--- a/ui/snapshot/snapshot.target.linux-x86.mk
+++ b/ui/snapshot/snapshot.target.linux-x86.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -177,13 +177,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc
index 29daf9f..ea4cb1b 100644
--- a/ui/snapshot/snapshot_aura.cc
+++ b/ui/snapshot/snapshot_aura.cc
@@ -40,9 +40,9 @@
   // We must take into account the window's position on the desktop.
   read_pixels_bounds.Offset(
       window->GetBoundsInRootWindow().origin().OffsetFromOrigin());
-  aura::RootWindow* root_window = window->GetRootWindow();
-  if (root_window)
-    root_window->GetRootTransform().TransformRect(&read_pixels_bounds);
+  aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
+  if (dispatcher)
+    dispatcher->GetRootTransform().TransformRect(&read_pixels_bounds);
 
   gfx::Rect read_pixels_bounds_in_pixel =
       gfx::ToEnclosingRect(read_pixels_bounds);
diff --git a/ui/surface/accelerated_surface_transformer_win_unittest.cc b/ui/surface/accelerated_surface_transformer_win_unittest.cc
index 607e361..67460ad 100644
--- a/ui/surface/accelerated_surface_transformer_win_unittest.cc
+++ b/ui/surface/accelerated_surface_transformer_win_unittest.cc
@@ -45,8 +45,8 @@
   gfx::Size size = d3d_utils::GetSize(surface);
   if (is_single_channel)
     size = gfx::Size(size.width() * 4, size.height());
-  result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
-  result.setIsOpaque(true);
+  result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height(),
+                   0, kOpaque_SkAlphaType);
   result.allocPixels();
   result.lockPixels();
   for (int y = 0; y < size.height(); ++y) {
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc
index 7f75e5f..a8b57c5 100644
--- a/ui/surface/accelerated_surface_win.cc
+++ b/ui/surface/accelerated_surface_win.cc
@@ -28,6 +28,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/win/shell.h"
 #include "ui/events/latency_info.h"
+#include "ui/gfx/frame_time.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/win/dpi.h"
 #include "ui/gfx/win/hwnd_util.h"
@@ -522,11 +523,10 @@
     }
   }
 
-  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
-                    dst_size.width(), dst_size.height());
+  bitmap->setConfig(SkBitmap::kARGB_8888_Config, dst_size.width(),
+                    dst_size.height(), 0, kOpaque_SkAlphaType);
   if (!bitmap->allocPixels())
     return false;
-  bitmap->setIsOpaque(true);
 
   // Copy |final_surface| to |bitmap|. This is always a synchronous operation.
   return gpu_ops->ReadFast(final_surface,
@@ -878,18 +878,22 @@
   if (raster_status.InVBlank)
     clamped_scanline = display_mode.Height;
 
-  base::TimeTicks current_time = base::TimeTicks::HighResNow();
-
   // Figure out approximately how far back in time the last vsync was based on
   // the ratio of the raster scanline to the display height.
   base::TimeTicks last_vsync_time;
   base::TimeDelta refresh_period;
+
   if (display_mode.Height) {
+    refresh_period = base::TimeDelta::FromMicroseconds(
+        1000000 / display_mode.RefreshRate);
+    // If FrameTime is not high resolution, we use a timebase of zero to avoid
+    // introducing jitter into our frame start times.
+    if (gfx::FrameTime::TimestampsAreHighRes()) {
+      base::TimeTicks current_time = gfx::FrameTime::Now();
       last_vsync_time = current_time -
         base::TimeDelta::FromMilliseconds((clamped_scanline * 1000) /
             (display_mode.RefreshRate * display_mode.Height));
-      refresh_period = base::TimeDelta::FromMicroseconds(
-          1000000 / display_mode.RefreshRate);
+    }
   }
 
   // Wait for the StretchRect to complete before notifying the GPU process
diff --git a/ui/surface/surface.target.darwin-arm.mk b/ui/surface/surface.target.darwin-arm.mk
index 6a28e72..196e7c3 100644
--- a/ui/surface/surface.target.darwin-arm.mk
+++ b/ui/surface/surface.target.darwin-arm.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -183,13 +183,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/surface/surface.target.darwin-mips.mk b/ui/surface/surface.target.darwin-mips.mk
index 3f1059d..8821781 100644
--- a/ui/surface/surface.target.darwin-mips.mk
+++ b/ui/surface/surface.target.darwin-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/surface/surface.target.darwin-x86.mk b/ui/surface/surface.target.darwin-x86.mk
index ed0105e..d0db014 100644
--- a/ui/surface/surface.target.darwin-x86.mk
+++ b/ui/surface/surface.target.darwin-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -187,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/surface/surface.target.linux-arm.mk b/ui/surface/surface.target.linux-arm.mk
index 6a28e72..196e7c3 100644
--- a/ui/surface/surface.target.linux-arm.mk
+++ b/ui/surface/surface.target.linux-arm.mk
@@ -70,13 +70,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -183,13 +183,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/surface/surface.target.linux-mips.mk b/ui/surface/surface.target.linux-mips.mk
index 3f1059d..8821781 100644
--- a/ui/surface/surface.target.linux-mips.mk
+++ b/ui/surface/surface.target.linux-mips.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -181,13 +181,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/surface/surface.target.linux-x86.mk b/ui/surface/surface.target.linux-x86.mk
index ed0105e..d0db014 100644
--- a/ui/surface/surface.target.linux-x86.mk
+++ b/ui/surface/surface.target.linux-x86.mk
@@ -72,13 +72,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -187,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 0a9fa91..a38f859 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -7,9 +7,7 @@
     'chromium_code': 1,
   },
   'includes': [
-    'shell_dialogs.gypi',
     'ui_resources.gypi',
-    'ui_unittests.gypi',
   ],
   'targets': [
     {
@@ -182,8 +180,6 @@
         'base/gtk/gtk_floating_container.cc',
         'base/gtk/gtk_floating_container.h',
         'base/gtk/gtk_hig_constants.h',
-        'base/gtk/gtk_im_context_util.cc',
-        'base/gtk/gtk_im_context_util.h',
         'base/gtk/gtk_screen_util.cc',
         'base/gtk/gtk_screen_util.h',
         'base/gtk/gtk_signal.h',
@@ -461,9 +457,6 @@
                 'dwmapi.lib',
               ],
             },
-            'VCCLCompilerTool': {
-              'ForcedIncludeFiles': [ 'build/intsafe_workaround.h' ],
-            },
           },
           'link_settings': {
             'libraries': [
diff --git a/ui/ui.target.darwin-arm.mk b/ui/ui.target.darwin-arm.mk
index dd7cc67..eb7b0c1 100644
--- a/ui/ui.target.darwin-arm.mk
+++ b/ui/ui.target.darwin-arm.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -108,13 +111,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -222,13 +225,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.target.darwin-mips.mk b/ui/ui.target.darwin-mips.mk
index b79f245..951c018 100644
--- a/ui/ui.target.darwin-mips.mk
+++ b/ui/ui.target.darwin-mips.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -107,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -220,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.target.darwin-x86.mk b/ui/ui.target.darwin-x86.mk
index 1558dba..bc47ec8 100644
--- a/ui/ui.target.darwin-x86.mk
+++ b/ui/ui.target.darwin-x86.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -110,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -226,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.target.linux-arm.mk b/ui/ui.target.linux-arm.mk
index dd7cc67..eb7b0c1 100644
--- a/ui/ui.target.linux-arm.mk
+++ b/ui/ui.target.linux-arm.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -108,13 +111,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -222,13 +225,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.target.linux-mips.mk b/ui/ui.target.linux-mips.mk
index b79f245..951c018 100644
--- a/ui/ui.target.linux-mips.mk
+++ b/ui/ui.target.linux-mips.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -107,13 +110,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -220,13 +223,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui.target.linux-x86.mk b/ui/ui.target.linux-x86.mk
index 1558dba..bc47ec8 100644
--- a/ui/ui.target.linux-x86.mk
+++ b/ui/ui.target.linux-x86.mk
@@ -67,7 +67,10 @@
 	ui/base/webui/web_ui_util.cc \
 	ui/base/window_open_disposition.cc \
 	ui/base/ime/composition_text.cc \
+	ui/base/ime/dummy_input_method_delegate.cc \
+	ui/base/ime/input_method_base.cc \
 	ui/base/ime/input_method_initializer.cc \
+	ui/base/ime/mock_input_method.cc \
 	ui/base/ime/text_input_client.cc
 
 
@@ -110,13 +113,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -226,13 +229,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.darwin-arm.mk b/ui/ui_jni_headers.target.darwin-arm.mk
index c2f1d66..4e77112 100644
--- a/ui/ui_jni_headers.target.darwin-arm.mk
+++ b/ui/ui_jni_headers.target.darwin-arm.mk
@@ -128,13 +128,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -206,13 +206,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.darwin-mips.mk b/ui/ui_jni_headers.target.darwin-mips.mk
index 91dd8fc..5e03535 100644
--- a/ui/ui_jni_headers.target.darwin-mips.mk
+++ b/ui/ui_jni_headers.target.darwin-mips.mk
@@ -127,13 +127,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -204,13 +204,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.darwin-x86.mk b/ui/ui_jni_headers.target.darwin-x86.mk
index 6a9be4a..d7f6a1b 100644
--- a/ui/ui_jni_headers.target.darwin-x86.mk
+++ b/ui/ui_jni_headers.target.darwin-x86.mk
@@ -130,13 +130,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.linux-arm.mk b/ui/ui_jni_headers.target.linux-arm.mk
index c2f1d66..4e77112 100644
--- a/ui/ui_jni_headers.target.linux-arm.mk
+++ b/ui/ui_jni_headers.target.linux-arm.mk
@@ -128,13 +128,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -206,13 +206,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.linux-mips.mk b/ui/ui_jni_headers.target.linux-mips.mk
index 91dd8fc..5e03535 100644
--- a/ui/ui_jni_headers.target.linux-mips.mk
+++ b/ui/ui_jni_headers.target.linux-mips.mk
@@ -127,13 +127,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -204,13 +204,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_jni_headers.target.linux-x86.mk b/ui/ui_jni_headers.target.linux-x86.mk
index 6a9be4a..d7f6a1b 100644
--- a/ui/ui_jni_headers.target.linux-x86.mk
+++ b/ui/ui_jni_headers.target.linux-x86.mk
@@ -130,13 +130,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/ui_resources.gypi b/ui/ui_resources.gypi
index 4008f0d..8336ef3 100644
--- a/ui/ui_resources.gypi
+++ b/ui/ui_resources.gypi
@@ -25,7 +25,6 @@
           },
           'includes': [ '../build/grit_action.gypi' ],
         },
-
         {
           'action_name': 'ui_unscaled_resources',
           'variables': {
@@ -33,17 +32,6 @@
           },
           'includes': [ '../build/grit_action.gypi' ],
         },
-
-      ],
-      # gfx_resources.pak is used by DumpRenderTree.
-      # TODO(oshima): Update DumpRenderTree.gyp to use new pak file and
-      # remove this.
-      'copies': [ {
-          'destination': '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/',
-          'files' : [
-             '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/gfx_resources.pak',
-          ],
-        },
       ],
       'includes': [ '../build/grit_target.gypi' ],
     },
diff --git a/ui/ui_resources.target.darwin-arm.mk b/ui/ui_resources.target.darwin-arm.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.darwin-arm.mk
+++ b/ui/ui_resources.target.darwin-arm.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_resources.target.darwin-mips.mk b/ui/ui_resources.target.darwin-mips.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.darwin-mips.mk
+++ b/ui/ui_resources.target.darwin-mips.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_resources.target.darwin-x86.mk b/ui/ui_resources.target.darwin-x86.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.darwin-x86.mk
+++ b/ui/ui_resources.target.darwin-x86.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_resources.target.linux-arm.mk b/ui/ui_resources.target.linux-arm.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.linux-arm.mk
+++ b/ui/ui_resources.target.linux-arm.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_resources.target.linux-mips.mk b/ui/ui_resources.target.linux-mips.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.linux-mips.mk
+++ b/ui/ui_resources.target.linux-mips.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_resources.target.linux-x86.mk b/ui/ui_resources.target.linux-x86.mk
index 2051d5a..57afb44 100644
--- a/ui/ui_resources.target.linux-x86.mk
+++ b/ui/ui_resources.target.linux-x86.mk
@@ -24,7 +24,6 @@
 
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
-$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h ;
@@ -56,19 +55,10 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc: $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h ;
 
 
-### Generated for copy rule.
-$(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak: $(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak $(GYP_TARGET_DEPENDENCIES) | $(ACP)
-	@echo Copying: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(ACP) -r $< $@
-
-ui_ui_gyp_ui_resources_target_copies = $(gyp_shared_intermediate_dir)/ui/gfx/gfx_resources.pak
-
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.cc \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources_map.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/gfx_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_100_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_200_percent.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_resources_touch_100_percent.pak \
@@ -79,8 +69,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources_map.h \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/webui_resources.pak \
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_unscaled_resources.h \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc \
-	$(ui_ui_gyp_ui_resources_target_copies)
+	$(gyp_shared_intermediate_dir)/ui/ui_resources/ui_unscaled_resources.rc
 
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
diff --git a/ui/ui_unittests.gyp b/ui/ui_unittests.gyp
new file mode 100644
index 0000000..7cd570d
--- /dev/null
+++ b/ui/ui_unittests.gyp
@@ -0,0 +1,385 @@
+# Copyright 2013 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'ui_test_support',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../skia/skia.gyp:skia',
+        '../testing/gtest.gyp:gtest',
+        'events/events.gyp:events',
+        'gfx/gfx.gyp:gfx',
+      ],
+      'sources': [
+        'base/test/cocoa_test_event_utils.h',
+        'base/test/cocoa_test_event_utils.mm',
+        'base/test/ui_cocoa_test_helper.h',
+        'base/test/ui_cocoa_test_helper.mm',
+        'base/test/ui_controls.h',
+        'base/test/ui_controls_aura.cc',
+        'base/test/ui_controls_gtk.cc',
+        'base/test/ui_controls_internal_win.cc',
+        'base/test/ui_controls_internal_win.h',
+        'base/test/ui_controls_mac.mm',
+        'base/test/ui_controls_win.cc',
+        'gfx/test/color_util.cc',
+        'gfx/test/color_util.h',
+      ],
+      'include_dirs': [
+        '../',
+      ],
+      'conditions': [
+        ['OS!="ios"', {
+          'type': 'static_library',
+          'includes': [ 'base/ime/ime_test_support.gypi' ],
+        }, {  # OS=="ios"
+          # None of the sources in this target are built on iOS, resulting in
+          # link errors when building targets that depend on this target
+          # because the static library isn't found. If this target is changed
+          # to have sources that are built on iOS, the target should be changed
+          # to be of type static_library on all platforms.
+          'type': 'none',
+          # The cocoa files don't apply to iOS.
+          'sources/': [['exclude', 'cocoa']],
+        }],
+        ['chromeos==1', {
+          'dependencies': [
+            '../chromeos/chromeos.gyp:chromeos_test_support_without_gmock',
+            '../skia/skia.gyp:skia',
+          ],
+        }],
+        ['use_aura==1', {
+          'sources!': [
+            'base/test/ui_controls_win.cc',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'run_ui_unittests',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/base.gyp:test_support_base',
+        'ui.gyp:ui',
+      ],
+      'sources': [
+        'test/test_suite.cc',
+        'test/test_suite.h',
+        'test/run_all_unittests.cc',
+      ],
+    },
+    {
+      'target_name': 'ui_unittests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/base.gyp:test_support_base',
+        '../skia/skia.gyp:skia',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+        '../third_party/libpng/libpng.gyp:libpng',
+        '../url/url.gyp:url_lib',
+        'base/strings/ui_strings.gyp:ui_strings',
+        'events/events.gyp:events',
+        'run_ui_unittests',
+        'shell_dialogs/shell_dialogs.gyp:shell_dialogs',
+        'ui.gyp:keycode_converter',
+        'ui.gyp:ui',
+        'ui.gyp:ui_resources',
+        'ui_test_support',
+      ],
+      # iOS uses a small subset of ui. common_sources are the only files that
+      # are built on iOS.
+      'common_sources' : [
+        'base/layout_unittest.cc',
+        'base/l10n/l10n_util_mac_unittest.mm',
+        'base/l10n/l10n_util_unittest.cc',
+        'base/l10n/l10n_util_win_unittest.cc',
+        'base/l10n/time_format_unittest.cc',
+        'base/models/tree_node_iterator_unittest.cc',
+        'base/resource/data_pack_literal.cc',
+        'base/resource/data_pack_unittest.cc',
+        'base/resource/resource_bundle_unittest.cc',
+        'gfx/animation/animation_container_unittest.cc',
+        'gfx/animation/animation_unittest.cc',
+        'gfx/animation/multi_animation_unittest.cc',
+        'gfx/animation/slide_animation_unittest.cc',
+        'gfx/box_unittest.cc',
+        'gfx/codec/png_codec_unittest.cc',
+        'gfx/color_utils_unittest.cc',
+        'gfx/display_unittest.cc',
+        'gfx/font_unittest.cc',
+        'gfx/image/image_family_unittest.cc',
+        'gfx/image/image_skia_unittest.cc',
+        'gfx/image/image_unittest.cc',
+        'gfx/image/image_unittest_util.cc',
+        'gfx/image/image_unittest_util.h',
+        'gfx/image/image_unittest_util_ios.mm',
+        'gfx/image/image_unittest_util_mac.mm',
+        'gfx/insets_unittest.cc',
+        'gfx/matrix3_unittest.cc',
+        'gfx/point_unittest.cc',
+        'gfx/point3_unittest.cc',
+        'gfx/quad_unittest.cc',
+        'gfx/range/range_mac_unittest.mm',
+        'gfx/range/range_unittest.cc',
+        'gfx/range/range_win_unittest.cc',
+        'gfx/rect_unittest.cc',
+        'gfx/safe_integer_conversions_unittest.cc',
+        'gfx/screen_unittest.cc',
+        'gfx/shadow_value_unittest.cc',
+        'gfx/size_unittest.cc',
+        'gfx/skbitmap_operations_unittest.cc',
+        'gfx/text_elider_unittest.cc',
+        'gfx/text_utils_unittest.cc',
+        'gfx/vector2d_unittest.cc',
+        'gfx/vector3d_unittest.cc',
+      ],
+      'all_sources': [
+        '<@(_common_sources)',
+        'base/accelerators/accelerator_manager_unittest.cc',
+        'base/accelerators/menu_label_accelerator_util_linux_unittest.cc',
+        'base/clipboard/clipboard_unittest.cc',
+        'base/clipboard/custom_data_helper_unittest.cc',
+        'base/cocoa/base_view_unittest.mm',
+        'base/cocoa/cocoa_event_utils_unittest.mm',
+        'base/cocoa/controls/blue_label_button_unittest.mm',
+        'base/cocoa/controls/hover_image_menu_button_unittest.mm',
+        'base/cocoa/controls/hyperlink_button_cell_unittest.mm',
+        'base/cocoa/events_mac_unittest.mm',
+        'base/cocoa/focus_tracker_unittest.mm',
+        'base/cocoa/fullscreen_window_manager_unittest.mm',
+        'base/cocoa/hover_image_button_unittest.mm',
+        'base/cocoa/menu_controller_unittest.mm',
+        'base/cocoa/nsgraphics_context_additions_unittest.mm',
+        'base/cocoa/tracking_area_unittest.mm',
+        'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
+        'base/gtk/gtk_expanded_container_unittest.cc',
+        'base/keycodes/keycode_converter_unittest.cc',
+        'base/models/list_model_unittest.cc',
+        'base/models/list_selection_model_unittest.cc',
+        'base/models/tree_node_model_unittest.cc',
+        'base/test/data/resource.h',
+        'base/text/bytes_formatting_unittest.cc',
+        'base/view_prop_unittest.cc',
+        'base/webui/web_ui_util_unittest.cc',
+        'events/event_dispatcher_unittest.cc',
+        'events/event_unittest.cc',
+        'events/latency_info_unittest.cc',
+        'events/ozone/evdev/key_event_converter_unittest.cc',
+        'events/ozone/evdev/touch_event_converter_unittest.cc',
+        'gfx/animation/tween_unittest.cc',
+        'gfx/blit_unittest.cc',
+        'gfx/break_list_unittest.cc',
+        'gfx/canvas_unittest.cc',
+        'gfx/canvas_unittest_mac.mm',
+        'gfx/codec/jpeg_codec_unittest.cc',
+        'gfx/color_analysis_unittest.cc',
+        'gfx/font_list_unittest.cc',
+        'gfx/image/image_mac_unittest.mm',
+        'gfx/image/image_util_unittest.cc',
+        'gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc',
+        'gfx/ozone/impl/software_surface_factory_ozone_unittest.cc',
+        'gfx/ozone/impl/software_surface_ozone_unittest.cc',
+        'gfx/platform_font_mac_unittest.mm',
+        'gfx/render_text_unittest.cc',
+        'gfx/sequential_id_generator_unittest.cc',
+        'gfx/transform_util_unittest.cc',
+        'gfx/utf16_indexing_unittest.cc',
+        'shell_dialogs/select_file_dialog_win_unittest.cc',
+      ],
+      'include_dirs': [
+        '../',
+      ],
+      'conditions': [
+        ['OS!="ios"', {
+          'sources' : ['<@(_all_sources)'],
+          'includes': [
+            'base/ime/ime_unittests.gypi',
+          ],
+        }, {  # OS=="ios"
+          'sources' : [
+            '<@(_common_sources)',
+          ],
+          # The ResourceBundle unittest expects a locale.pak file to exist in
+          # the bundle for English-US. Copy it in from where it was generated
+          # by ui_strings.gyp:ui_unittest_strings.
+          'mac_bundle_resources': [
+            '<(PRODUCT_DIR)/ui_unittests_strings/en.lproj/locale.pak',
+          ],
+        }],
+        ['OS == "win"', {
+          'sources': [
+            'test/ui_unittests.rc',
+            'base/dragdrop/os_exchange_data_win_unittest.cc',
+            'base/win/hwnd_subclass_unittest.cc',
+            'gfx/font_fallback_win_unittest.cc',
+            'gfx/icon_util_unittest.cc',
+            'gfx/platform_font_win_unittest.cc',
+          ],
+          'include_dirs': [
+            '../..',
+            '../third_party/wtl/include',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'd2d1.dll',
+                'd3d10_1.dll',
+              ],
+              'AdditionalDependencies': [
+                'd2d1.lib',
+                'd3d10_1.lib',
+              ],
+            },
+          },
+          'link_settings': {
+            'libraries': [
+              '-limm32.lib',
+              '-loleacc.lib',
+            ],
+          },
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [ 4267, ],
+        }],
+        ['OS == "linux" and toolkit_views==1', {
+          'sources': [
+            'events/x/events_x_unittest.cc',
+          ],
+        }],
+        ['OS != "mac" and OS != "ios"', {
+          'sources': [
+            'gfx/transform_unittest.cc',
+            'gfx/interpolated_transform_unittest.cc',
+          ],
+        }],
+        ['OS == "android" and gtest_target_type == "shared_library"', {
+          'dependencies': [
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+        ['use_glib == 1 or OS == "ios"', {
+          'dependencies': [
+            'base/strings/ui_strings.gyp:ui_unittest_strings',
+          ],
+        }],
+        ['use_pango == 1', {
+          'dependencies': [
+            '../build/linux/system.gyp:fontconfig',
+            '../build/linux/system.gyp:pangocairo',
+          ],
+          'sources': [
+            'gfx/platform_font_pango_unittest.cc',
+          ],
+          'conditions': [
+            ['linux_use_tcmalloc==1', {
+               'dependencies': [
+                 '../base/allocator/allocator.gyp:allocator',
+               ],
+            }],
+            ['toolkit_views==1', {
+              'sources!': [
+                'browser/ui/gtk/gtk_expanded_container_unittest.cc',
+              ],
+            }],
+          ],
+        }],
+        ['use_x11==1', {
+          'dependencies': [
+            '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+          ],
+        }],
+        ['toolkit_uses_gtk == 1', {
+          'sources': [
+            'base/dragdrop/gtk_dnd_util_unittest.cc',
+          ],
+          'dependencies': [
+            '../build/linux/system.gyp:gtk',
+          ],
+        }],
+        ['OS=="android" or OS=="ios"', {
+          'sources!': [
+            'gfx/render_text_unittest.cc',
+          ],
+        }],
+        ['OS!="win" or use_aura==0', {
+          'sources!': [
+            'base/view_prop_unittest.cc',
+          ],
+        }],
+        ['use_x11==1 and use_aura==1',  {
+          'sources': [
+            'base/cursor/cursor_loader_x11_unittest.cc',
+          ],
+        }],
+        ['use_aura==1 or toolkit_views==1',  {
+          'sources': [
+            'base/dragdrop/os_exchange_data_unittest.cc',
+            'events/gestures/velocity_calculator_unittest.cc',
+          ],
+        }, {
+          'sources!': [
+            'events/event_dispatcher_unittest.cc',
+            'events/event_unittest.cc',
+          ],
+        }],
+        ['use_aura==1', {
+          'sources!': [
+            'base/dialogs/select_file_dialog_win_unittest.cc',
+            'base/dragdrop/os_exchange_data_win_unittest.cc',
+            'gfx/screen_unittest.cc',
+          ],
+        }],
+        ['use_ozone==1', {
+          'dependencies': [
+          '<(DEPTH)/build/linux/system.gyp:dridrm',
+          ],
+        }],
+        ['chromeos==1', {
+          'sources!': [
+            'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
+          ],
+        }],
+      ],
+      'target_conditions': [
+        ['OS == "ios"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^base/l10n/l10n_util_mac_unittest\\.mm$'],
+          ],
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    # Special target to wrap a gtest_target_type==shared_library
+    # ui_unittests into an android apk for execution.
+    # See base.gyp for TODO(jrg)s about this strategy.
+    ['OS == "android" and gtest_target_type == "shared_library"', {
+      'targets': [
+        {
+          'target_name': 'ui_unittests_apk',
+          'type': 'none',
+          'dependencies': [
+            'ui_unittests',
+          ],
+          'variables': {
+            'test_suite_name': 'ui_unittests',
+            'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ui_unittests<(SHARED_LIB_SUFFIX)',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
deleted file mode 100644
index 6976f50..0000000
--- a/ui/ui_unittests.gypi
+++ /dev/null
@@ -1,379 +0,0 @@
-# Copyright (c) 2012 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': 'ui_test_support',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../skia/skia.gyp:skia',
-        '../testing/gtest.gyp:gtest',
-        'events/events.gyp:events',
-        'gfx/gfx.gyp:gfx',
-      ],
-      'sources': [
-        'base/test/cocoa_test_event_utils.h',
-        'base/test/cocoa_test_event_utils.mm',
-        'base/test/ui_cocoa_test_helper.h',
-        'base/test/ui_cocoa_test_helper.mm',
-        'base/test/ui_controls.h',
-        'base/test/ui_controls_aura.cc',
-        'base/test/ui_controls_gtk.cc',
-        'base/test/ui_controls_internal_win.cc',
-        'base/test/ui_controls_internal_win.h',
-        'base/test/ui_controls_mac.mm',
-        'base/test/ui_controls_win.cc',
-      ],
-      'include_dirs': [
-        '../',
-      ],
-      'conditions': [
-        ['OS!="ios"', {
-          'type': 'static_library',
-          'includes': [ 'base/ime/ime_test_support.gypi' ],
-        }, {  # OS=="ios"
-          # None of the sources in this target are built on iOS, resulting in
-          # link errors when building targets that depend on this target
-          # because the static library isn't found. If this target is changed
-          # to have sources that are built on iOS, the target should be changed
-          # to be of type static_library on all platforms.
-          'type': 'none',
-          # The cocoa files don't apply to iOS.
-          'sources/': [['exclude', 'cocoa']],
-        }],
-        ['chromeos==1', {
-          'dependencies': [
-            '../chromeos/chromeos.gyp:chromeos_test_support_without_gmock',
-            '../skia/skia.gyp:skia',
-          ],
-        }],
-        ['use_aura==1', {
-          'sources!': [
-            'base/test/ui_controls_win.cc',
-          ],
-        }],
-      ],
-    },
-    {
-      'target_name': 'run_ui_unittests',
-      'type': 'static_library',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/base.gyp:test_support_base',
-        'ui',
-      ],
-      'sources': [
-        'test/test_suite.cc',
-        'test/test_suite.h',
-        'test/run_all_unittests.cc',
-      ],
-    },
-    {
-      'target_name': 'ui_unittests',
-      'type': '<(gtest_target_type)',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/base.gyp:test_support_base',
-        '../skia/skia.gyp:skia',
-        '../testing/gmock.gyp:gmock',
-        '../testing/gtest.gyp:gtest',
-        '../third_party/icu/icu.gyp:icui18n',
-        '../third_party/icu/icu.gyp:icuuc',
-        '../third_party/libpng/libpng.gyp:libpng',
-        '../url/url.gyp:url_lib',
-        'base/strings/ui_strings.gyp:ui_strings',
-        'events/events.gyp:events',
-        'keycode_converter',
-        'run_ui_unittests',
-        'shell_dialogs',
-        'ui',
-        'ui_resources',
-        'ui_test_support',
-      ],
-      # iOS uses a small subset of ui. common_sources are the only files that
-      # are built on iOS.
-      'common_sources' : [
-        'base/layout_unittest.cc',
-        'base/l10n/l10n_util_mac_unittest.mm',
-        'base/l10n/l10n_util_unittest.cc',
-        'base/l10n/l10n_util_win_unittest.cc',
-        'base/l10n/time_format_unittest.cc',
-        'base/models/tree_node_iterator_unittest.cc',
-        'base/resource/data_pack_literal.cc',
-        'base/resource/data_pack_unittest.cc',
-        'base/resource/resource_bundle_unittest.cc',
-        'gfx/animation/animation_container_unittest.cc',
-        'gfx/animation/animation_unittest.cc',
-        'gfx/animation/multi_animation_unittest.cc',
-        'gfx/animation/slide_animation_unittest.cc',
-        'gfx/box_unittest.cc',
-        'gfx/codec/png_codec_unittest.cc',
-        'gfx/color_utils_unittest.cc',
-        'gfx/display_unittest.cc',
-        'gfx/font_unittest.cc',
-        'gfx/image/image_family_unittest.cc',
-        'gfx/image/image_skia_unittest.cc',
-        'gfx/image/image_unittest.cc',
-        'gfx/image/image_unittest_util.cc',
-        'gfx/image/image_unittest_util.h',
-        'gfx/image/image_unittest_util_ios.mm',
-        'gfx/image/image_unittest_util_mac.mm',
-        'gfx/insets_unittest.cc',
-        'gfx/matrix3_unittest.cc',
-        'gfx/point_unittest.cc',
-        'gfx/point3_unittest.cc',
-        'gfx/quad_unittest.cc',
-        'gfx/range/range_mac_unittest.mm',
-        'gfx/range/range_unittest.cc',
-        'gfx/range/range_win_unittest.cc',
-        'gfx/rect_unittest.cc',
-        'gfx/safe_integer_conversions_unittest.cc',
-        'gfx/screen_unittest.cc',
-        'gfx/shadow_value_unittest.cc',
-        'gfx/size_unittest.cc',
-        'gfx/skbitmap_operations_unittest.cc',
-        'gfx/text_elider_unittest.cc',
-        'gfx/text_utils_unittest.cc',
-        'gfx/vector2d_unittest.cc',
-        'gfx/vector3d_unittest.cc',
-      ],
-      'all_sources': [
-        '<@(_common_sources)',
-        'base/accelerators/accelerator_manager_unittest.cc',
-        'base/accelerators/menu_label_accelerator_util_linux_unittest.cc',
-        'base/clipboard/clipboard_unittest.cc',
-        'base/clipboard/custom_data_helper_unittest.cc',
-        'base/cocoa/base_view_unittest.mm',
-        'base/cocoa/cocoa_event_utils_unittest.mm',
-        'base/cocoa/controls/blue_label_button_unittest.mm',
-        'base/cocoa/controls/hover_image_menu_button_unittest.mm',
-        'base/cocoa/controls/hyperlink_button_cell_unittest.mm',
-        'base/cocoa/events_mac_unittest.mm',
-        'base/cocoa/focus_tracker_unittest.mm',
-        'base/cocoa/fullscreen_window_manager_unittest.mm',
-        'base/cocoa/hover_image_button_unittest.mm',
-        'base/cocoa/menu_controller_unittest.mm',
-        'base/cocoa/nsgraphics_context_additions_unittest.mm',
-        'base/cocoa/tracking_area_unittest.mm',
-        'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
-        'base/gtk/gtk_expanded_container_unittest.cc',
-        'base/gtk/gtk_im_context_util_unittest.cc',
-        'base/keycodes/keycode_converter_unittest.cc',
-        'base/models/list_model_unittest.cc',
-        'base/models/list_selection_model_unittest.cc',
-        'base/models/tree_node_model_unittest.cc',
-        'base/test/data/resource.h',
-        'base/text/bytes_formatting_unittest.cc',
-        'base/view_prop_unittest.cc',
-        'base/webui/web_ui_util_unittest.cc',
-        'events/event_dispatcher_unittest.cc',
-        'events/event_unittest.cc',
-        'events/latency_info_unittest.cc',
-        'events/ozone/evdev/touch_event_converter_unittest.cc',
-        'gfx/blit_unittest.cc',
-        'gfx/break_list_unittest.cc',
-        'gfx/canvas_unittest.cc',
-        'gfx/canvas_unittest_mac.mm',
-        'gfx/codec/jpeg_codec_unittest.cc',
-        'gfx/color_analysis_unittest.cc',
-        'gfx/font_list_unittest.cc',
-        'gfx/image/image_mac_unittest.mm',
-        'gfx/image/image_util_unittest.cc',
-        'gfx/ozone/impl/hardware_display_controller_ozone_unittest.cc',
-        'gfx/ozone/impl/software_surface_factory_ozone_unittest.cc',
-        'gfx/ozone/impl/software_surface_ozone_unittest.cc',
-        'gfx/platform_font_mac_unittest.mm',
-        'gfx/render_text_unittest.cc',
-        'gfx/sequential_id_generator_unittest.cc',
-        'gfx/transform_util_unittest.cc',
-        'gfx/utf16_indexing_unittest.cc',
-        'shell_dialogs/select_file_dialog_win_unittest.cc',
-      ],
-      'include_dirs': [
-        '../',
-      ],
-      'conditions': [
-        ['OS!="ios"', {
-          'sources' : ['<@(_all_sources)'],
-          'includes': [
-            'base/ime/ime_unittests.gypi',
-          ],
-        }, {  # OS=="ios"
-          'sources' : [
-            '<@(_common_sources)',
-          ],
-          # The ResourceBundle unittest expects a locale.pak file to exist in
-          # the bundle for English-US. Copy it in from where it was generated
-          # by ui_strings.gyp:ui_unittest_strings.
-          'mac_bundle_resources': [
-            '<(PRODUCT_DIR)/ui_unittests_strings/en.lproj/locale.pak',
-          ],
-        }],
-        ['OS == "win"', {
-          'sources': [
-            'test/ui_unittests.rc',
-            'base/dragdrop/os_exchange_data_win_unittest.cc',
-            'base/win/hwnd_subclass_unittest.cc',
-            'gfx/font_fallback_win_unittest.cc',
-            'gfx/icon_util_unittest.cc',
-            'gfx/platform_font_win_unittest.cc',
-          ],
-          'include_dirs': [
-            '../..',
-            '../third_party/wtl/include',
-          ],
-          'msvs_settings': {
-            'VCLinkerTool': {
-              'DelayLoadDLLs': [
-                'd2d1.dll',
-                'd3d10_1.dll',
-              ],
-              'AdditionalDependencies': [
-                'd2d1.lib',
-                'd3d10_1.lib',
-              ],
-            },
-          },
-          'link_settings': {
-            'libraries': [
-              '-limm32.lib',
-              '-loleacc.lib',
-            ],
-          },
-          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-          'msvs_disabled_warnings': [ 4267, ],
-        }],
-        ['OS == "linux" and toolkit_views==1', {
-          'sources': [
-            'events/x/events_x_unittest.cc',
-          ],
-        }],
-        ['OS != "mac" and OS != "ios"', {
-          'sources': [
-            'gfx/transform_unittest.cc',
-            'gfx/interpolated_transform_unittest.cc',
-          ],
-        }],
-        ['OS == "android" and gtest_target_type == "shared_library"', {
-          'dependencies': [
-            '../testing/android/native_test.gyp:native_test_native_code',
-          ],
-        }],
-        ['use_glib == 1 or OS == "ios"', {
-          'dependencies': [
-            'base/strings/ui_strings.gyp:ui_unittest_strings',
-          ],
-        }],
-        ['use_pango == 1', {
-          'dependencies': [
-            '../build/linux/system.gyp:fontconfig',
-            '../build/linux/system.gyp:pangocairo',
-          ],
-          'sources': [
-            'gfx/platform_font_pango_unittest.cc',
-          ],
-          'conditions': [
-            ['linux_use_tcmalloc==1', {
-               'dependencies': [
-                 '../base/allocator/allocator.gyp:allocator',
-               ],
-            }],
-            ['toolkit_views==1', {
-              'sources!': [
-                'browser/ui/gtk/gtk_expanded_container_unittest.cc',
-              ],
-            }],
-          ],
-        }],
-        ['use_x11==1', {
-          'dependencies': [
-            '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
-          ],
-        }],
-        ['toolkit_uses_gtk == 1', {
-          'sources': [
-            'base/dragdrop/gtk_dnd_util_unittest.cc',
-          ],
-          'dependencies': [
-            '../build/linux/system.gyp:gtk',
-          ],
-        }],
-        ['OS=="android" or OS=="ios"', {
-          'sources!': [
-            'gfx/render_text_unittest.cc',
-          ],
-        }],
-        ['OS!="win" or use_aura==0', {
-          'sources!': [
-            'base/view_prop_unittest.cc',
-          ],
-        }],
-        ['use_x11==1 and use_aura==1',  {
-          'sources': [
-            'base/cursor/cursor_loader_x11_unittest.cc',
-          ],
-        }],
-        ['use_aura==1 or toolkit_views==1',  {
-          'sources': [
-            'base/dragdrop/os_exchange_data_unittest.cc',
-            'events/gestures/velocity_calculator_unittest.cc',
-          ],
-        }, {
-          'sources!': [
-            'events/event_dispatcher_unittest.cc',
-            'events/event_unittest.cc',
-          ],
-        }],
-        ['use_aura==1', {
-          'sources!': [
-            'base/dialogs/select_file_dialog_win_unittest.cc',
-            'base/dragdrop/os_exchange_data_win_unittest.cc',
-            'gfx/screen_unittest.cc',
-          ],
-        }],
-        ['use_ozone==1', {
-          'dependencies': [
-          '<(DEPTH)/build/linux/system.gyp:dridrm',
-          ],
-        }],
-        ['chromeos==1', {
-          'sources!': [
-            'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
-          ],
-        }],
-      ],
-      'target_conditions': [
-        ['OS == "ios"', {
-          'sources/': [
-            # Pull in specific Mac files for iOS (which have been filtered out
-            # by file name rules).
-            ['include', '^base/l10n/l10n_util_mac_unittest\\.mm$'],
-          ],
-        }],
-      ],
-    },
-  ],
-  'conditions': [
-    # Special target to wrap a gtest_target_type==shared_library
-    # ui_unittests into an android apk for execution.
-    # See base.gyp for TODO(jrg)s about this strategy.
-    ['OS == "android" and gtest_target_type == "shared_library"', {
-      'targets': [
-        {
-          'target_name': 'ui_unittests_apk',
-          'type': 'none',
-          'dependencies': [
-            'ui_unittests',
-          ],
-          'variables': {
-            'test_suite_name': 'ui_unittests',
-            'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ui_unittests<(SHARED_LIB_SUFFIX)',
-          },
-          'includes': [ '../build/apk_test.gypi' ],
-        },
-      ],
-    }],
-  ],
-}
diff --git a/ui/views/controls/menu/display_change_listener_aura.cc b/ui/views/controls/menu/display_change_listener_aura.cc
index 1cec651..e6df560 100644
--- a/ui/views/controls/menu/display_change_listener_aura.cc
+++ b/ui/views/controls/menu/display_change_listener_aura.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/views/controls/menu/menu_runner.h"
-
-#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
+#include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/widget/widget.h"
 
 namespace views {
@@ -28,7 +27,7 @@
 
  private:
   MenuRunner* menu_runner_;
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(AuraDisplayChangeListener);
 };
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index a6258b6..0035ae3 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -37,6 +37,7 @@
 #include "ui/views/view_constants.h"
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/root_view.h"
+#include "ui/views/widget/tooltip_manager.h"
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_AURA)
@@ -1578,10 +1579,17 @@
   state_.open_leading.push_back(resulting_direction);
   bool do_capture = (!did_capture_ && blocking_run_);
   showing_submenu_ = true;
-  if (show)
+  if (show) {
+    // Menus are the only place using kGroupingPropertyKey, so any value (other
+    // than 0) is fine.
+    const int kGroupingId = 1001;
     item->GetSubmenu()->ShowAt(owner_, bounds, do_capture);
-  else
+    item->GetSubmenu()->GetWidget()->SetNativeWindowProperty(
+        TooltipManager::kGroupingPropertyKey,
+        reinterpret_cast<void*>(kGroupingId));
+  } else {
     item->GetSubmenu()->Reposition(bounds);
+  }
   showing_submenu_ = false;
 }
 
@@ -2139,8 +2147,9 @@
   if (event.IsMouseEvent()) {
     clone.reset(new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event)));
   } else if (event.IsGestureEvent()) {
-    const ui::GestureEvent& ge = static_cast<const ui::GestureEvent&>(event);
-    clone.reset(new ui::GestureEvent(ge));
+    // TODO(rbyers): Gesture event repost is tricky to get right
+    // crbug.com/170987.
+    return;
   } else {
     NOTREACHED();
     return;
diff --git a/ui/views/controls/menu/menu_controller_aura.cc b/ui/views/controls/menu/menu_controller_aura.cc
index c65c97f..48bf311 100644
--- a/ui/views/controls/menu/menu_controller_aura.cc
+++ b/ui/views/controls/menu/menu_controller_aura.cc
@@ -9,7 +9,7 @@
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/dispatcher_client.h"
 #include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/gfx/screen.h"
 #include "ui/views/widget/widget.h"
@@ -27,7 +27,7 @@
       public ui::EventHandler {
  public:
   ActivationChangeObserverImpl(MenuController* controller,
-                               aura::RootWindow* root)
+                               aura::Window* root)
       : controller_(controller),
         root_(root) {
     aura::client::GetActivationClient(root_)->AddObserver(this);
@@ -71,12 +71,12 @@
   }
 
   MenuController* controller_;
-  aura::RootWindow* root_;
+  aura::Window* root_;
 
   DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
 };
 
-aura::RootWindow* GetOwnerRootWindow(views::Widget* owner) {
+aura::Window* GetOwnerRootWindow(views::Widget* owner) {
   return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
 }
 
@@ -84,7 +84,7 @@
 
 void MenuController::RunMessageLoop(bool nested_menu) {
   // |owner_| may be NULL.
-  aura::RootWindow* root = GetOwnerRootWindow(owner_);
+  aura::Window* root = GetOwnerRootWindow(owner_);
   if (root) {
     scoped_ptr<ActivationChangeObserverImpl> observer;
     if (!nested_menu)
@@ -100,13 +100,13 @@
 }
 
 bool MenuController::ShouldQuitNow() const {
-  aura::RootWindow* root = GetOwnerRootWindow(owner_);
+  aura::Window* root = GetOwnerRootWindow(owner_);
   return !aura::client::GetDragDropClient(root) ||
       !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
 }
 
 gfx::Screen* MenuController::GetScreen() {
-  aura::RootWindow* root = GetOwnerRootWindow(owner_);
+  aura::Window* root = GetOwnerRootWindow(owner_);
   return root ?
       gfx::Screen::GetScreenFor(root) : gfx::Screen::GetNativeScreen();
 }
diff --git a/ui/views/controls/menu/menu_host.cc b/ui/views/controls/menu/menu_host.cc
index f9dd5b2..0852107 100644
--- a/ui/views/controls/menu/menu_host.cc
+++ b/ui/views/controls/menu/menu_host.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/controls/menu/menu_host.h"
 
+#include "base/auto_reset.h"
 #include "base/debug/trace_event.h"
 #include "ui/gfx/path.h"
 #include "ui/native_theme/native_theme.h"
@@ -73,11 +74,10 @@
 void MenuHost::ShowMenuHost(bool do_capture) {
   // Doing a capture may make us get capture lost. Ignore it while we're in the
   // process of showing.
-  ignore_capture_lost_ = true;
+  base::AutoReset<bool> reseter(&ignore_capture_lost_, true);
   Show();
   if (do_capture)
     native_widget_private()->SetCapture();
-  ignore_capture_lost_ = false;
 }
 
 void MenuHost::HideMenuHost() {
diff --git a/ui/views/controls/menu/submenu_view.h b/ui/views/controls/menu/submenu_view.h
index 5100cf8..19e0d46 100644
--- a/ui/views/controls/menu/submenu_view.h
+++ b/ui/views/controls/menu/submenu_view.h
@@ -84,9 +84,7 @@
 
   // Shows the menu at the specified location. Coordinates are in screen
   // coordinates. max_width gives the max width the view should be.
-  void ShowAt(Widget* parent,
-              const gfx::Rect& bounds,
-              bool do_capture);
+  void ShowAt(Widget* parent, const gfx::Rect& bounds, bool do_capture);
 
   // Resets the bounds of the submenu to |bounds|.
   void Reposition(const gfx::Rect& bounds);
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc
index aafbee5..821a9e3 100644
--- a/ui/views/controls/table/table_header.cc
+++ b/ui/views/controls/table/table_header.cc
@@ -178,46 +178,23 @@
 }
 
 bool TableHeader::OnMousePressed(const ui::MouseEvent& event) {
-  if (event.IsOnlyLeftMouseButton()) {
-    const int index = GetResizeColumn(GetMirroredXInView(event.x()));
-    if (index != -1) {
-      DCHECK(!is_resizing());
-      resize_details_.reset(new ColumnResizeDetails);
-      resize_details_->column_index = index;
-      resize_details_->initial_x = event.root_location().x();
-      resize_details_->initial_width =
-          table_->visible_columns()[index].width;
-    }
+  if (event.IsOnlyLeftMouseButton() && StartResize(event))
     return true;
-  }
+
   // Return false so that context menus on ancestors work.
   return false;
 }
 
 bool TableHeader::OnMouseDragged(const ui::MouseEvent& event) {
-  if (is_resizing()) {
-    const int scale = base::i18n::IsRTL() ? -1 : 1;
-    const int delta = scale *
-        (event.root_location().x() - resize_details_->initial_x);
-    table_->SetVisibleColumnWidth(
-        resize_details_->column_index,
-        std::max(kMinColumnWidth, resize_details_->initial_width + delta));
-  }
+  ContinueResize(event);
   return true;
 }
 
 void TableHeader::OnMouseReleased(const ui::MouseEvent& event) {
   const bool was_resizing = resize_details_ != NULL;
   resize_details_.reset();
-  if (!was_resizing && event.IsOnlyLeftMouseButton() &&
-      !table_->visible_columns().empty()) {
-    const int x = GetMirroredXInView(event.x());
-    const int index = GetClosestVisibleColumnIndex(table_, x);
-    const TableView::VisibleColumn& column(table_->visible_columns()[index]);
-    if (x >= column.x && x < column.x + column.width && event.y() >= 0 &&
-        event.y() < height())
-      table_->ToggleSortOrder(index);
-  }
+  if (!was_resizing && event.IsOnlyLeftMouseButton())
+    ToggleSortOrder(event);
 }
 
 void TableHeader::OnMouseCaptureLost() {
@@ -228,6 +205,66 @@
   resize_details_.reset();
 }
 
+void TableHeader::OnGestureEvent(ui::GestureEvent* event) {
+  switch (event->type()) {
+    case ui::ET_GESTURE_TAP:
+      if (!resize_details_.get())
+        ToggleSortOrder(*event);
+      break;
+    case ui::ET_GESTURE_SCROLL_BEGIN:
+      StartResize(*event);
+      break;
+    case ui::ET_GESTURE_SCROLL_UPDATE:
+      ContinueResize(*event);
+      break;
+    case ui::ET_GESTURE_SCROLL_END:
+      resize_details_.reset();
+      break;
+    default:
+      return;
+  }
+  event->SetHandled();
+}
+
+bool TableHeader::StartResize(const ui::LocatedEvent& event) {
+  if (is_resizing())
+    return false;
+
+  const int index = GetResizeColumn(GetMirroredXInView(event.x()));
+  if (index == -1)
+    return false;
+
+  resize_details_.reset(new ColumnResizeDetails);
+  resize_details_->column_index = index;
+  resize_details_->initial_x = event.root_location().x();
+  resize_details_->initial_width = table_->visible_columns()[index].width;
+  return true;
+}
+
+void TableHeader::ContinueResize(const ui::LocatedEvent& event) {
+  if (!is_resizing())
+    return;
+
+  const int scale = base::i18n::IsRTL() ? -1 : 1;
+  const int delta = scale *
+      (event.root_location().x() - resize_details_->initial_x);
+  table_->SetVisibleColumnWidth(
+      resize_details_->column_index,
+      std::max(kMinColumnWidth, resize_details_->initial_width + delta));
+}
+
+void TableHeader::ToggleSortOrder(const ui::LocatedEvent& event) {
+  if (table_->visible_columns().empty())
+    return;
+
+  const int x = GetMirroredXInView(event.x());
+  const int index = GetClosestVisibleColumnIndex(table_, x);
+  const TableView::VisibleColumn& column(table_->visible_columns()[index]);
+  if (x >= column.x && x < column.x + column.width && event.y() >= 0 &&
+      event.y() < height())
+    table_->ToggleSortOrder(index);
+}
+
 int TableHeader::GetResizeColumn(int x) const {
   const Columns& columns(table_->visible_columns());
   if (columns.empty())
diff --git a/ui/views/controls/table/table_header.h b/ui/views/controls/table/table_header.h
index ef10603..2aa280d 100644
--- a/ui/views/controls/table/table_header.h
+++ b/ui/views/controls/table/table_header.h
@@ -36,6 +36,7 @@
   virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
   virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
   virtual void OnMouseCaptureLost() OVERRIDE;
+  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
 
  private:
   // Used to track the column being resized.
@@ -52,6 +53,17 @@
     int initial_width;
   };
 
+  // If not already resizing and |event| is over a resizable column starts
+  // resizing.
+  bool StartResize(const ui::LocatedEvent& event);
+
+  // Continues a resize operation. Does nothing if not in the process of
+  // resizing.
+  void ContinueResize(const ui::LocatedEvent& event);
+
+  // Toggles the sort order of the column at the location in |event|.
+  void ToggleSortOrder(const ui::LocatedEvent& event);
+
   // Returns the column to resize given the specified x-coordinate, or -1 if |x|
   // is not in the resize range of any columns.
   int GetResizeColumn(int x) const;
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index c655eb6..cf9c0ff 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -389,6 +389,20 @@
   return true;
 }
 
+void TableView::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->type() != ui::ET_GESTURE_TAP)
+    return;
+
+  const int row = event->y() / row_height_;
+  if (row < 0 || row >= RowCount())
+    return;
+
+  event->StopPropagation();
+  ui::ListSelectionModel new_model;
+  ConfigureSelectionModelForEvent(*event, &new_model);
+  SetSelectionModel(new_model);
+}
+
 bool TableView::GetTooltipText(const gfx::Point& p,
                                string16* tooltip) const {
   return GetTooltipImpl(p, tooltip, NULL);
@@ -792,7 +806,7 @@
 }
 
 void TableView::ConfigureSelectionModelForEvent(
-    const ui::MouseEvent& event,
+    const ui::LocatedEvent& event,
     ui::ListSelectionModel* model) const {
   const int view_index = event.y() / row_height_;
   DCHECK(view_index >= 0 && view_index < RowCount());
diff --git a/ui/views/controls/table/table_view.h b/ui/views/controls/table/table_view.h
index 63b7dc7..c2a9472 100644
--- a/ui/views/controls/table/table_view.h
+++ b/ui/views/controls/table/table_view.h
@@ -169,6 +169,7 @@
   virtual gfx::Size GetPreferredSize() OVERRIDE;
   virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
   virtual bool GetTooltipText(const gfx::Point& p,
                               string16* tooltip) const OVERRIDE;
   virtual bool GetTooltipTextOrigin(const gfx::Point& p,
@@ -270,8 +271,8 @@
   // Advances the selection (from the active index) in the specified direction.
   void AdvanceSelection(AdvanceDirection direction);
 
-  // Sets |model| appropriately based on a mouse event.
-  void ConfigureSelectionModelForEvent(const ui::MouseEvent& event,
+  // Sets |model| appropriately based on a event.
+  void ConfigureSelectionModelForEvent(const ui::LocatedEvent& event,
                                        ui::ListSelectionModel* model) const;
 
   // Set the selection state of row at |view_index| to |select|, additionally
diff --git a/ui/views/controls/table/table_view_unittest.cc b/ui/views/controls/table/table_view_unittest.cc
index aeba7f6..b1fe88a 100644
--- a/ui/views/controls/table/table_view_unittest.cc
+++ b/ui/views/controls/table/table_view_unittest.cc
@@ -195,6 +195,15 @@
     table_->OnMousePressed(pressed);
   }
 
+  void TapOnRow(int row) {
+    const int y = row * table_->row_height();
+    const ui::GestureEventDetails event_details(ui::ET_GESTURE_TAP,
+                                                .0f, .0f);
+    ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, y, 0, base::TimeDelta(),
+                         event_details, 1);
+    table_->OnGestureEvent(&tap);
+  }
+
   // Returns the state of the selection model as a string. The format is:
   // 'active=X anchor=X selection=X X X...'.
   std::string SelectionStateAsString() const {
@@ -291,6 +300,25 @@
   EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
 }
 
+// Verifies resizing a column works with a gesture.
+TEST_F(TableViewTest, ResizeViaGesture) {
+  const int x = table_->visible_columns()[0].width;
+  EXPECT_NE(0, x);
+  // Drag the mouse 1 pixel to the left.
+  const ui::GestureEventDetails event_details(ui::ET_GESTURE_SCROLL_BEGIN,
+                                              .0f, .0f);
+  ui::GestureEvent scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, x, 0, 0,
+                                base::TimeDelta(), event_details, 1);
+  helper_->header()->OnGestureEvent(&scroll_begin);
+  ui::GestureEvent scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, x - 1, 0,
+                                 0, base::TimeDelta(), event_details, 1);
+  helper_->header()->OnGestureEvent(&scroll_update);
+
+  // This should shrink the first column and pull the second column in.
+  EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
+  EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
+}
+
 // Assertions for table sorting.
 TEST_F(TableViewTest, Sort) {
   // Toggle the sort order of the first column, shouldn't change anything.
@@ -504,6 +532,22 @@
   table_->SetObserver(NULL);
 }
 
+// Verifies selection works by way of a gesture.
+TEST_F(TableViewTest, SelectOnTap) {
+  // Initially no selection.
+  EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
+
+  TableViewObserverImpl observer;
+  table_->SetObserver(&observer);
+
+  // Click on the first row, should select it.
+  TapOnRow(0);
+  EXPECT_EQ(1, observer.GetChangedCountAndClear());
+  EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
+
+  table_->SetObserver(NULL);
+}
+
 // Verifies up/down correctly navigates through groups.
 TEST_F(TableViewTest, KeyUpDown) {
   // Configure the grouper so that there are three groups:
diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc
index b72c0eb..eae8f88 100644
--- a/ui/views/controls/textfield/native_textfield_views.cc
+++ b/ui/views/controls/textfield/native_textfield_views.cc
@@ -745,6 +745,10 @@
 }
 
 bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
+  TextfieldController* controller = textfield_->GetController();
+  if (controller && controller->HandlesCommand(command_id))
+    return controller->IsCommandIdEnabled(command_id);
+
   bool editable = !textfield_->read_only();
   string16 result;
   switch (command_id) {
@@ -763,7 +767,7 @@
     case IDS_APP_SELECT_ALL:
       return !model_->GetText().empty();
     default:
-      return textfield_->GetController()->IsCommandIdEnabled(command_id);
+      return controller->IsCommandIdEnabled(command_id);
   }
 }
 
diff --git a/ui/views/controls/textfield/native_textfield_views_unittest.cc b/ui/views/controls/textfield/native_textfield_views_unittest.cc
index 01ef578..88e43b1 100644
--- a/ui/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/ui/views/controls/textfield/native_textfield_views_unittest.cc
@@ -1902,15 +1902,17 @@
       kStringPoint, kStringPoint));
 }
 
-TEST_F(NativeTextfieldViewsTest, GetTextfieldBaseline_FontFallbackTest) {
 #if defined(OS_WIN)
-  // This test fails on some versions of Windows because two different strings
-  // have the same baseline.
-  if (base::win::GetVersion() <= base::win::VERSION_XP ||
-      base::win::VERSION_WIN8 <= base::win::GetVersion())
-    return;
+// This test fails on some versions of Windows because two different strings
+// have the same baseline.
+#define MAYBE_GetTextfieldBaseline_FontFallbackTest \
+    DISABLED_GetTextfieldBaseline_FontFallbackTest
+#else
+#define MAYBE_GetTextfieldBaseline_FontFallbackTest \
+    GetTextfieldBaseline_FontFallbackTest
 #endif
 
+TEST_F(NativeTextfieldViewsTest, MAYBE_GetTextfieldBaseline_FontFallbackTest) {
   InitTextfield(Textfield::STYLE_DEFAULT);
   textfield_->SetText(UTF8ToUTF16("abc"));
   const int old_baseline = textfield_->GetBaseline();
diff --git a/ui/views/controls/webview/unhandled_keyboard_event_handler_aurax11.cc b/ui/views/controls/webview/unhandled_keyboard_event_handler_aurax11.cc
deleted file mode 100644
index 7e09af9..0000000
--- a/ui/views/controls/webview/unhandled_keyboard_event_handler_aurax11.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
-
-#include "base/logging.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "ui/events/event.h"
-#include "ui/views/focus/focus_manager.h"
-
-using content::NativeWebKeyboardEvent;
-
-namespace views {
-
-UnhandledKeyboardEventHandler::UnhandledKeyboardEventHandler() {
-}
-
-void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
-    const NativeWebKeyboardEvent& event,
-    FocusManager* focus_manager) {
-  if (!focus_manager) {
-    NOTREACHED();
-    return;
-  }
-  if (event.os_event && !event.skip_in_browser)
-    focus_manager->OnKeyEvent(*static_cast<ui::KeyEvent*>(event.os_event));
-}
-
-}  // namespace views
diff --git a/ui/views/controls/webview/unhandled_keyboard_event_handler_linux.cc b/ui/views/controls/webview/unhandled_keyboard_event_handler_linux.cc
new file mode 100644
index 0000000..2776d41
--- /dev/null
+++ b/ui/views/controls/webview/unhandled_keyboard_event_handler_linux.cc
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
+
+#include "base/logging.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "ui/events/event.h"
+#include "ui/views/focus/focus_manager.h"
+
+using content::NativeWebKeyboardEvent;
+
+namespace views {
+
+UnhandledKeyboardEventHandler::UnhandledKeyboardEventHandler() {
+}
+
+void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
+    const NativeWebKeyboardEvent& event,
+    FocusManager* focus_manager) {
+  if (!focus_manager) {
+    NOTREACHED();
+    return;
+  }
+  if (event.os_event && !event.skip_in_browser)
+    focus_manager->OnKeyEvent(*static_cast<ui::KeyEvent*>(event.os_event));
+}
+
+}  // namespace views
diff --git a/ui/views/controls/webview/webview.gyp b/ui/views/controls/webview/webview.gyp
index 2fde653..6d74ef2 100644
--- a/ui/views/controls/webview/webview.gyp
+++ b/ui/views/controls/webview/webview.gyp
@@ -29,7 +29,7 @@
       'sources': [
         'unhandled_keyboard_event_handler.cc',
         'unhandled_keyboard_event_handler.h',
-        'unhandled_keyboard_event_handler_aurax11.cc',
+        'unhandled_keyboard_event_handler_linux.cc',
         'unhandled_keyboard_event_handler_win.cc',
         'web_dialog_view.cc',
         'web_dialog_view.h',
diff --git a/ui/views/corewm/capture_controller.cc b/ui/views/corewm/capture_controller.cc
index 1276c82..59ff199 100644
--- a/ui/views/corewm/capture_controller.cc
+++ b/ui/views/corewm/capture_controller.cc
@@ -13,13 +13,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // CaptureController, public:
 
-void CaptureController::Attach(aura::RootWindow* root) {
+void CaptureController::Attach(aura::Window* root) {
   DCHECK_EQ(0u, root_windows_.count(root));
   root_windows_.insert(root);
   aura::client::SetCaptureClient(root, this);
 }
 
-void CaptureController::Detach(aura::RootWindow* root) {
+void CaptureController::Detach(aura::Window* root) {
   root_windows_.erase(root);
   aura::client::SetCaptureClient(root, NULL);
 }
@@ -36,7 +36,7 @@
   DCHECK(!capture_window_ || capture_window_->GetRootWindow());
 
   aura::Window* old_capture_window = capture_window_;
-  aura::RootWindow* old_capture_root = old_capture_window ?
+  aura::Window* old_capture_root = old_capture_window ?
       old_capture_window->GetRootWindow() : NULL;
 
   // Copy the list in case it's modified out from under us.
@@ -57,19 +57,20 @@
 
   for (RootWindows::const_iterator i = root_windows.begin();
        i != root_windows.end(); ++i) {
-    aura::client::CaptureDelegate* delegate = *i;
+    aura::client::CaptureDelegate* delegate = (*i)->GetDispatcher();
     delegate->UpdateCapture(old_capture_window, new_capture_window);
   }
 
-  aura::RootWindow* capture_root =
+  aura::Window* capture_root =
       capture_window_ ? capture_window_->GetRootWindow() : NULL;
   if (capture_root != old_capture_root) {
     if (old_capture_root) {
-      aura::client::CaptureDelegate* delegate = old_capture_root;
+      aura::client::CaptureDelegate* delegate =
+          old_capture_root->GetDispatcher();
       delegate->ReleaseNativeCapture();
     }
     if (capture_root) {
-      aura::client::CaptureDelegate* delegate = capture_root;
+      aura::client::CaptureDelegate* delegate = capture_root->GetDispatcher();
       delegate->SetNativeCapture();
     }
   }
@@ -101,7 +102,7 @@
 // static
 CaptureController* ScopedCaptureClient::capture_controller_ = NULL;
 
-ScopedCaptureClient::ScopedCaptureClient(aura::RootWindow* root)
+ScopedCaptureClient::ScopedCaptureClient(aura::Window* root)
     : root_window_(root) {
   root->AddObserver(this);
   if (!capture_controller_)
diff --git a/ui/views/corewm/capture_controller.h b/ui/views/corewm/capture_controller.h
index 343c3c0..3250221 100644
--- a/ui/views/corewm/capture_controller.h
+++ b/ui/views/corewm/capture_controller.h
@@ -20,10 +20,10 @@
 class VIEWS_EXPORT CaptureController : public aura::client::CaptureClient {
  public:
   // Adds |root| to the list of RootWindows notified when capture changes.
-  void Attach(aura::RootWindow* root);
+  void Attach(aura::Window* root);
 
   // Removes |root| from the list of RootWindows notified when capture changes.
-  void Detach(aura::RootWindow* root);
+  void Detach(aura::Window* root);
 
   // Returns true if this CaptureController is installed on at least one
   // RootWindow.
@@ -36,7 +36,7 @@
 
  private:
   friend class ScopedCaptureClient;
-  typedef std::set<aura::RootWindow*> RootWindows;
+  typedef std::set<aura::Window*> RootWindows;
 
   CaptureController();
   virtual ~CaptureController();
@@ -55,7 +55,7 @@
 // among all ScopedCaptureClients and adds the RootWindow to it.
 class VIEWS_EXPORT ScopedCaptureClient : public aura::WindowObserver {
  public:
-  explicit ScopedCaptureClient(aura::RootWindow* root);
+  explicit ScopedCaptureClient(aura::Window* root);
   virtual ~ScopedCaptureClient();
 
   // Returns true if there is a CaptureController with at least one RootWindow.
@@ -76,7 +76,7 @@
   static CaptureController* capture_controller_;
 
   // RootWindow this ScopedCaptureClient was create for.
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedCaptureClient);
 };
diff --git a/ui/views/corewm/compound_event_filter.cc b/ui/views/corewm/compound_event_filter.cc
index 0d021bd..146edb3 100644
--- a/ui/views/corewm/compound_event_filter.cc
+++ b/ui/views/corewm/compound_event_filter.cc
@@ -123,7 +123,7 @@
                                        ui::MouseEvent* event) {
   // If drag and drop is in progress, let the drag drop client set the cursor
   // instead of setting the cursor here.
-  aura::RootWindow* root_window = target->GetRootWindow();
+  aura::Window* root_window = target->GetRootWindow();
   aura::client::DragDropClient* drag_drop_client =
       aura::client::GetDragDropClient(root_window);
   if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
diff --git a/ui/views/corewm/desktop_capture_controller_unittest.cc b/ui/views/corewm/desktop_capture_controller_unittest.cc
index 8811be5..c655ec8 100644
--- a/ui/views/corewm/desktop_capture_controller_unittest.cc
+++ b/ui/views/corewm/desktop_capture_controller_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
+#include "ui/aura/test/event_generator.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/events/event.h"
 #include "ui/views/test/views_test_base.h"
@@ -48,6 +49,38 @@
   DISALLOW_COPY_AND_ASSIGN(DesktopViewInputTest);
 };
 
+views::Widget* CreateWidget() {
+  views::Widget* widget = new views::Widget;
+  views::Widget::InitParams params;
+  params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+  params.accept_events = true;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.native_widget = new DesktopNativeWidgetAura(widget);
+  params.bounds = gfx::Rect(0, 0, 200, 100);
+  widget->Init(params);
+  widget->Show();
+  return widget;
+}
+
+// Verifies mouse handlers are reset when a window gains capture. Specifically
+// creates two widgets, does a mouse press in one, sets capture in the other and
+// verifies state is reset in the first.
+TEST_F(DesktopCaptureControllerTest, ResetMouseHandlers) {
+  scoped_ptr<Widget> w1(CreateWidget());
+  scoped_ptr<Widget> w2(CreateWidget());
+  aura::test::EventGenerator generator1(w1->GetNativeView()->GetRootWindow());
+  generator1.MoveMouseToCenterOf(w1->GetNativeView());
+  generator1.PressLeftButton();
+  EXPECT_FALSE(w1->HasCapture());
+  aura::RootWindow* w1_root = w1->GetNativeView()->GetDispatcher();
+  EXPECT_TRUE(w1_root->mouse_pressed_handler() != NULL);
+  EXPECT_TRUE(w1_root->mouse_moved_handler() != NULL);
+  w2->SetCapture(w2->GetRootView());
+  EXPECT_TRUE(w2->HasCapture());
+  EXPECT_TRUE(w1_root->mouse_pressed_handler() == NULL);
+  EXPECT_TRUE(w1_root->mouse_moved_handler() == NULL);
+}
+
 // Tests aura::Window capture and whether gesture events are sent to the window
 // which has capture.
 // The test case creates two visible widgets and sets capture to the underlying
diff --git a/ui/views/corewm/focus_controller.h b/ui/views/corewm/focus_controller.h
index d3d34e6..1dc69b7 100644
--- a/ui/views/corewm/focus_controller.h
+++ b/ui/views/corewm/focus_controller.h
@@ -6,10 +6,13 @@
 #define UI_VIEWS_COREWM_FOCUS_CONTROLLER_H_
 
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
 #include "ui/views/views_export.h"
 
 namespace views {
diff --git a/ui/views/corewm/focus_controller_unittest.cc b/ui/views/corewm/focus_controller_unittest.cc
index 964fd58..2177271 100644
--- a/ui/views/corewm/focus_controller_unittest.cc
+++ b/ui/views/corewm/focus_controller_unittest.cc
@@ -98,7 +98,7 @@
 
 class ScopedTargetFocusNotificationObserver : public FocusNotificationObserver {
  public:
-  ScopedTargetFocusNotificationObserver(aura::RootWindow* root_window, int id)
+  ScopedTargetFocusNotificationObserver(aura::Window* root_window, int id)
       : target_(root_window->GetChildById(id)) {
     aura::client::SetActivationChangeObserver(target_, this);
     aura::client::SetFocusChangeObserver(target_, this);
diff --git a/ui/views/corewm/input_method_event_filter.cc b/ui/views/corewm/input_method_event_filter.cc
index cfdab6b..8c99063 100644
--- a/ui/views/corewm/input_method_event_filter.cc
+++ b/ui/views/corewm/input_method_event_filter.cc
@@ -18,7 +18,7 @@
 
 InputMethodEventFilter::InputMethodEventFilter(gfx::AcceleratedWidget widget)
     : input_method_(ui::CreateInputMethod(this, widget)),
-      target_root_window_(NULL) {
+      target_dispatcher_(NULL) {
   // TODO(yusukes): Check if the root window is currently focused and pass the
   // result to Init().
   input_method_->Init(true);
@@ -28,7 +28,7 @@
 }
 
 void InputMethodEventFilter::SetInputMethodPropertyInRootWindow(
-    aura::RootWindow* root_window) {
+    aura::Window* root_window) {
   root_window->SetProperty(aura::client::kRootWindowInputMethodKey,
                            input_method_.get());
 }
@@ -45,10 +45,10 @@
     static_cast<ui::TranslatedKeyEvent*>(event)->ConvertToKeyEvent();
   } else {
     // If the focused window is changed, all requests to IME will be
-    // discarded so it's safe to update the target_root_window_ here.
+    // discarded so it's safe to update the target_dispatcher_ here.
     aura::Window* target = static_cast<aura::Window*>(event->target());
-    target_root_window_ = target->GetRootWindow();
-    DCHECK(target_root_window_);
+    target_dispatcher_ = target->GetRootWindow()->GetDispatcher();
+    DCHECK(target_dispatcher_);
     bool handled = false;
     if (event->HasNativeEvent())
       handled = input_method_->DispatchKeyEvent(event->native_event());
@@ -68,7 +68,7 @@
   DCHECK(event.message != WM_CHAR);
 #endif
   ui::TranslatedKeyEvent aura_event(event, false /* is_char */);
-  return target_root_window_->AsRootWindowHostDelegate()->OnHostKeyEvent(
+  return target_dispatcher_->AsRootWindowHostDelegate()->OnHostKeyEvent(
       &aura_event);
 }
 
@@ -78,7 +78,7 @@
     int flags) {
   ui::TranslatedKeyEvent aura_event(type == ui::ET_KEY_PRESSED, key_code,
                                     flags);
-  return target_root_window_->AsRootWindowHostDelegate()->OnHostKeyEvent(
+  return target_dispatcher_->AsRootWindowHostDelegate()->OnHostKeyEvent(
       &aura_event);
 }
 
diff --git a/ui/views/corewm/input_method_event_filter.h b/ui/views/corewm/input_method_event_filter.h
index cb1fae4..902244c 100644
--- a/ui/views/corewm/input_method_event_filter.h
+++ b/ui/views/corewm/input_method_event_filter.h
@@ -8,15 +8,12 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
 #include "ui/base/ime/input_method_delegate.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
-namespace aura {
-class RootWindow;
-}
-
 namespace ui {
 class InputMethod;
 }
@@ -33,7 +30,7 @@
   explicit InputMethodEventFilter(gfx::AcceleratedWidget widget);
   virtual ~InputMethodEventFilter();
 
-  void SetInputMethodPropertyInRootWindow(aura::RootWindow* root_window);
+  void SetInputMethodPropertyInRootWindow(aura::Window* root_window);
 
   ui::InputMethod* input_method() const { return input_method_.get(); }
 
@@ -49,9 +46,8 @@
 
   scoped_ptr<ui::InputMethod> input_method_;
 
-  // The target root window to which the key event translated by IME will
-  // be dispatched.
-  aura::RootWindow* target_root_window_;
+  // The target dispatcher that will receive translated key events from the IME.
+  aura::WindowEventDispatcher* target_dispatcher_;
 
   DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilter);
 };
diff --git a/ui/views/corewm/shadow_controller_unittest.cc b/ui/views/corewm/shadow_controller_unittest.cc
index acfb324..4140f7d 100644
--- a/ui/views/corewm/shadow_controller_unittest.cc
+++ b/ui/views/corewm/shadow_controller_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/window.h"
@@ -56,7 +57,7 @@
   scoped_ptr<aura::Window> window(new aura::Window(NULL));
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window.get());
+  ParentWindow(window.get());
 
   // We should create the shadow before the window is visible (the shadow's
   // layer won't get drawn yet since it's a child of the window's layer).
@@ -92,7 +93,7 @@
   scoped_ptr<aura::Window> window(new aura::Window(NULL));
   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window.get());
+  ParentWindow(window.get());
   window->Show();
 
   const gfx::Rect kOldBounds(20, 30, 400, 300);
@@ -121,7 +122,7 @@
   scoped_ptr<aura::Window> window1(new aura::Window(NULL));
   window1->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window1->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window1.get());
+  ParentWindow(window1.get());
   window1->SetBounds(gfx::Rect(10, 20, 300, 400));
   window1->Show();
   ActivateWindow(window1.get());
@@ -135,7 +136,7 @@
   scoped_ptr<aura::Window> window2(new aura::Window(NULL));
   window2->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window2->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window2.get());
+  ParentWindow(window2.get());
   window2->SetBounds(gfx::Rect(11, 21, 301, 401));
   window2->Show();
   ActivateWindow(window2.get());
@@ -154,7 +155,7 @@
   scoped_ptr<aura::Window> tooltip_window(new aura::Window(NULL));
   tooltip_window->SetType(aura::client::WINDOW_TYPE_TOOLTIP);
   tooltip_window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(tooltip_window.get());
+  ParentWindow(tooltip_window.get());
   tooltip_window->SetBounds(gfx::Rect(10, 20, 300, 400));
   tooltip_window->Show();
 
@@ -165,7 +166,7 @@
   scoped_ptr<aura::Window> menu_window(new aura::Window(NULL));
   menu_window->SetType(aura::client::WINDOW_TYPE_MENU);
   menu_window->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(menu_window.get());
+  ParentWindow(menu_window.get());
   menu_window->SetBounds(gfx::Rect(10, 20, 300, 400));
   menu_window->Show();
 
@@ -182,7 +183,7 @@
   scoped_ptr<aura::Window> window1(new aura::Window(NULL));
   window1->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window1->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window1.get());
+  ParentWindow(window1.get());
   window1->SetBounds(gfx::Rect(10, 20, 300, 400));
   window1->Show();
   ActivateWindow(window1.get());
@@ -198,7 +199,7 @@
   scoped_ptr<aura::Window> window2(new aura::Window(NULL));
   window2->SetType(aura::client::WINDOW_TYPE_NORMAL);
   window2->Init(ui::LAYER_TEXTURED);
-  SetDefaultParentByPrimaryRootWindow(window2.get());
+  ParentWindow(window2.get());
   window2->SetBounds(gfx::Rect(11, 21, 301, 401));
   window1->AddTransientChild(window2.get());
   aura::client::SetHideOnDeactivate(window2.get(), true);
diff --git a/ui/views/corewm/tooltip_aura.cc b/ui/views/corewm/tooltip_aura.cc
index 70e07e3..1f7029e 100644
--- a/ui/views/corewm/tooltip_aura.cc
+++ b/ui/views/corewm/tooltip_aura.cc
@@ -172,8 +172,9 @@
   // (which comes from the RootWindow).
   if (screen_type_ == gfx::SCREEN_TYPE_NATIVE &&
       gfx::SCREEN_TYPE_NATIVE != gfx::SCREEN_TYPE_ALTERNATE) {
-    aura::RootWindow* root = tooltip_window_->GetRootWindow();
-    widget_bounds = gfx::Rect(root->GetHostOrigin(), root->GetHostSize());
+    aura::WindowEventDispatcher* dispatcher = tooltip_window_->GetDispatcher();
+    widget_bounds = gfx::Rect(dispatcher->GetHostOrigin(),
+                              dispatcher->GetHostSize());
   }
   gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_);
   gfx::Rect bounds(screen->GetDisplayNearestPoint(origin).bounds());
diff --git a/ui/views/corewm/tooltip_controller.cc b/ui/views/corewm/tooltip_controller.cc
index 5b79c97..d858f8e 100644
--- a/ui/views/corewm/tooltip_controller.cc
+++ b/ui/views/corewm/tooltip_controller.cc
@@ -6,27 +6,88 @@
 
 #include <vector>
 
+#include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/events/event.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/rect.h"
+#include "ui/gfx/screen.h"
 #include "ui/views/corewm/tooltip.h"
 #include "ui/views/widget/tooltip_manager.h"
 
+namespace views {
+namespace corewm {
 namespace {
 
 const int kTooltipTimeoutMs = 500;
 const int kDefaultTooltipShownTimeoutMs = 10000;
 
-}  // namespace
+// Returns true if |target| is a valid window to get the tooltip from.
+// |event_target| is the original target from the event and |target| the window
+// at the same location.
+bool IsValidTarget(aura::Window* event_target, aura::Window* target) {
+  if (!target || (event_target == target))
+    return true;
 
-namespace views {
-namespace corewm {
+  void* event_target_grouping_id = event_target->GetNativeWindowProperty(
+      TooltipManager::kGroupingPropertyKey);
+  void* target_grouping_id = target->GetNativeWindowProperty(
+      TooltipManager::kGroupingPropertyKey);
+  return event_target_grouping_id &&
+      event_target_grouping_id == target_grouping_id;
+}
+
+// Returns the target (the Window tooltip text comes from) based on the event.
+// If a Window other than event.target() is returned, |location| is adjusted
+// to be in the coordinates of the returned Window.
+aura::Window* GetTooltipTarget(const ui::MouseEvent& event,
+                               gfx::Point* location) {
+  switch (event.type()) {
+    case ui::ET_MOUSE_CAPTURE_CHANGED:
+      // On windows we can get a capture changed without an exit. We need to
+      // reset state when this happens else the tooltip may incorrectly show.
+      return NULL;
+    case ui::ET_MOUSE_EXITED:
+      return NULL;
+    case ui::ET_MOUSE_MOVED:
+    case ui::ET_MOUSE_DRAGGED: {
+      aura::Window* event_target = static_cast<aura::Window*>(event.target());
+      if (!event_target || !event_target->HasCapture())
+        return event_target;
+
+      // If |target| has capture all events go to it, even if the mouse is
+      // really over another window. Find the real window the mouse is over.
+      gfx::Point screen_loc(event.location());
+      aura::client::GetScreenPositionClient(event_target->GetRootWindow())->
+          ConvertPointToScreen(event_target, &screen_loc);
+      gfx::Screen* screen = gfx::Screen::GetScreenFor(event_target);
+      aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc);
+      if (!target)
+        return NULL;
+      gfx::Point target_loc(screen_loc);
+      aura::client::GetScreenPositionClient(target->GetRootWindow())->
+          ConvertPointFromScreen(target, &target_loc);
+      aura::Window* screen_target = target->GetEventHandlerForPoint(target_loc);
+      if (!IsValidTarget(event_target, screen_target))
+        return NULL;
+
+      aura::Window::ConvertPointToTarget(screen_target, target, &target_loc);
+      *location = target_loc;
+      return screen_target;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+  return NULL;
+}
+
+}  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 // TooltipController public:
@@ -86,13 +147,13 @@
 }
 
 void TooltipController::OnMouseEvent(ui::MouseEvent* event) {
-  aura::Window* target = static_cast<aura::Window*>(event->target());
   switch (event->type()) {
+    case ui::ET_MOUSE_CAPTURE_CHANGED:
     case ui::ET_MOUSE_EXITED:
-      target = NULL;
-      // Fall through.
     case ui::ET_MOUSE_MOVED:
-    case ui::ET_MOUSE_DRAGGED:
+    case ui::ET_MOUSE_DRAGGED: {
+      curr_mouse_loc_ = event->location();
+      aura::Window* target = GetTooltipTarget(*event, &curr_mouse_loc_);
       if (tooltip_window_ != target) {
         if (tooltip_window_)
           tooltip_window_->RemoveObserver(this);
@@ -100,15 +161,16 @@
         if (tooltip_window_)
           tooltip_window_->AddObserver(this);
       }
-      curr_mouse_loc_ = event->location();
       if (tooltip_timer_.IsRunning())
         tooltip_timer_.Reset();
 
       if (tooltip_->IsVisible())
         UpdateIfRequired();
       break;
+    }
     case ui::ET_MOUSE_PRESSED:
       if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) {
+        aura::Window* target = static_cast<aura::Window*>(event->target());
         // We don't get a release for non-client areas.
         tooltip_window_at_mouse_press_ = target;
         if (target)
@@ -116,7 +178,6 @@
       }
       tooltip_->Hide();
       break;
-    case ui::ET_MOUSE_CAPTURE_CHANGED:
     case ui::ET_MOUSEWHEEL:
       // Hide the tooltip for click, release, drag, wheel events.
       if (tooltip_->IsVisible())
@@ -197,11 +258,15 @@
   if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible()) {
     tooltip_shown_timer_.Stop();
     tooltip_text_ = tooltip_text;
-    if (tooltip_text_.empty()) {
+    base::string16 trimmed_text(tooltip_text_);
+    views::TooltipManager::TrimTooltipText(&trimmed_text);
+    // If the string consists entirely of whitespace, then don't both showing it
+    // (an empty tooltip is useless).
+    base::string16 whitespace_removed_text;
+    TrimWhitespace(trimmed_text, TRIM_ALL, &whitespace_removed_text);
+    if (whitespace_removed_text.empty()) {
       tooltip_->Hide();
     } else {
-      base::string16 trimmed_text(tooltip_text_);
-      views::TooltipManager::TrimTooltipText(&trimmed_text);
       gfx::Point widget_loc = curr_mouse_loc_ +
           tooltip_window_->GetBoundsInScreen().OffsetFromOrigin();
       tooltip_->SetText(tooltip_window_, trimmed_text, widget_loc);
@@ -231,7 +296,7 @@
 bool TooltipController::IsCursorVisible() {
   if (!tooltip_window_)
     return false;
-  aura::RootWindow* root = tooltip_window_->GetRootWindow();
+  aura::Window* root = tooltip_window_->GetRootWindow();
   if (!root)
     return false;
   aura::client::CursorClient* cursor_client =
diff --git a/ui/views/corewm/tooltip_controller.h b/ui/views/corewm/tooltip_controller.h
index a8ae59a..66b6a32 100644
--- a/ui/views/corewm/tooltip_controller.h
+++ b/ui/views/corewm/tooltip_controller.h
@@ -89,6 +89,7 @@
   // this timer fires.
   base::OneShotTimer<TooltipController> tooltip_shown_timer_;
 
+  // Location of the last event in |tooltip_window_|'s coordinates.
   gfx::Point curr_mouse_loc_;
 
   bool tooltips_enabled_;
diff --git a/ui/views/corewm/tooltip_controller_unittest.cc b/ui/views/corewm/tooltip_controller_unittest.cc
index 023bbdc..1a5db6b 100644
--- a/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/ui/views/corewm/tooltip_controller_unittest.cc
@@ -6,28 +6,34 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/client/tooltip_client.h"
 #include "ui/aura/client/window_types.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_screen.h"
 #include "ui/aura/window.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/point.h"
+#include "ui/gfx/screen.h"
 #include "ui/gfx/screen_type_delegate.h"
 #include "ui/gfx/text_elider.h"
 #include "ui/views/corewm/tooltip_aura.h"
 #include "ui/views/corewm/tooltip_controller_test_helper.h"
 #include "ui/views/view.h"
+#include "ui/views/widget/tooltip_manager.h"
 #include "ui/views/widget/widget.h"
 
 #if defined(OS_WIN)
 #include "ui/base/win/scoped_ole_initializer.h"
 #endif
+
 #if !defined(OS_CHROMEOS)
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
 #endif
 
 namespace views {
@@ -101,7 +107,7 @@
     return widget_->GetNativeWindow();
   }
 
-  aura::RootWindow* GetRootWindow() {
+  aura::Window* GetRootWindow() {
     return GetWindow()->GetRootWindow();
   }
 
@@ -159,7 +165,7 @@
 
   PrepareSecondView();
   aura::Window* window = GetWindow();
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
 
   // Fire tooltip timer so tooltip becomes visible.
   generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint());
@@ -199,7 +205,7 @@
   helper_->FireTooltipTimer();
   EXPECT_TRUE(helper_->IsTooltipVisible());
 
-  // Diable tooltips and check again.
+  // Disable tooltips and check again.
   helper_->controller()->SetTooltipsEnabled(false);
   EXPECT_FALSE(helper_->IsTooltipVisible());
   helper_->FireTooltipTimer();
@@ -212,6 +218,18 @@
   EXPECT_TRUE(helper_->IsTooltipVisible());
 }
 
+// Verifies tooltip isn't shown if tooltip text consists entirely of whitespace.
+TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
+  view_->set_tooltip_text(ASCIIToUTF16("                     "));
+  EXPECT_EQ(string16(), helper_->GetTooltipText());
+  EXPECT_EQ(NULL, helper_->GetTooltipWindow());
+
+  generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint());
+
+  helper_->FireTooltipTimer();
+  EXPECT_FALSE(helper_->IsTooltipVisible());
+}
+
 TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
   view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
   EXPECT_EQ(string16(), helper_->GetTooltipText());
@@ -326,6 +344,152 @@
   EXPECT_FALSE(helper_->IsTooltipVisible());
 }
 
+namespace {
+
+// Returns the index of |window| in its parent's children.
+int IndexInParent(const aura::Window* window) {
+  aura::Window::Windows::const_iterator i =
+      std::find(window->parent()->children().begin(),
+                window->parent()->children().end(),
+                window);
+  return i == window->parent()->children().end() ? -1 :
+      static_cast<int>(i - window->parent()->children().begin());
+}
+
+class TestScreenPositionClient : public aura::client::ScreenPositionClient {
+ public:
+  TestScreenPositionClient() {}
+  virtual ~TestScreenPositionClient() {}
+
+  // ScreenPositionClient overrides:
+  virtual void ConvertPointToScreen(const aura::Window* window,
+                                    gfx::Point* point) OVERRIDE {
+  }
+  virtual void ConvertPointFromScreen(const aura::Window* window,
+                                      gfx::Point* point) OVERRIDE {
+  }
+  virtual void ConvertHostPointToScreen(aura::Window* root_gwindow,
+                                        gfx::Point* point) OVERRIDE {
+    NOTREACHED();
+  }
+  virtual void SetBounds(aura::Window* window,
+                         const gfx::Rect& bounds,
+                         const gfx::Display& display) OVERRIDE {
+    window->SetBounds(bounds);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient);
+};
+
+}  // namespace
+
+class TooltipControllerCaptureTest : public TooltipControllerTest {
+ public:
+  TooltipControllerCaptureTest() {}
+  virtual ~TooltipControllerCaptureTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    TooltipControllerTest::SetUp();
+    aura::client::SetScreenPositionClient(GetRootWindow(),
+                                          &screen_position_client_);
+#if !defined(OS_CHROMEOS)
+    desktop_screen_.reset(CreateDesktopScreen());
+    gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
+                                   desktop_screen_.get());
+#endif
+  }
+
+  virtual void TearDown() OVERRIDE {
+#if !defined(OS_CHROMEOS)
+    gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen());
+    desktop_screen_.reset();
+#endif
+    aura::client::SetScreenPositionClient(GetRootWindow(), NULL);
+    TooltipControllerTest::TearDown();
+  }
+
+ private:
+  TestScreenPositionClient screen_position_client_;
+  scoped_ptr<gfx::Screen> desktop_screen_;
+
+  DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest);
+};
+
+// Verifies when capture is released the TooltipController resets state.
+TEST_F(TooltipControllerCaptureTest, CloseOnCaptureLost) {
+  view_->GetWidget()->SetCapture(view_);
+  view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
+  generator_->MoveMouseToCenterOf(GetWindow());
+  string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+  EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
+  EXPECT_EQ(string16(), helper_->GetTooltipText());
+  EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
+
+  // Fire tooltip timer so tooltip becomes visible.
+  helper_->FireTooltipTimer();
+
+  EXPECT_TRUE(helper_->IsTooltipVisible());
+  view_->GetWidget()->ReleaseCapture();
+  EXPECT_FALSE(helper_->IsTooltipVisible());
+  EXPECT_TRUE(helper_->GetTooltipWindow() == NULL);
+}
+
+// Disabled on linux as DesktopScreenX11::GetWindowAtScreenPoint() doesn't
+// consider z-order.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_Capture DISABLED_Capture
+#else
+#define MAYBE_Capture Capture
+#endif
+// Verifies the correct window is found for tooltips when there is a capture.
+TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) {
+  const string16 tooltip_text(ASCIIToUTF16("1"));
+  const string16 tooltip_text2(ASCIIToUTF16("2"));
+
+  widget_->SetBounds(gfx::Rect(0, 0, 200, 200));
+  view_->set_tooltip_text(tooltip_text);
+
+  scoped_ptr<views::Widget> widget2(CreateWidget(root_window()));
+  widget2->SetContentsView(new View);
+  TooltipTestView* view2 = new TooltipTestView;
+  widget2->GetContentsView()->AddChildView(view2);
+  view2->set_tooltip_text(tooltip_text2);
+  widget2->SetBounds(gfx::Rect(0, 0, 200, 200));
+  view2->SetBoundsRect(widget2->GetContentsView()->GetLocalBounds());
+
+  widget_->SetCapture(view_);
+  EXPECT_TRUE(widget_->HasCapture());
+  widget2->Show();
+  EXPECT_GE(IndexInParent(widget2->GetNativeWindow()),
+            IndexInParent(widget_->GetNativeWindow()));
+
+  generator_->MoveMouseRelativeTo(widget_->GetNativeWindow(),
+                                  view_->bounds().CenterPoint());
+
+  EXPECT_TRUE(helper_->IsTooltipTimerRunning());
+  helper_->FireTooltipTimer();
+  // Even though the mouse is over a window with a tooltip it shouldn't be
+  // picked up because the windows don't have the same value for
+  // |TooltipManager::kGroupingPropertyKey|.
+  EXPECT_TRUE(helper_->GetTooltipText().empty());
+
+  // Now make both the windows have same transient value for
+  // kGroupingPropertyKey. In this case the tooltip should be picked up from
+  // |widget2| (because the mouse is over it).
+  const int grouping_key = 1;
+  widget_->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey,
+                                   reinterpret_cast<void*>(grouping_key));
+  widget2->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey,
+                                   reinterpret_cast<void*>(grouping_key));
+  generator_->MoveMouseBy(1, 10);
+  EXPECT_TRUE(helper_->IsTooltipTimerRunning());
+  helper_->FireTooltipTimer();
+  EXPECT_EQ(tooltip_text2, helper_->GetTooltipText());
+
+  widget2.reset();
+}
+
 #if !defined(OS_CHROMEOS)
 // This test creates two top level windows and verifies that the tooltip
 // displays correctly when mouse moves are dispatched to these windows.
@@ -337,7 +501,7 @@
   EXPECT_EQ(NULL, helper_->GetTooltipWindow());
 
   aura::Window* window = GetWindow();
-  aura::RootWindow* root_window = GetRootWindow();
+  aura::Window* root_window = GetRootWindow();
 
   // Fire tooltip timer so tooltip becomes visible.
   generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint());
@@ -367,7 +531,7 @@
     view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text For RootWindow2"));
 
   aura::Window* window2 = widget2->GetNativeWindow();
-  aura::RootWindow* root_window2 =
+  aura::Window* root_window2 =
       widget2->GetNativeWindow()->GetRootWindow();
   // Fire tooltip timer so tooltip becomes visible.
   generator_->MoveMouseRelativeTo(window2, view2->bounds().CenterPoint());
diff --git a/ui/views/corewm/tooltip_win.cc b/ui/views/corewm/tooltip_win.cc
index 46ee267..10341d6 100644
--- a/ui/views/corewm/tooltip_win.cc
+++ b/ui/views/corewm/tooltip_win.cc
@@ -129,6 +129,8 @@
 
   SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE,
               TRUE, reinterpret_cast<LPARAM>(&toolinfo_));
+  SetWindowPos(tooltip_hwnd_, HWND_TOPMOST, 0, 0, 0, 0,
+               SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE);
 }
 
 void TooltipWin::Hide() {
diff --git a/ui/views/corewm/window_modality_controller.cc b/ui/views/corewm/window_modality_controller.cc
index 24be9ca..a535792 100644
--- a/ui/views/corewm/window_modality_controller.cc
+++ b/ui/views/corewm/window_modality_controller.cc
@@ -118,19 +118,19 @@
 void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
   if (GetModalTransient(target))
-    event->StopPropagation();
+    event->SetHandled();
 }
 
 void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
   if (ProcessLocatedEvent(target, event))
-   event->StopPropagation();
+   event->SetHandled();
 }
 
 void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
   if (ProcessLocatedEvent(target, event))
-    event->StopPropagation();
+    event->SetHandled();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -183,6 +183,8 @@
 
 bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
                                                    ui::LocatedEvent* event) {
+  if (event->handled())
+    return false;
   aura::Window* modal_transient_child = GetModalTransient(target);
   if (modal_transient_child && (event->type() == ui::ET_MOUSE_PRESSED ||
                                 event->type() == ui::ET_TOUCH_PRESSED)) {
diff --git a/ui/views/drag_utils.cc b/ui/views/drag_utils.cc
index b156276..0b9c317 100644
--- a/ui/views/drag_utils.cc
+++ b/ui/views/drag_utils.cc
@@ -47,7 +47,7 @@
                   ui::DragDropTypes::DragEventSource source) {
 #if defined(USE_AURA)
   gfx::Point root_location(location);
-  aura::RootWindow* root_window = view->GetRootWindow();
+  aura::Window* root_window = view->GetRootWindow();
   aura::Window::ConvertPointToTarget(view, root_window, &root_location);
   if (aura::client::GetDragDropClient(root_window)) {
     aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
diff --git a/ui/views/event_utils_aura.cc b/ui/views/event_utils_aura.cc
index 455ec1a..9a42656 100644
--- a/ui/views/event_utils_aura.cc
+++ b/ui/views/event_utils_aura.cc
@@ -20,10 +20,11 @@
   if (!window)
     return false;
 
-  aura::RootWindow* root_window = window->GetRootWindow();
+  aura::Window* root_window = window->GetRootWindow();
 
   gfx::Point root_loc(event.location());
-  ScreenPositionClient* spc = GetScreenPositionClient(root_window);
+  ScreenPositionClient* spc =
+      aura::client::GetScreenPositionClient(root_window);
   if (!spc)
     return false;
 
@@ -34,8 +35,9 @@
     const ui::MouseEvent& orig = static_cast<const ui::MouseEvent&>(event);
     relocated.reset(new ui::MouseEvent(orig));
   } else if (event.IsGestureEvent()) {
-    const ui::GestureEvent& orig = static_cast<const ui::GestureEvent&>(event);
-    relocated.reset(new ui::GestureEvent(orig));
+    // TODO(rbyers): Gesture event repost is tricky to get right
+    // crbug.com/170987.
+    return false;
   } else {
     NOTREACHED();
     return false;
@@ -43,7 +45,7 @@
   relocated->set_location(root_loc);
   relocated->set_root_location(root_loc);
 
-  root_window->RepostEvent(*relocated);
+  root_window->GetDispatcher()->RepostEvent(*relocated);
   return true;
 }
 
diff --git a/ui/views/examples/text_example.cc b/ui/views/examples/text_example.cc
index c62f24e..e0f2352 100644
--- a/ui/views/examples/text_example.cc
+++ b/ui/views/examples/text_example.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/combobox/combobox.h"
 #include "ui/views/controls/label.h"
@@ -48,11 +49,8 @@
 const char* kElidingBehaviors[] = {
     "Ellipsis",
     "None",
-#if defined(OS_WIN)
     "Fade Tail",
     "Fade Head",
-    "Fade Head and Tail",
-#endif
 };
 
 const char* kPrefixOptions[] = {
@@ -83,9 +81,7 @@
 class TextExample::TextExampleView : public View {
  public:
   TextExampleView()
-    : font_(ResourceBundle::GetSharedInstance().GetFont(
-          ResourceBundle::BaseFont)),
-      text_(ASCIIToUTF16(kShortText)),
+    : text_(ASCIIToUTF16(kShortText)),
       text_flags_(0),
       halo_(false),
       fade_(false),
@@ -94,25 +90,17 @@
 
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
     View::OnPaint(canvas);
-
     const gfx::Rect bounds = GetContentsBounds();
 
-#if defined(OS_WIN)
     if (fade_) {
-      size_t characters_to_truncate_from_head =
-          gfx::Canvas::TruncateFadeHeadAndTail ? 10 : 0;
-      canvas->DrawFadeTruncatingString(text_, fade_mode_,
-          characters_to_truncate_from_head, font_, SK_ColorDKGRAY, bounds);
-      return;
-    }
-#endif
-
-    if (halo_) {
-      canvas->DrawStringWithHalo(text_, font_, SK_ColorDKGRAY, SK_ColorWHITE,
-          bounds.x(), bounds.y(), bounds.width(), bounds.height(), text_flags_);
+      canvas->DrawFadeTruncatingStringRect(text_, fade_mode_, font_list_,
+                                           SK_ColorDKGRAY, bounds);
+    } else if (halo_) {
+      canvas->DrawStringRectWithHalo(text_, font_list_, SK_ColorDKGRAY,
+                                     SK_ColorWHITE, bounds, text_flags_);
     } else {
-      canvas->DrawStringInt(text_, font_, SK_ColorDKGRAY, bounds.x(),
-          bounds.y(), bounds.width(), bounds.height(), text_flags_);
+      canvas->DrawStringRectWithFlags(text_, font_list_, SK_ColorDKGRAY, bounds,
+                                      text_flags_);
     }
   }
 
@@ -129,20 +117,18 @@
   void set_fade(bool fade) { fade_ = fade; }
 
   gfx::Canvas::TruncateFadeMode fade_mode() const { return fade_mode_; }
-  void set_fade_mode(gfx::Canvas::TruncateFadeMode fade_mode) {
-    fade_mode_ = fade_mode;
-  }
+  void set_fade_mode(gfx::Canvas::TruncateFadeMode mode) { fade_mode_ = mode; }
 
   int GetFontStyle() const {
-    return font_.GetStyle();
+    return font_list_.GetFontStyle();
   }
   void SetFontStyle(int style) {
-    font_ = font_.DeriveFont(0, style);
+    font_list_ = font_list_.DeriveFontList(style);
   }
 
  private:
   // The font used for drawing the text.
-  gfx::Font font_;
+  gfx::FontList font_list_;
 
   // The text to draw.
   string16 text_;
@@ -313,7 +299,6 @@
         text_flags |= gfx::Canvas::NO_ELLIPSIS;
         text_view_->set_fade(false);
         break;
-#if defined(OS_WIN)
       case 2:
         text_view_->set_fade_mode(gfx::Canvas::TruncateFadeTail);
         text_view_->set_fade(true);
@@ -322,11 +307,6 @@
         text_view_->set_fade_mode(gfx::Canvas::TruncateFadeHead);
         text_view_->set_fade(true);
         break;
-      case 4:
-        text_view_->set_fade_mode(gfx::Canvas::TruncateFadeHeadAndTail);
-        text_view_->set_fade(true);
-        break;
-#endif
     }
   } else if (combobox == prefix_cb_) {
     text_flags &= ~(gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX);
diff --git a/ui/views/focus/focus_manager.h b/ui/views/focus/focus_manager.h
index ae3e088..44e663f 100644
--- a/ui/views/focus/focus_manager.h
+++ b/ui/views/focus/focus_manager.h
@@ -311,7 +311,6 @@
   // Gets an event handler suitable for registering as an observer.
   ui::EventHandler* GetEventHandler();
 
- private:
   // Returns the next focusable view. Traversal starts at |starting_view|. If
   // |starting_view| is NULL |starting_widget| is consuled to determine which
   // Widget to start from. See
@@ -323,6 +322,7 @@
                              bool reverse,
                              bool dont_loop);
 
+ private:
   // Returns the focusable view found in the FocusTraversable specified starting
   // at the specified view. This traverses down along the FocusTraversable
   // hierarchy.
diff --git a/ui/views/linux_ui/linux_ui.cc b/ui/views/linux_ui/linux_ui.cc
index 79f0a40..d6db069 100644
--- a/ui/views/linux_ui/linux_ui.cc
+++ b/ui/views/linux_ui/linux_ui.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/linux_ui/linux_ui.h"
 
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
 #include "ui/shell_dialogs/linux_shell_dialog.h"
 
 namespace {
@@ -17,7 +18,9 @@
 void LinuxUI::SetInstance(LinuxUI* instance) {
   delete g_linux_ui;
   g_linux_ui = instance;
-
+#if defined(USE_X11)
+  LinuxInputMethodContextFactory::SetInstance(instance);
+#endif
   LinuxShellDialog::SetInstance(instance);
 }
 
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h
index 757f871..6081827 100644
--- a/ui/views/linux_ui/linux_ui.h
+++ b/ui/views/linux_ui/linux_ui.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_LINUX_UI_LINUX_UI_H_
 
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
 #include "ui/shell_dialogs/linux_shell_dialog.h"
 #include "ui/views/linux_ui/status_icon_linux.h"
 #include "ui/views/views_export.h"
@@ -31,7 +32,8 @@
 // minimum) GTK2 and GTK3. LinuxUI::instance() should actually be a very
 // complex method that pokes around with dlopen against a libuigtk2.so, a
 // liuigtk3.so, etc.
-class VIEWS_EXPORT LinuxUI : public ui::LinuxShellDialog {
+class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
+                             public ui::LinuxShellDialog {
  public:
   virtual ~LinuxUI() {}
 
@@ -45,6 +47,8 @@
   // running with the "--ash" flag.)
   static LinuxUI* instance();
 
+  virtual void Initialize() = 0;
+
   // Returns an themed image per theme_provider.h
   virtual bool UseNativeTheme() const = 0;
   virtual gfx::Image GetThemeImageNamed(int id) const = 0;
diff --git a/ui/views/test/ui_controls_factory_desktop_aurax11.cc b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
new file mode 100644
index 0000000..bffa77b
--- /dev/null
+++ b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
@@ -0,0 +1,313 @@
+// Copyright 2013 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 <X11/keysym.h>
+#include <X11/Xlib.h>
+
+// X macro fail.
+#if defined(RootWindow)
+#undef RootWindow
+#endif
+
+#include "base/logging.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/ui_controls_factory_aura.h"
+#include "ui/base/test/ui_controls_aura.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+
+namespace views {
+namespace test {
+namespace {
+
+using ui_controls::DOWN;
+using ui_controls::LEFT;
+using ui_controls::MIDDLE;
+using ui_controls::MouseButton;
+using ui_controls::RIGHT;
+using ui_controls::UIControlsAura;
+using ui_controls::UP;
+
+// Mask of the buttons currently down.
+unsigned button_down_mask = 0;
+
+// Event waiter executes the specified closure|when a matching event
+// is found.
+// TODO(oshima): Move this to base.
+class EventWaiter : public base::MessageLoopForUI::Observer {
+ public:
+  typedef bool (*EventWaiterMatcher)(const base::NativeEvent& event);
+
+  EventWaiter(const base::Closure& closure, EventWaiterMatcher matcher)
+      : closure_(closure),
+        matcher_(matcher) {
+    base::MessageLoopForUI::current()->AddObserver(this);
+  }
+
+  virtual ~EventWaiter() {
+    base::MessageLoopForUI::current()->RemoveObserver(this);
+  }
+
+  // MessageLoop::Observer implementation:
+  virtual base::EventStatus WillProcessEvent(
+      const base::NativeEvent& event) OVERRIDE {
+    if ((*matcher_)(event)) {
+      base::MessageLoop::current()->PostTask(FROM_HERE, closure_);
+      delete this;
+    }
+    return base::EVENT_CONTINUE;
+  }
+
+  virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
+  }
+
+ private:
+  base::Closure closure_;
+  EventWaiterMatcher matcher_;
+  DISALLOW_COPY_AND_ASSIGN(EventWaiter);
+};
+
+// Returns atom that indidates that the XEvent is marker event.
+Atom MarkerEventAtom() {
+  return XInternAtom(gfx::GetXDisplay(), "marker_event", False);
+}
+
+// Returns true when the event is a marker event.
+bool Matcher(const base::NativeEvent& event) {
+  return event->xany.type == ClientMessage &&
+      event->xclient.message_type == MarkerEventAtom();
+}
+
+class UIControlsDesktopX11 : public UIControlsAura {
+ public:
+  UIControlsDesktopX11()
+      : x_display_(gfx::GetXDisplay()),
+        x_root_window_(DefaultRootWindow(x_display_)),
+        x_window_(XCreateWindow(
+            x_display_, x_root_window_,
+            -100, -100, 10, 10,  // x, y, width, height
+            0,                   // border width
+            CopyFromParent,      // depth
+            InputOnly,
+            CopyFromParent,      // visual
+            0,
+            NULL)) {
+    XStoreName(x_display_, x_window_, "Chromium UIControlsDesktopX11 Window");
+  }
+
+  virtual ~UIControlsDesktopX11() {
+    XDestroyWindow(x_display_, x_window_);
+  }
+
+  virtual bool SendKeyPress(gfx::NativeWindow window,
+                            ui::KeyboardCode key,
+                            bool control,
+                            bool shift,
+                            bool alt,
+                            bool command) OVERRIDE {
+    DCHECK(!command);  // No command key on Aura
+    return SendKeyPressNotifyWhenDone(
+        window, key, control, shift, alt, command, base::Closure());
+  }
+
+  virtual bool SendKeyPressNotifyWhenDone(
+      gfx::NativeWindow window,
+      ui::KeyboardCode key,
+      bool control,
+      bool shift,
+      bool alt,
+      bool command,
+      const base::Closure& closure) OVERRIDE {
+    DCHECK(!command);  // No command key on Aura
+
+    aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
+
+    XEvent xevent = {0};
+    xevent.xkey.type = KeyPress;
+    if (control) {
+      SetKeycodeAndSendThenMask(dispatcher, &xevent, XK_Control_L,
+                                ControlMask);
+    }
+    if (shift)
+      SetKeycodeAndSendThenMask(dispatcher, &xevent, XK_Shift_L, ShiftMask);
+    if (alt)
+      SetKeycodeAndSendThenMask(dispatcher, &xevent, XK_Alt_L, Mod1Mask);
+    xevent.xkey.keycode =
+        XKeysymToKeycode(x_display_,
+                         ui::XKeysymForWindowsKeyCode(key, shift));
+    dispatcher->PostNativeEvent(&xevent);
+
+    // Send key release events.
+    xevent.xkey.type = KeyRelease;
+    dispatcher->PostNativeEvent(&xevent);
+    if (alt)
+      UnmaskAndSetKeycodeThenSend(dispatcher, &xevent, Mod1Mask, XK_Alt_L);
+    if (shift)
+      UnmaskAndSetKeycodeThenSend(dispatcher, &xevent, ShiftMask, XK_Shift_L);
+    if (control) {
+      UnmaskAndSetKeycodeThenSend(dispatcher, &xevent, ControlMask,
+                                  XK_Control_L);
+    }
+    DCHECK(!xevent.xkey.state);
+    RunClosureAfterAllPendingUIEvents(closure);
+    return true;
+  }
+
+  // Simulate a mouse move. (x,y) are absolute screen coordinates.
+  virtual bool SendMouseMove(long x, long y) OVERRIDE {
+    return SendMouseMoveNotifyWhenDone(x, y, base::Closure());
+  }
+  virtual bool SendMouseMoveNotifyWhenDone(
+      long x,
+      long y,
+      const base::Closure& closure) OVERRIDE {
+    gfx::Point screen_point(x, y);
+    gfx::Point window_point = screen_point;
+    aura::Window* root_window = RootWindowForPoint(screen_point);
+
+    aura::client::ScreenPositionClient* screen_position_client =
+          aura::client::GetScreenPositionClient(root_window);
+    if (screen_position_client) {
+      screen_position_client->ConvertPointFromScreen(root_window,
+                                                     &window_point);
+    }
+
+    XEvent xevent = {0};
+    XMotionEvent* xmotion = &xevent.xmotion;
+    xmotion->type = MotionNotify;
+    xmotion->x = window_point.x();
+    xmotion->y = window_point.y();
+    xmotion->state = button_down_mask;
+    xmotion->same_screen = True;
+    // RootWindow will take care of other necessary fields.
+    root_window->GetDispatcher()->PostNativeEvent(&xevent);
+    RunClosureAfterAllPendingUIEvents(closure);
+    return true;
+  }
+  virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE {
+    return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
+  }
+  virtual bool SendMouseEventsNotifyWhenDone(
+      MouseButton type,
+      int state,
+      const base::Closure& closure) OVERRIDE {
+    XEvent xevent = {0};
+    XButtonEvent* xbutton = &xevent.xbutton;
+    gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
+    aura::Window* root_window = RootWindowForPoint(mouse_loc);
+    aura::client::ScreenPositionClient* screen_position_client =
+          aura::client::GetScreenPositionClient(root_window);
+    if (screen_position_client)
+      screen_position_client->ConvertPointFromScreen(root_window, &mouse_loc);
+    xbutton->x = mouse_loc.x();
+    xbutton->y = mouse_loc.y();
+    xbutton->same_screen = True;
+    switch (type) {
+      case LEFT:
+        xbutton->button = Button1;
+        xbutton->state = Button1Mask;
+        break;
+      case MIDDLE:
+        xbutton->button = Button2;
+        xbutton->state = Button2Mask;
+        break;
+      case RIGHT:
+        xbutton->button = Button3;
+        xbutton->state = Button3Mask;
+        break;
+    }
+    // RootWindow will take care of other necessary fields.
+    if (state & DOWN) {
+      xevent.xbutton.type = ButtonPress;
+      root_window->GetDispatcher()->PostNativeEvent(&xevent);
+      button_down_mask |= xbutton->state;
+    }
+    if (state & UP) {
+      xevent.xbutton.type = ButtonRelease;
+      root_window->GetDispatcher()->PostNativeEvent(&xevent);
+      button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state;
+    }
+    RunClosureAfterAllPendingUIEvents(closure);
+    return true;
+  }
+  virtual bool SendMouseClick(MouseButton type) OVERRIDE {
+    return SendMouseEvents(type, UP | DOWN);
+  }
+  virtual void RunClosureAfterAllPendingUIEvents(
+      const base::Closure& closure) OVERRIDE {
+    if (closure.is_null())
+      return;
+    static XEvent* marker_event = NULL;
+    if (!marker_event) {
+      marker_event = new XEvent();
+      marker_event->xclient.type = ClientMessage;
+      marker_event->xclient.display = x_display_;
+      marker_event->xclient.window = x_window_;
+      marker_event->xclient.format = 8;
+    }
+    marker_event->xclient.message_type = MarkerEventAtom();
+    XSendEvent(x_display_, x_window_, False, 0, marker_event);
+    new EventWaiter(closure, &Matcher);
+  }
+ private:
+  aura::Window* RootWindowForPoint(const gfx::Point& point) {
+    // Most interactive_ui_tests run inside of the aura_test_helper
+    // environment. This means that we can't rely on gfx::Screen and several
+    // other things to work properly. Therefore we hack around this by
+    // iterating across the windows owned DesktopRootWindowHostX11 since this
+    // doesn't rely on having a DesktopScreenX11.
+    std::vector<aura::Window*> windows =
+        DesktopRootWindowHostX11::GetAllOpenWindows();
+    for (std::vector<aura::Window*>::const_iterator it = windows.begin();
+         it != windows.end(); ++it) {
+      if ((*it)->GetBoundsInScreen().Contains(point)) {
+        return (*it)->GetRootWindow();
+      }
+    }
+
+    NOTREACHED() << "Coulding find RW for " << point.ToString() << " among "
+                 << windows.size() << " RWs.";
+    return NULL;
+  }
+
+  void SetKeycodeAndSendThenMask(aura::RootWindow* root_window,
+                                 XEvent* xevent,
+                                 KeySym keysym,
+                                 unsigned int mask) {
+    xevent->xkey.keycode = XKeysymToKeycode(x_display_, keysym);
+    root_window->PostNativeEvent(xevent);
+    xevent->xkey.state |= mask;
+  }
+
+  void UnmaskAndSetKeycodeThenSend(aura::RootWindow* root_window,
+                                   XEvent* xevent,
+                                   unsigned int mask,
+                                   KeySym keysym) {
+    xevent->xkey.state ^= mask;
+    xevent->xkey.keycode = XKeysymToKeycode(x_display_, keysym);
+    root_window->PostNativeEvent(xevent);
+  }
+
+  // Our X11 state.
+  Display* x_display_;
+  ::Window x_root_window_;
+
+  // Input-only window used for events.
+  ::Window x_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(UIControlsDesktopX11);
+};
+
+}  // namespace
+
+UIControlsAura* CreateUIControlsDesktopAura() {
+  return new UIControlsDesktopX11();
+}
+
+}  // namespace test
+}  // namespace views
diff --git a/ui/views/test/ui_controls_factory_desktop_aurax11.h b/ui/views/test/ui_controls_factory_desktop_aurax11.h
new file mode 100644
index 0000000..dc5c2bf
--- /dev/null
+++ b/ui/views/test/ui_controls_factory_desktop_aurax11.h
@@ -0,0 +1,16 @@
+// Copyright 2013 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_VIEWS_TEST_UI_CONTROLS_FACTORY_DESKTOP_AURAX11_H_
+#define UI_VIEWS_TEST_UI_CONTROLS_FACTORY_DESKTOP_AURAX11_H_
+
+namespace views {
+namespace test {
+
+ui_controls::UIControlsAura* CreateUIControlsDesktopAura();
+
+}  // namespace test
+}  // namespace views
+
+#endif  // UI_VIEWS_TEST_UI_CONTROLS_FACTORY_DESKTOP_AURAX11_H_
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h
index 3a0cba3..5669e7d 100644
--- a/ui/views/test/views_test_base.h
+++ b/ui/views/test/views_test_base.h
@@ -46,7 +46,7 @@
     views_delegate_.reset(views_delegate);
   }
 
-  base::MessageLoop* message_loop() { return &message_loop_; }
+  base::MessageLoopForUI* message_loop() { return &message_loop_; }
 
   // Returns a context view. In aura builds, this will be the
   // RootWindow. Everywhere else, NULL.
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 02dc07e..3b8de34 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -366,6 +366,7 @@
         'widget/desktop_aura/desktop_capture_client.cc',
         'widget/desktop_aura/desktop_capture_client.h',
         'widget/desktop_aura/desktop_cursor_loader_updater.h',
+        'widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc',
         'widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc',
         'widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h',
         'widget/desktop_aura/desktop_dispatcher_client.cc',
@@ -549,7 +550,7 @@
         }],
         ['OS=="linux" and chromeos==0', {
           'dependencies': [
-            '../ui.gyp:shell_dialogs',
+            '../shell_dialogs/shell_dialogs.gyp:shell_dialogs',
           ],
         }, { # OS=="linux" and chromeos==0
           'sources/': [
@@ -575,9 +576,6 @@
                   'user32.dll',
                 ],
               },
-              'VCCLCompilerTool': {
-                'ForcedIncludeFiles': [ 'build/intsafe_workaround.h' ],
-              },
             },
           },
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -632,6 +630,8 @@
         'test/test_views_delegate.h',
         'test/test_widget_observer.cc',
         'test/test_widget_observer.h',
+        'test/ui_controls_factory_desktop_aurax11.cc',
+        'test/ui_controls_factory_desktop_aurax11.h',
         'test/views_test_base.cc',
         'test/views_test_base.h',
         'test/widget_test.cc',
@@ -639,6 +639,12 @@
         'widget/root_view_test_helper.h',
       ],
       'conditions': [
+        ['chromeos==1', {
+          'sources!': [
+            'test/ui_controls_factory_desktop_aurax11.cc',
+            'test/ui_controls_factory_desktop_aurax11.h',
+          ],
+        }],
         ['use_aura==1', {
           'dependencies': [
             '../aura/aura.gyp:aura_test_support',
@@ -703,7 +709,7 @@
         '../gfx/gfx.gyp:gfx',
         '../ui.gyp:ui',
         '../ui.gyp:ui_resources',
-        '../ui.gyp:ui_test_support',
+        '../ui_unittests.gyp:ui_test_support',
         'views',
         'views_test_support',
       ],
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client.cc b/ui/views/widget/desktop_aura/desktop_capture_client.cc
index 5a5ec4e..a6348a9 100644
--- a/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ b/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -10,20 +10,21 @@
 namespace views {
 
 // static
-DesktopCaptureClient::Roots* DesktopCaptureClient::roots_ = NULL;
+DesktopCaptureClient::CaptureClients*
+DesktopCaptureClient::capture_clients_ = NULL;
 
 DesktopCaptureClient::DesktopCaptureClient(aura::RootWindow* root)
     : root_(root),
       capture_window_(NULL) {
-  if (!roots_)
-    roots_ = new Roots;
-  roots_->insert(root_);
+  if (!capture_clients_)
+    capture_clients_ = new CaptureClients;
+  capture_clients_->insert(this);
   aura::client::SetCaptureClient(root, this);
 }
 
 DesktopCaptureClient::~DesktopCaptureClient() {
   aura::client::SetCaptureClient(root_, NULL);
-  roots_->erase(root_);
+  capture_clients_->erase(this);
 }
 
 void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
@@ -38,9 +39,6 @@
 
   aura::Window* old_capture_window = capture_window_;
 
-  // Copy the set in case it's modified out from under us.
-  Roots roots(*roots_);
-
   // If we're actually starting capture, then cancel any touches/gestures
   // that aren't already locked to the new window, and transfer any on the
   // old capture window to the new one.  When capture is released we have no
@@ -62,6 +60,17 @@
     delegate->ReleaseNativeCapture();
   } else if (!old_capture_window) {
     delegate->SetNativeCapture();
+
+    // Notify the other roots that we got capture. This is important so that
+    // they reset state.
+    CaptureClients capture_clients(*capture_clients_);
+    for (CaptureClients::iterator i = capture_clients.begin();
+         i != capture_clients.end(); ++i) {
+      if (*i != this) {
+        aura::client::CaptureDelegate* delegate = (*i)->root_;
+        delegate->OnOtherRootGotCapture();
+      }
+    }
   }  // else case is capture is remaining in our root, nothing to do.
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client.h b/ui/views/widget/desktop_aura/desktop_capture_client.h
index fc075f3..5f8cecf 100644
--- a/ui/views/widget/desktop_aura/desktop_capture_client.h
+++ b/ui/views/widget/desktop_aura/desktop_capture_client.h
@@ -12,6 +12,10 @@
 #include "ui/aura/client/capture_client.h"
 #include "ui/views/views_export.h"
 
+namespace aura {
+class RootWindow;
+}
+
 namespace views {
 
 // Desktop implementation of CaptureClient. There is one CaptureClient per
@@ -27,13 +31,13 @@
   virtual aura::Window* GetCaptureWindow() OVERRIDE;
 
  private:
-  typedef std::set<aura::RootWindow*> Roots;
+  typedef std::set<DesktopCaptureClient*> CaptureClients;
 
   aura::RootWindow* root_;
   aura::Window* capture_window_;
 
-  // Set of RootWindows DesktopCaptureClient has been created for.
-  static Roots* roots_;
+  // Set of DesktopCaptureClients.
+  static CaptureClients* capture_clients_;
 
   DISALLOW_COPY_AND_ASSIGN(DesktopCaptureClient);
 };
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
index c312142..599b625 100644
--- a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
@@ -5,6 +5,9 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_
 
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/views_export.h"
+
 namespace aura {
 class RootWindow;
 }
@@ -21,10 +24,14 @@
 
 // An interface to optionally update the state of a cursor loader. Only used on
 // desktop AuraX11.
-class DesktopCursorLoaderUpdater {
+class VIEWS_EXPORT DesktopCursorLoaderUpdater {
  public:
   virtual ~DesktopCursorLoaderUpdater() {}
 
+  // Creates a new DesktopCursorLoaderUpdater, or NULL if the platform doesn't
+  // support one.
+  static scoped_ptr<DesktopCursorLoaderUpdater> Create();
+
   // Called when a CursorLoader is created.
   virtual void OnCreate(aura::RootWindow* window,
                         ui::CursorLoader* loader) = 0;
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc
new file mode 100644
index 0000000..cb94880
--- /dev/null
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+
+namespace views {
+
+// static
+scoped_ptr<DesktopCursorLoaderUpdater> DesktopCursorLoaderUpdater::Create() {
+  return scoped_ptr<DesktopCursorLoaderUpdater>().Pass();
+}
+
+}  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc
index 88f2193..16b5ca1 100644
--- a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.cc
@@ -64,4 +64,10 @@
   LoadImageCursors(display.device_scale_factor(), loader);
 }
 
+// static
+scoped_ptr<DesktopCursorLoaderUpdater> DesktopCursorLoaderUpdater::Create() {
+  return scoped_ptr<DesktopCursorLoaderUpdater>(
+      new DesktopCursorLoaderUpdaterAuraX11).Pass();
+}
+
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index 2657277..3b3ae39 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -366,7 +366,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     views::DesktopNativeCursorManager* cursor_manager,
     Display* xdisplay,
     ::Window xwindow)
@@ -562,7 +562,7 @@
 
 int DesktopDragDropClientAuraX11::StartDragAndDrop(
     const ui::OSExchangeData& data,
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& root_location,
     int operation,
@@ -681,7 +681,7 @@
     scoped_ptr<ui::DropTargetEvent>* event,
     aura::client::DragDropDelegate** delegate) {
   gfx::Point root_location = root_window_location;
-  root_window_->ConvertPointFromNativeScreen(&root_location);
+  root_window_->GetDispatcher()->ConvertPointFromNativeScreen(&root_location);
   aura::Window* target_window =
       root_window_->GetEventHandlerForPoint(root_location);
   bool target_window_changed = false;
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index 5913972..739fe53 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -5,12 +5,8 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
 
-#include <X11/Xlib.h>
-
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
-
 #include <set>
+#include <X11/Xlib.h>
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
@@ -25,7 +21,6 @@
 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
 
 namespace aura {
-class RootWindow;
 namespace client {
 class DragDropDelegate;
 }
@@ -40,7 +35,6 @@
 class DropTargetEvent;
 class OSExchangeData;
 class OSExchangeDataProviderAuraX11;
-class RootWindow;
 class SelectionFormatMap;
 }
 
@@ -56,7 +50,7 @@
       public X11WholeScreenMoveLoopDelegate {
  public:
   DesktopDragDropClientAuraX11(
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       views::DesktopNativeCursorManager* cursor_manager,
       Display* xdisplay,
       ::Window xwindow);
@@ -81,7 +75,7 @@
   // Overridden from aura::client::DragDropClient:
   virtual int StartDragAndDrop(
       const ui::OSExchangeData& data,
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       aura::Window* source_window,
       const gfx::Point& root_location,
       int operation,
@@ -155,7 +149,7 @@
   // X11WholeScreenMoveLoopDelegate interface.
   X11WholeScreenMoveLoop move_loop_;
 
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   Display* xdisplay_;
   ::Window xwindow_;
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
index 0c9b50b..5669f31 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -15,7 +15,7 @@
 namespace views {
 
 DesktopDragDropClientWin::DesktopDragDropClientWin(
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     HWND window)
     : drag_drop_in_progress_(false),
       drag_operation_(0) {
@@ -27,7 +27,7 @@
 
 int DesktopDragDropClientWin::StartDragAndDrop(
     const ui::OSExchangeData& data,
-    aura::RootWindow* root_window,
+    aura::Window* root_window,
     aura::Window* source_window,
     const gfx::Point& root_location,
     int operation,
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
index 7aa4952..042a5a8 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
@@ -12,7 +12,6 @@
 
 namespace ui {
 class DragSourceWin;
-class RootWindow;
 }
 
 namespace views {
@@ -22,13 +21,13 @@
 class VIEWS_EXPORT DesktopDragDropClientWin
     : public aura::client::DragDropClient {
  public:
-  DesktopDragDropClientWin(aura::RootWindow* root_window, HWND window);
+  DesktopDragDropClientWin(aura::Window* root_window, HWND window);
   virtual ~DesktopDragDropClientWin();
 
   // Overridden from aura::client::DragDropClient:
   virtual int StartDragAndDrop(
       const ui::OSExchangeData& data,
-      aura::RootWindow* root_window,
+      aura::Window* root_window,
       aura::Window* source_window,
       const gfx::Point& root_location,
       int operation,
diff --git a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index 5fb1091..1a9150f 100644
--- a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -20,7 +20,7 @@
 
 namespace views {
 
-DesktopDropTargetWin::DesktopDropTargetWin(aura::RootWindow* root_window,
+DesktopDropTargetWin::DesktopDropTargetWin(aura::Window* root_window,
                                            HWND window)
     : ui::DropTargetWin(window),
       root_window_(root_window),
@@ -96,7 +96,7 @@
     DragDropDelegate** delegate) {
   gfx::Point location(position.x, position.y);
   gfx::Point root_location = location;
-  root_window_->ConvertPointFromNativeScreen(&root_location);
+  root_window_->GetDispatcher()->ConvertPointFromNativeScreen(&root_location);
   aura::Window* target_window =
       root_window_->GetEventHandlerForPoint(root_location);
   bool target_window_changed = false;
diff --git a/ui/views/widget/desktop_aura/desktop_drop_target_win.h b/ui/views/widget/desktop_aura/desktop_drop_target_win.h
index 3fde71f..113fd75 100644
--- a/ui/views/widget/desktop_aura/desktop_drop_target_win.h
+++ b/ui/views/widget/desktop_aura/desktop_drop_target_win.h
@@ -10,7 +10,6 @@
 #include "ui/base/dragdrop/drop_target_win.h"
 
 namespace aura {
-class RootWindow;
 namespace client {
 class DragDropDelegate;
 }
@@ -29,7 +28,7 @@
 class DesktopDropTargetWin : public ui::DropTargetWin,
                              public aura::WindowObserver {
  public:
-  DesktopDropTargetWin(aura::RootWindow* root_window, HWND window);
+  DesktopDropTargetWin(aura::Window* root_window, HWND window);
   virtual ~DesktopDropTargetWin();
 
  private:
@@ -64,7 +63,7 @@
   void NotifyDragLeave();
 
   // The root window associated with this drop target.
-  aura::RootWindow* root_window_;
+  aura::Window* root_window_;
 
   // The Aura window that is currently under the cursor. We need to manually
   // keep track of this because Windows will only call our drag enter method
diff --git a/ui/views/widget/desktop_aura/desktop_factory_ozone.h b/ui/views/widget/desktop_aura/desktop_factory_ozone.h
index 18cf36e..e557d3b 100644
--- a/ui/views/widget/desktop_aura/desktop_factory_ozone.h
+++ b/ui/views/widget/desktop_aura/desktop_factory_ozone.h
@@ -34,8 +34,7 @@
   // Ozone implementation.
   virtual DesktopRootWindowHost* CreateRootWindowHost(
       internal::NativeWidgetDelegate* native_widget_delegate,
-      DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds) = 0;
+      DesktopNativeWidgetAura* desktop_native_widget_aura) = 0;
 
  private:
   static DesktopFactoryOzone* impl_; // not owned
diff --git a/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/ui/views/widget/desktop_aura/desktop_focus_rules.cc
index 9aaf301..475facf 100644
--- a/ui/views/widget/desktop_aura/desktop_focus_rules.cc
+++ b/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -21,6 +21,14 @@
          window->GetRootWindow() == window;
 }
 
+bool DesktopFocusRules::IsWindowConsideredVisibleForActivation(
+    aura::Window* window) const {
+  // |content_window_| is initially hidden and made visible from Show(). Even in
+  // this state we still want it to be active.
+  return BaseFocusRules::IsWindowConsideredVisibleForActivation(window) ||
+      (window == content_window_);
+}
+
 aura::Window* DesktopFocusRules::GetToplevelWindow(
     aura::Window* window) const {
   aura::Window* top_level_window =
diff --git a/ui/views/widget/desktop_aura/desktop_focus_rules.h b/ui/views/widget/desktop_aura/desktop_focus_rules.h
index 83ef323..fff8116 100644
--- a/ui/views/widget/desktop_aura/desktop_focus_rules.h
+++ b/ui/views/widget/desktop_aura/desktop_focus_rules.h
@@ -17,6 +17,8 @@
  private:
   // Overridden from corewm::BaseFocusRules:
   virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE;
+  virtual bool IsWindowConsideredVisibleForActivation(
+      aura::Window* window) const OVERRIDE;
   virtual aura::Window* GetToplevelWindow(aura::Window* window) const OVERRIDE;
   virtual aura::Window* GetNextActivatableWindow(
       aura::Window* window) const OVERRIDE;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index d4e47be..e1c56dd 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -8,8 +8,9 @@
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/drag_drop_client.h"
 #include "ui/aura/client/focus_client.h"
-#include "ui/aura/client/stacking_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/root_window_host.h"
 #include "ui/aura/window.h"
@@ -25,7 +26,10 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/corewm/compound_event_filter.h"
 #include "ui/views/corewm/corewm_switches.h"
+#include "ui/views/corewm/cursor_manager.h"
+#include "ui/views/corewm/focus_controller.h"
 #include "ui/views/corewm/input_method_event_filter.h"
+#include "ui/views/corewm/native_cursor_manager.h"
 #include "ui/views/corewm/shadow_controller.h"
 #include "ui/views/corewm/shadow_types.h"
 #include "ui/views/corewm/tooltip.h"
@@ -36,7 +40,12 @@
 #include "ui/views/ime/input_method.h"
 #include "ui/views/ime/input_method_bridge.h"
 #include "ui/views/widget/desktop_aura/desktop_capture_client.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
 #include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
 #include "ui/views/widget/drop_helper.h"
 #include "ui/views/widget/native_widget_aura.h"
 #include "ui/views/widget/root_view.h"
@@ -132,18 +141,19 @@
   DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetTopLevelHandler);
 };
 
-class DesktopNativeWidgetAuraStackingClient :
-    public aura::client::StackingClient {
+class DesktopNativeWidgetAuraWindowTreeClient :
+    public aura::client::WindowTreeClient {
  public:
-  explicit DesktopNativeWidgetAuraStackingClient(aura::RootWindow* root_window)
+  explicit DesktopNativeWidgetAuraWindowTreeClient(
+      aura::RootWindow* root_window)
       : root_window_(root_window) {
-    aura::client::SetStackingClient(root_window_, this);
+    aura::client::SetWindowTreeClient(root_window_, this);
   }
-  virtual ~DesktopNativeWidgetAuraStackingClient() {
-    aura::client::SetStackingClient(root_window_, NULL);
+  virtual ~DesktopNativeWidgetAuraWindowTreeClient() {
+    aura::client::SetWindowTreeClient(root_window_, NULL);
   }
 
-  // Overridden from client::StackingClient:
+  // Overridden from client::WindowTreeClient:
   virtual aura::Window* GetDefaultParent(aura::Window* context,
                                          aura::Window* window,
                                          const gfx::Rect& bounds) OVERRIDE {
@@ -166,7 +176,7 @@
  private:
   aura::RootWindow* root_window_;
 
-  DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAuraStackingClient);
+  DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAuraWindowTreeClient);
 };
 
 }  // namespace
@@ -214,8 +224,8 @@
   if (window_modality_controller_)
     window_modality_controller_.reset();
 
-  // Make sure we don't still have capture. Otherwise CaptureController and
-  // RootWindow are left referencing a deleted Window.
+  // Make sure we don't have capture. Otherwise CaptureController and RootWindow
+  // are left referencing a deleted Window.
   {
     aura::Window* capture_window = capture_client_->GetCaptureWindow();
     if (capture_window && root_window_->Contains(capture_window))
@@ -232,7 +242,7 @@
 
   root_window_event_filter_->RemoveHandler(input_method_event_filter_.get());
 
-  stacking_client_.reset();  // Uses root_window_ at destruction.
+  window_tree_client_.reset();  // Uses root_window_ at destruction.
 
   capture_client_.reset();  // Uses root_window_ at destruction.
 
@@ -247,27 +257,25 @@
     delete this;
 }
 
-void DesktopNativeWidgetAura::InstallInputMethodEventFilter(
+void DesktopNativeWidgetAura::OnDesktopRootWindowHostDestroyed(
     aura::RootWindow* root) {
-  DCHECK(!input_method_event_filter_.get());
+  // |root_window_| is still valid, but DesktopRootWindowHost is nearly
+  // destroyed. Do cleanup here of members DesktopRootWindowHost may also use.
+  aura::client::SetFocusClient(root, NULL);
+  aura::client::SetActivationClient(root, NULL);
+  focus_client_.reset();
 
-  // CEF sets focus to the window the user clicks down on.
-  // TODO(beng): see if we can't do this some other way. CEF seems a heavy-
-  //             handed way of accomplishing focus.
-  // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
-  root_window_event_filter_ = new corewm::CompoundEventFilter;
-  // Pass ownership of the filter to the root_window.
-  root->SetEventFilter(root_window_event_filter_);
+  aura::client::SetDispatcherClient(root, NULL);
+  dispatcher_client_.reset();
 
-  input_method_event_filter_.reset(
-      new corewm::InputMethodEventFilter(root->GetAcceleratedWidget()));
-  input_method_event_filter_->SetInputMethodPropertyInRootWindow(root);
-  root_window_event_filter_->AddHandler(input_method_event_filter_.get());
-}
+  aura::client::SetCursorClient(root, NULL);
+  cursor_client_.reset();
 
-void DesktopNativeWidgetAura::CreateCaptureClient(aura::RootWindow* root) {
-  DCHECK(!capture_client_.get());
-  capture_client_.reset(new DesktopCaptureClient(root));
+  aura::client::SetScreenPositionClient(root, NULL);
+  position_client_.reset();
+
+  aura::client::SetDragDropClient(root, NULL);
+  drag_drop_client_.reset();
 }
 
 void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
@@ -301,16 +309,6 @@
   }
 }
 
-void DesktopNativeWidgetAura::InstallWindowModalityController(
-    aura::RootWindow* root) {
-  // The WindowsModalityController event filter should be at the head of the
-  // pre target handlers list. This ensures that it handles input events first
-  // when modal windows are at the top of the Zorder.
-  if (widget_type_ == Widget::InitParams::TYPE_WINDOW)
-    window_modality_controller_.reset(
-        new views::corewm::WindowModalityController(root));
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
 
@@ -328,38 +326,93 @@
     content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
   }
   content_window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
+  content_window_->SetTransparent(true);
   content_window_->Init(params.layer_type);
   corewm::SetShadowType(content_window_, corewm::SHADOW_TYPE_NONE);
-#if defined(OS_LINUX)  // TODO(scottmg): http://crbug.com/180071
-  content_window_->Show();
-#endif
-
-  desktop_root_window_host_ = params.desktop_root_window_host ?
-      params.desktop_root_window_host :
-      DesktopRootWindowHost::Create(native_widget_delegate_,
-                                    this, params.bounds);
-  root_window_.reset(
-      desktop_root_window_host_->Init(content_window_, params));
-
-  UpdateWindowTransparency();
 
   content_window_container_ = new aura::Window(NULL);
   content_window_container_->Init(ui::LAYER_NOT_DRAWN);
   content_window_container_->Show();
   content_window_container_->AddChild(content_window_);
+
+  desktop_root_window_host_ = params.desktop_root_window_host ?
+      params.desktop_root_window_host :
+      DesktopRootWindowHost::Create(native_widget_delegate_, this);
+  aura::RootWindow::CreateParams rw_params(params.bounds);
+  desktop_root_window_host_->Init(content_window_, params, &rw_params);
+
+  root_window_.reset(new aura::RootWindow(rw_params));
+  root_window_->Init();
   root_window_->AddChild(content_window_container_);
+
+  // The WindowsModalityController event filter should be at the head of the
+  // pre target handlers list. This ensures that it handles input events first
+  // when modal windows are at the top of the Zorder.
+  if (widget_type_ == Widget::InitParams::TYPE_WINDOW)
+    window_modality_controller_.reset(
+        new views::corewm::WindowModalityController(root_window_.get()));
+
+  // |root_window_event_filter_| must be created before
+  // OnRootWindowHostCreated() is invoked.
+
+  // CEF sets focus to the window the user clicks down on.
+  // TODO(beng): see if we can't do this some other way. CEF seems a heavy-
+  //             handed way of accomplishing focus.
+  // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
+  root_window_event_filter_ = new corewm::CompoundEventFilter;
+  // Pass ownership of the filter to the root_window.
+  root_window_->SetEventFilter(root_window_event_filter_);
+
+  desktop_root_window_host_->OnRootWindowCreated(root_window_.get(), params);
+
+  native_widget_delegate_->OnNativeWidgetCreated(true);
+
+  capture_client_.reset(new DesktopCaptureClient(root_window_.get()));
+
+  corewm::FocusController* focus_controller =
+      new corewm::FocusController(new DesktopFocusRules(content_window_));
+  focus_client_.reset(focus_controller);
+  aura::client::SetFocusClient(root_window_.get(), focus_controller);
+  aura::client::SetActivationClient(root_window_.get(), focus_controller);
+  root_window_->AddPreTargetHandler(focus_controller);
+
+  dispatcher_client_.reset(new DesktopDispatcherClient);
+  aura::client::SetDispatcherClient(root_window_.get(),
+                                    dispatcher_client_.get());
+
+  DesktopNativeCursorManager* desktop_native_cursor_manager =
+      new views::DesktopNativeCursorManager(
+          root_window_.get(),
+          DesktopCursorLoaderUpdater::Create());
+  cursor_client_.reset(
+      new views::corewm::CursorManager(
+          scoped_ptr<corewm::NativeCursorManager>(
+              desktop_native_cursor_manager)));
+  aura::client::SetCursorClient(root_window_.get(), cursor_client_.get());
+
+  position_client_.reset(new DesktopScreenPositionClient());
+  aura::client::SetScreenPositionClient(root_window_.get(),
+                                        position_client_.get());
+
+  InstallInputMethodEventFilter();
+
+  drag_drop_client_ = desktop_root_window_host_->CreateDragDropClient(
+      desktop_native_cursor_manager);
+  aura::client::SetDragDropClient(root_window_.get(), drag_drop_client_.get());
+
+  focus_client_->FocusWindow(content_window_);
+
   OnRootWindowHostResized(root_window_.get());
 
   root_window_->AddRootWindowObserver(this);
 
-  stacking_client_.reset(
-      new DesktopNativeWidgetAuraStackingClient(root_window_.get()));
+  window_tree_client_.reset(
+      new DesktopNativeWidgetAuraWindowTreeClient(root_window_.get()));
   drop_helper_.reset(new DropHelper(
       static_cast<internal::RootView*>(GetWidget()->GetRootView())));
   aura::client::SetDragDropDelegate(content_window_, this);
 
-  tooltip_manager_.reset(new views::TooltipManagerAura(content_window_,
-                                                       GetWidget()));
+  tooltip_manager_.reset(new TooltipManagerAura(GetWidget()));
 
   tooltip_controller_.reset(
       new corewm::TooltipController(
@@ -382,7 +435,6 @@
     root_window_->AddPreTargetHandler(focus_manager->GetEventHandler());
   }
 
-  content_window_->Show();
   aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
 
   aura::client::SetActivationDelegate(content_window_, this);
@@ -405,7 +457,6 @@
 
 void DesktopNativeWidgetAura::FrameTypeChanged() {
   desktop_root_window_host_->FrameTypeChanged();
-  UpdateWindowTransparency();
 }
 
 Widget* DesktopNativeWidgetAura::GetWidget() {
@@ -859,6 +910,7 @@
   DCHECK(content_window_->IsVisible());
   if (tooltip_manager_.get())
     tooltip_manager_->UpdateTooltip();
+  TooltipManagerAura::UpdateTooltipManagerForCapture(GetWidget());
   native_widget_delegate_->OnMouseEvent(event);
   // WARNING: we may have been deleted.
 }
@@ -987,6 +1039,12 @@
 
 void DesktopNativeWidgetAura::OnRootWindowHostResized(
     const aura::RootWindow* root) {
+  // Don't update the bounds of the child layers when animating closed. If we
+  // did it would force a paint, which we don't want. We don't want the paint
+  // as we can't assume any of the children are valid.
+  if (desktop_root_window_host_->IsAnimatingClosed())
+    return;
+
   gfx::Rect new_bounds = gfx::Rect(root->bounds().size());
   // TODO(ananta)
   // This code by default scales the bounds rectangle by 1.
@@ -1016,8 +1074,14 @@
   return this;
 }
 
-void DesktopNativeWidgetAura::UpdateWindowTransparency() {
-  content_window_->SetTransparent(ShouldUseNativeFrame());
+void DesktopNativeWidgetAura::InstallInputMethodEventFilter() {
+  DCHECK(!input_method_event_filter_.get());
+
+  input_method_event_filter_.reset(
+      new corewm::InputMethodEventFilter(root_window_->GetAcceleratedWidget()));
+  input_method_event_filter_->SetInputMethodPropertyInRootWindow(
+      root_window_.get());
+  root_window_event_filter_->AddHandler(input_method_event_filter_.get());
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index c07ede9..6fc4b35 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -19,7 +19,10 @@
 namespace aura {
 class RootWindow;
 namespace client {
-class StackingClient;
+class DragDropClient;
+class FocusClient;
+class ScreenPositionClient;
+class WindowTreeClient;
 }
 }
 
@@ -27,6 +30,7 @@
 
 namespace corewm {
 class CompoundEventFilter;
+class CursorManager;
 class InputMethodEventFilter;
 class ShadowController;
 class TooltipController;
@@ -35,6 +39,7 @@
 }
 
 class DesktopCaptureClient;
+class DesktopDispatcherClient;
 class DesktopRootWindowHost;
 class DropHelper;
 class TooltipManagerAura;
@@ -60,9 +65,10 @@
   // this is the signal that we should start our shutdown.
   virtual void OnHostClosed();
 
-  // Installs the input method filter on |root|. This is intended to be invoked
-  // by the DesktopRootWindowHost implementation during Init().
-  void InstallInputMethodEventFilter(aura::RootWindow* root);
+  // Called from ~DesktopRootWindowHost. This takes the RootWindow as by the
+  // time we get here |root_window_| is NULL.
+  virtual void OnDesktopRootWindowHostDestroyed(aura::RootWindow* root);
+
   corewm::InputMethodEventFilter* input_method_event_filter() {
     return input_method_event_filter_.get();
   }
@@ -70,9 +76,6 @@
     return root_window_event_filter_;
   }
 
-  // Invoked from DesktopRootWindowHost creation to create the CaptureClient.
-  void CreateCaptureClient(aura::RootWindow* root);
-
   // Overridden from NativeWidget:
   virtual ui::EventHandler* GetEventHandler() OVERRIDE;
 
@@ -80,11 +83,6 @@
   // we are being activated/deactivated.
   void HandleActivationChanged(bool active);
 
-  // Installs the window modality controller event filter on the |root|. This
-  // should be invoked by the DesktopRootWindowHost implementation immediately
-  // after creation of the RootWindow.
-  void InstallWindowModalityController(aura::RootWindow* root);
-
  protected:
   // Overridden from internal::NativeWidgetPrivate:
   virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
@@ -225,6 +223,9 @@
                                      const gfx::Point& new_origin) OVERRIDE;
 
  private:
+  // Installs the input method filter.
+  void InstallInputMethodEventFilter();
+
   // To save a clear on platforms where the window is never transparent, the
   // window is only set as transparent when the glass frame is in use.
   void UpdateWindowTransparency();
@@ -258,7 +259,12 @@
 
   internal::NativeWidgetDelegate* native_widget_delegate_;
 
-  scoped_ptr<aura::client::StackingClient> stacking_client_;
+  scoped_ptr<aura::client::FocusClient> focus_client_;
+  scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
+  scoped_ptr<views::corewm::CursorManager> cursor_client_;
+  scoped_ptr<aura::client::ScreenPositionClient> position_client_;
+  scoped_ptr<aura::client::DragDropClient> drag_drop_client_;
+  scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
 
   // Toplevel event filter which dispatches to other event filters.
   corewm::CompoundEventFilter* root_window_event_filter_;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 126ce6d..7d844f5 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -53,4 +53,16 @@
             widget.GetNativeView()->parent()->bounds().ToString());
 }
 
+// Verifies GetNativeView() is initially hidden. If the native view is initially
+// shown then animations can not be disabled.
+TEST_F(DesktopNativeWidgetAuraTest, NativeViewInitiallyHidden) {
+  Widget widget;
+  Widget::InitParams init_params =
+      CreateParams(Widget::InitParams::TYPE_WINDOW);
+  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+  widget.Init(init_params);
+  EXPECT_FALSE(widget.GetNativeView()->IsVisible());
+}
+
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host.h b/ui/views/widget/desktop_aura/desktop_root_window_host.h
index e15a781..ad904fa 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host.h
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "ui/aura/root_window.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/widget.h"
@@ -13,6 +14,10 @@
 namespace aura {
 class RootWindowHost;
 class Window;
+
+namespace client {
+class DragDropClient;
+}
 }
 
 namespace gfx {
@@ -26,11 +31,15 @@
 
 namespace views {
 namespace corewm {
+
 class Tooltip;
 }
+
 namespace internal {
 class NativeWidgetDelegate;
 }
+
+class DesktopNativeCursorManager;
 class DesktopNativeWidgetAura;
 
 class VIEWS_EXPORT DesktopRootWindowHost {
@@ -39,23 +48,31 @@
 
   static DesktopRootWindowHost* Create(
       internal::NativeWidgetDelegate* native_widget_delegate,
-      DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds);
+      DesktopNativeWidgetAura* desktop_native_widget_aura);
 
   // Return the NativeTheme to use for |window|. WARNING: |window| may be NULL.
   static ui::NativeTheme* GetNativeTheme(aura::Window* window);
 
-  // Creates the aura resources associated with the native window we built.
-  // Caller takes ownership of returned RootWindow.
-  virtual aura::RootWindow* Init(aura::Window* content_window,
-                                 const Widget::InitParams& params) = 0;
-  virtual void InitFocus(aura::Window* window) = 0;
+  // Sets up resources needed before the RootWindow has been created.
+  virtual void Init(aura::Window* content_window,
+                    const Widget::InitParams& params,
+                    aura::RootWindow::CreateParams* rw_create_params) = 0;
+
+  // Invoked once the RootWindow has been created. Caller owns the RootWindow.
+  virtual void OnRootWindowCreated(aura::RootWindow* root,
+                                   const Widget::InitParams& params) = 0;
 
   // Creates and returns the Tooltip implementation to use. Return value is
   // owned by DesktopNativeWidgetAura and lives as long as
   // DesktopRootWindowHost.
   virtual scoped_ptr<corewm::Tooltip> CreateTooltip() = 0;
 
+  // Creates and returns the DragDropClient implementation to use. Return value
+  // is owned by DesktopNativeWidgetAura and lives as long as
+  // DesktopRootWindowHost.
+  virtual scoped_ptr<aura::client::DragDropClient> CreateDragDropClient(
+      DesktopNativeCursorManager* cursor_manager) = 0;
+
   virtual void Close() = 0;
   virtual void CloseNow() = 0;
 
@@ -126,6 +143,10 @@
   // blurred.
   virtual void OnNativeWidgetFocus() = 0;
   virtual void OnNativeWidgetBlur() = 0;
+
+  // Returns true if the Widget was closed but is still showing because of
+  // animations.
+  virtual bool IsAnimatingClosed() const = 0;
 };
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc
index ff905a3..b8877d3 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc
@@ -10,13 +10,11 @@
 
 DesktopRootWindowHost* DesktopRootWindowHost::Create(
     internal::NativeWidgetDelegate* native_widget_delegate,
-    DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds) {
+    DesktopNativeWidgetAura* desktop_native_widget_aura) {
   DesktopFactoryOzone* d_factory = DesktopFactoryOzone::GetInstance();
 
   return d_factory->CreateRootWindowHost(native_widget_delegate,
-                                         desktop_native_widget_aura,
-                                         initial_bounds);
+                                         desktop_native_widget_aura);
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
index e1c627f..2dad0d9 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
@@ -25,19 +25,14 @@
 #include "ui/native_theme/native_theme_win.h"
 #include "ui/views/corewm/compound_event_filter.h"
 #include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/cursor_manager.h"
-#include "ui/views/corewm/focus_controller.h"
 #include "ui/views/corewm/input_method_event_filter.h"
 #include "ui/views/corewm/tooltip_win.h"
 #include "ui/views/corewm/window_animations.h"
 #include "ui/views/ime/input_method_bridge.h"
 #include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
-#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
-#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/widget/widget_hwnd_utils.h"
@@ -54,14 +49,14 @@
 
 DesktopRootWindowHostWin::DesktopRootWindowHostWin(
     internal::NativeWidgetDelegate* native_widget_delegate,
-    DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds)
+    DesktopNativeWidgetAura* desktop_native_widget_aura)
     : root_window_(NULL),
       message_handler_(new HWNDMessageHandler(this)),
       native_widget_delegate_(native_widget_delegate),
       desktop_native_widget_aura_(desktop_native_widget_aura),
       root_window_host_delegate_(NULL),
       content_window_(NULL),
+      drag_drop_client_(NULL),
       should_animate_window_close_(false),
       pending_close_(false),
       has_non_client_view_(false),
@@ -70,12 +65,8 @@
 
 DesktopRootWindowHostWin::~DesktopRootWindowHostWin() {
   // WARNING: |content_window_| has been destroyed by the time we get here.
-  aura::client::SetFocusClient(root_window_, NULL);
-  aura::client::SetActivationClient(root_window_, NULL);
-  aura::client::SetScreenPositionClient(root_window_, NULL);
-  aura::client::SetDispatcherClient(root_window_, NULL);
-  aura::client::SetCursorClient(root_window_, NULL);
-  aura::client::SetDragDropClient(root_window_, NULL);
+  desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(
+      root_window_);
 }
 
 // static
@@ -88,11 +79,12 @@
 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
   // Use NativeThemeWin for windows shown on the desktop, those not on the
   // desktop come from Ash and get NativeThemeAura.
-  aura::RootWindow* root = window ? window->GetRootWindow() : NULL;
-  if (root) {
-    HWND root_hwnd = root->GetAcceleratedWidget();
-    if (root_hwnd &&
-        DesktopRootWindowHostWin::GetContentWindowForHWND(root_hwnd)) {
+  aura::WindowEventDispatcher* dispatcher =
+      window ? window->GetDispatcher() : NULL;
+  if (dispatcher) {
+    HWND host_hwnd = dispatcher->GetAcceleratedWidget();
+    if (host_hwnd &&
+        DesktopRootWindowHostWin::GetContentWindowForHWND(host_hwnd)) {
       return ui::NativeThemeWin::instance();
     }
   }
@@ -102,19 +94,22 @@
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostWin, DesktopRootWindowHost implementation:
 
-aura::RootWindow* DesktopRootWindowHostWin::Init(
+void DesktopRootWindowHostWin::Init(
     aura::Window* content_window,
-    const Widget::InitParams& params) {
+    const Widget::InitParams& params,
+    aura::RootWindow::CreateParams* rw_create_params) {
   // TODO(beng): SetInitParams().
   content_window_ = content_window;
 
+  aura::client::SetAnimationHost(content_window_, this);
+
   ConfigureWindowStyles(message_handler_.get(), params,
                         GetWidget()->widget_delegate(),
                         native_widget_delegate_);
 
   HWND parent_hwnd = NULL;
-  if (params.parent && params.parent->GetRootWindow())
-    parent_hwnd = params.parent->GetRootWindow()->GetAcceleratedWidget();
+  if (params.parent && params.parent->GetDispatcher())
+    parent_hwnd = params.parent->GetDispatcher()->GetAcceleratedWidget();
 
   message_handler_->set_remove_standard_frame(params.remove_standard_frame);
 
@@ -123,61 +118,24 @@
   gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
   message_handler_->Init(parent_hwnd, pixel_bounds);
 
-  aura::RootWindow::CreateParams rw_params(params.bounds);
-  rw_params.host = this;
-  root_window_ = new aura::RootWindow(rw_params);
+  rw_create_params->host = this;
+  rw_create_params->use_software_renderer =
+      params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
+}
 
-  SetWindowTransparency();
-  root_window_->Init();
-  root_window_->AddChild(content_window_);
+void DesktopRootWindowHostWin::OnRootWindowCreated(
+    aura::RootWindow* root,
+    const Widget::InitParams& params) {
+  root_window_ = root;
 
-  desktop_native_widget_aura_->InstallWindowModalityController(root_window_);
-  desktop_native_widget_aura_->CreateCaptureClient(root_window_);
-
-  corewm::FocusController* focus_controller =
-      new corewm::FocusController(new DesktopFocusRules(content_window));
-  focus_client_.reset(focus_controller);
-  aura::client::SetFocusClient(root_window_, focus_controller);
-  aura::client::SetActivationClient(root_window_, focus_controller);
-  root_window_->AddPreTargetHandler(focus_controller);
-
-  dispatcher_client_.reset(new DesktopDispatcherClient);
-  aura::client::SetDispatcherClient(root_window_,
-                                    dispatcher_client_.get());
-
-  cursor_client_.reset(
-      new views::corewm::CursorManager(
-          scoped_ptr<corewm::NativeCursorManager>(
-              new views::DesktopNativeCursorManager(
-                  root_window_,
-                  scoped_ptr<DesktopCursorLoaderUpdater>()))));
-  aura::client::SetCursorClient(root_window_,
-                                cursor_client_.get());
-
-  position_client_.reset(new DesktopScreenPositionClient());
-  aura::client::SetScreenPositionClient(root_window_,
-                                        position_client_.get());
-
-  desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_);
-
-  drag_drop_client_.reset(new DesktopDragDropClientWin(root_window_,
-                                                       GetHWND()));
-  aura::client::SetDragDropClient(root_window_, drag_drop_client_.get());
-
-  focus_client_->FocusWindow(content_window_);
   root_window_->SetProperty(kContentWindowForRootWindow, content_window_);
 
-  aura::client::SetAnimationHost(content_window_, this);
-
   should_animate_window_close_ =
       content_window_->type() != aura::client::WINDOW_TYPE_NORMAL &&
       !views::corewm::WindowAnimationsDisabled(content_window_);
 
-  return root_window_;
-}
-
-void DesktopRootWindowHostWin::InitFocus(aura::Window* window) {
-  focus_client_->FocusWindow(window);
+  root_window_->compositor()->SetHostHasTransparentBackground(true);
+  root_window_->SetTransparent(true);
 }
 
 scoped_ptr<corewm::Tooltip> DesktopRootWindowHostWin::CreateTooltip() {
@@ -186,6 +144,13 @@
   return scoped_ptr<corewm::Tooltip>(tooltip_);
 }
 
+scoped_ptr<aura::client::DragDropClient>
+DesktopRootWindowHostWin::CreateDragDropClient(
+    DesktopNativeCursorManager* cursor_manager) {
+  drag_drop_client_ = new DesktopDragDropClientWin(root_window_, GetHWND());
+  return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
+}
+
 void DesktopRootWindowHostWin::Close() {
   if (should_animate_window_close_) {
     pending_close_ = true;
@@ -351,7 +316,6 @@
 
 void DesktopRootWindowHostWin::FrameTypeChanged() {
   message_handler_->FrameTypeChanged();
-  SetWindowTransparency();
 }
 
 NonClientFrameView* DesktopRootWindowHostWin::CreateNonClientFrameView() {
@@ -361,7 +325,6 @@
 
 void DesktopRootWindowHostWin::SetFullscreen(bool fullscreen) {
   message_handler_->fullscreen_handler()->SetFullscreen(fullscreen);
-  SetWindowTransparency();
 }
 
 bool DesktopRootWindowHostWin::IsFullscreen() const {
@@ -397,6 +360,10 @@
 void DesktopRootWindowHostWin::OnNativeWidgetBlur() {
 }
 
+bool DesktopRootWindowHostWin::IsAnimatingClosed() const {
+  return pending_close_;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostWin, RootWindowHost implementation:
 
@@ -424,7 +391,6 @@
 }
 
 void DesktopRootWindowHostWin::ToggleFullScreen() {
-  SetWindowTransparency();
 }
 
 // GetBounds and SetBounds work in pixel coordinates, whereas other get/set
@@ -488,7 +454,7 @@
 
 bool DesktopRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
   aura::client::CursorClient* cursor_client =
-      aura::client::GetCursorClient(GetRootWindow());
+      aura::client::GetCursorClient(root_window_);
   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
     *location_return = gfx::Point(0, 0);
     return false;
@@ -711,8 +677,6 @@
   // TODO(beng): moar
   NOTIMPLEMENTED();
 
-  native_widget_delegate_->OnNativeWidgetCreated(true);
-
   // 1. Window property association
   // 2. MouseWheel.
 }
@@ -883,12 +847,6 @@
   return message_handler_->hwnd();
 }
 
-void DesktopRootWindowHostWin::SetWindowTransparency() {
-  bool transparent = ShouldUseNativeFrame() && !IsFullscreen();
-  root_window_->compositor()->SetHostHasTransparentBackground(transparent);
-  root_window_->SetTransparent(transparent);
-}
-
 bool DesktopRootWindowHostWin::IsModalWindowActive() const {
   // This function can get called during window creation which occurs before
   // root_window_ has been created.
@@ -912,11 +870,9 @@
 // static
 DesktopRootWindowHost* DesktopRootWindowHost::Create(
     internal::NativeWidgetDelegate* native_widget_delegate,
-    DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds) {
+    DesktopNativeWidgetAura* desktop_native_widget_aura) {
   return new DesktopRootWindowHostWin(native_widget_delegate,
-                                      desktop_native_widget_aura,
-                                      initial_bounds);
+                                      desktop_native_widget_aura);
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
index 9e3866a..6c02dda 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
@@ -13,19 +13,17 @@
 
 namespace aura {
 namespace client {
+class DragDropClient;
 class FocusClient;
-class ScreenPositionClient;
 }
 }
 
 namespace views {
 class DesktopCursorClient;
-class DesktopDispatcherClient;
 class DesktopDragDropClientWin;
 class HWNDMessageHandler;
 
 namespace corewm {
-class CursorManager;
 class TooltipWin;
 }
 
@@ -37,8 +35,7 @@
  public:
   DesktopRootWindowHostWin(
       internal::NativeWidgetDelegate* native_widget_delegate,
-      DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds);
+      DesktopNativeWidgetAura* desktop_native_widget_aura);
   virtual ~DesktopRootWindowHostWin();
 
   // A way of converting an HWND into a content window.
@@ -46,10 +43,14 @@
 
  protected:
   // Overridden from DesktopRootWindowHost:
-  virtual aura::RootWindow* Init(aura::Window* content_window,
-                                 const Widget::InitParams& params) OVERRIDE;
-  virtual void InitFocus(aura::Window* window) OVERRIDE;
+  virtual void Init(aura::Window* content_window,
+                    const Widget::InitParams& params,
+                    aura::RootWindow::CreateParams* rw_create_params) OVERRIDE;
+  virtual void OnRootWindowCreated(aura::RootWindow* root,
+                                   const Widget::InitParams& params) OVERRIDE;
   virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
+  virtual scoped_ptr<aura::client::DragDropClient>
+      CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
   virtual void Close() OVERRIDE;
   virtual void CloseNow() OVERRIDE;
   virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
@@ -99,6 +100,7 @@
   virtual void OnRootViewLayout() const OVERRIDE;
   virtual void OnNativeWidgetFocus() OVERRIDE;
   virtual void OnNativeWidgetBlur() OVERRIDE;
+  virtual bool IsAnimatingClosed() const OVERRIDE;
 
   // Overridden from aura::RootWindowHost:
   virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
@@ -213,8 +215,6 @@
   HWND GetHWND() const;
 
  private:
-  void SetWindowTransparency();
-
   // Returns true if a modal window is active in the current root window chain.
   bool IsModalWindowActive() const;
 
@@ -222,7 +222,6 @@
   aura::RootWindow* root_window_;
 
   scoped_ptr<HWNDMessageHandler> message_handler_;
-  scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
   scoped_ptr<aura::client::FocusClient> focus_client_;
 
   // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
@@ -234,14 +233,8 @@
   aura::RootWindowHostDelegate* root_window_host_delegate_;
   aura::Window* content_window_;
 
-  // In some cases, we set a screen position client on |root_window_|. If we
-  // do, we're responsible for the lifetime.
-  scoped_ptr<aura::client::ScreenPositionClient> position_client_;
-
-  // Controls visibility of the cursor.
-  scoped_ptr<views::corewm::CursorManager> cursor_client_;
-
-  scoped_ptr<DesktopDragDropClientWin> drag_drop_client_;
+  // Owned by DesktopNativeWidgetAura.
+  DesktopDragDropClientWin* drag_drop_client_;
 
   // When certain windows are being shown, we augment the window size
   // temporarily for animation. The following two members contain the top left
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
index c095379..180614e 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
@@ -15,7 +15,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "third_party/skia/include/core/SkPath.h"
-#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/user_action_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window_property.h"
@@ -30,19 +31,14 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/corewm/compound_event_filter.h"
 #include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/cursor_manager.h"
-#include "ui/views/corewm/focus_controller.h"
 #include "ui/views/corewm/tooltip_aura.h"
 #include "ui/views/ime/input_method.h"
 #include "ui/views/linux_ui/linux_ui.h"
-#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h"
 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
-#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
-#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
@@ -113,8 +109,7 @@
 
 DesktopRootWindowHostX11::DesktopRootWindowHostX11(
     internal::NativeWidgetDelegate* native_widget_delegate,
-    DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds)
+    DesktopNativeWidgetAura* desktop_native_widget_aura)
     : close_widget_factory_(this),
       xdisplay_(gfx::GetXDisplay()),
       xwindow_(0),
@@ -124,20 +119,20 @@
       focus_when_shown_(false),
       is_fullscreen_(false),
       is_always_on_top_(false),
+      root_window_(NULL),
+      drag_drop_client_(NULL),
       current_cursor_(ui::kCursorNull),
       native_widget_delegate_(native_widget_delegate),
-      desktop_native_widget_aura_(desktop_native_widget_aura) {
+      desktop_native_widget_aura_(desktop_native_widget_aura),
+      root_window_host_delegate_(NULL),
+      content_window_(NULL),
+      window_parent_(NULL) {
 }
 
 DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
   root_window_->ClearProperty(kHostForRootWindow);
-  aura::client::SetFocusClient(root_window_, NULL);
-  aura::client::SetActivationClient(root_window_, NULL);
-  aura::client::SetScreenPositionClient(root_window_, NULL);
-  aura::client::SetDispatcherClient(root_window_, NULL);
-  aura::client::SetCursorClient(root_window_, NULL);
-  aura::client::SetDragDropClient(root_window_, NULL);
   aura::client::SetWindowMoveClient(root_window_, NULL);
+  desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_);
 }
 
 // static
@@ -194,9 +189,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
 
-aura::RootWindow* DesktopRootWindowHostX11::Init(
+void DesktopRootWindowHostX11::Init(
     aura::Window* content_window,
-    const Widget::InitParams& params) {
+    const Widget::InitParams& params,
+    aura::RootWindow::CreateParams* rw_create_params) {
   content_window_ = content_window;
 
   // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
@@ -211,11 +207,39 @@
     sanitized_params.bounds.set_height(100);
 
   InitX11Window(sanitized_params);
-  return InitRootWindow(sanitized_params);
+
+  rw_create_params->initial_bounds = bounds_;
+  rw_create_params->host = this;
 }
 
-void DesktopRootWindowHostX11::InitFocus(aura::Window* window) {
-  focus_client_->FocusWindow(window);
+void DesktopRootWindowHostX11::OnRootWindowCreated(
+    aura::RootWindow* root,
+    const Widget::InitParams& params) {
+  root_window_ = root;
+
+  root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
+  root_window_->SetProperty(kHostForRootWindow, this);
+  root_window_host_delegate_ = root_window_;
+
+  // If we're given a parent, we need to mark ourselves as transient to another
+  // window. Otherwise activation gets screwy.
+  gfx::NativeView parent = params.parent;
+  if (!params.child && params.parent)
+    parent->AddTransientChild(content_window_);
+
+  // Ensure that the X11DesktopHandler exists so that it dispatches activation
+  // messages to us.
+  X11DesktopHandler::get();
+
+  // TODO(erg): Unify this code once the other consumer goes away.
+  x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_));
+  x11_window_event_filter_->SetUseHostWindowBorders(false);
+  desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
+      x11_window_event_filter_.get());
+
+  x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
+  aura::client::SetWindowMoveClient(root_window_,
+                                    x11_window_move_client_.get());
 }
 
 scoped_ptr<corewm::Tooltip> DesktopRootWindowHostX11::CreateTooltip() {
@@ -223,6 +247,14 @@
       new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
 }
 
+scoped_ptr<aura::client::DragDropClient>
+DesktopRootWindowHostX11::CreateDragDropClient(
+    DesktopNativeCursorManager* cursor_manager) {
+  drag_drop_client_ = new DesktopDragDropClientAuraX11(
+      root_window_, cursor_manager, xdisplay_, xwindow_);
+  return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
+}
+
 void DesktopRootWindowHostX11::Close() {
   // TODO(erg): Might need to do additional hiding tasks here.
 
@@ -244,6 +276,22 @@
 
   native_widget_delegate_->OnNativeWidgetDestroying();
 
+  // If we have children, close them. Use a copy for iteration because they'll
+  // remove themselves.
+  std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_;
+  for (std::set<DesktopRootWindowHostX11*>::iterator it =
+           window_children_copy.begin(); it != window_children_copy.end();
+       ++it) {
+    (*it)->CloseNow();
+  }
+  DCHECK(window_children_.empty());
+
+  // If we have a parent, remove ourselves from its children list.
+  if (window_parent_) {
+    window_parent_->window_children_.erase(this);
+    window_parent_ = NULL;
+  }
+
   // Remove the event listeners we've installed. We need to remove these
   // because otherwise we get assert during ~RootWindow().
   desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
@@ -594,6 +642,10 @@
     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
 }
 
+bool DesktopRootWindowHostX11::IsAnimatingClosed() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
 
@@ -938,77 +990,16 @@
     ui::SetWindowClassHint(
         xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
   }
-}
 
-aura::RootWindow* DesktopRootWindowHostX11::InitRootWindow(
-    const Widget::InitParams& params) {
-  aura::RootWindow::CreateParams rw_params(bounds_);
-  rw_params.host = this;
-  root_window_ = new aura::RootWindow(rw_params);
-  root_window_->Init();
-  root_window_->AddChild(content_window_);
-  root_window_->SetProperty(kViewsWindowForRootWindow, content_window_);
-  root_window_->SetProperty(kHostForRootWindow, this);
-  root_window_host_delegate_ = root_window_;
-
-  // If we're given a parent, we need to mark ourselves as transient to another
-  // window. Otherwise activation gets screwy.
-  gfx::NativeView parent = params.parent;
-  if (!params.child && params.parent)
-    parent->AddTransientChild(content_window_);
-
-  native_widget_delegate_->OnNativeWidgetCreated(true);
-
-  desktop_native_widget_aura_->InstallWindowModalityController(root_window_);
-  desktop_native_widget_aura_->CreateCaptureClient(root_window_);
-
-  // Ensure that the X11DesktopHandler exists so that it dispatches activation
-  // messages to us.
-  X11DesktopHandler::get();
-
-  corewm::FocusController* focus_controller =
-      new corewm::FocusController(new DesktopFocusRules(content_window_));
-  focus_client_.reset(focus_controller);
-  aura::client::SetFocusClient(root_window_, focus_controller);
-  aura::client::SetActivationClient(root_window_, focus_controller);
-  root_window_->AddPreTargetHandler(focus_controller);
-
-  dispatcher_client_.reset(new DesktopDispatcherClient);
-  aura::client::SetDispatcherClient(root_window_,
-                                    dispatcher_client_.get());
-
-  views::DesktopNativeCursorManager* desktop_native_cursor_manager =
-      new views::DesktopNativeCursorManager(
-          root_window_,
-          scoped_ptr<DesktopCursorLoaderUpdater>(
-              new DesktopCursorLoaderUpdaterAuraX11));
-  cursor_client_.reset(
-      new views::corewm::CursorManager(
-          scoped_ptr<corewm::NativeCursorManager>(
-              desktop_native_cursor_manager)));
-  aura::client::SetCursorClient(root_window_,
-                                cursor_client_.get());
-
-  position_client_.reset(new DesktopScreenPositionClient);
-  aura::client::SetScreenPositionClient(root_window_,
-                                        position_client_.get());
-
-  desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_);
-
-  drag_drop_client_.reset(new DesktopDragDropClientAuraX11(
-      root_window_, desktop_native_cursor_manager, xdisplay_, xwindow_));
-  aura::client::SetDragDropClient(root_window_, drag_drop_client_.get());
-
-  // TODO(erg): Unify this code once the other consumer goes away.
-  x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_));
-  x11_window_event_filter_->SetUseHostWindowBorders(false);
-  desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
-      x11_window_event_filter_.get());
-
-  x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
-  aura::client::SetWindowMoveClient(root_window_,
-                                    x11_window_move_client_.get());
-  return root_window_;
+  // If we have a parent, record the parent/child relationship. We use this
+  // data during destruction to make sure that when we try to close a parent
+  // window, we also destroy all child windows.
+  if (params.parent && params.parent->GetDispatcher()) {
+    XID parent_xid = params.parent->GetDispatcher()->GetAcceleratedWidget();
+    window_parent_ = GetHostForXID(parent_xid);
+    DCHECK(window_parent_);
+    window_parent_->window_children_.insert(this);
+  }
 }
 
 bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
@@ -1415,11 +1406,9 @@
 // static
 DesktopRootWindowHost* DesktopRootWindowHost::Create(
     internal::NativeWidgetDelegate* native_widget_delegate,
-    DesktopNativeWidgetAura* desktop_native_widget_aura,
-    const gfx::Rect& initial_bounds) {
+    DesktopNativeWidgetAura* desktop_native_widget_aura) {
   return new DesktopRootWindowHostX11(native_widget_delegate,
-                                      desktop_native_widget_aura,
-                                      initial_bounds);
+                                      desktop_native_widget_aura);
 }
 
 // static
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
index d2ae22f..19bc01c 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
@@ -13,7 +13,6 @@
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "ui/aura/client/cursor_client.h"
 #include "ui/aura/root_window_host.h"
 #include "ui/base/cursor/cursor_loader_x11.h"
 #include "ui/gfx/rect.h"
@@ -21,13 +20,6 @@
 #include "ui/views/views_export.h"
 #include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
 
-namespace aura {
-namespace client {
-class FocusClient;
-class ScreenPositionClient;
-}
-}
-
 namespace views {
 class DesktopDragDropClientAuraX11;
 class DesktopDispatcherClient;
@@ -35,10 +27,6 @@
 class X11DesktopWindowMoveClient;
 class X11WindowEventFilter;
 
-namespace corewm {
-class CursorManager;
-}
-
 class VIEWS_EXPORT DesktopRootWindowHostX11 :
     public DesktopRootWindowHost,
     public aura::RootWindowHost,
@@ -46,8 +34,7 @@
  public:
   DesktopRootWindowHostX11(
       internal::NativeWidgetDelegate* native_widget_delegate,
-      DesktopNativeWidgetAura* desktop_native_widget_aura,
-      const gfx::Rect& initial_bounds);
+      DesktopNativeWidgetAura* desktop_native_widget_aura);
   virtual ~DesktopRootWindowHostX11();
 
   // A way of converting an X11 |xid| host window into a |content_window_|.
@@ -75,10 +62,14 @@
 
  protected:
   // Overridden from DesktopRootWindowHost:
-  virtual aura::RootWindow* Init(aura::Window* content_window,
-                                 const Widget::InitParams& params) OVERRIDE;
-  virtual void InitFocus(aura::Window* window) OVERRIDE;
+  virtual void Init(aura::Window* content_window,
+                    const Widget::InitParams& params,
+                    aura::RootWindow::CreateParams* rw_create_params) OVERRIDE;
+  virtual void OnRootWindowCreated(aura::RootWindow* root,
+                                   const Widget::InitParams& params) OVERRIDE;
   virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
+  virtual scoped_ptr<aura::client::DragDropClient>
+      CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
   virtual void Close() OVERRIDE;
   virtual void CloseNow() OVERRIDE;
   virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
@@ -128,6 +119,7 @@
   virtual void OnRootViewLayout() const OVERRIDE;
   virtual void OnNativeWidgetFocus() OVERRIDE;
   virtual void OnNativeWidgetBlur() OVERRIDE;
+  virtual bool IsAnimatingClosed() const OVERRIDE;
 
   // Overridden from aura::RootWindowHost:
   virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
@@ -238,12 +230,9 @@
   // We are owned by the RootWindow, but we have to have a back pointer to it.
   aura::RootWindow* root_window_;
 
-  // aura:: objects that we own.
-  scoped_ptr<aura::client::FocusClient> focus_client_;
-  scoped_ptr<views::corewm::CursorManager> cursor_client_;
   scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
-  scoped_ptr<aura::client::ScreenPositionClient> position_client_;
-  scoped_ptr<DesktopDragDropClientAuraX11> drag_drop_client_;
+
+  DesktopDragDropClientAuraX11* drag_drop_client_;
 
   // Current Aura cursor.
   gfx::NativeCursor current_cursor_;
@@ -260,6 +249,11 @@
   aura::RootWindowHostDelegate* root_window_host_delegate_;
   aura::Window* content_window_;
 
+  // We can optionally have a parent which can order us to close, or own
+  // children who we're responsible for closing when we CloseNow().
+  DesktopRootWindowHostX11* window_parent_;
+  std::set<DesktopRootWindowHostX11*> window_children_;
+
   ObserverList<DesktopRootWindowHostObserverX11> observer_list_;
 
   // The current root window host that has capture. While X11 has something
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
index 2ca556c..1d21740 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -14,9 +14,9 @@
 
 namespace {
 
-gfx::Point GetOrigin(const aura::RootWindow* root_window) {
-  gfx::Point origin_in_pixels = root_window->GetHostOrigin();
-  aura::RootWindow* window = const_cast<aura::RootWindow*>(root_window);
+gfx::Point GetOrigin(const aura::Window* root_window) {
+  gfx::Point origin_in_pixels = root_window->GetDispatcher()->GetHostOrigin();
+  aura::Window* window = const_cast<aura::Window*>(root_window);
   float scale = gfx::Screen::GetScreenFor(window)->
        GetDisplayNearestWindow(window).device_scale_factor();
   return gfx::ToFlooredPoint(
@@ -44,7 +44,7 @@
 
 void DesktopScreenPositionClient::ConvertPointToScreen(
     const aura::Window* window, gfx::Point* point) {
-  const aura::RootWindow* root_window = window->GetRootWindow();
+  const aura::Window* root_window = window->GetRootWindow();
   aura::Window::ConvertPointToTarget(window, root_window, point);
   gfx::Point origin = GetOrigin(root_window);
   point->Offset(origin.x(), origin.y());
@@ -52,15 +52,16 @@
 
 void DesktopScreenPositionClient::ConvertPointFromScreen(
     const aura::Window* window, gfx::Point* point) {
-  const aura::RootWindow* root_window = window->GetRootWindow();
+  const aura::Window* root_window = window->GetRootWindow();
   gfx::Point origin = GetOrigin(root_window);
   point->Offset(-origin.x(), -origin.y());
   aura::Window::ConvertPointToTarget(root_window, window, point);
 }
 
 void DesktopScreenPositionClient::ConvertHostPointToScreen(
-    aura::RootWindow* window, gfx::Point* point) {
-  ConvertPointToScreen(window, point);
+    aura::Window* window, gfx::Point* point) {
+  aura::Window* root_window = window->GetRootWindow();
+  ConvertPointToScreen(root_window, point);
 }
 
 void DesktopScreenPositionClient::SetBounds(
@@ -68,7 +69,7 @@
     const gfx::Rect& bounds,
     const gfx::Display& display) {
   // TODO: Use the 3rd parameter, |display|.
-  aura::RootWindow* root = window->GetRootWindow();
+  aura::Window* root = window->GetRootWindow();
 
   if (PositionWindowInScreenCoordinates(window)) {
     // The caller expects windows we consider "embedded" to be placed in the
@@ -87,7 +88,7 @@
   DesktopNativeWidgetAura* desktop_native_widget =
       DesktopNativeWidgetAura::ForWindow(window);
   if (desktop_native_widget) {
-    root->SetHostBounds(bounds);
+    root->GetDispatcher()->SetHostBounds(bounds);
     // Setting bounds of root resizes |window|.
   } else {
     window->SetBounds(bounds);
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/ui/views/widget/desktop_aura/desktop_screen_position_client.h
index 479a1cc..da8ad40 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_position_client.h
+++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.h
@@ -23,7 +23,7 @@
                                     gfx::Point* point) OVERRIDE;
   virtual void ConvertPointFromScreen(const aura::Window* window,
                                       gfx::Point* point) OVERRIDE;
-  virtual void ConvertHostPointToScreen(aura::RootWindow* window,
+  virtual void ConvertHostPointToScreen(aura::Window* window,
                                         gfx::Point* point) OVERRIDE;
   virtual void SetBounds(aura::Window* window,
                          const gfx::Rect& bounds,
diff --git a/ui/views/widget/desktop_aura/desktop_screen_win.cc b/ui/views/widget/desktop_aura/desktop_screen_win.cc
index 93721bc..f1a7767 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -53,8 +53,8 @@
 }
 
 HWND DesktopScreenWin::GetHWNDFromNativeView(gfx::NativeView window) const {
-  aura::RootWindow* root_window = window->GetRootWindow();
-  return root_window ? root_window->GetAcceleratedWidget() : NULL;
+  aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
+  return dispatcher ? dispatcher->GetAcceleratedWidget() : NULL;
 }
 
 gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 9358875..c54378e 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -157,7 +157,7 @@
 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
     const gfx::Point& point) {
   std::vector<aura::Window*> windows =
-    DesktopRootWindowHostX11::GetAllOpenWindows();
+      DesktopRootWindowHostX11::GetAllOpenWindows();
 
   for (std::vector<aura::Window*>::const_iterator it = windows.begin();
        it != windows.end(); ++it) {
@@ -187,10 +187,10 @@
   // create the aura::RootWindow. So we ask what the DRWHX11 believes the
   // window bounds are instead of going through the aura::Window's screen
   // bounds.
-  aura::RootWindow* root_window = window->GetRootWindow();
-  if (root_window) {
+  aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
+  if (dispatcher) {
     DesktopRootWindowHostX11* rwh = DesktopRootWindowHostX11::GetHostForXID(
-        root_window->GetAcceleratedWidget());
+        dispatcher->GetAcceleratedWidget());
     if (rwh)
       return GetDisplayMatching(rwh->GetX11RootWindowBounds());
   }
diff --git a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
index 273372f..41573fe 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
+++ b/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
@@ -50,7 +50,7 @@
     const gfx::Vector2d& drag_offset,
     aura::client::WindowMoveSource move_source) {
   window_offset_ = drag_offset;
-  root_window_ = source->GetRootWindow();
+  root_window_ = source->GetDispatcher();
 
   bool success = move_loop_.RunMoveLoop(source, root_window_->last_cursor());
   return success ? aura::client::MOVE_SUCCESSFUL : aura::client::MOVE_CANCELED;
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 177d137..a88fdce 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -94,6 +94,11 @@
   if (!GrabPointerWithCursor(cursor))
     return false;
 
+  // We are handling a mouse drag outside of the aura::RootWindow system. We
+  // must manually make aura think that the mouse button is pressed so that we
+  // don't draw extraneous tooltips.
+  aura::Env::GetInstance()->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
+
   base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
   base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
   base::RunLoop run_loop(aura::Env::GetInstance()->GetDispatcher());
@@ -111,6 +116,9 @@
   if (!in_move_loop_)
     return;
 
+  // We undo our emulated mouse click from RunMoveLoop();
+  aura::Env::GetInstance()->set_mouse_button_flags(0);
+
   // TODO(erg): Is this ungrab the cause of having to click to give input focus
   // on drawn out windows? Not ungrabbing here screws the X server until I kill
   // the chrome process.
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index cfba08a..92f4b99 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -13,8 +13,8 @@
 #include "ui/aura/client/drag_drop_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/stacking_client.h"
 #include "ui/aura/client/window_move_client.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/client/window_types.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
@@ -152,8 +152,8 @@
   if (parent) {
     parent->AddChild(window_);
   } else {
-    window_->SetDefaultParentByRootWindow(context->GetRootWindow(),
-                                          window_bounds);
+    aura::client::ParentWindowWithContext(
+        window_, context->GetRootWindow(), window_bounds);
   }
 
   // Wait to set the bounds until we have a parent. That way we can know our
@@ -169,7 +169,7 @@
       params.type != Widget::InitParams::TYPE_TOOLTIP;
   DCHECK(GetWidget()->GetRootView());
   if (params.type != Widget::InitParams::TYPE_TOOLTIP)
-    tooltip_manager_.reset(new views::TooltipManagerAura(window_, GetWidget()));
+    tooltip_manager_.reset(new views::TooltipManagerAura(GetWidget()));
 
   drop_helper_.reset(new DropHelper(GetWidget()->GetRootView()));
   if (params.type != Widget::InitParams::TYPE_TOOLTIP &&
@@ -276,7 +276,7 @@
 InputMethod* NativeWidgetAura::CreateInputMethod() {
   if (!window_)
     return NULL;
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = window_->GetRootWindow();
   ui::InputMethod* host =
       root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
   return new InputMethodBridge(this, host, true);
@@ -391,7 +391,7 @@
   if (!window_)
     return;
 
-  aura::RootWindow* root = window_->GetRootWindow();
+  aura::Window* root = window_->GetRootWindow();
   if (root) {
     aura::client::ScreenPositionClient* screen_position_client =
         aura::client::GetScreenPositionClient(root);
@@ -523,7 +523,7 @@
 
   // We may up here during destruction of the root, in which case
   // GetRootWindow() returns NULL (~RootWindow() has run and we're in ~Window).
-  aura::RootWindow* root = window_->GetRootWindow();
+  aura::Window* root = window_->GetRootWindow();
   return root &&
       aura::client::GetActivationClient(root)->GetActiveWindow() == window_;
 }
@@ -834,6 +834,7 @@
 
   if (tooltip_manager_.get())
     tooltip_manager_->UpdateTooltip();
+  TooltipManagerAura::UpdateTooltipManagerForCapture(GetWidget());
   delegate_->OnMouseEvent(event);
 }
 
@@ -1109,7 +1110,7 @@
   } else {
     // The following looks weird, but it's the equivalent of what aura has
     // always done. (The previous behaviour of aura::Window::SetParent() used
-    // NULL as a special value that meant ask the StackingClient where things
+    // NULL as a special value that meant ask the WindowTreeClient where things
     // should go.)
     //
     // This probably isn't strictly correct, but its an invariant that a Window
@@ -1118,9 +1119,9 @@
     // in this case is the stacking client of the current RootWindow. This
     // matches our previous behaviour; the global stacking client would almost
     // always reattach the window to the same RootWindow.
-    aura::RootWindow* root_window = native_view->GetRootWindow();
-    native_view->SetDefaultParentByRootWindow(
-        root_window, root_window->GetBoundsInScreen());
+    aura::Window* root_window = native_view->GetRootWindow();
+    aura::client::ParentWindowWithContext(
+        native_view, root_window, root_window->GetBoundsInScreen());
   }
 
   // And now, notify them that they have a brand new parent.
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index 1185c75..95f94dc 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -120,8 +120,16 @@
   // keyboard.
   if (v && v->enabled() && ((event->key_code() == ui::VKEY_APPS) ||
      (event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) {
-    v->ShowContextMenu(v->GetKeyboardContextMenuLocation(),
-                       ui::MENU_SOURCE_KEYBOARD);
+    // Showing the context menu outside the visible bounds may result in a
+    // context menu appearing over a completely different window. Constrain
+    // location to visible bounds so this doesn't happen.
+    gfx::Rect visible_bounds(v->ConvertRectToWidget(v->GetVisibleBounds()));
+    visible_bounds.Offset(
+        widget_->GetClientAreaBoundsInScreen().OffsetFromOrigin());
+    gfx::Rect keyboard_loc(v->GetKeyboardContextMenuLocation(),
+                           gfx::Size(1, 1));
+    keyboard_loc.AdjustToFit(visible_bounds);
+    v->ShowContextMenu(keyboard_loc.origin(), ui::MENU_SOURCE_KEYBOARD);
     event->StopPropagation();
     return;
   }
@@ -631,6 +639,7 @@
     // When the root view is being hidden (e.g. when widget is minimized)
     // handlers are reset, so that after it is reshown, events are not captured
     // by old handlers.
+    explicit_mouse_handler_ = false;
     mouse_pressed_handler_ = NULL;
     mouse_move_handler_ = NULL;
     touch_pressed_handler_ = NULL;
diff --git a/ui/views/widget/tooltip_manager.cc b/ui/views/widget/tooltip_manager.cc
index 1c461ac..f1a85fe 100644
--- a/ui/views/widget/tooltip_manager.cc
+++ b/ui/views/widget/tooltip_manager.cc
@@ -13,6 +13,9 @@
 const size_t kMaxTooltipLength = 1024;
 
 // static
+const char TooltipManager::kGroupingPropertyKey[] = "GroupingPropertyKey";
+
+// static
 int TooltipManager::GetMaxWidth(int x, int y, gfx::NativeView context) {
   return GetMaxWidth(gfx::Screen::GetScreenFor(context)->GetDisplayNearestPoint(
                          gfx::Point(x, y)));
diff --git a/ui/views/widget/tooltip_manager.h b/ui/views/widget/tooltip_manager.h
index 2119223..923b19d 100644
--- a/ui/views/widget/tooltip_manager.h
+++ b/ui/views/widget/tooltip_manager.h
@@ -26,6 +26,15 @@
 // the various tooltip methods on View.
 class VIEWS_EXPORT TooltipManager {
  public:
+  // When a NativeView has capture all events are delivered to it. In some
+  // situations, such as menus, we want the tooltip to be shown for the
+  // NativeView the mouse is over, even if it differs from the NativeView that
+  // has capture (with menus the first menu shown has capture). To enable this
+  // if the NativeView that has capture has the same value for the property
+  // |kGroupingPropertyKey| as the NativeView the mouse is over the tooltip is
+  // shown.
+  static const char kGroupingPropertyKey[];
+
   TooltipManager() {}
   virtual ~TooltipManager() {}
 
diff --git a/ui/views/widget/tooltip_manager_aura.cc b/ui/views/widget/tooltip_manager_aura.cc
index dc812b8..1735979 100644
--- a/ui/views/widget/tooltip_manager_aura.cc
+++ b/ui/views/widget/tooltip_manager_aura.cc
@@ -5,6 +5,7 @@
 #include "ui/views/widget/tooltip_manager_aura.h"
 
 #include "base/logging.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/client/tooltip_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -24,14 +25,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 // TooltipManagerAura public:
 
-TooltipManagerAura::TooltipManagerAura(aura::Window* window, Widget* widget)
-    : window_(window),
-      widget_(widget) {
-  aura::client::SetTooltipText(window_, &tooltip_text_);
+TooltipManagerAura::TooltipManagerAura(Widget* widget) : widget_(widget) {
+  aura::client::SetTooltipText(GetWindow(), &tooltip_text_);
 }
 
 TooltipManagerAura::~TooltipManagerAura() {
-  aura::client::SetTooltipText(window_, NULL);
+  aura::client::SetTooltipText(GetWindow(), NULL);
 }
 
 // static
@@ -40,6 +39,47 @@
       ui::ResourceBundle::BaseFont);
 }
 
+// static
+void TooltipManagerAura::UpdateTooltipManagerForCapture(Widget* source) {
+  if (!source->HasCapture())
+    return;
+
+  aura::Window* root_window = source->GetNativeView()->GetRootWindow();
+  if (!root_window)
+    return;
+
+  gfx::Point screen_loc(
+      root_window->GetDispatcher()->GetLastMouseLocationInRoot());
+  aura::client::ScreenPositionClient* screen_position_client =
+      aura::client::GetScreenPositionClient(root_window);
+  if (!screen_position_client)
+    return;
+  screen_position_client->ConvertPointToScreen(root_window, &screen_loc);
+  gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window);
+  aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc);
+  if (!target)
+    return;
+  gfx::Point target_loc(screen_loc);
+  screen_position_client =
+      aura::client::GetScreenPositionClient(target->GetRootWindow());
+  if (!screen_position_client)
+    return;
+  screen_position_client->ConvertPointFromScreen(target, &target_loc);
+  target = target->GetEventHandlerForPoint(target_loc);
+  while (target) {
+    Widget* target_widget = Widget::GetWidgetForNativeView(target);
+    if (target_widget == source)
+      return;
+
+    if (target_widget) {
+      if (target_widget->GetTooltipManager())
+        target_widget->GetTooltipManager()->UpdateTooltip();
+      return;
+    }
+    target = target->parent();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TooltipManagerAura, TooltipManager implementation:
 
@@ -48,20 +88,22 @@
 }
 
 void TooltipManagerAura::UpdateTooltip() {
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = GetWindow()->GetRootWindow();
   if (aura::client::GetTooltipClient(root_window)) {
-    gfx::Point view_point = root_window->GetLastMouseLocationInRoot();
-    aura::Window::ConvertPointToTarget(root_window, window_, &view_point);
+    gfx::Point view_point =
+        root_window->GetDispatcher()->GetLastMouseLocationInRoot();
+    aura::Window::ConvertPointToTarget(root_window, GetWindow(), &view_point);
     View* view = GetViewUnderPoint(view_point);
     UpdateTooltipForTarget(view, view_point, root_window);
   }
 }
 
 void TooltipManagerAura::TooltipTextChanged(View* view)  {
-  aura::RootWindow* root_window = window_->GetRootWindow();
+  aura::Window* root_window = GetWindow()->GetRootWindow();
   if (aura::client::GetTooltipClient(root_window)) {
-    gfx::Point view_point = root_window->GetLastMouseLocationInRoot();
-    aura::Window::ConvertPointToTarget(root_window, window_, &view_point);
+    gfx::Point view_point =
+        root_window->GetDispatcher()->GetLastMouseLocationInRoot();
+    aura::Window::ConvertPointToTarget(root_window, GetWindow(), &view_point);
     View* target = GetViewUnderPoint(view_point);
     if (target != view)
       return;
@@ -78,7 +120,7 @@
 
 void TooltipManagerAura::UpdateTooltipForTarget(View* target,
                                                 const gfx::Point& point,
-                                                aura::RootWindow* root_window) {
+                                                aura::Window* root_window) {
   if (target) {
     gfx::Point view_point = point;
     View::ConvertPointFromWidget(target, &view_point);
@@ -90,7 +132,11 @@
   } else {
     tooltip_text_.clear();
   }
-  aura::client::GetTooltipClient(root_window)->UpdateTooltip(window_);
+  aura::client::GetTooltipClient(root_window)->UpdateTooltip(GetWindow());
+}
+
+aura::Window* TooltipManagerAura::GetWindow() {
+  return widget_->GetNativeView();
 }
 
 }  // namespace views.
diff --git a/ui/views/widget/tooltip_manager_aura.h b/ui/views/widget/tooltip_manager_aura.h
index 009d7e6..ed69c6d 100644
--- a/ui/views/widget/tooltip_manager_aura.h
+++ b/ui/views/widget/tooltip_manager_aura.h
@@ -11,7 +11,6 @@
 #include "ui/views/widget/tooltip_manager.h"
 
 namespace aura {
-class RootWindow;
 class Window;
 }
 
@@ -26,9 +25,15 @@
 // TooltipManager implementation for Aura.
 class TooltipManagerAura : public TooltipManager {
  public:
-  TooltipManagerAura(aura::Window* window, Widget* widget);
+  explicit TooltipManagerAura(Widget* widget);
   virtual ~TooltipManagerAura();
 
+  // If |source| has capture this finds the Widget under the mouse and invokes
+  // UpdateTooltip() on it's TooltipManager. This is necessary as when capture
+  // is held mouse events are only delivered to the Window that has capture even
+  // though we may show tooltips for the Window under the mouse.
+  static void UpdateTooltipManagerForCapture(Widget* source);
+
   // Returns the FontList used by all TooltipManagerAuras.
   static const gfx::FontList& GetDefaultFontList();
 
@@ -41,9 +46,11 @@
   View* GetViewUnderPoint(const gfx::Point& point);
   void UpdateTooltipForTarget(View* target,
                               const gfx::Point& point,
-                              aura::RootWindow* root_window);
+                              aura::Window* root_window);
 
-  aura::Window* window_;
+  // Returns the Window the tooltip text is installed on.
+  aura::Window* GetWindow();
+
   Widget* widget_;
   string16 tooltip_text_;
 
diff --git a/ui/views/widget/widget_hwnd_utils.cc b/ui/views/widget/widget_hwnd_utils.cc
index 53588c2..4e39af1 100644
--- a/ui/views/widget/widget_hwnd_utils.cc
+++ b/ui/views/widget/widget_hwnd_utils.cc
@@ -65,6 +65,8 @@
 #if defined(USE_AURA)
     if (ui::win::IsAeroGlassEnabled())
       *ex_style |= WS_EX_COMPOSITED;
+    else
+      *ex_style |= WS_EX_LAYERED;
 #else
     *ex_style |= WS_EX_LAYERED;
 #endif
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index f7cc483..f08fe8b 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -171,7 +171,7 @@
   widget1.Init(init_params);
   widget1.SetContentsView(contents_view1);
   widget1.Show();
-  aura::RootWindow* root_window1= widget1.GetNativeView()->GetRootWindow();
+  aura::Window* root_window1= widget1.GetNativeView()->GetRootWindow();
   contents_view1->RequestFocus();
 
   EXPECT_TRUE(root_window1 != NULL);
@@ -191,9 +191,9 @@
   widget2.Init(init_params2);
   widget2.SetContentsView(contents_view2);
   widget2.Show();
-  aura::RootWindow* root_window2 = widget2.GetNativeView()->GetRootWindow();
+  aura::Window* root_window2 = widget2.GetNativeView()->GetRootWindow();
   contents_view2->RequestFocus();
-  ::SetActiveWindow(root_window2->GetAcceleratedWidget());
+  ::SetActiveWindow(root_window2->GetDispatcher()->GetAcceleratedWidget());
 
   aura::client::ActivationClient* activation_client2 =
       aura::client::GetActivationClient(root_window2);
@@ -205,7 +205,7 @@
   // Now set focus back to widget 1 and expect the active window to be its
   // window.
   contents_view1->RequestFocus();
-  ::SetActiveWindow(root_window1->GetAcceleratedWidget());
+  ::SetActiveWindow(root_window1->GetDispatcher()->GetAcceleratedWidget());
   EXPECT_EQ(activation_client2->GetActiveWindow(),
             reinterpret_cast<aura::Window*>(NULL));
   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
@@ -693,9 +693,18 @@
 
 }  // namespace
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+// TODO(erg): linux_aura bringup: http://crbug.com/163931
+#define MAYBE_MouseEventDispatchedToRightWindow \
+  DISABLED_MouseEventDispatchedToRightWindow
+#else
+#define MAYBE_MouseEventDispatchedToRightWindow \
+  MouseEventDispatchedToRightWindow
+#endif
+
 // Verifies if a mouse event is received on a widget that doesn't have capture
 // it is correctly processed by the widget that doesn't have capture.
-TEST_F(WidgetCaptureTest, MouseEventDispatchedToRightWindow) {
+TEST_F(WidgetCaptureTest, MAYBE_MouseEventDispatchedToRightWindow) {
   MouseEventTrackingWidget widget1;
   Widget::InitParams params1 =
       CreateParams(views::Widget::InitParams::TYPE_WINDOW);
@@ -723,9 +732,8 @@
   // |widget2| has capture, |widget1| should still get the event.
   ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
                              ui::EF_NONE);
-  static_cast<aura::RootWindowHostDelegate*>(
-      widget1.GetNativeWindow()->GetRootWindow())->OnHostMouseEvent(
-          &mouse_event);
+  widget1.GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate()->
+      OnHostMouseEvent(&mouse_event);
   EXPECT_TRUE(widget1.GetAndClearGotMouseEvent());
   EXPECT_FALSE(widget2.GetAndClearGotMouseEvent());
 }
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index bb6c00f..67887b1 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -27,6 +27,7 @@
 
 #if defined(USE_AURA)
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/window.h"
@@ -1142,8 +1143,10 @@
       owned_window_->SetType(aura::client::WINDOW_TYPE_MENU);
     }
     owned_window_->Init(ui::LAYER_TEXTURED);
-    owned_window_->SetDefaultParentByRootWindow(
-        widget_.GetNativeView()->GetRootWindow(), gfx::Rect(0, 0, 1900, 1600));
+    aura::client::ParentWindowWithContext(
+        owned_window_,
+        widget_.GetNativeView()->GetRootWindow(),
+        gfx::Rect(0, 0, 1900, 1600));
     owned_window_->Show();
     owned_window_->AddObserver(this);
 
@@ -1307,7 +1310,7 @@
   ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
                             screen_bounds.CenterPoint(), 0);
   aura::RootWindowHostDelegate* rwhd =
-      widget->GetNativeWindow()->GetRootWindow()->AsRootWindowHostDelegate();
+      widget->GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate();
   rwhd->OnHostMouseEvent(&move_event);
   if (last_event_type == ui::ET_MOUSE_ENTERED)
     return;
@@ -1955,9 +1958,6 @@
   RunDestroyChildWidgetsTest(true, false);
 }
 
-// TODO: test fails on linux as destroying parent X widget does not
-// automatically destroy transients. http://crbug.com/300020 .
-#if !defined(OS_LINUX)
 // See description of RunDestroyChildWidgetsTest(). Both parent and child use
 // DesktopNativeWidgetAura.
 TEST_F(WidgetChildDestructionTest,
@@ -1965,7 +1965,6 @@
   RunDestroyChildWidgetsTest(true, true);
 }
 #endif
-#endif
 
 // See description of RunDestroyChildWidgetsTest().
 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
@@ -2014,7 +2013,7 @@
                            cursor_location_main,
                            cursor_location_main,
                            ui::EF_NONE);
-  top_level_widget.GetNativeView()->GetRootWindow()->
+  top_level_widget.GetNativeView()->GetDispatcher()->
       AsRootWindowHostDelegate()->OnHostMouseEvent(&move_main);
 
   EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
@@ -2040,7 +2039,7 @@
                                    cursor_location_dialog,
                                    cursor_location_dialog,
                                    ui::EF_NONE);
-  top_level_widget.GetNativeView()->GetRootWindow()->
+  top_level_widget.GetNativeView()->GetDispatcher()->
       AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_dialog);
   EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
 
@@ -2051,7 +2050,7 @@
                                  cursor_location_main2,
                                  cursor_location_main2,
                                  ui::EF_NONE);
-  top_level_widget.GetNativeView()->GetRootWindow()->
+  top_level_widget.GetNativeView()->GetDispatcher()->
       AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_main);
   EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
 
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index cdd3af3..8f24378 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -886,13 +886,13 @@
   // Otherwise we handle everything else.
   // NOTE: We inline ProcessWindowMessage() as 'this' may be destroyed during
   // dispatch and ProcessWindowMessage() doesn't deal with that well.
-  const BOOL old_msg_handled = m_bMsgHandled;
+  const BOOL old_msg_handled = msg_handled_;
   base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
   const BOOL processed =
       _ProcessWindowMessage(window, message, w_param, l_param, result, 0);
   if (!ref)
     return 0;
-  m_bMsgHandled = old_msg_handled;
+  msg_handled_ = old_msg_handled;
 
   if (!processed)
     result = DefWindowProc(window, message, w_param, l_param);
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index 510dfe1..5ab443a 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -52,6 +52,53 @@
 const int WM_NCUAHDRAWCAPTION = 0xAE;
 const int WM_NCUAHDRAWFRAME = 0xAF;
 
+// IsMsgHandled() and BEGIN_SAFE_MSG_MAP_EX are a modified version of
+// BEGIN_MSG_MAP_EX. The main difference is it adds a WeakPtrFactory member
+// (|weak_factory_|) that is used in _ProcessWindowMessage() and changing
+// IsMsgHandled() from a member function to a define that checks if the weak
+// factory is still valid in addition to the member. Together these allow for
+// |this| to be deleted during dispatch.
+#define IsMsgHandled() !ref.get() || msg_handled_
+
+#define BEGIN_SAFE_MSG_MAP_EX(the_class) \
+ private: \
+  base::WeakPtrFactory<the_class> weak_factory_; \
+  BOOL msg_handled_; \
+\
+ public: \
+  /* "handled" management for cracked handlers */ \
+  void SetMsgHandled(BOOL handled) { \
+    msg_handled_ = handled; \
+  } \
+  BOOL ProcessWindowMessage(HWND hwnd, \
+                            UINT msg, \
+                            WPARAM w_param, \
+                            LPARAM l_param, \
+                            LRESULT& l_result, \
+                            DWORD msg_map_id = 0) { \
+    BOOL old_msg_handled = msg_handled_; \
+    BOOL ret = _ProcessWindowMessage(hwnd, msg, w_param, l_param, l_result, \
+                                     msg_map_id); \
+    msg_handled_ = old_msg_handled; \
+    return ret; \
+  } \
+  BOOL _ProcessWindowMessage(HWND hWnd, \
+                             UINT uMsg, \
+                             WPARAM wParam, \
+                             LPARAM lParam, \
+                             LRESULT& lResult, \
+                             DWORD dwMsgMapID) { \
+    base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); \
+    BOOL bHandled = TRUE; \
+    hWnd; \
+    uMsg; \
+    wParam; \
+    lParam; \
+    lResult; \
+    bHandled; \
+    switch(dwMsgMapID) { \
+      case 0:
+
 // An object that handles messages for a HWND that implements the views
 // "Custom Frame" look. The purpose of this class is to isolate the windows-
 // specific message handling from the code that wraps it. It is intended to be
@@ -235,7 +282,7 @@
 
   // Message Handlers ----------------------------------------------------------
 
-  BEGIN_MSG_MAP_EX(HWNDMessageHandler)
+  BEGIN_SAFE_MSG_MAP_EX(HWNDMessageHandler)
     // Range handlers must go first!
     MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
     MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
@@ -378,8 +425,6 @@
 
   scoped_ptr<FullscreenHandler> fullscreen_handler_;
 
-  base::WeakPtrFactory<HWNDMessageHandler> weak_factory_;
-
   // Set to true in Close() and false is CloseNow().
   bool waiting_for_close_now_;
 
diff --git a/ui/views/win/hwnd_util_aurawin.cc b/ui/views/win/hwnd_util_aurawin.cc
index 6062478..a927df1 100644
--- a/ui/views/win/hwnd_util_aurawin.cc
+++ b/ui/views/win/hwnd_util_aurawin.cc
@@ -19,21 +19,21 @@
 
 HWND HWNDForNativeView(const gfx::NativeView view) {
   return view && view->GetRootWindow() ?
-      view->GetRootWindow()->GetAcceleratedWidget() : NULL;
+      view->GetDispatcher()->GetAcceleratedWidget() : NULL;
 }
 
 HWND HWNDForNativeWindow(const gfx::NativeWindow window) {
   return window && window->GetRootWindow() ?
-      window->GetRootWindow()->GetAcceleratedWidget() : NULL;
+      window->GetDispatcher()->GetAcceleratedWidget() : NULL;
 }
 
 gfx::Rect GetWindowBoundsForClientBounds(View* view,
                                          const gfx::Rect& client_bounds) {
   DCHECK(view);
-  aura::RootWindow* window =
-      view->GetWidget()->GetNativeWindow()->GetRootWindow();
-  if (window) {
-    HWND hwnd = window->GetAcceleratedWidget();
+  aura::WindowEventDispatcher* dispatcher =
+      view->GetWidget()->GetNativeWindow()->GetDispatcher();
+  if (dispatcher) {
+    HWND hwnd = dispatcher->GetAcceleratedWidget();
     RECT rect = client_bounds.ToRECT();
     DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
     DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
diff --git a/ui/web_dialogs/test/test_web_dialog_observer.cc b/ui/web_dialogs/test/test_web_dialog_observer.cc
deleted file mode 100644
index 5cd7b53..0000000
--- a/ui/web_dialogs/test/test_web_dialog_observer.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/web_dialogs/test/test_web_dialog_observer.h"
-
-#include "base/logging.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/test/js_injection_ready_observer.h"
-#include "content/public/test/test_utils.h"
-
-using content::NavigationController;
-
-namespace ui {
-namespace test {
-
-TestWebDialogObserver::TestWebDialogObserver(
-    content::JsInjectionReadyObserver* js_injection_ready_observer)
-    : js_injection_ready_observer_(js_injection_ready_observer),
-      web_ui_(NULL),
-      done_(false),
-      running_(false) {
-}
-
-TestWebDialogObserver::~TestWebDialogObserver() {
-}
-
-void TestWebDialogObserver::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-      break;
-    case content::NOTIFICATION_LOAD_STOP:
-      DCHECK(web_ui_);
-      registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
-                        content::Source<NavigationController>(
-                            &web_ui_->GetWebContents()->GetController()));
-      done_ = true;
-      // If the message loop is running stop it.
-      if (running_) {
-        running_ = false;
-        message_loop_runner_->Quit();
-      }
-      break;
-    default:
-      NOTREACHED();
-  };
-}
-
-void TestWebDialogObserver::OnDialogShown(
-      content::WebUI* webui,
-      content::RenderViewHost* render_view_host) {
-  if (js_injection_ready_observer_) {
-    js_injection_ready_observer_->OnJsInjectionReady(render_view_host);
-  }
-  web_ui_ = webui;
-  // Wait for navigation on the new WebUI instance to complete. This depends
-  // on receiving the notification of the WebDialog being shown before the
-  // NavigationController finishes loading. The WebDialog notification is
-  // issued from web_dialog_ui.cc on RenderView creation which results from
-  // the call to render_manager_.Navigate in the method
-  // WebContents::NavigateToEntry. The new RenderView is later told to
-  // navigate in this method, ensuring that this is not a race condition.
-  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
-                 content::Source<NavigationController>(
-                     &web_ui_->GetWebContents()->GetController()));
-}
-
-content::WebUI* TestWebDialogObserver::GetWebUI() {
-  if (!done_) {
-    DCHECK(running_ == false);
-    running_ = true;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-  }
-  return web_ui_;
-}
-
-}  // namespace test
-}  // namespace ui
diff --git a/ui/web_dialogs/test/test_web_dialog_observer.h b/ui/web_dialogs/test/test_web_dialog_observer.h
deleted file mode 100644
index 4cef970..0000000
--- a/ui/web_dialogs/test/test_web_dialog_observer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012 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_WEB_DIALOGS_TEST_TEST_WEB_DIALOG_OBSERVER_H_
-#define UI_WEB_DIALOGS_TEST_TEST_WEB_DIALOG_OBSERVER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/web_dialogs/web_dialog_observer.h"
-
-
-namespace content {
-class JsInjectionReadyObserver;
-class MessageLoopRunner;
-class RenderViewHost;
-class WebUI;
-}
-
-namespace ui {
-namespace test {
-
-// For browser_tests, which run on the UI thread, run a second message
-// MessageLoop to detect WebDialog creation and quit when the constructed
-// WebUI instance is captured and ready.
-class TestWebDialogObserver : public content::NotificationObserver,
-                              public WebDialogObserver {
- public:
-  // Create and register a new TestWebDialogObserver. If
-  // |js_injection_ready_observer| is non-NULL, notify it as soon as the RVH is
-  // available.
-  explicit TestWebDialogObserver(
-      content::JsInjectionReadyObserver* js_injection_ready_observer);
-  virtual ~TestWebDialogObserver();
-
-  // Overridden from WebDialogObserver:
-  virtual void OnDialogShown(
-      content::WebUI* webui,
-      content::RenderViewHost* render_view_host) OVERRIDE;
-
-  // Waits for an WebDialog to be created. The WebUI instance is captured
-  // and the method returns it when the navigation on the dialog is complete.
-  content::WebUI* GetWebUI();
-
- private:
-  // content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  content::NotificationRegistrar registrar_;
-
-  // Observer to take some action when the dialog is ready for JavaScript
-  // injection.
-  content::JsInjectionReadyObserver* js_injection_ready_observer_;
-  content::WebUI* web_ui_;
-  bool done_;
-  bool running_;
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWebDialogObserver);
-};
-
-}  // namespace test
-}  // namespace ui
-
-#endif  // UI_WEB_DIALOGS_TEST_TEST_WEB_DIALOG_OBSERVER_H_
diff --git a/ui/web_dialogs/web_dialog_observer.h b/ui/web_dialogs/web_dialog_observer.h
deleted file mode 100644
index 57995ee..0000000
--- a/ui/web_dialogs/web_dialog_observer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 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_WEB_DIALOGS_WEB_DIALOG_OBSERVER_H_
-#define UI_WEB_DIALOGS_WEB_DIALOG_OBSERVER_H_
-
-namespace content {
-class RenderViewHost;
-class WebUI;
-}
-
-namespace ui {
-
-// Implement this class to receive notifications.
-class WebDialogObserver {
- public:
-  // Invoked when a web dialog has been shown.
-  // |webui| is the WebUI with which the dialog is associated.
-  // |render_view_host| is the RenderViewHost for the shown dialog.
-  virtual void OnDialogShown(content::WebUI* webui,
-                             content::RenderViewHost* render_view_host) = 0;
-
- protected:
-  virtual ~WebDialogObserver() {}
-};
-
-}  // namespace ui
-
-#endif  // UI_WEB_DIALOGS_WEB_DIALOG_OBSERVER_H_
diff --git a/ui/web_dialogs/web_dialogs.gyp b/ui/web_dialogs/web_dialogs.gyp
index 35cc67b..cd7530d 100644
--- a/ui/web_dialogs/web_dialogs.gyp
+++ b/ui/web_dialogs/web_dialogs.gyp
@@ -23,7 +23,6 @@
         # All .cc, .h under web_dialogs, except unittests.
         'web_dialog_delegate.cc',
         'web_dialog_delegate.h',
-        'web_dialog_observer.h',
         'web_dialog_ui.cc',
         'web_dialog_ui.h',
         'web_dialog_web_contents_delegate.cc',
@@ -45,8 +44,6 @@
         'test/test_web_contents_handler.h',
         'test/test_web_dialog_delegate.cc',
         'test/test_web_dialog_delegate.h',
-        'test/test_web_dialog_observer.cc',
-        'test/test_web_dialog_observer.h',
       ],
     },
   ],
diff --git a/ui/webui/resources/js/cr/ui/context_menu_handler.js b/ui/webui/resources/js/cr/ui/context_menu_handler.js
index 7dc16aa..1a23019 100644
--- a/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -45,7 +45,7 @@
       menu.hidden = false;
       menu.contextElement = e.currentTarget;
 
-      // when the menu is shown we steal all keyboard events.
+      // When the menu is shown we steal a lot of events.
       var doc = menu.ownerDocument;
       var win = doc.defaultView;
       this.showingEvents_.add(doc, 'keydown', this, true);
diff --git a/ui/webui/resources/js/cr/ui/list_selection_model.js b/ui/webui/resources/js/cr/ui/list_selection_model.js
index db8e8be..81f66b1 100644
--- a/ui/webui/resources/js/cr/ui/list_selection_model.js
+++ b/ui/webui/resources/js/cr/ui/list_selection_model.js
@@ -304,7 +304,6 @@
       if (!this.changeCount_ && !this.independentLeadItem_ &&
           !this.getIndexSelected(index)) {
         var index2 = this.getNearestSelectedIndex_(index);
-        console.log(index + ' -> ' + index2);
         index = index2;
       }
       return index;
diff --git a/ui/window_open_disposition_java.target.darwin-arm.mk b/ui/window_open_disposition_java.target.darwin-arm.mk
index 4ef6bc8..d1defb4 100644
--- a/ui/window_open_disposition_java.target.darwin-arm.mk
+++ b/ui/window_open_disposition_java.target.darwin-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/window_open_disposition_java.target.darwin-mips.mk b/ui/window_open_disposition_java.target.darwin-mips.mk
index 8ce084d..ec3d683 100644
--- a/ui/window_open_disposition_java.target.darwin-mips.mk
+++ b/ui/window_open_disposition_java.target.darwin-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/window_open_disposition_java.target.darwin-x86.mk b/ui/window_open_disposition_java.target.darwin-x86.mk
index d0e5e95e..f3914fa 100644
--- a/ui/window_open_disposition_java.target.darwin-x86.mk
+++ b/ui/window_open_disposition_java.target.darwin-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/window_open_disposition_java.target.linux-arm.mk b/ui/window_open_disposition_java.target.linux-arm.mk
index 4ef6bc8..d1defb4 100644
--- a/ui/window_open_disposition_java.target.linux-arm.mk
+++ b/ui/window_open_disposition_java.target.linux-arm.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -157,13 +157,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/window_open_disposition_java.target.linux-mips.mk b/ui/window_open_disposition_java.target.linux-mips.mk
index 8ce084d..ec3d683 100644
--- a/ui/window_open_disposition_java.target.linux-mips.mk
+++ b/ui/window_open_disposition_java.target.linux-mips.mk
@@ -78,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -155,13 +155,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/ui/window_open_disposition_java.target.linux-x86.mk b/ui/window_open_disposition_java.target.linux-x86.mk
index d0e5e95e..f3914fa 100644
--- a/ui/window_open_disposition_java.target.linux-x86.mk
+++ b/ui/window_open_disposition_java.target.linux-x86.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -162,13 +162,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/gurl.cc b/url/gurl.cc
index 7997d22..15de85a 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -80,33 +80,34 @@
 
 } // namespace
 
-GURL::GURL() : is_valid_(false), inner_url_(NULL) {
+GURL::GURL() : is_valid_(false) {
 }
 
 GURL::GURL(const GURL& other)
     : spec_(other.spec_),
       is_valid_(other.is_valid_),
-      parsed_(other.parsed_),
-      inner_url_(NULL) {
+      parsed_(other.parsed_) {
   if (other.inner_url_)
-    inner_url_ = new GURL(*other.inner_url_);
+    inner_url_.reset(new GURL(*other.inner_url_));
   // Valid filesystem urls should always have an inner_url_.
   DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_);
 }
 
-GURL::GURL(const std::string& url_string) : inner_url_(NULL) {
+GURL::GURL(const std::string& url_string) {
   is_valid_ = InitCanonical(url_string, &spec_, &parsed_);
   if (is_valid_ && SchemeIsFileSystem()) {
-    inner_url_ =
-        new GURL(spec_.data(), parsed_.Length(), *parsed_.inner_parsed(), true);
+    inner_url_.reset(
+        new GURL(spec_.data(), parsed_.Length(),
+                 *parsed_.inner_parsed(), true));
   }
 }
 
-GURL::GURL(const base::string16& url_string) : inner_url_(NULL) {
+GURL::GURL(const base::string16& url_string) {
   is_valid_ = InitCanonical(url_string, &spec_, &parsed_);
   if (is_valid_ && SchemeIsFileSystem()) {
-    inner_url_ =
-        new GURL(spec_.data(), parsed_.Length(), *parsed_.inner_parsed(), true);
+    inner_url_.reset(
+        new GURL(spec_.data(), parsed_.Length(),
+                 *parsed_.inner_parsed(), true));
   }
 }
 
@@ -114,24 +115,23 @@
            const url_parse::Parsed& parsed, bool is_valid)
     : spec_(canonical_spec, canonical_spec_len),
       is_valid_(is_valid),
-      parsed_(parsed),
-      inner_url_(NULL) {
+      parsed_(parsed) {
   InitializeFromCanonicalSpec();
 }
 
 GURL::GURL(std::string canonical_spec,
            const url_parse::Parsed& parsed, bool is_valid)
     : is_valid_(is_valid),
-      parsed_(parsed),
-      inner_url_(NULL) {
+      parsed_(parsed) {
   spec_.swap(canonical_spec);
   InitializeFromCanonicalSpec();
 }
 
 void GURL::InitializeFromCanonicalSpec() {
   if (is_valid_ && SchemeIsFileSystem()) {
-    inner_url_ =
-        new GURL(spec_.data(), parsed_.Length(), *parsed_.inner_parsed(), true);
+    inner_url_.reset(
+        new GURL(spec_.data(), parsed_.Length(),
+                 *parsed_.inner_parsed(), true));
   }
 
 #ifndef NDEBUG
@@ -165,22 +165,10 @@
 }
 
 GURL::~GURL() {
-  delete inner_url_;
 }
 
-GURL& GURL::operator=(const GURL& other) {
-  if (&other == this)
-    return *this;
-
-  spec_ = other.spec_;
-  is_valid_ = other.is_valid_;
-  parsed_ = other.parsed_;
-  delete inner_url_;
-  inner_url_ = NULL;
-  if (other.inner_url_)
-    inner_url_ = new GURL(*other.inner_url_);
-  // Valid filesystem urls should always have an inner_url_.
-  DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_);
+GURL& GURL::operator=(GURL other) {
+  Swap(&other);
   return *this;
 }
 
@@ -225,8 +213,9 @@
   output.Complete();
   result.is_valid_ = true;
   if (result.SchemeIsFileSystem()) {
-    result.inner_url_ = new GURL(result.spec_.data(), result.parsed_.Length(),
-                                 *result.parsed_.inner_parsed(), true);
+    result.inner_url_.reset(
+        new GURL(result.spec_.data(), result.parsed_.Length(),
+                 *result.parsed_.inner_parsed(), true));
   }
   return result;
 }
@@ -257,8 +246,9 @@
   output.Complete();
   result.is_valid_ = true;
   if (result.SchemeIsFileSystem()) {
-    result.inner_url_ = new GURL(result.spec_.data(), result.parsed_.Length(),
-                                 *result.parsed_.inner_parsed(), true);
+    result.inner_url_.reset(
+        new GURL(result.spec_.data(), result.parsed_.Length(),
+                 *result.parsed_.inner_parsed(), true));
   }
   return result;
 }
@@ -283,8 +273,8 @@
 
   output.Complete();
   if (result.is_valid_ && result.SchemeIsFileSystem()) {
-    result.inner_url_ = new GURL(spec_.data(), result.parsed_.Length(),
-                                 *result.parsed_.inner_parsed(), true);
+    result.inner_url_.reset(new GURL(spec_.data(), result.parsed_.Length(),
+                                     *result.parsed_.inner_parsed(), true));
   }
   return result;
 }
@@ -309,8 +299,8 @@
 
   output.Complete();
   if (result.is_valid_ && result.SchemeIsFileSystem()) {
-    result.inner_url_ = new GURL(spec_.data(), result.parsed_.Length(),
-                                 *result.parsed_.inner_parsed(), true);
+    result.inner_url_.reset(new GURL(spec_.data(), result.parsed_.Length(),
+                                     *result.parsed_.inner_parsed(), true));
   }
   return result;
 }
@@ -422,6 +412,10 @@
   return ComponentString(h);
 }
 
+std::string GURL::GetContent() const {
+  return is_valid_ ? ComponentString(parsed_.GetContent()) : std::string();
+}
+
 bool GURL::HostIsIPAddress() const {
   if (!is_valid_ || spec_.empty())
      return false;
@@ -516,7 +510,7 @@
   spec_.swap(other->spec_);
   std::swap(is_valid_, other->is_valid_);
   std::swap(parsed_, other->parsed_);
-  std::swap(inner_url_, other->inner_url_);
+  inner_url_.swap(other->inner_url_);
 }
 
 std::ostream& operator<<(std::ostream& out, const GURL& url) {
diff --git a/url/gurl.h b/url/gurl.h
index 7e71aa9..d4ea10f 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -8,6 +8,7 @@
 #include <iosfwd>
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "url/url_canon.h"
 #include "url/url_canon_stdstring.h"
@@ -52,7 +53,7 @@
 
   ~GURL();
 
-  GURL& operator=(const GURL& other);
+  GURL& operator=(GURL other);
 
   // Returns true when this object represents a valid parsed URL. When not
   // valid, other functions will still succeed, but you will not get canonical
@@ -226,6 +227,11 @@
         (SchemeIsFileSystem() && inner_url() && inner_url()->SchemeIsSecure());
   }
 
+  // The "content" of the URL is everything after the scheme (skipping the
+  // scheme delimiting colon). It is an error to get the origin of an invalid
+  // URL. The result will be an empty string.
+  std::string GetContent() const;
+
   // Returns true if the hostname is an IP address. Note: this function isn't
   // as cheap as a simple getter because it re-parses the hostname to verify.
   // This currently identifies only IPv4 addresses (bug 822685).
@@ -345,7 +351,7 @@
   // Returns the inner URL of a nested URL [currently only non-null for
   // filesystem: URLs].
   const GURL* inner_url() const {
-    return inner_url_;
+    return inner_url_.get();
   }
 
  private:
@@ -370,7 +376,7 @@
   url_parse::Parsed parsed_;
 
   // Used for nested schemes [currently only filesystem:].
-  GURL* inner_url_;
+  scoped_ptr<GURL> inner_url_;
 
   // TODO bug 684583: Add encoding for query params.
 };
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index ddb55d8..67da8e4 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -136,6 +136,48 @@
   EXPECT_EQ("", invalid2.ref());
 }
 
+TEST(GURLTest, Assign) {
+  GURL url(WStringToUTF16(L"http://user:pass@google.com:99/foo;bar?q=a#ref"));
+
+  GURL url2;
+  url2 = url;
+  EXPECT_TRUE(url2.is_valid());
+
+  EXPECT_EQ("http://user:pass@google.com:99/foo;bar?q=a#ref", url2.spec());
+  EXPECT_EQ("http", url2.scheme());
+  EXPECT_EQ("user", url2.username());
+  EXPECT_EQ("pass", url2.password());
+  EXPECT_EQ("google.com", url2.host());
+  EXPECT_EQ("99", url2.port());
+  EXPECT_EQ(99, url2.IntPort());
+  EXPECT_EQ("/foo;bar", url2.path());
+  EXPECT_EQ("q=a", url2.query());
+  EXPECT_EQ("ref", url2.ref());
+
+  // Assignment of invalid URL should be invalid
+  GURL invalid;
+  GURL invalid2;
+  invalid2 = invalid;
+  EXPECT_FALSE(invalid2.is_valid());
+  EXPECT_EQ("", invalid2.spec());
+  EXPECT_EQ("", invalid2.scheme());
+  EXPECT_EQ("", invalid2.username());
+  EXPECT_EQ("", invalid2.password());
+  EXPECT_EQ("", invalid2.host());
+  EXPECT_EQ("", invalid2.port());
+  EXPECT_EQ(url_parse::PORT_UNSPECIFIED, invalid2.IntPort());
+  EXPECT_EQ("", invalid2.path());
+  EXPECT_EQ("", invalid2.query());
+  EXPECT_EQ("", invalid2.ref());
+}
+
+// This is a regression test for http://crbug.com/309975 .
+TEST(GURLTest, SelfAssign) {
+  GURL a("filesystem:http://example.com/temporary/");
+  // This should not crash.
+  a = a;
+}
+
 TEST(GURLTest, CopyFileSystem) {
   GURL url(WStringToUTF16(L"filesystem:https://user:pass@google.com:99/t/foo;bar?q=a#ref"));
 
@@ -487,10 +529,3 @@
   GURL c("foo://bar/baz");
   EXPECT_FALSE(c.IsStandard());
 }
-
-// This is a regression test for http://crbug.com/309975 .
-TEST(GURLTest, SelfAssignment) {
-  GURL a("filesystem:http://example.com/temporary/");
-  // This should not crash.
-  a = a;
-}
diff --git a/url/third_party/mozilla/url_parse.cc b/url/third_party/mozilla/url_parse.cc
index 52c6196..fbc8a9b 100644
--- a/url/third_party/mozilla/url_parse.cc
+++ b/url/third_party/mozilla/url_parse.cc
@@ -792,6 +792,15 @@
   return cur;
 }
 
+Component Parsed::GetContent() const {
+  const int begin = CountCharactersBefore(USERNAME, false);
+  const int len = Length() - begin;
+  // For compatability with the standard URL parser, we treat no content as
+  // -1, rather than having a length of 0 (we normally wouldn't care so
+  // much for these non-standard URLs).
+  return len ? Component(begin, len) : Component();
+}
+
 bool ExtractScheme(const char* url, int url_len, Component* scheme) {
   return DoExtractScheme(url, url_len, scheme);
 }
diff --git a/url/third_party/mozilla/url_parse.h b/url/third_party/mozilla/url_parse.h
index fd974f8..5fa9322 100644
--- a/url/third_party/mozilla/url_parse.h
+++ b/url/third_party/mozilla/url_parse.h
@@ -159,10 +159,11 @@
   // Port number.
   Component port;
 
-  // Path, this is everything following the host name. Length will be -1 if
-  // unspecified. This includes the preceeding slash, so the path on
-  // http://www.google.com/asdf" is "/asdf". As a result, it is impossible to
-  // have a 0 length path, it will be -1 in cases like "http://host?foo".
+  // Path, this is everything following the host name, stopping at the query of
+  // ref delimiter (if any). Length will be -1 if unspecified. This includes
+  // the preceeding slash, so the path on http://www.google.com/asdf" is
+  // "/asdf". As a result, it is impossible to have a 0 length path, it will
+  // be -1 in cases like "http://host?foo".
   // Note that we treat backslashes the same as slashes.
   Component path;
 
@@ -177,6 +178,12 @@
   // nothing follows it.
   Component ref;
 
+  // The URL spec from the character after the scheme: until the end of the
+  // URL, regardless of the scheme. This is mostly useful for 'opaque' non-
+  // hierarchical schemes like data: and javascript: as a convient way to get
+  // the string with the scheme stripped off.
+  Component GetContent() const;
+
   // This is used for nested URL types, currently only filesystem.  If you
   // parse a filesystem URL, the resulting Parsed will have a nested
   // inner_parsed_ to hold the parsed inner URL's component information.
diff --git a/url/url_lib.target.darwin-arm.mk b/url/url_lib.target.darwin-arm.mk
index dd2eb40..720ff0c 100644
--- a/url/url_lib.target.darwin-arm.mk
+++ b/url/url_lib.target.darwin-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/url_lib.target.darwin-mips.mk b/url/url_lib.target.darwin-mips.mk
index 271f9fb..12628ae 100644
--- a/url/url_lib.target.darwin-mips.mk
+++ b/url/url_lib.target.darwin-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/url_lib.target.darwin-x86.mk b/url/url_lib.target.darwin-x86.mk
index 45f368f..28199a6 100644
--- a/url/url_lib.target.darwin-x86.mk
+++ b/url/url_lib.target.darwin-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/url_lib.target.linux-arm.mk b/url/url_lib.target.linux-arm.mk
index dd2eb40..720ff0c 100644
--- a/url/url_lib.target.linux-arm.mk
+++ b/url/url_lib.target.linux-arm.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/url_lib.target.linux-mips.mk b/url/url_lib.target.linux-mips.mk
index 271f9fb..12628ae 100644
--- a/url/url_lib.target.linux-mips.mk
+++ b/url/url_lib.target.linux-mips.mk
@@ -81,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -166,13 +166,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/url/url_lib.target.linux-x86.mk b/url/url_lib.target.linux-x86.mk
index 45f368f..28199a6 100644
--- a/url/url_lib.target.linux-x86.mk
+++ b/url/url_lib.target.linux-x86.mk
@@ -84,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -173,13 +173,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/DEPS b/webkit/DEPS
index 4571d4c..b70f343 100644
--- a/webkit/DEPS
+++ b/webkit/DEPS
@@ -33,9 +33,6 @@
   "+gpu/GLES2",
   "+third_party/khronos/GLES2",
 
-  # For shared USB keycode conversion tables used by ppapi plugin code.
-  "+ui/base/keycodes",
-
   # TODO(brettw) - review these; move up if it's ok, or remove the dependency
   "+net",
   "+third_party/npapi/bindings",
diff --git a/webkit/browser/appcache/appcache_histograms.cc b/webkit/browser/appcache/appcache_histograms.cc
index 574eeb2..36a1260 100644
--- a/webkit/browser/appcache/appcache_histograms.cc
+++ b/webkit/browser/appcache/appcache_histograms.cc
@@ -14,6 +14,10 @@
        init_result, NUM_INIT_RESULT_TYPES);
 }
 
+void AppCacheHistograms::CountReinitAttempt(bool repeated_attempt) {
+  UMA_HISTOGRAM_BOOLEAN("appcache.ReinitAttempt", repeated_attempt);
+}
+
 void AppCacheHistograms::CountCheckResponseResult(
     CheckResponseResultType result) {
   UMA_HISTOGRAM_ENUMERATION(
diff --git a/webkit/browser/appcache/appcache_histograms.h b/webkit/browser/appcache/appcache_histograms.h
index 7de198a..928200f 100644
--- a/webkit/browser/appcache/appcache_histograms.h
+++ b/webkit/browser/appcache/appcache_histograms.h
@@ -20,6 +20,7 @@
     NUM_INIT_RESULT_TYPES
   };
   static void CountInitResult(InitResultType init_result);
+  static void CountReinitAttempt(bool repeated_attempt);
 
   enum CheckResponseResultType {
     RESPONSE_OK, MANIFEST_OUT_OF_DATE, RESPONSE_OUT_OF_DATE, ENTRY_NOT_FOUND,
diff --git a/webkit/browser/appcache/appcache_host.cc b/webkit/browser/appcache/appcache_host.cc
index efd8ce4..0f6523b 100644
--- a/webkit/browser/appcache/appcache_host.cc
+++ b/webkit/browser/appcache/appcache_host.cc
@@ -50,19 +50,22 @@
       pending_main_resource_cache_id_(kNoCacheId),
       pending_selected_cache_id_(kNoCacheId),
       frontend_(frontend), service_(service),
+      storage_(service->storage()),
       pending_callback_param_(NULL),
       main_resource_was_namespace_entry_(false),
       main_resource_blocked_(false),
       associated_cache_info_pending_(false) {
+  service_->AddObserver(this);
 }
 
 AppCacheHost::~AppCacheHost() {
+  service_->RemoveObserver(this);
   FOR_EACH_OBSERVER(Observer, observers_, OnDestructionImminent(this));
   if (associated_cache_.get())
     associated_cache_->UnassociateHost(this);
   if (group_being_updated_.get())
     group_being_updated_->RemoveUpdateObserver(this);
-  service_->storage()->CancelDelegateCallbacks(this);
+  storage()->CancelDelegateCallbacks(this);
   if (service()->quota_manager_proxy() && !origin_in_use_.is_empty())
     service()->quota_manager_proxy()->NotifyOriginNoLongerInUse(origin_in_use_);
 }
@@ -161,7 +164,7 @@
 void AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
                                       int64 cache_document_was_loaded_from) {
   // The document url is not the resource url in the fallback case.
-  service_->storage()->MarkEntryAsForeign(
+  storage()->MarkEntryAsForeign(
       main_resource_was_namespace_entry_ ? namespace_entry_url_ : document_url,
       cache_document_was_loaded_from);
   SelectCache(document_url, kNoCacheId, GURL());
@@ -329,7 +332,7 @@
 void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) {
   DCHECK(manifest_url.is_valid());
   pending_selected_manifest_url_ = manifest_url;
-  service_->storage()->LoadOrCreateGroup(manifest_url, this);
+  storage()->LoadOrCreateGroup(manifest_url, this);
 }
 
 void AppCacheHost::OnGroupLoaded(AppCacheGroup* group,
@@ -342,7 +345,7 @@
 void AppCacheHost::LoadSelectedCache(int64 cache_id) {
   DCHECK(cache_id != kNoCacheId);
   pending_selected_cache_id_ = cache_id;
-  service_->storage()->LoadCache(cache_id, this);
+  storage()->LoadCache(cache_id, this);
 }
 
 void AppCacheHost::OnCacheLoaded(AppCache* cache, int64 cache_id) {
@@ -417,6 +420,14 @@
   FOR_EACH_OBSERVER(Observer, observers_, OnCacheSelectionComplete(this));
 }
 
+void AppCacheHost::OnServiceReinitialized(
+    AppCacheStorageReference* old_storage_ref) {
+  // We continue to use the disabled instance, but arrange for its
+  // deletion when its no longer needed.
+  if (old_storage_ref->storage() == storage())
+    disabled_storage_reference_ = old_storage_ref;
+}
+
 void AppCacheHost::ObserveGroupBeingUpdated(AppCacheGroup* group) {
   DCHECK(!group_being_updated_.get());
   group_being_updated_ = group;
@@ -464,7 +475,7 @@
     return;
   }
   pending_main_resource_cache_id_ = cache_id;
-  service_->storage()->LoadCache(cache_id, this);
+  storage()->LoadCache(cache_id, this);
 }
 
 void AppCacheHost::NotifyMainResourceIsNamespaceEntry(
diff --git a/webkit/browser/appcache/appcache_host.h b/webkit/browser/appcache/appcache_host.h
index 4242bc1..7869dad 100644
--- a/webkit/browser/appcache/appcache_host.h
+++ b/webkit/browser/appcache/appcache_host.h
@@ -34,7 +34,8 @@
 // Server-side representation of an application cache host.
 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheHost
     : public AppCacheStorage::Delegate,
-      public AppCacheGroup::UpdateObserver {
+      public AppCacheGroup::UpdateObserver,
+      public AppCacheService::Observer {
  public:
 
   class WEBKIT_STORAGE_BROWSER_EXPORT Observer {
@@ -140,6 +141,7 @@
 
   int host_id() const { return host_id_; }
   AppCacheService* service() const { return service_; }
+  AppCacheStorage* storage() const { return storage_; }
   AppCacheFrontend* frontend() const { return frontend_; }
   AppCache* associated_cache() const { return associated_cache_.get(); }
 
@@ -162,6 +164,9 @@
   virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE;
   virtual void OnGroupLoaded(AppCacheGroup* group,
                              const GURL& manifest_url) OVERRIDE;
+  // AppCacheService::Observer impl
+  virtual void OnServiceReinitialized(
+      AppCacheStorageReference* old_storage_ref) OVERRIDE;
 
   void FinishCacheSelection(AppCache* cache, AppCacheGroup* group);
   void DoPendingGetStatus();
@@ -237,6 +242,15 @@
   // Our central service object.
   AppCacheService* service_;
 
+  // And the equally central storage object, with a twist. In some error
+  // conditions the storage object gets recreated and reinitialized. The
+  // disabled_reference_ allows for cleanup of an instance that got disabled
+  // after we had latched onto it. In normal circumstances,
+  // disabled_reference_ is expected to be NULL. When non-NULL both
+  // storage_ and disabled_reference_ refer to the same instance.
+  AppCacheStorage* storage_;
+  scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
+
   // Since these are synchronous scriptable API calls in the client, there can
   // only be one type of callback pending. Also, we have to wait until we have a
   // cache selection prior to responding to these calls, as cache selection
@@ -268,6 +282,7 @@
   // First party url to be used in policy checks.
   GURL first_party_url_;
 
+  friend class AppCacheStorageImplTest;
   friend class AppCacheRequestHandlerTest;
   friend class AppCacheUpdateJobTest;
   FRIEND_TEST_ALL_PREFIXES(AppCacheTest, CleanupUnusedCache);
diff --git a/webkit/browser/appcache/appcache_quota_client.cc b/webkit/browser/appcache/appcache_quota_client.cc
index fc8db6d..ec44a28 100644
--- a/webkit/browser/appcache/appcache_quota_client.cc
+++ b/webkit/browser/appcache/appcache_quota_client.cc
@@ -225,8 +225,11 @@
 }
 
 void AppCacheQuotaClient::NotifyAppCacheReady() {
-  appcache_is_ready_ = true;
-  ProcessPendingRequests();
+  // Can reoccur during reinitialization.
+  if (!appcache_is_ready_) {
+    appcache_is_ready_ = true;
+    ProcessPendingRequests();
+  }
 }
 
 void AppCacheQuotaClient::NotifyAppCacheDestroyed() {
diff --git a/webkit/browser/appcache/appcache_request_handler.cc b/webkit/browser/appcache/appcache_request_handler.cc
index d2367ce..957cf20 100644
--- a/webkit/browser/appcache/appcache_request_handler.cc
+++ b/webkit/browser/appcache/appcache_request_handler.cc
@@ -31,7 +31,7 @@
 
 AppCacheStorage* AppCacheRequestHandler::storage() const {
   DCHECK(host_);
-  return host_->service()->storage();
+  return host_->storage();
 }
 
 void AppCacheRequestHandler::GetExtraResponseInfo(
diff --git a/webkit/browser/appcache/appcache_response.cc b/webkit/browser/appcache/appcache_response.cc
index 529e587..9ba1dff 100644
--- a/webkit/browser/appcache/appcache_response.cc
+++ b/webkit/browser/appcache/appcache_response.cc
@@ -14,7 +14,7 @@
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "webkit/browser/appcache/appcache_service.h"
+#include "webkit/browser/appcache/appcache_storage.h"
 
 namespace appcache {
 
@@ -48,19 +48,19 @@
 // AppCacheResponseInfo ----------------------------------------------
 
 AppCacheResponseInfo::AppCacheResponseInfo(
-    AppCacheService* service, const GURL& manifest_url,
+    AppCacheStorage* storage, const GURL& manifest_url,
     int64 response_id,  net::HttpResponseInfo* http_info,
     int64 response_data_size)
     : manifest_url_(manifest_url), response_id_(response_id),
       http_response_info_(http_info), response_data_size_(response_data_size),
-      service_(service) {
+      storage_(storage) {
   DCHECK(http_info);
   DCHECK(response_id != kNoResponseId);
-  service_->storage()->working_set()->AddResponseInfo(this);
+  storage_->working_set()->AddResponseInfo(this);
 }
 
 AppCacheResponseInfo::~AppCacheResponseInfo() {
-  service_->storage()->working_set()->RemoveResponseInfo(this);
+  storage_->working_set()->RemoveResponseInfo(this);
 }
 
 // HttpResponseInfoIOBuffer ------------------------------------------
diff --git a/webkit/browser/appcache/appcache_response.h b/webkit/browser/appcache/appcache_response.h
index 9a23d84..610bdf4 100644
--- a/webkit/browser/appcache/appcache_response.h
+++ b/webkit/browser/appcache/appcache_response.h
@@ -21,7 +21,7 @@
 
 namespace appcache {
 
-class AppCacheService;
+class AppCacheStorage;
 
 static const int kUnkownResponseDataSize = -1;
 
@@ -31,7 +31,7 @@
     : public base::RefCounted<AppCacheResponseInfo> {
  public:
   // AppCacheResponseInfo takes ownership of the http_info.
-  AppCacheResponseInfo(AppCacheService* service, const GURL& manifest_url,
+  AppCacheResponseInfo(AppCacheStorage* storage, const GURL& manifest_url,
                        int64 response_id, net::HttpResponseInfo* http_info,
                        int64 response_data_size);
 
@@ -50,7 +50,7 @@
   const int64 response_id_;
   const scoped_ptr<net::HttpResponseInfo> http_response_info_;
   const int64 response_data_size_;
-  const AppCacheService* service_;
+  AppCacheStorage* storage_;
 };
 
 // A refcounted wrapper for HttpResponseInfo so we can apply the
diff --git a/webkit/browser/appcache/appcache_service.cc b/webkit/browser/appcache/appcache_service.cc
index 843df07..c11631c 100644
--- a/webkit/browser/appcache/appcache_service.cc
+++ b/webkit/browser/appcache/appcache_service.cc
@@ -427,13 +427,21 @@
 }
 
 
+// AppCacheStorageReference ------
+
+AppCacheStorageReference::AppCacheStorageReference(
+    scoped_ptr<AppCacheStorage> storage)
+    : storage_(storage.Pass()) {}
+AppCacheStorageReference::~AppCacheStorageReference() {}
+
 // AppCacheService -------
 
 AppCacheService::AppCacheService(quota::QuotaManagerProxy* quota_manager_proxy)
     : appcache_policy_(NULL), quota_client_(NULL), handler_factory_(NULL),
       quota_manager_proxy_(quota_manager_proxy),
       request_context_(NULL),
-      force_keep_session_state_(false) {
+      force_keep_session_state_(false),
+      was_reinitialized_(false) {
   if (quota_manager_proxy_.get()) {
     quota_client_ = new AppCacheQuotaClient(this);
     quota_manager_proxy_->RegisterClient(quota_client_);
@@ -458,11 +466,32 @@
                                  base::MessageLoopProxy* db_thread,
                                  base::MessageLoopProxy* cache_thread) {
   DCHECK(!storage_.get());
+  cache_directory_ = cache_directory;
+  db_thread_ = db_thread;
+  cache_thread_ = cache_thread;
   AppCacheStorageImpl* storage = new AppCacheStorageImpl(this);
   storage->Initialize(cache_directory, db_thread, cache_thread);
   storage_.reset(storage);
 }
 
+void AppCacheService::Reinitialize() {
+  AppCacheHistograms::CountReinitAttempt(was_reinitialized_);
+
+  // To avoid thrashing, we only do this once.
+  if (was_reinitialized_)
+    return;
+  was_reinitialized_ = true;
+
+  // Inform observers of about this and give them a chance to
+  // defer deletion of the old storage object.
+  scoped_refptr<AppCacheStorageReference>
+      old_storage_ref(new AppCacheStorageReference(storage_.Pass()));
+  FOR_EACH_OBSERVER(Observer, observers_,
+                    OnServiceReinitialized(old_storage_ref.get()));
+
+  Initialize(cache_directory_, db_thread_, cache_thread_);
+}
+
 void AppCacheService::CanHandleMainResourceOffline(
     const GURL& url,
     const GURL& first_party,
diff --git a/webkit/browser/appcache/appcache_service.h b/webkit/browser/appcache/appcache_service.h
index 92edf5c..43e38b4 100644
--- a/webkit/browser/appcache/appcache_service.h
+++ b/webkit/browser/appcache/appcache_service.h
@@ -11,6 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "webkit/browser/appcache/appcache_storage.h"
@@ -50,11 +51,38 @@
   virtual ~AppCacheInfoCollection();
 };
 
+// Refcounted container to manage the lifetime of the old storage instance
+// during Reinitialization.
+class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheStorageReference :
+    public base::RefCounted<AppCacheStorageReference> {
+ public:
+  AppCacheStorage* storage() const { return storage_.get(); }
+ private:
+  friend class AppCacheService;
+  friend class base::RefCounted<AppCacheStorageReference>;
+  AppCacheStorageReference(scoped_ptr<AppCacheStorage> storage);
+  ~AppCacheStorageReference();
+
+  scoped_ptr<AppCacheStorage> storage_;
+};
+
 // Class that manages the application cache service. Sends notifications
 // to many frontends.  One instance per user-profile. Each instance has
 // exclusive access to its cache_directory on disk.
 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheService {
  public:
+
+  class WEBKIT_STORAGE_BROWSER_EXPORT Observer {
+   public:
+    // An observer method to inform consumers of reinitialzation. Managing
+    // the lifetime of the old storage instance is a delicate process.
+    // Consumers can keep the old disabled instance alive by hanging on to the
+    // ref provided.
+    virtual void OnServiceReinitialized(
+        AppCacheStorageReference* old_storage_ref) = 0;
+    virtual ~Observer() {}
+  };
+
   // If not using quota management, the proxy may be NULL.
   explicit AppCacheService(quota::QuotaManagerProxy* quota_manager_proxy);
   virtual ~AppCacheService();
@@ -63,6 +91,18 @@
                   base::MessageLoopProxy* db_thread,
                   base::MessageLoopProxy* cache_thread);
 
+  void AddObserver(Observer* observer) {
+    observers_.AddObserver(observer);
+  }
+
+  void RemoveObserver(Observer* observer) {
+    observers_.RemoveObserver(observer);
+  }
+
+  // For use in a very specific failure mode to reboot the appcache system
+  // without relaunching the browser.
+  void Reinitialize();
+
   // Purges any memory not needed.
   void PurgeMemory() {
     if (storage_)
@@ -172,6 +212,9 @@
   typedef std::set<AsyncHelper*> PendingAsyncHelpers;
   typedef std::map<int, AppCacheBackendImpl*> BackendMap;
 
+  base::FilePath cache_directory_;
+  scoped_refptr<base::MessageLoopProxy> db_thread_;
+  scoped_refptr<base::MessageLoopProxy> cache_thread_;
   AppCachePolicy* appcache_policy_;
   AppCacheQuotaClient* quota_client_;
   AppCacheExecutableHandlerFactory* handler_factory_;
@@ -184,6 +227,8 @@
   net::URLRequestContext* request_context_;
   // If true, nothing (not even session-only data) should be deleted on exit.
   bool force_keep_session_state_;
+  bool was_reinitialized_;
+  ObserverList<Observer> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AppCacheService);
 };
diff --git a/webkit/browser/appcache/appcache_storage.cc b/webkit/browser/appcache/appcache_storage.cc
index aaa3100..2482cfa 100644
--- a/webkit/browser/appcache/appcache_storage.cc
+++ b/webkit/browser/appcache/appcache_storage.cc
@@ -70,7 +70,7 @@
   storage_->pending_info_loads_.erase(response_id_);
   scoped_refptr<AppCacheResponseInfo> info;
   if (result >= 0) {
-    info = new AppCacheResponseInfo(storage_->service(), manifest_url_,
+    info = new AppCacheResponseInfo(storage_, manifest_url_,
                                     response_id_,
                                     info_buffer_->http_info.release(),
                                     info_buffer_->response_data_size);
diff --git a/webkit/browser/appcache/appcache_storage_impl.cc b/webkit/browser/appcache/appcache_storage_impl.cc
index f0ee8e5..f762a16 100644
--- a/webkit/browser/appcache/appcache_storage_impl.cc
+++ b/webkit/browser/appcache/appcache_storage_impl.cc
@@ -1417,7 +1417,7 @@
   if (usage_map_.find(manifest_url.GetOrigin()) == usage_map_.end()) {
     // No need to query the database, return a new group immediately.
     scoped_refptr<AppCacheGroup> group(new AppCacheGroup(
-        service_->storage(), manifest_url, NewGroupId()));
+        this, manifest_url, NewGroupId()));
     delegate->OnGroupLoaded(group.get(), manifest_url);
     return;
   }
@@ -1807,17 +1807,24 @@
     AppCacheHistograms::CountInitResult(AppCacheHistograms::DISK_CACHE_ERROR);
 
     // We're unable to open the disk cache, this is a fatal error that we can't
-    // really recover from. We handle it by disabling the appcache for this
-    // browser session and deleting the directory on disk. The next browser
-    // session should start with a clean slate.
+    // really recover from. We handle it by temporarily disabling the appcache
+    // deleting the directory on disk and reinitializing the appcache system.
     Disable();
-    if (!is_incognito_) {
+    if (!is_incognito_ && rv != net::ERR_ABORTED) {
       VLOG(1) << "Deleting existing appcache data and starting over.";
-      db_thread_->PostTask(
-          FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
-                                cache_directory_, true));
+      db_thread_->PostTaskAndReply(
+          FROM_HERE,
+          base::Bind(base::IgnoreResult(&base::DeleteFile),
+                     cache_directory_, true),
+          base::Bind(&AppCacheStorageImpl::CallReinitialize,
+                     weak_factory_.GetWeakPtr()));
     }
   }
 }
 
+void AppCacheStorageImpl::CallReinitialize() {
+  service_->Reinitialize();
+  // note: 'this' may be deleted during reinit.
+}
+
 }  // namespace appcache
diff --git a/webkit/browser/appcache/appcache_storage_impl.h b/webkit/browser/appcache/appcache_storage_impl.h
index c705d26..163001d 100644
--- a/webkit/browser/appcache/appcache_storage_impl.h
+++ b/webkit/browser/appcache/appcache_storage_impl.h
@@ -114,6 +114,7 @@
 
   void OnDeletedOneResponse(int rv);
   void OnDiskCacheInitialized(int rv);
+  void CallReinitialize();
 
   // Sometimes we can respond without having to query the database.
   bool FindResponseForMainRequestInGroup(
diff --git a/webkit/browser/appcache/appcache_storage_impl_unittest.cc b/webkit/browser/appcache/appcache_storage_impl_unittest.cc
index 8c054c7..9739f06 100644
--- a/webkit/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/webkit/browser/appcache/appcache_storage_impl_unittest.cc
@@ -7,15 +7,26 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_error_job.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webkit/browser/appcache/appcache.h"
+#include "webkit/browser/appcache/appcache_backend_impl.h"
 #include "webkit/browser/appcache/appcache_database.h"
 #include "webkit/browser/appcache/appcache_entry.h"
 #include "webkit/browser/appcache/appcache_group.h"
+#include "webkit/browser/appcache/appcache_host.h"
+#include "webkit/browser/appcache/appcache_interceptor.h"
+#include "webkit/browser/appcache/appcache_request_handler.h"
 #include "webkit/browser/appcache/appcache_service.h"
 #include "webkit/browser/appcache/appcache_storage_impl.h"
 #include "webkit/browser/quota/quota_manager.h"
@@ -60,7 +71,100 @@
 
 const int kMockQuota = 5000;
 
-scoped_ptr<base::Thread> io_thread;
+// The Reinitialize test needs some http accessible resources to run,
+// we mock stuff inprocess for that.
+class MockHttpServer {
+ public:
+  static GURL GetMockUrl(const std::string& path) {
+    return GURL("http://mockhost/" + path);
+  }
+
+  static net::URLRequestJob* CreateJob(
+      net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+    if (request->url().host() != "mockhost")
+      return new net::URLRequestErrorJob(request, network_delegate, -100);
+
+    std::string headers, body;
+    GetMockResponse(request->url().path(), &headers, &body);
+    return new net::URLRequestTestJob(
+        request, network_delegate, headers, body, true);
+  }
+
+ private:
+  static void GetMockResponse(const std::string& path,
+                              std::string* headers,
+                              std::string* body) {
+    const char manifest_headers[] =
+        "HTTP/1.1 200 OK\0"
+        "Content-type: text/cache-manifest\0"
+        "\0";
+    const char page_headers[] =
+        "HTTP/1.1 200 OK\0"
+        "Content-type: text/html\0"
+        "\0";
+    const char not_found_headers[] =
+        "HTTP/1.1 404 NOT FOUND\0"
+        "\0";
+
+    if (path == "/manifest") {
+      (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
+      (*body) = "CACHE MANIFEST\n";
+    } else if (path == "/empty.html") {
+      (*headers) = std::string(page_headers, arraysize(page_headers));
+      (*body) = "";
+    } else {
+      (*headers) = std::string(not_found_headers,
+                               arraysize(not_found_headers));
+      (*body) = "";
+    }
+  }
+};
+
+class MockHttpServerJobFactory
+    : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+  virtual net::URLRequestJob* MaybeCreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const OVERRIDE {
+    return MockHttpServer::CreateJob(request, network_delegate);
+  }
+};
+
+class IOThread : public base::Thread {
+ public:
+  explicit IOThread(const char* name)
+      : base::Thread(name) {
+  }
+
+  virtual ~IOThread() {
+    Stop();
+  }
+
+  net::URLRequestContext* request_context() {
+    return request_context_.get();
+  }
+
+  virtual void Init() OVERRIDE {
+    scoped_ptr<net::URLRequestJobFactoryImpl> factory(
+        new net::URLRequestJobFactoryImpl());
+    factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
+    job_factory_ = factory.Pass();
+    request_context_.reset(new net::TestURLRequestContext());
+    request_context_->set_job_factory(job_factory_.get());
+    AppCacheInterceptor::EnsureRegistered();
+  }
+
+  virtual void CleanUp() OVERRIDE {
+    request_context_.reset();
+    job_factory_.reset();
+  }
+
+ private:
+  scoped_ptr<net::URLRequestJobFactory> job_factory_;
+  scoped_ptr<net::URLRequestContext> request_context_;
+};
+
+scoped_ptr<IOThread> io_thread;
 scoped_ptr<base::Thread> db_thread;
 
 }  // namespace
@@ -251,12 +355,13 @@
   }
 
   static void SetUpTestCase() {
-    io_thread.reset(new base::Thread("AppCacheTest.IOThread"));
+    // We start both threads as TYPE_IO because we also use the db_thead
+    // for the disk_cache which needs to be of TYPE_IO.
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+    io_thread.reset(new IOThread("AppCacheTest.IOThread"));
     ASSERT_TRUE(io_thread->StartWithOptions(options));
-
     db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
-    ASSERT_TRUE(db_thread->Start());
+    ASSERT_TRUE(db_thread->StartWithOptions(options));
   }
 
   static void TearDownTestCase() {
@@ -1455,6 +1560,197 @@
     TestFinished();
   }
 
+  // Reinitialize  -------------------------------
+  // This test is somewhat of a system integration test.
+  // It relies on running a mock http server on our IO thread,
+  // and involves other appcache classes to get some code
+  // coverage thruout when Reinitialize happens.
+
+  class MockServiceObserver : public AppCacheService::Observer {
+   public:
+    explicit MockServiceObserver(AppCacheStorageImplTest* test)
+        : test_(test) {}
+
+    virtual void OnServiceReinitialized(
+        AppCacheStorageReference* old_storage_ref) OVERRIDE {
+      observed_old_storage_ = old_storage_ref;
+      test_->ScheduleNextTask();
+    }
+
+    scoped_refptr<AppCacheStorageReference> observed_old_storage_;
+    AppCacheStorageImplTest* test_;
+  };
+
+  class MockAppCacheFrontend : public AppCacheFrontend {
+   public:
+    MockAppCacheFrontend() : error_event_was_raised_(false) {}
+
+    virtual void OnCacheSelected(
+        int host_id, const appcache::AppCacheInfo& info) OVERRIDE {}
+    virtual void OnStatusChanged(const std::vector<int>& host_ids,
+                                 Status status) OVERRIDE {}
+    virtual void OnEventRaised(const std::vector<int>& host_ids,
+                               EventID event_id) OVERRIDE {}
+    virtual void OnProgressEventRaised(
+        const std::vector<int>& host_ids,
+        const GURL& url,
+        int num_total, int num_complete) OVERRIDE {}
+    virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
+                                    const std::string& message) OVERRIDE {
+      error_event_was_raised_ = true;
+    }
+    virtual void OnLogMessage(int host_id, LogLevel log_level,
+                              const std::string& message) OVERRIDE {}
+    virtual void OnContentBlocked(
+        int host_id, const GURL& manifest_url) OVERRIDE {}
+
+    bool error_event_was_raised_;
+  };
+
+  void Reinitialize1() {
+    Reinitialize(1);
+  }
+
+  void Reinitialize2() {
+    Reinitialize(2);
+  }
+
+  void Reinitialize(int test_case) {
+    // Unlike all of the other tests, this one actually read/write files.
+    ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
+
+    // Create a corrupt/unopenable disk_cache index file.
+    const std::string kCorruptData("deadbeef");
+    base::FilePath disk_cache_directory =
+        temp_directory_.path().AppendASCII("Cache");
+    ASSERT_TRUE(file_util::CreateDirectory(disk_cache_directory));
+    base::FilePath index_file = disk_cache_directory.AppendASCII("index");
+    EXPECT_EQ(static_cast<int>(kCorruptData.length()),
+              file_util::WriteFile(
+                  index_file, kCorruptData.data(), kCorruptData.length()));
+
+    // Create records for a degenerate cached manifest that only contains
+    // one entry for the manifest file resource.
+    if (test_case == 2) {
+      AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
+      GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
+
+      AppCacheDatabase::GroupRecord group_record;
+      group_record.group_id = 1;
+      group_record.manifest_url = manifest_url;
+      group_record.origin = manifest_url.GetOrigin();
+      EXPECT_TRUE(db.InsertGroup(&group_record));
+      AppCacheDatabase::CacheRecord cache_record;
+      cache_record.cache_id = 1;
+      cache_record.group_id = 1;
+      cache_record.online_wildcard = false;
+      cache_record.update_time = kZeroTime;
+      cache_record.cache_size = kDefaultEntrySize;
+      EXPECT_TRUE(db.InsertCache(&cache_record));
+      AppCacheDatabase::EntryRecord entry_record;
+      entry_record.cache_id = 1;
+      entry_record.url = manifest_url;
+      entry_record.flags = AppCacheEntry::MANIFEST;
+      entry_record.response_id = 1;
+      entry_record.response_size = kDefaultEntrySize;
+      EXPECT_TRUE(db.InsertEntry(&entry_record));
+    }
+
+    // Recreate the service to point at the db and corruption on disk.
+    service_.reset(new AppCacheService(NULL));
+    service_->set_request_context(io_thread->request_context());
+    service_->Initialize(
+        temp_directory_.path(),
+        db_thread->message_loop_proxy().get(),
+        db_thread->message_loop_proxy().get());
+    mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
+    service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
+    delegate_.reset(new MockStorageDelegate(this));
+
+    // Additional setup to observe reinitailize happens.
+    observer_.reset(new MockServiceObserver(this));
+    service_->AddObserver(observer_.get());
+
+    // We continue after the init task is complete including the callback
+    // on the current thread.
+    FlushDbThreadTasks();
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
+                   base::Unretained(this),
+                   test_case));
+  }
+
+  void Continue_Reinitialize(int test_case) {
+    const int kMockProcessId = 1;
+    backend_.reset(new AppCacheBackendImpl);
+    backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
+
+    if (test_case == 1) {
+      // Try to create a new appcache, the resulting update job will
+      // eventually fail when it gets to disk cache initialization.
+      backend_->RegisterHost(1);
+      AppCacheHost* host1 = backend_->GetHost(1);
+      const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
+      host1->first_party_url_ = kEmptyPageUrl;
+      host1->SelectCache(kEmptyPageUrl,
+                         kNoCacheId,
+                         MockHttpServer::GetMockUrl("manifest"));
+    } else {
+      ASSERT_EQ(2, test_case);
+      // Try to access the existing cache manifest.
+      // The URLRequestJob  will eventually fail when it gets to disk
+      // cache initialization.
+      backend_->RegisterHost(2);
+      AppCacheHost* host2 = backend_->GetHost(2);
+      GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
+      request_.reset(
+          service()->request_context()->CreateRequest(manifest_url, NULL));
+      AppCacheInterceptor::SetExtraRequestInfo(
+          request_.get(), service_.get(),
+          backend_->process_id(), host2->host_id(),
+          ResourceType::MAIN_FRAME);
+      request_->Start();
+    }
+
+    PushNextTask(base::Bind(
+        &AppCacheStorageImplTest::Verify_Reinitialized,
+        base::Unretained(this),
+        test_case));
+  }
+
+  void Verify_Reinitialized(int test_case) {
+    // Verify we got notified of reinit and a new storage instance is created,
+    // and that the old data has been deleted.
+    EXPECT_TRUE(observer_->observed_old_storage_.get());
+    EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
+    EXPECT_FALSE(PathExists(
+        temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
+    EXPECT_FALSE(PathExists(
+        temp_directory_.path().AppendASCII("Index")));
+
+    // Verify that the hosts saw appropriate events.
+    if (test_case == 1) {
+      EXPECT_TRUE(frontend_.error_event_was_raised_);
+      AppCacheHost* host1 = backend_->GetHost(1);
+      EXPECT_FALSE(host1->associated_cache());
+      EXPECT_FALSE(host1->group_being_updated_);
+      EXPECT_TRUE(host1->disabled_storage_reference_.get());
+    } else {
+      ASSERT_EQ(2, test_case);
+      AppCacheHost* host2 = backend_->GetHost(2);
+      EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
+      EXPECT_TRUE(host2->disabled_storage_reference_.get());
+    }
+
+    // Cleanup and claim victory.
+    service_->RemoveObserver(observer_.get());
+    request_.reset();
+    backend_.reset();
+    observer_.reset();
+    TestFinished();
+  }
+
   // Test case helpers --------------------------------------------------
 
   AppCacheService* service() {
@@ -1520,6 +1816,13 @@
   scoped_refptr<AppCacheGroup> group_;
   scoped_refptr<AppCache> cache_;
   scoped_refptr<AppCache> cache2_;
+
+  // Specifically for the Reinitalize test.
+  base::ScopedTempDir temp_directory_;
+  scoped_ptr<MockServiceObserver> observer_;
+  MockAppCacheFrontend frontend_;
+  scoped_ptr<AppCacheBackendImpl> backend_;
+  scoped_ptr<net::URLRequest> request_;
 };
 
 
@@ -1641,6 +1944,14 @@
       &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
 }
 
+TEST_F(AppCacheStorageImplTest, Reinitialize1) {
+  RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
+}
+
+TEST_F(AppCacheStorageImplTest, Reinitialize2) {
+  RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
+}
+
 // That's all folks!
 
 }  // namespace appcache
diff --git a/webkit/browser/appcache/appcache_storage_unittest.cc b/webkit/browser/appcache/appcache_storage_unittest.cc
index b868262..32bca0c 100644
--- a/webkit/browser/appcache/appcache_storage_unittest.cc
+++ b/webkit/browser/appcache/appcache_storage_unittest.cc
@@ -59,7 +59,7 @@
 TEST_F(AppCacheStorageTest, AddRemoveResponseInfo) {
   MockAppCacheService service;
   scoped_refptr<AppCacheResponseInfo> info(
-      new AppCacheResponseInfo(&service, GURL(),
+      new AppCacheResponseInfo(service.storage(), GURL(),
                                111, new net::HttpResponseInfo,
                                kUnkownResponseDataSize));
 
diff --git a/webkit/browser/appcache/appcache_update_job.cc b/webkit/browser/appcache/appcache_update_job.cc
index 4efe947..c3ea6b4 100644
--- a/webkit/browser/appcache/appcache_update_job.cc
+++ b/webkit/browser/appcache/appcache_update_job.cc
@@ -302,10 +302,14 @@
       master_entries_completed_(0),
       url_fetches_completed_(0),
       manifest_fetcher_(NULL),
-      stored_state_(UNSTORED) {
+      stored_state_(UNSTORED),
+      storage_(service->storage()) {
+    service_->AddObserver(this);
 }
 
 AppCacheUpdateJob::~AppCacheUpdateJob() {
+  if (service_)
+    service_->RemoveObserver(this);
   if (internal_state_ != COMPLETED)
     Cancel();
 
@@ -383,7 +387,7 @@
 
 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() {
   AppCacheResponseWriter* writer =
-      service_->storage()->CreateResponseWriter(manifest_url_,
+      storage_->CreateResponseWriter(manifest_url_,
                                                 group_->group_id());
   stored_response_ids_.push_back(writer->response_id());
   return writer;
@@ -416,8 +420,8 @@
         group_->newest_complete_cache()->GetEntry(manifest_url_) : NULL;
     if (entry) {
       // Asynchronously load response info for manifest from newest cache.
-      service_->storage()->LoadResponseInfo(manifest_url_, group_->group_id(),
-                                            entry->response_id(), this);
+      storage_->LoadResponseInfo(manifest_url_, group_->group_id(),
+                                 entry->response_id(), this);
     } else {
       manifest_fetcher_->Start();
     }
@@ -457,7 +461,7 @@
     ContinueHandleManifestFetchCompleted(false);
   } else if ((response_code == 404 || response_code == 410) &&
              update_type_ == UPGRADE_ATTEMPT) {
-    service_->storage()->MakeGroupObsolete(group_, this);  // async
+    storage_->MakeGroupObsolete(group_, this);  // async
   } else {
     const char* kFormatString = "Manifest fetch failed (%d) %s";
     std::string message = base::StringPrintf(kFormatString, response_code,
@@ -508,8 +512,7 @@
 
   // Proceed with update process. Section 6.9.4 steps 8-20.
   internal_state_ = DOWNLOADING;
-  inprogress_cache_ = new AppCache(service_->storage(),
-                                   service_->storage()->NewCacheId());
+  inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId());
   BuildUrlFileList(manifest);
   inprogress_cache_->InitializeWithManifest(&manifest);
 
@@ -756,8 +759,7 @@
 
   // TODO(michaeln): dcheck is fishing for clues to crbug/95101
   DCHECK_EQ(manifest_url_, group_->manifest_url());
-  service_->storage()
-      ->StoreGroupAndNewestCache(group_, newest_cache.get(), this);  // async
+  storage_->StoreGroupAndNewestCache(group_, newest_cache.get(), this);
 }
 
 void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group,
@@ -843,24 +845,37 @@
   hosts.erase(it);
 }
 
+void AppCacheUpdateJob::OnServiceReinitialized(
+    AppCacheStorageReference* old_storage_ref) {
+  // We continue to use the disabled instance, but arrange for its
+  // deletion when its no longer needed.
+  if (old_storage_ref->storage() == storage_)
+    disabled_storage_reference_ = old_storage_ref;
+}
+
 void AppCacheUpdateJob::CheckIfManifestChanged() {
   DCHECK(update_type_ == UPGRADE_ATTEMPT);
-  AppCacheEntry* entry =
-      group_->newest_complete_cache()->GetEntry(manifest_url_);
+  AppCacheEntry* entry = NULL;
+  if (group_->newest_complete_cache())
+    entry = group_->newest_complete_cache()->GetEntry(manifest_url_);
   if (!entry) {
     // TODO(michaeln): This is just a bandaid to avoid a crash.
     // http://code.google.com/p/chromium/issues/detail?id=95101
-    HandleCacheFailure("Manifest entry not found in existing cache");
-    AppCacheHistograms::AddMissingManifestEntrySample();
-    service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+    if (service_->storage() == storage_) {
+      // Use a local variable because service_ is reset in HandleCacheFailure.
+      AppCacheService* service = service_;
+      HandleCacheFailure("Manifest entry not found in existing cache");
+      AppCacheHistograms::AddMissingManifestEntrySample();
+      service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+    }
     return;
   }
 
   // Load manifest data from storage to compare against fetched manifest.
   manifest_response_reader_.reset(
-      service_->storage()->CreateResponseReader(manifest_url_,
-                                                group_->group_id(),
-                                                entry->response_id()));
+      storage_->CreateResponseReader(manifest_url_,
+                                     group_->group_id(),
+                                     entry->response_id()));
   read_manifest_buffer_ = new net::IOBuffer(kBufferSize);
   manifest_response_reader_->ReadData(
       read_manifest_buffer_.get(),
@@ -1142,9 +1157,9 @@
   // Load HTTP headers for entry from newest cache.
   loading_responses_.insert(
       LoadingResponses::value_type(copy_me->response_id(), url));
-  service_->storage()->LoadResponseInfo(manifest_url_, group_->group_id(),
-                                        copy_me->response_id(),
-                                        this);
+  storage_->LoadResponseInfo(manifest_url_, group_->group_id(),
+                             copy_me->response_id(),
+                             this);
   // Async: wait for OnResponseInfoLoaded to complete.
   return true;
 }
@@ -1300,7 +1315,7 @@
   if (manifest_response_writer_)
     manifest_response_writer_.reset();
 
-  service_->storage()->CancelDelegateCallbacks(this);
+  storage_->CancelDelegateCallbacks(this);
 }
 
 void AppCacheUpdateJob::ClearPendingMasterEntries() {
@@ -1317,7 +1332,7 @@
 }
 
 void AppCacheUpdateJob::DiscardInprogressCache() {
-  service_->storage()->DoomResponses(manifest_url_, stored_response_ids_);
+  storage_->DoomResponses(manifest_url_, stored_response_ids_);
 
   if (!inprogress_cache_.get()) {
     // We have to undo the changes we made, if any, to the existing cache.
@@ -1337,13 +1352,15 @@
 }
 
 void AppCacheUpdateJob::DiscardDuplicateResponses() {
-  service_->storage()->DoomResponses(manifest_url_, duplicate_response_ids_);
+  storage_->DoomResponses(manifest_url_, duplicate_response_ids_);
 }
 
 void AppCacheUpdateJob::DeleteSoon() {
   ClearPendingMasterEntries();
   manifest_response_writer_.reset();
-  service_->storage()->CancelDelegateCallbacks(this);
+  storage_->CancelDelegateCallbacks(this);
+  service_->RemoveObserver(this);
+  service_ = NULL;
 
   // Break the connection with the group so the group cannot call delete
   // on this object after we've posted a task to delete ourselves.
diff --git a/webkit/browser/appcache/appcache_update_job.h b/webkit/browser/appcache/appcache_update_job.h
index 61b8827..ae631f0 100644
--- a/webkit/browser/appcache/appcache_update_job.h
+++ b/webkit/browser/appcache/appcache_update_job.h
@@ -20,6 +20,7 @@
 #include "webkit/browser/appcache/appcache.h"
 #include "webkit/browser/appcache/appcache_host.h"
 #include "webkit/browser/appcache/appcache_response.h"
+#include "webkit/browser/appcache/appcache_service.h"
 #include "webkit/browser/appcache/appcache_storage.h"
 #include "webkit/browser/webkit_storage_browser_export.h"
 #include "webkit/common/appcache/appcache_interfaces.h"
@@ -31,7 +32,8 @@
 // Application cache Update algorithm and state.
 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheUpdateJob
     : public AppCacheStorage::Delegate,
-      public AppCacheHost::Observer {
+      public AppCacheHost::Observer,
+      public AppCacheService::Observer {
  public:
   AppCacheUpdateJob(AppCacheService* service, AppCacheGroup* group);
   virtual ~AppCacheUpdateJob();
@@ -160,6 +162,10 @@
   virtual void OnCacheSelectionComplete(AppCacheHost* host) OVERRIDE {}  // N/A
   virtual void OnDestructionImminent(AppCacheHost* host) OVERRIDE;
 
+  // Methods for AppCacheService::Observer.
+  virtual void OnServiceReinitialized(
+      AppCacheStorageReference* old_storage) OVERRIDE;
+
   void HandleCacheFailure(const std::string& error_message);
 
   void FetchManifest(bool is_first_fetch);
@@ -300,6 +306,9 @@
   // Whether we've stored the resulting group/cache yet.
   StoredState stored_state_;
 
+  AppCacheStorage* storage_;
+  scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
+
   FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest, QueueUpdate);
 
   DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob);
diff --git a/webkit/browser/appcache/appcache_update_job_unittest.cc b/webkit/browser/appcache/appcache_update_job_unittest.cc
index a0416f9..3468758 100644
--- a/webkit/browser/appcache/appcache_update_job_unittest.cc
+++ b/webkit/browser/appcache/appcache_update_job_unittest.cc
@@ -3081,7 +3081,7 @@
     net::HttpResponseInfo* http_info = new net::HttpResponseInfo();
     http_info->headers = new net::HttpResponseHeaders(raw_headers);
     scoped_refptr<AppCacheResponseInfo> info(
-        new AppCacheResponseInfo(service_.get(), manifest_url,
+        new AppCacheResponseInfo(service_->storage(), manifest_url,
                                  response_id, http_info, 0));
     response_infos_.push_back(info);
     return info.get();
diff --git a/webkit/browser/appcache/appcache_url_request_job.cc b/webkit/browser/appcache/appcache_url_request_job.cc
index 077e09d..759d757 100644
--- a/webkit/browser/appcache/appcache_url_request_job.cc
+++ b/webkit/browser/appcache/appcache_url_request_job.cc
@@ -279,13 +279,15 @@
 
     NotifyHeadersComplete();
   } else {
-    // A resource that is expected to be in the appcache is missing.
-    // See http://code.google.com/p/chromium/issues/detail?id=50657
-    // Instead of failing the request, we restart the request. The retry
-    // attempt will fallthru to the network instead of trying to load
-    // from the appcache.
-    storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
-                                               entry_.response_id());
+    if (storage_->service()->storage() == storage_) {
+      // A resource that is expected to be in the appcache is missing.
+      // See http://code.google.com/p/chromium/issues/detail?id=50657
+      // Instead of failing the request, we restart the request. The retry
+      // attempt will fallthru to the network instead of trying to load
+      // from the appcache.
+      storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
+                                                 entry_.response_id());
+    }
     cache_entry_not_found_ = true;
     NotifyRestartRequired();
   }
@@ -343,8 +345,10 @@
   if (result == 0) {
     NotifyDone(net::URLRequestStatus());
   } else if (result < 0) {
-    storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
-                                               entry_.response_id());
+    if (storage_->service()->storage() == storage_) {
+      storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
+                                                 entry_.response_id());
+    }
     NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
   } else {
     SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
@@ -371,6 +375,10 @@
       storage_ = NULL;
     }
     host_ = NULL;
+    info_ = NULL;
+    cache_ = NULL;
+    group_ = NULL;
+    range_response_info_.reset();
     net::URLRequestJob::Kill();
     weak_factory_.InvalidateWeakPtrs();
   }
diff --git a/webkit/browser/appcache/view_appcache_internals_job.cc b/webkit/browser/appcache/view_appcache_internals_job.cc
index 0b68e99..8867b75 100644
--- a/webkit/browser/appcache/view_appcache_internals_job.cc
+++ b/webkit/browser/appcache/view_appcache_internals_job.cc
@@ -309,16 +309,31 @@
 }
 
 // Simple base class for the job subclasses defined here.
-class BaseInternalsJob : public net::URLRequestSimpleJob {
+class BaseInternalsJob : public net::URLRequestSimpleJob,
+                         public AppCacheService::Observer {
  protected:
   BaseInternalsJob(net::URLRequest* request,
                    net::NetworkDelegate* network_delegate,
                    AppCacheService* service)
       : URLRequestSimpleJob(request, network_delegate),
-        appcache_service_(service) {}
-  virtual ~BaseInternalsJob() {}
+        appcache_service_(service),
+        appcache_storage_(service->storage()) {
+    appcache_service_->AddObserver(this);
+  }
+
+  virtual ~BaseInternalsJob() {
+    appcache_service_->RemoveObserver(this);
+  }
+
+  virtual void OnServiceReinitialized(
+      AppCacheStorageReference* old_storage_ref) OVERRIDE {
+    if (old_storage_ref->storage() == appcache_storage_)
+      disabled_storage_reference_ = old_storage_ref;
+  }
 
   AppCacheService* appcache_service_;
+  AppCacheStorage* appcache_storage_;
+  scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
 };
 
 // Job that lists all appcaches in the system.
@@ -459,7 +474,7 @@
 
   virtual void Start() OVERRIDE {
     DCHECK(request_);
-    appcache_service_->storage()->LoadOrCreateGroup(manifest_url_, this);
+    appcache_storage_->LoadOrCreateGroup(manifest_url_, this);
   }
 
   // Produces a page containing the entries listing.
@@ -488,7 +503,7 @@
 
  private:
   virtual ~ViewAppCacheJob() {
-    appcache_service_->storage()->CancelDelegateCallbacks(this);
+    appcache_storage_->CancelDelegateCallbacks(this);
   }
 
   // AppCacheStorage::Delegate override
@@ -534,7 +549,7 @@
 
   virtual void Start() OVERRIDE {
     DCHECK(request_);
-    appcache_service_->storage()->LoadResponseInfo(
+    appcache_storage_->LoadResponseInfo(
         manifest_url_, group_id_, response_id_, this);
   }
 
@@ -573,7 +588,7 @@
 
  private:
   virtual ~ViewEntryJob() {
-    appcache_service_->storage()->CancelDelegateCallbacks(this);
+    appcache_storage_->CancelDelegateCallbacks(this);
   }
 
   virtual void OnResponseInfoLoaded(
@@ -590,7 +605,7 @@
         std::min(kLimit, response_info->response_data_size());
     response_data_ = new net::IOBuffer(amount_to_read);
 
-    reader_.reset(appcache_service_->storage()->CreateResponseReader(
+    reader_.reset(appcache_storage_->CreateResponseReader(
         manifest_url_, group_id_, response_id_));
     reader_->ReadData(
         response_data_.get(),
diff --git a/webkit/browser/blob/blob_storage_context.cc b/webkit/browser/blob/blob_storage_context.cc
index 84c5193..f62a26d 100644
--- a/webkit/browser/blob/blob_storage_context.cc
+++ b/webkit/browser/blob/blob_storage_context.cc
@@ -114,14 +114,6 @@
   public_blob_urls_.erase(blob_url);
 }
 
-std::string BlobStorageContext::LookupUuidFromDeprecatedURL(
-    const GURL& url) {
-  BlobURLMap::const_iterator found = deprecated_blob_urls_.find(url);
-  if (found == deprecated_blob_urls_.end())
-    return std::string();
-  return found->second;
-}
-
 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) {
   DCHECK(!IsInUse(uuid) && !uuid.empty());
   blob_map_[uuid] = BlobMapEntry(1, BEING_BUILT, new BlobData(uuid));
@@ -174,10 +166,7 @@
                                item.expected_modification_time());
       break;
     case BlobData::Item::TYPE_BLOB: {
-      scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(
-          item.blob_uuid().empty()
-          ? LookupUuidFromDeprecatedURL(item.blob_url())
-          : item.blob_uuid());
+      scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(item.blob_uuid());
       if (src)
         exceeded_memory = !ExpandStorageItems(target_blob_data,
                                               src->data(),
@@ -236,21 +225,6 @@
   }
 }
 
-void BlobStorageContext::DeprecatedRegisterPrivateBlobURL(
-    const GURL& url, const std::string& uuid) {
-  if (!IsInUse(uuid))
-    return;
-  IncrementBlobRefCount(uuid);
-  deprecated_blob_urls_[url] = uuid;
-}
-
-void BlobStorageContext::DeprecatedRevokePrivateBlobURL(const GURL& url) {
-  if (deprecated_blob_urls_.find(url) == deprecated_blob_urls_.end())
-    return;
-  DecrementBlobRefCount(deprecated_blob_urls_[url]);
-  deprecated_blob_urls_.erase(url);
-}
-
 bool BlobStorageContext::ExpandStorageItems(
     BlobData* target_blob_data, BlobData* src_blob_data,
     uint64 offset, uint64 length) {
diff --git a/webkit/browser/blob/blob_storage_context.h b/webkit/browser/blob/blob_storage_context.h
index ebe8450..619e283 100644
--- a/webkit/browser/blob/blob_storage_context.h
+++ b/webkit/browser/blob/blob_storage_context.h
@@ -47,9 +47,6 @@
   bool RegisterPublicBlobURL(const GURL& url, const std::string& uuid);
   void RevokePublicBlobURL(const GURL& url);
 
-  // Temporary support for mapping oldstyle blobUrls to new style uuids.
-  std::string LookupUuidFromDeprecatedURL(const GURL& url);
-
  private:
   friend class BlobDataHandle;
   friend class BlobStorageHost;
@@ -82,11 +79,6 @@
   void IncrementBlobRefCount(const std::string& uuid);
   void DecrementBlobRefCount(const std::string& uuid);
 
-  // Temporary support for mapping old style blobUrls to new style uuids.
-  void DeprecatedRegisterPrivateBlobURL(const GURL& url,
-                                        const std::string& uuid);
-  void DeprecatedRevokePrivateBlobURL(const GURL& url);
-
   bool ExpandStorageItems(BlobData* target_blob_data,
                           BlobData* src_blob_data,
                           uint64 offset,
@@ -108,7 +100,6 @@
 
   BlobMap blob_map_;
   BlobURLMap public_blob_urls_;
-  BlobURLMap deprecated_blob_urls_;
 
   // Used to keep track of how much memory is being utitlized for blob data,
   // we count only the items of TYPE_DATA which are held in memory and not
diff --git a/webkit/browser/blob/blob_storage_host.cc b/webkit/browser/blob/blob_storage_host.cc
index 9d3ddb9..c253a82 100644
--- a/webkit/browser/blob/blob_storage_host.cc
+++ b/webkit/browser/blob/blob_storage_host.cc
@@ -28,10 +28,6 @@
     for (int i = 0; i < iter->second; ++i)
       context_->DecrementBlobRefCount(iter->first);
   }
-  for (std::set<GURL>::iterator iter = private_blob_urls_.begin();
-       iter != private_blob_urls_.end(); ++iter) {
-    context_->DeprecatedRevokePrivateBlobURL(*iter);
-  }
 }
 
 bool BlobStorageHost::StartBuildingBlob(const std::string& uuid) {
@@ -103,56 +99,6 @@
   return true;
 }
 
-namespace {
-bool IsPrivateBlobURL(const GURL& url) {
-  return StartsWithASCII(url.spec(), "blob:blobinternal", true);
-}
-}
-
-void BlobStorageHost::DeprecatedRegisterBlobURL(
-    const GURL& private_url, const std::string& uuid) {
-  DCHECK(IsPrivateBlobURL(private_url));
-  if (!context_.get())
-    return;
-  context_->DeprecatedRegisterPrivateBlobURL(private_url, uuid);
-  private_blob_urls_.insert(private_url);
-}
-
-void BlobStorageHost::DeprecatedCloneBlobURL(
-    const GURL& url, const GURL& src_private_url) {
-  // This method is used in two ways.
-  // 1. During serialization/deserialization to 'clone' an existing blob.
-  //    In this case the src and dest urls are 'private' blob urls.
-  // 2. To register public blob urls. In this case the dest url is a
-  //    'public' blob url.
-  DCHECK(IsPrivateBlobURL(src_private_url));
-  if (!context_.get())
-    return;
-  std::string uuid = context_->LookupUuidFromDeprecatedURL(src_private_url);
-  if (uuid.empty())
-    return;
-  if (IsPrivateBlobURL(url)) {
-    DeprecatedRegisterBlobURL(url, uuid);
-  } else {
-    // Temporarily bump the refcount so the uuid passes the InUse
-    // check inside the RegisterPublicBlobURL method.
-    ignore_result(IncrementBlobRefCount(uuid));
-    ignore_result(RegisterPublicBlobURL(url, uuid));
-    ignore_result(DecrementBlobRefCount(uuid));
-  }
-}
-
-void BlobStorageHost::DeprecatedRevokeBlobURL(const GURL& url) {
-  if (!context_.get())
-    return;
-  if (IsPrivateBlobURL(url)) {
-    context_->DeprecatedRevokePrivateBlobURL(url);
-    private_blob_urls_.erase(url);
-  } else {
-    ignore_result(RevokePublicBlobURL(url));
-  }
-}
-
 bool BlobStorageHost::IsInUseInHost(const std::string& uuid) {
   return blobs_inuse_map_.find(uuid) != blobs_inuse_map_.end();
 }
diff --git a/webkit/browser/blob/blob_storage_host.h b/webkit/browser/blob/blob_storage_host.h
index 890db3a..5296ae1 100644
--- a/webkit/browser/blob/blob_storage_host.h
+++ b/webkit/browser/blob/blob_storage_host.h
@@ -47,13 +47,6 @@
                              const std::string& uuid) WARN_UNUSED_RESULT;
   bool RevokePublicBlobURL(const GURL& blob_url) WARN_UNUSED_RESULT;
 
-  // Temporary support for mapping old style private blob urls to uuids.
-  void DeprecatedRegisterBlobURL(const GURL& private_url,
-                                 const std::string& uuid);
-  void DeprecatedCloneBlobURL(const GURL& url,
-                              const GURL& src_private_url);
-  void DeprecatedRevokeBlobURL(const GURL& url);
-
  private:
   typedef std::map<std::string, int> BlobReferenceMap;
 
@@ -68,9 +61,6 @@
   // The set of public blob urls coined by this consumer.
   std::set<GURL> public_blob_urls_;
 
-  // And private deprecated blob urls.
-  std::set<GURL> private_blob_urls_;
-
   base::WeakPtr<BlobStorageContext> context_;
 
   DISALLOW_COPY_AND_ASSIGN(BlobStorageHost);
diff --git a/webkit/browser/blob/blob_url_request_job_factory.cc b/webkit/browser/blob/blob_url_request_job_factory.cc
index 6f4f70f..ed0a400 100644
--- a/webkit/browser/blob/blob_url_request_job_factory.cc
+++ b/webkit/browser/blob/blob_url_request_job_factory.cc
@@ -74,13 +74,6 @@
   if (!context_.get())
     return NULL;
 
-  // Retain support for looking up based on deprecated blob urls for now.
-  // The FeedbackExtensionAPI relies on this.
-  scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(
-      context_->LookupUuidFromDeprecatedURL(request->url()));
-  if (handle)
-    return handle->data();
-
   // Support looking up based on uuid, the FeedbackExtensionAPI relies on this.
   // TODO(michaeln): Replace this use case and others like it with a BlobReader
   // impl that does not depend on urlfetching to perform this function.
@@ -88,7 +81,7 @@
   if (!StartsWithASCII(request->url().spec(), kPrefix, true))
     return NULL;
   std::string uuid = request->url().spec().substr(kPrefix.length());
-  handle = context_->GetBlobDataFromUUID(uuid);
+  scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(uuid);
   return handle.get() ? handle->data() : NULL;
 }
 
diff --git a/webkit/browser/blob/view_blob_internals_job.cc b/webkit/browser/blob/view_blob_internals_job.cc
index e0523a4..fa9e82a 100644
--- a/webkit/browser/blob/view_blob_internals_job.cc
+++ b/webkit/browser/blob/view_blob_internals_job.cc
@@ -24,7 +24,6 @@
 namespace {
 
 const char kEmptyBlobStorageMessage[] = "No available blob data.";
-const char kRemove[] = "Remove";
 const char kContentType[] = "Content Type: ";
 const char kContentDisposition[] = "Content Disposition: ";
 const char kCount[] = "Count: ";
@@ -167,18 +166,6 @@
       EndHTMLList(out);
     }
   }
-  if (!blob_storage_context_->deprecated_blob_urls_.empty()) {
-    AddHorizontalRule(out);
-    for (BlobStorageContext::BlobURLMap::const_iterator iter =
-             blob_storage_context_->deprecated_blob_urls_.begin();
-         iter != blob_storage_context_->deprecated_blob_urls_.end();
-         ++iter) {
-      AddHTMLBoldText(iter->first.spec(), out);
-      StartHTMLList(out);
-      AddHTMLListItem(kUUID, iter->second, out);
-      EndHTMLList(out);
-    }
-  }
 }
 
 void ViewBlobInternalsJob::GenerateHTMLForBlobData(const BlobData& blob_data,
diff --git a/webkit/browser/database/database_tracker.cc b/webkit/browser/database/database_tracker.cc
index f9adb3b..19e3df8 100644
--- a/webkit/browser/database/database_tracker.cc
+++ b/webkit/browser/database/database_tracker.cc
@@ -786,7 +786,6 @@
 }
 
 void DatabaseTracker::DeleteIncognitoDBDirectory() {
-  shutting_down_ = true;
   is_initialized_ = false;
 
   for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
@@ -800,8 +799,6 @@
 }
 
 void DatabaseTracker::ClearSessionOnlyOrigins() {
-  shutting_down_ = true;
-
   bool has_session_only_databases =
       special_storage_policy_.get() &&
       special_storage_policy_->HasSessionOnlyOrigins();
@@ -852,10 +849,12 @@
     NOTREACHED();
     return;
   }
+  shutting_down_ = true;
   if (is_incognito_)
     DeleteIncognitoDBDirectory();
   else if (!force_keep_session_state_)
     ClearSessionOnlyOrigins();
+  CloseTrackerDatabaseAndClearCaches();
 }
 
 void DatabaseTracker::SetForceKeepSessionState() {
diff --git a/webkit/browser/fileapi/file_system_context.cc b/webkit/browser/fileapi/file_system_context.cc
index 3248d7c..14072ec 100644
--- a/webkit/browser/fileapi/file_system_context.cc
+++ b/webkit/browser/fileapi/file_system_context.cc
@@ -125,6 +125,11 @@
       sandbox_backend_(new SandboxFileSystemBackend(
           sandbox_delegate_.get())),
       isolated_backend_(new IsolatedFileSystemBackend()),
+      plugin_private_backend_(new PluginPrivateFileSystemBackend(
+          file_task_runner,
+          partition_path,
+          special_storage_policy,
+          options)),
       additional_backends_(additional_backends.Pass()),
       external_mount_points_(external_mount_points),
       partition_path_(partition_path),
@@ -132,6 +137,7 @@
       operation_runner_(new FileSystemOperationRunner(this)) {
   RegisterBackend(sandbox_backend_.get());
   RegisterBackend(isolated_backend_.get());
+  RegisterBackend(plugin_private_backend_.get());
 
   for (ScopedVector<FileSystemBackend>::const_iterator iter =
           additional_backends_.begin();
@@ -147,6 +153,7 @@
 
   sandbox_backend_->Initialize(this);
   isolated_backend_->Initialize(this);
+  plugin_private_backend_->Initialize(this);
   for (ScopedVector<FileSystemBackend>::const_iterator iter =
           additional_backends_.begin();
        iter != additional_backends_.end(); ++iter) {
@@ -404,6 +411,9 @@
 #endif
 
 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const {
+  // We never support accessing files in isolated filesystems via an URL.
+  if (url.mount_type() == kFileSystemTypeIsolated)
+    return false;
 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
   if (url.type() == kFileSystemTypeTemporary &&
       sandbox_backend_->enable_temporary_file_system_in_incognito()) {
@@ -413,6 +423,17 @@
   return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type());
 }
 
+void FileSystemContext::OpenPluginPrivateFileSystem(
+    const GURL& origin_url,
+    FileSystemType type,
+    const std::string& plugin_id,
+    OpenFileSystemMode mode,
+    const OpenPluginPrivateFileSystemCallback& callback) {
+  DCHECK(plugin_private_backend_);
+  plugin_private_backend_->OpenPrivateFileSystem(
+      origin_url, type, plugin_id, mode, callback);
+}
+
 FileSystemContext::~FileSystemContext() {
 }
 
diff --git a/webkit/browser/fileapi/file_system_context.h b/webkit/browser/fileapi/file_system_context.h
index 765af0f..7d781ed 100644
--- a/webkit/browser/fileapi/file_system_context.h
+++ b/webkit/browser/fileapi/file_system_context.h
@@ -17,6 +17,7 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/open_file_system_mode.h"
+#include "webkit/browser/fileapi/plugin_private_file_system_backend.h"
 #include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
 #include "webkit/browser/webkit_storage_browser_export.h"
@@ -166,6 +167,12 @@
   typedef base::Callback<void(base::PlatformFileError result)>
       DeleteFileSystemCallback;
 
+  // Used for OpenPluginPrivateFileSystem.
+  typedef base::Callback<void(const GURL& root,
+                              const std::string& filesystem_id,
+                              base::PlatformFileError result)>
+      OpenPluginPrivateFileSystemCallback;
+
   // Opens the filesystem for the given |origin_url| and |type|, and dispatches
   // |callback| on completion.
   // If |create| is true this may actually set up a filesystem instance
@@ -246,6 +253,15 @@
   // (E.g. this returns false if the context is created for incognito mode)
   bool CanServeURLRequest(const FileSystemURL& url) const;
 
+  // This must be used to open 'plugin private' filesystem.
+  // See "plugin_private_file_system_backend.h" for more details.
+  void OpenPluginPrivateFileSystem(
+      const GURL& origin_url,
+      FileSystemType type,
+      const std::string& plugin_id,
+      OpenFileSystemMode mode,
+      const OpenPluginPrivateFileSystemCallback& callback);
+
  private:
   typedef std::map<FileSystemType, FileSystemBackend*>
       FileSystemBackendMap;
@@ -256,6 +272,9 @@
   // For sandbox_backend().
   friend class SandboxFileSystemTestHelper;
 
+  // For plugin_private_backend().
+  friend class PluginPrivateFileSystemBackendTest;
+
   // Deleters.
   friend struct DefaultContextDeleter;
   friend class base::DeleteHelper<FileSystemContext>;
@@ -301,6 +320,11 @@
     return sandbox_backend_.get();
   }
 
+  // Used only by test code.
+  PluginPrivateFileSystemBackend* plugin_private_backend() const {
+    return plugin_private_backend_.get();
+  }
+
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   scoped_refptr<base::SequencedTaskRunner> default_file_task_runner_;
 
@@ -313,6 +337,7 @@
   scoped_ptr<IsolatedFileSystemBackend> isolated_backend_;
 
   // Additional file system backends.
+  scoped_ptr<PluginPrivateFileSystemBackend> plugin_private_backend_;
   ScopedVector<FileSystemBackend> additional_backends_;
 
   // Registered file system backends.
diff --git a/webkit/browser/fileapi/file_system_operation_runner.cc b/webkit/browser/fileapi/file_system_operation_runner.cc
index 5e45be5..8903187 100644
--- a/webkit/browser/fileapi/file_system_operation_runner.cc
+++ b/webkit/browser/fileapi/file_system_operation_runner.cc
@@ -494,9 +494,9 @@
     const FileSystemURL& url,
     base::FilePath* platform_path) {
   base::PlatformFileError error = base::PLATFORM_FILE_OK;
-  FileSystemOperation* operation =
-      file_system_context_->CreateFileSystemOperation(url, &error);
-  if (!operation)
+  scoped_ptr<FileSystemOperation> operation(
+      file_system_context_->CreateFileSystemOperation(url, &error));
+  if (!operation.get())
     return error;
   return operation->SyncGetPlatformPath(url, platform_path);
 }
diff --git a/webkit/browser/fileapi/local_file_stream_writer.cc b/webkit/browser/fileapi/local_file_stream_writer.cc
index 75c2cad..1796de5 100644
--- a/webkit/browser/fileapi/local_file_stream_writer.cc
+++ b/webkit/browser/fileapi/local_file_stream_writer.cc
@@ -84,9 +84,9 @@
                                              int64 initial_offset)
     : file_path_(file_path),
       initial_offset_(initial_offset),
+      task_runner_(task_runner),
       has_pending_operation_(false),
-      weak_factory_(this),
-      task_runner_(task_runner) {}
+      weak_factory_(this) {}
 
 int LocalFileStreamWriter::InitiateOpen(
     const net::CompletionCallback& error_callback,
diff --git a/webkit/browser/fileapi/native_file_util.cc b/webkit/browser/fileapi/native_file_util.cc
index eec9670..df290c5 100644
--- a/webkit/browser/fileapi/native_file_util.cc
+++ b/webkit/browser/fileapi/native_file_util.cc
@@ -140,8 +140,12 @@
   if (!file_util::CreateDirectory(path))
     return base::PLATFORM_FILE_ERROR_FAILED;
 
-  if (!SetPlatformSpecificDirectoryPermissions(path))
-    return base::PLATFORM_FILE_ERROR_FAILED;
+  if (!SetPlatformSpecificDirectoryPermissions(path)) {
+    // Since some file systems don't support permission setting, we do not treat
+    // an error from the function as the failure of copying. Just log it.
+    LOG(WARNING) << "Setting directory permission failed: "
+        << path.AsUTF8Unsafe();
+  }
 
   return base::PLATFORM_FILE_OK;
 }
diff --git a/webkit/browser/fileapi/obfuscated_file_util.cc b/webkit/browser/fileapi/obfuscated_file_util.cc
index a87db0e..46d733d 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.cc
+++ b/webkit/browser/fileapi/obfuscated_file_util.cc
@@ -28,6 +28,7 @@
 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
 #include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
 #include "webkit/browser/fileapi/sandbox_origin_database.h"
+#include "webkit/browser/fileapi/sandbox_prioritized_origin_database.h"
 #include "webkit/browser/fileapi/timed_task_helper.h"
 #include "webkit/browser/quota/quota_manager.h"
 #include "webkit/common/database/database_identifier.h"
@@ -256,13 +257,15 @@
     const base::FilePath& file_system_directory,
     base::SequencedTaskRunner* file_task_runner,
     const GetTypeStringForURLCallback& get_type_string_for_url,
-    const std::set<std::string>& known_type_strings)
+    const std::set<std::string>& known_type_strings,
+    SandboxFileSystemBackendDelegate* sandbox_delegate)
     : special_storage_policy_(special_storage_policy),
       file_system_directory_(file_system_directory),
       db_flush_delay_seconds_(10 * 60),  // 10 mins.
       file_task_runner_(file_task_runner),
       get_type_string_for_url_(get_type_string_for_url),
-      known_type_strings_(known_type_strings) {
+      known_type_strings_(known_type_strings),
+      sandbox_delegate_(sandbox_delegate) {
 }
 
 ObfuscatedFileUtil::~ObfuscatedFileUtil() {
@@ -277,10 +280,10 @@
                                                  file_handle, created);
   if (*file_handle != base::kInvalidPlatformFileValue &&
       file_flags & base::PLATFORM_FILE_WRITE &&
-      context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited) {
+      context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited &&
+      sandbox_delegate_) {
     DCHECK_EQ(base::PLATFORM_FILE_OK, error);
-    context->file_system_context()->sandbox_delegate()->
-        StickyInvalidateUsageCache(url.origin(), url.type());
+    sandbox_delegate_->StickyInvalidateUsageCache(url.origin(), url.type());
   }
   return error;
 }
@@ -899,7 +902,7 @@
   }
 
   // No other directories seem exist. Try deleting the entire origin directory.
-  InitOriginDatabase(false);
+  InitOriginDatabase(origin, false);
   if (origin_database_) {
     origin_database_->RemovePathForOrigin(
         webkit_database::GetIdentifierFromOrigin(origin));
@@ -914,7 +917,7 @@
 ObfuscatedFileUtil::CreateOriginEnumerator() {
   std::vector<SandboxOriginDatabase::OriginRecord> origins;
 
-  InitOriginDatabase(false);
+  InitOriginDatabase(GURL(), false);
   return new ObfuscatedOriginEnumerator(
       origin_database_.get(), file_system_directory_);
 }
@@ -945,6 +948,37 @@
   return UsageForPath(VirtualPath::BaseName(path).value().size());
 }
 
+void ObfuscatedFileUtil::MaybePrepopulateDatabase(
+    const std::vector<std::string>& type_strings_to_prepopulate) {
+  SandboxPrioritizedOriginDatabase database(file_system_directory_);
+  std::string origin_string = database.GetPrimaryOrigin();
+  if (origin_string.empty() || !database.HasOriginPath(origin_string))
+    return;
+  const GURL origin = webkit_database::GetOriginFromIdentifier(origin_string);
+
+  // Prepopulate the directory database(s) if and only if this instance
+  // has primary origin and the directory database is already there.
+  for (size_t i = 0; i < type_strings_to_prepopulate.size(); ++i) {
+    const std::string type_string = type_strings_to_prepopulate[i];
+    // Only handles known types.
+    if (!ContainsKey(known_type_strings_, type_string))
+      continue;
+    PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
+    base::FilePath path = GetDirectoryForOriginAndType(
+        origin, type_string, false, &error);
+    if (error != base::PLATFORM_FILE_OK)
+      continue;
+    scoped_ptr<SandboxDirectoryDatabase> db(new SandboxDirectoryDatabase(path));
+    if (db->Init(SandboxDirectoryDatabase::FAIL_ON_CORRUPTION)) {
+      directories_[GetDirectoryDatabaseKey(origin, type_string)] = db.release();
+      MarkUsed();
+      // Don't populate more than one database, as it may rather hurt
+      // performance.
+      break;
+    }
+  }
+}
+
 base::FilePath ObfuscatedFileUtil::GetDirectoryForURL(
     const FileSystemURL& url,
     bool create,
@@ -1104,10 +1138,6 @@
     return std::string();
   }
   // For isolated origin we just use a type string as a key.
-  if (HasIsolatedStorage(origin)) {
-    CHECK_EQ(isolated_origin_.spec(), origin.spec());
-    return type_string;
-  }
   return webkit_database::GetIdentifierFromOrigin(origin) +
       type_string;
 }
@@ -1143,11 +1173,7 @@
 
 base::FilePath ObfuscatedFileUtil::GetDirectoryForOrigin(
     const GURL& origin, bool create, base::PlatformFileError* error_code) {
-  if (HasIsolatedStorage(origin)) {
-    CHECK_EQ(isolated_origin_.spec(), origin.spec());
-  }
-
-  if (!InitOriginDatabase(create)) {
+  if (!InitOriginDatabase(origin, create)) {
     if (error_code) {
       *error_code = create ?
           base::PLATFORM_FILE_ERROR_FAILED :
@@ -1201,8 +1227,8 @@
     FileSystemOperationContext* context,
     const GURL& origin,
     FileSystemType type) {
-  context->file_system_context()->sandbox_delegate()->
-      InvalidateUsageCache(origin, type);
+  if (sandbox_delegate_)
+    sandbox_delegate_->InvalidateUsageCache(origin, type);
 }
 
 void ObfuscatedFileUtil::MarkUsed() {
@@ -1227,7 +1253,8 @@
   timer_.reset();
 }
 
-bool ObfuscatedFileUtil::InitOriginDatabase(bool create) {
+bool ObfuscatedFileUtil::InitOriginDatabase(const GURL& origin_hint,
+                                            bool create) {
   if (origin_database_)
     return true;
 
@@ -1239,19 +1266,30 @@
     return false;
   }
 
-  origin_database_.reset(
-      new SandboxOriginDatabase(file_system_directory_));
+  SandboxPrioritizedOriginDatabase* prioritized_origin_database =
+      new SandboxPrioritizedOriginDatabase(file_system_directory_);
+  origin_database_.reset(prioritized_origin_database);
 
+  if (origin_hint.is_empty() || !HasIsolatedStorage(origin_hint))
+    return true;
+
+  const std::string isolated_origin_string =
+      webkit_database::GetIdentifierFromOrigin(origin_hint);
+
+  // TODO(kinuko): Deprecate this after a few release cycles, e.g. around M33.
   base::FilePath isolated_origin_dir = file_system_directory_.Append(
-      SandboxIsolatedOriginDatabase::kOriginDirectory);
+      SandboxIsolatedOriginDatabase::kObsoleteOriginDirectory);
   if (base::DirectoryExists(isolated_origin_dir) &&
-      !isolated_origin_.is_empty()) {
-    SandboxIsolatedOriginDatabase::MigrateBackDatabase(
-        webkit_database::GetIdentifierFromOrigin(isolated_origin_),
+      prioritized_origin_database->GetSandboxOriginDatabase()) {
+    SandboxIsolatedOriginDatabase::MigrateBackFromObsoleteOriginDatabase(
+        isolated_origin_string,
         file_system_directory_,
-        static_cast<SandboxOriginDatabase*>(origin_database_.get()));
+        prioritized_origin_database->GetSandboxOriginDatabase());
   }
 
+  prioritized_origin_database->InitializePrimaryOrigin(
+      isolated_origin_string);
+
   return true;
 }
 
@@ -1365,24 +1403,8 @@
 }
 
 bool ObfuscatedFileUtil::HasIsolatedStorage(const GURL& origin) {
-  if (special_storage_policy_.get() &&
-      special_storage_policy_->HasIsolatedStorage(origin)) {
-    if (isolated_origin_.is_empty())
-      isolated_origin_ = origin;
-    // Record isolated_origin_, but always disable for now.
-    // crbug.com/264429
-    if (isolated_origin_ != origin) {
-      UMA_HISTOGRAM_ENUMERATION("FileSystem.IsolatedOriginStatus",
-                                kIsolatedOriginDontMatch,
-                                kIsolatedOriginStatusMax);
-    } else {
-      UMA_HISTOGRAM_ENUMERATION("FileSystem.IsolatedOriginStatus",
-                                kIsolatedOriginMatch,
-                                kIsolatedOriginStatusMax);
-    }
-    return false;
-  }
-  return false;
+  return special_storage_policy_.get() &&
+      special_storage_policy_->HasIsolatedStorage(origin);
 }
 
 }  // namespace fileapi
diff --git a/webkit/browser/fileapi/obfuscated_file_util.h b/webkit/browser/fileapi/obfuscated_file_util.h
index c5ce737..e25a99e 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.h
+++ b/webkit/browser/fileapi/obfuscated_file_util.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
@@ -18,6 +19,7 @@
 #include "webkit/browser/fileapi/file_system_file_util.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/sandbox_directory_database.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/browser/webkit_storage_browser_export.h"
 #include "webkit/common/blob/shareable_file_reference.h"
 #include "webkit/common/fileapi/file_system_types.h"
@@ -99,7 +101,8 @@
       const base::FilePath& file_system_directory,
       base::SequencedTaskRunner* file_task_runner,
       const GetTypeStringForURLCallback& get_type_string_for_url,
-      const std::set<std::string>& known_type_strings);
+      const std::set<std::string>& known_type_strings,
+      SandboxFileSystemBackendDelegate* sandbox_delegate);
   virtual ~ObfuscatedFileUtil();
 
   // FileSystemFileUtil overrides.
@@ -214,6 +217,13 @@
   // on each path segment and add the results.
   static int64 ComputeFilePathCost(const base::FilePath& path);
 
+  // Tries to prepopulate directory database for the given type strings.
+  // This tries from the first one in the given type_strings and stops
+  // once it succeeds to do so for one database (i.e. it prepopulates
+  // at most one database).
+  void MaybePrepopulateDatabase(
+      const std::vector<std::string>& type_strings_to_prepopulate);
+
  private:
   typedef SandboxDirectoryDatabase::FileId FileId;
   typedef SandboxDirectoryDatabase::FileInfo FileInfo;
@@ -302,7 +312,10 @@
 
   void MarkUsed();
   void DropDatabases();
-  bool InitOriginDatabase(bool create);
+
+  // Initializes the origin database. |origin_hint| may be used as a hint
+  // for initializing database if it's not empty.
+  bool InitOriginDatabase(const GURL& origin_hint, bool create);
 
   base::PlatformFileError GenerateNewLocalPath(
       SandboxDirectoryDatabase* db,
@@ -334,9 +347,8 @@
   GetTypeStringForURLCallback get_type_string_for_url_;
   std::set<std::string> known_type_strings_;
 
-  // If this instance is initialized for an isolated partition, this should
-  // only see a single origin.
-  GURL isolated_origin_;
+  // Not owned.
+  SandboxFileSystemBackendDelegate* sandbox_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtil);
 };
diff --git a/webkit/browser/fileapi/plugin_private_file_system_backend.cc b/webkit/browser/fileapi/plugin_private_file_system_backend.cc
index e7b6214..244aac4 100644
--- a/webkit/browser/fileapi/plugin_private_file_system_backend.cc
+++ b/webkit/browser/fileapi/plugin_private_file_system_backend.cc
@@ -103,7 +103,8 @@
           file_task_runner,
           base::Bind(&FileSystemIDToPluginMap::GetPluginIDForURL,
                      base::Owned(plugin_map_)),
-          std::set<std::string>())));
+          std::set<std::string>(),
+          NULL)));
 }
 
 PluginPrivateFileSystemBackend::~PluginPrivateFileSystemBackend() {
@@ -119,7 +120,7 @@
     FileSystemType type,
     const std::string& plugin_id,
     OpenFileSystemMode mode,
-    const OpenFileSystemCallback& callback) {
+    const OpenPrivateFileSystemCallback& callback) {
   if (!CanHandleType(type) || file_system_options_.is_incognito()) {
     base::MessageLoopProxy::current()->PostTask(
         FROM_HERE, base::Bind(callback, GURL(), std::string(),
@@ -142,7 +143,7 @@
       base::Bind(callback,
                  GURL(GetIsolatedFileSystemRootURIString(
                      origin_url, filesystem_id, name)),
-                 GetIsolatedFileSystemName(origin_url, filesystem_id)));
+                 filesystem_id));
 }
 
 bool PluginPrivateFileSystemBackend::CanHandleType(FileSystemType type) const {
diff --git a/webkit/browser/fileapi/plugin_private_file_system_backend.h b/webkit/browser/fileapi/plugin_private_file_system_backend.h
index b94d13a..a12e4c3 100644
--- a/webkit/browser/fileapi/plugin_private_file_system_backend.h
+++ b/webkit/browser/fileapi/plugin_private_file_system_backend.h
@@ -31,6 +31,10 @@
       public FileSystemQuotaUtil {
  public:
   class FileSystemIDToPluginMap;
+  typedef base::Callback<void(const GURL& root,
+                              const std::string& filesystem_id,
+                              base::PlatformFileError result)>
+      OpenPrivateFileSystemCallback;
 
   PluginPrivateFileSystemBackend(
       base::SequencedTaskRunner* file_task_runner,
@@ -50,7 +54,7 @@
       FileSystemType type,
       const std::string& plugin_id,
       OpenFileSystemMode mode,
-      const OpenFileSystemCallback& callback);
+      const OpenPrivateFileSystemCallback& callback);
 
   // FileSystemBackend overrides.
   virtual bool CanHandleType(FileSystemType type) const OVERRIDE;
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc
index 754c3b4..593e1a0 100644
--- a/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc
+++ b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -43,6 +43,11 @@
 const char kPersistentDirectoryName[] = "p";
 const char kSyncableDirectoryName[] = "s";
 
+const char* kPrepopulateTypes[] = {
+  kPersistentDirectoryName,
+  kTemporaryDirectoryName
+};
+
 enum FileSystemError {
   kOK = 0,
   kIncognito,
@@ -129,6 +134,12 @@
   callback.Run(*error);
 }
 
+template <typename T>
+void DeleteSoon(base::SequencedTaskRunner* runner, T* ptr) {
+  if (!runner->DeleteSoon(FROM_HERE, ptr))
+    delete ptr;
+}
+
 }  // namespace
 
 const base::FilePath::CharType
@@ -166,7 +177,8 @@
               profile_path.Append(kFileSystemDirectory),
               file_task_runner,
               base::Bind(&GetTypeStringForURL),
-              GetKnownTypeStrings()))),
+              GetKnownTypeStrings(),
+              this))),
       file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
       quota_observer_(new SandboxQuotaObserver(
           quota_manager_proxy,
@@ -177,21 +189,28 @@
       file_system_options_(file_system_options),
       is_filesystem_opened_(false),
       weak_factory_(this) {
+  // Prepopulate database only if it can run asynchronously (i.e. the current
+  // thread is not file_task_runner). Usually this is the case but may not
+  // in test code.
+  if (!file_task_runner_->RunsTasksOnCurrentThread()) {
+    std::vector<std::string> types_to_prepopulate(
+        &kPrepopulateTypes[0],
+        &kPrepopulateTypes[arraysize(kPrepopulateTypes)]);
+    file_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase,
+                  base::Unretained(obfuscated_file_util()),
+                  types_to_prepopulate));
+  }
 }
 
 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
   io_thread_checker_.DetachFromThread();
+
   if (!file_task_runner_->RunsTasksOnCurrentThread()) {
-    AsyncFileUtil* sandbox_file_util = sandbox_file_util_.release();
-    SandboxQuotaObserver* quota_observer = quota_observer_.release();
-    FileSystemUsageCache* file_system_usage_cache =
-        file_system_usage_cache_.release();
-    if (!file_task_runner_->DeleteSoon(FROM_HERE, sandbox_file_util))
-      delete sandbox_file_util;
-    if (!file_task_runner_->DeleteSoon(FROM_HERE, quota_observer))
-      delete quota_observer;
-    if (!file_task_runner_->DeleteSoon(FROM_HERE, file_system_usage_cache))
-      delete file_system_usage_cache;
+    DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release());
+    DeleteSoon(file_task_runner_.get(), quota_observer_.release());
+    DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release());
   }
 }
 
@@ -620,7 +639,8 @@
                                 file_system_directory,
                                 file_task_runner,
                                 base::Bind(&GetTypeStringForURL),
-                                GetKnownTypeStrings());
+                                GetKnownTypeStrings(),
+                                NULL);
 }
 
 }  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_isolated_origin_database.cc b/webkit/browser/fileapi/sandbox_isolated_origin_database.cc
index 7ed4e8c..901c4fd 100644
--- a/webkit/browser/fileapi/sandbox_isolated_origin_database.cc
+++ b/webkit/browser/fileapi/sandbox_isolated_origin_database.cc
@@ -12,14 +12,17 @@
 
 // Special directory name for isolated origin.
 const base::FilePath::CharType
-SandboxIsolatedOriginDatabase::kOriginDirectory[] = FILE_PATH_LITERAL("iso");
+SandboxIsolatedOriginDatabase::kObsoleteOriginDirectory[] =
+    FILE_PATH_LITERAL("iso");
 
 SandboxIsolatedOriginDatabase::SandboxIsolatedOriginDatabase(
     const std::string& origin,
-    const base::FilePath& file_system_directory)
+    const base::FilePath& file_system_directory,
+    const base::FilePath& origin_directory)
     : migration_checked_(false),
       origin_(origin),
-      file_system_directory_(file_system_directory) {
+      file_system_directory_(file_system_directory),
+      origin_directory_(origin_directory) {
 }
 
 SandboxIsolatedOriginDatabase::~SandboxIsolatedOriginDatabase() {
@@ -27,16 +30,14 @@
 
 bool SandboxIsolatedOriginDatabase::HasOriginPath(
     const std::string& origin) {
-  MigrateDatabaseIfNeeded();
   return (origin_ == origin);
 }
 
 bool SandboxIsolatedOriginDatabase::GetPathForOrigin(
     const std::string& origin, base::FilePath* directory) {
-  MigrateDatabaseIfNeeded();
   if (origin != origin_)
     return false;
-  *directory = base::FilePath(kOriginDirectory);
+  *directory = origin_directory_;
   return true;
 }
 
@@ -47,20 +48,19 @@
 
 bool SandboxIsolatedOriginDatabase::ListAllOrigins(
     std::vector<OriginRecord>* origins) {
-  MigrateDatabaseIfNeeded();
-  origins->push_back(OriginRecord(origin_, base::FilePath(kOriginDirectory)));
+  origins->push_back(OriginRecord(origin_, origin_directory_));
   return true;
 }
 
 void SandboxIsolatedOriginDatabase::DropDatabase() {
 }
 
-void SandboxIsolatedOriginDatabase::MigrateBackDatabase(
+void SandboxIsolatedOriginDatabase::MigrateBackFromObsoleteOriginDatabase(
     const std::string& origin,
     const base::FilePath& file_system_directory,
     SandboxOriginDatabase* database) {
   base::FilePath isolated_directory =
-      file_system_directory.Append(kOriginDirectory);
+      file_system_directory.Append(kObsoleteOriginDirectory);
 
   if (database->HasOriginPath(origin)) {
     // Don't bother.
@@ -77,29 +77,4 @@
   }
 }
 
-void SandboxIsolatedOriginDatabase::MigrateDatabaseIfNeeded() {
-  if (migration_checked_)
-    return;
-
-  migration_checked_ = true;
-  // See if we have non-isolated version of sandbox database.
-  scoped_ptr<SandboxOriginDatabase> database(
-      new SandboxOriginDatabase(file_system_directory_));
-  if (!database->HasOriginPath(origin_))
-    return;
-
-  base::FilePath directory_name;
-  if (database->GetPathForOrigin(origin_, &directory_name) &&
-      directory_name != base::FilePath(kOriginDirectory)) {
-    base::FilePath from_path = file_system_directory_.Append(directory_name);
-    base::FilePath to_path = file_system_directory_.Append(kOriginDirectory);
-
-    if (base::PathExists(to_path))
-      base::DeleteFile(to_path, true /* recursive */);
-    base::Move(from_path, to_path);
-  }
-
-  database->RemoveDatabase();
-}
-
 }  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_isolated_origin_database.h b/webkit/browser/fileapi/sandbox_isolated_origin_database.h
index 3d0de56..d3a882a 100644
--- a/webkit/browser/fileapi/sandbox_isolated_origin_database.h
+++ b/webkit/browser/fileapi/sandbox_isolated_origin_database.h
@@ -14,14 +14,19 @@
 
 class SandboxOriginDatabase;
 
+// This origin database implementation supports only one origin
+// (therefore is expected to run very fast).
 class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE SandboxIsolatedOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
-  static const base::FilePath::CharType kOriginDirectory[];
+  static const base::FilePath::CharType kObsoleteOriginDirectory[];
 
-  explicit SandboxIsolatedOriginDatabase(
+  // Initialize this database for |origin| which makes GetPathForOrigin return
+  // |origin_directory| (in |file_system_directory|).
+  SandboxIsolatedOriginDatabase(
       const std::string& origin,
-      const base::FilePath& file_system_directory);
+      const base::FilePath& file_system_directory,
+      const base::FilePath& origin_directory);
   virtual ~SandboxIsolatedOriginDatabase();
 
   // SandboxOriginDatabaseInterface overrides.
@@ -32,17 +37,21 @@
   virtual bool ListAllOrigins(std::vector<OriginRecord>* origins) OVERRIDE;
   virtual void DropDatabase() OVERRIDE;
 
-  static void MigrateBackDatabase(
+  // TODO(kinuko): Deprecate this after a few release cycles, e.g. around M33.
+  static void MigrateBackFromObsoleteOriginDatabase(
       const std::string& origin,
       const base::FilePath& file_system_directory,
       SandboxOriginDatabase* origin_database);
 
+  const std::string& origin() const { return origin_; }
+
  private:
   void MigrateDatabaseIfNeeded();
 
   bool migration_checked_;
   const std::string origin_;
   const base::FilePath file_system_directory_;
+  const base::FilePath origin_directory_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxIsolatedOriginDatabase);
 };
diff --git a/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc b/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
index aad2c7e..047a961 100644
--- a/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
+++ b/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
@@ -11,12 +11,17 @@
 
 namespace fileapi {
 
+namespace {
+const base::FilePath::CharType kOriginDirectory[] = FILE_PATH_LITERAL("iso");
+}  // namespace
+
 TEST(SandboxIsolatedOriginDatabaseTest, BasicTest) {
   base::ScopedTempDir dir;
   ASSERT_TRUE(dir.CreateUniqueTempDir());
 
   std::string kOrigin("origin");
-  SandboxIsolatedOriginDatabase database(kOrigin, dir.path());
+  SandboxIsolatedOriginDatabase database(kOrigin, dir.path(),
+                                         base::FilePath(kOriginDirectory));
 
   EXPECT_TRUE(database.HasOriginPath(kOrigin));
 
@@ -33,55 +38,4 @@
   EXPECT_EQ(path1, path2);
 }
 
-TEST(SandboxIsolatedOriginDatabaseTest, MigrationTest) {
-  base::ScopedTempDir dir;
-  ASSERT_TRUE(dir.CreateUniqueTempDir());
-
-  std::string kOrigin("origin");
-  std::string kFakeDirectoryData("0123456789");
-  base::FilePath path;
-  base::FilePath old_db_path;
-
-  // Initialize the directory with one origin using the regular
-  // SandboxOriginDatabase.
-  {
-    SandboxOriginDatabase database_old(dir.path());
-    old_db_path = database_old.GetDatabasePath();
-    EXPECT_FALSE(base::PathExists(old_db_path));
-    EXPECT_TRUE(database_old.GetPathForOrigin(kOrigin, &path));
-    EXPECT_FALSE(path.empty());
-    EXPECT_TRUE(base::DirectoryExists(old_db_path));
-
-    // Populate the origin directory with some fake data.
-    base::FilePath directory_db_path = dir.path().Append(path);
-    ASSERT_TRUE(file_util::CreateDirectory(directory_db_path));
-    EXPECT_EQ(static_cast<int>(kFakeDirectoryData.size()),
-              file_util::WriteFile(directory_db_path.AppendASCII("dummy"),
-                                   kFakeDirectoryData.data(),
-                                   kFakeDirectoryData.size()));
-  }
-
-  // Re-open the directory using sandboxIsolatedOriginDatabase.
-  SandboxIsolatedOriginDatabase database(kOrigin, dir.path());
-
-  // The database is migrated from the old one, so we should still
-  // see the same origin.
-  EXPECT_TRUE(database.HasOriginPath(kOrigin));
-  EXPECT_TRUE(database.GetPathForOrigin(kOrigin, &path));
-  EXPECT_FALSE(path.empty());
-
-  // The directory content must be kept (or migrated if necessary),
-  // so we should see the same fake data.
-  std::string origin_db_data;
-  base::FilePath directory_db_path = dir.path().Append(path);
-  EXPECT_TRUE(base::DirectoryExists(directory_db_path));
-  EXPECT_TRUE(base::PathExists(directory_db_path.AppendASCII("dummy")));
-  EXPECT_TRUE(base::ReadFileToString(
-      directory_db_path.AppendASCII("dummy"), &origin_db_data));
-  EXPECT_EQ(kFakeDirectoryData, origin_db_data);
-
-  // After the migration the database must be gone.
-  EXPECT_FALSE(base::PathExists(old_db_path));
-}
-
 }  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_prioritized_origin_database.cc b/webkit/browser/fileapi/sandbox_prioritized_origin_database.cc
new file mode 100644
index 0000000..06a44a0
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_prioritized_origin_database.cc
@@ -0,0 +1,229 @@
+// Copyright 2013 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 "webkit/browser/fileapi/sandbox_prioritized_origin_database.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_platform_file_closer.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/platform_file.h"
+#include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
+#include "webkit/browser/fileapi/sandbox_origin_database.h"
+
+namespace fileapi {
+
+namespace {
+
+const base::FilePath::CharType kPrimaryDirectory[] =
+    FILE_PATH_LITERAL("primary");
+const base::FilePath::CharType kPrimaryOriginFile[] =
+    FILE_PATH_LITERAL("primary.origin");
+
+bool WritePrimaryOriginFile(const base::FilePath& path,
+                            const std::string& origin) {
+  base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
+  bool created;
+  base::PlatformFile file = base::CreatePlatformFile(
+      path,
+      base::PLATFORM_FILE_OPEN_ALWAYS |
+      base::PLATFORM_FILE_WRITE,
+      &created, &error);
+  base::ScopedPlatformFileCloser closer(&file);
+  if (error != base::PLATFORM_FILE_OK ||
+      file == base::kInvalidPlatformFileValue)
+    return false;
+  base::TruncatePlatformFile(file, 0);
+  Pickle pickle;
+  pickle.WriteString(origin);
+  base::WritePlatformFile(file, 0, static_cast<const char*>(pickle.data()),
+                          pickle.size());
+  base::FlushPlatformFile(file);
+  return true;
+}
+
+bool ReadPrimaryOriginFile(const base::FilePath& path,
+                           std::string* origin) {
+  std::string buffer;
+  if (!base::ReadFileToString(path, &buffer))
+    return false;
+  Pickle pickle(buffer.data(), buffer.size());
+  PickleIterator iter(pickle);
+  return pickle.ReadString(&iter, origin) && !origin->empty();
+}
+
+}  // namespace
+
+SandboxPrioritizedOriginDatabase::SandboxPrioritizedOriginDatabase(
+    const base::FilePath& file_system_directory)
+    : file_system_directory_(file_system_directory),
+      primary_origin_file_(
+          file_system_directory_.Append(kPrimaryOriginFile)) {
+}
+
+SandboxPrioritizedOriginDatabase::~SandboxPrioritizedOriginDatabase() {
+}
+
+bool SandboxPrioritizedOriginDatabase::InitializePrimaryOrigin(
+    const std::string& origin) {
+  if (!primary_origin_database_) {
+    if (!MaybeLoadPrimaryOrigin() && ResetPrimaryOrigin(origin)) {
+      MaybeMigrateDatabase(origin);
+      primary_origin_database_.reset(
+          new SandboxIsolatedOriginDatabase(
+              origin,
+              file_system_directory_,
+              base::FilePath(kPrimaryDirectory)));
+      return true;
+    }
+  }
+
+  if (primary_origin_database_)
+    return primary_origin_database_->HasOriginPath(origin);
+
+  return false;
+}
+
+std::string SandboxPrioritizedOriginDatabase::GetPrimaryOrigin() {
+  MaybeLoadPrimaryOrigin();
+  if (primary_origin_database_)
+    return primary_origin_database_->origin();
+  return std::string();
+}
+
+bool SandboxPrioritizedOriginDatabase::HasOriginPath(
+    const std::string& origin) {
+  MaybeInitializeDatabases(false);
+  if (primary_origin_database_ &&
+      primary_origin_database_->HasOriginPath(origin))
+    return true;
+  if (origin_database_)
+    return origin_database_->HasOriginPath(origin);
+  return false;
+}
+
+bool SandboxPrioritizedOriginDatabase::GetPathForOrigin(
+    const std::string& origin, base::FilePath* directory) {
+  MaybeInitializeDatabases(true);
+  if (primary_origin_database_ &&
+      primary_origin_database_->GetPathForOrigin(origin, directory))
+    return true;
+  DCHECK(origin_database_);
+  return origin_database_->GetPathForOrigin(origin, directory);
+}
+
+bool SandboxPrioritizedOriginDatabase::RemovePathForOrigin(
+    const std::string& origin) {
+  MaybeInitializeDatabases(false);
+  if (primary_origin_database_ &&
+      primary_origin_database_->HasOriginPath(origin)) {
+    primary_origin_database_.reset();
+    base::DeleteFile(file_system_directory_.Append(kPrimaryOriginFile),
+                     true /* recursive */);
+    return true;
+  }
+  if (origin_database_)
+    return origin_database_->RemovePathForOrigin(origin);
+  return true;
+}
+
+bool SandboxPrioritizedOriginDatabase::ListAllOrigins(
+    std::vector<OriginRecord>* origins) {
+  // SandboxOriginDatabase may clear the |origins|, so call this before
+  // primary_origin_database_.
+  MaybeInitializeDatabases(false);
+  if (origin_database_ && !origin_database_->ListAllOrigins(origins))
+    return false;
+  if (primary_origin_database_)
+    return primary_origin_database_->ListAllOrigins(origins);
+  return true;
+}
+
+void SandboxPrioritizedOriginDatabase::DropDatabase() {
+  primary_origin_database_.reset();
+  origin_database_.reset();
+}
+
+bool SandboxPrioritizedOriginDatabase::MaybeLoadPrimaryOrigin() {
+  if (primary_origin_database_)
+    return true;
+  std::string saved_origin;
+  if (!ReadPrimaryOriginFile(primary_origin_file_, &saved_origin))
+    return false;
+  primary_origin_database_.reset(
+      new SandboxIsolatedOriginDatabase(
+          saved_origin,
+          file_system_directory_,
+          base::FilePath(kPrimaryDirectory)));
+  return true;
+}
+
+bool SandboxPrioritizedOriginDatabase::ResetPrimaryOrigin(
+    const std::string& origin) {
+  DCHECK(!primary_origin_database_);
+  if (!WritePrimaryOriginFile(primary_origin_file_, origin))
+    return false;
+  // We reset the primary origin directory too.
+  // (This means the origin file corruption causes data loss
+  // We could keep the directory there as the same origin will likely
+  // become the primary origin, but let's play conservatively.)
+  base::DeleteFile(file_system_directory_.Append(kPrimaryDirectory),
+                   true /* recursive */);
+  return true;
+}
+
+void SandboxPrioritizedOriginDatabase::MaybeMigrateDatabase(
+    const std::string& origin) {
+  MaybeInitializeNonPrimaryDatabase(false);
+  if (!origin_database_)
+    return;
+  if (origin_database_->HasOriginPath(origin)) {
+    base::FilePath directory_name;
+    if (origin_database_->GetPathForOrigin(origin, &directory_name) &&
+        directory_name != base::FilePath(kPrimaryOriginFile)) {
+      base::FilePath from_path = file_system_directory_.Append(directory_name);
+      base::FilePath to_path = file_system_directory_.Append(kPrimaryDirectory);
+
+      if (base::PathExists(to_path))
+        base::DeleteFile(to_path, true /* recursive */);
+      base::Move(from_path, to_path);
+    }
+
+    origin_database_->RemovePathForOrigin(origin);
+  }
+
+  std::vector<OriginRecord> origins;
+  origin_database_->ListAllOrigins(&origins);
+  if (origins.empty()) {
+    origin_database_->RemoveDatabase();
+    origin_database_.reset();
+  }
+}
+
+void SandboxPrioritizedOriginDatabase::MaybeInitializeDatabases(
+    bool create) {
+  MaybeLoadPrimaryOrigin();
+  MaybeInitializeNonPrimaryDatabase(create);
+}
+
+void SandboxPrioritizedOriginDatabase::MaybeInitializeNonPrimaryDatabase(
+    bool create) {
+  if (origin_database_)
+    return;
+
+  origin_database_.reset(new SandboxOriginDatabase(file_system_directory_));
+  if (!create && !base::DirectoryExists(origin_database_->GetDatabasePath())) {
+    origin_database_.reset();
+    return;
+  }
+}
+
+SandboxOriginDatabase*
+SandboxPrioritizedOriginDatabase::GetSandboxOriginDatabase() {
+  MaybeInitializeNonPrimaryDatabase(true);
+  return origin_database_.get();
+}
+
+}  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_prioritized_origin_database.h b/webkit/browser/fileapi/sandbox_prioritized_origin_database.h
new file mode 100644
index 0000000..5509d0f
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_prioritized_origin_database.h
@@ -0,0 +1,67 @@
+// Copyright 2013 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 WEBKIT_BROWSER_FILEAPI_SANDBOX_PRIORITIZED_ORIGIN_DATABASE_H_
+#define WEBKIT_BROWSER_FILEAPI_SANDBOX_PRIORITIZED_ORIGIN_DATABASE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "webkit/browser/fileapi/sandbox_origin_database_interface.h"
+
+namespace fileapi {
+
+class ObfuscatedFileUtil;
+class SandboxIsolatedOriginDatabase;
+class SandboxOriginDatabase;
+
+class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE SandboxPrioritizedOriginDatabase
+    : public SandboxOriginDatabaseInterface {
+ public:
+  explicit SandboxPrioritizedOriginDatabase(
+      const base::FilePath& file_system_directory);
+  virtual ~SandboxPrioritizedOriginDatabase();
+
+  // Sets |origin| as primary origin in this database (e.g. may
+  // allow faster access).
+  // Returns false if this database already has a primary origin
+  // which is different from |origin|.
+  bool InitializePrimaryOrigin(const std::string& origin);
+  std::string GetPrimaryOrigin();
+
+  // SandboxOriginDatabaseInterface overrides.
+  virtual bool HasOriginPath(const std::string& origin) OVERRIDE;
+  virtual bool GetPathForOrigin(const std::string& origin,
+                                base::FilePath* directory) OVERRIDE;
+  virtual bool RemovePathForOrigin(const std::string& origin) OVERRIDE;
+  virtual bool ListAllOrigins(std::vector<OriginRecord>* origins) OVERRIDE;
+  virtual void DropDatabase() OVERRIDE;
+
+  const base::FilePath& primary_origin_file() const {
+    return primary_origin_file_;
+  }
+
+ private:
+  bool MaybeLoadPrimaryOrigin();
+  bool ResetPrimaryOrigin(const std::string& origin);
+  void MaybeMigrateDatabase(const std::string& origin);
+  void MaybeInitializeDatabases(bool create);
+  void MaybeInitializeNonPrimaryDatabase(bool create);
+
+  // For migration.
+  friend class ObfuscatedFileUtil;
+  SandboxOriginDatabase* GetSandboxOriginDatabase();
+
+  const base::FilePath file_system_directory_;
+  const base::FilePath primary_origin_file_;
+  scoped_ptr<SandboxOriginDatabase> origin_database_;
+  scoped_ptr<SandboxIsolatedOriginDatabase> primary_origin_database_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxPrioritizedOriginDatabase);
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_BROWSER_FILEAPI_SANDBOX_PRIORITIZED_ORIGIN_DATABASE_H_
diff --git a/webkit/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc b/webkit/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
new file mode 100644
index 0000000..2195f36
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
@@ -0,0 +1,215 @@
+// Copyright 2013 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/basictypes.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/platform_file.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/sandbox_origin_database.h"
+#include "webkit/browser/fileapi/sandbox_prioritized_origin_database.h"
+
+namespace fileapi {
+
+TEST(SandboxPrioritizedOriginDatabaseTest, BasicTest) {
+  base::ScopedTempDir dir;
+  base::FilePath path;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+
+  const std::string kOrigin1("origin1");
+  const std::string kOrigin2("origin2");
+
+  SandboxPrioritizedOriginDatabase database(dir.path());
+
+  // Set the kOrigin1 as a parimary origin.
+  EXPECT_TRUE(database.InitializePrimaryOrigin(kOrigin1));
+
+  // Add two origins.
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin2, &path));
+
+  // Verify them.
+  EXPECT_TRUE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+  EXPECT_FALSE(path.empty());
+  EXPECT_TRUE(database.HasOriginPath(kOrigin2));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin2, &path));
+  EXPECT_FALSE(path.empty());
+
+  std::vector<SandboxOriginDatabaseInterface::OriginRecord> origins;
+  database.ListAllOrigins(&origins);
+  ASSERT_EQ(2U, origins.size());
+  EXPECT_TRUE(origins[0].origin == kOrigin1 ||
+              origins[1].origin == kOrigin1);
+  EXPECT_TRUE(origins[0].origin == kOrigin2 ||
+              origins[1].origin == kOrigin2);
+  EXPECT_NE(origins[0].path, origins[1].path);
+
+  // Try remove path for kOrigin1.
+  database.RemovePathForOrigin(kOrigin1);
+
+  // Verify the removal.
+  EXPECT_FALSE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.HasOriginPath(kOrigin2));
+  database.ListAllOrigins(&origins);
+  ASSERT_EQ(1U, origins.size());
+  EXPECT_EQ(kOrigin2, origins[0].origin);
+
+  // Try remove path for kOrigin2.
+  database.RemovePathForOrigin(kOrigin2);
+
+  // Verify the removal.
+  EXPECT_FALSE(database.HasOriginPath(kOrigin1));
+  EXPECT_FALSE(database.HasOriginPath(kOrigin2));
+  database.ListAllOrigins(&origins);
+  EXPECT_TRUE(origins.empty());
+}
+
+TEST(SandboxPrioritizedOriginDatabaseTest, SetPrimaryLaterTest) {
+  base::ScopedTempDir dir;
+  base::FilePath path;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+
+  const std::string kOrigin1("origin1");
+  const std::string kOrigin2("origin2");
+
+  SandboxPrioritizedOriginDatabase database(dir.path());
+
+  EXPECT_TRUE(database.GetPrimaryOrigin().empty());
+
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin2, &path));
+
+  // Set the kOrigin1 as a parimary origin.
+  EXPECT_TRUE(database.InitializePrimaryOrigin(kOrigin1));
+  EXPECT_EQ(kOrigin1, database.GetPrimaryOrigin());
+
+  // Regardless of whether it is initialized as primary or not
+  // they should just work.
+  EXPECT_TRUE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+  EXPECT_FALSE(path.empty());
+  EXPECT_TRUE(database.HasOriginPath(kOrigin2));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin2, &path));
+  EXPECT_FALSE(path.empty());
+}
+
+TEST(SandboxPrioritizedOriginDatabaseTest, LostPrimaryOriginFileTest) {
+  base::ScopedTempDir dir;
+  base::FilePath path;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+
+  const std::string kOrigin1("origin1");
+  const std::string kData("foo");
+
+  SandboxPrioritizedOriginDatabase database(dir.path());
+
+  EXPECT_TRUE(database.GetPrimaryOrigin().empty());
+
+  // Set the kOrigin1 as a parimary origin.
+  EXPECT_TRUE(database.InitializePrimaryOrigin(kOrigin1));
+  EXPECT_EQ(kOrigin1, database.GetPrimaryOrigin());
+
+  // Make sure it works.
+  EXPECT_TRUE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+
+  // Reset the database.
+  database.DropDatabase();
+
+  // kOrigin1 should still be marked as primary.
+  EXPECT_TRUE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path));
+
+  // Corrupt the primary origin file.
+  file_util::WriteFile(
+      database.primary_origin_file(), kData.data(), kData.size());
+
+  // Reset the database.
+  database.DropDatabase();
+
+  // kOrigin1 is no longer marked as primary, and unfortunately we fail
+  // to find the data for the origin.
+  EXPECT_FALSE(database.HasOriginPath(kOrigin1));
+}
+
+TEST(SandboxPrioritizedOriginDatabaseTest, MigrationTest) {
+  base::ScopedTempDir dir;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+
+  const std::string kOrigin1("origin1");
+  const std::string kOrigin2("origin2");
+  const std::string kFakeDirectoryData1("0123456789");
+  const std::string kFakeDirectoryData2("abcde");
+  base::FilePath old_dir_db_path1, old_dir_db_path2;
+  base::FilePath path1, path2;
+
+  // Initialize the directory with two origins using the regular
+  // SandboxOriginDatabase.
+  {
+    SandboxOriginDatabase database_old(dir.path());
+    base::FilePath old_db_path = database_old.GetDatabasePath();
+    EXPECT_FALSE(base::PathExists(old_db_path));
+
+    // Initialize paths for kOrigin1 and kOrigin2.
+    EXPECT_TRUE(database_old.GetPathForOrigin(kOrigin1, &path1));
+    EXPECT_FALSE(path1.empty());
+    EXPECT_TRUE(database_old.GetPathForOrigin(kOrigin2, &path2));
+    EXPECT_FALSE(path2.empty());
+
+    EXPECT_TRUE(base::DirectoryExists(old_db_path));
+
+    // Populate the origin directory with some fake data.
+    old_dir_db_path1 = dir.path().Append(path1);
+    ASSERT_TRUE(file_util::CreateDirectory(old_dir_db_path1));
+    EXPECT_EQ(static_cast<int>(kFakeDirectoryData1.size()),
+              file_util::WriteFile(old_dir_db_path1.AppendASCII("dummy"),
+                                   kFakeDirectoryData1.data(),
+                                   kFakeDirectoryData1.size()));
+    old_dir_db_path2 = dir.path().Append(path2);
+    ASSERT_TRUE(file_util::CreateDirectory(old_dir_db_path2));
+    EXPECT_EQ(static_cast<int>(kFakeDirectoryData2.size()),
+              file_util::WriteFile(old_dir_db_path2.AppendASCII("dummy"),
+                                   kFakeDirectoryData2.data(),
+                                   kFakeDirectoryData2.size()));
+  }
+
+  // Re-open the directory using sandboxPrioritizedOriginDatabase.
+  SandboxPrioritizedOriginDatabase database(dir.path());
+
+  // Set the kOrigin1 as a parimary origin.
+  // (Trying to initialize another origin should fail).
+  EXPECT_TRUE(database.InitializePrimaryOrigin(kOrigin1));
+  EXPECT_FALSE(database.InitializePrimaryOrigin(kOrigin2));
+
+  EXPECT_EQ(kOrigin1, database.GetPrimaryOrigin());
+
+  // Regardless of whether the origin is registered as primary or not
+  // it should just work.
+  EXPECT_TRUE(database.HasOriginPath(kOrigin1));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin1, &path1));
+  EXPECT_TRUE(database.HasOriginPath(kOrigin2));
+  EXPECT_TRUE(database.GetPathForOrigin(kOrigin2, &path2));
+
+  // The directory content must be kept (or migrated if necessary) as well.
+  std::string origin_db_data;
+  base::FilePath dir_db_path = dir.path().Append(path1);
+  EXPECT_TRUE(base::PathExists(dir_db_path.AppendASCII("dummy")));
+  EXPECT_TRUE(base::ReadFileToString(
+      dir_db_path.AppendASCII("dummy"), &origin_db_data));
+  EXPECT_EQ(kFakeDirectoryData1, origin_db_data);
+
+  origin_db_data.clear();
+  dir_db_path = dir.path().Append(path2);
+  EXPECT_TRUE(base::PathExists(dir_db_path.AppendASCII("dummy")));
+  EXPECT_TRUE(base::ReadFileToString(
+      dir_db_path.AppendASCII("dummy"), &origin_db_data));
+  EXPECT_EQ(kFakeDirectoryData2, origin_db_data);
+
+  // After the migration the kOrigin1 directory database path must be gone.
+  EXPECT_FALSE(base::PathExists(old_dir_db_path1));
+  EXPECT_TRUE(base::PathExists(old_dir_db_path2));
+}
+
+}  // namespace fileapi
diff --git a/webkit/browser/quota/quota_manager.cc b/webkit/browser/quota/quota_manager.cc
index 0f445a0..5df4231 100644
--- a/webkit/browser/quota/quota_manager.cc
+++ b/webkit/browser/quota/quota_manager.cc
@@ -504,6 +504,7 @@
   }
 
   void DidGetGlobalUsage(StorageType type, int64, int64) {
+    DCHECK(manager()->GetUsageTracker(type));
     AddEntries(type, manager()->GetUsageTracker(type));
   }
 
@@ -805,8 +806,8 @@
     temporary_quota_override_(-1),
     desired_available_space_(-1),
     special_storage_policy_(special_storage_policy),
-    weak_factory_(this),
-    get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace) {
+    get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace),
+    weak_factory_(this) {
 }
 
 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
@@ -851,6 +852,7 @@
     }
   }
 
+  DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin),
                                       dispatcher->GetHostUsageCallback());
 
@@ -909,6 +911,7 @@
                                         StorageType type,
                                         bool enabled) {
   LazyInitialize();
+  DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled);
 }
 
@@ -1066,6 +1069,7 @@
 void QuotaManager::GetGlobalUsage(StorageType type,
                                   const GlobalUsageCallback& callback) {
   LazyInitialize();
+  DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->GetGlobalUsage(callback);
 }
 
@@ -1073,6 +1077,7 @@
                                 StorageType type,
                                 const UsageCallback& callback) {
   LazyInitialize();
+  DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->GetHostUsage(host, callback);
 }
 
@@ -1081,6 +1086,7 @@
                                 QuotaClient::ID client_id,
                                 const UsageCallback& callback) {
   LazyInitialize();
+  DCHECK(GetUsageTracker(type));
   ClientUsageTracker* tracker =
       GetUsageTracker(type)->GetClientTracker(client_id);
   if (!tracker) {
@@ -1092,7 +1098,8 @@
 
 bool QuotaManager::IsTrackingHostUsage(StorageType type,
                                        QuotaClient::ID client_id) const {
-  return GetUsageTracker(type)->GetClientTracker(client_id) != NULL;
+  UsageTracker* tracker = GetUsageTracker(type);
+  return tracker && tracker->GetClientTracker(client_id);
 }
 
 void QuotaManager::GetStatistics(
@@ -1114,8 +1121,10 @@
   // quota must be capped by the server limit).
   if (type == kStorageTypeSyncable)
     return false;
+  if (type == kStorageTypeQuotaNotManaged)
+    return true;
   return special_storage_policy_.get() &&
-          special_storage_policy_->IsStorageUnlimited(origin);
+         special_storage_policy_->IsStorageUnlimited(origin);
 }
 
 void QuotaManager::GetOriginsModifiedSince(StorageType type,
@@ -1218,7 +1227,9 @@
       return persistent_usage_tracker_.get();
     case kStorageTypeSyncable:
       return syncable_usage_tracker_.get();
-    default:
+    case kStorageTypeQuotaNotManaged:
+      return NULL;
+    case kStorageTypeUnknown:
       NOTREACHED();
   }
   return NULL;
@@ -1259,6 +1270,7 @@
     int64 delta,
     base::Time modified_time) {
   LazyInitialize();
+  DCHECK(GetUsageTracker(type));
   GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
 
   PostTaskAndReplyWithResultForDBThread(
diff --git a/webkit/child/webkitplatformsupport_child_impl.cc b/webkit/child/webkitplatformsupport_child_impl.cc
index 849dcb7..c23c404 100644
--- a/webkit/child/webkitplatformsupport_child_impl.cc
+++ b/webkit/child/webkitplatformsupport_child_impl.cc
@@ -93,8 +93,6 @@
 
 WebKit::WebDiscardableMemory*
 WebKitPlatformSupportChildImpl::allocateAndLockDiscardableMemory(size_t bytes) {
-  if (!base::DiscardableMemory::Supported())
-    return NULL;
   return WebDiscardableMemoryImpl::CreateLockedMemory(bytes).release();
 }
 
diff --git a/webkit/child/webkitplatformsupport_impl.cc b/webkit/child/webkitplatformsupport_impl.cc
index baf8a34..8f68c3a 100644
--- a/webkit/child/webkitplatformsupport_impl.cc
+++ b/webkit/child/webkitplatformsupport_impl.cc
@@ -468,7 +468,12 @@
   return NULL;
 }
 
-void WebKitPlatformSupportImpl::addTraceEvent(
+COMPILE_ASSERT(
+    sizeof(WebKit::Platform::TraceEventHandle) ==
+        sizeof(base::debug::TraceEventHandle),
+    TraceEventHandle_types_must_be_same_size);
+
+WebKit::Platform::TraceEventHandle WebKitPlatformSupportImpl::addTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
     const char* name,
@@ -478,11 +483,20 @@
     const unsigned char* arg_types,
     const unsigned long long* arg_values,
     unsigned char flags) {
-  TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name, id,
-                                  num_args, arg_names, arg_types,
-                                  arg_values, NULL, flags);
+  base::debug::TraceEventHandle handle = TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_group_enabled, name, id,
+      num_args, arg_names, arg_types, arg_values, NULL, flags);
+  WebKit::Platform::TraceEventHandle result;
+  memcpy(&result, &handle, sizeof(result));
+  return result;
 }
 
+void WebKitPlatformSupportImpl::updateTraceEventDuration(
+    TraceEventHandle handle) {
+  base::debug::TraceEventHandle traceEventHandle;
+  memcpy(&traceEventHandle, &handle, sizeof(handle));
+  TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(traceEventHandle);
+}
 
 namespace {
 
diff --git a/webkit/child/webkitplatformsupport_impl.h b/webkit/child/webkitplatformsupport_impl.h
index 0dbaa1f..66e4759 100644
--- a/webkit/child/webkitplatformsupport_impl.h
+++ b/webkit/child/webkitplatformsupport_impl.h
@@ -76,7 +76,7 @@
   virtual const unsigned char* getTraceCategoryEnabledFlag(
       const char* category_name);
   virtual long* getTraceSamplingState(const unsigned thread_bucket);
-  virtual void addTraceEvent(
+  virtual TraceEventHandle addTraceEvent(
       char phase,
       const unsigned char* category_group_enabled,
       const char* name,
@@ -86,6 +86,7 @@
       const unsigned char* arg_types,
       const unsigned long long* arg_values,
       unsigned char flags);
+  virtual void updateTraceEventDuration(TraceEventHandle);
   virtual WebKit::WebData loadResource(const char* name);
   virtual WebKit::WebString queryLocalizedString(
       WebKit::WebLocalizedString::Name name);
diff --git a/webkit/child/weburlloader_impl.cc b/webkit/child/weburlloader_impl.cc
index 6922da6..09273f8 100644
--- a/webkit/child/weburlloader_impl.cc
+++ b/webkit/child/weburlloader_impl.cc
@@ -434,11 +434,7 @@
           break;
         }
         case WebHTTPBody::Element::TypeBlob:
-#ifdef USE_BLOB_UUIDS
           request_body->AppendBlob(element.blobUUID.utf8());
-#else
-          request_body->AppendBlobDeprecated(GURL(element.blobURL));
-#endif
           break;
         default:
           NOTREACHED();
diff --git a/webkit/common/DEPS b/webkit/common/DEPS
index 9dbc494..dea5c28 100644
--- a/webkit/common/DEPS
+++ b/webkit/common/DEPS
@@ -1,6 +1,4 @@
 include_rules = [
-  # TODO(scottmg): http://crbug.com/239107
-  "+ui/base/clipboard",
   "-webkit/browser",
   "-webkit/renderer",
 ]
diff --git a/webkit/common/blob/blob_data.cc b/webkit/common/blob/blob_data.cc
index 0934b2a..3681861 100644
--- a/webkit/common/blob/blob_data.cc
+++ b/webkit/common/blob/blob_data.cc
@@ -33,12 +33,6 @@
                                    expected_modification_time);
 }
 
-void BlobData::AppendBlob(const GURL& blob_url, uint64 offset, uint64 length) {
-  DCHECK_GT(length, 0ul);
-  items_.push_back(Item());
-  items_.back().SetToBlobUrlRange(blob_url, offset, length);
-}
-
 void BlobData::AppendBlob(const std::string& uuid,
                           uint64 offset, uint64 length) {
   DCHECK_GT(length, 0ul);
diff --git a/webkit/common/blob/blob_data.h b/webkit/common/blob/blob_data.h
index 01d477f..3ea6e91 100644
--- a/webkit/common/blob/blob_data.h
+++ b/webkit/common/blob/blob_data.h
@@ -36,12 +36,7 @@
 
   void AppendFile(const base::FilePath& file_path, uint64 offset, uint64 length,
                   const base::Time& expected_modification_time);
-
-  // Note: Identifying blobs by url is being deprecated, but while transitioning
-  // there's a little of both going on in the project.
-  void AppendBlob(const GURL& blob_url, uint64 offset, uint64 length);
   void AppendBlob(const std::string& uuid, uint64 offset, uint64 length);
-
   void AppendFileSystemFile(const GURL& url, uint64 offset, uint64 length,
                             const base::Time& expected_modification_time);
 
diff --git a/webkit/common/data_element.cc b/webkit/common/data_element.cc
index 5048821..f94a4c8 100644
--- a/webkit/common/data_element.cc
+++ b/webkit/common/data_element.cc
@@ -26,16 +26,6 @@
   expected_modification_time_ = expected_modification_time;
 }
 
-void DataElement::SetToBlobUrlRange(
-    const GURL& blob_url,
-    uint64 offset, uint64 length) {
-  type_ = TYPE_BLOB;
-  blob_url_ = blob_url;
-  offset_ = offset;
-  length_ = length;
-  blob_uuid_.clear();
-}
-
 void DataElement::SetToBlobRange(
     const std::string& blob_uuid,
     uint64 offset, uint64 length) {
@@ -43,7 +33,6 @@
   blob_uuid_ = blob_uuid;
   offset_ = offset;
   length_ = length;
-  blob_url_ = GURL();
 }
 
 void DataElement::SetToFileSystemUrlRange(
diff --git a/webkit/common/data_element.h b/webkit/common/data_element.h
index f93960b..4ec09ce 100644
--- a/webkit/common/data_element.h
+++ b/webkit/common/data_element.h
@@ -36,12 +36,7 @@
   const char* bytes() const { return bytes_ ? bytes_ : &buf_[0]; }
   const base::FilePath& path() const { return path_; }
   const GURL& filesystem_url() const { return filesystem_url_; }
-
-  // TODO(michaeln): crbug/174200, fully switch to using string uuids.
-  // Note: Identifying blobs by url is being deprecated, but while
-  // transitioning, there's a little of both going on in the project.
   const std::string& blob_uuid() const { return blob_uuid_; }
-  const GURL& blob_url() const { return blob_url_; }
   uint64 offset() const { return offset_; }
   uint64 length() const { return length_; }
   const base::Time& expected_modification_time() const {
@@ -69,9 +64,6 @@
   }
 
   // Sets TYPE_BLOB data.
-  void SetToBlobUrl(const GURL& blob_url) {
-    SetToBlobUrlRange(blob_url, 0, kuint64max);
-  }
   void SetToBlob(const std::string& uuid) {
     SetToBlobRange(uuid, 0, kuint64max);
   }
@@ -82,8 +74,6 @@
                           const base::Time& expected_modification_time);
 
   // Sets TYPE_BLOB data with range.
-  void SetToBlobUrlRange(const GURL& blob_url,
-                         uint64 offset, uint64 length);
   void SetToBlobRange(const std::string& blob_uuid,
                       uint64 offset, uint64 length);
 
@@ -98,7 +88,6 @@
   const char* bytes_;  // For TYPE_BYTES.
   base::FilePath path_;  // For TYPE_FILE.
   GURL filesystem_url_;  // For TYPE_FILE_FILESYSTEM.
-  GURL blob_url_;
   std::string blob_uuid_;
   uint64 offset_;
   uint64 length_;
@@ -118,8 +107,7 @@
       return a.path() == b.path() &&
              a.expected_modification_time() == b.expected_modification_time();
     case DataElement::TYPE_BLOB:
-      return a.blob_uuid().empty() ? (a.blob_url() == b.blob_url())
-                                   : (a.blob_uuid() == b.blob_uuid());
+      return a.blob_uuid() == b.blob_uuid();
     case DataElement::TYPE_FILE_FILESYSTEM:
       return a.filesystem_url() == b.filesystem_url();
     case DataElement::TYPE_UNKNOWN:
diff --git a/webkit/common/fileapi/file_system_util.cc b/webkit/common/fileapi/file_system_util.cc
index bc3f435..9670dd7 100644
--- a/webkit/common/fileapi/file_system_util.cc
+++ b/webkit/common/fileapi/file_system_util.cc
@@ -193,6 +193,7 @@
       return kFileSystemTypePersistent;
     case quota::kStorageTypeSyncable:
       return kFileSystemTypeSyncable;
+    case quota::kStorageTypeQuotaNotManaged:
     case quota::kStorageTypeUnknown:
       return kFileSystemTypeUnknown;
   }
@@ -208,6 +209,8 @@
     case kFileSystemTypeSyncable:
     case kFileSystemTypeSyncableForInternalSync:
       return quota::kStorageTypeSyncable;
+    case kFileSystemTypePluginPrivate:
+      return quota::kStorageTypeQuotaNotManaged;
     default:
       return quota::kStorageTypeUnknown;
   }
@@ -369,6 +372,14 @@
   return true;
 }
 
+bool ValidateIsolatedFileSystemId(const std::string& filesystem_id) {
+  const size_t kExpectedFileSystemIdSize = 32;
+  if (filesystem_id.size() != kExpectedFileSystemIdSize)
+    return false;
+  const std::string kExpectedChars("ABCDEF0123456789");
+  return ContainsOnlyChars(filesystem_id, kExpectedChars);
+}
+
 std::string GetIsolatedFileSystemRootURIString(
     const GURL& origin_url,
     const std::string& filesystem_id,
diff --git a/webkit/common/fileapi/file_system_util.h b/webkit/common/fileapi/file_system_util.h
index e7c9cc2..d6efeec 100644
--- a/webkit/common/fileapi/file_system_util.h
+++ b/webkit/common/fileapi/file_system_util.h
@@ -145,6 +145,10 @@
     const std::string& filesystem_name,
     std::string* filesystem_id);
 
+// Validates the given isolated file system id.
+WEBKIT_STORAGE_COMMON_EXPORT bool ValidateIsolatedFileSystemId(
+    const std::string& filesystem_id);
+
 // Returns the root URI for an isolated filesystem for origin |origin_url|
 // and |filesystem_id|. If the |optional_root_name| is given the resulting
 // root URI will point to the subfolder within the isolated filesystem.
diff --git a/webkit/common/fileapi/file_system_util_unittest.cc b/webkit/common/fileapi/file_system_util_unittest.cc
index 2cf53db..2cc3402 100644
--- a/webkit/common/fileapi/file_system_util_unittest.cc
+++ b/webkit/common/fileapi/file_system_util_unittest.cc
@@ -222,5 +222,42 @@
   EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Isolated_", &fsid));
 }
 
+TEST_F(FileSystemUtilTest, ValidateIsolatedFileSystemId) {
+  EXPECT_TRUE(ValidateIsolatedFileSystemId("ABCDEF0123456789ABCDEF0123456789"));
+  EXPECT_TRUE(ValidateIsolatedFileSystemId("ABCDEFABCDEFABCDEFABCDEFABCDEFAB"));
+  EXPECT_TRUE(ValidateIsolatedFileSystemId("01234567890123456789012345678901"));
+
+  const size_t kExpectedFileSystemIdSize = 32;
+
+  // Should not contain lowercase characters.
+  const std::string kLowercaseId = "abcdef0123456789abcdef0123456789";
+  EXPECT_EQ(kExpectedFileSystemIdSize, kLowercaseId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kLowercaseId));
+
+  // Should not be shorter/longer than expected.
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(std::string()));
+
+  const std::string kShorterId = "ABCDEF0123456789ABCDEF";
+  EXPECT_GT(kExpectedFileSystemIdSize, kShorterId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kShorterId));
+
+  const std::string kLongerId = "ABCDEF0123456789ABCDEF0123456789ABCDEF";
+  EXPECT_LT(kExpectedFileSystemIdSize, kLongerId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kLongerId));
+
+  // Should not contain not alphabetical nor numerical characters.
+  const std::string kSlashId = "ABCD/EFGH/IJKL/MNOP/QRST/UVWX/YZ";
+  EXPECT_EQ(kExpectedFileSystemIdSize, kSlashId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kSlashId));
+
+  const std::string kBackslashId = "ABCD\\EFGH\\IJKL\\MNOP\\QRST\\UVWX\\YZ";
+  EXPECT_EQ(kExpectedFileSystemIdSize, kBackslashId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kBackslashId));
+
+  const std::string kSpaceId = "ABCD EFGH IJKL MNOP QRST UVWX YZ";
+  EXPECT_EQ(kExpectedFileSystemIdSize, kSpaceId.size());
+  EXPECT_FALSE(ValidateIsolatedFileSystemId(kSpaceId));
+}
+
 }  // namespace
 }  // namespace fileapi
diff --git a/webkit/common/gpu/context_provider_in_process.cc b/webkit/common/gpu/context_provider_in_process.cc
index 272baed..bbadcb9 100644
--- a/webkit/common/gpu/context_provider_in_process.cc
+++ b/webkit/common/gpu/context_provider_in_process.cc
@@ -13,7 +13,6 @@
 #include "cc/output/managed_memory_policy.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
-#include "webkit/common/gpu/managed_memory_policy_convert.h"
 
 namespace webkit {
 namespace gpu {
@@ -59,28 +58,6 @@
   ContextProviderInProcess* provider_;
 };
 
-class ContextProviderInProcess::MemoryAllocationCallbackProxy
-    : public WebKit::WebGraphicsContext3D::
-          WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
- public:
-  explicit MemoryAllocationCallbackProxy(ContextProviderInProcess* provider)
-      : provider_(provider) {
-    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
-  }
-
-  virtual ~MemoryAllocationCallbackProxy() {
-    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
-  }
-
-  virtual void onMemoryAllocationChanged(
-      WebKit::WebGraphicsMemoryAllocation allocation) {
-    provider_->OnMemoryAllocationChanged(allocation);
-  }
-
- private:
-  ContextProviderInProcess* provider_;
-};
-
 // static
 scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
     scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
@@ -140,8 +117,6 @@
   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
   swap_buffers_complete_callback_proxy_.reset(
       new SwapBuffersCompleteCallbackProxy(this));
-  memory_allocation_callback_proxy_.reset(
-      new MemoryAllocationCallbackProxy(this));
   return true;
 }
 
@@ -226,27 +201,6 @@
     swap_buffers_complete_callback_.Run();
 }
 
-void ContextProviderInProcess::OnMemoryAllocationChanged(
-    const WebKit::WebGraphicsMemoryAllocation& allocation) {
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  if (gr_context_) {
-    bool nonzero_allocation = !!allocation.gpuResourceSizeInBytes;
-    gr_context_->SetMemoryLimit(nonzero_allocation);
-  }
-
-  if (memory_policy_changed_callback_.is_null())
-    return;
-
-  bool discard_backbuffer_when_not_visible;
-  cc::ManagedMemoryPolicy policy =
-      ManagedMemoryPolicyConvert::Convert(allocation,
-                                          &discard_backbuffer_when_not_visible);
-
-  memory_policy_changed_callback_.Run(
-      policy, discard_backbuffer_when_not_visible);
-}
-
 bool ContextProviderInProcess::DestroyedOnMainThread() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
@@ -272,10 +226,7 @@
 
 void ContextProviderInProcess::SetMemoryPolicyChangedCallback(
     const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-  DCHECK(memory_policy_changed_callback_.is_null() ||
-         memory_policy_changed_callback.is_null());
-  memory_policy_changed_callback_ = memory_policy_changed_callback;
+  // There's no memory manager for the in-process implementation.
 }
 
 }  // namespace gpu
diff --git a/webkit/common/gpu/context_provider_in_process.h b/webkit/common/gpu/context_provider_in_process.h
index 288e6a9..36c2bcd 100644
--- a/webkit/common/gpu/context_provider_in_process.h
+++ b/webkit/common/gpu/context_provider_in_process.h
@@ -13,10 +13,7 @@
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 #include "webkit/common/gpu/webkit_gpu_export.h"
 
-namespace WebKit {
-class WebGraphicsContext3D;
-struct WebGraphicsMemoryAllocation;
-}
+namespace WebKit { class WebGraphicsContext3D; }
 
 namespace webkit {
 namespace gpu {
@@ -57,8 +54,6 @@
 
   void OnLostContext();
   void OnSwapBuffersComplete();
-  void OnMemoryAllocationChanged(
-      const WebKit::WebGraphicsMemoryAllocation& allocation);
 
  private:
   base::ThreadChecker main_thread_checker_;
@@ -70,7 +65,6 @@
 
   LostContextCallback lost_context_callback_;
   SwapBuffersCompleteCallback swap_buffers_complete_callback_;
-  MemoryPolicyChangedCallback memory_policy_changed_callback_;
 
   base::Lock destroyed_lock_;
   bool destroyed_;
@@ -83,8 +77,7 @@
   scoped_ptr<SwapBuffersCompleteCallbackProxy>
       swap_buffers_complete_callback_proxy_;
 
-  class MemoryAllocationCallbackProxy;
-  scoped_ptr<MemoryAllocationCallbackProxy> memory_allocation_callback_proxy_;
+  DISALLOW_COPY_AND_ASSIGN(ContextProviderInProcess);
 };
 
 }  // namespace gpu
diff --git a/webkit/common/gpu/managed_memory_policy_convert.cc b/webkit/common/gpu/managed_memory_policy_convert.cc
deleted file mode 100644
index 548e2ae..0000000
--- a/webkit/common/gpu/managed_memory_policy_convert.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2013 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 "webkit/common/gpu/managed_memory_policy_convert.h"
-
-namespace webkit {
-namespace gpu {
-
-static cc::ManagedMemoryPolicy::PriorityCutoff ConvertPriorityCutoff(
-    WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priority_cutoff) {
-  // This is simple a 1:1 map, the names differ only because the WebKit names
-  // should be to match the cc names.
-  switch (priority_cutoff) {
-    case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing:
-      return cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
-    case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly:
-      return cc::ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
-    case WebKit::WebGraphicsMemoryAllocation::
-        PriorityCutoffAllowVisibleAndNearby:
-      return cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
-    case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything:
-      return cc::ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
-  }
-  NOTREACHED();
-  return cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
-}
-
-// static
-cc::ManagedMemoryPolicy ManagedMemoryPolicyConvert::Convert(
-    const WebKit::WebGraphicsMemoryAllocation& allocation,
-    bool* discard_backbuffer_when_not_visible) {
-  *discard_backbuffer_when_not_visible = !allocation.suggestHaveBackbuffer;
-  return cc::ManagedMemoryPolicy(
-      allocation.bytesLimitWhenVisible,
-      ConvertPriorityCutoff(allocation.priorityCutoffWhenVisible),
-      allocation.bytesLimitWhenNotVisible,
-      ConvertPriorityCutoff(allocation.priorityCutoffWhenNotVisible),
-      cc::ManagedMemoryPolicy::kDefaultNumResourcesLimit);
-}
-
-}  // namespace gpu
-}  // namespace webkit
diff --git a/webkit/common/gpu/managed_memory_policy_convert.h b/webkit/common/gpu/managed_memory_policy_convert.h
deleted file mode 100644
index 0309683..0000000
--- a/webkit/common/gpu/managed_memory_policy_convert.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013 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 WEBKIT_COMMON_GPU_MANAGED_MEMORY_POLICY_CONVERT_H_
-#define WEBKIT_COMMON_GPU_MANAGED_MEMORY_POLICY_CONVERT_H_
-
-#include "cc/output/managed_memory_policy.h"
-#include "third_party/WebKit/public/platform/WebGraphicsMemoryAllocation.h"
-#include "webkit/common/gpu/webkit_gpu_export.h"
-
-namespace webkit {
-namespace gpu {
-
-class WEBKIT_GPU_EXPORT ManagedMemoryPolicyConvert {
- public:
-  static cc::ManagedMemoryPolicy Convert(
-      const WebKit::WebGraphicsMemoryAllocation& allocation,
-      bool* discard_backbuffer_when_not_visible);
-};
-
-}  // namespace gpu
-}  // namespace webkit
-
-#endif  // WEBKIT_COMMON_GPU_MANAGED_MEMORY_POLICY_CONVERT_H_
diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
index b9ed930..bec5171 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -41,11 +41,6 @@
 const size_t kMinTransferBufferSize = 1 * 256 * 1024;
 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
 
-void OnSignalSyncPoint(
-    WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback* callback) {
-  callback->onSyncPointReached();
-}
-
 uint32_t GenFlushID() {
   static base::subtle::Atomic32 flush_id = 0;
 
@@ -243,6 +238,12 @@
   gl_->glname();                                                        \
 }
 
+#define DELEGATE_TO_GL_R(name, glname, rt)                              \
+rt WebGraphicsContext3DInProcessCommandBufferImpl::name() {             \
+  ClearContext();                                                       \
+  return gl_->glname();                                                 \
+}
+
 #define DELEGATE_TO_GL_1(name, glname, t1)                              \
 void WebGraphicsContext3DInProcessCommandBufferImpl::name(t1 a1) {      \
   ClearContext();                                                       \
@@ -392,11 +393,6 @@
     bool visible) {
 }
 
-void WebGraphicsContext3DInProcessCommandBufferImpl::
-    setMemoryAllocationChangedCallbackCHROMIUM(
-        WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) {
-}
-
 void WebGraphicsContext3DInProcessCommandBufferImpl::discardFramebufferEXT(
     WGC3Denum target, WGC3Dsizei numAttachments, const WGC3Denum* attachments) {
   gl_->DiscardFramebufferEXT(target, numAttachments, attachments);
@@ -982,6 +978,23 @@
 DELEGATE_TO_GL_4(viewport, Viewport,
                  WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei)
 
+DELEGATE_TO_GL_2(genBuffers, GenBuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genFramebuffers, GenFramebuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genRenderbuffers, GenRenderbuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(genTextures, GenTextures, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteBuffers, DeleteBuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteFramebuffers, DeleteFramebuffers, WGC3Dsizei, WebGLId*);
+
+DELEGATE_TO_GL_2(deleteRenderbuffers, DeleteRenderbuffers, WGC3Dsizei,
+                 WebGLId*);
+
+DELEGATE_TO_GL_2(deleteTextures, DeleteTextures, WGC3Dsizei, WebGLId*);
+
 WebGLId WebGraphicsContext3DInProcessCommandBufferImpl::createBuffer() {
   ClearContext();
   GLuint o;
@@ -996,11 +1009,6 @@
   return o;
 }
 
-WebGLId WebGraphicsContext3DInProcessCommandBufferImpl::createProgram() {
-  ClearContext();
-  return gl_->CreateProgram();
-}
-
 WebGLId WebGraphicsContext3DInProcessCommandBufferImpl::createRenderbuffer() {
   ClearContext();
   GLuint o;
@@ -1008,8 +1016,6 @@
   return o;
 }
 
-DELEGATE_TO_GL_1R(createShader, CreateShader, WGC3Denum, WebGLId);
-
 WebGLId WebGraphicsContext3DInProcessCommandBufferImpl::createTexture() {
   ClearContext();
   GLuint o;
@@ -1029,30 +1035,26 @@
   gl_->DeleteFramebuffers(1, &framebuffer);
 }
 
-void WebGraphicsContext3DInProcessCommandBufferImpl::deleteProgram(
-    WebGLId program) {
-  ClearContext();
-  gl_->DeleteProgram(program);
-}
-
 void WebGraphicsContext3DInProcessCommandBufferImpl::deleteRenderbuffer(
     WebGLId renderbuffer) {
   ClearContext();
   gl_->DeleteRenderbuffers(1, &renderbuffer);
 }
 
-void WebGraphicsContext3DInProcessCommandBufferImpl::deleteShader(
-    WebGLId shader) {
-  ClearContext();
-  gl_->DeleteShader(shader);
-}
-
 void WebGraphicsContext3DInProcessCommandBufferImpl::deleteTexture(
     WebGLId texture) {
   ClearContext();
   gl_->DeleteTextures(1, &texture);
 }
 
+DELEGATE_TO_GL_R(createProgram, CreateProgram, WebGLId);
+
+DELEGATE_TO_GL_1R(createShader, CreateShader, WGC3Denum, WebGLId);
+
+DELEGATE_TO_GL_1(deleteProgram, DeleteProgram, WebGLId);
+
+DELEGATE_TO_GL_1(deleteShader, DeleteShader, WebGLId);
+
 void WebGraphicsContext3DInProcessCommandBufferImpl::OnSwapBuffersComplete() {
 }
 
@@ -1185,18 +1187,6 @@
   return 0;
 }
 
-void WebGraphicsContext3DInProcessCommandBufferImpl::signalSyncPoint(
-    unsigned sync_point,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
-void WebGraphicsContext3DInProcessCommandBufferImpl::signalQuery(
-    unsigned query,
-    WebGraphicsSyncPointCallback* callback) {
-  NOTREACHED();
-}
-
 void WebGraphicsContext3DInProcessCommandBufferImpl::loseContextCHROMIUM(
     WGC3Denum current, WGC3Denum other) {
   gl_->LoseContextCHROMIUM(current, other);
diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
index 1e77471..b74a4e6 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -394,20 +394,32 @@
                         WGC3Dsizei width, WGC3Dsizei height);
 
   // Support for buffer creation and deletion
+  virtual void genBuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genFramebuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genRenderbuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void genTextures(WGC3Dsizei count, WebGLId* ids);
+
+  virtual void deleteBuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteFramebuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteRenderbuffers(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteTextures(WGC3Dsizei count, WebGLId* ids);
+
   virtual WebGLId createBuffer();
   virtual WebGLId createFramebuffer();
-  virtual WebGLId createProgram();
   virtual WebGLId createRenderbuffer();
-  virtual WebGLId createShader(WGC3Denum);
   virtual WebGLId createTexture();
 
   virtual void deleteBuffer(WebGLId);
   virtual void deleteFramebuffer(WebGLId);
-  virtual void deleteProgram(WebGLId);
   virtual void deleteRenderbuffer(WebGLId);
-  virtual void deleteShader(WebGLId);
   virtual void deleteTexture(WebGLId);
 
+  virtual WebGLId createProgram();
+  virtual WebGLId createShader(WGC3Denum);
+
+  virtual void deleteProgram(WebGLId);
+  virtual void deleteShader(WebGLId);
+
   virtual void synthesizeGLError(WGC3Denum);
 
   virtual void* mapBufferSubDataCHROMIUM(
@@ -428,9 +440,6 @@
 
   virtual void setVisibilityCHROMIUM(bool visible);
 
-  virtual void setMemoryAllocationChangedCallbackCHROMIUM(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback);
-
   virtual void discardFramebufferEXT(WGC3Denum target,
                                      WGC3Dsizei numAttachments,
                                      const WGC3Denum* attachments);
@@ -539,10 +548,6 @@
   virtual void drawBuffersEXT(WGC3Dsizei n, const WGC3Denum* bufs);
 
   virtual unsigned insertSyncPoint();
-  virtual void signalSyncPoint(unsigned sync_point,
-                               WebGraphicsSyncPointCallback* callback);
-  virtual void signalQuery(unsigned query,
-                           WebGraphicsSyncPointCallback* callback);
 
   virtual void loseContextCHROMIUM(WGC3Denum current, WGC3Denum other);
 
diff --git a/webkit/common/gpu/webkit_gpu.gyp b/webkit/common/gpu/webkit_gpu.gyp
index 86f7e43..e633126 100644
--- a/webkit/common/gpu/webkit_gpu.gyp
+++ b/webkit/common/gpu/webkit_gpu.gyp
@@ -26,7 +26,6 @@
             '<(DEPTH)/third_party/angle_dx11/src/build_angle.gyp:translator',
             '<(DEPTH)/ui/gl/gl.gyp:gl',
             '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
-            '<(DEPTH)/ui/ui.gyp:ui',
           ],
           'sources': [
             # This list contains all .h and .cc in gpu except for test code.
@@ -36,8 +35,6 @@
             'gl_bindings_skia_cmd_buffer.h',
             'grcontext_for_webgraphicscontext3d.cc',
             'grcontext_for_webgraphicscontext3d.h',
-            'managed_memory_policy_convert.cc',
-            'managed_memory_policy_convert.h',
             'test_context_provider_factory.cc',
             'test_context_provider_factory.h',
             'webgraphicscontext3d_in_process_command_buffer_impl.cc',
diff --git a/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk b/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk
index 843eba1..ba02d5f 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -78,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -97,8 +95,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -132,8 +128,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -193,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,8 +206,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -247,8 +239,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -314,8 +304,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk b/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
index 3b9d1d7..3c87e98 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -78,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -97,8 +95,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -132,8 +128,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -193,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,8 +206,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -247,8 +239,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -310,8 +300,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk b/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
index 2ffe6ca..1ff8f5a 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -80,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -99,7 +97,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -133,8 +130,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -197,13 +192,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,7 +211,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -250,8 +244,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -312,8 +304,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-arm.mk b/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
index 843eba1..ba02d5f 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -78,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -97,8 +95,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -132,8 +128,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -193,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,8 +206,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -247,8 +239,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -314,8 +304,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-mips.mk b/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
index 3b9d1d7..3c87e98 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -78,13 +76,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -97,8 +95,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -132,8 +128,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -193,13 +187,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -212,8 +206,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DPOSIX_AVOID_MMAP' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -247,8 +239,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -310,8 +300,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-x86.mk b/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
index 2ffe6ca..1ff8f5a 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_minimal_gyp)/blink_minimal.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -31,7 +30,6 @@
 	webkit/common/gpu/context_provider_in_process.cc \
 	webkit/common/gpu/gl_bindings_skia_cmd_buffer.cc \
 	webkit/common/gpu/grcontext_for_webgraphicscontext3d.cc \
-	webkit/common/gpu/managed_memory_policy_convert.cc \
 	webkit/common/gpu/test_context_provider_factory.cc \
 	webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc \
 	webkit/common/gpu/webgraphicscontext3d_provider_impl.cc
@@ -80,13 +78,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -99,7 +97,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -133,8 +130,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -197,13 +192,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -216,7 +211,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DMESA_EGL_NO_X11_HEADERS' \
-	'-DU_USING_ICU_NAMESPACE=0' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -250,8 +244,6 @@
 	$(LOCAL_PATH)/v8/include \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
 	$(PWD)/external/stlport/stlport
@@ -312,8 +304,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/common/quota/quota_types.h b/webkit/common/quota/quota_types.h
index 56fbc6c..6cb45c9 100644
--- a/webkit/common/quota/quota_types.h
+++ b/webkit/common/quota/quota_types.h
@@ -13,6 +13,7 @@
   kStorageTypeTemporary,
   kStorageTypePersistent,
   kStorageTypeSyncable,
+  kStorageTypeQuotaNotManaged,
   kStorageTypeUnknown,
 };
 
diff --git a/webkit/common/resource_request_body.cc b/webkit/common/resource_request_body.cc
index 097751b..42b798f 100644
--- a/webkit/common/resource_request_body.cc
+++ b/webkit/common/resource_request_body.cc
@@ -26,11 +26,6 @@
                                       expected_modification_time);
 }
 
-void ResourceRequestBody::AppendBlobDeprecated(const GURL& blob_url) {
-  elements_.push_back(Element());
-  elements_.back().SetToBlobUrl(blob_url);
-}
-
 void ResourceRequestBody::AppendBlob(const std::string& uuid) {
   elements_.push_back(Element());
   elements_.back().SetToBlob(uuid);
diff --git a/webkit/common/resource_request_body.h b/webkit/common/resource_request_body.h
index 6f74e67..ccfc1f3 100644
--- a/webkit/common/resource_request_body.h
+++ b/webkit/common/resource_request_body.h
@@ -34,7 +34,6 @@
   void AppendFileRange(const base::FilePath& file_path,
                        uint64 offset, uint64 length,
                        const base::Time& expected_modification_time);
-  void AppendBlobDeprecated(const GURL& blob_url);
   void AppendBlob(const std::string& uuid);
   void AppendFileSystemFileRange(const GURL& url, uint64 offset, uint64 length,
                                  const base::Time& expected_modification_time);
diff --git a/webkit/common/user_agent/user_agent.target.darwin-arm.mk b/webkit/common/user_agent/user_agent.target.darwin-arm.mk
index 1a0bf43..9f5e5bb 100644
--- a/webkit/common/user_agent/user_agent.target.darwin-arm.mk
+++ b/webkit/common/user_agent/user_agent.target.darwin-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/user_agent/user_agent.target.darwin-mips.mk b/webkit/common/user_agent/user_agent.target.darwin-mips.mk
index 2ddfa82..2bc4a67 100644
--- a/webkit/common/user_agent/user_agent.target.darwin-mips.mk
+++ b/webkit/common/user_agent/user_agent.target.darwin-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/user_agent/user_agent.target.darwin-x86.mk b/webkit/common/user_agent/user_agent.target.darwin-x86.mk
index 0eaf4f3..cc85ddc 100644
--- a/webkit/common/user_agent/user_agent.target.darwin-x86.mk
+++ b/webkit/common/user_agent/user_agent.target.darwin-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/user_agent/user_agent.target.linux-arm.mk b/webkit/common/user_agent/user_agent.target.linux-arm.mk
index 1a0bf43..9f5e5bb 100644
--- a/webkit/common/user_agent/user_agent.target.linux-arm.mk
+++ b/webkit/common/user_agent/user_agent.target.linux-arm.mk
@@ -69,13 +69,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -158,13 +158,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/user_agent/user_agent.target.linux-mips.mk b/webkit/common/user_agent/user_agent.target.linux-mips.mk
index 2ddfa82..2bc4a67 100644
--- a/webkit/common/user_agent/user_agent.target.linux-mips.mk
+++ b/webkit/common/user_agent/user_agent.target.linux-mips.mk
@@ -68,13 +68,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -156,13 +156,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/user_agent/user_agent.target.linux-x86.mk b/webkit/common/user_agent/user_agent.target.linux-x86.mk
index 0eaf4f3..cc85ddc 100644
--- a/webkit/common/user_agent/user_agent.target.linux-x86.mk
+++ b/webkit/common/user_agent/user_agent.target.linux-x86.mk
@@ -71,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.darwin-arm.mk b/webkit/common/webkit_common.target.darwin-arm.mk
index 6428a6f..28f554b 100644
--- a/webkit/common/webkit_common.target.darwin-arm.mk
+++ b/webkit/common/webkit_common.target.darwin-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.darwin-mips.mk b/webkit/common/webkit_common.target.darwin-mips.mk
index eda1f4b..5e44072 100644
--- a/webkit/common/webkit_common.target.darwin-mips.mk
+++ b/webkit/common/webkit_common.target.darwin-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -183,13 +183,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.darwin-x86.mk b/webkit/common/webkit_common.target.darwin-x86.mk
index 0615864..30bd96b 100644
--- a/webkit/common/webkit_common.target.darwin-x86.mk
+++ b/webkit/common/webkit_common.target.darwin-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.linux-arm.mk b/webkit/common/webkit_common.target.linux-arm.mk
index 6428a6f..28f554b 100644
--- a/webkit/common/webkit_common.target.linux-arm.mk
+++ b/webkit/common/webkit_common.target.linux-arm.mk
@@ -75,13 +75,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -185,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.linux-mips.mk b/webkit/common/webkit_common.target.linux-mips.mk
index eda1f4b..5e44072 100644
--- a/webkit/common/webkit_common.target.linux-mips.mk
+++ b/webkit/common/webkit_common.target.linux-mips.mk
@@ -74,13 +74,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -183,13 +183,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webkit_common.target.linux-x86.mk b/webkit/common/webkit_common.target.linux-x86.mk
index 0615864..30bd96b 100644
--- a/webkit/common/webkit_common.target.linux-x86.mk
+++ b/webkit/common/webkit_common.target.linux-x86.mk
@@ -77,13 +77,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -189,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/common/webpreferences.cc b/webkit/common/webpreferences.cc
index 1250512..5bb5e58 100644
--- a/webkit/common/webpreferences.cc
+++ b/webkit/common/webpreferences.cc
@@ -72,6 +72,7 @@
       accelerated_2d_canvas_enabled(false),
       minimum_accelerated_2d_canvas_size(257 * 256),
       antialiased_2d_canvas_disabled(false),
+      accelerated_2d_canvas_msaa_sample_count(0),
       accelerated_filters_enabled(false),
       gesture_tap_highlight_enabled(false),
       accelerated_compositing_for_plugins_enabled(false),
@@ -89,6 +90,7 @@
       device_supports_touch(false),
       device_supports_mouse(true),
       touch_adjustment_enabled(true),
+      pointer_events_max_touch_points(0),
       fixed_position_creates_stacking_context(false),
       sync_xhr_in_documents_enabled(true),
       deferred_image_decoding_enabled(false),
@@ -133,6 +135,7 @@
       wide_viewport_quirk(false),
       use_wide_viewport(true),
       viewport_meta_layout_size_quirk(false),
+      viewport_meta_merge_content_quirk(false),
       viewport_meta_zero_values_quirk(false),
       ignore_main_frame_overflow_hidden_quirk(false),
       report_screen_size_in_physical_pixels_quirk(false)
diff --git a/webkit/common/webpreferences.h b/webkit/common/webpreferences.h
index ddddb0b..bb15a08 100644
--- a/webkit/common/webpreferences.h
+++ b/webkit/common/webpreferences.h
@@ -121,6 +121,7 @@
   bool accelerated_2d_canvas_enabled;
   int minimum_accelerated_2d_canvas_size;
   bool antialiased_2d_canvas_disabled;
+  int accelerated_2d_canvas_msaa_sample_count;
   bool accelerated_filters_enabled;
   bool gesture_tap_highlight_enabled;
   bool accelerated_compositing_for_plugins_enabled;
@@ -139,6 +140,7 @@
   bool device_supports_touch;
   bool device_supports_mouse;
   bool touch_adjustment_enabled;
+  int pointer_events_max_touch_points;
   bool fixed_position_creates_stacking_context;
   bool sync_xhr_in_documents_enabled;
   bool deferred_image_decoding_enabled;
@@ -176,6 +178,7 @@
   bool wide_viewport_quirk;
   bool use_wide_viewport;
   bool viewport_meta_layout_size_quirk;
+  bool viewport_meta_merge_content_quirk;
   bool viewport_meta_zero_values_quirk;
   bool ignore_main_frame_overflow_hidden_quirk;
   bool report_screen_size_in_physical_pixels_quirk;
diff --git a/webkit/glue/glue.target.darwin-arm.mk b/webkit/glue/glue.target.darwin-arm.mk
index 203a14f..9b415a4 100644
--- a/webkit/glue/glue.target.darwin-arm.mk
+++ b/webkit/glue/glue.target.darwin-arm.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -83,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,7 +145,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -212,13 +209,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -277,7 +274,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -346,8 +342,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue.target.darwin-mips.mk b/webkit/glue/glue.target.darwin-mips.mk
index 8aa038d..f9f5d35 100644
--- a/webkit/glue/glue.target.darwin-mips.mk
+++ b/webkit/glue/glue.target.darwin-mips.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -82,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,7 +144,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -210,13 +207,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -275,7 +272,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -340,8 +336,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue.target.darwin-x86.mk b/webkit/glue/glue.target.darwin-x86.mk
index 6c50dfd..2bdb79b 100644
--- a/webkit/glue/glue.target.darwin-x86.mk
+++ b/webkit/glue/glue.target.darwin-x86.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -85,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,7 +146,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -216,13 +213,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -280,7 +277,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -344,8 +340,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue.target.linux-arm.mk b/webkit/glue/glue.target.linux-arm.mk
index 203a14f..9b415a4 100644
--- a/webkit/glue/glue.target.linux-arm.mk
+++ b/webkit/glue/glue.target.linux-arm.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -83,13 +81,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -147,7 +145,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -212,13 +209,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -277,7 +274,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -346,8 +342,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue.target.linux-mips.mk b/webkit/glue/glue.target.linux-mips.mk
index 8aa038d..f9f5d35 100644
--- a/webkit/glue/glue.target.linux-mips.mk
+++ b/webkit/glue/glue.target.linux-mips.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -82,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -146,7 +144,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -210,13 +207,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -275,7 +272,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -340,8 +336,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue.target.linux-x86.mk b/webkit/glue/glue.target.linux-x86.mk
index 6c50dfd..2bdb79b 100644
--- a/webkit/glue/glue.target.linux-x86.mk
+++ b/webkit/glue/glue.target.linux-x86.mk
@@ -17,8 +17,6 @@
 	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
 	$(call intermediates-dir-for,GYP,third_party_npapi_npapi_gyp)/npapi.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_gl_gl_gyp)/ui_gl_gl_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a \
-	$(call intermediates-dir-for,GYP,ui_ui_resources_gyp)/ui_resources.stamp \
 	$(call intermediates-dir-for,GYP,v8_tools_gyp_v8_gyp)/v8.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_resources_gyp)/webkit_resources.stamp \
 	$(call intermediates-dir-for,GYP,webkit_webkit_strings_gyp)/webkit_strings.stamp \
@@ -85,13 +83,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -148,7 +146,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -216,13 +213,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -280,7 +277,6 @@
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(gyp_shared_intermediate_dir)/ui/gl \
 	$(LOCAL_PATH)/third_party/mesa/src/include \
-	$(gyp_shared_intermediate_dir)/ui/ui_resources \
 	$(LOCAL_PATH)/v8/include \
 	$(LOCAL_PATH)/third_party/WebKit \
 	$(PWD)/frameworks/wilhelm/include \
@@ -344,8 +340,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	skia_skia_library_gyp \
-	ui_gl_gl_gyp \
-	ui_ui_gyp
+	ui_gl_gl_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/glue/glue_child.target.darwin-arm.mk b/webkit/glue/glue_child.target.darwin-arm.mk
index 3a02718..b5f2a10 100644
--- a/webkit/glue/glue_child.target.darwin-arm.mk
+++ b/webkit/glue/glue_child.target.darwin-arm.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/glue_child.target.darwin-mips.mk b/webkit/glue/glue_child.target.darwin-mips.mk
index 7698de7..1bb5c9c 100644
--- a/webkit/glue/glue_child.target.darwin-mips.mk
+++ b/webkit/glue/glue_child.target.darwin-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -209,13 +209,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/glue_child.target.darwin-x86.mk b/webkit/glue/glue_child.target.darwin-x86.mk
index c7c60c1..6815aba 100644
--- a/webkit/glue/glue_child.target.darwin-x86.mk
+++ b/webkit/glue/glue_child.target.darwin-x86.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -215,13 +215,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/glue_child.target.linux-arm.mk b/webkit/glue/glue_child.target.linux-arm.mk
index 3a02718..b5f2a10 100644
--- a/webkit/glue/glue_child.target.linux-arm.mk
+++ b/webkit/glue/glue_child.target.linux-arm.mk
@@ -91,13 +91,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -211,13 +211,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/glue_child.target.linux-mips.mk b/webkit/glue/glue_child.target.linux-mips.mk
index 7698de7..1bb5c9c 100644
--- a/webkit/glue/glue_child.target.linux-mips.mk
+++ b/webkit/glue/glue_child.target.linux-mips.mk
@@ -90,13 +90,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -209,13 +209,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/glue_child.target.linux-x86.mk b/webkit/glue/glue_child.target.linux-x86.mk
index c7c60c1..6815aba 100644
--- a/webkit/glue/glue_child.target.linux-x86.mk
+++ b/webkit/glue/glue_child.target.linux-x86.mk
@@ -93,13 +93,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -215,13 +215,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.darwin-arm.mk b/webkit/glue/overscroller_jni_headers.target.darwin-arm.mk
index 97b28a4..56a5df4 100644
--- a/webkit/glue/overscroller_jni_headers.target.darwin-arm.mk
+++ b/webkit/glue/overscroller_jni_headers.target.darwin-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.darwin-mips.mk b/webkit/glue/overscroller_jni_headers.target.darwin-mips.mk
index 7e98933..58c59b0 100644
--- a/webkit/glue/overscroller_jni_headers.target.darwin-mips.mk
+++ b/webkit/glue/overscroller_jni_headers.target.darwin-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.darwin-x86.mk b/webkit/glue/overscroller_jni_headers.target.darwin-x86.mk
index e1bd493..0398a0a 100644
--- a/webkit/glue/overscroller_jni_headers.target.darwin-x86.mk
+++ b/webkit/glue/overscroller_jni_headers.target.darwin-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.linux-arm.mk b/webkit/glue/overscroller_jni_headers.target.linux-arm.mk
index 97b28a4..56a5df4 100644
--- a/webkit/glue/overscroller_jni_headers.target.linux-arm.mk
+++ b/webkit/glue/overscroller_jni_headers.target.linux-arm.mk
@@ -80,13 +80,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,13 +165,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.linux-mips.mk b/webkit/glue/overscroller_jni_headers.target.linux-mips.mk
index 7e98933..58c59b0 100644
--- a/webkit/glue/overscroller_jni_headers.target.linux-mips.mk
+++ b/webkit/glue/overscroller_jni_headers.target.linux-mips.mk
@@ -79,13 +79,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -163,13 +163,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/overscroller_jni_headers.target.linux-x86.mk b/webkit/glue/overscroller_jni_headers.target.linux-x86.mk
index e1bd493..0398a0a 100644
--- a/webkit/glue/overscroller_jni_headers.target.linux-x86.mk
+++ b/webkit/glue/overscroller_jni_headers.target.linux-x86.mk
@@ -82,13 +82,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index bfff4bd..b044dc0 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -140,8 +140,6 @@
         '<(DEPTH)/third_party/npapi/npapi.gyp:npapi',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gl/gl.gyp:gl',
-        '<(DEPTH)/ui/ui.gyp:ui',
-        '<(DEPTH)/ui/ui.gyp:ui_resources',
         '<(DEPTH)/url/url.gyp:url_lib',
         '<(DEPTH)/v8/tools/gyp/v8.gyp:v8',
         '<(DEPTH)/webkit/common/user_agent/webkit_user_agent.gyp:user_agent',
diff --git a/webkit/renderer/compositor_bindings/compositor_bindings.gyp b/webkit/renderer/compositor_bindings/compositor_bindings.gyp
index d4a8113..abaf725 100644
--- a/webkit/renderer/compositor_bindings/compositor_bindings.gyp
+++ b/webkit/renderer/compositor_bindings/compositor_bindings.gyp
@@ -35,7 +35,6 @@
         '<(DEPTH)/skia/skia.gyp:skia',
         '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
-        '<(DEPTH)/ui/ui.gyp:ui',
         '<(DEPTH)/webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
       ],
       'defines': [
diff --git a/webkit/renderer/compositor_bindings/web_animation_impl.cc b/webkit/renderer/compositor_bindings/web_animation_impl.cc
index 06a1468..d0aec63 100644
--- a/webkit/renderer/compositor_bindings/web_animation_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_animation_impl.cc
@@ -45,14 +45,12 @@
       curve = transform_curve_impl->CloneToAnimationCurve();
       break;
     }
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
     case WebAnimationCurve::AnimationCurveTypeFilter: {
       const WebFilterAnimationCurveImpl* filter_curve_impl =
           static_cast<const WebFilterAnimationCurveImpl*>(&web_curve);
       curve = filter_curve_impl->CloneToAnimationCurve();
       break;
     }
-#endif
   }
   animation_ = Animation::Create(
       curve.Pass(),
@@ -109,9 +107,7 @@
     WebAnimation::TargetPropertyTransform, Animation::Transform);
 COMPILE_ASSERT_MATCHING_ENUMS(
     WebAnimation::TargetPropertyOpacity, Animation::Opacity);
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
 COMPILE_ASSERT_MATCHING_ENUMS(
     WebAnimation::TargetPropertyFilter, Animation::Filter);
-#endif
 
 }  // namespace webkit
diff --git a/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc b/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
index 54f1f77..fc2faaa 100644
--- a/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
@@ -30,9 +30,7 @@
 using WebKit::WebContentLayerClient;
 using WebKit::WebExternalTextureLayer;
 using WebKit::WebExternalTextureLayerClient;
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
 using WebKit::WebFilterAnimationCurve;
-#endif
 using WebKit::WebFilterOperations;
 using WebKit::WebFloatAnimationCurve;
 using WebKit::WebImageLayer;
@@ -99,12 +97,10 @@
   return new WebAnimationImpl(curve, target, animation_id, 0);
 }
 
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
 WebFilterAnimationCurve*
 WebCompositorSupportImpl::createFilterAnimationCurve() {
   return new WebFilterAnimationCurveImpl();
 }
-#endif
 
 WebFloatAnimationCurve* WebCompositorSupportImpl::createFloatAnimationCurve() {
   return new WebFloatAnimationCurveImpl();
diff --git a/webkit/renderer/compositor_bindings/web_compositor_support_impl.h b/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
index b0ac4d8..8e6e2cd 100644
--- a/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
+++ b/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop_proxy.h"
-#include "third_party/WebKit/public/platform/WebAnimationCurve.h"
 #include "third_party/WebKit/public/platform/WebCompositorSupport.h"
 #include "third_party/WebKit/public/platform/WebLayer.h"
 #include "third_party/WebKit/public/platform/WebTransformOperations.h"
@@ -42,9 +41,7 @@
       const WebKit::WebAnimationCurve& curve,
       WebKit::WebAnimation::TargetProperty target,
       int animation_id);
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
   virtual WebKit::WebFilterAnimationCurve* createFilterAnimationCurve();
-#endif
   virtual WebKit::WebFloatAnimationCurve* createFloatAnimationCurve();
   virtual WebKit::WebTransformAnimationCurve* createTransformAnimationCurve();
   virtual WebKit::WebTransformOperations* createTransformOperations();
diff --git a/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.cc b/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.cc
index f35cff6..4692d11 100644
--- a/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.cc
@@ -4,8 +4,6 @@
 
 #include "webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.h"
 
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
-
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/timing_function.h"
 #include "cc/output/filter_operations.h"
@@ -26,10 +24,6 @@
   return WebAnimationCurve::AnimationCurveTypeFilter;
 }
 
-void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe) {
-  add(keyframe, TimingFunctionTypeEase);
-}
-
 void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
                                       TimingFunctionType type) {
   const cc::FilterOperations& filter_operations =
@@ -60,5 +54,3 @@
 }
 
 }  // namespace webkit
-
-#endif  // WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
diff --git a/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.h b/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.h
index 4c0675a..6a6255c 100644
--- a/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.h
+++ b/webkit/renderer/compositor_bindings/web_filter_animation_curve_impl.h
@@ -5,10 +5,6 @@
 #ifndef WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_FILTER_ANIMATION_CURVE_IMPL_H_
 #define WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_FILTER_ANIMATION_CURVE_IMPL_H_
 
-#include "third_party/WebKit/public/platform/WebAnimationCurve.h"
-
-#if WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
-
 #include "base/memory/scoped_ptr.h"
 #include "third_party/WebKit/public/platform/WebFilterAnimationCurve.h"
 #include "webkit/renderer/compositor_bindings/webkit_compositor_bindings_export.h"
@@ -32,7 +28,6 @@
   virtual AnimationCurveType type() const;
 
   // WebKit::WebFilterAnimationCurve implementation.
-  virtual void add(const WebKit::WebFilterKeyframe& keyframe);
   virtual void add(const WebKit::WebFilterKeyframe& keyframe,
                    TimingFunctionType type);
   virtual void add(const WebKit::WebFilterKeyframe& keyframe,
@@ -51,6 +46,4 @@
 
 }  // namespace webkit
 
-#endif  // WEB_FILTER_ANIMATION_CURVE_IS_DEFINED
-
 #endif  // WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_FILTER_ANIMATION_CURVE_IMPL_H_
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.cc b/webkit/renderer/compositor_bindings/web_layer_impl.cc
index fb9f72e..b594610 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.cc
@@ -193,9 +193,7 @@
 bool WebLayerImpl::addAnimation(WebKit::WebAnimation* animation) {
   bool result = layer_->AddAnimation(
       static_cast<WebAnimationImpl*>(animation)->PassAnimation());
-#if defined(ANIMATION_OWNERSHIP_TRANSFER)
   delete animation;
-#endif
   return result;
 }
 
@@ -219,10 +217,6 @@
   layer_->SuspendAnimations(monotonic_time);
 }
 
-void WebLayerImpl::resumeAnimations(double monotonic_time) {
-  layer_->ResumeAnimations(monotonic_time);
-}
-
 bool WebLayerImpl::hasActiveAnimation() { return layer_->HasActiveAnimation(); }
 
 void WebLayerImpl::setForceRenderSurface(bool force_render_surface) {
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.h b/webkit/renderer/compositor_bindings/web_layer_impl.h
index 3a4a866..c18a5bb 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.h
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.h
@@ -94,7 +94,6 @@
                                WebKit::WebAnimation::TargetProperty);
   virtual void pauseAnimation(int animation_id, double time_offset);
   virtual void suspendAnimations(double monotonic_time);
-  virtual void resumeAnimations(double monotonic_time);
   virtual bool hasActiveAnimation();
   virtual void setForceRenderSurface(bool force);
   virtual void setScrollPosition(WebKit::WebPoint position);
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-arm.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-arm.mk
index 60aa1b9..05e66d3 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-arm.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -86,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -106,7 +105,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -199,13 +197,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -219,7 +217,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -322,8 +319,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-mips.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-mips.mk
index aa09124..089e17e 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-mips.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -85,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -105,7 +104,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -197,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -217,7 +215,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -316,8 +313,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-x86.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-x86.mk
index 6a08610..3d0804d 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-x86.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.darwin-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -88,13 +87,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -203,13 +202,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -320,8 +319,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-arm.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-arm.mk
index 60aa1b9..05e66d3 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-arm.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -86,13 +85,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -106,7 +105,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -199,13 +197,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -219,7 +217,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -322,8 +319,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-mips.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-mips.mk
index aa09124..089e17e 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-mips.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -85,13 +84,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -105,7 +104,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -197,13 +195,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -217,7 +215,6 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DPOSIX_AVOID_MMAP' \
 	'-D__STDC_CONSTANT_MACROS' \
 	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
@@ -316,8 +313,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-x86.mk b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-x86.mk
index 6a08610..3d0804d 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-x86.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_bindings.target.linux-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,gpu_gpu_gyp)/gpu.stamp \
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
-	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -88,13 +87,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -203,13 +202,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -320,8 +319,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-arm.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-arm.mk
index 90c5ada..1dec556 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-arm.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-mips.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-mips.mk
index 6c49888..2cf93e1 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-mips.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-x86.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-x86.mk
index 5dc2307..9d9cb97 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-x86.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.darwin-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-arm.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-arm.mk
index 90c5ada..1dec556 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-arm.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-arm.mk
@@ -65,13 +65,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -170,13 +170,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-mips.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-mips.mk
index 6c49888..2cf93e1 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-mips.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-mips.mk
@@ -64,13 +64,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -168,13 +168,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-x86.mk b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-x86.mk
index 5dc2307..9d9cb97 100644
--- a/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-x86.mk
+++ b/webkit/renderer/compositor_bindings/webkit_compositor_support.target.linux-x86.mk
@@ -67,13 +67,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -175,13 +175,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
diff --git a/webkit/renderer/webkit_renderer.gyp b/webkit/renderer/webkit_renderer.gyp
index fe17685..b120a0a 100644
--- a/webkit/renderer/webkit_renderer.gyp
+++ b/webkit/renderer/webkit_renderer.gyp
@@ -19,7 +19,6 @@
         '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
         '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
-        '<(DEPTH)/ui/ui.gyp:ui',
         '<(DEPTH)/url/url.gyp:url_lib',
         '<(DEPTH)/webkit/common/webkit_common.gyp:webkit_common',
       ],
diff --git a/webkit/renderer/webkit_renderer.target.darwin-arm.mk b/webkit/renderer/webkit_renderer.target.darwin-arm.mk
index ff9ffc4..533b503 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-arm.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -72,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -306,8 +305,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/webkit_renderer.target.darwin-mips.mk b/webkit/renderer/webkit_renderer.target.darwin-mips.mk
index 92a92e5..899820a 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-mips.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -72,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -302,8 +301,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/webkit_renderer.target.darwin-x86.mk b/webkit/renderer/webkit_renderer.target.darwin-x86.mk
index 4fdb364..921d6dd 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-x86.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -74,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -304,8 +303,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/webkit_renderer.target.linux-arm.mk b/webkit/renderer/webkit_renderer.target.linux-arm.mk
index ff9ffc4..533b503 100644
--- a/webkit/renderer/webkit_renderer.target.linux-arm.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-arm.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -72,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -306,8 +305,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/webkit_renderer.target.linux-mips.mk b/webkit/renderer/webkit_renderer.target.linux-mips.mk
index 92a92e5..899820a 100644
--- a/webkit/renderer/webkit_renderer.target.linux-mips.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-mips.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -72,13 +71,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -186,13 +185,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -302,8 +301,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/renderer/webkit_renderer.target.linux-x86.mk b/webkit/renderer/webkit_renderer.target.linux-x86.mk
index 4fdb364..921d6dd 100644
--- a/webkit/renderer/webkit_renderer.target.linux-x86.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-x86.mk
@@ -14,8 +14,7 @@
 	$(call intermediates-dir-for,GYP,skia_skia_gyp)/skia.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_ui_gyp)/ui_ui_gyp.a
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
 
 GYP_GENERATED_OUTPUTS :=
 
@@ -74,13 +73,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -190,13 +189,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -304,8 +303,7 @@
 LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
 
 LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_gyp \
-	ui_ui_gyp
+	skia_skia_library_gyp
 
 # Enable grouping to fix circular references
 LOCAL_GROUP_STATIC_LIBRARIES := true
diff --git a/webkit/storage_browser.gyp b/webkit/storage_browser.gyp
index 23f2f93..ecf1c94 100644
--- a/webkit/storage_browser.gyp
+++ b/webkit/storage_browser.gyp
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'chromium_code': 1,
+  },
   'targets': [
     {
       'target_name': 'webkit_storage_browser',
@@ -167,6 +170,8 @@
         'browser/fileapi/sandbox_origin_database.h',
         'browser/fileapi/sandbox_origin_database_interface.cc',
         'browser/fileapi/sandbox_origin_database_interface.h',
+        'browser/fileapi/sandbox_prioritized_origin_database.cc',
+        'browser/fileapi/sandbox_prioritized_origin_database.h',
         'browser/fileapi/sandbox_quota_observer.cc',
         'browser/fileapi/sandbox_quota_observer.h',
         'browser/fileapi/task_runner_bound_observer_list.h',
diff --git a/webkit/storage_common.gyp b/webkit/storage_common.gyp
index a77d4c5..51181fe 100644
--- a/webkit/storage_common.gyp
+++ b/webkit/storage_common.gyp
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'chromium_code': 1,
+  },
   'targets': [
     {
       'target_name': 'webkit_storage_common',
diff --git a/webkit/webkit_storage_browser.target.darwin-arm.mk b/webkit/webkit_storage_browser.target.darwin-arm.mk
index 9c4cebc..f813163 100644
--- a/webkit/webkit_storage_browser.target.darwin-arm.mk
+++ b/webkit/webkit_storage_browser.target.darwin-arm.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -107,14 +108,15 @@
 MY_CFLAGS_Debug := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -129,10 +131,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -143,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,6 +162,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -214,26 +214,26 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -248,10 +248,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -262,13 +258,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -283,6 +279,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -290,7 +288,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -333,12 +332,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_browser.target.darwin-mips.mk b/webkit/webkit_storage_browser.target.darwin-mips.mk
index 7bc7362..0beef6c 100644
--- a/webkit/webkit_storage_browser.target.darwin-mips.mk
+++ b/webkit/webkit_storage_browser.target.darwin-mips.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -110,12 +111,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -129,10 +130,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -143,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,6 +161,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -214,12 +213,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
@@ -229,12 +227,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -248,10 +246,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -262,13 +256,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -283,6 +277,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -290,7 +286,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -333,12 +330,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_browser.target.darwin-x86.mk b/webkit/webkit_storage_browser.target.darwin-x86.mk
index 9a048f7..4cadb56 100644
--- a/webkit/webkit_storage_browser.target.darwin-x86.mk
+++ b/webkit/webkit_storage_browser.target.darwin-x86.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -106,14 +107,15 @@
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Debug := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -130,10 +132,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-g \
@@ -145,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,6 +163,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -215,24 +215,24 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -249,10 +249,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-fno-ident \
@@ -266,13 +262,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -286,6 +282,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -293,7 +291,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -336,11 +335,10 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_browser.target.linux-arm.mk b/webkit/webkit_storage_browser.target.linux-arm.mk
index 9c4cebc..f813163 100644
--- a/webkit/webkit_storage_browser.target.linux-arm.mk
+++ b/webkit/webkit_storage_browser.target.linux-arm.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -107,14 +108,15 @@
 MY_CFLAGS_Debug := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -129,10 +131,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -143,13 +141,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,6 +162,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -214,26 +214,26 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -248,10 +248,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -262,13 +258,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -283,6 +279,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -290,7 +288,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -333,12 +332,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_browser.target.linux-mips.mk b/webkit/webkit_storage_browser.target.linux-mips.mk
index 7bc7362..0beef6c 100644
--- a/webkit/webkit_storage_browser.target.linux-mips.mk
+++ b/webkit/webkit_storage_browser.target.linux-mips.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -110,12 +111,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -129,10 +130,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -143,13 +140,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -164,6 +161,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -214,12 +213,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
@@ -229,12 +227,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -248,10 +246,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -262,13 +256,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -283,6 +277,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -290,7 +286,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -333,12 +330,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_browser.target.linux-x86.mk b/webkit/webkit_storage_browser.target.linux-x86.mk
index 9a048f7..4cadb56 100644
--- a/webkit/webkit_storage_browser.target.linux-x86.mk
+++ b/webkit/webkit_storage_browser.target.linux-x86.mk
@@ -91,6 +91,7 @@
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
+	webkit/browser/fileapi/sandbox_prioritized_origin_database.cc \
 	webkit/browser/fileapi/sandbox_quota_observer.cc \
 	webkit/browser/fileapi/timed_task_helper.cc \
 	webkit/browser/fileapi/transient_file_util.cc \
@@ -106,14 +107,15 @@
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Debug := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -130,10 +132,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-g \
@@ -145,13 +143,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -165,6 +163,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -215,24 +215,24 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -249,10 +249,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-fno-ident \
@@ -266,13 +262,13 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
@@ -286,6 +282,8 @@
 	'-DSK_USE_POSIX_THREADS' \
 	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
 	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -293,7 +291,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -336,11 +335,10 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.darwin-arm.mk b/webkit/webkit_storage_common.target.darwin-arm.mk
index 0af0a3b..2feecd6 100644
--- a/webkit/webkit_storage_common.target.darwin-arm.mk
+++ b/webkit/webkit_storage_common.target.darwin-arm.mk
@@ -39,14 +39,15 @@
 MY_CFLAGS_Debug := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -61,10 +62,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -75,18 +72,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -113,26 +112,26 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -147,10 +146,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -161,18 +156,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -180,7 +177,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -199,12 +197,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.darwin-mips.mk b/webkit/webkit_storage_common.target.darwin-mips.mk
index ef0fa5d..9780798 100644
--- a/webkit/webkit_storage_common.target.darwin-mips.mk
+++ b/webkit/webkit_storage_common.target.darwin-mips.mk
@@ -42,12 +42,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -61,10 +61,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -75,18 +71,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -113,12 +111,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
@@ -128,12 +125,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -147,10 +144,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -161,18 +154,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -180,7 +175,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -199,12 +195,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.darwin-x86.mk b/webkit/webkit_storage_common.target.darwin-x86.mk
index ca793ea..8d851cb 100644
--- a/webkit/webkit_storage_common.target.darwin-x86.mk
+++ b/webkit/webkit_storage_common.target.darwin-x86.mk
@@ -38,14 +38,15 @@
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Debug := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -62,10 +63,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-g \
@@ -77,17 +74,19 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -114,24 +113,24 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -148,10 +147,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-fno-ident \
@@ -165,17 +160,19 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -183,7 +180,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -202,11 +200,10 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.linux-arm.mk b/webkit/webkit_storage_common.target.linux-arm.mk
index 0af0a3b..2feecd6 100644
--- a/webkit/webkit_storage_common.target.linux-arm.mk
+++ b/webkit/webkit_storage_common.target.linux-arm.mk
@@ -39,14 +39,15 @@
 MY_CFLAGS_Debug := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -61,10 +62,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -75,18 +72,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -113,26 +112,26 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	-fstack-protector \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-fno-tree-sra \
 	-fuse-ld=gold \
 	-Wno-psabi \
@@ -147,10 +146,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -161,18 +156,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -180,7 +177,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -199,12 +197,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-abi \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.linux-mips.mk b/webkit/webkit_storage_common.target.linux-mips.mk
index ef0fa5d..9780798 100644
--- a/webkit/webkit_storage_common.target.linux-mips.mk
+++ b/webkit/webkit_storage_common.target.linux-mips.mk
@@ -42,12 +42,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -61,10 +61,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-g \
 	-fomit-frame-pointer \
@@ -75,18 +71,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -113,12 +111,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
@@ -128,12 +125,12 @@
 	 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-EL \
 	-mhard-float \
 	-ffunction-sections \
@@ -147,10 +144,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-Os \
 	-fno-ident \
 	-fdata-sections \
@@ -161,18 +154,20 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
 	'-DPOSIX_AVOID_MMAP' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -180,7 +175,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -199,12 +195,11 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-uninitialized \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
diff --git a/webkit/webkit_storage_common.target.linux-x86.mk b/webkit/webkit_storage_common.target.linux-x86.mk
index ca793ea..8d851cb 100644
--- a/webkit/webkit_storage_common.target.linux-x86.mk
+++ b/webkit/webkit_storage_common.target.linux-x86.mk
@@ -38,14 +38,15 @@
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Debug := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -62,10 +63,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-g \
@@ -77,17 +74,19 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -114,24 +113,24 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 # Flags passed to both C and C++ files.
 MY_CFLAGS_Release := \
 	--param=ssp-buffer-size=4 \
+	-Werror \
 	-fno-exceptions \
 	-fno-strict-aliasing \
+	-Wall \
 	-Wno-unused-parameter \
 	-Wno-missing-field-initializers \
 	-fvisibility=hidden \
 	-pipe \
 	-fPIC \
-	-Wno-format \
 	-m32 \
 	-mmmx \
 	-march=pentium4 \
@@ -148,10 +147,6 @@
 	-Wno-extra \
 	-Wno-ignored-qualifiers \
 	-Wno-type-limits \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
 	-fno-stack-protector \
 	-Os \
 	-fno-ident \
@@ -165,17 +160,19 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
-	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
-	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DCLD_VERSION=1' \
 	'-DWEBKIT_STORAGE_COMMON_IMPLEMENTATION' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
 	'-DANDROID' \
 	'-D__GNU_SOURCE=1' \
 	'-DUSE_STLPORT=1' \
@@ -183,7 +180,8 @@
 	'-DCHROME_BUILD_ID=""' \
 	'-DNDEBUG' \
 	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
 
 
 # Include paths placed before CFLAGS/CPPFLAGS
@@ -202,11 +200,10 @@
 	-fno-rtti \
 	-fno-threadsafe-statics \
 	-fvisibility-inlines-hidden \
-	-Wno-deprecated \
+	-Wsign-compare \
 	-Wno-error=c++0x-compat \
 	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
+	-Wno-sign-promo
 
 
 LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))